Imported Upstream version 4.3.stable 08/270008/1 upstream/4.3.stable
authorSeonah Moon <seonah1.moon@samsung.com>
Mon, 24 Jan 2022 06:24:05 +0000 (15:24 +0900)
committerSeonah Moon <seonah1.moon@samsung.com>
Mon, 24 Jan 2022 06:32:04 +0000 (15:32 +0900)
Change-Id: I2d7bc2f1851649e7a568f0aa72d8eec91eb3e4ad

1213 files changed:
.gitignore
.sai.json [new file with mode: 0644]
.travis.yml [deleted file]
CMakeLists-implied-options.txt [new file with mode: 0644]
CMakeLists.txt
LICENSE
README.md
READMEs/README.async-dns.md [new file with mode: 0644]
READMEs/README.build-android.md [new file with mode: 0644]
READMEs/README.build-windows.md [new file with mode: 0644]
READMEs/README.build.md
READMEs/README.captive-portal-detection.md [new file with mode: 0644]
READMEs/README.cbor-cose.md [new file with mode: 0644]
READMEs/README.cbor-lecp.md [new file with mode: 0644]
READMEs/README.cmake.md [new file with mode: 0644]
READMEs/README.coding.md
READMEs/README.content-security-policy.md
READMEs/README.ctest.md [new file with mode: 0644]
READMEs/README.debugging.md [new file with mode: 0644]
READMEs/README.event-libs.md [new file with mode: 0644]
READMEs/README.event-loops-intro.md [new file with mode: 0644]
READMEs/README.fault-injection.md [new file with mode: 0644]
READMEs/README.generic-sessions.md [deleted file]
READMEs/README.generic-table.md [deleted file]
READMEs/README.h2-long-poll.md [new file with mode: 0644]
READMEs/README.http-cache.md [new file with mode: 0644]
READMEs/README.http_parser.md [new file with mode: 0644]
READMEs/README.jit-trust.md [new file with mode: 0644]
READMEs/README.json-lejp.md [new file with mode: 0644]
READMEs/README.jwt.md [new file with mode: 0644]
READMEs/README.libressl.md [new file with mode: 0644]
READMEs/README.lifecycle.md [new file with mode: 0644]
READMEs/README.logging.md [new file with mode: 0644]
READMEs/README.lws_cache.md [new file with mode: 0644]
READMEs/README.lws_conmon.md [new file with mode: 0644]
READMEs/README.lws_map.md [new file with mode: 0644]
READMEs/README.lws_metrics.md [new file with mode: 0644]
READMEs/README.lws_plugins.md [new file with mode: 0644]
READMEs/README.lws_retry.md [new file with mode: 0644]
READMEs/README.lws_sequencer.md
READMEs/README.lws_sul.md
READMEs/README.lws_system.md [new file with mode: 0644]
READMEs/README.plugin-sshd-base.md
READMEs/README.problems.md
READMEs/README.release-policy.md
READMEs/README.routing.md [new file with mode: 0644]
READMEs/README.tcp_fastopen.md [new file with mode: 0644]
READMEs/README.test-apps.md
READMEs/README.tls-sessions.md [new file with mode: 0644]
READMEs/README.udp.md [new file with mode: 0644]
READMEs/README.vulnerability-reporting.md
READMEs/mainpage.md
READMEs/release-checklist
appveyor.yml [deleted file]
bug_report.md [new file with mode: 0644]
changelog
cmake/FindLibWebSockets.cmake [deleted file]
cmake/FindOpenSSLbins.cmake
cmake/LibwebsocketsConfig.cmake.in [deleted file]
cmake/LwsCheckRequirements.cmake [new file with mode: 0644]
cmake/libwebsockets-config-version.cmake.in [moved from cmake/LibwebsocketsConfigVersion.cmake.in with 100% similarity]
cmake/libwebsockets-config.cmake.in [new file with mode: 0644]
cmake/lws_config.h.in
cmake/lws_config_private.h.in
contrib/android-make-script.sh [deleted file]
contrib/cross-aarch64-android.cmake [new file with mode: 0644]
contrib/cross-aarch64-qnx.cmake [new file with mode: 0644]
contrib/cross-aarch64.cmake
contrib/cross-arm-android-gnueabi.cmake
contrib/cross-arm-linux-gnueabihf.cmake
contrib/cross-atmel.cmake [new file with mode: 0644]
contrib/cross-esp32.cmake
contrib/cross-linkit.cmake [new file with mode: 0644]
contrib/cross-ming.cmake
contrib/cross-w32.cmake
contrib/cross-w64.cmake
contrib/iOS.cmake [new file with mode: 0644]
doc-assets/fault-injection.png [new file with mode: 0644]
doc-assets/jit-trust-logo.png [new file with mode: 0644]
doc-assets/jit-trust-overview.png [new file with mode: 0644]
doc-assets/jit-trust-paths.png [new file with mode: 0644]
doc-assets/jit-trust-single-trust.png [new file with mode: 0644]
doc-assets/jit-trust-system-trust.png [new file with mode: 0644]
doc-assets/lifecycle-context.png [new file with mode: 0644]
doc-assets/lifecycle-server-wsi.png [new file with mode: 0644]
doc-assets/lifecycle-wsi.png [new file with mode: 0644]
doc-assets/lws-detailed-latency-example.png [new file with mode: 0644]
doc-assets/lws-overview.png
doc-assets/lws_cache-1.png [new file with mode: 0644]
doc-assets/lws_cache-2.png [new file with mode: 0644]
doc-assets/lws_metrics-decimation.png [new file with mode: 0644]
doc-assets/lws_metrics-policy.png [new file with mode: 0644]
doc-assets/smd-message.png [new file with mode: 0644]
doc-assets/smd-proxy.png [new file with mode: 0644]
doc-assets/smd-single-process.png [new file with mode: 0644]
doc-assets/ss-explain.png [new file with mode: 0644]
doc-assets/ss-operation-modes.png [new file with mode: 0644]
doc-assets/ss-state-flow-server.png [new file with mode: 0644]
doc-assets/ss-state-flow.png [new file with mode: 0644]
doc-assets/work.png [new file with mode: 0644]
include/libwebsockets.h
include/libwebsockets.hxx [new file with mode: 0644]
include/libwebsockets/abstract/abstract.h
include/libwebsockets/abstract/protocols.h
include/libwebsockets/abstract/protocols/smtp.h
include/libwebsockets/abstract/transports.h
include/libwebsockets/abstract/transports/raw-skt.h
include/libwebsockets/abstract/transports/unit-test.h
include/libwebsockets/lws-adopt.h
include/libwebsockets/lws-async-dns.h [new file with mode: 0644]
include/libwebsockets/lws-bb-i2c.h [new file with mode: 0644]
include/libwebsockets/lws-bb-spi.h [new file with mode: 0644]
include/libwebsockets/lws-button.h [new file with mode: 0644]
include/libwebsockets/lws-cache-ttl.h [new file with mode: 0644]
include/libwebsockets/lws-callbacks.h
include/libwebsockets/lws-cgi.h
include/libwebsockets/lws-client.h
include/libwebsockets/lws-conmon.h [new file with mode: 0644]
include/libwebsockets/lws-context-vhost.h
include/libwebsockets/lws-cose.h [new file with mode: 0644]
include/libwebsockets/lws-dbus.h
include/libwebsockets/lws-diskcache.h
include/libwebsockets/lws-display.h [new file with mode: 0644]
include/libwebsockets/lws-dll2.h [new file with mode: 0644]
include/libwebsockets/lws-dsh.h
include/libwebsockets/lws-esp32.h [deleted file]
include/libwebsockets/lws-eventlib-exports.h [new file with mode: 0644]
include/libwebsockets/lws-fault-injection.h [new file with mode: 0644]
include/libwebsockets/lws-freertos.h [new file with mode: 0644]
include/libwebsockets/lws-fts.h
include/libwebsockets/lws-genaes.h
include/libwebsockets/lws-gencrypto.h
include/libwebsockets/lws-genec.h
include/libwebsockets/lws-genhash.h
include/libwebsockets/lws-genrsa.h
include/libwebsockets/lws-gpio.h [new file with mode: 0644]
include/libwebsockets/lws-http.h
include/libwebsockets/lws-i2c.h [new file with mode: 0644]
include/libwebsockets/lws-ili9341-spi.h [new file with mode: 0644]
include/libwebsockets/lws-jose.h
include/libwebsockets/lws-jwe.h
include/libwebsockets/lws-jwk.h
include/libwebsockets/lws-jws.h
include/libwebsockets/lws-lecp.h [new file with mode: 0644]
include/libwebsockets/lws-led.h [new file with mode: 0644]
include/libwebsockets/lws-lejp.h
include/libwebsockets/lws-logs.h
include/libwebsockets/lws-lwsac.h
include/libwebsockets/lws-map.h [new file with mode: 0644]
include/libwebsockets/lws-metrics.h [new file with mode: 0644]
include/libwebsockets/lws-misc.h
include/libwebsockets/lws-mqtt.h [new file with mode: 0644]
include/libwebsockets/lws-netdev.h [new file with mode: 0644]
include/libwebsockets/lws-network-helper.h
include/libwebsockets/lws-optee.h
include/libwebsockets/lws-plugin-generic-sessions.h [deleted file]
include/libwebsockets/lws-protocols-plugins.h
include/libwebsockets/lws-purify.h
include/libwebsockets/lws-pwm.h [new file with mode: 0644]
include/libwebsockets/lws-retry.h
include/libwebsockets/lws-ring.h
include/libwebsockets/lws-secure-streams-client.h [new file with mode: 0644]
include/libwebsockets/lws-secure-streams-policy.h [new file with mode: 0644]
include/libwebsockets/lws-secure-streams.h [new file with mode: 0644]
include/libwebsockets/lws-sequencer.h
include/libwebsockets/lws-service.h
include/libwebsockets/lws-settings.h [new file with mode: 0644]
include/libwebsockets/lws-sha1-base64.h
include/libwebsockets/lws-smd.h [new file with mode: 0644]
include/libwebsockets/lws-spa.h
include/libwebsockets/lws-spi.h [new file with mode: 0644]
include/libwebsockets/lws-ssd1306-i2c.h [new file with mode: 0644]
include/libwebsockets/lws-state.h [new file with mode: 0644]
include/libwebsockets/lws-stats.h [deleted file]
include/libwebsockets/lws-struct.h
include/libwebsockets/lws-system.h
include/libwebsockets/lws-test-sequencer.h
include/libwebsockets/lws-threadpool.h
include/libwebsockets/lws-timeout-timer.h
include/libwebsockets/lws-tls-sessions.h [new file with mode: 0644]
include/libwebsockets/lws-tokenize.h
include/libwebsockets/lws-vfs.h
include/libwebsockets/lws-write.h
include/libwebsockets/lws-writeable.h
include/libwebsockets/lws-ws-close.h
include/libwebsockets/lws-ws-ext.h
include/libwebsockets/lws-ws-state.h
include/libwebsockets/lws-x509.h
lib/CMakeLists.txt [new file with mode: 0644]
lib/README.md
lib/abstract/CMakeLists.txt [new file with mode: 0644]
lib/abstract/abstract.c
lib/abstract/private-lib-abstract.h [new file with mode: 0644]
lib/abstract/private.h [deleted file]
lib/abstract/protocols/smtp/private-lib-abstract-protocols-smtp.h [new file with mode: 0644]
lib/abstract/protocols/smtp/smtp-sequencer.c [new file with mode: 0644]
lib/abstract/protocols/smtp/smtp.c
lib/abstract/test-sequencer.c
lib/abstract/transports/raw-skt.c
lib/abstract/transports/unit-test.c
lib/core-net/CMakeLists.txt [new file with mode: 0644]
lib/core-net/README.md [new file with mode: 0644]
lib/core-net/adopt.c
lib/core-net/client/client.c [moved from lib/core-net/client.c with 50% similarity]
lib/core-net/client/conmon.c [new file with mode: 0644]
lib/core-net/client/connect.c [new file with mode: 0644]
lib/core-net/client/connect2.c [new file with mode: 0644]
lib/core-net/client/connect3.c [new file with mode: 0644]
lib/core-net/client/connect4.c [new file with mode: 0644]
lib/core-net/client/sort-dns.c [new file with mode: 0644]
lib/core-net/close.c
lib/core-net/connect.c [deleted file]
lib/core-net/dummy-callback.c
lib/core-net/lws-dsh.c
lib/core-net/network.c
lib/core-net/output.c
lib/core-net/pollfd.c
lib/core-net/private-lib-core-net.h [new file with mode: 0644]
lib/core-net/private.h [deleted file]
lib/core-net/route.c [new file with mode: 0644]
lib/core-net/sequencer.c
lib/core-net/server.c [deleted file]
lib/core-net/service.c
lib/core-net/socks5-client.c [new file with mode: 0644]
lib/core-net/sorted-usec-list.c
lib/core-net/state.c [new file with mode: 0644]
lib/core-net/stats.c [deleted file]
lib/core-net/vhost.c
lib/core-net/wsi-timeout.c
lib/core-net/wsi.c
lib/core/CMakeLists.txt [new file with mode: 0644]
lib/core/alloc.c
lib/core/buflist.c
lib/core/context.c
lib/core/libwebsockets.c
lib/core/logs.c
lib/core/lws_dll.c [deleted file]
lib/core/lws_dll2.c
lib/core/lws_map.c [new file with mode: 0644]
lib/core/private-lib-core.h [new file with mode: 0644]
lib/core/private.h [deleted file]
lib/core/vfs.c
lib/cose/CMakeLists.txt [new file with mode: 0644]
lib/cose/cose_key.c [new file with mode: 0644]
lib/cose/cose_sign.c [new file with mode: 0644]
lib/cose/cose_sign_alg.c [new file with mode: 0644]
lib/cose/cose_validate.c [new file with mode: 0644]
lib/cose/cose_validate_alg.c [new file with mode: 0644]
lib/cose/private-lib-cose.h [new file with mode: 0644]
lib/drivers/CMakeLists.txt [new file with mode: 0644]
lib/drivers/README.md [new file with mode: 0644]
lib/drivers/button/README.md [new file with mode: 0644]
lib/drivers/button/lws-button.c [new file with mode: 0644]
lib/drivers/devices/display/ili9341.h [new file with mode: 0644]
lib/drivers/devices/display/ssd1306.h [new file with mode: 0644]
lib/drivers/display/README.md [new file with mode: 0644]
lib/drivers/display/ili9341-spi.c [new file with mode: 0644]
lib/drivers/display/lws-display.c [new file with mode: 0644]
lib/drivers/display/ssd1306-i2c.c [new file with mode: 0644]
lib/drivers/i2c/bitbang/lws-bb-i2c.c [new file with mode: 0644]
lib/drivers/i2c/lws-i2c.c [new file with mode: 0644]
lib/drivers/led/README.md [new file with mode: 0644]
lib/drivers/led/led-gpio.c [new file with mode: 0644]
lib/drivers/led/led-seq.c [new file with mode: 0644]
lib/drivers/led/private-lib-drivers-led.h [new file with mode: 0644]
lib/drivers/netdev/netdev.c [new file with mode: 0644]
lib/drivers/netdev/wifi.c [new file with mode: 0644]
lib/drivers/pwm/pwm.c [new file with mode: 0644]
lib/drivers/settings/settings.c [new file with mode: 0644]
lib/drivers/spi/bitbang/lws-bb-spi.c [new file with mode: 0644]
lib/drivers/spi/lws-spi.c [new file with mode: 0644]
lib/event-libs/CMakeLists.txt [new file with mode: 0644]
lib/event-libs/README.md
lib/event-libs/glib/CMakeLists.txt [new file with mode: 0644]
lib/event-libs/glib/glib.c [new file with mode: 0644]
lib/event-libs/glib/private-lib-event-libs-glib.h [new file with mode: 0644]
lib/event-libs/libev/CMakeLists.txt [new file with mode: 0644]
lib/event-libs/libev/libev.c
lib/event-libs/libev/private-lib-event-libs-libev.h [new file with mode: 0644]
lib/event-libs/libev/private.h [deleted file]
lib/event-libs/libevent/CMakeLists.txt [new file with mode: 0644]
lib/event-libs/libevent/libevent.c
lib/event-libs/libevent/private-lib-event-libs-libevent.h [new file with mode: 0644]
lib/event-libs/libevent/private.h [deleted file]
lib/event-libs/libuv/CMakeLists.txt [new file with mode: 0644]
lib/event-libs/libuv/libuv.c
lib/event-libs/libuv/private-lib-event-libs-libuv.h [new file with mode: 0644]
lib/event-libs/libuv/private.h [deleted file]
lib/event-libs/poll/CMakeLists.txt [new file with mode: 0644]
lib/event-libs/poll/poll.c
lib/event-libs/poll/private-lib-event-libs-poll.h [new file with mode: 0644]
lib/event-libs/poll/private.h [deleted file]
lib/event-libs/private-lib-event-libs.h [new file with mode: 0644]
lib/event-libs/private.h [deleted file]
lib/event-libs/sdevent/CMakeLists.txt [new file with mode: 0644]
lib/event-libs/sdevent/private-lib-event-libs-sdevent.h [new file with mode: 0644]
lib/event-libs/sdevent/sdevent.c [new file with mode: 0644]
lib/event-libs/uloop/CMakeLists.txt [new file with mode: 0644]
lib/event-libs/uloop/private-lib-event-libs-uloop.h [new file with mode: 0644]
lib/event-libs/uloop/uloop.c [new file with mode: 0644]
lib/jose/CMakeLists.txt [new file with mode: 0644]
lib/jose/jwe/enc/aescbc.c [changed mode: 0644->0755]
lib/jose/jwe/enc/aesgcm.c
lib/jose/jwe/enc/aeskw.c
lib/jose/jwe/jwe-ecdh-es-aeskw.c
lib/jose/jwe/jwe-rsa-aescbc.c
lib/jose/jwe/jwe-rsa-aesgcm.c
lib/jose/jwe/jwe.c [changed mode: 0644->0755]
lib/jose/jwe/private-lib-jose-jwe.h [moved from lib/jose/jwe/private.h with 52% similarity]
lib/jose/jwk/jose_key.c [new file with mode: 0644]
lib/jose/jwk/jwk.c
lib/jose/jws/jose.c
lib/jose/jws/jws.c
lib/jose/jws/private-lib-jose-jws.h [new file with mode: 0644]
lib/jose/jws/private.h [deleted file]
lib/jose/private-lib-jose.h [new file with mode: 0644]
lib/jose/private.h [deleted file]
lib/misc/CMakeLists.txt [new file with mode: 0644]
lib/misc/base64-decode.c
lib/misc/cache-ttl/file.c [new file with mode: 0644]
lib/misc/cache-ttl/heap.c [new file with mode: 0644]
lib/misc/cache-ttl/lws-cache-ttl.c [new file with mode: 0644]
lib/misc/cache-ttl/private-lib-misc-cache-ttl.h [new file with mode: 0644]
lib/misc/daemonize.c
lib/misc/dir.c
lib/misc/diskcache.c
lib/misc/fsmount.c [new file with mode: 0644]
lib/misc/fts/README.md
lib/misc/fts/private-lib-misc-fts.h [moved from lib/misc/fts/private.h with 100% similarity]
lib/misc/fts/trie-fd.c
lib/misc/fts/trie.c
lib/misc/getifaddrs.c
lib/misc/ieeehalfprecision.c [new file with mode: 0644]
lib/misc/lecp.c [new file with mode: 0644]
lib/misc/lejp.c
lib/misc/lws-ring.c
lib/misc/lws-struct-lejp.c
lib/misc/lws-struct-sqlite.c
lib/misc/lwsac/README.md
lib/misc/lwsac/cached-file.c
lib/misc/lwsac/lwsac.c
lib/misc/lwsac/lwsac.cxx [new file with mode: 0644]
lib/misc/lwsac/private-lib-misc-lwsac.h [new file with mode: 0644]
lib/misc/lwsac/private.h [deleted file]
lib/misc/peer-limits.c
lib/misc/prng.c [new file with mode: 0644]
lib/misc/romfs.c
lib/misc/sha-1.c
lib/misc/threadpool/threadpool.c
lib/plat/esp32/esp32-fds.c [deleted file]
lib/plat/esp32/esp32-helpers.c [deleted file]
lib/plat/esp32/esp32-misc.c [deleted file]
lib/plat/esp32/esp32-pipe.c [deleted file]
lib/plat/esp32/esp32-sockets.c [deleted file]
lib/plat/esp32/private.h [deleted file]
lib/plat/freertos/CMakeLists.txt [new file with mode: 0644]
lib/plat/freertos/esp32/drivers/gpio-esp32.c [new file with mode: 0644]
lib/plat/freertos/esp32/drivers/lws-plat-gpio.h [new file with mode: 0644]
lib/plat/freertos/esp32/drivers/netdev/wifi-esp32.c [new file with mode: 0644]
lib/plat/freertos/esp32/drivers/pwm-esp32.c [new file with mode: 0644]
lib/plat/freertos/esp32/drivers/settings-esp32.c [new file with mode: 0644]
lib/plat/freertos/esp32/esp_attr.h [moved from lib/plat/esp32/esp_attr.h with 100% similarity]
lib/plat/freertos/freertos-fds.c [new file with mode: 0644]
lib/plat/freertos/freertos-file.c [moved from lib/plat/esp32/esp32-file.c with 67% similarity]
lib/plat/freertos/freertos-init.c [moved from lib/plat/esp32/esp32-init.c with 56% similarity]
lib/plat/freertos/freertos-misc.c [new file with mode: 0644]
lib/plat/freertos/freertos-pipe.c [new file with mode: 0644]
lib/plat/freertos/freertos-resolv.c [new file with mode: 0644]
lib/plat/freertos/freertos-service.c [moved from lib/plat/esp32/esp32-service.c with 63% similarity]
lib/plat/freertos/freertos-sockets.c [new file with mode: 0644]
lib/plat/freertos/private-lib-plat-freertos.h [new file with mode: 0644]
lib/plat/optee/CMakeLists.txt [new file with mode: 0644]
lib/plat/optee/lws-plat-optee.c
lib/plat/optee/network.c
lib/plat/optee/private-lib-plat-optee.h [new file with mode: 0644]
lib/plat/optee/private.h [deleted file]
lib/plat/unix/CMakeLists.txt [new file with mode: 0644]
lib/plat/unix/android/android-resolv.c [new file with mode: 0644]
lib/plat/unix/private-lib-plat-unix.h [moved from lib/plat/unix/private.h with 63% similarity]
lib/plat/unix/unix-caps.c
lib/plat/unix/unix-fds.c
lib/plat/unix/unix-file.c
lib/plat/unix/unix-init.c
lib/plat/unix/unix-misc.c
lib/plat/unix/unix-pipe.c
lib/plat/unix/unix-plugins.c
lib/plat/unix/unix-resolv.c [new file with mode: 0644]
lib/plat/unix/unix-service.c
lib/plat/unix/unix-sockets.c
lib/plat/unix/unix-spawn.c [new file with mode: 0644]
lib/plat/windows/CMakeLists.txt [new file with mode: 0644]
lib/plat/windows/private-lib-plat-windows.h [moved from lib/plat/windows/private.h with 60% similarity]
lib/plat/windows/windows-fds.c
lib/plat/windows/windows-file.c
lib/plat/windows/windows-init.c
lib/plat/windows/windows-misc.c
lib/plat/windows/windows-pipe.c
lib/plat/windows/windows-plugins.c
lib/plat/windows/windows-resolv.c [new file with mode: 0644]
lib/plat/windows/windows-service.c
lib/plat/windows/windows-sockets.c
lib/plat/windows/windows-spawn.c [new file with mode: 0644]
lib/roles/CMakeLists.txt [new file with mode: 0644]
lib/roles/README.md
lib/roles/cgi/CMakeLists.txt [new file with mode: 0644]
lib/roles/cgi/cgi-server.c
lib/roles/cgi/ops-cgi.c
lib/roles/cgi/private-lib-roles-cgi.h [new file with mode: 0644]
lib/roles/cgi/private.h [deleted file]
lib/roles/dbus/CMakeLists.txt [new file with mode: 0644]
lib/roles/dbus/dbus.c
lib/roles/dbus/private-lib-roles-dbus.h [new file with mode: 0644]
lib/roles/dbus/private.h [deleted file]
lib/roles/h1/CMakeLists.txt [new file with mode: 0644]
lib/roles/h1/ops-h1.c
lib/roles/h1/private-lib-roles-h1.h [new file with mode: 0644]
lib/roles/h1/private.h [deleted file]
lib/roles/h2/CMakeLists.txt [new file with mode: 0644]
lib/roles/h2/hpack.c
lib/roles/h2/http2.c
lib/roles/h2/minihuf.c
lib/roles/h2/ops-h2.c
lib/roles/h2/private-lib-roles-h2.h [moved from lib/roles/h2/private.h with 79% similarity]
lib/roles/http/CMakeLists.txt [new file with mode: 0644]
lib/roles/http/client/client-handshake.c [deleted file]
lib/roles/http/client/client-http.c [new file with mode: 0644]
lib/roles/http/client/client.c [deleted file]
lib/roles/http/compression/README.md
lib/roles/http/compression/brotli/brotli.c
lib/roles/http/compression/deflate/deflate.c
lib/roles/http/compression/private-lib-roles-http-compression.h [moved from lib/roles/http/compression/private.h with 59% similarity]
lib/roles/http/compression/stream.c
lib/roles/http/cookie.c [new file with mode: 0644]
lib/roles/http/date.c [new file with mode: 0644]
lib/roles/http/header.c
lib/roles/http/lextable-strings.h
lib/roles/http/lextable.h
lib/roles/http/minilex.c
lib/roles/http/parsers.c [moved from lib/roles/http/server/parsers.c with 63% similarity]
lib/roles/http/private-lib-roles-http.h [moved from lib/roles/http/private.h with 72% similarity]
lib/roles/http/server/access-log.c
lib/roles/http/server/fops-zip.c
lib/roles/http/server/lejp-conf.c
lib/roles/http/server/lws-spa.c
lib/roles/http/server/ranges.c
lib/roles/http/server/rewrite.c
lib/roles/http/server/server.c
lib/roles/listen/CMakeLists.txt [new file with mode: 0644]
lib/roles/listen/ops-listen.c
lib/roles/mqtt/CMakeLists.txt [new file with mode: 0644]
lib/roles/mqtt/client/client-mqtt-handshake.c [new file with mode: 0644]
lib/roles/mqtt/client/client-mqtt.c [new file with mode: 0644]
lib/roles/mqtt/mqtt.c [new file with mode: 0644]
lib/roles/mqtt/ops-mqtt.c [new file with mode: 0644]
lib/roles/mqtt/primitives.c [new file with mode: 0644]
lib/roles/mqtt/private-lib-roles-mqtt.h [new file with mode: 0644]
lib/roles/netlink/ops-netlink.c [new file with mode: 0644]
lib/roles/pipe/ops-pipe.c
lib/roles/private-lib-roles.h [new file with mode: 0644]
lib/roles/private.h [deleted file]
lib/roles/raw-file/CMakeLists.txt [new file with mode: 0644]
lib/roles/raw-file/ops-raw-file.c
lib/roles/raw-proxy/CMakeLists.txt [new file with mode: 0644]
lib/roles/raw-proxy/ops-raw-proxy.c
lib/roles/raw-proxy/private-lib-roles-raw-proxy.h [new file with mode: 0644]
lib/roles/raw-proxy/private.h [deleted file]
lib/roles/raw-skt/CMakeLists.txt [new file with mode: 0644]
lib/roles/raw-skt/ops-raw-skt.c
lib/roles/ws/CMakeLists.txt [new file with mode: 0644]
lib/roles/ws/client-parser-ws.c
lib/roles/ws/client-ws.c
lib/roles/ws/ext/extension-permessage-deflate.c
lib/roles/ws/ext/extension-permessage-deflate.h
lib/roles/ws/ext/extension.c
lib/roles/ws/ops-ws.c
lib/roles/ws/private-lib-roles-ws.h [moved from lib/roles/ws/private.h with 74% similarity]
lib/roles/ws/server-ws.c
lib/secure-streams/CMakeLists.txt [new file with mode: 0644]
lib/secure-streams/README.md [new file with mode: 0644]
lib/secure-streams/cpp/README.md [new file with mode: 0644]
lib/secure-streams/cpp/lss.cxx [new file with mode: 0644]
lib/secure-streams/cpp/lssFile.cxx [new file with mode: 0644]
lib/secure-streams/cpp/lssMsg.cxx [new file with mode: 0644]
lib/secure-streams/plugins/ssp-h1url/h1url.c [new file with mode: 0644]
lib/secure-streams/policy-common.c [new file with mode: 0644]
lib/secure-streams/policy-json.c [new file with mode: 0644]
lib/secure-streams/private-lib-secure-streams.h [new file with mode: 0644]
lib/secure-streams/protocols/README.md [new file with mode: 0644]
lib/secure-streams/protocols/ss-h1.c [new file with mode: 0644]
lib/secure-streams/protocols/ss-h2.c [new file with mode: 0644]
lib/secure-streams/protocols/ss-mqtt.c [new file with mode: 0644]
lib/secure-streams/protocols/ss-raw.c [new file with mode: 0644]
lib/secure-streams/protocols/ss-ws.c [new file with mode: 0644]
lib/secure-streams/secure-streams-client.c [new file with mode: 0644]
lib/secure-streams/secure-streams-process.c [new file with mode: 0644]
lib/secure-streams/secure-streams-serialize.c [new file with mode: 0644]
lib/secure-streams/secure-streams.c [new file with mode: 0644]
lib/secure-streams/system/auth-api.amazon.com/auth.c [new file with mode: 0644]
lib/secure-streams/system/auth-sigv4/sign.c [new file with mode: 0644]
lib/secure-streams/system/captive-portal-detect/captive-portal-detect.c [new file with mode: 0644]
lib/secure-streams/system/fetch-policy/fetch-policy.c [new file with mode: 0644]
lib/system/CMakeLists.txt [new file with mode: 0644]
lib/system/README.md [new file with mode: 0644]
lib/system/async-dns/async-dns-parse.c [new file with mode: 0644]
lib/system/async-dns/async-dns.c [new file with mode: 0644]
lib/system/async-dns/private-lib-async-dns.h [new file with mode: 0644]
lib/system/dhcpclient/dhcpc4.c [new file with mode: 0644]
lib/system/dhcpclient/dhcpclient.c [new file with mode: 0644]
lib/system/dhcpclient/private-lib-system-dhcpclient.h [new file with mode: 0644]
lib/system/fault-injection/fault-injection.c [new file with mode: 0644]
lib/system/fault-injection/private-lib-system-fault-injection.h [new file with mode: 0644]
lib/system/metrics/CMakeLists.txt [new file with mode: 0644]
lib/system/metrics/metrics.c [new file with mode: 0644]
lib/system/metrics/private-lib-system-metrics.h [new file with mode: 0644]
lib/system/ntpclient/ntpclient.c [new file with mode: 0644]
lib/system/smd/CMakeLists.txt [new file with mode: 0644]
lib/system/smd/README.md [new file with mode: 0644]
lib/system/smd/private-lib-system-smd.h [new file with mode: 0644]
lib/system/smd/smd.c [new file with mode: 0644]
lib/system/system.c [new file with mode: 0644]
lib/tls/CMakeLists.txt [new file with mode: 0644]
lib/tls/lws-gencrypto-common.c
lib/tls/lws-genec-common.c
lib/tls/mbedtls/CMakeLists.txt [new file with mode: 0644]
lib/tls/mbedtls/lws-genaes.c
lib/tls/mbedtls/lws-gencrypto.c
lib/tls/mbedtls/lws-genec.c
lib/tls/mbedtls/lws-genhash.c
lib/tls/mbedtls/lws-genrsa.c
lib/tls/mbedtls/mbedtls-client.c
lib/tls/mbedtls/mbedtls-extensions.c [new file with mode: 0644]
lib/tls/mbedtls/mbedtls-server.c
lib/tls/mbedtls/mbedtls-session.c [new file with mode: 0644]
lib/tls/mbedtls/mbedtls-ssl.c [moved from lib/tls/mbedtls/ssl.c with 56% similarity]
lib/tls/mbedtls/mbedtls-tls.c [new file with mode: 0644]
lib/tls/mbedtls/mbedtls-x509.c [new file with mode: 0644]
lib/tls/mbedtls/private-lib-tls-mbedtls.h [new file with mode: 0644]
lib/tls/mbedtls/private.h [deleted file]
lib/tls/mbedtls/tls.c [deleted file]
lib/tls/mbedtls/wrapper/include/internal/ssl_cert.h
lib/tls/mbedtls/wrapper/include/internal/ssl_dbg.h
lib/tls/mbedtls/wrapper/include/internal/ssl_pkey.h
lib/tls/mbedtls/wrapper/include/internal/ssl_types.h
lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h
lib/tls/mbedtls/wrapper/include/openssl/ssl.h
lib/tls/mbedtls/wrapper/include/platform/ssl_pm.h
lib/tls/mbedtls/wrapper/library/ssl_cert.c
lib/tls/mbedtls/wrapper/library/ssl_lib.c
lib/tls/mbedtls/wrapper/library/ssl_methods.c
lib/tls/mbedtls/wrapper/library/ssl_pkey.c
lib/tls/mbedtls/wrapper/library/ssl_stack.c
lib/tls/mbedtls/wrapper/library/ssl_x509.c
lib/tls/mbedtls/wrapper/platform/ssl_pm.c
lib/tls/mbedtls/x509.c [deleted file]
lib/tls/openssl/lws-genaes.c
lib/tls/openssl/lws-gencrypto.c
lib/tls/openssl/lws-genec.c
lib/tls/openssl/lws-genhash.c
lib/tls/openssl/lws-genrsa.c
lib/tls/openssl/openssl-client.c
lib/tls/openssl/openssl-server.c
lib/tls/openssl/openssl-session.c [new file with mode: 0644]
lib/tls/openssl/openssl-ssl.c [moved from lib/tls/openssl/ssl.c with 63% similarity]
lib/tls/openssl/openssl-tls.c [new file with mode: 0644]
lib/tls/openssl/openssl-x509.c [moved from lib/tls/openssl/x509.c with 68% similarity]
lib/tls/openssl/private-lib-tls-openssl.h [new file with mode: 0644]
lib/tls/openssl/private.h [deleted file]
lib/tls/openssl/tls.c [deleted file]
lib/tls/private-jit-trust.h [new file with mode: 0644]
lib/tls/private-lib-tls.h [moved from lib/tls/private.h with 53% similarity]
lib/tls/private-network.h
lib/tls/tls-client.c
lib/tls/tls-jit-trust.c [new file with mode: 0644]
lib/tls/tls-network.c
lib/tls/tls-server.c
lib/tls/tls-sessions.c [new file with mode: 0644]
lib/tls/tls.c
libwebsockets.dox
lwsws/CMakeLists.txt [new file with mode: 0644]
lwsws/main.c
minimal-examples/CMakeLists.txt [new file with mode: 0644]
minimal-examples/README.md
minimal-examples/abstract/protocols/smtp-client/CMakeLists.txt
minimal-examples/abstract/protocols/smtp-client/main.c
minimal-examples/api-tests/api-test-async-dns/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-async-dns/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-cose/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-cose/README.md [new file with mode: 0644]
minimal-examples/api-tests/api-test-cose/keys.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-cose/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-cose/sign.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-dhcpc/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-dhcpc/README.md [new file with mode: 0644]
minimal-examples/api-tests/api-test-dhcpc/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-fts/CMakeLists.txt
minimal-examples/api-tests/api-test-fts/main.c
minimal-examples/api-tests/api-test-fts/selftest.sh [deleted file]
minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt
minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c
minimal-examples/api-tests/api-test-gencrypto/main.c
minimal-examples/api-tests/api-test-gencrypto/selftest.sh [deleted file]
minimal-examples/api-tests/api-test-jose/CMakeLists.txt
minimal-examples/api-tests/api-test-jose/jwe.c
minimal-examples/api-tests/api-test-jose/jws.c
minimal-examples/api-tests/api-test-jose/main.c
minimal-examples/api-tests/api-test-jose/selftest.sh [deleted file]
minimal-examples/api-tests/api-test-lecp/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-lecp/README.md [new file with mode: 0644]
minimal-examples/api-tests/api-test-lecp/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-lejp/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-lejp/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_cache/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_cache/README.md [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_cache/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_cache/text1.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_dsh/CMakeLists.txt
minimal-examples/api-tests/api-test-lws_dsh/main.c
minimal-examples/api-tests/api-test-lws_dsh/selftest.sh [deleted file]
minimal-examples/api-tests/api-test-lws_map/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_map/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_sequencer/CMakeLists.txt
minimal-examples/api-tests/api-test-lws_sequencer/libwebsockets.org.cer
minimal-examples/api-tests/api-test-lws_sequencer/main.c
minimal-examples/api-tests/api-test-lws_smd/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_smd/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_struct-json/CMakeLists.txt
minimal-examples/api-tests/api-test-lws_struct-json/README.md
minimal-examples/api-tests/api-test-lws_struct-json/main.c
minimal-examples/api-tests/api-test-lws_struct-json/selftest.sh [deleted file]
minimal-examples/api-tests/api-test-lws_struct-json/test2.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_struct_sqlite/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_struct_sqlite/README.md [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_struct_sqlite/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-lws_tokenize/CMakeLists.txt
minimal-examples/api-tests/api-test-lws_tokenize/main.c
minimal-examples/api-tests/api-test-lws_tokenize/selftest.sh [deleted file]
minimal-examples/api-tests/api-test-lwsac/CMakeLists.txt
minimal-examples/api-tests/api-test-lwsac/selftest.sh [deleted file]
minimal-examples/api-tests/api-test-secure-streams/CMakeLists.txt [new file with mode: 0644]
minimal-examples/api-tests/api-test-secure-streams/README.md [new file with mode: 0644]
minimal-examples/api-tests/api-test-secure-streams/main.c [new file with mode: 0644]
minimal-examples/api-tests/api-test-smtp_client/CMakeLists.txt
minimal-examples/api-tests/api-test-smtp_client/main.c
minimal-examples/client-server/minimal-ws-proxy/CMakeLists.txt
minimal-examples/client-server/minimal-ws-proxy/minimal-ws-proxy.c
minimal-examples/client-server/minimal-ws-proxy/mount-origin/example.js
minimal-examples/client-server/minimal-ws-proxy/mount-origin/libwebsockets.org-logo.svg
minimal-examples/client-server/minimal-ws-proxy/protocol_lws_minimal.c
minimal-examples/crypto/minimal-crypto-cose-key/CMakeLists.txt [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-key/README.md [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-key/main.c [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-key/set1.cks [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass01.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass02.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass03.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-key/sign_pass01.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-key/sign_pass02.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-key/sign_pass03.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/CMakeLists.txt [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/README.md [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/main.c [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/payload.txt [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/rsa-4096.ck [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/set1.cks [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/sign-rsa4096.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass01.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass02.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass03.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/sign_pass01.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/sign_pass02.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-cose-sign/sign_pass03.sig [new file with mode: 0644]
minimal-examples/crypto/minimal-crypto-jwe/CMakeLists.txt
minimal-examples/crypto/minimal-crypto-jwe/main.c
minimal-examples/crypto/minimal-crypto-jwk/CMakeLists.txt
minimal-examples/crypto/minimal-crypto-jwk/main.c
minimal-examples/crypto/minimal-crypto-jws/CMakeLists.txt
minimal-examples/crypto/minimal-crypto-jws/main.c
minimal-examples/crypto/minimal-crypto-x509/CMakeLists.txt
minimal-examples/crypto/minimal-crypto-x509/main.c
minimal-examples/dbus-client/minimal-dbus-client/CMakeLists.txt
minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/CMakeLists.txt
minimal-examples/dbus-client/minimal-dbus-ws-proxy-testclient/minimal-dbus-ws-proxy-testclient.c
minimal-examples/dbus-server/minimal-dbus-server/CMakeLists.txt
minimal-examples/dbus-server/minimal-dbus-ws-proxy/CMakeLists.txt
minimal-examples/dbus-server/minimal-dbus-ws-proxy/main.c
minimal-examples/dbus-server/minimal-dbus-ws-proxy/protocol_lws_minimal_dbus_ws_proxy.c
minimal-examples/embedded/esp32/esp-c3dev/CMakeLists.txt [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/lws-button.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/CMakeLists.txt [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/bb-i2c.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/bb-i2c.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/component.mk [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/devices.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/gpio-esp32.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/gpio-esp32.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/gpio.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/i2c.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/i2c.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/lws-minimal-esp32.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/main/policy.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/partitions.csv [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/private-lib-plat-freertos.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/sdkconfig [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-c3dev/sdkconfig.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/CMakeLists.txt [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/banded-img.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/main/CMakeLists.txt [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/main/devices.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/main/lws-minimal-esp32.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/main/policy.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/partitions.csv [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/scan/output.bmp [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/scan/pic.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/scan/pic.h.1 [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan [new file with mode: 0755]
minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan.sh [new file with mode: 0755]
minimal-examples/embedded/esp32/esp-heltec-wb32/sdkconfig [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-heltec-wb32/sdkconfig.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/CMakeLists.txt [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/main/CMakeLists.txt [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/main/cat-565.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/main/devices.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/main/lws-minimal-esp32.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/main/policy.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/main/static-policy.h [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/partitions.csv [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/rgb565/rgb565.c [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/sdkconfig [new file with mode: 0644]
minimal-examples/embedded/esp32/esp-wrover-kit/sdkconfig.h [new file with mode: 0644]
minimal-examples/gtk/minimal-gtk/CMakeLists.txt [new file with mode: 0644]
minimal-examples/gtk/minimal-gtk/README.md [new file with mode: 0644]
minimal-examples/gtk/minimal-gtk/main.c [new file with mode: 0644]
minimal-examples/gtk/minimal-gtk/warmcat.com.cer [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-attach/CMakeLists.txt [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-attach/README.md [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-attach/minimal-http-client-attach.c [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-captive-portal/CMakeLists.txt [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-captive-portal/README.md [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-captive-portal/minimal-http-client-captive-portal.c [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-certinfo/CMakeLists.txt
minimal-examples/http-client/minimal-http-client-certinfo/minimal-http-client-certinfo.c
minimal-examples/http-client/minimal-http-client-certinfo/warmcat.com.cer
minimal-examples/http-client/minimal-http-client-custom-headers/CMakeLists.txt
minimal-examples/http-client/minimal-http-client-custom-headers/minimal-http-client-custom-headers.c
minimal-examples/http-client/minimal-http-client-custom-headers/warmcat.com.cer
minimal-examples/http-client/minimal-http-client-h2-rxflow/CMakeLists.txt [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-h2-rxflow/README.md [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-h2-rxflow/minimal-http-client.c [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-h2-rxflow/warmcat.com.cer [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-hugeurl/CMakeLists.txt
minimal-examples/http-client/minimal-http-client-hugeurl/minimal-http-client-hugeurl.c
minimal-examples/http-client/minimal-http-client-hugeurl/selftest.sh [deleted file]
minimal-examples/http-client/minimal-http-client-hugeurl/warmcat.com.cer
minimal-examples/http-client/minimal-http-client-jit-trust/CMakeLists.txt [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-jit-trust/README.md [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-jit-trust/minimal-http-client.c [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-jit-trust/trust_blob.h [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-jit-trust/warmcat.com.cer [new file with mode: 0644]
minimal-examples/http-client/minimal-http-client-multi/CMakeLists.txt
minimal-examples/http-client/minimal-http-client-multi/README.md
minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c
minimal-examples/http-client/minimal-http-client-multi/selftest.sh [deleted file]
minimal-examples/http-client/minimal-http-client-multi/warmcat.com.cer
minimal-examples/http-client/minimal-http-client-post/CMakeLists.txt
minimal-examples/http-client/minimal-http-client-post/libwebsockets.org.cer
minimal-examples/http-client/minimal-http-client-post/minimal-http-client-post.c
minimal-examples/http-client/minimal-http-client-post/selftest.sh [deleted file]
minimal-examples/http-client/minimal-http-client/CMakeLists.txt
minimal-examples/http-client/minimal-http-client/README.md
minimal-examples/http-client/minimal-http-client/minimal-http-client.c
minimal-examples/http-client/minimal-http-client/selftest.sh [deleted file]
minimal-examples/http-client/minimal-http-client/warmcat.com.cer
minimal-examples/http-client/minimal-http-client/wrong.cer [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-basicauth/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-basicauth/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-basicauth/mount-secret-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-cgi/CMakeLists.txt [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-cgi/README.md [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-cgi/minimal-http-server.c [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-cgi/my-cgi-script.sh [new file with mode: 0755]
minimal-examples/http-server/minimal-http-server-custom-headers/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-custom-headers/minimal-http-server-custom-headers.c
minimal-examples/http-server/minimal-http-server-custom-headers/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-deaddrop/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-deaddrop/minimal-http-server-deaddrop.c
minimal-examples/http-server/minimal-http-server-deaddrop/mount-origin/deaddrop.js
minimal-examples/http-server/minimal-http-server-deaddrop/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-dynamic/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-dynamic/minimal-http-server-dynamic.c
minimal-examples/http-server/minimal-http-server-dynamic/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-eventlib-custom/CMakeLists.txt [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-custom/README.md [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-custom/minimal-http-server.c [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/404.html [moved from minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/404.html with 58% similarity]
minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/favicon.ico [moved from minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/favicon.ico with 100% similarity]
minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/index.html [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/libwebsockets.org-logo.svg [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/strict-csp.svg [moved from minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/strict-csp.svg with 100% similarity]
minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/symlink.html [new symlink]
minimal-examples/http-server/minimal-http-server-eventlib-demos/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-eventlib-demos/minimal-http-server-eventlib-demos.c
minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide-uncompressed.zip [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/lws-common.js
minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md
minimal-examples/http-server/minimal-http-server-eventlib-foreign/glib.c [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-foreign/libev.c [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-foreign/libevent.c [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-foreign/libsdevent.c [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-foreign/libuv.c [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c
minimal-examples/http-server/minimal-http-server-eventlib-foreign/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-foreign/uloop.c [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-eventlib-smp/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-eventlib-smp/minimal-http-server-eventlib-smp.c
minimal-examples/http-server/minimal-http-server-eventlib-smp/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-eventlib/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-eventlib/minimal-http-server-eventlib.c
minimal-examples/http-server/minimal-http-server-eventlib/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-form-get/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-form-get/minimal-http-server-form-get.c
minimal-examples/http-server/minimal-http-server-form-get/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-form-post-file/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-form-post-file/minimal-http-server-form-post-file.c
minimal-examples/http-server/minimal-http-server-form-post-file/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-form-post-lwsac/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-form-post-lwsac/minimal-http-server-form-post.c
minimal-examples/http-server/minimal-http-server-form-post/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-form-post/minimal-http-server-form-post.c
minimal-examples/http-server/minimal-http-server-form-post/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-fulltext-search/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-fulltext-search/minimal-http-server.c
minimal-examples/http-server/minimal-http-server-fulltext-search/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-fulltext-search/mount-origin/lws-fts.js
minimal-examples/http-server/minimal-http-server-generic-sessions/CMakeLists.txt [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/README.md [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/minimal-http-server-generic-sessions.c [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/admin-login.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/example.js [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/failed-login.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/http2.png [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/index.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/libwebsockets.org-logo.svg [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lws-common.js [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs-logo.png [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.css [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.js [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/md5.min.js [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needadmin/admin-login.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needauth/successful-login.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-fail.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-ok.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-fail.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-ok.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-fail.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-ok.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/seats.jpg [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-fail.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-ok.html [deleted file]
minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/successful-login.html [deleted file]
minimal-examples/http-server/minimal-http-server-h2-long-poll/CMakeLists.txt [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-h2-long-poll/README.md [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-h2-long-poll/localhost-100y.cert [moved from minimal-examples/http-server/minimal-http-server-generic-sessions/localhost-100y.cert with 100% similarity]
minimal-examples/http-server/minimal-http-server-h2-long-poll/localhost-100y.key [moved from minimal-examples/http-server/minimal-http-server-generic-sessions/localhost-100y.key with 100% similarity]
minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c [new file with mode: 0644]
minimal-examples/http-server/minimal-http-server-mimetypes/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-mimetypes/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-multivhost/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-multivhost/minimal-http-server.c
minimal-examples/http-server/minimal-http-server-multivhost/mount-origin-localhost1/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-multivhost/mount-origin-localhost2/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-multivhost/mount-origin-localhost3/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-proxy/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-smp/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-smp/README.md
minimal-examples/http-server/minimal-http-server-smp/minimal-http-server-smp.c
minimal-examples/http-server/minimal-http-server-smp/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-sse-ring/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-sse-ring/minimal-http-server-sse-ring.c
minimal-examples/http-server/minimal-http-server-sse-ring/mount-origin/example.js
minimal-examples/http-server/minimal-http-server-sse-ring/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-sse/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-sse/minimal-http-server-sse.c
minimal-examples/http-server/minimal-http-server-sse/mount-origin/example.js
minimal-examples/http-server/minimal-http-server-sse/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-tls-80/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-tls-80/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-tls-mem/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-tls-mem/minimal-http-server-tls-mem.c
minimal-examples/http-server/minimal-http-server-tls-mem/mount-origin/example.js
minimal-examples/http-server/minimal-http-server-tls-mem/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server-tls/CMakeLists.txt
minimal-examples/http-server/minimal-http-server-tls/minimal-http-server-tls.c
minimal-examples/http-server/minimal-http-server-tls/mount-origin/example.js
minimal-examples/http-server/minimal-http-server-tls/mount-origin/libwebsockets.org-logo.svg
minimal-examples/http-server/minimal-http-server/CMakeLists.txt
minimal-examples/http-server/minimal-http-server/minimal-http-server.c
minimal-examples/http-server/minimal-http-server/mount-origin/libwebsockets.org-logo.svg
minimal-examples/mqtt-client/README.md [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client-multi/CMakeLists.txt [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client-multi/README.md [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client-multi/minimal-mqtt-client-multi.c [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client-multi/selftest.sh.broken-on-travis [moved from minimal-examples/ws-client/minimal-ws-client-spam/selftest.sh with 77% similarity]
minimal-examples/mqtt-client/minimal-mqtt-client-multi/warmcat.com.cer [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client-multi/wget-log [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client/CMakeLists.txt [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client/README.md [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client/minimal-mqtt-client.c [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client/mosq-ca.crt [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client/mosq-server.crt [new file with mode: 0644]
minimal-examples/mqtt-client/minimal-mqtt-client/mosq-server.key [new file with mode: 0644]
minimal-examples/raw/minimal-raw-adopt-tcp/CMakeLists.txt
minimal-examples/raw/minimal-raw-adopt-tcp/minimal-raw-adopt-tcp.c
minimal-examples/raw/minimal-raw-adopt-udp/CMakeLists.txt
minimal-examples/raw/minimal-raw-adopt-udp/minimal-raw-adopt-udp.c
minimal-examples/raw/minimal-raw-audio/CMakeLists.txt [new file with mode: 0644]
minimal-examples/raw/minimal-raw-audio/README.md [new file with mode: 0644]
minimal-examples/raw/minimal-raw-audio/audio.c [new file with mode: 0644]
minimal-examples/raw/minimal-raw-fallback-http-server/CMakeLists.txt
minimal-examples/raw/minimal-raw-fallback-http-server/minimal-raw-fallback-http-server.c
minimal-examples/raw/minimal-raw-fallback-http-server/mount-origin/libwebsockets.org-logo.svg
minimal-examples/raw/minimal-raw-file/CMakeLists.txt
minimal-examples/raw/minimal-raw-file/minimal-raw-file.c
minimal-examples/raw/minimal-raw-netcat/CMakeLists.txt
minimal-examples/raw/minimal-raw-netcat/minimal-raw-netcat.c
minimal-examples/raw/minimal-raw-proxy-fallback/CMakeLists.txt
minimal-examples/raw/minimal-raw-proxy-fallback/minimal-raw-proxy-fallback.c
minimal-examples/raw/minimal-raw-proxy-fallback/mount-origin/libwebsockets.org-logo.svg
minimal-examples/raw/minimal-raw-proxy/CMakeLists.txt
minimal-examples/raw/minimal-raw-proxy/minimal-raw-proxy.c
minimal-examples/raw/minimal-raw-serial/CMakeLists.txt [new file with mode: 0644]
minimal-examples/raw/minimal-raw-serial/README.md [new file with mode: 0644]
minimal-examples/raw/minimal-raw-serial/minimal-raw-file.c [new file with mode: 0644]
minimal-examples/raw/minimal-raw-vhost/CMakeLists.txt
minimal-examples/raw/minimal-raw-vhost/minimal-raw-vhost.c
minimal-examples/secure-streams/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-alexa/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-alexa/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa_linux.ppn [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-alexa/audio.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-alexa/main.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-alexa/porcupine_params.pv [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-alexa/private.h [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-avs/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-avs/main-client.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-avs/main.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-avs/year.wav [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-binance/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-binance/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-binance/main.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-binance/policy.json [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-blob/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-blob/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-blob/minimal-secure-streams.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-client-tx/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-client-tx/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-client-tx/minimal-secure-streams-client-tx.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-cpp/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-cpp/main.cxx [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-hugeurl/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-hugeurl/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-hugeurl/minimal-secure-streams.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-metadata/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-metadata/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-metadata/minimal-secure-streams.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-metrics-proxy/metrics-proxy-policy.json [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-perf/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-perf/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-perf/minimal-secure-streams.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-policy2c/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-policy2c/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-policy2c/minimal-secure-streams.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-post/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-post/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-post/minimal-secure-streams-post.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-proxy/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-proxy/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-proxy/main.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-seq/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-seq/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-seq/minimal-secure-streams.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-server-raw/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-server-raw/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-server-raw/main.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-server-raw/ss-server.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-server/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-server/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-server/main.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-server/ss-client.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-sigv4/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-sigv4/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-sigv4/policy.json [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-sigv4/ss-s3-main.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-sigv4/ss-s3-put.h [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-sigv4/ss-s3-ss.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-sigv4/static_policy.h [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-smd/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-smd/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-smd/minimal-secure-streams-smd.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-smd/multi.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/minimal-secure-streams.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/static-policy.h [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/static-policy.json [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-stress/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-stress/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-stress/minimal-secure-streams.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-testsfail/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-testsfail/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-threads/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-threads/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams-threads/minimal-secure-streams-threads.c [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams/CMakeLists.txt [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams/README.md [new file with mode: 0644]
minimal-examples/secure-streams/minimal-secure-streams/minimal-secure-streams.c [new file with mode: 0644]
minimal-examples/selftests-library.sh [deleted file]
minimal-examples/selftests.sh [deleted file]
minimal-examples/ws-client/README.md
minimal-examples/ws-client/minimal-ws-client-binance/CMakeLists.txt [new file with mode: 0644]
minimal-examples/ws-client/minimal-ws-client-binance/README.md [new file with mode: 0644]
minimal-examples/ws-client/minimal-ws-client-binance/main.c [new file with mode: 0644]
minimal-examples/ws-client/minimal-ws-client-echo/CMakeLists.txt
minimal-examples/ws-client/minimal-ws-client-echo/minimal-ws-client-echo.c
minimal-examples/ws-client/minimal-ws-client-echo/protocol_lws_minimal_client_echo.c
minimal-examples/ws-client/minimal-ws-client-ping/CMakeLists.txt
minimal-examples/ws-client/minimal-ws-client-ping/README.md
minimal-examples/ws-client/minimal-ws-client-ping/libwebsockets.org.cer
minimal-examples/ws-client/minimal-ws-client-ping/minimal-ws-client-ping.c
minimal-examples/ws-client/minimal-ws-client-pmd-bulk/CMakeLists.txt
minimal-examples/ws-client/minimal-ws-client-pmd-bulk/minimal-ws-client-pmd-bulk.c
minimal-examples/ws-client/minimal-ws-client-pmd-bulk/protocol_lws_minimal_pmd_bulk.c
minimal-examples/ws-client/minimal-ws-client-rx/CMakeLists.txt
minimal-examples/ws-client/minimal-ws-client-rx/libwebsockets.org.cer
minimal-examples/ws-client/minimal-ws-client-rx/minimal-ws-client.c
minimal-examples/ws-client/minimal-ws-client-rx/selftest.sh [deleted file]
minimal-examples/ws-client/minimal-ws-client-spam-tx-rx/CMakeLists.txt [new file with mode: 0644]
minimal-examples/ws-client/minimal-ws-client-spam-tx-rx/libwebsockets.org.cer [new file with mode: 0644]
minimal-examples/ws-client/minimal-ws-client-spam-tx-rx/minimal-ws-client.c [new file with mode: 0644]
minimal-examples/ws-client/minimal-ws-client-spam/CMakeLists.txt
minimal-examples/ws-client/minimal-ws-client-spam/libwebsockets.org.cer
minimal-examples/ws-client/minimal-ws-client-spam/minimal-ws-client-spam.c
minimal-examples/ws-client/minimal-ws-client-tx/CMakeLists.txt
minimal-examples/ws-client/minimal-ws-client-tx/minimal-ws-client.c
minimal-examples/ws-client/minimal-ws-client/CMakeLists.txt [new file with mode: 0644]
minimal-examples/ws-client/minimal-ws-client/README.md [new file with mode: 0644]
minimal-examples/ws-client/minimal-ws-client/libwebsockets.org.cer [new file with mode: 0644]
minimal-examples/ws-client/minimal-ws-client/minimal-ws-client.c [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-broker/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-broker/minimal-ws-broker.c
minimal-examples/ws-server/minimal-ws-broker/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-broker/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-broker/protocol_lws_minimal.c
minimal-examples/ws-server/minimal-ws-raw-proxy/CMakeLists.txt [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-raw-proxy/README.md [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-raw-proxy/localhost-100y.cert [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-raw-proxy/localhost-100y.key [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-raw-proxy/minimal-ws-raw-proxy.c [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/example.js [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/favicon.ico [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/index.html [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/libwebsockets.org-logo.svg [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/strict-csp.svg [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-echo/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server-echo/minimal-ws-server-echo.c
minimal-examples/ws-server/minimal-ws-server-echo/protocol_lws_minimal_server_echo.c
minimal-examples/ws-server/minimal-ws-server-pmd-bulk/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server-pmd-bulk/minimal-ws-server-pmd-bulk.c
minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-server-pmd-bulk/protocol_lws_minimal_pmd_bulk.c
minimal-examples/ws-server/minimal-ws-server-pmd-corner/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server-pmd-corner/minimal-ws-server-pmd-corner.c
minimal-examples/ws-server/minimal-ws-server-pmd-corner/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-server-pmd-corner/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-server-pmd-corner/protocol_lws_minimal.c
minimal-examples/ws-server/minimal-ws-server-pmd/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server-pmd/minimal-ws-server-pmd.c
minimal-examples/ws-server/minimal-ws-server-pmd/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-server-pmd/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-server-pmd/protocol_lws_minimal.c
minimal-examples/ws-server/minimal-ws-server-ring/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server-ring/minimal-ws-server-ring.c
minimal-examples/ws-server/minimal-ws-server-ring/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-server-ring/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-server-ring/protocol_lws_minimal.c
minimal-examples/ws-server/minimal-ws-server-threadpool/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server-threadpool/minimal-ws-server-threadpool.c
minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-server-threadpool/protocol_lws_minimal_threadpool.c
minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/CMakeLists.txt [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/README.md [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/minimal-ws-server.c [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/example.js [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/favicon.ico [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/index.html [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/libwebsockets.org-logo.svg [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/strict-csp.svg [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/protocol_lws_minimal.c [new file with mode: 0644]
minimal-examples/ws-server/minimal-ws-server-threads-smp/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server-threads-smp/minimal-ws-server.c
minimal-examples/ws-server/minimal-ws-server-threads-smp/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-server-threads-smp/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-server-threads-smp/protocol_lws_minimal.c
minimal-examples/ws-server/minimal-ws-server-threads/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server-threads/minimal-ws-server.c
minimal-examples/ws-server/minimal-ws-server-threads/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-server-threads/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-server-threads/protocol_lws_minimal.c
minimal-examples/ws-server/minimal-ws-server-timer/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server-timer/minimal-ws-server.c
minimal-examples/ws-server/minimal-ws-server-timer/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-server-timer/mount-origin/favicon.ico
minimal-examples/ws-server/minimal-ws-server-timer/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-server/CMakeLists.txt
minimal-examples/ws-server/minimal-ws-server/README.md
minimal-examples/ws-server/minimal-ws-server/minimal-ws-server.c
minimal-examples/ws-server/minimal-ws-server/mount-origin/example.js
minimal-examples/ws-server/minimal-ws-server/mount-origin/libwebsockets.org-logo.svg
minimal-examples/ws-server/minimal-ws-server/protocol_lws_minimal.c
plugin-standalone/CMakeLists.txt
plugin-standalone/protocol_example_standalone.c
plugins/CMakeLists.txt [new file with mode: 0644]
plugins/acme-client/protocol_lws_acme_client.c
plugins/deaddrop/assets/deaddrop.js
plugins/deaddrop/protocol_lws_deaddrop.c
plugins/generic-sessions/assets/admin-login.html [deleted file]
plugins/generic-sessions/assets/failed-login.html [deleted file]
plugins/generic-sessions/assets/index.html [deleted file]
plugins/generic-sessions/assets/lwsgs-logo.png [deleted file]
plugins/generic-sessions/assets/lwsgs.css [deleted file]
plugins/generic-sessions/assets/lwsgs.js [deleted file]
plugins/generic-sessions/assets/md5.min.js [deleted file]
plugins/generic-sessions/assets/post-forgot-fail.html [deleted file]
plugins/generic-sessions/assets/post-forgot-ok.html [deleted file]
plugins/generic-sessions/assets/post-register-fail.html [deleted file]
plugins/generic-sessions/assets/post-register-ok.html [deleted file]
plugins/generic-sessions/assets/post-verify-fail.html [deleted file]
plugins/generic-sessions/assets/post-verify-ok.html [deleted file]
plugins/generic-sessions/assets/seats.jpg [deleted file]
plugins/generic-sessions/assets/sent-forgot-fail.html [deleted file]
plugins/generic-sessions/assets/sent-forgot-ok.html [deleted file]
plugins/generic-sessions/assets/successful-login.html [deleted file]
plugins/generic-sessions/handlers.c [deleted file]
plugins/generic-sessions/private-lwsgs.h [deleted file]
plugins/generic-sessions/protocol_generic_sessions.c [deleted file]
plugins/generic-sessions/protocol_lws_messageboard.c [deleted file]
plugins/generic-sessions/utils.c [deleted file]
plugins/generic-table/assets/index.html [deleted file]
plugins/generic-table/assets/lwsgt.js [deleted file]
plugins/generic-table/protocol_table_dirlisting.c [deleted file]
plugins/protocol_client_loopback_test.c
plugins/protocol_dumb_increment.c
plugins/protocol_esp32_lws_group.c [deleted file]
plugins/protocol_esp32_lws_ota.c [deleted file]
plugins/protocol_esp32_lws_reboot_to_factory.c [deleted file]
plugins/protocol_esp32_lws_scan.c [deleted file]
plugins/protocol_fulltext_demo.c
plugins/protocol_lws_mirror.c
plugins/protocol_lws_openmetrics_export.c [new file with mode: 0644]
plugins/protocol_lws_raw_test.c
plugins/protocol_lws_server_status.c [deleted file]
plugins/protocol_lws_sshd_demo.c
plugins/protocol_lws_status.c
plugins/protocol_post_demo.c
plugins/raw-proxy/protocol_lws_raw_proxy.c
plugins/server-status.html [deleted file]
plugins/server-status.js [deleted file]
plugins/ssh-base/crypto/chacha.c
plugins/ssh-base/crypto/ed25519.c
plugins/ssh-base/crypto/fe25519.c
plugins/ssh-base/crypto/ge25519.c
plugins/ssh-base/crypto/poly1305.c
plugins/ssh-base/crypto/sc25519.c
plugins/ssh-base/crypto/smult_curve25519_ref.c
plugins/ssh-base/include/lws-plugin-ssh.h
plugins/ssh-base/include/lws-ssh.h
plugins/ssh-base/kex-25519.c
plugins/ssh-base/sshd.c
plugins/ssh-base/telnet.c
scripts/ahrefs-topsites.sh [new file with mode: 0755]
scripts/attack.sh
scripts/autobahn-test-server.sh
scripts/client-ca/create-client-cert.sh
scripts/client-ca/create-server-cert.sh
scripts/ctest-background-kill.sh [new file with mode: 0755]
scripts/ctest-background.sh [new file with mode: 0755]
scripts/dox-extra.css [new file with mode: 0644]
scripts/libwebsockets.spec [deleted file]
scripts/mozilla-trust-gen.sh [new file with mode: 0755]
scripts/travis_control.sh
scripts/travis_install.sh
test-apps/CMakeLists.txt [new file with mode: 0644]
test-apps/candide-uncompressed.zip [new file with mode: 0644]
test-apps/libwebsockets.org-logo.svg
test-apps/lws-common.js
test-apps/test-client.c
test-apps/test-lecp.c [new file with mode: 0644]
test-apps/test-lejp.c
test-apps/test-server.c
test-apps/test-sshd.c
win32port/dirent/dirent-win32.h [new file with mode: 0644]
win32port/version.rc.in
win32port/win32helpers/gettimeofday.c
win32port/win32helpers/gettimeofday.h

index 21289f3..47f7a90 100644 (file)
@@ -55,3 +55,12 @@ doc
 /build-mingw64/
 /n9/
 /bb/
+/openssl3/
+/bb-linkit/
+/bq/
+/cros/
+/q/
+/b1/
+/destdir/
+/bb1/
+/bb3/
diff --git a/.sai.json b/.sai.json
new file mode 100644 (file)
index 0000000..7ac992e
--- /dev/null
+++ b/.sai.json
@@ -0,0 +1,323 @@
+{
+       "schema": "sai-1",
+
+       # We're doing separate install into destdir so that the test server
+       # has somewhere to go to find its /usr/share content like certs
+
+       "platforms": {
+               "linux-debian-11/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-debian-buster/x86-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-debian-sid/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-ubuntu-xenial/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-debian-sid/x86-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-debian-sid/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+
+               "linux-ubuntu-1804/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-ubuntu-2004/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-fedora-32/x86_64-amd/gcc": {
+                       "build": "rm -rf build destdir ; mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-gentoo/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G ZIP\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-centos-7/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-centos-8/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-centos-8/aarch64-a72-bcm2711-rpi4/gcc": {
+                       "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "linux-ubuntu-2004/aarch64-a72-bcm2711-rpi4/gcc": {
+                       "build": "mkdir build;cd build;export CCACHE_DISABLE=1;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j3 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j3 --output-on-failure ${cpack}",
+                       "default": false
+               },
+               "linux-android/aarch64/llvm": {
+                       "build": "mkdir build;cd build;cmake .. -DCMAKE_TOOLCHAIN_FILE=../libwebsockets/contrib/cross-aarch64-android.cmake ${cmake} && make -j",
+                       "default": false
+               },
+               "netbsd-iOS/aarch64/llvm": {
+                       "build": "mkdir build destdir; cd build; export SAI_CPACK=\"-G ZIP\";cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make -DCMAKE_IOS_DEVELOPER_ROOT=/opt/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer -DCMAKE_TOOLCHAIN_FILE=contrib/iOS.cmake -DIOS_PLATFORM=OS ${cmake} && make -j",
+                       "default": false
+               },
+               "netbsd-OSX-bigsur/x86_64-intel-i3/llvm": {
+                       "build": "mkdir build destdir; cd build; export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G ZIP\";export MACOSX_DEPLOYMENT_TARGET=10.15 ; cmake .. -DCMAKE_MAKE_PROGRAM=/usr/bin/make -DLWS_OPENSSL_INCLUDE_DIRS=/usr/local/opt/openssl@1.1/include -DLWS_OPENSSL_LIBRARIES=\"/usr/local/opt/openssl/lib/libssl.dylib;/usr/local/opt/openssl/lib/libcrypto.dylib\" ${cmake} && make -j4 && make -j DESTDIR=../destdir install && ctest -j2 --output-on-failure ${cpack}"
+               },
+               "netbsd-OSX-bigsur/aarch64-apple-m1/llvm": {
+                       "build": "mkdir build destdir; cd build; export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export SAI_CPACK=\"-G ZIP\";export MACOSX_DEPLOYMENT_TARGET=10.15 ; cmake .. -DLWS_WITH_SUL_DEBUGGING=1 -DCMAKE_SYSTEM_PREFIX_PATH=/opt/homebrew -DLWS_OPENSSL_INCLUDE_DIRS=/opt/homebrew/Cellar/openssl@1.1/1.1.1h/include '-DLWS_OPENSSL_LIBRARIES=/opt/homebrew/Cellar/openssl@1.1/1.1.1h/lib/libssl.dylib;/opt/homebrew/Cellar/openssl@1.1/1.1.1h/lib/libcrypto.dylib' ${cmake} && make -j6 && rm -rf ../destdir && make -j DESTDIR=../destdir install && ctest -j3 --output-on-failure ${cpack}"
+               },
+               "solaris/x86_64-amd/gcc": {
+                       "build": "mkdir build destdir; cd build; export SAI_CPACK=\"-G ZIP\";cmake .. ${cmake} && make -j 4 && make install DESTDIR=../destdir && ctest -j2 --output-on-failure ${cpack}",
+                       "default": false
+               },
+               "freertos-linkit/arm32-m4-mt7697-usi/gcc": {
+                       "build": "mkdir build;cd build;export CCACHE_DISABLE=1;cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/tmp -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-linkit.cmake -DLWS_PLAT_FREERTOS=1 -DLWS_WITH_ZLIB=0 -DLWS_WITHOUT_EXTENSIONS=1 -DLWS_WITH_ZIP_FOPS=0 -DLWS_WITH_HTTP_STREAM_COMPRESSION=0 -DLWS_WITH_MBEDTLS=1 -DLWS_WITH_FILE_OPS=0 -DLWS_IPV6=0 ${cmake};make -j",
+                       "default": false
+               },
+               "w10/x86_64-amd/msvc": {
+                       "build": "mkdir build && cd build && set SAI_CPACK=\"-G ZIP\" && cmake .. -DLWS_OPENSSL_LIBRARIES=\"C:\\Program Files\\OpenSSL\\lib\\libssl.lib;C:\\Program Files\\OpenSSL\\lib\\libcrypto.lib\" -DLWS_OPENSSL_INCLUDE_DIRS=\"C:\\Program Files\\OpenSSL\\include\" -DLWS_EXT_PTHREAD_INCLUDE_DIR=\"C:\\Program Files (x86)\\pthreads\\include\" -DLWS_EXT_PTHREAD_LIBRARIES=\"C:\\Program Files (x86)\\pthreads\\lib\\x64\\libpthreadGC2.a\" ${cmake} && cmake --build . --config DEBUG && set CTEST_OUTPUT_ON_FAILURE=1 && ctest . -C DEBUG -j1 --output-on-failure",
+                       "default": false
+               },
+
+               "w10/x86_64-amd/wmbedtlsmsvc": {
+                        "build": "mkdir build && cd build && set SAI_CPACK=\"-G ZIP\" && cmake ..  -DLWS_WITH_MBEDTLS=1 -DLWS_MBEDTLS_INCLUDE_DIRS=\"C:/Program Files (x86)/mbed TLS/include\" -DMBEDTLS_LIBRARY=\"C:/Program Files (x86)/mbed TLS/lib/mbedtls.lib\" -DMBEDX509_LIBRARY=\"C:/Program Files (x86)/mbed TLS/lib/mbedx509.lib\" -DMBEDCRYPTO_LIBRARY=\"C:/Program Files (x86)/mbed TLS/lib/mbedcrypto.lib\"  -DLWS_EXT_PTHREAD_INCLUDE_DIR=\"C:\\Program Files (x86)\\pthreads\\include\" -DLWS_EXT_PTHREAD_LIBRARIES=\"C:\\Program Files (x86)\\pthreads\\lib\\x64\\libpthreadGC2.a\" ${cmake} && cmake --build . --config DEBUG && set CTEST_OUTPUT_ON_FAILURE=1 && ctest . -C DEBUG -j1 --output-on-failure",
+                        "default": false
+                },
+               "w10/x86_64-amd/noptmsvc": {
+                       "build": "mkdir build && cd build && set SAI_CPACK=\"-G ZIP\" && cmake .. -DLWS_OPENSSL_LIBRARIES=\"C:\\Program Files\\OpenSSL\\lib\\libssl.lib;C:\\Program Files\\OpenSSL\\lib\\libcrypto.lib\" -DLWS_OPENSSL_INCLUDE_DIRS=\"C:\\Program Files\\OpenSSL\\include\" ${cmake} && cmake --build . --config DEBUG && set CTEST_OUTPUT_ON_FAILURE=1 && ctest . -C DEBUG -j1 --output-on-failure",
+                       "default": false
+               },
+               "w10/x86_64-amd/mingw32": {
+                       "build": "mkdir build && cd build && cmake .. -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-w32.cmake ${cmake} && cmake --build . --config DEBUG",
+                       "default": false
+               },
+               "w10/x86_64-amd/mingw64": {
+                       "build": "mkdir build && cd build && cmake .. -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-w64.cmake ${cmake} && cmake --build . --config DEBUG",
+                       "default": false
+               },
+               "freertos-espidf/xl6-esp32/gcc": {
+                       # official way to get sdkconfig.h is idf.py menuconfig, but
+                       # no obvious way to do that in CI
+                       "build":        "rm -rf ebuild ; mkdir ebuild; cd ebuild; cp -rp ../minimal-examples/embedded/esp32/${cpack} . ;  cd ${cpack} ; . /opt/esp/esp-idf/export.sh ; ln -sf ../.. libwebsockets ; idf.py set-target esp32 && cp libwebsockets/minimal-examples/embedded/esp32/${cpack}/sdkconfig . && cp sdkconfig.h build && idf.py ${cmake} build size size-components size-files && cd build && /usr/local/bin/sai-device ${cpack} ESPPORT=0 ctest --output-on-failure",
+                       "default":      false
+               },
+               "freertos-espidf/riscv-esp32c3/gcc": {
+                       "build":        "rm -rf ebuild ; mkdir ebuild; cd ebuild; cp -rp ../minimal-examples/embedded/esp32/${cpack} . ;  cd ${cpack} ; . /opt/esp/esp-idf/export.sh ; ln -sf ../.. libwebsockets ; idf.py set-target esp32c3 && cp libwebsockets/minimal-examples/embedded/esp32/${cpack}/sdkconfig . && cp sdkconfig.h build && idf.py ${cmake} build size size-components size-files && cd build && /usr/local/bin/sai-device ${cpack} ESPPORT=0 ctest --output-on-failure",
+                       "default":      false
+               },
+
+               "linux-fedora-32/riscv64-virt/gcc": {
+                       "build":        "mkdir build destdir;cd build;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j4 && rm -rf ../destdir && make -j12 DESTDIR=../destdir install && ctest -j3 --output-on-failure ${cpack}",
+                       "default":      false
+               },
+               "freebsd-12/x86_64-amd/llvm": {
+                       "build":        "mkdir build destdir;cd build;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export CCACHE_DISABLE=1;cmake .. ${cmake} && make -j3 && rm -rf ../destdir && make -j3 DESTDIR=../destdir install"
+               },
+               "openbsd/x86_64-amd/llvm": {
+                        "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;cmake .. ${cmake};make -j4 && rm -rf ../destdir && make -j3 DESTDIR=../destdir install && ctest -j3 --output-on-failure",
+                       "default": false
+               },
+                "netbsd/aarch64BE-bcm2837-a53/gcc": {
+                        "build": "mkdir build destdir;cd build;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export CCACHE_DISABLE=1;cmake .. ${cmake};make -j6 && rm -rf ../destdir && make -j6 DESTDIR=../destdir install && /usr/pkg/bin/ctest -j3 --output-on-failure",
+                        "default": false
+                },
+                "netbsd/x86_64-amd/gcc": {
+                        "build": "mkdir build destdir;cd build;export LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins:../destdir/usr/local/lib;export CCACHE_DISABLE=1;cmake .. ${cmake};make -j6 && rm -rf ../destdir && make -j6 DESTDIR=../destdir install && /usr/pkg/bin/ctest -j3 --output-on-failure",
+                        "default": false
+                }
+
+       },
+
+       "configurations": {
+               "default": {
+                       "cmake":        "",
+                       "platforms":    "w10/x86_64-amd/msvc, w10/x86_64-amd/noptmsvc, freertos-linkit/arm32-m4-mt7697-usi/gcc, linux-ubuntu-2004/aarch64-a72-bcm2711-rpi4/gcc, w10/x86_64-amd/mingw32, w10/x86_64-amd/mingw64, netbsd/aarch64BE-bcm2837-a53/gcc, netbsd/x86_64-amd/gcc, w10/x86_64-amd/wmbedtlsmsvc, openbsd/x86_64-amd/llvm, solaris/x86_64-amd/gcc"
+               },
+               "default-noudp": {
+                       "cmake":        "-DLWS_WITH_UDP=0",
+                       "platforms":    "w10/x86_64-amd/msvc, w10/x86_64-amd/noptmsvc, freertos-linkit/arm32-m4-mt7697-usi/gcc, linux-ubuntu-2004/aarch64-a72-bcm2711-rpi4/gcc, w10/x86_64-amd/mingw32, w10/x86_64-amd/mingw64, netbsd/aarch64BE-bcm2837-a53/gcc, netbsd/x86_64-amd/gcc, w10/x86_64-amd/wmbedtlsmsvc"
+               },
+               "fault-injection": {
+                       "cmake":        "-DLWS_WITH_SYS_FAULT_INJECTION=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_CBOR=1",
+                       "platforms":    "w10/x86_64-amd/msvc"
+               },
+               "esp32-c3": {
+                       "cmake":        "-DLWS_IPV6=0",
+                       "cpack":        "esp-c3dev",
+                       "platforms":    "none, freertos-espidf/riscv-esp32c3/gcc"
+               },
+               "esp32-heltec": {
+                       "cmake":        "-DLWS_IPV6=0",
+                       "cpack":        "esp-heltec-wb32",
+                       "platforms":    "none, freertos-espidf/xl6-esp32/gcc"
+               },
+               "esp32-wrover": {
+                       "cmake":        "-DLWS_IPV6=0 -DLWS_WITH_CBOR=1",
+                       "cpack":        "esp-wrover-kit",
+                       "platforms":    "none, freertos-espidf/xl6-esp32/gcc"
+               },
+               "esp32-wrover-static": {
+                       "cmake":        "-DLWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY=1 -DLWS_IPV6=0",
+                       "cpack":        "esp-wrover-kit",
+                       "platforms":    "none, freertos-espidf/xl6-esp32/gcc"
+               },
+               "default-examples-openssl-v3-nogencrypto": {
+                       "cmake":        "-DLWS_OPENSSL_LIBRARIES=\"/usr/local/src/openssl/v3/usr/local/lib64/libssl.a;/usr/local/src/openssl/v3/usr/local/lib64/libcrypto.a\" -DLWS_OPENSSL_INCLUDE_DIRS=\"/usr/local/src/openssl/v3/usr/local/include/\" -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_GENCRYPTO=0",
+                       "platforms":    "none,linux-fedora-32/x86_64-amd/gcc"
+               },
+               "default-examples-openssl-v3-gencrypto": {
+                       "cmake":        "-DLWS_SUPPRESS_DEPRECATED_API_WARNINGS=1 -DLWS_OPENSSL_LIBRARIES=\"/usr/local/src/openssl/v3/usr/local/lib64/libssl.a;/usr/local/src/openssl/v3/usr/local/lib64/libcrypto.a\" -DLWS_OPENSSL_INCLUDE_DIRS=\"/usr/local/src/openssl/v3/usr/local/include/\" -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_GENCRYPTO=1",
+                       "platforms":    "none,linux-fedora-32/x86_64-amd/gcc"
+               },
+               "default-examples-boringssl": {
+                       "cmake":        "cmake .. -DLWS_WITH_BORINGSSL=1 -DLWS_OPENSSL_INCLUDE_DIRS=\"/usr/local/src/boringssl/include\" -DLWS_OPENSSL_LIBRARIES=\"/usr/local/src/boringssl/build/ssl/libssl.so;/usr/local/src/boringssl/build/crypto/libcrypto.so\" -DLWS_WITH_MINIMAL_EXAMPLES=1",
+                       "platforms":    "none,linux-fedora-32/x86_64-amd/gcc"
+               },
+               "default-examples-libressl": {
+                       "cmake":        "cmake .. -DLWS_OPENSSL_LIBRARIES='/opt/libressl-3.3.1/build/tls/libtls.a;/opt/libressl-3.3.1/build/ssl/libssl.a;/opt/libressl-3.3.1/build/crypto/libcrypto.a' -DLWS_OPENSSL_INCLUDE_DIRS=/opt/libressl-3.3.1/include -DLWS_WITH_MINIMAL_EXAMPLES=1",
+                       "platforms":    "none,linux-fedora-32/x86_64-amd/gcc"
+               },
+               "default-wolfssl": {
+                       "cmake":        "-DLWS_WITH_WOLFSSL=1 -DLWS_WOLFSSL_INCLUDE_DIRS=/usr/local/include -DLWS_WOLFSSL_LIBRARIES=/usr/local/lib/libwolfssl.so",
+                       "platforms":    "none,linux-fedora-32/x86_64-amd/gcc"
+               },
+               "default-examples": {
+                       "cmake":        "-DLWS_WITH_MINIMAL_EXAMPLES=1",
+                       "platforms":    "w10/x86_64-amd/msvc, w10/x86_64-amd/noptmsvc, linux-ubuntu-2004/aarch64-a72-bcm2711-rpi4/gcc, netbsd/aarch64BE-bcm2837-a53/gcc, netbsd/x86_64-amd/gcc, openbsd/x86_64-amd/llvm, solaris/x86_64-amd/gcc"
+               },
+               "default-examples-tls-sess": {
+                       "cmake":        "-DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_TLS_SESSIONS=1",
+                       "platforms":    "w10/x86_64-amd/msvc, w10/x86_64-amd/noptmsvc, linux-ubuntu-2004/aarch64-a72-bcm2711-rpi4/gcc, netbsd/aarch64BE-bcm2837-a53/gcc, netbsd/x86_64-amd/gcc, openbsd/x86_64-amd/llvm, solaris/x86_64-amd/gcc"
+               },
+               "h1only-examples": {
+                       "cmake":        "cmake .. -DLWS_WITH_HTTP2=0 -DLWS_WITH_MINIMAL_EXAMPLES=1",
+                       "platforms":    "none,linux-fedora-32/x86_64-amd/gcc"
+               },
+               "unix-domain": {
+                       "cmake":        "-DUNIX_SOCK=1",
+                       "platforms":    "w10/x86_64-amd/msvc, w10/x86_64-amd/noptmsvc"
+               },
+               "plugins": {
+                       "cmake":        "-DLWS_WITH_PLUGINS=1",
+                       "platforms":    "none,linux-fedora-32/x86_64-amd/gcc,linux-debian-sid/x86-amd/gcc,linux-debian-sid/x86_64-amd/gcc"
+               },
+               # WARN_DEPRECATED disabled for openssl v3 case on windows
+               "lws_system": {
+                       "cmake":        "-DLWS_SUPPRESS_DEPRECATED_API_WARNINGS=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=RELEASE -DLWS_WITH_GENCRYPTO=1 -DLWS_WITH_JOSE=1 -DLWS_WITH_SYS_ASYNC_DNS=1 -DLWS_WITH_SYS_NTPCLIENT=1",
+                       "platforms":    "w10/x86_64-amd/msvc, w10/x86_64-amd/noptmsvc, openbsd/x86_64-amd/llvm"
+               },
+               "secure-streams": {
+                       "cmake":        "-DLWS_WITH_SECURE_STREAMS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1",
+                       "platforms":    "w10/x86_64-amd/msvc, w10/x86_64-amd/noptmsvc, openbsd/x86_64-amd/llvm, solaris/x86_64-amd/gcc"
+               },
+               "secure-streams-proxy": {
+                       "cmake":        "-DLWS_WITH_SECURE_STREAMS=1 -DLWS_WITH_SECURE_STREAMS_PROXY_API=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_SECURE_STREAMS_AUTH_SIGV4=1",
+                       "platforms":    "not w10/x86_64-amd/msvc, netbsd/aarch64BE-bcm2837-a53/gcc, netbsd/x86_64-amd/gcc, openbsd/x86_64-amd/llvm, solaris/x86_64-amd/gcc"
+               },
+               "secure-streams-proxy-metrics": {
+                       "cmake":        "-DLWS_WITH_SECURE_STREAMS=1 -DLWS_WITH_SECURE_STREAMS_PROXY_API=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_SECURE_STREAMS_AUTH_SIGV4=1 -DLWS_WITH_SYS_METRICS=1",
+                       "platforms":    "not w10/x86_64-amd/msvc, netbsd/aarch64BE-bcm2837-a53/gcc, netbsd/x86_64-amd/gcc"
+               },
+               "distro_recommended": { # minimal examples also needed for ctest
+                       "cmake":        "-DLWS_WITH_DISTRO_RECOMMENDED=1 -DLWS_WITH_MINIMAL_EXAMPLES=1",
+                       "platforms":    "not freebsd-12/x86_64-amd/llvm, not linkit-cross, not w10/x86_64-amd/msvc, linux-ubuntu-2004/aarch64-a72-bcm2711-rpi4/gcc, linux-fedora-32/riscv64-virt/gcc",
+                       "cpack":        "&& cpack $SAI_CPACK",
+                       "artifacts":    "build/*.rpm, build/*.deb, build/*.zip"
+               },
+               "lwsws": {
+                       "cmake":        "-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_WITH_GENCRYPTO=1 -DLWS_WITH_JOSE=1 -DLWS_WITH_SYS_ASYNC_DNS=1 -DLWS_WITH_SYS_NTPCLIENT=1",
+                       # no distro -devel package for libuv
+                       "platforms":    "not linux-centos-8/x86_64-amd/gcc"
+               },
+               "lwsws-nometrics": {
+                       "cmake":        "-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_WITH_GENCRYPTO=1 -DLWS_WITH_JOSE=1 -DLWS_WITH_SYS_ASYNC_DNS=1 -DLWS_WITH_SYS_NTPCLIENT=1 -DLWS_WITH_SYS_METRICS=0",
+                       # no distro -devel package for libuv
+                       "platforms":    "not linux-centos-8/x86_64-amd/gcc"
+               },
+               "lwsws2": {
+                       "cmake":        "-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_WITH_LWS_DSH=1 -DLWS_WITH_CACHE_NSCOOKIEJAR=0",
+                       # no distro -devel package for libuv
+                       "platforms":    "not linux-centos-8/x86_64-amd/gcc"
+               },
+               "justmbedtls": {
+                       "cmake": "-DLWS_WITH_MBEDTLS=1 -DLWS_WITHOUT_TESTAPPS=1",
+                       "platforms": "none, linux-android/aarch64/llvm"
+               },
+               "mbedtls": {
+                       "cmake":        "-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_JOSE=1 -DCMAKE_BUILD_TYPE=DEBUG",
+                       # no distro -devel package for mbedtls
+                       "platforms":    "not linux-centos-7/x86_64-amd/gcc, not linux-centos-8/x86_64-amd/gcc"
+               },
+               "mbedtls-metrics": {
+                       "cmake":        "-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_JOSE=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_WITH_SYS_METRICS=1",
+                       "platforms":    "not linux-centos-7/x86_64-amd/gcc, not linux-centos-8/x86_64-amd/gcc"
+               },
+               "noserver": {
+                       "cmake":        "-DLWS_WITHOUT_SERVER=ON -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_SECURE_STREAMS=1",
+                       "platforms":    "w10/x86_64-amd/msvc, w10/x86_64-amd/noptmsvc"
+               },
+               "noclient": {
+                       "cmake":        "-DLWS_WITHOUT_CLIENT=ON -DLWS_WITH_MINIMAL_EXAMPLES=1"
+               },
+               "ext": {
+                       "cmake":        "-DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_MINIMAL_EXAMPLES=1"
+               },
+               "nonetwork": {
+                       "cmake":        "-DLWS_WITH_NETWORK=0"
+               },
+               "libev": {
+                       "cmake":        "-DLWS_WITH_LIBEV=ON",
+                       "platforms":    "openbsd/x86_64-amd/llvm"
+               },
+               "libevent": {
+                       "cmake":        "-DLWS_WITH_LIBEVENT=ON"
+               },
+               "libglib": {
+                       "cmake":        "-DLWS_WITH_GLIB=ON"
+               },
+               "sdevent": {
+                       "cmake":        "-DLWS_WITH_SDEVENT=ON",
+                       "platforms":    "none, linux-fedora-32/x86_64-amd/gcc"
+               },
+               "uncommon_headers": {
+                       "cmake":        "-DLWS_WITH_HTTP_BASIC_AUTH=0 -DLWS_WITH_HTTP_UNCOMMON_HEADERS=0 -DLWS_HTTP_HEADERS_ALL=0",
+                       "platforms":    "none, linux-fedora-32/x86_64-amd/gcc"
+               },
+               "ipv6": {
+                       "cmake":        "-DLWS_IPV6=ON",
+                       "platforms":    "w10/x86_64-amd/mingw64, w10/x86_64-amd/msvc"
+               },
+               "nonetlink":    {
+                       "cmake":        "-DLWS_WITH_NETLINK=0",
+                       "platforms":    "none, linux-ubuntu-2004/x86_64-amd/gcc"
+               },
+               "nossl": {
+                       "cmake":        "-DLWS_WITH_SSL=OFF",
+                       "platforms":    "netbsd-iOS/aarch64/llvm"
+               },
+               "daemon": {
+                       "cmake":        "-DLWS_WITHOUT_DAEMONIZE=OFF"
+               },
+               "cgi": {
+                       "cmake":        "-DLWS_WITH_CGI=ON"
+               },
+               "nologs": {
+                       "cmake":        "-DLWS_WITH_NO_LOGS=ON"
+               },
+               "cookiejar": {
+                       "cmake":        "-DLWS_WITH_CACHE_NSCOOKIEJAR=ON"
+               },
+               "jittrust": {
+                       "cmake":        "-DLWS_WITH_TLS_JIT_TRUST=1",
+                       "platforms":    "none, linux-fedora-32/x86_64-amd/gcc"
+               },
+               "smp": {
+                       "cmake":        "-DLWS_MAX_SMP=32 -DLWS_WITH_MINIMAL_EXAMPLES=1"
+               },
+               "nows": {
+                       "cmake":        "-DLWS_ROLE_WS=0"
+               },
+               "threadpool": {
+                       "cmake":        "-DLWS_WITH_THREADPOOL=1 -DLWS_WITH_MINIMAL_EXAMPLES=1",
+                       "platforms":    "w10/x86_64-amd/msvc"
+               }
+       }
+}
+
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644 (file)
index df21b90..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-env:
-  # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
-  #   via the "travis encrypt" command using the project repo's public key
-  global:
-    - secure: "KhAdQ9ja+LBObWNQTYO7Df5J4DyOih6S+eerDMu8UPSO+CoWV2pWoQzbOfocjyOscGOwC+2PrrHDNZyGfqkCLDXg1BxynXPCFerHC1yc2IajvKpGXmAAygNIvp4KACDfGv/dkXrViqIzr/CdcNaU4vIMHSVb5xkeLi0W1dPnQOI="
-  matrix:
-    - LWS_METHOD=lwsws CMAKE_ARGS="-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2=/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ -DLWS_WITH_GENCRYPTO=1 -DLWS_WITH_JOSE=1"
-    - LWS_METHOD=lwsws2 CMAKE_ARGS="-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2=/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ -DLWS_WITH_LWS_DSH=1"
-    - LWS_METHOD=default CMAKE_ARGS="-DLWS_WITH_MINIMAL_EXAMPLES=1"
-    - LWS_METHOD=mbedtls CMAKE_ARGS="-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_JOSE=1 -DCMAKE_BUILD_TYPE=DEBUG"
-    - LWS_METHOD=noserver CMAKE_ARGS="-DLWS_WITHOUT_SERVER=ON -DLWS_WITH_MINIMAL_EXAMPLES=1"
-    - LWS_METHOD=noclient CMAKE_ARGS="-DLWS_WITHOUT_CLIENT=ON -DLWS_WITH_MINIMAL_EXAMPLES=1"
-    - LWS_METHOD=noext CMAKE_ARGS="-DLWS_WITHOUT_EXTENSIONS=ON -DLWS_WITH_MINIMAL_EXAMPLES=1"
-    - LWS_METHOD=nonetwork CMAKE_ARGS="-DLWS_WITH_NETWORK=0"
-    - LWS_METHOD=libev CMAKE_ARGS="-DLWS_WITH_LIBEV=ON"
-    - LWS_METHOD=noipv6 CMAKE_ARGS="-DLWS_IPV6=OFF"
-    - LWS_METHOD=nossl CMAKE_ARGS="-DLWS_WITH_SSL=OFF"
-    - LWS_METHOD=nodaemon CMAKE_ARGS="-DLWS_WITHOUT_DAEMONIZE=ON"
-    - LWS_METHOD=cgi CMAKE_ARGS="-DLWS_WITH_CGI=ON"
-    - LWS_METHOD=nologs CMAKE_ARGS="-DLWS_WITH_NO_LOGS=ON"
-    - LWS_METHOD=smp CMAKE_ARGS="-DLWS_MAX_SMP=32 -DLWS_WITH_MINIMAL_EXAMPLES=1"
-    - LWS_METHOD=nows CMAKE_ARGS="-DLWS_ROLE_WS=0"
-    - LWS_METHOD=threadpool CMAKE_ARGS="-DLWS_WITH_THREADPOOL=1 -DLWS_WITH_MINIMAL_EXAMPLES=1"
-
-os:
-  - linux
-  - osx
-language: generic
-install:
-  - ./scripts/travis_install.sh
-#  - ./travis-tool.sh github_package jimhester/covr
-
-#after_success:
-#  - Rscript -e 'covr::coveralls()'
-
-script:
-  - ./scripts/travis_control.sh
-sudo: required
-dist: trusty
-addons:
-  coverity_scan:
-    project:
-      name: "warmcat/libwebsockets"
-    notification_email: andy@warmcat.com
-    build_command_prepend: "mkdir build && cd build && cmake .."
-    build_command:   "cmake --build ."
-    branch_pattern: coverity_scan
-
diff --git a/CMakeLists-implied-options.txt b/CMakeLists-implied-options.txt
new file mode 100644 (file)
index 0000000..c8137af
--- /dev/null
@@ -0,0 +1,423 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# This part of the CMakeLists.txt defines internal logic between options
+
+if(IOS)
+    set(LWS_DETECTED_PLAT_IOS 1)
+endif()
+
+# Workaround for ESP-IDF
+# Detect ESP_PLATFORM environment flag, if exist, set LWS_WITH_ESP32.
+# Otherwise the user may not be able to run configuration ESP-IDF in the first time.
+if (ESP_PLATFORM)
+       message(STATUS "ESP-IDF enabled")
+       set(LWS_WITH_ESP32 ON)
+       set(LWS_WITH_ZLIB OFF)
+       set(LWS_HAVE_mbedtls_ssl_get_alpn_protocol 1)
+else()
+       set(LWS_WITH_ESP32_HELPER OFF)
+endif()
+
+if (LWS_WITH_ESP32)
+       set(LWS_PLAT_FREERTOS 1)
+endif()
+
+if (LWS_PLAT_OPTEE)
+       set(LWS_WITH_UDP 0)
+endif()
+
+if (LWS_PLAT_FREERTOS OR (${CMAKE_SYSTEM_NAME} MATCHES "QNX"))
+       message(STATUS "No LWS_WITH_DIR or LWS_WITH_LEJP_CONF")
+       set(LWS_WITH_DIR OFF)
+       set(LWS_WITH_LEJP_CONF OFF)
+       message("LWS_WITH_DIR ${LWS_WITH_DIR}")
+else()
+       message(STATUS "Compiled with LWS_WITH_DIR and LWS_WITH_LEJP_CONF")
+       set(LWS_WITH_DIR ON)
+       set(LWS_WITH_LEJP_CONF ON)
+endif()
+
+if (LWS_FOR_GITOHASHI)
+       set(LWS_WITH_THREADPOOL 1)
+       set(LWS_WITH_HTTP2 1)
+       set(LWS_UNIX_SOCK 1)
+       set(LWS_WITH_HTTP_PROXY 1)
+       set(LWS_WITH_FTS 1)
+       set(LWS_WITH_DISKCACHE 1)
+       set(LWS_WITH_LWSAC 1)
+       set(LWS_WITH_LEJP_CONF 1)
+       set(LWS_WITH_SPAWN 1)
+       set(LWS_WITH_FSMOUNT 1)
+       set(LWS_WITH_STRUCT_JSON 1)
+       set(LWS_WITH_STRUCT_SQLITE3 1)
+endif()
+
+if(LWS_WITH_DISTRO_RECOMMENDED)
+       set(LWS_WITH_HTTP2 1)                           # selfcontained
+       set(LWS_WITH_LWSWS 1)                           # libuv
+       set(LWS_WITH_CGI 1)                             # selfcontained
+       set(LWS_WITH_HTTP_STREAM_COMPRESSION 1)         # libz and brotli if avail
+       set(LWS_IPV6 1)                                 # selfcontained
+       set(LWS_WITH_ZIP_FOPS 1)                        # libz
+       set(LWS_WITH_SOCKS5 1)                          # selfcontained
+       set(LWS_WITH_RANGES 1)                          # selfcontained
+       set(LWS_WITH_ACME 1)                            # selfcontained / tls
+       set(LWS_WITH_SYS_METRICS 1)                     # selfcontained
+       set(LWS_WITH_GLIB 1)                            # glib
+       set(LWS_WITH_LIBUV 1)                           # libuv
+       set(LWS_WITH_LIBEV 1)                           # libev
+       set(LWS_WITH_LIBEVENT 1)                        # libevent
+       set(LWS_WITH_EVLIB_PLUGINS 1)                   # event libraries created as plugins / individual packages
+       set(LWS_WITHOUT_EXTENSIONS 0)                   # libz
+       set(LWS_ROLE_DBUS 1)                            # dbus-related libs
+       set(LWS_WITH_FTS 1)                             # selfcontained
+       set(LWS_WITH_THREADPOOL 1)                      # pthreads
+       set(LWS_UNIX_SOCK 1)                            # selfcontained
+       set(LWS_WITH_HTTP_PROXY 1)                      # selfcontained
+       set(LWS_WITH_DISKCACHE 1)                       # selfcontained
+       set(LWS_WITH_LWSAC 1)                           # selfcontained
+       set(LWS_WITH_LEJP_CONF 1)                       # selfcontained
+       set(LWS_WITH_PLUGINS_BUILTIN 1)                 # selfcontained
+       set(LWS_ROLE_RAW_PROXY 1)                       # selfcontained
+       set(LWS_WITH_GENCRYPTO 1)                       # selfcontained / tls
+       set(LWS_WITH_CBOR 1)                            # selfcontained
+       set(LWS_WITH_COSE 1)                            # selfcontained
+       set(LWS_WITH_JOSE 1)                            # selfcontained
+       set(LWS_WITH_STRUCT_JSON 1)                     # selfcontained
+       set(LWS_WITH_STRUCT_SQLITE3 1)                  # sqlite3
+       set(LWS_WITH_SPAWN 1)                           # selfcontained
+# libmount is problematic on Centos 8 / RHEL 8
+#      set(LWS_WITH_FSMOUNT 1)
+       set(LWS_ROLE_MQTT 1)                            # selfcontained
+       set(LWS_WITH_SECURE_STREAMS 1)                  # selfcontained
+       set(LWS_WITH_SECURE_STREAMS_PROXY_API 1)        # selfcontained
+       set(LWS_WITH_DIR 1)                             # selfcontained
+endif()
+
+# LWS_WITH_EVENT_LIBS is set if any event lib selected
+
+if (LWS_WITH_LIBEV OR
+    LWS_WITH_LIBUV OR
+    LWS_WITH_LIBEVENT OR
+    LWS_WITH_GLIB OR
+    LWS_WITH_SDEVENT OR
+    LWS_WITH_ULOOP)
+       set(LWS_WITH_EVENT_LIBS 1)
+else()
+       unset(LWS_WITH_EVENT_LIBS)
+endif()
+
+if (LWS_WITH_SECURE_STREAMS_PROXY_API)
+       set(LWS_WITH_LWS_DSH 1)
+       set(LWS_WITH_UNIX_SOCK 1)
+       set(LWS_WITH_SYS_SMD 1)
+endif()
+
+if (NOT LWS_WITH_NETWORK)
+       set(LWS_ROLE_MQTT 0)
+       set(LWS_ROLE_H1 0)
+       set(LWS_ROLE_WS 0)
+       set(LWS_ROLE_RAW 0)
+       set(LWS_WITHOUT_EXTENSIONS 1)
+       set(LWS_WITHOUT_SERVER 1)
+       set(LWS_WITHOUT_CLIENT 1)
+       set(LWS_WITH_HTTP2 0)
+       set(LWS_WITH_SOCKS5 0)
+       set(LWS_UNIX_SOCK 0)
+       set(LWS_WITH_HTTP_PROXY 0)
+       set(LWS_WITH_PLUGINS 0)
+       set(LWS_WITH_LWSWS 0)
+       set(LWS_WITH_CGI 0)
+       set(LWS_ROLE_RAW_PROXY 0)
+       set(LWS_WITH_PEER_LIMITS 0)
+       set(LWS_WITH_HTTP_STREAM_COMPRESSION 0)
+       set(LWS_WITH_HTTP_BROTLI 0)
+       set(LWS_WITH_POLL 0)
+       set(LWS_WITH_SEQUENCER 0)
+       set(LWS_ROLE_DBUS 0)
+       set(LWS_WITH_LWS_DSH 0)
+       set(LWS_WITH_THREADPOOL 0)
+       set(LWS_WITH_SYS_SMD 0)
+endif()
+
+if (LWS_WITH_CGI)
+       set(LWS_WITH_SPAWN 1)
+endif()
+
+if (LWS_WITH_STRUCT_SQLITE3)
+       set(LWS_WITH_SQLITE3 1)
+endif()
+
+if (LWS_WITH_HTTP_BASIC_AUTH)
+       # WWW_AUTHENTICATE used by basic auth is an "uncommon header"
+       set(LWS_WITH_HTTP_UNCOMMON_HEADERS 1)
+endif()
+
+if (LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+       set(LWS_WITH_GENCRYPTO 1)
+endif()
+
+if (APPLE)
+       set(LWS_ROLE_DBUS 0)
+endif()
+
+if(NOT DEFINED CMAKE_BUILD_TYPE)
+       set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type")
+endif()
+
+if (LWS_PLAT_FREERTOS)
+       set(LWS_UNIX_SOCK 0)
+endif()
+
+if (LWS_PLAT_FREERTOS)
+       set(LWS_WITH_FTS 0)
+endif()
+
+if (LWS_WITH_HTTP2)
+       set(LWS_ROLE_H2 1)
+endif()
+if (LWS_WITH_CGI)
+       set(LWS_ROLE_CGI 1)
+endif()
+
+if (NOT LWS_ROLE_WS)
+       set(LWS_WITHOUT_EXTENSIONS 1)
+endif()
+
+unset(LWS_WITH_LIBUV_INTERNAL)
+
+if (LWS_WITH_LWSWS)
+ message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV")
+ set(LWS_WITH_PLUGINS 1)
+ set(LWS_WITH_LIBUV 1)
+ set(LWS_WITH_LIBUV_INTERNAL 1)
+ set(LWS_WITH_EVENT_LIBS 1) # implied by LIBUV_INTERNAL
+ set(LWS_WITH_ACCESS_LOG 1)
+ set(LWS_WITH_SYS_METRICS 1)
+ set(LWS_WITH_LEJP 1)
+ set(LWS_WITH_LEJP_CONF 1)
+ set(LWS_WITH_PEER_LIMITS 1)
+ set(LWS_ROLE_RAW_PROXY 1)
+endif()
+
+# sshd plugin
+if (LWS_WITH_PLUGINS)
+ set(LWS_WITH_GENCRYPTO 1)
+endif()
+
+if (LWS_ROLE_RAW_PROXY)
+ set (LWS_WITH_CLIENT 1)
+ set (LWS_WITH_SERVER 1)
+endif()
+
+if (LWS_WITH_ACME)
+ set (LWS_WITH_CLIENT 1)
+ set (LWS_WITH_SERVER 1)
+ set (LWS_WITH_JOSE 1)
+endif()
+
+if (LWS_WITH_JOSE)
+ set(LWS_WITH_LEJP 1)
+ set(LWS_WITH_GENCRYPTO 1)
+endif()
+
+if (LWS_WITH_PLUGINS AND NOT LWS_WITH_LIBUV)
+message(STATUS "LWS_WITH_PLUGINS --> Enabling LWS_WITH_LIBUV")
+ set(LWS_WITH_LIBUV 1)
+ set(LWS_WITH_EVENT_LIBS 1)
+endif()
+
+if (LWS_WITH_PLUGINS OR LWS_WITH_CGI)
+       # sshd plugin
+ set(LWS_WITH_GENCRYPTO 1)
+endif()
+
+if (LWS_PLAT_FREERTOS)
+ set(LWS_WITH_SHARED OFF)
+ if (LWS_WITH_SSL)
+  set(LWS_WITH_MBEDTLS ON)
+ endif()
+  # set(LWS_WITHOUT_CLIENT ON)
+ set(LWS_WITHOUT_TESTAPPS ON)
+ set(LWS_WITHOUT_EXTENSIONS ON)
+ set(LWS_WITH_PLUGINS OFF)
+ set(LWS_WITH_RANGES ON)
+ # this implies no pthreads in the lib
+ set(LWS_MAX_SMP 1)
+ set(LWS_HAVE_MALLOC 1)
+ set(LWS_HAVE_REALLOC 1)
+ set(LWS_HAVE_GETIFADDRS 1)
+ set(LWS_WITH_CUSTOM_HEADERS 0)
+endif()
+
+#if (LWS_WITH_ESP32)
+# set(LWS_WITH_ZIP_FOPS 1)
+#endif()
+
+if (WIN32)
+#set(LWS_MAX_SMP 1)
+if (LWS_WITH_PLUGINS)
+set(LWS_WITH_LIBUV_INTERNAL 1)
+endif()
+endif()
+
+if (LWS_WITHOUT_SERVER)
+set(LWS_WITH_LWSWS OFF)
+endif()
+
+if (LWS_WITH_LEJP_CONF)
+       set(LWS_WITH_DIR 1)
+endif()
+
+# confirm H1 relationships
+
+if (NOT LWS_ROLE_H1 AND LWS_ROLE_H2)
+       message(FATAL_ERROR "H2 requires LWS_ROLE_H1")
+endif()
+
+if (NOT LWS_ROLE_H1 AND LWS_ROLE_WS)
+       message(FATAL_ERROR "WS requires LWS_ROLE_H1")
+endif()
+
+if (NOT LWS_ROLE_H1 AND LWS_ROLE_CGI)
+       message(FATAL_ERROR "CGI requires LWS_ROLE_H1")
+endif()
+
+# confirm HTTP relationships
+
+if (NOT LWS_ROLE_H1 AND NOT LWS_ROLE_H2 AND LWS_WITH_HTTP_PROXY)
+       message(FATAL_ERROR "LWS_WITH_LWSWS requires LWS_ROLE_H1")
+endif()
+
+if (NOT LWS_ROLE_H1 AND NOT LWS_ROLE_H2 AND LWS_WITH_HTTP_PROXY)
+       message(FATAL_ERROR "LWS_WITH_HTTP_PROXY requires LWS_ROLE_H1")
+endif()
+
+if (NOT LWS_ROLE_H1 AND NOT LWS_ROLE_H2 AND LWS_WITH_RANGES)
+       message(FATAL_ERROR "LWS_WITH_RANGES requires LWS_ROLE_H1")
+endif()
+
+if (NOT LWS_ROLE_H1 AND NOT LWS_ROLE_H2 AND LWS_WITH_ACCESS_LOG)
+       message(FATAL_ERROR "LWS_WITH_ACCESS_LOG requires LWS_ROLE_H1")
+endif()
+
+if (LWS_WITH_HTTP_PROXY AND (LWS_WITHOUT_CLIENT OR LWS_WITHOUT_SERVER))
+       message("You have to enable both client and server for http proxy")
+       set(LWS_WITH_HTTP_PROXY 0)
+endif()
+
+if (NOT LWS_WITHOUT_EXTENSIONS OR LWS_WITH_ZIP_FOPS)
+       set(LWS_WITH_ZLIB 1)
+endif()
+
+if (LWS_WITH_SECURE_STREAMS)
+       set(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM 1)
+endif()
+
+if (NOT (LWS_WITH_STATIC OR LWS_WITH_SHARED))
+       message(FATAL_ERROR "Makes no sense to compile with neither static nor shared libraries.")
+endif()
+
+if (LWS_WITHOUT_DAEMONIZE OR WIN32)
+       set(LWS_NO_DAEMONIZE 1)
+endif()
+
+if (LWS_IPV6)
+       set(LWS_WITH_IPV6 1)
+endif()
+
+if (LWS_UNIX_SOCK)
+    set(LWS_WITH_UNIX_SOCK 1)
+endif()
+
+if (NOT LWS_MAX_SMP)
+       set(LWS_MAX_SMP 1)
+endif()
+if ("${LWS_MAX_SMP}" STREQUAL "")
+       set(LWS_MAX_SMP 1)
+endif()
+
+set(LWS_WITH_CLIENT 1)
+if (LWS_WITHOUT_CLIENT)
+       set(LWS_WITH_CLIENT)
+       set(LWS_WITH_SECURE_STREAMS 0)
+endif()
+set(LWS_WITH_SERVER 1)
+if (LWS_WITHOUT_SERVER)
+       set(LWS_WITH_SERVER)
+endif()
+
+# using any abstract protocol enables LWS_WITH_ABSTRACT
+
+#if (LWS_WITH_SMTP)
+#      set(LWS_WITH_ABSTRACT 1)
+#endif()
+
+if (NOT LWS_WITH_EVLIB_PLUGINS AND (LWS_WITH_LIBEV AND LWS_WITH_LIBEVENT))
+       message(FATAL_ERROR "Sorry libev and libevent conflict with each others' namespace, you can only have one or the other")
+endif()
+
+if (LWS_SSL_SERVER_WITH_ECDH_CERT)
+       set(LWS_SSL_SERVER_WITH_ECDH_CERT 1)
+endif()
+
+# LWS_OPENSSL_SUPPORT deprecated... use LWS_WITH_TLS
+if (LWS_WITH_SSL OR LWS_WITH_MBEDTLS)
+       set(LWS_OPENSSL_SUPPORT 1)
+       set(LWS_WITH_TLS 1)
+endif()
+
+if (NOT LWS_WITH_SSL)
+       set(LWS_WITHOUT_BUILTIN_SHA1 OFF)
+endif()
+# protocol plugins dont make any sense either
+if (LWS_WITH_PLUGINS AND NOT LWS_WITH_SHARED)
+       message("Deselecting PLUGINS since building static")
+       set(LWS_WITH_PLUGINS 0)
+endif()
+
+if (LWS_WITH_TLS_SESSIONS)
+       if (NOT LWS_WITH_NETWORK OR NOT LWS_WITH_CLIENT)
+               message("TLS_SESSIONS support requires client, disabling")
+               set(LWS_WITH_TLS_SESSIONS OFF)
+       endif()
+endif()
+
+# if we're only building static, we don't want event lib plugins
+#
+if (LWS_WITH_EVLIB_PLUGINS AND NOT LWS_WITH_SHARED)
+       message("Deselecting EVLIB_PLUGINS since building static")
+       set(LWS_WITH_EVLIB_PLUGINS 0)
+endif()
+
+if (LWS_WITH_PLUGINS OR (LWS_WITH_EVLIB_PLUGINS AND LWS_WITH_EVENT_LIBS))
+       set(LWS_WITH_PLUGINS_API 1)
+endif()
+
+if (WIN32 AND NOT LWS_EXT_PTHREAD_LIBRARIES)
+        set(LWS_MAX_SMP 1)
+        message("SMD requires pthreads")
+        set(LWS_WITH_SYS_SMD 0)
+endif()
+
index ad86aa5..c4cd294 100644 (file)
@@ -1,4 +1,47 @@
-cmake_minimum_required(VERSION 2.8.9)
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+cmake_minimum_required(VERSION 2.8.12)
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+include(CheckIncludeFile)
+include(CheckIncludeFiles)
+include(CheckLibraryExists)
+include(CheckTypeSize)
+include(CheckCSourceCompiles)
+
+if (POLICY CMP0048)
+       cmake_policy(SET CMP0048 NEW)
+endif()
+
+#if (POLICY CMP0024)
+#      cmake_policy(SET CMP0024 NEW)
+#endif()
+
+if (POLICY CMP0075)
+       cmake_policy(SET CMP0075 NEW)
+endif()
 
 # General Advice
 #
@@ -13,6 +56,46 @@ endif()
 set(LWS_ROLE_RAW 1)
 set(LWS_WITH_POLL 1)
 
+if (ESP_PLATFORM)
+       set(LWS_ESP_PLATFORM 1)
+       #set(CMAKE_TOOLCHAIN_FILE contrib/cross-esp32.cmake)
+       set(LWIP_PROVIDE_ERRNO 1)
+endif()
+
+# it's at this point any toolchain file is brought in
+project(libwebsockets C CXX)
+include(CTest)
+
+if (ESP_PLATFORM)
+       include_directories(
+               $ENV{IDF_PATH}/components/esp_hw_support/include/soc/
+               $ENV{IDF_PATH}/components/freertos/include/
+               $ENV{IDF_PATH}/components/freertos/esp_additions/include/
+               $ENV{IDF_PATH}/components/freertos/esp_additions/include/freertos/
+               $ENV{IDF_PATH}/components/freertos/FreeRTOS-Kernel/include/
+               $ENV{IDF_PATH}/components/freertos/FreeRTOS-Kernel/portable/linux/include/
+               $ENV{IDF_PATH}/components/xtensa/${CONFIG_IDF_TARGET}/include/
+               $ENV{IDF_PATH}/components/freertos/include/esp_additions
+               $ENV{IDF_PATH}/components/hal/include
+               $ENV{IDF_PATH}/components/soc/${CONFIG_IDF_TARGET}/include/
+               $ENV{IDF_PATH}/components/soc/include/
+               $ENV{IDF_PATH}/components/esp_hw_support/include
+               $ENV{IDF_PATH}/components/hal/${CONFIG_IDF_TARGET}/include/
+       )
+
+       if (CONFIG_IDF_TARGET_ARCH_RISCV)
+                include_directories(
+                       $ENV{IDF_PATH}/components/freertos/port/riscv/include
+                       $ENV{IDF_PATH}/components/riscv/include)
+        else()
+                include_directories(
+                       $ENV{IDF_PATH}/components/freertos/port/xtensa/include
+                       $ENV{IDF_PATH}/components/xtensa/include)
+        endif()
+
+endif()
+
+
 #
 # Select features recommended for PC distro packaging
 #
@@ -20,33 +103,75 @@ option(LWS_WITH_DISTRO_RECOMMENDED "Enable features recommended for distro packa
 option(LWS_FOR_GITOHASHI "Enable features recommended for use with gitohashi" OFF)
 
 #
+# Compiler features
+#
+option(DISABLE_WERROR "Avoid treating compiler warnings as fatal errors" OFF)
+
+#
 # Major individual features
 #
 option(LWS_WITH_NETWORK "Compile with network-related code" ON)
 option(LWS_ROLE_H1 "Compile with support for http/1 (needed for ws)" ON)
 option(LWS_ROLE_WS "Compile with support for websockets" ON)
+option(LWS_ROLE_MQTT "Build with support for MQTT client" OFF)
 option(LWS_ROLE_DBUS "Compile with support for DBUS" OFF)
 option(LWS_ROLE_RAW_PROXY "Raw packet proxy" OFF)
+option(LWS_ROLE_RAW_FILE "Compile with support for raw files" ON)
 option(LWS_WITH_HTTP2 "Compile with server support for HTTP/2" ON)
 option(LWS_WITH_LWSWS "Libwebsockets Webserver" OFF)
 option(LWS_WITH_CGI "Include CGI (spawn process with network-connected stdin/out/err) APIs" OFF)
 option(LWS_IPV6 "Compile with support for ipv6" OFF)
-option(LWS_UNIX_SOCK "Compile with support for UNIX domain socket" OFF)
-option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions" OFF)
-option(LWS_WITH_HTTP_PROXY "Support for HTTP proxying" OFF)
+option(LWS_UNIX_SOCK "Compile with support for UNIX domain socket if OS supports it" ON)
+option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions (implies LWS_WITH_PLUGINS_API)" OFF)
+option(LWS_WITH_PLUGINS_BUILTIN "Build the plugin protocols directly into lws library" OFF)
+option(LWS_WITH_HTTP_PROXY "Support for active HTTP proxying" OFF)
 option(LWS_WITH_ZIP_FOPS "Support serving pre-zipped files" OFF)
 option(LWS_WITH_SOCKS5 "Allow use of SOCKS5 proxy on client connections" OFF)
-option(LWS_WITH_GENERIC_SESSIONS "With the Generic Sessions plugin" OFF)
 option(LWS_WITH_PEER_LIMITS "Track peers and restrict resources a single peer can allocate" OFF)
 option(LWS_WITH_ACCESS_LOG "Support generating Apache-compatible access logs" OFF)
 option(LWS_WITH_RANGES "Support http ranges (RFC7233)" OFF)
-option(LWS_WITH_SERVER_STATUS "Support json + jscript server monitoring" OFF)
 option(LWS_WITH_THREADPOOL "Managed worker thread pool support (relies on pthreads)" OFF)
 option(LWS_WITH_HTTP_STREAM_COMPRESSION "Support HTTP stream compression" OFF)
 option(LWS_WITH_HTTP_BROTLI "Also offer brotli http stream compression (requires LWS_WITH_HTTP_STREAM_COMPRESSION)" OFF)
 option(LWS_WITH_ACME "Enable support for ACME automatic cert acquisition + maintenance (letsencrypt etc)" OFF)
 option(LWS_WITH_HUBBUB "Enable libhubbub rewriting support" OFF)
+option(LWS_WITH_ALSA "Enable alsa audio example" OFF)
+option(LWS_WITH_GTK "Enable gtk example" OFF)
 option(LWS_WITH_FTS "Full Text Search support" OFF)
+option(LWS_WITH_SYS_ASYNC_DNS "Nonblocking internal IPv4 + IPv6 DNS resolver" OFF)
+option(LWS_WITH_SYS_NTPCLIENT "Build in tiny ntpclient good for tls date validation and run via lws_system" OFF)
+option(LWS_WITH_SYS_DHCP_CLIENT "Build in tiny DHCP client" OFF)
+option(LWS_WITH_HTTP_BASIC_AUTH "Support Basic Auth" ON)
+option(LWS_WITH_HTTP_UNCOMMON_HEADERS "Include less common http header support" ON)
+option(LWS_WITH_SYS_STATE "lws_system state support" ON)
+option(LWS_WITH_SYS_SMD "Lws System Message Distribution" ON)
+option(LWS_WITH_SYS_FAULT_INJECTION "Enable fault injection support" OFF)
+option(LWS_WITH_SYS_METRICS "Lws Metrics API" OFF)
+
+#
+# Secure Streams
+#
+option(LWS_WITH_SECURE_STREAMS "Secure Streams protocol-agnostic API" OFF)
+option(LWS_WITH_SECURE_STREAMS_CPP "Secure Streams C++ classes" OFF)
+option(LWS_WITH_SECURE_STREAMS_PROXY_API "Secure Streams support to work across processes" OFF)
+option(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM "Auth support for api.amazon.com" OFF)
+option(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY "Secure Streams Policy is hardcoded only" OFF)
+option(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4 "Secure Streams Auth support for AWS Sigv4" OFF)
+option(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP "Secure Streams protocol buffer dump" OFF)
+option(LWS_WITH_SS_DIRECT_PROTOCOL_STR "Secure Streams directly set/get metadata w/o policy" OFF)
+
+#
+# CTest options
+#
+#
+# If you build with LWS_WITH_MINIMAL_EXAMPLES, you can use CTest / make test to run
+# examples that can give a pass/fail response.  By default it runs tests both against
+# a local server peer and warmcat.com, if your CI wants to do the tests but does not
+# have internet routing, then you can still run a subset of tests with CTest / make
+# test that only does local tests by disabling this option.
+#
+option(LWS_CTEST_INTERNET_AVAILABLE "CTest will performs tests that need the Internet" ON)
+
 #
 # TLS library options... all except mbedTLS are basically OpenSSL variants.
 #
@@ -56,12 +181,34 @@ option(LWS_WITH_BORINGSSL "Use BoringSSL replacement for OpenSSL" OFF)
 option(LWS_WITH_CYASSL "Use CyaSSL replacement for OpenSSL. When setting this, you also need to specify LWS_CYASSL_LIBRARIES and LWS_CYASSL_INCLUDE_DIRS" OFF)
 option(LWS_WITH_WOLFSSL "Use wolfSSL replacement for OpenSSL. When setting this, you also need to specify LWS_WOLFSSL_LIBRARIES and LWS_WOLFSSL_INCLUDE_DIRS" OFF)
 option(LWS_SSL_CLIENT_USE_OS_CA_CERTS "SSL support should make use of the OS-installed CA root certs" ON)
+option(LWS_TLS_LOG_PLAINTEXT_RX "For debugging log the received plaintext as soon as decrypted" OFF)
+option(LWS_TLS_LOG_PLAINTEXT_TX "For debugging log the transmitted plaintext just before encryption" OFF)
+option(LWS_WITH_TLS_SESSIONS "Enable persistent, resumable TLS sessions" ON)
+option(LWS_WITH_TLS_JIT_TRUST "Enable dynamically computing which trusted TLS CA is needed to be instantiated" OFF)
+
 #
 # Event library options (may select multiple, or none for default poll()
 #
 option(LWS_WITH_LIBEV "Compile with support for libev" OFF)
 option(LWS_WITH_LIBUV "Compile with support for libuv" OFF)
 option(LWS_WITH_LIBEVENT "Compile with support for libevent" OFF)
+option(LWS_WITH_GLIB "Compile with support for glib event loop" OFF)
+option(LWS_WITH_SDEVENT "Compile with support for sd-event loop" OFF)
+option(LWS_WITH_ULOOP "Compile with support for uloop" OFF)
+
+if (UNIX)
+# since v4.1, on unix platforms default is build any event libs as runtime plugins
+option(LWS_WITH_EVLIB_PLUGINS "Compile event lib support into runtime-selected plugins" ON)
+else()
+# otherwise default to linking the event lib(s) to libwebsockets.so
+option(LWS_WITH_EVLIB_PLUGINS "Compile event lib support into runtime-selected plugins" OFF)
+endif()
+#
+# LWS Drivers
+#
+
+option(LWS_WITH_DRIVERS "With generic drivers for gpio, i2c, display etc" OFF)
+
 #
 # Static / Dynamic build options
 #
@@ -69,12 +216,16 @@ option(LWS_WITH_STATIC "Build the static version of the library" ON)
 option(LWS_WITH_SHARED "Build the shared version of the library" ON)
 option(LWS_LINK_TESTAPPS_DYNAMIC "Link the test apps to the shared version of the library. Default is to link statically" OFF)
 option(LWS_STATIC_PIC "Build the static version of the library with position-independent code" OFF)
+option(LWS_SUPPRESS_DEPRECATED_API_WARNINGS "Turn off complaints about, eg, openssl 3 deprecated api usage" ON)
+
 #
 # Specific platforms
 #
 option(LWS_WITH_ESP32 "Build for ESP32" OFF)
-option(LWS_WITH_ESP32_HELPER "Build ESP32 helper" OFF)
 option(LWS_PLAT_OPTEE "Build for OPTEE" OFF)
+option(LWS_PLAT_FREERTOS "Build for FreeRTOS" OFF)
+option(LWS_PLAT_ANDROID "Android flavour of unix platform" OFF)
+
 #
 # Client / Server / Test Apps build control
 #
@@ -95,25 +246,31 @@ option(LWS_WITHOUT_EXTENSIONS "Don't compile with extensions" ON)
 option(LWS_WITHOUT_BUILTIN_GETIFADDRS "Don't use the BSD getifaddrs implementation from libwebsockets if it is missing (this will result in a compilation error) ... The default is to assume that your libc provides it. On some systems such as uclibc it doesn't exist." OFF)
 option(LWS_FALLBACK_GETHOSTBYNAME "Also try to do dns resolution using gethostbyname if getaddrinfo fails" OFF)
 option(LWS_WITHOUT_BUILTIN_SHA1 "Don't build the lws sha-1 (eg, because openssl will provide it" OFF)
-option(LWS_WITH_LATENCY "Build latency measuring code into the library" OFF)
 option(LWS_WITHOUT_DAEMONIZE "Don't build the daemonization api" ON)
 option(LWS_SSL_SERVER_WITH_ECDH_CERT "Include SSL server use ECDH certificate" OFF)
 option(LWS_WITH_LEJP "With the Lightweight JSON Parser" ON)
+option(LWS_WITH_CBOR "With the Lightweight LECP CBOR Parser" OFF)
+option(LWS_WITH_CBOR_FLOAT "Build floating point types if building CBOR LECP" ON)
 option(LWS_WITH_SQLITE3 "Require SQLITE3 support" OFF)
-option(LWS_WITH_STRUCT_JSON "Generic struct serialization to and from JSON" ON)
+option(LWS_WITH_STRUCT_JSON "Generic struct serialization to and from JSON" OFF)
 option(LWS_WITH_STRUCT_SQLITE3 "Generic struct serialization to and from SQLITE3" OFF)
-option(LWS_WITH_SMTP "Provide SMTP support" OFF)
-if (WIN32 OR LWS_WITH_ESP32)
+# broken atm
+#option(LWS_WITH_SMTP "Provide SMTP support" OFF)
+if (LWS_WITH_ESP32)
 option(LWS_WITH_DIR "Directory scanning api support" OFF)
 option(LWS_WITH_LEJP_CONF "With LEJP configuration parser as used by lwsws" OFF)
 else()
 option(LWS_WITH_DIR "Directory scanning api support" ON)
 option(LWS_WITH_LEJP_CONF "With LEJP configuration parser as used by lwsws" ON)
 endif()
-option(LWS_WITH_NO_LOGS "Disable all logging from being compiled in" OFF)
+option(LWS_WITH_NO_LOGS "Disable all logging other than _err and _user from being compiled in" OFF)
+set(LWS_LOGGING_BITFIELD_SET 0 CACHE STRING "Bitfield describing which log levels to force included into the build")
+set(LWS_LOGGING_BITFIELD_CLEAR 0 CACHE STRING "Bitfield describing which log levels to force removed from the build")
+option(LWS_LOGS_TIMESTAMP "Timestamp at start of logs" ON)
+option(LWS_LOG_TAG_LIFECYCLE "Log tagged object lifecycle as NOTICE" ON)
 option(LWS_AVOID_SIGPIPE_IGN "Android 7+ reportedly needs this" OFF)
-option(LWS_WITH_STATS "Keep statistics of lws internal operations" OFF)
-option(LWS_WITH_JOSE "JSON Web Signature / Encryption / Keys (RFC7515/6/) API" OFF)
+option(LWS_WITH_JOSE "JOSE JSON Web Signature / Encryption / Keys (RFC7515/6/) API" OFF)
+option(LWS_WITH_COSE "COSE CBOR Signature / Encryption / Keys (RFC8152) API" OFF)
 option(LWS_WITH_GENCRYPTO "Enable support for Generic Crypto apis independent of TLS backend" OFF)
 option(LWS_WITH_SELFTESTS "Selftests run at context creation" OFF)
 option(LWS_WITH_GCOV "Build with gcc gcov coverage instrumentation" OFF)
@@ -122,187 +279,106 @@ option(LWS_REPRODUCIBLE "Build libwebsockets reproducible. It removes the build
 option(LWS_WITH_MINIMAL_EXAMPLES "Also build the normally standalone minimal examples, for QA" OFF)
 option(LWS_WITH_LWSAC "lwsac Chunk Allocation api" ON)
 option(LWS_WITH_CUSTOM_HEADERS "Store and allow querying custom HTTP headers (H1 only)" ON)
-option(LWS_WITH_DISKCACHE "Hashed cache directory with lazy LRU deletion to size limit" OFF)
+option(LWS_WITH_DISKCACHE "Hashed cache directory with lazy LRU deletion to size limit (unrelated to lws_cache_ttl)" OFF)
 option(LWS_WITH_ASAN "Build with gcc runtime sanitizer options enabled (needs libasan)" OFF)
-option(LWS_WITH_DIR "Directory scanning api support" OFF)
 option(LWS_WITH_LEJP_CONF "With LEJP configuration parser as used by lwsws" OFF)
 option(LWS_WITH_ZLIB "Include zlib support (required for extensions)" OFF)
 option(LWS_WITH_BUNDLED_ZLIB "Use bundled zlib version (Windows only)" ${LWS_WITH_BUNDLED_ZLIB_DEFAULT})
 option(LWS_WITH_MINIZ "Use miniz instead of zlib" OFF)
-option(LWS_WITH_DEPRECATED_LWS_DLL "Migrate to lws_dll2 instead ASAP" OFF)
-option(LWS_WITH_SEQUENCER "lws_seq_t support" ON)
+option(LWS_WITH_SEQUENCER "lws_seq_t support" OFF)
 option(LWS_WITH_EXTERNAL_POLL "Support external POLL integration using callback messages (not recommended)" OFF)
 option(LWS_WITH_LWS_DSH "Support lws_dsh_t Disordered Shared Heap" OFF)
-#
-# to use miniz, enable both LWS_WITH_ZLIB and LWS_WITH_MINIZ
-#
-# End of user settings
-#
-
-# Workaround for ESP-IDF
-# Detect ESP_PLATFORM environment flag, if exist, set LWS_WITH_ESP32.
-# Otherwise the user may not be able to run configuration ESP-IDF in the first time.
-if(ESP_PLATFORM)
-       message(STATUS "ESP-IDF enabled")
-       set(LWS_WITH_ESP32 ON)
+option(LWS_CLIENT_HTTP_PROXYING "Support external http proxies for client connections" ON)
+option(LWS_WITH_FILE_OPS "Support file operations vfs" ON)
+option(LWS_WITH_UDP "Platform supports UDP" ON)
+option(LWS_WITH_SPAWN "Spawn subprocesses with piped stdin/out/stderr" OFF)
+option(LWS_WITH_FSMOUNT "Overlayfs and fallback mounting apis" OFF)
+option(LWS_WITH_FANALYZER "Enable gcc -fanalyzer if compiler supports" OFF)
+option(LWS_HTTP_HEADERS_ALL "Override header reduction optimization and include all like older lws versions" OFF)
+option(LWS_WITH_SUL_DEBUGGING "Enable zombie lws_sul checking on object deletion" OFF)
+option(LWS_WITH_PLUGINS_API "Build generic lws_plugins apis (see LWS_WITH_PLUGINS to also build protocol plugins)" OFF)
+option(LWS_WITH_CONMON "Collect introspectable connection latency stats on individual client connections" ON)
+option(LWS_WITHOUT_EVENTFD "Force using pipe instead of eventfd" OFF)
+if (UNIX OR WIN32)
+       option(LWS_WITH_CACHE_NSCOOKIEJAR "Build file-backed lws-cache-ttl that uses netscape cookie jar format (linux-only)" ON)
 else()
-       set(LWS_WITH_ESP32_HELPER OFF)
+       option(LWS_WITH_CACHE_NSCOOKIEJAR "Build file-backed lws-cache-ttl that uses netscape cookie jar format (linux-only)" OFF)
 endif()
 
-if (WIN32 OR LWS_WITH_ESP32)
-       message(STATUS "No LWS_WITH_DIR and LWS_WITH_DIR")
-       set(LWS_WITH_DIR OFF)
-       set(LWS_WITH_LEJP_CONF OFF)
-       message("LWS_WITH_DIR ${LWS_WITH_DIR}")
+if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+       option(LWS_WITH_NETLINK "Monitor Netlink for Routing Table changes" ON)
 else()
-       message(STATUS "Compiled with LWS_WITH_DIR and LWS_WITH_DIR")
-       set(LWS_WITH_DIR ON)
-       set(LWS_WITH_LEJP_CONF ON)
-endif()
-
-if (LWS_FOR_GITOHASHI)
-       set(LWS_WITH_THREADPOOL 1)
-       set(LWS_WITH_HTTP2 1)
-       set(LWS_UNIX_SOCK 1)
-       set(LWS_WITH_HTTP_PROXY 1)
-       set(LWS_WITH_FTS 1)
-       set(LWS_WITH_DISKCACHE 1)
-       set(LWS_WITH_LWSAC 1)
-       set(LWS_WITH_LEJP_CONF 1)
-endif()
-
-if(LWS_WITH_DISTRO_RECOMMENDED)
-       set(LWS_WITH_HTTP2 1)
-       set(LWS_WITH_LWSWS 1)
-       set(LWS_WITH_CGI 1)
-       set(LWS_IPV6 1)
-       set(LWS_WITH_ZIP_FOPS 1)
-       set(LWS_WITH_SOCKS5 1)
-       set(LWS_WITH_RANGES 1)
-       set(LWS_WITH_ACME 1)
-       set(LWS_WITH_SERVER_STATUS 1)
-       set(LWS_WITH_LIBUV 1)
-       set(LWS_WITH_LIBEV 1)
-       # libev + libevent cannot coexist at build-time
-       set(LWS_WITH_LIBEVENT 0)
-       set(LWS_WITHOUT_EXTENSIONS 0)
-       set(LWS_ROLE_DBUS 1)
-       set(LWS_WITH_FTS 1)
-       set(LWS_WITH_THREADPOOL 1)
-       set(LWS_UNIX_SOCK 1)
-       set(LWS_WITH_HTTP_PROXY 1)
-       set(LWS_WITH_DISKCACHE 1)
-       set(LWS_WITH_LWSAC 1)
-       set(LWS_WITH_LEJP_CONF 1)
-       set(LWS_WITH_PLUGINS 1)
-       set(LWS_ROLE_RAW_PROXY 1)
-       set(LWS_WITH_GENCRYPTO 1)
-       set(LWS_WITH_JOSE 1)
-endif()
-
-if (NOT LWS_WITH_NETWORK)
-       set(LWS_ROLE_H1 0)
-       set(LWS_ROLE_WS 0)
-       set(LWS_ROLE_RAW 0)
-       set(LWS_WITHOUT_EXTENSIONS 1)
-       set(LWS_WITHOUT_SERVER 1)
-       set(LWS_WITHOUT_CLIENT 1)
-       set(LWS_WITH_HTTP2 0)
-       set(LWS_WITH_SOCKS5 0)
-       set(LWS_UNIX_SOCK 0)
-       set(LWS_WITH_HTTP_PROXY 0)
-       set(LWS_WITH_PLUGINS 0)
-       set(LWS_WITH_LWSWS 0)
-       set(LWS_WITH_CGI 0)
-       set(LWS_ROLE_RAW_PROXY 0)
-       set(LWS_WITH_PEER_LIMITS 0)
-       set(LWS_WITH_GENERIC_SESSIONS 0)
-       set(LWS_WITH_HTTP_STREAM_COMPRESSION 0)
-       set(LWS_WITH_HTTP_BROTLI 0)
-       set(LWS_WITH_POLL 0)
-       set(LWS_WITH_SEQUENCER 0)
-       set(LWS_ROLE_DBUS 0)
-       set(LWS_WITH_LWS_DSH 0)
-endif()
-
-if (LWS_WITH_STRUCT_SQLITE3)
-       set(LWS_WITH_SQLITE3 1)
+       set(LWS_WITH_NETLINK 0)
 endif()
 
-# do you care about this?  Then send me a patch where it disables it on travis
-# but allows it on APPLE
-if (APPLE)
-       set(LWS_ROLE_DBUS 0)
+if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
+       # its openssl has md5 deprecated
+       set(LWS_SUPPRESS_DEPRECATED_API_WARNINGS 1)
 endif()
 
-if(NOT DEFINED CMAKE_BUILD_TYPE)
-       set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type")
-endif()
-
-# microsoft... that's why you can't have nice things
-
-if (WIN32 OR LWS_WITH_ESP32)
-       set(LWS_UNIX_SOCK 0)
-endif()
 
-if (LWS_WITH_ESP32)
-       set(LWS_WITH_LWSAC 0)
-       set(LWS_WITH_FTS 0)
-endif()
-
-project(libwebsockets C)
+#
+# to use miniz, enable both LWS_WITH_ZLIB and LWS_WITH_MINIZ
+#
+# End of user settings
+#
 
-set(PACKAGE "libwebsockets")
-set(CPACK_PACKAGE_NAME "${PACKAGE}")
-set(CPACK_PACKAGE_VERSION_MAJOR "3")
-set(CPACK_PACKAGE_VERSION_MINOR "2")
-set(CPACK_PACKAGE_VERSION_PATCH "3")
-set(CPACK_PACKAGE_RELEASE 1)
-set(CPACK_GENERATOR "RPM")
-set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
-set(CPACK_PACKAGE_VENDOR "andy@warmcat.com")
-set(CPACK_PACKAGE_CONTACT "andy@warmcat.com")
-set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
-set(SOVERSION "15")
-if(NOT CPACK_GENERATOR)
-    if(UNIX)
-        set(CPACK_GENERATOR "TGZ")
-    else()
-        set(CPACK_GENERATOR "ZIP")
-    endif()
-endif()
-set(CPACK_SOURCE_GENERATOR "TGZ")
-set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
-set(VERSION "${CPACK_PACKAGE_VERSION}")
+# sets of sub-options implied by other options
+#
+set(LIB_LIST "")
+set(LIB_LIST_AT_END)
+set(LWS_LIBRARIES)
+set(LWS_OPENSSL_SUPPORT 0)
+include(CMakeLists-implied-options.txt)
 
-set(LWS_LIBRARY_VERSION ${CPACK_PACKAGE_VERSION})
-set(LWS_LIBRARY_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR})
-set(LWS_LIBRARY_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR})
-set(LWS_LIBRARY_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH})
+#
+# Structural helpers for cmake in subdirs
+#
 
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
+macro(add_subdir_include_directories arg1)
+       add_subdirectory(${arg1})
+       include_directories(${_CMAKE_INC_LIST})
+endmacro()
 
+macro(exports_to_parent_scope)
+       set(SOURCES ${SOURCES} PARENT_SCOPE)
+       if (LIB_LIST)
+               set(LIB_LIST ${LIB_LIST} PARENT_SCOPE)
+       endif()
+       get_property(_CURR DIRECTORY PROPERTY INCLUDE_DIRECTORIES) 
+       set(_CMAKE_INC_LIST ${_CURR} PARENT_SCOPE)
+       if (LWS_LIB_BUILD_INC_PATHS)
+               set(LWS_LIB_BUILD_INC_PATHS ${LWS_LIB_BUILD_INC_PATHS} PARENT_SCOPE)
+       endif()
+endmacro()
 
-message(STATUS "CMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}'")
+macro(export_to_parent_intermediate)
+       set(SOURCES ${SOURCES} PARENT_SCOPE)
+       if (LIB_LIST)
+               set(LIB_LIST ${LIB_LIST} PARENT_SCOPE)
+       endif()
+       set(_CMAKE_INC_LIST ${_CMAKE_INC_LIST} PARENT_SCOPE)
+       if (LWS_LIB_BUILD_INC_PATHS)
+               set(LWS_LIB_BUILD_INC_PATHS ${LWS_LIB_BUILD_INC_PATHS} PARENT_SCOPE)
+       endif()
+endmacro()
 
-if(WIN32)
-       configure_file(${CMAKE_CURRENT_SOURCE_DIR}/win32port/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/win32port/version.rc @ONLY)
-       set(RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/win32port/version.rc)
-endif()
+#
+# Try to find the current Git hash
+#
 
-# Try to find the current Git hash.
 find_package(Git)
 if(GIT_EXECUTABLE)
        execute_process(
                WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
-               COMMAND "${GIT_EXECUTABLE}" describe --tags
+               COMMAND "${GIT_EXECUTABLE}" describe --tags --always
                OUTPUT_VARIABLE GIT_HASH
                OUTPUT_STRIP_TRAILING_WHITESPACE
                )
        set(LWS_BUILD_HASH ${GIT_HASH})
 
        # append the build user and hostname
-       if(NOT LWS_REPRODUCIBLE)
+       if (NOT LWS_REPRODUCIBLE)
                execute_process(
                        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
                        COMMAND "whoami"
@@ -322,142 +398,78 @@ if(GIT_EXECUTABLE)
        message("Git commit hash: ${LWS_BUILD_HASH}")
 endif()
 
-# translate old functionality enables to set up ROLE enables so nothing changes
-if (LWS_WITH_HTTP2 AND LWS_WITHOUT_SERVER)
-       set(LWS_WITH_HTTP2 0)
-       message("HTTP2 disabled due to LWS_WITHOUT_SERVER")
+if ("${LWS_BUILD_HASH}" STREQUAL "")
+       set(LWS_BUILD_HASH "unknown")
 endif()
 
-if (LWS_WITH_HTTP2)
-       set(LWS_ROLE_H2 1)
-endif()
-if (LWS_WITH_CGI)
-       set(LWS_ROLE_CGI 1)
-endif()
+set(PACKAGE "libwebsockets")
+set(CPACK_RPM_PACKAGE_LICENSE "MIT")
+set(CPACK_PACKAGE_NAME "${PACKAGE}")
+set(CPACK_PACKAGE_VERSION_MAJOR "4")
+set(CPACK_PACKAGE_VERSION_MINOR "3")
+set(CPACK_PACKAGE_VERSION_PATCH_NUMBER "0")
 
-if (NOT LWS_ROLE_WS)
-       set(LWS_WITHOUT_EXTENSIONS 1)
-endif()
+set(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH_NUMBER}-${LWS_BUILD_HASH}")
+set(CPACK_PACKAGE_RELEASE 1)
 
-include_directories(include plugins)
-
-if (LWS_WITH_LWSWS)
- message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV")
- set(LWS_WITH_PLUGINS 1)
- set(LWS_WITH_LIBUV 1)
- set(LWS_WITH_ACCESS_LOG 1)
- set(LWS_WITH_SERVER_STATUS 1)
- set(LWS_WITH_LEJP 1)
- set(LWS_WITH_LEJP_CONF 1)
- set(LWS_WITH_PEER_LIMITS 1)
- set(LWS_ROLE_RAW_PROXY 1)
+set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+set(CPACK_PACKAGE_VENDOR "andy@warmcat.com")
+set(CPACK_PACKAGE_CONTACT "andy@warmcat.com")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${CPACK_PACKAGE_VERSION}")
+set(SOVERSION "19")
+if(NOT CPACK_GENERATOR)
+    if(UNIX)
+        set(CPACK_GENERATOR "TGZ")
+    else()
+        set(CPACK_GENERATOR "ZIP")
+    endif()
 endif()
+set(CPACK_SOURCE_GENERATOR "TGZ")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
+set(VERSION "${CPACK_PACKAGE_VERSION}")
 
-# sshd plugin
-if (LWS_WITH_PLUGINS)
- set(LWS_WITH_GENCRYPTO 1)
-endif()
+set(CPACK_RPM_PACKAGE_RELEASE_DIST ON)
+set(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
+# below makes path length problems in CI
+set(CPACK_RPM_DEBUGINFO_PACKAGE OFF)
+# below makes some kind of chimera rpm with binaries and sources
+set(CPACK_RPM_PACKAGE_SOURCES OFF)
+set(CPACK_RPM_INSTALL_WITH_EXEC ON)
+set(CPACK_RPM_COMPONENT_INSTALL ON)
 
-if (LWS_ROLE_RAW_PROXY)
- set (LWS_WITHOUT_CLIENT 0)
- set (LWS_WITHOUT_SERVER 0)
-endif()
+set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+set(CPACK_DEBIAN_DEBUGINFO_PACKAGE ON)
+set(CPACK_DEBIAN_PACKAGE_SOURCE ON)
+set(CPACK_DEBIAN_COMPONENT_INSTALL ON)
 
-if (LWS_WITH_ACME)
- set (LWS_WITHOUT_CLIENT 0)
- set (LWS_WITHOUT_SERVER 0)
- set (LWS_WITH_JOSE 1)
-endif()
 
-if (LWS_WITH_JOSE)
- set(LWS_WITH_LEJP 1)
- set(LWS_WITH_GENCRYPTO 1)
-endif()
+set(LWS_LIBRARY_VERSION ${CPACK_PACKAGE_VERSION})
+set(LWS_LIBRARY_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR})
+set(LWS_LIBRARY_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR})
+set(LWS_LIBRARY_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH_NUMBER})
+set(LWS_LIBRARY_VERSION_PATCH_ELABORATED ${CPACK_PACKAGE_VERSION_PATCH})
 
-if (LWS_WITH_PLUGINS AND NOT LWS_WITH_LIBUV)
-message(STATUS "LWS_WITH_PLUGINS --> Enabling LWS_WITH_LIBUV")
- set(LWS_WITH_LIBUV 1)
+if (NOT CMAKE_MODULE_PATH)
+       set(CMAKE_MODULE_PATH "")
 endif()
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
 
-if (LWS_WITH_PLUGINS OR LWS_WITH_CGI)
-       # sshd plugin
- set(LWS_WITH_GENCRYPTO 1)
-endif()
 
-if (LWS_WITH_GENERIC_SESSIONS)
- set(LWS_WITH_SQLITE3 1)
- set(LWS_WITH_SMTP 1)
- set(LWS_WITH_STRUCT_SQLITE3 1)
+if (CMAKE_TOOLCHAIN_FILE)
+       message(STATUS "CMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}'")
 endif()
 
-if (LWS_WITH_ESP32)
- set(LWS_WITH_SHARED OFF)
- set(LWS_WITH_MBEDTLS ON)
-  # set(LWS_WITHOUT_CLIENT ON)
- set(LWS_WITHOUT_TESTAPPS ON)
- set(LWS_WITHOUT_EXTENSIONS ON)
- set(LWS_WITH_PLUGINS OFF)
- set(LWS_WITH_RANGES ON)
- # this implies no pthreads in the lib
- set(LWS_MAX_SMP 1)
- set(LWS_HAVE_MALLOC 1)
- set(LWS_HAVE_REALLOC 1)
- set(LWS_HAVE_GETIFADDRS 1)
- set(LWS_WITH_ZIP_FOPS 1)
- set(LWS_WITH_CUSTOM_HEADERS 0)
+if (NOT LIB_SUFFIX)
+       set(LIB_SUFFIX "")
 endif()
 
-
 if (WIN32)
-set(LWS_MAX_SMP 1)
-set(LWS_WITH_THREADPOOL 0)
-endif()
-
-if (LWS_WITHOUT_SERVER)
-set(LWS_WITH_LWSWS OFF)
-endif()
-
-if (LWS_WITH_LEJP_CONF)
-       set(LWS_WITH_DIR 1)
-endif()
-
-# confirm H1 relationships
-
-if (NOT LWS_ROLE_H1 AND LWS_ROLE_H2)
-       message(FATAL_ERROR "H2 requires LWS_ROLE_H1")
-endif()
-
-if (NOT LWS_ROLE_H1 AND LWS_ROLE_WS)
-       message(FATAL_ERROR "WS requires LWS_ROLE_H1")
-endif()
-
-if (NOT LWS_ROLE_H1 AND LWS_ROLE_CGI)
-       message(FATAL_ERROR "CGI requires LWS_ROLE_H1")
-endif()
-
-# confirm HTTP relationships
-
-if (NOT LWS_ROLE_H1 AND NOT LWS_ROLE_H2 AND LWS_WITH_HTTP_PROXY)
-       message(FATAL_ERROR "LWS_WITH_LWSWS requires LWS_ROLE_H1")
-endif()
-
-if (NOT LWS_ROLE_H1 AND NOT LWS_ROLE_H2 AND LWS_WITH_HTTP_PROXY)
-       message(FATAL_ERROR "LWS_WITH_HTTP_PROXY requires LWS_ROLE_H1")
-endif()
-
-if (NOT LWS_ROLE_H1 AND NOT LWS_ROLE_H2 AND LWS_WITH_RANGES)
-       message(FATAL_ERROR "LWS_WITH_RANGES requires LWS_ROLE_H1")
-endif()
-
-if (NOT LWS_ROLE_H1 AND NOT LWS_ROLE_H2 AND LWS_WITH_ACCESS_LOG)
-       message(FATAL_ERROR "LWS_WITH_ACCESS_LOG requires LWS_ROLE_H1")
+       configure_file(${CMAKE_CURRENT_SOURCE_DIR}/win32port/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/win32port/version.rc @ONLY)
+       set(RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/win32port/version.rc)
 endif()
 
-
-if (LWS_WITH_HTTP_PROXY AND (LWS_WITHOUT_CLIENT OR LWS_WITHOUT_SERVER))
-       message("You have to enable both client and server for http proxy")
-       set(LWS_WITH_HTTP_PROXY 0)
-endif()
+include_directories(include)
 
 # Allow the user to override installation directories.
 set(LWS_INSTALL_LIB_DIR       lib CACHE PATH "Installation directory for libraries")
@@ -465,111 +477,20 @@ set(LWS_INSTALL_BIN_DIR       bin CACHE PATH "Installation directory for executa
 set(LWS_INSTALL_INCLUDE_DIR   include CACHE PATH "Installation directory for header files")
 set(LWS_INSTALL_EXAMPLES_DIR  bin CACHE PATH "Installation directory for example files")
 
-# Allow the user to use the old CyaSSL options/library in stead of wolfSSL
-if (LWS_WITH_CYASSL AND LWS_WITH_WOLFSSL)
-       message(FATAL_ERROR "LWS_WITH_CYASSL and LWS_WITH_WOLFSSL are mutually exclusive!")
-endif()
-if (LWS_WITH_CYASSL)
-       # Copy CyaSSL options to the wolfSSL options
-       set(LWS_WITH_WOLFSSL ${LWS_WITH_CYASSL} CACHE BOOL "Use wolfSSL/CyaSSL instead of OpenSSL" FORCE)
-       set(LWS_WOLFSSL_LIBRARIES ${LWS_CYASSL_LIBRARIES} CACHE PATH "Path to wolfSSL/CyaSSL libraries" FORCE)
-       set(LWS_WOLFSSL_INCLUDE_DIRS ${LWS_CYASSL_INCLUDE_DIRS} CACHE PATH "Path to wolfSSL/CyaSSL header files" FORCE)
-endif()
-
-if (NOT (LWS_WITH_STATIC OR LWS_WITH_SHARED))
-       message(FATAL_ERROR "Makes no sense to compile with neither static nor shared libraries.")
-endif()
-
-if (NOT LWS_WITHOUT_EXTENSIONS OR LWS_WITH_ZIP_FOPS)
-       set(LWS_WITH_ZLIB 1)
-endif()
-
 # if you gave LWS_WITH_MINIZ, point to MINIZ here if not found
 # automatically
 
 set(LWS_ZLIB_LIBRARIES CACHE PATH "Path to the zlib/miniz library")
 set(LWS_ZLIB_INCLUDE_DIRS CACHE PATH "Path to the zlib/miniz include directory")
-set(LWS_OPENSSL_LIBRARIES CACHE PATH "Path to the OpenSSL library")
-set(LWS_OPENSSL_INCLUDE_DIRS CACHE PATH "Path to the OpenSSL include directory")
-set(LWS_WOLFSSL_LIBRARIES CACHE PATH "Path to the wolfSSL library")
-set(LWS_WOLFSSL_INCLUDE_DIRS CACHE PATH "Path to the wolfSSL include directory")
-set(LWS_LIBEV_LIBRARIES CACHE PATH "Path to the libev library")
-set(LWS_LIBEV_INCLUDE_DIRS CACHE PATH "Path to the libev include directory")
-set(LWS_LIBUV_LIBRARIES CACHE PATH "Path to the libuv library")
-set(LWS_LIBUV_INCLUDE_DIRS CACHE PATH "Path to the libuv include directory")
 set(LWS_SQLITE3_LIBRARIES CACHE PATH "Path to the sqlite3 library")
 set(LWS_SQLITE3_INCLUDE_DIRS CACHE PATH "Path to the sqlite3 include directory")
-set(LWS_LIBEVENT_INCLUDE_DIRS CACHE PATH "Path to the libevent include directory")
-set(LWS_LIBEVENT_LIBRARIES CACHE PATH "Path to the libevent library")
-
-
-if (NOT LWS_WITH_SSL)
-       set(LWS_WITHOUT_BUILTIN_SHA1 OFF)
-endif()
-
-if (LWS_WITH_BORINGSSL)
-       # boringssl deprecated EVP_PKEY
-       set (LWS_WITH_GENHASH OFF)
-endif()
-
-if (LWS_WITH_SSL AND NOT LWS_WITH_WOLFSSL AND NOT LWS_WITH_MBEDTLS)
-       if ("${LWS_OPENSSL_LIBRARIES}" STREQUAL "" OR "${LWS_OPENSSL_INCLUDE_DIRS}" STREQUAL "")
-       else()
-               if (NOT LWS_WITH_ESP32)
-                       set(OPENSSL_LIBRARIES ${LWS_OPENSSL_LIBRARIES})
-               endif()
-               set(OPENSSL_INCLUDE_DIRS ${LWS_OPENSSL_INCLUDE_DIRS})
-               set(OPENSSL_FOUND 1)
-       endif()
-endif()
-
-if (LWS_WITH_SSL AND LWS_WITH_WOLFSSL)
-       if ("${LWS_WOLFSSL_LIBRARIES}" STREQUAL "" OR "${LWS_WOLFSSL_INCLUDE_DIRS}" STREQUAL "")
-               if (NOT WOLFSSL_FOUND)
-                       if (LWS_WITH_CYASSL)
-                               message(FATAL_ERROR "You must set LWS_CYASSL_LIBRARIES and LWS_CYASSL_INCLUDE_DIRS when LWS_WITH_CYASSL is turned on.")
-                       else()
-                               message(FATAL_ERROR "You must set LWS_WOLFSSL_LIBRARIES and LWS_WOLFSSL_INCLUDE_DIRS when LWS_WITH_WOLFSSL is turned on.")
-                       endif()
-               endif()
-       else()
-               set(WOLFSSL_LIBRARIES ${LWS_WOLFSSL_LIBRARIES})
-               set(WOLFSSL_INCLUDE_DIRS ${LWS_WOLFSSL_INCLUDE_DIRS})
-               set(WOLFSSL_FOUND 1)
-       endif()
-       set(USE_WOLFSSL 1)
-       set(LWS_WITH_TLS 1)
-       if (LWS_WITH_CYASSL)
-               set(USE_OLD_CYASSL 1)
-       endif()
-endif()
-
-if (LWS_WITH_SSL AND LWS_WITH_MBEDTLS)
-       if ("${LWS_MBEDTLS_LIBRARIES}" STREQUAL "" OR "${LWS_MBEDTLS_INCLUDE_DIRS}" STREQUAL "" AND NOT LWS_WITH_ESP32)
-
-               find_path(LWS_MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h)
-
-               find_library(MBEDTLS_LIBRARY mbedtls)
-               find_library(MBEDX509_LIBRARY mbedx509)
-               find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
-
-               set(LWS_MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
-
-               include(FindPackageHandleStandardArgs)
-               find_package_handle_standard_args(MBEDTLS DEFAULT_MSG
-                       LWS_MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+set(LWS_LIBMOUNT_INCLUDE_DIRS CACHE PATH "Path to the libmount include directory")
+set(LWS_LIBMOUNT_LIBRARIES CACHE PATH "Path to the libmount library")
+# on unix, these are in the toolchain.  On win32 you have to put them somewhere
+# yourself and point to them here
+set(LWS_EXT_PTHREAD_INCLUDE_DIR CACHE PATH "Path to an external pthreads include directory")
+set(LWS_EXT_PTHREAD_LIBRARIES CACHE PATH "Path to an external pthreads library")
 
-               mark_as_advanced(LWS_MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
-
-               if ("${LWS_MBEDTLS_LIBRARIES}" STREQUAL "" OR "${LWS_MBEDTLS_INCLUDE_DIRS}" STREQUAL "")
-                       message(FATAL_ERROR "You must set LWS_MBEDTLS_LIBRARIES and LWS_MBEDTLS_INCLUDE_DIRS when LWS_WITH_MBEDTLS is turned on.")
-               endif()
-       endif()
-       set(MBEDTLS_LIBRARIES ${LWS_MBEDTLS_LIBRARIES})
-       set(MBEDTLS_INCLUDE_DIRS ${LWS_MBEDTLS_INCLUDE_DIRS})
-       set(MBEDTLS_FOUND 1)
-       set(USE_MBEDTLS 1)
-endif()
 
 if (LWS_WITH_HTTP_STREAM_COMPRESSION)
        set(LWS_WITH_ZLIB 1)
@@ -584,32 +505,6 @@ if (LWS_WITH_ZLIB AND NOT LWS_WITH_BUNDLED_ZLIB)
        endif()
 endif()
 
-if (LWS_WITH_LIBEV)
-       if ("${LWS_LIBEV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBEV_INCLUDE_DIRS}" STREQUAL "")
-       else()
-               set(LIBEV_LIBRARIES ${LWS_LIBEV_LIBRARIES})
-               set(LIBEV_INCLUDE_DIRS ${LWS_LIBEV_INCLUDE_DIRS})
-               set(LIBEV_FOUND 1)
-       endif()
-endif()
-
-if (LWS_WITH_LIBUV)
-       if ("${LWS_LIBUV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBUV_INCLUDE_DIRS}" STREQUAL "")
-       else()
-               set(LIBUV_LIBRARIES ${LWS_LIBUV_LIBRARIES})
-               set(LIBUV_INCLUDE_DIRS ${LWS_LIBUV_INCLUDE_DIRS})
-               set(LIBUV_FOUND 1)
-       endif()
-endif()
-
-if (LWS_WITH_LIBEVENT)
-       if ("${LWS_LIBEVENT_LIBRARIES}" STREQUAL "" OR "${LWS_LIBEVENT_INCLUDE_DIRS}" STREQUAL "")
-       else()
-               set(LIBEVENT_LIBRARIES ${LWS_LIBEVENT_LIBRARIES})
-               set(LIBEVENT_INCLUDE_DIRS ${LWS_LIBEVENT_INCLUDE_DIRS})
-               set(LIBEVENT_FOUND 1)
-       endif()
-endif()
 
 if (LWS_WITH_SQLITE3)
        if ("${LWS_SQLITE3_LIBRARIES}" STREQUAL "" OR "${LWS_SQLITE3_INCLUDE_DIRS}" STREQUAL "")
@@ -620,155 +515,51 @@ if (LWS_WITH_SQLITE3)
        endif()
 endif()
 
+include_directories("${PROJECT_BINARY_DIR}")
 
-if (LWS_WITH_LIBEV AND LWS_WITH_LIBEVENT)
-       message(FATAL_ERROR "Sorry libev and libevent conflict with each others' namespace, you can only have one or the other")
-endif()
-
-# The base dir where the test-apps look for the SSL certs.
-set(LWS_OPENSSL_CLIENT_CERTS ../share CACHE PATH "Server SSL certificate directory")
-if (WIN32)
-       set(LWS_OPENSSL_CLIENT_CERTS . CACHE PATH "Client SSL certificate directory")
+# Check for different inline keyword versions.
+foreach(KEYWORD "inline" "__inline__" "__inline")
+       set(CMAKE_REQUIRED_DEFINITIONS "-DKEYWORD=${KEYWORD}")
+       CHECK_C_SOURCE_COMPILES(
+               "
+               #include <stdio.h>
+               static KEYWORD void a() {}
+               int main(int argc, char **argv) { a(); return 0; }
+               " LWS_HAVE_${KEYWORD})
+endforeach()
 
-       if (LWS_UNIX_SOCK)
-               set(LWS_UNIX_SOCK OFF)
-               message(WARNING "Windows does not support UNIX domain sockets")
+if (NOT LWS_HAVE_inline)
+       if (LWS_HAVE___inline__)
+               set(inline __inline__)
+       elseif(LWS_HAVE___inline)
+               set(inline __inline)
        endif()
-else()
-       set(LWS_OPENSSL_CLIENT_CERTS /etc/pki/tls/certs/ CACHE PATH "Client SSL certificate directory")
-endif()
-
-# LWS_OPENSSL_SUPPORT deprecated... use LWS_WITH_TLS
-if (LWS_WITH_SSL OR LWS_WITH_MBEDTLS)
-       set(LWS_OPENSSL_SUPPORT 1)
-       set(LWS_WITH_TLS 1)
-endif()
-
-if (LWS_SSL_CLIENT_USE_OS_CA_CERTS)
-       set(LWS_SSL_CLIENT_USE_OS_CA_CERTS 1)
-endif()
-
-if (LWS_WITH_LATENCY)
-       set(LWS_LATENCY 1)
 endif()
 
-if (LWS_WITHOUT_DAEMONIZE OR WIN32)
-       set(LWS_NO_DAEMONIZE 1)
-endif()
+# Put the libraries and binaries that get built into directories at the
+# top of the build tree rather than in hard-to-find leaf directories. 
+SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
+SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
+SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
 
-if (LWS_WITHOUT_SERVER)
-       set(LWS_NO_SERVER 1)
-endif()
+SET(LWS_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}")
 
-if (LWS_WITHOUT_CLIENT)
-       set(LWS_NO_CLIENT 1)
-endif()
+# Put absolute path of dynamic libraries into the object code. Some
+# architectures, notably Mac OS X, need this.
+SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}")
 
-if (LWS_WITH_LIBEV)
-       set(LWS_WITH_LIBEV 1)
+if (LWS_WITHOUT_BUILTIN_SHA1)
+       set(LWS_SHA1_USE_OPENSSL_NAME 1)
 endif()
 
-if (LWS_WITH_LIBUV)
-       set(LWS_WITH_LIBUV 1)
-endif()
-
-if (LWS_WITH_LIBEVENT)
-       set(LWS_WITH_LIBEVENT 1)
-endif()
-
-if (LWS_IPV6)
-       set(LWS_WITH_IPV6 1)
-endif()
-
-if (LWS_UNIX_SOCK)
-    set(LWS_WITH_UNIX_SOCK 1)
-endif()
-
-if (LWS_WITH_HTTP2)
-       set(LWS_WITH_HTTP2 1)
-endif()
-
-if ("${LWS_MAX_SMP}" STREQUAL "")
-       set(LWS_MAX_SMP 1)
-endif()
-
-# using any abstract protocol enables LWS_WITH_ABSTRACT
-
-if (LWS_WITH_SMTP)
-       set(LWS_WITH_ABSTRACT 1)
-endif()
-
-
-
-if (MINGW)
-       set(LWS_MINGW_SUPPORT 1)
-       set(CMAKE_C_FLAGS "-D__USE_MINGW_ANSI_STDIO ${CMAKE_C_FLAGS}")
-       add_definitions(-DWINVER=0x0601 -D_WIN32_WINNT=0x0601)
-endif()
-
-if (LWS_SSL_SERVER_WITH_ECDH_CERT)
-       set(LWS_SSL_SERVER_WITH_ECDH_CERT 1)
-endif()
-
-include_directories("${PROJECT_BINARY_DIR}")
-
-include(CheckCSourceCompiles)
-
-# Check for different inline keyword versions.
-foreach(KEYWORD "inline" "__inline__" "__inline")
-       set(CMAKE_REQUIRED_DEFINITIONS "-DKEYWORD=${KEYWORD}")
-       CHECK_C_SOURCE_COMPILES(
-               "
-               #include <stdio.h>
-               static KEYWORD void a() {}
-               int main(int argc, char **argv) { a(); return 0; }
-               " LWS_HAVE_${KEYWORD})
-endforeach()
-
-if (NOT LWS_HAVE_inline)
-       if (LWS_HAVE___inline__)
-               set(inline __inline__)
-       elseif(LWS_HAVE___inline)
-               set(inline __inline)
-       endif()
-endif()
-
-# Put the libraries and binaries that get built into directories at the
-# top of the build tree rather than in hard-to-find leaf directories. 
-SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
-SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
-SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
-
-SET(LWS_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}")
-
-# Put absolute path of dynamic libraries into the object code. Some
-# architectures, notably Mac OS X, need this.
-SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}")
-
-include(CheckFunctionExists)
-include(CheckSymbolExists)
-include(CheckIncludeFile)
-include(CheckIncludeFiles)
-include(CheckLibraryExists)
-include(CheckTypeSize)
-include(CheckCSourceCompiles)
-
-if (LWS_WITHOUT_BUILTIN_SHA1)
-       set(LWS_SHA1_USE_OPENSSL_NAME 1)
-endif()
-
-if (HAIKU)
-       set(CMAKE_REQUIRED_LIBRARIES network)
-endif()
-
-CHECK_C_SOURCE_COMPILES(
-       "#include <malloc.h>
-       int main(int argc, char **argv) { return malloc_trim(0); }
-       " LWS_HAVE_MALLOC_TRIM)
-CHECK_C_SOURCE_COMPILES(
-       "#include <malloc.h>
-       int main(int argc, char **argv) { return (int)malloc_usable_size((void *)0); }
-       " LWS_HAVE_MALLOC_USABLE_SIZE)
+CHECK_C_SOURCE_COMPILES(
+       "#include <malloc.h>
+       int main(int argc, char **argv) { return malloc_trim(0); }
+       " LWS_HAVE_MALLOC_TRIM)
+CHECK_C_SOURCE_COMPILES(
+       "#include <malloc.h>
+       int main(int argc, char **argv) { return (int)malloc_usable_size((void *)0); }
+       " LWS_HAVE_MALLOC_USABLE_SIZE)
 
 CHECK_FUNCTION_EXISTS(fork LWS_HAVE_FORK)
 CHECK_FUNCTION_EXISTS(getenv LWS_HAVE_GETENV)
@@ -788,7 +579,21 @@ CHECK_FUNCTION_EXISTS(atoll LWS_HAVE_ATOLL)
 CHECK_FUNCTION_EXISTS(_atoi64 LWS_HAVE__ATOI64)
 CHECK_FUNCTION_EXISTS(_stat32i64 LWS_HAVE__STAT32I64)
 CHECK_FUNCTION_EXISTS(clock_gettime LWS_HAVE_CLOCK_GETTIME)
-CHECK_FUNCTION_EXISTS(eventfd LWS_HAVE_EVENTFD)
+CHECK_FUNCTION_EXISTS(localtime_r LWS_HAVE_LOCALTIME_R)
+CHECK_FUNCTION_EXISTS(gmtime_r LWS_HAVE_GMTIME_R)
+CHECK_FUNCTION_EXISTS(ctime_r LWS_HAVE_CTIME_R)
+CHECK_FUNCTION_EXISTS(getgrgid_r LWS_HAVE_GETGRGID_R)
+CHECK_FUNCTION_EXISTS(getgrnam_r LWS_HAVE_GETGRNAM_R)
+CHECK_FUNCTION_EXISTS(getpwuid_r LWS_HAVE_GETPWUID_R)
+CHECK_FUNCTION_EXISTS(getpwnam_r LWS_HAVE_GETPWNAM_R)
+CHECK_FUNCTION_EXISTS(timegm LWS_HAVE_TIMEGM)
+
+if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+       if(CMAKE_OSX_DEPLOYMENT_TARGET LESS "10.12")
+               message("No clock_gettime found on macOS ${CMAKE_OSX_DEPLOYMENT_TARGET}. Disabling LWS_HAVE_CLOCK_GETTIME.")
+               set(LWS_HAVE_CLOCK_GETTIME 0)
+       endif()
+endif()
 
 if (NOT LWS_HAVE_GETIFADDRS)
        if (LWS_WITHOUT_BUILTIN_GETIFADDRS)
@@ -797,8 +602,31 @@ if (NOT LWS_HAVE_GETIFADDRS)
        set(LWS_BUILTIN_GETIFADDRS 1)
 endif()
 
-CHECK_INCLUDE_FILE(dlfcn.h LWS_HAVE_DLFCN_H)
-CHECK_INCLUDE_FILE(fcntl.h LWS_HAVE_FCNTL_H)
+if (LWS_EXT_PTHREAD_INCLUDE_DIR)
+       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_EXT_PTHREAD_INCLUDE_DIR})
+       include_directories(${LWS_EXT_PTHREAD_INCLUDE_DIR})
+
+       list(APPEND LIB_LIST_AT_END ${LWS_EXT_PTHREAD_LIBRARIES})
+       set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} " -DHAVE_STRUCT_TIMESPEC=1")
+endif()
+
+#
+# add libs here that need to be at the end of the link order
+#
+
+if (LWS_EXT_PTHREAD_INCLUDE_DIR)
+       list(APPEND LIB_LIST_AT_END ${LWS_EXT_PTHREAD_LIBRARIES})
+endif()
+
+if (LWS_WITH_ZLIB AND NOT LWS_WITH_BUNDLED_ZLIB)
+       list(APPEND LIB_LIST_AT_END "${ZLIB_LIBRARIES}")
+endif()
+
+if (LWS_WITH_PLUGINS_API AND UNIX AND CMAKE_DL_LIBS AND NOT (${CMAKE_SYSTEM_NAME} MATCHES "QNX"))
+       list(APPEND LIB_LIST_AT_END ${CMAKE_DL_LIBS})
+endif()
+
+
 CHECK_INCLUDE_FILE(in6addr.h LWS_HAVE_IN6ADDR_H)
 CHECK_INCLUDE_FILE(memory.h LWS_HAVE_MEMORY_H)
 CHECK_INCLUDE_FILE(netinet/in.h LWS_HAVE_NETINET_IN_H)
@@ -817,61 +645,20 @@ CHECK_INCLUDE_FILE(sys/capability.h LWS_HAVE_SYS_CAPABILITY_H)
 CHECK_INCLUDE_FILE(malloc.h LWS_HAVE_MALLOC_H)
 CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
 CHECK_INCLUDE_FILE(inttypes.h LWS_HAVE_INTTYPES_H)
+CHECK_INCLUDE_FILE(sys/resource.h LWS_HAVE_SYS_RESOURCE_H)
 
-CHECK_LIBRARY_EXISTS(cap cap_set_flag "" LWS_HAVE_LIBCAP)
-
-if (LWS_ROLE_DBUS)
-
-       if (NOT LWS_DBUS_LIB)
-               set(LWS_DBUS_LIB "dbus-1")
-       endif()
-
-       CHECK_LIBRARY_EXISTS(${LWS_DBUS_LIB} dbus_connection_set_watch_functions "" LWS_HAVE_LIBDBUS)
-       if (NOT LWS_HAVE_LIBDBUS)
-               message(FATAL_ERROR "Install dbus-devel, or libdbus-1-dev etc")
-       endif()
-
-       if (NOT LWS_DBUS_INCLUDE1)
-               # look in fedora and debian / ubuntu place
-               if (EXISTS "/usr/include/dbus-1.0")
-                       set(LWS_DBUS_INCLUDE1 "/usr/include/dbus-1.0")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE1 to /usr/include/dbus-1.0 or wherever the main dbus includes are")
-               endif()
-       endif()
+if (WIN32 OR MSVC)
+       CHECK_C_SOURCE_COMPILES("#include <winsock2.h>
+                                #include <afunix.h>
+                                int main() { return 0; }" LWS_HAVE_WIN32_AFUNIX_H)
 
-       if (NOT LWS_DBUS_INCLUDE2)
-               # look in fedora... debian / ubuntu has the ARCH in the path...
-               if (EXISTS "/usr/lib64/dbus-1.0/include")
-                       set(LWS_DBUS_INCLUDE2 "/usr/lib64/dbus-1.0/include")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE2 to /usr/lib/ARCH-linux-gnu/dbus-1.0/include or wherever dbus-arch-deps.h is on your system")
-               endif()
+       if (LWS_UNIX_SOCK AND NOT LWS_HAVE_WIN32_AFUNIX_H)
+               message("No afunix.h found. Disabling LWS_UNIX_SOCK.")
+               set(LWS_WITH_UNIX_SOCK OFF)
        endif()
-
-       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_DBUS_INCLUDE1};${LWS_DBUS_INCLUDE2})
-
-       CHECK_C_SOURCE_COMPILES("#include <dbus/dbus.h>
-       int main(void) {
-               return 0;
-       }" LWS_DBUS_CHECK_OK)
-endif()
-
-if (LWS_WITH_LIBUV)
-CHECK_INCLUDE_FILE(uv-version.h LWS_HAVE_UV_VERSION_H)
-  # libuv changed the location in 1.21.0. Retain both
-  # checks temporarily to ensure a smooth transition.
-  if (NOT LWS_HAVE_UV_VERSION_H)
-    CHECK_INCLUDE_FILE(uv/version.h LWS_HAVE_NEW_UV_VERSION_H)
-  endif()
 endif()
 
-if (LWS_WITH_LIBEV)
-       CHECK_C_SOURCE_COMPILES(
-        "#include <ev.h>
-        int main(int argc, char **argv) { return EVBACKEND_LINUXAIO; }
-        " LWS_HAVE_EVBACKEND_LINUXAIO)
-endif()
+CHECK_LIBRARY_EXISTS(cap cap_set_flag "" LWS_HAVE_LIBCAP)
 
 
 if (LWS_WITH_ZLIB AND NOT LWS_WITH_BUNDLED_ZLIB)
@@ -882,11 +669,17 @@ if (LWS_WITH_ZLIB AND NOT LWS_WITH_BUNDLED_ZLIB)
        endif()
 endif()
 
-# TODO: These can also be tested to see whether they actually work...
-set(LWS_HAVE_WORKING_FORK LWS_HAVE_FORK)
-set(LWS_HAVE_WORKING_VFORK LWS_HAVE_VFORK)
+CHECK_INCLUDE_FILES("stdlib.h;stdarg.h;string.h" STDC_HEADERS)
 
-CHECK_INCLUDE_FILES("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
+if (NOT CMAKE_REQUIRED_FLAGS)
+       set(CMAKE_REQUIRED_FLAGS "")
+endif()
+if (NOT CMAKE_REQUIRED_INCLUDES)
+       set(CMAKE_REQUIRED_INCLUDES "")
+endif()
+if (NOT CMAKE_REQUIRED_LIBRARIES)
+       set(CMAKE_REQUIRED_LIBRARIES "")
+endif()
 
 CHECK_C_SOURCE_COMPILES("#include <stdint.h> 
        int main(void) {
@@ -894,17 +687,23 @@ CHECK_C_SOURCE_COMPILES("#include <stdint.h>
                return 0;
        }" LWS_HAS_INTPTR_T)
 
-if (LWS_HAVE_PTHREAD_H)
-       if ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
-               set(CMAKE_REQUIRED_FLAGS "-pthread -Wno-error=unused-command-line-argument")
-       else()
-               set(CMAKE_REQUIRED_FLAGS "-pthread")
-       endif()
+if ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR
+    (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
+       set(COMPILER_IS_CLANG ON)
+endif()
 
-       CHECK_C_SOURCE_COMPILES("#define _GNU_SOURCE
+if (LWS_HAVE_PTHREAD_H AND NOT LWS_PLAT_FREERTOS)
+       CHECK_C_SOURCE_COMPILES("
+               #ifndef _GNU_SOURCE
+               #define _GNU_SOURCE
+               #endif
                #include <pthread.h>
                int main(void) {
+               #ifdef __PTW32_H
+                       pthread_t th = {0,0};
+               #else
                        pthread_t th = 0;
+               #endif
                        pthread_setname_np(th, NULL);
                        return 0;
                }" LWS_HAS_PTHREAD_SETNAME_NP)
@@ -917,6 +716,17 @@ CHECK_C_SOURCE_COMPILES("#include <stddef.h>
                return p != NULL;
        }" LWS_HAS_GETOPT_LONG)
 
+CHECK_C_SOURCE_COMPILES("#include <linux/rtnetlink.h>
+       int main(void) {
+               int test = RTA_PREF;
+               return 0;
+       }" LWS_HAVE_RTA_PREF)
+
+CHECK_C_SOURCE_COMPILES("#include <sys/types.h>
+       int main(void) {
+               suseconds_t x = 0;
+               return (int)x;
+       }" LWS_HAVE_SUSECONDS_T)
 
 if (NOT PID_T_SIZE)
        set(pid_t int)
@@ -934,1586 +744,317 @@ if (NOT LWS_HAVE_REALLOC)
        set(realloc rpl_realloc)
 endif()
 
-if (UNIX)
-       execute_process(COMMAND uname -n OUTPUT_VARIABLE NODENAME)
-       # Need to chomp the \n at end of output.
-       string(REGEX REPLACE "[\n]+" "" NODENAME "${NODENAME}")
 
-       if( NODENAME STREQUAL "smartos" )
-               add_definitions( "-D__smartos__" )
-               set(SMARTOS 1)
-       endif()
-endif()
 
-if (MSVC)
-       # Turn off stupid microsoft security warnings.
-       add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
-endif(MSVC)
 
-include_directories("${PROJECT_SOURCE_DIR}/lib")
+if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR COMPILER_IS_CLANG)
+    include (CheckCCompilerFlag)
+    CHECK_C_COMPILER_FLAG(-fvisibility=hidden LWS_HAVE_VISIBILITY)
+    if (LWS_WITH_FANALYZER)
+           CHECK_C_COMPILER_FLAG(-fanalyzer LWS_HAVE_FANALYZER)
+    endif()
+    if (LWS_HAVE_VISIBILITY)
+                set(VISIBILITY_FLAG -fvisibility=hidden)
+    endif()
+    if (LWS_WITH_GCOV)
+           set (GCOV_FLAGS "-fprofile-arcs -ftest-coverage ")
+    else()
+           set(GCOV_FLAGS "")
+    endif()
 
-# Group headers and sources.
-# Some IDEs use this for nicer file structure.
-set(HDR_PRIVATE
-       lib/core/private.h)
+       if (LWS_WITH_ASAN)
+               set (ASAN_FLAGS "-fsanitize=address -fsanitize=undefined -fsanitize-address-use-after-scope -fsanitize-undefined-trap-on-error")
+               if (NOT COMPILER_IS_CLANG)
+                       set (ASAN_FLAGS "${ASAN_FLAGS} -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=leak")
+               endif()
+               message("Enabling ASAN")
+       else()
+               set(ASAN_FLAGS "")
+       endif()
 
-set(HDR_PUBLIC
-       "${PROJECT_SOURCE_DIR}/include/libwebsockets.h"
-       "${PROJECT_BINARY_DIR}/lws_config.h"
-       "${PROJECT_SOURCE_DIR}/plugins/ssh-base/include/lws-plugin-ssh.h"
-       )
+       check_c_compiler_flag("-Wignored-qualifiers" LWS_GCC_HAS_IGNORED_QUALIFIERS)
+       check_c_compiler_flag("-Wtype-limits" LWS_GCC_HAS_TYPE_LIMITS)
+       check_c_compiler_flag("-Wno-deprecated-declarations" LWS_GCC_HAS_NO_DEPRECATED_DECLARATIONS)
 
-set(SOURCES
-       lib/core/alloc.c
-       lib/core/buflist.c
-       lib/core/context.c
-       lib/core/lws_dll2.c
-       lib/core/libwebsockets.c
-       lib/core/logs.c
-       lib/misc/base64-decode.c
-       lib/core/vfs.c
-       lib/misc/lws-ring.c
-)
+       if (LWS_GCC_HAS_IGNORED_QUALIFIERS)
+               set(CMAKE_C_FLAGS "-Wignored-qualifiers ${CMAKE_C_FLAGS}" )
+       endif()
 
-if (LWS_WITH_DEPRECATED_LWS_DLL)
-       list(APPEND SOURCES
-               lib/core/lws_dll.c)
-endif()
-       
-if (LWS_WITH_NETWORK)
-       list(APPEND SOURCES
-               lib/core-net/dummy-callback.c
-               lib/core-net/output.c
-               lib/core-net/close.c
-               lib/core-net/network.c
-               lib/core-net/vhost.c
-               lib/core-net/pollfd.c
-               lib/core-net/service.c
-               lib/core-net/sorted-usec-list.c
-               lib/core-net/stats.c
-               lib/core-net/wsi.c
-               lib/core-net/wsi-timeout.c
-               lib/core-net/adopt.c
-               lib/roles/pipe/ops-pipe.c
-       )
+       if (LWS_GCC_HAS_TYPE_LIMITS)
+               set(CMAKE_C_FLAGS "-Wtype-limits ${CMAKE_C_FLAGS}" )
+       endif()
 
-       if (LWS_WITH_LWS_DSH)
-               list(APPEND SOURCES
-                       lib/core-net/lws-dsh.c)
+       if (LWS_WITH_FANALYZER AND LWS_HAVE_FANALYZER)
+               set(CMAKE_C_FLAGS "-fanalyzer ${CMAKE_C_FLAGS}" )
        endif()
 
-       if (LWS_WITH_SEQUENCER)
-               list(APPEND SOURCES
-                       lib/core-net/sequencer.c)
+       if (CMAKE_COMPILER_IS_CLANG OR CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4)
+               set(CMAKE_C_FLAGS "-Wuninitialized ${CMAKE_C_FLAGS}")
        endif()
 
-       if (LWS_WITH_ABSTRACT)
-               list(APPEND SOURCES
-                       lib/abstract/abstract.c
-               )
-               if (LWS_WITH_SEQUENCER)
-                       list(APPEND SOURCES
-                               lib/abstract/test-sequencer.c)
-               endif()
+       # always warn all and generate debug info
+       if (UNIX AND NOT LWS_PLAT_FREERTOS)
+               set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wconversion -Wsign-compare -Wstrict-aliasing ${VISIBILITY_FLAG} -Wundef ${GCOV_FLAGS} ${CMAKE_C_FLAGS} ${ASAN_FLAGS}" )
+       else()
+               set(CMAKE_C_FLAGS "-Wall -Wsign-compare ${VISIBILITY_FLAG} ${GCOV_FLAGS} ${CMAKE_C_FLAGS}" )
        endif()
 
-       if (LWS_WITH_STATS)
-               list(APPEND SOURCES
-                       lib/core-net/stats.c
-               )
+       if (PICO_SDK_PATH)
+               set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wconversion -Wsign-compare -Wstrict-aliasing -Wundef -nolibc")
        endif()
-endif()
 
-if (LWS_WITH_DIR)
-       list(APPEND SOURCES lib/misc/dir.c)
-endif()
-       
-if (LWS_WITH_THREADPOOL AND UNIX AND LWS_HAVE_PTHREAD_H)
-       list(APPEND SOURCES lib/misc/threadpool/threadpool.c)
-endif()
+       if (ESP_PLATFORM AND (CONFIG_IDF_TARGET_ESP32 OR CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32S3))
+               set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlongcalls")
+       endif()
 
-if (LWS_ROLE_H1 OR LWS_ROLE_H2)
-       list(APPEND SOURCES
-               lib/roles/http/header.c
-               lib/roles/http/server/parsers.c)
-       if (LWS_WITH_HTTP_STREAM_COMPRESSION)
-               list(APPEND SOURCES
-                       lib/roles/http/compression/stream.c
-                       lib/roles/http/compression/deflate/deflate.c)
-               if (LWS_WITH_HTTP_BROTLI)
-                       list(APPEND SOURCES
-                               lib/roles/http/compression/brotli/brotli.c)
+       if ("${DISABLE_WERROR}" STREQUAL "OFF")
+               set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
+       endif()
+
+       if (LWS_SUPPRESS_DEPRECATED_API_WARNINGS)
+               set(CMAKE_C_FLAGS "-Wno-deprecated ${CMAKE_C_FLAGS}")
+               if (LWS_GCC_HAS_NO_DEPRECATED_DECLARATIONS)
+                       set(CMAKE_C_FLAGS "-Wno-deprecated-declarations ${CMAKE_C_FLAGS}")
                endif()
        endif()
-endif()
+endif ()
 
-if (LWS_ROLE_H1)
-       list(APPEND SOURCES
-               lib/roles/h1/ops-h1.c)
+if ((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT LWS_WITHOUT_TESTAPPS)
+       if (UNIX AND LWS_HAVE_PTHREAD_H AND NOT (${CMAKE_SYSTEM_NAME} MATCHES "QNX"))
+       # jeez clang understands -pthread but dies if he sees it at link time!
+       # http://stackoverflow.com/questions/2391194/what-is-gs-pthread-equiv-in-clang
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread" )
+       list(APPEND LIB_LIST_AT_END -lpthread)
+    endif()
 endif()
 
-if (LWS_ROLE_WS)
-       list(APPEND SOURCES
-               lib/roles/ws/ops-ws.c)
-       if (NOT LWS_WITHOUT_CLIENT)
-               list(APPEND SOURCES
-                       lib/roles/ws/client-ws.c
-                       lib/roles/ws/client-parser-ws.c)
-       endif()
-       if (NOT LWS_WITHOUT_SERVER)
-               list(APPEND SOURCES
-                       lib/roles/ws/server-ws.c)
-       endif()
-endif()
+if (COMPILER_IS_CLANG)
 
-if (LWS_ROLE_RAW)
-       list(APPEND SOURCES
-               lib/roles/raw-skt/ops-raw-skt.c
-               lib/roles/raw-file/ops-raw-file.c)
-               
-       if (LWS_WITH_ABSTRACT)
-               list(APPEND SOURCES
-                       lib/abstract/transports/raw-skt.c)
+       # otherwise osx blows a bunch of openssl deprecated api errors
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations" )
+       if (UNIX AND LWS_HAVE_PTHREAD_H)
+               set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -Wno-error=unused-command-line-argument" )
        endif()
 endif()
 
-if (LWS_ROLE_RAW_PROXY)
-       list(APPEND SOURCES
-               lib/roles/raw-proxy/ops-raw-proxy.c)
+if (WINCE)
+       list(APPEND LIB_LIST_AT_END ws2.lib)
+elseif (WIN32)
+       list(APPEND LIB_LIST_AT_END ws2_32.lib userenv.lib psapi.lib iphlpapi.lib crypt32.lib)
 endif()
 
-if (LWS_ROLE_CGI)
-       list(APPEND SOURCES
-               lib/roles/cgi/cgi-server.c
-               lib/roles/cgi/ops-cgi.c)
-endif()
+if (MSVC)
+       # Turn off pointless microsoft security warnings.
+       add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
+       # Fail the build if any warnings
+       add_compile_options(/W3 /WX)
+       # Unbreak MSVC broken preprocessor __VA_ARGS__ behaviour
+       add_compile_options(/Zc:preprocessor /experimental:preprocessor /wd5105)
+endif(MSVC)
 
-if (LWS_ROLE_DBUS)
-       list(APPEND SOURCES
-               lib/roles/dbus/dbus.c)
+if (MINGW)
+       set(LWS_MINGW_SUPPORT 1)
+       set(CMAKE_C_FLAGS "-D__USE_MINGW_ANSI_STDIO ${CMAKE_C_FLAGS}")
+       add_definitions(-DWINVER=0x0601 -D_WIN32_WINNT=0x0601)
 endif()
 
-if (LWS_WITH_ACCESS_LOG)
-       list(APPEND SOURCES
-               lib/roles/http/server/access-log.c)
+if (HDR_PRIVATE)
+       source_group("Headers Private"  FILES ${HDR_PRIVATE})
 endif()
-
-if (LWS_WITH_PEER_LIMITS)
-       list(APPEND SOURCES
-               lib/misc/peer-limits.c)
+if (HDR_PUBLIC)
+       source_group("Headers Public"   FILES ${HDR_PUBLIC})
 endif()
-
-if (LWS_WITH_LWSAC)
-       list(APPEND SOURCES
-               lib/misc/lwsac/lwsac.c
-               lib/misc/lwsac/cached-file.c)
+if (SOURCES)
+       source_group("Sources"          FILES ${SOURCES})
 endif()
-
-if (LWS_WITH_FTS)
-       list(APPEND SOURCES
-               lib/misc/fts/trie.c
-               lib/misc/fts/trie-fd.c)
+if (RESOURCES)
+       source_group("Resources"        FILES ${RESOURCES})
 endif()
 
-if (LWS_WITH_DISKCACHE)
-       list(APPEND SOURCES
-               lib/misc/diskcache.c)
+
+#
+# ZLIB (needed for deflate extension and if LWS_WITH_HTTP_STREAM_COMPRESSION)
+#
+if (LWS_WITH_ZLIB)
+       if (NOT ZLIB_FOUND)
+               if (LWS_WITH_MINIZ)
+                       find_package(Miniz REQUIRED)
+                       set(ZLIB_INCLUDE_DIRS ${MINIZ_INCLUDE_DIR})
+                       set(ZLIB_LIBRARIES ${MINIZ_LIBRARIES})
+               else()
+                       find_package(ZLIB REQUIRED)
+               endif()
+       endif()
+       message("zlib/miniz include dirs: ${ZLIB_INCLUDE_DIRS}")
+       message("zlib/miniz libraries: ${ZLIB_LIBRARIES}")
+       include_directories(${ZLIB_INCLUDE_DIRS})
+       # done later at end of link list
+       # list(APPEND LIB_LIST ${ZLIB_LIBRARIES})
+       set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${ZLIB_LIBRARIES})
+       list(APPEND LIB_LIST_AT_END ${ZLIB_LIBRARIES})
 endif()
 
-if (LWS_WITH_STRUCT_JSON)
-       list(APPEND SOURCES
-               lib/misc/lws-struct-lejp.c)
+
+if (LWS_WITH_FSMOUNT AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+       if (NOT LWS_LIBMOUNT_INCLUDE_DIRS STREQUAL "")
+               include_directories(${LWS_LIBMOUNT_INCLUDE_DIRS})
+               message("libmount include dir: ${LWS_LIBMOUNT_INCLUDE_DIRS}")
+       endif()
+       if (NOT LWS_LIBMOUNT_LIBRARIES STREQUAL "")
+               message("libmount libraries: ${LWS_LIBMOUNT_LIBRARIES}")
+               list(APPEND LIB_LIST ${LWS_LIBMOUNT_LIBRARIES})
+       else()
+               list(APPEND LIB_LIST mount)
+       endif()
 endif()
 
-if (LWS_WITH_STRUCT_SQLITE3)
-       list(APPEND SOURCES
-               lib/misc/lws-struct-sqlite.c)
+
+if (LWS_WITH_SQLITE3)
+       if (NOT SQLITE3_FOUND)
+               find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h)
+               find_library(SQLITE3_LIBRARIES NAMES sqlite3)
+               if(SQLITE3_INCLUDE_DIRS AND SQLITE3_LIBRARIES)
+                       set(SQLITE3_FOUND 1)
+               endif()
+       endif()
+       message("sqlite3 include dir: ${SQLITE3_INCLUDE_DIRS}")
+       message("sqlite3 libraries: ${SQLITE3_LIBRARIES}")
+       include_directories("${SQLITE3_INCLUDE_DIRS}")
+       list(APPEND LIB_LIST ${SQLITE3_LIBRARIES})
 endif()
 
-if (NOT LWS_WITHOUT_CLIENT)
-       list(APPEND SOURCES
-               lib/core-net/connect.c
-               lib/core-net/client.c
-               lib/roles/http/client/client.c
-               lib/roles/http/client/client-handshake.c)
+
+if (LWS_WITH_HUBBUB)
+       find_library(LIBHUBBUB_LIBRARIES NAMES hubbub)
+       list(APPEND LIB_LIST ${LIBHUBBUB_LIBRARIES} )
 endif()
 
-if (NOT LWS_WITHOUT_SERVER)
-       list(APPEND SOURCES
-               lib/core-net/server.c
-               lib/roles/listen/ops-listen.c)
+if (LWS_HAVE_LIBCAP)
+       find_library(LIBCAP_LIBRARIES NAMES cap)
+       list(APPEND LIB_LIST ${LIBCAP_LIBRARIES} )
 endif()
 
-if (LWS_WITH_MBEDTLS)
-       set(LWS_WITH_SSL ON)
-       
-       include_directories(lib/tls/mbedtls/wrapper/include)
-       include_directories(lib/tls/mbedtls/wrapper/include/platform)
-       include_directories(lib/tls/mbedtls/wrapper/include/internal)
-       include_directories(lib/tls/mbedtls/wrapper/include/openssl)
-       
-       if (LWS_WITH_NETWORK)
-               list(APPEND HDR_PRIVATE
-                       lib/tls/mbedtls/wrapper/include/internal/ssl3.h
-                       lib/tls/mbedtls/wrapper/include/internal/ssl_cert.h
-                       lib/tls/mbedtls/wrapper/include/internal/ssl_code.h
-                       lib/tls/mbedtls/wrapper/include/internal/ssl_dbg.h
-                       lib/tls/mbedtls/wrapper/include/internal/ssl_lib.h
-                       lib/tls/mbedtls/wrapper/include/internal/ssl_methods.h
-                       lib/tls/mbedtls/wrapper/include/internal/ssl_pkey.h
-                       lib/tls/mbedtls/wrapper/include/internal/ssl_stack.h
-                       lib/tls/mbedtls/wrapper/include/internal/ssl_types.h
-                       lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h
-                       lib/tls/mbedtls/wrapper/include/internal/tls1.h
-                       lib/tls/mbedtls/wrapper/include/internal/x509_vfy.h)
-       
-               list(APPEND HDR_PRIVATE
-                       lib/tls/mbedtls/wrapper/include/openssl/ssl.h)
-       
-               list(APPEND HDR_PRIVATE
-                       lib/tls/mbedtls/wrapper/include/platform/ssl_pm.h
-                       lib/tls/mbedtls/wrapper/include/platform/ssl_port.h)
-       
-               list(APPEND SOURCES
-                       lib/tls/mbedtls/wrapper/library/ssl_cert.c
-                       lib/tls/mbedtls/wrapper/library/ssl_lib.c
-                       lib/tls/mbedtls/wrapper/library/ssl_methods.c
-                       lib/tls/mbedtls/wrapper/library/ssl_pkey.c
-                       lib/tls/mbedtls/wrapper/library/ssl_stack.c
-                       lib/tls/mbedtls/wrapper/library/ssl_x509.c)
-       
-               list(APPEND SOURCES
-                       lib/tls/mbedtls/wrapper/platform/ssl_pm.c
-                       lib/tls/mbedtls/wrapper/platform/ssl_port.c)
-       endif()
+if (LWS_WITH_PLUGINS_BUILTIN)
+       add_subdirectory(plugins)
 endif()
 
-if (LWS_WITH_SSL)
-       list(APPEND SOURCES
-               lib/tls/tls.c
-       )
-       if (LWS_WITH_NETWORK)
-               list(APPEND SOURCES
-                       lib/tls/tls-network.c
-               )
-       endif()
-               
-       if (LWS_WITH_MBEDTLS)
-               list(APPEND SOURCES
-                       lib/tls/mbedtls/tls.c
-                       lib/tls/mbedtls/x509.c
-               )
-               if (LWS_WITH_NETWORK)
-                       list(APPEND SOURCES
-                               lib/tls/mbedtls/ssl.c
-                       )
-               endif()
-               if (LWS_WITH_GENCRYPTO)
-                       list(APPEND SOURCES
-                               lib/tls/mbedtls/lws-genhash.c
-                               lib/tls/mbedtls/lws-genrsa.c
-                               lib/tls/mbedtls/lws-genaes.c
-                               lib/tls/lws-genec-common.c
-                               lib/tls/mbedtls/lws-genec.c
-                               lib/tls/mbedtls/lws-gencrypto.c
-                       )
-               endif()
-       else()
-               list(APPEND SOURCES
-                       lib/tls/openssl/tls.c
-                       lib/tls/openssl/x509.c
-               )
-               if (LWS_WITH_NETWORK)
-                       list(APPEND SOURCES
-                               lib/tls/openssl/ssl.c
-                       )
-               endif()
-               if (LWS_WITH_GENCRYPTO)
-                       list(APPEND SOURCES
-                               lib/tls/openssl/lws-genhash.c
-                               lib/tls/openssl/lws-genrsa.c
-                               lib/tls/openssl/lws-genaes.c
-                               lib/tls/lws-genec-common.c
-                               lib/tls/openssl/lws-genec.c
-                               lib/tls/openssl/lws-gencrypto.c
-                       )
-               endif()
-       endif()
-               
-       if (NOT LWS_WITHOUT_SERVER)
-               list(APPEND SOURCES
-                       lib/tls/tls-server.c)
-               if (LWS_WITH_MBEDTLS)
-                       list(APPEND SOURCES
-                               lib/tls/mbedtls/mbedtls-server.c)
-               else()
-                       list(APPEND SOURCES
-                               lib/tls/openssl/openssl-server.c)
-               endif()
-       endif()
-       if (NOT LWS_WITHOUT_CLIENT)
-               list(APPEND SOURCES
-                       lib/tls/tls-client.c)
-               if (LWS_WITH_MBEDTLS)
-                       list(APPEND SOURCES
-                               lib/tls/mbedtls/mbedtls-client.c)
-               else()
-                       list(APPEND SOURCES
-                               lib/tls/openssl/openssl-client.c)
-               endif()
-               
-       endif()
-endif()
-
-if (NOT LWS_WITHOUT_BUILTIN_SHA1)
-       list(APPEND SOURCES
-               lib/misc/sha-1.c)
-endif()
-
-if (LWS_WITH_HTTP2 AND NOT LWS_WITHOUT_SERVER)
-       list(APPEND SOURCES
-               lib/roles/h2/http2.c
-               lib/roles/h2/hpack.c
-               lib/roles/h2/ops-h2.c)
-endif()
-# select the active platform files
-
-if (WIN32)
-       list(APPEND SOURCES
-               lib/plat/windows/windows-fds.c
-               lib/plat/windows/windows-file.c
-               lib/plat/windows/windows-init.c
-               lib/plat/windows/windows-misc.c
-               lib/plat/windows/windows-pipe.c
-               lib/plat/windows/windows-plugins.c
-               lib/plat/windows/windows-service.c
-               lib/plat/windows/windows-sockets.c
-               )
-else()
-
-       if (LWS_PLAT_OPTEE)
-               list(APPEND SOURCES
-                       lib/plat/optee/lws-plat-optee.c
-               )
-               if (LWS_WITH_NETWORK)
-                       list(APPEND SOURCES
-                               lib/plat/optee/network.c
-                       )
-               endif()
-       else()
-               if (LWS_WITH_ESP32)
-                       list(APPEND SOURCES
-                               lib/plat/esp32/esp32-fds.c
-                               lib/plat/esp32/esp32-file.c
-                               lib/plat/esp32/esp32-init.c
-                               lib/plat/esp32/esp32-misc.c
-                               lib/plat/esp32/esp32-pipe.c
-                               lib/plat/esp32/esp32-service.c
-                               lib/plat/esp32/esp32-sockets.c
-                               lib/misc/romfs.c)
-                       if(LWS_WITH_ESP32_HELPER)
-                               list(APPEND SOURCES lib/plat/esp32/esp32-helpers.c)
-                       endif()
-               else()
-                       set(LWS_PLAT_UNIX 1)
-                       list(APPEND SOURCES
-                               lib/plat/unix/unix-caps.c
-                               lib/plat/unix/unix-file.c
-                               lib/plat/unix/unix-misc.c
-                               lib/plat/unix/unix-init.c
-                       )
-                       if (LWS_WITH_NETWORK)
-                               list(APPEND SOURCES
-                                       lib/plat/unix/unix-pipe.c
-                                       lib/plat/unix/unix-service.c
-                                       lib/plat/unix/unix-sockets.c
-                                       lib/plat/unix/unix-fds.c
-                               )
-                       endif()
-                               
-                       if (LWS_WITH_PLUGINS AND LWS_WITH_LIBUV)
-                               list(APPEND SOURCES lib/plat/unix/unix-plugins.c)
-                       endif()
-               endif()
-       endif()
-endif()
-
-if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_SERVER)
-       list(APPEND SOURCES
-               lib/roles/http/server/server.c
-               lib/roles/http/server/lws-spa.c)
-endif()
-
-if (LWS_ROLE_WS AND NOT LWS_WITHOUT_EXTENSIONS)
-       list(APPEND HDR_PRIVATE
-               lib/roles/ws/ext/extension-permessage-deflate.h)
-       list(APPEND SOURCES
-               lib/roles/ws/ext/extension.c
-               lib/roles/ws/ext/extension-permessage-deflate.c)
-endif()
-
-if (LWS_WITH_HTTP_PROXY)
-       list(APPEND SOURCES
-               lib/roles/http/server/rewrite.c)
-endif()
-
-if (LWS_WITH_POLL AND LWS_WITH_NETWORK)
-       list(APPEND SOURCES
-               lib/event-libs/poll/poll.c)
-endif()
-
-if (LWS_WITH_LIBUV AND LWS_WITH_NETWORK)
-       list(APPEND SOURCES
-               lib/event-libs/libuv/libuv.c)
-endif()
-
-if (LWS_WITH_LIBEVENT AND LWS_WITH_NETWORK)
-       list(APPEND SOURCES
-               lib/event-libs/libevent/libevent.c)
-endif()
-
-if (LWS_WITH_LIBEV AND LWS_WITH_NETWORK)
-       list(APPEND SOURCES
-               lib/event-libs/libev/libev.c)
-       # libev generates a big mess of warnings with gcc, maintainer claims gcc to blame
-       set_source_files_properties( lib/event-libs/libev/libev.c PROPERTIES COMPILE_FLAGS "-Wno-error" )
-endif()
-
-if (LWS_WITH_LEJP)
-       list(APPEND SOURCES
-               lib/misc/lejp.c)
-endif()        
-if (LWS_WITH_LEJP_CONF AND LWS_WITH_NETWORK AND NOT LWS_PLAT_OPTEE)
-               list(APPEND SOURCES
-                       "lib/roles/http/server/lejp-conf.c"
-               )
-endif()
-
-if (LWS_WITH_ABSTRACT)
-       list(APPEND SOURCES
-               lib/abstract/transports/unit-test.c)
-endif()
-
-if (LWS_WITH_SMTP)
-       list(APPEND SOURCES
-               lib/abstract/protocols/smtp/smtp.c)
-endif()
-
-if (LWS_WITH_RANGES)
-       list(APPEND SOURCES
-               lib/roles/http/server/ranges.c)
-endif()
-
-if (LWS_WITH_ZIP_FOPS)
-       if (LWS_WITH_ZLIB)
-               list(APPEND SOURCES
-                       lib/roles/http/server/fops-zip.c)
-       else()
-               message(FATAL_ERROR "Pre-zipped file support (LWS_WITH_ZIP_FOPS) requires ZLIB (LWS_WITH_ZLIB)")
-       endif()
-endif()
-
-if (LWS_WITH_JOSE)
-       list(APPEND SOURCES
-               lib/jose/jwk/jwk.c
-               lib/jose/jws/jose.c
-               lib/jose/jws/jws.c
-               lib/jose/jwe/jwe.c
-               lib/jose/jwe/enc/aescbc.c
-               lib/jose/jwe/enc/aesgcm.c
-               lib/jose/jwe/enc/aeskw.c
-               lib/jose/jwe/jwe-rsa-aescbc.c
-               lib/jose/jwe/jwe-rsa-aesgcm.c
-               lib/jose/jwe/jwe-ecdh-es-aeskw.c
-               )
-endif()
-
-if (LWS_WITH_JOSE OR LWS_WITH_GENCRYPTO)
-       list(APPEND SOURCES
-               lib/tls/lws-gencrypto-common.c)
-endif()
-
-# Add helper files for Windows.
-if (WIN32)
-       set(WIN32_HELPERS_PATH win32port/win32helpers)
-       include_directories(${WIN32_HELPERS_PATH})
-
-               if (WIN32)
-                       list(APPEND SOURCES
-                               ${WIN32_HELPERS_PATH}/gettimeofday.c
-                       )
-
-                       list(APPEND HDR_PRIVATE
-                               ${WIN32_HELPERS_PATH}/gettimeofday.h
-                       )
-               endif(WIN32)
-
-else()
-       # Unix.
-       if (NOT LWS_WITHOUT_DAEMONIZE)
-               list(APPEND SOURCES
-                       lib/misc/daemonize.c)
-       endif()
-endif()
-
-if (UNIX)
-       if (NOT LWS_HAVE_GETIFADDRS)
-               list(APPEND HDR_PRIVATE lib/misc/getifaddrs.h)
-               list(APPEND SOURCES lib/misc/getifaddrs.c)
-       endif()
-endif()
-
-if ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
-       set(COMPILER_IS_CLANG ON)
-endif()
-
-if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR COMPILER_IS_CLANG)
-    include (CheckCCompilerFlag)
-    CHECK_C_COMPILER_FLAG(-fvisibility=hidden LWS_HAVE_VISIBILITY)
-    if (LWS_HAVE_VISIBILITY)
-                set(VISIBILITY_FLAG -fvisibility=hidden)
-    endif()
-    if (LWS_WITH_GCOV)
-           set (GCOV_FLAGS "-fprofile-arcs -ftest-coverage ")
-    endif()
-
-       if (LWS_WITH_ASAN)
-               set (ASAN_FLAGS "-fsanitize=address -fsanitize=undefined -fsanitize-address-use-after-scope -fsanitize-undefined-trap-on-error")
-               if (NOT COMPILER_IS_CLANG)
-                       set (ASAN_FLAGS "${ASAN_FLAGS} -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=leak")
-               endif()
-               message("Enabling ASAN")
-       endif()
-
-       check_c_compiler_flag("-Wignored-qualifiers" LWS_GCC_HAS_IGNORED_QUALIFIERS)
-       check_c_compiler_flag("-Wtype-limits" LWS_GCC_HAS_TYPE_LIMITS)
-
-       if (LWS_GCC_HAS_IGNORED_QUALIFIERS)
-               set(CMAKE_C_FLAGS "-Wignored-qualifiers ${CMAKE_C_FLAGS}" )
-       endif()
-
-       if (LWS_GCC_HAS_TYPE_LIMITS)
-               set(CMAKE_C_FLAGS "-Wtype-limits ${CMAKE_C_FLAGS}" )
-       endif()
-
-    if (UNIX AND NOT LWS_WITH_ESP32)
-           set(CMAKE_C_FLAGS "-Wall -Wsign-compare -Wuninitialized -Werror ${VISIBILITY_FLAG} -Wundef ${GCOV_FLAGS} ${CMAKE_C_FLAGS} ${ASAN_FLAGS}" )
-    else()
-           set(CMAKE_C_FLAGS "-Wall -Wsign-compare -Wuninitialized -Werror ${VISIBILITY_FLAG} ${GCOV_FLAGS} ${CMAKE_C_FLAGS}" )
-    endif()
-endif ()
-
-if (LWS_PLAT_OPTEE)
-       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --sysroot ../../../../lib/libutils/isoc/include -I../../../../lib/libutils/isoc/include -I../../../../lib/libutils/ext/include" )
-endif()
-
-if ((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT LWS_WITHOUT_TESTAPPS)
-       if (UNIX AND LWS_HAVE_PTHREAD_H)
-       # jeez clang understands -pthread but dies if he sees it at link time!
-       # http://stackoverflow.com/questions/2391194/what-is-gs-pthread-equiv-in-clang
-       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread" )
-    endif()
-endif()
-
-if (COMPILER_IS_CLANG)
-
-       # otherwise osx blows a bunch of openssl deprecated api errors
-       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations" )
-       if (UNIX AND LWS_HAVE_PTHREAD_H)
-               set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -Wno-error=unused-command-line-argument" )
-       endif()
-endif()
-
-source_group("Headers Private"  FILES ${HDR_PRIVATE})
-source_group("Headers Public"   FILES ${HDR_PUBLIC})
-source_group("Sources"          FILES ${SOURCES})
-source_group("Resources"        FILES ${RESOURCES})
 
 #
-# Create the lib.
+# Append the "at end" pieces to the lib list
 #
-set(LWS_LIBRARIES)
-
-if (LWS_WITH_STATIC)
-    if (LWS_STATIC_PIC)
-        set(CMAKE_POSITION_INDEPENDENT_CODE ON)
-    endif()
-       add_library(websockets STATIC
-                               ${HDR_PRIVATE}
-                               ${HDR_PUBLIC}
-                               ${SOURCES})
-       list(APPEND LWS_LIBRARIES websockets)
-
-       if (WIN32)
-               # Windows uses the same .lib ending for static libraries and shared
-               # library linker files, so rename the static library.
-               set_target_properties(websockets
-                       PROPERTIES
-                       OUTPUT_NAME websockets_static)
-       endif()
-       add_custom_command(
-                     TARGET websockets
-                     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/include/libwebsockets.h
-                                                        ${CMAKE_CURRENT_BINARY_DIR}/include/libwebsockets.h
-       )
-
-       add_custom_command(
-                     TARGET websockets
-                     COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/libwebsockets/
-                                                                       ${CMAKE_CURRENT_BINARY_DIR}/include/libwebsockets
-       )
-
-       add_custom_command(
-                     TARGET websockets
-                     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/lws_config.h
-                                                        ${CMAKE_CURRENT_BINARY_DIR}/include/lws_config.h
-       )
-
-endif()
-
-if (LWS_WITH_SHARED)
-       add_library(websockets_shared SHARED
-                               ${HDR_PRIVATE}
-                               ${HDR_PUBLIC}
-                               ${SOURCES}
-                               ${RESOURCES})
-       list(APPEND LWS_LIBRARIES websockets_shared)
-
-       # We want the shared lib to be named "libwebsockets"
-       # not "libwebsocket_shared".
-       set_target_properties(websockets_shared
-               PROPERTIES
-               OUTPUT_NAME websockets)
-
-       if (WIN32)
-               # Compile as DLL (export function declarations)
-               set_property(
-                       TARGET websockets_shared
-                       PROPERTY COMPILE_DEFINITIONS
-                       LWS_DLL
-                       LWS_INTERNAL)
-       endif()
-
-       if (APPLE)
-               set_property(TARGET websockets_shared PROPERTY MACOSX_RPATH YES)
-       endif()
-
-       add_custom_command(
-                     TARGET websockets_shared
-                     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/include/libwebsockets.h
-                                                        ${CMAKE_CURRENT_BINARY_DIR}/include/libwebsockets.h
-       )
-
-       add_custom_command(
-                     TARGET websockets
-                     COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/libwebsockets
-                                                                       ${CMAKE_CURRENT_BINARY_DIR}/include/libwebsockets
-       )
-
-       add_custom_command(
-                     TARGET websockets_shared
-                     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/lws_config.h
-                                                        ${CMAKE_CURRENT_BINARY_DIR}/include/lws_config.h
-       )
-
-
-endif()
-
-# Set the so version of the lib.
-# Equivalent to LDFLAGS=-version-info x:x:x
-if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR COMPILER_IS_CLANG)
-       foreach(lib ${LWS_LIBRARIES})
-               set_target_properties(${lib}
-                       PROPERTIES
-                       SOVERSION ${SOVERSION})
-       endforeach()
-endif()
-
-set(LIB_LIST)
+list(APPEND LIB_LIST ${LIB_LIST_AT_END})
 
 #
-# Find libraries.
+# Second-level CMakeLists
 #
 
-#
-# ZLIB (needed for deflate extension and if LWS_WITH_HTTP_STREAM_COMPRESSION)
-#
-if (LWS_WITH_ZLIB)
-       if (LWS_WITH_BUNDLED_ZLIB)
-               if (WIN32)
-                       set(WIN32_ZLIB_PATH "win32port/zlib")
-                       set(ZLIB_SRCS
-                               ${WIN32_ZLIB_PATH}/adler32.c
-                               ${WIN32_ZLIB_PATH}/compress.c
-                               ${WIN32_ZLIB_PATH}/crc32.c
-                               ${WIN32_ZLIB_PATH}/deflate.c
-                               ${WIN32_ZLIB_PATH}/gzlib.c
-                               ${WIN32_ZLIB_PATH}/gzread.c
-                               ${WIN32_ZLIB_PATH}/gzwrite.c
-                               ${WIN32_ZLIB_PATH}/infback.c
-                               ${WIN32_ZLIB_PATH}/inffast.c
-                               ${WIN32_ZLIB_PATH}/inflate.c
-                               ${WIN32_ZLIB_PATH}/inftrees.c
-                               ${WIN32_ZLIB_PATH}/trees.c
-                               ${WIN32_ZLIB_PATH}/uncompr.c
-                               ${WIN32_ZLIB_PATH}/zutil.c)
-                       add_library(zlib_internal STATIC ${ZLIB_SRCS})
-                       set(ZLIB_INCLUDE_DIRS ${WIN32_ZLIB_PATH})
-                       get_property(ZLIB_LIBRARIES TARGET zlib_internal PROPERTY LOCATION)
-                       set(ZLIB_FOUND 1)
-                       # Make sure zlib_internal is compiled before the libs.
-                       foreach (lib ${LWS_LIBRARIES})
-                               add_dependencies(${lib} zlib_internal)
-                       endforeach()
-               else()
-                       message(FATAL_ERROR "Don't have bundled zlib for that platform")
-               endif()
-       elseif (NOT ZLIB_FOUND)
-               if (LWS_WITH_MINIZ)
-                       find_package(Miniz REQUIRED)
-                       set(ZLIB_INCLUDE_DIRS ${MINIZ_INCLUDE_DIRS})
-                       set(ZLIB_LIBRARIES ${MINIZ_LIBRARIES})
-               else()
-                       find_package(ZLIB REQUIRED)
-               endif()
-       endif()
-       message("zlib/miniz include dirs: ${ZLIB_INCLUDE_DIRS}")
-       message("zlib/miniz libraries: ${ZLIB_LIBRARIES}")
-       include_directories(${ZLIB_INCLUDE_DIRS})
-       # done later at end of link list
-       # list(APPEND LIB_LIST ${ZLIB_LIBRARIES})
-endif()
-
-if (LWS_WITH_HTTP_BROTLI)
-       list(APPEND LIB_LIST brotlienc brotlidec brotlidec)
-endif()
-
-#
-# OpenSSL
-#
-if (LWS_WITH_SSL)
-       message("Compiling with SSL support")
-       set(chose_ssl 0)
-       if (LWS_WITH_WOLFSSL)
-               # Use wolfSSL as OpenSSL replacement.
-               # TODO: Add a find_package command for this also.
-               message("wolfSSL include dir: ${WOLFSSL_INCLUDE_DIRS}")
-               message("wolfSSL libraries: ${WOLFSSL_LIBRARIES}")
-
-               # Additional to the root directory we need to include
-               # the wolfssl/ subdirectory which contains the OpenSSL
-               # compatibility layer headers.
-
-               if (LWS_WITH_CYASSL)
-                       foreach(inc ${WOLFSSL_INCLUDE_DIRS})
-                               include_directories("${inc}" "${inc}/cyassl")
-                       endforeach()
-               else()
-                       foreach(inc ${WOLFSSL_INCLUDE_DIRS})
-                               include_directories("${inc}" "${inc}/wolfssl")
-                       endforeach()
-               endif()
-
-               list(APPEND LIB_LIST "${WOLFSSL_LIBRARIES}")
-               set(chose_ssl 1)
-       endif()
-
-       if (LWS_WITH_MBEDTLS)
-               message("MBEDTLS include dir: ${MBEDTLS_INCLUDE_DIRS}")
-               message("MBEDTLS libraries: ${MBEDTLS_LIBRARIES}")
-
-               foreach(inc ${MBEDTLS_INCLUDE_DIRS})
-                       include_directories("${inc}" "${inc}/mbedtls")
-               endforeach()
-
-               list(APPEND LIB_LIST "${MBEDTLS_LIBRARIES}")
-               set(chose_ssl 1)
-       endif()
-
-       if (NOT chose_ssl)
-               if (NOT OPENSSL_FOUND AND NOT LWS_WITH_BORINGSSL)
-                       # TODO: Add support for STATIC also.
-               if (NOT LWS_WITH_ESP32)
-                       find_package(OpenSSL REQUIRED)
-               endif()
-                       set(OPENSSL_INCLUDE_DIRS "${OPENSSL_INCLUDE_DIR}")
-               endif()
-
-               message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIRS}")
-               if (NOT LWS_WITH_ESP32)
-                       message("OpenSSL libraries: ${OPENSSL_LIBRARIES}")
-               endif()
-
-               include_directories("${OPENSSL_INCLUDE_DIRS}")
-               if (NOT LWS_WITH_ESP32)
-                       list(APPEND LIB_LIST ${OPENSSL_LIBRARIES})
-               endif()
-
-       if (NOT LWS_WITH_MBEDTLS)
-               # older (0.98) Openssl lacks this
-               set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
-               check_include_file(openssl/ecdh.h LWS_HAVE_OPENSSL_ECDH_H)
-
-               if (LWS_SSL_SERVER_WITH_ECDH_CERT AND NOT LWS_HAVE_OPENSSL_ECDH_H)
-                       message(FATAL_ERROR "Missing openssl/ecdh.h, so cannot use LWS_SSL_SERVER_WITH_ECDH_CERT")
-               endif()
-       else()
-               unset(LWS_HAVE_OPENSSL_ECDH_H)
-       endif(NOT LWS_WITH_MBEDTLS)
-       endif()
-
-endif(LWS_WITH_SSL)
-
-if (LWS_WITH_LIBEV)
-       if (NOT LIBEV_FOUND)
-               find_path(LIBEV_INCLUDE_DIRS NAMES ev.h)
-               find_library(LIBEV_LIBRARIES NAMES ev)
-               if(LIBEV_INCLUDE_DIRS AND LIBEV_LIBRARIES)
-                       set(LIBEV_FOUND 1)
-               endif()
-       endif()
-       message("libev include dir: ${LIBEV_INCLUDE_DIRS}")
-       message("libev libraries: ${LIBEV_LIBRARIES}")
-       include_directories("${LIBEV_INCLUDE_DIRS}")
-       list(APPEND LIB_LIST ${LIBEV_LIBRARIES})
-endif(LWS_WITH_LIBEV)
-
-if (LWS_WITH_LIBUV)
-       if (NOT LIBUV_FOUND)
-               find_path(LIBUV_INCLUDE_DIRS NAMES uv.h)
-               find_library(LIBUV_LIBRARIES NAMES uv)
-               if(LIBUV_INCLUDE_DIRS AND LIBUV_LIBRARIES)
-                       set(LIBUV_FOUND 1)
-               endif()
-       endif()
-       message("libuv include dir: ${LIBUV_INCLUDE_DIRS}")
-       message("libuv libraries: ${LIBUV_LIBRARIES}")
-       include_directories("${LIBUV_INCLUDE_DIRS}")
-       list(APPEND LIB_LIST ${LIBUV_LIBRARIES})
-endif()
-
-if (LWS_WITH_LIBEVENT)
-       if (NOT LIBEVENT_FOUND)
-               find_path(LIBEVENT_INCLUDE_DIRS NAMES event2/event.h)
-               find_library(LIBEVENT_LIBRARIES NAMES event)
-               if(LIBEVENT_INCLUDE_DIRS AND LIBEVENT_LIBRARIES)
-                       set(LIBEVENT_FOUND 1)
-               endif()
-       endif()
-       message("libevent include dir: ${LIBEVENT_INCLUDE_DIRS}")
-       message("libevent libraries: ${LIBEVENT_LIBRARIES}")
-       include_directories("${LIBEVENT_INCLUDE_DIRS}")
-       list(APPEND LIB_LIST ${LIBEVENT_LIBRARIES})
-endif(LWS_WITH_LIBEVENT)
-
-if (LWS_WITH_SQLITE3)
-       if (NOT SQLITE3_FOUND)
-               find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h)
-               find_library(SQLITE3_LIBRARIES NAMES sqlite3)
-               if(SQLITE3_INCLUDE_DIRS AND SQLITE3_LIBRARIES)
-                       set(SQLITE3_FOUND 1)
-               endif()
-       endif()
-       message("sqlite3 include dir: ${SQLITE3_INCLUDE_DIRS}")
-       message("sqlite3 libraries: ${SQLITE3_LIBRARIES}")
-       include_directories("${SQLITE3_INCLUDE_DIRS}")
-       list(APPEND LIB_LIST ${SQLITE3_LIBRARIES})
-endif()
-
-
-if (LWS_WITH_HUBBUB)
-       find_library(LIBHUBBUB_LIBRARIES NAMES hubbub)
-       list(APPEND LIB_LIST ${LIBHUBBUB_LIBRARIES} )
-endif()
-
-if (LWS_ROLE_DBUS)
-       message("dbus include dir 1: ${LWS_DBUS_INCLUDE1}")
-       message("dbus include dir 2: ${LWS_DBUS_INCLUDE2}")
-       include_directories("${LWS_DBUS_INCLUDE1}")
-       include_directories("${LWS_DBUS_INCLUDE2}")
-       list(APPEND LIB_LIST ${LWS_DBUS_LIB})
-endif()
-
-#
-# Platform specific libs.
-#
-if (WINCE)
-       list(APPEND LIB_LIST ws2.lib)
-elseif (WIN32)
-       list(APPEND LIB_LIST ws2_32.lib userenv.lib psapi.lib iphlpapi.lib)
-endif()
-
-if (${CMAKE_SYSTEM_NAME} MATCHES "QNX")
-       list(APPEND LIB_LIST socket)
-endif()
+include_directories("${PROJECT_SOURCE_DIR}/lib")
 
-#
-# add libs here that need to be at the end of the link order
-#
+add_subdirectory(lib)
 
-if (UNIX)
-       list(APPEND LIB_LIST m)
-endif()
 
-if(SMARTOS)
-       list(APPEND LIB_LIST socket)
+if(WIN32 AND NOT CYGWIN)
+  set(DEF_INSTALL_CMAKE_DIR cmake)
+else()
+  set(DEF_INSTALL_CMAKE_DIR lib${LIB_SUFFIX}/cmake/libwebsockets)
 endif()
+                
+configure_file(${PROJECT_SOURCE_DIR}/cmake/LwsCheckRequirements.cmake
+               ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LwsCheckRequirements.cmake
+               @ONLY)
+               
+configure_file(${PROJECT_SOURCE_DIR}/cmake/LwsCheckRequirements.cmake
+               ${PROJECT_BINARY_DIR}/LwsCheckRequirements.cmake
+               @ONLY)  
 
-if (HAIKU)
-       list(APPEND LIB_LIST network)
-endif()
+# Generate version info for both build-tree and install-tree.
+configure_file(${PROJECT_SOURCE_DIR}/cmake/libwebsockets-config-version.cmake.in
+                ${PROJECT_BINARY_DIR}/libwebsockets-config-version.cmake 
+                @ONLY)
 
-if (LWS_HAVE_LIBCAP)
-       list(APPEND LIB_LIST cap )
-endif()
+# Generate the config file for the build-tree.
+set(LWS__INCLUDE_DIRS 
+    "${PROJECT_SOURCE_DIR}/lib"
+    "${PROJECT_BINARY_DIR}")
+set(LIBWEBSOCKETS_INCLUDE_DIRS ${LWS__INCLUDE_DIRS} CACHE PATH "Libwebsockets include directories")
+configure_file(${PROJECT_SOURCE_DIR}/cmake/libwebsockets-config.cmake.in
+                ${PROJECT_BINARY_DIR}/libwebsockets-config.cmake 
+                @ONLY)
+set(LWS_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
 
-if (UNIX)
-       list(APPEND LIB_LIST dl)
+# Export targets (This is used for other CMake projects to easily find the libraries and include files).
+if (LWS_WITH_EXPORT_LWSTARGETS)
+    export(TARGETS ${LWS_LIBRARIES}
+            FILE "${PROJECT_BINARY_DIR}/LibwebsocketsTargets.cmake")
 endif()
 
-if (LWS_WITH_ZLIB AND NOT LWS_WITH_BUNDLED_ZLIB)
-       list(APPEND LIB_LIST "${ZLIB_LIBRARIES}")
-endif()
 
-# Setup the linking for all libs.
-foreach (lib ${LWS_LIBRARIES})
-       target_link_libraries(${lib} ${LIB_LIST})
-endforeach()
 
-set (temp ${CMAKE_REQUIRED_LIBRARIES})
-set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST})
+set(libwebsockets_DIR ${PROJECT_BINARY_DIR})
+set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
+message("DIR ${libwebsockets_DIR} CMP ${CMAKE_MODULE_PATH}")
 
-if (LWS_WITH_ZLIB)
-       if (LWS_WITH_BUNDLED_ZLIB)
-               if (WIN32)
-                       # it's trying to delete internal zlib entry
-                       LIST(REMOVE_AT CMAKE_REQUIRED_LIBRARIES 0 )
-               endif()
-       endif()
+if (LWS_WITH_MINIMAL_EXAMPLES)
+       add_subdirectory(minimal-examples)
 endif()
 
-CHECK_FUNCTION_EXISTS(SSL_CTX_set1_param LWS_HAVE_SSL_CTX_set1_param)
-CHECK_FUNCTION_EXISTS(SSL_set_info_callback LWS_HAVE_SSL_SET_INFO_CALLBACK)
-CHECK_FUNCTION_EXISTS(X509_VERIFY_PARAM_set1_host LWS_HAVE_X509_VERIFY_PARAM_set1_host)
-CHECK_FUNCTION_EXISTS(RSA_set0_key LWS_HAVE_RSA_SET0_KEY)
-CHECK_FUNCTION_EXISTS(X509_get_key_usage LWS_HAVE_X509_get_key_usage)
-CHECK_FUNCTION_EXISTS(EVP_PKEY_new_raw_private_key LWS_HAVE_SSL_CTX_EVP_PKEY_new_raw_private_key)
-CHECK_FUNCTION_EXISTS(SSL_CTX_get0_certificate LWS_HAVE_SSL_CTX_get0_certificate)
-CHECK_FUNCTION_EXISTS(SSL_get0_alpn_selected LWS_HAVE_SSL_get0_alpn_selected)
-CHECK_FUNCTION_EXISTS(SSL_set_alpn_protos LWS_HAVE_SSL_set_alpn_protos)
-CHECK_FUNCTION_EXISTS(EVP_aes_128_cfb8 LWS_HAVE_EVP_aes_128_cfb8)
-CHECK_FUNCTION_EXISTS(EVP_aes_128_cfb128 LWS_HAVE_EVP_aes_128_cfb128)
-CHECK_FUNCTION_EXISTS(EVP_aes_192_cfb8 LWS_HAVE_EVP_aes_192_cfb8)
-CHECK_FUNCTION_EXISTS(EVP_aes_192_cfb128 LWS_HAVE_EVP_aes_192_cfb128)
-CHECK_FUNCTION_EXISTS(EVP_aes_256_cfb8 LWS_HAVE_EVP_aes_256_cfb8)
-CHECK_FUNCTION_EXISTS(EVP_aes_256_cfb128 LWS_HAVE_EVP_aes_256_cfb128)
-CHECK_FUNCTION_EXISTS(EVP_aes_128_xts LWS_HAVE_EVP_aes_128_xts)
-CHECK_FUNCTION_EXISTS(RSA_verify_pss_mgf1 LWS_HAVE_RSA_verify_pss_mgf1)
-CHECK_FUNCTION_EXISTS(HMAC_CTX_new LWS_HAVE_HMAC_CTX_new)
-CHECK_FUNCTION_EXISTS(SSL_CTX_set_ciphersuites LWS_HAVE_SSL_CTX_set_ciphersuites)
-if (LWS_WITH_SSL AND NOT LWS_WITH_MBEDTLS)
- if (UNIX)
- set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} dl)
- endif()
-CHECK_C_SOURCE_COMPILES("#include <openssl/ssl.h>\nint main(void) { STACK_OF(X509) *c = NULL; SSL_CTX *ctx = NULL; return (int)SSL_CTX_get_extra_chain_certs_only(ctx, &c); }\n" LWS_HAVE_SSL_EXTRA_CHAIN_CERTS)
-CHECK_C_SOURCE_COMPILES("#include <openssl/ssl.h>\nint main(void) { EVP_MD_CTX *md_ctx = NULL; EVP_MD_CTX_free(md_ctx); return 0; }\n" LWS_HAVE_EVP_MD_CTX_free)
-CHECK_FUNCTION_EXISTS(ECDSA_SIG_set0 LWS_HAVE_ECDSA_SIG_set0)
-CHECK_FUNCTION_EXISTS(BN_bn2binpad LWS_HAVE_BN_bn2binpad)
-CHECK_FUNCTION_EXISTS(EVP_aes_128_wrap LWS_HAVE_EVP_aes_128_wrap)
-CHECK_FUNCTION_EXISTS(EC_POINT_get_affine_coordinates LWS_HAVE_EC_POINT_get_affine_coordinates)
+if (NOT LWS_WITHOUT_TESTAPPS)
+       add_subdirectory(test-apps)
 endif()
-if (LWS_WITH_MBEDTLS)
-       set(LWS_HAVE_TLS_CLIENT_METHOD 1)
-       if (NOT LWS_WITH_ESP32)
-               # not supported in esp-idf openssl wrapper yet, but is in our version
-               set(LWS_HAVE_X509_VERIFY_PARAM_set1_host 1)
-       endif()
 
-       CHECK_FUNCTION_EXISTS(mbedtls_ssl_conf_alpn_protocols LWS_HAVE_mbedtls_ssl_conf_alpn_protocols)
-       CHECK_FUNCTION_EXISTS(mbedtls_ssl_get_alpn_protocol LWS_HAVE_mbedtls_ssl_get_alpn_protocol)
-       CHECK_FUNCTION_EXISTS(mbedtls_ssl_conf_sni LWS_HAVE_mbedtls_ssl_conf_sni)
-       CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_ca_chain LWS_HAVE_mbedtls_ssl_set_hs_ca_chain)
-       CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_own_cert LWS_HAVE_mbedtls_ssl_set_hs_own_cert)
-       CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_authmode LWS_HAVE_mbedtls_ssl_set_hs_authmode)
-       CHECK_FUNCTION_EXISTS(mbedtls_net_init LWS_HAVE_mbedtls_net_init)
-
-else()
-CHECK_FUNCTION_EXISTS(TLS_client_method LWS_HAVE_TLS_CLIENT_METHOD)
-CHECK_FUNCTION_EXISTS(TLSv1_2_client_method LWS_HAVE_TLSV1_2_CLIENT_METHOD)
+if (NOT LWS_WITH_PLUGINS_BUILTIN)
+add_subdirectory(plugins)
 endif()
+add_subdirectory(lwsws)
 
-# ideally we want to use pipe2()
-
-CHECK_C_SOURCE_COMPILES("#define _GNU_SOURCE\n#include <unistd.h>\nint main(void) {int fd[2];\n return pipe2(fd, 0);\n}\n" LWS_HAVE_PIPE2)
-
-# tcp keepalive needs this on linux to work practically... but it only exists
-# after kernel 2.6.37
-
-CHECK_C_SOURCE_COMPILES("#include <netinet/tcp.h>\nint main(void) { return TCP_USER_TIMEOUT; }\n" LWS_HAVE_TCP_USER_TIMEOUT)
-
-set(CMAKE_REQUIRED_LIBRARIES ${temp})
 # Generate the lws_config.h that includes all the public compilation settings.
 configure_file(
        "${PROJECT_SOURCE_DIR}/cmake/lws_config.h.in"
        "${PROJECT_BINARY_DIR}/lws_config.h")
+       
+add_custom_command(
+               OUTPUT ${PROJECT_BINARY_DIR}/include/lws_config.h
+                       ${PROJECT_BINARY_DIR}/include/libwebsockets
+                       ${PROJECT_BINARY_DIR}/include/libwebsockets.h
+               COMMENT "Creating build include dir"
+               COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/include/libwebsockets.h
+                       ${CMAKE_CURRENT_BINARY_DIR}/include/libwebsockets.h
+               COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/libwebsockets/
+                       ${CMAKE_CURRENT_BINARY_DIR}/include/libwebsockets
+               COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/lws_config.h
+                       ${CMAKE_CURRENT_BINARY_DIR}/include/lws_config.h
+               MAIN_DEPENDENCY ${PROJECT_BINARY_DIR}/lws_config.h
+)
 
-# Generate the lws_config.h that includes all the private compilation settings.
-configure_file(
-       "${PROJECT_SOURCE_DIR}/cmake/lws_config_private.h.in"
-       "${PROJECT_BINARY_DIR}/lws_config_private.h")
-
-# Generate self-signed SSL certs for the test-server.
+add_custom_target(GENHDR DEPENDS  ${PROJECT_BINARY_DIR}/include/lws_config.h)
 
-if (LWS_WITH_SSL AND NOT LWS_WITH_WOLFSSL)
-       message("Searching for OpenSSL executable and dlls")
-       find_package(OpenSSLbins)
-       message("OpenSSL executable: ${OPENSSL_EXECUTABLE}")
-       if (OPENSSL_EXECUTABLE MATCHES "^$")
-               set(OPENSSL_EXECUTABLE openssl)
-       endif()
-       if (NOT OPENSSL_EXECUTABLE)
-               set(OPENSSL_EXECUTABLE openssl)
-       endif()
+file(GLOB HDR_PUBLIC1 RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} include/libwebsockets/*.h)
+file(GLOB HDR_PUBLIC2 RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} include/libwebsockets.h)
+file(GLOB HDR_PUBLIC3 RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/include/lws_config.h)
+list(APPEND HDR_PUBLIC ${HDR_PUBLIC1} ${HDR_PUBLIC2} ${HDR_PUBLIC3})
 
-endif()
+set_source_files_properties(${HDR_PUBLIC} PROPERTIES GENERATED 1)
 
-set(GENCERTS 0)
-
-if (LWS_WITH_SSL AND OPENSSL_EXECUTABLE AND NOT LWS_WITHOUT_TEST_SERVER AND NOT LWS_WITHOUT_SERVER AND NOT LWS_WITHOUT_TESTAPPS)
-       set(GENCERTS 1)
-endif()
-if (LWS_WITH_ESP32)
-       set(GENCERTS 1)
+if (LWS_WITH_STATIC)
+       add_dependencies(websockets GENHDR)
 endif()
-message(" GENCERTS = ${GENCERTS}")
-if (GENCERTS)
-       message("Generating SSL Certificates for the test-server...")
-
-       set(TEST_SERVER_SSL_KEY "${PROJECT_BINARY_DIR}/libwebsockets-test-server.key.pem")
-       set(TEST_SERVER_SSL_CERT "${PROJECT_BINARY_DIR}/libwebsockets-test-server.pem")
-
-       if (WIN32)
-               if (MINGW)
-                       message("cmd = \"${OPENSSL_EXECUTABLE}\" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -subj \"/C=GB/ST=Erewhon/L=All around/O=libwebsockets-test/CN=localhost\" -keyout \"${TEST_SERVER_SSL_KEY}\" -out \"${TEST_SERVER_SSL_CERT}\"")
-                       execute_process(
-                               COMMAND "${OPENSSL_EXECUTABLE}" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -subj "/C=GB/ST=Erewhon/L=All around/O=libwebsockets-test/CN=localhost" -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
-                               RESULT_VARIABLE OPENSSL_RETURN_CODE)
-               else()
-                       file(WRITE "${PROJECT_BINARY_DIR}/openssl_input.txt"
-                               "GB\n"
-                               "Erewhon\n"
-                               "All around\n"
-                               "libwebsockets-test\n"
-                               "localhost\n"
-                               "none@invalid.org\n\n"
-                               )
-
-                       # The "type" command is a bit picky with paths.
-                       file(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/openssl_input.txt" OPENSSL_INPUT_WIN_PATH)
-                       message("OPENSSL_INPUT_WIN_PATH = ${OPENSSL_INPUT_WIN_PATH}")
-                       message("cmd = \"${OPENSSL_EXECUTABLE}\" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout \"${TEST_SERVER_SSL_KEY}\" -out \"${TEST_SERVER_SSL_CERT}\"")
-
-                       execute_process(
-                               COMMAND cmd /c type "${OPENSSL_INPUT_WIN_PATH}"
-                               COMMAND "${OPENSSL_EXECUTABLE}" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
-                               RESULT_VARIABLE OPENSSL_RETURN_CODE
-                               OUTPUT_QUIET ERROR_QUIET)
-
-                       message("\n")
-               endif()
-
-               if (OPENSSL_RETURN_CODE)
-                       message(WARNING "!!! Failed to generate SSL certificate for Test Server using cmd.exe !!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")
-               else()
-                       message("SUCCSESFULLY generated SSL certificate")
-               endif()
-       else()
-               # Unix.
-               execute_process(
-                       COMMAND printf "GB\\nErewhon\\nAll around\\nlibwebsockets-test\\n\\nlocalhost\\nnone@invalid.org\\n"
-                       COMMAND "${OPENSSL_EXECUTABLE}"
-                               req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
-                       RESULT_VARIABLE OPENSSL_RETURN_CODE
-                       #               OUTPUT_QUIET ERROR_QUIET
-                       )
-
-               if (OPENSSL_RETURN_CODE)
-                       message(WARNING "!!! Failed to generate SSL certificate for Test Server!!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")
-               else()
-                       message("SUCCESSFULLY generated SSL certificate")
-               endif()
-       endif()
-
-       list(APPEND TEST_SERVER_DATA 
-               "${TEST_SERVER_SSL_KEY}"
-               "${TEST_SERVER_SSL_CERT}")
+if (LWS_WITH_SHARED)
+       add_dependencies(websockets_shared GENHDR)
 endif()
 
 
 
-
-#
-# Test applications
 #
-set(TEST_APP_LIST)
-if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
-       #
-       # Helper function for adding a test app.
-       #
-       macro(create_test_app TEST_NAME MAIN_SRC S2 S3 S4 S5 S6)
-
-               set(TEST_SRCS ${MAIN_SRC})
-               set(TEST_HDR)
-               if ("${S2}" STREQUAL "")
-               else()
-                       list(APPEND TEST_SRCS ${S2})
-               endif()
-               if ("${S3}" STREQUAL "")
-               else()
-                       list(APPEND TEST_SRCS ${S3})
-               endif()
-               if ("${S4}" STREQUAL "")
-               else()
-                       list(APPEND TEST_SRCS ${S4})
-               endif()
-               if ("${S5}" STREQUAL "")
-               else()
-                       list(APPEND TEST_SRCS ${S5})
-               endif()
-               if ("${S6}" STREQUAL "")
-               else()
-                       list(APPEND TEST_SRCS ${S6})
-               endif()
-               if (WIN32)
-                       list(APPEND TEST_SRCS
-                               ${WIN32_HELPERS_PATH}/getopt.c
-                               ${WIN32_HELPERS_PATH}/getopt_long.c
-                               ${WIN32_HELPERS_PATH}/gettimeofday.c
-                       )
-
-                       list(APPEND TEST_HDR
-                               ${WIN32_HELPERS_PATH}/getopt.h
-                               ${WIN32_HELPERS_PATH}/gettimeofday.h
-                       )
-               endif(WIN32)
-
-               source_group("Headers Private"   FILES ${TEST_HDR})
-               source_group("Sources"   FILES ${TEST_SRCS})
-               add_executable(${TEST_NAME} ${TEST_SRCS} ${TEST_HDR})
-
-               if (LWS_LINK_TESTAPPS_DYNAMIC)
-                       if (NOT LWS_WITH_SHARED)
-                               message(FATAL_ERROR "Build of the shared library is disabled. LWS_LINK_TESTAPPS_DYNAMIC must be combined with LWS_WITH_SHARED.")
-                       endif()
-                       target_link_libraries(${TEST_NAME} websockets_shared)
-                       add_dependencies(${TEST_NAME} websockets_shared)
-               else()
-                       if (NOT LWS_WITH_STATIC)
-                               message(FATAL_ERROR "Build of the static library is disabled. Disabled LWS_LINK_TESTAPPS_DYNAMIC must be combined with LWS_WITH_STATIC.")
-                       endif()
-                       target_link_libraries(${TEST_NAME} websockets)
-                       add_dependencies(${TEST_NAME} websockets)
-                       if (UNIX AND LWS_WITH_SSL AND NOT LWS_WITH_MBEDTLS)
-                               target_link_libraries(${TEST_NAME} dl)
-                       endif()
-               endif()
-
-               if (LWS_WITH_HTTP_STREAM_COMPRESSION)
-                       target_link_libraries(${TEST_NAME} z)
-               endif()
-
-               # Set test app specific defines.
-               set_property(TARGET ${TEST_NAME}
-                                       PROPERTY COMPILE_DEFINITIONS
-                                               INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
-                                       )
-
-               # Prefix the binary names with libwebsockets.
-               set_target_properties(${TEST_NAME}
-                       PROPERTIES
-                       OUTPUT_NAME libwebsockets-${TEST_NAME})
-
-               # Add to the list of tests.
-               list(APPEND TEST_APP_LIST ${TEST_NAME})
-       endmacro()
-
-       if (UNIX AND LWS_WITH_PLUGINS)
-               set(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
-               if(NOT((${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") OR (${CMAKE_SYSTEM_NAME} MATCHES "QNX")))
-                       target_link_libraries(websockets dl)
-               endif()
-       endif()
-
-       if (NOT LWS_WITHOUT_SERVER)
-               #
-               # test-server
-               #
-               if (NOT LWS_WITHOUT_TEST_SERVER)
-                       create_test_app(test-server "test-apps/test-server.c"
-                               ""
-                               ""
-                               ""
-                               ""
-                               "")
-
-                       if (LWS_WITH_CGI)
-                       create_test_app(test-sshd "test-apps/test-sshd.c"
-                               ""
-                               ""
-                               ""
-                               ""
-                               "")
-                       target_include_directories(test-sshd PRIVATE "${PROJECT_SOURCE_DIR}/plugins/ssh-base/include")
-
-                       endif()
-
-               endif()
-
-               #
-               # test-server-extpoll
-               #
-               if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL AND NOT WIN32)
-                       create_test_app(test-server-extpoll
-                               "test-apps/test-server.c"
-                               ""
-                               ""
-                               ""
-                               ""
-                               "")
-                       # Set defines for this executable only.
-                       set_property(
-                               TARGET test-server-extpoll
-                               PROPERTY COMPILE_DEFINITIONS 
-                                       EXTERNAL_POLL 
-                                       INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
-                               )
-
-                       # We need to link against winsock code.
-                       if (WIN32)
-                               target_link_libraries(test-server-extpoll ws2_32.lib)
-                       endif(WIN32)
-               endif()
-
-               if (LWS_WITH_LEJP)
-                       create_test_app(
-                               test-lejp
-                               "test-apps/test-lejp.c"
-                               ""
-                               ""
-                               ""
-                               ""
-                               "")
-               endif()
-
-               # Data files for running the test server.
-               list(APPEND TEST_SERVER_DATA
-                       "${PROJECT_SOURCE_DIR}/test-apps/favicon.ico"
-                       "${PROJECT_SOURCE_DIR}/test-apps/leaf.jpg"
-                       "${PROJECT_SOURCE_DIR}/test-apps/candide.zip"
-                       "${PROJECT_SOURCE_DIR}/test-apps/libwebsockets.org-logo.svg"
-                       "${PROJECT_SOURCE_DIR}/test-apps/http2.png"
-                       "${PROJECT_SOURCE_DIR}/test-apps/wss-over-h2.png"
-                       "${PROJECT_SOURCE_DIR}/test-apps/lws-common.js"
-                       "${PROJECT_SOURCE_DIR}/test-apps/test.html"
-                       "${PROJECT_SOURCE_DIR}/test-apps/test.css"
-                       "${PROJECT_SOURCE_DIR}/test-apps/test.js")
-
-               add_custom_command(TARGET test-server
-                                               POST_BUILD 
-                                               COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server")
-
-               # Copy the file needed to run the server so that the test apps can
-               # reach them from their default output location
-               foreach (TEST_FILE ${TEST_SERVER_DATA})
-                       if (EXISTS ${TEST_FILE})
-                               add_custom_command(TARGET test-server
-                                                       POST_BUILD 
-                                                       COMMAND "${CMAKE_COMMAND}" -E copy "${TEST_FILE}" "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server" VERBATIM)
-                       endif()
-               endforeach()
-       endif(NOT LWS_WITHOUT_SERVER)
-
-       if (NOT LWS_WITHOUT_CLIENT)
-               #
-               # test-client
-               #
-               if (NOT LWS_WITHOUT_TEST_CLIENT)
-                       create_test_app(test-client "test-apps/test-client.c" "" "" "" "" "")
-               endif()
-
-       endif(NOT LWS_WITHOUT_CLIENT)
-       
-       
-       if (LWS_WITH_PLUGINS AND LWS_WITH_SHARED)
-               macro(create_plugin PLUGIN_NAME PLUGIN_INCLUDE MAIN_SRC S2 S3)
-
-               set(PLUGIN_SRCS ${MAIN_SRC})
-
-               if ("${S2}" STREQUAL "")
-               else()
-                       list(APPEND PLUGIN_SRCS ${S2})
-               endif()
-               if ("${S3}" STREQUAL "")
-               else()
-                       list(APPEND PLUGIN_SRCS ${S3})
-               endif()
-
-               if (WIN32)
-                       list(APPEND PLUGIN_SRCS
-                               ${WIN32_HELPERS_PATH}/getopt.c
-                               ${WIN32_HELPERS_PATH}/getopt_long.c
-                               ${WIN32_HELPERS_PATH}/gettimeofday.c
-                       )
-
-                       list(APPEND PLUGIN_HDR
-                               ${WIN32_HELPERS_PATH}/getopt.h
-                               ${WIN32_HELPERS_PATH}/gettimeofday.h
-                       )
-               endif(WIN32)
-
-               source_group("Headers Private"   FILES ${PLUGIN_HDR})
-               source_group("Sources"   FILES ${PLUGIN_SRCS})
-               add_library(${PLUGIN_NAME} SHARED ${PLUGIN_SRCS} ${PLUGIN_HDR})
-               
-               target_link_libraries(${PLUGIN_NAME} websockets_shared)
-               add_dependencies(${PLUGIN_NAME} websockets_shared)
-               include_directories(${PLUGIN_INCLUDE})
-
-               # Set test app specific defines.
-               set_property(TARGET ${PLUGIN_NAME}
-                            PROPERTY COMPILE_DEFINITIONS
-                            INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/plugins"
-               )
-
-               SET_TARGET_PROPERTIES(${PLUGIN_NAME}
-                               PROPERTIES COMPILE_FLAGS ${CMAKE_C_FLAGS})
-
-#              set_target_properties(${PLUGIN_NAME}
-#                      PROPERTIES
-#                      OUTPUT_NAME ${PLUGIN_NAME})
-
-               list(APPEND PLUGINS_LIST ${PLUGIN_NAME})
-
-               endmacro()
-               
-if (LWS_ROLE_WS)
-               create_plugin(protocol_dumb_increment ""
-                             "plugins/protocol_dumb_increment.c" "" "")
-               create_plugin(protocol_lws_mirror ""
-                             "plugins/protocol_lws_mirror.c" "" "")
-               create_plugin(protocol_lws_status ""
-                             "plugins/protocol_lws_status.c" "" "")
-               create_plugin(protocol_lws_table_dirlisting ""
-                             "plugins/generic-table/protocol_table_dirlisting.c" "" "")
-               if (NOT WIN32)
-                       create_plugin(protocol_lws_raw_test ""
-                             "plugins/protocol_lws_raw_test.c" "" "")
-
-                       create_plugin(protocol_deaddrop ""
-                             "plugins/deaddrop/protocol_lws_deaddrop.c" "" "")
-
-               endif()
-
-if (LWS_WITH_SERVER_STATUS)
-               create_plugin(protocol_lws_server_status ""
-                             "plugins/protocol_lws_server_status.c" "" "")
-endif()
-
-if (NOT LWS_WITHOUT_CLIENT)
-               create_plugin(protocol_client_loopback_test ""
-                              "plugins/protocol_client_loopback_test.c" "" "")
-endif()
-
-endif()
-
-               create_plugin(protocol_post_demo ""
-                             "plugins/protocol_post_demo.c" "" "")
-
-if (LWS_ROLE_RAW_PROXY)
-               create_plugin(protocol_lws_raw_proxy ""
-                             "plugins/raw-proxy/protocol_lws_raw_proxy.c" "" "")
-endif()
-
-if (LWS_WITH_FTS)
-               create_plugin(protocol_fulltext_demo ""
-                             "plugins/protocol_fulltext_demo.c" "" "")
-endif()
-
-
-if (LWS_WITH_SSL)
-               create_plugin(protocol_lws_ssh_base "plugins/ssh-base/include"
-                             "plugins/ssh-base/sshd.c;plugins/ssh-base/telnet.c;plugins/ssh-base/kex-25519.c" "plugins/ssh-base/crypto/chacha.c;plugins/ssh-base/crypto/ed25519.c;plugins/ssh-base/crypto/fe25519.c;plugins/ssh-base/crypto/ge25519.c;plugins/ssh-base/crypto/poly1305.c;plugins/ssh-base/crypto/sc25519.c;plugins/ssh-base/crypto/smult_curve25519_ref.c" "")
-               create_plugin(protocol_lws_sshd_demo "plugins/ssh-base/include" "plugins/protocol_lws_sshd_demo.c" "" "")
-
-               include_directories("${PROJECT_SOURCE_DIR}/plugins/ssh-base/include")
-endif()
-
-
-
-if (LWS_WITH_ACME)
-               create_plugin(protocol_lws_acme_client ""
-                             "plugins/acme-client/protocol_lws_acme_client.c" "" "")
-endif()
-
-if (LWS_WITH_GENERIC_SESSIONS AND LWS_ROLE_WS)
-       create_plugin(protocol_generic_sessions ""
-                      "plugins/generic-sessions/protocol_generic_sessions.c"
-                     "plugins/generic-sessions/utils.c"
-                     "plugins/generic-sessions/handlers.c")
-
-       if (WIN32)
-               target_link_libraries(protocol_generic_sessions ${LWS_SQLITE3_LIBRARIES})
-       else()
-               target_link_libraries(protocol_generic_sessions sqlite3 )
-       endif(WIN32)
-
-               create_plugin(protocol_lws_messageboard ""
-                             "plugins/generic-sessions/protocol_lws_messageboard.c" "" "")
-       if (WIN32)
-               target_link_libraries(protocol_lws_messageboard ${LWS_SQLITE3_LIBRARIES})
-       else()
-               target_link_libraries(protocol_lws_messageboard sqlite3 )
-       endif(WIN32)
-
-endif(LWS_WITH_GENERIC_SESSIONS AND LWS_ROLE_WS)
-
-
-       endif(LWS_WITH_PLUGINS AND LWS_WITH_SHARED)
-
-       #
-       # Copy OpenSSL dlls to the output directory on Windows.
-       # (Otherwise we'll get an error when trying to run)
-       #
-       if (WIN32 AND LWS_WITH_SSL AND NOT LWS_WITH_WOLFSSL)
-               if(OPENSSL_BIN_FOUND)
-                       message("OpenSSL dlls found:")
-                       message("  Libeay: ${LIBEAY_BIN}")
-                       message("  SSLeay: ${SSLEAY_BIN}")
-
-                       foreach(TARGET_BIN ${TEST_APP_LIST})
-                               add_custom_command(TARGET ${TARGET_BIN}
-                                       POST_BUILD
-                                       COMMAND "${CMAKE_COMMAND}" -E copy "${LIBEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
-                               add_custom_command(TARGET ${TARGET_BIN}
-                                       POST_BUILD
-                                       COMMAND "${CMAKE_COMMAND}" -E copy "${SSLEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
-
-                               #
-                               # Win32: if we are using libuv, also need to copy it in the output dir
-                               #
-                               if (WIN32 AND LWS_WITH_LIBUV)
-                                       STRING(REPLACE ".lib" ".dll" LIBUV_BIN ${LIBUV_LIBRARIES})
-                                       add_custom_command(TARGET ${TARGET_BIN}
-                                               POST_BUILD
-                                               COMMAND "${CMAKE_COMMAND}" -E copy "${LIBUV_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
-                               endif()
-                       endforeach()
-               endif()
-       endif()
-endif((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS)
-
-if (LWS_WITH_LWSWS)
-               list(APPEND LWSWS_SRCS
-                       "lwsws/main.c"
-               )
-
-               if (WIN32)
-                       list(APPEND LWSWS_SRCS
-                               ${WIN32_HELPERS_PATH}/getopt.c
-                               ${WIN32_HELPERS_PATH}/getopt_long.c
-                               ${WIN32_HELPERS_PATH}/gettimeofday.c
-                       )
-
-                       list(APPEND LWSWS_HDR
-                               ${WIN32_HELPERS_PATH}/getopt.h
-                               ${WIN32_HELPERS_PATH}/gettimeofday.h
-                       )
-               endif(WIN32)
-
-               source_group("Headers Private"   FILES ${LWSWS_HDR})
-               source_group("Sources"   FILES ${LWSWS_SRCS})
-               add_executable("lwsws" ${LWSWS_SRCS} ${LWSWS_HDR})
-
-               target_link_libraries("lwsws" websockets_shared)
-               add_dependencies("lwsws" websockets_shared)
-
-               # Set test app specific defines.
-               set_property(TARGET "lwsws"
-                            PROPERTY COMPILE_DEFINITIONS
-                            INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
-               )
-endif (LWS_WITH_LWSWS)
-
-if (UNIX)
-
-# Generate and install pkgconfig.
-# (This is not indented, because the tabs will be part of the output)
-file(WRITE "${PROJECT_BINARY_DIR}/libwebsockets.pc"
-"prefix=\"${CMAKE_INSTALL_PREFIX}\"
-exec_prefix=\${prefix}
-libdir=\${exec_prefix}/lib${LIB_SUFFIX}
-includedir=\${prefix}/include
-
-Name: libwebsockets
-Description: Websockets server and client library
-Version: ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}
-
-Libs: -L\${libdir} -lwebsockets
-Cflags: -I\${includedir}"
-)
-
-       install(FILES "${PROJECT_BINARY_DIR}/libwebsockets.pc"
-               DESTINATION lib${LIB_SUFFIX}/pkgconfig)
-
-file(WRITE "${PROJECT_BINARY_DIR}/libwebsockets_static.pc"
-"prefix=\"${CMAKE_INSTALL_PREFIX}\"
-exec_prefix=\${prefix}
-libdir=\${exec_prefix}/lib${LIB_SUFFIX}
-includedir=\${prefix}/include
-
-Name: libwebsockets_static
-Description: Websockets server and client static library
-Version: ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}
-
-Libs: -L\${libdir} -lwebsockets_static
-Libs.private:
-Cflags: -I\${includedir}"
-)
-
-       install(FILES "${PROJECT_BINARY_DIR}/libwebsockets_static.pc"
-               DESTINATION lib${LIB_SUFFIX}/pkgconfig)
-
-
-endif(UNIX)
-
 #
 # Installation preparations.
 #
 
-if(WIN32 AND NOT CYGWIN)
-  set(DEF_INSTALL_CMAKE_DIR cmake)
-else()
-  set(DEF_INSTALL_CMAKE_DIR lib${LIB_SUFFIX}/cmake/libwebsockets)
-endif()
-
-set(LWS_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
-
-# Export targets (This is used for other CMake projects to easily find the libraries and include files).
-if (LWS_WITH_EXPORT_LWSTARGETS)
-    export(TARGETS ${LWS_LIBRARIES}
-            FILE "${PROJECT_BINARY_DIR}/LibwebsocketsTargets.cmake")
-endif()
-
 export(PACKAGE libwebsockets)
 
-# Generate the config file for the build-tree.
-set(LWS__INCLUDE_DIRS 
-    "${PROJECT_SOURCE_DIR}/lib"
-    "${PROJECT_BINARY_DIR}")
-set(LIBWEBSOCKETS_INCLUDE_DIRS ${LWS__INCLUDE_DIRS} CACHE PATH "Libwebsockets include directories")
-configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfig.cmake.in
-                ${PROJECT_BINARY_DIR}/LibwebsocketsConfig.cmake 
-                @ONLY)
+install(DIRECTORY include/libwebsockets
+       DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev)
+install(FILES ${PROJECT_BINARY_DIR}/include/libwebsockets.h ${PROJECT_BINARY_DIR}/include/lws_config.h
+       DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev)
 
 # Generate the config file for the installation tree.
 get_filename_component(LWS_ABSOLUTE_INSTALL_CMAKE_DIR ${LWS_INSTALL_CMAKE_DIR} ABSOLUTE)
@@ -2523,139 +1064,25 @@ file(RELATIVE_PATH
     "${LWS_ABSOLUTE_INSTALL_CMAKE_DIR}"
     "${LWS_ABSOLUTE_INSTALL_INCLUDE_DIR}") # Calculate the relative directory from the cmake dir.
 
-# Note the EVENT_CMAKE_DIR is defined in JanssonConfig.cmake.in, 
-# we escape it here so it's evaluated when it is included instead
-# so that the include dirs are given relative to where the 
-# config file is located.
-set(LWS__INCLUDE_DIRS 
-    "\${LWS_CMAKE_DIR}/${REL_INCLUDE_DIR}") 
-configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfig.cmake.in
-                ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LibwebsocketsConfig.cmake 
-                @ONLY)
-
-# Generate version info for both build-tree and install-tree.
-configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfigVersion.cmake.in
-                ${PROJECT_BINARY_DIR}/LibwebsocketsConfigVersion.cmake 
-                @ONLY)
-
-                       set_target_properties(${LWS_LIBRARIES}
-                                       PROPERTIES PUBLIC_HEADER "${HDR_PUBLIC}")
-
-#
-# Installation.
-#
-
-install(DIRECTORY include/libwebsockets
-       DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev_headers)
-
-# Install libs and headers.
-install(TARGETS ${LWS_LIBRARIES}
-               EXPORT LibwebsocketsTargets
-               LIBRARY DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries
-               ARCHIVE DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries
-               RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT libraries # Windows DLLs
-               PUBLIC_HEADER DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev)
-               
-set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
-set(CPACK_COMPONENT_DEV_DISPLAY_NAME "Development files")
-
-# Install test apps.
-if (NOT LWS_WITHOUT_TESTAPPS)
-       install(TARGETS ${TEST_APP_LIST}
-                       RUNTIME DESTINATION ${LWS_INSTALL_EXAMPLES_DIR}
-                       COMPONENT examples)
-       set(CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "Example files")
+if (DEFINED REL_INCLUDE_DIR)
+    set(LWS__INCLUDE_DIRS "\${LWS_CMAKE_DIR}/${REL_INCLUDE_DIR}")
 endif()
-
-# lwsws
-if (LWS_WITH_LWSWS)
-       install(TARGETS lwsws
-               RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT lwsws )
-endif()
-
-# Programs shared files used by the test-server.
-if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_SERVER)
-       install(FILES ${TEST_SERVER_DATA}
-                       DESTINATION share/libwebsockets-test-server
-               COMPONENT examples)
-
-               install(FILES "${PROJECT_SOURCE_DIR}/test-apps/private/index.html"
-                       DESTINATION share/libwebsockets-test-server/private
-                       COMPONENT examples)
-if (LWS_WITH_CGI)
-       set(CGI_TEST_SCRIPT "${PROJECT_SOURCE_DIR}/test-apps/lws-cgi-test.sh")
-       install(FILES ${CGI_TEST_SCRIPT}
-                       PERMISSIONS  OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ
-                       DESTINATION share/libwebsockets-test-server
-                       COMPONENT examples)
-       endif()
+if (DEFINED OPENSSL_INCLUDE_DIRS)
+       set(LWS__INCLUDE_DIRS "${LWS__INCLUDE_DIRS};${OPENSSL_INCLUDE_DIRS}")
 endif()
 
+configure_file(${PROJECT_SOURCE_DIR}/cmake/libwebsockets-config.cmake.in
+                ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libwebsockets-config.cmake
+                @ONLY)
 
-if (NOT LWS_WITHOUT_TEST_SERVER AND NOT LWS_WITHOUT_SERVER AND NOT LWS_WITHOUT_TESTAPPS)
-       install(FILES test-apps/lws-ssh-test-keys;test-apps/lws-ssh-test-keys.pub
-               DESTINATION share/libwebsockets-test-server
-               COMPONENT examples)
-endif()
-
-# plugins
-
-if (LWS_WITH_PLUGINS)
-       install(TARGETS ${PLUGINS_LIST}
-               PERMISSIONS  OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ
-               DESTINATION share/libwebsockets-test-server/plugins
-               COMPONENT plugins)
-
-       if (NOT WIN32)
-               install(FILES plugins/deaddrop/assets/index.html;plugins/deaddrop/assets/deaddrop.js;plugins/deaddrop/assets/deaddrop.css;plugins/deaddrop/assets/drop.svg
-                       DESTINATION share/libwebsockets-test-server/deaddrop
-                       COMPONENT plugins)
-       endif()
-
-
-if (LWS_WITH_SERVER_STATUS)
-       install(FILES plugins/server-status.html;plugins/server-status.js;plugins/server-status.css;plugins/lwsws-logo.png
-               DESTINATION share/libwebsockets-test-server/server-status
-                       COMPONENT examples)
-endif()
-if (LWS_WITH_GENERIC_SESSIONS)
-       install(FILES
-                     plugins/generic-sessions/assets/lwsgs-logo.png
-                     plugins/generic-sessions/assets/seats.jpg
-                     plugins/generic-sessions/assets/failed-login.html
-                     plugins/generic-sessions/assets/lwsgs.js
-                     plugins/generic-sessions/assets/lwsgs.css
-                     plugins/generic-sessions/assets/post-register-fail.html
-                     plugins/generic-sessions/assets/post-register-ok.html
-                     plugins/generic-sessions/assets/post-verify-ok.html
-                     plugins/generic-sessions/assets/post-verify-fail.html
-                     plugins/generic-sessions/assets/sent-forgot-ok.html
-                     plugins/generic-sessions/assets/sent-forgot-fail.html
-                     plugins/generic-sessions/assets/post-forgot-ok.html
-                     plugins/generic-sessions/assets/post-forgot-fail.html
-                     plugins/generic-sessions/assets/index.html
-               DESTINATION share/libwebsockets-test-server/generic-sessions
-                       COMPONENT examples)
-       install(FILES plugins/generic-sessions/assets/successful-login.html 
-               DESTINATION share/libwebsockets-test-server/generic-sessions/needauth
-                       COMPONENT examples)
-       install(FILES plugins/generic-sessions/assets/admin-login.html
-               DESTINATION share/libwebsockets-test-server/generic-sessions/needadmin
-                       COMPONENT examples)
-endif()
-
-       install(FILES
-                     plugins/generic-table/assets/lwsgt.js
-                     plugins/generic-table/assets/index.html
-               DESTINATION share/libwebsockets-test-server/generic-table
-                       COMPONENT examples)
-
-endif()
+set_target_properties(${LWS_LIBRARIES}
+               PROPERTIES PUBLIC_HEADER "${HDR_PUBLIC}")
 
 # Install the LibwebsocketsConfig.cmake and LibwebsocketsConfigVersion.cmake
 install(FILES
-               "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LibwebsocketsConfig.cmake"
-               "${PROJECT_BINARY_DIR}/LibwebsocketsConfigVersion.cmake"
+               "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libwebsockets-config.cmake"
+               "${PROJECT_BINARY_DIR}/libwebsockets-config-version.cmake"
+               "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LwsCheckRequirements.cmake"
                DESTINATION "${LWS_INSTALL_CMAKE_DIR}" COMPONENT dev)
 
 # Install exports for the install-tree.
@@ -2670,114 +1097,7 @@ set(CPACK_SOURCE_IGNORE_FILES $(CPACK_SOURCE_IGNORE_FILES) "/.git/" "/build/" "\
 # Most people are more used to "make dist" compared to "make package_source"
 add_custom_target(dist COMMAND "${CMAKE_MAKE_PROGRAM}" package_source)
 
-include(UseRPMTools)
-if (RPMTools_FOUND)
-       RPMTools_ADD_RPM_TARGETS(libwebsockets scripts/libwebsockets.spec)
-endif()
-
-message("---------------------------------------------------------------------")
-message("  Settings:  (For more help do cmake -LH <srcpath>)")
-message("---------------------------------------------------------------------")
-message(" LWS_WITH_STATIC = ${LWS_WITH_STATIC}")
-message(" LWS_WITH_SHARED = ${LWS_WITH_SHARED}")
-message(" LWS_WITH_SSL = ${LWS_WITH_SSL} (SSL Support)")
-message(" LWS_SSL_CLIENT_USE_OS_CA_CERTS = ${LWS_SSL_CLIENT_USE_OS_CA_CERTS}")
-message(" LWS_WITH_WOLFSSL = ${LWS_WITH_WOLFSSL} (wolfSSL/CyaSSL replacement for OpenSSL)")
-if (LWS_WITH_WOLFSSL)
-       message("   LWS_WOLFSSL_LIBRARIES = ${LWS_WOLFSSL_LIBRARIES}")
-       message("   LWS_WOLFSSL_INCLUDE_DIRS = ${LWS_WOLFSSL_INCLUDE_DIRS}")
-endif()
-message(" LWS_WITH_MBEDTLS = ${LWS_WITH_MBEDTLS} (mbedTLS replacement for OpenSSL)")
-message(" LWS_WITHOUT_BUILTIN_SHA1 = ${LWS_WITHOUT_BUILTIN_SHA1}")
-message(" LWS_WITHOUT_BUILTIN_GETIFADDRS = ${LWS_WITHOUT_BUILTIN_GETIFADDRS}")
-message(" LWS_WITHOUT_CLIENT = ${LWS_WITHOUT_CLIENT}")
-message(" LWS_WITHOUT_SERVER = ${LWS_WITHOUT_SERVER}")
-message(" LWS_LINK_TESTAPPS_DYNAMIC = ${LWS_LINK_TESTAPPS_DYNAMIC}")
-message(" LWS_WITHOUT_TESTAPPS = ${LWS_WITHOUT_TESTAPPS}")
-message(" LWS_WITHOUT_TEST_SERVER = ${LWS_WITHOUT_TEST_SERVER}")
-message(" LWS_WITHOUT_TEST_SERVER_EXTPOLL = ${LWS_WITHOUT_TEST_SERVER_EXTPOLL}")
-message(" LWS_WITHOUT_TEST_PING = ${LWS_WITHOUT_TEST_PING}")
-message(" LWS_WITHOUT_TEST_CLIENT = ${LWS_WITHOUT_TEST_CLIENT}")
-message(" LWS_WITHOUT_EXTENSIONS = ${LWS_WITHOUT_EXTENSIONS}")
-message(" LWS_WITH_LATENCY = ${LWS_WITH_LATENCY}")
-message(" LWS_WITHOUT_DAEMONIZE = ${LWS_WITHOUT_DAEMONIZE}")
-message(" LWS_WITH_LIBEV = ${LWS_WITH_LIBEV}")
-message(" LWS_WITH_LIBUV = ${LWS_WITH_LIBUV}")
-message(" LWS_WITH_LIBEVENT = ${LWS_WITH_LIBEVENT}")
-message(" LWS_IPV6 = ${LWS_IPV6}")
-message(" LWS_UNIX_SOCK = ${LWS_UNIX_SOCK}")
-message(" LWS_WITH_HTTP2 = ${LWS_WITH_HTTP2}")
-message(" LWS_SSL_SERVER_WITH_ECDH_CERT = ${LWS_SSL_SERVER_WITH_ECDH_CERT}")
-message(" LWS_MAX_SMP = ${LWS_MAX_SMP}")
-message(" LWS_HAVE_PTHREAD_H = ${LWS_HAVE_PTHREAD_H}")
-message(" LWS_WITH_CGI = ${LWS_WITH_CGI}")
-message(" LWS_HAVE_OPENSSL_ECDH_H = ${LWS_HAVE_OPENSSL_ECDH_H}")
-message(" LWS_HAVE_SSL_CTX_set1_param = ${LWS_HAVE_SSL_CTX_set1_param}")
-message(" LWS_HAVE_RSA_SET0_KEY = ${LWS_HAVE_RSA_SET0_KEY}")
-message(" LWS_WITH_HTTP_PROXY = ${LWS_WITH_HTTP_PROXY}")
-message(" LIBHUBBUB_LIBRARIES = ${LIBHUBBUB_LIBRARIES}")
-message(" PLUGINS = ${PLUGINS_LIST}")
-message(" LWS_WITH_ACCESS_LOG = ${LWS_WITH_ACCESS_LOG}")
-message(" LWS_WITH_SERVER_STATUS = ${LWS_WITH_SERVER_STATUS}")
-message(" LWS_WITH_LEJP = ${LWS_WITH_LEJP}")
-message(" LWS_WITH_LEJP_CONF = ${LWS_WITH_LEJP_CONF}")
-message(" LWS_WITH_SMTP = ${LWS_WITH_SMTP}")
-message(" LWS_WITH_GENERIC_SESSIONS = ${LWS_WITH_GENERIC_SESSIONS}")
-message(" LWS_STATIC_PIC = ${LWS_STATIC_PIC}")
-message(" LWS_WITH_RANGES = ${LWS_WITH_RANGES}")
-message(" LWS_PLAT_OPTEE = ${LWS_PLAT_OPTEE}")
-message(" LWS_WITH_ESP32 = ${LWS_WITH_ESP32}")
-message(" LWS_WITH_ZIP_FOPS = ${LWS_WITH_ZIP_FOPS}")
-message(" LWS_AVOID_SIGPIPE_IGN = ${LWS_AVOID_SIGPIPE_IGN}")
-message(" LWS_WITH_STATS = ${LWS_WITH_STATS}")
-message(" LWS_WITH_SOCKS5 = ${LWS_WITH_SOCKS5}")
-message(" LWS_HAVE_SYS_CAPABILITY_H = ${LWS_HAVE_SYS_CAPABILITY_H}")
-message(" LWS_HAVE_LIBCAP = ${LWS_HAVE_LIBCAP}")
-message(" LWS_WITH_PEER_LIMITS = ${LWS_WITH_PEER_LIMITS}")
-message(" LWS_HAVE_ATOLL = ${LWS_HAVE_ATOLL}")
-message(" LWS_HAVE__ATOI64 = ${LWS_HAVE__ATOI64}")
-message(" LWS_HAVE_STAT32I64 = ${LWS_HAVE_STAT32I64}")
-message(" LWS_HAS_INTPTR_T = ${LWS_HAS_INTPTR_T}")
-message(" LWS_WITH_EXPORT_LWSTARGETS = ${LWS_WITH_EXPORT_LWSTARGETS}")
-message(" LWS_WITH_ABSTRACT = ${LWS_WITH_ABSTRACT}")
-
-message("---------------------------------------------------------------------")
-
-# These will be available to parent projects including libwebsockets using add_subdirectory()
-set(LIBWEBSOCKETS_LIBRARIES ${LWS_LIBRARIES} CACHE STRING "Libwebsocket libraries")
-if (LWS_WITH_STATIC)
-       set(LIBWEBSOCKETS_LIBRARIES_STATIC websockets CACHE STRING "Libwebsocket static library")
-endif()
-if (LWS_WITH_SHARED)
-       set(LIBWEBSOCKETS_LIBRARIES_SHARED websockets_shared CACHE STRING "Libwebsocket shared library")
-endif()
 
-if (LWS_WITH_MINIMAL_EXAMPLES)
-       MACRO(SUBDIRLIST result curdir)
-         FILE(GLOB children RELATIVE ${curdir} ${curdir}/*)
-         SET(dirlist "")
-
-         FOREACH(child ${children})
-           IF(IS_DIRECTORY ${curdir}/${child})
-               LIST(APPEND dirlist ${child})
-           ENDIF()
-         ENDFOREACH()
-
-         SET(${result} ${dirlist})
-       ENDMACRO()
-
-       SUBDIRLIST(SUBDIRS "${PROJECT_SOURCE_DIR}/minimal-examples")
-       FOREACH(subdir ${SUBDIRS})
-
-               SUBDIRLIST(SUBDIRS2 "${PROJECT_SOURCE_DIR}/minimal-examples/${subdir}")
-               FOREACH(subdir2 ${SUBDIRS2})
-                       if (EXISTS "${PROJECT_SOURCE_DIR}/minimal-examples/${subdir}/${subdir2}/CMakeLists.txt")
-                               message("Processing ${PROJECT_SOURCE_DIR}/minimal-examples/${subdir}/${subdir2}")
-                               add_subdirectory("${PROJECT_SOURCE_DIR}/minimal-examples/${subdir}/${subdir2}")
-                       endif()
-               ENDFOREACH()
-       ENDFOREACH()
-ENDIF()
 
 # This must always be last!
 include(CPack)
diff --git a/LICENSE b/LICENSE
index 6c7cd90..917f8dc 100644 (file)
--- a/LICENSE
+++ b/LICENSE
-Libwebsockets and included programs are provided under the terms of the GNU
-Library General Public License (LGPL) 2.1, with the following exceptions:
+Libwebsockets and included programs are provided under the terms of the
+MIT license shown below, with the exception that some sources are under
+a similar permissive license like BSD, or are explicitly CC0 / public
+domain to remove any obstacles from basing differently-licensed code on
+them.
 
-1) Any reference, whether in these modifications or in the GNU
-Library General Public License 2.1, to this License, these terms, the
-GNU Lesser Public License,  GNU Library General Public License, LGPL, or
-any similar reference shall refer to the GNU Library General Public
-License 2.1 as modified by these paragraphs 1) through 4).
+Original liberal license retained:
 
-2) Static linking of programs with the libwebsockets library does not
-constitute a derivative work and does not require the author to provide 
-source code for the program, use the shared libwebsockets libraries, or
-link their program against a user-supplied version of libwebsockets.
+  - lib/misc/sha-1.c                     - 3-clause BSD license retained, link to original [BSD3]
+  - win32port/zlib                       - ZLIB license (see zlib.h) [ZLIB]
+  - lib/tls/mbedtls/wrapper              - Apache 2.0 (only built if linked against mbedtls) [APACHE2]
+    lib/tls/mbedtls/mbedtls-extensions.c
+  - lib/misc/base64-decode.c             - already MIT
+  - lib/misc/ieeehalfprecision.c         - 2-clause BSD license retained [BSD2]
 
-If you link the program to a modified version of libwebsockets, then the
-changes to libwebsockets must be provided under the terms of the LGPL in
-sections 1, 2, and 4.
+Relicensed to MIT:
 
-3) You do not have to provide a copy of the libwebsockets license with
-programs that are linked to the libwebsockets library, nor do you have to
-identify the libwebsockets license in your program or documentation as
-required by section 6 of the LGPL.
+  - lib/misc/daemonize.c               - relicensed from Public Domain to MIT,
+                                         link to original Public Domain version
+  - lib/plat/windows/windows-resolv.c  - relicensed from "Beerware v42" to MIT
 
-However, programs must still identify their use of libwebsockets. The
-following example statement can be included in user documentation to
-satisfy this requirement:
-
-"[program] is based in part on the work of the libwebsockets  project
-(https://libwebsockets.org)"
-
-4) Some sources included have their own, more liberal licenses, or options
-to get original sources with the liberal terms.
-
-Original liberal license retained
-
-  - lib/misc/sha-1.c    - 3-clause BSD license retained, link to original
-  - win32port/zlib      - ZLIB license (see zlib.h)
-  - lib/tls/mbedtls/wrapper - Apache 2.0 (only built if linked against mbedtls)
-
-Relicensed to libwebsocket license
-
-  - lib/misc/base64-decode.c - relicensed to LGPL2.1+SLE, link to original
-  - lib/misc/daemonize.c     - relicensed from Public Domain to LGPL2.1+SLE,
-                               link to original Public Domain version
-
-Public Domain (CC-zero) to simplify reuse
+Public Domain (CC-zero) to simplify reuse:
 
   - test-apps/*.c
   - test-apps/*.h
   - minimal-examples/*
   - lwsws/*
 
------- end of exceptions
-                  GNU LESSER GENERAL PUBLIC LICENSE
-                       Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL.  It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
-                            Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
-  This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it.  You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
-  When we speak of free software, we are referring to freedom of use,
-not price.  Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
-  To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights.  These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
-  For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you.  You must make sure that they, too, receive or can get the source
-code.  If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it.  And you must show them these terms so they know their rights.
-
-  We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
-  To protect each distributor, we want to make it very clear that
-there is no warranty for the free library.  Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-\f
-  Finally, software patents pose a constant threat to the existence of
-any free program.  We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder.  Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
-  Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License.  This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License.  We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
-  When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library.  The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom.  The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
-  We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License.  It also provides other free software developers Less
-of an advantage over competing non-free programs.  These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries.  However, the Lesser license provides advantages in certain
-special circumstances.
-
-  For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard.  To achieve this, non-free programs must be
-allowed to use the library.  A more frequent case is that a free
-library does the same job as widely used non-free libraries.  In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
-  In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software.  For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
-  Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.  Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library".  The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-\f
-                  GNU LESSER GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
-  A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
-  The "Library", below, refers to any such software library or work
-which has been distributed under these terms.  A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language.  (Hereinafter, translation is
-included without limitation in the term "modification".)
-
-  "Source code" for a work means the preferred form of the work for
-making modifications to it.  For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
-  Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it).  Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
-  1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
-  You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-\f
-  2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) The modified work must itself be a software library.
-
-    b) You must cause the files modified to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    c) You must cause the whole of the work to be licensed at no
-    charge to all third parties under the terms of this License.
-
-    d) If a facility in the modified Library refers to a function or a
-    table of data to be supplied by an application program that uses
-    the facility, other than as an argument passed when the facility
-    is invoked, then you must make a good faith effort to ensure that,
-    in the event an application does not supply such function or
-    table, the facility still operates, and performs whatever part of
-    its purpose remains meaningful.
-
-    (For example, a function in a library to compute square roots has
-    a purpose that is entirely well-defined independent of the
-    application.  Therefore, Subsection 2d requires that any
-    application-supplied function or table used by this function must
-    be optional: if the application does not supply it, the square
-    root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library.  To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License.  (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.)  Do not make any other change in
-these notices.
-\f
-  Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
-  This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
-  4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
-  If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library".  Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
-  However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library".  The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
-  When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library.  The
-threshold for this to be true is not precisely defined by law.
-
-  If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work.  (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
-  Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-\f
-  6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
-  You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License.  You must supply a copy of this License.  If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License.  Also, you must do one
-of these things:
-
-    a) Accompany the work with the complete corresponding
-    machine-readable source code for the Library including whatever
-    changes were used in the work (which must be distributed under
-    Sections 1 and 2 above); and, if the work is an executable linked
-    with the Library, with the complete machine-readable "work that
-    uses the Library", as object code and/or source code, so that the
-    user can modify the Library and then relink to produce a modified
-    executable containing the modified Library.  (It is understood
-    that the user who changes the contents of definitions files in the
-    Library will not necessarily be able to recompile the application
-    to use the modified definitions.)
-
-    b) Use a suitable shared library mechanism for linking with the
-    Library.  A suitable mechanism is one that (1) uses at run time a
-    copy of the library already present on the user's computer system,
-    rather than copying library functions into the executable, and (2)
-    will operate properly with a modified version of the library, if
-    the user installs one, as long as the modified version is
-    interface-compatible with the version that the work was made with.
-
-    c) Accompany the work with a written offer, valid for at
-    least three years, to give the same user the materials
-    specified in Subsection 6a, above, for a charge no more
-    than the cost of performing this distribution.
-
-    d) If distribution of the work is made by offering access to copy
-    from a designated place, offer equivalent access to copy the above
-    specified materials from the same place.
-
-    e) Verify that the user has already received a copy of these
-    materials or that you have already sent this user a copy.
-
-  For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it.  However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
-  It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system.  Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-\f
-  7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
-    a) Accompany the combined library with a copy of the same work
-    based on the Library, uncombined with any other library
-    facilities.  This must be distributed under the terms of the
-    Sections above.
-
-    b) Give prominent notice with the combined library of the fact
-    that part of it is a work based on the Library, and explaining
-    where to find the accompanying uncombined form of the same work.
-
-  8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License.  Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License.  However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-  9. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Library or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
-  10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-\f
-  11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded.  In such case, this License incorporates the limitation as if
-written in the body of this License.
-
-  13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation.  If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-\f
-  14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission.  For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this.  Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
-                            NO WARRANTY
-
-  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
-                     END OF TERMS AND CONDITIONS
-\f
-           How to Apply These Terms to Your New Libraries
-
-  If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change.  You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
-  To apply these terms, attach the following notices to the library.  It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the library's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Lesser General Public
-    License as published by the Free Software Foundation; either
-    version 2.1 of the License, or (at your option) any later version.
-
-    This library 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
-    Lesser General Public License for more details.
-
-    You should have received a copy of the GNU Lesser General Public
-    License along with this library; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the
-  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
-  <signature of Ty Coon>, 1 April 1990
-  Ty Coon, President of Vice
-
-That's all there is to it!
+Although libwebsockets is available under a permissive license, it does not
+change the reality of dealing with large lumps of external code... if your
+copy diverges it is guaranteed to contain security problems after a while
+and can be very painful to pick backports (especially since historically,
+we are very hot on cleaning and refactoring the codebase).  The least
+painful and lowest risk way remains sending your changes and fixes upstream
+to us so you can easily use later releases and fixes.
+
+## MIT License applied to libwebsockets
+
+https://opensource.org/licenses/MIT 
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to
+ deal in the Software without restriction, including without limitation the
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+## BSD2
+
+```
+ *  Redistribution and use in source and binary forms, with or without 
+ *  modification, are permitted provided that the following conditions are 
+ *  met:
+ *
+ *     * Redistributions of source code must retain the above copyright 
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright 
+ *       notice, this list of conditions and the following disclaimer in 
+ *       the documentation and/or other materials provided with the distribution
+ *      
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ *  POSSIBILITY OF SUCH DAMAGE.
+```
+
+## BSD3
+
+For convenience, a copy of the license on `./lib/misc/sha-1.c`.  In binary
+distribution, this applies to builds with ws support enabled, and without
+`LWS_WITHOUT_BUILTIN_SHA1` at cmake.
+
+```
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH
+```
+
+## ZLIB
+
+For convenience, a copy of the license on zlib.  In binary distribution,
+this applies for win32 builds with internal zlib only.  You can avoid
+building any zlib usage or copy at all with `-DLWS_WITH_ZLIB=0` (the
+default), and so avoid needing to observe the license for binary
+distribution that doesn't include the related code.
+
+```
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+```
+
+
+## APACHE2
+
+For convenience, a copy of the license on the mbedtls wrapper part.  In binary
+distribution, this applies only when building lws against mbedtls.
+
+The canonical license application to source files uses the URL reference, so the
+whole is not reproduced here.
+
+```
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+```
+
+## CC0
+
+For convenience,the full text of CC0 dedication found on the lws examples.
+The intention of this is to dedicate the examples to the public domain, so
+users can build off and modify them without any constraint.
+
+```
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
+
+    the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
+    moral rights retained by the original author(s) and/or performer(s);
+    publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
+    rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
+    rights protecting the extraction, dissemination, use and reuse of data in a Work;
+    database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
+    other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+    No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
+    Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
+    Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
+    Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
+```
+
index aa3ed30..552603f 100644 (file)
--- a/README.md
+++ b/README.md
-[![Travis Build Status](https://travis-ci.org/warmcat/libwebsockets.svg)](https://travis-ci.org/warmcat/libwebsockets) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/qfasji8mnfnd2r8t?svg=true)](https://ci.appveyor.com/project/lws-team/libwebsockets) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3576/badge.svg)](https://scan.coverity.com/projects/3576) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2266/badge)](https://bestpractices.coreinfrastructure.org/projects/2266) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/144fb195a83046e484a75c8b4c6cfc99)](https://www.codacy.com/app/lws-team/libwebsockets?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=warmcat/libwebsockets&amp;utm_campaign=Badge_Grade)
+[![CI status](https://libwebsockets.org/sai/status/libwebsockets)](https://libwebsockets.org/git/libwebsockets) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3576/badge.svg)](https://scan.coverity.com/projects/3576) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2266/badge)](https://bestpractices.coreinfrastructure.org/projects/2266) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/144fb195a83046e484a75c8b4c6cfc99)](https://www.codacy.com/app/lws-team/libwebsockets?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=warmcat/libwebsockets&amp;utm_campaign=Badge_Grade) [![Total alerts](https://img.shields.io/lgtm/alerts/g/warmcat/libwebsockets.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/warmcat/libwebsockets/alerts/) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/warmcat/libwebsockets.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/warmcat/libwebsockets/context:cpp) [![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/warmcat/libwebsockets.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/warmcat/libwebsockets/context:javascript)
 
 # Libwebsockets
 
-Libwebsockets is a simple-to-use, pure C library providing client and server
-for **http/1**, **http/2**, **websockets** and other protocols in a security-minded,
+Libwebsockets is a simple-to-use, MIT-license, pure C library providing client and server
+for **http/1**, **http/2**, **websockets**, **MQTT** and other protocols in a security-minded,
 lightweight, configurable, scalable and flexible way.  It's easy to build and
 cross-build via cmake and is suitable for tasks from embedded RTOS through mass
 cloud serving.
 
-[50 minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples) for
-various scenarios, CC0-licensed (public domain) for cut-and-paste, allow you to get started quickly.
+It supports a lot of lightweight ancilliary implementations for things like JSON,
+CBOR, JOSE, COSE, and supports OpenSSL and MbedTLS v2 and v3 out of the box for everything.
+It's very gregarious when it comes to event loop sharing, supporting libuv, libevent, libev,
+sdevent, glib and uloop, as well as custom event libs.
 
-![overview](./doc-assets/lws-overview.png)
-
-News
-----
-
-## V3.2 relase last planned LGPLv2.1+SLE release
-
-As foretold the v3.2 release is the last planned release that will have the code
-under LGPLv2.1+SLE.  Master has those parts changed to MIT license; the pieces
-that were CC0 or another liberal license remain the same.
-
-## License change plan
-
-Lws is planning to change the pieces that are currently LGPLv2.1+SLE to MIT
-https://opensource.org/licenses/MIT .  Stuff that is already CC0 or another
-permissive license will stay as it is.
-
-This license change is making an already permissive license (it was already LGPL,
-and the SLE removed most restrictions already) even more permissive.
-So I expect most contributors either don't much care or are happy about it.
-Contributors who object should contact me via:
-
- - the lws mailing list https://libwebsockets.org/mailman/listinfo/libwebsockets
- - github issue https://github.com/warmcat/libwebsockets , or
- - email to `andy@warmcat.com`
-
-...before **Aug 11 2019**, and I'll rewrite the related code before the change.
-There'll be a last release of the currently-licensed stuff (probably v3.2) and
-then the same code will have the licese grant changed in the sources, become
-master and also have an otherwise identical release, probably v4.0.  The v3.2
-stuff won't be maintained (by me anyway... it's FOSS though) but the v4.0
-stuff which is the same except the license will get the usual v4.0-stable
-treatment.
-
-Even after the change I will continue to rely on users to help me with bug
-reports and patches, work together on new features.  The license will no
-longer require it but the practical advantages from staying aligned with
-upstream lws for users remain the same.
-
-## New features on master
-
- - `LWS_WITH_NETWORK` cmake option (default on) allows one-step removal of vhost,
-   wsi, roles, event loop and all network-related code from the build.  This
-   enables use-cases where you actually need unrelated features like JOSE or FTS
-   compactly.  lws_context still exists and if tls is enabled, the tls-related code
-   is still built so the crypto is available, just nothing related to network.
-
- - New Crypto-agile APIs + JOSE / JWS / JWE / JWK support... apis work exactly
-   the same with OpenSSL or mbedTLS tls library backends, and allow key cycling
-   and crypto algorithm changes while allowing for grace periods
-
-   [README.crypto-apis](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.crypto-apis.md)
-
- - CMake config simplification for crypto: `-DLWS_WITH_GENCRYPTO=1` for all
-   generic cipher and hash apis built (which work the same on mbedtls and
-   OpenSSL transparently), and `-DLWS_WITH_JOSE=1` for all JOSE, JWK, JWS
-   and JWE support built (which use gencrypto and so also work the same
-   regardless of tls library backend).
-
- - **`x.509`** - new generic x509 api allows PEM-based certificate and key
-   trust relationship verification, and conversion between x.509 keys and
-   JWK.  Works for EC and RSA keys, and on mbedtls and OpenSSl the same.
-
-   [x.509 api](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-x509.h), 
-   [x.509 minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-x509)
-
- - **`JWE`** - JWE (RFC7516) Algorithms with CI tests:
-
-|Key Encryption|Payload authentication + crypt|Enc + Dec Support|
-|---|---|---|
-|`RSAES-PKCS1-v1.5` 2048b & 4096b|`AES_128_CBC_HMAC_SHA_256`|Enc + Dec|
-|`RSAES-PKCS1-v1.5` 2048b|`AES_192_CBC_HMAC_SHA_384`|Enc + Dec|
-|`RSAES-PKCS1-v1.5` 2048b|`AES_256_CBC_HMAC_SHA_512`|Enc + Dec|
-|`RSAES-OAEP`|`AES_256_GCM`|Enc + Dec|
-|`AES128KW`, `AES192KW`, `AES256KW`|`AES_128_CBC_HMAC_SHA_256`|Enc + Dec|
-|`AES128KW`, `AES192KW`, `AES256KW`|`AES_192_CBC_HMAC_SHA_384`|Enc + Dec|
-|`AES128KW`, `AES192KW`, `AES256KW`|`AES_256_CBC_HMAC_SHA_512`|Enc + Dec|
-|`ECDH-ES` (P-256/384/521 key)|`AES_128/192/256_GCM`|Enc + Dec|
-|`ECDH-ES+A128/192/256KW` (P-256/384/521 key)|`AES_128/192/256_GCM`|Enc + Dec|
-
-All tests pass on both OpenSSL and mbedTLS backends, using keys generated on
-both OpenSSL and mbedTLS in the tests.
-
-A minimal example tool shows how to encrypt and decrypt compact JWE objects
-from the commandline for all supported algorithms.
-
-   [jwe api](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jwe.h), 
-   [jwe unit tests](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-jose/jwe.c), 
-   [jwe minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwe)
-
- - **`lws-genec` ECDSA** - JWS-compatible ECDSA is supported on both OpenSSL and mbedtls.
-
- - **`JWS`** - JWS (RFC7515) is now supported for none, HS256/384/512, RS256/384/512, and ES256/384/512, on both OpenSSL and mbedtls.  There's a minimal example tool that signs and verifies compact
- representation JWS from stdin.
-   [jws api](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jws.h), 
-   [jws unit tests](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-jose/jws.c), 
-   [jws minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwe)
-
- - **`JWK`** - JWK (RFC7517) now supports oct, RSA and EC keys including JSON key
-   arrays on both OpenSSL and mbedtls.  A minimal example tool shows how to create
-   new JSON JWK keys to specified parameters from the commandline for all supported
-   ciphers.
-
-   [jwk minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwk)
-
- - **`lws-genrsa` OAEP + PSS support** - in addition to PKCS#1 1.5 padding, OAEP and PSS are
-   now supported on both mbedtls and openssl backends.
+[100+ independent minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples) for various scenarios, CC0-licensed
+(public domain) for cut-and-paste, allow you to get started quickly.
 
- - **`lws-genaes` Generic AES crypto** - thin api layer works identically with both mbedtls and openssl
-   backends.  Supports CBC, CFB128, CFB8, CTR, ECB, OFB, XTS and GCM variants.  Unit tests in CI.
-   [genaes api](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genaes.h),
-   [api test](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-gencrypto),
-   CMake config: `-DLWS_WITH_GENCRYPTO=1`
+[There are a lot of READMEs](https://libwebsockets.org/git/libwebsockets/tree/READMEs) on a variety of topics.
 
- - **http fallback support** - you can specify a role and protocol to apply if non-http or non-tls
-   packets arrive at an http(s) listen port.  For example, you can specify that the new `raw proxy`
-   role + protocol should be used, to proxy your sshd port over :443 or :80.  Without affecting
-   normal http(s) serving on those ports but allowing, eg, `ssh -p 443 invalid@libwebsockets.org`.
-   [http fallback docs](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.http-fallback.md)
+[We do a huge amount of CI testing per push](https://libwebsockets.org/sai/), currently 582 builds on 30 platforms.
+[You can see the lws CI rack and read about how lws-based Sai is used to coordinate all the testing](https://warmcat.com/2021/08/21/Sai-CI.html).
 
- - **raw tcp proxy role and protocol** - adding raw tcp proxying is now trivial using the built-in lws
-   implementation.  You can control the onward connection using a pvo in the format "ipv4:server.com:port"
-   [raw proxy minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/raw/minimal-raw-proxy),
-   [raw proxy docs](https://libwebsockets.org/git/libwebsockets/tree/plugins/raw-proxy),
-   Cmake config: `-DLWS_ROLE_RAW_PROXY=1 -DLWS_WITH_PLUGINS=1`
-
- - **deaddrop HTML file upload protocol** - protocol and minimal example for file upload and sharing using
-   drag and drop and a file picker.  Integrated with basic auth, uploaded files marked with upload user,
-   and files owned by the authenticated user may be deleted via the UI.  Supports multiple simultaneous
-   uploads both by drag-and-drop and from the file picker.
-   [deaddrop minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/http-server/minimal-http-server-deaddrop)
-
- - **basic auth for ws(s)** - You can apply basic auth credential requirement to ws connections same
-   as on mounts now.  Just add a pvo "basic-auth" with the value being the credentials file path when
-   enabling the ws protocol for the vhost.
-
-## v3.1 released: new features in v3.1
-
- - **lws threadpool** - lightweight pool of pthreads integrated to lws wsi, with all
-   synchronization to event loop handled internally, queue for excess tasks
-   [threadpool docs](https://libwebsockets.org/git/libwebsockets/tree/lib/misc/threadpool), 
-   [threadpool minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/ws-server/minimal-ws-server-threadpool), 
-   Cmake config: `-DLWS_WITH_THREADPOOL=1`
-
- - **libdbus support** integrated on lws event loop
-   [lws dbus docs](https://libwebsockets.org/git/libwebsockets/tree/lib/roles/dbus), 
-   [lws dbus client minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/dbus-client), 
-   [lws dbus server minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/dbus-server), 
-   Cmake config: `-DLWS_ROLE_DBUS=1`
-
- - **lws allocated chunks (lwsac)** - helpers for optimized mass allocation of small
-   objects inside a few larger malloc chunks... if you need to allocate a lot of
-   inter-related structs for a limited time, this removes per-struct allocation
-   library overhead completely and removes the need for any destruction handling
-   [lwsac docs](https://libwebsockets.org/git/libwebsockets/tree/lib/misc/lwsac), 
-   [lwsac minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-lwsac), 
-   Cmake Config: `-DLWS_WITH_LWSAC=1`
-
- - **lws tokenizer** - helper api for robustly tokenizing your own strings without
-   allocating or adding complexity.  Configurable by flags for common delimiter
-   sets and comma-separated-lists in the tokenizer.  Detects and reports syntax
-   errors.
-   [lws_tokenize docs](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-tokenize.h), 
-   [lws_tokenize minimal example / api test](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-lws_tokenize)
-
- - **lws full-text search** - optimized trie generation, serialization,
-   autocomplete suggestion generation and instant global search support extensible
-   to huge corpuses of UTF-8 text while remaining super lightweight on resources.
-   [full-text search docs](https://libwebsockets.org/git/libwebsockets/tree/lib/misc/fts), 
-   [full-text search minimal example / api test](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-fts), 
-   [demo](https://libwebsockets.org/ftsdemo/), 
-   [demo sources](https://libwebsockets.org/git/libwebsockets/tree/plugins/protocol_fulltext_demo.c), 
-   Cmake config: `-DLWS_WITH_FTS=1 -DLWS_WITH_LWSAC=1`
-
- - **gzip + brotli http server-side compression** - h1 and h2 detection of client support
-   for server compression, and auto-application to files with mimetypes "text/*",
-   "application/javascript" and "image/svg.xml".
-   Cmake config: `-DLWS_WITH_HTTP_STREAM_COMPRESSION=1` for gzip, optionally also give
-   `-DLWS_WITH_HTTP_BROTLI=1` for preferred `br` brotli compression
-
- - **managed disk cache** - API for managing a directory containing cached files
-   with hashed names, and automatic deletion of LRU files once the cache is
-   above a given limit.
-   [lws diskcache docs](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-diskcache.h), 
-   Cmake config: `-DLWS_WITH_DISKCACHE=1`
-
- - **http reverse proxy** - lws mounts support proxying h1 or h2 requests to
-   a local or remote IP, or unix domain socket over h1.  This allows microservice
-   type architectures where parts of the common URL space are actually handled
-   by external processes which may be remote or on the same machine.
-   [lws gitohashi serving](https://libwebsockets.org/git/) is handled this way.
-   [unix domain sockets reverse proxy docs](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.unix-domain-reverse-proxy.md), 
-   CMake config: `-DLWS_WITH_HTTP_PROXY=1` and `-DLWS_UNIX_SOCK=1` for Unix Domain Sockets
-
- - **update minimal examples for strict Content Security Policy** the minimal
-   examples now show the best practices around Content Security Policy and
-   disabling inline Javascript.  Updated examples that are served with the
-   recommended security restrictions show a new "Strict Content Security Policy"
-   graphic.  [Read how to upgrade your applications to use a strict CSP](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.content-security-policy.md).
-
- - **release policy docs** - unsure what branch, version or tag to use, or how
-   to follow master cleanly?  [Read the release policy docs](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.release-policy.md)
-   which explain how and why lws is developed, released and maintained.
-
-## v3.0.1 released
-
-See the git log for the list of fixes.
-
-## v3.0.0 released
-
-See the changelog for info https://libwebsockets.org/git/libwebsockets/tree/changelog?h=v3.0-stable
-
-## Major CI improvements for QA
-
-The Travis build of lws done on every commit now runs:
-
-Tests|Count|Explanation
----|---|---
-Build / Linux / gcc|16|-Wall -Werror cmake config variants
-Build / Mac / Clang|16|-Wall -Werror cmake config variants
-Build / Windows / MSVC|7|default
-Selftests|openssl:43, mbedtls:43|minimal examples built and run against each other and remote server
-attack.sh|225|Correctness, robustness and security tests for http parser
-Autobahn Server|480|Testing lws ws client, including permessage-deflate
-Autobahn Client|480|Testing lws ws server, including permaessage-deflate
-h2spec|openssl:146, mbedtls:146|Http/2 server compliance suite (in strict mode)
-h2load|openssl:6, mbedtls:6|Http/2 server load tool (checks 10K / 100K in h1 and h2, at 1, 10, 100 concurrency)
-h2load SMP|6|Http/2 and http/1.1 server load checks on SMP server build
-
-The over 1,500 tests run on every commit take 1hr 15 of compute time to complete.
-If any problems are found, it breaks the travis build, generating an email.
-
-Codacy also checks every patch and the information used to keep lws at zero issues.
-
-Current master is checked by Coverity at least daily and kept at zero issues.
-
-Current master passes all the tests and these new CI arrangements will help
-keep it that way.
-
-## Lws has the first official ws-over-h2 server support
-
-![wss-over-h2](./doc-assets/wss2.png)
+![overview](./doc-assets/lws-overview.png)
 
-There's a new [RFC](https://tools.ietf.org/html/rfc8441) that enables multiplexing ws connections
-over an http/2 link.  Compared to making individual tcp and tls connections for
-each ws link back to the same server, this makes your site start up radically
-faster, and since all the connections are in one tls tunnel, with considerable memory
-reduction serverside.
+News
+----
 
-To enable it on master you just need -DLWS_WITH_HTTP2=1 at cmake.  No changes to
-existing code are necessary for either http/2 (if you use the official header creation
-apis if you return your own headers, as shown in the test apps for several versions)
-or to take advantage of ws-over-h2.  When built with http/2 support, it automatically
-falls back to http/1 and traditional ws upgrade if that's all the client can handle.
+## v4.3 is released
 
-Currently only Chrome Canary v67 supports this ws-over-h2 encapsulation (chrome
-must be started with `--enable-websocket-over-http2` switch to enable it currently),
-and patches exist for Firefox.  Authors of both browser implementations tested
-against the lws server implementation.
+See the [changelog](https://libwebsockets.org/git/libwebsockets/tree/changelog)
 
-## New "minimal examples"
 
-https://libwebsockets.org/git/libwebsockets/tree/minimal-examples
+## Lws work retrospective
 
-These are like the test apps, but focus on doing one thing, the best way, with the
-minimum amount of code.  For example the minimal-http-server serves the cwd on
-http/1 or http/2 in 50 LOC.  Same thing with tls is just three more lines.
+The initial commit for lws will have been 11 years ago come Oct 28 2021, it's been a lot of work.
+There are a total of 4.3K patches, touching 800KLOC cumulatively (this is not the size in the
+repo, but over the years, how many source lines were changed by patches).
 
-They build standalone, so it's easier to copy them directly to start your own project; they
-are CC0 licensed (public domain) to facilitate that.
+![overview](./doc-assets/work.png)
 
-## Windows binary builds
+Gratifyingly, it turns out over the years, ~15% of that was contributed by 404 contributors: that's not so bad.
+Thanks a lot to everyone who has provided patches.
 
-32- and 64-bit Windows binary builds are available via Appveyor.  Visit
-[lws on Appveyor](https://ci.appveyor.com/project/lws-team/libwebsockets),
-click on a build, the ARTIFACTS, and unzip the zip file at `C:\Program Files (x86)/libwebsockets`.
+Today at least tens of millions of devices and product features rely on lws to
+handle their communications including several from FAANG; Google now include lws
+as part of Android sources.
 
 ## Support
 
@@ -303,5 +61,5 @@ You can get the latest version of the library from git:
 
 - https://libwebsockets.org/git
 
-Doxygen API docs for master: https://libwebsockets.org/lws-api-doc-master/html/index.html
+Doxygen API docs for development: https://libwebsockets.org/lws-api-doc-main/html/index.html
 
diff --git a/READMEs/README.async-dns.md b/READMEs/README.async-dns.md
new file mode 100644 (file)
index 0000000..64cbf34
--- /dev/null
@@ -0,0 +1,100 @@
+# Asynchronous DNS
+
+## Introduction
+
+Lws now features optional asynchronous, ie, nonblocking recursive DNS
+resolution done on the event loop, enable `-DLWS_WITH_SYS_ASYNC_DNS=1`
+at cmake to build it in.
+
+## Description
+
+The default libc name resolution is via libc `getaddrinfo()`, which is
+blocking, possibly for quite long periods (seconds).  If you are
+taking care about latency, but want to create outgoing connections,
+you can't tolerate this exception from the rule that everything in
+lws is nonblocking.
+
+Lws' asynchronous DNS resolver creates a caching name resolver
+that directly queries the configured nameserver itself over UDP,
+from the event loop.
+
+It supports both ipv4 / A records and ipv6 / AAAA records (see later
+for a description about how).  One server supported over UDP :53,
+and the nameserver is autodicovered on linux, windows, and freertos.
+    
+Other features
+
+ - lws-style paranoid response parsing
+ - random unique tid generation to increase difficulty of poisoning
+ - it's really integrated with the lws event loop, it does not spawn
+   threads or use the libc resolver, and of course no blocking at all
+ - platform-specific server address capturing (from /etc/resolv.conf
+   on linux, windows apis on windows)
+ - LRU caching
+ - piggybacking (multiple requests before the first completes go on
+    a list on the first request, not spawn multiple requests)
+ - observes TTL in cache
+ - TTL and timeout use `lws_sul` timers on the event loop
+ - Uses CNAME resolution inside the same response if present, otherwise
+   recurses to resolve the CNAME (up to 3 deep)
+ - ipv6 pieces only built if cmake `LWS_IPV6` enabled
+
+## Api
+
+If enabled at cmake, the async DNS implementation is used automatically
+for lws client connections.  It's also possible to call it directly, see
+the api-test-async-dns example for how.
+
+The Api follows that of `getaddrinfo()` but results are not created on
+the heap.  Instead a single, const cached copy of the addrinfo struct
+chain is reference-counted, with `lws_async_dns_freeaddrinfo()` provided
+to deduct from the reference count.  Cached items with a nonzero
+reference count can't be destroyed from the cache, so it's safe to keep
+a pointer to the results and iterate through them.
+
+## Dealing with IPv4 and IPv6
+
+DNS is a very old standard that has some quirks... one of them is that
+multiple queries are not supported in one packet, even though the protocol
+suggests it is.  This creates problems on ipv6 enabled systems, where
+it may prefer to have AAAA results, but the server may only have A records.
+
+To square the circle, for ipv4 only systems (`LWS_IPV6=0`) the resolver
+requests only A records.  For ipv6-capable systems, it always requests
+first A and then immediately afterwards AAAA records.
+
+To simplify the implementation, the tid b0 is used to differentiate
+between A (b0 = 0) and AAAA (b0 = 1) requests and responses using the
+same query body.
+
+The first response to come back is parsed, and a cache entry made...
+it leaves a note in the query about the address of the last `struct addrinfo`
+record.  When the second response comes, a second allocation is made,
+but not added to the logical cache... instead it's chained on to the
+first cache entry and the `struct addrinfo` linked-list from the
+first cache entry is extended into the second one.  At the time the
+second result arrives, the query is destroyed and the cached results
+provided on the result callback.
+
+## Recursion
+
+Where CNAMEs are returned, DNS servers may take two approaches... if the
+CNAME is also resolved by the same server and so it knows what it should
+resolve to, it may provide the CNAME resolution in the same response
+packet.
+
+In the case the CNAME is actually resolved by a different name server,
+the server with the CNAME does not have the information to hand to also
+resolve the CNAME in the same response.  So it just leaves it for the
+client to sort out.
+
+The lws implementation can deal with both of these, first it "recurses"
+(it does not recurse on the process stack but uses its own manual stack)
+to look for results in the same packet that told it about the CNAME.  If
+there are no results, it resets the query to look instead for the CNAME,
+and restarts it.  It allows this to happen for 3 CNAME deep.
+
+At the end, either way, the cached result is set using the original
+query name and the results from the last CNAME in the chain.
+
+
diff --git a/READMEs/README.build-android.md b/READMEs/README.build-android.md
new file mode 100644 (file)
index 0000000..be7a980
--- /dev/null
@@ -0,0 +1,77 @@
+# Building for Android NDK
+
+If you have the ndk and prebuilt toolchains with that, you can simply build
+lws library for your android app from one cmake and one make command.
+
+However if you want a tls lib, you have to take care of building and pointing
+to that first.  But if it's a cmake project like mbedtls, that also is just a
+matter of one cmake and one make.
+
+## Installing NDK pieces
+
+There's probably a more direct way but the official way is install the whole
+Android Studio and then run `sdkmanager` to install a recent NDK.
+
+I installed the sdk and ndk pieces into /opt/android/ and that's how the
+`./contrib/cross-aarch64-android.cmake` toolchain file is shipped.  You can
+adapt some settings at the top of that file including the path if needed.
+
+## Fetching lws (needed first for cross toolchain file)
+
+It doesn't care where you put these projects, but for simplicity they should
+be in the same parent dir, like
+
+```
+ - /home/someone
+  - /home/someone/libwebsockets
+  - /home/someone/mbedtls
+```
+
+The reason is that building mbedtls need the cross toolchain file from
+libwebsockets, that's also why we have to get libwebsockets first now but
+build it later.
+
+```
+$ git clone https://libwebsockets.org/repo/libwebsockets
+```
+
+## Building mbedtls
+
+```
+$ git clone https://github.com/ARMmbed/mbedtls.git
+$ cd mbedtls
+$ mkdir build
+$ cd build
+$ rm -f CMakeCache.txt && \
+  cmake .. -DCMAKE_TOOLCHAIN_FILE=../libwebsockets/contrib/cross-aarch64-android.cmake \
+  -DUSE_SHARED_MBEDTLS_LIBRARY=1 \
+  -DENABLE_PROGRAMS=0 \
+  -Wno-dev && \
+  make -j && \
+  cmake --install .
+```
+
+The lws toolchain file sets the path to install into as the cross root path, so
+despite it looks like the destination dir is missing for the install, it will
+go into, eg `/opt/android/ndk/21.1.6352462/platforms/android-24/arch-arm64/lib/libmbedcrypto.a`
+where lws will look for it
+
+## Building lws
+
+You don't need to explain where mbedtls can be found... lws will build with the
+same toolchain file that sets the cross root to the same place as mbedtls, it
+will easily find them there without any further hints.
+
+```
+$ mkdir build
+$ cd build
+$ rm -f CMakeCache.txt && \
+  cmake .. -DCMAKE_TOOLCHAIN_FILE=../libwebsockets/contrib/cross-aarch64-android.cmake \
+  -DLWS_WITH_MBEDTLS=1 \
+  -DLWS_WITHOUT_TESTAPPS=1 && \
+  make && \
+  cmake --install .
+```
+
+That's it, both mbedtls and lws library and header files are installed into the
+ndk cross root.
diff --git a/READMEs/README.build-windows.md b/READMEs/README.build-windows.md
new file mode 100644 (file)
index 0000000..e9d7a23
--- /dev/null
@@ -0,0 +1,214 @@
+# Some notes for the windows jungle
+
+This was how I compiled libwebsockets starting from a blank windows install
+in March - April 2020.  Doing this on a linux distro is way simpler and quicker
+than all this!
+
+## Notes on vm installation
+
+### Disk size
+
+For building you'll need 40GB+ available for the guest storage.
+
+### Required: Windows product key
+
+Assuming like me the first thing you do with a new laptop is install Linux over
+the windows it came with, you can recover your 'windows tax' windows product key
+from your device typically using `sudo strings /sys/firmware/acpi/tables/MSDM`,
+and use that for your VM install.
+
+### Required: Spice guest 
+
+To have shared clipboard, and for windows video driver to match your vm window
+resolution, you must install spice guest tools inside the windows VM.  It also
+installs some virtio pieces you will want.
+
+https://www.spice-space.org/download/windows/spice-guest-tools/spice-guest-tools-latest.exe
+
+### Blood-pressure reduction: Firefox
+
+https://www.mozilla.org/en-US/exp/firefox/
+
+When it's up, add-ons: ublock origin, privacy badger, noscript, disable search
+bar prediction
+
+### Blood-pressure reduction: Clink
+
+This is a hack on cmd.exe that lets it understand Ctrl-R and fixup unix-style
+slashes automagically.
+
+https://github.com/mridgers/clink/releases/download/0.4.9/clink_0.4.9_setup.exe
+
+If you're usually using *nix, you definitely need this to keep your sanity.
+
+### Required: cmake
+
+CMake have a windows installer thing downloadable from here
+
+[cmake](https://cmake.org/download/)
+
+after that you can use `cmake` from the terminal OK.
+
+### Required: git
+
+Visit the canonical git site to download their windows installer thing
+
+[git](https://git-scm.com/download/win)
+
+**Select the install option for "extra unix commands"** so you can get `ls -l`,
+`cp`, `mv` and suchlike working in cmd.exe... that's awesome, thanks git!
+
+Afterwards you can just use `git` as normal from cmd.exe as well.
+
+### Required: Install the "free" "community" visual studio
+
+You can do this through "windows store" by searching for "visual studio"
+
+I installed as little as possible, we just want the C "C++" tools... 7GB :-)
+
+It still wouldn't link without the "mt" helper tool from the
+huge windows SDK, so you have to install GB of that as well.
+
+They don't mention it during the install, but after 30 days this "free"
+"community" edition demands you open a microsoft account or it stops working.
+In the install they give you the option to add a microsoft account and the
+alternative is, "not now, maybe later".  Compare and contrast to gcc or git or
+the other FOSS projects.
+
+### Required: OpenSSL
+
+Ugh... I tried using prebuilts but it's unreliable and needs an unfeasible
+amount of trust.  So I recommend bite the bullet and build your own... that's
+trivial on Linux but of course windows makes everything nasty.
+
+At least hopefully all the "research" is done and listed out here.
+
+#### OpenSSL build Prerequisite: install perl binary
+
+Move the git version of perl out of the way, it won't work for OpenSSL build
+
+```
+mv /usr/bin/perl /usr/bin/perl-git
+```
+
+For windows, OpenSSL "recommends" ActiveState perl but it doesn't work for me,
+complaining about stuff needed from cpan and then dying when it was installed.
+"Strawberry Perl" is installed in `C:\Strawberry` and worked out the box.
+
+http://strawberryperl.com/download/5.30.2.1/strawberry-perl-5.30.2.1-64bit.msi
+
+The installer sets up `%PATH%` if you open a new cmd window.  
+
+#### OpenSSL build Prerequisite: NASM
+
+Go here and click on the latest stable, download the win32 .exe
+
+https://nasm.us/
+
+Just install via the defaults.  Then add it to the PATH temporarily...
+
+```
+$ set PATH=%PATH%;C:\Program Files (x86)\NASM
+```
+
+#### OpenSSL build setup: source VC env vars
+
+These fix up the PATH and include dirs etc necessary for VC build in the cmd
+window.
+
+```
+$ call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64
+```
+
+### OpenSSL build:
+
+Grab openssl from git... assuming the prerequisites above went well it will
+just sit there building for 30 minutes or whatever.
+
+```
+$ git clone https://github.com/openssl/openssl
+$ cd openssl
+$ perl Configure VC-WIN64A
+$ nmake
+```
+
+Afterwards, open an Administrator mode cmd.exe, redo the msvc path and then
+install the build.
+
+```
+$ cd openssl
+$ call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64
+$ nmake install
+```
+
+Oh another grindingly slow windows build action.  Finally it's in there in
+`C:\Program Files\OpenSSL`.
+
+libraries are looking for a cert bundle at "C:\Program Files\Common Files\SSL\cert.pem"...
+it's not documented or included in the zip file from the above, so...
+
+#### Installing a cert bundle
+
+You can get a trusted cert bundle from here
+
+[drwetter/testssl cert bundle](https://raw.githubusercontent.com/drwetter/testssl.sh/3.1dev/etc/Microsoft.pem)
+
+Save it into `C:\Program Files\Common Files\SSL\cert.pem` where openssl will be able to see it.
+
+## Required: pthreads
+
+It's amazing but after all these years windows doesn't offer pthreads compatibility
+itself.  Just like the many other missing POSIX bits like fork().
+
+I downloaded the latest (2012) zip release of pthreads-win32 from here
+
+ftp://sourceware.org/pub/pthreads-win32
+
+Then I created a dir "C:\Program Files (x86)\pthreads", and copied the `dll`,
+`include` and `lib` subdirs from the `prebuilt` folder in the zip there.
+
+The cmake incantation to build against pthreads set up like that is
+
+```
+ $ cmake .. -DLWS_HAVE_PTHREAD_H=1 -DLWS_EXT_PTHREAD_INCLUDE_DIR="C:\Program Files (x86)\pthreads\include" -DLWS_EXT_PTHREAD_LIBRARIES="C:\Program Files (x86)\pthreads\lib\x64\libpthreadGC2.a" -DLWS_WITH_MINIMAL_EXAMPLES=1
+```
+
+## Building libwebsockets
+
+We'll clone libwebsockets then use cmake to build via vs tools
+
+```
+> git clone https://libwebsockets.org/repo/libwebsockets
+> cd libwebsockets
+> mkdir build
+> cd build
+> cmake ..
+> cmake --build . --config DEBUG
+```
+
+Installing requires admin privs, I opened a second cmd window as admin and did it
+there.
+
+```
+> cmake --install . --config DEBUG
+```
+
+### Hack the libs into view
+
+The libs we built against aren't visible in the system, I don't know what
+Real Windows Programmers are supposed to do about that, but I used an Admin cmd
+prompt to copy them into C:\windows\system32
+
+```
+$ cp "C:\Program Files (x86)\pthreads\dll\x64\pthreadGC2.dll" "C:\Program Files\OpenSSL\bin\libcrypto-3.dll"  "C:\Program Files\OpenSSL\bin\libssl-3.dll" C:\Windows\system32
+```
+
+After that you can run the test apps OK, eg
+
+```
+$ libwebsockets-test-server.exe -s
+```
+
+## Note about using paths with spaces in with cmake
+
+
index 17044f6..0b3db34 100644 (file)
@@ -1,6 +1,15 @@
 Notes about building lws
 ========================
 
+You can download and install lws using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
+```
+git clone https://github.com/microsoft/vcpkg.git
+cd vcpkg
+./bootstrap-vcpkg.sh
+./vcpkg integrate install
+vcpkg install libwebsockets
+```
+The lws port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg/) on the vcpkg repository.
 
 @section cm Introduction to CMake
 
@@ -536,7 +545,7 @@ All "foreign" cross-built binaries are sent into `/tmp/cross` so they cannot be
 
 1) `cd /tmp`
 
-2) `wget -O mytoolchainfile https://raw.githubusercontent.com/warmcat/libwebsockets/master/contrib/cross-arm-linux-gnueabihf.cmake` 
+2) `wget -O mytoolchainfile https://raw.githubusercontent.com/warmcat/libwebsockets/main/contrib/cross-arm-linux-gnueabihf.cmake` 
 
 3) Edit `/tmp/mytoolchainfile` adapting `CROSS_PATH`, `CMAKE_C_COMPILER` and `CMAKE_CXX_COMPILER` to reflect your toolchain install dir and path to your toolchain C and C++ compilers respectively.  For my case:
 
diff --git a/READMEs/README.captive-portal-detection.md b/READMEs/README.captive-portal-detection.md
new file mode 100644 (file)
index 0000000..ceab7b4
--- /dev/null
@@ -0,0 +1,88 @@
+# Captive Portal Detection
+
+## Background
+
+Wifi devices may face some interception of their connection to the
+internet, it's very common for, eg, coffee shop wifi to present some
+kind of login or other clickthrough before access to the Internet is
+granted.  Devices may need to understand that they are in this
+situation, and there are several different techniques for trying to
+gague it.
+
+Sequence-wise the device has been granted a DHCP lease and has been
+configured with DNS, but the DNS may be wrongly resolving everything
+to an address on the LAN or a portal on the net.
+
+Whether there is a captive portal active should be a sticky state for a given
+connection if there is not going to be any attempt to login or pass the landing
+page, it only needs checking for after DHCP acquisition then.  If there will be
+an attempt to satisfy the landing page, the test should be repeated after the
+attempt.
+
+## Detection schemes
+
+The most popular detection scheme by numbers is Android's method,
+which is to make an HTTP client GET to `http://connectivitycheck.android.com/generate_204`
+and see if a 204 is coming back... if intercepted, typically there'll be a
+3xx redirect to the portal, perhaps on https.  Or, it may reply on http with
+a 200 and show the portal directly... either way it won't deliver a 204
+like the real remote server does.
+
+Variations include expecting a 200 but with specific http body content, and
+doing a DNS lookup for a static IP that the device knows; if it's resolved to
+something else, it knows there's monkey business implying a captive portal.
+
+Other schemes involve https connections going out and detecting that the cert
+of the server it's actually talking to doesn't check out, although this is
+potentially ambiguous.
+
+Yet more methods are possible outside of tcp or http.
+
+## lws captive portal detect support
+
+lws provides a generic api to start captive portal detection...
+
+```
+LWS_EXTERN LWS_VISIBLE int
+lws_system_cpd_start(struct lws_context *context);
+```
+
+and two states in `lws_system` states to trigger it from, either
+`LWS_SYSTATE_CPD_PRE_TIME` which happens after DHCP acquisition but before
+ntpclient and is suitable for non https-based scheme where the time doesn't
+need to be known, or the alternative `LWS_SYSTATE_CPD_POST_TIME` state which
+happens after ntpclient has completed and we know the time.
+
+The actual platform implementation is set using `lws_system_ops_t` function
+pointer `captive_portal_detect_request`, ie
+
+```
+       int (*captive_portal_detect_request)(struct lws_context *context);
+       /**< Check if we can go out on the internet cleanly, or if we are being
+        * redirected or intercepted by a captive portal.
+        * Start the check that proceeds asynchronously, and report the results
+        * by calling lws_captive_portal_detect_result() api
+        */
+```
+
+User platform code can provide this to implement whatever scheme they want, when
+it has arrived at a result, it can call the lws api `lws_system_cpd_result()` to
+inform lws.  If there isn't any captive portal, this will also try to advance the
+system state towards OPERATIONAL.
+
+```
+/**
+ * lws_system_cpd_result() - report the result of the captive portal detection
+ *
+ * \param context: the lws_context
+ * \param result: one of the LWS_CPD_ constants representing captive portal state
+ * \param redirect_url: NULL, or the url we were redirected to if result is
+ *     LWS_CPD_HTTP_REDIRECT
+ *
+ * Sets the context's captive portal detection state to result.  User captive
+ * portal detection code would call this once it had a result from its test.
+ */
+LWS_EXTERN LWS_VISIBLE int
+lws_system_cpd_result(struct lws_context *context, int result, const char *redirect_url);
+```
+
diff --git a/READMEs/README.cbor-cose.md b/READMEs/README.cbor-cose.md
new file mode 100644 (file)
index 0000000..baa9d7d
--- /dev/null
@@ -0,0 +1,272 @@
+# RFC8152 COSE apis
+
+|||
+|---|---|---|
+|cmake| `LWS_WITH_COSE`|
+|Header| ./include/libwebsockets/lws-cose.h|
+|api-test| ./minimal-examples/api-tests/api-test-cose/|
+|README| ./READMEs/README.cbor-cose.md
+
+COSE is the CBOR equivalent of the JOSE suite of crypto objects and operations.
+You can represent public and private EC, RSA and SYMMETRIC keys, and sets of
+keys of various types; import the logical keys to and from CBOR; and sign /
+verify and encrypt / decrypt payloads using structured CBOR.  Key generation is
+also supported.
+
+|type|operations|algs|
+|---|---|---|
+|lws_cose_key_t|import, export, generation|EC / RSA / SYMMETRIC|
+|cose_sign1|sign, validate|ES256/384/512, RS256/384/512|
+|cose_sign|sign, validate|ES256/384/512, RS256/384/512|
+|cose_mac0|sign, validate|HS256/HS256_64/384/512|
+|cose_mac|validate only|HS256/HS256_64/384/512|
+
+The lws COSE support uses the lws gencrypto layer, which calls through to the
+tls crypto library, and so works on both OpenSSL and mbedTLS the same.
+
+An increasing number of higher-level IETF specifications use COSE underneath.
+
+## cose_key and sets
+
+Lws provides an `lws_cose_key_t` object to contain a single key's metadata and
+key material for EC, RSA and SYMMETRIC key types.
+
+There is a commandline tool wrapping the key dumping and generation apis
+available at `./minimal-examples/crypto/lws-crypto-cose-key`
+
+### cose_key and sets import from CBOR and destroying
+
+```
+lws_cose_key_t *
+lws_cose_key_import(lws_dll2_owner_t *pkey_set, lws_cose_key_import_callback cb,
+                   void *user, const uint8_t *in, size_t len);
+void
+lws_cose_key_destroy(lws_cose_key_t **ck);
+
+void
+lws_cose_key_set_destroy(lws_dll2_owner_t *o);
+```
+
+To convert a single key, `pkey_set` should be NULL and the created key will be
+returned, for a cose_key set, which is simply a CBOR array of cose_keys, it
+should be a prepared (ie, zero'd down if nothing in it) lws_dll2_owner_t that
+will contain the resulting list of `lws_cose_key_t` objects that were created.
+In both cases the return is NULL if there was a fatal error and anything created
+has been cleaned up, the return has no other meaning in the cose_key set case.
+
+`lws_cose_key_destroy()` destroys a single `lws_cose_key_t` and sets the
+contents of the pointer to NULL, for cose_key sets you instead pass a pointer to
+the owner object to `lws_cose_key_set_destroy()` to destroy all the keys in the
+set in one step.
+
+cose_key has some confusions about type, kty and alg may be either ints,
+representing well-known standardized key and alg types, or freeform strings.
+We convert the well-known ints to their string representations at import, so
+there can be no confusion later.
+
+### cose_key generation
+
+```
+lws_cose_key_t *
+lws_cose_key_generate(struct lws_context *context, int cose_kty, int use_mask,
+                      int bits, const char *curve, const char *kid);
+```
+
+This creates an `lws_cose_key_t`, generates a key (SYMMETRIC) or keypair into
+it and returns a pointer to it.
+
+`cose_kty` is one of `LWSCOSE_WKKTV_OKP`, `LWSCOSE_WKKTV_EC2`, `LWSCOSE_WKKTV_RSA`,
+or `LWSCOSE_WKKTV_SYMMETRIC`.  `bits` is valid for RSA keys and for EC keys,
+`curve` should be a well-known curve name, one of `P-256`, `P-384` and `P-521`
+currently.  `use_mask` is a bitfield made up of  (1 << LWSCOSE_WKKO_...) set to
+enable the usage on the key.
+
+### cose_key export to CBOR
+
+The export api uses the same CBOR write context as `lws_lec_printf()` uses to
+emit the key into an output buffer.  Like the CBOR output apis, it may return
+`LWS_LECPCTX_RET_AGAIN` to indicate it filled the buffer and should be called
+again to fill another buffer.  `lws_lec_init()` should be used to prepare the
+write context and `lws_lec_setbuf()` to reset the output buffer on subsequent
+calls, exactly the same as the CBOR write apis.
+
+```
+enum lws_lec_pctx_ret
+lws_cose_key_export(lws_cose_key_t *ck, lws_lec_pctx_t *ctx, int flags);
+```
+
+`flags` may be 0 to only output the public key pieces, or `LWSJWKF_EXPORT_PRIVATE`
+to output everything.
+
+## Signing and signature validation
+
+COSE specifies three kinds of signed object, `cose_sign1` which signs a payload
+with a single algorithm and key, `cose_sign` which may sign a payload with
+multiple algorithms and keys, and `countersign`.
+
+`cose_sign1` has the advantage it can be validated with a single pass through
+the signed object; `cose_sign` unfortunately specifies the parameters of the
+signatures after the payload and must be done with multiple passes through the
+payload, for inline payloads, by caching it in heap.
+
+`cose_sign` and `cose_sign1` objects are supported by lws, Countersigned
+objects are not yet supported.
+
+`cose_mac0` is supported using HMAC for signing and validation, `cose_mac` is
+only supported for validation.
+
+There is a commandline tool wrapping the signing and validation apis
+available at `./minimal-examples/crypto/lws-crypto-cose-sign`
+
+### Signature validation
+
+Signature validation does not have to be done synchronously, to facilitate this
+first you create a validation context specifying the type (eg, `SIGTYPE_SINGLE`)
+and a keyset of public keys the signature might use to validate (notice even a
+single key is passed in an lws_dll2_owner_t keyset).
+
+Creation uses a public `lws_cose_validate_create_info_t` info struct
+
+```
+typedef struct lws_cose_validate_create_info {
+       struct lws_context              *cx;
+       /**< REQUIRED: the lws context */
+       lws_dll2_owner_t                *keyset;
+       /**< REQUIRED: one or more cose_keys */
+
+       enum lws_cose_sig_types         sigtype;
+       /**<  0 if a CBOR tag is in the sig, else one of SIGTYPE_MULTI,
+        * SIGTYPE_SINGLE, etc*/
+
+       lws_cose_validate_pay_cb_t      pay_cb;
+       /**< optional: called back with unvalidated payload pieces */
+       void                            *pay_opaque;
+       /**< optional: passed into pay_cb callback along with payload chunk */
+
+       lws_cose_sign_ext_pay_cb_t      ext_cb;
+       /**< optional extra application data provision callback */
+       void                            *ext_opaque;
+       /**< optional extra application data provision callback opaque */
+       size_t                          ext_len;
+       /**< if we have extra app data, this must be set to the length of it */
+} lws_cose_validate_create_info_t;
+```
+
+```
+struct lws_cose_validate_context *
+lws_cose_validate_create(const lws_cose_validate_create_info_t *info);
+
+void
+lws_cose_validate_destroy(struct lws_cose_validate_context **cps);
+```
+
+after that as pieces of the signature CBOR become available, they can be
+processed by the validation context
+
+```
+int
+lws_cose_validate_chunk(struct lws_cose_validate_context *cps,
+                       const uint8_t *in, size_t in_len, size_t *used_in);
+```
+
+The parsing of the signature yields a list of result objects indicating
+information about each signature it encountered and whether it was validated or
+not.  The parsing itself only fails if there is an unrecoverable error, the
+completion of parsing does not indicate validation, it may yield zero or more
+result objects indicating the validation failed.
+
+```
+lws_dll2_owner_t *
+lws_cose_validate_results(struct lws_cose_validate_context *cps);
+
+typedef struct {
+       lws_dll2_t              list;
+
+       const lws_cose_key_t    *cose_key;
+       cose_param_t            cose_alg;
+
+       int                     result; /* 0 = validated */
+
+} lws_cose_validate_res_t;
+```
+
+It's like this because for multiple signatures, we may only have keys for some
+of them, and we may have different policies for validation that can only be
+assessed as a whole, eg, we may inisit that signatures pass with specific
+algorithms, or all signatures for specific keys must be present and pass.  This
+way user code can assess the situation after the signature parsing and make its
+decision about overall validity according to its own policies.
+
+## Signing
+
+Signing is again done by creating a signing context using an info struct to pass
+in the paramter (a `lws_cose_sign_create_info_t`).
+
+```
+#define LCSC_FL_ADD_CBOR_TAG           (1 << 0)
+#define LCSC_FL_ADD_CBOR_PREFER_MAC0   (1 << 1)
+
+typedef struct lws_cose_sign_create_info {
+       struct lws_context              *cx;
+       /**< REQUIRED: the lws context */
+       lws_dll2_owner_t                *keyset;
+       /**< REQUIRED: one or more cose_keys */
+
+       lws_lec_pctx_t                  *lec;
+       /**< REQUIRED: the cbor output context to emit to, user must
+        * initialize with lws_lec_init() beforehand */
+
+       lws_cose_sign_ext_pay_cb_t      ext_cb;
+       /**< optional extra application data provision callback */
+       void                            *ext_opaque;
+       /**< optional extra application data provision callback opaque */
+       size_t                          ext_len;
+       /**< if we have extra app data, this must be set to the length of it */
+
+       size_t                          inline_payload_len;
+       /**< REQUIRED: size of the inline payload we will provide */
+
+       int                             flags;
+       /**< bitmap of  LCSC_FL_* */
+       enum lws_cose_sig_types         sigtype;
+       /**< 0, or sign type hint */
+} lws_cose_sign_create_info_t;
+```
+
+```
+struct lws_cose_sign_context *
+lws_cose_sign_create(const lws_cose_sign_create_info_t *info);
+```
+
+After creating the signing context, you call `lws_cose_sign_add()` one or more
+times to add algorithms and keys to sign with (since cose_sign allows multiple
+recipients with the same payload signed in different ways).
+
+```
+int
+lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
+                 const lws_cose_key_t *ck);
+```
+
+The payload does not have to be provided all at once and can be passed in chunk
+by chunk over time via `lws_cose_sign_payload_chunk()`.
+
+Output is mediated via an lws CBOR output context provided in the info at
+creation-time, it's only emitted during the `lws_cose_sign_payload_chunk()`
+phase.  If it returns `LWS_LECPCTX_RET_AGAIN`, you must call that api again
+after using the CBOR output context data and resetting its buffer by
+`lws_lec_setbuf()`, so it can continue to output.
+
+```
+enum lws_lec_pctx_ret
+lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
+                           const uint8_t *in, size_t in_len);
+```
+
+Finally the signing context is destroyed.
+
+```
+void
+lws_cose_sign_destroy(struct lws_cose_sign_context **csc);
+```
+
diff --git a/READMEs/README.cbor-lecp.md b/READMEs/README.cbor-lecp.md
new file mode 100644 (file)
index 0000000..109dc0c
--- /dev/null
@@ -0,0 +1,344 @@
+# RFC8949 CBOR Stream Parsing and Writing
+
+|||
+|---|---|---|
+|cmake| `LWS_WITH_CBOR`, `LWS_WITH_CBOR_FLOAT`|
+|Header| ./include/libwebsockets/lws-lecp.h|
+|api-test| ./minimal-examples/api-tests/api-test-lecp/|
+|test app| ./test-apps/test-lecp.c -> libwebsockets-test-lecp|
+
+LECP is the RFC8949 CBOR stream parsing counterpart to LEJP for JSON.
+
+## Features
+
+ - Completely immune to input fragmentation, give it any size blocks of CBOR as
+   they become available; 1 byte, or 100K at a time give identical parsing
+   results
+ - Input chunks discarded as they are parsed, whole CBOR never needed in memory
+ - Nonrecursive, fixed stack usage of a few dozen bytes
+ - No heap allocations at all, just requires ~500 byte context usually on
+   caller stack
+ - Creates callbacks to a user-provided handler as members are parsed out
+ - No payload size limit, supports huge / endless strings or blobs bigger than
+   system memory
+ - Collates utf-8 text and blob payloads into a 250-byte chunk buffer for ease
+   of access
+ - Write apis don't use any heap allocations or recursion either
+ - Write apis use an explicit context with its own lifecycle, and printf style
+   vaargs including sized blobs, C strings, double, int, unsigned long etc
+ - Completely immune to output fragmentation, supports huge strings and blobs
+   into small buffers, api returns to indicates unfinished if it needs to be
+   called again to continue; 1 byte or 100K output buffer give same results
+ - Write apis completely fill available buffer and if unfinished, continues
+   into same or different buffer when called again with same args; no
+   requirement for subsequent calls to be done sequentially or even from same
+   function
+
+## Type limits
+
+CBOR allows negative integers of up to 64 bits, these do not fit into a `uint64_t`.
+LECP has a union for numbers that includes the types `uint64_t` and `int64_t`,
+but it does not separately handle negative integers.  Only -2^63.. 2^64 -1 can
+be handled by the C types, the oversize negative numbers wrap and should be
+avoided.
+
+## Floating point support
+
+Floats are handled using the IEEE memory format, it means they can be parsed
+from the CBOR without needing any floating point support in the build.  If
+floating point is available, you can also enable `LWS_WITH_CBOR_FLOAT` and
+a `float` and `double` types are available in the number item union.  Otherwise
+these are handled as `ctx->item.u.u32` and `ctx->item.u.u64` union members.
+
+Half-float (16-bit) is defined in CBOR and always handled as a `uint16_t`
+number union member `ctx->item.u.hf`.
+
+## Callback reasons
+
+The user callback does not have to handle any callbacks, it only needs to
+process the data for the ones it is interested in.
+
+|Callback reason|CBOR structure|Associated data|
+|---|---|---|
+|`LECPCB_CONSTRUCTED`|Created the parse context||
+|`LECPCB_DESTRUCTED`|Destroyed the parse context||
+|`LECPCB_COMPLETE`|The parsing completed OK||
+|`LECPCB_FAILED`|The parsing failed||
+|`LECPCB_VAL_TRUE`|boolean true||
+|`LECPCB_VAL_FALSE`|boolean false||
+|`LECPCB_VAL_NULL`|explicit NULL||
+|`LECPCB_VAL_NUM_INT`|signed integer|`ctx->item.u.i64`|
+|`LECPCB_VAL_STR_START`|A UTF-8 string is starting||
+|`LECPCB_VAL_STR_CHUNK`|The next string chunk|`ctx->npos` bytes in `ctx->buf`|
+|`LECPCB_VAL_STR_END`|The last string chunk|`ctx->npos` bytes in `ctx->buf`|
+|`LECPCB_ARRAY_START`|An array is starting||
+|`LECPCB_ARRAY_END`|An array has ended||
+|`LECPCB_OBJECT_START`|A CBOR map is starting||
+|`LECPCB_OBJECT_END`|A CBOR map has ended||
+|`LECPCB_TAG_START`|The following data has a tag index|`ctx->item.u.u64`|
+|`LECPCB_TAG_END`|The end of the data referenced by the last tag||
+|`LECPCB_VAL_NUM_UINT`|Unsigned integer|`ctx->item.u.u64`|
+|`LECPCB_VAL_UNDEFINED`|CBOR undefined||
+|`LECPCB_VAL_FLOAT16`|half-float available as host-endian `uint16_t`|`ctx->item.u.hf`|
+|`LECPCB_VAL_FLOAT32`|`float` (`uint32_t` if no float support) available|`ctx->item.u.f`|
+|`LECPCB_VAL_FLOAT64`|`double` (`uint64_t` if no float support) available|`ctx->item.u.d`|
+|`LECPCB_VAL_SIMPLE`|CBOR simple|`ctx->item.u.u64`|
+|`LECPCB_VAL_BLOB_START`|A binary blob is starting||
+|`LECPCB_VAL_BLOB_CHUNK`|The next blob chunk|`ctx->npos` bytes in `ctx->buf`|
+|`LECPCB_VAL_BLOB_END`|The last blob chunk|`ctx->npos` bytes in `ctx->buf`|
+|`LECPCB_ARRAY_ITEM_START`|A logical item in an array is starting|
+|`LCEPDB_ARRAY_ITEM_END`|A logical item in an array has completed|
+
+## CBOR indeterminite lengths
+
+Indeterminite lengths are supported, but are concealed in the parser as far as
+possible, the CBOR lengths or its indeterminacy are not exposed in the callback
+interface at all, just chunks of data that may be the start, the middle, or the
+end.
+
+## Handling CBOR UTF-8 strings and blobs
+
+When a string or blob is parsed, an advisory callback of `LECPCB_VAL_STR_START` or
+`LECPCB_VAL_BLOB_START` occurs first.  The `_STR_` callbacks indicate the
+content is a CBOR UTF-8 string, `_BLOB_` indicates it is binary data.
+
+Strings or blobs may have indeterminite length, but if so, they are composed
+of logical chunks which must have known lengths.  When the `_START` callback
+occurs, the logical length either of the whole string, or of the sub-chunk if
+indeterminite length, can be found in `ctx->item.u.u64`.
+
+Payload is collated into `ctx->buf[]`, the valid length is in `ctx->npos`.
+
+For short strings or blobs where the length is known, the whole payload is
+delivered in a single `LECPCB_VAL_STR_END` or `LECPCB_VAL_BLOB_END` callback.
+
+For payloads larger than the size of `ctx->buf[]`, `LECPCB_VAL_STR_CHUNK` or
+`LECPCB_VAL_BLOB_CHUNK` callbacks occur delivering each sequential bufferload.
+If the CBOR indicates the total length, the last chunk is delievered in a
+`LECPCB_VAL_STR_END` or `LECPCB_VAL_BLOB_END`.
+
+If the CBOR indicates the string end after the chunk, a zero-length `..._END`
+callback is provided.
+
+## Handling CBOR tags
+
+CBOR tags are exposed as `LECPCB_TAG_START` and `LECPCB_TAG_END` pairs, at
+the `_START` callback the tag index is available in `ctx->item.u.u64`.
+
+## CBOR maps
+
+You can check if you are on the "key" part of a map "key:value" pair using the
+helper api `lecp_parse_map_is_key(ctx)`.
+
+## Parsing paths
+
+LECP maintains a "parsing path" in `ctx->path` that represents the context of
+the callback events.  As a convenience, at LECP context creation time, you can
+pass in an array of path strings you want to match on, and have any match
+checkable in the callback using `ctx->path_match`, it's 0 if no active match,
+or the match index from your path array starting from 1 for the first entry.
+
+|CBOR element|Representation in path|
+|---|---|
+|CBOR Array|`[]`|
+|CBOR Map|`.`|
+|CBOR Map entry key string|`keystring`|
+
+## Accessing raw CBOR subtrees
+
+Some CBOR usages like COSE require access to selected raw CBOR from the input
+stream.  `lecp_parse_report_raw(ctx, on)` lets you turn on and off buffering of
+raw CBOR and reporting it in the parse callback with `LECPCB_LITERAL_CBOR`
+callbacks.  The callbacks mean the temp buffer `ctx->cbor[]` has `ctx->cbor_pos`
+bytes of raw CBOR available in it.  Callbacks are triggered when the buffer
+fills, or reporting is turned off and the buffer has something in it.
+
+By turning the reporting on and off according to the outer CBOR parsing state,
+it's possible to get exactly the raw CBOR subtree that's needed.
+
+Capturing and reporting the raw CBOR does not change that the same CBOR is being
+passed to the parser as usual as well.
+
+## Comparison with LEJP (JSON parser)
+
+LECP is based on the same principles as LEJP and shares most of the callbacks.
+The major differences:
+
+ - LEJP value callbacks all appear in `ctx->buf[]`, ie, floating-point is
+   provided to the callback in ascii form like `"1.0"`.  CBOR provides a more
+   strict typing system, and the different type values are provided either in
+   `ctx->buf[]` for blobs or utf-8 text strtings, or the `item.u` union for
+   converted types, with additional callback reasons specific to each type.
+
+ - CBOR "maps" use `_OBJECT_START` and `_END` parsing callbacks around the
+   key / value pairs.  LEJP has a special callback type `PAIR_NAME` for the
+   key string / integer, but in LECP these are provided as generic callbacks
+   dependent on type, ie, generic string callbacks or integer ones, and the
+   value part is represented according to whatever comes.
+
+
+# Writing CBOR
+
+CBOR is written into a `lws_lec_pctx_t` object that has been initialized to
+point to an output buffer of a specified size, using printf type formatting.
+
+Output is paused if the buffer fills, and the write api may be called again
+later with the same context object, to resume emitting to the same or different
+buffer.
+
+This allows bufferloads of encoded CBOR to be produced on demand, it's designed
+to fit usage in WRITEABLE callbacks and Secure Streams tx() callbacks where the
+buffer size for one packet is already fixed.
+
+CBOR array and map lengths are deduced from the format string, as is whether to
+use indeterminite length formatting or not.  For indeterminite text or binary
+strings, a container of < > 
+
+|Format|Arg(s)|Meaning|
+|---|---|---|
+|`123`||unsigned literal number|
+|`-123`||signed literal number|
+|`%u`|`unsigned int`|number|
+|`%lu`|`unsigned long int`|number|
+|`%llu`|`unsigned long long int`|number|
+|`%d`|`signed int`|number|
+|`%ld`|`signed long int`|number|
+|`%lld`|`signed long long int`|number|
+|`%f`|`double`|floating point number|
+|`123(...)`||literal tag and scope|
+|`%t(...)`|`unsigned int`|tag and scope|
+|`%lt(...)`|`unsigned long int`|tag and scope|
+|`%llt(...)`|`unsigned long long int`|tag and scope|
+|`[...]`||Array (fixed len if `]` in same format string)|
+|`{...}`||Map (fixed len if `}` in same format string)|
+|`<t...>`||Container for indeterminite text string frags|
+|`<b...>`||Container for indeterminite binary string frags|
+|`'string'`||Literal text of known length|
+|`%s`|`const char *`|NUL-terminated string|
+|`%.*s`|`int`, `const char *`|length-specified string|
+|`%.*b`|`int`, `const uint8_t *`|length-specified binary|
+|`:`||separator between Map items (a:b)|
+|`,`||separator between Map pairs or array items|
+
+Backslash is used as an escape in `'...'` literal strings, so `'\\'` represents
+a string consisting of a single backslash, and `'\''` a string consisting of a
+single single-quote.
+
+For integers, various natural C types are available, but in all cases, the
+number is represented in CBOR using the smallest valid way based on its value,
+the long or long-long modifiers just apply to the expected C type in the args.
+
+For floats, the C argument is always expected to be a `double` type following
+C type promotion, but again it is represented in CBOR using the smallest valid
+way based on value, half-floats are used for NaN / Infinity and where possible
+for values like 0.0 and -1.0.
+
+## Examples
+
+### Literal ints
+
+```
+       uint8_t buf[128];
+       lws_lec_pctx_t cbw;
+
+       lws_lec_init(&cbw, buf, sizeof(buf));
+       lws_lec_printf(ctx, "-1");
+```
+|||
+|---|---|
+|Return| `LWS_LECPCTX_RET_FINISHED`|
+|`ctx->used`|1|
+|`buf[]`|20|
+
+### Dynamic ints
+
+```
+       uint8_t buf[128];
+       lws_lec_pctx_t cbw;
+       int n = -1; /* could be long */
+
+       lws_lec_init(&cbw, buf, sizeof(buf));
+       lws_lec_printf(ctx, "%d", n); /* use %ld for long */
+```
+|||
+|---|---|
+|Return| `LWS_LECPCTX_RET_FINISHED`|
+|`ctx->used`|1|
+|`buf[]`|20|
+
+### Maps, arrays and dynamic ints
+
+```
+       ...
+       int args[3] = { 1, 2, 3 };
+
+       lws_lec_printf(ctx, "{'a':%d,'b':[%d,%d]}", args[0], args[1], args[2]);
+```
+
+|||
+|---|---|
+|Return| `LWS_LECPCTX_RET_FINISHED`|
+|`ctx->used`|9|
+|`buf[]`|A2 61 61 01 61 62 82 02 03|
+
+### String longer than the buffer
+
+Using `%s` and the same string as an arg gives same results
+
+```
+       uint8_t buf[16];
+       lws_lec_pctx_t cbw;
+
+       lws_lec_init(&cbw, buf, sizeof(buf));
+       lws_lec_printf(ctx, "'A literal string > one buf'");
+       /* not required to be in same function context or same buf,
+        * but the string must remain the same */
+       lws_lec_setbuf(&cbw, buf, sizeof(buf));
+       lws_lec_printf(ctx, "'A literal string > one buf'");
+```
+
+First call
+
+|||
+|---|---|
+|Return| `LWS_LECPCTX_RET_AGAIN`|
+|`ctx->used`|16|
+|`buf[]`|78 1A 41 20 6C 69 74 65 72 61 6C 20 73 74 72 69|
+
+Second call
+
+|||
+|---|---|
+|Return| `LWS_LECPCTX_RET_FINISHED`|
+|`ctx->used`|12|
+|`buf[]`|6E 67 20 3E 20 6F 6E 65 20 62 75 66|
+
+### Binary blob longer than the buffer
+
+```
+       uint8_t buf[16], blob[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
+       lws_lec_pctx_t cbw;
+
+       lws_lec_init(&cbw, buf, sizeof(buf));
+       lws_lec_printf(ctx, "%.*b", (int)sizeof(blob), blob);
+       /* not required to be in same function context or same buf,
+        * but the length and blob must remain the same */
+       lws_lec_setbuf(&cbw, buf, sizeof(buf));
+       lws_lec_printf(ctx, "%.*b", (int)sizeof(blob), blob);
+```
+
+First call
+
+|||
+|---|---|
+|Return| `LWS_LECPCTX_RET_AGAIN`|
+|`ctx->used`|16|
+|`buf[]`|52 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F|
+
+Second call
+
+|||
+|---|---|
+|Return| `LWS_LECPCTX_RET_FINISHED`|
+|`ctx->used`|3|
+|`buf[]`|10 11 12|
diff --git a/READMEs/README.cmake.md b/READMEs/README.cmake.md
new file mode 100644 (file)
index 0000000..127282a
--- /dev/null
@@ -0,0 +1,41 @@
+# Tips about CMake
+
+## Don't be afraid to nuke your build dir
+
+CMake likes to cache options and other things in the build dir... if you stop
+asserting the state of something like `-DMY_OPTION=1`, then the last way it was
+set it cached.  On order to keep track of what you have set and not set, it's
+very advisable to explicitly keep all your options and set them all on one cmake
+line.
+
+Then, when you meet a situation you changed something but somehow cmake is
+sticking with what it knew before, you can fearlessly delete your build dir
+and create a new one with your explicit config.
+
+On Linux, it's usually enough to delete `CMakeCache.txt` to trigger it to config
+from the start again, but on, eg, windows, it isn't, for whatever reason it
+literally needs the build dir removing.
+
+## CMake presence tests that fail
+
+Lws makes use of various CMake features to figure out what apis your libraries
+offer, eg, OpenSSL has many different apis based on version, lws knows how to
+work around most of the changes, but to do it it must find out what apis are
+available first on your build environment.
+
+CMake basically builds little throwaway test programs using each api in turn, and
+if it builds, it understands that the api was available and sets a preprocessor
+symbol that's available in the main build accordingly.  Then we can do `#if xxx`
+to figure out if we can use `xxx` or need to do a workaround at build-time.
+
+This works very well, but unfortunately if the program didn't build, there are
+many possible ways for the build to break even if the api being tested is
+really available... for example, some library in your toolchain isn't being
+linked for the throwaway test program.
+
+When this happens, cmake indicates that apis that must be available are not available...
+CMake keeps a log of what happened with the failed test programs in
+`./build/CMakeFiles/CMakeError.log`.  This is appeneded to, so the best way is blow
+away the build dir and reconfig a new one from scratch, and go look in there to
+find out what the compiler or linker was complaining about.
+
index 40aa506..d1143f5 100644 (file)
@@ -1,7 +1,7 @@
 Notes about coding with lws
 ===========================
 
-@section era Old lws and lws v2.0
+@section era Old lws and lws v2.0+
 
 Originally lws only supported the "manual" method of handling everything in the
 user callback found in test-server.c / test-server-http.c.
@@ -183,28 +183,17 @@ loop wait (sleeping in `poll()` or `epoll()` or whatever).  The rules above
 mean directly sending data on the connection from another thread is out of the
 question.
 
-Therefore the two apis mentioned above that may be used from another thread are
+The only lws api that's safe to call from other thread contexts is `lws_cancel_service()`.
+This will take a platform-specific action to wake the lws event loop thread wait,
+either put a byte into a pipe2() the event loop is waiting on, or send a packet on
+a UDP socket pair that the event loop waits on.  When the wake is handled by the
+lws event loop thread, it will broadcast a `LWS_CALLBACK_EVENT_WAIT_CANCELLED`
+message to every vhost-protocol instantiation, so you can handle this callback,
+usually lock a shared data region, and if you see you need to write, call
+`lws_callback_on_writeable()` for the wsi(s) that need to write.
 
- - For LWS using the default poll() event loop, `lws_callback_on_writable()`
-
- - For LWS using libuv/libev/libevent event loop, `lws_cancel_service()`
-
-If you are using the default poll() event loop, one "foreign thread" at a time may
-call `lws_callback_on_writable()` directly for a wsi.  You need to use your own
-locking around that to serialize multiple thread access to it.
-
-If you implement LWS_CALLBACK_GET_THREAD_ID in protocols[0], then LWS will detect
-when it has been called from a foreign thread and automatically use
-`lws_cancel_service()` to additionally wake the service loop from its wait.
-
-For libuv/libev/libevent event loop, they cannot handle being called from other
-threads.  So there is a slightly different scheme, you may call `lws_cancel_service()` 
-to force the event loop to end immediately.  This then broadcasts a callback (in the
-service thread context) `LWS_CALLBACK_EVENT_WAIT_CANCELLED`, to all protocols on all
-vhosts, where you can perform your own locking and walk a list of wsi that need
-`lws_callback_on_writable()` calling on them.
-
-`lws_cancel_service()` is very cheap to call.
+There's no restriction on multiple threads calling `lws_cancel_service()`, it's
+unconditionally safe due to how it is implemented underneath.
 
 5) The obverse of this truism about the receiver being the boss is the case where
 we are receiving.  If we get into a situation we actually can't usefully
@@ -351,32 +340,7 @@ deal with fragmented messages.
 
 @section debuglog Debug Logging
 
-Also using `lws_set_log_level` api you may provide a custom callback to actually
-emit the log string.  By default, this points to an internal emit function
-that sends to stderr.  Setting it to `NULL` leaves it as it is instead.
-
-A helper function `lwsl_emit_syslog()` is exported from the library to simplify
-logging to syslog.  You still need to use `setlogmask`, `openlog` and `closelog`
-in your user code.
-
-The logging apis are made available for user code.
-
-- `lwsl_err(...)`
-- `lwsl_warn(...)`
-- `lwsl_notice(...)`
-- `lwsl_info(...)`
-- `lwsl_debug(...)`
-
-The difference between notice and info is that notice will be logged by default
-whereas info is ignored by default.
-
-If you are not building with _DEBUG defined, ie, without this
-
-```
-       $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG
-```
-
-then log levels below notice do not actually get compiled in.
+See ./READMEs/README.logging.md
 
 @section asan Building with ASAN
 
index 0fe0cc2..462adce 100644 (file)
@@ -17,7 +17,7 @@ CSP lets the origin server define what is legitimate for the page it
 served and everything else is denied.
 
 The CSP for warmcat.com and libwebsockets.org looks like this,
-I removed a handful of whitelisted image sources like travis
+I removed a handful of approved image sources like travis
 status etc for clarity...
 
 ```
@@ -40,7 +40,7 @@ provide a very significant increase in client security.
 ### Implications of strict CSP
 
 Halfhearted CSP isn't worth much.  The only useful approach is to start
-with `default-src 'none'` which disables everything, and then whitelist the
+with `default-src 'none'` which disables everything, and then allow the
 minimum needed for the pages to operate.
 
 "Minimum needed for the pages to operate" doesn't mean defeat the protections
@@ -63,7 +63,7 @@ files referenced in the document `<head>` section, along these lines:
 #### Inline styles must die
 
 All styling must go in one or more `.css` file(s) best served by the same
-server... while you can whitelist other sources in the CSP if you have to,
+server... while you can approve other sources in the CSP if you have to,
 unless you control that server as well, you are allowing whoever gains
 access to that server access to your users.
 
diff --git a/READMEs/README.ctest.md b/READMEs/README.ctest.md
new file mode 100644 (file)
index 0000000..0ed8a84
--- /dev/null
@@ -0,0 +1,345 @@
+## Using CTest with lws
+
+### Updating ancient cmake
+
+You need a recent cmake to have the CTest tests work properly, if you're on an
+older distro you need to update your cmake.  Luckily Kitware provide a repo for
+common distros.  These instructions work for bionic and xenial.
+
+First remove the old distro cmake and install the pieces needed to get the new repo keys
+
+```
+# apt purge --auto-remove cmake
+# apt install gnupg wget apt-transport-https ca-certificates
+# wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -
+# apt edit-sources
+```
+
+Add the line `deb https://apt.kitware.com/ubuntu/ bionic main` at the end
+replacing `bionic` with `xenial` as needed, and save (:wq).  Then
+
+```
+# apt update
+# apt install cmake
+```
+
+## Tests live in CMakeLists.txt
+
+The rules for tests are described in ctest / cmake language inside the minimal
+examples and api tests that are enabled by current build options, so you need
+to build with `-DLWS_WITH_MINIMAL_EXAMPLES=1` to build the examples along with
+the library.
+
+The tests are typically running the examples or api tests and regarding the
+process exiting with exit code 0 as success, anything else as failure.
+
+## Generating the tests
+
+The main tests just need `-DLWS_WITH_MINIMAL_EXAMPLES=1`.  You can optionally set
+`-DLWS_CTEST_INTERNET_AVAILABLE=0` to indicate you can't run the tests that need
+internet connectivity.
+
+## Preparing to run the tests
+
+The tests have to be able to run without root and without disturbing any other
+install of lws in the build machine.
+
+For that reason you have to do an unprivileged side-install into `../destdir`,
+using `make install DESTDIR=../destdir` from the build directory and perform the
+tests on the pieces in there.
+
+## Running the tests
+
+We must take care to run the pieces (.so etc) we just built, without having
+root access, and not any of the same pieces from some other lws version that may
+have been installed on the build machine.  That includes, eg, plugins that
+we just built, to ensure precedence of those in the search path we can set our
+DESTDIR unprivileged install path in `LD_LIBRARY_PATH`.
+
+Then we can run ctest on the unprivileged install.  The whole step looks
+something like this:
+
+```
+build $ make -j12 && \
+  rm -rf ../destdir && \
+  make -j12 DESTDIR=../destdir install && \\
+  LD_LIBRARY_PATH=../destdir/usr/local/share/libwebsockets-test-server/plugins ctest -j2 --output-on-failure
+```  
+
+On windows, it looks like `ctest . -C DEBUG` or RELEASE if that was the build
+type.
+
+Good results look something like this (which tests can run depend on your
+build options)
+
+```
+Test project /projects/libwebsockets/build
+      Start 71: st_wcs_srv
+      Start 43: st_hcp_srv
+ 1/73 Test #71: st_wcs_srv ..................................   Passed    5.01 sec
+      Start 19: st_hcmp_srv
+ 2/73 Test #43: st_hcp_srv ..................................   Passed    5.01 sec
+      Start 17: st_hcm_srv
+ 3/73 Test #19: st_hcmp_srv .................................   Passed    5.01 sec
+      Start 55: st_ssproxyctx
+ 4/73 Test #17: st_hcm_srv ..................................   Passed    5.01 sec
+      Start 52: st_ssproxy
+ 5/73 Test #55: st_ssproxyctx ...............................   Passed    1.02 sec
+      Start 67: st_sstfproxy
+ 6/73 Test #52: st_ssproxy ..................................   Passed    1.02 sec
+      Start 60: st_ssprxsmd_sspc
+ 7/73 Test #67: st_sstfproxy ................................   Passed    1.01 sec
+      Start 63: st_mulssprxsmd_sspc
+ 8/73 Test #60: st_ssprxsmd_sspc ............................   Passed    1.01 sec
+      Start 69: sspc-minimaltf
+ 9/73 Test #63: st_mulssprxsmd_sspc .........................   Passed    1.02 sec
+      Start 73: ws-client-spam
+10/73 Test #73: ws-client-spam ..............................   Passed   12.21 sec
+      Start 57: sspc-minimaltx
+11/73 Test #57: sspc-minimaltx ..............................   Passed    5.90 sec
+      Start 65: mulsspcsmd_sspc
+12/73 Test #65: mulsspcsmd_sspc .............................   Passed    3.58 sec
+      Start 62: sspcsmd_sspc
+13/73 Test #62: sspcsmd_sspc ................................   Passed    1.73 sec
+      Start 22: http-client-multi-h1
+14/73 Test #22: http-client-multi-h1 ........................   Passed    5.04 sec
+      Start 25: http-client-multi-stag
+15/73 Test #25: http-client-multi-stag ......................   Passed    4.53 sec
+      Start 26: http-client-multi-stag-h1
+16/73 Test #26: http-client-multi-stag-h1 ...................   Passed    4.40 sec
+      Start 21: http-client-multi
+17/73 Test #21: http-client-multi ...........................   Passed    4.37 sec
+      Start 36: http-client-multi-post-h1
+18/73 Test #36: http-client-multi-post-h1 ...................   Passed    2.73 sec
+      Start 54: sspc-minimal
+19/73 Test #54: sspc-minimal ................................   Passed    0.93 sec
+      Start 39: http-client-multi-post-stag
+20/73 Test #39: http-client-multi-post-stag .................   Passed    2.29 sec
+      Start 40: http-client-multi-post-stag-h1
+21/73 Test #69: sspc-minimaltf ..............................   Passed   49.83 sec
+      Start 35: http-client-multi-post
+22/73 Test #40: http-client-multi-post-stag-h1 ..............   Passed    4.30 sec
+      Start 33: http-client-multi-restrict-nopipe-fail
+23/73 Test #35: http-client-multi-post ......................   Passed    3.23 sec
+      Start 28: http-client-multi-stag-h1-pipe
+24/73 Test #33: http-client-multi-restrict-nopipe-fail ......   Passed    2.86 sec
+      Start 32: http-client-multi-restrict-stag-h1-pipe
+25/73 Test #28: http-client-multi-stag-h1-pipe ..............   Passed    2.86 sec
+      Start 27: http-client-multi-stag-pipe
+26/73 Test #32: http-client-multi-restrict-stag-h1-pipe .....   Passed    1.51 sec
+      Start 31: http-client-multi-restrict-stag-pipe
+27/73 Test #27: http-client-multi-stag-pipe .................   Passed    1.52 sec
+      Start 34: http-client-multi-restrict-h1-nopipe-fail
+28/73 Test #34: http-client-multi-restrict-h1-nopipe-fail ...   Passed    2.78 sec
+      Start 46: http-client-post-m
+29/73 Test #31: http-client-multi-restrict-stag-pipe ........   Passed    2.80 sec
+      Start 42: http-client-multi-post-stag-h1-pipe
+30/73 Test #42: http-client-multi-post-stag-h1-pipe .........   Passed    1.51 sec
+      Start 41: http-client-multi-post-stag-pipe
+31/73 Test #46: http-client-post-m ..........................   Passed    1.59 sec
+      Start 48: http-client-post-m-h1
+32/73 Test #48: http-client-post-m-h1 .......................   Passed    1.10 sec
+      Start 23: http-client-multi-pipe
+33/73 Test #41: http-client-multi-post-stag-pipe ............   Passed    1.51 sec
+      Start 29: http-client-multi-restrict-pipe
+34/73 Test #23: http-client-multi-pipe ......................   Passed    1.09 sec
+      Start 24: http-client-multi-h1-pipe
+35/73 Test #29: http-client-multi-restrict-pipe .............   Passed    0.74 sec
+      Start 30: http-client-multi-restrict-h1-pipe
+36/73 Test #24: http-client-multi-h1-pipe ...................   Passed    1.14 sec
+      Start 45: http-client-post
+37/73 Test #30: http-client-multi-restrict-h1-pipe ..........   Passed    1.14 sec
+      Start 38: http-client-multi-post-h1-pipe
+38/73 Test #45: http-client-post ............................   Passed    0.30 sec
+      Start 37: http-client-multi-post-pipe
+39/73 Test #38: http-client-multi-post-h1-pipe ..............   Passed    0.49 sec
+      Start 47: http-client-post-h1
+40/73 Test #37: http-client-multi-post-pipe .................   Passed    0.31 sec
+      Start 50: hs_evlib_foreign_event
+41/73 Test #47: http-client-post-h1 .........................   Passed    0.29 sec
+      Start 66: ss-tf
+42/73 Test #50: hs_evlib_foreign_event ......................   Passed   22.02 sec
+      Start 49: hs_evlib_foreign_uv
+43/73 Test #49: hs_evlib_foreign_uv .........................   Passed   21.03 sec
+      Start 51: ss-warmcat
+44/73 Test #51: ss-warmcat ..................................   Passed    2.69 sec
+      Start 59: ss-smd
+45/73 Test #59: ss-smd ......................................   Passed    1.78 sec
+      Start 10: api-test-secure-streams
+46/73 Test #10: api-test-secure-streams .....................   Passed    1.34 sec
+      Start 11: http-client-warmcat
+47/73 Test #11: http-client-warmcat .........................   Passed    0.27 sec
+      Start 58: sspost-warmcat
+48/73 Test #58: sspost-warmcat ..............................   Passed    0.84 sec
+      Start 12: http-client-warmcat-h1
+49/73 Test #12: http-client-warmcat-h1 ......................   Passed    0.25 sec
+      Start  2: api-test-jose
+50/73 Test  #2: api-test-jose ...............................   Passed    0.27 sec
+      Start 70: ws-client-rx-warmcat
+51/73 Test #70: ws-client-rx-warmcat ........................   Passed    0.27 sec
+      Start 56: ki_ssproxyctx
+52/73 Test #56: ki_ssproxyctx ...............................   Passed    0.12 sec
+      Start 68: ki_ssproxy
+53/73 Test #68: ki_ssproxy ..................................   Passed    0.11 sec
+      Start 64: ki_mulssprxsmd_sspc
+54/73 Test #64: ki_mulssprxsmd_sspc .........................   Passed    0.10 sec
+      Start 61: ki_ssprxsmd_sspc
+55/73 Test #61: ki_ssprxsmd_sspc ............................   Passed    0.11 sec
+      Start 13: http-client-h2-rxflow-warmcat
+56/73 Test #13: http-client-h2-rxflow-warmcat ...............   Passed    0.28 sec
+      Start 14: http-client-h2-rxflow-warmcat-h1
+57/73 Test #14: http-client-h2-rxflow-warmcat-h1 ............   Passed    0.34 sec
+      Start 16: http-client-hugeurl-warmcat-h1
+58/73 Test #16: http-client-hugeurl-warmcat-h1 ..............   Passed    0.16 sec
+      Start 15: http-client-hugeurl-warmcat
+59/73 Test #15: http-client-hugeurl-warmcat .................   Passed    0.16 sec
+      Start 72: ki_wcs_srv
+60/73 Test #72: ki_wcs_srv ..................................   Passed    0.12 sec
+      Start 44: ki_hcp_srv
+61/73 Test #44: ki_hcp_srv ..................................   Passed    0.11 sec
+      Start 20: ki_hcmp_srv
+62/73 Test #20: ki_hcmp_srv .................................   Passed    0.11 sec
+      Start 18: ki_hcm_srv
+63/73 Test #18: ki_hcm_srv ..................................   Passed    0.11 sec
+      Start  7: api-test-lws_struct_sqlite
+64/73 Test  #7: api-test-lws_struct_sqlite ..................   Passed    0.03 sec
+      Start  1: api-test-gencrypto
+65/73 Test  #1: api-test-gencrypto ..........................   Passed    0.02 sec
+      Start  6: api-test-lws_struct-json
+66/73 Test  #6: api-test-lws_struct-json ....................   Passed    0.01 sec
+      Start  4: api-test-lws_dsh
+67/73 Test  #4: api-test-lws_dsh ............................   Passed    0.01 sec
+      Start  8: api-test-lws_tokenize
+68/73 Test  #8: api-test-lws_tokenize .......................   Passed    0.01 sec
+      Start  9: api-test-lwsac
+69/73 Test  #9: api-test-lwsac ..............................   Passed    0.00 sec
+      Start  3: api-test-lejp
+70/73 Test  #3: api-test-lejp ...............................   Passed    0.00 sec
+      Start 53: ki_ssproxy
+71/73 Test #53: ki_ssproxy ..................................   Passed    0.11 sec
+72/73 Test #66: ss-tf .......................................   Passed   55.51 sec
+      Start  5: api-test-lws_smd
+73/73 Test  #5: api-test-lws_smd ............................   Passed    4.22 sec
+
+100% tests passed, 0 tests failed out of 73
+
+Total Test time (real) = 137.76 sec
+```
+
+## Considerations for creating tests
+
+### Timeout
+
+The default test timeout is 1500s, for that reason it's good practice to set
+a more suitable `TIMEOUT` property on every test.
+
+### Working Directory
+
+Server-side test apps usually need to be run from their `./minimal-examples/...`
+directory so they can access their assets like index.html etc.
+
+However when building with `-DLWS_WITH_MBEDTLS=1` then even client-side apps
+need to be run from their directory, since they need to get the trusted CA for
+warmcat.com or libwebsockets.org additionally.
+
+For that reason it's good practice to set the `WORKING_DIRECTORY` property to
+the home dir of the example app in all cases.
+
+### Spawning Buddies
+
+Many networking tests need to either spawn a client or a server in order to
+have a "buddy" to talk to during the test for the opposing side.  This is a
+bit awkward in cmake since it does not directly support spawning daemons as
+test dependencies.
+
+Lws provides helper scripts for unix type targets in `./scripts/ctest-background.sh`
+and `./scripts/ctest-background-kill.sh`, which spawn background processes,
+save the pid in a decorated /tmp file and can later take the process down.  This
+also has arrangements to dump the log of any background process that exited
+early.
+
+To arrange the buddy to run aligned with the test, you first explain to cmake
+how to start and stop the buddy using phony tests to make a "fixture" in cmake
+terms.
+
+In this example, taken from minimal-http-client-multi, we arrange for
+minimal-http-server-tls to be available for our actual test.  The starting and
+stopping definition, for "st_hcm_srv" and "ki_hcm_srv":
+
+```
+       add_test(NAME st_hcm_srv COMMAND
+               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                       hcm_srv $<TARGET_FILE:lws-minimal-http-server-tls>
+                       --port ${PORT_HCM_SRV} )
+       add_test(NAME ki_hcm_srv COMMAND
+               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                       hcm_srv $<TARGET_FILE_NAME:lws-minimal-http-server-tls>
+                               --port ${PORT_HCM_SRV})
+```
+
+... and binding those together so cmake knows they start and stop a specific
+named fixture "hcm_srv", itself with an 800s timeout
+
+```
+       set_tests_properties(st_hcm_srv PROPERTIES
+                       WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-tls
+               FIXTURES_SETUP hcm_srv
+               TIMEOUT 800)
+       set_tests_properties(ki_hcm_srv PROPERTIES
+               FIXTURES_CLEANUP hcm_srv)
+```
+
+... and finally, adding the "hcm_srv" fixture as a requirement on the actual
+test (http-client-multi) we are testing
+
+```
+       set_tests_properties(http-client-multi
+                            PROPERTIES
+                            FIXTURES_REQUIRED "hcm_srv"
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client-multi
+                            TIMEOUT 50)
+```
+
+Once all that explaining is done, ctest itself will take care about starting
+and killing hcm_srv before and after http-client-multi test.
+
+### Buddy sockets and test concurrency
+
+For tests with local buddies using tcp sockets inside the same VM or systemd-
+nspawn networking context, you cannot just use a well-known port like 7681.
+
+ctest itself is usually executed concurrently, and Sai is typically building
+multiple different instances concurrently as well (typically 3), so it may be
+running different ctests inside the same VM simultaneously.
+
+Different tests can have their own convention for port ranges, to solve the
+problem about Sai running different tests concurrently inside one ctest.
+
+For the case there are multiple ctests running, we can use the env var
+`$ENV{SAI_INSTANCE_IDX}`, which is an ordinal like 0 or 1, to further ensure
+that port selections won't conflict.  If not using Sai, you can just set this
+in the evironment yourself to reflect your build instance index.
+
+```
+       #
+       # instantiate the server per sai builder instance, they are running in the same
+       # machine context in parallel so they can tread on each other otherwise
+       #
+       set(PORT_HCM_SRV "7670")
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0")
+               set(PORT_HCM_SRV 7671)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1")
+               set(PORT_HCM_SRV 7672)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2")
+               set(PORT_HCM_SRV 7673)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3")
+               set(PORT_HCM_SRV 7674)
+       endif()
+```
+
+This is complicated enough that the best approach is copy an existing simple
+case like the CMakeLists.txt for minimal-http-client and change the names and
+ports to be unique.
diff --git a/READMEs/README.debugging.md b/READMEs/README.debugging.md
new file mode 100644 (file)
index 0000000..aca24b2
--- /dev/null
@@ -0,0 +1,63 @@
+# Tips on debugging with lws
+
+## Problem with the library, or your code?
+
+Because lws is only really used when already combined with user code,
+it can be a headache figuring out if the actual problem is inside lws
+or in the user code.
+
+If it's in lws, I would really like to solve it, but if it's in your
+code, that's your problem.  Finding out which side it's on when it
+involves your code is also something you need to try to resolve.
+
+The minimal examples are useful because if they demonstrate the same
+problem, it's something about your platform or lws itself, I have the
+minimal examples so I can test it and find out if it's your platform.
+If I can reproduce it, it's my problem.
+
+## Debug builds
+
+With cmake, build with `-DCMAKE_BUILD_TYPE=DEBUG` to build in extra
+logging, and use a log level bitmap of eg, 1039 or 1151 to enable
+the extra logs for print.
+
+The minimal examples take a -d xxx commandline parameter so you can
+select the logging level when you run it.
+
+The extra logging can be very useful to understand the sequencing of
+problematic actions.
+
+## Valgrind
+
+If your problems involve heap corruption or use-after-free, Valgrind
+is indespensible.  It's simple to use, if you normally run `xxx`, just
+run `valgrind xxx`.  Your code will run slower, usually something
+like 2 - 4x slower but it depends on the exact code.  However you will
+get a backtrace as soon as there is some kind of misbehaviour of either
+lws or your code.
+
+lws is developed using valgrind routinely and strives to be completely
+valgrind-clean.  So typically any problems reported are telling you
+about problems in user code (or my bugs).
+
+## Traffic dumping
+
+The best place for dumping traffic, assuming you are linking against a
+tls library, is `lws_ssl_capable_read()` and `lws_ssl_capable_write()`
+in either `./lib/tls/openssl/openssl-ssl.c` or
+`./lib/tls/mbedtls/mbedtls-ssl.c` according to which tls library you
+are using.  There are default-`#if 0` sections in each function like
+
+```
+#if 0
+       /*
+        * If using mbedtls type tls library, this is the earliest point for all
+        * paths to dump what was received as decrypted data from the tls tunnel
+        */
+       lwsl_notice("%s: len %d\n", __func__, len);
+       lwsl_hexdump_notice(buf, len);
+#endif
+```
+
+Enable these to get hexdumps for all unencrypted data in both directions.
+
diff --git a/READMEs/README.event-libs.md b/READMEs/README.event-libs.md
new file mode 100644 (file)
index 0000000..391d74c
--- /dev/null
@@ -0,0 +1,80 @@
+# lws event library support
+
+## v4.0 and below
+
+Before v4.1, lws allowed selecting some event library support for inclusion
+in the libwebsockets library
+
+Option|Feature
+---|---
+`LWS_WITH_GLIB`|glib
+`LWS_WITH_LIBEVENT`|libevent
+`LWS_WITH_LIBUV`|libuv
+`LWS_WITH_LIBEV`|libev
+
+The user code can select by `info->options` flags at runtime which event loop
+it wants to use.
+
+The only restriction is that libev and libevent can't coexist, because their
+header namespace conflicts.
+
+## v4.1 and above
+
+Lws continues to support the old way described above, but there's an additional
+new cmake option that decides how they are built if any are selected,
+`LWS_WITH_EVLIB_PLUGINS`.
+
+The old behaviour is set by `LWS_WITH_EVLIB_PLUGINS=0`, for UNIX platforms, this
+is set to 1 by default.  This causes the enabled event lib support to each be built into
+its own dynamically linked plugin, and lws will bring in the requested support alone
+at runtime after seeing the `info->options` flags requested by the user code.
+
+This has two main benefits, first the conflict around building libevent and libev
+together is removed, they each build isolated in their own plugin; the libwebsockets
+core library build doesn't import any of their headers (see below for exception).
+And second, for distro packaging, the event lib support plugins can be separately
+packaged, and apps take dependencies on the specific event lib plugin package, which
+itself depends on the libwebsockets core library.  This allows just the needed
+dependencies for the packageset without forcing everything to bring everything in.
+
+Separately, lws itself has some optional dependencies on libuv, if you build lwsws
+or on Windows you want plugins at all.  CMake will detect these situations and
+select to link the lws library itself to libuv if so as well, independent of whatever
+is happening with the event lib support.
+
+## evlib plugin install
+
+The produced plugins are named
+
+event lib|plugin name
+---|---
+glib|`libwebsockets-evlib_glib.so`
+event|`libwebsockets-evlib_event.so`
+uv|`libwebsockets-evlib_uv.so`
+ev|`libwebsockets-evlib_ev.so`
+
+The evlib plugins are installed alongside libwebsockets.so/.a into the configured
+library dir, it's often `/usr/local/lib/` by default on linux.
+
+Lws looks for them at runtime using the build-time-configured path.
+
+## Component packaging
+
+The canonical package name is `libwebsockets`, the recommended way to split the
+packaging is put the expected libs and pkgconfig in `libwebsockets` or `libwebsockets-core`,
+the latter is followed by the provided cmake, and produce an additional package per build
+event library plugin, named, eg `libwebsockets-evlib_glib`, which has a dependency on
+`libwebsockets[-core]`.
+
+Applications that use the default event loop can directly require `libwebsockets[-core]`,
+and application packages that need specific event loop support can just require, eg,
+`libwebsockets-evlib_glib`, which will bring that in and the core lws pieces in one step.
+There is then no problem with multiple apps requiring different event libs, they will
+bring in all the necessary pieces which will not conflict either as packages or at
+runtime.
+
+## `LWS_WITH_DISTRO_RECOMMENDED`
+
+The cmake helper config `LWS_WITH_DISTRO_RECOMMENDED` is adapted to build all the
+event libs with the event lib plugin support enabled.
+
diff --git a/READMEs/README.event-loops-intro.md b/READMEs/README.event-loops-intro.md
new file mode 100644 (file)
index 0000000..35b5161
--- /dev/null
@@ -0,0 +1,285 @@
+# Considerations around Event Loops
+
+Much of the software we use is written around an **event loop**.  Some examples
+
+ - Chrome / Chromium, transmission, tmux, ntp SNTP... [libevent](https://libevent.org/)
+ - node.js / cjdns / Julia / cmake ... [libuv](https://archive.is/64pOt)
+ - Gstreamer, Gnome / GTK apps ... [glib](https://people.gnome.org/~desrt/glib-docs/glib-The-Main-Event-Loop.html)
+ - SystemD ... sdevent
+ - OpenWRT ... uloop
+
+Many applications roll their own event loop using poll() or epoll() or similar,
+using the same techniques.  Another set of apps use message dispatchers that
+take the same approach, but are for cases that don't need to support sockets.
+Event libraries provide crossplatform abstractions for this functoinality, and
+provide the best backend for their event waits on the platform automagically.
+
+libwebsockets networking operations require an event loop, it provides a default
+one for the platform (based on poll() for Unix) if needed, but also can natively
+use any of the event loop libraries listed above, including "foreign" loops
+already created and managed by the application.
+
+## What is an 'event loop'?
+
+Event loops have the following characteristics:
+
+ - they have a **single thread**, therefore they do not require locking
+ - they are **not threadsafe**
+ - they require **nonblocking IO**
+ - they **sleep** while there are no events (aka the "event wait")
+ - if one or more event seen, they call back into user code to handle each in
+   turn and then return to the wait (ie, "loop")
+
+### They have a single thread
+
+By doing everything in turn on a single thread, there can be no possibility of
+conflicting access to resources from different threads... if the single thread
+is in callback A, it cannot be in two places at the same time and also in
+callback B accessing the same thing: it can never run any other code
+concurrently, only sequentially, by design.
+
+It means that all mutexes and other synchronization and locking can be
+eliminated, along with the many kinds of bugs related to them.
+
+### They are not threadsafe
+
+Event loops mandate doing everything in a single thread.  You cannot call their
+apis from other threads, since there is no protection against reentrancy.
+
+Lws apis cannot be called safely from any thread other than the event loop one,
+with the sole exception of `lws_cancel_service()`.
+
+### They have nonblocking IO
+
+With blocking IO, you have to create threads in order to block them to learn
+when your IO could proceed.  In an event loop, all descriptors are set to use
+nonblocking mode, we only attempt to read or write when we have been informed by
+an event that there is something to read, or it is possible to write.
+
+So sacrificial, blocking discrete IO threads are also eliminated, we just do
+what we should do sequentially, when we get the event indicating that we should
+do it.
+
+### They sleep while there are no events
+
+An OS "wait" of some kind is used to sleep the event loop thread until something
+to do.  There's an explicit wait on file descriptors that have pending read or
+write, and also an implicit wait for the next scheduled event.  Even if idle for
+descriptor events, the event loop will wake and handle scheduled events at the
+right time.
+
+In an idle system, the event loop stays in the wait and takes 0% CPU.
+
+### If one or more event, they handle them and then return to sleep
+
+As you can expect from "event loop", it is an infinite loop alternating between
+sleeping in the event wait and sequentially servicing pending events, by calling
+callbacks for each event on each object.
+
+The callbacks handle the event and then "return to the event loop".  The state
+of things in the loop itself is guaranteed to stay consistent while in a user
+callback, until you return from the callback to the event loop, when socket
+closes may be processed and lead to object destruction.
+
+Event libraries like libevent are operating the same way, once you start the
+event loop, it sits in an inifinite loop in the library, calling back on events
+until you "stop" or "break" the loop by calling apis.
+
+## Why are event libraries popular?
+
+Developers prefer an external library solution for the event loop because:
+
+ - the quality is generally higher than self-rolled ones.  Someone else is
+   maintaining it, a fulltime team in some cases.
+ - the event libraries are crossplatform, they will pick the most effective
+   event wait for the platform without the developer having to know the details.
+   For example most libs can conceal whether the platform is windows or unix,
+   and use native waits like epoll() or WSA accordingly.
+ - If your application uses a event library, it is possible to integrate very
+   cleanly with other libraries like lws that can use the same event library.
+   That is extremely messy or downright impossible to do with hand-rolled loops.
+
+Compared to just throwing threads on it
+
+ - thread lifecycle has to be closely managed, threads must start and must be
+   brought to an end in a controlled way.  Event loops may end and destroy
+   objects they control at any time a callback returns to the event loop.
+
+ - threads may do things sequentially or genuinely concurrently, this requires
+   locking and careful management so only deterministic and expected things
+   happen at the user data.
+
+ - threads do not scale well to, eg, serving tens of thousands of connections;
+   web servers use event loops.
+
+## Multiple codebases cooperating on one event loop
+
+The ideal situation is all your code operates via a single event loop thread.
+For lws-only code, including lws_protocols callbacks, this is the normal state
+of affairs.
+
+When there is other code that also needs to handle events, say already existing
+application code, or code handling a protocol not supported by lws, there are a
+few options to allow them to work together, which is "best" depends on the
+details of what you're trying to do and what the existing code looks like.
+In descending order of desirability:
+
+### 1) Use a common event library for both lws and application code
+
+This is the best choice for Linux-class devices.  If you write your application
+to use, eg, a libevent loop, then you only need to configure lws to also use
+your libevent loop for them to be able to interoperate perfectly.  Lws will
+operate as a guest on this "foreign loop", and can cleanly create and destroy
+its context on the loop without disturbing the loop.
+
+In addition, your application can merge and interoperate with any other
+libevent-capable libraries the same way, and compared to hand-rolled loops, the
+quality will be higher.
+
+### 2) Use lws native wsi semantics in the other code too
+
+Lws supports raw sockets and file fd abstractions inside the event loop.  So if
+your other code fits into that model, one way is to express your connections as
+"RAW" wsis and handle them using lws_protocols callback semantics.
+
+This ties the application code to lws, but it has the advantage that the
+resulting code is aware of the underlying event loop implementation and will
+work no matter what it is.
+
+### 3) Make a custom lws event lib shim for your custom loop
+
+Lws provides an ops struct abstraction in order to integrate with event
+libraries, you can find it in ./includes/libwebsockets/lws-eventlib-exports.h.
+
+Lws uses this interface to implement its own event library plugins, but you can
+also use it to make your own customized event loop shim, in the case there is
+too much written for your custom event loop to be practical to change it.
+
+In other words this is a way to write a customized event lib "plugin" and tell
+the lws_context to use it at creation time.  See [minimal-http-server.c](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/http-server/minimal-http-server-eventlib-custom/minimal-http-server.c)
+
+### 4) Cooperate at thread level
+
+This is less desirable because it gives up on unifying the code to run from a
+single thread, it means the codebases cannot call each other's apis directly.
+
+In this scheme the existing threads do their own thing, lock a shared
+area of memory and list what they want done from the lws thread context, before
+calling `lws_cancel_service()` to break the lws event wait.  Lws will then
+broadcast a `LWS_CALLBACK_EVENT_WAIT_CANCELLED` protocol callback, the handler
+for which can lock the shared area and perform the requested operations from the
+lws thread context.
+
+### 5) Glue the loops together to wait sequentially (don't do this)
+
+If you have two or more chunks of code with their own waits, it may be tempting
+to have them wait sequentially in an outer event loop.  (This is only possible
+with the lws default loop and not the event library support, event libraries
+have this loop inside their own `...run(loop)` apis.)
+
+```
+       while (1) {
+               do_lws_wait(); /* interrupted at short intervals */
+               do_app_wait(); /* interrupted at short intervals */
+       }
+```
+
+This never works well, either:
+
+ - the whole thing spins at 100% CPU when idle, or
+
+ - the waits have timeouts where they sleep for short periods, but then the
+   latency to service on set of events is increased by the idle timeout period
+   of the wait for other set of events
+
+## Common Misunderstandings
+
+### "Real Men Use Threads"
+
+Sometimes you need threads or child processes.  But typically, whatever you're
+trying to do does not literally require threads.  Threads are an architectural
+choice that can go either way depending on the goal and the constraints.
+
+Any thread you add should have a clear reason to specifically be a thread and
+not done on the event loop, without a new thread or the consequent locking (and
+bugs).
+
+### But blocking IO is faster and simpler
+
+No, blocking IO has a lot of costs to conceal the event wait by blocking.
+
+For any IO that may wait, you must spawn an IO thread for it, purely to handle
+the situation you get blocked in read() or write() for an arbitrary amount of
+time.  It buys you a simple story in one place, that you will proceed on the
+thread if read() or write() has completed, but costs threads and locking to get
+to that.
+
+Event loops dispense with the threads and locking, and still provide a simple
+story, you will get called back when data arrives or you may send.
+
+Event loops can scale much better, a busy server with 50,000 connections active
+does not have to pay the overhead of 50,000 threads and their competing for
+locking.
+
+With blocked threads, the thread can do no useful work at all while it is stuck
+waiting.  With event loops the thread can service other events until something
+happens on the fd.
+
+### Threads are inexpensive
+
+In the cases you really need threads, you must have them, or fork off another
+process.  But if you don't really need them, they bring with them a lot of
+expense, some you may only notice when your code runs on constrained targets
+
+ - threads have an OS-side footprint both as objects and in the scheduler
+
+ - thread context switches are not slow on modern CPUs, but have side effects
+   like cache flushing
+
+ - threads are designed to be blocked for arbitrary amounts of time if you use
+   blocking IO apis like write() or read().  Then how much concurrency is really
+   happening?  Since blocked threads just go away silently, it is hard to know
+   when in fact your thread is almost always blocked and not doing useful work.
+
+ - threads require their own stack, which is on embedded is typically suffering
+   from a dedicated worst-case allocation where the headroom is usually idle
+
+ - locking must be handled, and missed locking or lock order bugs found
+
+### But... what about latency if only one thing happens at a time?
+
+ - Typically, at CPU speeds, nothing is happening at any given time on most
+   systems, the event loop is spending most of its time in the event wait
+   asleep at 0% cpu.
+
+ - The POSIX sockets layer is disjoint from the actual network device driver.
+   It means that once you hand off the packet to the networking stack, the POSIX
+   api just returns and leaves the rest of the scheduling, retries etc to the
+   networking stack and device, descriptor queuing is driven by interrupts in
+   the driver part completely unaffected by the event loop part.
+
+ - Passing data around via POSIX apis between the user code and the networking
+   stack tends to return almost immediately since its onward path is managed
+   later in another, usually interrupt, context.
+
+ - So long as enough packets-worth of data are in the network stack ready to be
+   handed to descriptors, actual throughput is completely insensitive to jitter
+   or latency at the application event loop
+
+ - The network device itself is inherently serializing packets, it can only send
+   one thing at a time.  The networking stack locking also introduces hidden
+   serialization by blocking multiple threads.
+
+ - Many user systems are decoupled like the network stack and POSIX... the user
+   event loop and its latencies do not affect backend processes occurring in
+   interrupt or internal thread or other process contexts
+
+## Conclusion
+
+Event loops have been around for a very long time and are in wide use today due
+to their advantages.  Working with them successfully requires understand how to
+use them and why they have the advantages and restrictions they do.
+
+The best results come from all the participants joining the same loop directly.
+Using a common event library in the participating codebases allows completely
+different code can call each other's apis safely without locking.
diff --git a/READMEs/README.fault-injection.md b/READMEs/README.fault-injection.md
new file mode 100644 (file)
index 0000000..7810679
--- /dev/null
@@ -0,0 +1,358 @@
+# `lws_fi` Fault Injection
+
+Most efforts during development go towards trying to make the system do what
+it is supposed to do during normal operation.
+
+But to provide reliable quality there's a need to not just test the code paths
+for normal operation, but also to be able to easily confirm that they act
+correctly under various fault conditions that may be difficult to arrange at
+test-time. It's otherwise very easy for error conditions that are low
+probability to be overlooked and turn out to do the wrong thing, eg, try to
+clean up things they had not actually initialized, or forget to free things etc.
+
+Code handling the operational failures we want to check may be anywhere,
+including during early initialization or in user code before lws intialization.
+
+To help with this lws has a `LWS_WITH_SYS_FAULT_INJECTION` build option that
+provides a simple but powerful api for targeted fault injection in any lws or
+user code, and provides a wide range of well-known internal faults inside lws
+you can trigger from outside.
+
+## Fault contexts and faults
+
+The basic idea is objects in the user code can choose to initialize "fault
+contexts" inside objects, that list named, well-known "faults" that the code
+supoorts and that the user wants to inject.
+
+Although these "fault contexts" can be embedded in objects directly at object
+creation time, eg, for lws in the lws_context creation info struct, or the
+client connection info struct, or Secure Stream info struct, it's usually
+inconvenient to pass the desired faults directly deep into the code and attach
+them at creation time.  Eg, if you want to cause a fault in a wsi instantiated
+by a Secure Stream, that is internal lws code one step removed from the Secure
+Stream object creation making it difficult to arrange.
+
+For that reason, faults have a targeted inheritance scheme using namespace
+paths, it's usually enough to just list the faults you want at context creation
+time and they will be filter down to the internal objects you want to target
+when they are created later.
+
+![Fault Injection Overview](../doc-assets/fault-injection.png)
+
+A fault injection request is made in `lws_fi_t` objects, specifying the
+fault name and whether, and how often to inject the fault.
+
+The "fault context" objects `lws_fi_ctx_t` embedded in the creation info
+structs are linked-lists of `lws_fi_t` objects.  When Fault Injection is enabled
+at build-time, the key system objects like the `lws_context`, `lws_vhost`, `wsi`
+and Secure Stream handles / SSPC handles contain their own `lws_fi_ctx_t` lists
+that may have any number of `lws_fi_t` added to them.
+
+When downstream objects are created, eg, when an lws_context creates a Secure
+Stream, in addition to using any faults provided directly in the SS info,
+the lws_context faults are consulted to see if any relate to that streamtype
+and should be applied.
+
+Although faults can be added to objects at creation, it is far more convenient
+to just pass a list of faults you want into the lws_context and have the
+objects later match them using namespacing, described later.
+
+## Integrating fault injection conditionals into code in private lws code
+
+A simple query api `lws_fi(fi_ctx, "name")` is provided that returns 0 if no
+fault to be injected, or 1 if the fault should be synthesized.  If there is no
+rule matching "name", the answer is always to not inject a fault, ie, returns 0.
+
+Similarly for convenience if FAULT_INJECTION is disabled at build, the `lws_fi()`
+call always returns the constant `0`.
+
+By default then just enabling Fault Injection at build does not have any impact
+on code operation since the user must also add the fault injection rules he
+wants to the objects's Fault Injection context.
+
+## Integrating fault injection conditionals into user code with public apis
+
+These public apis query the fault context in a wsi, lws_context, ss handle, or
+sspc handle (client side of proxy) to find any matching rule, if so they return
+1 if the conditions (eg, probability) are met and the fault should be injected.
+
+These allow user code to use the whole Fault Injection system without having to
+understand anything except the common object like a wsi they want to query and
+the name of the fault rule they are checking.
+
+|FI context owner|Public API|
+|---|---|
+|lws_context|`int lws_fi_user_context_fi(struct lws_context *ctx, const char *rule)`|
+|wsi|`int lws_fi_user_wsi_fi(struct lws *wsi, const char *rule)`|
+|ss handle|`int lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *rule)`|
+|sspc handle|`int lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *rule)`|
+
+For example, the minimal-http-client user code example contains this in its
+ESTABLISHED callback
+
+```
+               if (lws_fi_user_wsi_fi(wsi, "user_reject_at_est"))
+                       return -1;
+```
+
+which can be triggered by running it with
+
+`lws-minimal-http-client --fault-injection 'wsi/user_reject_at_est'`, causing
+
+```
+...
+[2021/03/11 13:41:05:2769] U: Connected to 46.105.127.147, http response: 200
+[2021/03/11 13:41:05:2776] W: lws_fi: Injecting fault unk->user_reject_at_est
+[2021/03/11 13:41:05:2789] E: CLIENT_CONNECTION_ERROR: HS: disallowed at ESTABLISHED
+...
+```
+
+When `LWS_WITH_SYS_FAULT_INJECTION` is disabled, these public apis become
+preprocessor defines to `(0)`, so the related code is removed by the compiler.
+
+## Types of fault injection "when" strategy
+
+The api keeps track of each time the context was asked and uses this information
+to drive the decision about when to say yes, according to the type of rule
+
+|Injection rule type|Description|
+|---|---|
+|`LWSFI_ALWAYS`|Unconditionally inject the fault|
+|`LWSFI_DETERMINISTIC`|after `pre` times without the fault, the next `count` times exhibit the fault`|
+|`LWSFI_PROBABILISTIC`|exhibit a fault `pre` percentage of the time|
+|`LWSFI_PATTERN`|Reference `pre` bits pointed to by `pattern` and fault if the bit set, pointing to static array|
+|`LWSFI_PATTERN_ALLOC`|Reference `pre` bits pointed to by `pattern` and fault if the bit set, pointing to allocated array, freed when fault goes out of scope|
+
+Probabalistic choices are sourced from a PRNG with a seed set in the context
+creation info Fault Injection Context.  By default the lws helper
+`lws_cmdline_option_handle_builtin()` sets this to the time in us, but it can
+be overridden using `--fault-seed <decimal>`, and the effective PRNG seed is
+logged when the commandline options are initially parsed.
+
+## Addings Fault Injection Rules to `lws_fi_ctx_t`
+
+Typically the lws_context is used as the central, toplevel place to define
+faults.  This is done by adding prepared `lws_fi_t` objects on the stack one by
+one to the context creation info struct's `.fic` member, using
+`lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi);`, this will allocate and copy
+the provided `fi` into the allocation, and attach it to the `lws_fi_ctx_t` list.
+
+When the context (or other object using the same scheme) is created, it imports
+all the faults from the info structure `.fic` and takes ownership of them,
+leaving the info `.fic` empty and ready to go out of scope.
+
+## Passing in fault injection rules
+
+A key requirement is that Fault Injection rules must be availble to the code
+creating an object before the object has been created.  This is why the user
+code prepares a Fault Injection context listing his rules in the creation info
+struct, rather than waiting for the object to be created and then attach Fault
+Injection rules... it's too late then to test faults during the creation.
+
+## Directly applying fault contexts
+
+You can pass in a Fault Injection context prepared with lws_fi_t added to it
+when creating the following kinds of objects
+
+|Object being created|info struct|Fault injection Context member|
+|---|---|---|
+|lws context|struct lws_context_creation_info|`fic`|
+|vhost|struct lws_context_creation_info|`fic`|
+|Secure Stream|struct lws_ss_info|`fic`|
+|client wsi|struct lws_client_connect_info|`fic`|
+
+However typically the approach is just provide a list of faults at context
+creation time, and let the objects match and inherit using namespacing,
+described next.
+
+## Using the namespace to target specific instances
+
+Lws objects created by the user can directly have a Fault Injection context
+attached to them at creation time, so the fault injection objects directly
+relate to the object.
+
+But in other common scenarios, there is no direct visibility of the object that
+we want to trigger faults in, it may not exist until some time later.  Eg, we
+want to trigger faults in the listen socket of a vhost.  To allow this, the
+fault names can be structured with a /path/ type namespace so objects created
+later can inherit faults.
+
+Notice that if you are directly creating the vhost, Secure Stream or wsi, you
+can directly attach the subrule yourself without the namespacing needed.  The
+namespacing is used when you have access to a higher level object at creation-
+time, like the lws_context, and it will itself create the object you want to
+target without your having any direct access to it.
+
+|namespace form|effect|
+|---|---|
+|**vh=myvhost/**subrule|subrule is inherited by the vhost named "myvhost" when it is created|
+|**vh/**subrule|subrule is inherited by any vhost when it is created|
+|**ss=mystream/**subrule|subrule is inherited by SS of streamtype "mystream" (also covers SSPC / proxy client)|
+|**ss/**subrule|subrule is inherited by all SS of any streamtype (also covers SSPC / proxy client)|
+|**wsi=myname/**subrule|subrule is inherited by client wsi created with `info->fi_wsi_name` "myname"|
+|**wsi/**subrule|subrule is inherited by any wsi|
+
+Namespaces can be combined, for example `vh=myvhost/wsi/listenskt` will set the
+`listenskt` fault on wsi created by the server vhost "myvhost", ie, it will
+cause the listen socket for the vhost to error out on creation.
+
+In the case of wsi migration when it's the network connection wsi on an h2
+connection that is migrated to be SID 1, the attached faults also migrate.
+
+Here is which Fault Injection Contexts each type of object inherits matching
+Fault Injection rules from:
+
+|Object type|Initialized with|Inherit matching faults from|
+|---|---|---|
+|context|`struct lws_context_creation_info` .fic|-|
+|vhost|`struct lws_context_creation_info` .fic|context FIC|
+|client wsi|`struct lws_client_connect_info` .fic|context FIC, vhost FIC|
+|ss / sspc|`lws_ss_info_t` .fic|context FIC|
+|ss / sspc wsi|-|context FIC, vhost FIC, ss / sspc .fic|
+
+Since everything can be reached from the lws_context fault context, directly or
+by additional inheritence, and that's the most convenient to set from the
+outside, that's typically the original source of all injected faults.
+
+## Integration with minimal examples
+
+All the minimal examples that use the `lws_cmdline_option_handle_builtin()` api
+can take an additional `--fault-injection "...,..."` switch, which automatically
+parses the comma-separated list in the argument to add faults with the given
+name to the lws_context.  For example,
+
+`lws-minimal-http-client --fault-injection "wsi/dnsfail"`
+
+will force all wsi dns lookups to fail for that run of the example.
+
+### Specifying when to inject the fault
+
+By default, if you just give the name part, if the namespace is absent or
+matches an object, the fault will be injected every time.  It's also possible
+to make the fault inject itself at a random probability, or in a cyclic pattern,
+by giving additional information in brackets, eg
+
+|Syntax|Used with|Meaning|
+|---|---|---|
+|`wsi/thefault`|lws_fi()|Inject the fault every time|
+|`wsi/thefault(10%)`|lws_fi()|Randomly inject the fault at 10% probability|
+|`wsi/thefault(.............X.X)`|lws_fi()|Inject the fault on the 14th and 16th try, every 16 tries|
+|`wsi/thefault2(123..456)`|lws_fi_range()|Pick a number between 123 and 456|
+
+You must quote the strings containing these symbols, since they may otherwise be
+interpreted by your shell.
+
+The last example above does not decide whether to inject the fault via `lws_fi()`
+like the others.  Instead you can use it via `lws_fi_range()` as part of the
+fault processing, on a secondary fault injection name.  For example you may have
+a fault `myfault` you use with `lws_fi()` to decide when to inject the fault,
+and then a second, related fault name `myfault_delay` to allow you to add code
+to delay the fault action by some random amount of ms within an externally-
+given range.  You can get a pseudo-random number within the externally-given
+range by calling `lws_fi_range()` on `myfault_delay`, and control the whole
+thing by giving, eg, `"myfault(10%),myfault_delay(123..456)"`
+
+## Well-known fault names in lws
+
+|Scope|Namespc|Name|Fault effect|
+|---|---|---|---|
+|context||`ctx_createfail1`|Fail context creation immediately at entry|
+|context||`ctx_createfail_plugin_init`|Fail context creation as if a plugin init failed (if plugins enabled)|
+|context||`ctx_createfail_evlib_plugin`|Fail context creation due to event lib plugin failed init (if evlib plugins enabled)|
+|context||`ctx_createfail_evlib_sel`|Fail context creation due to unable to select event lib|
+|context||`ctx_createfail_oom_ctx`|Fail context creation due to OOM on context object|
+|context||`ctx_createfail_privdrop`|Fail context creation due to failure dropping privileges|
+|context||`ctx_createfail_maxfds`|Fail context creation due to unable to determine process fd limit|
+|context||`ctx_createfail_oom_fds`|Fail context creation due to OOM on fds table|
+|context||`ctx_createfail_plat_init`|Fail context creation due to platform init failed|
+|context||`ctx_createfail_evlib_init`|Fail context creation due to event lib init failed|
+|context||`ctx_createfail_evlib_pt`|Fail context creation due to event lib pt init failed|
+|context||`ctx_createfail_sys_vh`|Fail context creation due to system vhost creation failed|
+|context||`ctx_createfail_sys_vh_init`|Fail context creaton due to system vhost init failed|
+|context||`ctx_createfail_def_vh`|Fail context creation due to default vhost creation failed|
+|context||`ctx_createfail_ss_pol1`|Fail context creation due to ss policy parse start failed (if policy enabled)|
+|context||`ctx_createfail_ss_pol2`|Fail context creation due to ss policy parse failed (if policy enabled)|
+|context||`ctx_createfail_ss_pol3`|Fail context creation due to ss policy set failed (if policy enabled)|
+|context||`cache_createfail`|Fail `lws_cache` creation due to OOM|
+|context||`cache_lookup_oom`|Fail `lws_cache` lookup due to OOM|
+|vhost|`vh`|`vh_create_oom`|Fail vh creation on vh object alloc OOM|
+|vhost|`vh`|`vh_create_oom`|Fail vh creation on vh object alloc OOM|
+|vhost|`vh`|`vh_create_pcols_oom`|Fail vh creation at protocols alloc OOM|
+|vhost|`vh`|`vh_create_access_log_open_fail`|Fail vh creation due to unable to open access log (LWS_WITH_ACCESS_LOG)|
+|vhost|`vh`|`vh_create_ssl_srv`|Fail server ssl_ctx init|
+|vhost|`vh`|`vh_create_ssl_cli`|Fail client ssl_ctx init|
+|vhost|`vh`|`vh_create_srv_init`|Fail server init|
+|vhost|`vh`|`vh_create_protocol_init`|Fail late protocol init (for late vhost creation)|
+|srv vhost|`vh=xxx/wsi`|`listenskt`|Causes `socket()` allocation for vhost listen socket to fail|
+|cli wsi|`wsi`|`dnsfail`|Sync: `getaddrinfo()` is not called and a EAI_FAIL return synthesized, Async: request not started and immediate fail synthesized|
+|cli wsi|`wsi`|`sendfail`|Attempts to send data on the wsi socket fail|
+|cli wsi|`wsi`|`connfail`|Attempts to connect on the wsi socket fail|
+|cli wsi|`wsi`|`createfail`|Creating the client wsi itself fails|
+|udp wsi|`wsi`|`udp_rx_loss`|Drop UDP RX that was actually received, useful with probabalistic mode|
+|udp wsi|`wsi`|`udp_tx_loss`|Drop UDP TX so that it's not actually sent, useful with probabalistic mode|
+|srv ss|`ss`|`ss_srv_vh_fail`|Secure Streams Server vhost creation forced to fail|
+|cli ss|`ss`|`ss_no_streamtype_policy`|The policy for the streamtype is made to seem as if it is missing|
+|sspc|`ss`|`sspc_fail_on_linkup`|Reject the connection to the proxy when we hear it has succeeded, it will provoke endless retries|
+|sspc|`ss`|`sspc_fake_rxparse_disconnect_me`|Force client-proxy link parse to seem to ask to be disconnected, it will provoke endless retries|
+|sspc|`ss`|`sspc_fake_rxparse_destroy_me`|Force client-proxy link parse to seem to ask to destroy the SS, it will destroy the SS cleanly|
+|sspc|`ss`|`sspc_link_write_fail`|Force write on the link to fail, it will provoke endless retries|
+|sspc|`ss`|`sspc_create_oom`|Cause the sspc handle allocation to fail as if OOM at creation time|
+|sspc|`ss`|`sspc_fail_metadata_set`|Cause the metadata allocation to fail|
+|sspc|`ss`|`sspc_rx_fake_destroy_me`|Make it seem that client's user code *rx() returned DESTROY_ME|
+|sspc|`ss`|`sspc_rx_metadata_oom`|Cause metadata from proxy allocation to fail|
+|ssproxy|`ss`|`ssproxy_dsh_create_oom`|Cause proxy's creation of DSH to fail|
+|ssproxy|`ss`|`ssproxy_dsh_rx_queue_oom`|Cause proxy's allocation in the onward SS->P[->C] DSH rx direction to fail as if OOM, this causes the onward connection to disconnect|
+|ssproxy|`wsi`|`ssproxy_client_adopt_oom`|Cause proxy to be unable to allocate for new client - proxy link connection object|
+|ssproxy|`wsi`|`ssproxy_client_write_fail`|Cause proxy write to client to fail|
+|ssproxy|`wsi`|`sspc_dsh_ss2p_oom`|Cause ss->proxy dsh allocation to fail|
+|ssproxy|`ss`|`ssproxy_onward_conn_fail`|Act as if proxy onward client connection failed immediately|
+|ssproxy|`ss`|`ssproxy_dsh_c2p_pay_oom`|Cause proxy's DSH alloc for C->P payload to fail|
+|ss|`ss`|`ss_create_smd`|SMD: ss creation smd registration fail|
+|ss|`ss`|`ss_create_vhost`|Server: ss creation acts like no vhost matching typename (only for `!vhost`)|
+|ss|`ss`|`ss_create_pcol`|Server: ss creation acts like no protocol given in policy|
+|ss|`ss`|`ss_srv_vh_fail`|Server: ss creation acts like unable to create vhost|
+|ss|`ss`|`ss_create_destroy_me`|ss creation acts like CREATING state returned DESTROY_ME|
+|ss|`ss`|`ss_create_no_ts`|Static Policy: ss creation acts like no trust store|
+|ss|`ss`|`ss_create_smd_1`|SMD: ss creation acts like CONNECTING said DESTROY_ME|
+|ss|`ss`|`ss_create_smd_2`|SMD: ss creation acts like CONNECTED said DESTROY_ME|
+|ss|`ss`|`ss_create_conn`|Nailed up: ss creation client connection fails with DESTROY_ME|
+|wsi|`wsi`|`timedclose`|(see next) Cause wsi to close after some time|
+|wsi|`wsi`|`timedclose_ms`|Range of ms for timedclose (eg, "timedclose_ms(10..250)"|
+
+## Well-known namespace targets
+
+Namespaces can be used to target these more precisely, for example even though
+we are only passing the faults we want inject at the lws_context, we can use
+the namespace "paths" to target only the wsis created by other things.
+
+To target wsis from SS-based connections, you can use `ss=stream_type_name/`,
+eg for captive portal detection, to have it unable to find its policy entry:
+
+`ss=captive_portal_detect/ss_no_streamtype_policy` (disables CPD from operating)
+
+...to force it to fail to resolve the server DNS:
+
+`ss=captive_portal_detect/wsi/dnsfail` (this makes CPD feel there is no internet)
+
+...to target the connection part of the captive portal testing instead:
+
+`ss=captive_portal_detect/wsi/connfail` (this also makes CPD feel there is no internet)
+
+### Well-known internal wsi type names
+
+Wsi created for internal features like Async DNS processing can also be targeted
+
+|wsi target|Meaning|
+|---|---|
+|`wsi=asyncdns/`|UDP wsi used by lws Async DNS support to talk to DNS servers|
+|`wsi=dhcpc/`|UDP wsi used by lws DHCP Client|
+|`wsi=ntpclient/`|UDP wsi used by lws NTP Client|
+
+For example, passing in at lws_context level `wsi=asyncdns/udp_tx_loss`
+will force async dns to be unable to resolve anything since its UDP tx is
+being suppressed.
+
+At client connection creation time, user code can also specify their own names
+to match on these `wsi=xxx/` namespace parts, so the faults only apply to
+specific wsi they are creating themselves later.  This is done by setting the
+client creation info struct `.fi_wsi_name` to the string "xxx".
diff --git a/READMEs/README.generic-sessions.md b/READMEs/README.generic-sessions.md
deleted file mode 100644 (file)
index 376342a..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-Notes about generic-sessions Plugin
-===================================
-
-@section gseb Enabling lwsgs for build
-
-Enable at CMake with -DLWS_WITH_GENERIC_SESSIONS=1
-
-This also needs sqlite3 (libsqlite3-dev or similar package)
-
-
-@section gsi lwsgs Introduction
-
-The generic-sessions protocol plugin provides cookie-based login
-authentication for lws web and ws connections.
-
-The plugin handles everything about generic account registration,
-email verification, lost password, account deletion, and other generic account
-management.
-
-Other code, in another eg, ws protocol handler, only needs very high-level
-state information from generic-sessions, ie, which user the client is
-authenticated as.  Everything underneath is managed in generic-sessions.
-
-
- - random 20-byte session id managed in a cookie
-
- - all information related to the session held at the server, nothing managed clientside
-
- - sqlite3 used at the server to manage active sessions and users
-
- - defaults to creating anonymous sessions with no user associated
-
- - admin account (with user-selectable username) is defined in config with a SHA-1 of the password; rest of the accounts are in sqlite3
- - user account passwords stored as salted SHA-1 with additional confounder
-  only stored in the JSON config, not the database 
-
- - login, logout, register account + email verification built-in with examples
-
- - in a mount, some file suffixes (ie, .js) can be associated with a protocol for the purposes of rewriting symbolnames.  These are read-only copies of logged-in server state.
-
- - When your page fetches .js or other rewritten files from that mount, "$lwsgs_user" and so on are rewritten on the fly using chunked transfer encoding
-
- - Eliminates server-side scripting with a few rewritten symbols and
- javascript on client side
-
- - 32-bit bitfield for authentication sectoring, mounts can provide a mask on the loggin-in session's associated server-side bitfield that must be set for access.
-
- - No code (just config) required for, eg, private URL namespace that requires login to access. 
-
-@section gsin Lwsgs Integration to HTML
-
-Only three steps are needed to integrate lwsgs in your HTML.
-
-1) lwsgs HTML UI is bundled with the javascript it uses in `lwsgs.js`, so
-import that script file in your head section
-
-2) define an empty div of id "lwsgs" somewhere
-
-3) Call lwsgs_initial() in your page
-
-That's it.  An example is below
-
-```
-       <html>
-        <head>
-         <script src="lwsgs.js"></script>
-         <style>
-            .body { font-size: 12 }
-            .gstitle { font-size: 18 }
-         </style>
-         </head>
-         <body style="background-image:url(seats.jpg)">
-           <table style="width:100%;transition: max-height 2s;">
-            <tr>
-             <td style="vertical-align:top;text-align:left;width=200px">
-              <img src="lwsgs-logo.png">
-             </td>
-             <td style="vertical-align:top;float:right">
-               <div id=lwsgs style="text-align:right;background-color: rgba(255, 255, 255, 0.8);"></div>
-             </td>
-            </tr>
-           </table>
-          </form>
-          
-          <script>lwsgs_initial();</script>
-       
-        </body>
-       </html>
-```
-
-@section gsof Lwsgs Overall Flow@
-
-When the protocol is initialized, it gets per-vhost information from the config, such
-as where the sqlite3 databases are to be stored.  The admin username and sha-1 of the
-admin password are also taken from here.
-
-In the mounts using protocol-generic-sessions, a cookie is maintained against any requests; if no cookie was active on the initial request a new session is
-created with no attached user.
-
-So there should always be an active session after any transactions with the server.
-
-In the example html going to the mount /lwsgs loads a login / register page as the default.
-
-The <form> in the login page contains 'next url' hidden inputs that let the html 'program' where the form handler will go after a successful admin login, a successful user login and a failed login.
-
-After a successful login, the sqlite record at the server for the current session is updated to have the logged-in username associated with it. 
-
-
-
-@section gsconf Lwsgs Configuration
-
-"auth-mask" defines the authorization sector bits that must be enabled on the session to gain access.
-
-"auth-mask" 0 is the default.
-
-  - b0 is set if you are logged in as a user at all.
-  - b1 is set if you are logged in with the user configured to be admin
-  - b2 is set if the account has been verified (the account configured for admin is always verified)
-  - b3 is set if your session just did the forgot password flow successfully
-
-```
-             {
-               # things in here can always be served
-               "mountpoint": "/lwsgs",
-               "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions",
-               "origin": "callback://protocol-lws-messageboard",
-               "default": "generic-sessions-login-example.html",
-               "auth-mask": "0",
-               "interpret": {
-                       ".js": "protocol-lws-messageboard"
-               }
-              }, {
-               # things in here can only be served if logged in as a user
-               "mountpoint": "/lwsgs/needauth",
-               "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needauth",
-               "origin": "callback://protocol-lws-messageboard",
-               "default": "generic-sessions-login-example.html",
-               "auth-mask": "5", # logged in as a verified user
-               "interpret": {
-                       ".js": "protocol-lws-messageboard"
-               }
-              }, {
-               # things in here can only be served if logged in as admin
-               "mountpoint": "/lwsgs/needadmin",
-               "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needadmin",
-               "origin": "callback://protocol-lws-messageboard",
-               "default": "generic-sessions-login-example.html",
-               "auth-mask": "7", # b2 = verified (by email / or admin), b1 = admin, b0 = logged in with any user name
-               "interpret": {
-                       ".js": "protocol-lws-messageboard"
-               }
-              }
-```
-Note that the name of the real application protocol that uses generic-sessions
-is used, not generic-sessions itself. 
-
-The vhost configures the storage dir, admin credentials and session cookie lifetimes:
-
-```
-            "ws-protocols": [{
-              "protocol-generic-sessions": {
-                "status": "ok",
-                "admin-user": "admin",
-       
-       # create the pw hash like this (for the example pw, "jipdocesExunt" )
-       # $ echo -n "jipdocesExunt" | sha1sum
-       # 046ce9a9cca769e85798133be06ef30c9c0122c9 -
-       #
-       # Obviously ** change this password hash to a secret one before deploying **
-       #
-                "admin-password-sha1": "046ce9a9cca769e85798133be06ef30c9c0122c9",
-                "session-db": "/var/www/sessions/lws.sqlite3",
-                "timeout-idle-secs": "600",
-                "timeout-anon-idle-secs": "1200",
-                "timeout-absolute-secs": "6000",
-       # the confounder is part of the salted password hashes.  If this config
-       # file is in a 0700 root:root dir, an attacker with apache credentials
-       # will have to get the confounder out of the process image to even try
-       # to guess the password hashes.
-                "confounder": "Change to <=31 chars of junk",
-       
-                "email-from": "noreply@example.com",
-                "email-smtp-ip": "127.0.0.1",
-                "email-expire": "3600",
-                "email-helo": "myhost.com",
-                "email-contact-person": "Set Me <real-person@email.com>",
-                "email-confirm-url-base": "http://localhost:7681/lwsgs"
-              }
-```
-
-The email- related settings control generation of automatic emails for
-registration and forgotten password.
-
- - `email-from`: The email address automatic emails are sent from
-
- - `email-smtp-ip`: Normally 127.0.0.1, if you have a suitable server on port
-   25 on your lan you can use this instead here.
-
- - `email-expire`: Seconds that links sent in email will work before being
-   deleted
-
- - `email-helo`: HELO to use when communicating with your SMTP server
-
- - `email-contact-person`: mentioned in the automatic emails as a human who can
-   answer questions
-
- - `email-confirm-url-base`: the URL to start links with in the emails, so the
-   recipient can get back to the web server
-   
-The real protocol that makes use of generic-sessions must also be listed and
-any configuration it needs given
-
-```
-              "protocol-lws-messageboard": {
-                "status": "ok",
-                "message-db": "/var/www/sessions/messageboard.sqlite3"
-              },
-```
-
-Notice the real application uses his own sqlite db, no details about how
-generic-sessions works or how it stores data are available to it.
-
-
-@section gspwc Lwsgs Password Confounder
-
-You can also define a per-vhost confounder shown in the example above, used
-when aggregating the password with the salt when it is hashed.  Any attacker
-will also need to get the confounder along with the database, which you can
-make harder by making the config dir only eneterable / readable by root.
-
-
-@section gsprep Lwsgs Preparing the db directory
-
-You will have to prepare the db directory so it's suitable for the lwsws user to use,
-that usually means apache, eg
-
-```
-       # mkdir -p /var/www/sessions
-       # chown root:apache /var/www/sessions
-       # chmod 770 /var/www/sessions
-```
-
-@section gsrmail Lwsgs Email configuration
-
-lwsgs will can send emails by talking to an SMTP server on localhost:25.  That
-will usually be sendmail or postfix, you should confirm that works first by
-itself using the `mail` application to send on it.
-
-lwsgs has been tested on stock Fedora sendmail and postfix.
-
-
-@section gsap Lwsgs Integration with another protocol
-
-lwsgs is designed to provide sessions and accounts in a standalone and generic way.
-
-But it's not useful by itself, there will always be the actual application who wants
-to make use of generic-sessions features.
-
-We provide the "messageboard" plugin as an example of how to integrate with
-your actual application protocol.
-
-The basic approach is the 'real' protocol handler (usually a plugin itself)
-subclasses the generic-sessions plugin and calls through to it by default.
-
-The "real" protocol handler entirely deals with ws-related stuff itself, since
-generic-sessions does not use ws.  But for
-
- - LWS_CALLBACK_HTTP
- - LWS_CALLBACK_HTTP_BODY
- - LWS_CALLBACK_HTTP_BODY_COMPLETION
- - LWS_CALLBACK_HTTP_DROP_PROTOCOL
-the "real" protocol handler checks if it recognizes the activity (eg, his own
-POST form URL) and if not, passes stuff through to the generic-sessions protocol callback to handle it.  To simplify matters the real protocol can just pass
-through any unhandled messages to generic-sessions.
-
-The "real" protocol can get a pointer to generic-sessions protocol on the
-same vhost using
-
-```
-       vhd->gsp = lws_vhost_name_to_protocol(vhd->vh, "protocol-generic-sessions");
-```
-
-The "real" protocol must also arrange generic-sessions per_session_data in his
-own per-session allocation.  To allow keeping generic-sessions opaque, the
-real protocol must allocate that space at runtime, using the pss size
-the generic-sessions protocol struct exposes
-
-```
-       struct per_session_data__myapp {
-               void *pss_gs;
-       ...
-       
-               pss->pss_gs = malloc(vhd->gsp->per_session_data_size);
-```
-
-The allocation reserved for generic-sessions is then used as user_space when
-the real protocol calls through to the generic-sessions callback
-
-```
-       vhd->gsp->callback(wsi, reason, &pss->pss_gs, in, len);
-```
-
-In that way the "real" protocol can subclass generic-sessions functionality.
-
-
-To ease management of these secondary allocations, there are callbacks that
-occur when a wsi binds to a protocol and when the binding is dropped.  These
-should be used to malloc and free and kind of per-connection
-secondary allocations.
-
-```
-       case LWS_CALLBACK_HTTP_BIND_PROTOCOL:
-               if (!pss || pss->pss_gs)
-                       break;
-
-               pss->pss_gs = malloc(vhd->gsp->per_session_data_size);
-               if (!pss->pss_gs)
-                       return -1;
-
-               memset(pss->pss_gs, 0, vhd->gsp->per_session_data_size);
-               break;
-
-       case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
-               if (vhd->gsp->callback(wsi, reason, pss ? pss->pss_gs : NULL, in, len))
-                       return -1;
-
-               if (pss->pss_gs) {
-                       free(pss->pss_gs);
-                       pss->pss_gs = NULL;
-               }
-               break;
-```
-
-
-#section gsapsib Getting session-specific information from another protocol
-
-At least at the time when someone tries to upgrade an http(s) connection to
-ws(s) with your real protocol, it is necessary to confirm the cookie the http(s)
-connection has with generic-sessions and find out his username and other info.
-
-Generic sessions lets another protocol check it again by calling his callback,
-and lws itself provides a generic session info struct to pass the related data
-
-```
-       struct lws_session_info {
-               char username[32];
-               char email[100];
-               char ip[72];
-               unsigned int mask;
-               char session[42];
-       };
-
-       struct lws_session_info sinfo;
-       ...
-       vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO,
-                                  &pss->pss_gs, &sinfo, 0);
-```
-
-After the call to generic-sessions, the results can be
-
- -  all the strings will be zero-length and .mask zero, there is no usable cookie
-  - only .ip and .session are set: the cookie is OK but no user logged in
-  
-  - all the strings contain information about the logged-in user
-
-the real protocol can use this to reject attempts to open ws connections from
-http connections that are not authenticated; afterwards there's no need to
-check the ws connection auth status again.
-
diff --git a/READMEs/README.generic-table.md b/READMEs/README.generic-table.md
deleted file mode 100644 (file)
index 7a85809..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-Notes about generic-table
-=========================
-
-@section gtint What is generic-table?
-
-Generic-table is a JSON schema and client-side JS file that makes it easy to
-display live, table structured HTML over a ws link.
-
-An example plugin and index.html using it are provided, but lwsgt itself doesn't
-have its own plugin, it's just a JSON schema and client-side JS that other
-plugins can use to simplify displaying live, table-based data without having
-to reinvent the wheel each time.
-
-The ws protocol sends JSON describing the table, and then JSON updating the table
-contents when it chooses, the brower table is updated automatically, live.
-
-\image html lwsgt-overview.png
-
- - Example protocol plugin (displays directory contents): https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/protocol_table_dirlisting.c
-
- - Example HTML: https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/assets/index.html
- - lwsgt.js (client-side table rendering / ws link management): https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/assets/lwsgt.js
-
-
-@section gteb Enabling for build
-
-Enable the demo plugin at CMake with -DLWS_WITH_PLUGINS=1
-
-
-@section gtinth Integrating with your html
-
- - In your HEAD section, include lwsgt.js
-
-```
-       <script src="lwsgt.js"></script>
-```
-
- - Also in your HEAD section, style the lwsgt CSS, eg
-
-```
-       <style>
-       .lwsgt_title { font-size: 24; text-align:center }
-       .lwsgt_breadcrumbs { font-size: 18; text-align:left }
-       .lwsgt_table { font-size: 14; padding:12px; margin: 12px; align:center }
-       .lwsgt_hdr { font-size: 18; text-align:center;
-                    background-color: rgba(40, 40, 40, 0.8); color: white }
-       .lwsgt_tr { padding: 10px  }
-       .lwsgt_td { padding: 3px  }
-       </style>
-```
-
-You can skip this but the result will be less beautiful until some CSS is
-provided.
-
- - In your body section, declare a div with an id (can be whatever you want)
-
-```
-       <tr><td><div id="lwsgt1" class="group1"></div></td></tr>
-```
-
-lwsgt JS will put its content there.
-
- - Finally in a <script> at the end of your page, instantiate lwsgt and
-provide a custom callback for clickable links
-
-```
-       <script>
-       var v1 = new lwsgt_initial("Dir listing demo",
-                                  "protocol-lws-table-dirlisting",
-                                  "lwsgt1", "lwsgt_dir_click", "v1");
-       
-       function lwsgt_dir_click(gt, u, col, row)
-       {
-               if (u[0] == '=') { /* change directory */
-                       window[gt].lwsgt_ws.send(u.substring(1, u.length));
-                       return;
-               }
-               var win = window.open(u, '_blank');
-               win.focus();
-       }
-
-       </script>
-```
-
-In the callback, you can recover the ws object by `window[gt].lwsgt_ws`.
-
-
-@section gtc Lwsgt constructor
-
-To instantiate the ws link and lwsgt instance, your HTML must call a lwsgt
-constructor for each region on the page managed by lwsgt.
-
-`var myvar = new lwsgt_initial(title, ws_protocol, div_id, click_cb, myvar);`
-
-All of the arguments are strings.
-
-| Parameter       | Description                                             |
-|-----------------|---------------------------------------------------------|
-| title           | Title string to go above the table                      |
-| ws_protocol     | Protocol name string to use when making ws connection   |
-| div_id          | HTML id of div to fill with content                     |
-| click_cb        | Callback function name string to handle clickable links |
-| myvar           | Name of var used to hold this instantiation globally    |
-
-Note "myvar" is needed so it can be passed to the click handling callback.
-
-
-@section gtclick Lwsgt click handling function
-
-When a clickable link produced by lwsgt is clicked, the function named in the
-click_cb parameter to lwsgt_initial is called.
-
-That function is expected to take four parameters, eg
-
-`function lwsgt_dir_click(gt, u, col, row)`
-
-| Parameter | Description                                               |
-|------- ---|-----------------------------------------------------------|
-| gt        | Name of global var holding this lwsgt context (ie, myvar) |
-| u         | Link "url" string                                         |
-| col       | Table column number link is from                          |
-| row       | Table row number link is from                             |
-
-
-
-@section gtgj Generic-table JSON
-
-### Column layout
-
-When the ws connection is established, the protocol should send a JSON message
-describing the table columns.  For example
-
-```
-         "cols": [
-               { "name": "Date" },
-               { "name": "Size", "align": "right" },
-               { "name": "Icon" },
-               { "name": "Name", "href": "uri"},
-               { "name": "uri", "hide": "1" }
-           ]
-         }
-```
-
- - This describes 5 columns
-
- - Only four columns (not "uri") should be visible
-
- - "Name" should be presented as a clickable link using "uri" as the
-   destination, when a "uri" field is presented.
-   
- - "Size" field should be presented aligned to the right
- ### Breadcrumbs
- When a view is hierarchical, it's useful to provide a "path" with links back
- in the "path", known as "breadcrumbs".
- Elements before the last one should provide a "url" member as well as the
- displayable name, which is used to create the link destination.
- The last element, being the current displayed page should not have a url
- member and be displayed without link style.
- ```
-       "breadcrumbs":[{"name":"top", "url": "/" }, {"name":"mydir"}]
- ```
- ### Table data
- The actual file data consists of an array of rows, containing the columns
- mentioned in the original "cols" section.
- ```
-       "data":[
-               {
-                "Icon":" ",
-                "Date":"2015-Feb-06 03:08:35 +0000",
-                "Size":"1406",
-                "uri":"./serve//favicon.ico",
-                "Name":"favicon.ico"
-               }
-       ]
-
- ```
- @section gtdirl Setting up protocol-lws-table-dirlisting
- The example protocol needs two mounts, one to provide the index.html, js and
- the protocol itself
- ```
-       {
-        "mountpoint": "/dirtest",
-         "origin": "file:///usr/share/libwebsockets-test-server/generic-table",
-        "origin": "callback://protocol-lws-table-dirlisting",
-        "default": "index.html",
-        "pmo": [{
-               "dir": "/usr/share/libwebsockets-test-server"
-        }]
-       },
-```
-
-The protocol wants a per-mount option (PMO) to tell it the base directory it
-is serving from, named "dir".
-
-The other mount is there to simply serve items that get clicked on from the
-table in a secure way
-
-```
-       {
-        "mountpoint": "/dirtest/serve",
-         "origin": "file:///usr/share/libwebsockets-test-server",
-        "default": "index.html"
-       },
-```
-
-This last bit is not related to using lwsgt itself.
diff --git a/READMEs/README.h2-long-poll.md b/READMEs/README.h2-long-poll.md
new file mode 100644 (file)
index 0000000..ab8c25f
--- /dev/null
@@ -0,0 +1,55 @@
+# h2 long poll in lws
+
+lws server and client can support "immortal" streams that are
+not subject to normal timeouts under a special condition.  These
+are read-only (to the client).
+
+Network connections that contain at least one immortal stream
+are themselves not subject to timeouts until the last immortal
+stream they are carrying closes.
+
+Because of this, it's recommended there is some other way of
+confirming that the client is still active.
+
+## Setting up lws server for h2 long poll
+
+Vhosts that wish to allow clients to serve these immortal
+streams need to set the info.options flag `LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL`
+at vhost creation time.  The JSON config equivalent is to set
+
+```
+"h2-half-closed-long-poll": "1"
+```
+
+on the vhost.  That's all that is needed.
+
+Streams continue to act normally for timeout with the exception
+client streams are allowed to signal they are half-closing by
+sending a zero-length DATA frame with END_STREAM set.  These
+streams are allowed to exist outside of any timeout and data
+can be sent on them at will in the server -> client direction.
+
+## Setting client streams for long poll
+
+An API is provided to allow established h2 client streams to
+transition to immortal mode and send the END_STREAM to the server
+to indicate it.
+
+```
+int
+lws_h2_client_stream_long_poll_rxonly(struct lws *wsi);
+```
+
+## Example applications
+
+You can confirm the long poll flow simply using example applications.
+Build and run `http-server/minimal-http-server-h2-long-poll` in one
+terminal.
+
+In another, build the usual `http-client/minimal-http-client` example
+and run it with the flags `-l --long-poll`
+
+The client will connect to the server and transition to the immortal mode.
+The server sends a timestamp every minute to the client, and that will
+stay up without timeouts.
+
diff --git a/READMEs/README.http-cache.md b/READMEs/README.http-cache.md
new file mode 100644 (file)
index 0000000..a137836
--- /dev/null
@@ -0,0 +1,40 @@
+# Client http cookie storage, caching and application
+
+lws now has the option to store incoming cookies in a Netscape cookie jar file
+persistently, and auto-apply relevant cookies to future outgoing requests.
+
+A L1 heap cache of recent cookies is maintained, along with LRU tracking and
+removal of entries from cache and the cookie jar file according to their cookie
+expiry time.
+
+The cookie handling is off by default per-connection for backwards compatibility
+and to avoid unexpected tracking.
+
+## Enabling at build-time
+
+Make sure `-DLWS_WITH_CACHE_NSCOOKIEJAR=1` is enabled at cmake (it is on by
+default now).
+
+## Configuring the cookie cache
+
+The cookie cache is managed through context creation info struct members.
+
+|member|function|
+|---|---|
+|`.http_nsc_filepath`|Filepath to store the cookie jar file at|
+|`.http_nsc_heap_max_footprint`|0, or Max size in bytes for the L1 heap cache|
+|`.http_nsc_heap_max_items`|0, or Max number of cookies allowed in L1 heap cache|
+|`.http_nsc_heap_max_payload`|0, or Largest cookie we are willing to handle|
+
+## Enabling per-connection in lws
+
+To enable it on connections at lws level, add the flag `LCCSCF_CACHE_COOKIES` to
+the client connection info struct `.ssl_connection` flags.
+
+## Enabling per-connection in Secure Streams policy
+
+To enable it on Secure Streams, in the streamtype policy add
+
+```
+       "http_cookies":         true
+```
diff --git a/READMEs/README.http_parser.md b/READMEs/README.http_parser.md
new file mode 100644 (file)
index 0000000..e77125c
--- /dev/null
@@ -0,0 +1,33 @@
+# Notes on http parser corner cases
+
+## Dealing with %00
+
+%00 is considered illegal in
+
+ - the path part of the URL.  A lot of user code handles it as a NUL terminated string,
+   even though the header get apis are based around length.  So it is disallowed to
+   avoid ambiguity.
+
+ - the name part of a urlarg, like ?name=value
+
+%00 is valid in
+
+ - the value part of a urlarg, like ?name=value
+
+When the parser sees %00 where it is not allowed, it simply drops the connection.
+
+## Note on proper urlarg handling
+
+urlargs are allowed to contain non-NUL terminated binary.  So it is important to
+use the length-based urlarg apis
+
+ - `lws_hdr_copy_fragment()`
+ - `lws_get_urlarg_by_name_safe()`
+
+The non-length based urlarg api
+
+ - `lws_get_urlarg_by_name()`
+
+...is soft-deprecated, it's still allowed but it will be fooled by the first %00
+seen in the argument into truncating the argument.  Use `lws_get_urlarg_by_name_safe()`
+instead.
diff --git a/READMEs/README.jit-trust.md b/READMEs/README.jit-trust.md
new file mode 100644 (file)
index 0000000..dfdd12b
--- /dev/null
@@ -0,0 +1,446 @@
+# JIT trust
+
+![JIT Trust logo](../doc-assets/jit-trust-logo.png)
+
+## Background
+
+Most systems using openssl rely on a system trust bundle that openssl was
+compiled to load at library init.  This is a bit expensive, since it
+instantiates over 120 CA X.509 certs, but most modern Linux systems don't really
+notice the permanent use of 1MB or so of heap from init, the advantage is client
+connections have all the trusted root certs available in memory to perform
+validation.
+
+![Using system trust bundles](../doc-assets/jit-trust-system-trust.png)
+
+For the kind of systems that choose mbedtls, they will typically either be
+burdened by or not even have enough ram to take this approach.
+
+If the device only connects to endpoints that are signed by a specific
+CA, you can just prepare the connection with the known trusted CA, that's
+the approach the examples take.  This method should still be used for critical
+connections to the cloud, for example provide the necessary CA cert in the
+Secure Streams policy, or at vhost creation time.
+
+![Using system trust bundles](../doc-assets/jit-trust-single-trust.png)
+
+However if you also have a browser type application that could connect anywhere,
+but you don't have heap spare to preload all the CAs, you need something like
+"JIT trust".
+
+## JIT trust overview
+
+The basic approach is to connect to the server to retrieve its certificates,
+then study the certificates to determine the identity of the missing trusted
+cert we should be trying to validate with.
+
+![JIT Trust overview](../doc-assets/jit-trust-overview.png)
+
+We attempt to get the trusted cert from some local or remote store, and retry
+the connection having instantiated the missing CA cert as trusted for that
+connection, if it is one that we do actually trust.  If it lies about what CA it
+needs to validate, or we do not trust the one it asks for, subsequent
+connections will fail.
+
+If it asked for a trusted CA that we trust, and the relationship was valid, the
+tls negotiation should then complete successfully, and we can cache the CA cert
+and the host -> CA cert pre-trust requirement so future connections can work
+first time.
+
+## Subject Key Id and Authority Key Id
+
+All of the certificates publish a unique-enough personal "Subject Key ID" or
+SKID blob.  These are typically 20-byte hashes based on the cert public key.
+
+When a server certificate is issued by the CA, an entry is made first in the
+certificate noting the SKID of the certificate that will be used to sign it,
+in an "Authority Key ID", or AKID, extension.  The certificate is then signed by
+the parent certificate private key to prove it was issued by the real owner of
+the CA or intermediate certificate.
+
+![X.509 validation paths](../doc-assets/jit-trust-paths.png)
+
+Basically this AKID on a certificate is guiding the validator with
+information about which certificate it claims is next in the chain of trust
+leading back to a trusted CA.  Lying about it doesn't help an attacker,
+because we're only using the AKID to get the CA certificate and then try to do
+the full signature check using it, if it's not really signed by the AKID cert it
+told, or anything else wrong, the actual validation will just fail.
+
+A chain that terminates in a CA certificate is complete, and can undergo full
+validation using the tls library.
+
+## Converting the Mozilla trust bundle for JIT trust
+
+Lws provides a bash script `./scripts/mozilla-trust-gen.sh` that can fetch the
+latest Mozilla CA trust bundle for certs usable for tls validation, and convert
+it to three different forms to allow maintaining the trust bundle in different
+ways for different kinds of device to consume.
+
+ - as a webroot directory, so you can server trusted DERs, with
+   symlink indexes to the CA certs by SKID and issuer/serial
+
+ - as an atomic binary blob, currently about 143KB, with structure
+   at the start pointing to DER certs and indexes inside
+
+ - a C-compiler friendly `uint8_t` array version of the blob,
+   so it can be compiled into .rodata directly if necessary.
+
+Currently there are 128 certs in the trust bundle, and the whole blob is about
+143KB uncompressed.
+
+## Considerations about maintaining the trust blob
+
+Mozilla update their trust bundle at intervals, and there have been at least
+three cases where they have removed or distrusted CAs from it by their own
+decision, because they have issued dangerous certificates, (like one for `*`
+that will validate anything at all).  Certifacte owners may also revoke their
+own certificates for any reason and issue replacements.
+
+The certs in the trust bundle expire, currently 10/128 will expire within 3
+years and 50/128 over the next 10 years.  So new and replacement certificates
+are also being added at intervals.
+
+Part of using the trust bundle is building in some way to update what is trusted
+over the lifetime of the device, which may exceed 10 years.
+
+Depending on the device, it may not be any problem to keep the trust blob in the
+firmware, and update the firmware ongoing every few months.  So you could build
+it into the firmware using the C array include file (the minimal example takes
+this approach).
+
+Another device may have difficulty updating the firmware outside of emergencies,
+it could keep the trust blob in a separate area and update it separately.
+Having it as a single blob makes it easy to fetch and update.
+
+Finally constrained devices, say in ESP32 class, may not have space or desire
+to store the trust blob in the device at all, it could query a remote server on
+demand to check for any trusted CA matching a given AKID and retrieve and cache
+it in volatile ram.  This would use the webroot produced by the script, via tls
+and a fixed CA cert outside this system.
+
+## Format of the JIT trust blob
+
+The trust blob layout is currently
+
+```
+00:  54 42 4c 42     Magic "TBLB"
+04:  00 01           MSB-first trust blob layout version
+06:  XX XX           MSB-first count of certificates
+08:  XX XX XX XX     MSB-first trust blob generation unix time
+0c:  XX XX XX XX     MSB-first offset from blob start of cert length table
+10:  XX XX XX XX     MSB-first offset from blob start of SKID length table
+14:  XX XX XX XX     MSB-first offset from blob start of SKID table
+18:  XX XX XX XX     MSB-first total blob length
+
+1c:  XX .. XX        DER certs (start at +0x1c)
+  :  XX .. XX        DER cert length table (MSB-first 16-bit per cert)
+  :  XX .. XX        SKID length table (8-bit per cert)
+  :  XX .. XX        SKID table (variable per cert)
+```
+
+## Enabling JIT Trust
+
+```
+$ cmake .. -DLWS_WITH_TLS_JIT_TRUST=1
+```
+
+## Minimal example for JIT Trust
+
+`minimal-examples/http-client/minimal-http-client-jit-trust` is built if JIT
+Trust is enabled at cmake and `-DLWS_WITH_MINIMAL_EXAMPLES=1`.  This is based on
+minimal-http-client, except the loading of the system trust bundle is defeated,
+so by default it does not trust anything and cannot complete any tls connection.
+It includes the mozilla trust blob as a header file when built.
+
+It tries to do an http client connection twice, the first time fails but JIT
+Trust determines which trusted CA cert is missing, retreives it from the trust
+blob and creates the necessary temporary vhost with the correct CA cert(s)
+trusted.  On the next retry, the connection succeeds.
+
+## Processing of x509 AKID and SKIDs
+
+We study each x509 cert sent by the server in turn.  We parse out the SKID and
+AKID on each one and stash them (up to 4 deep).
+
+After the initial validation fails due to lack of any trusted CA, lws has
+collected all the AKID and SKIDs that were in certs sent by the server.  Since
+these may be sent in any order, may be malicious, and may even contain the
+(untrusted) root CA, they are sorted into a trust path using the AKID and SKID
+relationships.
+
+To cover cross-signing and cases where the root cert(s) were wrongly sent by
+a misconfigured server, all of the AKIDs in the stash are queried against the
+trusted CA store.  In cross-signing, multiple intermediates are provided with
+the same SKID, that all match the server certificate AKID parent.  Since we
+might meet certificates that trust multiple valid CAs that can validate the
+certificate, we support up to three CA certs imported.
+
+A user `lws_system_ops` handler performs the query, so it can consist of any
+kind of backing store or remote lookup. Helpers are provided to query the JIT
+trust mozilla blob, so the system helper is small in the typical case, just
+calling lws helpers.
+
+The results (up to three CA certs to account for cross-signing scenarios) are
+collected and a 1hr TTL cache entry made for the hostname and the SKIDs of the
+matched CAs, if there is no existing JIT vhost with its tls context configured
+with the needed trusted CAs, one is created.
+
+When the connection is retried, lws checks the cache for the hostname having
+a binding to an existing JIT vhost, if that exists the connection proceeds
+bound to that.  If there is a cache entry but no JIT vhost, one is created using
+the information in the cache entry.
+
+## Efficiency considerations
+
+From cold, the JIT Trust flow is 
+
+1. A sacrificial connection is made to get the server certs
+2. Query the JIT Trust database for AKIDs mentioned in the certs (this may be
+done asynchronously)
+3. Create a temporary vhost with the appropriate trusted certs enabled in it,
+   and add an entry in the cache for this hostname to the SKIDs of the CAs
+   enabled on this temporary vhost
+4. Retry, querying the cache to bind the connection to the right temporary vhost
+
+An lws_cache in heap is maintained so step 1 can be skipped while hostname->
+SKID items exist in the cache.  If the items expire or are evicted, it just
+means we have to do step 1 again.
+
+For a short time, the vhost created in step 3 is allowed to exist when idle, ie
+when no connections are actively using it.  In the case the vhost exists and
+the cache entry exists for the hostname, the connection can proceed successfully
+right away without steps 1 through 3.
+
+## APIs related to JIT Trust 
+
+Systems that support JIT trust define an `lws_system_ops` callback
+that does whatever the system needs to do for attempting to acquire
+a trusted cert with a specified SKID or issuer/serial.
+
+```
+int (*jit_trust_query)(struct lws_context *cx, const uint8_t *skid, size_t skid_len, void *got_opaque);
+```
+
+The ops handler doesn't have to find the trusted cert immediately before
+returning, it is OK starting the process and later if successful calling a
+helper `lws_tls_jit_trust_got_cert_cb()` with the `got_opaque` from the query.
+This will cache the CA cert so it's available at the next connection retry for
+preloading.
+
+An helper suitable for `ops->jit_trust_query` using trust blob lookup in .rodata
+is provided in `lws_tls_jit_trust_blob_queury_skid()`, the callback above should
+be called with its results as shown in the minimal example.
+
+## Runtime tuning for JIT Trust
+
+The context creation info struct has a couple of runtime-tunable settings
+related to JIT Trust.
+
+`.jitt_cache_max_footprint`: default 0 means no limit, otherwise the hostname->
+SKID cache is kept below this many bytes in heap, by evicting LRU entries.
+
+`.vh_idle_grace_ms`: default 0 means 5000ms, otherwise sets the length of time
+a JIT Trust vhost is allowed to exist when it has no connections using it.
+Notice that, eg, h2 connections have their own grace period when they become
+idle, to optimize reuse, this period does not start until any h2 network
+connection bound to the vhost has really closed.
+
+## Considerations around http redirects
+
+HTTP redirects are transactions that tell the client to go somewhere else to
+continue, typically a 301 response with a Location: header explaining where to
+go.
+
+JIT Trust supports redirects to hosts with the same or different trust
+requirements, each step in the redirect is treated as a new connection that will
+fail, try to create a vhost with the right trust and work on the retry.
+
+Lws rejects by default protocol downgrades (https -> http) on redirects, the
+example used a context option `LCCSCF_ACCEPT_TLS_DOWNGRADE_REDIRECTS` to
+override this.
+
+## Works out of the box on recent mbedtls and openssl
+
+No modifications are needed to either tls library.
+
+## Compatibility Testing
+
+A list of the top 100 sites each from the US and the ROW were combined to
+produce 156 unqiue domain names [1]
+
+The Mbedtls build of JIT trust minimal example was run against each of these
+doing a GET on path `/` and restricted to h1 (`--server xxx --h1`).  In some
+cases, the server at the base domain name is broken or down, as verified using
+ssllabs.com as a second opinion.  These domains only resolve properly using
+`www.` prefix.
+
+In some cases the sites check the user agent and return a 4xx, these are taken
+as success for this test, since there was no problem at the tls layer.
+
+|site|h1|h2|comment|
+|---|---|---|---|
+|adobe.com|✓|✓||
+|allegro.pl|✓|✓||
+|allrecipes.com|✓|✓||
+|amazon.co.jp|✓|✓||
+|amazon.com|✓|✓||
+|amazon.co.uk|✓|✓||
+|amazon.de|✓|✓||
+|amazon.fr|✓|✓||
+|amazon.in|✓|✓||
+|amazon.it|✓|✓||
+|aol.com|✓|✓||
+|apartments.com|✓|✓||
+|apple.com|✓|✓||
+|ar.wikipedia.org|✓|✓||
+|att.com|✓|✓||
+|bankofamerica.com|✓|✓||
+|bbc.com|✓|✓||
+|bbc.co.uk|✓|✓||
+|bestbuy.com|✕|✓|redirect-> `www.` then h1: timeout, h2: 403 forbidden... geolocated?|
+|booking.com|✓|✓||
+|britannica.com|✓|✓||
+|bulbagarden.net|✓|✓||
+|businessinsider.com|✓|✓||
+|ca.gov|✓|✓||
+|caixa.gov.br|✕|✕|TLS trust works fine.  Continuously redirects to self... sends set-cookie that we don't return yet|
+|capitalone.com|✓|✓||
+|cbssports.com|✓|✓||
+|cdc.gov|✓|✓||
+|chase.com|✓|✓||
+|chrome.google.com|✓|✓||
+|cnbc.com|✓|✓||
+|cnet.com|✓|✓||
+|cnn.com|✓|✓||
+|cookpad.com|✓|✓||
+|costco.com|✕|✓|TLS trust works fine.  But with or without `www.` server does not reply within 15s on h1, sends 403 OK on h2... Curl acts the same as we do, firefox works... geolocated?||
+|craigslist.org|✓|✓||
+|dailymotion.com|✓|✓||
+|de.wikipedia.org|✓|✓||
+|dictionary.com|✓|✓||
+|ebay.com|✓|✓||
+|ebay.co.uk|✓|✓||
+|en.wikipedia.org|✓|✓||
+|epicgames.com|✓|✓||
+|espn.com|✓|✓||
+|es.wikipedia.org|✓|✓||
+|etsy.com|✓|✓||
+|expedia.com|✓|✓||
+|facebook.com|✓|✓||
+|fandom.com|✓|✓||
+|fedex.com|✓|✓||
+|finance.yahoo.com|✓|✓||
+|www.foodnetwork.com|✓|✓|`www.` served correctly, base domain is misconfigured with expired cert, confirmed with ssllabs + curl|
+|forbes.com|✓|✓||
+|foxnews.com|✓|✓||
+|fr.wikipedia.org|✓|✓||
+|gamepedia.com|✓|✓||
+|genius.com|✓|✓||
+|glassdoor.com|✓|✓||
+|globo.com|✓|✓||
+|google.com|✓|✓||
+|healthline.com|✓|✓||
+|homedepot.com|✓|✓||
+|hulu.com|✓|✓||
+|hurriyet.com.tr|✓|✓||
+|id.wikipedia.org|✓|✓||
+|ign.com|✓|✓||
+|ikea.com|✓|✓|`www.` served correctly, base domain is misconfigured with nonresponsive server, confirmed with ssllabs|
+|ilovepdf.com|✓|✓||
+|imdb.com|✓|✓||
+|indeed.com|✓|✓||
+|indiatimes.com|✓|✓||
+|instagram.com|✓|✓||
+|investopedia.com|✓|✓||
+|irs.gov|✓|✓||
+|it.wikipedia.org|✓|✓||
+|ivi.ru|✓|✓||
+|ja.wikipedia.org|✓|✓||
+|kakaku.com|✓|✓||
+|khanacademy.org|✓|✓||
+|kinopoisk.ru|✓|✓||
+|leboncoin.fr|✓|✓||
+|linkedin.com|✓|✓||
+|live.com|✓|✓||
+|lowes.com|✓|✓||
+|macys.com|✕|✓|TLS trust works fine.  Continuously redirects to self... `www.` same, curl acts same but OK if given -b -c, so akami cookie storage issue|
+|mail.ru|✓|✓||
+|mail.yahoo.com|✓|✓||
+|mapquest.com|✓|✓||
+|mayoclinic.org|✓|✓||
+|medicalnewstoday.com|✓|✓||
+|mercadolivre.com.br|✓|✓||
+|merriam-webster.com|✓|✓||
+|microsoft.com|✓|✓||
+|msn.com|✓|✓||
+|namu.wiki|✓|✓||
+|nbcnews.com|✓|✓||
+|netflix.com|✓|✓||
+|nih.gov|✓|✓||
+|nl.wikipedia.org|✓|✓||
+|ny.gov|✓|✓||
+|nytimes.com|✓|✓||
+|ok.ru|✓|✓||
+|onet.pl|✓||
+|orange.fr|✓|✓||
+|paypal.com|✓|✓||
+|pinterest.com|✓|✓||
+|pixiv.net|✓|✓||
+|play.google.com|✓|✓||
+|pl.wikipedia.org|✓|✓||
+|www.programme-tv.net|✓|✓|OK with `www.`, without `www.` TLS trust works fine but server does not reply, same with curl|
+|pt.wikipedia.org|✓|✓||
+|quizlet.com|✓|✓||
+|quora.com|✓|✓|||
+|rakuten.co.jp|✓|✓||
+|realtor.com|✓|✓||
+|reddit.com|✓|✓||
+|reverso.net|✓|✓||
+|roblox.com|✓|✓||
+|rottentomatoes.com|✓|✓||
+|ru.wikipedia.org|✓|✓||
+|sahibinden.com|✓|✓||
+|smallpdf.com|✓|✓||
+|speedtest.net|✓|✓||
+|spotify.com|✓|✓||
+|steampowered.com|✓|✓||
+|target.com|✓|✓||
+|theguardian.com|✓|✓||
+|tripadvisor.com|✓|✓||
+|tr.wikipedia.org|✓|✓||
+|twitch.tv|✓|✓||
+|twitter.com|✓|✓||
+|uol.com.br|✓|✓||
+|ups.com|✓|✓||
+|urbandictionary.com|✓|✓||
+|usatoday.com|✓|✓||
+|usnews.com|✕|✓|TLS trust works fine. Needs `www.` else server doesn't respond in 15s, sends 403 on h2, Curl acts the same, geolocated?|
+|usps.com|✓|✓||
+|verizon.com|✓|✓||
+|vk.com|✓|✓||
+|walmart.com|✓|✓||
+|washingtonpost.com|✓|✓||
+|weather.com|✓|✓||
+|webmd.com|✓|✓||
+|whatsapp.com|✓|✓||
+|wowhead.com|✓|✓||
+|wp.pl|✓|✓||
+|www.gov.uk|✓|✓||
+|xfinity.com|✓|✓||
+|yahoo.co.jp|✓|✓||
+|yahoo.com|✓|✓||
+|yandex.ru|✓|✓||
+|yellowpages.com|✓|✓||
+|yelp.com|✓|✓||
+|youtube.com|✓|✓||
+|zh.wikipedia.org|✓|✓||
+|zillow.com|✓|✓||
+
+[1]
+```
+wget -O- https://ahrefs.com/blog/most-visited-websites/ | grep most-visited-websites-us | \
+        sed -E 's/class="column-2">/|/g' | tr '|' '\n' | \
+        sed 's/<.*//g' | grep -v Domain | grep -v Josh | sort | uniq
+```
+
diff --git a/READMEs/README.json-lejp.md b/READMEs/README.json-lejp.md
new file mode 100644 (file)
index 0000000..1471c17
--- /dev/null
@@ -0,0 +1,107 @@
+# LEJP JSON Stream Parser
+
+|||
+|---|---|---|
+|cmake| `LWS_WITH_LEJP`|
+|Header| ./include/libwebsockets/lws-lejp.h|
+|api-test| ./minimal-examples/api-tests/api-test-lejp/|
+|test app| ./test-apps/test-lejp.c -> libwebsockets-test-lejp|
+
+LEJP is a lightweight JSON stream parser.
+
+The features are:
+
+ - completely immune to input fragmentation, give it any size blocks of JSON as
+   they become available, 1 byte, or 100K at a time give identical parsing
+   results
+ - input chunks discarded as they are parsed, whole JSON never needed in memory
+ - nonrecursive, fixed stack usage of a few dozen bytes
+ - no heap allocations at all, just requires ~500 byte context usually on
+   caller stack
+ - creates callbacks to a user-provided handler as members are parsed out
+ - no payload size limit, supports huge / endless strings bigger than
+   system memory
+ - collates utf-8 text payloads into a 250-byte chunk buffer in the json parser
+   context object for ease of access
+
+## Type handling
+
+LEJP leaves all numbers in text form, they are signalled in different callbacks
+according to int or float, but delivered as text strings in the first
+`ctx->npos` chars of `ctx->buf`.
+
+For numeric types, you would typically use `atoi()` or similar to recover the
+number as a host type.
+
+## Callback reasons
+
+The user callback does not have to handle any callbacks, it only needs to
+process the data for the ones it is interested in.
+
+|Callback reason|JSON structure|Associated data|
+|---|---|---|
+|`LEJPCB_CONSTRUCTED`|Created the parse context||
+|`LEJPCB_DESTRUCTED`|Destroyed the parse context||
+|`LEJPCB_COMPLETE`|The parsing completed OK||
+|`LEJPCB_FAILED`|The parsing failed||
+|`LEJPCB_VAL_TRUE`|boolean true||
+|`LEJPCB_VAL_FALSE`|boolean false||
+|`LEJPCB_VAL_NULL`|explicit NULL||
+|`LEJPCB_PAIR_NAME`|The name part of a JSON `key: value` map pair|`ctx->buf`|
+|`LEJPCB_VAL_STR_START`|A UTF-8 string is starting||
+|`LEJPCB_VAL_STR_CHUNK`|The next string chunk|`ctx->npos` bytes in `ctx->buf`|
+|`LEJPCB_VAL_STR_END`|The last string chunk|`ctx->npos` bytes in `ctx->buf`|
+|`LEJPCB_ARRAY_START`|An array is starting||
+|`LEJPCB_ARRAY_END`|An array has ended||
+|`LEJPCB_OBJECT_START`|A JSON object is starting||
+|`LEJPCB_OBJECT_END`|A JSON object has ended||
+
+## Handling JSON UTF-8 strings
+
+When a string is parsed, an advisory callback of `LECPCB_VAL_STR_START` occurs
+first.  No payload is delivered with the START callback.
+
+Payload is collated into `ctx->buf[]`, the valid length is in `ctx->npos`.
+
+For short strings or blobs where the length is known, the whole payload is
+delivered in a single `LECPCB_VAL_STR_END` callback.
+
+For payloads larger than the size of `ctx->buf[]`, `LECPCB_VAL_STR_CHUNK`
+callbacks occur delivering each sequential bufferload.
+
+The last chunk (which may be zero length) is delievered by `LECPCB_VAL_STR_END`.
+
+## Parsing paths
+
+LEJP maintains a "parsing path" in `ctx->path` that represents the context of
+the callback events.  As a convenience, at LEJP context creation time, you can
+pass in an array of path strings you want to match on, and have any match
+checkable in the callback using `ctx->path_match`, it's 0 if no active match,
+or the match index from your path array starting from 1 for the first entry.
+
+|CBOR element|Representation in path|
+|---|---|
+|JSON Array|`[]`|
+|JSON Map|`.`|
+|JSON Map entry key string|`keystring`|
+
+
+
+## Comparison with LECP (CBOR parser)
+
+LECP is based on the same principles as LEJP and shares most of the callbacks.
+The major differences:
+
+ - LEJP value callbacks all appear in `ctx->buf[]`, ie, floating-point is
+   provided to the callback in ascii form like `"1.0"`.  CBOR provides a more
+   strict typing system, and the different type values are provided either in
+   `ctx->buf[]` for blobs or utf-8 text strtings, or the `item.u` union for
+   converted types, with additional callback reasons specific to each type.
+
+ - CBOR "maps" use `_OBJECT_START` and `_END` parsing callbacks around the
+   key / value pairs.  LEJP has a special callback type `PAIR_NAME` for the
+   key string / integer, but in LECP these are provided as generic callbacks
+   dependent on type, ie, generic string callbacks or integer ones, and the
+   value part is represented according to whatever comes.
+
+
diff --git a/READMEs/README.jwt.md b/READMEs/README.jwt.md
new file mode 100644 (file)
index 0000000..e0c7e25
--- /dev/null
@@ -0,0 +1,176 @@
+# JWT support in lws
+
+lws supports the common usage scenarios of JWS (signed) JWT generation,
+parsing and transferring in and out as http cookies.  Care is taken to provide
+helpers that implement the current security best practices for cookie handling
+and JWT validation.  All of the common algorithms like ES512 are supported
+along with JWK generation and handling apis.
+
+The build options needed are `-DLWS_WITH_JOSE=1` `-DLWS_WITH_GENCRYPTO=1`.
+
+Underlying JOSE primitives are exposed as apis, some JWT specific primitives
+and finally a JWT-via http cookie level creation apis each building on top of
+what was underneath.
+
+The higher level APIs are provided additionally because they have the most
+opportunity for implementation pitfalls like not validating alg carefully, or
+not using the latest cookie security options; the provided APIs handle that
+centrally for you.  If your needs vary from what the higher level apis are
+doing, you can cut-and-paste out those implementations and create your own
+using the public lower level apis.
+
+## LWS JWT fields
+
+Lws JWT uses mainly well-known fields
+
+Field|Std|Meaning
+---|---|---
+iss|yes|Issuer, typically the domain like "warmcat.com"
+aud|yes|Audience, typically a url path like "https://warmcat.com/sai"
+iat|yes|Unix-time "Issued At"
+nbf|yes|Unix-time "Not Before"
+exp|yes|Unix-time "Expired"
+sub|yes|Subject, eg, a username or user email
+csrf|no|A random 16-char hex token generated with the JWT for use in links specific to the JWT bearer
+ext|no|Application-specific JSON sub-object with whatever fields you need, eg, `"authorization": 1`
+
+## Approach for JWT as session token
+
+Once JWTs are produced, they are autonomous bearer tokens, if they are not kept
+secret between the browser and the site, they will be accepted as evidence for
+having rights to the session from anyone.
+
+Requiring https, and various other cookie hardening techniques make it more
+difficult for them to leak, but it is still necessary to strictly constrain the
+token's validity time, usually to a few tens of minutes or how long it takes a
+user to login and get stuff done on the site in one session.
+
+## CSRF mitigation
+
+Cross Site Request Forgery (CSRF) is a hacking scenario where an authorized
+user with a valid token is tricked into clicking on an external link that
+performs some action with side-effects on the site he has active auth on.  For
+example, he has a cookie that's logged into his bank, and the link posts a form
+to the bank site transferring money to the attacker.
+
+Lws JWT mitigates this possibility by putting a random secret in the generated
+JWT; when the authorized user presents his JWT to generate the page, generated
+links that require auth to perform their actions include the CSRF string from
+that user's current JWT.
+
+When the user clicks those links intentionally, the CSRF string in the link
+matches the CSRF string in the currently valid JWT that was also provided to
+the server along with the click, and all is well.
+
+An attacker does not know the random, ephemeral JWT CSRF secret to include in
+forged links, so the attacker-controlled action gets rejected at the server as
+having used an invalid link.
+
+The checking and link manipulation need to be implemented in user code / JS...
+lws JWT provides the random CSRF secret in the JWT and makes it visible to the
+server when the incoming JWT is processed.
+
+## Need for client tracking of short JWT validity times
+
+Many links or references on pages do not require CSRF strings, only those that
+perform actions with side-effects like deletion or money transfer should need
+protecting this way.
+
+Due to CSRF mitigation, generated pages containing the protected links
+effectively have an expiry time linked to that of the JWT, since only the bearer
+of the JWT used to generate the links on the page can use them; once that
+expires actually nobody can use them and the page contents, which may anyway
+be showing content that only authenticated users can see must be invalidated and
+re-fetched.  Even if the contents are visible without authentication, additional
+UI elements like delete buttons that should only be shown when authenticated
+will wrongly still be shown 
+
+For that reason, the client should be informed by the server along with the
+authentication status, the expiry time of it.  The client should then by itself
+make arrangements to refresh the page when this time is passed,
+either showing an unauthenticated version of the same page if it exists, or by
+redirecting to the site homepage if showing any of the contents required
+authentication.  The user can then log back in using his credientials typically
+stored in the browser's password store and receive a new short-term JWT with a
+new random csrf token along with a new page using the new csrf token in its
+links.
+
+## Considerations for long-lived connections
+
+Once established as authorized, websocket links may be very long-lived and hold
+their authorization state at the server.  Although the browser monitoring the
+JWT reloading the page on auth expiry should mitigate this, an attacker can
+choose to just not do that and have an immortally useful websocket link.
+
+At least for actions on the long-lived connection, it should not only confirm
+the JWT authorized it but that the current time is still before the "exp" time
+in the JWT, this is made available as `expiry_unix_time` in the args struct
+after successful validation.
+
+Ideally the server should close long-lived connections according to their auth
+expiry time.
+
+## JWT lower level APIs
+
+The related apis are in `./include/libwebsockets/lws-jws.h`
+
+### Validation of JWT
+
+```
+int
+lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
+                       const char *alg_list, const char *com, size_t len,
+                       char *temp, int tl, char *out, size_t *out_len);
+```
+
+### Composing and signing JWT
+
+```
+int
+lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
+                    const char *alg, char *out, size_t *out_len, char *temp,
+                    int tl, const char *format, ...);
+```
+
+## JWT creation and cookie get / set API
+
+Both the validation and signing apis use the same struct to contain their
+aguments.
+
+```
+struct lws_jwt_sign_set_cookie {
+       struct lws_jwk                  *jwk;
+       /**< entry: required signing key */
+       const char                      *alg;
+       /**< entry: required signing alg, eg, "ES512" */
+       const char                      *iss;
+       /**< entry: issuer name to use */
+       const char                      *aud;
+       /**< entry: audience */
+       const char                      *cookie_name;
+       /**< entry: the name of the cookie */
+       char                            sub[33];
+       /**< sign-entry, validate-exit: subject */
+       const char                      *extra_json;
+       /**< sign-entry, validate-exit:
+        * optional "ext" JSON object contents for the JWT */
+       size_t                          extra_json_len;
+       /**< validate-exit:
+        * length of optional "ext" JSON object contents for the JWT */
+       const char                      *csrf_in;
+       /**< validate-entry:
+        * NULL, or an external CSRF token to check against what is in the JWT */
+       unsigned long                   expiry_unix_time;
+       /**< sign-entry: seconds the JWT and cookie may live,
+        * validate-exit: expiry unix time */
+};
+
+int
+lws_jwt_sign_token_set_http_cookie(struct lws *wsi,
+                                  const struct lws_jwt_sign_set_cookie *i,
+                                  uint8_t **p, uint8_t *end);
+int
+lws_jwt_get_http_cookie_validate_jwt(struct lws *wsi,
+                                    struct lws_jwt_sign_set_cookie *i,
+                                    char *out, size_t *out_len);
+```
diff --git a/READMEs/README.libressl.md b/READMEs/README.libressl.md
new file mode 100644 (file)
index 0000000..b794f3b
--- /dev/null
@@ -0,0 +1,66 @@
+## Background
+
+libressl is another fork of Openssl.
+
+## Example build for libressl itself
+
+If you unpack or clone into `/path/to/libressl` and enter that dir...
+
+```
+$ mkdir build
+$ cd build
+$ cmake ..
+$ make -j8
+```
+
+## Example build for lws against libressl
+
+You can just build lws as you would for a specific version of openssl
+
+```
+$ mkdir build
+$ cd build
+$ cmake .. -DLWS_OPENSSL_LIBRARIES='/path/to/libressl/build/tls/libtls.a;/path/to/libressl/build/ssl/libssl.a;/path/to//libressl/build/crypto/libcrypto.a' -DLWS_OPENSSL_INCLUDE_DIRS=/path/to/libressl/include -DLWS_WITH_MINIMAL_EXAMPLES=1
+$ make -j8
+```
+
+Libressl by default will look for a trust bundle in `/usr/local/etc/ssl/cert.pem`, you either have to
+symlink this to your trust bundle if that doesnt happen to be where it is, or give your app the trusted CA
+specifically as is done for MBEDTLS and WOLFSSL in the examples.
+
+In Fedora, the system trust store can be found at `/etc/pki/tls/cert.pem`, so you can symlink it
+
+```
+$ sudo mkdir -p /usr/local/etc/ssl
+$ sudo ln -sf /etc/pki/tls/cert.pem /usr/local/etc/ssl/cert.pem
+```
+
+after that you can run examples from the build dir, eg,
+
+```
+$ ./bin/lws-minimal-http-client
+[2021/02/08 20:10:52:0781] U: LWS minimal http client [-d<verbosity>] [-l] [--h1]
+[2021/02/08 20:10:52:0784] N: LWS: 4.1.99-v4.1.0-269-g762ef33fca, loglevel 1031
+[2021/02/08 20:10:52:0784] N: NET CLI SRV H1 H2 WS IPv6-absent
+[2021/02/08 20:10:52:0786] N:  ++ [wsi|0|pipe] (1)
+[2021/02/08 20:10:52:0787] N:  ++ [vh|0|netlink] (1)
+[2021/02/08 20:10:52:0802] N:  ++ [vh|1|default] (2)
+[2021/02/08 20:10:52:1850] N:  ++ [wsicli|0|GET/h1/warmcat.com] (1)
+[2021/02/08 20:10:52:2982] N:  ++ [mux|0|h2_sid1_(wsicli|0|GET/h1/warmcat.com)] (1)
+[2021/02/08 20:10:52:3271] U: Connected to 46.105.127.147, http response: 200
+[2021/02/08 20:10:52:3335] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2021/02/08 20:10:52:3335] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2021/02/08 20:10:52:3526] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2021/02/08 20:10:52:3526] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2021/02/08 20:10:52:3543] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2021/02/08 20:10:52:3543] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2021/02/08 20:10:52:3545] U: RECEIVE_CLIENT_HTTP_READ: read 3502
+[2021/02/08 20:10:52:3546] U: LWS_CALLBACK_COMPLETED_CLIENT_HTTP
+[2021/02/08 20:10:52:3546] N:  -- [wsi|0|pipe] (0) 276.019ms
+[2021/02/08 20:10:52:3547] N:  -- [mux|0|h2_sid1_(wsicli|0|GET/h1/warmcat.com)] (0) 56.417ms
+[2021/02/08 20:10:52:3566] N:  -- [vh|1|default] (1) 276.384ms
+[2021/02/08 20:10:52:3566] N:  -- [wsicli|0|GET/h1/warmcat.com|default|h2|h2] (0) 171.599ms
+[2021/02/08 20:10:52:3567] N:  -- [vh|0|netlink] (0) 277.974ms
+[2021/02/08 20:10:52:3567] U: Completed: OK
+```
+
diff --git a/READMEs/README.lifecycle.md b/READMEs/README.lifecycle.md
new file mode 100644 (file)
index 0000000..eb029b4
--- /dev/null
@@ -0,0 +1,43 @@
+# lws lifecycles
+
+## Context
+
+![context lifecycle](/doc-assets/lifecycle-context.png)
+
+## Client wsi
+
+![client wsi](/doc-assets/lifecycle-wsi.png)
+
+## Server wsi
+
+![server wsi](/doc-assets/lifecycle-server-wsi.png)
+
+## role-specific events
+
+role|client|server
+---|---|---
+http COMPLETED|`LWS_CALLBACK_COMPLETED_CLIENT_HTTP`|-
+http RECEIVE|`LWS_CALLBACK_RECEIVE_CLIENT_HTTP`|`LWS_CALLBACK_RECEIVE_HTTP`
+http WRITEABLE|`LWS_CALLBACK_CLIENT_HTTP_WRITEABLE`|`LWS_CALLBACK_HTTP_WRITEABLE`
+http CLOSE|`LWS_CALLBACK_CLOSED_CLIENT_HTTP`|`LWS_CALLBACK_CLOSED_HTTP`
+http BIND|`LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL`|`LWS_CALLBACK_HTTP_BIND_PROTOCOL`
+http DROP|`LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL`|`LWS_CALLBACK_HTTP_DROP_PROTOCOL`
+
+role|client|server
+---|---|---
+ws ESTABLISHED|`LWS_CALLBACK_CLIENT_ESTABLISHED`|`LWS_CALLBACK_ESTABLISHED`
+ws RECEIVE|`LWS_CALLBACK_CLIENT_RECEIVE`|`LWS_CALLBACK_RECEIVE`
+ws WRITEABLE|`LWS_CALLBACK_CLIENT_WRITEABLE`|`LWS_CALLBACK_SERVER_WRITEABLE`
+ws CLOSE|`LWS_CALLBACK_CLIENT_CLOSED`|`LWS_CALLBACK_CLOSED`
+ws BIND|`LWS_CALLBACK_WS_CLIENT_BIND_PROTOCOL`|`LWS_CALLBACK_WS_BIND_PROTOCOL`
+ws DROP|`LWS_CALLBACK_WS_CLIENT_DROP_PROTOCOL`|`LWS_CALLBACK_WS_DROP_PROTOCOL`
+
+role|client|server
+---|---|---
+raw ESTABLISHED|`LWS_CALLBACK_RAW_CONNECTED`|`LWS_CALLBACK_RAW_ADOPT`
+raw RECEIVE|`LWS_CALLBACK_RAW_RX`|`LWS_CALLBACK_RAW_RX`
+raw WRITEABLE|`LWS_CALLBACK_RAW_WRITEABLE`|`LWS_CALLBACK_RAW_WRITEABLE`
+raw CLOSE|`LWS_CALLBACK_RAW_CLOSE`|`LWS_CALLBACK_RAW_CLOSE`
+raw BIND|`LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL`|`LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL`
+raw DROP|`LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL`|`LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL`
+
diff --git a/READMEs/README.logging.md b/READMEs/README.logging.md
new file mode 100644 (file)
index 0000000..933a920
--- /dev/null
@@ -0,0 +1,288 @@
+# lws logging
+
+# `lwsl_` logging apis
+
+LWS has traditionally provided logging arrangements that are not indirected
+through the lws context, because logging may be needed before and after the
+context existence.  For that reason the original logging arrangements are
+processwide.
+
+By default the logs are emitted on stdout, but this can be overridden
+using `lws_set_log_level()` and either syslog (provided by `lwsl_emit_syslog()`)
+or custom log emission is possible if you point it to your own.
+
+Currently the following log levels are defined
+
+|name|function|release|meaning|
+|---|---|---|---|
+|`LLL_ERR`|`lwsl_err()`|y|Serious operation errors anyone needs to know|
+|`LLL_WARN`|`lwsl_warn()`|y|Operation errors you may need to know|
+|`LLL_USER`|`lws_user()`|y|Information user code wants you to know|
+|`LLL_NOTICE`|`lwsl_notice()`|y|Information about what lws is doing useful for logging|
+|`LLL_INFO`|`lwsl_info()`|n|Detailed information about what lws is doing|
+|`LLL_DEBUG`|`lwsl_debug()`|n|Very detailed information about what lws is doing|
+|`LLL_PARSER`|`lwsl_parser()`|n|Very detailed information about parsing|
+|`LLL_HEADER`|`lwsl_header()`|n|Very detailed information about header processing|
+|`LLL_EXT`|`lwsl_ext()`|n|Very detailed information about ws extensions|
+|`LLL_CLIENT`|`lwsl_client()`|n|Very detailed information about client connections|
+|`LLL_LATENCY`|`lwsl_latency()`|n|detailed latency stats|
+|`LLL_THREAD`|`lwsl_thread()`|n|detailed threadpool information|
+
+The first four log levels are built into lws even on Release builds, the others
+are only built in Debug builds.
+
+You can select between Debug and Release builds using cmake `-DCMAKE_BUILD_TYPE=`
+`DEBUG` or `Release`
+
+`lws_set_log_level()` is used to OR together the logging bitfields you want to
+see emitted, only log levels that were built in can be enabled since the code for them
+is just not there otherwise.
+
+## Finegrained control of log level build
+
+You can deviate from the default log inclusion for release / debug by overriding it
+at cmake, using `LWS_LOGGING_BITFIELD_SET` and `LWS_LOGGING_BITFIELD_CLEAR`.
+
+For example you can set `-DLWS_LOGGING_BITFIELD_SET="LLL_INFO|LLL_DEBUG"`, which will
+cause those log level traces to be built in even in Release mode.  Clear works
+similarly to defeat build of specific log levels.
+
+## Object tags in lws
+
+Commonly logging wants to refer to an object in a repeatable way, the usual way to
+do this is with `%p` to print the object pointer.  But this has a couple of drawbacks,
+first the same memory may be freed and reallocated for a different instance of the same
+or another object, causing confusion, and second when multiple processes are allocating
+objects and logging, the same address may be allocated in different process also causing
+confusion.
+
+Lws has introduced unique tag strings to refer to object identity in logging instead, these
+contain various information such as a 64-bit ordinal for the group the object belongs
+to that won't repeat even if reallocated to the same address (until 2^64 allocations,
+anyway).
+
+Tags are fixed at object creation time for the whole object lifetime, although in some
+cases the tag may be appended to... accepted server wsis for example don't have much
+information available to form the tag until they start to indicate what they want to
+do.
+
+At their simplest the tags look like this (in a log indicating creation)
+
+```
+[2020/12/27 08:49:19:2956] N:  ++ (4) [wsi|5|h2]
+```
+
+It means a wsi has been created with the tag `[wsi|5|h2]`, and after that, there are 4
+active objects in the wsi group.
+
+The corresponding object destruction log with the tag is
+
+```
+[2020/12/27 08:49:24:4226] N:  -- (3)   5.126s [wsi|5|h2]
+```
+
+it indicates the object's tag, that it lived for 5.126s and after its destruction,
+there are 3 objects in its group left.
+
+### Compound tags
+
+If the object has bindings, the tag can reflect that, eg
+
+```
+[2020/12/27 08:49:19:4787] N:  ++ (2) [wsiSScli|6|d_h1]
+[2020/12/27 08:49:19:4793] N:  ++ (2) [wsicli|6|GET/h1/httpbin.org/([wsiSScli|6|d_h1])]
+```
+
+the first log is describing a proxied SS client connection at the proxy, and the second
+is a wsi bound to the SS object from the first log to do the outgoing client action.
+
+## Tags in user code
+
+When user code wants to refer to a tagged object like a wsi or vhost, there are helpers
+that return a `const char *` containing the tag
+
+|tag accessors|
+|---|
+|`lws_wsi_tag(wsi)`|
+|`lws_vh_tag(vh)`|
+|`lws_ss_tag(h)`|
+
+# New logging context apis
+
+From v4.3 on lws additionally provides wrappers that issue logs into a
+"log context" object, one of these is embedded in the lws_context, lws_vhost,
+wsi, ss and sspc handles.  These follow the same general approach as before, but
+allow logs to be issued in "the context" of any of those objects, and to fall
+back sanely if the object pointer is NULL.
+
+The traditional process scope logs and emit management remain available as
+before, and if you do not set custom log contexts, the new log apis use the
+processwide log context emit and mask as before too.
+
+Here's a summary of the differences:
+
+|Traditional process scope logs|New log context apis|
+|---|---|
+|Single processwide log context|Defaults to processwide, but object can use custom log contexts|
+|Single processwide emit function|Emit function per log context|
+|Single processwide log mask|log mask is in log context, objects can be bound to custom log contexts at creation time|
+|Require trailing `\n` in format|Trailing `\n` added if not present|
+|Manual `__func__`|`__func__` added in wrapper macros automatically|
+|Manual tag addition|Object tag prepended automatically|
+|No hierarchy|Log contexts may refer to parent log contexts, which may prepend to child logs|
+|Macros per level (eg, `lwsl_err(...)`)|Macros per object type / level (eg, `lwsl_wsi_err(wsi, ...)`)|
+
+In addition to being able to control the emit function and log level for
+individual log contexts, eg, for a particular wsi, the log functions understand
+how to prepend object-specific information such as tags and `__func__`
+automatically.  They also do not need a trailing `\n` in the format string.  So
+the new context aware logs remove boilerplate from the logging calls while
+making the log information more consistent.
+
+So comparing this kind of logging the processwide and log context aware ways:
+
+```
+[2021/06/25 09:39:34:7050] N: [669282|wsicli|4|GET/h1/libwebsockets.org|default]: _lws_generic_transaction_completed_active_conn:  ...
+```
+
+|Type|Example code|
+|---|---|
+|Process scope apis|`lwsl_notice("%s: %s: mylog %d\n", __func__, lws_wsi_tag(wsi), n);`|
+|New log context apis|`lwsl_wsi_notice(wsi, "mylog %d", n);`|
+
+The log context / object-aware apis do not replace the processwide logging but
+augment it, and the new apis default to use the original processwide emit
+function and log mask, so the behaviours are the same.  The original processwide
+log apis themselves are unchanged.
+
+At lws_context creation time, you can set the context info `.log_cx` to a user
+defined log context which is inherited by objects created in that lws_context by
+default.  Vhost creation, wsi creation and ss / sspc creation all allow passing
+a user log_cx to customize how logs for that object are handled.
+
+## Using the new logging apis
+
+This table describes the different ways to issue an ERROR verbosity log, it
+works the same for info, notice, warn, etc.
+
+|Scope|Api example|Functionality|
+|---|---|---|
+|Old, Processwide|lwsl_err(...)|Traditional processwide error log|
+|lws_context|lwsl_cx_err(context, ...)|error log bound to lws_context|
+|lws_vhost|lwsl_vhost_err(vh, ...)|error log bound to lws_vhost|
+|lws_wsi|lwsl_wsi_err(wsi, ...)|error log bound to wsi|
+|lws_ss|lwsl_ss_err(handle, ...)|error log bound to secure stream|
+
+Similarly hexdumps can be bound to different log contexts
+
+|Scope|Api example|Functionality|
+|---|---|---|
+|Old, Processwide|lwsl_hexdump_err(...)|Traditional processwide error hexdump|
+|lws_context|lwsl_hexdump_cx_err(context, ...)|error hexdump bound to lws_context|
+|lws_vhost|lwsl_hexdump_vhost_err(vh, ...)|error hexdump bound to lws_vhost|
+|lws_wsi|lwsl_hexdump_wsi_err(wsi, ...)|error hexdump bound to wsi|
+|lws_ss|lwsl_hexdump_ss_err(handle, ...)|error hexdump bound to secure stream|
+
+## Creating and using custom log contexts
+
+The log context object is public, in `libwebsockets/lws-logs.h`, currently it
+is like this
+
+```
+typedef void (*lws_log_emit_t)(int level, const char *line);
+typedef void (*lws_log_emit_cx_t)(struct lws_log_cx *cx, int level,
+                                 const char *line, size_t len);
+typedef void (*lws_log_prepend_cx_t)(struct lws_log_cx *cx, void *obj,
+                                    char **p, char *e);
+typedef void (*lws_log_use_cx_t)(struct lws_log_cx *cx, int _new);
+typedef struct lws_log_cx {
+       union {
+               lws_log_emit_t          emit; /* legacy emit function */
+               lws_log_emit_cx_t       emit_cx; /* LLLF_LOG_CONTEXT_AWARE */
+       } u;
+       lws_log_use_cx_t                refcount_cb;
+       /**< NULL, or a function called after each change to .refcount below,
+        * this enables implementing side-effects like opening and closing
+        * log files when the first and last object binds / unbinds */
+       lws_log_prepend_cx_t            prepend;
+       /**< NULL, or a cb to optionally prepend a string to logs we are a
+        * parent of */
+       struct lws_log_cx               *parent;
+       /**< NULL, or points to log ctx we are a child of */
+       void                            *opaque;
+       /**< ignored by lws, used to pass config to emit_cx, eg, filepath */
+       void                            *stg;
+       /**< ignored by lws, may be used a storage by refcount_cb / emit_cx */
+       uint32_t                        lll_flags;
+       /**< mask of log levels we want to emit in this context */
+       int32_t                         refcount;
+       /**< refcount of objects bound to this log context */
+} lws_log_cx_t;
+```
+
+The emit function is a union because the traditional logs and the old emit
+functions are also implemented using the new log contexts internally.  For
+new log context-aware code, you would use `.u.emit_cx` and set the flag
+`LLLF_LOG_CONTEXT_AWARE` on `.lll_flags`.
+
+Lws also exports some common emit and refcount functions so you don't have to
+reinvent the wheel
+
+|Dest|emit member|`.lll_flags`|emit|`.refcount_cb`|`.opaque`|
+|---|---|---|---|---|---|
+|stderr|`.u.emit`|-|`lwsl_emit_stderr`|NULL|NULL|
+|file|`.u.emit_cx`|`LLLF_LOG_CONTEXT_AWARE`|`lws_log_emit_cx_file`|`lws_log_use_cx_file`|`(const char *)filepath`|
+
+For example, a custom log context that emits to a configurable file can be
+declared like this (lws exports the needed helpers already)
+
+```
+static lws_log_cx_t my_log_cx = {
+        .lll_flags      = LLLF_LOG_CONTEXT_AWARE |
+                          LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER,
+        .refcount_cb    = lws_log_use_cx_file,
+        .u.emit_cx      = lws_log_emit_cx_file,
+        .opaque                = "/tmp/mylogpath.log" /* also settable at runtime */
+};
+```
+
+To bind the lws_context to this log context, set `log_cx` in the context
+creation info struct
+
+```
+       info.log_cx = &my_log_cx;
+```
+
+### Log context hierarchy
+
+Log contexts may also point to a parent log context... the top level log context
+defines the emit function to be used, but parent log contexts are consulted by
+calling their prepend function if any, to annotate logs with information from
+parent levels.
+
+### Log context prepend function
+
+Logs contexts may define a "prepend" function callback, that knows how to
+represent the object in a brief string to be prepended to other logs.  For
+example the wsi-aware log context layer knows how to provide the wsi tag
+when called.
+
+Prepend functions should add `:<space>` after their output, if any, since these
+will appear before the start of other logs.
+
+### Log context opaque member
+
+The `.opaque` member is available for passing in configuration to the emit and
+refcount_cb members.  Lws does not use this itself at all.
+
+### Log context refcounting
+
+An expected use for custom log contexts is emitting to a specific file, and
+then binding one or more objects to that log context.  Since it's too expensive
+to keep opening and closing the output file per log, it means we need to know
+when we bind to the first object and unbind from the last, so we can keep the
+file handle open.
+
+For this reason the log contexts have a refcount, and an opaque `void *stg`
+availble for the emit and refounct_cb to use how they see fit, eg, for storing
+the output log file descriptor.
diff --git a/READMEs/README.lws_cache.md b/READMEs/README.lws_cache.md
new file mode 100644 (file)
index 0000000..9a471c1
--- /dev/null
@@ -0,0 +1,160 @@
+# lws_cache: Flexible single and multilevel caching
+
+lws_cache implements a single- or multi-level cache for generic payload items
+that are **keyed by a unique string**.
+
+![lws_cache overview](../doc-assets/lws_cache-1.png)
+
+L1 cache is always stored on heap, but it may be hooked up to additional levels
+of cache objects with different backing storage.  The last level always contains
+a complete set of cached items, earlier levels may be empty or contain a partial
+set of objects.
+
+User code can define its own subclassed lws_cache objects with custom storage
+formats and media, while being able to take advantage of a suitably-sized L1
+heap cache to minimize the cost of repeated access.
+
+![lws_cache overview](../doc-assets/lws_cache-2.png)
+
+You can find examples of how to create, use and destroy single and multilevel
+caches in `minimal-examples/api-tests/api-test-lws_cache`
+
+## Cache size restriction, LRU and TTL
+
+The max heap footprint of its items and max number of items can be capped.  LRU
+tracking is performed so the least recently relevant items are evicted first.
+It's also possible to limit the maximum size of any single payload.
+
+Time To Live (TTL) tracking is also performed automatically, so cached items
+auto-expire if a non-zero TTL is provided when the object is created.  A user
+callback can be defined to get called when an item is about to be removed from
+a particular cache level, in case any housekeeping needed.
+
+## Atomicity
+
+Items in L1 can be accessed in heap casually and reliably if the following is
+borne in mind:
+
+ - Any return to the event loop may perform removal of cache items due to TTL
+expiry
+
+ - Any operation that writes new items may evict items from non-last
+cache levels which have limits to the footprint or item count to make room for
+it, using LRU ordering.
+
+In short process cache results before returning to the event loop or writing
+or removing items in the cache.
+
+## Cache creation
+
+Caches are created using an info struct `struct lws_cache_creation_info`
+that should be zeroed down.  Most members are optional and can be left at zero,
+a pointer to the lws_context and a short cache name are mandatory.
+
+```
+struct lws_cache_ttl_lru *
+lws_cache_create(const struct lws_cache_creation_info *info);
+```
+
+How caches work is defined by an "ops struct" that the cache is bound to at
+creation time.  `lws_cache_ops_heap` ops struct is provided by lws, you can
+define your own to implement your own specialized cache level.  See
+`./include/libwebsockets/lws-cache-ttl.h` for the definition.
+
+## Cache destruction
+
+Created cache levels should be destroyed when you are finished with them.
+
+```
+void
+lws_cache_destroy(struct lws_cache_ttl_lru **cache);
+```
+
+For L1, in heap, this frees any allocations.  For other levels, eg, with file
+storage for the items, this would close the file and leave any entries as they
+are.
+
+## Writethrough
+
+```
+int
+lws_cache_write_through(struct lws_cache_ttl_lru *cache,
+                       const char *specific_key, const uint8_t *source,
+                       size_t size, lws_usec_t expiry, void **ppay);
+```
+
+The combined caches are always accessed via the L1 cache, writing new items is
+done at L1 and writes through to each cache layer immediately, so new items go
+into the backing store without delay, but are available from heap for read.
+
+If existing keys are rewritten, the previous item of the same key is deleted
+from all levels of the cache before writing the new one.
+
+## Removal
+
+Removal also is performed at all cache levels at once.
+
+```
+int
+lws_cache_item_remove(struct lws_cache_ttl_lru *cache, const char *wildcard_key);
+```
+
+internally earlier cache levels can evict cached items just at their level, but
+this is triggered automatically and not by api.
+
+A wildcard key is supported, removing all items matching, eg "myitem*".
+
+## Get by key
+
+```
+int
+lws_cache_item_get(struct lws_cache_ttl_lru *cache, const char *specific_key,
+                  const void **pdata, size_t *psize);
+```
+
+Apis are provided to get the blob related to a specific key, if it exists at
+any cache layer.  Again this should use L1, it will bring a copy of the item
+into L1 if one is not already there, so it can be accessed from heap.
+
+## Lookup with wildcards
+
+```
+int
+lws_cache_lookup(struct lws_cache_ttl_lru *cache, const char *wildcard_key,
+                const void **pdata, size_t *psize);
+```
+
+lws_cache also supports **lookup** queries that contain wildcards or otherwise match
+on multiple keys according to cache-specific rules.  These queries do not return
+a single item, instead they return lists of keys that match, in a blob of its
+own that is also cached in L1.
+
+The user can walk the lookup results blob using a provided helper api
+
+```
+int
+lws_cache_results_walk(lws_cache_results_t *walk_ctx);
+```
+
+After recovering each result key this way, the user code can use the _get api
+to access the blob for each indiviudally.
+
+The lookup results themselves are cached in L1, any new key that matches the
+wildcard lookup in any cached results, or any deletion of items with keys
+matching the cached wildcard lookup invalidate the affected cached lookup
+results so they will be regenerated next time.
+
+In the typical case after a lookup, at least for a while the lookup results blob
+and all items mentioned in the lookup results will already be in L1 and cheaply
+accessible.
+
+## Expunging
+
+An api is also provided to "expunge" or completely empty all cache levels and
+corresponding backing stores.
+
+```
+int
+lws_cache_expunge(struct lws_cache_ttl_lru *cache);
+```
+
diff --git a/READMEs/README.lws_conmon.md b/READMEs/README.lws_conmon.md
new file mode 100644 (file)
index 0000000..7e148c3
--- /dev/null
@@ -0,0 +1,36 @@
+## `lws_conmon` apis
+
+`LWS_WITH_CONMON` build option enables `lws_conmon` apis for user code... these add
+some staticistic and information to client connections that can use useful for devices
+to introspect how the connection to their servers is actually performing.
+
+The public apis can be found in `libwebsockets/lws-conmon.h`.
+
+A struct is provided that describes
+
+ - the peer sockaddr the wsi actually connected to, if any
+
+ - a deep copy of the aggregate DNS results (struct addrinfo list) that the
+   client had access to for the peer
+
+ - the number of us dns lookup took
+
+ - the number of us the socket connection took
+
+ - the number of us the tls link establishment took
+
+ - the number of us from the transaction request to the first response, if
+   the protocol has a transaction concept
+
+Because the user code may want to hold on to the DNS list for longer than the
+life of the wsi that originated it, the `lws_conmon_wsi_take()` api allows
+the ownership of the allocated list to be transferred to the user code (as
+well as copying data out into the user's struct so it no longer has any
+dependency on wsi lifetime either).  The DNS list copy in the struct must be
+released at some point by calling `lws_conmon_release()`, but that
+can be at any time afterwards.
+
+The lws-minimal-http-client example shows how user code can use the apis, build
+lws with the `LWS_WITH_CONMON` cmake option and run with `--conmon` to get a
+dump of the collected information.
+
diff --git a/READMEs/README.lws_map.md b/READMEs/README.lws_map.md
new file mode 100644 (file)
index 0000000..7772d66
--- /dev/null
@@ -0,0 +1,117 @@
+# lws_map generic map abstraction
+
+|||
+|---|---|---|
+|cmake|core feature|
+|Header| ./include/libwebsockets/lws-map.h|
+|api-test| ./minimal-examples/api-tests/api-test-lws_map/|
+
+lws_map provides a robust abstraction for containing a collection of items that
+map key objects to value objects, where both the key and value objects may
+differ in size each time and have any type.
+
+Its one-level linked-list hashtables are useful up to hundreds or low thousands
+of items in the map on may platforms.
+
+The map itself and the items inside it are opaque.
+
+## Creating and destroying the map
+
+The user should prepare a `lws_map_info_t` object, it's legal for it to be
+all zeros to select defaults, an 8-way hashtable with item allocation from heap,
+simple bytewise key comparison, and xor / shift key hashing.  These are often
+what you want simplifying construction.
+
+The info object allows user override of item allocator, freeing, key comparison
+and object hashing, allowing custom objects to be keys if desired.
+
+Custom allocator / free implementations for using lwsac for item allocation are
+provided to simplify that case.
+
+Just call `lws_map_create()` with the info struct to create the map, later it
+and all its contents can be destroyed with `lws_map_destroy()`.  The info struct
+can go out of scope immediately after the create call.
+
+```
+lws_map_t *
+lws_map_create(const lws_map_info_t *info);
+void
+lws_map_destroy(lws_map_t **pmap);
+```
+
+## Keys in lws_map
+
+Items are managed in the map by a key, this may be, eg, a string, but it also
+can be an arbitrary object itself.  If comparing keys takes more than a simple
+bytewise comparison, the map creation info struct ._compare() operation should
+be overridden with a user-supplied one that knows how to use the user's
+custom key objects.
+
+Keys are not required to be the same length, so objects with variable size
+overallocation can be used as keys.
+
+Keys and values are copied into allocations inside the map, the original objects
+they are copied from may go out of scope after item creation assuming there are
+no pointers to them copied in the objects themselves.
+
+## Adding items to a map
+
+The map's info._alloc allocator is used for creating items.  By default that
+just creates into the heap.
+
+If you create a new item with the same key as an existing one, the existing one
+is destroyed before the new one is created.  So there is only one item allowed
+at a given key at a time.
+
+To allocate and create a new item containing the key and value, use
+`lws_map_item_create()`
+
+```
+lws_map_item_t *
+lws_map_item_create(lws_map_t *map,
+                   const lws_map_key_t key, size_t keylen,
+                   const lws_map_value_t value, size_t valuelen);
+```
+
+Eg,
+
+```
+       if (!lws_map_item_create(map, (lws_map_key_t)&my_key,
+                                     sizeof(my_key),
+                                    (lws_map_value_t)"4567", 4))
+               /* fail */
+```
+
+
+In the case the key is a string, there is a ..._ks wrapper to simplify usage
+
+```
+       if (!lws_map_item_create_ks(map, "123", (lws_map_value_t)"4567", 4))
+               /* fail */
+```
+
+## Lookups in the map
+
+You can retreive a pointer to an item in the map with a give key using
+
+```
+lws_map_item_t *
+lws_map_item_lookup(lws_map_t *map, const lws_map_key_t key, size_t keylen);
+```
+
+The item is opaque, but there are accessors
+
+|Accessor|Function|
+|---|---|
+|`lws_map_item_key(lws_map_item_t *_item)`|get a pointer to the item key|
+|`lws_map_item_value(lws_map_item_t *_item)`|get a pointer to the item value|
+|`lws_map_item_key_len(lws_map_item_t *_item)`|get the key length|
+|`lws_map_item_value_len(lws_map_item_t *_item)`|get the value length|
+
+Again there is a ..._ks() helper to simplify C strings as keys
+
+```
+       item = lws_map_item_lookup_ks(map, "abc");
+       if (!item)
+               /* fail */
+```
diff --git a/READMEs/README.lws_metrics.md b/READMEs/README.lws_metrics.md
new file mode 100644 (file)
index 0000000..82cd2a5
--- /dev/null
@@ -0,0 +1,245 @@
+## `lws_metrics`
+
+### Introduction
+
+`lws_metrics` records and aggregates **events** at all lws layers.
+
+There are three distinct parts:
+
+ - the architecture inside lws for collecting and aggregating / decimating the
+   events and maintaining statistics about them, these are lws_metric objects
+
+ - an external handler for forwarding aggregated metrics.  An lws_system ops
+   interface to pass on the aggregated metrics to an external backend.  lws
+   presents its own public metrics objects and leaves it to the external
+   code to have a shim to marry the lws metrics up to whatever is needed in the
+   metrics backend
+
+ - a policy for when to emit each type of aggregated information to the external
+   handler.  This can be specified in the generic Secure Streams policy, or
+   a linked-list of lws_metric_policy_t object passed it at context creation in
+   `info.metrics_policies`.
+
+The external backend interface code may itself make use of lws connectivity apis
+including Secure Streams itself, and lws metrics are available on that too.
+
+### `lws_metrics` policy-based reporting
+
+Normally metrics implementations are fixed at build-time and cannot change
+without a coordinated reflash of devices along with a change of backend schema.
+
+`lws_metrics` separates out the objects and code necessary to collect and
+aggregate the data cheaply, and the reporting policy that controls if, or how
+often, the results are reported to the external handler.
+
+![policy based metrics](/doc-assets/lws_metrics-policy.png)
+
+Metrics are created with a namespace name and the policy applies itself to those
+by listing the names, with wildcards allowed, the policy applies to, eg if
+specified in the Secure Streams JSON policy
+
+```
+       ...
+       "metrics": [
+                {
+                        "name":         "tensecs",
+                        "us_schedule":  10000000,
+                        "report":      "cpu.*"
+                }, {
+                        "name":         "30secs",
+                        "us_schedule":  30000000,
+                        "report":       "n.cn.*, n.http.*, n.ss.*, vh.*"
+                }
+        ],
+        ...
+```
+
+Metrics that do not have a reporting policy do not report, but continue to
+aggregate measurements in case they are bound to a policy dynamically later.
+
+### Freeform metrics naming
+
+There is no predefined metrics schema, metrics objects, including those created
+by applications, can independently choose their own name in a namespace like
+"cpu.srv" or "n.cn.dns", and can set a prefix for all metrics names created in a
+context (by setting `info.metrics_prefix` at context creation time).
+
+This allows multiple processes in a single device to expose copies of the same
+metrics in an individually addressable way, eg, if the UI process specifies the
+prefix "ui", then its lws metrics like "cpu.srv" will actually be created as
+"ui.cpu.srv".
+
+Applications can freely define their own `lws_metrics` measurements with their
+own names in the namespace too, without central registration, and refer to those
+names in the reporting policy same as any other metric names.
+
+If the metrics backend requires a fixed schema, the mapping between the
+`lws_metrics` names and the backend schema indexes will be done in the
+`lws_system` external reporting api implementation alone.  Metrics objects
+contain a `void * backend_opaque` that is ignored by lws and can be set and
+read by the external reporting handler implementation to facilitate that.
+
+### Histogram metrics tagging
+
+Histogram metrics track differently-qualified results in the same metric, for
+example the metric `n.cn.failures` maintains separate result counts for all
+variations and kinds of failure.
+
+```
+[2021/03/01 06:34:05:6570] U: my_metric_report: ssproxy.n.cn.failures{ss="badcert_selfsigned",hostname="invalidca.badcert.warmcat.com",peer="46.105.127.147",tls="invalidca"} 2
+[2021/03/01 06:34:05:6573] U: my_metric_report: ssproxy.n.cn.failures{hostname="invalidca.badcert.warmcat.com",peer="46.105.127.147",tls="invalidca"} 1
+[2021/03/01 06:34:05:6576] U: my_metric_report: ssproxy.n.cn.failures{ss="badcert_expired",hostname="warmcat.com",peer="46.105.127.147",tls="expired"} 2
+[2021/03/01 06:34:05:6578] U: my_metric_report: ssproxy.n.cn.failures{hostname="warmcat.com",peer="46.105.127.147",tls="expired"} 1
+[2021/03/01 06:34:05:6580] U: my_metric_report: ssproxy.n.cn.failures{ss="badcert_hostname",hostname="hostname.badcert.warmcat.com",peer="46.105.127.147",tls="hostname"} 2
+[2021/03/01 06:34:05:6583] U: my_metric_report: ssproxy.n.cn.failures{hostname="hostname.badcert.warmcat.com",peer="46.105.127.147",tls="hostname"} 1
+[2021/03/01 06:34:05:6585] U: my_metric_report: ssproxy.n.cn.failures{dns="nores -2"} 8
+```
+
+The user handler for metrics is expected to iterate these, in the provided
+examples (eg, minimal-secure-streams-testsfail)
+
+```
+#if defined(LWS_WITH_SYS_METRICS)
+static int
+my_metric_report(lws_metric_pub_t *mp)
+{
+       lws_metric_bucket_t *sub = mp->u.hist.head;
+       char buf[192];
+
+       do {
+               if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
+                       lwsl_user("%s: %s\n", __func__, buf);
+       } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
+
+       /* 0 = leave metric to accumulate, 1 = reset the metric */
+
+       return 1;
+}
+
+static const lws_system_ops_t system_ops = {
+       .metric_report = my_metric_report,
+};
+
+#endif
+```
+
+### `lws_metrics` decimation
+
+Event information can easily be produced faster than it can be transmitted, or
+is useful to record if everything is working.  In the case that things are not
+working, then eventually the number of events that are unable to be forwarded
+to the backend would overwhelm the local storage.
+
+For that reason, the metrics objects are designed to absorb and summarize a
+potentially large number of events cheaply by aggregating them, so even extreme
+situations can be tracked meaningfully inbetween dumps to the backend.
+
+There are two approaches:
+
+ - "aggregation": decimate keeping a uint64 mean + sum, along with a max and min
+ - "histogram": keep a linked-list of different named buckets, with a 64-bit
+   counter for the number of times an event in each bucket was observed
+
+A single metric aggregation object has separate "go / no-go" counters, since
+most operations can fail, and failing operations act differently.
+
+`lws_metrics` 'aggregation' supports decimation by
+
+ - a mean of a 64-bit event metric, separate for go and no-go events
+ - counters of go and no-go events
+ - a min and max of the metric
+ - keeping track of when the sample period started
+
+![metrics decimation](/doc-assets/lws_metrics-decimation.png)
+
+In addition, the policy defines a percentage variance from the mean that
+optionally qualifies events to be reported individually.
+
+The `lws_metrics` 'histogram' allows monitoring of different outcomes to
+produce counts of each outcome in the "bucket".  
+
+### `lws_metrics` flags
+
+When the metrics object is created, flags are used to control how it will be
+used and consumed.
+
+For example to create a histogram metrics object rather than the default
+aggregation type, you would give the flag `LWSMTFL_REPORT_HIST` at creation
+time.
+
+|Flag|Meaning|
+|---|---|
+|`LWSMTFL_REPORT_OUTLIERS`|track outliers and report them internally|
+|`LWSMTFL_REPORT_OUTLIERS_OOB`|report each outlier externally as they happen|
+|`LWSMTFL_REPORT_INACTIVITY_AT_PERIODIC`|explicitly externally report no activity at periodic cb, by default no events in the period is just not reported|
+|`LWSMTFL_REPORT_MEAN`|the mean is interesting for this metric|
+|`LWSMTFL_REPORT_ONLY_GO`|no-go pieces invalid and should be ignored, used for simple counters|
+|`LWSMTFL_REPORT_DUTY_WALLCLOCK_US`|the aggregated sum or mean can be compared to wallclock time| 
+|`LWSMTFL_REPORT_HIST`|object is a histogram (else aggregator)|
+
+### Built-in lws-layer metrics
+
+lws creates and maintains various well-known metrics when you enable build
+with cmake `-DLWS_WITH_SYS_METRICS=1`:
+
+#### Aggregation metrics
+|metric name|scope|type|meaning|
+---|---|---|---|
+`cpu.svc`|context|monotonic over time|time spent servicing, outside of event loop wait|
+`n.cn.dns`|context|go/no-go mean|duration of blocking libc DNS lookup|
+`n.cn.adns`|context|go/no-go mean|duration of SYS_ASYNC_DNS lws DNS lookup|
+`n.cn.tcp`|context|go/no-go mean|duration of tcp connection until accept|
+`n.cn.tls`|context|go/no-go mean|duration of tls connection until accept|
+`n.http.txn`|context|go (2xx)/no-go mean|duration of lws http transaction|
+`n.ss.conn`|context|go/no-go mean|duration of Secure Stream transaction|
+`n.ss.cliprox.conn`|context|go/no-go mean|time taken for client -> proxy connection|
+`vh.[vh-name].rx`|vhost|go/no-go sum|received data on the vhost|
+`vh.[vh-name].tx`|vhost|go/no-go sum|transmitted data on the vhost|
+
+#### Histogram metrics
+|metric name|scope|type|meaning|
+|---|---|---|---|
+`n.cn.failures`|context|histogram|Histogram of connection attempt failure reasons|
+
+#### Connection failure histogram buckets
+|Bucket name|Meaning|
+|---|---|
+`tls/invalidca`|Peer certificate CA signature missing or not trusted|
+`tls/hostname`|Peer certificate CN or SAN doesn't match the endpoint we asked for|
+`tls/notyetvalid`|Peer certificate start date is in the future (time wrong?)|
+`tls/expired`|Peer certificate is expiry date is in the past|
+`dns/badsrv`|No DNS result because couldn't talk to the server|
+`dns/nxdomain`|No DNS result because server says no result|
+
+The `lws-minimal-secure-streams` example is able to report the aggregated
+metrics at the end of execution, eg
+
+```
+[2021/01/13 11:47:19:9145] U: my_metric_report: cpu.svc: 137.045ms / 884.563ms (15%)
+[2021/01/13 11:47:19:9145] U: my_metric_report: n.cn.dns: Go: 4, mean: 3.792ms, min: 2.470ms, max: 5.426ms
+[2021/01/13 11:47:19:9145] U: my_metric_report: n.cn.tcp: Go: 4, mean: 40.633ms, min: 17.107ms, max: 94.560ms
+[2021/01/13 11:47:19:9145] U: my_metric_report: n.cn.tls: Go: 3, mean: 91.232ms, min: 30.322ms, max: 204.635ms
+[2021/01/13 11:47:19:9145] U: my_metric_report: n.http.txn: Go: 4, mean: 63.089ms, min: 20.184ms, max: 125.474ms
+[2021/01/13 11:47:19:9145] U: my_metric_report: n.ss.conn: Go: 4, mean: 161.740ms, min: 42.937ms, max: 429.510ms
+[2021/01/13 11:47:19:9145] U: my_metric_report: vh._ss_default.rx: Go: (1) 102, NoGo: (1) 0
+[2021/01/13 11:47:19:9145] U: my_metric_report: vh.le_via_dst.rx: Go: (22) 28.165Ki
+[2021/01/13 11:47:19:9145] U: my_metric_report: vh.le_via_dst.tx: Go: (1) 267
+[2021/01/13 11:47:19:9145] U: my_metric_report: vh.api_amazon_com.rx: Go: (1) 1.611Ki, NoGo: (1) 0
+[2021/01/13 11:47:19:9145] U: my_metric_report: vh.api_amazon_com.tx: Go: (3) 1.505Ki
+```
+
+lws-minimal-secure-stream-testsfail which tests various kinds of connection failure
+reports histogram results like this
+
+```
+[2021/01/15 13:10:16:0933] U: my_metric_report: n.cn.failures: tot: 36, [ tls/invalidca: 5, tls/expired: 5, tls/hostname: 5, dns/nxdomain: 21 ]
+```
+
+## Support for openmetrics
+
+Openmetrics https://tools.ietf.org/html/draft-richih-opsawg-openmetrics-00
+defines a textual metrics export format comaptible with Prometheus.  Lws
+provides a protocol plugin in `./plugins/protocol_lws_openmetrics_export`
+that enables direct export for prometheus scraping, and also protocols to
+proxy openmetrics export for unreachable servers.
diff --git a/READMEs/README.lws_plugins.md b/READMEs/README.lws_plugins.md
new file mode 100644 (file)
index 0000000..5a4b7d9
--- /dev/null
@@ -0,0 +1,105 @@
+# lws_plugins
+
+Lws now offers apis to manage your own user plugins with `LWS_WITH_PLUGINS_API`.
+Lws uses these apis internally for protocol plugins and event loop plugins
+if they're selected for build.  But they are also exported for user code to
+use them how you like.
+
+## Creating your plugin export
+
+### Specifying your plugin export type
+
+Lws plugins have a single exported struct with a specified header and a user
+defined remainder.  The public `lws_plugin_header_t` describes the common
+plugin export header, it's defined via libwebsockets.h as
+
+```
+typedef struct lws_plugin_header {
+       const char *name;
+       const char *_class;
+
+       unsigned int api_magic;
+       /* set to LWS_PLUGIN_API_MAGIC at plugin build time */
+
+       /* plugin-class specific superclass data follows */
+} lws_plugin_header_t;
+```
+
+The exported symbol name itself must match the plugin filename, for
+example if the symbol name is `my_plugin`, then the filename of the
+plugin might be `libmyapp-my_plugin.so` or similar... the matching
+part is after the first `-` or `_`, up to the first `.`.  The exact
+details differ by platform but these rules cover the supported
+platforms.  If lws has the filename of the plugin, it can then
+deduce the symbol export it should look for in the plugin.
+
+`name` is a freeform human-readable description for the plugin.
+
+`_class` is shared by your plugins and used to select them from other kinds
+of plugin that may be in the same dir.  So choose a unique name like
+`"myapp xxx plugin"` or whatever shared by all plugins of that class.
+
+`api_magic` is set to `LWS_PLUGIN_API_MAGIC` to detect if the plugin is
+incompatible with the lws plugin apis version.
+
+So for example your plugin type wrapping the header might look like
+
+```
+typedef struct myapp_plugin {
+        lws_plugin_header_t    hdr; /* must be first */
+
+       /* optional extra data like function pointers from your plugin */
+       mytype_t                mymember;
+       /* ... */
+} myapp_plugin_t;
+```
+
+Typically, you will put function pointers to whatever capability your plugin
+class offers as the additional members.
+
+## Building your own plugins
+
+Plugins are built standalone, cmake is recommended but you can do what you want.
+
+The only requirement is the single visible export of the plugin name, eg
+
+```
+const myapp_plugin_t my_plugin = {
+       .hdr = {
+               "my_plugin",
+               "myapp xxx plugin",
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .mymember       = my_plugin_init,
+       /*...*/
+};
+```
+
+## Bringing in plugins at runtime
+
+Lws provides an api to import plugins into the process space and another to
+remove and destroy plugins.
+
+You can take two approaches depending on what you're doing, either bring in and
+later destroy a whole class of plugins at once, and walk them via a linked-list,
+or bring in and later destroy a single specific plugin from the class by filtering
+on its specific export name.
+
+See `include/libwebsockets/lws-protocols-plugins.h` for documentation.
+
+```
+LWS_VISIBLE LWS_EXTERN int
+lws_plugins_init(struct lws_plugin **pplugin, const char * const *d,
+                const char *_class, const char *filter,
+                each_plugin_cb_t each, void *each_user);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_plugins_destroy(struct lws_plugin **pplugin, each_plugin_cb_t each,
+                   void *each_user);
+```
+
+`struct lws_plugin` is a public struct that contains the linked-list of loaded
+plugins and a pointer to its exported header object, so you can walk this
+after loading.
+
diff --git a/READMEs/README.lws_retry.md b/READMEs/README.lws_retry.md
new file mode 100644 (file)
index 0000000..03afcc2
--- /dev/null
@@ -0,0 +1,98 @@
+# `lws_retry_bo_t` client connection management
+
+This struct sets the policy for delays between retries, and for
+how long a connection may be 'idle' before it first tries to
+ping / pong on it to confirm it's up, or drops the connection
+if still idle.
+
+## Retry rate limiting
+
+You can define a table of ms-resolution delays indexed by which
+connection attempt number is ongoing, this is pointed to by
+`.retry_ms_table` with `.retry_ms_table_count` containing the
+count of table entries.
+
+`.conceal_count` is the number of retries that should be allowed
+before informing the parent that the connection has failed.  If it's
+greater than the number of entries in the table, the last entry is
+reused for the additional attempts.
+
+`.jitter_percent` controls how much additional random delay is
+added to the actual interval to be used... this stops a lot of
+devices all synchronizing when they try to connect after a single
+trigger event and DDoS-ing the server.
+
+The struct and apis are provided for user implementations, lws does
+not offer reconnection itself.
+
+## Connection validity management
+
+Lws has a sophisticated idea of connection validity and the need to
+reconfirm that a connection is still operable if proof of validity
+has not been seen for some time.  It concerns itself only with network
+connections rather than streams, for example, it only checks h2
+network connections rather than the individual streams inside (which
+is consistent with h2 PING frames only working at the network stream
+level itself).
+
+Connections may fail in a variety of ways, these include that no traffic
+at all is passing, or, eg, incoming traffic may be received but no
+outbound traffic is making it to the network, and vice versa.  In the
+case that tx is not failing at any point but just isn't getting sent,
+endpoints can potentially kid themselves that since "they are sending"
+and they are seeing RX, the combination means the connection is valid.
+This can potentially continue for a long time if the peer is not
+performing keepalives.
+
+"Connection validity" is proven when one side sends something and later
+receives a response that can only have been generated by the peer
+receiving what was just sent.  This can happen for some kinds of user
+transactions on any stream using the connection, or by sending PING /
+PONG protocol packets where the PONG is only returned for a received PING.
+
+To ensure that the generated traffic is only sent when necessary, user
+code can report for any stream that it has observed a transaction amounting
+to a proof of connection validity using an api.  This resets the timer for
+the associated network connection before the validity is considered
+expired.
+
+`.secs_since_valid_ping` in the retry struct sets the number of seconds since
+the last validity after which lws will issue a protocol-specific PING of some
+kind on the connection.  `.secs_since_valid_hangup` specifies how long lws
+will allow the connection to go without a confirmation of validity before
+simply hanging up on it.
+
+## Defaults
+
+The context defaults to having a 5m valid ping interval and 5m10s hangup interval,
+ie, it'll send a ping at 5m idle if the protocol supports it, and if no response
+validating the connection arrives in another 10s, hang up the connection.
+
+User code can set this in the context creation info and can individually set the
+retry policy per vhost for server connections.  Client connections can set it
+per connection in the client creation info `.retry_and_idle_policy`.
+
+## Checking for h2 and ws
+
+Check using paired minimal examples with the -v flag on one or both sides to get a
+small validity check period set of 3s / 10s
+
+Also give, eg, -d1039 to see info level debug logging
+
+### h2
+
+```
+$ lws-minimal-http-server-h2-long-poll -v
+
+$ lws-minimal-http-client -l -v
+```
+
+### ws
+
+```
+$ lws-minimal-ws-server-h2 -s -v
+
+$ lws-minimal-ws-client-ping -n --server 127.0.0.1 --port 7681 -v
+```
+
+
index fab0573..9a3b676 100644 (file)
@@ -1,4 +1,4 @@
-# `lws_sequencer_t` introduction
+# `struct lws_sequencer` introduction
 
 Often a single network action like a client GET is just part of a
 larger series of actions, perhaps involving different connections.
@@ -10,7 +10,7 @@ loop thread.
 
 ![lws_sequencer](/doc-assets/lws_sequencer.svg)
 
-`lws_sequencer_t` provides a generic way to stage multi-step
+`struct lws_sequencer` provides a generic way to stage multi-step
 operations from inside the event loop.  Because it participates
 in the event loop similar to a wsi, it always operates from the
 service thread context and can access structures that share the
@@ -48,7 +48,7 @@ only sends the message.  This allows the timeout to be used to, eg, wait
 out a retry cooloff period and then start the retry when the
 `LWSSEQ_TIMED_OUT` is received, according to the state of the sequencer.
 
-## Creating an `lws_sequencer_t`
+## Creating an `struct lws_sequencer`
 
 ```
 typedef struct lws_seq_info {
@@ -63,7 +63,7 @@ typedef struct lws_seq_info {
 ```
 
 ```
-lws_sequencer_t *
+struct lws_sequencer *
 lws_sequencer_create(lws_seq_info_t *info);
 ```
 
@@ -77,7 +77,7 @@ typedef int (*lws_seq_event_cb)(struct lws_sequencer *seq, void *user_data,
                                lws_seq_events_t event, void *data);
 ```
 
-`lws_sequencer_t` objects are private to lws and opaque to the user.  A small
+`struct lws_sequencer` objects are private to lws and opaque to the user.  A small
 set of apis lets you perform operations on the pointer returned by the
 create api.
 
@@ -95,7 +95,7 @@ callback from inside the event loop at a rate of one per event loop wait.
 
 ## Destroying sequencers
 
-`lws_sequencer_t` objects are cleaned up during context destruction if they are
+`struct lws_sequencer` objects are cleaned up during context destruction if they are
 still around.
 
 Normally the sequencer callback receives a queued message that
index 1908f10..f1cae4e 100644 (file)
@@ -60,3 +60,40 @@ In the case you destroy your object and need to cancel the scheduled callback, u
        lws_sul_schedule(context, 0, &sul_stagger, NULL, LWS_SET_TIMER_USEC_CANCEL);
 ```
 
+# lws_sul2 and system suspend
+
+In v4.1, alongside the existing `lws_sul` apis there is a refactor and additional
+functionality aimed at negotiating system suspend, while remaining completely
+backwards-compatible with v3.2+ lws_sul apis.
+
+Devicewide suspend is basically the withdrawal of CPU availability for an unbounded
+amount of time, so what may have been scheduled by the user code may miss its time
+slot because the cpu was down and nothing is getting serviced.  Whether that is
+actively desirable, OK, a big disaster, or a failure that will be corrected at other
+layers at the cost of, eg, some additional latency, depends on the required device
+behaviours and the function of the user code that was scheduled, and its meaning to
+the system.
+
+Before v4.1, lws just offers the same scheduling service for everything both internal
+and arranged by user code, and has no way to know what is critical for the device to
+operate as intended, and so must force wake from suspend, or if for that scheduled
+event 'failure [to get the event] is an option'.
+
+For example locally-initiated periodic keepalive pings not happening may allow
+persistently dead (ie, no longer passing data) connections to remain unrenewed, but
+eventually when suspend ends for another reason, the locally-initiated PING probes
+will resume and it will be discovered and if the connectivity allows, corrected.
+
+If the device's function can handle the latency of there being no connectivity in
+suspend under those conditions until it wakes for another reason, it's OK for these
+kind of timeouts to be suppressed during suspend and basically take the power saving
+instead.  If for a particular device it's intolerable to ever have a silently dead
+connection for more than a very short time compared to suspend durations, then these
+kind of timeouts must have the priority to wake the whole device from suspend so
+they continue to operate unimpeded.
+
+That is just one example, lws offers generic scheduler services the user code can
+exploit for any purpose, including mission-critical ones.  The changes give the user
+code a way to tell lws if a particular scheduled event is important enough to the
+system operation to wake the system from devicewide suspend.
+
diff --git a/READMEs/README.lws_system.md b/READMEs/README.lws_system.md
new file mode 100644 (file)
index 0000000..e1a91ee
--- /dev/null
@@ -0,0 +1,220 @@
+# `lws_system`
+
+See `include/libwebsockets/lws-system.h` for function and object prototypes.
+
+## System integration api
+
+`lws_system` allows you to set a `system_ops` struct at context creation time,
+which can write up some function callbacks for system integration.  The goal
+is the user code calls these by getting the ops struct pointer from the
+context using `lws_system_get_ops(context)` and so does not spread system
+dependencies around the user code, making it directly usable on completely
+different platforms.
+
+```
+typedef struct lws_system_ops {
+       int (*reboot)(void);
+       int (*set_clock)(lws_usec_t us);
+       int (*attach)(struct lws_context *context, int tsi, lws_attach_cb_t cb,
+                     lws_system_states_t state, void *opaque,
+                     struct lws_attach_item **get);
+} lws_system_ops_t;
+```
+
+|Item|Meaning|
+|---|---|
+|`(*reboot)()`|Reboot the system|
+|`(*set_clock)()`|Set the system clock|
+|`(*attach)()`|Request an event loop callback from another thread context|
+
+### `reboot`
+
+Reboots the device
+
+### `set_clock`
+
+Set the system clock to us-resolution Unix time in seconds
+
+### `attach`
+
+Request a callback from the event loop from a foreign thread.  This is used, for
+example, for foreign threads to set up their event loop activity in their
+callback, and eg, exit once it is done, with their event loop activity able to
+continue wholly from the lws event loop thread and stack context.
+
+## Foreign thread `attach` architecture
+
+When lws is started, it should define an `lws_system_ops_t` at context creation
+time which defines its `.attach` handler.  In the `.attach` handler
+implementation, it should perform platform-specific locking around a call to
+`__lws_system_attach()`, a public lws api that actually queues the callback
+request and does the main work.  The platform-specific wrapper is just there to
+do the locking so multiple calls from different threads to the `.attach()`
+operation can't conflict.
+
+User code can indicate it wants a callback from the lws event loop like this:
+
+```
+lws_system_get_ops(context)->attach(context, tsi, cb, state, opaque, NULL)
+```
+
+`context` is a pointer to the lws_context, `tsi` is normally 0, `cb` is the user
+callback in the form  
+
+```
+void (*lws_attach_cb_t)(struct lws_context *context, int tsi, void *opaque);
+```
+
+`state` is the `lws_system` state we should have reached before performing the
+callback (usually, `LWS_SYSTATE_OPERATIONAL`), and `opaque` is a user pointer that
+will be passed into the callback.
+
+`cb` will normally want to create scheduled events and set up lws network-related
+activity from the event loop thread and stack context.
+
+Once the event loop callback has been booked by calling this api, the thread and
+its stack context that booked it may be freed.  It will be called back and can
+continue operations from the lws event loop thread and stack context.  For that
+reason, if `opaque` is needed it will usually point to something on the heap,
+since the stack context active at the time the callback was booked may be long
+dead by the time of the callback. 
+
+See ./lib/system/README.md for more details.
+
+## `lws_system` blobs
+
+"Blobs" are arbitrary binary objects that have a total length.  Lws lets you set
+them in two ways
+
+ - "directly", by pointing to them, which has no heap implication
+
+ - "heap", by adding one or more arbitrary chunk to a chained heap object
+
+In the "heap" case, it can be incrementally defined and the blob doesn't all
+have to be declared at once.
+
+For read, the same api allows you to read all or part of the blob into a user
+buffer. 
+
+The following kinds of blob are defined 
+
+|Item|Meaning|
+|---|---|
+|`LWS_SYSBLOB_TYPE_AUTH`|Auth-related blob 1, typically a registration token|
+|`LWS_SYSBLOB_TYPE_AUTH + 1`|Auth-related blob 2, typically an auth token|
+|`LWS_SYSBLOB_TYPE_CLIENT_CERT_DER`|Client cert public part|
+|`LWS_SYSBLOB_TYPE_CLIENT_KEY_DER`|Client cert key part|
+|`LWS_SYSBLOB_TYPE_DEVICE_SERIAL`|Arbitrary device serial number|
+|`LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION`|Arbitrary firmware version|
+|`LWS_SYSBLOB_TYPE_DEVICE_TYPE`|Arbitrary Device Type identifier|
+|`LWS_SYSBLOB_TYPE_NTP_SERVER`|String with the ntp server address (defaults to pool.ntp.org)|
+
+### Blob handle api
+
+Returns an object representing the blob for a particular type (listed above)
+
+```
+lws_system_blob_t *
+lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
+                    int idx);
+```
+
+### Blob Setting apis
+
+Sets the blob to point length `len` at `ptr`.  No heap allocation is used.
+
+```
+void
+lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
+```
+
+Allocates and copied `len` bytes from `buf` into heap and chains it on the end of
+any existing.
+
+```
+int
+lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *buf, size_t len)
+```
+
+Remove any content from the blob, freeing it if it was on the heap
+
+```
+void
+lws_system_blob_heap_empty(lws_system_blob_t *b)
+```
+
+### Blob getting apis
+
+Get the total size of the blob (ie, if on the heap, the aggreate size of all the
+chunks that were appeneded)
+
+```
+size_t
+lws_system_blob_get_size(lws_system_blob_t *b)
+```
+
+Copy part or all of the blob starting at offset ofs into a user buffer at buf.
+`*len` should be the length of the user buffer on entry, on exit it's set to
+the used extent of `buf`.  This works the same whether the bob is a direct pointer
+or on the heap.
+
+```
+int
+lws_system_blob_get(lws_system_blob_t *b, uint8_t *buf, size_t *len, size_t ofs)
+```
+
+If you know that the blob was handled as a single direct pointer, or a single
+allocation, you can get a pointer to it without copying using this.
+
+```
+int
+lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr)
+```
+
+### Blob destroy api
+
+Deallocates any heap allocation for the blob
+
+```
+void
+lws_system_blob_destroy(lws_system_blob_t *b)
+```
+
+
+## System state and notifiers
+
+Lws implements a state in the context that reflects the readiness of the system
+for various steps leading up to normal operation.  By default it acts in a
+backwards-compatible way and directly reaches the OPERATIONAL state just after
+the context is created.
+
+However other pieces of lws, and user, code may define notification handlers
+that get called back when the state changes incrementally, and may veto or delay
+the changes until work necessary for the new state has completed asynchronously.
+
+The generic states defined are:
+
+|State|Meaning|
+|---|---|
+|`LWS_SYSTATE_CONTEXT_CREATED`|The context was just created.|
+|`LWS_SYSTATE_INITIALIZED`|The vhost protocols have been initialized|
+|`LWS_SYSTATE_IFACE_COLDPLUG`|Existing network interfaces have been iterated|
+|`LWS_SYSTATE_DHCP`|Network identity is available|
+|`LWS_SYSTATE_TIME_VALID`|The system knows the time|
+|`LWS_SYSTATE_POLICY_VALID`|If the system needs information about how to act from the net, it has it|
+|`LWS_SYSTATE_REGISTERED`|The device has a registered identity|
+|`LWS_SYSTATE_AUTH1`|The device identity has produced a time-limited access token|
+|`LWS_SYSTATE_AUTH2`|Optional second access token for different services|
+|`LWS_SYSTATE_OPERATIONAL`|The system is ready for user code to work normally|
+|`LWS_SYSTATE_POLICY_INVALID`|All connections are being dropped because policy information is changing.  It will transition back to `LWS_SYSTATE_INITIALIZED` and onward to `OPERATIONAL` again afterwards with the new policy|
+|`LWS_SYSTATE_CONTEXT_DESTROYING`|Context is going down and smd with it|
+
+### Inserting a notifier
+
+You should create an object `lws_system_notify_link_t` in non-const memory and zero it down.
+Set the `notify_cb` member and the `name` member and then register it using either
+`lws_system_reg_notifier()` or the `.register_notifier_list`
+member of the context creation info struct to make sure it will exist early
+enough to see all events.  The context creation info method takes a list of
+pointers to notify_link structs ending with a NULL entry.
+
index 65d67f8..7a1241d 100644 (file)
@@ -47,11 +47,10 @@ the following functions:
 
 ## License
 
-lws-ssh-base is Free Software, available under libwebsocket's LGPLv2 +
-static linking exception license.
+lws-ssh-base is Free Software, available under libwebsockets' MIT license.
 
 The crypto parts are available elsewhere under a BSD license.  But for
-simplicity the whole plugin is under LGPLv2.
+simplicity the whole plugin is under MIT.
 
 ## Generating your own keys
 
index 6d12f6f..9313582 100644 (file)
@@ -8,15 +8,15 @@ Older versions of lws don't attract any new work after they are released
 (see [the release policy](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.release-policy.md) for details);
 for a while they will get backported bugfixes but that's it.
 
-All new work and bugfixes happen on master branch.
+All new work and bugfixes happen on `main` branch.
 
 Old, old versions may be convenient for you to use for some reason.  But unless
 you pay for support or have contributed work to lws so we feel we owe you some
 consideration, nobody else has any reason to particularly care about solving
-issues on ancient versions.  Whereas if the problem exists on master, and can be
+issues on ancient versions.  Whereas if the problem exists on `main`, and can be
 reproduced by developers, it usually gets attention, often immediately.
 
-If the problem doesn't exist on master, you can either use master or check also
+If the problem doesn't exist on `main`, you can either use `main` or check also
 the -stable branch of the last released version to see if it was already solved
 there.
 
index 6fb457a..322b918 100644 (file)
@@ -1,29 +1,51 @@
 # lws release policy
 
-## Master branch
+## How should users consume lws?
+
+The one definitively wrong way to consume lws (or anything else) is "import" some
+version of it into your proprietary tree and think you will stick with that
+forever, perhaps piling cryptic fixes or hacks on top until quite quickly,
+nobody dare think about updating it.
+
+The stable releases go on to a branch like v4.0-stable as described below, over
+time these attract dozens or even hundreds of minor or major fix patches
+backported from the development branch.  So you should not consume tags like
+v4.0.0 but build into your planning that you will need to follow v4.0-stable in
+order to stay on top of known bugs.
+
+And we only backport fixes to the last stable release, although we will make
+exceptions for important fixes.  So after a while, trying to stick with one
+old versions means nobody is providing security fixes on it any more.  So you
+should build into your planning that you will follow lws release upgrades.
+
+If you find problems and create fixes, please upstream them, simplifying your
+life so you can just directly consume the upstream tree with no private changes.
+
+## Development
 
 Master branch is the default and all new work happens there.  It's unstable and
 subject to history rewrites, patches moving about and being squashed etc.  In
 terms of it working, it is subject to passing CI tests including a battery of
 runtime tests, so if it is passing CI as it usually is then it's probably in
-usable shape.
+usable shape.  See "Why no history on development" below for why it's managed like
+that.
 
-![all work happens on master](../doc-assets/lws-relpol-1.svg)
+![all work happens on main](../doc-assets/lws-relpol-1.svg)
 
-If you have patches (you are a hero) they should be targeted at master.
+If you have patches (you are a hero) they should be targeted at `main`.
 
 To follow such a branch, `git pull` is the wrong tool... the starting point
 of what you currently have may no longer exist remotely due to rearranging the
 patches there.  Instead use a flow like this:
 
 ```
- $ git fetch https://libwebsockets.org/repo/libwebsockets +master:m && git reset --hard m
+ $ git fetch https://libwebsockets.org/repo/libwebsockets +main:m && git reset --hard m
 ```
 
-This fetches current remote master into local branch `m`, and then forces your
+This fetches current remote development branch into local branch `m`, and then forces your
 local checkout to exactly match `m`.  This replaces your checked-out tree
 including any of your local changes, so stash those first, or use stgit or so
-to pop them before updating your basis against lws master.
+to pop them before updating your basis against lws development.
 
 ## Stable branches
 
@@ -31,23 +53,23 @@ Master is very useful for coordinating development, and integrating WIP,
 but for distros or integration into large user projects some stability is often
 more desirable than the latest development work.
 
-Periodically, when master seems in good shape and various new developments seem
-to be working, it's copied out into a versioned stable branch, like `v3.0-stable`.
+Periodically, when development seems in good shape and various new developments seem
+to be working, it's copied out into a versioned stable branch, like `v4.0-stable`.
 
-![stable branches are copied from master](../doc-assets/lws-relpol-2.svg)
+![stable branches are copied from development](../doc-assets/lws-relpol-2.svg)
 
-The initial copy is tagged with, eg, `v3.0.0`.
+The initial copy is tagged with, eg, `v4.0.0`.
 
-(At that time, master's logical version is set to "...99", eg, `v3.0.99` so
-version comparisons show that version of master is "later" than any other
-v3.0 version, which will never reach 99 point releases itself, but "earlier"
-than, eg, v3.1.)
+(At that time, development's logical version is set to "...99", eg, `v4.0.99` so
+version comparisons show that development version is "later" than any other
+v4.0 version, which will never reach 99 point releases itself, but "earlier"
+than, eg, v4.1.)
 
 ## Backport policy
 
-Work continues on master, and as part of that usually bugs are reported and / or
-fixes found that may apply not just to current master, but the version of master
-that was copied to form the last -stable branch.
+Development continues, and as part of that usually bugs are reported and / or
+fixes found that may apply not just to current development, but the version of
+the development branch that was copied to form the last -stable branch.
 
 In that case, the patch may be backported to the last stable branch to also fix
 the bug there.  In the case of refactors or major internal improvements, these
@@ -61,12 +83,13 @@ madness.
 When new stable releases are made, the soname is bumped reflecting the API is
 different than that of previous versions.
 
-![backports from master to stable](../doc-assets/lws-relpol-3.svg)
+![backports from main to stable](../doc-assets/lws-relpol-3.svg)
 
 If there is something you need in a later lws version that is not backported,
-you need to either backport it yourself (remember that lws is LGPL and you must
-provide your changes when you distribute the binary) or use a later lws version.
-Using a more recent version of lws is almost always the correct way.
+you need to either backport it yourself or use a later lws version.
+Using a more recent version of lws (and contributing fixes and changes so you
+yourself can get them easily as well as contributing for others) is almost
+always the correct way.
 
 ## Stable point releases
 
@@ -85,4 +108,19 @@ uncommon though.
 
 ![backport to multiple stable branches](../doc-assets/lws-relpol-5.svg)
 
+## Why no history on the development branch
+
+Git is a wonderful tool that can be understood to have two main modes of operation,
+merge and rebase that are mutually exclusive.  Most devs only use merge / pull,
+but rebase / fetch is much more flexible.  Developing via rebases allows me to
+dispense with feature branches during development and enables tracking multiple
+in-progress patches in-tree by updating them in place.  If this doesn't make
+sense or seems heretical to you, it's OK I don't need devsplain'ing about it,
+just sit back and enjoy the clean, rapid development results.
+
+Since stable branches don't allow new features, they are run as traditional trees
+with a history, like a one-way pile of patches on top of the original release.  If
+CI shows something is messed up with the latest patch, I will edit it in-place if
+it has only been out for a few hours, but there is no re-ordering or other history
+manipulation.
 
diff --git a/READMEs/README.routing.md b/READMEs/README.routing.md
new file mode 100644 (file)
index 0000000..7af8f5e
--- /dev/null
@@ -0,0 +1,51 @@
+# Lws routing
+
+lws is mainly built around POSIX sockets and operates from the
+information available from those.  But in some cases, it needs to go
+a step further and monitor and understand the device routing table.
+
+## Recognizing loss of routability
+
+On mobile devices, switching between interfaces and losing / regaining
+connections quickly is a given.  But POSIX sockets do not act like
+that, the socket remains connected until something times it out if it
+no longer has a route to its peer, and the tcp timeouts can be in the
+order of minutes.
+
+In order to do better, lws must monitor and understand how the routing
+table relates to existing connections, dynamically.
+
+## Linux: netlink
+
+For linux-based devices you can build in netlink-based route monitoring
+with `-DLWS_WITH_NETLINK=1`, lws aquires a copy of the routing table
+when the context / pt starts up and modifies it according to netlink
+messages from then on.
+
+On Linux routing table events do not take much care about backing out
+changes made on interface up by, eg, NetworkManager.  So lws also
+monitors for link / interface down to remove the related routes.
+
+## Actions in lws based on routing table
+
+Both server and client connections now store their peer sockaddr in the
+wsi, and when the routing table changes, all active wsi on a pt are
+checked against the routing table to confirm the peer is still
+routable.
+
+For example if there is no net route matching the peer and no gateway,
+the connection is invalidated and closed.  Similarly, if we are
+removing the highest priority gateway route, all connections to a peer
+without a net route match are invalidated.  However connections with
+an unaffected  matching net route like 127.0.0.0/8 are left alone.
+
+## Intergration to other subsystems
+
+If SMD is built in, on any route change a NETWORK message
+`{"rt":"add|del"}` is issued.
+
+If SMD is built in, on any route change involving a gateway, a NETWORK
+message `{"trigger":"cpdcheck", "src":"gw-change"}` is issued.  If
+Captive Portal Detection is built in, this will cause a new captive
+portal detection sequence.
+
diff --git a/READMEs/README.tcp_fastopen.md b/READMEs/README.tcp_fastopen.md
new file mode 100644 (file)
index 0000000..f9ca8eb
--- /dev/null
@@ -0,0 +1,32 @@
+# `TCP_FASTOPEN` support in lws
+
+Lws supports enabling TCP_FASTOPEN oper-vhost for listen sockets.
+
+## Enabling per vhost serving
+
+Set the `info.fo_listen_queue` to nonzero at vhost creation.  Different
+platforms interpret this number differently, zero always disables it
+but on Linux, the number is interpreted as a SYN queue length.
+
+On FreeBSD, OSX and Windows, the number is basically a bool, with the
+extra restriction OSX and Windows only allows 0 or 1.
+
+## Enabling Linux for serving with TCP_FASTOPEN
+
+To configure the kernel for listening socket TCP_FASTOPEN, you need
+
+```
+# sysctl -w net.ipv4.tcp_fastopen=3
+```
+
+## Enabling BSD for serving with TCP_FASTOPEN
+
+At least on FreeBSD, you need to set the net.inet.tcp.fastopen.enabled
+sysctl to 1
+
+## Enabling Windows for serving with TCP_FASTOPEN
+
+```
+> netsh int tcp set global fastopenfallback=disabled
+> netsh int tcp show global
+```
index 7565b43..4ae0b92 100644 (file)
@@ -24,7 +24,7 @@ lwsws.
 NOTE this method implies libuv is used by lws, to provide crossplatform
 implementations of timers, dynamic lib loading etc for plugins and lwsws.
 
-2) test-server-v2.0.c
+2) Using plugins in code
 
 This method lets you configure web serving in code, instead of using lwsws.
 
@@ -34,7 +34,7 @@ loaded.
 
  $ cmake .. -DLWS_WITH_PLUGINS=1
 
-See [test-server-v2.0.c](../test-apps/test-server-v2.0.c)
+See, eg, the [test-server](../test-apps/test-server.c)
 
 3) protocols in the server app
 
@@ -81,7 +81,7 @@ background and return immediately.  In this daemonized mode all stderr is
 disabled and logging goes only to syslog, eg, `/var/log/messages` or similar.
 
 The server maintains a lockfile at `/tmp/.lwsts-lock` that contains the pid
-of the master process, and deletes this file when the master process
+of the parent process, and deletes this file when the parent process
 terminates.
 
 To stop the daemon, do
@@ -302,7 +302,7 @@ By default it runs in server mode
 ```
        $ libwebsockets-test-fraggle
        libwebsockets test fraggle
-       (C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under LGPL2.1
+       (C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under MIT
         Compiled with SSL support, not using it
         Listening on port 7681
        server sees client connect
@@ -318,7 +318,7 @@ give the `-c` switch and the server address at least:
 ```
        $ libwebsockets-test-fraggle -c localhost
        libwebsockets test fraggle
-       (C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under LGPL2.1
+       (C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under MIT
         Client mode
        Connecting to localhost:7681
        denied deflate-stream extension
diff --git a/READMEs/README.tls-sessions.md b/READMEs/README.tls-sessions.md
new file mode 100644 (file)
index 0000000..5247555
--- /dev/null
@@ -0,0 +1,119 @@
+# Using TLS Session resumption
+
+Lws supports clientside session caching and session resumption on both mbedtls
+and openssl-type tls library backends, to accellerate connection re-
+establishment.
+
+## Background
+
+TLS specifies logical "sessions" that get "established" on both sides when the
+tls tunnel is negotiated... these are the object that gets validated by the
+certificate PKI.  They each have a server-unique "Session ID" of up to 32 bytes
+each.
+
+Normally the default is that there is a new session negotiated per connection,
+so multiple connections to the same endpoint each negotiate fresh sessions from
+scratch.
+
+However tls servers typically maintain a cache of recent sessions, and where
+both the server and client still have a copy of a previously-negotiated session
+around, support the client explicitly requesting additional connections binding
+to the old session by asking for it by its Session ID at negotiation time.
+
+### Re-use of validated sessions
+
+The advantage is that the timeconsuming key exchange part of the negotiation can
+be skipped, and a connection-specific AES key agreed at both sides just by
+hashing on the secret held in the session object at each side.  This allows new
+tunnels to be established much faster after the first, while the session from
+the first is still valid and available at both sides.
+
+Both the server and client may apply their own lifetime restriction to their
+copy of the session, the first side to expire it will cause a new session to be
+forced at the next reuse attempt.  Lifetimes above 24h are not recommended by
+RFC5246.
+
+### Multiple concurrent use of validated sessions
+
+In addition, the session's scope is any connection to the server that knows the
+original session ID, because individual new AES keys are hashed from the session
+secret, multiple connections to the same endpoint can take advantage of a single
+valid session object.
+
+### Difference from Session Tickets
+
+TLS also supports sessions as bearer tokens, but these are generally considered
+as degrading security.  Lws doesn't support Session Tickets, just reuse by
+Session IDs.
+
+## Support in lws
+
+Server-side TLS generally has session caching enabled by default.  For client
+side, lws now enables `LWS_WITH_TLS_SESSIONS` at cmake by default, which adds
+a configurable tls session cache that is automatically kept updated with a
+MRU-sorted list of established sessions.
+
+It's also possible to serialize sessions and save and load them, but this has to
+be treated with caution.
+
+Filling, expiring and consulting the session cache for client connections is
+performed automatically.
+
+### tls library differences
+
+Mbedtls supports clientside session caching in lws, but it does not have a
+session message arrival callback to synchronize updating the client session
+cache like openssl does.
+
+Separately, the session cb in boringssl is reportedly nonfunctional at the
+moment.
+
+To solve both cases, lws will schedule a check for the session at +500ms after
+the tls negotiation completed, and for the case the connection doesn't last
+500ms or the server is slow issuing the message, also attempt to update the
+cache at the time the tls connection object is closing.
+
+### Session namespacing in lws
+
+Internally sessions are referred to by a vhostname.hostname.port tuple.
+
+### Configuring the clientside cache
+
+Session caches in lws exist in and are bound to the vhost.  Different vhosts may
+provide different authentication (eg, client certs) to the same endpoint that
+another connection should not be able to take advantage of.
+
+The max size of this cache can be set at `.tls_session_cache_max` in the vhost
+creation info struct, if left at 0 then a default of 10 is applied.
+
+The Time-To-Live policy for sessions at the client can be set in seconds at
+`.tls_session_timeout`, by default whatever the tls library thinks it should be,
+perhaps 300s.
+
+You can disable session caching for a particular vhost by adding the vhost
+option flag `LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE` to `.options` at
+vhost creation time.
+
+### Session saving and loading
+
+Trying to make sessions really persistent is supported but requires extra
+caution.  RFC5246 says
+
+   Applications that may be run in relatively insecure environments should not
+   write session IDs to stable storage.
+
+The issue is that while in process memory the session object is relatively
+secure compared to sensitive secrets and tls library data already in process
+memory.
+
+But when serialized to, eg, some external, unencrypted medium, the accessibility
+of what is basically a secret able to decrypt tls connections can become a
+security hazard.  It's left to the user to take any necessary steps to secure
+sessions stored that way.
+
+For openssl, Public APIs are provided in `libwebsockets/lws-tls-sessions.h` to
+serialize any session in the cache associated with a vhost/host/port tuple, and
+to preload any available session into a vhost session cache by describing the
+endpoint hostname and port.
+
+The session saving and loading apis aren't supported for mbedtls yet.
diff --git a/READMEs/README.udp.md b/READMEs/README.udp.md
new file mode 100644 (file)
index 0000000..e986be8
--- /dev/null
@@ -0,0 +1,50 @@
+## Using UDP in lws
+
+UDP is supported in lws... the quickest way is to use the api
+`lws_create_adopt_udp()` which returns a wsi bound to the provided
+vhost, protocol, `lws_retry` struct, dns address and port.
+
+The wsi can be treated normally and `lws_write()` used to write on
+it.
+
+## Implementing UDP retries
+
+Retries are important in udp but there's no standardized ack method
+unlike tcp.  Lws allows you to bind an `lws_retry` struct describing
+the policy to the udp wsi, but since one UDP socket may have many
+transactions in flight, the `lws_sul` and `uint16_t` to count the
+retries must live in the user's transaction object like this
+
+```
+...
+       lws_sorted_usec_list_t  sul;
+       uint16_t                retry;
+...
+```
+
+in the `LWS_CALLBACK_RAW_WRITEABLE` callback, before doing the write,
+set up the retry like this
+
+```
+       if (lws_dll2_is_detached(&transaction->sul_write.list) &&
+           lws_retry_sul_schedule_retry_wsi(wsi, &transaction->sul_write,
+                                            transaction_retry_write_cb,
+                                            &transaction->retry_count_write)) {
+                       /* we have reached the end of our concealed retries */
+               lwsl_warn("%s: concealed retries done, failing\n", __func__);
+               goto retry_conn;
+       }
+```
+
+This manages the retry counter in the transaction object, guards against it wrapping,
+selects the timeout using the policy bound to the wsi, and sets the `lws_sul` in the
+transaction object to call the given callback if the sul time expires.
+
+In the callback, it should simply call `lws_callback_on_writable()` for the udp wsi.
+
+## Simulating packetloss
+
+You can simulate udp packetloss at tx and rx by using the Fault Injection apis
+with the well-known fault names "udp_tx_loss" and "udp_rx_loss", typically
+with the probabilistic setting, in commandline format something like
+`--fault-injection "wsi/udp_tx_loss(10%)"`
index ae06435..8cd8931 100644 (file)
@@ -7,6 +7,6 @@ direct email.
 ## Procedure for announcing vulnerability fixes
 
 The problem and fixed versions will be announced on the
-libwebsockets mailing list and a note added to the master
+libwebsockets mailing list and a note added to the `main`
 README.md.
 
index 2c6f180..fca3fea 100644 (file)
@@ -17,7 +17,11 @@ Libwebsockets covers a lot of interesting features for people making embedded se
 Please note you just need in include libwebsockets.h.  It includes all the individual
 includes in /usr/include/libwebsockets/ itself.
 
-You can browse by api category <a href="modules.html">here</a>
+Browse by <a href="modules.html">API category (module)</a>
+
+Browse by <a href="files.html">file listing</a>
+
+Browse by <a href="annotated.html">data structures</a>
 
 A collection of READMEs for build, coding, lwsws etc are <a href="pages.html">here</a>
 
index e142130..6693738 100644 (file)
@@ -36,45 +36,25 @@ Release Checklist
    set(CPACK_PACKAGE_VERSION_MINOR "6")
    set(CPACK_PACKAGE_VERSION_PATCH "0")
 
-5) specfile
+5) Announce latest version on README.md
 
- a) rpm version bump to match CMake one
+6) Make sure all new READMEs and public headers are in libwebsockets.dox
 
-  scripts/libwebsockets.spec
-
-   Version: 1.6.0
-
- b) Summarize changelog
-
-  scripts/libwebsockets.spec
-
-%changelog
-* Sun Jan 17 2016 Andrew Cooks <acooks@linux.com> 1.6.4-1
-- Bump version to 1.6.4
-- MINOR fix xyz
-
- c) Use -DLWS_WITH_DISTRO_RECOMMENDED=1 then make package and adapt the .spec
-    to match the file list
-
-6) Announce latest version on README.md
-
-7) Make sure all new READMEs and public headers are in libwebsockets.dox
-
-8) signed tag
+7) signed tag
 
   git tag -s vX.Y[.Z]
 
-9) git
+8) git
 
  a) push
  
  b) final CI check, if fail delete tag, kill pushed tags, restart flow
 
-10) website
+9) website
 
  a) update latest tag for release branch
 
-11) post-relase version bump
+10) post-relase version bump
 
 Bump the PATCH part of the version to 99
 
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644 (file)
index 809ff62..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-environment:
-  matrix:
-    - LWS_METHOD: jose
-      CMAKE_ARGS: -DLWS_WITH_JOSE=1
-
-    - LWS_METHOD: x64
-      CMAKE_ARGS: -DCMAKE_GENERATOR_PLATFORM=x64 -DLWS_WITH_HTTP2=1 -DLWS_WITH_PLUGINS=1 -DLIBUV_INCLUDE_DIRS=C:\assets\libuv64\include -DLIBUV_LIBRARIES=C:\assets\libuv64\libuv.lib
-
-    - LWS_METHOD: lwsws
-      CMAKE_ARGS: -DLWS_WITH_LWSWS=1 -DSQLITE3_INCLUDE_DIRS=C:\assets\sqlite3 -DSQLITE3_LIBRARIES=C:\assets\sqlite3\sqlite3.lib -DLIBUV_INCLUDE_DIRS=C:\assets\libuv\include -DLIBUV_LIBRARIES=C:\assets\libuv\libuv.lib
-
-    - LWS_METHOD: default
-
-    - LWS_METHOD: noserver
-      CMAKE_ARGS: -DLWS_WITHOUT_SERVER=ON
-
-    - LWS_METHOD: noclient
-      CMAKE_ARGS: -DLWS_WITHOUT_CLIENT=ON
-
-    - LWS_METHOD: noext
-      CMAKE_ARGS: -DLWS_WITHOUT_EXTENSIONS=ON
-
-    - LWS_METHOD: nossl
-      CMAKE_ARGS: -DLWS_WITH_SSL=OFF
-
-install:
-  - appveyor DownloadFile https://libwebsockets.org:444/win-libuv.zip
-  - mkdir c:\assets
-  - mkdir c:\assets\libuv
-  - 7z x -oc:\assets\libuv win-libuv.zip
-  - appveyor DownloadFile https://libwebsockets.org:444/win-libuv64.zip
-  - mkdir c:\assets\libuv64
-  - 7z x -oc:\assets\libuv64 win-libuv64.zip
-  - appveyor DownloadFile https://libwebsockets.org:444/nsis-3.0rc1-setup.exe
-  - cmd /c start /wait nsis-3.0rc1-setup.exe /S /D=C:\nsis
-  - appveyor DownloadFile https://libwebsockets.org:444/sqlite-dll-win32-x86-3130000.zip
-  - mkdir c:\assets\sqlite3
-  - 7z x -oc:\assets\sqlite3 sqlite-dll-win32-x86-3130000.zip
-  - SET PATH=C:\Program Files\NSIS\;C:\Program Files (x86)\NSIS\;c:\nsis;%PATH%
-
-build_script:
-  - md build
-  - cd build
-  - cmake -DCMAKE_BUILD_TYPE=Release %CMAKE_ARGS% ..
-  - cmake --build . --config Release
-
-after_build:
-  - cd %APPVEYOR_BUILD_FOLDER%
-  - mkdir staging
-  - mkdir staging\include
-  - cp -r %APPVEYOR_BUILD_FOLDER%\build\bin %APPVEYOR_BUILD_FOLDER%\build\lib staging
-  - if EXIST staging\bin\share mv staging\bin\share staging
-  - if NOT EXIST staging\share\libwebsockets-test-server mkdir staging\share\libwebsockets-test-server
-  - IF EXIST %APPVEYOR_BUILD_FOLDER%\build\libwebsockets-test-server.pem cp %APPVEYOR_BUILD_FOLDER%\build\libwebsockets-test-server.pem staging\share\libwebsockets-test-server
-  - IF EXIST %APPVEYOR_BUILD_FOLDER%\build\libwebsockets-test-server.key.pem cp %APPVEYOR_BUILD_FOLDER%\build\libwebsockets-test-server.key.pem staging\share\libwebsockets-test-server
-  - IF EXIST %APPVEYOR_BUILD_FOLDER%\build\lws_config.h cp %APPVEYOR_BUILD_FOLDER%\build\lws_config.h staging\include
-  - cp %APPVEYOR_BUILD_FOLDER%\include\libwebsockets.h staging\include
-  - cp -r %APPVEYOR_BUILD_FOLDER%\include\libwebsockets staging\include
-  - 7z a build\lws-%LWS_METHOD%-%APPVEYOR_BUILD_ID%.zip %APPVEYOR_BUILD_FOLDER%\staging\*
-
-artifacts:
-  - path: build\lws-%LWS_METHOD%-%APPVEYOR_BUILD_ID%.zip
-
-#deploy:
-#- provider: BinTray
-#  username: lws-team
-#  api_key:
-#    secure: nDpZ7P/wrk98DwJPMC6KpCC23QrVP8f3RxvKzBaqOmb9LiVrg1IyO1cc5vcgShZC
-#  subject: lws-team
-#  repo: libwebsockets
-#  package: windows
-#  publish: true
-#  override: true
-#  explode: false
-
-matrix:
-  fast_finish: true
diff --git a/bug_report.md b/bug_report.md
new file mode 100644 (file)
index 0000000..07a81d1
--- /dev/null
@@ -0,0 +1,38 @@
+** What version of lws **
+
+"vx.y.z" or "01234567 from `main` thismorning" etc
+
+If it's much older than last stable release, we will likely suggest you try that
+or `main`.
+
+** What platform and arch? **
+
+"Fedora 32 x86_64" or "OSX Catalina" etc
+
+** What parts of lws does it involve? **
+
+dunno / core / client / server
+raw / http / ws / mqtt / other (give me a hint)
+
+** How can I reproduce the problem just using lws code? **
+
+We can't guess your problem especially in your code.  It's great if you can give us a way to
+realize our own failure clearly with a reproducer that uses our own code.
+
+Try to remove your code from the equation by trying the same flow on an lws minimal example and provide a little diff against that. We can find out if it's only on your platform, or only on that version, or only in your code from that quickly, and if something to fix in lws, I can confirm it really is fixed using the same test.
+
+** Describe the bug **
+
+    "fails" --> this word is a red flag you didn't try to debug the issue much... exactly how does it "fail", what evidence is it leaving like logs or return codes or traces?
+    "hangs" --> this word is a red flag you didn't try to debug the issue much... exactly what does it mean, whole device frozen? Spinning 100% cpu? Just idle? Building on fire? Have you tried it via strace or similar if it seems frozen to see what it's doing? Attach a debugger like gdb -p pid and get a backtrace? perf top if Linux to see what it spends its time on.
+    "crashes" --> what happens if you run under valgrind? You know lws is not threadsafe except for lws_cancel_service(), right...
+    "sucks" --> let's discuss you writing a patch to improve whatever it is
+
+** Additional data **
+
+Build problems? Describe the toolchain and paste the warnings / errors.
+
+Crash? Get a usable backtrace by building with `cmake .. -DCMAKE_BUILD_TYPE=DEBUG` and run under gdb, lldb, or valgrind.
+
+Mysterious happenings? Get verbose lws logs by building with `cmake .. -DCMAKE_BUILD_TYPE=DEBUG` and run with `lws_set_log_level(1151, NULL)`, on the example apps they all take a switch like -d1151.
+
index 0783fee..e1f4830 100644 (file)
--- a/changelog
+++ b/changelog
@@ -1,6 +1,288 @@
 Changelog
 ---------
 
+v4.3.0
+======
+
+ - Add full CBOR stream parsing and writing support, with huge
+   amount of test vectors and resumable printf type write apis
+   See ./READMEs/README.cbor-lecp.md
+ - Add COSE key and signing / validation support with huge amount of
+   test vectors
+    cose_sign[1] ES256/384/512, RS256/384/512
+    cose_mac0    HS256/384/512
+   See ./READMEs/README.cbor-cose.md
+ - JIT Trust: for constrained devices, provides a way to determine the
+   trusted CA certs the peer requires, and instantiate just those.
+   This allows generic client browsing without the overhead of ~130
+   x.509 CA certs in memory permanently.
+   See ./READMEs/README.jit-trust.md
+ - Add support for client Netscape cookie jar with caching
+ - Secure Streams: issue LWSSSCS_EVENT_WAIT_CANCELLED state() when
+   lws_cancel_service() called, so cross-thread events can be handled
+   in SS
+ - Actively assert() on attempt to destroy SS handles still active in
+   the call stack, use DESTROY_ME returns instead so caller can choose
+   how to handle it.
+ - Improved Client Connection Error report strings for tls errors
+ - SMP: Use a private fakewsi for PROTOCOL_INIT so pts cannot try to
+   use the same one concurrently
+ - MbedTLS v3 support for all release changes, as well as retaining
+   support for v2.x
+ - MQTT client: support QoS2
+ - Event lib ops can now be set at context creation time directly,
+   bringing full event lib hooking to custom event loops.  See
+   minimal-http-server-eventlib-custom
+ - Extra APIs to recover AKID and SKID from x.509 in mbedtls and openssl
+ - Improve http redirect to handle h2-> h2 cleanly
+ - IPv4+6 listen sockets on vhosts are now done with two separate
+   sockets bound individually to AF_INET and AF_INET6 addresses,
+   handled by the same vhost listen flow.
+ - Improved tls restriction handling
+ - Log contexts: allow objects to log into local logging contexts, by
+   lws_context, vhost, wsi and ss handle.  Each context has its own
+   emit function and log level. See ./READMEs/README.logging.md
+ - Upgrade compiler checking to default to -Werror -Wall -Wextra
+ - Fault injection apis now also support pseudo-random number binding
+   within a specified range, eg,
+   --fault-injection "f1(10%),f1_delay(123..456)"
+ - Remove LWS_WITH_DEPRECATED_THINGS, remove master branch
+ - Interface binding now uses ipv6 scoring to select bind address
+
+v4.2.0
+======
+
+ - Sai coverage upgrades, 495 builds on 27 platforms, including OSX M1,
+   Xenial, Bionic and Focal Ubuntu, Debian Sid and Buster on both 32 and
+   64-bit OS, and NetBSD, Solaris, FreeBSD, Windows, ESP32.
+   Ctest run on more scenarios including all LWS_WITH_DISTRO_RECOMMENDED.
+   More tests use valgrind if available on platform.
+ - RFC7231 date and time parsing and retry-after wired up to lws_retry
+ - `LWS_WITH_SUL_DEBUGGING` checks that no sul belonging to Secure Streams
+   and wsi objects are left registered on destruction
+ - Netlink monitoring on Linux dynamically tracks interface address and
+   routing changes, and immediately closes connections on invalidated
+   routes.
+ - RFC6724 DNS results sorting over ipv4 + ipv6 results, according to
+   available dynamic route information
+ - Support new event library, sdevent (systemd native loop), via
+   `LWS_WITH_SDEVENT`
+ - Reduce .rodata cost of role structs by making them sparse
+ - Additional Secure Streams QA tests and runtime state transition
+   validation
+ - SMD-over-ss-proxy documentation and helpers to simplify forwarding
+ - SSPC stream buffering at proxy and client set from policy by streamtype
+ - Trigger Captive Portal Detection if DNS resolution fails
+ - Switch all logs related to wsi and Secure Streams to use unique,
+   descriptive tags instead of pointers (which may be reallocated)
+ - Use NOITCE logging for Secure Streams and wsi lifecycle logging using
+   tags
+ - Update SSPC serialization to include versioning on initial handshake,
+   and pass client pid to proxy so related objects are tagged with it
+ - Enable errors on -Wconversion pedantic type-related build issues
+   throughout the lws sources and upgrade every affected cast.
+ - Windows remove WSA event implementation and replace with WSAPoll, with
+   a pair of UDP sockets instead of pipe() for `lws_cancel_service()`
+ - `lws_strcmp_wildcard()` helper that understand "x*", "x*y", "x*y*" etc
+ - `LWS_WITH_PLUGINS_BUILTIN` cmake option just builds plugins into the main
+ library image directly
+ - Secure Streams proxy supports policy for flow control between proxy and
+ clients
+ - libressl also supported along with boringssl, wolfssl
+ - prepared for openssl v3 compatibility, for main function and GENCRYPTO
+ - Fault injection apis can confirm operation of 48 error paths and counting
+ - `LWS_WITH_SYS_METRICS` keeps stats and reports them to user-defined
+ function, compatible with openmetrics
+ - windows platform knows how to prepare openssl with system trust store certs
+ - `LWS_WITH_SYS_CONMON` allows selected client connections to make precise
+ measurements of connection performance and DNS results, and report them in a struct
+ - New native support for uloop event loop (OpenWRT loop)
+ - More options around JWT
+ - Support TLS session caching and reuse by default, on both OpenSSL and
+ mbedtls
+ - Many fixes and improvements...
+
+v4.1.0
+======
+
+ - NEW: travis / appveyor / bintray are replaced by Sai
+   https://libwebsockets.org/sai/ which for lws currently does 193 builds per
+   git push on 16 platforms, all self-hosted.  The homebrew bash scripts used
+   to select Minimal examples are replaced by CTest.  Platforms currently
+   include Fedora/AMD/GCC, Windows/AMD/mingw32, Windows/AMD/mingw64, Android/
+   aarch64/LLVM, esp-idf (on WROVER-KIT and HELTEC physical boards), Fedora/
+   RISCV (on QEMU)/GCC, CentOS8/AMD/GCC, Gentoo/AMD/GCC, Bionic/AMD/GCC,
+   Linkit 7697, Focal/AMD/GCC, Windows (on QEMU)/AMD/MSVC,
+   Focal/aarch64-RPI4/GCC, iOS/aarch64/LLVM and OSX/AMD/LLVM.
+
+ - NEW: The single CMakeLists.txt has been refactored and modernized into smaller
+ CMakeLists.txt in the subdirectory along with the code that is being managed
+ for build by it.  Build options are still listed in the top level as before
+ but the new way is much more maintainable.
+
+ - NEW: event lib support on Unix is now built into dynamically loaded plugins
+ and brought in at runtime, allowing all of the support to be built in
+ isolation without conflicts, and separately packaged with individual
+ dependencies.  See ./READMEs/event-libs.md for details and how to force
+ the old static build into lws method.
+
+ - NEW: Captive Portal Detection.  Lws can determine if the active default
+ route is able to connect to the internet, or is in a captive portal type
+ situation, by trying to connect to a remote server that will respond in an
+ unusual way, like provide a 204.
+
+ - NEW: Secure streams: Support system trust store if it exists
+                        Build on Windows
+                       Support lws raw socket protocol in SS
+                       Support Unix Domain Socket transport
+
+ - NEW: Windows: Support Unix Domain Sockets same as other platforms
+
+ - NEW: Windows: Build using native pthreads, async dns, ipv6 on MSVC
+
+ - NEW: lws_struct: BLOB support
+
+ - NEW: lws_sul: Now provides two sorted timer domains, a default one as
+ before, and another whose scheduled events are capable to wake the system from suspend
+
+ - NEW: System Message Distribution: lws_smd provides a very lightweight way
+ to pass short messages between subsystems both in RTOS type case where the
+ subsystems are all on the lws event loop, and in the case participants are in
+ different processes, using Secure Streams proxying.   Participants register a bitmap
+ of message classes they care about; if no particpant cares about a particular message,
+ it is rejected at allocation time for the sender, making it cheap to provide messages
+ speculatively.  See lib/system/smd/README.md for full details.
+
+ - NEW: lws_drivers: wrappers for SDK driver abstractions (or actual drivers)
+                See lib/drivers/README.md, example implementations
+                minimal-examples/embedded/esp32/esp-wrover-kit
+                     - generic gpio
+                    - generic LED (by name)    lib/drivers/led/README.md
+                    - generic PWM, sophisticated interpolated table
+                                   sequencers with crossfade  
+                    - generic button (by name), with debounce and press classification
+                                      emitting rich SMD click, long-click, double-click,
+                                      down, repeat, up JSON messages
+                                      lib/drivers/button/README.md
+                    - bitbang i2c on generic gpio (hw support can use same
+                                      abstract API)
+                    - bitbang spi on generic gpio (hw support can use same
+                                      abstract API)
+                    - generic display object, can be wired up to controller
+                                 drivers that hook up by generic i2c or spi,
+                                 generic backlight PWM sequencing and
+                                 blanking timer support
+                    - generic settings storage: get and set blobs by name
+                    - generic network device: netdev abstract class with
+                                              WIFI / Ethernet implementations
+                                              using underlying SDK APIs;
+                                              generic 80211 Scan managements
+                                              and credentials handling via
+                                              lws_settings
+                    This is the new way to provide embedded platform
+                    functionality that was in the past done like
+                    esp32-factory.  Unlike the old way, the new way has no
+                    native apis in it and can be built on other SDK / SoCs
+                    the same.
+
+ - NEW: Security-aware JWS JWT (JSON Web Tokens) apis are provided on top of the existing
+ JOSE / JWS apis.  All the common algorithms are available along with some
+ high level apis like lws http cookie -> JWT struct -> lws http cookie.
+
+ - REMOVED: esp32-helper and friends used by esp32-factory now lws_drivers
+ exists
+
+ - REMOVED: generic sessions and friends now JWT is provided
+
+v4.0.0
+======
+
+ - NEW: Lws is now under the MIT license, see ./LICENSE for details
+ - NEW: GLIB native event loop support, lws + gtk example
+
+ - NEW: native lws MQTT client... supports client stream binding like h2 when
+   multiple logical connections are going to the same endpoint over MQTT, they
+   transparently and independently share the one connection + tls tunnel
+ - NEW: "Secure Streams"... if you are making a device with client connections
+   to the internet or cloud, this allows separation of the communications
+   policy (endpoints, tls cert validation, protocols, etc) from the code, with
+   the goal you can combine streams, change protocols and cloud provision, and
+   reflect that in the device's JSON policy document without having to change
+   any code.
+
+ - NEW: lws_system: New lightweight and efficient Asynchronous DNS resolver
+   implementation for both A and AAAA records, supports recursive (without
+   recursion in code) lookups, caching, and getaddrinfo() compatible results
+   scheme (from cache directly without per-consumer allocation).  Able to
+   perform DNS lookups without introducing latency in the event loop.
+
+ - NEW: lws_system: ntpclient implementation with interface for setting system
+   time via lws_system ops
+ - NEW: lws_system: dhcpclient implementation
+ - NEW: Connection validity tracking, autoproduce PING/PONG for protocols that
+   support it if not informed that the connection has passed data in both
+   directions recently enough
+
+ - NEW: lws_retry: standardized exponential backoff and retry timing based
+   around backoff table and lws_sul
+
+ - NEW: there are official public helpers for unaligned de/serialization of all
+   common types, see eh, lws_ser_wu16be() in include/libwebsockets/lws-misc.h
+
+ - NEW: lws_tls_client_vhost_extra_cert_mem() api allows attaching extra certs
+   to a client vhost from DER in memory
+   
+ - NEW: lws_system: generic blobs support passing auth tokens, per-connection
+   client certs etc from platform into lws
+
+ - NEW: public helpers to consume and produce ipv4/6 addresses in a clean way,
+   along with lws_sockaddr46 type now public.  See eg, lws_sockaddr46-based
+   lws_sa46_parse_numeric_address(), lws_write_numeric_address()
+   in include/libwebsockets/lws-network-helper.h
+
+ - Improved client redirect handling, h2 compatibility
+ - NEW: lwsac: additional features for constant folding support (strings that
+   already are in the lwsac can be pointed to without copying again), backfill
+   (look for gaps in previous chunks that could take a new use size), and
+   lwsac_extend() so last use() can attempt to use more unallocated chunk space
+
+ - NEW: lws_humanize: apis for reporting scalar quanties like 1234 as "1.234KB"
+   with the scaled symbol strings passed in by caller
+
+ - NEW: freertos: support lws_cancel_service() by using UDP pair bound to lo,
+   since it doesn't have logical pipes
+
+ - NEW: "esp32" plat, which implemented freertos plat compatibility on esp32, is
+   renamed to "freertos" plat, targeting esp32 and other freertos platforms
+
+ - NEW: base64 has an additional api supporting stateful decode, where the input
+   is not all in the same place at the same time and can be processed
+   incrementally
+
+ - NEW: lws ws proxy: support RFC8441
+   
+ - NEW: lws_spawn_piped apis: generic support for vforking a process with child
+   wsis attached to its stdin, stdout and stderr via pipes.  When processes are
+   reaped, a specified callback is triggered.  Currently Linux + OSX.
+   
+ - NEW: lws_fsmount apis: Linux-only overlayfs mount and unmount management for
+   aggregating read-only layers with disposable, changeable upper layer fs
+
+ - Improvements for RTOS / small build case bring the footprint of lws v4 below
+   that of v3.1 on ARM 
+   
+ - lws_tokenize: flag specifying # should mark rest of line as comment
+
+ - NEW: minimal example for integrating libasound / alsa via raw file
+
+ - lws_struct: sqlite and json / lejp translation now usable
+
+
 v3.2.0
 ======
 
@@ -445,627 +727,4 @@ See README.lwsws.md for more information.
  See README.coding.md
 
 
-v2.1.0
-======
-
-Major new features
-
- - Support POST arguments, including multipart and file attachment
-
- - Move most of lwsws into lws, make the stub CC0
-
- - Add loopback test plugin to confirm client ws / http coexistence
-
- - Integrate lwsws testing on Appveyor (ie, windows)
-
- - Introduce helpers for sql, urlencode and urldecode sanitation
-
- - Introduce LWS_CALLBACK_HTTP_BIND_PROTOCOL / DROP_PROTOCOL that
- are compatible with http:/1.1 pipelining and different plugins
- owning different parts of the URL space
-
- - lwsgs - Generic Sessions plugin supports serverside sessions,
- cookies, hashed logins, forgot password etc
-
- - Added APIs for sending email to SMTP servers
-
- - Messageboard example plugin for lwsgs
-
- - Automatic PING sending at fixed intervals and close if no response
-
- - Change default header limit in ah to 4096 (from 1024)
-
- - Add SNI matching for wildcards if no specific wildcard vhost name match
-
- - Convert docs to Doxygen
-
- - ESP8266 support ^^
-
-Fixes
------
-
-See git log v2.0.0..
-
-
-
-v2.0.0
-======
-
-Summary
--------
-
- - There are only api additions, the api is compatible with v1.7.x.  But
-   there is necessarily an soname bump to 8.
- - If you are using lws client, you mainly need to be aware the option
-   LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT is needed at context-creation time
-   if you will use SSL.
-   
- - If you are using lws for serving, the above is also true but there are
-   many new features to simplify your code (and life).  There is a
-   summany online here
-   
-     https://libwebsockets.org/lws-2.0-new-features.html
-     
-   but basically the keywords are vhosts, mounts and plugins.  You can now
-   do the web serving part from lws without any user callback code at all.
-   See ./test-server/test-server-v2.0.c for an example, it has no user
-   code for ws either since it uses the protocol plugins... that one C file
-   is all that is needed to do the whole test server function.
-   
-   You now have the option to use a small generic ws-capable webserver
-   "lwsws" and write your ws part as a plugin.  That eliminates even
-   cut-and-pasting the test server code and offers more configurable
-   features like control over http cacheability in JSON.
-
-
-Fixes
------
-
-These are already in 1.7.x series
-
-1) MAJOR (Windows-only) fix assert firing
-
-2) MAJOR http:/1.1 connections handled by  lws_return_http_status() did not
-get sent a content-length resulting in the link hanging until the peer closed
-it.  attack.sh updated to add a test for this.
-
-3) MINOR An error about hdr struct in _lws_ws_related is corrected, it's not
-known to affect anything until after it was fixed
-
-4) MINOR During the close shutdown wait state introduced at v1.7, if something
-requests callback on writeable for the socket it will busywait until the
-socket closes
-
-5) MAJOR Although the test server has done it for a few versions already, it
-is now required for the user code to explicitly call
-
-       if (lws_http_transaction_completed(wsi))
-               return -1;
-
-when it finishes replying to a transaction in http.  Previously the library
-did it for you, but that disallowed large, long transfers with multiple
-trips around the event loop (and cgi...).
-
-6) MAJOR connections on ah waiting list that closed did not get removed from
-the waiting list...
-
-7) MAJOR since we added the ability to hold an ah across http keepalive
-transactions where more headers had already arrived, we broke the ability
-to tell if more headers had arrived.  Result was if the browser didn't
-close the keepalive, we retained ah for the lifetime of the keepalive,
-using up the pool.
-
-8) MAJOR windows-only-POLLHUP was not coming
-
-9) Client should not send ext hdr if no exts
-
-Changes
--------
-
-1) MINOR test-server gained some new switches
-
-   -C <file>  use external SSL cert file
-   -K <file>  use external SSL key file
-   -A <file>  use external SSL CA cert file
-   
-   -u <uid>  set effective uid
-   -g <gid>  set effective gid
-
-together you can use them like this to have the test-server work with the
-usual purchased SSL certs from an official CA.
-
-   --ssl -C your.crt -K your.key -A your.cer -u 99 -g 99
-
-2) MINOR the OpenSSL magic to setup ECDH cipher usage is implemented in the
-library, and the ciphers restricted to use ECDH only.
-Using this, the lws test server can score an A at SSLLABS test
-
-3) MINOR STS (SSL always) header is added to the test server if you use --ssl.  With
-that, we score A+ at SSLLABS test
-
-4) MINOR daemonize function (disabled at cmake by default) is updated to work
-with systemd
-
-5) MINOR example systemd .service file now provided for test server
-(not installed by default)
-
-6) test server html is updated with tabs and a new live server monitoring
-feature.  Input sanitization added to the js.
-
-7) client connections attempted when no ah is free no longer fail, they are
-just deferred until an ah becomes available.
-
-8) The test client pays attention to if you give it an http:/ or https://
-protocol string to its argument in URL format.  If so, it stays in http[s]
-client mode and doesn't upgrade to ws[s], allowing you to do generic http client
-operations.  Receiving transfer-encoding: chunked is supported.
-
-9) If you enable -DLWS_WITH_HTTP_PROXY=1 at cmake, the test server has a
-new URI path http://localhost:7681/proxytest If you visit here, a client
-connection to http://example.com:80 is spawned, and the results piped on
-to your original connection.
-
-10) Also with LWS_WITH_HTTP_PROXY enabled at cmake, lws wants to link to an
-additional library, "libhubbub".  This allows lws to do html rewriting on the
-fly, adjusting proxied urls in a lightweight and fast way.
-
-11) There's a new context creation flag LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT,
-this is included automatically if you give any other SSL-related option flag.
-If you give no SSL-related option flag, nor this one directly, then even
-though SSL support may be compiled in, it is never initialized nor used for the
-whole lifetime of the lws context.
-
-Conversely in order to prepare the context to use SSL, even though, eg, you
-are not listening on SSL but will use SSL client connections later, you must
-give this flag explicitly to make sure SSL is initialized.
-
-
-User API additions
-------------------
-
-1) MINOR APIBREAK There's a new member in struct lws_context_creation_info, ecdh_curve,
-which lets you set the name of the ECDH curve OpenSSL should use.  By
-default (if you leave ecdh_curve NULL) it will use "prime256v1"
-
-2) MINOR NEWAPI It was already possible to adopt a foreign socket that had not
-been read from using lws_adopt_socket() since v1.7.  Now you can adopt a
-partially-used socket if you don't need SSL, by passing it what you read
-so it can drain that before reading from the socket.
-
-LWS_VISIBLE LWS_EXTERN struct lws *
-lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
-               const char *readbuf, size_t len);
-
-3) MINOR NEWAPI CGI type "network io" subprocess execution is now possible from
-a simple api.
-
-LWS_VISIBLE LWS_EXTERN int
-lws_cgi(struct lws *wsi, char * const *exec_array,  int script_uri_path_len,
-        int timeout_secs);
-
-LWS_VISIBLE LWS_EXTERN int
-lws_cgi_kill(struct lws *wsi);
-
-To use it, you must first set the cmake option
-
-$ cmake .. -DLWS_WITH_CGI=1
-
-See test-server-http.c and  test server path
-
-http://localhost:7681/cgitest
-
-stdin gets http body, you can test it with wget
-
-$ echo hello > hello.txt
-$ wget http://localhost:7681/cgitest --post-file=hello.txt -O- --quiet
-lwstest script
-read="hello"
-
-The test script returns text/html table showing /proc/meminfo.  But the cgi
-support is complete enough to run cgit cgi.
-
-4) There is a helper api for forming logging timestamps
-
-LWS_VISIBLE int
-lwsl_timestamp(int level, char *p, int len)
-
-this generates this kind of timestamp for use as logging preamble
-
-lwsts[13116]: [2016/01/25 14:52:52:8386] NOTICE: Initial logging level 7
-
-5) struct lws_client_connect_info has a new member
-
- const char *method
-If it's NULL, then everything happens as before, lws_client_connect_via_info()
-makes a ws or wss connection to the address given.
-
-If you set method to a valid http method like "GET", though, then this method
-is used and the connection remains in http[s], it's not upgraded to ws[s].
-
-So with this, you can perform http[s] client operations as well as ws[s] ones.
-
-There are 4 new related callbacks
-
-       LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP                    = 44,
-       LWS_CALLBACK_CLOSED_CLIENT_HTTP                         = 45,
-       LWS_CALLBACK_RECEIVE_CLIENT_HTTP                        = 46,
-       LWS_CALLBACK_COMPLETED_CLIENT_HTTP                      = 47,
-
-6) struct lws_client_connect_info has a new member
-
- const char *parent_wsi
-if non-NULL, the client wsi is set to be a child of parent_wsi.  This ensures
-if parent_wsi closes, then the client child is closed just before.
-
-7) If you're using SSL, there's a new context creation-time option flag
-LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS.  If you give this, non-ssl
-connections to the server listen port are accepted and receive a 301
-redirect to / on the same host and port using https://
-
-8) User code may set per-connection extension options now, using a new api
-"lws_set_extension_option()".
-
-This should be called from the ESTABLISHED callback like this
-
- lws_set_extension_option(wsi, "permessage-deflate",
-                          "rx_buf_size", "12"); /* 1 << 12 */
-
-If the extension is not active (missing or not negotiated for the
-connection, or extensions are disabled on the library) the call is
-just returns -1.  Otherwise the connection's extension has its
-named option changed.
-
-The extension may decide to alter or disallow the change, in the
-example above permessage-deflate restricts the size of his rx
-output buffer also considering the protocol's rx_buf_size member.
-
-
-New application lwsws
----------------------
-
-A libwebsockets-based general webserver is built by default now, lwsws.
-
-It's configured by JSON, by default in
-
-  /etc/lwsws/conf
-
-which contains global lws context settings like this
-
-{
-  "global": {
-   "uid": "99",
-   "gid": "99",
-   "interface": "eth0",
-   "count-threads": "1"
- }
-}
-
-  /etc/lwsws/conf.d/*
-
-which contains zero or more files describing vhosts, like this
-
-{
- "vhosts": [
-  { "name": "warmcat.com",
-    "port": "443",
-    "host-ssl-key": "/etc/pki/tls/private/warmcat.com.key",
-    "host-ssl-cert": "/etc/pki/tls/certs/warmcat.com.crt",
-    "host-ssl-ca": "/etc/pki/tls/certs/warmcat.com.cer",
-    "mounts": [
-      { "/": [
-       { "home": "file:///var/www/warmcat.com" },
-       { "default": "index.html" }
-      ]
-     }
-    ]
-   }
- ]
-}
-
-
-
-v1.7.0
-======
-
-Extension Changes
------------------
-
-1) There is now a "permessage-deflate" / RFC7692 implementation.  It's very
-similar to "deflate-frame" we have offered for a long while; deflate-frame is
-now provided as an alias of permessage-deflate.
-
-The main differences are that the new permessage-deflate implementation:
-
- - properly performs streaming respecting input and output buffer limits.  The
-   old deflate-frame implementation could only work on complete deflate input
-   and produce complete inflate output for each frame.  The new implementation
-   only mallocs buffers at initialization.
-
- - goes around the event loop after each input package is processed allowing
-   interleaved output processing.  The RX flow control api can be used to
-   force compressed input processing to match the rate of compressed output
-   processing (test--echo shows an example of how to do this).
-
- - when being "deflate-frame" for compatibility he uses the same default zlib
-   settings as the old "deflate-frame", but instead of exponentially increasing
-   malloc allocations until the whole output will fit, he observes the default
-   input and output chunking buffer sizes of "permessage-deflate", that's
-   1024 in and 1024 out at a time.
-
-2) deflate-stream has been disabled for many versions (for over a year) and is
-now removed.  Browsers are now standardizing on "permessage-deflate" / RFC7692
-
-3) struct lws_extension is simplified, and lws extensions now have a public
-api (their callback) for use in user code to compose extensions and options
-the user code wants.  lws_get_internal_exts() is deprecated but kept around
-as a NOP.  The changes allow one extension implementation to go by different
-names and allows the user client code to control option offers per-ext.
-
-The test client and server are updated to use the new way.  If you use
-the old way it should still work, but extensions will be disabled until you
-update your code.
-
-Extensions are now responsible for allocating and per-instance private struct
-at instance construction time and freeing it when the instance is destroyed.
-Not needing to know the size means the extension's struct can be opaque
-to user code.
-
-
-User api additions
-------------------
-
-1) The info struct gained three new members
-
- - max_http_header_data: 0 for default (1024) or set the maximum amount of known
-    http header payload that lws can deal with.  Payload in unknown http
-    headers is dropped silently.  If for some reason you need to send huge
-    cookies or other HTTP-level headers, you can now increase this at context-
-    creation time.
-
- - max_http_header_pool: 0 for default (16) or set the maximum amount of http
-     headers that can be tracked by lws in this context.  For the server, if
-     the header pool is completely in use then accepts on the listen socket
-     are disabled until one becomes free.  For the client, if you simultaneously
-     have pending connects for more than this number of client connections,
-     additional connects will fail until some of the pending connections timeout
-     or complete.
-
- - timeout_secs: 0 for default (currently 20s), or set the library's
-     network activity timeout to the given number of seconds
-
-HTTP header processing in lws only exists until just after the first main
-callback after the HTTP handshake... for ws connections that is ESTABLISHED and
-for HTTP connections the HTTP callback.
-
-So these settings are not related to the maximum number of simultaneous
-connections, but the number of HTTP handshakes that may be expected or ongoing,
-or have just completed, at one time.  The reason it's useful is it changes the
-memory allocation for header processing to be one-time at context creation
-instead of every time there is a new connection, and gives you control over
-the peak allocation.
-
-Setting max_http_header_pool to 1 is fine it will just queue incoming
-connections before the accept as necessary, you can still have as many
-simultaneous post-header connections as you like.  Since the http header
-processing is completed and the allocation released after ESTABLISHED or the
-HTTP callback, even with a pool of 1 many connections can be handled rapidly.
-
-2) There is a new callback that allows the user code to get acccess to the
-optional close code + aux data that may have been sent by the peer.
-
-LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
-             The peer has sent an unsolicited Close WS packet.  @in and
-             @len are the optional close code (first 2 bytes, network
-             order) and the optional additional information which is not
-             defined in the standard, and may be a string or non-human-
-             readble data.
-             If you return 0 lws will echo the close and then close the
-             connection.  If you return nonzero lws will just close the
-             connection.
-
-As usual not handling it does the right thing, if you're not interested in it
-just ignore it.
-
-The test server has "open and close" testing buttons at the bottom, if you
-open and close that connection, on close it will send a close code 3000 decimal
-and the string "Bye!" as the aux data.
-
-The test server dumb-increment callback handles this callback reason and prints
-
-lwsts[15714]: LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: len 6
-lwsts[15714]:  0: 0x0B
-lwsts[15714]:  1: 0xB8
-lwsts[15714]:  2: 0x42
-lwsts[15714]:  3: 0x79
-lwsts[15714]:  4: 0x65
-lwsts[15714]:  5: 0x21
-
-3) There is a new API to allow the user code to control the content of the
-close frame sent when about to return nonzero from the user callback to
-indicate the connection should close.
-
-/**
- * lws_close_reason - Set reason and aux data to send with Close packet
- *             If you are going to return nonzero from the callback
- *             requesting the connection to close, you can optionally
- *             call this to set the reason the peer will be told if
- *             possible.
- *
- * @wsi:       The websocket connection to set the close reason on
- * @status:    A valid close status from websocket standard
- * @buf:       NULL or buffer containing up to 124 bytes of auxiliary data
- * @len:       Length of data in @buf to send
- */
-LWS_VISIBLE LWS_EXTERN void
-lws_close_reason(struct lws *wsi, enum lws_close_status status,
-                unsigned char *buf, size_t len);
-
-An extra button is added to the "open and close" test server page that requests
-that the test server close the connection from his end.
-
-The test server code will do so by
-
-                       lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY,
-                                        (unsigned char *)"seeya", 5);
-                       return -1;
-
-The browser shows the close code and reason he received
-
-websocket connection CLOSED, code: 1001, reason: seeya
-
-4) There's a new context creation time option flag
-
-LWS_SERVER_OPTION_VALIDATE_UTF8
-
-if you set it in info->options, then TEXT and CLOSE frames will get checked to
-confirm that they contain valid UTF-8.  If they don't, the connection will get
-closed by lws.
-
-5) ECDH Certs are now supported.  Enable the CMake option
-
-cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1 
-
-**and** the info->options flag
-
-LWS_SERVER_OPTION_SSL_ECDH
-
-to build in support and select it at runtime.
-
-6) There's a new api lws_parse_uri() that simplifies chopping up
-https://xxx:yyy/zzz uris into parts nicely.  The test client now uses this
-to allow proper uris as well as the old address style.
-
-7) SMP support is integrated into LWS without any internal threading.  It's
-very simple to use, libwebsockets-test-server-pthread shows how to do it,
-use -j <n> argument there to control the number of service threads up to 32.
-
-Two new members are added to the info struct
-
-       unsigned int count_threads;
-       unsigned int fd_limit_per_thread;
-       
-leave them at the default 0 to get the normal singlethreaded service loop.
-
-Set count_threads to n to tell lws you will have n simultaneous service threads
-operating on the context.
-
-There is still a single listen socket on one port, no matter how many
-service threads.
-
-When a connection is made, it is accepted by the service thread with the least
-connections active to perform load balancing.
-
-The user code is responsible for spawning n threads running the service loop
-associated to a specific tsi (Thread Service Index, 0 .. n - 1).  See
-the libwebsockets-test-server-pthread for how to do.
-
-If you leave fd_limit_per_thread at 0, then the process limit of fds is shared
-between the service threads; if you process was allowed 1024 fds overall then
-each thread is limited to 1024 / n.
-
-You can set fd_limit_per_thread to a nonzero number to control this manually, eg
-the overall supported fd limit is less than the process allowance.
-
-You can control the context basic data allocation for multithreading from Cmake
-using -DLWS_MAX_SMP=, if not given it's set to 32.  The serv_buf allocation
-for the threads (currently 4096) is made at runtime only for active threads.
-
-Because lws will limit the requested number of actual threads supported
-according to LWS_MAX_SMP, there is an api lws_get_count_threads(context) to
-discover how many threads were actually allowed when the context was created.
-
-It's required to implement locking in the user code in the same way that
-libwebsockets-test-server-pthread does it, for the FD locking callbacks.
-
-If LWS_MAX_SMP=1, then there is no code related to pthreads compiled in the
-library.  If more than 1, a small amount of pthread mutex code is built into
-the library.
-
-8) New API
-
-LWS_VISIBLE struct lws *
-lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
-
-allows foreign sockets accepted by non-lws code to be adopted by lws as if they
-had just been accepted by lws' own listen socket.
-
-9) X-Real-IP: header has been added as WSI_TOKEN_HTTP_X_REAL_IP
-
-10) Libuv support is added, there are new related user apis
-
-typedef void (lws_uv_signal_cb_t)(uv_loop_t *l, uv_signal_t *w, int revents);
-
-LWS_VISIBLE LWS_EXTERN int
-lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
-                 lws_uv_signal_cb_t *cb);
-
-LWS_VISIBLE LWS_EXTERN int
-lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi);
-
-LWS_VISIBLE void
-lws_uv_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents);
-
-and CMAKE option
-
-LWS_WITH_LIBUV
-
-
-User api changes
-----------------
-
-1) LWS_SEND_BUFFER_POST_PADDING is now 0 and deprecated.  You can remove it; if
-you still use it, obviously it does nothing.  Old binary code with nonzero
-LWS_SEND_BUFFER_POST_PADDING is perfectly compatible, the old code just
-allocated a buffer bigger than the library is going to use.
-
-The example apps no longer use LWS_SEND_BUFFER_POST_PADDING.
-
-The only path who made use of it was sending with LWS_WRITE_CLOSE --->
-
-2) Because of lws_close_reason() formalizing handling close frames,
-LWS_WRITE_CLOSE is removed from libwebsockets.h.  It was only of use to send
-close frames...close frame content should be managed using lws_close_reason()
-now.
-
-3) We check for invalid CLOSE codes and complain about protocol violation in
-our close code.  But it changes little since we were in the middle of closing
-anyway.
-
-4) zero-length RX frames and zero length TX frames are now allowed.
-
-5) Pings and close used to be limited to 124 bytes, the correct limit is 125
-so that is now also allowed.
-
-6) LWS_PRE is provided as a synonym for LWS_SEND_BUFFER_PRE_PADDING, either is
-valid to use now.
-
-7) There's generic support for RFC7462 style extension options built into the
-library now.  As a consequence, a field "options" is added to lws_extension.
-It can be NULL if there are no options on the extension.  Extension internal
-info is part of the public abi because extensions may be implemented outside
-the library.
-
-8) WSI_TOKEN_PROXY enum was accidentally defined to collide with another token
-of value 73.  That's now corrected and WSI_TOKEN_PROXY moved to his own place at
-77.
-
-9) With the addition of libuv support, libev is not the only event loop
-library in town and his api names must be elaborated with _ev_
-
-  Callback typedef: lws_signal_cb ---> lws_ev_signal_cb_t
-  lws_sigint_cfg --> lws_ev_sigint_cfg
-  lws_initloop --> lws_ev_initloop
-  lws_sigint_cb --> lws_ev_sigint_cb
-
-10) Libev support is made compatible with multithreaded service,
-lws_ev_initloop (was lws_initloop) gets an extra argument for the
-thread service index (use 0 if you will just have 1 service thread).
-
-LWS_VISIBLE LWS_EXTERN int
-lws_ev_initloop(struct lws_context *context, ev_loop_t *loop, int tsi);
-
-
 (for earlier changelogs, see the tagged releases)
diff --git a/cmake/FindLibWebSockets.cmake b/cmake/FindLibWebSockets.cmake
deleted file mode 100644 (file)
index 1dfe115..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-# This module tries to find libWebsockets library and include files
-#
-# LIBWEBSOCKETS_INCLUDE_DIR, path where to find libwebsockets.h
-# LIBWEBSOCKETS_LIBRARY_DIR, path where to find libwebsockets.so
-# LIBWEBSOCKETS_LIBRARIES, the library to link against
-# LIBWEBSOCKETS_FOUND, If false, do not try to use libWebSockets
-#
-# This currently works probably only for Linux
-
-FIND_PATH ( LIBWEBSOCKETS_INCLUDE_DIR libwebsockets.h
-    /usr/local/include
-    /usr/include
-)
-
-FIND_LIBRARY ( LIBWEBSOCKETS_LIBRARIES websockets
-    /usr/local/lib
-    /usr/lib
-)
-
-GET_FILENAME_COMPONENT( LIBWEBSOCKETS_LIBRARY_DIR ${LIBWEBSOCKETS_LIBRARIES} PATH )
-
-SET ( LIBWEBSOCKETS_FOUND "NO" )
-IF ( LIBWEBSOCKETS_INCLUDE_DIR )
-    IF ( LIBWEBSOCKETS_LIBRARIES )
-        SET ( LIBWEBSOCKETS_FOUND "YES" )
-    ENDIF ( LIBWEBSOCKETS_LIBRARIES )
-ENDIF ( LIBWEBSOCKETS_INCLUDE_DIR )
-
-MARK_AS_ADVANCED(
-    LIBWEBSOCKETS_LIBRARY_DIR
-    LIBWEBSOCKETS_INCLUDE_DIR
-    LIBWEBSOCKETS_LIBRARIES
-)
\ No newline at end of file
index 5611c04..3f32994 100644 (file)
-
-if(OPENSSL_FOUND)
-
-       find_program(OPENSSL_EXECUTABLE openssl openssl.exe bin/openssl.exe
-               HINTS ${_OPENSSL_ROOT_HINTS}
-               PATH 
-                       /usr/bin/ 
-                       bin/
-               DOC "Openssl executable")
-
-       mark_as_advanced(OPENSSL_EXECUTABLE)
-       
-       # On Windows, we need to copy the OpenSSL dlls 
-       # to the output directory.
-       if(WIN32)
-               set(OPENSSL_BIN_FOUND 0)
-
-               find_file(LIBEAY_BIN
-                       NAMES
-                       libeay32.dll
-                       HINTS
-                       ${_OPENSSL_ROOT_HINTS}
-                       PATH_SUFFIXES
-                       bin)
-               
-               find_file(SSLEAY_BIN
-                       NAMES
-                       ssleay32.dll
-                       HINTS
-                       ${_OPENSSL_ROOT_HINTS}
-                       PATH_SUFFIXES
-                       bin)
-               
-               if(LIBEAY_BIN)
-                       if(SSLEAY_BIN)
-                               set(OPENSSL_BIN_FOUND 1)
-                       endif(SSLEAY_BIN)
-               endif(LIBEAY_BIN)
-       endif(WIN32)
-               
-endif(OPENSSL_FOUND)
-
+\r
+if(OPENSSL_FOUND)\r
+\r
+       find_program(OPENSSL_EXECUTABLE openssl openssl.exe bin/openssl.exe\r
+               HINTS ${_OPENSSL_ROOT_HINTS}\r
+               PATH \r
+                       /usr/bin/ \r
+                       bin/\r
+               DOC "Openssl executable")\r
+\r
+       mark_as_advanced(OPENSSL_EXECUTABLE)\r
+       \r
+       # On Windows, we need to copy the OpenSSL dlls \r
+       # to the output directory.\r
+  # BUT only if non-static libs (referencing dlls) are used\r
+  # In this case\r
+  # ** we only want to find dlls that are compatible with the libs\r
+  #    the assumption is that these are part of the same OpenSSL package\r
+  #    and typically reside in the same or in a close by directory as the executable\r
+  # ** we do NOT want to find dlls in general dll directories such as C:\Windows\systemXX\r
+  #    because these IN GENERAL are not compatible with the libs\r
+       if (WIN32 AND OPENSSL_VERSION)\r
+               set(OPENSSL_BIN_FOUND 0)\r
+\r
+    # we check for OpenSSL versioning, as described in https://wiki.openssl.org/index.php/Versioning\r
+    string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.(.*)$" REGEX_MATCH ${OPENSSL_VERSION})\r
+\r
+    if (NOT ${REGEX_MATCH} EQUAL "")\r
+\r
+      message(DEBUG "Assuming OpenSSL release ${OPENSSL_VERSION} >= 1.1.0 for dll discovery")\r
+\r
+      # the regex matched - so we assume OpenSSL release >= 1.1\r
+      set(OVNR "${CMAKE_MATCH_1}") # OpenSSL version number\r
+      set(ORNR "${CMAKE_MATCH_2}") # OpenSSL release number\r
+      set(CRYPTO32_NAME "libcrypto-${OVNR}_${ORNR}.dll")\r
+      set(CRYPTO64_NAME "libcrypto-${OVNR}_${ORNR}-x64.dll")\r
+      message(VERBOSE "CRYPTO32_NAME=${CRYPTO32_NAME}")\r
+      message(VERBOSE "CRYPTO64_NAME=${CRYPTO64_NAME}")\r
+      set(SSL32_NAME "libssl-${OVNR}_${ORNR}.dll")\r
+      set(SSL64_NAME "libssl-${OVNR}_${ORNR}-x64.dll")\r
+      message(VERBOSE "SSL32_NAME=${SSL32_NAME}")\r
+      message(VERBOSE "SSL64_NAME=${SSL64_NAME}")\r
+\r
+      get_filename_component(OPENSSL_EXECUTABLE_PATH ${OPENSSL_EXECUTABLE} DIRECTORY)\r
+      message(VERBOSE "OPENSSL_EXECUTABLE_PATH=${OPENSSL_EXECUTABLE_PATH}")\r
+      set(OPENSSL_EXECUTABLE_BIN_PATH "")\r
+      string(REGEX MATCH "^(.*)/tools/openssl$" REGEX_MATCH ${OPENSSL_EXECUTABLE_PATH})\r
+      message(DEBUG "REGEX_MATCH=\"${REGEX_MATCH}\"")\r
+      message(DEBUG "CMAKE_MATCH_1=\"${CMAKE_MATCH_1}\"")\r
+      if (NOT ${REGEX_MATCH} EQUAL "")\r
+        set(OPENSSL_EXECUTABLE_BIN_PATH "${CMAKE_MATCH_1}/bin") # bin path of this openssl variant\r
+      endif()\r
+      message(VERBOSE "OPENSSL_EXECUTABLE_BIN_PATH=${OPENSSL_EXECUTABLE_BIN_PATH}")\r
+\r
+      unset(LIBCRYPTO_BIN)         # clear \r
+      unset(LIBCRYPTO_BIN CACHE)   # clear as well, because otherwise find_file might use it\r
+      find_file(LIBCRYPTO_BIN\r
+        NO_DEFAULT_PATH\r
+        NAMES ${CRYPTO32_NAME} ${CRYPTO64_NAME}\r
+        PATHS ${OPENSSL_EXECUTABLE_PATH} ${OPENSSL_EXECUTABLE_BIN_PATH}\r
+      )\r
+      message(VERBOSE "LIBCRYPTO_BIN=${LIBCRYPTO_BIN}")\r
+\r
+      unset(LIBSSL_BIN)         # clear \r
+      unset(LIBSSL_BIN CACHE)   # clear as well, because otherwise find_file might use it\r
+                 find_file(LIBSSL_BIN\r
+        NO_DEFAULT_PATH\r
+        NAMES ${SSL32_NAME} ${SSL64_NAME}\r
+        PATHS ${OPENSSL_EXECUTABLE_PATH} ${OPENSSL_EXECUTABLE_BIN_PATH}\r
+      )\r
+      message(VERBOSE "LIBSSL_BIN=${LIBSSL_BIN}")\r
+\r
+    else() # the version regex did not match\r
+    \r
+    # as a fallback, we check for "old" OpenSSL library (used before OpenSSL 1.1.0)\r
+\r
+               find_file(LIBCRYPTO_BIN\r
+                       NAMES\r
+                       libeay32.dll\r
+                       HINTS\r
+                       ${_OPENSSL_ROOT_HINTS}\r
+                       PATH_SUFFIXES\r
+                       bin)\r
+               \r
+               find_file(LIBSSL_BIN\r
+                       NAMES\r
+                       ssleay32.dll\r
+                       HINTS\r
+                       ${_OPENSSL_ROOT_HINTS}\r
+                       PATH_SUFFIXES\r
+                       bin)\r
+               \r
+    endif()\r
+\r
+               if(LIBCRYPTO_BIN AND LIBSSL_BIN)\r
+                       set(OPENSSL_BIN_FOUND 1)\r
+               endif()\r
+\r
+       endif(WIN32 AND OPENSSL_VERSION)\r
+               \r
+endif(OPENSSL_FOUND)\r
+\r
diff --git a/cmake/LibwebsocketsConfig.cmake.in b/cmake/LibwebsocketsConfig.cmake.in
deleted file mode 100644 (file)
index bea82b5..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# - Config file for the Libevent package
-# It defines the following variables
-#  LIBWEBSOCKETS_INCLUDE_DIRS - include directories for FooBar
-#  LIBWEBSOCKETS_LIBRARIES    - libraries to link against
-
-# Get the path of the current file.
-get_filename_component(LWS_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-
-# Set the include directories.
-set(LIBWEBSOCKETS_INCLUDE_DIRS "@LWS__INCLUDE_DIRS@")
-
-# Include the project Targets file, this contains definitions for IMPORTED targets.
-include(${LWS_CMAKE_DIR}/LibwebsocketsTargets.cmake)
-
-# IMPORTED targets from LibwebsocketsTargets.cmake
-set(LIBWEBSOCKETS_LIBRARIES websockets websockets_shared)
-
diff --git a/cmake/LwsCheckRequirements.cmake b/cmake/LwsCheckRequirements.cmake
new file mode 100644 (file)
index 0000000..9fc76e6
--- /dev/null
@@ -0,0 +1,127 @@
+# If we are being built as part of lws, confirm current build config supports
+# reqconfig, else skip building ourselves.
+#
+# If we are being built externally, confirm installed lws was configured to
+# support reqconfig, else error out with a helpful message about the problem.
+#
+
+include(CheckIncludeFile)
+
+MACRO(require_lws_config reqconfig _val result)
+
+       if (DEFINED ${reqconfig})
+       if (${reqconfig})
+               set (rq 1)
+       else()
+               set (rq 0)
+       endif()
+       else()
+               set(rq 0)
+       endif()
+
+       if (${_val} EQUAL ${rq})
+               set(SAME 1)
+       else()
+               set(SAME 0)
+       endif()
+
+       string(COMPARE EQUAL "${result}" requirements _cmp)
+
+       # we go in the first clause if in-tree
+       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
+               if (${_val})
+                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
+               else()
+                       message("${SAMP}: skipping as lws built with ${reqconfig}")
+               endif()
+               set(${result} 0)
+       else()
+               if (LWS_WITH_MINIMAL_EXAMPLES)
+                       set(MET ${SAME})
+               else()
+                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
+                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
+                               set(HAS_${reqconfig} 0)
+                       else()
+                               set(HAS_${reqconfig} 1)
+                       endif()
+                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
+                               set(MET 1)
+                       else()
+                               set(MET 0)
+                       endif()
+               endif()
+               if (NOT MET AND _cmp)
+                       if (${_val})
+                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
+                       else()
+                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
+                       endif()
+               endif()
+
+       endif()
+ENDMACRO()
+
+MACRO(require_pthreads result)
+       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
+       if (NOT LWS_HAVE_PTHREAD_H)
+               if (LWS_WITH_MINIMAL_EXAMPLES)
+                       set(${result} 0)
+                       message("${SAMP}: skipping as no pthreads")
+               else()
+                       message(FATAL_ERROR "threading support requires pthreads")
+               endif()
+       else()
+               if (WIN32)
+                       set(PTHREAD_LIB ${LWS_EXT_PTHREAD_LIBRARIES})
+               else()
+                       if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "QNX")
+                               set(PTHREAD_LIB pthread)
+                       endif()
+               endif()
+       endif()
+ENDMACRO()
+
+MACRO(sai_resource SR_NAME SR_AMOUNT SR_LEASE SR_SCOPE)
+       if (DEFINED ENV{SAI_OVN})
+
+               site_name(HOST_NAME)
+               
+               #
+               # Creates a "test" called res_${SR_SCOPE} that waits to be
+               # given a lease on ${SR_AMOUNT} of a resource ${SR_NAME}, for at
+               # most $SR_LEASE seconds, until the test dependent on it can
+               # proceed.
+               #
+               # We need to keep this sai-resource instance up for the
+               # duration of the actual test it is authorizing, when it
+               # is killed, the resource is then immediately released.
+               #
+               # The resource cookie has to be globally unique within the
+               # distributed builder sessions, so it includes the builder
+               # hostname and builder instance information
+               #
+
+               add_test(NAME st_res_${SR_SCOPE} COMMAND
+                        ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                        res_${SR_SCOPE}
+                        sai-resource ${SR_NAME} ${SR_AMOUNT} ${SR_LEASE}
+                        ${HOST_NAME}-res_${SR_SCOPE}-$ENV{SAI_PROJECT}-$ENV{SAI_OVN})
+
+               # allow it to wait for up to 100s for the resource lease
+
+               set_tests_properties(st_res_${SR_SCOPE} PROPERTIES
+                                    WORKING_DIRECTORY .
+                                    FIXTURES_SETUP res_sspcmin
+                                    TIMEOUT 100)
+
+               add_test(NAME ki_res_${SR_SCOPE} COMMAND
+                        ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                        res_${SR_SCOPE} sai-resource )
+
+               set_tests_properties(ki_res_${SR_SCOPE} PROPERTIES
+                                       FIXTURES_CLEANUP res_${SR_SCOPE})
+
+       endif()
+ENDMACRO()
+
diff --git a/cmake/libwebsockets-config.cmake.in b/cmake/libwebsockets-config.cmake.in
new file mode 100644 (file)
index 0000000..6247b2c
--- /dev/null
@@ -0,0 +1,37 @@
+# - Config file for lws
+
+# It defines the following variables
+#  LIBWEBSOCKETS_INCLUDE_DIRS - include directories for lws
+#  LIBWEBSOCKETS_LIBRARIES    - libraries to link against
+
+# Get the path of the current file.
+get_filename_component(LWS_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+list(APPEND CMAKE_MODULE_PATH ${libwebsockets_DIR})
+
+set(LIBWEBSOCKETS_INCLUDE_DIRS "@LWS__INCLUDE_DIRS@" "@LWS_PUBLIC_INCLUDES@")
+
+# Include the project Targets file, this contains definitions for IMPORTED targets.
+include(${LWS_CMAKE_DIR}/LibwebsocketsTargets.cmake)
+include(${LWS_CMAKE_DIR}/LwsCheckRequirements.cmake)
+
+# IMPORTED targets from LibwebsocketsTargets.cmake
+set(LIBWEBSOCKETS_LIBRARIES websockets websockets_shared)
+
+# These are additional include paths you will need
+foreach(item "${LIBWEBSOCKETS_INCLUDE_DIRS}")
+       include_directories(${item})
+       set(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}" ${item})
+endforeach()
+
+# These are additional libs that lws wants your app to also link to
+foreach(item "@LIB_LIST_AT_END@")
+       list(APPEND LIBWEBSOCKETS_DEP_LIBS ${item})
+endforeach()
+
+# Move boilerplate for consuming cmake files into here
+
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+set(requirements 1)
+
index dbb5701..f3f4a9d 100644 (file)
@@ -7,18 +7,28 @@
 #endif
 
 #define LWS_INSTALL_DATADIR "${CMAKE_INSTALL_PREFIX}/share"
+#define LWS_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}"
 #define LWS_LIBRARY_VERSION_MAJOR ${LWS_LIBRARY_VERSION_MAJOR}
 #define LWS_LIBRARY_VERSION_MINOR ${LWS_LIBRARY_VERSION_MINOR}
+#define LWS_LIBRARY_VERSION_PATCH_ELABORATED ${LWS_LIBRARY_VERSION_PATCH_ELABORATED}
 #define LWS_LIBRARY_VERSION_PATCH ${LWS_LIBRARY_VERSION_PATCH}
+
 /* LWS_LIBRARY_VERSION_NUMBER looks like 1005001 for e.g. version 1.5.1 */
 #define LWS_LIBRARY_VERSION_NUMBER (LWS_LIBRARY_VERSION_MAJOR * 1000000) + \
                                        (LWS_LIBRARY_VERSION_MINOR * 1000) + \
                                        LWS_LIBRARY_VERSION_PATCH
 #define LWS_MAX_SMP ${LWS_MAX_SMP}
 
+#cmakedefine LWS_ESP_PLATFORM
+#cmakedefine LWS_LIBRARY_VERSION_NUMBER
+
+#cmakedefine LWS_EXT_PTHREAD_LIBRARIES
+
 #cmakedefine LWS_AVOID_SIGPIPE_IGN
 #cmakedefine LWS_BUILD_HASH "${LWS_BUILD_HASH}"
 #cmakedefine LWS_BUILTIN_GETIFADDRS
+#cmakedefine LWS_CLIENT_HTTP_PROXYING
+#cmakedefine LWS_DETECTED_PLAT_IOS
 #cmakedefine LWS_FALLBACK_GETHOSTBYNAME
 #cmakedefine LWS_HAS_INTPTR_T
 #cmakedefine LWS_HAS_GETOPT_LONG
@@ -27,6 +37,7 @@
 #cmakedefine LWS_HAVE_BN_bn2binpad
 #cmakedefine LWS_HAVE_CLOCK_GETTIME
 #cmakedefine LWS_HAVE_EC_POINT_get_affine_coordinates
+#cmakedefine LWS_HAVE_EC_KEY_new_by_curve_name
 #cmakedefine LWS_HAVE_ECDSA_SIG_set0
 #cmakedefine LWS_HAVE_EVP_MD_CTX_free
 #cmakedefine LWS_HAVE_EVP_aes_128_wrap
 #cmakedefine LWS_HAVE_EVP_aes_192_cfb128
 #cmakedefine LWS_HAVE_EVP_aes_256_cfb8
 #cmakedefine LWS_HAVE_EVP_aes_256_cfb128
+#cmakedefine LWS_HAVE_EVP_aes_128_ofb
 #cmakedefine LWS_HAVE_EVP_aes_128_xts
+#cmakedefine LWS_HAVE_EVP_aes_128_ctr
+#cmakedefine LWS_HAVE_EVP_aes_128_ecb
+#cmakedefine LWS_HAVE_EVP_PKEY_new_raw_private_key
+#cmakedefine LWS_HAVE_EXECVPE
+#cmakedefine LWS_HAVE_LOCALTIME_R
+#cmakedefine LWS_HAVE_GMTIME_R
+#cmakedefine LWS_HAVE_CTIME_R
+#cmakedefine LWS_HAVE_GETGRGID_R
+#cmakedefine LWS_HAVE_GETGRNAM_R
+#cmakedefine LWS_HAVE_GETPWUID_R
+#cmakedefine LWS_HAVE_GETPWNAM_R
 #cmakedefine LWS_HAVE_LIBCAP
 #cmakedefine LWS_HAVE_HMAC_CTX_new
 #cmakedefine LWS_HAVE_MALLOC_H
 #cmakedefine LWS_HAVE_MALLOC_TRIM
 #cmakedefine LWS_HAVE_MALLOC_USABLE_SIZE
+#cmakedefine LWS_HAVE_mbedtls_md_setup
 #cmakedefine LWS_HAVE_mbedtls_net_init
+#cmakedefine LWS_HAVE_mbedtls_rsa_complete
+#cmakedefine LWS_HAVE_mbedtls_internal_aes_encrypt
 #cmakedefine LWS_HAVE_mbedtls_ssl_conf_alpn_protocols
 #cmakedefine LWS_HAVE_mbedtls_ssl_get_alpn_protocol
 #cmakedefine LWS_HAVE_mbedtls_ssl_conf_sni
 #cmakedefine LWS_HAVE_mbedtls_ssl_set_hs_ca_chain
 #cmakedefine LWS_HAVE_mbedtls_ssl_set_hs_own_cert
 #cmakedefine LWS_HAVE_mbedtls_ssl_set_hs_authmode
+#cmakedefine LWS_HAVE_mbedtls_ssl_set_verify
+#cmakedefine LWS_HAVE_mbedtls_x509_crt_parse_file
+#cmakedefine LWS_HAVE_MBEDTLS_NET_SOCKETS
+#cmakedefine LWS_HAVE_MBEDTLS_AUTH_KEY_ID
 #cmakedefine LWS_HAVE_NEW_UV_VERSION_H
 #cmakedefine LWS_HAVE_OPENSSL_ECDH_H
+#cmakedefine LWS_HAVE_OPENSSL_STACK
 #cmakedefine LWS_HAVE_PIPE2
 #cmakedefine LWS_HAVE_EVENTFD
 #cmakedefine LWS_HAVE_PTHREAD_H
 #cmakedefine LWS_HAVE_RSA_SET0_KEY
 #cmakedefine LWS_HAVE_RSA_verify_pss_mgf1
 #cmakedefine LWS_HAVE_SSL_CTX_get0_certificate
+#cmakedefine LWS_HAVE_SSL_CTX_load_verify_file
+#cmakedefine LWS_HAVE_SSL_CTX_load_verify_dir
 #cmakedefine LWS_HAVE_SSL_CTX_set1_param
 #cmakedefine LWS_HAVE_SSL_CTX_set_ciphersuites
 #cmakedefine LWS_HAVE_SSL_EXTRA_CHAIN_CERTS
 #cmakedefine LWS_HAVE_SSL_CTX_EVP_PKEY_new_raw_private_key
 #cmakedefine LWS_HAVE_SSL_set_alpn_protos
 #cmakedefine LWS_HAVE_SSL_SET_INFO_CALLBACK
+#cmakedefine LWS_HAVE_SSL_SESSION_set_time
+#cmakedefine LWS_HAVE_SSL_SESSION_up_ref
 #cmakedefine LWS_HAVE__STAT32I64
 #cmakedefine LWS_HAVE_STDINT_H
 #cmakedefine LWS_HAVE_SYS_CAPABILITY_H
+#cmakedefine LWS_HAVE_TIMEGM
 #cmakedefine LWS_HAVE_TLS_CLIENT_METHOD
 #cmakedefine LWS_HAVE_TLSV1_2_CLIENT_METHOD
+#cmakedefine LWS_HAVE_SUSECONDS_T
 #cmakedefine LWS_HAVE_UV_VERSION_H
+#cmakedefine LWS_HAVE_VFORK
 #cmakedefine LWS_HAVE_X509_get_key_usage
 #cmakedefine LWS_HAVE_X509_VERIFY_PARAM_set1_host
-#cmakedefine LWS_LATENCY
 #cmakedefine LWS_LIBRARY_VERSION "${LWS_LIBRARY_VERSION}"
+#define LWS_LOGGING_BITFIELD_CLEAR ${LWS_LOGGING_BITFIELD_CLEAR}
+#define LWS_LOGGING_BITFIELD_SET ${LWS_LOGGING_BITFIELD_SET}
+#cmakedefine LWS_LOG_TAG_LIFECYCLE
 #cmakedefine LWS_MINGW_SUPPORT
 #cmakedefine LWS_NO_CLIENT
 #cmakedefine LWS_NO_DAEMONIZE
-#cmakedefine LWS_NO_SERVER
 #cmakedefine LWS_OPENSSL_CLIENT_CERTS "${LWS_OPENSSL_CLIENT_CERTS}"
 #cmakedefine LWS_OPENSSL_SUPPORT
 #cmakedefine LWS_PLAT_OPTEE
 #cmakedefine LWS_PLAT_UNIX
+#cmakedefine LWS_PLAT_FREERTOS
 #cmakedefine LWS_ROLE_CGI
 #cmakedefine LWS_ROLE_DBUS
 #cmakedefine LWS_ROLE_H1
 #cmakedefine LWS_ROLE_H2
 #cmakedefine LWS_ROLE_RAW
+#cmakedefine LWS_ROLE_RAW_FILE
 #cmakedefine LWS_ROLE_RAW_PROXY
 #cmakedefine LWS_ROLE_WS
+#cmakedefine LWS_ROLE_MQTT
 #cmakedefine LWS_SHA1_USE_OPENSSL_NAME
 #cmakedefine LWS_SSL_CLIENT_USE_OS_CA_CERTS
 #cmakedefine LWS_SSL_SERVER_WITH_ECDH_CERT
+#cmakedefine LWS_SUPPRESS_DEPRECATED_API_WARNINGS
+#cmakedefine LWS_TLS_LOG_PLAINTEXT_RX
+#cmakedefine LWS_TLS_LOG_PLAINTEXT_TX
 #cmakedefine LWS_WITH_ABSTRACT
 #cmakedefine LWS_WITH_ACCESS_LOG
 #cmakedefine LWS_WITH_ACME
+#cmakedefine LWS_WITH_ALSA
+#cmakedefine LWS_WITH_SYS_ASYNC_DNS
 #cmakedefine LWS_WITH_BORINGSSL
 #cmakedefine LWS_WITH_CGI
+#cmakedefine LWS_WITH_CONMON
+#cmakedefine LWS_WITH_COSE
 #cmakedefine LWS_WITH_CUSTOM_HEADERS
 #cmakedefine LWS_WITH_DEPRECATED_LWS_DLL
+#cmakedefine LWS_WITH_DETAILED_LATENCY
 #cmakedefine LWS_WITH_DIR
+#cmakedefine LWS_WITH_DRIVERS
 #cmakedefine LWS_WITH_ESP32
 #cmakedefine LWS_HAVE_EVBACKEND_LINUXAIO
+#cmakedefine LWS_HAVE_EVBACKEND_IOURING
 #cmakedefine LWS_WITH_EXTERNAL_POLL
+#cmakedefine LWS_WITH_FILE_OPS
+#cmakedefine LWS_WITH_FSMOUNT
 #cmakedefine LWS_WITH_FTS
 #cmakedefine LWS_WITH_GENCRYPTO
 #cmakedefine LWS_WITH_GENERIC_SESSIONS
+#cmakedefine LWS_WITH_GLIB
+#cmakedefine LWS_WITH_GTK
 #cmakedefine LWS_WITH_HTTP2
+#cmakedefine LWS_WITH_HTTP_BASIC_AUTH
 #cmakedefine LWS_WITH_HTTP_BROTLI
+#cmakedefine LWS_HTTP_HEADERS_ALL
 #cmakedefine LWS_WITH_HTTP_PROXY
 #cmakedefine LWS_WITH_HTTP_STREAM_COMPRESSION
+#cmakedefine LWS_WITH_HTTP_UNCOMMON_HEADERS
 #cmakedefine LWS_WITH_IPV6
 #cmakedefine LWS_WITH_JOSE
+#cmakedefine LWS_WITH_CBOR
+#cmakedefine LWS_WITH_CBOR_FLOAT
 #cmakedefine LWS_WITH_LEJP
 #cmakedefine LWS_WITH_LIBEV
 #cmakedefine LWS_WITH_LIBEVENT
 #cmakedefine LWS_WITH_LIBUV
+#cmakedefine LWS_WITH_SDEVENT
 #cmakedefine LWS_WITH_LWSAC
+#cmakedefine LWS_LOGS_TIMESTAMP
 #cmakedefine LWS_WITH_MBEDTLS
 #cmakedefine LWS_WITH_MINIZ
+#cmakedefine LWS_WITH_NETLINK
 #cmakedefine LWS_WITH_NETWORK
 #cmakedefine LWS_WITH_NO_LOGS
-#cmakedefine LWS_WITHOUT_CLIENT
+#cmakedefine LWS_WITH_CACHE_NSCOOKIEJAR
+#cmakedefine LWS_WITH_CLIENT
 #cmakedefine LWS_WITHOUT_EXTENSIONS
-#cmakedefine LWS_WITHOUT_SERVER
+#cmakedefine LWS_WITH_SERVER
+#cmakedefine LWS_WITH_SPAWN
 #cmakedefine LWS_WITH_PEER_LIMITS
 #cmakedefine LWS_WITH_PLUGINS
+#cmakedefine LWS_WITH_PLUGINS_BUILTIN
 #cmakedefine LWS_WITH_POLARSSL
 #cmakedefine LWS_WITH_POLL
 #cmakedefine LWS_WITH_RANGES
+#cmakedefine LWS_WITH_RFC6724
+#cmakedefine LWS_WITH_SECURE_STREAMS
+#cmakedefine LWS_WITH_SECURE_STREAMS_CPP
+#cmakedefine LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM
+#cmakedefine LWS_WITH_SECURE_STREAMS_PROXY_API
+#cmakedefine LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY
+#cmakedefine LWS_WITH_SECURE_STREAMS_AUTH_SIGV4
+#cmakedefine LWS_WITH_SECURE_STREAMS_BUFFER_DUMP
+#cmakedefine LWS_WITH_SS_DIRECT_PROTOCOL_STR
 #cmakedefine LWS_WITH_SELFTESTS
 #cmakedefine LWS_WITH_SEQUENCER
 #cmakedefine LWS_WITH_SERVER_STATUS
+#cmakedefine LWS_WITH_SYS_SMD
 #cmakedefine LWS_WITH_SMTP
 #cmakedefine LWS_WITH_SOCKS5
 #cmakedefine LWS_WITH_STATEFUL_URLDECODE
 #cmakedefine LWS_WITH_STATS
 #cmakedefine LWS_WITH_STRUCT_SQLITE3
+#cmakedefine LWS_WITH_STRUCT_JSON
+#cmakedefine LWS_WITH_SUL_DEBUGGING
 #cmakedefine LWS_WITH_SQLITE3
+#cmakedefine LWS_WITH_SYS_DHCP_CLIENT
+#cmakedefine LWS_WITH_SYS_FAULT_INJECTION
+#cmakedefine LWS_WITH_SYS_METRICS
+#cmakedefine LWS_WITH_SYS_NTPCLIENT
+#cmakedefine LWS_WITH_SYS_STATE
 #cmakedefine LWS_WITH_THREADPOOL
 #cmakedefine LWS_WITH_TLS
+#cmakedefine LWS_WITH_TLS_JIT_TRUST
+#cmakedefine LWS_WITH_TLS_SESSIONS
+#cmakedefine LWS_WITH_UDP
+#cmakedefine LWS_WITH_ULOOP
 #cmakedefine LWS_WITH_UNIX_SOCK
 #cmakedefine LWS_WITH_ZIP_FOPS
 #cmakedefine USE_OLD_CYASSL
 #cmakedefine USE_WOLFSSL
+#cmakedefine LWS_WITH_EVENT_LIBS
+#cmakedefine LWS_WITH_EVLIB_PLUGINS
+#cmakedefine LWS_WITH_LIBUV_INTERNAL
+#cmakedefine LWS_WITH_PLUGINS_API
+#cmakedefine LWS_HAVE_RTA_PREF
 
-${LWS_SIZEOFPTR_CODE}
index 55bd4fb..7f61e4f 100644 (file)
@@ -5,21 +5,16 @@
                #define _DEBUG
        #endif
 #endif
+#cmakedefine LWIP_PROVIDE_ERRNO
 
 /* Define to 1 to use CyaSSL as a replacement for OpenSSL. 
  * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */
 #cmakedefine USE_CYASSL
 
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#cmakedefine LWS_HAVE_DLFCN_H
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#cmakedefine LWS_HAVE_FCNTL_H
-
 /* Define to 1 if you have the `fork' function. */
 #cmakedefine LWS_HAVE_FORK
 
-/* Define to 1 if you have the `getenv function. */
+/* Define to 1 if you have the `getenv' function. */
 #cmakedefine LWS_HAVE_GETENV
 
 /* Define to 1 if you have the <in6addr.h> header file. */
 /* Define to 1 if you have the <memory.h> header file. */
 #cmakedefine LWS_HAVE_MEMORY_H
 
-/* Define to 1 if you have the `memset' function. */
-#cmakedefine LWS_HAVE_MEMSET
-
 /* Define to 1 if you have the <netinet/in.h> header file. */
 #cmakedefine LWS_HAVE_NETINET_IN_H
 
-/* Define to 1 if your system has a GNU libc compatible `realloc' function,
-   and to 0 otherwise. */
-#cmakedefine LWS_HAVE_REALLOC
-
-/* Define to 1 if you have the `socket' function. */
-#cmakedefine LWS_HAVE_SOCKET
-
 /* Define to 1 if you have the <stdint.h> header file. */
 #cmakedefine LWS_HAVE_STDINT_H
 
@@ -63,6 +48,9 @@
 /* Define to 1 if you have the <sys/prctl.h> header file. */
 #cmakedefine LWS_HAVE_SYS_PRCTL_H
 
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#cmakedefine LWS_HAVE_SYS_RESOURCE_H
+
 /* Define to 1 if you have the <sys/socket.h> header file. */
 #cmakedefine LWS_HAVE_SYS_SOCKET_H
 
diff --git a/contrib/android-make-script.sh b/contrib/android-make-script.sh
deleted file mode 100755 (executable)
index 1ef8607..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/bin/bash
-
-#
-# Build libwebsockets static library for Android
-#
-
-# path to NDK
-export NDK=/opt/ndk_r17/android-ndk-r17-beta2-linux-x86_64/android-ndk-r17-beta2
-export ANDROID_NDK=${NDK}
-export TOOLCHAIN=${NDK}/toolchain
-export CORSS_SYSROOT=${NDK}/sysroot
-export SYSROOT=${NDK}/platforms/android-22/arch-arm
-set -e
-
-# Download packages libz, libuv, mbedtls and libwebsockets
-#zlib-1.2.8
-#libuv-1.x
-#mbedtls-2.11.0
-#libwebsockets-3.0.0
-
-
-# create a local android toolchain
-API=${3:-24}
-
-$NDK/build/tools/make-standalone-toolchain.sh \
- --toolchain=arm-linux-androideabi-4.9 \
- --arch=arm \
- --install-dir=`pwd`/android-toolchain-arm \
- --platform=android-$API \
- --stl=libc++ \
- --force \
- --verbose
-
-# setup environment to use the gcc/ld from the android toolchain
-export INSTALL_PATH=/opt/libwebsockets_android/android-toolchain-arm
-export TOOLCHAIN_PATH=`pwd`/android-toolchain-arm
-export TOOL=arm-linux-androideabi
-export NDK_TOOLCHAIN_BASENAME=${TOOLCHAIN_PATH}/bin/${TOOL}
-export PATH=`pwd`/android-toolchain-arm/bin:$PATH
-export CC=$NDK_TOOLCHAIN_BASENAME-gcc
-export CXX=$NDK_TOOLCHAIN_BASENAME-g++
-export LINK=${CXX}
-export LD=$NDK_TOOLCHAIN_BASENAME-ld
-export AR=$NDK_TOOLCHAIN_BASENAME-ar
-export RANLIB=$NDK_TOOLCHAIN_BASENAME-ranlib
-export STRIP=$NDK_TOOLCHAIN_BASENAME-strip
-export PLATFORM=android
-export CFLAGS="D__ANDROID_API__=$API"
-
-# configure and build libuv
-[ ! -f ./android-toolchain-arm/lib/libuv.so ] && {
-cd libuv
-echo "=============================================>> build libuv"
-
-PATH=$TOOLCHAIN_PATH:$PATH make clean
-PATH=$TOOLCHAIN_PATH:$PATH make
-PATH=$TOOLCHAIN_PATH:$PATH make install
-echo "<<============================================= build libuv"
-cd ..
-}
-
-# configure and build zlib
-[ ! -f ./android-toolchain-arm/lib/libz.so ] && {
-cd zlib-1.2.8
-echo "=============================================>> build libz"
-
-PATH=$TOOLCHAIN_PATH:$PATH make clean 
-PATH=$TOOLCHAIN_PATH:$PATH make
-PATH=$TOOLCHAIN_PATH:$PATH make install
-echo "<<============================================= build libz"
-cd ..
-}
-
-# configure and build mbedtls
-[ ! -f ./android-toolchain-arm/lib/libmbedtls.so ] && {
-echo "=============================================>> build mbedtls"
-PREFIX=$TOOLCHAIN_PATH
-cd mbedtls-2.11.0
-[ ! -d build ] && mkdir build
-cd build
-export CFLAGS="$CFLAGS -fomit-frame-pointer"
-
-PATH=$TOOLCHAIN_PATH:$PATH cmake .. -DCMAKE_TOOLCHAIN_FILE=`pwd`/../cross-arm-android-gnueabi.cmake \
-  -DCMAKE_INSTALL_PREFIX:PATH=${INSTALL_PATH} \
-  -DCMAKE_BUILD_TYPE=RELEASE -DUSE_SHARED_MBEDTLS_LIBRARY=On
-  
-PATH=$TOOLCHAIN_PATH:$PATH make clean
-PATH=$TOOLCHAIN_PATH:$PATH make SHARED=1
-PATH=$TOOLCHAIN_PATH:$PATH make install
-echo "<<============================================= build mbedtls"
-cd ../..
-}
-
-# configure and build libwebsockets
-[ ! -f ./android-toolchain-arm/lib/libwebsockets.so ] && {
-cd libwebsockets
-[ ! -d build ] && mkdir build
-cd build
-echo "=============================================>> build libwebsockets"
-
-PATH=$TOOLCHAIN_PATH:$PATH cmake .. -DCMAKE_TOOLCHAIN_FILE=`pwd`/../cross-arm-android-gnueabi.cmake \
-  -DCMAKE_INSTALL_PREFIX:PATH=${INSTALL_PATH} \
-  -DLWS_WITH_LWSWS=1 \
-  -DLWS_WITH_MBEDTLS=1 \
-  -DLWS_WITHOUT_TESTAPPS=1 \
-  -DLWS_MBEDTLS_LIBRARIES="${INSTALL_PATH}/lib/libmbedcrypto.a;${INSTALL_PATH}/lib/libmbedtls.a;${INSTALL_PATH}/lib/libmbedx509.a" \
-  -DLWS_MBEDTLS_INCLUDE_DIRS=${INSTALL_PATH}/include \
-  -DLWS_LIBUV_LIBRARIES=${INSTALL_PATH}/lib/libuv.so \
-  -DLWS_LIBUV_INCLUDE_DIRS=${INSTALL_PATH}/include \
-  -DLWS_ZLIB_LIBRARIES=${INSTALL_PATH}/lib/libz.so \
-  -DLWS_ZLIB_INCLUDE_DIRS=${INSTALL_PATH}/include 
-PATH=$TOOLCHAIN_PATH:$PATH make
-PATH=$TOOLCHAIN_PATH:$PATH make install
-echo "<<============================================= build libwebsockets"
-cd ../..
-}
diff --git a/contrib/cross-aarch64-android.cmake b/contrib/cross-aarch64-android.cmake
new file mode 100644 (file)
index 0000000..a0b3f4e
--- /dev/null
@@ -0,0 +1,58 @@
+#
+# CMake Toolchain file for crosscompiling Android / aarch64
+#
+# This can be used when running cmake in the following way:
+#  cd build/
+#  cmake .. -DCMAKE_TOOLCHAIN_FILE=contrib/cross-aarch64-android.cmake
+#
+
+
+set(ANDROID_API_VER 24)
+set(ABARCH1 arm64)
+set(CMAKE_SYSTEM_PROCESSOR aarch64)
+set(NDK /opt/android/ndk/21.1.6352462/)
+set(CROSS_SYSROOT "${NDK}/platforms/android-${ANDROID_API_VER}/arch-${ABARCH1}")
+set(BUILD_ARCH linux-x86_64)
+
+#
+# Rest should be computed from the above
+#
+set(TC_PATH ${NDK}/toolchains/llvm/prebuilt/${BUILD_ARCH})
+set(TC_BASE ${TC_PATH}/bin/${CMAKE_SYSTEM_PROCESSOR}-linux-android)
+set(PLATFORM android)
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_C_COMPILER "${TC_BASE}${ANDROID_API_VER}-clang")
+set(CMAKE_CXX_COMPILER "${TC_BASE}${ANDROID_API_VER}-clang++")
+set(CMAKE_STAGING_PREFIX "${CROSS_SYSROOT}")
+
+#
+# Different build system distros set release optimization level to different
+# things according to their local policy, eg, Fedora is -O2 and Ubuntu is -O3
+# here.  Actually the build system's local policy is completely unrelated to
+# our desire for cross-build release optimization policy for code built to run
+# on a completely different target than the build system itself.
+#
+# Since this goes last on the compiler commandline we have to override it to a
+# sane value for cross-build here.  Notice some gcc versions enable broken
+# optimizations with -O3.
+#
+if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
+endif()
+
+#-nostdlib
+SET(CMAKE_C_FLAGS "-DGCC_VER=\"\\\"$(GCC_VER)\\\"\" -DARM64=1 -D__LP64__=1 -Os -g3 -fpie -mstrict-align -fPIC -ffunction-sections -fdata-sections -D__ANDROID_API__=${ANDROID_API_VER} -Wno-pointer-sign" CACHE STRING "" FORCE)
+
+
+set(CMAKE_FIND_ROOT_PATH "${CROSS_SYSROOT}")
+
+# Adjust the default behavior of the FIND_XXX() commands:
+# search programs in the host environment only.
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+
+# Search headers and libraries in the target environment only.
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+
diff --git a/contrib/cross-aarch64-qnx.cmake b/contrib/cross-aarch64-qnx.cmake
new file mode 100644 (file)
index 0000000..404d1d9
--- /dev/null
@@ -0,0 +1,50 @@
+#
+# CMake Toolchain file for crosscompiling aarch64 for QNX.
+#
+# This can be used when running cmake in the following way:
+#  cd build/
+#  cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-aarch64-qnx.cmake
+#
+
+# adapt to your toolchain path
+set(CROSS_PATH /var/toolchain/qnx5.4/host/linux/x86_64/usr)
+
+# Target operating system name.
+set(CMAKE_SYSTEM_NAME QNX)
+set(BUILD_SHARED_LIBS OFF)
+set(CMAKE_SYSTEM_PROCESSOR aarch64)
+
+# Name of C compiler.
+set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/ntoaarch64-gcc")
+set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/ntoaarch64-g++")
+
+set(CMAKE_C_FLAGS "-Wno-error")
+set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
+
+#
+# Different build system distros set release optimization level to different
+# things according to their local policy, eg, Fedora is -O2 and Ubuntu is -O3
+# here.  Actually the build system's local policy is completely unrelated to
+# our desire for cross-build release optimization policy for code built to run
+# on a completely different target than the build system itself.
+#
+# Since this goes last on the compiler commandline we have to override it to a
+# sane value for cross-build here.  Notice some gcc versions enable broken
+# optimizations with -O3.
+#
+if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
+endif()
+
+# Where to look for the target environment. (More paths can be added here)
+set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
+
+# Adjust the default behavior of the FIND_XXX() commands:
+# search programs in the host environment only.
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+
+# Search headers and libraries in the target environment only.
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
index c8d880d..894ffed 100644 (file)
@@ -26,8 +26,8 @@ set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++")
 # optimizations with -O3.
 #
 if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
-       set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -O2)
-       set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} -O2)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
 endif()
 
 #-nostdlib
index da9aaae..11515d8 100644 (file)
@@ -30,8 +30,8 @@ set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/arm-linux-androideabi-g++")
 # optimizations with -O3.
 #
 if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
-       set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -O2)
-       set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} -O2)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
 endif()
 
 # Where to look for the target environment. (More paths can be added here)
index 289f27a..df8c1c3 100644 (file)
@@ -27,8 +27,8 @@ set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-g++")
 # optimizations with -O3.
 #
 if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
-       set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -O2)
-       set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} -O2)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
 endif()
 
 # Where to look for the target environment. (More paths can be added here)
diff --git a/contrib/cross-atmel.cmake b/contrib/cross-atmel.cmake
new file mode 100644 (file)
index 0000000..b4a44aa
--- /dev/null
@@ -0,0 +1,119 @@
+#
+# CMake Toolchain file for crosscompiling on Atmel Arm products
+#
+# To build without tls
+#
+#  cd build/
+#  cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/opt/atmel/cross-root \
+#           -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-atmel.cmake \
+#           -DLWS_PLAT_FREERTOS=1 \
+#           -DLWS_WITH_ZLIB=0 \
+#           -DLWS_WITHOUT_EXTENSIONS=1 \
+#           -DLWS_WITH_ZIP_FOPS=0 \
+#           -DLWS_WITH_HTTP_STREAM_COMPRESSION=0 \
+#           -DLWS_WITH_MBEDTLS=0 \
+#           -DLWS_WITH_SSL=0 \
+#           -DLWS_WITH_FILE_OPS=0
+#
+
+# I had to edit /opt/xdk-asf-3.48.0/thirdparty/lwip/lwip-port-1.4.1-dev/sam/include/arch/cc.h
+# to comment out #define LWIP_PROVIDE_ERRNO
+
+# if your sdk lives somewhere else, this is the only place that should need changing
+
+set(CROSS_BASE /opt/arm-none-eabi)
+set(SDK_BASE /opt/xdk-asf-3.48.0)
+set(CROSS_PATH ${CROSS_BASE}/bin/arm-none-eabi)
+
+set(LWIP_VER 1.4.1-dev)
+set(FREERTOS_VER 10.0.0)
+
+#
+# Target operating system name.
+set(CMAKE_SYSTEM_NAME Generic)
+
+# Name of C compiler.
+set(CMAKE_C_COMPILER "${CROSS_PATH}-gcc")
+
+#
+# cmake believes we should link a NOP test program OK, but since we're
+# baremetal, that's not true in our case.  It tries to build this test
+# with the cross compiler, but with no args on it, and it fails.
+# So disable this test for this toolchain (we'll find out soon enough
+# if we actually can't compile anything)
+
+set(CMAKE_C_COMPILER_WORKS 1)
+set(CMAKE_CXX_COMPILER_WORKS 1)
+
+#
+# similarly we're building a .a like this, we can't actually build
+# complete test programs to probe api availability... so force some
+# key ones
+
+set(LWS_HAVE_mbedtls_ssl_conf_alpn_protocols 1)
+set(LWS_HAVE_mbedtls_ssl_conf_alpn_protocols 1)
+set(LWS_HAVE_mbedtls_ssl_get_alpn_protocol 1)
+set(LWS_HAVE_mbedtls_ssl_conf_sni 1)
+set(LWS_HAVE_mbedtls_ssl_set_hs_ca_chain 1)
+set(LWS_HAVE_mbedtls_ssl_set_hs_own_cert 1)
+set(LWS_HAVE_mbedtls_ssl_set_hs_authmode 1)
+set(LWS_HAVE_mbedtls_net_init 1)
+set(LWS_HAVE_mbedtls_md_setup 1) # not on xenial 2.2
+set(LWS_HAVE_mbedtls_rsa_complete 1) # not on xenial 2.2
+set(LWS_HAVE_mbedtls_internal_aes_encrypt 1)
+#
+# Different build system distros set release optimization level to different
+# things according to their local policy, eg, Fedora is -O2 and Ubuntu is -O3
+# here.  Actually the build system's local policy is completely unrelated to
+# our desire for cross-build release optimization policy for code built to run
+# on a completely different target than the build system itself.
+#
+# Since this goes last on the compiler commandline we have to override it to a
+# sane value for cross-build here.  Notice some gcc versions enable broken
+# optimizations with -O3.
+#
+if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
+endif()
+
+set(PLAT_ARCH        ARM_CM4F)
+set(PLAT_ARCH_CMSIS  sam4e)
+set(PLAT_SOC         __SAM4E16E__)
+set(PLAT_BOARD       SAM4E_XPLAINED_PRO)
+
+set(CF_LWIP "${CF_LWIP} -I${SDK_BASE}/thirdparty/lwip/lwip-${LWIP_VER}/src/include/lwip")
+set(CF_LWIP "${CF_LWIP} -I${SDK_BASE}/thirdparty/lwip/lwip-${LWIP_VER}/src/include/posix")
+set(CF_LWIP "${CF_LWIP} -I${SDK_BASE}/thirdparty/lwip/lwip-${LWIP_VER}/src/include")
+set(CF_LWIP "${CF_LWIP} -I${SDK_BASE}/thirdparty/lwip/lwip-${LWIP_VER}/src/module_config")
+set(CF_LWIP "${CF_LWIP} -I${SDK_BASE}/thirdparty/lwip/lwip-port-${LWIP_VER}/sam/include")
+set(CF_LWIP "${CF_LWIP} -I${SDK_BASE}/thirdparty/lwip/lwip-${LWIP_VER}/src/include/ipv4")
+
+set(CF_FREERTOS "${CF_FREERTOS} -I${SDK_BASE}/thirdparty/freertos/freertos-${FREERTOS_VER}/Source/include")
+set(CF_FREERTOS "${CF_FREERTOS} -I${SDK_BASE}/thirdparty/freertos/freertos-${FREERTOS_VER}/module_config")
+set(CF_FREERTOS "${CF_FREERTOS} -I${SDK_BASE}/thirdparty/freertos/freertos-${FREERTOS_VER}/Source/portable/GCC/${PLAT_ARCH}")
+
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/common/boards")
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/common/utils")
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/sam/utils/")
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/sam/utils/preprocessor")
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/sam/utils/header_files")
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/sam/boards")
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/sam/utils/cmsis/${PLAT_ARCH_CMSIS}/source/templates")
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/sam/utils/cmsis/${PLAT_ARCH_CMSIS}/include")
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/thirdparty/CMSIS/Include")
+set(CF_SDK_GLUE "${CF_SDK_GLUE} -I${SDK_BASE}/common/utils/osprintf")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lnosys -nostartfiles ${CF_LWIP} ${CF_FREERTOS} ${CF_SDK_GLUE} -DBOARD=${PLAT_BOARD} -D${PLAT_SOC} -DLWIP_TIMEVAL_PRIVATE=0 -DLWS_AMAZON_RTOS=1 -DLWIP_SOCKET_OFFSET=0 -DLWIP_COMPAT_SOCKETS -DLWIP_DNS=1 -DLWIP_SOCKETS=1 "  CACHE STRING "" FORCE)
+
+# Where to look for the target environment. (More paths can be added here)
+set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
+
+# Adjust the default behavior of the FIND_XXX() commands:
+# search programs in the host environment only.
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+
+# Search headers and libraries in the target environment only.
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
index 2c8996b..083654f 100644 (file)
@@ -9,11 +9,13 @@
 # Target operating system name.
 set(CMAKE_SYSTEM_NAME Linux)
 
-# Name of C compiler.
-set(CMAKE_C_COMPILER   "${CROSS_PATH}/bin/xtensa-esp32-elf-gcc${EXECUTABLE_EXT}")
-set(CMAKE_AR           "${CROSS_PATH}/bin/xtensa-esp32-elf-ar${EXECUTABLE_EXT}")
-set(CMAKE_RANLIB       "${CROSS_PATH}/bin/xtensa-esp32-elf-ranlib${EXECUTABLE_EXT}")
-set(CMAKE_LINKER       "${CROSS_PATH}/bin/xtensa-esp32-elf-ld${EXECUTABLE_EXT}")
+# assumed these are set up on the $PATH
+set(TC xtensa-esp32-elf)
+
+set(CMAKE_C_COMPILER   "${TC}-gcc${EXECUTABLE_EXT}")
+set(CMAKE_AR           "${TC}-ar${EXECUTABLE_EXT}")
+set(CMAKE_RANLIB       "${TC}-ranlib${EXECUTABLE_EXT}")
+set(CMAKE_LINKER       "${TC}-ld${EXECUTABLE_EXT}")
 
 #
 # Different build system distros set release optimization level to different
@@ -27,8 +29,8 @@ set(CMAKE_LINKER      "${CROSS_PATH}/bin/xtensa-esp32-elf-ld${EXECUTABLE_EXT}")
 # optimizations with -O3.
 #
 if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
-       set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -O2)
-       set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} -O2)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
 endif()
 
 SET(CMAKE_C_FLAGS "-nostdlib -Wall -Werror \
diff --git a/contrib/cross-linkit.cmake b/contrib/cross-linkit.cmake
new file mode 100644 (file)
index 0000000..5d417ac
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# CMake Toolchain file for crosscompiling on Mediatek Linkit 7967
+#
+# This can be used like this (with Linkit sdk unpacked to /opt/linkit)
+#
+#  cd build/
+#  cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/opt/linkit/cross-root \
+#           -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-linkit.cmake \
+#           -DLWS_PLAT_FREERTOS=1 \
+#           -DLWS_WITH_ZLIB=0 \
+#           -DLWS_WITHOUT_EXTENSIONS=1 \
+#           -DLWS_WITH_ZIP_FOPS=0 \
+#           -DLWS_WITH_HTTP_STREAM_COMPRESSION=0 \
+#           -DLWS_WITH_MBEDTLS=1 \
+#           -DLWS_WITH_FILE_OPS=0
+#
+
+# if your sdk lives somewhere else, this is the only place that should need changing
+set(CROSS_BASE /opt/linkit/sdk)
+set(CROSS_PATH ${CROSS_BASE}/tools/gcc/gcc-arm-none-eabi)
+
+#
+# Target operating system name.
+set(CMAKE_SYSTEM_NAME Generic)
+
+# Name of C compiler.
+set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/arm-none-eabi-gcc")
+set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/arm-none-eabi-g++")
+
+#
+# cmake believes we should link a NOP test program OK, but since we're
+# baremetal, that's not true in our case.  It tries to build this test
+# with the cross compiler, but with no args on it, and it fails.
+# So disable this test for this toolchain (we'll find out soon enough
+# if we actually can't compile anything)
+
+set(CMAKE_C_COMPILER_WORKS 1)
+set(CMAKE_CXX_COMPILER_WORKS 1)
+
+#
+# similarly we're building a .a like this, we can't actually build
+# complete test programs to probe api availability... so force some
+# key ones
+
+set(LWS_HAVE_mbedtls_ssl_conf_alpn_protocols 1)
+set(LWS_HAVE_mbedtls_ssl_conf_alpn_protocols 1)
+set(LWS_HAVE_mbedtls_ssl_get_alpn_protocol 1)
+set(LWS_HAVE_mbedtls_ssl_conf_sni 1)
+set(LWS_HAVE_mbedtls_ssl_set_hs_ca_chain 1)
+set(LWS_HAVE_mbedtls_ssl_set_hs_own_cert 1)
+set(LWS_HAVE_mbedtls_ssl_set_hs_authmode 1)
+set(LWS_HAVE_mbedtls_net_init 1)
+set(LWS_HAVE_mbedtls_md_setup 1) # not on xenial 2.2
+set(LWS_HAVE_mbedtls_rsa_complete 1) # not on xenial 2.2
+set(LWS_HAVE_mbedtls_internal_aes_encrypt 1)
+#
+# Different build system distros set release optimization level to different
+# things according to their local policy, eg, Fedora is -O2 and Ubuntu is -O3
+# here.  Actually the build system's local policy is completely unrelated to
+# our desire for cross-build release optimization policy for code built to run
+# on a completely different target than the build system itself.
+#
+# Since this goes last on the compiler commandline we have to override it to a
+# sane value for cross-build here.  Notice some gcc versions enable broken
+# optimizations with -O3.
+#
+if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
+endif()
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lnosys -nostartfiles -I${CROSS_BASE}/middleware/third_party/lwip/src/include/lwip -I${CROSS_BASE}/middleware/third_party/lwip/src/include -I${CROSS_BASE}/project/mt7687_hdk/apps/httpd/inc/ -I${CROSS_BASE}/kernel/service/inc/ -I${CROSS_BASE}/driver/chip/inc -I${CROSS_BASE}/driver/chip/mt7687/inc/ -I${CROSS_BASE}/driver/CMSIS/Device/MTK/mt7687/Include/ -I${CROSS_BASE}/driver/CMSIS/Include -I${CROSS_BASE}/middleware/third_party/lwip/ports/include/ -I${CROSS_BASE}/middleware/third_party/lwip/src/include/posix/ -I${CROSS_BASE}/kernel/rtos/FreeRTOS/Source/include/ -I${CROSS_BASE}/middleware/third_party/mbedtls/include/ -I${CROSS_BASE}/kernel/rtos/FreeRTOS/Source/portable/GCC/ARM_CM4F/ -I${CROSS_BASE}/middleware/third_party/sntp/inc/ -DLWS_AMAZON_RTOS=1"  CACHE STRING "" FORCE)
+
+# Where to look for the target environment. (More paths can be added here)
+set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
+
+# Adjust the default behavior of the FIND_XXX() commands:
+# search programs in the host environment only.
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+
+# Search headers and libraries in the target environment only.
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
index 1b21014..a2cca48 100644 (file)
@@ -30,8 +30,8 @@ set(CMAKE_C_FLAGS "-Wno-error")
 # optimizations with -O3.
 #
 if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
-       set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -O2)
-       set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} -O2)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
 endif()
 
 # Where to look for the target environment. (More paths can be added here)
index 0512885..cfe563c 100644 (file)
@@ -6,7 +6,11 @@
 #  cmake .. -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-w32.cmake -DLWS_WITH_SSL=0
 #
 
-set(CROSS_PATH /opt/mingw32)
+# the outermost path to your cross toolchain
+#set(CROSS_PATH /opt/mingw32)
+set(CROSS_PATH /usr)
+# your cross root
+set(CROSS_ROOT ${CROSS_PATH}/i686-w64-mingw32/sys-root/)
 
 # Target operating system name.
 set(CMAKE_SYSTEM_NAME Windows)
@@ -15,7 +19,6 @@ set(CMAKE_SYSTEM_NAME Windows)
 set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/i686-w64-mingw32-gcc")
 set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/i686-w64-mingw32-g++")
 set(CMAKE_RC_COMPILER "${CROSS_PATH}/bin/i686-w64-mingw32-windres")
-set(CMAKE_C_FLAGS "-Wno-error")
 
 #
 # Different build system distros set release optimization level to different
@@ -29,12 +32,13 @@ set(CMAKE_C_FLAGS "-Wno-error")
 # optimizations with -O3.
 #
 if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
-       set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -O2)
-       set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} -O2)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
 endif()
 
 # Where to look for the target environment. (More paths can be added here)
-set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
+set(CMAKE_FIND_ROOT_PATH "${CROSS_ROOT}/mingw")
+set(CMAKE_SYSROOT ${CROSS_ROOT})
 
 # Adjust the default behavior of the FIND_XXX() commands:
 # search programs in the host environment only.
index 4fff882..1f1c769 100644 (file)
@@ -3,13 +3,18 @@
 #
 # This can be used when running cmake in the following way:
 #  cd build/
-#  cmake .. -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-w64.cmake -DLWS_WITH_SSL=0
+#  cmake .. -DCMAKE_TOOLCHAIN_FILE=../contrib/cross-w64.cmake
 #
 
-set(CROSS_PATH /opt/mingw64)
+# the outermost path to your cross toolchain
+#set(CROSS_PATH /opt/mingw64)
+set(CROSS_PATH /usr)
+# your cross root
+set(CROSS_ROOT ${CROSS_PATH}/x86_64-w64-mingw32/sys-root/)
 
 # Target operating system name.
 set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSROOT ${CROSS_ROOT})
 
 # Name of C compiler.
 set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/x86_64-w64-mingw32-gcc")
@@ -29,12 +34,12 @@ set(CMAKE_C_FLAGS "-Wno-error")
 # optimizations with -O3.
 #
 if (CMAKE_BUILD_TYPE MATCHES RELEASE OR CMAKE_BUILD_TYPE MATCHES Release OR CMAKE_BUILD_TYPE MATCHES release)
-       set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -O2)
-       set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} -O2)
+       set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
+       set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
 endif()
 
 # Where to look for the target environment. (More paths can be added here)
-set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
+set(CMAKE_FIND_ROOT_PATH "${CROSS_ROOT}/mingw")
 
 # Adjust the default behavior of the FIND_XXX() commands:
 # search programs in the host environment only.
diff --git a/contrib/iOS.cmake b/contrib/iOS.cmake
new file mode 100644 (file)
index 0000000..365e6a3
--- /dev/null
@@ -0,0 +1,229 @@
+# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
+# files which are included with CMake 2.8.4
+# It has been altered for iOS development
+
+# Options:
+#
+# IOS_PLATFORM = OS (default) or OS32 or SIMULATOR or SIMULATOR64
+#   This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
+#   OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
+#   SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.
+#
+# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
+#   By default this location is automatcially chosen based on the IOS_PLATFORM value above.
+#   If set manually, it will override the default location and force the user of a particular Developer Platform
+#
+# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
+#   By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.
+#   In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.
+#   If set manually, this will force the use of a specific SDK version
+#
+# IOS_BITCODE = 1/0: Enable bitcode or not. Only iOS >= 6.0 device build can enable bitcode. Default is enabled.
+
+# Macros:
+#
+# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE)
+#  A convenience macro for setting xcode specific properties on targets
+#  example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1")
+#
+# find_host_package (PROGRAM ARGS)
+#  A macro used to find executable programs on the host system, not within the iOS environment.
+#  Thanks to the android-cmake project for providing the command
+
+# Standard settings
+set (CMAKE_SYSTEM_NAME Darwin)
+set (CMAKE_SYSTEM_VERSION 1)
+set(CMAKE_CROSSCOMPILING TRUE)
+set (UNIX TRUE)
+set (APPLE TRUE)
+set (IOS TRUE)
+
+if(NOT DEFINED IOS_BITCODE) # check xcode/clang version? since xcode 7
+  set(IOS_BITCODE 1)
+endif()
+set(IOS_BITCODE_MARKER 0)
+
+# Required as of cmake 2.8.10
+set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
+
+# Determine the cmake host system version so we know where to find the iOS SDKs
+find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
+if (CMAKE_UNAME)
+       exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
+       string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
+endif (CMAKE_UNAME)
+
+# Force the compilers to gcc for iOS
+include (CMakeForceCompiler)
+set (CMAKE_C_COMPILER /usr/bin/clang)
+set (CMAKE_CXX_COMPILER /usr/bin/clang++)
+set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
+
+# Skip the platform compiler checks for cross compiling
+set (CMAKE_CXX_COMPILER_WORKS TRUE)
+set (CMAKE_C_COMPILER_WORKS TRUE)
+
+# All iOS/Darwin specific settings - some may be redundant
+set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
+set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
+set (CMAKE_SHARED_MODULE_PREFIX "lib")
+set (CMAKE_SHARED_MODULE_SUFFIX ".so")
+set (CMAKE_MODULE_EXISTS 1)
+set (CMAKE_DL_LIBS "")
+
+if(IOS_BITCODE)
+    set(BITCODE_FLAGS "-fembed-bitcode")
+  elseif(IOS_BITCODE_MARKER)
+    set(BITCODE_FLAGS "-fembed-bitcode-marker")
+  endif()
+
+set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
+set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
+set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
+
+# Hidden visibilty is required for cxx on iOS 
+set (CMAKE_C_FLAGS_INIT "${BITCODE_FLAGS}")
+set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden ${BITCODE_FLAGS}")
+
+set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
+set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
+
+set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
+set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
+set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
+set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
+set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
+set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
+
+# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
+# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
+# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
+# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
+if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
+       find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
+endif ()
+
+# Setup iOS platform unless specified manually with IOS_PLATFORM
+if (NOT DEFINED IOS_PLATFORM)
+       set (IOS_PLATFORM "OS")
+endif ()
+set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform")
+
+# Setup building for arm64 or not
+if (NOT DEFINED BUILD_ARM64)
+    set (BUILD_ARM64 true)
+endif ()
+set (BUILD_ARM64 ${BUILD_ARM64} CACHE STRING "Build arm64 arch or not")
+
+# Check the platform selection and setup for developer root
+if (${IOS_PLATFORM} STREQUAL "OS")
+       set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
+
+       # This causes the installers to properly locate the output libraries
+       set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
+elseif (${IOS_PLATFORM} STREQUAL "OS32")
+       set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
+
+       # This causes the installers to properly locate the output libraries
+       set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
+elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
+    set (IS_SIMULATOR true)
+       set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
+
+       # This causes the installers to properly locate the output libraries
+       set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
+elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64")
+    set (IS_SIMULATOR true)
+       set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
+
+       # This causes the installers to properly locate the output libraries
+       set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
+else ()
+       message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR")
+endif ()
+
+# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT
+# Note Xcode 4.3 changed the installation location, choose the most recent one available
+exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR)
+set (XCODE_POST_43_ROOT "${CMAKE_XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
+set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
+if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
+       if (EXISTS ${XCODE_POST_43_ROOT})
+               set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT})
+       elseif(EXISTS ${XCODE_PRE_43_ROOT})
+               set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT})
+       endif (EXISTS ${XCODE_POST_43_ROOT})
+endif ()
+set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform")
+
+# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT
+if (NOT DEFINED CMAKE_IOS_SDK_ROOT)
+       file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*")
+       if (_CMAKE_IOS_SDKS) 
+               list (SORT _CMAKE_IOS_SDKS)
+               list (REVERSE _CMAKE_IOS_SDKS)
+               list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT)
+       else (_CMAKE_IOS_SDKS)
+               message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.")
+       endif (_CMAKE_IOS_SDKS)
+       message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}")
+endif ()
+set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
+
+# Set the sysroot default to the most recent SDK
+set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
+
+# set the architecture for iOS 
+if (${IOS_PLATFORM} STREQUAL "OS")
+    set (IOS_ARCH arm64)
+elseif (${IOS_PLATFORM} STREQUAL "OS32")
+       set (IOS_ARCH armv7)
+elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
+    set (IOS_ARCH i386)
+elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64")
+    set (IOS_ARCH x86_64)
+endif ()
+
+set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING  "Build architecture for iOS")
+
+# Set the find root to the iOS developer roots and to user defined paths
+set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE STRING  "iOS find search path root")
+
+# default to searching for frameworks first
+set (CMAKE_FIND_FRAMEWORK FIRST)
+
+# set up the default search directories for frameworks
+set (CMAKE_SYSTEM_FRAMEWORK_PATH
+       ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
+       ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
+       ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
+)
+
+# only search the iOS sdks, not the remainder of the host filesystem
+set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+
+# This little macro lets you set any XCode specific property
+macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
+       set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
+endmacro (set_xcode_property)
+
+
+# This macro lets you find executable programs on the host system
+macro (find_host_package)
+       set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+       set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
+       set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
+       set (IOS FALSE)
+
+       find_package(${ARGN})
+
+       set (IOS TRUE)
+       set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+       set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+       set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+endmacro (find_host_package)
+
diff --git a/doc-assets/fault-injection.png b/doc-assets/fault-injection.png
new file mode 100644 (file)
index 0000000..acaf9d4
Binary files /dev/null and b/doc-assets/fault-injection.png differ
diff --git a/doc-assets/jit-trust-logo.png b/doc-assets/jit-trust-logo.png
new file mode 100644 (file)
index 0000000..86f7a0a
Binary files /dev/null and b/doc-assets/jit-trust-logo.png differ
diff --git a/doc-assets/jit-trust-overview.png b/doc-assets/jit-trust-overview.png
new file mode 100644 (file)
index 0000000..1250693
Binary files /dev/null and b/doc-assets/jit-trust-overview.png differ
diff --git a/doc-assets/jit-trust-paths.png b/doc-assets/jit-trust-paths.png
new file mode 100644 (file)
index 0000000..395d883
Binary files /dev/null and b/doc-assets/jit-trust-paths.png differ
diff --git a/doc-assets/jit-trust-single-trust.png b/doc-assets/jit-trust-single-trust.png
new file mode 100644 (file)
index 0000000..67758c5
Binary files /dev/null and b/doc-assets/jit-trust-single-trust.png differ
diff --git a/doc-assets/jit-trust-system-trust.png b/doc-assets/jit-trust-system-trust.png
new file mode 100644 (file)
index 0000000..be2b99b
Binary files /dev/null and b/doc-assets/jit-trust-system-trust.png differ
diff --git a/doc-assets/lifecycle-context.png b/doc-assets/lifecycle-context.png
new file mode 100644 (file)
index 0000000..bf92b76
Binary files /dev/null and b/doc-assets/lifecycle-context.png differ
diff --git a/doc-assets/lifecycle-server-wsi.png b/doc-assets/lifecycle-server-wsi.png
new file mode 100644 (file)
index 0000000..f41164c
Binary files /dev/null and b/doc-assets/lifecycle-server-wsi.png differ
diff --git a/doc-assets/lifecycle-wsi.png b/doc-assets/lifecycle-wsi.png
new file mode 100644 (file)
index 0000000..4db2d37
Binary files /dev/null and b/doc-assets/lifecycle-wsi.png differ
diff --git a/doc-assets/lws-detailed-latency-example.png b/doc-assets/lws-detailed-latency-example.png
new file mode 100644 (file)
index 0000000..e23132b
Binary files /dev/null and b/doc-assets/lws-detailed-latency-example.png differ
index 64195d9..af444d4 100644 (file)
Binary files a/doc-assets/lws-overview.png and b/doc-assets/lws-overview.png differ
diff --git a/doc-assets/lws_cache-1.png b/doc-assets/lws_cache-1.png
new file mode 100644 (file)
index 0000000..260677d
Binary files /dev/null and b/doc-assets/lws_cache-1.png differ
diff --git a/doc-assets/lws_cache-2.png b/doc-assets/lws_cache-2.png
new file mode 100644 (file)
index 0000000..ab69c3d
Binary files /dev/null and b/doc-assets/lws_cache-2.png differ
diff --git a/doc-assets/lws_metrics-decimation.png b/doc-assets/lws_metrics-decimation.png
new file mode 100644 (file)
index 0000000..e791608
Binary files /dev/null and b/doc-assets/lws_metrics-decimation.png differ
diff --git a/doc-assets/lws_metrics-policy.png b/doc-assets/lws_metrics-policy.png
new file mode 100644 (file)
index 0000000..d1d5766
Binary files /dev/null and b/doc-assets/lws_metrics-policy.png differ
diff --git a/doc-assets/smd-message.png b/doc-assets/smd-message.png
new file mode 100644 (file)
index 0000000..cd528a7
Binary files /dev/null and b/doc-assets/smd-message.png differ
diff --git a/doc-assets/smd-proxy.png b/doc-assets/smd-proxy.png
new file mode 100644 (file)
index 0000000..ae522ca
Binary files /dev/null and b/doc-assets/smd-proxy.png differ
diff --git a/doc-assets/smd-single-process.png b/doc-assets/smd-single-process.png
new file mode 100644 (file)
index 0000000..4ae9e9c
Binary files /dev/null and b/doc-assets/smd-single-process.png differ
diff --git a/doc-assets/ss-explain.png b/doc-assets/ss-explain.png
new file mode 100644 (file)
index 0000000..14bd7e7
Binary files /dev/null and b/doc-assets/ss-explain.png differ
diff --git a/doc-assets/ss-operation-modes.png b/doc-assets/ss-operation-modes.png
new file mode 100644 (file)
index 0000000..8c0f5d3
Binary files /dev/null and b/doc-assets/ss-operation-modes.png differ
diff --git a/doc-assets/ss-state-flow-server.png b/doc-assets/ss-state-flow-server.png
new file mode 100644 (file)
index 0000000..9d8cfd5
Binary files /dev/null and b/doc-assets/ss-state-flow-server.png differ
diff --git a/doc-assets/ss-state-flow.png b/doc-assets/ss-state-flow.png
new file mode 100644 (file)
index 0000000..151207e
Binary files /dev/null and b/doc-assets/ss-state-flow.png differ
diff --git a/doc-assets/work.png b/doc-assets/work.png
new file mode 100644 (file)
index 0000000..37b3801
Binary files /dev/null and b/doc-assets/work.png differ
index 642f56b..4409ee2 100644 (file)
@@ -1,22 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** @file */
@@ -38,11 +41,15 @@ extern "C" {
 
 #include "lws_config.h"
 
+#if defined(LWS_SUPPRESS_DEPRECATED_API_WARNINGS)
+#define OPENSSL_USE_DEPRECATED
+#endif
+
 /* place for one-shot opaque forward references */
 
-typedef struct lws_sequencer lws_seq_t; /* opaque */
-typedef struct lws_sorted_usec_list lws_sorted_usec_list_t; /* opaque */
-typedef struct lws_dsh lws_dsh_t;
+typedef struct lws_context * lws_ctx_t;
+struct lws_sequencer;
+struct lws_dsh;
 
 /*
  * CARE: everything using cmake defines needs to be below here
@@ -85,25 +92,44 @@ typedef unsigned long long lws_intptr_t;
 #define O_RDONLY       _O_RDONLY
 #endif
 
+typedef int uid_t;
+typedef int gid_t;
+typedef unsigned short sa_family_t;
+#if !defined(LWS_HAVE_SUSECONDS_T)
+typedef unsigned int useconds_t;
+typedef int suseconds_t;
+#endif
+
 #define LWS_INLINE __inline
 #define LWS_VISIBLE
 #define LWS_WARN_UNUSED_RESULT
 #define LWS_WARN_DEPRECATED
 #define LWS_FORMAT(string_index)
 
-#if !defined(LWS_EXTERN)
+#if !defined(LWS_EXTERN) && defined(LWS_BUILDING_SHARED)
 #ifdef LWS_DLL
 #ifdef LWS_INTERNAL
 #define LWS_EXTERN extern __declspec(dllexport)
 #else
 #define LWS_EXTERN extern __declspec(dllimport)
 #endif
-#else
+#endif
+#endif
+
+#if !defined(LWS_INTERNAL) && !defined(LWS_EXTERN)
 #define LWS_EXTERN
+#define LWS_VISIBLE
 #endif
+
+#if !defined(LWS_EXTERN)
+#define LWS_EXTERN
 #endif
 
+#if defined(__MINGW32__)
+#define LWS_INVALID_FILE -1
+#else
 #define LWS_INVALID_FILE INVALID_HANDLE_VALUE
+#endif
 #define LWS_SOCK_INVALID (INVALID_SOCKET)
 #define LWS_O_RDONLY _O_RDONLY
 #define LWS_O_WRONLY _O_WRONLY
@@ -131,14 +157,14 @@ typedef unsigned long long lws_intptr_t;
 #define LWS_O_CREAT O_CREAT
 #define LWS_O_TRUNC O_TRUNC
 
-#if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_TA) && !defined(LWS_WITH_ESP32)
+#if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_TA) && !defined(LWS_PLAT_FREERTOS)
 #include <poll.h>
 #include <netdb.h>
 #define LWS_INVALID_FILE -1
 #define LWS_SOCK_INVALID (-1)
 #else
 #define getdtablesize() (30)
-#if defined(LWS_WITH_ESP32)
+#if defined(LWS_PLAT_FREERTOS)
 #define LWS_INVALID_FILE NULL
 #define LWS_SOCK_INVALID (-1)
 #else
@@ -147,6 +173,9 @@ typedef unsigned long long lws_intptr_t;
 #endif
 #endif
 
+#if defined(__FreeBSD__)
+#include <sys/signal.h>
+#endif
 #if defined(__GNUC__)
 
 /* warn_unused_result attribute only supported by GCC 3.4 or later */
@@ -156,50 +185,65 @@ typedef unsigned long long lws_intptr_t;
 #define LWS_WARN_UNUSED_RESULT
 #endif
 
+#if defined(LWS_BUILDING_SHARED)
+/* this is only set when we're building lws itself shared */
 #define LWS_VISIBLE __attribute__((visibility("default")))
+#define LWS_EXTERN extern
+
+#else /* not shared */
+#if defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
+#define LWS_VISIBLE
+#define LWS_EXTERN extern
+#else
+/*
+ * If we explicitly say hidden here, symbols exist as T but
+ * cannot be imported at link-time.
+ */
+#define LWS_VISIBLE
+#define LWS_EXTERN
+#endif
+
+#endif /* not shared */
+
 #define LWS_WARN_DEPRECATED __attribute__ ((deprecated))
 #define LWS_FORMAT(string_index) __attribute__ ((format(printf, string_index, string_index+1)))
-#else
+#else /* not GNUC */
+
 #define LWS_VISIBLE
 #define LWS_WARN_UNUSED_RESULT
 #define LWS_WARN_DEPRECATED
 #define LWS_FORMAT(string_index)
+#if !defined(LWS_EXTERN)
+#define LWS_EXTERN extern
+#endif
 #endif
 
+
 #if defined(__ANDROID__)
 #include <netinet/in.h>
 #include <unistd.h>
 #endif
+#endif
 
+#ifdef _WIN32
+#define random rand
+#else
+#if !defined(LWS_PLAT_OPTEE)
+#include <sys/time.h>
+#include <unistd.h>
+#endif
 #endif
 
-#if defined(LWS_WITH_LIBEV)
-#include <ev.h>
-#endif /* LWS_WITH_LIBEV */
-#ifdef LWS_WITH_LIBUV
+#if defined(LWS_WITH_LIBUV_INTERNAL)
 #include <uv.h>
+
 #ifdef LWS_HAVE_UV_VERSION_H
 #include <uv-version.h>
 #endif
+
 #ifdef LWS_HAVE_NEW_UV_VERSION_H
 #include <uv/version.h>
 #endif
-#endif /* LWS_WITH_LIBUV */
-#if defined(LWS_WITH_LIBEVENT)
-#include <event2/event.h>
-#endif /* LWS_WITH_LIBEVENT */
-
-#ifndef LWS_EXTERN
-#define LWS_EXTERN extern
-#endif
-
-#ifdef _WIN32
-#define random rand
-#else
-#if !defined(LWS_PLAT_OPTEE)
-#include <sys/time.h>
-#include <unistd.h>
-#endif
 #endif
 
 #if defined(LWS_WITH_TLS)
@@ -235,7 +279,7 @@ typedef unsigned long long lws_intptr_t;
 #endif /* not USE_OLD_CYASSL */
 #else
 #if defined(LWS_WITH_MBEDTLS)
-#if defined(LWS_WITH_ESP32)
+#if defined(LWS_PLAT_FREERTOS)
 /* this filepath is passed to us but without quotes or <> */
 #if !defined(LWS_AMAZON_RTOS)
 /* AMAZON RTOS has its own setting via MTK_MBEDTLS_CONFIG_FILE */
@@ -243,9 +287,16 @@ typedef unsigned long long lws_intptr_t;
 #define MBEDTLS_CONFIG_FILE <mbedtls/esp_config.h>
 #endif
 #endif
+#if defined(LWS_WITH_TLS)
 #include <mbedtls/ssl.h>
 #include <mbedtls/entropy.h>
 #include <mbedtls/ctr_drbg.h>
+
+#if !defined(MBEDTLS_PRIVATE)
+#define MBEDTLS_PRIVATE(_q) _q
+#endif
+
+#endif
 #else
 #include <openssl/ssl.h>
 #if !defined(LWS_WITH_MBEDTLS)
@@ -312,6 +363,7 @@ lws_pthread_mutex_unlock(pthread_mutex_t *lock)
 #ifndef lws_container_of
 #define lws_container_of(P,T,M)        ((T *)((char *)(P) - offsetof(T, M)))
 #endif
+#define LWS_ALIGN_TO(x, bou) x += ((bou) - ((x) % (bou))) % (bou)
 
 struct lws;
 
@@ -335,22 +387,24 @@ struct lws;
 #if defined(_WIN32)
 #if !defined(LWS_WIN32_HANDLE_TYPES)
 typedef SOCKET lws_sockfd_type;
+#if defined(__MINGW32__)
+typedef int lws_filefd_type;
+#else
 typedef HANDLE lws_filefd_type;
 #endif
+#endif
+
+
+#define lws_pollfd pollfd
+#define LWS_POLLHUP    (POLLHUP)
+#define LWS_POLLIN     (POLLRDNORM | POLLRDBAND)
+#define LWS_POLLOUT    (POLLWRNORM)
 
-struct lws_pollfd {
-       lws_sockfd_type fd; /**< file descriptor */
-       SHORT events; /**< which events to respond to */
-       SHORT revents; /**< which events happened */
-};
-#define LWS_POLLHUP (FD_CLOSE)
-#define LWS_POLLIN (FD_READ | FD_ACCEPT)
-#define LWS_POLLOUT (FD_WRITE)
 #else
 
 
-#if defined(LWS_WITH_ESP32)
-#include <libwebsockets/lws-esp32.h>
+#if defined(LWS_PLAT_FREERTOS)
+#include <libwebsockets/lws-freertos.h>
 #else
 typedef int lws_sockfd_type;
 typedef int lws_filefd_type;
@@ -518,53 +572,85 @@ struct lws_pollargs {
 
 struct lws_extension; /* needed even with ws exts disabled for create context */
 struct lws_token_limits;
+struct lws_protocols;
 struct lws_context;
 struct lws_tokens;
 struct lws_vhost;
 struct lws;
 
+#include <libwebsockets/lws-dll2.h>
+#include <libwebsockets/lws-map.h>
+
+#include <libwebsockets/lws-fault-injection.h>
+#include <libwebsockets/lws-timeout-timer.h>
+#include <libwebsockets/lws-cache-ttl.h>
+#if defined(LWS_WITH_SYS_SMD)
+#include <libwebsockets/lws-smd.h>
+#endif
+#include <libwebsockets/lws-state.h>
+#include <libwebsockets/lws-retry.h>
+#include <libwebsockets/lws-adopt.h>
+#include <libwebsockets/lws-network-helper.h>
+#include <libwebsockets/lws-metrics.h>
 #include <libwebsockets/lws-system.h>
 #include <libwebsockets/lws-ws-close.h>
 #include <libwebsockets/lws-callbacks.h>
 #include <libwebsockets/lws-ws-state.h>
 #include <libwebsockets/lws-ws-ext.h>
 #include <libwebsockets/lws-protocols-plugins.h>
-#include <libwebsockets/lws-plugin-generic-sessions.h>
+
 #include <libwebsockets/lws-context-vhost.h>
+
+#if defined(LWS_WITH_CONMON)
+#include <libwebsockets/lws-conmon.h>
+#endif
+
+#if defined(LWS_ROLE_MQTT)
+#include <libwebsockets/lws-mqtt.h>
+#endif
 #include <libwebsockets/lws-client.h>
 #include <libwebsockets/lws-http.h>
 #include <libwebsockets/lws-spa.h>
 #include <libwebsockets/lws-purify.h>
 #include <libwebsockets/lws-misc.h>
 #include <libwebsockets/lws-dsh.h>
-#include <libwebsockets/lws-timeout-timer.h>
 #include <libwebsockets/lws-service.h>
 #include <libwebsockets/lws-write.h>
 #include <libwebsockets/lws-writeable.h>
-#include <libwebsockets/lws-adopt.h>
-#include <libwebsockets/lws-network-helper.h>
 #include <libwebsockets/lws-ring.h>
 #include <libwebsockets/lws-sha1-base64.h>
 #include <libwebsockets/lws-x509.h>
 #include <libwebsockets/lws-cgi.h>
+#if defined(LWS_WITH_FILE_OPS)
 #include <libwebsockets/lws-vfs.h>
+#endif
+#include <libwebsockets/lws-gencrypto.h>
+
 #include <libwebsockets/lws-lejp.h>
-#include <libwebsockets/lws-stats.h>
+#include <libwebsockets/lws-lecp.h>
+#include <libwebsockets/lws-cose.h>
 #include <libwebsockets/lws-struct.h>
 #include <libwebsockets/lws-threadpool.h>
 #include <libwebsockets/lws-tokenize.h>
 #include <libwebsockets/lws-lwsac.h>
 #include <libwebsockets/lws-fts.h>
 #include <libwebsockets/lws-diskcache.h>
-#include <libwebsockets/lws-retry.h>
 #include <libwebsockets/lws-sequencer.h>
+#include <libwebsockets/lws-secure-streams.h>
+#include <libwebsockets/lws-secure-streams-policy.h>
+#include <libwebsockets/lws-secure-streams-client.h>
 
+#if !defined(LWS_PLAT_FREERTOS)
 #include <libwebsockets/abstract/abstract.h>
 
 #include <libwebsockets/lws-test-sequencer.h>
+#endif
+#include <libwebsockets/lws-async-dns.h>
 
 #if defined(LWS_WITH_TLS)
 
+#include <libwebsockets/lws-tls-sessions.h>
+
 #if defined(LWS_WITH_MBEDTLS)
 #include <mbedtls/md5.h>
 #include <mbedtls/sha1.h>
@@ -572,7 +658,6 @@ struct lws;
 #include <mbedtls/sha512.h>
 #endif
 
-#include <libwebsockets/lws-gencrypto.h>
 #include <libwebsockets/lws-genhash.h>
 #include <libwebsockets/lws-genrsa.h>
 #include <libwebsockets/lws-genaes.h>
@@ -585,6 +670,21 @@ struct lws;
 
 #endif
 
+#include <libwebsockets/lws-eventlib-exports.h>
+#include <libwebsockets/lws-i2c.h>
+#include <libwebsockets/lws-spi.h>
+#include <libwebsockets/lws-gpio.h>
+#include <libwebsockets/lws-bb-i2c.h>
+#include <libwebsockets/lws-bb-spi.h>
+#include <libwebsockets/lws-button.h>
+#include <libwebsockets/lws-led.h>
+#include <libwebsockets/lws-pwm.h>
+#include <libwebsockets/lws-display.h>
+#include <libwebsockets/lws-ssd1306-i2c.h>
+#include <libwebsockets/lws-ili9341-spi.h>
+#include <libwebsockets/lws-settings.h>
+#include <libwebsockets/lws-netdev.h>
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/libwebsockets.hxx b/include/libwebsockets.hxx
new file mode 100644 (file)
index 0000000..4e395a7
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * C++ classes for Secure Streams
+ */
+
+#include <map>
+#include <set>
+#include <list>
+#include <string>
+#include <vector>
+#include <exception>
+
+#include "libwebsockets.h"
+
+class lss;
+
+/*
+ * Exception subclass for lss-specific issues
+ */
+
+class lssException : public std::exception
+{
+private:
+       std::string details;
+public:
+       lssException(std::string _details) { details = _details; }
+       ~lssException() throw() { }
+       virtual const char *what() const throw() { return details.c_str(); }
+};
+
+typedef struct lssbuf {
+       uint8_t                         *buf;
+       size_t                          len;
+} lssbuf_t;
+
+class lssAc
+{
+private:
+       struct lwsac                    *ac;
+       struct lwsac                    *iter;
+       lssAc() { ac = NULL; }
+       ~lssAc() { lwsac_free(&ac); }
+
+public:
+       void append(lssbuf_t *lb);
+       void start(bool atomic);
+       int get(lssbuf_t *lb);
+};
+
+/*
+ * Fixed userdata priv used with ss creation... userdata lives in the lss
+ * subclasses' members
+ */
+
+class lssPriv
+{
+public:
+       struct lws_ss_handle            *m_ss;
+       void                            *m_plss;
+};
+
+#define userobj_to_lss(uo) ((lss *)(((lssPriv *)userobj)->m_plss))
+
+/*
+ * The completion callback... it's called once, and state will be one of
+ *
+ * LWSSSCS_QOS_ACK_REMOTE:     it completed OK
+ * LWSSSCS_DESTROYING:         we didn't complete
+ * LWSSSCS_ALL_RETRIES_FAILED:  "
+ * LWSSSCS_QOS_NACK_REMOTE:     "
+ */
+
+typedef int (*lsscomp_t)(lss *lss, lws_ss_constate_t state, void *arg);
+
+/*
+ * Base class for Secure Stream objects
+ */
+
+class lss
+{
+public:
+       lss(lws_ctx_t _ctx, std::string _uri, lsscomp_t _comp, bool _psh,
+           lws_sscb_rx rx, lws_sscb_tx tx, lws_sscb_state state);
+       virtual ~lss();
+       int call_completion(lws_ss_constate_t state);
+
+       lsscomp_t                       comp;
+       struct lws_ss_handle            *m_ss;
+       uint64_t                        rxlen;
+       lws_usec_t                      us_start;
+
+private:
+       lws_ctx_t                       ctx;
+       char                            *uri;
+       lws_ss_policy_t                 pol;
+       bool                            comp_done;
+};
+
+/*
+ * Subclass of lss for atomic messages on heap
+ */
+
+class lssMsg : public lss
+{
+public:
+       lssMsg(lws_ctx_t _ctx, lsscomp_t _comp, std::string _uri);
+       virtual ~lssMsg();
+};
+
+/*
+ * Subclass of lss for file transactions
+ */
+
+class lssFile : public lss
+{
+public:
+       lssFile(lws_ctx_t _ctx, std::string _uri, std::string _path,
+               lsscomp_t _comp, bool _psh);
+       virtual ~lssFile();
+       lws_ss_state_return_t write(const uint8_t *buf, size_t len, int flags);
+
+       std::string                     path;
+
+private:
+       lws_filefd_type                 fd;
+       bool                            push;
+};
index d8f0228..c312a1f 100644 (file)
@@ -1,22 +1,25 @@
 /*
- * libwebsockets - abstract top level header
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*
@@ -39,8 +42,7 @@ typedef struct lws_token_map {
 /*
  * The indvidual protocols and transports define their own name_index-es which
  * are meaningful to them.  Define index 0 globally as the end of an array of
- * them, and separate the ones used for protocols and transport so we can
- * sanity check they are at least in the correct category.
+ * them, and provide bases so user protocol and transport ones don't overlap.
  */
 
 enum {
@@ -53,6 +55,7 @@ enum {
 
 struct lws_abs_transport;
 struct lws_abs_protocol;
+typedef struct lws_abs lws_abs_t;
 
 LWS_VISIBLE LWS_EXTERN const lws_token_map_t *
 lws_abs_get_token(const lws_token_map_t *token_map, short name_index);
@@ -64,28 +67,40 @@ lws_abs_get_token(const lws_token_map_t *token_map, short name_index);
 typedef void lws_abs_transport_inst_t;
 typedef void lws_abs_protocol_inst_t;
 
-typedef struct lws_abs {
-       void                            *user;
-       struct lws_vhost                *vh;
-
-       const struct lws_abs_protocol   *ap;
-       const lws_token_map_t           *ap_tokens;
-       const struct lws_abs_transport  *at;
-       const lws_token_map_t           *at_tokens;
-
-       lws_seq_t                       *seq;
-       void                            *opaque_user_data;
+/**
+ * lws_abstract_alloc() - allocate and configure an lws_abs_t
+ *
+ * \param vhost: the struct lws_vhost to bind to
+ * \param user: opaque user pointer
+ * \param abstract_path: "protocol.transport" names
+ * \param ap_tokens: tokens for protocol options
+ * \param at_tokens: tokens for transport
+ * \param seq: optional sequencer we should bind to, or NULL
+ * \param opaque_user_data: data given in sequencer callback, if any
+ *
+ * Returns an allocated lws_abs_t pointer set up with the other arguments.
+ *
+ * Doesn't create a connection instance, just allocates the lws_abs_t and
+ * sets it up with the arguments.
+ *
+ * Returns NULL is there's any problem.
+ */
+LWS_VISIBLE LWS_EXTERN lws_abs_t *
+lws_abstract_alloc(struct lws_vhost *vhost, void *user,
+                  const char *abstract_path, const lws_token_map_t *ap_tokens,
+                  const lws_token_map_t *at_tokens, struct lws_sequencer *seq,
+                  void *opaque_user_data);
 
-       /*
-        * These are filled in by lws_abs_bind_and_create_instance() in the
-        * instance copy.  They do not need to be set when creating the struct
-        * for use by lws_abs_bind_and_create_instance()
-        */
+/**
+ * lws_abstract_free() - free an allocated lws_abs_t
+ *
+ * \param pabs: pointer to the lws_abs_t * to free
+ *
+ * Frees and sets the pointer to NULL.
+ */
 
-       struct lws_dll2                 abstract_instances;
-       lws_abs_transport_inst_t        *ati;
-       lws_abs_protocol_inst_t         *api;
-} lws_abs_t;
+LWS_VISIBLE LWS_EXTERN void
+lws_abstract_free(lws_abs_t **pabs);
 
 /**
  * lws_abs_bind_and_create_instance - use an abstract protocol and transport
index a6f802a..7790020 100644 (file)
@@ -1,38 +1,72 @@
 /*
- * libwebsockets - abstract protocol definitions
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+/*
+ * Information about how this protocol handles multiple use of connections.
+ *
+ * .flags of 0 indicates each connection must start with a fresh transport.
+ *
+ * Flags can be used to indicate the protocol itself supports different
+ * kinds of multiple use.  However the actual use or not of these may depend on
+ * negotiation with the remote peer.
+ *
+ * LWS_AP_FLAG_PIPELINE_TRANSACTIONS:  other instances can be queued on one
+ *                                     with an existing connection and get a
+ *                                     chance to "hot take over" the existing
+ *                                     transport in turn, like h1 keepalive
+ *                                     pipelining
+ *
+ * LWS_AP_FLAG_MUXABLE_STREAM: an existing connection can absorb more child
+ *                             connections and mux them as separate child
+ *                             streams ongoing, like h2
+ */
+
+enum {
+       LWS_AP_FLAG_PIPELINE_TRANSACTIONS                       = (1 << 0),
+       LWS_AP_FLAG_MUXABLE_STREAM                              = (1 << 1),
+};
+
 typedef struct lws_abs_protocol {
        const char      *name;
        int             alloc;
+       int             flags;
 
-       int (*create)(const struct lws_abs *ai);
-       void (*destroy)(lws_abs_protocol_inst_t **d);
+       int             (*create)(const struct lws_abs *ai);
+       void            (*destroy)(lws_abs_protocol_inst_t **d);
+       int             (*compare)(lws_abs_t *abs1, lws_abs_t *abs2);
 
        /* events the transport invokes (handled by abstract protocol) */
 
-       int (*accept)(lws_abs_protocol_inst_t *d);
-       int (*rx)(lws_abs_protocol_inst_t *d, uint8_t *buf, size_t len);
-       int (*writeable)(lws_abs_protocol_inst_t *d, size_t budget);
-       int (*closed)(lws_abs_protocol_inst_t *d);
-       int (*heartbeat)(lws_abs_protocol_inst_t *d);
+       int             (*accept)(lws_abs_protocol_inst_t *d);
+       int             (*rx)(lws_abs_protocol_inst_t *d, const uint8_t *b, size_t l);
+       int             (*writeable)(lws_abs_protocol_inst_t *d, size_t budget);
+       int             (*closed)(lws_abs_protocol_inst_t *d);
+       int             (*heartbeat)(lws_abs_protocol_inst_t *d);
+
+       /* as parent, we get a notification a new child / queue entry
+        * bound to us... this is the parent lws_abs_t as arg */
+       int             (*child_bind)(lws_abs_t *abs);
 } lws_abs_protocol_t;
 
 /**
@@ -51,3 +85,4 @@ lws_abs_protocol_get_by_name(const char *name);
  */
 
 #include <libwebsockets/abstract/protocols/smtp.h>
+
index 5fb434e..90b69c6 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup smtp SMTP related functions
  * 25 and able to send email using the "mail" commandline app.  Usually distro
  * MTAs are configured for this by default.
  *
- * It runs via its own libuv events if initialized (which requires giving it
- * a libuv loop to attach to).
- *
- * It operates using three callbacks, on_next() queries if there is a new email
- * to send, on_get_body() asks for the body of the email, and on_sent() is
- * called after the email is successfully sent.
- *
- * To use it
- *
- *  - create an lws_email struct
- *
- *  - initialize data, loop, the email_* strings, max_content_size and
- *    the callbacks
- *
- *  - call lws_email_init()
- *
- *  When you have at least one email to send, call lws_email_check() to
- *  schedule starting to send it.
+ * You can either use the abstract protocol layer directly, or instead use the
+ * provided smtp sequencer... this takes care of creating the protocol
+ * connections, and provides and email queue and retry management.
  */
 //@{
+
 #if defined(LWS_WITH_SMTP)
 
 enum {
        LTMI_PSMTP_V_HELO = LTMI_PROTOCOL_BASE,         /* u.value */
-       LTMI_PSMTP_LV_RETRY_INTERVAL,                   /* u.lvalue */
-       LTMI_PSMTP_LV_DELIVERY_TIMEOUT,                 /* u.lvalue */
-       LTMI_PSMTP_LV_EMAIL_QUEUE_MAX,                  /* u.lvalue */
-       LTMI_PSMTP_LV_MAX_CONTENT_SIZE,                 /* u.lvalue */
-};
 
-typedef struct lws_smtp_client lws_smtp_client_t;
-typedef struct lws_abs lws_abs_t;
-
-typedef struct lws_smtp_email {
-       struct lws_dll2 list;
+       LTMI_PSMTP_V_LWS_SMTP_EMAIL_T,                  /* u.value */
+};
 
-       void *data;
-       void *extra;
+enum {
+       LWS_SMTP_DISPOSITION_SENT,
+       LWS_SMTP_DISPOSITION_FAILED,
+       LWS_SMTP_DISPOSITION_FAILED_DESTROY
+};
 
-       time_t added;
-       time_t last_try;
+typedef struct lws_smtp_sequencer_args {
+       const char              helo[32];
+       struct lws_vhost        *vhost;
+       time_t                  retry_interval;
+       time_t                  delivery_timeout;
+       size_t                  email_queue_max;
+       size_t                  max_content_size;
+} lws_smtp_sequencer_args_t;
 
-       const char *email_from;
-       const char *email_to;
-       const char *payload;
+typedef struct lws_smtp_sequencer lws_smtp_sequencer_t;
+typedef struct lws_smtp_email lws_smtp_email_t;
 
-       int (*done)(struct lws_smtp_email *e, void *buf, size_t len);
+LWS_VISIBLE LWS_EXTERN lws_smtp_sequencer_t *
+lws_smtp_sequencer_create(const lws_smtp_sequencer_args_t *args);
 
-       int tries;
-} lws_smtp_email_t;
+LWS_VISIBLE LWS_EXTERN void
+lws_smtp_sequencer_destroy(lws_smtp_sequencer_t *s);
 
+typedef int (*lws_smtp_cb_t)(void *e, void *d, int disp, const void *b, size_t l);
+typedef struct lws_smtp_email lws_smtp_email_t;
 
 /**
- * lws_smtp_client_alloc_email_helper() - Allocates and inits an email object
+ * lws_smtpc_add_email() - Allocates and queues an email object
  *
+ * \param s: smtp sequencer to queue on
  * \param payload: the email payload string, with headers and terminating .
  * \param payload_len: size in bytes of the payload string
  * \param sender: the sender name and email
  * \param recipient: the recipient name and email
+ * \param data: opaque user data returned in the done callback
+ * \param done: callback called when the email send succeeded or failed
  *
  * Allocates an email object and copies the payload, sender and recipient into
  * it and initializes it.  Returns NULL if OOM, otherwise the allocated email
@@ -102,33 +95,21 @@ typedef struct lws_smtp_email {
  * The done() callback must free the email object.  It doesn't have to free any
  * individual members.
  */
-LWS_VISIBLE LWS_EXTERN lws_smtp_email_t *
-lws_smtp_client_alloc_email_helper(const char *payload, size_t payload_len,
-                                  const char *sender, const char *recipient,
-                                  const char *extra, size_t extra_len, void *data,
-                                  int (*done)(struct lws_smtp_email *e,
-                                              void *buf, size_t len));
+LWS_VISIBLE LWS_EXTERN int
+lws_smtpc_add_email(lws_smtp_sequencer_t *s, const char *payload,
+                   size_t payload_len, const char *sender,
+                   const char *recipient, void *data, lws_smtp_cb_t done);
 
 /**
- * lws_smtp_client_add_email() - Add email to the list of ones being sent
+ * lws_smtpc_free_email() - Add email to the list of ones being sent
  *
- * \param instance: smtp client + transport
  * \param e: email to queue for sending on \p c
  *
  * Adds an email to the linked-list of emails to send
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_smtp_client_add_email(lws_abs_t *instance, lws_smtp_email_t *e);
+lws_smtpc_free_email(lws_smtp_email_t *e);
 
-/**
- * lws_smtp_client_kick() - Request check for new email
- *
- * \param instance: instance to kick
- *
- * Gives smtp client a chance to move things on
- */
-LWS_VISIBLE LWS_EXTERN void
-lws_smtp_client_kick(lws_abs_t *instance);
 
 #endif
 //@}
index e0aebc3..e9d7aa5 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*
@@ -29,9 +30,12 @@ typedef struct lws_abs_transport {
        const char *name;
        int alloc;
 
-       int (*create)(struct lws_abs *abs);
+       int (*create)(lws_abs_t *abs);
        void (*destroy)(lws_abs_transport_inst_t **d);
 
+       /* check if the transport settings for these connections are the same */
+       int (*compare)(lws_abs_t *abs1, lws_abs_t *abs2);
+
        /* events the abstract protocol invokes (handled by transport) */
 
        int (*tx)(lws_abs_transport_inst_t *d, uint8_t *buf, size_t len);
index f35ecaf..beff9a3 100644 (file)
@@ -1,22 +1,25 @@
 /*
- * libwebsockets - raw-skt abstract transport
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 enum {
index 1527ec8..2213f29 100644 (file)
@@ -1,22 +1,25 @@
-/*
- * libwebsockets include/libwebsockets/abstract/transports/unit-test.c
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * This is an abstract transport useful for unit testing abstract protocols.
  *
index 81d2811..94a1818 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup sock-adopt Socket adoption helpers
@@ -63,12 +64,12 @@ LWS_VISIBLE LWS_EXTERN struct lws *
 lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
 
 typedef enum {
-       LWS_ADOPT_RAW_FILE_DESC = 0,    /* convenience constant */
-       LWS_ADOPT_HTTP = 1,             /* flag: absent implies RAW */
-       LWS_ADOPT_SOCKET = 2,           /* flag: absent implies file descr */
-       LWS_ADOPT_ALLOW_SSL = 4,        /* flag: if set requires LWS_ADOPT_SOCKET */
-       LWS_ADOPT_FLAG_UDP = 16,        /* flag: socket is UDP */
-       LWS_ADOPT_FLAG_RAW_PROXY = 32,  /* flag: raw proxy */
+       LWS_ADOPT_RAW_FILE_DESC         =  0,   /* convenience constant */
+       LWS_ADOPT_HTTP                  =  1,   /* flag: absent implies RAW */
+       LWS_ADOPT_SOCKET                =  2,   /* flag: absent implies file */
+       LWS_ADOPT_ALLOW_SSL             =  4,   /* flag: use tls */
+       LWS_ADOPT_FLAG_UDP              = 16,   /* flag: socket is UDP */
+       LWS_ADOPT_FLAG_RAW_PROXY        = 32,   /* flag: raw proxy */
 
        LWS_ADOPT_RAW_SOCKET_UDP = LWS_ADOPT_SOCKET | LWS_ADOPT_FLAG_UDP,
 } lws_adoption_type;
@@ -78,13 +79,45 @@ typedef union {
        lws_filefd_type filefd;
 } lws_sock_file_fd_type;
 
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
-struct lws_udp {
-       struct sockaddr sa;
-       socklen_t salen;
+#if defined(LWS_ESP_PLATFORM)
+#include <lwip/sockets.h>
+#endif
 
-       struct sockaddr sa_pending;
-       socklen_t salen_pending;
+typedef union {
+#if defined(LWS_WITH_IPV6)
+       struct sockaddr_in6 sa6;
+#else
+#if defined(LWS_ESP_PLATFORM)
+       uint8_t _pad_sa6[28];
+#endif
+#endif
+       struct sockaddr_in sa4;
+} lws_sockaddr46;
+
+#define sa46_sockaddr(_sa46) ((struct sockaddr *)(_sa46))
+
+#if defined(LWS_WITH_IPV6)
+#define sa46_socklen(_sa46) (socklen_t)((_sa46)->sa4.sin_family == AF_INET ? \
+                               sizeof(struct sockaddr_in) : \
+                               sizeof(struct sockaddr_in6))
+#define sa46_sockport(_sa46, _sp)  { if ((_sa46)->sa4.sin_family == AF_INET) \
+                                       (_sa46)->sa4.sin_port = (_sp); else \
+                                       (_sa46)->sa6.sin6_port = (_sp); }
+#define sa46_address(_sa46) ((uint8_t *)((_sa46)->sa4.sin_family == AF_INET ? \
+                    &_sa46->sa4.sin_addr : &_sa46->sa6.sin6_addr ))
+#else
+#define sa46_socklen(_sa46) (socklen_t)sizeof(struct sockaddr_in)
+#define sa46_sockport(_sa46, _sp)  (_sa46)->sa4.sin_port = (_sp)
+#define sa46_address(_sa46) (uint8_t *)&_sa46->sa4.sin_addr
+#endif
+
+#define sa46_address_len(_sa46) ((_sa46)->sa4.sin_family == AF_INET ? 4 : 16)
+
+#if defined(LWS_WITH_UDP)
+struct lws_udp {
+       lws_sockaddr46          sa46;
+       lws_sockaddr46          sa46_pending;
+       uint8_t                 connected:1;
 };
 #endif
 
@@ -112,6 +145,41 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
                           lws_sock_file_fd_type fd, const char *vh_prot_name,
                           struct lws *parent);
 
+typedef struct lws_adopt_desc {
+       struct lws_vhost *vh;           /**< vhost the wsi should belong to */
+       lws_adoption_type type;         /**< OR-ed combinations of lws_adoption_type flags */
+       lws_sock_file_fd_type fd;       /**< union with either .sockfd or .filefd set */
+       const char *vh_prot_name;       /**< NULL or vh protocol name to bind raw connection to */
+       struct lws *parent;             /**< NULL or struct lws to attach new_wsi to as a child */
+       void *opaque;                   /**< opaque pointer to set on created wsi */
+       const char *fi_wsi_name;        /**< NULL, or Fault Injection inheritence filter for wsi=string/ context faults */
+} lws_adopt_desc_t;
+
+/**
+* lws_adopt_descriptor_vhost_via_info() - adopt foreign socket or file descriptor
+* if socket descriptor, should already have been accepted from listen socket
+*
+* \param info: the struct containing the parameters
+*
+*  - vh: lws vhost
+*  - type: OR-ed combinations of lws_adoption_type flags
+*  - fd: union with either .sockfd or .filefd set
+*  - vh_prot_name: NULL or vh protocol name to bind raw connection to
+*  - parent: NULL or struct lws to attach new_wsi to as a child
+*  - opaque: opaque pointer to set on created wsi
+*
+* Either returns new wsi bound to accept_fd, or closes accept_fd and
+* returns NULL, having cleaned up any new wsi pieces.
+*
+* If LWS_ADOPT_SOCKET is set, LWS adopts the socket in http serving mode, it's
+* ready to accept an upgrade to ws or just serve http.
+*
+* parent may be NULL, if given it should be an existing wsi that will become the
+* parent of the new wsi created by this call.
+*/
+LWS_VISIBLE LWS_EXTERN struct lws *
+lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info);
+
 /**
  * lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it
  * for the default vhost of context.
@@ -165,21 +233,39 @@ lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
                               lws_sockfd_type accept_fd, const char *readbuf,
                               size_t len);
 
-#define LWS_CAUDP_BIND 1
+#define LWS_CAUDP_BIND (1 << 0)
+#define LWS_CAUDP_BROADCAST (1 << 1)
+#define LWS_CAUDP_PF_PACKET (1 << 2)
 
+#if defined(LWS_WITH_UDP)
 /**
  * lws_create_adopt_udp() - create, bind and adopt a UDP socket
  *
  * \param vhost:        lws vhost
+ * \param ads:          NULL or address to do dns lookup on
  * \param port:                 UDP port to bind to, -1 means unbound
  * \param flags:        0 or LWS_CAUDP_NO_BIND
  * \param protocol_name: Name of protocol on vhost to bind wsi to
+ * \param ifname:       NULL, for network interface name to bind socket to
  * \param parent_wsi:   NULL or parent wsi new wsi will be a child of
+ * \param opaque:       set created wsi opaque ptr to this
+ * \param retry_policy:         NULL for vhost default policy else wsi specific policy
+ * \param fi_wsi_name:  NULL, or string to inherit Fault Injection rules in
+ *                      form "wsi=string/rule".  "wsi/rule" faults will be
+ *                      automatically applied as well.  It's done at creation
+ *                      time so the rules can, eg, inject faults related to
+ *                      creation.
  *
  * Either returns new wsi bound to accept_fd, or closes accept_fd and
  * returns NULL, having cleaned up any new wsi pieces.
  * */
 LWS_VISIBLE LWS_EXTERN struct lws *
-lws_create_adopt_udp(struct lws_vhost *vhost, int port, int flags,
-                    const char *protocol_name, struct lws *parent_wsi);
+lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
+                    int flags, const char *protocol_name, const char *ifname,
+                    struct lws *parent_wsi, void *opaque,
+                    const lws_retry_bo_t *retry_policy, const char *fi_wsi_name);
+#endif
+
+
+
 ///@}
diff --git a/include/libwebsockets/lws-async-dns.h b/include/libwebsockets/lws-async-dns.h
new file mode 100644 (file)
index 0000000..dc8b417
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if defined(LWS_WITH_UDP)
+
+typedef enum dns_query_type {
+       LWS_ADNS_RECORD_A                                       = 0x01,
+       LWS_ADNS_RECORD_CNAME                                   = 0x05,
+       LWS_ADNS_RECORD_MX                                      = 0x0f,
+       LWS_ADNS_RECORD_AAAA                                    = 0x1c,
+} adns_query_type_t;
+
+typedef enum {
+       LADNS_RET_FAILED_WSI_CLOSED                             = -4,
+       LADNS_RET_NXDOMAIN                                      = -3,
+       LADNS_RET_TIMEDOUT                                      = -2,
+       LADNS_RET_FAILED                                        = -1,
+       LADNS_RET_FOUND,
+       LADNS_RET_CONTINUING
+} lws_async_dns_retcode_t;
+
+struct addrinfo;
+
+typedef struct lws * (*lws_async_dns_cb_t)(struct lws *wsi, const char *ads,
+               const struct addrinfo *result, int n, void *opaque);
+
+/**
+ * lws_async_dns_query() - perform a dns lookup using async dns
+ *
+ * \param context: the lws_context
+ * \param tsi: thread service index (usually 0)
+ * \param name: DNS name to look up
+ * \param qtype: type of query (A, AAAA etc)
+ * \param cb: query completion callback
+ * \param wsi: wsi if the query is related to one
+ *
+ * Starts an asynchronous DNS lookup, on completion the \p cb callback will
+ * be called.
+ *
+ * The reference count on the cached object is incremented for every callback
+ * that was called with the cached addrinfo results.
+ *
+ * The cached object can't be evicted until the reference count reaches zero...
+ * use lws_async_dns_freeaddrinfo() to indicate you're finsihed with the
+ * results for each callback that happened with them.
+ */
+LWS_VISIBLE LWS_EXTERN lws_async_dns_retcode_t
+lws_async_dns_query(struct lws_context *context, int tsi, const char *name,
+                   adns_query_type_t qtype, lws_async_dns_cb_t cb,
+                   struct lws *wsi, void *opaque);
+
+/**
+ * lws_async_dns_freeaddrinfo() - decrement refcount on cached addrinfo results
+ *
+ * \param pai: a pointert to a pointer to first addrinfo returned as result in the callback
+ *
+ * Decrements the cache object's reference count.  When it reaches zero, the
+ * cached object may be reaped subject to LRU rules.
+ *
+ * The pointer to the first addrinfo give in the argument is set to NULL.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_async_dns_freeaddrinfo(const struct addrinfo **ai);
+
+#endif
diff --git a/include/libwebsockets/lws-bb-i2c.h b/include/libwebsockets/lws-bb-i2c.h
new file mode 100644 (file)
index 0000000..bd9718e
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * I2C - bitbanged generic gpio implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is like an abstract class for gpio, a real implementation provides
+ * functions for the ops that use the underlying OS gpio arrangements.
+ */
+
+typedef struct lws_bb_i2c {
+       lws_i2c_ops_t           bb_ops; /* init to lws_bb_i2c_ops */
+
+       /* implementation-specific members */
+
+       _lws_plat_gpio_t        scl;
+       _lws_plat_gpio_t        sda;
+
+       const lws_gpio_ops_t    *gpio;
+       void (*delay)(void);
+} lws_bb_i2c_t;
+
+#define lws_bb_i2c_ops \
+       { \
+               .init = lws_bb_i2c_init, \
+               .start = lws_bb_i2c_start, \
+               .stop = lws_bb_i2c_stop, \
+               .write = lws_bb_i2c_write, \
+               .read = lws_bb_i2c_read, \
+               .set_ack = lws_bb_i2c_set_ack, \
+       }
+
+int
+lws_bb_i2c_init(const lws_i2c_ops_t *octx);
+
+int
+lws_bb_i2c_start(const lws_i2c_ops_t *octx);
+
+void
+lws_bb_i2c_stop(const lws_i2c_ops_t *octx);
+
+int
+lws_bb_i2c_write(const lws_i2c_ops_t *octx, uint8_t data);
+
+int
+lws_bb_i2c_read(const lws_i2c_ops_t *octx);
+
+void
+lws_bb_i2c_set_ack(const lws_i2c_ops_t *octx, int ack);
diff --git a/include/libwebsockets/lws-bb-spi.h b/include/libwebsockets/lws-bb-spi.h
new file mode 100644 (file)
index 0000000..52c801c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * I2C - bitbanged generic gpio implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is like an abstract class for gpio, a real implementation provides
+ * functions for the ops that use the underlying OS gpio arrangements.
+ */
+
+#define LWSBBSPI_FLAG_USE_NCMD3                (1 << 7)
+#define LWSBBSPI_FLAG_USE_NCMD2                (1 << 6)
+#define LWSBBSPI_FLAG_USE_NCMD1                (1 << 5)
+#define LWSBBSPI_FLAG_USE_NCMD0                (1 << 4)
+#define LWSBBSPI_FLAG_USE_NCS3         (1 << 3)
+#define LWSBBSPI_FLAG_USE_NCS2         (1 << 2)
+#define LWSBBSPI_FLAG_USE_NCS1         (1 << 1)
+#define LWSBBSPI_FLAG_USE_NCS0         (1 << 0)
+
+#define LWS_SPI_BB_MAX_CH              4
+
+typedef struct lws_bb_spi {
+       lws_spi_ops_t           bb_ops; /* init to lws_bb_spi_ops */
+
+       /* implementation-specific members */
+       const lws_gpio_ops_t    *gpio;
+
+       _lws_plat_gpio_t        clk;
+       _lws_plat_gpio_t        ncs[LWS_SPI_BB_MAX_CH];
+       _lws_plat_gpio_t        ncmd[LWS_SPI_BB_MAX_CH];
+       _lws_plat_gpio_t        mosi;
+       _lws_plat_gpio_t        miso;
+
+       uint8_t                 flags;
+} lws_bb_spi_t;
+
+#define lws_bb_spi_ops \
+               .init           = lws_bb_spi_init, \
+               .queue          = lws_bb_spi_queue
+
+int
+lws_bb_spi_init(const lws_spi_ops_t *octx);
+
+int
+lws_bb_spi_queue(const lws_spi_ops_t *octx, const lws_spi_desc_t *desc);
diff --git a/include/libwebsockets/lws-button.h b/include/libwebsockets/lws-button.h
new file mode 100644 (file)
index 0000000..e198142
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Generic button ops
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Leverages the lws generic gpio pieces to bind gpio buttons to smd events
+ */
+
+#if !defined(__LWS_BUTTON_H__)
+#define __LWS_BUTTON_H__
+
+typedef uint16_t lws_button_idx_t;
+
+/* actual minimum may be 1 x RTOS tick depending on platform */
+#define LWS_BUTTON_MON_TIMER_MS 5
+
+typedef void (*lws_button_cb_t)(void *opaque, lws_button_idx_t idx, int state);
+
+/* These are specified in ms but the granularity is LWS_BUTTON_MON_TIMER_MS,
+ * which may have been rounded up to an RTOS tick depending on platform */
+
+enum {
+       LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK = (1 << 0)
+};
+
+typedef struct lws_button_regime {
+       uint16_t                        ms_min_down;
+       uint16_t                        ms_min_down_longpress;
+       uint16_t                        ms_up_settle;
+       uint16_t                        ms_doubleclick_grace;
+       uint16_t                        ms_repeat_down;
+       uint8_t                         flags;
+       /**< when double-click classification is enabled, clicks are delayed
+        * by ms_min_down + ms_doubleclick_grace to wait and see if it will
+        * become a double-click.  Set LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK to
+        * enable it or leave that bit at 0 to get faster single-click
+        * classification.
+        */
+} lws_button_regime_t;
+
+/*
+ * This is the const part of the button controller, describing the static
+ * bindings to gpio, and lws_smd event name information
+ */
+
+typedef struct lws_button_map {
+       _lws_plat_gpio_t                gpio;
+       const char                      *smd_interaction_name;
+       const lws_button_regime_t       *regime;
+       /**< a default regime is applied if this is left NULL */
+} lws_button_map_t;
+
+typedef struct lws_button_controller {
+       const char                      *smd_bc_name;
+       const lws_gpio_ops_t            *gpio_ops;
+       const lws_button_map_t          *button_map;
+       lws_button_idx_t                active_state_bitmap;
+       uint8_t                         count_buttons;
+} lws_button_controller_t;
+
+struct lws_button_state; /* opaque */
+
+/**
+ * lws_button_controller_create() - instantiate a button controller
+ *
+ * \param ctx: the lws_context
+ * \param controller: the static controller definition
+ *
+ * Instantiates a button controller from a static definition of the buttons
+ * and their smd names, and active levels, and binds it to a gpio implementation
+ */
+
+LWS_VISIBLE LWS_EXTERN struct lws_button_state *
+lws_button_controller_create(struct lws_context *ctx,
+                            const lws_button_controller_t *controller);
+
+/**
+ * lws_button_controller_destroy() - destroys a button controller
+ *
+ * \param bcs: button controller state previously created
+ *
+ * Disables all buttons and then destroys and frees a previously created
+ * button controller.
+ */
+
+LWS_VISIBLE LWS_EXTERN void
+lws_button_controller_destroy(struct lws_button_state *bcs);
+
+
+LWS_VISIBLE LWS_EXTERN lws_button_idx_t
+lws_button_get_bit(struct lws_button_state *bcs, const char *name);
+
+/*
+ * lws_button_enable() - enable and disable buttons
+ */
+
+LWS_VISIBLE LWS_EXTERN void
+lws_button_enable(struct lws_button_state *bcs,
+                 lws_button_idx_t _reset, lws_button_idx_t _set);
+
+#endif
+
diff --git a/include/libwebsockets/lws-cache-ttl.h b/include/libwebsockets/lws-cache-ttl.h
new file mode 100644 (file)
index 0000000..9942dc7
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** \defgroup lws_cache_ttl Cache supporting expiry
+ * ##Cache supporting expiry
+ *
+ * These apis let you quickly and reliably implement caches of named objects,
+ * that have a "destroy-by date" and cache limits that will be observed.
+ *
+ * You can instantiate as many caches as you need.  The first one must be an
+ * L1 / heap cache type, it can have parents and grandparents of other types
+ * which are accessible why writing / looking up and getting from the L1 cache.
+ * The outer "cache" layer may persistently store items to a backing store.
+ *
+ * Allocated object memory is entirely for the use of user code, up to the
+ * requested size.
+ *
+ * The key name for the listed objects may be any string chosen by the user,
+ * there is no special length limit as it is also allocated.
+ *
+ * Both expiry and LRU orderings are kept so it is easy to find out usage
+ * ordering and when the next object that will expire.
+ *
+ * Cached objects may be destroyed any time you go around the event loop, when
+ * you allocate new objects (to keep the whole cache under the specified limit),
+ * or when their expiry time arrives.  So you shouldn't keep copies of pointers
+ * to cached objects after returning to the event loop.
+ */
+///@{
+
+
+struct lws_cache_ttl_lru;
+
+/**
+ * lws_cache_write_through() - add a new cache item object in all layers
+ *
+ * \param cache: the existing cache to allocate the object in
+ * \param specific_key: a key string that identifies the item in the cache
+ * \param source: optional payload for the cached item, NULL means caller will
+ *               write the payload
+ * \param size: the size of the object to allocate
+ * \param expiry: the usec time that the object will autodestroy
+ * \param ppay: NULL, or a pointer to a void * to be set to the L1 payload
+ *
+ * If an item with the key already exists, it is destroyed before allocating a
+ * new one.
+ *
+ * Returns 0 if successful.  The written entry will be scheduled to be auto-
+ * destroyed when \p expiry occurs.
+ *
+ * Adding or removing cache items may cause invalidation of cached queries.
+ */
+LWS_VISIBLE LWS_EXTERN int /* only valid until return to event loop */
+lws_cache_write_through(struct lws_cache_ttl_lru *cache,
+                       const char *specific_key, const uint8_t *source,
+                       size_t size, lws_usec_t expiry, void **ppay);
+
+typedef struct lws_cache_match {
+       lws_dll2_t                      list;
+       lws_usec_t                      expiry;
+       /* earliest expiry amongst results */
+       size_t                          payload_size;
+       /**< the payload is not attached here.  This is a hint about what
+        * (*get)() will return for this tag name.
+        */
+       size_t                          tag_size;
+
+       /* tag name + NUL is overcommitted */
+} lws_cache_match_t;
+
+/**
+ * lws_cache_heap_lookup() - get a list of matching items
+ *
+ * \param cache: the cache to search for the key
+ * \param wildcard_key: the item key string, may contain wildcards
+ * \param pdata: pointer to pointer to be set to the serialized result list
+ * \param psize: pointer to size_t to receive length of serialized result list
+ *
+ * This finds all unique items in the final cache that match search_key, which
+ * may contain wildcards.  It does not return the payloads for matching items,
+ * just a list of specific tags in the that match.
+ *
+ * If successful, results are provided in a serialized list format, in no
+ * particular order, each result has the following fields
+ *
+ * - BE32: payload size in bytes (payload itself is not included)
+ * - BE32: specific tag name length in bytes
+ * - chars: tag name with terminating NUL
+ *
+ * These serialized results are themselves cached in L1 cache (only) and the
+ * result pointers are set pointing into that.  If the results are still in L1
+ * cache next time this api is called, the results will be returned directly
+ * from that without repeating the expensive lookup on the backup store.  That
+ * is why the results are provided in serialized form.
+ *
+ * The cached results list expiry is set to the earliest expiry of any listed
+ * item.  Additionally any cached results are invalidated on addition or
+ * deletion (update is done as addition + deletion) of any item that would
+ * match the results' original wildcard_key.  For the typical case new items
+ * are rare compared to lookups, this is efficient.
+ *
+ * Lookup matching does not itself affect LRU or cache status of the result
+ * itsems.  Typically user code will get the lookup results, and then perform
+ * get operations on each item in its desired order, that will bring the items
+ * to the head of the LRU list and occupy L1 cache.
+ *
+ * Returns 0 if proceeded alright, or nonzero if error.  If there was an error,
+ * any partial results set has been deallocated cleanly before returning.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_cache_lookup(struct lws_cache_ttl_lru *cache, const char *wildcard_key,
+                const void **pdata, size_t *psize);
+
+/**
+ * lws_cache_item_get() - bring a specific item into L1 and get payload info
+ *
+ * \param cache: the cache to search for the key
+ * \param specific_key: the key string of the item to get
+ * \param pdata: pointer to a void * to be set to the payload in L1 cache
+ * \param psize: pointer to a size_t to be set to the payload size
+ *
+ * If the cache still has an item matching the key string, it will be destroyed.
+ *
+ * Adding or removing cache items may cause invalidation of cached queries.
+ *
+ * Notice the cache payload is a blob of the given size.  If you are storing
+ * strings, there is no NUL termination unless you stored them with it.
+ *
+ * Returns 0 if successful.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_cache_item_get(struct lws_cache_ttl_lru *cache, const char *specific_key,
+                  const void **pdata, size_t *psize);
+
+/**
+ * lws_cache_item_remove() - remove item from all cache levels
+ *
+ * \param cache: the cache to search for the key
+ * \param wildcard_key: the item key string
+ *
+ * Removes any copy of any item matching the \p wildcard_key from any cache
+ * level in one step.
+ *
+ * Adding or removing cache items may cause invalidation of cached queries
+ * that could refer to the removed item.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_cache_item_remove(struct lws_cache_ttl_lru *cache, const char *wildcard_key);
+
+/**
+ * lws_cache_footprint() - query the amount of storage used by the cache layer
+ *
+ * \param cache: cache to query
+ *
+ * Returns number of payload bytes stored in cache currently
+ */
+LWS_VISIBLE LWS_EXTERN uint64_t
+lws_cache_footprint(struct lws_cache_ttl_lru *cache);
+
+/**
+ * lws_cache_debug_dump() - if built in debug mode dump cache contents to log
+ *
+ * \param cache: cache to dump
+ *
+ * If lws was built in debug mode, dump cache to log, otherwise a NOP.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_cache_debug_dump(struct lws_cache_ttl_lru *cache);
+
+typedef struct lws_cache_results {
+       const uint8_t           *ptr; /* set before using walk api */
+       size_t                  size; /* set before using walk api */
+
+       size_t                  payload_len;
+       size_t                  tag_len;
+       const uint8_t           *tag;
+} lws_cache_results_t;
+
+/**
+ * lws_cache_results_walk() - parse next result
+ *
+ * \param walk_ctx: the context of the results blob to walk
+ *
+ * Caller must initialize \p walk_ctx.ptr and \p walk_ctx.size before calling.
+ * These are set to the results returned from a _lookup api call.
+ *
+ * The call returns 0 if the struct elements have been set to a result, or 1
+ * if there where no more results in the blob to walk.
+ *
+ * If successful, after the call \p payload_len is set to the length of the
+ * payload related to this result key (the payload itself is not present),
+ * \p tag_len is set to the length of the result key name, and \p tag is set
+ * to the result tag name, with a terminating NUL.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_cache_results_walk(lws_cache_results_t *walk_ctx);
+
+typedef void (*lws_cache_item_destroy_cb)(void *item, size_t size);
+struct lws_cache_creation_info {
+       struct lws_context              *cx;
+       /**< Mandatory: the lws_context */
+       const char                      *name;
+       /**< Mandatory: short cache name */
+       lws_cache_item_destroy_cb       cb;
+       /**< NULL, or a callback that can hook cache item destory */
+       struct lws_cache_ttl_lru        *parent;
+       /**< NULL, or next cache level */
+       const struct lws_cache_ops      *ops;
+       /**< NULL for default, heap-based ops, else custom cache storage and
+        * query implementation */
+
+       union {
+               struct {
+                       const char      *filepath;
+                       /**< the filepath to store items in */
+               } nscookiejar;
+       } u;
+       /**< these are extra configuration for specific cache types */
+
+       size_t                          max_footprint;
+       /**< 0, or the max heap allocation allowed before destroying
+        *   lru items to keep it under the limit */
+       size_t                          max_items;
+       /**< 0, or the max number of items allowed in the cache before
+        *   destroying lru items to keep it under the limit */
+       size_t                          max_payload;
+       /**< 0, or the max allowed payload size for one item */
+       int                             tsi;
+       /**< 0 unless using SMP, then tsi to bind sul to */
+};
+
+struct lws_cache_ops {
+       struct lws_cache_ttl_lru *
+       (*create)(const struct lws_cache_creation_info *info);
+       /**< create an instance of the cache type specified in info */
+
+       void
+       (*destroy)(struct lws_cache_ttl_lru **_cache);
+       /**< destroy the logical cache instance pointed to by *_cache, doesn't
+        * affect any NV backing storage */
+
+       int
+       (*expunge)(struct lws_cache_ttl_lru *cache);
+       /**< completely delete any backing storage related to the cache
+        * instance, eg, delete the backing file */
+
+       int
+       (*write)(struct lws_cache_ttl_lru *cache, const char *specific_key,
+                const uint8_t *source, size_t size, lws_usec_t expiry,
+                void **ppvoid);
+       /**< create an entry in the cache level according to the given info */
+       int
+       (*tag_match)(struct lws_cache_ttl_lru *cache, const char *wc,
+                    const char *tag, char lookup_rules);
+       /**< Just tell us if tag would match wildcard, using whatever special
+        * rules the backing store might use for tag matching.  0 indicates
+        * it is a match on wildcard, nonzero means does not match.
+        */
+       int
+       (*lookup)(struct lws_cache_ttl_lru *cache, const char *wildcard_key,
+                     lws_dll2_owner_t *results_owner);
+       /**+ add keys for search_key matches not already listed in the results
+        * owner */
+       int
+       (*invalidate)(struct lws_cache_ttl_lru *cache, const char *wildcard_key);
+       /**< remove matching item(s) from cache level */
+
+       int
+       (*get)(struct lws_cache_ttl_lru *cache, const char *specific_key,
+              const void **pdata, size_t *psize);
+       /**< if it has the item, fills L1 with item. updates LRU, and returns
+        * pointer to payload in L1 */
+
+       void
+       (*debug_dump)(struct lws_cache_ttl_lru *cache);
+       /**< Helper to dump the whole cache contents to log, useful for debug */
+};
+
+/**
+ * lws_cache_create() - create an empty cache you can allocate items in
+ *
+ * \param info: a struct describing the cache to create
+ *
+ * Create an empty cache you can allocate items in.  The cache will be kept
+ * below the max_footprint and max_items limits if they are nonzero, by
+ * destroying least-recently-used items until it remains below the limits.
+ *
+ * Items will auto-destroy when their expiry time is reached.
+ *
+ * When items are destroyed from the cache, if \p cb is non-NULL, it will be
+ * called back with the item pointer after it has been removed from the cache,
+ * but before it is deallocated and destroyed.
+ *
+ * context and tsi are used when scheduling expiry callbacks
+ */
+LWS_VISIBLE LWS_EXTERN struct lws_cache_ttl_lru *
+lws_cache_create(const struct lws_cache_creation_info *info);
+
+/**
+ * lws_cache_destroy() - destroy a previously created cache
+ *
+ * \param cache: pointer to the cache
+ *
+ * Everything in the cache is destroyed, then the cache itself is destroyed,
+ * and *cache set to NULL.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_cache_destroy(struct lws_cache_ttl_lru **cache);
+
+/**
+ * lws_cache_expunge() - destroy all items in cache and parents
+ *
+ * \param cache: pointer to the cache
+ *
+ * Everything in the cache and parents is destroyed, leaving it empty.
+ * If the cache has a backing store, it is deleted.
+ *
+ * Returns 0 if no problems reported at any cache layer, else nonzero.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_cache_expunge(struct lws_cache_ttl_lru *cache);
+
+LWS_VISIBLE extern const struct lws_cache_ops lws_cache_ops_heap,
+                                             lws_cache_ops_nscookiejar;
+
+///@}
+
index 691f783..62848fa 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup usercb User Callback
@@ -61,6 +62,7 @@ enum {
        LWS_TLS_REQ_ELEMENT_LOCALITY,
        LWS_TLS_REQ_ELEMENT_ORGANIZATION,
        LWS_TLS_REQ_ELEMENT_COMMON_NAME,
+       LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME,
        LWS_TLS_REQ_ELEMENT_EMAIL,
 
        LWS_TLS_REQ_ELEMENT_COUNT,
@@ -79,6 +81,17 @@ struct lws_acme_cert_aging_args {
 };
 
 /*
+ * With LWS_CALLBACK_FILTER_NETWORK_CONNECTION callback, user_data pointer
+ * points to one of these
+ */
+
+struct lws_filter_network_conn_args {
+       struct sockaddr_storage         cli_addr;
+       socklen_t                       clilen;
+       lws_sockfd_type                 accept_fd;
+};
+
+/*
  * NOTE: These public enums are part of the abi.  If you want to add one,
  * add it at where specified so existing users are unaffected.
  */
@@ -105,6 +118,9 @@ enum lws_callback_reasons {
        LWS_CALLBACK_WSI_DESTROY                                = 30,
        /**< outermost (latest) wsi destroy notification to protocols[0] */
 
+       LWS_CALLBACK_WSI_TX_CREDIT_GET                          = 103,
+       /**< manually-managed connection received TX credit (len is int32) */
+
 
        /* ---------------------------------------------------------------------
         * ----- Callbacks related to Server TLS -----
@@ -278,6 +294,15 @@ enum lws_callback_reasons {
         *          break;
         */
 
+       LWS_CALLBACK_VERIFY_BASIC_AUTHORIZATION = 102,
+       /**< This gives the user code a chance to accept or reject credentials
+        * provided HTTP to basic authorization. It will only be called if the
+        * http mount's authentication_mode is set to LWSAUTHM_BASIC_AUTH_CALLBACK
+        * `in` points to a credential string of the form `username:password` If
+        * the callback returns zero (the default if unhandled), then the
+        * transaction ends with HTTP_STATUS_UNAUTHORIZED, otherwise the request
+        * will be processed */
+
        LWS_CALLBACK_CHECK_ACCESS_RIGHTS                        = 51,
        /**< This gives the user code a chance to forbid an http access.
         * `in` points to a `struct lws_process_html_args`, which
@@ -376,6 +401,9 @@ enum lws_callback_reasons {
         * lws know by calling lws_client_http_body_pending(wsi, 0)
         */
 
+       LWS_CALLBACK_CLIENT_HTTP_REDIRECT                       = 104,
+       /**< we're handling a 3xx redirect... return nonzero to hang up */
+
        LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL                  = 85,
        LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL                  = 76,
 
@@ -564,9 +592,17 @@ enum lws_callback_reasons {
        /**< called when a client connects to
         * the server at network level; the connection is accepted but then
         * passed to this callback to decide whether to hang up immediately
-        * or not, based on the client IP.  in contains the connection
-        * socket's descriptor. Since the client connection information is
-        * not available yet, wsi still pointing to the main server socket.
+        * or not, based on the client IP.
+        *
+        * user_data in the callback points to a
+        * struct lws_filter_network_conn_args that is prepared with the
+        * sockfd, and the peer's address information.
+        *
+        * in contains the connection socket's descriptor.
+        *
+        * Since the client connection information is not available yet,
+        * wsi still pointing to the main server socket.
+        *
         * Return non-zero to terminate the connection before sending or
         * receiving anything. Because this happens immediately after the
         * network connection from the client, there's no websocket protocol
@@ -790,6 +826,15 @@ enum lws_callback_reasons {
         * destroyed.  in is the child wsi.
         */
 
+       LWS_CALLBACK_CONNECTING                                 = 105,
+       /**< Called before a socketfd is about to connect().  In is the
+        * socketfd, cast to a (void *), if on a platform where the socketfd
+        * is an int, recover portably using (lws_sockfd_type)(intptr_t)in.
+        *
+        * It's also called in SOCKS5 or http_proxy cases where the socketfd is
+        * going to try to connect to its proxy.
+        */
+
        /* ---------------------------------------------------------------------
         * ----- Callbacks related to TLS certificate management -----
         */
@@ -813,6 +858,35 @@ enum lws_callback_reasons {
         * and failure.  in points to optional JSON, and len represents the
         * connection state using enum lws_cert_update_state */
 
+       /* ---------------------------------------------------------------------
+        * ----- Callbacks related to MQTT Client  -----
+        */
+
+       LWS_CALLBACK_MQTT_NEW_CLIENT_INSTANTIATED               = 200,
+       LWS_CALLBACK_MQTT_IDLE                                  = 201,
+       LWS_CALLBACK_MQTT_CLIENT_ESTABLISHED                    = 202,
+       LWS_CALLBACK_MQTT_SUBSCRIBED                            = 203,
+       LWS_CALLBACK_MQTT_CLIENT_WRITEABLE                      = 204,
+       LWS_CALLBACK_MQTT_CLIENT_RX                             = 205,
+       LWS_CALLBACK_MQTT_UNSUBSCRIBED                          = 206,
+       LWS_CALLBACK_MQTT_DROP_PROTOCOL                         = 207,
+       LWS_CALLBACK_MQTT_CLIENT_CLOSED                         = 208,
+       LWS_CALLBACK_MQTT_ACK                                   = 209,
+       /**< When a message is fully sent, if QoS0 this callback is generated
+        * to locally "acknowledge" it.  For QoS1, this callback is only
+        * generated when the matching PUBACK is received.  Return nonzero to
+        * close the wsi.
+        */
+       LWS_CALLBACK_MQTT_RESEND                                = 210,
+       /**< In QoS1 or QoS2, this callback is generated instead of the _ACK one
+        * if we timed out waiting for a PUBACK or a PUBREC, and we must resend
+        * the message.  Return nonzero to close the wsi.
+        */
+       LWS_CALLBACK_MQTT_UNSUBSCRIBE_TIMEOUT                   = 211,
+       /**< When a UNSUBSCRIBE is sent, this callback is generated instead of
+        * the _UNSUBSCRIBED one if we timed out waiting for a UNSUBACK.
+        * Return nonzero to close the wsi.
+        */
 
        /****** add new things just above ---^ ******/
 
index 7a5eca2..fe42fd8 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup cgi cgi handling
index 2f1a2df..bb5f2d0 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup client Client related functions
@@ -39,6 +40,14 @@ enum lws_client_connect_ssl_connection_flags {
        LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK  = (1 << 2),
        LCCSCF_ALLOW_EXPIRED                    = (1 << 3),
        LCCSCF_ALLOW_INSECURE                   = (1 << 4),
+       LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM      = (1 << 5),
+       LCCSCF_H2_QUIRK_OVERFLOWS_TXCR          = (1 << 6),
+       LCCSCF_H2_AUTH_BEARER                   = (1 << 7),
+       LCCSCF_H2_HEXIFY_AUTH_TOKEN             = (1 << 8),
+       LCCSCF_H2_MANUAL_RXFLOW                 = (1 << 9),
+       LCCSCF_HTTP_MULTIPART_MIME              = (1 << 10),
+       LCCSCF_HTTP_X_WWW_FORM_URLENCODED       = (1 << 11),
+       LCCSCF_HTTP_NO_FOLLOW_REDIRECT          = (1 << 12),
 
        LCCSCF_PIPELINE                         = (1 << 16),
                /**< Serialize / pipeline multiple client connections
@@ -47,7 +56,49 @@ enum lws_client_connect_ssl_connection_flags {
                 * HTTP/1.0: possible if Keep-Alive: yes sent by server
                 * HTTP/1.1: always possible... uses pipelining
                 * HTTP/2:   always possible... uses parallel streams
-                * */
+                */
+       LCCSCF_MUXABLE_STREAM                   = (1 << 17),
+       LCCSCF_H2_PRIOR_KNOWLEDGE               = (1 << 18),
+       LCCSCF_WAKE_SUSPEND__VALIDITY           = (1 << 19),
+       /* our validity checks are important enough to wake from suspend */
+       LCCSCF_PRIORITIZE_READS                 = (1 << 20),
+       /**<
+        * Normally lws balances reads and writes on all connections, so both
+        * are possible even on busy connections, and we go around the event
+        * loop more often to facilitate that, even if there is pending data.
+        *
+        * This flag indicates that you want to handle any pending reads on this
+        * connection without yielding the service loop for anything else.  This
+        * means you may block other connection processing in favour of incoming
+        * data processing on this one if it receives back to back incoming rx.
+        */
+       LCCSCF_SECSTREAM_CLIENT                 = (1 << 21),
+       /**< used to mark client wsi as bound to secure stream */
+       LCCSCF_SECSTREAM_PROXY_LINK             = (1 << 22),
+       /**< client is a link between SS client and SS proxy */
+       LCCSCF_SECSTREAM_PROXY_ONWARD           = (1 << 23),
+       /**< client the SS proxy's onward connection */
+
+       LCCSCF_IP_LOW_LATENCY                   = (1 << 24),
+       /**< set the "low delay" bit on the IP packets of this connection */
+       LCCSCF_IP_HIGH_THROUGHPUT               = (1 << 25),
+       /**< set the "high throughput" bit on the IP packets of this
+        *   connection */
+       LCCSCF_IP_HIGH_RELIABILITY              = (1 << 26),
+       /**< set the "high reliability" bit on the IP packets of this
+        *   connection */
+       LCCSCF_IP_LOW_COST                      = (1 << 27),
+       /**< set the "minimize monetary cost" bit on the IP packets of this
+        *   connection */
+       LCCSCF_CONMON                           = (1 << 28),
+       /**< If LWS_WITH_CONMON enabled for build, keeps a copy of the
+        * getaddrinfo results so they can be queried subsequently */
+       LCCSCF_ACCEPT_TLS_DOWNGRADE_REDIRECTS   = (1 << 29),
+       /**< By default lws rejects https redirecting to http.  Set this
+        * flag on the client connection to allow it. */
+       LCCSCF_CACHE_COOKIES                    = (1 << 30),
+       /**< If built with -DLWS_WITH_CACHE_NSCOOKIEJAR, store and reapply
+        * http cookies in a Netscape Cookie Jar on this connection */
 };
 
 /** struct lws_client_connect_info - parameters to connect with when using
@@ -63,7 +114,8 @@ struct lws_client_connect_info {
        int ssl_connection;
        /**< 0, or a combination of LCCSCF_ flags */
        const char *path;
-       /**< uri path */
+       /**< URI path. Prefix with + for a UNIX socket. (+@ for
+     * a Linux abstract-namespace socket) */
        const char *host;
        /**< content of host header */
        const char *origin;
@@ -120,7 +172,7 @@ struct lws_client_connect_info {
         *           tokens
         */
 
-       lws_seq_t *seq;
+       struct lws_sequencer *seq;
        /**< NULL, or an lws_seq_t that wants to be given messages about
         * this wsi's lifecycle as it connects, errors or closes.
         */
@@ -132,6 +184,57 @@ struct lws_client_connect_info {
         *   an lws_seq_t.
         */
 
+       const lws_retry_bo_t *retry_and_idle_policy;
+       /**< optional retry and idle policy to apply to this connection.
+        *   Currently only the idle parts are applied to the connection.
+        */
+
+       int             manual_initial_tx_credit;
+       /**< if LCCSCF_H2_MANUAL_REFLOW is set, this becomes the initial tx
+        * credit for the stream.
+        */
+
+       uint8_t         sys_tls_client_cert;
+       /**< 0 means no client cert.  1+ means apply lws_system client cert 0+
+        * to the client connection.
+        */
+
+       uint8_t         priority;
+       /**< 0 means normal priority... otherwise sets the IP priority on
+        * packets coming from this connection, from 1 - 7.  Setting 7
+        * (network management priority) requires CAP_NET_ADMIN capability but
+        * the others can be set by anyone.
+        */
+
+#if defined(LWS_ROLE_MQTT)
+       const lws_mqtt_client_connect_param_t *mqtt_cp;
+#else
+       void            *mqtt_cp;
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_ctx_t                            fic;
+       /**< Attach external Fault Injection context to the client wsi,
+        * hierarchy is wsi -> vhost -> context */
+#endif
+       /* for convenience, available when FI disabled in build */
+       const char                              *fi_wsi_name;
+       /**< specific Fault Injection namespace name for wsi created for this
+        * connection, allows targeting by "wsi=XXX/..." if you give XXX here.
+        */
+
+       uint16_t                                keep_warm_secs;
+       /**< 0 means 5s.  If the client connection to the endpoint becomes idle,
+        * defer closing it for this many seconds in case another outgoing
+        * connection to the same endpoint turns up.
+        */
+
+       lws_log_cx_t                            *log_cx;
+       /**< NULL to use lws_context log context, else a pointer to a log
+        * context template to take a copy of for this wsi.  Used to isolate
+        * wsi-specific logs into their own stream or file.
+        */
+
        /* Add new things just above here ---^
         * This is part of the ABI, don't needlessly break compatibility
         *
@@ -210,6 +313,7 @@ lws_http_client_read(struct lws *wsi, char **buf, int *len);
  * \param wsi: client connection
  *
  * Returns the last server response code, eg, 200 for client http connections.
+ * If there is no valid response, it will return 0.
  *
  * You should capture this during the LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP
  * callback, because after that the memory reserved for storing the related
@@ -218,11 +322,23 @@ lws_http_client_read(struct lws *wsi, char **buf, int *len);
 LWS_VISIBLE LWS_EXTERN unsigned int
 lws_http_client_http_response(struct lws *wsi);
 
-LWS_VISIBLE LWS_EXTERN void
-lws_client_http_body_pending(struct lws *wsi, int something_left_to_send);
+/**
+ * lws_tls_client_vhost_extra_cert_mem() - add more certs to vh client tls ctx
+ *
+ * \param vh: the vhost to give more client certs to
+ * \param der: pointer to der format additional cert
+ * \param der_len: size in bytes of der
+ *
+ * After the vhost is created with one cert for client verification, you
+ * can add additional, eg, intermediate, certs to the client tls context
+ * of the vhost, for use with validating the incoming server cert(s).
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh,
+               const uint8_t *der, size_t der_len);
 
 /**
- * lws_client_http_body_pending() - control if client connection neeeds to send body
+ * lws_client_http_body_pending() - control if client connection needs to send body
  *
  * \param wsi: client connection
  * \param something_left_to_send: nonzero if need to send more body, 0 (default)
@@ -240,5 +356,58 @@ lws_client_http_body_pending(struct lws *wsi, int something_left_to_send);
  * if there is more to come, or lws_client_http_body_pending(wsi, 0); to
  * let lws know the last part is sent and the connection can move on.
  */
+LWS_VISIBLE LWS_EXTERN void
+lws_client_http_body_pending(struct lws *wsi, int something_left_to_send);
+
+/**
+ * lws_client_http_multipart() - issue appropriate multipart header or trailer
+ *
+ * \param wsi: client connection
+ * \param name: multipart header name field, or NULL if end of multipart
+ * \param filename: multipart header filename field, or NULL if none
+ * \param content_type: multipart header content-type part, or NULL if none
+ * \param p: pointer to position in buffer
+ * \param end: end of buffer
+ *
+ * This issues a multipart mime boundary, or terminator if name = NULL.
+ *
+ * Returns 0 if OK or nonzero if couldn't fit in buffer
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_client_http_multipart(struct lws *wsi, const char *name,
+                         const char *filename, const char *content_type,
+                         char **p, char *end);
+
+/**
+ * lws_http_basic_auth_gen() - helper to encode client basic auth string
+ *
+ * \param user: user name
+ * \param pw: password
+ * \param buf: where to store base64 result
+ * \param len: max usable size of buf
+ *
+ * Encodes a username and password in Basic Auth format for use with the
+ * Authorization header.  On return, buf is filled with something like
+ * "Basic QWxhZGRpbjpPcGVuU2VzYW1l".
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_http_basic_auth_gen(const char *user, const char *pw, char *buf, size_t len);
+
+/**
+ * lws_tls_session_is_reused() - returns nonzero if tls session was cached
+ *
+ * \param wsi: the wsi
+ *
+ * Returns zero if the tls session is fresh, else nonzero if the tls session was
+ * taken from the cache.  If lws is built with LWS_WITH_TLS_SESSIONS and the vhost
+ * was created with the option LWS_SERVER_OPTION_ENABLE_TLS_SESSION_CACHE, then
+ * on full tls session establishment of a client connection, the session is added
+ * to the tls cache.
+ *
+ * This lets you find out if your session was new (0) or from the cache (nonzero),
+ * it'a mainly useful for stats and testing.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_tls_session_is_reused(struct lws *wsi);
 
 ///@}
diff --git a/include/libwebsockets/lws-conmon.h b/include/libwebsockets/lws-conmon.h
new file mode 100644 (file)
index 0000000..12a0eec
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** \defgroup conmon Connection Latency information
+ * ## Connection Latency information
+ *
+ * When LWS_WITH_CONMON is enabled at build, collects detailed statistics
+ * about the client connection setup latency, available to the connection
+ * itself
+ */
+///@{
+
+/* enough for 4191s, or just over an hour */
+typedef uint32_t lws_conmon_interval_us_t;
+
+/*
+ * Connection latency information... note that not all wsi actually make
+ * connections, for example h2 streams after the initial one will have 0
+ * for everything except ciu_txn_resp.
+ *
+ * If represented in JSON, it should look like this
+ *
+ *     {
+ *        "peer": "46.105.127.147",
+ *        "dns_us": 1234,
+ *        "dns_disp": 1,
+ *        "sockconn_us": 1234,
+ *        "tls_us": 1234,
+ *        "txn_resp_us": 1234,
+ *        "dns":["46.105.127.147", "2001:41d0:2:ee93::1"],
+ *        "prot_specific": {
+ *             "protocol": "http",
+ *             "resp": 200
+ *        }
+ *      }
+ *
+ * The indexes in "dns_disp" are declared in lws_conmon_dns_disposition_t
+ * below.
+ *
+ * "prot_specific" may not be present if the protocol doesn't have anything
+ * to report or is not supported.
+ */
+
+typedef enum lws_conmon_pcol {
+       LWSCONMON_PCOL_NONE,
+       LWSCONMON_PCOL_HTTP, /* .protocol_specific.http is valid */
+} lws_conmon_pcol_t;
+
+typedef enum lws_conmon_dns_disposition {
+       LWSCONMON_DNS_NONE,
+       /**< did not attempt DNS */
+       LWSCONMON_DNS_OK                                = 1,
+       /**< DNS lookup did give results */
+       LWSCONMON_DNS_SERVER_UNREACHABLE                = 2,
+       /**< DNS server was not reachable */
+       LWSCONMON_DNS_NO_RESULT                         = 3
+       /**< DNS server replied but nothing usable */
+} lws_conmon_dns_disposition_t;
+
+struct lws_conmon {
+       lws_sockaddr46                          peer46;
+       /**< The peer we actually connected to, if any.  .peer46.sa4.sa_family
+        * is either 0 if invalid, or the AF_ */
+
+       union {
+               struct {
+                       int     response;
+                       /**< h1 http response code */
+               } http;
+       } protocol_specific;
+       /**< possibly-present protocol-specific additional information.  This
+        * is only valid for the first transaction after connection and does
+        * not capture results for persistent or muxed connections like ws
+        * messages, mqtt messages, or h2 streams */
+
+       struct addrinfo                         *dns_results_copy;
+       /**< NULL, or Allocated copy of dns results, owned by this object and
+        * freed when object destroyed.
+        * Only set if client flag LCCSCF_CONMON applied  */
+
+       lws_conmon_interval_us_t                ciu_dns;
+       /**< 0, or if a socket connection, us taken to acquire this DNS response
+        *
+        */
+       lws_conmon_interval_us_t                ciu_sockconn;
+       /**< 0, or if connection-based, the us interval between the socket
+        * connect() attempt that succeeded, and the connection setup */
+       lws_conmon_interval_us_t                ciu_tls;
+       /**< 0 if no tls, or us taken to establish the tls tunnel */
+       lws_conmon_interval_us_t                ciu_txn_resp;
+       /**< 0, or if the protocol supports transactions, the interval between
+        * sending the initial transaction request and starting to receive the
+        * response */
+
+       lws_conmon_pcol_t                       pcol;
+       /**< indicates which extra protocol_specific info member is valid,
+        *   if any */
+
+       lws_conmon_dns_disposition_t            dns_disposition;
+       /**< indicates general disposition of DNS request */
+};
+
+/**
+ * lws_conmon_wsi_take() - create a connection latency object from client wsi
+ *
+ * \param context: lws wsi
+ * \param dest: conmon struct to fill
+ *
+ * Copies wsi conmon data into the caller's struct.  Passes ownership of
+ * any allocations in the addrinfo list to the caller, lws will not delete that
+ * any more on wsi close after this call.  The caller must call
+ * lws_conmon_release() on the struct to destroy any addrinfo in the struct
+ * that is prepared by this eventually but it can defer it as long as it wants.
+ *
+ * Other than the addrinfo list, the contents of the returned object are
+ * completely selfcontained and don't point outside of the object itself, ie,
+ * everything else in there remains in scope while the object itself does.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_conmon_wsi_take(struct lws *wsi, struct lws_conmon *dest);
+
+/**
+ * lws_conmon_release() - free any allocations in the conmon struct
+ *
+ * \param conmon: pointer to conmon struct
+ *
+ * Destroys any allocations in the conmon struct so it can go out of scope.
+ * It doesn't free \p dest itself, it's designed to clean out a struct that
+ * is on the stack or embedded in another object.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_conmon_release(struct lws_conmon *conmon);
+
+///@}
index bf4710b..b3de140 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup context-and-vhost context and vhost related functions
  * add it at where specified so existing users are unaffected.
  */
 
-/** enum lws_context_options - context and vhost options */
-enum lws_context_options {
-       LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT     = (1 << 1) |
-                                                                 (1 << 12),
+
+#define LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT     ((1ll << 1) | \
+                                                                 (1ll << 12))
        /**< (VH) Don't allow the connection unless the client has a
         * client cert that we recognize; provides
         * LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT */
-       LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME            = (1 << 2),
+#define LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME             (1ll << 2)
        /**< (CTX) Don't try to get the server's hostname */
-       LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT             = (1 << 3) |
-                                                                 (1 << 12),
+#define LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT             ((1ll << 3) | \
+                                                                 (1ll << 12))
        /**< (VH) Allow non-SSL (plaintext) connections on the same
         * port as SSL is listening.  If combined with
         * LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS it will try to
         * force http connections on an https listener (eg, http://x.com:443) to
         * redirect to an explicit https connection (eg, https://x.com)
         */
-       LWS_SERVER_OPTION_LIBEV                                 = (1 << 4),
+#define LWS_SERVER_OPTION_LIBEV                                         (1ll << 4)
        /**< (CTX) Use libev event loop */
-       LWS_SERVER_OPTION_DISABLE_IPV6                          = (1 << 5),
+#define LWS_SERVER_OPTION_DISABLE_IPV6                          (1ll << 5)
        /**< (VH) Disable IPV6 support */
-       LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS                   = (1 << 6),
+#define LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS                   (1ll << 6)
        /**< (VH) Don't load OS CA certs, you will need to load your
         * own CA cert(s) */
-       LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED                = (1 << 7),
+#define LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED                (1ll << 7)
        /**< (VH) Accept connections with no valid Cert (eg, selfsigned) */
-       LWS_SERVER_OPTION_VALIDATE_UTF8                         = (1 << 8),
+#define LWS_SERVER_OPTION_VALIDATE_UTF8                                 (1ll << 8)
        /**< (VH) Check UT-8 correctness */
-       LWS_SERVER_OPTION_SSL_ECDH                              = (1 << 9) |
-                                                                 (1 << 12),
+#define LWS_SERVER_OPTION_SSL_ECDH                              ((1ll << 9) | \
+                                                                 (1ll << 12))
        /**< (VH)  initialize ECDH ciphers */
-       LWS_SERVER_OPTION_LIBUV                                 = (1 << 10),
+#define LWS_SERVER_OPTION_LIBUV                                        (1ll << 10)
        /**< (CTX)  Use libuv event loop */
-       LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS                = (1 << 11) |
-                                                                 (1 << 12),
+#define LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS               ((1ll << 11) |\
+                                                                (1ll << 12))
        /**< (VH) Use an http redirect to force the client to ask for https.
         * Notice if your http server issues the STS header and the client has
         * ever seen that, the client will fail the http connection before it
@@ -85,35 +85,35 @@ enum lws_context_options {
         * http://x.com:443 -> https://x.com
         *
         * (deprecated: use mount redirection) */
-       LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT                    = (1 << 12),
+#define LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT                    (1ll << 12)
        /**< (CTX) Initialize the SSL library at all */
-       LWS_SERVER_OPTION_EXPLICIT_VHOSTS                       = (1 << 13),
+#define LWS_SERVER_OPTION_EXPLICIT_VHOSTS                       (1ll << 13)
        /**< (CTX) Only create the context when calling context
         * create api, implies user code will create its own vhosts */
-       LWS_SERVER_OPTION_UNIX_SOCK                             = (1 << 14),
+#define LWS_SERVER_OPTION_UNIX_SOCK                             (1ll << 14)
        /**< (VH) Use Unix socket */
-       LWS_SERVER_OPTION_STS                                   = (1 << 15),
+#define LWS_SERVER_OPTION_STS                                   (1ll << 15)
        /**< (VH) Send Strict Transport Security header, making
         * clients subsequently go to https even if user asked for http */
-       LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY                    = (1 << 16),
+#define LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY                    (1ll << 16)
        /**< (VH) Enable LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE to take effect */
-       LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE                     = (1 << 17),
+#define LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE                     (1ll << 17)
        /**< (VH) if set, only ipv6 allowed on the vhost */
-       LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN             = (1 << 18),
+#define LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN             (1ll << 18)
        /**< (CTX) Libuv only: Do not spin on SIGSEGV / SIGFPE.  A segfault
         * normally makes the lib spin so you can attach a debugger to it
         * even if it happened without a debugger in place.  You can disable
         * that by giving this option.
         */
-       LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN                   = (1 << 19),
+#define LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN                   (1ll << 19)
        /**< For backwards-compatibility reasons, by default
         * lws prepends "http://" to the origin you give in the client
         * connection info struct.  If you give this flag when you create
         * the context, only the string you give in the client connect
         * info for .origin (if any) will be used directly.
         */
-       LWS_SERVER_OPTION_FALLBACK_TO_RAW /* use below name */  = (1 << 20),
-       LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG= (1 << 20),
+#define LWS_SERVER_OPTION_FALLBACK_TO_RAW /* use below name */  (1ll << 20)
+#define LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG (1ll << 20)
        /**< (VH) if invalid http is coming in the first line, then abandon
         * trying to treat the connection as http, and belatedly apply the
         * .listen_accept_role / .listen_accept_protocol info struct members to
@@ -126,11 +126,11 @@ enum lws_context_options {
         * to work with a socket listening with tls.
         */
 
-       LWS_SERVER_OPTION_LIBEVENT                              = (1 << 21),
+#define LWS_SERVER_OPTION_LIBEVENT                             (1ll << 21)
        /**< (CTX) Use libevent event loop */
 
-       LWS_SERVER_OPTION_ONLY_RAW /* Use below name instead */ = (1 << 22),
-       LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG      = (1 << 22),
+#define LWS_SERVER_OPTION_ONLY_RAW /* Use below name instead */        (1ll << 22)
+#define LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG     (1ll << 22)
        /**< (VH) All connections to this vhost / port are bound to the
         * role and protocol given in .listen_accept_role /
         * .listen_accept_protocol.
@@ -143,31 +143,31 @@ enum lws_context_options {
         * It's much preferred to specify the role + protocol using the
         * .listen_accept_role and .listen_accept_protocol in the info struct.
         */
-       LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE                    = (1 << 23),
+#define LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE                   (1ll << 23)
        /**< (VH) Set to allow multiple listen sockets on one interface +
         * address + port.  The default is to strictly allow only one
         * listen socket at a time.  This is automatically selected if you
         * have multiple service threads.  Linux only.
         */
-       LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX                  = (1 << 24),
+#define LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX                 (1ll << 24)
        /**< (VH) Force setting up the vhost SSL_CTX, even though the user
         * code doesn't explicitly provide a cert in the info struct.  It
         * implies the user code is going to provide a cert at the
         * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS callback, which
         * provides the vhost SSL_CTX * in the user parameter.
         */
-       LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT                    = (1 << 25),
+#define LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT                   (1ll << 25)
        /**< (VH) You probably don't want this.  It forces this vhost to not
         * call LWS_CALLBACK_PROTOCOL_INIT on its protocols.  It's used in the
         * special case of a temporary vhost bound to a single protocol.
         */
-       LWS_SERVER_OPTION_IGNORE_MISSING_CERT                   = (1 << 26),
+#define LWS_SERVER_OPTION_IGNORE_MISSING_CERT                  (1ll << 26)
        /**< (VH) Don't fail if the vhost TLS cert or key are missing, just
         * continue.  The vhost won't be able to serve anything, but if for
         * example the ACME plugin was configured to fetch a cert, this lets
         * you bootstrap your vhost from having no cert to start with.
         */
-       LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK           = (1 << 27),
+#define LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK          (1ll << 27)
        /**< (VH) On this vhost, if the connection is being upgraded, insist
         * that there's a Host: header and that the contents match the vhost
         * name + port (443 / 80 are assumed if no :port given based on if the
@@ -178,7 +178,7 @@ enum lws_context_options {
         * allow lax hostname mappings like localhost / 127.0.0.1, and CNAME
         * mappings like www.mysite.com / mysite.com
         */
-       LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE  = (1 << 28),
+#define LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE (1ll << 28)
        /**< (VH) Send lws default HTTP headers recommended by Mozilla
         * Observatory for security.  This is a helper option that sends canned
         * headers on each http response enabling a VERY strict Content Security
@@ -195,7 +195,7 @@ enum lws_context_options {
         * yourself.
         */
 
-       LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER          = (1 << 29),
+#define LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER          (1ll << 29)
        /**< (VH) If you really want to allow HTTP connections on a tls
         * listener, you can do it with this combined with
         * LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT.  But this is allowing
@@ -203,21 +203,61 @@ enum lws_context_options {
         * on the client using http when he meant https... it's not
         * recommended.
         */
-       LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND              = (1 << 30),
+#define LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND              (1ll << 30)
        /**< (VH) When instantiating a new vhost and the specified port is
         * already in use, a null value shall be return to signal the error.
         */
 
-       LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW    = (1 << 31),
+#define LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW    (1ll << 31)
        /**< (VH) Indicates the connections using this vhost should ignore
         * h2 WINDOW_UPDATE from broken peers and fix them up */
 
+#define LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL           (1ll << 32)
+       /**< (VH) Tell the vhost to treat half-closed remote clients as
+        * entered into an immortal (ie, not subject to normal timeouts) long
+        * poll mode.
+        */
+
+#define LWS_SERVER_OPTION_GLIB                                  (1ll << 33)
+       /**< (CTX) Use glib event loop */
+
+#define LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE                    (1ll << 34)
+       /**< (VH) Tell the vhost to treat plain text http connections as
+        * H2 with prior knowledge (no upgrade request involved)
+        */
+
+#define LWS_SERVER_OPTION_NO_LWS_SYSTEM_STATES                  (1ll << 35)
+       /**< (CTX) Disable lws_system state, eg, because we are a secure streams
+        * proxy client that is not trying to track system state by itself. */
+
+#define LWS_SERVER_OPTION_SS_PROXY                              (1ll << 36)
+       /**< (VH) We are being a SS Proxy listen socket for the vhost */
+
+#define LWS_SERVER_OPTION_SDEVENT                               (1ll << 37)
+       /**< (CTX) Use sd-event loop */
+
+#define LWS_SERVER_OPTION_ULOOP                                         (1ll << 38)
+       /**< (CTX) Use libubox / uloop event loop */
+
+#define LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE             (1ll << 39)
+       /**< (VHOST) Disallow use of client tls caching (on by default) */
+
+
        /****** add new things just above ---^ ******/
-};
 
-#define lws_check_opt(c, f) (((c) & (f)) == (f))
+
+#define lws_check_opt(c, f) ((((uint64_t)c) & ((uint64_t)f)) == ((uint64_t)f))
 
 struct lws_plat_file_ops;
+struct lws_ss_policy;
+struct lws_ss_plugin;
+struct lws_metric_policy;
+
+typedef int (*lws_context_ready_cb_t)(struct lws_context *context);
+
+typedef int (*lws_peer_limits_notify_t)(struct lws_context *ctx,
+                                       lws_sockfd_type sockfd,
+                                       lws_sockaddr46 *sa46);
 
 /** struct lws_context_creation_info - parameters to create context and /or vhost with
  *
@@ -229,15 +269,7 @@ struct lws_plat_file_ops;
  * at the same time as the context, they are expected to be created afterwards.
  */
 struct lws_context_creation_info {
-       int port;
-       /**< VHOST: Port to listen on. Use CONTEXT_PORT_NO_LISTEN to suppress
-        * listening for a client. Use CONTEXT_PORT_NO_LISTEN_SERVER if you are
-        * writing a server but you are using \ref sock-adopt instead of the
-        * built-in listener.
-        *
-        * You can also set port to 0, in which case the kernel will pick
-        * a random port that is not already in use.  You can find out what
-        * port the vhost is listening on using lws_get_vhost_listen_port() */
+#if defined(LWS_WITH_NETWORK)
        const char *iface;
        /**< VHOST: NULL to bind the listen socket to all interfaces, or the
         * interface name, eg, "eth2"
@@ -251,12 +283,94 @@ struct lws_context_creation_info {
         * entry that has a NULL callback pointer.  SEE ALSO .pprotocols below,
         * which gives an alternative way to provide an array of pointers to
         * protocol structs. */
+#if defined(LWS_ROLE_WS)
        const struct lws_extension *extensions;
        /**< VHOST: NULL or array of lws_extension structs listing the
         * extensions this context supports. */
+#endif
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
        const struct lws_token_limits *token_limits;
        /**< CONTEXT: NULL or struct lws_token_limits pointer which is
         * initialized with a token length limit for each possible WSI_TOKEN_ */
+       const char *http_proxy_address;
+       /**< VHOST: If non-NULL, attempts to proxy via the given address.
+        * If proxy auth is required, use format
+        * "username:password\@server:port" */
+       const struct lws_protocol_vhost_options *headers;
+               /**< VHOST: pointer to optional linked list of per-vhost
+                * canned headers that are added to server responses */
+
+       const struct lws_protocol_vhost_options *reject_service_keywords;
+       /**< CONTEXT: Optional list of keywords and rejection codes + text.
+        *
+        * The keywords are checked for existing in the user agent string.
+        *
+        * Eg, "badrobot" "404 Not Found"
+        */
+       const struct lws_protocol_vhost_options *pvo;
+       /**< VHOST: pointer to optional linked list of per-vhost
+        * options made accessible to protocols */
+       const char *log_filepath;
+       /**< VHOST: filepath to append logs to... this is opened before
+        *              any dropping of initial privileges */
+       const struct lws_http_mount *mounts;
+       /**< VHOST: optional linked list of mounts for this vhost */
+       const char *server_string;
+       /**< CONTEXT: string used in HTTP headers to identify server
+        * software, if NULL, "libwebsockets". */
+
+       const char *error_document_404;
+       /**< VHOST: If non-NULL, when asked to serve a non-existent file,
+        *          lws attempts to server this url path instead.  Eg,
+        *          "/404.html" */
+       int port;
+       /**< VHOST: Port to listen on. Use CONTEXT_PORT_NO_LISTEN to suppress
+        * listening for a client. Use CONTEXT_PORT_NO_LISTEN_SERVER if you are
+        * writing a server but you are using \ref sock-adopt instead of the
+        * built-in listener.
+        *
+        * You can also set port to 0, in which case the kernel will pick
+        * a random port that is not already in use.  You can find out what
+        * port the vhost is listening on using lws_get_vhost_listen_port() */
+
+       unsigned int http_proxy_port;
+       /**< VHOST: If http_proxy_address was non-NULL, uses this port */
+       unsigned int max_http_header_data2;
+       /**< CONTEXT: if max_http_header_data is 0 and this
+        * is nonzero, this will be used in place of the default.  It's
+        * like this for compatibility with the original short version,
+        * this is unsigned int length. */
+       unsigned int max_http_header_pool2;
+       /**< CONTEXT: if max_http_header_pool is 0 and this
+        * is nonzero, this will be used in place of the default.  It's
+        * like this for compatibility with the original short version:
+        * this is unsigned int length. */
+
+       int keepalive_timeout;
+       /**< VHOST: (default = 0 = 5s, 31s for http/2) seconds to allow remote
+        * client to hold on to an idle HTTP/1.1 connection.  Timeout lifetime
+        * applied to idle h2 network connections */
+       uint32_t        http2_settings[7];
+       /**< VHOST:  if http2_settings[0] is nonzero, the values given in
+        *            http2_settings[1]..[6] are used instead of the lws
+        *            platform default values.
+        *            Just leave all at 0 if you don't care.
+        */
+
+       unsigned short max_http_header_data;
+       /**< CONTEXT: The max amount of header payload that can be handled
+        * in an http request (unrecognized header payload is dropped) */
+       unsigned short max_http_header_pool;
+       /**< CONTEXT: The max number of connections with http headers that
+        * can be processed simultaneously (the corresponding memory is
+        * allocated and deallocated dynamically as needed).  If the pool is
+        * fully busy new incoming connections must wait for accept until one
+        * becomes free. 0 = allow as many ah as number of availble fds for
+        * the process */
+
+#endif
+
+#if defined(LWS_WITH_TLS)
        const char *ssl_private_key_password;
        /**< VHOST: NULL or the passphrase needed for the private key. (For
         * backwards compatibility, this can also be used to pass the client
@@ -307,29 +421,137 @@ struct lws_context_creation_info {
         * SEE .tls1_3_plus_cipher_list and .client_tls_1_3_plus_cipher_list
         * for the equivalent for tls1.3.
         */
-       const char *http_proxy_address;
-       /**< VHOST: If non-NULL, attempts to proxy via the given address.
-        * If proxy auth is required, use format
-        * "username:password\@server:port" */
-       unsigned int http_proxy_port;
-       /**< VHOST: If http_proxy_address was non-NULL, uses this port */
-       int gid;
-       /**< CONTEXT: group id to change to after setting listen socket,
-        *   or -1. See also .username below. */
-       int uid;
-       /**< CONTEXT: user id to change to after setting listen socket,
-        *   or -1.  See also .groupname below. */
-       unsigned int options;
-       /**< VHOST + CONTEXT: 0, or LWS_SERVER_OPTION_... bitfields */
-       void *user;
-       /**< VHOST + CONTEXT: optional user pointer that will be associated
-        * with the context when creating the context (and can be retrieved by
-        * lws_context_user(context), or with the vhost when creating the vhost
-        * (and can be retrieved by lws_vhost_user(vhost)).  You will need to
-        * use LWS_SERVER_OPTION_EXPLICIT_VHOSTS and create the vhost separately
-        * if you care about giving the context and vhost different user pointer
-        * values.
+       const char *ecdh_curve;
+       /**< VHOST: if NULL, defaults to initializing server with
+        *   "prime256v1" */
+       const char *tls1_3_plus_cipher_list;
+       /**< VHOST: List of valid ciphers to use for incoming server connections
+        * ON TLS1.3 AND ABOVE (eg, "TLS_CHACHA20_POLY1305_SHA256" on this vhost
+        * or you can leave it as NULL to get "DEFAULT".
+        * SEE .client_tls_1_3_plus_cipher_list to do the same on the vhost
+        * client SSL_CTX.
         */
+
+       const void *server_ssl_cert_mem;
+       /**< VHOST: Alternative for \p ssl_cert_filepath that allows setting
+        * from memory instead of from a file.  At most one of
+        * \p ssl_cert_filepath or \p server_ssl_cert_mem should be non-NULL. */
+       const void *server_ssl_private_key_mem;
+       /**<  VHOST: Alternative for \p ssl_private_key_filepath allowing
+        * init from a private key in memory instead of a file.  At most one
+        * of \p ssl_private_key_filepath or \p server_ssl_private_key_mem
+        * should be non-NULL. */
+       const void *server_ssl_ca_mem;
+       /**< VHOST: Alternative for \p ssl_ca_filepath allowing
+        * init from a CA cert in memory instead of a file.  At most one
+        * of \p ssl_ca_filepath or \p server_ssl_ca_mem should be non-NULL. */
+
+       long ssl_options_set;
+       /**< VHOST: Any bits set here will be set as server SSL options */
+       long ssl_options_clear;
+       /**< VHOST: Any bits set here will be cleared as server SSL options */
+       int simultaneous_ssl_restriction;
+       /**< CONTEXT: 0 (no limit) or limit of simultaneous SSL sessions
+        * possible.*/
+       int simultaneous_ssl_handshake_restriction;
+       /**< CONTEXT: 0 (no limit) or limit of simultaneous SSL handshakes ongoing */
+       int ssl_info_event_mask;
+       /**< VHOST: mask of ssl events to be reported on LWS_CALLBACK_SSL_INFO
+        * callback for connections on this vhost.  The mask values are of
+        * the form SSL_CB_ALERT, defined in openssl/ssl.h.  The default of
+        * 0 means no info events will be reported.
+        */
+       unsigned int server_ssl_cert_mem_len;
+       /**< VHOST: Server SSL context init: length of server_ssl_cert_mem in
+        * bytes */
+       unsigned int server_ssl_private_key_mem_len;
+       /**< VHOST: length of \p server_ssl_private_key_mem in memory */
+       unsigned int server_ssl_ca_mem_len;
+       /**< VHOST: length of \p server_ssl_ca_mem in memory */
+
+       const char *alpn;
+       /**< CONTEXT: If non-NULL, default list of advertised alpn, comma-
+        *            separated
+        *
+        *     VHOST: If non-NULL, per-vhost list of advertised alpn, comma-
+        *            separated
+        */
+
+
+#if defined(LWS_WITH_CLIENT)
+       const char *client_ssl_private_key_password;
+       /**< VHOST: Client SSL context init: NULL or the passphrase needed
+        * for the private key */
+       const char *client_ssl_cert_filepath;
+       /**< VHOST: Client SSL context init: The certificate the client
+        * should present to the peer on connection */
+       const void *client_ssl_cert_mem;
+       /**< VHOST: Client SSL context init: client certificate memory buffer or
+        * NULL... use this to load client cert from memory instead of file */
+       unsigned int client_ssl_cert_mem_len;
+       /**< VHOST: Client SSL context init: length of client_ssl_cert_mem in
+        * bytes */
+       const char *client_ssl_private_key_filepath;
+       /**<  VHOST: Client SSL context init: filepath to client private key
+        * if this is set to NULL but client_ssl_cert_filepath is set, you
+        * can handle the LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS
+        * callback of protocols[0] to allow setting of the private key directly
+        * via tls library calls */
+       const void *client_ssl_key_mem;
+       /**< VHOST: Client SSL context init: client key memory buffer or
+        * NULL... use this to load client key from memory instead of file */
+       const char *client_ssl_ca_filepath;
+       /**< VHOST: Client SSL context init: CA certificate filepath or NULL */
+       const void *client_ssl_ca_mem;
+       /**< VHOST: Client SSL context init: CA certificate memory buffer or
+        * NULL... use this to load CA cert from memory instead of file */
+
+       const char *client_ssl_cipher_list;
+       /**< VHOST: Client SSL context init: List of valid ciphers to use (eg,
+       * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"
+       * or you can leave it as NULL to get "DEFAULT" */
+       const char *client_tls_1_3_plus_cipher_list;
+       /**< VHOST: List of valid ciphers to use for outgoing client connections
+        * ON TLS1.3 AND ABOVE on this vhost (eg,
+        * "TLS_CHACHA20_POLY1305_SHA256") or you can leave it as NULL to get
+        * "DEFAULT".
+        */
+
+       long ssl_client_options_set;
+       /**< VHOST: Any bits set here will be set as CLIENT SSL options */
+       long ssl_client_options_clear;
+       /**< VHOST: Any bits set here will be cleared as CLIENT SSL options */
+
+
+       unsigned int client_ssl_ca_mem_len;
+       /**< VHOST: Client SSL context init: length of client_ssl_ca_mem in
+        * bytes */
+       unsigned int client_ssl_key_mem_len;
+       /**< VHOST: Client SSL context init: length of client_ssl_key_mem in
+        * bytes */
+
+#endif
+
+#if !defined(LWS_WITH_MBEDTLS)
+       SSL_CTX *provided_client_ssl_ctx;
+       /**< CONTEXT: If non-null, swap out libwebsockets ssl
+         * implementation for the one provided by provided_ssl_ctx.
+         * Libwebsockets no longer is responsible for freeing the context
+         * if this option is selected. */
+#else /* WITH_MBEDTLS */
+       const char *mbedtls_client_preload_filepath;
+       /**< CONTEXT: If NULL, no effect.  Otherwise it should point to a
+        * filepath where every created client SSL_CTX is preloaded from the
+        * system trust bundle.
+        *
+        * This sets a processwide variable that affects all contexts.
+        *
+        * Requires that the mbedtls provides mbedtls_x509_crt_parse_file(),
+        * else disabled.
+        */
+#endif
+#endif
+
        int ka_time;
        /**< CONTEXT: 0 for no TCP keepalive, otherwise apply this keepalive
         * timeout to all libwebsocket sockets, client or server */
@@ -340,27 +562,57 @@ struct lws_context_creation_info {
        int ka_interval;
        /**< CONTEXT: if ka_time was nonzero, how long to wait before each ka_probes
         * attempt */
-#if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
-       SSL_CTX *provided_client_ssl_ctx;
-       /**< CONTEXT: If non-null, swap out libwebsockets ssl
-         * implementation for the one provided by provided_ssl_ctx.
-         * Libwebsockets no longer is responsible for freeing the context
-         * if this option is selected. */
-#else /* maintain structure layout either way */
-       void *provided_client_ssl_ctx; /**< dummy if ssl disabled */
-#endif
+       unsigned int timeout_secs;
+       /**< VHOST: various processes involving network roundtrips in the
+        * library are protected from hanging forever by timeouts.  If
+        * nonzero, this member lets you set the timeout used in seconds.
+        * Otherwise a default timeout is used. */
+       unsigned int connect_timeout_secs;
+       /**< VHOST: client connections have this long to find a working server
+        * from the DNS results, or the whole connection times out.  If zero,
+        * a default timeout is used */
+       int bind_iface;
+       /**< VHOST: nonzero to strictly bind sockets to the interface name in
+        * .iface (eg, "eth2"), using SO_BIND_TO_DEVICE.
+        *
+        * Requires SO_BINDTODEVICE support from your OS and CAP_NET_RAW
+        * capability.
+        *
+        * Notice that common things like access network interface IP from
+        * your local machine use your lo / loopback interface and will be
+        * disallowed by this.
+        */
+       unsigned int timeout_secs_ah_idle;
+       /**< VHOST: seconds to allow a client to hold an ah without using it.
+        * 0 defaults to 10s. */
+#endif /* WITH_NETWORK */
 
-       unsigned short max_http_header_data;
-       /**< CONTEXT: The max amount of header payload that can be handled
-        * in an http request (unrecognized header payload is dropped) */
-       unsigned short max_http_header_pool;
-       /**< CONTEXT: The max number of connections with http headers that
-        * can be processed simultaneously (the corresponding memory is
-        * allocated and deallocated dynamically as needed).  If the pool is
-        * fully busy new incoming connections must wait for accept until one
-        * becomes free. 0 = allow as many ah as number of availble fds for
-        * the process */
+#if defined(LWS_WITH_TLS_SESSIONS)
+       uint32_t                        tls_session_timeout;
+       /**< VHOST: seconds until timeout/ttl for newly created sessions.
+        * 0 means default timeout (defined per protocol, usually 300s). */
+       uint32_t                        tls_session_cache_max;
+       /**< VHOST: 0 for default limit of 10, or the maximum number of
+        * client tls sessions we are willing to cache */
+#endif
 
+       gid_t gid;
+       /**< CONTEXT: group id to change to after setting listen socket,
+        *   or -1. See also .username below. */
+       uid_t uid;
+       /**< CONTEXT: user id to change to after setting listen socket,
+        *   or -1.  See also .groupname below. */
+       uint64_t options;
+       /**< VHOST + CONTEXT: 0, or LWS_SERVER_OPTION_... bitfields */
+       void *user;
+       /**< VHOST + CONTEXT: optional user pointer that will be associated
+        * with the context when creating the context (and can be retrieved by
+        * lws_context_user(context), or with the vhost when creating the vhost
+        * (and can be retrieved by lws_vhost_user(vhost)).  You will need to
+        * use LWS_SERVER_OPTION_EXPLICIT_VHOSTS and create the vhost separately
+        * if you care about giving the context and vhost different user pointer
+        * values.
+        */
        unsigned int count_threads;
        /**< CONTEXT: how many contexts to create in an array, 0 = 1 */
        unsigned int fd_limit_per_thread;
@@ -379,73 +631,18 @@ struct lws_context_creation_info {
         * cancel pipe, so you may need to allow for some extras for normal
         * operation.
         */
-       unsigned int timeout_secs;
-       /**< VHOST: various processes involving network roundtrips in the
-        * library are protected from hanging forever by timeouts.  If
-        * nonzero, this member lets you set the timeout used in seconds.
-        * Otherwise a default timeout is used. */
-       const char *ecdh_curve;
-       /**< VHOST: if NULL, defaults to initializing server with
-        *   "prime256v1" */
        const char *vhost_name;
        /**< VHOST: name of vhost, must match external DNS name used to
         * access the site, like "warmcat.com" as it's used to match
-        * Host: header and / or SNI name for SSL. */
+        * Host: header and / or SNI name for SSL.
+        * CONTEXT: NULL, or the name to associate with the context for
+        * context-specific logging
+        */
+#if defined(LWS_WITH_PLUGINS)
        const char * const *plugin_dirs;
        /**< CONTEXT: NULL, or NULL-terminated array of directories to
         * scan for lws protocol plugins at context creation time */
-       const struct lws_protocol_vhost_options *pvo;
-       /**< VHOST: pointer to optional linked list of per-vhost
-        * options made accessible to protocols */
-       int keepalive_timeout;
-       /**< VHOST: (default = 0 = 5s) seconds to allow remote
-        * client to hold on to an idle HTTP/1.1 connection */
-       const char *log_filepath;
-       /**< VHOST: filepath to append logs to... this is opened before
-        *              any dropping of initial privileges */
-       const struct lws_http_mount *mounts;
-       /**< VHOST: optional linked list of mounts for this vhost */
-       const char *server_string;
-       /**< CONTEXT: string used in HTTP headers to identify server
- *             software, if NULL, "libwebsockets". */
-       unsigned int pt_serv_buf_size;
-       /**< CONTEXT: 0 = default of 4096.  This buffer is used by
-        * various service related features including file serving, it
-        * defines the max chunk of file that can be sent at once.
-        * At the risk of lws having to buffer failed large sends, it
-        * can be increased to, eg, 128KiB to improve throughput. */
-       unsigned int max_http_header_data2;
-       /**< CONTEXT: if max_http_header_data is 0 and this
-        * is nonzero, this will be used in place of the default.  It's
-        * like this for compatibility with the original short version,
-        * this is unsigned int length. */
-       long ssl_options_set;
-       /**< VHOST: Any bits set here will be set as server SSL options */
-       long ssl_options_clear;
-       /**< VHOST: Any bits set here will be cleared as server SSL options */
-       unsigned short ws_ping_pong_interval;
-       /**< CONTEXT: 0 for none, else interval in seconds between sending
-        * PINGs on idle websocket connections.  When the PING is sent,
-        * the PONG must come within the normal timeout_secs timeout period
-        * or the connection will be dropped.
-        * Any RX or TX traffic on the connection restarts the interval timer,
-        * so a connection which always sends or receives something at intervals
-        * less than the interval given here will never send PINGs / expect
-        * PONGs.  Conversely as soon as the ws connection is established, an
-        * idle connection will do the PING / PONG roundtrip as soon as
-        * ws_ping_pong_interval seconds has passed without traffic
-        */
-       const struct lws_protocol_vhost_options *headers;
-               /**< VHOST: pointer to optional linked list of per-vhost
-                * canned headers that are added to server responses */
-
-       const struct lws_protocol_vhost_options *reject_service_keywords;
-       /**< CONTEXT: Optional list of keywords and rejection codes + text.
-        *
-        * The keywords are checked for existing in the user agent string.
-        *
-        * Eg, "badrobot" "404 Not Found"
-        */
+#endif
        void *external_baggage_free_on_destroy;
        /**< CONTEXT: NULL, or pointer to something externally malloc'd, that
         * should be freed when the context is destroyed.  This allows you to
@@ -454,38 +651,14 @@ struct lws_context_creation_info {
         * succeeded to create.
         */
 
-       const char *client_ssl_private_key_password;
-       /**< VHOST: Client SSL context init: NULL or the passphrase needed
-        * for the private key */
-       const char *client_ssl_cert_filepath;
-       /**< VHOST: Client SSL context init: The certificate the client
-        * should present to the peer on connection */
-       const void *client_ssl_cert_mem;
-       /**< VHOST: Client SSL context init: client certificate memory buffer or
-        * NULL... use this to load client cert from memory instead of file */
-       unsigned int client_ssl_cert_mem_len;
-       /**< VHOST: Client SSL context init: length of client_ssl_cert_mem in
-        * bytes */
-       const char *client_ssl_private_key_filepath;
-       /**<  VHOST: Client SSL context init: filepath to client private key
-        * if this is set to NULL but client_ssl_cert_filepath is set, you
-        * can handle the LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS
-        * callback of protocols[0] to allow setting of the private key directly
-        * via tls library calls */
-       const char *client_ssl_ca_filepath;
-       /**< VHOST: Client SSL context init: CA certificate filepath or NULL */
-       const void *client_ssl_ca_mem;
-       /**< VHOST: Client SSL context init: CA certificate memory buffer or
-        * NULL... use this to load CA cert from memory instead of file */
-       unsigned int client_ssl_ca_mem_len;
-       /**< VHOST: Client SSL context init: length of client_ssl_ca_mem in
-        * bytes */
-
-       const char *client_ssl_cipher_list;
-       /**< VHOST: Client SSL context init: List of valid ciphers to use (eg,
-       * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"
-       * or you can leave it as NULL to get "DEFAULT" */
 
+       unsigned int pt_serv_buf_size;
+       /**< CONTEXT: 0 = default of 4096.  This buffer is used by
+        * various service related features including file serving, it
+        * defines the max chunk of file that can be sent at once.
+        * At the risk of lws having to buffer failed large sends, it
+        * can be increased to, eg, 128KiB to improve throughput. */
+#if defined(LWS_WITH_FILE_OPS)
        const struct lws_plat_file_ops *fops;
        /**< CONTEXT: NULL, or pointer to an array of fops structs, terminated
         * by a sentinel with NULL .open.
@@ -493,15 +666,19 @@ struct lws_context_creation_info {
         * If NULL, lws provides just the platform file operations struct for
         * backwards compatibility.
         */
-       int simultaneous_ssl_restriction;
-       /**< CONTEXT: 0 (no limit) or limit of simultaneous SSL sessions
-        * possible.*/
+#endif
+
+#if defined(LWS_WITH_SOCKS5)
        const char *socks_proxy_address;
        /**< VHOST: If non-NULL, attempts to proxy via the given address.
         * If proxy auth is required, use format
         * "username:password\@server:port" */
        unsigned int socks_proxy_port;
-       /**< VHOST: If socks_proxy_address was non-NULL, uses this port */
+       /**< VHOST: If socks_proxy_address was non-NULL, uses this port
+        * if nonzero, otherwise requires "server:port" in .socks_proxy_address
+        */
+#endif
+
 #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
        cap_value_t caps[4];
        /**< CONTEXT: array holding Linux capabilities you want to
@@ -514,58 +691,6 @@ struct lws_context_creation_info {
        /**< CONTEXT: count of Linux capabilities in .caps[].  0 means
         * no capabilities will be inherited from root (the default) */
 #endif
-       int bind_iface;
-       /**< VHOST: nonzero to strictly bind sockets to the interface name in
-        * .iface (eg, "eth2"), using SO_BIND_TO_DEVICE.
-        *
-        * Requires SO_BINDTODEVICE support from your OS and CAP_NET_RAW
-        * capability.
-        *
-        * Notice that common things like access network interface IP from
-        * your local machine use your lo / loopback interface and will be
-        * disallowed by this.
-        */
-       int ssl_info_event_mask;
-       /**< VHOST: mask of ssl events to be reported on LWS_CALLBACK_SSL_INFO
-        * callback for connections on this vhost.  The mask values are of
-        * the form SSL_CB_ALERT, defined in openssl/ssl.h.  The default of
-        * 0 means no info events will be reported.
-        */
-       unsigned int timeout_secs_ah_idle;
-       /**< VHOST: seconds to allow a client to hold an ah without using it.
-        * 0 defaults to 10s. */
-       unsigned short ip_limit_ah;
-       /**< CONTEXT: max number of ah a single IP may use simultaneously
-        *            0 is no limit. This is a soft limit: if the limit is
-        *            reached, connections from that IP will wait in the ah
-        *            waiting list and not be able to acquire an ah until
-        *            a connection belonging to the IP relinquishes one it
-        *            already has.
-        */
-       unsigned short ip_limit_wsi;
-       /**< CONTEXT: max number of wsi a single IP may use simultaneously.
-        *            0 is no limit.  This is a hard limit, connections from
-        *            the same IP will simply be dropped once it acquires the
-        *            amount of simultaneous wsi / accepted connections
-        *            given here.
-        */
-       uint32_t        http2_settings[7];
-       /**< VHOST:  if http2_settings[0] is nonzero, the values given in
-        *            http2_settings[1]..[6] are used instead of the lws
-        *            platform default values.
-        *            Just leave all at 0 if you don't care.
-        */
-       const char *error_document_404;
-       /**< VHOST: If non-NULL, when asked to serve a non-existent file,
-        *          lws attempts to server this url path instead.  Eg,
-        *          "/404.html" */
-       const char *alpn;
-       /**< CONTEXT: If non-NULL, default list of advertised alpn, comma-
-        *            separated
-        *
-        *     VHOST: If non-NULL, per-vhost list of advertised alpn, comma-
-        *            separated
-        */
        void **foreign_loops;
        /**< CONTEXT: This is ignored if the context is not being started with
         *              an event loop, ie, .options has a flag like
@@ -601,30 +726,6 @@ struct lws_context_creation_info {
        /**< VHOST: opaque pointer lws ignores but passes to the finalize
         *          callback.  If you don't care, leave it NULL.
         */
-       unsigned int max_http_header_pool2;
-       /**< CONTEXT: if max_http_header_pool is 0 and this
-        * is nonzero, this will be used in place of the default.  It's
-        * like this for compatibility with the original short version:
-        * this is unsigned int length. */
-
-       long ssl_client_options_set;
-       /**< VHOST: Any bits set here will be set as CLIENT SSL options */
-       long ssl_client_options_clear;
-       /**< VHOST: Any bits set here will be cleared as CLIENT SSL options */
-
-       const char *tls1_3_plus_cipher_list;
-       /**< VHOST: List of valid ciphers to use for incoming server connections
-        * ON TLS1.3 AND ABOVE (eg, "TLS_CHACHA20_POLY1305_SHA256" on this vhost
-        * or you can leave it as NULL to get "DEFAULT".
-        * SEE .client_tls_1_3_plus_cipher_list to do the same on the vhost
-        * client SSL_CTX.
-        */
-       const char *client_tls_1_3_plus_cipher_list;
-       /**< VHOST: List of valid ciphers to use for outgoing client connections
-        * ON TLS1.3 AND ABOVE on this vhost (eg,
-        * "TLS_CHACHA20_POLY1305_SHA256") or you can leave it as NULL to get
-        * "DEFAULT".
-        */
        const char *listen_accept_role;
        /**< VHOST: NULL for default, or force accepted incoming connections to
         * bind to this role.  Uses the role names from their ops struct, eg,
@@ -645,26 +746,6 @@ struct lws_context_creation_info {
         * the type of the user data to be known so its size can be given.
         */
 
-       const void *server_ssl_cert_mem;
-       /**< VHOST: Alternative for \p ssl_cert_filepath that allows setting
-        * from memory instead of from a file.  At most one of
-        * \p ssl_cert_filepath or \p server_ssl_cert_mem should be non-NULL. */
-       unsigned int server_ssl_cert_mem_len;
-       /**< VHOST: Server SSL context init: length of server_ssl_cert_mem in
-        * bytes */
-       const void *server_ssl_private_key_mem;
-       /**<  VHOST: Alternative for \p ssl_private_key_filepath allowing
-        * init from a private key in memory instead of a file.  At most one
-        * of \p ssl_private_key_filepath or \p server_ssl_private_key_mem
-        * should be non-NULL. */
-       unsigned int server_ssl_private_key_mem_len;
-       /**< VHOST: length of \p server_ssl_private_key_mem in memory */
-       const void *server_ssl_ca_mem;
-       /**< VHOST: Alternative for \p ssl_ca_filepath allowing
-        * init from a CA cert in memory instead of a file.  At most one
-        * of \p ssl_ca_filepath or \p server_ssl_ca_mem should be non-NULL. */
-       unsigned int server_ssl_ca_mem_len;
-       /**< VHOST: length of \p server_ssl_ca_mem in memory */
        const char *username; /**< CONTEXT: string username for post-init
         * permissions.  Like .uid but takes a string username. */
        const char *groupname; /**< CONTEXT: string groupname for post-init
@@ -676,6 +757,161 @@ struct lws_context_creation_info {
        const lws_system_ops_t *system_ops;
        /**< CONTEXT: hook up lws_system_ apis to system-specific
         * implementations */
+       const lws_retry_bo_t *retry_and_idle_policy;
+       /**< VHOST: optional retry and idle policy to apply to this vhost.
+        *   Currently only the idle parts are applied to the connections.
+        */
+#if defined(LWS_WITH_SYS_STATE)
+       lws_state_notify_link_t * const *register_notifier_list;
+       /**< CONTEXT: NULL, or pointer to an array of notifiers that should
+        * be registered during context creation, so they can see state change
+        * events from very early on.  The array should end with a NULL. */
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS)
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       const struct lws_ss_policy *pss_policies; /**< CONTEXT: point to first
+        * in a linked-list of streamtype policies prepared by user code */
+#else
+       const char *pss_policies_json; /**< CONTEXT: point to a string
+        * containing a JSON description of the secure streams policies.  Set
+        * to NULL if not using Secure Streams.
+        * If the platform supports files and the string does not begin with
+        * '{', lws treats the string as a filepath to open to get the JSON
+        * policy.
+        */
+#endif
+       const struct lws_ss_plugin **pss_plugins; /**< CONTEXT: point to an array
+        * of pointers to plugin structs here, terminated with a NULL ptr.
+        * Set to NULL if not using Secure Streams. */
+       const char *ss_proxy_bind; /**< CONTEXT: NULL, or: ss_proxy_port == 0:
+        * point to a string giving the Unix Domain Socket address to use (start
+        * with @ for abstract namespace), ss_proxy_port nonzero: set the
+        * network interface address (not name, it's ambiguous for ipv4/6) to
+        * bind the tcp connection to the proxy to */
+       const char *ss_proxy_address; /**< CONTEXT: NULL, or if ss_proxy_port
+        * nonzero: the tcp address of the ss proxy to connect to */
+       uint16_t ss_proxy_port; /* 0 = if connecting to ss proxy, do it via a
+        * Unix Domain Socket, "+@proxy.ss.lws" if ss_proxy_bind is NULL else
+        * the socket path given in ss_proxy_bind (start it with a + or +@);
+        * nonzero means connect via a tcp socket to the tcp address in
+        * ss_proxy_bind and the given port */
+#endif
+
+       int rlimit_nofile;
+       /**< 0 = inherit the initial ulimit for files / sockets from the startup
+        * environment.  Nonzero = try to set the limit for this process.
+        */
+#if defined(LWS_WITH_PEER_LIMITS)
+       lws_peer_limits_notify_t pl_notify_cb;
+       /**< CONTEXT: NULL, or a callback to receive notifications each time a
+        * connection is being dropped because of peer limits.
+        *
+        * The callback provides the context, and an lws_sockaddr46 with the
+        * peer address and port.
+        */
+       unsigned short ip_limit_ah;
+       /**< CONTEXT: max number of ah a single IP may use simultaneously
+        *            0 is no limit. This is a soft limit: if the limit is
+        *            reached, connections from that IP will wait in the ah
+        *            waiting list and not be able to acquire an ah until
+        *            a connection belonging to the IP relinquishes one it
+        *            already has.
+        */
+       unsigned short ip_limit_wsi;
+       /**< CONTEXT: max number of wsi a single IP may use simultaneously.
+        *            0 is no limit.  This is a hard limit, connections from
+        *            the same IP will simply be dropped once it acquires the
+        *            amount of simultaneous wsi / accepted connections
+        *            given here.
+        */
+
+#endif /* PEER_LIMITS */
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_ctx_t                            fic;
+       /**< CONTEXT | VHOST: attach external Fault Injection context to the
+        * lws_context or vhost.  If creating the context + default vhost in
+        * one step, only the context binds to \p fi.  When creating a vhost
+        * otherwise this can bind to the vhost so the faults can be injected
+        * from the start.
+        */
+#endif
+
+#if defined(LWS_WITH_SYS_SMD)
+       lws_smd_notification_cb_t               early_smd_cb;
+       /**< CONTEXT: NULL, or an smd notification callback that will be registered
+        * immediately after the smd in the context is initialized.  This ensures
+        * you can get all notifications without having to intercept the event loop
+        * creation, eg, when using an event library.  Other callbacks can be
+        * registered later manually without problems.
+        */
+       void                                    *early_smd_opaque;
+       lws_smd_class_t                         early_smd_class_filter;
+       lws_usec_t                              smd_ttl_us;
+       /**< CONTEXT: SMD messages older than this many us are removed from the
+        * queue and destroyed even if not fully delivered yet.  If zero,
+        * defaults to 2 seconds (5 second for FREERTOS).
+        */
+       uint16_t                                smd_queue_depth;
+       /**< CONTEXT: Maximum queue depth, If zero defaults to 40
+        * (20 for FREERTOS) */
+#endif
+
+#if defined(LWS_WITH_SYS_METRICS)
+       const struct lws_metric_policy          *metrics_policies;
+       /**< CONTEXT: non-SS policy metrics policies */
+       const char                              *metrics_prefix;
+       /**< CONTEXT: prefix for this context's metrics, used to distinguish
+        * metrics pooled from different processes / applications, so, eg what
+        * would be "cpu.svc" if this is NULL becomes "myapp.cpu.svc" is this is
+        * set to "myapp".  Policies are applied using the name with the prefix,
+        * if present.
+        */
+#endif
+
+       int                                     fo_listen_queue;
+       /**< VHOST: 0 = no TCP_FASTOPEN, nonzero = enable TCP_FASTOPEN if the
+        * platform supports it, with the given queue length for the listen
+        * socket.
+        */
+
+       const struct lws_plugin_evlib           *event_lib_custom;
+       /**< CONTEXT: If non-NULL, override event library selection so it uses
+        * this custom event library implementation, instead of default internal
+        * loop.  Don't set any other event lib context creation flags in that
+        * case. it will be used automatically.  This is useful for integration
+        * where an existing application is using its own handrolled event loop
+        * instead of an event library, it provides a way to allow lws to use
+        * the custom event loop natively as if it were an "event library".
+        */
+
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       size_t                                  jitt_cache_max_footprint;
+       /**< CONTEXT: 0 for no limit, else max bytes used by JIT Trust cache...
+        * LRU items are evicted to keep under this limit */
+       int                                     vh_idle_grace_ms;
+       /**< CONTEXT: 0 for default of 5000ms, or number of ms JIT Trust vhosts
+        * are allowed to live without active connections using them. */
+#endif
+
+       lws_log_cx_t                            *log_cx;
+       /**< CONTEXT: NULL to use the default, process-scope logging context,
+        * else a specific logging context to associate with this context */
+
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
+       const char                              *http_nsc_filepath;
+       /**< CONTEXT: Filepath to use for http netscape cookiejar file */
+
+       size_t                                  http_nsc_heap_max_footprint;
+       /**< CONTEXT: 0, or limit in bytes for heap usage of memory cookie
+        * cache */
+       size_t                                  http_nsc_heap_max_items;
+       /**< CONTEXT: 0, or the max number of items allowed in the cookie cache
+        * before destroying lru items to keep it under the limit */
+       size_t                                  http_nsc_heap_max_payload;
+       /**< CONTEXT: 0, or the maximum size of a single cookie we are able to
+        * handle */
+#endif
 
        /* Add new things just above here ---^
         * This is part of the ABI, don't needlessly break compatibility
@@ -685,7 +921,7 @@ struct lws_context_creation_info {
         * was not built against the newer headers.
         */
 
-       void *_unused[4]; /**< dummy */
+       void *_unused[2]; /**< dummy */
 };
 
 /**
@@ -979,6 +1215,27 @@ lws_vhost_user(struct lws_vhost *vhost);
 LWS_VISIBLE LWS_EXTERN void *
 lws_context_user(struct lws_context *context);
 
+LWS_VISIBLE LWS_EXTERN const char *
+lws_vh_tag(struct lws_vhost *vh);
+
+/**
+ * lws_context_is_being_destroyed() - find out if context is being destroyed
+ *
+ * \param context: the struct lws_context pointer
+ *
+ * Returns nonzero if the context has had lws_context_destroy() called on it...
+ * when using event library loops the destroy process can be asynchronous.  In
+ * the special case of libuv foreign loops, the failure to create the context
+ * may have to do work on the foreign loop to reverse the partial creation,
+ * meaning a failed context create cannot unpick what it did and return NULL.
+ *
+ * In that condition, a valid context that is already started the destroy
+ * process is returned, and this test api will return nonzero as a way to
+ * find out the create is in the middle of failing.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_context_is_being_destroyed(struct lws_context *context);
+
 /*! \defgroup vhost-mounts Vhost mounts and options
  * \ingroup context-and-vhost-creation
  *
@@ -1012,6 +1269,18 @@ enum lws_mount_protocols {
        LWSMPRO_CALLBACK        = 6, /**< hand by named protocol's callback */
 };
 
+/** enum lws_authentication_mode
+ * This specifies the authentication mode of the mount. The basic_auth_login_file mount parameter
+ * is ignored unless LWSAUTHM_DEFAULT is set.
+ */
+enum lws_authentication_mode {
+       LWSAUTHM_DEFAULT = 0, /**< default authenticate only if basic_auth_login_file is provided */
+       LWSAUTHM_BASIC_AUTH_CALLBACK = 1 << 28 /**< Basic auth with a custom verifier */
+};
+
+/** The authentication mode is stored in the top 4 bits of lws_http_mount.auth_mask */
+#define AUTH_MODE_MASK 0xF0000000
+
 /** struct lws_http_mount
  *
  * arguments for mounting something in a vhost's url namespace
@@ -1052,17 +1321,11 @@ struct lws_http_mount {
        unsigned char mountpoint_len; /**< length of mountpoint string */
 
        const char *basic_auth_login_file;
-       /**<NULL, or filepath to use to check basic auth logins against */
+       /**<NULL, or filepath to use to check basic auth logins against. (requires LWSAUTHM_DEFAULT) */
 
        /* Add new things just above here ---^
         * This is part of the ABI, don't needlessly break compatibility
-        *
-        * The below is to ensure later library versions with new
-        * members added above will see 0 (default) even if the app
-        * was not built against the newer headers.
         */
-
-       void *_unused[2]; /**< dummy */
 };
 
 ///@}
diff --git a/include/libwebsockets/lws-cose.h b/include/libwebsockets/lws-cose.h
new file mode 100644 (file)
index 0000000..1ea6791
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** \defgroup cose COSE apis
+ * ##COSE related functions
+ * \ingroup lwsaoi
+ *
+ * COSE RFC 8152 relates to signed and encrypted CBOR
+ */
+//@{
+
+enum {
+       /*  RFC8152: Table 2: Common Header Parameters
+        * https://www.iana.org/assignments/cose/cose.xhtml#header-parameters
+        */
+
+       LWSCOSE_WKL_ALG                         = 1,   /* int / tstr */
+       LWSCOSE_WKL_CRIT,                              /* [+ label ] */
+       LWSCOSE_WKL_CONTENT_TYPE,                      /* tstr / uint */
+       LWSCOSE_WKL_KID,                               /* bstr */
+       LWSCOSE_WKL_IV,                                /* bstr */
+       LWSCOSE_WKL_IV_PARTIAL,                        /* bstr */
+       LWSCOSE_WKL_COUNTERSIG,                        /* COSE sig(s) */
+       LWSCOSE_WKL_COUNTERSIG0                 = 9,   /* bstr */
+       LWSCOSE_WKL_KID_CONTEXT,                       /* bstr */
+       LWSCOSE_WKL_CUPH_NONCE                  = 256, /* bstr */
+       LWSCOSE_WKL_CUPH_OWNER_PUBKEY           = 257, /* array */
+
+       /*  RFC8152: Table 3: key map labels */
+
+       LWSCOSE_WKK_KTY                         = 1, /* int / tstr */
+       LWSCOSE_WKK_KID,                             /* bstr */
+       LWSCOSE_WKK_ALG,                             /* int / tstr */
+       LWSCOSE_WKK_KEY_OPS,                         /* [ + (int / tstr) ] */
+       LWSCOSE_WKK_BASE_IV,                         /* bstr */
+
+       /*  RFC8152: Table 4: Key Operation Values */
+
+       LWSCOSE_WKKO_SIGN                       = 1,
+       LWSCOSE_WKKO_VERIFY,
+       LWSCOSE_WKKO_ENCRYPT,
+       LWSCOSE_WKKO_DECRYPT,
+       LWSCOSE_WKKO_WRAP_KEY,
+       LWSCOSE_WKKO_UNWRAP_KEY,
+       LWSCOSE_WKKO_DERIVE_KEY,
+       LWSCOSE_WKKO_DERIVE_BITS,
+       LWSCOSE_WKKO_MAC_CREATE,
+       LWSCOSE_WKKO_MAC_VERIFY,
+
+       /*  RFC8152: Table 5: ECDSA algs */
+
+       LWSCOSE_WKAECDSA_ALG_ES256              = -7,
+       LWSCOSE_WKAECDSA_ALG_ES384              = -35,
+       LWSCOSE_WKAECDSA_ALG_ES512              = -36,
+
+       /*  RFC8152: Table 6: EDDSA algs */
+
+       LWSCOSE_WKAEDDSA_ALG_EDDSA              = -8,
+
+       /*  RFC8152: Table 7: HMAC algs */
+
+       LWSCOSE_WKAHMAC_256_64                  = 4,
+       LWSCOSE_WKAHMAC_256_256,
+       LWSCOSE_WKAHMAC_384_384,
+       LWSCOSE_WKAHMAC_512_512,
+
+       /*  RFC8152: Table 8: AES algs */
+
+       LWSCOSE_WKAAES_128_64                   = 14,
+       LWSCOSE_WKAAES_256_64,
+       LWSCOSE_WKAAES_128_128                  = 25,
+       LWSCOSE_WKAAES_256_128,
+
+       /*  RFC8152: Table 9: AES GCM algs */
+
+       LWSCOSE_WKAAESGCM_128                   = 1,
+       LWSCOSE_WKAAESGCM_192,
+       LWSCOSE_WKAAESGCM_256,
+
+       /*  RFC8152: Table 10: AES CCM algs */
+
+       LWSCOSE_WKAAESCCM_16_64_128             = 10,
+       LWSCOSE_WKAAESCCM_16_64_256,
+       LWSCOSE_WKAAESCCM_64_64_128,
+       LWSCOSE_WKAAESCCM_64_64_256,
+       LWSCOSE_WKAAESCCM_16_128_128,
+       LWSCOSE_WKAAESCCM_16_128_256,
+       LWSCOSE_WKAAESCCM_64_128_128,
+       LWSCOSE_WKAAESCCM_64_128_256,
+
+       /*  RFC8152: Table 11: CHACHA20 / Poly1305 */
+
+       LWSCOSE_WKACHACHA_POLY1305              = 24,
+
+       /*  RFC8152: Table 13: HKDF param */
+
+       LWSCOSE_WKAPHKDF_SALT                   = -20,
+
+       /* RFC8152: Table 14: Context Algorithm Parameters */
+
+       LWSCOSE_WKAPCTX_PARTY_U_IDENTITY        = -21,
+       LWSCOSE_WKAPCTX_PARTY_U_NONCE           = -22,
+       LWSCOSE_WKAPCTX_PARTY_U_OTHER           = -23,
+       LWSCOSE_WKAPCTX_PARTY_V_IDENTITY        = -24,
+       LWSCOSE_WKAPCTX_PARTY_V_NONCE           = -25,
+       LWSCOSE_WKAPCTX_PARTY_V_OTHER           = -26,
+
+       /* RFC8152: Table 15: Direct key */
+
+       LWSCOSE_WKK_DIRECT_CEK                  = -6,
+
+       /* RFC8152: Table 16: Direct key with KDF */
+
+       LWSCOSE_WKK_DIRECT_HKDF_SHA_256         = -10,
+       LWSCOSE_WKK_DIRECT_HKDF_SHA_512         = -11,
+       LWSCOSE_WKK_DIRECT_HKDF_AES_128         = -12,
+       LWSCOSE_WKK_DIRECT_HKDF_AES_256         = -13,
+
+       /* RFC8152: Table 17: AES Key Wrap Algorithm Values */
+
+       LWSCOSE_WKK_DIRECT_HKDFKW_SHA_256       = -3,
+       LWSCOSE_WKK_DIRECT_HKDFKW_SHA_512       = -4,
+       LWSCOSE_WKK_DIRECT_HKDFKW_AES_128       = -5,
+
+       /* RFC8152: Table 18: ECDH Algorithm Values */
+
+       LWSCOSE_WKAECDH_ALG_ES_HKDF_256         = -25,
+       LWSCOSE_WKAECDH_ALG_ES_HKDF_512         = -26,
+       LWSCOSE_WKAECDH_ALG_SS_HKDF_256         = -27,
+       LWSCOSE_WKAECDH_ALG_SS_HKDF_512         = -28,
+
+       /* RFC8152: Table 19: ECDH Algorithm Parameters */
+
+       LWSCOSE_WKAPECDH_EPHEMERAL_KEY          = -1,
+       LWSCOSE_WKAPECDH_STATIC_KEY             = -2,
+       LWSCOSE_WKAPECDH_STATIC_KEY_ID          = -3,
+
+       /* RFC8152: Table 20: ECDH Algorithm Parameters with key wrap */
+
+       LWSCOSE_WKAPECDH_ES_A128KW              = -29,
+       LWSCOSE_WKAPECDH_ES_A192KW              = -30,
+       LWSCOSE_WKAPECDH_ES_A256KW              = -31,
+       LWSCOSE_WKAPECDH_SS_A128KW              = -32,
+       LWSCOSE_WKAPECDH_SS_A192KW              = -33,
+       LWSCOSE_WKAPECDH_SS_A256KW              = -34,
+
+       /* RFC8152: Table 21: Key Type Values
+        *  https://www.iana.org/assignments/cose/cose.xhtml#key-type
+        */
+
+       LWSCOSE_WKKTV_OKP                       = 1,
+       LWSCOSE_WKKTV_EC2                       = 2,
+       LWSCOSE_WKKTV_RSA                       = 3,
+       LWSCOSE_WKKTV_SYMMETRIC                 = 4,
+       LWSCOSE_WKKTV_HSS_LMS                   = 5,
+       LWSCOSE_WKKTV_WALNUTDSA                 = 6,
+
+
+       /* RFC8152: Table 22: Elliptic Curves
+        * https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves
+        */
+
+       LWSCOSE_WKEC_P256                       = 1,
+       LWSCOSE_WKEC_P384,
+       LWSCOSE_WKEC_P521,
+       LWSCOSE_WKEC_X25519,
+       LWSCOSE_WKEC_X448,
+       LWSCOSE_WKEC_ED25519,
+       LWSCOSE_WKEC_ED448,
+       LWSCOSE_WKEC_SECP256K1,
+
+       /* RFC8152: Table 23: EC Key Parameters */
+
+       LWSCOSE_WKECKP_CRV                      = -1,
+       LWSCOSE_WKECKP_X                        = -2,
+       LWSCOSE_WKECKP_Y                        = -3,
+       LWSCOSE_WKECKP_D                        = -4,
+
+       /* RFC8152: Table 24: Octet Key Pair (OKP) Parameters */
+
+       LWSCOSE_WKOKP_CRV                       = -1,
+       LWSCOSE_WKOKP_X                         = -2,
+       LWSCOSE_WKOKP_D                         = -4,
+
+       /* Additional from
+        * https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters
+        */
+
+       LWSCOSE_WKKPRSA_N                       = -1,
+       LWSCOSE_WKKPRSA_E                       = -2,
+       LWSCOSE_WKKPRSA_D                       = -3,
+       LWSCOSE_WKKPRSA_P                       = -4,
+       LWSCOSE_WKKPRSA_Q                       = -5,
+       LWSCOSE_WKKPRSA_DP                      = -6,
+       LWSCOSE_WKKPRSA_DQ                      = -7,
+       LWSCOSE_WKKPRSA_QINV                    = -8,
+       LWSCOSE_WKKPRSA_OTHER                   = -9,
+       LWSCOSE_WKKPRSA_RI                      = -10,
+       LWSCOSE_WKKPRSA_DI                      = -11,
+       LWSCOSE_WKKPRSA_TI                      = -12,
+
+       /* RFC8152: Table 25: Symmetric Key Parameters */
+
+       LWSCOSE_WKSYMKP_KEY_VALUE               = 4,
+
+       /* RFC8152: Table 26: CoAP Content-Formats for COSE */
+
+       LWSCOAP_CONTENTFORMAT_COSE_SIGN         = 98,
+       LWSCOAP_CONTENTFORMAT_COSE_SIGN1        = 18,
+       LWSCOAP_CONTENTFORMAT_COSE_ENCRYPT      = 96,
+       LWSCOAP_CONTENTFORMAT_COSE_ENCRYPT0     = 16,
+       LWSCOAP_CONTENTFORMAT_COSE_MAC          = 97,
+       LWSCOAP_CONTENTFORMAT_COSE_MAC0         = 17,
+       LWSCOAP_CONTENTFORMAT_COSE_KEY          = 101,
+       LWSCOAP_CONTENTFORMAT_COSE_KEY_SET      = 102,
+
+       /* RFC8152: Table 27: Header Parameter for CounterSignature0 */
+
+       LWSCOSE_WKL_COUNTERSIGNATURE0           = 9, /* bstr */
+
+       /* RFC8812: Table 1: RSASSA-PKCS1-v1_5 Algorithm Values */
+
+       LWSCOSE_WKARSA_ALG_RS256                = -257, /* + SHA-256 */
+       LWSCOSE_WKARSA_ALG_RS384                = -258, /* + SHA-384 */
+       LWSCOSE_WKARSA_ALG_RS512                = -259, /* + SHA-512 */
+};
+
+enum enum_cose_key_meta_tok {
+       COSEKEY_META_KTY,
+       COSEKEY_META_KID,
+       COSEKEY_META_KEY_OPS,
+       COSEKEY_META_BASE_IV,
+       COSEKEY_META_ALG,
+
+       LWS_COUNT_COSE_KEY_ELEMENTS
+};
+
+typedef int64_t cose_param_t;
+
+LWS_VISIBLE LWS_EXTERN const char *
+lws_cose_alg_to_name(cose_param_t alg);
+
+LWS_VISIBLE LWS_EXTERN cose_param_t
+lws_cose_name_to_alg(const char *name);
+
+/*
+ * cose_key
+ */
+
+typedef struct lws_cose_key {
+       /* key data elements */
+       struct lws_gencrypto_keyelem    e[LWS_GENCRYPTO_MAX_KEYEL_COUNT];
+       /* generic meta key elements, like KID */
+       struct lws_gencrypto_keyelem    meta[LWS_COUNT_COSE_KEY_ELEMENTS];
+       lws_dll2_t                      list; /* used when part of a set */
+       int                             gencrypto_kty;  /**< one of LWS_GENCRYPTO_KTY_ */
+       cose_param_t                    kty;
+       cose_param_t                    cose_alg;
+       cose_param_t                    cose_curve;
+       char                            private_key; /* nonzero = has private key elements */
+} lws_cose_key_t;
+
+typedef int (*lws_cose_key_import_callback)(struct lws_cose_key *s, void *user);
+
+/** lws_cose_jwk_import() - Create an lws_cose_key_t object from cose_key CBOR
+ *
+ * \param pkey_set: NULL, or a pointer to an lws_dll2_owner_t for a cose_key set
+ * \param cb: callback for each jwk-processed key, or NULL if importing a single
+ *           key with no parent "keys" JSON
+ * \param user: pointer to be passed to the callback, otherwise ignored by lws.
+ *             NULL if importing a single key with no parent "keys" JSON
+ * \param in: a single cose_key
+ * \param len: the length of the cose_key in bytes
+ *
+ * Creates a single lws_cose_key_t if \p pkey_set is NULL or if the incoming
+ * CBOR doesn't start with an array, otherwise expects a CBOR array containing
+ * zero or more cose_key CBOR, and adds each to the \p pkey_set
+ * lws_dll2_owner_t struct.  Created lws_cose_key_t are filled with data from
+ * the COSE representation and can be used with other COSE crypto ops.
+ */
+LWS_VISIBLE LWS_EXTERN lws_cose_key_t *
+lws_cose_key_import(lws_dll2_owner_t *pkey_set, lws_cose_key_import_callback cb,
+                   void *user, const uint8_t *in, size_t len);
+
+/** lws_cose_key_export() - Create cose_key CBOR from an lws_cose_key_t
+ *
+ * \param ck: the lws_cose_key_t to export to CBOR
+ * \param ctx: the CBOR writing context (same as for lws_lec_printf())
+ * \param flags: 0 to export only public elements, or LWSJWKF_EXPORT_PRIVATE
+ *
+ * Creates an lws_jwk struct filled with data from the COSE representation.
+ */
+LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
+lws_cose_key_export(lws_cose_key_t *ck, lws_lec_pctx_t *ctx, int flags);
+
+/**
+ * lws_cose_key_generate() - generate a fresh key
+ *
+ * \param context: the lws_context used to get random
+ * \param cose_kty: one of LWSCOSE_WKKTV_ indicating the well-known key type
+ * \param use_mask: 0, or a bitfield where (1 << LWSCOSE_WKKO_...) set means valid for use
+ * \param bits: key bits for RSA
+ * \param curve: for EC keys, one of "P-256", "P-384" or "P-521" currently
+ * \param kid: string describing the key, or NULL
+ *
+ * Create an lws_cose_key_t of the specified type and return it
+ */
+LWS_VISIBLE LWS_EXTERN lws_cose_key_t *
+lws_cose_key_generate(struct lws_context *context, cose_param_t cose_kty,
+                     int use_mask, int bits, const char *curve,
+                     const uint8_t *kid, size_t kl);
+
+LWS_VISIBLE LWS_EXTERN lws_cose_key_t *
+lws_cose_key_from_set(lws_dll2_owner_t *set, const uint8_t *kid, size_t kl);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_cose_key_destroy(lws_cose_key_t **ck);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_cose_key_set_destroy(lws_dll2_owner_t *o);
+
+/* only available in _DEBUG build */
+
+LWS_VISIBLE LWS_EXTERN void
+lws_cose_key_dump(const lws_cose_key_t *ck);
+
+/*
+ * cose_sign
+ */
+
+struct lws_cose_validate_context;
+
+
+enum lws_cose_sig_types {
+       SIGTYPE_UNKNOWN,
+       SIGTYPE_MULTI,
+       SIGTYPE_SINGLE,
+       SIGTYPE_COUNTERSIGNED, /* not yet supported */
+       SIGTYPE_MAC, /* only supported for validation */
+       SIGTYPE_MAC0,
+};
+
+/* a list of these result objects is the output of the validation process */
+
+typedef struct {
+       lws_dll2_t              list;
+
+       const lws_cose_key_t    *cose_key;
+       cose_param_t            cose_alg;
+
+       int                     result; /* 0 = validated */
+
+} lws_cose_validate_res_t;
+
+enum {
+       LCOSESIGEXTCB_RET_FINISHED,
+       LCOSESIGEXTCB_RET_AGAIN,
+       LCOSESIGEXTCB_RET_ERROR         = -1
+};
+
+typedef struct {
+       struct lws_cose_validate_context *cps;
+       const uint8_t                    *ext;
+       size_t                           xl;
+} lws_cose_sig_ext_pay_t;
+
+typedef int (*lws_cose_sign_ext_pay_cb_t)(lws_cose_sig_ext_pay_t *x);
+typedef int (*lws_cose_validate_pay_cb_t)(struct lws_cose_validate_context *cps,
+                                         void *opaque, const uint8_t *paychunk,
+                                         size_t paychunk_len);
+
+typedef struct lws_cose_validate_create_info {
+       struct lws_context              *cx;
+       /**< REQUIRED: the lws context */
+       lws_dll2_owner_t                *keyset;
+       /**< REQUIRED: one or more cose_keys */
+
+       enum lws_cose_sig_types         sigtype;
+       /**<  0 if a CBOR tag is in the sig, else one of SIGTYPE_MULTI,
+        * SIGTYPE_SINGLE, etc*/
+
+       lws_cose_validate_pay_cb_t      pay_cb;
+       /**< optional: called back with unvalidated payload pieces */
+       void                            *pay_opaque;
+       /**< optional: passed into pay_cb callback along with payload chunk */
+
+       lws_cose_sign_ext_pay_cb_t      ext_cb;
+       /**< optional extra application data provision callback */
+       void                            *ext_opaque;
+       /**< optional extra application data provision callback opaque */
+       size_t                          ext_len;
+       /**< if we have extra app data, this must be set to the length of it */
+} lws_cose_validate_create_info_t;
+
+/**
+ * lws_cose_validate_create() - create a signature validation context
+ *
+ * \param info: struct describing the validation context to create
+ *
+ * Creates a signature validation context set up as described in \p info.
+ *
+ * You can then pass the signature cbor chunks to it using
+ * lws_cose_validate_chunk(), finialize and get the results list using
+ * lws_cose_validate_results() and destroy with lws_cose_validate_destroy().
+ */
+LWS_VISIBLE LWS_EXTERN struct lws_cose_validate_context *
+lws_cose_validate_create(const lws_cose_validate_create_info_t *info);
+
+/**
+ * lws_cose_validate_chunk() - passes chunks of CBOR into the signature validator
+ *
+ * \param cps: the validation context
+ * \param in: the chunk of CBOR (does not have to be logically complete)
+ * \param in_len: number of bytes available at \p in
+ *
+ * Parses signature CBOR to produce a list of result objects.
+ *
+ *
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_cose_validate_chunk(struct lws_cose_validate_context *cps,
+                       const uint8_t *in, size_t in_len, size_t *used_in);
+
+LWS_VISIBLE LWS_EXTERN lws_dll2_owner_t *
+lws_cose_validate_results(struct lws_cose_validate_context *cps);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_cose_validate_destroy(struct lws_cose_validate_context **cps);
+
+struct lws_cose_sign_context;
+
+#define LCSC_FL_ADD_CBOR_TAG           (1 << 0)
+#define LCSC_FL_ADD_CBOR_PREFER_MAC0   (1 << 1)
+
+typedef struct lws_cose_sign_create_info {
+       struct lws_context              *cx;
+       /**< REQUIRED: the lws context */
+       lws_dll2_owner_t                *keyset;
+       /**< REQUIRED: one or more cose_keys */
+
+       lws_lec_pctx_t                  *lec;
+       /**< REQUIRED: the cbor output context to emit to, user must
+        * initialize with lws_lec_init() beforehand */
+
+       lws_cose_sign_ext_pay_cb_t      ext_cb;
+       /**< optional extra application data provision callback */
+       void                            *ext_opaque;
+       /**< optional extra application data provision callback opaque */
+       size_t                          ext_len;
+       /**< if we have extra app data, this must be set to the length of it */
+
+       size_t                          inline_payload_len;
+       /**< REQUIRED: size of the inline payload we will provide */
+
+       int                             flags;
+       /**< bitmap of  LCSC_FL_* */
+       enum lws_cose_sig_types         sigtype;
+       /**< 0, or sign type hint */
+} lws_cose_sign_create_info_t;
+
+/**
+ * lws_cose_sign_create() - Create a signing context
+ *
+ * \param info: a structure describing the signing context you want to create
+ *
+ * This allocates and returns a signing context created according to what is in
+ * the \p info parameter.
+ *
+ * \p info must be prepared with the lws_context, a keyset to use, a CBOR
+ * output context, and the inline payload length.
+ *
+ * Returns NULL on failure or the created signing context ready to add alg(s)
+ * to.
+ */
+
+LWS_VISIBLE LWS_EXTERN struct lws_cose_sign_context *
+lws_cose_sign_create(const lws_cose_sign_create_info_t *info);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
+                 const lws_cose_key_t *ck);
+
+LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
+lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
+                           const uint8_t *in, size_t in_len);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_cose_sign_destroy(struct lws_cose_sign_context **csc);
+
+//@}
index 20de5a2..2a82d81 100644 (file)
@@ -1,22 +1,25 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * must be included manually as
  *
index 8cc97e2..ebca888 100644 (file)
@@ -1,24 +1,25 @@
 /*
- * libwebsockets - disk cache helpers
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup diskcache LWS disk cache
@@ -99,7 +100,7 @@ lws_diskcache_destroy(struct lws_diskcache_scan **lds);
  * will transition to use when it drops root privileges.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_diskcache_prepare(const char *cache_base_dir, int mode, int uid);
+lws_diskcache_prepare(const char *cache_base_dir, int mode, uid_t uid);
 
 #define LWS_DISKCACHE_QUERY_NO_CACHE   0
 #define LWS_DISKCACHE_QUERY_EXISTS     1
diff --git a/include/libwebsockets/lws-display.h b/include/libwebsockets/lws-display.h
new file mode 100644 (file)
index 0000000..203cfc5
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * lws abstract display
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(__LWS_DISPLAY_H__)
+#define __LWS_DISPLAY_H__
+
+#include <stdint.h>
+
+typedef uint16_t lws_display_scalar;
+
+/*
+ * This is embedded in the actual display implementation object at the top,
+ * so a pointer to this can be cast to a pointer to the implementation object
+ * by any code that is specific to how it was implemented.
+ *
+ * Notice for the backlight / display intensity we contain pwm_ops... these can
+ * be some other pwm_ops like existing gpio pwm ops, or handled in a customized
+ * way like set oled contrast.  Either way, the pwm level is arrived at via a
+ * full set of lws_led_sequences capable of generic lws transitions
+ */
+
+typedef struct lws_display {
+       int (*init)(const struct lws_display *disp);
+       const lws_pwm_ops_t             *bl_pwm_ops;
+       int (*contrast)(const struct lws_display *disp, uint8_t contrast);
+       int (*blit)(const struct lws_display *disp, const uint8_t *src,
+                   lws_display_scalar x, lws_display_scalar y,
+                   lws_display_scalar w, lws_display_scalar h);
+       int (*power)(const struct lws_display *disp, int state);
+
+       const lws_led_sequence_def_t    *bl_active;
+       const lws_led_sequence_def_t    *bl_dim;
+       const lws_led_sequence_def_t    *bl_transition;
+
+       void                            *variant;
+
+       int                             bl_index;
+
+       lws_display_scalar              w;
+       /**< display surface width in pixels */
+       lws_display_scalar              h;
+       /**< display surface height in pixels */
+
+       uint8_t                         latency_wake_ms;
+       /**< ms required after wake from sleep before display usable again...
+        * delay bringing up the backlight for this amount of time on wake.
+        * This is managed via a sul on the event loop, not blocking. */
+} lws_display_t;
+
+/*
+ * This contains dynamic data related to display state
+ */
+
+enum lws_display_controller_state {
+       LWSDISPS_OFF,
+       LWSDISPS_AUTODIMMED,      /* is in pre- blanking static dim mode */
+       LWSDISPS_BECOMING_ACTIVE, /* waiting for wake latency before active */
+       LWSDISPS_ACTIVE,          /* is active */
+       LWSDISPS_GOING_OFF        /* dimming then off */
+};
+
+typedef struct lws_display_state {
+
+       lws_sorted_usec_list_t          sul_autodim;
+       const lws_display_t             *disp;
+       struct lws_context              *ctx;
+
+       int                             autodim_ms;
+       int                             off_ms;
+
+       struct lws_led_state            *bl_lcs;
+
+       lws_led_state_chs_t             chs;
+       /* set of sequencer transition channels */
+
+       enum lws_display_controller_state state;
+
+} lws_display_state_t;
+
+/**
+ * lws_display_state_init() - initialize display states
+ *
+ * \param lds: the display state object
+ * \param ctx: the lws context
+ * \param autodim_ms: ms since last active report to dim display (<0 = never)
+ * \param off_ms: ms since dim to turn display off (<0 = never)
+ * \param bl_lcs: the led controller instance that has the backlight
+ * \param disp: generic display object we belong to
+ *
+ * This initializes a display's state, and sets up the optional screen auto-dim
+ * and blanking on inactive, and gradual brightness change timer.
+ *
+ *  - auto-dim then off: set autodim to some ms and off_ms to some ms
+ *  - auto-dim only: set autodim to some ms and off_ms to -1
+ *  - off-only: set autodim to some ms and off_ms to 0
+ *  - neither: set both autodim and off_ms to -1
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_display_state_init(lws_display_state_t *lds, struct lws_context *ctx,
+                      int autodim_ms, int off_ms, struct lws_led_state *bl_lcs,
+                      const lws_display_t *disp);
+
+/**
+ * lws_display_state_set_brightness() - gradually change the brightness
+ *
+ * \param lds: the display state we are changing
+ * \param target: the target brightness to transition to
+ *
+ * Adjusts the brightness gradually twoards the target at 20Hz
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_display_state_set_brightness(lws_display_state_t *lds,
+                                const lws_led_sequence_def_t *pwmseq);
+
+/*
+ * lws_display_state_active() - inform the system the display is active
+ *
+ * \param lds: the display state we are marking as active
+ *
+ * Resets the auto-dim and auto-off timers and makes sure the display is on and
+ * at the active brightness level
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_display_state_active(lws_display_state_t *lds);
+
+/*
+ * lws_display_state_off() - turns off the related display
+ *
+ * \param lds: the display state we are turning off
+ *
+ * Turns the display to least power mode or completely off if possible.
+ * Disables the timers related to dimming and blanking.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_display_state_off(lws_display_state_t *lds);
+
+#endif
diff --git a/include/libwebsockets/lws-dll2.h b/include/libwebsockets/lws-dll2.h
new file mode 100644 (file)
index 0000000..14f0fcd
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** \defgroup ll linked-lists
+* ##Linked list apis
+*
+* simple single and doubly-linked lists
+*/
+///@{
+
+/**
+ * lws_start_foreach_ll(): linkedlist iterator helper start
+ *
+ * \param type: type of iteration, eg, struct xyz *
+ * \param it: iterator var name to create
+ * \param start: start of list
+ *
+ * This helper creates an iterator and starts a while (it) {
+ * loop.  The iterator runs through the linked list starting at start and
+ * ends when it gets a NULL.
+ * The while loop should be terminated using lws_start_foreach_ll().
+ */
+#define lws_start_foreach_ll(type, it, start)\
+{ \
+       type it = start; \
+       while (it) {
+
+/**
+ * lws_end_foreach_ll(): linkedlist iterator helper end
+ *
+ * \param it: same iterator var name given when starting
+ * \param nxt: member name in the iterator pointing to next list element
+ *
+ * This helper is the partner for lws_start_foreach_ll() that ends the
+ * while loop.
+ */
+
+#define lws_end_foreach_ll(it, nxt) \
+               it = it->nxt; \
+       } \
+}
+
+/**
+ * lws_start_foreach_ll_safe(): linkedlist iterator helper start safe against delete
+ *
+ * \param type: type of iteration, eg, struct xyz *
+ * \param it: iterator var name to create
+ * \param start: start of list
+ * \param nxt: member name in the iterator pointing to next list element
+ *
+ * This helper creates an iterator and starts a while (it) {
+ * loop.  The iterator runs through the linked list starting at start and
+ * ends when it gets a NULL.
+ * The while loop should be terminated using lws_end_foreach_ll_safe().
+ * Performs storage of next increment for situations where iterator can become invalidated
+ * during iteration.
+ */
+#define lws_start_foreach_ll_safe(type, it, start, nxt)\
+{ \
+       type it = start; \
+       while (it) { \
+               type next_##it = it->nxt;
+
+/**
+ * lws_end_foreach_ll_safe(): linkedlist iterator helper end (pre increment storage)
+ *
+ * \param it: same iterator var name given when starting
+ *
+ * This helper is the partner for lws_start_foreach_ll_safe() that ends the
+ * while loop. It uses the precreated next_ variable already stored during
+ * start.
+ */
+
+#define lws_end_foreach_ll_safe(it) \
+               it = next_##it; \
+       } \
+}
+
+/**
+ * lws_start_foreach_llp(): linkedlist pointer iterator helper start
+ *
+ * \param type: type of iteration, eg, struct xyz **
+ * \param it: iterator var name to create
+ * \param start: start of list
+ *
+ * This helper creates an iterator and starts a while (it) {
+ * loop.  The iterator runs through the linked list starting at the
+ * address of start and ends when it gets a NULL.
+ * The while loop should be terminated using lws_start_foreach_llp().
+ *
+ * This helper variant iterates using a pointer to the previous linked-list
+ * element.  That allows you to easily delete list members by rewriting the
+ * previous pointer to the element's next pointer.
+ */
+#define lws_start_foreach_llp(type, it, start)\
+{ \
+       type it = &(start); \
+       while (*(it)) {
+
+#define lws_start_foreach_llp_safe(type, it, start, nxt)\
+{ \
+       type it = &(start); \
+       type next; \
+       while (*(it)) { \
+               next = &((*(it))->nxt); \
+
+/**
+ * lws_end_foreach_llp(): linkedlist pointer iterator helper end
+ *
+ * \param it: same iterator var name given when starting
+ * \param nxt: member name in the iterator pointing to next list element
+ *
+ * This helper is the partner for lws_start_foreach_llp() that ends the
+ * while loop.
+ */
+
+#define lws_end_foreach_llp(it, nxt) \
+               it = &(*(it))->nxt; \
+       } \
+}
+
+#define lws_end_foreach_llp_safe(it) \
+               it = next; \
+       } \
+}
+
+#define lws_ll_fwd_insert(\
+       ___new_object,  /* pointer to new object */ \
+       ___m_list,      /* member for next list object ptr */ \
+       ___list_head    /* list head */ \
+               ) {\
+               ___new_object->___m_list = ___list_head; \
+               ___list_head = ___new_object; \
+       }
+
+#define lws_ll_fwd_remove(\
+       ___type,        /* type of listed object */ \
+       ___m_list,      /* member for next list object ptr */ \
+       ___target,      /* object to remove from list */ \
+       ___list_head    /* list head */ \
+       ) { \
+                lws_start_foreach_llp(___type **, ___ppss, ___list_head) { \
+                        if (*___ppss == ___target) { \
+                                *___ppss = ___target->___m_list; \
+                                break; \
+                        } \
+                } lws_end_foreach_llp(___ppss, ___m_list); \
+       }
+
+
+/*
+ * doubly linked-list
+ */
+
+/*
+ * lws_dll2_owner / lws_dll2 : more capable version of lws_dll.  Differences:
+ *
+ *  - there's an explicit lws_dll2_owner struct which holds head, tail and
+ *    count of members.
+ *
+ *  - list members all hold a pointer to their owner.  So user code does not
+ *    have to track anything about exactly what lws_dll2_owner list the object
+ *    is a member of.
+ *
+ *  - you can use lws_dll unless you want the member count or the ability to
+ *    not track exactly which list it's on.
+ *
+ *  - layout is compatible with lws_dll (but lws_dll apis will not update the
+ *    new stuff)
+ */
+
+
+struct lws_dll2;
+struct lws_dll2_owner;
+
+typedef struct lws_dll2 {
+       struct lws_dll2         *prev;
+       struct lws_dll2         *next;
+       struct lws_dll2_owner   *owner;
+} lws_dll2_t;
+
+typedef struct lws_dll2_owner {
+       struct lws_dll2         *tail;
+       struct lws_dll2         *head;
+
+       uint32_t                count;
+} lws_dll2_owner_t;
+
+LWS_VISIBLE LWS_EXTERN int
+lws_dll2_is_detached(const struct lws_dll2 *d);
+
+static LWS_INLINE const struct lws_dll2_owner *
+lws_dll2_owner(const struct lws_dll2 *d) { return d->owner; }
+
+static LWS_INLINE struct lws_dll2 *
+lws_dll2_get_head(struct lws_dll2_owner *owner) { return owner->head; }
+
+static LWS_INLINE struct lws_dll2 *
+lws_dll2_get_tail(struct lws_dll2_owner *owner) { return owner->tail; }
+
+LWS_VISIBLE LWS_EXTERN void
+lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_dll2_remove(struct lws_dll2 *d);
+
+typedef int (*lws_dll2_foreach_cb_t)(struct lws_dll2 *d, void *user);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
+                     lws_dll2_foreach_cb_t cb);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_dll2_clear(struct lws_dll2 *d);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_dll2_owner_clear(struct lws_dll2_owner *d);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_dll2_add_before(struct lws_dll2 *d, struct lws_dll2 *after);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_dll2_add_sorted(lws_dll2_t *d, lws_dll2_owner_t *own,
+                   int (*compare)(const lws_dll2_t *d, const lws_dll2_t *i));
+
+LWS_VISIBLE LWS_EXTERN void
+lws_dll2_add_sorted_priv(lws_dll2_t *d, lws_dll2_owner_t *own, void *priv,
+                        int (*compare3)(void *priv, const lws_dll2_t *d,
+                                        const lws_dll2_t *i));
+
+LWS_VISIBLE LWS_EXTERN void *
+_lws_dll2_search_sz_pl(lws_dll2_owner_t *own, const char *name, size_t namelen,
+                     size_t dll2_ofs, size_t ptr_ofs);
+
+/*
+ * Searches objects in an owner list linearly and returns one with a given
+ * member C-string matching a supplied length-provided string if it exists, else
+ * NULL.
+ */
+
+#define lws_dll2_search_sz_pl(own, name, namelen, type, membd2list, membptr) \
+               ((type *)_lws_dll2_search_sz_pl(own, name, namelen, \
+                                      offsetof(type, membd2list), \
+                                      offsetof(type, membptr)))
+
+#if defined(_DEBUG)
+void
+lws_dll2_describe(struct lws_dll2_owner *owner, const char *desc);
+#else
+#define lws_dll2_describe(x, y)
+#endif
+
+/*
+ * these are safe against the current container object getting deleted,
+ * since the hold his next in a temp and go to that next.  ___tmp is
+ * the temp.
+ */
+
+#define lws_start_foreach_dll_safe(___type, ___it, ___tmp, ___start) \
+{ \
+       ___type ___it = ___start; \
+       while (___it) { \
+               ___type ___tmp = (___it)->next;
+
+#define lws_end_foreach_dll_safe(___it, ___tmp) \
+               ___it = ___tmp; \
+       } \
+}
+
+#define lws_start_foreach_dll(___type, ___it, ___start) \
+{ \
+       ___type ___it = ___start; \
+       while (___it) {
+
+#define lws_end_foreach_dll(___it) \
+               ___it = (___it)->next; \
+       } \
+}
+
+///@}
+
index 18b5bcb..09c950c 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*
@@ -61,7 +62,7 @@
  *
  * Returns an opaque pointer to the dsh, or NULL if allocation failed.
  */
-LWS_VISIBLE LWS_EXTERN lws_dsh_t *
+LWS_VISIBLE LWS_EXTERN struct lws_dsh *
 lws_dsh_create(lws_dll2_owner_t *owner, size_t buffer_size, int count_kinds);
 
 /**
@@ -79,7 +80,7 @@ lws_dsh_create(lws_dll2_owner_t *owner, size_t buffer_size, int count_kinds);
  * unmigratable objects are cleanly destroyed.
  */
 LWS_VISIBLE LWS_EXTERN void
-lws_dsh_destroy(lws_dsh_t **pdsh);
+lws_dsh_destroy(struct lws_dsh **pdsh);
 
 /**
  * lws_dsh_alloc_tail() - make a suballocation inside a dsh
@@ -100,8 +101,8 @@ lws_dsh_destroy(lws_dsh_t **pdsh);
  * The suballocation is added to the kind-specific FIFO at the tail.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
-                   const void *src2, size_t size2);
+lws_dsh_alloc_tail(struct lws_dsh *dsh, int kind, const void *src1,
+                  size_t size1, const void *src2, size_t size2);
 
 /**
  * lws_dsh_free() - free a suballocation from the dsh
@@ -114,8 +115,11 @@ lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
 LWS_VISIBLE LWS_EXTERN void
 lws_dsh_free(void **obj);
 
+LWS_VISIBLE LWS_EXTERN size_t
+lws_dsh_get_size(struct lws_dsh *dsh, int kind);
+
 /**
- * lws_dsh_get_head() - free a suballocation from the dsh
+ * lws_dsh_get_head() - get the head allocation inside the dsh
  *
  * \param dsh: the dsh tracking the allocation
  * \param kind: the kind of allocation
@@ -130,7 +134,7 @@ lws_dsh_free(void **obj);
  * free list.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_dsh_get_head(lws_dsh_t *dsh, int kind, void **obj, size_t *size);
+lws_dsh_get_head(struct lws_dsh *dsh, int kind, void **obj, size_t *size);
 
 /**
  * lws_dsh_describe() - DEBUG BUILDS ONLY dump the dsh to the logs
@@ -141,4 +145,4 @@ lws_dsh_get_head(lws_dsh_t *dsh, int kind, void **obj, size_t *size);
  * Useful information for debugging lws_dsh
  */
 LWS_VISIBLE LWS_EXTERN void
-lws_dsh_describe(lws_dsh_t *dsh, const char *desc);
+lws_dsh_describe(struct lws_dsh *dsh, const char *desc);
diff --git a/include/libwebsockets/lws-esp32.h b/include/libwebsockets/lws-esp32.h
deleted file mode 100644 (file)
index 0350586..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
- */
-
-typedef int lws_sockfd_type;
-typedef int lws_filefd_type;
-
-/*
- * Later lwip (at least 2.1.12) already defines these in its own headers
- * protected by the same test as used here... if POLLIN / POLLOUT already exist
- * then assume no need to declare those and struct pollfd.
- *
- * Older lwip needs these declarations done here.
- */
-
-#if !defined(POLLIN) && !defined(POLLOUT)
-
-struct pollfd {
-       lws_sockfd_type fd; /**< fd related to */
-       short events; /**< which POLL... events to respond to */
-       short revents; /**< which POLL... events occurred */
-};
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-#endif
-
-#if defined(LWS_AMAZON_RTOS)
-#include <FreeRTOS.h>
-#include <event_groups.h>
-#include <string.h>
-#include "timers.h"
-#else /* LWS_AMAZON_RTOS */
-#include <freertos/FreeRTOS.h>
-#include <freertos/event_groups.h>
-#include <string.h>
-#include "esp_wifi.h"
-#include "esp_system.h"
-#include "esp_event.h"
-#include "esp_event_loop.h"
-#include "nvs.h"
-#include "driver/gpio.h"
-#include "esp_spi_flash.h"
-#include "freertos/timers.h"
-#endif /* LWS_AMAZON_RTOS */
-
-#if !defined(CONFIG_FREERTOS_HZ)
-#define CONFIG_FREERTOS_HZ 100
-#endif
-
-typedef TimerHandle_t uv_timer_t;
-typedef void uv_cb_t(uv_timer_t *);
-typedef void * uv_handle_t;
-
-struct timer_mapping {
-       uv_cb_t *cb;
-       uv_timer_t *t;
-};
-
-#define UV_VERSION_MAJOR 1
-
-#define lws_uv_getloop(a, b) (NULL)
-
-static LWS_INLINE void uv_timer_init(void *l, uv_timer_t *t)
-{
-       (void)l;
-       *t = NULL;
-}
-
-extern void esp32_uvtimer_cb(TimerHandle_t t);
-
-static LWS_INLINE void uv_timer_start(uv_timer_t *t, uv_cb_t *cb, int first, int rep)
-{
-       struct timer_mapping *tm = (struct timer_mapping *)malloc(sizeof(*tm));
-
-       if (!tm)
-               return;
-
-       tm->t = t;
-       tm->cb = cb;
-
-       *t = xTimerCreate("x", pdMS_TO_TICKS(first), !!rep, tm,
-                         (TimerCallbackFunction_t)esp32_uvtimer_cb);
-       xTimerStart(*t, 0);
-}
-
-static LWS_INLINE void uv_timer_stop(uv_timer_t *t)
-{
-       xTimerStop(*t, 0);
-}
-
-static LWS_INLINE void uv_close(uv_handle_t *h, void *v)
-{
-       free(pvTimerGetTimerID((uv_timer_t)h));
-       xTimerDelete(*(uv_timer_t *)h, 0);
-}
-
-
-#if !defined(LWS_AMAZON_RTOS)
-
-/* ESP32 helper declarations */
-
-#include <mdns.h>
-#include <esp_partition.h>
-
-#define LWS_PLUGIN_STATIC
-#define LWS_MAGIC_REBOOT_TYPE_ADS 0x50001ffc
-#define LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY 0xb00bcafe
-#define LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY 0xfaceb00b
-#define LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON 0xf0cedfac
-#define LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY_ERASE_OTA 0xfac0eeee
-
-/* user code provides these */
-
-extern void
-lws_esp32_identify_physical_device(void);
-
-/* lws-plat-esp32 provides these */
-
-typedef void (*lws_cb_scan_done)(uint16_t count, wifi_ap_record_t *recs, void *arg);
-
-enum genled_state {
-       LWSESP32_GENLED__INIT,
-       LWSESP32_GENLED__LOST_NETWORK,
-       LWSESP32_GENLED__NO_NETWORK,
-       LWSESP32_GENLED__CONN_AP,
-       LWSESP32_GENLED__GOT_IP,
-       LWSESP32_GENLED__OK,
-};
-
-struct lws_group_member {
-       struct lws_group_member *next;
-       uint64_t last_seen;
-       char model[16];
-       char role[16];
-       char host[32];
-       char mac[20];
-       int width, height;
-       struct ip4_addr addr;
-       struct ip6_addr addrv6;
-       uint8_t flags;
-};
-
-#define LWS_SYSTEM_GROUP_MEMBER_ADD            1
-#define LWS_SYSTEM_GROUP_MEMBER_CHANGE         2
-#define LWS_SYSTEM_GROUP_MEMBER_REMOVE         3
-
-#define LWS_GROUP_FLAG_SELF 1
-
-struct lws_esp32 {
-       char sta_ip[16];
-       char sta_mask[16];
-       char sta_gw[16];
-       char serial[16];
-       char opts[16];
-       char model[16];
-       char group[16];
-       char role[16];
-       char ssid[4][64];
-       char password[4][64];
-       char active_ssid[64];
-       char access_pw[16];
-       char hostname[32];
-       char mac[20];
-       char le_dns[64];
-       char le_email[64];
-               char region;
-               char inet;
-       char conn_ap;
-
-       enum genled_state genled;
-       uint64_t genled_t;
-
-       lws_cb_scan_done scan_consumer;
-       void *scan_consumer_arg;
-       struct lws_group_member *first;
-       int extant_group_members;
-
-       char acme;
-       char upload;
-
-       volatile char button_is_down;
-};
-
-struct lws_esp32_image {
-       uint32_t romfs;
-       uint32_t romfs_len;
-       uint32_t json;
-       uint32_t json_len;
-};
-
-extern struct lws_esp32 lws_esp32;
-struct lws_vhost;
-
-extern esp_err_t
-lws_esp32_event_passthru(void *ctx, system_event_t *event);
-extern void
-lws_esp32_wlan_config(void);
-extern void
-lws_esp32_wlan_start_ap(void);
-extern void
-lws_esp32_wlan_start_station(void);
-struct lws_context_creation_info;
-extern void
-lws_esp32_set_creation_defaults(struct lws_context_creation_info *info);
-extern struct lws_context *
-lws_esp32_init(struct lws_context_creation_info *, struct lws_vhost **pvh);
-extern int
-lws_esp32_wlan_nvs_get(int retry);
-extern esp_err_t
-lws_nvs_set_str(nvs_handle handle, const char* key, const char* value);
-extern void
-lws_esp32_restart_guided(uint32_t type);
-extern const esp_partition_t *
-lws_esp_ota_get_boot_partition(void);
-extern int
-lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i, char *json, int json_len);
-extern int
-lws_esp32_leds_network_indication(void);
-
-extern uint32_t lws_esp32_get_reboot_type(void);
-extern uint16_t lws_esp32_sine_interp(int n);
-
-/* required in external code by esp32 plat (may just return if no leds) */
-extern void lws_esp32_leds_timer_cb(TimerHandle_t th);
-
-#endif /* LWS_AMAZON_RTOS */
diff --git a/include/libwebsockets/lws-eventlib-exports.h b/include/libwebsockets/lws-eventlib-exports.h
new file mode 100644 (file)
index 0000000..5d01caa
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * These are exports needed by event lib plugins.
+ */
+
+enum lws_event_lib_ops_flags {
+       LELOF_ISPOLL                            = (1 >> 0),
+       LELOF_DESTROY_FINAL                     = (1 >> 1),
+};
+
+enum {
+       LWS_EV_READ                             = (1 << 0),
+       LWS_EV_WRITE                            = (1 << 1),
+       LWS_EV_START                            = (1 << 2),
+       LWS_EV_STOP                             = (1 << 3),
+};
+
+struct lws_event_loop_ops {
+       const char *name;
+       /* event loop-specific context init during context creation */
+       int (*init_context)(struct lws_context *context,
+                           const struct lws_context_creation_info *info);
+       /* called during lws_destroy_context */
+       int (*destroy_context1)(struct lws_context *context);
+       /* called during lws_destroy_context2 */
+       int (*destroy_context2)(struct lws_context *context);
+       /* init vhost listening wsi */
+       int (*init_vhost_listen_wsi)(struct lws *wsi);
+       /* init the event loop for a pt */
+       int (*init_pt)(struct lws_context *context, void *_loop, int tsi);
+       /* called at end of first phase of close_free_wsi()  */
+       int (*wsi_logical_close)(struct lws *wsi);
+       /* return nonzero if client connect not allowed  */
+       int (*check_client_connect_ok)(struct lws *wsi);
+       /* close handle manually  */
+       void (*close_handle_manually)(struct lws *wsi);
+       /* event loop accept processing  */
+       int (*sock_accept)(struct lws *wsi);
+       /* control wsi active events  */
+       void (*io)(struct lws *wsi, unsigned int flags);
+       /* run the event loop for a pt */
+       void (*run_pt)(struct lws_context *context, int tsi);
+       /* called before pt is destroyed */
+       void (*destroy_pt)(struct lws_context *context, int tsi);
+       /* called just before wsi is freed  */
+       void (*destroy_wsi)(struct lws *wsi);
+       /* return nonzero if caller thread is not loop service thread  */
+       int (*foreign_thread)(struct lws_context *context, int tsi);
+
+       uint8_t flags;
+
+       uint16_t        evlib_size_ctx;
+       uint16_t        evlib_size_pt;
+       uint16_t        evlib_size_vh;
+       uint16_t        evlib_size_wsi;
+};
+
+LWS_VISIBLE LWS_EXTERN void *
+lws_evlib_wsi_to_evlib_pt(struct lws *wsi);
+
+LWS_VISIBLE LWS_EXTERN void *
+lws_evlib_tsi_to_evlib_pt(struct lws_context *ctx, int tsi);
+
+ /*
+  * You should consider these opaque for normal user code.
+  */
+
+LWS_VISIBLE LWS_EXTERN void *
+lws_realloc(void *ptr, size_t size, const char *reason);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_vhost_destroy1(struct lws_vhost *vh);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
+                  const char *caller);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_vhost_foreach_listen_wsi(struct lws_context *cx, void *arg,
+                            lws_dll2_foreach_cb_t cb);
+
+struct lws_context_per_thread;
+LWS_VISIBLE LWS_EXTERN void
+lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt);
+
+#if !defined(wsi_from_fd) && !defined(WIN32) && !defined(_WIN32)
+struct lws_context;
+LWS_VISIBLE LWS_EXTERN struct lws *
+wsi_from_fd(const struct lws_context *context, int fd);
+#endif
+
+LWS_VISIBLE LWS_EXTERN int
+_lws_plat_service_forced_tsi(struct lws_context *context, int tsi);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_context_destroy2(struct lws_context *context);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_destroy_event_pipe(struct lws *wsi);
+
+LWS_VISIBLE LWS_EXTERN void
+__lws_close_free_wsi_final(struct lws *wsi);
+
+#if LWS_MAX_SMP > 1
+
+struct lws_mutex_refcount {
+       pthread_mutex_t lock;
+       pthread_t lock_owner;
+       const char *last_lock_reason;
+       char lock_depth;
+       char metadata;
+};
+
+LWS_VISIBLE LWS_EXTERN void
+lws_mutex_refcount_assert_held(struct lws_mutex_refcount *mr);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_mutex_refcount_init(struct lws_mutex_refcount *mr);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr);
+
+#endif
diff --git a/include/libwebsockets/lws-fault-injection.h b/include/libwebsockets/lws-fault-injection.h
new file mode 100644 (file)
index 0000000..e913376
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Fault injection api if built with LWS_WITH_SYS_FAULT_INJECTION
+ */
+
+typedef struct lws_xos {
+       uint64_t s[4];
+} lws_xos_t;
+
+/**
+ * lws_xos_init() - seed xoshiro256 PRNG
+ *
+ * \param xos: the prng state object to initialize
+ * \param seed: the 64-bit seed
+ *
+ * Initialize PRNG \xos with the starting state represented by \p seed
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_xos_init(struct lws_xos *xos, uint64_t seed);
+
+/**
+ * lws_xos() - get next xoshiro256 PRNG result and update state
+ *
+ * \param xos: the PRNG state to use
+ *
+ * Returns next 64-bit PRNG result.  These are cheap to get,
+ * quite a white noise sequence, and completely deterministic
+ * according to the seed it was initialized with.
+ */
+LWS_VISIBLE LWS_EXTERN uint64_t LWS_WARN_UNUSED_RESULT
+lws_xos(struct lws_xos *xos);
+
+/**
+ * lws_xos_percent() - return 1 a given percent of the time on average
+ *
+ * \param xos: the PRNG state to use
+ * \param percent: chance in 100 of returning 1
+ *
+ * Returns 1 if next random % 100 is < \p percent, such that
+ * 100 always returns 1, 0 never returns 1, and the chance linearly scales
+ * inbetween
+ */
+LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
+lws_xos_percent(struct lws_xos *xos, int percent);
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+
+enum {
+       LWSFI_ALWAYS,
+       LWSFI_DETERMINISTIC,    /* do .count injections after .pre then stop */
+       LWSFI_PROBABILISTIC,    /* .pre % chance of injection */
+       LWSFI_PATTERN,          /* use .count bits in .pattern after .pre */
+       LWSFI_PATTERN_ALLOC,    /* as _PATTERN, but .pattern is malloc'd */
+       LWSFI_RANGE             /* pick a number between pre and count */
+};
+
+typedef struct lws_fi {
+       const char              *name;
+       const uint8_t           *pattern;
+       uint64_t                pre;
+       uint64_t                count;
+       uint64_t                times;          /* start at 0, tracks usage */
+       char                    type;           /* LWSFI_* */
+} lws_fi_t;
+
+typedef struct lws_fi_ctx {
+       lws_dll2_owner_t        fi_owner;
+       struct lws_xos          xos;
+       const char              *name;
+} lws_fi_ctx_t;
+
+/**
+ * lws_fi() - find out if we should perform the named fault injection this time
+ *
+ * \param fic: fault injection tracking context
+ * \param fi_name: name of fault injection
+ *
+ * This checks if the named fault is configured in the fi tracking context
+ * provided, if it is, then it will make a decision if the named fault should
+ * be applied this time, using the tracking in the named lws_fi_t.
+ *
+ * If the provided context has a parent, that is also checked for the named fi
+ * item recursively, with the first found being used to determine if to inject
+ * or not.
+ *
+ * If LWS_WITH_SYS_FAULT_INJECTION is not defined, then this always return 0.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_fi(const lws_fi_ctx_t *fic, const char *fi_name);
+
+/**
+ * lws_fi_range() - get a random number from a range
+ *
+ * \param fic: fault injection tracking context
+ * \param fi_name: name of fault injection
+ * \param result: points to uint64_t to be set to the result
+ *
+ * This lets you get a random number from an externally-set range, set using a
+ * fault injection syntax like "myfault(123..456)".  That will cause us to
+ * return a number between those two inclusive, from the seeded PRNG.
+ *
+ * This is useful when you used lws_fi() with its own fault name to decide
+ * whether to inject the fault, and then the code to cause the fault needs
+ * additional constrained pseudo-random fuzzing for, eg, delays before issuing
+ * the fault.
+ *
+ * Returns 0 if \p *result is set, else nonzero for failure.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_fi_range(const lws_fi_ctx_t *fic, const char *name, uint64_t *result);
+
+/**
+ * lws_fi_add() - add an allocated copy of fault injection to a context
+ *
+ * \param fic: fault injection tracking context
+ * \param fi: the fault injection details
+ *
+ * This allocates a copy of \p fi and attaches it to the fault injection context
+ * \p fic.  \p fi can go out of scope after this safely.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi);
+
+/**
+ * lws_fi_remove() - remove an allocated copy of fault injection from a context
+ *
+ * \param fic: fault injection tracking context
+ * \param name: the fault injection name to remove
+ *
+ * This looks for the named fault injection and removes and destroys it from
+ * the specified fault injection context
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_fi_remove(lws_fi_ctx_t *fic, const char *name);
+
+/**
+ * lws_fi_import() - transfers all the faults from one context to another
+ *
+ * \param fic_dest: the fault context to receive the faults
+ * \param fic_src: the fault context that will be emptied out into \p fic_dest
+ *
+ * This is used to initialize created object fault injection contexts from
+ * the caller.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_fi_import(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src);
+
+/**
+ * lws_fi_inherit_copy() - attach copies of matching fault injection objects to dest
+ *
+ * \param fic_dest: destination Fault Injection context
+ * \param fic_src: parent fault context that may contain matching rules
+ * \param scope: the name of the path match required, eg, "vh"
+ * \param value: the dynamic name of our match, eg, "myvhost"
+ *
+ * If called with scope "vh" and value "myvhost", then matches faults starting
+ * "vh=myvhost/", strips that part of the name if it matches and makes a copy
+ * of the rule with the modified name attached to the destination Fault Injection
+ * context.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_fi_inherit_copy(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src,
+                   const char *scope, const char *value);
+
+/**
+ * lws_fi_destroy() - removes all allocated fault injection entries
+ *
+ * \param fic: fault injection tracking context
+ *
+ * This walks any allocated fault injection entries in \p fic and detaches and
+ * destroys them.  It doesn't try to destroc \p fic itself, since this is
+ * not usually directly allocated.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_fi_destroy(const lws_fi_ctx_t *fic);
+
+/**
+ * lws_fi_deserialize() - adds fault in string form to Fault Injection Context
+ *
+ * \p fic: the fault injection context
+ * \p sers: the string serializing the desired fault details
+ *
+ * This turns a string like "ss=captive_portal_detect/wsi/dnsfail(10%)" into
+ * a fault injection struct added to the fault injection context \p fic
+ *
+ * You can prepare the context creation info .fic with these before creating
+ * the context, and use namespace paths on those to target other objects.
+ */
+
+LWS_VISIBLE LWS_EXTERN void
+lws_fi_deserialize(lws_fi_ctx_t *fic, const char *sers);
+
+LWS_VISIBLE LWS_EXTERN int
+_lws_fi_user_wsi_fi(struct lws *wsi, const char *name);
+LWS_VISIBLE LWS_EXTERN int
+_lws_fi_user_context_fi(struct lws_context *ctx, const char *name);
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+struct lws_ss_handle;
+LWS_VISIBLE LWS_EXTERN int
+_lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *name);
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+struct lws_sspc_handle;
+LWS_VISIBLE LWS_EXTERN int
+_lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *name);
+#endif
+#endif
+
+#define lws_fi_user_wsi_fi(_wsi, _name) _lws_fi_user_wsi_fi(_wsi, _name)
+#define lws_fi_user_context_fi(_ctx, _name) _lws_fi_user_context_fi(_ctx, _name)
+#define lws_fi_user_ss_fi(_h, _name) _lws_fi_user_ss_fi(_h, _name)
+#define lws_fi_user_sspc_fi(_h, _name) _lws_fi_user_sspc_fi(_h, _name)
+
+#else
+
+/*
+ * Helper so we can leave lws_fi() calls embedded in the code being tested,
+ * if fault injection is not enabled then it just always says "no" at buildtime.
+ */
+
+#define lws_fi(_fi_name, _fic) (0)
+#define lws_fi_destroy(_x)
+#define lws_fi_inherit_copy(_a, _b, _c, _d)
+#define lws_fi_deserialize(_x, _y)
+#define lws_fi_user_wsi_fi(_wsi, _name) (0)
+#define lws_fi_user_context_fi(_wsi, _name) (0)
+#define lws_fi_user_ss_fi(_h, _name) (0)
+#define lws_fi_user_sspc_fi(_h, _name) (0)
+
+#endif
diff --git a/include/libwebsockets/lws-freertos.h b/include/libwebsockets/lws-freertos.h
new file mode 100644 (file)
index 0000000..a787229
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is included from libwebsockets.h if LWS_PLAT_FREERTOS
+ */
+
+typedef int lws_sockfd_type;
+typedef int lws_filefd_type;
+
+#if defined(LWS_AMAZON_RTOS)
+#include <FreeRTOS.h>
+#include <event_groups.h>
+#include <string.h>
+#include "timers.h"
+#include <lwip/sockets.h>
+
+/*
+ * Later lwip (at least 2.1.12) already defines these in its own headers
+ * protected by the same test as used here... if POLLIN / POLLOUT already exist
+ * then assume no need to declare those and struct pollfd.
+ *
+ * Older lwip needs these declarations done here.
+ */
+
+#if !defined(POLLIN) && !defined(POLLOUT)
+
+struct pollfd {
+       lws_sockfd_type fd; /**< fd related to */
+       short events; /**< which POLL... events to respond to */
+       short revents; /**< which POLL... events occurred */
+};
+#define POLLIN         0x0001
+#define POLLPRI                0x0002
+#define POLLOUT                0x0004
+#define POLLERR                0x0008
+#define POLLHUP                0x0010
+#define POLLNVAL       0x0020
+
+#endif
+
+#else /* LWS_AMAZON_RTOS */
+#include <freertos/FreeRTOS.h>
+#include <freertos/event_groups.h>
+#include <string.h>
+#include "esp_wifi.h"
+#include "esp_system.h"
+#include "esp_event.h"
+//#include "esp_event_loop.h"
+#include "nvs.h"
+#include "driver/gpio.h"
+#include "esp_spi_flash.h"
+#include "freertos/timers.h"
+
+#if defined(LWS_ESP_PLATFORM)
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+#if defined(LWS_WITH_DRIVERS)
+#include "libwebsockets/lws-gpio.h"
+extern const lws_gpio_ops_t lws_gpio_plat;
+#endif
+#endif
+
+#endif /* LWS_AMAZON_RTOS */
+
+#if !defined(CONFIG_FREERTOS_HZ)
+#define CONFIG_FREERTOS_HZ 100
+#endif
index 29405bd..e7d31af 100644 (file)
@@ -1,24 +1,25 @@
 /*
- * libwebsockets - fulltext search
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup search Search
index dfb7de6..6095f68 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup generic AES
@@ -62,6 +63,7 @@ enum enum_aes_padding {
 /* include/libwebsockets/lws-jwk.h must be included before this */
 
 #define LWS_AES_BLOCKSIZE 128
+#define LWS_AES_CBC_BLOCKLEN 16
 
 struct lws_genaes_ctx {
 #if defined(LWS_WITH_MBEDTLS)
index d82fb60..0018231 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*
@@ -58,6 +59,13 @@ enum lws_gencrypto_rsa_tok {
        LWS_GENCRYPTO_RSA_KEYEL_DQ,
        LWS_GENCRYPTO_RSA_KEYEL_QI,
 
+       /* we don't actively use these if given, but may come from COSE */
+
+       LWS_GENCRYPTO_RSA_KEYEL_OTHER,
+       LWS_GENCRYPTO_RSA_KEYEL_RI,
+       LWS_GENCRYPTO_RSA_KEYEL_DI,
+       LWS_GENCRYPTO_RSA_KEYEL_TI,
+
        LWS_GENCRYPTO_RSA_KEYEL_COUNT
 };
 
@@ -88,10 +96,10 @@ enum lws_gencrypto_aes_tok {
  * type.
  */
 
-struct lws_gencrypto_keyelem {
+typedef struct lws_gencrypto_keyelem {
        uint8_t *buf;
        uint32_t len;
-};
+} lws_gc_elem_t;
 
 
 /**
@@ -115,3 +123,15 @@ lws_gencrypto_bits_to_bytes(int bits);
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_base64_size(int bytes);
+
+/**
+ * lws_gencrypto_padded_length() - returns PKCS#5/#7 padded length
+ *
+ * @param blocksize - blocksize to pad to
+ * @param len - Length of input to pad
+ *
+ * Returns the length of a buffer originally of size len after PKCS#5 or PKCS#7
+ * padding has been applied to it.
+ */
+LWS_VISIBLE LWS_EXTERN size_t
+lws_gencrypto_padded_length(size_t block_size, size_t len);
index 7db796e..5ae1d2f 100644 (file)
@@ -1,24 +1,25 @@
 /*
- * libwebsockets - Generic Elliptic Curve Encryption
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 enum enum_genec_alg {
@@ -71,7 +72,7 @@ struct lws_ec_curves {
  * \param context: your lws_context (for RNG access)
  * \param curve_table: NULL, enabling P-256, P-384 and P-521, or a replacement
  *                    struct lws_ec_curves array, terminated by an entry with
- *                    .name = NULL, of curves you want to whitelist
+ *                    .name = NULL, of curves you want to allow
  *
  * Initializes a genecdh
  */
@@ -117,7 +118,7 @@ lws_genecdh_compute_shared_secret(struct lws_genec_ctx *ctx, uint8_t *ss,
  * \param context: your lws_context (for RNG access)
  * \param curve_table: NULL, enabling P-256, P-384 and P-521, or a replacement
  *                    struct lws_ec_curves array, terminated by an entry with
- *                    .name = NULL, of curves you want to whitelist
+ *                    .name = NULL, of curves you want to allow
  *
  * Initializes a genecdh
  */
@@ -146,7 +147,7 @@ lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name,
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_genecdsa_set_key(struct lws_genec_ctx *ctx,
-                    struct lws_gencrypto_keyelem *el);
+                    const struct lws_gencrypto_keyelem *el);
 
 /** lws_genecdsa_hash_sig_verify_jws() - Verifies a JWS ECDSA signature on a given hash
  *
@@ -183,7 +184,7 @@ lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
  * \param sig: pointer to buffer to take signature
  * \param sig_len: length of the buffer (must be >= length of key N)
  *
- * Returns <0 for error, or 0 for success.
+ * Returns <0 for error, or >=0 for success.
  *
  * This creates a JWS ECDSA signature for a hash you already computed and provide.
  *
index 6fe5dbd..f27c3b9 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup generichash Generic Hash
@@ -73,19 +74,27 @@ struct lws_genhmac_ctx {
        mbedtls_md_context_t ctx;
 #else
        const EVP_MD *evp_type;
+
+#if defined(LWS_HAVE_EVP_PKEY_new_raw_private_key)
+       EVP_MD_CTX *ctx;
+       EVP_PKEY *key;
+#else
 #if defined(LWS_HAVE_HMAC_CTX_new)
         HMAC_CTX *ctx;
 #else
         HMAC_CTX ctx;
 #endif
 #endif
+
+#endif
 };
 
 /** lws_genhash_size() - get hash size in bytes
  *
  * \param type:        one of LWS_GENHASH_TYPE_...
  *
- * Returns number of bytes in this type of hash
+ * Returns number of bytes in this type of hash, if the hash type is unknown, it
+ * will return 0.
  */
 LWS_VISIBLE LWS_EXTERN size_t LWS_WARN_UNUSED_RESULT
 lws_genhash_size(enum lws_genhash_types type);
@@ -94,7 +103,8 @@ lws_genhash_size(enum lws_genhash_types type);
  *
  * \param type:        one of LWS_GENHASH_TYPE_...
  *
- * Returns number of bytes in this type of hmac
+ * Returns number of bytes in this type of hmac, if the hmac type is unknown, it
+ * will return 0.
  */
 LWS_VISIBLE LWS_EXTERN size_t LWS_WARN_UNUSED_RESULT
 lws_genhmac_size(enum lws_genhmac_types type);
index eb91629..3f23031 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup genericRSA Generic RSA
@@ -73,7 +74,8 @@ struct lws_genrsa_ctx {
  * This and related APIs operate identically with OpenSSL or mbedTLS backends.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
+lws_genrsa_create(struct lws_genrsa_ctx *ctx,
+                 const struct lws_gencrypto_keyelem *el,
                  struct lws_context *context, enum enum_genrsa_mode mode,
                  enum lws_genhash_types oaep_hashid);
 
@@ -214,7 +216,7 @@ lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in,
  * \param sig: pointer to buffer to take signature
  * \param sig_len: length of the buffer (must be >= length of key N)
  *
- * Returns <0 for error, or 0 for success.
+ * Returns <0 for error, or \p sig_len for success.
  *
  * This creates an RSA signature for a hash you already computed and provide.
  * You should have created the hash before calling this by iterating over the
diff --git a/include/libwebsockets/lws-gpio.h b/include/libwebsockets/lws-gpio.h
new file mode 100644 (file)
index 0000000..f86620a
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Generic GPIO ops
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is like an abstract class for gpio, a real implementation provides
+ * functions for the ops that use the underlying OS gpio arrangements.
+ */
+
+#if !defined(__LWS_GPIO_H__)
+#define __LWS_GPIO_H__
+
+typedef int _lws_plat_gpio_t;
+
+typedef enum {
+       LWSGGPIO_IRQ_NONE,
+       LWSGGPIO_IRQ_RISING,
+       LWSGGPIO_IRQ_FALLING,
+       LWSGGPIO_IRQ_CHANGE,
+       LWSGGPIO_IRQ_LOW,
+       LWSGGPIO_IRQ_HIGH
+} lws_gpio_irq_t;
+
+enum {
+       LWSGGPIO_FL_READ                        = (1 << 0),
+       LWSGGPIO_FL_WRITE                       = (1 << 1),
+       LWSGGPIO_FL_PULLUP                      = (1 << 2),
+       LWSGGPIO_FL_PULLDOWN                    = (1 << 3),
+       LWSGGPIO_FL_START_LOW                   = (1 << 4),
+};
+
+typedef void (*lws_gpio_irq_cb_t)(void *arg);
+
+typedef struct lws_gpio_ops {
+       void (*mode)(_lws_plat_gpio_t gpio, int flags);
+       int (*read)(_lws_plat_gpio_t gpio);
+       void (*set)(_lws_plat_gpio_t gpio, int val);
+       int (*irq_mode)(_lws_plat_gpio_t gpio, lws_gpio_irq_t irq,
+                       lws_gpio_irq_cb_t cb, void *arg);
+} lws_gpio_ops_t;
+
+#endif
index 913e04c..2c5bd64 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /* minimal space for typical headers and CSP stuff */
@@ -212,97 +213,130 @@ struct lws_tokens {
  * add it at where specified so existing users are unaffected.
  */
 enum lws_token_indexes {
-       WSI_TOKEN_GET_URI                                       =  0,
-       WSI_TOKEN_POST_URI                                      =  1,
-       WSI_TOKEN_OPTIONS_URI                                   =  2,
-       WSI_TOKEN_HOST                                          =  3,
-       WSI_TOKEN_CONNECTION                                    =  4,
-       WSI_TOKEN_UPGRADE                                       =  5,
-       WSI_TOKEN_ORIGIN                                        =  6,
-       WSI_TOKEN_DRAFT                                         =  7,
-       WSI_TOKEN_CHALLENGE                                     =  8,
-       WSI_TOKEN_EXTENSIONS                                    =  9,
-       WSI_TOKEN_KEY1                                          = 10,
-       WSI_TOKEN_KEY2                                          = 11,
-       WSI_TOKEN_PROTOCOL                                      = 12,
-       WSI_TOKEN_ACCEPT                                        = 13,
-       WSI_TOKEN_NONCE                                         = 14,
-       WSI_TOKEN_HTTP                                          = 15,
-       WSI_TOKEN_HTTP2_SETTINGS                                = 16,
-       WSI_TOKEN_HTTP_ACCEPT                                   = 17,
-       WSI_TOKEN_HTTP_AC_REQUEST_HEADERS                       = 18,
-       WSI_TOKEN_HTTP_IF_MODIFIED_SINCE                        = 19,
-       WSI_TOKEN_HTTP_IF_NONE_MATCH                            = 20,
-       WSI_TOKEN_HTTP_ACCEPT_ENCODING                          = 21,
-       WSI_TOKEN_HTTP_ACCEPT_LANGUAGE                          = 22,
-       WSI_TOKEN_HTTP_PRAGMA                                   = 23,
-       WSI_TOKEN_HTTP_CACHE_CONTROL                            = 24,
-       WSI_TOKEN_HTTP_AUTHORIZATION                            = 25,
-       WSI_TOKEN_HTTP_COOKIE                                   = 26,
-       WSI_TOKEN_HTTP_CONTENT_LENGTH                           = 27,
-       WSI_TOKEN_HTTP_CONTENT_TYPE                             = 28,
-       WSI_TOKEN_HTTP_DATE                                     = 29,
-       WSI_TOKEN_HTTP_RANGE                                    = 30,
-       WSI_TOKEN_HTTP_REFERER                                  = 31,
-       WSI_TOKEN_KEY                                           = 32,
-       WSI_TOKEN_VERSION                                       = 33,
-       WSI_TOKEN_SWORIGIN                                      = 34,
-
-       WSI_TOKEN_HTTP_COLON_AUTHORITY                          = 35,
-       WSI_TOKEN_HTTP_COLON_METHOD                             = 36,
-       WSI_TOKEN_HTTP_COLON_PATH                               = 37,
-       WSI_TOKEN_HTTP_COLON_SCHEME                             = 38,
-       WSI_TOKEN_HTTP_COLON_STATUS                             = 39,
-
-       WSI_TOKEN_HTTP_ACCEPT_CHARSET                           = 40,
-       WSI_TOKEN_HTTP_ACCEPT_RANGES                            = 41,
-       WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN              = 42,
-       WSI_TOKEN_HTTP_AGE                                      = 43,
-       WSI_TOKEN_HTTP_ALLOW                                    = 44,
-       WSI_TOKEN_HTTP_CONTENT_DISPOSITION                      = 45,
-       WSI_TOKEN_HTTP_CONTENT_ENCODING                         = 46,
-       WSI_TOKEN_HTTP_CONTENT_LANGUAGE                         = 47,
-       WSI_TOKEN_HTTP_CONTENT_LOCATION                         = 48,
-       WSI_TOKEN_HTTP_CONTENT_RANGE                            = 49,
-       WSI_TOKEN_HTTP_ETAG                                     = 50,
-       WSI_TOKEN_HTTP_EXPECT                                   = 51,
-       WSI_TOKEN_HTTP_EXPIRES                                  = 52,
-       WSI_TOKEN_HTTP_FROM                                     = 53,
-       WSI_TOKEN_HTTP_IF_MATCH                                 = 54,
-       WSI_TOKEN_HTTP_IF_RANGE                                 = 55,
-       WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE                      = 56,
-       WSI_TOKEN_HTTP_LAST_MODIFIED                            = 57,
-       WSI_TOKEN_HTTP_LINK                                     = 58,
-       WSI_TOKEN_HTTP_LOCATION                                 = 59,
-       WSI_TOKEN_HTTP_MAX_FORWARDS                             = 60,
-       WSI_TOKEN_HTTP_PROXY_AUTHENTICATE                       = 61,
-       WSI_TOKEN_HTTP_PROXY_AUTHORIZATION                      = 62,
-       WSI_TOKEN_HTTP_REFRESH                                  = 63,
-       WSI_TOKEN_HTTP_RETRY_AFTER                              = 64,
-       WSI_TOKEN_HTTP_SERVER                                   = 65,
-       WSI_TOKEN_HTTP_SET_COOKIE                               = 66,
-       WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY                = 67,
-       WSI_TOKEN_HTTP_TRANSFER_ENCODING                        = 68,
-       WSI_TOKEN_HTTP_USER_AGENT                               = 69,
-       WSI_TOKEN_HTTP_VARY                                     = 70,
-       WSI_TOKEN_HTTP_VIA                                      = 71,
-       WSI_TOKEN_HTTP_WWW_AUTHENTICATE                         = 72,
-
-       WSI_TOKEN_PATCH_URI                                     = 73,
-       WSI_TOKEN_PUT_URI                                       = 74,
-       WSI_TOKEN_DELETE_URI                                    = 75,
-
-       WSI_TOKEN_HTTP_URI_ARGS                                 = 76,
-       WSI_TOKEN_PROXY                                         = 77,
-       WSI_TOKEN_HTTP_X_REAL_IP                                = 78,
-       WSI_TOKEN_HTTP1_0                                       = 79,
-       WSI_TOKEN_X_FORWARDED_FOR                               = 80,
-       WSI_TOKEN_CONNECT                                       = 81,
-       WSI_TOKEN_HEAD_URI                                      = 82,
-       WSI_TOKEN_TE                                            = 83,
-       WSI_TOKEN_REPLAY_NONCE                                  = 84,
-       WSI_TOKEN_COLON_PROTOCOL                                = 85,
-       WSI_TOKEN_X_AUTH_TOKEN                                  = 86,
+       WSI_TOKEN_GET_URI, /* 0 */
+       WSI_TOKEN_POST_URI,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_OPTIONS_URI,
+#endif
+       WSI_TOKEN_HOST,
+       WSI_TOKEN_CONNECTION,
+       WSI_TOKEN_UPGRADE, /* 5 */
+       WSI_TOKEN_ORIGIN,
+#if defined(LWS_ROLE_WS) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_DRAFT,
+#endif
+       WSI_TOKEN_CHALLENGE,
+#if defined(LWS_ROLE_WS) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_EXTENSIONS,
+       WSI_TOKEN_KEY1, /* 10 */
+       WSI_TOKEN_KEY2,
+       WSI_TOKEN_PROTOCOL,
+       WSI_TOKEN_ACCEPT,
+       WSI_TOKEN_NONCE,
+#endif
+       WSI_TOKEN_HTTP,
+#if defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_HTTP2_SETTINGS, /* 16 */
+#endif
+       WSI_TOKEN_HTTP_ACCEPT,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_HTTP_AC_REQUEST_HEADERS,
+#endif
+       WSI_TOKEN_HTTP_IF_MODIFIED_SINCE,
+       WSI_TOKEN_HTTP_IF_NONE_MATCH, /* 20 */
+       WSI_TOKEN_HTTP_ACCEPT_ENCODING,
+       WSI_TOKEN_HTTP_ACCEPT_LANGUAGE,
+       WSI_TOKEN_HTTP_PRAGMA,
+       WSI_TOKEN_HTTP_CACHE_CONTROL,
+       WSI_TOKEN_HTTP_AUTHORIZATION,
+       WSI_TOKEN_HTTP_COOKIE,
+       WSI_TOKEN_HTTP_CONTENT_LENGTH, /* 27 */
+       WSI_TOKEN_HTTP_CONTENT_TYPE,
+       WSI_TOKEN_HTTP_DATE,
+       WSI_TOKEN_HTTP_RANGE,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_HTTP_REFERER,
+#endif
+#if defined(LWS_ROLE_WS) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_KEY,
+       WSI_TOKEN_VERSION,
+       WSI_TOKEN_SWORIGIN,
+#endif
+#if defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_HTTP_COLON_AUTHORITY,
+       WSI_TOKEN_HTTP_COLON_METHOD,
+       WSI_TOKEN_HTTP_COLON_PATH,
+       WSI_TOKEN_HTTP_COLON_SCHEME,
+       WSI_TOKEN_HTTP_COLON_STATUS,
+#endif
+
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_HTTP_ACCEPT_CHARSET,
+#endif
+       WSI_TOKEN_HTTP_ACCEPT_RANGES,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,
+#endif
+       WSI_TOKEN_HTTP_AGE,
+       WSI_TOKEN_HTTP_ALLOW,
+       WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
+       WSI_TOKEN_HTTP_CONTENT_ENCODING,
+       WSI_TOKEN_HTTP_CONTENT_LANGUAGE,
+       WSI_TOKEN_HTTP_CONTENT_LOCATION,
+       WSI_TOKEN_HTTP_CONTENT_RANGE,
+       WSI_TOKEN_HTTP_ETAG,
+       WSI_TOKEN_HTTP_EXPECT,
+       WSI_TOKEN_HTTP_EXPIRES,
+       WSI_TOKEN_HTTP_FROM,
+       WSI_TOKEN_HTTP_IF_MATCH,
+       WSI_TOKEN_HTTP_IF_RANGE,
+       WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE,
+       WSI_TOKEN_HTTP_LAST_MODIFIED,
+       WSI_TOKEN_HTTP_LINK,
+       WSI_TOKEN_HTTP_LOCATION,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_HTTP_MAX_FORWARDS,
+       WSI_TOKEN_HTTP_PROXY_AUTHENTICATE,
+       WSI_TOKEN_HTTP_PROXY_AUTHORIZATION,
+#endif
+       WSI_TOKEN_HTTP_REFRESH,
+       WSI_TOKEN_HTTP_RETRY_AFTER,
+       WSI_TOKEN_HTTP_SERVER,
+       WSI_TOKEN_HTTP_SET_COOKIE,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY,
+#endif
+       WSI_TOKEN_HTTP_TRANSFER_ENCODING,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_HTTP_USER_AGENT,
+       WSI_TOKEN_HTTP_VARY,
+       WSI_TOKEN_HTTP_VIA,
+       WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
+#endif
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_PATCH_URI,
+       WSI_TOKEN_PUT_URI,
+       WSI_TOKEN_DELETE_URI,
+#endif
+
+       WSI_TOKEN_HTTP_URI_ARGS,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_PROXY,
+       WSI_TOKEN_HTTP_X_REAL_IP,
+#endif
+       WSI_TOKEN_HTTP1_0,
+       WSI_TOKEN_X_FORWARDED_FOR,
+       WSI_TOKEN_CONNECT,
+       WSI_TOKEN_HEAD_URI,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_TE,
+       WSI_TOKEN_REPLAY_NONCE, /* ACME */
+#endif
+#if defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
+       WSI_TOKEN_COLON_PROTOCOL,
+#endif
+       WSI_TOKEN_X_AUTH_TOKEN,
+       WSI_TOKEN_DSS_SIGNATURE,
 
        /****** add new things just above ---^ ******/
 
@@ -323,7 +357,7 @@ enum lws_token_indexes {
 
        /* parser state additions, no storage associated */
        WSI_TOKEN_NAME_PART,
-#if defined(LWS_WITH_CUSTOM_HEADERS)
+#if defined(LWS_WITH_CUSTOM_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
        WSI_TOKEN_UNKNOWN_VALUE_PART,
 #endif
        WSI_TOKEN_SKIPPING,
@@ -336,6 +370,19 @@ struct lws_token_limits {
        unsigned short token_limit[WSI_TOKEN_COUNT]; /**< max chars for this token */
 };
 
+enum lws_h2_settings {
+       H2SET_HEADER_TABLE_SIZE = 1,
+       H2SET_ENABLE_PUSH,
+       H2SET_MAX_CONCURRENT_STREAMS,
+       H2SET_INITIAL_WINDOW_SIZE,
+       H2SET_MAX_FRAME_SIZE,
+       H2SET_MAX_HEADER_LIST_SIZE,
+       H2SET_RESERVED7,
+       H2SET_ENABLE_CONNECT_PROTOCOL, /* defined in mcmanus-httpbis-h2-ws-02 */
+
+       H2SET_COUNT /* always last */
+};
+
 /**
  * lws_token_to_string() - returns a textual representation of a hdr token index
  *
@@ -447,8 +494,55 @@ LWS_VISIBLE LWS_EXTERN int
 lws_hdr_custom_copy(struct lws *wsi, char *dst, int len, const char *name,
                    int nlen);
 
+typedef void (*lws_hdr_custom_fe_cb_t)(const char *name, int nlen, void *opaque);
+/**
+ * lws_hdr_custom_name_foreach() - Iterate the custom header names
+ *
+ * \param wsi: websocket connection
+ * \param cb: callback for each custom header name
+ * \param opaque: ignored by lws except to pass to callback
+ *
+ * Lws knows about 100 common http headers, and parses them into indexes when
+ * it recognizes them.  When it meets a header that it doesn't know, it stores
+ * the name and value directly, and you can look them up using
+ * lws_hdr_custom_length() and lws_hdr_custom_copy().
+ * 
+ * This api returns -1 on error else 0. Use lws_hdr_custom_copy() to get the
+ * values of headers. Lws must be built with LWS_WITH_CUSTOM_HEADERS (on by
+ * default) to use this api.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_hdr_custom_name_foreach(struct lws *wsi, lws_hdr_custom_fe_cb_t cb, void *opaque);
+
+/**
+ * lws_get_urlarg_by_name_safe() - get copy and return length of y for x=y urlargs
+ *
+ * \param wsi: the connection to check
+ * \param name: the arg name, like "token" or "token="
+ * \param buf: the buffer to receive the urlarg (including the name= part)
+ * \param len: the length of the buffer to receive the urlarg
+ *
+ * Returns -1 if not present, else the length of y in the urlarg name=y.  If
+ * zero or greater, then buf contains a copy of the string y.  Any = after the
+ * name match is trimmed off if the name does not end with = itself.
+ *
+ * This returns the explicit length and so can deal with binary blobs that are
+ * percent-encoded.  It also makes sure buf has a NUL just after the valid
+ * length so it can work with NUL-based apis if you don't care about truncation.
+ *
+ * buf may have been written even when -1 is returned indicating no match.
+ *
+ * Use this in place of lws_get_urlarg_by_name() that does not return an
+ * explicit length.
+ *
+ * Use lws_get_urlarg_by_name_safe() instead of this, which returns the length.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_get_urlarg_by_name_safe(struct lws *wsi, const char *name, char *buf, int len);
+
 /**
  * lws_get_urlarg_by_name() - return pointer to arg value if present
+ *
  * \param wsi: the connection to check
  * \param name: the arg name, like "token="
  * \param buf: the buffer to receive the urlarg (including the name= part)
@@ -456,9 +550,16 @@ lws_hdr_custom_copy(struct lws *wsi, char *dst, int len, const char *name,
  *
  *     Returns NULL if not found or a pointer inside buf to just after the
  *     name= part.
+ *
+ * This assumed the argument can be represented with a NUL-terminated string.
+ * It can't correctly deal with binary values encoded with %XX, eg. %00 will
+ * be understood to terminate the string.
+ *
+ * Use lws_get_urlarg_by_name_safe() instead of this, which returns the length.
  */
 LWS_VISIBLE LWS_EXTERN const char *
-lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len);
+lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len)
+/* LWS_WARN_DEPRECATED */;
 ///@}
 
 /*! \defgroup HTTP-headers-create HTTP headers: create
@@ -502,7 +603,7 @@ lws_add_http_header_status(struct lws *wsi,
  * lws_add_http_header_by_name() - append named header and value
  *
  * \param wsi: the connection to check
- * \param name: the hdr name, like "my-header"
+ * \param name: the hdr name, like "my-header:"
  * \param value: the value after the = for this header
  * \param length: the length of the value
  * \param p: pointer to current position in buffer pointer
@@ -606,6 +707,18 @@ lws_add_http_common_headers(struct lws *wsi, unsigned int code,
                            const char *content_type, lws_filepos_t content_len,
                            unsigned char **p, unsigned char *end);
 
+enum {
+       LWSHUMETH_GET,
+       LWSHUMETH_POST,
+       LWSHUMETH_OPTIONS,
+       LWSHUMETH_PUT,
+       LWSHUMETH_PATCH,
+       LWSHUMETH_DELETE,
+       LWSHUMETH_CONNECT,
+       LWSHUMETH_HEAD,
+       LWSHUMETH_COLON_PATH,
+};
+
 /**
  * lws_http_get_uri_and_method() - Get information on method and url
  *
@@ -613,17 +726,7 @@ lws_add_http_common_headers(struct lws *wsi, unsigned int code,
  * \param puri_ptr: points to pointer to set to url
  * \param puri_len: points to int to set to uri length
  *
- * Returns -1 or method index
- *
- * GET      0
- * POST     1
- * OPTIONS  2
- * PUT      3
- * PATCH    4
- * DELETE   5
- * CONNECT  6
- * HEAD     7
- * :path    8
+ * Returns -1 or method index as one of the LWSHUMETH_ constants
  *
  * If returns method, *puri_ptr is set to the method's URI string and *puri_len
  * to its length
@@ -684,6 +787,53 @@ lws_urldecode(char *string, const char *escaped, int len);
 ///@}
 
 /**
+ * lws_http_date_render_from_unix() - render unixtime as RFC7231 date string
+ *
+ * \param buf:         Destination string buffer
+ * \param len:         avilable length of dest string buffer in bytes
+ * \param t:           pointer to the time_t to render
+ *
+ * Returns 0 if time_t is rendered into the string buffer successfully, else
+ * nonzero.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_http_date_render_from_unix(char *buf, size_t len, const time_t *t);
+
+/**
+ * lws_http_date_parse_unix() - parse a RFC7231 date string into unixtime
+ *
+ * \param b:           Source string buffer
+ * \param len:         avilable length of source string buffer in bytes
+ * \param t:           pointer to the destination time_t to set
+ *
+ * Returns 0 if string buffer parsed as RFC7231 time successfully, and
+ * *t set to the parsed unixtime, else return nonzero.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_http_date_parse_unix(const char *b, size_t len, time_t *t);
+
+/**
+ * lws_http_check_retry_after() - increase a timeout if retry-after present
+ *
+ * \param wsi:         http stream this relates to
+ * \param us_interval_in_out: default us retry interval on entry may be updated
+ *
+ * This function may extend the incoming retry interval if the server has
+ * requested that using retry-after: header.  It won't reduce the incoming
+ * retry interval, only leave it alone or increase it.
+ *
+ * *us_interval_in_out should be set to a default retry interval on entry, if
+ * the wsi has a retry-after time or interval that resolves to an interval
+ * longer than the entry *us_interval_in_out, that will be updated to the longer
+ * interval and return 0.
+ *
+ * If no usable retry-after or the time is now or in the past,
+ * *us_interval_in_out is left alone and the function returns nonzero.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_http_check_retry_after(struct lws *wsi, lws_usec_t *us_interval_in_out);
+
+/**
  * lws_return_http_status() - Return simple http status
  * \param wsi:         Websocket instance (available from user callback)
  * \param code:                Status index, eg, 404
@@ -716,7 +866,7 @@ lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
  * lws_http_transaction_completed() - wait for new http transaction or close
  * \param wsi: websocket connection
  *
- *     Returns 1 if the HTTP connection must close now
+ *     Returns nonzero if the HTTP connection must close now
  *     Returns 0 and resets connection to wait for new HTTP header /
  *       transaction if possible
  */
@@ -745,6 +895,24 @@ LWS_VISIBLE LWS_EXTERN int
 lws_http_mark_sse(struct lws *wsi);
 
 /**
+ * lws_h2_client_stream_long_poll_rxonly() - h2 stream to immortal read-only
+ *
+ * \param wsi: h2 stream client wsi
+ *
+ * Send END_STREAM-flagged zero-length DATA frame to set client stream wsi into
+ * half-closed (local) and remote into half-closed (remote).  Set the client
+ * stream wsi to be immortal (not subject to timeouts).
+ *
+ * Used if the remote server supports immortal long poll to put the stream into
+ * a read-only state where it can wait as long as needed for rx.
+ *
+ * Returns 0 if the process (which happens asynchronously) started or non-zero
+ * if it wasn't an h2 stream.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_h2_client_stream_long_poll_rxonly(struct lws *wsi);
+
+/**
  * lws_http_compression_apply() - apply an http compression transform
  *
  * \param wsi: the wsi to apply the compression transform to
@@ -769,8 +937,94 @@ lws_http_mark_sse(struct lws *wsi);
  * LWS_WITH_HTTP_STREAM_COMPRESSION set, then a NOP is provided for this api,
  * allowing user code to build either way and use compression if available.
  */
-LWS_VISIBLE int
+LWS_VISIBLE LWS_EXTERN int
 lws_http_compression_apply(struct lws *wsi, const char *name,
                           unsigned char **p, unsigned char *end, char decomp);
+
+/**
+ * lws_http_is_redirected_to_get() - true if redirected to GET
+ *
+ * \param wsi: the wsi to check
+ *
+ * Check if the wsi is currently in GET mode, after, eg, doing a POST and
+ * receiving a 303.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_http_is_redirected_to_get(struct lws *wsi);
+
+/**
+ * lws_http_cookie_get() - return copy of named cookie if present
+ *
+ * \param wsi: the wsi to check
+ * \param name: name of the cookie
+ * \param buf: buffer to store the cookie contents into
+ * \param max_len: on entry, maximum length of buf... on exit, used len of buf
+ *
+ * If no cookie header, or no cookie of the requested name, or the value is
+ * larger than can fit in buf, returns nonzero.
+ *
+ * If the cookie is found, copies its value into buf with a terminating NUL,
+ * sets *max_len to the used length, and returns 0.
+ *
+ * This handles the parsing of the possibly multi-cookie header string and
+ * terminating the requested cookie at the next ; if present.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_http_cookie_get(struct lws *wsi, const char *name, char *buf, size_t *max);
+
+/**
+ * lws_http_client_http_error() - determine if the response code indicates an error
+ *
+ * \param code: the response code to test
+ *
+ * Returns nonzero if the code indicates an error, else zero if reflects a
+ * non-error condition
+ */
+#define lws_http_client_http_resp_is_error(code) (!(code < 400))
+
+/**
+ * lws_h2_update_peer_txcredit() - manually update stream peer tx credit
+ *
+ * \param wsi: the h2 child stream whose peer credit to change
+ * \param sid: the stream ID, or LWS_H2_STREAM_SID for the wsi stream ID
+ * \param bump: signed change to confer upon peer tx credit for sid
+ *
+ * In conjunction with LCCSCF_H2_MANUAL_RXFLOW flag, allows the user code to
+ * selectively starve the remote peer of the ability to send us data on a client
+ * connection.
+ *
+ * Normally lws sends an initial window size for the peer to send to it of 0,
+ * but during the header phase it sends a WINDOW_UPDATE to increase the amount
+ * available.  LCCSCF_H2_MANUAL_RXFLOW restricts this initial increase in tx
+ * credit for the stream, before it has been asked to send us anything, to the
+ * amount specified in the client info .manual_initial_tx_credit member, and
+ * this api can be called to send the other side permission to send us up to
+ * \p bump additional bytes.
+ *
+ * The nwsi tx credit is updated automatically for exactly what was sent to us
+ * on a stream with LCCSCF_H2_MANUAL_RXFLOW flag, but the stream's own tx credit
+ * must be handled manually by user code via this api.
+ *
+ * Returns 0 for success or nonzero for failure.
+ */
+#define LWS_H2_STREAM_SID -1
+LWS_VISIBLE LWS_EXTERN int
+lws_h2_update_peer_txcredit(struct lws *wsi, unsigned int sid, int bump);
+
+
+/**
+ * lws_h2_get_peer_txcredit_estimate() - return peer tx credit estimate
+ *
+ * \param wsi: the h2 child stream whose peer credit estimate to return
+ *
+ * Returns the estimated amount of tx credit at the peer, in other words the
+ * number of bytes the peer is authorized to send to us.
+ *
+ * It's an 'estimate' because we don't know how much is already in flight
+ * towards us and actually already used.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_h2_get_peer_txcredit_estimate(struct lws *wsi);
+
 ///@}
 
diff --git a/include/libwebsockets/lws-i2c.h b/include/libwebsockets/lws-i2c.h
new file mode 100644 (file)
index 0000000..3bd81ed
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Generic I2C ops
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is like an abstract class for i2c, a real implementation provides
+ * functions for the ops that use the underlying OS arrangements.
+ */
+
+#if !defined(__LWS_I2C_H__)
+#define __LWS_I2C_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef struct lws_i2c_ops {
+       int  (*init)(const struct lws_i2c_ops *ctx);
+       int  (*start)(const struct lws_i2c_ops *ctx);
+       void (*stop)(const struct lws_i2c_ops *ctx);
+       int  (*write)(const struct lws_i2c_ops *ctx, uint8_t data);
+       int  (*read)(const struct lws_i2c_ops *ctx);
+       void (*set_ack)(const struct lws_i2c_ops *octx, int ack);
+} lws_i2c_ops_t;
+
+/*
+ * These are implemented by calling the ops above, and so are generic
+ */
+
+LWS_VISIBLE LWS_EXTERN int
+lws_i2c_command(const lws_i2c_ops_t *ctx, uint8_t ads7, uint8_t c);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_i2c_command_list(const lws_i2c_ops_t *ctx, uint8_t ads7, const uint8_t *buf,
+                    size_t len);
+
+#endif
diff --git a/include/libwebsockets/lws-ili9341-spi.h b/include/libwebsockets/lws-ili9341-spi.h
new file mode 100644 (file)
index 0000000..70a361a
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * lws abstract display implementation for ili9341 on spi
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(__LWS_DISPLAY_ILI9341_SPI_H__)
+#define __LWS_DISPLAY_ILI9341_SPI_H__
+
+
+typedef struct lws_display_ili9341 {
+
+       lws_display_t           disp; /* use lws_display_ili9341_ops to set */
+       const lws_spi_ops_t     *spi;         /* spi ops */
+
+       const lws_gpio_ops_t    *gpio;        /* NULL or gpio ops */
+       _lws_plat_gpio_t        reset_gpio;   /* if gpio ops, nReset gpio # */
+
+       uint8_t                 spi_index; /* cs index starting from 0 */
+
+} lws_display_ili9341_t;
+
+int
+lws_display_ili9341_spi_init(const struct lws_display *disp);
+int
+lws_display_ili9341_spi_blit(const struct lws_display *disp, const uint8_t *src,
+                             lws_display_scalar x, lws_display_scalar y,
+                             lws_display_scalar w, lws_display_scalar h);
+int
+lws_display_ili9341_spi_power(const struct lws_display *disp, int state);
+
+#define lws_display_ili9341_ops \
+       .init = lws_display_ili9341_spi_init, \
+       .blit = lws_display_ili9341_spi_blit, \
+       .power = lws_display_ili9341_spi_power
+#endif
index fc0fcc0..c780c0e 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 enum lws_jws_jose_hdr_indexes {
@@ -118,6 +119,8 @@ struct lws_jose {
 
        struct lws_jws_recpient recipient[LWS_JWS_MAX_RECIPIENTS];
 
+       char typ[32];
+
        /* information from the protected header part */
        const struct lws_jose_jwe_alg *alg;
        const struct lws_jose_jwe_alg *enc_alg;
@@ -186,7 +189,8 @@ lws_gencrypto_jwe_enc_to_definition(const char *enc,
  * \param temp: parent-owned buffer to "allocate" elements into
  * \param temp_len: amount of space available in temp
  *
- * returns the amount of temp used, or -1 for error
+ * returns 0 for success, or -1 for error
+ * *\p temp_len is updated to reflect the amount of \p temp used if successful.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_jws_parse_jose(struct lws_jose *jose,
@@ -201,7 +205,8 @@ lws_jws_parse_jose(struct lws_jose *jose,
  * \param temp: parent-owned buffer to "allocate" elements into
  * \param temp_len: amount of space available in temp
  *
- * returns the amount of temp used, or -1 for error
+ * returns 0 for success, or -1 for error
+ * *\p temp_len is updated to reflect the amount of \p temp used if successful.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_jwe_parse_jose(struct lws_jose *jose,
index 3798dee..6fa9979 100644 (file)
@@ -1,24 +1,25 @@
-/*
- * libwebsockets - JSON Web Encryption
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * JWE Compact Serialization consists of
  *
index f55826a..a2205d2 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup jwk JSON Web Keys
@@ -51,7 +52,7 @@ struct lws_jwk {
        struct lws_gencrypto_keyelem e[LWS_GENCRYPTO_MAX_KEYEL_COUNT];
        /* generic meta key elements, like KID */
        struct lws_gencrypto_keyelem meta[LWS_COUNT_JWK_ELEMENTS];
-       int kty;                        /**< one of LWS_JWK_ */
+       int kty;                        /**< one of LWS_GENCRYPTO_KTY_ */
        char private_key; /* nonzero = has private key elements */
 };
 
@@ -63,6 +64,8 @@ struct lws_jwk_parse_state {
        lws_jwk_key_import_callback per_key_cb;
        void *user;
        int pos;
+       int cose_state;
+       int seen;
        unsigned short possible;
 };
 
@@ -114,19 +117,30 @@ lws_jwk_destroy(struct lws_jwk *jwk);
 LWS_VISIBLE LWS_EXTERN int
 lws_jwk_dup_oct(struct lws_jwk *jwk, const void *key, int len);
 
+#define LWSJWKF_EXPORT_PRIVATE                         (1 << 0)
+#define LWSJWKF_EXPORT_NOCRLF                          (1 << 1)
+
 /** lws_jwk_export() - Export a JSON Web key to a textual representation
  *
  * \param jwk: the JWK object to export
- * \param _private: 0 = just export public parts, 1 = export everything
+ * \param flags: control export options
  * \param p: the buffer to write the exported JWK to
  * \param len: the length of the buffer \p p in bytes... reduced by used amount
  *
  * Returns length of the used part of the buffer if OK, or -1 for error.
  *
+ * \p flags can be OR-ed together
+ *
+ * LWSJWKF_EXPORT_PRIVATE: default is only public part, set this to also export
+ *                        the private part
+ *
+ * LWSJWKF_EXPORT_NOCRLF: normally adds a CRLF at the end of the export, if
+ *                       you need to suppress it, set this flag
+ *
  * Serializes the content of the JWK into a char buffer.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_jwk_export(struct lws_jwk *jwk, int _private, char *p, int *len);
+lws_jwk_export(struct lws_jwk *jwk, int flags, char *p, int *len);
 
 /** lws_jwk_load() - Import a JSON Web key from a file
  *
@@ -179,7 +193,7 @@ lws_jwk_rfc7638_fingerprint(struct lws_jwk *jwk, char *digest32);
  * \param in: string to copy
  * \param len: length of string to copy
  *
- * Returns 0 for OK or -1 for failure
+ * Returns 0 for OK or nonzero for failure
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_jwk_strdup_meta(struct lws_jwk *jwk, enum enum_jwk_meta_tok idx,
@@ -197,7 +211,7 @@ lws_jwk_dump(struct lws_jwk *jwk);
  * \param bits: for OCT and RSA keys, the number of bits
  * \param curve: for EC keys, the name of the curve
  *
- * Returns 0 for OK or -1 for failure
+ * Returns 0 for OK or nonzero for failure
  */
 LWS_VISIBLE int
 lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk,
index ac01a78..f15d503 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup jws JSON Web Signature
@@ -110,7 +111,7 @@ lws_jws_destroy(struct lws_jws *jws);
  * in a map... it'll make a temp b64 version needed for comparison.  See below
  * for other variants.
  *
- * Returns 0 on match.
+ * Returns 0 on match, else nonzero.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk,
@@ -138,7 +139,7 @@ lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
  * (jose.payload.hdr.sig) as an aggregated string... it'll make a temp plain
  * version needed for comparison.
  *
- * Returns 0 on match.
+ * Returns 0 on match, else nonzero.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
@@ -162,7 +163,7 @@ lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
  * will end up with both maps, and can use this api version, saving needlessly
  * regenerating any temp map.
  *
- * Returns 0 on match.
+ * Returns 0 on match, else nonzero.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_jws_sig_confirm(struct lws_jws_map *map_b64, /* b64-encoded */
@@ -186,7 +187,9 @@ lws_jws_sig_confirm(struct lws_jws_map *map_b64, /* b64-encoded */
  * case \p b64_hdr may be NULL, and only the payload will be hashed before
  * signing.
  *
- * Returns the length of the encoded signature written to \p b64_sig, or -1.
+ * If successful, returns the length of the encoded signature written to
+ * \p b64_sig.  If the jose signing type is unknown, 0 is returned.  Otherwise
+ * -1 indicates failure.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws, char *b64_sig,
@@ -397,8 +400,202 @@ lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);
  * Returns either -1 if problems, or the number of bytes written to \p out.
  * If the section is not the first one, '.' is prepended.
  */
-
 LWS_VISIBLE LWS_EXTERN int
 lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
                       char *end);
+
+/**
+ * lws_jwt_signed_validate() - check a compact JWT against a key and alg
+ *
+ * \param ctx: the lws_context
+ * \param jwk: the key for checking the signature
+ * \param alg_list: the expected alg name, like "ES512"
+ * \param com: the compact JWT
+ * \param len: the length of com
+ * \param temp: a temp scratchpad
+ * \param tl: available length of temp scratchpad
+ * \param out: the output buffer to hold the validated plaintext
+ * \param out_len: on entry, max length of out; on exit, used length of out
+ *
+ * Returns nonzero if the JWT cannot be validated or the plaintext can't fit the
+ * provided output buffer, or 0 if it is validated as being signed by the
+ * provided jwk.
+ *
+ * If validated, the plaintext in the JWT is copied into out and out_len set to
+ * the used length.
+ *
+ * temp can be discarded or reused after the call returned, it's used to hold
+ * transformations of the B64 JWS in the JWT.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
+                       const char *alg_list, const char *com, size_t len,
+                       char *temp, int tl, char *out, size_t *out_len);
+
+/**
+ * lws_jwt_sign_compact() - generate a compact JWT using a key and alg
+ *
+ * \param ctx: the lws_context
+ * \param jwk: the signing key
+ * \param alg: the signing alg name, like "ES512"
+ * \param out: the output buffer to hold the signed JWT in compact form
+ * \param out_len: on entry, the length of out; on exit, the used amount of out
+ * \param temp: a temp scratchpad
+ * \param tl: available length of temp scratchpad
+ * \param format: a printf style format specification
+ * \param ...: zero or more args for the format specification
+ *
+ * Creates a JWT in a single step, from the format string and args through to
+ * outputting a well-formed compact JWT representation in out.
+ *
+ * Returns 0 if all is well and *out_len is the amount of data in out, else
+ * nonzero if failed.  Temp must be large enough to hold various intermediate
+ * representations.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
+                    const char *alg, char *out, size_t *out_len, char *temp,
+                    int tl, const char *format, ...) LWS_FORMAT(8);
+
+struct lws_jwt_sign_info {
+       const char *alg;
+       /**< entry: signing alg name, like "RS256" */
+       const char *jose_hdr;
+       /**< entry: optional JOSE hdr; if present, alg field is ignored; instead the
+        *          whole claim object has to be provided in this parameter */
+       size_t jose_hdr_len;
+       /**< entry: if jose_hdr is not NULL, JOSE header length without terminating '\0' */
+       char *out;
+       /**< exit: signed JWT in compact form*/
+       size_t *out_len;
+       /**< entry,exit: buffer size of out; actual size of JWT on exit */
+       char *temp;
+       /**< exit undefined content, used by the function as a temporary scratchpad; MUST
+        * be large enogh to store various intermediate representations */
+       int tl;
+       /**< entry: size of temp buffer */
+};
+
+/**
+ * lws_jwt_sign_compact() - generate a compact JWT using a key and JOSE header
+ *
+ * \param ctx: the lws_context
+ * \param jwk: the signing key
+ * \param info: info describing the JWT's content and output/temp buffers
+ * \param format: a printf style format specification of the claims object
+ * \param ...: zero or more args for the format specification
+ *
+ * Creates a JWT in a single step, from the format string and args through to
+ * outputting a well-formed compact JWT representation in out. The provided
+ * JOSE header's syntax is checked before it is added to the JWT.
+ *
+ * Returns 0 if all is well and *out_len is the amount of data in out, else
+ * nonzero if failed.  Temp must be large enough to hold various intermediate
+ * representations.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_jwt_sign_via_info(struct lws_context *ctx, struct lws_jwk *jwk,
+         const struct lws_jwt_sign_info *info, const char *format, ...) LWS_FORMAT(4);
+
+/**
+ * lws_jwt_token_sanity() - check a validated jwt payload for sanity
+ *
+ * \param in: the JWT payload
+ * \param in_len: the length of the JWT payload
+ * \param iss: the expected issuer of the token
+ * \param aud: the expected audience of the token
+ * \param csrf_in: NULL, or the csrf token that came in on a URL
+ * \param sub: a buffer to hold the subject name in the JWT (eg, account name)
+ * \param sub_len: the max length of the sub buffer
+ * \param secs_left: set to the number of seconds of valid auth left if valid
+ *
+ * This performs some generic sanity tests on validated JWT payload...
+ *
+ *  - the issuer is as expected
+ *  - the audience is us
+ *  - current time is OK for nbf ("not before") in the token
+ *  - current time is OK for exp ("expiry") in the token
+ *  - if csrf_in is not NULL, that the JWK has a csrf and it matches it
+ *  - if sub is not NULL, that the JWK provides a subject (and copies it to sub)
+ *
+ * If the tests pass, *secs_left is set to the number of remaining seconds the
+ * auth is valid.
+ *
+ * Returns 0 if no inconsistency, else nonzero.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_jwt_token_sanity(const char *in, size_t in_len,
+                    const char *iss, const char *aud, const char *csrf_in,
+                    char *sub, size_t sub_len, unsigned long *exp_unix_time);
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+
+struct lws_jwt_sign_set_cookie {
+       struct lws_jwk                  *jwk;
+       /**< entry: required signing key */
+       const char                      *alg;
+       /**< entry: required signing alg, eg, "ES512" */
+       const char                      *iss;
+       /**< entry: issuer name to use */
+       const char                      *aud;
+       /**< entry: audience */
+       const char                      *cookie_name;
+       /**< entry: the name of the cookie */
+       char                            sub[33];
+       /**< sign-entry, validate-exit: subject */
+       const char                      *extra_json;
+       /**< sign-entry, validate-exit:
+        * optional "ext" JSON object contents for the JWT */
+       size_t                          extra_json_len;
+       /**< validate-exit:
+        * length of optional "ext" JSON object contents for the JWT */
+       const char                      *csrf_in;
+       /**< validate-entry:
+        * NULL, or an external CSRF token to check against what is in the JWT */
+       unsigned long                   expiry_unix_time;
+       /**< sign-entry: seconds the JWT and cookie may live,
+        * validate-exit: expiry unix time */
+};
+
+/**
+ * lws_jwt_sign_token_set_http_cookie() - creates sets a JWT in a wsi cookie
+ *
+ * \param wsi: the wsi to create the cookie header on
+ * \param i: structure describing what should be in the JWT
+ * \param p: wsi headers area
+ * \param end: end of wsi headers area
+ *
+ * Creates a JWT specified \p i, and attaches it to the outgoing headers on
+ * wsi.  Returns 0 if successful.
+ *
+ * Best-practice security restrictions are applied to the cookie set action,
+ * including forcing httponly, and __Host- prefix.  As required by __Host-, the
+ * cookie Path is set to /.  __Host- is applied by the function, the cookie_name
+ * should just be "xyz" for "__Host-xyz".
+ *
+ * \p extra_json should just be the bare JSON, a { } is provided around it by
+ * the function if it's non-NULL.  For example, "\"authorization\": 1".
+ *
+ * It's recommended the secs parameter is kept as small as consistent with one
+ * user session on the site if possible, eg, 10 minutes or 20 minutes.  At the
+ * server, it can determine how much time is left in the auth and inform the
+ * client; if the JWT validity expires, the page should reload so the UI always
+ * reflects what's possible to do with the authorization state correctly.  If
+ * the JWT expires, the user can log back in using credentials usually stored in
+ * the browser and auto-filled-in, so this is not very inconvenient.
+ *
+ * This is a helper on top of the other JOSE and JWT apis that somewhat crosses
+ * over between JWT and HTTP, since it knows about cookies.  So it is only built
+ * if both LWS_WITH_JOSE and one of the http-related roles enabled.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_jwt_sign_token_set_http_cookie(struct lws *wsi,
+                                  const struct lws_jwt_sign_set_cookie *i,
+                                  uint8_t **p, uint8_t *end);
+LWS_VISIBLE LWS_EXTERN int
+lws_jwt_get_http_cookie_validate_jwt(struct lws *wsi,
+                                    struct lws_jwt_sign_set_cookie *i,
+                                    char *out, size_t *out_len);
+#endif
+
 ///@}
diff --git a/include/libwebsockets/lws-lecp.h b/include/libwebsockets/lws-lecp.h
new file mode 100644 (file)
index 0000000..8133e4b
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** \defgroup lecp CBOR parser
+ * ##CBOR parsing related functions
+ * \ingroup lwsapi
+ *
+ * LECP is an extremely lightweight CBOR stream parser included in lws.  It
+ * is aligned in approach with the LEJP JSON stream parser, with some additional
+ * things needed for CBOR.
+ */
+//@{
+
+#ifndef LECP_MAX_PARSING_STACK_DEPTH
+#define LECP_MAX_PARSING_STACK_DEPTH   5
+#endif
+#ifndef LECP_MAX_DEPTH
+#define LECP_MAX_DEPTH                 12
+#endif
+#ifndef LECP_MAX_INDEX_DEPTH
+#define LECP_MAX_INDEX_DEPTH           8
+#endif
+#ifndef LECP_MAX_PATH
+#define LECP_MAX_PATH                  128
+#endif
+#ifndef LECP_STRING_CHUNK
+/* must be >= 30 to assemble floats */
+#define LECP_STRING_CHUNK              254
+#endif
+
+#define LECP_FLAG_CB_IS_VALUE 64
+
+/*
+ * CBOR initial byte 3 x MSB bits are these
+ */
+
+enum {
+       LWS_CBOR_MAJTYP_UINT            = 0 << 5,
+       LWS_CBOR_MAJTYP_INT_NEG         = 1 << 5,
+       LWS_CBOR_MAJTYP_BSTR            = 2 << 5,
+       LWS_CBOR_MAJTYP_TSTR            = 3 << 5,
+       LWS_CBOR_MAJTYP_ARRAY           = 4 << 5,
+       LWS_CBOR_MAJTYP_MAP             = 5 << 5,
+       LWS_CBOR_MAJTYP_TAG             = 6 << 5,
+       LWS_CBOR_MAJTYP_FLOAT           = 7 << 5,  /* also BREAK */
+
+       LWS_CBOR_MAJTYP_MASK            = 7 << 5,
+
+       /*
+        * For the low 5 bits of the opcode, 0-23 are literals, unless it's
+        * FLOAT.
+        *
+        * 24 = 1 byte; 25 = 2..., 26 = 4... and 27 = 8 bytes following literal.
+        */
+       LWS_CBOR_1                      = 24,
+       LWS_CBOR_2                      = 25,
+       LWS_CBOR_4                      = 26,
+       LWS_CBOR_8                      = 27,
+
+       LWS_CBOR_RESERVED               = 28,
+
+       LWS_CBOR_SUBMASK                = 0x1f,
+
+       /*
+        * Major type 7 discriminators in low 5 bits
+        * 0 - 23 is SIMPLE implicit value (like, eg, LWS_CBOR_SWK_TRUE)
+        */
+       LWS_CBOR_SWK_FALSE              = 20,
+       LWS_CBOR_SWK_TRUE               = 21,
+       LWS_CBOR_SWK_NULL               = 22,
+       LWS_CBOR_SWK_UNDEFINED          = 23,
+
+       LWS_CBOR_M7_SUBTYP_SIMPLE_X8    = 24, /* simple with additional byte */
+       LWS_CBOR_M7_SUBTYP_FLOAT16      = 25,
+       LWS_CBOR_M7_SUBTYP_FLOAT32      = 26,
+       LWS_CBOR_M7_SUBTYP_FLOAT64      = 27,
+       LWS_CBOR_M7_BREAK               = 31,
+
+/* 28, 29, 30 are illegal.
+ *
+ * 31 is illegal for UINT, INT_NEG, and TAG;
+ *               for BSTR, TSTR, ARRAY and MAP it means "indefinite length", ie,
+ *               it's made up of an endless amount of determinite-length
+ *               fragments terminated with a BREAK (FLOAT | 31) instead of the
+ *               next determinite-length fragment.  The second framing level
+ *               means no need for escapes for BREAK in the data.
+ */
+
+       LWS_CBOR_INDETERMINITE          = 31,
+
+/*
+ * Well-known tags
+ */
+
+       LWS_CBOR_WKTAG_DATETIME_STD     = 0, /* text */
+       LWS_CBOR_WKTAG_DATETIME_EPOCH   = 1, /* int or float */
+       LWS_CBOR_WKTAG_BIGNUM_UNSIGNED  = 2, /* byte string */
+       LWS_CBOR_WKTAG_BIGNUM_NEGATIVE  = 3, /* byte string */
+       LWS_CBOR_WKTAG_DECIMAL_FRAC     = 4, /* array */
+       LWS_CBOR_WKTAG_BIGFLOAT         = 5, /* array */
+
+       LWS_CBOR_WKTAG_COSE_ENC0        = 16,
+       LWS_CBOR_WKTAG_COSE_MAC0        = 17,
+       LWS_CBOR_WKTAG_COSE_SIGN1       = 18,
+
+       LWS_CBOR_WKTAG_TO_B64U          = 21, /* any */
+       LWS_CBOR_WKTAG_TO_B64           = 22, /* any */
+       LWS_CBOR_WKTAG_TO_B16           = 23, /* any */
+       LWS_CBOR_WKTAG_CBOR             = 24, /* byte string */
+
+       LWS_CBOR_WKTAG_URI              = 32, /* text string */
+       LWS_CBOR_WKTAG_B64U             = 33, /* text string */
+       LWS_CBOR_WKTAG_B64              = 34, /* text string */
+       LWS_CBOR_WKTAG_MIME             = 36, /* text string */
+
+       LWS_CBOR_WKTAG_COSE_ENC         = 96,
+       LWS_CBOR_WKTAG_COSE_MAC         = 97,
+       LWS_CBOR_WKTAG_COSE_SIGN        = 98,
+
+       LWS_CBOR_WKTAG_SELFDESCCBOR     = 55799
+};
+
+enum lecp_callbacks {
+       LECPCB_CONSTRUCTED              = 0,
+       LECPCB_DESTRUCTED               = 1,
+
+       LECPCB_COMPLETE                 = 3,
+       LECPCB_FAILED                   = 4,
+
+       LECPCB_PAIR_NAME                = 5,
+
+       LECPCB_VAL_TRUE                 = LECP_FLAG_CB_IS_VALUE | 6,
+       LECPCB_VAL_FALSE                = LECP_FLAG_CB_IS_VALUE | 7,
+       LECPCB_VAL_NULL                 = LECP_FLAG_CB_IS_VALUE | 8,
+       LECPCB_VAL_NUM_INT              = LECP_FLAG_CB_IS_VALUE | 9,
+       LECPCB_VAL_RESERVED             = LECP_FLAG_CB_IS_VALUE | 10,
+       LECPCB_VAL_STR_START            = 11, /* notice handle separately */
+       LECPCB_VAL_STR_CHUNK            = LECP_FLAG_CB_IS_VALUE | 12,
+       LECPCB_VAL_STR_END              = LECP_FLAG_CB_IS_VALUE | 13,
+
+       LECPCB_ARRAY_START              = 14,
+       LECPCB_ARRAY_END                = 15,
+
+       LECPCB_OBJECT_START             = 16,
+       LECPCB_OBJECT_END               = 17,
+
+       LECPCB_TAG_START                = 18,
+       LECPCB_TAG_END                  = 19,
+
+       LECPCB_VAL_NUM_UINT             = LECP_FLAG_CB_IS_VALUE | 20,
+       LECPCB_VAL_UNDEFINED            = LECP_FLAG_CB_IS_VALUE | 21,
+       LECPCB_VAL_FLOAT16              = LECP_FLAG_CB_IS_VALUE | 22,
+       LECPCB_VAL_FLOAT32              = LECP_FLAG_CB_IS_VALUE | 23,
+       LECPCB_VAL_FLOAT64              = LECP_FLAG_CB_IS_VALUE | 24,
+
+       LECPCB_VAL_SIMPLE               = LECP_FLAG_CB_IS_VALUE | 25,
+
+       LECPCB_VAL_BLOB_START           = 26, /* notice handle separately */
+       LECPCB_VAL_BLOB_CHUNK           = LECP_FLAG_CB_IS_VALUE | 27,
+       LECPCB_VAL_BLOB_END             = LECP_FLAG_CB_IS_VALUE | 28,
+
+       LECPCB_ARRAY_ITEM_START         = 29,
+       LECPCB_ARRAY_ITEM_END           = 30,
+
+       LECPCB_LITERAL_CBOR             = 31,
+};
+
+enum lecp_reasons {
+       LECP_CONTINUE                   = -1,
+       LECP_REJECT_BAD_CODING          = -2,
+       LECP_REJECT_UNKNOWN             = -3,
+       LECP_REJECT_CALLBACK            = -4,
+       LECP_STACK_OVERFLOW             = -5,
+};
+
+
+struct lecp_item {
+       union {
+               uint64_t        u64;
+               int64_t         i64;
+
+               uint64_t        u32;
+
+               uint16_t        hf;
+#if defined(LWS_WITH_CBOR_FLOAT)
+               float           f;
+               double          d;
+#else
+               uint32_t        f;
+               uint64_t        d;
+#endif
+       } u;
+       uint8_t                 opcode;
+};
+
+struct lecp_ctx;
+typedef signed char (*lecp_callback)(struct lecp_ctx *ctx, char reason);
+
+struct _lecp_stack {
+       char                    s; /* lejp_state stack*/
+       uint8_t                 p; /* path length */
+       char                    i; /* index array length */
+       char                    indet; /* indeterminite */
+       char                    intermediate; /* in middle of string */
+
+       char                    pop_iss;
+       uint64_t                tag;
+       uint64_t                collect_rem;
+       uint32_t                ordinal;
+       uint8_t                 opcode;
+       uint8_t                 send_new_array_item;
+       uint8_t                 barrier;
+};
+
+struct _lecp_parsing_stack {
+       void                    *user;  /* private to the stack level */
+       lecp_callback           cb;
+       const char * const      *paths;
+       uint8_t                 count_paths;
+       uint8_t                 ppos;
+       uint8_t                 path_match;
+};
+
+struct lecp_ctx {
+
+       /* sorted by type for most compact alignment
+        *
+        * pointers
+        */
+       void *user;
+       uint8_t                 *collect_tgt;
+
+       /* arrays */
+
+       struct _lecp_parsing_stack pst[LECP_MAX_PARSING_STACK_DEPTH];
+       struct _lecp_stack      st[LECP_MAX_DEPTH];
+       uint16_t                i[LECP_MAX_INDEX_DEPTH]; /* index array */
+       uint16_t                wild[LECP_MAX_INDEX_DEPTH]; /* index array */
+       char                    path[LECP_MAX_PATH];
+       uint8_t                 cbor[64]; /* literal cbor capture */
+
+       struct lecp_item        item;
+
+
+       /* size_t */
+
+       size_t                  path_stride; /* 0 means default ptr size, else
+                                             * stride...  allows paths to be
+                                             * provided composed inside a
+                                             * larger user struct instead of a
+                                             * duplicated array */
+       size_t                  used_in;     /* bytes of input consumed */
+
+       /* short */
+
+       uint16_t                uni;
+
+       /* char */
+
+       uint8_t                 npos;
+       uint8_t                 dcount;
+       uint8_t                 f;
+       uint8_t                 sp; /* stack head */
+       uint8_t                 ipos; /* index stack depth */
+       uint8_t                 count_paths;
+       uint8_t                 path_match;
+       uint8_t                 path_match_len;
+       uint8_t                 wildcount;
+       uint8_t                 pst_sp; /* parsing stack head */
+       uint8_t                 outer_array;
+       uint8_t                 cbor_pos;
+       uint8_t                 literal_cbor_report;
+       char                    present; /* temp for cb reason to use */
+
+       uint8_t                 be; /* big endian */
+
+       /* at end so we can memset the rest of it */
+
+       char buf[LECP_STRING_CHUNK + 1];
+};
+
+enum lws_lec_pctx_ret {
+       LWS_LECPCTX_RET_FINISHED                = 0,
+       LWS_LECPCTX_RET_AGAIN, /* call again to continue writing buffer */
+       LWS_LECPCTX_RET_FAIL /* something broken, eg, format string */
+};
+
+enum cbp_state {
+       CBPS_IDLE,
+       CBPS_PC1,
+       CBPS_PC2,
+       CBPS_PC3,
+
+       CBPS_STRING_BODY,
+
+       CBPS_NUM_LIT,
+
+       CBPS_STRING_LIT,
+
+       CBPS_CONTYPE,
+};
+
+typedef struct lws_lec_pctx {
+       uint8_t                 stack[16];
+       uint8_t                 vaa[16];
+       uint8_t                 indet[16];
+       uint8_t                 scratch[24];
+       uint8_t                 *start;    /* the beginning of the out buf */
+       uint8_t                 *buf;      /* cur pos in output buf */
+       uint8_t                 *end;      /* the end of the output buf */
+
+       const uint8_t           *ongoing_src;
+       uint64_t                ongoing_len;
+       uint64_t                ongoing_done;
+
+       struct lecp_item        item;
+
+       size_t                  used;      /* number of bytes valid from start */
+
+       int                     opaque[4]; /* ignored by lws, caller may use */
+
+       enum cbp_state          state;
+       unsigned int            fmt_pos;
+       uint8_t                 sp;
+       uint8_t                 scratch_len;
+       uint8_t                 escflag;
+       uint8_t                 _long;
+       uint8_t                 vaa_pos;
+       uint8_t                 dotstar;
+} lws_lec_pctx_t;
+
+LWS_VISIBLE LWS_EXTERN void
+lws_lec_int(lws_lec_pctx_t *ctx, uint8_t opcode, uint8_t indet, uint64_t num);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_lec_scratch(lws_lec_pctx_t *ctx);
+
+/*
+ * lws_lec_init() - prepare a cbor writing context
+ *
+ * \param ctx: the cbor writing context to prepare
+ * \param buf: the output buffer start
+ * \param len: the amount of the output buffer we can use
+ *
+ * Prepares a cbor writing context so that les_lec_printf can be used to
+ * write into it.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_lec_init(lws_lec_pctx_t *ctx, uint8_t *buf, size_t len);
+
+/*
+ * lws_lec_setbuf() - update the output buffer for an initialized cbor writing ctx
+ *
+ * \param ctx: the cbor writing context to prepare
+ * \param buf: the output buffer start
+ * \param len: the amount of the output buffer we can use
+ *
+ * Leaves the cbor writing context state as it is, but resets the output buffer
+ * it writes into as given in \p buf and \p len
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_lec_setbuf(lws_lec_pctx_t *ctx, uint8_t *buf, size_t len);
+
+/*
+ * lws_lec_vsprintf() - write into a cbor writing context
+ *
+ * \param ctx: the cbor writing context to prepare
+ * \param format: a printf style argument map
+ * \param args: the va args
+ *
+ * CBOR-aware vsprintf which pauses output when it fills the output buffer.  You
+ * can call it again with the same args and same lws_lex_pctx to resume filling
+ *
+ * Returns either LWS_LECPCTX_RET_FINISHED if we have nothing left over that we
+ * want to put in the buffer, or LWS_LECPCTX_RET_AGAIN if the function should
+ * be called again with the same arguments (perhaps into a different output
+ * buffer) to continue emitting output from where it left off.
+ *
+ * If LWS_LECPCTX_RET_AGAIN is returned, lws_lec_setbuf() must be used on the
+ * context to reset or change the output buffer before calling again.
+ *
+ * The number of bytes placed in the output buffer is available in ctx->used.
+ *
+ * \p format is a printf-type format string that is specialized for CBOR
+ * generation.  It understands the following specifiers
+ *
+ * |`123`||unsigned literal number|
+ * |`-123`||signed literal number|
+ * |`%u`|`unsigned int`|number|
+ * |`%lu`|`unsigned long int`|number|
+ * |`%llu`|`unsigned long long int`|number|
+ * |`%d`|`signed int`|number|
+ * |`%ld`|`signed long int`|number|
+ * |`%lld`|`signed long long int`|number|
+ * |`%f`|`double`|floating point number|
+ * |`123(...)`||literal tag and scope|
+ * |`%t(...)`|`unsigned int`|tag and scope|
+ * |`%lt(...)`|`unsigned long int`|tag and scope|
+ * |`%llt(...)`|`unsigned long long int`|tag and scope|
+ * |`[...]`||Array (fixed len if `]` in same format string)|
+ * |`{...}`||Map (fixed len if `}` in same format string)|
+ * |`<t...>`||Container for indeterminite text string frags|
+ * |`<b...>`||Container for indeterminite binary string frags|
+ * |`'string'`||Literal text of known length|
+ * |`%s`|`const char *`|NUL-terminated string|
+ * |`%.*s`|`int`, `const char *`|length-specified string|
+ * |`%.*b`|`int`, `const uint8_t *`|length-specified binary|
+ * |`:`||separator between Map items (a:b)|
+ * |`,`||separator between Map pairs or array items|
+ *
+ * See READMEs/README.cbor-lecp.md for more details.
+ */
+LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
+lws_lec_vsprintf(lws_lec_pctx_t *ctx, const char *format, va_list args);
+
+/*
+ * lws_lec_printf() - write into a cbor writing context
+ *
+ * \param ctx: the cbor writing context to prepare
+ * \param format: a printf style argument map
+ * \param ...: format args
+ *
+ * See lws_lec_vsprintf() for format details.  This is the most common way
+ * to format the CBOR output.
+ *
+ * See READMEs/README.cbor-lecp.md for more details.
+ */
+LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
+lws_lec_printf(lws_lec_pctx_t *ctx, const char *format, ...);
+
+/**
+ * lecp_construct() - Construct an LECP parser context
+ *
+ * \param ctx: the parser context object to be initialized
+ * \param cb: the user callback to receive the parsing events
+ * \param user: an opaque user pointer available at \p cb
+ * \param paths: an optional array of parsing paths
+ * \param paths_count: how many paths in \p paths
+ *
+ * Prepares an LECP parser context for parsing.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lecp_construct(struct lecp_ctx *ctx, lecp_callback cb, void *user,
+              const char * const *paths, unsigned char paths_count);
+
+/**
+ * lecp_destruct() - Destroys an LECP parser context
+ *
+ * \param ctx: the parser context object to be destroyed
+ */
+LWS_VISIBLE LWS_EXTERN void
+lecp_destruct(struct lecp_ctx *ctx);
+
+/**
+ * lecp_parse() - parses a chunk of input CBOR
+ *
+ * \p ctx: the parsing context
+ * \p cbor: the start of the chunk of CBOR
+ * \p len: the number of bytes of CBOR available at \p cbor
+ *
+ * Returns LECP_CONTINUE if more input needed, one of enum lecp_reasons for a
+ * fatal error, else 0 for successful parsing completion.
+ *
+ * On success or _CONTINUE, ctx->used_in is set to the number of input bytes
+ * consumed.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lecp_parse(struct lecp_ctx *ctx, const uint8_t *cbor, size_t len);
+
+LWS_VISIBLE LWS_EXTERN void
+lecp_change_callback(struct lecp_ctx *ctx, lecp_callback cb);
+
+LWS_VISIBLE LWS_EXTERN const char *
+lecp_error_to_string(int e);
+
+/**
+ * lecp_parse_report_raw() - turn cbor raw reporting on and off
+ *
+ * \param ctx: the lecp context
+ * \param on: 0 to disable (defaults disabled), 1 to enable
+ *
+ * For cose_sign, it needs access to raw cbor subtrees for the hash input.
+ * This api causes LECPCB_LITERAL_CBOR parse callbacks when there are
+ * ctx->cbor_pos bytes of raw cbor available in ctx->cbor[]. the callbacks
+ * occur when the ctx->cbor[] buffer fills or if it holds anything when this
+ * spi is used to stop the reports.
+ *
+ * The same CBOR that is being captured continues to be passed for parsing.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lecp_parse_report_raw(struct lecp_ctx *ctx, int on);
+
+/**
+ * lecp_parse_map_is_key() - return nonzero if we're in a map and this is a key
+ *
+ * \param ctx: the lwcp context
+ *
+ * Checks if the current value is a key in a map, ie, that you are on a "key" in
+ * a list of "{key: value}" pairs.  Zero means you're either not in a map or not
+ * on the key part, and nonzero means you are in a map and on a key part.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lecp_parse_map_is_key(struct lecp_ctx *ctx);
+
+LWS_VISIBLE LWS_EXTERN int
+lecp_parse_subtree(struct lecp_ctx *ctx, const uint8_t *in, size_t len);
+
+/*
+ * Helpers for half-float
+ */
+
+LWS_VISIBLE LWS_EXTERN void
+lws_singles2halfp(uint16_t *hp, uint32_t x);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_halfp2singles(uint32_t *xp, uint16_t h);
+
+//@}
diff --git a/include/libwebsockets/lws-led.h b/include/libwebsockets/lws-led.h
new file mode 100644 (file)
index 0000000..79e0343
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Generic LED controller ops
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is like an abstract class for leds, a real implementation provides
+ * functions for the ops that use the underlying, eg, OS gpio arrangements.
+ */
+
+/* only b15 significant for GPIO */
+typedef uint16_t lws_led_intensity_t;
+typedef uint16_t lws_led_seq_phase_t;
+
+/* the normalized max intensity */
+#define LWS_LED_MAX_INTENSITY                  (0xffff)
+
+/* the normalized 360 degree phase count for intensity functions */
+#define LWS_LED_FUNC_PHASE                     65536
+/* used when the sequence doesn't stop by itself and goes around forever */
+#define LWS_SEQ_LEDPHASE_TOTAL_ENDLESS         (-1)
+
+#define LWS_LED_SEQUENCER_UPDATE_INTERVAL_MS   33
+
+struct lws_led_state; /* opaque */
+struct lws_pwm_ops; /* forward ref */
+
+typedef lws_led_intensity_t (*lws_led_lookup_t)(lws_led_seq_phase_t ph);
+
+typedef struct lws_led_sequence_def_t {
+       lws_led_lookup_t                func;
+       lws_led_seq_phase_t             ledphase_offset;
+       int                             ledphase_total; /* 65536= one cycle */
+       uint16_t                        ms;
+       uint8_t                         flags;
+} lws_led_sequence_def_t;
+
+enum {
+       LLSI_CURR,
+       LLSI_NEXT,
+       LLSI_TRANS
+};
+
+typedef struct lws_led_state_ch
+{
+       const lws_led_sequence_def_t            *seq; /* NULL = inactive */
+       lws_led_seq_phase_t                     ph;
+       lws_led_seq_phase_t                     step;
+       int                                     phase_budget;
+       lws_led_intensity_t                     last;
+       /**< at the end of the sequence we decouple the sequencer, but leave
+        * the last computed sample behind for further transitions to base off
+        */
+} lws_led_state_ch_t;
+
+typedef struct lws_led_state_chs
+{
+       lws_led_state_ch_t                      seqs[3];
+} lws_led_state_chs_t;
+
+/* this should always be first in the subclassed implementation types */
+
+typedef struct lws_led_ops {
+       void (*intensity)(const struct lws_led_ops *lo, const char *name,
+                         lws_led_intensity_t inten);
+       /**< for BOOL led control like GPIO, only inten b15 is significant */
+       struct lws_led_state * (*create)(const struct lws_led_ops *led_ops);
+       void (*destroy)(struct lws_led_state *);
+} lws_led_ops_t;
+
+typedef struct lws_led_gpio_map {
+       const char                      *name;
+       _lws_plat_gpio_t                gpio;
+       lws_led_lookup_t                intensity_correction;
+       /**< May be NULL.  If GPIO-based LED, ignored.  If pwm_ops provided,
+        * NULL means use default CIE 100% correction function.  If non-NULL,
+        * use the pointed-to correction function.  This is useful to provide
+        * LED-specific intensity correction / scaling so different types of
+        * LED can "look the same". */
+       const struct lws_pwm_ops        *pwm_ops;
+       /**< if NULL, gpio controls the led directly.  If set to a pwm_ops,
+        * the led control is outsourced to the pwm controller. */
+       uint8_t                         active_level;
+} lws_led_gpio_map_t;
+
+typedef struct lws_led_gpio_controller {
+       const lws_led_ops_t             led_ops;
+
+       const lws_gpio_ops_t            *gpio_ops;
+       const lws_led_gpio_map_t        *led_map;
+       uint8_t                         count_leds;
+} lws_led_gpio_controller_t;
+
+/* ops */
+
+LWS_VISIBLE LWS_EXTERN struct lws_led_state *
+lws_led_gpio_create(const lws_led_ops_t *led_ops);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_led_gpio_destroy(struct lws_led_state *lcs);
+
+/**
+ * lws_led_gpio_intensity() - set the static intensity of an led
+ *
+ * \param lo: the base class of the led controller
+ * \param index: which led in the controller set
+ * \param inten: 16-bit unsigned intensity
+ *
+ * For LEDs controlled by a BOOL like GPIO, only inten b15 is significant.
+ * For PWM type LED control, as many bits as the hardware can support from b15
+ * down are significant.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_led_gpio_intensity(const struct lws_led_ops *lo, const char *name,
+                      lws_led_intensity_t inten);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_led_transition(struct lws_led_state *lcs, const char *name,
+                  const lws_led_sequence_def_t *next,
+                  const lws_led_sequence_def_t *trans);
+
+
+#define lws_led_gpio_ops \
+       { \
+               .create         = lws_led_gpio_create, \
+               .destroy        = lws_led_gpio_destroy, \
+               .intensity      = lws_led_gpio_intensity, \
+       }
+
index 3fd37dd..f9f5027 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup lejp JSON parser
@@ -152,11 +153,12 @@ enum lejp_callbacks {
  *
  *  LEJPCB_VAL_STR_START: We are starting to parse a string, no data yet
  *
- *  LEJPCB_VAL_STR_CHUNK: We parsed LEJP_STRING_CHUNK -1 bytes of string data in
- *                     ctx->buf, which is as much as we can buffer, so we are
- *                     spilling it.  If all your strings are less than
- *                     LEJP_STRING_CHUNK - 1 bytes, you will never see this
- *                     callback.
+ *  LEJPCB_VAL_STR_CHUNK: We filled the string buffer in the ctx, but it's not
+ *                       the end of the string.  We produce this to spill the
+ *                       intermediate buffer to the user code, so we can handle
+ *                       huge JSON strings using only the small buffer in the
+ *                       ctx.  If the whole JSON string fits in the ctx buffer,
+ *                       you won't get these callbacks.
  *
  *  LEJPCB_VAL_STR_END:        String parsing has completed, the last chunk of the
  *                     string is in ctx->buf.
@@ -180,7 +182,7 @@ typedef signed char (*lejp_callback)(struct lejp_ctx *ctx, char reason);
 #define LEJP_MAX_DEPTH 12
 #endif
 #ifndef LEJP_MAX_INDEX_DEPTH
-#define LEJP_MAX_INDEX_DEPTH 5
+#define LEJP_MAX_INDEX_DEPTH 8
 #endif
 #ifndef LEJP_MAX_PATH
 #define LEJP_MAX_PATH 128
@@ -191,26 +193,26 @@ typedef signed char (*lejp_callback)(struct lejp_ctx *ctx, char reason);
 #endif
 
 enum num_flags {
-       LEJP_SEEN_MINUS = (1 << 0),
-       LEJP_SEEN_POINT = (1 << 1),
-       LEJP_SEEN_POST_POINT = (1 << 2),
-       LEJP_SEEN_EXP = (1 << 3)
+       LEJP_SEEN_MINUS         = (1 << 0),
+       LEJP_SEEN_POINT         = (1 << 1),
+       LEJP_SEEN_POST_POINT    = (1 << 2),
+       LEJP_SEEN_EXP           = (1 << 3)
 };
 
 struct _lejp_stack {
-       char s; /* lejp_state stack*/
-       char p; /* path length */
-       char i; /* index array length */
-       char b; /* user bitfield */
+       char                    s; /* lejp_state stack*/
+       char                    p;      /* path length */
+       char                    i; /* index array length */
+       char                    b; /* user bitfield */
 };
 
 struct _lejp_parsing_stack {
-       void *user;     /* private to the stack level */
-       signed char (*callback)(struct lejp_ctx *ctx, char reason);
-       const char * const *paths;
-       uint8_t count_paths;
-       uint8_t ppos;
-       uint8_t path_match;
+       void                    *user;  /* private to the stack level */
+       signed char             (*callback)(struct lejp_ctx *ctx, char reason);
+       const char * const      *paths;
+       uint8_t                 count_paths;
+       uint8_t                 ppos;
+       uint8_t                 path_match;
 };
 
 struct lejp_ctx {
@@ -254,6 +256,7 @@ struct lejp_ctx {
        uint8_t path_match_len;
        uint8_t wildcount;
        uint8_t pst_sp; /* parsing stack head */
+       uint8_t outer_array;
 };
 
 LWS_VISIBLE LWS_EXTERN void
index d71f946..3f21b81 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup log Logging
  *
  * Log categories may be individually filtered bitwise, and directed to built-in
  * sinks for syslog-compatible logging, or a user-defined function.
+ *
+ * Traditional logs use a single, processwide logging context.  New style log
+ * apis (lws_xxx_cx()) can pass the logging context to use in.
  */
 ///@{
 
-enum lws_log_levels {
-       LLL_ERR         = 1 << 0,
-       LLL_WARN        = 1 << 1,
-       LLL_NOTICE      = 1 << 2,
-       LLL_INFO        = 1 << 3,
-       LLL_DEBUG       = 1 << 4,
-       LLL_PARSER      = 1 << 5,
-       LLL_HEADER      = 1 << 6,
-       LLL_EXT         = 1 << 7,
-       LLL_CLIENT      = 1 << 8,
-       LLL_LATENCY     = 1 << 9,
-       LLL_USER        = 1 << 10,
-       LLL_THREAD      = 1 << 11,
-
-       LLL_COUNT       = 12 /* set to count of valid flags */
-};
+#define LLL_ERR                        (1 << 0)
+#define        LLL_WARN                (1 << 1)
+#define        LLL_NOTICE              (1 << 2)
+#define        LLL_INFO                (1 << 3)
+#define        LLL_DEBUG               (1 << 4)
+#define        LLL_PARSER              (1 << 5)
+#define        LLL_HEADER              (1 << 6)
+#define        LLL_EXT                 (1 << 7)
+#define        LLL_CLIENT              (1 << 8)
+#define        LLL_LATENCY             (1 << 9)
+#define        LLL_USER                (1 << 10)
+#define        LLL_THREAD              (1 << 11)
+
+#define        LLL_COUNT               (12) /* set to count of valid flags */
+
+#define        LLLF_SECRECY_PII        (1 << 16)
+       /**< contains Personally Identifiable Information */
+#define LLLF_SECRECY_BEARER    (1 << 17)
+       /**< possession of this data allows impersonation */
+
+#define        LLLF_LOG_TIMESTAMP      (1 << 18)
+       /**< set to prepend logs with timestamp */
+
+#define        LLLF_LOG_CONTEXT_AWARE  (1 << 30)
+/**< set if the context uses an emit function that takes the logctx, auto-
+ * applied when setting emit using lws_set_log_level_cx() api */
+
+struct lws_log_cx;
+
+typedef void (*lws_log_emit_t)(int level, const char *line);
+typedef void (*lws_log_emit_cx_t)(struct lws_log_cx *cx, int level,
+                                 const char *line, size_t len);
+typedef void (*lws_log_prepend_cx_t)(struct lws_log_cx *cx, void *obj,
+                                    char **p, char *e);
+typedef void (*lws_log_use_cx_t)(struct lws_log_cx *cx, int _new);
+
+/*
+ * This is the logging context
+ */
+
+typedef struct lws_log_cx {
+       union {
+               lws_log_emit_t          emit; /* legacy emit function */
+               lws_log_emit_cx_t       emit_cx; /* LLLF_LOG_CONTEXT_AWARE */
+       } u;
+       lws_log_use_cx_t                refcount_cb;
+       /**< NULL, or a function called after each change to .refcount below,
+        * this enables implementing side-effects like opening and closing
+        * log files when the first and last object binds / unbinds */
+       lws_log_prepend_cx_t            prepend;
+       /**< NULL, or a cb to optionally prepend a string to logs we are a
+        * parent of */
+       struct lws_log_cx               *parent;
+       /**< NULL, or points to log ctx we are a child of */
+       void                            *opaque;
+       /**< ignored by lws, used to pass config to emit_cx, eg, filepath */
+       void                            *stg;
+       /**< ignored by lws, may be used a storage by refcount_cb / emit_cx */
+       uint32_t                        lll_flags;
+       /**< mask of log levels we want to emit in this context */
+       int32_t                         refcount;
+       /**< refcount of objects bound to this log context */
+} lws_log_cx_t;
 
 /**
  * lwsl_timestamp: generate logging timestamp string
@@ -60,62 +111,216 @@ enum lws_log_levels {
  * returns length written in p
  */
 LWS_VISIBLE LWS_EXTERN int
-lwsl_timestamp(int level, char *p, int len);
+lwsl_timestamp(int level, char *p, size_t len);
 
 #if defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK)
 #define _lws_log(aaa, ...) SMSG(__VA_ARGS__)
 #else
-LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...) LWS_FORMAT(2);
-LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl);
+LWS_VISIBLE LWS_EXTERN void
+_lws_log(int filter, const char *format, ...) LWS_FORMAT(2);
+LWS_VISIBLE LWS_EXTERN void
+_lws_logv(int filter, const char *format, va_list vl);
 #endif
 
-/* these guys are unconditionally included */
+struct lws_vhost;
+struct lws;
 
-#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__)
-#define lwsl_user(...) _lws_log(LLL_USER, __VA_ARGS__)
+LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
+lwsl_context_get_cx(struct lws_context *cx);
+LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
+lwsl_vhost_get_cx(struct lws_vhost *vh);
+LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
+lwsl_wsi_get_cx(struct lws *wsi);
+#if defined(LWS_WITH_SECURE_STREAMS)
+struct lws_ss_handle;
+struct lws_sspc_handle;
+LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
+lwsl_ss_get_cx(struct lws_ss_handle *ss);
+LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
+lwsl_sspc_get_cx(struct lws_sspc_handle *ss);
+#endif
 
-#if !defined(LWS_WITH_NO_LOGS)
-/* notice and warn are usually included by being compiled in */
-#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__)
-#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__)
+LWS_VISIBLE LWS_EXTERN void
+lws_log_emit_cx_file(struct lws_log_cx *cx, int level, const char *line,
+                       size_t len);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_log_use_cx_file(struct lws_log_cx *cx, int _new);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_log_prepend_context(struct lws_log_cx *cx, void *obj, char **p, char *e);
+LWS_VISIBLE LWS_EXTERN void
+lws_log_prepend_vhost(struct lws_log_cx *cx, void *obj, char **p, char *e);
+LWS_VISIBLE LWS_EXTERN void
+lws_log_prepend_wsi(struct lws_log_cx *cx, void *obj, char **p, char *e);
+#if defined(LWS_WITH_SECURE_STREAMS)
+LWS_VISIBLE LWS_EXTERN void
+lws_log_prepend_ss(struct lws_log_cx *cx, void *obj, char **p, char *e);
+LWS_VISIBLE LWS_EXTERN void
+lws_log_prepend_sspc(struct lws_log_cx *cx, void *obj, char **p, char *e);
 #endif
+
+LWS_VISIBLE LWS_EXTERN void
+_lws_log_cx(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
+           int filter, const char *_fun, const char *format, ...) LWS_FORMAT(6);
+
+#define lwsl_cx(_c, _fil, ...) \
+                _lws_log_cx(lwsl_context_get_cx(_c), lws_log_prepend_context, \
+                                       _c, _fil, __func__, __VA_ARGS__)
+#define lwsl_vhost(_v, _fil, ...) \
+                _lws_log_cx(lwsl_vhost_get_cx(_v), lws_log_prepend_vhost, _v, \
+                                       _fil, __func__, __VA_ARGS__)
+#define lwsl_wsi(_w, _fil, ...) \
+                _lws_log_cx(lwsl_wsi_get_cx(_w), lws_log_prepend_wsi, _w, \
+                                       _fil, __func__, __VA_ARGS__)
+#define lwsl_ss(_h, _fil, ...) \
+                _lws_log_cx(lwsl_ss_get_cx(_h), lws_log_prepend_ss, _h, \
+                                       _fil, __func__, __VA_ARGS__)
+
+#define lwsl_hexdump_context(_c, _fil, _buf, _len) \
+               lwsl_hexdump_level_cx(lwsl_context_get_cx(_c), \
+                                     lws_log_prepend_context, \
+                                     _c, _fil, _buf, _len)
+#define lwsl_hexdump_vhost(_v, _fil, _buf, _len) \
+               lwsl_hexdump_level_cx(lwsl_vhost_get_cx(_v), \
+                                     lws_log_prepend_vhost, \
+                                     _v, _fil, _buf, _len)
+#define lwsl_hexdump_wsi(_w, _fil, _buf, _len) \
+               lwsl_hexdump_level_cx(lwsl_wsi_get_cx(_w), \
+                                     lws_log_prepend_wsi, \
+                                     _w, _fil, _buf, _len)
+#define lwsl_hexdump_ss(_h, _fil, _buf, _len) \
+               lwsl_hexdump_level_cx(lwsl_ss_get_cx(_h), \
+                                     lws_log_prepend_ss, \
+                                     _h, _fil, _buf, _len)
+
 /*
- *  weaker logging can be deselected by telling CMake to build in RELEASE mode
- *  that gets rid of the overhead of checking while keeping _warn and _err
- *  active
+ * Figure out which logs to build in or not
  */
 
 #if defined(_DEBUG)
+ /*
+  * In DEBUG build, select all logs unless NO_LOGS
+  */
+ #if defined(LWS_WITH_NO_LOGS)
+  #define _LWS_LINIT (LLL_ERR | LLL_USER)
+ #else
+   #define _LWS_LINIT ((1 << LLL_COUNT) - 1)
+ #endif
+#else /* not _DEBUG */
 #if defined(LWS_WITH_NO_LOGS)
-/* notice, warn and log are always compiled in */
-#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__)
-#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__)
+#define _LWS_LINIT (LLL_ERR | LLL_USER)
+#else
+ #define _LWS_LINIT (LLL_ERR | LLL_USER | LLL_WARN | LLL_NOTICE)
 #endif
-#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__)
-#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__)
-#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__)
-#define lwsl_header(...)  _lws_log(LLL_HEADER, __VA_ARGS__)
-#define lwsl_ext(...)  _lws_log(LLL_EXT, __VA_ARGS__)
-#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__)
-#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__)
-#define lwsl_thread(...) _lws_log(LLL_THREAD, __VA_ARGS__)
+#endif /* _DEBUG */
 
-#else /* no debug */
-#if defined(LWS_WITH_NO_LOGS)
+/*
+ * Create either empty overrides or the ones forced at build-time.
+ * These overrides have the final say... any bits set in
+ * LWS_LOGGING_BITFIELD_SET force the build of those logs, any bits
+ * set in LWS_LOGGING_BITFIELD_CLEAR disable the build of those logs.
+ *
+ * If not defined lws decides based on CMAKE_BUILD_TYPE=DEBUG or not
+ */
+
+#if defined(LWS_LOGGING_BITFIELD_SET)
+ #define _LWS_LBS (LWS_LOGGING_BITFIELD_SET)
+#else
+ #define _LWS_LBS 0
+#endif
+
+#if defined(LWS_LOGGING_BITFIELD_CLEAR)
+ #define _LWS_LBC (LWS_LOGGING_BITFIELD_CLEAR)
+#else
+ #define _LWS_LBC 0
+#endif
+
+/*
+ * Compute the final active logging bitfield for build
+ */
+#define _LWS_ENABLED_LOGS (((_LWS_LINIT) | (_LWS_LBS)) & ~(_LWS_LBC))
+
+/*
+ * Individually enable or disable log levels for build
+ * depending on what was computed
+ */
+
+/*
+ * Process scope logs
+ */
+
+#if (_LWS_ENABLED_LOGS & LLL_ERR)
+#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__)
+#else
+#define lwsl_err(...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_WARN)
+#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__)
+#else
 #define lwsl_warn(...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
+#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__)
+#else
 #define lwsl_notice(...) do {} while(0)
 #endif
+
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__)
+#else
 #define lwsl_info(...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
+#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__)
+#else
 #define lwsl_debug(...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_PARSER)
+#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__)
+#else
 #define lwsl_parser(...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_HEADER)
+#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__)
+#else
 #define lwsl_header(...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_EXT)
+#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__)
+#else
 #define lwsl_ext(...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
+#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__)
+#else
 #define lwsl_client(...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
+#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__)
+#else
 #define lwsl_latency(...) do {} while(0)
-#define lwsl_thread(...) do {} while(0)
+#endif
 
+#if (_LWS_ENABLED_LOGS & LLL_THREAD)
+#define lwsl_thread(...) _lws_log(LLL_THREAD, __VA_ARGS__)
+#else
+#define lwsl_thread(...) do {} while(0)
 #endif
 
+#if (_LWS_ENABLED_LOGS & LLL_USER)
+#define lwsl_user(...) _lws_log(LLL_USER, __VA_ARGS__)
+#else
+#define lwsl_user(...) do {} while(0)
+#endif
 
 #define lwsl_hexdump_err(...) lwsl_hexdump_level(LLL_ERR, __VA_ARGS__)
 #define lwsl_hexdump_warn(...) lwsl_hexdump_level(LLL_WARN, __VA_ARGS__)
@@ -123,6 +328,338 @@ LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl
 #define lwsl_hexdump_info(...) lwsl_hexdump_level(LLL_INFO, __VA_ARGS__)
 #define lwsl_hexdump_debug(...) lwsl_hexdump_level(LLL_DEBUG, __VA_ARGS__)
 
+/*
+ * lws_context scope logs
+ */
+
+#if (_LWS_ENABLED_LOGS & LLL_ERR)
+#define lwsl_cx_err(_c, ...) lwsl_cx(_c, LLL_ERR, __VA_ARGS__)
+#else
+#define lwsl_cx_err(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_WARN)
+#define lwsl_cx_warn(_c, ...) lwsl_cx(_c, LLL_WARN, __VA_ARGS__)
+#else
+#define lwsl_cx_warn(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
+#define lwsl_cx_notice(_c, ...) lwsl_cx(_c, LLL_NOTICE, __VA_ARGS__)
+#else
+#define lwsl_cx_notice(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+#define lwsl_cx_info(_c, ...) lwsl_cx(_c, LLL_INFO, __VA_ARGS__)
+#else
+#define lwsl_cx_info(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
+#define lwsl_cx_debug(_c, ...) lwsl_cx(_c, LLL_DEBUG, __VA_ARGS__)
+#else
+#define lwsl_cx_debug(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_PARSER)
+#define lwsl_cx_parser(_c, ...) lwsl_cx(_c, LLL_PARSER, __VA_ARGS__)
+#else
+#define lwsl_cx_parser(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_HEADER)
+#define lwsl_cx_header(_c, ...) lwsl_cx(_c, LLL_HEADER, __VA_ARGS__)
+#else
+#define lwsl_cx_header(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_EXT)
+#define lwsl_cx_ext(_c, ...) lwsl_cx(_c, LLL_EXT, __VA_ARGS__)
+#else
+#define lwsl_cx_ext(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
+#define lwsl_cx_client(_c, ...) lwsl_cx(_c, LLL_CLIENT, __VA_ARGS__)
+#else
+#define lwsl_cx_client(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
+#define lwsl_cx_latency(_c, ...) lwsl_cx(_c, LLL_LATENCY, __VA_ARGS__)
+#else
+#define lwsl_cx_latency(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_THREAD)
+#define lwsl_cx_thread(_c, ...) lwsl_cx(_c, LLL_THREAD, __VA_ARGS__)
+#else
+#define lwsl_cx_thread(_c, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_USER)
+#define lwsl_cx_user(_c, ...) lwsl_cx(_c, LLL_USER, __VA_ARGS__)
+#else
+#define lwsl_cx_user(_c, ...) do {} while(0)
+#endif
+
+#define lwsl_hexdump_cx_err(_c, ...)    lwsl_hexdump_context(_c, LLL_ERR, __VA_ARGS__)
+#define lwsl_hexdump_cx_warn(_c, ...)   lwsl_hexdump_context(_c, LLL_WARN, __VA_ARGS__)
+#define lwsl_hexdump_cx_notice(_c, ...) lwsl_hexdump_context(_c, LLL_NOTICE, __VA_ARGS__)
+#define lwsl_hexdump_cx_info(_c, ...)   lwsl_hexdump_context(_c, LLL_INFO, __VA_ARGS__)
+#define lwsl_hexdump_cx_debug(_c, ...)  lwsl_hexdump_context(_c, LLL_DEBUG, __VA_ARGS__)
+
+/*
+ * lws_vhost
+ */
+
+#if (_LWS_ENABLED_LOGS & LLL_ERR)
+#define lwsl_vhost_err(_v, ...) lwsl_vhost(_v, LLL_ERR, __VA_ARGS__)
+#else
+#define lwsl_vhost_err(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_WARN)
+#define lwsl_vhost_warn(_v, ...) lwsl_vhost(_v, LLL_WARN, __VA_ARGS__)
+#else
+#define lwsl_vhost_warn(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
+#define lwsl_vhost_notice(_v, ...) lwsl_vhost(_v, LLL_NOTICE, __VA_ARGS__)
+#else
+#define lwsl_vhost_notice(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+#define lwsl_vhost_info(_v, ...) lwsl_vhost(_v, LLL_INFO, __VA_ARGS__)
+#else
+#define lwsl_vhost_info(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
+#define lwsl_vhost_debug(_v, ...) lwsl_vhost(_v, LLL_DEBUG, __VA_ARGS__)
+#else
+#define lwsl_vhost_debug(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_PARSER)
+#define lwsl_vhost_parser(_v, ...) lwsl_vhost(_v, LLL_PARSER, __VA_ARGS__)
+#else
+#define lwsl_vhost_parser(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_HEADER)
+#define lwsl_vhost_header(_v, ...) lwsl_vhost(_v, LLL_HEADER, __VA_ARGS__)
+#else
+#define lwsl_vhost_header(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_EXT)
+#define lwsl_vhost_ext(_v, ...) lwsl_vhost(_v, LLL_EXT, __VA_ARGS__)
+#else
+#define lwsl_vhost_ext(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
+#define lwsl_vhost_client(_v, ...) lwsl_vhost(_v, LLL_CLIENT, __VA_ARGS__)
+#else
+#define lwsl_vhost_client(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
+#define lwsl_vhost_latency(_v, ...) lwsl_vhost(_v, LLL_LATENCY, __VA_ARGS__)
+#else
+#define lwsl_vhost_latency(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_THREAD)
+#define lwsl_vhost_thread(_v, ...) lwsl_vhost(_v, LLL_THREAD, __VA_ARGS__)
+#else
+#define lwsl_vhost_thread(_v, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_USER)
+#define lwsl_vhost_user(_v, ...) lwsl_vhost(_v, LLL_USER, __VA_ARGS__)
+#else
+#define lwsl_vhost_user(_v, ...) do {} while(0)
+#endif
+
+#define lwsl_hexdump_vhost_err(_v, ...)    lwsl_hexdump_vhost(_v, LLL_ERR, __VA_ARGS__)
+#define lwsl_hexdump_vhost_warn(_v, ...)   lwsl_hexdump_vhost(_v, LLL_WARN, __VA_ARGS__)
+#define lwsl_hexdump_vhost_notice(_v, ...) lwsl_hexdump_vhost(_v, LLL_NOTICE, __VA_ARGS__)
+#define lwsl_hexdump_vhost_info(_v, ...)   lwsl_hexdump_vhost(_v, LLL_INFO, __VA_ARGS__)
+#define lwsl_hexdump_vhost_debug(_v, ...)  lwsl_hexdump_vhost(_v, LLL_DEBUG, __VA_ARGS__)
+
+
+/*
+ * lws_wsi
+ */
+
+#if (_LWS_ENABLED_LOGS & LLL_ERR)
+#define lwsl_wsi_err(_w, ...) lwsl_wsi(_w, LLL_ERR, __VA_ARGS__)
+#else
+#define lwsl_wsi_err(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_WARN)
+#define lwsl_wsi_warn(_w, ...) lwsl_wsi(_w, LLL_WARN, __VA_ARGS__)
+#else
+#define lwsl_wsi_warn(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
+#define lwsl_wsi_notice(_w, ...) lwsl_wsi(_w, LLL_NOTICE, __VA_ARGS__)
+#else
+#define lwsl_wsi_notice(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+#define lwsl_wsi_info(_w, ...) lwsl_wsi(_w, LLL_INFO, __VA_ARGS__)
+#else
+#define lwsl_wsi_info(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
+#define lwsl_wsi_debug(_w, ...) lwsl_wsi(_w, LLL_DEBUG, __VA_ARGS__)
+#else
+#define lwsl_wsi_debug(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_PARSER)
+#define lwsl_wsi_parser(_w, ...) lwsl_wsi(_w, LLL_PARSER, __VA_ARGS__)
+#else
+#define lwsl_wsi_parser(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_HEADER)
+#define lwsl_wsi_header(_w, ...) lwsl_wsi(_w, LLL_HEADER, __VA_ARGS__)
+#else
+#define lwsl_wsi_header(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_EXT)
+#define lwsl_wsi_ext(_w, ...) lwsl_wsi(_w, LLL_EXT, __VA_ARGS__)
+#else
+#define lwsl_wsi_ext(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
+#define lwsl_wsi_client(_w, ...) lwsl_wsi(_w, LLL_CLIENT, __VA_ARGS__)
+#else
+#define lwsl_wsi_client(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
+#define lwsl_wsi_latency(_w, ...) lwsl_wsi(_w, LLL_LATENCY, __VA_ARGS__)
+#else
+#define lwsl_wsi_latency(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_THREAD)
+#define lwsl_wsi_thread(_w, ...) lwsl_wsi(_w, LLL_THREAD, __VA_ARGS__)
+#else
+#define lwsl_wsi_thread(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_USER)
+#define lwsl_wsi_user(_w, ...) lwsl_wsi(_w, LLL_USER, __VA_ARGS__)
+#else
+#define lwsl_wsi_user(_w, ...) do {} while(0)
+#endif
+
+#define lwsl_hexdump_wsi_err(_v, ...)    lwsl_hexdump_wsi(_v, LLL_ERR, __VA_ARGS__)
+#define lwsl_hexdump_wsi_warn(_v, ...)   lwsl_hexdump_wsi(_v, LLL_WARN, __VA_ARGS__)
+#define lwsl_hexdump_wsi_notice(_v, ...) lwsl_hexdump_wsi(_v, LLL_NOTICE, __VA_ARGS__)
+#define lwsl_hexdump_wsi_info(_v, ...)   lwsl_hexdump_wsi(_v, LLL_INFO, __VA_ARGS__)
+#define lwsl_hexdump_wsi_debug(_v, ...)  lwsl_hexdump_wsi(_v, LLL_DEBUG, __VA_ARGS__)
+
+
+/*
+ * lwsl_ss
+ */
+
+#if (_LWS_ENABLED_LOGS & LLL_ERR)
+#define lwsl_ss_err(_w, ...) lwsl_ss(_w, LLL_ERR, __VA_ARGS__)
+#else
+#define lwsl_ss_err(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_WARN)
+#define lwsl_ss_warn(_w, ...) lwsl_ss(_w, LLL_WARN, __VA_ARGS__)
+#else
+#define lwsl_ss_warn(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
+#define lwsl_ss_notice(_w, ...) lwsl_ss(_w, LLL_NOTICE, __VA_ARGS__)
+#else
+#define lwsl_ss_notice(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+#define lwsl_ss_info(_w, ...) lwsl_ss(_w, LLL_INFO, __VA_ARGS__)
+#else
+#define lwsl_ss_info(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
+#define lwsl_ss_debug(_w, ...) lwsl_ss(_w, LLL_DEBUG, __VA_ARGS__)
+#else
+#define lwsl_ss_debug(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_PARSER)
+#define lwsl_ss_parser(_w, ...) lwsl_ss(_w, LLL_PARSER, __VA_ARGS__)
+#else
+#define lwsl_ss_parser(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_HEADER)
+#define lwsl_ss_header(_w, ...) lwsl_ss(_w, LLL_HEADER, __VA_ARGS__)
+#else
+#define lwsl_ss_header(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_EXT)
+#define lwsl_ss_ext(_w, ...) lwsl_ss(_w, LLL_EXT, __VA_ARGS__)
+#else
+#define lwsl_ss_ext(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
+#define lwsl_ss_client(_w, ...) lwsl_ss(_w, LLL_CLIENT, __VA_ARGS__)
+#else
+#define lwsl_ss_client(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
+#define lwsl_ss_latency(_w, ...) lwsl_ss(_w, LLL_LATENCY, __VA_ARGS__)
+#else
+#define lwsl_ss_latency(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_THREAD)
+#define lwsl_ss_thread(_w, ...) lwsl_ss(_w, LLL_THREAD, __VA_ARGS__)
+#else
+#define lwsl_ss_thread(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_USER)
+#define lwsl_ss_user(_w, ...) lwsl_ss(_w, LLL_USER, __VA_ARGS__)
+#else
+#define lwsl_ss_user(_w, ...) do {} while(0)
+#endif
+
+#define lwsl_hexdump_ss_err(_v, ...)    lwsl_hexdump_ss(_v, LLL_ERR, __VA_ARGS__)
+#define lwsl_hexdump_ss_warn(_v, ...)   lwsl_hexdump_ss(_v, LLL_WARN, __VA_ARGS__)
+#define lwsl_hexdump_ss_notice(_v, ...) lwsl_hexdump_ss(_v, LLL_NOTICE, __VA_ARGS__)
+#define lwsl_hexdump_ss_info(_v, ...)   lwsl_hexdump_ss(_v, LLL_INFO, __VA_ARGS__)
+#define lwsl_hexdump_ss_debug(_v, ...)  lwsl_hexdump_ss(_v, LLL_DEBUG, __VA_ARGS__)
+
+
+
 /**
  * lwsl_hexdump_level() - helper to hexdump a buffer at a selected debug level
  *
@@ -136,6 +673,10 @@ LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl
 LWS_VISIBLE LWS_EXTERN void
 lwsl_hexdump_level(int level, const void *vbuf, size_t len);
 
+LWS_VISIBLE LWS_EXTERN void
+lwsl_hexdump_level_cx(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
+                     int hexdump_level, const void *vbuf, size_t len);
+
 /**
  * lwsl_hexdump() - helper to hexdump a buffer (DEBUG builds only)
  *
@@ -165,13 +706,20 @@ static LWS_INLINE int lws_is_be(void) {
  *                     function to perform log string emission instead of
  *                     the default stderr one.
  *
- *     log level defaults to "err", "warn" and "notice" contexts enabled and
- *     emission on stderr.  If stderr is a tty (according to isatty()) then
- *     the output is coloured according to the log level using ANSI escapes.
+ * log level defaults to "err", "warn" and "notice" contexts enabled and
+ * emission on stderr.  If stderr is a tty (according to isatty()) then
+ * the output is coloured according to the log level using ANSI escapes.
+ *
+ * You can set the default security level for logging using the
+ * secrecy_and_log_level() macro to set the \p level parameter, eg
+ *
+ * lws_set_log_level(secrecy_and_log_level(LWS_SECRECY_PII, LLL_ERR | LLL_WARN),
+ *                  my_emit_function);
+ *
+ * Normally you can just leave it at the default.
  */
 LWS_VISIBLE LWS_EXTERN void
-lws_set_log_level(int level,
-                 void (*log_emit_function)(int level, const char *line));
+lws_set_log_level(int level, lws_log_emit_t log_emit_function);
 
 /**
  * lwsl_emit_syslog() - helper log emit function writes to system log
@@ -227,4 +775,12 @@ lwsl_emit_stderr_notimestamp(int level, const char *line);
 LWS_VISIBLE LWS_EXTERN int
 lwsl_visible(int level);
 
+struct lws;
+
+LWS_VISIBLE LWS_EXTERN const char *
+lws_wsi_tag(struct lws *wsi);
+
+LWS_VISIBLE LWS_EXTERN void
+lwsl_refcount_cx(lws_log_cx_t *cx, int _new);
+
 ///@}
index 81c3b71..2295039 100644 (file)
@@ -1,24 +1,25 @@
 /*
- * libwebsockets - lws alloc chunk
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup lwsac lwsac
@@ -94,13 +95,16 @@ lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add,
  * whatever is necessary to return you a pointer to ensure bytes of memory
  * reserved for the caller.
  *
+ * This always allocates in the current chunk or a new chunk... see the
+ * lwsac_use_backfill() variant to try first to find space in earlier chunks.
+ *
  * Returns NULL if OOM.
  */
 LWS_VISIBLE LWS_EXTERN void *
 lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size);
 
 /**
- * lwsac_use_zero - allocate / use some memory from a lwsac and zero it
+ * lwsac_use_backfill - allocate / use some memory from a lwsac
  *
  * \param head: pointer to the lwsac list object
  * \param ensure: the number of bytes we want to use
@@ -113,12 +117,13 @@ lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size);
  * whatever is necessary to return you a pointer to ensure bytes of memory
  * reserved for the caller.
  *
- * \p ensure bytes at the return address are zeroed if the allocation succeeded.
+ * Also checks if earlier blocks have enough remaining space to take the
+ * allocation before making a new allocation.
  *
  * Returns NULL if OOM.
  */
 LWS_VISIBLE LWS_EXTERN void *
-lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size);
+lwsac_use_backfill(struct lwsac **head, size_t ensure, size_t chunk_size);
 
 /**
  * lwsac_use - allocate / use some memory from a lwsac
@@ -136,7 +141,9 @@ lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size);
  * Returns NULL if OOM.
  */
 LWS_VISIBLE LWS_EXTERN void *
-lwsac_use_zeroed(struct lwsac **head, size_t ensure, size_t chunk_size);
+lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size);
+
+#define lwsac_use_zeroed lwsac_use_zero
 
 /**
  * lwsac_free - deallocate all chunks in the lwsac and set head NULL
@@ -181,7 +188,7 @@ LWS_VISIBLE LWS_EXTERN void
 lwsac_reference(struct lwsac *head);
 
 /**
- * lwsac_reference() - increase the lwsac reference count
+ * lwsac_unreference() - decrease the lwsac reference count
  *
  * \param head: pointer to the lwsac list object
  *
@@ -191,6 +198,38 @@ lwsac_reference(struct lwsac *head);
 LWS_VISIBLE LWS_EXTERN void
 lwsac_unreference(struct lwsac **head);
 
+/**
+ * lwsac_extend() - try to increase the size of the last block
+ *
+ * \param head: pointer to the lwsac list object
+ * \param amount: amount to try to increase usage for
+ *
+ * This will either increase the usage reservation of the last allocated block
+ * by amount and return 0, or fail and return 1.
+ *
+ * This is very cheap to call and is designed to optimize usage after a static
+ * struct for vari-sized additional content which may flow into an additional
+ * block in a new chunk if necessary, but wants to make the most of the space
+ * in front of it first to try to avoid gaps and the new chunk if it can.
+ *
+ * The additional area if the call succeeds will have been memset to 0.
+ *
+ * To use it, the following must be true:
+ *
+ * - only the last lwsac use can be extended
+ *
+ * - if another use happens inbetween the use and extend, it will break
+ *
+ * - the use cannot have been using backfill
+ *
+ * - a user object must be tracking the current allocated size of the last use
+ *   (lwsac doesn't know it) and increment by amount if the extend call succeeds
+ *
+ * Despite these restrictions this can be an important optimization for some
+ * cases
+ */
+LWS_VISIBLE LWS_EXTERN int
+lwsac_extend(struct lwsac *head, size_t amount);
 
 /* helpers to keep a file cached in memory */
 
@@ -209,8 +248,9 @@ lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache,
 
 /* more advanced helpers */
 
+/* offset from lac to start of payload, first = 1 = first lac in chain */
 LWS_VISIBLE LWS_EXTERN size_t
-lwsac_sizeof(void);
+lwsac_sizeof(int first);
 
 LWS_VISIBLE LWS_EXTERN size_t
 lwsac_get_tail_pos(struct lwsac *lac);
@@ -227,4 +267,24 @@ lwsac_info(struct lwsac *head);
 LWS_VISIBLE LWS_EXTERN uint64_t
 lwsac_total_alloc(struct lwsac *head);
 
+LWS_VISIBLE LWS_EXTERN uint64_t
+lwsac_total_overhead(struct lwsac *head);
+
+/**
+ * lwsac_scan_extant() - returns existing copy of blob, or NULL
+ *
+ * \param head: the lwsac to scan
+ * \param find: the blob to look for
+ * \param len: the length of the blob to look for
+ * \param nul: nonzero if the next byte must be NUL
+ *
+ * Helper that looks through a whole lwsac for a given binary blob already
+ * present.  Used in the case that lwsac contents are const once written, and
+ * strings or blobs may be repeated in the input: this allows the earlier
+ * copy to be pointed to by subsequent references without repeating the string
+ * or blob redundantly.
+ */
+LWS_VISIBLE LWS_EXTERN uint8_t *
+lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul);
+
 ///@}
diff --git a/include/libwebsockets/lws-map.h b/include/libwebsockets/lws-map.h
new file mode 100644 (file)
index 0000000..4462881
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** \defgroup lws_map generic map apis
+ * ##Generic map structures and apis
+ * \ingroup lwsapi
+ *
+ * lws_map
+ *
+ * Discrete owner object represents the whole map, created with key-specific
+ * ops for hashing the key to a uint32_t and comparing two keys.  Owns a list
+ * of hash tables whose size / modulo it set at creation time.
+ *
+ * Items in the map are contained in a lws_map_item_t that is indexed in a
+ * hash table.
+ *
+ * It's difficult to make a single compact map abstraction that fits all cases,
+ * this is useful to the extent you have the memory to trade off the number of
+ * hashtables needed for the amount of items and the lookup latency limit for
+ * your application, typically for hundreds or low thousands of items.
+ */
+//@{
+
+typedef struct lws_map lws_map_t;
+typedef struct lws_map_item lws_map_item_t;
+
+typedef void * lws_map_key_t;
+typedef void * lws_map_value_t;
+typedef uint32_t lws_map_hash_t;
+
+typedef lws_map_hash_t (*lws_map_hash_from_key_t)(const lws_map_key_t key,
+                                                 size_t kl);
+typedef int (*lws_map_compare_key_t)(const lws_map_key_t key1, size_t kl1,
+                                    const lws_map_value_t key2, size_t kl2);
+typedef void * (*lws_map_alloc_t)(struct lws_map *mo, size_t x);
+typedef void (*lws_map_free_t)(void *);
+
+/*
+ * Creation parameters for the map, copied into the map owner
+ */
+
+typedef struct lws_map_info {
+       lws_map_hash_from_key_t         _hash;
+       lws_map_compare_key_t           _compare;
+       lws_map_alloc_t                 _alloc; /* NULL = lws_malloc */
+       lws_map_free_t                  _free;  /* NULL = lws_free */
+
+       void                            *opaque;
+       /**< &lwsac if using lwsac allocator */
+       void                            *aux;
+       /**< chunk size if using lwsac allocator */
+       /**< this can be used by the alloc handler, eg for lws_ac */
+       size_t                          modulo;
+       /**< number of hashed owner lists to create */
+} lws_map_info_t;
+
+LWS_VISIBLE LWS_EXTERN const void *
+lws_map_item_key(lws_map_item_t *_item);
+LWS_VISIBLE LWS_EXTERN const void *
+lws_map_item_value(lws_map_item_t *_item);
+LWS_VISIBLE LWS_EXTERN size_t
+lws_map_item_key_len(lws_map_item_t *_item);
+LWS_VISIBLE LWS_EXTERN size_t
+lws_map_item_value_len(lws_map_item_t *_item);
+
+/*
+ * Helpers for C string keys case
+ */
+
+#define lws_map_item_create_ks(_map, _str, _v, _vl) \
+               lws_map_item_create(_map, (const lws_map_key_t)_str, \
+                                   strlen(_str), (const lws_map_value_t)_v, \
+                                                   _vl)
+#define lws_map_item_lookup_ks(_map, _str) \
+               lws_map_item_lookup(_map, (const lws_map_key_t)_str, strlen(_str))
+
+/**
+ * lws_map_create() - create a map object and hashtables on heap
+ *
+ * \param info: description of map to create
+ *
+ * Creates a map object on heap, using lws_malloc().
+ *
+ * \p info may be all zeros inside, if so, modulo defaults to 8, and the
+ * operation callbacks default to using lws_malloc() / _free() for item alloc,
+ * a default xor / shift based hash and simple linear memory key compare.
+ *
+ * For less typical use-cases, the provided \p info members can be tuned to
+ * control how the allocation of mapped items is done, lws provides two exports
+ * lws_map_alloc_lwsac() and lws_map_free_lwsac() that can be used for _alloc
+ * and _free to have items allocated inside an lwsac.
+ *
+ * The map itself is created on the heap directly, the info._alloc() op is only
+ * used when creating items.
+ *
+ * keys have individual memory sizes and do not need to all be the same length.
+ */
+LWS_VISIBLE LWS_EXTERN lws_map_t *
+lws_map_create(const lws_map_info_t *info);
+
+/*
+ * helpers that can be used for info._alloc and info._free if using lwsac
+ * allocation for items, set info.opaque to point to the lwsac pointer, and
+ * aux to (void *)chunksize, or leave zero / NULL for the default
+ */
+
+LWS_VISIBLE LWS_EXTERN void *
+lws_map_alloc_lwsac(struct lws_map *map, size_t x);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_map_free_lwsac(void *v);
+
+/**
+ * lws_map_destroy() - deallocate all items and free map
+ *
+ * \param pmap: pointer to pointer map object to deallocate
+ *
+ * Frees all items in the map, using info._free(), and then frees the map
+ * from heap directly.  \p *pmap is set to NULL.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_map_destroy(lws_map_t **pmap);
+
+/**
+ * lws_map_item_create() - allocate and map an item into an existing map
+ *
+ * \param map: the map to add items into
+ * \param key: the key, may be any kind of object
+ * \param keylen: the length of the key in bytes
+ * \param value: the value, may be any kind of object
+ * \param valuelen: the length of value
+ *
+ * Allocates space for the item, key and value using the map allocator, and
+ * if non-NULL, copies the key and value into the item.
+ *
+ * If an item with the same key exists, it is removed and destroyed before
+ * creating and adding the new one.
+ */
+
+LWS_VISIBLE LWS_EXTERN lws_map_item_t *
+lws_map_item_create(lws_map_t *map,
+                   const lws_map_key_t key, size_t keylen,
+                   const lws_map_value_t value, size_t valuelen);
+
+/**
+ * lws_map_item_destroy() - remove item from map and free
+ *
+ * \param item: the item in the map to remove and free
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_map_item_destroy(lws_map_item_t *item);
+
+/**
+ * lws_map_item_lookup() - look for a item with the given key in the map
+ *
+ * \param map: the map
+ * \param key: the key to look for
+ * \param keylen: the length of the key to look for
+ *
+ * Searches for the key in the map, using the map's key hash and key compare
+ * functions.
+ */
+
+LWS_VISIBLE LWS_EXTERN lws_map_item_t *
+lws_map_item_lookup(lws_map_t *map, const lws_map_key_t key, size_t keylen);
+
+//@}
diff --git a/include/libwebsockets/lws-metrics.h b/include/libwebsockets/lws-metrics.h
new file mode 100644 (file)
index 0000000..4df7a26
--- /dev/null
@@ -0,0 +1,329 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Public apis related to metric collection and reporting
+ */
+
+/* lws_metrics public part */
+
+typedef uint64_t u_mt_t;
+
+enum {
+       LWSMTFL_REPORT_OUTLIERS                         = (1 << 0),
+       /**< track outliers and report them internally */
+       LWSMTFL_REPORT_OOB                              = (1 << 1),
+       /**< report events as they happen */
+       LWSMTFL_REPORT_INACTIVITY_AT_PERIODIC           = (1 << 2),
+       /**< explicitly externally report no activity at periodic cb, by
+        * default no events in the period is just not reported */
+       LWSMTFL_REPORT_MEAN                             = (1 << 3),
+       /**< average/min/max is meaningful, else only sum is meaningful */
+       LWSMTFL_REPORT_ONLY_GO                          = (1 << 4),
+       /**< no-go pieces invalid */
+       LWSMTFL_REPORT_DUTY_WALLCLOCK_US                = (1 << 5),
+       /**< aggregate compares to wallclock us for duty cycle */
+       LWSMTFL_REPORT_HIST                             = (1 << 6),
+       /**< our type is histogram (otherwise, sum / mean aggregation) */
+};
+
+/*
+ * lws_metrics_tag allows your object to accumulate OpenMetrics-style
+ * descriptive tags before accounting for it with a metrics object at the end.
+ *
+ * Tags should represent low entropy information that is likely to repeat
+ * identically, so, eg, http method name, not eg, latency in us which is
+ * unlikely to be seen the same twice.
+ *
+ * Tags are just a list of name=value pairs, used for qualifying the final
+ * metrics entry with decorations in additional dimensions.  For example,
+ * rather than keep individual metrics on methods, scheme, mountpoint, result
+ * code, you can keep metrics on http transactions only, and qualify the
+ * transaction metrics entries with tags that can be queried on the metrics
+ * backend to get the finer-grained information.
+ *
+ * http_srv{code="404",mount="/",method="GET",scheme="http"} 3
+ *
+ * For OpenMetrics the tags are converted to a { list } and appended to the base
+ * metrics name before using with actual metrics objects, the same set of tags
+ * on different transactions resolve to the same qualification string.
+ */
+
+typedef struct lws_metrics_tag {
+       lws_dll2_t      list;
+
+       const char      *name; /* tag, intended to be in .rodata, not copied */
+       /* overallocated value */
+} lws_metrics_tag_t;
+
+LWS_EXTERN LWS_VISIBLE int
+lws_metrics_tag_add(lws_dll2_owner_t *owner, const char *name, const char *val);
+
+#if defined(LWS_WITH_SYS_METRICS)
+/*
+ * wsi-specific version that also appends the tag value to the lifecycle tag
+ * used for logging the wsi identity
+ */
+LWS_EXTERN LWS_VISIBLE int
+lws_metrics_tag_wsi_add(struct lws *wsi, const char *name, const char *val);
+#else
+#define lws_metrics_tag_wsi_add(_a, _b, _c)
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+/*
+ * ss-specific version that also appends the tag value to the lifecycle tag
+ * used for logging the ss identity
+ */
+#if defined(LWS_WITH_SYS_METRICS)
+LWS_EXTERN LWS_VISIBLE int
+lws_metrics_tag_ss_add(struct lws_ss_handle *ss, const char *name, const char *val);
+#else
+#define lws_metrics_tag_ss_add(_a, _b, _c)
+#endif
+#endif
+
+LWS_EXTERN LWS_VISIBLE void
+lws_metrics_tags_destroy(lws_dll2_owner_t *owner);
+
+LWS_EXTERN LWS_VISIBLE size_t
+lws_metrics_tags_serialize(lws_dll2_owner_t *owner, char *buf, size_t len);
+
+LWS_EXTERN LWS_VISIBLE const char *
+lws_metrics_tag_get(lws_dll2_owner_t *owner, const char *name);
+
+/* histogram bucket */
+
+typedef struct lws_metric_bucket {
+       struct lws_metric_bucket        *next;
+       uint64_t                        count;
+
+       /* name + NUL is overallocated */
+} lws_metric_bucket_t;
+
+/* get overallocated name of bucket from bucket pointer */
+#define lws_metric_bucket_name_len(_b) (*((uint8_t *)&(_b)[1]))
+#define lws_metric_bucket_name(_b) (((const char *)&(_b)[1]) + 1)
+
+/*
+ * These represent persistent local event measurements.  They may aggregate
+ * a large number of events inbetween external dumping of summaries of the
+ * period covered, in two different ways
+ *
+ * 1) aggregation by sum or mean, to absorb multiple scalar readings
+ *
+ *  - go / no-go ratio counting
+ *  - mean averaging for, eg, latencies
+ *  - min / max for averaged values
+ *  - period the stats covers
+ *
+ * 2) aggregation by histogram, to absorb a range of outcomes that may occur
+ *    multiple times
+ *
+ *  - add named buckets to histogram
+ *  - bucket has a 64-bit count
+ *  - bumping a bucket just increments the count if already exists, else adds
+ *    a new one with count set to 1
+ *
+ * The same type with a union covers both cases.
+ *
+ * The lws_system ops api that hooks lws_metrics up to a metrics backend is
+ * given a pointer to these according to the related policy, eg, hourly, or
+ * every event passed straight through.
+ */
+
+typedef struct lws_metric_pub {
+       const char              *name;
+       /**< eg, "n.cn.dns", "vh.myendpoint" */
+       void                    *backend_opaque;
+       /**< ignored by lws, backend handler completely owns it */
+
+       lws_usec_t              us_first;
+       /**< us time metric started collecting, reset to us_dumped at dump */
+       lws_usec_t              us_last;
+       /**< 0, or us time last event, reset to 0 at last dump */
+       lws_usec_t              us_dumped;
+       /**< 0 if never, else us time of last dump to external api */
+
+       /* scope of data in .u is "since last dump" --> */
+
+       union {
+               /* aggregation, by sum or mean */
+
+               struct {
+                       u_mt_t                  sum[2];
+                       /**< go, no-go summed for mean or plan sum */
+                       u_mt_t                  min;
+                       /**< smallest individual measurement */
+                       u_mt_t                  max;
+                       /**< largest individual measurement */
+
+                       uint32_t                count[2];
+                       /**< go, no-go count of measurements in sum */
+               } agg;
+
+               /* histogram with dynamic named buckets */
+
+               struct {
+                       lws_metric_bucket_t     *head;
+                       /**< first bucket in our bucket list */
+
+                       uint64_t                total_count;
+                       /**< total count in all of our buckets */
+                       uint32_t                list_size;
+                       /**< number of buckets in our bucket list */
+               } hist;
+       } u;
+
+       uint8_t                 flags;
+
+} lws_metric_pub_t;
+
+LWS_EXTERN LWS_VISIBLE void
+lws_metrics_hist_bump_priv_tagged(lws_metric_pub_t *mt, lws_dll2_owner_t *tow,
+                                 lws_dll2_owner_t *tow2);
+
+
+/*
+ * Calipers are a helper struct for implementing "hanging latency" detection,
+ * where setting the start time and finding the end time may happen in more than
+ * one place.
+ *
+ * There are convenience wrappers to eliminate caliper definitions and code
+ * cleanly if WITH_SYS_METRICS is disabled for the build.
+ */
+
+struct lws_metric;
+
+typedef struct lws_metric_caliper {
+       struct lws_dll2_owner   mtags_owner; /**< collect tags here during
+                                             * caliper lifetime */
+       struct lws_metric       *mt; /**< NULL == inactive */
+       lws_usec_t              us_start;
+} lws_metric_caliper_t;
+
+#if defined(LWS_WITH_SYS_METRICS)
+#define lws_metrics_caliper_compose(_name) \
+               lws_metric_caliper_t _name;
+#define lws_metrics_caliper_bind(_name, _mt) \
+       { if (_name.mt) { \
+               lwsl_err("caliper: overwrite %s\n", \
+                               lws_metrics_priv_to_pub(_name.mt)->name); \
+               assert(0); } \
+         _name.mt = _mt; _name.us_start = lws_now_usecs(); }
+#define lws_metrics_caliper_declare(_name, _mt) \
+       lws_metric_caliper_t _name = { .mt = _mt, .us_start = lws_now_usecs() }
+#define lws_metrics_caliper_report(_name, _go_nogo) \
+       { if (_name.us_start) { lws_metric_event(_name.mt, _go_nogo, \
+                          (u_mt_t)(lws_now_usecs() - \
+                                          _name.us_start)); \
+                                         }  lws_metrics_caliper_done(_name);  }
+#define lws_metrics_caliper_report_hist(_name, pwsi) if (_name.mt) { \
+               lws_metrics_hist_bump_priv_tagged(lws_metrics_priv_to_pub(_name.mt), \
+                                                 &_name.mtags_owner, \
+                                                 pwsi ? &((pwsi)->cal_conn.mtags_owner) : NULL); \
+               lws_metrics_caliper_done(_name);  }
+
+#define lws_metrics_caliper_cancel(_name) { lws_metrics_caliper_done(_name); }
+#define lws_metrics_hist_bump(_mt, _name) \
+               lws_metrics_hist_bump_(_mt, _name)
+#define lws_metrics_hist_bump_priv(_mt, _name) \
+               lws_metrics_hist_bump_(lws_metrics_priv_to_pub(_mt), _name)
+#define lws_metrics_caliper_done(_name) { \
+               _name.us_start = 0; _name.mt = NULL; \
+               lws_metrics_tags_destroy(&_name.mtags_owner); }
+#else
+#define lws_metrics_caliper_compose(_name)
+#define lws_metrics_caliper_bind(_name, _mt)
+#define lws_metrics_caliper_declare(_name, _mp)
+#define lws_metrics_caliper_report(_name, _go_nogo)
+#define lws_metrics_caliper_report_hist(_name, pwsiconn)
+#define lws_metrics_caliper_cancel(_name)
+#define lws_metrics_hist_bump(_mt, _name)
+#define lws_metrics_hist_bump_priv(_mt, _name)
+#define lws_metrics_caliper_done(_name)
+#endif
+
+/**
+ * lws_metrics_format() - helper to format a metrics object for logging
+ *
+ * \param pub: public part of metrics object
+ * \param buf: output buffer to place string in
+ * \param len: available length of \p buf
+ *
+ * Helper for describing the state of a metrics object as a human-readable
+ * string, accounting for how its flags indicate what it contains.  This is not
+ * how you would report metrics, but during development it can be useful to
+ * log them inbetween possibily long report intervals.
+ *
+ * It uses the metric's flags to adapt the format shown appropriately, eg,
+ * as a histogram if LWSMTFL_REPORT_HIST etc
+ */
+LWS_EXTERN LWS_VISIBLE int
+lws_metrics_format(lws_metric_pub_t *pub, lws_metric_bucket_t **sub,
+                  char *buf, size_t len);
+
+/**
+ * lws_metrics_hist_bump() - add or increment histogram bucket
+ *
+ * \param pub: public part of metrics object
+ * \param name: bucket name to increment
+ *
+ * Either increment the count of an existing bucket of the right name in the
+ * metrics object, or add a new bucket of the given name and set its count to 1.
+ *
+ * The metrics object must have been created with flag LWSMTFL_REPORT_HIST
+ *
+ * Normally, you will actually use the preprocessor wrapper
+ * lws_metrics_hist_bump() defined above, since this automatically takes care of
+ * removing itself from the build if WITH_SYS_METRICS is not defined, without
+ * needing any preprocessor conditionals.
+ */
+LWS_EXTERN LWS_VISIBLE int
+lws_metrics_hist_bump_(lws_metric_pub_t *pub, const char *name);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_metrics_foreach(struct lws_context *ctx, void *user,
+                   int (*cb)(lws_metric_pub_t *pub, void *user));
+
+LWS_VISIBLE LWS_EXTERN int
+lws_metrics_hist_bump_describe_wsi(struct lws *wsi, lws_metric_pub_t *pub,
+                                  const char *name);
+
+enum {
+       LMT_NORMAL = 0, /* related to successful events */
+       LMT_OUTLIER,    /* related to successful events outside of bounds */
+
+       LMT_FAIL,       /* related to failed events */
+
+       LMT_COUNT,
+};
+
+typedef enum lws_metric_rpt {
+       LMR_PERIODIC = 0,       /* we are reporting on a schedule */
+       LMR_OUTLIER,            /* we are reporting the last outlier */
+} lws_metric_rpt_kind_t;
+
+#define METRES_GO      0
+#define METRES_NOGO    1
+
+
index 26b413b..c6dc439 100644 (file)
@@ -1,26 +1,40 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if defined(LWS_WITH_SPAWN)
+
+#if defined(WIN32) || defined(_WIN32)
+#else
+#include <sys/wait.h>
+#include <sys/times.h>
+#endif
+#endif
+
+#if defined(__OpenBSD__)
+#include <sys/siginfo.h>
+#endif
+
 /** \defgroup misc Miscellaneous APIs
 * ##Miscellaneous APIs
 *
 */
 ///@{
 
-/**
- * lws_start_foreach_ll(): linkedlist iterator helper start
- *
- * \param type: type of iteration, eg, struct xyz *
- * \param it: iterator var name to create
- * \param start: start of list
- *
- * This helper creates an iterator and starts a while (it) {
- * loop.  The iterator runs through the linked list starting at start and
- * ends when it gets a NULL.
- * The while loop should be terminated using lws_start_foreach_ll().
- */
-#define lws_start_foreach_ll(type, it, start)\
-{ \
-       type it = start; \
-       while (it) {
-
-/**
- * lws_end_foreach_ll(): linkedlist iterator helper end
- *
- * \param it: same iterator var name given when starting
- * \param nxt: member name in the iterator pointing to next list element
- *
- * This helper is the partner for lws_start_foreach_ll() that ends the
- * while loop.
- */
-
-#define lws_end_foreach_ll(it, nxt) \
-               it = it->nxt; \
-       } \
-}
-
-/**
- * lws_start_foreach_ll_safe(): linkedlist iterator helper start safe against delete
- *
- * \param type: type of iteration, eg, struct xyz *
- * \param it: iterator var name to create
- * \param start: start of list
- * \param nxt: member name in the iterator pointing to next list element
- *
- * This helper creates an iterator and starts a while (it) {
- * loop.  The iterator runs through the linked list starting at start and
- * ends when it gets a NULL.
- * The while loop should be terminated using lws_end_foreach_ll_safe().
- * Performs storage of next increment for situations where iterator can become invalidated
- * during iteration.
- */
-#define lws_start_foreach_ll_safe(type, it, start, nxt)\
-{ \
-       type it = start; \
-       while (it) { \
-               type next_##it = it->nxt;
-
-/**
- * lws_end_foreach_ll_safe(): linkedlist iterator helper end (pre increment storage)
- *
- * \param it: same iterator var name given when starting
- *
- * This helper is the partner for lws_start_foreach_ll_safe() that ends the
- * while loop. It uses the precreated next_ variable already stored during
- * start.
- */
-
-#define lws_end_foreach_ll_safe(it) \
-               it = next_##it; \
-       } \
-}
-
-/**
- * lws_start_foreach_llp(): linkedlist pointer iterator helper start
- *
- * \param type: type of iteration, eg, struct xyz **
- * \param it: iterator var name to create
- * \param start: start of list
- *
- * This helper creates an iterator and starts a while (it) {
- * loop.  The iterator runs through the linked list starting at the
- * address of start and ends when it gets a NULL.
- * The while loop should be terminated using lws_start_foreach_llp().
- *
- * This helper variant iterates using a pointer to the previous linked-list
- * element.  That allows you to easily delete list members by rewriting the
- * previous pointer to the element's next pointer.
- */
-#define lws_start_foreach_llp(type, it, start)\
-{ \
-       type it = &(start); \
-       while (*(it)) {
-
-#define lws_start_foreach_llp_safe(type, it, start, nxt)\
-{ \
-       type it = &(start); \
-       type next; \
-       while (*(it)) { \
-               next = &((*(it))->nxt); \
-
-/**
- * lws_end_foreach_llp(): linkedlist pointer iterator helper end
- *
- * \param it: same iterator var name given when starting
- * \param nxt: member name in the iterator pointing to next list element
- *
- * This helper is the partner for lws_start_foreach_llp() that ends the
- * while loop.
- */
-
-#define lws_end_foreach_llp(it, nxt) \
-               it = &(*(it))->nxt; \
-       } \
-}
-
-#define lws_end_foreach_llp_safe(it) \
-               it = next; \
-       } \
-}
-
-#define lws_ll_fwd_insert(\
-       ___new_object,  /* pointer to new object */ \
-       ___m_list,      /* member for next list object ptr */ \
-       ___list_head    /* list head */ \
-               ) {\
-               ___new_object->___m_list = ___list_head; \
-               ___list_head = ___new_object; \
-       }
-
-#define lws_ll_fwd_remove(\
-       ___type,        /* type of listed object */ \
-       ___m_list,      /* member for next list object ptr */ \
-       ___target,      /* object to remove from list */ \
-       ___list_head    /* list head */ \
-       ) { \
-                lws_start_foreach_llp(___type **, ___ppss, ___list_head) { \
-                        if (*___ppss == ___target) { \
-                                *___ppss = ___target->___m_list; \
-                                break; \
-                        } \
-                } lws_end_foreach_llp(___ppss, ___m_list); \
-       }
-
-/*
- * doubly linked-list
- */
-
-#if defined (LWS_WITH_DEPRECATED_LWS_DLL)
-
-/*
- * This is going away in v4.1.  You can set the cmake option above to keep it
- * around temporarily.  Migrate your stuff to the more capable and robust
- * lws_dll2 below
- */
-
-struct lws_dll {
-       struct lws_dll *prev;
-       struct lws_dll *next;
-};
-
-/*
- * these all point to the composed list objects... you have to use the
- * lws_container_of() helper to recover the start of the containing struct
- */
-
-#define lws_dll_add_front lws_dll_add_head
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll_add_head(struct lws_dll *d, struct lws_dll *phead);
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll_add_tail(struct lws_dll *d, struct lws_dll *phead);
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll_insert(struct lws_dll *d, struct lws_dll *target,
-              struct lws_dll *phead, int before);
-
-static LWS_INLINE struct lws_dll *
-lws_dll_get_head(struct lws_dll *phead) { return phead->next; }
-
-static LWS_INLINE struct lws_dll *
-lws_dll_get_tail(struct lws_dll *phead) { return phead->prev; }
-
-/*
- * caution, this doesn't track the tail in the head struct.  Use
- * lws_dll_remove_track_tail() instead of this if you want tail tracking.  Using
- * this means you can't use lws_dll_add_tail() amd
- */
-LWS_VISIBLE LWS_EXTERN void
-lws_dll_remove(struct lws_dll *d) LWS_WARN_DEPRECATED;
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll_remove_track_tail(struct lws_dll *d, struct lws_dll *phead);
-
-/* another way to do lws_start_foreach_dll_safe() on a list via a cb */
-
-LWS_VISIBLE LWS_EXTERN int
-lws_dll_foreach_safe(struct lws_dll *phead, void *user,
-                    int (*cb)(struct lws_dll *d, void *user));
-
-#define lws_dll_is_detached(___dll, __head) \
-       (!(___dll)->prev && !(___dll)->next && (__head)->prev != (___dll))
-
-#endif
-
-/*
- * lws_dll2_owner / lws_dll2 : more capable version of lws_dll.  Differences:
- *
- *  - there's an explicit lws_dll2_owner struct which holds head, tail and
- *    count of members.
- *
- *  - list members all hold a pointer to their owner.  So user code does not
- *    have to track anything about exactly what lws_dll2_owner list the object
- *    is a member of.
- *
- *  - you can use lws_dll unless you want the member count or the ability to
- *    not track exactly which list it's on.
- *
- *  - layout is compatible with lws_dll (but lws_dll apis will not update the
- *    new stuff)
- */
-
-
-struct lws_dll2;
-struct lws_dll2_owner;
-
-typedef struct lws_dll2 {
-       struct lws_dll2         *prev;
-       struct lws_dll2         *next;
-       struct lws_dll2_owner   *owner;
-} lws_dll2_t;
-
-typedef struct lws_dll2_owner {
-       struct lws_dll2         *tail;
-       struct lws_dll2         *head;
-
-       uint32_t                count;
-} lws_dll2_owner_t;
-
-static LWS_INLINE int
-lws_dll2_is_detached(const struct lws_dll2 *d) { return !d->owner; }
-
-static LWS_INLINE const struct lws_dll2_owner *
-lws_dll2_owner(const struct lws_dll2 *d) { return d->owner; }
-
-static LWS_INLINE struct lws_dll2 *
-lws_dll2_get_head(struct lws_dll2_owner *owner) { return owner->head; }
-
-static LWS_INLINE struct lws_dll2 *
-lws_dll2_get_tail(struct lws_dll2_owner *owner) { return owner->tail; }
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner);
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner);
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll2_remove(struct lws_dll2 *d);
-
-LWS_VISIBLE LWS_EXTERN int
-lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
-                     int (*cb)(struct lws_dll2 *d, void *user));
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll2_clear(struct lws_dll2 *d);
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll2_owner_clear(struct lws_dll2_owner *d);
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll2_add_before(struct lws_dll2 *d, struct lws_dll2 *after);
-
-LWS_VISIBLE LWS_EXTERN void
-lws_dll2_add_sorted(lws_dll2_t *d, lws_dll2_owner_t *own,
-                   int (*compare)(const lws_dll2_t *d, const lws_dll2_t *i));
-
-#if defined(_DEBUG)
-void
-lws_dll2_describe(struct lws_dll2_owner *owner, const char *desc);
-#else
-#define lws_dll2_describe(x, y)
-#endif
-
-/*
- * these are safe against the current container object getting deleted,
- * since the hold his next in a temp and go to that next.  ___tmp is
- * the temp.
- */
-
-#define lws_start_foreach_dll_safe(___type, ___it, ___tmp, ___start) \
-{ \
-       ___type ___it = ___start; \
-       while (___it) { \
-               ___type ___tmp = (___it)->next;
-
-#define lws_end_foreach_dll_safe(___it, ___tmp) \
-               ___it = ___tmp; \
-       } \
-}
-
-#define lws_start_foreach_dll(___type, ___it, ___start) \
-{ \
-       ___type ___it = ___start; \
-       while (___it) {
-
-#define lws_end_foreach_dll(___it) \
-               ___it = (___it)->next; \
-       } \
-}
-
 struct lws_buflist;
 
 /**
@@ -378,10 +85,76 @@ lws_buflist_next_segment_len(struct lws_buflist **head, uint8_t **buf);
  * Returns the number of bytes left in the current segment.  0 indicates
  * that the buflist is empty (there are no segments on the buflist).
  */
-LWS_VISIBLE LWS_EXTERN int
+LWS_VISIBLE LWS_EXTERN size_t
 lws_buflist_use_segment(struct lws_buflist **head, size_t len);
 
 /**
+ * lws_buflist_total_len(): Get the total size of the buflist
+ *
+ * \param head: list head
+ *
+ * Returns the total number of bytes held on all segments of the buflist
+ */
+LWS_VISIBLE LWS_EXTERN size_t
+lws_buflist_total_len(struct lws_buflist **head);
+
+/**
+ * lws_buflist_linear_copy(): copy everything out as one without consuming
+ *
+ * \param head: list head
+ * \param ofs: start offset into buflist in bytes
+ * \param buf: buffer to copy linearly into
+ * \param len: length of buffer available
+ *
+ * Returns -1 if len is too small, or bytes copied.  Happy to do partial
+ * copies, returns 0 when there are no more bytes to copy.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_buflist_linear_copy(struct lws_buflist **head, size_t ofs, uint8_t *buf,
+                       size_t len);
+
+/**
+ * lws_buflist_linear_use(): copy and consume from buflist head
+ *
+ * \param head: list head
+ * \param buf: buffer to copy linearly into
+ * \param len: length of buffer available
+ *
+ * Copies a possibly fragmented buflist from the head into the linear output
+ * buffer \p buf for up to length \p len, and consumes the buflist content that
+ * was copied out.
+ *
+ * Since it was consumed, calling again will resume copying out and consuming
+ * from as far as it got the first time.
+ *
+ * Returns the number of bytes written into \p buf.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_buflist_linear_use(struct lws_buflist **head, uint8_t *buf, size_t len);
+
+/**
+ * lws_buflist_fragment_use(): copy and consume <= 1 frag from buflist head
+ *
+ * \param head: list head
+ * \param buf: buffer to copy linearly into
+ * \param len: length of buffer available
+ * \param frag_first: pointer to char written on exit to if this is start of frag
+ * \param frag_fin: pointer to char written on exit to if this is end of frag
+ *
+ * Copies all or part of the fragment at the start of a buflist from the head
+ * into the output buffer \p buf for up to length \p len, and consumes the
+ * buflist content that was copied out.
+ *
+ * Since it was consumed, calling again will resume copying out and consuming
+ * from as far as it got the first time.
+ *
+ * Returns the number of bytes written into \p buf.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_buflist_fragment_use(struct lws_buflist **head, uint8_t *buf,
+                        size_t len, char *frag_first, char *frag_fin);
+
+/**
  * lws_buflist_destroy_all_segments(): free all segments on the list
  *
  * \param head: list head
@@ -392,8 +165,18 @@ lws_buflist_use_segment(struct lws_buflist **head, size_t len);
 LWS_VISIBLE LWS_EXTERN void
 lws_buflist_destroy_all_segments(struct lws_buflist **head);
 
-void
-lws_buflist_describe(struct lws_buflist **head, void *id);
+/**
+ * lws_buflist_describe(): debug helper logging buflist status
+ *
+ * \param head: list head
+ * \param id: pointer shown in debug list
+ * \param reason: reason string show in debug list
+ *
+ * Iterates through the buflist segments showing position and size.
+ * This only exists when lws was built in debug mode
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_buflist_describe(struct lws_buflist **head, void *id, const char *reason);
 
 /**
  * lws_ptr_diff(): helper to report distance between pointers as an int
@@ -407,6 +190,9 @@ lws_buflist_describe(struct lws_buflist **head, void *id);
 #define lws_ptr_diff(head, tail) \
                        ((int)((char *)(head) - (char *)(tail)))
 
+#define lws_ptr_diff_size_t(head, tail) \
+                       ((size_t)(ssize_t)((char *)(head) - (char *)(tail)))
+
 /**
  * lws_snprintf(): snprintf that truncates the returned length too
  *
@@ -434,6 +220,76 @@ lws_snprintf(char *str, size_t size, const char *format, ...) LWS_FORMAT(3);
 LWS_VISIBLE LWS_EXTERN char *
 lws_strncpy(char *dest, const char *src, size_t size);
 
+/*
+ * Variation where we want to use the smaller of two lengths, useful when the
+ * source string is not NUL terminated
+ */
+#define lws_strnncpy(dest, src, size1, destsize) \
+       lws_strncpy(dest, src, (size_t)(size1 + 1) < (size_t)(destsize) ? \
+                               (size_t)(size1 + 1) : (size_t)(destsize))
+
+/**
+ * lws_nstrstr(): like strstr for length-based strings without terminating NUL
+ *
+ * \param buf: the string to search
+ * \param len: the length of the string to search
+ * \param name: the substring to search for
+ * \param nl: the length of name
+ *
+ * Returns NULL if \p name is not present in \p buf.  Otherwise returns the
+ * address of the first instance of \p name in \p buf.
+ *
+ * Neither buf nor name need to be NUL-terminated.
+ */
+LWS_VISIBLE LWS_EXTERN const char *
+lws_nstrstr(const char *buf, size_t len, const char *name, size_t nl);
+
+/**
+ * lws_json_simple_find(): dumb JSON string parser
+ *
+ * \param buf: the JSON to search
+ * \param len: the length of the JSON to search
+ * \param name: the name field to search the JSON for, eg, "\"myname\":"
+ * \param alen: set to the length of the argument part if non-NULL return
+ *
+ * Either returns NULL if \p name is not present in buf, or returns a pointer
+ * to the argument body of the first instance of \p name, and sets *alen to the
+ * length of the argument body.
+ *
+ * This can cheaply handle fishing out, eg, myarg from {"myname": "myarg"} by
+ * searching for "\"myname\":".  It will return a pointer to myarg and set *alen
+ * to 5.  It equally handles args like "myname": true, or "myname":false, and
+ * null or numbers are all returned as delimited strings.
+ *
+ * Anything more complicated like the value is a subobject or array, you should
+ * parse it using a full parser like lejp.  This is suitable is the JSON is
+ * and will remain short and simple, and contains well-known names amongst other
+ * extensible JSON members.
+ */
+LWS_VISIBLE LWS_EXTERN const char *
+lws_json_simple_find(const char *buf, size_t len, const char *name, size_t *alen);
+
+/**
+ * lws_json_simple_strcmp(): dumb JSON string comparison
+ *
+ * \param buf: the JSON to search
+ * \param len: the length of the JSON to search
+ * \param name: the name field to search the JSON for, eg, "\"myname\":"
+ * \param comp: return a strcmp of this and the discovered argument
+ *
+ * Helper that combines lws_json_simple_find() with strcmp() if it was found.
+ * If the \p name was not found, returns -1.  Otherwise returns a strcmp()
+ * between what was found and \p comp, ie, return 0 if they match or something
+ * else if they don't.
+ *
+ * If the JSON is relatively simple and you want to target constrained
+ * devices, this can be a good choice.  If the JSON may be complex, you
+ * should use a full JSON parser.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_json_simple_strcmp(const char *buf, size_t len, const char *name, const char *comp);
+
+
 /**
  * lws_hex_to_byte_array(): convert hex string like 0123456789ab into byte data
  *
@@ -453,6 +309,36 @@ lws_strncpy(char *dest, const char *src, size_t size);
 LWS_VISIBLE LWS_EXTERN int
 lws_hex_to_byte_array(const char *h, uint8_t *dest, int max);
 
+/**
+ * lws_hex_from_byte_array(): render byte array as hex char string
+ *
+ * \param src: incoming binary source array
+ * \param slen: length of src in bytes
+ * \param dest: array to fill with hex chars representing src
+ * \param len: max extent of dest
+ *
+ * This converts binary data of length slen at src, into a hex string at dest
+ * of maximum length len.  Even if truncated, the result will be NUL-terminated.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_hex_from_byte_array(const uint8_t *src, size_t slen, char *dest, size_t len);
+
+/**
+ * lws_hex_random(): generate len - 1 or - 2 characters of random ascii hex
+ *
+ * \param context: the lws_context used to get the random
+ * \param dest: destination for hex ascii chars
+ * \param len: the number of bytes the buffer dest points to can hold
+ *
+ * This creates random ascii-hex strings up to a given length, with a
+ * terminating NUL.
+ *
+ * There will not be any characters produced that are not 0-9, a-f, so it's
+ * safe to go straight into, eg, JSON.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_hex_random(struct lws_context *context, char *dest, size_t len);
+
 /*
  * lws_timingsafe_bcmp(): constant time memcmp
  *
@@ -479,8 +365,8 @@ lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len);
  * Fills buf with len bytes of random.  Returns the number of bytes set, if
  * not equal to len, then getting the random failed.
  */
-LWS_VISIBLE LWS_EXTERN int
-lws_get_random(struct lws_context *context, void *buf, int len);
+LWS_VISIBLE LWS_EXTERN size_t
+lws_get_random(struct lws_context *context, void *buf, size_t len);
 /**
  * lws_daemonize(): make current process run in the background
  *
@@ -508,6 +394,15 @@ LWS_VISIBLE LWS_EXTERN void *
 lws_wsi_user(struct lws *wsi);
 
 /**
+ * lws_wsi_tsi() - get the service thread index the wsi is bound to
+ * \param wsi: lws connection
+ *
+ * Only useful is LWS_MAX_SMP > 1
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_wsi_tsi(struct lws *wsi);
+
+/**
  * lws_set_wsi_user() - set the user data associated with the client connection
  * \param wsi: lws connection
  * \param user: user data
@@ -566,6 +461,22 @@ LWS_VISIBLE LWS_EXTERN const char *
 lws_cmdline_option(int argc, const char **argv, const char *val);
 
 /**
+ * lws_cmdline_option_handle_builtin(): apply standard cmdline options
+ *
+ * \param argc:                count of argument strings
+ * \param argv:                argument strings
+ * \param info:                context creation info
+ *
+ * Applies standard options to the context creation info to save them having
+ * to be (unevenly) copied into the minimal examples.
+ *
+ * Applies default log levels that can be overriden by -d
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_cmdline_option_handle_builtin(int argc, const char **argv,
+                                 struct lws_context_creation_info *info);
+
+/**
  * lws_now_secs(): return seconds since 1970-1-1
  */
 LWS_VISIBLE LWS_EXTERN unsigned long
@@ -645,7 +556,7 @@ lws_get_child(const struct lws *wsi);
  * and subdir creation / permissions down /var/cache dynamically.
  */
 LWS_VISIBLE LWS_EXTERN void
-lws_get_effective_uid_gid(struct lws_context *context, int *uid, int *gid);
+lws_get_effective_uid_gid(struct lws_context *context, uid_t *uid, gid_t *gid);
 
 /**
  * lws_get_udp() - get wsi's udp struct
@@ -815,6 +726,53 @@ lws_dir_callback_function(const char *dirpath, void *user,
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb);
+
+/**
+ * lws_dir_rm_rf_cb() - callback for lws_dir that performs recursive rm -rf
+ *
+ * \param dirpath: directory we are at in lws_dir
+ * \param user: ignored
+ * \param lde: lws_dir info on the file or directory we are at
+ *
+ * This is a readymade rm -rf callback for use with lws_dir.  It recursively
+ * removes everything below the starting dir and then the starting dir itself.
+ * Works on linux, OSX and Windows at least.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_dir_rm_rf_cb(const char *dirpath, void *user, struct lws_dir_entry *lde);
+
+/*
+ * We pass every file in the base dir through a filter, and call back on the
+ * ones that match.  Directories are ignored.
+ *
+ * The original path filter string may look like, eg, "sai-*.deb" or "*.txt"
+ */
+
+typedef int (*lws_dir_glob_cb_t)(void *data, const char *path);
+
+typedef struct lws_dir_glob {
+       const char              *filter;
+       lws_dir_glob_cb_t       cb;
+       void                    *user;
+} lws_dir_glob_t;
+
+/**
+ * lws_dir_glob_cb() - callback for lws_dir that performs filename globbing
+ *
+ * \param dirpath: directory we are at in lws_dir
+ * \param user: pointer to your prepared lws_dir_glob_cb_t
+ * \param lde: lws_dir info on the file or directory we are at
+ *
+ * \p user is prepared with an `lws_dir_glob_t` containing a callback for paths
+ * that pass the filtering, a user pointer to pass to that callback, and a
+ * glob string like "*.txt".  It may not contain directories, the lws_dir musr
+ * be started at the correct dir.
+ *
+ * Only the base path passed to lws_dir is scanned, it does not look in subdirs.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_dir_glob_cb(const char *dirpath, void *user, struct lws_dir_entry *lde);
+
 #endif
 
 /**
@@ -835,12 +793,19 @@ lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb);
 size_t lws_get_allocated_heap(void);
 
 /**
+ * lws_get_tsi() - Get thread service index wsi belong to
+ * \param wsi:  websocket connection to check
+ *
+ * Returns more than zero (or zero if only one service thread as is the default).
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_get_tsi(struct lws *wsi);
+
+/**
  * lws_is_ssl() - Find out if connection is using SSL
  * \param wsi: websocket connection to check
  *
- *     Returns 0 if the connection is not using SSL, 1 if using SSL and
- *     using verified cert, and 2 if using SSL but the cert was not
- *     checked (appears for client wsi told to skip check on connection)
+ * Returns nonzero if the wsi is inside a tls tunnel, else zero.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_is_ssl(struct lws *wsi);
@@ -853,6 +818,25 @@ LWS_VISIBLE LWS_EXTERN int
 lws_is_cgi(struct lws *wsi);
 
 /**
+ * lws_tls_jit_trust_blob_queury_skid() - walk jit trust blob for skid
+ *
+ * \param _blob: the start of the blob in memory
+ * \param blen: the length of the blob in memory
+ * \param skid: the SKID we are looking for
+ * \param skid_len: the length of the SKID we are looking for
+ * \param prpder: result pointer to receive a pointer to the matching DER
+ * \param prder_len: result pointer to receive matching DER length
+ *
+ * Helper to scan a JIT Trust blob in memory for a trusted CA cert matching
+ * a given SKID.  Returns 0 if found and *prpder and *prder_len are set, else
+ * nonzero.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_tls_jit_trust_blob_queury_skid(const void *_blob, size_t blen,
+                                  const uint8_t *skid, size_t skid_len,
+                                  const uint8_t **prpder, size_t *prder_len);
+
+/**
  * lws_open() - platform-specific wrapper for open that prepares the fd
  *
  * \param __file: the filepath to open
@@ -894,9 +878,9 @@ typedef struct lws_humanize_unit {
        uint64_t factor;
 } lws_humanize_unit_t;
 
-LWS_VISIBLE LWS_EXTERN const lws_humanize_unit_t humanize_schema_si[7];
-LWS_VISIBLE LWS_EXTERN const lws_humanize_unit_t humanize_schema_si_bytes[7];
-LWS_VISIBLE LWS_EXTERN const lws_humanize_unit_t humanize_schema_us[8];
+LWS_VISIBLE extern const lws_humanize_unit_t humanize_schema_si[7];
+LWS_VISIBLE extern const lws_humanize_unit_t humanize_schema_si_bytes[7];
+LWS_VISIBLE extern const lws_humanize_unit_t humanize_schema_us[8];
 
 /**
  * lws_humanize() - Convert possibly large number to human-readable uints
@@ -920,7 +904,219 @@ LWS_VISIBLE LWS_EXTERN const lws_humanize_unit_t humanize_schema_us[8];
  */
 
 LWS_VISIBLE LWS_EXTERN int
-lws_humanize(char *buf, int len, uint64_t value,
+lws_humanize(char *buf, size_t len, uint64_t value,
             const lws_humanize_unit_t *schema);
 
+LWS_VISIBLE LWS_EXTERN void
+lws_ser_wu16be(uint8_t *b, uint16_t u);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_ser_wu32be(uint8_t *b, uint32_t u32);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_ser_wu64be(uint8_t *b, uint64_t u64);
+
+LWS_VISIBLE LWS_EXTERN uint16_t
+lws_ser_ru16be(const uint8_t *b);
+
+LWS_VISIBLE LWS_EXTERN uint32_t
+lws_ser_ru32be(const uint8_t *b);
+
+LWS_VISIBLE LWS_EXTERN uint64_t
+lws_ser_ru64be(const uint8_t *b);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_vbi_encode(uint64_t value, void *buf);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_vbi_decode(const void *buf, uint64_t *value, size_t len);
+
 ///@}
+
+#if defined(LWS_WITH_SPAWN)
+
+/* opaque internal struct */
+struct lws_spawn_piped;
+
+#if defined(WIN32)
+struct _lws_siginfo_t {
+       int retcode;
+};
+typedef struct _lws_siginfo_t siginfo_t;
+#endif
+
+typedef void (*lsp_cb_t)(void *opaque, lws_usec_t *accounting, siginfo_t *si,
+                        int we_killed_him);
+
+
+/**
+ * lws_spawn_piped_info - details given to create a spawned pipe
+ *
+ * \p owner: lws_dll2_owner_t that lists all active spawns, or NULL
+ * \p vh: vhost to bind stdwsi to... from opt_parent if given
+ * \p opt_parent: optional parent wsi for stdwsi
+ * \p exec_array: argv for process to spawn
+ * \p env_array: environment for spawned process, NULL ends env list
+ * \p protocol_name: NULL, or vhost protocol name to bind stdwsi to
+ * \p chroot_path: NULL, or chroot patch for child process
+ * \p wd: working directory to cd to after fork, NULL defaults to /tmp
+ * \p plsp: NULL, or pointer to the outer lsp pointer so it can be set NULL when destroyed
+ * \p opaque: pointer passed to the reap callback, if any
+ * \p timeout: optional us-resolution timeout, or zero
+ * \p reap_cb: callback when child process has been reaped and the lsp destroyed
+ * \p tsi: tsi to bind stdwsi to... from opt_parent if given
+ */
+struct lws_spawn_piped_info {
+       struct lws_dll2_owner           *owner;
+       struct lws_vhost                *vh;
+       struct lws                      *opt_parent;
+
+       const char * const              *exec_array;
+       const char                      **env_array;
+       const char                      *protocol_name;
+       const char                      *chroot_path;
+       const char                      *wd;
+
+       struct lws_spawn_piped          **plsp;
+
+       void                            *opaque;
+
+       lsp_cb_t                        reap_cb;
+
+       lws_usec_t                      timeout_us;
+       int                             max_log_lines;
+       int                             tsi;
+
+       const struct lws_role_ops       *ops; /* NULL is raw file */
+
+       uint8_t                         disable_ctrlc;
+};
+
+/**
+ * lws_spawn_piped() - spawn a child process with stdxxx redirected
+ *
+ * \p lspi: info struct describing details of spawn to create
+ *
+ * This spawns a child process managed in the lsp object and with attributes
+ * set in the arguments.  The stdin/out/err streams are redirected to pipes
+ * which are instantiated into wsi that become child wsi of \p parent if non-
+ * NULL.  .opaque_user_data on the stdwsi created is set to point to the
+ * lsp object, so this can be recovered easily in the protocol handler.
+ *
+ * If \p owner is non-NULL, successful spawns join the given dll2 owner in the
+ * original process.
+ *
+ * If \p timeout is non-zero, successful spawns register a sul with the us-
+ * resolution timeout to callback \p timeout_cb, in the original process.
+ *
+ * Returns 0 if the spawn went OK or nonzero if it failed and was cleaned up.
+ * The spawned process continues asynchronously and this will return after
+ * starting it if all went well.
+ */
+LWS_VISIBLE LWS_EXTERN struct lws_spawn_piped *
+lws_spawn_piped(const struct lws_spawn_piped_info *lspi);
+
+/*
+ * lws_spawn_piped_kill_child_process() - attempt to kill child process
+ *
+ * \p lsp: child object to kill
+ *
+ * Attempts to signal the child process in \p lsp to terminate.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_spawn_piped_kill_child_process(struct lws_spawn_piped *lsp);
+
+/**
+ * lws_spawn_stdwsi_closed() - inform the spawn one of its stdxxx pipes closed
+ *
+ * \p lsp: the spawn object
+ * \p wsi: the wsi that is closing
+ *
+ * When you notice one of the spawn stdxxx pipes closed, inform the spawn
+ * instance using this api.  When it sees all three have closed, it will
+ * automatically try to reap the child process.
+ *
+ * This is the mechanism whereby the spawn object can understand its child
+ * has closed.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_spawn_stdwsi_closed(struct lws_spawn_piped *lsp, struct lws *wsi);
+
+/**
+ * lws_spawn_get_stdfd() - return std channel index for stdwsi
+ *
+ * \p wsi: the wsi
+ *
+ * If you know wsi is a stdwsi from a spawn, you can determine its original
+ * channel index / fd before the pipes replaced the default fds.  It will return
+ * one of 0 (STDIN), 1 (STDOUT) or 2 (STDERR).  You can handle all three in the
+ * same protocol handler and then disambiguate them using this api.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_spawn_get_stdfd(struct lws *wsi);
+
+#endif
+
+struct lws_fsmount {
+       const char      *layers_path;   /* where layers live */
+       const char      *overlay_path;  /* where overlay instantiations live */
+
+       char            mp[256];        /* mountpoint path */
+       char            ovname[64];     /* unique name for mount instance */
+       char            distro[64];     /* unique name for layer source */
+
+#if defined(__linux__)
+       const char      *layers[4];     /* distro layers, like "base", "env" */
+#endif
+};
+
+/**
+ * lws_fsmount_mount() - Mounts an overlayfs stack of layers
+ *
+ * \p fsm: struct lws_fsmount specifying the mount layout
+ *
+ * This api is able to assemble up to 4 layer directories on to a mountpoint
+ * using overlayfs mount (Linux only).
+ *
+ * Set fsm.layers_path to the base dir where the layers themselves live, the
+ * entries in fsm.layers[] specifies the relative path to the layer, comprising
+ * fsm.layers_path/fsm.distro/fsm.layers[], with [0] being the deepest, earliest
+ * layer and the rest being progressively on top of [0]; NULL indicates the
+ * layer is unused.
+ *
+ * fsm.overlay_path is the base path of the overlayfs instantiations... empty
+ * dirs must exist at
+ *
+ * fsm.overlay_path/overlays/fsm.ovname/work
+ * fsm.overlay_path/overlays/fsm.ovname/session
+ *
+ * Set fsm.mp to the path of an already-existing empty dir that will be the
+ * mountpoint, this can be whereever you like.
+ *
+ * Overlayfs merges the union of all the contributing layers at the mountpoint,
+ * the mount is writeable but the layer themselves are immutable, all additions
+ * and changes are stored in
+ *
+ * fsm.overlay_path/overlays/fsm.ovname/session
+ *
+ * Returns 0 if mounted OK, nonzero if errors.
+ *
+ * Retain fsm for use with unmounting.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_fsmount_mount(struct lws_fsmount *fsm);
+
+/**
+ * lws_fsmount_unmount() - Unmounts an overlayfs dir
+ *
+ * \p fsm: struct lws_fsmount specifying the mount layout
+ *
+ * Unmounts the mountpoint in fsm.mp.
+ *
+ * Delete fsm.overlay_path/overlays/fsm.ovname/session to permanently eradicate
+ * all changes from the time the mountpoint was in use.
+ *
+ * Returns 0 if unmounted OK.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_fsmount_unmount(struct lws_fsmount *fsm);
diff --git a/include/libwebsockets/lws-mqtt.h b/include/libwebsockets/lws-mqtt.h
new file mode 100644 (file)
index 0000000..2286580
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * libwebsockets - protocol - mqtt
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * included from libwebsockets.h
+ */
+
+#ifndef _LWS_MQTT_H
+#define _LWS_MQTT_H 1
+
+struct _lws_mqtt_related;
+typedef struct _lws_mqtt_related lws_mqtt_related_t;
+struct lws_mqtt_str_st;
+typedef struct lws_mqtt_str_st lws_mqtt_str_t;
+
+#define MQTT_VER_3_1_1 4
+
+#define LWS_MQTT_FINAL_PART 1
+
+#define LWS_MQTT_MAX_AWSIOT_TOPICLEN  256
+#define LWS_MQTT_MAX_TOPICLEN  65535
+#define LWS_MQTT_MAX_CIDLEN    128
+#define LWS_MQTT_RANDOM_CIDLEN 23 /* 3.1.3.1-5: Server MUST... between
+                                    1 and 23 chars... */
+
+typedef enum {
+       QOS0,
+       QOS1,
+       QOS2,                           /* not supported */
+       RESERVED_QOS_LEVEL,
+       FAILURE_QOS_LEVEL = 0x80
+} lws_mqtt_qos_levels_t;
+
+typedef union {
+       struct {
+               uint8_t         retain:1;
+               uint8_t         qos:2;
+               uint8_t         dup:1;
+               uint8_t         ctrl_pkt_type:4;
+       } flags;
+       uint8_t                 bits;
+} lws_mqtt_fixed_hdr_t;
+
+/*
+ * MQTT connection parameters, passed into struct
+ * lws_client_connect_info to establish a connection using
+ * lws_client_connect_via_info().
+*/
+typedef struct lws_mqtt_client_connect_param_s {
+       const char                      *client_id;     /* Client ID */
+       uint16_t                        keep_alive;     /* MQTT keep alive
+                                                          interval in
+                                                          seconds */
+       uint8_t                         clean_start:1;  /* MQTT clean
+                                                          session */
+       uint8_t                         client_id_nofree:1;
+       /**< do not free the client id */
+       uint8_t                         username_nofree:1;
+       /**< do not free the username */
+       uint8_t                         password_nofree:1;
+       /**< do not free the password */
+       struct {
+               const char              *topic;
+               const char              *message;
+               lws_mqtt_qos_levels_t   qos;
+               uint8_t                 retain;
+       } will_param;                           /* MQTT LWT
+                                                  parameters */
+       struct {
+               const char              *topic;
+               const char              *message;
+               lws_mqtt_qos_levels_t   qos;
+               uint8_t                 retain;
+       } birth_param;                          /* MQTT Birth
+                                                  parameters */
+       const char                      *username;
+       const char                      *password;
+       uint8_t                         aws_iot;
+} lws_mqtt_client_connect_param_t;
+
+/*
+ * MQTT publish parameters
+*/
+typedef struct lws_mqtt_publish_param_s {
+       char                    *topic;         /* Topic Name */
+       uint16_t                topic_len;
+       const void              *payload;       /* Publish Payload */
+       uint32_t                payload_len;    /* Size of the
+                                                  complete payload */
+       uint32_t                payload_pos;    /* where we are in payload */
+       lws_mqtt_qos_levels_t   qos;
+
+       /*--v-Following will be used by LWS-v--*/
+       uint16_t                packet_id;      /* Packet ID for QoS >
+                                                  0 */
+       uint8_t                 dup:1;          /* Retried PUBLISH,
+                                                  for QoS > 0 */
+} lws_mqtt_publish_param_t;
+
+typedef struct topic_elem {
+       const char              *name;          /* Topic Name */
+       lws_mqtt_qos_levels_t   qos;            /* Requested QoS */
+
+       /*--v-Following will be used by LWS-v--*/
+       uint8_t                 acked;
+} lws_mqtt_topic_elem_t;
+
+/*
+ * MQTT publish parameters
+*/
+typedef struct lws_mqtt_subscribe_param_s {
+       uint32_t                num_topics;     /* Number of topics */
+       lws_mqtt_topic_elem_t   *topic;         /* Array of topic elements */
+
+       /*--v-Following will be used by LWS-v--*/
+       uint16_t                packet_id;
+} lws_mqtt_subscribe_param_t;
+
+typedef enum {
+       LMQCP_RESERVED,
+       LMQCP_CTOS_CONNECT,     /* Connection request */
+       LMQCP_STOC_CONNACK,     /* Connection acknowledgment */
+       LMQCP_PUBLISH,          /* Publish Message */
+       LMQCP_PUBACK,           /* QoS 1:   Publish acknowledgment */
+       LMQCP_PUBREC,           /* QoS 2.1: Publish received */
+       LMQCP_PUBREL,           /* QoS 2.2: Publish release */
+       LMQCP_PUBCOMP,          /* QoS 2.3: Publish complete */
+       LMQCP_CTOS_SUBSCRIBE,   /* Subscribe request */
+       LMQCP_STOC_SUBACK,      /* Subscribe acknowledgment */
+       LMQCP_CTOS_UNSUBSCRIBE, /* Unsubscribe request */
+       LMQCP_STOC_UNSUBACK,    /* Unsubscribe acknowledgment */
+       LMQCP_CTOS_PINGREQ,     /* PING request */
+       LMQCP_STOC_PINGRESP,    /* PONG response */
+       LMQCP_DISCONNECT,       /* Disconnect notification */
+       LMQCP_AUTH              /* Authentication exchange */
+} lws_mqtt_control_packet_t;
+
+/* flags from byte 8 of C_TO_S CONNECT */
+typedef enum {
+       LMQCFT_USERNAME_NOFREE                                  = (1 << 10),
+       LMQCFT_PASSWORD_NOFREE                                  = (1 << 9),
+       LMQCFT_CLIENT_ID_NOFREE                                 = (1 << 8),
+       /* only the low 8 are standardized and go out in the protocol */
+       LMQCFT_USERNAME                                         = (1 << 7),
+       LMQCFT_PASSWORD                                         = (1 << 6),
+       LMQCFT_WILL_RETAIN                                      = (1 << 5),
+       LMQCFT_WILL_QOS                                         = (1 << 3),
+       LMQCFT_WILL_FLAG                                        = (1 << 2),
+       LMQCFT_CLEAN_START                                      = (1 << 1),
+       LMQCFT_RESERVED                                         = (1 << 0),
+
+       LMQCFT_WILL_QOS_MASK                                    = (3 << 3),
+} lws_mqtt_connect_flags_t;
+
+/* flags for S_TO_C CONNACK */
+typedef enum {
+       LMQCFT_SESSION_PRESENT                                  = (1 << 0),
+} lws_mqtt_connack_flags_t;
+
+typedef enum {
+       LMQCP_REASON_SUCCESS                                    = 0x00,
+       LMQCP_REASON_NORMAL_DISCONNECTION                       = 0x00,
+       LMQCP_REASON_GRANTED_QOS0                               = 0x00,
+       LMQCP_REASON_GRANTED_QOS1                               = 0x01,
+       LMQCP_REASON_GRANTED_QOS2                               = 0x02,
+       LMQCP_REASON_DISCONNECT_WILL                            = 0x04,
+       LMQCP_REASON_NO_MATCHING_SUBSCRIBER                     = 0x10,
+       LMQCP_REASON_NO_SUBSCRIPTION_EXISTED                    = 0x11,
+       LMQCP_REASON_CONTINUE_AUTHENTICATION                    = 0x18,
+       LMQCP_REASON_RE_AUTHENTICATE                            = 0x19,
+
+       LMQCP_REASON_UNSPECIFIED_ERROR                          = 0x80,
+       LMQCP_REASON_MALFORMED_PACKET                           = 0x81,
+       LMQCP_REASON_PROTOCOL_ERROR                             = 0x82,
+       LMQCP_REASON_IMPLEMENTATION_SPECIFIC_ERROR              = 0x83,
+
+       /* Begin - Error codes for CONNACK */
+       LMQCP_REASON_UNSUPPORTED_PROTOCOL                       = 0x84,
+       LMQCP_REASON_CLIENT_ID_INVALID                          = 0x85,
+       LMQCP_REASON_BAD_CREDENTIALS                            = 0x86,
+       LMQCP_REASON_NOT_AUTHORIZED                             = 0x87,
+       /* End - Error codes for CONNACK */
+
+       LMQCP_REASON_SERVER_UNAVAILABLE                         = 0x88,
+       LMQCP_REASON_SERVER_BUSY                                = 0x89,
+       LMQCP_REASON_BANNED                                     = 0x8a,
+       LMQCP_REASON_SERVER_SHUTTING_DOWN                       = 0x8b,
+       LMQCP_REASON_BAD_AUTHENTICATION_METHOD                  = 0x8c,
+       LMQCP_REASON_KEEPALIVE_TIMEOUT                          = 0x8d,
+       LMQCP_REASON_SESSION_TAKEN_OVER                         = 0x8e,
+       LMQCP_REASON_TOPIC_FILTER_INVALID                       = 0x8f,
+       LMQCP_REASON_TOPIC_NAME_INVALID                         = 0x90,
+       LMQCP_REASON_PACKET_ID_IN_USE                           = 0x91,
+       LMQCP_REASON_PACKET_ID_NOT_FOUND                        = 0x92,
+       LMQCP_REASON_MAX_RX_EXCEEDED                            = 0x93,
+       LMQCP_REASON_TOPIC_ALIAS_INVALID                        = 0x94,
+       LMQCP_REASON_PACKET_TOO_LARGE                           = 0x95,
+       LMQCP_REASON_RATELIMIT                                  = 0x96,
+       LMQCP_REASON_QUOTA_EXCEEDED                             = 0x97,
+       LMQCP_REASON_ADMINISTRATIVE_ACTION                      = 0x98,
+       LMQCP_REASON_PAYLOAD_FORMAT_INVALID                     = 0x99,
+       LMQCP_REASON_RETAIN_NOT_SUPPORTED                       = 0x9a,
+       LMQCP_REASON_QOS_NOT_SUPPORTED                          = 0x9b,
+       LMQCP_REASON_USE_ANOTHER_SERVER                         = 0x9c,
+       LMQCP_REASON_SERVER_MOVED                               = 0x9d,
+       LMQCP_REASON_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED         = 0x9e,
+       LMQCP_REASON_CONNECTION_RATE_EXCEEDED                   = 0x9f,
+       LMQCP_REASON_MAXIMUM_CONNECT_TIME                       = 0xa0,
+       LMQCP_REASON_SUBSCRIPTION_IDS_NOT_SUPPORTED             = 0xa1,
+       LMQCP_REASON_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED       = 0xa2,
+} lws_mqtt_reason_t;
+
+typedef enum {
+       LMQPROP_INVALID,
+       LMQPROP_PAYLOAD_FORMAT_INDICATOR                        = 0x01,
+       LMQPROP_MESSAGE_EXPIRY_INTERVAL                         = 0x02,
+       LMQPROP_CONTENT_TYPE                                    = 0x03,
+       LMQPROP_RESPONSE_TOPIC                                  = 0x08,
+       LMQPROP_CORRELATION_DATA                                = 0x09,
+       LMQPROP_SUBSCRIPTION_IDENTIFIER                         = 0x0b,
+       LMQPROP_SESSION_EXPIRY_INTERVAL                         = 0x11,
+       LMQPROP_ASSIGNED_CLIENT_IDENTIFIER                      = 0x12,
+       LMQPROP_SERVER_KEEP_ALIVE                               = 0x13,
+       LMQPROP_AUTHENTICATION_METHOD                           = 0x15,
+       LMQPROP_AUTHENTICATION_DATA                             = 0x16,
+       LMQPROP_REQUEST_PROBLEM_INFORMATION                     = 0x17,
+       LMQPROP_WILL_DELAY_INTERVAL                             = 0x18,
+       LMQPROP_REQUEST_RESPONSE_INFORMATION                    = 0x19,
+       LMQPROP_RESPONSE_INFORMATION                            = 0x1a,
+       LMQPROP_SERVER_REFERENCE                                = 0x1c,
+       LMQPROP_REASON_STRING                                   = 0x1f,
+       LMQPROP_RECEIVE_MAXIMUM                                 = 0x21,
+       LMQPROP_TOPIC_ALIAS_MAXIMUM                             = 0x22,
+       LMQPROP_TOPIC_ALIAS                                     = 0x23,
+       LMQPROP_MAXIMUM_QOS                                     = 0x24,
+       LMQPROP_RETAIN_AVAILABLE                                = 0x25,
+       LMQPROP_USER_PROPERTY                                   = 0x26,
+       LMQPROP_MAXIMUM_PACKET_SIZE                             = 0x27,
+       LMQPROP_WILDCARD_SUBSCRIPTION_AVAIL                     = 0x28,
+       LMQPROP_SUBSCRIPTION_IDENTIFIER_AVAIL                   = 0x29,
+       LMQPROP_SHARED_SUBSCRIPTION_AVAIL                       = 0x2a
+} lws_mqtt_property;
+
+int
+lws_read_mqtt(struct lws *wsi, unsigned char *buf, lws_filepos_t len);
+
+/* returns 0 if bd1 and bd2 are "the same", that includes empty, else nonzero */
+LWS_VISIBLE LWS_EXTERN int
+lws_mqtt_bindata_cmp(const lws_mqtt_str_t *bd1, const lws_mqtt_str_t *bd2);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_mqtt_str_init(lws_mqtt_str_t *s, uint8_t *buf, uint16_t lim, char nf);
+
+LWS_VISIBLE LWS_EXTERN lws_mqtt_str_t *
+lws_mqtt_str_create(uint16_t lim);
+
+LWS_VISIBLE LWS_EXTERN lws_mqtt_str_t *
+lws_mqtt_str_create_init(uint8_t *buf, uint16_t len, uint16_t lim);
+
+LWS_VISIBLE LWS_EXTERN lws_mqtt_str_t *
+lws_mqtt_str_create_cstr_dup(const char *buf, uint16_t lim);
+
+LWS_VISIBLE LWS_EXTERN uint8_t *
+lws_mqtt_str_next(lws_mqtt_str_t *s, uint16_t *budget);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_mqtt_str_advance(lws_mqtt_str_t *s, int n);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_mqtt_str_free(lws_mqtt_str_t **s);
+
+
+/**
+ * lws_mqtt_client_send_publish() - lws_write a publish packet
+ *
+ * \param wsi: the mqtt child wsi
+ * \param pub: additional information on what we're publishing
+ * \param buf: payload to send
+ * \param len: length of data in buf
+ * \param final: flag indicating this is the last part
+ *
+ * Issues part of, or the whole of, a PUBLISH frame.  The first part of the
+ * frame contains the header, and uses the .qos and .payload_len parts of \p pub
+ * since MQTT requires the frame to specify the PUBLISH message length at the
+ * start.  The \p len paramter may be less than \p pub.payload_len, in which
+ * case subsequent calls with more payload are needed to complete the frame.
+ *
+ * Although the connection is stuck waiting for the remainder, in that it can't
+ * issue any other frames until the current one is completed, lws returns to the
+ * event loop normally and can continue the calls with additional payload even
+ * for huge frames as the data becomes available, consistent with timeout needs
+ * and latency to start any new frame (even, eg, related to ping / pong).
+ *
+ * If you're sending large frames, the OS will typically not allow the data to
+ * be sent all at once to kernel side.  So you should ideally cut the payload
+ * up into 1 or 2- mtu sized chunks and send that.
+ *
+ * Final should be set when you're calling with the last part of the payload.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_mqtt_client_send_publish(struct lws *wsi, lws_mqtt_publish_param_t *pub,
+                            const void *buf, uint32_t len, int final);
+
+/**
+ * lws_mqtt_client_send_subcribe() - lws_write a subscribe packet
+ *
+ * \param wsi: the mqtt child wsi
+ * \param sub: which topic(s) we want to subscribe to
+ *
+ * For topics other child streams have not already subscribed to, send a packet
+ * to the server asking to subscribe to them.  If all topics listed are already
+ * subscribed to be the shared network connection, just trigger the
+ * LWS_CALLBACK_MQTT_SUBSCRIBED callback as if a SUBACK had come.
+ *
+ * \p sub doesn't need to exist after the return from this function.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_mqtt_client_send_subcribe(struct lws *wsi, lws_mqtt_subscribe_param_t *sub);
+
+/**
+ * lws_mqtt_client_send_unsubcribe() - lws_write a unsubscribe packet
+ *
+ * \param wsi: the mqtt child wsi
+ * \param sub: which topic(s) we want to unsubscribe from
+ *
+ * For topics other child streams are not subscribed to, send a packet
+ * to the server asking to unsubscribe from them.  If all topics
+ * listed are already subscribed by other child streams on the shared
+ * network connection, just trigger the LWS_CALLBACK_MQTT_UNSUBSCRIBED
+ * callback as if a UNSUBACK had come.
+ *
+ * \p unsub doesn't need to exist after the return from this function.
+ */
+LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
+lws_mqtt_client_send_unsubcribe(struct lws *wsi,
+                               const lws_mqtt_subscribe_param_t *unsub);
+
+#endif /* _LWS_MQTT_H */
diff --git a/include/libwebsockets/lws-netdev.h b/include/libwebsockets/lws-netdev.h
new file mode 100644 (file)
index 0000000..8a0dc03
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define LWS_WIFI_MAX_SCAN_TRACK 16
+#define LWS_ETH_ALEN 6
+
+typedef uint8_t        lws_wifi_ch_t;
+typedef int8_t lws_wifi_rssi_t;
+struct lws_netdev_instance;
+
+typedef enum {
+       LWSNDTYP_UNKNOWN,
+       LWSNDTYP_WIFI,
+       LWSNDTYP_ETH,
+} lws_netdev_type_t;
+
+/*
+ * Base class for netdev configuration
+ */
+
+typedef struct lws_netdev_config {
+       void                            *plat_config;
+} lws_netdev_config_t;
+
+/*
+ * Const Logical generic network interface ops
+ */
+
+typedef struct lws_netdev_ops {
+       struct lws_netdev_instance * (*create)(struct lws_context *ctx,
+                                              const struct lws_netdev_ops *ops,
+                                              const char *name, void *platinfo);
+       int (*configure)(struct lws_netdev_instance *nd,
+                        lws_netdev_config_t *config);
+       int (*up)(struct lws_netdev_instance *nd);
+       int (*down)(struct lws_netdev_instance *nd);
+       int (*event)(struct lws_netdev_instance *nd, lws_usec_t timestamp,
+                    void *buf, size_t len);
+       /**< these are SMD events coming from lws event loop thread context */
+       void (*destroy)(struct lws_netdev_instance **pnd);
+       int (*connect)(struct lws_netdev_instance *wnd, const char *ssid,
+                           const char *passphrase, uint8_t *bssid);
+       void (*scan)(struct lws_netdev_instance *nd);
+} lws_netdev_ops_t;
+
+/*
+ * Network devices on this platform
+ *
+ * We also hold a list of all known network credentials (when they are needed
+ * because there is a network interface without anything to connect to) and
+ * the lws_settings instance they are stored in
+ */
+
+typedef struct lws_netdevs {
+       lws_dll2_owner_t                owner;
+       /**< list of netdevs / lws_netdev_instance_t -based objects */
+
+       lws_dll2_owner_t                owner_creds;
+       /**< list of known credentials */
+       struct lwsac                    *ac_creds;
+       /**< lwsac holding retreived credentials settings, or NULL */
+       lws_settings_instance_t         *si;
+
+       lws_sockaddr46                  sa46_dns_resolver;
+
+       uint8_t                         refcount_creds;
+       /**< when there are multiple netdevs, must refcount creds in mem */
+} lws_netdevs_t;
+
+/*
+ * Base class for an allocated instantiated derived object using lws_netdev_ops,
+ * ie, a specific ethernet device
+ */
+
+typedef struct lws_netdev_instance {
+       const char                      *name;
+       const lws_netdev_ops_t          *ops;
+       void                            *platinfo;
+       lws_dll2_t                      list;
+       uint8_t                         mac[LWS_ETH_ALEN];
+       uint8_t                         type; /* lws_netdev_type_t */
+} lws_netdev_instance_t;
+
+enum {
+       LNDIW_ALG_OPEN,
+       LNDIW_ALG_WPA2,
+
+       LNDIW_MODE_STA                  = (1 << 0),
+       LNDIW_MODE_AP                   = (1 << 1),
+       LNDIW_UP                        = (1 << 7),
+
+       LNDIW_ACQ_IPv4                  = (1 << 0),
+       LNDIW_ACQ_IPv6                  = (1 << 1),
+};
+
+/*
+ * Group AP / Station State
+ */
+
+typedef enum {
+       LWSNDVWIFI_STATE_INITIAL,
+               /*
+                * We should gratuitously try whatever last worked for us, then
+                * if that fails, worry about the rest of the logic
+                */
+       LWSNDVWIFI_STATE_SCAN,
+               /*
+                * Unconnected, scanning: AP known in one of the config slots ->
+                * configure it, start timeout + LWSNDVWIFI_STATE_STAT, if no AP
+                * already up in same group with lower MAC, after a random
+                * period start up our AP (LWSNDVWIFI_STATE_AP)
+                */
+       LWSNDVWIFI_STATE_AP,
+               /* Trying to be the group AP... periodically do a scan
+                * LWSNDVWIFI_STATE_AP_SCAN, faster and then slower
+                        */
+       LWSNDVWIFI_STATE_AP_SCAN,
+               /*
+                * doing a scan while trying to be the group AP... if we see a
+                * lower MAC being the AP for the same group AP, abandon being
+                * an AP and join that AP as a station
+                */
+       LWSNDVWIFI_STATE_STAT_GRP_AP,
+               /*
+                * We have decided to join another group member who is being the
+                * AP, as its MAC is lower than ours.  This is a stable state,
+                * but we still do periodic scans
+                * LWSNDVWIFI_STATE_STAT_GRP_AP_SCAN and will always prefer an
+                * AP configured in a slot.
+                */
+       LWSNDVWIFI_STATE_STAT_GRP_AP_SCAN,
+               /*
+                * We have joined a group member who is doing the AP job... we
+                * want to check every now and then if a configured AP has
+                * appeared that we should better use instead.  Otherwise stay
+                * in LWSNDVWIFI_STATE_STAT_GRP_AP
+                */
+       LWSNDVWIFI_STATE_STAT,
+               /*
+                * trying to connect to another non-group AP. If we don't get an
+                * IP within a timeout and retries, mark it as unusable it and go back
+                */
+       LWSNDVWIFI_STATE_STAT_HAPPY,
+} lws_netdev_wifi_state_t;
+
+/*
+ * Generic WIFI credentials
+ */
+
+typedef struct lws_wifi_creds {
+       lws_dll2_t                      list;
+
+       uint8_t                         bssid[LWS_ETH_ALEN];
+       char                            passphrase[64];
+       char                            ssid[33];
+       uint8_t                         alg;
+} lws_wifi_creds_t;
+
+/*
+ * Generic WIFI Network Device Instance
+ */
+
+typedef struct lws_netdev_instance_wifi {
+       lws_netdev_instance_t           inst;
+       lws_dll2_owner_t                scan; /* sorted scan results */
+       lws_sorted_usec_list_t          sul_scan;
+
+       lws_wifi_creds_t                *ap_cred;
+       const char                      *ap_ip;
+
+       const char                      *sta_ads;
+
+       char                            current_attempt_ssid[33];
+       uint8_t                         current_attempt_bssid[LWS_ETH_ALEN];
+
+       uint8_t                         flags;
+       uint8_t                         state; /* lws_netdev_wifi_state_t */
+} lws_netdev_instance_wifi_t;
+
+/*
+ * Logical scan results sorted list item
+ */
+
+typedef struct lws_wifi_sta {
+       lws_dll2_t                      list;
+
+       uint32_t                        last_seen; /* unix time */
+       uint32_t                        last_tried; /* unix time */
+
+       uint8_t                         bssid[LWS_ETH_ALEN];
+       char                            *ssid; /* points to overallocation */
+       uint8_t                         ssid_len;
+       lws_wifi_ch_t                   ch;
+       lws_wifi_rssi_t                 rssi[8];
+       int16_t                         rssi_avg;
+       uint8_t                         authmode;
+
+       uint8_t                         rssi_count;
+       uint8_t                         rssi_next;
+
+       /* ssid overallocated afterwards */
+} lws_wifi_sta_t;
+
+#define rssi_averaged(_x) (_x->rssi_count ? \
+               ((int)_x->rssi_avg / (int)_x->rssi_count) : \
+                       -200)
+
+LWS_VISIBLE LWS_EXTERN lws_netdevs_t *
+lws_netdevs_from_ctx(struct lws_context *ctx);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_netdev_credentials_settings_set(lws_netdevs_t *nds);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_netdev_credentials_settings_get(lws_netdevs_t *nds);
+
+LWS_VISIBLE LWS_EXTERN struct lws_netdev_instance *
+lws_netdev_wifi_create_plat(struct lws_context *ctx,
+                           const lws_netdev_ops_t *ops, const char *name,
+                           void *platinfo);
+LWS_VISIBLE LWS_EXTERN int
+lws_netdev_wifi_configure_plat(struct lws_netdev_instance *nd,
+                              lws_netdev_config_t *config);
+LWS_VISIBLE LWS_EXTERN int
+lws_netdev_wifi_event_plat(struct lws_netdev_instance *nd, lws_usec_t timestamp,
+                          void *buf, size_t len);
+LWS_VISIBLE LWS_EXTERN int
+lws_netdev_wifi_up_plat(struct lws_netdev_instance *nd);
+LWS_VISIBLE LWS_EXTERN int
+lws_netdev_wifi_down_plat(struct lws_netdev_instance *nd);
+LWS_VISIBLE LWS_EXTERN void
+lws_netdev_wifi_destroy_plat(struct lws_netdev_instance **pnd);
+LWS_VISIBLE LWS_EXTERN void
+lws_netdev_wifi_scan_plat(lws_netdev_instance_t *nd);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_netdev_wifi_connect_plat(lws_netdev_instance_t *wnd, const char *ssid,
+                            const char *passphrase, uint8_t *bssid);
+
+LWS_VISIBLE LWS_EXTERN lws_netdev_instance_t *
+lws_netdev_find(lws_netdevs_t *netdevs, const char *ifname);
+
+#define lws_netdev_wifi_plat_ops \
+       .create                         = lws_netdev_wifi_create_plat, \
+       .configure                      = lws_netdev_wifi_configure_plat, \
+       .event                          = lws_netdev_wifi_event_plat, \
+       .up                             = lws_netdev_wifi_up_plat, \
+       .down                           = lws_netdev_wifi_down_plat, \
+       .connect                        = lws_netdev_wifi_connect_plat, \
+       .scan                           = lws_netdev_wifi_scan_plat, \
+       .destroy                        = lws_netdev_wifi_destroy_plat
+
+/*
+ * This is for plat / OS level init that is necessary to be able to use
+ * networking or wifi at all, without mentioning any specific device
+ */
+
+LWS_VISIBLE LWS_EXTERN int
+lws_netdev_plat_init(void);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_netdev_plat_wifi_init(void);
index b3ad596..20a3225 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup net Network related helper APIs
  */
 ///@{
 
+#if defined(LWS_ESP_PLATFORM)
+#include <lwip/sockets.h>
+#endif
+
+typedef uint8_t lws_route_uidx_t;
+
+typedef struct lws_dns_score {
+       uint8_t precedence;
+       uint8_t label;
+} lws_dns_score_t;
+
+/*
+ * This represents an entry in the system routing table
+ */
+
+typedef struct lws_route {
+       lws_dll2_t              list;
+
+       lws_sockaddr46          src;
+       lws_sockaddr46          dest;
+       lws_sockaddr46          gateway;
+
+       struct lws_route        *source; /* when used as lws_dns_sort_t */
+       lws_dns_score_t         score; /* when used as lws_dns_sort_t */
+
+       int                     if_idx;
+       int                     priority;
+       int                     ifa_flags; /* if source_ads */
+
+       lws_route_uidx_t        uidx; /* unique index for this route */
+
+       uint8_t                 proto;
+       uint8_t                 dest_len;
+       uint8_t                 src_len;
+       uint8_t                 scope; /* if source_ads */
+       uint8_t                 af; /* if source_ads */
+
+       uint8_t                 source_ads:1;
+} lws_route_t;
+
+/*
+ * We reuse the route object as the dns sort granule, so there's only one
+ * struct needs to know all the gnarly ipv6 details
+ */
+
+typedef lws_route_t lws_dns_sort_t;
+
 /**
  * lws_canonical_hostname() - returns this host's hostname
  *
@@ -69,7 +117,10 @@ lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
  * peer that has connected to wsi
  */
 LWS_VISIBLE LWS_EXTERN const char *
-lws_get_peer_simple(struct lws *wsi, char *name, int namelen);
+lws_get_peer_simple(struct lws *wsi, char *name, size_t namelen);
+
+LWS_VISIBLE LWS_EXTERN const char *
+lws_get_peer_simple_fd(lws_sockfd_type fd, char *name, size_t namelen);
 
 #define LWS_ITOSA_USABLE       0
 #define LWS_ITOSA_NOT_EXIST    -1
@@ -77,7 +128,7 @@ lws_get_peer_simple(struct lws *wsi, char *name, int namelen);
 #define LWS_ITOSA_BUSY         -3 /* only returned by lws_socket_bind() on
                                        EADDRINUSE */
 
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
+#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
 /**
  * lws_interface_to_sa() - Convert interface name or IP to sockaddr struct
  *
@@ -102,4 +153,96 @@ LWS_VISIBLE LWS_EXTERN int
 lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
                    size_t addrlen);
 #endif
+
+/**
+ * lws_sa46_compare_ads() - checks if two sa46 have the same address
+ *
+ * \param sa46a: first
+ * \param sa46b: second
+ *
+ * Returns 0 if the address family is INET or INET6 and the address is the same,
+ * or if the AF is the same but not INET or INET6, otherwise nonzero.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b);
+
+/**
+ * lws_sa46_on_net() - checks if an sa46 is on the subnet represented by another
+ *
+ * \param sa46a: first
+ * \param sa46_net: network
+ * \param net_len: length of network non-mask
+ *
+ * Returns 0 if sa46a belongs on network sa46_net/net_len
+ *
+ * If there is an ipv4 / v6 mismatch between the ip and the net, the ipv4
+ * address is promoted to ::ffff:x.x.x.x before the comparison.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_sa46_on_net(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46_net,
+                       int net_len);
+
+/*
+ * lws_parse_numeric_address() - converts numeric ipv4 or ipv6 to byte address
+ *
+ * \param ads: the numeric ipv4 or ipv6 address string
+ * \param result: result array
+ * \param max_len: max length of result array
+ *
+ * Converts a 1.2.3.4 or 2001:abcd:123:: or ::ffff:1.2.3.4 formatted numeric
+ * address into an array of network ordered byte address elements.
+ *
+ * Returns < 0 on error, else length of result set, either 4 or 16 for ipv4 /
+ * ipv6.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_parse_numeric_address(const char *ads, uint8_t *result, size_t max_len);
+
+/*
+ * lws_sa46_parse_numeric_address() - converts numeric ipv4 or ipv6 to sa46
+ *
+ * \param ads: the numeric ipv4 or ipv6 address string
+ * \param sa46: pointer to sa46 to set
+ *
+ * Converts a 1.2.3.4 or 2001:abcd:123:: or ::ffff:1.2.3.4 formatted numeric
+ * address into an sa46, a union of sockaddr_in or sockaddr_in6 depending on
+ * what kind of address was found.  sa46->sa4.sin_fmaily will be AF_INET if
+ * ipv4, or AF_INET6 if ipv6.
+ *
+ * Returns 0 if the sa46 was set, else < 0 on error.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_sa46_parse_numeric_address(const char *ads, lws_sockaddr46 *sa46);
+
+/**
+ * lws_write_numeric_address() - convert network byte order ads to text
+ *
+ * \param ads: network byte order address array
+ * \param size: number of bytes valid in ads
+ * \param buf: result buffer to take text format
+ * \param len: max size of text buffer
+ *
+ * Converts an array of network-ordered byte address elements to a textual
+ * representation of the numeric address, like "1.2.3.4" or "::1".  Returns the
+ * number of chars written into buf, else < 0.  ipv6 only supported with
+ * LWS_IPV6=1 at cmake.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_write_numeric_address(const uint8_t *ads, int size, char *buf, size_t len);
+
+/**
+ * lws_sa46_write_numeric_address() - convert sa46 ads to textual numeric ads
+ *
+ * \param sa46: the sa46 whose address to show
+ * \param buf: result buffer to take text format
+ * \param len: max size of text buffer
+ *
+ * Converts the ipv4 or ipv6 address in an lws_sockaddr46 to a textual
+ * representation of the numeric address, like "1.2.3.4" or "::1".  Returns the
+ * number of chars written into buf, else < 0.  ipv6 only supported with
+ * LWS_IPV6=1 at cmake.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_sa46_write_numeric_address(lws_sockaddr46 *sa46, char *buf, size_t len);
+
 ///@}
index 9b73d30..1f58194 100644 (file)
@@ -1,25 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
- * SPDX-License-Identifier: LGPL-2.1-only
  *
- * Copyright (C) 2019 Akira Tsukamoto <akira.tsukamoto@gmail.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #ifndef __LWS_OPTEE_H
diff --git a/include/libwebsockets/lws-plugin-generic-sessions.h b/include/libwebsockets/lws-plugin-generic-sessions.h
deleted file mode 100644 (file)
index caf27b7..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
- */
-
-/*! \defgroup generic-sessions plugin: generic-sessions
- * \ingroup Protocols-and-Plugins
- *
- * ##Plugin Generic-sessions related
- *
- * generic-sessions plugin provides a reusable, generic session and login /
- * register / forgot password framework including email verification.
- */
-///@{
-
-#define LWSGS_EMAIL_CONTENT_SIZE 16384
-/**< Maximum size of email we might send */
-
-/* SHA-1 binary and hexified versions */
-/** typedef struct lwsgw_hash_bin */
-typedef struct { unsigned char bin[32]; /**< binary representation of hash */} lwsgw_hash_bin;
-/** typedef struct lwsgw_hash */
-typedef struct { char id[65]; /**< ascii hex representation of hash */ } lwsgw_hash;
-
-/** enum lwsgs_auth_bits */
-enum lwsgs_auth_bits {
-       LWSGS_AUTH_LOGGED_IN    = 1, /**< user is logged in as somebody */
-       LWSGS_AUTH_ADMIN        = 2, /**< logged in as the admin user */
-       LWSGS_AUTH_VERIFIED     = 4, /**< user has verified his email */
-       LWSGS_AUTH_FORGOT_FLOW  = 8, /**< just completed "forgot password" */
-};
-
-/** struct lws_session_info - information about user session status */
-struct lws_session_info {
-       char username[32]; /**< username logged in as, or empty string */
-       char email[100]; /**< email address associated with login, or empty string */
-       char ip[72]; /**< ip address session was started from */
-       unsigned int mask; /**< access rights mask associated with session
-                           * see enum lwsgs_auth_bits */
-       char session[42]; /**< session id string, usable as opaque uid when not logged in */
-};
-
-/** enum lws_gs_event */
-enum lws_gs_event {
-       LWSGSE_CREATED, /**< a new user was created */
-       LWSGSE_DELETED  /**< an existing user was deleted */
-};
-
-/** struct lws_gs_event_args */
-struct lws_gs_event_args {
-       enum lws_gs_event event; /**< which event happened */
-       const char *username; /**< which username the event happened to */
-       const char *email; /**< the email address of that user */
-};
-
-///@}
index b8d3b61..66240c9 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup Protocols-and-Plugins Protocols and Plugins
@@ -67,7 +68,7 @@ struct lws_protocols {
         * to the selected protocol.  For example if this protocol was
         * called "myprotocol-v2", you might set id to 2, and the user
         * code that acts differently according to the version can do so by
-        * switch (wsi->protocol->id), user code might use some bits as
+        * switch (wsi->a.protocol->id), user code might use some bits as
         * capability flags based on selected protocol version, etc. */
        void *user; /**< ignored by lws, but user code can pass a pointer
                        here it can later access from the protocol callback */
@@ -85,6 +86,8 @@ struct lws_protocols {
         * This is part of the ABI, don't needlessly break compatibility */
 };
 
+#define LWS_PROTOCOL_LIST_TERM { NULL, NULL, 0, 0, 0, NULL, 0 }
+
 /**
  * lws_vhost_name_to_protocol() - get vhost's protocol object from its name
  *
@@ -140,6 +143,41 @@ lws_protocol_vh_priv_get(struct lws_vhost *vhost,
                         const struct lws_protocols *prot);
 
 /**
+ * lws_vhd_find_by_pvo() - find a partner vhd
+ *
+ *  \param cx: the lws_context
+ *  \param protname: the name of the lws_protocol the vhd belongs to
+ *  \param pvo_name: the name of a pvo that must exist bound to the vhd
+ *  \param pvo_value: the required value of the named pvo
+ *
+ * This allows architectures with multiple protocols bound together to
+ * cleanly discover partner protocol instances even on completely
+ * different vhosts.  For example, a proxy may consist of two protocols
+ * listening on different vhosts, and there may be multiple instances
+ * of the proxy in the same process.  It's desirable that each side of
+ * the proxy is an independent protocol that can be freely bound to any
+ * vhost, eg, allowing Unix Domain to tls / h2 proxying, or each side
+ * bound to different network interfaces for localhost-only visibility
+ * on one side, using existing vhost management.
+ *
+ * That leaves the problem that the two sides have to find each other
+ * and bind at runtime.  This api allows each side to specify the
+ * protocol name, and a common pvo name and pvo value that indicates
+ * the two sides belong together, and search through all the instantiated
+ * vhost-protocols looking for a match.  If found, the private allocation
+ * (aka "vhd" of the match is returned).  NULL is returned on no match.
+ *
+ * Since this can only succeed when called by the last of the two
+ * protocols to be instantiated, both sides should call it and handle
+ * NULL gracefully, since it may mean that they were first and their
+ * partner vhsot-protocol has not been instantiated yet.
+ */
+LWS_VISIBLE LWS_EXTERN void *
+lws_vhd_find_by_pvo(struct lws_context *cx, const char *protname,
+                   const char *pvo_name, const char *pvo_value);
+
+
+/**
  * lws_adjust_protocol_psds - change a vhost protocol's per session data size
  *
  * \param wsi: a connection with the protocol to change
@@ -193,36 +231,153 @@ lws_pvo_get_str(void *in, const char *name, const char **result);
 LWS_VISIBLE LWS_EXTERN int
 lws_protocol_init(struct lws_context *context);
 
-#ifdef LWS_WITH_PLUGINS
+#define LWS_PLUGIN_API_MAGIC 191
+
+/*
+ * Abstract plugin header for any kind of plugin class, always at top of
+ * actual class plugin export type.
+ *
+ * The export type object must be exported with the same name as the plugin
+ * file, eg, libmyplugin.so must export a const one of these as the symbol
+ * "myplugin".
+ *
+ * That is the only expected export from the plugin.
+ */
+
+typedef struct lws_plugin_header {
+       const char *name;
+       const char *_class;
+       const char *lws_build_hash; /* set to LWS_BUILD_HASH */
 
-/* PLUGINS implies LIBUV */
+       unsigned int api_magic;
+       /* set to LWS_PLUGIN_API_MAGIC at plugin build time */
 
-#define LWS_PLUGIN_API_MAGIC 180
+       /* plugin-class specific superclass data follows */
+} lws_plugin_header_t;
+
+/*
+ * "lws_protocol_plugin" class export, for lws_protocol implementations done
+ * as plugins
+ */
+typedef struct lws_plugin_protocol {
+       lws_plugin_header_t hdr;
 
-/** struct lws_plugin_capability - how a plugin introduces itself to lws */
-struct lws_plugin_capability {
-       unsigned int api_magic; /**< caller fills this in, plugin fills rest */
        const struct lws_protocols *protocols; /**< array of supported protocols provided by plugin */
-       int count_protocols; /**< how many protocols */
        const struct lws_extension *extensions; /**< array of extensions provided by plugin */
+       int count_protocols; /**< how many protocols */
        int count_extensions; /**< how many extensions */
-};
+} lws_plugin_protocol_t;
 
-typedef int (*lws_plugin_init_func)(struct lws_context *,
-                                   struct lws_plugin_capability *);
-typedef int (*lws_plugin_destroy_func)(struct lws_context *);
 
-/** struct lws_plugin */
+/*
+ * This is the dynamic, runtime created part of the plugin instantiation.
+ * These are kept in a linked-list and destroyed with the context.
+ */
+
 struct lws_plugin {
        struct lws_plugin *list; /**< linked list */
+
+       const lws_plugin_header_t *hdr;
+
+       union {
+#if defined(LWS_WITH_LIBUV) && defined(UV_ERRNO_MAP)
 #if (UV_VERSION_MAJOR > 0)
-       uv_lib_t lib; /**< shared library pointer */
+               uv_lib_t lib; /**< shared library pointer */
+#endif
 #endif
-       void *l; /**< so we can compile on ancient libuv */
-       char name[64]; /**< name of the plugin */
-       struct lws_plugin_capability caps; /**< plugin capabilities */
+               void *l; /**<  */
+       } u;
 };
 
+/*
+ * Event lib library plugin type (when LWS_WITH_EVLIB_PLUGINS)
+ * Public so new event libs can equally be supported outside lws itself
+ */
+
+typedef struct lws_plugin_evlib {
+       lws_plugin_header_t hdr;
+       const struct lws_event_loop_ops *ops;
+} lws_plugin_evlib_t;
+
+typedef int (*each_plugin_cb_t)(struct lws_plugin *p, void *user);
+
+/**
+ * lws_plugins_init() - dynamically load plugins of matching class from dirs
+ *
+ * \param pplugin:     pointer to linked-list for this kind of plugin
+ * \param d: array of directory paths to look in
+ * \param _class: class string that plugin must declare
+ * \param filter: NULL, or a string that must appear after the third char of the plugin filename
+ * \param each: NULL, or each_plugin_cb_t callback for each instantiated plugin
+ * \param each_user: pointer passed to each callback
+ *
+ * Allows you to instantiate a class of plugins to a specified linked-list.
+ * The each callback allows you to init each inistantiated callback and pass a
+ * pointer each_user to it.
+ *
+ * To take down the plugins, pass a pointer to the linked-list head to
+ * lws_plugins_destroy.
+ *
+ * This is used for lws protocol plugins but you can define your own plugin
+ * class name like "mypluginclass", declare it in your plugin headers, and load
+ * your own plugins to your own list using this api the same way.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_plugins_init(struct lws_plugin **pplugin, const char * const *d,
+                const char *_class, const char *filter,
+                each_plugin_cb_t each, void *each_user);
+
+/**
+ * lws_plugins_destroy() - dynamically unload list of plugins
+ *
+ * \param pplugin:     pointer to linked-list for this kind of plugin
+ * \param each: NULL, or each_plugin_cb_t callback for each instantiated plugin
+ * \param each_user: pointer passed to each callback
+ *
+ * Allows you to destroy a class of plugins from a specified linked-list
+ * created by a call to lws_plugins_init().
+ *
+ * The each callback allows you to deinit each inistantiated callback and pass a
+ * pointer each_user to it, just before its footprint is destroyed.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_plugins_destroy(struct lws_plugin **pplugin, each_plugin_cb_t each,
+                   void *each_user);
+
+#if defined(LWS_WITH_PLUGINS_BUILTIN)
+
+/* provide exports for builtin plugin protocols */
+
+extern const struct lws_protocols post_demo_protocols[1];
+extern const struct lws_protocols lws_raw_proxy_protocols[1];
+extern const struct lws_protocols lws_status_protocols[1];
+extern const struct lws_protocols lws_mirror_protocols[1];
+extern const struct lws_protocols lws_ssh_base_protocols[2];
+extern const struct lws_protocols post_demo_protocols[1];
+extern const struct lws_protocols dumb_increment_protocols[1];
+extern const struct lws_protocols deaddrop_protocols[1];
+extern const struct lws_protocols lws_raw_test_protocols[1];
+extern const struct lws_protocols lws_sshd_demo_protocols[1];
+extern const struct lws_protocols lws_acme_client_protocols[1];
+extern const struct lws_protocols client_loopback_test_protocols[1];
+extern const struct lws_protocols fulltext_demo_protocols[1];
+extern const struct lws_protocols lws_openmetrics_export_protocols[
+#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_CLIENT) && defined(LWS_ROLE_WS)
+       4
+#else
+#if defined(LWS_WITH_SERVER)
+       3
+#else
+       1
+#endif
+#endif
+       ];
+
+#define LWSOMPROIDX_DIRECT_HTTP_SERVER         0
+#define LWSOMPROIDX_PROX_HTTP_SERVER           1
+#define LWSOMPROIDX_PROX_WS_SERVER             2
+#define LWSOMPROIDX_PROX_WS_CLIENT             3
+
 #endif
 
 ///@}
index 0ae35ce..68acc60 100644 (file)
@@ -1,27 +1,27 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-
 /*! \defgroup pur Sanitize / purify SQL and JSON helpers
  *
  * ##Sanitize / purify SQL and JSON helpers
  * possible to do it in-place, ie, with escaped == string
  */
 LWS_VISIBLE LWS_EXTERN const char *
-lws_sql_purify(char *escaped, const char *string, int len);
+lws_sql_purify(char *escaped, const char *string, size_t len);
+
+/**
+ * lws_sql_purify_len() - return length of purified version of input string
+ *
+ * \param string: input buffer ('/0' terminated)
+ *
+ * Calculates any character escaping without writing it anywhere and returns the
+ * calculated length of the purified string.
+ */
+int
+lws_sql_purify_len(const char *p);
 
 /**
  * lws_json_purify() - like strncpy but with escaping for json chars
@@ -49,12 +60,25 @@ lws_sql_purify(char *escaped, const char *string, int len);
  * \param escaped: output buffer
  * \param string: input buffer ('/0' terminated)
  * \param len: output buffer max length
+ * \param in_used: number of bytes of string we could escape in len
  *
  * Because escaping expands the output string, it's not
  * possible to do it in-place, ie, with escaped == string
  */
 LWS_VISIBLE LWS_EXTERN const char *
-lws_json_purify(char *escaped, const char *string, int len);
+lws_json_purify(char *escaped, const char *string, int len, int *in_used);
+
+/**
+ * lws_json_purify_len() - find out the escaped length of a string
+ *
+ * \param string: input buffer ('/0' terminated)
+ *
+ * JSON may have to expand escapes by up to 6x the original depending on what
+ * it is.  This doesn't actually do the escaping but goes through the motions
+ * and computes the length of the escaped string.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_json_purify_len(const char *string);
 
 /**
  * lws_filename_purify_inplace() - replace scary filename chars with underscore
@@ -69,12 +93,12 @@ lws_filename_purify_inplace(char *filename);
 
 LWS_VISIBLE LWS_EXTERN int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
-                       int len);
+                       size_t len);
 LWS_VISIBLE LWS_EXTERN int
-lws_plat_write_file(const char *filename, void *buf, int len);
+lws_plat_write_file(const char *filename, void *buf, size_t len);
 
 LWS_VISIBLE LWS_EXTERN int
-lws_plat_read_file(const char *filename, void *buf, int len);
+lws_plat_read_file(const char *filename, void *buf, size_t len);
 
 LWS_VISIBLE LWS_EXTERN int
 lws_plat_recommended_rsa_bits(void);
diff --git a/include/libwebsockets/lws-pwm.h b/include/libwebsockets/lws-pwm.h
new file mode 100644 (file)
index 0000000..b57635f
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Generic PWM controller ops
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+typedef struct lws_pwm_map {
+       _lws_plat_gpio_t                gpio;
+       uint8_t                         index;
+       uint8_t                         active_level;
+} lws_pwm_map_t;
+
+typedef struct lws_pwm_ops {
+       int (*init)(const struct lws_pwm_ops *lo);
+       void (*intensity)(const struct lws_pwm_ops *lo, _lws_plat_gpio_t gpio,
+                         lws_led_intensity_t inten);
+       const lws_pwm_map_t             *pwm_map;
+       uint8_t                         count_pwm_map;
+} lws_pwm_ops_t;
+
+LWS_VISIBLE LWS_EXTERN int
+lws_pwm_plat_init(const struct lws_pwm_ops *lo);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_pwm_plat_intensity(const struct lws_pwm_ops *lo, _lws_plat_gpio_t gpio,
+                      lws_led_intensity_t inten);
+
+#define lws_pwm_plat_ops \
+               .init                   = lws_pwm_plat_init, \
+               .intensity              = lws_pwm_plat_intensity
+
+/*
+ * May be useful for making your own transitions or sequences
+ */
+
+LWS_VISIBLE LWS_EXTERN lws_led_intensity_t
+lws_led_func_linear(lws_led_seq_phase_t n);
+LWS_VISIBLE LWS_EXTERN lws_led_intensity_t
+lws_led_func_sine(lws_led_seq_phase_t n);
+
+/* canned sequences that can work out of the box */
+
+extern const lws_led_sequence_def_t lws_pwmseq_sine_endless_slow,
+                                   lws_pwmseq_sine_endless_fast,
+                                   lws_pwmseq_linear_wipe,
+                                   lws_pwmseq_sine_up, lws_pwmseq_sine_down,
+                                   lws_pwmseq_static_on,
+                                   lws_pwmseq_static_half,
+                                   lws_pwmseq_static_off;
index fe058c5..386ccdc 100644 (file)
@@ -1,48 +1,43 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
- */ 
-
-/*
- * Specifies backoff ranges using a pair of uint32_t in ms for the min, max.
- *
- * The actual backoff timing is picked randomly within the range.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-typedef struct lws_retry_range {
-       uint32_t                min_ms;
-       uint32_t                max_ms;
-} lws_retry_range_t;
-
 typedef struct lws_retry_bo {
-       const lws_retry_range_t *retry_ms_table;        /* backoff range pair */
-       uint16_t                retry_ms_table_count;      /* ranges in table */
-       uint16_t                conceal_count;      /* max retries to conceal */
+       const uint32_t  *retry_ms_table;           /* base delay in ms */
+       uint16_t        retry_ms_table_count;      /* entries in table */
+       uint16_t        conceal_count;             /* max retries to conceal */
+       uint16_t        secs_since_valid_ping;     /* idle before PING issued */
+       uint16_t        secs_since_valid_hangup;   /* idle before hangup conn */
+       uint8_t         jitter_percent;         /* % additional random jitter */
 } lws_retry_bo_t;
 
+#define LWS_RETRY_CONCEAL_ALWAYS (0xffff)
+
 /**
  * lws_retry_get_delay_ms() - get next delay from backoff table
  *
  * \param lws_context: the lws context (used for getting random)
- * \param retry: the retry backoff table we are using
+ * \param retry: the retry backoff table we are using, or NULL for default
  * \param ctry: pointer to the try counter
  * \param conceal: pointer to flag set to nonzero if the try should be concealed
  *                     in terms of creating an error
@@ -52,9 +47,49 @@ typedef struct lws_retry_bo {
  * set if the number of tries is less than the backoff table conceal_count, or
  * is zero if it exceeded it.  This lets you conceal a certain number of retries
  * before alerting the caller there is a problem.
+ *
+ * If \p retry is NULL, a default of 3s + (0..300ms jitter) is used.  If it's
+ * non-NULL but jitter_percent is 0, the default of 30% jitter is retained.
  */
 
 LWS_VISIBLE LWS_EXTERN unsigned int
 lws_retry_get_delay_ms(struct lws_context *context, const lws_retry_bo_t *retry,
-                       uint16_t *ctry, char *conceal);
+                      uint16_t *ctry, char *conceal);
+
+/**
+ * lws_retry_sul_schedule() - schedule a sul according to the backoff table
+ *
+ * \param lws_context: the lws context (used for getting random)
+ * \param sul: pointer to the sul to schedule
+ * \param retry: the retry backoff table we are using, or NULL for default
+ * \param cb: the callback for when the sul schedule time arrives
+ * \param ctry: pointer to the try counter
+ *
+ * Helper that combines interpreting the retry table with scheduling a sul to
+ * the computed delay.  If conceal is not set, it will not schedule the sul
+ * and just return 1.  Otherwise the sul is scheduled and it returns 0.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_retry_sul_schedule(struct lws_context *context, int tid,
+                      lws_sorted_usec_list_t *sul, const lws_retry_bo_t *retry,
+                      sul_cb_t cb, uint16_t *ctry);
 
+/**
+ * lws_retry_sul_schedule_retry_wsi() - retry sul schedule helper using wsi
+ *
+ * \param wsi: the wsi to set the hrtimer sul on to the next retry interval
+ * \param sul: pointer to the sul to schedule
+ * \param cb: the callback for when the sul schedule time arrives
+ * \param ctry: pointer to the try counter
+ *
+ * Helper that uses context, tid and retry policy from a wsi to call
+ * lws_retry_sul_schedule.
+ *
+ * Since a udp connection can have many writes in flight, the retry count and
+ * the sul used to track each thing that wants to be written have to be handled
+ * individually, not the wsi.  But the retry policy and the other things can
+ * be filled in from the wsi conveniently.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_retry_sul_schedule_retry_wsi(struct lws *wsi, lws_sorted_usec_list_t *sul,
+                                sul_cb_t cb, uint16_t *ctry);
index ee43d30..e642f0f 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup lws_ring LWS Ringbuffer APIs
@@ -276,7 +277,7 @@ lws_ring_dump(struct lws_ring *ring, uint32_t *tail);
                ___n = 0; \
                ___oldest = *(___ptail); \
                lws_start_foreach_llp(___type **, ___ppss, ___list_head) { \
-                       ___m = lws_ring_get_count_waiting_elements( \
+                       ___m = (int)lws_ring_get_count_waiting_elements( \
                                        ___ring, &(*___ppss)->___mtail); \
                        if (___m >= ___n) { \
                                ___n = ___m; \
diff --git a/include/libwebsockets/lws-secure-streams-client.h b/include/libwebsockets/lws-secure-streams-client.h
new file mode 100644 (file)
index 0000000..4d24cba
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is the headers for secure stream api variants that deal with clients in
+ * different threads or even different processes.
+ *
+ * lws_ss_          when client is directly using the event loop
+ * lws_sstc_        when client is in a different thread to the event loop
+ * lws_sspc_        when client is in a different process to the event loop
+ *
+ * The client api is almost the same except the slightly diffent names.
+ */
+
+/*
+ * lws_sspc_ apis... different process
+ */
+
+/*
+ * Helper translation so user code written to lws_ss_ can be built for
+ * lws_sspc_ in one step by #define LWS_SS_USE_SSPC before including
+ */
+
+struct lws_sspc_handle;
+
+#if defined(LWS_SS_USE_SSPC)
+#define lws_ss_handle                  lws_sspc_handle
+#define lws_ss_create                  lws_sspc_create
+#define lws_ss_destroy                 lws_sspc_destroy
+#define lws_ss_request_tx              lws_sspc_request_tx
+#define lws_ss_request_tx_len          lws_sspc_request_tx_len
+#define lws_ss_client_connect          lws_sspc_client_connect
+#define lws_ss_get_sequencer           lws_sspc_get_sequencer
+#define lws_ss_proxy_create            lws_sspc_proxy_create
+#define lws_ss_get_context             lws_sspc_get_context
+#define lws_ss_rideshare               lws_sspc_rideshare
+#define lws_ss_set_metadata            lws_sspc_set_metadata
+#define lws_ss_get_metadata            lws_sspc_get_metadata
+#define lws_ss_add_peer_tx_credit      lws_sspc_add_peer_tx_credit
+#define lws_ss_get_est_peer_tx_credit  lws_sspc_get_est_peer_tx_credit
+#define lws_ss_start_timeout           lws_sspc_start_timeout
+#define lws_ss_cancel_timeout          lws_sspc_cancel_timeout
+#define lws_ss_to_user_object          lws_sspc_to_user_object
+#define lws_ss_change_handlers         lws_sspc_change_handlers
+#define lws_smd_ss_rx_forward          lws_smd_sspc_rx_forward
+#define lws_ss_tag                     lws_sspc_tag
+#define _lws_fi_user_ss_fi             _lws_fi_user_sspc_fi
+#define lwsl_ss_get_cx                 lwsl_sspc_get_cx
+
+LWS_VISIBLE LWS_EXTERN void
+lws_log_prepend_sspc(struct lws_log_cx *cx, void *obj, char **p, char *e);
+
+LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
+lwsl_sspc_get_cx(struct lws_sspc_handle *ss);
+
+#undef lwsl_ss
+#define lwsl_ss lwsl_sspc
+
+#undef lwsl_hexdump_ss
+#define lwsl_hexdump_ss lwsl_hexdump_sspc
+#endif
+
+#define lwsl_sspc(_h, _fil, ...) \
+                _lws_log_cx(lwsl_sspc_get_cx(_h), lws_log_prepend_sspc, _h, \
+                                       _fil, __func__, __VA_ARGS__)
+
+#define lwsl_hexdump_sspc(_h, _fil, _buf, _len) \
+               lwsl_hexdump_level_cx(lwsl_sspc_get_cx(_h), \
+                                     lws_log_prepend_sspc, \
+                                     _h, _fil, _buf, _len)
+
+/*
+ * lwsl_sspc
+ */
+
+#if (_LWS_ENABLED_LOGS & LLL_ERR)
+#define lwsl_sspc_err(_w, ...) lwsl_sspc(_w, LLL_ERR, __VA_ARGS__)
+#else
+#define lwsl_sspc_err(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_WARN)
+#define lwsl_sspc_warn(_w, ...) lwsl_sspc(_w, LLL_WARN, __VA_ARGS__)
+#else
+#define lwsl_sspc_warn(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
+#define lwsl_sspc_notice(_w, ...) lwsl_sspc(_w, LLL_NOTICE, __VA_ARGS__)
+#else
+#define lwsl_sspc_notice(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+#define lwsl_sspc_info(_w, ...) lwsl_sspc(_w, LLL_INFO, __VA_ARGS__)
+#else
+#define lwsl_sspc_info(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
+#define lwsl_sspc_debug(_w, ...) lwsl_sspc(_w, LLL_DEBUG, __VA_ARGS__)
+#else
+#define lwsl_sspc_debug(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_PARSER)
+#define lwsl_sspc_parser(_w, ...) lwsl_sspc(_w, LLL_PARSER, __VA_ARGS__)
+#else
+#define lwsl_sspc_parser(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_HEADER)
+#define lwsl_sspc_header(_w, ...) lwsl_sspc(_w, LLL_HEADER, __VA_ARGS__)
+#else
+#define lwsl_sspc_header(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_EXT)
+#define lwsl_sspc_ext(_w, ...) lwsl_sspc(_w, LLL_EXT, __VA_ARGS__)
+#else
+#define lwsl_sspc_ext(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
+#define lwsl_sspc_client(_w, ...) lwsl_sspc(_w, LLL_CLIENT, __VA_ARGS__)
+#else
+#define lwsl_sspc_client(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
+#define lwsl_sspc_latency(_w, ...) lwsl_sspc(_w, LLL_LATENCY, __VA_ARGS__)
+#else
+#define lwsl_sspc_latency(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_THREAD)
+#define lwsl_sspc_thread(_w, ...) lwsl_sspc(_w, LLL_THREAD, __VA_ARGS__)
+#else
+#define lwsl_sspc_thread(_w, ...) do {} while(0)
+#endif
+
+#if (_LWS_ENABLED_LOGS & LLL_USER)
+#define lwsl_sspc_user(_w, ...) lwsl_sspc(_w, LLL_USER, __VA_ARGS__)
+#else
+#define lwsl_sspc_user(_w, ...) do {} while(0)
+#endif
+
+#define lwsl_hexdump_sspc_err(_v, ...)    lwsl_hexdump_sspc(_v, LLL_ERR, __VA_ARGS__)
+#define lwsl_hexdump_sspc_warn(_v, ...)   lwsl_hexdump_sspc(_v, LLL_WARN, __VA_ARGS__)
+#define lwsl_hexdump_sspc_notice(_v, ...) lwsl_hexdump_sspc(_v, LLL_NOTICE, __VA_ARGS__)
+#define lwsl_hexdump_sspc_info(_v, ...)   lwsl_hexdump_sspc(_v, LLL_INFO, __VA_ARGS__)
+#define lwsl_hexdump_sspc_debug(_v, ...)  lwsl_hexdump_sspc(_v, LLL_DEBUG, __VA_ARGS__)
+
+
+LWS_VISIBLE LWS_EXTERN int
+lws_sspc_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
+               void *opaque_user_data, struct lws_sspc_handle **ppss,
+               struct lws_sequencer *seq_owner, const char **ppayload_fmt);
+
+/**
+ * lws_sspc_destroy() - Destroy secure stream
+ *
+ * \param ppss: pointer to lws_ss_t pointer to be destroyed
+ *
+ * Destroys the lws_ss_t pointed to by *ppss, and sets *ppss to NULL.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_sspc_destroy(struct lws_sspc_handle **ppss);
+
+/**
+ * lws_sspc_request_tx() - Schedule stream for tx
+ *
+ * \param pss: pointer to lws_ss_t representing stream that wants to transmit
+ *
+ * Schedules a write on the stream represented by \p pss.  When it's possible to
+ * write on this stream, the *tx callback will occur with an empty buffer for
+ * the stream owner to fill in.
+ */
+LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t
+lws_sspc_request_tx(struct lws_sspc_handle *pss);
+
+/**
+ * lws_sspc_request_tx_len() - Schedule stream for tx with length hint
+ *
+ * \param h: pointer to handle representing stream that wants to transmit
+ * \param len: the length of the write in bytes
+ *
+ * Schedules a write on the stream represented by \p pss.  When it's possible to
+ * write on this stream, the *tx callback will occur with an empty buffer for
+ * the stream owner to fill in.
+ *
+ * This api variant should be used when it's possible the payload will go out
+ * over h1 with x-web-form-urlencoded or similar Content-Type.
+ *
+ * The serialized, sspc type api actually serializes and forwards the length
+ * hint to its upstream proxy, where it's available for use to produce the
+ * internet-capable protocol framing.
+ */
+LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t
+lws_sspc_request_tx_len(struct lws_sspc_handle *h, unsigned long len);
+
+/**
+ * lws_sspc_client_connect() - Attempt the client connect
+ *
+ * \param h: secure streams handle
+ *
+ * Starts the connection process for the secure stream.  Returns 0.
+ */
+LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t
+lws_sspc_client_connect(struct lws_sspc_handle *h);
+
+/**
+ * lws_sspc_get_sequencer() - Return parent sequencer pointer if any
+ *
+ * \param h: secure streams handle
+ *
+ * Returns NULL if the secure stream is not associated with a sequencer.
+ * Otherwise returns a pointer to the owning sequencer.  You can use this to
+ * identify which sequencer to direct messages to, from the secure stream
+ * callback.
+ */
+LWS_VISIBLE LWS_EXTERN struct lws_sequencer *
+lws_sspc_get_sequencer(struct lws_sspc_handle *h);
+
+/**
+ * lws_sspc_proxy_create() - Start a unix domain socket proxy for Secure Streams
+ *
+ * \param context: lws_context
+ *
+ * Creates a vhost that listens on an abstract namespace unix domain socket at
+ * address "proxy.ss.lws".  Client connections to this proxy to Secure Streams
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_sspc_proxy_create(struct lws_context *context);
+
+/**
+ * lws_ss_get_context() - convenience helper to recover the lws context
+ *
+ * \h: secure streams handle
+ *
+ * Returns the lws context.  Dispenses with the need to pass a copy of it into
+ * your secure streams handler.
+ */
+
+LWS_VISIBLE LWS_EXTERN struct lws_context *
+lws_sspc_get_context(struct lws_sspc_handle *h);
+
+LWS_VISIBLE extern const struct lws_protocols lws_sspc_protocols[2];
+
+LWS_VISIBLE LWS_EXTERN const char *
+lws_sspc_rideshare(struct lws_sspc_handle *h);
+
+
+/**
+ * lws_sspc_set_metadata() - allow user to bind external data to defined ss metadata
+ *
+ * \h: secure streams handle
+ * \name: metadata name from the policy
+ * \value: pointer to user-managed data to bind to name
+ * \len: length of the user-managed data in value
+ *
+ * Binds user-managed data to the named metadata item from the ss policy.
+ * If present, the metadata item is handled in a protocol-specific way using
+ * the associated policy information.  For example, in the policy
+ *
+ *     "\"metadata\":"         "["
+ *             "{\"uptag\":"  "\"X-Upload-Tag:\"},"
+ *             "{\"ctype\":"  "\"Content-Type:\"},"
+ *             "{\"xctype\":" "\"X-Content-Type:\"}"
+ *     "],"
+ *
+ * when the policy is using h1 is interpreted to add h1 headers of the given
+ * name with the value of the metadata on the left.
+ *
+ * Return 0 if OK, or nonzero if failed.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_sspc_set_metadata(struct lws_sspc_handle *h, const char *name,
+                     const void *value, size_t len);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_sspc_get_metadata(struct lws_sspc_handle *h, const char *name,
+                     const void **value, size_t *len);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_sspc_add_peer_tx_credit(struct lws_sspc_handle *h, int32_t add);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_sspc_get_est_peer_tx_credit(struct lws_sspc_handle *h);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_sspc_start_timeout(struct lws_sspc_handle *h, unsigned int timeout_ms);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_sspc_cancel_timeout(struct lws_sspc_handle *h);
+
+LWS_VISIBLE LWS_EXTERN void *
+lws_sspc_to_user_object(struct lws_sspc_handle *h);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_sspc_change_handlers(struct lws_sspc_handle *h,
+       lws_ss_state_return_t (*rx)(void *userobj, const uint8_t *buf,
+                                   size_t len, int flags),
+       lws_ss_state_return_t (*tx)(void *userobj, lws_ss_tx_ordinal_t ord,
+                                   uint8_t *buf, size_t *len, int *flags),
+       lws_ss_state_return_t (*state)(void *userobj, void *h_src
+                                       /* ss handle type */,
+                                      lws_ss_constate_t state,
+                                      lws_ss_tx_ordinal_t ack));
+
+const char *
+lws_sspc_tag(struct lws_sspc_handle *h);
diff --git a/include/libwebsockets/lws-secure-streams-policy.h b/include/libwebsockets/lws-secure-streams-policy.h
new file mode 100644 (file)
index 0000000..863140d
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * included from libwebsockets.h
+ */
+
+typedef int (*plugin_auth_status_cb)(struct lws_ss_handle *ss, int status);
+
+/**
+ * lws_ss_plugin_auth_t - api for an auth plugin
+ *
+ * Auth plugins create and sequence authenticated connections that can carry one
+ * or more streams to an endpoint.  That may involve other connections to other
+ * places to eg, gather authenticated tokens and then make the real connection
+ * using the tokens.
+ *
+ * The secure stream object contains members to record which auth plugin the
+ * stream is bound to and an over-allocation of the secure stream object to
+ * contain the plugin auth private data.
+ *
+ * The auth plugin controls the state of the stream connection via the status
+ * callback, and handles retries.
+ *
+ * Network connections may require one kind of auth sequencing, and streams
+ * inside those connections another kind of auth sequencing depending on their
+ * role.  So the secure stream object allows defining plugins for both kinds.
+ *
+ * Streams may disappear at any time and require reauth to bring a new one up.
+ * The auth plugin sequencer will connect / reconnect either on demand, or from
+ * the start and after any connectivity loss if any stream using the connection
+ * has the LWSSSPOLF_NAILED_UP flag.
+ */
+
+#if defined(LWS_WITH_SSPLUGINS)
+typedef struct lws_ss_plugin {
+       struct lws_ss_plugin    *next;
+       const char              *name;  /**< auth plugin name */
+       size_t                  alloc;  /**< size of private allocation */
+
+       int                     (*create)(struct lws_ss_handle *ss, void *info,
+                                         plugin_auth_status_cb status);
+                               /**< called when the auth plugin is instantiated
+                                    and bound to the secure stream.  status is
+                                    called back with advisory information about
+                                    the authenticated stream state as it
+                                    proceeds */
+       int                     (*destroy)(struct lws_ss_handle *ss);
+                               /**< called when the related secure stream is
+                                    being destroyed, and anything the auth
+                                    plugin is doing should also be destroyed */
+       int                     (*munge)(struct lws_ss_handle *ss, char *path,
+                                        size_t path_len);
+                               /**< if the plugin needs to munge transactions
+                                    that have metadata outside the payload (eg,
+                                    add http headers) this callback will give
+                                    it the opportunity to do so */
+} lws_ss_plugin_t;
+#endif
+
+/* the public, const metrics policy definition */
+
+typedef struct lws_metric_policy {
+       /* order of first two mandated by JSON policy parsing scope union */
+       const struct lws_metric_policy  *next;
+       const char                      *name;
+
+       const char                      *report;
+
+       /**< the metrics policy name in the policy, used to bind to it */
+       uint64_t                        us_schedule;
+       /**< us interval between lws_system metrics api reports */
+
+       uint32_t                        us_decay_unit;
+       /**< how many us to decay avg by half, 0 = no decay */
+       uint8_t                         min_contributors;
+       /**< before we can judge something is an outlier */
+} lws_metric_policy_t;
+
+typedef struct lws_ss_x509 {
+       struct lws_ss_x509      *next;
+       const char              *vhost_name; /**< vhost name using cert ctx */
+       const uint8_t           *ca_der;        /**< DER x.509 cert */
+       size_t                  ca_der_len;     /**< length of DER cert */
+       uint8_t                 keep:1; /**< ie, if used in server tls */
+} lws_ss_x509_t;
+
+enum {
+       LWSSSPOLF_OPPORTUNISTIC                                 = (1 << 0),
+       /**< the connection doesn't exist unless client asks to write */
+       LWSSSPOLF_NAILED_UP                                     = (1 << 1),
+       /**< the connection tries to be connected the whole life of the ss */
+       LWSSSPOLF_URGENT_TX                                     = (1 << 2),
+       /**< this connection carries critical tx data */
+       LWSSSPOLF_URGENT_RX                                     = (1 << 3),
+       /**< this connection carries critical rx data */
+       LWSSSPOLF_TLS                                           = (1 << 4),
+       /**< stream must be connected via a tls tunnel */
+       LWSSSPOLF_LONG_POLL                                     = (1 << 5),
+       /**< stream used to receive async rx at arbitrary intervals */
+       LWSSSPOLF_AUTH_BEARER                                   = (1 << 6),
+       /**< for http, use lws_system auth token 0 in authentication: bearer */
+       LWSSSPOLF_HTTP_NO_CONTENT_LENGTH                        = (1 << 7),
+       /**< don't add any content length even if we have it */
+       LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM                      = (1 << 8),
+       /**< set the client flag LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM */
+       LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR                       = (1 << 9),
+       /**< set the client flag LCCSCF_H2_QUIRK_OVERFLOWS_TXCR */
+       LWSSSPOLF_H2_QUIRK_UNCLEAN_HPACK_STATE                  = (1 << 10),
+       /**< HPACK decoder state does not end cleanly */
+       LWSSSPOLF_HTTP_MULTIPART                                = (1 << 11),
+       /**< indicates stream goes out as specifically a multipart mime POST
+        * section... if the tx has LWSSS_FLAG_COALESCE_CONTINUES flag then more
+        * multipart sections are expected.  Without it, the multipart wrapper
+        * is closed and the http transaction issue completed when this message
+        * finishes. */
+       LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED                    = (1 << 12),
+       /**< set up lws_system client cert */
+       LWSSSPOLF_LOCAL_SINK                                    = (1 << 13),
+       /**< expected to bind to a local sink only */
+       LWSSSPOLF_WAKE_SUSPEND__VALIDITY                        = (1 << 14),
+       /**< this stream's idle validity checks are critical enough we
+        * should arrange to wake from suspend to perform them
+        */
+       LWSSSPOLF_SERVER                                        = (1 << 15),
+       /**< we listen on a socket as a server */
+       LWSSSPOLF_ALLOW_REDIRECTS                               = (1 << 16),
+       /**< follow redirects */
+       LWSSSPOLF_HTTP_MULTIPART_IN                             = (1 << 17),
+       /**< handle inbound multipart mime at SS level */
+
+       LWSSSPOLF_ATTR_LOW_LATENCY                              = (1 << 18),
+       /**< stream requires low latency */
+       LWSSSPOLF_ATTR_HIGH_THROUGHPUT                          = (1 << 19),
+       /**< stream requires high throughput */
+       LWSSSPOLF_ATTR_HIGH_RELIABILITY                         = (1 << 20),
+       /**< stream requires high reliability */
+       LWSSSPOLF_ATTR_LOW_COST                                 = (1 << 21),
+       /**< stream is not critical and should be handled as cheap as poss */
+       LWSSSPOLF_PERF                                          = (1 << 22),
+       /**< capture and report performace information */
+       LWSSSPOLF_DIRECT_PROTO_STR                              = (1 << 23),
+       /**< metadata as direct protocol string, e.g. http header */
+       LWSSSPOLF_HTTP_CACHE_COOKIES                            = (1 << 24),
+       /**< Record http cookies and pass them back on future requests */
+       LWSSSPOLF_PRIORITIZE_READS                              = (1 << 25),
+       /**< prioritize clearing reads at expense of writes */
+
+};
+
+typedef struct lws_ss_trust_store {
+       struct lws_ss_trust_store       *next;
+       const char                      *name;
+
+       const lws_ss_x509_t             *ssx509[6];
+       int                             count;
+} lws_ss_trust_store_t;
+
+enum {
+       LWSSSP_H1,
+       LWSSSP_H2,
+       LWSSSP_WS,
+       LWSSSP_MQTT,
+       LWSSSP_RAW,
+
+
+       LWSSS_HBI_AUTH = 0,
+       LWSSS_HBI_DSN,
+       LWSSS_HBI_FWV,
+       LWSSS_HBI_TYPE,
+
+       _LWSSS_HBI_COUNT /* always last */
+};
+
+/*
+ * This does for both the static policy metadata entry, and the runtime metadata
+ * handling object.
+ */
+
+typedef struct lws_ss_metadata {
+       struct lws_ss_metadata  *next;
+       const char              *name;
+       void                    *value__may_own_heap;
+       size_t                  length;
+
+       uint8_t                 value_length; /* only valid if set by policy */
+       uint8_t                 value_is_http_token; /* valid if set by policy */
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       uint8_t                 name_on_lws_heap:1;  /* proxy metatadata does this */
+#endif
+       uint8_t                 value_on_lws_heap:1; /* proxy + rx metadata does this */
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       uint8_t                 pending_onward:1;
+#endif
+} lws_ss_metadata_t;
+
+typedef struct lws_ss_http_respmap {
+       uint16_t                resp;   /* the http response code */
+       uint16_t                state;  /* low 16-bits of associated state */
+} lws_ss_http_respmap_t;
+
+/*
+ * This is a mapping between an auth streamtype and a name and other information
+ * that can be independently instantiated.  Other streamtypes can indicate they
+ * require this authentication on their connection.
+ */
+
+typedef struct lws_ss_auth {
+       struct lws_ss_auth      *next;
+       const char              *name;
+
+       const char              *type;
+       const char              *streamtype;
+       uint8_t                 blob_index;
+} lws_ss_auth_t;
+
+/**
+ * lws_ss_policy_t: policy database entry for a stream type
+ *
+ * Decides the system policy for how to implement connections of name
+ * .streamtype.
+ *
+ * Streams may need one kind of auth sequencing for the network connection and
+ * another kind of auth sequencing for the streams that are carried inside it,
+ * this is the purpose of .nauth and .sauth.  Both are optional and may be NULL.
+ *
+ * An array of these is set at context creation time, ending with one with a
+ * NULL streamtype.
+ */
+typedef struct lws_ss_policy {
+       struct lws_ss_policy    *next;
+       const char              *streamtype; /**< stream type lhs to match on */
+
+       const char              *endpoint;   /**< DNS address to connect to */
+       const char              *rideshare_streamtype; /**< optional transport
+                                       * on another, preexisting stream of this
+                                       * streamtype name */
+       const char              *payload_fmt;
+       const char              *socks5_proxy;
+       lws_ss_metadata_t       *metadata; /* linked-list of metadata */
+       const lws_metric_policy_t *metrics; /* linked-list of metric policies */
+       const lws_ss_auth_t     *auth; /* NULL or auth object we bind to */
+
+       /* protocol-specific connection policy details */
+
+       union {
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) || defined(LWS_ROLE_WS)
+
+               /* details for http-related protocols... */
+
+               struct {
+
+                       /* common to all http-related protocols */
+
+                       const char      *method;
+                       const char      *url;
+
+                       const char      *multipart_name;
+                       const char      *multipart_filename;
+                       const char      *multipart_content_type;
+
+                       const char      *blob_header[_LWSSS_HBI_COUNT];
+                       const char      *auth_preamble;
+
+                       const lws_ss_http_respmap_t *respmap;
+
+                       union {
+//                             struct { /* LWSSSP_H1 */
+//                             } h1;
+//                             struct { /* LWSSSP_H2 */
+//                             } h2;
+                               struct { /* LWSSSP_WS */
+                                       const char      *subprotocol;
+                                       uint8_t         binary;
+                                       /* false = TEXT, true = BINARY */
+                               } ws;
+                       } u;
+
+                       uint16_t        resp_expect;
+                       uint8_t         count_respmap;
+                       uint8_t         fail_redirect:1;
+               } http;
+
+#endif
+
+#if defined(LWS_ROLE_MQTT)
+
+               struct {
+                       const char      *topic;     /* stream sends on this topic */
+                       const char      *subscribe; /* stream subscribes to this topic */
+
+                       const char      *will_topic;
+                       const char      *will_message;
+
+                       const char      *birth_topic;
+                       const char      *birth_message;
+
+                       uint16_t        keep_alive;
+                       uint8_t         qos;
+                       uint8_t         clean_start;
+                       uint8_t         will_qos;
+                       uint8_t         will_retain;
+                       uint8_t         birth_qos;
+                       uint8_t         birth_retain;
+                       uint8_t         aws_iot;
+
+               } mqtt;
+
+#endif
+
+               /* details for non-http related protocols... */
+       } u;
+
+#if defined(LWS_WITH_SSPLUGINS)
+       const
+       struct lws_ss_plugin    *plugins[2]; /**< NULL or auth plugin */
+       const void              *plugins_info[2];   /**< plugin-specific data */
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+       /* directly point to the metadata name, no need to expand */
+       const char *aws_region;
+       const char *aws_service;
+#endif
+       /*
+        * We're either a client connection policy that wants a trust store,
+        * or we're a server policy that wants a mem cert and key... Hold
+        * these mutually-exclusive things in a union.
+        */
+
+       union {
+               const lws_ss_trust_store_t              *store;
+               /**< CA certs needed for conn validation, only set between
+                * policy parsing and vhost creation */
+               struct {
+                       const lws_ss_x509_t             *cert;
+                       /**< the server's signed cert with the pubkey */
+                       const lws_ss_x509_t             *key;
+                       /**< the server's matching private key */
+               } server;
+       } trust;
+
+       const lws_retry_bo_t    *retry_bo;   /**< retry policy to use */
+
+       uint32_t                proxy_buflen; /**< max dsh alloc for proxy */
+       uint32_t                proxy_buflen_rxflow_on_above;
+       uint32_t                proxy_buflen_rxflow_off_below;
+
+       uint32_t                client_buflen; /**< max dsh alloc for client */
+       uint32_t                client_buflen_rxflow_on_above;
+       uint32_t                client_buflen_rxflow_off_below;
+
+
+       uint32_t                timeout_ms;  /**< default message response
+                                             * timeout in ms */
+       uint32_t                flags;       /**< stream attribute flags */
+
+       uint16_t                port;        /**< endpoint port */
+
+       uint8_t                 metadata_count;    /**< metadata count */
+       uint8_t                 protocol;    /**< protocol index */
+       uint8_t                 client_cert; /**< which client cert to apply
+                                                 0 = none, 1+ = cc 0+ */
+       uint8_t                 priority;       /* 0 = normal, 6 = max normal,
+                                                * 7 = network management */
+} lws_ss_policy_t;
+
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+
+/*
+ * These only exist / have meaning if there's a dynamic JSON policy enabled
+ */
+
+LWS_VISIBLE LWS_EXTERN int
+lws_ss_policy_parse_begin(struct lws_context *context, int overlay);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_ss_policy_parse_abandon(struct lws_context *context);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_ss_policy_parse(struct lws_context *context, const uint8_t *buf, size_t len);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_ss_policy_overlay(struct lws_context *context, const char *overlay);
+
+/*
+ * You almost certainly don't want these, they return the first policy or auth
+ * object in a linked-list of objects created by lws_ss_policy_parse above,
+ * they are exported to generate static policy with
+ */
+LWS_VISIBLE LWS_EXTERN const lws_ss_policy_t *
+lws_ss_policy_get(struct lws_context *context);
+
+LWS_VISIBLE LWS_EXTERN const lws_ss_auth_t *
+lws_ss_auth_get(struct lws_context *context);
+
+#endif
diff --git a/include/libwebsockets/lws-secure-streams.h b/include/libwebsockets/lws-secure-streams.h
new file mode 100644 (file)
index 0000000..8157c70
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * included from libwebsockets.h
+ *
+ *
+ * Secure Streams is a *payload-only* client communication channel where all the
+ * details about the connection are held in a systemwide policy database and
+ * are keyed by the streamtype field... the user of the communication channel
+ * does not know or manage the choice of endpoint, tls CA, or even wire
+ * protocol.  The advantage is he then does not have any dependency on any of
+ * those and they can be changed just by changing the policy database without
+ * touching the code using the stream.
+ *
+ * There are two ways secure streams interfaces to user code:
+ *
+ * 1) [Linux / RTOS] the natural, smallest interface is to call back to user
+ *    code that only operates directly from the lws event loop thread context
+ *    (direct callbacks from lws_ss_t)
+ *
+ *    lws_thread( [user code] ---- lws )
+ *
+ * 2) [Linux] where the user code is in a different process and communicates
+ *    asynchronously via a proxy socket
+ *
+ *    user_process{ [user code] | shim | socket-}------ lws_process{ lws }
+ *
+ * In the second, IPC, case, all packets are prepended by one or more bytes
+ * indicating the packet type and serializing any associated data, known as
+ * Serialized Secure Streams or SSS.
+ *
+ * Serialized Secure Streams
+ * -------------------------
+ *
+ * On the transport, adjacent packets may be coalesced, that is, the original
+ * packet sizes are lost and two or more packets are combined.  For that reason
+ * the serialization format always contains a 1-byte type and then a 2-byte
+ * frame length.
+ *
+ * Client to proxy
+ *
+ * - Proxied connection setup
+ *
+ *   -  0: LWSSS_SER_TXPRE_STREAMTYPE
+ *   -  1: 2-byte MSB-first rest-of-frame length
+ *   -  3: 1-byte Client SSS protocol version (introduced in SSSv1)
+ *   -  4: 4-byte Client PID (introduced in SSSv1)
+ *   -  8: 4-byte MSB-first initial tx credit
+ *   - 12: the streamtype name with no NUL
+ *
+ * - Proxied tx
+ *
+ *   -  0: LWSSS_SER_TXPRE_TX_PAYLOAD
+ *   -  1: 2 byte MSB-first rest-of-frame length
+ *   -  3: 4-byte MSB-first flags
+ *   -  7: 4-byte MSB-first us between client requested write and wrote to proxy
+ *   - 11: 8-byte MSB-first us resolution unix time client wrote to proxy
+ *   - 19: payload
+ *
+ * - Proxied secure stream destroy
+ *
+ *   -  0: LWSSS_SER_TXPRE_DESTROYING
+ *   -  1: 00, 00
+ *
+ * - Proxied metadata - sent when one metadata item set clientside
+ *
+ *   -  0: LWSSS_SER_TXPRE_METADATA
+ *   -  1: 2-byte MSB-first rest-of-frame length
+ *   -  3: 1-byte metadata name length
+ *   -  4: metadata name
+ *   -  ...: metadata value (for rest of packet)
+ *
+ * - TX credit management - sent when using tx credit apis, cf METADATA
+ *
+ *   - 0: LWSSS_SER_TXPRE_TXCR_UPDATE
+ *   - 1: 2-byte MSB-first rest-of-frame length 00, 04
+ *   - 3: 4-byte additional tx credit adjust value
+ *
+ * - Stream timeout management - forwarded when user applying or cancelling t.o.
+ *
+ *   -  0: LWSSS_SER_TXPRE_TIMEOUT_UPDATE
+ *   -  1: 2-byte MSB-first rest-of-frame length 00, 04
+ *   -  3: 4-byte MSB-first unsigned 32-bit timeout, 0 = use policy, -1 = cancel
+ *
+ * - Passing up payload length hint
+ *
+ *   -  0: LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT
+ *   -  1: 2-byte MSB-first rest-of-frame length 00, 04
+ *   -  3: 4-byte MSB-first unsigned 32-bit payload length hint
+ *
+ * Proxy to client
+ *
+ * - Proxied connection setup result
+ *
+ *   -  0: LWSSS_SER_RXPRE_CREATE_RESULT
+ *   -  1: 2 byte MSB-first rest-of-frame length (usually 00, 03)
+ *   -  3: 1 byte result, 0 = success.  On failure, proxy will close connection.
+ *   -  4: 4 byte client dsh allocation recommended for stream type, from policy
+ *         (introduced in SSSv1)
+ *   -  8: 2 byte MSB-first initial tx credit
+ *   - 10: if present, comma-sep list of rideshare types from policy
+ *
+ * - Proxied rx
+ *
+ *   -  0: LWSSS_SER_RXPRE_RX_PAYLOAD
+ *   -  1: 2 byte MSB-first rest-of-frame length
+ *   -  3: 4-byte MSB-first flags
+ *   -  7: 4-byte MSB-first us between inbound read and wrote to client
+ *   - 11: 8-byte MSB-first us resolution unix time proxy wrote to client
+ *   - 17: (rideshare name len + rideshare name if flags & LWSSS_FLAG_RIDESHARE)
+ *          payload
+ *
+ * - Proxied tx credit
+ *
+ *   -  0: LWSSS_SER_RXPRE_TXCR_UPDATE
+ *   -  1: 00, 04
+ *   -  3: 4-byte MSB-first addition tx credit bytes
+ *
+ * - Proxied rx metadata
+ *
+ *   -  0: LWSSS_SER_RXPRE_METADATA
+ *   -  1: 2-byte MSB-first rest-of-frame length
+ *   -  3: 1-byte metadata name length
+ *   -  4: metadata name
+ *   -  ...: metadata value (for rest of packet)
+ *
+ * - Proxied state (8 or 11 byte packet)
+ *
+ *   -  0: LWSSS_SER_RXPRE_CONNSTATE
+ *   -  1: 00, 05 if state < 256, else 00, 08
+ *   -  3: 1 byte state index if state < 256, else 4-byte MSB-first state index
+ *   -  4 or 7: 4-byte MSB-first ordinal
+ *
+ * - Proxied performance information
+ *
+ *   -  0: LWSSS_SER_RXPRE_PERF
+ *   -  1: 2-byte MSB-first rest-of-frame length
+ *   -  3: ... performance JSON (for rest of packet)
+ *
+ * Proxied tx may be read by the proxy but rejected due to lack of buffer space
+ * at the proxy.  For that reason, tx must be held at the sender until it has
+ * been acknowledged or denied.
+ *
+ * Sinks
+ * -----
+ *
+ * Sinks are logical "servers", you can register as a sink for a particular
+ * streamtype by using the lws_ss_create() api with ssi->register_sink set to 1.
+ *
+ * For directly fulfilled Secure Streams, new streams of that streamtype bind
+ * to the rx, tx and state handlers given when it was registered.
+ *
+ *  - When new streams are created the registered sink handler for (*state) is
+ *    called with event LWSSSCS_SINK_JOIN and the new client stream handle in
+ *    the h_src parameter.
+ *
+ *  - When the client stream sends something to the sink, it calls the sink's
+ *    (*rx) with the client stream's
+ */
+
+/** \defgroup secstr Secure Streams
+* ##Secure Streams
+*
+* Secure Streams related apis
+*/
+///@{
+
+#define LWS_SS_MTU 1540
+
+struct lws_ss_handle;
+typedef uint32_t lws_ss_tx_ordinal_t;
+
+/*
+ * connection state events
+ *
+ * If you add states, take care about the state names and state transition
+ * validity enforcement tables too
+ */
+typedef enum {
+       /* zero means unset */
+       LWSSSCS_CREATING                = 1,
+       LWSSSCS_DISCONNECTED,
+       LWSSSCS_UNREACHABLE,            /* oridinal arg = 1 = caused by dns
+                                        * server reachability failure */
+       LWSSSCS_AUTH_FAILED,
+       LWSSSCS_CONNECTED,
+       LWSSSCS_CONNECTING,
+       LWSSSCS_DESTROYING,
+       LWSSSCS_POLL,
+       LWSSSCS_ALL_RETRIES_FAILED,     /* all retries in bo policy failed */
+       LWSSSCS_QOS_ACK_REMOTE,         /* remote peer received and acked tx */
+       LWSSSCS_QOS_NACK_REMOTE,
+       LWSSSCS_QOS_ACK_LOCAL,          /* local proxy accepted our tx */
+       LWSSSCS_QOS_NACK_LOCAL,         /* local proxy refused our tx */
+       LWSSSCS_TIMEOUT,                /* optional timeout timer fired */
+
+       LWSSSCS_SERVER_TXN,
+       LWSSSCS_SERVER_UPGRADE,         /* the server protocol upgraded */
+
+       LWSSSCS_EVENT_WAIT_CANCELLED, /* somebody called lws_cancel_service */
+
+       LWSSSCS_UPSTREAM_LINK_RETRY,    /* if we are being proxied over some
+                                        * intermediate link, this transient
+                                        * state may be sent to indicate we are
+                                        * waiting to establish that link before
+                                        * creation can proceed.. ack is the
+                                        * number of ms we have been trying */
+
+       LWSSSCS_SINK_JOIN,              /* sinks get this when a new source
+                                        * stream joins the sink */
+       LWSSSCS_SINK_PART,              /* sinks get this when a new source
+                                        * stream leaves the sink */
+
+       LWSSSCS_USER_BASE = 1000
+} lws_ss_constate_t;
+
+enum {
+       LWSSS_FLAG_SOM                                          = (1 << 0),
+       /* payload contains the start of new message */
+       LWSSS_FLAG_EOM                                          = (1 << 1),
+       /* payload contains the end of message */
+       LWSSS_FLAG_POLL                                         = (1 << 2),
+       /* Not a real transmit... poll for rx if protocol needs it */
+       LWSSS_FLAG_RELATED_START                                = (1 << 3),
+       /* Appears in a zero-length message indicating a message group of zero
+        * or more messages is now starting. */
+       LWSSS_FLAG_RELATED_END                                  = (1 << 4),
+       /* Appears in a zero-length message indicating a message group of zero
+        * or more messages has now finished. */
+       LWSSS_FLAG_RIDESHARE                                    = (1 << 5),
+       /* Serialized payload starts with non-default rideshare name length and
+        * name string without NUL, then payload */
+       LWSSS_FLAG_PERF_JSON                                    = (1 << 6),
+       /* This RX is JSON performance data, only on streams with "perf" flag
+        * set */
+
+       /*
+        * In the case the secure stream is proxied across a process or thread
+        * boundary, eg by proxying through a socket for IPC, metadata must be
+        * carried in-band.  A byte is prepended to each rx payload to
+        * differentiate what it is.
+        *
+        * Secure streams where the user is called back directly does not need
+        * any of this and only pure payloads are passed.
+        *
+        * rx (received by client) prepends for proxied connections
+        */
+
+       LWSSS_SER_RXPRE_RX_PAYLOAD                              = 0x55,
+       LWSSS_SER_RXPRE_CREATE_RESULT,
+       LWSSS_SER_RXPRE_CONNSTATE,
+       LWSSS_SER_RXPRE_TXCR_UPDATE,
+       LWSSS_SER_RXPRE_METADATA,
+       LWSSS_SER_RXPRE_TLSNEG_ENCLAVE_SIGN,
+       LWSSS_SER_RXPRE_PERF,
+
+       /* tx (send by client) prepends for proxied connections */
+
+       LWSSS_SER_TXPRE_STREAMTYPE                              = 0xaa,
+       LWSSS_SER_TXPRE_ONWARD_CONNECT,
+       LWSSS_SER_TXPRE_DESTROYING,
+       LWSSS_SER_TXPRE_TX_PAYLOAD,
+       LWSSS_SER_TXPRE_METADATA,
+       LWSSS_SER_TXPRE_TXCR_UPDATE,
+       LWSSS_SER_TXPRE_TIMEOUT_UPDATE,
+       LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT,
+       LWSSS_SER_TXPRE_TLSNEG_ENCLAVE_SIGNED,
+};
+
+typedef enum {
+       LPCSPROX_WAIT_INITIAL_TX = 1, /* after connect, must send streamtype */
+       LPCSPROX_REPORTING_FAIL, /* stream creation failed, wait to to tell */
+       LPCSPROX_REPORTING_OK, /* stream creation succeeded, wait to to tell */
+       LPCSPROX_OPERATIONAL, /* ready for payloads */
+       LPCSPROX_DESTROYED,
+
+       LPCSCLI_SENDING_INITIAL_TX,  /* after connect, must send streamtype */
+       LPCSCLI_WAITING_CREATE_RESULT,   /* wait to hear if proxy ss create OK */
+       LPCSCLI_LOCAL_CONNECTED,              /* we are in touch with the proxy */
+       LPCSCLI_ONWARD_CONNECT,       /* request onward ss connection */
+       LPCSCLI_OPERATIONAL, /* ready for payloads */
+
+} lws_ss_conn_states_t;
+
+/*
+ * Returns from state() callback can tell the caller what the user code
+ * wants to do
+ */
+
+typedef enum lws_ss_state_return {
+       LWSSSSRET_TX_DONT_SEND          =  1, /* (*tx) only, or failure */
+
+       LWSSSSRET_OK                    =  0, /* no error */
+       LWSSSSRET_DISCONNECT_ME         = -1, /* caller should disconnect us */
+       LWSSSSRET_DESTROY_ME            = -2, /* caller should destroy us */
+} lws_ss_state_return_t;
+
+/**
+ * lws_ss_info_t: information about stream to be created
+ *
+ * Prepare this struct with information about what the stream type is and how
+ * the stream should interface with your code, and pass it to lws_ss_create()
+ * to create the requested stream.
+ */
+
+enum {
+       LWSSSINFLAGS_REGISTER_SINK                      =       (1 << 0),
+       /**< If set, we're not creating a specific stream, but registering
+        * ourselves as the "sink" for .streamtype.  It's analogous to saying
+        * we want to be the many-to-one "server" for .streamtype; when other
+        * streams are created with that streamtype, they should be forwarded
+        * to this stream owner, where they join and part from the sink via
+        * (*state) LWSSSCS_SINK_JOIN / _PART events, the new client handle
+        * being provided in the h_src parameter.
+        */
+       LWSSSINFLAGS_PROXIED                            =       (1 << 1),
+       /**< Set if the stream is being created as a stand-in at the proxy */
+       LWSSSINFLAGS_SERVER                             =       (1 << 2),
+       /**< Set on the server object copy of the ssi / info to indicate that
+        * stream creation using this ssi is for Accepted connections belonging
+        * to a server */
+       LWSSSINFLAGS_ACCEPTED                           =       (1 << 3),
+       /**< Set on the accepted object copy of the ssi / info to indicate that
+        * we are an accepted connection from a server's listening socket */
+};
+
+typedef lws_ss_state_return_t (*lws_sscb_rx)(void *userobj, const uint8_t *buf,
+                                            size_t len, int flags);
+typedef lws_ss_state_return_t (*lws_sscb_tx)(void *userobj,
+                                            lws_ss_tx_ordinal_t ord,
+                                            uint8_t *buf, size_t *len,
+                                            int *flags);
+typedef lws_ss_state_return_t (*lws_sscb_state)(void *userobj, void *h_src,
+                                               lws_ss_constate_t state,
+                                               lws_ss_tx_ordinal_t ack);
+
+#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
+typedef void (*lws_ss_buffer_dump_cb)(void *userobj, const uint8_t *buf,
+               size_t len, int done);
+#endif
+
+struct lws_ss_policy;
+
+typedef struct lws_ss_info {
+       const char *streamtype; /**< type of stream we want to create */
+       size_t      user_alloc; /**< size of user allocation */
+       size_t      handle_offset; /**< offset of handle stg in user_alloc type,
+                                   set to offsetof(mytype, my_handle_member) */
+       size_t      opaque_user_data_offset;
+       /**< offset of opaque user data ptr in user_alloc type, set to
+            offsetof(mytype, opaque_ud_member) */
+
+#if defined(LWS_WITH_SECURE_STREAMS_CPP)
+       const struct lws_ss_policy      *policy;
+       /**< Normally NULL, or a locally-generated policy to apply to this
+        * connection instead of a named streamtype */
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_ctx_t                            fic;
+       /**< Attach external Fault Injection context to the stream, hierarchy
+        * is ss->context */
+#endif
+
+       lws_sscb_rx rx;
+       /**< callback with rx payload for this stream */
+       lws_sscb_tx tx;
+       /**< callback to send payload on this stream... 0 = send as set in
+        * len and flags, 1 = do not send anything (ie, not even 0 len frame) */
+       lws_sscb_state state;
+       /**< advisory cb about state of stream and QoS status if applicable...
+        * h_src is only used with sinks and LWSSSCS_SINK_JOIN/_PART events.
+        * Return nonzero to indicate you want to destroy the stream. */
+#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
+       lws_ss_buffer_dump_cb dump;
+       /**< cb to record needed protocol buffer data*/
+#endif
+       int         manual_initial_tx_credit;
+       /**< 0 = manage any tx credit automatically, nonzero explicitly sets the
+        * peer stream to have the given amount of tx credit, if the protocol
+        * can support it.
+        *
+        * In the special case of _lws_smd streamtype, this is used to indicate
+        * the connection's rx class mask.
+        * */
+       uint32_t        client_pid;
+       /**< used in proxy / serialization case to hold the client pid this
+        * proxied connection is to be tagged with
+        */
+       uint8_t         flags;
+       uint8_t         sss_protocol_version;
+       /**< used in proxy / serialization case to hold the SS serialization
+        * protocol level to use with this peer... clients automatically request
+        * the most recent version they were built with
+        * (LWS_SSS_CLIENT_PROTOCOL_VERSION) and the proxy stores the requested
+        * version in here
+        */
+
+} lws_ss_info_t;
+
+/**
+ * lws_ss_create() - Create secure stream
+ *
+ * \param context: the lws context to create this inside
+ * \param tsi: service thread index to create on (normally 0)
+ * \param ssi: pointer to lws_ss_info_t filled in with info about desired stream
+ * \param opaque_user_data: opaque data to set in the stream's user object
+ * \param ppss: pointer to secure stream handle pointer set on exit
+ * \param ppayload_fmt: NULL or pointer to a string ptr to take payload format
+ *                     name from the policy
+ *
+ * Requests a new secure stream described by \p ssi be created.  If successful,
+ * the stream is created, its state callback called with LWSSSCS_CREATING, \p *ppss
+ * is set to point to the handle, and it returns 0.  If it failed, it returns
+ * nonzero.
+ *
+ * Along with the opaque stream object, streams overallocate
+ *
+ * 1) a user data struct whose size is set in ssi
+ * 2) nauth plugin instantiation data (size set in the plugin struct)
+ * 3) sauth plugin instantiation data (size set in the plugin struct)
+ * 4) space for a copy of the stream type name
+ *
+ * The user data struct is initialized to all zeros, then the .handle_offset and
+ * .opaque_user_data_offset fields of the ssi are used to prepare the user data
+ * struct with the ss handle that was created, and a copy of the
+ * opaque_user_data pointer given as an argument.
+ *
+ * If you want to set up the stream with specific information, point to it in
+ * opaque_user_data and use the copy of that pointer in your user data member
+ * for it starting from the LWSSSCS_CREATING state call.
+ *
+ * Since different endpoints chosen by the policy may require different payload
+ * formats, \p ppayload_fmt is set to point to the name of the needed payload
+ * format from the policy database if non-NULL.
+ */
+LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
+lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
+             void *opaque_user_data, struct lws_ss_handle **ppss,
+             struct lws_sequencer *seq_owner, const char **ppayload_fmt);
+
+/**
+ * lws_ss_destroy() - Destroy secure stream
+ *
+ * \param ppss: pointer to lws_ss_t pointer to be destroyed
+ *
+ * Destroys the lws_ss_t pointed to by \p *ppss, and sets \p *ppss to NULL.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_ss_destroy(struct lws_ss_handle **ppss);
+
+/**
+ * lws_ss_request_tx() - Schedule stream for tx
+ *
+ * \param pss: pointer to lws_ss_t representing stream that wants to transmit
+ *
+ * Schedules a write on the stream represented by \p pss.  When it's possible to
+ * write on this stream, the \p *tx callback will occur with an empty buffer for
+ * the stream owner to fill in.
+ *
+ * Returns 0 or LWSSSSRET_DESTROY_ME
+ */
+LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t LWS_WARN_UNUSED_RESULT
+lws_ss_request_tx(struct lws_ss_handle *pss);
+
+/**
+ * lws_ss_request_tx() - Schedule stream for tx
+ *
+ * \param pss: pointer to lws_ss_t representing stream that wants to transmit
+ * \param len: the length of the write in bytes
+ *
+ * Schedules a write on the stream represented by \p pss.  When it's possible to
+ * write on this stream, the \p *tx callback will occur with an empty buffer for
+ * the stream owner to fill in.
+ *
+ * This api variant should be used when it's possible the payload will go out
+ * over h1 with x-web-form-urlencoded or similar Content-Type.
+ */
+LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t LWS_WARN_UNUSED_RESULT
+lws_ss_request_tx_len(struct lws_ss_handle *pss, unsigned long len);
+
+/**
+ * lws_ss_client_connect() - Attempt the client connect
+ *
+ * \param h: secure streams handle
+ *
+ * Starts the connection process for the secure stream.
+ *
+ * Can return any of the lws_ss_state_return_t values depending on user
+ * state callback returns.
+ *
+ * LWSSSSRET_OK means the connection is ongoing.
+ *
+ */
+LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t LWS_WARN_UNUSED_RESULT
+lws_ss_client_connect(struct lws_ss_handle *h);
+
+/**
+ * lws_ss_get_sequencer() - Return parent sequencer pointer if any
+ *
+ * \param h: secure streams handle
+ *
+ * Returns NULL if the secure stream is not associated with a sequencer.
+ * Otherwise returns a pointer to the owning sequencer.  You can use this to
+ * identify which sequencer to direct messages to, from the secure stream
+ * callback.
+ */
+LWS_VISIBLE LWS_EXTERN struct lws_sequencer *
+lws_ss_get_sequencer(struct lws_ss_handle *h);
+
+/**
+ * lws_ss_proxy_create() - Start a unix domain socket proxy for Secure Streams
+ *
+ * \param context: lws_context
+ * \param bind: if port is 0, unix domain path with leading @ for abstract.
+ *             if port nonzero, NULL, or network interface to bind listen to
+ * \param port: tcp port to listen on
+ *
+ * Creates a vhost that listens either on an abstract namespace unix domain
+ * socket (port = 0) or a tcp listen socket (port nonzero).  If bind is NULL
+ * and port is 0, the abstract unix domain socket defaults to "proxy.ss.lws".
+ *
+ * Client connections to this proxy to Secure Streams are fulfilled using the
+ * policy local to the proxy and the data passed between the client and the
+ * proxy using serialized Secure Streams protocol.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_ss_proxy_create(struct lws_context *context, const char *bind, int port);
+
+/**
+ * lws_ss_state_name() - convenience helper to get a printable conn state name
+ *
+ * \param state: the connection state index
+ *
+ * Returns a printable name for the connection state index passed in.
+ */
+LWS_VISIBLE LWS_EXTERN const char *
+lws_ss_state_name(int state);
+
+/**
+ * lws_ss_get_context() - convenience helper to recover the lws context
+ *
+ * \param h: secure streams handle
+ *
+ * Returns the lws context.  Dispenses with the need to pass a copy of it into
+ * your secure streams handler.
+ */
+LWS_VISIBLE LWS_EXTERN struct lws_context *
+lws_ss_get_context(struct lws_ss_handle *h);
+
+#define LWSSS_TIMEOUT_FROM_POLICY                              0
+
+/**
+ * lws_ss_start_timeout() - start or restart the timeout on the stream
+ *
+ * \param h: secure streams handle
+ * \param timeout_ms: LWSSS_TIMEOUT_FROM_POLICY for policy value, else use timeout_ms
+ *
+ * Starts or restarts the stream's own timeout timer.  If the specified time
+ * passes without lws_ss_cancel_timeout() being called on the stream, then the
+ * stream state callback receives LWSSSCS_TIMEOUT
+ *
+ * The process being protected by the timeout is up to the user code, it may be
+ * arbitrarily long and cross multiple protocol transactions or involve other
+ * streams.  It's up to the user to decide when to start and when / if to cancel
+ * the stream timeout.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_ss_start_timeout(struct lws_ss_handle *h, unsigned int timeout_ms);
+
+/**
+ * lws_ss_cancel_timeout() - remove any timeout on the stream
+ *
+ * \param h: secure streams handle
+ *
+ * Disable any timeout that was applied to the stream by lws_ss_start_timeout().
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_ss_cancel_timeout(struct lws_ss_handle *h);
+
+/**
+ * lws_ss_to_user_object() - convenience helper to get user object from handle
+ *
+ * \param h: secure streams handle
+ *
+ * Returns the user allocation related to the handle.  Normally you won't need
+ * this since it's available in the rx, tx and state callbacks as "userdata"
+ * already.
+ */
+LWS_VISIBLE LWS_EXTERN void *
+lws_ss_to_user_object(struct lws_ss_handle *h);
+
+/**
+ * lws_ss_rideshare() - find the current streamtype when types rideshare
+ *
+ * \param h: the stream handle
+ *
+ * Under some conditions, the payloads may be structured using protocol-
+ * specific formatting, eg, http multipart mime.  It's possible to map the
+ * logical partitions in the payload to different stream types using
+ * the policy "rideshare" feature.
+ *
+ * This api lets the callback code find out which rideshare stream type the
+ * current payload chunk belongs to.
+ */
+LWS_VISIBLE LWS_EXTERN const char *
+lws_ss_rideshare(struct lws_ss_handle *h);
+
+
+/**
+ * lws_ss_set_metadata() - allow user to bind external data to defined ss metadata
+ *
+ * \param h: secure streams handle
+ * \param name: metadata name from the policy
+ * \param value: pointer to user-managed data to bind to name
+ * \param len: length of the user-managed data in value
+ *
+ * Binds user-managed data to the named metadata item from the ss policy.
+ * If present, the metadata item is handled in a protocol-specific way using
+ * the associated policy information.  For example, in the policy
+ *
+ *     "\"metadata\":"         "["
+ *             "{\"uptag\":"  "\"X-Upload-Tag:\"},"
+ *             "{\"ctype\":"  "\"Content-Type:\"},"
+ *             "{\"xctype\":" "\"\"}"
+ *     "],"
+ *
+ * when the policy is using h1 is interpreted to add h1 headers of the given
+ * name with the value of the metadata on the left.
+ *
+ * Return 0 if OK or nonzero if, eg, metadata name does not exist on the
+ * streamtype.  You must check the result of this, eg, transient OOM can cause
+ * these to fail and you should retry later.
+ */
+LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
+lws_ss_set_metadata(struct lws_ss_handle *h, const char *name,
+                   const void *value, size_t len);
+
+/**
+ * lws_ss_alloc_set_metadata() - copy data and bind to ss metadata
+ *
+ * \param h: secure streams handle
+ * \param name: metadata name from the policy
+ * \param value: pointer to user-managed data to bind to name
+ * \param len: length of the user-managed data in value
+ *
+ * Same as lws_ss_set_metadata(), but allocates a heap buffer for the data
+ * first and takes a copy of it, so the original can go out of scope
+ * immediately after.
+ */
+LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
+lws_ss_alloc_set_metadata(struct lws_ss_handle *h, const char *name,
+                         const void *value, size_t len);
+
+/**
+ * lws_ss_get_metadata() - get current value of stream metadata item
+ *
+ * \param h: secure streams handle
+ * \param name: metadata name from the policy
+ * \param value: pointer to pointer to be set to point at the value
+ * \param len: pointer to size_t to set to the length of the value
+ *
+ * Binds user-managed data to the named metadata item from the ss policy.
+ * If present, the metadata item is handled in a protocol-specific way using
+ * the associated policy information.  For example, in the policy
+ *
+ *     "\"metadata\":"         "["
+ *             "{\"uptag\":"  "\"X-Upload-Tag:\"},"
+ *             "{\"ctype\":"  "\"Content-Type:\"},"
+ *             "{\"xctype\":" "\"\"}"
+ *     "],"
+ *
+ * when the policy is using h1 is interpreted to add h1 headers of the given
+ * name with the value of the metadata on the left.
+ *
+ * Return 0 if \p *value and \p *len set OK, or nonzero if, eg, metadata \p name does
+ * not exist on the streamtype.
+ *
+ * The pointed-to values may only exist until the next time around the event
+ * loop.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_ss_get_metadata(struct lws_ss_handle *h, const char *name,
+                   const void **value, size_t *len);
+
+/**
+ * lws_ss_server_ack() - indicate how we feel about what the server has sent
+ *
+ * \param h: ss handle of accepted connection
+ * \param nack: 0 means we are OK with it, else some problem
+ *
+ * For SERVER secure streams
+ *
+ * Depending on the protocol, the server sending us something may be
+ * transactional, ie, built into it sending something is the idea we will
+ * respond somehow out-of-band; HTTP is like this with, eg, 200 response code.
+ *
+ * Calling this with nack=0 indicates that when we later respond, we want to
+ * acknowledge the transaction (eg, it means a 200 if http underneath), if
+ * nonzero that the transaction should act like it failed.
+ *
+ * If the underlying protocol doesn't understand transactions (eg, ws) then this
+ * has no effect either way.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_ss_server_ack(struct lws_ss_handle *h, int nack);
+
+typedef void (*lws_sssfec_cb)(struct lws_ss_handle *h, void *arg);
+
+/**
+ * lws_ss_server_foreach_client() - callback for each live client connected to server
+ *
+ * \param h: server ss handle
+ * \param cb: the callback
+ * \param arg: arg passed to callback
+ *
+ * For SERVER secure streams
+ *
+ * Call the callback \p cb once for each client ss connected to the server,
+ * passing \p arg as an additional callback argument each time.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_ss_server_foreach_client(struct lws_ss_handle *h, lws_sssfec_cb cb,
+                            void *arg);
+
+/**
+ * lws_ss_change_handlers() - helper for dynamically changing stream handlers
+ *
+ * \param h: ss handle
+ * \param rx: the new RX handler
+ * \param tx: the new TX handler
+ * \param state: the new state handler
+ *
+ * Handlers set to NULL are left unchanged.
+ *
+ * This works on any handle, client or server and takes effect immediately.
+ *
+ * Depending on circumstances this may be helpful when
+ *
+ * a) a server stream undergoes an LWSSSCS_SERVER_UPGRADE (as in http -> ws) and
+ * the payloads in the new protocol have a different purpose that is best
+ * handled in their own rx and tx callbacks, and
+ *
+ * b) you may want to serve several different, possibly large things based on
+ * what was requested.  Setting a customized handler allows clean encapsulation
+ * of the different serving strategies.
+ *
+ * If the stream is long-lived, like ws, you should set the changed handler back
+ * to the default when the transaction wanting it is completed.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_ss_change_handlers(struct lws_ss_handle *h, lws_sscb_rx rx, lws_sscb_tx tx,
+                      lws_sscb_state state);
+
+/**
+ * lws_ss_add_peer_tx_credit() - allow peer to transmit more to us
+ *
+ * \param h: secure streams handle
+ * \param add: additional tx credit (signed)
+ *
+ * Indicate to remote peer that we can accept \p add bytes more payload being
+ * sent to us.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_ss_add_peer_tx_credit(struct lws_ss_handle *h, int32_t add);
+
+/**
+ * lws_ss_get_est_peer_tx_credit() - get our current estimate of peer's tx credit
+ *
+ * \param h: secure streams handle
+ *
+ * Based on what credit we gave it, and what we have received, report our
+ * estimate of peer's tx credit usable to transmit to us.  This may be outdated
+ * in that some or all of its credit may already have been expended by sending
+ * stuff to us that is in flight already.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_ss_get_est_peer_tx_credit(struct lws_ss_handle *h);
+
+LWS_VISIBLE LWS_EXTERN const char *
+lws_ss_tag(struct lws_ss_handle *h);
+
+
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+/**
+ * lws_ss_sigv4_set_aws_key() - set aws credential into system blob
+ *
+ * \param context: lws_context
+ * \param idx:     the system blob index specified in the policy, currently
+ *                  up to 4 blobs.
+ * \param keyid:   aws access keyid
+ * \param key:     aws access key
+ *
+ * Return 0 if OK or nonzero if e.g. idx is invalid; system blob heap appending
+ * fails.
+ */
+
+LWS_VISIBLE LWS_EXTERN int
+lws_ss_sigv4_set_aws_key(struct lws_context* context, uint8_t idx,
+                               const char * keyid, const char * key);
+
+/**
+ * lws_aws_filesystem_credentials_helper() - read aws credentials from file
+ *
+ * \param path: path to read, ~ at start is converted to $HOME contents if any
+ * \param kid: eg, "aws_access_key_id"
+ * \param ak: eg, "aws_secret_access_key"
+ * \param aws_keyid: pointer to pointer for allocated keyid from credentials file
+ * \param aws_key: pointer to pointer for allocated key from credentials file
+ *
+ * Return 0 if both *aws_keyid and *aws_key allocated from the config file, else
+ * nonzero, and neither *aws_keyid or *aws_key are allocated.
+ *
+ * If *aws_keyid and *aws_key are set, it's the user's responsibility to
+ * free() them when they are no longer needed.
+ */
+
+LWS_VISIBLE LWS_EXTERN int
+lws_aws_filesystem_credentials_helper(const char *path, const char *kid,
+                                     const char *ak, char **aws_keyid,
+                                     char **aws_key);
+
+#endif
+
+///@}
+
index 90ba4c3..7189788 100644 (file)
@@ -1,24 +1,25 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * lws_sequencer is intended to help implement sequences that:
  *
@@ -48,6 +49,14 @@ typedef enum {
        LWSSEQ_WSI_CONN_FAIL,   /* wsi we bound to us has failed to connect */
        LWSSEQ_WSI_CONN_CLOSE,  /* wsi we bound to us has closed */
 
+
+       LWSSEQ_SS_STATE_BASE,   /* secure streams owned by a sequencer provide
+                                * automatic messages about state changes on
+                                * the sequencer, passing the oridinal in the
+                                * event argument field.  The message index is
+                                * LWSSEQ_SS_STATE_BASE + the enum from
+                                * lws_ss_constate_t */
+
        LWSSEQ_USER_BASE = 100  /* define your events from here */
 } lws_seq_events_t;
 
@@ -78,6 +87,8 @@ typedef struct lws_seq_info {
        lws_seq_event_cb                cb;         /* seq callback */
        const char                      *name;      /* seq name */
        const lws_retry_bo_t            *retry;     /* retry policy */
+       uint8_t                         wakesuspend:1; /* important enough to
+                                                    * wake system */
 } lws_seq_info_t;
 
 /**
@@ -95,7 +106,7 @@ typedef struct lws_seq_info {
  *
  * pt locking is used to protect the related data structures.
  */
-LWS_VISIBLE LWS_EXTERN lws_seq_t *
+LWS_VISIBLE LWS_EXTERN struct lws_sequencer *
 lws_seq_create(lws_seq_info_t *info);
 
 /**
@@ -109,7 +120,7 @@ lws_seq_create(lws_seq_info_t *info);
  * set to NULL.
  */
 LWS_VISIBLE LWS_EXTERN void
-lws_seq_destroy(lws_seq_t **seq);
+lws_seq_destroy(struct lws_sequencer **seq);
 
 /**
  * lws_seq_queue_event() - queue an event on the given sequencer
@@ -129,7 +140,7 @@ lws_seq_destroy(lws_seq_t **seq);
  * values here.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_seq_queue_event(lws_seq_t *seq, lws_seq_events_t e, void *data,
+lws_seq_queue_event(struct lws_sequencer *seq, lws_seq_events_t e, void *data,
                          void *aux);
 
 /**
@@ -149,7 +160,7 @@ lws_seq_queue_event(lws_seq_t *seq, lws_seq_events_t e, void *data,
  * close message yet.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_seq_check_wsi(lws_seq_t *seq, struct lws *wsi);
+lws_seq_check_wsi(struct lws_sequencer *seq, struct lws *wsi);
 
 #define LWSSEQTO_NONE 0
 
@@ -179,7 +190,7 @@ lws_seq_check_wsi(lws_seq_t *seq, struct lws *wsi);
  * react appropriately.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_seq_timeout_us(lws_seq_t *seq, lws_usec_t us);
+lws_seq_timeout_us(struct lws_sequencer *seq, lws_usec_t us);
 
 /**
  * lws_seq_from_user(): get the lws_seq_t pointer from the user ptr
@@ -194,7 +205,7 @@ lws_seq_timeout_us(lws_seq_t *seq, lws_usec_t us);
  * size of the lws_seq_t is unknown to user code, this helper does it for
  * you.
  */
-LWS_VISIBLE LWS_EXTERN lws_seq_t *
+LWS_VISIBLE LWS_EXTERN struct lws_sequencer *
 lws_seq_from_user(void *u);
 
 /**
@@ -207,7 +218,7 @@ lws_seq_from_user(void *u);
  * step considering a global sequencer lifetime limit.
  */
 LWS_VISIBLE LWS_EXTERN lws_usec_t
-lws_seq_us_since_creation(lws_seq_t *seq);
+lws_seq_us_since_creation(struct lws_sequencer *seq);
 
 /**
  * lws_seq_name(): get the name of this sequencer
@@ -218,7 +229,7 @@ lws_seq_us_since_creation(lws_seq_t *seq);
  * annotate logging when then are multiple sequencers in play.
  */
 LWS_VISIBLE LWS_EXTERN const char *
-lws_seq_name(lws_seq_t *seq);
+lws_seq_name(struct lws_sequencer *seq);
 
 /**
  * lws_seq_get_context(): get the lws_context sequencer was created on
@@ -229,4 +240,4 @@ lws_seq_name(lws_seq_t *seq);
  * pointer handy.
  */
 LWS_VISIBLE LWS_EXTERN struct lws_context *
-lws_seq_get_context(lws_seq_t *seq);
+lws_seq_get_context(struct lws_sequencer *seq);
index 096e270..73e498a 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup service Built-in service loop entry
@@ -58,7 +59,7 @@ lws_service(struct lws_context *context, int timeout_ms);
  * \param tsi:         Thread service index, starting at 0
  *
  * Same as lws_service(), but for a specific thread service index.  Only needed
- * if you are spawning multiple service threads.
+ * if you are spawning multiple service threads that operate on the same lws_context.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi);
@@ -166,12 +167,13 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd);
  * APIs specific to libuv event loop itegration
  */
 ///@{
-#ifdef LWS_WITH_LIBUV
+#if defined(LWS_WITH_LIBUV) && defined(UV_ERRNO_MAP)
+
 /*
  * Any direct libuv allocations in lws protocol handlers must participate in the
  * lws reference counting scheme.  Two apis are provided:
  *
- * - lws_libuv_static_refcount_add(handle, context) to mark the handle with
+ * - lws_libuv_static_refcount_add(handle, context, tsi) to mark the handle with
  *  a pointer to the context and increment the global uv object counter
  *
  * - lws_libuv_static_refcount_del() which should be used as the close callback
@@ -185,15 +187,16 @@ LWS_VISIBLE LWS_EXTERN uv_loop_t *
 lws_uv_getloop(struct lws_context *context, int tsi);
 
 LWS_VISIBLE LWS_EXTERN void
-lws_libuv_static_refcount_add(uv_handle_t *, struct lws_context *context);
+lws_libuv_static_refcount_add(uv_handle_t *, struct lws_context *context,
+                               int tsi);
 
 LWS_VISIBLE LWS_EXTERN void
 lws_libuv_static_refcount_del(uv_handle_t *);
 
 #endif /* LWS_WITH_LIBUV */
 
-#if defined(LWS_WITH_ESP32)
-#define lws_libuv_static_refcount_add(_a, _b)
+#if defined(LWS_PLAT_FREERTOS)
+#define lws_libuv_static_refcount_add(_a, _b, _c)
 #define lws_libuv_static_refcount_del NULL
 #endif
 ///@}
diff --git a/include/libwebsockets/lws-settings.h b/include/libwebsockets/lws-settings.h
new file mode 100644 (file)
index 0000000..56b4711
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Generic Settings storage
+ *
+ * Copyright (C) 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *
+ * This is like an abstract class for non-volatile storage, whether in a file-
+ * system or flash-backed blocks, etc.  Named blobs of variable size are stored
+ * in nonvolatile media of some sort.  Typically, these are JSON objects under
+ * a naming scheme like, eg, "network".
+ *
+ * There's a platform-specific storage identifier opaque_plat provided when the
+ * storage object is instantiated, this describes eg the storage device or
+ * partition in instantiation-specific terms.
+ *
+ * Blobs have a further "filename" associated with them.
+ */
+
+#define LSOOPEN_FLAG_WRITEABLE                         (1 << 0)
+
+struct lws_settings_ops;
+
+typedef struct {
+       void                                            *handle_plat;
+       const struct lws_settings_ops                   *so;
+       uint8_t                                         refcount;
+       void                                            *opaque_plat;
+} lws_settings_instance_t;
+
+typedef struct lws_settings_ops {
+       int (*get)(lws_settings_instance_t *si, const char *name,
+                  uint8_t *dest, size_t *max_actual);
+       /**< if dest is NULL, max_actual is set to the actual length without
+        * copying anything out */
+       int (*set)(lws_settings_instance_t *si, const char *name,
+                  const uint8_t *src, size_t len);
+} lws_settings_ops_t;
+
+/**
+ * lws_settings_plat_get() - read a named blob from a settings instance
+ *
+ * \param si: the settings instance
+ * \param name: the name of the setting blob in the instance
+ * \param dest: NULL, or the buffer to copy the setting blob info
+ * \param max_actual: point to size of dest, or zero; actual blob size on exit
+ *
+ * If the named blob doesn't exist in the si, or can't read, returns nonzero.
+ * Otherwise, returns 0 and sets *max_actual to the true blob size.  If dest is
+ * non-NULL, as much of the blob as will fit in the amount specified by
+ * *max_actual on entry is copied to dest.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_settings_plat_get(lws_settings_instance_t *si, const char *name,
+                     uint8_t *dest, size_t *max_actual);
+
+/**
+ * lws_settings_plat_get() - read a named blob from a settings instance
+ *
+ * \param si: the settings instance
+ * \param name: the name of the setting blob in the instance
+ * \param src: blob to copy to settings instance
+ * \param len: length of blob to copy
+ *
+ * Creates or replaces a settings blob of the given name made up of the \p len
+ * bytes of data from \p src.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_settings_plat_set(lws_settings_instance_t *si, const char *name,
+                     const uint8_t *src, size_t len);
+
+/**
+ * lws_settings_plat_printf() - read a named blob from a settings instance
+ *
+ * \param si: the settings instance
+ * \param name: the name of the setting blob in the instance
+ * \param format: printf-style format string
+ *
+ * Creates or replaces a settings blob of the given name from the printf-style
+ * format string and arguments provided.  There's no specific limit to the size,
+ * the size is computed and then a temp heap buffer used.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_settings_plat_printf(lws_settings_instance_t *si, const char *name,
+                        const char *format, ...) LWS_FORMAT(3);
+
+#define lws_settings_ops_plat \
+       .get            = lws_settings_plat_get, \
+       .set            = lws_settings_plat_set,
+
+LWS_VISIBLE LWS_EXTERN lws_settings_instance_t *
+lws_settings_init(const lws_settings_ops_t *so, void *opaque_plat);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_settings_deinit(lws_settings_instance_t **si);
index 5a2bfdb..0438aa9 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup sha SHA and B64 helpers
@@ -89,5 +90,20 @@ lws_b64_decode_string(const char *in, char *out, int out_size);
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_b64_decode_string_len(const char *in, int in_len, char *out, int out_size);
+
+struct lws_b64state {
+       unsigned char quad[4];
+       size_t done;
+       size_t len;
+       int i;
+       int c;
+};
+
+LWS_VISIBLE LWS_EXTERN void
+lws_b64_decode_state_init(struct lws_b64state *state);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_b64_decode_stateful(struct lws_b64state *s, const char *in, size_t *in_len,
+                       uint8_t *out, size_t *out_size, int final);
 ///@}
 
diff --git a/include/libwebsockets/lws-smd.h b/include/libwebsockets/lws-smd.h
new file mode 100644 (file)
index 0000000..50dbc9e
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * lws System Message Distribution
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define LWS_SMD_MAX_PAYLOAD            384
+#define LWS_SMD_CLASS_BITFIELD_BYTES   4
+
+#define LWS_SMD_STREAMTYPENAME         "_lws_smd"
+#define LWS_SMD_SS_RX_HEADER_LEN       16
+
+typedef uint32_t lws_smd_class_t;
+
+struct lws_smd_msg; /* opaque */
+struct lws_smd_peer; /* opaque */
+
+/*
+ * Well-known device classes
+ */
+
+enum {
+       LWSSMDCL_INTERACTION                                    = (1 << 0),
+       /**<
+        * Any kind of event indicating a user was interacting with the device,
+        * eg, press a button, touched the screen, lifted the device etc
+        */
+       LWSSMDCL_SYSTEM_STATE                                   = (1 << 1),
+       /**<
+        * The lws_system state changed, eg, to OPERATIONAL
+        */
+       LWSSMDCL_NETWORK                                        = (1 << 2),
+       /**<
+        * Something happened on the network, eg, link-up or DHCP, or captive
+        * portal state update
+        */
+       LWSSMDCL_METRICS                                        = (1 << 3),
+       /**<
+        * An SS client process is reporting a metric to the proxy (this class
+        * is special in that it is not rebroadcast by the proxy)
+        */
+
+       LWSSMDCL_USER_BASE_BITNUM                               = 24
+};
+
+/**
+ * lws_smd_msg_alloc() - allocate a message of length len
+ *
+ * \param ctx: the lws_context
+ * \param _class: the smd message class, recipients filter on this
+ * \param len: the required payload length
+ *
+ * This helper returns an opaque lws_smd_msg pointer and sets *buf to a buffer
+ * associated with it of length \p len.
+ *
+ * In this way the lws_msg_smd type remains completely opaque and the allocated
+ * area can be prepared by the caller directly, without copying.
+ *
+ * On failure, it returns NULL... it may fail for OOM but it may also fail if
+ * you request to allocate for a message class that the system has no
+ * participant who is listening for that class of event currently... the event
+ * generation action at the caller should be bypassed without error then.
+ *
+ * This is useful if you have a message you know the length of.  For text-based
+ * messages like JSON, lws_smd_msg_printf() is more convenient.
+ */
+LWS_VISIBLE LWS_EXTERN void * /* payload */
+lws_smd_msg_alloc(struct lws_context *ctx, lws_smd_class_t _class, size_t len);
+
+/**
+ * lws_smd_msg_free() - abandon a previously allocated message before sending
+ *
+ * \param payload: pointer the previously-allocated message payload
+ *
+ * Destroys a previously-allocated opaque message object and the requested
+ * buffer space, in the case that between allocating it and sending it, some
+ * condition was met that means it can no longer be sent, eg, an error
+ * generating the content.  Otherwise there is no need to destroy allocated
+ * message objects with this, lws will take care of it.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_smd_msg_free(void **payload);
+
+/**
+ * lws_smd_msg_send() - queue a previously allocated message
+ *
+ * \param ctx: the lws_context
+ * \param msg: the prepared message
+ *
+ * Queues an allocated, prepared message for delivery to smd clients
+ *
+ * This is threadsafe to call from a non-service thread.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_smd_msg_send(struct lws_context *ctx, void *payload);
+
+/**
+ * lws_smd_msg_printf() - queue a previously allocated message
+ *
+ * \param ctx: the lws_context
+ * \param _class: the message class
+ * \param format: the format string to prepare the payload with
+ * \param ...: arguments for the format string, if any
+ *
+ * For string-based messages, eg, JSON, allows formatted creating of the payload
+ * size discovery, allocation and message send all in one step.
+ *
+ * Unlike lws_smd_msg_alloc() you do not need to know the length beforehand as
+ * this computes it and calls lws_smd_msg_alloc() with the correct length.
+ *
+ * To be clear this also calls through to lws_smd_msg_send(), it really does
+ * everything in one step.  If there are no registered participants that want
+ * messages of \p _class, this function returns immediately without doing any
+ * allocation or anything else.
+ *
+ * This is threadsafe to call from a non-service thread.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_smd_msg_printf(struct lws_context *ctx, lws_smd_class_t _class,
+                  const char *format, ...) LWS_FORMAT(3);
+
+/**
+ * lws_smd_ss_msg_printf() - helper to prepare smd ss message tx
+ *
+ * \param h: the ss handle
+ * \param buf: the ss tx buffer
+ * \param len: on entry, points to the ss tx buffer length, on exit, set to used
+ * \param _class: the message class
+ * \param format: the format string to prepare the payload with
+ * \param ...: arguments for the format string, if any
+ *
+ * This helper lets you produce SMD messages on an SS link of the builtin
+ * streamtype LWS_SMD_STREAMTYPENAME, using the same api format as
+ * lws_smd_msg_prinf(), but writing the message into the ss tx buffer from
+ * its tx() callback.
+ */
+
+struct lws_ss_handle;
+LWS_VISIBLE LWS_EXTERN int
+lws_smd_ss_msg_printf(const char *tag, uint8_t *buf, size_t *len,
+                     lws_smd_class_t _class, const char *format, ...)
+                     LWS_FORMAT(5);
+
+/**
+ * lws_smd_ss_rx_forward() - helper to forward smd messages that came in by SS
+ *
+ * \param ss_user: ss user pointer, as delivered to rx callback
+ * \param buf: the ss rx buffer
+ * \param len: the length of the ss rx buffer
+ *
+ * Proxied Secure Streams with the streamtype LWS_SMD_STREAMTYPENAME receive
+ * serialized SMD messages from the proxy, this helper allows them to be
+ * translated into deserialized SMD messages and forwarded to registered SMD
+ * participants in the local context in one step.
+ *
+ * Just pass through what arrived in the LWS_SMD_STREAMTYPENAME rx() callback
+ * to this api.
+ *
+ * Returns 0 if OK else nonzero if unable to queue the SMD message.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_smd_ss_rx_forward(void *ss_user, const uint8_t *buf, size_t len);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_smd_sspc_rx_forward(void *ss_user, const uint8_t *buf, size_t len);
+
+typedef int (*lws_smd_notification_cb_t)(void *opaque, lws_smd_class_t _class,
+                                        lws_usec_t timestamp, void *buf,
+                                        size_t len);
+
+#define LWSSMDREG_FLAG_PROXIED_SS      (1 << 0)
+/**< It's actually a proxied SS connection registering, opaque is the ss h */
+
+/*
+ * lws_smd_register() - register to receive smd messages
+ *
+ * \param ctx: the lws_context
+ * \param opaque: an opaque pointer handed to the callback
+ * \param flags: typically 0
+ * \param _class_filter: bitmap of message classes we care about
+ * \param cb: the callback to receive messages
+ *
+ * Queues an allocated, prepared message for delivery to smd clients.
+ *
+ * Returns NULL on failure, or an opaque handle which may be given to
+ * lws_smd_unregister() to stop participating in the shared message queue.
+ *
+ * This is threadsafe to call from a non-service thread.
+ */
+
+LWS_VISIBLE LWS_EXTERN struct lws_smd_peer *
+lws_smd_register(struct lws_context *ctx, void *opaque, int flags,
+                lws_smd_class_t _class_filter, lws_smd_notification_cb_t cb);
+
+/*
+ * lws_smd_unregister() - unregister receiving smd messages
+ *
+ * \param pr: the handle returned from the registration
+ *
+ * Destroys the registration of the callback for messages and ability to send
+ * messages.
+ *
+ * It's not necessary to call this if the registration wants to survive for as
+ * long as the lws_context... lws_context_destroy will also clean up any
+ * registrations still active by then.
+ */
+
+LWS_VISIBLE LWS_EXTERN void
+lws_smd_unregister(struct lws_smd_peer *pr);
index 448f2da..c5ddab2 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup form-parsing  Form Parsing
diff --git a/include/libwebsockets/lws-spi.h b/include/libwebsockets/lws-spi.h
new file mode 100644 (file)
index 0000000..666113e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Generic I2C ops
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is like an abstract class for spi, a real implementation provides
+ * functions for the ops that use the underlying OS arrangements.
+ *
+ * It uses descriptor / queuing semantics but eg the GPIO BB implementantion is
+ * synchronous.
+ */
+
+#if !defined(__LWS_SPI_H__)
+#define __LWS_SPI_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef int (*lws_spi_cb_t)(void *opaque);
+
+enum {
+       LWSSPIMODE_CPOL                                 = (1 << 0),
+       LWSSPIMODE_CPHA                                 = (1 << 1),
+
+       LWS_SPI_BUSMODE_CLK_IDLE_LOW_SAMP_RISING        = 0,
+       LWS_SPI_BUSMODE_CLK_IDLE_HIGH_SAMP_RISING       = LWSSPIMODE_CPOL,
+       LWS_SPI_BUSMODE_CLK_IDLE_LOW_SAMP_FALLING       = LWSSPIMODE_CPHA,
+       LWS_SPI_BUSMODE_CLK_IDLE_HIGH_SAMP_FALLING      = LWSSPIMODE_CPHA |
+                                                         LWSSPIMODE_CPOL,
+
+       LWS_SPI_TXN_HALF_DUPLEX_DISCRETE        = 0,
+       /**< separate MISO and MOSI, but only either MISO or MOSI has data at
+        * one time... i2c style in SPI */
+};
+
+typedef struct lws_spi_desc {
+       const uint8_t           *src;
+       const uint8_t           *data;
+       uint8_t                 *dest;
+       void                    *opaque;
+       lws_spi_cb_t            completion_cb;
+       uint16_t                count_cmd;
+       uint16_t                count_write;
+       uint16_t                count_read;
+       uint8_t                 txn_type;
+       uint8_t                 channel;
+} lws_spi_desc_t;
+
+typedef struct lws_spi_ops {
+       int  (*init)(const struct lws_spi_ops *ctx);
+       int  (*queue)(const struct lws_spi_ops *ctx, const lws_spi_desc_t *desc);
+       uint8_t bus_mode;
+} lws_spi_ops_t;
+
+#endif
diff --git a/include/libwebsockets/lws-ssd1306-i2c.h b/include/libwebsockets/lws-ssd1306-i2c.h
new file mode 100644 (file)
index 0000000..8b2f6e3
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * lws abstract display implementation for ssd1306 on i2c
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(__LWS_DISPLAY_SSD1306_I2C_H__)
+#define __LWS_DISPLAY_SSD1306_I2C_H__
+
+/*
+ * D/C# pin on SSD1306 sets the I2C device ads
+ * from these two options (7-bit address)
+ */
+
+#define SSD1306_I2C7_ADS1              0x3c
+#define SSD1306_I2C7_ADS2              0x3d
+
+typedef struct lws_display_ssd1306 {
+
+       lws_display_t           disp; /* use lws_display_ssd1306_ops to set ops */
+       const lws_i2c_ops_t     *i2c;         /* i2c ops */
+
+       const lws_gpio_ops_t    *gpio;        /* NULL or gpio ops */
+       _lws_plat_gpio_t        reset_gpio;   /* if gpio ops, nReset gpio # */
+
+       uint8_t                 i2c7_address; /* one of SSD1306_I2C7_ADS... */
+
+} lws_display_ssd1306_t;
+
+int
+lws_display_ssd1306_i2c_init(const struct lws_display *disp);
+int
+lws_display_ssd1306_i2c_contrast(const struct lws_display *disp, uint8_t b);
+int
+lws_display_ssd1306_i2c_blit(const struct lws_display *disp, const uint8_t *src,
+                             lws_display_scalar x, lws_display_scalar y,
+                             lws_display_scalar w, lws_display_scalar h);
+int
+lws_display_ssd1306_i2c_power(const struct lws_display *disp, int state);
+
+#define lws_display_ssd1306_ops \
+       .init = lws_display_ssd1306_i2c_init, \
+       .contrast = lws_display_ssd1306_i2c_contrast, \
+       .blit = lws_display_ssd1306_i2c_blit, \
+       .power = lws_display_ssd1306_i2c_power
+#endif
diff --git a/include/libwebsockets/lws-state.h b/include/libwebsockets/lws-state.h
new file mode 100644 (file)
index 0000000..7828153
--- /dev/null
@@ -0,0 +1,119 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+struct lws_state_notify_link;
+struct lws_state_manager;
+
+#if defined(LWS_WITH_SYS_STATE)
+
+typedef int (*lws_state_notify_t)(struct lws_state_manager *mgr,
+                                 struct lws_state_notify_link *link,
+                                 int current, int target);
+
+typedef struct lws_state_notify_link {
+       lws_dll2_t              list;
+       lws_state_notify_t      notify_cb;
+       const char              *name;
+} lws_state_notify_link_t;
+
+typedef struct lws_state_manager {
+       lws_dll2_owner_t        notify_list;
+       struct lws_context      *context;
+       void                    *parent;
+#if defined(LWS_WITH_SYS_SMD)
+       lws_smd_class_t         smd_class;
+#endif
+       /**< optional opaque pointer to owning object... useful to make such
+        * a pointer available to a notification callback.  Ignored by lws */
+       const char              **state_names;
+       const char              *name;
+       int                     state;
+} lws_state_manager_t;
+
+/**
+ * lws_state_reg_notifier() - add dep handler for state notifications
+ *
+ * \param context: the lws_context
+ * \param nl: the handler to add to the notifier linked-list
+ *
+ * Add \p notify_link to the context's list of notification handlers for system
+ * state changes.  The handlers can defeat or take over responsibility for
+ * retrying the change after they have initiated some dependency.
+ */
+
+LWS_EXTERN LWS_VISIBLE void
+lws_state_reg_notifier(lws_state_manager_t *mgr, lws_state_notify_link_t *nl);
+
+/**
+ * lws_state_reg_deregister() - deregister a notifier
+ *
+ * \param nl: notification hardler to deregister
+ *
+ * Remove a notification handler from its state manager
+ */
+
+LWS_EXTERN LWS_VISIBLE void
+lws_state_reg_deregister(lws_state_notify_link_t *nl);
+
+/**
+ * lws_state_reg_notifier_list() - add dep handlers for state notifications
+ *
+ * \param context: the lws_context
+ * \param nl: list of notification handlers
+ *
+ * Add a NULL-terminated list of notification handler pointers to a notification
+ * manager object
+ */
+
+LWS_EXTERN LWS_VISIBLE void
+lws_state_reg_notifier_list(lws_state_manager_t *mgr,
+                           lws_state_notify_link_t * const *nl);
+
+/**
+ * lws_state_transition_steps() - move to state via starting any deps
+ *
+ * \param mgr: the state manager object
+ * \param target: the state we wish to move to
+ *
+ * Advance state by state towards state \p target.  At each state, notifiers
+ * may veto the change and be triggered to perform dependencies, stopping the
+ * advance towards the target state.
+ */
+LWS_EXTERN LWS_VISIBLE int
+lws_state_transition_steps(lws_state_manager_t *mgr, int target);
+
+/**
+ * lws_state_transition() - move to state via starting any deps
+ *
+ * \param mgr: the state manager object
+ * \param target: the state we wish to move to
+ *
+ * Jump to state target atomically.  Notifiers may veto it.
+ */
+LWS_EXTERN LWS_VISIBLE int
+lws_state_transition(lws_state_manager_t *mgr, int target);
+
+#else
+
+#endif
diff --git a/include/libwebsockets/lws-stats.h b/include/libwebsockets/lws-stats.h
deleted file mode 100644 (file)
index 58d02de..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
- */
-
-/*
- * Stats are all uint64_t numbers that start at 0.
- * Index names here have the convention
- *
- *  _C_ counter
- *  _B_ byte count
- *  _MS_ millisecond count
- */
-
-enum {
-       LWSSTATS_C_CONNECTIONS, /**< count incoming connections */
-       LWSSTATS_C_API_CLOSE, /**< count calls to close api */
-       LWSSTATS_C_API_READ, /**< count calls to read from socket api */
-       LWSSTATS_C_API_LWS_WRITE, /**< count calls to lws_write API */
-       LWSSTATS_C_API_WRITE, /**< count calls to write API */
-       LWSSTATS_C_WRITE_PARTIALS, /**< count of partial writes */
-       LWSSTATS_C_WRITEABLE_CB_REQ, /**< count of writable callback requests */
-       LWSSTATS_C_WRITEABLE_CB_EFF_REQ, /**< count of effective writable callback requests */
-       LWSSTATS_C_WRITEABLE_CB, /**< count of writable callbacks */
-       LWSSTATS_C_SSL_CONNECTIONS_FAILED, /**< count of failed SSL connections */
-       LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, /**< count of accepted SSL connections */
-       LWSSTATS_C_SSL_ACCEPT_SPIN, /**< count of SSL_accept() attempts */
-       LWSSTATS_C_SSL_CONNS_HAD_RX, /**< count of accepted SSL conns that have had some RX */
-       LWSSTATS_C_TIMEOUTS, /**< count of timed-out connections */
-       LWSSTATS_C_SERVICE_ENTRY, /**< count of entries to lws service loop */
-       LWSSTATS_B_READ, /**< aggregate bytes read */
-       LWSSTATS_B_WRITE, /**< aggregate bytes written */
-       LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, /**< aggreate of size of accepted write data from new partials */
-       LWSSTATS_US_SSL_ACCEPT_LATENCY_AVG, /**< aggregate delay in accepting connection */
-       LWSSTATS_US_WRITABLE_DELAY_AVG, /**< aggregate delay between asking for writable and getting cb */
-       LWSSTATS_US_WORST_WRITABLE_DELAY, /**< single worst delay between asking for writable and getting cb */
-       LWSSTATS_US_SSL_RX_DELAY_AVG, /**< aggregate delay between ssl accept complete and first RX */
-       LWSSTATS_C_PEER_LIMIT_AH_DENIED, /**< number of times we would have given an ah but for the peer limit */
-       LWSSTATS_C_PEER_LIMIT_WSI_DENIED, /**< number of times we would have given a wsi but for the peer limit */
-       LWSSTATS_C_CONNS_CLIENT, /**< attempted client conns */
-       LWSSTATS_C_CONNS_CLIENT_FAILED, /**< failed client conns */
-
-       /* Add new things just above here ---^
-        * This is part of the ABI, don't needlessly break compatibility
-        *
-        * UPDATE stat_names in stats.c in sync with this!
-        */
-       LWSSTATS_SIZE
-};
-
-#if defined(LWS_WITH_STATS)
-
-LWS_VISIBLE LWS_EXTERN uint64_t
-lws_stats_get(struct lws_context *context, int index);
-LWS_VISIBLE LWS_EXTERN void
-lws_stats_log_dump(struct lws_context *context);
-#else
-static LWS_INLINE uint64_t
-lws_stats_get(struct lws_context *context, int index) { (void)context; (void)index;  return 0; }
-static LWS_INLINE void
-lws_stats_log_dump(struct lws_context *context) { (void)context; }
-#endif
index 0d02f59..dac2619 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #if defined(LWS_WITH_STRUCT_SQLITE3)
@@ -34,6 +35,7 @@ typedef enum {
        LSMT_LIST,
        LSMT_CHILD_PTR,
        LSMT_SCHEMA,
+       LSMT_BLOB_PTR,
 
 } lws_struct_map_type_eum;
 
@@ -69,6 +71,8 @@ typedef struct lws_struct_args {
        size_t ac_block_size;
        int subtype;
 
+       int top_schema_index;
+
        /*
         * temp ac used to collate unknown possibly huge strings before final
         * allocation and copy
@@ -186,6 +190,23 @@ typedef struct lws_struct_args {
          LSMT_SCHEMA \
        }
 
+/*
+ * This is just used to create the table schema, it is not part of serialization
+ * and deserialization.  Blobs should be accessed separately.
+ */
+
+#define LSM_BLOB_PTR(type, blobptr_name, qname) \
+       { \
+         qname, /* JSON item, or sqlite3 column name */ \
+         NULL, \
+         NULL, \
+         offsetof(type, blobptr_name),       /* member that points to blob */ \
+         sizeof (((type *)0)->blobptr_name),       /* size of blob pointer */ \
+         0,             /* member holding blob len */ \
+         0, /* size of blob length member */ \
+         LSMT_BLOB_PTR \
+       }
+
 typedef struct lws_struct_serialize_st {
        const struct lws_dll2 *dllpos;
        const lws_struct_map_t *map;
@@ -198,7 +219,8 @@ typedef struct lws_struct_serialize_st {
 } lws_struct_serialize_st_t;
 
 enum {
-       LSSERJ_FLAG_PRETTY = 1
+       LSSERJ_FLAG_PRETTY      = (1 << 0),
+       LSSERJ_FLAG_OMIT_SCHEMA = (1 << 1)
 };
 
 typedef struct lws_struct_serialize {
@@ -229,7 +251,8 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason);
 
 LWS_VISIBLE LWS_EXTERN lws_struct_serialize_t *
 lws_struct_json_serialize_create(const lws_struct_map_t *map,
-                                size_t map_entries, int flags, void *ptoplevel);
+                                size_t map_entries, int flags,
+                                const void *ptoplevel);
 
 LWS_VISIBLE LWS_EXTERN void
 lws_struct_json_serialize_destroy(lws_struct_serialize_t **pjs);
@@ -238,21 +261,24 @@ LWS_VISIBLE LWS_EXTERN lws_struct_json_serialize_result_t
 lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                          size_t len, size_t *written);
 
-#if defined(LWS_WITH_STRUCT_SQLITE3)
+typedef struct sqlite3 sqlite3;
 
 LWS_VISIBLE LWS_EXTERN int
-lws_struct_sq3_deserialize(sqlite3 *pdb, const lws_struct_map_t *schema,
-                          lws_dll2_owner_t *o, struct lwsac **ac,
-                          uint64_t start, int limit);
+lws_struct_sq3_serialize(sqlite3 *pdb, const lws_struct_map_t *schema,
+                        lws_dll2_owner_t *owner, uint32_t manual_idx);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_struct_sq3_deserialize(sqlite3 *pdb, const char *filter, const char *order,
+                          const lws_struct_map_t *schema, lws_dll2_owner_t *o,
+                          struct lwsac **ac, int start, int limit);
 
 LWS_VISIBLE LWS_EXTERN int
 lws_struct_sq3_create_table(sqlite3 *pdb, const lws_struct_map_t *schema);
 
 LWS_VISIBLE LWS_EXTERN int
 lws_struct_sq3_open(struct lws_context *context, const char *sqlite3_path,
-                   sqlite3 **pdb);
+                   char create_if_missing, sqlite3 **pdb);
 
 LWS_VISIBLE LWS_EXTERN int
 lws_struct_sq3_close(sqlite3 **pdb);
 
-#endif
index 6ad2f7a..07900e0 100644 (file)
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * This provides a clean way to interface lws user code to be able to
  * work unchanged on different systems for fetching common system information,
  * and performing common system operations like reboot.
+ */
+
+/*
+ * Types of system blob that can be set and retreived
+ */
+
+typedef enum {
+       LWS_SYSBLOB_TYPE_AUTH,
+       LWS_SYSBLOB_TYPE_CLIENT_CERT_DER = LWS_SYSBLOB_TYPE_AUTH + 2,
+       LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
+       LWS_SYSBLOB_TYPE_DEVICE_SERIAL,
+       LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION,
+       LWS_SYSBLOB_TYPE_DEVICE_TYPE,
+       LWS_SYSBLOB_TYPE_NTP_SERVER,
+       LWS_SYSBLOB_TYPE_MQTT_CLIENT_ID,
+       LWS_SYSBLOB_TYPE_MQTT_USERNAME,
+       LWS_SYSBLOB_TYPE_MQTT_PASSWORD,
+
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+       /* extend 4 more auth blobs, each has 2 slots */
+       LWS_SYSBLOB_TYPE_EXT_AUTH1,
+       LWS_SYSBLOB_TYPE_EXT_AUTH2 = LWS_SYSBLOB_TYPE_EXT_AUTH1 + 2,
+       LWS_SYSBLOB_TYPE_EXT_AUTH3 = LWS_SYSBLOB_TYPE_EXT_AUTH2 + 2,
+       LWS_SYSBLOB_TYPE_EXT_AUTH4 = LWS_SYSBLOB_TYPE_EXT_AUTH3 + 2,
+       LWS_SYSBLOB_TYPE_EXT_AUTH4_1,
+#endif
+
+       LWS_SYSBLOB_TYPE_COUNT /* ... always last */
+} lws_system_blob_item_t;
+
+/* opaque generic blob whose content may be on-the-heap or pointed-to
+ * directly case by case.  When it's on the heap, it can be produced by
+ * appending (it's a buflist underneath).  Either way, it can be consumed by
+ * copying out a given length from a given offset.
+ */
+
+typedef struct lws_system_blob lws_system_blob_t;
+
+LWS_EXTERN LWS_VISIBLE void
+lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
+
+LWS_EXTERN LWS_VISIBLE void
+lws_system_blob_heap_empty(lws_system_blob_t *b);
+
+LWS_EXTERN LWS_VISIBLE int
+lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
+
+LWS_EXTERN LWS_VISIBLE size_t
+lws_system_blob_get_size(lws_system_blob_t *b);
+
+/* return 0 and sets *ptr to point to blob data if possible, nonzero = fail */
+LWS_EXTERN LWS_VISIBLE int
+lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr);
+
+LWS_EXTERN LWS_VISIBLE int
+lws_system_blob_get(lws_system_blob_t *b, uint8_t *ptr, size_t *len, size_t ofs);
+
+LWS_EXTERN LWS_VISIBLE void
+lws_system_blob_destroy(lws_system_blob_t *b);
+
+/*
+ * Get the opaque blob for index idx of various system blobs.  Returns 0 if
+ * *b was set otherwise nonzero means out of range
+ */
+
+LWS_EXTERN LWS_VISIBLE lws_system_blob_t *
+lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
+                    int idx);
+
+/*
+ * Lws view of system state... normal operation from user code perspective is
+ * dependent on implicit (eg, knowing the date for cert validation) and
+ * explicit dependencies.
  *
- * An ops struct with the system-specific implementations is set at
- * context creation time, and apis are provided that call through to
- * those where they exist.
+ * Bit of lws and user code can register notification handlers that can enforce
+ * dependent operations before state transitions can complete.
  */
 
+typedef enum { /* keep system_state_names[] in sync in context.c */
+       LWS_SYSTATE_UNKNOWN,
+
+       LWS_SYSTATE_CONTEXT_CREATED,     /* context was just created */
+       LWS_SYSTATE_INITIALIZED,         /* protocols initialized.  Lws itself
+                                         * can operate normally */
+       LWS_SYSTATE_IFACE_COLDPLUG,      /* existing net ifaces iterated */
+       LWS_SYSTATE_DHCP,                /* at least one net iface configured */
+       LWS_SYSTATE_CPD_PRE_TIME,        /* Captive portal detect without valid
+                                         * time, good for non-https tests... if
+                                         * you care about it, implement and
+                                         * call lws_system_ops_t
+                                         * .captive_portal_detect_request()
+                                         * and move the state forward according
+                                         * to the result. */
+       LWS_SYSTATE_TIME_VALID,          /* ntpclient ran, or hw time valid...
+                                         * tls cannot work until we reach here
+                                         */
+       LWS_SYSTATE_CPD_POST_TIME,       /* Captive portal detect after time was
+                                         * time, good for https tests... if
+                                         * you care about it, implement and
+                                         * call lws_system_ops_t
+                                         * .captive_portal_detect_request()
+                                         * and move the state forward according
+                                         * to the result. */
+
+       LWS_SYSTATE_POLICY_VALID,        /* user code knows how to operate... */
+       LWS_SYSTATE_REGISTERED,          /* device has an identity... */
+       LWS_SYSTATE_AUTH1,               /* identity used for main auth token */
+       LWS_SYSTATE_AUTH2,               /* identity used for optional auth */
+
+       LWS_SYSTATE_OPERATIONAL,         /* user code can operate normally */
+
+       LWS_SYSTATE_POLICY_INVALID,      /* user code is changing its policies
+                                         * drop everything done with old
+                                         * policy, switch to new then enter
+                                         * LWS_SYSTATE_POLICY_VALID */
+       LWS_SYSTATE_CONTEXT_DESTROYING,  /* Context is being destroyed */
+} lws_system_states_t;
+
+/* Captive Portal Detect -related */
+
 typedef enum {
-       LWS_SYSI_HRS_DEVICE_MODEL = 1,
-       LWS_SYSI_HRS_DEVICE_SERIAL,
-       LWS_SYSI_HRS_FIRMWARE_VERSION,
+       LWS_CPD_UNKNOWN = 0,    /* test didn't happen ince last DHCP acq yet */
+       LWS_CPD_INTERNET_OK,    /* no captive portal: our CPD test passed OK,
+                                * we can go out on the internet */
+       LWS_CPD_CAPTIVE_PORTAL, /* we inferred we're behind a captive portal */
+       LWS_CPD_NO_INTERNET,    /* we couldn't touch anything */
+} lws_cpd_result_t;
 
-       LWS_SYSI_USER_BASE = 100
-} lws_system_item_t;
+typedef void (*lws_attach_cb_t)(struct lws_context *context, int tsi, void *opaque);
+struct lws_attach_item;
 
-typedef union {
-       const char      *hrs;   /* human readable string */
-       void            *data;
-       time_t          t;
-} lws_system_arg_t;
+LWS_EXTERN LWS_VISIBLE int
+lws_tls_jit_trust_got_cert_cb(struct lws_context *cx, void *got_opaque,
+                             const uint8_t *skid, size_t skid_len,
+                             const uint8_t *der, size_t der_len);
 
 typedef struct lws_system_ops {
-       int (*get_info)(lws_system_item_t i, lws_system_arg_t arg, size_t *len);
        int (*reboot)(void);
+       int (*set_clock)(lws_usec_t us);
+       int (*attach)(struct lws_context *context, int tsi, lws_attach_cb_t cb,
+                     lws_system_states_t state, void *opaque,
+                     struct lws_attach_item **get);
+       /**< if \p get is NULL, add an attach callback request to the pt for
+        * \p cb with arg \p opaque, that should be called when we're at or past
+        * system state \p state.
+        *
+        * If \p get is non-NULL, look for the first listed item on the pt whose
+        * state situation is ready, and set *get to point to it.  If no items,
+        * or none where the system state is right, set *get to NULL.
+        *
+        * It's done like this so (*attach) can perform system-specific
+        * locking outside of lws core, for both getting and adding items the
+        * same so it is thread-safe.  A non-threadsafe helper
+        * __lws_system_attach() is provided to do the actual work inside the
+        * system-specific locking.
+        */
+       int (*captive_portal_detect_request)(struct lws_context *context);
+       /**< Check if we can go out on the internet cleanly, or if we are being
+        * redirected or intercepted by a captive portal.
+        * Start the check that proceeds asynchronously, and report the results
+        * by calling lws_captive_portal_detect_result() api
+        */
+
+       int (*metric_report)(lws_metric_pub_t *mdata);
+       /**< metric \p item is reporting an event of kind \p rpt,
+        * held in \p mdata... return 0 to leave the metric object as it is,
+        * or nonzero to reset it. */
+
+       int (*jit_trust_query)(struct lws_context *cx, const uint8_t *skid,
+                              size_t skid_len, void *got_opaque);
+       /**< user defined trust store search, if we do trust a cert with SKID
+        * matching skid / skid_len, then it should get hold of the DER for the
+        * matching root CA and call
+        * lws_tls_jit_trust_got_cert_cb(..., got_opaque) before cleaning up and
+        * returning.  The DER should be destroyed if in heap before returning.
+        */
+
+       uint32_t        wake_latency_us;
+       /**< time taken for this device to wake from suspend, in us
+        */
 } lws_system_ops_t;
 
+#if defined(LWS_WITH_SYS_STATE)
+
+/**
+ * lws_system_get_state_manager() - return the state mgr object for system state
+ *
+ * \param context: the lws_context
+ *
+ * The returned pointer can be used with the lws_state_ apis
+ */
+
+LWS_EXTERN LWS_VISIBLE lws_state_manager_t *
+lws_system_get_state_manager(struct lws_context *context);
+
+#endif
+
 /* wrappers handle NULL members or no ops struct set at all cleanly */
 
+#define LWSSYSGAUTH_HEX (1 << 0)
+
+/**
+ * lws_system_get_ops() - get ahold of the system ops struct from the context
+ *
+ * \param context: the lws_context
+ *
+ * Returns the system ops struct.  It may return NULL and if not, anything in
+ * there may be NULL.
+ */
+LWS_EXTERN LWS_VISIBLE const lws_system_ops_t *
+lws_system_get_ops(struct lws_context *context);
+
+#if defined(LWS_WITH_SYS_STATE)
+
+/**
+ * lws_system_context_from_system_mgr() - return context from system state mgr
+ *
+ * \param mgr: pointer to specifically the system state mgr
+ *
+ * Returns the context from the system state mgr.  Helper since the lws_context
+ * is opaque.
+ */
+LWS_EXTERN LWS_VISIBLE struct lws_context *
+lws_system_context_from_system_mgr(lws_state_manager_t *mgr);
+
+#endif
+
 /**
- * lws_system_get_info() - get standardized system information
+ * __lws_system_attach() - get and set items on context attach list
+ *
+ * \param context: context to get or set attach items to
+ * \param tsi: thread service index (normally 0)
+ * \param cb: callback to call from context event loop thread
+ * \param state: the lws_system state we have to be in or have passed through
+ * \param opaque: optional pointer to user specific info given to callback
+ * \param get: NULL, or pointer to pointer to take detached tail item on exit
+ *
+ * This allows other threads to enqueue callback requests to happen from a pt's
+ * event loop thread safely.  The callback gets the context pointer and a user
+ * opaque pointer that can be optionally given when the item is added to the
+ * attach list.
+ *
+ * This api is the no-locking core function for getting and setting items on the
+ * pt's attach list.  The lws_system operation (*attach) is the actual
+ * api that user and internal code calls for this feature, it should perform
+ * system-specific locking, call this helper, release the locking and then
+ * return the result.  This api is public only so it can be used in the locked
+ * implementation of (*attach).
+ *
+ * If get is NULL, then the call adds to the head of the pt attach list using
+ * cb, state, and opaque; if get is non-NULL, then *get is set to the first
+ * waiting attached item that meets the state criteria and that item is removed
+ * from the list.
+ *
+ * This is a non-threadsafe helper only designed to be called from
+ * implementations of struct lws_system's (*attach) operation where system-
+ * specific locking has been applied around it, making it threadsafe.
+ */
+LWS_EXTERN LWS_VISIBLE int
+__lws_system_attach(struct lws_context *context, int tsi, lws_attach_cb_t cb,
+                   lws_system_states_t state, void *opaque,
+                   struct lws_attach_item **get);
+
+
+enum {
+       LWSDH_IPV4_SUBNET_MASK          = 0,
+       LWSDH_IPV4_BROADCAST,
+       LWSDH_LEASE_SECS,
+       LWSDH_REBINDING_SECS,
+       LWSDH_RENEWAL_SECS,
+
+       _LWSDH_NUMS_COUNT,
+
+       LWSDH_SA46_IP                   = 0,
+       LWSDH_SA46_DNS_SRV_1,
+       LWSDH_SA46_DNS_SRV_2,
+       LWSDH_SA46_DNS_SRV_3,
+       LWSDH_SA46_DNS_SRV_4,
+       LWSDH_SA46_IPV4_ROUTER,
+       LWSDH_SA46_NTP_SERVER,
+       LWSDH_SA46_DHCP_SERVER,
+
+       _LWSDH_SA46_COUNT,
+};
+
+typedef struct lws_dhcpc_ifstate {
+       char                            ifname[16];
+       char                            domain[64];
+       uint8_t                         mac[6];
+       uint32_t                        nums[_LWSDH_NUMS_COUNT];
+       lws_sockaddr46                  sa46[_LWSDH_SA46_COUNT];
+} lws_dhcpc_ifstate_t;
+
+typedef int (*dhcpc_cb_t)(void *opaque, lws_dhcpc_ifstate_t *is);
+
+/**
+ * lws_dhcpc_request() - add a network interface to dhcpc management
+ *
+ * \param c: the lws_context
+ * \param i: the interface name, like "eth0"
+ * \param af: address family
+ * \param cb: the change callback
+ * \param opaque: opaque pointer given to the callback
+ *
+ * Register a network interface as being managed by DHCP.  lws will proceed to
+ * try to acquire an IP.  Requires LWS_WITH_SYS_DHCP_CLIENT at cmake.
+ */
+LWS_EXTERN LWS_VISIBLE int
+lws_dhcpc_request(struct lws_context *c, const char *i, int af, dhcpc_cb_t cb,
+               void *opaque);
+
+/**
+ * lws_dhcpc_remove() - remove a network interface to dhcpc management
  *
  * \param context: the lws_context
- * \param item: which information to fetch
- * \param arg: where to place the result
- * \param len: incoming: max length of result, outgoing: used length of result
- *
- * This queries a standardized information-fetching ops struct that can be
- * applied to the context... the advantage is it allows you to get common items
- * of information like a device serial number writing the code once, even if the
- * actual serial number muse be fetched in wildly different ways depending on
- * the exact platform it's running on.
- *
- * Set arg and *len on entry to be the result location and the max length that
- * can be used there, on seccessful exit *len is set to the actual length and
- * 0 is returned.  On error, 1 is returned.
+ * \param iface: the interface name, like "eth0"
+ *
+ * Remove handling of the network interface from dhcp.
  */
 LWS_EXTERN LWS_VISIBLE int
-lws_system_get_info(struct lws_context *context, lws_system_item_t item,
-                   lws_system_arg_t arg, size_t *len);
+lws_dhcpc_remove(struct lws_context *context, const char *iface);
 
+/**
+ * lws_dhcpc_status() - has any interface reached BOUND state
+ *
+ * \param context: the lws_context
+ * \param sa46: set to a DNS server from a bound interface, or NULL
+ *
+ * Returns 1 if any network interface managed by dhcpc has reached the BOUND
+ * state (has acquired an IP, gateway and DNS server), otherwise 0.
+ */
+LWS_EXTERN LWS_VISIBLE int
+lws_dhcpc_status(struct lws_context *context, lws_sockaddr46 *sa46);
 
 /**
- * lws_system_reboot() - if provided, use the lws_system ops to reboot
+ * lws_system_cpd_start() - helper to initiate captive portal detection
  *
  * \param context: the lws_context
  *
- * If possible, the system will reboot.  Otherwise returns 1.
+ * Resets the context's captive portal state to LWS_CPD_UNKNOWN and calls the
+ * lws_system_ops_t captive_portal_detect_request() implementation to begin
+ * testing the captive portal state.
  */
 LWS_EXTERN LWS_VISIBLE int
-lws_system_reboot(struct lws_context *context);
+lws_system_cpd_start(struct lws_context *context);
+
+LWS_EXTERN LWS_VISIBLE void
+lws_system_cpd_start_defer(struct lws_context *cx, lws_usec_t defer_us);
+
+
+/**
+ * lws_system_cpd_set() - report the result of the captive portal detection
+ *
+ * \param context: the lws_context
+ * \param result: one of the LWS_CPD_ constants representing captive portal state
+ *
+ * Sets the context's captive portal detection state to result.  User captive
+ * portal detection code would call this once it had a result from its test.
+ */
+LWS_EXTERN LWS_VISIBLE void
+lws_system_cpd_set(struct lws_context *context, lws_cpd_result_t result);
+
+
+/**
+ * lws_system_cpd_state_get() - returns the last tested captive portal state
+ *
+ * \param context: the lws_context
+ *
+ * Returns one of the LWS_CPD_ constants indicating the system's understanding
+ * of the current captive portal situation.
+ */
+LWS_EXTERN LWS_VISIBLE lws_cpd_result_t
+lws_system_cpd_state_get(struct lws_context *context);
index 45680b0..334116c 100644 (file)
@@ -1,24 +1,25 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * lws_test_sequencer manages running an array of unit tests.
  */
index eb6c6e1..144c255 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup threadpool Threadpool related functions
@@ -70,7 +71,11 @@ struct lws_threadpool_create_args {
 };
 
 struct lws_threadpool_task_args {
-       struct lws *wsi;        /**< user must set to wsi task is bound to */
+#if defined(LWS_WITH_SECURE_STREAMS)
+       struct lws_ss_handle *ss; /**< either wsi or ss must be set */
+#endif
+       struct lws *wsi;        /**< either wsi or ss must be set */
+
        void *user;             /**< user may set (user-private pointer) */
        const char *name;       /**< user may set to describe task */
        char async_task;        /**< set to allow the task to shrug off the loss
@@ -172,12 +177,21 @@ lws_threadpool_enqueue(struct lws_threadpool *tp,
  * This doesn't free the task.  It only shortcuts it to state
  * LWS_TP_STATUS_STOPPED.  lws_threadpool_task_status() must be performed on
  * the task separately once it is in LWS_TP_STATUS_STOPPED to free the task.
+ *
+ * DEPRECATED: You should use lws_threadpool_dequeue_task() with
+ * lws_threadpool_get_task_wsi() / _ss() if you know there can only be one task
+ * per connection, or call it via lws_threadpool_foreach_task_wsi() / _ss() to
+ * get the tasks bound to the connection.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_threadpool_dequeue(struct lws *wsi);
+lws_threadpool_dequeue(struct lws *wsi) LWS_WARN_DEPRECATED;
+
+LWS_VISIBLE LWS_EXTERN int
+lws_threadpool_dequeue_task(struct lws_threadpool_task *task);
+
 
 /**
- * lws_threadpool_task_status() - Dequeue or try to stop a running task
+ * lws_threadpool_task_status() - reap completed tasks
  *
  * \param wsi: the wsi to query the current task of
  * \param task: receives a pointer to the opaque task
@@ -192,10 +206,21 @@ lws_threadpool_dequeue(struct lws *wsi);
  *
  * Its use is to make sure the service thread has seen the state of the task
  * before deleting it.
+ *
+ * DEPRECATED... use lws_threadpool_task_status() instead and get the task
+ * pointer from lws_threadpool_get_task_wsi() / _ss() if you know there can only
+ * be one, else call it via lws_threadpool_foreach_task_wsi() / _ss()
  */
 LWS_VISIBLE LWS_EXTERN enum lws_threadpool_task_status
 lws_threadpool_task_status_wsi(struct lws *wsi,
-                              struct lws_threadpool_task **task, void **user);
+                              struct lws_threadpool_task **task, void **user)
+                               LWS_WARN_DEPRECATED;
+
+LWS_VISIBLE LWS_EXTERN enum lws_threadpool_task_status
+lws_threadpool_task_status(struct lws_threadpool_task *task, void **user);
+
+LWS_VISIBLE LWS_EXTERN enum lws_threadpool_task_status
+lws_threadpool_task_status_noreap(struct lws_threadpool_task *task);
 
 /**
  * lws_threadpool_task_sync() - Indicate to a stalled task it may continue
@@ -228,4 +253,28 @@ lws_threadpool_task_sync(struct lws_threadpool_task *task, int stop);
 
 LWS_VISIBLE LWS_EXTERN void
 lws_threadpool_dump(struct lws_threadpool *tp);
+
+
+
+LWS_VISIBLE LWS_EXTERN struct lws_threadpool_task *
+lws_threadpool_get_task_wsi(struct lws *wsi);
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+LWS_VISIBLE LWS_EXTERN struct lws_threadpool_task *
+lws_threadpool_get_task_ss(struct lws_ss_handle *ss);
+#endif
+
+
+LWS_VISIBLE LWS_EXTERN int
+lws_threadpool_foreach_task_wsi(struct lws *wsi, void *user,
+                               int (*cb)(struct lws_threadpool_task *task,
+                                         void *user));
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+LWS_VISIBLE LWS_EXTERN int
+lws_threadpool_foreach_task_ss(struct lws_ss_handle *ss, void *user,
+               int (*cb)(struct lws_threadpool_task *task, void *user));
+#endif
+
+
 //@}
index 57e70d4..102a25f 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup timeout Connection timeouts
@@ -112,6 +113,10 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
 void
 lws_set_timeout_us(struct lws *wsi, enum pending_timeout reason, lws_usec_t us);
 
+/* helper for clearer LWS_TO_KILL_ASYNC / LWS_TO_KILL_SYNC usage */
+#define lws_wsi_close(w, to_kill) lws_set_timeout(w, 1, to_kill)
+
+
 #define LWS_SET_TIMER_USEC_CANCEL ((lws_usec_t)-1ll)
 #define LWS_USEC_PER_SEC ((lws_usec_t)1000000)
 
@@ -145,86 +150,155 @@ lws_set_timeout_us(struct lws *wsi, enum pending_timeout reason, lws_usec_t us);
 LWS_VISIBLE LWS_EXTERN void
 lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs);
 
+struct lws_sorted_usec_list;
+
+typedef void (*sul_cb_t)(struct lws_sorted_usec_list *sul);
+
+typedef struct lws_sorted_usec_list {
+       struct lws_dll2 list;   /* simplify the code by keeping this at start */
+       lws_usec_t      us;
+       sul_cb_t        cb;
+       uint32_t        latency_us;     /* us it may safely be delayed */
+} lws_sorted_usec_list_t;
+
 /*
- * lws_timed_callback_vh_protocol() - calls back a protocol on a vhost after
- *                                     the specified delay in seconds
+ * There are multiple sul owners to allow accounting for, a) events that must
+ * wake from suspend, and b) events that can be missued due to suspend
+ */
+#define LWS_COUNT_PT_SUL_OWNERS                        2
+
+#define LWSSULLI_MISS_IF_SUSPENDED             0
+#define LWSSULLI_WAKE_IF_SUSPENDED             1
+
+/*
+ * lws_sul2_schedule() - schedule a callback
+ *
+ * \param context: the lws_context
+ * \param tsi: the thread service index (usually 0)
+ * \param flags: LWSSULLI_...
+ * \param sul: pointer to the sul element
+ *
+ * Generic callback-at-a-later time function.  The callback happens on the
+ * event loop thread context.
  *
- * \param vh:   the vhost to call back
- * \param protocol: the protocol to call back
- * \param reason: callback reason
- * \param secs:        how many seconds in the future to do the callback.
+ * Although the api has us resultion, the actual resolution depends on the
+ * platform and may be, eg, 1ms.
  *
- * Callback the specified protocol with a fake wsi pointing to the specified
- * vhost and protocol, with the specified reason, at the specified time in the
- * future.
+ * This doesn't allocate and doesn't fail.
  *
- * Returns 0 if OK or 1 on OOM.
+ * If flags contains LWSSULLI_WAKE_IF_SUSPENDED, the scheduled event is placed
+ * on a sul owner list that, if the system has entered low power suspend mode,
+ * tries to arrange that the system should wake from platform suspend just
+ * before the event is due.  Scheduled events without this flag will be missed
+ * in the case the system is in suspend and nothing else happens to have woken
+ * it.
  *
- * In the multithreaded service case, the callback will occur in the same
- * service thread context as the call to this api that requested it.  If it is
- * called from a non-service thread, tsi 0 will handle it.
+ * You can call it again with another us value to change the delay or move the
+ * event to a different owner (ie, wake or miss on suspend).
  */
-LWS_VISIBLE LWS_EXTERN int
-lws_timed_callback_vh_protocol(struct lws_vhost *vh,
-                              const struct lws_protocols *prot,
-                              int reason, int secs);
+LWS_VISIBLE LWS_EXTERN void
+lws_sul2_schedule(struct lws_context *context, int tsi, int flags,
+                 lws_sorted_usec_list_t *sul);
 
 /*
- * lws_timed_callback_vh_protocol_us() - calls back a protocol on a vhost after
- *                                      the specified delay in us
+ * lws_sul_cancel() - cancel scheduled callback
  *
- * \param vh:   the vhost to call back
- * \param protocol: the protocol to call back
- * \param reason: callback reason
- * \param us:  how many us in the future to do the callback.
+ * \param sul: pointer to the sul element
  *
- * Callback the specified protocol with a fake wsi pointing to the specified
- * vhost and protocol, with the specified reason, at the specified time in the
- * future.
+ * If it's scheduled, remove the sul from its owning sorted list.
+ * If not scheduled, it's a NOP.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_sul_cancel(lws_sorted_usec_list_t *sul);
+
+/*
+ * lws_sul_earliest_wakeable_event() - get earliest wake-from-suspend event
  *
- * Returns 0 if OK or 1 on OOM.
+ * \param ctx: the lws context
+ * \param pearliest: pointer to lws_usec_t to take the result
  *
- * In the multithreaded service case, the callback will occur in the same
- * service thread context as the call to this api that requested it.  If it is
- * called from a non-service thread, tsi 0 will handle it.
+ * Either returns 1 if no pending event, or 0 and sets *pearliest to the
+ * MONOTONIC time of the current earliest next expected event.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_timed_callback_vh_protocol_us(struct lws_vhost *vh,
-                                 const struct lws_protocols *prot, int reason,
-                                 lws_usec_t us);
-
+lws_sul_earliest_wakeable_event(struct lws_context *ctx, lws_usec_t *pearliest);
 
-typedef void (*sul_cb_t)(lws_sorted_usec_list_t *sul);
+/*
+ * For backwards compatibility
+ *
+ * If us is LWS_SET_TIMER_USEC_CANCEL, the sul is removed from the scheduler.
+ * New code can use lws_sul_cancel()
+ */
 
-struct lws_sorted_usec_list {
-       struct lws_dll2 list;   /* simplify the code by keeping this at start */
-       sul_cb_t        cb;
-       lws_usec_t      us;
-};
+LWS_VISIBLE LWS_EXTERN void
+lws_sul_schedule(struct lws_context *ctx, int tsi, lws_sorted_usec_list_t *sul,
+                sul_cb_t _cb, lws_usec_t _us);
+LWS_VISIBLE LWS_EXTERN void
+lws_sul_schedule_wakesuspend(struct lws_context *ctx, int tsi,
+                            lws_sorted_usec_list_t *sul, sul_cb_t _cb,
+                            lws_usec_t _us);
 
+#if defined(LWS_WITH_SUL_DEBUGGING)
+/**
+ * lws_sul_debug_zombies() - assert there are no scheduled sul in a given object
+ *
+ * \param ctx: lws_context
+ * \param po: pointer to the object that is about to be destroyed
+ * \param len: length of the object that is about to be destroyed
+ * \param destroy_description: string clue what any failure is related to
+ *
+ * This is an optional debugging helper that walks the sul scheduler lists
+ * confirming that there are no suls scheduled that live inside the object
+ * footprint described by po and len.  When internal objects are about to be
+ * destroyed, like wsi / user_data or secure stream handles, if
+ * LWS_WITH_SUL_DEBUGGING is enabled the scheduler is checked for anything
+ * in the object being destroyed.  If something found, an error is printed and
+ * an assert fired.
+ *
+ * Internal sul like timeouts should always be cleaned up correctly, but user
+ * suls in, eg, wsi user_data area, or in secure stream user allocation, may be
+ * the cause of difficult to find bugs if valgrind not available and the user
+ * code left a sul in the scheduler after destroying the object the sul was
+ * living in.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_sul_debug_zombies(struct lws_context *ctx, void *po, size_t len,
+                     const char *destroy_description);
+#else
+#define lws_sul_debug_zombies(_a, _b, _c, _d)
+#endif
 
 /*
- * lws_sul_schedule() - schedule a callback
+ * lws_validity_confirmed() - reset the validity timer for a network connection
  *
- * \param context: the lws_context
- * \param tsi: the thread service index (usually 0)
- * \param sul: pointer to the sul element
- * \param cb: the scheduled callback
- * \param us: the delay before the callback arrives, or
- *             LWS_SET_TIMER_USEC_CANCEL to cancel it.
+ * \param wsi: the connection that saw traffic proving the connection valid
  *
- * Generic callback-at-a-later time function.  The callback happens on the
- * event loop thread context.
- *
- * Although the api has us resultion, the actual resolution depends on the
- * platform and is commonly 1ms.
+ * Network connections are subject to intervals defined by the context, the
+ * vhost if server connections, or the client connect info if a client
+ * connection.  If the connection goes longer than the specified time since
+ * last observing traffic that can only happen if traffic is passing in both
+ * directions, then lws will try to create a PING transaction on the network
+ * connection.
  *
- * This doesn't allocate and doesn't fail.
+ * If the connection reaches the specified `.secs_since_valid_hangup` time
+ * still without any proof of validity, the connection will be closed.
  *
- * You can call it again with another us value to change the delay.
+ * If the PONG comes, or user code observes traffic that satisfies the proof
+ * that both directions are passing traffic to the peer and calls this api,
+ * the connection validity timer is reset and the scheme repeats.
  */
 LWS_VISIBLE LWS_EXTERN void
-lws_sul_schedule(struct lws_context *context, int tsi,
-                lws_sorted_usec_list_t *sul, sul_cb_t cb, lws_usec_t us);
+lws_validity_confirmed(struct lws *wsi);
+
+/*
+ * These are not normally needed, they're exported for the case there's code
+ * using lws_sul for which lws is an optional link dependency.
+ */
+
+LWS_VISIBLE LWS_EXTERN int
+__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul);
+
+LWS_VISIBLE LWS_EXTERN lws_usec_t
+__lws_sul_service_ripe(lws_dll2_owner_t *own, int own_len, lws_usec_t usnow);
 
 ///@}
diff --git a/include/libwebsockets/lws-tls-sessions.h b/include/libwebsockets/lws-tls-sessions.h
new file mode 100644 (file)
index 0000000..e0b409e
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*! \defgroup tls_sessions TLS Session Management
+
+    APIs related to managing TLS Sessions
+*/
+//@{
+
+
+#define LWS_SESSION_TAG_LEN 96
+
+struct lws_tls_session_dump
+{
+       char                    tag[LWS_SESSION_TAG_LEN];
+       void                    *blob;
+        void                   *opaque;
+       size_t                  blob_len;
+};
+
+typedef int (*lws_tls_sess_cb_t)(struct lws_context *cx,
+                                struct lws_tls_session_dump *info);
+
+/**
+ * lws_tls_session_dump_save() - serialize a tls session via a callback
+ *
+ * \param vh: the vhost to load into the session cache
+ * \param host: the name of the host the session relates to
+ * \param port: the port the session connects to on the host
+ * \param cb_save: the callback to perform the saving of the session blob
+ * \param opq: an opaque pointer passed into the callback
+ *
+ * If a session matching the vhost/host/port exists in the vhost's session
+ * cache, serialize it via the provided callback.
+ *
+ * \p opq is passed to the callback without being used by lws at all.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_tls_session_dump_save(struct lws_vhost *vh, const char *host, uint16_t port,
+                         lws_tls_sess_cb_t cb_save, void *opq);
+
+/**
+ * lws_tls_session_dump_load() - deserialize a tls session via a callback
+ *
+ * \param vh: the vhost to load into the session cache
+ * \param host: the name of the host the session relates to
+ * \param port: the port the session connects to on the host
+ * \param cb_load: the callback to retreive the session blob from
+ * \param opq: an opaque pointer passed into the callback
+ *
+ * Try to preload a session described by the first three parameters into the
+ * client session cache, from the given callback.
+ *
+ * \p opq is passed to the callback without being used by lws at all.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_tls_session_dump_load(struct lws_vhost *vh, const char *host, uint16_t port,
+                         lws_tls_sess_cb_t cb_load, void *opq);
+
+///@}
index 0e14284..66b34b4 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /* Do not treat - as a terminal character, so "my-token" is one token */
 #define LWS_TOKENIZE_F_NO_FLOATS       (1 << 5)
 /* Instead of LWS_TOKZE_INTEGER, report integers as any other string token */
 #define LWS_TOKENIZE_F_NO_INTEGERS     (1 << 6)
+/* # makes the rest of the line a comment */
+#define LWS_TOKENIZE_F_HASH_COMMENT    (1 << 7)
+/* Do not treat / as a terminal character, so "multipart/related" is one token */
+#define LWS_TOKENIZE_F_SLASH_NONTERM   (1 << 8)
+/* Do not treat * as a terminal character, so "myfile*" is one token */
+#define LWS_TOKENIZE_F_ASTERISK_NONTERM        (1 << 9)
+/* Do not treat = as a terminal character, so "x=y" is one token */
+#define LWS_TOKENIZE_F_EQUALS_NONTERM  (1 << 10)
 
 typedef enum {
 
@@ -75,15 +84,17 @@ enum lws_tokenize_delimiter_tracking {
        LWSTZ_DT_NEED_NEXT_CONTENT,
 };
 
-struct lws_tokenize {
+typedef struct lws_tokenize {
        const char *start; /**< set to the start of the string to tokenize */
        const char *token; /**< the start of an identified token or delimiter */
-       int len;        /**< set to the length of the string to tokenize */
-       int token_len;  /**< the length of the identied token or delimiter */
+       size_t len;     /**< set to the length of the string to tokenize */
+       size_t token_len;       /**< the length of the identied token or delimiter */
 
-       int flags;      /**< optional LWS_TOKENIZE_F_ flags, or 0 */
-       int delim;
-};
+       uint16_t flags; /**< optional LWS_TOKENIZE_F_ flags, or 0 */
+       uint8_t delim;
+
+       int8_t e; /**< convenient for storing lws_tokenize return */
+} lws_tokenize_t;
 
 /**
  * lws_tokenize() - breaks down a string into tokens and delimiters in-place
@@ -135,4 +146,127 @@ lws_tokenize(struct lws_tokenize *ts);
  */
 
 LWS_VISIBLE LWS_EXTERN int
-lws_tokenize_cstr(struct lws_tokenize *ts, char *str, int max);
+lws_tokenize_cstr(struct lws_tokenize *ts, char *str, size_t max);
+
+
+/*
+ * lws_strexp: flexible string expansion helper api
+ *
+ * This stateful helper can handle multiple separate input chunks and multiple
+ * output buffer loads with arbitrary boundaries between literals and expanded
+ * symbols.  This allows it to handle fragmented input as well as arbitrarily
+ * long symbol expansions that are bigger than the output buffer itself.
+ *
+ * A user callback is used to convert symbol names to the symbol value.
+ *
+ * A single byte buffer for input and another for output can process any
+ * length substitution then.  The state object is around 64 bytes on a 64-bit
+ * system and it only uses 8 bytes stack.
+ */
+
+
+typedef int (*lws_strexp_expand_cb)(void *priv, const char *name, char *out,
+                                   size_t *pos, size_t olen, size_t *exp_ofs);
+
+typedef struct lws_strexp {
+       char                    name[32];
+       lws_strexp_expand_cb    cb;
+       void                    *priv;
+       char                    *out;
+       size_t                  olen;
+       size_t                  pos;
+
+       size_t                  exp_ofs;
+
+       uint8_t                 name_pos;
+       char                    state;
+} lws_strexp_t;
+
+enum {
+       LSTRX_DONE,                     /* it completed OK */
+       LSTRX_FILLED_OUT,               /* out buf filled and needs resetting */
+       LSTRX_FATAL_NAME_TOO_LONG = -1, /* fatal */
+       LSTRX_FATAL_NAME_UNKNOWN  = -2,
+};
+
+
+/**
+ * lws_strexp_init() - initialize an lws_strexp_t for use
+ *
+ * \p exp: the exp object to init
+ * \p priv: the user's object pointer to pass to callback
+ * \p cb: the callback to expand named objects
+ * \p out: the start of the output buffer, or NULL just to get the length
+ * \p olen: the length of the output buffer in bytes
+ *
+ * Prepares an lws_strexp_t for use and sets the initial output buffer
+ *
+ * If \p out is NULL, substitution proceeds normally, but no output is produced,
+ * only the length is returned.  olen should be set to the largest feasible
+ * overall length.  To use this mode, the substitution callback must also check
+ * for NULL \p out and avoid producing the output.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_strexp_init(lws_strexp_t *exp, void *priv, lws_strexp_expand_cb cb,
+               char *out, size_t olen);
+
+/**
+ * lws_strexp_reset_out() - reset the output buffer on an existing strexp
+ *
+ * \p exp: the exp object to init
+ * \p out: the start of the output buffer, or NULL to just get length
+ * \p olen: the length of the output buffer in bytes
+ *
+ * Provides a new output buffer for lws_strexp_expand() to continue to write
+ * into.  It can be the same as the old one if it has been copied out or used.
+ * The position of the next write will be reset to the start of the given buf.
+ *
+ * If \p out is NULL, substitution proceeds normally, but no output is produced,
+ * only the length is returned.  \p olen should be set to the largest feasible
+ * overall length.  To use this mode, the substitution callback must also check
+ * for NULL \p out and avoid producing the output.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_strexp_reset_out(lws_strexp_t *exp, char *out, size_t olen);
+
+/**
+ * lws_strexp_expand() - copy / expand a string into the output buffer
+ *
+ * \p exp: the exp object for the copy / expansion
+ * \p in: the start of the next input data
+ * \p len: the length of the input data
+ * \p pused_in: pointer to write the amount of input used
+ * \p pused_out: pointer to write the amount of output used
+ *
+ * Copies in to the output buffer set in exp, expanding any ${name} tokens using
+ * the callback.  \p *pused_in is set to the number of input chars used and
+ * \p *pused_out the number of output characters used
+ *
+ * May return LSTRX_FILLED_OUT early with *pused < len if the output buffer is
+ * filled.  Handle the output buffer and reset it with lws_strexp_reset_out()
+ * before calling again with adjusted in / len to continue.
+ *
+ * In the case of large expansions, the expansion itself may fill the output
+ * buffer, in which case the expansion callback returns the LSTRX_FILLED_OUT
+ * and will be called again to continue with its *exp_ofs parameter set
+ * appropriately.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_strexp_expand(lws_strexp_t *exp, const char *in, size_t len,
+                 size_t *pused_in, size_t *pused_out);
+
+/**
+ * lws_strcmp_wildcard() - strcmp but the first arg can have wildcards
+ *
+ * \p wildcard: a string that may contain zero to three *, and may lack a NUL
+ * \p wlen: length of the wildcard string
+ * \p check: string to test to see if it matches wildcard
+ * \p clen: length of check string
+ *
+ * Like strcmp, but supports patterns like "a*", "a*b", "a*b*" etc
+ * where a and b are arbitrary substrings.  Both the wc and check strings need
+ * not be NUL terminated, but are specified by lengths.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_strcmp_wildcard(const char *wildcard, size_t wlen, const char *check,
+                   size_t clen);
index 1586fec..4b0c707 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup fops file operation wrapping
@@ -44,7 +45,7 @@
  * library and in the user code.
  */
 
-#if defined(LWS_WITH_ESP32)
+#if defined(LWS_PLAT_FREERTOS)
 /* sdk preprocessor defs? compiler issue? gets confused with member names */
 #define LWS_FOP_OPEN           _open
 #define LWS_FOP_CLOSE          _close
index f6e464d..5fffb4d 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup sending-data Sending data
@@ -136,12 +137,13 @@ struct lws_write_passthru {
  *             bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
  *             are used.
  *
- *     This function provides the way to issue data back to the client
- *     for both http and websocket protocols.
+ * This function provides the way to issue data back to the client, for any
+ * role (h1, h2, ws, raw, etc).  It can only be called from the WRITEABLE
+ * callback.
  *
  * IMPORTANT NOTICE!
  *
- * When sending with websocket protocol
+ * When sending with ws protocol
  *
  * LWS_WRITE_TEXT,
  * LWS_WRITE_BINARY,
@@ -149,12 +151,11 @@ struct lws_write_passthru {
  * LWS_WRITE_PING,
  * LWS_WRITE_PONG,
  *
- * or sending on http/2,
- *
- * the send buffer has to have LWS_PRE bytes valid BEFORE the buffer pointer you
- * pass to lws_write().  Since you'll probably want to use http/2 before too
- * long, it's wise to just always do this with lws_write buffers... LWS_PRE is
- * typically 16 bytes it's not going to hurt usually.
+ * or sending on http/2... the send buffer has to have LWS_PRE bytes valid
+ * BEFORE the buffer pointer you pass to lws_write().  Since you'll probably
+ * want to use http/2 before too long, it's wise to just always do this with
+ * lws_write buffers... LWS_PRE is typically 16 bytes it's not going to hurt
+ * usually.
  *
  * start of alloc       ptr passed to lws_write      end of allocation
  *       |                         |                         |
@@ -162,8 +163,8 @@ struct lws_write_passthru {
  *       [----------------  allocated memory  ---------------]
  *              (for lws use)      [====== user buffer ======]
  *
- * This allows us to add protocol info before and after the data, and send as
- * one packet on the network without payload copying, for maximum efficiency.
+ * This allows us to add protocol info before the data, and send as one packet
+ * on the network without payload copying, for maximum efficiency.
  *
  * So for example you need this kind of code to use lws_write with a
  * 128-byte payload
@@ -173,24 +174,23 @@ struct lws_write_passthru {
  *   // fill your part of the buffer... for example here it's all zeros
  *   memset(&buf[LWS_PRE], 0, 128);
  *
- *   lws_write(wsi, &buf[LWS_PRE], 128, LWS_WRITE_TEXT);
+ *   if (lws_write(wsi, &buf[LWS_PRE], 128, LWS_WRITE_TEXT) < 128) {
+ *             ... the connection is dead ...
+ *             return -1;
+ *   }
  *
- * LWS_PRE is at least the frame nonce + 2 header + 8 length
- * LWS_SEND_BUFFER_POST_PADDING is deprecated, it's now 0 and can be left off.
- * The example apps no longer use it.
+ * LWS_PRE is currently 16, which covers ws and h2 frame headers, and is
+ * compatible with 32 and 64-bit alignment requirements.
  *
- * Pad LWS_PRE to the CPU word size, so that word references
- * to the address immediately after the padding won't cause an unaligned access
- * error. Sometimes for performance reasons the recommended padding is even
- * larger than sizeof(void *).
+ * (LWS_SEND_BUFFER_POST_PADDING is deprecated, it's now 0 and can be left off.)
  *
- *     In the case of sending using websocket protocol, be sure to allocate
- *     valid storage before and after buf as explained above.  This scheme
- *     allows maximum efficiency of sending data and protocol in a single
- *     packet while not burdening the user code with any protocol knowledge.
+ * Return may be -1 is the write failed in a way indicating that the connection
+ * has ended already, in which case you can close your side, or a positive
+ * number that is at least the number of bytes requested to send (under some
+ * encapsulation scenarios, it can indicate more than you asked was sent).
  *
- *     Return may be -1 for a fatal error needing connection close, or the
- *     number of bytes sent.
+ * The recommended test of the return is less than what you asked indicates
+ * the connection has failed.
  *
  * Truncated Writes
  * ================
@@ -203,11 +203,24 @@ struct lws_write_passthru {
  *
  * LWS will buffer the remainder automatically, and send it out autonomously.
  *
- * During that time, WRITABLE callbacks will be suppressed.
+ * During that time, WRITABLE callbacks to user code will be suppressed and
+ * instead used internally.  After it completes, it will send an extra WRITEABLE
+ * callback to the user code, in case any request was missed.  So it is possible
+ * to receive unasked-for WRITEABLE callbacks, the user code should have enough
+ * state to know if it wants to write anything and just return if not.
  *
  * This is to handle corner cases where unexpectedly the OS refuses what we
- * usually expect it to accept.  You should try to send in chunks that are
- * almost always accepted in order to avoid the inefficiency of the buffering.
+ * usually expect it to accept.  It's not recommended as the way to randomly
+ * send huge payloads, since it is being copied on to heap and is inefficient.
+ *
+ * Huge payloads should instead be sent in fragments that are around 2 x mtu,
+ * which is almost always directly accepted by the OS.  To simplify this for
+ * ws fragments, there is a helper lws_write_ws_flags() below that simplifies
+ * selecting the correct flags to give lws_write() for each fragment.
+ *
+ * In the case of RFC8441 ws-over-h2, you cannot send ws fragments larger than
+ * the max h2 frame size, typically 16KB, but should further restrict it to
+ * the same ~2 x mtu limit mentioned above.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_write(struct lws *wsi, unsigned char *buf, size_t len,
index dd5659c..8848911 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup callback-when-writeable Callback when writeable
@@ -165,7 +166,7 @@ lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
  * wsi.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len)
+lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, size_t len)
 LWS_WARN_DEPRECATED;
 
 /**
@@ -222,4 +223,24 @@ lws_get_socket_fd(struct lws *wsi);
  */
 LWS_VISIBLE LWS_EXTERN lws_fileofs_t
 lws_get_peer_write_allowance(struct lws *wsi);
+
+/**
+ * lws_wsi_tx_credit() - get / set generic tx credit if role supports it
+ *
+ * \param wsi: connection to set / get tx credit on
+ * \param peer_to_us: 0 = set / get us-to-peer direction, else peer-to-us
+ * \param add: amount of credit to add
+ *
+ * If the wsi does not support tx credit, returns 0.
+ *
+ * If add is zero, returns one of the wsi tx credit values for the wsi.
+ * If add is nonzero, \p add is added to the selected tx credit value
+ * for the wsi.
+ */
+#define LWSTXCR_US_TO_PEER 0
+#define LWSTXCR_PEER_TO_US 1
+
+LWS_VISIBLE LWS_EXTERN int
+lws_wsi_tx_credit(struct lws *wsi, char peer_to_us, int add);
+
 ///@}
index e207329..0d7b22b 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup wsclose Websocket Close
index 3face4f..10c7a64 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /*! \defgroup extensions Extension related functions
index 3f65724..d21c2a7 100644 (file)
@@ -1,24 +1,25 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 /** \defgroup wsstatus Websocket status APIs
index 8b4ec9b..e60d6d1 100644 (file)
@@ -3,22 +3,23 @@
  *
  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * included from libwebsockets.h
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 enum lws_tls_cert_info {
@@ -41,6 +42,19 @@ enum lws_tls_cert_info {
         * same tls backend, ie, OpenSSL or mbedTLS.  The different backends
         * produce different, incompatible representations for the same cert.
         */
+       LWS_TLS_CERT_INFO_DER_RAW,
+       /**< the certificate's raw DER representation.  If it's too big,
+        * -1 is returned and the size will be returned in buf->ns.len.
+        * If the certificate cannot be found -1 is returned and 0 in
+        * buf->ns.len. */
+       LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID,
+       /**< If the cert has one, the key ID responsible for the signature */
+       LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER,
+       /**< If the cert has one, the issuer responsible for the signature */
+       LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_SERIAL,
+       /**< If the cert has one, serial number responsible for the signature */
+       LWS_TLS_CERT_INFO_SUBJECT_KEY_ID,
+       /**< If the cert has one, the cert's subject key ID */
 };
 
 union lws_tls_cert_info_results {
@@ -92,7 +106,7 @@ lws_x509_create(struct lws_x509_cert **x509);
  * IMPORTANT for compatibility with mbedtls, the last used byte of \p pem
  * must be '\0' and the \p len must include it.
  *
- * Returns 0 if all went OK.
+ * Returns 0 if all went OK, or nonzero for failure.
  */
 LWS_VISIBLE LWS_EXTERN int
 lws_x509_parse_from_pem(struct lws_x509_cert *x509, const void *pem, size_t len);
@@ -134,6 +148,7 @@ lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509,
  * lws_x509_jwk_privkey_pem() - Copy a private key PEM into a jwk that has the
  *                             public part already
  *
+ * \param cx: lws_context (for random)
  * \param jwk: pointer to the jwk to initialize and set to the public key
  * \param pem: pointer to PEM private key in memory
  * \param len: length of PEM private key in memory
@@ -149,8 +164,8 @@ lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509,
  * The caller should take care to zero down passphrase if used.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_x509_jwk_privkey_pem(struct lws_jwk *jwk, void *pem, size_t len,
-                        const char *passphrase);
+lws_x509_jwk_privkey_pem(struct lws_context *cx, struct lws_jwk *jwk,
+                        void *pem, size_t len, const char *passphrase);
 
 /**
  * lws_x509_destroy() - Destroy a previously allocated lws_x509_cert object
@@ -177,8 +192,8 @@ lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type,
  * lws_tls_peer_cert_info() lets you get hold of information from the peer
  * certificate.
  *
- * Return 0 if there is a result in \p buf, or -1 indicating there was no cert
- * or another problem.
+ * Return 0 if there is a result in \p buf, or nonzero indicating there was no
+ * cert, or another problem.
  *
  * This function works the same no matter if the TLS backend is OpenSSL or
  * mbedTLS.
@@ -198,8 +213,8 @@ lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
  * lws_tls_vhost_cert_info() lets you get hold of information from the vhost
  * certificate.
  *
- * Return 0 if there is a result in \p buf, or -1 indicating there was no cert
- * or another problem.
+ * Return 0 if there is a result in \p buf, or nonzero indicating there was no
+ * cert, or another problem.
  *
  * This function works the same no matter if the TLS backend is OpenSSL or
  * mbedTLS.
@@ -217,8 +232,8 @@ lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
  * \param san_b: second SAN written into the certificate
  *
  *
- * Returns 0 if created and attached to the vhost.  Returns -1 if problems and
- * frees all allocations before returning.
+ * Returns 0 if created and attached to the vhost.  Returns nonzero if problems,
+ * and frees all allocations before returning.
  *
  * On success, any allocations are destroyed at vhost destruction automatically.
  */
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c55c619
--- /dev/null
@@ -0,0 +1,384 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+include_directories(.)
+
+macro(add_subdir_include_dirs arg1)
+       add_subdirectory(${arg1})
+       list(APPEND LWS_LIB_BUILD_INC_PATHS ${_CMAKE_INC_LIST}) 
+endmacro()
+
+set(LWS_LIB_INCLUDES "")
+
+#
+# Plat specific build items
+#
+
+if (LWS_PLAT_FREERTOS)
+       add_subdir_include_dirs(plat/freertos)
+       if (ESP_PLATFORM)
+               include_directories($ENV{IDF_PATH}/components/freertos/include
+                   $ENV{IDF_PATH}/components/esp_hw_support/include/soc/
+                   $ENV{IDF_PATH}/components/esp_common/include
+                   $ENV{IDF_PATH}/components/esp_timer/include
+                   $ENV{IDF_PATH}/components/soc/include
+                   $ENV{IDF_PATH}/components/soc/src/esp32/include
+                   $ENV{IDF_PATH}/components/lwip/port/esp32/include
+                   $ENV{IDF_PATH}/components/lwip/lwip/src/include
+                   $ENV{IDF_PATH}/components/lwip/port/esp32/include
+                   ${CMAKE_BINARY_DIR}/config
+                   $ENV{IDF_PATH}/components/esp_rom/include
+                   $ENV{IDF_PATH}/components/esp_system/include
+                   $ENV{IDF_PATH}/components/lwip/include/apps/sntp
+                   $ENV{IDF_PATH}/components/soc/soc/esp32/include
+                   $ENV{IDF_PATH}/components/heap/include
+                   $ENV{IDF_PATH}/components/mbedtls/mbedtls/include
+                   $ENV{IDF_PATH}/components/mbedtls/port/include
+                   $ENV{IDF_PATH}/components/esp_wifi/include
+                   $ENV{IDF_PATH}/components/esp_event/include
+                   $ENV{IDF_PATH}/components/esp_netif/include
+                   $ENV{IDF_PATH}/components/esp_eth/include
+                   $ENV{IDF_PATH}/components/driver/include
+                   $ENV{IDF_PATH}/components/soc/soc/include
+                   $ENV{IDF_PATH}/components/tcpip_adapter/include
+                   $ENV{IDF_PATH}/components/lwip/include/apps
+                   $ENV{IDF_PATH}/components/nvs_flash/include
+                   $ENV{IDF_PATH}/components/esp32/include
+                   $ENV{IDF_PATH}/components/spi_flash/include
+                   $ENV{IDF_PATH}/components/mdns/include
+                   $ENV{IDF_PATH}/components/lwip/lwip/src/include/lwip
+                   $ENV{IDF_PATH}/components/lwip/lwip/src/include
+                   $ENV{IDF_PATH}/components/lwip/lwip/src/include/lwip
+                   $ENV{IDF_PATH}/components/newlib/platform_include )
+       endif()
+       
+else()
+       if (LWS_PLAT_OPTEE)
+               add_subdir_include_dirs(plat/optee)
+       else()
+               if (WIN32)
+                       add_subdir_include_dirs(plat/windows)
+               else()
+                       add_subdir_include_dirs(plat/unix)
+               endif()
+       endif()
+endif()
+
+if (LIB_LIST)
+       set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST} ${CMAKE_REQUIRED_LIBRARIES})
+endif()
+
+if (LWS_WITH_ZLIB)
+       if (LWS_WITH_BUNDLED_ZLIB)
+               if (WIN32)
+                       # it's trying to delete internal zlib entry
+                       LIST(REMOVE_AT CMAKE_REQUIRED_LIBRARIES 0 )
+               endif()
+       endif()
+endif()
+
+
+# ideally we want to use pipe2()
+
+CHECK_C_SOURCE_COMPILES("
+       #ifndef _GNU_SOURCE
+       #define _GNU_SOURCE
+       #endif
+       #include <unistd.h>
+       int main(void) {
+               int fd[2];
+               return pipe2(fd, 0);
+       }" LWS_HAVE_PIPE2)
+
+# tcp keepalive needs this on linux to work practically... but it only exists
+# after kernel 2.6.37
+
+CHECK_C_SOURCE_COMPILES("#include <netinet/tcp.h>\nint main(void) { return TCP_USER_TIMEOUT; }\n" LWS_HAVE_TCP_USER_TIMEOUT)
+set(LWS_PUBLIC_INCLUDES "")
+if (LWS_WITH_TLS)
+       add_subdir_include_dirs(tls)
+endif()
+
+# Generate the lws_config.h that includes all the private compilation settings.
+configure_file(
+       "${PROJECT_SOURCE_DIR}/cmake/lws_config_private.h.in"
+       "${PROJECT_BINARY_DIR}/lws_config_private.h")
+
+add_subdir_include_dirs(core)
+add_subdir_include_dirs(misc)
+add_subdir_include_dirs(system)
+
+if (LWS_WITH_DRIVERS)
+       add_subdir_include_dirs(drivers)
+endif()
+
+if (LWS_WITH_NETWORK)
+       add_subdir_include_dirs(core-net)
+       if (LWS_WITH_ABSTRACT)
+               add_subdir_include_dirs(abstract)
+       endif()
+       add_subdir_include_dirs(roles)
+endif()
+
+if (LWS_WITH_JOSE)
+       add_subdir_include_dirs(jose)
+endif()
+if (LWS_WITH_COSE)
+       add_subdir_include_dirs(cose)
+endif()
+
+
+if (LWS_WITH_SECURE_STREAMS)
+       add_subdir_include_dirs(secure-streams)
+endif()
+
+add_subdir_include_dirs(event-libs)
+
+if (LWS_WITH_STATIC)
+    if (LWS_STATIC_PIC)
+        set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+    endif()
+
+       add_library(websockets STATIC ${SOURCES})# ${HDR_PUBLIC})
+       set_target_properties(websockets PROPERTIES LINKER_LANGUAGE C)
+       list(APPEND LWS_LIBRARIES websockets)
+       target_include_directories(websockets INTERFACE
+               $<INSTALL_INTERFACE:${LWS_INSTALL_INCLUDE_DIR}>
+               $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
+               $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/../include>
+       )
+       target_include_directories(websockets PRIVATE ${LWS_LIB_BUILD_INC_PATHS})
+       target_compile_definitions(websockets PRIVATE LWS_BUILDING_STATIC)
+       target_include_directories(websockets PUBLIC ${LWS_PUBLIC_INCLUDES})
+       set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} PARENT_SCOPE)
+
+       if (WIN32)
+               # Windows uses the same .lib ending for static libraries and shared
+               # library linker files, so rename the static library.
+               set_target_properties(websockets
+                       PROPERTIES
+                       OUTPUT_NAME websockets_static)
+       endif()
+       
+endif()
+
+if (LWS_WITH_SHARED)
+       if (NOT RESOURCES)
+               set(RESOURCES "")
+       endif()
+       
+       add_library(websockets_shared SHARED ${SOURCES} ${RESOURCES})# ${HDR_PUBLIC})
+       set_target_properties(websockets_shared PROPERTIES LINKER_LANGUAGE C)
+       list(APPEND LWS_LIBRARIES websockets_shared)
+       target_include_directories(websockets_shared INTERFACE
+               $<INSTALL_INTERFACE:${LWS_INSTALL_INCLUDE_DIR}>
+               $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
+               $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/../include>
+       )
+       target_include_directories(websockets_shared PRIVATE ${LWS_LIB_BUILD_INC_PATHS})
+       target_compile_definitions(websockets_shared PRIVATE LWS_BUILDING_SHARED)
+       target_include_directories(websockets_shared PUBLIC ${LWS_PUBLIC_INCLUDES})
+       set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} PARENT_SCOPE)
+
+       # We want the shared lib to be named "libwebsockets"
+       # not "libwebsocket_shared".
+       set_target_properties(websockets_shared
+               PROPERTIES
+               OUTPUT_NAME websockets)
+
+       if (WIN32)
+               # Compile as DLL (export function declarations)
+               set_property(
+                       TARGET websockets_shared
+                       PROPERTY COMPILE_DEFINITIONS
+                       LWS_DLL
+                       LWS_INTERNAL)
+       endif()
+
+       if (APPLE)
+               set_property(TARGET websockets_shared PROPERTY MACOSX_RPATH YES)
+       endif()
+
+       if (UNIX AND LWS_WITH_PLUGINS_API)
+               set (CMAKE_POSITION_INDEPENDENT_CODE ON)
+               if (NOT((${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") OR
+                  (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") OR
+                  (${CMAKE_SYSTEM_NAME} MATCHES "QNX")))
+                  if (LWS_WITH_SHARED)
+                               target_link_libraries(websockets_shared dl)
+                       endif()
+               endif()
+       endif()
+
+endif()
+
+#
+# expose the library private include dirs to plugins, test apps etc that are
+# part of the lib build but different targets 
+#
+
+if (LWS_WITH_SHARED)
+       get_target_property(LWS_LIB_INCLUDES websockets_shared INCLUDE_DIRECTORIES)
+else()
+       get_target_property(LWS_LIB_INCLUDES websockets INCLUDE_DIRECTORIES)
+endif()
+
+
+# Set the so version of the lib.
+# Equivalent to LDFLAGS=-version-info x:x:x
+
+if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR COMPILER_IS_CLANG)
+       foreach(lib ${LWS_LIBRARIES})
+               set_target_properties(${lib}
+                       PROPERTIES
+                       SOVERSION ${SOVERSION})
+       endforeach()
+endif()
+
+
+# Setup the linking for all libs.
+foreach (lib ${LWS_LIBRARIES})
+       target_link_libraries(${lib} ${LIB_LIST})
+endforeach()
+
+#
+# These will be available to parent projects including libwebsockets
+# using add_subdirectory()
+#
+set(LIBWEBSOCKETS_LIBRARIES ${LWS_LIBRARIES} CACHE STRING "Libwebsocket libraries")
+if (LWS_WITH_STATIC)
+       set(LIBWEBSOCKETS_LIBRARIES_STATIC websockets CACHE STRING "Libwebsocket static library")
+endif()
+if (LWS_WITH_SHARED)
+       set(LIBWEBSOCKETS_LIBRARIES_SHARED websockets_shared CACHE STRING "Libwebsocket shared library")
+endif()
+
+# Install libs and headers.
+install(TARGETS ${LWS_LIBRARIES}
+               EXPORT LibwebsocketsTargets
+               LIBRARY DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT core
+               ARCHIVE DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT core
+               RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT core # Windows DLLs
+               PUBLIC_HEADER DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev)
+               
+       #set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries" PARENT_SCOPE)
+set(CPACK_COMPONENT_DEV_DISPLAY_NAME "Development files" PARENT_SCOPE)
+
+
+if (UNIX OR MINGW)
+
+# figure out pkfcfg required libs here
+
+set(lws_requires "")
+if (LWS_HAVE_LIBCAP)
+       if (NOT lws_requires STREQUAL "")
+               set(lws_requires "${lws_requires},libcap")
+       else()
+               set(lws_requires "libcap")
+       endif()
+endif()
+
+
+# Generate and install pkgconfig.
+# (This is not indented, because the tabs will be part of the output)
+file(WRITE "${PROJECT_BINARY_DIR}/libwebsockets.pc"
+"prefix=\"${CMAKE_INSTALL_PREFIX}\"
+exec_prefix=\${prefix}
+libdir=\${exec_prefix}/lib${LIB_SUFFIX}
+includedir=\${prefix}/include
+
+Name: libwebsockets
+Description: Websockets server and client library
+Version: ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}
+
+Libs: -L\${libdir} -lwebsockets
+Cflags: -I\${includedir}
+"
+)
+if (NOT ${lws_requires} STREQUAL "")
+        file(APPEND "${PROJECT_BINARY_DIR}/libwebsockets.pc" "Requires: ${lws_requires}")
+endif()
+
+
+       install(FILES "${PROJECT_BINARY_DIR}/libwebsockets.pc"
+               DESTINATION lib${LIB_SUFFIX}/pkgconfig)
+
+file(WRITE "${PROJECT_BINARY_DIR}/libwebsockets_static.pc"
+"prefix=\"${CMAKE_INSTALL_PREFIX}\"
+exec_prefix=\${prefix}
+libdir=\${exec_prefix}/lib${LIB_SUFFIX}
+includedir=\${prefix}/include
+
+Name: libwebsockets_static
+Description: Websockets server and client static library
+Version: ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}
+
+Libs: -L\${libdir} -lwebsockets_static
+Libs.private:
+Cflags: -I\${includedir}
+"
+)
+
+if (NOT ${lws_requires} STREQUAL "")
+        file(APPEND "${PROJECT_BINARY_DIR}/libwebsockets_static.pc" "Requires: ${lws_requires}")
+endif()
+
+
+       install(FILES "${PROJECT_BINARY_DIR}/libwebsockets_static.pc"
+               DESTINATION lib${LIB_SUFFIX}/pkgconfig)
+
+endif(UNIX OR MINGW)
+
+
+# Keep explicit parent scope exports at end
+#
+
+export_to_parent_intermediate()
+if (DEFINED LWS_PLAT_UNIX)
+       set(LWS_PLAT_UNIX ${LWS_PLAT_UNIX} PARENT_SCOPE)
+       if (ILLUMOS)
+               add_definitions("-D__illumos__")
+       endif()
+endif()
+set(LWS_HAVE_MBEDTLS_NET_SOCKETS ${LWS_HAVE_MBEDTLS_NET_SOCKETS} PARENT_SCOPE)
+set(TEST_SERVER_SSL_KEY "${TEST_SERVER_SSL_KEY}" PARENT_SCOPE)
+set(TEST_SERVER_SSL_CERT "${TEST_SERVER_SSL_CERT}" PARENT_SCOPE)
+set(TEST_SERVER_DATA ${TEST_SERVER_DATA} PARENT_SCOPE)
+set(LWS_HAVE_PIPE2 ${LWS_HAVE_PIPE2} PARENT_SCOPE)
+set(LWS_LIBRARIES ${LWS_LIBRARIES} PARENT_SCOPE)
+if (DEFINED WIN32_HELPERS_PATH)
+       set(WIN32_HELPERS_PATH ${WIN32_HELPERS_PATH} PARENT_SCOPE)
+endif()
+if (DEFINED HDR_PRIVATE)
+set(HDR_PRIVATE ${HDR_PRIVATE} PARENT_SCOPE)
+endif()
+if (DEFINED ZLIB_FOUND)
+       set(ZLIB_FOUND ${ZLIB_FOUND} PARENT_SCOPE)
+endif()
+if (DEFINED LIB_LIST_AT_END)
+set(LIB_LIST_AT_END ${LIB_LIST_AT_END} PARENT_SCOPE)
+endif()
+set(USE_WOLFSSL ${USE_WOLFSSL} PARENT_SCOPE)
+set(LWS_DEPS_LIB_PATHS ${LWS_DEPS_LIB_PATHS} PARENT_SCOPE)
+
index 2c0c900..41ae618 100644 (file)
@@ -5,11 +5,12 @@ Code that goes in the libwebsockets library itself lives down ./lib
 Path|Sources
 ---|---
 lib/core|Core lws code related to generic fd and wsi servicing and management
+lib/core-net|Core lws code that applies only if networking enabled
 lib/event-libs|Code containing optional event-lib specific adaptations
 lib/jose|JOSE / JWS / JWK / JWE implementations
 lib/misc|Code for various mostly optional miscellaneous features
 lib/plat|Platform-specific adaptation code
 lib/roles|Code for specific optional wsi roles, eg, http/1, h2, ws, raw, etc
+lib/system|Code for system-level features, eg, dhcpclient
 lib/tls|Code supporting the various TLS libraries
-libwebsockets.h|Public API header for the whole of lws
 
diff --git a/lib/abstract/CMakeLists.txt b/lib/abstract/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3496c6e
--- /dev/null
@@ -0,0 +1,57 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       abstract/abstract.c
+)
+if (LWS_WITH_SEQUENCER)
+       list(APPEND SOURCES
+               abstract/test-sequencer.c)
+endif()
+
+list(APPEND SOURCES
+       abstract/transports/unit-test.c)
+       
+#if (LWS_WITH_SMTP)
+#      list(APPEND SOURCES
+#              abstract/protocols/smtp/smtp.c
+#              abstract/protocols/smtp/smtp-sequencer.c
+#              )
+#endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+
index 0f52869..cbf3db2 100644 (file)
@@ -1,44 +1,52 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
-#include <abstract/private.h>
+#include <private-lib-core.h>
+#include <private-lib-abstract.h>
 
 extern const lws_abs_transport_t lws_abs_transport_cli_raw_skt,
                                 lws_abs_transport_cli_unit_test;
 #if defined(LWS_WITH_SMTP)
 extern const lws_abs_protocol_t lws_abs_protocol_smtp;
 #endif
+#if defined(LWS_WITH_MQTT)
+extern const lws_abs_protocol_t lws_abs_protocol_mqttc;
+#endif
 
 static const lws_abs_transport_t * const available_abs_transports[] = {
        &lws_abs_transport_cli_raw_skt,
        &lws_abs_transport_cli_unit_test,
 };
 
-/* HACK: microsoft compiler can't handle zero length array definition */
-#if defined(LWS_WITH_SMTP)
+#if defined(LWS_WITH_ABSTRACT)
 static const lws_abs_protocol_t * const available_abs_protocols[] = {
 #if defined(LWS_WITH_SMTP)
        &lws_abs_protocol_smtp,
 #endif
+#if defined(LWS_WITH_MQTT)
+       &lws_abs_protocol_mqttc,
+#endif
 };
 #endif
 
@@ -59,7 +67,7 @@ lws_abs_transport_get_by_name(const char *name)
 const lws_abs_protocol_t *
 lws_abs_protocol_get_by_name(const char *name)
 {
-#if defined(LWS_WITH_SMTP)
+#if defined(LWS_WITH_ABSTRACT)
        int n;
 
        for (n = 0; n < (int)LWS_ARRAY_SIZE(available_abs_protocols); n++)
@@ -86,20 +94,59 @@ lws_abs_get_token(const lws_token_map_t *token_map, short name_index)
        return NULL;
 }
 
-void
-lws_abs_destroy_instance(lws_abs_t **ai)
+static int
+lws_abstract_compare_connection(lws_abs_t *abs1, lws_abs_t *abs2)
 {
-       lws_abs_t *a = *ai;
+       /* it has to be using the same protocol */
+       if (abs1->ap != abs2->ap)
+               return 1;
 
-       if (a->api)
-               a->ap->destroy(&a->api);
-       if (a->ati)
-               a->at->destroy(&a->ati);
+       /* protocol has to allow some kind of binding */
+       if (!abs1->ap->flags)
+               return 1;
 
-       lws_dll2_remove(&a->abstract_instances);
+       /* it has to be using the same transport */
+       if (abs1->at != abs2->at)
+               return 1;
 
-       *ai = NULL;
-       free(a);
+       /*
+        * The transport must feel the endpoint and conditions in use match the
+        * requested endpoint and conditions... and the transport type must be
+        * willing to allow it
+        */
+       if (abs1->at->compare(abs1, abs2))
+               return 1;
+
+       /*
+        * The protocol must feel they are in compatible modes if any
+        * (and the protocol type must be willing to allow it)
+        */
+       if (abs1->ap->compare(abs1, abs2))
+               return 1;
+
+       /*
+        * If no objection by now, we can say there's already a comparable
+        * connection and both the protocol and transport feel we can make
+        * use of it.
+        */
+
+       return 0;
+}
+
+static int
+find_compatible(struct lws_dll2 *d, void *user)
+{
+       lws_abs_t *ai1 = (lws_abs_t *)user,
+                 *ai2 = lws_container_of(d, lws_abs_t, abstract_instances);
+
+       if (!lws_abstract_compare_connection(ai1, ai2)) {
+               /* we can bind to it */
+               lws_dll2_add_tail(&ai1->bound, &ai2->children_owner);
+
+               return 1;
+       }
+
+       return 0;
 }
 
 lws_abs_t *
@@ -107,6 +154,7 @@ lws_abs_bind_and_create_instance(const lws_abs_t *abs)
 {
        size_t size = sizeof(lws_abs_t) + abs->ap->alloc + abs->at->alloc;
        lws_abs_t *ai;
+       int n;
 
        /*
         * since we know we will allocate the lws_abs_t, the protocol's
@@ -121,10 +169,27 @@ lws_abs_bind_and_create_instance(const lws_abs_t *abs)
        ai->ati = NULL;
 
        ai->api = (char *)ai + sizeof(lws_abs_t);
-       if (ai->ap->create(ai)) {
-               ai->api = NULL;
-               goto bail;
-       }
+
+       if (!ai->ap->flags) /* protocol only understands single connections */
+               goto fresh;
+
+       lws_vhost_lock(ai->vh); /* ----------------------------------- vh { */
+
+       /*
+        * Let's have a look for any already-connected transport we can use
+        */
+
+       n = lws_dll2_foreach_safe(&ai->vh->abstract_instances_owner, ai,
+                                 find_compatible);
+
+       lws_vhost_unlock(ai->vh); /* } vh --------------------------------- */
+
+       if (n)
+               goto vh_list_add;
+
+       /* there's no existing connection doing what we want */
+
+fresh:
 
        ai->ati = (char *)ai->api + abs->ap->alloc;
        if (ai->at->create(ai)) {
@@ -132,12 +197,36 @@ lws_abs_bind_and_create_instance(const lws_abs_t *abs)
                goto bail;
        }
 
+vh_list_add:
        /* add us to the vhost's dll2 of instances */
 
        lws_dll2_clear(&ai->abstract_instances);
        lws_dll2_add_head(&ai->abstract_instances,
                          &ai->vh->abstract_instances_owner);
 
+       if (ai->ap->create(ai)) {
+               ai->api = NULL;
+               goto bail;
+       }
+
+       if (ai->bound.owner) { /* we are a piggybacker */
+               lws_abs_t *ai2 = lws_container_of(ai->bound.owner, lws_abs_t,
+                                                 children_owner);
+               /*
+                * Provide an 'event' in the parent context to start handling
+                * the bind if it's otherwise idle.  We give the parent abs
+                * because we don't know if we're "next" or whatever.  Just that
+                * a child joined him and he should look into his child
+                * situation in case he was waiting for one to appear.
+                */
+               if (ai2->ap->child_bind(ai2)) {
+                       lwsl_info("%s: anticpated child bind fail\n", __func__);
+                       lws_dll2_remove(&ai->bound);
+
+                       goto bail;
+               }
+       }
+
        return ai;
 
 bail:
@@ -145,3 +234,122 @@ bail:
 
        return NULL;
 }
+
+/*
+ * We get called to clean up each child that was still bound to a parent
+ * at the time the parent is getting destroyed.
+ */
+
+static void
+__lws_abs_destroy_instance2(lws_abs_t **ai)
+{
+       lws_abs_t *a = *ai;
+
+       if (a->api)
+               a->ap->destroy(&a->api);
+       if (a->ati)
+               a->at->destroy(&a->ati);
+
+       lws_dll2_remove(&a->abstract_instances);
+
+       *ai = NULL;
+       free(a);
+}
+
+static int
+__reap_children(struct lws_dll2 *d, void *user)
+{
+       lws_abs_t *ac = lws_container_of(d, lws_abs_t, bound);
+
+       lws_dll2_foreach_safe(&ac->children_owner, NULL, __reap_children);
+
+       /* then destroy ourselves */
+
+       __lws_abs_destroy_instance2(&ac);
+
+       return 0;
+}
+
+void
+lws_abs_destroy_instance(lws_abs_t **ai)
+{
+       lws_abs_t *a = *ai;
+
+       /* destroy child instances that are bound to us first... */
+
+       lws_vhost_lock(a->vh); /* ----------------------------------- vh { */
+
+       lws_dll2_foreach_safe(&a->children_owner, NULL, __reap_children);
+
+       /* ...then destroy ourselves */
+
+       __lws_abs_destroy_instance2(ai);
+
+       lws_vhost_unlock(a->vh); /* } vh --------------------------------- */
+}
+
+lws_abs_t *
+lws_abstract_alloc(struct lws_vhost *vhost, void *user,
+                  const char *abstract_path, const lws_token_map_t *ap_tokens,
+                  const lws_token_map_t *at_tokens, struct lws_sequencer *seq,
+                  void *opaque_user_data)
+{
+       lws_abs_t *abs = lws_zalloc(sizeof(*abs), __func__);
+       struct lws_tokenize ts;
+       lws_tokenize_elem e;
+       char tmp[30];
+
+       if (!abs)
+               return NULL;
+
+       lws_tokenize_init(&ts, abstract_path, LWS_TOKENIZE_F_MINUS_NONTERM);
+
+       e = lws_tokenize(&ts);
+       if (e != LWS_TOKZE_TOKEN)
+               goto abs_path_problem;
+
+       if (lws_tokenize_cstr(&ts, tmp, sizeof(tmp)))
+               goto abs_path_problem;
+
+       abs->ap = lws_abs_protocol_get_by_name(tmp);
+       if (!abs->ap)
+               goto abs_path_problem;
+
+       e = lws_tokenize(&ts);
+       if (e != LWS_TOKZE_DELIMITER)
+               goto abs_path_problem;
+
+       e = lws_tokenize(&ts);
+       if (e != LWS_TOKZE_TOKEN)
+               goto abs_path_problem;
+
+       if (lws_tokenize_cstr(&ts, tmp, sizeof(tmp)))
+               goto abs_path_problem;
+
+       abs->at = lws_abs_transport_get_by_name(tmp);
+       if (!abs->at)
+               goto abs_path_problem;
+
+       abs->vh = vhost;
+       abs->ap_tokens = ap_tokens;
+       abs->at_tokens = at_tokens;
+       abs->seq = seq;
+       abs->opaque_user_data = opaque_user_data;
+
+       lwsl_info("%s: allocated %s\n", __func__, abstract_path);
+
+       return abs;
+
+abs_path_problem:
+       lwsl_err("%s: bad abs path '%s'\n", __func__, abstract_path);
+       lws_free_set_NULL(abs);
+
+       return NULL;
+}
+
+void
+lws_abstract_free(lws_abs_t **pabs)
+{
+       if (*pabs)
+               lws_free_set_NULL(*pabs);
+}
diff --git a/lib/abstract/private-lib-abstract.h b/lib/abstract/private-lib-abstract.h
new file mode 100644 (file)
index 0000000..0204b50
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(__PRIVATE_LIB_ABSTRACT_H__)
+#define __PRIVATE_LIB_ABSTRACT_H__
+
+typedef struct lws_token_map lws_token_map_t;
+typedef void lws_abs_transport_inst_t;
+typedef void lws_abs_protocol_inst_t;
+
+typedef struct lws_abs {
+       void                            *user;
+       struct lws_vhost                *vh;
+
+       const struct lws_abs_protocol   *ap;
+       const lws_token_map_t           *ap_tokens;
+       const struct lws_abs_transport  *at;
+       const lws_token_map_t           *at_tokens;
+
+       struct lws_sequencer            *seq;
+       void                            *opaque_user_data;
+
+       /* vh lock */
+       struct lws_dll2_owner           children_owner; /* our children / queue */
+       /* vh lock */
+       struct lws_dll2                 bound; /* parent or encapsulator */
+       /* vh lock */
+       struct lws_dll2                 abstract_instances;
+       lws_abs_transport_inst_t        *ati;
+       lws_abs_protocol_inst_t         *api;
+} lws_abs_t;
+
+#endif
+
diff --git a/lib/abstract/private.h b/lib/abstract/private.h
deleted file mode 100644 (file)
index a9b1ca2..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-
-
-
diff --git a/lib/abstract/protocols/smtp/private-lib-abstract-protocols-smtp.h b/lib/abstract/protocols/smtp/private-lib-abstract-protocols-smtp.h
new file mode 100644 (file)
index 0000000..0498e08
--- /dev/null
@@ -0,0 +1,24 @@
+#define LWS_SMTP_MAX_EMAIL_LEN 32
+
+
+/*
+ * These are allocated on to the heap with an over-allocation to hold the
+ * payload at the end
+ */
+
+typedef struct lws_smtp_email {
+       struct lws_dll2 list;
+       void            *data;
+
+       char            from[LWS_SMTP_MAX_EMAIL_LEN];
+       char            to[LWS_SMTP_MAX_EMAIL_LEN];
+
+       time_t          added;
+       time_t          last_try;
+
+       lws_smtp_cb_t   done;
+
+       int             tries;
+
+       /* email payload follows */
+} lws_smtp_email_t;
diff --git a/lib/abstract/protocols/smtp/smtp-sequencer.c b/lib/abstract/protocols/smtp/smtp-sequencer.c
new file mode 100644 (file)
index 0000000..24d8f44
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Abstract SMTP support for libwebsockets - SMTP sequencer
+ *
+ * Copyright (C) 2016-2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This sequencer sits above the abstract protocol, and manages queueing,
+ * retrying mail transmission, and retry limits.
+ *
+ * Having the sequencer means that, eg, we can manage retries after complete
+ * connection failure.
+ *
+ * Connections to the smtp server are serialized
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-abstract-protocols-smtp.h"
+
+typedef enum {
+       LSMTPSS_DISCONNECTED,
+       LSMTPSS_CONNECTING,
+       LSMTPSS_CONNECTED,
+       LSMTPSS_BUSY,
+} smtpss_connstate_t;
+
+typedef struct lws_smtp_sequencer {
+       struct lws_dll2_owner           emails_owner; /* email queue */
+
+       lws_abs_t                       *abs, *instance;
+       lws_smtp_sequencer_args_t       args;
+       struct lws_sequencer            *seq;
+
+       smtpss_connstate_t              connstate;
+
+       time_t                          email_connect_started;
+
+       /* holds the HELO for the smtp protocol to consume */
+       lws_token_map_t                 apt[3];
+} lws_smtp_sequencer_t;
+
+/* sequencer messages specific to this sequencer */
+
+enum {
+       SEQ_MSG_CLIENT_FAILED = LWSSEQ_USER_BASE,
+       SEQ_MSG_CLIENT_DONE,
+};
+
+/*
+ * We're going to bind to the raw-skt transport, so tell that what we want it
+ * to connect to
+ */
+
+static const lws_token_map_t smtp_rs_transport_tokens[] = {
+ {
+       .u = { .value = "127.0.0.1" },
+       .name_index = LTMI_PEER_V_DNS_ADDRESS,
+ }, {
+       .u = { .lvalue = 25 },
+       .name_index = LTMI_PEER_LV_PORT,
+ }, {
+ }
+};
+
+static void
+lws_smtpc_kick_internal(lws_smtp_sequencer_t *s)
+{
+       lws_smtp_email_t *e;
+       lws_dll2_t *d;
+       char buf[64];
+       int n;
+       lws_dll2_t *pd2;
+
+       pd2 = lws_dll2_get_head(&s->emails_owner);
+       if (!pd2)
+               return;
+
+       e = lws_container_of(pd2, lws_smtp_email_t, list);
+       if (!e)
+               return;
+
+       /* Is there something to do?  If so, we need a connection... */
+
+       if (s->connstate == LSMTPSS_DISCONNECTED) {
+
+               s->apt[0].u.value = s->args.helo;
+               s->apt[0].name_index = LTMI_PSMTP_V_HELO;
+               s->apt[1].u.value = (void *)e;
+               s->apt[1].name_index = LTMI_PSMTP_V_LWS_SMTP_EMAIL_T;
+
+               /*
+                * create and connect the smtp protocol + transport
+                */
+
+               s->abs = lws_abstract_alloc(s->args.vhost, NULL, "smtp.raw_skt",
+                                           s->apt, smtp_rs_transport_tokens,
+                                           s->seq, NULL);
+               if (!s->abs)
+                       return;
+
+               s->instance = lws_abs_bind_and_create_instance(s->abs);
+               if (!s->instance) {
+                       lws_abstract_free(&s->abs);
+                       lwsl_err("%s: failed to create SMTP client\n", __func__);
+
+                       goto bail1;
+               }
+
+               s->connstate = LSMTPSS_CONNECTING;
+               lws_seq_timeout_us(s->seq, 10 * LWS_USEC_PER_SEC);
+               return;
+       }
+
+       /* ask the transport if we have a connection to the server ongoing */
+
+       if (s->abs->at->state(s->abs->ati)) {
+               /*
+                * there's a connection, it could be still trying to connect
+                * or established
+                */
+               s->abs->at->ask_for_writeable(s->abs->ati);
+
+               return;
+       }
+
+       /* there's no existing connection */
+
+       lws_smtpc_state_transition(c, LGSSMTP_CONNECTING);
+
+       if (s->abs->at->client_conn(s->abs)) {
+               lwsl_err("%s: failed to connect\n", __func__);
+
+               return;
+       }
+
+       e->tries++;
+       e->last_try = lws_now_secs();
+}
+
+
+/*
+ * The callback we get from the smtp protocol... we use this to drive
+ * decisions about destroy email, retry and fail.
+ *
+ * Sequencer will handle it via the event loop.
+ */
+
+static int
+email_result(void *e, void *d, int disp, void *b, size_t l)
+{
+       lws_smtp_sequencer_t *s = (lws_smtp_sequencer_t *)d;
+
+       lws_sequencer_event(s->seq, LWSSEQ_USER_BASE + disp, e);
+
+       return 0;
+}
+
+static int
+cleanup(struct lws_dll2 *d, void *user)
+{
+       lws_smtp_email_t *e;
+
+       e = lws_container_of(d, lws_smtp_email_t, list);
+       if (e->done)
+               e->done(e, "destroying", 10);
+
+       lws_dll2_remove(d);
+       lws_free(e);
+
+       return 0;
+}
+
+static lws_seq_cb_return_t
+smtp_sequencer_cb(struct lws_sequencer *seq, void *user, int event, void *data)
+{
+       struct lws_smtp_sequencer_t *s = (struct lws_smtp_sequencer_t *)user;
+
+       switch ((int)event) {
+       case LWSSEQ_CREATED: /* our sequencer just got started */
+               lwsl_notice("%s: %s: created\n", __func__,
+                           lws_sequencer_name(seq));
+               s->connstate = LSMTPSS_DISCONNECTED;
+               s->state = 0;  /* first thing we'll do is the first url */
+               goto step;
+
+       case LWSSEQ_DESTROYED:
+               lws_dll2_foreach_safe(&s->pending_owner, NULL, cleanup);
+               break;
+
+       case LWSSEQ_TIMED_OUT:
+               lwsl_notice("%s: LWSSEQ_TIMED_OUT\n", __func__);
+               break;
+
+       case LWSSEQ_USER_BASE + LWS_SMTP_DISPOSITION_SENT:
+               lws_smtpc_free_email(data);
+               break;
+
+       case LWSSEQ_WSI_CONNECTED:
+               s->connstate = LSMTPSS_CONNECTED;
+               lws_smtpc_kick_internal(s);
+               break;
+
+       case LWSSEQ_WSI_CONN_FAIL:
+       case LWSSEQ_WSI_CONN_CLOSE:
+               s->connstate = LSMTPSS_DISCONNECTED;
+               lws_smtpc_kick_internal(s);
+               break;
+
+       case SEQ_MSG_SENT:
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSEQ_RET_CONTINUE;
+}
+
+/*
+ * Creates an lws_sequencer to manage the test sequence
+ */
+
+lws_smtp_sequencer_t *
+lws_smtp_sequencer_create(const lws_smtp_sequencer_args_t *args)
+{
+       lws_smtp_sequencer_t *s;
+       struct lws_sequencer *seq;
+
+       /*
+        * Create a sequencer in the event loop to manage the SMTP queue
+        */
+
+       seq = lws_sequencer_create(args->vhost->context, 0,
+                                  sizeof(lws_smtp_sequencer_t), (void **)&s,
+                                  smtp_sequencer_cb, "smtp-seq");
+       if (!seq) {
+               lwsl_err("%s: unable to create sequencer\n", __func__);
+               return NULL;
+       }
+
+       s->abs = *args->abs;
+       s->args = *args;
+       s->seq = seq;
+
+       /* set defaults in our copy of the args */
+
+       if (!s->args.helo[0])
+               strcpy(s->args.helo, "default-helo");
+       if (!s->args.email_queue_max)
+               s->args.email_queue_max = 8;
+       if (!s->args.retry_interval)
+               s->args.retry_interval = 15 * 60;
+       if (!s->args.delivery_timeout)
+               s->args.delivery_timeout = 12 * 60 * 60;
+
+       return s;
+}
+
+void
+lws_smtp_sequencer_destroy(lws_smtp_sequencer_t *s)
+{
+       /* sequencer destruction destroys all assets */
+       lws_sequencer_destroy(&s->seq);
+}
+
+int
+lws_smtpc_add_email(lws_smtp_sequencer_t *s, const char *payload,
+                   size_t payload_len, const char *sender,
+                   const char *recipient, void *data, lws_smtp_cb_t done)
+{
+       lws_smtp_email_t *e;
+
+       if (s->emails_owner.count > s->args.email_queue_max) {
+               lwsl_err("%s: email queue at limit of %d\n", __func__,
+                        (int)s->args.email_queue_max);
+
+               return 1;
+       }
+
+       if (!done)
+               return 1;
+
+       e = malloc(sizeof(*e) + payload_len + 1);
+       if (!e)
+               return 1;
+
+       memset(e, 0, sizeof(*e));
+
+       e->data = data;
+       e->done = done;
+
+       lws_strncpy(e->from, sender, sizeof(e->from));
+       lws_strncpy(e->to, recipient, sizeof(e->to));
+
+       memcpy((char *)&e[1], payload, payload_len + 1);
+
+       e->added = lws_now_secs();
+       e->last_try = 0;
+       e->tries = 0;
+
+       lws_dll2_clear(&e->list);
+       lws_dll2_add_tail(&e->list, &s->emails_owner);
+
+       lws_smtpc_kick_internal(s);
+
+       return 0;
+}
index 668ab19..e0a9555 100644 (file)
@@ -1,59 +1,65 @@
 /*
- * Abstract SMTP support for libwebsockets
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2016-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- * This library 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.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- * You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-#include "abstract/private.h"
+#include "private-lib-core.h"
+#include "private-lib-abstract.h"
 
 /** enum lwsgs_smtp_states - where we are in SMTP protocol sequence */
 typedef enum lwsgs_smtp_states {
        LGSSMTP_IDLE,           /**< awaiting new email */
        LGSSMTP_CONNECTING,     /**< opening tcp connection to MTA */
        LGSSMTP_CONNECTED,      /**< tcp connection to MTA is connected */
+               /* (server sends greeting) */
        LGSSMTP_SENT_HELO,      /**< sent the HELO */
+
        LGSSMTP_SENT_FROM,      /**< sent FROM */
        LGSSMTP_SENT_TO,        /**< sent TO */
        LGSSMTP_SENT_DATA,      /**< sent DATA request */
        LGSSMTP_SENT_BODY,      /**< sent the email body */
-       LGSSMTP_SENT_QUIT,      /**< sent the session quit */
-} lwsgs_smtp_states_t;
 
-/** struct lws_email - abstract context for performing SMTP operations */
-typedef struct lws_smtp_client {
-       struct lws_dll2_owner pending_owner;
+               /*
+                * (server sends, eg, "250 Ok: queued as 12345")
+                * at this point we can return to LGSSMTP_SENT_HELO and send a
+                * new email, or continue below to QUIT, or just wait
+                */
 
-       const struct lws_abs *abs;
+       LGSSMTP_SENT_QUIT,      /**< sent the session quit */
 
-       const char *helo;
+       /* (server sends, eg, "221 Bye" and closes the connection) */
+} lwsgs_smtp_states_t;
 
-       lwsgs_smtp_states_t estate;
-       time_t email_connect_started;
+/** abstract protocol instance data */
 
-       time_t retry_interval;
-       time_t delivery_timeout;
+typedef struct lws_smtp_client_protocol {
+       const struct lws_abs    *abs;
+       lwsgs_smtp_states_t     estate;
 
-       size_t email_queue_max;
-       size_t max_content_size;
+       lws_smtp_email_t        *e;     /* the email we are trying to send */
+       const char              *helo;
 
-       unsigned char send_pending:1;
-} lws_smtp_client_t;
+       unsigned char           send_pending:1;
+} lws_smtpcp_t;
 
 static const short retcodes[] = {
        0,      /* idle */
@@ -68,80 +74,71 @@ static const short retcodes[] = {
 };
 
 static void
-lws_smtp_client_state_transition(lws_smtp_client_t *c, lwsgs_smtp_states_t s)
+lws_smtpc_state_transition(lws_smtpcp_t *c, lwsgs_smtp_states_t s)
 {
        lwsl_debug("%s: cli %p: state %d -> %d\n", __func__, c, c->estate, s);
        c->estate = s;
 }
 
-static void
-lws_smtp_client_kick_internal(lws_smtp_client_t *c)
+static lws_smtp_email_t *
+lws_smtpc_get_email(lws_smtpcp_t *c)
 {
-       lws_smtp_email_t *e;
-       lws_dll2_t *d;
-       char buf[64];
-       int n;
-
-       if (c->estate != LGSSMTP_IDLE)
-               return;
-
-       /* is there something to do? */
-
-again:
-       d = lws_dll2_get_head(&c->pending_owner);
-       if (!d)
-               return;
+       const lws_token_map_t *tm;
 
-       e = lws_container_of(d, lws_smtp_email_t, list);
+       /* ... the email we want to send */
+       tm = lws_abs_get_token(c->abs->ap_tokens, LTMI_PSMTP_V_LWS_SMTP_EMAIL_T);
+       if (!tm) {
+               assert(0);
 
-       /* do we need to time out this guy? */
+               return NULL;
+       }
 
-       if ((time_t)lws_now_secs() - e->added > (time_t)c->delivery_timeout) {
-               lwsl_err("%s: timing out email\n", __func__);
-               lws_dll2_remove(&e->list);
-               n = lws_snprintf(buf, sizeof(buf), "0 Timed out retrying send");
-               e->done(e, buf, n);
+       return (lws_smtp_email_t *)tm->u.value;
+}
 
-               if (lws_dll2_get_head(&c->pending_owner))
-                       goto again;
+/*
+ * Called when something happened so that we know now the final disposition of
+ * the email send attempt, for good or ill.
+ *
+ * Inform the owner via the done callback and set up the next queued one if any.
+ *
+ * Returns nonzero if we queued a new one
+ */
 
-               return;
-       }
+static int
+lws_smtpc_email_disposition(lws_smtpcp_t *c, int disp, const void *buf,
+                           size_t len)
+{
+       lws_smtpcp_t *ch;
+       lws_abs_t *ach;
+       lws_dll2_t *d;
 
-       /* is it time for his retry yet? */
+       lws_smtpc_state_transition(c, LGSSMTP_SENT_HELO);
 
-       if (e->last_try &&
-           (time_t)lws_now_secs() - e->last_try < (time_t)c->retry_interval) {
-               /* no... send him to the tail */
-               lws_dll2_remove(&e->list);
-               lws_dll2_add_tail(&e->list, &c->pending_owner);
-               return;
-       }
+       /* lifetime of the email object is handled by done callback */
+       c->e->done(c->e, c->e->data, disp, buf, len);
+       c->e = NULL;
 
-       /* ask the transport if we have a connection to the server ongoing */
+       /* this may not be the time to try to send anything else... */
 
-       if (c->abs->at->state(c->abs->ati)) {
-               /*
-                * there's a connection, it could be still trying to connect
-                * or established
-                */
-               c->abs->at->ask_for_writeable(c->abs->ati);
+       if (disp == LWS_SMTP_DISPOSITION_FAILED_DESTROY)
+               return 0;
 
-               return;
-       }
+       /* ... otherwise... do we have another queued? */
 
-       /* there's no existing connection */
+       d = lws_dll2_get_tail(&c->abs->children_owner);
+       if (!d)
+               return 0;
 
-       lws_smtp_client_state_transition(c, LGSSMTP_CONNECTING);
+       ach = lws_container_of(d, lws_abs_t, bound);
+       ch = (lws_smtpcp_t *)ach->api;
 
-       if (c->abs->at->client_conn(c->abs)) {
-               lwsl_err("%s: failed to connect\n", __func__);
+       c->e = lws_smtpc_get_email(ch);
 
-               return;
-       }
+       /* since we took it on, remove it from the queue */
+       lws_dll2_remove(d);
 
-       e->tries++;
-       e->last_try = lws_now_secs();
+       return 1;
 }
 
 /*
@@ -149,53 +146,85 @@ again:
  */
 
 static int
-lws_smtp_client_abs_accept(lws_abs_protocol_inst_t *api)
+lws_smtpc_abs_accept(lws_abs_protocol_inst_t *api)
 {
-       lws_smtp_client_t *c = (lws_smtp_client_t *)api;
+       lws_smtpcp_t *c = (lws_smtpcp_t *)api;
+
+       /* we have become connected in the tcp sense */
+
+       lws_smtpc_state_transition(c, LGSSMTP_CONNECTED);
+
+       /*
+        * From the accept(), the next thing that should happen is the SMTP
+        * server sends its greeting like "220 smtp2.example.com ESMTP Postfix",
+        * we'll hear about it in the rx callback, or time out
+        */
 
-       lws_smtp_client_state_transition(c, LGSSMTP_CONNECTED);
+       c->abs->at->set_timeout(c->abs->ati,
+                               PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, 3);
 
        return 0;
 }
 
 static int
-lws_smtp_client_abs_rx(lws_abs_protocol_inst_t *api, uint8_t *buf, size_t len)
+lws_smtpc_abs_rx(lws_abs_protocol_inst_t *api, const uint8_t *buf, size_t len)
 {
-       lws_smtp_client_t *c = (lws_smtp_client_t *)api;
-       lws_smtp_email_t *e;
-       lws_dll2_t *pd2;
+       lws_smtpcp_t *c = (lws_smtpcp_t *)api;
+       char dotstar[96], at[5];
        int n;
 
-       pd2 = lws_dll2_get_head(&c->pending_owner);
-       if (!pd2)
-               return 0;
+       c->abs->at->set_timeout(c->abs->ati, NO_PENDING_TIMEOUT, 0);
 
-       e = lws_container_of(pd2, lws_smtp_email_t, list);
-       if (!e)
-               return 0;
+       lws_strncpy(at, (const char *)buf, sizeof(at));
+       n = atoi(at);
 
-       n = atoi((char *)buf);
-       if (n != retcodes[c->estate]) {
-               lwsl_notice("%s: bad response from server: %d (state %d) %.*s\n",
-                               __func__, n, c->estate, (int)len, buf);
+       switch (c->estate) {
+       case LGSSMTP_CONNECTED:
+               if (n != 220) {
+                       /*
+                        * The server did not properly greet us... we can't
+                        * even get started, so fail the transport connection
+                        * (and anything queued on it)
+                        */
 
-               lws_dll2_remove(&e->list);
-               lws_dll2_add_tail(&e->list, &c->pending_owner);
-               lws_smtp_client_state_transition(c, LGSSMTP_IDLE);
-               lws_smtp_client_kick_internal(c);
+                       lws_strnncpy(dotstar, (const char *)buf, len, sizeof(dotstar));
+                       lwsl_err("%s: server: %s\n", __func__, dotstar);
 
-               return 0;
-       }
+                       return 1;
+               }
+               break;
 
-       if (c->estate == LGSSMTP_SENT_QUIT) {
-               lwsl_debug("%s: done\n", __func__);
-               lws_smtp_client_state_transition(c, LGSSMTP_IDLE);
+       case LGSSMTP_SENT_BODY:
+               /*
+                * We finished one way or another... let's prepare to send a
+                * new one... or wait until server hangs up on us
+                */
+               if (!lws_smtpc_email_disposition(c,
+                                       n == 250 ? LWS_SMTP_DISPOSITION_SENT :
+                                                  LWS_SMTP_DISPOSITION_FAILED,
+                                       "destroyed", 0))
+                       return 0; /* become idle */
 
-               lws_dll2_remove(&e->list);
-               if (e->done && e->done(e, "sent OK", 7))
-                       return 1;
+               break; /* ask to send */
+
+       case LGSSMTP_SENT_QUIT:
+               lwsl_debug("%s: done\n", __func__);
+               lws_smtpc_state_transition(c, LGSSMTP_IDLE);
 
                return 1;
+
+       default:
+               if (n != retcodes[c->estate]) {
+                       lws_strnncpy(dotstar, buf, len, sizeof(dotstar));
+                       lwsl_notice("%s: bad response: %d (state %d) %s\n",
+                                   __func__, n, c->estate, dotstar);
+
+                       lws_smtpc_email_disposition(c,
+                                       LWS_SMTP_DISPOSITION_FAILED, buf, len);
+
+                       return 0;
+               }
+               break;
        }
 
        c->send_pending = 1;
@@ -205,24 +234,13 @@ lws_smtp_client_abs_rx(lws_abs_protocol_inst_t *api, uint8_t *buf, size_t len)
 }
 
 static int
-lws_smtp_client_abs_writeable(lws_abs_protocol_inst_t *api, size_t budget)
+lws_smtpc_abs_writeable(lws_abs_protocol_inst_t *api, size_t budget)
 {
-       lws_smtp_client_t *c = (lws_smtp_client_t *)api;
        char b[256 + LWS_PRE], *p = b + LWS_PRE;
-       lws_smtp_email_t *e;
-       lws_dll2_t *pd2;
+       lws_smtpcp_t *c = (lws_smtpcp_t *)api;
        int n;
 
-       pd2 = lws_dll2_get_head(&c->pending_owner);
-       if (!pd2)
-               return 0;
-
-       e = lws_container_of(pd2, lws_smtp_email_t, list);
-       if (!e)
-               return 0;
-
-
-       if (!c->send_pending)
+       if (!c->send_pending || !c->e)
                return 0;
 
        c->send_pending = 0;
@@ -232,31 +250,37 @@ lws_smtp_client_abs_writeable(lws_abs_protocol_inst_t *api, size_t budget)
        switch (c->estate) {
        case LGSSMTP_CONNECTED:
                n = lws_snprintf(p, sizeof(b) - LWS_PRE, "HELO %s\n", c->helo);
-               lws_smtp_client_state_transition(c, LGSSMTP_SENT_HELO);
+               lws_smtpc_state_transition(c, LGSSMTP_SENT_HELO);
                break;
+
        case LGSSMTP_SENT_HELO:
                n = lws_snprintf(p, sizeof(b) - LWS_PRE, "MAIL FROM: <%s>\n",
-                                e->email_from);
-               lws_smtp_client_state_transition(c, LGSSMTP_SENT_FROM);
+                                c->e->from);
+               lws_smtpc_state_transition(c, LGSSMTP_SENT_FROM);
                break;
+
        case LGSSMTP_SENT_FROM:
                n = lws_snprintf(p, sizeof(b) - LWS_PRE,
-                                "RCPT TO: <%s>\n", e->email_to);
-               lws_smtp_client_state_transition(c, LGSSMTP_SENT_TO);
+                                "RCPT TO: <%s>\n", c->e->to);
+               lws_smtpc_state_transition(c, LGSSMTP_SENT_TO);
                break;
+
        case LGSSMTP_SENT_TO:
                n = lws_snprintf(p, sizeof(b) - LWS_PRE, "DATA\n");
-               lws_smtp_client_state_transition(c, LGSSMTP_SENT_DATA);
+               lws_smtpc_state_transition(c, LGSSMTP_SENT_DATA);
                break;
+
        case LGSSMTP_SENT_DATA:
-               p = (char *)e->payload;
-               n = strlen(e->payload);
-               lws_smtp_client_state_transition(c, LGSSMTP_SENT_BODY);
+               p = (char *)&c->e[1];
+               n = strlen(p);
+               lws_smtpc_state_transition(c, LGSSMTP_SENT_BODY);
                break;
+
        case LGSSMTP_SENT_BODY:
                n = lws_snprintf(p, sizeof(b) - LWS_PRE, "quit\n");
-               lws_smtp_client_state_transition(c, LGSSMTP_SENT_QUIT);
+               lws_smtpc_state_transition(c, LGSSMTP_SENT_QUIT);
                break;
+
        case LGSSMTP_SENT_QUIT:
                return 0;
 
@@ -271,179 +295,88 @@ lws_smtp_client_abs_writeable(lws_abs_protocol_inst_t *api, size_t budget)
 }
 
 static int
-lws_smtp_client_abs_closed(lws_abs_protocol_inst_t *api)
+lws_smtpc_abs_closed(lws_abs_protocol_inst_t *api)
 {
-       lws_smtp_client_t *c = (lws_smtp_client_t *)api;
+       lws_smtpcp_t *c = (lws_smtpcp_t *)api;
 
        if (c)
-               lws_smtp_client_state_transition(c, LGSSMTP_IDLE);
+               lws_smtpc_state_transition(c, LGSSMTP_IDLE);
 
        return 0;
 }
 
-static int
-lws_smtp_client_abs_heartbeat(lws_abs_protocol_inst_t *api)
-{
-       lws_smtp_client_t *c = (lws_smtp_client_t *)api;
-
-       lws_smtp_client_kick_internal(c);
-
-       return 0;
-}
+/*
+ * Creating for initial transport and for piggybacking on another transport
+ * both get created here the same.  But piggybackers have ai->bound attached.
+ */
 
-lws_smtp_email_t *
-lws_smtp_client_alloc_email_helper(const char *payload, size_t payload_len,
-                                  const char *sender, const char *recipient,
-                                  const char *extra, size_t extra_len, void *data,
-                                  int (*done)(struct lws_smtp_email *e,
-                                              void *buf, size_t len))
+static int
+lws_smtpc_create(const lws_abs_t *ai)
 {
-       size_t ls = strlen(sender), lr = strlen(recipient);
-       lws_smtp_email_t *em;
-       char *p;
+       lws_smtpcp_t *c = (lws_smtpcp_t *)ai->api;
 
-       em = malloc(sizeof(*em) + payload_len + ls + lr + extra_len + 4);
-       if (!em) {
-               lwsl_err("OOM\n");
-               return NULL;
-       }
-
-       p = (char *)&em[1];
-
-       memset(em, 0, sizeof(*em));
+       memset(c, 0, sizeof(*c));
 
-       em->data = data;
-       em->done = done;
+       c->abs = ai;
+       c->e = lws_smtpc_get_email(c);
 
-       em->email_from = p;
-       memcpy(p, sender, ls + 1);
-       p += ls + 1;
-       em->email_to = p;
-       memcpy(p, recipient, lr + 1);
-       p += lr + 1;
-       em->payload = p;
-       memcpy(p, payload, payload_len + 1);
-       p += payload_len + 1;
+       lws_smtpc_state_transition(c, lws_dll2_is_detached(&ai->bound) ?
+                                       LGSSMTP_CONNECTING : LGSSMTP_IDLE);
 
-       if (extra) {
-               em->extra = p;
-               memcpy(p, extra, extra_len + 1);
-       }
+       /* If we are initiating the transport, we will get an accept() next...
+        *
+        * If we are piggybacking, the parent will get a .child_bind() after
+        * this to give it a chance to act on us joining (eg, it was completely
+        * idle and we joined).
+        */
 
-       return em;
+       return 0;
 }
 
-int
-lws_smtp_client_add_email(lws_abs_t *instance, lws_smtp_email_t *e)
+static void
+lws_smtpc_destroy(lws_abs_protocol_inst_t **_c)
 {
-       lws_smtp_client_t *c = (lws_smtp_client_t *)instance->api;
+       lws_smtpcp_t *c = (lws_smtpcp_t *)*_c;
 
-       if (c->pending_owner.count > c->email_queue_max) {
-               lwsl_err("%s: email queue at limit of %d\n", __func__,
-                               (int)c->email_queue_max);
-
-               return 1;
-       }
-
-       e->added = lws_now_secs();
-       e->last_try = 0;
-       e->tries = 0;
-
-       lws_dll2_clear(&e->list);
-       lws_dll2_add_tail(&e->list, &c->pending_owner);
+       if (!c)
+               return;
 
-       lws_smtp_client_kick_internal(c);
+       /* so if we are still holding on to c->e, we have failed to send it */
+       if (c->e)
+               lws_smtpc_email_disposition(c,
+                       LWS_SMTP_DISPOSITION_FAILED_DESTROY, "destroyed", 0);
 
-       return 0;
+       *_c = NULL;
 }
 
-void
-lws_smtp_client_kick(lws_abs_t *instance)
-{
-       lws_smtp_client_t *c = (lws_smtp_client_t *)instance->api;
-
-       lws_smtp_client_kick_internal(c);
-}
 static int
-lws_smtp_client_create(const lws_abs_t *ai)
+lws_smtpc_compare(lws_abs_t *abs1, lws_abs_t *abs2)
 {
-       lws_smtp_client_t *c = (lws_smtp_client_t *)ai->api;
-       const lws_token_map_t *tm;
-
-       memset(c, 0, sizeof(*c));
-
-       c->abs = ai;
-
-       tm = lws_abs_get_token(ai->ap_tokens, LTMI_PSMTP_V_HELO);
-       if (!tm) {
-               lwsl_err("%s: LTMI_PSMTP_V_HELO is required\n", __func__);
-
-               return 1;
-       }
-       c->helo = tm->u.value;
-
-       c->email_queue_max      = 8;
-       c->retry_interval       = 15 * 60;
-       c->delivery_timeout     = 12 * 60 * 60;
-
-       tm = lws_abs_get_token(ai->ap_tokens, LTMI_PSMTP_LV_EMAIL_QUEUE_MAX);
-       if (tm)
-               c->email_queue_max = tm->u.lvalue;
-       tm = lws_abs_get_token(ai->ap_tokens, LTMI_PSMTP_LV_RETRY_INTERVAL);
-       if (tm)
-               c->retry_interval = tm->u.lvalue;
-       tm = lws_abs_get_token(ai->ap_tokens, LTMI_PSMTP_LV_DELIVERY_TIMEOUT);
-       if (tm)
-               c->delivery_timeout = tm->u.lvalue;
-
-       lws_smtp_client_state_transition(c, LGSSMTP_IDLE);
-
        return 0;
 }
 
 static int
-cleanup(struct lws_dll2 *d, void *user)
+lws_smtpc_child_bind(lws_abs_t *abs)
 {
-       lws_smtp_email_t *e;
-
-       e = lws_container_of(d, lws_smtp_email_t, list);
-       if (e->done && e->done(e, "destroying", 10))
-               return 1;
-
        return 0;
 }
 
-static void
-lws_smtp_client_destroy(lws_abs_protocol_inst_t **_c)
-{
-       lws_smtp_client_t *c = (lws_smtp_client_t *)*_c;
-
-       if (!c)
-               return;
-
-       lws_dll2_foreach_safe(&c->pending_owner, NULL, cleanup);
-
-       /*
-        * We don't free anything because the abstract layer combined our
-        * allocation with that of the instance, and it will free the whole
-        * thing after this.
-        */
-
-       *_c = NULL;
-}
-
 /* events the transport invokes (handled by abstract protocol) */
 
 const lws_abs_protocol_t lws_abs_protocol_smtp = {
        .name           = "smtp",
-       .alloc          = sizeof(lws_smtp_client_t),
+       .alloc          = sizeof(lws_smtpcp_t),
+       .flags          = LWSABSPR_FLAG_PIPELINE,
+
+       .create         = lws_smtpc_create,
+       .destroy        = lws_smtpc_destroy,
+       .compare        = lws_smtpc_compare,
 
-       .create         = lws_smtp_client_create,
-       .destroy        = lws_smtp_client_destroy,
+       .accept         = lws_smtpc_abs_accept,
+       .rx             = lws_smtpc_abs_rx,
+       .writeable      = lws_smtpc_abs_writeable,
+       .closed         = lws_smtpc_abs_closed,
+       .heartbeat      = NULL,
 
-       .accept         = lws_smtp_client_abs_accept,
-       .rx             = lws_smtp_client_abs_rx,
-       .writeable      = lws_smtp_client_abs_writeable,
-       .closed         = lws_smtp_client_abs_closed,
-       .heartbeat      = lws_smtp_client_abs_heartbeat,
+       .child_bind     = lws_smtpc_child_bind,
 };
index 2872aef..c4fa677 100644 (file)
@@ -1,23 +1,25 @@
-/*
- * libwebsockets lib/abstract/test-sequencer.c
- *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * A helper for running multiple unit tests against abstract protocols.
  *
@@ -26,7 +28,7 @@
  * for each test using te
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 struct lws_seq_test_sequencer {
        lws_abs_t                       original_abs;
@@ -35,7 +37,7 @@ struct lws_seq_test_sequencer {
 
        struct lws_context              *context;
        struct lws_vhost                *vhost;
-       lws_seq_t                       *unit_test_seq;
+       struct lws_sequencer            *unit_test_seq;
 
        /* holds the per-test token for the unit-test transport to consume */
        lws_token_map_t                 uttt[4];
@@ -233,7 +235,7 @@ int
 lws_abs_unit_test_sequencer(const lws_test_sequencer_args_t *args)
 {
        struct lws_seq_test_sequencer *s;
-       lws_seq_t *seq;
+       struct lws_sequencer *seq;
        lws_seq_info_t i;
 
        memset(&i, 0, sizeof(i));
index 74f08ab..fec2db7 100644 (file)
@@ -1,26 +1,29 @@
 /*
- * libwebsockets lib/abstract/transports/raw-skt.c
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-#include "abstract/private.h"
+#include "private-lib-core.h"
+#include "private-lib-abstract.h"
 
 typedef struct lws_abstxp_raw_skt_priv {
        struct lws_abs *abs;
@@ -210,7 +213,7 @@ lws_atcrs_tx(lws_abs_transport_inst_t *ati, uint8_t *buf, size_t len)
        return 0;
 }
 
-#if !defined(LWS_WITHOUT_CLIENT)
+#if defined(LWS_WITH_CLIENT)
 static int
 lws_atcrs_client_conn(const lws_abs_t *abs)
 {
@@ -270,6 +273,16 @@ lws_atcrs_client_conn(const lws_abs_t *abs)
        i.seq = abs->seq;
        i.opaque_user_data = abs->opaque_user_data;
 
+       /*
+        * the protocol itself has some natural attributes we should pass on
+        */
+
+       if (abs->ap->flags & LWS_AP_FLAG_PIPELINE_TRANSACTIONS)
+               i.ssl_connection |= LCCSCF_PIPELINE;
+
+       if (abs->ap->flags & LWS_AP_FLAG_MUXABLE_STREAM)
+               i.ssl_connection |= LCCSCF_MUXABLE_STREAM;
+
        priv->wsi = lws_client_connect_via_info(&i);
        if (!priv->wsi)
                return 1;
@@ -308,9 +321,9 @@ static void
 lws_atcrs_destroy(lws_abs_transport_inst_t **pati)
 {
        /*
-        * We don't free anything because the abstract layer combined our
-        * allocation with that of the instance, and it will free the whole
-        * thing after this.
+        * For ourselves, we don't free anything because the abstract layer
+        * combined our allocation with that of the abs instance, and it will
+        * free the whole thing after this.
         */
        *pati = NULL;
 }
@@ -336,15 +349,54 @@ lws_atcrs_state(lws_abs_transport_inst_t *ati)
        return 1;
 }
 
+static int
+lws_atcrs_compare(lws_abs_t *abs1, lws_abs_t *abs2)
+{
+       const lws_token_map_t *tm1, *tm2;
+
+       tm1 = lws_abs_get_token(abs1->at_tokens, LTMI_PEER_V_DNS_ADDRESS);
+       tm2 = lws_abs_get_token(abs2->at_tokens, LTMI_PEER_V_DNS_ADDRESS);
+
+       /* Address token is mandatory and must match */
+       if (!tm1 || !tm2 || strcmp(tm1->u.value, tm2->u.value))
+               return 1;
+
+       /* Port token is mandatory and must match */
+       tm1 = lws_abs_get_token(abs1->at_tokens, LTMI_PEER_LV_PORT);
+       tm2 = lws_abs_get_token(abs2->at_tokens, LTMI_PEER_LV_PORT);
+       if (!tm1 || !tm2 || tm1->u.lvalue != tm2->u.lvalue)
+               return 1;
+
+       /* TLS is optional... */
+       tm1 = lws_abs_get_token(abs1->at_tokens, LTMI_PEER_LV_TLS_FLAGS);
+       tm2 = lws_abs_get_token(abs2->at_tokens, LTMI_PEER_LV_TLS_FLAGS);
+
+       /* ... but both must have the same situation with it given or not... */
+       if (!!tm1 != !!tm2)
+               return 1;
+
+       /* if not using TLS, then that's enough to call it */
+       if (!tm1)
+               return 0;
+
+       /* ...and if there are tls flags, both must have the same tls flags */
+       if (tm1->u.lvalue != tm2->u.lvalue)
+               return 1;
+
+       /* ... and both must use the same client tls ctx / vhost */
+       return abs1->vh != abs2->vh;
+}
+
 const lws_abs_transport_t lws_abs_transport_cli_raw_skt = {
        .name                   = "raw_skt",
        .alloc                  = sizeof(abs_raw_skt_priv_t),
 
        .create                 = lws_atcrs_create,
        .destroy                = lws_atcrs_destroy,
+       .compare                = lws_atcrs_compare,
 
        .tx                     = lws_atcrs_tx,
-#if defined(LWS_WITHOUT_CLIENT)
+#if !defined(LWS_WITH_CLIENT)
        .client_conn            = NULL,
 #else
        .client_conn            = lws_atcrs_client_conn,
index c891861..25052d8 100644 (file)
@@ -1,31 +1,33 @@
-/*
- * libwebsockets lib/abstract/transports/unit-test.c
- *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * An abstract transport that is useful for unit testing an abstract protocol.
  * It doesn't actually connect to anything, but checks the protocol's response
  * to provided canned packets from an array of test vectors.
  */
 
-#include "core/private.h"
-#include "abstract/private.h"
+#include "private-lib-core.h"
+#include "private-lib-abstract.h"
 
 /* this is the transport priv instantiated at abs->ati */
 
@@ -33,7 +35,7 @@ typedef struct lws_abstxp_unit_test_priv {
        char                                    note[128];
        struct lws_abs                          *abs;
 
-       lws_seq_t                               *seq;
+       struct lws_sequencer                    *seq;
        lws_unit_test_t                         *current_test;
        lws_unit_test_packet_t                  *expect;
        lws_unit_test_packet_test_cb            result_cb;
@@ -339,7 +341,7 @@ lws_atcut_tx(lws_abs_transport_inst_t *ati, uint8_t *buf, size_t len)
        return 0;
 }
 
-#if !defined(LWS_WITHOUT_CLIENT)
+#if defined(LWS_WITH_CLIENT)
 static int
 lws_atcut_client_conn(const lws_abs_t *abs)
 {
@@ -417,7 +419,7 @@ static int
 lws_atcut_create(lws_abs_t *ai)
 {
        abs_unit_test_priv_t *priv;
-       lws_seq_t *seq;
+       struct lws_sequencer *seq;
        lws_seq_info_t i;
        seq_priv_t *s;
 
@@ -511,15 +513,22 @@ lws_unit_test_result_name(int in)
        return dnames[in];
 }
 
+static int
+lws_atcut_compare(lws_abs_t *abs1, lws_abs_t *abs2)
+{
+       return 0;
+}
+
 const lws_abs_transport_t lws_abs_transport_cli_unit_test = {
        .name                   = "unit_test",
        .alloc                  = sizeof(abs_unit_test_priv_t),
 
        .create                 = lws_atcut_create,
        .destroy                = lws_atcut_destroy,
+       .compare                = lws_atcut_compare,
 
        .tx                     = lws_atcut_tx,
-#if defined(LWS_WITHOUT_CLIENT)
+#if !defined(LWS_WITH_CLIENT)
        .client_conn            = NULL,
 #else
        .client_conn            = lws_atcut_client_conn,
diff --git a/lib/core-net/CMakeLists.txt b/lib/core-net/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fd56927
--- /dev/null
@@ -0,0 +1,85 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+include_directories(.)
+
+list(APPEND SOURCES
+       core-net/dummy-callback.c
+       core-net/output.c
+       core-net/close.c
+       core-net/network.c
+       core-net/vhost.c
+       core-net/pollfd.c
+       core-net/service.c
+       core-net/sorted-usec-list.c
+       core-net/wsi.c
+       core-net/wsi-timeout.c
+       core-net/adopt.c
+       roles/pipe/ops-pipe.c
+)
+
+if (LWS_WITH_SYS_STATE)
+       list(APPEND SOURCES
+               core-net/state.c
+       )
+endif()
+
+if (LWS_WITH_NETLINK)
+       list(APPEND SOURCES
+               core-net/route.c
+       )
+endif()
+
+if (LWS_WITH_LWS_DSH)
+       list(APPEND SOURCES
+               core-net/lws-dsh.c)
+endif()
+
+if (LWS_WITH_SEQUENCER)
+       list(APPEND SOURCES
+               core-net/sequencer.c)
+endif()
+
+if (LWS_WITH_CLIENT)
+       list(APPEND SOURCES
+               core-net/client/client.c
+               core-net/client/connect.c
+               core-net/client/connect2.c
+               core-net/client/connect3.c
+               core-net/client/connect4.c
+               core-net/client/sort-dns.c
+       )
+       if (LWS_WITH_CONMON)
+               list(APPEND SOURCES
+                       core-net/client/conmon.c
+               )
+       endif()
+endif()
+
+if (LWS_WITH_SOCKS5 AND NOT LWS_WITHOUT_CLIENT)
+       list(APPEND SOURCES
+               core-net/socks5-client.c)
+endif()
+
+exports_to_parent_scope()
diff --git a/lib/core-net/README.md b/lib/core-net/README.md
new file mode 100644 (file)
index 0000000..f7c794f
--- /dev/null
@@ -0,0 +1,58 @@
+# Implementation background
+
+## Client connection Queueing
+
+By default lws treats each client connection as completely separate, and each is
+made from scratch with its own network connection independently.
+
+If the user code sets the `LCCSCF_PIPELINE` bit on `info.ssl_connection` when
+creating the client connection though, lws attempts to optimize multiple client
+connections to the same place by sharing any existing connection and its tls
+tunnel where possible.
+
+There are two basic approaches, for h1 additional connections of the same type
+and endpoint basically queue on a leader and happen sequentially.
+
+For muxed protocols like h2, they may also queue if the initial connection is
+not up yet, but subsequently the will all join the existing connection
+simultaneously "broadside".
+
+## h1 queueing
+
+The initial wsi to start the network connection becomes the "leader" that
+subsequent connection attempts will queue against.  Each vhost has a dll2_owner
+`wsi->dll_cli_active_conns_owner` that "leaders" who are actually making network
+connections themselves can register on as "active client connections".
+
+Other client wsi being created who find there is already a leader on the active
+client connection list for the vhost, can join their dll2 wsi->dll2_cli_txn_queue
+to the leader's wsi->dll2_cli_txn_queue_owner to "queue" on the leader.
+
+The user code does not know which wsi was first or is queued, it just waits for
+stuff to happen the same either way.
+
+When the "leader" wsi connects, it performs its client transaction as normal,
+and at the end arrives at `lws_http_transaction_completed_client()`.  Here, it
+calls through to the lws_mux `_lws_generic_transaction_completed_active_conn()`
+helper.  This helper sees if anything else is queued, and if so, migrates assets
+like the SSL *, the socket fd, and any remaining queue from the original leader
+to the head of the list, which replaces the old leader as the "active client
+connection" any subsequent connects would queue on.
+
+It has to be done this way so that user code which may know each client wsi by
+its wsi, or have marked it with an opaque_user_data pointer, is getting its
+specific request handled by the wsi it expects it to be handled by.
+
+A side effect of this, and in order to be able to handle POSTs cleanly, lws
+does not attempt to send the headers for the next queued child before the
+previous child has finished.
+
+The process of moving the SSL context and fd etc between the queued wsi continues
+until the queue is all handled.
+
+## muxed protocol queueing and stream binding
+
+h2 connections act the same as h1 before the initial connection has been made,
+but once it is made all the queued connections join the network connection as
+child mux streams immediately, "broadside", binding the stream to the existing
+network connection.
index 9b84af2..e411945 100644 (file)
@@ -1,34 +1,38 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-
+#include "private-lib-core.h"
 
 static int
 lws_get_idlest_tsi(struct lws_context *context)
 {
-       unsigned int lowest = ~0;
+       unsigned int lowest = ~0u;
        int n = 0, hit = -1;
 
        for (; n < context->count_threads; n++) {
+               lwsl_cx_debug(context, "%d %d\n", context->pt[n].fds_count,
+                               context->fd_limit_per_thread - 1);
                if ((unsigned int)context->pt[n].fds_count !=
                    context->fd_limit_per_thread - 1 &&
                    (unsigned int)context->pt[n].fds_count < lowest) {
@@ -41,7 +45,7 @@ lws_get_idlest_tsi(struct lws_context *context)
 }
 
 struct lws *
-lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi)
+lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi, const char *desc)
 {
        struct lws *new_wsi;
        int n = fixed_tsi;
@@ -50,25 +54,35 @@ lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi)
                n = lws_get_idlest_tsi(vhost->context);
 
        if (n < 0) {
-               lwsl_err("no space for new conn\n");
+               lwsl_vhost_err(vhost, "no space for new conn");
                return NULL;
        }
 
-       new_wsi = lws_zalloc(sizeof(struct lws), "new server wsi");
+       lws_context_lock(vhost->context, __func__);
+       new_wsi = __lws_wsi_create_with_role(vhost->context, n, NULL,
+                                            vhost->lc.log_cx);
+       lws_context_unlock(vhost->context);
        if (new_wsi == NULL) {
-               lwsl_err("Out of memory for new connection\n");
+               lwsl_vhost_err(vhost, "OOM");
                return NULL;
        }
 
+       lws_wsi_fault_timedclose(new_wsi);
+
+       __lws_lc_tag(vhost->context, &vhost->context->lcg[
+#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
+       strcmp(desc, "adopted") ? LWSLCG_WSI_MUX :
+#endif
+       LWSLCG_WSI_SERVER], &new_wsi->lc, desc);
+
        new_wsi->wsistate |= LWSIFR_SERVER;
-       new_wsi->tsi = n;
-       lwsl_debug("new wsi %p joining vhost %s, tsi %d\n", new_wsi,
-                  vhost->name, new_wsi->tsi);
+       new_wsi->tsi = (char)n;
+       lwsl_wsi_debug(new_wsi, "joining vh %s, tsi %d",
+                       vhost->name, new_wsi->tsi);
 
        lws_vhost_bind_wsi(vhost, new_wsi);
-       new_wsi->context = vhost->context;
-       new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
        new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
+       new_wsi->retry_policy = vhost->retry_policy;
 
        /* initialize the instance struct */
 
@@ -85,12 +99,8 @@ lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi)
         * to the start of the supported list, so it can look
         * for matching ones during the handshake
         */
-       new_wsi->protocol = vhost->protocols;
+       new_wsi->a.protocol = vhost->protocols;
        new_wsi->user_space = NULL;
-       new_wsi->desc.sockfd = LWS_SOCK_INVALID;
-       new_wsi->position_in_fds_table = LWS_NO_FDS_POS;
-
-       vhost->context->count_wsi_allocated++;
 
        /*
         * outermost create notification for wsi
@@ -103,57 +113,53 @@ lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi)
 }
 
 
-/* if not a socket, it's a raw, non-ssl file descriptor */
+/* if not a socket, it's a raw, non-ssl file descriptor
+ * req cx lock, acq pt lock, acq vh lock
+ */
 
-LWS_VISIBLE struct lws *
-lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
-                          lws_sock_file_fd_type fd, const char *vh_prot_name,
-                          struct lws *parent)
+static struct lws *
+__lws_adopt_descriptor_vhost1(struct lws_vhost *vh, lws_adoption_type type,
+                           const char *vh_prot_name, struct lws *parent,
+                           void *opaque, const char *fi_wsi_name)
 {
-       struct lws_context *context = vh->context;
+       struct lws_context *context;
        struct lws_context_per_thread *pt;
        struct lws *new_wsi;
        int n;
 
-#if defined(LWS_WITH_PEER_LIMITS)
-       struct lws_peer *peer = NULL;
-
-       if (type & LWS_ADOPT_SOCKET) {
-               peer = lws_get_or_create_peer(vh, fd.sockfd);
-
-               if (peer && context->ip_limit_wsi &&
-                   peer->count_wsi >= context->ip_limit_wsi) {
-                       lwsl_notice("Peer reached wsi limit %d\n",
-                                       context->ip_limit_wsi);
-                       lws_stats_bump(&context->pt[0],
-                                             LWSSTATS_C_PEER_LIMIT_WSI_DENIED,
-                                             1);
-                       return NULL;
-               }
-       }
-#endif
-
        /*
         * Notice that in SMP case, the wsi may be being created on an
         * entirely different pt / tsi for load balancing.  In that case as
         * we initialize it, it may become "live" concurrently unexpectedly...
         */
 
+       if (!vh)
+               return NULL;
+
+       context = vh->context;
+
+       lws_context_assert_lock_held(vh->context);
+
        n = -1;
        if (parent)
                n = parent->tsi;
-       new_wsi = lws_create_new_server_wsi(vh, n);
-       if (!new_wsi) {
-               if (type & LWS_ADOPT_SOCKET)
-                       compatible_close(fd.sockfd);
+       new_wsi = lws_create_new_server_wsi(vh, n, "adopted");
+       if (!new_wsi)
+               return NULL;
+
+       /* bring in specific fault injection rules early */
+       lws_fi_inherit_copy(&new_wsi->fic, &context->fic, "wsi", fi_wsi_name);
+
+       if (lws_fi(&new_wsi->fic, "createfail")) {
+               lws_fi_destroy(&new_wsi->fic);
+
                return NULL;
        }
-#if defined(LWS_WITH_PEER_LIMITS)
-       if (peer)
-               lws_peer_add_wsi(context, peer, new_wsi);
-#endif
+
+       new_wsi->a.opaque_user_data = opaque;
+
        pt = &context->pt[(int)new_wsi->tsi];
-       lws_stats_bump(pt, LWSSTATS_C_CONNECTIONS, 1);
+       lws_pt_lock(pt, __func__);
 
        if (parent) {
                new_wsi->parent = parent;
@@ -161,47 +167,218 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
                parent->child_list = new_wsi;
        }
 
+       if (vh_prot_name) {
+               new_wsi->a.protocol = lws_vhost_name_to_protocol(new_wsi->a.vhost,
+                                                              vh_prot_name);
+               if (!new_wsi->a.protocol) {
+                       lwsl_vhost_err(new_wsi->a.vhost, "Protocol %s not enabled",
+                                                     vh_prot_name);
+                       goto bail;
+               }
+               if (lws_ensure_user_space(new_wsi)) {
+                       lwsl_wsi_notice(new_wsi, "OOM");
+                       goto bail;
+               }
+       }
+
+       if (!LWS_SSL_ENABLED(new_wsi->a.vhost) ||
+           !(type & LWS_ADOPT_SOCKET))
+               type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL;
+
+       if (lws_role_call_adoption_bind(new_wsi, (int)type, vh_prot_name)) {
+               lwsl_wsi_err(new_wsi, "no role for desc type 0x%x", type);
+               goto bail;
+       }
+
+#if defined(LWS_WITH_SERVER)
+       if (new_wsi->role_ops) {
+               lws_metrics_tag_wsi_add(new_wsi, "role", new_wsi->role_ops->name);
+       }
+#endif
+
+       lws_pt_unlock(pt);
+
+       /*
+        * he's an allocated wsi, but he's not on any fds list or child list,
+        * join him to the vhost's list of these kinds of incomplete wsi until
+        * he gets another identity (he may do async dns now...)
+        */
+       lws_vhost_lock(new_wsi->a.vhost);
+       lws_dll2_add_head(&new_wsi->vh_awaiting_socket,
+                         &new_wsi->a.vhost->vh_awaiting_socket_owner);
+       lws_vhost_unlock(new_wsi->a.vhost);
+
+       return new_wsi;
+
+bail:
+       lwsl_wsi_notice(new_wsi, "exiting on bail");
+       if (parent)
+               parent->child_list = new_wsi->sibling_list;
+       if (new_wsi->user_space)
+               lws_free(new_wsi->user_space);
+
+       lws_fi_destroy(&new_wsi->fic);
+
+       lws_pt_unlock(pt);
+       __lws_vhost_unbind_wsi(new_wsi); /* req cx, acq vh lock */
+
+       lws_free(new_wsi);
+
+       return NULL;
+}
+
+#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
+
+/*
+ * If the incoming wsi is bound to a vhost that is a ss server, this creates
+ * an accepted ss bound to the wsi.
+ *
+ * For h1 or raw, we can do the binding here, but for muxed protocols like h2
+ * or mqtt we have to do it not on the nwsi but on the stream.  And for h2 we
+ * start off bound to h1 role, since we don't know if we will upgrade to h2
+ * until we meet the server.
+ *
+ * 1) No tls is assumed to mean no muxed protocol so can do it at adopt.
+ *
+ * 2) After alpn if not muxed we can do it.
+ *
+ * 3) For muxed, do it at the nwsi migration and on new stream
+ */
+
+int
+lws_adopt_ss_server_accept(struct lws *new_wsi)
+{
+       struct lws_context_per_thread *pt =
+                       &new_wsi->a.context->pt[(int)new_wsi->tsi];
+       lws_ss_handle_t *h;
+       void *pv, **ppv;
+
+       if (!new_wsi->a.vhost->ss_handle)
+               return 0;
+
+       pv = (char *)&new_wsi->a.vhost->ss_handle[1];
+
+       /*
+        * Yes... the vhost is pointing to its secure stream representing the
+        * server... we want to create an accepted SS and bind it to new_wsi,
+        * the info/ssi from the server SS (so the SS callbacks defined there),
+        * the opaque_user_data of the server object and the policy of it.
+        */
+
+       ppv = (void **)((char *)pv +
+             new_wsi->a.vhost->ss_handle->info.opaque_user_data_offset);
+
+       /*
+        * indicate we are an accepted connection referencing the
+        * server object
+        */
+
+       new_wsi->a.vhost->ss_handle->info.flags |= LWSSSINFLAGS_SERVER;
+
+       if (lws_ss_create(new_wsi->a.context, new_wsi->tsi,
+                         &new_wsi->a.vhost->ss_handle->info,
+                         *ppv, &h, NULL, NULL)) {
+               lwsl_wsi_err(new_wsi, "accept ss creation failed");
+               goto fail1;
+       }
+
+       /*
+        * We made a fresh accepted SS conn from the server pieces,
+        * now bind the wsi... the problem is, this is the nwsi if it's
+        * h2.
+        */
+
+       h->wsi = new_wsi;
+       new_wsi->a.opaque_user_data = h;
+       h->info.flags |= LWSSSINFLAGS_ACCEPTED;
+       /* indicate wsi should invalidate any ss link to it on close */
+       new_wsi->for_ss = 1;
+
+       // lwsl_wsi_notice(new_wsi, "%s: opaq %p, role %s",
+       //                           new_wsi->a.opaque_user_data,
+       //                           new_wsi->role_ops->name);
+
+       h->policy = new_wsi->a.vhost->ss_handle->policy;
+
+       /* apply requested socket options */
+       if (lws_plat_set_socket_options_ip(new_wsi->desc.sockfd,
+                                          h->policy->priority,
+                     (LCCSCF_IP_LOW_LATENCY *
+                      !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_LATENCY)) |
+                     (LCCSCF_IP_HIGH_THROUGHPUT *
+                      !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_THROUGHPUT)) |
+                     (LCCSCF_IP_HIGH_RELIABILITY *
+                      !!(h->policy->flags & LWSSSPOLF_ATTR_HIGH_RELIABILITY)) |
+                     (LCCSCF_IP_LOW_COST *
+                      !!(h->policy->flags & LWSSSPOLF_ATTR_LOW_COST))))
+               lwsl_wsi_warn(new_wsi, "unable to set ip options");
+
+       /*
+        * add us to the list of clients that came in from the server
+        */
+
+       lws_pt_lock(pt, __func__);
+       lws_dll2_add_tail(&h->cli_list, &new_wsi->a.vhost->ss_handle->src_list);
+       lws_pt_unlock(pt);
+
+       /*
+        * Let's give it appropriate state notifications
+        */
+
+       if (lws_ss_event_helper(h, LWSSSCS_CREATING))
+               goto fail;
+       if (lws_ss_event_helper(h, LWSSSCS_CONNECTING))
+               goto fail;
+
+       /* defer CONNECTED until we see if he is upgrading */
+
+//     if (lws_ss_event_helper(h, LWSSSCS_CONNECTED))
+//             goto fail;
+
+       // lwsl_notice("%s: accepted ss complete, pcol %s\n", __func__,
+       //              new_wsi->a.protocol->name);
+
+       return 0;
+
+fail:
+       lws_ss_destroy(&h);
+fail1:
+       return 1;
+}
+
+#endif
+
+
+static struct lws *
+lws_adopt_descriptor_vhost2(struct lws *new_wsi, lws_adoption_type type,
+                           lws_sock_file_fd_type fd)
+{
+       struct lws_context_per_thread *pt =
+                       &new_wsi->a.context->pt[(int)new_wsi->tsi];
+       int n;
+
        /* enforce that every fd is nonblocking */
 
        if (type & LWS_ADOPT_SOCKET) {
                if (lws_plat_set_nonblocking(fd.sockfd)) {
-                       lwsl_err("%s: unable to set sockfd nonblocking\n",
-                                __func__);
-                       goto bail;
+                       lwsl_wsi_err(new_wsi, "unable to set sockfd %d nonblocking",
+                                    fd.sockfd);
+                       goto fail;
                }
        }
 #if !defined(WIN32)
        else
                if (lws_plat_set_nonblocking(fd.filefd)) {
-                       lwsl_err("%s: unable to set filefd nonblocking\n",
-                                __func__);
-                       goto bail;
+                       lwsl_wsi_err(new_wsi, "unable to set filefd nonblocking");
+                       goto fail;
                }
 #endif
 
        new_wsi->desc = fd;
 
-       if (vh_prot_name) {
-               new_wsi->protocol = lws_vhost_name_to_protocol(new_wsi->vhost,
-                                                              vh_prot_name);
-               if (!new_wsi->protocol) {
-                       lwsl_err("Protocol %s not enabled on vhost %s\n",
-                                vh_prot_name, new_wsi->vhost->name);
-                       goto bail;
-               }
-               if (lws_ensure_user_space(new_wsi)) {
-                      lwsl_notice("OOM trying to get user_space\n");
-                       goto bail;
-               }
-       }
-
-       if (!LWS_SSL_ENABLED(new_wsi->vhost) || !(type & LWS_ADOPT_SOCKET))
-               type &= ~LWS_ADOPT_ALLOW_SSL;
-
-       if (lws_role_call_adoption_bind(new_wsi, type, vh_prot_name)) {
-               lwsl_err("Unable to find a role that can adopt descriptor type 0x%x\n", type);
-               goto bail;
-       }
+       if (!LWS_SSL_ENABLED(new_wsi->a.vhost) ||
+           !(type & LWS_ADOPT_SOCKET))
+               type &= (unsigned int)~LWS_ADOPT_ALLOW_SSL;
 
        /*
         * A new connection was accepted. Give the user a chance to
@@ -214,11 +391,9 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
        if (new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)])
                n = new_wsi->role_ops->adoption_cb[lwsi_role_server(new_wsi)];
 
-#if !defined(LWS_AMAZON_RTOS)
-       if (context->event_loop_ops->accept)
-               if (context->event_loop_ops->accept(new_wsi))
+       if (new_wsi->a.context->event_loop_ops->sock_accept)
+               if (new_wsi->a.context->event_loop_ops->sock_accept(new_wsi))
                        goto fail;
-#endif
 
 #if LWS_MAX_SMP > 1
        /*
@@ -231,33 +406,54 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
 
        if (!(type & LWS_ADOPT_ALLOW_SSL)) {
                lws_pt_lock(pt, __func__);
-               if (__insert_wsi_socket_into_fds(context, new_wsi)) {
+               if (__insert_wsi_socket_into_fds(new_wsi->a.context, new_wsi)) {
                        lws_pt_unlock(pt);
-                       lwsl_err("%s: fail inserting socket\n", __func__);
+                       lwsl_wsi_err(new_wsi, "fail inserting socket");
                        goto fail;
                }
                lws_pt_unlock(pt);
        }
-#if !defined(LWS_WITHOUT_SERVER)
+#if defined(LWS_WITH_SERVER)
         else
-               if (lws_server_socket_service_ssl(new_wsi, fd.sockfd)) {
-                       lwsl_info("%s: fail ssl negotiation\n", __func__);
+               if (lws_server_socket_service_ssl(new_wsi, fd.sockfd, 0)) {
+                       lwsl_wsi_info(new_wsi, "fail ssl negotiation");
+
                        goto fail;
                }
 #endif
 
+       lws_vhost_lock(new_wsi->a.vhost);
+       /* he has fds visibility now, remove from vhost orphan list */
+       lws_dll2_remove(&new_wsi->vh_awaiting_socket);
+       lws_vhost_unlock(new_wsi->a.vhost);
+
        /*
         *  by deferring callback to this point, after insertion to fds,
         * lws_callback_on_writable() can work from the callback
         */
-       if ((new_wsi->protocol->callback)(new_wsi, n, new_wsi->user_space,
+       if ((new_wsi->a.protocol->callback)(new_wsi, (enum lws_callback_reasons)n, new_wsi->user_space,
                                          NULL, 0))
                goto fail;
 
        /* role may need to do something after all adoption completed */
 
-       lws_role_call_adoption_bind(new_wsi, type | _LWS_ADOPT_FINISH,
-                                   vh_prot_name);
+       lws_role_call_adoption_bind(new_wsi, (int)type | _LWS_ADOPT_FINISH,
+                                   new_wsi->a.protocol->name);
+
+#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
+       /*
+        * Did we come from an accepted client connection to a ss server?
+        *
+        * !!! For mux protocols, this will cause an additional inactive ss
+        * representing the nwsi.  Doing that allows us to support both h1
+        * (here) and h2 (at __lws_wsi_server_new())
+        */
+
+       lwsl_wsi_info(new_wsi, "vhost %s", new_wsi->a.vhost->lc.gutag);
+
+       if (lws_adopt_ss_server_accept(new_wsi))
+               goto fail;
+#endif
 
 #if LWS_MAX_SMP > 1
        /* its actual pt can service it now */
@@ -275,25 +471,86 @@ fail:
                                   "adopt skt fail");
 
        return NULL;
+}
 
-bail:
-       lwsl_notice("%s: exiting on bail\n", __func__);
-       if (parent)
-               parent->child_list = new_wsi->sibling_list;
-       if (new_wsi->user_space)
-               lws_free(new_wsi->user_space);
 
-       vh->context->count_wsi_allocated--;
+/* if not a socket, it's a raw, non-ssl file descriptor */
+
+struct lws *
+lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
+                          lws_sock_file_fd_type fd, const char *vh_prot_name,
+                          struct lws *parent)
+{
+       lws_adopt_desc_t info;
 
-       lws_vhost_unbind_wsi(new_wsi);
-       lws_free(new_wsi);
+       memset(&info, 0, sizeof(info));
 
-       compatible_close(fd.sockfd);
+       info.vh = vh;
+       info.type = type;
+       info.fd = fd;
+       info.vh_prot_name = vh_prot_name;
+       info.parent = parent;
 
-       return NULL;
+       return lws_adopt_descriptor_vhost_via_info(&info);
 }
 
-LWS_VISIBLE struct lws *
+struct lws *
+lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info)
+{
+       socklen_t slen = sizeof(lws_sockaddr46);
+       struct lws *new_wsi;
+
+#if defined(LWS_WITH_PEER_LIMITS)
+       struct lws_peer *peer = NULL;
+
+       if (info->type & LWS_ADOPT_SOCKET) {
+               peer = lws_get_or_create_peer(info->vh, info->fd.sockfd);
+
+               if (peer && info->vh->context->ip_limit_wsi &&
+                   peer->count_wsi >= info->vh->context->ip_limit_wsi) {
+                       lwsl_info("Peer reached wsi limit %d\n",
+                                       info->vh->context->ip_limit_wsi);
+                       if (info->vh->context->pl_notify_cb)
+                               info->vh->context->pl_notify_cb(
+                                                       info->vh->context,
+                                                       info->fd.sockfd,
+                                                       &peer->sa46);
+                       compatible_close(info->fd.sockfd);
+                       return NULL;
+               }
+       }
+#endif
+
+       lws_context_lock(info->vh->context, __func__);
+
+       new_wsi = __lws_adopt_descriptor_vhost1(info->vh, info->type,
+                                             info->vh_prot_name, info->parent,
+                                             info->opaque, info->fi_wsi_name);
+       if (!new_wsi) {
+               if (info->type & LWS_ADOPT_SOCKET)
+                       compatible_close(info->fd.sockfd);
+               goto bail;
+       }
+
+       if (info->type & LWS_ADOPT_SOCKET &&
+           getpeername(info->fd.sockfd, (struct sockaddr *)&new_wsi->sa46_peer,
+                                                                   &slen) < 0)
+               lwsl_info("%s: getpeername failed\n", __func__);
+
+#if defined(LWS_WITH_PEER_LIMITS)
+       if (peer)
+               lws_peer_add_wsi(info->vh->context, peer, new_wsi);
+#endif
+
+       new_wsi = lws_adopt_descriptor_vhost2(new_wsi, info->type, info->fd);
+
+bail:
+       lws_context_unlock(info->vh->context);
+
+       return new_wsi;
+}
+
+struct lws *
 lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
 {
        lws_sock_file_fd_type fd;
@@ -303,7 +560,7 @@ lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
                        LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);
 }
 
-LWS_VISIBLE struct lws *
+struct lws *
 lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
 {
        return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
@@ -326,7 +583,7 @@ adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
        if (wsi->position_in_fds_table == LWS_NO_FDS_POS)
                return wsi;
 
-       pt = &wsi->context->pt[(int)wsi->tsi];
+       pt = &wsi->a.context->pt[(int)wsi->tsi];
 
        n = lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf,
                                       len);
@@ -358,7 +615,7 @@ adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
                pfd = &pt->fds[wsi->position_in_fds_table];
                pfd->revents |= LWS_POLLIN;
                lwsl_err("%s: calling service\n", __func__);
-               if (lws_service_fd_tsi(wsi->context, pfd, wsi->tsi))
+               if (lws_service_fd_tsi(wsi->a.context, pfd, wsi->tsi))
                        /* service closed us */
                        return NULL;
 
@@ -375,78 +632,294 @@ bail:
        return NULL;
 }
 
-LWS_EXTERN struct lws *
-lws_create_adopt_udp(struct lws_vhost *vhost, int port, int flags,
-                    const char *protocol_name, struct lws *parent_wsi)
+#if defined(LWS_WITH_UDP)
+#if defined(LWS_WITH_CLIENT)
+
+/*
+ * This is the ASYNC_DNS callback target for udp client, it's analogous to
+ * connect3()
+ */
+
+static struct lws *
+lws_create_adopt_udp2(struct lws *wsi, const char *ads,
+                     const struct addrinfo *r, int n, void *opaque)
 {
-#if !defined(LWS_PLAT_OPTEE)
        lws_sock_file_fd_type sock;
-       struct addrinfo h, *r, *rp;
-       struct lws *wsi = NULL;
-       char buf[16];
-       int n;
+       int bc = 1, m;
 
-       memset(&h, 0, sizeof(h));
-       h.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
-       h.ai_socktype = SOCK_DGRAM;
-       h.ai_protocol = IPPROTO_UDP;
-       h.ai_flags = AI_PASSIVE;
-#ifdef AI_ADDRCONFIG
-       h.ai_flags |= AI_ADDRCONFIG;
-#endif
+       assert(wsi);
 
-       lws_snprintf(buf, sizeof(buf), "%u", port);
-       n = getaddrinfo(NULL, buf, &h, &r);
-       if (n) {
-#ifndef LWS_WITH_ESP32
-               lwsl_info("%s: getaddrinfo error: %s\n", __func__, gai_strerror(n));
+       if (ads && (n < 0 || !r)) {
+               /*
+                * DNS lookup failed: there are no usable results.  Fail the
+                * overall connection request.
+                */
+               lwsl_notice("%s: bad: n %d, r %p\n", __func__, n, r);
+
+               goto bail;
+       }
+
+       m = lws_sort_dns(wsi, r);
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       lws_async_dns_freeaddrinfo(&r);
 #else
-        lwsl_info("%s: getaddrinfo error: %s\n", __func__, strerror(n));
+       freeaddrinfo((struct addrinfo *)r);
 #endif
+       if (m)
                goto bail;
-       }
 
-       for (rp = r; rp; rp = rp->ai_next) {
-               sock.sockfd = socket(rp->ai_family, rp->ai_socktype,
-                                    rp->ai_protocol);
-               if (sock.sockfd != LWS_SOCK_INVALID)
-                       break;
+       while (lws_dll2_get_head(&wsi->dns_sorted_list)) {
+               lws_dns_sort_t *s = lws_container_of(
+                               lws_dll2_get_head(&wsi->dns_sorted_list),
+                               lws_dns_sort_t, list);
+
+               /*
+                * Remove it from the head, but don't free it yet... we are
+                * taking responsibility to free it
+                */
+               lws_dll2_remove(&s->list);
+
+               /*
+                * We have done the dns lookup, identify the result we want
+                * if any, and then complete the adoption by binding wsi to
+                * socket opened on it.
+                *
+                * Ignore the weak assumptions about protocol driven by port
+                * number and force to DGRAM / UDP since that's what this
+                * function is for.
+                */
+
+#if !defined(__linux__)
+               sock.sockfd = socket(s->dest.sa4.sin_family,
+                                    SOCK_DGRAM, IPPROTO_UDP);
+#else
+               /* PF_PACKET is linux-only */
+               sock.sockfd = socket(wsi->pf_packet ? PF_PACKET :
+                                               s->dest.sa4.sin_family,
+                                    SOCK_DGRAM, wsi->pf_packet ?
+                                       htons(0x800) : IPPROTO_UDP);
+#endif
+               if (sock.sockfd == LWS_SOCK_INVALID)
+                       goto resume;
+
+               /* ipv6 udp!!! */
+
+               if (s->af == AF_INET)
+                       s->dest.sa4.sin_port = htons(wsi->c_port);
+#if defined(LWS_WITH_IPV6)
+               else
+                       s->dest.sa6.sin6_port = htons(wsi->c_port);
+#endif
+
+               if (setsockopt(sock.sockfd, SOL_SOCKET, SO_REUSEADDR,
+                              (const char *)&bc, sizeof(bc)) < 0)
+                       lwsl_err("%s: failed to set reuse\n", __func__);
+
+               if (wsi->do_broadcast &&
+                   setsockopt(sock.sockfd, SOL_SOCKET, SO_BROADCAST,
+                              (const char *)&bc, sizeof(bc)) < 0)
+                       lwsl_err("%s: failed to set broadcast\n", __func__);
+
+               /* Bind the udp socket to a particular network interface */
+
+               if (opaque &&
+                   lws_plat_BINDTODEVICE(sock.sockfd, (const char *)opaque))
+                       goto resume;
+
+               if (wsi->do_bind &&
+                   bind(sock.sockfd, sa46_sockaddr(&s->dest),
+#if defined(_WIN32)
+                        (int)sa46_socklen(&s->dest)
+#else
+                        sizeof(struct sockaddr)
+#endif
+               ) == -1) {
+                       lwsl_err("%s: bind failed\n", __func__);
+                       goto resume;
+               }
+
+               if (!wsi->do_bind && !wsi->pf_packet) {
+#if !defined(__APPLE__)
+                       if (connect(sock.sockfd, sa46_sockaddr(&s->dest),
+                                   sa46_socklen(&s->dest)) == -1 &&
+                           errno != EADDRNOTAVAIL /* openbsd */ ) {
+                               lwsl_err("%s: conn fd %d fam %d %s:%u failed "
+                                        "errno %d\n", __func__, sock.sockfd,
+                                        s->dest.sa4.sin_family,
+                                        ads ? ads : "null", wsi->c_port,
+                                        LWS_ERRNO);
+                               compatible_close(sock.sockfd);
+                               goto resume;
+                       }
+#endif
+               }
+
+               if (wsi->udp)
+                       wsi->udp->sa46 = s->dest;
+               wsi->sa46_peer = s->dest;
+
+               /* we connected: complete the udp socket adoption flow */
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       if (wsi->a.context->async_dns.wsi == wsi)
+               wsi->a.context->async_dns.dns_server_connected = 1;
+#endif
+
+               lws_free(s);
+               lws_addrinfo_clean(wsi);
+               return lws_adopt_descriptor_vhost2(wsi,
+                                               LWS_ADOPT_RAW_SOCKET_UDP, sock);
+
+resume:
+               lws_free(s);
        }
-       if (!rp) {
-               lwsl_err("%s: unable to create INET socket\n", __func__);
-               goto bail1;
+
+       lwsl_err("%s: unable to create INET socket %d\n", __func__, LWS_ERRNO);
+       lws_addrinfo_clean(wsi);
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       if (wsi->a.context->async_dns.wsi == wsi)
+               lws_async_dns_drop_server(wsi->a.context);
+#endif
+
+bail:
+
+       /* caller must close */
+
+       return NULL;
+}
+
+struct lws *
+lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
+                    int flags, const char *protocol_name, const char *ifname,
+                    struct lws *parent_wsi, void *opaque,
+                    const lws_retry_bo_t *retry_policy, const char *fi_wsi_name)
+{
+#if !defined(LWS_PLAT_OPTEE)
+       struct lws *wsi;
+       int n;
+
+       lwsl_info("%s: %s:%u\n", __func__, ads ? ads : "null", port);
+
+       /* create the logical wsi without any valid fd */
+
+       lws_context_lock(vhost->context, __func__);
+
+       wsi = __lws_adopt_descriptor_vhost1(vhost, LWS_ADOPT_SOCKET |
+                                                LWS_ADOPT_RAW_SOCKET_UDP,
+                                         protocol_name, parent_wsi, opaque,
+                                         fi_wsi_name);
+
+       lws_context_unlock(vhost->context);
+       if (!wsi) {
+               lwsl_err("%s: udp wsi creation failed\n", __func__);
+               goto bail;
        }
 
-       if ((flags & LWS_CAUDP_BIND) && bind(sock.sockfd, rp->ai_addr,
-#if defined(_WIN32)
-                           (int)rp->ai_addrlen
+       // lwsl_notice("%s: role %s\n", __func__, wsi->role_ops->name);
+
+       wsi->do_bind = !!(flags & LWS_CAUDP_BIND);
+       wsi->do_broadcast = !!(flags & LWS_CAUDP_BROADCAST);
+       wsi->pf_packet = !!(flags & LWS_CAUDP_PF_PACKET);
+       wsi->c_port = (uint16_t)(unsigned int)port;
+       if (retry_policy)
+               wsi->retry_policy = retry_policy;
+       else
+               wsi->retry_policy = vhost->retry_policy;
+
+#if !defined(LWS_WITH_SYS_ASYNC_DNS)
+       {
+               struct addrinfo *r, h;
+               char buf[16];
+
+               memset(&h, 0, sizeof(h));
+               h.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
+               h.ai_socktype = SOCK_DGRAM;
+               h.ai_protocol = IPPROTO_UDP;
+#if defined(AI_PASSIVE)
+               h.ai_flags = AI_PASSIVE;
+#endif
+#ifdef AI_ADDRCONFIG
+               h.ai_flags |= AI_ADDRCONFIG;
+#endif
+
+               /* if the dns lookup is synchronous, do the whole thing now */
+               lws_snprintf(buf, sizeof(buf), "%u", port);
+               n = getaddrinfo(ads, buf, &h, &r);
+               if (n) {
+#if !defined(LWS_PLAT_FREERTOS)
+                       lwsl_info("%s: getaddrinfo error: %s\n", __func__,
+                                 gai_strerror(n));
 #else
-                           rp->ai_addrlen
+                       lwsl_info("%s: getaddrinfo error: %s\n", __func__,
+                                       strerror(n));
 #endif
-          ) == -1) {
-               lwsl_err("%s: bind failed\n", __func__);
-               goto bail2;
+                       //freeaddrinfo(r);
+                       goto bail1;
+               }
+               /*
+                * With synchronous dns, complete it immediately after the
+                * blocking dns lookup finished... free r when connect either
+                * completed or failed
+                */
+               wsi = lws_create_adopt_udp2(wsi, ads, r, 0, NULL);
+
+               return wsi;
+       }
+#else
+       if (ads) {
+               /*
+                * with async dns, use the wsi as the point about which to do
+                * the dns lookup and have it call the second part when it's
+                * done.
+                *
+                * Keep a refcount on the results and free it when we connected
+                * or definitively failed.
+                *
+                * Notice wsi has no socket at this point (we don't know what
+                * kind to ask for until we get the dns back).  But it is bound
+                * to a vhost and can be cleaned up from that at vhost destroy.
+                */
+               n = lws_async_dns_query(vhost->context, 0, ads,
+                                       LWS_ADNS_RECORD_A,
+                                       lws_create_adopt_udp2, wsi,
+                                       (void *)ifname);
+               // lwsl_notice("%s: dns query returned %d\n", __func__, n);
+               if (n == LADNS_RET_FAILED) {
+                       lwsl_err("%s: async dns failed\n", __func__);
+                       wsi = NULL;
+                       /*
+                        * It was already closed by calling callback with error
+                        * from lws_async_dns_query()
+                        */
+                       goto bail;
+               }
+       } else {
+               lwsl_debug("%s: udp adopt has no ads\n", __func__);
+               wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, (void *)ifname);
        }
 
-       wsi = lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_RAW_SOCKET_UDP, sock,
-                                       protocol_name, parent_wsi);
-       if (!wsi)
-               lwsl_err("%s: udp adoption failed\n", __func__);
+       /* dns lookup is happening asynchronously */
 
-bail2:
-       if (!wsi)
-               compatible_close((int)sock.sockfd);
-bail1:
-       freeaddrinfo(r);
+       // lwsl_notice("%s: returning wsi %p\n", __func__, wsi);
 
+       return wsi;
+#endif
+#if !defined(LWS_WITH_SYS_ASYNC_DNS)
+bail1:
+       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail");
+       wsi = NULL;
+#endif
 bail:
        return wsi;
 #else
        return NULL;
 #endif
 }
+#endif
+#endif
 
-LWS_VISIBLE struct lws *
+struct lws *
 lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
                         const char *readbuf, size_t len)
 {
@@ -454,7 +927,7 @@ lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
                                    readbuf, len);
 }
 
-LWS_VISIBLE struct lws *
+struct lws *
 lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
                               lws_sockfd_type accept_fd,
                               const char *readbuf, size_t len)
similarity index 50%
rename from lib/core-net/client.c
rename to lib/core-net/client/client.c
index 873478b..e3bc6d5 100644 (file)
@@ -1,28 +1,32 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
+#if defined(LWS_CLIENT_HTTP_PROXYING)
 
-LWS_VISIBLE int
+int
 lws_set_proxy(struct lws_vhost *vhost, const char *proxy)
 {
        char authstring[96];
@@ -39,17 +43,17 @@ lws_set_proxy(struct lws_vhost *vhost, const char *proxy)
        p = strrchr(proxy, '@');
        if (p) { /* auth is around */
 
-               if ((unsigned int)(p - proxy) > sizeof(authstring) - 1)
+               if (lws_ptr_diff_size_t(p, proxy) > sizeof(authstring) - 1)
                        goto auth_too_long;
 
-               lws_strncpy(authstring, proxy, p - proxy + 1);
+               lws_strncpy(authstring, proxy, lws_ptr_diff_size_t(p, proxy) + 1);
                // null termination not needed on input
                if (lws_b64_encode_string(authstring, lws_ptr_diff(p, proxy),
                                vhost->proxy_basic_auth_token,
                    sizeof vhost->proxy_basic_auth_token) < 0)
                        goto auth_too_long;
 
-               lwsl_info(" Proxy auth in use\n");
+               lwsl_vhost_info(vhost, " Proxy auth in use");
 
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
                proxy = p + 1;
@@ -84,7 +88,7 @@ lws_set_proxy(struct lws_vhost *vhost, const char *proxy)
 
                p = strchr(vhost->http.http_proxy_address, ']');
                if (!p) {
-                       lwsl_err("%s: malformed proxy '%s'\n", __func__, proxy);
+                       lwsl_vhost_err(vhost, "malformed proxy '%s'", proxy);
 
                        return -1;
                }
@@ -94,24 +98,24 @@ lws_set_proxy(struct lws_vhost *vhost, const char *proxy)
 
        p = strchr(p, ':');
        if (!p && !vhost->http.http_proxy_port) {
-               lwsl_err("http_proxy needs to be ads:port\n");
+               lwsl_vhost_err(vhost, "http_proxy needs to be ads:port");
 
                return -1;
        }
        if (p) {
                *p = '\0';
-               vhost->http.http_proxy_port = atoi(p + 1);
+               vhost->http.http_proxy_port = (unsigned int)atoi(p + 1);
        }
 
-       lwsl_info(" Proxy %s:%u\n", vhost->http.http_proxy_address,
-                 vhost->http.http_proxy_port);
+       lwsl_vhost_info(vhost, " Proxy %s:%u", vhost->http.http_proxy_address,
+                                           vhost->http.http_proxy_port);
 #endif
 
        return 0;
 
 auth_too_long:
-       lwsl_err("proxy auth too long\n");
+       lwsl_vhost_err(vhost, "proxy auth too long");
 
        return -1;
 }
-
+#endif
diff --git a/lib/core-net/client/conmon.c b/lib/core-net/client/conmon.c
new file mode 100644 (file)
index 0000000..21f67c9
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Client Connection Latency and DNS reporting
+ */
+
+/*
+ * We want to allocate copies for and append DNS results that we don't already
+ * have.  We take this approach because a) we may be getting duplicated results
+ * from multiple DNS servers, and b) we may be getting results stacatto over
+ * time.
+ *
+ * We capture DNS results from either getaddrinfo or ASYNC_DNS the same here,
+ * before they are sorted and filtered.
+ *
+ * Because this is relatively expensive, we only do it on client wsi that
+ * explicitly indicated that they want it with the LCCSCF_CONMON flag.
+ */
+
+#include <private-lib-core.h>
+
+int
+lws_conmon_append_copy_new_dns_results(struct lws *wsi,
+                                      const struct addrinfo *cai)
+{
+       if (!(wsi->flags & LCCSCF_CONMON))
+               return 0;
+
+       /*
+        * Let's go through the incoming guys, seeing if we already have them,
+        * or if we want to take a copy
+        */
+
+       while (cai) {
+               struct addrinfo *ai = wsi->conmon.dns_results_copy;
+               char skip = 0;
+
+               /* do we already have this guy? */
+
+               while (ai) {
+
+                       if (ai->ai_family != cai->ai_family &&
+                           ai->ai_addrlen != cai->ai_addrlen &&
+                           ai->ai_protocol != cai->ai_protocol &&
+                           ai->ai_socktype != cai->ai_socktype &&
+                           /* either ipv4 or v6 address must match */
+                           ((ai->ai_family == AF_INET &&
+                             ((struct sockaddr_in *)ai->ai_addr)->
+                                                            sin_addr.s_addr ==
+                             ((struct sockaddr_in *)cai->ai_addr)->
+                                                            sin_addr.s_addr)
+#if defined(LWS_WITH_IPV6)
+                                           ||
+                           (ai->ai_family == AF_INET6 &&
+                            !memcmp(((struct sockaddr_in6 *)ai->ai_addr)->
+                                                            sin6_addr.s6_addr,
+                                    ((struct sockaddr_in6 *)cai->ai_addr)->
+                                                    sin6_addr.s6_addr, 16))
+#endif
+                           )) {
+                               /* yes, we already got a copy then */
+                               skip = 1;
+                               break;
+                       }
+
+                       ai = ai->ai_next;
+               }
+
+               if (!skip) {
+                       /*
+                        * No we don't already have a copy of this one, let's
+                        * allocate and append it then
+                        */
+                       size_t al = sizeof(struct addrinfo) +
+                                   (size_t)cai->ai_addrlen;
+                       size_t cl = cai->ai_canonname ?
+                                       strlen(cai->ai_canonname) + 1 : 0;
+
+                       ai = lws_malloc(al + cl + 1, __func__);
+                       if (!ai) {
+                               lwsl_wsi_warn(wsi, "OOM");
+                               return 1;
+                       }
+                       *ai = *cai;
+                       ai->ai_addr = (struct sockaddr *)&ai[1];
+                       memcpy(ai->ai_addr, cai->ai_addr, (size_t)cai->ai_addrlen);
+
+                       if (cl) {
+                               ai->ai_canonname = ((char *)ai->ai_addr) +
+                                                       cai->ai_addrlen;
+                               memcpy(ai->ai_canonname, cai->ai_canonname,
+                                      cl + 1);
+                       }
+                       ai->ai_next = wsi->conmon.dns_results_copy;
+                       wsi->conmon.dns_results_copy = ai;
+               }
+
+               cai = cai->ai_next;
+       }
+
+       return 0;
+}
+
+void
+lws_conmon_addrinfo_destroy(struct addrinfo *ai)
+{
+       while (ai) {
+               struct addrinfo *ai1 = ai->ai_next;
+
+               lws_free(ai);
+               ai = ai1;
+       }
+}
+
+void
+lws_conmon_wsi_take(struct lws *wsi, struct lws_conmon *dest)
+{
+       memcpy(dest, &wsi->conmon, sizeof(*dest));
+       dest->peer46 = wsi->sa46_peer;
+
+       /* wsi no longer has to free it... */
+       wsi->conmon.dns_results_copy = NULL;
+       wsi->perf_done = 1;
+}
+
+void
+lws_conmon_release(struct lws_conmon *conmon)
+{
+       if (!conmon)
+               return;
+
+       lws_conmon_addrinfo_destroy(conmon->dns_results_copy);
+       conmon->dns_results_copy = NULL;
+}
diff --git a/lib/core-net/client/connect.c b/lib/core-net/client/connect.c
new file mode 100644 (file)
index 0000000..23c4c36
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+static const uint8_t hnames[] = {
+       _WSI_TOKEN_CLIENT_PEER_ADDRESS,
+       _WSI_TOKEN_CLIENT_URI,
+       _WSI_TOKEN_CLIENT_HOST,
+       _WSI_TOKEN_CLIENT_ORIGIN,
+       _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
+       _WSI_TOKEN_CLIENT_METHOD,
+       _WSI_TOKEN_CLIENT_IFACE,
+       _WSI_TOKEN_CLIENT_ALPN
+};
+
+struct lws *
+lws_http_client_connect_via_info2(struct lws *wsi)
+{
+       struct client_info_stash *stash = wsi->stash;
+       int n;
+
+       lwsl_wsi_debug(wsi, "stash %p", stash);
+
+       if (!stash)
+               return wsi;
+
+       wsi->a.opaque_user_data = wsi->stash->opaque_user_data;
+
+       if (stash->cis[CIS_METHOD] && (!strcmp(stash->cis[CIS_METHOD], "RAW") ||
+                                     !strcmp(stash->cis[CIS_METHOD], "MQTT")))
+               goto no_ah;
+
+       /*
+        * we're not necessarily in a position to action these right away,
+        * stash them... we only need during connect phase so into a temp
+        * allocated stash
+        */
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames); n++)
+               if (hnames[n] && stash->cis[n] &&
+                   lws_hdr_simple_create(wsi, hnames[n], stash->cis[n]))
+                       goto bail;
+
+#if defined(LWS_WITH_SOCKS5)
+       if (!wsi->a.vhost->socks_proxy_port)
+               lws_free_set_NULL(wsi->stash);
+#endif
+
+no_ah:
+       return lws_client_connect_2_dnsreq(wsi);
+
+bail:
+#if defined(LWS_WITH_SOCKS5)
+       if (!wsi->a.vhost->socks_proxy_port)
+               lws_free_set_NULL(wsi->stash);
+#endif
+
+       lws_free_set_NULL(wsi->stash);
+
+       return NULL;
+}
+
+int
+lws_client_stash_create(struct lws *wsi, const char **cisin)
+{
+       size_t size;
+       char *pc;
+       int n;
+
+       size = sizeof(*wsi->stash) + 1;
+
+       /*
+        * Let's overallocate the stash object with space for all the args
+        * in one hit.
+        */
+       for (n = 0; n < CIS_COUNT; n++)
+               if (cisin[n])
+                       size += strlen(cisin[n]) + 1;
+
+       if (wsi->stash)
+               lws_free_set_NULL(wsi->stash);
+
+       wsi->stash = lws_malloc(size, "client stash");
+       if (!wsi->stash)
+               return 1;
+
+       /* all the pointers default to NULL, but no need to zero the args */
+       memset(wsi->stash, 0, sizeof(*wsi->stash));
+
+       pc = (char *)&wsi->stash[1];
+
+       for (n = 0; n < CIS_COUNT; n++)
+               if (cisin[n]) {
+                       size_t mm;
+                       wsi->stash->cis[n] = pc;
+                       if (n == CIS_PATH && cisin[n][0] != '/')
+                               *pc++ = '/';
+                       mm = strlen(cisin[n]) + 1;
+                       memcpy(pc, cisin[n], mm);
+                       pc += mm;
+               }
+
+       return 0;
+}
+
+struct lws *
+lws_client_connect_via_info(const struct lws_client_connect_info *i)
+{
+       const char *local = i->protocol;
+       struct lws *wsi, *safe = NULL;
+       const struct lws_protocols *p;
+       const char *cisin[CIS_COUNT];
+       struct lws_vhost *vh;
+       int tsi;
+
+       if (i->context->requested_stop_internal_loops)
+               return NULL;
+
+       if (!i->context->protocol_init_done)
+               if (lws_protocol_init(i->context))
+                       return NULL;
+
+       /*
+        * If we have .local_protocol_name, use it to select the local protocol
+        * handler to bind to.  Otherwise use .protocol if http[s].
+        */
+       if (i->local_protocol_name)
+               local = i->local_protocol_name;
+
+       lws_context_lock(i->context, __func__);
+       /*
+        * PHASE 1: if SMP, find out the tsi related to current service thread
+        */
+
+       tsi = lws_pthread_self_to_tsi(i->context);
+       assert(tsi >= 0);
+
+       /* PHASE 2: create a bare wsi */
+
+       wsi = __lws_wsi_create_with_role(i->context, tsi, NULL, i->log_cx);
+       lws_context_unlock(i->context);
+       if (wsi == NULL)
+               return NULL;
+
+       vh = i->vhost;
+       if (!vh) {
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+               if (lws_tls_jit_trust_vhost_bind(i->context, i->address, &vh))
+#endif
+               {
+                       vh = lws_get_vhost_by_name(i->context, "default");
+                       if (!vh) {
+
+                               vh = i->context->vhost_list;
+
+                               if (!vh) { /* coverity */
+                                       lwsl_cx_err(i->context, "no vhost");
+                                       goto bail;
+                               }
+                               if (!strcmp(vh->name, "system"))
+                                       vh = vh->vhost_next;
+                       }
+               }
+       }
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       /* any of these imply we are a client wsi bound to an SS, which
+        * implies our opaque user ptr is the ss (or sspc if PROXY_LINK) handle
+        */
+       wsi->for_ss = !!(i->ssl_connection & (LCCSCF_SECSTREAM_CLIENT | LCCSCF_SECSTREAM_PROXY_LINK | LCCSCF_SECSTREAM_PROXY_ONWARD));
+       wsi->client_bound_sspc = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK); /* so wsi close understands need to remove sspc ptr to wsi */
+       wsi->client_proxy_onward = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_ONWARD);
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       wsi->fic.name = "wsi";
+       if (i->fic.fi_owner.count)
+               /*
+                * This moves all the lws_fi_t from i->fi to the vhost fi,
+                * leaving it empty
+                */
+               lws_fi_import(&wsi->fic, &i->fic);
+
+       lws_fi_inherit_copy(&wsi->fic, &i->context->fic, "wsi", i->fi_wsi_name);
+
+       if (lws_fi(&wsi->fic, "createfail"))
+               goto bail;
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       if (wsi->client_bound_sspc) {
+               lws_sspc_handle_t *fih = (lws_sspc_handle_t *)i->opaque_user_data;
+               lws_fi_inherit_copy(&wsi->fic, &fih->fic, "wsi", NULL);
+       }
+#endif
+       if (wsi->for_ss) {
+               lws_ss_handle_t *fih = (lws_ss_handle_t *)i->opaque_user_data;
+               lws_fi_inherit_copy(&wsi->fic, &fih->fic, "wsi", NULL);
+       }
+#endif
+#endif
+
+       lws_wsi_fault_timedclose(wsi);
+
+       /*
+        * Until we exit, we can report connection failure directly to the
+        * caller without needing to call through to protocol CONNECTION_ERROR.
+        */
+       wsi->client_suppress_CONNECTION_ERROR = 1;
+
+       if (i->keep_warm_secs)
+               wsi->keep_warm_secs = i->keep_warm_secs;
+       else
+               wsi->keep_warm_secs = 5;
+
+       wsi->seq = i->seq;
+       wsi->flags = i->ssl_connection;
+
+       wsi->c_pri = i->priority;
+
+       if (i->retry_and_idle_policy)
+               wsi->retry_policy = i->retry_and_idle_policy;
+       else
+               wsi->retry_policy = &i->context->default_retry;
+
+       if (i->ssl_connection & LCCSCF_WAKE_SUSPEND__VALIDITY)
+               wsi->conn_validity_wakesuspend = 1;
+
+       lws_vhost_bind_wsi(vh, wsi);
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       /* additionally inerit from vhost we bound to */
+       lws_fi_inherit_copy(&wsi->fic, &vh->fic, "wsi", i->fi_wsi_name);
+#endif
+
+       if (!wsi->a.vhost) {
+               lwsl_wsi_err(wsi, "No vhost in the context");
+
+               goto bail;
+       }
+
+       /*
+        * PHASE 3: Choose an initial role for the wsi and do role-specific init
+        *
+        * Note the initial role may not reflect the final role, eg,
+        * we may want ws, but first we have to go through h1 to get that
+        */
+
+       if (lws_role_call_client_bind(wsi, i) < 0) {
+               lwsl_wsi_err(wsi, "unable to bind to role");
+
+               goto bail;
+       }
+       lwsl_wsi_info(wsi, "role binding to %s", wsi->role_ops->name);
+
+       /*
+        * PHASE 4: fill up the wsi with stuff from the connect_info as far as
+        * it can go.  It's uncertain because not only is our connection
+        * going to complete asynchronously, we might have bound to h1 and not
+        * even be able to get ahold of an ah immediately.
+        */
+
+       wsi->user_space = NULL;
+       wsi->pending_timeout = NO_PENDING_TIMEOUT;
+       wsi->position_in_fds_table = LWS_NO_FDS_POS;
+       wsi->ocport = wsi->c_port = (uint16_t)(unsigned int)i->port;
+       wsi->sys_tls_client_cert = i->sys_tls_client_cert;
+
+#if defined(LWS_ROLE_H2)
+       wsi->txc.manual_initial_tx_credit =
+                       (int32_t)i->manual_initial_tx_credit;
+#endif
+
+       wsi->a.protocol = &wsi->a.vhost->protocols[0];
+       wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE);
+       wsi->client_no_follow_redirect = !!(i->ssl_connection &
+                                           LCCSCF_HTTP_NO_FOLLOW_REDIRECT);
+
+       /*
+        * PHASE 5: handle external user_space now, generic alloc is done in
+        * role finalization
+        */
+
+       if (i->userdata) {
+               wsi->user_space_externally_allocated = 1;
+               wsi->user_space = i->userdata;
+       }
+
+       if (local) {
+               lwsl_wsi_info(wsi, "vh %s protocol binding to %s\n",
+                               wsi->a.vhost->name, local);
+               p = lws_vhost_name_to_protocol(wsi->a.vhost, local);
+               if (p)
+                       lws_bind_protocol(wsi, p, __func__);
+               else
+                       lwsl_wsi_info(wsi, "unknown protocol %s", local);
+
+               lwsl_wsi_info(wsi, "%s: %s %s entry",
+                           lws_wsi_tag(wsi), wsi->role_ops->name,
+                           wsi->a.protocol ? wsi->a.protocol->name : "none");
+       }
+
+       /*
+        * PHASE 5: handle external user_space now, generic alloc is done in
+        * role finalization
+        */
+
+       if (!wsi->user_space && i->userdata) {
+               wsi->user_space_externally_allocated = 1;
+               wsi->user_space = i->userdata;
+       }
+
+#if defined(LWS_WITH_TLS)
+       wsi->tls.use_ssl = (unsigned int)i->ssl_connection;
+#else
+       if (i->ssl_connection & LCCSCF_USE_SSL) {
+               lwsl_wsi_err(wsi, "lws not configured for tls");
+               goto bail;
+       }
+#endif
+
+       /*
+        * PHASE 6: stash the things from connect_info that we can't process
+        * right now, eg, if http binding, without an ah.  If h1 and no ah, we
+        * will go on the ah waiting list and process those things later (after
+        * the connect_info and maybe the things pointed to have gone out of
+        * scope)
+        *
+        * However these things are stashed in a generic way at this point,
+        * with no relationship to http or ah
+        */
+
+       cisin[CIS_ADDRESS]      = i->address;
+       cisin[CIS_PATH]         = i->path;
+       cisin[CIS_HOST]         = i->host;
+       cisin[CIS_ORIGIN]       = i->origin;
+       cisin[CIS_PROTOCOL]     = i->protocol;
+       cisin[CIS_METHOD]       = i->method;
+       cisin[CIS_IFACE]        = i->iface;
+       cisin[CIS_ALPN]         = i->alpn;
+
+       if (lws_client_stash_create(wsi, cisin))
+               goto bail;
+
+#if defined(LWS_WITH_TLS)
+       if (i->alpn)
+               lws_strncpy(wsi->alpn, i->alpn, sizeof(wsi->alpn));
+#endif
+
+       wsi->a.opaque_user_data = wsi->stash->opaque_user_data =
+               i->opaque_user_data;
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+
+       if (wsi->for_ss) {
+               /* it's related to ss... the options are
+                *
+                * LCCSCF_SECSTREAM_PROXY_LINK  : client SSPC link to proxy
+                * LCCSCF_SECSTREAM_PROXY_ONWARD: proxy's onward connection
+                */
+               __lws_lc_tag(i->context, &i->context->lcg[
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+                        i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK ? LWSLCG_WSI_SSP_CLIENT :
+#if defined(LWS_WITH_SERVER)
+                        (i->ssl_connection & LCCSCF_SECSTREAM_PROXY_ONWARD ? LWSLCG_WSI_SSP_ONWARD :
+#endif
+                         LWSLCG_WSI_CLIENT
+#if defined(LWS_WITH_SERVER)
+                         )
+#endif
+               ],
+#else
+                               LWSLCG_WSI_CLIENT],
+#endif
+                       &wsi->lc, "%s/%s/%s/(%s)", i->method ? i->method : "WS",
+                       wsi->role_ops->name, i->address,
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+                       wsi->client_bound_sspc ?
+                               lws_sspc_tag((lws_sspc_handle_t *)i->opaque_user_data) :
+#endif
+                       lws_ss_tag(((lws_ss_handle_t *)i->opaque_user_data)));
+       } else
+#endif
+               __lws_lc_tag(i->context, &i->context->lcg[LWSLCG_WSI_CLIENT], &wsi->lc,
+                            "%s/%s/%s/%s", i->method ? i->method : "WS",
+                            wsi->role_ops->name ? wsi->role_ops->name : "novh", vh->name, i->address);
+
+       lws_metrics_tag_wsi_add(wsi, "vh", wsi->a.vhost->name);
+
+       /*
+        * at this point user callbacks like
+        * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER will be interested to
+        * know the parent... eg for proxying we can grab extra headers from
+        * the parent's incoming ah and add them to the child client handshake
+        */
+
+       if (i->parent_wsi) {
+               lwsl_wsi_info(wsi, "created as child %s",
+                             lws_wsi_tag(i->parent_wsi));
+               wsi->parent = i->parent_wsi;
+               safe = wsi->sibling_list = i->parent_wsi->child_list;
+               i->parent_wsi->child_list = wsi;
+       }
+
+       /*
+        * PHASE 7: Do any role-specific finalization processing.  We can still
+        * see important info things via wsi->stash
+        */
+
+       if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_client_bind)) {
+
+               int n = lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_client_bind).
+                                                       client_bind(wsi, NULL);
+
+               if (n && i->parent_wsi)
+                       /* unpick from parent */
+                       i->parent_wsi->child_list = safe;
+
+               if (n < 0)
+                       /* we didn't survive, wsi is freed */
+                       goto bail2;
+
+               if (n)
+                       /* something else failed, wsi needs freeing */
+                       goto bail;
+       }
+
+       /* let the caller's optional wsi storage have the wsi we created */
+
+       if (i->pwsi)
+               *i->pwsi = wsi;
+
+       if (!wsi->a.protocol)
+               /* we must have one protocol or another bound by this point */
+               goto bail;
+
+       /* PHASE 8: notify protocol with role-specific connected callback */
+
+       /* raw socket per se doesn't want this... raw socket proxy wants it... */
+
+       if (wsi->role_ops != &role_ops_raw_skt ||
+           (i->local_protocol_name &&
+            !strcmp(i->local_protocol_name, "raw-proxy"))) {
+               lwsl_wsi_debug(wsi, "adoption cb %d to %s %s",
+                          wsi->role_ops->adoption_cb[0],
+                          wsi->role_ops->name, wsi->a.protocol->name);
+
+               wsi->a.protocol->callback(wsi, wsi->role_ops->adoption_cb[0],
+                               wsi->user_space, NULL, 0);
+       }
+
+#if defined(LWS_WITH_HUBBUB)
+       if (i->uri_replace_to)
+               wsi->http.rw = lws_rewrite_create(wsi, html_parser_cb,
+                                            i->uri_replace_from,
+                                            i->uri_replace_to);
+#endif
+
+       if (i->method && (!strcmp(i->method, "RAW") // ||
+//                       !strcmp(i->method, "MQTT")
+       )) {
+
+               /*
+                * Not for MQTT here, since we don't know if we will
+                * pipeline it or not...
+                */
+
+#if defined(LWS_WITH_TLS)
+
+               wsi->tls.ssl = NULL;
+
+               if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
+                       const char *cce = NULL;
+
+                       switch (
+#if !defined(LWS_WITH_SYS_ASYNC_DNS)
+                       lws_client_create_tls(wsi, &cce, 1)
+#else
+                       lws_client_create_tls(wsi, &cce, 0)
+#endif
+                       ) {
+                       case 1:
+                               return wsi;
+                       case 0:
+                               break;
+                       default:
+                               goto bail3;
+                       }
+               }
+#endif
+
+
+               /* fallthru */
+
+               wsi = lws_http_client_connect_via_info2(wsi);
+       }
+
+       if (wsi)
+               /*
+                * If it subsequently fails, report CONNECTION_ERROR,
+                * because we're going to return a non-error return now.
+                */
+               wsi->client_suppress_CONNECTION_ERROR = 0;
+
+       return wsi;
+
+#if defined(LWS_WITH_TLS)
+bail3:
+       lwsl_wsi_info(wsi, "tls start fail");
+       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "tls start fail");
+
+       if (i->pwsi)
+               *i->pwsi = NULL;
+
+       return NULL;
+#endif
+
+bail:
+#if defined(LWS_WITH_TLS)
+       if (wsi->tls.ssl)
+               lws_tls_restrict_return(wsi);
+#endif
+
+       lws_free_set_NULL(wsi->stash);
+       lws_fi_destroy(&wsi->fic);
+       lws_free(wsi);
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+bail2:
+#endif
+
+       if (i->pwsi)
+               *i->pwsi = NULL;
+
+       return NULL;
+}
diff --git a/lib/core-net/client/connect2.c b/lib/core-net/client/connect2.c
new file mode 100644 (file)
index 0000000..0ccb3cb
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+#if !defined(WIN32)
+#include <netdb.h>
+#endif
+
+#if !defined(LWS_WITH_SYS_ASYNC_DNS)
+static int
+lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)
+{
+       lws_metrics_caliper_declare(cal, wsi->a.context->mt_conn_dns);
+       struct addrinfo hints;
+#if defined(LWS_WITH_SYS_METRICS)
+       char buckname[32];
+#endif
+       int n;
+
+       memset(&hints, 0, sizeof(hints));
+       *result = NULL;
+
+       hints.ai_socktype = SOCK_STREAM;
+
+#ifdef LWS_WITH_IPV6
+       if (wsi->ipv6) {
+
+#if !defined(__ANDROID__)
+               hints.ai_family = AF_UNSPEC;
+#if !defined(__OpenBSD__) && !defined(__OPENBSD)
+               hints.ai_flags = AI_V4MAPPED;
+#endif
+#endif
+       } else
+#endif
+       {
+               hints.ai_family = PF_UNSPEC;
+       }
+
+#if defined(LWS_WITH_CONMON)
+       wsi->conmon_datum = lws_now_usecs();
+#endif
+
+       wsi->dns_reachability = 0;
+       if (lws_fi(&wsi->fic, "dnsfail"))
+               n = EAI_FAIL;
+       else
+               n = getaddrinfo(ads, NULL, &hints, result);
+
+#if defined(LWS_WITH_CONMON)
+       wsi->conmon.ciu_dns = (lws_conmon_interval_us_t)
+                                       (lws_now_usecs() - wsi->conmon_datum);
+#endif
+
+       /*
+        * Which EAI_* are available and the meanings are highly platform-
+        * dependent, even different linux distros differ.
+        */
+
+       if (0
+#if defined(EAI_SYSTEM)
+                       || n == EAI_SYSTEM
+#endif
+#if defined(EAI_NODATA)
+                       || n == EAI_NODATA
+#endif
+#if defined(EAI_FAIL)
+                       || n == EAI_FAIL
+#endif
+#if defined(EAI_AGAIN)
+                       || n == EAI_AGAIN
+#endif
+                       ) {
+               wsi->dns_reachability = 1;
+               lws_metrics_caliper_report(cal, METRES_NOGO);
+#if defined(LWS_WITH_SYS_METRICS)
+               lws_snprintf(buckname, sizeof(buckname), "dns=\"unreachable %d\"", n);
+               lws_metrics_hist_bump_priv_wsi(wsi, mth_conn_failures, buckname);
+#endif
+
+#if defined(LWS_WITH_CONMON)
+               wsi->conmon.dns_disposition = LWSCONMON_DNS_SERVER_UNREACHABLE;
+#endif
+
+#if 0
+               lwsl_wsi_debug(wsi, "asking to recheck CPD in 1s");
+               lws_system_cpd_start_defer(wsi->a.context, LWS_US_PER_SEC);
+#endif
+       }
+
+       lwsl_wsi_info(wsi, "getaddrinfo '%s' says %d", ads, n);
+
+#if defined(LWS_WITH_SYS_METRICS)
+       if (n < 0) {
+               lws_snprintf(buckname, sizeof(buckname), "dns=\"nores %d\"", n);
+               lws_metrics_hist_bump_priv_wsi(wsi, mth_conn_failures, buckname);
+       }
+#endif
+#if defined(LWS_WITH_CONMON)
+       wsi->conmon.dns_disposition = n < 0 ? LWSCONMON_DNS_NO_RESULT :
+                                             LWSCONMON_DNS_OK;
+#endif
+
+       lws_metrics_caliper_report(cal, n >= 0 ? METRES_GO : METRES_NOGO);
+
+       return n;
+}
+#endif
+
+#if !defined(LWS_WITH_SYS_ASYNC_DNS) && defined(EAI_NONAME)
+static const char * const dns_nxdomain = "DNS NXDOMAIN";
+#endif
+
+struct lws *
+lws_client_connect_2_dnsreq(struct lws *wsi)
+{
+       struct addrinfo *result = NULL;
+       const char *meth = NULL;
+#if defined(LWS_WITH_IPV6)
+       struct sockaddr_in addr;
+       const char *iface;
+#endif
+       const char *adsin;
+       int n, port = 0;
+       struct lws *w;
+
+       if (lwsi_state(wsi) == LRS_WAITING_DNS ||
+           lwsi_state(wsi) == LRS_WAITING_CONNECT) {
+               lwsl_wsi_info(wsi, "LRS_WAITING_DNS / CONNECT");
+
+               return wsi;
+       }
+
+       /*
+        * clients who will create their own fresh connection keep a copy of
+        * the hostname they originally connected to, in case other connections
+        * want to use it too
+        */
+
+       if (!wsi->cli_hostname_copy) {
+               const char *pa = lws_wsi_client_stash_item(wsi, CIS_HOST,
+                                       _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+
+               if (pa)
+                       wsi->cli_hostname_copy = lws_strdup(pa);
+       }
+
+       /*
+        * The first job is figure out if we want to pipeline on or just join
+        * an existing "active connection" to the same place
+        */
+
+       meth = lws_wsi_client_stash_item(wsi, CIS_METHOD,
+                                        _WSI_TOKEN_CLIENT_METHOD);
+       /* consult active connections to find out disposition */
+
+       adsin = lws_wsi_client_stash_item(wsi, CIS_ADDRESS,
+                                         _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+
+       /* we only pipeline connections that said it was okay */
+
+       if (!wsi->client_pipeline) {
+               lwsl_wsi_debug(wsi, "new conn on no pipeline flag");
+
+               goto solo;
+       }
+
+       /* only pipeline things we associate with being a stream */
+
+       if (meth && strcmp(meth, "RAW") && strcmp(meth, "GET") &&
+                   strcmp(meth, "POST") && strcmp(meth, "PUT") &&
+                   strcmp(meth, "UDP") && strcmp(meth, "MQTT"))
+               goto solo;
+
+       if (!adsin)
+               /*
+                * This cannot happen since user code must provide the client
+                * address to get this far, it's here to satisfy Coverity
+                */
+               return NULL;
+
+       switch (lws_vhost_active_conns(wsi, &w, adsin)) {
+       case ACTIVE_CONNS_SOLO:
+               break;
+       case ACTIVE_CONNS_MUXED:
+               lwsl_wsi_notice(wsi, "ACTIVE_CONNS_MUXED");
+               if (lwsi_role_h2(wsi)) {
+
+                       if (wsi->a.protocol->callback(wsi,
+                                       LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
+                                       wsi->user_space, NULL, 0))
+                               goto failed1;
+
+                       //lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
+                       //lwsi_set_state(w, LRS_ESTABLISHED);
+                       lws_callback_on_writable(wsi);
+               }
+
+               return wsi;
+       case ACTIVE_CONNS_QUEUED:
+               lwsl_wsi_debug(wsi, "ACTIVE_CONNS_QUEUED st 0x%x: ",
+                                                       lwsi_state(wsi));
+
+               if (lwsi_state(wsi) == LRS_UNCONNECTED) {
+                       if (lwsi_role_h2(w))
+                               lwsi_set_state(wsi,
+                                              LRS_H2_WAITING_TO_SEND_HEADERS);
+                       else
+                               lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
+               }
+
+               return lws_client_connect_4_established(wsi, w, 0);
+       }
+
+solo:
+
+       /*
+        * If we made our own connection, and we're doing a method that can
+        * take a pipeline, we are an "active client connection".
+        *
+        * Add ourselves to the vhost list of those so that others can
+        * piggyback on our transaction queue
+        */
+
+       if (meth && (!strcmp(meth, "RAW") || !strcmp(meth, "GET") ||
+                    !strcmp(meth, "POST") || !strcmp(meth, "PUT") ||
+                    !strcmp(meth, "MQTT")) &&
+           lws_dll2_is_detached(&wsi->dll2_cli_txn_queue) &&
+           lws_dll2_is_detached(&wsi->dll_cli_active_conns)) {
+               lws_context_lock(wsi->a.context, __func__);
+               lws_vhost_lock(wsi->a.vhost);
+               lwsl_wsi_info(wsi, "adding as active conn");
+               /* caution... we will have to unpick this on oom4 path */
+               lws_dll2_add_head(&wsi->dll_cli_active_conns,
+                                &wsi->a.vhost->dll_cli_active_conns_owner);
+               lws_vhost_unlock(wsi->a.vhost);
+               lws_context_unlock(wsi->a.context);
+       }
+
+       /*
+        * Since address must be given at client creation, should not be
+        * possible, but necessary to satisfy coverity
+        */
+       if (!adsin)
+               return NULL;
+
+#if defined(LWS_WITH_UNIX_SOCK)
+       /*
+        * unix socket destination?
+        */
+
+       if (*adsin == '+') {
+               wsi->unix_skt = 1;
+               n = 0;
+               goto next_step;
+       }
+#endif
+
+       /*
+        * start off allowing ipv6 on connection if vhost allows it
+        */
+       wsi->ipv6 = LWS_IPV6_ENABLED(wsi->a.vhost);
+#ifdef LWS_WITH_IPV6
+       if (wsi->stash)
+               iface = wsi->stash->cis[CIS_IFACE];
+       else
+               iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
+
+       if (wsi->ipv6 && iface &&
+           inet_pton(AF_INET, iface, &addr.sin_addr) == 1) {
+               lwsl_wsi_notice(wsi, "client connection forced to IPv4");
+               wsi->ipv6 = 0;
+       }
+#endif
+
+#if defined(LWS_CLIENT_HTTP_PROXYING) && \
+       (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
+
+       /* Decide what it is we need to connect to:
+        *
+        * Priority 1: connect to http proxy */
+
+       if (wsi->a.vhost->http.http_proxy_port) {
+               adsin = wsi->a.vhost->http.http_proxy_address;
+               port = (int)wsi->a.vhost->http.http_proxy_port;
+#else
+               if (0) {
+#endif
+
+#if defined(LWS_WITH_SOCKS5)
+
+       /* Priority 2: Connect to SOCK5 Proxy */
+
+       } else if (wsi->a.vhost->socks_proxy_port) {
+               lwsl_wsi_client(wsi, "Sending SOCKS Greeting");
+               adsin = wsi->a.vhost->socks_proxy_address;
+               port = (int)wsi->a.vhost->socks_proxy_port;
+#endif
+       } else {
+
+               /* Priority 3: Connect directly */
+
+               /* ads already set */
+               port = wsi->c_port;
+       }
+
+       /*
+        * prepare the actual connection
+        * to whatever we decided to connect to
+        */
+       lwsi_set_state(wsi, LRS_WAITING_DNS);
+
+       lwsl_wsi_info(wsi, "lookup %s:%u", adsin, port);
+       wsi->conn_port = (uint16_t)port;
+
+#if !defined(LWS_WITH_SYS_ASYNC_DNS)
+       n = 0;
+       if (!wsi->dns_sorted_list.count) {
+               /*
+                * blocking dns resolution
+                */
+               n = lws_getaddrinfo46(wsi, adsin, &result);
+#if defined(EAI_NONAME)
+               if (n == EAI_NONAME) {
+                       /*
+                        * The DNS server responded with NXDOMAIN... even
+                        * though this is still in the client creation call,
+                        * we need to make a CCE, otherwise there won't be
+                        * any user indication of what went wrong
+                        */
+                       wsi->client_suppress_CONNECTION_ERROR = 0;
+                       lws_inform_client_conn_fail(wsi, (void *)dns_nxdomain,
+                                                   strlen(dns_nxdomain));
+                       goto failed1;
+               }
+#endif
+       }
+#else
+       /* this is either FAILED, CONTINUING, or already called connect_4 */
+
+       if (lws_fi(&wsi->fic, "dnsfail"))
+               return lws_client_connect_3_connect(wsi, NULL, NULL, -4, NULL);
+       else
+               n = lws_async_dns_query(wsi->a.context, wsi->tsi, adsin,
+                               LWS_ADNS_RECORD_A, lws_client_connect_3_connect,
+                               wsi, NULL);
+
+       if (n == LADNS_RET_FAILED_WSI_CLOSED)
+               return NULL;
+
+       if (n == LADNS_RET_FAILED)
+               goto failed1;
+
+       return wsi;
+#endif
+
+#if defined(LWS_WITH_UNIX_SOCK)
+next_step:
+#endif
+       return lws_client_connect_3_connect(wsi, adsin, result, n, NULL);
+
+//#if defined(LWS_WITH_SYS_ASYNC_DNS)
+failed1:
+       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
+
+       return NULL;
+//#endif
+}
diff --git a/lib/core-net/client/connect3.c b/lib/core-net/client/connect3.c
new file mode 100644 (file)
index 0000000..a310216
--- /dev/null
@@ -0,0 +1,714 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+void
+lws_client_conn_wait_timeout(lws_sorted_usec_list_t *sul)
+{
+       struct lws *wsi = lws_container_of(sul, struct lws,
+                                          sul_connect_timeout);
+
+       /*
+        * This is used to constrain the time we're willing to wait for a
+        * connection before giving up on it and retrying.
+        */
+
+       lwsl_wsi_info(wsi, "connect wait timeout has fired");
+       lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL);
+}
+
+void
+lws_client_dns_retry_timeout(lws_sorted_usec_list_t *sul)
+{
+       struct lws *wsi = lws_container_of(sul, struct lws,
+                                          sul_connect_timeout);
+
+       /*
+        * This limits the amount of dns lookups we will try before
+        * giving up and failing... it reuses sul_connect_timeout, which
+        * isn't officially used until we connected somewhere.
+        */
+
+       lwsl_wsi_info(wsi, "dns retry");
+       if (!lws_client_connect_2_dnsreq(wsi))
+               lwsl_wsi_notice(wsi, "DNS lookup failed");
+}
+
+/*
+ * Figure out if an ongoing connect() has arrived at a final disposition or not
+ *
+ * We can check using getsockopt if our connect actually completed.
+ * Posix connect() allows nonblocking to redo the connect to
+ * find out if it succeeded.
+ */
+
+typedef enum {
+       LCCCR_CONNECTED                 = 1,
+       LCCCR_CONTINUE                  = 0,
+       LCCCR_FAILED                    = -1,
+} lcccr_t;
+
+static lcccr_t
+lws_client_connect_check(struct lws *wsi)
+{
+       int en = 0;
+#if !defined(WIN32)
+       int e;
+       socklen_t sl = sizeof(e);
+#endif
+
+       (void)en;
+
+       /*
+        * This resets SO_ERROR after reading it.  If there's an error
+        * condition, the connect definitively failed.
+        */
+
+#if !defined(WIN32)
+       if (!getsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_ERROR, &e, &sl)) {
+               en = LWS_ERRNO;
+               if (!e) {
+                       lwsl_wsi_debug(wsi, "getsockopt: conn OK errno %d", en);
+
+                       return LCCCR_CONNECTED;
+               }
+
+               lwsl_wsi_notice(wsi, "getsockopt fd %d says e %d",
+                                                       wsi->desc.sockfd, e);
+
+               return LCCCR_FAILED;
+       }
+
+#else
+
+       if (!connect(wsi->desc.sockfd, NULL, 0))
+               return LCCCR_CONNECTED;
+
+       en = LWS_ERRNO;
+
+       if (en == WSAEISCONN) /* already connected */
+               return LCCCR_CONNECTED;
+
+       if (en == WSAEALREADY) {
+               /* reset the POLLOUT wait */
+               if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
+                       lwsl_wsi_notice(wsi, "pollfd failed");
+       }
+
+       if (!en || en == WSAEINVAL ||
+                  en == WSAEWOULDBLOCK ||
+                  en == WSAEALREADY) {
+               lwsl_wsi_debug(wsi, "errno %d", en);
+               return LCCCR_CONTINUE;
+       }
+#endif
+
+       lwsl_wsi_notice(wsi, "connect check take as FAILED: errno %d", en);
+
+       return LCCCR_FAILED;
+}
+
+/*
+ * We come here to fire off a connect, and to check its disposition later.
+ *
+ * If it did not complete before the individual attempt timeout, we will try to
+ * connect again with the next dns result.
+ */
+
+struct lws *
+lws_client_connect_3_connect(struct lws *wsi, const char *ads,
+                            const struct addrinfo *result, int n, void *opaque)
+{
+#if defined(LWS_WITH_UNIX_SOCK)
+       struct sockaddr_un sau;
+#endif
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       const char *cce = "Unable to connect", *iface;
+       const struct sockaddr *psa = NULL;
+       uint16_t port = wsi->conn_port;
+       lws_dns_sort_t *curr;
+       ssize_t plen = 0;
+       lws_dll2_t *d;
+       char dcce[48];
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       int cfail;
+#endif
+       int m, af = 0;
+
+       /*
+        * If we come here with result set, we need to convert getaddrinfo
+        * results to a lws_dns_sort_t list one time and free the results.
+        *
+        * We use this pattern because ASYNC_DNS will callback here with the
+        * results when it gets them (and may come here more than once, eg, for
+        * AAAA then A or vice-versa)
+        */
+
+       if (result) {
+               lws_sul_cancel(&wsi->sul_connect_timeout);
+
+#if defined(LWS_WITH_CONMON)
+               /* append a copy from before the sorting */
+               lws_conmon_append_copy_new_dns_results(wsi, result);
+#endif
+
+               lws_sort_dns(wsi, result);
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+               lws_async_dns_freeaddrinfo(&result);
+#else
+               freeaddrinfo((struct addrinfo *)result);
+#endif
+               result = NULL;
+       }
+
+#if defined(LWS_WITH_UNIX_SOCK)
+       memset(&sau, 0, sizeof(sau));
+#endif
+
+       /*
+        * async dns calls back here for everybody who cares when it gets a
+        * result... but if we are piggybacking, we do not want to connect
+        * ourselves
+        */
+
+       if (!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue))
+               return wsi;
+
+       if (n &&  /* calling back with a problem */
+           !wsi->dns_sorted_list.count && /* there's no results */
+           !lws_socket_is_valid(wsi->desc.sockfd) && /* no attempt ongoing */
+           !wsi->speculative_connect_owner.count /* no spec attempt */ ) {
+               lwsl_wsi_notice(wsi, "dns lookup failed %d", n);
+
+               /*
+                * DNS lookup itself failed... let's try again until we
+                * timeout
+                */
+
+               lwsi_set_state(wsi, LRS_UNCONNECTED);
+               lws_sul_schedule(wsi->a.context, 0, &wsi->sul_connect_timeout,
+                                lws_client_dns_retry_timeout,
+                                                LWS_USEC_PER_SEC);
+               return wsi;
+
+//             cce = "dns lookup failed";
+//             goto oom4;
+       }
+
+       /*
+        * We come back here again when we think the connect() may have
+        * completed one way or the other, we can't proceed until we know we
+        * actually connected.
+        */
+
+       if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
+           lws_socket_is_valid(wsi->desc.sockfd)) {
+
+               if (!wsi->dns_sorted_list.count &&
+                   !wsi->sul_connect_timeout.list.owner)
+                       /* no dns results and no ongoing timeout for one */
+                       goto connect_to;
+
+               switch (lws_client_connect_check(wsi)) {
+               case LCCCR_CONNECTED:
+                       /*
+                        * Oh, it has happened...
+                        */
+                       goto conn_good;
+               case LCCCR_CONTINUE:
+                       return NULL;
+               default:
+                       lws_snprintf(dcce, sizeof(dcce), "conn fail: errno %d",
+                                                               LWS_ERRNO);
+                       cce = dcce;
+                       lwsl_wsi_debug(wsi, "%s", dcce);
+                       lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
+                       goto try_next_dns_result_fds;
+               }
+       }
+
+#if defined(LWS_WITH_UNIX_SOCK)
+
+       if (ads && *ads == '+') {
+               ads++;
+               memset(&wsi->sa46_peer, 0, sizeof(wsi->sa46_peer));
+               af = sau.sun_family = AF_UNIX;
+               strncpy(sau.sun_path, ads, sizeof(sau.sun_path));
+               sau.sun_path[sizeof(sau.sun_path) - 1] = '\0';
+
+               lwsl_wsi_info(wsi, "Unix skt: %s", ads);
+
+               if (sau.sun_path[0] == '@')
+                       sau.sun_path[0] = '\0';
+
+               goto ads_known;
+       }
+#endif
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       if (n == LADNS_RET_FAILED) {
+               lwsl_wsi_notice(wsi, "adns failed %s", ads);
+               /*
+                * Caller that is giving us LADNS_RET_FAILED will deal
+                * with cleanup
+                */
+               return NULL;
+       }
+#endif
+
+       /*
+        * Let's try directly connecting to each of the results in turn until
+        * one works, or we run out of results...
+        *
+        * We have a sorted dll2 list with the head one most preferable
+        */
+
+next_dns_result:
+
+       cce = "Unable to connect";
+
+       if (!wsi->dns_sorted_list.count)
+               goto failed1;
+
+       /*
+        * Copy the wsi head sorted dns result into the wsi->sa46_peer, and
+        * remove and free the original from the sorted list
+        */
+
+       d = lws_dll2_get_head(&wsi->dns_sorted_list);
+       curr = lws_container_of(d, lws_dns_sort_t, list);
+
+       lws_dll2_remove(&curr->list);
+       wsi->sa46_peer = curr->dest;
+#if defined(LWS_WITH_NETLINK)
+       wsi->peer_route_uidx = curr->uidx;
+       lwsl_wsi_info(wsi, "peer_route_uidx %d", wsi->peer_route_uidx);
+#endif
+
+       lws_free(curr);
+
+       sa46_sockport(&wsi->sa46_peer, htons(port));
+
+       psa = sa46_sockaddr(&wsi->sa46_peer);
+       n = (int)sa46_socklen(&wsi->sa46_peer);
+
+#if defined(LWS_WITH_UNIX_SOCK)
+ads_known:
+#endif
+
+       /*
+        * Now we prepared psa, if not already connecting, create the related
+        * socket and add to the fds
+        */
+
+       if (!lws_socket_is_valid(wsi->desc.sockfd)) {
+
+               if (wsi->a.context->event_loop_ops->check_client_connect_ok &&
+                   wsi->a.context->event_loop_ops->check_client_connect_ok(wsi)
+               ) {
+                       cce = "waiting for event loop watcher to close";
+                       goto oom4;
+               }
+
+#if defined(LWS_WITH_UNIX_SOCK)
+               af = 0;
+               if (wsi->unix_skt) {
+                       af = AF_UNIX;
+                       wsi->desc.sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+               }
+               else
+#endif
+               {
+                       af = wsi->sa46_peer.sa4.sin_family;
+                       wsi->desc.sockfd = socket(wsi->sa46_peer.sa4.sin_family,
+                                                 SOCK_STREAM, 0);
+               }
+
+               if (!lws_socket_is_valid(wsi->desc.sockfd)) {
+                       lws_snprintf(dcce, sizeof(dcce),
+                                    "conn fail: skt creation: errno %d",
+                                                               LWS_ERRNO);
+                       cce = dcce;
+                       lwsl_wsi_warn(wsi, "%s", dcce);
+                       goto try_next_dns_result;
+               }
+
+               if (lws_plat_set_socket_options(wsi->a.vhost, wsi->desc.sockfd,
+#if defined(LWS_WITH_UNIX_SOCK)
+                                               wsi->unix_skt)) {
+#else
+                                               0)) {
+#endif
+                       lws_snprintf(dcce, sizeof(dcce),
+                                    "conn fail: skt options: errno %d",
+                                                               LWS_ERRNO);
+                       cce = dcce;
+                       lwsl_wsi_warn(wsi, "%s", dcce);
+                       goto try_next_dns_result_closesock;
+               }
+
+               /* apply requested socket options */
+               if (lws_plat_set_socket_options_ip(wsi->desc.sockfd,
+                                                  wsi->c_pri, wsi->flags))
+                       lwsl_wsi_warn(wsi, "unable to set ip options");
+
+               lwsl_wsi_debug(wsi, "WAITING_CONNECT");
+               lwsi_set_state(wsi, LRS_WAITING_CONNECT);
+
+               if (wsi->a.context->event_loop_ops->sock_accept)
+                       if (wsi->a.context->event_loop_ops->sock_accept(wsi)) {
+                               lws_snprintf(dcce, sizeof(dcce),
+                                            "conn fail: sock accept");
+                               cce = dcce;
+                               lwsl_wsi_warn(wsi, "%s", dcce);
+                               goto try_next_dns_result_closesock;
+                       }
+
+               lws_pt_lock(pt, __func__);
+               if (__insert_wsi_socket_into_fds(wsi->a.context, wsi)) {
+                       lws_snprintf(dcce, sizeof(dcce),
+                                    "conn fail: insert fd");
+                       cce = dcce;
+                       lws_pt_unlock(pt);
+                       goto try_next_dns_result_closesock;
+               }
+               lws_pt_unlock(pt);
+
+               /*
+                * The fd + wsi combination is entered into the wsi tables
+                * at this point, with a pollfd
+                *
+                * Past here, we can't simply free the structs as error
+                * handling as oom4 does.
+                *
+                * We can run the whole close flow, or unpick the fds inclusion
+                * and anything else we have done.
+                */
+
+               if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
+                       lws_snprintf(dcce, sizeof(dcce),
+                                    "conn fail: change pollfd");
+                       cce = dcce;
+                       goto try_next_dns_result_fds;
+               }
+
+               if (!wsi->a.protocol)
+                       wsi->a.protocol = &wsi->a.vhost->protocols[0];
+
+               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
+                               wsi->a.vhost->connect_timeout_secs);
+
+               iface = lws_wsi_client_stash_item(wsi, CIS_IFACE,
+                                                 _WSI_TOKEN_CLIENT_IFACE);
+
+               if (iface && *iface) {
+                       m = lws_socket_bind(wsi->a.vhost, wsi, wsi->desc.sockfd,
+                                           0, iface, af);
+                       if (m < 0) {
+                               lws_snprintf(dcce, sizeof(dcce),
+                                            "conn fail: socket bind");
+                               cce = dcce;
+                               goto try_next_dns_result_fds;
+                       }
+               }
+       }
+
+#if defined(LWS_WITH_UNIX_SOCK)
+       if (wsi->unix_skt) {
+               psa = (const struct sockaddr *)&sau;
+               if (sau.sun_path[0])
+                       n = (int)(sizeof(uint16_t) + strlen(sau.sun_path));
+               else
+                       n = (int)(sizeof(uint16_t) +
+                                       strlen(&sau.sun_path[1]) + 1);
+       } else
+#endif
+
+       if (!psa) /* coverity */
+               goto try_next_dns_result_fds;
+
+       /*
+        * The actual connection attempt
+        */
+
+#if defined(LWS_ESP_PLATFORM)
+       errno = 0;
+#endif
+
+       /* grab a copy for peer tracking */
+#if defined(LWS_WITH_UNIX_SOCK)
+       if (!wsi->unix_skt)
+#endif
+               memmove(&wsi->sa46_peer, psa, (unsigned int)n);
+
+       /*
+        * Finally, make the actual connection attempt
+        */
+
+#if defined(LWS_WITH_SYS_METRICS)
+       if (wsi->cal_conn.mt) {
+               lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
+       }
+       lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mt_conn_tcp);
+#endif
+
+       wsi->socket_is_permanently_unusable = 0;
+
+       if (lws_fi(&wsi->fic, "conn_cb_rej") ||
+           user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
+                       LWS_CALLBACK_CONNECTING, wsi->user_space,
+                       (void *)(intptr_t)wsi->desc.sockfd, 0)) {
+               lwsl_wsi_info(wsi, "CONNECTION CB closed");
+               goto failed1;
+       }
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       cfail = lws_fi(&wsi->fic, "connfail");
+       if (cfail)
+               m = -1;
+       else
+#endif
+               m = connect(wsi->desc.sockfd, (const struct sockaddr *)psa,
+                           (socklen_t)n);
+
+#if defined(LWS_WITH_CONMON)
+       wsi->conmon_datum = lws_now_usecs();
+       wsi->conmon.ciu_sockconn = 0;
+#endif
+
+       if (m == -1) {
+               /*
+                * Since we're nonblocking, connect not having completed is not
+                * necessarily indicating any problem... we have to look at
+                * either errno or the socket to understand if we actually
+                * failed already...
+                */
+
+               int errno_copy = LWS_ERRNO;
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+               if (cfail)
+                       /* fake an abnormal, fatal situation */
+                       errno_copy = 999;
+#endif
+
+               lwsl_wsi_debug(wsi, "connect: fd %d errno: %d",
+                               wsi->desc.sockfd, errno_copy);
+
+               if (errno_copy &&
+                   errno_copy != LWS_EALREADY &&
+                   errno_copy != LWS_EINPROGRESS &&
+                   errno_copy != LWS_EWOULDBLOCK
+#ifdef _WIN32
+                && errno_copy != WSAEINVAL
+                 && errno_copy != WSAEISCONN
+#endif
+               ) {
+                       /*
+                        * The connect() failed immediately...
+                        */
+
+#if defined(LWS_WITH_CONMON)
+                       wsi->conmon.ciu_sockconn = (lws_conmon_interval_us_t)
+                                       (lws_now_usecs() - wsi->conmon_datum);
+#endif
+
+                       lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
+
+#if defined(_DEBUG)
+#if defined(LWS_WITH_UNIX_SOCK)
+                       if (!wsi->unix_skt) {
+#endif
+
+                       char nads[48];
+
+                       lws_sa46_write_numeric_address(&wsi->sa46_peer, nads,
+                                                      sizeof(nads));
+
+                       lws_snprintf(dcce, sizeof(dcce),
+                                    "conn fail: errno %d: %s:%d",
+                                               errno_copy, nads, port);
+                       cce = dcce;
+
+                       wsi->sa46_peer.sa4.sin_family = 0;
+                       lwsl_wsi_info(wsi, "%s", cce);
+#if defined(LWS_WITH_UNIX_SOCK)
+                       } else {
+                               lws_snprintf(dcce, sizeof(dcce),
+                                            "conn fail: errno %d: UDS %s",
+                                                              errno_copy, ads);
+                               cce = dcce;
+                       }
+#endif
+#endif
+
+                       goto try_next_dns_result_fds;
+               }
+
+#if defined(WIN32)
+               if (lws_plat_check_connection_error(wsi))
+                       goto try_next_dns_result_fds;
+
+               if (errno_copy == WSAEISCONN)
+                       goto conn_good;
+#endif
+
+               /*
+                * The connection attempt is ongoing asynchronously... let's set
+                * a specialized timeout for this connect attempt completion, it
+                * uses wsi->sul_connect_timeout just for this purpose
+                */
+
+               lws_sul_schedule(wsi->a.context, 0, &wsi->sul_connect_timeout,
+                                lws_client_conn_wait_timeout,
+                                wsi->a.context->timeout_secs *
+                                                LWS_USEC_PER_SEC);
+
+               /*
+                * must do specifically a POLLOUT poll to hear
+                * about the connect completion
+                */
+               if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
+                       goto try_next_dns_result_fds;
+
+               return wsi;
+       }
+
+conn_good:
+
+       /*
+        * The connection has happened
+        */
+
+#if defined(LWS_WITH_CONMON)
+       wsi->conmon.ciu_sockconn = (lws_conmon_interval_us_t)
+                                       (lws_now_usecs() - wsi->conmon_datum);
+#endif
+
+#if !defined(LWS_PLAT_OPTEE)
+       {
+               socklen_t salen = sizeof(wsi->sa46_local);
+#if defined(_DEBUG)
+               char buf[64];
+#endif
+               if (getsockname((int)wsi->desc.sockfd,
+                               (struct sockaddr *)&wsi->sa46_local,
+                               &salen) == -1)
+                       lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
+#if defined(_DEBUG)
+#if defined(LWS_WITH_UNIX_SOCK)
+               if (wsi->unix_skt)
+                       buf[0] = '\0';
+               else
+#endif
+                       lws_sa46_write_numeric_address(&wsi->sa46_local, buf, sizeof(buf));
+
+               lwsl_wsi_info(wsi, "source ads %s", buf);
+#endif
+       }
+#endif
+
+       lws_sul_cancel(&wsi->sul_connect_timeout);
+       lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
+
+       lws_addrinfo_clean(wsi);
+
+       if (wsi->a.protocol)
+               wsi->a.protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
+                                         wsi->user_space, NULL, 0);
+
+       lwsl_wsi_debug(wsi, "going into connect_4");
+
+       return lws_client_connect_4_established(wsi, NULL, plen);
+
+oom4:
+       /*
+        * We get here if we're trying to clean up a connection attempt that
+        * didn't make it as far as getting inserted into the wsi / fd tables
+        */
+
+       if (lwsi_role_client(wsi) && wsi->a.protocol
+                               /* && lwsi_state_est(wsi) */)
+               lws_inform_client_conn_fail(wsi,(void *)cce, strlen(cce));
+
+       /* take care that we might be inserted in fds already */
+       if (wsi->position_in_fds_table != LWS_NO_FDS_POS)
+               /* do the full wsi close flow */
+               goto failed1;
+
+       lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
+
+       /*
+        * We can't be an active client connection any more, if we thought
+        * that was what we were going to be doing.  It should be if we are
+        * failing by oom4 path, we are still called by
+        * lws_client_connect_via_info() and will be returning NULL to that,
+        * so nobody else should have had a chance to queue on us.
+        */
+       {
+               struct lws_vhost *vhost = wsi->a.vhost;
+               lws_sockfd_type sfd = wsi->desc.sockfd;
+
+               //lws_vhost_lock(vhost);
+               __lws_free_wsi(wsi); /* acquires vhost lock in wsi reset */
+               //lws_vhost_unlock(vhost);
+
+               sanity_assert_no_wsi_traces(vhost->context, wsi);
+               sanity_assert_no_sockfd_traces(vhost->context, sfd);
+       }
+
+       return NULL;
+
+connect_to:
+       /*
+        * It looks like the sul_connect_timeout fired
+        */
+       lwsl_wsi_info(wsi, "abandoning connect due to timeout");
+
+try_next_dns_result_fds:
+       lws_pt_lock(pt, __func__);
+       __remove_wsi_socket_from_fds(wsi);
+       lws_pt_unlock(pt);
+
+try_next_dns_result_closesock:
+       /*
+        * We are killing the socket but leaving
+        */
+       compatible_close(wsi->desc.sockfd);
+       wsi->desc.sockfd = LWS_SOCK_INVALID;
+
+try_next_dns_result:
+       lws_sul_cancel(&wsi->sul_connect_timeout);
+       if (lws_dll2_get_head(&wsi->dns_sorted_list))
+               goto next_dns_result;
+
+       lws_addrinfo_clean(wsi);
+       lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
+
+failed1:
+       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect3");
+
+       return NULL;
+}
diff --git a/lib/core-net/client/connect4.c b/lib/core-net/client/connect4.c
new file mode 100644 (file)
index 0000000..c34d225
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+struct lws *
+lws_client_connect_4_established(struct lws *wsi, struct lws *wsi_piggyback,
+                                ssize_t plen)
+{
+#if defined(LWS_CLIENT_HTTP_PROXYING)
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+#endif
+       const char *meth;
+       struct lws_pollfd pfd;
+       const char *cce = "";
+       int n, m, rawish = 0;
+
+       meth = lws_wsi_client_stash_item(wsi, CIS_METHOD,
+                                        _WSI_TOKEN_CLIENT_METHOD);
+
+       if (meth && (!strcmp(meth, "RAW")
+#if defined(LWS_ROLE_MQTT)
+                    || !strcmp(meth, "MQTT")
+#endif
+       ))
+               rawish = 1;
+
+       if (wsi_piggyback)
+               goto send_hs;
+
+#if defined(LWS_CLIENT_HTTP_PROXYING)
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       /* we are connected to server, or proxy */
+
+       /* http proxy */
+       if (wsi->a.vhost->http.http_proxy_port) {
+               const char *cpa;
+
+               cpa = lws_wsi_client_stash_item(wsi, CIS_ADDRESS,
+                                               _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+               if (!cpa)
+                       goto failed;
+
+               lwsl_wsi_info(wsi, "going via proxy");
+
+               plen = lws_snprintf((char *)pt->serv_buf, 256,
+                       "CONNECT %s:%u HTTP/1.1\x0d\x0a"
+                       "Host: %s:%u\x0d\x0a"
+                       "User-agent: lws\x0d\x0a", cpa, wsi->ocport,
+                                                  cpa, wsi->ocport);
+
+#if defined(LWS_WITH_HTTP_BASIC_AUTH)
+               if (wsi->a.vhost->proxy_basic_auth_token[0])
+                       plen += lws_snprintf((char *)pt->serv_buf + plen, 256,
+                                       "Proxy-authorization: basic %s\x0d\x0a",
+                                       wsi->a.vhost->proxy_basic_auth_token);
+#endif
+
+               plen += lws_snprintf((char *)pt->serv_buf + plen, 5,
+                                       "\x0d\x0a");
+
+               /* lwsl_hexdump_notice(pt->serv_buf, plen); */
+
+               /*
+                * OK from now on we talk via the proxy, so connect to that
+                */
+               if (wsi->stash)
+                       wsi->stash->cis[CIS_ADDRESS] =
+                               wsi->a.vhost->http.http_proxy_address;
+               else
+                       if (lws_hdr_simple_create(wsi,
+                                       _WSI_TOKEN_CLIENT_PEER_ADDRESS,
+                                       wsi->a.vhost->http.http_proxy_address))
+                       goto failed;
+               wsi->c_port = (uint16_t)wsi->a.vhost->http.http_proxy_port;
+
+               n = (int)send(wsi->desc.sockfd, (char *)pt->serv_buf,
+                             (unsigned int)plen,
+                        MSG_NOSIGNAL);
+               if (n < 0) {
+                       lwsl_wsi_debug(wsi, "ERROR writing to proxy socket");
+                       cce = "proxy write failed";
+                       goto failed;
+               }
+
+               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
+                               (int)wsi->a.context->timeout_secs);
+
+               wsi->conn_port = wsi->c_port;
+               lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY);
+
+               return wsi;
+       }
+#endif
+#endif
+
+       /* coverity */
+       if (!wsi->a.protocol)
+               return NULL;
+
+#if defined(LWS_WITH_SOCKS5)
+       if (lwsi_state(wsi) !=  LRS_ESTABLISHED)
+               switch (lws_socks5c_greet(wsi, &cce)) {
+               case -1:
+                       goto failed;
+               case 1:
+                       return wsi;
+               default:
+                       break;
+               }
+#endif
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+send_hs:
+
+       if (wsi_piggyback &&
+           !lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
+               /*
+                * We are pipelining on an already-established connection...
+                * we can skip tls establishment.
+                *
+                * Set these queued guys to a state where they won't actually
+                * send their headers until we decide later.
+                */
+
+               lwsi_set_state(wsi, LRS_H2_WAITING_TO_SEND_HEADERS);
+
+               /*
+                * we can't send our headers directly, because they have to
+                * be sent when the parent is writeable.  The parent will check
+                * for anybody on his client transaction queue that is in
+                * LRS_H1C_ISSUE_HANDSHAKE2, and let them write.
+                *
+                * If we are trying to do this too early, before the network
+                * connection has written his own headers, then it will just
+                * wait in the queue until it's possible to send them.
+                */
+               lws_callback_on_writable(wsi_piggyback);
+
+               lwsl_wsi_info(wsi, "waiting to send hdrs (par state 0x%x)",
+                             lwsi_state(wsi_piggyback));
+       } else {
+               lwsl_wsi_info(wsi, "%s %s client created own conn "
+                         "(raw %d) vh %s st 0x%x",
+                         wsi->role_ops->name, wsi->a.protocol->name, rawish,
+                         wsi->a.vhost->name, lwsi_state(wsi));
+
+               /* we are making our own connection */
+
+               if (!rawish
+#if defined(LWS_WITH_TLS)
+                   // && (!(wsi->tls.use_ssl & LCCSCF_USE_SSL) || wsi->tls.ssl)
+#endif
+                   ) {
+
+                       if (lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2)
+                               lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);
+               } else {
+                       /* for a method = "RAW" connection, this makes us
+                        * established */
+
+#if defined(LWS_WITH_TLS)// && !defined(LWS_WITH_MBEDTLS)
+
+                       /* we have connected if we got here */
+
+                       if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
+                           (wsi->tls.use_ssl & LCCSCF_USE_SSL)) {
+                               int result;
+
+                               //lwsi_set_state(wsi, LRS_WAITING_SSL);
+
+                               /*
+                                * We can retry this... just cook the SSL BIO
+                                * the first time
+                                */
+
+                               result = lws_client_create_tls(wsi, &cce, 1);
+                               switch (result) {
+                               case CCTLS_RETURN_DONE:
+                                       break;
+                               case CCTLS_RETURN_RETRY:
+                                       lwsl_wsi_debug(wsi, "create_tls RETRY");
+                                       return wsi;
+                               default:
+                                       lwsl_wsi_debug(wsi, "create_tls FAIL");
+                                       goto failed;
+                               }
+
+                               /*
+                                * We succeeded to negotiate a new client tls
+                                * tunnel.  If it's h2 alpn, we have arranged
+                                * to send the h2 prefix and set our state to
+                                * LRS_H2_WAITING_TO_SEND_HEADERS already.
+                                */
+
+                               lwsl_wsi_notice(wsi, "tls established st 0x%x, "
+                                           "client_h2_alpn %d", lwsi_state(wsi),
+                                           wsi->client_h2_alpn);
+
+                               if (lwsi_state(wsi) !=
+                                               LRS_H2_WAITING_TO_SEND_HEADERS)
+                                       lwsi_set_state(wsi,
+                                               LRS_H1C_ISSUE_HANDSHAKE2);
+                               lws_set_timeout(wsi,
+                                       PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
+                                       (int)wsi->a.context->timeout_secs);
+#if 0
+                               /* ensure pollin enabled */
+                               if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
+                                       lwsl_wsi_notice(wsi,
+                                                       "unable to set POLLIN");
+#endif
+
+                               goto provoke_service;
+                       }
+#endif
+
+                       /* clear his established timeout */
+                       lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+                       m = wsi->role_ops->adoption_cb[0];
+                       if (m) {
+                               n = user_callback_handle_rxflow(
+                                               wsi->a.protocol->callback, wsi,
+                                               (enum lws_callback_reasons)m,
+                                               wsi->user_space, NULL, 0);
+                               if (n < 0) {
+                                       lwsl_wsi_info(wsi, "RAW_PROXY_CLI_ADOPT err");
+                                       goto failed;
+                               }
+                       }
+
+                       /* service.c pollout processing wants this */
+                       wsi->hdr_parsing_completed = 1;
+#if defined(LWS_ROLE_MQTT)
+                       if (meth && !strcmp(meth, "MQTT")) {
+#if defined(LWS_WITH_TLS)
+                               if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
+                                       lwsi_set_state(wsi, LRS_WAITING_SSL);
+                                       return wsi;
+                               }
+#endif
+                               lwsl_wsi_info(wsi, "settings LRS_MQTTC_IDLE");
+                               lwsi_set_state(wsi, LRS_MQTTC_IDLE);
+
+                               /*
+                                * provoke service to issue the CONNECT
+                                * directly.
+                                */
+                               lws_set_timeout(wsi,
+                                       PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
+                                               (int)wsi->a.context->timeout_secs);
+
+                               assert(lws_socket_is_valid(wsi->desc.sockfd));
+
+                               pfd.fd = wsi->desc.sockfd;
+                               pfd.events = LWS_POLLIN;
+                               pfd.revents = LWS_POLLOUT;
+
+                               lwsl_wsi_info(wsi, "going to service fd");
+                               n = lws_service_fd(wsi->a.context, &pfd);
+                               if (n < 0) {
+                                       cce = "first service failed";
+                                       goto failed;
+                               }
+                               if (n)
+                                       /* returns 1 on fail after close wsi */
+                                       return NULL;
+                               return wsi;
+                       }
+#endif
+                       lwsl_wsi_info(wsi, "setting ESTABLISHED");
+                       lwsi_set_state(wsi, LRS_ESTABLISHED);
+
+                       return wsi;
+               }
+
+               /*
+                * provoke service to issue the handshake directly.
+                *
+                * we need to do it this way because in the proxy case, this is
+                * the next state and executed only if and when we get a good
+                * proxy response inside the state machine... but notice in
+                * SSL case this may not have sent anything yet with 0 return,
+                * and won't until many retries from main loop.  To stop that
+                * becoming endless, cover with a timeout.
+                */
+#if defined(LWS_WITH_TLS) //&& !defined(LWS_WITH_MBEDTLS)
+provoke_service:
+#endif
+               lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
+                               (int)wsi->a.context->timeout_secs);
+
+               assert(lws_socket_is_valid(wsi->desc.sockfd));
+
+               pfd.fd = wsi->desc.sockfd;
+               pfd.events = LWS_POLLIN;
+               pfd.revents = LWS_POLLIN;
+
+               n = lws_service_fd(wsi->a.context, &pfd);
+               if (n < 0) {
+                       cce = "first service failed";
+                       goto failed;
+               }
+               if (n) /* returns 1 on failure after closing wsi */
+                       return NULL;
+       }
+#endif
+       return wsi;
+
+failed:
+       lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
+
+       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect4");
+
+       return NULL;
+}
diff --git a/lib/core-net/client/sort-dns.c b/lib/core-net/client/sort-dns.c
new file mode 100644 (file)
index 0000000..db105c5
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *
+ *  Either the libc getaddrinfo() or ASYNC_DNS provides a chain of addrinfo,
+ *  we use lws_sort_dns() to convert it to an lws_dll2 of lws_dns_sort_t, after
+ *  which the addrinfo results are freed.
+ *
+ *  If the system has no routing table info (from, eg, NETLINK), then that's
+ *  it the sorted results are bound to the wsi and used.
+ *
+ *  If the system has routing table info, we study the routing table and the
+ *  DNS results in order to sort the lws_dns_sort_t result linked-list into
+ *  most desirable at the head, and strip results we can't see a way to route.
+ */
+
+#include "private-lib-core.h"
+
+#if defined(__linux__)
+#include <linux/if_addr.h>
+#endif
+
+#if defined(__FreeBSD__)
+#include <net/if.h>
+#include <netinet6/in6_var.h>
+#endif
+
+#if defined(LWS_WITH_IPV6) && defined(LWS_WITH_NETLINK)
+
+/*
+ * RFC6724 default policy table
+ *
+ *      Prefix        Precedence Label
+ *    ::1/128               50     0
+ *    ::/0                  40     1
+ *    ::ffff:0:0/96         35     4  (override prec to 100 to prefer ipv4)
+ *    2002::/16             30     2
+ *    2001::/32              5     5
+ *    fc00::/7               3    13
+ *    ::/96                  1     3
+ *    fec0::/10              1    11
+ *    3ffe::/16              1    12
+ *
+ * implemented using offsets into a combined 40-byte table below
+ */
+
+static const uint8_t ma[] = {
+       /*  0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+       /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff,
+       /* 28 */ 0x20, 0x02,
+       /* 30 */ 0x20, 0x01, 0x00, 0x00,
+       /* 34 */ 0xfc, 0x00,
+       /* 36 */ 0xfe, 0xc0,
+       /* 38 */ 0x3f, 0xfe
+};
+
+static const uint8_t frac[] = {
+       0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
+};
+
+/* 9 x 4 byte = 36 byte policy index table */
+
+static const struct score_policy {
+       uint8_t                 ma_ofs;
+       uint8_t                 prefix;
+       lws_dns_score_t         score;
+} rfc6724_policy[] = {
+
+       {  0,   128,    {  50,  0 } },          /* ::1/128 */
+       {  0,     0,    {  40,  1 } },          /* ::0 */
+#if 1
+       /* favour ipv6 as a general policy */
+       { 16,    96,    {  35,  4 } },          /* ::ffff:0:0/96 */
+#else
+       /* favour ipv4 as a general policy */
+       { 16,    96,    { 100,  4 } },          /* ::ffff:0:0/96 */
+#endif
+       { 28,    16,    {  30,  2 } },          /* 2002::/16 */
+       { 30,    32,    {   5,  5 } },          /* 2001::/32 */
+       { 34,     7,    {   3, 13 } },          /* fc00::/7 */
+       {  0,    96,    {   1,  3 } },          /* ::/96 */
+       { 36,    10,    {   1, 11 } },          /* fec0::/10 */
+       { 38,    16,    {   1, 12 } },          /* 3ffe::/16 */
+
+};
+
+static int
+lws_ipv6_prefix_match_len(const struct sockaddr_in6 *a,
+                         const struct sockaddr_in6 *b)
+{
+       const uint8_t *ads_a = (uint8_t *)&a->sin6_addr,
+                     *ads_b = (uint8_t *)&b->sin6_addr;
+       int n = 0, match = 0;
+
+       for (n = 0; n < 16; n++) {
+               if (ads_a[n] == ads_b[n])
+                       match += 8;
+               else
+                       break;
+       }
+
+       if (match != 128) {
+               int m;
+
+               for (m = 1; m < 8; m++) {
+                       if ((ads_a[n] & frac[m]) == (ads_b[n] & frac[m]))
+                               match++;
+                       else
+                               break;
+               }
+       }
+
+       return match;
+}
+
+static int
+lws_ipv6_unicast_scope(const struct sockaddr_in6 *sa)
+{
+       uint64_t *u;
+
+       u = (uint64_t *)&sa->sin6_addr;
+       if (*u == 0xfe80000000000000ull)
+               return 2; /* link-local */
+
+       return 0xe;
+}
+
+static int
+lws_sort_dns_scope(lws_sockaddr46 *sa46)
+{
+       if (sa46->sa4.sin_family == AF_INET) {
+               uint8_t *p = (uint8_t *)&sa46->sa4.sin_addr;
+
+               /* RFC6724 3.2 */
+
+               if (p[0] == 127 || (p[0] == 169 && p[1] == 254))
+                       return 2; /* link-local */
+
+               return 0xe; /* global */
+       }
+
+       return lws_ipv6_unicast_scope(&sa46->sa6);
+}
+
+static int
+lws_sort_dns_classify(lws_sockaddr46 *sa46, lws_dns_score_t *score)
+{
+       const struct score_policy *pol = rfc6724_policy;
+       const uint8_t *p, *po;
+       lws_sockaddr46 s;
+       int n, m;
+
+       memset(score, 0, sizeof(*score));
+
+       if (sa46->sa4.sin_family == AF_INET) {
+               memset(&s, 0, sizeof(s));
+               s.sa6.sin6_family = AF_INET6;
+               lws_4to6((uint8_t *)s.sa6.sin6_addr.s6_addr,
+                        (const uint8_t *)&sa46->sa4.sin_addr);
+
+               /* use the v6 version of the v4 address */
+               sa46 = &s;
+       }
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(rfc6724_policy); n++) {
+               po = (uint8_t *)&sa46->sa6.sin6_addr.s6_addr;
+               p = &ma[pol->ma_ofs];
+               for (m = 0; m < pol->prefix >> 3; m++)
+                       if (*p++ != *po++)
+                               goto next;
+
+               if ((pol->prefix & 7) && (*p & frac[pol->prefix & 7]) !=
+                                         (*po & frac[pol->prefix & 7]))
+                       goto next;
+
+               *score = pol->score;
+
+               return 0;
+
+next:
+               pol++;
+       }
+
+       return 1;
+}
+
+
+enum {
+       SAS_PREFER_A    =  1,
+       SAS_SAME        =  0,
+       SAS_PREFER_B    = -1
+};
+
+/* ifa is laid out with types for ipv4, if it's AF_INET6 case to sockaddr_in6 */
+#define to_v6_sa(x) ((struct sockaddr_in6 *)x)
+#define to_sa46_sa(x) ((lws_sockaddr46 *)x)
+
+/*
+ * The source address selection algorithm produces as output a single
+ * source address for use with a given destination address.  This
+ * algorithm only applies to IPv6 destination addresses, not IPv4
+ * addresses.
+ *
+ * This implements RFC6724 Section 5.
+ *
+ * Either or both sa and sb can be dest or gateway routes
+ */
+
+static int
+lws_sort_dns_scomp(struct lws_context_per_thread *pt, const lws_route_t *sa,
+                  const lws_route_t *sb, const struct sockaddr_in6 *dst)
+{
+       const struct sockaddr_in6 *sa6 = to_v6_sa(&sa->dest),
+                                 *sb6 = to_v6_sa(&sb->dest);
+       lws_dns_score_t scorea, scoreb, scoredst;
+       int scopea, scopeb, scoped, mla, mlb;
+       lws_route_t *rd;
+
+       if (!sa->dest.sa4.sin_family)
+               sa6 = to_v6_sa(&sa->gateway);
+       if (!sb->dest.sa4.sin_family)
+               sb6 = to_v6_sa(&sb->gateway);
+
+       /*
+        * We shouldn't come here unless sa and sb both have AF_INET6 addresses
+        */
+
+       assert(sa6->sin6_family == AF_INET6);
+       assert(sb6->sin6_family == AF_INET6);
+
+       /*
+        * Rule 1: Prefer same address.
+        * If SA = D, then prefer SA.  Similarly, if SB = D, then prefer SB.
+        */
+
+       if (!memcmp(&sa6->sin6_addr, &dst->sin6_addr, 16))
+               return SAS_PREFER_A;
+       if (!memcmp(&sb6->sin6_addr, &dst->sin6_addr, 16))
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 2: Prefer appropriate scope.
+        * If Scope(SA) < Scope(SB): If Scope(SA) < Scope(D), then prefer SB
+        * and otherwise prefer SA.
+        *
+        * Similarly, if Scope(SB) < Scope(SA): If Scope(SB) < Scope(D), then
+        * prefer SA and otherwise prefer SB.
+        */
+
+       scopea = lws_sort_dns_scope(to_sa46_sa(sa6));
+       scopeb = lws_sort_dns_scope(to_sa46_sa(sb6));
+       scoped = lws_sort_dns_scope(to_sa46_sa(dst));
+
+       if (scopea < scopeb)
+               return scopea < scoped ? SAS_PREFER_B : SAS_PREFER_A;
+
+       if (scopeb < scopea)
+               return scopeb < scoped ? SAS_PREFER_A : SAS_PREFER_B;
+
+       /*
+        * Rule 3: Avoid deprecated addresses.
+        * If one of the two source addresses is "preferred" and one of them
+        * is "deprecated" (in the RFC 4862 sense), then prefer the one that
+        * is "preferred".
+        */
+
+       if (!(sa->ifa_flags & IFA_F_DEPRECATED) &&
+            (sb->ifa_flags & IFA_F_DEPRECATED))
+               return SAS_PREFER_A;
+
+       if ( (sa->ifa_flags & IFA_F_DEPRECATED) &&
+           !(sb->ifa_flags & IFA_F_DEPRECATED))
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 4: Prefer home addresses.
+        * If SA is simultaneously a home address and care-of address and SB is
+        * not, then prefer SA.  Similarly, if SB is simultaneously a home
+        * address and care-of address and SA is not, then prefer SB.  If SA is
+        * just a home address and SB is just a care-of address, then prefer SA.
+        * Similarly, if SB is just a home address and SA is just a care-of
+        * address, then prefer SB.
+        *
+        * !!! not sure how to determine if care-of address
+        */
+
+       if ( (sa->ifa_flags & IFA_F_HOMEADDRESS) &&
+           !(sb->ifa_flags & IFA_F_HOMEADDRESS))
+               return SAS_PREFER_A;
+
+       if (!(sa->ifa_flags & IFA_F_HOMEADDRESS) &&
+            (sb->ifa_flags & IFA_F_HOMEADDRESS))
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 5: Prefer outgoing interface.
+        * If SA is assigned to the interface that will be used to send to D
+        * and SB is assigned to a different interface, then prefer SA.
+        * Similarly, if SB is assigned to the interface that will be used
+        * to send to D and SA is assigned to a different interface, then
+        * prefer SB.
+        */
+
+       rd = _lws_route_est_outgoing(pt, (lws_sockaddr46 *)dst);
+       if (rd) {
+               if (rd->if_idx == sa->if_idx)
+                       return SAS_PREFER_A;
+               if (rd->if_idx == sb->if_idx)
+                       return SAS_PREFER_B;
+       }
+
+       /*
+        * Rule 6: Prefer matching label.
+        * If Label(SA) = Label(D) and Label(SB) <> Label(D), then prefer SA.
+        * Similarly, if Label(SB) = Label(D) and Label(SA) <> Label(D), then
+        * prefer SB.
+        */
+
+       lws_sort_dns_classify(to_sa46_sa(sa6), &scorea);
+       lws_sort_dns_classify(to_sa46_sa(sb6), &scoreb);
+       lws_sort_dns_classify(to_sa46_sa(dst), &scoredst);
+
+       if (scorea.label == scoredst.label && scoreb.label != scoredst.label)
+               return SAS_PREFER_A;
+       if (scoreb.label == scoredst.label && scorea.label != scoredst.label)
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 7: Prefer temporary addresses.
+        * If SA is a temporary address and SB is a public address, then
+        * prefer SA.  Similarly, if SB is a temporary address and SA is a
+        * public address, then prefer SB.
+        */
+
+       if ( (sa->ifa_flags & IFA_F_TEMPORARY) &&
+           !(sb->ifa_flags & IFA_F_TEMPORARY))
+               return SAS_PREFER_A;
+
+       if (!(sa->ifa_flags & IFA_F_TEMPORARY) &&
+            (sb->ifa_flags & IFA_F_TEMPORARY))
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 8: Use longest matching prefix.
+        * If CommonPrefixLen(SA, D) > CommonPrefixLen(SB, D), then prefer SA.
+        * Similarly, if CommonPrefixLen(SB, D) > CommonPrefixLen(SA, D), then
+        * prefer SB.
+        */
+
+       mla = lws_ipv6_prefix_match_len(sa6, dst);
+       mlb = lws_ipv6_prefix_match_len(sb6, dst);
+
+       if (mla > mlb)
+               return SAS_PREFER_A;
+
+       return SAS_SAME;
+}
+
+/*
+ * Given two possible source addresses and the destination address, we attempt
+ * to pick which one is "better".
+ *
+ * This implements RFC6724 Section 6.
+ */
+
+static int
+lws_sort_dns_dcomp(const lws_dns_sort_t *da, const lws_dns_sort_t *db)
+{
+       int scopea, scopeb, scope_srca, scope_srcb, cpla, cplb;
+       const uint8_t *da_ads = (const uint8_t *)&da->dest.sa6.sin6_addr,
+                     *db_ads = (const uint8_t *)&db->dest.sa6.sin6_addr;
+       lws_dns_score_t score_srca, score_srcb;
+
+       /*
+        * Rule 1: Avoid unusable destinations
+        *
+        * We already strip destinations with no usable source
+        */
+
+       /*
+        * Rule 2: Prefer matching scope
+        *
+        * If Scope(DA) = Scope(Source(DA)) and Scope(DB) <> Scope(Source(DB)),
+        * then prefer DA.  Similarly, if Scope(DA) <> Scope(Source(DA)) and
+        * Scope(DB) = Scope(Source(DB)), then prefer DB.
+        */
+
+       scopea = lws_ipv6_unicast_scope(to_v6_sa(&da->dest));
+       scopeb = lws_ipv6_unicast_scope(to_v6_sa(&db->dest));
+       scope_srca = lws_ipv6_unicast_scope(to_v6_sa(&da->source));
+       scope_srcb = lws_ipv6_unicast_scope(to_v6_sa(&db->source));
+
+       if (scopea == scope_srca && scopeb != scope_srcb)
+               return SAS_PREFER_A;
+
+       if (scopea != scope_srca && scopeb == scope_srcb)
+               return SAS_PREFER_B;
+
+#if defined(IFA_F_DEPRECATED)
+       /*
+        * Rule 3: Avoid deprecated addresses.
+        *
+        * If Source(DA) is deprecated and Source(DB) is not, then prefer DB.
+        * Similarly, if Source(DA) is not deprecated and Source(DB) is
+        * deprecated, then prefer DA.
+        */
+
+       if (!(da->ifa_flags & IFA_F_DEPRECATED) &&
+            (db->ifa_flags & IFA_F_DEPRECATED))
+               return SAS_PREFER_A;
+
+       if ( (da->ifa_flags & IFA_F_DEPRECATED) &&
+           !(db->ifa_flags & IFA_F_DEPRECATED))
+               return SAS_PREFER_B;
+#endif
+
+       /*
+        * Rule 4: Prefer home addresses.
+        *
+        * If Source(DA) is simultaneously a home address and care-of address
+        * and Source(DB) is not, then prefer DA.  Similarly, if Source(DB) is
+        * simultaneously a home address and care-of address and Source(DA) is
+        * not, then prefer DB.
+        *
+        * If Source(DA) is just a home address and Source(DB) is just a care-of
+        * address, then prefer DA.  Similarly, if Source(DA) is just a care-of
+        * address and Source(DB) is just a home address, then prefer DB.
+        *
+        * !!! not sure how to determine if care-of address
+        */
+
+       if ( (da->ifa_flags & IFA_F_HOMEADDRESS) &&
+           !(db->ifa_flags & IFA_F_HOMEADDRESS))
+               return SAS_PREFER_A;
+
+       if (!(da->ifa_flags & IFA_F_HOMEADDRESS) &&
+            (db->ifa_flags & IFA_F_HOMEADDRESS))
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 5: Prefer matching label.
+        *
+        * If Label(Source(DA)) = Label(DA) and Label(Source(DB)) <> Label(DB),
+        * then prefer DA.  Similarly, if Label(Source(DA)) <> Label(DA) and
+        * Label(Source(DB)) = Label(DB), then prefer DB
+        */
+
+       if (!da->source)
+               return SAS_PREFER_B;
+       if (!db->source)
+               return SAS_PREFER_A;
+
+       lws_sort_dns_classify(&da->source->dest, &score_srca);
+       lws_sort_dns_classify(&db->source->dest, &score_srcb);
+
+       if (score_srca.label == da->score.label &&
+           score_srcb.label != db->score.label)
+               return SAS_PREFER_A;
+       if (score_srca.label != da->score.label &&
+           score_srcb.label == db->score.label)
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 6: Prefer higher precedence.
+        *
+        * If Precedence(DA) > Precedence(DB), then prefer DA.  Similarly, if
+        * Precedence(DA) < Precedence(DB), then prefer DB.
+        */
+
+       if (da->score.precedence > db->score.precedence)
+               return SAS_PREFER_A;
+
+       if (da->score.precedence < db->score.precedence)
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 7: Prefer native transport.
+        * If DA is reached via an encapsulating transition mechanism (e.g.,
+        * IPv6 in IPv4) and DB is not, then prefer DB.  Similarly, if DB is
+        * reached via encapsulation and DA is not, then prefer DA.
+        */
+
+       if (!memcmp(&ma[16], da_ads, 12) && memcmp(&ma[16], db_ads, 12))
+               return SAS_PREFER_B;
+
+       if (memcmp(&ma[16], da_ads, 12) && !memcmp(&ma[16], db_ads, 12))
+               return SAS_PREFER_A;
+
+       /*
+        * Rule 8: Prefer smaller scope.
+        * If Scope(DA) < Scope(DB), then prefer DA.  Similarly, if Scope(DA) >
+        * Scope(DB), then prefer DB.
+        */
+
+       if (scopea < scopeb)
+               return SAS_PREFER_A;
+
+       if (scopea > scopeb)
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 9: Use longest matching prefix.
+        * When DA and DB belong to the same address family (both are IPv6 or
+        * both are IPv4): If CommonPrefixLen(Source(DA), DA) >
+        * CommonPrefixLen(Source(DB), DB), then prefer DA.  Similarly, if
+        * CommonPrefixLen(Source(DA), DA) < CommonPrefixLen(Source(DB), DB),
+        * then prefer DB.
+        */
+
+       cpla = lws_ipv6_prefix_match_len(&da->source->dest.sa6, &da->dest.sa6);
+       cplb = lws_ipv6_prefix_match_len(&db->source->dest.sa6, &db->dest.sa6);
+
+       if (cpla > cplb)
+               return SAS_PREFER_A;
+
+       if (cpla < cplb)
+               return SAS_PREFER_B;
+
+       /*
+        * Rule 10: Otherwise, leave the order unchanged.
+        */
+
+       return SAS_SAME;
+}
+
+static int
+lws_sort_dns_compare(const lws_dll2_t *a, const lws_dll2_t *b)
+{
+       const lws_dns_sort_t *sa = lws_container_of(a, lws_dns_sort_t, list),
+                            *sb = lws_container_of(b, lws_dns_sort_t, list);
+
+       return lws_sort_dns_dcomp(sa, sb);
+}
+
+#endif /* ipv6 + netlink */
+
+#if defined(_DEBUG)
+
+static void
+lws_sort_dns_dump(struct lws *wsi)
+{
+       int n = 1;
+
+       (void)n; /* nologs */
+
+       if (!lws_dll2_get_head(&wsi->dns_sorted_list))
+               lwsl_wsi_notice(wsi, "empty");
+
+       lws_start_foreach_dll(struct lws_dll2 *, d,
+                             lws_dll2_get_head(&wsi->dns_sorted_list)) {
+               lws_dns_sort_t *s = lws_container_of(d, lws_dns_sort_t, list);
+               char dest[48], gw[48];
+
+               lws_sa46_write_numeric_address(&s->dest, dest, sizeof(dest));
+               lws_sa46_write_numeric_address(&s->gateway, gw, sizeof(gw));
+
+               lwsl_wsi_info(wsi, "%d: (%d)%s, gw (%d)%s, idi: %d, "
+                               "lbl: %d, prec: %d", n++,
+                           s->dest.sa4.sin_family, dest,
+                           s->gateway.sa4.sin_family, gw,
+                           s->if_idx, s->score.label, s->score.precedence);
+
+       } lws_end_foreach_dll(d);
+}
+
+#endif
+
+int
+lws_sort_dns(struct lws *wsi, const struct addrinfo *result)
+{
+#if defined(LWS_WITH_NETLINK)
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+#endif
+       const struct addrinfo *ai = result;
+
+       lwsl_wsi_info(wsi, "sort_dns: %p", result);
+
+       /*
+        * We're going to take the dns results and produce our own linked-list
+        * of them, if we can sorted into descending preferability order, and
+        * possibly filtered.
+        *
+        * First let's just convert the addrinfo list into our expanded
+        * lws_dns_sort_t list, we can discard the addrinfo list then
+        */
+
+       while (ai) {
+#if defined(LWS_WITH_NETLINK) || \
+       (defined(LWS_WITH_NETLINK) && defined(LWS_WITH_IPV6))
+               lws_route_t
+#if defined(LWS_WITH_NETLINK)
+                       *estr = NULL
+#endif
+#if defined(LWS_WITH_NETLINK) && defined(LWS_WITH_IPV6)
+                       , *bestsrc = NULL
+#endif
+               ;
+#endif
+               lws_dns_sort_t *ds;
+               char afip[48];
+
+               /*
+                * Only transfer address families we can cope with
+                */
+               if ((int)ai->ai_addrlen > (int)sizeof(lws_sockaddr46) ||
+                   (ai->ai_family != AF_INET && ai->ai_family != AF_INET6))
+                       goto next;
+
+               ds = lws_zalloc(sizeof(*ds), __func__);
+               if (!ds)
+                       return 1;
+
+               memcpy(&ds->dest, ai->ai_addr, (size_t)ai->ai_addrlen);
+               ds->dest.sa4.sin_family = (sa_family_t)ai->ai_family;
+
+               lws_sa46_write_numeric_address(&ds->dest, afip, sizeof(afip));
+
+               lwsl_wsi_info(wsi, "unsorted entry (af %d) %s",
+                                  ds->dest.sa4.sin_family, afip);
+
+#if defined(LWS_WITH_NETLINK)
+
+               /*
+                * Let's assess this DNS result in terms of route
+                * selection, eg, if no usable net route or gateway for it,
+                * we don't have a way to use it if we listed it
+                */
+
+               if (pt->context->routing_table.count) {
+
+                       estr = _lws_route_est_outgoing(pt, &ds->dest);
+                       if (!estr) {
+                               lws_free(ds);
+                               lwsl_wsi_notice(wsi, "%s has no route out\n",
+                                               afip);
+                               /*
+                                * There's no outbound route for this, it's
+                                * unusable, so don't add it to the list
+                                */
+                               goto next;
+                       }
+
+                       ds->if_idx = estr->if_idx;
+                       ds->uidx = estr->uidx;
+
+                       /*
+                        * ...evidently, there's a way for it to go out...
+                        */
+               }
+#endif
+
+#if defined(LWS_WITH_NETLINK) && defined(LWS_WITH_IPV6)
+
+               /*
+                * These sorting rules only apply to ipv6.  If we have ipv4
+                * dest and estimate we will use an ipv4 source address to
+                * route it, then skip this.
+                *
+                * However if we have ipv4 dest and estimate we will use an
+                * ipv6 source address to route it, because of ipv6-only
+                * egress, then promote it to ipv6 and sort it
+                */
+
+               if (ds->dest.sa4.sin_family == AF_INET) {
+                       if (!estr ||
+                           estr->dest.sa4.sin_family == AF_INET ||
+                           estr->gateway.sa4.sin_family == AF_INET)
+                               /*
+                                * No estimated route, or v4 estimated route,
+                                * just add it to sorted list
+                                */
+                               goto just_add;
+
+                       /*
+                        * v4 dest on estimated v6 source ads route, because
+                        * eg, there's no active v4 source ads just ipv6...
+                        * promote v4 -> v6 address using ::ffff:xx:yy
+                        */
+
+                       lwsl_wsi_info(wsi, "promoting v4->v6");
+
+                       lws_sa46_4to6(&ds->dest,
+                                     (uint8_t *)&ds->dest.sa4.sin_addr, 0);
+               }
+
+               /* first, classify this destination ads */
+               lws_sort_dns_classify(&ds->dest, &ds->score);
+
+               /*
+                * RFC6724 Section 5: Source Address Selection
+                *
+                * Go through the source options choosing the best for this
+                * destination... this can only operate on ipv6 destination
+                * address
+                */
+
+               lws_start_foreach_dll(struct lws_dll2 *, d,
+                                     lws_dll2_get_head(&pt->context->routing_table)) {
+                       lws_route_t *r = lws_container_of(d, lws_route_t, list);
+
+                       /* gateway routes are skipped here */
+
+                       if (ds->dest.sa6.sin6_family == AF_INET6 &&
+                           r->dest.sa4.sin_family == AF_INET6 && (!bestsrc ||
+                           lws_sort_dns_scomp(pt, bestsrc, r, &ds->dest.sa6) ==
+                                                           SAS_PREFER_B))
+                               bestsrc = r;
+
+               } lws_end_foreach_dll(d);
+
+               /* bestsrc is the best source route, or NULL if none */
+
+               if (!bestsrc && pt->context->routing_table.count) {
+                       /* drop it, no usable source route */
+                       lws_free(ds);
+                       goto next;
+               }
+
+just_add:
+               if (!bestsrc) {
+                       lws_dll2_add_tail(&ds->list, &wsi->dns_sorted_list);
+                       goto next;
+               }
+
+               ds->source = bestsrc;
+
+               /*
+                * RFC6724 Section 6: Destination Address Selection
+                *
+                * Insert the destination into the list at a position reflecting
+                * its preferability, so the head entry is the most preferred
+                */
+
+               lws_dll2_add_sorted(&ds->list, &wsi->dns_sorted_list,
+                                   lws_sort_dns_compare);
+#else
+               /*
+                * We don't have the routing table + source address details in
+                * order to sort the DNS results... simply make entries in the
+                * order of the addrinfo results
+                */
+
+               lws_dll2_add_tail(&ds->list, &wsi->dns_sorted_list);
+#endif
+
+next:
+               ai = ai->ai_next;
+       }
+
+       //lwsl_notice("%s: sorted table: %d\n", __func__,
+       //              wsi->dns_sorted_list.count);
+
+#if defined(_DEBUG)
+       lws_sort_dns_dump(wsi);
+#endif
+
+       return !wsi->dns_sorted_list.count;
+}
index 95f2201..1d92b39 100644 (file)
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
+#if defined(LWS_WITH_CLIENT)
+static int
+lws_close_trans_q_leader(struct lws_dll2 *d, void *user)
+{
+       struct lws *w = lws_container_of(d, struct lws, dll2_cli_txn_queue);
+
+       __lws_close_free_wsi(w, (enum lws_close_status)-1, "trans q leader closing");
+
+       return 0;
+}
+#endif
 
 void
-__lws_free_wsi(struct lws *wsi)
+__lws_reset_wsi(struct lws *wsi)
 {
        if (!wsi)
                return;
 
+#if defined(LWS_WITH_CLIENT)
+
+       lws_free_set_NULL(wsi->cli_hostname_copy);
+
+#if defined(LWS_WITH_CONMON)
+
+       if (wsi->conmon.dns_results_copy) {
+               lws_conmon_addrinfo_destroy(wsi->conmon.dns_results_copy);
+               wsi->conmon.dns_results_copy = NULL;
+       }
+
+       wsi->conmon.ciu_dns =
+               wsi->conmon.ciu_sockconn =
+               wsi->conmon.ciu_tls =
+               wsi->conmon.ciu_txn_resp = 0;
+#endif
+
+       /*
+        * if we have wsi in our transaction queue, if we are closing we
+        * must go through and close all those first
+        */
+       if (wsi->a.vhost) {
+
+               /* we are no longer an active client connection that can piggyback */
+               lws_dll2_remove(&wsi->dll_cli_active_conns);
+
+               lws_dll2_foreach_safe(&wsi->dll2_cli_txn_queue_owner, NULL,
+                                     lws_close_trans_q_leader);
+
+               /*
+                * !!! If we are closing, but we have pending pipelined
+                * transaction results we already sent headers for, that's going
+                * to destroy sync for HTTP/1 and leave H2 stream with no live
+                * swsi.`
+                *
+                * However this is normal if we are being closed because the
+                * transaction queue leader is closing.
+                */
+               lws_dll2_remove(&wsi->dll2_cli_txn_queue);
+       }
+#endif
+
+       if (wsi->a.vhost) {
+               lws_vhost_lock(wsi->a.vhost);
+               lws_dll2_remove(&wsi->vh_awaiting_socket);
+               lws_vhost_unlock(wsi->a.vhost);
+       }
+
        /*
         * Protocol user data may be allocated either internally by lws
         * or by specified the user. We should only free what we allocated.
         */
-       if (wsi->protocol && wsi->protocol->per_session_data_size &&
-           wsi->user_space && !wsi->user_space_externally_allocated)
-               lws_free(wsi->user_space);
+       if (wsi->a.protocol && wsi->a.protocol->per_session_data_size &&
+           wsi->user_space && !wsi->user_space_externally_allocated) {
+               /* confirm no sul left scheduled in user data itself */
+               lws_sul_debug_zombies(wsi->a.context, wsi->user_space,
+                               wsi->a.protocol->per_session_data_size, __func__);
+               lws_free_set_NULL(wsi->user_space);
+       }
+
+       /*
+        * Don't let buflist content or state from the wsi's previous life
+        * carry over to the new life
+        */
 
        lws_buflist_destroy_all_segments(&wsi->buflist);
+       lws_dll2_remove(&wsi->dll_buflist);
        lws_buflist_destroy_all_segments(&wsi->buflist_out);
-       lws_free_set_NULL(wsi->udp);
+#if defined(LWS_WITH_UDP)
+       if (wsi->udp) {
+               /* confirm no sul left scheduled in wsi->udp itself */
+               lws_sul_debug_zombies(wsi->a.context, wsi->udp,
+                                     sizeof(*wsi->udp), "close udp wsi");
+               lws_free_set_NULL(wsi->udp);
+       }
+#endif
+       wsi->retry = 0;
 
-       if (wsi->vhost && wsi->vhost->lserv_wsi == wsi)
-               wsi->vhost->lserv_wsi = NULL;
-#if !defined(LWS_NO_CLIENT)
-       if (wsi->vhost)
-               lws_dll2_remove(&wsi->dll_cli_active_conns);
+#if defined(LWS_WITH_CLIENT)
+       lws_dll2_remove(&wsi->dll2_cli_txn_queue);
+       lws_dll2_remove(&wsi->dll_cli_active_conns);
+       if (wsi->cli_hostname_copy)
+               lws_free_set_NULL(wsi->cli_hostname_copy);
 #endif
-       wsi->context->count_wsi_allocated--;
 
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       __lws_header_table_detach(wsi, 0);
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       lws_async_dns_cancel(wsi);
 #endif
+
+#if defined(LWS_WITH_HTTP_PROXY)
+       if (wsi->http.buflist_post_body)
+               lws_buflist_destroy_all_segments(&wsi->http.buflist_post_body);
+#endif
+
+#if defined(LWS_WITH_SERVER)
+       lws_dll2_remove(&wsi->listen_list);
+#endif
+
+#if defined(LWS_WITH_CLIENT)
+       if (wsi->a.vhost)
+               lws_dll2_remove(&wsi->dll_cli_active_conns);
+#endif
+
        __lws_same_vh_protocol_remove(wsi);
-#if !defined(LWS_NO_CLIENT)
-       lws_client_stash_destroy(wsi);
+#if defined(LWS_WITH_CLIENT)
+       //lws_free_set_NULL(wsi->stash);
        lws_free_set_NULL(wsi->cli_hostname_copy);
 #endif
 
-       if (wsi->role_ops->destroy_role)
-               wsi->role_ops->destroy_role(wsi);
-
 #if defined(LWS_WITH_PEER_LIMITS)
-       lws_peer_track_wsi_close(wsi->context, wsi->peer);
+       lws_peer_track_wsi_close(wsi->a.context, wsi->peer);
        wsi->peer = NULL;
 #endif
 
@@ -72,14 +163,107 @@ __lws_free_wsi(struct lws *wsi)
 #endif
        __lws_wsi_remove_from_sul(wsi);
 
-       if (wsi->context->event_loop_ops->destroy_wsi)
-               wsi->context->event_loop_ops->destroy_wsi(wsi);
+       if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_destroy_role))
+               lws_rops_func_fidx(wsi->role_ops,
+                                  LWS_ROPS_destroy_role).destroy_role(wsi);
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       __lws_header_table_detach(wsi, 0);
+#endif
+
+#if defined(LWS_ROLE_H2)
+       /*
+        * Let's try to clean out the h2-ness of the wsi
+        */
+
+       memset(&wsi->h2, 0, sizeof(wsi->h2));
+
+       wsi->hdr_parsing_completed = wsi->mux_substream =
+       wsi->upgraded_to_http2 = wsi->mux_stream_immortal =
+       wsi->h2_acked_settings = wsi->seen_nonpseudoheader =
+       wsi->socket_is_permanently_unusable = wsi->favoured_pollin =
+       wsi->already_did_cce = wsi->told_user_closed =
+       wsi->waiting_to_send_close_frame = wsi->close_needs_ack =
+       wsi->parent_pending_cb_on_writable = wsi->seen_zero_length_recv =
+       wsi->close_when_buffered_out_drained = wsi->could_have_pending = 0;
+#endif
+
+#if defined(LWS_WITH_CLIENT)
+       wsi->do_ws = wsi->chunked = wsi->client_rx_avail =
+       wsi->client_http_body_pending = wsi->transaction_from_pipeline_queue =
+       wsi->keepalive_active = wsi->keepalive_rejected =
+       wsi->redirected_to_get = wsi->client_pipeline = wsi->client_h2_alpn =
+       wsi->client_mux_substream = wsi->client_mux_migrated =
+       wsi->tls_session_reused = wsi->perf_done = 0;
+
+       wsi->immortal_substream_count = 0;
+#endif
+}
+
+/* req cx lock */
+
+void
+__lws_free_wsi(struct lws *wsi)
+{
+       struct lws_vhost *vh;
+
+       if (!wsi)
+               return;
+
+       lws_context_assert_lock_held(wsi->a.context);
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       if (wsi->for_ss) {
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+               if (wsi->client_bound_sspc) {
+                       lws_sspc_handle_t *h = (lws_sspc_handle_t *)
+                                                       wsi->a.opaque_user_data;
+                       if (h) {
+                               h->cwsi = NULL;
+                               wsi->a.opaque_user_data = NULL;
+                       }
+               } else
+#endif
+               {
+                       /*
+                        * Make certain it is disconnected from the ss by now
+                        */
+                       lws_ss_handle_t *h = (lws_ss_handle_t *)
+                                                       wsi->a.opaque_user_data;
+
+                       if (h) {
+                               h->wsi = NULL;
+                               wsi->a.opaque_user_data = NULL;
+                       }
+               }
+       }
+#endif
+
+       vh = wsi->a.vhost;
+
+       __lws_reset_wsi(wsi);
+       __lws_wsi_remove_from_sul(wsi);
+
+       if (vh)
+               /* this may destroy vh */
+               __lws_vhost_unbind_wsi(wsi); /* req cx + vh lock */
+
+#if defined(LWS_WITH_CLIENT)
+       if (wsi->stash)
+               lws_free_set_NULL(wsi->stash);
+#endif
 
-       lws_vhost_unbind_wsi(wsi);
+       if (wsi->a.context->event_loop_ops->destroy_wsi)
+               wsi->a.context->event_loop_ops->destroy_wsi(wsi);
 
-       lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
-                       wsi->context->count_wsi_allocated);
+       lwsl_wsi_debug(wsi, "tsi fds count %d\n",
+                       wsi->a.context->pt[(int)wsi->tsi].fds_count);
 
+       /* confirm no sul left scheduled in wsi itself */
+       lws_sul_debug_zombies(wsi->a.context, wsi, sizeof(*wsi), __func__);
+
+       __lws_lc_untag(wsi->a.context, &wsi->lc);
        lws_free(wsi);
 }
 
@@ -97,11 +281,11 @@ lws_remove_child_from_any_parent(struct lws *wsi)
        pwsi = &wsi->parent->child_list;
        while (*pwsi) {
                if (*pwsi == wsi) {
-                       lwsl_info("%s: detach %p from parent %p\n", __func__,
-                                 wsi, wsi->parent);
+                       lwsl_wsi_info(wsi, "detach from parent %s",
+                                           lws_wsi_tag(wsi->parent));
 
-                       if (wsi->parent->protocol)
-                               wsi->parent->protocol->callback(wsi,
+                       if (wsi->parent->a.protocol)
+                               wsi->parent->a.protocol->callback(wsi,
                                                LWS_CALLBACK_CHILD_CLOSING,
                                               wsi->parent->user_space, wsi, 0);
 
@@ -112,96 +296,110 @@ lws_remove_child_from_any_parent(struct lws *wsi)
                pwsi = &(*pwsi)->sibling_list;
        }
        if (!seen)
-               lwsl_err("%s: failed to detach from parent\n", __func__);
+               lwsl_wsi_err(wsi, "failed to detach from parent");
 
        wsi->parent = NULL;
 }
 
-#if !defined(LWS_NO_CLIENT)
-static int
-lws_close_trans_q_leader(struct lws_dll2 *d, void *user)
-{
-       struct lws *w = lws_container_of(d, struct lws, dll2_cli_txn_queue);
-
-       __lws_close_free_wsi(w, -1, "trans q leader closing");
-
-       return 0;
-}
-
+#if defined(LWS_WITH_CLIENT)
 void
 lws_inform_client_conn_fail(struct lws *wsi, void *arg, size_t len)
 {
+       lws_addrinfo_clean(wsi);
+
        if (wsi->already_did_cce)
                return;
 
        wsi->already_did_cce = 1;
-       lws_stats_bump(&wsi->context->pt[(int)wsi->tsi],
-                      LWSSTATS_C_CONNS_CLIENT_FAILED, 1);
 
-       if (!wsi->protocol)
+       if (!wsi->a.protocol)
                return;
 
-       wsi->protocol->callback(wsi,
-                               LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
-                               wsi->user_space, arg, len);
+       if (!wsi->client_suppress_CONNECTION_ERROR)
+               wsi->a.protocol->callback(wsi,
+                                       LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
+                                       wsi->user_space, arg, len);
 }
 #endif
 
 void
+lws_addrinfo_clean(struct lws *wsi)
+{
+#if defined(LWS_WITH_CLIENT)
+       struct lws_dll2 *d = lws_dll2_get_head(&wsi->dns_sorted_list), *d1;
+
+       while (d) {
+               lws_dns_sort_t *r = lws_container_of(d, lws_dns_sort_t, list);
+
+               d1 = d->next;
+               lws_dll2_remove(d);
+               lws_free(r);
+
+               d = d1;
+       }
+#endif
+}
+
+/* requires cx and pt lock */
+
+void
 __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
                     const char *caller)
 {
        struct lws_context_per_thread *pt;
-       struct lws *wsi1, *wsi2;
+       const struct lws_protocols *pro;
        struct lws_context *context;
-#if !defined(LWS_NO_CLIENT)
-       long rl = (long)(int)reason;
-#endif
-       int n;
-
-       lwsl_info("%s: %p: caller: %s\n", __func__, wsi, caller);
+       struct lws *wsi1, *wsi2;
+       int n, ccb;
 
        if (!wsi)
                return;
 
+       lwsl_wsi_info(wsi, "caller: %s", caller);
+
        lws_access_log(wsi);
 
-       context = wsi->context;
+       if (!lws_dll2_is_detached(&wsi->dll_buflist))
+               lwsl_wsi_info(wsi, "going down with stuff in buflist");
+
+       context = wsi->a.context;
        pt = &context->pt[(int)wsi->tsi];
-       lws_stats_bump(pt, LWSSTATS_C_API_CLOSE, 1);
 
-#if !defined(LWS_NO_CLIENT)
+       if (pt->pipe_wsi == wsi)
+               pt->pipe_wsi = NULL;
+
+#if defined(LWS_WITH_SYS_METRICS) && \
+    (defined(LWS_WITH_CLIENT) || defined(LWS_WITH_SERVER))
+       /* wsi level: only reports if dangling caliper */
+       if (wsi->cal_conn.mt && wsi->cal_conn.us_start) {
+               if ((lws_metrics_priv_to_pub(wsi->cal_conn.mt)->flags) & LWSMTFL_REPORT_HIST) {
+                       lws_metrics_caliper_report_hist(wsi->cal_conn, (struct lws *)NULL);
+               } else {
+                       lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
+                       lws_metrics_caliper_done(wsi->cal_conn);
+               }
+       } else
+               lws_metrics_caliper_done(wsi->cal_conn);
+#endif
 
-       lws_free_set_NULL(wsi->cli_hostname_copy);
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       if (wsi == context->async_dns.wsi)
+               context->async_dns.wsi = NULL;
+#endif
 
-       /*
-        * if we have wsi in our transaction queue, if we are closing we
-        * must go through and close all those first
-        */
-       if (wsi->vhost) {
+       lws_pt_assert_lock_held(pt);
 
-               /* we are no longer an active client connection that can piggyback */
-               lws_dll2_remove(&wsi->dll_cli_active_conns);
+#if defined(LWS_WITH_CLIENT)
 
-               if (rl != -1l)
-                       lws_vhost_lock(wsi->vhost);
+       lws_free_set_NULL(wsi->cli_hostname_copy);
+       wsi->client_mux_substream_was = wsi->client_mux_substream;
 
-               lws_dll2_foreach_safe(&wsi->dll2_cli_txn_queue_owner, NULL,
-                                     lws_close_trans_q_leader);
+       lws_addrinfo_clean(wsi);
+#endif
 
-               /*
-                * !!! If we are closing, but we have pending pipelined
-                * transaction results we already sent headers for, that's going
-                * to destroy sync for HTTP/1 and leave H2 stream with no live
-                * swsi.`
-                *
-                * However this is normal if we are being closed because the
-                * transaction queue leader is closing.
-                */
-               lws_dll2_remove(&wsi->dll2_cli_txn_queue);
-               if (rl != -1l)
-                       lws_vhost_unlock(wsi->vhost);
-       }
+#if defined(LWS_WITH_HTTP2)
+       if (wsi->mux_stream_immortal)
+               lws_http_close_immortal(wsi);
 #endif
 
        /* if we have children, close them first */
@@ -209,7 +407,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
                wsi2 = wsi->child_list;
                while (wsi2) {
                        wsi1 = wsi2->sibling_list;
-                       wsi2->parent = NULL;
+//                     wsi2->parent = NULL;
                        /* stop it doing shutdown processing */
                        wsi2->socket_is_permanently_unusable = 1;
                        __lws_close_free_wsi(wsi2, reason,
@@ -219,30 +417,38 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
                wsi->child_list = NULL;
        }
 
+#if defined(LWS_ROLE_RAW_FILE)
        if (wsi->role_ops == &role_ops_raw_file) {
                lws_remove_child_from_any_parent(wsi);
                __remove_wsi_socket_from_fds(wsi);
-               if (wsi->protocol)
-                       wsi->protocol->callback(wsi, wsi->role_ops->close_cb[0],
+               if (wsi->a.protocol)
+                       wsi->a.protocol->callback(wsi, wsi->role_ops->close_cb[0],
                                        wsi->user_space, NULL, 0);
                goto async_close;
        }
+#endif
 
        wsi->wsistate_pre_close = wsi->wsistate;
 
 #ifdef LWS_WITH_CGI
        if (wsi->role_ops == &role_ops_cgi) {
 
-               // lwsl_debug("%s: closing stdwsi index %d\n", __func__, (int)wsi->cgi_channel);
+               // lwsl_debug("%s: closing stdwsi index %d\n", __func__, (int)wsi->lsp_channel);
 
                /* we are not a network connection, but a handler for CGI io */
                if (wsi->parent && wsi->parent->http.cgi) {
 
-                       if (wsi->parent->child_list == wsi && !wsi->sibling_list)
-                               lws_cgi_remove_and_kill(wsi->parent);
+                       /*
+                        * We need to keep the logical cgi around so we can
+                        * drain it
+                        */
+
+//                     if (wsi->parent->child_list == wsi && !wsi->sibling_list)
+//                             lws_cgi_remove_and_kill(wsi->parent);
 
-                       /* end the binding between us and master */
-                       wsi->parent->http.cgi->stdwsi[(int)wsi->cgi_channel] =
+                       /* end the binding between us and network connection */
+                       if (wsi->parent->http.cgi && wsi->parent->http.cgi->lsp)
+                               wsi->parent->http.cgi->lsp->stdwsi[(int)wsi->lsp_channel] =
                                                                        NULL;
                }
                wsi->socket_is_permanently_unusable = 1;
@@ -254,15 +460,16 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
                lws_cgi_remove_and_kill(wsi);
 #endif
 
-#if !defined(LWS_NO_CLIENT)
-       lws_client_stash_destroy(wsi);
+#if defined(LWS_WITH_CLIENT)
+       if (!wsi->close_is_redirect)
+               lws_free_set_NULL(wsi->stash);
 #endif
 
        if (wsi->role_ops == &role_ops_raw_skt) {
                wsi->socket_is_permanently_unusable = 1;
                goto just_kill_connection;
        }
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+#if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
        if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
            wsi->http.fop_fd != NULL)
                lws_vfs_file_close(&wsi->http.fop_fd);
@@ -296,7 +503,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
                        lws_callback_on_writable(wsi);
                        return;
                }
-               lwsl_info("%p: end LRS_FLUSHING_BEFORE_CLOSE\n", wsi);
+               lwsl_wsi_info(wsi, " end LRS_FLUSHING_BEFORE_CLOSE");
                goto just_kill_connection;
        default:
                if (lws_has_buffered_out(wsi)
@@ -305,7 +512,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
                    wsi->http.comp_ctx.may_have_more
 #endif
                ) {
-                       lwsl_info("%p: LRS_FLUSHING_BEFORE_CLOSE\n", wsi);
+                       lwsl_wsi_info(wsi, "LRS_FLUSHING_BEFORE_CLOSE");
                        lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE);
                        __lws_set_timeout(wsi,
                                PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE, 5);
@@ -315,12 +522,13 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
        }
 
        if (lwsi_state(wsi) == LRS_WAITING_CONNECT ||
+           lwsi_state(wsi) == LRS_WAITING_DNS ||
            lwsi_state(wsi) == LRS_H1C_ISSUE_HANDSHAKE)
                goto just_kill_connection;
 
-       if (!wsi->told_user_closed && wsi->user_space && wsi->protocol &&
+       if (!wsi->told_user_closed && wsi->user_space && wsi->a.protocol &&
            wsi->protocol_bind_balance) {
-               wsi->protocol->callback(wsi,
+               wsi->a.protocol->callback(wsi,
                                wsi->role_ops->protocol_unbind_cb[
                                       !!lwsi_role_server(wsi)],
                                       wsi->user_space, (void *)__func__, 0);
@@ -339,46 +547,87 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
         * LRS_AWAITING_CLOSE_ACK and will skip doing this a second time.
         */
 
-       if (wsi->role_ops->close_via_role_protocol &&
-           wsi->role_ops->close_via_role_protocol(wsi, reason))
+       if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_close_via_role_protocol) &&
+           lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_close_via_role_protocol).
+                                        close_via_role_protocol(wsi, reason)) {
+               lwsl_wsi_info(wsi, "close_via_role took over (sockfd %d)",
+                             wsi->desc.sockfd);
                return;
+       }
 
 just_kill_connection:
 
+       lwsl_wsi_debug(wsi, "real just_kill_connection A: (sockfd %d)",
+                       wsi->desc.sockfd);
+
+#if defined(LWS_WITH_THREADPOOL)
+       lws_threadpool_wsi_closing(wsi);
+#endif
+
 #if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
-       if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
-           wsi->http.fop_fd != NULL)
-              lws_vfs_file_close(&wsi->http.fop_fd);
+       if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
+           wsi->http.fop_fd != NULL)
+               lws_vfs_file_close(&wsi->http.fop_fd);
+#endif
+
+       lws_sul_cancel(&wsi->sul_connect_timeout);
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       lws_async_dns_cancel(wsi);
 #endif
 
 #if defined(LWS_WITH_HTTP_PROXY)
        if (wsi->http.buflist_post_body)
                lws_buflist_destroy_all_segments(&wsi->http.buflist_post_body);
 #endif
+#if defined(LWS_WITH_UDP)
+       if (wsi->udp) {
+               /* confirm no sul left scheduled in wsi->udp itself */
+               lws_sul_debug_zombies(wsi->a.context, wsi->udp,
+                                       sizeof(*wsi->udp), "close udp wsi");
 
-       if (wsi->role_ops->close_kill_connection)
-               wsi->role_ops->close_kill_connection(wsi, reason);
+               lws_free_set_NULL(wsi->udp);
+       }
+#endif
+
+       if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_close_kill_connection))
+               lws_rops_func_fidx(wsi->role_ops,
+                                  LWS_ROPS_close_kill_connection).
+                                           close_kill_connection(wsi, reason);
 
        n = 0;
 
        if (!wsi->told_user_closed && wsi->user_space &&
-           wsi->protocol_bind_balance && wsi->protocol) {
-               lwsl_debug("%s: %p: DROP_PROTOCOL %s\n", __func__, wsi,
-                          wsi->protocol ? wsi->protocol->name: "NULL");
-               if (wsi->protocol)
-                       wsi->protocol->callback(wsi,
+           wsi->protocol_bind_balance && wsi->a.protocol) {
+               lwsl_debug("%s: %s: DROP_PROTOCOL %s\n", __func__, lws_wsi_tag(wsi),
+                          wsi->a.protocol ? wsi->a.protocol->name: "NULL");
+               if (wsi->a.protocol)
+                       wsi->a.protocol->callback(wsi,
                                wsi->role_ops->protocol_unbind_cb[
                                       !!lwsi_role_server(wsi)],
                                       wsi->user_space, (void *)__func__, 0);
                wsi->protocol_bind_balance = 0;
        }
 
-#if !defined(LWS_NO_CLIENT)
-       if ((lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY ||
+#if defined(LWS_WITH_CLIENT)
+       if ((
+#if defined(LWS_ROLE_WS)
+               /*
+                * If our goal is a ws upgrade, effectively we did not reach
+                * ESTABLISHED if we did not get the upgrade server reply
+                */
+               (lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY &&
+                wsi->role_ops == &role_ops_ws) ||
+#endif
+            lwsi_state(wsi) == LRS_WAITING_DNS ||
             lwsi_state(wsi) == LRS_WAITING_CONNECT) &&
-            !wsi->already_did_cce && wsi->protocol) {
+            !wsi->already_did_cce && wsi->a.protocol &&
+            !wsi->close_is_redirect) {
                static const char _reason[] = "closed before established";
 
+               lwsl_wsi_debug(wsi, "closing in unestablished state 0x%x",
+                               lwsi_state(wsi));
+               wsi->socket_is_permanently_unusable = 1;
+
                lws_inform_client_conn_fail(wsi,
                        (void *)_reason, sizeof(_reason));
        }
@@ -411,8 +660,8 @@ just_kill_connection:
                } else
 #endif
                {
-                       lwsl_info("%s: shutdown conn: %p (sk %d, state 0x%x)\n",
-                                 __func__, wsi, (int)(long)wsi->desc.sockfd,
+                       lwsl_info("%s: shutdown conn: %s (sk %d, state 0x%x)\n",
+                                 __func__, lws_wsi_tag(wsi), (int)(lws_intptr_t)wsi->desc.sockfd,
                                  lwsi_state(wsi));
                        if (!wsi->socket_is_permanently_unusable &&
                            lws_socket_is_valid(wsi->desc.sockfd)) {
@@ -421,31 +670,34 @@ just_kill_connection:
                        }
                }
                if (n)
-                       lwsl_debug("closing: shutdown (state 0x%x) ret %d\n",
+                       lwsl_wsi_debug(wsi, "closing: shutdown (state 0x%x) ret %d",
                                   lwsi_state(wsi), LWS_ERRNO);
 
                /*
                 * This causes problems on WINCE / ESP32 with disconnection
                 * when the events are half closing connection
                 */
-#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP32)
+#if !defined(_WIN32_WCE) && !defined(LWS_PLAT_FREERTOS)
                /* libuv: no event available to guarantee completion */
                if (!wsi->socket_is_permanently_unusable &&
+#if defined(LWS_WITH_CLIENT)
+                   !wsi->close_is_redirect &&
+#endif
                    lws_socket_is_valid(wsi->desc.sockfd) &&
                    lwsi_state(wsi) != LRS_SHUTDOWN &&
-                   context->event_loop_ops->periodic_events_available) {
+                   (context->event_loop_ops->flags & LELOF_ISPOLL)) {
                        __lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
                        lwsi_set_state(wsi, LRS_SHUTDOWN);
                        __lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,
-                                         context->timeout_secs);
+                                         (int)context->timeout_secs);
 
                        return;
                }
 #endif
        }
 
-       lwsl_debug("%s: real just_kill_connection: %p (sockfd %d)\n", __func__,
-                  wsi, wsi->desc.sockfd);
+       lwsl_wsi_info(wsi, "real just_kill_connection: sockfd %d\n",
+                       wsi->desc.sockfd);
 
 #ifdef LWS_WITH_HUBBUB
        if (wsi->http.rw) {
@@ -467,35 +719,28 @@ just_kill_connection:
        //if (wsi->told_event_loop_closed) // cgi std close case (dummy-callback)
        //      return;
 
-       // lwsl_notice("%s: wsi %p, fd %d\n", __func__, wsi, wsi->desc.sockfd);
-
        /* checking return redundant since we anyway close */
-       if (wsi->desc.sockfd != LWS_SOCK_INVALID)
-               __remove_wsi_socket_from_fds(wsi);
-       else
-               __lws_same_vh_protocol_remove(wsi);
+       __remove_wsi_socket_from_fds(wsi);
 
        lwsi_set_state(wsi, LRS_DEAD_SOCKET);
        lws_buflist_destroy_all_segments(&wsi->buflist);
        lws_dll2_remove(&wsi->dll_buflist);
 
-       if (wsi->role_ops->close_role)
-           wsi->role_ops->close_role(pt, wsi);
+       if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_close_role))
+               lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_close_role).
+                                                       close_role(pt, wsi);
 
        /* tell the user it's all over for this guy */
 
+       ccb = 0;
        if ((lwsi_state_est_PRE_CLOSE(wsi) ||
            /* raw skt adopted but didn't complete tls hs should CLOSE */
            (wsi->role_ops == &role_ops_raw_skt && !lwsi_role_client(wsi)) ||
             lwsi_state_PRE_CLOSE(wsi) == LRS_WAITING_SERVER_REPLY) &&
            !wsi->told_user_closed &&
            wsi->role_ops->close_cb[lwsi_role_server(wsi)]) {
-               const struct lws_protocols *pro = wsi->protocol;
-
-               if (!wsi->protocol && wsi->vhost && wsi->vhost->protocols)
-                       pro = &wsi->vhost->protocols[0];
-
-               if (pro && (!wsi->upgraded_to_http2 || !lwsi_role_client(wsi)))
+               if (!wsi->upgraded_to_http2 || !lwsi_role_client(wsi))
+                       ccb = 1;
                        /*
                         * The network wsi for a client h2 connection shouldn't
                         * call back for its role: the child stream connections
@@ -503,23 +748,131 @@ just_kill_connection:
                         * one too many times as the children do it and then
                         * the closing network stream.
                         */
+       }
+
+       if (!wsi->told_user_closed &&
+           !lws_dll2_is_detached(&wsi->vh_awaiting_socket))
+               /*
+                * He's a guy who go started with dns, but failed or is
+                * caught with a shutdown before he got the result.  We have
+                * to issclient_mux_substream_wasue him a close cb
+                */
+               ccb = 1;
+
+       lwsl_wsi_info(wsi, "cce=%d", ccb);
+
+       pro = wsi->a.protocol;
+
+       if (wsi->already_did_cce)
+               /*
+                * If we handled this by CLIENT_CONNECTION_ERROR, it's
+                * mutually exclusive with CLOSE
+                */
+               ccb = 0;
+
+#if defined(LWS_WITH_CLIENT)
+       if (!wsi->close_is_redirect && !ccb &&
+           (lwsi_state_PRE_CLOSE(wsi) & LWSIFS_NOT_EST) &&
+                       lwsi_role_client(wsi)) {
+               lws_inform_client_conn_fail(wsi, "Closed before conn", 18);
+       }
+#endif
+       if (ccb
+#if defined(LWS_WITH_CLIENT)
+                       && !wsi->close_is_redirect
+#endif
+       ) {
+
+               if (!wsi->a.protocol && wsi->a.vhost && wsi->a.vhost->protocols)
+                       pro = &wsi->a.vhost->protocols[0];
+
+               if (pro)
                        pro->callback(wsi,
-                             wsi->role_ops->close_cb[lwsi_role_server(wsi)],
-                             wsi->user_space, NULL, 0);
+                               wsi->role_ops->close_cb[lwsi_role_server(wsi)],
+                               wsi->user_space, NULL, 0);
                wsi->told_user_closed = 1;
        }
 
+#if defined(LWS_ROLE_RAW_FILE)
 async_close:
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       if (wsi->for_ss) {
+               lwsl_wsi_debug(wsi, "for_ss");
+               /*
+                * We were adopted for a particular ss, but, eg, we may not
+                * have succeeded with the connection... we are closing which is
+                * good, but we have to invalidate any pointer the related ss
+                * handle may be holding on us
+                */
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+               if (wsi->client_proxy_onward) {
+                       /*
+                        * We are an onward proxied wsi at the proxy,
+                        * opaque is proxing "conn", we must remove its pointer
+                        * to us since we are destroying
+                        */
+                       lws_proxy_clean_conn_ss(wsi);
+               } else
+
+                       if (wsi->client_bound_sspc) {
+                               lws_sspc_handle_t *h = (lws_sspc_handle_t *)wsi->a.opaque_user_data;
+
+                               if (h) { // && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) {
+
+#if defined(LWS_WITH_SYS_METRICS)
+                                       /*
+                                        * If any hanging caliper measurement, dump it, and free any tags
+                                        */
+                                       lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+
+                                       h->cwsi = NULL;
+                                       //wsi->a.opaque_user_data = NULL;
+                               }
+                       } else
+#endif
+               {
+                       lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data;
+
+                       if (h) { // && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) {
+
+                               /*
+                                * ss level: only reports if dangling caliper
+                                * not already reported
+                                */
+                               lws_metrics_caliper_report_hist(h->cal_txn, wsi);
+
+                               h->wsi = NULL;
+                               wsi->a.opaque_user_data = NULL;
+
+                               if (h->ss_dangling_connected &&
+                                   lws_ss_event_helper(h, LWSSSCS_DISCONNECTED) ==
+                                                   LWSSSSRET_DESTROY_ME) {
+
+                                       lws_ss_destroy(&h);
+                               }
+                       }
+               }
+       }
+#endif
+
+
        lws_remove_child_from_any_parent(wsi);
        wsi->socket_is_permanently_unusable = 1;
 
-       if (wsi->context->event_loop_ops->wsi_logical_close)
-               if (wsi->context->event_loop_ops->wsi_logical_close(wsi))
+       if (wsi->a.context->event_loop_ops->wsi_logical_close)
+               if (wsi->a.context->event_loop_ops->wsi_logical_close(wsi))
                        return;
 
        __lws_close_free_wsi_final(wsi);
 }
 
+
+/* cx + vh lock */
+
 void
 __lws_close_free_wsi_final(struct lws *wsi)
 {
@@ -527,36 +880,126 @@ __lws_close_free_wsi_final(struct lws *wsi)
 
        if (!wsi->shadow &&
            lws_socket_is_valid(wsi->desc.sockfd) && !lws_ssl_close(wsi)) {
-               lwsl_debug("%s: wsi %p: fd %d\n", __func__, wsi, wsi->desc.sockfd);
+               lwsl_wsi_debug(wsi, "fd %d", wsi->desc.sockfd);
                n = compatible_close(wsi->desc.sockfd);
                if (n)
-                       lwsl_debug("closing: close ret %d\n", LWS_ERRNO);
+                       lwsl_wsi_debug(wsi, "closing: close ret %d", LWS_ERRNO);
+
+               __remove_wsi_socket_from_fds(wsi);
+               if (lws_socket_is_valid(wsi->desc.sockfd))
+                       delete_from_fd(wsi->a.context, wsi->desc.sockfd);
+
+#if !defined(LWS_PLAT_FREERTOS) && !defined(WIN32) && !defined(LWS_PLAT_OPTEE)
+               delete_from_fdwsi(wsi->a.context, wsi);
+#endif
 
-               wsi->desc.sockfd = LWS_SOCK_INVALID;
+               sanity_assert_no_sockfd_traces(wsi->a.context, wsi->desc.sockfd);
        }
 
-       /* outermost destroy notification for wsi (user_space still intact) */
-       if (wsi->vhost)
-               wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY,
-                                                 wsi->user_space, NULL, 0);
+       /* ... if we're closing the cancel pipe, account for it */
 
-#ifdef LWS_WITH_CGI
-       if (wsi->http.cgi) {
+       {
+               struct lws_context_per_thread *pt =
+                               &wsi->a.context->pt[(int)wsi->tsi];
+
+               if (pt->pipe_wsi == wsi)
+                       pt->pipe_wsi = NULL;
+               if (pt->dummy_pipe_fds[0] == wsi->desc.sockfd)
+                       pt->dummy_pipe_fds[0] = LWS_SOCK_INVALID;
+       }
+
+       wsi->desc.sockfd = LWS_SOCK_INVALID;
+
+#if defined(LWS_WITH_CLIENT)
+       lws_free_set_NULL(wsi->cli_hostname_copy);
+       if (wsi->close_is_redirect) {
+
+               wsi->close_is_redirect = 0;
+
+               lwsl_wsi_info(wsi, "picking up redirection");
+
+               lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
+                                   &role_ops_h1);
+
+#if defined(LWS_WITH_HTTP2)
+               if (wsi->client_mux_substream_was)
+                       wsi->h2.END_STREAM = wsi->h2.END_HEADERS = 0;
+#endif
+#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
+               if (wsi->mux.parent_wsi) {
+                       lws_wsi_mux_sibling_disconnect(wsi);
+                       wsi->mux.parent_wsi = NULL;
+               }
+#endif
+
+#if defined(LWS_WITH_TLS)
+               memset(&wsi->tls, 0, sizeof(wsi->tls));
+#endif
+
+       //      wsi->a.protocol = NULL;
+               if (wsi->a.protocol)
+                       lws_bind_protocol(wsi, wsi->a.protocol, "client_reset");
+               wsi->pending_timeout = NO_PENDING_TIMEOUT;
+               wsi->hdr_parsing_completed = 0;
 
-               for (n = 0; n < 3; n++) {
-                       if (wsi->http.cgi->pipe_fds[n][!!(n == 0)] == 0)
-                               lwsl_err("ZERO FD IN CGI CLOSE");
+#if defined(LWS_WITH_TLS)
+               if (wsi->stash->cis[CIS_ALPN])
+                       lws_strncpy(wsi->alpn, wsi->stash->cis[CIS_ALPN],
+                                   sizeof(wsi->alpn));
+#endif
 
-                       if (wsi->http.cgi->pipe_fds[n][!!(n == 0)] >= 0) {
-                               close(wsi->http.cgi->pipe_fds[n][!!(n == 0)]);
-                               wsi->http.cgi->pipe_fds[n][!!(n == 0)] = LWS_SOCK_INVALID;
+               if (lws_header_table_attach(wsi, 0)) {
+                       lwsl_wsi_err(wsi, "failed to get ah");
+                       return;
+               }
+//             }
+               //_lws_header_table_reset(wsi->http.ah);
+
+#if defined(LWS_WITH_TLS)
+               wsi->tls.use_ssl = (unsigned int)wsi->flags;
+#endif
+
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+               if (wsi->stash && wsi->stash->cis[CIS_ADDRESS]) {
+                       struct lws_vhost *vh = NULL;
+                       lws_tls_jit_trust_vhost_bind(wsi->a.context,
+                                                    wsi->stash->cis[CIS_ADDRESS],
+                                                    &vh);
+                       if (vh) {
+                               if (!vh->count_bound_wsi && vh->grace_after_unref) {
+                                       lwsl_wsi_info(wsi, "%s in use\n",
+                                                               vh->lc.gutag);
+                                       lws_sul_cancel(&vh->sul_unref);
+                               }
+                               vh->count_bound_wsi++;
+                               wsi->a.vhost = vh;
                        }
                }
+#endif
 
+               return;
+       }
+#endif
+
+       /* outermost destroy notification for wsi (user_space still intact) */
+       if (wsi->a.vhost)
+               wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY,
+                                                 wsi->user_space, NULL, 0);
+
+#ifdef LWS_WITH_CGI
+       if (wsi->http.cgi) {
+               lws_spawn_piped_destroy(&wsi->http.cgi->lsp);
+               lws_sul_cancel(&wsi->http.cgi->sul_grace);
                lws_free_set_NULL(wsi->http.cgi);
        }
 #endif
 
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_destroy(&wsi->fic);
+#endif
+
+       __lws_wsi_remove_from_sul(wsi);
+       sanity_assert_no_wsi_traces(wsi->a.context, wsi);
        __lws_free_wsi(wsi);
 }
 
@@ -564,11 +1007,17 @@ __lws_close_free_wsi_final(struct lws *wsi)
 void
 lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *caller)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context *cx = wsi->a.context;
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+
+       lws_context_lock(cx, __func__);
 
        lws_pt_lock(pt, __func__);
+       /* may destroy vhost, cannot hold vhost lock outside it */
        __lws_close_free_wsi(wsi, reason, caller);
        lws_pt_unlock(pt);
+
+       lws_context_unlock(cx);
 }
 
 
diff --git a/lib/core-net/connect.c b/lib/core-net/connect.c
deleted file mode 100644 (file)
index 3d01dc8..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-void
-lws_client_stash_destroy(struct lws *wsi)
-{
-       if (!wsi || !wsi->stash)
-               return;
-
-       lws_free_set_NULL(wsi->stash->address);
-       lws_free_set_NULL(wsi->stash->path);
-       lws_free_set_NULL(wsi->stash->host);
-       lws_free_set_NULL(wsi->stash->origin);
-       lws_free_set_NULL(wsi->stash->protocol);
-       lws_free_set_NULL(wsi->stash->method);
-       lws_free_set_NULL(wsi->stash->iface);
-       lws_free_set_NULL(wsi->stash->alpn);
-
-       lws_free_set_NULL(wsi->stash);
-}
-
-LWS_VISIBLE struct lws *
-lws_client_connect_via_info(const struct lws_client_connect_info *i)
-{
-       struct lws *wsi, *safe = NULL;
-       const struct lws_protocols *p;
-       const char *local = i->protocol;
-       int tid = 0;
-#if LWS_MAX_SMP > 1
-       int n;
-#endif
-
-       if (i->context->requested_kill)
-               return NULL;
-
-       if (!i->context->protocol_init_done)
-               if (lws_protocol_init(i->context))
-                       return NULL;
-
-       /*
-        * If we have .local_protocol_name, use it to select the local protocol
-        * handler to bind to.  Otherwise use .protocol if http[s].
-        */
-       if (i->local_protocol_name)
-               local = i->local_protocol_name;
-
-       lws_stats_bump(&i->context->pt[tid], LWSSTATS_C_CONNS_CLIENT, 1);
-
-       /* PHASE 1: create a bare wsi */
-
-       wsi = lws_zalloc(sizeof(struct lws), "client wsi");
-       if (wsi == NULL)
-               goto bail;
-
-       wsi->context = i->context;
-       wsi->desc.sockfd = LWS_SOCK_INVALID;
-       wsi->seq = i->seq;
-
-       wsi->vhost = NULL;
-       if (!i->vhost)
-               lws_vhost_bind_wsi(i->context->vhost_list, wsi);
-       else
-               lws_vhost_bind_wsi(i->vhost, wsi);
-
-       if (!wsi->vhost) {
-               lwsl_err("%s: No vhost in the context\n", __func__);
-
-               goto bail;
-       }
-
-#if LWS_MAX_SMP > 1
-       tid = wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_GET_THREAD_ID,
-                                               NULL, NULL, 0);
-#endif
-
-       /*
-        * PHASE 2: if SMP, bind the client to whatever tsi the current thread
-        * represents
-        */
-
-#if LWS_MAX_SMP > 1
-       lws_context_lock(i->context, "client find tsi");
-
-       for (n = 0; n < i->context->count_threads; n++)
-               if (i->context->pt[n].service_tid == tid) {
-                       lwsl_info("%s: client binds to caller tsi %d\n",
-                                 __func__, n);
-                       wsi->tsi = n;
-                       break;
-               }
-
-       /*
-        * this binding is sort of provisional, since when we try to insert
-        * into the pt fds, there may be no space and it will fail
-        */
-
-       lws_context_unlock(i->context);
-#endif
-
-       /*
-        * PHASE 3: Choose an initial role for the wsi and do role-specific init
-        *
-        * Note the initial role may not reflect the final role, eg,
-        * we may want ws, but first we have to go through h1 to get that
-        */
-
-       if (lws_role_call_client_bind(wsi, i) < 0) {
-               lwsl_err("%s: unable to bind to role\n", __func__);
-
-               goto bail;
-       }
-       lwsl_info("%s: role binding to %s\n", __func__, wsi->role_ops->name);
-
-       /*
-        * PHASE 4: fill up the wsi with stuff from the connect_info as far as
-        * it can go.  It's uncertain because not only is our connection
-        * going to complete asynchronously, we might have bound to h1 and not
-        * even be able to get ahold of an ah immediately.
-        */
-
-       wsi->user_space = NULL;
-       wsi->pending_timeout = NO_PENDING_TIMEOUT;
-       wsi->position_in_fds_table = LWS_NO_FDS_POS;
-       wsi->ocport = wsi->c_port = i->port;
-
-       wsi->protocol = &wsi->vhost->protocols[0];
-       wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE);
-
-       /*
-        * PHASE 5: handle external user_space now, generic alloc is done in
-        * role finalization
-        */
-
-       if (!wsi->user_space && i->userdata) {
-               wsi->user_space_externally_allocated = 1;
-               wsi->user_space = i->userdata;
-       }
-
-       if (local) {
-               lwsl_info("%s: protocol binding to %s\n", __func__, local);
-               p = lws_vhost_name_to_protocol(wsi->vhost, local);
-               if (p)
-                       lws_bind_protocol(wsi, p, __func__);
-       }
-
-       /*
-        * PHASE 5: handle external user_space now, generic alloc is done in
-        * role finalization
-        */
-
-       if (!wsi->user_space && i->userdata) {
-               wsi->user_space_externally_allocated = 1;
-               wsi->user_space = i->userdata;
-       }
-
-#if defined(LWS_WITH_TLS)
-       wsi->tls.use_ssl = i->ssl_connection;
-#else
-       if (i->ssl_connection & LCCSCF_USE_SSL) {
-               lwsl_err("%s: lws not configured for tls\n", __func__);
-               goto bail;
-       }
-#endif
-
-       /*
-        * PHASE 6: stash the things from connect_info that we can't process
-        * right now, eg, if http binding, without an ah.  If h1 and no ah, we
-        * will go on the ah waiting list and process those things later (after
-        * the connect_info and maybe the things pointed to have gone out of
-        * scope)
-        *
-        * However these things are stashed in a generic way at this point,
-        * with no relationship to http or ah
-        */
-
-       wsi->stash = lws_zalloc(sizeof(*wsi->stash), "client stash");
-       if (!wsi->stash) {
-               lwsl_err("%s: OOM\n", __func__);
-               goto bail1;
-       }
-
-       wsi->stash->address = lws_strdup(i->address);
-       wsi->stash->path = lws_strdup(i->path);
-       wsi->stash->host = lws_strdup(i->host);
-       wsi->stash->opaque_user_data = i->opaque_user_data;
-
-       if (!wsi->stash->address || !wsi->stash->path || !wsi->stash->host)
-               goto bail1;
-
-       if (i->origin) {
-               wsi->stash->origin = lws_strdup(i->origin);
-               if (!wsi->stash->origin)
-                       goto bail1;
-       }
-       if (i->protocol) {
-               wsi->stash->protocol = lws_strdup(i->protocol);
-               if (!wsi->stash->protocol)
-                       goto bail1;
-       }
-       if (i->method) {
-               wsi->stash->method = lws_strdup(i->method);
-               if (!wsi->stash->method)
-                       goto bail1;
-       }
-       if (i->iface) {
-               wsi->stash->iface = lws_strdup(i->iface);
-               if (!wsi->stash->iface)
-                       goto bail1;
-       }
-       if (i->alpn) {
-               wsi->stash->alpn = lws_strdup(i->alpn);
-               if (!wsi->stash->alpn)
-                       goto bail1;
-       }
-
-       /*
-        * at this point user callbacks like
-        * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER will be interested to
-        * know the parent... eg for proxying we can grab extra headers from
-        * the parent's incoming ah and add them to the child client handshake
-        */
-
-       if (i->parent_wsi) {
-               lwsl_info("%s: created child %p of parent %p\n", __func__,
-                         wsi, i->parent_wsi);
-               wsi->parent = i->parent_wsi;
-               safe = wsi->sibling_list = i->parent_wsi->child_list;
-               i->parent_wsi->child_list = wsi;
-       }
-
-       /*
-        * PHASE 7: Do any role-specific finalization processing.  We can still
-        * see important info things via wsi->stash
-        */
-
-       if (wsi->role_ops->client_bind) {
-               int n = wsi->role_ops->client_bind(wsi, NULL);
-
-               if (n && i->parent_wsi) {
-                       /* unpick from parent */
-
-                       i->parent_wsi->child_list = safe;
-               }
-
-               if (n < 0)
-                       /* we didn't survive, wsi is freed */
-                       goto bail2;
-
-               if (n)
-                       /* something else failed, wsi needs freeing */
-                       goto bail;
-       }
-
-       /* let the caller's optional wsi storage have the wsi we created */
-
-       if (i->pwsi)
-               *i->pwsi = wsi;
-
-       /* PHASE 8: notify protocol with role-specific connected callback */
-
-       lwsl_debug("%s: wsi %p: cb %d to %s %s\n", __func__,
-                       wsi, wsi->role_ops->adoption_cb[0],
-                       wsi->role_ops->name, wsi->protocol->name);
-
-       wsi->protocol->callback(wsi,
-                       wsi->role_ops->adoption_cb[0],
-                       wsi->user_space, NULL, 0);
-
-#if defined(LWS_WITH_HUBBUB)
-       if (i->uri_replace_to)
-               wsi->http.rw = lws_rewrite_create(wsi, html_parser_cb,
-                                            i->uri_replace_from,
-                                            i->uri_replace_to);
-#endif
-
-       if (i->method && !strcmp(i->method, "RAW"))
-               lws_http_client_connect_via_info2(wsi);
-
-       return wsi;
-
-bail1:
-       lws_client_stash_destroy(wsi);
-
-bail:
-       lws_free(wsi);
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-bail2:
-#endif
-       if (i->pwsi)
-               *i->pwsi = NULL;
-
-       lws_stats_bump(&i->context->pt[tid], LWSSTATS_C_CONNS_CLIENT_FAILED, 1);
-
-       return NULL;
-}
index 097fb03..9552af5 100644 (file)
@@ -1,45 +1,58 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
+
+/* max individual proxied header payload size */
+#define MAXHDRVAL 1024
 
 #if defined(LWS_WITH_HTTP_PROXY)
 static int
 proxy_header(struct lws *wsi, struct lws *par, unsigned char *temp,
             int temp_len, int index, unsigned char **p, unsigned char *end)
 {
-       int n = lws_hdr_total_length(par, index);
+       int n = lws_hdr_total_length(par, (enum lws_token_indexes)index);
 
        if (n < 1) {
-               lwsl_debug("%s: no index %d:\n", __func__, index);
+               lwsl_wsi_debug(wsi, "no index %d:", index);
+
                return 0;
        }
 
-       if (lws_hdr_copy(par, (char *)temp, temp_len, index) < 0)
+       if (lws_hdr_copy(par, (char *)temp, temp_len, (enum lws_token_indexes)index) < 0) {
+               lwsl_wsi_notice(wsi, "unable to copy par hdr idx %d (len %d)",
+                                     index, n);
                return -1;
+       }
 
-       lwsl_debug("%s: index %d: %s\n", __func__, index, (char *)temp);
+       lwsl_wsi_debug(wsi, "index %d: %s", index, (char *)temp);
 
-       if (lws_add_http_header_by_token(wsi, index, temp, n, p, end))
+       if (lws_add_http_header_by_token(wsi, (enum lws_token_indexes)index, temp, n, p, end)) {
+               lwsl_wsi_notice(wsi, "unable to append par hdr idx %d (len %d)",
+                                    index, n);
                return -1;
+       }
 
        return 0;
 }
@@ -54,31 +67,30 @@ stream_close(struct lws *wsi)
 
        wsi->http.did_stream_close = 1;
 
-       if (wsi->http2_substream) {
+       if (wsi->mux_substream) {
                if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
-                             LWS_WRITE_HTTP_FINAL) < 0) {
-                       lwsl_info("%s: COMPL_CLIENT_HTTP: h2 fin wr failed\n",
-                                 __func__);
+                             LWS_WRITE_HTTP_FINAL) < 0)
+                       goto bail;
 
-                       return -1;
-               }
-       } else {
-               *out++ = '0';
-               *out++ = '\x0d';
-               *out++ = '\x0a';
-               *out++ = '\x0d';
-               *out++ = '\x0a';
-
-               if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 5,
-                             LWS_WRITE_HTTP_FINAL) < 0) {
-                       lwsl_err("%s: COMPL_CLIENT_HTTP: "
-                                "h2 final write failed\n", __func__);
-
-                       return -1;
-               }
+               return 0;
        }
 
+       *out++ = '0';
+       *out++ = '\x0d';
+       *out++ = '\x0a';
+       *out++ = '\x0d';
+       *out++ = '\x0a';
+
+       if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 5,
+                     LWS_WRITE_HTTP_FINAL) < 0)
+               goto bail;
+
        return 0;
+
+bail:
+       lwsl_wsi_info(wsi, "h2 fin wr failed");
+
+       return -1;
 }
 
 #endif
@@ -109,11 +121,12 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason,
                if (!wsi->h1_ws_proxied || !wsi->parent)
                        break;
 
-               lws_process_ws_upgrade2(wsi->parent);
+               if (lws_process_ws_upgrade2(wsi->parent))
+                       return -1;
 
 #if defined(LWS_WITH_HTTP2)
-               if (wsi->parent->http2_substream)
-                       lwsl_info("%s: proxied h2 -> h1 ws established\n", __func__);
+               if (wsi->parent->mux_substream)
+                       lwsl_wsi_info(wsi, "proxied h2 -> h1 ws established");
 #endif
                break;
 
@@ -122,17 +135,16 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason,
 
        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
        case LWS_CALLBACK_CLIENT_CLOSED:
-               lwsl_user("%s: client closed: parent %p\n", __func__, wsi->parent);
+               lwsl_wsi_info(wsi, "client closed: parent %s",
+                                  lws_wsi_tag(wsi->parent));
                if (wsi->parent)
-                       lws_set_timeout(wsi->parent,
-                               PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE,
-                               LWS_TO_KILL_ASYNC);
+                       lws_set_timeout(wsi->parent, 1, LWS_TO_KILL_ASYNC);
                break;
 
        case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
        {
                unsigned char **p = (unsigned char **)in, *end = (*p) + len,
-                                   tmp[128];
+                                   tmp[MAXHDRVAL];
 
                proxy_header(wsi, wsi->parent, tmp, sizeof(tmp),
                              WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end);
@@ -148,19 +160,18 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason,
        case LWS_CALLBACK_CLIENT_RECEIVE:
                wsi->parent->ws->proxy_buffered += len;
                if (wsi->parent->ws->proxy_buffered > 10 * 1024 * 1024) {
-                       lwsl_err("%s: proxied ws connection excessive buffering: dropping\n",
-                                       __func__);
+                       lwsl_wsi_err(wsi, "proxied ws connection "
+                                         "excessive buffering: dropping");
                        return -1;
                }
                pkt = lws_zalloc(sizeof(*pkt) + LWS_PRE + len, __func__);
                if (!pkt)
                        return -1;
 
-               pkt->pkt_list.prev = pkt->pkt_list.next = NULL;
                pkt->len = len;
-               pkt->first = lws_is_first_fragment(wsi);
-               pkt->final = lws_is_final_fragment(wsi);
-               pkt->binary = lws_frame_is_binary(wsi);
+               pkt->first = (char)lws_is_first_fragment(wsi);
+               pkt->final = (char)lws_is_final_fragment(wsi);
+               pkt->binary = (char)lws_frame_is_binary(wsi);
 
                memcpy(((uint8_t *)&pkt[1]) + LWS_PRE, in, len);
 
@@ -169,23 +180,21 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason,
                break;
 
        case LWS_CALLBACK_CLIENT_WRITEABLE:
-               dll = lws_dll2_get_tail(&wsi->ws->proxy_owner);
+               dll = lws_dll2_get_head(&wsi->ws->proxy_owner);
                if (!dll)
                        break;
 
                pkt = (struct lws_proxy_pkt *)dll;
                if (lws_write(wsi, ((unsigned char *)&pkt[1]) +
-                             LWS_PRE, pkt->len, lws_write_ws_flags(
+                             LWS_PRE, pkt->len, (enum lws_write_protocol)lws_write_ws_flags(
                                pkt->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT,
                                        pkt->first, pkt->final)) < 0)
                        return -1;
 
-               wsi->parent->ws->proxy_buffered -= pkt->len;
-
                lws_dll2_remove(dll);
                lws_free(pkt);
 
-               if (lws_dll2_get_tail(&wsi->ws->proxy_owner))
+               if (lws_dll2_get_head(&wsi->ws->proxy_owner))
                        lws_callback_on_writable(wsi);
                break;
 
@@ -195,7 +204,7 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason,
                return 1;
 
        case LWS_CALLBACK_CLOSED:
-               lwsl_user("%s: closed\n", __func__);
+               lwsl_wsi_info(wsi, "closed");
                return -1;
 
        case LWS_CALLBACK_RECEIVE:
@@ -203,11 +212,10 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason,
                if (!pkt)
                        return -1;
 
-               pkt->pkt_list.prev = pkt->pkt_list.next = NULL;
                pkt->len = len;
-               pkt->first = lws_is_first_fragment(wsi);
-               pkt->final = lws_is_final_fragment(wsi);
-               pkt->binary = lws_frame_is_binary(wsi);
+               pkt->first = (char)lws_is_first_fragment(wsi);
+               pkt->final = (char)lws_is_final_fragment(wsi);
+               pkt->binary = (char)lws_frame_is_binary(wsi);
 
                memcpy(((uint8_t *)&pkt[1]) + LWS_PRE, in, len);
 
@@ -216,21 +224,23 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason,
                break;
 
        case LWS_CALLBACK_SERVER_WRITEABLE:
-               dll = lws_dll2_get_tail(&wsi->ws->proxy_owner);
+               dll = lws_dll2_get_head(&wsi->ws->proxy_owner);
                if (!dll)
                        break;
 
                pkt = (struct lws_proxy_pkt *)dll;
                if (lws_write(wsi, ((unsigned char *)&pkt[1]) +
-                             LWS_PRE, pkt->len, lws_write_ws_flags(
+                             LWS_PRE, pkt->len, (enum lws_write_protocol)lws_write_ws_flags(
                                pkt->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT,
                                        pkt->first, pkt->final)) < 0)
                        return -1;
 
+               wsi->ws->proxy_buffered -= pkt->len;
+
                lws_dll2_remove(dll);
                lws_free(pkt);
 
-               if (lws_dll2_get_tail(&wsi->ws->proxy_owner))
+               if (lws_dll2_get_head(&wsi->ws->proxy_owner))
                        lws_callback_on_writable(wsi);
                break;
 
@@ -251,7 +261,8 @@ const struct lws_protocols lws_ws_proxy = {
 
 #endif
 
-LWS_VISIBLE int
+
+int
 lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                        void *user, void *in, size_t len)
 {
@@ -260,7 +271,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
        struct lws_cgi_args *args;
 #endif
 #if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
-       char buf[8192];
+       char buf[LWS_PRE + 32 + 8192];
        int n;
 #endif
 #if defined(LWS_WITH_HTTP_PROXY)
@@ -271,7 +282,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
        switch (reason) {
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
        case LWS_CALLBACK_HTTP:
-#ifndef LWS_NO_SERVER
+#if defined(LWS_WITH_SERVER)
                if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
                        return -1;
 
@@ -279,14 +290,20 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
 #endif
                        return -1;
                break;
-#if !defined(LWS_NO_SERVER)
+#if defined(LWS_WITH_SERVER)
        case LWS_CALLBACK_HTTP_BODY_COMPLETION:
 #if defined(LWS_WITH_HTTP_PROXY)
                if (wsi->child_list) {
-                       lwsl_user("%s: LWS_CALLBACK_HTTP_BODY_COMPLETION: %d\n", __func__, (int)len);
+                       lwsl_wsi_info(wsi, "HTTP_BODY_COMPLETION: %d",
+                                          (int)len);
+                       lws_callback_on_writable(wsi->child_list);
                        break;
                }
 #endif
+               if (lws_return_http_status(wsi, 200, NULL))
+                       return -1;
+               break;
+
                /* fallthru */
        case LWS_CALLBACK_HTTP_FILE_COMPLETION:
                if (lws_http_transaction_completed(wsi))
@@ -297,9 +314,11 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
 #if defined(LWS_WITH_HTTP_PROXY)
        case LWS_CALLBACK_HTTP_BODY:
                if (wsi->child_list) {
-                       lwsl_user("%s: LWS_CALLBACK_HTTP_BODY: stashing %d\n", __func__, (int)len);
-                       if (lws_buflist_append_segment(&wsi->http.buflist_post_body, in, len) < 0)
+                       lwsl_wsi_info(wsi, "HTTP_BODY: stashing %d", (int)len);
+                       if (lws_buflist_append_segment(
+                                    &wsi->http.buflist_post_body, in, len) < 0)
                                return -1;
+                       lws_client_http_body_pending(wsi->child_list, 1);
                        lws_callback_on_writable(wsi->child_list);
                }
                break;
@@ -312,32 +331,37 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                                      LWS_CB_REASON_AUX_BF__CGI)) {
                        n = lws_cgi_write_split_stdout_headers(wsi);
                        if (n < 0) {
-                               lwsl_debug("AUX_BF__CGI forcing close\n");
+                               lwsl_wsi_debug(wsi, "AUX_BF__CGI forcing close");
                                return -1;
                        }
-                       if (!n && wsi->http.cgi && wsi->http.cgi->stdwsi[LWS_STDOUT])
+                       if (!n && wsi->http.cgi && wsi->http.cgi->lsp &&
+                           wsi->http.cgi->lsp->stdwsi[LWS_STDOUT])
                                lws_rx_flow_control(
-                                       wsi->http.cgi->stdwsi[LWS_STDOUT], 1);
+                                       wsi->http.cgi->lsp->stdwsi[LWS_STDOUT], 1);
 
                        if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
                                wsi->reason_bf &=
-                                       ~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
+                                       (char)~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
                        else
-                               wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI;
+                               wsi->reason_bf &= (char)~LWS_CB_REASON_AUX_BF__CGI;
 
-                       if (wsi->http.cgi && wsi->http.cgi->cgi_transaction_over)
+                       if (wsi->http.cgi && wsi->http.cgi->cgi_transaction_over) {
+                               lwsl_wsi_info(wsi, "txn over");
                                return -1;
+                       }
+
                        break;
                }
 
-               if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {
-                       if (!wsi->http2_substream) {
+               if ((wsi->http.cgi && wsi->http.cgi->cgi_transaction_over) ||
+                   (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END)) {
+                       if (!wsi->mux_substream) {
                                memcpy(buf + LWS_PRE, "0\x0d\x0a\x0d\x0a", 5);
-                               lwsl_debug("writing chunk term and exiting\n");
-                               n = lws_write(wsi, (unsigned char *)buf +
+                               lwsl_wsi_debug(wsi, "wr chunk term and exiting");
+                               lws_write(wsi, (unsigned char *)buf +
                                                   LWS_PRE, 5, LWS_WRITE_HTTP);
                        } else
-                               n = lws_write(wsi, (unsigned char *)buf +
+                               lws_write(wsi, (unsigned char *)buf +
                                                   LWS_PRE, 0,
                                                   LWS_WRITE_HTTP_FINAL);
 
@@ -351,23 +375,25 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
 
                if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_HEADERS) {
 
-                       wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
+                       wsi->reason_bf &=
+                                    (char)~LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
 
                        n = LWS_WRITE_HTTP_HEADERS;
                        if (!wsi->http.prh_content_length)
                                n |= LWS_WRITE_H2_STREAM_END;
 
-                       lwsl_debug("%s: %p: issuing proxy headers: clen %d\n",
-                                   __func__, wsi, (int)wsi->http.prh_content_length);
+                       lwsl_wsi_debug(wsi, "issuing proxy headers: clen %d",
+                                   (int)wsi->http.prh_content_length);
                        n = lws_write(wsi, wsi->http.pending_return_headers +
                                           LWS_PRE,
-                                     wsi->http.pending_return_headers_len, n);
+                                     wsi->http.pending_return_headers_len,
+                                     (enum lws_write_protocol)n);
 
                        lws_free_set_NULL(wsi->http.pending_return_headers);
 
                        if (n < 0) {
-                               lwsl_err("%s: EST_CLIENT_HTTP: write failed\n",
-                                        __func__);
+                               lwsl_wsi_err(wsi, "EST_CLIENT_HTTP: wr failed");
+
                                return -1;
                        }
 
@@ -385,15 +411,15 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                         * suitable size to send or what's available, whichever
                         * is the smaller.
                         */
-                       wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
+                       wsi->reason_bf &= (char)~LWS_CB_REASON_AUX_BF__PROXY;
                        if (!lws_get_child(wsi))
                                break;
 
                        /* this causes LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ */
                        if (lws_http_client_read(lws_get_child(wsi), &px,
                                                 &lenx) < 0) {
-                               lwsl_info("%s: LWS_CB_REASON_AUX_BF__PROXY: "
-                                          "client closed\n", __func__);
+                               lwsl_wsi_info(wsi, "LWS_CB_REASON_AUX_BF__PROXY: "
+                                          "client closed");
 
                                stream_close(wsi);
 
@@ -403,10 +429,9 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                }
 
                if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_TRANS_END) {
-                       lwsl_info("%s: LWS_CB_REASON_AUX_BF__PROXY_TRANS_END\n",
-                                  __func__);
+                       lwsl_wsi_info(wsi, "PROXY_TRANS_END");
 
-                       wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
+                       wsi->reason_bf &= (char)~LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
 
                        if (stream_close(wsi))
                                return -1;
@@ -434,7 +459,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                if (wsi->http.proxy_parent_chunked) {
 
                        if (len > sizeof(buf) - LWS_PRE - 16) {
-                               lwsl_err("oversize buf %d %d\n", (int)len,
+                               lwsl_wsi_err(wsi, "oversize buf %d %d", (int)len,
                                                (int)sizeof(buf) - LWS_PRE - 16);
                                return -1;
                        }
@@ -452,7 +477,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
 
                        n = lws_write(lws_get_parent(wsi),
                                      (unsigned char *)buf + LWS_PRE,
-                                     len + n + 2, LWS_WRITE_HTTP);
+                                     (size_t)(unsigned int)(len + (unsigned int)n + 2), LWS_WRITE_HTTP);
                } else
                        n = lws_write(lws_get_parent(wsi), (unsigned char *)in,
                                      len, LWS_WRITE_HTTP);
@@ -482,7 +507,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                        return 0;
 
                start = p = (unsigned char *)buf + LWS_PRE;
-               end = p + sizeof(buf) - LWS_PRE - 256;
+               end = p + sizeof(buf) - LWS_PRE - MAXHDRVAL;
 
                if (lws_add_http_header_status(lws_get_parent(wsi),
                                lws_http_client_http_response(wsi), &p, end))
@@ -492,24 +517,24 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                 * copy these headers from the client connection to the parent
                 */
 
-               proxy_header(parent, wsi, end, 256,
+               proxy_header(parent, wsi, end, MAXHDRVAL,
                             WSI_TOKEN_HTTP_CONTENT_LENGTH, &p, end);
-               proxy_header(parent, wsi, end, 256,
+               proxy_header(parent, wsi, end, MAXHDRVAL,
                             WSI_TOKEN_HTTP_CONTENT_TYPE, &p, end);
-               proxy_header(parent, wsi, end, 256,
+               proxy_header(parent, wsi, end, MAXHDRVAL,
                             WSI_TOKEN_HTTP_ETAG, &p, end);
-               proxy_header(parent, wsi, end, 256,
+               proxy_header(parent, wsi, end, MAXHDRVAL,
                             WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, &p, end);
-               proxy_header(parent, wsi, end, 256,
+               proxy_header(parent, wsi, end, MAXHDRVAL,
                             WSI_TOKEN_HTTP_CONTENT_ENCODING, &p, end);
-               proxy_header(parent, wsi, end, 256,
+               proxy_header(parent, wsi, end, MAXHDRVAL,
                             WSI_TOKEN_HTTP_CACHE_CONTROL, &p, end);
-               proxy_header(parent, wsi, end, 256,
+               proxy_header(parent, wsi, end, MAXHDRVAL,
                             WSI_TOKEN_HTTP_SET_COOKIE, &p, end);
-               proxy_header(parent, wsi, end, 256,
+               proxy_header(parent, wsi, end, MAXHDRVAL,
                             WSI_TOKEN_HTTP_LOCATION, &p, end);
 
-               if (!parent->http2_substream)
+               if (!parent->mux_substream)
                        if (lws_add_http_header_by_token(parent,
                                WSI_TOKEN_CONNECTION, (unsigned char *)"close",
                                5, &p, end))
@@ -523,9 +548,9 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                 * our own chunking since we still don't know the size.
                 */
 
-               if (!parent->http2_substream &&
+               if (!parent->mux_substream &&
                    !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
-                       lwsl_debug("downstream parent chunked\n");
+                       lwsl_wsi_debug(wsi, "downstream parent chunked");
                        if (lws_add_http_header_by_token(parent,
                                        WSI_TOKEN_HTTP_TRANSFER_ENCODING,
                                        (unsigned char *)"chunked", 7, &p, end))
@@ -537,13 +562,13 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                if (lws_finalize_http_header(parent, &p, end))
                        return 1;
 
-               parent->http.prh_content_length = -1;
+               parent->http.prh_content_length = (size_t)-1;
                if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH))
-                       parent->http.prh_content_length = atoll(
+                       parent->http.prh_content_length = (size_t)atoll(
                                lws_hdr_simple_ptr(wsi,
                                                WSI_TOKEN_HTTP_CONTENT_LENGTH));
 
-               parent->http.pending_return_headers_len = lws_ptr_diff(p, start);
+               parent->http.pending_return_headers_len = lws_ptr_diff_size_t(p, start);
                parent->http.pending_return_headers =
                        lws_malloc(parent->http.pending_return_headers_len +
                                    LWS_PRE, "return proxy headers");
@@ -555,8 +580,8 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
 
                parent->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
 
-               lwsl_debug("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: "
-                          "prepared %d headers (len %d)\n", __func__,
+               lwsl_wsi_debug(wsi, "ESTABLISHED_CLIENT_HTTP: "
+                          "prepared %d headers (len %d)",
                           lws_http_client_http_response(wsi),
                           (int)parent->http.prh_content_length);
 
@@ -571,8 +596,8 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                break; }
 
        case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
-               lwsl_info("%s: COMPLETED_CLIENT_HTTP: %p (parent %p)\n",
-                                       __func__, wsi, lws_get_parent(wsi));
+               lwsl_wsi_info(wsi, "COMPLETED_CLIENT_HTTP: (parent %s)",
+                                  lws_wsi_tag(lws_get_parent(wsi)));
                if (!lws_get_parent(wsi))
                        break;
                lws_get_parent(wsi)->reason_bf |=
@@ -583,10 +608,10 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
        case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
                if (!lws_get_parent(wsi))
                        break;
-               lwsl_err("%s: LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", __func__);
-               lws_set_timeout(lws_get_parent(wsi),
-                               PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE,
-                               LWS_TO_KILL_ASYNC);
+       //      lwsl_err("%s: LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", __func__);
+               lws_set_timeout(lws_get_parent(wsi),
+                              (enum pending_timeout)LWS_TO_KILL_ASYNC,
+                               (int)PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE);
                break;
 
        case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
@@ -638,8 +663,9 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                        /* TBD stdin rx flow control */
                        break;
                case LWS_STDOUT:
-                       /* quench POLLIN on STDOUT until MASTER got writeable */
-                       lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
+                       if (args->stdwsi[LWS_STDOUT])
+                               /* quench POLLIN on STDOUT until MASTER got writeable */
+                               lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
                        wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
                        /* when writing to MASTER would not block */
                        lws_callback_on_writable(wsi);
@@ -648,32 +674,37 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                        n = lws_get_socket_fd(args->stdwsi[LWS_STDERR]);
                        if (n < 0)
                                break;
-                       n = read(n, buf, sizeof(buf) - 2);
+                       n = (int)read(n, buf, sizeof(buf) - 2);
                        if (n > 0) {
                                if (buf[n - 1] != '\n')
                                        buf[n++] = '\n';
                                buf[n] = '\0';
-                               lwsl_notice("CGI-stderr: %s\n", buf);
+                               lwsl_wsi_notice(wsi, "CGI-stderr: %s", buf);
                        }
                        break;
                }
                break;
 
        case LWS_CALLBACK_CGI_TERMINATED:
-               lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: %d %" PRIu64 "\n",
+               lwsl_wsi_debug(wsi, "CGI_TERMINATED: %d %" PRIu64,
                                wsi->http.cgi->explicitly_chunked,
                                (uint64_t)wsi->http.cgi->content_length);
-               if (!wsi->http.cgi->explicitly_chunked &&
+               if (!(wsi->http.cgi->explicitly_chunked && wsi->mux_substream) &&
                    !wsi->http.cgi->content_length) {
                        /* send terminating chunk */
-                       lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: ending\n");
+                       lwsl_wsi_debug(wsi, "LWS_CALLBACK_CGI_TERMINATED: ending");
                        wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
                        lws_callback_on_writable(wsi);
                        lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);
                        break;
                }
+               if (wsi->mux_substream && !wsi->cgi_stdout_zero_length)
+                       lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
+                                                     LWS_WRITE_HTTP_FINAL);
+#if defined(LWS_WITH_SERVER)
                if (lws_http_transaction_completed(wsi))
                        return -1;
+#endif
                return 0;
 
        case LWS_CALLBACK_CGI_STDIN_DATA:  /* POST body for stdin */
@@ -690,15 +721,14 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                        /* gzip handling */
 
                        if (!wsi->http.cgi->gzip_init) {
-                               lwsl_info("inflating gzip\n");
+                               lwsl_wsi_info(wsi, "inflating gzip");
 
                                memset(&wsi->http.cgi->inflate, 0,
                                       sizeof(wsi->http.cgi->inflate));
 
                                if (inflateInit2(&wsi->http.cgi->inflate,
                                                 16 + 15) != Z_OK) {
-                                       lwsl_err("%s: iniflateInit failed\n",
-                                                __func__);
+                                       lwsl_wsi_err(wsi, "iniflateInit fail");
                                        return -1;
                                }
 
@@ -706,7 +736,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                        }
 
                        wsi->http.cgi->inflate.next_in = args->data;
-                       wsi->http.cgi->inflate.avail_in = args->len;
+                       wsi->http.cgi->inflate.avail_in = (unsigned int)args->len;
 
                        do {
 
@@ -725,7 +755,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                                case Z_MEM_ERROR:
                                        inflateEnd(&wsi->http.cgi->inflate);
                                        wsi->http.cgi->gzip_init = 0;
-                                       lwsl_err("zlib error inflate %d\n", n);
+                                       lwsl_wsi_err(wsi, "zlib err inflate %d", n);
                                        return -1;
                                }
 
@@ -733,7 +763,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                                           sizeof(wsi->http.cgi->inflate_buf)) {
                                        int written;
 
-                                       written = write(args->stdwsi[LWS_STDIN]->desc.filefd,
+                                       written = (int)write(args->stdwsi[LWS_STDIN]->desc.filefd,
                                                wsi->http.cgi->inflate_buf,
                                                sizeof(wsi->http.cgi->inflate_buf) -
                                                wsi->http.cgi->inflate.avail_out);
@@ -741,12 +771,15 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                                        if (written != (int)(
                                                sizeof(wsi->http.cgi->inflate_buf) -
                                                wsi->http.cgi->inflate.avail_out)) {
-                                               lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
-                                                       "sent %d only %d went", n, args->len);
+                                               lwsl_wsi_notice(wsi,
+                                                       "CGI_STDIN_DATA: "
+                                                       "sent %d only %d went",
+                                                       n, args->len);
                                        }
 
                                        if (n == Z_STREAM_END) {
-                                               lwsl_err("gzip inflate end\n");
+                                               lwsl_wsi_err(wsi,
+                                                           "gzip inflate end");
                                                inflateEnd(&wsi->http.cgi->inflate);
                                                wsi->http.cgi->gzip_init = 0;
                                                break;
@@ -764,39 +797,43 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                }
 #endif /* WITH_ZLIB */
 
-               n = write(n, args->data, args->len);
+               n = (int)write(n, args->data, (unsigned int)args->len);
 //             lwsl_hexdump_notice(args->data, args->len);
                if (n < args->len)
-                       lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
+                       lwsl_wsi_notice(wsi, "CGI_STDIN_DATA: "
                                    "sent %d only %d went", n, args->len);
 
+               lwsl_wsi_info(wsi, "proxied %d bytes", n);
+
                if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] &&
                    args->stdwsi[LWS_STDIN]->desc.filefd > 0) {
-                       wsi->http.cgi->post_in_expected -= n;
+                       wsi->http.cgi->post_in_expected -= (unsigned int)n;
+
                        if (!wsi->http.cgi->post_in_expected) {
                                struct lws *siwsi = args->stdwsi[LWS_STDIN];
 
-                               lwsl_debug("%s: expected POST in end: "
-                                          "closing stdin wsi %p, fd %d\n",
-                                          __func__, siwsi, siwsi->desc.sockfd);
-
-                               __remove_wsi_socket_from_fds(siwsi);
-                               lwsi_set_state(siwsi, LRS_DEAD_SOCKET);
-                               siwsi->socket_is_permanently_unusable = 1;
-//                             lws_remove_child_from_any_parent(siwsi);
-                               if (wsi->context->event_loop_ops->
-                                                       close_handle_manually) {
-
-                                       wsi->context->event_loop_ops->
-                                               close_handle_manually(siwsi);
-                                       siwsi->told_event_loop_closed = 1;
-                               } else {
-                                       compatible_close(siwsi->desc.sockfd);
-                                       __lws_free_wsi(siwsi);
-                               }
-                               wsi->http.cgi->pipe_fds[LWS_STDIN][1] = -1;
-
-//                             args->stdwsi[LWS_STDIN] = NULL;
+                               /*
+                                * The situation here is that we finished
+                                * proxying the incoming body from the net to
+                                * the STDIN stdwsi... and we want to close it
+                                * so it can understand we are done (necessary
+                                * if no content-length)...
+                                */
+
+                               lwsl_wsi_info(siwsi, "expected POST in end: "
+                                                    "closing stdin fd %d",
+                                                    siwsi->desc.sockfd);
+
+                               /*
+                                * We don't want the child / parent relationship
+                                * to be handled in close, since we want the
+                                * rest of the cgi and children to stay up
+                                */
+
+                               lws_remove_child_from_any_parent(siwsi);
+                               lws_wsi_close(siwsi, LWS_TO_KILL_ASYNC);
+                               wsi->http.cgi->lsp->stdwsi[LWS_STDIN] = NULL;
+                               lws_spawn_stdwsi_closed(wsi->http.cgi->lsp, siwsi);
                        }
                }
 
@@ -807,13 +844,19 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
                si = in;
 
                (void)si;
-               lwsl_notice("LWS_CALLBACK_SSL_INFO: where: 0x%x, ret: 0x%x\n",
-                           si->where, si->ret);
+               lwsl_wsi_notice(wsi, "SSL_INFO: where: 0x%x, ret: 0x%x",
+                               si->where, si->ret);
                break;
 
 #if LWS_MAX_SMP > 1
        case LWS_CALLBACK_GET_THREAD_ID:
-               return (int)(unsigned long long)pthread_self();
+#ifdef __PTW32_H
+               /* If we use implementation of PThreads for Win that is
+                * distributed by VCPKG */
+               return (int)(lws_intptr_t)(pthread_self()).p;
+#else
+               return (int)(lws_intptr_t)pthread_self();
+#endif // __PTW32_H
 #endif
 
        default:
index e03a149..fc332ae 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 struct lws_dsh_search {
        size_t          required;
@@ -49,13 +52,15 @@ lws_dsh_align(size_t length)
 lws_dsh_t *
 lws_dsh_create(lws_dll2_owner_t *owner, size_t buf_len, int count_kinds)
 {
-       size_t oha_len = sizeof(lws_dsh_obj_head_t) * ++count_kinds;
+       size_t oha_len = sizeof(lws_dsh_obj_head_t) * (unsigned int)(++count_kinds);
        lws_dsh_obj_t *obj;
        lws_dsh_t *dsh;
        int n;
 
        assert(buf_len);
        assert(count_kinds > 1);
+       assert(buf_len > sizeof(lws_dsh_t) + oha_len);
+       buf_len += 64;
 
        dsh = lws_malloc(sizeof(lws_dsh_t) + buf_len + oha_len, __func__);
        if (!dsh)
@@ -72,8 +77,10 @@ lws_dsh_create(lws_dll2_owner_t *owner, size_t buf_len, int count_kinds)
        /* clear down the obj heads array */
 
        memset(dsh->oha, 0, oha_len);
-       for (n = 0; n < count_kinds; n++)
+       for (n = 0; n < count_kinds; n++) {
                dsh->oha[n].kind = n;
+               dsh->oha[n].total_size = 0;
+       }
 
        /* initially the whole buffer is on the free kind (0) list */
 
@@ -113,125 +120,16 @@ search_best_free(struct lws_dll2 *d, void *user)
        return 0;
 }
 
-static int
-try_foreign(struct lws_dll2 *d, void *user)
-{
-       struct lws_dsh_search *s = (struct lws_dsh_search *)user;
-       lws_dsh_t *dsh1 = lws_container_of(d, lws_dsh_t, list);
-
-       if (dsh1 == s->already_checked)
-               return 0;
-
-       if (dsh1->being_destroyed)
-               return 0;
-
-       if (dsh1->count_kinds < s->kind + 1)
-               return 0;
-
-       lwsl_debug("%s: actual try_foreign: dsh %p (free list size %d)\n",
-                       __func__, dsh1, dsh1->oha[0].owner.count);
-
-       s->this_dsh = dsh1;
-       if (lws_dll2_foreach_safe(&dsh1->oha[0].owner, s, search_best_free))
-               return 1;
-
-       return 0;
-}
-
-static int
-free_foreign(struct lws_dll2 *d, void *user)
-{
-       lws_dsh_obj_t *obj = lws_container_of(d, lws_dsh_obj_t, list);
-       lws_dsh_t *dsh = (lws_dsh_t *)user;
-       void *p = (void *)&obj[1];
-
-       if (obj->dsh != dsh)
-               lws_dsh_free(&p);
-
-       return 0;
-}
-
-static int
-evict2(struct lws_dll2 *d, void *user)
-{
-       lws_dsh_obj_t *obj = lws_container_of(d, lws_dsh_obj_t, list);
-       lws_dsh_t *dsh = (lws_dsh_t *)user;
-       void *p;
-
-       if (obj->dsh != dsh)
-               return 0;
-
-       /*
-        * If we are here, it means obj is a live object that is allocated on
-        * the dsh being destroyed, from a different dsh.  We need to migrate
-        * the object to a dsh that isn't being destroyed.
-        */
-
-       lwsl_debug("%s: migrating object size %zu\n", __func__, obj->size);
-
-       if (_lws_dsh_alloc_tail(dsh, 0, (void *)&obj[1], obj->size, NULL, 0, &obj->list)) {
-               lwsl_notice("%s: failed to migrate object\n", __func__);
-               /*
-                * only thing we can do is drop the logical object
-                */
-               p = (uint8_t *)&obj[1];
-               lws_dsh_free(&p);
-       }
-
-       return 0;
-}
-
-static int
-evict1(struct lws_dll2 *d, void *user)
-{
-       lws_dsh_t *dsh1 = lws_container_of(d, lws_dsh_t, list);
-       lws_dsh_t *dsh = (lws_dsh_t *)user;
-       int n;
-
-       if (dsh1->being_destroyed)
-               return 0;
-
-       /*
-        * For every dsh that's not being destroyed, send every object to
-        * evict2 for checking.
-        */
-
-       lwsl_debug("%s: checking dsh %p\n", __func__, dsh1);
-
-       for (n = 1; n < dsh1->count_kinds; n++) {
-               lws_dll2_describe(&dsh1->oha[n].owner, "check dsh1");
-               lws_dll2_foreach_safe(&dsh1->oha[n].owner, dsh, evict2);
-       }
-
-       return 0;
-}
-
 void
 lws_dsh_destroy(lws_dsh_t **pdsh)
 {
        lws_dsh_t *dsh = *pdsh;
-       int n;
 
        if (!dsh)
                return;
 
-       lwsl_debug("%s: destroying dsh %p\n", __func__, dsh);
-
        dsh->being_destroyed = 1;
 
-       /* we need to explicitly free any of our allocations in foreign dsh */
-
-       for (n = 1; n < dsh->count_kinds; n++)
-               lws_dll2_foreach_safe(&dsh->oha[n].owner, dsh, free_foreign);
-
-       /*
-        * We need to have anybody else with allocations in us evict them
-        * and make a copy in a buffer that isn't being destroyed
-        */
-
-       if (dsh->list.owner)
-               lws_dll2_foreach_safe(dsh->list.owner, dsh, evict1);
-
        lws_dll2_remove(&dsh->list);
 
        /* everything else is in one heap allocation */
@@ -239,6 +137,15 @@ lws_dsh_destroy(lws_dsh_t **pdsh)
        lws_free_set_NULL(*pdsh);
 }
 
+size_t
+lws_dsh_get_size(struct lws_dsh *dsh, int kind)
+{
+       kind++;
+       assert(kind < dsh->count_kinds);
+
+       return dsh->oha[kind].total_size;
+}
+
 static int
 _lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
                    const void *src2, size_t size2, lws_dll2_t *replace)
@@ -264,19 +171,9 @@ _lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
                lws_dll2_foreach_safe(&dsh->oha[0].owner, &s, search_best_free);
 
        if (!s.best) {
-               /*
-                * Let's see if any other buffer has room
-                */
-               s.already_checked = dsh;
-
-               if (dsh && dsh->list.owner)
-                       lws_dll2_foreach_safe(dsh->list.owner, &s, try_foreign);
+               lwsl_notice("%s: no buffer has space\n", __func__);
 
-               if (!s.best) {
-                       lwsl_notice("%s: no buffer has space\n", __func__);
-
-                       return 1;
-               }
+               return 1;
        }
 
        /* anything coming out of here must be aligned */
@@ -292,6 +189,7 @@ _lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
                 */
                lws_dll2_remove(&s.best->list);
                s.best->dsh = s.dsh;
+               s.best->kind = kind;
                s.best->size = size1 + size2;
                memcpy(&s.best[1], src1, size1);
                if (src2)
@@ -306,12 +204,15 @@ _lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
                        if (replace->next)
                                replace->next->prev = &s.best->list;
                } else
-                       if (dsh)
+                       if (dsh) {
+                               assert(!(((unsigned long)(intptr_t)(s.best)) & (sizeof(int *) - 1)));
                                lws_dll2_add_tail(&s.best->list, &dsh->oha[kind].owner);
+                       }
 
                assert(s.dsh->locally_free >= s.best->asize);
                s.dsh->locally_free -= s.best->asize;
                s.dsh->locally_in_use += s.best->asize;
+               dsh->oha[kind].total_size += s.best->asize;
                assert(s.dsh->locally_in_use <= s.dsh->buffer_size);
        } else {
                lws_dsh_obj_t *obj;
@@ -330,10 +231,11 @@ _lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
 
                /* latter part becomes new object */
 
-               obj = (lws_dsh_obj_t *)(((uint8_t *)s.best) + s.best->asize);
+               obj = (lws_dsh_obj_t *)(((uint8_t *)s.best) + lws_dsh_align(s.best->asize));
 
                lws_dll2_clear(&obj->list);
                obj->dsh = s.dsh;
+               obj->kind = kind;
                obj->size = size1 + size2;
                obj->asize = asize;
 
@@ -350,12 +252,15 @@ _lws_dsh_alloc_tail(lws_dsh_t *dsh, int kind, const void *src1, size_t size1,
                        if (replace->next)
                                replace->next->prev = &s.best->list;
                } else
-                       if (dsh)
+                       if (dsh) {
+                               assert(!(((unsigned long)(intptr_t)(obj)) & (sizeof(int *) - 1)));
                                lws_dll2_add_tail(&obj->list, &dsh->oha[kind].owner);
+                       }
 
                assert(s.dsh->locally_free >= asize);
                s.dsh->locally_free -= asize;
                s.dsh->locally_in_use += asize;
+               dsh->oha[kind].total_size += asize;
                assert(s.dsh->locally_in_use <= s.dsh->buffer_size);
        }
 
@@ -398,6 +303,7 @@ lws_dsh_free(void **pobj)
        assert(dsh->locally_in_use >= _o->asize);
        dsh->locally_free += _o->asize;
        dsh->locally_in_use -= _o->asize;
+       dsh->oha[_o->kind].total_size -= _o->asize; /* account for usage by kind */
        assert(dsh->locally_in_use <= dsh->buffer_size);
 
        /*
@@ -451,8 +357,12 @@ lws_dsh_free(void **pobj)
 int
 lws_dsh_get_head(lws_dsh_t *dsh, int kind, void **obj, size_t *size)
 {
-       lws_dsh_obj_t *_obj = (lws_dsh_obj_t *)
-                       lws_dll2_get_head(&dsh->oha[kind + 1].owner);
+       lws_dsh_obj_t *_obj;
+
+       if (!dsh)
+               return 1;
+
+       _obj = (lws_dsh_obj_t *)lws_dll2_get_head(&dsh->oha[kind + 1].owner);
 
        if (!_obj) {
                *obj = 0;
@@ -465,12 +375,12 @@ lws_dsh_get_head(lws_dsh_t *dsh, int kind, void **obj, size_t *size)
        *size = _obj->size;
 
        /* anything coming out of here must be aligned */
-       assert(!(((unsigned long)(*obj)) & (sizeof(int *) - 1)));
+       assert(!(((unsigned long)(intptr_t)(*obj)) & (sizeof(int *) - 1)));
 
        return 0;       /* we returned the head */
 }
 
-#if defined(_DEBUG)
+#if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
 
 static int
 describe_kind(struct lws_dll2 *d, void *user)
index 8c3fe1a..4ba98a1 100644 (file)
@@ -1,27 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
+#include <errno.h>
 
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
+#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
 static int
 interface_to_sa(struct lws_vhost *vh, const char *ifname,
                struct sockaddr_in *addr, size_t addrlen, int allow_ipv6)
@@ -53,8 +57,8 @@ lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
        if (LWS_IPV6_ENABLED(vh)) {
                if (!lws_plat_inet_ntop(AF_INET6,
                                        &((struct sockaddr_in6 *)ads)->sin6_addr,
-                                       rip, rip_len)) {
-                       lwsl_err("inet_ntop: %s", strerror(LWS_ERRNO));
+                                       rip, (socklen_t)rip_len)) {
+                       lwsl_vhost_err(vh, "inet_ntop: %s", strerror(LWS_ERRNO));
                        return -1;
                }
 
@@ -63,7 +67,13 @@ lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
                        memmove(rip, rip + 7, strlen(rip) - 6);
 
                getnameinfo((struct sockaddr *)ads, sizeof(struct sockaddr_in6),
-                           name, name_len, NULL, 0, 0);
+                           name,
+#if defined(__ANDROID__)
+                           (size_t)name_len,
+#else
+                           (socklen_t)name_len,
+#endif
+                           NULL, 0, 0);
 
                return 0;
        } else
@@ -74,10 +84,16 @@ lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
                memset(&ai, 0, sizeof ai);
                ai.ai_family = PF_UNSPEC;
                ai.ai_socktype = SOCK_STREAM;
-#if !defined(LWS_WITH_ESP32)
+#if !defined(LWS_PLAT_FREERTOS)
                if (getnameinfo((struct sockaddr *)ads,
                                sizeof(struct sockaddr_in),
-                               name, name_len, NULL, 0, 0))
+                               name,
+#if defined(__ANDROID__)
+                               (size_t)name_len,
+#else
+                               (socklen_t)name_len,
+#endif
+                               NULL, 0, 0))
                        return -1;
 #endif
 
@@ -102,51 +118,39 @@ lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
        if (addr4.sin_family == AF_UNSPEC)
                return -1;
 
-       if (lws_plat_inet_ntop(AF_INET, &addr4.sin_addr, rip, rip_len) == NULL)
+       if (lws_plat_inet_ntop(AF_INET, &addr4.sin_addr, rip,
+                              (socklen_t)rip_len) == NULL)
                return -1;
 
        return 0;
 }
 
-
-LWS_VISIBLE const char *
-lws_get_peer_simple(struct lws *wsi, char *name, int namelen)
+const char *
+lws_get_peer_simple_fd(lws_sockfd_type fd, char *name, size_t namelen)
 {
-       socklen_t len, olen;
-#ifdef LWS_WITH_IPV6
-       struct sockaddr_in6 sin6;
-#endif
-       struct sockaddr_in sin4;
-       int af = AF_INET;
-       void *p, *q;
-
-       wsi = lws_get_network_wsi(wsi);
+       lws_sockaddr46 sa46;
+       socklen_t len = sizeof(sa46);
 
-#ifdef LWS_WITH_IPV6
-       if (LWS_IPV6_ENABLED(wsi->vhost)) {
-               len = sizeof(sin6);
-               p = &sin6;
-               af = AF_INET6;
-               q = &sin6.sin6_addr;
-       } else
-#endif
-       {
-               len = sizeof(sin4);
-               p = &sin4;
-               q = &sin4.sin_addr;
+       if (getpeername(fd, (struct sockaddr *)&sa46, &len) < 0) {
+               lws_snprintf(name, namelen, "getpeername: %s",
+                               strerror(LWS_ERRNO));
+               return name;
        }
 
-       olen = len;
-       if (getpeername(wsi->desc.sockfd, p, &len) < 0 || len > olen) {
-               lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
-               return NULL;
-       }
+       lws_sa46_write_numeric_address(&sa46, name, namelen);
+
+       return name;
+}
 
-       return lws_plat_inet_ntop(af, q, name, namelen);
+const char *
+lws_get_peer_simple(struct lws *wsi, char *name, size_t namelen)
+{
+       wsi = lws_get_network_wsi(wsi);
+       return lws_get_peer_simple_fd(wsi->desc.sockfd, name, namelen);
 }
 #endif
 
-LWS_VISIBLE void
+void
 lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
                       int name_len, char *rip, int rip_len)
 {
@@ -156,17 +160,13 @@ lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
        struct sockaddr_in6 sin6;
 #endif
        struct sockaddr_in sin4;
-       struct lws_context *context = wsi->context;
-       int ret = -1;
        void *p;
 
        rip[0] = '\0';
        name[0] = '\0';
 
-       lws_latency_pre(context, wsi);
-
 #ifdef LWS_WITH_IPV6
-       if (LWS_IPV6_ENABLED(wsi->vhost)) {
+       if (LWS_IPV6_ENABLED(wsi->a.vhost)) {
                len = sizeof(sin6);
                p = &sin6;
        } else
@@ -177,14 +177,13 @@ lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
        }
 
        if (getpeername(fd, p, &len) < 0) {
-               lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
+               lwsl_wsi_warn(wsi, "getpeername: %s", strerror(LWS_ERRNO));
                goto bail;
        }
 
-       ret = lws_get_addresses(wsi->vhost, p, name, name_len, rip, rip_len);
+       lws_get_addresses(wsi->a.vhost, p, name, name_len, rip, rip_len);
 
 bail:
-       lws_latency(context, wsi, "lws_get_peer_addresses", ret, 1);
 #endif
        (void)wsi;
        (void)fd;
@@ -204,9 +203,10 @@ bail:
  * LWS_ITOSA_BUSY:       the port at the requested iface + port is already in use
  */
 
-LWS_EXTERN int
-lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
-               const char *iface, int ipv6_allowed)
+int
+lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
+               lws_sockfd_type sockfd, int port, const char *iface,
+               int af)
 {
 #ifdef LWS_WITH_UNIX_SOCK
        struct sockaddr_un serv_unix;
@@ -218,106 +218,121 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
 #ifndef LWS_PLAT_OPTEE
        socklen_t len = sizeof(struct sockaddr_storage);
 #endif
-       int n;
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
+       int n = 0;
+#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
        int m;
 #endif
-       struct sockaddr_storage sin;
+       struct sockaddr_storage sin, *psin = &sin;
        struct sockaddr *v;
 
        memset(&sin, 0, sizeof(sin));
 
+       /* if there's a wsi, we want to mark it with our source ads:port */
+       if (wsi)
+               psin = (struct sockaddr_storage *)&wsi->sa46_local;
+
+       switch (af) {
 #if defined(LWS_WITH_UNIX_SOCK)
-       if (LWS_UNIX_SOCK_ENABLED(vhost)) {
+       case AF_UNIX:
                v = (struct sockaddr *)&serv_unix;
-               n = sizeof(struct sockaddr_un);
                memset(&serv_unix, 0, sizeof(serv_unix));
                serv_unix.sun_family = AF_UNIX;
                if (!iface)
                        return LWS_ITOSA_NOT_EXIST;
                if (sizeof(serv_unix.sun_path) <= strlen(iface)) {
-                       lwsl_err("\"%s\" too long for UNIX domain socket\n",
+                       lwsl_wsi_err(wsi, "\"%s\" too long for UNIX domain socket",
                                 iface);
                        return LWS_ITOSA_NOT_EXIST;
                }
+               n = (int)(sizeof(uint16_t) + strlen(iface));
                strcpy(serv_unix.sun_path, iface);
                if (serv_unix.sun_path[0] == '@')
                        serv_unix.sun_path[0] = '\0';
                else
                        unlink(serv_unix.sun_path);
 
-       } else
+               // lwsl_hexdump_notice(v, n);
+               break;
 #endif
-#if defined(LWS_WITH_IPV6) && !defined(LWS_WITH_ESP32)
-       if (ipv6_allowed && LWS_IPV6_ENABLED(vhost)) {
+#if defined(LWS_WITH_IPV6) && !defined(LWS_PLAT_FREERTOS)
+       case AF_INET6:
                v = (struct sockaddr *)&serv_addr6;
                n = sizeof(struct sockaddr_in6);
+
                memset(&serv_addr6, 0, sizeof(serv_addr6));
+               serv_addr6.sin6_family = AF_INET6;
                if (iface) {
                        m = interface_to_sa(vhost, iface,
-                                   (struct sockaddr_in *)v, n, 1);
+                                   (struct sockaddr_in *)v, (unsigned int)n, 1);
                        if (m == LWS_ITOSA_NOT_USABLE) {
-                               lwsl_info("%s: netif %s: Not usable\n",
-                                        __func__, iface);
+                               lwsl_wsi_info(wsi, "netif %s: Not usable",
+                                                  iface);
                                return m;
                        }
                        if (m == LWS_ITOSA_NOT_EXIST) {
-                               lwsl_info("%s: netif %s: Does not exist\n",
-                                        __func__, iface);
+                               lwsl_wsi_info(wsi, "netif %s: Does not exist",
+                                                  iface);
                                return m;
                        }
-                       serv_addr6.sin6_scope_id = lws_get_addr_scope(iface);
+                       serv_addr6.sin6_scope_id = (unsigned int)htonl((uint32_t)
+                                       lws_get_addr_scope(wsi, iface));
                }
 
-               serv_addr6.sin6_family = AF_INET6;
-               serv_addr6.sin6_port = htons(port);
-       } else
+               serv_addr6.sin6_port = (uint16_t)htons((uint16_t)port);
+               break;
 #endif
-       {
+
+       case AF_INET:
                v = (struct sockaddr *)&serv_addr4;
                n = sizeof(serv_addr4);
                memset(&serv_addr4, 0, sizeof(serv_addr4));
                serv_addr4.sin_addr.s_addr = INADDR_ANY;
                serv_addr4.sin_family = AF_INET;
 
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
+#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
                if (iface) {
                    m = interface_to_sa(vhost, iface,
-                                   (struct sockaddr_in *)v, n, 0);
+                                   (struct sockaddr_in *)v, (unsigned int)n, 0);
                        if (m == LWS_ITOSA_NOT_USABLE) {
-                               lwsl_info("%s: netif %s: Not usable\n",
-                                        __func__, iface);
+                               lwsl_wsi_info(wsi, "netif %s: Not usable",
+                                                  iface);
                                return m;
                        }
                        if (m == LWS_ITOSA_NOT_EXIST) {
-                               lwsl_info("%s: netif %s: Does not exist\n",
-                                        __func__, iface);
+                               lwsl_wsi_info(wsi, "netif %s: Does not exist",
+                                                  iface);
                                return m;
                        }
                }
 #endif
-               serv_addr4.sin_port = htons(port);
-       } /* ipv4 */
+               serv_addr4.sin_port = htons((uint16_t)(unsigned int)port);
+               break;
+       default:
+               return -1;
+       } /* switch */
 
        /* just checking for the interface extant */
        if (sockfd == LWS_SOCK_INVALID)
                return LWS_ITOSA_USABLE;
 
-       n = bind(sockfd, v, n);
+       n = bind(sockfd, v, (socklen_t)n);
 #ifdef LWS_WITH_UNIX_SOCK
-       if (n < 0 && LWS_UNIX_SOCK_ENABLED(vhost)) {
-               lwsl_err("ERROR on binding fd %d to \"%s\" (%d %d)\n",
-                        sockfd, iface, n, LWS_ERRNO);
+       if (n < 0 && af == AF_UNIX) {
+               lwsl_wsi_err(wsi, "ERROR on binding fd %d to \"%s\" (%d %d)",
+                                 sockfd, iface, n, LWS_ERRNO);
+
                return LWS_ITOSA_NOT_EXIST;
        } else
 #endif
        if (n < 0) {
-               lwsl_err("ERROR on binding fd %d to port %d (%d %d)\n",
-                        sockfd, port, n, LWS_ERRNO);
+               int _lws_errno = LWS_ERRNO;
+
+               lwsl_wsi_err(wsi, "ERROR on binding fd %d to port %d (%d %d)",
+                                 sockfd, port, n, _lws_errno);
 
                /* if something already listening, tell caller to fail permanently */
 
-               if (LWS_ERRNO == LWS_EADDRINUSE)
+               if (_lws_errno == LWS_EADDRINUSE)
                        return LWS_ITOSA_BUSY;
 
                /* otherwise ask caller to retry later */
@@ -325,34 +340,34 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
                return LWS_ITOSA_NOT_EXIST;
        }
 
-#if defined(LWS_WITH_UNIX_SOCK)
-       if (LWS_UNIX_SOCK_ENABLED(vhost)) {
+#if defined(LWS_WITH_UNIX_SOCK) && !defined(WIN32)
+       if (af == AF_UNIX) {
                uid_t uid = vhost->context->uid;
                gid_t gid = vhost->context->gid;
 
                if (vhost->unix_socket_perms) {
                        if (lws_plat_user_colon_group_to_ids(
                                vhost->unix_socket_perms, &uid, &gid)) {
-                               lwsl_err("%s: Failed to translate %s\n",
-                                         __func__, vhost->unix_socket_perms);
+                               lwsl_wsi_err(wsi, "Failed to translate %s",
+                                                  vhost->unix_socket_perms);
                                return LWS_ITOSA_NOT_EXIST;
                        }
                }
-               if (uid && gid) {
-                       if (chown(serv_unix.sun_path, uid, gid)) {
-                               lwsl_err("%s: failed to set %s perms %u:%u\n",
-                                        __func__, serv_unix.sun_path,
-                                        (unsigned int)uid, (unsigned int)gid);
+               if (iface && iface[0] != '@' && uid && gid) {
+                       if (chown(iface, uid, gid)) {
+                               lwsl_wsi_err(wsi, "failed to set %s perms %u:%u",
+                                                 iface, (unsigned int)uid,
+                                                 (unsigned int)gid);
 
                                return LWS_ITOSA_NOT_EXIST;
                        }
-                       lwsl_notice("%s: vh %s unix skt %s perms %u:%u\n",
-                                   __func__, vhost->name, serv_unix.sun_path,
-                                   (unsigned int)uid, (unsigned int)gid);
+                       lwsl_wsi_notice(wsi, "vh %s unix skt %s perms %u:%u",
+                                             vhost->name, iface,
+                                             (unsigned int)uid,
+                                             (unsigned int)gid);
 
-                       if (chmod(serv_unix.sun_path, 0660)) {
-                               lwsl_err("%s: failed to set %s to 0600 mode\n",
-                                        __func__, serv_unix.sun_path);
+                       if (chmod(iface, 0660)) {
+                               lwsl_wsi_err(wsi, "0600 mode on %s fail", iface);
 
                                return LWS_ITOSA_NOT_EXIST;
                        }
@@ -361,49 +376,64 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
 #endif
 
 #ifndef LWS_PLAT_OPTEE
-       if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1)
-               lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
+       if (getsockname(sockfd, (struct sockaddr *)psin, &len) == -1)
+               lwsl_wsi_warn(wsi, "getsockname: %s", strerror(LWS_ERRNO));
        else
 #endif
 #if defined(LWS_WITH_IPV6)
                port = (sin.ss_family == AF_INET6) ?
-                       ntohs(((struct sockaddr_in6 *) &sin)->sin6_port) :
-                       ntohs(((struct sockaddr_in *) &sin)->sin_port);
+                       ntohs(((struct sockaddr_in6 *)psin)->sin6_port) :
+                       ntohs(((struct sockaddr_in *)psin)->sin_port);
 #else
                {
                        struct sockaddr_in sain;
-                       memcpy(&sain, &sin, sizeof(sain));
+                       memcpy(&sain, psin, sizeof(sain));
                        port = ntohs(sain.sin_port);
                }
 #endif
 
+               {
+                       char buf[72];
+                       lws_sa46_write_numeric_address((lws_sockaddr46 *)psin,
+                                                       buf, sizeof(buf));
+
+                       lwsl_vhost_notice(vhost, "source ads %s", buf);
+               }
+
        return port;
 }
 
-static const lws_retry_range_t default_bo = { 3000, 7000 };
+#if defined(LWS_WITH_CLIENT)
 
 unsigned int
 lws_retry_get_delay_ms(struct lws_context *context,
-                      const lws_retry_bo_t *retry, uint16_t *ctry, char *conceal)
+                      const lws_retry_bo_t *retry, uint16_t *ctry,
+                      char *conceal)
 {
-       const lws_retry_range_t *r = &default_bo;
-       unsigned int ms;
+       uint64_t ms = 3000, pc = 30; /* sane-ish defaults if no retry table */
        uint16_t ra;
 
        if (conceal)
                *conceal = 0;
 
        if (retry) {
-               if (*ctry < retry->retry_ms_table_count)
-                       r = &retry->retry_ms_table[*ctry];
-               else
-                       r = &retry->retry_ms_table[
-                               retry->retry_ms_table_count - 1];
+               if (retry->retry_ms_table_count) {
+                       if (*ctry < retry->retry_ms_table_count)
+                               ms = retry->retry_ms_table[*ctry];
+                       else
+                               ms = retry->retry_ms_table[
+                                       retry->retry_ms_table_count - 1];
+               }
+
+               /* if no percent given, use the default 30% */
+               if (retry->jitter_percent)
+                       pc = retry->jitter_percent;
        }
 
-       ms = r->min_ms;
        if (lws_get_random(context, &ra, sizeof(ra)) == sizeof(ra))
-               ms += ((r->max_ms - ms) * ra) / 65535;
+               ms += ((ms * pc * ra) >> 16) / 100;
+       else
+               assert(0);
 
        if (*ctry < 0xffff)
                (*ctry)++;
@@ -411,19 +441,100 @@ lws_retry_get_delay_ms(struct lws_context *context,
        if (retry && conceal)
                *conceal = (int)*ctry <= retry->conceal_count;
 
-       return ms;
+       return (unsigned int)ms;
 }
 
-#if defined(LWS_WITH_IPV6)
-LWS_EXTERN unsigned long
-lws_get_addr_scope(const char *ipaddr)
+int
+lws_retry_sul_schedule(struct lws_context *context, int tid,
+                      lws_sorted_usec_list_t *sul,
+                      const lws_retry_bo_t *retry, sul_cb_t cb, uint16_t *ctry)
 {
-       unsigned long scope = 0;
+       char conceal;
+       uint64_t ms = lws_retry_get_delay_ms(context, retry, ctry, &conceal);
 
-#ifndef WIN32
-       struct ifaddrs *addrs, *addr;
+       if (!conceal)
+               return 1;
+
+       lwsl_cx_info(context, "sul %p: scheduling retry in %dms", sul, (int)ms);
+
+       lws_sul_schedule(context, tid, sul, cb, (int64_t)(ms * 1000));
+
+       return 0;
+}
+
+int
+lws_retry_sul_schedule_retry_wsi(struct lws *wsi, lws_sorted_usec_list_t *sul,
+                                sul_cb_t cb, uint16_t *ctry)
+{
+       char conceal;
+       lws_usec_t us = lws_retry_get_delay_ms(wsi->a.context,
+                                              wsi->retry_policy, ctry,
+                                              &conceal) * LWS_US_PER_MS;
+
+       if (!conceal)
+               /* if our reties are up, they're up... */
+               return 1;
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       if (
+#if defined(LWS_ROLE_H1)
+               wsi->role_ops == &role_ops_h1
+#endif
+#if defined(LWS_ROLE_H1) && defined(LWS_ROLE_H2)
+               ||
+#endif
+#if defined(LWS_ROLE_H2)
+               wsi->role_ops == &role_ops_h2
+#endif
+               )
+               /*
+                * Since we're doing it by wsi, we're in a position to check for
+                * http retry-after, it will increase us accordingly if found
+                */
+               lws_http_check_retry_after(wsi, &us);
+#endif
+       lws_sul_schedule(wsi->a.context, wsi->tsi, sul, cb, us);
+
+       return 0;
+}
+
+#endif
+
+#if defined(LWS_WITH_IPV6)
+unsigned long
+lws_get_addr_scope(struct lws *wsi, const char *ifname_or_ipaddr)
+{
+       unsigned long scope;
        char ip[NI_MAXHOST];
        unsigned int i;
+#if !defined(WIN32)
+       struct ifaddrs *addrs, *addr;
+#else
+       PIP_ADAPTER_ADDRESSES adapter, addrs = NULL;
+       PIP_ADAPTER_UNICAST_ADDRESS addr;
+       struct sockaddr_in6 *sockaddr;
+       ULONG size = 0;
+       int found = 0;
+       DWORD ret;
+#endif
+
+       /*
+        * First see if we can look the string up as a network interface name...
+        * windows vista+ also has this
+        */
+
+       scope = if_nametoindex(ifname_or_ipaddr);
+       if (scope > 0)
+               /* we found it from the interface name lookup */
+               return scope;
+
+       /*
+        * if not, try to look it up as an IP -> interface -> interface index
+        */
+
+       scope = 0;
+
+#if !defined(WIN32)
 
        getifaddrs(&addrs);
        for (addr = addrs; addr; addr = addr->ifa_next) {
@@ -431,10 +542,9 @@ lws_get_addr_scope(const char *ipaddr)
                        addr->ifa_addr->sa_family != AF_INET6)
                        continue;
 
-               getnameinfo(addr->ifa_addr,
-                               sizeof(struct sockaddr_in6),
-                               ip, sizeof(ip),
-                               NULL, 0, NI_NUMERICHOST);
+               ip[0] = '\0';
+               getnameinfo(addr->ifa_addr, sizeof(struct sockaddr_in6),
+                           ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
 
                i = 0;
                while (ip[i])
@@ -443,43 +553,30 @@ lws_get_addr_scope(const char *ipaddr)
                                break;
                        }
 
-               if (!strcmp(ip, ipaddr)) {
+               if (!strcmp(ip, ifname_or_ipaddr)) {
                        scope = if_nametoindex(addr->ifa_name);
                        break;
                }
        }
        freeifaddrs(addrs);
 #else
-       PIP_ADAPTER_ADDRESSES adapter, addrs = NULL;
-       PIP_ADAPTER_UNICAST_ADDRESS addr;
-       ULONG size = 0;
-       DWORD ret;
-       struct sockaddr_in6 *sockaddr;
-       char ip[NI_MAXHOST];
-       unsigned int i;
-       int found = 0;
 
-       for (i = 0; i < 5; i++)
-       {
+       for (i = 0; i < 5; i++) {
                ret = GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX,
                                           NULL, addrs, &size);
-               if ((ret == NO_ERROR) || (ret == ERROR_NO_DATA)) {
+               if (ret == NO_ERROR || ret == ERROR_NO_DATA)
                        break;
-               } else if (ret == ERROR_BUFFER_OVERFLOW)
-               {
-                       if (addrs)
-                               free(addrs);
-                       addrs = (IP_ADAPTER_ADDRESSES *)malloc(size);
-               } else
-               {
-                       if (addrs)
-                       {
-                               free(addrs);
-                               addrs = NULL;
-                       }
-                       lwsl_err("Failed to get IPv6 address table (%d)", ret);
+
+               if (addrs)
+                       free(addrs);
+
+               if (ret != ERROR_BUFFER_OVERFLOW) {
+                       addrs = NULL;
+                       lwsl_wsi_err(wsi, "Get IPv6 ads table fail (%d)", ret);
                        break;
                }
+
+               addrs = (IP_ADAPTER_ADDRESSES *)malloc(size);
        }
 
        if ((ret == NO_ERROR) && (addrs)) {
@@ -496,7 +593,7 @@ lws_get_addr_scope(const char *ipaddr)
                                                        &sockaddr->sin6_addr,
                                                        ip, sizeof(ip));
 
-                                       if (!strcmp(ip, ipaddr)) {
+                                       if (!strcmp(ip, ifname_or_ipaddr)) {
                                                scope = sockaddr->sin6_scope_id;
                                                found = 1;
                                                break;
@@ -515,5 +612,416 @@ lws_get_addr_scope(const char *ipaddr)
 }
 #endif
 
+/*
+ * https://en.wikipedia.org/wiki/IPv6_address
+ *
+ * An IPv6 address is represented as eight groups of four hexadecimal digits,
+ * each group representing 16 bits (two octets, a group sometimes also called a
+ * hextet[6][7]). The groups are separated by colons (:). An example of an IPv6
+ * address is:
+ *
+ *    2001:0db8:85a3:0000:0000:8a2e:0370:7334
+ *
+ * The hexadecimal digits are case-insensitive, but IETF recommendations suggest
+ * the use of lower case letters. The full representation of eight 4-digit
+ * groups may be simplified by several techniques, eliminating parts of the
+ * representation.
+ *
+ * Leading zeroes in a group may be omitted, but each group must retain at least
+ * one hexadecimal digit.[1] Thus, the example address may be written as:
+ *
+ *    2001:db8:85a3:0:0:8a2e:370:7334
+ *
+ * One or more consecutive groups containing zeros only may be replaced with a
+ * single empty group, using two consecutive colons (::).[1] The substitution
+ * may only be applied once in the address, however, because multiple
+ * occurrences would create an ambiguous representation. Thus, the example
+ * address can be further simplified:
+ *
+ *    2001:db8:85a3::8a2e:370:7334
+ *
+ * The localhost (loopback) address, 0:0:0:0:0:0:0:1, and the IPv6 unspecified
+ * address, 0:0:0:0:0:0:0:0, are reduced to ::1 and ::, respectively.
+ *
+ * During the transition of the Internet from IPv4 to IPv6, it is typical to
+ * operate in a mixed addressing environment. For such use cases, a special
+ * notation has been introduced, which expresses IPv4-mapped and IPv4-compatible
+ * IPv6 addresses by writing the least-significant 32 bits of an address in the
+ * familiar IPv4 dot-decimal notation, whereas the other 96 (most significant)
+ * bits are written in IPv6 format. For example, the IPv4-mapped IPv6 address
+ * ::ffff:c000:0280 is written as ::ffff:192.0.2.128, thus expressing clearly
+ * the original IPv4 address that was mapped to IPv6.
+ */
+
+int
+lws_parse_numeric_address(const char *ads, uint8_t *result, size_t max_len)
+{
+       struct lws_tokenize ts;
+       uint8_t *orig = result, temp[16];
+       int sects = 0, ipv6 = !!strchr(ads, ':'), skip_point = -1, dm = 0;
+       char t[5];
+       size_t n;
+       long u;
+
+       lws_tokenize_init(&ts, ads, LWS_TOKENIZE_F_NO_INTEGERS |
+                                   LWS_TOKENIZE_F_MINUS_NONTERM);
+       ts.len = strlen(ads);
+       if (!ipv6 && ts.len < 7)
+               return -1;
+
+       if (ipv6 && ts.len < 2)
+               return -2;
+
+       if (!ipv6 && max_len < 4)
+               return -3;
+
+       if (ipv6 && max_len < 16)
+               return -4;
+
+       if (ipv6)
+               memset(result, 0, max_len);
+
+       do {
+               ts.e = (int8_t)lws_tokenize(&ts);
+               switch (ts.e) {
+               case LWS_TOKZE_TOKEN:
+                       dm = 0;
+                       if (ipv6) {
+                               if (ts.token_len > 4)
+                                       return -1;
+                               memcpy(t, ts.token, ts.token_len);
+                               t[ts.token_len] = '\0';
+                               for (n = 0; n < ts.token_len; n++)
+                                       if (t[n] < '0' || t[n] > 'f' ||
+                                           (t[n] > '9' && t[n] < 'A') ||
+                                           (t[n] > 'F' && t[n] < 'a'))
+                                               return -1;
+                               u = strtol(t, NULL, 16);
+                               if (u > 0xffff)
+                                       return -5;
+                               *result++ = (uint8_t)(u >> 8);
+                       } else {
+                               if (ts.token_len > 3)
+                                       return -1;
+                               memcpy(t, ts.token, ts.token_len);
+                               t[ts.token_len] = '\0';
+                               for (n = 0; n < ts.token_len; n++)
+                                       if (t[n] < '0' || t[n] > '9')
+                                               return -1;
+                               u = strtol(t, NULL, 10);
+                               if (u > 0xff)
+                                       return -6;
+                       }
+                       if (u < 0)
+                               return -7;
+                       *result++ = (uint8_t)u;
+                       sects++;
+                       break;
+
+               case LWS_TOKZE_DELIMITER:
+                       if (dm++) {
+                               if (dm > 2)
+                                       return -8;
+                               if (*ts.token != ':')
+                                       return -9;
+                               /* back to back : */
+                               *result++ = 0;
+                               *result++ = 0;
+                               skip_point = lws_ptr_diff(result, orig);
+                               break;
+                       }
+                       if (ipv6 && orig[2] == 0xff && orig[3] == 0xff &&
+                           skip_point == 2) {
+                               /* ipv4 backwards compatible format */
+                               ipv6 = 0;
+                               memset(orig, 0, max_len);
+                               orig[10] = 0xff;
+                               orig[11] = 0xff;
+                               skip_point = -1;
+                               result = &orig[12];
+                               sects = 0;
+                               break;
+                       }
+                       if (ipv6 && *ts.token != ':')
+                               return -10;
+                       if (!ipv6 && *ts.token != '.')
+                               return -11;
+                       break;
+
+               case LWS_TOKZE_ENDED:
+                       if (!ipv6 && sects == 4)
+                               return lws_ptr_diff(result, orig);
+                       if (ipv6 && sects == 8)
+                               return lws_ptr_diff(result, orig);
+                       if (skip_point != -1) {
+                               int ow = lws_ptr_diff(result, orig);
+                               /*
+                                * contains ...::...
+                                */
+                               if (ow == 16)
+                                       return 16;
+                               memcpy(temp, &orig[skip_point], (unsigned int)(ow - skip_point));
+                               memset(&orig[skip_point], 0, (unsigned int)(16 - skip_point));
+                               memcpy(&orig[16 - (ow - skip_point)], temp,
+                                                  (unsigned int)(ow - skip_point));
+
+                               return 16;
+                       }
+                       return -12;
+
+               default: /* includes ENDED */
+                       lwsl_err("%s: malformed ip address\n",
+                                __func__);
+
+                       return -13;
+               }
+       } while (ts.e > 0 && result - orig <= (int)max_len);
+
+       lwsl_err("%s: ended on e %d\n", __func__, ts.e);
+
+       return -14;
+}
+
+int
+lws_sa46_parse_numeric_address(const char *ads, lws_sockaddr46 *sa46)
+{
+       uint8_t a[16];
+       int n;
+
+       n = lws_parse_numeric_address(ads, a, sizeof(a));
+       if (n < 0)
+               return -1;
+
+#if defined(LWS_WITH_IPV6)
+       if (n == 16) {
+               sa46->sa6.sin6_family = AF_INET6;
+               memcpy(sa46->sa6.sin6_addr.s6_addr, a,
+                      sizeof(sa46->sa6.sin6_addr.s6_addr));
+
+               return 0;
+       }
+#endif
+
+       if (n != 4)
+               return -1;
+
+       sa46->sa4.sin_family = AF_INET;
+       memcpy(&sa46->sa4.sin_addr.s_addr, a,
+              sizeof(sa46->sa4.sin_addr.s_addr));
+
+       return 0;
+}
+
+int
+lws_write_numeric_address(const uint8_t *ads, int size, char *buf, size_t len)
+{
+       char c, elided = 0, soe = 0, zb = (char)-1, n, ipv4 = 0;
+       const char *e = buf + len;
+       char *obuf = buf;
+       int q = 0;
+
+       if (size == 4)
+               return lws_snprintf(buf, len, "%u.%u.%u.%u",
+                                   ads[0], ads[1], ads[2], ads[3]);
+
+       if (size != 16)
+               return -1;
+
+       for (c = 0; c < (char)size / 2; c++) {
+               uint16_t v = (uint16_t)((ads[q] << 8) | ads[q + 1]);
+
+               if (buf + 8 > e)
+                       return -1;
+
+               q += 2;
+               if (soe) {
+                       if (v)
+                               *buf++ = ':';
+                               /* fall thru to print hex value */
+               } else
+                       if (!elided && !soe && !v) {
+                               elided = soe = 1;
+                               zb = c;
+                               continue;
+                       }
+
+               if (ipv4) {
+                       n = (char)lws_snprintf(buf, lws_ptr_diff_size_t(e, buf), "%u.%u",
+                                       ads[q - 2], ads[q - 1]);
+                       buf += n;
+                       if (c == 6)
+                               *buf++ = '.';
+               } else {
+                       if (soe && !v)
+                               continue;
+                       if (c)
+                               *buf++ = ':';
+
+                       buf += lws_snprintf(buf, lws_ptr_diff_size_t(e, buf), "%x", v);
+
+                       if (soe && v) {
+                               soe = 0;
+                               if (c == 5 && v == 0xffff && !zb) {
+                                       ipv4 = 1;
+                                       *buf++ = ':';
+                               }
+                       }
+               }
+       }
+       if (buf + 3 > e)
+               return -1;
+
+       if (soe) { /* as is the case for all zeros */
+               *buf++ = ':';
+               *buf++ = ':';
+               *buf = '\0';
+       }
+
+       return lws_ptr_diff(buf, obuf);
+}
+
+int
+lws_sa46_write_numeric_address(lws_sockaddr46 *sa46, char *buf, size_t len)
+{
+       *buf = '\0';
+#if defined(LWS_WITH_IPV6)
+       if (sa46->sa4.sin_family == AF_INET6)
+               return lws_write_numeric_address(
+                               (uint8_t *)&sa46->sa6.sin6_addr, 16, buf, len);
+#endif
+       if (sa46->sa4.sin_family == AF_INET)
+               return lws_write_numeric_address(
+                               (uint8_t *)&sa46->sa4.sin_addr, 4, buf, len);
+
+#if defined(LWS_WITH_UNIX_SOCK)
+       if (sa46->sa4.sin_family == AF_UNIX)
+               return lws_snprintf(buf, len, "(unix skt)");
+#endif
 
+       if (!sa46->sa4.sin_family)
+               return lws_snprintf(buf, len, "(unset)");
 
+       if (sa46->sa4.sin_family == AF_INET6)
+               return lws_snprintf(buf, len, "(ipv6 unsupp)");
+
+       lws_snprintf(buf, len, "(AF%d unsupp)", (int)sa46->sa4.sin_family);
+
+       return -1;
+}
+
+int
+lws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b)
+{
+       if (sa46a->sa4.sin_family != sa46b->sa4.sin_family)
+               return 1;
+
+#if defined(LWS_WITH_IPV6)
+       if (sa46a->sa4.sin_family == AF_INET6)
+               return memcmp(&sa46a->sa6.sin6_addr, &sa46b->sa6.sin6_addr, 16);
+#endif
+
+       if (sa46a->sa4.sin_family == AF_INET)
+               return sa46a->sa4.sin_addr.s_addr != sa46b->sa4.sin_addr.s_addr;
+
+       return 0;
+}
+
+void
+lws_4to6(uint8_t *v6addr, const uint8_t *v4addr)
+{
+       v6addr[12] = v4addr[0];
+       v6addr[13] = v4addr[1];
+       v6addr[14] = v4addr[2];
+       v6addr[15] = v4addr[3];
+
+       memset(v6addr, 0, 10);
+
+       v6addr[10] = v6addr[11] = 0xff;
+}
+
+#if defined(LWS_WITH_IPV6)
+void
+lws_sa46_4to6(lws_sockaddr46 *sa46, const uint8_t *v4addr, uint16_t port)
+{
+       sa46->sa4.sin_family = AF_INET6;
+
+       lws_4to6((uint8_t *)&sa46->sa6.sin6_addr.s6_addr[0], v4addr);
+
+       sa46->sa6.sin6_port = htons(port);
+}
+#endif
+
+int
+lws_sa46_on_net(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46_net,
+               int net_len)
+{
+       uint8_t mask = 0xff, norm[16];
+       const uint8_t *p1, *p2;
+
+       if (sa46a->sa4.sin_family == AF_INET) {
+               p1 = (uint8_t *)&sa46a->sa4.sin_addr;
+               if (sa46_net->sa4.sin_family == AF_INET6) {
+                       /* ip is v4, net is v6, promote ip to v6 */
+
+                       lws_4to6(norm, p1);
+                       p1 = norm;
+               }
+#if defined(LWS_WITH_IPV6)
+       } else
+               if (sa46a->sa4.sin_family == AF_INET6) {
+                       p1 = (uint8_t *)&sa46a->sa6.sin6_addr;
+#endif
+               } else
+                       return 1;
+
+       if (sa46_net->sa4.sin_family == AF_INET) {
+               p2 = (uint8_t *)&sa46_net->sa4.sin_addr;
+               if (sa46a->sa4.sin_family == AF_INET6) {
+                       /* ip is v6, net is v4, promote net to v6 */
+
+                       lws_4to6(norm, p2);
+                       p2 = norm;
+                       /* because the mask length is for net v4 address */
+                       net_len += 12 * 8;
+               }
+#if defined(LWS_WITH_IPV6)
+       } else
+               if (sa46a->sa4.sin_family == AF_INET6) {
+                       p2 = (uint8_t *)&sa46_net->sa6.sin6_addr;
+#endif
+               } else
+                       return 1;
+
+       while (net_len > 0) {
+               if (net_len < 8)
+                       mask = (uint8_t)(mask << (8 - net_len));
+
+               if (((*p1++) & mask) != ((*p2++) & mask))
+                       return 1;
+
+               net_len -= 8;
+       }
+
+       return 0;
+}
+
+void
+lws_sa46_copy_address(lws_sockaddr46 *sa46a, const void *in, int af)
+{
+       sa46a->sa4.sin_family = (sa_family_t)af;
+
+       if (af == AF_INET)
+               memcpy(&sa46a->sa4.sin_addr, in, 4);
+#if defined(LWS_WITH_IPV6)
+       else if (af == AF_INET6)
+               memcpy(&sa46a->sa6.sin6_addr, in, sizeof(sa46a->sa6.sin6_addr));
+#endif
+}
+
+#if defined(LWS_WITH_SYS_STATE)
+lws_state_manager_t *
+lws_system_get_state_manager(struct lws_context *context)
+{
+       return &context->mgr_system;
+}
+#endif
index 6f9ecc8..911688e 100644 (file)
@@ -1,54 +1,48 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /*
  * notice this returns number of bytes consumed, or -1
  */
-int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
+int
+lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
 {
        struct lws_context *context = lws_get_context(wsi);
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
        size_t real_len = len;
        unsigned int n, m;
 
-       // lwsl_notice("%s: len %d\n", __func__, (int)len);
-       // lwsl_hexdump_level(LLL_NOTICE, buf, len);
-
        /*
-        * Detect if we got called twice without going through the
-        * event loop to handle pending.  Since that guarantees extending any
-        * existing buflist_out it's inefficient.
+        * If you're looking to dump data being sent down the tls tunnel, see
+        * lws_ssl_capable_write() in lib/tls/mbedtls/mbedtls-ssl.c or
+        * lib/tls/openssl/openssl-ssl.c.
+        *
+        * There's also a corresponding lws_ssl_capable_read() in those files
+        * where you can enable a dump of decrypted data as soon as it was
+        * read.
         */
-       if (0 && buf && wsi->could_have_pending) {
-               lwsl_hexdump_level(LLL_INFO, buf, len);
-               lwsl_info("** %p: vh: %s, prot: %s, role %s: "
-                         "Inefficient back-to-back write of %lu detected...\n",
-                         wsi, wsi->vhost ? wsi->vhost->name : "no vhost",
-                         wsi->protocol->name, wsi->role_ops->name,
-                         (unsigned long)len);
-       }
-
-       lws_stats_bump(pt, LWSSTATS_C_API_WRITE, 1);
 
        /* just ignore sends after we cleared the truncation buffer */
        if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE &&
@@ -60,9 +54,8 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
                return (int)len;
 
        if (buf && lws_has_buffered_out(wsi)) {
-               lwsl_info("** %p: vh: %s, prot: %s, incr buflist_out by %lu\n",
-                         wsi, wsi->vhost ? wsi->vhost->name : "no vhost",
-                         wsi->protocol->name, (unsigned long)len);
+               lwsl_wsi_info(wsi, "** prot: %s, incr buflist_out by %lu",
+                                  wsi->a.protocol->name, (unsigned long)len);
 
                /*
                 * already buflist ahead of this, add it on the tail of the
@@ -83,38 +76,40 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
                len = lws_buflist_next_segment_len(&wsi->buflist_out, &buf);
                real_len = len;
 
-               lwsl_debug("%s: draining %d\n", __func__, (int)len);
+               lwsl_wsi_debug(wsi, "draining %d", (int)len);
        }
 
        if (!len || !buf)
                return 0;
 
-       if (!wsi->http2_substream && !lws_socket_is_valid(wsi->desc.sockfd))
-               lwsl_warn("** error invalid sock but expected to send\n");
+       if (!wsi->mux_substream && !lws_socket_is_valid(wsi->desc.sockfd))
+               lwsl_wsi_err(wsi, "invalid sock");
 
        /* limit sending */
-       if (wsi->protocol->tx_packet_size)
-               n = (int)wsi->protocol->tx_packet_size;
+       if (wsi->a.protocol->tx_packet_size)
+               n = (unsigned int)wsi->a.protocol->tx_packet_size;
        else {
-               n = (int)wsi->protocol->rx_buffer_size;
+               n = (unsigned int)wsi->a.protocol->rx_buffer_size;
                if (!n)
                        n = context->pt_serv_buf_size;
        }
        n += LWS_PRE + 4;
        if (n > len)
-               n = (int)len;
+               n = (unsigned int)len;
 
        /* nope, send it on the socket directly */
-       lws_latency_pre(context, wsi);
-       m = lws_ssl_capable_write(wsi, buf, n);
-       lws_latency(context, wsi, "send lws_issue_raw", n, n == m);
 
-       lwsl_info("%s: ssl_capable_write (%d) says %d\n", __func__, n, m);
+       if (lws_fi(&wsi->fic, "sendfail"))
+               m = (unsigned int)LWS_SSL_CAPABLE_ERROR;
+       else
+               m = (unsigned int)lws_ssl_capable_write(wsi, buf, n);
+
+       lwsl_wsi_info(wsi, "ssl_capable_write (%d) says %d", n, m);
 
        /* something got written, it can have been truncated now */
        wsi->could_have_pending = 1;
 
-       switch (m) {
+       switch ((int)m) {
        case LWS_SSL_CAPABLE_ERROR:
                /* we're going to close, let close know sends aren't possible */
                wsi->socket_is_permanently_unusable = 1;
@@ -139,18 +134,17 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
         */
        if (lws_has_buffered_out(wsi)) {
                if (m) {
-                       lwsl_info("%p partial adv %d (vs %ld)\n", wsi, m,
-                                       (long)real_len);
+                       lwsl_wsi_info(wsi, "partial adv %d (vs %ld)",
+                                          m, (long)real_len);
                        lws_buflist_use_segment(&wsi->buflist_out, m);
                }
 
                if (!lws_has_buffered_out(wsi)) {
-                       lwsl_info("%s: wsi %p: buflist_out flushed\n",
-                                 __func__, wsi);
+                       lwsl_wsi_info(wsi, "buflist_out flushed");
 
-                       m = (int)real_len;
+                       m = (unsigned int)real_len;
                        if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) {
-                               lwsl_info("*%p signalling to close now\n", wsi);
+                               lwsl_wsi_info(wsi, "*signalling to close now");
                                return -1; /* retry closing now */
                        }
 
@@ -160,11 +154,10 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
                        }
 
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-#if !defined(LWS_WITHOUT_SERVER)
+#if defined(LWS_WITH_SERVER)
                        if (wsi->http.deferred_transaction_completed) {
-                               lwsl_notice("%s: partial completed, doing "
-                                           "deferred transaction completed\n",
-                                           __func__);
+                               lwsl_wsi_notice(wsi, "partial completed, doing "
+                                           "deferred transaction completed");
                                wsi->http.deferred_transaction_completed = 0;
                                return lws_http_transaction_completed(wsi) ?
                                                        -1 : (int)real_len;
@@ -180,7 +173,7 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
                /* always callback on writeable */
                lws_callback_on_writable(wsi);
 
-               return m;
+               return (int)m;
        }
 
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
@@ -190,7 +183,7 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
 
        if (m == real_len)
                /* what we just sent went out cleanly */
-               return m;
+               return (int)m;
 
        /*
         * We were not able to send everything... and we were not sending from
@@ -198,22 +191,17 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
         * buffering the unsent remainder on it.
         * (it will get first priority next time the socket is writable).
         */
-       lwsl_debug("%p new partial sent %d from %lu total\n", wsi, m,
-                   (unsigned long)real_len);
+       lwsl_wsi_debug(wsi, "new partial sent %d from %lu total",
+                           m, (unsigned long)real_len);
 
        if (lws_buflist_append_segment(&wsi->buflist_out, buf + m,
                                       real_len - m) < 0)
                return -1;
 
-       lws_stats_bump(pt, LWSSTATS_C_WRITE_PARTIALS, 1);
-       lws_stats_bump(pt, LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, m);
-
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
-       if (lws_wsi_is_udp(wsi)) {
+#if defined(LWS_WITH_UDP)
+       if (lws_wsi_is_udp(wsi))
                /* stash original destination for fulfilling UDP partials */
-               wsi->udp->sa_pending = wsi->udp->sa;
-               wsi->udp->salen_pending = wsi->udp->salen;
-       }
+               wsi->udp->sa46_pending = wsi->udp->sa46;
 #endif
 
        /* since something buffered, force it to get another chance to send */
@@ -222,102 +210,150 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
        return (int)real_len;
 }
 
-LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
-                         enum lws_write_protocol wp)
+int
+lws_write(struct lws *wsi, unsigned char *buf, size_t len,
+         enum lws_write_protocol wp)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-
-       lws_stats_bump(pt, LWSSTATS_C_API_LWS_WRITE, 1);
+       int m;
 
        if ((int)len < 0) {
-               lwsl_err("%s: suspicious len int %d, ulong %lu\n", __func__,
-                               (int)len, (unsigned long)len);
+               lwsl_wsi_err(wsi, "suspicious len int %d, ulong %lu",
+                                 (int)len, (unsigned long)len);
                return -1;
        }
 
-       lws_stats_bump(pt, LWSSTATS_B_WRITE, len);
-
 #ifdef LWS_WITH_ACCESS_LOG
        wsi->http.access_log.sent += len;
 #endif
-       if (wsi->vhost)
-               wsi->vhost->conn_stats.tx += len;
 
        assert(wsi->role_ops);
-       if (!wsi->role_ops->write_role_protocol)
-               return lws_issue_raw(wsi, buf, len);
 
-       return wsi->role_ops->write_role_protocol(wsi, buf, len, &wp);
+       if (!lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol))
+               m = lws_issue_raw(wsi, buf, len);
+       else
+               m = lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol).
+                               write_role_protocol(wsi, buf, len, &wp);
+
+#if defined(LWS_WITH_SYS_METRICS)
+       if (wsi->a.vhost)
+               lws_metric_event(wsi->a.vhost->mt_traffic_tx, (char)
+                                (m < 0 ? METRES_NOGO : METRES_GO), len);
+#endif
+
+       return m;
 }
 
-LWS_VISIBLE int
-lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
+int
+lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, size_t len)
 {
-       struct lws_context *context = wsi->context;
-       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-       int n = 0;
-
-       lws_stats_bump(pt, LWSSTATS_C_API_READ, 1);
+       int n = 0, en;
 
        errno = 0;
+#if defined(LWS_WITH_UDP)
        if (lws_wsi_is_udp(wsi)) {
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
-               wsi->udp->salen = sizeof(wsi->udp->sa);
-               n = recvfrom(wsi->desc.sockfd, (char *)buf, len, 0,
-                            &wsi->udp->sa, &wsi->udp->salen);
+               socklen_t slt = sizeof(wsi->udp->sa46);
+
+               n = (int)recvfrom(wsi->desc.sockfd, (char *)buf,
+#if defined(WIN32)
+                               (int)
 #endif
+                               len, 0,
+                               sa46_sockaddr(&wsi->udp->sa46), &slt);
        } else
-               n = recv(wsi->desc.sockfd, (char *)buf, len, 0);
-
+#endif
+               n = (int)recv(wsi->desc.sockfd, (char *)buf,
+#if defined(WIN32)
+                               (int)
+#endif
+                               len, 0);
+       en = LWS_ERRNO;
        if (n >= 0) {
 
                if (!n && wsi->unix_skt)
-                       return LWS_SSL_CAPABLE_ERROR;
+                       goto do_err;
 
                /*
                 * See https://libwebsockets.org/
                 * pipermail/libwebsockets/2019-March/007857.html
                 */
-               if (!n)
-                       return LWS_SSL_CAPABLE_ERROR;
+               if (!n && !wsi->unix_skt)
+                       goto do_err;
 
-               if (wsi->vhost)
-                       wsi->vhost->conn_stats.rx += n;
-               lws_stats_bump(pt, LWSSTATS_B_READ, n);
+#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_SERVER)
+               if (wsi->a.vhost)
+                       lws_metric_event(wsi->a.vhost->mt_traffic_rx,
+                                        METRES_GO /* rx */, (unsigned int)n);
+#endif
 
                return n;
        }
 
-       if (LWS_ERRNO == LWS_EAGAIN ||
-           LWS_ERRNO == LWS_EWOULDBLOCK ||
-           LWS_ERRNO == LWS_EINTR)
+       if (en == LWS_EAGAIN ||
+           en == LWS_EWOULDBLOCK ||
+           en == LWS_EINTR)
                return LWS_SSL_CAPABLE_MORE_SERVICE;
 
-       lwsl_info("error on reading from skt : %d\n", LWS_ERRNO);
+do_err:
+#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_SERVER)
+       if (wsi->a.vhost)
+               lws_metric_event(wsi->a.vhost->mt_traffic_rx, METRES_NOGO, 0u);
+#endif
+
+       lwsl_wsi_info(wsi, "error on reading from skt : %d, errno %d", n, en);
+
        return LWS_SSL_CAPABLE_ERROR;
 }
 
-LWS_VISIBLE int
-lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
+int
+lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, size_t len)
 {
        int n = 0;
 #if defined(LWS_PLAT_OPTEE)
        ssize_t send(int sockfd, const void *buf, size_t len, int flags);
 #endif
 
+#if defined(LWS_WITH_UDP)
        if (lws_wsi_is_udp(wsi)) {
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
+
+               if (lws_fi(&wsi->fic, "udp_tx_loss")) {
+                       /* pretend it was sent */
+                       n = (int)(ssize_t)len;
+                       goto post_send;
+               }
+
                if (lws_has_buffered_out(wsi))
-                       n = sendto(wsi->desc.sockfd, (const char *)buf,
-                                  len, 0, &wsi->udp->sa_pending,
-                                  wsi->udp->salen_pending);
+                       n = (int)sendto(wsi->desc.sockfd, (const char *)buf,
+#if defined(WIN32)
+                               (int)
+#endif
+                                  len, 0, sa46_sockaddr(&wsi->udp->sa46_pending),
+                                  sa46_socklen(&wsi->udp->sa46_pending));
                else
-                       n = sendto(wsi->desc.sockfd, (const char *)buf,
-                                  len, 0, &wsi->udp->sa, wsi->udp->salen);
+                       n = (int)sendto(wsi->desc.sockfd, (const char *)buf,
+#if defined(WIN32)
+                               (int)
 #endif
+                                  len, 0, sa46_sockaddr(&wsi->udp->sa46),
+                                  sa46_socklen(&wsi->udp->sa46));
        } else
-               n = send(wsi->desc.sockfd, (char *)buf, len, MSG_NOSIGNAL);
+#endif
+               if (wsi->role_ops->file_handle)
+                       n = (int)write((int)(lws_intptr_t)wsi->desc.filefd, buf,
+#if defined(WIN32)
+                               (int)
+#endif
+                                       len);
+               else
+                       n = (int)send(wsi->desc.sockfd, (char *)buf,
+#if defined(WIN32)
+                               (int)
+#endif
+                                       len, MSG_NOSIGNAL);
 //     lwsl_info("%s: sent len %d result %d", __func__, len, n);
+
+#if defined(LWS_WITH_UDP)
+post_send:
+#endif
        if (n >= 0)
                return n;
 
@@ -331,17 +367,17 @@ lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
                return LWS_SSL_CAPABLE_MORE_SERVICE;
        }
 
-       lwsl_debug("ERROR writing len %d to skt fd %d err %d / errno %d\n",
-                  len, wsi->desc.sockfd, n, LWS_ERRNO);
+       lwsl_wsi_debug(wsi, "ERROR writing len %d to skt fd %d err %d / errno %d",
+                           (int)(ssize_t)len, wsi->desc.sockfd, n, LWS_ERRNO);
 
        return LWS_SSL_CAPABLE_ERROR;
 }
 
-LWS_VISIBLE int
+int
 lws_ssl_pending_no_ssl(struct lws *wsi)
 {
        (void)wsi;
-#if defined(LWS_WITH_ESP32)
+#if defined(LWS_PLAT_FREERTOS)
        return 100;
 #else
        return 0;
index 725861c..dea85ae 100644 (file)
@@ -1,30 +1,33 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 int
 _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
 {
-#if !defined(LWS_WITH_LIBUV) && !defined(LWS_WITH_LIBEV) && !defined(LWS_WITH_LIBEVENT)
+#if !defined(LWS_WITH_EVENT_LIBS)
        volatile struct lws_context_per_thread *vpt;
 #endif
        struct lws_context_per_thread *pt;
@@ -58,19 +61,17 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
                 * to cancel service
                 */
 
-               lwsl_debug("%s: using leave_pollout_active\n", __func__);
+               lwsl_wsi_debug(wsi, "using leave_pollout_active");
 
                return 0;
        }
 
-       context = wsi->context;
+       context = wsi->a.context;
        pt = &context->pt[(int)wsi->tsi];
 
        assert(wsi->position_in_fds_table < (int)pt->fds_count);
 
-#if !defined(LWS_WITH_LIBUV) && \
-    !defined(LWS_WITH_LIBEV) && \
-    !defined(LWS_WITH_LIBEVENT)
+#if !defined(LWS_WITH_EVENT_LIBS)
        /*
         * This only applies when we use the default poll() event loop.
         *
@@ -137,20 +138,27 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
        lws_memory_barrier();
 #endif
 
+#if !defined(__linux__) && !defined(WIN32)
+       /* OSX couldn't see close on stdin pipe side otherwise; WSAPOLL
+        * blows up if we give it POLLHUP
+        */
+       _or |= LWS_POLLHUP;
+#endif
+
        pfd = &pt->fds[wsi->position_in_fds_table];
        pa->fd = wsi->desc.sockfd;
-       lwsl_debug("%s: wsi %p: fd %d events %d -> %d\n", __func__, wsi,
-                  pa->fd, pfd->events, (pfd->events & ~_and) | _or);
+       lwsl_wsi_debug(wsi, "fd %d events %d -> %d", pa->fd, pfd->events,
+                                               (pfd->events & ~_and) | _or);
        pa->prev_events = pfd->events;
-       pa->events = pfd->events = (pfd->events & ~_and) | _or;
+       pa->events = pfd->events = (short)((pfd->events & ~_and) | _or);
 
-       if (wsi->http2_substream)
+       if (wsi->mux_substream)
                return 0;
 
 #if defined(LWS_WITH_EXTERNAL_POLL)
 
-       if (wsi->vhost &&
-           wsi->vhost->protocols[0].callback(wsi,
+       if (wsi->a.vhost &&
+           wsi->a.vhost->protocols[0].callback(wsi,
                                              LWS_CALLBACK_CHANGE_MODE_POLL_FD,
                                              wsi->user_space, (void *)pa, 0)) {
                ret = -1;
@@ -184,16 +192,17 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
         *         then cancel it to force a restart with our changed events
         */
        pa_events = pa->prev_events != pa->events;
+       pfd->events = (short)pa->events;
 
        if (pa_events) {
                if (lws_plat_change_pollfd(context, wsi, pfd)) {
-                       lwsl_info("%s failed\n", __func__);
+                       lwsl_wsi_info(wsi, "failed");
                        ret = -1;
                        goto bail;
                }
                sampled_tid = pt->service_tid;
-               if (sampled_tid && wsi->vhost) {
-                       tid = wsi->vhost->protocols[0].callback(wsi,
+               if (sampled_tid && wsi->a.vhost) {
+                       tid = wsi->a.vhost->protocols[0].callback(wsi,
                                     LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
                        if (tid == -1) {
                                ret = -1;
@@ -208,7 +217,7 @@ bail:
        return ret;
 }
 
-#ifndef LWS_NO_SERVER
+#if defined(LWS_WITH_SERVER)
 /*
  * Enable or disable listen sockets on this pt globally...
  * it's modulated according to the pt having space for a new accept.
@@ -221,32 +230,33 @@ lws_accept_modulation(struct lws_context *context,
        struct lws_pollargs pa1;
 
        while (vh) {
-               if (vh->lserv_wsi) {
-                       if (allow)
-                               _lws_change_pollfd(vh->lserv_wsi,
-                                          0, LWS_POLLIN, &pa1);
-                       else
-                               _lws_change_pollfd(vh->lserv_wsi,
-                                          LWS_POLLIN, 0, &pa1);
-               }
+               lws_start_foreach_dll(struct lws_dll2 *, d,
+                                     lws_dll2_get_head(&vh->listen_wsi)) {
+                       struct lws *wsi = lws_container_of(d, struct lws,
+                                                          listen_list);
+
+                       _lws_change_pollfd(wsi, allow ? 0 : LWS_POLLIN,
+                                               allow ? LWS_POLLIN : 0, &pa1);
+               } lws_end_foreach_dll(d);
+
                vh = vh->vhost_next;
        }
 }
 #endif
 
-#if defined(_DEBUG)
+#if _LWS_ENABLED_LOGS & LLL_WARN
 void
 __dump_fds(struct lws_context_per_thread *pt, const char *s)
 {
        unsigned int n;
 
-       lwsl_warn("%s: fds_count %u, %s\n", __func__, pt->fds_count, s);
+       lwsl_cx_warn(pt->context, "fds_count %u, %s", pt->fds_count, s);
 
        for (n = 0; n < pt->fds_count; n++) {
                struct lws *wsi = wsi_from_fd(pt->context, pt->fds[n].fd);
 
-               lwsl_warn("  %d: fd %d, wsi %p, pos_in_fds: %d\n",
-                       n + 1, pt->fds[n].fd, wsi,
+               lwsl_cx_warn(pt->context, "  %d: fd %d, wsi %s, pos_in_fds: %d",
+                       n + 1, pt->fds[n].fd, lws_wsi_tag(wsi),
                        wsi ? wsi->position_in_fds_table : -1);
        }
 }
@@ -265,19 +275,21 @@ __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
 
 //     __dump_fds(pt, "pre insert");
 
-       lwsl_debug("%s: %p: tsi=%d, sock=%d, pos-in-fds=%d\n",
-                 __func__, wsi, wsi->tsi, wsi->desc.sockfd, pt->fds_count);
+       lws_pt_assert_lock_held(pt);
+
+       lwsl_wsi_debug(wsi, "tsi=%d, sock=%d, pos-in-fds=%d",
+                       wsi->tsi, wsi->desc.sockfd, pt->fds_count);
 
        if ((unsigned int)pt->fds_count >= context->fd_limit_per_thread) {
-               lwsl_err("Too many fds (%d vs %d)\n", context->max_fds,
-                               context->fd_limit_per_thread    );
+               lwsl_cx_err(context, "Too many fds (%d vs %d)", context->max_fds,
+                               context->fd_limit_per_thread);
                return 1;
        }
 
 #if !defined(_WIN32)
-       if (!wsi->context->max_fds_unrelated_to_ulimit &&
-           wsi->desc.sockfd - lws_plat_socket_offset() >= context->max_fds) {
-               lwsl_err("Socket fd %d is too high (%d) offset %d\n",
+       if (!wsi->a.context->max_fds_unrelated_to_ulimit &&
+           wsi->desc.sockfd - lws_plat_socket_offset() >= (int)context->max_fds) {
+               lwsl_cx_err(context, "Socket fd %d is too high (%d) offset %d",
                         wsi->desc.sockfd, context->max_fds,
                         lws_plat_socket_offset());
                return 1;
@@ -285,13 +297,18 @@ __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
 #endif
 
        assert(wsi);
-       assert(wsi->event_pipe || wsi->vhost);
+
+#if defined(LWS_WITH_NETLINK)
+       assert(wsi->event_pipe || wsi->a.vhost || wsi == pt->context->netlink);
+#else
+       assert(wsi->event_pipe || wsi->a.vhost);
+#endif
        assert(lws_socket_is_valid(wsi->desc.sockfd));
 
 #if defined(LWS_WITH_EXTERNAL_POLL)
 
-       if (wsi->vhost &&
-           wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
+       if (wsi->a.vhost &&
+           wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
                                           wsi->user_space, (void *) &pa, 1))
                return -1;
 #endif
@@ -299,7 +316,7 @@ __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
        if (insert_wsi(context, wsi))
                return -1;
        pt->count_conns++;
-       wsi->position_in_fds_table = pt->fds_count;
+       wsi->position_in_fds_table = (int)pt->fds_count;
 
        pt->fds[wsi->position_in_fds_table].fd = wsi->desc.sockfd;
        pt->fds[wsi->position_in_fds_table].events = LWS_POLLIN;
@@ -312,20 +329,20 @@ __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
 #if defined(LWS_WITH_EXTERNAL_POLL)
 
        /* external POLL support via protocol 0 */
-       if (wsi->vhost &&
-           wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_ADD_POLL_FD,
+       if (wsi->a.vhost &&
+           wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_ADD_POLL_FD,
                                           wsi->user_space, (void *) &pa, 0))
                ret =  -1;
 #endif
-#ifndef LWS_NO_SERVER
-       /* if no more room, defeat accepts on this thread */
+#if defined(LWS_WITH_SERVER)
+       /* if no more room, defeat accepts on this service thread */
        if ((unsigned int)pt->fds_count == context->fd_limit_per_thread - 1)
                lws_accept_modulation(context, pt, 0);
 #endif
 
 #if defined(LWS_WITH_EXTERNAL_POLL)
-       if (wsi->vhost &&
-           wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
+       if (wsi->a.vhost &&
+           wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
                                           wsi->user_space, (void *)&pa, 1))
                ret = -1;
 #endif
@@ -335,10 +352,12 @@ __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
        return ret;
 }
 
+/* requires pt lock */
+
 int
 __remove_wsi_socket_from_fds(struct lws *wsi)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
 #if defined(LWS_WITH_EXTERNAL_POLL)
        struct lws_pollargs pa = { wsi->desc.sockfd, 0, 0 };
 #endif
@@ -346,40 +365,41 @@ __remove_wsi_socket_from_fds(struct lws *wsi)
        struct lws *end_wsi;
        int v, m, ret = 0;
 
+       lws_pt_assert_lock_held(pt);
+
 //     __dump_fds(pt, "pre remove");
 
 #if !defined(_WIN32)
-       if (!wsi->context->max_fds_unrelated_to_ulimit &&
-           wsi->desc.sockfd - lws_plat_socket_offset() > context->max_fds) {
-               lwsl_err("fd %d too high (%d)\n", wsi->desc.sockfd,
-                        context->max_fds);
+       if (!wsi->a.context->max_fds_unrelated_to_ulimit &&
+           wsi->desc.sockfd - lws_plat_socket_offset() > (int)context->max_fds) {
+               lwsl_wsi_err(wsi, "fd %d too high (%d)",
+                                  wsi->desc.sockfd,
+                                  context->max_fds);
 
                return 1;
        }
 #endif
 #if defined(LWS_WITH_EXTERNAL_POLL)
-       if (wsi->vhost && wsi->vhost->protocols &&
-           wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
+       if (wsi->a.vhost && wsi->a.vhost->protocols &&
+           wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
                                           wsi->user_space, (void *)&pa, 1))
                return -1;
 #endif
 
-       lws_same_vh_protocol_remove(wsi);
+       __lws_same_vh_protocol_remove(wsi);
 
        /* the guy who is to be deleted's slot index in pt->fds */
        m = wsi->position_in_fds_table;
        
        /* these are the only valid possibilities for position_in_fds_table */
-       assert(m == LWS_NO_FDS_POS || (m >= 0 &&
-                                      (unsigned int)m < pt->fds_count));
+       assert(m == LWS_NO_FDS_POS || (m >= 0 && (unsigned int)m < pt->fds_count));
 
        if (context->event_loop_ops->io)
-               context->event_loop_ops->io(wsi,
-                                 LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE |
-                                 LWS_EV_PREPARE_DELETION);
+               context->event_loop_ops->io(wsi, LWS_EV_STOP | LWS_EV_READ |
+                                                              LWS_EV_WRITE);
 /*
-       lwsl_notice("%s: wsi=%p, skt=%d, fds pos=%d, end guy pos=%d, endfd=%d\n",
-                 __func__, wsi, wsi->desc.sockfd, wsi->position_in_fds_table,
+       lwsl_notice("%s: wsi=%s, skt=%d, fds pos=%d, end guy pos=%d, endfd=%d\n",
+                 __func__, lws_wsi_tag(wsi), wsi->desc.sockfd, wsi->position_in_fds_table,
                  pt->fds_count, pt->fds[pt->fds_count - 1].fd); */
 
        if (m != LWS_NO_FDS_POS) {
@@ -407,27 +427,30 @@ __remove_wsi_socket_from_fds(struct lws *wsi)
                         * deletion guy's old one */
                        end_wsi = wsi_from_fd(context, v);
                        if (!end_wsi) {
-                               lwsl_err("no wsi for fd %d pos %d, "
-                                        "pt->fds_count=%d\n",
-                                        (int)pt->fds[m].fd, m, pt->fds_count);
-                               assert(0);
+                               lwsl_wsi_err(wsi, "no wsi for fd %d pos %d, "
+                                                 "pt->fds_count=%d",
+                                                 (int)pt->fds[m].fd, m,
+                                                 pt->fds_count);
+                               // assert(0);
                        } else
                                end_wsi->position_in_fds_table = m;
                }
 
                /* removed wsi has no position any more */
                wsi->position_in_fds_table = LWS_NO_FDS_POS;
-       }
 
 #if defined(LWS_WITH_EXTERNAL_POLL)
-       /* remove also from external POLL support via protocol 0 */
-       if (lws_socket_is_valid(wsi->desc.sockfd) && wsi->vhost &&
-           wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_DEL_POLL_FD,
-                                             wsi->user_space, (void *) &pa, 0))
-               ret = -1;
+               /* remove also from external POLL support via protocol 0 */
+               if (lws_socket_is_valid(wsi->desc.sockfd) && wsi->a.vhost &&
+                   wsi->a.vhost->protocols[0].callback(wsi,
+                                                       LWS_CALLBACK_DEL_POLL_FD,
+                                                       wsi->user_space,
+                                                       (void *) &pa, 0))
+                       ret = -1;
 #endif
+       }
 
-#ifndef LWS_NO_SERVER
+#if defined(LWS_WITH_SERVER)
        if (!context->being_destroyed &&
            /* if this made some room, accept connects on this thread */
            (unsigned int)pt->fds_count < context->fd_limit_per_thread - 1)
@@ -435,8 +458,8 @@ __remove_wsi_socket_from_fds(struct lws *wsi)
 #endif
 
 #if defined(LWS_WITH_EXTERNAL_POLL)
-       if (wsi->vhost &&
-           wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
+       if (wsi->a.vhost &&
+           wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
                                              wsi->user_space, (void *) &pa, 1))
                ret = -1;
 #endif
@@ -453,7 +476,7 @@ __lws_change_pollfd(struct lws *wsi, int _and, int _or)
        struct lws_pollargs pa;
        int ret = 0;
 
-       if (!wsi || (!wsi->protocol && !wsi->event_pipe) ||
+       if (!wsi || (!wsi->a.protocol && !wsi->event_pipe) ||
            wsi->position_in_fds_table == LWS_NO_FDS_POS)
                return 0;
 
@@ -462,8 +485,8 @@ __lws_change_pollfd(struct lws *wsi, int _and, int _or)
                return 1;
 
 #if defined(LWS_WITH_EXTERNAL_POLL)
-       if (wsi->vhost &&
-           wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
+       if (wsi->a.vhost &&
+           wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
                                              wsi->user_space, (void *) &pa, 0))
                return -1;
 #endif
@@ -471,8 +494,8 @@ __lws_change_pollfd(struct lws *wsi, int _and, int _or)
        ret = _lws_change_pollfd(wsi, _and, _or, &pa);
 
 #if defined(LWS_WITH_EXTERNAL_POLL)
-       if (wsi->vhost &&
-           wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
+       if (wsi->a.vhost &&
+           wsi->a.vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
                                           wsi->user_space, (void *) &pa, 0))
                ret = -1;
 #endif
@@ -486,7 +509,7 @@ lws_change_pollfd(struct lws *wsi, int _and, int _or)
        struct lws_context_per_thread *pt;
        int ret = 0;
 
-       pt = &wsi->context->pt[(int)wsi->tsi];
+       pt = &wsi->a.context->pt[(int)wsi->tsi];
 
        lws_pt_lock(pt, __func__);
        ret = __lws_change_pollfd(wsi, _and, _or);
@@ -495,10 +518,10 @@ lws_change_pollfd(struct lws *wsi, int _and, int _or)
        return ret;
 }
 
-LWS_VISIBLE int
+int
 lws_callback_on_writable(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt;
+       struct lws *w = wsi;
 
        if (lwsi_state(wsi) == LRS_SHUTDOWN)
                return 0;
@@ -506,30 +529,21 @@ lws_callback_on_writable(struct lws *wsi)
        if (wsi->socket_is_permanently_unusable)
                return 0;
 
-       pt = &wsi->context->pt[(int)wsi->tsi];
-
-       lws_stats_bump(pt, LWSSTATS_C_WRITEABLE_CB_REQ, 1);
-#if defined(LWS_WITH_STATS)
-       if (!wsi->active_writable_req_us) {
-               wsi->active_writable_req_us = lws_now_usecs();
-               lws_stats_bump(pt, LWSSTATS_C_WRITEABLE_CB_EFF_REQ, 1);
-       }
-#endif
-
-
-       if (wsi->role_ops->callback_on_writable) {
-               if (wsi->role_ops->callback_on_writable(wsi))
+       if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_callback_on_writable)) {
+               int q = lws_rops_func_fidx(wsi->role_ops,
+                                          LWS_ROPS_callback_on_writable).
+                                                     callback_on_writable(wsi);
+               if (q)
                        return 1;
-               wsi = lws_get_network_wsi(wsi);
-       }
-
-       if (wsi->position_in_fds_table == LWS_NO_FDS_POS) {
-               lwsl_debug("%s: failed to find socket %d\n", __func__,
-                          wsi->desc.sockfd);
-               return -1;
-       }
+               w = lws_get_network_wsi(wsi);
+       } else
+               if (w->position_in_fds_table == LWS_NO_FDS_POS) {
+                       lwsl_wsi_debug(wsi, "failed to find socket %d",
+                                           wsi->desc.sockfd);
+                       return -1;
+               }
 
-       if (__lws_change_pollfd(wsi, 0, LWS_POLLOUT))
+       if (__lws_change_pollfd(w, 0, LWS_POLLOUT))
                return -1;
 
        return 1;
@@ -548,39 +562,43 @@ lws_callback_on_writable(struct lws *wsi)
 void
 lws_same_vh_protocol_insert(struct lws *wsi, int n)
 {
-       lws_vhost_lock(wsi->vhost);
+       lws_context_lock(wsi->a.context, __func__);
+       lws_vhost_lock(wsi->a.vhost);
 
        lws_dll2_remove(&wsi->same_vh_protocol);
        lws_dll2_add_head(&wsi->same_vh_protocol,
-                         &wsi->vhost->same_vh_protocol_owner[n]);
+                         &wsi->a.vhost->same_vh_protocol_owner[n]);
 
-       wsi->bound_vhost_index = n;
+       wsi->bound_vhost_index = (uint8_t)n;
 
-       lws_vhost_unlock(wsi->vhost);
+       lws_vhost_unlock(wsi->a.vhost);
+       lws_context_unlock(wsi->a.context);
 }
 
 void
 __lws_same_vh_protocol_remove(struct lws *wsi)
 {
-       if (wsi->vhost && wsi->vhost->same_vh_protocol_owner)
+       if (wsi->a.vhost && wsi->a.vhost->same_vh_protocol_owner)
                lws_dll2_remove(&wsi->same_vh_protocol);
 }
 
 void
 lws_same_vh_protocol_remove(struct lws *wsi)
 {
-       if (!wsi->vhost)
+       if (!wsi->a.vhost)
                return;
 
-       lws_vhost_lock(wsi->vhost);
+       lws_context_lock(wsi->a.context, __func__);
+       lws_vhost_lock(wsi->a.vhost);
 
        __lws_same_vh_protocol_remove(wsi);
 
-       lws_vhost_unlock(wsi->vhost);
+       lws_vhost_unlock(wsi->a.vhost);
+       lws_context_unlock(wsi->a.context);
 }
 
 
-LWS_VISIBLE int
+int
 lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
                                           const struct lws_protocols *protocol)
 {
@@ -589,9 +607,10 @@ lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
 
        if (protocol < vhost->protocols ||
            protocol >= (vhost->protocols + vhost->count_protocols)) {
-               lwsl_err("%s: protocol %p is not from vhost %p (%p - %p)\n",
-                       __func__, protocol, vhost->protocols, vhost,
-                       (vhost->protocols + vhost->count_protocols));
+               lwsl_vhost_err((struct lws_vhost *)vhost,
+                              "protocol %p is not from vhost %p (%p - %p)",
+                              protocol, vhost->protocols, vhost,
+                                 (vhost->protocols + vhost->count_protocols));
 
                return -1;
        }
@@ -602,7 +621,7 @@ lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
                        lws_dll2_get_head(&vhost->same_vh_protocol_owner[n])) {
                wsi = lws_container_of(d, struct lws, same_vh_protocol);
 
-               assert(wsi->protocol == protocol);
+               assert(wsi->a.protocol == protocol);
                lws_callback_on_writable(wsi);
 
        } lws_end_foreach_dll_safe(d, d1);
@@ -610,7 +629,7 @@ lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_callback_on_writable_all_protocol(const struct lws_context *context,
                                      const struct lws_protocols *protocol)
 {
diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h
new file mode 100644 (file)
index 0000000..2d3f73a
--- /dev/null
@@ -0,0 +1,1614 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(__LWS_CORE_NET_PRIVATE_H__)
+#define __LWS_CORE_NET_PRIVATE_H__
+
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+
+/*
+ * Generic pieces needed to manage muxable stream protocols like h2
+ */
+
+struct lws_muxable {
+       struct lws      *parent_wsi;
+       struct lws      *child_list;
+       struct lws      *sibling_list;
+
+       unsigned int    my_sid;
+       unsigned int    child_count;
+
+       uint32_t        highest_sid;
+
+       uint8_t         requested_POLLOUT;
+};
+
+#include "private-lib-roles.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define __lws_sul_insert_us(owner, sul, _us) \
+               (sul)->us = lws_now_usecs() + (lws_usec_t)(_us); \
+               __lws_sul_insert(owner, sul)
+
+
+/*
+ *
+ *  ------ roles ------
+ *
+ */
+
+/* null-terminated array of pointers to roles lws built with */
+extern const struct lws_role_ops *available_roles[];
+
+#define LWS_FOR_EVERY_AVAILABLE_ROLE_START(xx) { \
+               const struct lws_role_ops **ppxx = available_roles; \
+               while (*ppxx) { \
+                       const struct lws_role_ops *xx = *ppxx++;
+
+#define LWS_FOR_EVERY_AVAILABLE_ROLE_END }}
+
+/*
+ *
+ *  ------ event_loop ops ------
+ *
+ */
+
+/* enums of socks version */
+enum socks_version {
+       SOCKS_VERSION_4 = 4,
+       SOCKS_VERSION_5 = 5
+};
+
+/* enums of subnegotiation version */
+enum socks_subnegotiation_version {
+       SOCKS_SUBNEGOTIATION_VERSION_1 = 1,
+};
+
+/* enums of socks commands */
+enum socks_command {
+       SOCKS_COMMAND_CONNECT = 1,
+       SOCKS_COMMAND_BIND = 2,
+       SOCKS_COMMAND_UDP_ASSOCIATE = 3
+};
+
+/* enums of socks address type */
+enum socks_atyp {
+       SOCKS_ATYP_IPV4 = 1,
+       SOCKS_ATYP_DOMAINNAME = 3,
+       SOCKS_ATYP_IPV6 = 4
+};
+
+/* enums of socks authentication methods */
+enum socks_auth_method {
+       SOCKS_AUTH_NO_AUTH = 0,
+       SOCKS_AUTH_GSSAPI = 1,
+       SOCKS_AUTH_USERNAME_PASSWORD = 2
+};
+
+/* enums of subnegotiation status */
+enum socks_subnegotiation_status {
+       SOCKS_SUBNEGOTIATION_STATUS_SUCCESS = 0,
+};
+
+/* enums of socks request reply */
+enum socks_request_reply {
+       SOCKS_REQUEST_REPLY_SUCCESS = 0,
+       SOCKS_REQUEST_REPLY_FAILURE_GENERAL = 1,
+       SOCKS_REQUEST_REPLY_CONNECTION_NOT_ALLOWED = 2,
+       SOCKS_REQUEST_REPLY_NETWORK_UNREACHABLE = 3,
+       SOCKS_REQUEST_REPLY_HOST_UNREACHABLE = 4,
+       SOCKS_REQUEST_REPLY_CONNECTION_REFUSED = 5,
+       SOCKS_REQUEST_REPLY_TTL_EXPIRED = 6,
+       SOCKS_REQUEST_REPLY_COMMAND_NOT_SUPPORTED = 7,
+       SOCKS_REQUEST_REPLY_ATYP_NOT_SUPPORTED = 8
+};
+
+/* enums used to generate socks messages */
+enum socks_msg_type {
+       /* greeting */
+       SOCKS_MSG_GREETING,
+       /* credential, user name and password */
+       SOCKS_MSG_USERNAME_PASSWORD,
+       /* connect command */
+       SOCKS_MSG_CONNECT
+};
+
+enum {
+       LWS_RXFLOW_ALLOW = (1 << 0),
+       LWS_RXFLOW_PENDING_CHANGE = (1 << 1),
+};
+
+typedef enum lws_parser_return {
+       LPR_FORBIDDEN   = -2,
+       LPR_FAIL        = -1,
+       LPR_OK          = 0,
+       LPR_DO_FALLBACK = 2,
+} lws_parser_return_t;
+
+enum pmd_return {
+       PMDR_UNKNOWN,
+       PMDR_DID_NOTHING,
+       PMDR_HAS_PENDING,
+       PMDR_EMPTY_NONFINAL,
+       PMDR_EMPTY_FINAL,
+       PMDR_NOTHING_WE_SHOULD_DO,
+
+       PMDR_FAILED = -1
+};
+
+#if defined(LWS_WITH_PEER_LIMITS)
+struct lws_peer {
+       struct lws_peer *next;
+       struct lws_peer *peer_wait_list;
+
+       lws_sockaddr46  sa46;
+
+       time_t time_created;
+       time_t time_closed_all;
+
+       uint32_t hash;
+       uint32_t count_wsi;
+       uint32_t total_wsi;
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       struct lws_peer_role_http http;
+#endif
+};
+#endif
+
+#ifdef LWS_WITH_IPV6
+#define LWS_IPV6_ENABLED(vh) \
+       (!lws_check_opt(vh->context->options, LWS_SERVER_OPTION_DISABLE_IPV6) && \
+        !lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_IPV6))
+#else
+#define LWS_IPV6_ENABLED(context) (0)
+#endif
+
+#ifdef LWS_WITH_UNIX_SOCK
+#define LWS_UNIX_SOCK_ENABLED(vhost) \
+       (vhost->options & LWS_SERVER_OPTION_UNIX_SOCK)
+#else
+#define LWS_UNIX_SOCK_ENABLED(vhost) (0)
+#endif
+
+enum uri_path_states {
+       URIPS_IDLE,
+       URIPS_SEEN_SLASH,
+       URIPS_SEEN_SLASH_DOT,
+       URIPS_SEEN_SLASH_DOT_DOT,
+};
+
+enum uri_esc_states {
+       URIES_IDLE,
+       URIES_SEEN_PERCENT,
+       URIES_SEEN_PERCENT_H1,
+};
+
+#if defined(LWS_WITH_CLIENT)
+
+enum {
+       CIS_ADDRESS,
+       CIS_PATH,
+       CIS_HOST,
+       CIS_ORIGIN,
+       CIS_PROTOCOL,
+       CIS_METHOD,
+       CIS_IFACE,
+       CIS_ALPN,
+
+
+       CIS_COUNT
+};
+
+struct client_info_stash {
+       char *cis[CIS_COUNT];
+       void *opaque_user_data; /* not allocated or freed by lws */
+};
+#endif
+
+#if defined(LWS_WITH_UDP)
+#define lws_wsi_is_udp(___wsi) (!!___wsi->udp)
+#endif
+
+#define LWS_H2_FRAME_HEADER_LENGTH 9
+
+lws_usec_t
+__lws_sul_service_ripe(lws_dll2_owner_t *own, int num_own, lws_usec_t usnow);
+
+/*
+ * lws_async_dns
+ */
+
+typedef struct lws_async_dns {
+       lws_sockaddr46          sa46; /* nameserver */
+       lws_dll2_owner_t        waiting;
+       lws_dll2_owner_t        cached;
+       struct lws              *wsi;
+       time_t                  time_set_server;
+       uint8_t                 dns_server_set:1;
+       uint8_t                 dns_server_connected:1;
+} lws_async_dns_t;
+
+typedef enum {
+       LADNS_CONF_SERVER_UNKNOWN                               = -1,
+       LADNS_CONF_SERVER_SAME,
+       LADNS_CONF_SERVER_CHANGED
+} lws_async_dns_server_check_t;
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+void
+lws_aysnc_dns_completed(struct lws *wsi, void *sa, size_t salen,
+                       lws_async_dns_retcode_t ret);
+#endif
+void
+lws_async_dns_cancel(struct lws *wsi);
+
+void
+lws_async_dns_drop_server(struct lws_context *context);
+
+/*
+ * so we can have n connections being serviced simultaneously,
+ * these things need to be isolated per-thread.
+ */
+
+struct lws_context_per_thread {
+#if LWS_MAX_SMP > 1
+       pthread_mutex_t lock_stats;
+       struct lws_mutex_refcount mr;
+       pthread_t self;
+#endif
+       struct lws_dll2_owner dll_buflist_owner;  /* guys with pending rxflow */
+       struct lws_dll2_owner seq_owner;           /* list of lws_sequencer-s */
+       lws_dll2_owner_t      attach_owner;     /* pending lws_attach */
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       lws_dll2_owner_t ss_owner;
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) || \
+    defined(LWS_WITH_SECURE_STREAMS_THREAD_API)
+       lws_dll2_owner_t ss_dsh_owner;
+       lws_dll2_owner_t ss_client_owner;
+#endif
+
+       struct lws_dll2_owner pt_sul_owner[LWS_COUNT_PT_SUL_OWNERS];
+
+#if defined (LWS_WITH_SEQUENCER)
+       lws_sorted_usec_list_t sul_seq_heartbeat;
+#endif
+#if (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)) && defined(LWS_WITH_SERVER)
+       lws_sorted_usec_list_t sul_ah_lifecheck;
+#endif
+#if defined(LWS_WITH_TLS) && defined(LWS_WITH_SERVER)
+       lws_sorted_usec_list_t sul_tls;
+#endif
+#if defined(LWS_PLAT_UNIX)
+       lws_sorted_usec_list_t sul_plat;
+#endif
+#if defined(LWS_ROLE_CGI)
+       lws_sorted_usec_list_t sul_cgi;
+#endif
+#if defined(LWS_WITH_PEER_LIMITS)
+       lws_sorted_usec_list_t sul_peer_limits;
+#endif
+
+#if !defined(LWS_PLAT_FREERTOS)
+       struct lws *fake_wsi;   /* used for callbacks where there's no wsi */
+#endif
+
+#if defined(WIN32)
+       struct sockaddr_in frt_pipe_si;
+#endif
+
+#if defined(LWS_WITH_TLS)
+       struct lws_pt_tls tls;
+#endif
+       struct lws_context *context;
+
+       /*
+        * usable by anything in the service code, but only if the scope
+        * does not last longer than the service action (since next service
+        * of any socket can likewise use it and overwrite)
+        */
+       unsigned char *serv_buf;
+
+       struct lws_pollfd *fds;
+       volatile struct lws_foreign_thread_pollfd * volatile foreign_pfd_list;
+
+       lws_sockfd_type dummy_pipe_fds[2];
+       struct lws *pipe_wsi;
+
+       /* --- role based members --- */
+
+#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
+       struct lws_pt_role_ws ws;
+#endif
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       struct lws_pt_role_http http;
+#endif
+#if defined(LWS_ROLE_DBUS)
+       struct lws_pt_role_dbus dbus;
+#endif
+       /* --- event library based members --- */
+
+       void            *evlib_pt; /* overallocated */
+
+       /* --- */
+
+       unsigned long count_conns;
+       unsigned int fds_count;
+
+       /*
+        * set to the Thread ID that's doing the service loop just before entry
+        * to poll indicates service thread likely idling in poll()
+        * volatile because other threads may check it as part of processing
+        * for pollfd event change.
+        */
+       volatile int service_tid;
+       int service_tid_detected;
+#if !defined(LWS_PLAT_FREERTOS)
+       int count_event_loop_static_asset_handles;
+#endif
+
+       volatile unsigned char inside_poll;
+       volatile unsigned char foreign_spinlock;
+
+       unsigned char tid;
+
+       unsigned char inside_service:1;
+       unsigned char inside_lws_service:1;
+       unsigned char event_loop_foreign:1;
+       unsigned char event_loop_destroy_processing_done:1;
+       unsigned char event_loop_pt_unused:1;
+       unsigned char destroy_self:1;
+       unsigned char is_destroyed:1;
+};
+
+/*
+ * virtual host -related context information
+ *   vhostwide SSL context
+ *   vhostwide proxy
+ *
+ * hierarchy:
+ *
+ * context -> vhost -> wsi
+ *
+ * incoming connection non-SSL vhost binding:
+ *
+ *    listen socket -> wsi -> select vhost after first headers
+ *
+ * incoming connection SSL vhost binding:
+ *
+ *    SSL SNI -> wsi -> bind after SSL negotiation
+ */
+
+struct lws_vhost {
+#if defined(LWS_WITH_CLIENT) && defined(LWS_CLIENT_HTTP_PROXYING)
+       char proxy_basic_auth_token[128];
+#endif
+#if LWS_MAX_SMP > 1
+       struct lws_mutex_refcount               mr;
+       char                                    close_flow_vs_tsi[LWS_MAX_SMP];
+#endif
+
+#if defined(LWS_ROLE_H2)
+       struct lws_vhost_role_h2 h2;
+#endif
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       struct lws_vhost_role_http http;
+#endif
+#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
+       struct lws_vhost_role_ws ws;
+#endif
+
+       lws_lifecycle_t         lc;
+       lws_dll2_t              vh_being_destroyed_list;
+
+#if defined(LWS_WITH_SOCKS5)
+       char socks_proxy_address[128];
+       char socks_user[96];
+       char socks_password[96];
+#endif
+
+#if defined(LWS_WITH_TLS_SESSIONS)
+       lws_dll2_owner_t        tls_sessions; /* vh lock */
+#endif
+
+#if defined(LWS_WITH_EVENT_LIBS)
+       void            *evlib_vh; /* overallocated */
+#endif
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_metric_t    *mt_traffic_rx;
+       lws_metric_t    *mt_traffic_tx;
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_ctx_t                            fic;
+       /**< Fault Injection ctx for the vhost, hierarchy vhost->context */
+#endif
+
+       uint64_t options;
+
+       struct lws_context *context;
+       struct lws_vhost *vhost_next;
+
+       const lws_retry_bo_t *retry_policy;
+
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       lws_sorted_usec_list_t          sul_unref; /* grace period after idle */
+#endif
+
+#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
+       lws_ss_handle_t         *ss_handle; /* ss handle for the server obj */
+#endif
+
+       lws_dll2_owner_t        listen_wsi;
+
+       const char *name;
+       const char *iface;
+       const char *listen_accept_role;
+       const char *listen_accept_protocol;
+       const char *unix_socket_perms;
+
+       void (*finalize)(struct lws_vhost *vh, void *arg);
+       void *finalize_arg;
+
+       const struct lws_protocols *protocols;
+       void **protocol_vh_privs;
+       const struct lws_protocol_vhost_options *pvo;
+       const struct lws_protocol_vhost_options *headers;
+       struct lws_dll2_owner *same_vh_protocol_owner;
+       struct lws_vhost *no_listener_vhost_list;
+       struct lws_dll2_owner abstract_instances_owner;         /* vh lock */
+
+#if defined(LWS_WITH_CLIENT)
+       struct lws_dll2_owner dll_cli_active_conns_owner;
+#endif
+       struct lws_dll2_owner vh_awaiting_socket_owner;
+
+#if defined(LWS_WITH_TLS)
+       struct lws_vhost_tls tls;
+#endif
+
+       void *user;
+
+       int listen_port;
+#if !defined(LWS_PLAT_FREERTOS) && !defined(OPTEE_TA) && !defined(WIN32)
+       int bind_iface;
+#endif
+
+#if defined(LWS_WITH_SOCKS5)
+       unsigned int socks_proxy_port;
+#endif
+       int count_protocols;
+       int ka_time;
+       int ka_probes;
+       int ka_interval;
+       int keepalive_timeout;
+       int timeout_secs_ah_idle;
+       int connect_timeout_secs;
+       int fo_listen_queue;
+
+       int count_bound_wsi;
+
+#ifdef LWS_WITH_ACCESS_LOG
+       int log_fd;
+#endif
+
+#if defined(LWS_WITH_TLS_SESSIONS)
+       uint32_t                tls_session_cache_max;
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) || defined(LWS_WITH_SECURE_STREAMS_CPP)
+       int8_t                  ss_refcount;
+       /**< refcount of number of ss connections with streamtypes using this
+        * trust store */
+#endif
+
+       uint8_t allocated_vhost_protocols:1;
+       uint8_t created_vhost_protocols:1;
+       uint8_t being_destroyed:1;
+       uint8_t from_ss_policy:1;
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       uint8_t                 grace_after_unref:1;
+       /* grace time / autodelete aoplies to us */
+#endif
+
+       unsigned char default_protocol_index;
+       unsigned char raw_protocol_index;
+};
+
+void
+__lws_vhost_destroy2(struct lws_vhost *vh);
+
+#define mux_to_wsi(_m) lws_container_of(_m, struct lws, mux)
+
+void
+lws_wsi_mux_insert(struct lws *wsi, struct lws *parent_wsi, unsigned int sid);
+int
+lws_wsi_mux_mark_parents_needing_writeable(struct lws *wsi);
+struct lws *
+lws_wsi_mux_move_child_to_tail(struct lws **wsi2);
+int
+lws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi);
+
+void
+lws_wsi_mux_dump_children(struct lws *wsi);
+
+void
+lws_wsi_mux_close_children(struct lws *wsi, int reason);
+
+void
+lws_wsi_mux_sibling_disconnect(struct lws *wsi);
+
+void
+lws_wsi_mux_dump_waiting_children(struct lws *wsi);
+
+int
+lws_wsi_mux_apply_queue(struct lws *wsi);
+
+/*
+ * struct lws
+ */
+
+/*
+ * These pieces are very commonly used (via accessors) in user protocol handlers
+ * and have to be valid, even in the case no real wsi is available for the cb.
+ *
+ * We put all this category of pointers in there and compose it at the top of
+ * struct lws, so a dummy wsi providing these only needs to be this big, while
+ * still being castable for being a struct wsi *
+ */
+
+struct lws_a {
+       struct lws_context              *context;
+       struct lws_vhost                *vhost;
+       const struct lws_protocols      *protocol;
+       void                            *opaque_user_data;
+};
+
+/*
+ * For RTOS-class platforms, their code is relatively new, post-minimal examples
+ * and tend to not have legacy user protocol handler baggage touching unexpected
+ * things in fakewsi unconditionally... we can use an lws_a on the stack and
+ * don't need to define the rest of the wsi content, just cast it, this saves
+ * a wsi footprint in heap (typ 800 bytes nowadays even on RTOS).
+ *
+ * For other platforms that have been around for years and have thousands of
+ * different user protocol handler implementations, it's likely some of them
+ * will be touching the struct lws content unconditionally in the handler even
+ * when we are calling back with a non wsi-specific reason, and may react badly
+ * to it being garbage.  So continue to implement those as a full, zero-ed down
+ * prepared fakewsi on heap at context creation time.
+ */
+
+#if defined(LWS_PLAT_FREERTOS)
+#define lws_fakewsi_def_plwsa(pt) struct lws_a lwsa, *plwsa = &lwsa
+#else
+#define lws_fakewsi_def_plwsa(pt) struct lws_a *plwsa = &(pt)->fake_wsi->a
+#endif
+/* since we reuse the pt version, also correct to zero down the lws_a part */
+#define lws_fakewsi_prep_plwsa_ctx(_c) \
+               memset(plwsa, 0, sizeof(*plwsa)); plwsa->context = _c
+
+struct lws {
+
+       struct lws_a                    a;
+
+       /* structs */
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       struct _lws_http_mode_related   http;
+#endif
+#if defined(LWS_ROLE_H2)
+       struct _lws_h2_related          h2;
+#endif
+#if defined(LWS_ROLE_WS)
+       struct _lws_websocket_related   *ws; /* allocated if we upgrade to ws */
+#endif
+#if defined(LWS_ROLE_DBUS)
+       struct _lws_dbus_mode_related   dbus;
+#endif
+#if defined(LWS_ROLE_MQTT)
+       struct _lws_mqtt_related        *mqtt;
+#endif
+
+#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
+       struct lws_muxable              mux;
+       struct lws_tx_credit            txc;
+#endif
+
+       lws_lifecycle_t                 lc;
+
+       /* lifetime members */
+
+#if defined(LWS_WITH_EVENT_LIBS)
+       void                            *evlib_wsi; /* overallocated */
+#endif
+
+       lws_sorted_usec_list_t          sul_timeout;
+       lws_sorted_usec_list_t          sul_hrtimer;
+       lws_sorted_usec_list_t          sul_validity;
+       lws_sorted_usec_list_t          sul_connect_timeout;
+
+       struct lws_dll2                 dll_buflist; /* guys with pending rxflow */
+       struct lws_dll2                 same_vh_protocol;
+       struct lws_dll2                 vh_awaiting_socket;
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       struct lws_dll2                 adns; /* on adns list of guys to tell result */
+       lws_async_dns_cb_t              adns_cb; /* callback with result */
+#endif
+#if defined(LWS_WITH_SERVER)
+       struct lws_dll2                 listen_list;
+#endif
+#if defined(LWS_WITH_CLIENT)
+       struct lws_dll2                 dll_cli_active_conns;
+       struct lws_dll2                 dll2_cli_txn_queue;
+       struct lws_dll2_owner           dll2_cli_txn_queue_owner;
+
+       /**< caliper is reused for tcp, tls and txn conn phases */
+
+       lws_dll2_t                      speculative_list;
+       lws_dll2_owner_t                speculative_connect_owner;
+       /* wsis: additional connection candidates */
+       lws_dll2_owner_t                dns_sorted_list;
+       /* lws_dns_sort_t: dns results wrapped and sorted in a linked-list...
+        * deleted as they are tried, list empty == everything tried */
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_ctx_t                    fic;
+       /**< Fault Injection ctx for the wsi, hierarchy wsi->vhost->context */
+       lws_sorted_usec_list_t          sul_fault_timedclose;
+       /**< used to inject a fault that closes the wsi after a random time */
+#endif
+
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_metrics_caliper_compose(cal_conn)
+#endif
+
+       lws_sockaddr46                  sa46_local;
+       lws_sockaddr46                  sa46_peer;
+
+       /* pointers */
+
+       struct lws                      *parent; /* points to parent, if any */
+       struct lws                      *child_list; /* points to first child */
+       struct lws                      *sibling_list; /* subsequent children at same level */
+       const struct lws_role_ops       *role_ops;
+       struct lws_sequencer            *seq;   /* associated sequencer if any */
+       const lws_retry_bo_t            *retry_policy;
+
+       lws_log_cx_t                    *log_cx;
+
+#if defined(LWS_WITH_THREADPOOL)
+       lws_dll2_owner_t                tp_task_owner; /* struct lws_threadpool_task */
+#endif
+
+#if defined(LWS_WITH_PEER_LIMITS)
+       struct lws_peer                 *peer;
+#endif
+
+#if defined(LWS_WITH_UDP)
+       struct lws_udp                  *udp;
+#endif
+#if defined(LWS_WITH_CLIENT)
+       struct client_info_stash        *stash;
+       char                            *cli_hostname_copy;
+
+#if defined(LWS_WITH_CONMON)
+       struct lws_conmon               conmon;
+       lws_usec_t                      conmon_datum;
+#endif
+#endif /* WITH_CLIENT */
+       void                            *user_space;
+       void                            *opaque_parent_data;
+
+       struct lws_buflist              *buflist; /* input-side buflist */
+       struct lws_buflist              *buflist_out; /* output-side buflist */
+
+#if defined(LWS_WITH_TLS)
+       struct lws_lws_tls              tls;
+       char                            alpn[24];
+#endif
+
+       lws_sock_file_fd_type           desc; /* .filefd / .sockfd */
+
+       lws_wsi_state_t                 wsistate;
+       lws_wsi_state_t                 wsistate_pre_close;
+
+       /* ints */
+#define LWS_NO_FDS_POS (-1)
+       int                             position_in_fds_table;
+
+#if defined(LWS_WITH_CLIENT)
+       int                             chunk_remaining;
+       int                             flags;
+#endif
+       unsigned int                    cache_secs;
+
+       short                           bugcatcher;
+
+       unsigned int                    hdr_parsing_completed:1;
+       unsigned int                    mux_substream:1;
+       unsigned int                    upgraded_to_http2:1;
+       unsigned int                    mux_stream_immortal:1;
+       unsigned int                    h2_stream_carries_ws:1; /* immortal set as well */
+       unsigned int                    h2_stream_carries_sse:1; /* immortal set as well */
+       unsigned int                    h2_acked_settings:1;
+       unsigned int                    seen_nonpseudoheader:1;
+       unsigned int                    listener:1;
+       unsigned int                    pf_packet:1;
+       unsigned int                    do_broadcast:1;
+       unsigned int                    user_space_externally_allocated:1;
+       unsigned int                    socket_is_permanently_unusable:1;
+       unsigned int                    rxflow_change_to:2;
+       unsigned int                    conn_stat_done:1;
+       unsigned int                    cache_reuse:1;
+       unsigned int                    cache_revalidate:1;
+       unsigned int                    cache_intermediaries:1;
+       unsigned int                    favoured_pollin:1;
+       unsigned int                    sending_chunked:1;
+       unsigned int                    interpreting:1;
+       unsigned int                    already_did_cce:1;
+       unsigned int                    told_user_closed:1;
+       unsigned int                    told_event_loop_closed:1;
+       unsigned int                    waiting_to_send_close_frame:1;
+       unsigned int                    close_needs_ack:1;
+       unsigned int                    ipv6:1;
+       unsigned int                    parent_pending_cb_on_writable:1;
+       unsigned int                    cgi_stdout_zero_length:1;
+       unsigned int                    seen_zero_length_recv:1;
+       unsigned int                    rxflow_will_be_applied:1;
+       unsigned int                    event_pipe:1;
+       unsigned int                    handling_404:1;
+       unsigned int                    protocol_bind_balance:1;
+       unsigned int                    unix_skt:1;
+       unsigned int                    close_when_buffered_out_drained:1;
+       unsigned int                    h1_ws_proxied:1;
+       unsigned int                    proxied_ws_parent:1;
+       unsigned int                    do_bind:1;
+       unsigned int                    validity_hup:1;
+       unsigned int                    skip_fallback:1;
+       unsigned int                    file_desc:1;
+       unsigned int                    conn_validity_wakesuspend:1;
+       unsigned int                    dns_reachability:1;
+
+       unsigned int                    could_have_pending:1; /* detect back-to-back writes */
+       unsigned int                    outer_will_close:1;
+       unsigned int                    shadow:1; /* we do not control fd lifecycle at all */
+#if defined(LWS_WITH_SECURE_STREAMS)
+       unsigned int                    for_ss:1;
+       unsigned int                    bound_ss_proxy_conn:1;
+       unsigned int                    client_bound_sspc:1;
+       unsigned int                    client_proxy_onward:1;
+#endif
+       unsigned int                    tls_borrowed:1;
+       unsigned int                    tls_borrowed_hs:1;
+       unsigned int                    tls_read_wanted_write:1;
+
+#ifdef LWS_WITH_ACCESS_LOG
+       unsigned int                    access_log_pending:1;
+#endif
+#if defined(LWS_WITH_CLIENT)
+       unsigned int                    do_ws:1; /* whether we are doing http or ws flow */
+       unsigned int                    chunked:1; /* if the clientside connection is chunked */
+       unsigned int                    client_rx_avail:1;
+       unsigned int                    client_http_body_pending:1;
+       unsigned int                    transaction_from_pipeline_queue:1;
+       unsigned int                    keepalive_active:1;
+       unsigned int                    keepalive_rejected:1;
+       unsigned int                    redirected_to_get:1;
+       unsigned int                    client_pipeline:1;
+       unsigned int                    client_h2_alpn:1;
+       unsigned int                    client_mux_substream:1;
+       unsigned int                    client_mux_migrated:1;
+       unsigned int                    client_subsequent_mime_part:1;
+       unsigned int                    client_no_follow_redirect:1;
+       unsigned int                    client_suppress_CONNECTION_ERROR:1;
+       /**< because the client connection creation api is still the parent of
+        * this activity, and will report the failure */
+       unsigned int                    tls_session_reused:1;
+       unsigned int                    perf_done:1;
+       unsigned int                    close_is_redirect:1;
+       unsigned int                    client_mux_substream_was:1;
+#endif
+
+#ifdef _WIN32
+       unsigned int sock_send_blocking:1;
+#endif
+
+       uint16_t                        ocport, c_port, conn_port;
+       uint16_t                        retry;
+#if defined(LWS_WITH_CLIENT)
+       uint16_t                        keep_warm_secs;
+#endif
+
+       /* chars */
+
+       char lws_rx_parse_state; /* enum lws_rx_parse_state */
+       char rx_frame_type; /* enum lws_write_protocol */
+       char pending_timeout; /* enum pending_timeout */
+       char tsi; /* thread service index we belong to */
+       char protocol_interpret_idx;
+       char redirects;
+       uint8_t rxflow_bitmap;
+       uint8_t bound_vhost_index;
+       uint8_t lsp_channel; /* which of stdin/out/err */
+#ifdef LWS_WITH_CGI
+       char hdr_state;
+#endif
+#if defined(LWS_WITH_CLIENT)
+       char chunk_parser; /* enum lws_chunk_parser */
+       uint8_t addrinfo_idx;
+       uint8_t sys_tls_client_cert;
+       uint8_t c_pri;
+#endif
+       uint8_t         af;
+#if defined(LWS_WITH_CGI) || defined(LWS_WITH_CLIENT)
+       char reason_bf; /* internal writeable callback reason bitfield */
+#endif
+#if defined(LWS_WITH_NETLINK)
+       lws_route_uidx_t                peer_route_uidx;
+       /**< unique index of the route the connection is estimated to take */
+#endif
+       uint8_t immortal_substream_count;
+       /* volatile to make sure code is aware other thread can change */
+       volatile char handling_pollout;
+       volatile char leave_pollout_active;
+#if LWS_MAX_SMP > 1
+       volatile char undergoing_init_from_other_pt;
+#endif
+
+};
+
+#define lws_is_flowcontrolled(w) (!!(wsi->rxflow_bitmap))
+
+#if defined(LWS_WITH_SPAWN)
+
+#if defined(WIN32) || defined(_WIN32)
+#else
+#include <sys/wait.h>
+#include <sys/times.h>
+#endif
+
+struct lws_spawn_piped {
+
+       struct lws_spawn_piped_info     info;
+
+       struct lws_dll2                 dll;
+       lws_sorted_usec_list_t          sul;
+       lws_sorted_usec_list_t          sul_reap;
+
+       struct lws_context              *context;
+       struct lws                      *stdwsi[3];
+       lws_filefd_type                 pipe_fds[3][2];
+       int                             count_log_lines;
+
+       lws_usec_t                      created; /* set by lws_spawn_piped() */
+       lws_usec_t                      reaped;
+
+       lws_usec_t                      accounting[4];
+
+#if defined(WIN32)
+       HANDLE                          child_pid;
+       lws_sorted_usec_list_t          sul_poll;
+#else
+       pid_t                           child_pid;
+
+       siginfo_t                       si;
+#endif
+       int                             reap_retry_budget;
+
+       uint8_t                         pipes_alive:2;
+       uint8_t                         we_killed_him_timeout:1;
+       uint8_t                         we_killed_him_spew:1;
+       uint8_t                         ungraceful:1;
+};
+
+void
+lws_spawn_piped_destroy(struct lws_spawn_piped **lsp);
+
+int
+lws_spawn_reap(struct lws_spawn_piped *lsp);
+
+#endif
+
+void
+lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt);
+
+const struct lws_role_ops *
+lws_role_by_name(const char *name);
+
+int
+lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
+               lws_sockfd_type sockfd, int port, const char *iface,
+               int ipv6_allowed);
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+void
+lws_wsi_fault_timedclose(struct lws *wsi);
+#else
+#define lws_wsi_fault_timedclose(_w)
+#endif
+
+#if defined(LWS_WITH_IPV6)
+unsigned long
+lws_get_addr_scope(struct lws *wsi, const char *ipaddr);
+#endif
+
+void
+lws_close_free_wsi(struct lws *wsi, enum lws_close_status, const char *caller);
+void
+__lws_close_free_wsi(struct lws *wsi, enum lws_close_status, const char *caller);
+
+void
+__lws_free_wsi(struct lws *wsi);
+
+void
+lws_conmon_addrinfo_destroy(struct addrinfo *ai);
+
+int
+lws_conmon_append_copy_new_dns_results(struct lws *wsi,
+                                      const struct addrinfo *cai);
+
+#if LWS_MAX_SMP > 1
+
+static LWS_INLINE void
+lws_pt_mutex_init(struct lws_context_per_thread *pt)
+{
+       lws_mutex_refcount_init(&pt->mr);
+       pthread_mutex_init(&pt->lock_stats, NULL);
+}
+
+static LWS_INLINE void
+lws_pt_mutex_destroy(struct lws_context_per_thread *pt)
+{
+       pthread_mutex_destroy(&pt->lock_stats);
+       lws_mutex_refcount_destroy(&pt->mr);
+}
+
+#define lws_pt_lock(pt, reason) lws_mutex_refcount_lock(&pt->mr, reason)
+#define lws_pt_unlock(pt) lws_mutex_refcount_unlock(&pt->mr)
+#define lws_pt_assert_lock_held(pt) lws_mutex_refcount_assert_held(&pt->mr)
+
+static LWS_INLINE void
+lws_pt_stats_lock(struct lws_context_per_thread *pt)
+{
+       pthread_mutex_lock(&pt->lock_stats);
+}
+
+static LWS_INLINE void
+lws_pt_stats_unlock(struct lws_context_per_thread *pt)
+{
+       pthread_mutex_unlock(&pt->lock_stats);
+}
+#endif
+
+/*
+ * EXTENSIONS
+ */
+
+#if defined(LWS_WITHOUT_EXTENSIONS)
+#define lws_any_extension_handled(_a, _b, _c, _d) (0)
+#define lws_ext_cb_active(_a, _b, _c, _d) (0)
+#define lws_ext_cb_all_exts(_a, _b, _c, _d, _e) (0)
+#define lws_issue_raw_ext_access lws_issue_raw
+#define lws_context_init_extensions(_a, _b)
+#endif
+
+int LWS_WARN_UNUSED_RESULT
+lws_client_interpret_server_handshake(struct lws *wsi);
+
+int LWS_WARN_UNUSED_RESULT
+lws_ws_rx_sm(struct lws *wsi, char already_processed, unsigned char c);
+
+int LWS_WARN_UNUSED_RESULT
+lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len);
+
+void
+lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state,
+                   const struct lws_role_ops *ops);
+
+int
+lws_http_to_fallback(struct lws *wsi, unsigned char *buf, size_t len);
+
+int LWS_WARN_UNUSED_RESULT
+user_callback_handle_rxflow(lws_callback_function, struct lws *wsi,
+                           enum lws_callback_reasons reason, void *user,
+                           void *in, size_t len);
+
+int
+lws_plat_set_nonblocking(lws_sockfd_type fd);
+
+int
+lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd,
+                           int unix_skt);
+
+int
+lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags);
+
+int
+lws_plat_check_connection_error(struct lws *wsi);
+
+int LWS_WARN_UNUSED_RESULT
+lws_header_table_attach(struct lws *wsi, int autoservice);
+
+int
+lws_header_table_detach(struct lws *wsi, int autoservice);
+int
+__lws_header_table_detach(struct lws *wsi, int autoservice);
+
+void
+lws_header_table_reset(struct lws *wsi, int autoservice);
+
+void
+__lws_header_table_reset(struct lws *wsi, int autoservice);
+
+char * LWS_WARN_UNUSED_RESULT
+lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h);
+
+int LWS_WARN_UNUSED_RESULT
+lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s);
+
+int LWS_WARN_UNUSED_RESULT
+lws_ensure_user_space(struct lws *wsi);
+
+int LWS_WARN_UNUSED_RESULT
+lws_change_pollfd(struct lws *wsi, int _and, int _or);
+
+#if defined(LWS_WITH_SERVER)
+ int _lws_vhost_init_server(const struct lws_context_creation_info *info,
+                             struct lws_vhost *vhost);
+struct lws_vhost *
+ lws_select_vhost(struct lws_context *context, int port, const char *servername);
+int LWS_WARN_UNUSED_RESULT
+ lws_parse_ws(struct lws *wsi, unsigned char **buf, size_t len);
+void
+ lws_server_get_canonical_hostname(struct lws_context *context,
+                                  const struct lws_context_creation_info *info);
+#else
+ #define _lws_vhost_init_server(_a, _b) (0)
+ #define lws_parse_ws(_a, _b, _c) (0)
+ #define lws_server_get_canonical_hostname(_a, _b)
+#endif
+
+int
+__remove_wsi_socket_from_fds(struct lws *wsi);
+
+enum {
+       LWSRXFC_ERROR = -1,
+       LWSRXFC_CACHED = 0,
+       LWSRXFC_ADDITIONAL = 1,
+       LWSRXFC_TRIMMED = 2,
+};
+
+
+int
+_lws_plat_service_forced_tsi(struct lws_context *context, int tsi);
+
+int
+lws_rxflow_cache(struct lws *wsi, unsigned char *buf, size_t n, size_t len);
+
+int
+lws_service_flag_pending(struct lws_context *context, int tsi);
+
+int
+lws_has_buffered_out(struct lws *wsi);
+
+int LWS_WARN_UNUSED_RESULT
+lws_ws_client_rx_sm(struct lws *wsi, unsigned char c);
+
+lws_parser_return_t LWS_WARN_UNUSED_RESULT
+lws_parse(struct lws *wsi, unsigned char *buf, int *len);
+
+int LWS_WARN_UNUSED_RESULT
+lws_parse_urldecode(struct lws *wsi, uint8_t *_c);
+
+void
+lws_sa46_copy_address(lws_sockaddr46 *sa46a, const void *in, int af);
+
+int LWS_WARN_UNUSED_RESULT
+lws_http_action(struct lws *wsi);
+
+void
+__lws_close_free_wsi_final(struct lws *wsi);
+void
+lws_libuv_closehandle(struct lws *wsi);
+int
+lws_libuv_check_watcher_active(struct lws *wsi);
+
+#if defined(LWS_WITH_EVLIB_PLUGINS) || defined(LWS_WITH_PLUGINS)
+const lws_plugin_header_t *
+lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath,
+               const char *sofilename, const char *_class,
+               each_plugin_cb_t each, void *each_user);
+
+int
+lws_plat_destroy_dl(struct lws_plugin *p);
+#endif
+
+struct lws *
+lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
+
+void
+lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi);
+void
+__lws_vhost_unbind_wsi(struct lws *wsi); /* req cx + vh lock */
+
+void
+__lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
+int
+__lws_change_pollfd(struct lws *wsi, int _and, int _or);
+
+
+int
+lws_callback_as_writeable(struct lws *wsi);
+
+int
+lws_role_call_client_bind(struct lws *wsi,
+                         const struct lws_client_connect_info *i);
+void
+lws_remove_child_from_any_parent(struct lws *wsi);
+
+char *
+lws_generate_client_ws_handshake(struct lws *wsi, char *p, const char *conn1);
+int
+lws_client_ws_upgrade(struct lws *wsi, const char **cce);
+int
+lws_create_client_ws_object(const struct lws_client_connect_info *i,
+                           struct lws *wsi);
+int
+lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len);
+int
+lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn);
+int
+lws_tls_server_conn_alpn(struct lws *wsi);
+
+int
+lws_ws_client_rx_sm_block(struct lws *wsi, unsigned char **buf, size_t len);
+void
+lws_destroy_event_pipe(struct lws *wsi);
+
+/* socks */
+int
+lws_socks5c_generate_msg(struct lws *wsi, enum socks_msg_type type, ssize_t *msg_len);
+
+int LWS_WARN_UNUSED_RESULT
+__insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi);
+
+int LWS_WARN_UNUSED_RESULT
+lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len);
+
+lws_usec_t
+__lws_seq_timeout_check(struct lws_context_per_thread *pt, lws_usec_t usnow);
+
+lws_usec_t
+__lws_ss_timeout_check(struct lws_context_per_thread *pt, lws_usec_t usnow);
+
+struct lws * LWS_WARN_UNUSED_RESULT
+lws_client_connect_2_dnsreq(struct lws *wsi);
+
+LWS_VISIBLE struct lws * LWS_WARN_UNUSED_RESULT
+lws_client_reset(struct lws **wsi, int ssl, const char *address, int port,
+                const char *path, const char *host, char weak);
+
+struct lws * LWS_WARN_UNUSED_RESULT
+lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi, const char *desc);
+
+char * LWS_WARN_UNUSED_RESULT
+lws_generate_client_handshake(struct lws *wsi, char *pkt);
+
+int
+lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd);
+
+struct lws *
+lws_http_client_connect_via_info2(struct lws *wsi);
+
+
+struct lws *
+__lws_wsi_create_with_role(struct lws_context *context, int tsi,
+                        const struct lws_role_ops *ops,
+                        lws_log_cx_t *log_cx_template);
+int
+lws_wsi_inject_to_loop(struct lws_context_per_thread *pt, struct lws *wsi);
+
+int
+lws_wsi_extract_from_loop(struct lws *wsi);
+
+
+#if defined(LWS_WITH_CLIENT)
+int
+lws_http_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd);
+
+int LWS_WARN_UNUSED_RESULT
+lws_http_transaction_completed_client(struct lws *wsi);
+#if !defined(LWS_WITH_TLS)
+       #define lws_context_init_client_ssl(_a, _b) (0)
+#endif
+void
+lws_decode_ssl_error(void);
+#else
+#define lws_context_init_client_ssl(_a, _b) (0)
+#endif
+
+int
+__lws_rx_flow_control(struct lws *wsi);
+
+int
+_lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa);
+
+#if defined(LWS_WITH_SERVER)
+int
+lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len);
+#else
+#define lws_server_socket_service(_b, _c) (0)
+#define lws_handshake_server(_a, _b, _c) (0)
+#endif
+
+#ifdef LWS_WITH_ACCESS_LOG
+int
+lws_access_log(struct lws *wsi);
+void
+lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int len, int meth);
+#else
+#define lws_access_log(_a)
+#endif
+
+#if defined(_DEBUG)
+void
+lws_wsi_txc_describe(struct lws_tx_credit *txc, const char *at, uint32_t sid);
+#else
+#define lws_wsi_txc_describe(x, y, z) { (void)x; }
+#endif
+
+int
+lws_wsi_txc_check_skint(struct lws_tx_credit *txc, int32_t tx_cr);
+
+int
+lws_wsi_txc_report_manual_txcr_in(struct lws *wsi, int32_t bump);
+
+void
+lws_mux_mark_immortal(struct lws *wsi);
+void
+lws_http_close_immortal(struct lws *wsi);
+
+int
+lws_cgi_kill_terminated(struct lws_context_per_thread *pt);
+
+void
+lws_cgi_remove_and_kill(struct lws *wsi);
+
+void
+lws_plat_delete_socket_from_fds(struct lws_context *context,
+                               struct lws *wsi, int m);
+void
+lws_plat_insert_socket_into_fds(struct lws_context *context,
+                               struct lws *wsi);
+
+int
+lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi,
+                      struct lws_pollfd *pfd);
+
+#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
+int
+lws_adopt_ss_server_accept(struct lws *new_wsi);
+#endif
+
+int
+lws_plat_pipe_create(struct lws *wsi);
+int
+lws_plat_pipe_signal(struct lws_context *ctx, int tsi);
+void
+lws_plat_pipe_close(struct lws *wsi);
+
+void
+lws_addrinfo_clean(struct lws *wsi);
+
+void
+lws_add_wsi_to_draining_ext_list(struct lws *wsi);
+void
+lws_remove_wsi_from_draining_ext_list(struct lws *wsi);
+int
+lws_poll_listen_fd(struct lws_pollfd *fd);
+int
+lws_plat_service(struct lws_context *context, int timeout_ms);
+LWS_VISIBLE int
+_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi);
+
+int
+lws_pthread_self_to_tsi(struct lws_context *context);
+const char * LWS_WARN_UNUSED_RESULT
+lws_plat_inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
+int LWS_WARN_UNUSED_RESULT
+lws_plat_inet_pton(int af, const char *src, void *dst);
+
+void
+lws_same_vh_protocol_remove(struct lws *wsi);
+void
+__lws_same_vh_protocol_remove(struct lws *wsi);
+void
+lws_same_vh_protocol_insert(struct lws *wsi, int n);
+
+int
+lws_client_stash_create(struct lws *wsi, const char **cisin);
+
+void
+lws_seq_destroy_all_on_pt(struct lws_context_per_thread *pt);
+
+void
+lws_addrinfo_clean(struct lws *wsi);
+
+int
+_lws_route_pt_close_unroutable(struct lws_context_per_thread *pt);
+
+void
+_lws_routing_entry_dump(struct lws_context *cx, lws_route_t *rou);
+
+void
+_lws_routing_table_dump(struct lws_context *cx);
+
+#define LRR_IGNORE_PRI                 (1 << 0)
+#define LRR_MATCH_SRC                  (1 << 1)
+#define LRR_JUST_CHECK                 (1 << 2)
+
+lws_route_t *
+_lws_route_remove(struct lws_context_per_thread *pt, lws_route_t *robj, int flags);
+
+void
+_lws_route_table_empty(struct lws_context_per_thread *pt);
+
+void
+_lws_route_table_ifdown(struct lws_context_per_thread *pt, int idx);
+
+lws_route_uidx_t
+_lws_route_get_uidx(struct lws_context *cx);
+
+int
+_lws_route_pt_close_route_users(struct lws_context_per_thread *pt,
+                               lws_route_uidx_t uidx);
+
+lws_route_t *
+_lws_route_est_outgoing(struct lws_context_per_thread *pt,
+                       const lws_sockaddr46 *dest);
+
+int
+lws_sort_dns(struct lws *wsi, const struct addrinfo *result);
+
+int
+lws_broadcast(struct lws_context_per_thread *pt, int reason, void *in, size_t len);
+
+
+#if defined(LWS_WITH_PEER_LIMITS)
+void
+lws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer);
+int
+lws_peer_confirm_ah_attach_ok(struct lws_context *context,
+                             struct lws_peer *peer);
+void
+lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer);
+void
+lws_peer_cull_peer_wait_list(struct lws_context *context);
+struct lws_peer *
+lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd);
+void
+lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,
+                struct lws *wsi);
+void
+lws_peer_dump_from_wsi(struct lws *wsi);
+#endif
+
+#ifdef LWS_WITH_HUBBUB
+hubbub_error
+html_parser_cb(const hubbub_token *token, void *pw);
+#endif
+
+#if defined(_DEBUG)
+void
+lws_service_assert_loop_thread(struct lws_context *cx, int tsi);
+#else
+#define lws_service_assert_loop_thread(_cx, _tsi)
+#endif
+
+int
+lws_threadpool_tsi_context(struct lws_context *context, int tsi);
+
+void
+lws_threadpool_wsi_closing(struct lws *wsi);
+
+void
+__lws_wsi_remove_from_sul(struct lws *wsi);
+
+void
+lws_validity_confirmed(struct lws *wsi);
+void
+_lws_validity_confirmed_role(struct lws *wsi);
+
+int
+lws_seq_pt_init(struct lws_context_per_thread *pt);
+
+int
+lws_buflist_aware_read(struct lws_context_per_thread *pt, struct lws *wsi,
+                      struct lws_tokens *ebuf, char fr, const char *hint);
+int
+lws_buflist_aware_finished_consuming(struct lws *wsi, struct lws_tokens *ebuf,
+                                    int used, int buffered, const char *hint);
+
+extern const struct lws_protocols protocol_abs_client_raw_skt,
+                                 protocol_abs_client_unit_test;
+
+void
+__lws_reset_wsi(struct lws *wsi);
+
+void
+lws_metrics_dump(struct lws_context *ctx);
+
+void
+lws_inform_client_conn_fail(struct lws *wsi, void *arg, size_t len);
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+lws_async_dns_server_check_t
+lws_plat_asyncdns_init(struct lws_context *context, lws_sockaddr46 *sa);
+int
+lws_async_dns_init(struct lws_context *context);
+void
+lws_async_dns_deinit(lws_async_dns_t *dns);
+#endif
+
+int
+lws_protocol_init_vhost(struct lws_vhost *vh, int *any);
+int
+_lws_generic_transaction_completed_active_conn(struct lws **wsi, char take_vh_lock);
+
+#define ACTIVE_CONNS_SOLO 0
+#define ACTIVE_CONNS_MUXED 1
+#define ACTIVE_CONNS_QUEUED 2
+#define ACTIVE_CONNS_FAILED 3
+
+#if defined(_DEBUG) && !defined(LWS_PLAT_FREERTOS) && !defined(WIN32) && !defined(LWS_PLAT_OPTEE)
+
+int
+sanity_assert_no_wsi_traces(const struct lws_context *context, struct lws *wsi);
+int
+sanity_assert_no_sockfd_traces(const struct lws_context *context,
+                              lws_sockfd_type sfd);
+#else
+static inline int sanity_assert_no_wsi_traces(const struct lws_context *context, struct lws *wsi) { (void)context; (void)wsi; return 0; }
+static inline int sanity_assert_no_sockfd_traces(const struct lws_context *context, lws_sockfd_type sfd) { (void)context; (void)sfd; return 0; }
+#endif
+
+
+void
+delete_from_fdwsi(const struct lws_context *context, struct lws *wsi);
+
+int
+lws_vhost_active_conns(struct lws *wsi, struct lws **nwsi, const char *adsin);
+
+const char *
+lws_wsi_client_stash_item(struct lws *wsi, int stash_idx, int hdr_idx);
+
+int
+lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname);
+
+int
+lws_socks5c_ads_server(struct lws_vhost *vh,
+                      const struct lws_context_creation_info *info);
+
+int
+lws_socks5c_handle_state(struct lws *wsi, struct lws_pollfd *pollfd,
+                        const char **pcce);
+
+int
+lws_socks5c_greet(struct lws *wsi, const char **pcce);
+
+int
+lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len);
+
+int
+lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len);
+
+lws_usec_t
+lws_sul_nonmonotonic_adjust(struct lws_context *ctx, int64_t step_us);
+
+void
+__lws_vhost_destroy_pt_wsi_dieback_start(struct lws_vhost *vh);
+
+int
+lws_vhost_compare_listen(struct lws_vhost *v1, struct lws_vhost *v2);
+
+void
+lws_netdev_instance_remove_destroy(struct lws_netdev_instance *ni);
+
+int
+lws_score_dns_results(struct lws_context *ctx,
+                            const struct addrinfo **result);
+
+#if defined(LWS_WITH_SYS_SMD)
+int
+lws_netdev_smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
+                 void *buf, size_t len);
+#endif
+
+void
+lws_netdev_instance_create(lws_netdev_instance_t *ni, struct lws_context *ctx,
+                          const lws_netdev_ops_t *ops, const char *name,
+                          void *platinfo);
+
+int
+lws_netdev_wifi_rssi_sort_compare(const lws_dll2_t *d, const lws_dll2_t *i);
+void
+lws_netdev_wifi_scan_empty(lws_netdev_instance_wifi_t *wnd);
+
+lws_wifi_sta_t *
+lws_netdev_wifi_scan_find(lws_netdev_instance_wifi_t *wnd, const char *ssid,
+                         const uint8_t *bssid);
+
+int
+lws_netdev_wifi_scan_select(lws_netdev_instance_wifi_t *wnd);
+
+lws_wifi_creds_t *
+lws_netdev_credentials_find(lws_netdevs_t *netdevs, const char *ssid,
+                           const uint8_t *bssid);
+
+int
+lws_netdev_wifi_redo_last(lws_netdev_instance_wifi_t *wnd);
+
+void
+lws_ntpc_trigger(struct lws_context *ctx);
+
+void
+lws_netdev_wifi_scan(lws_sorted_usec_list_t *sul);
+
+#define lws_netdevs_from_ndi(ni) \
+               lws_container_of((ni)->list.owner, lws_netdevs_t, owner)
+
+#define lws_context_from_netdevs(nd) \
+               lws_container_of(nd, struct lws_context, netdevs)
+
+/* get the owner of the ni, then compute the context the owner is embedded in */
+#define netdev_instance_to_ctx(ni) \
+               lws_container_of(lws_netdevs_from_ndi(ni), \
+                                struct lws_context, netdevs)
+
+enum {
+       LW5CHS_RET_RET0,
+       LW5CHS_RET_BAIL3,
+       LW5CHS_RET_STARTHS,
+       LW5CHS_RET_NOTHING
+};
+
+void
+lws_4to6(uint8_t *v6addr, const uint8_t *v4addr);
+void
+lws_sa46_4to6(lws_sockaddr46 *sa46, const uint8_t *v4addr, uint16_t port);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/lib/core-net/private.h b/lib/core-net/private.h
deleted file mode 100644 (file)
index 326e6ba..0000000
+++ /dev/null
@@ -1,1168 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#if !defined(__LWS_CORE_NET_PRIVATE_H__)
-#define __LWS_CORE_NET_PRIVATE_H__
-
-#if !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200112L
-#endif
-
-#include "roles/private.h"
-
-#ifdef LWS_WITH_IPV6
-#if defined(WIN32) || defined(_WIN32)
-#include <iphlpapi.h>
-#else
-#include <net/if.h>
-#endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * All lws_tls...() functions must return this type, converting the
- * native backend result and doing the extra work to determine which one
- * as needed.
- *
- * Native TLS backend return codes are NOT ALLOWED outside the backend.
- *
- * Non-SSL mode also uses these types.
- */
-enum lws_ssl_capable_status {
-       LWS_SSL_CAPABLE_ERROR                   = -1, /* it failed */
-       LWS_SSL_CAPABLE_DONE                    = 0,  /* it succeeded */
-       LWS_SSL_CAPABLE_MORE_SERVICE_READ       = -2, /* retry WANT_READ */
-       LWS_SSL_CAPABLE_MORE_SERVICE_WRITE      = -3, /* retry WANT_WRITE */
-       LWS_SSL_CAPABLE_MORE_SERVICE            = -4, /* general retry */
-};
-
-
-/*
- *
- *  ------ roles ------
- *
- */
-
-/* null-terminated array of pointers to roles lws built with */
-extern const struct lws_role_ops *available_roles[];
-
-#define LWS_FOR_EVERY_AVAILABLE_ROLE_START(xx) { \
-               const struct lws_role_ops **ppxx = available_roles; \
-               while (*ppxx) { \
-                       const struct lws_role_ops *xx = *ppxx++;
-
-#define LWS_FOR_EVERY_AVAILABLE_ROLE_END }}
-
-/*
- *
- *  ------ event_loop ops ------
- *
- */
-
-/* enums of socks version */
-enum socks_version {
-       SOCKS_VERSION_4 = 4,
-       SOCKS_VERSION_5 = 5
-};
-
-/* enums of subnegotiation version */
-enum socks_subnegotiation_version {
-       SOCKS_SUBNEGOTIATION_VERSION_1 = 1,
-};
-
-/* enums of socks commands */
-enum socks_command {
-       SOCKS_COMMAND_CONNECT = 1,
-       SOCKS_COMMAND_BIND = 2,
-       SOCKS_COMMAND_UDP_ASSOCIATE = 3
-};
-
-/* enums of socks address type */
-enum socks_atyp {
-       SOCKS_ATYP_IPV4 = 1,
-       SOCKS_ATYP_DOMAINNAME = 3,
-       SOCKS_ATYP_IPV6 = 4
-};
-
-/* enums of socks authentication methods */
-enum socks_auth_method {
-       SOCKS_AUTH_NO_AUTH = 0,
-       SOCKS_AUTH_GSSAPI = 1,
-       SOCKS_AUTH_USERNAME_PASSWORD = 2
-};
-
-/* enums of subnegotiation status */
-enum socks_subnegotiation_status {
-       SOCKS_SUBNEGOTIATION_STATUS_SUCCESS = 0,
-};
-
-/* enums of socks request reply */
-enum socks_request_reply {
-       SOCKS_REQUEST_REPLY_SUCCESS = 0,
-       SOCKS_REQUEST_REPLY_FAILURE_GENERAL = 1,
-       SOCKS_REQUEST_REPLY_CONNECTION_NOT_ALLOWED = 2,
-       SOCKS_REQUEST_REPLY_NETWORK_UNREACHABLE = 3,
-       SOCKS_REQUEST_REPLY_HOST_UNREACHABLE = 4,
-       SOCKS_REQUEST_REPLY_CONNECTION_REFUSED = 5,
-       SOCKS_REQUEST_REPLY_TTL_EXPIRED = 6,
-       SOCKS_REQUEST_REPLY_COMMAND_NOT_SUPPORTED = 7,
-       SOCKS_REQUEST_REPLY_ATYP_NOT_SUPPORTED = 8
-};
-
-/* enums used to generate socks messages */
-enum socks_msg_type {
-       /* greeting */
-       SOCKS_MSG_GREETING,
-       /* credential, user name and password */
-       SOCKS_MSG_USERNAME_PASSWORD,
-       /* connect command */
-       SOCKS_MSG_CONNECT
-};
-
-enum {
-       LWS_RXFLOW_ALLOW = (1 << 0),
-       LWS_RXFLOW_PENDING_CHANGE = (1 << 1),
-};
-
-enum lws_parser_return {
-       LPR_OK          = 0,
-       LPR_FAIL        = -1,
-       LPR_DO_FALLBACK = 2,
-       LPR_FORBIDDEN   = -2
-};
-
-enum pmd_return {
-       PMDR_UNKNOWN,
-       PMDR_DID_NOTHING,
-       PMDR_HAS_PENDING,
-       PMDR_EMPTY_NONFINAL,
-       PMDR_EMPTY_FINAL,
-
-       PMDR_FAILED = -1
-};
-
-typedef union {
-#ifdef LWS_WITH_IPV6
-       struct sockaddr_in6 sa6;
-#endif
-       struct sockaddr_in sa4;
-} sockaddr46;
-
-
-#if defined(LWS_WITH_PEER_LIMITS)
-struct lws_peer {
-       struct lws_peer *next;
-       struct lws_peer *peer_wait_list;
-
-       time_t time_created;
-       time_t time_closed_all;
-
-       uint8_t addr[32];
-       uint32_t hash;
-       uint32_t count_wsi;
-       uint32_t total_wsi;
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       struct lws_peer_role_http http;
-#endif
-
-       uint8_t af;
-};
-#endif
-
-enum {
-       LWS_EV_READ = (1 << 0),
-       LWS_EV_WRITE = (1 << 1),
-       LWS_EV_START = (1 << 2),
-       LWS_EV_STOP = (1 << 3),
-
-       LWS_EV_PREPARE_DELETION = (1u << 31),
-};
-
-#ifdef LWS_WITH_IPV6
-#define LWS_IPV6_ENABLED(vh) \
-       (!lws_check_opt(vh->context->options, LWS_SERVER_OPTION_DISABLE_IPV6) && \
-        !lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_IPV6))
-#else
-#define LWS_IPV6_ENABLED(context) (0)
-#endif
-
-#ifdef LWS_WITH_UNIX_SOCK
-#define LWS_UNIX_SOCK_ENABLED(vhost) \
-       (vhost->options & LWS_SERVER_OPTION_UNIX_SOCK)
-#else
-#define LWS_UNIX_SOCK_ENABLED(vhost) (0)
-#endif
-
-enum uri_path_states {
-       URIPS_IDLE,
-       URIPS_SEEN_SLASH,
-       URIPS_SEEN_SLASH_DOT,
-       URIPS_SEEN_SLASH_DOT_DOT,
-};
-
-enum uri_esc_states {
-       URIES_IDLE,
-       URIES_SEEN_PERCENT,
-       URIES_SEEN_PERCENT_H1,
-};
-
-
-#ifndef LWS_NO_CLIENT
-struct client_info_stash {
-       char *address;
-       char *path;
-       char *host;
-       char *origin;
-       char *protocol;
-       char *method;
-       char *iface;
-       char *alpn;
-       void *opaque_user_data; /* not allocated or freed by lws */
-};
-#endif
-
-#define lws_wsi_is_udp(___wsi) (!!___wsi->udp)
-
-#define LWS_H2_FRAME_HEADER_LENGTH 9
-
-int
-__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul,
-                lws_usec_t us);
-
-lws_usec_t
-__lws_sul_service_ripe(lws_dll2_owner_t *own, lws_usec_t usnow);
-
-struct lws_timed_vh_protocol {
-       struct lws_timed_vh_protocol    *next;
-       lws_sorted_usec_list_t          sul;
-       const struct lws_protocols      *protocol;
-       struct lws_vhost *vhost; /* only used for pending processing */
-       int                             reason;
-       int                             tsi_req;
-};
-
-/*
- * lws_dsh
-*/
-
-typedef struct lws_dsh_obj_head {
-       lws_dll2_owner_t                owner;
-       int                             kind;
-} lws_dsh_obj_head_t;
-
-typedef struct lws_dsh_obj {
-       lws_dll2_t                      list;   /* must be first */
-       lws_dsh_t                       *dsh;   /* invalid when on free list */
-       size_t                          size;   /* invalid when on free list */
-       size_t                          asize;
-} lws_dsh_obj_t;
-
-struct lws_dsh {
-       lws_dll2_t                      list;
-       uint8_t                         *buf;
-       lws_dsh_obj_head_t              *oha;   /* array of object heads/kind */
-       size_t                          buffer_size;
-       size_t                          locally_in_use;
-       size_t                          locally_free;
-       int                             count_kinds;
-       uint8_t                         being_destroyed;
-       /*
-        * Overallocations at create:
-        *
-        *  - the buffer itself
-        *  - the object heads array
-        */
-};
-
-/*
- * so we can have n connections being serviced simultaneously,
- * these things need to be isolated per-thread.
- */
-
-struct lws_context_per_thread {
-#if LWS_MAX_SMP > 1
-       pthread_mutex_t lock_stats;
-       struct lws_mutex_refcount mr;
-       pthread_t self;
-#endif
-       struct lws_dll2_owner dll_buflist_owner;  /* guys with pending rxflow */
-       struct lws_dll2_owner seq_owner;           /* list of lws_sequencer-s */
-
-       struct lws_dll2_owner pt_sul_owner;
-
-#if defined (LWS_WITH_SEQUENCER)
-       lws_sorted_usec_list_t sul_seq_heartbeat;
-#endif
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       lws_sorted_usec_list_t sul_ah_lifecheck;
-#endif
-#if defined(LWS_WITH_TLS) && !defined(LWS_NO_SERVER)
-       lws_sorted_usec_list_t sul_tls;
-#endif
-#if defined(LWS_PLAT_UNIX)
-       lws_sorted_usec_list_t sul_plat;
-#endif
-#if defined(LWS_WITH_STATS)
-       uint64_t lws_stats[LWSSTATS_SIZE];
-       int updated;
-       lws_sorted_usec_list_t sul_stats;
-#endif
-#if defined(LWS_WITH_PEER_LIMITS)
-       lws_sorted_usec_list_t sul_peer_limits;
-#endif
-
-#if defined(LWS_WITH_TLS)
-       struct lws_pt_tls tls;
-#endif
-       struct lws *fake_wsi;   /* used for callbacks where there's no wsi */
-
-       struct lws_context *context;
-
-       /*
-        * usable by anything in the service code, but only if the scope
-        * does not last longer than the service action (since next service
-        * of any socket can likewise use it and overwrite)
-        */
-       unsigned char *serv_buf;
-
-       struct lws_pollfd *fds;
-       volatile struct lws_foreign_thread_pollfd * volatile foreign_pfd_list;
-#ifdef _WIN32
-       WSAEVENT events;
-       CRITICAL_SECTION interrupt_lock;
-#endif
-       lws_sockfd_type dummy_pipe_fds[2];
-       struct lws *pipe_wsi;
-
-       /* --- role based members --- */
-
-#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
-       struct lws_pt_role_ws ws;
-#endif
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       struct lws_pt_role_http http;
-#endif
-#if defined(LWS_ROLE_DBUS)
-       struct lws_pt_role_dbus dbus;
-#endif
-
-       /* --- event library based members --- */
-
-#if defined(LWS_WITH_LIBEV)
-       struct lws_pt_eventlibs_libev ev;
-#endif
-#if defined(LWS_WITH_LIBUV)
-       struct lws_pt_eventlibs_libuv uv;
-#endif
-#if defined(LWS_WITH_LIBEVENT)
-       struct lws_pt_eventlibs_libevent event;
-#endif
-
-#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \
-    defined(LWS_WITH_LIBEVENT)
-       struct lws_signal_watcher w_sigint;
-#endif
-
-       /* --- */
-
-       unsigned long count_conns;
-       unsigned int fds_count;
-
-       /*
-        * set to the Thread ID that's doing the service loop just before entry
-        * to poll indicates service thread likely idling in poll()
-        * volatile because other threads may check it as part of processing
-        * for pollfd event change.
-        */
-       volatile int service_tid;
-       int service_tid_detected;
-
-       volatile unsigned char inside_poll;
-       volatile unsigned char foreign_spinlock;
-
-       unsigned char tid;
-
-       unsigned char inside_service:1;
-       unsigned char event_loop_foreign:1;
-       unsigned char event_loop_destroy_processing_done:1;
-#ifdef _WIN32
-       unsigned char interrupt_requested:1;
-#endif
-};
-
-struct lws_conn_stats {
-       unsigned long long rx, tx;
-       unsigned long h1_conn, h1_trans, h2_trans, ws_upg, h2_alpn, h2_subs,
-                     h2_upg, rejected;
-};
-
-/*
- * virtual host -related context information
- *   vhostwide SSL context
- *   vhostwide proxy
- *
- * hierarchy:
- *
- * context -> vhost -> wsi
- *
- * incoming connection non-SSL vhost binding:
- *
- *    listen socket -> wsi -> select vhost after first headers
- *
- * incoming connection SSL vhost binding:
- *
- *    SSL SNI -> wsi -> bind after SSL negotiation
- */
-
-
-struct lws_vhost {
-#if !defined(LWS_WITHOUT_CLIENT)
-       char proxy_basic_auth_token[128];
-#endif
-#if LWS_MAX_SMP > 1
-       pthread_mutex_t lock;
-       char close_flow_vs_tsi[LWS_MAX_SMP];
-#endif
-
-#if defined(LWS_ROLE_H2)
-       struct lws_vhost_role_h2 h2;
-#endif
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       struct lws_vhost_role_http http;
-#endif
-#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
-       struct lws_vhost_role_ws ws;
-#endif
-
-#if defined(LWS_WITH_SOCKS5)
-       char socks_proxy_address[128];
-       char socks_user[96];
-       char socks_password[96];
-#endif
-#if defined(LWS_WITH_LIBEV)
-       struct lws_io_watcher w_accept;
-#endif
-       struct lws_conn_stats conn_stats;
-       struct lws_context *context;
-       struct lws_vhost *vhost_next;
-
-       struct lws *lserv_wsi;
-       const char *name;
-       const char *iface;
-       const char *listen_accept_role;
-       const char *listen_accept_protocol;
-       const char *unix_socket_perms;
-
-       void (*finalize)(struct lws_vhost *vh, void *arg);
-       void *finalize_arg;
-
-#if !defined(LWS_WITH_ESP32) && !defined(OPTEE_TA) && !defined(WIN32)
-       int bind_iface;
-#endif
-       const struct lws_protocols *protocols;
-       void **protocol_vh_privs;
-       const struct lws_protocol_vhost_options *pvo;
-       const struct lws_protocol_vhost_options *headers;
-       struct lws_dll2_owner *same_vh_protocol_owner;
-       struct lws_vhost *no_listener_vhost_list;
-       struct lws_dll2_owner abstract_instances_owner;
-
-#if !defined(LWS_NO_CLIENT)
-       struct lws_dll2_owner dll_cli_active_conns_owner;
-#endif
-
-#if defined(LWS_WITH_TLS)
-       struct lws_vhost_tls tls;
-#endif
-
-       struct lws_timed_vh_protocol *timed_vh_protocol_list;
-       void *user;
-
-       int listen_port;
-
-#if defined(LWS_WITH_SOCKS5)
-       unsigned int socks_proxy_port;
-#endif
-       unsigned int options;
-       int count_protocols;
-       int ka_time;
-       int ka_probes;
-       int ka_interval;
-       int keepalive_timeout;
-       int timeout_secs_ah_idle;
-
-       int count_bound_wsi;
-
-#ifdef LWS_WITH_ACCESS_LOG
-       int log_fd;
-#endif
-
-       unsigned int allocated_vhost_protocols:1;
-       unsigned int created_vhost_protocols:1;
-       unsigned int being_destroyed:1;
-
-       unsigned char default_protocol_index;
-       unsigned char raw_protocol_index;
-};
-
-void
-__lws_vhost_destroy2(struct lws_vhost *vh);
-
-struct lws {
-       /* structs */
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       struct _lws_http_mode_related http;
-#endif
-#if defined(LWS_ROLE_H2)
-       struct _lws_h2_related h2;
-#endif
-#if defined(LWS_ROLE_WS)
-       struct _lws_websocket_related *ws; /* allocated if we upgrade to ws */
-       lws_sorted_usec_list_t sul_ping;
-#endif
-#if defined(LWS_ROLE_DBUS)
-       struct _lws_dbus_mode_related dbus;
-#endif
-
-
-       const struct lws_role_ops *role_ops;
-       lws_wsi_state_t wsistate;
-       lws_wsi_state_t wsistate_pre_close;
-
-       /* lifetime members */
-
-#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \
-    defined(LWS_WITH_LIBEVENT)
-       struct lws_io_watcher w_read;
-#endif
-#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBEVENT)
-       struct lws_io_watcher w_write;
-#endif
-
-       lws_sorted_usec_list_t sul_timeout;
-       lws_sorted_usec_list_t sul_hrtimer;
-
-       /* pointers */
-
-       struct lws_context *context;
-       struct lws_vhost *vhost;
-       struct lws *parent; /* points to parent, if any */
-       struct lws *child_list; /* points to first child */
-       struct lws *sibling_list; /* subsequent children at same level */
-
-       const struct lws_protocols *protocol;
-       struct lws_dll2 same_vh_protocol;
-
-       lws_seq_t *seq; /* associated sequencer if any */
-
-       struct lws_dll2 dll_buflist; /* guys with pending rxflow */
-
-#if defined(LWS_WITH_THREADPOOL)
-       struct lws_threadpool_task *tp_task;
-#endif
-
-#if defined(LWS_WITH_PEER_LIMITS)
-       struct lws_peer *peer;
-#endif
-
-       struct lws_udp *udp;
-#ifndef LWS_NO_CLIENT
-       struct client_info_stash *stash;
-       char *cli_hostname_copy;
-       struct lws_dll2 dll_cli_active_conns;
-       struct lws_dll2_owner dll2_cli_txn_queue_owner;
-       struct lws_dll2 dll2_cli_txn_queue;
-#endif
-       void *user_space;
-       void *opaque_parent_data;
-       void *opaque_user_data;
-
-       struct lws_buflist *buflist;            /* input-side buflist */
-       struct lws_buflist *buflist_out;        /* output-side buflist */
-
-#if defined(LWS_WITH_TLS)
-       struct lws_lws_tls tls;
-#endif
-
-       lws_sock_file_fd_type desc; /* .filefd / .sockfd */
-#if defined(LWS_WITH_STATS)
-       uint64_t active_writable_req_us;
-#if defined(LWS_WITH_TLS)
-       uint64_t accept_start_us;
-#endif
-#endif
-
-#ifdef LWS_LATENCY
-       unsigned long action_start;
-       unsigned long latency_start;
-#endif
-
-       /* ints */
-#define LWS_NO_FDS_POS (-1)
-       int position_in_fds_table;
-
-#ifndef LWS_NO_CLIENT
-       int chunk_remaining;
-#endif
-       unsigned int cache_secs;
-
-       unsigned int hdr_parsing_completed:1;
-       unsigned int http2_substream:1;
-       unsigned int upgraded_to_http2:1;
-       unsigned int h2_stream_carries_ws:1;
-       unsigned int h2_stream_carries_sse:1;
-       unsigned int seen_nonpseudoheader:1;
-       unsigned int listener:1;
-       unsigned int user_space_externally_allocated:1;
-       unsigned int socket_is_permanently_unusable:1;
-       unsigned int rxflow_change_to:2;
-       unsigned int conn_stat_done:1;
-       unsigned int cache_reuse:1;
-       unsigned int cache_revalidate:1;
-       unsigned int cache_intermediaries:1;
-       unsigned int favoured_pollin:1;
-       unsigned int sending_chunked:1;
-       unsigned int interpreting:1;
-       unsigned int already_did_cce:1;
-       unsigned int told_user_closed:1;
-       unsigned int told_event_loop_closed:1;
-       unsigned int waiting_to_send_close_frame:1;
-       unsigned int close_needs_ack:1;
-       unsigned int ipv6:1;
-       unsigned int parent_pending_cb_on_writable:1;
-       unsigned int cgi_stdout_zero_length:1;
-       unsigned int seen_zero_length_recv:1;
-       unsigned int rxflow_will_be_applied:1;
-       unsigned int event_pipe:1;
-       unsigned int handling_404:1;
-       unsigned int protocol_bind_balance:1;
-       unsigned int unix_skt:1;
-       unsigned int close_when_buffered_out_drained:1;
-       unsigned int h1_ws_proxied;
-       unsigned int proxied_ws_parent;
-
-       unsigned int could_have_pending:1; /* detect back-to-back writes */
-       unsigned int outer_will_close:1;
-       unsigned int shadow:1; /* we do not control fd lifecycle at all */
-
-#ifdef LWS_WITH_ACCESS_LOG
-       unsigned int access_log_pending:1;
-#endif
-#ifndef LWS_NO_CLIENT
-       unsigned int do_ws:1; /* whether we are doing http or ws flow */
-       unsigned int chunked:1; /* if the clientside connection is chunked */
-       unsigned int client_rx_avail:1;
-       unsigned int client_http_body_pending:1;
-       unsigned int transaction_from_pipeline_queue:1;
-       unsigned int keepalive_active:1;
-       unsigned int keepalive_rejected:1;
-       unsigned int client_pipeline:1;
-       unsigned int client_h2_alpn:1;
-       unsigned int client_h2_substream:1;
-#endif
-
-#ifdef _WIN32
-       unsigned int sock_send_blocking:1;
-#endif
-
-#ifndef LWS_NO_CLIENT
-       unsigned short ocport, c_port;
-#endif
-
-       /* chars */
-
-       char lws_rx_parse_state; /* enum lws_rx_parse_state */
-       char rx_frame_type; /* enum lws_write_protocol */
-       char pending_timeout; /* enum pending_timeout */
-       char tsi; /* thread service index we belong to */
-       char protocol_interpret_idx;
-       char redirects;
-       uint8_t rxflow_bitmap;
-       uint8_t bound_vhost_index;
-#ifdef LWS_WITH_CGI
-       char cgi_channel; /* which of stdin/out/err */
-       char hdr_state;
-#endif
-#ifndef LWS_NO_CLIENT
-       char chunk_parser; /* enum lws_chunk_parser */
-#endif
-#if defined(LWS_WITH_CGI) || !defined(LWS_NO_CLIENT)
-       char reason_bf; /* internal writeable callback reason bitfield */
-#endif
-#if defined(LWS_WITH_STATS) && defined(LWS_WITH_TLS)
-       char seen_rx;
-#endif
-       uint8_t immortal_substream_count;
-       /* volatile to make sure code is aware other thread can change */
-       volatile char handling_pollout;
-       volatile char leave_pollout_active;
-#if LWS_MAX_SMP > 1
-       volatile char undergoing_init_from_other_pt;
-#endif
-
-};
-
-#define lws_is_flowcontrolled(w) (!!(wsi->rxflow_bitmap))
-
-void
-lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt);
-
-const struct lws_role_ops *
-lws_role_by_name(const char *name);
-
-LWS_EXTERN int
-lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
-               const char *iface, int ipv6_allowed);
-
-#if defined(LWS_WITH_IPV6)
-LWS_EXTERN unsigned long
-lws_get_addr_scope(const char *ipaddr);
-#endif
-
-LWS_EXTERN void
-lws_close_free_wsi(struct lws *wsi, enum lws_close_status, const char *caller);
-LWS_EXTERN void
-__lws_close_free_wsi(struct lws *wsi, enum lws_close_status, const char *caller);
-
-LWS_EXTERN void
-__lws_free_wsi(struct lws *wsi);
-
-#if LWS_MAX_SMP > 1
-
-static LWS_INLINE void
-lws_pt_mutex_init(struct lws_context_per_thread *pt)
-{
-       lws_mutex_refcount_init(&pt->mr);
-       pthread_mutex_init(&pt->lock_stats, NULL);
-}
-
-static LWS_INLINE void
-lws_pt_mutex_destroy(struct lws_context_per_thread *pt)
-{
-       pthread_mutex_destroy(&pt->lock_stats);
-       lws_mutex_refcount_destroy(&pt->mr);
-}
-
-#define lws_pt_lock(pt, reason) lws_mutex_refcount_lock(&pt->mr, reason)
-#define lws_pt_unlock(pt) lws_mutex_refcount_unlock(&pt->mr)
-
-static LWS_INLINE void
-lws_pt_stats_lock(struct lws_context_per_thread *pt)
-{
-       pthread_mutex_lock(&pt->lock_stats);
-}
-
-static LWS_INLINE void
-lws_pt_stats_unlock(struct lws_context_per_thread *pt)
-{
-       pthread_mutex_unlock(&pt->lock_stats);
-}
-#endif
-
-/*
- * EXTENSIONS
- */
-
-#if defined(LWS_WITHOUT_EXTENSIONS)
-#define lws_any_extension_handled(_a, _b, _c, _d) (0)
-#define lws_ext_cb_active(_a, _b, _c, _d) (0)
-#define lws_ext_cb_all_exts(_a, _b, _c, _d, _e) (0)
-#define lws_issue_raw_ext_access lws_issue_raw
-#define lws_context_init_extensions(_a, _b)
-#endif
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_client_interpret_server_handshake(struct lws *wsi);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ws_rx_sm(struct lws *wsi, char already_processed, unsigned char c);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len);
-
-LWS_EXTERN void
-lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state,
-                   const struct lws_role_ops *ops);
-
-int
-lws_http_to_fallback(struct lws *wsi, unsigned char *buf, size_t len);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-user_callback_handle_rxflow(lws_callback_function, struct lws *wsi,
-                           enum lws_callback_reasons reason, void *user,
-                           void *in, size_t len);
-
-LWS_EXTERN int
-lws_plat_set_nonblocking(int fd);
-
-LWS_EXTERN int
-lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd,
-                           int unix_skt);
-
-LWS_EXTERN int
-lws_plat_check_connection_error(struct lws *wsi);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_header_table_attach(struct lws *wsi, int autoservice);
-
-LWS_EXTERN int
-lws_header_table_detach(struct lws *wsi, int autoservice);
-LWS_EXTERN int
-__lws_header_table_detach(struct lws *wsi, int autoservice);
-
-LWS_EXTERN void
-lws_header_table_reset(struct lws *wsi, int autoservice);
-
-void
-__lws_header_table_reset(struct lws *wsi, int autoservice);
-
-LWS_EXTERN char * LWS_WARN_UNUSED_RESULT
-lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ensure_user_space(struct lws *wsi);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_change_pollfd(struct lws *wsi, int _and, int _or);
-
-#ifndef LWS_NO_SERVER
- int _lws_vhost_init_server(const struct lws_context_creation_info *info,
-                             struct lws_vhost *vhost);
- LWS_EXTERN struct lws_vhost *
- lws_select_vhost(struct lws_context *context, int port, const char *servername);
- LWS_EXTERN int LWS_WARN_UNUSED_RESULT
- lws_parse_ws(struct lws *wsi, unsigned char **buf, size_t len);
- LWS_EXTERN void
- lws_server_get_canonical_hostname(struct lws_context *context,
-                                  const struct lws_context_creation_info *info);
-#else
- #define _lws_vhost_init_server(_a, _b) (0)
- #define lws_parse_ws(_a, _b, _c) (0)
- #define lws_server_get_canonical_hostname(_a, _b)
-#endif
-
-LWS_EXTERN int
-__remove_wsi_socket_from_fds(struct lws *wsi);
-
-enum {
-       LWSRXFC_ERROR = -1,
-       LWSRXFC_CACHED = 0,
-       LWSRXFC_ADDITIONAL = 1,
-       LWSRXFC_TRIMMED = 2,
-};
-
-
-int
-_lws_plat_service_forced_tsi(struct lws_context *context, int tsi);
-
-LWS_EXTERN int
-lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len);
-
-LWS_EXTERN int
-lws_service_flag_pending(struct lws_context *context, int tsi);
-
-LWS_EXTERN void
-lws_client_stash_destroy(struct lws *wsi);
-
-static LWS_INLINE int
-lws_has_buffered_out(struct lws *wsi) { return !!wsi->buflist_out; }
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ws_client_rx_sm(struct lws *wsi, unsigned char c);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_parse(struct lws *wsi, unsigned char *buf, int *len);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_parse_urldecode(struct lws *wsi, uint8_t *_c);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_http_action(struct lws *wsi);
-
-LWS_EXTERN void
-__lws_close_free_wsi_final(struct lws *wsi);
-LWS_EXTERN void
-lws_libuv_closehandle(struct lws *wsi);
-LWS_EXTERN int
-lws_libuv_check_watcher_active(struct lws *wsi);
-
-LWS_VISIBLE LWS_EXTERN int
-lws_plat_plugins_init(struct lws_context * context, const char * const *d);
-
-LWS_VISIBLE LWS_EXTERN int
-lws_plat_plugins_destroy(struct lws_context * context);
-
-LWS_EXTERN void
-lws_restart_ws_ping_pong_timer(struct lws *wsi);
-
-struct lws *
-lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
-
-void
-lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi);
-void
-lws_vhost_unbind_wsi(struct lws *wsi);
-
-void
-__lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
-int
-__lws_change_pollfd(struct lws *wsi, int _and, int _or);
-
-
-int
-lws_callback_as_writeable(struct lws *wsi);
-
-int
-lws_role_call_client_bind(struct lws *wsi,
-                         const struct lws_client_connect_info *i);
-void
-lws_remove_child_from_any_parent(struct lws *wsi);
-
-char *
-lws_generate_client_ws_handshake(struct lws *wsi, char *p, const char *conn1);
-int
-lws_client_ws_upgrade(struct lws *wsi, const char **cce);
-int
-lws_create_client_ws_object(const struct lws_client_connect_info *i,
-                           struct lws *wsi);
-int
-lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len);
-int
-lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn);
-int
-lws_tls_server_conn_alpn(struct lws *wsi);
-
-int
-lws_ws_client_rx_sm_block(struct lws *wsi, unsigned char **buf, size_t len);
-void
-lws_destroy_event_pipe(struct lws *wsi);
-
-/* socks */
-int
-socks_generate_msg(struct lws *wsi, enum socks_msg_type type, ssize_t *msg_len);
-
-
-void
-lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs);
-
-LWS_EXTERN int
-__lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-__insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len);
-
-LWS_EXTERN lws_usec_t
-__lws_seq_timeout_check(struct lws_context_per_thread *pt, lws_usec_t usnow);
-
-LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
-lws_client_connect_2(struct lws *wsi);
-
-LWS_VISIBLE struct lws * LWS_WARN_UNUSED_RESULT
-lws_client_reset(struct lws **wsi, int ssl, const char *address, int port,
-                const char *path, const char *host);
-
-LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
-lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi);
-
-LWS_EXTERN char * LWS_WARN_UNUSED_RESULT
-lws_generate_client_handshake(struct lws *wsi, char *pkt);
-
-LWS_EXTERN int
-lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd);
-
-LWS_EXTERN struct lws *
-lws_http_client_connect_via_info2(struct lws *wsi);
-
-
-#ifndef LWS_NO_CLIENT
-LWS_EXTERN int lws_client_socket_service(struct lws *wsi,
-                                        struct lws_pollfd *pollfd,
-                                        struct lws *wsi_conn);
-LWS_EXTERN struct lws *
-lws_client_wsi_effective(struct lws *wsi);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_http_transaction_completed_client(struct lws *wsi);
-#if !defined(LWS_WITH_TLS)
-       #define lws_context_init_client_ssl(_a, _b) (0)
-#endif
-LWS_EXTERN void
-lws_decode_ssl_error(void);
-#else
-#define lws_context_init_client_ssl(_a, _b) (0)
-#endif
-
-LWS_EXTERN int
-__lws_rx_flow_control(struct lws *wsi);
-
-LWS_EXTERN int
-_lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa);
-
-#ifndef LWS_NO_SERVER
-LWS_EXTERN int
-lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len);
-#else
-#define lws_server_socket_service(_b, _c) (0)
-#define lws_handshake_server(_a, _b, _c) (0)
-#endif
-
-#ifdef LWS_WITH_ACCESS_LOG
-LWS_EXTERN int
-lws_access_log(struct lws *wsi);
-LWS_EXTERN void
-lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int len, int meth);
-#else
-#define lws_access_log(_a)
-#endif
-
-LWS_EXTERN int
-lws_cgi_kill_terminated(struct lws_context_per_thread *pt);
-
-LWS_EXTERN void
-lws_cgi_remove_and_kill(struct lws *wsi);
-
-LWS_EXTERN void
-lws_plat_delete_socket_from_fds(struct lws_context *context,
-                               struct lws *wsi, int m);
-LWS_EXTERN void
-lws_plat_insert_socket_into_fds(struct lws_context *context,
-                               struct lws *wsi);
-
-LWS_EXTERN int
-lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi,
-                      struct lws_pollfd *pfd);
-
-
-int
-lws_plat_pipe_create(struct lws *wsi);
-int
-lws_plat_pipe_signal(struct lws *wsi);
-void
-lws_plat_pipe_close(struct lws *wsi);
-
-LWS_EXTERN void
-lws_add_wsi_to_draining_ext_list(struct lws *wsi);
-LWS_EXTERN void
-lws_remove_wsi_from_draining_ext_list(struct lws *wsi);
-LWS_EXTERN int
-lws_poll_listen_fd(struct lws_pollfd *fd);
-LWS_EXTERN int
-lws_plat_service(struct lws_context *context, int timeout_ms);
-LWS_EXTERN LWS_VISIBLE int
-_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi);
-
-LWS_EXTERN int
-lws_pthread_self_to_tsi(struct lws_context *context);
-LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT
-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_plat_inet_pton(int af, const char *src, void *dst);
-
-LWS_EXTERN void
-lws_same_vh_protocol_remove(struct lws *wsi);
-LWS_EXTERN void
-__lws_same_vh_protocol_remove(struct lws *wsi);
-LWS_EXTERN void
-lws_same_vh_protocol_insert(struct lws *wsi, int n);
-
-void
-lws_seq_destroy_all_on_pt(struct lws_context_per_thread *pt);
-
-LWS_EXTERN int
-lws_broadcast(struct lws_context_per_thread *pt, int reason, void *in, size_t len);
-
-#if defined(LWS_WITH_STATS)
- void
- lws_stats_bump(struct lws_context_per_thread *pt, int i, uint64_t bump);
- void
- lws_stats_max(struct lws_context_per_thread *pt, int index, uint64_t val);
-#else
- static LWS_INLINE uint64_t lws_stats_bump(
-               struct lws_context_per_thread *pt, int index, uint64_t bump) {
-       (void)pt; (void)index; (void)bump; return 0; }
- static LWS_INLINE uint64_t lws_stats_max(
-               struct lws_context_per_thread *pt, int index, uint64_t val) {
-       (void)pt; (void)index; (void)val; return 0; }
-#endif
-
-
-
-#if defined(LWS_WITH_PEER_LIMITS)
-void
-lws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer);
-int
-lws_peer_confirm_ah_attach_ok(struct lws_context *context,
-                             struct lws_peer *peer);
-void
-lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer);
-void
-lws_peer_cull_peer_wait_list(struct lws_context *context);
-struct lws_peer *
-lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd);
-void
-lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,
-                struct lws *wsi);
-void
-lws_peer_dump_from_wsi(struct lws *wsi);
-#endif
-
-#ifdef LWS_WITH_HUBBUB
-hubbub_error
-html_parser_cb(const hubbub_token *token, void *pw);
-#endif
-
-int
-lws_threadpool_tsi_context(struct lws_context *context, int tsi);
-
-void
-__lws_wsi_remove_from_sul(struct lws *wsi);
-
-int
-lws_seq_pt_init(struct lws_context_per_thread *pt);
-
-int
-lws_buflist_aware_read(struct lws_context_per_thread *pt, struct lws *wsi,
-                      struct lws_tokens *ebuf);
-int
-lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
-                         int buffered);
-
-extern const struct lws_protocols protocol_abs_client_raw_skt,
-                                 protocol_abs_client_unit_test;
-
-void
-lws_inform_client_conn_fail(struct lws *wsi, void *arg, size_t len);
-
-#ifdef __cplusplus
-};
-#endif
-
-#endif
diff --git a/lib/core-net/route.c b/lib/core-net/route.c
new file mode 100644 (file)
index 0000000..2a85152
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * We mainly focus on the routing table / gateways because those are the
+ * elements that decide if we can get on to the internet or not.
+ *
+ * Everything here is _ because the caller needs to hold the pt lock in order
+ * to access the pt routing table safely
+ */
+
+#include <private-lib-core.h>
+
+#if defined(_DEBUG)
+
+
+
+void
+_lws_routing_entry_dump(struct lws_context *cx, lws_route_t *rou)
+{
+       char sa[48], fin[192], *end = &fin[sizeof(fin)];
+
+       fin[0] = '\0';
+
+       if (rou->dest.sa4.sin_family) {
+               lws_sa46_write_numeric_address(&rou->dest, sa, sizeof(sa));
+               lws_snprintf(fin, lws_ptr_diff_size_t(end, fin),
+                                 "dst: %s/%d, ", sa, rou->dest_len);
+       }
+
+       if (rou->src.sa4.sin_family) {
+               lws_sa46_write_numeric_address(&rou->src, sa, sizeof(sa));
+               lws_snprintf(fin, lws_ptr_diff_size_t(end, fin),
+                                 "src: %s/%d, ", sa, rou->src_len);
+       }
+
+       if (rou->gateway.sa4.sin_family) {
+               lws_sa46_write_numeric_address(&rou->gateway, sa, sizeof(sa));
+               lws_snprintf(fin, lws_ptr_diff_size_t(end, fin),
+                                 "gw: %s, ", sa);
+       }
+
+       lwsl_cx_info(cx, " %s ifidx: %d, pri: %d, proto: %d\n", fin,
+                 rou->if_idx, rou->priority, rou->proto);
+}
+
+void
+_lws_routing_table_dump(struct lws_context *cx)
+{
+       lwsl_cx_info(cx, "\n");
+       lws_start_foreach_dll(struct lws_dll2 *, d,
+                             lws_dll2_get_head(&cx->routing_table)) {
+               lws_route_t *rou = lws_container_of(d, lws_route_t, list);
+
+               _lws_routing_entry_dump(cx, rou);
+       } lws_end_foreach_dll(d);
+}
+#endif
+
+/*
+ * We will provide a "fingerprint ordinal" as the route uidx that is unique in
+ * the routing table.  Wsi that connect mark themselves with the uidx of the
+ * route they are estimated to be using.
+ *
+ * This lets us detect things like gw changes, eg when switching from wlan to
+ * lte there may still be a valid gateway route, but all existing tcp
+ * connections previously using the wlan gateway will be broken, since their
+ * connections are from its gateway to the peer.
+ *
+ * So when we take down a route, we take care to look for any wsi that was
+ * estimated to be using that route, eg, for gateway, and close those wsi.
+ *
+ * It's OK if the route uidx wraps, we explicitly confirm nobody else is using
+ * the uidx before assigning one to a new route.
+ *
+ * We won't use uidx 0, so it can be understood to mean the uidx was never set.
+ */
+
+lws_route_uidx_t
+_lws_route_get_uidx(struct lws_context *cx)
+{
+       uint8_t ou;
+
+       if (!cx->route_uidx)
+               cx->route_uidx++;
+
+       ou = cx->route_uidx;
+
+       do {
+               uint8_t again = 0;
+
+               /* Anybody in the table already uses the pt's next uidx? */
+
+               lws_start_foreach_dll(struct lws_dll2 *, d,
+                                     lws_dll2_get_head(&cx->routing_table)) {
+                       lws_route_t *rou = lws_container_of(d, lws_route_t, list);
+
+                       if (rou->uidx == cx->route_uidx) {
+                               /* if so, bump and restart the check */
+                               cx->route_uidx++;
+                               if (!cx->route_uidx)
+                                       cx->route_uidx++;
+                               if (cx->route_uidx == ou) {
+                                       assert(0); /* we have filled up the 8-bit uidx space? */
+                                       return 0;
+                               }
+                               again = 1;
+                               break;
+                       }
+               } lws_end_foreach_dll(d);
+
+               if (!again)
+                       return cx->route_uidx++;
+       } while (1);
+}
+
+lws_route_t *
+_lws_route_remove(struct lws_context_per_thread *pt, lws_route_t *robj, int flags)
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                             lws_dll2_get_head(&pt->context->routing_table)) {
+               lws_route_t *rou = lws_container_of(d, lws_route_t, list);
+
+               if ((!(flags & LRR_MATCH_SRC) || !lws_sa46_compare_ads(&robj->src, &rou->src)) &&
+                   ((flags & LRR_MATCH_SRC) || !lws_sa46_compare_ads(&robj->dest, &rou->dest)) &&
+                   (!robj->gateway.sa4.sin_family ||
+                    !lws_sa46_compare_ads(&robj->gateway, &rou->gateway)) &&
+                   robj->dest_len <= rou->dest_len &&
+                   robj->if_idx == rou->if_idx &&
+                   ((flags & LRR_IGNORE_PRI) ||
+                     robj->priority == rou->priority)
+                   ) {
+                       if (flags & LRR_JUST_CHECK)
+                               return rou;
+                       lwsl_cx_info(pt->context, "deleting route");
+                       _lws_route_pt_close_route_users(pt, robj->uidx);
+                       lws_dll2_remove(&rou->list);
+                       lws_free(rou);
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       return NULL;
+}
+
+void
+_lws_route_table_empty(struct lws_context_per_thread *pt)
+{
+
+       if (!pt->context)
+               return;
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  lws_dll2_get_head(&pt->context->routing_table)) {
+               lws_route_t *rou = lws_container_of(d, lws_route_t, list);
+
+               lws_dll2_remove(&rou->list);
+               lws_free(rou);
+
+       } lws_end_foreach_dll_safe(d, d1);
+}
+
+void
+_lws_route_table_ifdown(struct lws_context_per_thread *pt, int idx)
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  lws_dll2_get_head(&pt->context->routing_table)) {
+               lws_route_t *rou = lws_container_of(d, lws_route_t, list);
+
+               if (rou->if_idx == idx) {
+                       lws_dll2_remove(&rou->list);
+                       lws_free(rou);
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+}
+
+lws_route_t *
+_lws_route_est_outgoing(struct lws_context_per_thread *pt,
+                       const lws_sockaddr46 *dest)
+{
+       lws_route_t *best_gw = NULL;
+       int best_gw_priority = INT_MAX;
+
+       if (!dest->sa4.sin_family) {
+               lwsl_cx_notice(pt->context, "dest has 0 AF");
+               /* leave it alone */
+               return NULL;
+       }
+
+       /*
+        * Given the dest address and the current routing table, select the
+        * route we think it would go out on... if we find a matching network
+        * route, just return that, otherwise find the "best" gateway by
+        * looking at the priority of them.
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, d,
+                             lws_dll2_get_head(&pt->context->routing_table)) {
+               lws_route_t *rou = lws_container_of(d, lws_route_t, list);
+
+               // _lws_routing_entry_dump(rou);
+
+               if (rou->dest.sa4.sin_family &&
+                   !lws_sa46_on_net(dest, &rou->dest, rou->dest_len))
+                       /*
+                        * Yes, he has a matching network route, it beats out
+                        * any gateway route.  This is like finding a route for
+                        * 192.168.0.0/24 when dest is 192.168.0.1.
+                        */
+                       return rou;
+
+               lwsl_cx_debug(pt->context, "dest af %d, rou gw af %d, pri %d",
+                             dest->sa4.sin_family, rou->gateway.sa4.sin_family,
+                             rou->priority);
+
+               if (rou->gateway.sa4.sin_family &&
+
+                       /*
+                        *  dest  gw
+                        *   4     4    OK
+                        *   4     6    OK with ::ffff:x:x
+                        *   6     4    not supported directly
+                        *   6     6    OK
+                        */
+
+                   (dest->sa4.sin_family == rou->gateway.sa4.sin_family ||
+                       (dest->sa4.sin_family == AF_INET &&
+                        rou->gateway.sa4.sin_family == AF_INET6)) &&
+                   rou->priority < best_gw_priority) {
+                       lwsl_cx_info(pt->context, "gw hit");
+                       best_gw_priority = rou->priority;
+                       best_gw = rou;
+               }
+
+       } lws_end_foreach_dll(d);
+
+       /*
+        * Either best_gw is the best gw route and we set *best_gw_priority to
+        * the best one's priority, or we're returning NULL as no network or
+        * gw route for dest.
+        */
+
+       lwsl_cx_info(pt->context, "returning %p", best_gw);
+
+       return best_gw;
+}
+
+/*
+ * Determine if the source still exists
+ */
+
+lws_route_t *
+_lws_route_find_source(struct lws_context_per_thread *pt,
+                      const lws_sockaddr46 *src)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, d,
+                             lws_dll2_get_head(&pt->context->routing_table)) {
+               lws_route_t *rou = lws_container_of(d, lws_route_t, list);
+
+               // _lws_routing_entry_dump(rou);
+
+               if (rou->src.sa4.sin_family &&
+                   !lws_sa46_compare_ads(src, &rou->src))
+                       /*
+                        * Source route still exists
+                        */
+                       return rou;
+
+       } lws_end_foreach_dll(d);
+
+       return NULL;
+}
+
+int
+_lws_route_check_wsi(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       char buf[72];
+
+       if (!wsi->sa46_peer.sa4.sin_family ||
+#if defined(LWS_WITH_UNIX_SOCK)
+            wsi->unix_skt ||
+            wsi->sa46_peer.sa4.sin_family == AF_UNIX ||
+#endif
+           wsi->desc.sockfd == LWS_SOCK_INVALID)
+               /* not a socket, cannot judge by route, or not connected,
+                * leave it alone */
+               return 0; /* OK */
+
+       /* the route to the peer is still workable? */
+
+       if (!_lws_route_est_outgoing(pt, &wsi->sa46_peer)) {
+               /* no way to talk to the peer */
+               lwsl_wsi_notice(wsi, "dest route gone");
+               return 1;
+       }
+
+       /* the source address is still workable? */
+
+       lws_sa46_write_numeric_address(&wsi->sa46_local,
+                                      buf, sizeof(buf));
+       //lwsl_notice("%s: %s sa46_local %s fam %d\n", __func__, wsi->lc.gutag,
+       //              buf, wsi->sa46_local.sa4.sin_family);
+
+       if (wsi->sa46_local.sa4.sin_family &&
+           !_lws_route_find_source(pt, &wsi->sa46_local)) {
+
+               lws_sa46_write_numeric_address(&wsi->sa46_local,
+                                              buf, sizeof(buf));
+               lwsl_wsi_notice(wsi, "source %s gone", buf);
+
+               return 1;
+       }
+
+       lwsl_wsi_debug(wsi, "source + dest OK");
+
+       return 0;
+}
+
+int
+_lws_route_pt_close_unroutable(struct lws_context_per_thread *pt)
+{
+       struct lws *wsi;
+       unsigned int n;
+
+       if (!pt->context->nl_initial_done
+#if defined(LWS_WITH_SYS_STATE)
+                       ||
+           pt->context->mgr_system.state < LWS_SYSTATE_IFACE_COLDPLUG
+#endif
+       )
+               return 0;
+
+       lwsl_cx_debug(pt->context, "in");
+#if defined(_DEBUG)
+       _lws_routing_table_dump(pt->context);
+#endif
+
+       for (n = 0; n < pt->fds_count; n++) {
+               wsi = wsi_from_fd(pt->context, pt->fds[n].fd);
+               if (!wsi)
+                       continue;
+
+               if (_lws_route_check_wsi(wsi)) {
+                       lwsl_wsi_info(wsi, "culling wsi");
+                       lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
+               }
+       }
+
+       return 0;
+}
+
+int
+_lws_route_pt_close_route_users(struct lws_context_per_thread *pt,
+                               lws_route_uidx_t uidx)
+{
+       struct lws *wsi;
+       unsigned int n;
+
+       if (!uidx)
+               return 0;
+
+       lwsl_cx_info(pt->context, "closing users of route %d", uidx);
+
+       for (n = 0; n < pt->fds_count; n++) {
+               wsi = wsi_from_fd(pt->context, pt->fds[n].fd);
+               if (!wsi)
+                       continue;
+
+               if (wsi->desc.sockfd != LWS_SOCK_INVALID &&
+#if defined(LWS_WITH_UNIX_SOCK)
+                   !wsi->unix_skt &&
+                   wsi->sa46_peer.sa4.sin_family != AF_UNIX &&
+#endif
+                   wsi->sa46_peer.sa4.sin_family &&
+                   wsi->peer_route_uidx == uidx) {
+                       lwsl_wsi_notice(wsi, "culling wsi");
+                       lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
+               }
+       }
+
+       return 0;
+}
index 3ddf009..aa6a0cb 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * libwebsockets - lib/core-net/sequencer.c
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /*
  * per pending event
@@ -35,7 +38,7 @@ typedef struct lws_seq_event {
 /*
  * per sequencer
  */
-struct lws_sequencer {
+typedef struct lws_sequencer {
        struct lws_dll2                 seq_list;
 
        lws_sorted_usec_list_t          sul_timeout;
@@ -50,8 +53,9 @@ struct lws_sequencer {
        lws_usec_t                      time_created;
        lws_usec_t                      timeout; /* 0 or time we timeout */
 
-       char                            going_down;
-};
+       uint8_t                         going_down:1;
+       uint8_t                         wakesuspend:1;
+} lws_seq_t;
 
 #define QUEUE_SANITY_LIMIT 10
 
@@ -74,8 +78,8 @@ lws_sul_seq_heartbeat_cb(lws_sorted_usec_list_t *sul)
 
        /* schedule the next one */
 
-       __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_seq_heartbeat,
-                        LWS_US_PER_SEC);
+       __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                           &pt->sul_seq_heartbeat, LWS_US_PER_SEC);
 }
 
 int
@@ -84,8 +88,8 @@ lws_seq_pt_init(struct lws_context_per_thread *pt)
        pt->sul_seq_heartbeat.cb = lws_sul_seq_heartbeat_cb;
 
        /* schedule the first heartbeat */
-       __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_seq_heartbeat,
-                        LWS_US_PER_SEC);
+       __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                           &pt->sul_seq_heartbeat, LWS_US_PER_SEC);
 
        return 0;
 }
@@ -103,6 +107,7 @@ lws_seq_create(lws_seq_info_t *i)
        seq->pt = pt;
        seq->name = i->name;
        seq->retry = i->retry;
+       seq->wakesuspend = i->wakesuspend;
 
        *i->puser = (void *)&seq[1];
 
@@ -193,7 +198,7 @@ lws_seq_sul_pending_cb(lws_sorted_usec_list_t *sul)
        dh = lws_dll2_get_head(&seq->seq_event_owner);
        seqe = lws_container_of(dh, lws_seq_event_t, seq_event_list);
 
-       n = seq->cb(seq, (void *)&seq[1], seqe->e, seqe->data, seqe->aux);
+       n = (int)seq->cb(seq, (void *)&seq[1], (int)seqe->e, seqe->data, seqe->aux);
 
        /* ... have to lock here though, because we will change the list */
 
@@ -239,7 +244,8 @@ lws_seq_queue_event(lws_seq_t *seq, lws_seq_events_t e, void *data, void *aux)
        lws_dll2_add_tail(&seqe->seq_event_list, &seq->seq_event_owner);
 
        seq->sul_pending.cb = lws_seq_sul_pending_cb;
-       __lws_sul_insert(&seq->pt->pt_sul_owner, &seq->sul_pending, 1);
+       __lws_sul_insert_us(&seq->pt->pt_sul_owner[seq->wakesuspend],
+                           &seq->sul_pending, 1);
 
        lws_pt_unlock(seq->pt); /* } pt ------------------------------------- */
 
@@ -297,8 +303,10 @@ lws_seq_timeout_us(lws_seq_t *seq, lws_usec_t us)
 {
        seq->sul_timeout.cb = lws_seq_sul_timeout_cb;
        /* list is always at the very top of the sul */
-       return __lws_sul_insert(&seq->pt->pt_sul_owner,
+       __lws_sul_insert_us(&seq->pt->pt_sul_owner[seq->wakesuspend],
                        (lws_sorted_usec_list_t *)&seq->sul_timeout.list, us);
+
+       return 0;
 }
 
 lws_seq_t *
diff --git a/lib/core-net/server.c b/lib/core-net/server.c
deleted file mode 100644 (file)
index e64c034..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-#if defined(LWS_WITH_SERVER_STATUS)
-
-void
-lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs)
-{
-       const struct lws_vhost *vh = ctx->vhost_list;
-
-       while (vh) {
-
-               cs->rx += vh->conn_stats.rx;
-               cs->tx += vh->conn_stats.tx;
-               cs->h1_conn += vh->conn_stats.h1_conn;
-               cs->h1_trans += vh->conn_stats.h1_trans;
-               cs->h2_trans += vh->conn_stats.h2_trans;
-               cs->ws_upg += vh->conn_stats.ws_upg;
-               cs->h2_upg += vh->conn_stats.h2_upg;
-               cs->h2_alpn += vh->conn_stats.h2_alpn;
-               cs->h2_subs += vh->conn_stats.h2_subs;
-               cs->rejected += vh->conn_stats.rejected;
-
-               vh = vh->vhost_next;
-       }
-}
-
-LWS_EXTERN int
-lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
-{
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       static const char * const prots[] = {
-               "http://",
-               "https://",
-               "file://",
-               "cgi://",
-               ">http://",
-               ">https://",
-               "callback://"
-       };
-#endif
-       char *orig = buf, *end = buf + len - 1, first = 1;
-       int n = 0;
-
-       if (len < 100)
-               return 0;
-
-       buf += lws_snprintf(buf, end - buf,
-                       "{\n \"name\":\"%s\",\n"
-                       " \"port\":\"%d\",\n"
-                       " \"use_ssl\":\"%d\",\n"
-                       " \"sts\":\"%d\",\n"
-                       " \"rx\":\"%llu\",\n"
-                       " \"tx\":\"%llu\",\n"
-                       " \"h1_conn\":\"%lu\",\n"
-                       " \"h1_trans\":\"%lu\",\n"
-                       " \"h2_trans\":\"%lu\",\n"
-                       " \"ws_upg\":\"%lu\",\n"
-                       " \"rejected\":\"%lu\",\n"
-                       " \"h2_upg\":\"%lu\",\n"
-                       " \"h2_alpn\":\"%lu\",\n"
-                       " \"h2_subs\":\"%lu\""
-                       ,
-                       vh->name, vh->listen_port,
-#if defined(LWS_WITH_TLS)
-                       vh->tls.use_ssl & LCCSCF_USE_SSL,
-#else
-                       0,
-#endif
-                       !!(vh->options & LWS_SERVER_OPTION_STS),
-                       vh->conn_stats.rx, vh->conn_stats.tx,
-                       vh->conn_stats.h1_conn,
-                       vh->conn_stats.h1_trans,
-                       vh->conn_stats.h2_trans,
-                       vh->conn_stats.ws_upg,
-                       vh->conn_stats.rejected,
-                       vh->conn_stats.h2_upg,
-                       vh->conn_stats.h2_alpn,
-                       vh->conn_stats.h2_subs
-       );
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       if (vh->http.mount_list) {
-               const struct lws_http_mount *m = vh->http.mount_list;
-
-               buf += lws_snprintf(buf, end - buf, ",\n \"mounts\":[");
-               while (m) {
-                       if (!first)
-                               buf += lws_snprintf(buf, end - buf, ",");
-                       buf += lws_snprintf(buf, end - buf,
-                                       "\n  {\n   \"mountpoint\":\"%s\",\n"
-                                       "  \"origin\":\"%s%s\",\n"
-                                       "  \"cache_max_age\":\"%d\",\n"
-                                       "  \"cache_reuse\":\"%d\",\n"
-                                       "  \"cache_revalidate\":\"%d\",\n"
-                                       "  \"cache_intermediaries\":\"%d\"\n"
-                                       ,
-                                       m->mountpoint,
-                                       prots[m->origin_protocol],
-                                       m->origin,
-                                       m->cache_max_age,
-                                       m->cache_reusable,
-                                       m->cache_revalidate,
-                                       m->cache_intermediaries);
-                       if (m->def)
-                               buf += lws_snprintf(buf, end - buf,
-                                               ",\n  \"default\":\"%s\"",
-                                               m->def);
-                       buf += lws_snprintf(buf, end - buf, "\n  }");
-                       first = 0;
-                       m = m->mount_next;
-               }
-               buf += lws_snprintf(buf, end - buf, "\n ]");
-       }
-#endif
-       if (vh->protocols) {
-               n = 0;
-               first = 1;
-
-               buf += lws_snprintf(buf, end - buf, ",\n \"ws-protocols\":[");
-               while (n < vh->count_protocols) {
-                       if (!first)
-                               buf += lws_snprintf(buf, end - buf, ",");
-                       buf += lws_snprintf(buf, end - buf,
-                                       "\n  {\n   \"%s\":{\n"
-                                       "    \"status\":\"ok\"\n   }\n  }"
-                                       ,
-                                       vh->protocols[n].name);
-                       first = 0;
-                       n++;
-               }
-               buf += lws_snprintf(buf, end - buf, "\n ]");
-       }
-
-       buf += lws_snprintf(buf, end - buf, "\n}");
-
-       return buf - orig;
-}
-
-
-LWS_EXTERN LWS_VISIBLE int
-lws_json_dump_context(const struct lws_context *context, char *buf, int len,
-               int hide_vhosts)
-{
-       char *orig = buf, *end = buf + len - 1, first = 1;
-       const struct lws_vhost *vh = context->vhost_list;
-       const struct lws_context_per_thread *pt;
-       int n, listening = 0, cgi_count = 0, fd;
-       struct lws_conn_stats cs;
-       double d = 0;
-#ifdef LWS_WITH_CGI
-       struct lws_cgi * const *pcgi;
-#endif
-
-#ifdef LWS_WITH_LIBUV
-       uv_uptime(&d);
-#endif
-
-       buf += lws_snprintf(buf, end - buf, "{ "
-                           "\"version\":\"%s\",\n"
-                           "\"uptime\":\"%ld\",\n",
-                           lws_get_library_version(),
-                           (long)d);
-
-#ifdef LWS_HAVE_GETLOADAVG
-       {
-               double d[3];
-               int m;
-
-               m = getloadavg(d, 3);
-               for (n = 0; n < m; n++) {
-                       buf += lws_snprintf(buf, end - buf,
-                               "\"l%d\":\"%.2f\",\n",
-                               n + 1, d[n]);
-               }
-       }
-#endif
-
-       fd = lws_open("/proc/self/statm", LWS_O_RDONLY);
-       if (fd >= 0) {
-               char contents[96], pure[96];
-               n = read(fd, contents, sizeof(contents) - 1);
-               if (n > 0) {
-                       contents[n] = '\0';
-                       if (contents[n - 1] == '\n')
-                               contents[--n] = '\0';
-                       lws_json_purify(pure, contents, sizeof(pure));
-
-                       buf += lws_snprintf(buf, end - buf,
-                                         "\"statm\": \"%s\",\n", pure);
-               }
-               close(fd);
-       }
-
-       buf += lws_snprintf(buf, end - buf, "\"heap\":%lld,\n\"contexts\":[\n",
-                               (long long)lws_get_allocated_heap());
-
-       buf += lws_snprintf(buf, end - buf, "{ "
-                               "\"context_uptime\":\"%llu\",\n"
-                               "\"cgi_spawned\":\"%d\",\n"
-                               "\"pt_fd_max\":\"%d\",\n"
-                               "\"ah_pool_max\":\"%d\",\n"
-                               "\"deprecated\":\"%d\",\n"
-                               "\"wsi_alive\":\"%d\",\n",
-                               (unsigned long long)(lws_now_usecs() - context->time_up),
-                               context->count_cgi_spawned,
-                               context->fd_limit_per_thread,
-                               context->max_http_header_pool,
-                               context->deprecated,
-                               context->count_wsi_allocated);
-
-       buf += lws_snprintf(buf, end - buf, "\"pt\":[\n ");
-       for (n = 0; n < context->count_threads; n++) {
-               pt = &context->pt[n];
-               if (n)
-                       buf += lws_snprintf(buf, end - buf, ",");
-               buf += lws_snprintf(buf, end - buf,
-                               "\n  {\n"
-                               "    \"fds_count\":\"%d\",\n"
-                               "    \"ah_pool_inuse\":\"%d\",\n"
-                               "    \"ah_wait_list\":\"%d\"\n"
-                               "    }",
-                               pt->fds_count,
-                               pt->http.ah_count_in_use,
-                               pt->http.ah_wait_list_length);
-       }
-
-       buf += lws_snprintf(buf, end - buf, "]");
-
-       buf += lws_snprintf(buf, end - buf, ", \"vhosts\":[\n ");
-
-       first = 1;
-       vh = context->vhost_list;
-       listening = 0;
-       cs = context->conn_stats;
-       lws_sum_stats(context, &cs);
-       while (vh) {
-
-               if (!hide_vhosts) {
-                       if (!first)
-                               if(buf != end)
-                                       *buf++ = ',';
-                       buf += lws_json_dump_vhost(vh, buf, end - buf);
-                       first = 0;
-               }
-               if (vh->lserv_wsi)
-                       listening++;
-               vh = vh->vhost_next;
-       }
-
-       buf += lws_snprintf(buf, end - buf,
-                       "],\n\"listen_wsi\":\"%d\",\n"
-                       " \"rx\":\"%llu\",\n"
-                       " \"tx\":\"%llu\",\n"
-                       " \"h1_conn\":\"%lu\",\n"
-                       " \"h1_trans\":\"%lu\",\n"
-                       " \"h2_trans\":\"%lu\",\n"
-                       " \"ws_upg\":\"%lu\",\n"
-                       " \"rejected\":\"%lu\",\n"
-                       " \"h2_alpn\":\"%lu\",\n"
-                       " \"h2_subs\":\"%lu\",\n"
-                       " \"h2_upg\":\"%lu\"",
-                       listening, cs.rx, cs.tx,
-                       cs.h1_conn,
-                       cs.h1_trans,
-                       cs.h2_trans,
-                       cs.ws_upg,
-                       cs.rejected,
-                       cs.h2_alpn,
-                       cs.h2_subs,
-                       cs.h2_upg);
-
-#ifdef LWS_WITH_CGI
-       for (n = 0; n < context->count_threads; n++) {
-               pt = &context->pt[n];
-               pcgi = &pt->http.cgi_list;
-
-               while (*pcgi) {
-                       pcgi = &(*pcgi)->cgi_list;
-
-                       cgi_count++;
-               }
-       }
-#endif
-       buf += lws_snprintf(buf, end - buf, ",\n \"cgi_alive\":\"%d\"\n ",
-                       cgi_count);
-
-       buf += lws_snprintf(buf, end - buf, "}");
-
-
-       buf += lws_snprintf(buf, end - buf, "]}\n ");
-
-       return buf - orig;
-}
-
-#endif
index 05c14e9..02e4c05 100644 (file)
@@ -1,60 +1,71 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
-int
-lws_callback_as_writeable(struct lws *wsi)
+#if defined(_DEBUG)
+void
+lws_service_assert_loop_thread(struct lws_context *cx, int tsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-       int n, m;
+       if (!cx->event_loop_ops->foreign_thread)
+               /* we can't judge it */
+               return;
 
-       lws_stats_bump(pt, LWSSTATS_C_WRITEABLE_CB, 1);
-#if defined(LWS_WITH_STATS)
-       if (wsi->active_writable_req_us) {
-               uint64_t ul = lws_now_usecs() -
-                             wsi->active_writable_req_us;
+       if (!cx->event_loop_ops->foreign_thread(cx, tsi))
+               /* OK */
+               return;
 
-               lws_stats_bump(pt, LWSSTATS_US_WRITABLE_DELAY_AVG, ul);
-               lws_stats_max(pt, LWSSTATS_US_WORST_WRITABLE_DELAY, ul);
-               wsi->active_writable_req_us = 0;
-       }
+       /*
+        * Lws apis are NOT THREADSAFE with the sole exception of
+        * lws_cancel_service().  If you look at the assert backtrace, you
+        * should see you're illegally calling an lws api from another thread.
+        */
+       assert(0);
+}
 #endif
 
-       n = wsi->role_ops->writeable_cb[lwsi_role_server(wsi)];
+int
+lws_callback_as_writeable(struct lws *wsi)
+{
+       int n, m;
 
-       m = user_callback_handle_rxflow(wsi->protocol->callback,
+       n = wsi->role_ops->writeable_cb[lwsi_role_server(wsi)];
+       m = user_callback_handle_rxflow(wsi->a.protocol->callback,
                                        wsi, (enum lws_callback_reasons) n,
                                        wsi->user_space, NULL, 0);
 
        return m;
 }
 
-LWS_VISIBLE int
+int
 lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
 {
        volatile struct lws *vwsi = (volatile struct lws *)wsi;
        int n;
 
-       // lwsl_notice("%s: %p\n", __func__, wsi);
+       if (wsi->socket_is_permanently_unusable)
+               return 0;
 
        vwsi->leave_pollout_active = 0;
        vwsi->handling_pollout = 1;
@@ -77,9 +88,8 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
         */
 
        if (lws_has_buffered_out(wsi)) {
-               //lwsl_notice("%s: completing partial\n", __func__);
                if (lws_issue_raw(wsi, NULL, 0) < 0) {
-                       lwsl_info("%s signalling to close\n", __func__);
+                       lwsl_wsi_info(wsi, "signalling to close");
                        goto bail_die;
                }
                /* leave POLLOUT active either way */
@@ -97,13 +107,14 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
            wsi->http.comp_ctx.may_have_more) {
                enum lws_write_protocol wp = LWS_WRITE_HTTP;
 
-               lwsl_info("%s: completing comp partial (buflist_comp %p, may %d)\n",
-                               __func__, wsi->http.comp_ctx.buflist_comp,
-                               wsi->http.comp_ctx.may_have_more
-                               );
+               lwsl_wsi_info(wsi, "compl comp partial (buflist_comp %p, may %d)",
+                                  wsi->http.comp_ctx.buflist_comp,
+                                  wsi->http.comp_ctx.may_have_more);
 
-               if (wsi->role_ops->write_role_protocol(wsi, NULL, 0, &wp) < 0) {
-                       lwsl_info("%s signalling to close\n", __func__);
+               if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) &&
+                   lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol).
+                                       write_role_protocol(wsi, NULL, 0, &wp) < 0) {
+                       lwsl_wsi_info(wsi, "signalling to close");
                        goto bail_die;
                }
                lws_callback_on_writable(wsi);
@@ -114,14 +125,14 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
 
 #ifdef LWS_WITH_CGI
        /*
-        * A cgi master's wire protocol remains h1 or h2.  He is just getting
-        * his data from his child cgis.
+        * A cgi connection's wire protocol remains h1 or h2.  He is just
+        * getting his data from his child cgis.
         */
        if (wsi->http.cgi) {
                /* also one shot */
                if (pollfd)
                        if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
-                               lwsl_info("failed at set pollfd\n");
+                               lwsl_wsi_info(wsi, "failed at set pollfd");
                                return 1;
                        }
                goto user_service_go_again;
@@ -131,14 +142,17 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
        /* if we got here, we should have wire protocol ops set on the wsi */
        assert(wsi->role_ops);
 
-       if (!wsi->role_ops->handle_POLLOUT)
+       if (!lws_rops_fidx(wsi->role_ops, LWS_ROPS_handle_POLLOUT))
                goto bail_ok;
 
-       switch ((wsi->role_ops->handle_POLLOUT)(wsi)) {
+       n = lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_handle_POLLOUT).
+                                                       handle_POLLOUT(wsi);
+       switch (n) {
        case LWS_HP_RET_BAIL_OK:
                goto bail_ok;
        case LWS_HP_RET_BAIL_DIE:
                goto bail_die;
+       case LWS_HP_RET_DROP_POLLOUT:
        case LWS_HP_RET_USER_SERVICE:
                break;
        default:
@@ -152,7 +166,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
 
                if (!eff) {
                        if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
-                               lwsl_info("failed at set pollfd\n");
+                               lwsl_wsi_info(wsi, "failed at set pollfd");
                                goto bail_die;
                        }
                }
@@ -165,9 +179,9 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
                         * got set inbetween sampling eff and clearing
                         * handling_pollout, force POLLOUT on
                         */
-                       lwsl_debug("leave_pollout_active\n");
+                       lwsl_wsi_debug(wsi, "leave_pollout_active");
                        if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
-                               lwsl_info("failed at set pollfd\n");
+                               lwsl_wsi_info(wsi, "failed at set pollfd");
                                goto bail_die;
                        }
                }
@@ -180,20 +194,25 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
             lwsi_state(wsi) != LRS_ISSUE_HTTP_BODY)
                goto bail_ok;
 
+       if (n == LWS_HP_RET_DROP_POLLOUT)
+               goto bail_ok;
+
 
 #ifdef LWS_WITH_CGI
 user_service_go_again:
 #endif
 
-       if (wsi->role_ops->perform_user_POLLOUT) {
-               if (wsi->role_ops->perform_user_POLLOUT(wsi) == -1)
+       if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_perform_user_POLLOUT)) {
+               if (lws_rops_func_fidx(wsi->role_ops,
+                                      LWS_ROPS_perform_user_POLLOUT).
+                                               perform_user_POLLOUT(wsi) == -1)
                        goto bail_die;
                else
                        goto bail_ok;
        }
-       
-       lwsl_debug("%s: %p: non mux: wsistate 0x%lx, ops %s\n", __func__, wsi,
-                  (unsigned long)wsi->wsistate, wsi->role_ops->name);
+
+       lwsl_wsi_debug(wsi, "non mux: wsistate 0x%lx, ops %s",
+                           (unsigned long)wsi->wsistate, wsi->role_ops->name);
 
        vwsi = (volatile struct lws *)wsi;
        vwsi->leave_pollout_active = 0;
@@ -226,9 +245,9 @@ bail_die:
 }
 
 int
-lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len)
+lws_rxflow_cache(struct lws *wsi, unsigned char *buf, size_t n, size_t len)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        uint8_t *buffered;
        size_t blen;
        int ret = LWSRXFC_CACHED, m;
@@ -246,8 +265,8 @@ lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len)
                         */
 
                        lws_buflist_use_segment(&wsi->buflist, blen - len);
-                       lwsl_debug("%s: trim existing rxflow %d -> %d\n",
-                                       __func__, (int)blen, (int)len);
+                       lwsl_wsi_debug(wsi, "trim existing rxflow %d -> %d",
+                                           (int)blen, (int)len);
 
                        return LWSRXFC_TRIMMED;
                }
@@ -256,13 +275,15 @@ lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len)
 
        /* a new rxflow, buffer it and warn caller */
 
+       lwsl_wsi_debug(wsi, "rxflow append %d", (int)(len - n));
        m = lws_buflist_append_segment(&wsi->buflist, buf + n, len - n);
 
        if (m < 0)
                return LWSRXFC_ERROR;
        if (m) {
-               lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
-               lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner);
+               lwsl_wsi_debug(wsi, "added to rxflow list");;
+               if (lws_dll2_is_detached(&wsi->dll_buflist))
+                       lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner);
        }
 
        return ret;
@@ -272,10 +293,44 @@ lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len)
  * activity in poll() when we have something that already needs service
  */
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
 {
-       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_context_per_thread *pt;
+
+       if (!context)
+               return 1;
+
+        if (!context->protocol_init_done)
+                if (lws_protocol_init(context))
+                        return 1;
+
+#if defined(LWS_WITH_SYS_SMD)
+       if (!tsi && lws_smd_message_pending(context)) {
+               lws_smd_msg_distribute(context);
+               if (lws_smd_message_pending(context))
+                       return 0;
+       }
+#endif
+
+       pt = &context->pt[tsi];
+
+       if (pt->evlib_pt) {
+               lws_usec_t u;
+
+               lws_pt_lock(pt, __func__); /* -------------- pt { */
+
+               u = __lws_sul_service_ripe(pt->pt_sul_owner,
+                                     LWS_COUNT_PT_SUL_OWNERS, lws_now_usecs());
+               /*
+                * We will come back with 0 if nothing to do at the moment, or
+                * the number of us until something to do
+                */
+               if (u && u < (lws_usec_t)timeout_ms * (lws_usec_t)1000)
+                       timeout_ms = (int)(u / 1000);
+
+               lws_pt_unlock(pt);
+       }
 
        /*
         * Figure out if we really want to wait in poll()... we only need to
@@ -327,51 +382,97 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
  */
 int
 lws_buflist_aware_read(struct lws_context_per_thread *pt, struct lws *wsi,
-                      struct lws_tokens *ebuf)
+                      struct lws_tokens *ebuf, char fr, const char *hint)
 {
-       int n, prior = (int)lws_buflist_next_segment_len(&wsi->buflist, NULL);
+       int n, e, bns;
+       uint8_t *ep, *b;
 
-       ebuf->token = pt->serv_buf;
-       ebuf->len = lws_ssl_capable_read(wsi, pt->serv_buf,
-                                        wsi->context->pt_serv_buf_size);
+       // lwsl_debug("%s: %s: %s: prior %d\n", __func__, lws_wsi_tag(wsi), hint, prior);
+       // lws_buflist_describe(&wsi->buflist, wsi, __func__);
 
-       if (ebuf->len == LWS_SSL_CAPABLE_MORE_SERVICE && prior)
-               goto get_from_buflist;
+       (void)hint;
+       if (!ebuf->token)
+               ebuf->token = pt->serv_buf + LWS_PRE;
+       if (!ebuf->len ||
+           (unsigned int)ebuf->len > wsi->a.context->pt_serv_buf_size - LWS_PRE)
+               ebuf->len = (int)(wsi->a.context->pt_serv_buf_size - LWS_PRE);
 
-       if (ebuf->len <= 0)
-               return 0;
+       e = ebuf->len;
+       ep = ebuf->token;
 
-       /* nothing in buflist already?  Then just use what we read */
+       /* h2 or muxed stream... must force the read due to HOL blocking */
 
-       if (!prior)
-               return 0;
+       if (wsi->mux_substream)
+               fr = 1;
+
+       /* there's something on the buflist? */
+
+       bns = (int)lws_buflist_next_segment_len(&wsi->buflist, &ebuf->token);
+       b = ebuf->token;
 
-       /* stash what we read */
+       if (!fr && bns)
+               goto buflist_material;
 
-       n = lws_buflist_append_segment(&wsi->buflist, ebuf->token,
-                                      ebuf->len);
-       if (n < 0)
+       /* we're going to read something */
+
+       ebuf->token = ep;
+       ebuf->len = n = lws_ssl_capable_read(wsi, ep, (size_t)e);
+
+       lwsl_wsi_debug(wsi, "%s: ssl_capable_read %d", hint, ebuf->len);
+
+       if (!bns && /* only acknowledge error when we handled buflist content */
+           n == LWS_SSL_CAPABLE_ERROR) {
+               lwsl_debug("%s: SSL_CAPABLE_ERROR\n", __func__);
                return -1;
-       if (n) {
-               lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
-               lws_dll2_add_head(&wsi->dll_buflist, &pt->dll_buflist_owner);
        }
 
-       /* get the first buflist guy in line */
+       if (n <= 0 && bns)
+               /*
+                * There wasn't anything to read yet, but there's something
+                * on the buflist to give him
+                */
+               goto buflist_material;
+
+       /* we read something */
+
+       if (fr && bns) {
+               /*
+                * Stash what we read, since there's earlier buflist material
+                */
 
-get_from_buflist:
+               n = lws_buflist_append_segment(&wsi->buflist, ebuf->token, (size_t)ebuf->len);
+               if (n < 0)
+                       return -1;
+               if (n && lws_dll2_is_detached(&wsi->dll_buflist))
+                       lws_dll2_add_head(&wsi->dll_buflist,
+                                         &pt->dll_buflist_owner);
 
-       ebuf->len = (int)lws_buflist_next_segment_len(&wsi->buflist,
-                                                     &ebuf->token);
+               goto buflist_material;
+       }
 
-       return 1; /* came from buflist */
+       /*
+        * directly return what we read
+        */
+
+       return 0;
+
+buflist_material:
+
+       ebuf->token = b;
+       if (e < bns)
+               /* restrict to e, if more than e available */
+               ebuf->len = e;
+       else
+               ebuf->len = bns;
+
+       return 1; /* from buflist */
 }
 
 int
-lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
-                         int buffered)
+lws_buflist_aware_finished_consuming(struct lws *wsi, struct lws_tokens *ebuf,
+                                    int used, int buffered, const char *hint)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        int m;
 
        /* it's in the buflist; we didn't use any */
@@ -380,13 +481,14 @@ lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
                return 0;
 
        if (used && buffered) {
-               m = lws_buflist_use_segment(&wsi->buflist, used);
-               lwsl_info("%s: draining rxflow: used %d, next %d\n",
-                           __func__, used, m);
-               if (m)
-                       return 0;
+               if (wsi->buflist) {
+                       m = (int)lws_buflist_use_segment(&wsi->buflist,
+                                                        (size_t)used);
+                       if (m)
+                               return 0;
+               }
 
-               lwsl_info("%s: removed %p from dll_buflist\n", __func__, wsi);
+               lwsl_wsi_info(wsi, "removed from dll_buflist");
                lws_dll2_remove(&wsi->dll_buflist);
 
                return 0;
@@ -394,16 +496,16 @@ lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
 
        /* any remainder goes on the buflist */
 
-       if (used != ebuf->len) {
+       if (used < ebuf->len && ebuf->len >= 0 && used >= 0) {
                m = lws_buflist_append_segment(&wsi->buflist,
                                               ebuf->token + used,
-                                              ebuf->len - used);
+                                              (unsigned int)(ebuf->len - used));
                if (m < 0)
                        return 1; /* OOM */
                if (m) {
-                       lwsl_debug("%s: added %p to rxflow list\n",
-                                  __func__, wsi);
-                       lws_dll2_add_head(&wsi->dll_buflist,
+                       lwsl_wsi_debug(wsi, "added to rxflow list");
+                       if (lws_dll2_is_detached(&wsi->dll_buflist))
+                               lws_dll2_add_head(&wsi->dll_buflist,
                                         &pt->dll_buflist_owner);
                }
        }
@@ -434,16 +536,22 @@ lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt)
                pfd.revents = LWS_POLLIN;
                pfd.fd = -1;
 
-               lwsl_debug("%s: rxflow processing: %p fc=%d, 0x%lx\n", __func__,
-                          wsi, lws_is_flowcontrolled(wsi),
-                          (unsigned long)wsi->wsistate);
+               lwsl_wsi_debug(wsi, "rxflow processing: fc=%d, 0x%lx",
+                                   lws_is_flowcontrolled(wsi),
+                                   (unsigned long)wsi->wsistate);
 
                if (!lws_is_flowcontrolled(wsi) &&
-                   lwsi_state(wsi) != LRS_DEFERRING_ACTION &&
-                   (wsi->role_ops->handle_POLLIN)(pt, wsi, &pfd) ==
+                   lwsi_state(wsi) != LRS_DEFERRING_ACTION) {
+                       pt->inside_lws_service = 1;
+
+                       if (lws_rops_func_fidx(wsi->role_ops,
+                                              LWS_ROPS_handle_POLLIN).
+                                               handle_POLLIN(pt, wsi, &pfd) ==
                                                   LWS_HPI_RET_PLEASE_CLOSE_ME)
-                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
-                                          "close_and_handled");
+                               lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
+                                               "close_and_handled");
+                       pt->inside_lws_service = 0;
+               }
 
        } lws_end_foreach_dll_safe(d, d1);
 
@@ -459,9 +567,14 @@ lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt)
 int
 lws_service_flag_pending(struct lws_context *context, int tsi)
 {
-       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_context_per_thread *pt;
        int forced = 0;
 
+       if (!context)
+               return 1;
+
+       pt = &context->pt[tsi];
+
        lws_pt_lock(pt, __func__);
 
        /*
@@ -480,7 +593,9 @@ lws_service_flag_pending(struct lws_context *context, int tsi)
        } lws_end_foreach_dll(d);
 
 #if defined(LWS_ROLE_WS)
-       forced |= role_ops_ws.service_flag_pending(context, tsi);
+       forced |= lws_rops_func_fidx(&role_ops_ws,
+                                    LWS_ROPS_service_flag_pending).
+                                       service_flag_pending(context, tsi);
 #endif
 
 #if defined(LWS_WITH_TLS)
@@ -495,17 +610,20 @@ lws_service_flag_pending(struct lws_context *context, int tsi)
                struct lws *wsi = lws_container_of(p, struct lws,
                                                   tls.dll_pending_tls);
 
-               pt->fds[wsi->position_in_fds_table].revents |=
-                       pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
-               if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN) {
-                       forced = 1;
-                       /*
-                        * he's going to get serviced now, take him off the
-                        * list of guys with buffered SSL.  If he still has some
-                        * at the end of the service, he'll get put back on the
-                        * list then.
-                        */
-                       __lws_ssl_remove_wsi_from_buffered_list(wsi);
+               if (wsi->position_in_fds_table >= 0) {
+
+                       pt->fds[wsi->position_in_fds_table].revents = (short)(
+                                       pt->fds[wsi->position_in_fds_table].revents |
+                               (pt->fds[wsi->position_in_fds_table].events &
+                                                               LWS_POLLIN));
+                       if (pt->fds[wsi->position_in_fds_table].revents &
+                                                               LWS_POLLIN)
+                               /*
+                                * We're not going to remove the wsi from the
+                                * pending tls list.  The processing will have
+                                * to do it if he exhausts the pending tls.
+                                */
+                               forced = 1;
                }
 
        } lws_end_foreach_dll_safe(p, p1);
@@ -516,14 +634,20 @@ lws_service_flag_pending(struct lws_context *context, int tsi)
        return forced;
 }
 
-LWS_VISIBLE int
+int
 lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
                   int tsi)
 {
-       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_context_per_thread *pt;
        struct lws *wsi;
+       char cow = 0;
+
+       if (!context || context->service_no_longer_possible)
+               return -1;
 
-       if (!context || context->being_destroyed1 )
+       pt = &context->pt[tsi];
+
+       if (pt->event_loop_pt_unused)
                return -1;
 
        if (!pollfd) {
@@ -556,15 +680,40 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
         * zero down pollfd->revents after handling
         */
 
-       /* handle session socket closed */
+       /*
+        * Whatever the situation with buffered rx packets, or explicitly read-
+        * and-buffered rx going to be handled before we want to acknowledge the
+        * socket is gone, any sign of HUP always immediately means no more tx
+        * is possible.
+        */
 
-       if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
-           (pollfd->revents & LWS_POLLHUP)) {
+       if ((pollfd->revents & LWS_POLLHUP) == LWS_POLLHUP) {
                wsi->socket_is_permanently_unusable = 1;
-               lwsl_debug("Session Socket %p (fd=%d) dead\n",
-                          (void *)wsi, pollfd->fd);
 
-               goto close_and_handled;
+               if (!(pollfd->revents & pollfd->events & LWS_POLLIN)) {
+
+                       /* ... there are no pending rx packets waiting... */
+
+                       if (!lws_buflist_total_len(&wsi->buflist)) {
+
+                               /*
+                                * ... nothing stashed in the buflist either,
+                                * so acknowledge the wsi is done
+                                */
+
+                               lwsl_wsi_debug(wsi, "Session Socket %d dead",
+                                                   pollfd->fd);
+
+                               goto close_and_handled;
+                       }
+
+                       /*
+                        * ... in fact we have some unread rx buffered in the
+                        * input buflist.  Hold off the closing a bit...
+                        */
+
+                       lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 3);
+               }
        }
 
 #ifdef _WIN32
@@ -572,13 +721,6 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
                wsi->sock_send_blocking = FALSE;
 #endif
 
-       if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
-           (pollfd->revents & LWS_POLLHUP)) {
-               lwsl_debug("pollhup\n");
-               wsi->socket_is_permanently_unusable = 1;
-               goto close_and_handled;
-       }
-
 #if defined(LWS_WITH_TLS)
        if (lwsi_state(wsi) == LRS_SHUTDOWN &&
            lws_is_ssl(wsi) && wsi->tls.ssl) {
@@ -594,7 +736,24 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
                }
        }
 #endif
+
+       if ((pollfd->revents & LWS_POLLOUT) == LWS_POLLOUT &&
+           wsi->tls_read_wanted_write) {
+               /*
+                * If this wsi has a pending WANT_WRITE from SSL_read(), it has
+                * asked for a callback on writeable so it can retry the read.
+                *
+                *  Let's consume the POLLOUT by turning it into a POLLIIN, and
+                *  setting a flag to request a new writeable
+                */
+               wsi->tls_read_wanted_write = 0;
+               pollfd->revents &= ~(LWS_POLLOUT);
+               pollfd->revents |= LWS_POLLIN;
+               cow = 1;
+       }
+
        wsi->could_have_pending = 0; /* clear back-to-back write detection */
+       pt->inside_lws_service = 1;
 
        /* okay, what we came here to do... */
 
@@ -604,14 +763,18 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
        // lwsl_notice("%s: %s: wsistate 0x%x\n", __func__, wsi->role_ops->name,
        //          wsi->wsistate);
 
-       switch ((wsi->role_ops->handle_POLLIN)(pt, wsi, pollfd)) {
+       switch (lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_handle_POLLIN).
+                                              handle_POLLIN(pt, wsi, pollfd)) {
        case LWS_HPI_RET_WSI_ALREADY_DIED:
+               pt->inside_lws_service = 0;
                return 1;
        case LWS_HPI_RET_HANDLED:
                break;
        case LWS_HPI_RET_PLEASE_CLOSE_ME:
+               //lwsl_notice("%s: %s pollin says please close me\n", __func__,
+               //              wsi->role_ops->name);
 close_and_handled:
-               lwsl_debug("%p: Close and handled\n", wsi);
+               lwsl_wsi_debug(wsi, "Close and handled");
                lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
                                   "close_and_handled");
 #if defined(_DEBUG) && defined(LWS_WITH_LIBUV)
@@ -620,7 +783,7 @@ close_and_handled:
                 * it waits for libuv service to complete the first async
                 * close
                 */
-               if (context->event_loop_ops == &event_loop_ops_uv)
+               if (!strcmp(context->event_loop_ops->name, "libuv"))
                        lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
                                           "close_and_handled uv repeat test");
 #endif
@@ -630,6 +793,7 @@ close_and_handled:
                 * we can't clear revents now because it'd be the wrong guy's
                 * revents
                 */
+               pt->inside_lws_service = 0;
                return 1;
        default:
                assert(0);
@@ -638,31 +802,29 @@ close_and_handled:
 handled:
 #endif
        pollfd->revents = 0;
-
-       if (!context->protocol_init_done)
-               if (lws_protocol_init(context)) {
-                       lwsl_err("%s: lws_protocol_init failed\n", __func__);
-                       return -1;
-               }
+       if (cow)
+               lws_callback_on_writable(wsi);
+       pt->inside_lws_service = 0;
 
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd)
 {
        return lws_service_fd_tsi(context, pollfd, 0);
 }
 
-LWS_VISIBLE int
+int
 lws_service(struct lws_context *context, int timeout_ms)
 {
-       struct lws_context_per_thread *pt = &context->pt[0];
+       struct lws_context_per_thread *pt;
        int n;
 
        if (!context)
                return 1;
 
+       pt = &context->pt[0];
        pt->inside_service = 1;
 
        if (context->event_loop_ops->run_pt) {
@@ -675,17 +837,22 @@ lws_service(struct lws_context *context, int timeout_ms)
        }
        n = lws_plat_service(context, timeout_ms);
 
-       pt->inside_service = 0;
+       if (n != -1)
+               pt->inside_service = 0;
 
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
 {
-       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_context_per_thread *pt;
        int n;
 
+       if (!context)
+               return 1;
+
+       pt = &context->pt[tsi];
        pt->inside_service = 1;
 #if LWS_MAX_SMP > 1
        pt->self = pthread_self();
diff --git a/lib/core-net/socks5-client.c b/lib/core-net/socks5-client.c
new file mode 100644 (file)
index 0000000..4d7572a
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Socks5 Client -related helpers
+ */
+
+#include "private-lib-core.h"
+
+int
+lws_set_socks(struct lws_vhost *vhost, const char *socks)
+{
+       char *p_at, *p_colon;
+       char user[96];
+       char password[96];
+
+       if (!socks)
+               return -1;
+
+       vhost->socks_user[0] = '\0';
+       vhost->socks_password[0] = '\0';
+
+       p_at = strrchr(socks, '@');
+       if (p_at) { /* auth is around */
+               if (lws_ptr_diff_size_t(p_at, socks) > (sizeof(user) +
+                                                       sizeof(password) - 2)) {
+                       lwsl_vhost_err(vhost, "auth too long");
+                       goto bail;
+               }
+
+               p_colon = strchr(socks, ':');
+               if (p_colon) {
+                       if (lws_ptr_diff_size_t(p_colon, socks) >
+                                                            sizeof(user) - 1) {
+                               lwsl_vhost_err(vhost, "user too long");
+                               goto bail;
+                       }
+                       if (lws_ptr_diff_size_t(p_at, p_colon) >
+                                                        sizeof(password) - 1) {
+                               lwsl_vhost_err(vhost, "pw too long");
+                               goto bail;
+                       }
+
+                       lws_strncpy(vhost->socks_user, socks,
+                                   lws_ptr_diff_size_t(p_colon, socks) + 1);
+                       lws_strncpy(vhost->socks_password, p_colon + 1,
+                               lws_ptr_diff_size_t(p_at, (p_colon + 1)) + 1);
+               }
+
+               lwsl_vhost_info(vhost, " Socks auth, user: %s, password: %s",
+                                      vhost->socks_user,
+                                      vhost->socks_password);
+
+               socks = p_at + 1;
+       }
+
+       lws_strncpy(vhost->socks_proxy_address, socks,
+                   sizeof(vhost->socks_proxy_address));
+
+       p_colon = strchr(vhost->socks_proxy_address, ':');
+       if (!p_colon && !vhost->socks_proxy_port) {
+               lwsl_vhost_err(vhost, "socks_proxy needs to be address:port");
+
+               return -1;
+       }
+
+       if (p_colon) {
+               *p_colon = '\0';
+               vhost->socks_proxy_port = (unsigned int)atoi(p_colon + 1);
+       }
+
+       lwsl_vhost_debug(vhost, "Connections via Socks5 %s:%u",
+                               vhost->socks_proxy_address,
+                               vhost->socks_proxy_port);
+
+       return 0;
+
+bail:
+       return -1;
+}
+
+int
+lws_socks5c_generate_msg(struct lws *wsi, enum socks_msg_type type,
+                        ssize_t *msg_len)
+{
+       struct lws_context *context = wsi->a.context;
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+       uint8_t *p = pt->serv_buf, *end = &p[context->pt_serv_buf_size];
+       ssize_t n, passwd_len;
+       short net_num;
+       char *cp;
+
+       switch (type) {
+       case SOCKS_MSG_GREETING:
+               if (lws_ptr_diff(end, p) < 4)
+                       return 1;
+               /* socks version, version 5 only */
+               *p++ = SOCKS_VERSION_5;
+               /* number of methods */
+               *p++ = 2;
+               /* username password method */
+               *p++ = SOCKS_AUTH_USERNAME_PASSWORD;
+               /* no authentication method */
+               *p++ = SOCKS_AUTH_NO_AUTH;
+               break;
+
+       case SOCKS_MSG_USERNAME_PASSWORD:
+               n = (ssize_t)strlen(wsi->a.vhost->socks_user);
+               passwd_len = (ssize_t)strlen(wsi->a.vhost->socks_password);
+
+               if (n > 254 || passwd_len > 254)
+                       return 1;
+
+               if (lws_ptr_diff(end, p) < 3 + n + passwd_len)
+                       return 1;
+
+               /* the subnegotiation version */
+               *p++ = SOCKS_SUBNEGOTIATION_VERSION_1;
+
+               /* length of the user name */
+               *p++ = (uint8_t)n;
+               /* user name */
+               memcpy(p, wsi->a.vhost->socks_user, (size_t)n);
+               p += (uint8_t)n;
+
+               /* length of the password */
+               *p++ = (uint8_t)passwd_len;
+
+               /* password */
+               memcpy(p, wsi->a.vhost->socks_password, (size_t)passwd_len);
+               p += passwd_len;
+               break;
+
+       case SOCKS_MSG_CONNECT:
+               n = (ssize_t)strlen(wsi->stash->cis[CIS_ADDRESS]);
+
+               if (n > 254 || lws_ptr_diff(end, p) < 5 + n + 2)
+                       return 1;
+
+               cp = (char *)&net_num;
+
+               /* socks version */
+               *p++ = SOCKS_VERSION_5;
+               /* socks command */
+               *p++ = SOCKS_COMMAND_CONNECT;
+               /* reserved */
+               *p++ = 0;
+               /* address type */
+               *p++ = SOCKS_ATYP_DOMAINNAME;
+               /* length of ---> */
+               *p++ = (uint8_t)n;
+
+               /* the address we tell SOCKS proxy to connect to */
+               memcpy(p, wsi->stash->cis[CIS_ADDRESS], (size_t)n);
+               p += n;
+
+               net_num = (short)htons(wsi->c_port);
+
+               /* the port we tell SOCKS proxy to connect to */
+               *p++ = (uint8_t)cp[0];
+               *p++ = (uint8_t)cp[1];
+
+               break;
+
+       default:
+               return 1;
+       }
+
+       *msg_len = lws_ptr_diff(p, pt->serv_buf);
+
+       return 0;
+}
+
+int
+lws_socks5c_ads_server(struct lws_vhost *vh,
+                     const struct lws_context_creation_info *info)
+{
+       /* socks proxy */
+       if (info->socks_proxy_address) {
+               /* override for backwards compatibility */
+               if (info->socks_proxy_port)
+                       vh->socks_proxy_port = info->socks_proxy_port;
+               lws_set_socks(vh, info->socks_proxy_address);
+
+               return 0;
+       }
+#ifdef LWS_HAVE_GETENV
+       {
+               char *p = getenv("socks_proxy");
+
+               if (p && strlen(p) > 0 && strlen(p) < 95)
+                       lws_set_socks(vh, p);
+       }
+#endif
+
+       return 0;
+}
+
+/*
+ * Returns 0 = nothing for caller to do, 1 = return wsi, -1 = goto failed
+ */
+
+int
+lws_socks5c_greet(struct lws *wsi, const char **pcce)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       ssize_t plen;
+       int n;
+
+       /* socks proxy */
+       if (!wsi->a.vhost->socks_proxy_port)
+               return 0;
+
+       if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_GREETING, &plen)) {
+               *pcce = "socks msg too large";
+               return -1;
+       }
+       // lwsl_hexdump_notice(pt->serv_buf, plen);
+       n = (int)send(wsi->desc.sockfd, (char *)pt->serv_buf, (size_t)plen,
+                     MSG_NOSIGNAL);
+       if (n < 0) {
+               lwsl_wsi_debug(wsi, "ERROR writing socks greeting");
+               *pcce = "socks write failed";
+               return -1;
+       }
+
+       lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
+                       (int)wsi->a.context->timeout_secs);
+
+       lwsi_set_state(wsi, LRS_WAITING_SOCKS_GREETING_REPLY);
+
+       return 1;
+}
+
+int
+lws_socks5c_handle_state(struct lws *wsi, struct lws_pollfd *pollfd,
+                        const char **pcce)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       int conn_mode = 0, pending_timeout = 0;
+       ssize_t len;
+       int n;
+
+       /* handle proxy hung up on us */
+
+       if (pollfd->revents & LWS_POLLHUP) {
+               lwsl_wsi_warn(wsi, "SOCKS fd=%d dead", pollfd->fd);
+               *pcce = "socks conn dead";
+               return LW5CHS_RET_BAIL3;
+       }
+
+       n = (int)recv(wsi->desc.sockfd, (void *)pt->serv_buf,
+                wsi->a.context->pt_serv_buf_size, 0);
+       if (n < 0) {
+               if (LWS_ERRNO == LWS_EAGAIN) {
+                       lwsl_wsi_debug(wsi, "SOCKS read EAGAIN, retrying");
+                       return LW5CHS_RET_RET0;
+               }
+               lwsl_wsi_err(wsi, "ERROR reading from SOCKS socket");
+               *pcce = "socks recv fail";
+               return LW5CHS_RET_BAIL3;
+       }
+
+       // lwsl_hexdump_warn(pt->serv_buf, n);
+
+       switch (lwsi_state(wsi)) {
+
+       case LRS_WAITING_SOCKS_GREETING_REPLY:
+               if (pt->serv_buf[0] != SOCKS_VERSION_5)
+                       goto socks_reply_fail;
+
+               if (pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH) {
+                       lwsl_wsi_client(wsi, "SOCKS GR: No Auth Method");
+                       if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_CONNECT,
+                                                    &len)) {
+                               lwsl_wsi_err(wsi, "generate connect msg fail");
+                               goto socks_send_msg_fail;
+                       }
+                       conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY;
+                       pending_timeout =
+                          PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
+                       goto socks_send;
+               }
+
+               if (pt->serv_buf[1] == SOCKS_AUTH_USERNAME_PASSWORD) {
+                       lwsl_wsi_client(wsi, "SOCKS GR: User/Pw Method");
+                       if (lws_socks5c_generate_msg(wsi,
+                                          SOCKS_MSG_USERNAME_PASSWORD,
+                                          &len))
+                               goto socks_send_msg_fail;
+                       conn_mode = LRS_WAITING_SOCKS_AUTH_REPLY;
+                       pending_timeout =
+                             PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY;
+                       goto socks_send;
+               }
+               goto socks_reply_fail;
+
+       case LRS_WAITING_SOCKS_AUTH_REPLY:
+               if (pt->serv_buf[0] != SOCKS_SUBNEGOTIATION_VERSION_1 ||
+                   pt->serv_buf[1] !=
+                                   SOCKS_SUBNEGOTIATION_STATUS_SUCCESS)
+                       goto socks_reply_fail;
+
+               lwsl_wsi_client(wsi, "SOCKS password OK, sending connect");
+               if (lws_socks5c_generate_msg(wsi, SOCKS_MSG_CONNECT, &len)) {
+socks_send_msg_fail:
+                       *pcce = "socks gen msg fail";
+                       return LW5CHS_RET_BAIL3;
+               }
+               conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY;
+               pending_timeout =
+                          PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
+socks_send:
+               // lwsl_hexdump_notice(pt->serv_buf, len);
+               n = (int)send(wsi->desc.sockfd, (char *)pt->serv_buf,
+                             (size_t)len, MSG_NOSIGNAL);
+               if (n < 0) {
+                       lwsl_wsi_debug(wsi, "ERROR writing to socks proxy");
+                       *pcce = "socks write fail";
+                       return LW5CHS_RET_BAIL3;
+               }
+
+               lws_set_timeout(wsi, (enum pending_timeout)pending_timeout,
+                               (int)wsi->a.context->timeout_secs);
+               lwsi_set_state(wsi, (lws_wsi_state_t)conn_mode);
+               break;
+
+socks_reply_fail:
+               lwsl_wsi_err(wsi, "socks reply: v%d, err %d",
+                            pt->serv_buf[0], pt->serv_buf[1]);
+               *pcce = "socks reply fail";
+               return LW5CHS_RET_BAIL3;
+
+       case LRS_WAITING_SOCKS_CONNECT_REPLY:
+               if (pt->serv_buf[0] != SOCKS_VERSION_5 ||
+                   pt->serv_buf[1] != SOCKS_REQUEST_REPLY_SUCCESS)
+                       goto socks_reply_fail;
+
+               lwsl_wsi_client(wsi, "socks connect OK");
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+               if (lwsi_role_http(wsi) &&
+                   lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
+                                         wsi->a.vhost->socks_proxy_address)) {
+                       *pcce = "socks connect fail";
+                       return LW5CHS_RET_BAIL3;
+               }
+#endif
+
+               wsi->c_port = (uint16_t)wsi->a.vhost->socks_proxy_port;
+
+               /* clear his proxy connection timeout */
+               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+               return LW5CHS_RET_STARTHS;
+       default:
+               break;
+       }
+
+       return LW5CHS_RET_NOTHING;
+}
index fcf381c..e9b9c1f 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 static int
 sul_compare(const lws_dll2_t *d, const lws_dll2_t *i)
@@ -40,99 +43,345 @@ sul_compare(const lws_dll2_t *d, const lws_dll2_t *i)
        return 0;
 }
 
+/*
+ * notice owner was chosen already, and sul->us was already computed
+ */
+
 int
-__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul,
-                lws_usec_t us)
+__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul)
 {
-       lws_usec_t now = lws_now_usecs();
        lws_dll2_remove(&sul->list);
 
-       if (us == LWS_SET_TIMER_USEC_CANCEL) {
-               /* we are clearing the timeout */
-               sul->us = 0;
-
-               return 0;
-       }
-
-       sul->us = now + us;
        assert(sul->cb);
 
        /*
         * we sort the pt's list of sequencers with pending timeouts, so it's
-        * cheap to check it every second
+        * cheap to check it every poll wait
         */
 
        lws_dll2_add_sorted(&sul->list, own, sul_compare);
 
-#if 0 // defined(_DEBUG)
-       {
-               lws_usec_t worst = 0;
-               int n = 1;
-
-               lwsl_info("%s: own %p: count %d\n", __func__, own, own->count);
-
-               lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
-                                          lws_dll2_get_head(own)) {
-                       lws_sorted_usec_list_t *sul = (lws_sorted_usec_list_t *)p;
-                       lwsl_info("%s:    %d: %llu (+%lld)\n", __func__, n++,
-                                       (unsigned long long)sul->us,
-                                       (long long)(sul->us - now));
-                       if (sul->us < worst) {
-                               lwsl_err("%s: wrongly sorted sul entry!\n",
-                                               __func__);
-                               assert(0);
-                       }
-                       worst = sul->us;
-               } lws_end_foreach_dll_safe(p, tp);
-       }
-#endif
-
        return 0;
 }
 
 void
-lws_sul_schedule(struct lws_context *context, int tsi,
-                lws_sorted_usec_list_t *sul, sul_cb_t cb, lws_usec_t us)
+lws_sul_cancel(lws_sorted_usec_list_t *sul)
+{
+       lws_dll2_remove(&sul->list);
+
+       /* we are clearing the timeout and leaving ourselves detached */
+       sul->us = 0;
+}
+
+void
+lws_sul2_schedule(struct lws_context *context, int tsi, int flags,
+                 lws_sorted_usec_list_t *sul)
 {
        struct lws_context_per_thread *pt = &context->pt[tsi];
 
-       sul->cb = cb;
+       lws_pt_assert_lock_held(pt);
 
-       __lws_sul_insert(&pt->pt_sul_owner, sul, us);
+       assert(sul->cb);
+
+       __lws_sul_insert(
+               &pt->pt_sul_owner[!!(flags & LWSSULLI_WAKE_IF_SUSPENDED)], sul);
 }
 
+/*
+ * own points to the first in an array of length own_len
+ *
+ * While any sul list owner has a "ripe", ie, ready to handle sul we do them
+ * strictly in order of sul time.  When nobody has a ripe sul we return 0, if
+ * actually nobody has any sul, or the interval between usnow and the next
+ * earliest scheduled event on any list.
+ */
+
 lws_usec_t
-__lws_sul_service_ripe(lws_dll2_owner_t *own, lws_usec_t usnow)
+__lws_sul_service_ripe(lws_dll2_owner_t *own, int own_len, lws_usec_t usnow)
 {
-       while (lws_dll2_get_head(own)) {
-                /* .list is always first member in lws_sorted_usec_list_t */
-                lws_sorted_usec_list_t *sul = (lws_sorted_usec_list_t *)
-                                                        lws_dll2_get_head(own);
-               assert(sul->us); /* shouldn't be on the list otherwise */
-               if (sul->us > usnow)
-                       /*
-                        * No need to look further if we met one later than now:
-                        * the list is sorted in ascending time order
-                        */
-                       return sul->us - usnow;
-
-               /* his moment has come... remove him from timeout list */
-
-               lws_dll2_remove(&sul->list);
-               sul->us = 0;
-               sul->cb(sul);
-                /*
-                 * The callback may have done any mixture of delete
-                 * and add sul entries... eg, close a wsi may pull out
-                 * multiple entries making iterating it statefully
-                 * unsafe.  Always restart at the current head of list.
-                 */
-       }
+       struct lws_context_per_thread *pt = (struct lws_context_per_thread *)
+                       lws_container_of(own, struct lws_context_per_thread,
+                                        pt_sul_owner);
+
+       if (pt->attach_owner.count)
+               lws_system_do_attach(pt);
+
+       lws_pt_assert_lock_held(pt);
+
+       /* must be at least 1 */
+       assert(own_len > 0);
 
        /*
-        * Nothing left to take care of in the list (cannot return 0 otherwise
-        * because we will service anything equal to usnow rather than return)
+        * Of the own_len sul owning lists, the earliest next sul could be on
+        * any of them.  We have to find it and handle each in turn until no
+        * ripe sul left on any owning list, and we can exit.
+        *
+        * This ensures the ripe sul are handled strictly in the right order no
+        * matter which owning list they are on.
         */
 
+       do {
+               lws_sorted_usec_list_t *hit = NULL;
+               lws_usec_t lowest = 0;
+               int n = 0;
+
+               for (n = 0; n < own_len; n++) {
+                       lws_sorted_usec_list_t *sul;
+                       if (!own[n].count)
+                               continue;
+                        sul = (lws_sorted_usec_list_t *)
+                                                    lws_dll2_get_head(&own[n]);
+
+                       if (!hit || sul->us <= lowest) {
+                               hit = sul;
+                               lowest = sul->us;
+                       }
+               }
+
+               if (!hit)
+                       return 0;
+
+               if (lowest > usnow)
+                       return lowest - usnow;
+
+               /* his moment has come... remove him from his owning list */
+
+               lws_dll2_remove(&hit->list);
+               hit->us = 0;
+
+               // lwsl_notice("%s: sul: %p\n", __func__, hit->cb);
+
+               pt->inside_lws_service = 1;
+               hit->cb(hit);
+               pt->inside_lws_service = 0;
+
+       } while (1);
+
+       /* unreachable */
+
        return 0;
 }
+
+/*
+ * Normally we use the OS monotonic time, which does not step when the
+ * gettimeofday() time is adjusted after, eg, ntpclient.  But on some OSes,
+ * high resolution monotonic time doesn't exist; sul time is computed from and
+ * compared against gettimeofday() time and breaks when that steps.
+ *
+ * For those cases, this allows us to retrospectively adjust existing suls on
+ * all owning lists by the step amount, at the same time we adjust the
+ * nonmonotonic clock.  Then nothing breaks so long as we do this when the
+ * gettimeofday() clock is stepped.
+ *
+ * Linux and so on offer Posix MONOTONIC, which lws uses.  FreeRTOS doesn't
+ * have a high-resolution monotonic clock and has to use gettimeofday(), which
+ * requires this adjustment when it is stepped.
+ */
+
+lws_usec_t
+lws_sul_nonmonotonic_adjust(struct lws_context *ctx, int64_t step_us)
+{
+       struct lws_context_per_thread *pt = &ctx->pt[0];
+       int n, m;
+
+       /*
+        * for each pt
+        */
+
+       for (m = 0; m < ctx->count_threads; m++) {
+
+               /*
+                * For each owning list...
+                */
+
+               lws_pt_lock(pt, __func__);
+
+               for (n = 0; n < LWS_COUNT_PT_SUL_OWNERS; n++) {
+
+                       if (!pt->pt_sul_owner[n].count)
+                               continue;
+
+                       /* ... and for every existing sul on a list... */
+
+                       lws_start_foreach_dll(struct lws_dll2 *, p,
+                                             lws_dll2_get_head(
+                                                       &pt->pt_sul_owner[n])) {
+                               lws_sorted_usec_list_t *sul = lws_container_of(
+                                              p, lws_sorted_usec_list_t, list);
+
+                               /*
+                                * ... retrospectively step its ripe time by the
+                                * step we will adjust the gettimeofday() clock
+                                * with
+                                */
+
+                               sul->us += step_us;
+
+                       } lws_end_foreach_dll(p);
+               }
+
+               lws_pt_unlock(pt);
+
+               pt++;
+       }
+
+       return 0;
+}
+
+/*
+ * Earliest wakeable event on any pt
+ */
+
+int
+lws_sul_earliest_wakeable_event(struct lws_context *ctx, lws_usec_t *pearliest)
+{
+       struct lws_context_per_thread *pt;
+       int n = 0, hit = -1;
+       lws_usec_t lowest = 0;
+
+       for (n = 0; n < ctx->count_threads; n++) {
+               pt = &ctx->pt[n];
+
+               lws_pt_lock(pt, __func__);
+
+               if (pt->pt_sul_owner[LWSSULLI_WAKE_IF_SUSPENDED].count) {
+                       lws_sorted_usec_list_t *sul = (lws_sorted_usec_list_t *)
+                                       lws_dll2_get_head(&pt->pt_sul_owner[
+                                                  LWSSULLI_WAKE_IF_SUSPENDED]);
+
+                       if (hit == -1 || sul->us < lowest) {
+                               hit = n;
+                               lowest = sul->us;
+                       }
+               }
+
+               lws_pt_unlock(pt);
+       }
+
+
+       if (hit == -1)
+               /* there is no pending event */
+               return 1;
+
+       *pearliest = lowest;
+
+       return 0;
+}
+
+void
+lws_sul_schedule(struct lws_context *ctx, int tsi, lws_sorted_usec_list_t *sul,
+                sul_cb_t _cb, lws_usec_t _us)
+{
+       struct lws_context_per_thread *_pt = &ctx->pt[tsi];
+
+       assert(_cb);
+
+       lws_pt_lock(_pt, __func__);
+
+       if (_us == (lws_usec_t)LWS_SET_TIMER_USEC_CANCEL)
+               lws_sul_cancel(sul);
+       else {
+               sul->cb = _cb;
+               sul->us = lws_now_usecs() + _us;
+               lws_sul2_schedule(ctx, tsi, LWSSULLI_MISS_IF_SUSPENDED, sul);
+       }
+
+       lws_pt_unlock(_pt);
+}
+
+void
+lws_sul_schedule_wakesuspend(struct lws_context *ctx, int tsi,
+                            lws_sorted_usec_list_t *sul, sul_cb_t _cb,
+                            lws_usec_t _us)
+{
+       struct lws_context_per_thread *_pt = &ctx->pt[tsi];
+
+       assert(_cb);
+
+       lws_pt_lock(_pt, __func__);
+
+       if (_us == (lws_usec_t)LWS_SET_TIMER_USEC_CANCEL)
+               lws_sul_cancel(sul);
+       else {
+               sul->cb = _cb;
+               sul->us = lws_now_usecs() + _us;
+               lws_sul2_schedule(ctx, tsi, LWSSULLI_WAKE_IF_SUSPENDED, sul);
+       }
+
+       lws_pt_unlock(_pt);
+}
+
+#if defined(LWS_WITH_SUL_DEBUGGING)
+
+/*
+ * Sanity checker for any sul left scheduled when its containing object is
+ * freed... code scheduling suls must take care to cancel them when destroying
+ * their object.  This optional debugging helper checks that when an object is
+ * being destroyed, there is no live sul scheduled from inside the object.
+ */
+
+void
+lws_sul_debug_zombies(struct lws_context *ctx, void *po, size_t len,
+                     const char *destroy_description)
+{
+       struct lws_context_per_thread *pt;
+       int n, m;
+
+       for (n = 0; n < ctx->count_threads; n++) {
+               pt = &ctx->pt[n];
+
+               lws_pt_lock(pt, __func__);
+
+               for (m = 0; m < LWS_COUNT_PT_SUL_OWNERS; m++) {
+
+                       lws_start_foreach_dll(struct lws_dll2 *, p,
+                                     lws_dll2_get_head(&pt->pt_sul_owner[m])) {
+                               lws_sorted_usec_list_t *sul =
+                                       lws_container_of(p,
+                                               lws_sorted_usec_list_t, list);
+
+                               if (!po) {
+                                       lwsl_cx_err(ctx, "%s",
+                                                        destroy_description);
+                                       /* just sanity check the list */
+                                       assert(sul->cb);
+                               }
+
+                               /*
+                                * Is the sul resident inside the object that is
+                                * indicated as being deleted?
+                                */
+
+                               if (po &&
+                                   (void *)sul >= po &&
+                                   (size_t)lws_ptr_diff(sul, po) < len) {
+                                       lwsl_cx_err(ctx, "ERROR: Zombie Sul "
+                                                "(on list %d) %s, cb %p\n", m,
+                                                destroy_description, sul->cb);
+                                       /*
+                                        * This assert fires if you have left
+                                        * a sul scheduled to fire later, but
+                                        * are about to destroy the object the
+                                        * sul lives in.  You must take care to
+                                        * do lws_sul_cancel(&sul) on any suls
+                                        * that may be scheduled before
+                                        * destroying the object the sul lives
+                                        * inside.
+                                        *
+                                        * You can look up the cb pointer in
+                                        * your mapfile to find out which
+                                        * callback function the sul was using
+                                        * which usually tells you which sul
+                                        * it is.
+                                        */
+                                       assert(0);
+                               }
+
+                       } lws_end_foreach_dll(p);
+               }
+
+               lws_pt_unlock(pt);
+       }
+}
+
+#endif
diff --git a/lib/core-net/state.c b/lib/core-net/state.c
new file mode 100644 (file)
index 0000000..8eabce2
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+void
+lws_state_reg_notifier(lws_state_manager_t *mgr,
+                      lws_state_notify_link_t *notify_link)
+{
+       lws_dll2_add_head(&notify_link->list, &mgr->notify_list);
+}
+
+void
+lws_state_reg_deregister(lws_state_notify_link_t *nl)
+{
+       lws_dll2_remove(&nl->list);
+}
+
+void
+lws_state_reg_notifier_list(lws_state_manager_t *mgr,
+                           lws_state_notify_link_t * const *notify_link_array)
+{
+       if (notify_link_array)
+               while (*notify_link_array)
+                       lws_state_reg_notifier(mgr, *notify_link_array++);
+}
+
+#if (_LWS_ENABLED_LOGS & (LLL_INFO | LLL_DEBUG))
+static const char *
+_systnm(lws_state_manager_t *mgr, int state, char *temp8)
+{
+       if (!mgr->state_names) {
+               lws_snprintf(temp8, 8, "%d", state);
+               return temp8;
+       }
+
+       return mgr->state_names[state];
+}
+#endif
+
+static int
+_report(lws_state_manager_t *mgr, int a, int b)
+{
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+       char temp8[8];
+#endif
+
+       lws_start_foreach_dll(struct lws_dll2 *, d, mgr->notify_list.head) {
+               lws_state_notify_link_t *l =
+                       lws_container_of(d, lws_state_notify_link_t, list);
+
+               if (l->notify_cb(mgr, l, a, b)) {
+                       /* a dependency took responsibility for retry */
+
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+                       lwsl_cx_info(mgr->context, "%s: %s: rejected '%s' -> '%s'",
+                                    mgr->name, l->name,
+                                    _systnm(mgr, a, temp8),
+                                    _systnm(mgr, b, temp8));
+#endif
+
+                       return 1;
+               }
+
+       } lws_end_foreach_dll(d);
+
+       return 0;
+}
+
+static int
+_lws_state_transition(lws_state_manager_t *mgr, int target)
+{
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
+       char temp8[8];
+#endif
+
+       if (_report(mgr, mgr->state, target))
+               return 1;
+
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
+       if (mgr->context)
+       lwsl_cx_debug(mgr->context, "%s: changed %d '%s' -> %d '%s'", mgr->name,
+                  mgr->state, _systnm(mgr, mgr->state, temp8), target,
+                  _systnm(mgr, target, temp8));
+#endif
+
+       mgr->state = target;
+
+       /* Indicate success by calling the notifers again with both args same */
+       _report(mgr, target, target);
+
+#if defined(LWS_WITH_SYS_SMD)
+       if (mgr->smd_class && mgr->context)
+               (void)lws_smd_msg_printf(mgr->context,
+                                  mgr->smd_class, "{\"state\":\"%s\"}",
+                                  mgr->state_names[target]);
+#endif
+
+       return 0;
+}
+
+int
+lws_state_transition_steps(lws_state_manager_t *mgr, int target)
+{
+       int n = 0;
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+       int i = mgr->state;
+       char temp8[8];
+#endif
+
+       if (mgr->state > target)
+               return 0;
+
+       while (!n && mgr->state != target)
+               n = _lws_state_transition(mgr, mgr->state + 1);
+
+#if (_LWS_ENABLED_LOGS & LLL_INFO)
+       lwsl_cx_info(mgr->context, "%s -> %s", _systnm(mgr, i, temp8),
+                       _systnm(mgr, mgr->state, temp8));
+#endif
+
+       return 0;
+}
+
+int
+lws_state_transition(lws_state_manager_t *mgr, int target)
+{
+       if (mgr->state != target)
+               _lws_state_transition(mgr, target);
+
+       return 0;
+}
diff --git a/lib/core-net/stats.c b/lib/core-net/stats.c
deleted file mode 100644 (file)
index e87fc2e..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-
-#if defined(LWS_WITH_STATS)
-
-LWS_VISIBLE LWS_EXTERN uint64_t
-lws_stats_get(struct lws_context *context, int index)
-{
-       struct lws_context_per_thread *pt = &context->pt[0];
-
-       if (index >= LWSSTATS_SIZE)
-               return 0;
-
-       return pt->lws_stats[index];
-}
-
-static const char * stat_names[] = {
-       "C_CONNECTIONS",
-       "C_API_CLOSE",
-       "C_API_READ",
-       "C_API_LWS_WRITE",
-       "C_API_WRITE",
-       "C_WRITE_PARTIALS",
-       "C_WRITEABLE_CB_REQ",
-       "C_WRITEABLE_CB_EFF_REQ",
-       "C_WRITEABLE_CB",
-       "C_SSL_CONNECTIONS_FAILED",
-       "C_SSL_CONNECTIONS_ACCEPTED",
-       "C_SSL_CONNECTIONS_ACCEPT_SPIN",
-       "C_SSL_CONNS_HAD_RX",
-       "C_TIMEOUTS",
-       "C_SERVICE_ENTRY",
-       "B_READ",
-       "B_WRITE",
-       "B_PARTIALS_ACCEPTED_PARTS",
-       "US_SSL_ACCEPT_LATENCY_AVG",
-       "US_WRITABLE_DELAY_AVG",
-       "US_WORST_WRITABLE_DELAY",
-       "US_SSL_RX_DELAY_AVG",
-       "C_PEER_LIMIT_AH_DENIED",
-       "C_PEER_LIMIT_WSI_DENIED",
-       "C_CONNECTIONS_CLIENT",
-       "C_CONNECTIONS_CLIENT_FAILED",
-};
-
-static int
-quantify(struct lws_context *context, int tsi, char *p, int len, int idx,
-        uint64_t *sum)
-{
-       const lws_humanize_unit_t *schema = humanize_schema_si;
-       struct lws_context_per_thread *pt = &context->pt[tsi];
-       uint64_t u, u1;
-
-       lws_pt_stats_lock(pt);
-       u = pt->lws_stats[idx];
-
-       /* it's supposed to be an average? */
-
-       switch (idx) {
-       case LWSSTATS_US_SSL_ACCEPT_LATENCY_AVG:
-               u1 = pt->lws_stats[LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED];
-               if (u1)
-                       u = u / u1;
-               break;
-       case LWSSTATS_US_SSL_RX_DELAY_AVG:
-               u1 = pt->lws_stats[LWSSTATS_C_SSL_CONNS_HAD_RX];
-               if (u1)
-                       u = u / u1;
-               break;
-       case LWSSTATS_US_WRITABLE_DELAY_AVG:
-               u1 = pt->lws_stats[LWSSTATS_C_WRITEABLE_CB];
-               if (u1)
-                       u = u / u1;
-               break;
-       }
-       lws_pt_stats_unlock(pt);
-
-       *sum += u;
-
-       switch (stat_names[idx][0]) {
-       case 'U':
-               schema = humanize_schema_us;
-               break;
-       case 'B':
-               schema = humanize_schema_si_bytes;
-               break;
-       }
-
-       return lws_humanize(p, len, u, schema);
-}
-
-
-LWS_VISIBLE LWS_EXTERN void
-lws_stats_log_dump(struct lws_context *context)
-{
-       struct lws_vhost *v = context->vhost_list;
-       uint64_t summary[LWSSTATS_SIZE];
-       char bufline[128], *p, *end = bufline + sizeof(bufline) - 1;
-       int n, m;
-
-       if (!context->updated)
-               return;
-
-       context->updated = 0;
-       memset(summary, 0, sizeof(summary));
-
-       lwsl_notice("\n");
-       lwsl_notice("LWS internal statistics dump ----->\n");
-       for (n = 0; n < (int)LWS_ARRAY_SIZE(stat_names); n++) {
-               uint64_t u = 0;
-
-               /* if it's all zeroes, don't report it */
-
-               for (m = 0; m < context->count_threads; m++) {
-                       struct lws_context_per_thread *pt = &context->pt[m];
-
-                       u |= pt->lws_stats[n];
-               }
-               if (!u)
-                       continue;
-
-               p = bufline;
-               p += lws_snprintf(p, lws_ptr_diff(end, p), "%28s: ",
-                                 stat_names[n]);
-
-               for (m = 0; m < context->count_threads; m++)
-                       quantify(context, m, p, lws_ptr_diff(end, p), n, &summary[n]);
-
-               lwsl_notice("%s\n", bufline);
-       }
-
-       lwsl_notice("Simultaneous SSL restriction:  %8d/%d\n",
-                       context->simultaneous_ssl,
-                       context->simultaneous_ssl_restriction);
-
-       lwsl_notice("Live wsi:                      %8d\n",
-                       context->count_wsi_allocated);
-
-       context->updated = 1;
-
-       while (v) {
-               if (v->lserv_wsi &&
-                   v->lserv_wsi->position_in_fds_table != LWS_NO_FDS_POS) {
-
-                       struct lws_context_per_thread *pt =
-                                       &context->pt[(int)v->lserv_wsi->tsi];
-                       struct lws_pollfd *pfd;
-
-                       pfd = &pt->fds[v->lserv_wsi->position_in_fds_table];
-
-                       lwsl_notice("  Listen port %d actual POLLIN:   %d\n",
-                                   v->listen_port,
-                                   (int)pfd->events & LWS_POLLIN);
-               }
-
-               v = v->vhost_next;
-       }
-
-       for (n = 0; n < context->count_threads; n++) {
-               struct lws_context_per_thread *pt = &context->pt[n];
-               struct lws *wl;
-               int m = 0;
-
-               lwsl_notice("PT %d\n", n + 1);
-
-               lws_pt_lock(pt, __func__);
-
-               lwsl_notice("  AH in use / max:                  %d / %d\n",
-                               pt->http.ah_count_in_use,
-                               context->max_http_header_pool);
-
-               wl = pt->http.ah_wait_list;
-               while (wl) {
-                       m++;
-                       wl = wl->http.ah_wait_list;
-               }
-
-               lwsl_notice("  AH wait list count / actual:      %d / %d\n",
-                               pt->http.ah_wait_list_length, m);
-
-               lws_pt_unlock(pt);
-       }
-
-#if defined(LWS_WITH_PEER_LIMITS)
-       m = 0;
-       for (n = 0; n < (int)context->pl_hash_elements; n++) {
-               lws_start_foreach_llp(struct lws_peer **, peer,
-                                     context->pl_hash_table[n]) {
-                       m++;
-               } lws_end_foreach_llp(peer, next);
-       }
-
-       lwsl_notice(" Peers: total active %d\n", m);
-       if (m > 10) {
-               m = 10;
-               lwsl_notice("  (showing 10 peers only)\n");
-       }
-
-       if (m) {
-               for (n = 0; n < (int)context->pl_hash_elements; n++) {
-                       char buf[72];
-
-                       lws_start_foreach_llp(struct lws_peer **, peer,
-                                             context->pl_hash_table[n]) {
-                               struct lws_peer *df = *peer;
-
-                               if (!lws_plat_inet_ntop(df->af, df->addr, buf,
-                                                       sizeof(buf) - 1))
-                                       strcpy(buf, "unknown");
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-                               lwsl_notice("  peer %s: count wsi: %d, count ah: %d\n",
-                                           buf, df->count_wsi,
-                                           df->http.count_ah);
-#else
-                               lwsl_notice("  peer %s: count wsi: %d\n",
-                                           buf, df->count_wsi);
-#endif
-
-                               if (!--m)
-                                       break;
-                       } lws_end_foreach_llp(peer, next);
-               }
-       }
-#endif
-
-       lwsl_notice("\n");
-}
-
-void
-lws_stats_bump(struct lws_context_per_thread *pt, int i, uint64_t bump)
-{
-       lws_pt_stats_lock(pt);
-       pt->lws_stats[i] += bump;
-       if (i != LWSSTATS_C_SERVICE_ENTRY) {
-               pt->updated = 1;
-               pt->context->updated = 1;
-       }
-       lws_pt_stats_unlock(pt);
-}
-
-void
-lws_stats_max(struct lws_context_per_thread *pt, int index, uint64_t val)
-{
-       lws_pt_stats_lock(pt);
-       if (val > pt->lws_stats[index]) {
-               pt->lws_stats[index] = val;
-               pt->updated = 1;
-               pt->context->updated = 1;
-       }
-       lws_pt_stats_unlock(pt);
-}
-
-#endif
-
-
index 283b802..298bf01 100644 (file)
@@ -1,25 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
+
+void
+lws_tls_session_vh_destroy(struct lws_vhost *vh);
 
 const struct lws_role_ops *available_roles[] = {
 #if defined(LWS_ROLE_H2)
@@ -37,21 +43,11 @@ const struct lws_role_ops *available_roles[] = {
 #if defined(LWS_ROLE_RAW_PROXY)
        &role_ops_raw_proxy,
 #endif
-       NULL
-};
-
-const struct lws_event_loop_ops *available_event_libs[] = {
-#if defined(LWS_WITH_POLL)
-       &event_loop_ops_poll,
-#endif
-#if defined(LWS_WITH_LIBUV)
-       &event_loop_ops_uv,
+#if defined(LWS_ROLE_MQTT) && defined(LWS_WITH_CLIENT)
+       &role_ops_mqtt,
 #endif
-#if defined(LWS_WITH_LIBEVENT)
-       &event_loop_ops_event,
-#endif
-#if defined(LWS_WITH_LIBEV)
-       &event_loop_ops_ev,
+#if defined(LWS_WITH_NETLINK)
+       &role_ops_netlink,
 #endif
        NULL
 };
@@ -65,6 +61,25 @@ const struct lws_protocols *available_abstract_protocols[] = {
 };
 #endif
 
+#if defined(LWS_WITH_SECURE_STREAMS)
+const struct lws_protocols *available_secstream_protocols[] = {
+#if defined(LWS_ROLE_H1)
+       &protocol_secstream_h1,
+#endif
+#if defined(LWS_ROLE_H2)
+       &protocol_secstream_h2,
+#endif
+#if defined(LWS_ROLE_WS)
+       &protocol_secstream_ws,
+#endif
+#if defined(LWS_ROLE_MQTT)
+       &protocol_secstream_mqtt,
+#endif
+       &protocol_secstream_raw,
+       NULL
+};
+#endif
+
 static const char * const mount_protocols[] = {
        "http://",
        "https://",
@@ -86,8 +101,10 @@ lws_role_by_name(const char *name)
        if (!strcmp(name, role_ops_raw_skt.name))
                return &role_ops_raw_skt;
 
+#if defined(LWS_ROLE_RAW_FILE)
        if (!strcmp(name, role_ops_raw_file.name))
                return &role_ops_raw_file;
+#endif
 
        return NULL;
 }
@@ -99,17 +116,24 @@ lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn)
        if (!alpn)
                return 0;
 
-       lwsl_info("%s: '%s'\n", __func__, alpn);
+#if !defined(LWS_ESP_PLATFORM)
+       lwsl_wsi_info(wsi, "'%s'", alpn);
+#endif
 
        LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
-               if (ar->alpn && !strcmp(ar->alpn, alpn) && ar->alpn_negotiated)
-                       return ar->alpn_negotiated(wsi, alpn);
+               if (ar->alpn && !strcmp(ar->alpn, alpn) &&
+                   lws_rops_fidx(ar, LWS_ROPS_alpn_negotiated)) {
+#if defined(LWS_WITH_SERVER)
+                       lws_metrics_tag_wsi_add(wsi, "upg", ar->name);
+#endif
+                       return (lws_rops_func_fidx(ar, LWS_ROPS_alpn_negotiated)).
+                                                  alpn_negotiated(wsi, alpn);
+               }
        LWS_FOR_EVERY_AVAILABLE_ROLE_END;
 #endif
        return 0;
 }
 
-//#if !defined(LWS_WITHOUT_SERVER)
 int
 lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot)
 {
@@ -119,21 +143,25 @@ lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot)
         * if the vhost is told to bind accepted sockets to a given role,
         * then look it up by name and try to bind to the specific role.
         */
-       if (lws_check_opt(wsi->vhost->options,
+       if (lws_check_opt(wsi->a.vhost->options,
                          LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG) &&
-           wsi->vhost->listen_accept_role) {
+           wsi->a.vhost->listen_accept_role) {
                const struct lws_role_ops *role =
-                       lws_role_by_name(wsi->vhost->listen_accept_role);
+                       lws_role_by_name(wsi->a.vhost->listen_accept_role);
 
                if (!prot)
-                       prot = wsi->vhost->listen_accept_protocol;
+                       prot = wsi->a.vhost->listen_accept_protocol;
 
                if (!role)
-                       lwsl_err("%s: can't find role '%s'\n", __func__,
-                                 wsi->vhost->listen_accept_role);
+                       lwsl_wsi_err(wsi, "can't find role '%s'",
+                                         wsi->a.vhost->listen_accept_role);
 
-               if (role && role->adoption_bind) {
-                       n = role->adoption_bind(wsi, type, prot);
+               if (!strcmp(wsi->a.vhost->listen_accept_role, "raw-proxy"))
+                       type |= LWS_ADOPT_FLAG_RAW_PROXY;
+
+               if (role && lws_rops_fidx(role, LWS_ROPS_adoption_bind)) {
+                       n = (lws_rops_func_fidx(role, LWS_ROPS_adoption_bind)).
+                                               adoption_bind(wsi, type, prot);
                        if (n < 0)
                                return -1;
                        if (n) /* did the bind */
@@ -141,15 +169,14 @@ lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot)
                }
 
                if (type & _LWS_ADOPT_FINISH) {
-                       lwsl_debug("%s: leaving bound to role %s\n", __func__,
-                                  wsi->role_ops->name);
+                       lwsl_wsi_debug(wsi, "leaving bound to role %s",
+                                           wsi->role_ops->name);
                        return 0;
                }
 
-
-               lwsl_warn("%s: adoption bind to role '%s', "
-                         "protocol '%s', type 0x%x, failed\n", __func__,
-                         wsi->vhost->listen_accept_role, prot, type);
+               lwsl_wsi_warn(wsi, "adoption bind to role '%s', "
+                         "protocol '%s', type 0x%x, failed",
+                         wsi->a.vhost->listen_accept_role, prot, type);
        }
 
        /*
@@ -158,34 +185,44 @@ lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot)
         */
 
        LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
-               if (ar->adoption_bind && ar->adoption_bind(wsi, type, prot))
+               if (lws_rops_fidx(ar, LWS_ROPS_adoption_bind) &&
+                   (lws_rops_func_fidx(ar, LWS_ROPS_adoption_bind)).
+                                           adoption_bind(wsi, type, prot))
                        return 0;
        LWS_FOR_EVERY_AVAILABLE_ROLE_END;
 
        /* fall back to raw socket role if, eg, h1 not configured */
 
-       if (role_ops_raw_skt.adoption_bind &&
-           role_ops_raw_skt.adoption_bind(wsi, type, prot))
+       if (lws_rops_fidx(&role_ops_raw_skt, LWS_ROPS_adoption_bind) &&
+           (lws_rops_func_fidx(&role_ops_raw_skt, LWS_ROPS_adoption_bind)).
+                                   adoption_bind(wsi, type, prot))
                return 0;
 
+#if defined(LWS_ROLE_RAW_FILE)
+
+       lwsl_wsi_notice(wsi, "falling back to raw file role bind");
+
        /* fall back to raw file role if, eg, h1 not configured */
 
-       if (role_ops_raw_file.adoption_bind &&
-           role_ops_raw_file.adoption_bind(wsi, type, prot))
+       if (lws_rops_fidx(&role_ops_raw_file, LWS_ROPS_adoption_bind) &&
+           (lws_rops_func_fidx(&role_ops_raw_file, LWS_ROPS_adoption_bind)).
+                                   adoption_bind(wsi, type, prot))
                return 0;
+#endif
 
        return 1;
 }
-//#endif
 
-#if !defined(LWS_WITHOUT_CLIENT)
+#if defined(LWS_WITH_CLIENT)
 int
 lws_role_call_client_bind(struct lws *wsi,
                          const struct lws_client_connect_info *i)
 {
        LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
-               if (ar->client_bind) {
-                       int m = ar->client_bind(wsi, i);
+               if (lws_rops_fidx(ar, LWS_ROPS_client_bind)) {
+                       int m = (lws_rops_func_fidx(ar, LWS_ROPS_client_bind)).
+                                                       client_bind(wsi, i);
+
                        if (m < 0)
                                return m;
                        if (m)
@@ -195,25 +232,30 @@ lws_role_call_client_bind(struct lws *wsi,
 
        /* fall back to raw socket role if, eg, h1 not configured */
 
-       if (role_ops_raw_skt.client_bind &&
-           role_ops_raw_skt.client_bind(wsi, i))
+       if (lws_rops_fidx(&role_ops_raw_skt, LWS_ROPS_client_bind) &&
+           (lws_rops_func_fidx(&role_ops_raw_skt, LWS_ROPS_client_bind)).
+                                       client_bind(wsi, i))
                return 0;
 
        return 1;
 }
 #endif
 
-LWS_VISIBLE void *
+void *
 lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost,
                            const struct lws_protocols *prot, int size)
 {
        int n = 0;
 
+       if (!vhost || !prot || !vhost->protocols || !prot->name)
+               return NULL;
+
        /* allocate the vh priv array only on demand */
        if (!vhost->protocol_vh_privs) {
                vhost->protocol_vh_privs = (void **)lws_zalloc(
-                               vhost->count_protocols * sizeof(void *),
+                               (size_t)vhost->count_protocols * sizeof(void *),
                                "protocol_vh_privs");
+
                if (!vhost->protocol_vh_privs)
                        return NULL;
        }
@@ -223,25 +265,31 @@ lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost,
 
        if (n == vhost->count_protocols) {
                n = 0;
-               while (n < vhost->count_protocols &&
-                      strcmp(vhost->protocols[n].name, prot->name))
+               while (n < vhost->count_protocols) {
+                       if (vhost->protocols[n].name &&
+                           !strcmp(vhost->protocols[n].name, prot->name))
+                               break;
                        n++;
+               }
 
-               if (n == vhost->count_protocols)
+               if (n == vhost->count_protocols) {
+                       lwsl_vhost_err(vhost, "unknown protocol %p", prot);
                        return NULL;
+               }
        }
 
-       vhost->protocol_vh_privs[n] = lws_zalloc(size, "vh priv");
+       vhost->protocol_vh_privs[n] = lws_zalloc((size_t)size, "vh priv");
        return vhost->protocol_vh_privs[n];
 }
 
-LWS_VISIBLE void *
+void *
 lws_protocol_vh_priv_get(struct lws_vhost *vhost,
                         const struct lws_protocols *prot)
 {
        int n = 0;
 
-       if (!vhost || !vhost->protocol_vh_privs || !prot)
+       if (!vhost || !vhost->protocols ||
+           !vhost->protocol_vh_privs || !prot || !prot->name)
                return NULL;
 
        while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
@@ -249,12 +297,15 @@ lws_protocol_vh_priv_get(struct lws_vhost *vhost,
 
        if (n == vhost->count_protocols) {
                n = 0;
-               while (n < vhost->count_protocols &&
-                      strcmp(vhost->protocols[n].name, prot->name))
+               while (n < vhost->count_protocols) {
+                       if (vhost->protocols[n].name &&
+                           !strcmp(vhost->protocols[n].name, prot->name))
+                               break;
                        n++;
+               }
 
                if (n == vhost->count_protocols) {
-                       lwsl_err("%s: unknown protocol %p\n", __func__, prot);
+                       lwsl_vhost_err(vhost, "unknown protocol %p", prot);
                        return NULL;
                }
        }
@@ -262,6 +313,53 @@ lws_protocol_vh_priv_get(struct lws_vhost *vhost,
        return vhost->protocol_vh_privs[n];
 }
 
+void *
+lws_vhd_find_by_pvo(struct lws_context *cx, const char *protname,
+                   const char *pvo_name, const char *pvo_value)
+{
+       struct lws_vhost *vh;
+       int n;
+
+       /* let's go through all the vhosts */
+
+       vh = cx->vhost_list;
+       while (vh) {
+
+               if (vh->protocol_vh_privs) {
+
+               for (n = 0; n < vh->count_protocols; n++) {
+                       const struct lws_protocol_vhost_options *pv;
+
+                       if (strcmp(vh->protocols[n].name, protname))
+                               continue;
+
+                       /* this vh has an instance of the required protocol */
+
+                       pv = lws_pvo_search(vh->pvo, protname);
+                       if (!pv)
+                               continue;
+
+                       pv = lws_pvo_search(pv->options, pvo_name);
+                       if (!pv)
+                               continue;
+
+                       /* ... he also has a pvo of the right name... */
+                       if (!strcmp(pv->value, pvo_value))
+                               /*
+                                * ... yes, the pvo has the right value too,
+                                * return a pointer to this vhost-protocol
+                                * private alloc (ie, its "vhd")
+                                */
+                               return vh->protocol_vh_privs[n];
+               }
+               } else
+                       lwsl_vhost_notice(vh, "no privs yet");
+               vh = vh->vhost_next;
+       }
+
+       return NULL;
+}
+
 const struct lws_protocol_vhost_options *
 lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
 {
@@ -279,120 +377,169 @@ lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
        return NULL;
 }
 
-/*
- * inform every vhost that hasn't already done it, that
- * his protocols are initializing
- */
-LWS_VISIBLE int
-lws_protocol_init(struct lws_context *context)
+int
+lws_protocol_init_vhost(struct lws_vhost *vh, int *any)
 {
-       struct lws_vhost *vh = context->vhost_list;
        const struct lws_protocol_vhost_options *pvo, *pvo1;
-       struct lws wsi;
-       int n, any = 0;
-
-       if (context->doing_protocol_init)
-               return 0;
-
-       context->doing_protocol_init = 1;
-
-       memset(&wsi, 0, sizeof(wsi));
-       wsi.context = context;
+       int n;
+#if defined(LWS_PLAT_FREERTOS)
+       struct lws_a _lwsa, *lwsa = &_lwsa;
 
-       lwsl_info("%s\n", __func__);
+       memset(&_lwsa, 0, sizeof(_lwsa));
+#else
+       struct lws _lws;
+       struct lws_a *lwsa = &_lws.a;
 
-       while (vh) {
-               wsi.vhost = vh;
+       memset(&_lws, 0, sizeof(_lws));
+#endif
 
-               /* only do the protocol init once for a given vhost */
-               if (vh->created_vhost_protocols ||
-                   (vh->options & LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT))
-                       goto next;
+       lwsa->context = vh->context;
+       lwsa->vhost = vh;
 
-               /* initialize supported protocols on this vhost */
+       /* initialize supported protocols on this vhost */
 
-               for (n = 0; n < vh->count_protocols; n++) {
-                       wsi.protocol = &vh->protocols[n];
-                       if (!vh->protocols[n].name)
-                               continue;
-                       pvo = lws_vhost_protocol_options(vh,
-                                                        vh->protocols[n].name);
-                       if (pvo) {
-                               /*
-                                * linked list of options specific to
-                                * vh + protocol
-                                */
-                               pvo1 = pvo;
-                               pvo = pvo1->options;
-
-                               while (pvo) {
-                                       lwsl_debug(
-                                               "    vhost \"%s\", "
-                                               "protocol \"%s\", "
-                                               "option \"%s\"\n",
-                                                       vh->name,
-                                                       vh->protocols[n].name,
-                                                       pvo->name);
-
-                                       if (!strcmp(pvo->name, "default")) {
-                                               lwsl_info("Setting default "
-                                                  "protocol for vh %s to %s\n",
-                                                  vh->name,
-                                                  vh->protocols[n].name);
-                                               vh->default_protocol_index = n;
-                                       }
-                                       if (!strcmp(pvo->name, "raw")) {
-                                               lwsl_info("Setting raw "
-                                                  "protocol for vh %s to %s\n",
-                                                  vh->name,
-                                                  vh->protocols[n].name);
-                                               vh->raw_protocol_index = n;
-                                       }
-                                       pvo = pvo->next;
+       for (n = 0; n < vh->count_protocols; n++) {
+               lwsa->protocol = &vh->protocols[n];
+               if (!vh->protocols[n].name)
+                       continue;
+               pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
+               if (pvo) {
+                       /*
+                        * linked list of options specific to
+                        * vh + protocol
+                        */
+                       pvo1 = pvo;
+                       pvo = pvo1->options;
+
+                       while (pvo) {
+                               lwsl_vhost_debug(vh, "protocol \"%s\", "
+                                                    "option \"%s\"",
+                                                    vh->protocols[n].name,
+                                                    pvo->name);
+
+                               if (!strcmp(pvo->name, "default")) {
+                                       lwsl_vhost_info(vh, "Setting default "
+                                                            "protocol to %s",
+                                                            vh->protocols[n].name);
+                                       vh->default_protocol_index = (unsigned char)n;
                                }
-
-                               pvo = pvo1->options;
+                               if (!strcmp(pvo->name, "raw")) {
+                                       lwsl_vhost_info(vh, "Setting raw "
+                                                            "protocol to %s",
+                                                            vh->protocols[n].name);
+                                       vh->raw_protocol_index = (unsigned char)n;
+                               }
+                               pvo = pvo->next;
                        }
+               } else
+                       lwsl_vhost_debug(vh, "not instantiating %s",
+                                            vh->protocols[n].name);
 
 #if defined(LWS_WITH_TLS)
-                       any |= !!vh->tls.ssl_ctx;
+               if (any)
+                       *any |= !!vh->tls.ssl_ctx;
 #endif
 
-                       /*
-                        * inform all the protocols that they are doing their
-                        * one-time initialization if they want to.
-                        *
-                        * NOTE the wsi is all zeros except for the context, vh
-                        * + protocol ptrs so lws_get_context(wsi) etc can work
-                        */
-                       if (vh->protocols[n].callback(&wsi,
-                                       LWS_CALLBACK_PROTOCOL_INIT, NULL,
-                                       (void *)pvo, 0)) {
-                               if (vh->protocol_vh_privs[n]) {
+               pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
+
+               /*
+                * inform all the protocols that they are doing their
+                * one-time initialization if they want to.
+                *
+                * NOTE the fakewsi is garbage, except the key pointers that are
+                * prepared in case the protocol handler wants to touch them
+                */
+
+               if (pvo
+#if !defined(LWS_WITH_PLUGINS)
+                               /*
+                                * with plugins, you have to explicitly
+                                * instantiate them per-vhost with pvos.
+                                *
+                                * Without plugins, not setting the vhost pvo
+                                * list at creation enables all the protocols
+                                * by default, for backwards compatibility
+                                */
+                               || !vh->pvo
+#endif
+               ) {
+                       lwsl_vhost_info(vh, "init %s.%s", vh->name,
+                                       vh->protocols[n].name);
+                       if (vh->protocols[n].callback((struct lws *)lwsa,
+                               LWS_CALLBACK_PROTOCOL_INIT, NULL,
+#if !defined(LWS_WITH_PLUGINS)
+                               (void *)(pvo ? pvo->options : NULL),
+#else
+                               (void *)pvo->options,
+#endif
+                               0)) {
+                               if (vh->protocol_vh_privs && vh->protocol_vh_privs[n]) {
                                        lws_free(vh->protocol_vh_privs[n]);
                                        vh->protocol_vh_privs[n] = NULL;
                                }
-                               lwsl_err("%s: protocol %s failed init\n",
-                                        __func__, vh->protocols[n].name);
+                       lwsl_vhost_err(vh, "protocol %s failed init",
+                                       vh->protocols[n].name);
 
                                return 1;
                        }
                }
+       }
+
+       vh->created_vhost_protocols = 1;
+
+       return 0;
+}
+
+/*
+ * inform every vhost that hasn't already done it, that
+ * his protocols are initializing
+ */
+int
+lws_protocol_init(struct lws_context *context)
+{
+       struct lws_vhost *vh = context->vhost_list;
+       int any = 0, r = 0;
+
+       if (context->doing_protocol_init)
+               return 0;
 
-               vh->created_vhost_protocols = 1;
+       context->doing_protocol_init = 1;
+
+       lwsl_cx_info(context, "\n");
+
+       while (vh) {
+
+               /* only do the protocol init once for a given vhost */
+               if (vh->created_vhost_protocols ||
+                   (lws_check_opt(vh->options, LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT)))
+                       goto next;
+
+               if (lws_protocol_init_vhost(vh, &any)) {
+                       lwsl_vhost_warn(vh, "init vhost %s failed", vh->name);
+                       r = -1;
+               }
 next:
                vh = vh->vhost_next;
        }
 
        context->doing_protocol_init = 0;
 
-       if (!context->protocol_init_done && lws_finalize_startup(context))
-               return 1;
+       if (r)
+               lwsl_cx_warn(context, "some protocols did not init");
+
+       if (!context->protocol_init_done) {
+
+               context->protocol_init_done = 1;
+               lws_finalize_startup(context);
 
-       context->protocol_init_done = 1;
+               return 0;
+       }
 
-       if (any)
+#if defined(LWS_WITH_SERVER)
+       if (any) {
                lws_tls_check_all_cert_lifetimes(context);
+       }
+#endif
 
        return 0;
 }
@@ -423,53 +570,113 @@ static const struct lws_protocols protocols_dummy[] = {
 #undef LWS_HAVE_GETENV
 #endif
 
-LWS_VISIBLE struct lws_vhost *
+struct lws_vhost *
 lws_create_vhost(struct lws_context *context,
                 const struct lws_context_creation_info *info)
 {
-       struct lws_vhost *vh = lws_zalloc(sizeof(*vh), "create vhost"),
-                        **vh1 = &context->vhost_list;
+       struct lws_vhost *vh, **vh1 = &context->vhost_list;
        const struct lws_http_mount *mounts;
        const struct lws_protocols *pcols = info->protocols;
 #ifdef LWS_WITH_PLUGINS
        struct lws_plugin *plugin = context->plugin_list;
 #endif
        struct lws_protocols *lwsp;
-       int m, f = !info->pvo, fx = 0, abs_pcol_count = 0;
+       int m, f = !info->pvo, fx = 0, abs_pcol_count = 0, sec_pcol_count = 0;
+       const char *name = "default";
        char buf[96];
-#if (!defined(LWS_WITHOUT_CLIENT) || defined(LWS_WITH_SOCKS5)) && defined(LWS_HAVE_GETENV)
        char *p;
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       extern struct lws_protocols lws_async_dns_protocol;
 #endif
        int n;
 
+       if (info->vhost_name)
+               name = info->vhost_name;
+
+       if (lws_fi(&info->fic, "vh_create_oom"))
+               vh = NULL;
+       else
+               vh = lws_zalloc(sizeof(*vh) + strlen(name) + 1
+#if defined(LWS_WITH_EVENT_LIBS)
+                       + context->event_loop_ops->evlib_size_vh
+#endif
+                       , __func__);
        if (!vh)
-               return NULL;
+               goto early_bail;
+
+       if (info->log_cx)
+               vh->lc.log_cx = info->log_cx;
+       else
+               vh->lc.log_cx = &log_cx;
+
+#if defined(LWS_WITH_EVENT_LIBS)
+       vh->evlib_vh = (void *)&vh[1];
+       vh->name = (const char *)vh->evlib_vh +
+                       context->event_loop_ops->evlib_size_vh;
+#else
+       vh->name = (const char *)&vh[1];
+#endif
+       memcpy((char *)vh->name, name, strlen(name) + 1);
 
 #if LWS_MAX_SMP > 1
-       pthread_mutex_init(&vh->lock, NULL);
+       lws_mutex_refcount_init(&vh->mr);
 #endif
 
        if (!pcols && !info->pprotocols)
                pcols = &protocols_dummy[0];
 
        vh->context = context;
-       if (!info->vhost_name)
-               vh->name = "default";
-       else
-               vh->name = info->vhost_name;
+       {
+               char *end = buf + sizeof(buf) - 1;
+               p = buf;
+
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s", vh->name);
+               if (info->iface)
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "|%s", info->iface);
+               if (info->port && !(info->port & 0xffff))
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "|%u", info->port);
+       }
+
+       __lws_lc_tag(context, &context->lcg[LWSLCG_VHOST], &vh->lc, "%s|%s|%d",
+                    buf, info->iface ? info->iface : "", info->port);
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       vh->fic.name = "vh";
+       if (info->fic.fi_owner.count)
+               /*
+                * This moves all the lws_fi_t from info->fi to the vhost fi,
+                * leaving it empty
+                */
+               lws_fi_import(&vh->fic, &info->fic);
+
+       lws_fi_inherit_copy(&vh->fic, &context->fic, "vh", vh->name);
+       if (lws_fi(&vh->fic, "vh_create_oom"))
+               goto bail;
+#endif
 
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
        vh->http.error_document_404 = info->error_document_404;
 #endif
 
-       if (info->options & LWS_SERVER_OPTION_ONLY_RAW)
-               lwsl_info("%s set to only support RAW\n", vh->name);
+       if (lws_check_opt(info->options, LWS_SERVER_OPTION_ONLY_RAW))
+               lwsl_vhost_info(vh, "set to only support RAW");
 
        vh->iface = info->iface;
-#if !defined(LWS_WITH_ESP32) && \
-    !defined(OPTEE_TA) && !defined(WIN32)
+#if !defined(LWS_PLAT_FREERTOS) && !defined(OPTEE_TA) && !defined(WIN32)
        vh->bind_iface = info->bind_iface;
 #endif
+#if defined(LWS_WITH_CLIENT)
+       if (info->connect_timeout_secs)
+               vh->connect_timeout_secs = (int)info->connect_timeout_secs;
+       else
+               vh->connect_timeout_secs = 20;
+#endif
+       /* apply the context default lws_retry */
+
+       if (info->retry_and_idle_policy)
+               vh->retry_policy = info->retry_and_idle_policy;
+       else
+               vh->retry_policy = &context->default_retry;
 
        /*
         * let's figure out how many protocols the user is handing us, using the
@@ -487,20 +694,21 @@ lws_create_vhost(struct lws_context *context,
                        vh->count_protocols++)
                                ;
 
-       vh->options = info->options;
-       vh->pvo = info->pvo;
-       vh->headers = info->headers;
-       vh->user = info->user;
-       vh->finalize = info->finalize;
-       vh->finalize_arg = info->finalize_arg;
-       vh->listen_accept_role = info->listen_accept_role;
-       vh->listen_accept_protocol = info->listen_accept_protocol;
-       vh->unix_socket_perms = info->unix_socket_perms;
+       vh->options                     = info->options;
+       vh->pvo                         = info->pvo;
+       vh->headers                     = info->headers;
+       vh->user                        = info->user;
+       vh->finalize                    = info->finalize;
+       vh->finalize_arg                = info->finalize_arg;
+       vh->listen_accept_role          = info->listen_accept_role;
+       vh->listen_accept_protocol      = info->listen_accept_protocol;
+       vh->unix_socket_perms           = info->unix_socket_perms;
+       vh->fo_listen_queue             = info->fo_listen_queue;
 
        LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
-               if (ar->init_vhost)
-                       if (ar->init_vhost(vh, info))
-                               return NULL;
+       if (lws_rops_fidx(ar, LWS_ROPS_init_vhost) &&
+           (lws_rops_func_fidx(ar, LWS_ROPS_init_vhost)).init_vhost(vh, info))
+               return NULL;
        LWS_FOR_EVERY_AVAILABLE_ROLE_END;
 
 
@@ -510,7 +718,7 @@ lws_create_vhost(struct lws_context *context,
                vh->keepalive_timeout = 5;
 
        if (info->timeout_secs_ah_idle)
-               vh->timeout_secs_ah_idle = info->timeout_secs_ah_idle;
+               vh->timeout_secs_ah_idle = (int)info->timeout_secs_ah_idle;
        else
                vh->timeout_secs_ah_idle = 10;
 
@@ -532,11 +740,11 @@ lws_create_vhost(struct lws_context *context,
 
        if (n) {
                vh->tls.key_path = vh->tls.alloc_cert_path =
-                                       lws_malloc(n, "vh paths");
+                                       lws_malloc((unsigned int)n, "vh paths");
                if (info->ssl_cert_filepath) {
                        n = (int)strlen(info->ssl_cert_filepath) + 1;
                        memcpy(vh->tls.alloc_cert_path,
-                              info->ssl_cert_filepath, n);
+                              info->ssl_cert_filepath, (unsigned int)n);
                        vh->tls.key_path += n;
                }
                if (info->ssl_private_key_filepath)
@@ -551,23 +759,31 @@ lws_create_vhost(struct lws_context *context,
 #if defined(LWS_WITH_ABSTRACT)
        abs_pcol_count = (int)LWS_ARRAY_SIZE(available_abstract_protocols) - 1;
 #endif
+#if defined(LWS_WITH_SECURE_STREAMS)
+       sec_pcol_count = (int)LWS_ARRAY_SIZE(available_secstream_protocols) - 1;
+#endif
 
        /*
         * give the vhost a unified list of protocols including:
         *
+        * - internal, async_dns if enabled (first vhost only)
         * - internal, abstracted ones
         * - the ones that came from plugins
         * - his user protocols
         */
-       lwsp = lws_zalloc(sizeof(struct lws_protocols) *
-                               (vh->count_protocols +
-                                  abs_pcol_count +
-                                  context->plugin_protocol_count +
-                                  fx + 1),
-                         "vhost-specific plugin table");
+
+       if (lws_fi(&vh->fic, "vh_create_pcols_oom"))
+               lwsp = NULL;
+       else
+               lwsp = lws_zalloc(sizeof(struct lws_protocols) *
+                               ((unsigned int)vh->count_protocols +
+                                  (unsigned int)abs_pcol_count +
+                                  (unsigned int)sec_pcol_count +
+                                  (unsigned int)context->plugin_protocol_count +
+                                  (unsigned int)fx + 1), "vh plugin table");
        if (!lwsp) {
                lwsl_err("OOM\n");
-               return NULL;
+               goto bail;
        }
 
        /*
@@ -579,7 +795,7 @@ lws_create_vhost(struct lws_context *context,
                for (n = 0; n < m; n++)
                        memcpy(&lwsp[n], info->pprotocols[n], sizeof(lwsp[0]));
        } else
-               memcpy(lwsp, pcols, sizeof(struct lws_protocols) * m);
+               memcpy(lwsp, pcols, sizeof(struct lws_protocols) * (unsigned int)m);
 
        /*
         * 2: abstract protocols
@@ -591,6 +807,24 @@ lws_create_vhost(struct lws_context *context,
                vh->count_protocols++;
        }
 #endif
+       /*
+        * 3: async dns protocol (first vhost only)
+        */
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       if (!context->vhost_list) {
+               memcpy(&lwsp[m++], &lws_async_dns_protocol,
+                      sizeof(struct lws_protocols));
+               vh->count_protocols++;
+       }
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       for (n = 0; n < sec_pcol_count; n++) {
+               memcpy(&lwsp[m++], available_secstream_protocols[n],
+                      sizeof(*lwsp));
+               vh->count_protocols++;
+       }
+#endif
 
        /*
         * 3: For compatibility, all protocols enabled on vhost if only
@@ -604,15 +838,18 @@ lws_create_vhost(struct lws_context *context,
 #ifdef LWS_WITH_PLUGINS
        if (plugin) {
                while (plugin) {
-                       for (n = 0; n < plugin->caps.count_protocols; n++) {
+                       const lws_plugin_protocol_t *plpr =
+                               (const lws_plugin_protocol_t *)plugin->hdr;
+
+                       for (n = 0; n < plpr->count_protocols; n++) {
                                /*
                                 * for compatibility's sake, no pvo implies
                                 * allow all protocols
                                 */
                                if (f || lws_vhost_protocol_options(vh,
-                                   plugin->caps.protocols[n].name)) {
+                                               plpr->protocols[n].name)) {
                                        memcpy(&lwsp[m],
-                                              &plugin->caps.protocols[n],
+                                              &plpr->protocols[n],
                                               sizeof(struct lws_protocols));
                                        m++;
                                        vh->count_protocols++;
@@ -633,14 +870,31 @@ lws_create_vhost(struct lws_context *context,
 
        vh->same_vh_protocol_owner = (struct lws_dll2_owner *)
                        lws_zalloc(sizeof(struct lws_dll2_owner) *
-                                  vh->count_protocols, "same vh list");
+                                  (unsigned int)vh->count_protocols, "same vh list");
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
        vh->http.mount_list = info->mounts;
 #endif
 
+#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_SERVER)
+       {
+               char *end = buf + sizeof(buf) - 1;
+               p = buf;
+
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "vh.%s", vh->name);
+               if (info->iface)
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".%s", info->iface);
+               if (info->port && !(info->port & 0xffff))
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".%u", info->port);
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ".rx");
+               vh->mt_traffic_rx = lws_metric_create(context, 0, buf);
+               p[-2] = 't';
+               vh->mt_traffic_tx = lws_metric_create(context, 0, buf);
+       }
+#endif
+
 #ifdef LWS_WITH_UNIX_SOCK
        if (LWS_UNIX_SOCK_ENABLED(vh)) {
-               lwsl_info("Creating Vhost '%s' path \"%s\", %d protocols\n",
+               lwsl_vhost_info(vh, "Creating '%s' path \"%s\", %d protocols",
                                vh->name, vh->iface, vh->count_protocols);
        } else
 #endif
@@ -656,33 +910,33 @@ lws_create_vhost(struct lws_context *context,
                        lws_snprintf(buf, sizeof(buf), "port %u", info->port);
                        break;
                }
-               lwsl_info("Creating Vhost '%s' %s, %d protocols, IPv6 %s\n",
+               lwsl_vhost_info(vh, "Creating Vhost '%s' %s, %d protocols, IPv6 %s",
                            vh->name, buf, vh->count_protocols,
                            LWS_IPV6_ENABLED(vh) ? "on" : "off");
        }
        mounts = info->mounts;
        while (mounts) {
                (void)mount_protocols[0];
-               lwsl_info("   mounting %s%s to %s\n",
+               lwsl_vhost_info(vh, "   mounting %s%s to %s",
                          mount_protocols[mounts->origin_protocol],
-                         mounts->origin, mounts->mountpoint);
+                         mounts->origin ? mounts->origin : "none",
+                         mounts->mountpoint);
 
                mounts = mounts->mount_next;
        }
 
        vh->listen_port = info->port;
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       vh->http.http_proxy_port = 0;
-       vh->http.http_proxy_address[0] = '\0';
-#endif
+
 #if defined(LWS_WITH_SOCKS5)
        vh->socks_proxy_port = 0;
        vh->socks_proxy_address[0] = '\0';
 #endif
 
-#if !defined(LWS_WITHOUT_CLIENT)
+#if defined(LWS_WITH_CLIENT) && defined(LWS_CLIENT_HTTP_PROXYING)
        /* either use proxy from info, or try get it from env var */
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       vh->http.http_proxy_port = 0;
+       vh->http.http_proxy_address[0] = '\0';
        /* http proxy */
        if (info->http_proxy_address) {
                /* override for backwards compatibility */
@@ -693,29 +947,20 @@ lws_create_vhost(struct lws_context *context,
 #endif
        {
 #ifdef LWS_HAVE_GETENV
-               p = getenv("http_proxy");
+#if defined(__COVERITY__)
+               p = NULL;
+#else
+               p = getenv("http_proxy"); /* coverity[tainted_scalar] */
                if (p) {
                        lws_strncpy(buf, p, sizeof(buf));
-
                        lws_set_proxy(vh, buf);
                }
 #endif
+#endif
        }
 #endif
 #if defined(LWS_WITH_SOCKS5)
-       /* socks proxy */
-       if (info->socks_proxy_address) {
-               /* override for backwards compatibility */
-               if (info->socks_proxy_port)
-                       vh->socks_proxy_port = info->socks_proxy_port;
-               lws_set_socks(vh, info->socks_proxy_address);
-       } else {
-#ifdef LWS_HAVE_GETENV
-               p = getenv("socks_proxy");
-               if (p && strlen(p) > 0 && strlen(p) < 95)
-                       lws_set_socks(vh, p);
-#endif
-       }
+       lws_socks5c_ads_server(vh, info);
 #endif
 
        vh->ka_time = info->ka_time;
@@ -723,42 +968,56 @@ lws_create_vhost(struct lws_context *context,
        vh->ka_probes = info->ka_probes;
 
        if (vh->options & LWS_SERVER_OPTION_STS)
-               lwsl_notice("   STS enabled\n");
+               lwsl_vhost_notice(vh, "   STS enabled");
 
 #ifdef LWS_WITH_ACCESS_LOG
        if (info->log_filepath) {
-               vh->log_fd = lws_open(info->log_filepath,
+               if (lws_fi(&vh->fic, "vh_create_access_log_open_fail"))
+                       vh->log_fd = (int)LWS_INVALID_FILE;
+               else
+                       vh->log_fd = lws_open(info->log_filepath,
                                  O_CREAT | O_APPEND | O_RDWR, 0600);
                if (vh->log_fd == (int)LWS_INVALID_FILE) {
-                       lwsl_err("unable to open log filepath %s\n",
-                                info->log_filepath);
+                       lwsl_vhost_err(vh, "unable to open log filepath %s",
+                                          info->log_filepath);
                        goto bail;
                }
 #ifndef WIN32
-               if (context->uid != -1)
+               if (context->uid != (uid_t)-1)
                        if (chown(info->log_filepath, context->uid,
                                  context->gid) == -1)
-                               lwsl_err("unable to chown log file %s\n",
-                                               info->log_filepath);
+                               lwsl_vhost_err(vh, "unable to chown log file %s",
+                                                  info->log_filepath);
 #endif
        } else
                vh->log_fd = (int)LWS_INVALID_FILE;
 #endif
-       if (lws_context_init_server_ssl(info, vh)) {
-               lwsl_err("%s: lws_context_init_server_ssl failed\n", __func__);
+       if (lws_fi(&vh->fic, "vh_create_ssl_srv") ||
+           lws_context_init_server_ssl(info, vh)) {
+               lwsl_vhost_err(vh, "lws_context_init_server_ssl failed");
                goto bail1;
        }
-       if (lws_context_init_client_ssl(info, vh)) {
-               lwsl_err("%s: lws_context_init_client_ssl failed\n", __func__);
+       if (lws_fi(&vh->fic, "vh_create_ssl_cli") ||
+           lws_context_init_client_ssl(info, vh)) {
+               lwsl_vhost_err(vh, "lws_context_init_client_ssl failed");
                goto bail1;
        }
-       lws_context_lock(context, "create_vhost");
-       n = _lws_vhost_init_server(info, vh);
+#if defined(LWS_WITH_SERVER)
+       lws_context_lock(context, __func__);
+       if (lws_fi(&vh->fic, "vh_create_srv_init"))
+               n = -1;
+       else
+               n = _lws_vhost_init_server(info, vh);
        lws_context_unlock(context);
        if (n < 0) {
-               lwsl_err("init server failed\n");
+               lwsl_vhost_err(vh, "init server failed\n");
                goto bail1;
        }
+#endif
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       n = !!context->vhost_list;
+#endif
 
        while (1) {
                if (!(*vh1)) {
@@ -768,11 +1027,17 @@ lws_create_vhost(struct lws_context *context,
                vh1 = &(*vh1)->vhost_next;
        };
 
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       if (!n)
+               lws_async_dns_init(context);
+#endif
+
        /* for the case we are adding a vhost much later, after server init */
 
        if (context->protocol_init_done)
-               if (lws_protocol_init(context)) {
-                       lwsl_err("%s: lws_protocol_init failed\n", __func__);
+               if (lws_fi(&vh->fic, "vh_create_protocol_init") ||
+                   lws_protocol_init(context)) {
+                       lwsl_vhost_err(vh, "lws_protocol_init failed");
                        goto bail1;
                }
 
@@ -783,15 +1048,18 @@ bail1:
 
        return NULL;
 
-#ifdef LWS_WITH_ACCESS_LOG
 bail:
+       __lws_lc_untag(vh->context, &vh->lc);
+       lws_fi_destroy(&vh->fic);
        lws_free(vh);
-#endif
+
+early_bail:
+       lws_fi_destroy(&info->fic);
 
        return NULL;
 }
 
-LWS_VISIBLE int
+int
 lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
                          struct lws_vhost *vhost)
 {
@@ -803,33 +1071,34 @@ lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
        return lws_context_init_client_ssl(&i, vhost);
 }
 
-LWS_VISIBLE void
+void
 lws_cancel_service_pt(struct lws *wsi)
 {
-       lws_plat_pipe_signal(wsi);
+       lws_plat_pipe_signal(wsi->a.context, wsi->tsi);
 }
 
-LWS_VISIBLE void
+void
 lws_cancel_service(struct lws_context *context)
 {
        struct lws_context_per_thread *pt = &context->pt[0];
-       short m = context->count_threads;
+       short m;
 
-       if (context->being_destroyed1)
+       if (context->service_no_longer_possible)
                return;
 
-       lwsl_info("%s\n", __func__);
+       lwsl_cx_debug(context, "\n");
 
-       while (m--) {
+       for (m = 0; m < context->count_threads; m++) {
                if (pt->pipe_wsi)
-                       lws_plat_pipe_signal(pt->pipe_wsi);
+                       lws_plat_pipe_signal(pt->context, m);
                pt++;
        }
 }
 
 int
-lws_create_event_pipes(struct lws_context *context)
+__lws_create_event_pipes(struct lws_context *context)
 {
+       struct lws_context_per_thread *pt;
        struct lws *wsi;
        int n;
 
@@ -838,26 +1107,29 @@ lws_create_event_pipes(struct lws_context *context)
         * not bound to a vhost or protocol (both are NULL)
         */
 
+#if LWS_MAX_SMP > 1
        for (n = 0; n < context->count_threads; n++) {
-               if (context->pt[n].pipe_wsi)
-                       continue;
+#else
+       n = 0;
+       {
+#endif
+               pt = &context->pt[n];
 
-               wsi = lws_zalloc(sizeof(*wsi), "event pipe wsi");
-               if (!wsi) {
-                       lwsl_err("%s: Out of mem\n", __func__);
+               if (pt->pipe_wsi)
+                       return 0;
+
+               wsi = __lws_wsi_create_with_role(context, n, &role_ops_pipe,
+                                                       NULL);
+               if (!wsi)
                        return 1;
-               }
-               wsi->context = context;
-               lws_role_transition(wsi, 0, LRS_UNCONNECTED, &role_ops_pipe);
-               wsi->protocol = NULL;
-               wsi->tsi = n;
-               wsi->vhost = NULL;
+
+               __lws_lc_tag(context, &context->lcg[LWSLCG_WSI], &wsi->lc,
+                               "pipe");
+
                wsi->event_pipe = 1;
-               wsi->desc.sockfd = LWS_SOCK_INVALID;
-               context->pt[n].pipe_wsi = wsi;
-               context->count_wsi_allocated++;
+               pt->pipe_wsi = wsi;
 
-               if (lws_plat_pipe_create(wsi))
+               if (!lws_plat_pipe_create(wsi)) {
                        /*
                         * platform code returns 0 if it actually created pipes
                         * and initialized pt->dummy_pipe_fds[].  If it used
@@ -866,81 +1138,210 @@ lws_create_event_pipes(struct lws_context *context)
                         * related to dummy_pipe_fds[], adding it to the fds,
                         * etc.
                         */
-                       continue;
-
-               wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0];
-               lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd);
 
-#if !defined(LWS_AMAZON_RTOS)
-               if (context->event_loop_ops->accept)
-                       if (context->event_loop_ops->accept(wsi))
-                               return 1;
-#endif
+                       wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0];
+                       // lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd);
 
-               if (__insert_wsi_socket_into_fds(context, wsi))
-                       return 1;
+                       if (lws_wsi_inject_to_loop(pt, wsi))
+                                       goto bail;
+               }
        }
 
        return 0;
+
+bail:
+
+       return 1;
 }
 
 void
 lws_destroy_event_pipe(struct lws *wsi)
 {
-       lwsl_info("%s\n", __func__);
-       __remove_wsi_socket_from_fds(wsi);
+       int n;
+
+       lwsl_wsi_info(wsi, "in");
+
+       n = lws_wsi_extract_from_loop(wsi);
+       lws_plat_pipe_close(wsi);
+       if (!n)
+               lws_free(wsi);
+}
+
+/*
+ * Start close process for any wsi bound to this vhost that belong to the
+ * service thread we are called from.  Because of async event lib close, or
+ * protocol staged close on wsi, latency with pts joining in closing their
+ * wsi on the vhost, this may take some time.
+ *
+ * When the wsi count bound to the vhost (from all pts) drops to zero, the
+ * vhost destruction will be finalized.
+ */
+
+void
+__lws_vhost_destroy_pt_wsi_dieback_start(struct lws_vhost *vh)
+{
+#if LWS_MAX_SMP > 1
+       /* calling pt thread has done its wsi dieback */
+       int tsi = lws_pthread_self_to_tsi(vh->context);
+#else
+       int tsi = 0;
+#endif
+       struct lws_context *ctx = vh->context;
+       struct lws_context_per_thread *pt = &ctx->pt[tsi];
+       unsigned int n;
 
-       if (wsi->context->event_loop_ops->wsi_logical_close) {
-               wsi->context->event_loop_ops->wsi_logical_close(wsi);
-               lws_plat_pipe_close(wsi);
+#if LWS_MAX_SMP > 1
+       if (vh->close_flow_vs_tsi[lws_pthread_self_to_tsi(vh->context)])
+               /* this pt has already done its bit */
                return;
+#endif
+
+#if defined(LWS_WITH_CLIENT)
+       /*
+        * destroy any wsi that are associated with us but have no socket
+        * (and will otherwise be missed for destruction)
+        */
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                             vh->vh_awaiting_socket_owner.head) {
+               struct lws *w =
+                       lws_container_of(d, struct lws, vh_awaiting_socket);
+
+               if (w->tsi == tsi) {
+
+                       lwsl_vhost_debug(vh, "closing aso");
+                       lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
+                                          "awaiting skt");
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+#endif
+
+       /*
+        * Close any wsi on this pt bound to the vhost
+        */
+
+       n = 0;
+       while (n < pt->fds_count) {
+               struct lws *wsi = wsi_from_fd(ctx, pt->fds[n].fd);
+
+               if (wsi && wsi->tsi == tsi && wsi->a.vhost == vh) {
+
+                       lwsl_wsi_debug(wsi, "pt %d: closin, role %s", tsi,
+                                           wsi->role_ops->name);
+
+                       lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
+
+                       if (pt->pipe_wsi == wsi)
+                               pt->pipe_wsi = NULL;
+               }
+               n++;
        }
 
-       if (wsi->context->event_loop_ops->destroy_wsi)
-               wsi->context->event_loop_ops->destroy_wsi(wsi);
-       lws_plat_pipe_close(wsi);
-       wsi->context->count_wsi_allocated--;
-       lws_free(wsi);
+#if LWS_MAX_SMP > 1
+       /* calling pt thread has done its wsi dieback */
+       vh->close_flow_vs_tsi[lws_pthread_self_to_tsi(vh->context)] = 1;
+#endif
 }
 
+#if defined(LWS_WITH_NETWORK)
+
+/* returns nonzero if v1 and v2 can share listen sockets */
+int
+lws_vhost_compare_listen(struct lws_vhost *v1, struct lws_vhost *v2)
+{
+       return ((!v1->iface && !v2->iface) ||
+                (v1->iface && v2->iface && !strcmp(v1->iface, v2->iface))) &&
+               v1->listen_port == v2->listen_port;
+}
+
+/* helper to interate every listen socket on any vhost and call cb on it */
+int
+lws_vhost_foreach_listen_wsi(struct lws_context *cx, void *arg,
+                            lws_dll2_foreach_cb_t cb)
+{
+       struct lws_vhost *v = cx->vhost_list;
+       int n;
+
+       while (v) {
+
+               n = lws_dll2_foreach_safe(&v->listen_wsi, arg, cb);
+               if (n)
+                       return n;
+
+               v = v->vhost_next;
+       }
+
+       return 0;
+}
+
+#endif
+
+/*
+ * Mark the vhost as being destroyed, so things trying to use it abort.
+ *
+ * Dispose of the listen socket.
+ */
 
 void
 lws_vhost_destroy1(struct lws_vhost *vh)
 {
        struct lws_context *context = vh->context;
+       int n;
 
-       lwsl_info("%s\n", __func__);
+       lwsl_vhost_info(vh, "\n");
 
        lws_context_lock(context, "vhost destroy 1"); /* ---------- context { */
 
        if (vh->being_destroyed)
                goto out;
 
+       /*
+        * let's lock all the pts, to enforce pt->vh order... pt is refcounted
+        * so it's OK if we acquire it later inside this
+        */
+
+       for (n = 0; n < context->count_threads; n++)
+               lws_pt_lock((&context->pt[n]), __func__);
+
        lws_vhost_lock(vh); /* -------------- vh { */
 
+#if defined(LWS_WITH_TLS_SESSIONS) && defined(LWS_WITH_TLS)
+       lws_tls_session_vh_destroy(vh);
+#endif
+
        vh->being_destroyed = 1;
-#if defined(LWS_WITH_NETWORK)
+       lws_dll2_add_tail(&vh->vh_being_destroyed_list,
+                         &context->owner_vh_being_destroyed);
+
+#if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_SERVER)
        /*
         * PHASE 1: take down or reassign any listen wsi
         *
-        * Are there other vhosts that are piggybacking on our listen socket?
-        * If so we need to hand the listen socket off to one of the others
+        * Are there other vhosts that are piggybacking on our listen sockets?
+        * If so we need to hand each listen socket off to one of the others
         * so it will remain open.
         *
-        * If not, leave it attached to the closing vhost, the vh being marked
-        * being_destroyed will defeat any service and it will get closed in
-        * later phases.
+        * If not, close the listen socket now.
+        *
+        * Either way the listen socket response to the vhost close is
+        * immediately performed.
         */
 
-       if (vh->lserv_wsi)
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                             lws_dll2_get_head(&vh->listen_wsi)) {
+               struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+
+               /*
+                * For each of our listen sockets, check every other vhost to
+                * see if another vhost should be given our listen socket.
+                *
+                * ipv4 and ipv6 sockets will both match and be migrated.
+                */
+
                lws_start_foreach_ll(struct lws_vhost *, v,
                                     context->vhost_list) {
-                       if (v != vh &&
-                           !v->being_destroyed &&
-                           v->listen_port == vh->listen_port &&
-                           ((!v->iface && !vh->iface) ||
-                           (v->iface && vh->iface &&
-                           !strcmp(v->iface, vh->iface)))) {
+                       if (v != vh && !v->being_destroyed &&
+                           lws_vhost_compare_listen(v, vh)) {
                                /*
                                 * this can only be a listen wsi, which is
                                 * restricted... it has no protocol or other
@@ -948,32 +1349,58 @@ lws_vhost_destroy1(struct lws_vhost *vh)
                                 * swap it to a vhost that has the same
                                 * iface + port, but is not closing.
                                 */
-                               assert(v->lserv_wsi == NULL);
-                               v->lserv_wsi = vh->lserv_wsi;
 
-                               lwsl_notice("%s: listen skt from %s to %s\n",
-                                           __func__, vh->name, v->name);
+                               lwsl_vhost_notice(vh, "listen skt migrate -> %s",
+                                                     lws_vh_tag(v));
 
-                               if (v->lserv_wsi) {
-                                       lws_vhost_unbind_wsi(vh->lserv_wsi);
-                                       lws_vhost_bind_wsi(v, v->lserv_wsi);
-                               }
+                               lws_dll2_remove(&wsi->listen_list);
+                               lws_dll2_add_tail(&wsi->listen_list,
+                                                 &v->listen_wsi);
 
+                               /* req cx + vh lock */
+                               /*
+                                * If the vhost sees it's being destroyed and
+                                * in the unbind the number of wsis bound to
+                                * it falls to zero, it will destroy the
+                                * vhost opportunistically before we can
+                                * complete the transfer.  Add a fake wsi
+                                * bind temporarily to disallow this...
+                                */
+                               v->count_bound_wsi++;
+                               __lws_vhost_unbind_wsi(wsi);
+                               lws_vhost_bind_wsi(v, wsi);
+                               /*
+                                * ... remove the fake wsi bind
+                                */
+                               v->count_bound_wsi--;
                                break;
                        }
                } lws_end_foreach_ll(v, vhost_next);
 
+       } lws_end_foreach_dll_safe(d, d1);
+
+       /*
+        * If any listen wsi left we couldn't pass to other vhosts, close them
+        */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  lws_dll2_get_head(&vh->listen_wsi)) {
+               struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+
+               lws_dll2_remove(&wsi->listen_list);
+               lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+#endif
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       lws_sul_cancel(&vh->sul_unref);
 #endif
 
        lws_vhost_unlock(vh); /* } vh -------------- */
 
-       /*
-        * lws_check_deferred_free() will notice there is a vhost that is
-        * marked for destruction during the next 1s, for all tsi.
-        *
-        * It will start closing all wsi on this vhost.  When the last wsi
-        * is closed, it will trigger lws_vhost_destroy2()
-        */
+       for (n = 0; n < context->count_threads; n++)
+               lws_pt_unlock((&context->pt[n]));
 
 out:
        lws_context_unlock(context); /* --------------------------- context { */
@@ -991,34 +1418,39 @@ destroy_ais(struct lws_dll2 *d, void *user)
 }
 #endif
 
+/*
+ * Either start close or destroy any wsi on the vhost that belong to this pt,
+ * if SMP mark the vh that we have done it for
+ *
+ * Must not have lock on vh
+ */
+
 void
 __lws_vhost_destroy2(struct lws_vhost *vh)
 {
        const struct lws_protocols *protocol = NULL;
        struct lws_context *context = vh->context;
-       struct lws_deferred_free *df;
        struct lws wsi;
        int n;
 
-       /*
-        * destroy any pending timed events
-        */
+       vh->being_destroyed = 0;
 
-       while (vh->timed_vh_protocol_list)
-               __lws_timed_callback_remove(vh, vh->timed_vh_protocol_list);
+       // lwsl_info("%s: %s\n", __func__, vh->name);
 
        /*
         * let the protocols destroy the per-vhost protocol objects
         */
 
        memset(&wsi, 0, sizeof(wsi));
-       wsi.context = vh->context;
-       wsi.vhost = vh; /* not a real bound wsi */
+       wsi.a.context = vh->context;
+       wsi.a.vhost = vh; /* not a real bound wsi */
        protocol = vh->protocols;
        if (protocol && vh->created_vhost_protocols) {
                n = 0;
                while (n < vh->count_protocols) {
-                       wsi.protocol = protocol;
+                       wsi.a.protocol = protocol;
+
+                       lwsl_vhost_debug(vh, "protocol destroy");
 
                        if (protocol->callback)
                                protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
@@ -1041,22 +1473,12 @@ __lws_vhost_destroy2(struct lws_vhost *vh)
 
        /* add ourselves to the pending destruction list */
 
-       vh->vhost_next = vh->context->vhost_pending_destruction_list;
-       vh->context->vhost_pending_destruction_list = vh;
-
-       lwsl_info("%s: %p\n", __func__, vh);
+       if (vh->context->vhost_pending_destruction_list != vh) {
+               vh->vhost_next = vh->context->vhost_pending_destruction_list;
+               vh->context->vhost_pending_destruction_list = vh;
+       }
 
-       /* if we are still on deferred free list, remove ourselves */
-
-       lws_start_foreach_llp(struct lws_deferred_free **, pdf,
-                             context->deferred_free_list) {
-               if ((*pdf)->payload == vh) {
-                       df = *pdf;
-                       *pdf = df->next;
-                       lws_free(df);
-                       break;
-               }
-       } lws_end_foreach_llp(pdf, next);
+       //lwsl_debug("%s: do dfl '%s'\n", __func__, vh->name);
 
        /* remove ourselves from the pending destruction list */
 
@@ -1090,14 +1512,18 @@ __lws_vhost_destroy2(struct lws_vhost *vh)
        lws_ssl_SSL_CTX_destroy(vh);
        lws_free(vh->same_vh_protocol_owner);
 
-       if (context->plugin_list ||
+       if (
+#if defined(LWS_WITH_PLUGINS)
+               context->plugin_list ||
+#endif
            (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS) ||
            vh->allocated_vhost_protocols)
                lws_free((void *)vh->protocols);
 #if defined(LWS_WITH_NETWORK)
        LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
-               if (ar->destroy_vhost)
-                       ar->destroy_vhost(vh);
+       if (lws_rops_fidx(ar, LWS_ROPS_destroy_vhost))
+               lws_rops_func_fidx(ar, LWS_ROPS_destroy_vhost).
+                                                       destroy_vhost(vh);
        LWS_FOR_EVERY_AVAILABLE_ROLE_END;
 #endif
 
@@ -1111,14 +1537,14 @@ __lws_vhost_destroy2(struct lws_vhost *vh)
 #endif
 
 #if LWS_MAX_SMP > 1
-       pthread_mutex_destroy(&vh->lock);
+       lws_mutex_refcount_destroy(&vh->mr);
 #endif
 
 #if defined(LWS_WITH_UNIX_SOCK)
        if (LWS_UNIX_SOCK_ENABLED(vh)) {
                n = unlink(vh->iface);
                if (n)
-                       lwsl_info("Closing unix socket %s: errno %d\n",
+                       lwsl_vhost_info(vh, "Closing unix socket %s: errno %d\n",
                                  vh->iface, errno);
        }
 #endif
@@ -1139,180 +1565,377 @@ __lws_vhost_destroy2(struct lws_vhost *vh)
        lws_dll2_foreach_safe(&vh->abstract_instances_owner, NULL, destroy_ais);
 #endif
 
-       lwsl_info("  %s: Freeing vhost %p\n", __func__, vh);
-
-       memset(vh, 0, sizeof(*vh));
-       lws_free(vh);
-}
-
-/*
- * each service thread calls this once a second or so
- */
-
-int
-lws_check_deferred_free(struct lws_context *context, int tsi, int force)
-{
-       struct lws_context_per_thread *pt;
-       int n;
-
-       /*
-        * If we see a vhost is being destroyed, forcibly close every wsi on
-        * this tsi associated with this vhost.  That will include the listen
-        * socket if it is still associated with the closing vhost.
-        *
-        * For SMP, we do this once per tsi per destroyed vhost.  The reference
-        * counting on the vhost as the bound wsi close will notice that there
-        * are no bound wsi left, that vhost destruction can complete,
-        * and perform it.  It doesn't matter which service thread does that
-        * because there is nothing left using the vhost to conflict.
-        */
-
-       lws_context_lock(context, "check deferred free"); /* ------ context { */
-
-       lws_start_foreach_ll_safe(struct lws_vhost *, v, context->vhost_list, vhost_next) {
-               if (v->being_destroyed
-#if LWS_MAX_SMP > 1
-                       && !v->close_flow_vs_tsi[tsi]
+#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SYS_METRICS)
+       lws_metric_destroy(&vh->mt_traffic_rx, 0);
+       lws_metric_destroy(&vh->mt_traffic_tx, 0);
 #endif
-               ) {
 
-                       pt = &context->pt[tsi];
+       lws_dll2_remove(&vh->vh_being_destroyed_list);
 
-                       lws_pt_lock(pt, "vhost removal"); /* -------------- pt { */
-
-#if LWS_MAX_SMP > 1
-                       v->close_flow_vs_tsi[tsi] = 1;
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_destroy(&vh->fic);
+#endif
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       lws_sul_cancel(&vh->sul_unref);
 #endif
 
-                       for (n = 0; (unsigned int)n < pt->fds_count; n++) {
-                               struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
-                               if (!wsi)
-                                       continue;
-                               if (wsi->vhost != v)
-                                       continue;
-
-                               __lws_close_free_wsi(wsi,
-                                       LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
-                                       "vh destroy"
-                                       /* no protocol close */);
-                               n--;
-                       }
-
-                       lws_pt_unlock(pt); /* } pt -------------- */
-               }
-       } lws_end_foreach_ll_safe(v);
-
-
-       lws_context_unlock(context); /* } context ------------------- */
+       __lws_lc_untag(vh->context, &vh->lc);
 
-       return 0;
+       memset(vh, 0, sizeof(*vh));
+       lws_free(vh);
 }
 
+/*
+ * Starts the vhost destroy process
+ *
+ * Vhosts are not simple to deal with because they are an abstraction that
+ * crosses SMP thread boundaries, a wsi on any pt can bind to any vhost.  If we
+ * want another pt to do something to its wsis safely, we have to asynchronously
+ * ask it to do it.
+ *
+ * In addition, with event libs, closing any handles (which are bound to vhosts
+ * in their wsi) can happens asynchronously, so we can't just linearly do some
+ * cleanup flow and free it in one step.
+ *
+ * The vhost destroy is cut into two pieces:
+ *
+ * 1) dispose of the listen socket, either by passing it on to another vhost
+ *    that was already sharing it, or just closing it.
+ *
+ *    If any wsi bound to the vhost, mark the vhost as in the process of being
+ *    destroyed, triggering each pt to close all wsi bound to the vhost next
+ *    time around the event loop.  Call lws_cancel_service() so all the pts wake
+ *    to deal with this without long poll waits making delays.
+ *
+ * 2) When the number of wsis bound to the vhost reaches zero, do the final
+ *    vhost destroy flow, this can be triggered from any pt.
+ */
 
-LWS_VISIBLE void
+void
 lws_vhost_destroy(struct lws_vhost *vh)
 {
-       struct lws_deferred_free *df = lws_malloc(sizeof(*df), "deferred free");
        struct lws_context *context = vh->context;
 
-       if (!df)
-               return;
-
        lws_context_lock(context, __func__); /* ------ context { */
 
+       /* dispose of the listen socket one way or another */
        lws_vhost_destroy1(vh);
 
+       /* start async closure of all wsi on this pt thread attached to vh */
+       __lws_vhost_destroy_pt_wsi_dieback_start(vh);
+
+       lwsl_vhost_info(vh, "count_bound_wsi %d", vh->count_bound_wsi);
+
+       /* if there are none, finalize now since no further chance */
        if (!vh->count_bound_wsi) {
-               /*
-                * After listen handoff, there are already no wsi bound to this
-                * vhost by any pt: nothing can be servicing any wsi belonging
-                * to it any more.
-                *
-                * Finalize the vh destruction immediately
-                */
                __lws_vhost_destroy2(vh);
-               lws_free(df);
 
                goto out;
        }
 
-       /* part 2 is deferred to allow all the handle closes to complete */
+       /*
+        * We have some wsi bound to this vhost, we have to wait for these to
+        * complete close and unbind before progressing the vhost removal.
+        *
+        * When the last bound wsi on this vh is destroyed we will auto-call
+        * __lws_vhost_destroy2() to finalize vh destruction
+        */
 
-       df->next = vh->context->deferred_free_list;
-       df->deadline = lws_now_secs();
-       df->payload = vh;
-       vh->context->deferred_free_list = df;
+#if LWS_MAX_SMP > 1
+       /* alert other pts they also need to do dieback flow for their wsi */
+       lws_cancel_service(context);
+#endif
 
 out:
        lws_context_unlock(context); /* } context ------------------- */
 }
 
 
-LWS_EXTERN void *
+void *
 lws_vhost_user(struct lws_vhost *vhost)
 {
        return vhost->user;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_get_vhost_listen_port(struct lws_vhost *vhost)
 {
        return vhost->listen_port;
 }
 
-
-LWS_VISIBLE LWS_EXTERN void
-lws_context_deprecate(struct lws_context *context, lws_reload_func cb)
+#if defined(LWS_WITH_SERVER)
+void
+lws_context_deprecate(struct lws_context *cx, lws_reload_func cb)
 {
-       struct lws_vhost *vh = context->vhost_list, *vh1;
+       struct lws_vhost *vh = cx->vhost_list;
 
        /*
-        * "deprecation" means disable the context from accepting any new
+        * "deprecation" means disable the cx from accepting any new
         * connections and free up listen sockets to be used by a replacement
-        * context.
+        * cx.
         *
-        * Otherwise the deprecated context remains operational, until its
+        * Otherwise the deprecated cx remains operational, until its
         * number of connected sockets falls to zero, when it is deleted.
+        *
+        * So, for each vhost, close his listen sockets
         */
 
-       /* for each vhost, close his listen socket */
-
        while (vh) {
-               struct lws *wsi = vh->lserv_wsi;
 
-               if (wsi) {
+               lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                          lws_dll2_get_head(&vh->listen_wsi)) {
+                       struct lws *wsi = lws_container_of(d, struct lws,
+                                                          listen_list);
+
                        wsi->socket_is_permanently_unusable = 1;
-                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "ctx deprecate");
-                       wsi->context->deprecation_pending_listen_close_count++;
-                       /*
-                        * other vhosts can share the listen port, they
-                        * point to the same wsi.  So zap those too.
-                        */
-                       vh1 = context->vhost_list;
-                       while (vh1) {
-                               if (vh1->lserv_wsi == wsi)
-                                       vh1->lserv_wsi = NULL;
-                               vh1 = vh1->vhost_next;
-                       }
-               }
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
+                                          __func__);
+                       cx->deprecation_pending_listen_close_count++;
+
+               } lws_end_foreach_dll_safe(d, d1);
+
                vh = vh->vhost_next;
        }
 
-       context->deprecated = 1;
-       context->deprecation_cb = cb;
+       cx->deprecated = 1;
+       cx->deprecation_cb = cb;
 }
+#endif
 
 #if defined(LWS_WITH_NETWORK)
+
 struct lws_vhost *
 lws_get_vhost_by_name(struct lws_context *context, const char *name)
 {
        lws_start_foreach_ll(struct lws_vhost *, v,
                             context->vhost_list) {
-               if (!strcmp(v->name, name))
+               if (!v->being_destroyed && !strcmp(v->name, name))
                        return v;
 
        } lws_end_foreach_ll(v, vhost_next);
 
        return NULL;
 }
+
+
+#if defined(LWS_WITH_CLIENT)
+/*
+ * This is the logic checking to see if the new connection wsi should have a
+ * pipelining or muxing relationship with an existing "active connection" to
+ * the same endpoint under the same conditions.
+ *
+ * This was originally in the client code but since the list is held on the
+ * vhost (to ensure the same client tls ctx is involved) it's cleaner in vhost.c
+ *
+ * ACTIVE_CONNS_QUEUED: We're queued on an active connection, set *nwsi to that
+ * ACTIVE_CONNS_MUXED: We are joining an active mux conn *nwsi as a child
+ * ACTIVE_CONNS_SOLO: There's no existing conn to join either way
+ */
+
+int
+lws_vhost_active_conns(struct lws *wsi, struct lws **nwsi, const char *adsin)
+{
+#if defined(LWS_WITH_TLS)
+       const char *my_alpn = lws_wsi_client_stash_item(wsi, CIS_ALPN,
+                                                       _WSI_TOKEN_CLIENT_ALPN);
+#endif
+#if defined(LWS_WITH_TLS)
+       char newconn_cannot_use_h1 = 0;
+
+       if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) &&
+           my_alpn && !strstr(my_alpn, "http/1.1"))
+               /*
+                * new guy wants to use tls, he specifies the alpn and he does
+                * not list h1 as a choice ==> he can't bind to existing h1
+                */
+               newconn_cannot_use_h1 = 1;
+#endif
+
+       if (!lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
+               struct lws *w = lws_container_of(
+                               wsi->dll2_cli_txn_queue.owner, struct lws,
+                               dll2_cli_txn_queue_owner);
+               *nwsi = w;
+
+               return ACTIVE_CONNS_QUEUED;
+       }
+
+#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
+       if (wsi->mux.parent_wsi) {
+               /*
+                * We already decided...
+                */
+
+               *nwsi = wsi->mux.parent_wsi;
+
+               return ACTIVE_CONNS_MUXED;
+       }
+#endif
+
+       lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */
+       lws_vhost_lock(wsi->a.vhost); /* ----------------------------------- { */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  wsi->a.vhost->dll_cli_active_conns_owner.head) {
+               struct lws *w = lws_container_of(d, struct lws,
+                                                dll_cli_active_conns);
+
+               lwsl_wsi_debug(wsi, "check %s %s %s %d %d",
+                                   lws_wsi_tag(w), adsin,
+                                   w->cli_hostname_copy ? w->cli_hostname_copy :
+                                                           "null",
+                                   wsi->c_port, w->c_port);
+
+               if (w != wsi &&
+                   /*
+                    * "same internet protocol"... this is a bit tricky,
+                    * since h2 start out as h1, and may stay at h1.
+                    *
+                    * But an idle h1 connection cannot be used by a connection
+                    * request that doesn't have http/1.1 in its alpn list...
+                    */
+                   (w->role_ops == wsi->role_ops ||
+                    (lwsi_role_http(w) && lwsi_role_http(wsi))) &&
+                    /* ... same role, or at least both some kind of http */
+                   w->cli_hostname_copy && !strcmp(adsin, w->cli_hostname_copy) &&
+                   /* same endpoint hostname */
+#if defined(LWS_WITH_TLS)
+                  !(newconn_cannot_use_h1 && w->role_ops == &role_ops_h1) &&
+                  /* if we can't use h1, old guy must not be h1 */
+                   (wsi->tls.use_ssl & LCCSCF_USE_SSL) ==
+                    (w->tls.use_ssl & LCCSCF_USE_SSL) &&
+                    /* must both agree on tls use or not */
 #endif
+                   wsi->c_port == w->c_port) {
+                       /* same endpoint port */
+
+                       /*
+                        * There's already an active connection.
+                        *
+                        * The server may have told the existing active
+                        * connection that it doesn't support pipelining...
+                        */
+                       if (w->keepalive_rejected) {
+                               lwsl_wsi_notice(w, "defeating pipelining");
+                               goto solo;
+                       }
+
+#if defined(LWS_WITH_HTTP2)
+                       /*
+                        * h2: if in usable state already: just use it without
+                        *     going through the queue
+                        */
+                       if (w->client_h2_alpn && w->client_mux_migrated &&
+                           (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS ||
+                            lwsi_state(w) == LRS_ESTABLISHED ||
+                            lwsi_state(w) == LRS_IDLING)) {
+
+                               lwsl_wsi_notice(w, "just join h2 directly 0x%x",
+                                                  lwsi_state(w));
+
+                               if (lwsi_state(w) == LRS_IDLING)
+                                       _lws_generic_transaction_completed_active_conn(&w, 0);
+
+                               //lwsi_set_state(w, LRS_H1C_ISSUE_HANDSHAKE2);
+
+                               wsi->client_h2_alpn = 1;
+                               lws_wsi_h2_adopt(w, wsi);
+                               lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
+                               lws_context_unlock(wsi->a.context); /* -------------- cx { */
+
+                               *nwsi = w;
+
+                               return ACTIVE_CONNS_MUXED;
+                       }
+#endif
+
+#if defined(LWS_ROLE_MQTT)
+                       /*
+                        * MQTT: if in usable state already: just use it without
+                        *       going through the queue
+                        */
+
+                       if (lwsi_role_mqtt(wsi) && w->client_mux_migrated &&
+                           lwsi_state(w) == LRS_ESTABLISHED) {
+
+                               if (lws_wsi_mqtt_adopt(w, wsi)) {
+                                       lwsl_wsi_notice(w, "join mqtt directly");
+                                       lws_dll2_remove(&wsi->dll2_cli_txn_queue);
+                                       wsi->client_mux_substream = 1;
+
+                                       lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
+                                       lws_context_unlock(wsi->a.context); /* -------------- cx { */
+
+                                       return ACTIVE_CONNS_MUXED;
+                               }
+                       }
+#endif
+
+                       /*
+                        * If the connection is viable but not yet in a usable
+                        * state, let's attach ourselves to it and wait for it
+                        * to get there or fail.
+                        */
+
+                       lwsl_wsi_notice(wsi, "apply txn queue %s, state 0x%lx",
+                                            lws_wsi_tag(w),
+                                            (unsigned long)w->wsistate);
+                       /*
+                        * ...let's add ourselves to his transaction queue...
+                        * we are adding ourselves at the TAIL
+                        */
+                       lws_dll2_add_tail(&wsi->dll2_cli_txn_queue,
+                                         &w->dll2_cli_txn_queue_owner);
+
+                       if (lwsi_state(w) == LRS_IDLING)
+                               _lws_generic_transaction_completed_active_conn(&w, 0);
+
+                       /*
+                        * For eg, h1 next we'd pipeline our headers out on him,
+                        * and wait for our turn at client transaction_complete
+                        * to take over parsing the rx.
+                        */
+                       lws_vhost_unlock(wsi->a.vhost); /* } ---------- */
+                       lws_context_unlock(wsi->a.context); /* -------------- cx { */
+
+                       *nwsi = w;
+
+                       return ACTIVE_CONNS_QUEUED;
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+solo:
+       lws_vhost_unlock(wsi->a.vhost); /* } ---------------------------------- */
+       lws_context_unlock(wsi->a.context); /* -------------- cx { */
+
+       /* there is nobody already connected in the same way */
+
+       return ACTIVE_CONNS_SOLO;
+}
+#endif
+#endif
+
+const char *
+lws_vh_tag(struct lws_vhost *vh)
+{
+       return lws_lc_tag(&vh->lc);
+}
+
+struct lws_log_cx *
+lwsl_vhost_get_cx(struct lws_vhost *vh)
+{
+       if (!vh)
+               return NULL;
+
+       return vh->lc.log_cx;
+}
+
+void
+lws_log_prepend_vhost(struct lws_log_cx *cx, void *obj, char **p, char *e)
+{
+       struct lws_vhost *vh = (struct lws_vhost *)obj;
+
+       *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
+                                                       lws_vh_tag(vh));
+}
index 4dfb1e8..bbaed54 100644 (file)
@@ -1,38 +1,38 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 void
 __lws_wsi_remove_from_sul(struct lws *wsi)
 {
-       //struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-
-       //lwsl_notice("%s: wsi %p, to %p, hr %p\n", __func__, wsi,
-       //              &wsi->sul_timeout.list, &wsi->sul_hrtimer.list);
-
-       // lws_dll2_describe(&pt->pt_sul_owner, "pre-remove");
-       lws_dll2_remove(&wsi->sul_timeout.list);
-       lws_dll2_remove(&wsi->sul_hrtimer.list);
-       // lws_dll2_describe(&pt->pt_sul_owner, "post-remove");
+       lws_sul_cancel(&wsi->sul_timeout);
+       lws_sul_cancel(&wsi->sul_hrtimer);
+       lws_sul_cancel(&wsi->sul_validity);
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_sul_cancel(&wsi->sul_fault_timedclose);
+#endif
 }
 
 /*
@@ -44,8 +44,8 @@ lws_sul_hrtimer_cb(lws_sorted_usec_list_t *sul)
 {
        struct lws *wsi = lws_container_of(sul, struct lws, sul_hrtimer);
 
-       if (wsi->protocol &&
-           wsi->protocol->callback(wsi, LWS_CALLBACK_TIMER,
+       if (wsi->a.protocol &&
+           wsi->a.protocol->callback(wsi, LWS_CALLBACK_TIMER,
                                    wsi->user_space, NULL, 0))
                __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
                                     "hrtimer cb errored");
@@ -54,13 +54,14 @@ lws_sul_hrtimer_cb(lws_sorted_usec_list_t *sul)
 void
 __lws_set_timer_usecs(struct lws *wsi, lws_usec_t us)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
 
        wsi->sul_hrtimer.cb = lws_sul_hrtimer_cb;
-       __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_hrtimer, us);
+       __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                           &wsi->sul_hrtimer, us);
 }
 
-LWS_VISIBLE void
+void
 lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs)
 {
        __lws_set_timer_usecs(wsi, usecs);
@@ -74,28 +75,25 @@ static void
 lws_sul_wsitimeout_cb(lws_sorted_usec_list_t *sul)
 {
        struct lws *wsi = lws_container_of(sul, struct lws, sul_timeout);
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-
-       if (wsi->pending_timeout != PENDING_TIMEOUT_USER_OK)
-               lws_stats_bump(pt, LWSSTATS_C_TIMEOUTS, 1);
+       struct lws_context *cx = wsi->a.context;
+       struct lws_context_per_thread *pt = &cx->pt[(int)wsi->tsi];
 
        /* no need to log normal idle keepalive timeout */
 //             if (wsi->pending_timeout != PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE)
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
        if (wsi->pending_timeout != PENDING_TIMEOUT_USER_OK)
-               lwsl_info("wsi %p: TIMEDOUT WAITING on %d "
-                         "(did hdr %d, ah %p, wl %d)\n",
-                         (void *)wsi, wsi->pending_timeout,
-                         wsi->hdr_parsing_completed, wsi->http.ah,
-                         pt->http.ah_wait_list_length);
+               lwsl_wsi_info(wsi, "TIMEDOUT WAITING %d, dhdr %d, ah %p, wl %d",
+                                  wsi->pending_timeout,
+                                  wsi->hdr_parsing_completed, wsi->http.ah,
+                                  pt->http.ah_wait_list_length);
 #if defined(LWS_WITH_CGI)
        if (wsi->http.cgi)
-               lwsl_notice("CGI timeout: %s\n", wsi->http.cgi->summary);
+               lwsl_wsi_notice(wsi, "CGI timeout: %s", wsi->http.cgi->summary);
 #endif
 #else
        if (wsi->pending_timeout != PENDING_TIMEOUT_USER_OK)
-               lwsl_info("wsi %p: TIMEDOUT WAITING on %d ", (void *)wsi,
-                               wsi->pending_timeout);
+               lwsl_wsi_info(wsi, "TIMEDOUT WAITING on %d ",
+                                  wsi->pending_timeout);
 #endif
        /* cgi timeout */
        if (wsi->pending_timeout != PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE)
@@ -107,43 +105,53 @@ lws_sul_wsitimeout_cb(lws_sorted_usec_list_t *sul)
                 * don't try to do protocol cleanup like flush partials.
                 */
                wsi->socket_is_permanently_unusable = 1;
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
        if (lwsi_state(wsi) == LRS_WAITING_SSL)
                lws_inform_client_conn_fail(wsi,
                        (void *)"Timed out waiting SSL", 21);
+       if (lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY)
+               lws_inform_client_conn_fail(wsi,
+                       (void *)"Timed out waiting server reply", 30);
 #endif
 
+       lws_context_lock(cx, __func__);
+       lws_pt_lock(pt, __func__);
        __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "timeout");
+       lws_pt_unlock(pt);
+       lws_context_unlock(cx);
 }
 
 void
 __lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
 
        wsi->sul_timeout.cb = lws_sul_wsitimeout_cb;
-       __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_timeout,
-                        ((lws_usec_t)secs) * LWS_US_PER_SEC);
+       __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                           &wsi->sul_timeout,
+                           ((lws_usec_t)secs) * LWS_US_PER_SEC);
 
-       lwsl_debug("%s: %p: %d secs, reason %d\n", __func__, wsi, secs, reason);
+       lwsl_wsi_debug(wsi, "%d secs, reason %d\n", secs, reason);
 
-       wsi->pending_timeout = reason;
+       wsi->pending_timeout = (char)reason;
 }
 
 void
 lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
 
+       lws_context_lock(pt->context, __func__);
        lws_pt_lock(pt, __func__);
        lws_dll2_remove(&wsi->sul_timeout.list);
        lws_pt_unlock(pt);
 
        if (!secs)
-               return;
+               goto bail;
 
        if (secs == LWS_TO_KILL_SYNC) {
-               lwsl_debug("synchronously killing %p\n", wsi);
+               lwsl_wsi_debug(wsi, "TO_KILL_SYNC");
+               lws_context_unlock(pt->context);
                lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
                                   "to sync kill");
                return;
@@ -152,15 +160,22 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
        if (secs == LWS_TO_KILL_ASYNC)
                secs = 0;
 
+       // assert(!secs || !wsi->mux_stream_immortal);
+       if (secs && wsi->mux_stream_immortal)
+               lwsl_wsi_err(wsi, "on immortal stream %d %d", reason, secs);
+
        lws_pt_lock(pt, __func__);
        __lws_set_timeout(wsi, reason, secs);
        lws_pt_unlock(pt);
+
+bail:
+       lws_context_unlock(pt->context);
 }
 
 void
 lws_set_timeout_us(struct lws *wsi, enum pending_timeout reason, lws_usec_t us)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
 
        lws_pt_lock(pt, __func__);
        lws_dll2_remove(&wsi->sul_timeout.list);
@@ -170,100 +185,104 @@ lws_set_timeout_us(struct lws *wsi, enum pending_timeout reason, lws_usec_t us)
                return;
 
        lws_pt_lock(pt, __func__);
-       __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_timeout, us);
+       __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                           &wsi->sul_timeout, us);
 
-       lwsl_notice("%s: %p: %llu us, reason %d\n", __func__, wsi,
-                  (unsigned long long)us, reason);
+       lwsl_wsi_notice(wsi, "%llu us, reason %d",
+                            (unsigned long long)us, reason);
 
-       wsi->pending_timeout = reason;
+       wsi->pending_timeout = (char)reason;
        lws_pt_unlock(pt);
 }
 
-/* requires context + vh lock */
-
-int
-__lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p)
-{
-       lws_start_foreach_llp_safe(struct lws_timed_vh_protocol **, pt,
-                             vh->timed_vh_protocol_list, next) {
-               if (*pt == p) {
-                       *pt = p->next;
-                       lws_dll2_remove(&p->sul.list);
-                       lws_free(p);
-
-                       return 0;
-               }
-       } lws_end_foreach_llp_safe(pt);
-
-       return 1;
-}
-
-void
-lws_sul_timed_callback_vh_protocol_cb(lws_sorted_usec_list_t *sul)
+static void
+lws_validity_cb(lws_sorted_usec_list_t *sul)
 {
-       struct lws_timed_vh_protocol *tvp = lws_container_of(sul,
-                                       struct lws_timed_vh_protocol, sul);
-       struct lws_context_per_thread *pt =
-                               &tvp->vhost->context->pt[tvp->tsi_req];
+       struct lws *wsi = lws_container_of(sul, struct lws, sul_validity);
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       const lws_retry_bo_t *rbo = wsi->retry_policy;
 
-       pt->fake_wsi->context = tvp->vhost->context;
+       /* one of either the ping or hangup validity threshold was crossed */
 
-       pt->fake_wsi->vhost = tvp->vhost; /* not a real bound wsi */
-       pt->fake_wsi->protocol = tvp->protocol;
+       if (wsi->validity_hup) {
+               lwsl_wsi_info(wsi, "validity too old");
+               struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
 
-       lwsl_debug("%s: timed cb: vh %s, protocol %s, reason %d\n", __func__,
-                  tvp->vhost->name, tvp->protocol->name, tvp->reason);
+               lws_context_lock(wsi->a.context, __func__);
+               lws_pt_lock(pt, __func__);
+               __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
+                                    "validity timeout");
+               lws_pt_unlock(pt);
+               lws_context_unlock(wsi->a.context);
+               return;
+       }
 
-       tvp->protocol->callback(pt->fake_wsi, tvp->reason, NULL, NULL, 0);
+       /* schedule a protocol-dependent ping */
 
-       __lws_timed_callback_remove(tvp->vhost, tvp);
-}
+       lwsl_wsi_info(wsi, "scheduling validity check");
 
-LWS_VISIBLE LWS_EXTERN int
-lws_timed_callback_vh_protocol_us(struct lws_vhost *vh,
-                                 const struct lws_protocols *prot, int reason,
-                                 lws_usec_t us)
-{
-       struct lws_timed_vh_protocol *p = (struct lws_timed_vh_protocol *)
-                       lws_malloc(sizeof(*p), "timed_vh");
+       if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_issue_keepalive))
+               lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_issue_keepalive).
+                                                       issue_keepalive(wsi, 0);
 
-       if (!p)
-               return 1;
+       /*
+        * We arrange to come back here after the additional ping to hangup time
+        * and do the hangup, unless we get validated (by, eg, a PONG) and
+        * reset the timer
+        */
 
-       memset(p, 0, sizeof(*p));
+       assert(rbo->secs_since_valid_hangup > rbo->secs_since_valid_ping);
 
-       p->tsi_req = lws_pthread_self_to_tsi(vh->context);
-       if (p->tsi_req < 0) /* not called from a service thread --> tsi 0 */
-               p->tsi_req = 0;
+       wsi->validity_hup = 1;
+       __lws_sul_insert_us(&pt->pt_sul_owner[!!wsi->conn_validity_wakesuspend],
+                           &wsi->sul_validity,
+                           ((uint64_t)rbo->secs_since_valid_hangup -
+                                rbo->secs_since_valid_ping) * LWS_US_PER_SEC);
+}
 
-       lws_context_lock(vh->context, __func__); /* context ----------------- */
+/*
+ * The role calls this back to actually confirm validity on a particular wsi
+ * (which may not be the original wsi)
+ */
 
-       p->protocol = prot;
-       p->reason = reason;
-       p->vhost = vh;
+void
+_lws_validity_confirmed_role(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       const lws_retry_bo_t *rbo = wsi->retry_policy;
 
-       p->sul.cb = lws_sul_timed_callback_vh_protocol_cb;
-       /* list is always at the very top of the sul */
-       __lws_sul_insert(&vh->context->pt[p->tsi_req].pt_sul_owner,
-                        (lws_sorted_usec_list_t *)&p->sul.list, us);
+       if (!rbo || !rbo->secs_since_valid_hangup)
+               return;
 
-       // lwsl_notice("%s: %s.%s %d\n", __func__, vh->name, prot->name, secs);
+       wsi->validity_hup = 0;
+       wsi->sul_validity.cb = lws_validity_cb;
 
-       lws_vhost_lock(vh); /* vhost ---------------------------------------- */
-       p->next = vh->timed_vh_protocol_list;
-       vh->timed_vh_protocol_list = p;
-       lws_vhost_unlock(vh); /* -------------------------------------- vhost */
+       wsi->validity_hup = rbo->secs_since_valid_ping >=
+                           rbo->secs_since_valid_hangup;
 
-       lws_context_unlock(vh->context); /* ------------------------- context */
+       lwsl_wsi_info(wsi, "setting validity timer %ds (hup %d)",
+                          wsi->validity_hup ? rbo->secs_since_valid_hangup :
+                                           rbo->secs_since_valid_ping,
+                          wsi->validity_hup);
 
-       return 0;
+       __lws_sul_insert_us(&pt->pt_sul_owner[!!wsi->conn_validity_wakesuspend],
+                           &wsi->sul_validity,
+                           ((uint64_t)(wsi->validity_hup ?
+                               rbo->secs_since_valid_hangup :
+                               rbo->secs_since_valid_ping)) * LWS_US_PER_SEC);
 }
 
-LWS_VISIBLE LWS_EXTERN int
-lws_timed_callback_vh_protocol(struct lws_vhost *vh,
-                              const struct lws_protocols *prot, int reason,
-                              int secs)
+void
+lws_validity_confirmed(struct lws *wsi)
 {
-       return lws_timed_callback_vh_protocol_us(vh, prot, reason,
-                                       ((lws_usec_t)secs) * LWS_US_PER_SEC);
+       /*
+        * This may be a stream inside a muxed network connection... leave it
+        * to the role to figure out who actually needs to understand their
+        * validity was confirmed.
+        */
+       if (!wsi->h2_stream_carries_ws && /* only if not encapsulated */
+           wsi->role_ops &&
+           lws_rops_fidx(wsi->role_ops, LWS_ROPS_issue_keepalive))
+               lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_issue_keepalive).
+                                                       issue_keepalive(wsi, 1);
 }
index 3968f62..978d1e8 100644 (file)
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
+
+const char *
+lws_wsi_tag(struct lws *wsi)
+{
+       if (!wsi)
+               return "[null wsi]";
+       return lws_lc_tag(&wsi->lc);
+}
 
 #if defined (_DEBUG)
 void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role)
 {
        wsi->wsistate = (wsi->wsistate & (~LWSI_ROLE_MASK)) | role;
 
-       lwsl_debug("lwsi_set_role(%p, 0x%lx)\n", wsi,
-                                       (unsigned long)wsi->wsistate);
+       lwsl_wsi_debug(wsi, "state 0x%lx", (unsigned long)wsi->wsistate);
 }
 
 void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs)
 {
-       wsi->wsistate = (wsi->wsistate & (~LRS_MASK)) | lrs;
+       lws_wsi_state_t old = wsi->wsistate;
 
-       lwsl_debug("lwsi_set_state(%p, 0x%lx)\n", wsi,
-                                       (unsigned long)wsi->wsistate);
+       wsi->wsistate = (old & (unsigned int)(~LRS_MASK)) | lrs;
+
+       lwsl_wsi_debug(wsi, "lwsi_set_state 0x%lx -> 0x%lx",
+                       (unsigned long)old, (unsigned long)wsi->wsistate);
 }
 #endif
 
 
 void
+lws_log_prepend_wsi(struct lws_log_cx *cx, void *obj, char **p, char *e)
+{
+       struct lws *wsi = (struct lws *)obj;
+
+       *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
+                                                       lws_wsi_tag(wsi));
+}
+
+void
 lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi)
 {
-       if (wsi->vhost == vh)
+       if (wsi->a.vhost == vh)
                return;
+
        lws_context_lock(vh->context, __func__); /* ---------- context { */
-       wsi->vhost = vh;
+       wsi->a.vhost = vh;
+
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       if (!vh->count_bound_wsi && vh->grace_after_unref) {
+               lwsl_wsi_info(wsi, "in use");
+               lws_sul_cancel(&vh->sul_unref);
+       }
+#endif
+
        vh->count_bound_wsi++;
        lws_context_unlock(vh->context); /* } context ---------- */
-       lwsl_info("%s: vh %s: count_bound_wsi %d\n",
-                   __func__, vh->name, vh->count_bound_wsi);
-       assert(wsi->vhost->count_bound_wsi > 0);
+
+       lwsl_wsi_debug(wsi, "vh %s: wsi %s/%s, count_bound_wsi %d\n",
+                  vh->name, wsi->role_ops ? wsi->role_ops->name : "none",
+                  wsi->a.protocol ? wsi->a.protocol->name : "none",
+                  vh->count_bound_wsi);
+       assert(wsi->a.vhost->count_bound_wsi > 0);
 }
 
+
+/* req cx lock... acquires vh lock */
 void
-lws_vhost_unbind_wsi(struct lws *wsi)
+__lws_vhost_unbind_wsi(struct lws *wsi)
 {
-       if (!wsi->vhost)
-               return;
+        struct lws_vhost *vh = wsi->a.vhost;
+
+        if (!vh)
+                return;
+
+       lws_context_assert_lock_held(wsi->a.context);
 
-       lws_context_lock(wsi->context, __func__); /* ---------- context { */
+       lws_vhost_lock(vh);
 
-       assert(wsi->vhost->count_bound_wsi > 0);
-       wsi->vhost->count_bound_wsi--;
-       lwsl_info("%s: vh %s: count_bound_wsi %d\n", __func__,
-                 wsi->vhost->name, wsi->vhost->count_bound_wsi);
+       assert(vh->count_bound_wsi > 0);
+       vh->count_bound_wsi--;
 
-       if (!wsi->vhost->count_bound_wsi &&
-           wsi->vhost->being_destroyed) {
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       if (!vh->count_bound_wsi && vh->grace_after_unref)
+               lws_tls_jit_trust_vh_start_grace(vh);
+#endif
+
+       lwsl_wsi_debug(wsi, "vh %s: count_bound_wsi %d",
+                  vh->name, vh->count_bound_wsi);
+
+       lws_vhost_unlock(vh);
+
+       if (!vh->count_bound_wsi && vh->being_destroyed)
                /*
                 * We have closed all wsi that were bound to this vhost
                 * by any pt: nothing can be servicing any wsi belonging
                 * to it any more.
                 *
-                * Finalize the vh destruction
+                * Finalize the vh destruction... must drop vh lock
                 */
-               __lws_vhost_destroy2(wsi->vhost);
-       }
-       wsi->vhost = NULL;
+               __lws_vhost_destroy2(vh);
 
-       lws_context_unlock(wsi->context); /* } context ---------- */
+       wsi->a.vhost = NULL;
 }
 
-LWS_VISIBLE struct lws *
+struct lws *
 lws_get_network_wsi(struct lws *wsi)
 {
        if (!wsi)
                return NULL;
 
-#if defined(LWS_WITH_HTTP2)
-       if (!wsi->http2_substream
-#if !defined(LWS_NO_CLIENT)
-                       && !wsi->client_h2_substream
+#if defined(LWS_WITH_HTTP2) || defined(LWS_ROLE_MQTT)
+       if (!wsi->mux_substream
+#if defined(LWS_WITH_CLIENT)
+                       && !wsi->client_mux_substream
 #endif
        )
                return wsi;
 
-       while (wsi->h2.parent_wsi)
-               wsi = wsi->h2.parent_wsi;
+       while (wsi->mux.parent_wsi)
+               wsi = wsi->mux.parent_wsi;
 #endif
 
        return wsi;
 }
 
 
-LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
+const struct lws_protocols *
 lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name)
 {
        int n;
@@ -117,7 +161,7 @@ lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name)
        return NULL;
 }
 
-LWS_VISIBLE int
+int
 lws_callback_all_protocol(struct lws_context *context,
                          const struct lws_protocols *protocol, int reason)
 {
@@ -130,9 +174,10 @@ lws_callback_all_protocol(struct lws_context *context,
                        wsi = wsi_from_fd(context, pt->fds[n].fd);
                        if (!wsi)
                                continue;
-                       if (wsi->protocol == protocol)
-                               protocol->callback(wsi, reason, wsi->user_space,
-                                                  NULL, 0);
+                       if (wsi->a.protocol == protocol)
+                               protocol->callback(wsi,
+                                       (enum lws_callback_reasons)reason,
+                                       wsi->user_space, NULL, 0);
                }
                pt++;
        }
@@ -140,7 +185,23 @@ lws_callback_all_protocol(struct lws_context *context,
        return 0;
 }
 
-LWS_VISIBLE int
+void *
+lws_evlib_wsi_to_evlib_pt(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+
+       return pt->evlib_pt;
+}
+
+void *
+lws_evlib_tsi_to_evlib_pt(struct lws_context *cx, int tsi)
+{
+       struct lws_context_per_thread *pt = &cx->pt[tsi];
+
+       return pt->evlib_pt;
+}
+
+int
 lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
                          const struct lws_protocols *protocol, int reason,
                          void *argp, size_t len)
@@ -155,9 +216,9 @@ lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
                        wsi = wsi_from_fd(context, pt->fds[n].fd);
                        if (!wsi)
                                continue;
-                       if (wsi->vhost == vh && (wsi->protocol == protocol ||
+                       if (wsi->a.vhost == vh && (wsi->a.protocol == protocol ||
                                                 !protocol))
-                               wsi->protocol->callback(wsi, reason,
+                               wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)reason,
                                                wsi->user_space, argp, len);
                }
                pt++;
@@ -166,26 +227,165 @@ lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_callback_all_protocol_vhost(struct lws_vhost *vh,
                          const struct lws_protocols *protocol, int reason)
 {
        return lws_callback_all_protocol_vhost_args(vh, protocol, reason, NULL, 0);
 }
 
-LWS_VISIBLE LWS_EXTERN int
-lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len)
+int
+lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, size_t len)
 {
        int n;
 
-       for (n = 0; n < wsi->vhost->count_protocols; n++)
-               if (wsi->vhost->protocols[n].callback(wsi, reason, NULL, in, len))
+       for (n = 0; n < wsi->a.vhost->count_protocols; n++)
+               if (wsi->a.vhost->protocols[n].callback(wsi, (enum lws_callback_reasons)reason, NULL, in, len))
                        return 1;
 
        return 0;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+/*
+ * We want to inject a fault that makes it feel like the peer hung up on us,
+ * or we were otherwise cut off.
+ */
+void
+lws_wsi_fault_timedclose_cb(lws_sorted_usec_list_t *s)
+{
+       struct lws *wsi = lws_container_of(s, struct lws, sul_fault_timedclose);
+
+       lwsl_wsi_warn(wsi, "force-closing");
+       lws_wsi_close(wsi, LWS_TO_KILL_ASYNC);
+}
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+void
+lws_wsi_fault_timedclose(struct lws *wsi)
+{
+       uint64_t u;
+
+       if (!lws_fi(&wsi->fic, "timedclose"))
+               return;
+
+       if (lws_fi_range(&wsi->fic, "timedclose_ms", &u))
+               return;
+
+       lwsl_wsi_warn(wsi, "injecting close in %ums", (unsigned int)u);
+       lws_sul_schedule(wsi->a.context, wsi->tsi, &wsi->sul_fault_timedclose,
+                        lws_wsi_fault_timedclose_cb,
+                        (lws_usec_t)(u * 1000ull));
+}
+#endif
+
+
+/*
+ * We need the context lock
+ */
+
+struct lws *
+__lws_wsi_create_with_role(struct lws_context *context, int tsi,
+                          const struct lws_role_ops *ops,
+                          lws_log_cx_t *log_cx_template)
+{
+       size_t s = sizeof(struct lws);
+       struct lws *wsi;
+
+       assert(tsi >= 0 && tsi < LWS_MAX_SMP);
+
+       lws_context_assert_lock_held(context);
+
+#if defined(LWS_WITH_EVENT_LIBS)
+       s += context->event_loop_ops->evlib_size_wsi;
+#endif
+
+       wsi = lws_zalloc(s, __func__);
+
+       if (!wsi) {
+               lwsl_cx_err(context, "OOM");
+               return NULL;
+       }
+
+       if (log_cx_template)
+               wsi->lc.log_cx = log_cx_template;
+       else
+               wsi->lc.log_cx = context->log_cx;
+
+#if defined(LWS_WITH_EVENT_LIBS)
+       wsi->evlib_wsi = (uint8_t *)wsi + sizeof(*wsi);
+#endif
+       wsi->a.context = context;
+       lws_role_transition(wsi, 0, LRS_UNCONNECTED, ops);
+       wsi->pending_timeout = NO_PENDING_TIMEOUT;
+       wsi->a.protocol = NULL;
+       wsi->tsi = (char)tsi;
+       wsi->a.vhost = NULL;
+       wsi->desc.sockfd = LWS_SOCK_INVALID;
+       wsi->position_in_fds_table = LWS_NO_FDS_POS;
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_xos_init(&wsi->fic.xos, lws_xos(&context->fic.xos));
+#endif
+
+       lws_fi_inherit_copy(&wsi->fic, &context->fic, "wsi", NULL);
+
+       if (lws_fi(&wsi->fic, "createfail")) {
+               lws_fi_destroy(&wsi->fic);
+               lws_free(wsi);
+               return NULL;
+       }
+
+       return wsi;
+}
+
+int
+lws_wsi_inject_to_loop(struct lws_context_per_thread *pt, struct lws *wsi)
+{
+       int ret = 1;
+
+       lws_pt_lock(pt, __func__); /* -------------- pt { */
+
+       if (pt->context->event_loop_ops->sock_accept)
+               if (pt->context->event_loop_ops->sock_accept(wsi))
+                       goto bail;
+
+       if (__insert_wsi_socket_into_fds(pt->context, wsi))
+               goto bail;
+
+       ret = 0;
+
+bail:
+       lws_pt_unlock(pt);
+
+       return ret;
+}
+
+/*
+ * Take a copy of wsi->desc.sockfd before calling this, then close it
+ * afterwards
+ */
+
+int
+lws_wsi_extract_from_loop(struct lws *wsi)
+{
+       if (lws_socket_is_valid(wsi->desc.sockfd))
+               __remove_wsi_socket_from_fds(wsi);
+
+       if (!wsi->a.context->event_loop_ops->destroy_wsi &&
+           wsi->a.context->event_loop_ops->wsi_logical_close) {
+               wsi->a.context->event_loop_ops->wsi_logical_close(wsi);
+               return 1; /* close / destroy continues async */
+       }
+
+       if (wsi->a.context->event_loop_ops->destroy_wsi)
+               wsi->a.context->event_loop_ops->destroy_wsi(wsi);
+
+       return 0; /* he is destroyed */
+}
+
+int
 lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in,
                                   size_t len)
 {
@@ -195,12 +395,12 @@ lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in,
        if (!wsi)
                return 1;
 
-       wsi->context = vh->context;
+       wsi->a.context = vh->context;
        lws_vhost_bind_wsi(vh, wsi);
 
-       for (n = 0; n < wsi->vhost->count_protocols; n++) {
-               wsi->protocol = &vh->protocols[n];
-               if (wsi->protocol->callback(wsi, reason, NULL, in, len)) {
+       for (n = 0; n < wsi->a.vhost->count_protocols; n++) {
+               wsi->a.protocol = &vh->protocols[n];
+               if (wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)reason, NULL, in, len)) {
                        lws_free(wsi);
                        return 1;
                }
@@ -212,18 +412,18 @@ lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in,
 }
 
 
-LWS_VISIBLE int
+int
 lws_rx_flow_control(struct lws *wsi, int _enable)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        int en = _enable;
 
        // h2 ignores rx flow control atm
-       if (lwsi_role_h2(wsi) || wsi->http2_substream ||
+       if (lwsi_role_h2(wsi) || wsi->mux_substream ||
            lwsi_role_h2_ENCAPSULATION(wsi))
                return 0; // !!!
 
-       lwsl_info("%s: %p 0x%x\n", __func__, wsi, _enable);
+       lwsl_wsi_info(wsi, "0x%x", _enable);
 
        if (!(_enable & LWS_RXFLOW_REASON_APPLIES)) {
                /*
@@ -239,9 +439,9 @@ lws_rx_flow_control(struct lws *wsi, int _enable)
 
        /* any bit set in rxflow_bitmap DISABLEs rxflow control */
        if (en & LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT)
-               wsi->rxflow_bitmap &= ~(en & 0xff);
+               wsi->rxflow_bitmap = (uint8_t)(wsi->rxflow_bitmap & ~(en & 0xff));
        else
-               wsi->rxflow_bitmap |= en & 0xff;
+               wsi->rxflow_bitmap = (uint8_t)(wsi->rxflow_bitmap | (en & 0xff));
 
        if ((LWS_RXFLOW_PENDING_CHANGE | (!wsi->rxflow_bitmap)) ==
            wsi->rxflow_change_to)
@@ -250,8 +450,8 @@ lws_rx_flow_control(struct lws *wsi, int _enable)
        wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE |
                                (!wsi->rxflow_bitmap);
 
-       lwsl_info("%s: %p: bitmap 0x%x: en 0x%x, ch 0x%x\n", __func__, wsi,
-                 wsi->rxflow_bitmap, en, wsi->rxflow_change_to);
+       lwsl_wsi_info(wsi, "bitmap 0x%x: en 0x%x, ch 0x%x",
+                          wsi->rxflow_bitmap, en, wsi->rxflow_change_to);
 
        if (_enable & LWS_RXFLOW_REASON_FLAG_PROCESS_NOW ||
            !wsi->rxflow_will_be_applied) {
@@ -267,7 +467,7 @@ skip:
        return 0;
 }
 
-LWS_VISIBLE void
+void
 lws_rx_flow_allow_all_protocol(const struct lws_context *context,
                               const struct lws_protocols *protocol)
 {
@@ -280,7 +480,7 @@ lws_rx_flow_allow_all_protocol(const struct lws_context *context,
                        wsi = wsi_from_fd(context, pt->fds[n].fd);
                        if (!wsi)
                                continue;
-                       if (wsi->protocol == protocol)
+                       if (wsi->a.protocol == protocol)
                                lws_rx_flow_control(wsi, LWS_RXFLOW_ALLOW);
                }
                pt++;
@@ -303,13 +503,13 @@ int user_callback_handle_rxflow(lws_callback_function callback_function,
        return n;
 }
 
-LWS_EXTERN int
+int
 __lws_rx_flow_control(struct lws *wsi)
 {
        struct lws *wsic = wsi->child_list;
 
        // h2 ignores rx flow control atm
-       if (lwsi_role_h2(wsi) || wsi->http2_substream ||
+       if (lwsi_role_h2(wsi) || wsi->mux_substream ||
            lwsi_role_h2_ENCAPSULATION(wsi))
                return 0; // !!!
 
@@ -334,18 +534,18 @@ __lws_rx_flow_control(struct lws *wsi)
 
        /* now the pending is cleared, we can change rxflow state */
 
-       wsi->rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE;
+       wsi->rxflow_change_to &= (~LWS_RXFLOW_PENDING_CHANGE) & 3;
 
-       lwsl_info("rxflow: wsi %p change_to %d\n", wsi,
-                 wsi->rxflow_change_to & LWS_RXFLOW_ALLOW);
+       lwsl_wsi_info(wsi, "rxflow: change_to %d",
+                     wsi->rxflow_change_to & LWS_RXFLOW_ALLOW);
 
        /* adjust the pollfd for this wsi */
 
        if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) {
-               lwsl_info("%s: reenable POLLIN\n", __func__);
-               // lws_buflist_describe(&wsi->buflist, NULL);
+               lwsl_wsi_info(wsi, "reenable POLLIN");
+               // lws_buflist_describe(&wsi->buflist, NULL, __func__);
                if (__lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
-                       lwsl_info("%s: fail\n", __func__);
+                       lwsl_wsi_info(wsi, "fail");
                        return -1;
                }
        } else
@@ -356,36 +556,36 @@ __lws_rx_flow_control(struct lws *wsi)
 }
 
 
-LWS_VISIBLE const struct lws_protocols *
+const struct lws_protocols *
 lws_get_protocol(struct lws *wsi)
 {
-       return wsi->protocol;
+       return wsi->a.protocol;
 }
 
 
 int
 lws_ensure_user_space(struct lws *wsi)
 {
-       if (!wsi->protocol)
+       if (!wsi->a.protocol)
                return 0;
 
        /* allocate the per-connection user memory (if any) */
 
-       if (wsi->protocol->per_session_data_size && !wsi->user_space) {
+       if (wsi->a.protocol->per_session_data_size && !wsi->user_space) {
                wsi->user_space = lws_zalloc(
-                           wsi->protocol->per_session_data_size, "user space");
+                           wsi->a.protocol->per_session_data_size, "user space");
                if (wsi->user_space == NULL) {
-                       lwsl_err("%s: OOM\n", __func__);
+                       lwsl_wsi_err(wsi, "OOM");
                        return 1;
                }
        } else
-               lwsl_debug("%s: %p protocol pss %lu, user_space=%p\n", __func__,
-                          wsi, (long)wsi->protocol->per_session_data_size,
-                          wsi->user_space);
+               lwsl_wsi_debug(wsi, "protocol pss %lu, user_space=%p",
+                                   (long)wsi->a.protocol->per_session_data_size,
+                                   wsi->user_space);
        return 0;
 }
 
-LWS_VISIBLE void *
+void *
 lws_adjust_protocol_psds(struct lws *wsi, size_t new_size)
 {
        ((struct lws_protocols *)lws_get_protocol(wsi))->per_session_data_size =
@@ -397,9 +597,13 @@ lws_adjust_protocol_psds(struct lws *wsi, size_t new_size)
        return wsi->user_space;
 }
 
+int
+lws_get_tsi(struct lws *wsi)
+{
+        return (int)wsi->tsi;
+}
 
-
-LWS_VISIBLE int
+int
 lws_is_ssl(struct lws *wsi)
 {
 #if defined(LWS_WITH_TLS)
@@ -411,46 +615,66 @@ lws_is_ssl(struct lws *wsi)
 }
 
 #if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
-LWS_VISIBLE lws_tls_conn*
+lws_tls_conn*
 lws_get_ssl(struct lws *wsi)
 {
        return wsi->tls.ssl;
 }
 #endif
 
-LWS_VISIBLE int
+int
+lws_has_buffered_out(struct lws *wsi)
+{
+       if (wsi->buflist_out)
+               return 1;
+
+#if defined(LWS_ROLE_H2)
+       {
+               struct lws *nwsi = lws_get_network_wsi(wsi);
+
+               if (nwsi->buflist_out)
+                       return 1;
+       }
+#endif
+
+       return 0;
+}
+
+int
 lws_partial_buffered(struct lws *wsi)
 {
        return lws_has_buffered_out(wsi);
 }
 
-LWS_VISIBLE lws_fileofs_t
+lws_fileofs_t
 lws_get_peer_write_allowance(struct lws *wsi)
 {
-       if (!wsi->role_ops->tx_credit)
+       if (!lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit))
                return -1;
-       return wsi->role_ops->tx_credit(wsi);
+
+       return lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_tx_credit).
+                                  tx_credit(wsi, LWSTXCR_US_TO_PEER, 0);
 }
 
-LWS_VISIBLE void
+void
 lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state,
                    const struct lws_role_ops *ops)
 {
-#if defined(_DEBUG)
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG) 
        const char *name = "(unset)";
 #endif
-       wsi->wsistate = role | state;
+       wsi->wsistate = (unsigned int)role | (unsigned int)state;
        if (ops)
                wsi->role_ops = ops;
-#if defined(_DEBUG)
+#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
        if (wsi->role_ops)
                name = wsi->role_ops->name;
-       lwsl_debug("%s: %p: wsistate 0x%lx, ops %s\n", __func__, wsi,
-                  (unsigned long)wsi->wsistate, name);
+       lwsl_wsi_debug(wsi, "wsistate 0x%lx, ops %s",
+                           (unsigned long)wsi->wsistate, name);
 #endif
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
              const char **path)
 {
@@ -506,21 +730,49 @@ lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
 
 /* ... */
 
-LWS_VISIBLE LWS_EXTERN const char *
-lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len)
+int
+lws_get_urlarg_by_name_safe(struct lws *wsi, const char *name, char *buf, int len)
 {
-       int n = 0, sl = (int)strlen(name);
+       int n = 0, fraglen, sl = (int)strlen(name);
 
-       while (lws_hdr_copy_fragment(wsi, buf, len,
-                         WSI_TOKEN_HTTP_URI_ARGS, n) >= 0) {
+       do {
+               fraglen = lws_hdr_copy_fragment(wsi, buf, len,
+                                               WSI_TOKEN_HTTP_URI_ARGS, n);
 
-               if (!strncmp(buf, name, sl))
-                       return buf + sl;
+               if (fraglen < 0)
+                       break;
+
+               if (fraglen + 1 < len &&
+                   fraglen >= sl &&
+                   !strncmp(buf, name, (size_t)sl)) {
+                       /*
+                        * If he left off the trailing =, trim it from the
+                        * result
+                        */
+
+                       if (name[sl - 1] != '=' &&
+                           sl < fraglen &&
+                           buf[sl] == '=')
+                               sl++;
+
+                       memmove(buf, buf + sl, (size_t)(fraglen - sl));
+                       buf[fraglen - sl] = '\0';
+
+                       return fraglen - sl;
+               }
 
                n++;
-       }
+       } while (1);
 
-       return NULL;
+       return -1;
+}
+
+const char *
+lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len)
+{
+       int n = lws_get_urlarg_by_name_safe(wsi, name, buf, len);
+
+       return n < 0 ? NULL : buf;
 }
 
 
@@ -531,7 +783,7 @@ lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len)
  * extensions disabled.
  */
 
-LWS_VISIBLE int
+int
 lws_extension_callback_pm_deflate(struct lws_context *context,
                                   const struct lws_extension *ext,
                                   struct lws *wsi,
@@ -549,7 +801,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
        return 0;
 }
 
-LWS_EXTERN int
+int
 lws_set_extension_option(struct lws *wsi, const char *ext_name,
                         const char *opt_name, const char *opt_val)
 {
@@ -557,7 +809,7 @@ lws_set_extension_option(struct lws *wsi, const char *ext_name,
 }
 #endif
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_is_cgi(struct lws *wsi) {
 #ifdef LWS_WITH_CGI
        return !!wsi->http.cgi;
@@ -598,86 +850,99 @@ int
 lws_broadcast(struct lws_context_per_thread *pt, int reason, void *in, size_t len)
 {
        struct lws_vhost *v = pt->context->vhost_list;
+       lws_fakewsi_def_plwsa(pt);
        int n, ret = 0;
 
-       pt->fake_wsi->context = pt->context;
+       lws_fakewsi_prep_plwsa_ctx(pt->context);
+#if !defined(LWS_PLAT_FREERTOS) && LWS_MAX_SMP > 1
+       ((struct lws *)plwsa)->tsi = (char)(int)(pt - &pt->context->pt[0]);
+#endif
 
        while (v) {
                const struct lws_protocols *p = v->protocols;
-               pt->fake_wsi->vhost = v; /* not a real bound wsi */
+
+               plwsa->vhost = v; /* not a real bound wsi */
 
                for (n = 0; n < v->count_protocols; n++) {
-                       pt->fake_wsi->protocol = p;
+                       plwsa->protocol = p;
                        if (p->callback &&
-                           p->callback(pt->fake_wsi, reason, NULL, in, len))
+                           p->callback((struct lws *)plwsa, (enum lws_callback_reasons)reason, NULL, in, len))
                                ret |= 1;
                        p++;
                }
+
                v = v->vhost_next;
        }
 
        return ret;
 }
 
-LWS_VISIBLE LWS_EXTERN void *
+void *
 lws_wsi_user(struct lws *wsi)
 {
        return wsi->user_space;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+int
+lws_wsi_tsi(struct lws *wsi)
+{
+       return wsi->tsi;
+}
+
+
+void
 lws_set_wsi_user(struct lws *wsi, void *data)
 {
-       if (wsi->user_space_externally_allocated)
-               wsi->user_space = data;
-       else
-               lwsl_err("%s: Cannot set internally-allocated user_space\n",
-                        __func__);
+       if (!wsi->user_space_externally_allocated && wsi->user_space)
+               lws_free(wsi->user_space);
+
+       wsi->user_space_externally_allocated = 1;
+       wsi->user_space = data;
 }
 
-LWS_VISIBLE LWS_EXTERN struct lws *
+struct lws *
 lws_get_parent(const struct lws *wsi)
 {
        return wsi->parent;
 }
 
-LWS_VISIBLE LWS_EXTERN struct lws *
+struct lws *
 lws_get_child(const struct lws *wsi)
 {
        return wsi->child_list;
 }
 
-LWS_VISIBLE LWS_EXTERN void *
+void *
 lws_get_opaque_parent_data(const struct lws *wsi)
 {
        return wsi->opaque_parent_data;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_set_opaque_parent_data(struct lws *wsi, void *data)
 {
        wsi->opaque_parent_data = data;
 }
 
-LWS_VISIBLE LWS_EXTERN void *
+void *
 lws_get_opaque_user_data(const struct lws *wsi)
 {
-       return wsi->opaque_user_data;
+       return wsi->a.opaque_user_data;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_set_opaque_user_data(struct lws *wsi, void *data)
 {
-       wsi->opaque_user_data = data;
+       wsi->a.opaque_user_data = data;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_get_child_pending_on_writable(const struct lws *wsi)
 {
        return wsi->parent_pending_cb_on_writable;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_clear_child_pending_on_writable(struct lws *wsi)
 {
        wsi->parent_pending_cb_on_writable = 0;
@@ -685,31 +950,31 @@ lws_clear_child_pending_on_writable(struct lws *wsi)
 
 
 
-LWS_VISIBLE LWS_EXTERN const char *
+const char *
 lws_get_vhost_name(struct lws_vhost *vhost)
 {
        return vhost->name;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_get_vhost_port(struct lws_vhost *vhost)
 {
        return vhost->listen_port;
 }
 
-LWS_VISIBLE LWS_EXTERN void *
+void *
 lws_get_vhost_user(struct lws_vhost *vhost)
 {
        return vhost->user;
 }
 
-LWS_VISIBLE LWS_EXTERN const char *
+const char *
 lws_get_vhost_iface(struct lws_vhost *vhost)
 {
        return vhost->iface;
 }
 
-LWS_VISIBLE lws_sockfd_type
+lws_sockfd_type
 lws_get_socket_fd(struct lws *wsi)
 {
        if (!wsi)
@@ -718,78 +983,211 @@ lws_get_socket_fd(struct lws *wsi)
 }
 
 
-LWS_VISIBLE struct lws_vhost *
+struct lws_vhost *
 lws_vhost_get(struct lws *wsi)
 {
-       return wsi->vhost;
+       return wsi->a.vhost;
 }
 
-LWS_VISIBLE struct lws_vhost *
+struct lws_vhost *
 lws_get_vhost(struct lws *wsi)
 {
-       return wsi->vhost;
+       return wsi->a.vhost;
 }
 
-LWS_VISIBLE const struct lws_protocols *
+const struct lws_protocols *
 lws_protocol_get(struct lws *wsi)
 {
-       return wsi->protocol;
+       return wsi->a.protocol;
 }
 
-LWS_VISIBLE const struct lws_udp *
+#if defined(LWS_WITH_UDP)
+const struct lws_udp *
 lws_get_udp(const struct lws *wsi)
 {
        return wsi->udp;
 }
+#endif
 
-LWS_VISIBLE LWS_EXTERN struct lws_context *
+struct lws_context *
 lws_get_context(const struct lws *wsi)
 {
-       return wsi->context;
+       return wsi->a.context;
 }
 
-#ifdef LWS_LATENCY
-void
-lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
-           int ret, int completed)
+struct lws_log_cx *
+lwsl_wsi_get_cx(struct lws *wsi)
 {
-       unsigned long long u;
-       char buf[256];
+       if (!wsi)
+               return NULL;
 
-       u = lws_now_usecs();
+       return wsi->lc.log_cx;
+}
 
-       if (!action) {
-               wsi->latency_start = u;
-               if (!wsi->action_start)
-                       wsi->action_start = u;
-               return;
+#if defined(LWS_WITH_CLIENT)
+int
+_lws_generic_transaction_completed_active_conn(struct lws **_wsi, char take_vh_lock)
+{
+       struct lws *wnew, *wsi = *_wsi;
+
+       /*
+        * Are we constitutionally capable of having a queue, ie, we are on
+        * the "active client connections" list?
+        *
+        * If not, that's it for us.
+        */
+
+       if (lws_dll2_is_detached(&wsi->dll_cli_active_conns))
+               return 0; /* no new transaction */
+
+       /*
+        * With h1 queuing, the original "active client" moves his attributes
+        * like fd, ssl, queue and active client list entry to the next guy in
+        * the queue before closing... it's because the user code knows the
+        * individual wsi and the action must take place in the correct wsi
+        * context.  Note this means we don't truly pipeline headers.
+        *
+        * Trying to keep the original "active client" in place to do the work
+        * of the wsi breaks down when dealing with queued POSTs otherwise; it's
+        * also competing with the real mux child arrangements and complicating
+        * the code.
+        *
+        * For that reason, see if we have any queued child now...
+        */
+
+       if (!wsi->dll2_cli_txn_queue_owner.head) {
+               /*
+                * Nothing pipelined... we should hang around a bit
+                * in case something turns up... otherwise we'll close
+                */
+               lwsl_wsi_info(wsi, "nothing pipelined waiting");
+               lwsi_set_state(wsi, LRS_IDLING);
+
+               lws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE,
+                               wsi->keep_warm_secs);
+
+               return 0; /* no new transaction right now */
        }
-       if (completed) {
-               if (wsi->action_start == wsi->latency_start)
-                       sprintf(buf,
-                         "Completion first try lat %lluus: %p: ret %d: %s\n",
-                                       u - wsi->latency_start,
-                                                     (void *)wsi, ret, action);
-               else
-                       sprintf(buf,
-                         "Completion %lluus: lat %lluus: %p: ret %d: %s\n",
-                               u - wsi->action_start,
-                                       u - wsi->latency_start,
-                                                     (void *)wsi, ret, action);
-               wsi->action_start = 0;
-       } else
-               sprintf(buf, "lat %lluus: %p: ret %d: %s\n",
-                             u - wsi->latency_start, (void *)wsi, ret, action);
 
-       if (u - wsi->latency_start > context->worst_latency) {
-               context->worst_latency = u - wsi->latency_start;
-               strcpy(context->worst_latency_info, buf);
+       /*
+        * We have a queued child wsi we should bequeath our assets to, before
+        * closing ourself
+        */
+
+       if (take_vh_lock)
+               lws_vhost_lock(wsi->a.vhost);
+
+       wnew = lws_container_of(wsi->dll2_cli_txn_queue_owner.head, struct lws,
+                               dll2_cli_txn_queue);
+
+       assert(wsi != wnew);
+
+       lws_dll2_remove(&wnew->dll2_cli_txn_queue);
+
+       assert(lws_socket_is_valid(wsi->desc.sockfd));
+
+       __lws_change_pollfd(wsi, LWS_POLLOUT | LWS_POLLIN, 0);
+
+       /* copy the fd */
+       wnew->desc = wsi->desc;
+
+       assert(lws_socket_is_valid(wnew->desc.sockfd));
+
+       /* disconnect the fd from association with old wsi */
+
+       if (__remove_wsi_socket_from_fds(wsi))
+               return -1;
+
+       sanity_assert_no_wsi_traces(wsi->a.context, wsi);
+       sanity_assert_no_sockfd_traces(wsi->a.context, wsi->desc.sockfd);
+       wsi->desc.sockfd = LWS_SOCK_INVALID;
+
+       __lws_wsi_remove_from_sul(wsi);
+
+       /*
+        * ... we're doing some magic here in terms of handing off the socket
+        * that has been active to a wsi that has not yet itself been active...
+        * depending on the event lib we may need to give a magic spark to the
+        * new guy and snuff out the old guy's magic spark at that level as well
+        */
+
+#if defined(LWS_WITH_EVENT_LIBS)
+       if (wsi->a.context->event_loop_ops->destroy_wsi)
+               wsi->a.context->event_loop_ops->destroy_wsi(wsi);
+       if (wsi->a.context->event_loop_ops->sock_accept)
+               wsi->a.context->event_loop_ops->sock_accept(wnew);
+#endif
+
+       /* point the fd table entry to new guy */
+
+       assert(lws_socket_is_valid(wnew->desc.sockfd));
+
+       if (__insert_wsi_socket_into_fds(wsi->a.context, wnew))
+               return -1;
+
+#if defined(LWS_WITH_TLS)
+       /* pass on the tls */
+
+       wnew->tls = wsi->tls;
+       wsi->tls.client_bio = NULL;
+       wsi->tls.ssl = NULL;
+       wsi->tls.use_ssl = 0;
+#endif
+
+       /* take over his copy of his endpoint as an active connection */
+
+       if (!wnew->cli_hostname_copy && wsi->cli_hostname_copy) {
+               wnew->cli_hostname_copy = wsi->cli_hostname_copy;
+               wsi->cli_hostname_copy = NULL;
        }
-       lwsl_latency("%s", buf);
+       wnew->keep_warm_secs = wsi->keep_warm_secs;
+
+       /*
+        * selected queued guy now replaces the original leader on the
+        * active client conn list
+        */
+
+       lws_dll2_remove(&wsi->dll_cli_active_conns);
+       lws_dll2_add_tail(&wnew->dll_cli_active_conns,
+                         &wsi->a.vhost->dll_cli_active_conns_owner);
+
+       /* move any queued guys to queue on new active conn */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  wsi->dll2_cli_txn_queue_owner.head) {
+               struct lws *ww = lws_container_of(d, struct lws,
+                                         dll2_cli_txn_queue);
+
+               lws_dll2_remove(&ww->dll2_cli_txn_queue);
+               lws_dll2_add_tail(&ww->dll2_cli_txn_queue,
+                                 &wnew->dll2_cli_txn_queue_owner);
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       if (take_vh_lock)
+               lws_vhost_unlock(wsi->a.vhost);
+
+       /*
+        * The original leader who passed on all his powers already can die...
+        * in the call stack above us there are guys who still want to touch
+        * him, so have him die next time around the event loop, not now.
+        */
+
+       wsi->already_did_cce = 1; /* so the close doesn't trigger a CCE */
+       lws_set_timeout(wsi, 1, LWS_TO_KILL_ASYNC);
+
+       /* after the first one, they can only be coming from the queue */
+       wnew->transaction_from_pipeline_queue = 1;
+
+       lwsl_wsi_notice(wsi, " pipeline queue passed -> %s", lws_wsi_tag(wnew));
+
+       *_wsi = wnew; /* inform caller we swapped */
+
+       return 1; /* new transaction */
 }
 #endif
 
-LWS_VISIBLE int LWS_WARN_UNUSED_RESULT
+int LWS_WARN_UNUSED_RESULT
 lws_raw_transaction_completed(struct lws *wsi)
 {
        if (lws_has_buffered_out(wsi)) {
@@ -801,7 +1199,8 @@ lws_raw_transaction_completed(struct lws *wsi)
                 * Defer the close until the last part of the partial is sent.
                 *
                 */
-               lwsl_debug("%s: %p: deferring due to partial\n", __func__, wsi);
+
+               lwsl_wsi_debug(wsi, "deferring due to partial");
                wsi->close_when_buffered_out_drained = 1;
                lws_callback_on_writable(wsi);
 
@@ -815,12 +1214,12 @@ int
 lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
                  const char *reason)
 {
-//     if (wsi->protocol == p)
+//     if (wsi->a.protocol == p)
 //             return 0;
-       const struct lws_protocols *vp = wsi->vhost->protocols, *vpo;
+       const struct lws_protocols *vp = wsi->a.vhost->protocols, *vpo;
 
-       if (wsi->protocol && wsi->protocol_bind_balance) {
-               wsi->protocol->callback(wsi,
+       if (wsi->a.protocol && wsi->protocol_bind_balance) {
+               wsi->a.protocol->callback(wsi,
                       wsi->role_ops->protocol_unbind_cb[!!lwsi_role_server(wsi)],
                                        wsi->user_space, (void *)reason, 0);
                wsi->protocol_bind_balance = 0;
@@ -830,17 +1229,17 @@ lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
 
        lws_same_vh_protocol_remove(wsi);
 
-       wsi->protocol = p;
+       wsi->a.protocol = p;
        if (!p)
                return 0;
 
        if (lws_ensure_user_space(wsi))
                return 1;
 
-       if (p > vp && p < &vp[wsi->vhost->count_protocols])
+       if (p > vp && p < &vp[wsi->a.vhost->count_protocols])
                lws_same_vh_protocol_insert(wsi, (int)(p - vp));
        else {
-               int n = wsi->vhost->count_protocols;
+               int n = wsi->a.vhost->count_protocols;
                int hit = 0;
 
                vpo = vp;
@@ -855,10 +1254,10 @@ lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
                }
                if (!hit)
                        lwsl_err("%s: %p is not in vhost '%s' protocols list\n",
-                                __func__, p, wsi->vhost->name);
+                                __func__, p, wsi->a.vhost->name);
        }
 
-       if (wsi->protocol->callback(wsi, wsi->role_ops->protocol_bind_cb[
+       if (wsi->a.protocol->callback(wsi, wsi->role_ops->protocol_bind_cb[
                                    !!lwsi_role_server(wsi)],
                                    wsi->user_space, NULL, 0))
                return 1;
@@ -868,20 +1267,412 @@ lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
        return 0;
 }
 
+void
+lws_http_close_immortal(struct lws *wsi)
+{
+       struct lws *nwsi;
+
+       if (!wsi->mux_substream)
+               return;
+
+       assert(wsi->mux_stream_immortal);
+       wsi->mux_stream_immortal = 0;
+
+       nwsi = lws_get_network_wsi(wsi);
+       lwsl_wsi_debug(wsi, "%s (%d)", lws_wsi_tag(nwsi),
+                                      nwsi->immortal_substream_count);
+       assert(nwsi->immortal_substream_count);
+       nwsi->immortal_substream_count--;
+       if (!nwsi->immortal_substream_count)
+               /*
+                * since we closed the only immortal stream on this nwsi, we
+                * need to reapply a normal timeout regime to the nwsi
+                */
+               lws_set_timeout(nwsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
+                               wsi->a.vhost->keepalive_timeout ?
+                                   wsi->a.vhost->keepalive_timeout : 31);
+}
+
+void
+lws_mux_mark_immortal(struct lws *wsi)
+{
+       struct lws *nwsi;
+
+       lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+       if (!wsi->mux_substream
+#if defined(LWS_WITH_CLIENT)
+                       && !wsi->client_mux_substream
+#endif
+       ) {
+               lwsl_wsi_err(wsi, "not mux substream");
+               return;
+       }
+
+       if (wsi->mux_stream_immortal)
+               /* only need to handle it once per child wsi */
+               return;
+
+       nwsi = lws_get_network_wsi(wsi);
+       if (!nwsi)
+               return;
+
+       lwsl_wsi_debug(wsi, "%s (%d)\n", lws_wsi_tag(nwsi),
+                                   nwsi->immortal_substream_count);
+
+       wsi->mux_stream_immortal = 1;
+       assert(nwsi->immortal_substream_count < 255); /* largest count */
+       nwsi->immortal_substream_count++;
+       if (nwsi->immortal_substream_count == 1)
+               lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
+}
+
 int
 lws_http_mark_sse(struct lws *wsi)
 {
-       lws_http_headers_detach(wsi);
-       lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+       if (!wsi)
+               return 0;
 
-       if (wsi->http2_substream) {
-               struct lws *nwsi = lws_get_network_wsi(wsi);
+       lws_http_headers_detach(wsi);
+       lws_mux_mark_immortal(wsi);
 
+       if (wsi->mux_substream)
                wsi->h2_stream_carries_sse = 1;
-               nwsi->immortal_substream_count++;
-               if (nwsi->immortal_substream_count == 1)
-                       lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
+
+       return 0;
+}
+
+#if defined(LWS_WITH_CLIENT)
+
+const char *
+lws_wsi_client_stash_item(struct lws *wsi, int stash_idx, int hdr_idx)
+{
+       /* try the generic client stash */
+       if (wsi->stash)
+               return wsi->stash->cis[stash_idx];
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       /* if not, use the ah stash if applicable */
+       return lws_hdr_simple_ptr(wsi, (enum lws_token_indexes)hdr_idx);
+#else
+       return NULL;
+#endif
+}
+#endif
+
+#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
+
+void
+lws_wsi_mux_insert(struct lws *wsi, struct lws *parent_wsi, unsigned int sid)
+{
+       lwsl_wsi_info(wsi, "par %s: assign sid %d (curr %d)",
+                       lws_wsi_tag(parent_wsi), sid, wsi->mux.my_sid);
+
+       if (wsi->mux.my_sid && wsi->mux.my_sid != (unsigned int)sid)
+               assert(0);
+
+       wsi->mux.my_sid = sid;
+       wsi->mux.parent_wsi = parent_wsi;
+       wsi->role_ops = parent_wsi->role_ops;
+
+       /* new guy's sibling is whoever was the first child before */
+       wsi->mux.sibling_list = parent_wsi->mux.child_list;
+
+       /* first child is now the new guy */
+       parent_wsi->mux.child_list = wsi;
+
+       parent_wsi->mux.child_count++;
+}
+
+struct lws *
+lws_wsi_mux_from_id(struct lws *parent_wsi, unsigned int sid)
+{
+       lws_start_foreach_ll(struct lws *, wsi, parent_wsi->mux.child_list) {
+               if (wsi->mux.my_sid == sid)
+                       return wsi;
+       } lws_end_foreach_ll(wsi, mux.sibling_list);
+
+       return NULL;
+}
+
+void
+lws_wsi_mux_dump_children(struct lws *wsi)
+{
+#if defined(_DEBUG)
+       if (!wsi->mux.parent_wsi || !lwsl_visible(LLL_INFO))
+               return;
+
+       lws_start_foreach_llp(struct lws **, w,
+                             wsi->mux.parent_wsi->mux.child_list) {
+               lwsl_wsi_info(wsi, "   \\---- child %s %s\n",
+                                  (*w)->role_ops ? (*w)->role_ops->name : "?",
+                                                          lws_wsi_tag(*w));
+               assert(*w != (*w)->mux.sibling_list);
+       } lws_end_foreach_llp(w, mux.sibling_list);
+#endif
+}
+
+void
+lws_wsi_mux_close_children(struct lws *wsi, int reason)
+{
+       struct lws *wsi2;
+       struct lws **w;
+
+       if (!wsi->mux.child_list)
+               return;
+
+       w = &wsi->mux.child_list;
+       while (*w) {
+               lwsl_wsi_info((*w), "   closing child");
+               /* disconnect from siblings */
+               wsi2 = (*w)->mux.sibling_list;
+               assert (wsi2 != *w);
+               (*w)->mux.sibling_list = NULL;
+               (*w)->socket_is_permanently_unusable = 1;
+               __lws_close_free_wsi(*w, (enum lws_close_status)reason, "mux child recurse");
+               *w = wsi2;
        }
+}
+
+
+void
+lws_wsi_mux_sibling_disconnect(struct lws *wsi)
+{
+       struct lws *wsi2;
+
+       lws_start_foreach_llp(struct lws **, w,
+                             wsi->mux.parent_wsi->mux.child_list) {
+
+               /* disconnect from siblings */
+               if (*w == wsi) {
+                       wsi2 = (*w)->mux.sibling_list;
+                       (*w)->mux.sibling_list = NULL;
+                       *w = wsi2;
+                       lwsl_wsi_debug(wsi, " disentangled from sibling %s",
+                                           lws_wsi_tag(wsi2));
+                       break;
+               }
+       } lws_end_foreach_llp(w, mux.sibling_list);
+       wsi->mux.parent_wsi->mux.child_count--;
+
+       wsi->mux.parent_wsi = NULL;
+}
+
+void
+lws_wsi_mux_dump_waiting_children(struct lws *wsi)
+{
+#if defined(_DEBUG)
+       lwsl_info("%s: %s: children waiting for POLLOUT service:\n",
+                 __func__, lws_wsi_tag(wsi));
+
+       wsi = wsi->mux.child_list;
+       while (wsi) {
+               lwsl_wsi_info(wsi, "  %c sid %u: 0x%x %s %s",
+                         wsi->mux.requested_POLLOUT ? '*' : ' ',
+                         wsi->mux.my_sid, lwsi_state(wsi),
+                         wsi->role_ops->name,
+                         wsi->a.protocol ? wsi->a.protocol->name : "noprotocol");
+
+               wsi = wsi->mux.sibling_list;
+       }
+#endif
+}
+
+int
+lws_wsi_mux_mark_parents_needing_writeable(struct lws *wsi)
+{
+       struct lws /* *network_wsi = lws_get_network_wsi(wsi), */ *wsi2;
+       //int already = network_wsi->mux.requested_POLLOUT;
+
+       /* mark everybody above him as requesting pollout */
+
+       wsi2 = wsi;
+       while (wsi2) {
+               wsi2->mux.requested_POLLOUT = 1;
+               lwsl_wsi_info(wsi2, "sid %u, pending writable",
+                                                       wsi2->mux.my_sid);
+               wsi2 = wsi2->mux.parent_wsi;
+       }
+
+       return 0; // already;
+}
+
+struct lws *
+lws_wsi_mux_move_child_to_tail(struct lws **wsi2)
+{
+       struct lws *w = *wsi2;
+
+       while (w) {
+               if (!w->mux.sibling_list) { /* w is the current last */
+                       lwsl_wsi_debug(w, "*wsi2 = %s\n", lws_wsi_tag(*wsi2));
+
+                       if (w == *wsi2) /* we are already last */
+                               break;
+
+                       /* last points to us as new last */
+                       w->mux.sibling_list = *wsi2;
+
+                       /* guy pointing to us until now points to
+                        * our old next */
+                       *wsi2 = (*wsi2)->mux.sibling_list;
+
+                       /* we point to nothing because we are last */
+                       w->mux.sibling_list->mux.sibling_list = NULL;
+
+                       /* w becomes us */
+                       w = w->mux.sibling_list;
+                       break;
+               }
+               w = w->mux.sibling_list;
+       }
+
+       /* clear the waiting for POLLOUT on the guy that was chosen */
+
+       if (w)
+               w->mux.requested_POLLOUT = 0;
+
+       return w;
+}
+
+int
+lws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi)
+{
+       struct lws *w = wsi->mux.child_list;
+
+       while (w) {
+               if (w->mux.requested_POLLOUT) {
+                       if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
+                               return -1;
+                       return 0;
+               }
+               w = w->mux.sibling_list;
+       }
+
+       if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
+               return -1;
 
        return 0;
 }
+
+int
+lws_wsi_txc_check_skint(struct lws_tx_credit *txc, int32_t tx_cr)
+{
+       if (txc->tx_cr <= 0) {
+               /*
+                * If other side is not able to cope with us sending any DATA
+                * so no matter if we have POLLOUT on our side if it's DATA we
+                * want to send.
+                */
+
+               if (!txc->skint)
+                       lwsl_info("%s: %p: skint (%d)\n", __func__, txc,
+                                 (int)txc->tx_cr);
+
+               txc->skint = 1;
+
+               return 1;
+       }
+
+       if (txc->skint)
+               lwsl_info("%s: %p: unskint (%d)\n", __func__, txc,
+                         (int)txc->tx_cr);
+
+       txc->skint = 0;
+
+       return 0;
+}
+
+#if defined(_DEBUG)
+void
+lws_wsi_txc_describe(struct lws_tx_credit *txc, const char *at, uint32_t sid)
+{
+       lwsl_info("%s: %p: %s: sid %d: %speer-to-us: %d, us-to-peer: %d\n",
+                 __func__, txc, at, (int)sid, txc->skint ? "SKINT, " : "",
+                 (int)txc->peer_tx_cr_est, (int)txc->tx_cr);
+}
+#endif
+
+int
+lws_wsi_tx_credit(struct lws *wsi, char peer_to_us, int add)
+{
+       if (wsi->role_ops && lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit))
+               return lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_tx_credit).
+                                  tx_credit(wsi, peer_to_us, add);
+
+       return 0;
+}
+
+/*
+ * Let the protocol know about incoming tx credit window updates if it's
+ * managing the flow control manually (it may want to proxy this information)
+ */
+
+int
+lws_wsi_txc_report_manual_txcr_in(struct lws *wsi, int32_t bump)
+{
+       if (!wsi->txc.manual)
+               /*
+                * If we don't care about managing it manually, no need to
+                * report it
+                */
+               return 0;
+
+       return user_callback_handle_rxflow(wsi->a.protocol->callback,
+                                          wsi, LWS_CALLBACK_WSI_TX_CREDIT_GET,
+                                          wsi->user_space, NULL, (size_t)bump);
+}
+
+#if defined(LWS_WITH_CLIENT)
+
+int
+lws_wsi_mux_apply_queue(struct lws *wsi)
+{
+       /* we have a transaction queue that wants to pipeline */
+
+       lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */
+       lws_vhost_lock(wsi->a.vhost);
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  wsi->dll2_cli_txn_queue_owner.head) {
+               struct lws *w = lws_container_of(d, struct lws,
+                                                dll2_cli_txn_queue);
+
+#if defined(LWS_ROLE_H2)
+               if (lwsi_role_http(wsi) &&
+                   lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS) {
+                       lwsl_wsi_info(w, "cli pipeq to be h2");
+
+                       lwsi_set_state(w, LRS_H1C_ISSUE_HANDSHAKE2);
+
+                       /* remove ourselves from client queue */
+                       lws_dll2_remove(&w->dll2_cli_txn_queue);
+
+                       /* attach ourselves as an h2 stream */
+                       lws_wsi_h2_adopt(wsi, w);
+               }
+#endif
+
+#if defined(LWS_ROLE_MQTT)
+               if (lwsi_role_mqtt(wsi) &&
+                   lwsi_state(wsi) == LRS_ESTABLISHED) {
+                       lwsl_wsi_info(w, "cli pipeq to be mqtt\n");
+
+                       /* remove ourselves from client queue */
+                       lws_dll2_remove(&w->dll2_cli_txn_queue);
+
+                       /* attach ourselves as an h2 stream */
+                       lws_wsi_mqtt_adopt(wsi, w);
+               }
+#endif
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       lws_vhost_unlock(wsi->a.vhost);
+       lws_context_unlock(wsi->a.context); /* } cx --------------  */
+
+       return 0;
+}
+
+#endif
+
+#endif
diff --git a/lib/core/CMakeLists.txt b/lib/core/CMakeLists.txt
new file mode 100644 (file)
index 0000000..dc64794
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+include_directories(.)
+
+list(APPEND SOURCES
+       core/alloc.c
+       core/buflist.c
+       core/context.c
+       core/lws_dll2.c
+       core/lws_map.c
+       core/libwebsockets.c
+       core/logs.c
+)
+
+if (LWS_WITH_FILE_OPS)
+       list(APPEND SOURCES core/vfs.c)
+endif()
+
+exports_to_parent_scope()
+
index 09d8882..b9ca8f0 100644 (file)
@@ -1,4 +1,28 @@
-#include "core/private.h"
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
 
 #if defined(LWS_HAVE_MALLOC_USABLE_SIZE)
 
@@ -86,8 +110,8 @@ _realloc(void *ptr, size_t size, const char *reason)
        void *v;
 
        if (size) {
-#if defined(LWS_WITH_ESP32)
-               lwsl_notice("%s: size %lu: %s (free heap %d)\n", __func__,
+#if defined(LWS_PLAT_FREERTOS)
+               lwsl_debug("%s: size %lu: %s (free heap %d)\n", __func__,
 #if defined(LWS_AMAZON_RTOS)
                            (unsigned long)size, reason, (unsigned int)xPortGetFreeHeapSize() - (int)size);
 #else
index 75c156f..b89330a 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #ifdef LWS_HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -56,7 +59,8 @@ lws_buflist_append_segment(struct lws_buflist **head, const uint8_t *buf,
        lwsl_info("%s: len %u first %d %p\n", __func__, (unsigned int)len,
                                              first, p);
 
-       nbuf = (struct lws_buflist *)lws_malloc(sizeof(**head) + len, __func__);
+       nbuf = (struct lws_buflist *)lws_malloc(sizeof(struct lws_buflist) +
+                                               len + LWS_PRE + 1, __func__);
        if (!nbuf) {
                lwsl_err("%s: OOM\n", __func__);
                return -1;
@@ -66,7 +70,8 @@ lws_buflist_append_segment(struct lws_buflist **head, const uint8_t *buf,
        nbuf->pos = 0;
        nbuf->next = NULL;
 
-       p = (void *)nbuf->buf;
+       /* whoever consumes this might need LWS_PRE from the start... */
+       p = (uint8_t *)nbuf + sizeof(*nbuf) + LWS_PRE;
        memcpy(p, buf, len);
 
        *head = nbuf;
@@ -82,6 +87,7 @@ lws_buflist_destroy_segment(struct lws_buflist **head)
        assert(*head);
        *head = old->next;
        old->next = NULL;
+       old->pos = old->len = 0;
        lws_free(old);
 
        return !*head; /* returns 1 if last segment just destroyed */
@@ -105,59 +111,153 @@ lws_buflist_destroy_all_segments(struct lws_buflist **head)
 size_t
 lws_buflist_next_segment_len(struct lws_buflist **head, uint8_t **buf)
 {
-       if (!*head) {
-               if (buf)
-                       *buf = NULL;
+       struct lws_buflist *b = (*head);
 
-               return 0;
-       }
+       if (buf)
+               *buf = NULL;
 
-       if (!(*head)->len && (*head)->next)
-               lws_buflist_destroy_segment(head);
+       if (!b)
+               return 0;       /* there is no next segment len */
 
-       if (!*head) {
-               if (buf)
-                       *buf = NULL;
+       if (!b->len && b->next)
+               if (lws_buflist_destroy_segment(head))
+                       return 0;
 
-               return 0;
-       }
+       b = (*head);
+       if (!b)
+               return 0;       /* there is no next segment len */
 
-       assert((*head)->pos < (*head)->len);
+       assert(b->pos < b->len);
 
        if (buf)
-               *buf = (*head)->buf + (*head)->pos;
+               *buf = ((uint8_t *)b) + sizeof(*b) + b->pos + LWS_PRE;
 
-       return (*head)->len - (*head)->pos;
+       return b->len - b->pos;
 }
 
-int
+size_t
 lws_buflist_use_segment(struct lws_buflist **head, size_t len)
 {
-       assert(*head);
+       struct lws_buflist *b = (*head);
+
+       assert(b);
        assert(len);
-       assert((*head)->pos + len <= (*head)->len);
+       assert(b->pos + len <= b->len);
+
+       b->pos = b->pos + (size_t)len;
+
+       assert(b->pos <= b->len);
 
-       (*head)->pos += len;
-       if ((*head)->pos == (*head)->len)
-               lws_buflist_destroy_segment(head);
+       if (b->pos < b->len)
+               return (unsigned int)(b->len - b->pos);
+
+       if (lws_buflist_destroy_segment(head))
+               /* last segment was just destroyed */
+               return 0;
+
+       return lws_buflist_next_segment_len(head, NULL);
+}
+
+size_t
+lws_buflist_total_len(struct lws_buflist **head)
+{
+       struct lws_buflist *p = *head;
+       size_t size = 0;
+
+       while (p) {
+               size += p->len;
+               p = p->next;
+       }
+
+       return size;
+}
+
+int
+lws_buflist_linear_copy(struct lws_buflist **head, size_t ofs, uint8_t *buf,
+                       size_t len)
+{
+       struct lws_buflist *p = *head;
+       uint8_t *obuf = buf;
+       size_t s;
+
+       while (p && len) {
+               if (ofs < p->len) {
+                       s = p->len - ofs;
+                       if (s > len)
+                               s = len;
+                       memcpy(buf, ((uint8_t *)&p[1]) + LWS_PRE + ofs, s);
+                       len -= s;
+                       buf += s;
+                       ofs = 0;
+               } else
+                       ofs -= p->len;
+               p = p->next;
+       }
+
+       return lws_ptr_diff(buf, obuf);
+}
+
+int
+lws_buflist_linear_use(struct lws_buflist **head, uint8_t *buf, size_t len)
+{
+       uint8_t *obuf = buf;
+       size_t s;
+
+       while (*head && len) {
+               s = (*head)->len - (*head)->pos;
+               if (s > len)
+                       s = len;
+               memcpy(buf, ((uint8_t *)((*head) + 1)) +
+                           LWS_PRE + (*head)->pos, s);
+               len -= s;
+               buf += s;
+               lws_buflist_use_segment(head, s);
+       }
+
+       return lws_ptr_diff(buf, obuf);
+}
+
+int
+lws_buflist_fragment_use(struct lws_buflist **head, uint8_t *buf,
+                        size_t len, char *frag_first, char *frag_fin)
+{
+       uint8_t *obuf = buf;
+       size_t s;
 
        if (!*head)
                return 0;
 
-       return (int)((*head)->len - (*head)->pos);
+       s = (*head)->len - (*head)->pos;
+       if (s > len)
+               s = len;
+
+       if (frag_first)
+               *frag_first = !(*head)->pos;
+
+       if (frag_fin)
+               *frag_fin = (*head)->pos + s == (*head)->len;
+
+       memcpy(buf, ((uint8_t *)((*head) + 1)) + LWS_PRE + (*head)->pos, s);
+       len -= s;
+       buf += s;
+       lws_buflist_use_segment(head, s);
+
+       return lws_ptr_diff(buf, obuf);
 }
 
+#if defined(_DEBUG)
 void
-lws_buflist_describe(struct lws_buflist **head, void *id)
+lws_buflist_describe(struct lws_buflist **head, void *id, const char *reason)
 {
        struct lws_buflist *old;
        int n = 0;
 
        if (*head == NULL)
-               lwsl_notice("%p: buflist empty\n", id);
+               lwsl_notice("%p: %s: buflist empty\n", id, reason);
 
        while (*head) {
-               lwsl_notice("%p: %d: %llu / %llu (%llu left)\n", id, n,
+               lwsl_notice("%p: %s: %d: %llu / %llu (%llu left)\n", id,
+                           reason, n,
                            (unsigned long long)(*head)->pos,
                            (unsigned long long)(*head)->len,
                            (unsigned long long)(*head)->len - (*head)->pos);
@@ -170,3 +270,4 @@ lws_buflist_describe(struct lws_buflist **head, void *id)
                n++;
        }
 }
+#endif
index 5d2aa33..fb684e5 100644 (file)
@@ -1,32 +1,48 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #ifndef LWS_BUILD_HASH
 #define LWS_BUILD_HASH "unknown-build-hash"
 #endif
 
+static const char *library_version = LWS_LIBRARY_VERSION;
 
-static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
+#if defined(LWS_WITH_MBEDTLS)
+extern const char *mbedtls_client_preload_filepath;
+#endif
+
+#if defined(LWS_HAVE_SYS_RESOURCE_H)
+/* for setrlimit */
+#include <sys/resource.h>
+#endif
+
+#if defined(LWS_WITH_NETWORK)
+/* in ms */
+static uint32_t default_backoff_table[] = { 1000, 3000, 9000, 17000 };
+#endif
 
 /**
  * lws_get_library_version: get version and git hash library built from
@@ -35,123 +51,824 @@ static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
  *     representing the library version followed by the git head hash it
  *     was built from
  */
-LWS_VISIBLE const char *
+const char *
 lws_get_library_version(void)
 {
        return library_version;
 }
 
-#if defined(LWS_WITH_STATS)
-static void
-lws_sul_stats_cb(lws_sorted_usec_list_t *sul)
+#if defined(LWS_WITH_NETWORK)
+
+#if defined(LWS_WITH_SYS_STATE)
+
+static const char * system_state_names[] = {
+       "undef",
+       "CONTEXT_CREATED",
+       "INITIALIZED",
+       "IFACE_COLDPLUG",
+       "DHCP",
+       "CPD_PRE_TIME",
+       "TIME_VALID",
+       "CPD_POST_TIME",
+       "POLICY_VALID",
+       "REGISTERED",
+       "AUTH1",
+       "AUTH2",
+       "OPERATIONAL",
+       "POLICY_INVALID",
+       "DESTROYING"
+};
+
+
+/*
+ * Handle provoking protocol init when we pass through the right system state
+ */
+
+static int
+lws_state_notify_protocol_init(struct lws_state_manager *mgr,
+                              struct lws_state_notify_link *link, int current,
+                              int target)
 {
-       struct lws_context_per_thread *pt = lws_container_of(sul,
-                       struct lws_context_per_thread, sul_stats);
+       struct lws_context *context = lws_container_of(mgr, struct lws_context,
+                                                      mgr_system);
+#if defined(LWS_WITH_SECURE_STREAMS) && \
+    defined(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM)
+       lws_system_blob_t *ab0, *ab1;
+#endif
+       int n;
+
+       /*
+        * Deal with any attachments that were waiting for the right state
+        * to come along
+        */
 
-       lws_stats_log_dump(pt->context);
+       for (n = 0; n < context->count_threads; n++)
+               lws_system_do_attach(&context->pt[n]);
 
-       __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_stats, 10 * LWS_US_PER_SEC);
-}
+#if defined(LWS_WITH_SYS_DHCP_CLIENT)
+       if (target == LWS_SYSTATE_DHCP) {
+               /*
+                * Don't let it past here until at least one iface has been
+                * configured for operation with DHCP
+                */
+
+               if (!lws_dhcpc_status(context, NULL))
+                       return 1;
+       }
 #endif
-#if defined(LWS_WITH_PEER_LIMITS)
+
+#if defined(LWS_WITH_SYS_NTPCLIENT)
+       if (target == LWS_SYSTATE_TIME_VALID &&
+           lws_now_secs() < 1594017754) /* 06:42 Mon Jul 6 2020 UTC */ {
+               lws_ntpc_trigger(context);
+
+               return 1;
+       }
+#endif
+
+#if defined(LWS_WITH_NETLINK)
+       /*
+        * If we're going to use netlink routing data for DNS, we have to
+        * wait to collect it asynchronously from the platform first.  Netlink
+        * role init starts a ctx sul for 350ms (reset to 100ms each time some
+        * new netlink data comes) that sets nl_initial_done and tries to move
+        * us to OPERATIONAL
+        */
+
+       if (target == LWS_SYSTATE_IFACE_COLDPLUG &&
+           context->netlink &&
+           !context->nl_initial_done) {
+               lwsl_cx_info(context, "waiting for netlink coldplug");
+
+               return 1;
+       }
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS) && \
+    defined(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM)
+       /*
+        * Skip this if we are running something without the policy for it
+        *
+        * If root token is empty, skip too.
+        */
+
+       ab0 = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, 0);
+       ab1 = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, 1);
+
+       if (target == LWS_SYSTATE_AUTH1 &&
+           context->pss_policies && ab0 && ab1 &&
+           !lws_system_blob_get_size(ab0) &&
+           lws_system_blob_get_size(ab1)) {
+               lwsl_cx_info(context,
+                            "AUTH1 state triggering api.amazon.com auth");
+               /*
+                * Start trying to acquire it if it's not already in progress
+                * returns nonzero if we determine it's not needed
+                */
+               if (!lws_ss_sys_auth_api_amazon_com(context))
+                       return 1;
+       }
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+#if defined(LWS_WITH_DRIVERS)
+       /*
+        * See if we should do the SS Captive Portal Detection
+        */
+       if (target == LWS_SYSTATE_CPD_PRE_TIME) {
+               if (lws_system_cpd_state_get(context) == LWS_CPD_INTERNET_OK)
+                       return 0; /* allow it */
+
+               /*
+                * Don't allow it to move past here until we get an IP and
+                * CPD passes, driven by SMD
+                */
+
+               return 1;
+       }
+#endif
+
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       /*
+        * Skip this if we are running something without the policy for it
+        */
+       if (target == LWS_SYSTATE_POLICY_VALID &&
+           context->pss_policies && !context->policy_updated) {
+
+               if (context->hss_fetch_policy)
+                       return 1;
+
+               lwsl_cx_debug(context, "starting policy fetch");
+               /*
+                * Start trying to acquire it if it's not already in progress
+                * returns nonzero if we determine it's not needed
+                */
+               if (!lws_ss_sys_fetch_policy(context))
+                       /* we have it */
+                       return 0;
+
+               /* deny while we fetch it */
+
+               return 1;
+       }
+#endif
+#endif
+
+       /* protocol part */
+
+       if (context->protocol_init_done)
+               return 0;
+
+       if (target != LWS_SYSTATE_POLICY_VALID)
+               return 0;
+
+       lwsl_cx_info(context, "doing protocol init on POLICY_VALID\n");
+
+       return lws_protocol_init(context);
+}
+
 static void
-lws_sul_peer_limits_cb(lws_sorted_usec_list_t *sul)
+lws_context_creation_completion_cb(lws_sorted_usec_list_t *sul)
+{
+       struct lws_context *context = lws_container_of(sul, struct lws_context,
+                                                      sul_system_state);
+
+       /* if nothing is there to intercept anything, go all the way */
+       lws_state_transition_steps(&context->mgr_system,
+                                  LWS_SYSTATE_OPERATIONAL);
+}
+#endif /* WITH_SYS_STATE */
+
+#if defined(LWS_WITH_SYS_SMD)
+static int
+lws_system_smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
+                 void *buf, size_t len)
 {
-       struct lws_context_per_thread *pt = lws_container_of(sul,
-                       struct lws_context_per_thread, sul_peer_limits);
+       struct lws_context *cx = (struct lws_context *)opaque;
+
+       if (_class != LWSSMDCL_NETWORK)
+               return 0;
+
+       /* something external requested CPD check */
+
+       if (!lws_json_simple_strcmp(buf, len, "\"trigger\":", "cpdcheck"))
+               lws_system_cpd_start(cx);
+       else
+               /*
+                * IP acquisition on any interface triggers captive portal
+                * check on default route
+                */
+               if (!lws_json_simple_strcmp(buf, len, "\"type\":", "ipacq"))
+                       lws_system_cpd_start(cx);
+
+#if defined(LWS_WITH_SYS_NTPCLIENT)
+       /*
+        * Captive portal detect showing internet workable triggers NTP Client
+        */
+       if (!lws_json_simple_strcmp(buf, len, "\"type\":", "cps") &&
+           !lws_json_simple_strcmp(buf, len, "\"result\":", "OK") &&
+           lws_now_secs() < 1594017754) /* 06:42 Mon Jul 6 2020 UTC */
+               lws_ntpc_trigger(cx);
+#endif
+
+#if defined(LWS_WITH_SYS_DHCP_CLIENT) && 0
+       /*
+        * Any network interface linkup triggers DHCP
+        */
+       if (!lws_json_simple_strcmp(buf, len, "\"type\":", "linkup"))
+               lws_ntpc_trigger(cx);
 
-       lws_peer_cull_peer_wait_list(pt->context);
+#endif
+
+#if defined(LWS_WITH_DRIVERS) && defined(LWS_WITH_NETWORK)
+       lws_netdev_smd_cb(opaque, _class, timestamp, buf, len);
+#endif
 
-       __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_peer_limits, 10 * LWS_US_PER_SEC);
+       return 0;
 }
 #endif
 
 
-LWS_VISIBLE struct lws_context *
+
+#endif /* NETWORK */
+
+#if !defined(LWS_WITH_NO_LOGS)
+
+static const char * const opts_str =
+#if defined(LWS_WITH_NETWORK)
+                       "NET "
+#else
+                       "NoNET "
+#endif
+#if defined(LWS_WITH_CLIENT)
+                       "CLI "
+#endif
+#if defined(LWS_WITH_SERVER)
+                       "SRV "
+#endif
+#if defined(LWS_ROLE_H1)
+                       "H1 "
+#endif
+#if defined(LWS_ROLE_H2)
+                       "H2 "
+#endif
+#if defined(LWS_ROLE_WS)
+                       "WS "
+#endif
+#if defined(LWS_ROLE_MQTT)
+                       "MQTT "
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS) && !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+                       "SS-JSON-POL "
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+                       "SS-STATIC-POL "
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+                       "SSPROX "
+#endif
+
+#if defined(LWS_WITH_MBEDTLS)
+                       "MbedTLS "
+#endif
+#if defined(LWS_WITH_CONMON)
+                       "ConMon "
+#endif
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+                       "FLTINJ "
+#endif
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+                       "ASYNC_DNS "
+#endif
+#if defined(LWS_WITH_SYS_NTPCLIENT)
+                       "NTPCLIENT "
+#endif
+#if defined(LWS_WITH_SYS_DHCP_CLIENT)
+                       "DHCP_CLIENT "
+#endif
+;
+
+#endif
+
+#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
+static const struct lws_evlib_map {
+       uint64_t        flag;
+       const char      *name;
+} map[] = {
+       { LWS_SERVER_OPTION_LIBUV,    "evlib_uv" },
+       { LWS_SERVER_OPTION_LIBEVENT, "evlib_event" },
+       { LWS_SERVER_OPTION_GLIB,     "evlib_glib" },
+       { LWS_SERVER_OPTION_LIBEV,    "evlib_ev" },
+       { LWS_SERVER_OPTION_SDEVENT,  "evlib_sd" },
+       { LWS_SERVER_OPTION_ULOOP,    "evlib_uloop" },
+};
+static const char * const dlist[] = {
+       ".",                            /* Priority 1: plugins in cwd */
+       LWS_INSTALL_LIBDIR,             /* Priority 2: plugins in install dir */
+       NULL
+};
+#endif
+
+struct lws_context *
 lws_create_context(const struct lws_context_creation_info *info)
 {
        struct lws_context *context = NULL;
+#if !defined(LWS_WITH_NO_LOGS)
+       const char *s = "IPv6-absent";
+#endif
+#if defined(LWS_WITH_FILE_OPS)
        struct lws_plat_file_ops *prev;
+#endif
 #ifndef LWS_NO_DAEMONIZE
        pid_t pid_daemon = get_daemonize_pid();
 #endif
 #if defined(LWS_WITH_NETWORK)
-       int n;
+       const lws_plugin_evlib_t *plev = NULL;
+       unsigned short count_threads = 1;
+       uint8_t *u;
+       uint16_t us_wait_resolution = 0;
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
+       struct lws_cache_creation_info ci;
 #endif
+
 #if defined(__ANDROID__)
        struct rlimit rt;
 #endif
+       size_t
+#if defined(LWS_PLAT_FREERTOS)
+               /* smaller default, can set in info->pt_serv_buf_size */
+               s1 = 2048,
+#else
+               s1 = 4096,
+#endif
+               size = sizeof(struct lws_context);
+#endif
+
+       int n;
+       unsigned int lpf = info->fd_limit_per_thread;
+#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
+       struct lws_plugin               *evlib_plugin_list = NULL;
+#if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
+       char            *ld_env;
+#endif
+#endif
+#if defined(LWS_WITH_LIBUV)
+       char fatal_exit_defer = 0;
+#endif
+
+
+       if (lws_fi(&info->fic, "ctx_createfail1"))
+               goto early_bail;
 
-       lwsl_info("Initial logging level %d\n", log_level);
-       lwsl_info("Libwebsockets version: %s\n", library_version);
+       if (lpf) {
+               lpf+= 2;
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+               lpf++;
+#endif
+#if defined(LWS_WITH_SYS_NTPCLIENT)
+               lpf++;
+#endif
+#if defined(LWS_WITH_SYS_DHCP_CLIENT)
+               lpf++;
+#endif
+       }
 
-#ifdef LWS_WITH_IPV6
+#if defined(LWS_WITH_IPV6) && !defined(LWS_WITH_NO_LOGS)
        if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6))
-               lwsl_info("IPV6 compiled in and enabled\n");
+               s = "IPV6-on";
        else
-               lwsl_info("IPV6 compiled in but disabled\n");
-#else
-       lwsl_info("IPV6 not compiled in\n");
+               s = "IPV6-off";
 #endif
 
-       lwsl_info(" LWS_DEF_HEADER_LEN    : %u\n", LWS_DEF_HEADER_LEN);
-       lwsl_info(" LWS_MAX_PROTOCOLS     : %u\n", LWS_MAX_PROTOCOLS);
-       lwsl_info(" LWS_MAX_SMP           : %u\n", LWS_MAX_SMP);
-       lwsl_info(" sizeof (*info)        : %ld\n", (long)sizeof(*info));
-#if defined(LWS_WITH_STATS)
-       lwsl_info(" LWS_WITH_STATS        : on\n");
+       if (lws_plat_context_early_init())
+               goto early_bail;
+
+#if defined(LWS_WITH_NETWORK)
+       if (info->count_threads)
+               count_threads = (unsigned short)info->count_threads;
+
+       if (count_threads > LWS_MAX_SMP)
+               count_threads = LWS_MAX_SMP;
+
+       if (info->pt_serv_buf_size)
+               s1 = info->pt_serv_buf_size;
+
+       /* pt fakewsi and the pt serv buf allocations ride after the context */
+       size += count_threads * s1;
+#if !defined(LWS_PLAT_FREERTOS)
+       size += (count_threads * sizeof(struct lws));
+#endif
+
+       if (info->event_lib_custom) {
+               plev = info->event_lib_custom;
+               us_wait_resolution = 0;
+       }
+#if defined(LWS_WITH_POLL)
+       else {
+               extern const lws_plugin_evlib_t evlib_poll;
+               plev = &evlib_poll;
+#if !defined(LWS_PLAT_FREERTOS)
+               /*
+                * ... freertos has us-resolution select()...
+                * others are to ms-resolution poll()
+                */
+               us_wait_resolution = 1000;
+#endif
+       }
+#endif
+
+#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
+
+       /*
+        * New style dynamically loaded event lib support
+        *
+        * We have to pick and load the event lib plugin before we allocate
+        * the context object, so we can overallocate it correctly
+        */
+
+#if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
+       ld_env = getenv("LD_LIBRARY_PATH");
+       lwsl_info("%s: ev lib path %s, '%s'\n", __func__,
+                       LWS_INSTALL_LIBDIR, ld_env);
 #endif
-       lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
-#if defined(LWS_WITH_HTTP2)
-       lwsl_info(" HTTP2 support         : available\n");
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(map); n++) {
+               char ok = 0;
+
+               if (!lws_check_opt(info->options, map[n].flag))
+                       continue;
+
+               if (!lws_plugins_init(&evlib_plugin_list,
+                                    dlist, "lws_evlib_plugin",
+                                    map[n].name, NULL, NULL))
+                       ok = 1;
+
+               if (!ok || lws_fi(&info->fic, "ctx_createfail_plugin_init")) {
+                       lwsl_err("%s: failed to load %s\n", __func__,
+                                       map[n].name);
+                       goto bail;
+               }
+
+#if defined(LWS_WITH_LIBUV)
+               if (!n) /* libuv */
+                       fatal_exit_defer = !!info->foreign_loops;
+#endif
+
+               if (!evlib_plugin_list ||
+                   lws_fi(&info->fic, "ctx_createfail_evlib_plugin")) {
+                       lwsl_err("%s: unable to load evlib plugin %s\n",
+                                       __func__, map[n].name);
+
+                       goto bail;
+               }
+               plev = (const lws_plugin_evlib_t *)evlib_plugin_list->hdr;
+               break;
+       }
 #else
-       lwsl_info(" HTTP2 support         : not configured\n");
+#if defined(LWS_WITH_EVENT_LIBS)
+       /*
+        * set the context event loops ops struct
+        *
+        * after this, all event_loop actions use the generic ops
+        */
+
+       /*
+        * oldstyle built-in event lib support
+        *
+        * We have composed them into the libwebsockets lib itself, we can
+        * just pick the ops we want and done
+        */
+
+#if defined(LWS_WITH_LIBUV)
+       if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV)) {
+               extern const lws_plugin_evlib_t evlib_uv;
+               plev = &evlib_uv;
+               fatal_exit_defer = !!info->foreign_loops;
+               us_wait_resolution = 0;
+       }
 #endif
-       if (lws_plat_context_early_init())
-               return NULL;
 
-       context = lws_zalloc(sizeof(struct lws_context), "context");
-       if (!context) {
-               lwsl_err("No memory for websocket context\n");
-               return NULL;
+#if defined(LWS_WITH_LIBEVENT)
+       if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEVENT)) {
+               extern const lws_plugin_evlib_t evlib_event;
+               plev = &evlib_event;
+               us_wait_resolution = 0;
        }
+#endif
 
+#if defined(LWS_WITH_GLIB)
+       if (lws_check_opt(info->options, LWS_SERVER_OPTION_GLIB)) {
+               extern const lws_plugin_evlib_t evlib_glib;
+               plev = &evlib_glib;
+               us_wait_resolution = 0;
+       }
+#endif
+
+#if defined(LWS_WITH_LIBEV)
+       if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEV)) {
+               extern const lws_plugin_evlib_t evlib_ev;
+               plev = &evlib_ev;
+               us_wait_resolution = 0;
+       }
+#endif
+
+#if defined(LWS_WITH_SDEVENT)
+    if (lws_check_opt(info->options, LWS_SERVER_OPTION_SDEVENT)) {
+        extern const lws_plugin_evlib_t evlib_sd;
+        plev = &evlib_sd;
+        us_wait_resolution = 0;
+    }
+#endif
+
+#if defined(LWS_WITH_ULOOP)
+    if (lws_check_opt(info->options, LWS_SERVER_OPTION_ULOOP)) {
+        extern const lws_plugin_evlib_t evlib_uloop;
+        plev = &evlib_uloop;
+        us_wait_resolution = 0;
+    }
+#endif
+
+#endif /* with event libs */
+
+#endif /* not with ev plugins */
+
+       if (!plev || lws_fi(&info->fic, "ctx_createfail_evlib_sel"))
+               goto fail_event_libs;
+
+#if defined(LWS_WITH_NETWORK)
+       size += (size_t)plev->ops->evlib_size_ctx /* the ctx evlib priv */ +
+               (count_threads * (size_t)plev->ops->evlib_size_pt) /* the pt evlib priv */;
+#endif
+
+       context = lws_zalloc(size, "context");
+       if (!context || lws_fi(&info->fic, "ctx_createfail_oom_ctx")) {
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+               lws_free(context);
+#endif
+               lwsl_err("OOM");
+               goto early_bail;
+       }
+
+#if defined(LWS_WITH_NETWORK)
+       context->event_loop_ops = plev->ops;
+       context->us_wait_resolution = us_wait_resolution;
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       {
+               struct lws_cache_creation_info ci;
+
+               memset(&ci, 0, sizeof(ci));
+               ci.cx = context;
+               ci.ops = &lws_cache_ops_heap;
+               ci.name = "jitt";
+               ci.max_footprint = info->jitt_cache_max_footprint;
+               context->trust_cache = lws_cache_create(&ci);
+       }
+#endif
+#endif
+#if defined(LWS_WITH_EVENT_LIBS)
+       /* at the very end */
+       context->evlib_ctx = (uint8_t *)context + size -
+                                       plev->ops->evlib_size_ctx;
+#endif
+#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
+       context->evlib_plugin_list = evlib_plugin_list;
+#endif
+
+#if !defined(LWS_PLAT_FREERTOS)
        context->uid = info->uid;
        context->gid = info->gid;
        context->username = info->username;
        context->groupname = info->groupname;
+#endif
+       context->name                   = info->vhost_name;
+       if (info->log_cx)
+               context->log_cx = info->log_cx;
+       else
+               context->log_cx = &log_cx;
+       lwsl_refcount_cx(context->log_cx, 1);
+
        context->system_ops = info->system_ops;
+       context->pt_serv_buf_size = (unsigned int)s1;
+       context->protocols_copy = info->protocols;
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       context->vh_idle_grace_ms = info->vh_idle_grace_ms ?
+                       info->vh_idle_grace_ms : 5000;
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       context->fic.name = "ctx";
+       if (info->fic.fi_owner.count)
+               /*
+                * This moves all the lws_fi_t from info->fi to the context fi,
+                * leaving it empty, so no injection added to default vhost
+                */
+               lws_fi_import(&context->fic, &info->fic);
+#endif
+
+
+#if defined(LWS_WITH_SYS_SMD)
+       context->smd_ttl_us = info->smd_ttl_us ? info->smd_ttl_us :
+#if defined(LWS_PLAT_FREERTOS)
+                       5000000;
+#else
+                       2000000;
+#endif
+       context->smd_queue_depth = (uint16_t)(info->smd_queue_depth ?
+                                               info->smd_queue_depth :
+#if defined(LWS_PLAT_FREERTOS)
+                                               20);
+#else
+                                               40);
+#endif
+#endif
+
+#if defined(LWS_WITH_NETWORK)
+       context->lcg[LWSLCG_WSI].tag_prefix = "wsi";
+       context->lcg[LWSLCG_VHOST].tag_prefix = "vh";
+       context->lcg[LWSLCG_WSI_SERVER].tag_prefix = "wsisrv"; /* adopted */
+
+#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
+       context->lcg[LWSLCG_WSI_MUX].tag_prefix = "mux"; /* a mux child wsi */
+#endif
+
+#if defined(LWS_WITH_CLIENT)
+       context->lcg[LWSLCG_WSI_CLIENT].tag_prefix = "wsicli";
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+#if defined(LWS_WITH_CLIENT)
+       context->lcg[LWSLCG_SS_CLIENT].tag_prefix = "SScli";
+#endif
+#if defined(LWS_WITH_SERVER)
+       context->lcg[LWSLCG_SS_SERVER].tag_prefix = "SSsrv";
+#endif
+#if defined(LWS_WITH_CLIENT)
+       context->lcg[LWSLCG_WSI_SS_CLIENT].tag_prefix = "wsiSScli";
+#endif
+#if defined(LWS_WITH_SERVER)
+       context->lcg[LWSLCG_WSI_SS_SERVER].tag_prefix = "wsiSSsrv";
+#endif
+#endif
+#endif
+
+#if defined(LWS_WITH_SYS_METRICS)
+       /*
+        * If we're not using secure streams, we can still pass in a linked-
+        * list of metrics policies
+        */
+       context->metrics_policies = info->metrics_policies;
+       context->metrics_prefix = info->metrics_prefix;
+
+       context->mt_service = lws_metric_create(context,
+                                       LWSMTFL_REPORT_DUTY_WALLCLOCK_US |
+                                       LWSMTFL_REPORT_ONLY_GO, "cpu.svc");
+
+#if defined(LWS_WITH_CLIENT)
+
+       context->mt_conn_dns = lws_metric_create(context,
+                                                LWSMTFL_REPORT_MEAN |
+                                                LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
+                                                "n.cn.dns");
+       context->mt_conn_tcp = lws_metric_create(context,
+                                                LWSMTFL_REPORT_MEAN |
+                                                LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
+                                                "n.cn.tcp");
+       context->mt_conn_tls = lws_metric_create(context,
+                                                LWSMTFL_REPORT_MEAN |
+                                                LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
+                                                "n.cn.tls");
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       context->mt_http_txn = lws_metric_create(context,
+                                                LWSMTFL_REPORT_MEAN |
+                                                LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
+                                                "n.http.txn");
+#endif
+
+       context->mth_conn_failures = lws_metric_create(context,
+                                       LWSMTFL_REPORT_HIST, "n.cn.failures");
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       context->mt_adns_cache = lws_metric_create(context,
+                                                  LWSMTFL_REPORT_MEAN |
+                                                  LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
+                                                  "n.cn.adns");
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS)
+       context->mth_ss_conn = lws_metric_create(context, LWSMTFL_REPORT_HIST,
+                                                "n.ss.conn");
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       context->mt_ss_cliprox_conn = lws_metric_create(context,
+                       LWSMTFL_REPORT_HIST,
+                                                       "n.ss.cliprox.conn");
+       context->mt_ss_cliprox_paylat = lws_metric_create(context,
+                                                         LWSMTFL_REPORT_MEAN |
+                                                         LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
+                                                         "n.ss.cliprox.paylat");
+       context->mt_ss_proxcli_paylat = lws_metric_create(context,
+                                                         LWSMTFL_REPORT_MEAN |
+                                                         LWSMTFL_REPORT_DUTY_WALLCLOCK_US,
+                                                         "n.ss.proxcli.paylat");
+#endif
+
+#endif /* network + metrics + client */
+
+#if defined(LWS_WITH_SERVER)
+       context->mth_srv = lws_metric_create(context,
+                                            LWSMTFL_REPORT_HIST, "n.srv");
+#endif /* network + metrics + server */
+
+#endif /* network + metrics */
+
+#endif /* network */
+
+       lwsl_cx_notice(context, "LWS: %s, %s%s", library_version, opts_str, s);
+#if defined(LWS_WITH_NETWORK)
+       lwsl_cx_info(context, "Event loop: %s", plev->ops->name);
+#endif
+
+       /*
+        * Proxy group
+        */
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+#if defined(LWS_WITH_CLIENT)
+       context->lcg[LWSLCG_SSP_CLIENT].tag_prefix = "SSPcli";
+#endif
+#if defined(LWS_WITH_SERVER)
+       context->lcg[LWSLCG_SSP_ONWARD].tag_prefix = "SSPonw";
+#endif
+#if defined(LWS_WITH_CLIENT)
+       context->lcg[LWSLCG_WSI_SSP_CLIENT].tag_prefix = "wsiSSPcli";
+#endif
+#if defined(LWS_WITH_SERVER)
+       context->lcg[LWSLCG_WSI_SSP_ONWARD].tag_prefix = "wsiSSPonw";
+#endif
+#endif
+
+
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       /* directly use the user-provided policy object list */
+       context->pss_policies = info->pss_policies;
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) && defined(LWS_WITH_CLIENT)
+       context->ss_proxy_bind = info->ss_proxy_bind;
+       context->ss_proxy_port = info->ss_proxy_port;
+       context->ss_proxy_address = info->ss_proxy_address;
+       if (context->ss_proxy_bind && context->ss_proxy_address)
+               lwsl_cx_notice(context, "ss proxy bind '%s', port %d, ads '%s'",
+                       context->ss_proxy_bind, context->ss_proxy_port,
+                       context->ss_proxy_address);
+#endif
+
+#if defined(LWS_WITH_NETWORK)
+       context->undestroyed_threads = count_threads;
+       context->count_threads = count_threads;
+
+#if defined(LWS_ROLE_WS) && defined(LWS_WITHOUT_EXTENSIONS)
+        if (info->extensions)
+                lwsl_cx_warn(context, "WITHOUT_EXTENSIONS but exts ptr set");
+#endif
+#endif /* network */
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       context->pss_policies_json = info->pss_policies_json;
+#endif
+#if defined(LWS_WITH_SSPLUGINS)
+       context->pss_plugins = info->pss_plugins;
+#endif
+#endif
 
        /* if he gave us names, set the uid / gid */
-       if (lws_plat_drop_app_privileges(context, 0))
-               goto bail;
+       if (lws_plat_drop_app_privileges(context, 0) ||
+           lws_fi(&context->fic, "ctx_createfail_privdrop"))
+               goto free_context_fail2;
 
-lwsl_info("context created\n");
 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
 #if defined(LWS_WITH_MBEDTLS)
        context->tls_ops = &tls_ops_mbedtls;
+
+       mbedtls_client_preload_filepath = info->mbedtls_client_preload_filepath;
 #else
        context->tls_ops = &tls_ops_openssl;
 #endif
 #endif
 
-       if (info->pt_serv_buf_size)
-               context->pt_serv_buf_size = info->pt_serv_buf_size;
-       else
-               context->pt_serv_buf_size = 4096;
-
-#if defined(LWS_ROLE_H2)
-       role_ops_h2.init_context(context, info);
-#endif
-
 #if LWS_MAX_SMP > 1
        lws_mutex_refcount_init(&context->mr);
 #endif
 
-#if defined(LWS_WITH_ESP32)
+#if defined(LWS_PLAT_FREERTOS)
+#if defined(LWS_AMAZON_RTOS)
+       context->last_free_heap = xPortGetFreeHeapSize();
+#else
        context->last_free_heap = esp_get_free_heap_size();
 #endif
+#endif
 
+#if defined(LWS_WITH_FILE_OPS)
        /* default to just the platform fops implementation */
 
        context->fops_platform.LWS_FOP_OPEN     = _lws_plat_file_open;
@@ -182,8 +899,11 @@ lwsl_info("context created\n");
        /* if user provided fops, tack them on the end of the list */
        if (info->fops)
                prev->next = info->fops;
+#endif
 
+#if defined(LWS_WITH_SERVER)
        context->reject_service_keywords = info->reject_service_keywords;
+#endif
        if (info->external_baggage_free_on_destroy)
                context->external_baggage_free_on_destroy =
                        info->external_baggage_free_on_destroy;
@@ -192,47 +912,68 @@ lwsl_info("context created\n");
 #endif
        context->pcontext_finalize = info->pcontext;
 
+#if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
        context->simultaneous_ssl_restriction =
                        info->simultaneous_ssl_restriction;
+       context->simultaneous_ssl_handshake_restriction =
+                       info->simultaneous_ssl_handshake_restriction;
+#endif
 
        context->options = info->options;
 
+#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE) && !defined(WIN32)
+       /*
+        * If asked, try to set the rlimit / ulimit for process sockets / files.
+        * We read the effective limit in a moment, so we will find out the
+        * real limit according to system constraints then.
+        */
+       if (info->rlimit_nofile) {
+               struct rlimit rl;
+
+               rl.rlim_cur = (unsigned int)info->rlimit_nofile;
+               rl.rlim_max = (unsigned int)info->rlimit_nofile;
+               setrlimit(RLIMIT_NOFILE, &rl);
+       }
+#endif
+
 #ifndef LWS_NO_DAEMONIZE
        if (pid_daemon) {
                context->started_with_parent = pid_daemon;
-               lwsl_info(" Started with daemon pid %u\n", (unsigned int)pid_daemon);
+               lwsl_cx_info(context, " Started with daemon pid %u",
+                               (unsigned int)pid_daemon);
        }
 #endif
 #if defined(__ANDROID__)
-               n = getrlimit(RLIMIT_NOFILE, &rt);
-               if (n == -1) {
-                       lwsl_err("Get RLIMIT_NOFILE failed!\n");
+       n = getrlimit(RLIMIT_NOFILE, &rt);
+       if (n == -1) {
+               lwsl_cx_err(context, "Get RLIMIT_NOFILE failed!");
 
-                       return NULL;
-               }
-               context->max_fds = rt.rlim_cur;
+               goto free_context_fail2;
+       }
+       context->max_fds = (unsigned int)rt.rlim_cur;
 #else
-#if defined(WIN32) || defined(_WIN32) || defined(LWS_AMAZON_RTOS)
-               context->max_fds = getdtablesize();
+#if defined(WIN32) || defined(_WIN32) || defined(LWS_AMAZON_RTOS) || defined(LWS_ESP_PLATFORM)
+       context->max_fds = getdtablesize();
 #else
-               context->max_fds = sysconf(_SC_OPEN_MAX);
-#endif
-#endif
-
-               if (context->max_fds < 0) {
-                       lwsl_err("%s: problem getting process max files\n",
-                                __func__);
+       {
+               long l = sysconf(_SC_OPEN_MAX);
 
-                       return NULL;
-               }
+               context->max_fds = 2560;
 
-       if (info->count_threads)
-               context->count_threads = info->count_threads;
-       else
-               context->count_threads = 1;
+               if (l > 10000000)
+                       lwsl_cx_warn(context, "unreasonable ulimit -n workaround");
+               else
+                       if (l != -1l)
+                               context->max_fds = (unsigned int)l;
+       }
+#endif
+       if ((int)context->max_fds < 0 ||
+            lws_fi(&context->fic, "ctx_createfail_maxfds")) {
+               lwsl_cx_err(context, "problem getting process max files");
 
-       if (context->count_threads > LWS_MAX_SMP)
-               context->count_threads = LWS_MAX_SMP;
+               goto free_context_fail2;
+       }
+#endif
 
        /*
         * deal with any max_fds override, if it's reducing (setting it to
@@ -240,7 +981,7 @@ lwsl_info("context created\n");
         * figure out what if this is something it can deal with.
         */
        if (info->fd_limit_per_thread) {
-               int mf = info->fd_limit_per_thread * context->count_threads;
+               unsigned int mf = lpf * context->count_threads;
 
                if (mf < context->max_fds) {
                        context->max_fds_unrelated_to_ulimit = 1;
@@ -248,46 +989,10 @@ lwsl_info("context created\n");
                }
        }
 
-       context->token_limits = info->token_limits;
-
 #if defined(LWS_WITH_NETWORK)
-
-       /*
-        * set the context event loops ops struct
-        *
-        * after this, all event_loop actions use the generic ops
-        */
-
-#if defined(LWS_WITH_POLL)
-       context->event_loop_ops = &event_loop_ops_poll;
-#endif
-
-       if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
-#if defined(LWS_WITH_LIBUV)
-               context->event_loop_ops = &event_loop_ops_uv;
-#else
-               goto fail_event_libs;
-#endif
-
-       if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV))
-#if defined(LWS_WITH_LIBEV)
-               context->event_loop_ops = &event_loop_ops_ev;
-#else
-               goto fail_event_libs;
-#endif
-
-       if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT))
-#if defined(LWS_WITH_LIBEVENT)
-               context->event_loop_ops = &event_loop_ops_event;
-#else
-               goto fail_event_libs;
+       context->token_limits = info->token_limits;
 #endif
 
-       if (!context->event_loop_ops)
-               goto fail_event_libs;
-
-       lwsl_info("Using event loop: %s\n", context->event_loop_ops->name);
-#endif
 
 #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
        time(&context->tls.last_cert_check_s);
@@ -300,10 +1005,10 @@ lwsl_info("context created\n");
                        if (ar->alpn) {
                                if (!first)
                                        *p++ = ',';
-                               p += lws_snprintf(p,
-                                       context->tls.alpn_discovered +
+                               p += lws_snprintf(p, (unsigned int)(
+                                       (context->tls.alpn_discovered +
                                        sizeof(context->tls.alpn_discovered) -
-                                       2 - p, "%s", ar->alpn);
+                                       2) - p), "%s", ar->alpn);
                                first = 0;
                        }
                } LWS_FOR_EVERY_AVAILABLE_ROLE_END;
@@ -311,24 +1016,21 @@ lwsl_info("context created\n");
                context->tls.alpn_default = context->tls.alpn_discovered;
        }
 
-       lwsl_info("Default ALPN advertisment: %s\n", context->tls.alpn_default);
 #endif
-
+#if defined(LWS_WITH_NETWORK)
        if (info->timeout_secs)
                context->timeout_secs = info->timeout_secs;
        else
-               context->timeout_secs = AWAITING_TIMEOUT;
-
-       context->ws_ping_pong_interval = info->ws_ping_pong_interval;
-
-       lwsl_info(" default timeout (secs): %u\n", context->timeout_secs);
+#endif
+               context->timeout_secs = 15;
 
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
        if (info->max_http_header_data)
                context->max_http_header_data = info->max_http_header_data;
        else
                if (info->max_http_header_data2)
                        context->max_http_header_data =
-                                       info->max_http_header_data2;
+                                       (unsigned short)info->max_http_header_data2;
                else
                        context->max_http_header_data = LWS_DEF_HEADER_LEN;
 
@@ -337,35 +1039,71 @@ lwsl_info("context created\n");
        else
                if (info->max_http_header_pool2)
                        context->max_http_header_pool =
-                                       info->max_http_header_pool2;
+                                       (unsigned short)info->max_http_header_pool2;
                else
                        context->max_http_header_pool = context->max_fds;
-
+#endif
 
        if (info->fd_limit_per_thread)
-               context->fd_limit_per_thread = info->fd_limit_per_thread;
+               context->fd_limit_per_thread = lpf;
        else
                if (context->count_threads)
                        context->fd_limit_per_thread = context->max_fds /
                                                        context->count_threads;
 
+#if defined(LWS_WITH_SYS_SMD)
+       lws_mutex_init(context->smd.lock_messages);
+       lws_mutex_init(context->smd.lock_peers);
+
+       /* lws_system smd participant */
+
+       if (!lws_smd_register(context, context, 0, LWSSMDCL_NETWORK,
+                             lws_system_smd_cb)) {
+               lwsl_cx_err(context, "early smd register failed");
+       }
+
+       /* user smd participant */
+
+       if (info->early_smd_cb &&
+           !lws_smd_register(context, info->early_smd_opaque, 0,
+                             info->early_smd_class_filter,
+                             info->early_smd_cb)) {
+               lwsl_cx_err(context, "early smd register failed");
+       }
+#endif
+
+       n = 0;
 #if defined(LWS_WITH_NETWORK)
+
+       context->default_retry.retry_ms_table = default_backoff_table;
+       context->default_retry.conceal_count =
+                       context->default_retry.retry_ms_table_count =
+                                       LWS_ARRAY_SIZE(default_backoff_table);
+       context->default_retry.jitter_percent = 20;
+       context->default_retry.secs_since_valid_ping = 300;
+       context->default_retry.secs_since_valid_hangup = 310;
+
+       if (info->retry_and_idle_policy &&
+           info->retry_and_idle_policy->secs_since_valid_ping) {
+               context->default_retry.secs_since_valid_ping =
+                               info->retry_and_idle_policy->secs_since_valid_ping;
+               context->default_retry.secs_since_valid_hangup =
+                               info->retry_and_idle_policy->secs_since_valid_hangup;
+       }
+
        /*
         * Allocate the per-thread storage for scratchpad buffers,
         * and header data pool
         */
+       u = (uint8_t *)&context[1];
        for (n = 0; n < context->count_threads; n++) {
-               context->pt[n].serv_buf = lws_malloc(
-                               context->pt_serv_buf_size + sizeof(struct lws),
-                                                    "pt_serv_buf");
-               if (!context->pt[n].serv_buf) {
-                       lwsl_err("OOM\n");
-                       return NULL;
-               }
+               context->pt[n].serv_buf = u;
+               u += context->pt_serv_buf_size;
 
                context->pt[n].context = context;
-               context->pt[n].tid = n;
+               context->pt[n].tid = (uint8_t)n;
 
+#if !defined(LWS_PLAT_FREERTOS)
                /*
                 * We overallocated for a fakewsi (can't compose it in the
                 * pt because size isn't known at that time).  point to it
@@ -373,10 +1111,14 @@ lwsl_info("context created\n");
                 * when the source of the callback is not actually from a wsi
                 * context.
                 */
-               context->pt[n].fake_wsi = (struct lws *)(context->pt[n].serv_buf +
-                                               context->pt_serv_buf_size);
+               context->pt[n].fake_wsi = (struct lws *)u;
+               u += sizeof(struct lws);
 
                memset(context->pt[n].fake_wsi, 0, sizeof(struct lws));
+#endif
+
+               context->pt[n].evlib_pt = u;
+               u += plev->ops->evlib_size_pt;
 
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
                context->pt[n].http.ah_list = NULL;
@@ -386,14 +1128,18 @@ lwsl_info("context created\n");
 #if defined(LWS_WITH_SEQUENCER)
                lws_seq_pt_init(&context->pt[n]);
 #endif
-       }
 
-       lwsl_info(" Threads: %d each %d fds\n", context->count_threads,
-                   context->fd_limit_per_thread);
+#if defined(LWS_WITH_CGI)
+               if (lws_rops_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy))
+                       (lws_rops_func_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy)).
+                               pt_init_destroy(context, info,
+                                               &context->pt[n], 0);
+#endif
+       }
 
        if (!info->ka_interval && info->ka_time > 0) {
-               lwsl_err("info->ka_interval can't be 0 if ka_time used\n");
-               return NULL;
+               lwsl_cx_err(context, "info->ka_interval can't be 0 if ka_time used");
+               goto free_context_fail;
        }
 
 #if defined(LWS_WITH_PEER_LIMITS)
@@ -409,39 +1155,49 @@ lwsl_info("context created\n");
 
        context->ip_limit_ah = info->ip_limit_ah;
        context->ip_limit_wsi = info->ip_limit_wsi;
+       context->pl_notify_cb = info->pl_notify_cb;
+#endif
+
+       /*
+        * fds table contains pollfd structs for as many pollfds as we can
+        * handle... spread across as many service threads as we have going
+        */
+       n = (int)(sizeof(struct lws_pollfd) * context->count_threads *
+           context->fd_limit_per_thread);
+       context->pt[0].fds = lws_zalloc((unsigned int)n, "fds table");
+       if (context->pt[0].fds == NULL ||
+           lws_fi(&context->fic, "ctx_createfail_oom_fds")) {
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+               lws_free(context->pt[0].fds);
+#endif
+               lwsl_cx_err(context, "OOM allocating %d fds\n", context->max_fds);
+               goto free_context_fail;
+       }
 #endif
 
-       lwsl_info(" mem: context:         %5lu B (%ld ctx + (%ld thr x %d))\n",
+       lwsl_cx_info(context, "ctx: %5luB (%ld ctx + pt(%ld thr x %d)), "
+                 "pt-fds: %d, fdmap: %d",
                  (long)sizeof(struct lws_context) +
                  (context->count_threads * context->pt_serv_buf_size),
                  (long)sizeof(struct lws_context),
                  (long)context->count_threads,
-                 context->pt_serv_buf_size);
+                 context->pt_serv_buf_size,
+                 context->fd_limit_per_thread, n);
+
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       lwsl_info(" mem: http hdr size:   (%u + %lu), max count %u\n",
+       lwsl_cx_info(context, " http: ah_data: %u, ah: %lu, max count %u",
                    context->max_http_header_data,
                    (long)sizeof(struct allocated_headers),
                    context->max_http_header_pool);
 #endif
 
-       /*
-        * fds table contains pollfd structs for as many pollfds as we can
-        * handle... spread across as many service threads as we have going
-        */
-       n = sizeof(struct lws_pollfd) * context->count_threads *
-           context->fd_limit_per_thread;
-       context->pt[0].fds = lws_zalloc(n, "fds table");
-       if (context->pt[0].fds == NULL) {
-               lwsl_err("OOM allocating %d fds\n", context->max_fds);
-               goto bail;
-       }
-       lwsl_info(" mem: pollfd map:      %5u B\n", n);
-#endif
+#if defined(LWS_WITH_SERVER)
        if (info->server_string) {
                context->server_string = info->server_string;
                context->server_string_len = (short)
                                strlen(context->server_string);
        }
+#endif
 
 #if LWS_MAX_SMP > 1
        /* each thread serves his own chunk of fds */
@@ -450,14 +1206,27 @@ lwsl_info("context created\n");
                                     context->fd_limit_per_thread;
 #endif
 
-       if (lws_plat_init(context, info))
-               goto bail;
+
+       /*
+        * Past here, we may have added handles to the event lib
+        * loop and if libuv,  have to take care about how to unpick them...
+        */
+
+       if (lws_plat_init(context, info) ||
+           lws_fi(&context->fic, "ctx_createfail_plat_init"))
+               goto bail_libuv_aware;
 
 #if defined(LWS_WITH_NETWORK)
+
+       if (lws_fi(&context->fic, "ctx_createfail_evlib_init"))
+               goto bail_libuv_aware;
+
        if (context->event_loop_ops->init_context)
                if (context->event_loop_ops->init_context(context, info))
-                       goto bail;
+                       goto bail_libuv_aware;
 
+       if (lws_fi(&context->fic, "ctx_createfail_evlib_pt"))
+               goto bail_libuv_aware;
 
        if (context->event_loop_ops->init_pt)
                for (n = 0; n < context->count_threads; n++) {
@@ -467,59 +1236,229 @@ lwsl_info("context created\n");
                                lp = info->foreign_loops[n];
 
                        if (context->event_loop_ops->init_pt(context, lp, n))
-                               goto bail;
+                               goto bail_libuv_aware;
                }
 
-#if !defined(LWS_AMAZON_RTOS)
-       if (lws_create_event_pipes(context))
-               goto bail;
-#endif
+       lws_context_lock(context, __func__);
+       n = __lws_create_event_pipes(context);
+       lws_context_unlock(context);
+       if (n)
+               goto bail_libuv_aware;
+
+       for (n = 0; n < context->count_threads; n++) {
+               LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
+                       if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy))
+                               (lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)).
+                                       pt_init_destroy(context, info,
+                                                       &context->pt[n], 0);
+               } LWS_FOR_EVERY_AVAILABLE_ROLE_END;
+       }
 #endif
 
-       lws_context_init_ssl_library(info);
+       lws_context_init_ssl_library(context, info);
 
        context->user_space = info->user;
+
+#if defined(LWS_WITH_SERVER)
+       strcpy(context->canonical_hostname, "unknown");
+#if defined(LWS_WITH_NETWORK)
+       lws_server_get_canonical_hostname(context, info);
+#endif
+#endif
+
+#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
+       memcpy(context->caps, info->caps, sizeof(context->caps));
+       context->count_caps = info->count_caps;
+#endif
+
+
 #if defined(LWS_WITH_NETWORK)
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS) || defined(LWS_WITH_SYS_NTPCLIENT) || \
+       defined(LWS_WITH_SYS_DHCP_CLIENT)
+       {
+               /*
+                * system vhost
+                */
+
+               struct lws_context_creation_info ii;
+               const struct lws_protocols *pp[4];
+               struct lws_vhost *vh;
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+               extern const struct lws_protocols lws_async_dns_protocol;
+#endif
+#if defined(LWS_WITH_SYS_NTPCLIENT)
+               extern const struct lws_protocols lws_system_protocol_ntpc;
+#endif
+#if defined(LWS_WITH_SYS_DHCP_CLIENT)
+               extern const struct lws_protocols lws_system_protocol_dhcpc4;
+#endif
+
+               n = 0;
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+               pp[n++] = &lws_async_dns_protocol;
+#endif
+#if defined(LWS_WITH_SYS_NTPCLIENT)
+               pp[n++] = &lws_system_protocol_ntpc;
+#endif
+#if defined(LWS_WITH_SYS_DHCP_CLIENT)
+               pp[n++] = &lws_system_protocol_dhcpc4;
+#endif
+               pp[n] = NULL;
+
+               memset(&ii, 0, sizeof(ii));
+               ii.vhost_name = "system";
+               ii.pprotocols = pp;
+               ii.port = CONTEXT_PORT_NO_LISTEN;
+
+               if (lws_fi(&context->fic, "ctx_createfail_sys_vh"))
+                       vh = NULL;
+               else
+                       vh = lws_create_vhost(context, &ii);
+               if (!vh) {
+                       lwsl_cx_err(context, "failed to create system vhost");
+                       goto bail_libuv_aware;
+               }
+
+               context->vhost_system = vh;
+
+               if (lws_protocol_init_vhost(vh, NULL) ||
+                   lws_fi(&context->fic, "ctx_createfail_sys_vh_init")) {
+                       lwsl_cx_err(context, "failed to init system vhost");
+                       goto bail_libuv_aware;
+               }
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+               lws_async_dns_init(context);
+                       //goto bail_libuv_aware;
+#endif
+       }
+
+#endif
+
+#if defined(LWS_WITH_SYS_STATE)
+       /*
+        * init the lws_state mgr for the system state
+        */
+
+       context->mgr_system.state_names         = system_state_names;
+       context->mgr_system.name                = "system";
+       context->mgr_system.state               = LWS_SYSTATE_CONTEXT_CREATED;
+       context->mgr_system.parent              = context;
+       context->mgr_system.context             = context;
+#if defined(LWS_WITH_SYS_SMD)
+       context->mgr_system.smd_class           = LWSSMDCL_SYSTEM_STATE;
+#endif
+
+       context->protocols_notify.name          = "prot_init";
+       context->protocols_notify.notify_cb     = lws_state_notify_protocol_init;
+
+       lws_state_reg_notifier(&context->mgr_system, &context->protocols_notify);
+
+       /*
+        * insert user notifiers here so they can participate with vetoing us
+        * trying to jump straight to operational, or at least observe us
+        * reaching 'operational', before we returned from context creation.
+        */
+
+       lws_state_reg_notifier_list(&context->mgr_system,
+                                   info->register_notifier_list);
+#endif
+
        /*
         * if he's not saying he'll make his own vhosts later then act
         * compatibly and make a default vhost using the data in the info
         */
-       if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
-               if (!lws_create_vhost(context, info)) {
-                       lwsl_err("Failed to create default vhost\n");
-                       for (n = 0; n < context->count_threads; n++)
-                               lws_free_set_NULL(context->pt[n].serv_buf);
+       if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
+               if (!lws_create_vhost(context, info) ||
+                   lws_fi(&context->fic, "ctx_createfail_def_vh")) {
+                       lwsl_cx_err(context, "Failed to create default vhost");
+
 #if defined(LWS_WITH_PEER_LIMITS)
                        lws_free_set_NULL(context->pl_hash_table);
 #endif
-                       goto fail_clean_pipes;
+                       goto bail;
                }
+       }
 
-       lws_context_init_extensions(info, context);
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
+       if (info->http_nsc_filepath) {
+               memset(&ci, 0, sizeof(ci));
 
-       lwsl_info(" mem: per-conn:        %5lu bytes + protocol rx buf\n",
-                   (unsigned long)sizeof(struct lws));
+               ci.cx                      = context;
+               ci.ops                     = &lws_cache_ops_nscookiejar;
+               ci.name                    = "NSC";
+               ci.u.nscookiejar.filepath  = info->http_nsc_filepath;
+
+               context->nsc = lws_cache_create(&ci);
+               if (!context->nsc)
+                       goto bail;
+
+               ci.ops                    = &lws_cache_ops_heap;
+               ci.name                   = "L1";
+               ci.parent                 = context->nsc;
+               ci.max_footprint          = info->http_nsc_heap_max_footprint;
+               ci.max_items              = info->http_nsc_heap_max_items;
+               ci.max_payload            = info->http_nsc_heap_max_payload;
+
+               context->l1 = lws_cache_create(&ci);
+               if (!context->l1) {
+                       lwsl_cx_err(context, "Failed to init cookiejar");
+                       goto bail;
+               }
+       }
 #endif
-       strcpy(context->canonical_hostname, "unknown");
-#if defined(LWS_WITH_NETWORK)
-       lws_server_get_canonical_hostname(context, info);
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       if (context->pss_policies_json) {
+               /*
+                * You must create your context with the explicit vhosts flag
+                * in order to use secure streams
+                */
+               assert(lws_check_opt(info->options,
+                      LWS_SERVER_OPTION_EXPLICIT_VHOSTS));
+
+               if (lws_ss_policy_parse_begin(context, 0) ||
+                   lws_fi(&context->fic, "ctx_createfail_ss_pol1")) {
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+                       lws_ss_policy_parse_abandon(context);
 #endif
+                       goto bail_libuv_aware;
+               }
+
+               n = lws_ss_policy_parse(context,
+                                       (uint8_t *)context->pss_policies_json,
+                                       strlen(context->pss_policies_json));
+               if ((n != LEJP_CONTINUE && n < 0) ||
+                   lws_fi(&context->fic, "ctx_createfail_ss_pol2")) {
+                       lws_ss_policy_parse_abandon(context);
+                       goto bail_libuv_aware;
+               }
+
+               if (lws_ss_policy_set(context, "hardcoded") ||
+                   lws_fi(&context->fic, "ctx_createfail_ss_pol3")) {
+                       lwsl_cx_err(context, "policy set failed");
+                       goto bail_libuv_aware;
+               }
+       }
+#else
+       if (context->pss_policies) {
+               /* user code set the policy objects directly, no parsing step */
 
-#if defined(LWS_WITH_STATS)
-       context->pt[0].sul_stats.cb = lws_sul_stats_cb;
-       __lws_sul_insert(&context->pt[0].pt_sul_owner, &context->pt[0].sul_stats,
-                        10 * LWS_US_PER_SEC);
+               if (lws_ss_policy_set(context, "hardcoded") ||
+                   lws_fi(&context->fic, "ctx_createfail_ss_pol3")) {
+                       lwsl_cx_err(context, "policy set failed");
+                       goto bail_libuv_aware;
+               }
+       }
 #endif
-#if defined(LWS_WITH_PEER_LIMITS)
-       context->pt[0].sul_peer_limits.cb = lws_sul_peer_limits_cb;
-       __lws_sul_insert(&context->pt[0].pt_sul_owner,
-                        &context->pt[0].sul_peer_limits, 10 * LWS_US_PER_SEC);
 #endif
 
-#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
-       memcpy(context->caps, info->caps, sizeof(context->caps));
-       context->count_caps = info->count_caps;
-#endif
+       lws_context_init_extensions(info, context);
+
+       lwsl_cx_info(context, " mem: per-conn:        %5lu bytes + protocol rx buf",
+                   (unsigned long)sizeof(struct lws));
 
        /*
         * drop any root privs for this process
@@ -527,55 +1466,161 @@ lwsl_info("context created\n");
         * listening, we don't want the power for anything else
         */
        if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
-               if (lws_plat_drop_app_privileges(context, 1))
-                       goto bail;
+               if (lws_plat_drop_app_privileges(context, 1) ||
+                   lws_fi(&context->fic, "ctx_createfail_privdrop"))
+                       goto bail_libuv_aware;
+
+#if defined(LWS_WITH_SYS_STATE)
+       /*
+        * We want to move on the syste, state as far as it can go towards
+        * OPERATIONAL now.  But we have to return from here first so the user
+        * code that called us can set its copy of context, which it may be
+        * relying on to perform operations triggered by the state change.
+        *
+        * We set up a sul to come back immediately and do the state change.
+        */
+
+       lws_sul_schedule(context, 0, &context->sul_system_state,
+                        lws_context_creation_completion_cb, 1);
+#endif
 
-#if defined(LWS_WITH_NETWORK)
        /* expedite post-context init (eg, protocols) */
        lws_cancel_service(context);
 #endif
 
-       return context;
+       return context;
+
+early_bail:
+       lws_fi_destroy(&info->fic);
+
+       return NULL;
+
+#if defined(LWS_WITH_NETWORK)
+bail:
+       lws_fi_destroy(&info->fic);
+       lws_context_destroy(context);
+
+       return NULL;
+#endif
+
+bail_libuv_aware:
+       lws_context_destroy(context);
+#if defined(LWS_WITH_LIBUV)
+       return fatal_exit_defer ? context : NULL;
+#else
+       return NULL;
+#endif
+
+#if defined(LWS_WITH_NETWORK)
+fail_event_libs:
+       if (context)
+       lwsl_cx_err(context, "Requested event library support not configured");
+#endif
+
+#if defined(LWS_WITH_NETWORK)
+free_context_fail:
+       if (context) {
+#if defined(LWS_WITH_SYS_SMD)
+               _lws_smd_destroy(context);
+#endif
+       }
+#endif
+free_context_fail2:
+       if (context) {
+#if defined(LWS_WITH_SYS_METRICS)
+               lws_metrics_destroy(context);
+#endif
+               lws_fi_destroy(&context->fic);
+       }
+       lws_fi_destroy(&info->fic);
+       if (context) {
+               lwsl_refcount_cx(context->log_cx, -1);
+               lws_free(context);
+       }
+
+       return NULL;
+}
+
+#if defined(LWS_WITH_NETWORK)
+int
+lws_system_cpd_start(struct lws_context *cx)
+{
+       cx->captive_portal_detect = LWS_CPD_UNKNOWN;
+
+       /* if there's a platform implementation, use it */
+
+       if (lws_system_get_ops(cx) &&
+           lws_system_get_ops(cx)->captive_portal_detect_request)
+               return lws_system_get_ops(cx)->captive_portal_detect_request(cx);
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       /*
+        * Otherwise try to use SS "captive_portal_detect" if that's enabled
+        */
+       return lws_ss_sys_cpd(cx);
+#else
+       return 0;
+#endif
+}
+
+static void
+lws_system_deferred_cb(lws_sorted_usec_list_t *sul)
+{
+       struct lws_context *cx =
+                    lws_container_of(sul, struct lws_context, sul_cpd_defer);
 
-#if defined(LWS_WITH_NETWORK)
-fail_clean_pipes:
-       for (n = 0; n < context->count_threads; n++)
-               lws_destroy_event_pipe(context->pt[n].pipe_wsi);
+       lws_system_cpd_start(cx);
+}
 
-       lws_free_set_NULL(context->pt[0].fds);
-       lws_plat_context_late_destroy(context);
-       lws_free_set_NULL(context);
+void
+lws_system_cpd_start_defer(struct lws_context *cx, lws_usec_t defer_us)
+{
+       lws_sul_schedule(cx, 0, &cx->sul_cpd_defer,
+                        lws_system_deferred_cb, defer_us);
+}
 
-       return NULL;
+#if (defined(LWS_WITH_SYS_STATE) && defined(LWS_WITH_SYS_SMD)) || !defined(LWS_WITH_NO_LOGS)
+static const char *cname[] = { "Unknown", "OK", "Captive", "No internet" };
 #endif
 
-bail:
-       lws_context_destroy(context);
+void
+lws_system_cpd_set(struct lws_context *cx, lws_cpd_result_t result)
+{
+       if (cx->captive_portal_detect != LWS_CPD_UNKNOWN)
+               return;
 
-       return NULL;
+#if !defined(LWS_WITH_NO_LOGS)
+       lwsl_cx_notice(cx, "setting CPD result %s", cname[result]);
+#endif
 
-#if defined(LWS_WITH_NETWORK)
-fail_event_libs:
-       lwsl_err("Requested event library support not configured, available:\n");
-       {
-               extern const struct lws_event_loop_ops *available_event_libs[];
-               const struct lws_event_loop_ops **elops = available_event_libs;
+       cx->captive_portal_detect = (uint8_t)result;
 
-               while (*elops) {
-                       lwsl_err("  - %s\n", (*elops)->name);
-                       elops++;
-               }
-       }
+#if defined(LWS_WITH_SYS_STATE)
+#if defined(LWS_WITH_SYS_SMD)
+       lws_smd_msg_printf(cx, LWSSMDCL_NETWORK,
+                          "{\"type\":\"cpd\",\"result\":\"%s\"}",
+                          cname[cx->captive_portal_detect]);
 #endif
-       lws_free(context);
 
-       return NULL;
+       /* if nothing is there to intercept anything, go all the way */
+       if (cx->mgr_system.state != LWS_SYSTATE_POLICY_INVALID)
+               lws_state_transition_steps(&cx->mgr_system,
+                                          LWS_SYSTATE_OPERATIONAL);
+#endif
+}
+
+lws_cpd_result_t
+lws_system_cpd_state_get(struct lws_context *cx)
+{
+       return (lws_cpd_result_t)cx->captive_portal_detect;
 }
 
-LWS_VISIBLE LWS_EXTERN int
-lws_context_is_deprecated(struct lws_context *context)
+#endif
+
+int
+lws_context_is_deprecated(struct lws_context *cx)
 {
-       return context->deprecated;
+       return cx->deprecated;
 }
 
 /*
@@ -601,282 +1646,621 @@ lws_context_is_deprecated(struct lws_context *context)
  *     destroys the context itself, setting what was info.pcontext to NULL.
  */
 
-/*
- * destroy the actual context itself
- */
 
+#if defined(LWS_WITH_NETWORK)
 static void
-lws_context_destroy3(struct lws_context *context)
+lws_pt_destroy(struct lws_context_per_thread *pt)
 {
-       struct lws_context **pcontext_finalize = context->pcontext_finalize;
-#if defined(LWS_WITH_NETWORK)
-       int n;
+       volatile struct lws_foreign_thread_pollfd *ftp, *next;
+       volatile struct lws_context_per_thread *vpt;
+#if defined(LWS_WITH_CGI)
+       lws_ctx_t ctx = pt->context;
 
-       lwsl_debug("%s\n", __func__);
+               if (lws_rops_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy))
+                       (lws_rops_func_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy)).
+                               pt_init_destroy(ctx, NULL, pt, 1);
+#endif
+       vpt = (volatile struct lws_context_per_thread *)pt;
+       ftp = vpt->foreign_pfd_list;
+       while (ftp) {
+               next = ftp->next;
+               lws_free((void *)ftp);
+               ftp = next;
+       }
+       vpt->foreign_pfd_list = NULL;
 
-       for (n = 0; n < context->count_threads; n++) {
-               struct lws_context_per_thread *pt = &context->pt[n];
-               (void)pt;
-#if defined(LWS_WITH_SEQUENCER)
-               lws_seq_destroy_all_on_pt(pt);
+       lws_pt_lock(pt, __func__);
+
+       if (pt->pipe_wsi) {
+               lws_destroy_event_pipe(pt->pipe_wsi);
+               pt->pipe_wsi = NULL;
+       }
+
+       if (pt->dummy_pipe_fds[0]
+#if !defined(WIN32)
+           && (int)pt->dummy_pipe_fds[0] != -1
+#endif
+       ) {
+               struct lws wsi;
+
+               memset(&wsi, 0, sizeof(wsi));
+               wsi.a.context = pt->context;
+               wsi.tsi = (char)pt->tid;
+               lws_plat_pipe_close(&wsi);
+       }
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       lws_dll2_foreach_safe(&pt->ss_owner, NULL, lws_ss_destroy_dll);
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) && defined(LWS_WITH_CLIENT)
+       lws_dll2_foreach_safe(&pt->ss_client_owner, NULL, lws_sspc_destroy_dll);
 #endif
 
-               if (context->event_loop_ops->destroy_pt)
-                       context->event_loop_ops->destroy_pt(context, n);
+#if defined(LWS_WITH_SEQUENCER)
+       lws_seq_destroy_all_on_pt(pt);
+#endif
 
-               lws_free_set_NULL(context->pt[n].serv_buf);
 
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
                while (pt->http.ah_list)
                        _lws_destroy_ah(pt, pt->http.ah_list);
 #endif
-       }
 
-       if (context->pt[0].fds)
-               lws_free_set_NULL(context->pt[0].fds);
 #endif
-       lws_context_deinit_ssl_library(context);
 
-       lws_free(context);
-       lwsl_info("%s: ctx %p freed\n", __func__, context);
+       lws_pt_unlock(pt);
+       pt->pipe_wsi = NULL;
 
-       if (pcontext_finalize)
-               *pcontext_finalize = NULL;
 }
+#endif
 
 /*
- * really start destroying things
+ * Context destruction is now a state machine that's aware of SMP pts and
+ * various event lib approaches.
+ *
+ * lws_context_destroy() expects to be called at the end of the user code's
+ * usage of it.  But it can also be called non-finally, as a way to stop
+ * service and exit the outer user service loop, and then complete in the
+ * final call.
+ *
+ * For libuv, with async close, it must decide by refcounting the hamdles on
+ * the loop if it has extricated itself from the loop and can be destroyed.
+ *
+ * The various entry states for the staged destroy
+ *
+ * LWSCD_NO_DESTROY: begin destroy process
+ *     - mark context as starting destroy process
+ *     - start vhost destroy
+ *     - stop any further user protocol service
+ *
+ * LWSCD_PT_WAS_DEFERRED: come back here if any pt inside service
+ *     - Check for pts that are inside service loop, mark deferral needed if so
+ *     - If not, close all wsi on the pt loop and start logical pt destroy
+ *     - If any deferred, set state to LWSCD_PT_WAS_DEFERRED and exit
+ *
+ * LWSCD_PT_WAIT_ALL_DESTROYED: come back here for async loop / pt closes
+ *     - exit if any pt not marked as unused, or destroyed
+ *     - if all pt down, call into evlib to advance context destroy
+ *     - finalize vhost destruction
+ *     - finalize pt destruction
+ *     - if foreign loops, set state to LWSCD_FINALIZATION and exit
+ *
+ * LWSCD_FINALIZATION: come back here at final lws_destroy_context() call
+ *     - destroy sundries
+ *     - destroy and free the actual context
  */
 
 void
-lws_context_destroy2(struct lws_context *context)
+lws_context_destroy(struct lws_context *context)
 {
+       struct lws_context **pcontext_finalize;
 #if defined(LWS_WITH_NETWORK)
+       struct lws_context_per_thread *pt;
        struct lws_vhost *vh = NULL, *vh1;
+       int alive = 0, deferred_pt = 0;
 #endif
 #if defined(LWS_WITH_PEER_LIMITS)
        uint32_t nu;
 #endif
+       int n;
 
-       lwsl_info("%s: ctx %p\n", __func__, context);
+       if (!context || context->inside_context_destroy)
+               return;
 
-       lws_context_lock(context, "context destroy 2"); /* ------ context { */
+       pcontext_finalize = context->pcontext_finalize;
 
-       context->being_destroyed2 = 1;
-#if defined(LWS_WITH_NETWORK)
-       /*
-        * free all the per-vhost allocations
-        */
+       lws_context_lock(context, __func__);
+       context->inside_context_destroy = 1;
 
-       vh = context->vhost_list;
-       while (vh) {
-               vh1 = vh->vhost_next;
-               __lws_vhost_destroy2(vh);
-               vh = vh1;
-       }
+       lwsl_cx_info(context, "destroy_state %d", context->destroy_state);
+
+       switch (context->destroy_state) {
+       case LWSCD_NO_DESTROY:
+               /*
+                * We're getting started
+                */
+
+               lwsl_cx_info(context, "starting context destroy flow");
+               context->being_destroyed = 1;
+
+#if defined(LWS_WITH_NETWORK)
 
-       lwsl_debug("%p: post vh listl\n", __func__);
+               /*
+                * Close any vhost listen wsi
+                *
+                * inform all the protocols that they are done and will have no
+                * more callbacks.
+                *
+                * We can't free things until after the event loop shuts down.
+                */
 
-       /* remove ourselves from the pending destruction list */
+               if (context->protocol_init_done)
+                       vh = context->vhost_list;
 
-       while (context->vhost_pending_destruction_list)
-               /* removes itself from list */
-               __lws_vhost_destroy2(context->vhost_pending_destruction_list);
+               while (vh) {
+                       lwsl_vhost_info(vh, "start close");
+                       vh1 = vh->vhost_next;
+                       lws_vhost_destroy1(vh);
+                       vh = vh1;
+               }
 #endif
 
-       lwsl_debug("%p: post pdl\n", __func__);
+               lws_plat_context_early_destroy(context);
+
+               context->service_no_longer_possible = 1;
+               context->requested_stop_internal_loops = 1;
+
+               /* fallthru */
+
+       case LWSCD_PT_WAS_DEFERRED:
 
-       lws_stats_log_dump(context);
 #if defined(LWS_WITH_NETWORK)
-       lws_ssl_context_destroy(context);
+
+               /*
+                * We want to mark the pts as their destruction having been
+                * initiated, so they will reject any new wsi, and iterate all
+                * existing pt wsi starting to close them.
+                *
+                * If the event loop has async close, we have to return after
+                * this and try again when all the loops stop after all the
+                * refcounted wsi are gone.
+                */
+
+               pt = context->pt;
+               for (n = 0; n < context->count_threads; n++) {
+                       lws_pt_lock(pt, __func__);
+
+                       /* evlib will realize it needs to destroy pt */
+                       pt->destroy_self = 1;
+
+                       if (pt->inside_lws_service) {
+                               pt->event_loop_pt_unused = 1;
+                               deferred_pt = 1;
+                               goto next;
+                       }
+
+                       /*
+                        * Close every handle in the fds
+                        */
+
+                       while (pt->fds_count) {
+                               struct lws *wsi = wsi_from_fd(context,
+                                                             pt->fds[0].fd);
+
+                               if (wsi) {
+
+                                       lwsl_cx_debug(context,
+                                               "pt %d: closing wsi %p: role %s",
+                                               n, wsi, wsi->role_ops->name);
+
+                                       lws_close_free_wsi(wsi,
+                                               LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
+                                               "ctx destroy"
+                                               /* no protocol close */);
+
+                                       if (pt->pipe_wsi == wsi)
+                                               pt->pipe_wsi = NULL;
+                               }
+                       }
+
+#if defined(LWS_WITH_CGI)
+                       (lws_rops_func_fidx(&role_ops_cgi,
+                                           LWS_ROPS_pt_init_destroy)).
+                                           pt_init_destroy(context, NULL,
+                                                           pt, 1);
 #endif
-       lws_plat_context_late_destroy(context);
 
-#if defined(LWS_WITH_PEER_LIMITS)
-       for (nu = 0; nu < context->pl_hash_elements; nu++)      {
-               lws_start_foreach_llp(struct lws_peer **, peer,
-                                     context->pl_hash_table[nu]) {
-                       struct lws_peer *df = *peer;
-                       *peer = df->next;
-                       lws_free(df);
-                       continue;
-               } lws_end_foreach_llp(peer, next);
-       }
-       lws_free(context->pl_hash_table);
+                       /*
+                        * This closes handles that belong to the evlib pt
+                        * footprint, eg, timers, idle
+                        */
+
+                       if (context->event_loop_ops->destroy_pt) {
+                               lwsl_cx_info(context,
+                                            "calling evlib destroy_pt %d\n", n);
+                               context->event_loop_ops->destroy_pt(context, n);
+                       }
+
+next:
+                       lws_pt_unlock(pt);
+
+                       pt++;
+               }
+
+               if (deferred_pt) {
+                       context->destroy_state = LWSCD_PT_WAS_DEFERRED;
+                       lwsl_cx_notice(context, "destroy from inside service");
+                       lws_cancel_service(context);
+                       goto bail;
+               }
 #endif
+               context->destroy_state = LWSCD_PT_WAIT_ALL_DESTROYED;
+
+               /*
+                * We have different needs depending if foreign loop or not.
+                *
+                * 1) If foreign loop, we really want to advance the
+                *    destroy_context() past here, and block only for libuv-
+                *    style async close completion.
+                *
+                * 2a) If poll, and we exited by ourselves and are calling a
+                *     final destroy_context() outside of any service already,
+                *     we want to advance all the way in one step.
+                *
+                * 2b) If poll, and we are reacting to a SIGINT, service
+                *     thread(s) may be in poll wait or servicing.  We can't
+                *     advance the destroy_context() to the point it's freeing
+                *     things; we have to leave that for the final
+                *     destroy_context() after the service thread(s) are
+                *     finished calling for service.
+                */
+
+#if defined(LWS_WITH_NETWORK)
+               if (context->event_loop_ops->destroy_context1) {
+                       lwsl_cx_info(context, "do evlib destroy_context1 and wait");
+                       context->event_loop_ops->destroy_context1(context);
+
+                       goto bail;
+               }
+
+               /*
+                * ...if the more typical sync close, we can clean up the pts
+                * now ourselves...
+                */
+
+               lwsl_cx_info(context, "manually destroying pts");
 
-       lwsl_debug("%p: baggage\n", __func__);
+               pt = context->pt;
+               for (n = 0; n < context->count_threads; n++, pt++) {
+                       pt->event_loop_pt_unused = 1;
+                       lws_pt_destroy(pt);
+               }
+#endif
+               /* fallthru */
 
-       if (context->external_baggage_free_on_destroy)
-               free(context->external_baggage_free_on_destroy);
+       case LWSCD_PT_WAIT_ALL_DESTROYED:
 
 #if defined(LWS_WITH_NETWORK)
-       lws_check_deferred_free(context, 0, 1);
+
+               for (n = 0; n < context->count_threads; n++)
+                       if (!context->pt[n].is_destroyed &&
+                           !context->pt[n].event_loop_pt_unused)
+                               alive++;
+
+               lwsl_cx_info(context, "PT_WAIT_ALL_DESTROYED: %d alive", alive);
+
+               if (alive)
+                       break;
+
+               /*
+                * With foreign loops, removing all our fds from the loop
+                * means there are no more ways for the foreign loop to give
+                * us any further CPU once we leave here... so we must make
+                * sure related service threads are exiting so we can pick up
+                * again at the original app thread and do the context
+                * destroy completion
+                */
+
+               /*
+                * evlib specific loop destroy?
+                */
+               if (context->event_loop_ops->destroy_context2)
+                       /*
+                        * He returns nonzero to indicate the evlib must
+                        * continue around the loop before destroy of it is
+                        * completed so it can be freed
+                        */
+                       context->event_loop_ops->destroy_context2(context);
+               context->requested_stop_internal_loops = 1;
 #endif
 
-#if LWS_MAX_SMP > 1
-       lws_mutex_refcount_destroy(&context->mr);
+               /*
+                * Every pt and wsi that may depend on the logical vhosts
+                * is destroyed.  We can remove the logical vhosts.
+                */
+
+#if defined(LWS_WITH_SYS_STATE) && defined(LWS_WITH_NETWORK)
+       lws_state_transition(&context->mgr_system, LWS_SYSTATE_POLICY_INVALID);
 #endif
+
 #if defined(LWS_WITH_NETWORK)
-       if (context->event_loop_ops->destroy_context2)
-               if (context->event_loop_ops->destroy_context2(context)) {
-                       lws_context_unlock(context); /* } context ----------- */
-                       context->finalize_destroy_after_internal_loops_stopped = 1;
-                       return;
+               /*
+                * free all the per-vhost allocations
+                */
+
+               vh = context->vhost_list;
+               while (vh) {
+                       vh1 = vh->vhost_next;
+               //      lwsl_vhost_debug(vh, "vh %s destroy2", vh->name);
+                       __lws_vhost_destroy2(vh);
+                       vh = vh1;
                }
 
-       lwsl_debug("%p: post dc2\n", __func__);
+               /* remove ourselves from the pending destruction list */
 
-       if (!context->pt[0].event_loop_foreign) {
-               int n;
-               for (n = 0; n < context->count_threads; n++)
-                       if (context->pt[n].inside_service) {
-                               lwsl_debug("%p: bailing as inside service\n", __func__);
-                               lws_context_unlock(context); /* } context --- */
-                               return;
-                       }
-       }
+               while (context->vhost_pending_destruction_list)
+                       /* removes itself from list */
+                       __lws_vhost_destroy2(context->vhost_pending_destruction_list);
 #endif
-       lws_context_unlock(context); /* } context ------------------- */
 
-       lws_context_destroy3(context);
-}
+#if defined(LWS_WITH_NETWORK)
+               lws_ssl_context_destroy(context);
+#endif
+               lws_plat_context_late_destroy(context);
 
-/*
- * Begin the context takedown
- */
+#if defined(LWS_WITH_PEER_LIMITS)
+               for (nu = 0; nu < context->pl_hash_elements; nu++)      {
+                       lws_start_foreach_llp(struct lws_peer **, peer,
+                                             context->pl_hash_table[nu]) {
+                               struct lws_peer *df = *peer;
+                               *peer = df->next;
+                               lws_free(df);
+                               continue;
+                       } lws_end_foreach_llp(peer, next);
+               }
+               lws_free(context->pl_hash_table);
+#endif
 
-LWS_VISIBLE void
-lws_context_destroy(struct lws_context *context)
-{
 #if defined(LWS_WITH_NETWORK)
-       volatile struct lws_foreign_thread_pollfd *ftp, *next;
-       volatile struct lws_context_per_thread *vpt;
-       struct lws_vhost *vh = NULL;
-       struct lws wsi;
-       int n, m;
+
+               for (n = 0; n < context->count_threads; n++) {
+                       struct lws_context_per_thread *pt = &context->pt[n];
+
+                       (void)pt;
+#if defined(LWS_WITH_SEQUENCER)
+                       lws_seq_destroy_all_on_pt(pt);
+#endif
+                       LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
+                               if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy))
+                                       (lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)).
+                                               pt_init_destroy(context, NULL, pt, 1);
+                       } LWS_FOR_EVERY_AVAILABLE_ROLE_END;
+
+#if defined(LWS_WITH_CGI)
+                       lws_rops_func_fidx(&role_ops_cgi,
+                                          LWS_ROPS_pt_init_destroy).
+                                               pt_init_destroy(context, NULL,
+                                                               pt, 1);
 #endif
 
-       if (!context)
-               return;
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+                       while (pt->http.ah_list)
+                               _lws_destroy_ah(pt, pt->http.ah_list);
+#endif
+                       lwsl_cx_info(context, "pt destroy %d", n);
+                       lws_pt_destroy(pt);
+               }
+#endif /* NETWORK */
+
+               context->destroy_state = LWSCD_FINALIZATION;
+
+#if defined(LWS_WITH_NETWORK)
+
+               if (context->pt[0].event_loop_foreign &&
+                   context->event_loop_ops->destroy_context1) {
+
+                       lwsl_cx_info(context,
+                                   "leaving final context destruction"
+                                       " for final call");
+                       goto bail;
+               }
+
+               if (context->event_loop_ops->destroy_context1 &&
+                   !context->pt[0].event_loop_foreign) {
+                       lwsl_cx_notice(context, "waiting for internal loop exit");
+
+                       goto bail;
+               }
+#endif
+               /* fallthru */
+
+       case LWSCD_FINALIZATION:
+
+#if defined(LWS_WITH_SYS_METRICS)
+               lws_metrics_dump(context);
+#endif
+
+               context->evlib_finalize_destroy_after_int_loops_stop = 1;
+
 #if defined(LWS_WITH_NETWORK)
-       if (context->finalize_destroy_after_internal_loops_stopped) {
                if (context->event_loop_ops->destroy_context2)
                        context->event_loop_ops->destroy_context2(context);
-               lws_context_destroy3(context);
-
-               return;
-       }
+#if defined(LWS_WITH_SYS_STATE)
+               lws_state_transition_steps(&context->mgr_system,
+                                          LWS_SYSTATE_CONTEXT_DESTROYING);
 #endif
-       if (context->being_destroyed1) {
-               if (!context->being_destroyed2) {
-                       lws_context_destroy2(context);
+               /*
+                * finalize destroy of pt and things hanging off it
+                */
 
-                       return;
+               for (n = 0; n < context->count_threads; n++) {
+                       struct lws_context_per_thread *pt = &context->pt[n];
+
+                       /*
+                        * Destroy the pt-roles
+                        */
+
+                       LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
+                               if (lws_rops_fidx(ar, LWS_ROPS_pt_init_destroy))
+                                       (lws_rops_func_fidx(ar, LWS_ROPS_pt_init_destroy)).
+                                                       pt_init_destroy(context, NULL, pt, 1);
+                       } LWS_FOR_EVERY_AVAILABLE_ROLE_END;
+
+               #if defined(LWS_WITH_CGI)
+                       lws_rops_func_fidx(&role_ops_cgi, LWS_ROPS_pt_init_destroy).
+                                               pt_init_destroy(context, NULL, pt, 1);
+               #endif
+
+                       lws_pt_mutex_destroy(pt);
+                       assert(!pt->is_destroyed);
+                       pt->destroy_self = 0;
+                       pt->is_destroyed = 1;
+
+                       lwsl_cx_info(context, "pt %d fully destroyed",
+                                       (int)(pt - pt->context->pt));
                }
-               lwsl_info("%s: ctx %p: already being destroyed\n",
-                           __func__, context);
 
-               lws_context_destroy3(context);
-               return;
-       }
+               /*
+                * wsis are gone, pts are gone, vhosts are gone.
+                *
+                * clean up the context and things hanging off it
+                */
 
-       lwsl_info("%s: ctx %p\n", __func__, context);
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+               lws_cache_destroy(&context->trust_cache);
+               lws_tls_jit_trust_inflight_destroy_all(context);
+#endif
 
-       context->being_destroyed = 1;
-       context->being_destroyed1 = 1;
-       context->requested_kill = 1;
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
+               lws_cache_destroy(&context->nsc);
+               lws_cache_destroy(&context->l1);
+#endif
 
-#if defined(LWS_WITH_NETWORK)
-       m = context->count_threads;
-       memset(&wsi, 0, sizeof(wsi));
-       wsi.context = context;
+#if defined(LWS_WITH_SYS_SMD)
+               _lws_smd_destroy(context);
+#endif
 
-#ifdef LWS_LATENCY
-       if (context->worst_latency_info[0])
-               lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+               lws_async_dns_deinit(&context->async_dns);
+#endif
+#if defined(LWS_WITH_SYS_DHCP_CLIENT)
+               lws_dhcpc_remove(context, NULL);
 #endif
 
-       while (m--) {
-               struct lws_context_per_thread *pt = &context->pt[m];
-               vpt = (volatile struct lws_context_per_thread *)pt;
+               if (context->pt[0].fds)
+                       lws_free_set_NULL(context->pt[0].fds);
+#endif
+               lws_context_deinit_ssl_library(context);
 
-               ftp = vpt->foreign_pfd_list;
-               while (ftp) {
-                       next = ftp->next;
-                       lws_free((void *)ftp);
-                       ftp = next;
-               }
-               vpt->foreign_pfd_list = NULL;
+#if defined(LWS_WITH_DETAILED_LATENCIES)
+               if (context->latencies_fd != -1)
+                       compatible_close(context->latencies_fd);
+#endif
 
-               for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
-                       struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
-                       if (!wsi)
-                               continue;
+               for (n = 0; n < LWS_SYSBLOB_TYPE_COUNT; n++)
+                       lws_system_blob_destroy(
+                                       lws_system_get_blob(context, (lws_system_blob_item_t)n, 0));
+
+#if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_SECURE_STREAMS) && \
+       !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+
+               while (context->server_der_list) {
+                       struct lws_ss_x509 *x = context->server_der_list;
 
-                       if (wsi->event_pipe)
-                               lws_destroy_event_pipe(wsi);
-                       else
-                               lws_close_free_wsi(wsi,
-                                       LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
-                                       "ctx destroy"
-                                       /* no protocol close */);
-                       n--;
+                       context->server_der_list = x->next;
+                       lws_free((void *)x->ca_der);
                }
-               lws_pt_mutex_destroy(pt);
-       }
 
-       /*
-        * inform all the protocols that they are done and will have no more
-        * callbacks.
-        *
-        * We can't free things until after the event loop shuts down.
-        */
-       if (context->protocol_init_done)
-               vh = context->vhost_list;
-       while (vh) {
-               struct lws_vhost *vhn = vh->vhost_next;
-               lws_vhost_destroy1(vh);
-               vh = vhn;
-       }
+               if (context->ac_policy)
+                       lwsac_free(&context->ac_policy);
 #endif
 
-       lws_plat_context_early_destroy(context);
+               /*
+                * Context lock is about to go away
+                */
 
-#if defined(LWS_WITH_NETWORK)
+               lws_context_unlock(context);
 
-       /*
-        * We face two different needs depending if foreign loop or not.
-        *
-        * 1) If foreign loop, we really want to advance the destroy_context()
-        *    past here, and block only for libuv-style async close completion.
-        *
-        * 2a) If poll, and we exited by ourselves and are calling a final
-        *     destroy_context() outside of any service already, we want to
-        *     advance all the way in one step.
-        *
-        * 2b) If poll, and we are reacting to a SIGINT, service thread(s) may
-        *     be in poll wait or servicing.  We can't advance the
-        *     destroy_context() to the point it's freeing things; we have to
-        *     leave that for the final destroy_context() after the service
-        *     thread(s) are finished calling for service.
-        */
+#if LWS_MAX_SMP > 1
+               lws_mutex_refcount_destroy(&context->mr);
+#endif
+
+#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_NETWORK)
+               lws_metrics_destroy(context);
+#endif
+
+               if (context->external_baggage_free_on_destroy)
+                       free(context->external_baggage_free_on_destroy);
 
-       if (context->event_loop_ops->destroy_context1) {
-               context->event_loop_ops->destroy_context1(context);
+#if defined(LWS_PLAT_FREERTOS)
+#if defined(LWS_AMAZON_RTOS)
+               context->last_free_heap = xPortGetFreeHeapSize();
+#else
+               context->last_free_heap = esp_get_free_heap_size();
+#endif
+#endif
+
+#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
+               if (context->evlib_plugin_list)
+                       lws_plugins_destroy(&context->evlib_plugin_list,
+                                           NULL, NULL);
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+               lws_fi_destroy(&context->fic);
+#endif
+
+               lwsl_refcount_cx(context->log_cx, -1);
+
+               lws_free(context);
+
+               if (pcontext_finalize)
+                       *pcontext_finalize = NULL;
 
                return;
        }
+
+#if defined(LWS_WITH_NETWORK)
+bail:
 #endif
+       lwsl_cx_info(context, "leaving");
+       context->inside_context_destroy = 0;
+       lws_context_unlock(context);
+}
 
-#if defined(LWS_WITH_ESP32)
-#if defined(LWS_AMAZON_RTOS)
-       context->last_free_heap = xPortGetFreeHeapSize();
+int
+lws_context_is_being_destroyed(struct lws_context *context)
+{
+       return !!context->being_destroyed;
+}
+
+#if defined(LWS_WITH_SYS_STATE)
+struct lws_context *
+lws_system_context_from_system_mgr(lws_state_manager_t *mgr)
+{
+#if defined(LWS_WITH_NETWORK)
+       return mgr->context;
 #else
-       context->last_free_heap = esp_get_free_heap_size();
+       return NULL;
 #endif
+}
 #endif
 
-       lws_context_destroy2(context);
+void
+lws_log_prepend_context(struct lws_log_cx *cx, void *obj, char **p, char *e)
+{
+       struct lws_context *lcx = (struct lws_context *)obj;
+
+       if (lcx->name)
+               *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
+                                  lcx->name);
 }
 
+struct lws_log_cx *
+lwsl_context_get_cx(struct lws_context *cx)
+{
+       if (!cx)
+               return NULL;
+
+       return cx->log_cx;
+}
index c425cdc..1c66e8b 100644 (file)
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #ifdef LWS_HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
+#include <signal.h>
+
+void
+lws_ser_wu16be(uint8_t *b, uint16_t u)
+{
+       *b++ = (uint8_t)(u >> 8);
+       *b = (uint8_t)u;
+}
+
+void
+lws_ser_wu32be(uint8_t *b, uint32_t u32)
+{
+       *b++ = (uint8_t)(u32 >> 24);
+       *b++ = (uint8_t)(u32 >> 16);
+       *b++ = (uint8_t)(u32 >> 8);
+       *b = (uint8_t)u32;
+}
+
+void
+lws_ser_wu64be(uint8_t *b, uint64_t u64)
+{
+       lws_ser_wu32be(b, (uint32_t)(u64 >> 32));
+       lws_ser_wu32be(b + 4, (uint32_t)u64);
+}
+
+uint16_t
+lws_ser_ru16be(const uint8_t *b)
+{
+       return (uint16_t)((b[0] << 8) | b[1]);
+}
+
+uint32_t
+lws_ser_ru32be(const uint8_t *b)
+{
+       return (unsigned int)((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
+}
+
+uint64_t
+lws_ser_ru64be(const uint8_t *b)
+{
+       return (((uint64_t)lws_ser_ru32be(b)) << 32) | lws_ser_ru32be(b + 4);
+}
+
+int
+lws_vbi_encode(uint64_t value, void *buf)
+{
+       uint8_t *p = (uint8_t *)buf, b;
+
+       if (value > 0xfffffff) {
+               assert(0);
+               return -1;
+       }
+
+       do {
+               b = value & 0x7f;
+               value >>= 7;
+               if (value)
+                       *p++ = (0x80 | b);
+               else
+                       *p++ = b;
+       } while (value);
+
+       return lws_ptr_diff(p, buf);
+}
+
+int
+lws_vbi_decode(const void *buf, uint64_t *value, size_t len)
+{
+       const uint8_t *p = (const uint8_t *)buf, *end = p + len;
+       uint64_t v = 0;
+       int s = 0;
+
+       while (p < end) {
+               v |= (((uint64_t)(*p)) & 0x7f) << s;
+               if (*p & 0x80) {
+                       *value = v;
+
+                       return lws_ptr_diff(p, buf);
+               }
+               s += 7;
+               if (s >= 64)
+                       return 0;
+               p++;
+       }
+
+       return 0;
+}
 
 signed char char_to_hex(const char c)
 {
        if (c >= '0' && c <= '9')
-               return c - '0';
+               return (signed char)(c - '0');
 
        if (c >= 'a' && c <= 'f')
-               return c - 'a' + 10;
+               return (signed char)(c - 'a' + 10);
 
        if (c >= 'A' && c <= 'F')
-               return c - 'A' + 10;
+               return (signed char)(c - 'A' + 10);
 
-       return -1;
+       return (signed char)-1;
 }
 
 int
@@ -54,19 +144,60 @@ lws_hex_to_byte_array(const char *h, uint8_t *dest, int max)
                if (t1 < 0)
                        return -1;
 
-               *dest++ = (t << 4) | t1;
+               *dest++ = (uint8_t)((t << 4) | t1);
        }
 
        if (max < 0)
                return -1;
 
-       return dest - odest;
+       return lws_ptr_diff(dest, odest);
 }
 
+static char *hexch = "0123456789abcdef";
+
+void
+lws_hex_from_byte_array(const uint8_t *src, size_t slen, char *dest, size_t len)
+{
+       char *end = &dest[len - 1];
+
+       while (slen-- && dest != end) {
+               uint8_t b = *src++;
+               *dest++ = hexch[b >> 4];
+               if (dest == end)
+                       break;
+               *dest++ = hexch[b & 0xf];
+       }
+
+       *dest = '\0';
+}
+
+int
+lws_hex_random(struct lws_context *context, char *dest, size_t len)
+{
+       size_t n = ((len - 1) / 2) + 1;
+       uint8_t b, *r = (uint8_t *)dest + len - n;
+
+       if (lws_get_random(context, r, n) != n)
+               return 1;
+
+       while (len >= 3) {
+               b = *r++;
+               *dest++ = hexch[b >> 4];
+               *dest++ = hexch[b & 0xf];
+               len -= 2;
+       }
+
+       if (len == 2)
+               *dest++ = hexch[(*r) >> 4];
+
+       *dest = '\0';
+
+       return 0;
+}
 
 #if !defined(LWS_PLAT_OPTEE)
 
-#if !defined(LWS_AMAZON_RTOS)
+#if defined(LWS_WITH_FILE_OPS)
 int lws_open(const char *__file, int __oflag, ...)
 {
        va_list ap;
@@ -78,8 +209,18 @@ int lws_open(const char *__file, int __oflag, ...)
                || ((__oflag & O_TMPFILE) == O_TMPFILE)
 #endif
        )
+#if defined(WIN32)
                /* last arg is really a mode_t.  But windows... */
                n = open(__file, __oflag, va_arg(ap, uint32_t));
+#else
+               /* ... and some other toolchains...
+                *
+                * error: second argument to 'va_arg' is of promotable type 'mode_t'
+                * (aka 'unsigned short'); this va_arg has undefined behavior because
+                * arguments will be promoted to 'int'
+                */
+               n = open(__file, __oflag, (mode_t)va_arg(ap, unsigned int));
+#endif
        else
                n = open(__file, __oflag);
        va_end(ap);
@@ -103,6 +244,10 @@ lws_pthread_self_to_tsi(struct lws_context *context)
        struct lws_context_per_thread *pt = &context->pt[0];
        int n;
 
+       /* case that we have SMP build, but don't use it */
+       if (context->count_threads == 1)
+               return 0;
+
        for (n = 0; n < context->count_threads; n++) {
                if (pthread_equal(ps, pt->self))
                        return n;
@@ -115,13 +260,13 @@ lws_pthread_self_to_tsi(struct lws_context *context)
 #endif
 }
 
-LWS_EXTERN void *
+void *
 lws_context_user(struct lws_context *context)
 {
        return context->user_space;
 }
 
-LWS_VISIBLE void
+void
 lws_explicit_bzero(void *p, size_t len)
 {
        volatile uint8_t *vp = p;
@@ -136,96 +281,27 @@ lws_explicit_bzero(void *p, size_t len)
  * lws_now_secs() - seconds since 1970-1-1
  *
  */
-LWS_VISIBLE LWS_EXTERN unsigned long
+unsigned long
 lws_now_secs(void)
 {
        struct timeval tv;
 
        gettimeofday(&tv, NULL);
 
-       return tv.tv_sec;
+       return (unsigned long)tv.tv_sec;
 }
 
 #endif
-LWS_VISIBLE extern const char *
+
+#if defined(LWS_WITH_SERVER)
+const char *
 lws_canonical_hostname(struct lws_context *context)
 {
        return (const char *)context->canonical_hostname;
 }
-
-#if defined(LWS_WITH_SOCKS5)
-LWS_VISIBLE int
-lws_set_socks(struct lws_vhost *vhost, const char *socks)
-{
-       char *p_at, *p_colon;
-       char user[96];
-       char password[96];
-
-       if (!socks)
-               return -1;
-
-       vhost->socks_user[0] = '\0';
-       vhost->socks_password[0] = '\0';
-
-       p_at = strrchr(socks, '@');
-       if (p_at) { /* auth is around */
-               if ((unsigned int)(p_at - socks) > (sizeof(user)
-                       + sizeof(password) - 2)) {
-                       lwsl_err("Socks auth too long\n");
-                       goto bail;
-               }
-
-               p_colon = strchr(socks, ':');
-               if (p_colon) {
-                       if ((unsigned int)(p_colon - socks) > (sizeof(user)
-                               - 1) ) {
-                               lwsl_err("Socks user too long\n");
-                               goto bail;
-                       }
-                       if ((unsigned int)(p_at - p_colon) > (sizeof(password)
-                               - 1) ) {
-                               lwsl_err("Socks password too long\n");
-                               goto bail;
-                       }
-
-                       lws_strncpy(vhost->socks_user, socks, p_colon - socks + 1);
-                       lws_strncpy(vhost->socks_password, p_colon + 1,
-                               p_at - (p_colon + 1) + 1);
-               }
-
-               lwsl_info(" Socks auth, user: %s, password: %s\n",
-                       vhost->socks_user, vhost->socks_password );
-
-               socks = p_at + 1;
-       }
-
-       lws_strncpy(vhost->socks_proxy_address, socks,
-                   sizeof(vhost->socks_proxy_address));
-
-       p_colon = strchr(vhost->socks_proxy_address, ':');
-       if (!p_colon && !vhost->socks_proxy_port) {
-               lwsl_err("socks_proxy needs to be address:port\n");
-               return -1;
-       } else {
-               if (p_colon) {
-                       *p_colon = '\0';
-                       vhost->socks_proxy_port = atoi(p_colon + 1);
-               }
-       }
-
-       lwsl_info(" Socks %s:%u\n", vhost->socks_proxy_address,
-                       vhost->socks_proxy_port);
-
-       return 0;
-
-bail:
-       return -1;
-}
 #endif
 
-
-
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_get_count_threads(struct lws_context *context)
 {
        return context->count_threads;
@@ -259,7 +335,7 @@ static const unsigned char e0f4[] = {
        0x80 | ((4 - 1) << 2) | 1, /* s3 */
 };
 
-LWS_EXTERN int
+int
 lws_check_byte_utf8(unsigned char state, unsigned char c)
 {
        unsigned char s = state;
@@ -282,7 +358,7 @@ lws_check_byte_utf8(unsigned char state, unsigned char c)
        return e0f4[21 + (s & 3)];
 }
 
-LWS_EXTERN int
+int
 lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len)
 {
        unsigned char s = *state;
@@ -324,10 +400,118 @@ lws_strdup(const char *s)
        return d;
 }
 
+const char *
+lws_nstrstr(const char *buf, size_t len, const char *name, size_t nl)
+{
+       const char *end = buf + len - nl + 1;
+       size_t n;
+
+       if (nl > len)
+               /* it cannot be found if the needle is longer than the haystack */
+               return NULL;
+
+       while (buf < end) {
+               if (*buf != name[0]) {
+                       buf++;
+                       continue;
+               }
+
+               if (nl == 1)
+                       /* single char match, we are done */
+                       return buf;
+
+               if (buf[nl - 1] == name[nl - 1]) {
+                       /*
+                        * This is looking interesting then... the first
+                        * and last chars match, let's check the insides
+                        */
+                       n = 1;
+                       while (n < nl && buf[n] == name[n])
+                               n++;
+
+                       if (n == nl)
+                               /* it's a hit */
+                               return buf;
+               }
+
+               buf++;
+       }
+
+       return NULL;
+}
+
+/*
+ * name wants to be something like "\"myname\":"
+ */
+
+const char *
+lws_json_simple_find(const char *buf, size_t len, const char *name, size_t *alen)
+{
+       size_t nl = strlen(name);
+       const char *np = lws_nstrstr(buf, len, name, nl),
+                  *end = buf + len, *as;
+       int qu = 0;
+
+       if (!np)
+               return NULL;
+
+       np += nl;
+
+       while (np < end && (*np == ' ' || *np == '\t'))
+               np++;
+
+       if (np >= end)
+               return NULL;
+
+       /*
+        * The arg could be lots of things after "name": with JSON, commonly a
+        * string like "mystring", true, false, null, [...] or {...} ... we want
+        * to handle common, simple cases cheaply with this; the user can choose
+        * a full JSON parser like lejp if it's complicated.  So if no opening
+        * quote, return until a terminator like , ] }.  If there's an opening
+        * quote, return until closing quote, handling escaped quotes.
+        */
+
+       if (*np == '\"') {
+               qu = 1;
+               np++;
+       }
+
+       as = np;
+       while (np < end &&
+              (!qu || *np != '\"') && /* end quote is EOT if quoted */
+              (qu || (*np != '}' && *np != ']' && *np != ',')) /* delimiters */
+       ) {
+               if (qu && *np == '\\') /* skip next char if quoted escape */
+                       np++;
+               np++;
+       }
+
+       *alen = (unsigned int)lws_ptr_diff(np, as);
+
+       return as;
+}
+
+int
+lws_json_simple_strcmp(const char *buf, size_t len, const char *name,
+                      const char *comp)
+{
+       size_t al;
+       const char *hit = lws_json_simple_find(buf, len, name, &al);
+
+       if (!hit)
+               return -1;
+
+       if (al != strlen(comp))
+               return -1;
+
+       return strncmp(hit, comp, al);
+}
+
 static const char *hex = "0123456789ABCDEF";
 
-LWS_VISIBLE LWS_EXTERN const char *
-lws_sql_purify(char *escaped, const char *string, int len)
+const char *
+lws_sql_purify(char *escaped, const char *string, size_t len)
 {
        const char *p = string;
        char *q = escaped;
@@ -346,8 +530,22 @@ lws_sql_purify(char *escaped, const char *string, int len)
        return escaped;
 }
 
-LWS_VISIBLE LWS_EXTERN const char *
-lws_json_purify(char *escaped, const char *string, int len)
+int
+lws_sql_purify_len(const char *p)
+{
+       int olen = 0;
+
+       while (*p) {
+               if (*p++ == '\'')
+                       olen++;
+               olen++;
+       }
+
+       return olen;
+}
+
+const char *
+lws_json_purify(char *escaped, const char *string, int len, int *in_used)
 {
        const char *p = string;
        char *q = escaped;
@@ -379,7 +577,14 @@ lws_json_purify(char *escaped, const char *string, int len)
                        continue;
                }
 
-               if (*p == '\"' || *p == '\\' || *p < 0x20) {
+               if (*p == '\\') {
+                       p++;
+                       *q++ = '\\';
+                       *q++ = '\\';
+                       continue;
+               }
+
+               if (*p == '\"' || *p < 0x20) {
                        *q++ = '\\';
                        *q++ = 'u';
                        *q++ = '0';
@@ -393,10 +598,38 @@ lws_json_purify(char *escaped, const char *string, int len)
        }
        *q = '\0';
 
+       if (in_used)
+               *in_used = lws_ptr_diff(p, string);
+
        return escaped;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+int
+lws_json_purify_len(const char *string)
+{
+       int len = 0;
+       const char *p = string;
+
+       while (*p) {
+               if (*p == '\t' || *p == '\n' || *p == '\r') {
+                       p++;
+                       len += 2;
+                       continue;
+               }
+
+               if (*p == '\"' || *p == '\\' || *p < 0x20) {
+                       len += 6;
+                       p++;
+                       continue;
+               }
+               p++;
+               len++;
+       }
+
+       return len;
+}
+
+void
 lws_filename_purify_inplace(char *filename)
 {
        while (*filename) {
@@ -407,7 +640,9 @@ lws_filename_purify_inplace(char *filename)
                }
 
                if (*filename == ':' ||
+#if !defined(WIN32)
                    *filename == '\\' ||
+#endif
                    *filename == '$' ||
                    *filename == '%')
                        *filename = '_';
@@ -416,7 +651,7 @@ lws_filename_purify_inplace(char *filename)
        }
 }
 
-LWS_VISIBLE LWS_EXTERN const char *
+const char *
 lws_urlencode(char *escaped, const char *string, int len)
 {
        const char *p = string;
@@ -446,7 +681,7 @@ lws_urlencode(char *escaped, const char *string, int len)
        return escaped;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_urldecode(char *string, const char *escaped, int len)
 {
        int state = 0, n;
@@ -474,7 +709,7 @@ lws_urldecode(char *string, const char *escaped, int len)
                        if (n < 0)
                                return -1;
                        escaped++;
-                       sum = n << 4;
+                       sum = (char)(n << 4);
                        state++;
                        break;
 
@@ -483,7 +718,7 @@ lws_urldecode(char *string, const char *escaped, int len)
                        if (n < 0)
                                return -1;
                        escaped++;
-                       *string++ = sum | n;
+                       *string++ = (char)(sum | n);
                        len--;
                        state = 0;
                        break;
@@ -495,7 +730,7 @@ lws_urldecode(char *string, const char *escaped, int len)
        return 0;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_finalize_startup(struct lws_context *context)
 {
        if (lws_check_opt(context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
@@ -505,12 +740,14 @@ lws_finalize_startup(struct lws_context *context)
        return 0;
 }
 
-LWS_VISIBLE LWS_EXTERN void
-lws_get_effective_uid_gid(struct lws_context *context, int *uid, int *gid)
+#if !defined(LWS_PLAT_FREERTOS)
+void
+lws_get_effective_uid_gid(struct lws_context *context, uid_t *uid, gid_t *gid)
 {
        *uid = context->uid;
        *gid = context->gid;
 }
+#endif
 
 int
 lws_snprintf(char *str, size_t size, const char *format, ...)
@@ -547,7 +784,7 @@ lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len)
        uint8_t sum = 0;
 
        while (len--)
-               sum |= (*pa++ ^ *pb++);
+               sum |= (uint8_t)(*pa++ ^ *pb++);
 
        return sum;
 }
@@ -560,18 +797,14 @@ typedef enum {
        LWS_TOKZS_TOKEN_POST_TERMINAL
 } lws_tokenize_state;
 
-#if defined(LWS_AMAZON_RTOS)
 lws_tokenize_elem
-#else
-int
-#endif
 lws_tokenize(struct lws_tokenize *ts)
 {
        const char *rfc7230_delims = "(),/:;<=>?@[\\]{}";
        lws_tokenize_state state = LWS_TOKZS_LEADING_WHITESPACE;
-       char c, flo = 0, d_minus = '-', d_dot = '.', s_minus = '\0',
-            s_dot = '\0';
-       signed char num = ts->flags & LWS_TOKENIZE_F_NO_INTEGERS ? 0 : -1;
+       char c, flo = 0, d_minus = '-', d_dot = '.', d_star = '*', s_minus = '\0',
+            s_dot = '\0', s_star = '\0', d_eq = '=', s_eq = '\0', skipping = 0;
+       signed char num = (ts->flags & LWS_TOKENIZE_F_NO_INTEGERS) ? 0 : -1;
        int utf8 = 0;
 
        /* for speed, compute the effect of the flags outside the loop */
@@ -584,6 +817,14 @@ lws_tokenize(struct lws_tokenize *ts)
                d_dot = '\0';
                s_dot = '.';
        }
+       if (ts->flags & LWS_TOKENIZE_F_ASTERISK_NONTERM) {
+               d_star = '\0';
+               s_star = '*';
+       }
+       if (ts->flags & LWS_TOKENIZE_F_EQUALS_NONTERM) {
+               d_eq = '\0';
+               s_eq = '=';
+       }
 
        ts->token = NULL;
        ts->token_len = 0;
@@ -592,13 +833,29 @@ lws_tokenize(struct lws_tokenize *ts)
                c = *ts->start++;
                ts->len--;
 
-               utf8 = lws_check_byte_utf8((unsigned char)utf8, c);
+               utf8 = lws_check_byte_utf8((unsigned char)utf8, (unsigned char)c);
                if (utf8 < 0)
                        return LWS_TOKZE_ERR_BROKEN_UTF8;
 
                if (!c)
                        break;
 
+               if (skipping) {
+                       if (c != '\r' && c != '\n')
+                               continue;
+                       else
+                               skipping = 0;
+               }
+
+               /* comment */
+
+               if (ts->flags & LWS_TOKENIZE_F_HASH_COMMENT &&
+                   state != LWS_TOKZS_QUOTED_STRING &&
+                   c == '#') {
+                       skipping = 1;
+                       continue;
+               }
+
                /* whitespace */
 
                if (c == ' ' || c == '\t' || c == '\n' || c == '\r' ||
@@ -641,7 +898,8 @@ lws_tokenize(struct lws_tokenize *ts)
 
                /* token= aggregation */
 
-               if (c == '=' && (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
+               if (!(ts->flags & LWS_TOKENIZE_F_EQUALS_NONTERM) &&
+                   c == '=' && (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
                                 state == LWS_TOKZS_TOKEN)) {
                        if (num == 1)
                                return LWS_TOKZE_ERR_NUM_ON_LHS;
@@ -690,9 +948,10 @@ lws_tokenize(struct lws_tokenize *ts)
                    ((!(ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS) &&
                     (c < '0' || c > '9') && (c < 'A' || c > 'Z') &&
                     (c < 'a' || c > 'z') && c != '_') &&
-                    c != s_minus && c != s_dot) ||
-                   c == d_minus || c == d_dot
-                   )) {
+                    c != s_minus && c != s_dot && c != s_star && c != s_eq) ||
+                   c == d_minus || c == d_dot || c == d_star || c == d_eq
+                   ) &&
+                   !((ts->flags & LWS_TOKENIZE_F_SLASH_NONTERM) && c == '/')) {
                        switch (state) {
                        case LWS_TOKZS_LEADING_WHITESPACE:
                                if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
@@ -786,8 +1045,8 @@ token_or_numeric:
 }
 
 
-LWS_VISIBLE LWS_EXTERN int
-lws_tokenize_cstr(struct lws_tokenize *ts, char *str, int max)
+int
+lws_tokenize_cstr(struct lws_tokenize *ts, char *str, size_t max)
 {
        if (ts->token_len + 1 >= max)
                return 1;
@@ -798,15 +1057,210 @@ lws_tokenize_cstr(struct lws_tokenize *ts, char *str, int max)
        return 0;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_tokenize_init(struct lws_tokenize *ts, const char *start, int flags)
 {
        ts->start = start;
        ts->len = 0x7fffffff;
-       ts->flags = flags;
+       ts->flags = (uint16_t)(unsigned int)flags;
        ts->delim = LWSTZ_DT_NEED_FIRST_CONTENT;
 }
 
+
+typedef enum {
+       LWS_EXPS_LITERAL,
+       LWS_EXPS_OPEN_OR_LIT,
+       LWS_EXPS_NAME_OR_CLOSE,
+       LWS_EXPS_DRAIN,
+} lws_strexp_state;
+
+void
+lws_strexp_init(lws_strexp_t *exp, void *priv, lws_strexp_expand_cb cb,
+                char *out, size_t olen)
+{
+       memset(exp, 0, sizeof(*exp));
+       exp->cb = cb;
+       exp->out = out;
+       exp->olen = olen;
+       exp->state = LWS_EXPS_LITERAL;
+       exp->priv = priv;
+}
+
+void
+lws_strexp_reset_out(lws_strexp_t *exp, char *out, size_t olen)
+{
+       exp->out = out;
+       exp->olen = olen;
+       exp->pos = 0;
+}
+
+int
+lws_strexp_expand(lws_strexp_t *exp, const char *in, size_t len,
+                 size_t *pused_in, size_t *pused_out)
+{
+       size_t used = 0;
+       int n;
+
+       while (used < len) {
+
+               switch (exp->state) {
+               case LWS_EXPS_LITERAL:
+                       if (*in == '$') {
+                               exp->state = LWS_EXPS_OPEN_OR_LIT;
+                               break;
+                       }
+
+                       if (exp->out)
+                               exp->out[exp->pos] = *in;
+                       exp->pos++;
+                       if (exp->olen - exp->pos < 1) {
+                               *pused_in = used + 1;
+                               *pused_out = exp->pos;
+                               return LSTRX_FILLED_OUT;
+                       }
+                       break;
+
+               case LWS_EXPS_OPEN_OR_LIT:
+                       if (*in == '{') {
+                               exp->state = LWS_EXPS_NAME_OR_CLOSE;
+                               exp->name_pos = 0;
+                               exp->exp_ofs = 0;
+                               break;
+                       }
+                       /* treat as a literal */
+                       if (exp->olen - exp->pos < 3)
+                               return -1;
+
+                       if (exp->out) {
+                               exp->out[exp->pos++] = '$';
+                               exp->out[exp->pos++] = *in;
+                       } else
+                               exp->pos += 2;
+                       if (*in != '$')
+                               exp->state = LWS_EXPS_LITERAL;
+                       break;
+
+               case LWS_EXPS_NAME_OR_CLOSE:
+                       if (*in == '}') {
+                               exp->name[exp->name_pos] = '\0';
+                               exp->state = LWS_EXPS_DRAIN;
+                               goto drain;
+                       }
+                       if (exp->name_pos >= sizeof(exp->name) - 1)
+                               return LSTRX_FATAL_NAME_TOO_LONG;
+
+                       exp->name[exp->name_pos++] = *in;
+                       break;
+
+               case LWS_EXPS_DRAIN:
+drain:
+                       *pused_in = used;
+                       n = exp->cb(exp->priv, exp->name, exp->out, &exp->pos,
+                                   exp->olen, &exp->exp_ofs);
+                       *pused_out = exp->pos;
+                       if (n == LSTRX_FILLED_OUT ||
+                           n == LSTRX_FATAL_NAME_UNKNOWN)
+                               return n;
+
+                       exp->state = LWS_EXPS_LITERAL;
+                       break;
+               }
+
+               used++;
+               in++;
+       }
+
+       if (exp->out)
+               exp->out[exp->pos] = '\0';
+       *pused_in = used;
+       *pused_out = exp->pos;
+
+       return LSTRX_DONE;
+}
+
+int
+lws_strcmp_wildcard(const char *wildcard, size_t wlen, const char *check,
+                   size_t clen)
+{
+       const char *match[3], *wc[3], *wc_end = wildcard + wlen,
+                  *cend = check + clen;
+       int sp = 0;
+
+       do {
+
+               if (wildcard == wc_end) {
+                       /*
+                        * We reached the end of wildcard, but not of check,
+                        * and the last thing in wildcard was not a * or we
+                        * would have completed already... if we can rewind,
+                        * let's try that...
+                        */
+                       if (sp) {
+                               wildcard = wc[sp - 1];
+                               check = match[--sp];
+
+                               continue;
+                       }
+
+                       /* otherwise it's the end of the road for this one */
+
+                       return 1;
+               }
+
+               if (*wildcard == '*') {
+
+                       if (++wildcard == wc_end)
+                                /*
+                                 * Wildcard ended on a *, so we know we will
+                                 * match unconditionally
+                                 */
+                               return 0;
+
+                       /*
+                        * Now we need to stick wildcard here and see if there
+                        * is any remaining match exists, for eg b of "a*b"
+                        */
+
+                       if (sp == LWS_ARRAY_SIZE(match)) {
+                               lwsl_err("%s: exceeds * stack\n", __func__);
+                               return 1; /* we can't deal with it */
+                       }
+
+                       wc[sp] = wildcard;
+                       /* if we ever pop and come back here, pick up from +1 */
+                       match[sp++] = check + 1;
+                       continue;
+               }
+
+               if (*(check++) == *wildcard) {
+
+                       if (wildcard == wc_end)
+                               return 0;
+                       /*
+                        * We're still compatible with wildcard... keep going
+                        */
+                       wildcard++;
+
+                       continue;
+               }
+
+               if (!sp)
+                       /*
+                        * We're just trying to match literals, and failed...
+                        */
+                       return 1;
+
+               /* we're looking for a post-* match... keep looking... */
+
+       } while (check < cend);
+
+       /*
+        * We reached the end of check, if also at end of wildcard we're OK
+        */
+
+       return wildcard != wc_end;
+}
+
 #if LWS_MAX_SMP > 1
 
 void
@@ -816,7 +1270,13 @@ lws_mutex_refcount_init(struct lws_mutex_refcount *mr)
        mr->last_lock_reason = NULL;
        mr->lock_depth = 0;
        mr->metadata = 0;
+#ifdef __PTW32_H
+       /* If we use implementation of PThreads for Win that is
+        * distributed by VCPKG */
+       memset(&mr->lock_owner, 0, sizeof(pthread_t));
+#else
        mr->lock_owner = 0;
+#endif
 }
 
 void
@@ -838,7 +1298,14 @@ lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason)
         *
         *  - it can be false and change to a different tid that is also false
         */
-       if (mr->lock_owner == pthread_self()) {
+#ifdef __PTW32_H
+       /* If we use implementation of PThreads for Win that is
+        * distributed by VCPKG */
+       if (pthread_equal(mr->lock_owner, pthread_self()))
+#else
+       if (mr->lock_owner == pthread_self())
+#endif
+       {
                /* atomic because we only change it if we own the lock */
                mr->lock_depth++;
                return;
@@ -860,18 +1327,37 @@ lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr)
                return;
 
        mr->last_lock_reason = "free";
+#ifdef __PTW32_H
+       /* If we use implementation of PThreads for Win that is
+        * distributed by VCPKG */
+       memset(&mr->lock_owner, 0, sizeof(pthread_t));
+#else
        mr->lock_owner = 0;
-       //lwsl_notice("tid %d: unlock %s\n", mr->tid, mr->last_lock_reason);
+#endif
+       // lwsl_notice("tid %d: unlock %s\n", mr->tid, mr->last_lock_reason);
        pthread_mutex_unlock(&mr->lock);
 }
 
+void
+lws_mutex_refcount_assert_held(struct lws_mutex_refcount *mr)
+{
+#ifdef __PTW32_H
+       /* If we use implementation of PThreads for Win that is
+        * distributed by VCPKG */
+       assert(pthread_equal(mr->lock_owner, pthread_self()) && mr->lock_depth);
+#else
+       assert(mr->lock_owner == pthread_self() && mr->lock_depth);
+#endif
+}
+
 #endif /* SMP */
 
 
 const char *
 lws_cmdline_option(int argc, const char **argv, const char *val)
 {
-       int n = (int)strlen(val), c = argc;
+       size_t n = strlen(val);
+       int c = argc;
 
        while (--c > 0) {
 
@@ -883,6 +1369,8 @@ lws_cmdline_option(int argc, const char **argv, const char *val)
                                return argv[c + 1];
                        }
 
+                       if (argv[c][n] == '=')
+                               return &argv[c][n + 1];
                        return argv[c] + n;
                }
        }
@@ -890,66 +1378,162 @@ lws_cmdline_option(int argc, const char **argv, const char *val)
        return NULL;
 }
 
+static const char * const builtins[] = {
+       "-d",
+       "--fault-injection",
+       "--fault-seed",
+       "--ignore-sigterm"
+};
+
+enum opts {
+       OPT_DEBUGLEVEL,
+       OPT_FAULTINJECTION,
+       OPT_FAULT_SEED,
+       OPT_IGNORE_SIGTERM,
+};
+
+#if !defined(LWS_PLAT_FREERTOS)
+static void
+lws_sigterm_catch(int sig)
+{
+}
+#endif
+
+void
+lws_cmdline_option_handle_builtin(int argc, const char **argv,
+                                 struct lws_context_creation_info *info)
+{
+       const char *p;
+       int n, m, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       uint64_t seed = (uint64_t)lws_now_usecs();
+#endif
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(builtins); n++) {
+               p = lws_cmdline_option(argc, argv, builtins[n]);
+               if (!p)
+                       continue;
+
+               m = atoi(p);
+
+               switch (n) {
+               case OPT_DEBUGLEVEL:
+                       logs = m;
+                       break;
+
+               case OPT_FAULTINJECTION:
+#if !defined(LWS_WITH_SYS_FAULT_INJECTION)
+                       lwsl_err("%s: FAULT_INJECTION not built\n", __func__);
+#endif
+                       lws_fi_deserialize(&info->fic, p);
+                       break;
+
+               case OPT_FAULT_SEED:
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+                       seed = (uint64_t)atoll(p);
+#endif
+                       break;
+
+               case OPT_IGNORE_SIGTERM:
+#if !defined(LWS_PLAT_FREERTOS)
+                       signal(SIGTERM, lws_sigterm_catch);
+#endif
+                       break;
+               }
+       }
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_xos_init(&info->fic.xos, seed);
+#endif
+       lws_set_log_level(logs, NULL);
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       if (info->fic.fi_owner.count)
+               lwsl_notice("%s: Fault Injection seed %llu\n", __func__,
+                               (unsigned long long)seed);
+#endif
+}
+
 
 const lws_humanize_unit_t humanize_schema_si[] = {
-       { "Pi ", LWS_PI }, { "Ti ", LWS_TI }, { "Gi ", LWS_GI },
-       { "Mi ", LWS_MI }, { "Ki ", LWS_KI }, { "   ", 1 },
+       { "Pi", LWS_PI }, { "Ti", LWS_TI }, { "Gi", LWS_GI },
+       { "Mi", LWS_MI }, { "Ki", LWS_KI }, { "", 1 },
        { NULL, 0 }
 };
 const lws_humanize_unit_t humanize_schema_si_bytes[] = {
        { "PiB", LWS_PI }, { "TiB", LWS_TI }, { "GiB", LWS_GI },
-       { "MiB", LWS_MI }, { "KiB", LWS_KI }, { "B  ", 1 },
+       { "MiB", LWS_MI }, { "KiB", LWS_KI }, { "B", 1 },
        { NULL, 0 }
 };
 const lws_humanize_unit_t humanize_schema_us[] = {
-       { "y  ",  (uint64_t)365 * 24 * 3600 * LWS_US_PER_SEC },
-       { "d  ",  (uint64_t)24 * 3600 * LWS_US_PER_SEC },
-       { "hr ", (uint64_t)3600 * LWS_US_PER_SEC },
+       { "y",  (uint64_t)365 * 24 * 3600 * LWS_US_PER_SEC },
+       { "d",  (uint64_t)24 * 3600 * LWS_US_PER_SEC },
+       { "hr", (uint64_t)3600 * LWS_US_PER_SEC },
        { "min", 60 * LWS_US_PER_SEC },
-       { "s  ", LWS_US_PER_SEC },
-       { "ms ", LWS_US_PER_MS },
-       { "us ", 1 },
+       { "s", LWS_US_PER_SEC },
+       { "ms", LWS_US_PER_MS },
+#if defined(WIN32)
+       { "us", 1 },
+#else
+       { "μs", 1 },
+#endif
        { NULL, 0 }
 };
 
+/* biggest ull is 18446744073709551615 (20 chars) */
+
+static int
+decim(char *r, uint64_t v, char chars, char leading)
+{
+       uint64_t q = 1;
+       char *ro = r;
+       int n = 1;
+
+       while ((leading || v > (q * 10) - 1) && n < 20 && n < chars) {
+               q = q * 10;
+               n++;
+       }
+
+       /* n is how many chars needed */
+
+       while (n--) {
+               *r++ = (char)('0' + (char)((v / q) % 10));
+               q = q / 10;
+       }
+
+       *r = '\0';
+
+       return lws_ptr_diff(r, ro);
+}
+
 int
-lws_humanize(char *p, int len, uint64_t v, const lws_humanize_unit_t *schema)
+lws_humanize(char *p, size_t len, uint64_t v, const lws_humanize_unit_t *schema)
 {
+       char *obuf = p, *end = p + len;
+
        do {
                if (v >= schema->factor || schema->factor == 1) {
-                       if (schema->factor == 1)
-                               return lws_snprintf(p, len,
-                                       " %4"PRIu64"%s    ",
-                                       v / schema->factor, schema->name);
-
-                       return lws_snprintf(p, len, " %4"PRIu64".%03"PRIu64"%s",
-                               v / schema->factor,
-                               (v % schema->factor) / (schema->factor / 1000),
-                               schema->name);
+                       if (schema->factor == 1) {
+                               p += decim(p, v, 4, 0);
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                                   "%s", schema->name);
+                               return lws_ptr_diff(p, obuf);
+                       }
+
+                       p += decim(p, v / schema->factor, 4, 0);
+                       *p++ = '.';
+                       p += decim(p, (v % schema->factor) /
+                                       (schema->factor / 1000), 3, 1);
+
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                           "%s", schema->name);
+                       return lws_ptr_diff(p, obuf);
                }
                schema++;
        } while (schema->name);
 
        assert(0);
+       strncpy(p, "unknown value", len);
 
        return 0;
 }
-
-int
-lws_system_get_info(struct lws_context *context, lws_system_item_t item,
-                   lws_system_arg_t arg, size_t *len)
-{
-       if (!context->system_ops || !context->system_ops->get_info)
-               return 1;
-
-       return context->system_ops->get_info(item, arg, len);
-}
-
-int
-lws_system_reboot(struct lws_context *context)
-{
-       if (!context->system_ops || !context->system_ops->reboot)
-               return 1;
-
-       return context->system_ops->reboot();
-}
index dbece69..a13c841 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #ifdef LWS_HAVE_SYS_TYPES_H
 #include <sys/types.h>
 void lwsl_emit_optee(int level, const char *line);
 #endif
 
-int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE;
-static void (*lwsl_emit)(int level, const char *line)
-#ifndef LWS_PLAT_OPTEE
-       = lwsl_emit_stderr
+lws_log_cx_t log_cx = {
+#if !defined(LWS_PLAT_OPTEE)
+       .u.emit                         = lwsl_emit_stderr,
 #else
-       = lwsl_emit_optee;
+       .u.emit                         = lwsl_emit_optee,
 #endif
-       ;
-#ifndef LWS_PLAT_OPTEE
-static const char * const log_level_names[] = {
-       "E",
-       "W",
-       "N",
-       "I",
-       "D",
-       "P",
-       "H",
-       "EXT",
-       "C",
-       "L",
-       "U",
-       "T",
-       "?",
-       "?"
+       .lll_flags                      = LLL_ERR | LLL_WARN | LLL_NOTICE,
 };
+
+#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NO_LOGS)
+static const char * log_level_names ="EWNIDPHXCLUT??";
 #endif
 
-LWS_VISIBLE int
-lwsl_timestamp(int level, char *p, int len)
+/*
+ * Name an instance tag and attach to a group
+ */
+
+void
+__lws_lc_tag(struct lws_context *context, lws_lifecycle_group_t *grp,
+            lws_lifecycle_t *lc, const char *format, ...)
 {
-#ifndef LWS_PLAT_OPTEE
-#ifndef _WIN32_WCE
-       time_t o_now = time(NULL);
+       va_list ap;
+       int n = 1;
+
+       if (*lc->gutag == '[') {
+               /* appending inside [] */
+
+               char *cp = strchr(lc->gutag, ']');
+               char rend[96];
+               size_t ll, k;
+               int n;
+
+               if (!cp)
+                       return;
+
+               /* length of closing brace and anything else after it */
+               k = strlen(cp);
+
+               /* compute the remaining gutag unused */
+               ll = sizeof(lc->gutag) - lws_ptr_diff_size_t(cp, lc->gutag) - k - 1;
+               if (ll > sizeof(rend) - 1)
+                       ll = sizeof(rend) - 1;
+               va_start(ap, format);
+               n = vsnprintf(rend, ll, format, ap);
+               va_end(ap);
+
+               if ((unsigned int)n > ll)
+                       n = (int)ll;
+
+               /* shove the trailer up by what we added */
+               memmove(cp + n, cp, k);
+               assert(k + (unsigned int)n < sizeof(lc->gutag));
+               cp[k + (unsigned int)n] = '\0';
+               /* copy what we added into place */
+               memcpy(cp, rend, (unsigned int)n);
+
+               return;
+       }
+
+       assert(grp);
+       assert(grp->tag_prefix); /* lc group must have a tag prefix string */
+
+       lc->gutag[0] = '[';
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) /* ie, will have getpid if set */
+       n += lws_snprintf(&lc->gutag[n], sizeof(lc->gutag) -
+                                        (unsigned int)n - 1u, "%u|", getpid());
+#endif
+       n += lws_snprintf(&lc->gutag[n], sizeof(lc->gutag) -
+                                        (unsigned int)n - 1u, "%s|%lx|",
+                                        grp->tag_prefix,
+                                        (unsigned long)grp->ordinal++);
+
+       va_start(ap, format);
+       n += vsnprintf(&lc->gutag[n], sizeof(lc->gutag) - (unsigned int)n -
+                       1u, format, ap);
+       va_end(ap);
+
+       if (n < (int)sizeof(lc->gutag) - 2) {
+               lc->gutag[n++] = ']';
+               lc->gutag[n++] = '\0';
+       } else {
+               lc->gutag[sizeof(lc->gutag) - 2] = ']';
+               lc->gutag[sizeof(lc->gutag) - 1] = '\0';
+       }
+
+       lc->us_creation = (uint64_t)lws_now_usecs();
+       lws_dll2_add_tail(&lc->list, &grp->owner);
+
+       lwsl_refcount_cx(lc->log_cx, 1);
+
+#if defined(LWS_LOG_TAG_LIFECYCLE)
+       lwsl_cx_notice(context, " ++ %s (%d)", lc->gutag, (int)grp->owner.count);
+#endif
+}
+
+/*
+ * Normally we want to set the tag one time at creation.  But sometimes we
+ * don't have enough information at that point to give it a meaningful tag, eg,
+ * it's an accepted, served connection but we haven't read data from it yet
+ * to find out what it wants to be.
+ *
+ * This allows you to append some extra info to the tag in those cases, the
+ * initial tag remains the same on the lhs so it can be tracked correctly.
+ */
+
+void
+__lws_lc_tag_append(lws_lifecycle_t *lc, const char *app)
+{
+       int n = (int)strlen(lc->gutag);
+
+       if (n && lc->gutag[n - 1] == ']')
+               n--;
+
+       n += lws_snprintf(&lc->gutag[n], sizeof(lc->gutag) - 2u -
+                                        (unsigned int)n, "|%s]", app);
+
+       if ((unsigned int)n >= sizeof(lc->gutag) - 2u) {
+               lc->gutag[sizeof(lc->gutag) - 2] = ']';
+               lc->gutag[sizeof(lc->gutag) - 1] = '\0';
+       }
+}
+
+/*
+ * Remove instance from group
+ */
+
+void
+__lws_lc_untag(struct lws_context *context, lws_lifecycle_t *lc)
+{
+       //lws_lifecycle_group_t *grp;
+       char buf[24];
+
+       if (!lc->gutag[0]) { /* we never tagged this object... */
+               lwsl_cx_err(context, "%s never tagged", lc->gutag);
+               assert(0);
+               return;
+       }
+
+       if (!lc->list.owner) { /* we already untagged this object... */
+               lwsl_cx_err(context, "%s untagged twice", lc->gutag);
+               assert(0);
+               return;
+       }
+
+       //grp = lws_container_of(lc->list.owner, lws_lifecycle_group_t, owner);
+
+       lws_humanize(buf, sizeof(buf),
+                    (uint64_t)lws_now_usecs() - lc->us_creation,
+                    humanize_schema_us);
+
+#if defined(LWS_LOG_TAG_LIFECYCLE)
+       lwsl_cx_notice(context, " -- %s (%d) %s", lc->gutag,
+                   (int)lc->list.owner->count - 1, buf);
 #endif
+
+       lws_dll2_remove(&lc->list);
+
+       lwsl_refcount_cx(lc->log_cx, -1);
+}
+
+const char *
+lws_lc_tag(lws_lifecycle_t *lc)
+{
+       return lc->gutag;
+}
+
+
+int
+lwsl_timestamp(int level, char *p, size_t len)
+{
+#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NO_LOGS)
+       time_t o_now;
        unsigned long long now;
+       struct timeval tv;
        struct tm *ptm = NULL;
-#ifndef WIN32
+#if defined(LWS_HAVE_LOCALTIME_R)
        struct tm tm;
 #endif
        int n;
 
-#ifndef _WIN32_WCE
-#ifdef WIN32
-       ptm = localtime(&o_now);
+       gettimeofday(&tv, NULL);
+       o_now = tv.tv_sec;
+       now = ((unsigned long long)tv.tv_sec * 10000) +
+                               (unsigned int)(tv.tv_usec / 100);
+
+#if defined(LWS_HAVE_LOCALTIME_R)
+       ptm = localtime_r(&o_now, &tm);
 #else
-       if (localtime_r(&o_now, &tm))
-               ptm = &tm;
-#endif
+       ptm = localtime(&o_now);
 #endif
        p[0] = '\0';
        for (n = 0; n < LLL_COUNT; n++) {
                if (level != (1 << n))
                        continue;
-               now = lws_now_usecs() / 100;
+
                if (ptm)
                        n = lws_snprintf(p, len,
-                               "[%04d/%02d/%02d %02d:%02d:%02d:%04d] %s: ",
+                               "[%04d/%02d/%02d %02d:%02d:%02d:%04d] %c: ",
                                ptm->tm_year + 1900,
                                ptm->tm_mon + 1,
                                ptm->tm_mday,
@@ -94,7 +239,7 @@ lwsl_timestamp(int level, char *p, int len)
                                ptm->tm_sec,
                                (int)(now % 10000), log_level_names[n]);
                else
-                       n = lws_snprintf(p, len, "[%llu:%04d] %s: ",
+                       n = lws_snprintf(p, len, "[%llu:%04d] %c: ",
                                        (unsigned long long) now / 10000,
                                        (int)(now % 10000), log_level_names[n]);
                return n;
@@ -118,21 +263,19 @@ static const char * const colours[] = {
        "[33m", /* LLL_EXT */
        "[33m", /* LLL_CLIENT */
        "[33;1m", /* LLL_LATENCY */
-       "[30;1m", /* LLL_USER */
+        "[0;1m", /* LLL_USER */
        "[31m", /* LLL_THREAD */
 };
 
 static char tty;
 
-LWS_VISIBLE void
-lwsl_emit_stderr(int level, const char *line)
+static void
+_lwsl_emit_stderr(int level, const char *line)
 {
-       char buf[50];
        int n, m = LWS_ARRAY_SIZE(colours) - 1;
 
        if (!tty)
-               tty = isatty(2) | 2;
-       lwsl_timestamp(level, buf, sizeof(buf));
+               tty = (char)(isatty(2) | 2);
 
        if (tty == 3) {
                n = 1 << (LWS_ARRAY_SIZE(colours) - 1);
@@ -142,102 +285,264 @@ lwsl_emit_stderr(int level, const char *line)
                        m--;
                        n >>= 1;
                }
-               fprintf(stderr, "%c%s%s%s%c[0m", 27, colours[m], buf, line, 27);
+               fprintf(stderr, "%c%s%s%c[0m", 27, colours[m], line, 27);
        } else
-               fprintf(stderr, "%s%s", buf, line);
+               fprintf(stderr, "%s", line);
+}
+
+void
+lwsl_emit_stderr(int level, const char *line)
+{
+       _lwsl_emit_stderr(level, line);
 }
 
-LWS_VISIBLE void
+void
 lwsl_emit_stderr_notimestamp(int level, const char *line)
 {
-       int n, m = LWS_ARRAY_SIZE(colours) - 1;
+       _lwsl_emit_stderr(level, line);
+}
 
-       if (!tty)
-               tty = isatty(2) | 2;
+#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
 
-       if (tty == 3) {
-               n = 1 << (LWS_ARRAY_SIZE(colours) - 1);
-               while (n) {
-                       if (level & n)
-                               break;
-                       m--;
-                       n >>= 1;
-               }
-               fprintf(stderr, "%c%s%s%c[0m", 27, colours[m], line, 27);
-       } else
-               fprintf(stderr, "%s", line);
+/*
+ * Helper to emit to a file
+ */
+
+void
+lws_log_emit_cx_file(struct lws_log_cx *cx, int level, const char *line,
+                       size_t len)
+{
+       int fd = (int)(intptr_t)cx->stg;
+
+       if (fd >= 0)
+               if (write(fd, line, (unsigned int)len) != (ssize_t)len)
+                       fprintf(stderr, "Unable to write log to file\n");
+}
+
+/*
+ * Helper to use a .refcount_cb to store logs in a file
+ */
+
+void
+lws_log_use_cx_file(struct lws_log_cx *cx, int _new)
+{
+       int fd;
+
+       if (_new > 0 && cx->refcount == 1) {
+               fd = open((const char *)cx->opaque,
+                               LWS_O_CREAT | LWS_O_TRUNC | LWS_O_WRONLY, 0600);
+               if (fd < 0)
+                       fprintf(stderr, "Unable to open log %s: errno %d\n",
+                               (const char *)cx->opaque, errno);
+               cx->stg = (void *)(intptr_t)fd;
+
+               return;
+       }
+
+       fd = (int)(intptr_t)cx->stg;
+
+       if (_new <= 0 && cx->refcount == 0 && fd >= 0) {
+               close(fd);
+               cx->stg = (void *)(intptr_t)-1;
+       }
 }
 
 #endif
 
+#endif
+
 #if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK))
-LWS_VISIBLE void _lws_logv(int filter, const char *format, va_list vl)
+void
+__lws_logv(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
+          int filter, const char *_fun, const char *format, va_list vl)
 {
+#if LWS_MAX_SMP == 1 && !defined(LWS_WITH_THREADPOOL)
+       /* this is incompatible with multithreaded logging */
        static char buf[256];
-       int n;
+#else
+       char buf[1024];
+#endif
+       char *p = buf, *end = p + sizeof(buf) - 1;
+       lws_log_cx_t *cxp;
+       int n, back = 0;
+
+       /*
+        * We need to handle NULL wsi etc at the wrappers as gracefully as
+        * possible
+        */
+
+       if (!cx) {
+               lws_strncpy(p, "NULL log cx: ", sizeof(buf) - 1);
+               p += 13;
+               /* use the processwide one for lack of anything better */
+               cx = &log_cx;
+       }
 
-       if (!(log_level & filter))
+       cxp = cx;
+
+       if (!(cx->lll_flags & (uint32_t)filter))
+               /*
+                * logs may be produced and built in to the code but disabled
+                * at runtime
+                */
                return;
 
-       n = vsnprintf(buf, sizeof(buf) - 1, format, vl);
-       (void)n;
-       /* vnsprintf returns what it would have written, even if truncated */
-       if (n > (int)sizeof(buf) - 1) {
-               n = sizeof(buf) - 5;
-               buf[n++] = '.';
-               buf[n++] = '.';
-               buf[n++] = '.';
-               buf[n++] = '\n';
-               buf[n] = '\0';
+#if !defined(LWS_LOGS_TIMESTAMP)
+       if (cx->lll_flags & LLLF_LOG_TIMESTAMP)
+#endif
+       {
+               buf[0] = '\0';
+               lwsl_timestamp(filter, buf, sizeof(buf));
+               p += strlen(buf);
        }
-       if (n > 0)
-               buf[n] = '\0';
-       lwsl_emit(filter, buf);
+
+       /*
+        * prepend parent log ctx content first
+        * top level cx also gets an opportunity to prepend
+        */
+
+       while (cxp->parent) {
+               cxp = cxp->parent;
+               back++;
+       }
+
+       do {
+               int b = back;
+
+               cxp = cx;
+               while (b--)
+                       cxp = cxp->parent;
+               if (cxp->prepend)
+                       cxp->prepend(cxp, NULL, &p, end);
+
+               back--;
+       } while (back > 0);
+
+       if (prep)
+               prep(cxp, obj, &p, end);
+
+       if (_fun)
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s: ", _fun);
+
+       /*
+        * The actual log content
+        */
+
+       n = vsnprintf(p, lws_ptr_diff_size_t(end, p), format, vl);
+
+       /* vnsprintf returns what it would have written, even if truncated */
+       if (p + n > end - 2) {
+               p = end - 5;
+               *p++ = '.';
+               *p++ = '.';
+               *p++ = '.';
+               *p++ = '\n';
+               *p++ = '\0';
+       } else
+               if (n > 0) {
+                       p += n;
+                       if (p[-1] != '\n')
+                               *p++ = '\n';
+                       *p = '\0';
+               }
+
+       /*
+        * The actual emit
+        */
+
+       if (cx->lll_flags & LLLF_LOG_CONTEXT_AWARE)
+               cx->u.emit_cx(cx, filter, buf, lws_ptr_diff_size_t(p, buf));
+       else
+               cx->u.emit(filter, buf);
+}
+
+void _lws_logv(int filter, const char *format, va_list vl)
+{
+       __lws_logv(&log_cx, NULL, NULL, filter, NULL, format, vl);
 }
 
-LWS_VISIBLE void _lws_log(int filter, const char *format, ...)
+void _lws_log(int filter, const char *format, ...)
 {
        va_list ap;
 
        va_start(ap, format);
-       _lws_logv(filter, format, ap);
+       __lws_logv(&log_cx, NULL, NULL, filter, NULL, format, ap);
+       va_end(ap);
+}
+
+void _lws_log_cx(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
+                int filter, const char *_fun, const char *format, ...)
+{
+       va_list ap;
+
+       if (!cx)
+               cx = &log_cx;
+
+       va_start(ap, format);
+       __lws_logv(cx, prep, obj, filter, _fun, format, ap);
        va_end(ap);
 }
 #endif
-LWS_VISIBLE void lws_set_log_level(int level,
-                                  void (*func)(int level, const char *line))
+
+void
+lws_set_log_level(int flags, lws_log_emit_t func)
 {
-       log_level = level;
+       log_cx.lll_flags = (uint32_t)(flags & (~LLLF_LOG_CONTEXT_AWARE));
+
        if (func)
-               lwsl_emit = func;
+               log_cx.u.emit = func;
 }
 
-LWS_VISIBLE int lwsl_visible(int level)
+int lwsl_visible(int level)
 {
-       return log_level & level;
+       return !!(log_cx.lll_flags & (uint32_t)level);
 }
 
-LWS_VISIBLE void
-lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)
+int lwsl_visible_cx(lws_log_cx_t *cx, int level)
+{
+       return !!(cx->lll_flags & (uint32_t)level);
+}
+
+void
+lwsl_refcount_cx(lws_log_cx_t *cx, int _new)
+{
+       if (!cx)
+               return;
+
+       if (_new > 0)
+               cx->refcount++;
+       else {
+               assert(cx->refcount);
+               cx->refcount--;
+       }
+
+       if (cx->refcount_cb)
+               cx->refcount_cb(cx, _new);
+}
+
+void
+lwsl_hexdump_level_cx(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
+                     int hexdump_level, const void *vbuf, size_t len)
 {
        unsigned char *buf = (unsigned char *)vbuf;
        unsigned int n;
 
-       if (!lwsl_visible(hexdump_level))
+       if (!lwsl_visible_cx(cx, hexdump_level))
                return;
 
        if (!len) {
-               _lws_log(hexdump_level, "(hexdump: zero length)\n");
+               _lws_log_cx(cx, prep, obj, hexdump_level, NULL,
+                                       "(hexdump: zero length)\n");
                return;
        }
 
        if (!vbuf) {
-               _lws_log(hexdump_level, "(hexdump: trying to dump %d at NULL)\n",
-                                       (int)len);
+               _lws_log_cx(cx, prep, obj, hexdump_level, NULL,
+                                       "(hexdump: NULL ptr)\n");
                return;
        }
 
-       _lws_log(hexdump_level, "\n");
+       _lws_log_cx(cx, prep, obj, hexdump_level, NULL, "\n");
 
        for (n = 0; n < len;) {
                unsigned int start = n, m;
@@ -254,7 +559,7 @@ lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)
 
                for (m = 0; m < 16 && (start + m) < len; m++) {
                        if (buf[start + m] >= ' ' && buf[start + m] < 127)
-                               *p++ = buf[start + m];
+                               *p++ = (char)buf[start + m];
                        else
                                *p++ = '.';
                }
@@ -263,14 +568,20 @@ lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)
 
                *p++ = '\n';
                *p = '\0';
-               _lws_log(hexdump_level, "%s", line);
+               _lws_log_cx(cx, prep, obj, hexdump_level, NULL, "%s", line);
                (void)line;
        }
 
-       _lws_log(hexdump_level, "\n");
+       _lws_log_cx(cx, prep, obj, hexdump_level, NULL, "\n");
+}
+
+void
+lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)
+{
+       lwsl_hexdump_level_cx(&log_cx, NULL, NULL, hexdump_level, vbuf, len);
 }
 
-LWS_VISIBLE void
+void
 lwsl_hexdump(const void *vbuf, size_t len)
 {
 #if defined(_DEBUG)
diff --git a/lib/core/lws_dll.c b/lib/core/lws_dll.c
deleted file mode 100644 (file)
index bbb9c2b..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-#ifdef LWS_HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-
-void
-lws_dll_add_head(struct lws_dll *d, struct lws_dll *phead)
-{
-       if (!lws_dll_is_detached(d, phead)) {
-               assert(0); /* only wholly detached things can be added */
-               return;
-       }
-
-       /* our next guy is current first guy, if any */
-       if (phead->next != d)
-               d->next = phead->next;
-
-       /* if there is a next guy, set his prev ptr to our next ptr */
-       if (d->next)
-               d->next->prev = d;
-       /* there is nobody previous to us, we are the head */
-       d->prev = NULL;
-
-       /* set the first guy to be us */
-       phead->next = d;
-
-       /* if there was nothing on the list before, we are also now the tail */
-       if (!phead->prev)
-               phead->prev = d;
-
-       assert(d->prev != d);
-       assert(d->next != d);
-}
-
-void
-lws_dll_add_tail(struct lws_dll *d, struct lws_dll *phead)
-{
-       if (!lws_dll_is_detached(d, phead)) {
-               assert(0); /* only wholly detached things can be added */
-               return;
-       }
-
-       /* our previous guy is current last guy */
-       d->prev = phead->prev;
-       /* if there is a prev guy, set his next ptr to our prev ptr */
-       if (d->prev)
-               d->prev->next = d;
-       /* our next ptr is NULL */
-       d->next = NULL;
-       /* set the last guy to be us */
-       phead->prev = d;
-
-       /* list head is also us if we're the first */
-       if (!phead->next)
-               phead->next = d;
-
-       assert(d->prev != d);
-       assert(d->next != d);
-}
-
-void
-lws_dll_insert(struct lws_dll *n, struct lws_dll *target,
-              struct lws_dll *phead, int before)
-{
-       if (!lws_dll_is_detached(n, phead)) {
-               assert(0); /* only wholly detached things can be inserted */
-               return;
-       }
-       if (!target) {
-               /*
-                * the case where there's no target identified degenerates to
-                * a simple add at head or tail
-                */
-               if (before) {
-                       lws_dll_add_head(n, phead);
-                       return;
-               }
-               lws_dll_add_tail(n, phead);
-               return;
-       }
-
-       /*
-        * in the case there's a target "cursor", we have to do the work to
-        * stitch the new guy in appropriately
-        */
-
-       if (before) {
-               /*
-                *  we go before dd
-                *  DDp <-> DD <-> DDn   -->   DDp <-> us <-> DD <-> DDn
-                */
-               /* we point forward to dd */
-               n->next = target;
-               /* we point back to what dd used to point back to */
-               n->prev = target->prev;
-               /* DDp points forward to us now */
-               if (target->prev)
-                       target->prev->next = n;
-               /* DD points back to us now */
-               target->prev = n;
-
-               /* if target was the head, we are now the head */
-               if (phead->next == target)
-                       phead->next = n;
-
-               /* since we are before another guy, we cannot become the tail */
-
-       } else {
-               /*
-                *  we go after dd
-                *  DDp <-> DD <-> DDn   -->   DDp <-> DD <-> us <-> DDn
-                */
-               /* we point forward to what dd used to point forward to */
-               n->next = target->next;
-               /* we point back to dd */
-               n->prev = target;
-               /* DDn points back to us */
-               if (target->next)
-                       target->next->prev = n;
-               /* DD points forward to us */
-               target->next = n;
-
-               /* if target was the tail, we are now the tail */
-               if (phead->prev == target)
-                       phead->prev = n;
-
-               /* since we go after another guy, we cannot become the head */
-       }
-}
-
-/* situation is:
- *
- *  HEAD: struct lws_dll * = &entry1
- *
- *  Entry 1: struct lws_dll  .pprev = &HEAD , .next = Entry 2
- *  Entry 2: struct lws_dll  .pprev = &entry1 , .next = &entry2
- *  Entry 3: struct lws_dll  .pprev = &entry2 , .next = NULL
- *
- *  Delete Entry1:
- *
- *   - HEAD = &entry2
- *   - Entry2: .pprev = &HEAD, .next = &entry3
- *   - Entry3: .pprev = &entry2, .next = NULL
- *
- *  Delete Entry2:
- *
- *   - HEAD = &entry1
- *   - Entry1: .pprev = &HEAD, .next = &entry3
- *   - Entry3: .pprev = &entry1, .next = NULL
- *
- *  Delete Entry3:
- *
- *   - HEAD = &entry1
- *   - Entry1: .pprev = &HEAD, .next = &entry2
- *   - Entry2: .pprev = &entry1, .next = NULL
- *
- */
-
-void
-lws_dll_remove(struct lws_dll *d)
-{
-       if (!d->prev && !d->next)
-               return;
-
-       /*
-        *  remove us
-        *
-        *  USp <-> us <-> USn  -->  USp <-> USn
-        */
-
-       /* if we have a next guy, set his prev to our prev */
-       if (d->next)
-               d->next->prev = d->prev;
-
-       /* set our prev guy to our next guy instead of us */
-       if (d->prev)
-               d->prev->next = d->next;
-
-       /* we're out of the list, we should not point anywhere any more */
-       d->prev = NULL;
-       d->next = NULL;
-}
-
-void
-lws_dll_remove_track_tail(struct lws_dll *d, struct lws_dll *phead)
-{
-       if (lws_dll_is_detached(d, phead)) {
-               assert(phead->prev != d);
-               assert(phead->next != d);
-               return;
-       }
-
-       /* if we have a next guy, set his prev to our prev */
-       if (d->next)
-               d->next->prev = d->prev;
-
-       /* if we have a previous guy, set his next to our next */
-       if (d->prev)
-               d->prev->next = d->next;
-
-       if (phead->prev == d)
-               phead->prev = d->prev;
-
-       if (phead->next == d)
-               phead->next = d->next;
-
-       /* we're out of the list, we should not point anywhere any more */
-       d->prev = NULL;
-       d->next = NULL;
-}
-
-
-int
-lws_dll_foreach_safe(struct lws_dll *phead, void *user,
-                    int (*cb)(struct lws_dll *d, void *user))
-{
-       lws_start_foreach_dll_safe(struct lws_dll *, p, tp, phead->next) {
-               if (cb(p, user))
-                       return 1;
-       } lws_end_foreach_dll_safe(p, tp);
-
-       return 0;
-}
index f3b47f9..18888dd 100644 (file)
@@ -1,31 +1,59 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #ifdef LWS_HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
 
 int
+lws_dll2_is_detached(const struct lws_dll2 *d)
+{
+       if (d->owner)
+               return 0;
+
+       if (d->next || d->prev) {
+               lwsl_err("%s: dll2 %p: detached but next %p, prev %p\n",
+                               __func__, d, d->next, d->prev);
+               /*
+                * New lws_dll2 objects and removed lws_dll2 objects
+                * have .owner, .next and .prev all set to NULL, so we
+                * can just check .owner to see if we are detached.
+                *
+                * We assert here if we encounter an lws_dll2 in the illegal
+                * state of NULL .owner, but non-NULL in .next or .prev,
+                * it's evidence of corruption, use-after-free, threads
+                * contending on accessing without locking etc.
+                */
+               assert(0);
+       }
+
+       return 1;
+}
+
+int
 lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
                      int (*cb)(struct lws_dll2 *d, void *user))
 {
@@ -181,6 +209,31 @@ lws_dll2_owner_clear(struct lws_dll2_owner *d)
 }
 
 void
+lws_dll2_add_sorted_priv(lws_dll2_t *d, lws_dll2_owner_t *own, void *priv,
+                        int (*compare3)(void *priv, const lws_dll2_t *d,
+                                       const lws_dll2_t *i))
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
+                                  lws_dll2_get_head(own)) {
+               assert(p != d);
+
+               if (compare3(priv, p, d) >= 0) {
+                       /* drop us in before this guy */
+                       lws_dll2_add_before(d, p);
+
+                       return;
+               }
+       } lws_end_foreach_dll_safe(p, tp);
+
+       /*
+        * Either nobody on the list yet to compare him to, or he's the
+        * furthest away timeout... stick him at the tail end
+        */
+
+       lws_dll2_add_tail(d, own);
+}
+
+void
 lws_dll2_add_sorted(lws_dll2_t *d, lws_dll2_owner_t *own,
                    int (*compare)(const lws_dll2_t *d, const lws_dll2_t *i))
 {
@@ -192,8 +245,6 @@ lws_dll2_add_sorted(lws_dll2_t *d, lws_dll2_owner_t *own,
                        /* drop us in before this guy */
                        lws_dll2_add_before(d, p);
 
-                       // lws_dll2_describe(own, "post-insert");
-
                        return;
                }
        } lws_end_foreach_dll_safe(p, tp);
@@ -206,21 +257,42 @@ lws_dll2_add_sorted(lws_dll2_t *d, lws_dll2_owner_t *own,
        lws_dll2_add_tail(d, own);
 }
 
+void *
+_lws_dll2_search_sz_pl(lws_dll2_owner_t *own, const char *name, size_t namelen,
+                      size_t dll2_ofs, size_t ptr_ofs)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(own)) {
+               uint8_t *ref = ((uint8_t *)p) - dll2_ofs;
+               /*
+                * We have to read the const char * at the computed place and
+                * the string is where that points
+                */
+               const char *str = *((const char **)(ref + ptr_ofs));
+
+               if (str && !strncmp(str, name, namelen) && !str[namelen])
+                       return (void *)ref;
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
 #if defined(_DEBUG)
 
 void
 lws_dll2_describe(lws_dll2_owner_t *owner, const char *desc)
 {
+#if _LWS_ENABLED_LOGS & LLL_INFO
        int n = 1;
 
        lwsl_info("%s: %s: owner %p: count %d, head %p, tail %p\n",
-                   __func__, desc, owner, owner->count, owner->head, owner->tail);
+                   __func__, desc, owner, (int)owner->count, owner->head, owner->tail);
 
        lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
                                   lws_dll2_get_head(owner)) {
                lwsl_info("%s:    %d: %p: owner %p, prev %p, next %p\n",
                            __func__, n++, p, p->owner, p->prev, p->next);
        } lws_end_foreach_dll_safe(p, tp);
+#endif
 }
 
 #endif
diff --git a/lib/core/lws_map.c b/lib/core/lws_map.c
new file mode 100644 (file)
index 0000000..d149d86
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+typedef struct lws_map_hashtable {
+       struct lws_map                  *map_owner; /* so items can find map */
+       lws_dll2_owner_t                ho;
+} lws_map_hashtable_t;
+
+typedef struct lws_map {
+       lws_map_info_t                  info;
+
+       /* array of info.modulo x lws_map_hashtable_t overallocated */
+} lws_map_t;
+
+typedef struct lws_map_item {
+       lws_dll2_t                      list; /* owned by hashtable */
+
+       size_t                          keylen;
+       size_t                          valuelen;
+
+       /* key then value is overallocated */
+} lws_map_item_t;
+
+/*
+ * lwsac-aware allocator
+ */
+
+void *
+lws_map_alloc_lwsac(struct lws_map *map, size_t x)
+{
+       return lwsac_use((struct lwsac **)map->info.opaque, x,
+                                       (size_t)map->info.aux);
+}
+
+void
+lws_map_free_lwsac(void *v)
+{
+}
+
+/*
+ * Default allocation / free if none given in info
+ */
+
+void *
+lws_map_alloc_lws_malloc(struct lws_map *mo, size_t x)
+{
+       return lws_malloc(x, __func__);
+}
+
+void
+lws_map_free_lws_free(void *v)
+{
+       lws_free(v);
+}
+
+/*
+ * This just needs to approximate a flat distribution, it's not related to
+ * security at all.
+ */
+
+lws_map_hash_t
+lws_map_hash_from_key_default(const lws_map_key_t key, size_t kl)
+{
+       lws_map_hash_t h = 0x12345678;
+       const uint8_t *u = (const uint8_t *)key;
+
+       while (kl--)
+               h = ((((h << 7) | (h >> 25)) + 0xa1b2c3d4) ^ (*u++)) ^ h;
+
+       return h;
+}
+
+int
+lws_map_compare_key_default(const lws_map_key_t key1, size_t kl1,
+                           const lws_map_value_t key2, size_t kl2)
+{
+       if (kl1 != kl2)
+               return 1;
+
+       return memcmp(key1, key2, kl1);
+}
+
+lws_map_t *
+lws_map_create(const lws_map_info_t *info)
+{
+       lws_map_t *map;
+       lws_map_alloc_t a = info->_alloc;
+       size_t modulo = info->modulo;
+       lws_map_hashtable_t *ht;
+       size_t size;
+
+       if (!a)
+               a = lws_map_alloc_lws_malloc;
+
+       if (!modulo)
+               modulo = 8;
+
+       size = sizeof(*map) + (modulo * sizeof(lws_map_hashtable_t));
+       map = lws_malloc(size, __func__);
+       if (!map)
+               return NULL;
+
+       memset(map, 0, size);
+
+       map->info = *info;
+
+       map->info._alloc = a;
+       map->info.modulo = modulo;
+       if (!info->_free)
+               map->info._free = lws_map_free_lws_free;
+       if (!info->_hash)
+               map->info._hash = lws_map_hash_from_key_default;
+       if (!info->_compare)
+               map->info._compare = lws_map_compare_key_default;
+
+       ht = (lws_map_hashtable_t *)&map[1];
+       while (modulo--)
+               ht[modulo].map_owner = map;
+
+       return map;
+}
+
+static int
+ho_free_item(struct lws_dll2 *d, void *user)
+{
+       lws_map_item_t *i = lws_container_of(d, lws_map_item_t, list);
+
+       lws_map_item_destroy(i);
+
+       return 0;
+}
+
+void
+lws_map_destroy(lws_map_t **pmap)
+{
+       lws_map_hashtable_t *ht;
+       lws_map_t *map = *pmap;
+
+       if (!map)
+               return;
+
+       /* empty out all the hashtables */
+
+       ht = (lws_map_hashtable_t *)&(map[1]);
+       while (map->info.modulo--) {
+               lws_dll2_foreach_safe(&ht->ho, ht, ho_free_item);
+               ht++;
+       }
+
+       /* free the map itself */
+
+       lws_free_set_NULL(*pmap);
+}
+
+lws_map_item_t *
+lws_map_item_create(lws_map_t *map,
+                   const lws_map_key_t key, size_t keylen,
+                   const lws_map_value_t value, size_t valuelen)
+{
+       lws_map_hashtable_t *ht;
+       lws_map_item_t *item;
+       lws_map_hash_t h;
+       size_t hti;
+       uint8_t *u;
+
+       item = lws_map_item_lookup(map, key, keylen);
+       if (item)
+               lws_map_item_destroy(item);
+
+       item = map->info._alloc(map, sizeof(*item) + keylen + valuelen);
+       if (!item)
+               return NULL;
+
+       lws_dll2_clear(&item->list);
+       item->keylen = keylen;
+       item->valuelen = valuelen;
+
+       u = (uint8_t *)&item[1];
+       memcpy(u, key, keylen);
+       u += keylen;
+       if (value)
+               memcpy(u, value, valuelen);
+
+       h = map->info._hash(key, keylen);
+
+       hti = h % map->info.modulo;
+       ht = (lws_map_hashtable_t *)&map[1];
+
+       lws_dll2_add_head(&item->list, &ht[hti].ho);
+
+       return item;
+}
+
+void
+lws_map_item_destroy(lws_map_item_t *item)
+{
+       lws_map_hashtable_t *ht = lws_container_of(item->list.owner,
+                                                  lws_map_hashtable_t, ho);
+
+       lws_dll2_remove(&item->list);
+       ht->map_owner->info._free(item);
+}
+
+lws_map_item_t *
+lws_map_item_lookup(lws_map_t *map, const lws_map_key_t key, size_t keylen)
+{
+       lws_map_hash_t h = map->info._hash(key, keylen);
+       lws_map_hashtable_t *ht = (lws_map_hashtable_t *)&map[1];
+
+       lws_start_foreach_dll(struct lws_dll2 *, p,
+                             ht[h % map->info.modulo].ho.head) {
+               lws_map_item_t *i = lws_container_of(p, lws_map_item_t, list);
+
+               if (!map->info._compare(key, keylen, &i[1], i->keylen))
+                       return i;
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
+const void *
+lws_map_item_key(lws_map_item_t *_item)
+{
+       return ((void *)&_item[1]);
+}
+
+const void *
+lws_map_item_value(lws_map_item_t *_item)
+{
+       return (void *)(((uint8_t *)&_item[1]) + _item->keylen);
+}
+
+size_t
+lws_map_item_key_len(lws_map_item_t *_item)
+{
+       return _item->keylen;
+}
+
+size_t
+lws_map_item_value_len(lws_map_item_t *_item)
+{
+       return _item->valuelen;
+}
diff --git a/lib/core/private-lib-core.h b/lib/core/private-lib-core.h
new file mode 100644 (file)
index 0000000..8ba0852
--- /dev/null
@@ -0,0 +1,982 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(__LWS_PRIVATE_LIB_CORE_H__)
+#define __LWS_PRIVATE_LIB_CORE_H__
+
+#include "lws_config.h"
+#include "lws_config_private.h"
+
+
+#if defined(LWS_WITH_CGI) && defined(LWS_HAVE_VFORK) && \
+    !defined(NO_GNU_SOURCE_THIS_TIME) && !defined(_GNU_SOURCE)
+ #define  _GNU_SOURCE
+#endif
+
+/*
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#ifdef LWS_HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include <assert.h>
+
+#ifdef LWS_HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+#endif
+#if defined(LWS_HAVE_SYS_STAT_H) && !defined(LWS_PLAT_OPTEE)
+ #include <sys/stat.h>
+#endif
+
+#if LWS_MAX_SMP > 1 || defined(LWS_WITH_SYS_SMD)
+ /* https://stackoverflow.com/questions/33557506/timespec-redefinition-error */
+ #define HAVE_STRUCT_TIMESPEC
+ #include <pthread.h>
+#else
+ #if !defined(pid_t) && defined(WIN32)
+ #define pid_t int
+ #endif
+#endif
+
+#ifndef LWS_DEF_HEADER_LEN
+#define LWS_DEF_HEADER_LEN 4096
+#endif
+#ifndef LWS_DEF_HEADER_POOL
+#define LWS_DEF_HEADER_POOL 4
+#endif
+#ifndef LWS_MAX_PROTOCOLS
+#define LWS_MAX_PROTOCOLS 5
+#endif
+#ifndef LWS_MAX_EXTENSIONS_ACTIVE
+#define LWS_MAX_EXTENSIONS_ACTIVE 1
+#endif
+#ifndef LWS_MAX_EXT_OFFERS
+#define LWS_MAX_EXT_OFFERS 8
+#endif
+#ifndef SPEC_LATEST_SUPPORTED
+#define SPEC_LATEST_SUPPORTED 13
+#endif
+#ifndef CIPHERS_LIST_STRING
+#define CIPHERS_LIST_STRING "DEFAULT"
+#endif
+#ifndef LWS_SOMAXCONN
+#define LWS_SOMAXCONN SOMAXCONN
+#endif
+
+#define MAX_WEBSOCKET_04_KEY_LEN 128
+
+#ifndef SYSTEM_RANDOM_FILEPATH
+#define SYSTEM_RANDOM_FILEPATH "/dev/urandom"
+#endif
+
+#define LWS_H2_RX_SCRATCH_SIZE 512
+
+#define lws_socket_is_valid(x) (x != LWS_SOCK_INVALID)
+
+#ifndef LWS_HAVE_STRERROR
+ #define strerror(x) ""
+#endif
+
+ /*
+  *
+  *  ------ private platform defines ------
+  *
+  */
+
+#if defined(LWS_PLAT_FREERTOS)
+ #include "private-lib-plat-freertos.h"
+#else
+ #if defined(WIN32) || defined(_WIN32)
+  #include "private-lib-plat-windows.h"
+ #else
+  #if defined(LWS_PLAT_OPTEE)
+   #include "private-lib-plat.h"
+  #else
+   #include "private-lib-plat-unix.h"
+  #endif
+ #endif
+#endif
+
+ /*
+  *
+  *  ------ public api ------
+  *
+  */
+
+#include "libwebsockets.h"
+
+/*
+ * lws_dsh
+*/
+
+typedef struct lws_dsh_obj_head {
+       lws_dll2_owner_t                owner;
+       size_t                          total_size; /* for this kind in dsh */
+       int                             kind;
+} lws_dsh_obj_head_t;
+
+typedef struct lws_dsh_obj {
+       lws_dll2_t                      list;   /* must be first */
+       struct lws_dsh                  *dsh;   /* invalid when on free list */
+       size_t                          size;   /* invalid when on free list */
+       size_t                          asize;
+       int                             kind; /* so we can account at free */
+} lws_dsh_obj_t;
+
+typedef struct lws_dsh {
+       lws_dll2_t                      list;
+       uint8_t                         *buf;
+       lws_dsh_obj_head_t              *oha;   /* array of object heads/kind */
+       size_t                          buffer_size;
+       size_t                          locally_in_use;
+       size_t                          locally_free;
+       int                             count_kinds;
+       uint8_t                         being_destroyed;
+       /*
+        * Overallocations at create:
+        *
+        *  - the buffer itself
+        *  - the object heads array
+        */
+} lws_dsh_t;
+
+ /*
+  *
+  *  ------ lifecycle defines ------
+  *
+  */
+
+typedef struct lws_lifecycle_group {
+       lws_dll2_owner_t                owner; /* active count / list */
+       uint64_t                        ordinal; /* monotonic uid count */
+       const char                      *tag_prefix; /* eg, "wsi" */
+} lws_lifecycle_group_t;
+
+typedef struct lws_lifecycle {
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       /* we append parent streams on the tag */
+       char                            gutag[96]; /* object unique tag + relationship info */
+#else
+       char                            gutag[64];
+#endif
+       lws_dll2_t                      list; /* group list membership */
+       uint64_t                        us_creation; /* creation timestamp */
+       lws_log_cx_t                    *log_cx;
+} lws_lifecycle_t;
+
+void
+__lws_lc_tag(struct lws_context *cx, lws_lifecycle_group_t *grp,
+            lws_lifecycle_t *lc, const char *format, ...);
+
+void
+__lws_lc_tag_append(lws_lifecycle_t *lc, const char *app);
+
+void
+__lws_lc_untag(struct lws_context *cx, lws_lifecycle_t *lc);
+
+const char *
+lws_lc_tag(lws_lifecycle_t *lc);
+
+extern lws_log_cx_t log_cx;
+
+/*
+ * Generic bidi tx credit management
+ */
+
+struct lws_tx_credit {
+       int32_t                 tx_cr;          /* our credit to write peer */
+       int32_t                 peer_tx_cr_est; /* peer's credit to write us */
+
+       int32_t                 manual_initial_tx_credit;
+
+       uint8_t                 skint; /* unable to write anything */
+       uint8_t                 manual;
+};
+
+#ifdef LWS_WITH_IPV6
+#if defined(WIN32) || defined(_WIN32)
+#include <iphlpapi.h>
+#else
+#include <net/if.h>
+#endif
+#endif
+
+#undef X509_NAME
+
+/*
+ * All lws_tls...() functions must return this type, converting the
+ * native backend result and doing the extra work to determine which one
+ * as needed.
+ *
+ * Native TLS backend return codes are NOT ALLOWED outside the backend.
+ *
+ * Non-SSL mode also uses these types.
+ */
+enum lws_ssl_capable_status {
+       LWS_SSL_CAPABLE_ERROR                   = -1, /* it failed */
+       LWS_SSL_CAPABLE_DONE                    = 0,  /* it succeeded */
+       LWS_SSL_CAPABLE_MORE_SERVICE_READ       = -2, /* retry WANT_READ */
+       LWS_SSL_CAPABLE_MORE_SERVICE_WRITE      = -3, /* retry WANT_WRITE */
+       LWS_SSL_CAPABLE_MORE_SERVICE            = -4, /* general retry */
+};
+
+enum lws_context_destroy {
+       LWSCD_NO_DESTROY,               /* running */
+       LWSCD_PT_WAS_DEFERRED,          /* destroy from inside service */
+       LWSCD_PT_WAIT_ALL_DESTROYED,    /* libuv ends up here later */
+       LWSCD_FINALIZATION              /* the final destruction of context */
+};
+
+#if defined(LWS_WITH_TLS)
+#include "private-lib-tls.h"
+#endif
+
+#if defined(WIN32) || defined(_WIN32)
+        // Visual studio older than 2015 and WIN_CE has only _stricmp
+       #if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
+       #define strcasecmp _stricmp
+       #define strncasecmp _strnicmp
+       #elif !defined(__MINGW32__)
+       #define strcasecmp stricmp
+       #define strncasecmp strnicmp
+       #endif
+       #define getdtablesize() 30000
+#endif
+
+#ifndef LWS_ARRAY_SIZE
+#define LWS_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define lws_safe_modulo(_a, _b) ((_b) ? ((_a) % (_b)) : 0)
+
+#if defined(__clang__)
+#define lws_memory_barrier() __sync_synchronize()
+#elif defined(__GNUC__)
+#define lws_memory_barrier() __sync_synchronize()
+#else
+#define lws_memory_barrier()
+#endif
+
+
+struct lws_ring {
+       void *buf;
+       void (*destroy_element)(void *element);
+       uint32_t buflen;
+       uint32_t element_len;
+       uint32_t head;
+       uint32_t oldest_tail;
+};
+
+struct lws_protocols;
+struct lws;
+
+#if defined(LWS_WITH_NETWORK) /* network */
+#include "private-lib-event-libs.h"
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+#include "private-lib-secure-streams.h"
+#endif
+
+#if defined(LWS_WITH_SYS_SMD)
+#include "private-lib-system-smd.h"
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+#include "private-lib-system-fault-injection.h"
+#endif
+
+#include "private-lib-system-metrics.h"
+
+
+struct lws_foreign_thread_pollfd {
+       struct lws_foreign_thread_pollfd *next;
+       int fd_index;
+       int _and;
+       int _or;
+};
+#endif /* network */
+
+#if defined(LWS_WITH_NETWORK)
+#include "private-lib-core-net.h"
+#endif
+
+struct lws_system_blob {
+       union {
+               struct lws_buflist *bl;
+               struct {
+                       const uint8_t *ptr;
+                       size_t len;
+               } direct;
+       } u;
+       char    is_direct;
+};
+
+
+typedef struct lws_attach_item {
+       lws_dll2_t                      list;
+       lws_attach_cb_t                 cb;
+       void                            *opaque;
+       lws_system_states_t             state;
+} lws_attach_item_t;
+
+/*
+ * These are the context's lifecycle group indexes that exist in this build
+ * configuration.  If you add some, make sure to also add the tag_prefix in
+ * context.c context creation with matching preprocessor conditionals.
+ */
+
+enum {
+       LWSLCG_WSI,                     /* generic wsi, eg, pipe, listen */
+       LWSLCG_VHOST,
+
+       LWSLCG_WSI_SERVER,              /* server wsi */
+
+#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
+       LWSLCG_WSI_MUX,                 /* a mux child wsi */
+#endif
+
+#if defined(LWS_WITH_CLIENT)
+       LWSLCG_WSI_CLIENT,              /* client wsi */
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+#if defined(LWS_WITH_CLIENT)
+       LWSLCG_SS_CLIENT,               /* secstream client handle */
+#endif
+#if defined(LWS_WITH_SERVER)
+       LWSLCG_SS_SERVER,               /* secstream server handle */
+#endif
+#if defined(LWS_WITH_CLIENT)
+       LWSLCG_WSI_SS_CLIENT,           /* wsi bound to ss client handle */
+#endif
+#if defined(LWS_WITH_SERVER)
+       LWSLCG_WSI_SS_SERVER,           /* wsi bound to ss server handle */
+#endif
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+#if defined(LWS_WITH_CLIENT)
+       LWSLCG_SSP_CLIENT,              /* SSPC handle client connection to proxy */
+#endif
+#if defined(LWS_WITH_SERVER)
+       LWSLCG_SSP_ONWARD,              /* SS handle at proxy for onward conn */
+#endif
+#if defined(LWS_WITH_CLIENT)
+       LWSLCG_WSI_SSP_CLIENT,          /* wsi bound to SSPC cli conn to proxy */
+#endif
+#if defined(LWS_WITH_SERVER)
+       LWSLCG_WSI_SSP_ONWARD,          /* wsi bound to Proxy onward connection */
+#endif
+#endif
+
+       /* always last */
+       LWSLCG_COUNT
+};
+
+/*
+ * the rest is managed per-context, that includes
+ *
+ *  - processwide single fd -> wsi lookup
+ *  - contextwide headers pool
+ */
+
+struct lws_context {
+ #if defined(LWS_WITH_SERVER)
+       char canonical_hostname[96];
+ #endif
+
+#if defined(LWS_WITH_FILE_OPS)
+       struct lws_plat_file_ops fops_platform;
+#endif
+
+#if defined(LWS_WITH_ZIP_FOPS)
+       struct lws_plat_file_ops fops_zip;
+#endif
+
+       lws_system_blob_t system_blobs[LWS_SYSBLOB_TYPE_COUNT];
+
+#if defined(LWS_WITH_SYS_SMD)
+       lws_smd_t                               smd;
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS)
+       struct lws_ss_handle                    *ss_cpd;
+#endif
+       lws_sorted_usec_list_t                  sul_cpd_defer;
+
+#if defined(LWS_WITH_NETWORK)
+       struct lws_context_per_thread           pt[LWS_MAX_SMP];
+       lws_retry_bo_t                          default_retry;
+       lws_sorted_usec_list_t                  sul_system_state;
+
+       lws_lifecycle_group_t                   lcg[LWSLCG_COUNT];
+
+       const struct lws_protocols              *protocols_copy;
+
+#if defined(LWS_WITH_NETLINK)
+       lws_sorted_usec_list_t                  sul_nl_coldplug;
+       /* process can only have one netlink socket, have to do it in ctx */
+       lws_dll2_owner_t                        routing_table;
+       struct lws                              *netlink;
+#endif
+
+#if defined(LWS_PLAT_FREERTOS)
+       struct sockaddr_in                      frt_pipe_si;
+#endif
+
+#if defined(LWS_WITH_HTTP2)
+       struct http2_settings                   set;
+#endif
+
+#if LWS_MAX_SMP > 1
+       struct lws_mutex_refcount               mr;
+#endif
+
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_dll2_owner_t                        owner_mtr_dynpol;
+       /**< owner for lws_metric_policy_dyn_t (dynamic part of metric pols) */
+       lws_dll2_owner_t                        owner_mtr_no_pol;
+       /**< owner for lws_metric_pub_t with no policy to bind to */
+#endif
+
+#if defined(LWS_WITH_NETWORK)
+/*
+ * LWS_WITH_NETWORK =====>
+ */
+
+       lws_dll2_owner_t                owner_vh_being_destroyed;
+
+       lws_metric_t                    *mt_service; /* doing service */
+       const lws_metric_policy_t       *metrics_policies;
+       const char                      *metrics_prefix;
+
+#if defined(LWS_WITH_SYS_METRICS) && defined(LWS_WITH_CLIENT)
+       lws_metric_t                    *mt_conn_tcp; /* client tcp conns */
+       lws_metric_t                    *mt_conn_tls; /* client tcp conns */
+       lws_metric_t                    *mt_conn_dns; /* client dns external lookups */
+       lws_metric_t                    *mth_conn_failures; /* histogram of conn failure reasons */
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       lws_metric_t                    *mt_http_txn; /* client http transaction */
+#endif
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       lws_metric_t                    *mt_adns_cache; /* async dns lookup lat */
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS)
+       lws_metric_t                    *mth_ss_conn; /* SS connection outcomes */
+#endif
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       lws_metric_t                    *mt_ss_cliprox_conn; /* SS cli->prox conn */
+       lws_metric_t                    *mt_ss_cliprox_paylat; /* cli->prox payload latency */
+       lws_metric_t                    *mt_ss_proxcli_paylat; /* prox->cli payload latency */
+#endif
+#endif /* client */
+
+#if defined(LWS_WITH_SERVER)
+       lws_metric_t                    *mth_srv;
+#endif
+
+#if defined(LWS_WITH_EVENT_LIBS)
+       struct lws_plugin               *evlib_plugin_list;
+       void                            *evlib_ctx; /* overallocated */
+#endif
+
+#if defined(LWS_WITH_TLS)
+       struct lws_context_tls          tls;
+#if defined (LWS_WITH_TLS_JIT_TRUST)
+       lws_dll2_owner_t                jit_inflight;
+       /* ongoing sync or async jit trust lookups */
+       struct lws_cache_ttl_lru        *trust_cache;
+       /* caches host -> truncated trust SKID mappings */
+#endif
+#endif
+#if defined(LWS_WITH_DRIVERS)
+       lws_netdevs_t                   netdevs;
+#endif
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+       lws_async_dns_t                 async_dns;
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_ctx_t                    fic;
+       /**< Toplevel Fault Injection ctx */
+#endif
+
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
+       struct lws_cache_ttl_lru *l1, *nsc;
+#endif
+
+#if defined(LWS_WITH_SYS_NTPCLIENT)
+       void                            *ntpclient_priv;
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       struct lws_ss_handle            *hss_fetch_policy;
+#if defined(LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM)
+       struct lws_ss_handle            *hss_auth;
+       lws_sorted_usec_list_t          sul_api_amazon_com;
+       lws_sorted_usec_list_t          sul_api_amazon_com_kick;
+#endif
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       struct lws_ss_x509              *server_der_list;
+#endif
+#endif
+
+#if defined(LWS_WITH_SYS_STATE)
+       lws_state_manager_t             mgr_system;
+       lws_state_notify_link_t         protocols_notify;
+#endif
+#if defined (LWS_WITH_SYS_DHCP_CLIENT)
+       lws_dll2_owner_t                dhcpc_owner;
+                                       /**< list of ifaces with dhcpc */
+#endif
+
+       /* pointers */
+
+       struct lws_vhost                *vhost_list;
+       struct lws_vhost                *no_listener_vhost_list;
+       struct lws_vhost                *vhost_pending_destruction_list;
+       struct lws_vhost                *vhost_system;
+
+#if defined(LWS_WITH_SERVER)
+       const char                      *server_string;
+#endif
+
+       const struct lws_event_loop_ops *event_loop_ops;
+#endif
+
+#if defined(LWS_WITH_TLS)
+       const struct lws_tls_ops        *tls_ops;
+#endif
+
+#if defined(LWS_WITH_PLUGINS)
+       struct lws_plugin               *plugin_list;
+#endif
+#ifdef _WIN32
+/* different implementation between unix and windows */
+       struct lws_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS];
+#else
+       struct lws **lws_lookup;
+
+#endif
+
+/*
+ * <====== LWS_WITH_NETWORK end
+ */
+
+#endif /* NETWORK */
+
+       lws_log_cx_t                    *log_cx;
+       const char                      *name;
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       const char      *ss_proxy_bind;
+       const char      *ss_proxy_address;
+#endif
+
+#if defined(LWS_WITH_FILE_OPS)
+       const struct lws_plat_file_ops *fops;
+#endif
+
+       struct lws_context **pcontext_finalize;
+#if !defined(LWS_PLAT_FREERTOS)
+       const char *username, *groupname;
+#endif
+
+#if defined(LWS_WITH_MBEDTLS)
+       mbedtls_entropy_context mec;
+       mbedtls_ctr_drbg_context mcdc;
+#endif
+
+#if defined(LWS_WITH_THREADPOOL)
+       struct lws_threadpool *tp_list_head;
+#endif
+
+#if defined(LWS_WITH_PEER_LIMITS)
+       struct lws_peer                 **pl_hash_table;
+       struct lws_peer                 *peer_wait_list;
+       lws_peer_limits_notify_t        pl_notify_cb;
+       time_t                          next_cull;
+#endif
+
+       const lws_system_ops_t          *system_ops;
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       const char                      *pss_policies_json;
+       struct lwsac                    *ac_policy;
+       void                            *pol_args;
+#endif
+       const lws_ss_policy_t           *pss_policies;
+       const lws_ss_auth_t             *pss_auths;
+#if defined(LWS_WITH_SSPLUGINS)
+       const lws_ss_plugin_t           **pss_plugins;
+#endif
+#endif
+
+       void *external_baggage_free_on_destroy;
+       const struct lws_token_limits *token_limits;
+       void *user_space;
+#if defined(LWS_WITH_SERVER)
+       const struct lws_protocol_vhost_options *reject_service_keywords;
+       lws_reload_func deprecation_cb;
+#endif
+#if !defined(LWS_PLAT_FREERTOS)
+       void (*eventlib_signal_cb)(void *event_lib_handle, int signum);
+#endif
+
+#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
+       cap_value_t caps[4];
+       char count_caps;
+#endif
+
+       lws_usec_t time_up; /* monotonic */
+#if defined(LWS_WITH_SYS_SMD)
+       lws_usec_t smd_ttl_us;
+#endif
+       uint64_t options;
+
+       time_t last_ws_ping_pong_check_s;
+#if defined(LWS_WITH_SECURE_STREAMS)
+       time_t                                  last_policy;
+#endif
+
+#if defined(LWS_PLAT_FREERTOS)
+       unsigned long time_last_state_dump;
+       uint32_t last_free_heap;
+#endif
+
+       unsigned int max_fds;
+#if !defined(LWS_NO_DAEMONIZE)
+       pid_t started_with_parent;
+#endif
+
+#if !defined(LWS_PLAT_FREERTOS)
+       uid_t uid;
+       gid_t gid;
+       int fd_random;
+       int count_cgi_spawned;
+#endif
+
+       unsigned int fd_limit_per_thread;
+       unsigned int timeout_secs;
+       unsigned int pt_serv_buf_size;
+       unsigned int max_http_header_data;
+       unsigned int max_http_header_pool;
+       int simultaneous_ssl_restriction;
+       int simultaneous_ssl;
+       int simultaneous_ssl_handshake_restriction;
+       int simultaneous_ssl_handshake;
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       int             vh_idle_grace_ms;
+#endif
+#if defined(LWS_WITH_PEER_LIMITS)
+       uint32_t pl_hash_elements;      /* protected by context->lock */
+       uint32_t count_peers;           /* protected by context->lock */
+       unsigned short ip_limit_ah;
+       unsigned short ip_limit_wsi;
+#endif
+
+#if defined(LWS_WITH_SYS_SMD)
+       uint16_t smd_queue_depth;
+#endif
+
+#if defined(LWS_WITH_NETLINK)
+       lws_route_uidx_t                        route_uidx;
+#endif
+
+       char            tls_gate_accepts;
+
+       unsigned int deprecated:1;
+       unsigned int inside_context_destroy:1;
+       unsigned int being_destroyed:1;
+       unsigned int service_no_longer_possible:1;
+       unsigned int being_destroyed2:1;
+       unsigned int requested_stop_internal_loops:1;
+       unsigned int protocol_init_done:1;
+       unsigned int doing_protocol_init:1;
+       unsigned int done_protocol_destroy_cb:1;
+       unsigned int evlib_finalize_destroy_after_int_loops_stop:1;
+       unsigned int max_fds_unrelated_to_ulimit:1;
+       unsigned int policy_updated:1;
+#if defined(LWS_WITH_NETLINK)
+       unsigned int nl_initial_done:1;
+#endif
+
+       unsigned short count_threads;
+       unsigned short undestroyed_threads;
+       short plugin_protocol_count;
+       short plugin_extension_count;
+       short server_string_len;
+       unsigned short deprecation_pending_listen_close_count;
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       uint16_t        ss_proxy_port;
+#endif
+       /* 0 if not known, else us resolution of the poll wait */
+       uint16_t us_wait_resolution;
+
+       uint8_t max_fi;
+       uint8_t captive_portal_detect;
+       uint8_t captive_portal_detect_type;
+
+       uint8_t         destroy_state; /* enum lws_context_destroy */
+};
+
+#define lws_get_context_protocol(ctx, x) ctx->vhost_list->protocols[x]
+#define lws_get_vh_protocol(vh, x) vh->protocols[x]
+
+int
+lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);
+
+void
+lws_vhost_destroy1(struct lws_vhost *vh);
+
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
+int
+lws_parse_set_cookie(struct lws *wsi);
+
+int
+lws_cookie_send_cookies(struct lws *wsi, char **pp, char *end);
+#endif
+
+#if defined(LWS_PLAT_FREERTOS)
+int
+lws_find_string_in_file(const char *filename, const char *str, int stringlen);
+#endif
+
+signed char char_to_hex(const char c);
+
+#if defined(LWS_WITH_NETWORK)
+int
+lws_system_do_attach(struct lws_context_per_thread *pt);
+#endif
+
+struct lws_buflist {
+       struct lws_buflist *next;
+       size_t len;
+       size_t pos;
+};
+
+char *
+lws_strdup(const char *s);
+
+int
+lws_b64_selftest(void);
+
+
+#ifndef LWS_NO_DAEMONIZE
+ pid_t get_daemonize_pid();
+#else
+ #define get_daemonize_pid() (0)
+#endif
+
+void lwsl_emit_stderr(int level, const char *line);
+
+#if !defined(LWS_WITH_TLS)
+ #define LWS_SSL_ENABLED(context) (0)
+ #define lws_context_init_server_ssl(_a, _b) (0)
+ #define lws_ssl_destroy(_a)
+ #define lws_context_init_alpn(_a)
+ #define lws_ssl_capable_read lws_ssl_capable_read_no_ssl
+ #define lws_ssl_capable_write lws_ssl_capable_write_no_ssl
+ #define lws_ssl_pending lws_ssl_pending_no_ssl
+ #define lws_server_socket_service_ssl(_b, _c, _d) (0)
+ #define lws_ssl_close(_a) (0)
+ #define lws_ssl_context_destroy(_a)
+ #define lws_ssl_SSL_CTX_destroy(_a)
+ #define lws_ssl_remove_wsi_from_buffered_list(_a)
+ #define __lws_ssl_remove_wsi_from_buffered_list(_a)
+ #define lws_context_init_ssl_library(_a, _b)
+ #define lws_context_deinit_ssl_library(_a)
+ #define lws_tls_check_all_cert_lifetimes(_a)
+ #define lws_tls_acme_sni_cert_destroy(_a)
+#endif
+
+
+
+#if LWS_MAX_SMP > 1
+#define lws_context_lock(c, reason) lws_mutex_refcount_lock(&c->mr, reason)
+#define lws_context_unlock(c) lws_mutex_refcount_unlock(&c->mr)
+#define lws_context_assert_lock_held(c) lws_mutex_refcount_assert_held(&c->mr)
+#define lws_vhost_assert_lock_held(v) lws_mutex_refcount_assert_held(&v->mr)
+/* enforce context lock held */
+#define lws_vhost_lock(v) lws_mutex_refcount_lock(&v->mr, __func__)
+#define lws_vhost_unlock(v) lws_mutex_refcount_unlock(&v->mr)
+
+
+#else
+#define lws_pt_mutex_init(_a) (void)(_a)
+#define lws_pt_mutex_destroy(_a) (void)(_a)
+#define lws_pt_lock(_a, b) (void)(_a)
+#define lws_pt_assert_lock_held(_a) (void)(_a)
+#define lws_pt_unlock(_a) (void)(_a)
+#define lws_context_lock(_a, _b) (void)(_a)
+#define lws_context_unlock(_a) (void)(_a)
+#define lws_context_assert_lock_held(_a) (void)(_a)
+#define lws_vhost_assert_lock_held(_a) (void)(_a)
+#define lws_vhost_lock(_a) (void)(_a)
+#define lws_vhost_unlock(_a) (void)(_a)
+#define lws_pt_stats_lock(_a) (void)(_a)
+#define lws_pt_stats_unlock(_a) (void)(_a)
+#endif
+
+int LWS_WARN_UNUSED_RESULT
+lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, size_t len);
+
+int LWS_WARN_UNUSED_RESULT
+lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, size_t len);
+
+int LWS_WARN_UNUSED_RESULT
+lws_ssl_pending_no_ssl(struct lws *wsi);
+
+int
+lws_tls_check_cert_lifetime(struct lws_vhost *vhost);
+
+int lws_jws_selftest(void);
+int lws_jwe_selftest(void);
+
+int
+lws_protocol_init(struct lws_context *context);
+
+int
+lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
+                 const char *reason);
+
+const struct lws_protocol_vhost_options *
+lws_vhost_protocol_options(struct lws_vhost *vh, const char *name);
+
+const struct lws_http_mount *
+lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len);
+
+#ifdef LWS_WITH_HTTP2
+int lws_wsi_is_h2(struct lws *wsi);
+#endif
+/*
+ * custom allocator
+ */
+void *
+lws_realloc(void *ptr, size_t size, const char *reason);
+
+void * LWS_WARN_UNUSED_RESULT
+lws_zalloc(size_t size, const char *reason);
+
+#ifdef LWS_PLAT_OPTEE
+void *lws_malloc(size_t size, const char *reason);
+void lws_free(void *p);
+#define lws_free_set_NULL(P)    do { lws_free(P); (P) = NULL; } while(0)
+#else
+#define lws_malloc(S, R)       lws_realloc(NULL, S, R)
+#define lws_free(P)    lws_realloc(P, 0, "lws_free")
+#define lws_free_set_NULL(P)   do { lws_realloc(P, 0, "free"); (P) = NULL; } while(0)
+#endif
+
+int
+__lws_create_event_pipes(struct lws_context *context);
+
+int
+lws_plat_apply_FD_CLOEXEC(int n);
+
+const struct lws_plat_file_ops *
+lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
+                   const char **vpath);
+
+/* lws_plat_ */
+
+int
+lws_plat_context_early_init(void);
+void
+lws_plat_context_early_destroy(struct lws_context *context);
+void
+lws_plat_context_late_destroy(struct lws_context *context);
+
+int
+lws_plat_init(struct lws_context *context,
+             const struct lws_context_creation_info *info);
+int
+lws_plat_drop_app_privileges(struct lws_context *context, int actually_drop);
+
+#if defined(LWS_WITH_UNIX_SOCK) && !defined(WIN32)
+int
+lws_plat_user_colon_group_to_ids(const char *u_colon_g, uid_t *puid, gid_t *pgid);
+#endif
+
+int
+lws_plat_ntpclient_config(struct lws_context *context);
+
+int
+lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len);
+
+int
+lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost);
+
+int
+lws_check_byte_utf8(unsigned char state, unsigned char c);
+int LWS_WARN_UNUSED_RESULT
+lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len);
+int alloc_file(struct lws_context *context, const char *filename,
+                         uint8_t **buf, lws_filepos_t *amount);
+
+int
+lws_lec_scratch(lws_lec_pctx_t *ctx);
+void
+lws_lec_signed(lws_lec_pctx_t *ctx, int64_t num);
+
+int
+lws_cose_key_checks(const lws_cose_key_t *key, int64_t kty, int64_t alg,
+                   int key_op, const char *crv);
+
+void lws_msleep(unsigned int);
+
+void
+lws_context_destroy2(struct lws_context *context);
+
+#if !defined(PRIu64)
+#define PRIu64 "llu"
+#endif
+
+#if defined(LWS_WITH_ABSTRACT)
+#include "private-lib-abstract.h"
+#endif
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/lib/core/private.h b/lib/core/private.h
deleted file mode 100644 (file)
index 4e03929..0000000
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "lws_config.h"
-#include "lws_config_private.h"
-
-#if defined(LWS_WITH_CGI) && defined(LWS_HAVE_VFORK) && \
-    !defined(NO_GNU_SOURCE_THIS_TIME)
- #define  _GNU_SOURCE
-#endif
-
-/*
-#if !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 200112L
-#endif
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <ctype.h>
-#include <limits.h>
-#include <stdarg.h>
-
-#ifdef LWS_HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-
-#include <assert.h>
-
-#ifdef LWS_HAVE_SYS_TYPES_H
- #include <sys/types.h>
-#endif
-#if defined(LWS_HAVE_SYS_STAT_H) && !defined(LWS_PLAT_OPTEE)
- #include <sys/stat.h>
-#endif
-
-#if LWS_MAX_SMP > 1
- #include <pthread.h>
-#endif
-
-#ifndef LWS_DEF_HEADER_LEN
-#define LWS_DEF_HEADER_LEN 4096
-#endif
-#ifndef LWS_DEF_HEADER_POOL
-#define LWS_DEF_HEADER_POOL 4
-#endif
-#ifndef LWS_MAX_PROTOCOLS
-#define LWS_MAX_PROTOCOLS 5
-#endif
-#ifndef LWS_MAX_EXTENSIONS_ACTIVE
-#define LWS_MAX_EXTENSIONS_ACTIVE 1
-#endif
-#ifndef LWS_MAX_EXT_OFFERS
-#define LWS_MAX_EXT_OFFERS 8
-#endif
-#ifndef SPEC_LATEST_SUPPORTED
-#define SPEC_LATEST_SUPPORTED 13
-#endif
-#ifndef AWAITING_TIMEOUT
-#define AWAITING_TIMEOUT 20
-#endif
-#ifndef CIPHERS_LIST_STRING
-#define CIPHERS_LIST_STRING "DEFAULT"
-#endif
-#ifndef LWS_SOMAXCONN
-#define LWS_SOMAXCONN SOMAXCONN
-#endif
-
-#define MAX_WEBSOCKET_04_KEY_LEN 128
-
-#ifndef SYSTEM_RANDOM_FILEPATH
-#define SYSTEM_RANDOM_FILEPATH "/dev/urandom"
-#endif
-
-#define LWS_H2_RX_SCRATCH_SIZE 512
-
-#define lws_socket_is_valid(x) (x != LWS_SOCK_INVALID)
-
-#ifndef LWS_HAVE_STRERROR
- #define strerror(x) ""
-#endif
-
-
- /*
-  *
-  *  ------ private platform defines ------
-  *
-  */
-
-#if defined(LWS_WITH_ESP32)
- #include "plat/esp32/private.h"
-#else
- #if defined(WIN32) || defined(_WIN32)
-  #include "plat/windows/private.h"
- #else
-  #if defined(LWS_PLAT_OPTEE)
-   #include "plat/optee/private.h"
-  #else
-   #include "plat/unix/private.h"
-  #endif
- #endif
-#endif
-
- /*
-  *
-  *  ------ public api ------
-  *
-  */
-
-#include "libwebsockets.h"
-
-#include "tls/private.h"
-
-#if defined(WIN32) || defined(_WIN32)
-        // Visual studio older than 2015 and WIN_CE has only _stricmp
-       #if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
-       #define strcasecmp _stricmp
-       #define strncasecmp _strnicmp
-       #elif !defined(__MINGW32__)
-       #define strcasecmp stricmp
-       #define strncasecmp strnicmp
-       #endif
-       #define getdtablesize() 30000
-#endif
-
-#ifndef LWS_ARRAY_SIZE
-#define LWS_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-
-#if defined(__clang__)
-#define lws_memory_barrier() __sync_synchronize()
-#elif defined(__GNUC__)
-#define lws_memory_barrier() __sync_synchronize()
-#else
-#define lws_memory_barrier()
-#endif
-
-
-struct lws_ring {
-       void *buf;
-       void (*destroy_element)(void *element);
-       uint32_t buflen;
-       uint32_t element_len;
-       uint32_t head;
-       uint32_t oldest_tail;
-};
-
-struct lws_protocols;
-struct lws;
-
-#if defined(LWS_WITH_NETWORK)
-#include "event-libs/private.h"
-
-
-struct lws_io_watcher {
-#ifdef LWS_WITH_LIBEV
-       struct lws_io_watcher_libev ev;
-#endif
-#ifdef LWS_WITH_LIBUV
-       struct lws_io_watcher_libuv uv;
-#endif
-#ifdef LWS_WITH_LIBEVENT
-       struct lws_io_watcher_libevent event;
-#endif
-       struct lws_context *context;
-
-       uint8_t actual_events;
-};
-
-struct lws_signal_watcher {
-#ifdef LWS_WITH_LIBEV
-       struct lws_signal_watcher_libev ev;
-#endif
-#ifdef LWS_WITH_LIBUV
-       struct lws_signal_watcher_libuv uv;
-#endif
-#ifdef LWS_WITH_LIBEVENT
-       struct lws_signal_watcher_libevent event;
-#endif
-       struct lws_context *context;
-};
-
-struct lws_foreign_thread_pollfd {
-       struct lws_foreign_thread_pollfd *next;
-       int fd_index;
-       int _and;
-       int _or;
-};
-#endif
-
-#if LWS_MAX_SMP > 1
-
-struct lws_mutex_refcount {
-       pthread_mutex_t lock;
-       pthread_t lock_owner;
-       const char *last_lock_reason;
-       char lock_depth;
-       char metadata;
-};
-
-void
-lws_mutex_refcount_init(struct lws_mutex_refcount *mr);
-
-void
-lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr);
-
-void
-lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason);
-
-void
-lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr);
-#endif
-
-#if defined(LWS_WITH_NETWORK)
-#include "core-net/private.h"
-#endif
-
-struct lws_deferred_free
-{
-       struct lws_deferred_free *next;
-       time_t deadline;
-       void *payload;
-};
-
-/*
- * the rest is managed per-context, that includes
- *
- *  - processwide single fd -> wsi lookup
- *  - contextwide headers pool
- */
-
-struct lws_context {
-       time_t last_ws_ping_pong_check_s;
-       lws_usec_t time_up; /* monotonic */
-       const struct lws_plat_file_ops *fops;
-       struct lws_plat_file_ops fops_platform;
-       struct lws_context **pcontext_finalize;
-
-       const struct lws_tls_ops *tls_ops;
-
-       const char *username, *groupname;
-
-#if defined(LWS_WITH_HTTP2)
-       struct http2_settings set;
-#endif
-#if defined(LWS_WITH_ZIP_FOPS)
-       struct lws_plat_file_ops fops_zip;
-#endif
-#if defined(LWS_WITH_NETWORK)
-       struct lws_context_per_thread pt[LWS_MAX_SMP];
-       struct lws_conn_stats conn_stats;
-       struct lws_vhost *vhost_list;
-       struct lws_vhost *no_listener_vhost_list;
-       struct lws_vhost *vhost_pending_destruction_list;
-       struct lws_plugin *plugin_list;
-#ifdef _WIN32
-/* different implementation between unix and windows */
-       struct lws_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS];
-#else
-       struct lws **lws_lookup;
-
-#endif
-#endif
-#if LWS_MAX_SMP > 1
-       struct lws_mutex_refcount mr;
-#endif
-
-#if defined(LWS_AMAZON_RTOS)
-       mbedtls_entropy_context mec;
-       mbedtls_ctr_drbg_context mcdc;
-#endif
-
-       struct lws_deferred_free *deferred_free_list;
-
-#if defined(LWS_WITH_THREADPOOL)
-       struct lws_threadpool *tp_list_head;
-#endif
-
-#if defined(LWS_WITH_PEER_LIMITS)
-       struct lws_peer **pl_hash_table;
-       struct lws_peer *peer_wait_list;
-       time_t next_cull;
-#endif
-
-       const lws_system_ops_t *system_ops;
-       void *external_baggage_free_on_destroy;
-       const struct lws_token_limits *token_limits;
-       void *user_space;
-       const struct lws_protocol_vhost_options *reject_service_keywords;
-       lws_reload_func deprecation_cb;
-       void (*eventlib_signal_cb)(void *event_lib_handle, int signum);
-
-#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
-       cap_value_t caps[4];
-       char count_caps;
-#endif
-
-#if defined(LWS_WITH_NETWORK)
-#if defined(LWS_WITH_LIBEV)
-       struct lws_context_eventlibs_libev ev;
-#endif
-#if defined(LWS_WITH_LIBUV)
-       struct lws_context_eventlibs_libuv uv;
-#endif
-#if defined(LWS_WITH_LIBEVENT)
-       struct lws_context_eventlibs_libevent event;
-#endif
-       struct lws_event_loop_ops *event_loop_ops;
-#endif
-
-#if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
-       struct lws_context_tls tls;
-#endif
-
-       char canonical_hostname[128];
-       const char *server_string;
-
-#ifdef LWS_LATENCY
-       unsigned long worst_latency;
-       char worst_latency_info[256];
-#endif
-
-#if defined(LWS_WITH_ESP32)
-       unsigned long time_last_state_dump;
-       uint32_t last_free_heap;
-#endif
-
-       int max_fds;
-       int count_event_loop_static_asset_handles;
-#if !defined(LWS_NO_DAEMONIZE)
-       pid_t started_with_parent;
-#endif
-       int uid, gid;
-
-       int fd_random;
-
-       int count_wsi_allocated;
-       int count_cgi_spawned;
-       unsigned int options;
-       unsigned int fd_limit_per_thread;
-       unsigned int timeout_secs;
-       unsigned int pt_serv_buf_size;
-       int max_http_header_data;
-       int max_http_header_pool;
-       int simultaneous_ssl_restriction;
-       int simultaneous_ssl;
-#if defined(LWS_WITH_PEER_LIMITS)
-       uint32_t pl_hash_elements;      /* protected by context->lock */
-       uint32_t count_peers;           /* protected by context->lock */
-       unsigned short ip_limit_ah;
-       unsigned short ip_limit_wsi;
-#endif
-       unsigned int deprecated:1;
-       unsigned int being_destroyed:1;
-       unsigned int being_destroyed1:1;
-       unsigned int being_destroyed2:1;
-       unsigned int requested_kill:1;
-       unsigned int protocol_init_done:1;
-       unsigned int doing_protocol_init:1;
-       unsigned int done_protocol_destroy_cb:1;
-       unsigned int finalize_destroy_after_internal_loops_stopped:1;
-       unsigned int max_fds_unrelated_to_ulimit:1;
-
-       short count_threads;
-       short plugin_protocol_count;
-       short plugin_extension_count;
-       short server_string_len;
-       unsigned short ws_ping_pong_interval;
-       unsigned short deprecation_pending_listen_close_count;
-
-       uint8_t max_fi;
-
-#if defined(LWS_WITH_STATS)
-       uint8_t updated;
-#endif
-};
-
-int
-lws_check_deferred_free(struct lws_context *context, int tsi, int force);
-
-#define lws_get_context_protocol(ctx, x) ctx->vhost_list->protocols[x]
-#define lws_get_vh_protocol(vh, x) vh->protocols[x]
-
-int
-lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);
-
-void
-lws_vhost_destroy1(struct lws_vhost *vh);
-
-
-#if defined(LWS_WITH_ESP32)
-LWS_EXTERN int
-lws_find_string_in_file(const char *filename, const char *str, int stringlen);
-#endif
-
-
-signed char char_to_hex(const char c);
-
-
-struct lws_buflist {
-       struct lws_buflist *next;
-
-       size_t len;
-       size_t pos;
-
-       uint8_t buf[1]; /* true length of this is set by the oversize malloc */
-};
-
-
-LWS_EXTERN char *
-lws_strdup(const char *s);
-
-LWS_EXTERN int log_level;
-
-
-
-#ifndef LWS_LATENCY
-static LWS_INLINE void
-lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
-           int ret, int completion) {
-       do {
-               (void)context; (void)wsi; (void)action; (void)ret;
-               (void)completion;
-       } while (0);
-}
-static LWS_INLINE void
-lws_latency_pre(struct lws_context *context, struct lws *wsi) {
-       do { (void)context; (void)wsi; } while (0);
-}
-#else
-#define lws_latency_pre(_context, _wsi) lws_latency(_context, _wsi, NULL, 0, 0)
-extern void
-lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
-           int ret, int completion);
-#endif
-
-
-LWS_EXTERN int
-lws_b64_selftest(void);
-
-
-
-
-
-#ifndef LWS_NO_DAEMONIZE
- LWS_EXTERN pid_t get_daemonize_pid();
-#else
- #define get_daemonize_pid() (0)
-#endif
-
-LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
-
-#if !defined(LWS_WITH_TLS)
- #define LWS_SSL_ENABLED(context) (0)
- #define lws_context_init_server_ssl(_a, _b) (0)
- #define lws_ssl_destroy(_a)
- #define lws_context_init_alpn(_a)
- #define lws_ssl_capable_read lws_ssl_capable_read_no_ssl
- #define lws_ssl_capable_write lws_ssl_capable_write_no_ssl
- #define lws_ssl_pending lws_ssl_pending_no_ssl
- #define lws_server_socket_service_ssl(_b, _c) (0)
- #define lws_ssl_close(_a) (0)
- #define lws_ssl_context_destroy(_a)
- #define lws_ssl_SSL_CTX_destroy(_a)
- #define lws_ssl_remove_wsi_from_buffered_list(_a)
- #define __lws_ssl_remove_wsi_from_buffered_list(_a)
- #define lws_context_init_ssl_library(_a)
- #define lws_context_deinit_ssl_library(_a)
- #define lws_tls_check_all_cert_lifetimes(_a)
- #define lws_tls_acme_sni_cert_destroy(_a)
-#endif
-
-
-
-#if LWS_MAX_SMP > 1
-#define lws_context_lock(c, reason) lws_mutex_refcount_lock(&c->mr, reason)
-#define lws_context_unlock(c) lws_mutex_refcount_unlock(&c->mr)
-
-static LWS_INLINE void
-lws_vhost_lock(struct lws_vhost *vhost)
-{
-       pthread_mutex_lock(&vhost->lock);
-}
-
-static LWS_INLINE void
-lws_vhost_unlock(struct lws_vhost *vhost)
-{
-       pthread_mutex_unlock(&vhost->lock);
-}
-
-
-#else
-#define lws_pt_mutex_init(_a) (void)(_a)
-#define lws_pt_mutex_destroy(_a) (void)(_a)
-#define lws_pt_lock(_a, b) (void)(_a)
-#define lws_pt_unlock(_a) (void)(_a)
-#define lws_context_lock(_a, _b) (void)(_a)
-#define lws_context_unlock(_a) (void)(_a)
-#define lws_vhost_lock(_a) (void)(_a)
-#define lws_vhost_unlock(_a) (void)(_a)
-#define lws_pt_stats_lock(_a) (void)(_a)
-#define lws_pt_stats_unlock(_a) (void)(_a)
-#endif
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ssl_pending_no_ssl(struct lws *wsi);
-
-int
-lws_tls_check_cert_lifetime(struct lws_vhost *vhost);
-
-int lws_jws_selftest(void);
-int lws_jwe_selftest(void);
-
-int
-lws_protocol_init(struct lws_context *context);
-
-int
-lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
-                 const char *reason);
-
-const struct lws_protocol_vhost_options *
-lws_vhost_protocol_options(struct lws_vhost *vh, const char *name);
-
-const struct lws_http_mount *
-lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len);
-
-/*
- * custom allocator
- */
-LWS_EXTERN void *
-lws_realloc(void *ptr, size_t size, const char *reason);
-
-LWS_EXTERN void * LWS_WARN_UNUSED_RESULT
-lws_zalloc(size_t size, const char *reason);
-
-#ifdef LWS_PLAT_OPTEE
-void *lws_malloc(size_t size, const char *reason);
-void lws_free(void *p);
-#define lws_free_set_NULL(P)    do { lws_free(P); (P) = NULL; } while(0)
-#else
-#define lws_malloc(S, R)       lws_realloc(NULL, S, R)
-#define lws_free(P)    lws_realloc(P, 0, "lws_free")
-#define lws_free_set_NULL(P)   do { lws_realloc(P, 0, "free"); (P) = NULL; } while(0)
-#endif
-
-int
-lws_create_event_pipes(struct lws_context *context);
-
-int
-lws_plat_apply_FD_CLOEXEC(int n);
-
-const struct lws_plat_file_ops *
-lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
-                   const char **vpath);
-
-/* lws_plat_ */
-
-LWS_EXTERN int
-lws_plat_context_early_init(void);
-LWS_EXTERN void
-lws_plat_context_early_destroy(struct lws_context *context);
-LWS_EXTERN void
-lws_plat_context_late_destroy(struct lws_context *context);
-
-LWS_EXTERN int
-lws_plat_init(struct lws_context *context,
-             const struct lws_context_creation_info *info);
-LWS_EXTERN int
-lws_plat_drop_app_privileges(struct lws_context *context, int actually_drop);
-
-#if defined(LWS_WITH_UNIX_SOCK)
-int
-lws_plat_user_colon_group_to_ids(const char *u_colon_g, uid_t *puid, gid_t *pgid);
-#endif
-
-LWS_EXTERN int
-lws_check_byte_utf8(unsigned char state, unsigned char c);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len);
-LWS_EXTERN int alloc_file(struct lws_context *context, const char *filename,
-                         uint8_t **buf, lws_filepos_t *amount);
-
-void
-lws_context_destroy2(struct lws_context *context);
-
-
-#ifdef __cplusplus
-};
-#endif
index 0f37d90..e14d415 100644 (file)
@@ -1,67 +1,70 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
-
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_set_fops(struct lws_context *context, const struct lws_plat_file_ops *fops)
 {
        context->fops = fops;
 }
 
-LWS_VISIBLE LWS_EXTERN lws_filepos_t
+lws_filepos_t
 lws_vfs_tell(lws_fop_fd_t fop_fd)
 {
        return fop_fd->pos;
 }
 
-LWS_VISIBLE LWS_EXTERN lws_filepos_t
+lws_filepos_t
 lws_vfs_get_length(lws_fop_fd_t fop_fd)
 {
        return fop_fd->len;
 }
 
-LWS_VISIBLE LWS_EXTERN uint32_t
+uint32_t
 lws_vfs_get_mod_time(lws_fop_fd_t fop_fd)
 {
        return fop_fd->mod_time;
 }
 
-LWS_VISIBLE lws_fileofs_t
+lws_fileofs_t
 lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
 {
        lws_fileofs_t ofs;
 
-       ofs = fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd, offset - fop_fd->pos);
+       ofs = fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd,
+                       offset - (lws_fileofs_t)fop_fd->pos);
 
        return ofs;
 }
 
 
-LWS_VISIBLE lws_fileofs_t
+lws_fileofs_t
 lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
 {
-       return fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd, fop_fd->len +
-                                             fop_fd->pos + offset);
+       return fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd,
+                       (lws_fileofs_t)fop_fd->len + (lws_fileofs_t)fop_fd->pos + offset);
 }
 
 
@@ -98,7 +101,7 @@ lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
                                if (p >= vfs_path + pf->fi[n].len)
                                        if (!strncmp(p - (pf->fi[n].len - 1),
                                                     pf->fi[n].sig,
-                                                    pf->fi[n].len - 1)) {
+                                                    (unsigned int)(pf->fi[n].len - 1))) {
                                                *vpath = p + 1;
                                                return pf;
                                        }
@@ -113,7 +116,7 @@ lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
        return fops;
 }
 
-LWS_VISIBLE LWS_EXTERN lws_fop_fd_t LWS_WARN_UNUSED_RESULT
+lws_fop_fd_t LWS_WARN_UNUSED_RESULT
 lws_vfs_file_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
                  lws_fop_flags_t *flags)
 {
@@ -126,7 +129,7 @@ lws_vfs_file_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
 }
 
 
-LWS_VISIBLE struct lws_plat_file_ops *
+struct lws_plat_file_ops *
 lws_get_fops(struct lws_context *context)
 {
        return (struct lws_plat_file_ops *)context->fops;
diff --git a/lib/cose/CMakeLists.txt b/lib/cose/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c96e3db
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+if (LWS_WITH_COSE)
+       list(APPEND SOURCES
+               cose/cose_key.c
+               cose/cose_validate.c
+               cose/cose_validate_alg.c
+               cose/cose_sign.c
+               cose/cose_sign_alg.c
+               )
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
diff --git a/lib/cose/cose_key.c b/lib/cose/cose_key.c
new file mode 100644 (file)
index 0000000..66247cb
--- /dev/null
@@ -0,0 +1,1188 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * cose_key code
+ */
+
+#include "private-lib-core.h"
+//#include "private-lib-jose.h"
+
+#define lwsl_cose lwsl_notice
+#define lwsl_hexdump_cose lwsl_hexdump_notice
+
+// #define VERBOSE 1
+
+struct lws_cose_key_parse_state {
+       struct lws_cose_key             *ck;
+       /**< single key created here if pkey_set is NULL */
+       char                            buf[(8192 / 8) + 1];
+       /**< enough for 8Kb key, only needed during parse */
+       lws_cose_key_import_callback    per_key_cb;
+       lws_dll2_owner_t                *pkey_set;
+       /**< if non-NULL, expects a [ key set ], else single key */
+       void                            *user;
+       size_t                          pos;
+       int                             cose_state;
+       cose_param_t                    seen[16];
+       int                             seen_count;
+       int                             gencrypto_eidx;
+       int                             meta_idx;
+       unsigned short                  possible;
+};
+
+/*
+ * A COSE key representation is a CBOR map with a specified structure.  The
+ * keys are
+ *
+ *     LWSCOSE_WKK_KTY                 MUST      int / tstr
+ *     LWSCOSE_WKK_KID                 OPT       bstr
+ *     LWSCOSE_WKK_ALG                 OPT       int / tstr
+ *     LWSCOSE_WKK_KEY_OPS             OPT       [ + (int / tstr) ]
+ *     LWSCOSE_WKK_BASE_IV             OPT       bstr
+ */
+
+#if defined(_DEBUG)
+
+static const char *meta_names[] = {
+       "kty", "kid", "use", "key_ops", "base_iv", "alg"
+};
+
+static const char *oct_names[] = {
+       "k"
+};
+
+static const char *rsa_names[] = {
+       "e", "n", "d", "p", "q", "dp", "dq", "qi", "other", "ri", "di", "ti"
+};
+
+static const char *ec_names[] = {
+       "crv", "x", "d", "y",
+};
+
+void
+lws_cose_key_dump(const struct lws_cose_key *ck)
+{
+       const char **enames;
+       char hex[2048];
+       int elems;
+       int n;
+
+       (void)enames;
+       (void)meta_names;
+
+       switch (ck->gencrypto_kty) {
+
+       case LWS_GENCRYPTO_KTY_OCT:
+               elems = LWS_GENCRYPTO_OCT_KEYEL_COUNT;
+               enames = oct_names;
+               break;
+       case LWS_GENCRYPTO_KTY_RSA:
+               elems = LWS_GENCRYPTO_RSA_KEYEL_COUNT;
+               enames = rsa_names;
+               break;
+       case LWS_GENCRYPTO_KTY_EC:
+               elems = LWS_GENCRYPTO_EC_KEYEL_COUNT;
+               enames = ec_names;
+               break;
+
+       default:
+               lwsl_err("%s: jwk %p: unknown type\n", __func__, ck);
+
+               return;
+       }
+
+       lwsl_cose("%s: cose_key %p, kty: %lld (gc %d)\n", __func__, ck,
+                       (long long)ck->kty, ck->gencrypto_kty);
+
+       for (n = 0; n < LWS_COUNT_COSE_KEY_ELEMENTS; n++) {
+               if (ck->meta[n].buf) {
+                       lws_hex_from_byte_array(ck->meta[n].buf, ck->meta[n].len,
+                                               hex, sizeof(hex));
+                       lwsl_cose("  meta: %s: %s\n", meta_names[n], hex);
+               }
+       }
+
+       for (n = 0; n < elems; n++) {
+               if (ck->e[n].buf) {
+                       lws_hex_from_byte_array(ck->e[n].buf, ck->e[n].len,
+                                               hex, sizeof(hex));
+                       lwsl_cose("  e: %s: %s\n", enames[n], hex);
+               }
+       }
+}
+#endif
+
+static const char * const kty_strings[] = { NULL,
+       "OKP", "EC2", "RSA", "SYMMETRIC", "HSS_LMS", "WALNUTDSA"
+};
+
+int
+lws_cose_key_checks(const lws_cose_key_t *key, int64_t kty, cose_param_t alg,
+                   int key_op, const char *crv)
+{
+       const struct lws_gencrypto_keyelem *ke;
+
+       /*
+        * we ourselves have to have a very clear idea what we need, even if
+        * matches are optional in the key itself
+        */
+       assert(key);
+       assert(kty);
+       assert(alg);
+       assert(key_op);
+       assert((kty != LWSCOSE_WKKTV_OKP && kty != LWSCOSE_WKKTV_EC2) || crv);
+
+       /* RFC8152 8.1:
+        *
+        * The 'kty' field MUST be present, and it MUST be '...'.
+        *
+        * But kty can come as an int or a string, but we convert well-known
+        * kty ints to the corresponding string representation at key import
+        */
+       if (!kty || kty >= (int)LWS_ARRAY_SIZE(kty_strings)) {
+               /* we don't understand it */
+               lwsl_notice("%s: unknown kty %d\n", __func__, (int)kty);
+               goto bail;
+       }
+
+       ke = &key->meta[COSEKEY_META_KTY];
+       if (ke->buf && (strlen(kty_strings[kty]) != ke->len ||
+                       memcmp(kty_strings[kty], ke->buf, ke->len))) {
+               lwsl_notice("%s: key is of wrong kty\n", __func__);
+               lwsl_hexdump_notice(ke->buf, ke->len);
+               goto bail;
+       }
+
+       /* ...
+        * If the 'alg' field is present, it MUST match the ... signature
+        * algorithm being used.
+        *
+        * We attempt to convert key alg text representations to a well-known
+        * index, if we can't, then we don't know the alg anyway and should fail
+        * it
+        */
+
+       if (!key->cose_alg && key->meta[COSEKEY_META_ALG].buf) {
+               lwsl_notice("%s: alg fail 1\n", __func__);
+               goto bail;
+       }
+
+       if (key->cose_alg && /* accept it being absent altogether */
+           key->cose_alg != alg) {
+               lwsl_notice("%s: alg fail 2\n", __func__);
+
+               goto bail;
+       }
+
+       /* ...
+        * If the 'key_ops' field is present, it MUST include 'sign' / 'verify'
+        * when creating /verifying an ... signature.
+        */
+
+       ke = &key->meta[COSEKEY_META_KEY_OPS];
+       if (ke->buf && ke->len) {
+               uint32_t n;
+
+               for (n = 0; n < ke->len; n++)
+                       if (ke->buf[n] == key_op)
+                               break;
+
+               if (n == ke->len)
+                       goto bail;
+       }
+
+       /*
+        * If it's related to EC, check there is a curve associated with the
+        * key, and check it is what we expect
+        */
+
+       if (kty == LWSCOSE_WKKTV_OKP || kty == LWSCOSE_WKKTV_EC2) {
+               ke = &key->e[LWS_GENCRYPTO_EC_KEYEL_CRV];
+
+               if (!ke->buf)
+                       goto bail;
+               if (ke->len != strlen(crv))
+                       goto bail;
+               if (memcmp(ke->buf, crv, ke->len))
+                       goto bail;
+       }
+
+       /* We're willing to use this key for this operation */
+
+       return 0;
+
+bail:
+       lwsl_notice("%s: key rejected\n", __func__);
+
+       return 1;
+}
+
+
+static int
+lws_ck_set_el(struct lws_gencrypto_keyelem *e, char *in, size_t len)
+{
+       e->buf = lws_malloc(len + 1, "ck");
+       if (!e->buf)
+               return -1;
+
+       memcpy(e->buf, in, len);
+       e->buf[len] = '\0';
+       e->len = (uint32_t)len;
+
+       return 0;
+}
+
+static struct {
+       const char *curve;
+       cose_param_t cose_id;
+} cose_curves[] = {
+       { "P-256",      LWSCOSE_WKEC_P256 },
+       { "P-384",      LWSCOSE_WKEC_P384 },
+       { "P-521",      LWSCOSE_WKEC_P521 },
+       { "X25519",     LWSCOSE_WKEC_X25519 },
+       { "X448",       LWSCOSE_WKEC_X448 },
+       { "ED25519",    LWSCOSE_WKEC_ED25519 },
+       { "ED448",      LWSCOSE_WKEC_ED448 },
+       { "SECP256K1",  LWSCOSE_WKEC_SECP256K1 },
+};
+
+/* 0 means failed */
+
+static cose_param_t
+lws_cose_curve_name_to_id(const char *curve)
+{
+       int n;
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(cose_curves); n++)
+               if (!strcmp(cose_curves[n].curve, curve))
+                       return cose_curves[n].cose_id;
+
+       return 0;
+}
+
+static const char *
+lws_cose_curve_id_to_name(cose_param_t id)
+{
+       int n;
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(cose_curves); n++)
+               if (cose_curves[n].cose_id == id)
+                       return cose_curves[n].curve;
+
+       return 0;
+}
+
+static const char * const wk_algs[] = {
+       "ES256", "ES384", "ES512"
+};
+static signed char wk_alg_indexes[] = {
+       LWSCOSE_WKAECDSA_ALG_ES256,
+       LWSCOSE_WKAECDSA_ALG_ES384,
+       LWSCOSE_WKAECDSA_ALG_ES512,
+};
+
+static signed char
+cb_cose_key(struct lecp_ctx *ctx, char reason)
+{
+       struct lws_cose_key_parse_state *cps =
+                       (struct lws_cose_key_parse_state *)ctx->user;
+       struct lws_gencrypto_keyelem *ke = NULL;
+       const char *p;
+       int n;
+
+#if defined(VERBOSE)
+       lwsl_notice("%s: reason %d, path %s, ord %u, ppos %d\n", __func__,
+                       reason & 0x3f,
+                       ctx->path, ctx->st[ctx->sp - 1].ordinal,
+                       ctx->pst[ctx->pst_sp].ppos);
+#endif
+
+       switch (reason) {
+       case LECPCB_OBJECT_START:
+               if (cps->ck)
+                       break;
+               goto ak;
+       case LECPCB_ARRAY_ITEM_START:
+               if (cps->pkey_set && ctx->pst[ctx->pst_sp].ppos == 2) {
+                       ak:
+                       cps->ck = lws_zalloc(sizeof(*cps->ck), __func__);
+                       if (!cps->ck)
+                               goto bail;
+                       cps->cose_state = 0;
+                       cps->meta_idx = -1;
+                       cps->gencrypto_eidx = -1;
+                       cps->seen_count = 0;
+
+                       if (cps->pkey_set)
+                               lws_dll2_add_tail(&cps->ck->list, cps->pkey_set);
+               }
+               break;
+       case LECPCB_ARRAY_ITEM_END:
+               if (cps->pkey_set && ctx->pst[ctx->pst_sp].ppos == 2) {
+                       if (cps->per_key_cb)
+                               cps->per_key_cb(cps->ck, cps->user);
+               }
+               break;
+       case LECPCB_TAG_START:
+               if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_KEY) {
+                       lwsl_warn("%s: unexpected tag\n", __func__);
+                       goto bail;
+               }
+               break;
+
+       case LECPCB_VAL_NUM_INT:
+       case LECPCB_VAL_NUM_UINT:
+               if (!ctx->sp) {
+                       lwsl_warn("%s: unexpected uint %d, ppos %d\n",
+                                 __func__, ctx->sp, ctx->pst[ctx->sp].ppos);
+                       goto bail;
+               }
+
+               if (!lecp_parse_map_is_key(ctx)) {
+                       const char *kty_str;
+
+                       /* value part of map */
+
+                       switch (cps->cose_state) {
+                       case LWSCOSE_WKK_KTY:
+                               assert(cps->ck);
+                               cps->ck->kty = (int)ctx->item.u.u64;
+
+                               /* convert the cose key type to gencrypto one */
+                               switch (ctx->item.u.u64) {
+                               case LWSCOSE_WKKTV_OKP:
+                                       cps->ck->gencrypto_kty =
+                                                       LWS_GENCRYPTO_KTY_EC;
+                                       kty_str = "OKP";
+                                       break;
+                               case LWSCOSE_WKKTV_EC2:
+                                       kty_str = "EC2";
+                                       cps->ck->gencrypto_kty =
+                                                       LWS_GENCRYPTO_KTY_EC;
+                                       break;
+                               case LWSCOSE_WKKTV_RSA:
+                                       kty_str = "RSA";
+                                       cps->ck->gencrypto_kty =
+                                                       LWS_GENCRYPTO_KTY_RSA;
+                                       break;
+                               case LWSCOSE_WKKTV_SYMMETRIC:
+                                       kty_str = "SYMMETRIC";
+                                       cps->ck->gencrypto_kty =
+                                                       LWS_GENCRYPTO_KTY_OCT;
+                                       break;
+                               // case LWSCOSE_WKKTV_HSS_LMS:
+                               // case LWSCOSE_WKKTV_WALNUTDSA:
+                               default:
+                                       lwsl_warn("%s: unknown kty\n", __func__);
+                                       goto bail;
+                               }
+
+                               /* store the string version of the key type */
+
+                               ke = &cps->ck->meta[COSEKEY_META_KTY];
+                               ke->len = (uint32_t)strlen(kty_str);
+                               ke->buf = lws_malloc(ke->len + 1, __func__);
+                               if (!ke->buf)
+                                       goto bail;
+                               memcpy(ke->buf, kty_str, ke->len + 1);
+                               break;
+                       case LWSCOSE_WKK_ALG:
+                               /*
+                                * He can tie the key to a cose alg code
+                                */
+                               cps->ck->cose_alg = (int)ctx->item.u.u64;
+                               break;
+                       case LWSCOSE_WKK_KEY_OPS:
+                               if (!cps->pkey_set &&
+                                   (ctx->pst[ctx->sp].ppos != 3 ||
+                                    strcmp(ctx->path, ".[]"))) {
+                                       lwsl_warn("%s: unexpected kops\n",
+                                                               __func__);
+                                       goto bail;
+                               }
+                               if (cps->pkey_set &&
+                                   (ctx->pst[ctx->sp].ppos != 5 ||
+                                    strcmp(ctx->path, "[].[]"))) {
+                                       lwsl_warn("%s: unexpected kops\n",
+                                                               __func__);
+                                       goto bail;
+                               }
+                               break;
+                       case LWSCOSE_WKOKP_CRV:
+                               cps->ck->cose_curve = (int)ctx->item.u.u64;
+                               p = lws_cose_curve_id_to_name(cps->ck->cose_curve);
+                               if (p) {
+                                       ke = &cps->ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV];
+                                       ke->len = (uint32_t)strlen(p);
+                                       ke->buf = lws_malloc(ke->len + 1, __func__);
+                                       if (!ke->buf)
+                                               goto bail;
+                                       memcpy(ke->buf, p, ke->len);
+                                       ke->buf[ke->len] = '\0';
+                               }
+                               break;
+                       default:
+                               lwsl_warn("%s: uint not allowed in state %d\n",
+                                               __func__, cps->cose_state);
+                               /* int not allowed in this state */
+                               goto bail;
+                       }
+
+                       cps->cose_state = 0;
+                       break;
+               }
+
+               /* key part of map pair */
+
+               /*
+                * Disallow any of these coming more than once
+                */
+               cps->cose_state = (int)ctx->item.u.u64;
+               for (n = 0 ; n < cps->seen_count; n++)
+                       if (cps->seen[n] == cps->cose_state) {
+                               /* dupe */
+                               lwsl_warn("%s: duplicate map name %d\n",
+                                               __func__, cps->cose_state);
+                               goto bail;
+                       }
+
+               if (cps->seen_count >= (int)LWS_ARRAY_SIZE(cps->seen))
+                       goto bail;
+               cps->seen[cps->seen_count++] = cps->cose_state;
+
+               cps->meta_idx = -1;
+               switch ((int)ctx->item.u.u64) {
+               case LWSCOSE_WKK_KTY:
+                       cps->meta_idx = COSEKEY_META_KTY;
+                       break;
+               case LWSCOSE_WKK_KID:
+                       cps->meta_idx = COSEKEY_META_KID;
+                       break;
+               case LWSCOSE_WKK_ALG:
+                       cps->meta_idx = COSEKEY_META_ALG;
+                       break;
+               case LWSCOSE_WKK_KEY_OPS:
+                       cps->meta_idx = COSEKEY_META_KEY_OPS;
+                       break;
+               case LWSCOSE_WKK_BASE_IV:
+                       cps->meta_idx = COSEKEY_META_BASE_IV;
+                       break;
+
+               default:
+                       cps->gencrypto_eidx = -1;
+
+                       switch (cps->ck->kty) {
+                       case LWSCOSE_WKKTV_OKP:
+                               switch ((int)ctx->item.u.u64) {
+                               case LWSCOSE_WKOKP_CRV:
+                                       cps->cose_state = LWSCOSE_WKOKP_CRV;
+                                       break;
+                               case LWSCOSE_WKOKP_X:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_EC_KEYEL_X;
+                                       break;
+                               case LWSCOSE_WKOKP_D:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_EC_KEYEL_D;
+                                       break;
+                               default:
+                                       goto bail;
+                               }
+                               break;
+                       case LWSCOSE_WKKTV_EC2:
+                               switch ((int)ctx->item.u.u64) {
+                               case LWSCOSE_WKECKP_CRV:
+                                       cps->cose_state = LWSCOSE_WKOKP_CRV;
+                                       break;
+                               case LWSCOSE_WKECKP_X:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_EC_KEYEL_X;
+                                       break;
+                               case LWSCOSE_WKECKP_Y:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_EC_KEYEL_Y;
+                                       break;
+                               case LWSCOSE_WKECKP_D:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_EC_KEYEL_D;
+                                       break;
+                               default:
+                                       goto bail;
+                               }
+                               break;
+                       case LWSCOSE_WKKTV_RSA:
+                               switch ((int)ctx->item.u.u64) {
+                               case LWSCOSE_WKKPRSA_N:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_N;
+                                       break;
+                               case LWSCOSE_WKKPRSA_E:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_E;
+                                       break;
+                               case LWSCOSE_WKKPRSA_D:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_D;
+                                       break;
+                               case LWSCOSE_WKKPRSA_P:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_P;
+                                       break;
+                               case LWSCOSE_WKKPRSA_Q:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_Q;
+                                       break;
+                               case LWSCOSE_WKKPRSA_DP:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_DP;
+                                       break;
+                               case LWSCOSE_WKKPRSA_DQ:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_DQ;
+                                       break;
+                               case LWSCOSE_WKKPRSA_QINV:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_QI;
+                                       break;
+                               case LWSCOSE_WKKPRSA_OTHER:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_OTHER;
+                                       break;
+                               case LWSCOSE_WKKPRSA_RI:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_RI;
+                                       break;
+                               case LWSCOSE_WKKPRSA_DI:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_DI;
+                                       break;
+                               case LWSCOSE_WKKPRSA_TI:
+                                       cps->gencrypto_eidx =
+                                               LWS_GENCRYPTO_RSA_KEYEL_TI;
+                                       break;
+                               default:
+                                       goto bail;
+                               }
+                               break;
+                       case LWSCOSE_WKKTV_SYMMETRIC:
+                               if (ctx->item.u.i64 != -1 &&
+                                   ctx->item.u.u64 != LWSCOSE_WKSYMKP_KEY_VALUE)
+                                       goto bail;
+
+                               cps->gencrypto_eidx = LWS_GENCRYPTO_OCT_KEYEL_K;
+                               break;
+                       default:
+                               lwsl_warn("%s: unknown kty\n", __func__);
+                               goto bail;
+                       }
+                       break;
+               }
+               break;
+
+       case LECPCB_VAL_BLOB_START:
+               if (!ctx->sp || !(ctx->st[ctx->sp - 1].ordinal & 1)) {
+                       lwsl_warn("%s: unexpected blob\n", __func__);
+                       goto bail;
+               }
+
+               if (cps->cose_state == COSEKEY_META_KID)
+                       break;
+
+               /*
+                * Validate the association of the blob now, collect it into
+                * the temp buf in cps and then alloc and copy it into the
+                * related key element when it's at the end and the size known
+                */
+
+               cps->pos = 0;
+               if (cps->gencrypto_eidx >= 0) {
+                       if (cps->ck->e[cps->gencrypto_eidx].buf) {
+                               lwsl_warn("%s: e[%d] set twice %d\n", __func__,
+                                               cps->gencrypto_eidx,
+                                               cps->ck->e[cps->gencrypto_eidx].len);
+                               /* key elements must only come at most once */
+                               goto bail;
+                       }
+                       break;
+               }
+               if (cps->meta_idx >= 0)
+                       break;
+
+               goto bail;
+
+       case LECPCB_VAL_BLOB_CHUNK:
+       case LECPCB_VAL_BLOB_END:
+               if (cps->pos + ctx->npos > sizeof(cps->buf)) {
+                       lwsl_warn("%s: oversize blob\n", __func__);
+                       goto bail;
+               }
+               memcpy(cps->buf + cps->pos, ctx->buf, ctx->npos);
+               cps->pos += ctx->npos;
+
+               if (reason == LECPCB_VAL_BLOB_CHUNK)
+                       break;
+
+               /* we have the key element data, let's make the ck element */
+               if (cps->gencrypto_eidx >= 0) {
+
+                       if (cps->ck->e[cps->gencrypto_eidx].buf)
+                               break;
+
+                       lws_ck_set_el(&cps->ck->e[cps->gencrypto_eidx],
+                                       (char *)cps->buf, cps->pos);
+                       cps->gencrypto_eidx = -1;
+                       break;
+               }
+
+
+               if (cps->meta_idx >= 0) {
+                       lws_ck_set_el(&cps->ck->meta[cps->meta_idx],
+                                       (char *)cps->buf, cps->pos);
+                       cps->meta_idx = -1;
+               }
+               cps->pos = 0;
+               break;
+       case LECPCB_VAL_STR_END:
+               if (cps->cose_state == LWSCOSE_WKOKP_CRV) {
+                       cps->ck->cose_curve = lws_cose_curve_name_to_id(ctx->buf);
+                       ke = &cps->ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV];
+                       ke->len = ctx->npos;
+                       ke->buf = lws_malloc(ctx->npos, __func__);
+                       if (!ke->buf)
+                               goto bail;
+                       memcpy(ke->buf, ctx->buf, ctx->npos);
+               }
+
+               if (!lecp_parse_map_is_key(ctx) &&
+                   cps->cose_state == LWSCOSE_WKK_ALG) {
+                       size_t n;
+
+                       for (n = 0; n < LWS_ARRAY_SIZE(wk_algs); n++)
+                               if (ctx->npos == strlen(wk_algs[n]) &&
+                                   !memcmp(ctx->buf, wk_algs[n], ctx->npos)) {
+                                       cps->ck->cose_alg = wk_alg_indexes[n];
+                                       break;
+                               }
+
+                       if (n == LWS_ARRAY_SIZE(wk_algs))
+                               /* key is for an alg we don't understand */
+                               lwsl_warn("%s: key for unknown alg %.*s\n",
+                                         __func__, (int)ctx->npos, ctx->buf);
+
+                       ke = &cps->ck->meta[COSEKEY_META_ALG];
+                       ke->len = ctx->npos;
+                       ke->buf = lws_malloc(ctx->npos, __func__);
+                       if (!ke->buf)
+                               goto bail;
+                       memcpy(ke->buf, ctx->buf, ctx->npos);
+               }
+
+               break;
+       }
+
+       return 0;
+
+bail:
+       lwsl_warn("%s: bail\n", __func__);
+       lws_cose_key_destroy(&cps->ck);
+
+       if (cps->pkey_set) {
+               lws_cose_key_set_destroy(cps->pkey_set);
+               cps->pkey_set = NULL;
+       }
+
+       return -1;
+}
+
+void
+lws_cose_key_destroy_elements(struct lws_gencrypto_keyelem *el, int m)
+{
+       int n;
+
+       if (!el)
+               return;
+
+       for (n = 0; n < m; n++)
+               if (el[n].buf) {
+                       /* wipe all key material when it goes out of scope */
+                       lws_explicit_bzero(el[n].buf, el[n].len);
+                       lws_free_set_NULL(el[n].buf);
+                       el[n].len = 0;
+               }
+}
+
+void
+lws_cose_key_destroy(struct lws_cose_key **pck)
+{
+       struct lws_cose_key *ck = *pck;
+
+       if (!ck)
+               return;
+
+       lws_dll2_remove(&ck->list);
+
+       lws_cose_key_destroy_elements(ck->e, LWS_ARRAY_SIZE(ck->e));
+       lws_cose_key_destroy_elements(ck->meta, LWS_ARRAY_SIZE(ck->meta));
+
+       lws_free_set_NULL(*pck);
+}
+
+static int
+lws_cose_key_set_memb_remove(struct lws_dll2 *d, void *user)
+{
+       lws_cose_key_t *ck = lws_container_of(d, lws_cose_key_t, list);
+
+       lws_dll2_remove(d);
+       lws_cose_key_destroy(&ck);
+
+       return 0;
+}
+
+void
+lws_cose_key_set_destroy(lws_dll2_owner_t *o)
+{
+       lws_dll2_foreach_safe(o, NULL, lws_cose_key_set_memb_remove);
+}
+
+lws_cose_key_t *
+lws_cose_key_from_set(lws_dll2_owner_t *set, const uint8_t *kid, size_t kl)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(set)) {
+               lws_cose_key_t *ck = lws_container_of(p, lws_cose_key_t, list);
+               struct lws_gencrypto_keyelem *ke = &ck->meta[COSEKEY_META_KID];
+
+               if (!kid) /* always the first then */
+                       return ck;
+
+               if (ke->buf && ke->len == (uint32_t)kl &&
+                   !memcmp(ke->buf, kid, ke->len))
+                       return ck;
+
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
+lws_cose_key_t *
+lws_cose_key_generate(struct lws_context *context, cose_param_t cose_kty,
+                     int use_mask, int bits, const char *curve,
+                     const uint8_t *kid, size_t kl)
+{
+       struct lws_gencrypto_keyelem *ke;
+       lws_cose_key_t *ck;
+       size_t sn;
+       int n;
+
+       ck = lws_zalloc(sizeof(*ck), __func__);
+       if (!ck)
+               return NULL;
+
+       ck->kty = cose_kty;
+       ck->private_key = 1;
+
+       if (use_mask & 0xfffe) {
+               int count = 0;
+
+               for (n = 1; n < 15; n++)
+                       if (use_mask & (1 << n))
+                               count++;
+               ke = &ck->meta[COSEKEY_META_KEY_OPS];
+               ke->buf = lws_malloc((size_t)count, __func__);
+               if (!ke->buf)
+                       goto fail;
+               ke->len = (uint32_t)count;
+               count = 0;
+               for (n = 1; n < 15; n++)
+                       if (use_mask & (1 << n))
+                               ke->buf[count++] = (uint8_t)n;
+       }
+
+       if (kid) {
+               ke = &ck->meta[COSEKEY_META_KID];
+               ke->buf = lws_malloc(kl, __func__);
+               ke->len = (uint32_t)kl;
+               memcpy(ke->buf, kid, ke->len);
+       }
+
+       switch (cose_kty) {
+       case LWSCOSE_WKKTV_RSA:
+               {
+                       struct lws_genrsa_ctx ctx;
+
+                       memset(&ctx, 0, sizeof(ctx));
+                       ck->gencrypto_kty = LWS_GENCRYPTO_KTY_RSA;
+
+                       lwsl_notice("%s: generating %d bit RSA key\n",
+                                       __func__, bits);
+                       n = lws_genrsa_new_keypair(context, &ctx,
+                                                  LGRSAM_PKCS1_1_5,
+                                                  ck->e, bits);
+                       lws_genrsa_destroy(&ctx);
+                       if (n) {
+                               lwsl_err("%s: problem generating RSA key\n",
+                                               __func__);
+                               goto fail;
+                       }
+               }
+               break;
+       case LWSCOSE_WKKTV_SYMMETRIC:
+
+               ck->gencrypto_kty = LWS_GENCRYPTO_KTY_OCT;
+               sn = (unsigned int)lws_gencrypto_bits_to_bytes(bits);
+               ke = &ck->e[LWS_GENCRYPTO_OCT_KEYEL_K];
+               ke->buf = lws_malloc(sn, "oct");
+               if (!ke->buf)
+                       goto fail;
+               ke->len = (uint32_t)sn;
+               if (lws_get_random(context, ke->buf, sn) != sn) {
+                       lwsl_err("%s: problem getting random\n", __func__);
+                       goto fail;
+               }
+               break;
+
+       case LWSCOSE_WKKTV_OKP:
+       case LWSCOSE_WKKTV_EC2:
+       {
+               struct lws_genec_ctx ctx;
+
+               ck->gencrypto_kty = LWS_GENCRYPTO_KTY_EC;
+
+               if (!curve) {
+                       lwsl_err("%s: must have a named curve\n", __func__);
+
+                       goto fail;
+               }
+
+               if (lws_genecdsa_create(&ctx, context, NULL))
+                       goto fail;
+
+               ctx.genec_alg = LEGENEC_ECDSA;
+               lwsl_notice("%s: generating ECDSA key on curve %s\n", __func__,
+                               curve);
+
+               n = lws_genecdsa_new_keypair(&ctx, curve, ck->e);
+               lws_genec_destroy(&ctx);
+               if (n) {
+                       lwsl_err("%s: problem generating ECDSA key\n", __func__);
+                       goto fail;
+               }
+               /* trim the trailing NUL */
+               ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV].len = (uint32_t)strlen(curve);
+       }
+               break;
+
+       default:
+               lwsl_err("%s: unknown kty\n", __func__);
+               goto fail;
+       }
+
+       return ck;
+
+fail:
+       lws_free_set_NULL(ck);
+
+       return NULL;
+}
+
+struct lws_cose_key *
+lws_cose_key_import(lws_dll2_owner_t *pkey_set, lws_cose_key_import_callback cb,
+                   void *user, const uint8_t *in, size_t len)
+{
+       struct lws_cose_key_parse_state cps;
+       struct lecp_ctx ctx;
+       int m;
+
+       memset(&cps, 0, sizeof(cps));
+
+       cps.per_key_cb          = cb;
+       cps.user                = user;
+       cps.pkey_set            = pkey_set;
+       cps.gencrypto_eidx      = -1;
+
+       lecp_construct(&ctx, cb_cose_key, &cps, NULL, 0);
+       m = lecp_parse(&ctx, in, len);
+       lecp_destruct(&ctx);
+
+       if (m < 0) {
+               lwsl_notice("%s: parse got %d\n", __func__, m);
+               if (cps.pkey_set)
+                       lws_cose_key_set_destroy(cps.pkey_set);
+
+               return NULL;
+       }
+
+       switch (cps.ck->gencrypto_kty) {
+       case LWS_GENCRYPTO_KTY_UNKNOWN:
+               lwsl_notice("%s: missing or unknown ktys\n", __func__);
+               goto bail;
+       default:
+               break;
+       }
+
+       return cps.ck;
+
+bail:
+       lws_cose_key_destroy(&cps.ck);
+       return NULL;
+}
+
+/* gencrypto element orering -> cose key parameters */
+
+static const signed char ckp[3][12] = {
+       { /* LWS_GENCRYPTO_KTY_OCT (1) */
+               /* LWS_GENCRYPTO_OCT_KEYEL_K */ LWSCOSE_WKSYMKP_KEY_VALUE,
+       },
+       { /* LWS_GENCRYPTO_KTY_RSA (2) */
+               /* LWS_GENCRYPTO_RSA_KEYEL_E */       LWSCOSE_WKKPRSA_E,
+               /* LWS_GENCRYPTO_RSA_KEYEL_N */       LWSCOSE_WKKPRSA_N,
+               /* LWS_GENCRYPTO_RSA_KEYEL_D */       LWSCOSE_WKKPRSA_D,
+               /* LWS_GENCRYPTO_RSA_KEYEL_P */       LWSCOSE_WKKPRSA_P,
+               /* LWS_GENCRYPTO_RSA_KEYEL_Q */       LWSCOSE_WKKPRSA_Q,
+               /* LWS_GENCRYPTO_RSA_KEYEL_DP */      LWSCOSE_WKKPRSA_DP,
+               /* LWS_GENCRYPTO_RSA_KEYEL_DQ */      LWSCOSE_WKKPRSA_DQ,
+               /* LWS_GENCRYPTO_RSA_KEYEL_QT */      LWSCOSE_WKKPRSA_QINV,
+               /* LWS_GENCRYPTO_RSA_KEYEL_OTHER */   LWSCOSE_WKKPRSA_OTHER,
+               /* LWS_GENCRYPTO_RSA_KEYEL_RI */      LWSCOSE_WKKPRSA_RI,
+               /* LWS_GENCRYPTO_RSA_KEYEL_DI */      LWSCOSE_WKKPRSA_DI,
+               /* LWS_GENCRYPTO_RSA_KEYEL_TI */      LWSCOSE_WKKPRSA_TI,
+       },
+       { /* LWS_GENCRYPTO_KTY_EC (3) */
+               /* LWS_GENCRYPTO_EC_KEYEL_CRV */ LWSCOSE_WKECKP_CRV,
+               /* LWS_GENCRYPTO_EC_KEYEL_X */   LWSCOSE_WKECKP_X,
+               /* LWS_GENCRYPTO_EC_KEYEL_D */   LWSCOSE_WKECKP_D,
+               /* LWS_GENCRYPTO_EC_KEYEL_Y */   LWSCOSE_WKECKP_Y,
+       }
+};
+
+enum lws_lec_pctx_ret
+lws_cose_key_export(lws_cose_key_t *ck, lws_lec_pctx_t *ctx, int flags)
+{
+       cose_param_t pa = 0;
+       int n;
+
+       if (!ctx->opaque[0]) {
+
+               ctx->opaque[0] = 1; /* map pair count */
+               ctx->opaque[1] = 1; /* element index */
+               ctx->opaque[2] = 0; /* public mask */
+               ctx->opaque[3] = 0; /* doing AGAIN */
+
+               switch (ck->gencrypto_kty) {
+               case LWS_GENCRYPTO_KTY_OCT:
+                       /* nothing to differentiate */
+                       ctx->opaque[2] = 1 << LWS_GENCRYPTO_OCT_KEYEL_K;
+                       break;
+               case LWS_GENCRYPTO_KTY_RSA:
+                       ctx->opaque[2] = 1 << LWS_GENCRYPTO_RSA_KEYEL_E;
+                       break;
+               case LWS_GENCRYPTO_KTY_EC:
+                       ctx->opaque[2] = (1 << LWS_GENCRYPTO_EC_KEYEL_X) |
+                                        (1 << LWS_GENCRYPTO_EC_KEYEL_Y);
+                       break;
+               default:
+                       goto fail;
+               }
+
+               if (flags & LWSJWKF_EXPORT_PRIVATE)
+                       ctx->opaque[2] = 0xffff;
+
+               /*
+                * We first need to find out how many CBOR map pairs we are
+                * planning to create, so we can set a fixed length map of the
+                * right size.
+                */
+
+               for (n = 0; n < (int)LWS_ARRAY_SIZE(ck->e); n++)
+                       if ((ctx->opaque[2] & (1 << n)) && ck->e[n].buf)
+                               ctx->opaque[0]++;
+
+               /*
+                * We always issue kty, others may be
+                *
+                * KID / ALG / KEY_OPS / BASE_IV
+                */
+
+               if (ck->meta[COSEKEY_META_KID].buf)
+                       ctx->opaque[0]++;
+               if (ck->meta[COSEKEY_META_ALG].buf)
+                       ctx->opaque[0]++;
+               if (ck->meta[COSEKEY_META_KEY_OPS].buf)
+                       ctx->opaque[0]++;
+               if (ck->meta[COSEKEY_META_BASE_IV].buf)
+                       ctx->opaque[0]++;
+
+               lws_lec_int(ctx, LWS_CBOR_MAJTYP_MAP, 0, (uint64_t)ctx->opaque[0]);
+               lws_lec_signed(ctx, LWSCOSE_WKK_KTY);
+               lws_lec_signed(ctx, (int64_t)ck->kty);
+
+               if (ck->gencrypto_kty == LWS_GENCRYPTO_KTY_EC) {
+                       struct lws_gencrypto_keyelem *ke =
+                                       &ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV];
+
+                       if (!ke->buf ||
+                           ck->e[LWS_GENCRYPTO_EC_KEYEL_CRV].len > 10) {
+                               lwsl_err("%s: no curve type\n", __func__);
+                               goto fail;
+                       }
+
+                       pa = lws_cose_curve_name_to_id((const char *)ke->buf);
+                       lws_lec_signed(ctx, LWSCOSE_WKECKP_CRV);
+                       if (pa)
+                               lws_lec_signed(ctx, pa);
+                       else
+                               lws_lec_printf(ctx, "%.*s",
+                                               (int)ke->len, ke->buf);
+               }
+
+
+               ctx->opaque[1] = COSEKEY_META_KID;
+       }
+
+       /*
+        * Start from the second key meta, then do any elements that are set
+        */
+
+       while (ctx->buf != ctx->end) {
+               struct lws_gencrypto_keyelem *ke = NULL;
+               int cose_key_param = 0;
+
+               if (lws_lec_scratch(ctx))
+                       break;
+
+               if (ctx->opaque[1] == LWS_ARRAY_SIZE(ck->e) +
+                                     LWS_COUNT_COSE_KEY_ELEMENTS)
+                       break;
+
+               if (ctx->opaque[1] >= LWS_COUNT_COSE_KEY_ELEMENTS) {
+                       n = ctx->opaque[1] - LWS_COUNT_COSE_KEY_ELEMENTS;
+
+                       if (ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
+                           n != LWS_GENCRYPTO_EC_KEYEL_CRV) {
+                               /* we didn't already encode his curve */
+
+                               if ((ctx->opaque[2] & (1 << n)) &&
+                                    ck->e[n].buf && ck->e[n].len) {
+                                       ke = &ck->e[n];
+                                       cose_key_param = ckp[ck->gencrypto_kty - 1][n];
+                               }
+                       }
+               } else
+
+                       switch (ctx->opaque[1]) {
+
+                       case COSEKEY_META_KID: /* bstr */
+                               if (ck->meta[COSEKEY_META_KID].buf) {
+                                       ke = &ck->meta[COSEKEY_META_KID];
+                                       cose_key_param = LWSCOSE_WKK_KID;
+                                       // lwsl_hexdump_notice(ke->buf, ke->len);
+                               }
+                               break;
+
+                       case COSEKEY_META_ALG: /* int, tstr */
+                               if (ck->meta[COSEKEY_META_ALG].buf) {
+                                       ke = &ck->meta[COSEKEY_META_ALG];
+                                       cose_key_param = LWSCOSE_WKK_ALG;
+                               }
+                               break;
+
+                       case COSEKEY_META_KEY_OPS: /* [ int ] */
+                               if (!ck->meta[COSEKEY_META_KEY_OPS].buf)
+                                       break;
+                               ke = &ck->meta[COSEKEY_META_KEY_OPS];
+
+                               n = (int)ke->len;
+                               if (n > 10)
+                                       n = 10;
+
+                               /*
+                                * We copy this array into scratch by hand now we
+                                * made sure it will fit, we will never need AGAIN
+                                */
+
+                               lws_lec_signed(ctx, LWSCOSE_WKK_KEY_OPS);
+                               lws_lec_int(ctx, LWS_CBOR_MAJTYP_ARRAY, 0, (uint64_t)n);
+                               memcpy(&ctx->scratch[ctx->scratch_len], ke->buf,
+                                               (size_t)n);
+                               ctx->scratch_len = (uint8_t)(ctx->scratch_len + (uint8_t)n);
+                               ke = NULL;
+                               break;
+
+                       case COSEKEY_META_BASE_IV: /* bstr */
+                               if (ck->meta[COSEKEY_META_BASE_IV].buf) {
+                                       ke = &ck->meta[COSEKEY_META_BASE_IV];
+                                       cose_key_param = LWSCOSE_WKK_BASE_IV;
+                               }
+                               break;
+
+                       default:
+                               break;
+                       }
+
+               if (ke && ke->buf && ke->len) {
+
+                       if (!ctx->opaque[3])
+                               lws_lec_signed(ctx, cose_key_param);
+
+                       /* binary string or text string? */
+                       if (ctx->opaque[1] == COSEKEY_META_KID ||
+                           ctx->opaque[1] == COSEKEY_META_BASE_IV ||
+                           ctx->opaque[1] >= LWS_COUNT_COSE_KEY_ELEMENTS)
+                               n = (int)lws_lec_printf(ctx, "%.*b",
+                                                       (int)ke->len, ke->buf);
+                       else
+                               n = (int)lws_lec_printf(ctx, "%.*s",
+                                                       (int)ke->len, ke->buf);
+
+                       switch (n) {
+                       case LWS_LECPCTX_RET_AGAIN:
+                               ctx->opaque[3] = 1;
+                               /* dump what we have and come back */
+                               continue;
+                       case LWS_LECPCTX_RET_FAIL:
+                               goto fail;
+                       case LWS_LECPCTX_RET_FINISHED:
+                               break;
+                       }
+               }
+
+               /* move on if we finished that guy */
+               ctx->opaque[1]++;
+               ctx->opaque[3] = 0;
+       }
+
+       ctx->used = lws_ptr_diff_size_t(ctx->buf, ctx->start);
+
+       if (ctx->buf == ctx->end || ctx->scratch_len)
+               return LWS_LECPCTX_RET_AGAIN;
+
+       ctx->opaque[0] = 0;
+
+       return LWS_LECPCTX_RET_FINISHED;
+
+fail:
+       lwsl_notice("%s: failed\n", __func__);
+
+       ctx->opaque[0] = 0;
+
+       return LWS_LECPCTX_RET_FAIL;
+}
diff --git a/lib/cose/cose_sign.c b/lib/cose/cose_sign.c
new file mode 100644 (file)
index 0000000..d7ae64f
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-cose.h"
+
+struct lws_cose_sign_context *
+lws_cose_sign_create(const lws_cose_sign_create_info_t *info)
+{
+       struct lws_cose_sign_context *csc;
+
+       /* you have to have prepared a cbor output context for us to use */
+       assert(info->lec);
+       /* you have to provide at least one key in a cose_keyset */
+       assert(info->keyset);
+       /* you have to provide an lws_context (for crypto random) */
+       assert(info->cx);
+
+       if (info->sigtype == SIGTYPE_MAC) {
+               lwsl_err("%s: only mac0 supported for signing\n", __func__);
+               return NULL;
+       }
+
+       csc = lws_zalloc(sizeof(*csc), __func__);
+       if (!csc)
+               return NULL;
+
+       csc->info = *info;
+
+       return csc;
+}
+
+int
+lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
+                 const lws_cose_key_t *ck)
+{
+       lws_cose_sig_alg_t *si = lws_cose_sign_alg_create(csc->info.cx, ck, alg,
+                                                         LWSCOSE_WKKO_SIGN);
+
+       if (!si)
+               return 1;
+
+       lws_dll2_add_tail(&si->list, &csc->algs);
+
+       return 0;
+}
+
+static signed char cose_tags[] = {
+       0,
+       LWSCOAP_CONTENTFORMAT_COSE_SIGN,
+       LWSCOAP_CONTENTFORMAT_COSE_SIGN1,
+       LWSCOAP_CONTENTFORMAT_COSE_SIGN,
+       LWSCOAP_CONTENTFORMAT_COSE_MAC,
+       LWSCOAP_CONTENTFORMAT_COSE_MAC0
+};
+
+static void
+lws_cose_sign_hashing(struct lws_cose_sign_context *csc,
+                     const uint8_t *in, size_t in_len)
+{
+       //lwsl_hexdump_warn(in, in_len);
+
+       assert(in_len);
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
+                                  lws_dll2_get_head(&csc->algs)) {
+               lws_cose_sig_alg_t *alg = lws_container_of(p,
+                                               lws_cose_sig_alg_t, list);
+
+               if (lws_cose_sign_alg_hash(alg, in, in_len))
+                       alg->failed = 1;
+       } lws_end_foreach_dll_safe(p, tp);
+}
+
+/*
+ * These chunks may be payload or application AAD being emitted into the
+ * signed object somewhere else.  But we do not emit them ourselves here
+ * (since other non-emitted things are also hashed by us) and so can always
+ * deal with the whole in_len in one step.
+ */
+
+enum lws_lec_pctx_ret
+lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
+                           const uint8_t *in, size_t in_len)
+{
+       uint8_t lbuf[MAX_BLOBBED_PARAMS], lb[9];
+       const struct lws_gencrypto_keyelem *ke;
+       enum lws_lec_pctx_ret ret;
+       lws_lec_pctx_t lec, lec1;
+       lws_cose_sig_alg_t *alg;
+       uint8_t c;
+       size_t s;
+
+       switch (csc->tli) {
+       case ST_UNKNOWN:
+               /*
+                * We need to figure out what signing structure we need to use,
+                * given the algorithms that are in it.  So let's have a look
+                * and decide.
+                */
+
+               if (!csc->algs.count) {
+                       lwsl_err("%s: must add at least one signature\n", __func__);
+                       return 1;
+               }
+
+               csc->type = SIGTYPE_MULTI;
+               alg = lws_container_of(csc->algs.head, lws_cose_sig_alg_t, list);
+
+               switch (alg->cose_alg) {
+               case LWSCOSE_WKAHMAC_256_64:
+               case LWSCOSE_WKAHMAC_256_256:
+               case LWSCOSE_WKAHMAC_384_384:
+               case LWSCOSE_WKAHMAC_512_512:
+//                     if (csc->info.sigtype == SIGTYPE_MAC0)
+                               csc->type = SIGTYPE_MAC0;
+//                     else
+//                             csc->type = SIGTYPE_MAC;
+                       break;
+               }
+
+               if (csc->algs.count == 1) {
+                       if (!csc->info.sigtype && csc->type == SIGTYPE_MAC) {
+                           if (csc->info.flags & LCSC_FL_ADD_CBOR_PREFER_MAC0)
+                               csc->type = SIGTYPE_MAC0;
+                       } else
+                               if (!csc->info.sigtype ||
+                                   csc->info.sigtype == SIGTYPE_SINGLE) /* ie, if no hint */
+                                       csc->type = SIGTYPE_SINGLE;
+               }
+
+               lwsl_notice("%s: decided on type %d\n", __func__, csc->type);
+
+               /*
+                * Start emitting the appropriate tag if that's requested
+                */
+
+               if (csc->info.flags & LCSC_FL_ADD_CBOR_TAG) {
+                       ret = lws_lec_printf(csc->info.lec, "%t(",
+                                              cose_tags[csc->type]);
+
+                       if (ret != LWS_LECPCTX_RET_FINISHED)
+                               return ret;
+               }
+
+               /* The */
+               c = 0;
+               switch (csc->type) {
+               case SIGTYPE_MAC0:
+               case SIGTYPE_MULTI:
+               case SIGTYPE_SINGLE:
+                       c = 0x84;
+                       break;
+               case SIGTYPE_MAC:
+                       c = 0x85;
+                       break;
+               default:
+                       break;
+               }
+
+               /* The outer array */
+               csc->info.lec->scratch[csc->info.lec->scratch_len++] = c;
+
+               /*
+                * Then, let's start hashing with the sigtype constant part
+                */
+
+               lws_cose_sign_hashing(csc, sig_mctx[csc->type],
+                                          sig_mctx_len[csc->type]);
+
+               csc->tli = ST_OUTER_PROTECTED;
+               csc->subsequent = 0;
+
+               /* fallthru */
+
+       case ST_OUTER_PROTECTED:
+
+               /*
+                * We need to list and emit any outer protected data as a map
+                * into its own buffer, then emit that into the output as a bstr
+                */
+
+               switch (csc->type) {
+               case SIGTYPE_SINGLE:
+               case SIGTYPE_MAC0:
+                       alg = lws_container_of(csc->algs.head,
+                                              lws_cose_sig_alg_t, list);
+
+                       lws_lec_init(&lec, lbuf, sizeof(lbuf));
+
+                       /* we know it will fit */
+                       lws_lec_printf(&lec, "{1:%lld}",
+                                            (long long)alg->cose_alg);
+                       lws_lec_scratch(&lec);
+
+                       if (!csc->subsequent) {
+                               lws_lec_init(&lec1, lb, sizeof(lb));
+                               lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
+                                               lec.used);
+                               lws_cose_sign_hashing(csc, lec1.scratch,
+                                                          lec1.scratch_len);
+                               lws_cose_sign_hashing(csc, lec.start, lec.used);
+                               ret = lws_lec_printf(csc->info.lec, "%.*b",
+                                                    (int)lec.used, lec.start);
+
+                               if (ret != LWS_LECPCTX_RET_FINISHED)
+                                       return ret;
+                               csc->subsequent = 1;
+                       }
+                       break;
+               case SIGTYPE_MAC:
+               case SIGTYPE_MULTI:
+                       lws_lec_init(&lec, lbuf, sizeof(lbuf));
+                       lws_lec_int(&lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
+                       lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
+                       lws_lec_scratch(&lec);
+                       lec.used = lws_ptr_diff_size_t(lec.buf, lec.start);
+                       lws_cose_sign_hashing(csc, lec.start,
+                                                  lec.used);
+                       break;
+               default:
+                       lec.used = 0;
+                       break;
+               }
+
+               csc->tli = ST_OUTER_UNPROTECTED;
+
+               /* fallthru */
+
+       case ST_OUTER_UNPROTECTED:
+
+               /*
+                * We need to list and emit any outer unprotected data, as
+                * an inline cbor map
+                */
+
+               switch (csc->type) {
+               case SIGTYPE_SINGLE:
+               case SIGTYPE_MAC0:
+                       alg = lws_container_of(csc->algs.head,
+                                              lws_cose_sig_alg_t, list);
+                       ke = &alg->cose_key->meta[COSEKEY_META_KID];
+                       if (ke->len) {
+                               ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
+                                                    LWSCOSE_WKL_KID,
+                                                    (int)ke->len, ke->buf);
+
+                               if (ret != LWS_LECPCTX_RET_FINISHED)
+                                       return ret;
+                       }
+                       /* hack for no extra data */
+
+                       lws_lec_init(&lec1, lb, sizeof(lb));
+                       lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
+                       lws_cose_sign_hashing(csc, lec1.scratch,
+                                                  lec1.scratch_len);
+                       break;
+               case SIGTYPE_MAC:
+               case SIGTYPE_MULTI:
+
+                       lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
+
+                       /*
+                        * For cose-sign, we need to feed each sig alg its alg-
+                        * specific protected data into the hash before letting
+                        * all the hashes see the payload
+                        */
+
+                       lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
+                                                  lws_dll2_get_head(&csc->algs)) {
+                               alg = lws_container_of(p, lws_cose_sig_alg_t, list);
+
+                               lws_lec_init(&lec, lbuf, sizeof(lbuf));
+
+                               /* we know it will fit */
+                               lws_lec_printf(&lec, "{1:%lld}",
+                                                    (long long)alg->cose_alg);
+
+                               lws_lec_init(&lec1, lb, sizeof(lb));
+                               lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
+                                               lec.used);
+
+                               // lwsl_hexdump_warn(lec1.scratch, lec1.scratch_len);
+                               // lwsl_hexdump_warn(lec.start, lec.used);
+                               if (lws_cose_sign_alg_hash(alg, lec1.scratch,
+                                                          lec1.scratch_len))
+                                       alg->failed = 1;
+                               if (lws_cose_sign_alg_hash(alg, lec.start,
+                                                          lec.used))
+                                       alg->failed = 1;
+
+                       } lws_end_foreach_dll_safe(p, tp);
+
+                       lws_lec_init(&lec1, lb, sizeof(lb));
+                       lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
+                       lws_cose_sign_hashing(csc, lec1.scratch,
+                                                  lec1.scratch_len);
+
+                       break;
+               default:
+                       ret = lws_lec_printf(csc->info.lec, "{}");
+                       if (ret != LWS_LECPCTX_RET_FINISHED)
+                               return ret;
+                       break;
+               }
+
+               csc->tli = ST_OUTER_PAYLOAD;
+               csc->subsequent = 0;
+
+               /* Prepare the payload BSTR */
+
+               lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0,
+                                          csc->info.inline_payload_len);
+
+               lws_lec_init(&lec1, lb, sizeof(lb));
+               lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
+                           csc->info.inline_payload_len);
+               lws_cose_sign_hashing(csc, lec1.scratch,
+                                          lec1.scratch_len);
+
+               lws_lec_scratch(csc->info.lec);
+
+               csc->rem_pay = csc->info.inline_payload_len;
+
+               /* fallthru */
+
+       case ST_OUTER_PAYLOAD:
+
+               if (csc->along) {
+                       in += csc->along;
+                       in_len -= csc->along;
+               }
+
+               lws_lec_scratch(csc->info.lec);
+
+               if (csc->rem_pay) {
+
+                       lws_cose_sign_hashing(csc, in, in_len);
+
+                       /*
+                        * in / in_len is the payload chunk
+                        */
+
+                       s = lws_ptr_diff_size_t(csc->info.lec->end,
+                                               csc->info.lec->buf);
+                       if (s > (size_t)csc->rem_pay)
+                               s = (size_t)csc->rem_pay;
+                       if (s > in_len)
+                               s = in_len;
+
+                       memcpy(csc->info.lec->buf, in, s);
+                       csc->info.lec->buf += s;
+                       csc->info.lec->used = lws_ptr_diff_size_t(
+                                       csc->info.lec->buf,
+                                       csc->info.lec->start);
+                       csc->rem_pay -= s;
+
+                       csc->along = s;
+
+                       return LWS_LECPCTX_RET_AGAIN;
+               }
+
+               /* finished with rem_pay */
+
+               if (csc->type == SIGTYPE_MULTI) {
+
+                       csc->alg = lws_container_of(csc->algs.head,
+                                               lws_cose_sig_alg_t, list);
+                       lws_lec_init(&lec1, lb, sizeof(lb));
+                       lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
+                                   csc->algs.count);
+                       lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
+                                       csc->algs.count);
+                       csc->tli = ST_INNER_PROTECTED;
+                       goto inner_protected;
+               }
+               csc->tli = ST_OUTER_SIGN1_SIGNATURE;
+               csc->along = 0;
+
+               /* fallthru */
+
+       case ST_OUTER_SIGN1_SIGNATURE:
+
+               alg = lws_container_of(lws_dll2_get_head(&csc->algs),
+                                      lws_cose_sig_alg_t, list);
+
+               if (!alg->completed)
+                       lws_cose_sign_alg_complete(alg);
+               if (alg->failed)
+                       return LWS_LECPCTX_RET_FAIL;
+
+               ret = lws_lec_printf(csc->info.lec, "%.*b",
+                                    (int)alg->rhash_len, alg->rhash);
+               if (ret != LWS_LECPCTX_RET_FINISHED)
+                               return ret;
+
+               if (csc->type == SIGTYPE_MAC) {
+                       csc->alg = lws_container_of(csc->algs.head,
+                                               lws_cose_sig_alg_t, list);
+                       lws_lec_init(&lec1, lb, sizeof(lb));
+                       lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
+                                   csc->algs.count);
+                       lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
+                                       csc->algs.count);
+                       csc->tli = ST_INNER_PROTECTED;
+                       goto inner_protected;
+               }
+
+               break;
+
+       case ST_INNER_PROTECTED:
+inner_protected:
+
+               /*
+                * We need to list and emit any outer protected data as a map
+                * into its own buffer, then emit that into the output as a bstr
+                */
+
+               switch (csc->type) {
+               case SIGTYPE_MAC:
+               case SIGTYPE_MULTI:
+                       lws_lec_init(&lec1, lb, sizeof(lb));
+                       lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
+
+                       lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
+
+                       lws_lec_init(&lec, lbuf, sizeof(lbuf));
+
+                       /* we know it will fit */
+                       lws_lec_printf(&lec, "{1:%lld}",
+                                            (long long)csc->alg->cose_alg);
+
+                       lws_lec_init(&lec1, lb, sizeof(lb));
+                       lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
+                                       lec.used);
+                       lws_lec_printf(csc->info.lec, "{1:%lld}",
+                                            (long long)csc->alg->cose_alg);
+                       break;
+               default:
+                       lec.used = 0;
+                       break;
+               }
+
+
+               csc->tli = ST_INNER_UNPROTECTED;
+
+               /* fallthru */
+
+       case ST_INNER_UNPROTECTED:
+
+               switch (csc->type) {
+               case SIGTYPE_MULTI:
+                       alg = lws_container_of(csc->algs.head,
+                                              lws_cose_sig_alg_t, list);
+                       ke = &alg->cose_key->meta[COSEKEY_META_KID];
+                       if (ke->len) {
+                               ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
+                                                    LWSCOSE_WKL_KID,
+                                                    (int)ke->len, ke->buf);
+
+                               if (ret != LWS_LECPCTX_RET_FINISHED)
+                                       return ret;
+                       }
+                       break;
+               default:
+                       ret = lws_lec_printf(csc->info.lec, "{}");
+                       if (ret != LWS_LECPCTX_RET_FINISHED)
+                               return ret;
+                       break;
+               }
+
+               lws_cose_sign_alg_complete(csc->alg);
+               if (csc->alg->failed)
+                       return LWS_LECPCTX_RET_FAIL;
+               csc->tli = ST_INNER_SIGNATURE;
+
+               /* fallthru */
+
+       case ST_INNER_SIGNATURE:
+
+               ret = lws_lec_printf(csc->info.lec, "%.*b",
+                                    (int)csc->alg->rhash_len, csc->alg->rhash);
+               if (ret != LWS_LECPCTX_RET_FINISHED)
+                       return ret;
+
+               if (csc->alg->list.next) {
+                       csc->alg = (lws_cose_sig_alg_t *)csc->alg->list.next;
+                       csc->tli = ST_INNER_PROTECTED;
+               }
+               break;
+
+       }
+
+       return 0;
+}
+
+void
+lws_cose_sign_destroy(struct lws_cose_sign_context **_csc)
+{
+       struct lws_cose_sign_context *csc = *_csc;
+
+       if (!csc)
+               return;
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
+                                  lws_dll2_get_head(&csc->algs)) {
+               lws_cose_sig_alg_t *alg = lws_container_of(p,
+                                               lws_cose_sig_alg_t, list);
+
+               lws_dll2_remove(p);
+               lws_cose_sign_alg_destroy(&alg);
+       } lws_end_foreach_dll_safe(p, tp);
+
+       lws_free_set_NULL(*_csc);
+}
diff --git a/lib/cose/cose_sign_alg.c b/lib/cose/cose_sign_alg.c
new file mode 100644 (file)
index 0000000..71d5245
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-cose.h"
+
+lws_cose_sig_alg_t *
+lws_cose_sign_alg_create(struct lws_context *cx, const lws_cose_key_t *ck,
+                   cose_param_t cose_alg, int op)
+{
+       lws_cose_sig_alg_t *alg = lws_zalloc(sizeof(*alg), __func__);
+       const struct lws_gencrypto_keyelem *ke;
+       enum lws_genhmac_types ghm;
+       enum lws_genhash_types gh;
+       const char *crv;
+
+       if (!alg)
+               return NULL;
+
+       alg->cose_alg = cose_alg;
+       alg->cose_key = ck;
+
+       switch (cose_alg) {
+
+       /* ECDSA algs */
+
+       case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
+               crv = "P-256";
+               gh = LWS_GENHASH_TYPE_SHA256;
+               alg->keybits = 256;
+               goto ecdsa;
+       case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
+               crv = "P-384";
+               gh = LWS_GENHASH_TYPE_SHA384;
+               alg->keybits = 384;
+               goto ecdsa;
+       case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
+               crv = "P-521";
+               gh = LWS_GENHASH_TYPE_SHA512;
+               alg->keybits = 521;
+ecdsa:
+
+               /* the key is good for this? */
+
+               if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_EC2, cose_alg,
+                                       op, crv))
+                       goto bail_ecdsa;
+
+               if (lws_genhash_init(&alg->hash_ctx, gh))
+                       goto bail_ecdsa;
+
+               if (lws_genecdsa_create(&alg->u.ecdsactx, cx, lws_ec_curves)) {
+                       lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
+                                   __func__);
+                       goto bail_ecdsa1;
+               }
+
+               if (lws_genecdsa_set_key(&alg->u.ecdsactx, ck->e)) {
+                       lwsl_notice("%s: ec key import fail\n", __func__);
+                       goto bail_ecdsa2;
+               }
+
+               break;
+
+       /* HMAC algs */
+
+       case LWSCOSE_WKAHMAC_256_64:
+               ghm = LWS_GENHMAC_TYPE_SHA256;
+               alg->keybits = 64;
+               goto hmac;
+       case LWSCOSE_WKAHMAC_256_256:
+               ghm = LWS_GENHMAC_TYPE_SHA256;
+               alg->keybits = 256;
+               goto hmac;
+       case LWSCOSE_WKAHMAC_384_384:
+               ghm = LWS_GENHMAC_TYPE_SHA384;
+               alg->keybits = 384;
+               goto hmac;
+       case LWSCOSE_WKAHMAC_512_512:
+               ghm = LWS_GENHMAC_TYPE_SHA512;
+               alg->keybits = 512;
+
+hmac:
+               if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_SYMMETRIC,
+                                       cose_alg, op, NULL))
+                       goto bail_hmac;
+
+               ke = &ck->e[LWS_GENCRYPTO_OCT_KEYEL_K];
+               if (lws_genhmac_init(&alg->u.hmacctx, ghm, ke->buf, ke->len))
+                       goto bail_hmac;
+
+               break;
+
+       /* RSASSA algs */
+
+       case LWSCOSE_WKARSA_ALG_RS256:
+               gh = LWS_GENHASH_TYPE_SHA256;
+               goto rsassa;
+
+       case LWSCOSE_WKARSA_ALG_RS384:
+               gh = LWS_GENHASH_TYPE_SHA384;
+               goto rsassa;
+
+       case LWSCOSE_WKARSA_ALG_RS512:
+               gh = LWS_GENHASH_TYPE_SHA512;
+
+rsassa:
+               if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_RSA, cose_alg,
+                                       op, NULL))
+                       goto bail_hmac;
+
+               alg->keybits = (int)ck->e[LWS_GENCRYPTO_RSA_KEYEL_N].len * 8;
+
+               if (lws_genhash_init(&alg->hash_ctx, gh))
+                       goto bail_hmac;
+
+               if (lws_genrsa_create(&alg->u.rsactx, ck->e, cx,
+                                     LGRSAM_PKCS1_1_5, gh)) {
+                       lwsl_notice("%s: lws_genrsa_create fail\n", __func__);
+                       goto bail_hmac;
+               }
+               break;
+
+       default:
+               lwsl_warn("%s: unsupported alg %lld\n", __func__,
+                               (long long)cose_alg);
+               goto bail_hmac;
+       }
+
+       return alg;
+
+bail_ecdsa2:
+       lws_genec_destroy(&alg->u.ecdsactx);
+bail_ecdsa1:
+       lws_genhash_destroy(&alg->hash_ctx, NULL);
+bail_ecdsa:
+       lws_free(alg);
+
+       return NULL;
+
+bail_hmac:
+       lws_free(alg);
+
+       return NULL;
+}
+
+int
+lws_cose_sign_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len)
+{
+#if defined(VERBOSE)
+       lwsl_hexdump_warn(in, in_len);
+#endif
+
+       switch (alg->cose_alg) {
+
+       case LWSCOSE_WKAHMAC_256_64:
+       case LWSCOSE_WKAHMAC_256_256:
+       case LWSCOSE_WKAHMAC_384_384:
+       case LWSCOSE_WKAHMAC_512_512:
+               return lws_genhmac_update(&alg->u.hmacctx, in, in_len);
+       }
+
+       /* EC, rsa are just making the hash before signing */
+
+       return lws_genhash_update(&alg->hash_ctx, in, in_len);
+}
+
+/*
+ * We fill up alg-> rhash and rhash_len with the results, and destroy the
+ * crypto pieces cleanly.  Call lws_cose_sign_alg_destroy() afterwards to
+ * clean up the alg itself.
+ */
+
+void
+lws_cose_sign_alg_complete(lws_cose_sig_alg_t *alg)
+{
+       uint8_t digest[LWS_GENHASH_LARGEST];
+       unsigned int bytes;
+       uint8_t htype;
+       size_t hs;
+
+       if (alg->completed)
+               return;
+
+       switch (alg->cose_alg) {
+       case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
+       case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
+       case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
+               hs = lws_genhash_size(alg->hash_ctx.type);
+               bytes = (unsigned int)lws_gencrypto_bits_to_bytes(alg->keybits);
+               lws_genhash_destroy(&alg->hash_ctx, digest);
+               alg->rhash_len = 0;
+               lwsl_notice("alg keybits %d hs %d\n", (int)alg->keybits, (int)hs);
+               if (!alg->failed &&
+                   lws_genecdsa_hash_sign_jws(&alg->u.ecdsactx, digest,
+                                               alg->hash_ctx.type,
+                                               (int)alg->keybits, alg->rhash,
+                                               2u * bytes) >= 0)
+                       alg->rhash_len = (int)(2 * bytes);
+               else
+                       alg->failed = 1;
+
+               lws_genec_destroy(&alg->u.ecdsactx);
+               break;
+
+       case LWSCOSE_WKAHMAC_256_64:
+       case LWSCOSE_WKAHMAC_256_256:
+       case LWSCOSE_WKAHMAC_384_384:
+       case LWSCOSE_WKAHMAC_512_512:
+               alg->rhash_len = (int)lws_genhmac_size(alg->u.hmacctx.type);
+               if (alg->cose_alg == LWSCOSE_WKAHMAC_256_64)
+                       alg->rhash_len = 8;
+
+               if (lws_genhmac_destroy(&alg->u.hmacctx, alg->rhash)) {
+                       lwsl_err("%s: destroy failed\n", __func__);
+                       break;
+               }
+               break;
+
+       case LWSCOSE_WKARSA_ALG_RS256:
+       case LWSCOSE_WKARSA_ALG_RS384:
+       case LWSCOSE_WKARSA_ALG_RS512:
+               bytes = (unsigned int)lws_gencrypto_bits_to_bytes(alg->keybits);
+               htype = alg->hash_ctx.type;
+
+               if (!lws_genhash_destroy(&alg->hash_ctx, digest) &&
+                   !alg->failed &&
+                   lws_genrsa_hash_sign(&alg->u.rsactx, digest, htype,
+                                        alg->rhash, bytes) >= 0)
+                       alg->rhash_len = (int)bytes;
+               else
+                       lwsl_err("%s: lws_genrsa_hash_sign\n", __func__);
+
+               lws_genrsa_destroy(&alg->u.rsactx);
+               break;
+
+       default:
+               break;
+       }
+
+       alg->completed = 1;
+}
+
+void
+lws_cose_sign_alg_destroy(lws_cose_sig_alg_t **_alg)
+{
+       lws_dll2_remove(&(*_alg)->list);
+       lws_cose_sign_alg_complete(*_alg);
+       lws_free_set_NULL(*_alg);
+}
diff --git a/lib/cose/cose_validate.c b/lib/cose/cose_validate.c
new file mode 100644 (file)
index 0000000..1b9f3f3
--- /dev/null
@@ -0,0 +1,1051 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * cose_sign handling
+ *
+ * Validation:
+ *
+ *  - we put all our pieces and results in an lwsac in the parse state object
+ *
+ *  - we collect pieces needed for sig validation into lwsac elements
+ *
+ *  - we go through each signature making discrete results in the lwsac for
+ *    the user code to assess
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-cose.h"
+
+const uint8_t *sig_mctx[] = { (uint8_t *)"",
+                                   (uint8_t *)"\x85\x69""Signature",
+                                   (uint8_t *)"\x84\x6a""Signature1",
+                                   (uint8_t *)"\x85\x6f""CounterSignature",
+                                   (uint8_t *)"\x84\x63""MAC",
+                                   (uint8_t *)"\x84\x64""MAC0",
+};
+uint8_t sig_mctx_len[] = { 0, 11, 12, 17, 5, 6 };
+
+struct alg_names {
+       const char      *name;
+       cose_param_t    alg;
+} alg_names[] = {
+       { "ES256",      LWSCOSE_WKAECDSA_ALG_ES256 },
+       { "ES384",      LWSCOSE_WKAECDSA_ALG_ES384 },
+       { "ES512",      LWSCOSE_WKAECDSA_ALG_ES512 },
+       { "HS256_64",   LWSCOSE_WKAHMAC_256_64 },
+       { "HS256",      LWSCOSE_WKAHMAC_256_256 },
+       { "HS384",      LWSCOSE_WKAHMAC_384_384 },
+       { "HS512",      LWSCOSE_WKAHMAC_512_512 },
+       { "RS256",      LWSCOSE_WKARSA_ALG_RS256 },
+       { "RS384",      LWSCOSE_WKARSA_ALG_RS384 },
+       { "RS512",      LWSCOSE_WKARSA_ALG_RS512 },
+};
+
+/*
+ * The Sig_structure plaintext is new temp CBOR made up from pieces from the
+ * cose_sign, cose_signature, and payload in a specific order
+ *
+ *  tstr     context string
+ *  bstr     0-len or protected body headers
+ *  bstr     (Missing for sign1) 0-len or protected signer headers
+ *  bstr     0-len or protected application part
+ *  bstr     the payload
+ *
+ * We are getting CBOR with an optional outer tag and then an array of exactly
+ * 4 items in a fixed order
+ *
+ * [
+ *   protected headers: bstr containing a map (captured as CBOR in cps->ph[])
+ *   unprotected: map: for sign1, eg, the alg (!?), the kid
+ *   payload: bstr
+ *   if sign: signatures: [ cose_signature struct array,
+ *                         each is a 3-element array
+ *     [
+ *       protected: bstr containing a map: (eg, the alg) (captured as CBOR)
+ *       unprotected: map: (eg, the kid)
+ *       signature:  bstr
+ *     ]
+ *   if sign1: bstr containing signature
+ * ]
+ *
+ * The last signatures field may be an array of signatures, or a single
+ * cose_signature object for cose_sign1.
+ *
+ * For cose_sign1, we know the signature alg before the payload and can do it
+ * in a single pass.  But for sign, we do not know the signature algs until
+ * after the payload, which is an unfortunate oversight in cose_sign, meaning we
+ * cannot hash the payload one or more ways in a single pass.
+ */
+
+#if defined(VERBOSE)
+const char *cose_sections[] = {
+       "ST_UNKNOWN",
+
+       "ST_OUTER_PROTECTED",
+       "ST_OUTER_UNPROTECTED",
+       "ST_OUTER_PAYLOAD",
+       "ST_OUTER_SIGN1_SIGNATURE",
+
+       "ST_OUTER_SIGN_SIGARRAY",
+
+       "ST_OUTER_MACTAG",
+
+       "ST_INNER_PROTECTED",
+       "ST_INNER_UNPROTECTED",
+       "ST_INNER_SIGNATURE",
+
+       "ST_INNER_EXCESS",
+};
+#endif
+
+const char *
+lws_cose_alg_to_name(cose_param_t alg)
+{
+       size_t n;
+
+       for (n = 0; n < LWS_ARRAY_SIZE(alg_names); n++)
+               if (alg_names[n].alg == alg)
+                       return alg_names[n].name;
+
+       return "unknown_alg";
+}
+
+cose_param_t
+lws_cose_name_to_alg(const char *name)
+{
+       size_t n;
+
+       for (n = 0; n < LWS_ARRAY_SIZE(alg_names); n++)
+               if (!strcmp(alg_names[n].name, name))
+                       return alg_names[n].alg;
+
+       return 0;
+}
+
+static size_t
+bstr_len(uint8_t *t, size_t buflen, uint8_t opcode, uint64_t len)
+{
+       uint8_t *ot = t;
+
+       if (buflen < 9)
+               return 0;
+
+       if (len < 24) {
+               *t = (uint8_t)(opcode | len);
+
+               return 1;
+       }
+       if (len < 256) {
+               *t++ = opcode | LWS_CBOR_1;
+               goto b;
+       }
+       if (len < 65536) {
+               *t++ = opcode | LWS_CBOR_2;
+               goto b1;
+       }
+       if (len < 0xffffffffu) {
+               *t++ = opcode | LWS_CBOR_4;
+               goto b2;
+       }
+
+       *t++ = opcode | LWS_CBOR_8;
+
+       *t++ = (uint8_t)(len >> 56);
+       *t++ = (uint8_t)(len >> 48);
+       *t++ = (uint8_t)(len >> 40);
+       *t++ = (uint8_t)(len >> 32);
+
+b2:
+       *t++ = (uint8_t)(len >> 24);
+       *t++ = (uint8_t)(len >> 16);
+b1:
+       *t++ = (uint8_t)(len >> 8);
+b:
+       *t++ = (uint8_t)len;
+
+       return lws_ptr_diff_size_t(t, ot);
+}
+
+static int
+apply_external(struct lws_cose_validate_context *cps)
+{
+       lws_cose_sig_alg_t *alg;
+       uint8_t t[9];
+
+       alg = lws_container_of(cps->algs.head, lws_cose_sig_alg_t, list);
+       if (!alg)
+               /* expected if no key */
+               return 0;
+
+       /* get the external payload first, if any indicated */
+
+       if (cps->info.ext_len) {
+               lws_cose_sig_ext_pay_t ex;
+               size_t s;
+
+               s = bstr_len(t, sizeof(t), LWS_CBOR_MAJTYP_BSTR,
+                            cps->info.ext_len);
+               if (lws_cose_val_alg_hash(alg, t, s))
+                       return 1;
+
+               memset(&ex, 0, sizeof(ex));
+               ex.cps = cps;
+
+               do {
+                       int n;
+
+                       ex.xl = 0;
+                       n = cps->info.ext_cb(&ex);
+
+                       if (ex.xl &&
+                           lws_cose_val_alg_hash(alg, ex.ext, ex.xl))
+                               return 1;
+
+                       if (n == LCOSESIGEXTCB_RET_ERROR)
+                               return 1;
+
+                       if (n == LCOSESIGEXTCB_RET_FINISHED)
+                               break;
+               } while (1);
+       }
+
+       return 0;
+}
+
+static int
+create_alg(struct lecp_ctx *ctx, struct lws_cose_validate_context *cps)
+{
+       lws_cose_validate_param_stack_t *sl = &cps->st[cps->sp], *sl0 = &cps->st[0];
+       lws_cose_validate_res_t *res;
+       lws_cose_sig_alg_t *alg;
+       lws_cose_key_t *ck;
+       uint8_t *p;
+       size_t s;
+
+       /* with sign1, we can hash the payload in a
+        * single pass */
+
+       ck = lws_cose_key_from_set(cps->info.keyset, sl->kid.buf, sl->kid.len);
+       if (!ck) {
+               lwsl_notice("%s: no key\n", __func__);
+               lwsl_hexdump_notice(sl->kid.buf, sl->kid.len);
+               goto no_key_or_alg;
+       }
+
+       // lwsl_notice("%s: cps->alg %d\n", __func__, (int)cps->alg);
+
+       alg = lws_cose_val_alg_create(cps->info.cx, ck, cps->st[0].alg,
+                                     LWSCOSE_WKKO_VERIFY);
+       if (!alg) {
+               lwsl_info("%s: no alg\n", __func__);
+
+no_key_or_alg:
+               /*
+                * We can't create the alg then, so we can't normally
+                * create a result object.  Create one especially for this
+                * case and continue on
+                */
+
+               res = lws_zalloc(sizeof(*res), __func__);
+               if (res) {
+                       res->result = -1001;
+
+                       lws_dll2_add_tail(&res->list, &cps->results);
+               }
+
+               return 0;
+       }
+
+       lws_dll2_add_tail(&alg->list, &cps->algs);
+
+       /*
+        * Hash step 1: The first hash content depends on
+        *              sign/sign1/csign/mac/mac0 constant bstr
+        */
+
+       if (lws_cose_val_alg_hash(alg, sig_mctx[cps->info.sigtype],
+                              sig_mctx_len[cps->info.sigtype]))
+               goto bail;
+
+       /*
+        * Hash step 2: A zero-length bstr, or a copy of the
+        *              OUTER protected headers
+        *
+        *              A zero-entry map alone becomes a zero-
+        *              length bstr
+        */
+
+       if (sl0->ph_pos[0] < 2) {
+               /* nothing to speak of */
+               sl0->ph[0][0] = LWS_CBOR_MAJTYP_BSTR;
+               p = &sl0->ph[0][0];
+               s = 1;
+       } else {
+               if (sl0->ph_pos[0] < 24) {
+                       sl0->ph[0][2] = (uint8_t)
+                          (LWS_CBOR_MAJTYP_BSTR | sl0->ph_pos[0]);
+                       p = &sl0->ph[0][2];
+                       s = (size_t)sl0->ph_pos[0] + 1;
+               } else {
+                       sl0->ph[0][1] = LWS_CBOR_MAJTYP_BSTR |
+                                       LWS_CBOR_1;
+                       sl0->ph[0][2] = (uint8_t)sl0->ph_pos[0];
+                       p = &sl0->ph[0][1];
+                       s = (size_t)sl0->ph_pos[0] + 2;
+               }
+       }
+
+       if (lws_cose_val_alg_hash(alg, p, s))
+               goto bail;
+
+       /*
+        * Hash step 3: Protected signer headers (Elided for sign1)
+        */
+
+       if (cps->info.sigtype == SIGTYPE_MULTI) {
+               if (sl->ph_pos[2] < 2) {
+                       /* nothing to speak of */
+                       sl->ph[2][0] = LWS_CBOR_MAJTYP_BSTR;
+                       p = &sl->ph[2][0];
+                       s = 1;
+               } else {
+                       if (sl->ph_pos[2] < 24) {
+                               sl->ph[2][2] = (uint8_t)
+                                  (LWS_CBOR_MAJTYP_BSTR | sl->ph_pos[2]);
+                               p = &sl->ph[2][2];
+                               s = (size_t)sl->ph_pos[2] + 1;
+                       } else {
+                               sl->ph[2][1] = LWS_CBOR_MAJTYP_BSTR |
+                                               LWS_CBOR_1;
+                               sl->ph[2][2] = (uint8_t)sl->ph_pos[2];
+                               p = &sl->ph[2][1];
+                               s = (size_t)sl->ph_pos[2] + 2;
+                       }
+               }
+
+               if (lws_cose_val_alg_hash(alg, p, s))
+                       goto bail;
+       }
+
+       /* Hash step 4: bstr for applictation protected pieces
+        *              empty for now
+        */
+
+       if (!cps->info.ext_len) { /* ie, if no app data */
+               uint8_t u = LWS_CBOR_MAJTYP_BSTR;
+               if (lws_cose_val_alg_hash(alg, &u, 1))
+                       goto bail;
+       }
+
+       /*
+        * The final part is the payload in its own bstr, as
+        * we get it if sign1, else replayed from a cache in heap
+        */
+
+       if (cps->info.sigtype == SIGTYPE_SINGLE)
+               return 0;
+
+       if (!cps->payload_stash) {
+               lwsl_notice("%s: no payload stash\n", __func__);
+               goto bail;
+       }
+
+       apply_external(cps);
+
+       if (lws_cose_val_alg_hash(alg, cps->payload_stash, cps->payload_pos))
+               goto bail;
+lwsl_notice("a %d\n", (int)cps->sig_agg_pos);
+
+       lws_cose_val_alg_destroy(cps, &alg, (const uint8_t *)cps->sig_agg,
+                                cps->sig_agg_pos);
+
+       return 0;
+
+bail:
+       return 1;
+}
+
+#if defined(VERBOSE)
+static const char * const reason_names[] = {
+       "LECPCB_CONSTRUCTED",
+       "LECPCB_DESTRUCTED",
+       "LECPCB_START",
+       "LECPCB_COMPLETE",
+       "LECPCB_FAILED",
+       "LECPCB_PAIR_NAME",
+       "LECPCB_VAL_TRUE",
+       "LECPCB_VAL_FALSE",
+       "LECPCB_VAL_NULL",
+       "LECPCB_VAL_NUM_INT",
+       "LECPCB_VAL_RESERVED", /* float in lejp */
+       "LECPCB_VAL_STR_START",
+       "LECPCB_VAL_STR_CHUNK",
+       "LECPCB_VAL_STR_END",
+       "LECPCB_ARRAY_START",
+       "LECPCB_ARRAY_END",
+       "LECPCB_OBJECT_START",
+       "LECPCB_OBJECT_END",
+       "LECPCB_TAG_START",
+       "LECPCB_TAG_END",
+       "LECPCB_VAL_NUM_UINT",
+       "LECPCB_VAL_UNDEFINED",
+       "LECPCB_VAL_FLOAT16",
+       "LECPCB_VAL_FLOAT32",
+       "LECPCB_VAL_FLOAT64",
+       "LECPCB_VAL_SIMPLE",
+       "LECPCB_VAL_BLOB_START",
+       "LECPCB_VAL_BLOB_CHUNK",
+       "LECPCB_VAL_BLOB_END",
+       "LECPCB_ARRAY_ITEM_START",
+       "LECPCB_ARRAY_ITEM_END",
+       "LECPCB_LITERAL_CBOR"
+};
+#endif
+
+static int
+ph_index(struct lws_cose_validate_context *cps)
+{
+       switch (cps->tli) {
+       case ST_OUTER_PROTECTED:
+               return 0;
+       case ST_OUTER_UNPROTECTED:
+               return 1;
+       case ST_INNER_PROTECTED:
+               return 2;
+       case ST_INNER_UNPROTECTED:
+               return 3;
+       }
+
+       assert(0);
+       return 0;
+}
+
+static signed char
+cb_cose_sig(struct lecp_ctx *ctx, char reason)
+{
+       struct lws_cose_validate_context *cps =
+                       (struct lws_cose_validate_context *)ctx->user;
+       lws_cose_validate_param_stack_t *sl;
+       struct lws_gencrypto_keyelem *ke;
+       lws_cose_sig_alg_t *alg;
+       uint8_t t[9];
+       size_t s;
+       int hi;
+
+#if defined(VERBOSE)
+       lwsl_notice("%s: %s, tli %s, sub %d, ppos %d, sp %d\n", __func__,
+                       reason_names[reason & 0x1f], cose_sections[cps->tli],
+                       cps->sub, ctx->pst[ctx->pst_sp].ppos, cps->sp);
+#endif
+
+       switch (reason) {
+       case LECPCB_CONSTRUCTED:
+               break;
+
+       case LECPCB_TAG_START:
+
+               lwsl_notice("%s: tag sigtype %d\n", __func__, cps->info.sigtype);
+
+               switch (cps->info.sigtype) {
+               default:
+                       assert(0);
+                       break;
+               case SIGTYPE_UNKNOWN:
+                       /* it means use the tag value to set the type */
+                       switch (ctx->item.u.u64) {
+                       case LWSCOAP_CONTENTFORMAT_COSE_SIGN:
+                               cps->info.sigtype = SIGTYPE_MULTI;
+                               break;
+                       case LWSCOAP_CONTENTFORMAT_COSE_SIGN1:
+                               cps->info.sigtype = SIGTYPE_SINGLE;
+                               break;
+//                     case LWSCOAP_CONTENTFORMAT_COSE_SIGN__:
+//                             cps->info.sigtype = SIGTYPE_COUNTERSIGNED;
+//                             break;
+                       case LWSCOAP_CONTENTFORMAT_COSE_MAC0:
+                               cps->info.sigtype = SIGTYPE_MAC0;
+                               break;
+                       case LWSCOAP_CONTENTFORMAT_COSE_MAC:
+                               cps->info.sigtype = SIGTYPE_MAC;
+                               break;
+                       default:
+                               goto unexpected_tag;
+                       }
+                       break;
+               case SIGTYPE_MULTI:
+                       if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_SIGN)
+                               goto unexpected_tag;
+                       break;
+               case SIGTYPE_SINGLE:
+                       if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_SIGN1)
+                               goto unexpected_tag;
+                       break;
+               case SIGTYPE_COUNTERSIGNED:
+                       if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_SIGN)
+                               goto unexpected_tag;
+                       break;
+               case SIGTYPE_MAC0:
+                       if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_MAC0)
+                               goto unexpected_tag;
+                       break;
+               case SIGTYPE_MAC:
+                       if (ctx->item.u.u64 != LWSCOAP_CONTENTFORMAT_COSE_MAC) {
+unexpected_tag:
+                               lwsl_warn("%s: unexpected tag %d\n", __func__,
+                                               (int)ctx->item.u.u64);
+                               goto bail;
+                       }
+                       break;
+               }
+
+               cps->depth++;
+               break;
+
+       case LECPCB_ARRAY_ITEM_START:
+
+               if (cps->sub)
+                       break;
+
+               if (ctx->pst[ctx->pst_sp].ppos == 4 ||
+                   ctx->pst[ctx->pst_sp].ppos == 6) {
+                       switch (cps->tli) {
+                       case ST_INNER_UNPROTECTED:
+                       case ST_INNER_PROTECTED:
+                               hi = ph_index(cps);
+                               sl = &cps->st[cps->sp];
+                               sl->ph_pos[hi] = 0;
+                               lecp_parse_report_raw(ctx, 1);
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               }
+
+               if (ctx->pst[ctx->pst_sp].ppos != 2)
+                       break;
+
+               switch (cps->tli) {
+               case ST_OUTER_UNPROTECTED:
+               case ST_OUTER_PROTECTED:
+                       /*
+                        * Holy type confusion, Batman... this is a CBOR bstr
+                        * containing valid CBOR that must also be parsed as
+                        * part of the containing array... we need to collect
+                        * it anyway since it is part of the signing plaintext
+                        * in bstr form, let's get it and then parse it at the
+                        * END of the bstr.
+                        */
+                       lecp_parse_report_raw(ctx, 1);
+                       break;
+
+               case ST_OUTER_PAYLOAD:
+                       if (cps->info.sigtype != SIGTYPE_SINGLE)
+                               break;
+
+                       if (create_alg(ctx, cps))
+                               goto bail;
+
+                       break;
+
+               case ST_OUTER_SIGN_SIGARRAY:
+                       cps->tli = ST_INNER_PROTECTED;
+                       break;
+               }
+               break;
+
+       case LECPCB_ARRAY_ITEM_END:
+
+               if (cps->sub)
+                       break;
+
+               if (ctx->pst[ctx->pst_sp].ppos == 2) {
+                       sl = &cps->st[cps->sp];
+                       switch (cps->tli) {
+                       case ST_OUTER_UNPROTECTED:
+                               break;
+                               /* fallthru */
+                       case ST_OUTER_PROTECTED:
+                               lecp_parse_report_raw(ctx, 0);
+
+                               hi = ph_index(cps);
+
+                               if (!sl->ph_pos[hi] || cps->sub)
+                                       break;
+
+                               cps->sub = 1;
+                               s = (size_t)sl->ph_pos[hi];
+
+                               if (lecp_parse_subtree(&cps->ctx,
+                                                      sl->ph[hi] + 3, s) !=
+                                                             LECP_CONTINUE)
+                                       goto bail;
+                               cps->sub = 0;
+                               break;
+
+                       case ST_OUTER_PAYLOAD:
+                               switch (cps->info.sigtype) {
+                               case SIGTYPE_MULTI:
+                                       cps->tli = ST_OUTER_SIGN_SIGARRAY - 1;
+                                       break;
+                               case SIGTYPE_MAC:
+                               case SIGTYPE_MAC0:
+                                       cps->tli = ST_OUTER_MACTAG - 1;
+                                       break;
+                               case SIGTYPE_COUNTERSIGNED:
+                                       break;
+                               default:
+                                       break;
+                               }
+                               break;
+
+                       case ST_OUTER_SIGN1_SIGNATURE:
+                       case ST_OUTER_MACTAG:
+                               cps->sp++;
+                               cps->tli = ST_INNER_PROTECTED - 1;
+                               break;
+
+                       case ST_INNER_UNPROTECTED:
+                               lwsl_notice("ST_INNER_UNPROTECTED end\n");
+                               break;
+                       case ST_INNER_PROTECTED:
+                               lwsl_notice("ST_INNER_PROTECTED end\n");
+                               break;
+
+                       case ST_INNER_EXCESS:
+                       case ST_OUTER_SIGN_SIGARRAY:
+                               cps->tli--; /* so no change */
+                               break;
+                       }
+                       if (!cps->sub)
+                               cps->tli++;
+               }
+
+               if (ctx->pst[ctx->pst_sp].ppos >= 4) {
+                       uint8_t *p;
+                       uint8_t u;
+                       size_t s1;
+
+                       switch (cps->tli) {
+                       case ST_INNER_UNPROTECTED:
+                       case ST_INNER_PROTECTED:
+
+                               hi = ph_index(cps);
+                               sl = &cps->st[cps->sp];
+                               p = sl->ph[hi] + 3;
+                               lecp_parse_report_raw(ctx, 0);
+
+                               if (!sl->ph_pos[hi] || cps->sub) {
+                                       if (!cps->sub)
+                                               cps->tli++;
+                                       break;
+                               }
+
+                               cps->sub = 1;
+                               s = (size_t)sl->ph_pos[hi];
+
+                               /*
+                                * somehow the raw captures the
+                                * initial BSTR container length,
+                                * let's strip it
+                                */
+
+                               u = (*p) & LWS_CBOR_SUBMASK;
+                               if (((*p) & LWS_CBOR_MAJTYP_MASK) ==
+                                                       LWS_CBOR_MAJTYP_BSTR) {
+                                       s1 = 1;
+                                       if (u == LWS_CBOR_1)
+                                               s1 = 2;
+                                       else if (u == LWS_CBOR_2)
+                                               s1 = 3;
+                                       else if (u == LWS_CBOR_4)
+                                               s1 = 5;
+                                       else if (u == LWS_CBOR_8)
+                                               s1 = 9;
+
+                                       if (s1 > s)
+                                               goto bail;
+
+                                       sl->ph_pos[hi] = (int)
+                                               (sl->ph_pos[hi] - (ssize_t)s1);
+                                       s = s - s1;
+                                       memmove(p, p + s1, s);
+                               }
+
+                               if (lecp_parse_subtree(&cps->ctx, p, s) !=
+                                                               LECP_CONTINUE)
+                                       goto bail;
+
+                               cps->sub = 0;
+
+                               if (!cps->sub)
+                                       cps->tli++;
+                               break;
+
+                       case ST_INNER_SIGNATURE:
+                               if (cps->info.sigtype == SIGTYPE_MAC) {
+                                       // lwsl_err("Y: alg %d\n", (int)cps->alg);
+                                       if (create_alg(ctx, cps))
+                                               goto bail;
+                               }
+                               cps->tli++;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               break;
+
+       case LECPCB_VAL_NUM_INT:
+       case LECPCB_VAL_NUM_UINT:
+               switch (cps->tli) {
+               case ST_INNER_PROTECTED:
+               case ST_INNER_UNPROTECTED:
+               case ST_INNER_SIGNATURE:
+               case ST_OUTER_PROTECTED:
+               case ST_OUTER_UNPROTECTED:
+                       if (lecp_parse_map_is_key(ctx)) {
+                               cps->map_key = ctx->item.u.i64;
+                               // lwsl_notice("%s: key %d\n", __func__, (int)cps->map_key);
+                               break;
+                       }
+
+                       // lwsl_notice("%s: key %d val %d\n", __func__, (int)cps->map_key, (int)ctx->item.u.i64);
+
+                       if (cps->map_key == LWSCOSE_WKL_ALG) {
+                               sl = &cps->st[cps->sp];
+                               cps->map_key = 0;
+                               if (cps->tli == ST_INNER_PROTECTED ||
+                                    cps->tli == ST_INNER_UNPROTECTED ||
+                                    cps->tli == ST_INNER_SIGNATURE) {
+                                       sl->alg = ctx->item.u.i64;
+                                       if (!cps->st[0].alg)
+                                               cps->st[0].alg = sl->alg;
+                               } else
+                                       sl->alg = ctx->item.u.i64;
+                               break;
+                       }
+                       break;
+               }
+               break;
+
+       case LECPCB_VAL_STR_END:
+               switch (cps->tli) {
+               case ST_OUTER_UNPROTECTED:
+                       break;
+               }
+               break;
+
+       case LECPCB_VAL_BLOB_START:
+
+               lwsl_notice("%s: blob size %d\n", __func__, (int)ctx->item.u.u64);
+
+               if (cps->tli == ST_OUTER_SIGN1_SIGNATURE ||
+                   cps->tli == ST_INNER_SIGNATURE) {
+                       if (ctx->item.u.u64 > sizeof(cps->sig_agg))
+                               goto bail;
+                       cps->sig_agg_pos = 0;
+                       break;
+               }
+
+               if (cps->tli != ST_OUTER_PAYLOAD)
+                       break;
+
+               if (apply_external(cps)) {
+                       lwsl_notice("%s: ext\n", __func__);
+                       goto bail;
+               }
+
+               s = bstr_len(t, sizeof(t), LWS_CBOR_MAJTYP_BSTR,
+                            ctx->item.u.u64);
+
+               if (cps->info.sigtype == SIGTYPE_SINGLE) {
+                       alg = lws_container_of(cps->algs.head,
+                                              lws_cose_sig_alg_t, list);
+                       if (!alg)
+                               /* expected if no key */
+                               break;
+                       if (lws_cose_val_alg_hash(alg, t, s)) {
+                               lwsl_notice("%s: hash failed\n", __func__);
+                               goto bail;
+                       }
+
+                       break;
+               }
+
+               cps->payload_stash_size = (size_t)(ctx->item.u.u64 + s);
+               cps->payload_stash = lws_malloc(cps->payload_stash_size,
+                                                       __func__);
+               if (!cps->payload_stash) {
+                       lwsl_notice("%s: oom\n", __func__);
+                       goto bail;
+               }
+
+               memcpy(cps->payload_stash, t, s);
+               cps->payload_pos = s;
+
+               break;
+
+       case LECPCB_VAL_BLOB_CHUNK:
+               switch (cps->tli) {
+               case ST_OUTER_PAYLOAD:
+
+                       if (cps->info.pay_cb && ctx->npos)
+                               cps->info.pay_cb(cps, cps->info.pay_opaque,
+                                                (uint8_t *)ctx->buf, ctx->npos);
+
+                       if (cps->payload_stash) {
+                               if (cps->payload_pos + ctx->npos >
+                                       cps->payload_stash_size)
+                                       goto bail;
+                               memcpy(cps->payload_stash + cps->payload_pos,
+                                               ctx->buf, ctx->npos);
+                               cps->payload_pos += ctx->npos;
+                               break;
+                       }
+                       alg = lws_container_of(cps->algs.head,
+                                              lws_cose_sig_alg_t, list);
+                       if (!alg)
+                               /* expected if no key */
+                               break;
+                       if (ctx->npos &&
+                           lws_cose_val_alg_hash(alg, (uint8_t *)ctx->buf,
+                                             ctx->npos)) {
+                               lwsl_notice("%s: chunk fail\n", __func__);
+                               goto bail;
+                       }
+                       break;
+               case ST_INNER_SIGNATURE:
+               case ST_OUTER_SIGN1_SIGNATURE:
+                       /* the sig is big compared to ctx->buf... we need to
+                        * stash it then */
+                       memcpy(cps->sig_agg + cps->sig_agg_pos, ctx->buf,
+                               ctx->npos);
+                       cps->sig_agg_pos = cps->sig_agg_pos + ctx->npos;
+                       break;
+               }
+               break;
+
+       case LECPCB_VAL_BLOB_END:
+               switch (cps->tli) {
+
+               case ST_INNER_SIGNATURE:
+                       if (cps->info.sigtype == SIGTYPE_MULTI) {
+                               memcpy(cps->sig_agg + cps->sig_agg_pos, ctx->buf,
+                                       ctx->npos);
+                               cps->sig_agg_pos = cps->sig_agg_pos + ctx->npos;
+                               // lwsl_err("Y: alg %d\n", (int)cps->alg);
+                               if (create_alg(ctx, cps))
+                                       goto bail;
+                               break;
+                       }
+                       if (cps->info.sigtype != SIGTYPE_MAC)
+                               break;
+                       /* fallthru */
+               case ST_OUTER_PROTECTED:
+               case ST_OUTER_UNPROTECTED:
+               case ST_INNER_PROTECTED:
+               case ST_INNER_UNPROTECTED:
+                       if (cps->map_key == LWSCOSE_WKL_KID) {
+                               sl = &cps->st[cps->sp];
+                               ke = &sl->kid;
+                               if (ke->buf)
+                                       lws_free(ke->buf);
+                               ke->buf = lws_malloc(ctx->npos, __func__);
+                               if (!ke->buf)
+                                       goto bail;
+                               ke->len = ctx->npos;
+                               memcpy(ke->buf, ctx->buf, ctx->npos);
+                               cps->map_key = 0;
+                       }
+                       break;
+
+               case ST_OUTER_PAYLOAD:
+                       if (cps->info.pay_cb && ctx->npos)
+                               cps->info.pay_cb(cps, cps->info.pay_opaque,
+                                                (uint8_t *)ctx->buf, ctx->npos);
+                       if (cps->payload_stash) {
+                               if (cps->payload_pos + ctx->npos >
+                                       cps->payload_stash_size)
+                                       goto bail;
+                               memcpy(cps->payload_stash + cps->payload_pos,
+                                               ctx->buf, ctx->npos);
+                               cps->payload_pos += ctx->npos;
+                               break;
+                       }
+                       alg = lws_container_of(cps->algs.head,
+                                              lws_cose_sig_alg_t, list);
+                       if (!alg)
+                               /* expected if no key */
+                               break;
+
+                       if (ctx->npos &&
+                           lws_cose_val_alg_hash(alg, (uint8_t *)ctx->buf,
+                                             ctx->npos))
+                               goto bail;
+                       break;
+
+               case ST_OUTER_SIGN1_SIGNATURE:
+                       if (cps->info.sigtype == SIGTYPE_MULTI)
+                               break;
+
+                       memcpy(cps->sig_agg + cps->sig_agg_pos, ctx->buf,
+                               ctx->npos);
+                       cps->sig_agg_pos += ctx->npos;
+
+                       alg = lws_container_of(cps->algs.head,
+                                       lws_cose_sig_alg_t, list);
+                       lwsl_notice("b\n");
+                       if (alg)
+                               lws_cose_val_alg_destroy(cps, &alg,
+                                                        cps->sig_agg,
+                                                        cps->sig_agg_pos);
+                       break;
+
+               case ST_OUTER_MACTAG:
+                       if (cps->mac_pos + ctx->npos > sizeof(cps->mac))
+                               goto bail;
+                       memcpy(cps->mac + cps->mac_pos, ctx->buf, ctx->npos);
+                       cps->mac_pos += ctx->npos;
+
+                       if (cps->info.sigtype == SIGTYPE_MAC0) {
+                               if (create_alg(ctx, cps))
+                                       goto bail;
+                       }
+
+                       break;
+               }
+               break;
+
+       case LECPCB_LITERAL_CBOR:
+               /* only used for protected headers */
+               switch (cps->tli) {
+               case ST_INNER_PROTECTED:
+               case ST_OUTER_PROTECTED:
+               case ST_INNER_UNPROTECTED:
+               case ST_OUTER_UNPROTECTED:
+                       sl = &cps->st[cps->sp];
+                       hi = ph_index(cps);
+                       if (sl->ph_pos[hi] + 3 + ctx->cbor_pos >
+                                       (int)sizeof(sl->ph[hi]) - 3)
+                               /* more protected cbor than we can handle */
+                               goto bail;
+                       memcpy(sl->ph[hi] + 3 + sl->ph_pos[hi], ctx->cbor,
+                              ctx->cbor_pos);
+                       sl->ph_pos[hi] += ctx->cbor_pos;
+                       break;
+               }
+       }
+
+       return 0;
+
+bail:
+
+       return -1;
+}
+
+struct lws_cose_validate_context *
+lws_cose_validate_create(const lws_cose_validate_create_info_t *info)
+{
+       struct lws_cose_validate_context *cps;
+
+       /* you have to provide at least one key in a cose_keyset */
+       assert(info->keyset);
+       /* you have to provide an lws_context (for crypto random) */
+       assert(info->cx);
+
+       cps = lws_zalloc(sizeof(*cps), __func__);
+       if (!cps)
+               return NULL;
+
+       cps->info                       = *info;
+       cps->tli                        = ST_OUTER_PROTECTED;
+
+       lecp_construct(&cps->ctx, cb_cose_sig, cps, NULL, 0);
+
+       return cps;
+}
+
+int
+lws_cose_validate_chunk(struct lws_cose_validate_context *cps,
+                       const uint8_t *in, size_t in_len, size_t *used_in)
+{
+       int n;
+
+       n = lecp_parse(&cps->ctx, in, in_len);
+       if (used_in)
+               *used_in = cps->ctx.used_in;
+
+       if (n == LECP_CONTINUE)
+               return LECP_CONTINUE;
+
+       lecp_destruct(&cps->ctx);
+
+       return n;
+}
+
+lws_dll2_owner_t *
+lws_cose_validate_results(struct lws_cose_validate_context *cps)
+{
+       return &cps->results;
+}
+
+void
+lws_cose_validate_destroy(struct lws_cose_validate_context **_cps)
+{
+       struct lws_cose_validate_context *cps = *_cps;
+
+       if (!cps)
+               return;
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
+                                  lws_dll2_get_head(&cps->algs)) {
+               lws_cose_sig_alg_t *alg = lws_container_of(p,
+                                               lws_cose_sig_alg_t, list);
+
+               lws_dll2_remove(p);
+               lws_cose_val_alg_destroy(cps, &alg, NULL, 0);
+       } lws_end_foreach_dll_safe(p, tp);
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
+                                  lws_dll2_get_head(&cps->results)) {
+               lws_cose_validate_res_t *res = lws_container_of(p,
+                                       lws_cose_validate_res_t, list);
+
+               lws_dll2_remove(p);
+               lws_free(res);
+       } lws_end_foreach_dll_safe(p, tp);
+
+       lws_free_set_NULL(cps->payload_stash);
+
+       lwsac_free(&cps->ac);
+
+       while (cps->sp >= 0) {
+               if (cps->st[cps->sp].kid.buf)
+                       lws_free(cps->st[cps->sp].kid.buf);
+               cps->sp--;
+       }
+
+       lws_free_set_NULL(*_cps);
+}
diff --git a/lib/cose/cose_validate_alg.c b/lib/cose/cose_validate_alg.c
new file mode 100644 (file)
index 0000000..9f2e888
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-cose.h"
+
+lws_cose_sig_alg_t *
+lws_cose_val_alg_create(struct lws_context *cx, lws_cose_key_t *ck,
+                       cose_param_t cose_alg, int op)
+{
+       lws_cose_sig_alg_t *alg = lws_zalloc(sizeof(*alg), __func__);
+       struct lws_gencrypto_keyelem *ke;
+       enum lws_genhmac_types ghm;
+       enum lws_genhash_types gh;
+       const char *crv;
+
+       if (!alg)
+               return NULL;
+
+       alg->cose_alg = cose_alg;
+       alg->cose_key = ck;
+
+       switch (cose_alg) {
+
+       /* ECDSA algs */
+
+       case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
+               crv = "P-256";
+               gh = LWS_GENHASH_TYPE_SHA256;
+               alg->keybits = 256;
+               goto ecdsa;
+       case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
+               crv = "P-384";
+               gh = LWS_GENHASH_TYPE_SHA384;
+               alg->keybits = 384;
+               goto ecdsa;
+       case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
+               crv = "P-521";
+               gh = LWS_GENHASH_TYPE_SHA512;
+               alg->keybits = 521;
+ecdsa:
+
+               /* the key is good for this? */
+
+               if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_EC2, cose_alg,
+                                       op, crv))
+                       goto bail_ecdsa;
+
+               if (lws_genhash_init(&alg->hash_ctx, gh))
+                       goto bail_ecdsa;
+
+               if (lws_genecdsa_create(&alg->u.ecdsactx, cx, lws_ec_curves)) {
+                       lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
+                                   __func__);
+                       goto bail_ecdsa1;
+               }
+
+               if (lws_genecdsa_set_key(&alg->u.ecdsactx, ck->e)) {
+                       lwsl_notice("%s: ec key import fail\n", __func__);
+                       goto bail_ecdsa2;
+               }
+
+               break;
+
+       /* HMAC algs */
+
+       case LWSCOSE_WKAHMAC_256_64:
+               ghm = LWS_GENHMAC_TYPE_SHA256;
+               alg->keybits = 64;
+               goto hmac;
+       case LWSCOSE_WKAHMAC_256_256:
+               ghm = LWS_GENHMAC_TYPE_SHA256;
+               alg->keybits = 256;
+               goto hmac;
+       case LWSCOSE_WKAHMAC_384_384:
+               ghm = LWS_GENHMAC_TYPE_SHA384;
+               alg->keybits = 384;
+               goto hmac;
+       case LWSCOSE_WKAHMAC_512_512:
+               ghm = LWS_GENHMAC_TYPE_SHA512;
+               alg->keybits = 512;
+
+hmac:
+               if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_SYMMETRIC,
+                                       cose_alg, op, NULL))
+                       goto bail_hmac;
+
+               ke = &ck->e[LWS_GENCRYPTO_OCT_KEYEL_K];
+               if (lws_genhmac_init(&alg->u.hmacctx, ghm, ke->buf, ke->len))
+                       goto bail_hmac;
+
+               break;
+
+       /* RSASSA algs */
+
+       case LWSCOSE_WKARSA_ALG_RS256:
+               gh = LWS_GENHASH_TYPE_SHA256;
+               goto rsassa;
+
+       case LWSCOSE_WKARSA_ALG_RS384:
+               gh = LWS_GENHASH_TYPE_SHA384;
+               goto rsassa;
+
+       case LWSCOSE_WKARSA_ALG_RS512:
+               gh = LWS_GENHASH_TYPE_SHA512;
+
+rsassa:
+               if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_RSA, cose_alg,
+                                       op, NULL))
+                       goto bail_hmac;
+               alg->keybits = (int)ck->e[LWS_GENCRYPTO_RSA_KEYEL_N].len * 8;
+
+               if (lws_genhash_init(&alg->hash_ctx, gh))
+                       goto bail_ecdsa;
+
+               if (lws_genrsa_create(&alg->u.rsactx, ck->e, cx,
+                                     LGRSAM_PKCS1_1_5, gh)) {
+                       lwsl_notice("%s: lws_genrsa_create fail\n", __func__);
+                       goto bail_ecdsa1;
+               }
+               break;
+
+       default:
+               lwsl_warn("%s: unsupported alg %lld\n", __func__,
+                               (long long)cose_alg);
+               goto bail_hmac;
+       }
+
+       return alg;
+
+bail_ecdsa2:
+       lws_genec_destroy(&alg->u.ecdsactx);
+bail_ecdsa1:
+       lws_genhash_destroy(&alg->hash_ctx, NULL);
+bail_ecdsa:
+       lws_free(alg);
+
+       lwsl_notice("%s: failed\n", __func__);
+
+       return NULL;
+
+bail_hmac:
+       lws_free(alg);
+
+       return NULL;
+}
+
+int
+lws_cose_val_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len)
+{
+#if defined(VERBOSE)
+       lwsl_hexdump_warn(in, in_len);
+#endif
+
+       switch (alg->cose_alg) {
+       case LWSCOSE_WKAHMAC_256_64:
+       case LWSCOSE_WKAHMAC_256_256:
+       case LWSCOSE_WKAHMAC_384_384:
+       case LWSCOSE_WKAHMAC_512_512:
+               return lws_genhmac_update(&alg->u.hmacctx, in, in_len);
+       }
+
+       return lws_genhash_update(&alg->hash_ctx, in, in_len);
+}
+
+void
+lws_cose_val_alg_destroy(struct lws_cose_validate_context *cps,
+                        lws_cose_sig_alg_t **_alg, const uint8_t *against,
+                        size_t against_len)
+{
+       uint8_t digest[LWS_GENHASH_LARGEST];
+       lws_cose_sig_alg_t *alg = *_alg;
+       lws_cose_validate_res_t *res;
+       size_t hs, shs;
+       int keybits;
+       uint8_t ht;
+
+       lws_dll2_remove(&alg->list);
+       ht = alg->hash_ctx.type;
+       keybits = alg->keybits;
+
+       res = lws_zalloc(sizeof(*res), __func__);
+       if (res) {
+
+               res->cose_key = alg->cose_key;
+               res->cose_alg = alg->cose_alg;
+               res->result = -999;
+
+               lws_dll2_add_tail(&res->list, &cps->results);
+       }
+
+       switch (alg->cose_alg) {
+       case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
+       case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
+       case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
+               hs = lws_genhash_size(alg->hash_ctx.type);
+               lws_genhash_destroy(&alg->hash_ctx, digest);
+
+               lwsl_notice("%d %d %d\n", (int)hs, (int)keybits, (int)against_len);
+
+               if (res && against)
+                       res->result = lws_genecdsa_hash_sig_verify_jws(
+                                               &alg->u.ecdsactx, digest, ht,
+                                               keybits, against, against_len);
+               lws_genec_destroy(&alg->u.ecdsactx);
+               break;
+
+       case LWSCOSE_WKAHMAC_256_64:
+       case LWSCOSE_WKAHMAC_256_256:
+       case LWSCOSE_WKAHMAC_384_384:
+       case LWSCOSE_WKAHMAC_512_512:
+               shs = hs = lws_genhmac_size(alg->u.hmacctx.type);
+               if (alg->cose_alg == LWSCOSE_WKAHMAC_256_64)
+                       shs = 8;
+
+               if (lws_genhmac_destroy(&alg->u.hmacctx, digest)) {
+                       lwsl_err("%s: destroy failed\n", __func__);
+                       break;
+               }
+
+               if (cps->mac_pos != shs) {
+                       lwsl_warn("%s: mac wrong size\n", __func__);
+                       /* we can't compare it, leave it at fail */
+                       break;
+               }
+               if (res && against) {
+                       res->result = lws_timingsafe_bcmp(digest, cps->mac,
+                                                               (uint32_t)shs);
+                       if (res->result)
+                               lwsl_warn("%s: hash mismatch\n", __func__);
+               }
+               break;
+
+       case LWSCOSE_WKARSA_ALG_RS256:
+       case LWSCOSE_WKARSA_ALG_RS384:
+       case LWSCOSE_WKARSA_ALG_RS512:
+
+               if (!lws_genhash_destroy(&alg->hash_ctx, digest) &&
+                   !alg->failed &&
+                   lws_genrsa_hash_sig_verify(&alg->u.rsactx, digest,
+                                        alg->hash_ctx.type,
+                                        against, against_len) >= 0) {
+                       if (res)
+                               res->result = 0;
+               } else
+                       lwsl_err("%s: lws_genrsa_hash_verify\n", __func__);
+
+               lws_genrsa_destroy(&alg->u.rsactx);
+               break;
+       }
+
+       lws_free_set_NULL(*_alg);
+}
diff --git a/lib/cose/private-lib-cose.h b/lib/cose/private-lib-cose.h
new file mode 100644 (file)
index 0000000..97cc265
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define VERBOSE
+
+#define MAX_BLOBBED_PARAMS             96 /* largest bstr-encoded params */
+
+enum {
+       ST_UNKNOWN,
+
+       ST_OUTER_PROTECTED,
+       ST_OUTER_UNPROTECTED,
+       ST_OUTER_PAYLOAD,
+       ST_OUTER_SIGN1_SIGNATURE,
+
+       ST_OUTER_SIGN_SIGARRAY,
+
+       ST_OUTER_MACTAG,
+
+       ST_INNER_PROTECTED,
+       ST_INNER_UNPROTECTED,
+       ST_INNER_SIGNATURE,
+
+       ST_INNER_EXCESS,
+};
+
+typedef struct lws_cose_sig_alg {
+       lws_dll2_t                      list;
+       uint8_t                         rhash[512];
+       const lws_cose_key_t            *cose_key;
+       struct lws_genhash_ctx          hash_ctx;
+       union {
+               struct lws_genec_ctx    ecdsactx;
+               struct lws_genrsa_ctx   rsactx;
+               struct lws_genhmac_ctx  hmacctx;
+       } u;
+       cose_param_t                    cose_alg;
+       int                             keybits;
+       int                             rhash_len;
+
+       char                            failed;
+       char                            completed;
+} lws_cose_sig_alg_t;
+
+typedef struct lws_cose_validate_param_stack {
+       uint8_t                         ph[4][MAX_BLOBBED_PARAMS];
+       int                             ph_pos[4];
+       struct lws_gencrypto_keyelem    kid;
+       cose_param_t                    alg;
+} lws_cose_validate_param_stack_t;
+
+struct lws_cose_validate_context {
+       lws_cose_validate_create_info_t info;
+       uint8_t                         mac[LWS_GENHASH_LARGEST];
+       uint8_t                         sig_agg[512];
+       lws_cose_validate_param_stack_t st[3];
+       lws_dll2_owner_t                algs;
+       lws_dll2_owner_t                results;
+       uint8_t                         *payload_stash;
+       struct lwsac                    *ac;
+       struct lecp_ctx                 ctx;
+       void                            *user;
+
+       size_t                          payload_pos;
+       size_t                          payload_stash_size;
+
+       int                             seen;
+       int                             depth;
+
+       int                             outer;
+       size_t                          mac_pos;
+       size_t                          sig_agg_pos;
+
+       cose_param_t                    map_key; /* parsing temp before val */
+
+       int                             tli; /* toplevel item */
+       int                             sp;
+
+       uint8_t                         sub;
+};
+
+struct lws_cose_sign_context {
+       lws_cose_sign_create_info_t     info;
+
+       lws_dll2_owner_t                algs;
+       lws_cose_sig_alg_t              *alg;
+
+       size_t                          rem_pay;
+       enum lws_cose_sig_types         type; /* computed */
+       int                             flags;
+
+       size_t                          along;
+
+       int                             tli;
+
+       char                            subsequent;
+};
+
+extern const uint8_t *sig_mctx[];
+extern uint8_t sig_mctx_len[];
+extern const char *cose_sections[];
+
+lws_cose_sig_alg_t *
+lws_cose_val_alg_create(struct lws_context *cx, lws_cose_key_t *ck,
+                   cose_param_t cose_alg, int op);
+
+int
+lws_cose_val_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len);
+
+void
+lws_cose_val_alg_destroy(struct lws_cose_validate_context *cps,
+                    lws_cose_sig_alg_t **_alg, const uint8_t *against,
+                    size_t against_len);
+
+lws_cose_sig_alg_t *
+lws_cose_sign_alg_create(struct lws_context *cx, const lws_cose_key_t *ck,
+                   cose_param_t cose_alg, int op);
+
+int
+lws_cose_sign_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len);
+
+void
+lws_cose_sign_alg_complete(lws_cose_sig_alg_t *alg);
+
+void
+lws_cose_sign_alg_destroy(lws_cose_sig_alg_t **_alg);
+
diff --git a/lib/drivers/CMakeLists.txt b/lib/drivers/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1e1354b
--- /dev/null
@@ -0,0 +1,30 @@
+list(APPEND SOURCES
+        drivers/display/lws-display.c
+        drivers/display/ssd1306-i2c.c
+        drivers/display/ili9341-spi.c
+       drivers/i2c/lws-i2c.c
+        drivers/i2c/bitbang/lws-bb-i2c.c
+        drivers/spi/lws-spi.c
+        drivers/spi/bitbang/lws-bb-spi.c
+       drivers/button/lws-button.c
+       drivers/led/led-gpio.c
+       drivers/led/led-seq.c
+       drivers/pwm/pwm.c
+       drivers/settings/settings.c
+)
+
+if (LWS_WITH_NETWORK)
+       list(APPEND SOURCES
+               drivers/netdev/netdev.c
+               drivers/netdev/wifi.c)
+endif()
+
+if (LWS_ESP_PLATFORM)
+       list(APPEND SOURCES
+               plat/freertos/esp32/drivers/gpio-esp32.c
+               plat/freertos/esp32/drivers/pwm-esp32.c
+               )
+endif()
+
+exports_to_parent_scope()
+
diff --git a/lib/drivers/README.md b/lib/drivers/README.md
new file mode 100644 (file)
index 0000000..a18dfda
--- /dev/null
@@ -0,0 +1,44 @@
+# lws meta-drivers
+
+Although drivers in lws (enabled in cmake by `LWS_WITH_DRIVERS`) provide
+actual drivers for some devices like I2C OLED controllers, their main job is
+to conceal from user code the underlying OS APIs being used to interface
+to the SoC hardware assets.
+
+CMake already allows lws to be platform-agnostic for build, the plat adaptations
+allow lws to be platform-agnostic within itself for runtime.  The lws
+drivers intend to extend that agnosticism to user code.
+
+Using this technique on supported OSes frees the user code from dependencies
+on the underlying OS choice... for example, although ESP32 is very good, it
+comes with a highly specific set of apis in esp-idf that mean your code is
+locked in to esp-idf if you follow them.  Esp-idf uses freertos apis for things
+like OS timers, again if you follow those you are locked into freertos, the
+end result is your work is non-portable to other platforms and completely
+dependent on esp.
+
+LWS drivers provide a thin wrapper to eliminate the OS dependencies while
+still taking advantage of the work, drivers and maintenance of the underlying
+OS layer without duplicating them, but bringing the flexibility to retarget
+your work to other scenarios... for example, there is a generic gpio object
+subclassed for specific implementations, an i2c object which may be subclassed
+to use OS drivers or bitbang using the generic gpio object, buttons on top of
+generic gpio, led class that can use generic gpio or pwm interchangeably,
+platform-specific gpio, i2c, pwm implementations that can be used at the generic
+level are defined to use underlying OS native apis and drivers.
+
+## Building on the next layer up
+
+At these generic objects like buttons or led controllers, there is a stable
+codebase used by multiple implementations and the intention is to provide
+best-of-breed features there generically, like
+
+ - sophisticated button press debounce and classification
+
+ - high quality transitions and log-response compensation and mixing for led pwm
+
+ - display dimming timers, blanking timers, generic interaction detection to unblank
+
+which are automatically available on top of any implementation that is ported to
+lws drivers.
+
diff --git a/lib/drivers/button/README.md b/lib/drivers/button/README.md
new file mode 100644 (file)
index 0000000..758823d
--- /dev/null
@@ -0,0 +1,156 @@
+# LWS GPIO Button class drivers
+
+Lws provides an GPIO button controller class, this centralizes handling a set of
+up to 31 buttons for resource efficiency.  Each controller has two OS timers,
+one for interrupt to bottom-half event triggering and another that runs at 5ms
+intervals only when one or more button is down.
+
+Each button has its own active level control and sophisticated state tracking;
+each button can apply its own classification regime, to allow for different
+physical button characteristics, if not overridden a default one is provided.
+
+Both the controller and individual buttons specify names that are used in the
+JSON events produced when the buttons perform actions.
+
+## Button electronic to logical event processing
+
+Buttons are monitored using GPIO interrupts since this is very cheap in the
+usual case no interaction is ongoing.  There is assumed to be one interrupt
+per GPIO, but they are pointed at the same ISR, with an opaque pointer to an
+internal struct passed per-interrupt to differentiate them and bind them to a
+particular button.
+
+The interrupt is set for notification of the active-going edge, usually if
+the button is pulled-up, that's the downgoing edge only.  This avoids any
+ambiguity about the interrupt meaning, although oscillation is common around
+the transition region when the signal is becoming inactive too.
+
+An OS timer is used to schedule a bottom-half handler outside of interrupt
+context.
+
+To combat commonly-seen partial charging of the actual and parasitic network
+around the button causing drift and oscillation, the bottom-half briefly drives
+the button signal to the active level, forcing a more deterministic charge level
+if it reached the point the interrupt was triggered.  This removes much of the
+unpredictable behaviour in the us range.  It would be better done in the ISR
+but many OS apis cannot perform GPIO operations in interrupt context.
+
+The bottom-half makes sure a monitoring timer is enabled, by refcount.  This
+is the engine of the rest of the classification while any button is down.  The
+monitoring timer happens per OS tick or 5ms, whichever is longer.
+
+## Declaring button controllers
+
+An array of button map elements if provided first mapping at least GPIOs to
+button names, and also optionally the classification regime for that button.
+
+Then the button controller definition which points back to the button map.
+
+```
+static const lws_button_map_t bcm[] = {
+       {
+               .gpio                   = GPIO_NUM_0,
+               .smd_interaction_name   = "user"
+       },
+};
+
+static const lws_button_controller_t bc = {
+       .smd_bc_name                    = "bc",
+       .gpio_ops                       = &lws_gpio_plat,
+       .button_map                     = &bcm[0],
+       .active_state_bitmap            = 0,
+       .count_buttons                  = LWS_ARRAY_SIZE(bcm),
+};
+
+       struct lws_button_state *bcs;
+
+       bcs = lws_button_controller_create(context, &bc);
+       if (!bcs) {
+               lwsl_err("%s: could not create buttons\n", __func__);
+               goto spin;
+       }
+```
+
+That is all that is needed for init, button events will be issued on lws_smd
+when buttons are pressed.
+
+### Regime settings
+
+The classification regime is designed to reflect both the user interaction
+style and the characteristics of a particular type of button.
+
+Member|Default|Meaning
+---|---|---
+ms_min_down|20ms|Down events shorter than this are ignored
+ms_min_down_longpress|300ms|Down events longer than this are reported as a long-click
+ms_up_settle|20ms|After the first indication a button is no longer down, the button is ignored for this interval
+ms_doubleclick_grace|120ms|The time allowed after a click to see if a second, double-click, is forthcoming
+ms_repeat_down|0 / disabled|If held down, interval at which to issue `stilldown` events
+flags|LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK|Control which classifications can apply
+
+### lws_smd System Message Distribution Events
+
+The button controller emits system messages of class `LWSSMDCL_INTERACTION`,
+using a JSON formatted payload
+
+```
+{
+       "type":  "button",
+       "src":   "controller-name/button-name",
+       "event": "event-name"
+}
+```
+
+For example, `{"type":"button","src":"bc/user","event":"doubleclick"}`
+
+JSON is used because it is maintainable, extensible, self-documenting and does
+not require a central, fragile-against-versioning specification of mappings.
+Using button names allows the same code to adapt to different hardware or
+button mappings.  Button events may be synthesized for test or other purposes
+cleanly and clearly.
+
+All the events are somewhat filtered, too short glitches from EMI or whatever
+are not reported.  "up" and "down" events are reported for the buttons in case
+the intention is the duration of the press is meaningful to the user code, but
+more typically the user code wants to consume a higher-level classification of
+the interaction, eg, that it can be understood as a single "double-click" event. 
+
+Event name|Meaning
+---|---
+down|The button passes a filter for being down, useful for duration-based response
+stilldown|The regime can be configured to issue "repeat" notifications at intervals
+up|The button has come up, useful for duration-based response
+click|The button activity resulted in a classification as a single-click
+longclick|The button activity resulted in a classification as a long-click
+doubleclick|The button activity resulted in a classification as a double-click
+
+Since double-click detection requires delaying click reporting until it becomes
+clear a second click isn't coming, it is enabled as a possible classification in
+the regime structure and the regime structure chosen per-button.
+
+Typically user code is interested in, eg, a high level classification of what
+the button is doing, eg, a "click" event on a specific button.  Rather than
+perform a JSON parse, these events can be processed as strings cheaply using
+`lws_json_simple_strcmp()`, it's dumb enough to be cheap but smart enough to
+understand enough JSON semantics to be accurate, while retaining the ability to
+change and extend the JSON, eg
+
+```
+       if (!lws_json_simple_strcmp(buf, len, "\"src\":", "bc/user")) {
+               if (!lws_json_simple_strcmp(buf, len, "\"event\":", "click")) {
+                       ...
+               }
+               ...
+       }
+```
+
+### Relationship between up / down and classification
+
+Classification|Sequencing
+---|---
+click|down-up-click (it's classified when it went up and cannot be a longclick)
+longclick|down-longclick-up (it's classified while still down)
+doubleclick|down-up-down-doubleclick-up (classified as soon as second click down long enough)
+
+If the regime is configured for it, any "down" may be followed by one or more
+"stilldown" at intervals if the button is down long enough
diff --git a/lib/drivers/button/lws-button.c b/lib/drivers/button/lws-button.c
new file mode 100644 (file)
index 0000000..43456fb
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Generic GPIO / irq buttons
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "private-lib-core.h"
+
+typedef enum lws_button_classify_states {
+       LBCS_IDLE,              /* nothing happening */
+       LBCS_MIN_DOWN_QUALIFY,
+
+       LBCS_ASSESS_DOWN_HOLD,
+       LBCS_UP_SETTLE1,
+       LBCS_WAIT_DOUBLECLICK,
+       LBCS_MIN_DOWN_QUALIFY2,
+
+       LBCS_WAIT_UP,
+       LBCS_UP_SETTLE2,
+} lws_button_classify_states_t;
+
+/*
+ * This is the opaque, allocated, non-const, dynamic footprint of the
+ * button controller
+ */
+
+typedef struct lws_button_state {
+#if defined(LWS_PLAT_TIMER_TYPE)
+       LWS_PLAT_TIMER_TYPE                     timer;     /* bh timer */
+       LWS_PLAT_TIMER_TYPE                     timer_mon; /* monitor timer */
+#endif
+       const lws_button_controller_t           *controller;
+       struct lws_context                      *ctx;
+       short                                   mon_refcount;
+       lws_button_idx_t                        enable_bitmap;
+       lws_button_idx_t                        state_bitmap;
+
+       uint16_t                                mon_timer_count;
+       /* incremented each time the mon timer cb happens */
+
+       /* lws_button_each_t per button overallocated after this */
+} lws_button_state_t;
+
+typedef struct lws_button_each {
+       lws_button_state_t                      *bcs;
+       uint16_t                                mon_timer_comp;
+       uint16_t                                mon_timer_repeat;
+       uint8_t                                 state;
+       /**^ lws_button_classify_states_t */
+       uint8_t                                 isr_pending;
+} lws_button_each_t;
+
+#if defined(LWS_PLAT_TIMER_START)
+static const lws_button_regime_t default_regime = {
+       .ms_min_down                    = 20,
+       .ms_min_down_longpress          = 300,
+       .ms_up_settle                   = 20,
+       .ms_doubleclick_grace           = 120,
+       .flags                          = LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK
+};
+#endif
+
+
+/*
+ * This is happening in interrupt context, we have to schedule a bottom half to
+ * do the foreground lws_smd queueing, using, eg, a platform timer.
+ *
+ * All the buttons point here and use one timer per button controller.  An
+ * interrupt here means, "something happened to one or more buttons"
+ */
+#if defined(LWS_PLAT_TIMER_START)
+void
+lws_button_irq_cb_t(void *arg)
+{
+       lws_button_each_t *each = (lws_button_each_t *)arg;
+
+       each->isr_pending = 1;
+       LWS_PLAT_TIMER_START(each->bcs->timer);
+}
+#endif
+
+/*
+ * This is the bottom-half scheduled via a timer set in the ISR.  From here we
+ * are allowed to hold mutexes etc.  We are coming here because any button
+ * interrupt arrived, we have to run another timer that tries to put whatever is
+ * observed on any active button into context and either discard it or arrive at
+ * a definitive event classification.
+ */
+
+#if defined(LWS_PLAT_TIMER_CB)
+static LWS_PLAT_TIMER_CB(lws_button_bh, th)
+{
+       lws_button_state_t *bcs = LWS_PLAT_TIMER_CB_GET_OPAQUE(th);
+       lws_button_each_t *each = (lws_button_each_t *)&bcs[1];
+       const lws_button_controller_t *bc = bcs->controller;
+       size_t n;
+
+       /*
+        * The ISR and bottom-half is shared by all the buttons.  Each gpio
+        * IRQ has an individual opaque ptr pointing to the corresponding
+        * button's dynamic lws_button_each_t, the ISR marks the button's
+        * each->isr_pending and schedules this bottom half.
+        *
+        * So now the bh timer has fired and something to do, we need to go
+        * through all the buttons that have isr_pending set and service their
+        * state.  Intermediate states should start / bump the refcount on the
+        * mon timer.  That's refcounted so it only runs when a button down.
+        */
+
+       for (n = 0; n < bc->count_buttons; n++) {
+
+               if (!each[n].isr_pending)
+                       continue;
+
+               /*
+                * Hide what we're about to do from the delicate eyes of the
+                * IRQ controller...
+                */
+
+               bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
+                                      LWSGGPIO_IRQ_NONE, NULL, NULL);
+
+               each[n].isr_pending = 0;
+
+               /*
+                * Force the network around the switch to the
+                * active level briefly
+                */
+
+               bc->gpio_ops->set(bc->button_map[n].gpio,
+                                 !!(bc->active_state_bitmap & (1 << n)));
+               bc->gpio_ops->mode(bc->button_map[n].gpio, LWSGGPIO_FL_WRITE);
+
+               if (each[n].state == LBCS_IDLE) {
+                       /*
+                        * If this is the first sign something happening on this
+                        * button, make sure the monitor timer is running to
+                        * classify its response over time
+                        */
+
+                       each[n].state = LBCS_MIN_DOWN_QUALIFY;
+                       each[n].mon_timer_comp = bcs->mon_timer_count;
+
+                       if (!bcs->mon_refcount++) {
+#if defined(LWS_PLAT_TIMER_START)
+                               LWS_PLAT_TIMER_START(bcs->timer_mon);
+#endif
+                       }
+               }
+
+               /*
+                * Just for a us or two inbetween here, we're driving it to the
+                * level we were informed by the interrupt it had enetered, to
+                * force to charge on the actual and parasitic network around
+                * the switch to a deterministic-ish state.
+                *
+                * If the switch remains in that state, well, it makes no
+                * difference; if it was a pre-contact and the charge on the
+                * network was left indeterminate, this will dispose it to act
+                * consistently in the short term until the pullup / pulldown
+                * has time to act on it or the switch comes and forces the
+                * network charge state itself.
+                */
+               bc->gpio_ops->mode(bc->button_map[n].gpio, LWSGGPIO_FL_READ);
+
+               /*
+                * We could do a better job manipulating the irq mode according
+                * to the switch state.  But if an interrupt comes and we have
+                * done that, we can't tell if it's from before or after the
+                * mode change... ie, we don't know what the interrupt was
+                * telling us.  We can't trust the gpio state if we read it now
+                * to be related to what the irq from some time before was
+                * trying to tell us.  So always set it back to the same mode
+                * and accept the limitation.
+                */
+
+               bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
+                                      bc->active_state_bitmap & (1 << n) ?
+                                          LWSGGPIO_IRQ_RISING :
+                                          LWSGGPIO_IRQ_FALLING,
+                                             lws_button_irq_cb_t, &each[n]);
+       }
+}
+#endif
+
+#if defined(LWS_PLAT_TIMER_CB)
+static LWS_PLAT_TIMER_CB(lws_button_mon, th)
+{
+       lws_button_state_t *bcs = LWS_PLAT_TIMER_CB_GET_OPAQUE(th);
+       lws_button_each_t *each = (lws_button_each_t *)&bcs[1];
+       const lws_button_controller_t *bc = bcs->controller;
+       const lws_button_regime_t *regime;
+       const char *event_name;
+       int comp_age_ms;
+       char active;
+       size_t n;
+
+       bcs->mon_timer_count++;
+
+       for (n = 0; n < bc->count_buttons; n++) {
+
+               if (each->state == LBCS_IDLE) {
+                       each++;
+                       continue;
+               }
+
+               if (bc->button_map[n].regime)
+                       regime = bc->button_map[n].regime;
+               else
+                       regime = &default_regime;
+
+               comp_age_ms = (bcs->mon_timer_count - each->mon_timer_comp) *
+                               LWS_BUTTON_MON_TIMER_MS;
+
+               active = bc->gpio_ops->read(bc->button_map[n].gpio) ^
+                              (!(bc->active_state_bitmap & (1 << n)));
+
+               // lwsl_notice("%d\n", each->state);
+
+               switch (each->state) {
+               case LBCS_MIN_DOWN_QUALIFY:
+                       /*
+                        * We're trying to figure out if the initial down event
+                        * is a glitch, or if it meets the criteria for being
+                        * treated as the definitive start of some kind of click
+                        * action.  To get past this, he has to be solidly down
+                        * for the time mentioned in the applied regime (at
+                        * least when we sample it).
+                        *
+                        * Significant bounce at the start will abort this try,
+                        * but if it's really down there will be a subsequent
+                        * solid down period... it will simply restart this flow
+                        * from a new interrupt and pass the filter then.
+                        *
+                        * The "brief drive on edge" strategy considerably
+                        * reduces inconsistencies here.  But physical bounce
+                        * will continue to be observed.
+                        */
+
+                       if (!active) {
+                               /* We ignore stuff for a bit after discard */
+                               each->mon_timer_comp = bcs->mon_timer_count;
+                               each->state = LBCS_UP_SETTLE2;
+                               break;
+                       }
+
+                       if (comp_age_ms >= regime->ms_min_down) {
+
+                               /* We made it through the initial regime filter,
+                                * the next step is wait and see if this down
+                                * event evolves into a single/double click or
+                                * we can call it as a long-click
+                                */
+
+                               each->mon_timer_repeat = bcs->mon_timer_count;
+                               each->state = LBCS_ASSESS_DOWN_HOLD;
+                               event_name = "down";
+                               goto emit;
+                       }
+                       break;
+
+               case LBCS_ASSESS_DOWN_HOLD:
+
+                       /*
+                        * How long is he going to hold it?  If he holds it
+                        * past the long-click threshold, we can call it as a
+                        * long-click and do the up processing afterwards.
+                        */
+                       if (comp_age_ms >= regime->ms_min_down_longpress) {
+                               /* call it as a longclick */
+                               event_name = "longclick";
+                               each->state = LBCS_WAIT_UP;
+                               goto emit;
+                       }
+
+                       if (!active) {
+                               /*
+                                * He didn't hold it past the long-click
+                                * threshold... we could end up classifying it
+                                * as either a click or a double-click then.
+                                *
+                                * If double-clicks are not allowed to be
+                                * classified, then we can already classify it
+                                * as a single-click.
+                                */
+                               if (!(regime->flags &
+                                           LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK))
+                                       goto classify_single;
+
+                               /*
+                                * Just wait for the up settle time then start
+                                * looking for a second down.
+                                */
+                               each->mon_timer_comp = bcs->mon_timer_count;
+                               each->state = LBCS_UP_SETTLE1;
+                               event_name = "up";
+                               goto emit;
+                       }
+
+                       goto stilldown;
+
+               case LBCS_UP_SETTLE1:
+                       if (comp_age_ms > regime->ms_up_settle)
+                               /*
+                                * Just block anything for the up settle time
+                                */
+                               each->state = LBCS_WAIT_DOUBLECLICK;
+                       break;
+
+               case LBCS_WAIT_DOUBLECLICK:
+                       if (active) {
+                               /*
+                                * He has gone down again inside the regime's
+                                * doubleclick grace period... he's going down
+                                * the double-click path
+                                */
+                               each->mon_timer_comp = bcs->mon_timer_count;
+                               each->state = LBCS_MIN_DOWN_QUALIFY2;
+                               break;
+                       }
+
+                       if (comp_age_ms >= regime->ms_doubleclick_grace) {
+                               /*
+                                * The grace period expired, the second click
+                                * was either not forthcoming at all, or coming
+                                * quick enough to count: we classify it as a
+                                * single-click
+                                */
+
+                               goto classify_single;
+                       }
+                       break;
+
+               case LBCS_MIN_DOWN_QUALIFY2:
+                       if (!active) {
+
+                               /*
+                                * He went up again too quickly, classify it
+                                * as a single-click.  It could be bounce in
+                                * which case you might want to increase the
+                                * ms_up_settle in the regime
+                                */
+classify_single:
+                               event_name = "click";
+                               each->mon_timer_comp = bcs->mon_timer_count;
+                               each->state = LBCS_UP_SETTLE2;
+                               goto emit;
+                       }
+
+                       if (comp_age_ms == regime->ms_min_down) {
+                               event_name = "down";
+                               goto emit;
+                       }
+
+                       if (comp_age_ms > regime->ms_min_down) {
+                               /*
+                                * It's a double-click
+                                */
+                               event_name = "doubleclick";
+                               each->state = LBCS_WAIT_UP;
+                               goto emit;
+                       }
+                       break;
+
+               case LBCS_WAIT_UP:
+                       if (!active) {
+                               /*
+                                * He has stopped pressing it
+                                */
+                               each->mon_timer_comp = bcs->mon_timer_count;
+                               each->state = LBCS_UP_SETTLE2;
+                               event_name = "up";
+                               goto emit;
+                       }
+stilldown:
+                       if (regime->ms_repeat_down &&
+                           (bcs->mon_timer_count - each->mon_timer_repeat) *
+                            LWS_BUTTON_MON_TIMER_MS > regime->ms_repeat_down) {
+                               each->mon_timer_repeat = bcs->mon_timer_count;
+                               event_name = "stilldown";
+                               goto emit;
+                       }
+                       break;
+
+               case LBCS_UP_SETTLE2:
+                       if (comp_age_ms < regime->ms_up_settle)
+                               break;
+
+                       each->state = LBCS_IDLE;
+                       if (!(--bcs->mon_refcount)) {
+#if defined(LWS_PLAT_TIMER_STOP)
+                               LWS_PLAT_TIMER_STOP(bcs->timer_mon);
+#endif
+                       }
+               }
+
+               each++;
+               continue;
+
+emit:
+               lws_smd_msg_printf(bcs->ctx, LWSSMDCL_INTERACTION,
+                                  "{\"type\":\"button\","
+                                  "\"src\":\"%s/%s\",\"event\":\"%s\"}",
+                                  bc->smd_bc_name,
+                                  bc->button_map[n].smd_interaction_name,
+                                  event_name);
+
+               each++;
+       }
+}
+#endif
+
+struct lws_button_state *
+lws_button_controller_create(struct lws_context *ctx,
+                            const lws_button_controller_t *controller)
+{
+       lws_button_state_t *bcs = lws_zalloc(sizeof(lws_button_state_t) +
+                       (controller->count_buttons * sizeof(lws_button_each_t)),
+                       __func__);
+       lws_button_each_t *each = (lws_button_each_t *)&bcs[1];
+       size_t n;
+
+       if (!bcs)
+               return NULL;
+
+       bcs->controller = controller;
+       bcs->ctx = ctx;
+
+       for (n = 0; n < controller->count_buttons; n++)
+               each[n].bcs = bcs;
+
+#if defined(LWS_PLAT_TIMER_CREATE)
+       /* this only runs inbetween a gpio ISR and the bottom half */
+       bcs->timer = LWS_PLAT_TIMER_CREATE("bcst",
+                       1, 0, bcs, (TimerCallbackFunction_t)lws_button_bh);
+       if (!bcs->timer)
+               return NULL;
+
+       /* this only runs when a button activity is being classified */
+       bcs->timer_mon = LWS_PLAT_TIMER_CREATE("bcmon", LWS_BUTTON_MON_TIMER_MS,
+                                              1, bcs, (TimerCallbackFunction_t)
+                                                               lws_button_mon);
+       if (!bcs->timer_mon)
+               return NULL;
+#endif
+
+       return bcs;
+}
+
+void
+lws_button_controller_destroy(struct lws_button_state *bcs)
+{
+       /* disable them all */
+       lws_button_enable(bcs, 0, 0);
+
+#if defined(LWS_PLAT_TIMER_DELETE)
+       LWS_PLAT_TIMER_DELETE(bcs->timer);
+       LWS_PLAT_TIMER_DELETE(bcs->timer_mon);
+#endif
+
+       lws_free(bcs);
+}
+
+lws_button_idx_t
+lws_button_get_bit(struct lws_button_state *bcs, const char *name)
+{
+       const lws_button_controller_t *bc = bcs->controller;
+       int n;
+
+       for (n = 0; n < bc->count_buttons; n++)
+               if (!strcmp(name, bc->button_map[n].smd_interaction_name))
+                       return 1 << n;
+
+       return 0; /* not found */
+}
+
+void
+lws_button_enable(lws_button_state_t *bcs,
+                 lws_button_idx_t _reset, lws_button_idx_t _set)
+{
+       lws_button_idx_t u = (bcs->enable_bitmap & (~_reset)) | _set;
+       const lws_button_controller_t *bc = bcs->controller;
+#if defined(LWS_PLAT_TIMER_START)
+       lws_button_each_t *each = (lws_button_each_t *)&bcs[1];
+#endif
+       int n;
+
+       for (n = 0; n < bcs->controller->count_buttons; n++) {
+               if (!(bcs->enable_bitmap & (1 << n)) && (u & (1 << n))) {
+                       /* set as input with pullup or pulldown appropriately */
+                       bc->gpio_ops->mode(bc->button_map[n].gpio,
+                               LWSGGPIO_FL_READ |
+                               ((bc->active_state_bitmap & (1 << n)) ?
+                               LWSGGPIO_FL_PULLDOWN : LWSGGPIO_FL_PULLUP));
+#if defined(LWS_PLAT_TIMER_START)
+                       /*
+                        * This one is becoming enabled... the opaque for the
+                        * ISR is the indvidual lws_button_each_t, they all
+                        * point to the same ISR
+                        */
+                       bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
+                                       bc->active_state_bitmap & (1 << n) ?
+                                               LWSGGPIO_IRQ_RISING :
+                                                       LWSGGPIO_IRQ_FALLING,
+                                               lws_button_irq_cb_t, &each[n]);
+#endif
+               }
+               if ((bcs->enable_bitmap & (1 << n)) && !(u & (1 << n)))
+                       /* this one is becoming disabled */
+                       bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
+                                               LWSGGPIO_IRQ_NONE, NULL, NULL);
+       }
+
+       bcs->enable_bitmap = u;
+}
diff --git a/lib/drivers/devices/display/ili9341.h b/lib/drivers/devices/display/ili9341.h
new file mode 100644 (file)
index 0000000..cb4bc24
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Private register map for ILI9341
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#if !defined(__LWS_ILI9341_H__)
+#define __LWS_ILI9341_H__
+
+enum {
+
+       ILI9341_NOP                                             = 0x00,
+       ILI9341_SWRESET                                         = 0x01,
+       ILI9341_RDDID                                           = 0x04,
+       ILI9341_RDDST                                           = 0x09,
+
+       ILI9341_SLPIN                                           = 0x10,
+       ILI9341_SLPOUT                                          = 0x11,
+       ILI9341_PTLON                                           = 0x12,
+       ILI9341_NORON                                           = 0x13,
+
+       ILI9341_RDMODE                                          = 0x0a,
+       ILI9341_RDMADCTL                                        = 0x0b,
+       ILI9341_RDPIXFMT                                        = 0x0c,
+       ILI9341_RDIMGFMT                                        = 0x0d,
+       ILI9341_RDSELFDIAG                                      = 0x0f,
+
+       ILI9341_INVOFF                                          = 0x20,
+       ILI9341_INVON                                           = 0x21,
+       ILI9341_GAMMASET                                        = 0x26,
+       ILI9341_DISPOFF                                         = 0x28,
+       ILI9341_DISPON                                          = 0x29,
+       ILI9341_CASET                                           = 0x2a,
+       ILI9341_PASET                                           = 0x2b,
+       ILI9341_RAMWR                                           = 0x2c,
+       ILI9341_RAMRD                                           = 0x2e,
+
+       ILI9341_PTLAR                                           = 0x30,
+       ILI9341_VSCRDEF                                         = 0x33,
+       ILI9341_MADCTL                                          = 0x36,
+       ILI9341_VSCRSADD                                        = 0x37,
+       ILI9341_PIXFMT                                          = 0x3a,
+
+       ILI9341_FRMCTR1                                         = 0xb1,
+       ILI9341_FRMCTR2                                         = 0xb2,
+       ILI9341_FRMCTR3                                         = 0xb3,
+       ILI9341_INVCTR                                          = 0xb4,
+       ILI9341_DFUNCTR                                         = 0xb6,
+
+       ILI9341_PWCTR1                                          = 0xc0,
+       ILI9341_PWCTR2                                          = 0xc1,
+       ILI9341_PWCTR3                                          = 0xc2,
+       ILI9341_PWCTR4                                          = 0xc3,
+       ILI9341_PWCTR5                                          = 0xc4,
+       ILI9341_VMCTR1                                          = 0xc5,
+       ILI9341_VMCTR2                                          = 0xc7,
+       ILI9341_FACPUMPRAT                                      = 0xcb,
+       ILI9341_FACPWCTRB                                       = 0xcf,
+
+       ILI9341_RDID1                                           = 0xda,
+       ILI9341_RDID2                                           = 0xdb,
+       ILI9341_RDID3                                           = 0xdc,
+       ILI9341_RDID4                                           = 0xdd,
+
+       ILI9341_GMCTRP1                                         = 0xe0,
+       ILI9341_GMCTRN1                                         = 0xe1,
+       ILI9341_FACPWCTRA                                       = 0xe8,
+       ILI9341_FACPWCTR1                                       = 0xea,
+       ILI9341_FACDRTIMCTRA                                    = 0xed,
+
+       ILI9341_FACSETGAMMACRV                                  = 0xf2,
+       ILI9341_FACDRTIMCTR                                     = 0xf7,
+};
+
+#endif
+
diff --git a/lib/drivers/devices/display/ssd1306.h b/lib/drivers/devices/display/ssd1306.h
new file mode 100644 (file)
index 0000000..0d8fb45
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Private register map for SSD1306
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#if !defined(__LWS_SSD1306_H__)
+#define __LWS_SSD1306_H__
+
+enum {
+       SSD1306_SETLOWCOLUMN            = 0x00,
+       SSD1306_SETHIGHCOLUMN           = 0x10,
+
+       SSD1306_MEMORYMODE              = 0x20,
+       SSD1306_COLUMNADDR              = 0x21,
+       SSD1306_PAGEADDR                = 0x22,
+       SSD1306_DEACTIVATE_SCROLL       = 0x2e,
+
+       SSD1306_SETSTARTLINE            = 0x40,
+
+       SSD1306_SETCONTRAST             = 0x81,
+       SSD1306_CHARGEPUMP              = 0x8d,
+
+       SSD1306_SEGREMAP                = 0xa0,
+       SSD1306_SETSEGMENTREMAP         = 0xa1,
+       SSD1306_DISPLAYALLON_RESUME     = 0xa4,
+       SSD1306_DISPLAYALLON            = 0xa5,
+       SSD1306_NORMALDISPLAY           = 0xa6,
+       SSD1306_INVERTDISPLAY           = 0xa7,
+       SSD1306_SETMULTIPLEX            = 0xa8,
+       SSD1306_DISPLAYOFF              = 0xae,
+       SSD1306_DISPLAYON               = 0xaf,
+
+       SSD1306_COMSCANINC              = 0xc0,
+       SSD1306_COMSCANDEC              = 0xc8,
+
+       SSD1306_SETDISPLAYOFFSET        = 0xd3,
+       SSD1306_SETDISPLAYCLOCKDIV      = 0xd5,
+       SSD1306_SETPRECHARGE            = 0xd9,
+       SSD1306_SETCOMPINS              = 0xda,
+       SSD1306_SETVCOMDESELECT         = 0xdb,
+
+       SSD1306_NOP                     = 0xe3,
+};
+
+#endif
+
diff --git a/lib/drivers/display/README.md b/lib/drivers/display/README.md
new file mode 100644 (file)
index 0000000..f3c8b0d
--- /dev/null
@@ -0,0 +1,36 @@
+# lws_display
+
+lws provides a generic "display" object that is independent of the connection
+to the display, i2c and spi implementations are provided.
+
+Its purpose is to provide basic blit, backlight binding to lws_pwm, backlight /
+power management and display info like pixels wide and high in a generic way.
+
+The generic display object `lws_display_t` can be included at the top of a
+specific display implementation object, eg, binding it to additional members
+to define the actual IO operations to be used, eg, i2c or spi.
+
+When the display is instantiated, it allocates an additional structure on heap
+that contains dynamic information about display state, `lws_display_state_t`.
+
+## Power state machine
+
+lws_display objects have convenient power state management using a single lws
+sul event loop timer that is managed automatically.
+
+State|Meaning
+---|---
+OFF|The display is in sleep and not showing anything
+BECOMING_ACTIVE|The display was asked to come out of sleep and is waiting for .latency_wake_ms befor proceeding to ACTIVE.  The backlight if any is off.  After the delay, the backlight is sequenced up to `.bl_active` using `.bl_transition` sequencer
+ACTIVE|The backlight is ON and the dim timer is running
+AUTODIMMED|The dim timer was not told the display was active for `.autodim_ms`, we are at `.bl_dim` brightness.  After `.off_ms` we will transition to OFF 
+
+The lws_pwm sequencers are used to provide customizable, smooth transitions for
+the backlight, which may be nonlinear.
+
+## Active notification
+
+Calling `lws_display_state_active(&lds)` on eg, user interaction causes the
+display state to transition to ACTIVE smoothly, taking care of waking the display
+and waiting out a display-specific wake period, and sequencing the backlight
+transition to active level as specified in the display structure.
diff --git a/lib/drivers/display/ili9341-spi.c b/lib/drivers/display/ili9341-spi.c
new file mode 100644 (file)
index 0000000..1d01be3
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * lws abstract display implementation for ili9341 on spi
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+#include <drivers/devices/display/ili9341.h>
+
+
+static uint8_t ili9341_320x240_init[] = {
+       /*
+        * This provides 70Hz 320x240 at RGB565, we assume im[3:0] is 1110
+        * which is 4-bit SPI
+        */
+
+        3, ILI9341_FACPWCTRB,      0x00, 0x83, 0x30,
+        4, ILI9341_FACDRTIMCTRA,   0x64, 0x03, 0x12, 0x81,
+        3, ILI9341_FACPWCTRA,      0x85, 0x01, 0x79,
+        5, ILI9341_FACPUMPRAT,     0x39, 0x2c, 0x00, 0x34, 0x02,
+        1, ILI9341_FACDRTIMCTR,    0x20,
+        2, ILI9341_FACPWCTR1,      0x00, 0x00,
+
+        1, ILI9341_PWCTR1,         0x26,
+        1, ILI9341_PWCTR2,         0x11,
+        2, ILI9341_VMCTR1,         0x35, 0x3e,
+        1, ILI9341_VMCTR2,         0xbe,
+        1, ILI9341_MADCTL,         0x28,
+        1, ILI9341_VSCRSADD,       0x00,
+        1, ILI9341_PIXFMT,         0x55,
+        2, ILI9341_FRMCTR1,        0x00, 0x1b,
+        1, ILI9341_FACSETGAMMACRV, 0x00,
+        1, ILI9341_GAMMASET,       0x01,
+       15, ILI9341_GMCTRP1,        0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e,
+                                   0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09,
+                                   0x00,
+       15, ILI9341_GMCTRN1,        0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31,
+                                   0xc1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36,
+                                   0x0f,
+       4, ILI9341_DFUNCTR,         0x0a, 0x82, 0x27, 0x00,
+};
+
+int
+lws_display_ili9341_spi_init(const struct lws_display *disp)
+{
+       const lws_display_ili9341_t *ili = (const lws_display_ili9341_t *)disp;
+       lws_spi_desc_t desc;
+       size_t pos = 0;
+       uint8_t u[8];
+
+       lwsl_user("%s\n", __func__);
+
+       /* hardware nRESET */
+
+       if (ili->gpio) {
+               ili->gpio->mode(ili->reset_gpio, LWSGGPIO_FL_WRITE |
+                                                LWSGGPIO_FL_PULLUP);
+               ili->gpio->set(ili->reset_gpio, 0);
+
+               lws_msleep(1);
+               ili->gpio->set(ili->reset_gpio, 1);
+               lws_msleep(1);
+       }
+
+       /*
+        * We cut the init table up into transactions... atm we just go with
+        * the fact that bb spi is synchronous, using async / dma we can't use
+        * a single desc on the stack like this
+        */
+
+       memset(&desc, 0, sizeof(desc));
+       desc.count_cmd = 1;
+
+       while (pos < LWS_ARRAY_SIZE(ili9341_320x240_init)) {
+               desc.count_write = ili9341_320x240_init[pos++];
+               desc.src = &ili9341_320x240_init[pos++];
+               desc.data = &ili9341_320x240_init[pos];
+               pos += desc.count_write;
+
+               ili->spi->queue(ili->spi, &desc);
+       }
+
+       u[0] = ILI9341_SLPOUT;
+       desc.src = &u[0];
+       desc.count_write = 0;
+       ili->spi->queue(ili->spi, &desc);
+
+       lws_msleep(5);
+
+       u[0] = ILI9341_DISPON;
+       ili->spi->queue(ili->spi, &desc);
+
+       return 0;
+}
+
+/* backlight handled by PWM */
+
+int
+lws_display_ili9341_spi_brightness(const struct lws_display *disp, uint8_t b)
+{
+       return 0;
+}
+
+int
+lws_display_ili9341_spi_blit(const struct lws_display *disp, const uint8_t *src,
+                            lws_display_scalar x, lws_display_scalar y,
+                            lws_display_scalar w, lws_display_scalar h)
+{
+       const lws_display_ili9341_t *ili = (const lws_display_ili9341_t *)disp;
+       lws_spi_desc_t desc;
+       uint8_t u[5];
+
+       memset(&desc, 0, sizeof(desc));
+       desc.count_cmd = 1;
+       desc.src = &u[0];
+       desc.count_write = 0;
+
+       /*
+        * Blit a line at a time
+        */
+
+       while (h--) {
+
+               u[0] = ILI9341_CASET;
+               desc.data = &u[1];
+               u[1] = x;
+               u[2] = x;
+               u[3] = w >> 8;
+               u[4] = w & 0xff;
+               desc.count_write = 4;
+               ili->spi->queue(ili->spi, &desc);
+
+               u[0] = ILI9341_PASET;
+               u[1] = y >> 8;
+               u[2] = y & 0xff;
+               u[3] = (y + 1) >> 8;
+               u[4] = (y + 1) & 0xff;
+               desc.count_write = 4;
+               ili->spi->queue(ili->spi, &desc);
+
+               u[0] = ILI9341_RAMWR;
+               desc.data = src;
+               desc.count_write = w * 2;
+               ili->spi->queue(ili->spi, &desc);
+               src += w * 2;
+               y++;
+       }
+
+       return 0;
+}
+
+int
+lws_display_ili9341_spi_power(const struct lws_display *disp, int state)
+{
+
+       const lws_display_ili9341_t *ili = (const lws_display_ili9341_t *)disp;
+       lws_spi_desc_t desc;
+       uint8_t u[1];
+
+       memset(&desc, 0, sizeof(desc));
+       desc.count_cmd = 1;
+       desc.data = desc.src = &u[0];
+       u[0] = state ? ILI9341_SLPOUT : ILI9341_SLPIN;
+       ili->spi->queue(ili->spi, &desc);
+
+       /* we're not going to do anything useful for 5ms after this */
+
+       return 0;
+}
diff --git a/lib/drivers/display/lws-display.c b/lib/drivers/display/lws-display.c
new file mode 100644 (file)
index 0000000..28d0c97
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * lws abstract display
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <libwebsockets.h>
+
+static void
+sul_autodim_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_display_state_t *lds = lws_container_of(sul, lws_display_state_t,
+                                                   sul_autodim);
+       int next_ms = -1;
+
+       /* we fire both to dim and to blank... if already in dim state, blank */
+
+       switch (lds->state) {
+       case LWSDISPS_BECOMING_ACTIVE:
+               lws_display_state_set_brightness(lds, lds->disp->bl_active);
+               lds->state = LWSDISPS_ACTIVE;
+               next_ms = lds->autodim_ms;
+               break;
+
+       case LWSDISPS_ACTIVE:
+               /* active -> autodimmed */
+               lds->state = LWSDISPS_AUTODIMMED;
+               next_ms = lds->off_ms;
+               lws_display_state_set_brightness(lds, lds->disp->bl_dim);
+               break;
+
+       case LWSDISPS_AUTODIMMED:
+               /* dimmed -> OFF */
+               lws_display_state_set_brightness(lds, &lws_pwmseq_static_off);
+               lds->state = LWSDISPS_GOING_OFF;
+               next_ms = 600;
+               break;
+
+       case LWSDISPS_GOING_OFF:
+               /* off dimming completed, actual display OFF */
+               lws_display_state_off(lds);
+               return;
+
+       default:
+               return;
+       }
+
+       if (next_ms >= 0)
+               lws_sul_schedule(lds->ctx, 0, &lds->sul_autodim, sul_autodim_cb,
+                                next_ms * LWS_US_PER_MS);
+}
+
+void
+lws_display_state_init(lws_display_state_t *lds, struct lws_context *ctx,
+                      int dim_ms, int off_ms, struct lws_led_state *bl_lcs,
+                      const lws_display_t *disp)
+{
+       memset(lds, 0, sizeof(*lds));
+
+       lds->disp = disp;
+       lds->ctx = ctx;
+       lds->autodim_ms = dim_ms;
+       lds->off_ms = off_ms;
+       lds->bl_lcs = bl_lcs;
+       lds->state = LWSDISPS_OFF;
+
+       lws_led_transition(lds->bl_lcs, "backlight", &lws_pwmseq_static_off,
+                                                    &lws_pwmseq_static_on);
+
+       disp->init(disp);
+}
+
+void
+lws_display_state_set_brightness(lws_display_state_t *lds,
+                                const lws_led_sequence_def_t *pwmseq)
+{
+       lws_led_transition(lds->bl_lcs, "backlight", pwmseq,
+                          lds->disp->bl_transition);
+}
+
+void
+lws_display_state_active(lws_display_state_t *lds)
+{
+       int waiting_ms;
+
+       if (lds->state == LWSDISPS_OFF) {
+               /* power us up */
+               lds->disp->power(lds->disp, 1);
+               lds->state = LWSDISPS_BECOMING_ACTIVE;
+               waiting_ms = lds->disp->latency_wake_ms;
+       } else {
+
+               if (lds->state != LWSDISPS_ACTIVE)
+                       lws_display_state_set_brightness(lds,
+                                               lds->disp->bl_active);
+
+               lds->state = LWSDISPS_ACTIVE;
+               waiting_ms = lds->autodim_ms;
+       }
+
+       /* reset the autodim timer */
+       if (waiting_ms >= 0)
+               lws_sul_schedule(lds->ctx, 0, &lds->sul_autodim, sul_autodim_cb,
+                                waiting_ms * LWS_US_PER_MS);
+
+}
+
+void
+lws_display_state_off(lws_display_state_t *lds)
+{
+       lds->disp->power(lds->disp, 0);
+       lws_sul_cancel(&lds->sul_autodim);
+       lds->state = LWSDISPS_OFF;
+}
diff --git a/lib/drivers/display/ssd1306-i2c.c b/lib/drivers/display/ssd1306-i2c.c
new file mode 100644 (file)
index 0000000..bfcb755
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * lws abstract display implementation for ssd1306 on i2c
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+#include <drivers/devices/display/ssd1306.h>
+
+
+static uint8_t ssd1306_128x64_init[] = {
+       SSD1306_DISPLAYOFF,
+       SSD1306_SETDISPLAYCLOCKDIV,             0xf0,
+       SSD1306_SETMULTIPLEX,                   64 - 1,
+       SSD1306_SETDISPLAYOFFSET,               0,
+       SSD1306_CHARGEPUMP,                     0x14,
+       SSD1306_MEMORYMODE,                     0,
+       SSD1306_SEGREMAP | (0 << 0),
+       SSD1306_COMSCANDEC,
+       SSD1306_SETCOMPINS,                     (1 << 4) | 0x02,
+       SSD1306_SETCONTRAST,                    0, /* start at lowest */
+       SSD1306_SETPRECHARGE,                   (0xf << 4) | (1 << 0),
+       SSD1306_SETVCOMDESELECT,                (4 << 4),
+       SSD1306_DEACTIVATE_SCROLL,
+       SSD1306_DISPLAYALLON_RESUME,
+       SSD1306_NORMALDISPLAY,
+       SSD1306_DISPLAYON
+};
+
+int
+lws_display_ssd1306_i2c_init(const struct lws_display *disp)
+{
+       const lws_display_ssd1306_t *si = (const lws_display_ssd1306_t *)disp;
+
+       si->i2c->init(si->i2c);
+
+       if (si->gpio) {
+               si->gpio->mode(si->reset_gpio, LWSGGPIO_FL_WRITE |
+                                              LWSGGPIO_FL_PULLUP);
+               si->gpio->set(si->reset_gpio, 0);
+               lws_msleep(1);
+               si->gpio->set(si->reset_gpio, 1);
+               lws_msleep(1);
+       }
+
+       if (lws_i2c_command_list(si->i2c, si->i2c7_address,
+                                ssd1306_128x64_init,
+                                LWS_ARRAY_SIZE(ssd1306_128x64_init))) {
+               lwsl_err("%s: fail\n", __func__);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+lws_display_ssd1306_i2c_contrast(const struct lws_display *disp, uint8_t b)
+{
+       const lws_display_ssd1306_t *si = (const lws_display_ssd1306_t *)disp;
+       uint8_t ba[2];
+
+       ba[0] = SSD1306_SETCONTRAST;
+       ba[1] = b;
+
+       return lws_i2c_command_list(si->i2c, si->i2c7_address,
+                                   ba, LWS_ARRAY_SIZE(ba));
+}
+
+int
+lws_display_ssd1306_i2c_blit(const struct lws_display *disp, const uint8_t *src,
+                            lws_display_scalar x, lws_display_scalar y,
+                            lws_display_scalar w, lws_display_scalar h)
+{
+       const lws_display_ssd1306_t *si = (const lws_display_ssd1306_t *)disp;
+       uint8_t ba[6];
+       int n, m;
+
+       /*
+        * The display is arranged in 128x8 bands, with one byte containing
+        * the 8 vertical pixels of the band.
+        */
+
+       if (h < 8)
+               h = 8;
+
+       ba[0] = SSD1306_COLUMNADDR;
+       ba[1] = x;
+       ba[2] = x + w - 1;
+       ba[3] = SSD1306_PAGEADDR;
+       ba[4] = y / 8;
+       ba[5] = ba[4] + (h / 8) - 1;
+
+       if (lws_i2c_command_list(si->i2c, si->i2c7_address,
+                                ba, LWS_ARRAY_SIZE(ba))) {
+               lwsl_err("%s: fail\n", __func__);
+               return 1;
+       }
+
+        for (n = 0; n < (w * h) / 8;) {
+                lws_bb_i2c_start(si->i2c);
+                lws_bb_i2c_write(si->i2c, si->i2c7_address << 1);
+                lws_bb_i2c_write(si->i2c, SSD1306_SETSTARTLINE | y);
+
+                for (m = 0; m < w; m++)
+                        lws_bb_i2c_write(si->i2c, src[n++]);
+
+                lws_bb_i2c_stop(si->i2c);
+                y += 8;
+        }
+
+       return 0;
+}
+
+int
+lws_display_ssd1306_i2c_power(const struct lws_display *disp, int state)
+{
+       const lws_display_ssd1306_t *si = (const lws_display_ssd1306_t *)disp;
+
+       if (!state)
+               return lws_i2c_command(si->i2c, si->i2c7_address,
+                                      SSD1306_DISPLAYOFF | !!state);
+
+       return lws_display_ssd1306_i2c_init(disp);
+}
diff --git a/lib/drivers/i2c/bitbang/lws-bb-i2c.c b/lib/drivers/i2c/bitbang/lws-bb-i2c.c
new file mode 100644 (file)
index 0000000..99e92a5
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * I2C bitbang implementation using generic gpio
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is like an abstract class for gpio, a real implementation provides
+ * functions for the ops that use the underlying OS gpio arrangements.
+ */
+#include <libwebsockets.h>
+
+int
+lws_bb_i2c_init(const lws_i2c_ops_t *octx)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+
+       ctx->gpio->mode(ctx->scl, LWSGGPIO_FL_WRITE | LWSGGPIO_FL_READ | LWSGGPIO_FL_PULLUP);
+       ctx->gpio->mode(ctx->sda, LWSGGPIO_FL_WRITE | LWSGGPIO_FL_READ | LWSGGPIO_FL_PULLUP);
+
+       return 0;
+}
+
+int
+lws_bb_i2c_start(const lws_i2c_ops_t *octx)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+
+       ctx->gpio->set(ctx->sda, 1);
+       ctx->gpio->set(ctx->scl, 1);
+       ctx->delay();
+
+       if (!ctx->gpio->read(ctx->sda))
+               return 1;
+
+       ctx->gpio->set(ctx->sda, 0);
+       ctx->delay();
+       ctx->gpio->set(ctx->scl, 0);
+
+       return 0;
+}
+
+void
+lws_bb_i2c_stop(const lws_i2c_ops_t *octx)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+
+       ctx->gpio->set(ctx->sda, 0);
+       ctx->gpio->set(ctx->scl, 1);
+       ctx->delay();
+
+       while (!ctx->gpio->read(ctx->scl))
+               ;
+
+       ctx->gpio->set(ctx->sda, 1);
+       ctx->delay();
+}
+
+int
+lws_bb_i2c_write(const lws_i2c_ops_t *octx, uint8_t data)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+       int n;
+
+       for (n = 0; n < 8; n++) {
+               ctx->gpio->set(ctx->sda, !!(data & (1 << 7)));
+               ctx->delay();
+               ctx->gpio->set(ctx->scl, 1);
+               ctx->delay();
+               data <<= 1;
+               ctx->gpio->set(ctx->scl, 0);
+       }
+
+       ctx->gpio->set(ctx->sda, 1);
+       ctx->delay();
+       ctx->gpio->set(ctx->scl, 1);
+       ctx->delay();
+       n = ctx->gpio->read(ctx->sda);
+       ctx->gpio->set(ctx->scl, 0);
+       ctx->delay();
+
+       return !!n; /* 0 = ACKED = OK */
+}
+
+int
+lws_bb_i2c_read(const lws_i2c_ops_t *octx)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+       int n, r = 0;
+
+       ctx->gpio->set(ctx->sda, 1);
+
+       for (n = 7; n <= 0; n--) {
+               ctx->gpio->set(ctx->scl, 0);
+               ctx->delay();
+               ctx->gpio->set(ctx->scl, 1);
+               ctx->delay();
+               if (ctx->gpio->read(ctx->sda))
+                       r |= 1 << n;
+       }
+       ctx->gpio->set(ctx->scl, 0);
+
+       return r;
+}
+
+void
+lws_bb_i2c_set_ack(const lws_i2c_ops_t *octx, int ack)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+
+       ctx->gpio->set(ctx->scl, 0);
+       ctx->gpio->set(ctx->sda, !!ack);
+       ctx->delay();
+       ctx->gpio->set(ctx->scl, 1);
+       ctx->delay();
+       ctx->gpio->set(ctx->scl, 0);
+       ctx->delay();
+       ctx->gpio->set(ctx->sda, 1);
+}
diff --git a/lib/drivers/i2c/lws-i2c.c b/lib/drivers/i2c/lws-i2c.c
new file mode 100644 (file)
index 0000000..fa00008
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Generic I2C
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * These are generic helpers made up of calls to the i2c driver ops, so they
+ * just need implementing once like this and are usable for any i2c underlying
+ * implementation via the ops.
+ */
+
+#include <libwebsockets.h>
+       
+int
+lws_i2c_command(const lws_i2c_ops_t *ctx, uint8_t ads7, uint8_t c)
+{
+       if (ctx->start(ctx))
+               return 1;
+
+       if (ctx->write(ctx, ads7 << 1)) {
+               ctx->stop(ctx);
+
+               return 1;
+       }
+
+       ctx->write(ctx, 0);
+       ctx->write(ctx, c);
+       ctx->stop(ctx);
+
+       return 0;
+}
+
+int
+lws_i2c_command_list(const lws_i2c_ops_t *ctx, uint8_t ads7, const uint8_t *buf,
+                    size_t len)
+{
+       while (len--)
+               if (lws_i2c_command(ctx, ads7, *buf++))
+                       return 1;
+
+       return 0;
+}
diff --git a/lib/drivers/led/README.md b/lib/drivers/led/README.md
new file mode 100644 (file)
index 0000000..794b10f
--- /dev/null
@@ -0,0 +1,155 @@
+# lws_led gpio and pwm class drivers
+
+Lws provides an abstract led controller class that can bind an array of LEDs
+to gpio and pwm controllers, and automatically handled pwm sequencers.
+
+Lumience intensity is corrected for IEC curves to match perceptual intensity,
+and the correction can be overridden per led for curve adaptation matching.
+
+Intensity is normalized to a 16-bit scale, when controlled by a GPIO b15 is
+significant and the rest ignored.  When controlled by PWM, as many bits from
+b15 down are significant as the PWM arrangements can represent.
+
+The PWM sequencers use arbitrary function generation callbacks on a normalized
+16-bit phase space, they can choose how much to interpolate and how much to put
+in a table, a 64-sample, 16-bit sine function is provided along with 16-bit
+linear sawtooth.
+
+Changing the sequencer is subject to a third transition function sequencer, this
+can for example mix the transition linearly over, eg, 500ms so the leds look
+very smooth.
+
+## Defining an led controller
+
+An array of inidividual LED information is provided first, and referenced by
+the LED controller definintion.  Leds are named so code does not introduce
+dependencies on specific implementations.
+
+```
+static const lws_led_gpio_map_t lgm[] = {
+       {
+               .name                   = "alert",
+               .gpio                   = GPIO_NUM_25,
+               .pwm_ops                = &pwm_ops,
+               .active_level           = 1,
+       },
+};
+
+static const lws_led_gpio_controller_t lgc = {
+       .led_ops                        = lws_led_gpio_ops,
+       .gpio_ops                       = &lws_gpio_plat,
+       .led_map                        = &lgm[0],
+       .count_leds                     = LWS_ARRAY_SIZE(lgm)
+};
+
+       struct lws_led_state *lls;
+
+       lls = lgc.led_ops.create(&lgc.led_ops);
+       if (!lls) {
+               lwsl_err("%s: could not create led\n", __func__);
+               goto spin;
+       }
+
+```
+
+For GPIO control, the active level of the GPIO to light the LED may be set.
+
+Each LED may bind to a pwm controller, in which case setting the intensity
+programs the pwm controller corresponding to the GPIO.
+
+## Setting the intensity directly
+
+```
+       lgc.led_ops.intensity(&lgc.led_ops, "alert", 0);
+```
+
+## Defining Sequencer
+
+Some common sequencers are provided out of the box, you can also define your
+own arbitrary ones.
+
+The main point is sequencers have a function that returns an intensity for each
+of 65536 phase steps in its cycle.  For example, this is the linear function
+that is included
+
+```
+lws_led_intensity_t
+lws_led_func_linear(lws_led_seq_phase_t n)
+{
+       return (lws_led_intensity_t)n;
+}
+```
+
+It simply returns an intensity between 0 - 65535 matching the phase angle of
+0 - 65535 that it was given, so it's a sawtooth ramp.
+
+An interpolated sine function is also provided that returns an intensity
+between 0 - 65535 reflecting one cycle of sine wave for the phase angle of 0 -
+65535.
+
+These functions are packaged into sequencer structures like this
+
+```
+const lws_led_sequence_def_t lws_pwmseq_sine_endless_fast = {
+       .func                   = lws_led_func_sine,
+       .ledphase_offset        = 0, /* already at 0 amp at 0 phase */
+       .ledphase_total         = LWS_SEQ_LEDPHASE_TOTAL_ENDLESS,
+       .ms                     = 750
+};
+```
+
+This "endless" sequencer cycles through the sine function at 750ms per cycle.
+Non-endless sequencers have a specific start and end in the phase space, eg
+
+```
+const lws_led_sequence_def_t lws_pwmseq_sine_up = {
+       .func                   = lws_led_func_sine,
+       .ledphase_offset        = 0, /* already at 0 amp at 0 phase */
+       .ledphase_total         = LWS_LED_FUNC_PHASE / 2, /* 180 degree ./^ */
+       .ms                     = 300
+};
+```
+
+... this one traverses 180 degrees of the sine wave starting from 0 and ending
+at full intensity, over 300ms.
+
+A commonly-used, provided one is like this, as used in the next section
+
+```
+const lws_led_sequence_def_t lws_pwmseq_linear_wipe = {
+       .func                   = lws_led_func_linear,
+       .ledphase_offset        = 0,
+       .ledphase_total         = LWS_LED_FUNC_PHASE - 1,
+       .ms                     = 300
+};
+```
+
+## Setting the intensity using sequencer transitions
+
+The main api for high level sequenced control is
+
+```
+int
+lws_led_transition(struct lws_led_state *lcs, const char *name,
+                  const lws_led_sequence_def_t *next,
+                  const lws_led_sequence_def_t *trans);
+```
+
+This fades from the current sequence to a new sequence, using `trans` sequencer
+intensity as the mix factor.  `trans` is typically `lws_pwmseq_linear_wipe`,
+fading between the current and new linearly over 300ms.  At the end of the
+`trans` sequence, the new sequence simply replaces the current one and the
+transition is completed.
+
+Sequencers use a single 30Hz OS timer while any sequence is active.
+
+exported sequencer symbol|description
+---|---
+lws_pwmseq_sine_endless_slow|continuous 100% sine, 1.5s cycle 
+lws_pwmseq_sine_endless_fast|continuous 100% sine, 0.75s cycle 
+lws_pwmseq_linear_wipe|single 0 - 100% ramp over 0.3s
+lws_pwmseq_sine_up|single 0 - 100% using sine curve over 0.3s
+lws_pwmseq_sine_down|single 100% - 0 using sine curve over 0.3s
+lws_pwmseq_static_on|100% static
+lws_pwmseq_static_half|50% static
+lws_pwmseq_static_off|0% static
diff --git a/lib/drivers/led/led-gpio.c b/lib/drivers/led/led-gpio.c
new file mode 100644 (file)
index 0000000..382c3e6
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Generic GPIO led
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "private-lib-core.h"
+#include "drivers/led/private-lib-drivers-led.h"
+
+#if defined(LWS_PLAT_TIMER_CB)
+static LWS_PLAT_TIMER_CB(lws_led_timer_cb, th)
+{
+       lws_led_state_t *lcs = LWS_PLAT_TIMER_CB_GET_OPAQUE(th);
+
+       lws_seq_timer_handle(lcs);
+}
+#endif
+
+struct lws_led_state *
+lws_led_gpio_create(const lws_led_ops_t *led_ops)
+{
+       lws_led_gpio_controller_t *lgc = (lws_led_gpio_controller_t *)led_ops;
+       /*
+        * We allocate the main state object, and a 3 x seq dynamic footprint
+        * for each led, since it may be sequencing the transition between two
+        * other sequences.
+        */
+
+       lws_led_state_t *lcs = lws_zalloc(sizeof(lws_led_state_t) +
+                               (lgc->count_leds * sizeof(lws_led_state_chs_t)),
+                               __func__);
+       int n;
+
+       if (!lcs)
+               return NULL;
+
+       lcs->controller = lgc;
+
+#if defined(LWS_PLAT_TIMER_CREATE)
+       lcs->timer = LWS_PLAT_TIMER_CREATE("leds",
+                       LWS_LED_SEQUENCER_UPDATE_INTERVAL_MS, 1, lcs,
+                                 (TimerCallbackFunction_t)lws_led_timer_cb);
+       if (!lcs->timer)
+               return NULL;
+#endif
+
+       for (n = 0; n < lgc->count_leds; n++) {
+               const lws_led_gpio_map_t *map = &lgc->led_map[n];
+
+               if (map->pwm_ops) {
+                       lgc->gpio_ops->mode(map->gpio, LWSGGPIO_FL_READ);
+                       lgc->gpio_ops->set(map->gpio, 0);
+               } else {
+                       lgc->gpio_ops->mode(map->gpio, LWSGGPIO_FL_WRITE);
+                       lgc->gpio_ops->set(map->gpio,
+                                          !lgc->led_map[n].active_level);
+               }
+       }
+
+       return lcs;
+}
+
+void
+lws_led_gpio_destroy(struct lws_led_state *lcs)
+{
+#if defined(LWS_PLAT_TIMER_DELETE)
+       LWS_PLAT_TIMER_DELETE(lcs->timer);
+#endif
+       lws_free(lcs);
+}
+
+int
+lws_led_gpio_lookup(const struct lws_led_ops *lo, const char *name)
+{
+       const lws_led_gpio_controller_t *lgc = (lws_led_gpio_controller_t *)lo;
+       int n;
+
+       for (n = 0; n < lgc->count_leds; n++)
+               if (!strcmp(name, lgc->led_map[n].name))
+                       return n;
+
+       return -1;
+}
+
+void
+lws_led_gpio_intensity(const struct lws_led_ops *lo, const char *name,
+                      lws_led_intensity_t inten)
+{
+       const lws_led_gpio_controller_t *lgc = (lws_led_gpio_controller_t *)lo;
+       int idx = lws_led_gpio_lookup(lo, name);
+       const lws_led_gpio_map_t *map;
+
+       if (idx < 0)
+               return;
+
+       map = &lgc->led_map[idx];
+
+       if (map->pwm_ops)
+               map->pwm_ops->intensity(map->pwm_ops, map->gpio, inten);
+       else
+               lgc->gpio_ops->set(map->gpio,
+                               (!!map->active_level) ^ !(inten & 0x8000));
+}
diff --git a/lib/drivers/led/led-seq.c b/lib/drivers/led/led-seq.c
new file mode 100644 (file)
index 0000000..2fd2f62
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Generic GPIO led
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "private-lib-core.h"
+
+#include "drivers/led/private-lib-drivers-led.h"
+
+/*
+ * 64 entry interpolated CIE correction
+ * https://en.wikipedia.org/wiki/Lightness
+ */
+
+uint16_t cie[] = {
+       0, 113, 227, 340, 454, 568, 688, 824, 976, 1146,
+       1335, 1543, 1772, 2023, 2296, 2592, 2914, 3260, 3633, 4034,
+       4463, 4921, 5409, 5929, 6482, 7067, 7687, 8341, 9032, 9761,
+       10527, 11332, 12178, 13064, 13993, 14964, 15980, 17040, 18146, 19299,
+       20500, 21750, 23049, 24400, 25802, 27256, 28765, 30328, 31946, 33622,
+       35354, 37146, 38996, 40908, 42881, 44916, 47014, 49177, 51406, 53700,
+       56062, 58492, 60992, 63561,
+       65535 /* for interpolation */
+};
+
+/*
+ * This is the default intensity correction function, it can be overridden
+ * per-led to eg, normalize intensity of different leds
+ */
+
+static lws_led_intensity_t
+cie_antilog(lws_led_intensity_t lin)
+{
+        return (cie[lin >> 10]       * (0x3ff - (lin & 0x3ff)) +
+               cie[(lin >> 10) + 1] * (lin & 0x3ff)) / 0x3ff;
+}
+
+static void
+lws_seq_advance(lws_led_state_t *lcs, lws_led_state_ch_t *ch)
+{
+       if (!ch->seq)
+               return;
+
+       if (ch->phase_budget != LWS_SEQ_LEDPHASE_TOTAL_ENDLESS &&
+           (ch->phase_budget < ch->step || !ch->phase_budget)) {
+
+               /* we are done */
+
+               ch->seq = NULL;
+               if (!(--lcs->timer_refcount)) {
+#if defined(LWS_PLAT_TIMER_STOP)
+                       LWS_PLAT_TIMER_STOP(lcs->timer);
+#endif
+               }
+
+               return;
+       }
+
+       ch->ph += ch->step;
+       if (ch->phase_budget != LWS_SEQ_LEDPHASE_TOTAL_ENDLESS)
+               ch->phase_budget -= ch->step;
+}
+
+static lws_led_intensity_t
+lws_seq_sample(const lws_led_gpio_map_t *map, lws_led_state_chs_t *chs)
+{
+       unsigned int i;
+
+       if (chs->seqs[LLSI_CURR].seq)
+               chs->seqs[LLSI_CURR].last = chs->seqs[LLSI_CURR].seq->
+                                               func(chs->seqs[LLSI_CURR].ph);
+
+       if (chs->seqs[LLSI_TRANS].seq) {
+               /*
+                * If a transition is ongoing, we need to use the transition
+                * intensity as the mixing factor between the still-live current
+                * and newly-live next sequences
+                */
+               chs->seqs[LLSI_TRANS].last = chs->seqs[LLSI_TRANS].seq->
+                                               func(chs->seqs[LLSI_TRANS].ph);
+
+               if (chs->seqs[LLSI_NEXT].seq)
+                       chs->seqs[LLSI_NEXT].last = chs->seqs[LLSI_NEXT].seq->
+                                                 func(chs->seqs[LLSI_NEXT].ph);
+
+               i = (lws_led_intensity_t)(((
+                               (unsigned int)chs->seqs[LLSI_CURR].last *
+                               (65535 - chs->seqs[LLSI_TRANS].last) >> 16) +
+                       (((unsigned int)chs->seqs[LLSI_NEXT].last *
+                        (unsigned int)chs->seqs[LLSI_TRANS].last) >> 16)));
+       } else
+               i = chs->seqs[LLSI_CURR].last;
+
+       return map->intensity_correction ? map->intensity_correction(i) :
+                                          cie_antilog((lws_led_intensity_t)i);
+}
+
+void
+lws_seq_timer_handle(lws_led_state_t *lcs)
+{
+       lws_led_gpio_controller_t *lgc = lcs->controller;
+       lws_led_state_chs_t *chs = (lws_led_state_chs_t *)&lcs[1];
+       const lws_led_gpio_map_t *map = &lgc->led_map[0];
+       unsigned int n;
+
+       for (n = 0; n < lgc->count_leds; n++) {
+
+               lgc->led_ops.intensity(&lgc->led_ops, map->name,
+                                      lws_seq_sample(map, chs));
+
+               lws_seq_advance(lcs, &chs->seqs[LLSI_CURR]);
+
+               if (chs->seqs[LLSI_TRANS].seq) {
+                       lws_seq_advance(lcs, &chs->seqs[LLSI_NEXT]);
+                       lws_seq_advance(lcs, &chs->seqs[LLSI_TRANS]);
+
+                       /*
+                        * When we finished the transition, we can make the
+                        * "next" sequence the current sequence and no need for
+                        * a "next" or a transition any more.
+                        */
+
+                       if (!chs->seqs[LLSI_TRANS].seq) {
+                               chs->seqs[LLSI_CURR] = chs->seqs[LLSI_NEXT];
+                               chs->seqs[LLSI_NEXT].seq = NULL;
+                       }
+               }
+
+               map++;
+               chs++;
+       }
+}
+
+static int
+lws_led_set_chs_seq(struct lws_led_state *lcs, lws_led_state_ch_t *dest,
+                   const lws_led_sequence_def_t *def)
+{
+       int steps;
+
+       dest->seq = def;
+       dest->ph = def->ledphase_offset;
+       dest->phase_budget = def->ledphase_total;
+
+       /*
+        * We need to compute the incremental phase angle step to cover the
+        * total number of phases in the indicated ms, incrementing at the
+        * timer rate of LWS_LED_SEQUENCER_UPDATE_RATE_HZ.  Eg,
+        *
+        * 65536 phase steps (one cycle) in 2000ms at 30Hz timer rate means we
+        * will update 2000ms / 33ms = 60 times, so we must step at at
+        * 65536 / 60 = 1092 phase angle resolution
+        */
+
+       steps = def->ms / LWS_LED_SEQUENCER_UPDATE_INTERVAL_MS;
+       dest->step = (def->ledphase_total != LWS_SEQ_LEDPHASE_TOTAL_ENDLESS ?
+               def->ledphase_total : LWS_LED_FUNC_PHASE) / (steps ? steps : 1);
+
+       if (!lcs->timer_refcount++) {
+#if defined(LWS_PLAT_TIMER_START)
+               LWS_PLAT_TIMER_START(lcs->timer);
+#endif
+       }
+
+       return steps;
+}
+
+int
+lws_led_transition(struct lws_led_state *lcs, const char *name,
+                  const lws_led_sequence_def_t *next,
+                  const lws_led_sequence_def_t *trans)
+{
+       lws_led_state_chs_t *chs = (lws_led_state_chs_t *)&lcs[1];
+       int index = lws_led_gpio_lookup(&lcs->controller->led_ops, name);
+
+       if (index < 0)
+               return 1;
+
+       lws_led_set_chs_seq(lcs, &chs[index].seqs[LLSI_TRANS], trans);
+       lws_led_set_chs_seq(lcs, &chs[index].seqs[LLSI_NEXT], next);
+
+       return 0;
+}
diff --git a/lib/drivers/led/private-lib-drivers-led.h b/lib/drivers/led/private-lib-drivers-led.h
new file mode 100644 (file)
index 0000000..deefe09
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Generic GPIO led
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+typedef struct lws_led_state
+{
+#if defined(LWS_PLAT_TIMER_TYPE)
+       LWS_PLAT_TIMER_TYPE                     timer;
+#endif
+
+       lws_led_gpio_controller_t               *controller;
+       int                                     timer_refcount;
+} lws_led_state_t;
+
+void
+lws_seq_timer_handle(lws_led_state_t *lcs);
+
+int
+lws_led_gpio_lookup(const struct lws_led_ops *lo, const char *name);
diff --git a/lib/drivers/netdev/netdev.c b/lib/drivers/netdev/netdev.c
new file mode 100644 (file)
index 0000000..f550df1
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+static const lws_struct_map_t lsm_wifi_creds[] = {
+       LSM_CARRAY      (lws_wifi_creds_t, ssid,                "ssid"),
+       LSM_CARRAY      (lws_wifi_creds_t, passphrase,          "passphrase"),
+       LSM_UNSIGNED    (lws_wifi_creds_t, alg,                 "alg"),
+       LSM_STRING_PTR  (lws_wifi_creds_t, bssid,               "bssid"),
+};
+
+static const lws_struct_map_t lsm_netdev_credentials[] = {
+       LSM_LIST        (lws_netdevs_t, owner_creds, lws_wifi_creds_t, list,
+                        NULL, lsm_wifi_creds,                  "credentials"),
+};
+
+static const lws_struct_map_t lsm_netdev_schema[] = {
+        LSM_SCHEMA      (lws_netdevs_t, NULL, lsm_netdev_credentials,
+                                              "lws-netdev-creds"),
+};
+
+
+//LSM_CHILD_PTR        (lws_netdev_instance_wifi_t, ap_cred, lws_wifi_creds_t,
+//              NULL, lsm_wifi_creds,                  "ap_cred"),
+//LSM_STRING_PTR       (lws_netdev_instance_wifi_t, ap_ip,     "ap_ip"),
+
+int
+lws_netdev_credentials_settings_set(lws_netdevs_t *nds)
+{
+       lws_struct_serialize_t *js;
+       size_t w = 0, max = 2048;
+       int n, r = 1;
+       uint8_t *buf;
+
+       buf = lws_malloc(max, __func__); /* length should be computed */
+
+       js = lws_struct_json_serialize_create(lsm_netdev_schema,
+                       LWS_ARRAY_SIZE(lsm_netdev_schema), 0, nds);
+       if (!js)
+               goto bail;
+
+       n = lws_struct_json_serialize(js, buf, max, &w);
+       lws_struct_json_serialize_destroy(&js);
+       if (n != LSJS_RESULT_FINISH)
+               goto bail;
+
+       lwsl_notice("%s: setting %s\n", __func__, buf);
+
+       if (!lws_settings_plat_set(nds->si, "netdev.creds", buf, w))
+               r = 0;
+
+bail:
+       if (r)
+               lwsl_err("%s: failed\n", __func__);
+       lws_free(buf);
+
+       return r;
+}
+
+int
+lws_netdev_credentials_settings_get(lws_netdevs_t *nds)
+{
+       struct lejp_ctx ctx;
+       lws_struct_args_t a;
+       size_t l = 0;
+       uint8_t *buf;
+       int m;
+
+       memset(&a, 0, sizeof(a));
+
+       if (lws_settings_plat_get(nds->si, "netdev.creds", NULL, &l)) {
+               lwsl_notice("%s: not in settings\n", __func__);
+               return 1;
+       }
+
+       buf = lws_malloc(l, __func__);
+       if (!buf)
+               return 1;
+
+       if (lws_settings_plat_get(nds->si, "netdev.creds", buf, &l)) {
+               lwsl_err("%s: unexpected settings get fail\n", __func__);
+               goto bail;
+       }
+
+       a.map_st[0] = lsm_netdev_schema;
+       a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_netdev_schema);
+       a.ac_block_size = 512;
+
+       lws_struct_json_init_parse(&ctx, NULL, &a);
+       m = lejp_parse(&ctx, (uint8_t *)buf, l);
+       lws_free(buf);
+       if (m < 0 || !a.dest) {
+               lwsl_notice("%s: JSON decode failed '%s'\n",
+                           __func__, lejp_error_to_string(m));
+               goto bail1;
+       }
+
+       /*
+        * Forcibly set the state of the nds creds owner to the synthesized
+        * one in the ac, and keep the ac for as long as we keep the creds out
+        */
+       nds->owner_creds = ((lws_netdevs_t *)a.dest)->owner_creds;
+       nds->ac_creds = a.ac;
+
+       return 0;
+
+bail:
+       lws_free(buf);
+bail1:
+       lwsac_free(&a.ac);
+
+       return 1;
+}
+
+lws_wifi_creds_t *
+lws_netdev_credentials_find(lws_netdevs_t *netdevs, const char *ssid,
+                           const uint8_t *bssid)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(
+                                                      &netdevs->owner_creds)) {
+               lws_wifi_creds_t *w = lws_container_of(p, lws_wifi_creds_t, list);
+
+               if (!strcmp(ssid, (const char *)&w[1]) &&
+                   !memcmp(bssid, w->bssid, 6))
+                       return w;
+
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
+lws_netdev_instance_t *
+lws_netdev_find(lws_netdevs_t *netdevs, const char *ifname)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(
+                                                      &netdevs->owner)) {
+               lws_netdev_instance_t *ni = lws_container_of(p,
+                                               lws_netdev_instance_t, list);
+
+               if (!strcmp(ifname, ni->name))
+                       return ni;
+
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
+/*
+ * Context forwards NETWORK related smd here, in lws thread context
+ */
+
+int
+lws_netdev_smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
+                 void *buf, size_t len)
+{
+       struct lws_context *ctx = (struct lws_context *)opaque;
+       const char *iface;
+       char setname[16];
+       size_t al = 0;
+
+       /* deal with anything from whole-network perspective */
+
+       /* pass through netdev-specific messages to correct platform handler */
+
+       iface = lws_json_simple_find(buf, len, "\"if\":", &al);
+       if (!iface)
+               return 0;
+
+       lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(
+                                                        &ctx->netdevs.owner)) {
+               lws_netdev_instance_t *ni = lws_container_of(
+                                               p, lws_netdev_instance_t, list);
+
+               if (!strncmp(ni->name, iface, al)) {
+
+                       /*
+                        * IP assignment on our netif?  We can deal with marking
+                        * the last successful association generically...
+                        */
+
+                       if (ni->type == LWSNDTYP_WIFI &&
+                           !lws_json_simple_strcmp(buf, len, "\"type\":",
+                                                       "ipacq")) {
+                               const char *ev = lws_json_simple_find(buf, len,
+                                                       "\"ipv4\":", &al);
+                               lws_netdev_instance_wifi_t *wnd =
+                                              (lws_netdev_instance_wifi_t *)ni;
+
+                               if (!ev)
+                                       return 0;
+
+                               lws_snprintf(setname, sizeof(setname),
+                                               "netdev.last.%s", iface);
+
+                               lws_settings_plat_printf(ctx->netdevs.si,
+                                       setname, "{\"ssid\":\"%s\",\"bssid\":"
+                                       "\"%02X%02X%02X%02X%02X%02X\"}",
+                                       wnd->current_attempt_ssid,
+                                       wnd->current_attempt_bssid[0],
+                                       wnd->current_attempt_bssid[1],
+                                       wnd->current_attempt_bssid[2],
+                                       wnd->current_attempt_bssid[3],
+                                       wnd->current_attempt_bssid[4],
+                                       wnd->current_attempt_bssid[5]);
+                       }
+
+                       /*
+                        * Pass it through to related netdev instance for
+                        * private actions
+                        */
+
+                       return ni->ops->event(ni, timestamp, buf, len);
+               }
+
+       } lws_end_foreach_dll(p);
+
+       return 0;
+}
+
+/*
+ * This is the generic part of the netdev instance initialization that's always
+ * the same, regardless of the netdev type
+ */
+
+void
+lws_netdev_instance_create(lws_netdev_instance_t *ni, struct lws_context *ctx,
+                          const lws_netdev_ops_t *ops, const char *name,
+                          void *platinfo)
+{
+       ni->ops         = ops;
+       ni->name        = name;
+       ni->platinfo    = platinfo;
+
+       /* add us to the list of active netdevs */
+
+       lws_dll2_add_tail(&ni->list, &ctx->netdevs.owner);
+}
+
+void
+lws_netdev_instance_remove_destroy(struct lws_netdev_instance *ni)
+{
+       lws_dll2_remove(&ni->list);
+       lws_free(ni);
+}
+
+lws_netdevs_t *
+lws_netdevs_from_ctx(struct lws_context *ctx)
+{
+       return &ctx->netdevs;
+}
diff --git a/lib/drivers/netdev/wifi.c b/lib/drivers/netdev/wifi.c
new file mode 100644 (file)
index 0000000..ef11a28
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * libwebsockets - lws_netdev_wifi generic state handling
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * The generic wifi netdevs follow a
+ */
+
+#include "private-lib-core.h"
+
+int
+lws_netdev_wifi_rssi_sort_compare(const lws_dll2_t *d, const lws_dll2_t *i)
+{
+       const lws_wifi_sta_t *wsd = (const lws_wifi_sta_t *)d,
+                            *wsi = (const lws_wifi_sta_t *)i;
+       return rssi_averaged(wsd) > rssi_averaged(wsi);
+}
+
+void
+lws_netdev_wifi_scan_empty(lws_netdev_instance_wifi_t *wnd)
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, lws_dll2_get_head(
+                                                              &wnd->scan)) {
+               lws_wifi_sta_t *s = lws_container_of(p, lws_wifi_sta_t, list);
+
+               lws_dll2_remove(p);
+               lws_free(s);
+
+       } lws_end_foreach_dll_safe(p, p1);
+}
+
+void
+lws_netdev_wifi_scan(lws_sorted_usec_list_t *sul)
+{
+       lws_netdev_instance_wifi_t *wnd = lws_container_of(sul,
+                                       lws_netdev_instance_wifi_t, sul_scan);
+
+       wnd->inst.ops->scan(&wnd->inst);
+}
+
+lws_wifi_sta_t *
+lws_netdev_wifi_scan_find(lws_netdev_instance_wifi_t *wnd, const char *ssid,
+                         const uint8_t *bssid)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(
+                                                              &wnd->scan)) {
+               lws_wifi_sta_t *w = lws_container_of(p, lws_wifi_sta_t, list);
+
+               if (!strcmp(ssid, (const char *)&w[1]) &&
+                   !memcmp(bssid, w->bssid, 6))
+                       return w;
+
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
+int
+lws_netdev_wifi_scan_select(lws_netdev_instance_wifi_t *wnd)
+{
+       lws_netdevs_t *netdevs = lws_netdevs_from_ndi(&wnd->inst);
+       struct lws_context *cx = lws_context_from_netdevs(netdevs);
+       uint32_t least_recent = 0xffffffff;
+       lws_wifi_creds_t *pc = NULL;
+       lws_wifi_sta_t *pw = NULL;
+
+       /*
+        * Trim enough of the lowest RSSI guys in order to get us below the
+        * limit we are allowed to keep track of...
+        */
+
+       while (wnd->scan.count > LWS_WIFI_MAX_SCAN_TRACK) {
+               struct lws_dll2 *p = lws_dll2_get_tail(&wnd->scan);
+               lws_wifi_sta_t *w = lws_container_of(p, lws_wifi_sta_t, list);
+
+               lws_dll2_remove(p);
+               lws_free(w);
+       }
+
+       /*
+        * ... let's dump what's left
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(
+                                                              &wnd->scan)) {
+               lws_wifi_sta_t *w = lws_container_of(p, lws_wifi_sta_t, list);
+
+               lwsl_notice("%s: %s, %02X:%02X:%02X:%02X:%02X:%02X, ch %d, rssi %d\n",
+                           __func__, (const char *)&w[1], w->bssid[0],
+                           w->bssid[1], w->bssid[2], w->bssid[3], w->bssid[4],
+                           w->bssid[5], w->ch, rssi_averaged(w));
+
+       } lws_end_foreach_dll(p);
+
+       /*
+        * make sure we have our device's connection credentials at hand
+        */
+
+       if (!netdevs->ac_creds &&
+           lws_netdev_credentials_settings_get(netdevs))
+               return 0;
+       netdevs->refcount_creds++;
+
+       /*
+        * Let's go through each starting from the best RSSI seeing if we
+        * have credentials... if we do, pick the one we least-recently tried
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, p1, wnd->scan.head) {
+               lws_wifi_sta_t *w = lws_container_of(p1, lws_wifi_sta_t, list);
+
+               lws_start_foreach_dll(struct lws_dll2 *, q,
+                                     netdevs->owner_creds.head) {
+                       lws_wifi_creds_t *c = lws_container_of(q,
+                                                              lws_wifi_creds_t,
+                                                              list);
+
+                       if (!strcmp((const char *)&w[1], c->ssid) &&
+                           w->last_seen < least_recent) {
+                               /*
+                                * Not <= so we stick with higher RSSI when
+                                * all 0
+                                */
+                               pc = c;
+                               pw = w;
+                               least_recent = w->last_seen;
+                       }
+
+               } lws_end_foreach_dll(q);
+
+       } lws_end_foreach_dll(p1);
+
+
+       if (least_recent != 0xffffffff) {
+               /*
+                * We picked one to try... note what we're trying so we can
+                * record it in settings as last successful
+                */
+               lws_strncpy(wnd->current_attempt_ssid, (const char *)&pw[1],
+                           sizeof(wnd->current_attempt_ssid));
+               memcpy(wnd->current_attempt_bssid, pw->bssid, LWS_ETH_ALEN);
+               wnd->inst.ops->connect(&wnd->inst, pc->ssid, pc->passphrase,
+                                       pw->bssid);
+       } else {
+               /*
+                * We couldn't see anyone we recognized on this scan, let's
+                * rescan in a bit
+                */
+
+               lwsl_notice("%s: nothing usable in scan, redoing in 3s\n", __func__);
+               lws_sul_schedule(cx, 0, &wnd->sul_scan, lws_netdev_wifi_scan,
+                                3 * LWS_US_PER_SEC);
+       }
+
+       if (!--netdevs->refcount_creds) {
+               lws_dll2_owner_clear(&netdevs->owner_creds);
+               lwsac_free(&netdevs->ac_creds);
+       }
+
+       return 0;
+}
+
+/*
+ * Initially our best bet is just try to reconnect to whatever we last
+ * succeeded to connect to
+ */
+
+int
+lws_netdev_wifi_redo_last(lws_netdev_instance_wifi_t *wnd)
+{
+       lws_netdevs_t *netdevs = lws_netdevs_from_ndi(&wnd->inst);
+       uint8_t buf[256], bssid[LWS_ETH_ALEN];
+       const char *ssid, *pp = "", *pb;
+       char setname[16], ssid_copy[33];
+       size_t l = sizeof(buf), al;
+       lws_wifi_creds_t *cred;
+
+       /*
+        * Let's try to retreive the last successful connect info for this
+        * netdev
+        */
+
+       lws_snprintf(setname, sizeof(setname), "netdev.last.%s", wnd->inst.name);
+       if (lws_settings_plat_get(netdevs->si, setname, buf, &l))
+               return 1;
+
+       lwsl_notice("%s: last successful %s\n", __func__, buf);
+
+       ssid = lws_json_simple_find((const char *)buf, l, "\"ssid\":", &al);
+       if (!ssid || al > 32)
+               return 1;
+
+       memcpy(ssid_copy, ssid, al);
+       ssid_copy[al + 1] = '\0';
+
+       pb = lws_json_simple_find((const char *)buf, l, "\"bssid\":", &al);
+       if (!pb)
+               return 1;
+       lws_hex_to_byte_array(pb, bssid, sizeof(bssid));
+
+       /*
+        * make sure we have our device's connection credentials at hand
+        */
+
+       if (!netdevs->ac_creds &&
+           lws_netdev_credentials_settings_get(netdevs))
+               return 1;
+       netdevs->refcount_creds++;
+
+       cred = lws_netdev_credentials_find(netdevs, ssid_copy, bssid);
+       if (cred)
+               pp = cred->passphrase;
+
+       lws_strncpy(wnd->current_attempt_ssid, ssid_copy,
+                   sizeof(wnd->current_attempt_ssid));
+       memcpy(wnd->current_attempt_bssid, bssid, LWS_ETH_ALEN);
+       wnd->inst.ops->connect(&wnd->inst, ssid_copy, pp, bssid);
+
+       if (!--netdevs->refcount_creds) {
+               lws_dll2_owner_clear(&netdevs->owner_creds);
+               lwsac_free(&netdevs->ac_creds);
+       }
+
+       return 0;
+}
diff --git a/lib/drivers/pwm/pwm.c b/lib/drivers/pwm/pwm.c
new file mode 100644 (file)
index 0000000..b7f578d
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Generic GPIO led
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "private-lib-core.h"
+
+static const lws_led_intensity_t sineq16[] = {
+
+       /*
+        * Quadrant at sin(270) in 16 samples, normalized so
+        * -1 == 0 and 0 == 32767
+        */
+
+           0,   158,   630,  1411,  2494,  3869,  5522,  7437,
+        9597, 11980, 14562, 17321, 20228, 23225, 26374, 29555,
+       32767 /* to interpolate against */
+};
+
+/*
+ * Elaborate the 90 degree phase table to 360 degrees and offset to +32768,
+ * notice for the last sample we have to interpolate against a 17th sample
+ * reflecting full scale to avoid clipping due to interpolation against the
+ * 16th sample again
+ */
+
+static lws_led_intensity_t
+sine_lu(int n, int next)
+{
+        switch ((n >> 4) & 3) {
+        case 1:
+               /* forwards */
+                return 32768 + sineq16[(n & 15) + next];
+        case 2:
+               /* scan it backwards */
+                return 32768 + sineq16[15 - (n & 15) + (!next)];
+        case 3:
+               /* forwards */
+                return 32768 - sineq16[(n & 15) + next];
+        default:
+               /* scan it backwards */
+                return 32768 - sineq16[15 - (n & 15) + (!next)];
+        }
+}
+
+/*
+ * The normalized phase resolution is 16-bit, however much table you decide to
+ * have needs interpolating or indexing in a reduced number of significant
+ * phase bits if it doesn't have the same phase resolution.
+ *
+ * In this sine table we have a 16 x 15-bit sample quadrant reflected 4 times
+ * to make 360 degrees, so 64 accurate sample points, with the rest of the
+ * intermediate phases generated by linear interpolation.  That probably would
+ * sound a bit funky, but for modulating light dynamically it's more than
+ * enough.
+ */
+
+lws_led_intensity_t
+lws_led_func_sine(lws_led_seq_phase_t n)
+{
+        /*
+         * 2: quadrant
+         * 4: table entry in quadrant
+         * 10: interp (LSB)
+         */
+
+        return (sine_lu(n >> 10, 0) * (0x3ff - (n & 0x3ff)) +
+               sine_lu(n >> 10, 1) * (n & 0x3ff)) / 0x3ff;
+}
+
+lws_led_intensity_t
+lws_led_func_linear(lws_led_seq_phase_t n)
+{
+       return (lws_led_intensity_t)n;
+}
+
+
+static lws_led_intensity_t
+lws_led_func_static(lws_led_seq_phase_t n)
+{
+       return ((int)n * LWS_LED_MAX_INTENSITY) / 2;
+}
+
+const lws_led_sequence_def_t lws_pwmseq_static_off = {
+       .func                   = lws_led_func_static,
+       .ledphase_offset        = 0,
+       .ledphase_total         = 0,
+       .ms                     = 0
+};
+
+const lws_led_sequence_def_t lws_pwmseq_static_half = {
+       .func                   = lws_led_func_static,
+       .ledphase_offset        = 1,
+       .ledphase_total         = 0,
+       .ms                     = 0
+};
+
+const lws_led_sequence_def_t lws_pwmseq_static_on = {
+       .func                   = lws_led_func_static,
+       .ledphase_offset        = 2,
+       .ledphase_total         = 0,
+       .ms                     = 0
+};
+
+const lws_led_sequence_def_t lws_pwmseq_sine_up = {
+       .func                   = lws_led_func_sine,
+       .ledphase_offset        = 0, /* already at 0 amp at 0 phase */
+       .ledphase_total         = LWS_LED_FUNC_PHASE / 2, /* 180 degree ./^ */
+       .ms                     = 300
+};
+
+const lws_led_sequence_def_t lws_pwmseq_sine_down = {
+       .func                   = lws_led_func_sine,
+       .ledphase_offset        = LWS_LED_FUNC_PHASE / 2, /* start at peak */
+       .ledphase_total         = LWS_LED_FUNC_PHASE / 2, /* 180 degree ./^ */
+       .ms                     = 300
+};
+
+const lws_led_sequence_def_t lws_pwmseq_linear_wipe = {
+       .func                   = lws_led_func_linear,
+       .ledphase_offset        = 0,
+       .ledphase_total         = LWS_LED_FUNC_PHASE - 1,
+       .ms                     = 300
+};
+
+const lws_led_sequence_def_t lws_pwmseq_sine_endless_slow = {
+       .func                   = lws_led_func_sine,
+       .ledphase_offset        = 0, /* already at 0 amp at 0 phase */
+       .ledphase_total         = LWS_SEQ_LEDPHASE_TOTAL_ENDLESS,
+       .ms                     = 1500
+};
+
+const lws_led_sequence_def_t lws_pwmseq_sine_endless_fast = {
+       .func                   = lws_led_func_sine,
+       .ledphase_offset        = 0, /* already at 0 amp at 0 phase */
+       .ledphase_total         = LWS_SEQ_LEDPHASE_TOTAL_ENDLESS,
+       .ms                     = 750
+};
diff --git a/lib/drivers/settings/settings.c b/lib/drivers/settings/settings.c
new file mode 100644 (file)
index 0000000..cc3e2cb
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * lws_settings
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+lws_settings_instance_t *
+lws_settings_init(const lws_settings_ops_t *so, void *opaque_plat)
+{
+       lws_settings_instance_t *si = lws_zalloc(sizeof(*si), __func__);
+
+       if (!si)
+               return NULL;
+
+       si->so = so;
+       si->opaque_plat = opaque_plat;
+
+       return si;
+}
+
+void
+lws_settings_deinit(lws_settings_instance_t **si)
+{
+       lws_free(*si);
+       *si = NULL;
+}
+
+int
+lws_settings_plat_printf(lws_settings_instance_t *si, const char *name,
+                        const char *format, ...)
+{
+       va_list ap;
+       uint8_t *p;
+       int n;
+
+       va_start(ap, format);
+       n = vsnprintf(NULL, 0, format, ap);
+       va_end(ap);
+
+       p = lws_malloc(n + 2, __func__);
+       va_start(ap, format);
+       vsnprintf((char *)p, n + 2, format, ap);
+       va_end(ap);
+
+       n = si->so->set(si, name, p, n);
+       lws_free(p);
+
+       return n;
+}
diff --git a/lib/drivers/spi/bitbang/lws-bb-spi.c b/lib/drivers/spi/bitbang/lws-bb-spi.c
new file mode 100644 (file)
index 0000000..10f9bc5
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * SPI bitbang implementation using generic gpio
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <libwebsockets.h>
+
+int
+lws_bb_spi_init(const lws_spi_ops_t *octx)
+{
+       lws_bb_spi_t *ctx = (lws_bb_spi_t *)octx;
+       int n;
+
+       for (n = 0; n < LWS_SPI_BB_MAX_CH; n++) {
+               if (ctx->flags & (1 << n))
+                       ctx->gpio->mode(ctx->ncs[n], LWSGGPIO_FL_WRITE);
+               if (ctx->flags & (1 << (n + 4)))
+                       ctx->gpio->mode(ctx->ncmd[n], LWSGGPIO_FL_WRITE);
+       }
+
+       ctx->gpio->mode(ctx->clk, LWSGGPIO_FL_WRITE |
+                                 ((octx->bus_mode & LWSSPIMODE_CPOL) ?
+                                          0 : LWSGGPIO_FL_START_LOW));
+       ctx->gpio->mode(ctx->mosi, LWSGGPIO_FL_WRITE | LWSGGPIO_FL_START_LOW);
+       ctx->gpio->mode(ctx->miso, LWSGGPIO_FL_READ | LWSGGPIO_FL_PULLUP);
+
+       return 0;
+}
+
+/* if active, prepare DnC before this and call separately for Cmd / Data */
+
+static void
+lws_bb_spi_write(lws_bb_spi_t *ctx, const uint8_t *buf, size_t len)
+{
+       uint8_t u, inv = !!(ctx->bb_ops.bus_mode & LWSSPIMODE_CPOL);
+
+       while (len--) {
+               int n;
+
+               u = *buf++;
+
+               for (n = 0; n < 4; n++) {
+                       ctx->gpio->set(ctx->clk, inv);
+                       ctx->gpio->set(ctx->mosi, !!(u & 0x80));
+                       ctx->gpio->set(ctx->clk, !inv);
+                       ctx->gpio->set(ctx->clk, inv);
+                       ctx->gpio->set(ctx->mosi, !!(u & 0x40));
+                       ctx->gpio->set(ctx->clk, !inv);
+                       u <<= 2;
+               }
+       }
+
+       ctx->gpio->set(ctx->clk, 0 ^ inv);
+}
+
+static void
+lws_bb_spi_read(lws_bb_spi_t *ctx, uint8_t *buf, size_t len)
+{
+       uint8_t u = 0;
+       uint8_t inv = !!(ctx->bb_ops.bus_mode & LWSSPIMODE_CPOL);
+
+       while (len--) {
+               int n;
+
+               for (n = 0; n < 8; n++) {
+                       ctx->gpio->set(ctx->clk, inv);
+                       u = (u << 1) | !!ctx->gpio->read(ctx->miso);
+                       ctx->gpio->set(ctx->mosi, !!(u & 0x80));
+                       ctx->gpio->set(ctx->clk, !inv);
+               }
+               *buf++ = u;
+       }
+
+       ctx->gpio->set(ctx->clk, 0 ^ inv);
+}
+
+int
+lws_bb_spi_queue(const lws_spi_ops_t *octx, const lws_spi_desc_t *desc)
+{
+       lws_bb_spi_t *ctx = (lws_bb_spi_t *)octx;
+       const uint8_t *src = desc->src;
+
+       /* clock to idle */
+       ctx->gpio->set(ctx->clk, 0 ^ !!(octx->bus_mode & LWSSPIMODE_CPOL));
+       /* enable nCS */
+       ctx->gpio->set(ctx->ncs[desc->channel], 0);
+
+       if (desc->count_cmd) {
+               ctx->gpio->set(ctx->ncmd[desc->channel], 0);
+               lws_bb_spi_write(ctx, src, desc->count_cmd);
+               ctx->gpio->set(ctx->ncmd[desc->channel], 1);
+
+               src += desc->count_cmd;
+       }
+
+       if (desc->count_write)
+               lws_bb_spi_write(ctx, desc->data, desc->count_write);
+
+       if (desc->count_read)
+               lws_bb_spi_read(ctx, desc->dest, desc->count_read);
+
+       /* disable nCS */
+       ctx->gpio->set(ctx->ncs[desc->channel], 1);
+
+       /* clock to idle */
+       ctx->gpio->set(ctx->clk, 0 ^ !!(octx->bus_mode & LWSSPIMODE_CPOL));
+
+       return 0;
+}
diff --git a/lib/drivers/spi/lws-spi.c b/lib/drivers/spi/lws-spi.c
new file mode 100644 (file)
index 0000000..2d41ecf
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Generic SPI
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <libwebsockets.h>
+       
diff --git a/lib/event-libs/CMakeLists.txt b/lib/event-libs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8cbbc2f
--- /dev/null
@@ -0,0 +1,109 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+include_directories(.)
+
+macro(create_evlib_plugin PLUGIN_NAME MAIN_SRC PLUGIN_HDR EVLIB)
+
+       set(PLUGIN_SRCS ${MAIN_SRC})
+
+       source_group("Headers Private"   FILES ${PLUGIN_HDR})
+       source_group("Sources"   FILES ${MAIN_SRC})
+       add_library(websockets-${PLUGIN_NAME} SHARED ${MAIN_SRC} ${PLUGIN_HDR})
+
+       if (APPLE)
+               set_property(TARGET websockets-${PLUGIN_NAME} PROPERTY MACOSX_RPATH YES)
+       endif()
+
+       foreach(libpath ${LWS_DEP_LIB_PATHS})
+               target_link_directories(${TEST_NAME} ${libpath})
+       endforeach()
+
+       target_link_libraries(websockets-${PLUGIN_NAME} websockets_shared ${EVLIB})
+       add_dependencies(websockets-${PLUGIN_NAME} websockets_shared)
+       target_compile_definitions(websockets-${PLUGIN_NAME} PRIVATE LWS_BUILDING_SHARED)
+
+       target_include_directories(websockets-${PLUGIN_NAME} PRIVATE
+                       ${PLUGIN_INCLUDE} ${LWS_LIB_BUILD_INC_PATHS})
+
+       # Set test app specific defines.
+       #       set_property(TARGET ${PLUGIN_NAME}
+       #            PROPERTY COMPILE_DEFINITIONS
+       #            INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/evlib-plugins"
+       #)
+
+       set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+       install(TARGETS websockets-${PLUGIN_NAME}
+               EXPORT LibwebsocketsTargets
+               LIBRARY DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}"
+               COMPONENT ${PLUGIN_NAME})
+               
+       list(APPEND EVLIB_PLUGINS_LIST websockets-${PLUGIN_NAME})
+
+endmacro()
+
+#
+# poll support gets built into the lib as the default
+#
+
+if (LWS_WITH_POLL)
+       add_subdir_include_directories(poll)
+endif()
+
+if (LWS_WITH_LIBUV OR LWS_WITH_LIBUV_INTERNAL)
+       add_subdir_include_directories(libuv)
+       set(LWS_HAVE_UV_VERSION_H ${LWS_HAVE_UV_VERSION_H} PARENT_SCOPE)
+       set(LWS_HAVE_NEW_UV_VERSION_H ${LWS_HAVE_NEW_UV_VERSION_H} PARENT_SCOPE)
+endif()
+
+if (LWS_WITH_LIBEVENT)
+       add_subdir_include_directories(libevent)
+endif()
+
+if (LWS_WITH_GLIB)
+       add_subdir_include_directories(glib)
+endif()
+
+if (LWS_WITH_LIBEV)
+       add_subdir_include_directories(libev)
+       set(LWS_HAVE_EVBACKEND_LINUXAIO ${LWS_HAVE_EVBACKEND_LINUXAIO} PARENT_SCOPE)
+       set(LWS_HAVE_EVBACKEND_IOURING ${LWS_HAVE_EVBACKEND_IOURING} PARENT_SCOPE)
+endif()
+
+if (LWS_WITH_SDEVENT)
+       add_subdir_include_directories(sdevent)
+endif()
+
+if (LWS_WITH_ULOOP)
+       add_subdir_include_directories(uloop)
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+export_to_parent_intermediate()
+set(EVLIB_PLUGINS_LIST ${EVLIB_PLUGINS_LIST} PARENT_SCOPE)
+
index ccfbb7c..5d49bec 100644 (file)
@@ -2,12 +2,30 @@
 
 ### Introduction
 
-By default lws has built-in support for POSIX poll() as the event loop.
-
-However either to get access to epoll() or other platform specific better
-poll waits, or to integrate with existing applications already using a
-specific event loop, it can be desirable for lws to use another external
-event library, like libuv, libevent or libev.
+By default lws has built-in support for POSIX poll() as the event loop on unix,
+and native WSA on windows.
+
+To get access to epoll() or other platform specific better poll waits, or to
+integrate with existing applications already using a specific event loop, it can
+be desirable for lws to use another external event library, like libuv, glib,
+libevent, libev, or sdevent.
+
+Lws supports wholesale replacement of its wait selectable at runtime, either by
+building support for one or more event lib into the libwebsockets library, or by
+building runtime-loadable plugins.  CMake symbol `LWS_WITH_EVLIB_PLUGINS`
+decides if the support is built as plugins or included into the lws lib.
+
+Due to their history libevent and libev have conflicting defines in the same
+namespace and cannot be built together if included into the lib, however when
+built as plugins they are built separately without problems.
+See ./READMEs/README.event-libs.md for more details.
+
+Despite it may be more work, lws event lib implementations must support
+"foreign" loops cleanly, that is integration with an already-existing loop and
+the ability to destroy the lws_context without stopping or leaving the foreign
+loop in any different state than when lws found it.  For most loops this is
+fairly simple, but with libuv async close, it required refcounting lws libuv
+handles and deferring the actual destroy until they were all really closed.
 
 ### Code placement
 
@@ -15,89 +33,114 @@ The code specific to the event library should live in `./lib/event-libs/**lib na
 
 ### Allowing control over enabling event libs
 
-All event libs should add a cmake define `LWS_WITH_**lib name**` and make its build
-dependent on it in CMakeLists.txt.  Export the cmakedefine in `./cmake/lws_config.h.in`
-as well so user builds can understand if the event lib is available in the lws build it is
-trying to bind to.
+All event libs should add a cmake define `LWS_WITH_**lib name**` and make its
+build dependent on it in CMakeLists.txt.  Export the cmakedefine in
+`./cmake/lws_config.h.in` as well so user builds can understand if the event
+lib is available in the lws build it is trying to bind to.
 
-If the event lib is disabled in cmake, nothing in its directory is built or referenced.
+If the event lib is disabled in cmake, nothing in its directory is built or
+referenced.
 
 ### Event loop ops struct
 
-The event lib support is defined by `struct lws_event_loop_ops` in `lib/event-libs/private.h`,
-each event lib support instantiates one of these and fills in the appropriate ops
-callbacks to perform its job.  By convention that lives in
+The event lib support is defined by `struct lws_event_loop_ops` in
+`lib/event-libs/private-lib-event-libs.h`,
+each event lib support instantiates one of these and fills in the appropriate
+ops callbacks to perform its job.  By convention that lives in
 `./lib/event-libs/**lib name**/**lib_name**.c`.
 
+The ops struct must be public, not static, and must be named using `**lib_name**`,
+eg
+
+```
+```
+
 ### Private event lib declarations
 
-Truly private declarations for the event lib can go in the event-libs directory as you like.
-However when the declarations must be accessible to other things in lws build, eg,
-the event lib support adds members to `struct lws` when enabled, they should be in the
-event lib supporr directory in a file `private.h`.
+Truly private declarations for the event lib support that are only referenced by
+that code can go in the event-libs directory as you like.  The convention is
+they should be in the event lib support directory in a file
+`private-lib-event-libs-**lib name**.h`.
+
+### Integration with lws
+
+There are a couple of places to add refererences in ./lib/core/context.c, in a
+table of context creation time server option flags mapped to the **lib_name**,
+used for plugin mode, like this...
+
+```
+#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)
+static const struct lws_evlib_map {
+       uint64_t        flag;
+       const char      *name;
+} map[] = {
+       { LWS_SERVER_OPTION_LIBUV,    "evlib_uv" },
+       { LWS_SERVER_OPTION_LIBEVENT, "evlib_event" },
+       { LWS_SERVER_OPTION_GLIB,     "evlib_glib" },
+       { LWS_SERVER_OPTION_LIBEV,    "evlib_ev" },
+};
+```
 
-Search for "bring in event libs private declarations" in `./lib/core/private.h
-and add your private event lib support file there following the style used for the other
-event libs, eg,
+and for backwards compatibility add a stanza to the built-in checks like this
 
 ```
 #if defined(LWS_WITH_LIBUV)
- #include "event-libs/libuv/private.h"
+       if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV)) {
+               extern const lws_plugin_evlib_t evlib_uv;
+               plev = &evlib_uv;
+       }
 #endif
 ```
 
-If the event lib support is disabled at cmake, nothing from its private.h should be used anywhere.
+Both entries are the way the main libs hook up to the selected event lib ops
+struct at runtime.
 
 ### Integrating event lib assets to lws
 
-If your event lib needs special storage in lws objects, that's no problem.  But to keep
-things sane, there are some rules.
-
- - declare a "container struct" in your private.h for everything, eg, the libuv event
-   lib support need to add its own assets in the perthread struct, it declares in its private.h
+Declare "container structs" in your private....h for anything you need at
+wsi, pt, vhost and context levels, eg, the libuv event lib support need to
+add its own assets in the perthread struct, it declares in its private....h
 
 ```
 struct lws_pt_eventlibs_libuv {
        uv_loop_t *io_loop;
+       struct lws_context_per_thread *pt;
        uv_signal_t signals[8];
-       uv_timer_t timeout_watcher;
-       uv_timer_t hrtimer;
+       uv_timer_t sultimer;
        uv_idle_t idle;
+       struct lws_signal_watcher_libuv w_sigint;
 };
 ```
 
- - add your event lib content in one place in the related lws struct, protected by `#if defined(LWS_WITH_**lib name**)`,
-   eg, again for LWS_WITH_LIBUV
+this is completely private and opaque, but in the ops struct there are provided
+four entries to export the sizes of these event-lib specific objects
 
 ```
-struct lws_context_per_thread {
-
-...
-
-#if defined(LWS_WITH_LIBUV)
-       struct lws_pt_eventlibs_libuv uv;
-#endif
-
 ...
+       /* evlib_size_ctx */    sizeof(struct lws_context_eventlibs_libuv),
+       /* evlib_size_pt */     sizeof(struct lws_pt_eventlibs_libuv),
+       /* evlib_size_vh */     0,
+       /* evlib_size_wsi */    sizeof(struct lws_io_watcher_libuv),
+};
 ```
 
-### Adding to lws available event libs list
+If the particular event lib doesn't need to have a private footprint in an
+object, it can just set the size it needs there to 0.
 
-Edit the NULL-terminated array `available_event_libs` at the top of `./lib/context.c` to include
-a pointer to your new event lib support's ops struct, following the style already there.
+When the context, pts, vhosts or wsis are created in lws, they over-allocate
+to also allow for the event lib object, and set a pointer in the lws object
+being created to point at the over-allocation.  For example for the wsi
 
 ```
-const struct lws_event_loop_ops *available_event_libs[] = {
-#if defined(LWS_WITH_POLL)
-       &event_loop_ops_poll,
+#if defined(LWS_WITH_EVENT_LIBS)
+       void                            *evlib_wsi; /* overallocated */
 #endif
-#if defined(LWS_WITH_LIBUV)
-       &event_loop_ops_uv,
-#endif
-...
 ```
 
-This is used to provide a list of avilable configured backends.
+and similarly there are `evlib_pt` and so on for those objects, usable by the
+event lib and opaque to everyone else.  Once the event lib is selected at
+runtime, all of these objects are guaranteed to have the right size object at
+`wsi->evlib_wsi` initialized to zeroes.
 
 ### Enabling event lib adoption
 
@@ -112,13 +155,15 @@ as a guide.
 
 ### Destruction
 
-Ending the event loop is generally a bit tricky, because if the event loop is internal
-to the lws context, you cannot destroy it while the event loop is running.
+Ending the event loop is generally a bit tricky, because if the event loop is
+internal to the lws context, you cannot destroy it while the event loop is
+running.
 
-Don't add special exports... we tried that, it's a huge mess.  The same user code should be able
-work with any of the event loops including poll.
+Don't add special exports... we tried that, it's a huge mess.  The same user
+code should be able work with any of the event loops including poll.
 
-The solution we found was hide the different processing necessary for the different cases in
-lws_destroy_context().  To help with that there are ops available at two different places in
-the context destroy processing.
+The solution we found was hide the different processing necessary for the
+different cases in `lws_destroy_context()`.  To help with that there are event
+lib ops available that will be called at two different places in the context
+destroy processing.
 
diff --git a/lib/event-libs/glib/CMakeLists.txt b/lib/event-libs/glib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..90b5222
--- /dev/null
@@ -0,0 +1,77 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+set(LWS_GLIB_INCLUDE_DIRS CACHE PATH "Path to the glib include directory")
+set(LWS_GLIB_LIBRARIES CACHE PATH "Path to the glib library")
+
+include (FindPkgConfig)
+if (NOT GLIB_FOUND)
+       find_path(GLIB_INCLUDE_DIRS NAMES glib-2.0/glib.h)
+       find_library(GLIB_LIBRARIES NAMES glib-2.0)
+       if (GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES)
+               set(GLIB_FOUND)
+       endif()
+       if (GLIB_INCLUDE_DIRS)
+               set(GLIB_INCLUDE_DIRS "${GLIB_INCLUDE_DIRS}/glib-2.0" PARENT_SCOPE)
+       endif()
+endif()
+PKG_SEARCH_MODULE(LWS_GLIB2 glib-2.0)
+if (LWS_GLIB2_FOUND)
+       list(APPEND GLIB_INCLUDE_DIRS "${LWS_GLIB2_INCLUDE_DIRS}")
+endif()
+
+message("glib include dir: ${GLIB_INCLUDE_DIRS}")
+message("glib libraries: ${GLIB_LIBRARIES}")
+include_directories("${GLIB_INCLUDE_DIRS}")
+
+if (LWS_WITH_EVLIB_PLUGINS)
+
+       create_evlib_plugin(evlib_glib
+                           glib.c
+                           private-lib-event-libs-glib.h
+                           ${GLIB_LIBRARIES})
+
+else()
+
+       list(APPEND LIB_LIST ${GLIB_LIBRARIES})
+       
+       if (LWS_WITH_NETWORK)
+               list(APPEND SOURCES
+                       event-libs/glib/glib.c)
+       endif()
+
+endif()
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
diff --git a/lib/event-libs/glib/glib.c b/lib/event-libs/glib/glib.c
new file mode 100644 (file)
index 0000000..14c779e
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+#include <glib-unix.h>
+
+#include "private-lib-event-libs-glib.h"
+
+#if !defined(G_SOURCE_FUNC)
+#define G_SOURCE_FUNC(f)         ((GSourceFunc) (void (*)(void)) (f))
+#endif
+
+#define pt_to_priv_glib(_pt) ((struct lws_pt_eventlibs_glib *)(_pt)->evlib_pt)
+#define wsi_to_priv_glib(_w) ((struct lws_wsi_eventlibs_glib *)(_w)->evlib_wsi)
+
+#define wsi_to_subclass(_w)      (wsi_to_priv_glib(_w)->w_read.source)
+#define wsi_to_gsource(_w)       ((GSource *)wsi_to_subclass(_w))
+#define pt_to_loop(_pt)                  (pt_to_priv_glib(_pt)->loop)
+#define pt_to_g_main_context(_pt) g_main_loop_get_context(pt_to_loop(_pt))
+
+#define lws_gs_valid(t)                  (t.gs)
+#define lws_gs_destroy(t)        if (lws_gs_valid(t)) { \
+                                       g_source_destroy(t.gs); \
+                                       g_source_unref(t.gs); \
+                                       t.gs = NULL; t.tag = 0; }
+
+static gboolean
+lws_glib_idle_timer_cb(void *p);
+
+static gboolean
+lws_glib_hrtimer_cb(void *p);
+
+static gboolean
+lws_glib_check(GSource *src)
+{
+       struct lws_io_watcher_glib_subclass *sub =
+                       (struct lws_io_watcher_glib_subclass *)src;
+
+       return !!g_source_query_unix_fd(src, sub->tag);
+}
+
+/*
+ * These helpers attach only to the main_context that belongs to the pt's glib
+ * mainloop.  The simpler g_timeout_add() and g_idle_add() are forbidden
+ * because they implicitly choose the default main context to attach to
+ * instead of specifically the loop bound to the pt.
+ *
+ * https://developer.gnome.org/programming-guidelines/unstable/main-contexts.html.en#what-is-gmaincontext
+ */
+
+static int
+lws_glib_set_idle(struct lws_context_per_thread *pt)
+{
+       if (lws_gs_valid(pt_to_priv_glib(pt)->idle))
+               return 0;
+
+       pt_to_priv_glib(pt)->idle.gs = g_idle_source_new();
+       if (!pt_to_priv_glib(pt)->idle.gs)
+               return 1;
+
+       g_source_set_callback(pt_to_priv_glib(pt)->idle.gs,
+                             lws_glib_idle_timer_cb, pt, NULL);
+       pt_to_priv_glib(pt)->idle.tag = g_source_attach(
+                       pt_to_priv_glib(pt)->idle.gs, pt_to_g_main_context(pt));
+
+       return 0;
+}
+
+static int
+lws_glib_set_timeout(struct lws_context_per_thread *pt, unsigned int ms)
+{
+       lws_gs_destroy(pt_to_priv_glib(pt)->hrtimer);
+
+       pt_to_priv_glib(pt)->hrtimer.gs = g_timeout_source_new(ms);
+       if (!pt_to_priv_glib(pt)->hrtimer.gs)
+               return 1;
+
+       g_source_set_callback(pt_to_priv_glib(pt)->hrtimer.gs,
+                             lws_glib_hrtimer_cb, pt, NULL);
+       pt_to_priv_glib(pt)->hrtimer.tag = g_source_attach(
+                                               pt_to_priv_glib(pt)->hrtimer.gs,
+                                               pt_to_g_main_context(pt));
+
+       return 0;
+}
+
+static gboolean
+lws_glib_dispatch(GSource *src, GSourceFunc x, gpointer userData)
+{
+       struct lws_io_watcher_glib_subclass *sub =
+                       (struct lws_io_watcher_glib_subclass *)src;
+       struct lws_context_per_thread *pt;
+       struct lws_pollfd eventfd;
+       GIOCondition cond;
+
+       cond = g_source_query_unix_fd(src, sub->tag);
+       eventfd.revents = (short)cond;
+
+       /* translate from glib event namespace to platform */
+
+       if (cond & G_IO_IN)
+               eventfd.revents |= LWS_POLLIN;
+       if (cond & G_IO_OUT)
+               eventfd.revents |= LWS_POLLOUT;
+       if (cond & G_IO_ERR)
+               eventfd.revents |= LWS_POLLHUP;
+       if (cond & G_IO_HUP)
+               eventfd.revents |= LWS_POLLHUP;
+
+       eventfd.events = eventfd.revents;
+       eventfd.fd = sub->wsi->desc.sockfd;
+
+       lwsl_wsi_debug(sub->wsi, "fd %d, events %d",
+                                eventfd.fd, eventfd.revents);
+
+       pt = &sub->wsi->a.context->pt[(int)sub->wsi->tsi];
+       if (pt->is_destroyed)
+               return G_SOURCE_CONTINUE;
+
+       lws_service_fd_tsi(sub->wsi->a.context, &eventfd, sub->wsi->tsi);
+
+       if (!lws_gs_valid(pt_to_priv_glib(pt)->idle))
+               lws_glib_set_idle(pt);
+
+       if (pt->destroy_self)
+               lws_context_destroy(pt->context);
+
+       return G_SOURCE_CONTINUE;
+}
+
+static const GSourceFuncs lws_glib_source_ops = {
+    .prepare   = NULL,
+    .check     = lws_glib_check,
+    .dispatch  = lws_glib_dispatch,
+    .finalize  = NULL,
+};
+
+/*
+ * This is the callback for a timer object that is set to the earliest scheduled
+ * lws event... it services any lws scheduled events that are ready, and then
+ * resets the event loop timer to the earliest remaining event, if any.
+ */
+
+static gboolean
+lws_glib_hrtimer_cb(void *p)
+{
+       struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
+       unsigned int ms;
+       lws_usec_t us;
+
+       lws_pt_lock(pt, __func__);
+
+       lws_gs_destroy(pt_to_priv_glib(pt)->hrtimer);
+
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
+       if (us) {
+               ms = (unsigned int)(us / LWS_US_PER_MS);
+               if (!ms)
+                       ms = 1;
+
+               lws_glib_set_timeout(pt, ms);
+       }
+
+       lws_pt_unlock(pt);
+
+       lws_glib_set_idle(pt);
+
+       return FALSE; /* stop it repeating */
+}
+
+static gboolean
+lws_glib_idle_timer_cb(void *p)
+{
+       struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
+
+       if (pt->is_destroyed)
+               return FALSE;
+
+       lws_service_do_ripe_rxflow(pt);
+       lws_glib_hrtimer_cb(pt);
+
+       /*
+        * is there anybody with pending stuff that needs service forcing?
+        */
+       if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
+               /* -1 timeout means just do forced service */
+               _lws_plat_service_forced_tsi(pt->context, pt->tid);
+               /* still somebody left who wants forced service? */
+               if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
+                       return TRUE;
+       }
+
+       if (pt->destroy_self)
+               lws_context_destroy(pt->context);
+
+       /*
+        * For glib, this disables the idle callback.  Otherwise we keep
+        * coming back here immediately endlessly.
+        *
+        * We reenable the idle callback on the next network or scheduled event
+        */
+
+       lws_gs_destroy(pt_to_priv_glib(pt)->idle);
+
+       return FALSE;
+}
+
+void
+lws_glib_sigint_cb(void *ctx)
+{
+       struct lws_context_per_thread *pt = ctx;
+
+       pt->inside_service = 1;
+
+       if (pt->context->eventlib_signal_cb) {
+               pt->context->eventlib_signal_cb(NULL, 0);
+
+               return;
+       }
+       if (!pt->event_loop_foreign)
+               g_main_loop_quit(pt_to_loop(pt));
+}
+
+static int
+elops_init_context_glib(struct lws_context *context,
+                        const struct lws_context_creation_info *info)
+{
+//     int n;
+
+       context->eventlib_signal_cb = info->signal_cb;
+
+//     for (n = 0; n < context->count_threads; n++)
+//             pt_to_priv_glib(&context->pt[n])->w_sigint.context = context;
+
+       return 0;
+}
+
+static int
+elops_accept_glib(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_wsi_eventlibs_glib *wsipr = wsi_to_priv_glib(wsi);
+       int fd;
+
+       assert(!wsi_to_subclass(wsi));
+
+       wsi_to_subclass(wsi) = (struct lws_io_watcher_glib_subclass *)
+                       g_source_new((GSourceFuncs *)&lws_glib_source_ops,
+                                               sizeof(*wsi_to_subclass(wsi)));
+       if (!wsi_to_subclass(wsi))
+               return 1;
+
+       wsipr->w_read.context = wsi->a.context;
+       wsi_to_subclass(wsi)->wsi = wsi;
+
+       if (wsi->role_ops->file_handle)
+               fd = wsi->desc.filefd;
+       else
+               fd = wsi->desc.sockfd;
+
+       wsi_to_subclass(wsi)->tag = g_source_add_unix_fd(wsi_to_gsource(wsi),
+                                               fd, (GIOCondition)LWS_POLLIN);
+       wsipr->w_read.actual_events = LWS_POLLIN;
+
+       g_source_set_callback(wsi_to_gsource(wsi),
+                       G_SOURCE_FUNC(lws_service_fd), wsi->a.context, NULL);
+
+       g_source_attach(wsi_to_gsource(wsi), pt_to_g_main_context(pt));
+
+       return 0;
+}
+
+static int
+elops_listen_init_glib(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+
+       elops_accept_glib(wsi);
+
+       return 0;
+}
+
+static int
+elops_init_pt_glib(struct lws_context *context, void *_loop, int tsi)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_pt_eventlibs_glib *ptpr = pt_to_priv_glib(pt);
+       GMainLoop *loop = (GMainLoop *)_loop;
+
+       if (!loop)
+               loop = g_main_loop_new(NULL, 0);
+       else
+               context->pt[tsi].event_loop_foreign = 1;
+
+       if (!loop) {
+               lwsl_cx_err(context, "creating glib loop failed");
+
+               return -1;
+       }
+
+       ptpr->loop = loop;
+
+       lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_glib);
+
+       lws_glib_set_idle(pt);
+
+       /* Register the signal watcher unless it's a foreign loop */
+
+       if (pt->event_loop_foreign)
+               return 0;
+
+       ptpr->sigint.tag = g_unix_signal_add(SIGINT,
+                                       G_SOURCE_FUNC(lws_glib_sigint_cb), pt);
+
+       return 0;
+}
+
+/*
+ * We are changing the event wait for this guy
+ */
+
+static void
+elops_io_glib(struct lws *wsi, unsigned int flags)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_wsi_eventlibs_glib *wsipr = wsi_to_priv_glib(wsi);
+       GIOCondition cond = wsipr->w_read.actual_events | G_IO_ERR;
+
+       if (!pt_to_loop(pt) || wsi->a.context->being_destroyed ||
+           pt->is_destroyed)
+               return;
+
+       if (!wsi_to_subclass(wsi))
+               return;
+
+       /*
+        * We are being given individual set / clear operations using
+        * LWS_EV_ common namespace, convert them to glib namespace bitfield
+        */
+
+       if (flags & LWS_EV_READ) {
+               if (flags & LWS_EV_STOP)
+                       cond &= (unsigned int)~(G_IO_IN | G_IO_HUP);
+               else
+                       cond |= G_IO_IN | G_IO_HUP;
+       }
+
+       if (flags & LWS_EV_WRITE) {
+               if (flags & LWS_EV_STOP)
+                       cond &= (unsigned int)~G_IO_OUT;
+               else
+                       cond |= G_IO_OUT;
+       }
+
+       wsipr->w_read.actual_events = (uint8_t)cond;
+
+       lwsl_wsi_debug(wsi, "fd %d, 0x%x/0x%x", wsi->desc.sockfd,
+                                               flags, (int)cond);
+
+       g_source_modify_unix_fd(wsi_to_gsource(wsi), wsi_to_subclass(wsi)->tag,
+                               cond);
+}
+
+static void
+elops_run_pt_glib(struct lws_context *context, int tsi)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+
+       if (pt_to_loop(pt))
+               g_main_loop_run(pt_to_loop(pt));
+}
+
+static void
+elops_destroy_wsi_glib(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt;
+
+       if (!wsi)
+               return;
+
+       pt = &wsi->a.context->pt[(int)wsi->tsi];
+       if (pt->is_destroyed)
+               return;
+
+       if (!wsi_to_gsource(wsi))
+               return;
+
+       if (wsi_to_subclass(wsi)->tag) {
+               g_source_remove_unix_fd(wsi_to_gsource(wsi),
+                                       wsi_to_subclass(wsi)->tag);
+               wsi_to_subclass(wsi)->tag = NULL;
+       }
+
+       g_source_destroy(wsi_to_gsource(wsi));
+       g_source_unref(wsi_to_gsource(wsi));
+       wsi_to_subclass(wsi) = NULL;
+}
+
+static int
+elops_listen_destroy_glib(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+
+       elops_destroy_wsi_glib(wsi);
+
+       return 0;
+}
+
+static void
+elops_destroy_pt_glib(struct lws_context *context, int tsi)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_pt_eventlibs_glib *ptpr = pt_to_priv_glib(pt);
+
+       if (!pt_to_loop(pt))
+               return;
+
+       lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_glib);
+
+       lws_gs_destroy(ptpr->idle);
+       lws_gs_destroy(ptpr->hrtimer);
+
+       if (!pt->event_loop_foreign) {
+               g_main_loop_quit(pt_to_loop(pt));
+               lws_gs_destroy(ptpr->sigint);
+               g_main_loop_unref(pt_to_loop(pt));
+       }
+
+       pt_to_loop(pt) = NULL;
+}
+
+static int
+elops_destroy_context2_glib(struct lws_context *context)
+{
+       struct lws_context_per_thread *pt = &context->pt[0];
+       int n;
+
+       for (n = 0; n < (int)context->count_threads; n++) {
+               if (!pt->event_loop_foreign)
+                       g_main_loop_quit(pt_to_loop(pt));
+               pt++;
+       }
+
+       return 0;
+}
+
+static int
+elops_wsi_logical_close_glib(struct lws *wsi)
+{
+       elops_destroy_wsi_glib(wsi);
+
+       return 0;
+}
+
+static const struct lws_event_loop_ops event_loop_ops_glib = {
+       /* name */                      "glib",
+       /* init_context */              elops_init_context_glib,
+       /* destroy_context1 */          NULL,
+       /* destroy_context2 */          elops_destroy_context2_glib,
+       /* init_vhost_listen_wsi */     elops_accept_glib,
+       /* init_pt */                   elops_init_pt_glib,
+       /* wsi_logical_close */         elops_wsi_logical_close_glib,
+       /* check_client_connect_ok */   NULL,
+       /* close_handle_manually */     NULL,
+       /* accept */                    elops_accept_glib,
+       /* io */                        elops_io_glib,
+       /* run_pt */                    elops_run_pt_glib,
+       /* destroy_pt */                elops_destroy_pt_glib,
+       /* destroy wsi */               elops_destroy_wsi_glib,
+       /* foreign_thread */            NULL,
+
+       /* flags */                     LELOF_DESTROY_FINAL,
+
+       /* evlib_size_ctx */    0,
+       /* evlib_size_pt */     sizeof(struct lws_pt_eventlibs_glib),
+       /* evlib_size_vh */     0,
+       /* evlib_size_wsi */    sizeof(struct lws_io_watcher_glib),
+};
+
+#if defined(LWS_WITH_EVLIB_PLUGINS)
+LWS_VISIBLE
+#endif
+const lws_plugin_evlib_t evlib_glib = {
+       .hdr = {
+               "glib event loop",
+               "lws_evlib_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .ops    = &event_loop_ops_glib
+};
diff --git a/lib/event-libs/glib/private-lib-event-libs-glib.h b/lib/event-libs/glib/private-lib-event-libs-glib.h
new file mode 100644 (file)
index 0000000..10d9b0c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <glib.h>
+
+typedef struct lws_glib_tag {
+       GSource                 *gs;
+       guint                   tag;
+} lws_glib_tag_t;
+
+struct lws_pt_eventlibs_glib {
+       GMainLoop               *loop;
+
+       lws_glib_tag_t          hrtimer;
+       lws_glib_tag_t          sigint;
+       lws_glib_tag_t          idle;
+
+       //struct lws_signal_watcher_libuv w_sigint;
+};
+
+struct lws_io_watcher_glib_subclass {
+       GSource         base;
+       struct lws      *wsi;
+       gpointer        tag;
+};
+
+/*
+ * One of these is embedded in each wsi
+ */
+
+struct lws_io_watcher_glib {
+       struct lws_io_watcher_glib_subclass *source;    /* these are created and destroyed by glib */
+       struct lws_context *context;
+       uint8_t actual_events;
+};
+
+struct lws_wsi_eventlibs_glib {
+       struct lws_io_watcher_glib w_read;
+};
+
diff --git a/lib/event-libs/libev/CMakeLists.txt b/lib/event-libs/libev/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9fc8540
--- /dev/null
@@ -0,0 +1,88 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+set(LWS_LIBEV_LIBRARIES CACHE PATH "Path to the libev library")
+set(LWS_LIBEV_INCLUDE_DIRS CACHE PATH "Path to the libev include directory")
+
+if (NOT LIBEV_FOUND)
+       find_path(LIBEV_INCLUDE_DIRS NAMES ev.h)
+       find_library(LIBEV_LIBRARIES NAMES ev)
+endif()
+message("libev include dir: ${LIBEV_INCLUDE_DIRS}")
+message("libev libraries: ${LIBEV_LIBRARIES}")
+include_directories("${LIBEV_INCLUDE_DIRS}")
+
+if ("${LWS_LIBEV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBEV_INCLUDE_DIRS}" STREQUAL "")
+else()
+       set(LIBEV_LIBRARIES ${LWS_LIBEV_LIBRARIES})
+       set(LIBEV_INCLUDE_DIRS ${LWS_LIBEV_INCLUDE_DIRS})
+endif()
+
+if (LWS_WITH_EVLIB_PLUGINS)
+
+       create_evlib_plugin(
+               evlib_ev
+               libev.c
+               private-lib-event-libs-libev.h
+               ${LIBEV_LIBRARIES})
+
+else()
+
+       list(APPEND LIB_LIST ${LIBEV_LIBRARIES})
+
+       list(APPEND SOURCES
+                       event-libs/libev/libev.c)
+# see README.build.md for discussion of why of the supported event libs,
+# only libev cannot cope with -Werror
+       set_source_files_properties(event-libs/libev/libev.c
+                                   PROPERTIES COMPILE_FLAGS "-Wno-error" )
+endif()
+
+set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST})
+
+CHECK_C_SOURCE_COMPILES(
+       "#include <ev.h>
+        int main(int argc, char **argv) { return EVBACKEND_LINUXAIO; }
+       " LWS_HAVE_EVBACKEND_LINUXAIO)
+
+CHECK_C_SOURCE_COMPILES(
+       "#include <ev.h>
+        int main(int argc, char **argv) { return EVBACKEND_IOURING; }
+        " LWS_HAVE_EVBACKEND_IOURING)
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+set(LWS_HAVE_EVBACKEND_LINUXAIO ${LWS_HAVE_EVBACKEND_LINUXAIO} PARENT_SCOPE)
+set(LWS_HAVE_EVBACKEND_IOURING ${LWS_HAVE_EVBACKEND_IOURING} PARENT_SCOPE)
index 3e4e90a..4bdede7 100644 (file)
@@ -1,38 +1,48 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
+#include "private-lib-event-libs-libev.h"
+
+#define pt_to_priv_ev(_pt) ((struct lws_pt_eventlibs_libev *)(_pt)->evlib_pt)
+#define vh_to_priv_ev(_vh) ((struct lws_vh_eventlibs_libev *)(_vh)->evlib_vh)
+#define wsi_to_priv_ev(_w) ((struct lws_wsi_eventlibs_libev *)(_w)->evlib_wsi)
 
 static void
 lws_ev_hrtimer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
 {
-       struct lws_context_per_thread *pt =
-                       (struct lws_context_per_thread *)watcher->data;
+       struct lws_pt_eventlibs_libev *ptpr = lws_container_of(watcher,
+                                       struct lws_pt_eventlibs_libev, hrtimer);
+       struct lws_context_per_thread *pt = ptpr->pt;
        lws_usec_t us;
 
        lws_pt_lock(pt, __func__);
-       us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
        if (us) {
-               ev_timer_set(&pt->ev.hrtimer, ((float)us) / 1000000.0, 0);
-               ev_timer_start(pt->ev.io_loop, &pt->ev.hrtimer);
+               ev_timer_set(&ptpr->hrtimer, ((float)us) / 1000000.0, 0);
+               ev_timer_start(ptpr->io_loop, &ptpr->hrtimer);
        }
        lws_pt_unlock(pt);
 }
@@ -40,8 +50,10 @@ lws_ev_hrtimer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
 static void
 lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents)
 {
-       struct lws_context_per_thread *pt = lws_container_of(handle,
-                                       struct lws_context_per_thread, ev.idle);
+       struct lws_pt_eventlibs_libev *ptpr = lws_container_of(handle,
+                                       struct lws_pt_eventlibs_libev, idle);
+       struct lws_context_per_thread *pt = ptpr->pt;
+       int reschedule = 0;
        lws_usec_t us;
 
        lws_service_do_ripe_rxflow(pt);
@@ -51,29 +63,35 @@ lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents)
         */
        if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
                /* -1 timeout means just do forced service */
-               _lws_plat_service_forced_tsi(pt->context, pt->tid);
+               reschedule = _lws_plat_service_forced_tsi(pt->context, pt->tid);
 
        /* account for hrtimer */
 
        lws_pt_lock(pt, __func__);
-       us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
        if (us) {
-               ev_timer_set(&pt->ev.hrtimer, ((float)us) / 1000000.0, 0);
-               ev_timer_start(pt->ev.io_loop, &pt->ev.hrtimer);
+               ev_timer_set(&ptpr->hrtimer, ((float)us) / 1000000.0, 0);
+               ev_timer_start(ptpr->io_loop, &ptpr->hrtimer);
        }
        lws_pt_unlock(pt);
 
        /* there is nobody who needs service forcing, shut down idle */
-       ev_idle_stop(loop, handle);
+       if (!reschedule)
+               ev_idle_stop(loop, handle);
+
+       if (pt->destroy_self)
+               lws_context_destroy(pt->context);
 }
 
 static void
 lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
 {
-       struct lws_context_per_thread *pt;
-       struct lws_io_watcher *lws_io = lws_container_of(watcher,
-                                       struct lws_io_watcher, ev.watcher);
+       struct lws_io_watcher_libev *lws_io = lws_container_of(watcher,
+                                       struct lws_io_watcher_libev, watcher);
        struct lws_context *context = lws_io->context;
+       struct lws_pt_eventlibs_libev *ptpr;
+       struct lws_context_per_thread *pt;
        struct lws_pollfd eventfd;
        struct lws *wsi;
 
@@ -95,13 +113,14 @@ lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
 
        wsi = wsi_from_fd(context, watcher->fd);
        pt = &context->pt[(int)wsi->tsi];
+       ptpr = pt_to_priv_ev(pt);
 
        lws_service_fd_tsi(context, &eventfd, (int)wsi->tsi);
 
-       ev_idle_start(pt->ev.io_loop, &pt->ev.idle);
+       ev_idle_start(ptpr->io_loop, &ptpr->idle);
 }
 
-LWS_VISIBLE void
+void
 lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)
 {
        struct lws_context *context = watcher->data;
@@ -115,17 +134,40 @@ lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)
 }
 
 static int
+elops_listen_init_ev(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+       struct lws_context *context = (struct lws_context *)user;
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+       struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
+       struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
+       struct lws_vhost *vh = wsi->a.vhost;
+
+       w->w_read.context = context;
+       w->w_write.context = context;
+       vh_to_priv_ev(vh)->w_accept.context = context;
+
+       ev_io_init(&vh_to_priv_ev(vh)->w_accept.watcher,
+                  lws_accept_cb, wsi->desc.sockfd, EV_READ);
+       ev_io_start(ptpr->io_loop, &vh_to_priv_ev(vh)->w_accept.watcher);
+
+       return 0;
+}
+
+static int
 elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi)
 {
        struct lws_context_per_thread *pt = &context->pt[tsi];
-       struct ev_signal *w_sigint = &context->pt[tsi].w_sigint.ev.watcher;
-       struct lws_vhost *vh = context->vhost_list;
-       const char *backend_name;
+       struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
+       struct ev_signal *w_sigint = &ptpr->w_sigint.watcher;
        struct ev_loop *loop = (struct ev_loop *)_loop;
+       const char *backend_name;
+       unsigned int backend;
        int status = 0;
-       int backend;
 
-       lwsl_info("%s: loop %p\n", __func__, _loop);
+       lwsl_cx_info(context, "loop %p", _loop);
+
+       ptpr->pt = pt;
 
        if (!loop)
                loop = ev_loop_new(0);
@@ -133,29 +175,14 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi)
                context->pt[tsi].event_loop_foreign = 1;
 
        if (!loop) {
-               lwsl_err("%s: creating event base failed\n", __func__);
+               lwsl_cx_err(context, "creating event base failed");
 
                return -1;
        }
 
-       pt->ev.io_loop = loop;
+       ptpr->io_loop = loop;
 
-       /*
-        * Initialize the accept w_accept with all the listening sockets
-        * and register a callback for read operations
-        */
-       while (vh) {
-               if (vh->lserv_wsi) {
-                       vh->lserv_wsi->w_read.context = context;
-                       vh->w_accept.context = context;
-
-                       ev_io_init(&vh->w_accept.ev.watcher, lws_accept_cb,
-                                  vh->lserv_wsi->desc.sockfd, EV_READ);
-                       ev_io_start(loop, &vh->w_accept.ev.watcher);
-
-               }
-               vh = vh->vhost_next;
-       }
+       lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_ev);
 
        /* Register the signal watcher unless it's a foreign loop */
        if (!context->pt[tsi].event_loop_foreign) {
@@ -180,7 +207,12 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi)
                backend_name = "Linux AIO";
                break;
 #endif
-       case EVBACKEND_KQUEUE:
+#if defined(LWS_HAVE_EVBACKEND_IOURING)
+       case EVBACKEND_IOURING:
+               backend_name = "Linux io_uring";
+               break;
+#endif
+       case EVBACKEND_KQUEUE:
                backend_name = "kqueue";
                break;
        case EVBACKEND_DEVPOLL:
@@ -194,39 +226,46 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi)
                break;
        }
 
-       lwsl_info(" libev backend: %s\n", backend_name);
+       lwsl_cx_info(context, " libev backend: %s", backend_name);
        (void)backend_name;
 
-       ev_timer_init(&pt->ev.hrtimer, lws_ev_hrtimer_cb, 0, 0);
-       pt->ev.hrtimer.data = pt;
+       ev_timer_init(&ptpr->hrtimer, lws_ev_hrtimer_cb, 0, 0);
+       ptpr->hrtimer.data = pt;
 
-       ev_idle_init(&pt->ev.idle, lws_ev_idle_cb);
+       ev_idle_init(&ptpr->idle, lws_ev_idle_cb);
 
        return status;
 }
 
+static int
+elops_listen_destroy_ev(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+       struct lws_context *context = (struct lws_context *)user;
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+       struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
+       struct lws_vhost *vh = wsi->a.vhost;
+
+       ev_io_stop(ptpr->io_loop, &vh_to_priv_ev(vh)->w_accept.watcher);
+
+       return 0;
+}
+
 static void
 elops_destroy_pt_ev(struct lws_context *context, int tsi)
 {
        struct lws_context_per_thread *pt = &context->pt[tsi];
-       struct lws_vhost *vh = context->vhost_list;
+       struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
 
-       while (vh) {
-               if (vh->lserv_wsi)
-                       ev_io_stop(pt->ev.io_loop, &vh->w_accept.ev.watcher);
-               vh = vh->vhost_next;
-       }
+       lws_vhost_foreach_listen_wsi(context, context, elops_listen_destroy_ev);
 
        /* static assets */
 
-       ev_timer_stop(pt->ev.io_loop, &pt->ev.hrtimer);
-       ev_idle_stop(pt->ev.io_loop, &pt->ev.idle);
-
-       if (!pt->event_loop_foreign) {
-               ev_signal_stop(pt->ev.io_loop, &pt->w_sigint.ev.watcher);
+       ev_timer_stop(ptpr->io_loop, &ptpr->hrtimer);
+       ev_idle_stop(ptpr->io_loop, &ptpr->idle);
 
-               ev_loop_destroy(pt->ev.io_loop);
-       }
+       if (!pt->event_loop_foreign)
+               ev_signal_stop(ptpr->io_loop, &ptpr->w_sigint.watcher);
 }
 
 static int
@@ -238,7 +277,7 @@ elops_init_context_ev(struct lws_context *context,
        context->eventlib_signal_cb = info->signal_cb;
 
        for (n = 0; n < context->count_threads; n++)
-               context->pt[n].w_sigint.context = context;
+               pt_to_priv_ev(&context->pt[n])->w_sigint.context = context;
 
        return 0;
 }
@@ -246,6 +285,7 @@ elops_init_context_ev(struct lws_context *context,
 static int
 elops_accept_ev(struct lws *wsi)
 {
+       struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
        int fd;
 
        if (wsi->role_ops->file_handle)
@@ -253,21 +293,27 @@ elops_accept_ev(struct lws *wsi)
        else
                fd = wsi->desc.sockfd;
 
-       wsi->w_read.context = wsi->context;
-       wsi->w_write.context = wsi->context;
+       w->w_read.context = wsi->a.context;
+       w->w_write.context = wsi->a.context;
 
-       ev_io_init(&wsi->w_read.ev.watcher, lws_accept_cb, fd, EV_READ);
-       ev_io_init(&wsi->w_write.ev.watcher, lws_accept_cb, fd, EV_WRITE);
+       ev_io_init(&w->w_read.watcher, lws_accept_cb, fd, EV_READ);
+       ev_io_init(&w->w_write.watcher, lws_accept_cb, fd, EV_WRITE);
 
        return 0;
 }
 
 static void
-elops_io_ev(struct lws *wsi, int flags)
+elops_io_ev(struct lws *wsi, unsigned int flags)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
+       struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
 
-       if (!pt->ev.io_loop)
+       lwsl_wsi_debug(wsi, "%s flags 0x%x %p %d", wsi->role_ops->name, flags,
+                                                  ptpr->io_loop,
+                                                  pt->is_destroyed);
+
+       if (!ptpr->io_loop || pt->is_destroyed)
                return;
 
        assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
@@ -275,51 +321,54 @@ elops_io_ev(struct lws *wsi, int flags)
 
        if (flags & LWS_EV_START) {
                if (flags & LWS_EV_WRITE)
-                       ev_io_start(pt->ev.io_loop, &wsi->w_write.ev.watcher);
+                       ev_io_start(ptpr->io_loop, &w->w_write.watcher);
                if (flags & LWS_EV_READ)
-                       ev_io_start(pt->ev.io_loop, &wsi->w_read.ev.watcher);
+                       ev_io_start(ptpr->io_loop, &w->w_read.watcher);
        } else {
                if (flags & LWS_EV_WRITE)
-                       ev_io_stop(pt->ev.io_loop, &wsi->w_write.ev.watcher);
+                       ev_io_stop(ptpr->io_loop, &w->w_write.watcher);
                if (flags & LWS_EV_READ)
-                       ev_io_stop(pt->ev.io_loop, &wsi->w_read.ev.watcher);
+                       ev_io_stop(ptpr->io_loop, &w->w_read.watcher);
        }
+
+       if (pt->destroy_self)
+               lws_context_destroy(pt->context);
 }
 
 static void
 elops_run_pt_ev(struct lws_context *context, int tsi)
 {
-       if (context->pt[tsi].ev.io_loop)
-               ev_run(context->pt[tsi].ev.io_loop, 0);
+       if (pt_to_priv_ev(&context->pt[tsi])->io_loop)
+               ev_run(pt_to_priv_ev(&context->pt[tsi])->io_loop, 0);
 }
 
 static int
 elops_destroy_context2_ev(struct lws_context *context)
 {
        struct lws_context_per_thread *pt;
+       struct lws_pt_eventlibs_libev *ptpr;
        int n, m;
 
-       lwsl_debug("%s\n", __func__);
-
        for (n = 0; n < context->count_threads; n++) {
                int budget = 1000;
 
                pt = &context->pt[n];
+               ptpr = pt_to_priv_ev(pt);
 
                /* only for internal loops... */
 
-               if (pt->event_loop_foreign || !pt->ev.io_loop)
+               if (pt->event_loop_foreign || !ptpr->io_loop)
                        continue;
 
-               if (!context->finalize_destroy_after_internal_loops_stopped) {
-                       ev_break(pt->ev.io_loop, EVBREAK_ONE);
+               if (!context->evlib_finalize_destroy_after_int_loops_stop) {
+                       ev_break(ptpr->io_loop, EVBREAK_ONE);
                        continue;
                }
                while (budget-- &&
-                      (m = ev_run(pt->ev.io_loop, 0)))
+                      (m = ev_run(ptpr->io_loop, 0)))
                        ;
 
-               ev_loop_destroy(pt->ev.io_loop);
+               ev_loop_destroy(ptpr->io_loop);
        }
 
        return 0;
@@ -328,6 +377,7 @@ elops_destroy_context2_ev(struct lws_context *context)
 static int
 elops_init_vhost_listen_wsi_ev(struct lws *wsi)
 {
+       struct lws_wsi_eventlibs_libev *w;
        int fd;
 
        if (!wsi) {
@@ -335,16 +385,17 @@ elops_init_vhost_listen_wsi_ev(struct lws *wsi)
                return 0;
        }
 
-       wsi->w_read.context = wsi->context;
-       wsi->w_write.context = wsi->context;
+       w = wsi_to_priv_ev(wsi);
+       w->w_read.context = wsi->a.context;
+       w->w_write.context = wsi->a.context;
 
        if (wsi->role_ops->file_handle)
                fd = wsi->desc.filefd;
        else
                fd = wsi->desc.sockfd;
 
-       ev_io_init(&wsi->w_read.ev.watcher, lws_accept_cb, fd, EV_READ);
-       ev_io_init(&wsi->w_write.ev.watcher, lws_accept_cb, fd, EV_WRITE);
+       ev_io_init(&w->w_read.watcher, lws_accept_cb, fd, EV_READ);
+       //ev_io_init(&w->w_write.watcher, lws_accept_cb, fd, EV_WRITE);
 
        elops_io_ev(wsi, LWS_EV_START | LWS_EV_READ);
 
@@ -354,13 +405,15 @@ elops_init_vhost_listen_wsi_ev(struct lws *wsi)
 static void
 elops_destroy_wsi_ev(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
+       struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
 
-       ev_io_stop(pt->ev.io_loop, &wsi->w_read.ev.watcher);
-       ev_io_stop(pt->ev.io_loop, &wsi->w_write.ev.watcher);
+       ev_io_stop(ptpr->io_loop, &w->w_read.watcher);
+       ev_io_stop(ptpr->io_loop, &w->w_write.watcher);
 }
 
-struct lws_event_loop_ops event_loop_ops_ev = {
+static const struct lws_event_loop_ops event_loop_ops_ev = {
        /* name */                      "libev",
        /* init_context */              elops_init_context_ev,
        /* destroy_context1 */          NULL,
@@ -375,6 +428,26 @@ struct lws_event_loop_ops event_loop_ops_ev = {
        /* run_pt */                    elops_run_pt_ev,
        /* destroy_pt */                elops_destroy_pt_ev,
        /* destroy wsi */               elops_destroy_wsi_ev,
+       /* foreign_thread */            NULL,
+
+       /* flags */                     0,
 
-       /* periodic_events_available */ 0,
+       /* evlib_size_ctx */    0,
+       /* evlib_size_pt */     sizeof(struct lws_pt_eventlibs_libev),
+       /* evlib_size_vh */     sizeof(struct lws_vh_eventlibs_libev),
+       /* evlib_size_wsi */    sizeof(struct lws_wsi_eventlibs_libev),
+};
+
+#if defined(LWS_WITH_EVLIB_PLUGINS)
+LWS_VISIBLE
+#endif
+const lws_plugin_evlib_t evlib_ev = {
+       .hdr = {
+               "libev event loop",
+               "lws_evlib_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .ops    = &event_loop_ops_ev
 };
diff --git a/lib/event-libs/libev/private-lib-event-libs-libev.h b/lib/event-libs/libev/private-lib-event-libs-libev.h
new file mode 100644 (file)
index 0000000..5ea002f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <ev.h>
+
+#define LWS_EV_REFCOUNT_STATIC_HANDLE_NEW(_x, _ctx) \
+               { (_x)->data = _ctx; \
+               _ctx->count_event_loop_static_asset_handles++; }
+#define LWS_EV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x) \
+                       ((struct lws_context *)(_x)->data)))
+#define LWS_EV_REFCOUNT_STATIC_HANDLE_DESTROYED(_x) \
+               (--(LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x)-> \
+                               count_event_loop_static_asset_handles))
+
+struct lws_signal_watcher_libev {
+       ev_signal watcher;
+       struct lws_context *context;
+};
+
+struct lws_pt_eventlibs_libev {
+       struct ev_loop *io_loop;
+       struct ev_timer hrtimer;
+       struct ev_idle idle;
+       struct lws_signal_watcher_libev w_sigint;
+       struct lws_context_per_thread *pt;
+};
+
+struct lws_io_watcher_libev {
+       ev_io watcher;
+       struct lws_context *context;
+};
+
+struct lws_vh_eventlibs_libev {
+       struct lws_io_watcher_libev w_accept;
+};
+
+struct lws_wsi_eventlibs_libev {
+       struct lws_io_watcher_libev w_read;
+       struct lws_io_watcher_libev w_write;
+};
+
diff --git a/lib/event-libs/libev/private.h b/lib/event-libs/libev/private.h
deleted file mode 100644 (file)
index 9359f34..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h if LWS_WITH_LIBEV
- */
-
-#include <ev.h>
-
-#define LWS_EV_REFCOUNT_STATIC_HANDLE_NEW(_x, _ctx) \
-               { (_x)->data = _ctx; \
-               _ctx->count_event_loop_static_asset_handles++; }
-#define LWS_EV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x) \
-                       ((struct lws_context *)(_x)->data)))
-#define LWS_EV_REFCOUNT_STATIC_HANDLE_DESTROYED(_x) \
-               (--(LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x)-> \
-                               count_event_loop_static_asset_handles))
-
-struct lws_pt_eventlibs_libev {
-       struct ev_loop *io_loop;
-       struct ev_timer hrtimer;
-       struct ev_idle idle;
-};
-
-struct lws_io_watcher_libev {
-       ev_io watcher;
-};
-
-struct lws_signal_watcher_libev {
-       ev_signal watcher;
-};
-
-struct lws_context_eventlibs_libev {
-       int placeholder;
-};
-
-extern struct lws_event_loop_ops event_loop_ops_ev;
diff --git a/lib/event-libs/libevent/CMakeLists.txt b/lib/event-libs/libevent/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4404178
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+set(LWS_LIBEVENT_INCLUDE_DIRS CACHE PATH "Path to the libevent include directory")
+set(LWS_LIBEVENT_LIBRARIES CACHE PATH "Path to the libevent library")
+
+if (NOT LIBEVENT_FOUND)
+       find_path(LIBEVENT_INCLUDE_DIRS NAMES event2/event.h)
+       find_library(LIBEVENT_LIBRARIES NAMES event)
+endif()
+message("libevent include dir: ${LIBEVENT_INCLUDE_DIRS}")
+message("libevent libraries: ${LIBEVENT_LIBRARIES}")
+include_directories("${LIBEVENT_INCLUDE_DIRS}")
+
+if ("${LWS_LIBEVENT_LIBRARIES}" STREQUAL "" OR "${LWS_LIBEVENT_INCLUDE_DIRS}" STREQUAL "")
+else()
+       set(LIBEVENT_LIBRARIES ${LWS_LIBEVENT_LIBRARIES})
+       set(LIBEVENT_INCLUDE_DIRS ${LWS_LIBEVENT_INCLUDE_DIRS})
+endif()
+
+
+if (LWS_WITH_EVLIB_PLUGINS)
+
+       create_evlib_plugin(evlib_event
+                           libevent.c
+                           private-lib-event-libs-libevent.h
+                           ${LIBEVENT_LIBRARIES})
+
+else()
+
+       list(APPEND LIB_LIST ${LIBEVENT_LIBRARIES})
+       set(LIBEVENT_FOUND 1 PARENT_SCOPE)
+       if (LWS_WITH_NETWORK)
+               list(APPEND SOURCES
+                       event-libs/libevent/libevent.c)
+       endif()
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
index 2c27911..b7b310c 100644 (file)
@@ -1,50 +1,68 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
+#include "private-lib-event-libs-libevent.h"
+
+#define pt_to_priv_event(_pt) ((struct lws_pt_eventlibs_libevent *)(_pt)->evlib_pt)
+#define wsi_to_priv_event(_w) ((struct lws_wsi_eventlibs_libevent *)(_w)->evlib_wsi)
 
 static void
-lws_event_hrtimer_cb(int fd, short event, void *p)
+lws_event_hrtimer_cb(evutil_socket_t fd, short event, void *p)
 {
        struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
+       struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
        struct timeval tv;
        lws_usec_t us;
 
        lws_pt_lock(pt, __func__);
-       us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
        if (us) {
-               tv.tv_sec = us / LWS_US_PER_SEC;
-               tv.tv_usec = us - (tv.tv_sec * LWS_US_PER_SEC);
-               evtimer_add(pt->event.hrtimer, &tv);
+#if defined(__APPLE__)
+               tv.tv_sec = (int)(us / LWS_US_PER_SEC);
+               tv.tv_usec = (int)(us - (tv.tv_sec * LWS_US_PER_SEC));
+#else
+               tv.tv_sec = (long)(us / LWS_US_PER_SEC);
+               tv.tv_usec = (long)(us - (tv.tv_sec * LWS_US_PER_SEC));
+#endif
+               evtimer_add(ptpr->hrtimer, &tv);
        }
        lws_pt_unlock(pt);
 }
 
 static void
-lws_event_idle_timer_cb(int fd, short event, void *p)
+lws_event_idle_timer_cb(evutil_socket_t fd, short event, void *p)
 {
        struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
+       struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
        struct timeval tv;
        lws_usec_t us;
 
+       if (pt->is_destroyed)
+               return;
+
        lws_service_do_ripe_rxflow(pt);
 
        /*
@@ -59,30 +77,33 @@ lws_event_idle_timer_cb(int fd, short event, void *p)
 
                        tv.tv_sec = 0;
                        tv.tv_usec = 1000;
-                       evtimer_add(pt->event.idle_timer, &tv);
+                       evtimer_add(ptpr->idle_timer, &tv);
 
                        return;
                }
        }
 
-       lwsl_debug("%s: wait\n", __func__);
-
        /* account for hrtimer */
 
        lws_pt_lock(pt, __func__);
-       us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
        if (us) {
-               tv.tv_sec = us / LWS_US_PER_SEC;
-               tv.tv_usec = us - (tv.tv_sec * LWS_US_PER_SEC);
-               evtimer_add(pt->event.hrtimer, &tv);
+               tv.tv_sec = (suseconds_t)(us / LWS_US_PER_SEC);
+               tv.tv_usec = (suseconds_t)(us - (tv.tv_sec * LWS_US_PER_SEC));
+               evtimer_add(ptpr->hrtimer, &tv);
        }
        lws_pt_unlock(pt);
+
+       if (pt->destroy_self)
+               lws_context_destroy(pt->context);
 }
 
 static void
 lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx)
 {
-       struct lws_io_watcher *lws_io = (struct lws_io_watcher *)ctx;
+       struct lws_signal_watcher_libevent *lws_io =
+                       (struct lws_signal_watcher_libevent *)ctx;
        struct lws_context *context = lws_io->context;
        struct lws_context_per_thread *pt;
        struct lws_pollfd eventfd;
@@ -114,25 +135,33 @@ lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx)
        }
 
        wsi = wsi_from_fd(context, sock_fd);
-       if (!wsi) {
+       if (!wsi)
                return;
-       }
+
        pt = &context->pt[(int)wsi->tsi];
+       if (pt->is_destroyed)
+               return;
 
        lws_service_fd_tsi(context, &eventfd, wsi->tsi);
 
+       if (pt->destroy_self) {
+               lwsl_cx_notice(context, "pt destroy self coming true");
+               lws_context_destroy(pt->context);
+               return;
+       }
+
        /* set the idle timer for 1ms ahead */
 
        tv.tv_sec = 0;
        tv.tv_usec = 1000;
-       evtimer_add(pt->event.idle_timer, &tv);
+       evtimer_add(pt_to_priv_event(pt)->idle_timer, &tv);
 }
 
-LWS_VISIBLE void
+void
 lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx)
 {
        struct lws_context_per_thread *pt = ctx;
-       struct event *signal = (struct event *)ctx;
+       struct event *signal = pt_to_priv_event(pt)->w_sigint.watcher;
 
        if (pt->context->eventlib_signal_cb) {
                pt->context->eventlib_signal_cb((void *)(lws_intptr_t)sock_fd,
@@ -141,18 +170,36 @@ lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx)
                return;
        }
        if (!pt->event_loop_foreign)
-               event_base_loopbreak(pt->event.io_loop);
+               event_base_loopbreak(pt_to_priv_event(pt)->io_loop);
 }
 
+static int
+elops_listen_init_event(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+       struct lws_context *context = (struct lws_context *)user;
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+       struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
+       struct lws_io_watcher_libevent *w_read =
+                                       &(wsi_to_priv_event(wsi)->w_read);
+
+       w_read->context = context;
+       w_read->watcher = event_new(ptpr->io_loop, wsi->desc.sockfd,
+                               (EV_READ | EV_PERSIST), lws_event_cb, w_read);
+       event_add(w_read->watcher, NULL);
+       w_read->set = 1;
+
+       return 0;
+}
 
 static int
 elops_init_pt_event(struct lws_context *context, void *_loop, int tsi)
 {
-       struct lws_vhost *vh = context->vhost_list;
        struct event_base *loop = (struct event_base *)_loop;
        struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
 
-       lwsl_info("%s: loop %p\n", __func__, _loop);
+       lwsl_cx_info(context, "loop %p", _loop);
 
        if (!loop)
                loop = event_base_new();
@@ -160,46 +207,37 @@ elops_init_pt_event(struct lws_context *context, void *_loop, int tsi)
                context->pt[tsi].event_loop_foreign = 1;
 
        if (!loop) {
-               lwsl_err("%s: creating event base failed\n", __func__);
+               lwsl_cx_err(context, "creating event base failed");
 
                return -1;
        }
 
-       pt->event.io_loop = loop;
+       ptpr->io_loop = loop;
 
-       /*
-       * Initialize all events with the listening sockets
-       * and register a callback for read operations
-       */
-
-       while (vh) {
-               if (vh->lserv_wsi) {
-                       vh->lserv_wsi->w_read.context = context;
-                       vh->lserv_wsi->w_read.event.watcher = event_new(
-                                       loop, vh->lserv_wsi->desc.sockfd,
-                                       (EV_READ | EV_PERSIST), lws_event_cb,
-                                       &vh->lserv_wsi->w_read);
-                       event_add(vh->lserv_wsi->w_read.event.watcher, NULL);
-               }
-               vh = vh->vhost_next;
-       }
+       lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_event);
 
        /* static event loop objects */
 
-       pt->event.hrtimer = event_new(loop, -1, EV_PERSIST,
+       ptpr->hrtimer = event_new(loop, -1, EV_PERSIST,
                                      lws_event_hrtimer_cb, pt);
 
-       pt->event.idle_timer = event_new(loop, -1, 0,
+       ptpr->idle_timer = event_new(loop, -1, 0,
                                         lws_event_idle_timer_cb, pt);
+       {
+               struct timeval tv;
+               tv.tv_sec = (long)0;
+               tv.tv_usec = (long)1000;
+               evtimer_add(ptpr->hrtimer, &tv);
+       }
 
        /* Register the signal watcher unless it's a foreign loop */
 
        if (pt->event_loop_foreign)
                return 0;
 
-       pt->w_sigint.event.watcher = evsignal_new(loop, SIGINT,
+       ptpr->w_sigint.watcher = evsignal_new(loop, SIGINT,
                                                  lws_event_sigint_cb, pt);
-       event_add(pt->w_sigint.event.watcher, NULL);
+       event_add(ptpr->w_sigint.watcher, NULL);
 
        return 0;
 }
@@ -213,7 +251,7 @@ elops_init_context_event(struct lws_context *context,
        context->eventlib_signal_cb = info->signal_cb;
 
        for (n = 0; n < context->count_threads; n++)
-               context->pt[n].w_sigint.context = context;
+               pt_to_priv_event(&context->pt[n])->w_sigint.context = context;
 
        return 0;
 }
@@ -223,50 +261,64 @@ elops_accept_event(struct lws *wsi)
 {
        struct lws_context *context = lws_get_context(wsi);
        struct lws_context_per_thread *pt;
-       int fd;
+       struct lws_pt_eventlibs_libevent *ptpr;
+       struct lws_wsi_eventlibs_libevent *wpr = wsi_to_priv_event(wsi);
+       evutil_socket_t fd;
 
-       wsi->w_read.context = context;
-       wsi->w_write.context = context;
+       wpr->w_read.context = context;
+       wpr->w_write.context = context;
 
        // Initialize the event
        pt = &context->pt[(int)wsi->tsi];
+       ptpr = pt_to_priv_event(pt);
 
        if (wsi->role_ops->file_handle)
-               fd = wsi->desc.filefd;
+               fd = (evutil_socket_t)(ev_intptr_t) wsi->desc.filefd;
        else
                fd = wsi->desc.sockfd;
 
-       wsi->w_read.event.watcher = event_new(pt->event.io_loop, fd,
-                       (EV_READ | EV_PERSIST), lws_event_cb, &wsi->w_read);
-       wsi->w_write.event.watcher = event_new(pt->event.io_loop, fd,
-                       (EV_WRITE | EV_PERSIST), lws_event_cb, &wsi->w_write);
+       wpr->w_read.watcher = event_new(ptpr->io_loop, fd,
+                       (EV_READ | EV_PERSIST), lws_event_cb, &wpr->w_read);
+       wpr->w_write.watcher = event_new(ptpr->io_loop, fd,
+                       (EV_WRITE | EV_PERSIST), lws_event_cb, &wpr->w_write);
 
        return 0;
 }
 
 static void
-elops_io_event(struct lws *wsi, int flags)
+elops_io_event(struct lws *wsi, unsigned int flags)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
+       struct lws_wsi_eventlibs_libevent *wpr = wsi_to_priv_event(wsi);
 
-       if (!pt->event.io_loop || wsi->context->being_destroyed)
+       if (!ptpr->io_loop || wsi->a.context->being_destroyed ||
+           pt->is_destroyed)
                return;
 
        assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
               (flags & (LWS_EV_READ | LWS_EV_WRITE)));
 
        if (flags & LWS_EV_START) {
-               if (flags & LWS_EV_WRITE)
-                       event_add(wsi->w_write.event.watcher, NULL);
+               if ((flags & LWS_EV_WRITE) && !wpr->w_write.set) {
+                       event_add(wpr->w_write.watcher, NULL);
+                       wpr->w_write.set = 1;
+               }
 
-               if (flags & LWS_EV_READ)
-                       event_add(wsi->w_read.event.watcher, NULL);
+               if ((flags & LWS_EV_READ) && !wpr->w_read.set) {
+                       event_add(wpr->w_read.watcher, NULL);
+                       wpr->w_read.set = 1;
+               }
        } else {
-               if (flags & LWS_EV_WRITE)
-                       event_del(wsi->w_write.event.watcher);
+               if ((flags & LWS_EV_WRITE) && wpr->w_write.set) {
+                       event_del(wpr->w_write.watcher);
+                       wpr->w_write.set = 0;
+               }
 
-               if (flags & LWS_EV_READ)
-                       event_del(wsi->w_read.event.watcher);
+               if ((flags & LWS_EV_READ) && wpr->w_read.set) {
+                       event_del(wpr->w_read.watcher);
+                       wpr->w_read.set = 0;
+               }
        }
 }
 
@@ -274,85 +326,114 @@ static void
 elops_run_pt_event(struct lws_context *context, int tsi)
 {
        /* Run / Dispatch the event_base loop */
-       if (context->pt[tsi].event.io_loop)
-               event_base_dispatch(context->pt[tsi].event.io_loop);
+       if (pt_to_priv_event(&context->pt[tsi])->io_loop)
+               event_base_dispatch(
+                       pt_to_priv_event(&context->pt[tsi])->io_loop);
+}
+
+static int
+elops_listen_destroy_event(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+       struct lws_wsi_eventlibs_libevent *w = wsi_to_priv_event(wsi);
+
+       event_free(w->w_read.watcher);
+       w->w_read.watcher = NULL;
+       event_free(w->w_write.watcher);
+       w->w_write.watcher = NULL;
+
+       return 0;
 }
 
 static void
 elops_destroy_pt_event(struct lws_context *context, int tsi)
 {
        struct lws_context_per_thread *pt = &context->pt[tsi];
-       struct lws_vhost *vh = context->vhost_list;
-
-       lwsl_info("%s\n", __func__);
+       struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
 
-       if (!pt->event.io_loop)
+       if (!ptpr->io_loop)
                return;
 
-       /*
-        * Free all events with the listening sockets
-        */
-       while (vh) {
-               if (vh->lserv_wsi) {
-                       event_free(vh->lserv_wsi->w_read.event.watcher);
-                       vh->lserv_wsi->w_read.event.watcher = NULL;
-                       event_free(vh->lserv_wsi->w_write.event.watcher);
-                       vh->lserv_wsi->w_write.event.watcher = NULL;
-               }
-               vh = vh->vhost_next;
-       }
+       lws_vhost_foreach_listen_wsi(context, context, elops_listen_destroy_event);
 
-       event_free(pt->event.hrtimer);
-       event_free(pt->event.idle_timer);
+       event_free(ptpr->hrtimer);
+       event_free(ptpr->idle_timer);
 
        if (!pt->event_loop_foreign) {
-               event_del(pt->w_sigint.event.watcher);
-               event_free(pt->w_sigint.event.watcher);
-
-               event_base_free(pt->event.io_loop);
+               event_del(ptpr->w_sigint.watcher);
+               event_free(ptpr->w_sigint.watcher);
+               event_base_loopexit(ptpr->io_loop, NULL);
+       //      event_base_free(pt->event.io_loop);
+       //      pt->event.io_loop = NULL;
+               lwsl_cx_notice(context, "set to exit loop");
        }
 }
 
 static void
 elops_destroy_wsi_event(struct lws *wsi)
 {
+       struct lws_context_per_thread *pt;
+       struct lws_wsi_eventlibs_libevent *w;
+
        if (!wsi)
                return;
 
-       if (wsi->w_read.event.watcher)
-               event_free(wsi->w_read.event.watcher);
+       pt = &wsi->a.context->pt[(int)wsi->tsi];
+       if (pt->is_destroyed)
+               return;
+
+       w = wsi_to_priv_event(wsi);
+
+       if (w->w_read.watcher) {
+               event_free(w->w_read.watcher);
+               w->w_read.watcher = NULL;
+       }
 
-       if (wsi->w_write.event.watcher)
-               event_free(wsi->w_write.event.watcher);
+       if (w->w_write.watcher) {
+               event_free(w->w_write.watcher);
+               w->w_write.watcher = NULL;
+       }
+}
+
+static int
+elops_wsi_logical_close_event(struct lws *wsi)
+{
+       elops_destroy_wsi_event(wsi);
+
+       return 0;
 }
 
 static int
 elops_init_vhost_listen_wsi_event(struct lws *wsi)
 {
        struct lws_context_per_thread *pt;
-       int fd;
+       struct lws_pt_eventlibs_libevent *ptpr;
+       struct lws_wsi_eventlibs_libevent *w;
+       evutil_socket_t fd;
 
        if (!wsi) {
                assert(0);
                return 0;
        }
 
-       wsi->w_read.context = wsi->context;
-       wsi->w_write.context = wsi->context;
+       w = wsi_to_priv_event(wsi);
 
-       pt = &wsi->context->pt[(int)wsi->tsi];
+       w->w_read.context = wsi->a.context;
+       w->w_write.context = wsi->a.context;
+
+       pt = &wsi->a.context->pt[(int)wsi->tsi];
+       ptpr = pt_to_priv_event(pt);
 
        if (wsi->role_ops->file_handle)
-               fd = wsi->desc.filefd;
+               fd = (evutil_socket_t) wsi->desc.filefd;
        else
                fd = wsi->desc.sockfd;
 
-       wsi->w_read.event.watcher = event_new(pt->event.io_loop, fd,
-                                             (EV_READ | EV_PERSIST),
-                                             lws_event_cb, &wsi->w_read);
-       wsi->w_write.event.watcher = event_new(pt->event.io_loop, fd,
-                                              (EV_WRITE | EV_PERSIST),
-                                              lws_event_cb, &wsi->w_write);
+       w->w_read.watcher = event_new(ptpr->io_loop, fd, (EV_READ | EV_PERSIST),
+                                     lws_event_cb, &w->w_read);
+       w->w_write.watcher = event_new(ptpr->io_loop, fd,
+                                      (EV_WRITE | EV_PERSIST),
+                                      lws_event_cb, &w->w_write);
 
        elops_io_event(wsi, LWS_EV_START | LWS_EV_READ);
 
@@ -363,52 +444,45 @@ static int
 elops_destroy_context2_event(struct lws_context *context)
 {
        struct lws_context_per_thread *pt;
+       struct lws_pt_eventlibs_libevent *ptpr;
        int n, m;
 
-       lwsl_debug("%s: in\n", __func__);
-
        for (n = 0; n < context->count_threads; n++) {
                int budget = 1000;
 
                pt = &context->pt[n];
+               ptpr = pt_to_priv_event(pt);
 
                /* only for internal loops... */
 
-               if (pt->event_loop_foreign || !pt->event.io_loop)
+               if (pt->event_loop_foreign || !ptpr->io_loop)
                        continue;
 
-               if (!context->finalize_destroy_after_internal_loops_stopped) {
-                       event_base_loopexit(pt->event.io_loop, NULL);
+               if (!context->evlib_finalize_destroy_after_int_loops_stop) {
+                       event_base_loopexit(ptpr->io_loop, NULL);
                        continue;
                }
                while (budget-- &&
-                      (m = event_base_loop(pt->event.io_loop, EVLOOP_NONBLOCK)))
+                      (m = event_base_loop(ptpr->io_loop, EVLOOP_NONBLOCK)))
                        ;
-#if 0
-               if (m) {
-                       lwsl_err("%s: tsi %d: NOT everything closed\n",
-                                __func__, n);
-                       event_base_dump_events(pt->event.io_loop, stderr);
-               } else
-                       lwsl_debug("%s: %d: everything closed OK\n", __func__, n);
-#endif
-               event_base_free(pt->event.io_loop);
 
-       }
+               lwsl_cx_info(context, "event_base_free");
 
-       lwsl_debug("%s: out\n", __func__);
+               event_base_free(ptpr->io_loop);
+               ptpr->io_loop = NULL;
+       }
 
        return 0;
 }
 
-struct lws_event_loop_ops event_loop_ops_event = {
+static const struct lws_event_loop_ops event_loop_ops_event = {
        /* name */                      "libevent",
        /* init_context */              elops_init_context_event,
        /* destroy_context1 */          NULL,
        /* destroy_context2 */          elops_destroy_context2_event,
        /* init_vhost_listen_wsi */     elops_init_vhost_listen_wsi_event,
        /* init_pt */                   elops_init_pt_event,
-       /* wsi_logical_close */         NULL,
+       /* wsi_logical_close */         elops_wsi_logical_close_event,
        /* check_client_connect_ok */   NULL,
        /* close_handle_manually */     NULL,
        /* accept */                    elops_accept_event,
@@ -416,6 +490,26 @@ struct lws_event_loop_ops event_loop_ops_event = {
        /* run_pt */                    elops_run_pt_event,
        /* destroy_pt */                elops_destroy_pt_event,
        /* destroy wsi */               elops_destroy_wsi_event,
+       /* foreign_thread */            NULL,
+
+       /* flags */                     0,
 
-       /* periodic_events_available */ 0,
+       /* evlib_size_ctx */    0,
+       /* evlib_size_pt */     sizeof(struct lws_pt_eventlibs_libevent),
+       /* evlib_size_vh */     0,
+       /* evlib_size_wsi */    sizeof(struct lws_wsi_eventlibs_libevent),
+};
+
+#if defined(LWS_WITH_EVLIB_PLUGINS)
+LWS_VISIBLE
+#endif
+const lws_plugin_evlib_t evlib_event = {
+       .hdr = {
+               "libevent event loop",
+               "lws_evlib_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .ops    = &event_loop_ops_event
 };
diff --git a/lib/event-libs/libevent/private-lib-event-libs-libevent.h b/lib/event-libs/libevent/private-lib-event-libs-libevent.h
new file mode 100644 (file)
index 0000000..aa9b4b0
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <event2/event.h>
+
+struct lws_signal_watcher_libevent {
+       struct event *watcher;
+       struct lws_context *context;
+};
+
+struct lws_pt_eventlibs_libevent {
+       struct event_base *io_loop;
+       struct event *hrtimer;
+       struct event *idle_timer;
+       struct lws_signal_watcher_libevent w_sigint;
+};
+
+struct lws_io_watcher_libevent {
+       struct event *watcher;
+       struct lws_context *context;
+       uint8_t actual_events;
+       char            set;
+};
+
+struct lws_wsi_eventlibs_libevent {
+       struct lws_io_watcher_libevent w_read;
+       struct lws_io_watcher_libevent w_write;
+};
diff --git a/lib/event-libs/libevent/private.h b/lib/event-libs/libevent/private.h
deleted file mode 100644 (file)
index 04fbbdf..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h if LWS_WITH_LIBEVENT
- */
-
-#include <event2/event.h>
-
-struct lws_pt_eventlibs_libevent {
-       struct event_base *io_loop;
-       struct event *hrtimer;
-       struct event *idle_timer;
-};
-
-struct lws_io_watcher_libevent {
-       struct event *watcher;
-};
-
-struct lws_signal_watcher_libevent {
-       struct event *watcher;
-};
-
-struct lws_context_eventlibs_libevent {
-       int placeholder;
-};
-
-extern struct lws_event_loop_ops event_loop_ops_event;
diff --git a/lib/event-libs/libuv/CMakeLists.txt b/lib/event-libs/libuv/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fb810a8
--- /dev/null
@@ -0,0 +1,85 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+set(LWS_LIBUV_LIBRARIES CACHE PATH "Path to the libuv library")
+set(LWS_LIBUV_INCLUDE_DIRS CACHE PATH "Path to the libuv include directory")
+
+if ("${LWS_LIBUV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBUV_INCLUDE_DIRS}" STREQUAL "")
+       if (NOT LIBUV_FOUND)
+               find_path(LIBUV_INCLUDE_DIRS NAMES uv.h)
+               find_library(LIBUV_LIBRARIES NAMES uv)
+       endif()
+else()
+       set(LIBUV_LIBRARIES ${LWS_LIBUV_LIBRARIES})
+       set(LIBUV_INCLUDE_DIRS ${LWS_LIBUV_INCLUDE_DIRS})
+endif()
+
+message("libuv include dir: ${LIBUV_INCLUDE_DIRS}")
+message("libuv libraries: ${LIBUV_LIBRARIES}")
+
+include_directories("${LIBUV_INCLUDE_DIRS}")
+
+CHECK_INCLUDE_FILE(uv-version.h LWS_HAVE_UV_VERSION_H)
+  # libuv changed the location in 1.21.0. Retain both
+  # checks temporarily to ensure a smooth transition.
+  if (NOT LWS_HAVE_UV_VERSION_H)
+    CHECK_INCLUDE_FILE(uv/version.h LWS_HAVE_NEW_UV_VERSION_H)
+  endif()
+  
+  if (LWS_WITH_EVLIB_PLUGINS AND LWS_WITH_LIBUV)
+
+       create_evlib_plugin(evlib_uv
+                           libuv.c
+                           private-lib-event-libs-libuv.h
+                           ${LIBUV_LIBRARIES})
+   endif()
+
+   # wanting libuv in the library is a separate question than
+   # wanting libuv as a selectable event loop plugin
+   # we only came here because LWS_WITH_LIBUV or LWS_WITH_LIBUV_INTERNAL
+
+  if ((NOT LWS_WITH_EVLIB_PLUGINS) OR LWS_WITH_LIBUV_INTERNAL)
+       list(APPEND LIB_LIST ${LIBUV_LIBRARIES})
+
+       if (LWS_WITH_NETWORK)
+               list(APPEND SOURCES
+                       event-libs/libuv/libuv.c)
+       endif()
+  endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+set(LWS_HAVE_UV_VERSION_H ${LWS_HAVE_UV_VERSION_H} PARENT_SCOPE)
+set(LWS_HAVE_NEW_UV_VERSION_H ${LWS_HAVE_NEW_UV_VERSION_H} PARENT_SCOPE)
index 183d146..dad371a 100644 (file)
@@ -1,25 +1,32 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
+#include "private-lib-event-libs-libuv.h"
+
+#define pt_to_priv_uv(_pt) ((struct lws_pt_eventlibs_libuv *)(_pt)->evlib_pt)
+#define wsi_to_priv_uv(_w) ((struct lws_wsi_eventlibs_libuv *)(_w)->evlib_wsi)
 
 static void
 lws_uv_sultimer_cb(uv_timer_t *timer
@@ -28,16 +35,20 @@ lws_uv_sultimer_cb(uv_timer_t *timer
 #endif
 )
 {
-       struct lws_context_per_thread *pt = lws_container_of(timer,
-                               struct lws_context_per_thread, uv.sultimer);
+       struct lws_pt_eventlibs_libuv *ptpr = lws_container_of(timer,
+                               struct lws_pt_eventlibs_libuv, sultimer);
+       struct lws_context_per_thread *pt = ptpr->pt;
        lws_usec_t us;
 
+       lws_context_lock(pt->context, __func__);
        lws_pt_lock(pt, __func__);
-       us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
        if (us)
-               uv_timer_start(&pt->uv.sultimer, lws_uv_sultimer_cb,
-                              LWS_US_TO_MS(us), 0);
+               uv_timer_start(&pt_to_priv_uv(pt)->sultimer, lws_uv_sultimer_cb,
+                              LWS_US_TO_MS((uint64_t)us), 0);
        lws_pt_unlock(pt);
+       lws_context_unlock(pt->context);
 }
 
 static void
@@ -46,13 +57,16 @@ lws_uv_idle(uv_idle_t *handle
                , int status
 #endif
 )
-{
-       struct lws_context_per_thread *pt = lws_container_of(handle,
-                                       struct lws_context_per_thread, uv.idle);
+{      struct lws_pt_eventlibs_libuv *ptpr = lws_container_of(handle,
+               struct lws_pt_eventlibs_libuv, idle);
+       struct lws_context_per_thread *pt = ptpr->pt;
        lws_usec_t us;
 
        lws_service_do_ripe_rxflow(pt);
 
+       lws_context_lock(pt->context, __func__);
+       lws_pt_lock(pt, __func__);
+
        /*
         * is there anybody with pending stuff that needs service forcing?
         */
@@ -62,25 +76,40 @@ lws_uv_idle(uv_idle_t *handle
 
        /* account for sultimer */
 
-       lws_pt_lock(pt, __func__);
-       us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
        if (us)
-               uv_timer_start(&pt->uv.sultimer, lws_uv_sultimer_cb,
-                              LWS_US_TO_MS(us), 0);
-       lws_pt_unlock(pt);
+               uv_timer_start(&pt_to_priv_uv(pt)->sultimer, lws_uv_sultimer_cb,
+                              LWS_US_TO_MS((uint64_t)us), 0);
 
        /* there is nobody who needs service forcing, shut down idle */
        uv_idle_stop(handle);
+
+       lws_pt_unlock(pt);
+       lws_context_unlock(pt->context);
 }
 
 static void
 lws_io_cb(uv_poll_t *watcher, int status, int revents)
 {
        struct lws *wsi = (struct lws *)((uv_handle_t *)watcher)->data;
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+       struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
        struct lws_pollfd eventfd;
 
+       lws_context_lock(pt->context, __func__);
+       lws_pt_lock(pt, __func__);
+
+       if (pt->is_destroyed)
+               goto bail;
+
+       if (!ptpriv->thread_valid) {
+               /* record the thread id that gave us our first event */
+               ptpriv->uv_thread = uv_thread_self();
+               ptpriv->thread_valid = 1;
+       }
+
 #if defined(WIN32) || defined(_WIN32)
        eventfd.fd = watcher->socket;
 #else
@@ -97,7 +126,7 @@ lws_io_cb(uv_poll_t *watcher, int status, int revents)
                 * You might want to return; instead of servicing the fd in
                 * some cases */
                if (status == UV_EAGAIN)
-                       return;
+                       goto bail;
 
                eventfd.events |= LWS_POLLHUP;
                eventfd.revents |= LWS_POLLHUP;
@@ -111,9 +140,23 @@ lws_io_cb(uv_poll_t *watcher, int status, int revents)
                        eventfd.revents |= LWS_POLLOUT;
                }
        }
+
+       lws_pt_unlock(pt);
+       lws_context_unlock(pt->context);
+
        lws_service_fd_tsi(context, &eventfd, wsi->tsi);
 
-       uv_idle_start(&pt->uv.idle, lws_uv_idle);
+       if (pt->destroy_self) {
+               lws_context_destroy(pt->context);
+               return;
+       }
+
+       uv_idle_start(&ptpriv->idle, lws_uv_idle);
+       return;
+
+bail:
+       lws_pt_unlock(pt);
+       lws_context_unlock(pt->context);
 }
 
 /*
@@ -125,66 +168,85 @@ lws_io_cb(uv_poll_t *watcher, int status, int revents)
 static void
 lws_libuv_stop(struct lws_context *context)
 {
-       struct lws_context_per_thread *pt;
-       int n, m;
+       if (context->requested_stop_internal_loops) {
+               lwsl_cx_err(context, "ignoring");
+               return;
+       }
+
+       context->requested_stop_internal_loops = 1;
+       lws_context_destroy(context);
+}
 
-       lwsl_err("%s\n", __func__);
+static void
+lws_uv_signal_handler(uv_signal_t *watcher, int signum)
+{
+       struct lws_context_per_thread *pt = (struct lws_context_per_thread *)
+                                                       watcher->data;
+
+       if (pt->context->eventlib_signal_cb) {
+               pt->context->eventlib_signal_cb((void *)watcher, signum);
 
-       if (context->requested_kill) {
-               lwsl_err("%s: ignoring\n", __func__);
                return;
        }
 
-       context->requested_kill = 1;
-
-       m = context->count_threads;
-       context->being_destroyed = 1;
+       lwsl_cx_err(pt->context, "internal signal handler caught signal %d",
+                                signum);
+       lws_libuv_stop(pt->context);
+}
 
-       /*
-        * Phase 1: start the close of every dynamic uv handle
-        */
+static int
+lws_uv_finalize_pt(struct lws_context_per_thread *pt)
+{
+       pt->event_loop_pt_unused = 1;
 
-       while (m--) {
-               pt = &context->pt[m];
+       lwsl_cx_info(pt->context, "thr %d", (int)(pt - pt->context->pt));
 
-               if (pt->pipe_wsi) {
-                       uv_poll_stop(pt->pipe_wsi->w_read.uv.pwatcher);
-                       lws_destroy_event_pipe(pt->pipe_wsi);
-                       pt->pipe_wsi = NULL;
-               }
+       lws_context_lock(pt->context, __func__);
 
-               for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
-                       struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
+       if (!--pt->context->undestroyed_threads) {
+               struct lws_vhost *vh = pt->context->vhost_list;
 
-                       if (!wsi)
-                               continue;
-                       lws_close_free_wsi(wsi,
-                               LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
-                               __func__ /* no protocol close */);
-                       n--;
-               }
-       }
+               /*
+                * eventually, we emptied all the pts...
+                */
 
-       lwsl_info("%s: started closing all wsi\n", __func__);
+               lwsl_cx_debug(pt->context, "all pts down now");
 
-       /* we cannot have completed... there are at least the cancel pipes */
-}
+               /* protocols may have initialized libuv objects */
 
-static void
-lws_uv_signal_handler(uv_signal_t *watcher, int signum)
-{
-       struct lws_context *context = watcher->data;
+               while (vh) {
+                       lws_vhost_destroy1(vh);
+                       vh = vh->vhost_next;
+               }
 
-       if (context->eventlib_signal_cb) {
-               context->eventlib_signal_cb((void *)watcher, signum);
+               if (!pt->count_event_loop_static_asset_handles &&
+                   pt->event_loop_foreign) {
+                       lwsl_cx_info(pt->context, "resuming context_destroy");
+                       lws_context_unlock(pt->context);
+                       lws_context_destroy(pt->context);
+                       /*
+                        * For foreign, we're being called from the foreign
+                        * thread context the loop is associated with, we must
+                        * return to it cleanly even though we are done with it.
+                        */
+                       return 1;
+               }
+       } else
+               lwsl_cx_debug(pt->context, "still %d undestroyed",
+                                          pt->context->undestroyed_threads);
 
-               return;
-       }
+       lws_context_unlock(pt->context);
 
-       lwsl_err("internal signal handler caught signal %d\n", signum);
-       lws_libuv_stop(watcher->data);
+       return 0;
 }
 
+// static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
+// {
+//      if (!uv_is_closing(handle))
+//           lwsl_err("%s: handle %p still alive on loop\n", __func__, handle);
+// }
+
+
 static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE, SIGHUP };
 
 /*
@@ -194,40 +256,48 @@ static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE, SIGHUP };
 static void
 lws_uv_close_cb_sa(uv_handle_t *handle)
 {
-       struct lws_context *context =
-                       LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(handle);
-       int n;
+       struct lws_context_per_thread *pt =
+                       LWS_UV_REFCOUNT_STATIC_HANDLE_TO_PT(handle);
+       struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
+       struct lws_context *context = pt->context;
+#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
+       int tsi = (int)(pt - &context->pt[0]);
+#endif
 
-       lwsl_info("%s: sa left %d: dyn left: %d\n", __func__,
-                   context->count_event_loop_static_asset_handles,
-                   context->count_wsi_allocated);
+       lwsl_cx_info(context, "thr %d: sa left %d: dyn left: %d (rk %d)",
+                             tsi,
+                             pt->count_event_loop_static_asset_handles - 1,
+                             ptpriv->extant_handles,
+                             context->requested_stop_internal_loops);
 
        /* any static assets left? */
 
        if (LWS_UV_REFCOUNT_STATIC_HANDLE_DESTROYED(handle) ||
-           context->count_wsi_allocated)
+           ptpriv->extant_handles)
                return;
 
        /*
+        * So we believe nothing of ours left on the loop.  Let's sanity
+        * check it to count what's still on the loop
+        */
+
+       // uv_walk(pt_to_priv_uv(pt)->io_loop, lws_uv_walk_cb, NULL);
+
+       /*
         * That's it... all wsi were down, and now every
         * static asset lws had a UV handle for is down.
         *
         * Stop the loop so we can get out of here.
         */
 
-       for (n = 0; n < context->count_threads; n++) {
-               struct lws_context_per_thread *pt = &context->pt[n];
+       lwsl_cx_info(context, "thr %d: seen final static handle gone", tsi);
 
-               if (pt->uv.io_loop && !pt->event_loop_foreign)
-                       uv_stop(pt->uv.io_loop);
-       }
+       if (!pt->event_loop_foreign)
+               lws_context_destroy(context);
 
-       if (!context->pt[0].event_loop_foreign) {
-               lwsl_info("%s: calling lws_context_destroy2\n", __func__);
-               lws_context_destroy2(context);
-       }
+       lws_uv_finalize_pt(pt);
 
-       lwsl_info("%s: all done\n", __func__);
+       lwsl_cx_info(context, "all done");
 }
 
 /*
@@ -236,54 +306,37 @@ lws_uv_close_cb_sa(uv_handle_t *handle)
  * .... when the libuv object is created...
  */
 
-LWS_VISIBLE void
-lws_libuv_static_refcount_add(uv_handle_t *h, struct lws_context *context)
+void
+lws_libuv_static_refcount_add(uv_handle_t *h, struct lws_context *context,
+                               int tsi)
 {
-       LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(h, context);
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+
+       LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(h, pt);
 }
 
 /*
  * ... and in the close callback when the object is closed.
  */
 
-LWS_VISIBLE void
+void
 lws_libuv_static_refcount_del(uv_handle_t *h)
 {
        lws_uv_close_cb_sa(h);
 }
 
-
-static void lws_uv_close_cb(uv_handle_t *handle)
-{
-}
-
-static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
-{
-       if (!uv_is_closing(handle))
-               uv_close(handle, lws_uv_close_cb);
-}
-
-LWS_VISIBLE void
-lws_close_all_handles_in_loop(uv_loop_t *loop)
-{
-       uv_walk(loop, lws_uv_walk_cb, NULL);
-}
-
-
-LWS_VISIBLE void
+void
 lws_libuv_stop_without_kill(const struct lws_context *context, int tsi)
 {
-       if (context->pt[tsi].uv.io_loop)
-               uv_stop(context->pt[tsi].uv.io_loop);
+       if (pt_to_priv_uv(&context->pt[tsi])->io_loop)
+               uv_stop(pt_to_priv_uv(&context->pt[tsi])->io_loop);
 }
 
-
-
-LWS_VISIBLE uv_loop_t *
+uv_loop_t *
 lws_uv_getloop(struct lws_context *context, int tsi)
 {
-       if (context->pt[tsi].uv.io_loop)
-               return context->pt[tsi].uv.io_loop;
+       if (pt_to_priv_uv(&context->pt[tsi])->io_loop)
+               return pt_to_priv_uv(&context->pt[tsi])->io_loop;
 
        return NULL;
 }
@@ -291,7 +344,7 @@ lws_uv_getloop(struct lws_context *context, int tsi)
 int
 lws_libuv_check_watcher_active(struct lws *wsi)
 {
-       uv_handle_t *h = (uv_handle_t *)wsi->w_read.uv.pwatcher;
+       uv_handle_t *h = (uv_handle_t *)wsi_to_priv_uv(wsi)->w_read.pwatcher;
 
        if (!h)
                return 0;
@@ -299,169 +352,6 @@ lws_libuv_check_watcher_active(struct lws *wsi)
        return uv_is_active(h);
 }
 
-
-#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
-
-int
-lws_uv_plugins_init(struct lws_context *context, const char * const *d)
-{
-       struct lws_plugin_capability lcaps;
-       struct lws_plugin *plugin;
-       lws_plugin_init_func initfunc;
-       int m, ret = 0;
-       void *v;
-       uv_dirent_t dent;
-       uv_fs_t req;
-       char path[256];
-       uv_lib_t lib;
-       int pofs = 0;
-
-#if  defined(__MINGW32__) || !defined(WIN32)
-       pofs = 3;
-#endif
-
-       lib.errmsg = NULL;
-       lib.handle = NULL;
-
-       uv_loop_init(&context->uv.loop);
-
-       lwsl_notice("  Plugins:\n");
-
-       while (d && *d) {
-
-               lwsl_notice("  Scanning %s\n", *d);
-               m =uv_fs_scandir(&context->uv.loop, &req, *d, 0, NULL);
-               if (m < 1) {
-                       lwsl_err("Scandir on %s failed\n", *d);
-                       return 1;
-               }
-
-               while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
-                       if (strlen(dent.name) < 7)
-                               continue;
-
-                       lwsl_notice("   %s\n", dent.name);
-
-                       lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d,
-                                    dent.name);
-                       if (uv_dlopen(path, &lib)) {
-                               uv_dlerror(&lib);
-                               lwsl_err("Error loading DSO: %s\n", lib.errmsg);
-                               uv_dlclose(&lib);
-                               goto bail;
-                       }
-
-                       /* we could open it, can we get his init function? */
-
-#if !defined(WIN32) && !defined(__MINGW32__)
-                       m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
-                                    dent.name + pofs /* snip lib... */);
-                       path[m - 3] = '\0'; /* snip the .so */
-#else
-                       m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
-                                    dent.name + pofs);
-                       path[m - 4] = '\0'; /* snip the .dll */
-#endif
-                       if (uv_dlsym(&lib, path, &v)) {
-                               uv_dlerror(&lib);
-                               lwsl_err("Failed to get %s on %s: %s", path,
-                                               dent.name, lib.errmsg);
-                               uv_dlclose(&lib);
-                               goto bail;
-                       }
-                       initfunc = (lws_plugin_init_func)v;
-                       lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
-                       m = initfunc(context, &lcaps);
-                       if (m) {
-                               lwsl_err("Init %s failed %d\n", dent.name, m);
-                               goto skip;
-                       }
-
-                       plugin = lws_malloc(sizeof(*plugin), "plugin");
-                       if (!plugin) {
-                               uv_dlclose(&lib);
-                               lwsl_err("OOM\n");
-                               goto bail;
-                       }
-                       plugin->list = context->plugin_list;
-                       context->plugin_list = plugin;
-                       lws_strncpy(plugin->name, dent.name, sizeof(plugin->name));
-                       plugin->lib = lib;
-                       plugin->caps = lcaps;
-                       context->plugin_protocol_count += lcaps.count_protocols;
-                       context->plugin_extension_count += lcaps.count_extensions;
-
-                       continue;
-
-skip:
-                       uv_dlclose(&lib);
-               }
-bail:
-               uv_fs_req_cleanup(&req);
-               d++;
-       }
-
-       return ret;
-}
-
-int
-lws_uv_plugins_destroy(struct lws_context *context)
-{
-       struct lws_plugin *plugin = context->plugin_list, *p;
-       lws_plugin_destroy_func func;
-       char path[256];
-       int pofs = 0;
-       void *v;
-       int m;
-
-#if  defined(__MINGW32__) || !defined(WIN32)
-       pofs = 3;
-#endif
-
-       if (!plugin)
-               return 0;
-
-       while (plugin) {
-               p = plugin;
-
-#if !defined(WIN32) && !defined(__MINGW32__)
-               m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s",
-                                plugin->name + pofs);
-               path[m - 3] = '\0';
-#else
-               m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s",
-                                plugin->name + pofs);
-               path[m - 4] = '\0';
-#endif
-
-               if (uv_dlsym(&plugin->lib, path, &v)) {
-                       uv_dlerror(&plugin->lib);
-                       lwsl_err("Failed to get %s on %s: %s", path,
-                                       plugin->name, plugin->lib.errmsg);
-               } else {
-                       func = (lws_plugin_destroy_func)v;
-                       m = func(context);
-                       if (m)
-                               lwsl_err("Destroying %s failed %d\n",
-                                               plugin->name, m);
-               }
-
-               uv_dlclose(&p->lib);
-               plugin = p->list;
-               p->list = NULL;
-               free(p);
-       }
-
-       context->plugin_list = NULL;
-
-       while (uv_loop_close(&context->uv.loop))
-               ;
-
-       return 0;
-}
-
-#endif
-
 static int
 elops_init_context_uv(struct lws_context *context,
                      const struct lws_context_creation_info *info)
@@ -471,7 +361,7 @@ elops_init_context_uv(struct lws_context *context,
        context->eventlib_signal_cb = info->signal_cb;
 
        for (n = 0; n < context->count_threads; n++)
-               context->pt[n].w_sigint.context = context;
+               pt_to_priv_uv(&context->pt[n])->w_sigint.context = context;
 
        return 0;
 }
@@ -490,12 +380,11 @@ elops_destroy_context1_uv(struct lws_context *context)
 
                if (!pt->event_loop_foreign) {
 
-                       while (budget-- && (m = uv_run(pt->uv.io_loop,
+                       while (budget-- && (m = uv_run(pt_to_priv_uv(pt)->io_loop,
                                                  UV_RUN_NOWAIT)))
                                        ;
                        if (m)
-                               lwsl_err("%s: tsi %d: not all closed\n",
-                                        __func__, n);
+                               lwsl_cx_info(context, "tsi %d: unclosed", n);
 
                }
        }
@@ -515,15 +404,15 @@ elops_destroy_context2_uv(struct lws_context *context)
 
                /* only for internal loops... */
 
-               if (!pt->event_loop_foreign && pt->uv.io_loop) {
+               if (!pt->event_loop_foreign && pt_to_priv_uv(pt)->io_loop) {
                        internal = 1;
-                       if (!context->finalize_destroy_after_internal_loops_stopped)
-                               uv_stop(pt->uv.io_loop);
+                       if (!context->evlib_finalize_destroy_after_int_loops_stop)
+                               uv_stop(pt_to_priv_uv(pt)->io_loop);
                        else {
 #if UV_VERSION_MAJOR > 0
-                               uv_loop_close(pt->uv.io_loop);
+                               uv_loop_close(pt_to_priv_uv(pt)->io_loop);
 #endif
-                               lws_free_set_NULL(pt->uv.io_loop);
+                               lws_free_set_NULL(pt_to_priv_uv(pt)->io_loop);
                        }
                }
        }
@@ -534,16 +423,19 @@ elops_destroy_context2_uv(struct lws_context *context)
 static int
 elops_wsi_logical_close_uv(struct lws *wsi)
 {
-       if (!lws_socket_is_valid(wsi->desc.sockfd))
+       if (!lws_socket_is_valid(wsi->desc.sockfd) &&
+           wsi->role_ops && strcmp(wsi->role_ops->name, "raw-file") &&
+           !wsi_to_priv_uv(wsi)->w_read.pwatcher)
                return 0;
 
        if (wsi->listener || wsi->event_pipe) {
-               lwsl_debug("%s: %p: %d %d stop listener / pipe poll\n",
-                          __func__, wsi, wsi->listener, wsi->event_pipe);
-               if (wsi->w_read.uv.pwatcher)
-                       uv_poll_stop(wsi->w_read.uv.pwatcher);
+               lwsl_wsi_debug(wsi, "%d %d stop listener / pipe poll",
+                                   wsi->listener,
+                                   wsi->event_pipe);
+               if (wsi_to_priv_uv(wsi)->w_read.pwatcher)
+                       uv_poll_stop(wsi_to_priv_uv(wsi)->w_read.pwatcher);
        }
-       lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
+       lwsl_wsi_debug(wsi, "lws_libuv_closehandle");
        /*
         * libuv has to do his own close handle processing asynchronously
         */
@@ -556,7 +448,7 @@ static int
 elops_check_client_connect_ok_uv(struct lws *wsi)
 {
        if (lws_libuv_check_watcher_active(wsi)) {
-               lwsl_warn("Waiting for libuv watcher to close\n");
+               lwsl_wsi_warn(wsi, "Waiting for libuv watcher to close");
                return 1;
        }
 
@@ -567,6 +459,7 @@ static void
 lws_libuv_closewsi_m(uv_handle_t* handle)
 {
        lws_sockfd_type sockfd = (lws_sockfd_type)(lws_intptr_t)handle->data;
+
        lwsl_debug("%s: sockfd %d\n", __func__, sockfd);
        compatible_close(sockfd);
        lws_free(handle);
@@ -575,9 +468,9 @@ lws_libuv_closewsi_m(uv_handle_t* handle)
 static void
 elops_close_handle_manually_uv(struct lws *wsi)
 {
-       uv_handle_t *h = (uv_handle_t *)wsi->w_read.uv.pwatcher;
+       uv_handle_t *h = (uv_handle_t *)wsi_to_priv_uv(wsi)->w_read.pwatcher;
 
-       lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
+       lwsl_wsi_debug(wsi, "lws_libuv_closehandle");
 
        /*
         * the "manual" variant only closes the handle itself and the
@@ -591,7 +484,7 @@ elops_close_handle_manually_uv(struct lws *wsi)
         */
 
        wsi->desc.sockfd = LWS_SOCK_INVALID;
-       wsi->w_read.uv.pwatcher = NULL;
+       wsi_to_priv_uv(wsi)->w_read.pwatcher = NULL;
        wsi->told_event_loop_closed = 1;
 
        uv_close(h, lws_libuv_closewsi_m);
@@ -600,52 +493,74 @@ elops_close_handle_manually_uv(struct lws *wsi)
 static int
 elops_accept_uv(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
+       struct lws_io_watcher_libuv *w_read = &wsi_to_priv_uv(wsi)->w_read;
+       int n;
+
+       if (!ptpriv->thread_valid) {
+               /* record the thread id that gave us our first event */
+               ptpriv->uv_thread = uv_thread_self();
+               ptpriv->thread_valid = 1;
+       }
 
-       wsi->w_read.context = wsi->context;
+       w_read->context = wsi->a.context;
 
-       wsi->w_read.uv.pwatcher =
-               lws_malloc(sizeof(*wsi->w_read.uv.pwatcher), "uvh");
-       if (!wsi->w_read.uv.pwatcher)
+       w_read->pwatcher = lws_malloc(sizeof(*w_read->pwatcher), "uvh");
+       if (!w_read->pwatcher)
                return -1;
 
        if (wsi->role_ops->file_handle)
-               uv_poll_init(pt->uv.io_loop, wsi->w_read.uv.pwatcher,
-                            (int)(long long)wsi->desc.filefd);
+               n = uv_poll_init(pt_to_priv_uv(pt)->io_loop, w_read->pwatcher,
+                            (int)(lws_intptr_t)wsi->desc.filefd);
        else
-               uv_poll_init_socket(pt->uv.io_loop,
-                                   wsi->w_read.uv.pwatcher,
-                                   wsi->desc.sockfd);
+               n = uv_poll_init_socket(pt_to_priv_uv(pt)->io_loop,
+                                   w_read->pwatcher, wsi->desc.sockfd);
+
+       if (n) {
+               lwsl_wsi_err(wsi, "uv_poll_init failed %d, sockfd=%p", n,
+                                 (void *)(lws_intptr_t)wsi->desc.sockfd);
+               lws_free(w_read->pwatcher);
+               w_read->pwatcher = NULL;
+               return -1;
+       }
+
+       ((uv_handle_t *)w_read->pwatcher)->data = (void *)wsi;
+
+       ptpriv->extant_handles++;
 
-       ((uv_handle_t *)wsi->w_read.uv.pwatcher)->data = (void *)wsi;
+       lwsl_wsi_debug(wsi, "thr %d: sa left %d: dyn left: %d",
+                           (int)(pt - &pt->context->pt[0]),
+                           pt->count_event_loop_static_asset_handles,
+                           ptpriv->extant_handles);
 
        return 0;
 }
 
 static void
-elops_io_uv(struct lws *wsi, int flags)
+elops_io_uv(struct lws *wsi, unsigned int flags)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-       struct lws_io_watcher *w = &wsi->w_read;
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_io_watcher_libuv *w = &(wsi_to_priv_uv(wsi)->w_read);
        int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE);
 
-       lwsl_debug("%s: %p: %d\n", __func__, wsi, flags);
+       lwsl_wsi_debug(wsi, "%d", flags);
 
        /* w->context is set after the loop is initialized */
 
-       if (!pt->uv.io_loop || !w->context) {
-               lwsl_info("%s: no io loop yet\n", __func__);
+       if (!pt_to_priv_uv(pt)->io_loop || !w->context) {
+               lwsl_wsi_info(wsi, "no io loop yet");
                return;
        }
 
        if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
              (flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
-               lwsl_err("%s: assert: flags %d", __func__, flags);
+               lwsl_wsi_err(wsi, "assert: flags %d", flags);
                assert(0);
        }
 
-       if (!w->uv.pwatcher || wsi->told_event_loop_closed) {
-               lwsl_err("%s: no watcher\n", __func__);
+       if (!w->pwatcher || wsi->told_event_loop_closed) {
+               lwsl_wsi_info(wsi, "no watcher");
 
                return;
        }
@@ -657,7 +572,7 @@ elops_io_uv(struct lws *wsi, int flags)
                if (flags & LWS_EV_READ)
                        current_events |= UV_READABLE;
 
-               uv_poll_start(w->uv.pwatcher, current_events, lws_io_cb);
+               uv_poll_start(w->pwatcher, current_events, lws_io_cb);
        } else {
                if (flags & LWS_EV_WRITE)
                        current_events &= ~UV_WRITABLE;
@@ -666,47 +581,58 @@ elops_io_uv(struct lws *wsi, int flags)
                        current_events &= ~UV_READABLE;
 
                if (!(current_events & (UV_READABLE | UV_WRITABLE)))
-                       uv_poll_stop(w->uv.pwatcher);
+                       uv_poll_stop(w->pwatcher);
                else
-                       uv_poll_start(w->uv.pwatcher, current_events,
-                                     lws_io_cb);
+                       uv_poll_start(w->pwatcher, current_events, lws_io_cb);
        }
 
-       w->actual_events = current_events;
+       w->actual_events = (uint8_t)current_events;
 }
 
 static int
 elops_init_vhost_listen_wsi_uv(struct lws *wsi)
 {
        struct lws_context_per_thread *pt;
+       struct lws_pt_eventlibs_libuv *ptpriv;
+       struct lws_io_watcher_libuv *w_read;
        int n;
 
        if (!wsi)
                return 0;
-       if (wsi->w_read.context)
+
+       w_read = &wsi_to_priv_uv(wsi)->w_read;
+
+       if (w_read->context)
                return 0;
 
-       pt = &wsi->context->pt[(int)wsi->tsi];
-       if (!pt->uv.io_loop)
+       pt = &wsi->a.context->pt[(int)wsi->tsi];
+       ptpriv = pt_to_priv_uv(pt);
+       if (!ptpriv->io_loop)
                return 0;
 
-       wsi->w_read.context = wsi->context;
+       w_read->context = wsi->a.context;
 
-       wsi->w_read.uv.pwatcher =
-               lws_malloc(sizeof(*wsi->w_read.uv.pwatcher), "uvh");
-       if (!wsi->w_read.uv.pwatcher)
+       w_read->pwatcher = lws_malloc(sizeof(*w_read->pwatcher), "uvh");
+       if (!w_read->pwatcher)
                return -1;
 
-       n = uv_poll_init_socket(pt->uv.io_loop, wsi->w_read.uv.pwatcher,
-                                  wsi->desc.sockfd);
+       n = uv_poll_init_socket(pt_to_priv_uv(pt)->io_loop,
+                               w_read->pwatcher, wsi->desc.sockfd);
        if (n) {
-               lwsl_err("uv_poll_init failed %d, sockfd=%p\n", n,
-                               (void *)(lws_intptr_t)wsi->desc.sockfd);
+               lwsl_wsi_err(wsi, "uv_poll_init failed %d, sockfd=%p", n,
+                                 (void *)(lws_intptr_t)wsi->desc.sockfd);
 
                return -1;
        }
 
-       ((uv_handle_t *)wsi->w_read.uv.pwatcher)->data = (void *)wsi;
+       ptpriv->extant_handles++;
+
+       lwsl_wsi_debug(wsi, "thr %d: sa left %d: dyn left: %d",
+                           (int)(pt - &pt->context->pt[0]),
+                           pt->count_event_loop_static_asset_handles,
+                           ptpriv->extant_handles);
+
+       ((uv_handle_t *)w_read->pwatcher)->data = (void *)wsi;
 
        elops_io_uv(wsi, LWS_EV_START | LWS_EV_READ);
 
@@ -716,31 +642,37 @@ elops_init_vhost_listen_wsi_uv(struct lws *wsi)
 static void
 elops_run_pt_uv(struct lws_context *context, int tsi)
 {
-       if (context->pt[tsi].uv.io_loop)
-               uv_run(context->pt[tsi].uv.io_loop, 0);
+       if (pt_to_priv_uv(&context->pt[tsi])->io_loop)
+               uv_run(pt_to_priv_uv(&context->pt[tsi])->io_loop, 0);
 }
 
 static void
 elops_destroy_pt_uv(struct lws_context *context, int tsi)
 {
        struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
        int m, ns;
 
-       lwsl_info("%s: %d\n", __func__, tsi);
-
        if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
                return;
 
-       if (!pt->uv.io_loop)
+       if (!ptpriv->io_loop)
                return;
 
-       if (pt->event_loop_destroy_processing_done)
+       if (pt->event_loop_destroy_processing_done) {
+               if (!pt->event_loop_foreign) {
+                       lwsl_warn("%s: stopping event loop\n", __func__);
+                       uv_stop(pt_to_priv_uv(pt)->io_loop);
+               }
                return;
+       }
 
        pt->event_loop_destroy_processing_done = 1;
+       // lwsl_cx_debug(context, "%d", tsi);
 
        if (!pt->event_loop_foreign) {
-               uv_signal_stop(&pt->w_sigint.uv.watcher);
+
+               uv_signal_stop(&pt_to_priv_uv(pt)->w_sigint.watcher);
 
                ns = LWS_ARRAY_SIZE(sigs);
                if (lws_check_opt(context->options,
@@ -748,18 +680,29 @@ elops_destroy_pt_uv(struct lws_context *context, int tsi)
                        ns = 2;
 
                for (m = 0; m < ns; m++) {
-                       uv_signal_stop(&pt->uv.signals[m]);
-                       uv_close((uv_handle_t *)&pt->uv.signals[m],
+                       uv_signal_stop(&pt_to_priv_uv(pt)->signals[m]);
+                       uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->signals[m],
                                 lws_uv_close_cb_sa);
                }
        } else
-               lwsl_debug("%s: not closing pt signals\n", __func__);
+               lwsl_cx_debug(context, "not closing pt signals");
 
-       uv_timer_stop(&pt->uv.sultimer);
-       uv_close((uv_handle_t *)&pt->uv.sultimer, lws_uv_close_cb_sa);
+       uv_timer_stop(&pt_to_priv_uv(pt)->sultimer);
+       uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->sultimer, lws_uv_close_cb_sa);
 
-       uv_idle_stop(&pt->uv.idle);
-       uv_close((uv_handle_t *)&pt->uv.idle, lws_uv_close_cb_sa);
+       uv_idle_stop(&pt_to_priv_uv(pt)->idle);
+       uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->idle, lws_uv_close_cb_sa);
+}
+
+static int
+elops_listen_init_uv(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+
+       if (elops_init_vhost_listen_wsi_uv(wsi) == -1)
+               return -1;
+
+       return 0;
 }
 
 /*
@@ -769,37 +712,39 @@ elops_destroy_pt_uv(struct lws_context *context, int tsi)
  * called again to bind the vhost
  */
 
-LWS_VISIBLE int
+int
 elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi)
 {
        struct lws_context_per_thread *pt = &context->pt[tsi];
-       struct lws_vhost *vh = context->vhost_list;
+       struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
        int status = 0, n, ns, first = 1;
        uv_loop_t *loop = (uv_loop_t *)_loop;
 
-       if (!pt->uv.io_loop) {
+       ptpriv->pt = pt;
+
+       if (!ptpriv->io_loop) {
                if (!loop) {
                        loop = lws_malloc(sizeof(*loop), "libuv loop");
                        if (!loop) {
-                               lwsl_err("OOM\n");
+                               lwsl_cx_err(context, "OOM");
                                return -1;
                        }
-       #if UV_VERSION_MAJOR > 0
+#if UV_VERSION_MAJOR > 0
                        uv_loop_init(loop);
-       #else
-                       lwsl_err("This libuv is too old to work...\n");
+#else
+                       lwsl_cx_err(context, "This libuv is too old to work...");
                        return 1;
-       #endif
+#endif
                        pt->event_loop_foreign = 0;
                } else {
-                       lwsl_notice(" Using foreign event loop...\n");
+                       lwsl_cx_notice(context, " Using foreign event loop...");
                        pt->event_loop_foreign = 1;
                }
 
-               pt->uv.io_loop = loop;
-               uv_idle_init(loop, &pt->uv.idle);
-               LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.idle, context);
-
+               ptpriv->io_loop = loop;
+               uv_idle_init(loop, &ptpriv->idle);
+               LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&ptpriv->idle, pt);
+               uv_idle_start(&ptpriv->idle, lws_uv_idle);
 
                ns = LWS_ARRAY_SIZE(sigs);
                if (lws_check_opt(context->options,
@@ -807,13 +752,13 @@ elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi)
                        ns = 2;
 
                if (!pt->event_loop_foreign) {
-                       assert(ns <= (int)LWS_ARRAY_SIZE(pt->uv.signals));
+                       assert(ns <= (int)LWS_ARRAY_SIZE(ptpriv->signals));
                        for (n = 0; n < ns; n++) {
-                               uv_signal_init(loop, &pt->uv.signals[n]);
-                               LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.signals[n],
-                                                                 context);
-                               pt->uv.signals[n].data = pt->context;
-                               uv_signal_start(&pt->uv.signals[n],
+                               uv_signal_init(loop, &ptpriv->signals[n]);
+                               LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(
+                                               &ptpriv->signals[n], pt);
+                               ptpriv->signals[n].data = pt;
+                               uv_signal_start(&ptpriv->signals[n],
                                                lws_uv_signal_handler, sigs[n]);
                        }
                }
@@ -827,17 +772,13 @@ elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi)
         * We have to do it here because the uv loop(s) are not
         * initialized until after context creation.
         */
-       while (vh) {
-               if (elops_init_vhost_listen_wsi_uv(vh->lserv_wsi) == -1)
-                       return -1;
-               vh = vh->vhost_next;
-       }
+       lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_uv);
 
        if (!first)
                return status;
 
-       uv_timer_init(pt->uv.io_loop, &pt->uv.sultimer);
-       LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.sultimer, context);
+       uv_timer_init(ptpriv->io_loop, &ptpriv->sultimer);
+       LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&ptpriv->sultimer, pt);
 
        return status;
 }
@@ -848,18 +789,22 @@ lws_libuv_closewsi(uv_handle_t* handle)
        struct lws *wsi = (struct lws *)handle->data;
        struct lws_context *context = lws_get_context(wsi);
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-#if !defined(LWS_WITHOUT_SERVER)
+       struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
+#if defined(LWS_WITH_SERVER)
        int lspd = 0;
 #endif
 
-       lwsl_info("%s: %p\n", __func__, wsi);
+       // lwsl_wsi_notice(wsi, "in");
+
+       lws_context_lock(context, __func__);
 
        /*
         * We get called back here for every wsi that closes
         */
 
-#if !defined(LWS_WITHOUT_SERVER)
-       if (wsi->role_ops == &role_ops_listen && wsi->context->deprecated) {
+#if defined(LWS_WITH_SERVER)
+       if (wsi->role_ops && !strcmp(wsi->role_ops->name, "listen") &&
+           wsi->a.context->deprecated) {
                lspd = 1;
                context->deprecation_pending_listen_close_count--;
                if (!context->deprecation_pending_listen_close_count)
@@ -868,70 +813,62 @@ lws_libuv_closewsi(uv_handle_t* handle)
 #endif
 
        lws_pt_lock(pt, __func__);
+
+       lwsl_wsi_info(wsi, "thr %d: sa left %d: dyn left: %d (rk %d)",
+                          (int)(pt - &pt->context->pt[0]),
+                          pt->count_event_loop_static_asset_handles,
+                          ptpriv->extant_handles - 1,
+                          context->requested_stop_internal_loops);
+
        __lws_close_free_wsi_final(wsi);
+       assert(ptpriv->extant_handles);
+       ptpriv->extant_handles--;
        lws_pt_unlock(pt);
 
        /* it's our job to close the handle finally */
        lws_free(handle);
 
-#if !defined(LWS_WITHOUT_SERVER)
+#if defined(LWS_WITH_SERVER)
        if (lspd == 2 && context->deprecation_cb) {
-               lwsl_notice("calling deprecation callback\n");
+               lwsl_cx_notice(context, "calling deprecation callback");
                context->deprecation_cb();
        }
 #endif
 
-       lwsl_info("%s: sa left %d: dyn left: %d (rk %d)\n", __func__,
-                   context->count_event_loop_static_asset_handles,
-                   context->count_wsi_allocated, context->requested_kill);
-
        /*
         * eventually, we closed all the wsi...
         */
 
-       if (context->requested_kill && !context->count_wsi_allocated) {
-               struct lws_vhost *vh = context->vhost_list;
-               int m;
+       if (context->requested_stop_internal_loops &&
+           !ptpriv->extant_handles &&
+           !pt->count_event_loop_static_asset_handles) {
 
                /*
-                * Start Closing Phase 2: close of static handles
+                * we closed everything on this pt
                 */
 
-               lwsl_info("%s: all lws dynamic handles down, closing static\n",
-                           __func__);
-
-               for (m = 0; m < context->count_threads; m++)
-                       elops_destroy_pt_uv(context, m);
+               lws_context_unlock(context);
+               lws_uv_finalize_pt(pt);
 
-               /* protocols may have initialized libuv objects */
-
-               while (vh) {
-                       lws_vhost_destroy1(vh);
-                       vh = vh->vhost_next;
-               }
-
-               if (!context->count_event_loop_static_asset_handles &&
-                   context->pt[0].event_loop_foreign) {
-                       lwsl_info("%s: call lws_context_destroy2\n", __func__);
-                       lws_context_destroy2(context);
-               }
+               return;
        }
+
+       lws_context_unlock(context);
 }
 
 void
 lws_libuv_closehandle(struct lws *wsi)
 {
        uv_handle_t* handle;
+       struct lws_io_watcher_libuv *w_read = &wsi_to_priv_uv(wsi)->w_read;
 
-       if (!wsi->w_read.uv.pwatcher)
+       if (!w_read->pwatcher)
                return;
 
-       if (wsi->told_event_loop_closed) {
-       //      assert(0);
+       if (wsi->told_event_loop_closed)
                return;
-       }
 
-       lwsl_debug("%s: %p\n", __func__, wsi);
+//     lwsl_wsi_debug(wsi, "in");
 
        wsi->told_event_loop_closed = 1;
 
@@ -940,16 +877,37 @@ lws_libuv_closehandle(struct lws *wsi)
         * handle->data.
         */
 
-       handle = (uv_handle_t *)wsi->w_read.uv.pwatcher;
+       handle = (uv_handle_t *)w_read->pwatcher;
 
        /* ensure we can only do this once */
 
-       wsi->w_read.uv.pwatcher = NULL;
+       w_read->pwatcher = NULL;
 
        uv_close(handle, lws_libuv_closewsi);
 }
 
-struct lws_event_loop_ops event_loop_ops_uv = {
+static int
+elops_foreign_thread_uv(struct lws_context *cx, int tsi)
+{
+       struct lws_context_per_thread *pt = &cx->pt[tsi];
+       struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
+       uv_thread_t th = uv_thread_self();
+
+       if (!ptpriv->thread_valid)
+               /*
+                * We can't judge it until we get the first event from the loop
+                */
+               return 0;
+
+       /*
+        * This is the same thread that gave us the first event on this loop?
+        * Return 0 if so.
+        */
+
+       return !uv_thread_equal(&th, &ptpriv->uv_thread);
+}
+
+static const struct lws_event_loop_ops event_loop_ops_uv = {
        /* name */                      "libuv",
        /* init_context */              elops_init_context_uv,
        /* destroy_context1 */          elops_destroy_context1_uv,
@@ -964,6 +922,27 @@ struct lws_event_loop_ops event_loop_ops_uv = {
        /* run_pt */                    elops_run_pt_uv,
        /* destroy_pt */                elops_destroy_pt_uv,
        /* destroy wsi */               NULL,
+       /* foreign_thread */            elops_foreign_thread_uv,
+
+       /* flags */                     0,
+
+       /* evlib_size_ctx */    sizeof(struct lws_context_eventlibs_libuv),
+       /* evlib_size_pt */     sizeof(struct lws_pt_eventlibs_libuv),
+       /* evlib_size_vh */     0,
+       /* evlib_size_wsi */    sizeof(struct lws_io_watcher_libuv),
+};
 
-       /* periodic_events_available */ 0,
+#if defined(LWS_WITH_EVLIB_PLUGINS)
+LWS_VISIBLE
+#endif
+const lws_plugin_evlib_t evlib_uv = {
+       .hdr = {
+               "libuv event loop",
+               "lws_evlib_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .ops    = &event_loop_ops_uv
 };
+
diff --git a/lib/event-libs/libuv/private-lib-event-libs-libuv.h b/lib/event-libs/libuv/private-lib-event-libs-libuv.h
new file mode 100644 (file)
index 0000000..4871511
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <uv.h>
+
+/*
+ * libuv's async destroy cb means that asking to close something doesn't mean
+ * you can destroy it or parent things until after the close completes.
+ *
+ * So we must reference-count creation and close completions with libuv.
+ *
+ * All "static" (per-pt or per-context) uv handles must
+ *
+ *  - have their .data set to point to the context
+ *
+ *  - contribute to context->uv_count_static_asset_handles
+ *    counting
+ */
+#define LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(_x, _pt) \
+               { uv_handle_t *_uht = (uv_handle_t *)(_x); _uht->data = _pt; \
+               _pt->count_event_loop_static_asset_handles++; }
+#define LWS_UV_REFCOUNT_STATIC_HANDLE_TO_PT(_x) \
+               ((struct lws_context_per_thread *)((uv_handle_t *)((_x)->data)))
+#define LWS_UV_REFCOUNT_STATIC_HANDLE_DESTROYED(_x) \
+               (--(LWS_UV_REFCOUNT_STATIC_HANDLE_TO_PT(_x)-> \
+                               count_event_loop_static_asset_handles))
+
+struct lws_signal_watcher_libuv {
+       uv_signal_t watcher;
+       struct lws_context *context;
+};
+
+struct lws_pt_eventlibs_libuv {
+       uv_loop_t                       *io_loop;
+       struct lws_context_per_thread   *pt;
+       uv_signal_t                     signals[8];
+       uv_timer_t                      sultimer;
+       uv_idle_t                       idle;
+
+       uv_thread_t                     uv_thread;
+
+       struct lws_signal_watcher_libuv w_sigint;
+       int                             extant_handles;
+
+       char                            thread_valid;
+};
+
+struct lws_context_eventlibs_libuv {
+       uv_loop_t                       loop;
+};
+
+struct lws_io_watcher_libuv {
+       uv_poll_t                       *pwatcher;
+       struct lws_context              *context;
+       uint8_t                         actual_events;
+};
+
+struct lws_wsi_eventlibs_libuv {
+       struct lws_io_watcher_libuv     w_read;
+};
+
+uv_loop_t *
+lws_uv_getloop(struct lws_context *context, int tsi);
+
+int
+lws_uv_plugins_init(struct lws_context *context, const char * const *d);
+
+int
+lws_uv_plugins_destroy(struct lws_context *context);
diff --git a/lib/event-libs/libuv/private.h b/lib/event-libs/libuv/private.h
deleted file mode 100644 (file)
index 815f0f5..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h if LWS_WITH_LIBUV
- */
-
-#include <uv.h>
-
-/*
- * libuv's async destroy cb means that asking to close something doesn't mean
- * you can destroy it or parent things until after the close completes.
- *
- * So we must reference-count creation and close completions with libuv.
- *
- * All "static" (per-pt or per-context) uv handles must
- *
- *  - have their .data set to point to the context
- *
- *  - contribute to context->uv_count_static_asset_handles
- *    counting
- */
-#define LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(_x, _ctx) \
-               { uv_handle_t *_uht = (uv_handle_t *)(_x); _uht->data = _ctx; \
-               _ctx->count_event_loop_static_asset_handles++; }
-#define LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x) \
-               ((struct lws_context *)((uv_handle_t *)((_x)->data)))
-#define LWS_UV_REFCOUNT_STATIC_HANDLE_DESTROYED(_x) \
-               (--(LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x)-> \
-                               count_event_loop_static_asset_handles))
-
-struct lws_pt_eventlibs_libuv {
-       uv_loop_t *io_loop;
-       uv_signal_t signals[8];
-       uv_timer_t sultimer;
-       uv_idle_t idle;
-};
-
-struct lws_context_eventlibs_libuv {
-       uv_loop_t loop;
-};
-
-struct lws_io_watcher_libuv {
-       uv_poll_t *pwatcher;
-};
-
-struct lws_signal_watcher_libuv {
-       uv_signal_t watcher;
-};
-
-extern struct lws_event_loop_ops event_loop_ops_uv;
-
-uv_loop_t *
-lws_uv_getloop(struct lws_context *context, int tsi);
-
-int
-lws_uv_plugins_init(struct lws_context *context, const char * const *d);
-
-int
-lws_uv_plugins_destroy(struct lws_context *context);
diff --git a/lib/event-libs/poll/CMakeLists.txt b/lib/event-libs/poll/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ad634b9
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(../poll)
+
+if (LWS_WITH_NETWORK)
+       list(APPEND SOURCES
+               event-libs/poll/poll.c)
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
index 6fb312f..aa45dc5 100644 (file)
@@ -1,43 +1,62 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h if LWS_ROLE_WS
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
+#include "private-lib-event-libs-poll.h"
+
+static int
+elops_foreign_thread_poll(struct lws_context *cx, int tsi)
+{
+       struct lws_context_per_thread *pt = &cx->pt[tsi];
+       volatile struct lws_context_per_thread *vpt =
+                               (volatile struct lws_context_per_thread *)pt;
+
+       /*
+        * To avoid mandating a specific threading library, we can check
+        * probabilistically by seeing if the lws default wait is still asleep
+        * at the time we are checking, if it is then we cannot be being called
+        * by the event loop loop thread.
+        */
+
+       return vpt->inside_poll;
+}
 
 struct lws_event_loop_ops event_loop_ops_poll = {
-       /* name */                      "poll",
-       /* init_context */              NULL,
-       /* destroy_context1 */          NULL,
-       /* destroy_context2 */          NULL,
-       /* init_vhost_listen_wsi */     NULL,
-       /* init_pt */                   NULL,
-       /* wsi_logical_close */         NULL,
-       /* check_client_connect_ok */   NULL,
-       /* close_handle_manually */     NULL,
-       /* accept */                    NULL,
-       /* io */                        NULL,
-       /* run */                       NULL,
-       /* destroy_pt */                NULL,
-       /* destroy wsi */               NULL,
-
-       /* periodic_events_available */ 1,
+       .name                           = "poll",
+
+       .foreign_thread                 = elops_foreign_thread_poll,
+
+       .flags                          = LELOF_ISPOLL,
+};
+
+const lws_plugin_evlib_t evlib_poll = {
+       .hdr = {
+               "poll",
+               "lws_evlib_plugin",
+               "n/a",
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .ops    = &event_loop_ops_poll
 };
diff --git a/lib/event-libs/poll/private-lib-event-libs-poll.h b/lib/event-libs/poll/private-lib-event-libs-poll.h
new file mode 100644 (file)
index 0000000..9859754
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+extern struct lws_event_loop_ops event_loop_ops_poll;
diff --git a/lib/event-libs/poll/private.h b/lib/event-libs/poll/private.h
deleted file mode 100644 (file)
index ca313eb..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- */
-
-extern struct lws_event_loop_ops event_loop_ops_poll;
diff --git a/lib/event-libs/private-lib-event-libs.h b/lib/event-libs/private-lib-event-libs.h
new file mode 100644 (file)
index 0000000..5cc0b75
--- /dev/null
@@ -0,0 +1,27 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *  This is included from private-lib-core.h
+ */
+
+
diff --git a/lib/event-libs/private.h b/lib/event-libs/private.h
deleted file mode 100644 (file)
index 58bca94..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h
- */
-
-struct lws_event_loop_ops {
-       const char *name;
-       /* event loop-specific context init during context creation */
-       int (*init_context)(struct lws_context *context,
-                           const struct lws_context_creation_info *info);
-       /* called during lws_destroy_context */
-       int (*destroy_context1)(struct lws_context *context);
-       /* called during lws_destroy_context2 */
-       int (*destroy_context2)(struct lws_context *context);
-       /* init vhost listening wsi */
-       int (*init_vhost_listen_wsi)(struct lws *wsi);
-       /* init the event loop for a pt */
-       int (*init_pt)(struct lws_context *context, void *_loop, int tsi);
-       /* called at end of first phase of close_free_wsi()  */
-       int (*wsi_logical_close)(struct lws *wsi);
-       /* return nonzero if client connect not allowed  */
-       int (*check_client_connect_ok)(struct lws *wsi);
-       /* close handle manually  */
-       void (*close_handle_manually)(struct lws *wsi);
-       /* event loop accept processing  */
-       int (*accept)(struct lws *wsi);
-       /* control wsi active events  */
-       void (*io)(struct lws *wsi, int flags);
-       /* run the event loop for a pt */
-       void (*run_pt)(struct lws_context *context, int tsi);
-       /* called before pt is destroyed */
-       void (*destroy_pt)(struct lws_context *context, int tsi);
-       /* called just before wsi is freed  */
-       void (*destroy_wsi)(struct lws *wsi);
-
-       unsigned int periodic_events_available:1;
-};
-
-/* bring in event libs private declarations */
-
-#if defined(LWS_WITH_POLL)
-#include "event-libs/poll/private.h"
-#endif
-
-#if defined(LWS_WITH_LIBUV)
-#include "event-libs/libuv/private.h"
-#endif
-
-#if defined(LWS_WITH_LIBEVENT)
-#include "event-libs/libevent/private.h"
-#endif
-
-#if defined(LWS_WITH_LIBEV)
-#include "event-libs/libev/private.h"
-#endif
-
diff --git a/lib/event-libs/sdevent/CMakeLists.txt b/lib/event-libs/sdevent/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c4222d3
--- /dev/null
@@ -0,0 +1,44 @@
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+# configure or find systemd library
+set(LIB_SYSTEMD_LIBRARIES CACHE PATH "Path to the libsystemd library")
+if ("${LWS_SYSTEMD_LIBRARIES}" STREQUAL "")
+    if (NOT LIB_SYSTEMD_FOUND)
+        find_path(LIBSYSTEMD_INCLUDE_DIRS NAMES systemd/sd-event.h)
+        find_library(LIBSYSTEMD_LIBRARIES NAMES systemd)
+    endif()
+else()
+    set(LIBSYSTEMD_LIBRARIES ${LWS_SYSTEMD_LIBRARIES})
+    set(LIBSYSTEMD_INCLUDE_DIRS ${LWS_LIBSYSTEMD_INCLUDE_DIRS})
+endif()
+message("libsystemd include dir: ${LIBSYSTEMD_INCLUDE_DIRS}")
+message("libsystemd libraries: ${LIBSYSTEMD_LIBRARIES}")
+
+if (LWS_WITH_EVLIB_PLUGINS)
+
+    create_evlib_plugin(
+            evlib_sd
+            sdevent.c
+            private-lib-event-libs-sdevent.h
+            ${LIBSYSTEMD_LIBRARIES}
+    )
+
+else()
+
+    list(APPEND LIB_LIST ${LIBSYSTEMD_LIBRARIES})
+    list(APPEND SOURCES event-libs/sdevent/sdevent.c)
+
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
diff --git a/lib/event-libs/sdevent/private-lib-event-libs-sdevent.h b/lib/event-libs/sdevent/private-lib-event-libs-sdevent.h
new file mode 100644 (file)
index 0000000..b530d70
--- /dev/null
@@ -0,0 +1,3 @@
+#include <private-lib-core.h>
+
+extern const struct lws_event_loop_ops event_loop_ops_sdevent;
diff --git a/lib/event-libs/sdevent/sdevent.c b/lib/event-libs/sdevent/sdevent.c
new file mode 100644 (file)
index 0000000..0c7ddae
--- /dev/null
@@ -0,0 +1,442 @@
+#include <systemd/sd-event.h>
+
+#include <private-lib-core.h>
+#include "private-lib-event-libs-sdevent.h"
+
+#define pt_to_priv_sd(_pt) ((struct lws_pt_eventlibs_sdevent *)(_pt)->evlib_pt)
+#define wsi_to_priv_sd(_w) ((struct lws_wsi_watcher_sdevent *)(_w)->evlib_wsi)
+
+struct lws_pt_eventlibs_sdevent {
+       struct lws_context_per_thread *pt;
+       struct sd_event *io_loop;
+       struct sd_event_source *sultimer;
+       struct sd_event_source *idletimer;
+};
+
+struct lws_wsi_watcher_sdevent {
+       struct sd_event_source *source;
+       uint32_t events;
+};
+
+static int
+sultimer_handler(sd_event_source *s, uint64_t usec, void *userdata)
+{
+       struct lws_context_per_thread *pt = (struct lws_context_per_thread *)userdata;
+
+       lws_usec_t us;
+
+       lws_context_lock(pt->context, __func__);
+       lws_pt_lock(pt, __func__);
+
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
+       if (us) {
+               uint64_t at;
+
+               sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &at);
+               at += (uint64_t)us;
+               sd_event_source_set_time(pt_to_priv_sd(pt)->sultimer, at);
+               sd_event_source_set_enabled(pt_to_priv_sd(pt)->sultimer,
+                                           SD_EVENT_ONESHOT);
+       }
+
+       lws_pt_unlock(pt);
+       lws_context_unlock(pt->context);
+
+       return 0;
+}
+
+static int
+idle_handler(sd_event_source *s, uint64_t usec, void *userdata)
+{
+       struct lws_context_per_thread *pt = (struct lws_context_per_thread *)userdata;
+
+       lws_usec_t us;
+
+       lws_service_do_ripe_rxflow(pt);
+
+       lws_context_lock(pt->context, __func__);
+       lws_pt_lock(pt, __func__);
+
+       /*
+        * is there anybody with pending stuff that needs service forcing?
+        */
+        if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
+                /* -1 timeout means just do forced service */
+                _lws_plat_service_forced_tsi(pt->context, pt->tid);
+
+        /* account for sultimer */
+
+        us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                    lws_now_usecs());
+
+        if (us) {
+                uint64_t at;
+
+                sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &at);
+                at += (uint64_t)us;
+                sd_event_source_set_time(pt_to_priv_sd(pt)->sultimer, at);
+                sd_event_source_set_enabled(pt_to_priv_sd(pt)->sultimer,
+                                            SD_EVENT_ONESHOT);
+        }
+
+        sd_event_source_set_enabled(pt_to_priv_sd(pt)->idletimer, SD_EVENT_OFF);
+
+        lws_pt_unlock(pt);
+        lws_context_unlock(pt->context);
+
+        return 0;
+}
+
+static int
+sock_accept_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata)
+{
+       struct lws *wsi = (struct lws *)userdata;
+       struct lws_context *context = wsi->a.context;
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+       struct sd_event_source *idletimer, *watcher;
+       struct lws_pollfd eventfd;
+
+       lws_context_lock(pt->context, __func__);
+       lws_pt_lock(pt, __func__);
+
+       if (pt->is_destroyed)
+               goto bail;
+
+       eventfd.fd = fd;
+       eventfd.events = 0;
+       eventfd.revents = 0;
+
+       if (revents & EPOLLIN) {
+               eventfd.events |= LWS_POLLIN;
+               eventfd.revents |= LWS_POLLIN;
+       }
+
+       if (revents & EPOLLOUT) {
+               eventfd.events |= LWS_POLLOUT;
+               eventfd.revents |= LWS_POLLOUT;
+       }
+
+       lws_pt_unlock(pt);
+       lws_context_unlock(pt->context);
+
+       lws_service_fd_tsi(context, &eventfd, wsi->tsi);
+
+       if (pt->destroy_self) {
+               lws_context_destroy(pt->context);
+               return -1;
+       }
+
+       /* fire idle handler */
+       idletimer = pt_to_priv_sd(pt)->idletimer;
+       if (idletimer) {
+               sd_event_source_set_time(idletimer, (uint64_t) 0);
+               sd_event_source_set_enabled(idletimer, SD_EVENT_ON);
+       }
+
+       /*
+        * allow further events
+        *
+        * Note:
+        * do not move the assignment up, lws_service_fd_tsi may invalidate it!
+        */
+       watcher = wsi_to_priv_sd(wsi)->source;
+       if (watcher)
+               sd_event_source_set_enabled(watcher, SD_EVENT_ONESHOT);
+
+       return 0;
+
+bail:
+       lws_pt_unlock(pt);
+       lws_context_unlock(pt->context);
+
+       return -1;
+}
+
+static void
+io_sd(struct lws *wsi, unsigned int flags)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+
+       /*
+        * Only manipulate if there is an event source, and if
+        * the pt is still alive
+        */
+       if (!pt_to_priv_sd(pt)->io_loop ||
+           !wsi_to_priv_sd(wsi)->source ||
+           pt->is_destroyed)
+               return;
+
+       // assert that the requested flags do not contain anything unexpected
+       if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
+           (flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
+               lwsl_wsi_err(wsi, "assert: flags %d", flags);
+               assert(0);
+       }
+
+       // we are overdoing a bit here, so it resembles the structure in libuv.c
+       if (flags & LWS_EV_START) {
+               if (flags & LWS_EV_WRITE)
+                       wsi_to_priv_sd(wsi)->events |= EPOLLOUT;
+
+               if (flags & LWS_EV_READ)
+                       wsi_to_priv_sd(wsi)->events |= EPOLLIN;
+
+               sd_event_source_set_io_events(wsi_to_priv_sd(wsi)->source,
+                                             wsi_to_priv_sd(wsi)->events);
+               sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source,
+                                           SD_EVENT_ONESHOT);
+       } else {
+               if (flags & LWS_EV_WRITE)
+                       wsi_to_priv_sd(wsi)->events =
+                               wsi_to_priv_sd(wsi)->events &
+                                       (uint32_t)(~EPOLLOUT);
+
+               if (flags & LWS_EV_READ)
+                       wsi_to_priv_sd(wsi)->events =
+                               wsi_to_priv_sd(wsi)->events &
+                                       (uint32_t)(~EPOLLIN);
+
+               sd_event_source_set_io_events(wsi_to_priv_sd(wsi)->source,
+                                             wsi_to_priv_sd(wsi)->events);
+
+               if (!(wsi_to_priv_sd(wsi)->events & (EPOLLIN | EPOLLOUT)))
+                       sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source,
+                                                   SD_EVENT_ONESHOT);
+               else
+                       sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source,
+                                                   SD_EVENT_OFF);
+       }
+}
+
+static int
+init_vhost_listen_wsi_sd(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt;
+
+       if (!wsi)
+               return 0;
+
+       pt = &wsi->a.context->pt[(int)wsi->tsi];
+
+       sd_event_add_io(pt_to_priv_sd(pt)->io_loop,
+                       &wsi_to_priv_sd(wsi)->source,
+                       wsi->desc.sockfd,
+                       wsi_to_priv_sd(wsi)->events,
+                       sock_accept_handler,
+                       wsi);
+
+       io_sd(wsi, LWS_EV_START | LWS_EV_READ);
+
+       return 0;
+}
+
+static int
+elops_listen_init_sdevent(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+
+       if (init_vhost_listen_wsi_sd(wsi) == -1)
+               return -1;
+
+       return 0;
+}
+
+static int
+init_pt_sd(struct lws_context *context, void *_loop, int tsi)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt);
+       struct sd_event *loop = (struct sd_event *)_loop;
+       int first = 1;  /* first to create and initialize the loop */
+
+       ptpriv->pt = pt;
+
+       /* make sure we have an event loop */
+       if (!ptpriv->io_loop) {
+               if (!loop) {
+                       if (sd_event_default(&loop) < 0) {
+                               lwsl_cx_err(context, "sd_event_default failed");
+
+                               return -1;
+                       }
+                       pt->event_loop_foreign = 0;
+               } else {
+                       sd_event_ref(loop);
+                       pt->event_loop_foreign = 1;
+               }
+
+               ptpriv->io_loop = loop;
+       } else
+                /*
+                 * If the loop was initialized before, we do not need to
+                 * do full initialization
+                 */
+               first = 0;
+
+       lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_sdevent);
+
+       if (first) {
+
+               if (0 > sd_event_add_time(loop,
+                               &ptpriv->sultimer,
+                               CLOCK_MONOTONIC,
+                               UINT64_MAX,
+                               0,
+                               sultimer_handler,
+                               (void*) pt
+               ))
+                       return -1;
+
+               if (0 > sd_event_add_time(loop,
+                               &ptpriv->idletimer,
+                               CLOCK_MONOTONIC,
+                               0,
+                               0,
+                               idle_handler,
+                               (void *)pt))
+                       return -1;
+
+               sd_event_source_set_enabled(ptpriv->idletimer, SD_EVENT_ON);
+
+               if (0 > sd_event_source_set_priority(ptpriv->idletimer,
+                                                    SD_EVENT_PRIORITY_IDLE))
+                       return -1;
+
+       }
+
+       return 0;
+}
+
+static void
+wsi_destroy_sd(struct lws *wsi)
+{
+       if (!wsi)
+               return;
+
+       io_sd(wsi, LWS_EV_STOP | (LWS_EV_READ | LWS_EV_WRITE));
+
+       if (wsi_to_priv_sd(wsi)->source) {
+               sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source,
+                                           SD_EVENT_OFF);
+               sd_event_source_unref(wsi_to_priv_sd(wsi)->source);
+               wsi_to_priv_sd(wsi)->source = NULL;
+       }
+}
+
+static int
+wsi_logical_close_sd(struct lws *wsi)
+{
+       wsi_destroy_sd(wsi);
+
+       return 0;
+}
+
+static int
+sock_accept_sd(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+
+       if (wsi->role_ops->file_handle)
+               sd_event_add_io(pt_to_priv_sd(pt)->io_loop,
+                               &wsi_to_priv_sd(wsi)->source,
+                               wsi->desc.filefd,
+                               wsi_to_priv_sd(wsi)->events,
+                               sock_accept_handler,
+                               wsi);
+       else
+               sd_event_add_io(pt_to_priv_sd(pt)->io_loop,
+                               &wsi_to_priv_sd(wsi)->source,
+                               wsi->desc.sockfd,
+                               wsi_to_priv_sd(wsi)->events,
+                               sock_accept_handler,
+                               wsi);
+
+       return 0;
+}
+
+static void
+run_pt_sd(struct lws_context *context, int tsi)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt);
+
+       if (ptpriv->io_loop)
+               sd_event_run(ptpriv->io_loop, (uint64_t) -1);
+}
+
+static int
+elops_listen_destroy_sdevent(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+
+       wsi_logical_close_sd(wsi);
+
+       return 0;
+}
+
+static void
+destroy_pt_sd(struct lws_context *context, int tsi)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt);
+
+       lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_sdevent);
+
+       if (ptpriv->sultimer) {
+               sd_event_source_set_enabled(ptpriv->sultimer,
+                                           SD_EVENT_OFF);
+               sd_event_source_unref(ptpriv->sultimer);
+               ptpriv->sultimer = NULL;
+       }
+
+       if (ptpriv->idletimer) {
+               sd_event_source_set_enabled(ptpriv->idletimer,
+                                           SD_EVENT_OFF);
+               sd_event_source_unref(ptpriv->idletimer);
+               ptpriv->idletimer = NULL;
+       }
+
+       if (ptpriv->io_loop) {
+               sd_event_unref(ptpriv->io_loop);
+               ptpriv->io_loop = NULL;
+       }
+}
+
+const struct lws_event_loop_ops event_loop_ops_sdevent = {
+               .name                           = "sdevent",
+               .init_context                   = NULL,
+               .destroy_context1               = NULL,
+               .destroy_context2               = NULL,
+               .init_vhost_listen_wsi          = init_vhost_listen_wsi_sd,
+               .init_pt                        = init_pt_sd,
+               .wsi_logical_close              = wsi_logical_close_sd,
+               .check_client_connect_ok        = NULL,
+               .close_handle_manually          = NULL,
+               .sock_accept                    = sock_accept_sd,
+               .io                             = io_sd,
+               .run_pt                         = run_pt_sd,
+               .destroy_pt                     = destroy_pt_sd,
+               .destroy_wsi                    = wsi_destroy_sd,
+
+               .flags                          = 0,
+
+               .evlib_size_ctx                 = 0,
+               .evlib_size_pt                  = sizeof(struct lws_pt_eventlibs_sdevent),
+               .evlib_size_vh                  = 0,
+               .evlib_size_wsi                 = sizeof(struct lws_wsi_watcher_sdevent),
+};
+
+#if defined(LWS_WITH_EVLIB_PLUGINS)
+LWS_VISIBLE
+#endif
+const lws_plugin_evlib_t evlib_sd = {
+               .hdr = {
+                               "systemd event loop",
+                               "lws_evlib_plugin",
+                               LWS_BUILD_HASH,
+                               LWS_PLUGIN_API_MAGIC
+               },
+
+               .ops    = &event_loop_ops_sdevent
+};
diff --git a/lib/event-libs/uloop/CMakeLists.txt b/lib/event-libs/uloop/CMakeLists.txt
new file mode 100644 (file)
index 0000000..20be020
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+set(LWS_ULOOP_INCLUDE_DIRS CACHE PATH "Path to the libubox / uloop.h include directory")
+set(LWS_ULOOP_LIBRARIES CACHE PATH "Path to the libubox library")
+
+if (NOT ULOOP_FOUND)
+       find_path(ULOOP_INCLUDE_DIRS NAMES libubox/uloop.h)
+       find_library(ULOOP_LIBRARIES NAMES ubox)
+endif()
+message("libubox include dir: ${ULOOP_INCLUDE_DIRS}")
+message("libubox libraries: ${ULOOP_LIBRARIES}")
+include_directories("${ULOOP_INCLUDE_DIRS}")
+
+if ("${LWS_ULOOP_LIBRARIES}" STREQUAL "" OR "${LWS_ULOOP_INCLUDE_DIRS}" STREQUAL "")
+else()
+       set(ULOOP_LIBRARIES ${LWS_ULOOP_LIBRARIES})
+       set(ULOOP_INCLUDE_DIRS ${LWS_ULOOP_INCLUDE_DIRS})
+endif()
+
+
+if (LWS_WITH_EVLIB_PLUGINS)
+
+       create_evlib_plugin(evlib_uloop
+                           uloop.c
+                           private-lib-event-libs-uloop.h
+                           ${ULOOP_LIBRARIES})
+
+else()
+
+       list(APPEND LIB_LIST ${ULOOP_LIBRARIES})
+       set(ULOOP_FOUND 1 PARENT_SCOPE)
+       if (LWS_WITH_NETWORK)
+               list(APPEND SOURCES
+                       event-libs/uloop/uloop.c)
+       endif()
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
diff --git a/lib/event-libs/uloop/private-lib-event-libs-uloop.h b/lib/event-libs/uloop/private-lib-event-libs-uloop.h
new file mode 100644 (file)
index 0000000..1034770
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <libubox/uloop.h>
+
+struct lws_pt_eventlibs_uloop {
+       struct lws_context_per_thread           *pt;
+       struct uloop_timeout                    hrtimer;
+       struct uloop_timeout                    idle_timer;
+};
+
+struct lws_wsi_eventlibs_uloop {
+       struct lws                              *wsi;
+       struct uloop_fd                         fd;
+       unsigned int                            actual_events;
+};
diff --git a/lib/event-libs/uloop/uloop.c b/lib/event-libs/uloop/uloop.c
new file mode 100644 (file)
index 0000000..be9046c
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-event-libs-uloop.h"
+
+#define pt_to_priv_uloop(_pt) ((struct lws_pt_eventlibs_uloop *)(_pt)->evlib_pt)
+#define wsi_to_priv_uloop(_w) ((struct lws_wsi_eventlibs_uloop *)(_w)->evlib_wsi)
+
+static void
+lws_uloop_hrtimer_cb(struct uloop_timeout *ti)
+{
+       struct lws_pt_eventlibs_uloop *upt = lws_container_of(ti,
+                                       struct lws_pt_eventlibs_uloop, hrtimer);
+       struct lws_context_per_thread *pt = upt->pt;
+       lws_usec_t us;
+
+       lws_pt_lock(pt, __func__);
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
+       if (us)
+               uloop_timeout_set(ti, us < 1000 ? 1 : (int)(us / 1000));
+
+       lws_pt_unlock(pt);
+}
+
+static void
+lws_uloop_idle_timer_cb(struct uloop_timeout *ti)
+{
+       struct lws_pt_eventlibs_uloop *upt = lws_container_of(ti,
+                                               struct lws_pt_eventlibs_uloop,
+                                               idle_timer);
+       struct lws_context_per_thread *pt = upt->pt;
+       lws_usec_t us;
+
+       if (pt->is_destroyed)
+               return;
+
+       lws_service_do_ripe_rxflow(pt);
+
+       /*
+        * is there anybody with pending stuff that needs service forcing?
+        */
+       if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
+               /* -1 timeout means just do forced service */
+               _lws_plat_service_forced_tsi(pt->context, pt->tid);
+               /* still somebody left who wants forced service? */
+               if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
+                       /* yes... come back again later */
+
+                       uloop_timeout_set(ti, 1 /* 1ms */);
+
+                       return;
+               }
+       }
+
+       /* account for hrtimer */
+
+       lws_pt_lock(pt, __func__);
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
+                                   lws_now_usecs());
+       if (us) {
+               uloop_timeout_cancel(&upt->hrtimer);
+               uloop_timeout_set(&upt->hrtimer,
+                                 us < 1000 ? 1 : (int)(us / 1000));
+       }
+
+       lws_pt_unlock(pt);
+
+       if (pt->destroy_self)
+               lws_context_destroy(pt->context);
+}
+
+static void
+lws_uloop_cb(struct uloop_fd *ufd, unsigned int revents)
+{
+       struct lws_wsi_eventlibs_uloop *wu = lws_container_of(ufd,
+                                       struct lws_wsi_eventlibs_uloop, fd);
+       struct lws_context *context = wu->wsi->a.context;
+       struct lws_context_per_thread *pt;
+       struct lws_pollfd eventfd;
+
+       eventfd.fd = wu->wsi->desc.sockfd;
+       eventfd.events = 0;
+       eventfd.revents = 0;
+
+       if (revents & ULOOP_READ) {
+               eventfd.events = LWS_POLLIN;
+               eventfd.revents = LWS_POLLIN;
+       }
+       if (revents & ULOOP_WRITE) {
+               eventfd.events |= LWS_POLLOUT;
+               eventfd.revents |= LWS_POLLOUT;
+       }
+
+       pt = &context->pt[(int)wu->wsi->tsi];
+       if (pt->is_destroyed)
+               return;
+
+       lws_service_fd_tsi(context, &eventfd, wu->wsi->tsi);
+
+       if (pt->destroy_self) {
+               lwsl_cx_notice(context, "pt destroy self coming true");
+               lws_context_destroy(pt->context);
+               return;
+       }
+
+       /* set the idle timer for 1ms ahead */
+
+       uloop_timeout_cancel(&pt_to_priv_uloop(pt)->idle_timer);
+       uloop_timeout_set(&pt_to_priv_uloop(pt)->idle_timer, 1);
+}
+
+static int
+elops_listen_init_uloop(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+       struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi);
+
+       wu->wsi = wsi;
+       wu->fd.fd = wsi->desc.sockfd;
+       wu->fd.cb = lws_uloop_cb;
+       uloop_fd_add(&wu->fd,  ULOOP_READ);
+       wu->actual_events = ULOOP_READ;
+
+       return 0;
+}
+
+static int
+elops_init_pt_uloop(struct lws_context *context, void *v, int tsi)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_pt_eventlibs_uloop *ptpr = pt_to_priv_uloop(pt);
+
+       ptpr->pt = pt;
+
+       lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_uloop);
+
+       /* static event loop objects */
+
+       ptpr->hrtimer.cb = lws_uloop_hrtimer_cb;
+       ptpr->idle_timer.cb = lws_uloop_idle_timer_cb;
+
+       uloop_timeout_add(&ptpr->hrtimer);
+       uloop_timeout_add(&ptpr->idle_timer);
+
+       uloop_timeout_set(&ptpr->hrtimer, 1);
+
+       return 0;
+}
+
+static int
+elops_accept_uloop(struct lws *wsi)
+{
+       struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi);
+
+       wu->wsi = wsi;
+       wu->fd.fd = wsi->desc.sockfd;
+       wu->fd.cb = lws_uloop_cb;
+       uloop_fd_add(&wu->fd, ULOOP_READ);
+       wu->actual_events = ULOOP_READ;
+
+       return 0;
+}
+
+static void
+elops_io_uloop(struct lws *wsi, unsigned int flags)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi);
+       unsigned int ulf = (unsigned int)(((flags & LWS_EV_WRITE) ? ULOOP_WRITE : 0) |
+                           ((flags & LWS_EV_READ) ? ULOOP_READ : 0)), u;
+
+       if (wsi->a.context->being_destroyed || pt->is_destroyed)
+               return;
+
+       assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
+              (flags & (LWS_EV_READ | LWS_EV_WRITE)));
+
+       u = wu->actual_events;
+       if (flags & LWS_EV_START)
+               u |= ulf;
+       if (flags & LWS_EV_STOP)
+               u &= ~ulf;
+
+       uloop_fd_add(&wu->fd, u);
+       wu->actual_events = u;
+}
+
+static void
+elops_run_pt_uloop(struct lws_context *context, int tsi)
+{
+       uloop_run();
+}
+
+static int
+elops_listen_destroy_uloop(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+       struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi);
+
+       uloop_fd_delete(&wu->fd);
+
+       return 0;
+}
+
+static void
+elops_destroy_pt_uloop(struct lws_context *context, int tsi)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_pt_eventlibs_uloop *ptpr = pt_to_priv_uloop(pt);
+
+       lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_uloop);
+
+       uloop_timeout_cancel(&ptpr->hrtimer);
+       uloop_timeout_cancel(&ptpr->idle_timer);
+}
+
+static void
+elops_destroy_wsi_uloop(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt;
+
+       if (!wsi)
+               return;
+
+       pt = &wsi->a.context->pt[(int)wsi->tsi];
+       if (pt->is_destroyed)
+               return;
+
+       uloop_fd_delete(&wsi_to_priv_uloop(wsi)->fd);
+}
+
+static int
+elops_wsi_logical_close_uloop(struct lws *wsi)
+{
+       elops_destroy_wsi_uloop(wsi);
+
+       return 0;
+}
+
+static int
+elops_init_vhost_listen_wsi_uloop(struct lws *wsi)
+{
+       struct lws_wsi_eventlibs_uloop *wu;
+
+       if (!wsi) {
+               assert(0);
+               return 0;
+       }
+
+       wu = wsi_to_priv_uloop(wsi);
+       wu->wsi = wsi;
+       wu->fd.fd = wsi->desc.sockfd;
+       wu->fd.cb = lws_uloop_cb;
+       uloop_fd_add(&wu->fd,  ULOOP_READ);
+
+       wu->actual_events = ULOOP_READ;
+
+       return 0;
+}
+
+static const struct lws_event_loop_ops event_loop_ops_uloop = {
+       /* name */                      "uloop",
+       /* init_context */              NULL,
+       /* destroy_context1 */          NULL,
+       /* destroy_context2 */          NULL,
+       /* init_vhost_listen_wsi */     elops_init_vhost_listen_wsi_uloop,
+       /* init_pt */                   elops_init_pt_uloop,
+       /* wsi_logical_close */         elops_wsi_logical_close_uloop,
+       /* check_client_connect_ok */   NULL,
+       /* close_handle_manually */     NULL,
+       /* accept */                    elops_accept_uloop,
+       /* io */                        elops_io_uloop,
+       /* run_pt */                    elops_run_pt_uloop,
+       /* destroy_pt */                elops_destroy_pt_uloop,
+       /* destroy wsi */               elops_destroy_wsi_uloop,
+       /* foreign_thread */            NULL,
+
+       /* flags */                     0,
+
+       /* evlib_size_ctx */    0,
+       /* evlib_size_pt */     sizeof(struct lws_pt_eventlibs_uloop),
+       /* evlib_size_vh */     0,
+       /* evlib_size_wsi */    sizeof(struct lws_wsi_eventlibs_uloop),
+};
+
+#if defined(LWS_WITH_EVLIB_PLUGINS)
+LWS_VISIBLE
+#endif
+const lws_plugin_evlib_t evlib_uloop = {
+       .hdr = {
+               "uloop event loop",
+               "lws_evlib_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .ops    = &event_loop_ops_uloop
+};
diff --git a/lib/jose/CMakeLists.txt b/lib/jose/CMakeLists.txt
new file mode 100644 (file)
index 0000000..161744e
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+include_directories(. ./jwe ./jws ./jwk)
+
+if (LWS_WITH_JOSE)
+       list(APPEND SOURCES
+               jose/jws/jose.c
+               jose/jwk/jwk.c
+               jose/jwk/jose_key.c
+               jose/jws/jws.c
+               jose/jwe/jwe.c
+               jose/jwe/enc/aescbc.c
+               jose/jwe/enc/aesgcm.c
+               jose/jwe/enc/aeskw.c
+               jose/jwe/jwe-rsa-aescbc.c
+               jose/jwe/jwe-rsa-aesgcm.c
+               jose/jwe/jwe-ecdh-es-aeskw.c
+               )
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
old mode 100644 (file)
new mode 100755 (executable)
index 54cabc7..bf559d9
@@ -1,39 +1,40 @@
 /*
- * libwebsockets - JSON Web Encryption support
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *
- * JWE code for payload encrypt / decrypt using aescbc
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
-#include "core/private.h"
-#include "jose/jwe/private.h"
+
+#include "private-lib-core.h"
+#include "private-lib-jose-jwe.h"
 
 int
 lws_jwe_encrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *cek,
                       uint8_t *aad, int aad_len)
 {
-       int n, hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
+       int n, hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
        uint8_t digest[LWS_GENHASH_LARGEST];
        struct lws_gencrypto_keyelem el;
        struct lws_genhmac_ctx hmacctx;
        struct lws_genaes_ctx aesctx;
+       size_t paddedlen;
        uint8_t al[8];
 
        /* Caller must have prepared space for the results */
@@ -78,25 +79,30 @@ lws_jwe_encrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *cek,
 
        /* second half is the AES ENC_KEY */
        el.buf = cek + (hlen / 2);
-       el.len = hlen / 2;
+       el.len = (uint32_t)(hlen / 2);
 
        if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_CBC, &el,
-                             LWS_GAESP_NO_PADDING, NULL)) {
+                             LWS_GAESP_WITH_PADDING, NULL)) {
                lwsl_err("%s: lws_genaes_create failed\n", __func__);
 
                return -1;
        }
 
        /*
-        * the plaintext gets delivered to us in LJWE_CTXT, this replaces
-        * the plaintext there with the same amount of ciphertext
+        * the plaintext gets delivered to us in LJWE_CTXT, this replaces the
+        * plaintext there with the ciphertext, which will be larger by some
+        * padding bytes
         */
        n = lws_genaes_crypt(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
                             jwe->jws.map.len[LJWE_CTXT],
                             (uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
                             (uint8_t *)jwe->jws.map.buf[LJWE_IV],
-                            NULL, NULL, 16);
-       lws_genaes_destroy(&aesctx, NULL, 0);
+                            NULL, NULL, LWS_AES_CBC_BLOCKLEN);
+       paddedlen = lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN,
+                                               jwe->jws.map.len[LJWE_CTXT]);
+       jwe->jws.map.len[LJWE_CTXT] = (uint32_t)paddedlen;
+       lws_genaes_destroy(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_CTXT] +
+                          paddedlen - LWS_AES_CBC_BLOCKLEN, LWS_AES_CBC_BLOCKLEN);
        if (n) {
                lwsl_err("%s: lws_genaes_crypt failed\n", __func__);
                return -1;
@@ -107,11 +113,11 @@ lws_jwe_encrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *cek,
         *     Additional Authenticated Data A expressed as a 64-bit unsigned
         *     big-endian integer.
         */
-       lws_jwe_be64(aad_len * 8, al);
+       lws_jwe_be64((unsigned int)aad_len * 8, al);
 
        /* first half of the CEK is the MAC key */
        if (lws_genhmac_init(&hmacctx, jwe->jose.enc_alg->hmac_type,
-                               cek, hlen / 2))
+                               cek, (unsigned int)hlen / 2))
                return -1;
 
        /*
@@ -128,7 +134,7 @@ lws_jwe_encrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *cek,
         *    M are used as T.
         */
 
-       if (lws_genhmac_update(&hmacctx, aad, aad_len) ||
+       if (lws_genhmac_update(&hmacctx, aad, (unsigned int)aad_len) ||
            lws_genhmac_update(&hmacctx, jwe->jws.map.buf[LJWE_IV],
                               LWS_JWE_AES_IV_BYTES) ||
            /* since we encrypted it, this is the ciphertext */
@@ -147,16 +153,16 @@ lws_jwe_encrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *cek,
        }
 
        /* create tag */
-       memcpy((void *)jwe->jws.map.buf[LJWE_ATAG], digest, hlen / 2);
+       memcpy((void *)jwe->jws.map.buf[LJWE_ATAG], digest, (unsigned int)hlen / 2);
 
-       return jwe->jws.map.len[LJWE_CTXT];
+       return (int)jwe->jws.map.len[LJWE_CTXT];
 }
 
 int
 lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *enc_cek,
                                uint8_t *aad, int aad_len)
 {
-       int n, hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
+       int n, hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
        uint8_t digest[LWS_GENHASH_LARGEST];
        struct lws_gencrypto_keyelem el;
        struct lws_genhmac_ctx hmacctx;
@@ -191,16 +197,16 @@ lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *enc_cek,
         *
         */
 
-       lws_jwe_be64(aad_len * 8, al);
+       lws_jwe_be64((unsigned int)aad_len * 8, al);
 
        /* first half of enc_cek is the MAC key */
        if (lws_genhmac_init(&hmacctx, jwe->jose.enc_alg->hmac_type, enc_cek,
-                            hlen / 2)) {
+                            (unsigned int)hlen / 2)) {
                lwsl_err("%s: lws_genhmac_init fail\n", __func__);
                return -1;
        }
 
-       if (lws_genhmac_update(&hmacctx, aad, aad_len) ||
+       if (lws_genhmac_update(&hmacctx, aad, (unsigned int)aad_len) ||
            lws_genhmac_update(&hmacctx, (uint8_t *)jwe->jws.map.buf[LJWE_IV],
                                         jwe->jws.map.len[LJWE_IV]) ||
            lws_genhmac_update(&hmacctx, (uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
@@ -218,17 +224,17 @@ lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *enc_cek,
 
        /* first half of digest is the auth tag */
 
-       if (lws_timingsafe_bcmp(digest, jwe->jws.map.buf[LJWE_ATAG], hlen / 2)) {
+       if (lws_timingsafe_bcmp(digest, jwe->jws.map.buf[LJWE_ATAG], (unsigned int)hlen / 2)) {
                lwsl_err("%s: auth failed: hmac tag (%d) != ATAG (%d)\n",
                         __func__, hlen / 2, jwe->jws.map.len[LJWE_ATAG]);
-               lwsl_hexdump_notice(jwe->jws.map.buf[LJWE_ATAG], hlen / 2);
-               lwsl_hexdump_notice(digest, hlen / 2);
+               lwsl_hexdump_notice(jwe->jws.map.buf[LJWE_ATAG], (unsigned int)hlen / 2);
+               lwsl_hexdump_notice(digest, (unsigned int)hlen / 2);
                return -1;
        }
 
        /* second half of enc cek is the CEK KEY */
        el.buf = enc_cek + (hlen / 2);
-       el.len = hlen / 2;
+       el.len = (unsigned int)hlen / 2;
 
        if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_CBC,
                              &el, LWS_GAESP_NO_PADDING, NULL)) {
@@ -241,12 +247,25 @@ lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *enc_cek,
                             jwe->jws.map.len[LJWE_CTXT],
                             (uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
                             (uint8_t *)jwe->jws.map.buf[LJWE_IV], NULL, NULL, 16);
+
+       /* Strip the PKCS #7 padding */
+
+       if (jwe->jws.map.len[LJWE_CTXT] < LWS_AES_CBC_BLOCKLEN ||
+           jwe->jws.map.len[LJWE_CTXT] <= (unsigned char)jwe->jws.map.buf[LJWE_CTXT]
+                                               [jwe->jws.map.len[LJWE_CTXT] - 1]) {
+               lwsl_err("%s: invalid padded ciphertext length: %d. Corrupt data?\n",
+                               __func__, jwe->jws.map.len[LJWE_CTXT]);
+               return -1;
+       }
+       jwe->jws.map.len[LJWE_CTXT] = (uint32_t)((int)jwe->jws.map.len[LJWE_CTXT] -
+               jwe->jws.map.buf[LJWE_CTXT][jwe->jws.map.len[LJWE_CTXT] - 1]);
+
        n |= lws_genaes_destroy(&aesctx, NULL, 0);
        if (n) {
                lwsl_err("%s: lws_genaes_crypt failed\n", __func__);
                return -1;
        }
 
-       return jwe->jws.map.len[LJWE_CTXT];
+       return (int)jwe->jws.map.len[LJWE_CTXT];
 }
 
index 4e93878..ef822ad 100644 (file)
@@ -1,29 +1,29 @@
 /*
- * libwebsockets - JSON Web Encryption support
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *
- * JWE code related to aes gcm
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
-#include "core/private.h"
-#include "jose/jwe/private.h"
+
+#include "private-lib-core.h"
+#include "private-lib-jose-jwe.h"
 
 /*
  * NOTICE this is AESGCM content encryption, it's not AES GCM key wrapping
@@ -86,7 +86,7 @@ lws_jwe_encrypt_gcm(struct lws_jwe *jwe,
 
        /* aad */
 
-       n = lws_genaes_crypt(&aesctx, aad, aad_len, NULL,
+       n = lws_genaes_crypt(&aesctx, aad, (unsigned int)aad_len, NULL,
                             (uint8_t *)jwe->jws.map.buf[LJWE_IV],
                             (uint8_t *)jwe->jws.map.buf[LJWE_ATAG], &ivs,
                             LWS_AESGCM_TAG);
@@ -110,7 +110,7 @@ lws_jwe_encrypt_gcm(struct lws_jwe *jwe,
                return -1;
        }
 
-       return jwe->jws.map.len[LJWE_CTXT];
+       return (int)jwe->jws.map.len[LJWE_CTXT];
 }
 
 int
@@ -149,7 +149,7 @@ lws_jwe_auth_and_decrypt_gcm(struct lws_jwe *jwe,
                return -1;
        }
 
-       n = lws_genaes_crypt(&aesctx, aad, aad_len,
+       n = lws_genaes_crypt(&aesctx, aad, (unsigned int)aad_len,
                             NULL,
                             (uint8_t *)jwe->jws.map.buf[LJWE_IV],
                             (uint8_t *)jwe->jws.map.buf[LJWE_ATAG], &ivs, 16);
@@ -169,5 +169,5 @@ lws_jwe_auth_and_decrypt_gcm(struct lws_jwe *jwe,
                return -1;
        }
 
-       return jwe->jws.map.len[LJWE_CTXT];
+       return (int)jwe->jws.map.len[LJWE_CTXT];
 }
index 7d0b5a7..7d5ae0a 100644 (file)
@@ -1,30 +1,29 @@
 /*
- * libwebsockets - JSON Web Encryption support
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *
- * JWE code related to aeskw cbc
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
-#include "core/private.h"
-#include "jose/jwe/private.h"
 
+#include "private-lib-core.h"
+#include "private-lib-jose-jwe.h"
 
 /*
  * RFC3394 Key Wrap uses a 128-bit key, and bloats what it is wrapping by
@@ -42,7 +41,7 @@ lws_jwe_encrypt_aeskw_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
        /* we are wrapping a key, so size for the worst case after wrap */
        uint8_t enc_cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES +
                        LWS_JWE_RFC3394_OVERHEAD_BYTES];
-       int n, m, hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
+       int n, m, hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
                         ot = *temp_len;
 
        if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_OCT) {
@@ -54,7 +53,7 @@ lws_jwe_encrypt_aeskw_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
        /* create a b64 version of the JOSE header, needed for hashing */
 
        if (lws_jws_encode_b64_element(&jwe->jws.map_b64, LJWE_JOSE,
-                                      temp + (ot - *temp_len), temp_len,
+                                      temp, temp_len,
                                       jwe->jws.map.buf[LJWE_JOSE],
                                       jwe->jws.map.len[LJWE_JOSE]))
                return -1;
@@ -62,7 +61,7 @@ lws_jwe_encrypt_aeskw_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
        /* Allocate temp space for ATAG and IV */
 
        if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG, temp + (ot - *temp_len),
-                                 temp_len, hlen / 2, 0))
+                                 temp_len, (unsigned int)hlen / 2, 0))
                return -1;
 
        if (lws_jws_alloc_element(&jwe->jws.map, LJWE_IV, temp + (ot - *temp_len),
@@ -75,7 +74,7 @@ lws_jwe_encrypt_aeskw_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
 
        n = lws_jwe_encrypt_cbc_hs(jwe, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
                                   (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
-                                  jwe->jws.map_b64.len[LJWE_JOSE]);
+                                  (int)jwe->jws.map_b64.len[LJWE_JOSE]);
        if (n < 0) {
                lwsl_err("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__);
                return -1;
@@ -111,7 +110,7 @@ lws_jwe_encrypt_aeskw_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
        memcpy((uint8_t *)jwe->jws.map.buf[LJWE_EKEY], enc_cek,
               jwe->jws.map.len[LJWE_EKEY]);
 
-       return jwe->jws.map.len[LJWE_CTXT];
+       return (int)jwe->jws.map.len[LJWE_CTXT];
 }
 
 
@@ -165,14 +164,14 @@ lws_jwe_auth_and_decrypt_aeskw_cbc_hs(struct lws_jwe *jwe)
 
        n = lws_jwe_auth_and_decrypt_cbc_hs(jwe, enc_cek,
                             (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
-                            jwe->jws.map_b64.len[LJWE_JOSE]);
+                            (int)jwe->jws.map_b64.len[LJWE_JOSE]);
        if (n < 0) {
                lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs failed\n",
                                __func__);
                return -1;
        }
 
-       return jwe->jws.map.len[LJWE_CTXT];
+       return (int)jwe->jws.map.len[LJWE_CTXT];
 }
 
 
index 4be1a56..07c8c34 100644 (file)
@@ -1,29 +1,29 @@
 /*
- * libwebsockets - JSON Web Encryption support
- *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *
- * JWE code related to ecdh-es + Concat KDF and aes kw
- *
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
-#include "core/private.h"
-#include "jose/jwe/private.h"
+
+#include "private-lib-core.h"
+#include "private-lib-jose-jwe.h"
 
 /*
  * From RFC7518 JWA
@@ -203,7 +203,7 @@ lws_jwe_encrypt_ecdh(struct lws_jwe *jwe, char *temp, int *temp_len,
                derived[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
        int m, n, ret = -1, ot = *temp_len, ss_len = sizeof(shared_secret),
          //  kw_hlen = lws_genhash_size(jwe->jose.alg->hash_type),
-           enc_hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
+           enc_hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
            ekbytes = 32; //jwe->jose.alg->keybits_fixed / 8;
        struct lws_genec_ctx ecctx;
        struct lws_jwk *ephem = &jwe->jose.recipient[jwe->recip].jwk_ephemeral;
@@ -293,7 +293,8 @@ lws_jwe_encrypt_ecdh(struct lws_jwe *jwe, char *temp, int *temp_len,
 
                /* generate the actual CEK in cek */
 
-               if (lws_get_random(jwe->jws.context, cek, enc_hlen) != enc_hlen) {
+               if (lws_get_random(jwe->jws.context, cek, (unsigned int)enc_hlen) !=
+                                                       (size_t)enc_hlen) {
                        lwsl_err("Problem getting random\n");
                        goto bail;
                }
@@ -301,7 +302,7 @@ lws_jwe_encrypt_ecdh(struct lws_jwe *jwe, char *temp, int *temp_len,
                /* wrap with the derived key */
 
                el.buf = derived;
-               el.len = enc_hlen / 2;
+               el.len = (unsigned int)enc_hlen / 2;
 
                if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_KW, &el,
                                        1, NULL)) {
@@ -312,7 +313,7 @@ lws_jwe_encrypt_ecdh(struct lws_jwe *jwe, char *temp, int *temp_len,
 
                /* wrap CEK into EKEY */
 
-               n = lws_genaes_crypt(&aesctx, cek, enc_hlen,
+               n = lws_genaes_crypt(&aesctx, cek, (unsigned int)enc_hlen,
                                     (void *)jwe->jws.map.buf[LJWE_EKEY],
                                     NULL, NULL, NULL, 0);
                m = lws_genaes_destroy(&aesctx, NULL, 0);
@@ -325,18 +326,18 @@ lws_jwe_encrypt_ecdh(struct lws_jwe *jwe, char *temp, int *temp_len,
                        goto bail;
                }
 
-               jwe->jws.map.len[LJWE_EKEY] = enc_hlen + 8;
+               jwe->jws.map.len[LJWE_EKEY] = (unsigned int)enc_hlen + 8;
 
                /* Wrapped CEK is in EKEY. Random CEK is in cek. */
 
        } else /* direct derived CEK is in cek */
-               memcpy(cek, derived, enc_hlen);
+               memcpy(cek, derived, (unsigned int)enc_hlen);
 
        /* rewrite the protected JOSE header to have the epk pieces */
 
-       jwe->jws.map.buf[LJWE_JOSE] = temp + (ot - *temp_len);
+       jwe->jws.map.buf[LJWE_JOSE] = temp;
 
-       m = n = lws_snprintf(temp + (ot - *temp_len), *temp_len,
+       m = n = lws_snprintf(temp, (size_t)*temp_len,
                             "{\"alg\":\"%s\", \"enc\":\"%s\", \"epk\":",
                             jwe->jose.alg->alg, jwe->jose.enc_alg->alg);
        *temp_len -= n;
@@ -348,10 +349,10 @@ lws_jwe_encrypt_ecdh(struct lws_jwe *jwe, char *temp, int *temp_len,
        }
        m += n;
 
-       n = lws_snprintf(temp + (ot - *temp_len), *temp_len, "}");
+       n = lws_snprintf(temp + (ot - *temp_len), (size_t)*temp_len, "}");
        *temp_len -= n + 1;
        m += n;
-       jwe->jws.map.len[LJWE_JOSE] = m;
+       jwe->jws.map.len[LJWE_JOSE] = (unsigned int)m;
 
        /* create a b64 version of the JOSE header, needed later for AAD */
 
@@ -367,8 +368,8 @@ bail:
        lws_genec_destroy(&ecctx);
 
        /* cleanse the shared secret (watch out for cek at parent too) */
-       lws_explicit_bzero(shared_secret, ekbytes);
-       lws_explicit_bzero(derived, ekbytes);
+       lws_explicit_bzero(shared_secret, (unsigned int)ekbytes);
+       lws_explicit_bzero(derived, (unsigned int)ekbytes);
 
        return ret;
 }
@@ -377,7 +378,7 @@ int
 lws_jwe_encrypt_ecdh_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
 {
        int ss_len, // kw_hlen = lws_genhash_size(jwe->jose.alg->hash_type),
-           enc_hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
+           enc_hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
        uint8_t cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
        int ekbytes = jwe->jose.alg->keybits_fixed / 8;
        int n, ot = *temp_len, ret = -1;
@@ -387,7 +388,7 @@ lws_jwe_encrypt_ecdh_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
        if (jwe->jose.alg->algtype_crypto != LWS_JOSE_ENCTYPE_NONE) {
                if (lws_jws_alloc_element(&jwe->jws.map, LJWE_EKEY,
                                          temp + (ot - *temp_len), temp_len,
-                                         enc_hlen + 8, 0))
+                                         (unsigned int)enc_hlen + 8, 0))
                        goto bail;
        }
 
@@ -405,7 +406,7 @@ lws_jwe_encrypt_ecdh_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
 
        if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG,
                                  temp + (ot - *temp_len),
-                                 temp_len, enc_hlen / 2, 0))
+                                 temp_len, (unsigned int)enc_hlen / 2, 0))
                goto bail;
 
        if (lws_jws_alloc_element(&jwe->jws.map, LJWE_IV,
@@ -418,7 +419,7 @@ lws_jwe_encrypt_ecdh_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
 
        n = lws_jwe_encrypt_cbc_hs(jwe, cek,
                                   (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
-                                  jwe->jws.map_b64.len[LJWE_JOSE]);
+                                  (int)jwe->jws.map_b64.len[LJWE_JOSE]);
        if (n < 0) {
                lwsl_notice("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__);
                goto bail;
@@ -435,7 +436,7 @@ bail:
                jwe->jws.map.len[LJWE_EKEY] = 0;
        }
 
-       lws_explicit_bzero(cek, ekbytes);
+       lws_explicit_bzero(cek, (unsigned int)ekbytes);
 
        return ret;
 }
@@ -454,7 +455,7 @@ lws_jwe_auth_and_decrypt_ecdh(struct lws_jwe *jwe)
        uint8_t shared_secret[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES],
                derived[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
        int ekbytes = jwe->jose.enc_alg->keybits_fixed / 8,
-                     enc_hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
+                     enc_hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
        struct lws_genec_ctx ecctx;
        int n, ret = -1, ss_len = sizeof(shared_secret);
 
@@ -550,7 +551,7 @@ lws_jwe_auth_and_decrypt_ecdh(struct lws_jwe *jwe)
                /* unwrap with the KEK we derived */
 
                el.buf = derived;
-               el.len = enc_hlen / 2;
+               el.len = (unsigned int)enc_hlen / 2;
 
                if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_KW,
                                      &el, 1, NULL)) {
@@ -576,13 +577,13 @@ lws_jwe_auth_and_decrypt_ecdh(struct lws_jwe *jwe)
                        goto bail;
                }
        } else
-               memcpy(shared_secret, derived, enc_hlen);
+               memcpy(shared_secret, derived, (unsigned int)enc_hlen);
 
        /* either way, the recovered CEK is in shared_secret */
 
        if (lws_jwe_auth_and_decrypt_cbc_hs(jwe, shared_secret,
                        (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
-                       jwe->jws.map_b64.len[LJWE_JOSE]) < 0) {
+                       (int)jwe->jws.map_b64.len[LJWE_JOSE]) < 0) {
                lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs fail\n", __func__);
                goto bail;
        }
@@ -592,9 +593,9 @@ lws_jwe_auth_and_decrypt_ecdh(struct lws_jwe *jwe)
 
 bail:
        /* cleanse wrapped on stack that contained the CEK / wrapped key */
-       lws_explicit_bzero(derived, ekbytes);
+       lws_explicit_bzero(derived, (unsigned int)ekbytes);
        /* cleanse the shared secret */
-       lws_explicit_bzero(shared_secret, ekbytes);
+       lws_explicit_bzero(shared_secret, (unsigned int)ekbytes);
 
        return ret;
 }
index 7f2f21e..21e4e50 100644 (file)
@@ -1,29 +1,29 @@
 /*
- * libwebsockets - JSON Web Encryption support
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *
- * JWE code related to rsa + aescbc
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
-#include "core/private.h"
-#include "jose/jwe/private.h"
+
+#include "private-lib-core.h"
+#include "private-lib-jose-jwe.h"
 
 /*
  * Requirements on entry:
@@ -46,7 +46,8 @@ int
 lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe,
                               char *temp, int *temp_len)
 {
-       int n, hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type), ot = *temp_len;
+       int n, hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
+           ot = *temp_len;
        char ekey[LWS_GENHASH_LARGEST];
        struct lws_genrsa_ctx rsactx;
 
@@ -63,13 +64,13 @@ lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe,
         * Create a b64 version of the JOSE header, needed as aad
         */
        if (lws_jws_encode_b64_element(&jwe->jws.map_b64, LJWE_JOSE,
-                                      temp + (ot - *temp_len), temp_len,
+                                      temp, temp_len,
                                       jwe->jws.map.buf[LJWE_JOSE],
                                       jwe->jws.map.len[LJWE_JOSE]))
                return -1;
 
        if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG, temp + (ot - *temp_len),
-                                 temp_len, hlen / 2, 0))
+                                 temp_len, (unsigned int)hlen / 2, 0))
                return -1;
 
        if (lws_jws_alloc_element(&jwe->jws.map, LJWE_IV, temp + (ot - *temp_len),
@@ -90,7 +91,7 @@ lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe,
 
        n = lws_jwe_encrypt_cbc_hs(jwe, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
                                     (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
-                                    jwe->jws.map_b64.len[LJWE_JOSE]);
+                                    (int)jwe->jws.map_b64.len[LJWE_JOSE]);
        if (n < 0) {
                lwsl_err("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__);
                return -1;
@@ -108,17 +109,17 @@ lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe,
        /* encrypt the CEK using RSA, mbedtls can't handle both in and out are
         * the EKEY, so copy the unencrypted ekey out temporarily */
 
-       memcpy(ekey, jwe->jws.map.buf[LJWE_EKEY], hlen);
+       memcpy(ekey, jwe->jws.map.buf[LJWE_EKEY], (unsigned int)hlen);
 
-       n = lws_genrsa_public_encrypt(&rsactx, (uint8_t *)ekey, hlen,
+       n = lws_genrsa_public_encrypt(&rsactx, (uint8_t *)ekey, (unsigned int)hlen,
                                      (uint8_t *)jwe->jws.map.buf[LJWE_EKEY]);
        lws_genrsa_destroy(&rsactx);
-       lws_explicit_bzero(ekey, hlen); /* cleanse the temp CEK copy */
+       lws_explicit_bzero(ekey, (unsigned int)hlen); /* cleanse the temp CEK copy */
        if (n < 0) {
                lwsl_err("%s: encrypt cek fail\n", __func__);
                return -1;
        }
-       jwe->jws.map.len[LJWE_EKEY] = n; /* update to encrypted EKEY size */
+       jwe->jws.map.len[LJWE_EKEY] = (unsigned int)n; /* update to encrypted EKEY size */
 
        /*
         * We end up with IV, ATAG, set, EKEY encrypted and CTXT is ciphertext,
@@ -171,7 +172,7 @@ lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe)
 
        n = lws_jwe_auth_and_decrypt_cbc_hs(jwe, enc_cek,
                             (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
-                            jwe->jws.map_b64.len[LJWE_JOSE]);
+                            (int)jwe->jws.map_b64.len[LJWE_JOSE]);
        if (n < 0) {
                lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs failed\n",
                         __func__);
@@ -191,5 +192,5 @@ lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe)
        jwe->jws.map.len[LJWE_CTXT] -= n;
 #endif
 
-       return jwe->jws.map.len[LJWE_CTXT];
+       return (int)jwe->jws.map.len[LJWE_CTXT];
 }
index 42eb0b2..b75c674 100644 (file)
@@ -1,29 +1,29 @@
 /*
- * libwebsockets - JSON Web Encryption support
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *
- * JWE code related to aes gcm
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
-#include "core/private.h"
-#include "jose/jwe/private.h"
+
+#include "private-lib-core.h"
+#include "private-lib-jose-jwe.h"
 
 #define LWS_AESGCM_IV 12
 
@@ -44,7 +44,7 @@ lws_jwe_encrypt_rsa_aes_gcm(struct lws_jwe *jwe, char *temp, int *temp_len)
        /* create the IV + CEK */
 
        if (lws_jws_randomize_element(jwe->jws.context, &jwe->jws.map, LJWE_IV,
-                                     temp + (ot - *temp_len), temp_len,
+                                     temp, temp_len,
                                      LWS_AESGCM_IV, 0))
                return -1;
 
@@ -67,8 +67,8 @@ lws_jwe_encrypt_rsa_aes_gcm(struct lws_jwe *jwe, char *temp, int *temp_len)
         * just reuse it.  It will be cleansed in the JWE destroy.
         */
        if (!jwe->cek_valid) {
-               if (lws_get_random(jwe->jws.context, jwe->cek, ekbytes) !=
-                                                              ekbytes) {
+               if (lws_get_random(jwe->jws.context, jwe->cek, (unsigned int)ekbytes) !=
+                                                             (size_t)ekbytes) {
                        lwsl_err("%s: Problem getting random\n", __func__);
                        return -1;
                }
@@ -77,14 +77,14 @@ lws_jwe_encrypt_rsa_aes_gcm(struct lws_jwe *jwe, char *temp, int *temp_len)
 
        if (lws_jws_dup_element(&jwe->jws.map, LJWE_EKEY,
                                temp + (ot - *temp_len), temp_len,
-                               jwe->cek, ekbytes, 0))
+                               jwe->cek, (unsigned int)ekbytes, 0))
                return -1;
 
        /* encrypt the payload */
 
        n = lws_jwe_encrypt_gcm(jwe, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
                                (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
-                               jwe->jws.map_b64.len[LJWE_JOSE]);
+                               (int)jwe->jws.map_b64.len[LJWE_JOSE]);
        if (n < 0) {
                lwsl_err("%s: lws_jwe_encrypt_gcm failed\n",
                         __func__);
@@ -102,7 +102,7 @@ lws_jwe_encrypt_rsa_aes_gcm(struct lws_jwe *jwe, char *temp, int *temp_len)
                goto bail;
        }
 
-       n = lws_genrsa_public_encrypt(&rsactx, jwe->cek, ekbytes,
+       n = lws_genrsa_public_encrypt(&rsactx, jwe->cek, (unsigned int)ekbytes,
                                      (uint8_t *)jwe->jws.map.buf[LJWE_EKEY]);
        lws_genrsa_destroy(&rsactx);
        if (n < 0) {
@@ -111,9 +111,9 @@ lws_jwe_encrypt_rsa_aes_gcm(struct lws_jwe *jwe, char *temp, int *temp_len)
        }
 
        /* set the EKEY length to the actual enciphered length */
-       jwe->jws.map.len[LJWE_EKEY] = n;
+       jwe->jws.map.len[LJWE_EKEY] = (unsigned int)n;
 
-       ret = jwe->jws.map.len[LJWE_CTXT];
+       ret = (int32_t)jwe->jws.map.len[LJWE_CTXT];
 
 bail:
 
@@ -163,7 +163,7 @@ lws_jwe_auth_and_decrypt_rsa_aes_gcm(struct lws_jwe *jwe)
 
        n = lws_jwe_auth_and_decrypt_gcm(jwe, enc_cek,
                        (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
-                               jwe->jws.map_b64.len[LJWE_JOSE]);
+                               (int)jwe->jws.map_b64.len[LJWE_JOSE]);
        if (n < 0) {
                lwsl_err("%s: lws_jwe_auth_and_decrypt_gcm_hs failed\n",
                         __func__);
@@ -179,5 +179,5 @@ lws_jwe_auth_and_decrypt_rsa_aes_gcm(struct lws_jwe *jwe)
        jwe->jws.map.len[LJWE_CTXT] -= n;
 #endif
 
-       return jwe->jws.map.len[LJWE_CTXT];
+       return (int)jwe->jws.map.len[LJWE_CTXT];
 }
old mode 100644 (file)
new mode 100755 (executable)
index bb8446e..d000e13
@@ -1,30 +1,30 @@
 /*
- * libwebsockets - JSON Web Encryption support
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *
- * This supports RFC7516 JSON Web Encryption
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
-#include "core/private.h"
-#include "jose/private.h"
-#include "jose/jwe/private.h"
+
+#include "private-lib-core.h"
+#include "private-lib-jose.h"
+#include "private-lib-jose-jwe.h"
 
 /*
  * Currently only support flattened or compact (implicitly single signature)
@@ -118,7 +118,7 @@ append_string:
 
                n = lws_b64_decode_string_len(
                        (const char *)args->jws->map_b64.buf[m],
-                       args->jws->map_b64.len[m],
+                       (int)args->jws->map_b64.len[m],
                        (char *)args->temp, *args->temp_len);
                if (n < 0) {
                        lwsl_err("%s: b64 decode failed\n", __func__);
@@ -127,7 +127,7 @@ append_string:
 
                args->temp += n;
                *args->temp_len -= n;
-               args->jws->map.len[m] = n;
+               args->jws->map.len[m] = (uint32_t)n;
        }
 
        return 0;
@@ -148,7 +148,7 @@ lws_jwe_json_parse(struct lws_jwe *jwe, const uint8_t *buf, int len,
        lejp_construct(&jctx, lws_jwe_json_cb, &args, jwe_json,
                       LWS_ARRAY_SIZE(jwe_json));
 
-       m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)buf, len);
+       m = lejp_parse(&jctx, (uint8_t *)buf, len);
        lejp_destruct(&jctx);
        if (m < 0) {
                lwsl_notice("%s: parse returned %d\n", __func__, m);
@@ -184,10 +184,10 @@ be32(uint32_t i, uint32_t *p32)
 {
        uint8_t *p = (uint8_t *)p32;
 
-       *p++ = (i >> 24) & 0xff;
-       *p++ = (i >> 16) & 0xff;
-       *p++ = (i >> 8) & 0xff;
-       *p++ = i & 0xff;
+       *p++ = (uint8_t)((i >> 24) & 0xff);
+       *p++ = (uint8_t)((i >> 16) & 0xff);
+       *p++ = (uint8_t)((i >> 8) & 0xff);
+       *p++ = (uint8_t)(i & 0xff);
 
        return (uint8_t *)p32;
 }
@@ -209,7 +209,7 @@ int
 lws_jwa_concat_kdf(struct lws_jwe *jwe, int direct, uint8_t *out,
                   const uint8_t *shared_secret, int sslen)
 {
-       int hlen = lws_genhash_size(LWS_GENHASH_TYPE_SHA256), aidlen;
+       int hlen = (int)lws_genhash_size(LWS_GENHASH_TYPE_SHA256), aidlen;
        struct lws_genhash_ctx hash_ctx;
        uint32_t ctr = 1, t;
        const char *aid;
@@ -236,7 +236,7 @@ lws_jwa_concat_kdf(struct lws_jwe *jwe, int direct, uint8_t *out,
         */
 
        aid = direct ? jwe->jose.enc_alg->alg : jwe->jose.alg->alg;
-       aidlen = strlen(aid);
+       aidlen = (int)strlen(aid);
 
        /*
         *   PartyUInfo (PartyVInfo is the same deal)
@@ -282,10 +282,10 @@ lws_jwa_concat_kdf(struct lws_jwe *jwe, int direct, uint8_t *out,
                if (/* counter */
                    lws_genhash_update(&hash_ctx, be32(ctr++, &t), 4) ||
                    /* Z */
-                   lws_genhash_update(&hash_ctx, shared_secret, sslen) ||
+                   lws_genhash_update(&hash_ctx, shared_secret, (unsigned int)sslen) ||
                    /* other info */
-                   lws_genhash_update(&hash_ctx, be32(strlen(aid), &t), 4) ||
-                   lws_genhash_update(&hash_ctx, aid, aidlen) ||
+                   lws_genhash_update(&hash_ctx, be32((uint32_t)strlen(aid), &t), 4) ||
+                   lws_genhash_update(&hash_ctx, aid, (unsigned int)aidlen) ||
                    lws_genhash_update(&hash_ctx,
                                       be32(jwe->jose.e[LJJHI_APU].len, &t), 4) ||
                    lws_genhash_update(&hash_ctx, jwe->jose.e[LJJHI_APU].buf,
@@ -310,7 +310,7 @@ lws_jwa_concat_kdf(struct lws_jwe *jwe, int direct, uint8_t *out,
        return 0;
 }
 
-LWS_VISIBLE void
+void
 lws_jwe_be64(uint64_t c, uint8_t *p8)
 {
        int n;
@@ -319,24 +319,25 @@ lws_jwe_be64(uint64_t c, uint8_t *p8)
                *p8++ = (uint8_t)((c >> n) & 0xff);
 }
 
-LWS_VISIBLE int
+int
 lws_jwe_auth_and_decrypt(struct lws_jwe *jwe, char *temp, int *temp_len)
 {
        int valid_aescbc_hmac, valid_aesgcm;
+       char dotstar[96];
 
        if (lws_jwe_parse_jose(&jwe->jose, jwe->jws.map.buf[LJWS_JOSE],
-                              jwe->jws.map.len[LJWS_JOSE],
+                              (int)jwe->jws.map.len[LJWS_JOSE],
                               temp, temp_len) < 0) {
-               lwsl_err("%s: JOSE parse '%.*s' failed\n", __func__,
-                               jwe->jws.map.len[LJWS_JOSE],
-                               jwe->jws.map.buf[LJWS_JOSE]);
+               lws_strnncpy(dotstar, jwe->jws.map.buf[LJWS_JOSE],
+                            jwe->jws.map.len[LJWS_JOSE], sizeof(dotstar));
+               lwsl_err("%s: JOSE parse '%s' failed\n", __func__, dotstar);
                return -1;
        }
 
        if (!jwe->jose.alg) {
-               lwsl_err("%s: no jose.alg: %.*s\n", __func__,
-                               jwe->jws.map.len[LJWS_JOSE],
-                               jwe->jws.map.buf[LJWS_JOSE]);
+               lws_strnncpy(dotstar, jwe->jws.map.buf[LJWS_JOSE],
+                            jwe->jws.map.len[LJWS_JOSE], sizeof(dotstar));
+               lwsl_err("%s: no jose.alg: %s\n", __func__, dotstar);
 
                return -1;
        }
@@ -379,7 +380,7 @@ lws_jwe_auth_and_decrypt(struct lws_jwe *jwe, char *temp, int *temp_len)
 
        return -1;
 }
-LWS_VISIBLE int
+int
 lws_jwe_encrypt(struct lws_jwe *jwe, char *temp, int *temp_len)
 {
        int valid_aescbc_hmac, valid_aesgcm, ot = *temp_len, ret = -1;
@@ -394,7 +395,7 @@ lws_jwe_encrypt(struct lws_jwe *jwe, char *temp, int *temp_len)
                jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_GCM;
 
        if (lws_jwe_parse_jose(&jwe->jose, jwe->jws.map.buf[LJWS_JOSE],
-                              jwe->jws.map.len[LJWS_JOSE], temp, temp_len) < 0) {
+                              (int)jwe->jws.map.len[LJWS_JOSE], temp, temp_len) < 0) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
                goto bail;
        }
@@ -473,7 +474,7 @@ bail:
  *  - You can't emit Compact representation if there are multiple recipients
  */
 
-LWS_VISIBLE int
+int
 lws_jwe_render_compact(struct lws_jwe *jwe, char *out, size_t out_len)
 {
        size_t orig = out_len;
@@ -491,59 +492,59 @@ lws_jwe_render_compact(struct lws_jwe *jwe, char *out, size_t out_len)
                               jwe->jws.map.len[LJWS_JOSE], out, out_len);
        if (n < 0 || (int)out_len == n) {
                lwsl_info("%s: unable to encode JOSE\n", __func__);
-               return n;
+               return -1;
        }
 
        out += n;
        *out++ = '.';
-       out_len -= n + 1;
+       out_len -= (unsigned int)n + 1;
 
        n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_EKEY],
                               jwe->jws.map.len[LJWE_EKEY], out, out_len);
        if (n < 0 || (int)out_len == n) {
                lwsl_info("%s: unable to encode EKEY\n", __func__);
-               return n;
+               return -1;
        }
 
        out += n;
        *out++ = '.';
-       out_len -= n + 1;
+       out_len -= (unsigned int)n + 1;
        n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_IV],
                               jwe->jws.map.len[LJWE_IV], out, out_len);
        if (n < 0 || (int)out_len == n) {
                lwsl_info("%s: unable to encode IV\n", __func__);
-               return n;
+               return -1;
        }
 
        out += n;
        *out++ = '.';
-       out_len -= n + 1;
+       out_len -= (unsigned int)n + 1;
 
        n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_CTXT],
                               jwe->jws.map.len[LJWE_CTXT], out, out_len);
        if (n < 0 || (int)out_len == n) {
                lwsl_info("%s: unable to encode CTXT\n", __func__);
-               return n;
+               return -1;
        }
 
        out += n;
        *out++ = '.';
-       out_len -= n + 1;
+       out_len -= (unsigned int)n + 1;
        n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_ATAG],
                               jwe->jws.map.len[LJWE_ATAG], out, out_len);
        if (n < 0 || (int)out_len == n) {
                lwsl_info("%s: unable to encode ATAG\n", __func__);
-               return n;
+               return -1;
        }
 
        out += n;
        *out++ = '\0';
-       out_len -= n;
+       out_len -= (unsigned int)n;
 
-       return orig - out_len;
+       return (int)(orig - out_len);
 }
 
-LWS_VISIBLE int
+int
 lws_jwe_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,
                      const char *nonce, char *out, size_t out_len,
                      struct lws_context *context)
@@ -561,7 +562,7 @@ lws_jwe_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,
         * here temporarily.
         */
        n = LWS_PRE + 2048;
-       buf = malloc(n);
+       buf = malloc((unsigned int)n);
        if (!buf) {
                lwsl_notice("%s: malloc %d failed\n", __func__, n);
                return -1;
@@ -577,9 +578,9 @@ lws_jwe_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,
        if (!jwe->jose.alg || !jwe->jose.alg->alg)
                goto bail;
 
-       p += lws_snprintf(p, end - p, "{\"alg\":\"%s\",\"jwk\":",
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{\"alg\":\"%s\",\"jwk\":",
                          jwe->jose.alg->alg);
-       m = end - p;
+       m = lws_ptr_diff(end, p);
        n = lws_jwk_export(&jwe->jwk, 0, p, &m);
        if (n < 0) {
                lwsl_notice("failed to export jwk\n");
@@ -587,7 +588,7 @@ lws_jwe_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,
                goto bail;
        }
        p += n;
-       p += lws_snprintf(p, end - p, ",\"nonce\":\"%s\"}", nonce);
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ",\"nonce\":\"%s\"}", nonce);
 
        /*
         * prepare the signed outer JSON with all the parts in
@@ -596,57 +597,57 @@ lws_jwe_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,
        p1 = out;
        end1 = out + out_len - 1;
 
-       p1 += lws_snprintf(p1, end1 - p1, "{\"protected\":\"");
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "{\"protected\":\"");
        jws.map_b64.buf[LJWS_JOSE] = p1;
-       n = lws_jws_base64_enc(start, p - start, p1, end1 - p1);
+       n = lws_jws_base64_enc(start, lws_ptr_diff_size_t(p, start), p1, lws_ptr_diff_size_t(end1, p1));
        if (n < 0) {
                lwsl_notice("%s: failed to encode protected\n", __func__);
                goto bail;
        }
-       jws.map_b64.len[LJWS_JOSE] = n;
+       jws.map_b64.len[LJWS_JOSE] = (unsigned int)n;
        p1 += n;
 
-       p1 += lws_snprintf(p1, end1 - p1, "\",\"payload\":\"");
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\"payload\":\"");
        jws.map_b64.buf[LJWS_PYLD] = p1;
-       n = lws_jws_base64_enc(payload, len, p1, end1 - p1);
+       n = lws_jws_base64_enc(payload, len, p1, lws_ptr_diff_size_t(end1, p1));
        if (n < 0) {
                lwsl_notice("%s: failed to encode payload\n", __func__);
                goto bail;
        }
-       jws.map_b64.len[LJWS_PYLD] = n;
+       jws.map_b64.len[LJWS_PYLD] = (unsigned int)n;
        p1 += n;
 
-       p1 += lws_snprintf(p1, end1 - p1, "\",\"header\":\"");
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\"header\":\"");
        jws.map_b64.buf[LJWS_UHDR] = p1;
-       n = lws_jws_base64_enc(payload, len, p1, end1 - p1);
+       n = lws_jws_base64_enc(payload, len, p1, lws_ptr_diff_size_t(end1, p1));
        if (n < 0) {
                lwsl_notice("%s: failed to encode payload\n", __func__);
                goto bail;
        }
-       jws.map_b64.len[LJWS_UHDR] = n;
+       jws.map_b64.len[LJWS_UHDR] = (unsigned int)n;
 
        p1 += n;
-       p1 += lws_snprintf(p1, end1 - p1, "\",\"signature\":\"");
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\"signature\":\"");
 
        /*
         * taking the b64 protected header and the b64 payload, sign them
         * and place the signature into the packet
         */
-       n = lws_jws_sign_from_b64(&jwe->jose, &jws, p1, end1 - p1);
+       n = lws_jws_sign_from_b64(&jwe->jose, &jws, p1, lws_ptr_diff_size_t(end1, p1));
        if (n < 0) {
                lwsl_notice("sig gen failed\n");
 
                goto bail;
        }
        jws.map_b64.buf[LJWS_SIG] = p1;
-       jws.map_b64.len[LJWS_SIG] = n;
+       jws.map_b64.len[LJWS_SIG] = (unsigned int)n;
 
        p1 += n;
-       p1 += lws_snprintf(p1, end1 - p1, "\"}");
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\"}");
 
        free(buf);
 
-       return p1 - out;
+       return lws_ptr_diff(p1, out);
 
 bail:
        lws_jws_destroy(&jws);
@@ -717,7 +718,7 @@ static int protected_idx[] = {
  *     }
  */
 
-LWS_VISIBLE int
+int
 lws_jwe_render_flattened(struct lws_jwe *jwe, char *out, size_t out_len)
 {
        char buf[3072], *p1, *end1, protected[128];
@@ -745,28 +746,30 @@ lws_jwe_render_flattened(struct lws_jwe *jwe, char *out, size_t out_len)
                            "{\"alg\":\"%s\",\"enc\":\"%s\"}",
                            jwe->jose.alg->alg, jwe->jose.enc_alg->alg);
 
-       p1 += lws_snprintf(p1, end1 - p1, "{\"protected\":\"");
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "{\"protected\":\"");
        jwe->jws.map_b64.buf[LJWS_JOSE] = p1;
-       n = lws_jws_base64_enc(protected, plen, p1, end1 - p1);
+       n = lws_jws_base64_enc(protected, (size_t)plen, p1, lws_ptr_diff_size_t(end1, p1));
        if (n < 0) {
                lwsl_notice("%s: failed to encode protected\n", __func__);
                goto bail;
        }
-       jwe->jws.map_b64.len[LJWS_JOSE] = n;
+       jwe->jws.map_b64.len[LJWS_JOSE] = (unsigned int)n;
        p1 += n;
 
        /* unprotected not supported atm */
 
-       p1 += lws_snprintf(p1, end1 - p1, "\",\n\"header\":%.*s", jlen, buf);
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\n\"header\":");
+       lws_strnncpy(p1, buf, jlen, end1 - p1);
+       p1 += strlen(p1);
 
        for (m = 0; m < (int)LWS_ARRAY_SIZE(protected_en); m++)
                if (jwe->jws.map.buf[protected_idx[m]]) {
-                       p1 += lws_snprintf(p1, end1 - p1, ",\n\"%s\":\"",
+                       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), ",\n\"%s\":\"",
                                           protected_en[m]);
                        //jwe->jws.map_b64.buf[protected_idx[m]] = p1;
                        n = lws_jws_base64_enc(jwe->jws.map.buf[protected_idx[m]],
                                               jwe->jws.map.len[protected_idx[m]],
-                                              p1, end1 - p1);
+                                              p1, lws_ptr_diff_size_t(end1, p1));
                        if (n < 0) {
                                lwsl_notice("%s: failed to encode %s\n",
                                            __func__, protected_en[m]);
@@ -774,12 +777,12 @@ lws_jwe_render_flattened(struct lws_jwe *jwe, char *out, size_t out_len)
                        }
                        //jwe->jws.map_b64.len[protected_idx[m]] = n;
                        p1 += n;
-                       p1 += lws_snprintf(p1, end1 - p1, "\"");
+                       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\"");
                }
 
-       p1 += lws_snprintf(p1, end1 - p1, "\n}\n");
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\n}\n");
 
-       return p1 - out;
+       return lws_ptr_diff(p1, out);
 
 bail:
        lws_jws_destroy(&jwe->jws);
similarity index 52%
rename from lib/jose/jwe/private.h
rename to lib/jose/jwe/private-lib-jose-jwe.h
index f64a51f..7ee24da 100644 (file)
@@ -1,24 +1,27 @@
 /*
- * libwebsockets - JSON Web Encryption support
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
+
 #define LWS_AESGCM_IV 12
 #define LWS_AESGCM_TAG 16
 
diff --git a/lib/jose/jwk/jose_key.c b/lib/jose/jwk/jose_key.c
new file mode 100644 (file)
index 0000000..2d754d9
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * JOSE-specific JWK code
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-jose.h"
+
+#if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
+#include <fcntl.h>
+#endif
+
+static const char * const kty_names[] = {
+       "unknown",      /* LWS_GENCRYPTO_KTY_UNKNOWN */
+       "oct",          /* LWS_GENCRYPTO_KTY_OCT */
+       "RSA",          /* LWS_GENCRYPTO_KTY_RSA */
+       "EC"            /* LWS_GENCRYPTO_KTY_EC */
+};
+
+/*
+ * These are the entire legal token set for names in jwk.
+ *
+ * The first version is used to parse a detached single jwk that don't have any
+ * parent JSON context.  The second version is used to parse full jwk objects
+ * that has a "keys": [ ] array containing the keys.
+ */
+
+const char * const jwk_tok[] = {
+       "keys[]",                       /* dummy */
+       "e", "n", "d", "p", "q", "dp", "dq", "qi", /* RSA */
+       "kty",                          /* generic */
+       "k",                            /* symmetric key data */
+       "crv", "x", "y",                /* EC (also "D") */
+       "kid",                          /* generic */
+       "use"                           /* mutually exclusive with "key_ops" */,
+       "key_ops"                       /* mutually exclusive with "use" */,
+       "x5c",                          /* generic */
+       "alg"                           /* generic */
+}, * const jwk_outer_tok[] = {
+       "keys[]",
+       "keys[].e", "keys[].n", "keys[].d", "keys[].p", "keys[].q", "keys[].dp",
+       "keys[].dq", "keys[].qi",
+
+       "keys[].kty", "keys[].k",               /* generic */
+       "keys[].crv", "keys[].x", "keys[].y",   /* EC (also "D") */
+       "keys[].kid", "keys[].use"      /* mutually exclusive with "key_ops" */,
+       "keys[].key_ops",               /* mutually exclusive with "use" */
+       "keys[].x5c", "keys[].alg"
+};
+
+static unsigned short tok_map[] = {
+       F_RSA | F_EC | F_OCT | F_META |          0xff,
+       F_RSA |                         F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_E,
+       F_RSA |                         F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_N,
+       F_RSA | F_EC |                  F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_D,
+       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_P,
+       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_Q,
+       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_DP,
+       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_DQ,
+       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_QI,
+
+       F_RSA | F_EC | F_OCT | F_META |          F_M | JWK_META_KTY,
+                      F_OCT |          F_B64U | F_M | LWS_GENCRYPTO_OCT_KEYEL_K,
+
+               F_EC |                           F_M | LWS_GENCRYPTO_EC_KEYEL_CRV,
+               F_EC |                  F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_X,
+               F_EC |                  F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_Y,
+
+       F_RSA | F_EC | F_OCT | F_META |                JWK_META_KID,
+       F_RSA | F_EC | F_OCT | F_META |                JWK_META_USE,
+
+       F_RSA | F_EC | F_OCT | F_META |                JWK_META_KEY_OPS,
+       F_RSA | F_EC | F_OCT | F_META | F_B64 |        JWK_META_X5C,
+       F_RSA | F_EC | F_OCT | F_META |                JWK_META_ALG,
+};
+
+struct lexico {
+       const char *name;
+       int idx;
+       char meta;
+} lexico_ec[] =  {
+       { "alg",        JWK_META_ALG,                   1 },
+       { "crv",        LWS_GENCRYPTO_EC_KEYEL_CRV,     0 },
+       { "d",          LWS_GENCRYPTO_EC_KEYEL_D,       2 | 0 },
+       { "key_ops",    JWK_META_KEY_OPS,               1 },
+       { "kid",        JWK_META_KID,                   1 },
+       { "kty",        JWK_META_KTY,                   1 },
+       { "use",        JWK_META_USE,                   1 },
+       { "x",          LWS_GENCRYPTO_EC_KEYEL_X,       0 },
+       { "x5c",        JWK_META_X5C,                   1 },
+       { "y",          LWS_GENCRYPTO_EC_KEYEL_Y,       0 }
+}, lexico_oct[] =  {
+       { "alg",        JWK_META_ALG,                   1 },
+       { "k",          LWS_GENCRYPTO_OCT_KEYEL_K,      0 },
+       { "key_ops",    JWK_META_KEY_OPS,               1 },
+       { "kid",        JWK_META_KID,                   1 },
+       { "kty",        JWK_META_KTY,                   1 },
+       { "use",        JWK_META_USE,                   1 },
+       { "x5c",        JWK_META_X5C,                   1 }
+}, lexico_rsa[] =  {
+       { "alg",        JWK_META_ALG,                   1 },
+       { "d",          LWS_GENCRYPTO_RSA_KEYEL_D,      2 | 0 },
+       { "dp",         LWS_GENCRYPTO_RSA_KEYEL_DP,     2 | 0 },
+       { "dq",         LWS_GENCRYPTO_RSA_KEYEL_DQ,     2 | 0 },
+       { "e",          LWS_GENCRYPTO_RSA_KEYEL_E,      0 },
+       { "key_ops",    JWK_META_KEY_OPS,               1 },
+       { "kid",        JWK_META_KID,                   1 },
+       { "kty",        JWK_META_KTY,                   1 },
+       { "n",          LWS_GENCRYPTO_RSA_KEYEL_N,      0 },
+       { "p",          LWS_GENCRYPTO_RSA_KEYEL_P,      2 | 0 },
+       { "q",          LWS_GENCRYPTO_RSA_KEYEL_Q,      2 | 0 },
+       { "qi",         LWS_GENCRYPTO_RSA_KEYEL_QI,     2 | 0 },
+       { "use",        JWK_META_USE,                   1 },
+       { "x5c",        JWK_META_X5C,                   1 }
+};
+
+static int
+_lws_jwk_set_el_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len)
+{
+       size_t dec_size = (unsigned int)lws_base64_size(len);
+       int n;
+
+       e->buf = lws_malloc(dec_size, "jwk");
+       if (!e->buf)
+               return -1;
+
+       /* same decoder accepts both url or original styles */
+
+       n = lws_b64_decode_string_len(in, len, (char *)e->buf, (int)dec_size - 1);
+       if (n < 0)
+               return -1;
+       e->len = (uint32_t)n;
+
+       return 0;
+}
+
+static int
+_lws_jwk_set_el_jwk_b64u(struct lws_gencrypto_keyelem *e, char *in, int len)
+{
+       size_t dec_size = (size_t)lws_base64_size(len);
+       int n;
+
+       e->buf = lws_malloc(dec_size, "jwk");
+       if (!e->buf)
+               return -1;
+
+       /* same decoder accepts both url or original styles */
+
+       n = lws_b64_decode_string_len(in, len, (char *)e->buf, (int)dec_size - 1);
+       if (n < 0)
+               return -1;
+       e->len = (uint32_t)n;
+
+       return 0;
+}
+
+
+signed char
+cb_jwk(struct lejp_ctx *ctx, char reason)
+{
+       struct lws_jwk_parse_state *jps = (struct lws_jwk_parse_state *)ctx->user;
+       struct lws_jwk *jwk = jps->jwk;
+       unsigned int idx, n;
+       unsigned short poss;
+       char dotstar[64];
+
+       if (reason == LEJPCB_VAL_STR_START)
+               jps->pos = 0;
+
+       if (reason == LEJPCB_OBJECT_START && ctx->path_match == 0 + 1)
+               /*
+                * new keys[] member is starting
+                *
+                * Until we see some JSON names, it could be anything...
+                * there is no requirement for kty to be given first and eg,
+                * ACME specifies the keys must be ordered in lexographic
+                * order - where kty is not first.
+                */
+               jps->possible = F_RSA | F_EC | F_OCT;
+
+       if (reason == LEJPCB_OBJECT_END && ctx->path_match == 0 + 1) {
+               /* we completed parsing a key */
+               if (jps->per_key_cb && jps->possible) {
+                       if (jps->per_key_cb(jps->jwk, jps->user)) {
+
+                               lwsl_notice("%s: user cb halts import\n",
+                                           __func__);
+
+                               return -2;
+                       }
+
+                       /* clear it down */
+                       lws_jwk_destroy(jps->jwk);
+                       jps->possible = 0;
+               }
+       }
+
+       if (reason == LEJPCB_COMPLETE) {
+
+               /*
+                * Now we saw the whole jwk and know the key type, let'jwk insist
+                * that as a whole, it must be consistent and complete.
+                *
+                * The tracking of ->possible bits from even before we know the
+                * kty already makes certain we cannot have key element members
+                * defined that are inconsistent with the key type.
+                */
+
+               for (n = 0; n < LWS_ARRAY_SIZE(tok_map); n++)
+                       /*
+                        * All mandataory elements for the key type
+                        * must be present
+                        */
+                       if ((tok_map[n] & jps->possible) && (
+                           ((tok_map[n] & (F_M | F_META)) == (F_M | F_META) &&
+                            !jwk->meta[tok_map[n] & 0xff].buf) ||
+                           ((tok_map[n] & (F_M | F_META)) == F_M &&
+                            !jwk->e[tok_map[n] & 0xff].buf))) {
+                               lwsl_notice("%s: missing %s\n", __func__,
+                                           jwk_tok[n]);
+                                       return -3;
+                               }
+
+               /*
+                * When the key may be public or public + private, ensure the
+                * intra-key members related to that are consistent.
+                *
+                * Only RSA keys need extra care, since EC keys are already
+                * confirmed by making CRV, X and Y mandatory and only D
+                * (the singular private part) optional.  For RSA, N and E are
+                * also already known to be present using mandatory checking.
+                */
+
+               /*
+                * If a private key, it must have all D, P and Q.  Public key
+                * must have none of them.
+                */
+               if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
+                   !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) &&
+                     (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) &&
+                     (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) ||
+                     (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
+                      jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf &&
+                      jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf))
+                     ) {
+                       lwsl_notice("%s: RSA requires D, P and Q for private\n",
+                                   __func__);
+                       return -3;
+               }
+
+               /*
+                * If the precomputed private key terms appear, they must all
+                * appear together.
+                */
+               if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
+                   !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf) &&
+                     (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) &&
+                     (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf)) ||
+                     (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf &&
+                      jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf &&
+                      jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf))
+                     ) {
+                       lwsl_notice("%s: RSA DP, DQ, QI must all appear "
+                                   "or none\n", __func__);
+                       return -3;
+               }
+
+               /*
+                * The precomputed private key terms must not appear without
+                * the private key itself also appearing.
+                */
+               if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
+                   !jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
+                    jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) {
+                       lwsl_notice("%s: RSA DP, DQ, QI can appear only with "
+                                   "private key\n", __func__);
+                       return -3;
+               }
+
+               if ((jwk->kty == LWS_GENCRYPTO_KTY_RSA ||
+                    jwk->kty == LWS_GENCRYPTO_KTY_EC) &&
+                   jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf)
+               jwk->private_key = 1;
+       }
+
+       if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
+               return 0;
+
+       if (ctx->path_match == 0 + 1)
+               return 0;
+
+       idx = tok_map[ctx->path_match - 1];
+       if ((idx & 0xff) == 0xff)
+               return 0;
+
+       switch (idx) {
+       /* note: kty is not necessarily first... we have to keep track of
+        * what could match given which element names have already been
+        * seen.  Once kty comes, we confirm it'jwk still possible (ie, it'jwk
+        * not trying to tell us that it'jwk RSA now when we saw a "crv"
+        * earlier) and then reduce the possibilities to just the one that
+        * kty told. */
+       case F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY:
+
+               if (ctx->npos == 3 && !strncmp(ctx->buf, "oct", 3)) {
+                       if (!(jps->possible & F_OCT))
+                               goto elements_mismatch;
+                       jwk->kty = LWS_GENCRYPTO_KTY_OCT;
+                       jps->possible = F_OCT;
+                       goto cont;
+               }
+               if (ctx->npos == 3 && !strncmp(ctx->buf, "RSA", 3)) {
+                       if (!(jps->possible & F_RSA))
+                               goto elements_mismatch;
+                       jwk->kty = LWS_GENCRYPTO_KTY_RSA;
+                       jps->possible = F_RSA;
+                       goto cont;
+               }
+               if (ctx->npos == 2 && !strncmp(ctx->buf, "EC", 2)) {
+                       if (!(jps->possible & F_EC))
+                               goto elements_mismatch;
+                       jwk->kty = LWS_GENCRYPTO_KTY_EC;
+                       jps->possible = F_EC;
+                       goto cont;
+               }
+               lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
+               lwsl_err("%s: Unknown KTY '%s'\n", __func__, dotstar);
+               return -1;
+
+       default:
+cont:
+               if (jps->pos + ctx->npos >= (int)sizeof(jps->b64))
+                       goto bail;
+
+               memcpy(jps->b64 + jps->pos, ctx->buf, ctx->npos);
+               jps->pos += ctx->npos;
+
+               if (reason == LEJPCB_VAL_STR_CHUNK)
+                       return 0;
+
+               /* chunking has been collated */
+
+               poss = idx & (F_RSA | F_EC | F_OCT);
+               jps->possible &= poss;
+               if (!jps->possible)
+                       goto elements_mismatch;
+
+               if (idx & F_META) {
+                       if (_lws_jwk_set_el_jwk(&jwk->meta[idx & 0x7f],
+                                               jps->b64, (unsigned int)jps->pos) < 0)
+                               goto bail;
+
+                       break;
+               }
+
+               if (idx & F_B64U) {
+                       /* key data... do the base64 decode as needed */
+                       if (_lws_jwk_set_el_jwk_b64u(&jwk->e[idx & 0x7f],
+                                                    jps->b64, jps->pos) < 0)
+                               goto bail;
+
+                       if (jwk->e[idx & 0x7f].len >
+                                       LWS_JWE_LIMIT_KEY_ELEMENT_BYTES) {
+                               lwsl_notice("%s: oversize keydata\n", __func__);
+                               goto bail;
+                       }
+
+                       return 0;
+               }
+
+               if (idx & F_B64) {
+
+                       /* cert data... do non-urlcoded base64 decode */
+                       if (_lws_jwk_set_el_jwk_b64(&jwk->e[idx & 0x7f],
+                                                   jps->b64, jps->pos) < 0)
+                               goto bail;
+                       return 0;
+               }
+
+                       if (_lws_jwk_set_el_jwk(&jwk->e[idx & 0x7f],
+                                               jps->b64, (unsigned int)jps->pos) < 0)
+                               goto bail;
+               break;
+       }
+
+       return 0;
+
+elements_mismatch:
+       lwsl_err("%s: jwk elements mismatch\n", __func__);
+
+bail:
+       lwsl_err("%s: element failed\n", __func__);
+
+       return -1;
+}
+
+int
+lws_jwk_import(struct lws_jwk *jwk, lws_jwk_key_import_callback cb, void *user,
+              const char *in, size_t len)
+{
+       struct lejp_ctx jctx;
+       struct lws_jwk_parse_state jps;
+       int m;
+
+       lws_jwk_init_jps(&jps, jwk, cb, user);
+
+       lejp_construct(&jctx, cb_jwk, &jps, cb ? jwk_outer_tok: jwk_tok,
+                      LWS_ARRAY_SIZE(jwk_tok));
+
+       m = lejp_parse(&jctx, (uint8_t *)in, (int)len);
+       lejp_destruct(&jctx);
+
+       if (m < 0) {
+               lwsl_notice("%s: parse got %d\n", __func__, m);
+               lws_jwk_destroy(jwk);
+               return -1;
+       }
+
+       switch (jwk->kty) {
+       case LWS_GENCRYPTO_KTY_UNKNOWN:
+               lwsl_notice("%s: missing or unknown kty\n", __func__);
+               lws_jwk_destroy(jwk);
+               return -1;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+
+int
+lws_jwk_export(struct lws_jwk *jwk, int flags, char *p, int *len)
+{
+       char *start = p, *end = &p[*len - 1];
+       int n, m, limit, first = 1, asym = 0;
+       struct lexico *l;
+
+       /* RFC7638 lexicographic order requires
+        *  RSA: e -> kty -> n
+        *  oct: k -> kty
+        *
+        * ie, meta and key data elements appear interleaved in name alpha order
+        */
+
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{");
+
+       switch (jwk->kty) {
+       case LWS_GENCRYPTO_KTY_OCT:
+               l = lexico_oct;
+               limit = LWS_ARRAY_SIZE(lexico_oct);
+               break;
+       case LWS_GENCRYPTO_KTY_RSA:
+               l = lexico_rsa;
+               limit = LWS_ARRAY_SIZE(lexico_rsa);
+               asym = 1;
+               break;
+       case LWS_GENCRYPTO_KTY_EC:
+               l = lexico_ec;
+               limit = LWS_ARRAY_SIZE(lexico_ec);
+               asym = 1;
+               break;
+       default:
+               return -1;
+       }
+
+       for (n = 0; n < limit; n++) {
+               const char *q, *q_end;
+               char tok[12];
+               int pos = 0, f = 1;
+
+               if ((l->meta & 1) && (jwk->meta[l->idx].buf ||
+                                     l->idx == (int)JWK_META_KTY)) {
+
+                       switch (l->idx) {
+                       case JWK_META_KTY:
+                               if (!first)
+                                       *p++ = ',';
+                               first = 0;
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"%s\"",
+                                                 l->name, kty_names[jwk->kty]);
+                               break;
+                       case JWK_META_KEY_OPS:
+                               if (!first)
+                                       *p++ = ',';
+                               first = 0;
+                               q = (const char *)jwk->meta[l->idx].buf;
+                               q_end = q + jwk->meta[l->idx].len;
+
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                                 "\"%s\":[", l->name);
+                               /*
+                                * For the public version, usages that
+                                * require the private part must be
+                                * snipped
+                                */
+
+                               while (q < q_end) {
+                                       if (*q != ' ' && pos < (int)sizeof(tok) - 1) {
+                                               tok[pos++] = *q++;
+                                               if (q != q_end)
+                                                       continue;
+                                       }
+                                       tok[pos] = '\0';
+                                       pos = 0;
+                                       if ((flags & LWSJWKF_EXPORT_PRIVATE) ||
+                                           !asym || (strcmp(tok, "sign") &&
+                                                     strcmp(tok, "encrypt"))) {
+                                               if (!f)
+                                                       *p++ = ',';
+                                               f = 0;
+                                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                                       "\"%s\"", tok);
+                                       }
+                                       q++;
+                               }
+
+                               *p++ = ']';
+
+                               break;
+
+                       default:
+                               /* both sig and enc require asym private key */
+                               if (!(flags & LWSJWKF_EXPORT_PRIVATE) &&
+                                   asym && l->idx == (int)JWK_META_USE)
+                                       break;
+                               if (!first)
+                                       *p++ = ',';
+                               first = 0;
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"",
+                                                 l->name);
+                               lws_strnncpy(p, (const char *)jwk->meta[l->idx].buf,
+                                            jwk->meta[l->idx].len, end - p);
+                               p += strlen(p);
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"");
+                               break;
+                       }
+               }
+
+               if ((!(l->meta & 1)) && jwk->e[l->idx].buf &&
+                   ((flags & LWSJWKF_EXPORT_PRIVATE) || !(l->meta & 2))) {
+                       if (!first)
+                               *p++ = ',';
+                       first = 0;
+
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"%s\":\"", l->name);
+
+                       if (jwk->kty == LWS_GENCRYPTO_KTY_EC &&
+                           l->idx == (int)LWS_GENCRYPTO_EC_KEYEL_CRV) {
+                               lws_strnncpy(p,
+                                            (const char *)jwk->e[l->idx].buf,
+                                            jwk->e[l->idx].len, end - p);
+                               m = (int)strlen(p);
+                       } else
+                               m = lws_jws_base64_enc(
+                                       (const char *)jwk->e[l->idx].buf,
+                                       jwk->e[l->idx].len, p, lws_ptr_diff_size_t(end, p) - 4);
+                       if (m < 0) {
+                               lwsl_notice("%s: enc failed\n", __func__);
+                               return -1;
+                       }
+                       p += m;
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"");
+               }
+
+               l++;
+       }
+
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                         (flags & LWSJWKF_EXPORT_NOCRLF) ? "}" : "}\n");
+
+       *len -= lws_ptr_diff(p, start);
+
+       return lws_ptr_diff(p, start);
+}
+
+int
+lws_jwk_load(struct lws_jwk *jwk, const char *filename,
+            lws_jwk_key_import_callback cb, void *user)
+{
+       unsigned int buflen = 4096;
+       char *buf = lws_malloc(buflen, "jwk-load");
+       int n;
+
+       if (!buf)
+               return -1;
+
+       n = lws_plat_read_file(filename, buf, buflen);
+       if (n < 0)
+               goto bail;
+
+       n = lws_jwk_import(jwk, cb, user, buf, (unsigned int)n);
+       lws_free(buf);
+
+       return n;
+bail:
+       lws_free(buf);
+
+       return -1;
+}
+
+int
+lws_jwk_save(struct lws_jwk *jwk, const char *filename)
+{
+       int buflen = 4096;
+       char *buf = lws_malloc((unsigned int)buflen, "jwk-save");
+       int n, m;
+
+       if (!buf)
+               return -1;
+
+       n = lws_jwk_export(jwk, LWSJWKF_EXPORT_PRIVATE, buf, &buflen);
+       if (n < 0)
+               goto bail;
+
+       m = lws_plat_write_file(filename, buf, (size_t)n);
+
+       lws_free(buf);
+       if (m)
+               return -1;
+
+       return 0;
+
+bail:
+       lws_free(buf);
+
+       return -1;
+}
index 35f4723..d0befd8 100644 (file)
 /*
- * libwebsockets - JSON Web Key support
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-#include "jose/private.h"
-
-#if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
-#include <fcntl.h>
-#endif
-
-static const char * const kty_names[] = {
-       "unknown",      /* LWS_GENCRYPTO_KTY_UNKNOWN */
-       "oct",          /* LWS_GENCRYPTO_KTY_OCT */
-       "RSA",          /* LWS_GENCRYPTO_KTY_RSA */
-       "EC"            /* LWS_GENCRYPTO_KTY_EC */
-};
-
-/*
- * These are the entire legal token set for names in jwk.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
- * The first version is used to parse a detached single jwk that don't have any
- * parent JSON context.  The second version is used to parse full jwk objects
- * that has a "keys": [ ] array containing the keys.
+ * Shared JWK handling that's the same whether JOSE or COSE
  */
 
-static const char * const jwk_tok[] = {
-       "keys[]",                       /* dummy */
-       "e", "n", "d", "p", "q", "dp", "dq", "qi", /* RSA */
-       "kty",                          /* generic */
-       "k",                            /* symmetric key data */
-       "crv", "x", "y",                /* EC (also "D") */
-       "kid",                          /* generic */
-       "use"                           /* mutually exclusive with "key_ops" */,
-       "key_ops"                       /* mutually exclusive with "use" */,
-       "x5c",                          /* generic */
-       "alg"                           /* generic */
-}, * const jwk_outer_tok[] = {
-       "keys[]",
-       "keys[].e", "keys[].n", "keys[].d", "keys[].p", "keys[].q", "keys[].dp",
-       "keys[].dq", "keys[].qi",
-
-       "keys[].kty", "keys[].k",               /* generic */
-       "keys[].crv", "keys[].x", "keys[].y",   /* EC (also "D") */
-       "keys[].kid", "keys[].use"      /* mutually exclusive with "key_ops" */,
-       "keys[].key_ops",               /* mutually exclusive with "use" */
-       "keys[].x5c", "keys[].alg"
-};
-
-/* information about each token declared above */
-
-#define F_M    (1 <<  9)       /* Mandatory for key type */
-#define F_B64  (1 << 10)       /* Base64 coded octets */
-#define F_B64U (1 << 11)       /* Base64 Url coded octets */
-#define F_META (1 << 12)       /* JWK key metainformation */
-#define F_RSA  (1 << 13)       /* RSA key */
-#define F_EC   (1 << 14)       /* Elliptic curve key */
-#define F_OCT  (1 << 15)       /* octet key */
-
-static unsigned short tok_map[] = {
-       F_RSA | F_EC | F_OCT | F_META |          0xff,
-       F_RSA |                         F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_E,
-       F_RSA |                         F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_N,
-       F_RSA | F_EC |                  F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_D,
-       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_P,
-       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_Q,
-       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_DP,
-       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_DQ,
-       F_RSA |                         F_B64U |       LWS_GENCRYPTO_RSA_KEYEL_QI,
-
-       F_RSA | F_EC | F_OCT | F_META |          F_M | JWK_META_KTY,
-                      F_OCT |          F_B64U | F_M | LWS_GENCRYPTO_OCT_KEYEL_K,
-
-               F_EC |                           F_M | LWS_GENCRYPTO_EC_KEYEL_CRV,
-               F_EC |                  F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_X,
-               F_EC |                  F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_Y,
-
-       F_RSA | F_EC | F_OCT | F_META |                JWK_META_KID,
-       F_RSA | F_EC | F_OCT | F_META |                JWK_META_USE,
-
-       F_RSA | F_EC | F_OCT | F_META |                JWK_META_KEY_OPS,
-       F_RSA | F_EC | F_OCT | F_META | F_B64 |        JWK_META_X5C,
-       F_RSA | F_EC | F_OCT | F_META |                JWK_META_ALG,
-};
+#include "private-lib-core.h"
+#include "private-lib-jose.h"
 
 static const char *meta_names[] = {
        "kty", "kid", "use", "key_ops", "x5c", "alg"
 };
 
-struct lexico {
-       const char *name;
-       int idx;
-       char meta;
-} lexico_ec[] =  {
-       { "alg",        JWK_META_ALG,                   1 },
-       { "crv",        LWS_GENCRYPTO_EC_KEYEL_CRV,     0 },
-       { "d",          LWS_GENCRYPTO_EC_KEYEL_D,       2 | 0 },
-       { "key_ops",    JWK_META_KEY_OPS,               1 },
-       { "kid",        JWK_META_KID,                   1 },
-       { "kty",        JWK_META_KTY,                   1 },
-       { "use",        JWK_META_USE,                   1 },
-       { "x",          LWS_GENCRYPTO_EC_KEYEL_X,       0 },
-       { "x5c",        JWK_META_X5C,                   1 },
-       { "y",          LWS_GENCRYPTO_EC_KEYEL_Y,       0 }
-}, lexico_oct[] =  {
-       { "alg",        JWK_META_ALG,                   1 },
-       { "k",          LWS_GENCRYPTO_OCT_KEYEL_K,      0 },
-       { "key_ops",    JWK_META_KEY_OPS,               1 },
-       { "kid",        JWK_META_KID,                   1 },
-       { "kty",        JWK_META_KTY,                   1 },
-       { "use",        JWK_META_USE,                   1 },
-       { "x5c",        JWK_META_X5C,                   1 }
-}, lexico_rsa[] =  {
-       { "alg",        JWK_META_ALG,                   1 },
-       { "d",          LWS_GENCRYPTO_RSA_KEYEL_D,      2 | 0 },
-       { "dp",         LWS_GENCRYPTO_RSA_KEYEL_DP,     2 | 0 },
-       { "dq",         LWS_GENCRYPTO_RSA_KEYEL_DQ,     2 | 0 },
-       { "e",          LWS_GENCRYPTO_RSA_KEYEL_E,      0 },
-       { "key_ops",    JWK_META_KEY_OPS,               1 },
-       { "kid",        JWK_META_KID,                   1 },
-       { "kty",        JWK_META_KTY,                   1 },
-       { "n",          LWS_GENCRYPTO_RSA_KEYEL_N,      0 },
-       { "p",          LWS_GENCRYPTO_RSA_KEYEL_P,      2 | 0 },
-       { "q",          LWS_GENCRYPTO_RSA_KEYEL_Q,      2 | 0 },
-       { "qi",         LWS_GENCRYPTO_RSA_KEYEL_QI,     2 | 0 },
-       { "use",        JWK_META_USE,                   1 },
-       { "x5c",        JWK_META_X5C,                   1 }
-};
-
 static const char meta_b64[] = { 0, 0, 0, 0, 1, 0 };
 
 static const char *oct_names[] = {
@@ -161,7 +48,7 @@ static const char *ec_names[] = {
 };
 static const char ec_b64[] = { 0, 1, 1, 1 };
 
-LWS_VISIBLE int
+int
 lws_jwk_dump(struct lws_jwk *jwk)
 {
        const char **enames, *b64;
@@ -218,8 +105,8 @@ lws_jwk_dump(struct lws_jwk *jwk)
        return 0;
 }
 
-static int
-_lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, int len)
+int
+_lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, size_t len)
 {
        e->buf = lws_malloc(len + 1, "jwk");
        if (!e->buf)
@@ -227,45 +114,7 @@ _lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, int len)
 
        memcpy(e->buf, in, len);
        e->buf[len] = '\0';
-       e->len = len;
-
-       return 0;
-}
-
-static int
-_lws_jwk_set_el_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len)
-{
-       int dec_size = lws_base64_size(len), n;
-
-       e->buf = lws_malloc(dec_size, "jwk");
-       if (!e->buf)
-               return -1;
-
-       /* same decoder accepts both url or original styles */
-
-       n = lws_b64_decode_string_len(in, len, (char *)e->buf, dec_size - 1);
-       if (n < 0)
-               return -1;
-       e->len = n;
-
-       return 0;
-}
-
-static int
-_lws_jwk_set_el_jwk_b64u(struct lws_gencrypto_keyelem *e, char *in, int len)
-{
-       int dec_size = lws_base64_size(len), n;
-
-       e->buf = lws_malloc(dec_size, "jwk");
-       if (!e->buf)
-               return -1;
-
-       /* same decoder accepts both url or original styles */
-
-       n = lws_b64_decode_string_len(in, len, (char *)e->buf, dec_size - 1);
-       if (n < 0)
-               return -1;
-       e->len = n;
+       e->len = (uint32_t)len;
 
        return 0;
 }
@@ -284,292 +133,57 @@ lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m)
                }
 }
 
-LWS_VISIBLE void
+void
 lws_jwk_destroy(struct lws_jwk *jwk)
 {
        lws_jwk_destroy_elements(jwk->e, LWS_ARRAY_SIZE(jwk->e));
        lws_jwk_destroy_elements(jwk->meta, LWS_ARRAY_SIZE(jwk->meta));
 }
 
-static signed char
-cb_jwk(struct lejp_ctx *ctx, char reason)
-{
-       struct lws_jwk_parse_state *jps = (struct lws_jwk_parse_state *)ctx->user;
-       struct lws_jwk *jwk = jps->jwk;
-       unsigned int idx, poss, n;
-
-       if (reason == LEJPCB_VAL_STR_START)
-               jps->pos = 0;
-
-       if (reason == LEJPCB_OBJECT_START && ctx->path_match == 0 + 1)
-               /*
-                * new keys[] member is starting
-                *
-                * Until we see some JSON names, it could be anything...
-                * there is no requirement for kty to be given first and eg,
-                * ACME specifies the keys must be ordered in lexographic
-                * order - where kty is not first.
-                */
-               jps->possible = F_RSA | F_EC | F_OCT;
-
-       if (reason == LEJPCB_OBJECT_END && ctx->path_match == 0 + 1) {
-               /* we completed parsing a key */
-               if (jps->per_key_cb && jps->possible) {
-                       if (jps->per_key_cb(jps->jwk, jps->user)) {
-
-                               lwsl_notice("%s: user cb halts import\n",
-                                           __func__);
-
-                               return -2;
-                       }
-
-                       /* clear it down */
-                       lws_jwk_destroy(jps->jwk);
-                       jps->possible = 0;
-               }
-       }
-
-       if (reason == LEJPCB_COMPLETE) {
-
-               /*
-                * Now we saw the whole jwk and know the key type, let'jwk insist
-                * that as a whole, it must be consistent and complete.
-                *
-                * The tracking of ->possible bits from even before we know the
-                * kty already makes certain we cannot have key element members
-                * defined that are inconsistent with the key type.
-                */
-
-               for (n = 0; n < LWS_ARRAY_SIZE(tok_map); n++)
-                       /*
-                        * All mandataory elements for the key type
-                        * must be present
-                        */
-                       if ((tok_map[n] & jps->possible) && (
-                           ((tok_map[n] & (F_M | F_META)) == (F_M | F_META) &&
-                            !jwk->meta[tok_map[n] & 0xff].buf) ||
-                           ((tok_map[n] & (F_M | F_META)) == F_M &&
-                            !jwk->e[tok_map[n] & 0xff].buf))) {
-                               lwsl_notice("%s: missing %s\n", __func__,
-                                           jwk_tok[n]);
-                                       return -3;
-                               }
-
-               /*
-                * When the key may be public or public + private, ensure the
-                * intra-key members related to that are consistent.
-                *
-                * Only RSA keys need extra care, since EC keys are already
-                * confirmed by making CRV, X and Y mandatory and only D
-                * (the singular private part) optional.  For RSA, N and E are
-                * also already known to be present using mandatory checking.
-                */
-
-               /*
-                * If a private key, it must have all D, P and Q.  Public key
-                * must have none of them.
-                */
-               if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
-                   !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) &&
-                     (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) &&
-                     (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) ||
-                     (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
-                      jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf &&
-                      jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf))
-                     ) {
-                       lwsl_notice("%s: RSA requires D, P and Q for private\n",
-                                   __func__);
-                       return -3;
-               }
-
-               /*
-                * If the precomputed private key terms appear, they must all
-                * appear together.
-                */
-               if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
-                   !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf) &&
-                     (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) &&
-                     (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf)) ||
-                     (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf &&
-                      jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf &&
-                      jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf))
-                     ) {
-                       lwsl_notice("%s: RSA DP, DQ, QI must all appear "
-                                   "or none\n", __func__);
-                       return -3;
-               }
-
-               /*
-                * The precomputed private key terms must not appear without
-                * the private key itself also appearing.
-                */
-               if (jwk->kty == LWS_GENCRYPTO_KTY_RSA &&
-                   !jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf &&
-                    jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) {
-                       lwsl_notice("%s: RSA DP, DQ, QI can appear only with "
-                                   "private key\n", __func__);
-                       return -3;
-               }
-
-               if ((jwk->kty == LWS_GENCRYPTO_KTY_RSA ||
-                    jwk->kty == LWS_GENCRYPTO_KTY_EC) &&
-                   jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf)
-               jwk->private_key = 1;
-       }
-
-       if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
-               return 0;
-
-       if (ctx->path_match == 0 + 1)
-               return 0;
-
-       idx = tok_map[ctx->path_match - 1];
-       if ((idx & 0xff) == 0xff)
-               return 0;
-
-       switch (idx) {
-       /* note: kty is not necessarily first... we have to keep track of
-        * what could match given which element names have already been
-        * seen.  Once kty comes, we confirm it'jwk still possible (ie, it'jwk
-        * not trying to tell us that it'jwk RSA now when we saw a "crv"
-        * earlier) and then reduce the possibilities to just the one that
-        * kty told. */
-       case F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY:
-
-               if (ctx->npos == 3 && !strncmp(ctx->buf, "oct", 3)) {
-                       if (!(jps->possible & F_OCT))
-                               goto elements_mismatch;
-                       jwk->kty = LWS_GENCRYPTO_KTY_OCT;
-                       jps->possible = F_OCT;
-                       goto cont;
-               }
-               if (ctx->npos == 3 && !strncmp(ctx->buf, "RSA", 3)) {
-                       if (!(jps->possible & F_RSA))
-                               goto elements_mismatch;
-                       jwk->kty = LWS_GENCRYPTO_KTY_RSA;
-                       jps->possible = F_RSA;
-                       goto cont;
-               }
-               if (ctx->npos == 2 && !strncmp(ctx->buf, "EC", 2)) {
-                       if (!(jps->possible & F_EC))
-                               goto elements_mismatch;
-                       jwk->kty = LWS_GENCRYPTO_KTY_EC;
-                       jps->possible = F_EC;
-                       goto cont;
-               }
-               lwsl_err("%s: Unknown KTY '%.*s'\n", __func__, ctx->npos,
-                         ctx->buf);
-               return -1;
-
-       default:
-cont:
-               if (jps->pos + ctx->npos >= (int)sizeof(jps->b64))
-                       goto bail;
-
-               memcpy(jps->b64 + jps->pos, ctx->buf, ctx->npos);
-               jps->pos += ctx->npos;
-
-               if (reason == LEJPCB_VAL_STR_CHUNK)
-                       return 0;
-
-               /* chunking has been collated */
-
-               poss = idx & (F_RSA | F_EC | F_OCT);
-               jps->possible &= poss;
-               if (!jps->possible)
-                       goto elements_mismatch;
-
-               if (idx & F_META) {
-                       if (_lws_jwk_set_el_jwk(&jwk->meta[idx & 0x7f],
-                                               jps->b64, jps->pos) < 0)
-                               goto bail;
-
-                       break;
-               }
-
-               if (idx & F_B64U) {
-                       /* key data... do the base64 decode as needed */
-                       if (_lws_jwk_set_el_jwk_b64u(&jwk->e[idx & 0x7f],
-                                                    jps->b64, jps->pos) < 0)
-                               goto bail;
-
-                       if (jwk->e[idx & 0x7f].len >
-                                       LWS_JWE_LIMIT_KEY_ELEMENT_BYTES) {
-                               lwsl_notice("%s: oversize keydata\n", __func__);
-                               goto bail;
-                       }
-
-                       return 0;
-               }
-
-               if (idx & F_B64) {
-
-                       /* cert data... do non-urlcoded base64 decode */
-                       if (_lws_jwk_set_el_jwk_b64(&jwk->e[idx & 0x7f],
-                                                   jps->b64, jps->pos) < 0)
-                               goto bail;
-                       return 0;
-               }
-
-                       if (_lws_jwk_set_el_jwk(&jwk->e[idx & 0x7f],
-                                               jps->b64, jps->pos) < 0)
-                               goto bail;
-               break;
-       }
-
-       return 0;
-
-elements_mismatch:
-       lwsl_err("%s: jwk elements mismatch\n", __func__);
-
-bail:
-       lwsl_err("%s: element failed\n", __func__);
-
-       return -1;
-}
-
 void
-lws_jwk_init_jps(struct lejp_ctx *jctx, struct lws_jwk_parse_state *jps,
+lws_jwk_init_jps(struct lws_jwk_parse_state *jps,
                 struct lws_jwk *jwk, lws_jwk_key_import_callback cb,
                 void *user)
 {
        if (jwk)
                memset(jwk, 0, sizeof(*jwk));
 
-       jps->jwk = jwk;
-       jps->possible = F_RSA | F_EC | F_OCT;
-       jps->per_key_cb = cb;
-       jps->user = user;
-       jps->pos = 0;
-
-       lejp_construct(jctx, cb_jwk, jps, cb ? jwk_outer_tok: jwk_tok,
-                      LWS_ARRAY_SIZE(jwk_tok));
+       jps->jwk                = jwk;
+       jps->possible           = F_RSA | F_EC | F_OCT;
+       jps->per_key_cb         = cb;
+       jps->user               = user;
+       jps->pos                = 0;
+       jps->seen               = 0;
+       jps->cose_state         = 0;
 }
 
-LWS_VISIBLE int
+int
 lws_jwk_dup_oct(struct lws_jwk *jwk, const void *key, int len)
 {
-       jwk->e[LWS_GENCRYPTO_KTY_OCT].buf = lws_malloc(len, __func__);
+       unsigned int ulen = (unsigned int)len;
+
+       jwk->e[LWS_GENCRYPTO_KTY_OCT].buf = lws_malloc(ulen, __func__);
        if (!jwk->e[LWS_GENCRYPTO_KTY_OCT].buf)
                return -1;
 
        jwk->kty = LWS_GENCRYPTO_KTY_OCT;
-       jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].len = len;
+       jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].len = ulen;
 
-       memcpy(jwk->e[LWS_GENCRYPTO_KTY_OCT].buf, key, len);
+       memcpy(jwk->e[LWS_GENCRYPTO_KTY_OCT].buf, key, ulen);
 
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk,
                 enum lws_gencrypto_kty kty, int bits, const char *curve)
 {
+       size_t sn;
        int n;
 
        memset(jwk, 0, sizeof(*jwk));
 
-       jwk->kty = kty;
+       jwk->kty = (int)kty;
        jwk->private_key = 1;
 
        switch (kty) {
@@ -588,11 +202,13 @@ lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk,
        }
                break;
        case LWS_GENCRYPTO_KTY_OCT:
-               n = lws_gencrypto_bits_to_bytes(bits);
-               jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf = lws_malloc(n, "oct");
-               jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].len = n;
+               sn = (unsigned int)lws_gencrypto_bits_to_bytes(bits);
+               jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf = lws_malloc(sn, "oct");
+               if (!jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf)
+                       return 1;
+               jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].len = (uint32_t)sn;
                if (lws_get_random(context,
-                                jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, n) != n) {
+                            jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, sn) != sn) {
                        lwsl_err("%s: problem getting random\n", __func__);
                        return 1;
                }
@@ -631,194 +247,24 @@ lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk,
        return 0;
 }
 
-LWS_VISIBLE int
-lws_jwk_import(struct lws_jwk *jwk, lws_jwk_key_import_callback cb, void *user,
-              const char *in, size_t len)
-{
-       struct lejp_ctx jctx;
-       struct lws_jwk_parse_state jps;
-       int m;
-
-       lws_jwk_init_jps(&jctx, &jps, jwk, cb, user);
-
-       m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)in, len);
-       lejp_destruct(&jctx);
-
-       if (m < 0) {
-               lwsl_notice("%s: parse got %d\n", __func__, m);
-               lws_jwk_destroy(jwk);
-               return -1;
-       }
-
-       switch (jwk->kty) {
-       case LWS_GENCRYPTO_KTY_UNKNOWN:
-               lwsl_notice("%s: missing or unknown kyt\n", __func__);
-               lws_jwk_destroy(jwk);
-               return -1;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-
-LWS_VISIBLE int
-lws_jwk_export(struct lws_jwk *jwk, int private, char *p, int *len)
-{
-       char *start = p, *end = &p[*len - 1];
-       int n, m, limit, first = 1, asym = 0;
-       struct lexico *l;
-
-       /* RFC7638 lexicographic order requires
-        *  RSA: e -> kty -> n
-        *  oct: k -> kty
-        *
-        * ie, meta and key data elements appear interleaved in name alpha order
-        */
-
-       p += lws_snprintf(p, end - p, "{");
-
-       switch (jwk->kty) {
-       case LWS_GENCRYPTO_KTY_OCT:
-               l = lexico_oct;
-               limit = LWS_ARRAY_SIZE(lexico_oct);
-               break;
-       case LWS_GENCRYPTO_KTY_RSA:
-               l = lexico_rsa;
-               limit = LWS_ARRAY_SIZE(lexico_rsa);
-               asym = 1;
-               break;
-       case LWS_GENCRYPTO_KTY_EC:
-               l = lexico_ec;
-               limit = LWS_ARRAY_SIZE(lexico_ec);
-               asym = 1;
-               break;
-       default:
-               return -1;
-       }
-
-       for (n = 0; n < limit; n++) {
-               const char *q, *q_end;
-               char tok[12];
-               int pos = 0, f = 1;
-
-               if ((l->meta & 1) && (jwk->meta[l->idx].buf ||
-                                     l->idx == (int)JWK_META_KTY)) {
-
-                       switch (l->idx) {
-                       case JWK_META_KTY:
-                               if (!first)
-                                       *p++ = ',';
-                               first = 0;
-                               p += lws_snprintf(p, end - p, "\"%s\":\"%s\"",
-                                                 l->name, kty_names[jwk->kty]);
-                               break;
-                       case JWK_META_KEY_OPS:
-                               if (!first)
-                                       *p++ = ',';
-                               first = 0;
-                               q = (const char *)jwk->meta[l->idx].buf;
-                               q_end = q + jwk->meta[l->idx].len;
-
-                               p += lws_snprintf(p, end - p,
-                                                 "\"%s\":[", l->name);
-                               /*
-                                * For the public version, usages that
-                                * require the private part must be
-                                * snipped
-                                */
-
-                               while (q < q_end) {
-                                       if (*q != ' ' && pos < (int)sizeof(tok) - 1) {
-                                               tok[pos++] = *q++;
-                                               if (q != q_end)
-                                                       continue;
-                                       }
-                                       tok[pos] = '\0';
-                                       pos = 0;
-                                       if (private || !asym ||
-                                           (strcmp(tok, "sign") &&
-                                           strcmp(tok, "encrypt"))) {
-                                               if (!f)
-                                                       *p++ = ',';
-                                               f = 0;
-                                               p += lws_snprintf(p, end - p,
-                                                       "\"%s\"", tok);
-                                       }
-                                       q++;
-                               }
-
-                               *p++ = ']';
-
-                               break;
-
-                       default:
-                               /* both sig and enc require asym private key */
-                               if (!private && asym && l->idx == (int)JWK_META_USE)
-                                       break;
-                               if (!first)
-                                       *p++ = ',';
-                               first = 0;
-                               p += lws_snprintf(p, end - p, "\"%s\":\"%.*s\"",
-                                                 l->name, jwk->meta[l->idx].len,
-                                                 jwk->meta[l->idx].buf);
-                               break;
-                       }
-               }
-
-               if ((!(l->meta & 1)) && jwk->e[l->idx].buf &&
-                   (private || !(l->meta & 2))) {
-                       if (!first)
-                               *p++ = ',';
-                       first = 0;
-
-                       p += lws_snprintf(p, end - p, "\"%s\":\"", l->name);
-
-                       if (jwk->kty == LWS_GENCRYPTO_KTY_EC &&
-                           l->idx == (int)LWS_GENCRYPTO_EC_KEYEL_CRV)
-                               m = lws_snprintf(p, end - p, "%.*s",
-                                       jwk->e[l->idx].len,
-                                       (const char *)jwk->e[l->idx].buf);
-                       else
-                               m = lws_jws_base64_enc(
-                                       (const char *)jwk->e[l->idx].buf,
-                                       jwk->e[l->idx].len, p, end - p - 4);
-                       if (m < 0) {
-                               lwsl_notice("%s: enc failed\n", __func__);
-                               return -1;
-                       }
-                       p += m;
-                       p += lws_snprintf(p, end - p, "\"");
-               }
-
-               l++;
-       }
-
-       p += lws_snprintf(p, end - p, "}\n");
-
-       *len -= p - start;
-
-       return p - start;
-}
-
-LWS_VISIBLE int
+int
 lws_jwk_rfc7638_fingerprint(struct lws_jwk *jwk, char *digest32)
 {
        struct lws_genhash_ctx hash_ctx;
-       int tmpsize = 2536, n;
+       size_t tmpsize = 2536;
        char *tmp;
+       int n, m = (int)tmpsize;
 
        tmp = lws_malloc(tmpsize, "rfc7638 tmp");
 
-       n = lws_jwk_export(jwk, 0, tmp, &tmpsize);
+       n = lws_jwk_export(jwk, LWSJWKF_EXPORT_NOCRLF, tmp, &m);
        if (n < 0)
                goto bail;
 
        if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256))
                goto bail;
 
-       if (lws_genhash_update(&hash_ctx, tmp, n)) {
+       if (lws_genhash_update(&hash_ctx, tmp, (unsigned int)n)) {
                lws_genhash_destroy(&hash_ctx, NULL);
 
                goto bail;
@@ -836,68 +282,16 @@ bail:
        return -1;
 }
 
-LWS_VISIBLE int
+int
 lws_jwk_strdup_meta(struct lws_jwk *jwk, enum enum_jwk_meta_tok idx,
                    const char *in, int len)
 {
-       jwk->meta[idx].buf = lws_malloc(len, __func__);
+       jwk->meta[idx].buf = lws_malloc((unsigned int)len, __func__);
        if (!jwk->meta[idx].buf)
                return 1;
-       jwk->meta[idx].len = len;
-       memcpy(jwk->meta[idx].buf, in, len);
+       jwk->meta[idx].len = (uint32_t)(unsigned int)len;
+       memcpy(jwk->meta[idx].buf, in, (unsigned int)len);
 
        return 0;
 }
 
-LWS_VISIBLE int
-lws_jwk_load(struct lws_jwk *jwk, const char *filename,
-            lws_jwk_key_import_callback cb, void *user)
-{
-       int buflen = 4096;
-       char *buf = lws_malloc(buflen, "jwk-load");
-       int n;
-
-       if (!buf)
-               return -1;
-
-       n = lws_plat_read_file(filename, buf, buflen);
-       if (n < 0)
-               goto bail;
-
-       n = lws_jwk_import(jwk, cb, user, buf, n);
-       lws_free(buf);
-
-       return n;
-bail:
-       lws_free(buf);
-
-       return -1;
-}
-
-LWS_VISIBLE int
-lws_jwk_save(struct lws_jwk *jwk, const char *filename)
-{
-       int buflen = 4096;
-       char *buf = lws_malloc(buflen, "jwk-save");
-       int n, m;
-
-       if (!buf)
-               return -1;
-
-       n = lws_jwk_export(jwk, 1, buf, &buflen);
-       if (n < 0)
-               goto bail;
-
-       m = lws_plat_write_file(filename, buf, n);
-
-       lws_free(buf);
-       if (m)
-               return -1;
-
-       return 0;
-
-bail:
-       lws_free(buf);
-
-       return -1;
-}
index 627fd23..4007865 100644 (file)
@@ -1,29 +1,32 @@
-/*
- * libwebsockets - JSON Web Signature support
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * JOSE is actually specified as part of JWS RFC7515.  JWE references RFC7515
  * to specify its JOSE JSON object.  So it lives in ./lib/jose/jws/jose.c.
  */
 
-#include "core/private.h"
-#include "jose/private.h"
+#include "private-lib-core.h"
+#include "jose/private-lib-jose.h"
 
 #include <stdint.h>
 
@@ -225,8 +228,8 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason)
                return 0;
 
        case LJJHI_TYP: /* Optional: string: media type */
-               if (strcmp(ctx->buf, "JWT"))
-                       return -1;
+               lws_strnncpy(args->jose->typ, ctx->buf, ctx->npos,
+                            sizeof(args->jose->typ));
                break;
 
        case LJJHI_JKU: /* Optional: string */
@@ -361,19 +364,19 @@ append_string:
        if (reason == LEJPCB_VAL_STR_END) {
                n = lws_b64_decode_string_len(
                        (const char *)args->jose->e[ctx->path_match - 1].buf,
-                       args->jose->e[ctx->path_match - 1].len,
+                       (int)args->jose->e[ctx->path_match - 1].len,
                        (char *)args->jose->e[ctx->path_match - 1].buf,
-                       args->jose->e[ctx->path_match - 1].len + 1);
+                       (int)args->jose->e[ctx->path_match - 1].len + 1);
                if (n < 0) {
                        lwsl_err("%s: b64 decode failed\n", __func__);
                        return -1;
                }
 
-               args->temp -= args->jose->e[ctx->path_match - 1].len - n - 1;
+               args->temp -= (int)args->jose->e[ctx->path_match - 1].len - n - 1;
                *args->temp_len +=
-                       args->jose->e[ctx->path_match - 1].len - n - 1;
+                       (int)args->jose->e[ctx->path_match - 1].len - n - 1;
 
-               args->jose->e[ctx->path_match - 1].len = n;
+               args->jose->e[ctx->path_match - 1].len = (uint32_t)n;
        }
 
        return 0;
@@ -401,7 +404,6 @@ lws_jose_destroy(struct lws_jose *jose)
                lws_jose_recip_destroy(&jose->recipient[n]);
 }
 
-
 static int
 lws_jose_parse(struct lws_jose *jose, const uint8_t *buf, int n,
               char *temp, int *temp_len, int is_jwe)
@@ -410,27 +412,30 @@ lws_jose_parse(struct lws_jose *jose, const uint8_t *buf, int n,
        struct jose_cb_args args;
        int m;
 
-       if (is_jwe)
+       if (is_jwe) {
                /* prepare a context for JOSE epk ephemeral jwk parsing */
-               lws_jwk_init_jps(&args.jwk_jctx, &args.jps,
+               lws_jwk_init_jps(&args.jps,
                                 &jose->recipient[jose->recipients].jwk_ephemeral,
                                 NULL, NULL);
+               lejp_construct(&args.jwk_jctx, cb_jwk, &args.jps,
+                               jwk_tok, LWS_ARRAY_SIZE(jwk_tok));
+       }
 
-       args.is_jwe is_jwe;
-       args.temp = temp;
-       args.temp_len = temp_len;
-       args.jose = jose;
-       args.recip = 0;
-       args.recipients_array = 0;
-       jose->recipients = 0;
+       args.is_jwe             = (unsigned int)is_jwe;
+       args.temp               = temp;
+       args.temp_len           = temp_len;
+       args.jose               = jose;
+       args.recip              = 0;
+       args.recipients_array   = 0;
+       jose->recipients        = 0;
 
        lejp_construct(&jctx, lws_jws_jose_cb, &args, jws_jose,
                       LWS_ARRAY_SIZE(jws_jose));
 
-       m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)buf, n);
+       m = lejp_parse(&jctx, (uint8_t *)buf, n);
        lejp_destruct(&jctx);
        if (m < 0) {
-               lwsl_notice("%s: parse %.*s returned %d\n", __func__, n, buf, m);
+               lwsl_notice("%s: parse returned %d\n", __func__, m);
                return -1;
        }
 
@@ -485,7 +490,7 @@ lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
                case LJJHI_ENC: /* JWE only: Optional: string */
                case LJJHI_ZIP: /* JWE only: Optional: string ("DEF"=deflate) */
                        if (jose->e[n].buf) {
-                               out += lws_snprintf(out, end - out,
+                               out += lws_snprintf(out, lws_ptr_diff_size_t(end, out),
                                        "%s\"%s\":\"%s\"", sub ? ",\n" : "",
                                        jws_jose[n], jose->e[n].buf);
                                sub = 1;
@@ -500,17 +505,17 @@ lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
                case LJJHI_TAG: /* Additional arg for JWE AES:   b64url */
                case LJJHI_P2S: /* Additional arg for JWE PBES2: b64url: salt */
                        if (jose->e[n].buf) {
-                               out += lws_snprintf(out, end - out,
+                               out += lws_snprintf(out, lws_ptr_diff_size_t(end, out),
                                        "%s\"%s\":\"", sub ? ",\n" : "",
                                                jws_jose[n]);
                                sub = 1;
                                m = lws_b64_encode_string_url((const char *)
-                                               jose->e[n].buf, jose->e[n].len,
-                                               out, end - out);
+                                               jose->e[n].buf, (int)jose->e[n].len,
+                                               out, lws_ptr_diff(end, out));
                                if (m < 0)
                                        return -1;
                                out += m;
-                               out += lws_snprintf(out, end - out, "\"");
+                               out += lws_snprintf(out, lws_ptr_diff_size_t(end, out), "\"");
                        }
                        break;
 
@@ -519,17 +524,17 @@ lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
 
                case LJJHI_X5C: /* Optional: base64 (NOT -url): actual cert */
                        if (jose->e[n].buf) {
-                               out += lws_snprintf(out, end - out,
+                               out += lws_snprintf(out, lws_ptr_diff_size_t(end, out),
                                        "%s\"%s\":\"", sub ? ",\n" : "",
                                                        jws_jose[n]);
                                sub = 1;
                                m = lws_b64_encode_string((const char *)
-                                               jose->e[n].buf, jose->e[n].len,
-                                               out, end - out);
+                                               jose->e[n].buf, (int)jose->e[n].len,
+                                               out, lws_ptr_diff(end, out));
                                if (m < 0)
                                        return -1;
                                out += m;
-                               out += lws_snprintf(out, end - out, "\"");
+                               out += lws_snprintf(out, lws_ptr_diff_size_t(end, out), "\"");
                        }
                        break;
 
@@ -540,10 +545,10 @@ lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
                        if (!jwk || !jwk->kty)
                                break;
 
-                       out += lws_snprintf(out, end - out, "%s\"%s\":",
+                       out += lws_snprintf(out, lws_ptr_diff_size_t(end, out), "%s\"%s\":",
                                            sub ? ",\n" : "", jws_jose[n]);
                        sub = 1;
-                       vl = end - out;
+                       vl = lws_ptr_diff(end, out);
                        m = lws_jwk_export(jwk, 0, out, &vl);
                        if (m < 0) {
                                lwsl_notice("%s: failed to export key\n",
@@ -559,7 +564,7 @@ lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
                        if (!jose->e[n].buf)
                                break;
 
-                       out += lws_snprintf(out, end - out,
+                       out += lws_snprintf(out, lws_ptr_diff_size_t(end, out),
                                "%s\"%s\":[", sub ? ",\n" : "", jws_jose[n]);
                        sub = 1;
 
@@ -582,7 +587,7 @@ lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
                                        f = 0;
                                }
 
-                               *out++ = jose->e[n].buf[m];
+                               *out++ = (char)jose->e[n].buf[m];
                                m++;
                        }
 
@@ -595,7 +600,7 @@ lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
        if (out > end - 2)
                return -1;
 
-       return out_len - (end - out) - 1;
+       return lws_ptr_diff(out_len, (end - out)) - 1;
 
 bail:
        return -1;
index b568104..6364c6b 100644 (file)
@@ -1,26 +1,29 @@
 /*
- * libwebsockets - JSON Web Signature support
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-#include "private.h"
+#include "private-lib-core.h"
+#include "private-lib-jose-jws.h"
 
 /*
  * Currently only support flattened or compact (implicitly single signature)
@@ -117,7 +120,7 @@ append_string:
 
                n = lws_b64_decode_string_len(
                        (const char *)args->jws->map_b64.buf[m],
-                       args->jws->map_b64.len[m],
+                       (int)args->jws->map_b64.len[m],
                        (char *)args->temp, *args->temp_len);
                if (n < 0) {
                        lwsl_err("%s: b64 decode failed: in len %d, m %d\n", __func__, (int)args->jws->map_b64.len[m], m);
@@ -126,7 +129,7 @@ append_string:
 
                args->temp += n;
                *args->temp_len -= n;
-               args->jws->map.len[m] = n;
+               args->jws->map.len[m] = (unsigned int)n;
        }
 
        return 0;
@@ -147,7 +150,7 @@ lws_jws_json_parse(struct lws_jws *jws, const uint8_t *buf, int len,
        lejp_construct(&jctx, lws_jws_json_cb, &args, jws_json,
                       LWS_ARRAY_SIZE(jws_json));
 
-       m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)buf, len);
+       m = lejp_parse(&jctx, (uint8_t *)buf, len);
        lejp_destruct(&jctx);
        if (m < 0) {
                lwsl_notice("%s: parse returned %d\n", __func__, m);
@@ -157,7 +160,7 @@ lws_jws_json_parse(struct lws_jws *jws, const uint8_t *buf, int len,
        return 0;
 }
 
-LWS_VISIBLE void
+void
 lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk,
             struct lws_context *context)
 {
@@ -178,14 +181,14 @@ lws_jws_map_bzero(struct lws_jws_map *map)
                        lws_explicit_bzero((void *)map->buf[n], map->len[n]);
 }
 
-LWS_VISIBLE void
+void
 lws_jws_destroy(struct lws_jws *jws)
 {
        lws_jws_map_bzero(&jws->map);
        jws->jwk = NULL;
 }
 
-LWS_VISIBLE int
+int
 lws_jws_dup_element(struct lws_jws_map *map, int idx, char *temp, int *temp_len,
                    const void *in, size_t in_len, size_t actual_alloc)
 {
@@ -197,15 +200,15 @@ lws_jws_dup_element(struct lws_jws_map *map, int idx, char *temp, int *temp_len,
 
        memcpy(temp, in, in_len);
 
-       map->len[idx] = in_len;
+       map->len[idx] = (uint32_t)in_len;
        map->buf[idx] = temp;
 
-       *temp_len -= actual_alloc;
+       *temp_len -= (int)actual_alloc;
 
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
                           char *temp, int *temp_len, const void *in,
                           size_t in_len)
@@ -215,11 +218,11 @@ lws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
        if (*temp_len < lws_base64_size((int)in_len))
                return -1;
 
-       n = lws_jws_base64_enc(in, in_len, temp, *temp_len);
+       n = lws_jws_base64_enc(in, in_len, temp, (size_t)*temp_len);
        if (n < 0)
                return -1;
 
-       map->len[idx] = n;
+       map->len[idx] = (unsigned int)n;
        map->buf[idx] = temp;
 
        *temp_len -= n;
@@ -227,7 +230,7 @@ lws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_jws_randomize_element(struct lws_context *context, struct lws_jws_map *map,
                          int idx, char *temp, int *temp_len, size_t random_len,
                          size_t actual_alloc)
@@ -238,20 +241,20 @@ lws_jws_randomize_element(struct lws_context *context, struct lws_jws_map *map,
        if ((size_t)*temp_len < actual_alloc)
                return -1;
 
-       map->len[idx] = random_len;
+       map->len[idx] = (uint32_t)random_len;
        map->buf[idx] = temp;
 
-       if (lws_get_random(context, temp, random_len) != (int)random_len) {
+       if (lws_get_random(context, temp, random_len) != random_len) {
                lwsl_err("Problem getting random\n");
                return -1;
        }
 
-       *temp_len -= actual_alloc;
+       *temp_len -= (int)actual_alloc;
 
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp,
                      int *temp_len, size_t len, size_t actual_alloc)
 {
@@ -261,19 +264,19 @@ lws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp,
        if ((size_t)*temp_len < actual_alloc)
                return -1;
 
-       map->len[idx] = len;
+       map->len[idx] = (uint32_t)len;
        map->buf[idx] = temp;
-       *temp_len -= actual_alloc;
+       *temp_len -= (int)actual_alloc;
 
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max)
 {
        int n;
 
-       n = lws_b64_encode_string_url(in, in_len, out, out_max - 1);
+       n = lws_b64_encode_string_url(in, (int)in_len, out, (int)out_max - 1);
        if (n < 0) {
                lwsl_notice("%s: in len %d too large for %d out buf\n",
                                __func__, (int)in_len, (int)out_max);
@@ -289,7 +292,7 @@ lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max)
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map)
 {
        int me = 0;
@@ -317,7 +320,7 @@ lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map)
  * map_b64 set to b64 elements
  */
 
-LWS_VISIBLE int
+int
 lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
                       struct lws_jws_map *map_b64, char *out,
                       int *out_len)
@@ -336,7 +339,7 @@ lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
                return -1;
 
        while (m < blocks) {
-               n = lws_b64_decode_string_len(map_b64->buf[m], map_b64->len[m],
+               n = lws_b64_decode_string_len(map_b64->buf[m], (int)map_b64->len[m],
                                              out, *out_len);
                if (n < 0) {
                        lwsl_err("%s: b64 decode failed\n", __func__);
@@ -347,7 +350,7 @@ lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
                        map->buf[m] = out;
                else
                        map->buf[m] = NULL;
-               map->len[m++] = n;
+               map->len[m++] = (unsigned int)n;
                out += n;
                *out_len -= n;
 
@@ -365,7 +368,7 @@ lws_jws_compact_decode_map(struct lws_jws_map *map_b64, struct lws_jws_map *map,
        int n, m = 0;
 
        for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) {
-               n = lws_b64_decode_string_len(map_b64->buf[m], map_b64->len[m],
+               n = lws_b64_decode_string_len(map_b64->buf[m], (int)map_b64->len[m],
                                              out, *out_len);
                if (n < 0) {
                        lwsl_err("%s: b64 decode failed\n", __func__);
@@ -373,7 +376,7 @@ lws_jws_compact_decode_map(struct lws_jws_map *map_b64, struct lws_jws_map *map,
                }
                /* replace the map entry with the decoded content */
                map->buf[m] = out;
-               map->len[m++] = n;
+               map->len[m++] = (unsigned int)n;
                out += n;
                *out_len -= n;
 
@@ -384,11 +387,11 @@ lws_jws_compact_decode_map(struct lws_jws_map *map_b64, struct lws_jws_map *map,
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
                       char *end)
 {
-       int n, len = (end - *p) - 1;
+       int n, len = lws_ptr_diff(end, (*p)) - 1;
        char *p_entry = *p;
 
        if (len < 3)
@@ -397,16 +400,16 @@ lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
        if (!first)
                *(*p)++ = '.';
 
-       n = lws_jws_base64_enc(in, in_len, *p, len - 1);
+       n = lws_jws_base64_enc(in, in_len, *p, (unsigned int)len - 1);
        if (n < 0)
                return -1;
 
        *p += n;
 
-       return (*p) - p_entry;
+       return lws_ptr_diff((*p), p_entry);
 }
 
-LWS_VISIBLE int
+int
 lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
                       const struct lws_jws_map *map,   /* non-b64 */
                       char *buf, int *len)
@@ -419,7 +422,7 @@ lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
                        map_b64->len[n] = 0;
                        continue;
                }
-               m = lws_jws_base64_enc(map->buf[n], map->len[n], buf, *len);
+               m = lws_jws_base64_enc(map->buf[n], map->len[n], buf, (size_t)*len);
                if (m < 0)
                        return -1;
                buf += m;
@@ -438,7 +441,7 @@ lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
  * the JOSE header and signature, decoded versions too.
  */
 
-LWS_VISIBLE int
+int
 lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
                    struct lws_jwk *jwk, struct lws_context *context)
 {
@@ -458,7 +461,7 @@ lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
        if (!map_b64->buf[LJWS_SIG] && !map->buf[LJWS_UHDR])
                b = 2;
 
-       if (lws_jws_parse_jose(&jose, map->buf[LJWS_JOSE], map->len[LJWS_JOSE],
+       if (lws_jws_parse_jose(&jose, map->buf[LJWS_JOSE], (int)map->len[LJWS_JOSE],
                               temp, &temp_len) < 0 || !jose.alg) {
                lwsl_notice("%s: parse failed\n", __func__);
                return -1;
@@ -513,7 +516,7 @@ lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
 
                        return -1;
                }
-               h_len = lws_genhash_size(jose.alg->hash_type);
+               // h_len = lws_genhash_size(jose.alg->hash_type);
 
                if (lws_genrsa_create(&rsactx, jwk->e, context, padding,
                                LWS_GENHASH_TYPE_UNKNOWN)) {
@@ -539,7 +542,7 @@ lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
 
                /* SHA256/384/512 HMAC */
 
-               h_len = lws_genhmac_size(jose.alg->hmac_type);
+               h_len = (int)lws_genhmac_size(jose.alg->hmac_type);
 
                /* 6) compute HMAC over payload */
 
@@ -568,7 +571,7 @@ lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
 
                /* 7) Compare the computed and decoded hashes */
 
-               if (lws_timingsafe_bcmp(digest, map->buf[2], h_len)) {
+               if (lws_timingsafe_bcmp(digest, map->buf[2], (uint32_t)h_len)) {
                        lwsl_notice("digest mismatch\n");
 
                        return -1;
@@ -626,7 +629,7 @@ lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
                        return -1;
                }
 
-               h_len = lws_genhash_size(jose.alg->hash_type);
+               h_len = (int)lws_genhash_size(jose.alg->hash_type);
 
                if (lws_genecdsa_create(&ecdsactx, context, NULL)) {
                        lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
@@ -663,7 +666,7 @@ lws_jws_sig_confirm(struct lws_jws_map *map_b64, struct lws_jws_map *map,
 
 /* it's already a b64 map, we will make a temp plain version */
 
-LWS_VISIBLE int
+int
 lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
                                    struct lws_jwk *jwk,
                                    struct lws_context *context,
@@ -684,7 +687,7 @@ lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
  * plain version
  */
 
-LWS_VISIBLE int
+int
 lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
                                struct lws_jws_map *map, struct lws_jwk *jwk,
                                struct lws_context *context,
@@ -693,10 +696,10 @@ lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
        struct lws_jws_map map_b64;
        int n;
 
-       if (lws_jws_b64_compact_map(in, len, &map_b64) < 0)
+       if (lws_jws_b64_compact_map(in, (int)len, &map_b64) < 0)
                return -1;
 
-       n = lws_jws_compact_decode(in, len, map, &map_b64, temp, temp_len);
+       n = lws_jws_compact_decode(in, (int)len, map, &map_b64, temp, temp_len);
        if (n > 3 || n < 0)
                return -1;
 
@@ -705,7 +708,7 @@ lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
 
 /* it's already plain, we will make a temp b64 version */
 
-LWS_VISIBLE int
+int
 lws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk,
                            struct lws_context *context, char *temp,
                            int *temp_len)
@@ -724,7 +727,8 @@ lws_jws_sig_confirm_json(const char *in, size_t len,
                         struct lws_context *context,
                         char *temp, int *temp_len)
 {
-       if (lws_jws_json_parse(jws, (const uint8_t *)in, len, temp, temp_len)) {
+       if (lws_jws_json_parse(jws, (const uint8_t *)in,
+                              (int)len, temp, temp_len)) {
                lwsl_err("%s: lws_jws_json_parse failed\n", __func__);
 
                return -1;
@@ -779,13 +783,13 @@ lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws,
                        return -1;
                }
 
-               n = jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len;
-               buf = lws_malloc(lws_base64_size(n), "jws sign");
+               n = (int)jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len;
+               buf = lws_malloc((unsigned int)lws_base64_size(n), "jws sign");
                if (!buf)
                        return -1;
 
                n = lws_genrsa_hash_sign(&rsactx, digest, jose->alg->hash_type,
-                                        buf, n);
+                                        buf, (unsigned int)n);
                lws_genrsa_destroy(&rsactx);
                if (n < 0) {
                        lwsl_err("%s: lws_genrsa_hash_sign failed\n", __func__);
@@ -794,7 +798,7 @@ lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws,
                        return -1;
                }
 
-               n = lws_jws_base64_enc((char *)buf, n, b64_sig, sig_len);
+               n = lws_jws_base64_enc((char *)buf, (unsigned int)n, b64_sig, sig_len);
                lws_free(buf);
                if (n < 0) {
                        lwsl_err("%s: lws_jws_base64_enc failed\n", __func__);
@@ -843,14 +847,14 @@ lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws,
                        return -1;
                }
                m = lws_gencrypto_bits_to_bytes(jose->alg->keybits_fixed) * 2;
-               buf = lws_malloc(m, "jws sign");
+               buf = lws_malloc((unsigned int)m, "jws sign");
                if (!buf)
                        return -1;
 
                n = lws_genecdsa_hash_sign_jws(&ecdsactx, digest,
                                               jose->alg->hash_type,
                                               jose->alg->keybits_fixed,
-                                              (uint8_t *)buf, m);
+                                              (uint8_t *)buf, (unsigned int)m);
                lws_genec_destroy(&ecdsactx);
                if (n < 0) {
                        lws_free(buf);
@@ -859,7 +863,7 @@ lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws,
                        return -1;
                }
 
-               n = lws_jws_base64_enc((char *)buf, m, b64_sig, sig_len);
+               n = lws_jws_base64_enc((char *)buf, (unsigned int)m, b64_sig, sig_len);
                lws_free(buf);
 
                return n;
@@ -884,7 +888,7 @@ lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws,
  *   }
  */
 
-LWS_VISIBLE int
+int
 lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len)
 {
        size_t n = 0;
@@ -892,25 +896,34 @@ lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len)
        if (len < 1)
                return 1;
 
-       n += lws_snprintf(flattened + n, len - n , "{\"payload\": \"%.*s\",\n",
-                         jws->map_b64.len[LJWS_PYLD],
-                         jws->map_b64.buf[LJWS_PYLD]);
-
-       n += lws_snprintf(flattened + n, len - n , " \"protected\": \"%.*s\",\n",
-                         jws->map_b64.len[LJWS_JOSE],
-                         jws->map_b64.buf[LJWS_JOSE]);
+       n += (unsigned int)lws_snprintf(flattened + n, len - n , "{\"payload\": \"");
+       lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_PYLD],
+                       jws->map_b64.len[LJWS_PYLD], len - n);
+       n = n + strlen(flattened + n);
+
+       n += (unsigned int)lws_snprintf(flattened + n, len - n , "\",\n \"protected\": \"");
+       lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_JOSE],
+                       jws->map_b64.len[LJWS_JOSE], len - n);
+       n = n + strlen(flattened + n);
+
+       if (jws->map_b64.buf[LJWS_UHDR]) {
+               n += (unsigned int)lws_snprintf(flattened + n, len - n , "\",\n \"header\": ");
+               lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_UHDR],
+                               jws->map_b64.len[LJWS_UHDR], len - n);
+               n = n + strlen(flattened + n);
+       }
 
-       if (jws->map_b64.buf[LJWS_UHDR])
-               n += lws_snprintf(flattened + n, len - n , " \"header\": %.*s,\n",
-                         jws->map_b64.len[LJWS_UHDR], jws->map_b64.buf[LJWS_UHDR]);
+       n += (unsigned int)lws_snprintf(flattened + n, len - n , "\",\n \"signature\": \"");
+       lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_SIG],
+                       jws->map_b64.len[LJWS_SIG], len - n);
+       n = n + strlen(flattened + n);
 
-       n += lws_snprintf(flattened + n, len - n , " \"signature\": \"%.*s\"}\n",
-                       jws->map_b64.len[LJWS_SIG], jws->map_b64.buf[LJWS_SIG]);
+       n += (unsigned int)lws_snprintf(flattened + n, len - n , "\"}\n");
 
        return (n >= len - 1);
 }
 
-LWS_VISIBLE int
+int
 lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len)
 {
        size_t n = 0;
@@ -918,12 +931,375 @@ lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len)
        if (len < 1)
                return 1;
 
-       n += lws_snprintf(compact + n, len - n , "%.*s",
-                         jws->map_b64.len[LJWS_JOSE], jws->map_b64.buf[LJWS_JOSE]);
-       n += lws_snprintf(compact + n, len - n , ".%.*s",
-                         jws->map_b64.len[LJWS_PYLD], jws->map_b64.buf[LJWS_PYLD]);
-       n += lws_snprintf(compact + n, len - n , ".%.*s",
-                         jws->map_b64.len[LJWS_SIG], jws->map_b64.buf[LJWS_SIG]);
+       lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_JOSE],
+                    jws->map_b64.len[LJWS_JOSE], len - n);
+       n += strlen(compact + n);
+       if (n >= len - 1)
+               return 1;
+       compact[n++] = '.';
+       lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_PYLD],
+                    jws->map_b64.len[LJWS_PYLD], len - n);
+       n += strlen(compact + n);
+       if (n >= len - 1)
+               return 1;
+       compact[n++] = '.';
+       lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_SIG],
+                    jws->map_b64.len[LJWS_SIG], len - n);
+       n += strlen(compact + n);
 
        return n >= len - 1;
 }
+
+int
+lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
+                       const char *alg_list, const char *com, size_t len,
+                       char *temp, int tl, char *out, size_t *out_len)
+{
+       struct lws_tokenize ts;
+       struct lws_jose jose;
+       int otl = tl, r = 1;
+       struct lws_jws jws;
+       size_t n;
+
+       memset(&jws, 0, sizeof(jws));
+       lws_jose_init(&jose);
+
+       /*
+        * Decode the b64.b64[.b64] compact serialization
+        * blocks
+        */
+
+       n = (size_t)lws_jws_compact_decode(com, (int)len, &jws.map, &jws.map_b64,
+                                  temp, &tl);
+       if (n != 3) {
+               lwsl_err("%s: concat_map failed: %d\n", __func__, (int)n);
+               goto bail;
+       }
+
+       temp += otl - tl;
+       otl = tl;
+
+       /*
+        * Parse the JOSE header
+        */
+
+       if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE],
+                              (int)jws.map.len[LJWS_JOSE], temp, &tl) < 0) {
+               lwsl_err("%s: JOSE parse failed\n", __func__);
+               goto bail;
+       }
+
+       /*
+        * Insist to see an alg in there that we list as acceptable
+        */
+
+       lws_tokenize_init(&ts, alg_list, LWS_TOKENIZE_F_COMMA_SEP_LIST |
+                                        LWS_TOKENIZE_F_RFC7230_DELIMS);
+       n = strlen(jose.alg->alg);
+
+       do {
+               ts.e = (int8_t)lws_tokenize(&ts);
+               if (ts.e == LWS_TOKZE_TOKEN && ts.token_len == n &&
+                   !strncmp(jose.alg->alg, ts.token, ts.token_len))
+                       break;
+       } while (ts.e != LWS_TOKZE_ENDED);
+
+       if (ts.e != LWS_TOKZE_TOKEN) {
+               lwsl_err("%s: JOSE using alg %s (accepted: %s)\n", __func__,
+                        jose.alg->alg, alg_list);
+               goto bail;
+       }
+
+       /* we liked the alg... now how about the crypto? */
+
+       if (lws_jws_sig_confirm(&jws.map_b64, &jws.map, jwk, ctx) < 0) {
+               lwsl_notice("%s: confirm JWT sig failed\n",
+                           __func__);
+               goto bail;
+       }
+
+       /* yeah, it's validated... see about copying it out */
+
+       if (*out_len < jws.map.len[LJWS_PYLD] + 1) {
+               /* we don't have enough room */
+               r = 2;
+               goto bail;
+       }
+
+       memcpy(out, jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]);
+       *out_len = jws.map.len[LJWS_PYLD];
+       out[jws.map.len[LJWS_PYLD]] = '\0';
+
+       r = 0;
+
+bail:
+       lws_jws_destroy(&jws);
+       lws_jose_destroy(&jose);
+
+       return r;
+}
+
+static int lws_jwt_vsign_via_info(struct lws_context *ctx, struct lws_jwk *jwk,
+    const struct lws_jwt_sign_info *info, const char *format, va_list ap)
+{
+       size_t actual_hdr_len;
+       struct lws_jose jose;
+       struct lws_jws jws;
+       va_list ap_cpy;
+       int n, r = 1;
+       int otl, tlr;
+       char *p, *q;
+
+       lws_jws_init(&jws, jwk, ctx);
+       lws_jose_init(&jose);
+
+       otl = tlr = info->tl;
+       p = info->temp;
+
+       /*
+        * We either just use the provided info->jose_hdr, or build a
+        * minimal header from info->alg
+        */
+       actual_hdr_len = info->jose_hdr ? info->jose_hdr_len :
+                                         10 + strlen(info->alg);
+
+       if (actual_hdr_len > INT_MAX) {
+         goto bail;
+       }
+
+       if (lws_jws_alloc_element(&jws.map, LJWS_JOSE, info->temp, &tlr,
+                                 actual_hdr_len, 0)) {
+               lwsl_err("%s: temp space too small\n", __func__);
+               goto bail;
+       }
+
+       if (!info->jose_hdr) {
+
+               /* get algorithm from 'alg' string and write minimal JOSE header */
+               if (lws_gencrypto_jws_alg_to_definition(info->alg, &jose.alg)) {
+                       lwsl_err("%s: unknown alg %s\n", __func__, info->alg);
+
+                       goto bail;
+               }
+               jws.map.len[LJWS_JOSE] = (uint32_t)lws_snprintf(
+                               (char *)jws.map.buf[LJWS_JOSE], (size_t)otl,
+                                               "{\"alg\":\"%s\"}", info->alg);
+       } else {
+
+               /*
+                * Get algorithm by parsing the given JOSE header and copy it,
+                * if it's ok
+                */
+               if (lws_jws_parse_jose(&jose, info->jose_hdr,
+                                      (int)actual_hdr_len, info->temp, &tlr)) {
+                       lwsl_err("%s: invalid jose header\n", __func__);
+                       goto bail;
+               }
+               tlr = otl;
+               memcpy((char *)jws.map.buf[LJWS_JOSE], info->jose_hdr,
+                                                               actual_hdr_len);
+               jws.map.len[LJWS_JOSE] = (uint32_t)actual_hdr_len;
+               tlr -= (int)actual_hdr_len;
+       }
+
+       p += otl - tlr;
+       otl = tlr;
+
+       va_copy(ap_cpy, ap);
+       n = vsnprintf(NULL, 0, format, ap_cpy);
+       va_end(ap_cpy);
+       if (n + 2 >= tlr)
+               goto bail;
+
+       q = lws_malloc((unsigned int)n + 2, __func__);
+       if (!q)
+               goto bail;
+
+       vsnprintf(q, (unsigned int)n + 2, format, ap);
+
+       /* add the plaintext from stdin to the map and a b64 version */
+
+       jws.map.buf[LJWS_PYLD] = q;
+       jws.map.len[LJWS_PYLD] = (uint32_t)n;
+
+       if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_PYLD, p, &tlr,
+                                      jws.map.buf[LJWS_PYLD],
+                                      jws.map.len[LJWS_PYLD]))
+               goto bail1;
+
+       p += otl - tlr;
+       otl = tlr;
+
+       /* add the b64 JOSE header to the b64 map */
+
+       if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_JOSE, p, &tlr,
+                                      jws.map.buf[LJWS_JOSE],
+                                      jws.map.len[LJWS_JOSE]))
+               goto bail1;
+
+       p += otl - tlr;
+       otl = tlr;
+
+       /* prepare the space for the b64 signature in the map */
+
+       if (lws_jws_alloc_element(&jws.map_b64, LJWS_SIG, p, &tlr,
+                                 (size_t)lws_base64_size(LWS_JWE_LIMIT_KEY_ELEMENT_BYTES),
+                                 0))
+               goto bail1;
+
+       /* sign the plaintext */
+
+       n = lws_jws_sign_from_b64(&jose, &jws,
+                                 (char *)jws.map_b64.buf[LJWS_SIG],
+                                 jws.map_b64.len[LJWS_SIG]);
+       if (n < 0)
+               goto bail1;
+
+       /* set the actual b64 signature size */
+       jws.map_b64.len[LJWS_SIG] = (uint32_t)n;
+
+       /* create the compact JWS representation */
+       if (lws_jws_write_compact(&jws, info->out, *info->out_len))
+               goto bail1;
+
+       *info->out_len = strlen(info->out);
+
+       r = 0;
+
+bail1:
+       lws_free(q);
+
+bail:
+       jws.map.buf[LJWS_PYLD] = NULL;
+       jws.map.len[LJWS_PYLD] = 0;
+       lws_jws_destroy(&jws);
+       lws_jose_destroy(&jose);
+
+       return r;
+}
+
+int
+lws_jwt_sign_via_info(struct lws_context *ctx, struct lws_jwk *jwk,
+                    const struct lws_jwt_sign_info *info, const char *format,
+                    ...)
+{
+       int ret;
+       va_list ap;
+
+       va_start(ap, format);
+       ret = lws_jwt_vsign_via_info(ctx, jwk, info, format, ap);
+       va_end(ap);
+
+       return ret;
+}
+
+int
+lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
+                    const char *alg, char *out, size_t *out_len, char *temp,
+                    int tl, const char *format, ...)
+{
+       struct lws_jwt_sign_info info = {
+               .alg            = alg,
+               .jose_hdr       = NULL,
+               .out            = out,
+               .out_len        = out_len,
+               .temp           = temp,
+               .tl             = tl
+       };
+       int r = 1;
+       va_list ap;
+
+       va_start(ap, format);
+
+       r = lws_jwt_vsign_via_info(ctx, jwk, &info, format, ap);
+
+       va_end(ap);
+       return r;
+}
+
+int
+lws_jwt_token_sanity(const char *in, size_t in_len,
+                    const char *iss, const char *aud,
+                    const char *csrf_in,
+                    char *sub, size_t sub_len, unsigned long *expiry_unix_time)
+{
+       unsigned long now = lws_now_secs(), exp;
+       const char *cp;
+       size_t len;
+
+       /*
+        * It has our issuer?
+        */
+
+       if (lws_json_simple_strcmp(in, in_len, "\"iss\":", iss)) {
+               lwsl_notice("%s: iss mismatch\n", __func__);
+               return 1;
+       }
+
+       /*
+        * ... it is indended for us to consume? (this is set
+        * to the public base url for this sai instance)
+        */
+       if (lws_json_simple_strcmp(in, in_len, "\"aud\":", aud)) {
+               lwsl_notice("%s: aud mismatch\n", __func__);
+               return 1;
+       }
+
+       /*
+        * ...it's not too early for it?
+        */
+       cp = lws_json_simple_find(in, in_len, "\"nbf\":", &len);
+       if (!cp || (unsigned long)atol(cp) > now) {
+               lwsl_notice("%s: nbf fail\n", __func__);
+               return 1;
+       }
+
+       /*
+        * ... and not too late for it?
+        */
+       cp = lws_json_simple_find(in, in_len, "\"exp\":", &len);
+       exp = (unsigned long)atol(cp);
+       if (!cp || (unsigned long)atol(cp) < now) {
+               lwsl_notice("%s: exp fail %lu vs %lu\n", __func__,
+                               cp ? (unsigned long)atol(cp) : 0, now);
+               return 1;
+       }
+
+       /*
+        * Caller cares about subject?  Then we must have it, and it can't be
+        * empty.
+        */
+
+       if (sub) {
+               cp = lws_json_simple_find(in, in_len, "\"sub\":", &len);
+               if (!cp || !len) {
+                       lwsl_notice("%s: missing subject\n", __func__);
+                       return 1;
+               }
+               lws_strnncpy(sub, cp, len, sub_len);
+       }
+
+       /*
+        * If caller has been told a Cross Site Request Forgery (CSRF) nonce,
+        * require this JWT to express the same CSRF... this makes generated
+        * links for dangerous privileged auth'd actions expire with the JWT
+        * that was accessing the site when the links were generated.  And it
+        * leaves an attacker not knowing what links to synthesize unless he
+        * can read the token or pages generated with it.
+        *
+        * Using this is very good for security, but it implies you must refresh
+        * generated pages still when the auth token is expiring (and the user
+        * must log in again).
+        */
+
+       if (csrf_in &&
+           lws_json_simple_strcmp(in, in_len, "\"csrf\":", csrf_in)) {
+               lwsl_notice("%s: csrf mismatch\n", __func__);
+               return 1;
+       }
+
+       if (expiry_unix_time)
+               *expiry_unix_time = exp;
+
+       return 0;
+}
diff --git a/lib/jose/jws/private-lib-jose-jws.h b/lib/jose/jws/private-lib-jose-jws.h
new file mode 100644 (file)
index 0000000..e622d15
--- /dev/null
@@ -0,0 +1,27 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * JOSE is actually specified as part of JWS RFC7515.  JWE references RFC7515
+ * to specify its JOSE JSON object.  So it lives in ./lib/jose/jws/jose.c.
+ */
+
diff --git a/lib/jose/jws/private.h b/lib/jose/jws/private.h
deleted file mode 100644 (file)
index e7113d3..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * libwebsockets - JSON Web Signature support
- *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * JOSE is actually specified as part of JWS RFC7515.  JWE references RFC7515
- * to specify its JOSE JSON object.  So it lives in ./lib/jose/jws/jose.c.
- */
-
diff --git a/lib/jose/private-lib-jose.h b/lib/jose/private-lib-jose.h
new file mode 100644 (file)
index 0000000..c6508d3
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* information about each token declared above */
+
+#define F_M    (1 <<  9)       /* Mandatory for key type */
+#define F_B64  (1 << 10)       /* Base64 coded octets */
+#define F_B64U (1 << 11)       /* Base64 Url coded octets */
+#define F_META (1 << 12)       /* JWK key metainformation */
+#define F_RSA  (1 << 13)       /* RSA key */
+#define F_EC   (1 << 14)       /* Elliptic curve key */
+#define F_OCT  (1 << 15)       /* octet key */
+
+void
+lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m);
+
+int
+lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
+               char *out, size_t out_len);
+
+int
+_lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, size_t len);
+
+void
+lws_jwk_init_jps(struct lws_jwk_parse_state *jps,
+                struct lws_jwk *jwk, lws_jwk_key_import_callback cb,
+                void *user);
+
+signed char
+cb_jwk(struct lejp_ctx *ctx, char reason);
+
+extern const char * const jwk_tok[19], * const jwk_outer_tok[19];
diff --git a/lib/jose/private.h b/lib/jose/private.h
deleted file mode 100644 (file)
index 5e755f5..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * libwebsockets - jose private header
- *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-void
-lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m);
-
-void
-lws_jwk_init_jps(struct lejp_ctx *jctx, struct lws_jwk_parse_state *jps,
-                struct lws_jwk *jwk, lws_jwk_key_import_callback cb,
-                void *user);
-
-int
-lws_jose_render(struct lws_jose *jose, struct lws_jwk *aux_jwk,
-               char *out, size_t out_len);
diff --git a/lib/misc/CMakeLists.txt b/lib/misc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..337367a
--- /dev/null
@@ -0,0 +1,136 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       misc/base64-decode.c
+       misc/prng.c
+       misc/lws-ring.c)
+
+if (LWS_WITH_NETWORK)
+       list(APPEND SOURCES
+               misc/cache-ttl/lws-cache-ttl.c
+               misc/cache-ttl/heap.c
+               )
+
+       if (LWS_WITH_CACHE_NSCOOKIEJAR)
+               list(APPEND SOURCES
+                       misc/cache-ttl/file.c)
+       endif()
+
+endif()
+
+if (LWS_WITH_FTS)
+       list(APPEND SOURCES
+               misc/fts/trie.c
+               misc/fts/trie-fd.c)
+endif()
+
+# this is an older, standalone hashed disk cache
+# implementation unrelated to lws-cache-ttl
+if (LWS_WITH_DISKCACHE)
+       list(APPEND SOURCES
+               misc/diskcache.c)
+endif()
+
+if (LWS_WITH_STRUCT_JSON)
+       list(APPEND SOURCES
+               misc/lws-struct-lejp.c)
+endif()
+
+if (LWS_WITH_STRUCT_SQLITE3)
+       list(APPEND SOURCES
+               misc/lws-struct-sqlite.c)
+endif()
+
+if (LWS_WITH_FSMOUNT AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+       list(APPEND SOURCES misc/fsmount.c)
+endif()
+
+if (LWS_WITH_DIR)
+       list(APPEND SOURCES misc/dir.c)
+endif()
+
+if (LWS_WITH_THREADPOOL AND LWS_HAVE_PTHREAD_H)
+       list(APPEND SOURCES misc/threadpool/threadpool.c)
+endif()
+
+if (LWS_WITH_PEER_LIMITS)
+       list(APPEND SOURCES
+               misc/peer-limits.c)
+endif()
+
+if (LWS_WITH_LWSAC)
+       list(APPEND SOURCES
+               misc/lwsac/lwsac.c)
+       if (NOT LWS_PLAT_FREERTOS)
+               list(APPEND SOURCES
+                       misc/lwsac/cached-file.c)
+       endif()
+       if (LWS_WITH_SECURE_STREAMS_CPP)
+               list(APPEND SOURCES misc/lwsac/lwsac.cxx)
+       endif()
+endif()
+
+if (NOT LWS_WITHOUT_BUILTIN_SHA1)
+       list(APPEND SOURCES
+               misc/sha-1.c)
+endif()
+
+if (LWS_WITH_LEJP)
+       list(APPEND SOURCES
+               misc/lejp.c)
+endif()
+if (LWS_WITH_CBOR)
+       list(APPEND SOURCES
+               misc/lecp.c
+               misc/ieeehalfprecision.c)
+endif()
+
+
+if (UNIX)
+       if (NOT LWS_HAVE_GETIFADDRS)
+               list(APPEND HDR_PRIVATE misc/getifaddrs.h)
+               list(APPEND SOURCES misc/getifaddrs.c)
+       endif()
+endif()
+
+if (NOT WIN32 AND NOT LWS_WITHOUT_DAEMONIZE)
+       list(APPEND SOURCES
+               misc/daemonize.c)
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
index b46a942..9d18b33 100644 (file)
@@ -3,7 +3,7 @@
  *
  * http://base64.sourceforge.net/b64.c
  *
- * with the following license:
+ * already with MIT license, which is retained.
  *
  * LICENCE:        Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
  *
  *               Bob Trower 08/04/01 -- Create Version 0.00.00B
  *
  * I cleaned it up quite a bit to match the (linux kernel) style of the rest
- * of libwebsockets; this version is under LGPL2.1 + SLE like the rest of lws
- * since he explicitly allows sublicensing, but I give the URL above so you can
- * get the original with Bob's super-liberal terms directly if you prefer.
+ * of libwebsockets
  */
 
+#include "private-lib-core.h"
+
 #include <stdio.h>
 #include <string.h>
-#include "core/private.h"
 
 static const char encode_orig[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                             "abcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -54,15 +53,13 @@ _lws_b64_encode_string(const char *encode, const char *in, int in_len,
                       char *out, int out_size)
 {
        unsigned char triple[3];
-       int i;
-       int line = 0;
-       int done = 0;
+       int i, done = 0;
 
        while (in_len) {
                int len = 0;
                for (i = 0; i < 3; i++) {
                        if (in_len) {
-                               triple[i] = *in++;
+                               triple[i] = (unsigned char)*in++;
                                len++;
                                in_len--;
                        } else
@@ -73,14 +70,13 @@ _lws_b64_encode_string(const char *encode, const char *in, int in_len,
                        return -1;
 
                *out++ = encode[triple[0] >> 2];
-               *out++ = encode[((triple[0] & 0x03) << 4) |
-                                            ((triple[1] & 0xf0) >> 4)];
-               *out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) |
-                                            ((triple[2] & 0xc0) >> 6)] : '=');
-               *out++ = (len > 2 ? encode[triple[2] & 0x3f] : '=');
+               *out++ = encode[(((triple[0] & 0x03) << 4) & 0x30) |
+                                            (((triple[1] & 0xf0) >> 4) & 0x0f)];
+               *out++ = (char)(len > 1 ? encode[(((triple[1] & 0x0f) << 2) & 0x3c) |
+                                       (((triple[2] & 0xc0) >> 6) & 3)] : '=');
+               *out++ = (char)(len > 2 ? encode[triple[2] & 0x3f] : '=');
 
                done += 4;
-               line += 4;
        }
 
        if (done + 1 >= out_size)
@@ -91,62 +87,62 @@ _lws_b64_encode_string(const char *encode, const char *in, int in_len,
        return done;
 }
 
-LWS_VISIBLE int
+int
 lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)
 {
        return _lws_b64_encode_string(encode_orig, in, in_len, out, out_size);
 }
 
-LWS_VISIBLE int
+int
 lws_b64_encode_string_url(const char *in, int in_len, char *out, int out_size)
 {
        return _lws_b64_encode_string(encode_url, in, in_len, out, out_size);
 }
 
-/*
- * returns length of decoded string in out, or -1 if out was too small
- * according to out_size
- *
- * Only reads up to in_len chars, otherwise if in_len is -1 on entry reads until
- * the first NUL in the input.
- */
 
-static int
-_lws_b64_decode_string(const char *in, int in_len, char *out, int out_size)
+void
+lws_b64_decode_state_init(struct lws_b64state *state)
 {
-       int len, i, c = 0, done = 0;
-       unsigned char v, quad[4];
+       memset(state, 0, sizeof(*state));
+}
 
-       while (in_len && *in) {
+int
+lws_b64_decode_stateful(struct lws_b64state *s, const char *in, size_t *in_len,
+                       uint8_t *out, size_t *out_size, int final)
+{
+       const char *orig_in = in, *end_in = in + *in_len;
+       uint8_t *orig_out = out, *end_out = out + *out_size;
+
+       while (in < end_in && *in && out + 4 < end_out) {
 
-               len = 0;
-               for (i = 0; i < 4 && in_len && *in; i++) {
+               for (; s->i < 4 && in < end_in && *in; s->i++) {
+                       uint8_t v;
 
                        v = 0;
-                       c = 0;
-                       while (in_len && *in  && !v) {
-                               c = v = *in++;
-                               in_len--;
+                       s->c = 0;
+                       while (in < end_in && *in && !v) {
+                               s->c = v = (unsigned char)*in++;
                                /* support the url base64 variant too */
                                if (v == '-')
-                                       c = v = '+';
+                                       s->c = v = '+';
                                if (v == '_')
-                                       c = v = '/';
-                               v = (v < 43 || v > 122) ? 0 : decode[v - 43];
+                                       s->c = v = '/';
+                               v = (uint8_t)((v < 43 || v > 122) ? 0 : decode[v - 43]);
                                if (v)
-                                       v = (v == '$') ? 0 : v - 61;
+                                       v = (uint8_t)((v == '$') ? 0 : v - 61);
                        }
-                       if (c) {
-                               len++;
+                       if (s->c) {
+                               s->len++;
                                if (v)
-                                       quad[i] = v - 1;
+                                       s->quad[s->i] = (uint8_t)(v - 1);
                        } else
-                               quad[i] = 0;
+                               s->quad[s->i] = 0;
                }
 
-               if (out_size < (done + len + 1))
-                       /* out buffer is too small */
-                       return -1;
+               if (s->i != 4 && !final)
+                       continue;
+
+               s->i = 0;
 
                /*
                 * "The '==' sequence indicates that the last group contained
@@ -154,65 +150,96 @@ _lws_b64_decode_string(const char *in, int in_len, char *out, int out_size)
                 * bytes." (wikipedia)
                 */
 
-               if ((!in_len || !*in) && c == '=')
-                       len--;
+               if ((in >= end_in || !*in) && s->c == '=')
+                       s->len--;
 
-               if (len >= 2)
-                       *out++ = quad[0] << 2 | quad[1] >> 4;
-               if (len >= 3)
-                       *out++ = quad[1] << 4 | quad[2] >> 2;
-               if (len >= 4)
-                       *out++ = ((quad[2] << 6) & 0xc0) | quad[3];
+               if (s->len >= 2)
+                       *out++ = (uint8_t)(s->quad[0] << 2 | s->quad[1] >> 4);
+               if (s->len >= 3)
+                       *out++ = (uint8_t)(s->quad[1] << 4 | s->quad[2] >> 2);
+               if (s->len >= 4)
+                       *out++ = (uint8_t)(((s->quad[2] << 6) & 0xc0) | s->quad[3]);
 
-               done += len - 1;
+               s->done += s->len - 1;
+               s->len = 0;
        }
 
-       if (done + 1 >= out_size)
-               return -1;
-
        *out = '\0';
+       *in_len = (unsigned int)(in - orig_in);
+       *out_size = (unsigned int)(out - orig_out);
 
-       return done;
+       return 0;
 }
 
-LWS_VISIBLE int
+
+/*
+ * returns length of decoded string in out, or -1 if out was too small
+ * according to out_size
+ *
+ * Only reads up to in_len chars, otherwise if in_len is -1 on entry reads until
+ * the first NUL in the input.
+ */
+
+static size_t
+_lws_b64_decode_string(const char *in, int in_len, char *out, size_t out_size)
+{
+       struct lws_b64state state;
+       size_t il = (size_t)in_len, ol = out_size;
+
+       if (in_len == -1)
+               il = strlen(in);
+
+       lws_b64_decode_state_init(&state);
+       lws_b64_decode_stateful(&state, in, &il, (uint8_t *)out, &ol, 1);
+
+       if (!il)
+               return 0;
+
+       return ol;
+}
+
+int
 lws_b64_decode_string(const char *in, char *out, int out_size)
 {
-       return _lws_b64_decode_string(in, -1, out, out_size);
+       return (int)_lws_b64_decode_string(in, -1, out, (unsigned int)out_size);
 }
 
-LWS_VISIBLE int
+int
 lws_b64_decode_string_len(const char *in, int in_len, char *out, int out_size)
 {
-       return _lws_b64_decode_string(in, in_len, out, out_size);
+       return (int)_lws_b64_decode_string(in, in_len, out, (unsigned int)out_size);
 }
 
 #if 0
+static const char * const plaintext[] = {
+       "any carnal pleasure.",
+       "any carnal pleasure",
+       "any carnal pleasur",
+       "any carnal pleasu",
+       "any carnal pleas",
+       "Admin:kloikloi"
+};
+static const char * const coded[] = {
+       "YW55IGNhcm5hbCBwbGVhc3VyZS4=",
+       "YW55IGNhcm5hbCBwbGVhc3VyZQ==",
+       "YW55IGNhcm5hbCBwbGVhc3Vy",
+       "YW55IGNhcm5hbCBwbGVhc3U=",
+       "YW55IGNhcm5hbCBwbGVhcw==",
+       "QWRtaW46a2xvaWtsb2k="
+};
+
 int
 lws_b64_selftest(void)
 {
        char buf[64];
        unsigned int n,  r = 0;
        unsigned int test;
+
+       lwsl_notice("%s\n", __func__);
+
        /* examples from https://en.wikipedia.org/wiki/Base64 */
-       static const char * const plaintext[] = {
-               "any carnal pleasure.",
-               "any carnal pleasure",
-               "any carnal pleasur",
-               "any carnal pleasu",
-               "any carnal pleas",
-               "Admin:kloikloi"
-       };
-       static const char * const coded[] = {
-               "YW55IGNhcm5hbCBwbGVhc3VyZS4=",
-               "YW55IGNhcm5hbCBwbGVhc3VyZQ==",
-               "YW55IGNhcm5hbCBwbGVhc3Vy",
-               "YW55IGNhcm5hbCBwbGVhc3U=",
-               "YW55IGNhcm5hbCBwbGVhcw==",
-               "QWRtaW46a2xvaWtsb2k="
-       };
-
-       for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) {
+
+       for (test = 0; test < (int)LWS_ARRAY_SIZE(plaintext); test++) {
 
                buf[sizeof(buf) - 1] = '\0';
                n = lws_b64_encode_string(plaintext[test],
@@ -226,15 +253,20 @@ lws_b64_selftest(void)
                buf[sizeof(buf) - 1] = '\0';
                n = lws_b64_decode_string(coded[test], buf, sizeof buf);
                if (n != strlen(plaintext[test]) ||
-                                                strcmp(buf, plaintext[test])) {
+                   strcmp(buf, plaintext[test])) {
                        lwsl_err("Failed lws_b64 decode selftest "
-                                "%d result '%s' / '%s', %d / %d\n",
-                                test, buf, plaintext[test], n, strlen(plaintext[test]));
+                                "%d result '%s' / '%s', %d / %zu\n",
+                                test, buf, plaintext[test], n,
+                                strlen(plaintext[test]));
+                       lwsl_hexdump_err(buf, n);
                        r = -1;
                }
        }
 
-       lwsl_notice("Base 64 selftests passed\n");
+       if (!r)
+               lwsl_notice("Base 64 selftests passed\n");
+       else
+               lwsl_notice("Base64 selftests failed\n");
 
        return r;
 }
diff --git a/lib/misc/cache-ttl/file.c b/lib/misc/cache-ttl/file.c
new file mode 100644 (file)
index 0000000..3307faf
--- /dev/null
@@ -0,0 +1,960 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Implements a cache backing store compatible with netscape cookies.txt format
+ * There is one entry per "line", and fields are tab-delimited
+ *
+ * We need to know the format here, because while the unique cookie tag consists
+ * of "hostname|urlpath|cookiename", that does not appear like that in the file;
+ * we have to go parse the fields and synthesize the corresponding tag.
+ *
+ * We rely on all the fields except the cookie value fitting in a 256 byte
+ * buffer, and allow eating multiple buffers to get a huge cookie values.
+ *
+ * Because the cookie file is a device-wide asset, although lws will change it
+ * from the lws thread without conflict, there may be other processes that will
+ * change it by removal and regenerating the file asynchronously.  For that
+ * reason, file handles are opened fresh each time we want to use the file, so
+ * we always get the latest version.
+ *
+ * When updating the file ourselves, we use a lockfile to ensure our process
+ * has exclusive access.
+ *
+ *
+ * Tag Matching rules
+ *
+ * There are three kinds of tag matching rules
+ *
+ * 1) specific - tag strigs must be the same
+ * 2) wilcard - tags matched using optional wildcards
+ * 3) wildcard + lookup - wildcard, but path part matches using cookie scope rules
+ *
+ */
+
+#include <private-lib-core.h>
+#include "private-lib-misc-cache-ttl.h"
+
+typedef enum nsc_iterator_ret {
+       NIR_CONTINUE            = 0,
+       NIR_FINISH_OK           = 1,
+       NIR_FINISH_ERROR        = -1
+} nsc_iterator_ret_t;
+
+typedef enum cbreason {
+       LCN_SOL                 = (1 << 0),
+       LCN_EOL                 = (1 << 1)
+} cbreason_t;
+
+typedef int (*nsc_cb_t)(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
+                       const char *buf, size_t size);
+
+static void
+expiry_cb(lws_sorted_usec_list_t *sul);
+
+static int
+nsc_backing_open_lock(lws_cache_nscookiejar_t *cache, int mode, const char *par)
+{
+       int sanity = 50;
+       char lock[128];
+       int fd_lock, fd;
+
+       lwsl_debug("%s: %s\n", __func__, par);
+
+       lws_snprintf(lock, sizeof(lock), "%s.LCK",
+                       cache->cache.info.u.nscookiejar.filepath);
+
+       do {
+               fd_lock = open(lock, LWS_O_CREAT | O_EXCL, 0600);
+               if (fd_lock >= 0) {
+                       close(fd_lock);
+                       break;
+               }
+
+               if (!sanity--) {
+                       lwsl_warn("%s: unable to lock %s: errno %d\n", __func__,
+                                       lock, errno);
+                       return -1;
+               }
+
+#if defined(WIN32)
+               Sleep(100);
+#else
+               usleep(100000);
+#endif
+       } while (1);
+
+       fd = open(cache->cache.info.u.nscookiejar.filepath,
+                     LWS_O_CREAT | mode, 0600);
+
+       if (fd == -1) {
+               lwsl_warn("%s: unable to open or create %s\n", __func__,
+                               cache->cache.info.u.nscookiejar.filepath);
+               unlink(lock);
+       }
+
+       return fd;
+}
+
+static void
+nsc_backing_close_unlock(lws_cache_nscookiejar_t *cache, int fd)
+{
+       char lock[128];
+
+       lwsl_debug("%s\n", __func__);
+
+       lws_snprintf(lock, sizeof(lock), "%s.LCK",
+                       cache->cache.info.u.nscookiejar.filepath);
+       if (fd >= 0)
+               close(fd);
+       unlink(lock);
+}
+
+/*
+ * We're going to call the callback with chunks of the file with flags
+ * indicating we're giving it the start of a line and / or giving it the end
+ * of a line.
+ *
+ * It's like this because the cookie value may be huge (and to a lesser extent
+ * the path may also be big).
+ *
+ * If it's the start of a line (flags on the cb has LCN_SOL), then the buffer
+ * contains up to the first 256 chars of the line, it's enough to match with.
+ *
+ * We cannot hold the file open inbetweentimes, since other processes may
+ * regenerate it, so we need to bind to a new inode.  We open it with an
+ * exclusive flock() so other processes can't replace conflicting changes
+ * while we also write changes, without having to wait and see our changes.
+ */
+
+static int
+nscookiejar_iterate(lws_cache_nscookiejar_t *cache, int fd,
+                   nsc_cb_t cb, void *opaque)
+{
+       int m = 0, n = 0, e, r = LCN_SOL, ignore = 0, ret = 0;
+       char temp[256], eof = 0;
+
+       if (lseek(fd, 0, SEEK_SET) == (off_t)-1)
+               return -1;
+
+       do { /* for as many buffers in the file */
+
+               int n1;
+
+               lwsl_debug("%s: n %d, m %d\n", __func__, n, m);
+
+read:
+               n1 = (int)read(fd, temp + n, sizeof(temp) - (size_t)n);
+
+               lwsl_debug("%s: n1 %d\n", __func__, n1);
+
+               if (n1 <= 0) {
+                       eof = 1;
+                       if (m == n)
+                               continue;
+               } else
+                       n += n1;
+
+               while (m < n) {
+
+                       m++;
+
+                       if (temp[m - 1] != '\n')
+                               continue;
+
+                       /* ie, we hit EOL */
+
+                       if (temp[0] == '#')
+                               /* lines starting with # are comments */
+                               e = 0;
+                       else
+                               e = cb(cache, opaque, r | LCN_EOL, temp,
+                                      (size_t)m - 1);
+                       r = LCN_SOL;
+                       ignore = 0;
+                       /*
+                        * Move back remainder and prefill the gap that opened
+                        * up: we want to pass enough in the start chunk so the
+                        * cb can classify it even if it can't get all the
+                        * value part in one go
+                        */
+                       memmove(temp, temp + m, (size_t)(n - m));
+                       n -= m;
+                       m = 0;
+
+                       if (e) {
+                               ret = e;
+                               goto bail;
+                       }
+
+                       goto read;
+               }
+
+               if (m) {
+                       /* we ran out of buffer */
+                       if (ignore || (r == LCN_SOL && n && temp[0] == '#')) {
+                               e = 0;
+                               ignore = 1;
+                       } else {
+                               e = cb(cache, opaque,
+                                      r | (n == m && eof ? LCN_EOL : 0),
+                                      temp, (size_t)m);
+
+                               m = 0;
+                               n = 0;
+                       }
+
+                       if (e) {
+                               /*
+                                * We have to call off the whole thing if any
+                                * step, eg, OOMs
+                                */
+                               ret = e;
+                               goto bail;
+                       }
+                       r = 0;
+               }
+
+       } while (!eof || n != m);
+
+       ret = 0;
+
+bail:
+
+       return ret;
+}
+
+/*
+ * lookup() just handles wildcard resolution, it doesn't deal with moving the
+ * hits to L1.  That has to be done individually by non-wildcard names.
+ */
+
+enum {
+       NSC_COL_HOST            = 0, /* wc idx 0 */
+       NSC_COL_PATH            = 2, /* wc idx 1 */
+       NSC_COL_EXPIRY          = 4,
+       NSC_COL_NAME            = 5, /* wc idx 2 */
+
+       NSC_COL_COUNT           = 6
+};
+
+/*
+ * This performs the specialized wildcard that knows about cookie path match
+ * rules.
+ *
+ * To defeat the lookup path matching, lie to it about idx being NSC_COL_PATH
+ */
+
+static int
+nsc_match(const char *wc, size_t wc_len, const char *col, size_t col_len,
+         int idx)
+{
+       size_t n = 0;
+
+       if (idx != NSC_COL_PATH)
+               return lws_strcmp_wildcard(wc, wc_len, col, col_len);
+
+       /*
+        * Cookie path match is special, if we lookup on a path like /my/path,
+        * we must match on cookie paths for every dir level including /, so
+        * match on /, /my, and /my/path.  But we must not match on /m or
+        * /my/pa etc.  If we lookup on /, we must not match /my/path
+        *
+        * Let's go through wc checking at / and for every complete subpath if
+        * it is an explicit match
+        */
+
+       if (!strcmp(col, wc))
+               return 0; /* exact hit */
+
+       while (n <= wc_len) {
+               if (n == wc_len || wc[n] == '/') {
+                       if (n && col_len <= n && !strncmp(wc, col, n))
+                               return 0; /* hit */
+
+                       if (n != wc_len && col_len <= n + 1 &&
+                           !strncmp(wc, col, n + 1)) /* check for trailing / */
+                               return 0; /* hit */
+               }
+               n++;
+       }
+
+       return 1; /* fail */
+}
+
+static const uint8_t nsc_cols[] = { NSC_COL_HOST, NSC_COL_PATH, NSC_COL_NAME };
+
+static int
+lws_cache_nscookiejar_tag_match(struct lws_cache_ttl_lru *cache,
+                               const char *wc, const char *tag, char lookup)
+{
+       const char *wc_end = wc + strlen(wc), *tag_end = tag + strlen(tag),
+                       *start_wc, *start_tag;
+       int n = 0;
+
+       lwsl_cache("%s: '%s' vs '%s'\n", __func__, wc, tag);
+
+       /*
+        * Given a well-formed host|path|name tag and a wildcard term,
+        * make the determination if the tag matches the wildcard or not,
+        * using lookup rules that apply at this cache level.
+        */
+
+       while (n < 3) {
+               start_wc = wc;
+               while (wc < wc_end && *wc != LWSCTAG_SEP)
+                       wc++;
+
+               start_tag = tag;
+               while (tag < tag_end && *tag != LWSCTAG_SEP)
+                       tag++;
+
+               lwsl_cache("%s:   '%.*s' vs '%.*s'\n", __func__,
+                               lws_ptr_diff(wc, start_wc), start_wc,
+                               lws_ptr_diff(tag, start_tag), start_tag);
+               if (nsc_match(start_wc, lws_ptr_diff_size_t(wc, start_wc),
+                             start_tag, lws_ptr_diff_size_t(tag, start_tag),
+                             lookup ? nsc_cols[n] : NSC_COL_HOST)) {
+                       lwsl_cache("%s: fail\n", __func__);
+                       return 1;
+               }
+
+               if (wc < wc_end)
+                       wc++;
+               if (tag < tag_end)
+                       tag++;
+
+               n++;
+       }
+
+       lwsl_cache("%s: hit\n", __func__);
+
+       return 0; /* match */
+}
+
+/*
+ * Converts the start of a cookie file line into a tag
+ */
+
+static int
+nsc_line_to_tag(const char *buf, size_t size, char *tag, size_t max_tag,
+               lws_usec_t *pexpiry)
+{
+       int n, idx = 0, tl = 0;
+       lws_usec_t expiry = 0;
+       size_t bn = 0;
+       char col[64];
+
+       if (size < 3)
+               return 1;
+
+       while (bn < size && idx <= NSC_COL_NAME) {
+
+               n = 0;
+               while (bn < size && n < (int)sizeof(col) - 1 &&
+                      buf[bn] != '\t')
+                       col[n++] = buf[bn++];
+               col[n] = '\0';
+               if (buf[bn] == '\t')
+                       bn++;
+
+               switch (idx) {
+               case NSC_COL_EXPIRY:
+                       expiry = (lws_usec_t)((unsigned long long)atoll(col) *
+                                       (lws_usec_t)LWS_US_PER_SEC);
+                       break;
+
+               case NSC_COL_HOST:
+               case NSC_COL_PATH:
+               case NSC_COL_NAME:
+
+                       /*
+                        * As we match the pieces of the wildcard,
+                        * compose the matches into a specific tag
+                        */
+
+                       if (tl + n + 2 > (int)max_tag)
+                               return 1;
+                       if (tl)
+                               tag[tl++] = LWSCTAG_SEP;
+                       memcpy(tag + tl, col, (size_t)n);
+                       tl += n;
+                       tag[tl] = '\0';
+                       break;
+               default:
+                       break;
+               }
+
+               idx++;
+       }
+
+       if (pexpiry)
+               *pexpiry = expiry;
+
+       lwsl_info("%s: %.*s: tag '%s'\n", __func__, (int)size, buf, tag);
+
+       return 0;
+}
+
+struct nsc_lookup_ctx {
+       const char              *wildcard_key;
+       lws_dll2_owner_t        *results_owner;
+       lws_cache_match_t       *match; /* current match if any */
+       size_t                  wklen;
+};
+
+
+static int
+nsc_lookup_cb(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
+             const char *buf, size_t size)
+{
+       struct nsc_lookup_ctx *ctx = (struct nsc_lookup_ctx *)opaque;
+       lws_usec_t expiry;
+       char tag[200];
+       int tl;
+
+       if (!(flags & LCN_SOL)) {
+               if (ctx->match)
+                       ctx->match->payload_size += size;
+
+               return NIR_CONTINUE;
+       }
+
+       /*
+        * There should be enough in buf to match or reject it... let's
+        * synthesize a tag from the text "line" and then check the tags for
+        * a match
+        */
+
+       ctx->match = NULL; /* new SOL means stop tracking payload len */
+
+       if (nsc_line_to_tag(buf, size, tag, sizeof(tag), &expiry))
+               return NIR_CONTINUE;
+
+       if (lws_cache_nscookiejar_tag_match(&cache->cache,
+                                           ctx->wildcard_key, tag, 1))
+               return NIR_CONTINUE;
+
+       tl = (int)strlen(tag);
+
+       /*
+        * ... it looks like a match then... create new match
+        * object with the specific tag, and add it to the owner list
+        */
+
+       ctx->match = lws_fi(&cache->cache.info.cx->fic, "cache_lookup_oom") ? NULL :
+                       lws_malloc(sizeof(*ctx->match) + (unsigned int)tl + 1u,
+                               __func__);
+       if (!ctx->match)
+               /* caller of lookup will clean results list on fail */
+               return NIR_FINISH_ERROR;
+
+       ctx->match->payload_size = size;
+       ctx->match->tag_size = (size_t)tl;
+       ctx->match->expiry = expiry;
+
+       memset(&ctx->match->list, 0, sizeof(ctx->match->list));
+       memcpy(&ctx->match[1], tag, (size_t)tl + 1u);
+       lws_dll2_add_tail(&ctx->match->list, ctx->results_owner);
+
+       return NIR_CONTINUE;
+}
+
+static int
+lws_cache_nscookiejar_lookup(struct lws_cache_ttl_lru *_c,
+                            const char *wildcard_key,
+                            lws_dll2_owner_t *results_owner)
+{
+       lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
+       struct nsc_lookup_ctx ctx;
+       int ret, fd;
+
+       fd = nsc_backing_open_lock(cache, LWS_O_RDONLY, __func__);
+       if (fd < 0)
+               return 1;
+
+       ctx.wildcard_key = wildcard_key;
+       ctx.results_owner = results_owner;
+       ctx.wklen = strlen(wildcard_key);
+       ctx.match = 0;
+
+       ret = nscookiejar_iterate(cache, fd, nsc_lookup_cb, &ctx);
+               /*
+                * The cb can fail, eg, with OOM, making the whole lookup
+                * invalid and returning fail.  Caller will clean
+                * results_owner on fail.
+                */
+       nsc_backing_close_unlock(cache, fd);
+
+       return ret == NIR_FINISH_ERROR;
+}
+
+/*
+ * It's pretty horrible having to implement add or remove individual items by
+ * file regeneration, but if we don't want to keep it all in heap, and we want
+ * this cookie jar format, that is what we are into.
+ *
+ * Allow to optionally add a "line", optionally wildcard delete tags, and always
+ * delete expired entries.
+ *
+ * Although we can rely on the lws thread to be doing this, multiple processes
+ * may be using the cookie jar and can tread on each other.  So we use flock()
+ * (linux only) to get exclusive access while we are processing this.
+ *
+ * We leave the existing file alone and generate a new one alongside it, with a
+ * fixed name.tmp format so it can't leak, if that went OK then we unlink the
+ * old and rename the new.
+ */
+
+struct nsc_regen_ctx {
+       const char              *wildcard_key_delete;
+       const void              *add_data;
+       lws_usec_t              curr;
+       size_t                  add_size;
+       int                     fdt;
+       char                    drop;
+};
+
+/* only used by nsc_regen() */
+
+static int
+nsc_regen_cb(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
+             const char *buf, size_t size)
+{
+       struct nsc_regen_ctx *ctx = (struct nsc_regen_ctx *)opaque;
+       char tag[256];
+       lws_usec_t expiry;
+
+       if (flags & LCN_SOL) {
+
+               ctx->drop = 0;
+
+               if (nsc_line_to_tag(buf, size, tag, sizeof(tag), &expiry))
+                       /* filter it out if it is unparseable */
+                       goto drop;
+
+               /* routinely track the earliest expiry */
+
+               if (!cache->earliest_expiry ||
+                   (expiry && cache->earliest_expiry > expiry))
+                       cache->earliest_expiry = expiry;
+
+               if (expiry && expiry < ctx->curr)
+                       /* routinely strip anything beyond its expiry */
+                       goto drop;
+
+               if (ctx->wildcard_key_delete)
+                       lwsl_cache("%s: %s vs %s\n", __func__,
+                                       tag, ctx->wildcard_key_delete);
+               if (ctx->wildcard_key_delete &&
+                   !lws_cache_nscookiejar_tag_match(&cache->cache,
+                                                    ctx->wildcard_key_delete,
+                                                    tag, 0)) {
+                       lwsl_cache("%s: %s matches wc delete %s\n", __func__,
+                                       tag, ctx->wildcard_key_delete);
+                       goto drop;
+               }
+       }
+
+       if (ctx->drop)
+               return 0;
+
+       cache->cache.current_footprint += (uint64_t)size;
+
+       if (write(ctx->fdt, buf, /*msvc*/(unsigned int)size) != (ssize_t)size)
+               return NIR_FINISH_ERROR;
+
+       if (flags & LCN_EOL)
+               if ((size_t)write(ctx->fdt, "\n", 1) != 1)
+                       return NIR_FINISH_ERROR;
+
+       return 0;
+
+drop:
+       ctx->drop = 1;
+
+       return NIR_CONTINUE;
+}
+
+static int
+nsc_regen(lws_cache_nscookiejar_t *cache, const char *wc_delete,
+         const void *pay, size_t pay_size)
+{
+       struct nsc_regen_ctx ctx;
+       char filepath[128];
+       int fd, ret = 1;
+
+       fd = nsc_backing_open_lock(cache, LWS_O_RDONLY, __func__);
+       if (fd < 0)
+               return 1;
+
+       lws_snprintf(filepath, sizeof(filepath), "%s.tmp",
+                       cache->cache.info.u.nscookiejar.filepath);
+       unlink(filepath);
+
+       if (lws_fi(&cache->cache.info.cx->fic, "cache_regen_temp_open"))
+               goto bail;
+
+       ctx.fdt = open(filepath, LWS_O_CREAT | LWS_O_WRONLY, 0600);
+       if (ctx.fdt < 0)
+               goto bail;
+
+       /* magic header */
+
+       if (lws_fi(&cache->cache.info.cx->fic, "cache_regen_temp_write") ||
+       /* other consumers insist to see this at start of cookie jar */
+           write(ctx.fdt, "# Netscape HTTP Cookie File\n", 28) != 28)
+               goto bail1;
+
+       /* if we are adding something, put it first */
+
+       if (pay &&
+           write(ctx.fdt, pay, /*msvc*/(unsigned int)pay_size) !=
+                                                   (ssize_t)pay_size)
+               goto bail1;
+       if (pay && write(ctx.fdt, "\n", 1u) != (ssize_t)1)
+               goto bail1;
+
+       cache->cache.current_footprint = 0;
+
+       ctx.wildcard_key_delete = wc_delete;
+       ctx.add_data = pay;
+       ctx.add_size = pay_size;
+       ctx.curr = lws_now_usecs();
+       ctx.drop = 0;
+
+       cache->earliest_expiry = 0;
+
+       if (lws_fi(&cache->cache.info.cx->fic, "cache_regen_iter_fail") ||
+           nscookiejar_iterate(cache, fd, nsc_regen_cb, &ctx))
+               goto bail1;
+
+       close(ctx.fdt);
+       ctx.fdt = -1;
+
+       if (unlink(cache->cache.info.u.nscookiejar.filepath) == -1)
+               lwsl_info("%s: unlink %s failed\n", __func__,
+                         cache->cache.info.u.nscookiejar.filepath);
+       if (rename(filepath, cache->cache.info.u.nscookiejar.filepath) == -1)
+               lwsl_info("%s: rename %s failed\n", __func__,
+                         cache->cache.info.u.nscookiejar.filepath);
+
+       if (cache->earliest_expiry)
+               lws_cache_schedule(&cache->cache, expiry_cb,
+                                  cache->earliest_expiry);
+
+       ret = 0;
+       goto bail;
+
+bail1:
+       if (ctx.fdt >= 0)
+               close(ctx.fdt);
+bail:
+       unlink(filepath);
+
+       nsc_backing_close_unlock(cache, fd);
+
+       return ret;
+}
+
+static void
+expiry_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_cache_nscookiejar_t *cache = lws_container_of(sul,
+                                       lws_cache_nscookiejar_t, cache.sul);
+
+       /*
+        * regen the cookie jar without changes, so expired are removed and
+        * new earliest expired computed
+        */
+       if (nsc_regen(cache, NULL, NULL, 0))
+               return;
+
+       if (cache->earliest_expiry)
+               lws_cache_schedule(&cache->cache, expiry_cb,
+                                  cache->earliest_expiry);
+}
+
+
+/* specific_key and expiry are ignored, since it must be encoded in payload */
+
+static int
+lws_cache_nscookiejar_write(struct lws_cache_ttl_lru *_c,
+                           const char *specific_key, const uint8_t *source,
+                           size_t size, lws_usec_t expiry, void **ppvoid)
+{
+       lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
+       char tag[128];
+
+       lwsl_cache("%s: %s: len %d\n", __func__, _c->info.name, (int)size);
+
+       assert(source);
+
+       if (nsc_line_to_tag((const char *)source, size, tag, sizeof(tag), NULL))
+               return 1;
+
+       if (ppvoid)
+               *ppvoid = NULL;
+
+       if (nsc_regen(cache, tag, source, size)) {
+               lwsl_err("%s: regen failed\n", __func__);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+struct nsc_get_ctx {
+       struct lws_buflist      *buflist;
+       const char              *specific_key;
+       const void              **pdata;
+       size_t                  *psize;
+       lws_cache_ttl_lru_t     *l1;
+       lws_usec_t              expiry;
+};
+
+/*
+ * We're looking for a specific key, if found, we want to make an entry for it
+ * in L1 and return information about that
+ */
+
+static int
+nsc_get_cb(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
+          const char *buf, size_t size)
+{
+       struct nsc_get_ctx *ctx = (struct nsc_get_ctx *)opaque;
+       char tag[200];
+       uint8_t *q;
+
+       if (ctx->buflist)
+               goto collect;
+
+       if (!(flags & LCN_SOL))
+               return NIR_CONTINUE;
+
+       if (nsc_line_to_tag(buf, size, tag, sizeof(tag), &ctx->expiry)) {
+               lwsl_err("%s: can't get tag\n", __func__);
+               return NIR_CONTINUE;
+       }
+
+       lwsl_cache("%s: %s %s\n", __func__, ctx->specific_key, tag);
+
+       if (strcmp(ctx->specific_key, tag)) {
+               lwsl_cache("%s: no match\n", __func__);
+               return NIR_CONTINUE;
+       }
+
+       /* it's a match */
+
+       lwsl_cache("%s: IS match\n", __func__);
+
+       if (!(flags & LCN_EOL))
+               goto collect;
+
+       /* it all fit in the buffer, let's create it in L1 now */
+
+       *ctx->psize = size;
+       if (ctx->l1->info.ops->write(ctx->l1,
+                                    ctx->specific_key, (const uint8_t *)buf,
+                                    size, ctx->expiry, (void **)ctx->pdata))
+               return NIR_FINISH_ERROR;
+
+       return NIR_FINISH_OK;
+
+collect:
+       /*
+        * it's bigger than one buffer-load, we have to stash what we're getting
+        * on a buflist and create it when we have it all
+        */
+
+       if (lws_buflist_append_segment(&ctx->buflist, (const uint8_t *)buf,
+                                      size))
+               goto cleanup;
+
+       if (!(flags & LCN_EOL))
+               return NIR_CONTINUE;
+
+       /* we have all the payload, create the L1 entry without payload yet */
+
+       *ctx->psize = size;
+       if (ctx->l1->info.ops->write(ctx->l1, ctx->specific_key, NULL,
+                                    lws_buflist_total_len(&ctx->buflist),
+                                    ctx->expiry, (void **)&q))
+               goto cleanup;
+       *ctx->pdata = q;
+
+       /* dump the buflist into the L1 cache entry */
+
+       do {
+               uint8_t *p;
+               size_t len = lws_buflist_next_segment_len(&ctx->buflist, &p);
+
+               memcpy(q, p, len);
+               q += len;
+
+               lws_buflist_use_segment(&ctx->buflist, len);
+       } while (ctx->buflist);
+
+       return NIR_FINISH_OK;
+
+cleanup:
+       lws_buflist_destroy_all_segments(&ctx->buflist);
+
+       return NIR_FINISH_ERROR;
+}
+
+static int
+lws_cache_nscookiejar_get(struct lws_cache_ttl_lru *_c,
+                         const char *specific_key, const void **pdata,
+                         size_t *psize)
+{
+       lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
+       struct nsc_get_ctx ctx;
+       int ret, fd;
+
+       fd = nsc_backing_open_lock(cache, LWS_O_RDONLY, __func__);
+       if (fd < 0)
+               return 1;
+
+       /* get a pointer to l1 */
+       ctx.l1 = &cache->cache;
+       while (ctx.l1->child)
+               ctx.l1 = ctx.l1->child;
+
+       ctx.pdata = pdata;
+       ctx.psize = psize;
+       ctx.specific_key = specific_key;
+       ctx.buflist = NULL;
+       ctx.expiry = 0;
+
+       ret = nscookiejar_iterate(cache, fd, nsc_get_cb, &ctx);
+
+       nsc_backing_close_unlock(cache, fd);
+
+       return ret != NIR_FINISH_OK;
+}
+
+static int
+lws_cache_nscookiejar_invalidate(struct lws_cache_ttl_lru *_c,
+                                const char *wc_key)
+{
+       lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
+
+       return nsc_regen(cache, wc_key, NULL, 0);
+}
+
+static struct lws_cache_ttl_lru *
+lws_cache_nscookiejar_create(const struct lws_cache_creation_info *info)
+{
+       lws_cache_nscookiejar_t *cache;
+
+       cache = lws_fi(&info->cx->fic, "cache_createfail") ? NULL :
+                                       lws_zalloc(sizeof(*cache), __func__);
+       if (!cache)
+               return NULL;
+
+       cache->cache.info = *info;
+
+       /*
+        * We need to scan the file, if it exists, and find the earliest
+        * expiry while cleaning out any expired entries
+        */
+       expiry_cb(&cache->cache.sul);
+
+       lwsl_notice("%s: create %s\n", __func__, info->name ? info->name : "?");
+
+       return (struct lws_cache_ttl_lru *)cache;
+}
+
+static int
+lws_cache_nscookiejar_expunge(struct lws_cache_ttl_lru *_c)
+{
+       lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
+       int r;
+
+       if (!cache)
+               return 0;
+
+       r = unlink(cache->cache.info.u.nscookiejar.filepath);
+       if (r)
+               lwsl_warn("%s: failed to unlink %s\n", __func__,
+                               cache->cache.info.u.nscookiejar.filepath);
+
+       return r;
+}
+
+static void
+lws_cache_nscookiejar_destroy(struct lws_cache_ttl_lru **_pc)
+{
+       lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)*_pc;
+
+       if (!cache)
+               return;
+
+       lws_sul_cancel(&cache->cache.sul);
+
+       lws_free_set_NULL(*_pc);
+}
+
+#if defined(_DEBUG)
+
+static int
+nsc_dump_cb(lws_cache_nscookiejar_t *cache, void *opaque, int flags,
+             const char *buf, size_t size)
+{
+       lwsl_hexdump_cache(buf, size);
+
+       return 0;
+}
+
+static void
+lws_cache_nscookiejar_debug_dump(struct lws_cache_ttl_lru *_c)
+{
+       lws_cache_nscookiejar_t *cache = (lws_cache_nscookiejar_t *)_c;
+       int fd = nsc_backing_open_lock(cache, LWS_O_RDONLY, __func__);
+
+       if (fd < 0)
+               return;
+
+       lwsl_cache("%s: %s\n", __func__, _c->info.name);
+
+       nscookiejar_iterate(cache, fd, nsc_dump_cb, NULL);
+
+       nsc_backing_close_unlock(cache, fd);
+}
+#endif
+
+const struct lws_cache_ops lws_cache_ops_nscookiejar = {
+       .create                 = lws_cache_nscookiejar_create,
+       .destroy                = lws_cache_nscookiejar_destroy,
+       .expunge                = lws_cache_nscookiejar_expunge,
+
+       .write                  = lws_cache_nscookiejar_write,
+       .tag_match              = lws_cache_nscookiejar_tag_match,
+       .lookup                 = lws_cache_nscookiejar_lookup,
+       .invalidate             = lws_cache_nscookiejar_invalidate,
+       .get                    = lws_cache_nscookiejar_get,
+#if defined(_DEBUG)
+       .debug_dump             = lws_cache_nscookiejar_debug_dump,
+#endif
+};
diff --git a/lib/misc/cache-ttl/heap.c b/lib/misc/cache-ttl/heap.c
new file mode 100644 (file)
index 0000000..4fc1692
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+#include "private-lib-misc-cache-ttl.h"
+
+#if defined(write)
+#undef write
+#endif
+
+static void
+update_sul(lws_cache_ttl_lru_t_heap_t *cache);
+
+static int
+lws_cache_heap_invalidate(struct lws_cache_ttl_lru *_c, const char *key);
+
+static int
+sort_expiry(const lws_dll2_t *a, const lws_dll2_t *b)
+{
+       const lws_cache_ttl_item_heap_t
+               *c = lws_container_of(a, lws_cache_ttl_item_heap_t, list_expiry),
+               *d = lws_container_of(b, lws_cache_ttl_item_heap_t, list_expiry);
+
+       if (c->expiry > d->expiry)
+               return 1;
+       if (c->expiry < d->expiry)
+               return -1;
+
+       return 0;
+}
+
+static void
+_lws_cache_heap_item_destroy(lws_cache_ttl_lru_t_heap_t *cache,
+                            lws_cache_ttl_item_heap_t *item)
+{
+       lwsl_cache("%s: %s (%s)\n", __func__, cache->cache.info.name,
+                       (const char *)&item[1] + item->size);
+
+       lws_dll2_remove(&item->list_expiry);
+       lws_dll2_remove(&item->list_lru);
+
+       cache->cache.current_footprint -= item->size;
+
+       update_sul(cache);
+
+       if (cache->cache.info.cb)
+               cache->cache.info.cb((void *)((uint8_t *)&item[1]), item->size);
+
+       lws_free(item);
+}
+
+static void
+lws_cache_heap_item_destroy(lws_cache_ttl_lru_t_heap_t *cache,
+                           lws_cache_ttl_item_heap_t *item, int parent_too)
+{
+       struct lws_cache_ttl_lru *backing = &cache->cache;
+       const char *tag = ((const char *)&item[1]) + item->size;
+
+       /*
+        * We're destroying a normal item?
+        */
+
+       if (*tag == META_ITEM_LEADING)
+               /* no, nothing to check here then */
+               goto post;
+
+       if (backing->info.parent)
+               backing = backing->info.parent;
+
+       /*
+        * We need to check any cached meta-results from lookups that
+        * include this normal item, and if any, invalidate the meta-results
+        * since they have to be recalculated before being used again.
+        */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  cache->items_lru.head) {
+               lws_cache_ttl_item_heap_t *i = lws_container_of(d,
+                                               lws_cache_ttl_item_heap_t,
+                                               list_lru);
+               const char *iname = ((const char *)&item[1]) + item->size;
+               uint8_t *pay = (uint8_t *)&item[1], *end = pay + item->size;
+
+               if (*iname == META_ITEM_LEADING) {
+                       size_t taglen = strlen(iname);
+
+                       /*
+                        * If the item about to be destroyed makes an
+                        * appearance on the meta results list, we must kill
+                        * the meta result item to force recalc next time
+                        */
+
+                       while (pay < end) {
+                               uint32_t tlen = lws_ser_ru32be(pay + 4);
+
+                               if (tlen == taglen &&
+                                   !strcmp((const char *)pay + 8, iname)) {
+#if defined(_DEBUG)
+                                       /*
+                                        * Sanity check that the item tag is
+                                        * really a match for that meta results
+                                        * item
+                                        */
+
+                                       assert (!backing->info.ops->tag_match(
+                                                backing, iname + 1, tag, 1));
+#endif
+                                       _lws_cache_heap_item_destroy(cache, i);
+                                       break;
+                               }
+                               pay += 8 + tlen + 1;
+                       }
+
+#if defined(_DEBUG)
+                       /*
+                        * Sanity check that the item tag really isn't a match
+                        * for that meta results item
+                        */
+
+                       assert (backing->info.ops->tag_match(backing, iname + 1,
+                                                         tag, 1));
+#endif
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+post:
+       _lws_cache_heap_item_destroy(cache, item);
+}
+
+static void
+lws_cache_item_evict_lru(lws_cache_ttl_lru_t_heap_t *cache)
+{
+       lws_cache_ttl_item_heap_t *ei;
+
+       if (!cache->items_lru.head)
+               return;
+
+       ei = lws_container_of(cache->items_lru.head,
+                             lws_cache_ttl_item_heap_t, list_lru);
+
+       lws_cache_heap_item_destroy(cache, ei, 0);
+}
+
+/*
+ * We need to weed out expired entries in the backing file
+ */
+
+static void
+expiry_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_cache_ttl_lru_t_heap_t *cache = lws_container_of(sul,
+                                       lws_cache_ttl_lru_t_heap_t, cache.sul);
+       lws_usec_t now = lws_now_usecs();
+
+       lwsl_cache("%s: %s\n", __func__, cache->cache.info.name);
+
+       while (cache->items_expiry.head) {
+               lws_cache_ttl_item_heap_t *item;
+
+               item = lws_container_of(cache->items_expiry.head,
+                                       lws_cache_ttl_item_heap_t, list_expiry);
+
+               if (item->expiry > now)
+                       return;
+
+               lws_cache_heap_item_destroy(cache, item, 1);
+       }
+}
+
+/*
+ * Let's figure out what the earliest next expiry is
+ */
+
+static int
+earliest_expiry(lws_cache_ttl_lru_t_heap_t *cache, lws_usec_t *pearliest)
+{
+       lws_cache_ttl_item_heap_t *item;
+
+       if (!cache->items_expiry.head)
+               return 1;
+
+       item = lws_container_of(cache->items_expiry.head,
+                               lws_cache_ttl_item_heap_t, list_expiry);
+
+       *pearliest = item->expiry;
+
+       return 0;
+}
+
+static void
+update_sul(lws_cache_ttl_lru_t_heap_t *cache)
+{
+       lws_usec_t earliest;
+
+       /* weed out any newly-expired */
+       expiry_cb(&cache->cache.sul);
+
+       /* figure out the next soonest expiring item */
+       if (earliest_expiry(cache, &earliest)) {
+               lws_sul_cancel(&cache->cache.sul);
+               return;
+       }
+
+       lwsl_debug("%s: setting exp %llu\n", __func__,
+                       (unsigned long long)earliest);
+
+       if (earliest)
+               lws_cache_schedule(&cache->cache, expiry_cb, earliest);
+}
+
+static lws_cache_ttl_item_heap_t *
+lws_cache_heap_specific(lws_cache_ttl_lru_t_heap_t *cache,
+                       const char *specific_key)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, d, cache->items_lru.head) {
+               lws_cache_ttl_item_heap_t *item = lws_container_of(d,
+                                               lws_cache_ttl_item_heap_t,
+                                               list_lru);
+               const char *iname = ((const char *)&item[1]) + item->size;
+
+               if (!strcmp(specific_key, iname))
+                       return item;
+
+       } lws_end_foreach_dll(d);
+
+       return NULL;
+}
+
+static int
+lws_cache_heap_tag_match(struct lws_cache_ttl_lru *cache, const char *wc,
+                               const char *tag, char lookup_rules)
+{
+       return lws_strcmp_wildcard(wc, strlen(wc), tag, strlen(tag));
+}
+
+static int
+lws_cache_heap_lookup(struct lws_cache_ttl_lru *_c, const char *wildcard_key,
+                     lws_dll2_owner_t *results_owner)
+{
+       lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c;
+       size_t sklen = strlen(wildcard_key);
+
+       lws_start_foreach_dll(struct lws_dll2 *, d, cache->items_lru.head) {
+               lws_cache_ttl_item_heap_t *item = lws_container_of(d,
+                                               lws_cache_ttl_item_heap_t,
+                                               list_lru);
+               const char *iname = ((const char *)&item[1]) + item->size;
+
+               if (!lws_strcmp_wildcard(wildcard_key, sklen, iname,
+                                        strlen(iname))) {
+                       size_t ilen = strlen(iname);
+                       lws_cache_match_t *m;
+                       char hit = 0;
+
+                       /*
+                        * It musn't already be on the list from an earlier
+                        * cache level
+                        */
+
+                       lws_start_foreach_dll(struct lws_dll2 *, e,
+                                       results_owner->head) {
+                               lws_cache_match_t *i = lws_container_of(e,
+                                                       lws_cache_match_t, list);
+                               if (i->tag_size == ilen &&
+                                   !strcmp(iname, ((const char *)&i[1]))) {
+                                       hit = 1;
+                                       break;
+                               }
+                       } lws_end_foreach_dll(e);
+
+                       if (!hit) {
+
+                               /*
+                                * it's unique, instantiate a record for it
+                                */
+
+                               m = lws_fi(&_c->info.cx->fic,
+                                          "cache_lookup_oom") ? NULL :
+                                       lws_malloc(sizeof(*m) + ilen + 1,
+                                                  __func__);
+                               if (!m) {
+                                       lws_cache_clear_matches(results_owner);
+                                       return 1;
+                               }
+
+                               memset(&m->list, 0, sizeof(m->list));
+                               m->tag_size = ilen;
+                               memcpy(&m[1], iname, ilen + 1);
+
+                               lws_dll2_add_tail(&m->list, results_owner);
+                       }
+               }
+
+       } lws_end_foreach_dll(d);
+
+       return 0;
+}
+
+static int
+lws_cache_heap_write(struct lws_cache_ttl_lru *_c, const char *specific_key,
+                    const uint8_t *source, size_t size, lws_usec_t expiry,
+                    void **ppvoid)
+{
+       lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c;
+       struct lws_cache_ttl_lru *backing = _c;
+       lws_cache_ttl_item_heap_t *item, *ei;
+       size_t kl = strlen(specific_key);
+       char *p;
+
+       lwsl_cache("%s: %s: len %d\n", __func__, _c->info.name, (int)size);
+
+       /*
+        * Is this new tag going to invalidate any existing cached meta-results?
+        *
+        * If so, let's destroy any of those first to recover the heap
+        */
+
+       if (backing->info.parent)
+               backing = backing->info.parent;
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  cache->items_lru.head) {
+               lws_cache_ttl_item_heap_t *i = lws_container_of(d,
+                                               lws_cache_ttl_item_heap_t,
+                                               list_lru);
+               const char *iname = ((const char *)&i[1]) + i->size;
+
+               if (*iname == META_ITEM_LEADING) {
+
+                       /*
+                        * If the item about to be added would match any cached
+                        * results from before it was added, we have to
+                        * invalidate them.  To check this, we have to use the
+                        * matching rules at the backing store level
+                        */
+
+                       if (!strcmp(iname + 1, specific_key))
+                               _lws_cache_heap_item_destroy(cache, i);
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+
+       /*
+        * Keep us under the limit if possible... note this will always allow
+        * caching a single large item even if it is above the limits
+        */
+
+       while ((cache->cache.info.max_footprint &&
+               cache->cache.current_footprint + size >
+                                            cache->cache.info.max_footprint) ||
+              (cache->cache.info.max_items &&
+               cache->items_lru.count + 1 > cache->cache.info.max_items))
+               lws_cache_item_evict_lru(cache);
+
+       /* remove any existing entry of the same key */
+
+       lws_cache_heap_invalidate(&cache->cache, specific_key);
+
+       item = lws_fi(&_c->info.cx->fic, "cache_write_oom") ? NULL :
+                       lws_malloc(sizeof(*item) + kl + 1u + size, __func__);
+       if (!item)
+               return 1;
+
+       cache->cache.current_footprint += item->size;
+
+       /* only need to zero down our item object */
+       memset(item, 0, sizeof(*item));
+
+       p = (char *)&item[1];
+       if (ppvoid)
+               *ppvoid = p;
+
+       /* copy the payload into place */
+       if (source)
+               memcpy(p, source, size);
+
+       /* copy the key string into place, with terminating NUL */
+       memcpy(p + size, specific_key, kl + 1);
+
+       item->expiry = expiry;
+       item->key_len = kl;
+       item->size = size;
+
+       if (expiry) {
+               /* adding to expiry is optional, on nonzero expiry */
+               lws_dll2_add_sorted(&item->list_expiry, &cache->items_expiry,
+                                   sort_expiry);
+               ei = lws_container_of(cache->items_expiry.head,
+                                     lws_cache_ttl_item_heap_t, list_expiry);
+               lwsl_debug("%s: setting exp %llu\n", __func__,
+                                               (unsigned long long)ei->expiry);
+               lws_cache_schedule(&cache->cache, expiry_cb, ei->expiry);
+       }
+
+       /* always add outselves to head of lru list */
+       lws_dll2_add_head(&item->list_lru, &cache->items_lru);
+
+       return 0;
+}
+
+static int
+lws_cache_heap_get(struct lws_cache_ttl_lru *_c, const char *specific_key,
+                  const void **pdata, size_t *psize)
+{
+       lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c;
+       lws_cache_ttl_item_heap_t *item;
+
+       item = lws_cache_heap_specific(cache, specific_key);
+       if (!item)
+               return 1;
+
+       /* we are using it, move it to lru head */
+       lws_dll2_remove(&item->list_lru);
+       lws_dll2_add_head(&item->list_lru, &cache->items_lru);
+
+       if (pdata) {
+               *pdata = (const void *)&item[1];
+               *psize = item->size;
+       }
+
+       return 0;
+}
+
+static int
+lws_cache_heap_invalidate(struct lws_cache_ttl_lru *_c, const char *specific_key)
+{
+       lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c;
+       struct lws_cache_ttl_lru *backing = _c;
+       lws_cache_ttl_item_heap_t *item;
+       const void *user;
+       size_t size;
+
+       if (lws_cache_heap_get(_c, specific_key, &user, &size))
+               return 0;
+
+       if (backing->info.parent)
+               backing = backing->info.parent;
+
+       item = (lws_cache_ttl_item_heap_t *)(((uint8_t *)user) - sizeof(*item));
+
+       /*
+        * We must invalidate any cached results that would have included this
+        */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  cache->items_lru.head) {
+               lws_cache_ttl_item_heap_t *i = lws_container_of(d,
+                                               lws_cache_ttl_item_heap_t,
+                                               list_lru);
+               const char *iname = ((const char *)&i[1]) + i->size;
+
+               if (*iname == META_ITEM_LEADING) {
+
+                       /*
+                        * If the item about to be added would match any cached
+                        * results from before it was added, we have to
+                        * invalidate them.  To check this, we have to use the
+                        * matching rules at the backing store level
+                        */
+
+                       if (!backing->info.ops->tag_match(backing, iname + 1,
+                                                         specific_key, 1))
+                               _lws_cache_heap_item_destroy(cache, i);
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       lws_cache_heap_item_destroy(cache, item, 0);
+
+       return 0;
+}
+
+static struct lws_cache_ttl_lru *
+lws_cache_heap_create(const struct lws_cache_creation_info *info)
+{
+       lws_cache_ttl_lru_t_heap_t *cache;
+
+       assert(info->cx);
+       assert(info->name);
+
+       cache = lws_fi(&info->cx->fic, "cache_createfail") ? NULL :
+                                       lws_zalloc(sizeof(*cache), __func__);
+       if (!cache)
+               return NULL;
+
+       cache->cache.info = *info;
+       if (info->parent)
+               info->parent->child = &cache->cache;
+
+       // lwsl_cache("%s: create %s\n", __func__, info->name);
+
+       return (struct lws_cache_ttl_lru *)cache;
+}
+
+static int
+destroy_dll(struct lws_dll2 *d, void *user)
+{
+       lws_cache_ttl_lru_t *_c = (struct lws_cache_ttl_lru *)user;
+       lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c;
+       lws_cache_ttl_item_heap_t *item =
+                      lws_container_of(d, lws_cache_ttl_item_heap_t, list_lru);
+
+       lws_cache_heap_item_destroy(cache, item, 0);
+
+       return 0;
+}
+
+static int
+lws_cache_heap_expunge(struct lws_cache_ttl_lru *_c)
+{
+       lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c;
+
+       lws_dll2_foreach_safe(&cache->items_lru, cache, destroy_dll);
+
+       return 0;
+}
+
+static void
+lws_cache_heap_destroy(struct lws_cache_ttl_lru **_cache)
+{
+       lws_cache_ttl_lru_t *c = *_cache;
+       lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)c;
+
+       if (!cache)
+               return;
+
+       lws_sul_cancel(&c->sul);
+
+       lws_dll2_foreach_safe(&cache->items_lru, cache, destroy_dll);
+
+       lws_free_set_NULL(*_cache);
+}
+
+#if defined(_DEBUG)
+static int
+dump_dll(struct lws_dll2 *d, void *user)
+{
+       lws_cache_ttl_item_heap_t *item =
+                      lws_container_of(d, lws_cache_ttl_item_heap_t, list_lru);
+
+       lwsl_cache("  %s: size %d, exp %llu\n",
+                  (const char *)&item[1] + item->size,
+                  (int)item->size, (unsigned long long)item->expiry);
+
+       lwsl_hexdump_cache((const char *)&item[1], item->size);
+
+       return 0;
+}
+
+static void
+lws_cache_heap_debug_dump(struct lws_cache_ttl_lru *_c)
+{
+       lws_cache_ttl_lru_t_heap_t *cache = (lws_cache_ttl_lru_t_heap_t *)_c;
+#if !defined(LWS_WITH_NO_LOGS)
+       lws_cache_ttl_item_heap_t *item = NULL;
+
+       lws_dll2_t *d = cache->items_expiry.head;
+
+       if (d)
+               item = lws_container_of(d, lws_cache_ttl_item_heap_t,
+                                               list_expiry);
+
+       lwsl_cache("%s: %s: items %d, earliest %llu\n", __func__,
+                       cache->cache.info.name, (int)cache->items_lru.count,
+                       item ? (unsigned long long)item->expiry : 0ull);
+#endif
+
+       lws_dll2_foreach_safe(&cache->items_lru, cache, dump_dll);
+}
+#endif
+
+const struct lws_cache_ops lws_cache_ops_heap = {
+       .create                 = lws_cache_heap_create,
+       .destroy                = lws_cache_heap_destroy,
+       .expunge                = lws_cache_heap_expunge,
+
+       .write                  = lws_cache_heap_write,
+       .tag_match              = lws_cache_heap_tag_match,
+       .lookup                 = lws_cache_heap_lookup,
+       .invalidate             = lws_cache_heap_invalidate,
+       .get                    = lws_cache_heap_get,
+#if defined(_DEBUG)
+       .debug_dump             = lws_cache_heap_debug_dump,
+#endif
+};
diff --git a/lib/misc/cache-ttl/lws-cache-ttl.c b/lib/misc/cache-ttl/lws-cache-ttl.c
new file mode 100644 (file)
index 0000000..0bc80ab
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+#include "private-lib-misc-cache-ttl.h"
+
+#include <assert.h>
+
+#if defined(write)
+#undef write
+#endif
+
+void
+lws_cache_clear_matches(lws_dll2_owner_t *results_owner)
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, results_owner->head) {
+               lws_cache_match_t *item = lws_container_of(d, lws_cache_match_t,
+                                                          list);
+               lws_dll2_remove(d);
+               lws_free(item);
+       } lws_end_foreach_dll_safe(d, d1);
+}
+
+void
+lws_cache_schedule(struct lws_cache_ttl_lru *cache, sul_cb_t cb, lws_usec_t e)
+{
+       lwsl_cache("%s: %s schedule %llu\n", __func__, cache->info.name,
+                       (unsigned long long)e);
+
+       lws_sul_schedule(cache->info.cx, cache->info.tsi, &cache->sul, cb,
+                        e - lws_now_usecs());
+}
+
+int
+lws_cache_write_through(struct lws_cache_ttl_lru *cache,
+                       const char *specific_key, const uint8_t *source,
+                       size_t size, lws_usec_t expiry, void **ppay)
+{
+       struct lws_cache_ttl_lru *levels[LWS_CACHE_MAX_LEVELS], *c = cache;
+       int n = 0, r = 0;
+
+       lws_cache_item_remove(cache, specific_key);
+
+       /* starting from L1 */
+
+       do {
+               levels[n++] = c;
+               c = c->info.parent;
+       } while (c && n < (int)LWS_ARRAY_SIZE(levels));
+
+       /* starting from outermost cache level */
+
+       while (n) {
+               n--;
+               r = levels[n]->info.ops->write(levels[n], specific_key,
+                                               source, size, expiry, ppay);
+       }
+
+       return r;
+}
+
+/*
+ * We want to make a list of unique keys that exist at any cache level
+ * matching a wildcard search key.
+ *
+ * If L1 has a cached version though, we will just use that.
+ */
+
+int
+lws_cache_lookup(struct lws_cache_ttl_lru *cache, const char *wildcard_key,
+                const void **pdata, size_t *psize)
+{
+       struct lws_cache_ttl_lru *l1 = cache;
+       lws_dll2_owner_t results_owner;
+       lws_usec_t expiry = 0;
+       char meta_key[128];
+       uint8_t *p, *temp;
+       size_t sum = 0;
+       int n;
+
+       memset(&results_owner, 0, sizeof(results_owner));
+       meta_key[0] = META_ITEM_LEADING;
+       lws_strncpy(&meta_key[1], wildcard_key, sizeof(meta_key) - 2);
+
+       /*
+        * If we have a cached result set in L1 already, return that
+        */
+
+       if (!l1->info.ops->get(l1, meta_key, pdata, psize))
+               return 0;
+
+       /*
+        * No, we have to do the actual lookup work in the backing store layer
+        * to get results for this...
+        */
+
+       while (cache->info.parent)
+               cache = cache->info.parent;
+
+       if (cache->info.ops->lookup(cache, wildcard_key, &results_owner)) {
+               /* eg, OOM */
+
+               lwsl_cache("%s: bs lookup fail\n", __func__);
+
+               lws_cache_clear_matches(&results_owner);
+               return 1;
+       }
+
+       /*
+        * Scan the results, we want to know how big a payload it needs in
+        * the cache, and we want to know the earliest expiry of any of the
+        * component parts, so the meta cache entry for these results can be
+        * expired when any of the results would expire.
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, d, results_owner.head) {
+               lws_cache_match_t *m = lws_container_of(d, lws_cache_match_t,
+                                                       list);
+               sum += 8; /* payload size, name length */
+               sum += m->tag_size + 1;
+
+               if (m->expiry && (!expiry || expiry < m->expiry))
+                       expiry = m->expiry;
+
+       } lws_end_foreach_dll(d);
+
+       lwsl_cache("%s: results %d, size %d\n", __func__,
+                   (int)results_owner.count, (int)sum);
+
+       temp = lws_malloc(sum, __func__);
+       if (!temp) {
+               lws_cache_clear_matches(&results_owner);
+               return 1;
+       }
+
+       /*
+        * Fill temp with the serialized results
+        */
+
+       p = temp;
+       lws_start_foreach_dll(struct lws_dll2 *, d, results_owner.head) {
+               lws_cache_match_t *m = lws_container_of(d, lws_cache_match_t,
+                                                       list);
+
+               /* we don't copy the payload in, but take note of its size */
+               lws_ser_wu32be(p, (uint32_t)m->payload_size);
+               p += 4;
+               /* length of the tag name (there is an uncounted NUL after) */
+               lws_ser_wu32be(p, (uint32_t)m->tag_size);
+               p += 4;
+
+               /* then the tag name, plus the extra NUL */
+               memcpy(p, &m[1], m->tag_size + 1);
+               p += m->tag_size + 1;
+
+       } lws_end_foreach_dll(d);
+
+       lws_cache_clear_matches(&results_owner);
+
+       /*
+        * Create the right amount of space for an L1 record of these results,
+        * with its expiry set to the earliest of the results, and copy it in
+        * from temp
+        */
+
+       n = l1->info.ops->write(l1, meta_key, temp, sum, expiry, (void **)&p);
+       /* done with temp */
+       lws_free(temp);
+
+       if (n)
+               return 1;
+
+       /* point to the results in L1 */
+
+       *pdata = p;
+       *psize = sum;
+
+       return 0;
+}
+
+int
+lws_cache_item_get(struct lws_cache_ttl_lru *cache, const char *specific_key,
+                  const void **pdata, size_t *psize)
+{
+       while (cache) {
+               if (!cache->info.ops->get(cache, specific_key, pdata, psize)) {
+                       lwsl_cache("%s: hit\n", __func__);
+                       return 0;
+               }
+
+               cache = cache->info.parent;
+       }
+
+       return 1;
+}
+
+int
+lws_cache_expunge(struct lws_cache_ttl_lru *cache)
+{
+       int ret = 0;
+
+       while (cache) {
+               ret |= cache->info.ops->expunge(cache);
+
+               cache = cache->info.parent;
+       }
+
+       return ret;
+}
+
+int
+lws_cache_item_remove(struct lws_cache_ttl_lru *cache, const char *wildcard_key)
+{
+       while (cache) {
+               if (cache->info.ops->invalidate(cache, wildcard_key))
+                       return 1;
+
+               cache = cache->info.parent;
+       }
+
+       return 0;
+}
+
+uint64_t
+lws_cache_footprint(struct lws_cache_ttl_lru *cache)
+{
+       return cache->current_footprint;
+}
+
+void
+lws_cache_debug_dump(struct lws_cache_ttl_lru *cache)
+{
+#if defined(_DEBUG)
+       if (cache->info.ops->debug_dump)
+               cache->info.ops->debug_dump(cache);
+#endif
+}
+
+int
+lws_cache_results_walk(lws_cache_results_t *walk_ctx)
+{
+       if (!walk_ctx->size)
+               return 1;
+
+       walk_ctx->payload_len = lws_ser_ru32be(walk_ctx->ptr);
+       walk_ctx->tag_len = lws_ser_ru32be(walk_ctx->ptr + 4);
+       walk_ctx->tag = walk_ctx->ptr + 8;
+
+       walk_ctx->ptr += walk_ctx->tag_len + 1 + 8;
+       walk_ctx->size -= walk_ctx->tag_len + 1 + 8;
+
+       return 0;
+}
+
+struct lws_cache_ttl_lru *
+lws_cache_create(const struct lws_cache_creation_info *info)
+{
+       assert(info);
+       assert(info->ops);
+       assert(info->name);
+       assert(info->ops->create);
+
+       return info->ops->create(info);
+}
+
+void
+lws_cache_destroy(struct lws_cache_ttl_lru **_cache)
+{
+       lws_cache_ttl_lru_t *cache = *_cache;
+
+       if (!cache)
+               return;
+
+       assert(cache->info.ops->destroy);
+
+       lws_sul_cancel(&cache->sul);
+
+       cache->info.ops->destroy(_cache);
+}
diff --git a/lib/misc/cache-ttl/private-lib-misc-cache-ttl.h b/lib/misc/cache-ttl/private-lib-misc-cache-ttl.h
new file mode 100644 (file)
index 0000000..9ff356d
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define lwsl_cache lwsl_debug
+#define lwsl_hexdump_cache lwsl_hexdump_debug
+
+#define LWS_CACHE_MAX_LEVELS 3
+
+/*
+ * If we need structure inside the cache tag names, use this character as a
+ * separator
+ */
+#define LWSCTAG_SEP '|'
+
+/*
+ * Our synthetic cache result items all have tags starting with this char
+ */
+#define META_ITEM_LEADING '!'
+
+typedef struct lws_cache_ttl_item_heap {
+       lws_dll2_t                      list_expiry;
+       lws_dll2_t                      list_lru;
+
+       lws_usec_t                      expiry;
+       size_t                          key_len;
+       size_t                          size;
+
+       /*
+        * len + key_len + 1 bytes of data overcommitted, user object first
+        * so it is well-aligned, then the NUL-terminated key name
+        */
+} lws_cache_ttl_item_heap_t;
+
+/* this is a "base class", all cache implementations have one at the start */
+
+typedef struct lws_cache_ttl_lru {
+       struct lws_cache_creation_info  info;
+       lws_sorted_usec_list_t          sul;
+       struct lws_cache_ttl_lru        *child;
+       uint64_t                        current_footprint;
+} lws_cache_ttl_lru_t;
+
+/*
+ * The heap-backed cache uses lws_dll2 linked-lists to track items that are
+ * in it.
+ */
+
+typedef struct lws_cache_ttl_lru_heap {
+       lws_cache_ttl_lru_t             cache;
+
+       lws_dll2_owner_t                items_expiry;
+       lws_dll2_owner_t                items_lru;
+} lws_cache_ttl_lru_t_heap_t;
+
+/*
+ * We want to be able to work with a large file-backed implementation even on
+ * devices that don't have heap to track what is in it.  It means if lookups
+ * reach this cache layer, we will be scanning a potentially large file.
+ *
+ * L1 caching of lookups (including null result list) reduces the expense of
+ * this on average.  We keep a copy of the last computed earliest expiry.
+ *
+ * We can't keep an open file handle here.  Because other processes may change
+ * the cookie file by deleting and replacing it, we have to open it fresh each
+ * time.
+ */
+typedef struct lws_cache_nscookiejar {
+       lws_cache_ttl_lru_t             cache;
+
+       lws_usec_t                      earliest_expiry;
+} lws_cache_nscookiejar_t;
+
+void
+lws_cache_clear_matches(lws_dll2_owner_t *results_owner);
+
+void
+lws_cache_schedule(struct lws_cache_ttl_lru *cache, sul_cb_t cb, lws_usec_t e);
index 7378f19..6dec9d6 100644 (file)
@@ -7,7 +7,7 @@
  * he replied it is Public Domain.  Use the URL above to get the original
  * Public Domain version if you want it.
  *
- * This version is LGPL2.1+SLE like the rest of libwebsockets and is
+ * This version is MIT like the rest of libwebsockets and is
  * Copyright (c)2006 - 2013 Andy Green <andy@warmcat.com>
  *
  *
@@ -26,7 +26,8 @@
 #include <unistd.h>
 #include <errno.h>
 
-#include "core/private.h"
+#include <libwebsockets.h>
+#include "private-lib-core.h"
 
 pid_t pid_daemon;
 static char *lock_path;
@@ -63,7 +64,7 @@ child_handler(int signum)
                        exit(0);
                }
                len = sprintf(sz, "%u", (unsigned int)pid_daemon);
-               sent = write(fd, sz, len);
+               sent = (int)write(fd, sz, (size_t)len);
                if (sent != len)
                        fprintf(stderr,
                          "unable to write pid to lock file %s, code=%d (%s)\n",
@@ -99,7 +100,7 @@ static void lws_daemon_closing(int sigact)
  * The process context you called from has been terminated then.
  */
 
-LWS_VISIBLE int
+int
 lws_daemonize(const char *_lock_path)
 {
        struct sigaction act;
@@ -116,7 +117,7 @@ lws_daemonize(const char *_lock_path)
                if (fd >= 0) {
                        char buf[10];
 
-                       n = read(fd, buf, sizeof(buf));
+                       n = (int)read(fd, buf, sizeof(buf));
                        close(fd);
                        if (n) {
                                int ret;
@@ -135,8 +136,8 @@ lws_daemonize(const char *_lock_path)
                        }
                }
 
-               n = strlen(_lock_path) + 1;
-               lock_path = lws_malloc(n, "daemonize lock");
+               n = (int)strlen(_lock_path) + 1;
+               lock_path = lws_malloc((unsigned int)n, "daemonize lock");
                if (!lock_path) {
                        fprintf(stderr, "Out of mem in lws_daemonize\n");
                        return 1;
index f3d8781..94a07ca 100644 (file)
@@ -1,76 +1,63 @@
 /*
- * Lws directory scan wrapper
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(NO_GNU_SOURCE_THIS_TIME)
 #define NO_GNU_SOURCE_THIS_TIME
+#endif
+#if !defined(_DARWIN_C_SOURCE)
 #define _DARWIN_C_SOURCE
+#endif
 
-#include <libwebsockets.h>
-#include "core/private.h"
+#include "private-lib-core.h"
 #include <string.h>
 #include <stdio.h>
 
-#if defined(LWS_WITH_LIBUV) && UV_VERSION_MAJOR > 0
-
-int
-lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb)
-{
-       struct lws_dir_entry lde;
-       uv_dirent_t dent;
-       uv_fs_t req;
-       int ret = 1, ir;
-       uv_loop_t loop;
-
-       ir = uv_loop_init(&loop);
-       if (ir) {
-               lwsl_err("%s: loop init failed %d\n", __func__, ir);
-       }
-
-       ir = uv_fs_scandir(&loop, &req, dirpath, 0, NULL);
-       if (ir < 0) {
-               lwsl_err("Scandir on %s failed, errno %d\n", dirpath, LWS_ERRNO);
-               return 2;
-       }
-
-       while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
-               lde.name = dent.name;
-               lde.type = (int)dent.type;
-               if (cb(dirpath, user, &lde))
-                       goto bail;
-       }
-
-       ret = 0;
+#include <sys/stat.h>
+#if defined(WIN32)
+#include <direct.h>
+#define read _read
+#define open _open
+#define close _close
+#define write _write
+#define mkdir(x,y) _mkdir(x)
+#define rmdir _rmdir
+#define unlink _unlink
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif /* win32 */
 
-bail:
-       uv_fs_req_cleanup(&req);
-       while (uv_loop_close(&loop))
-               ;
+#define COMBO_SIZEOF 512
 
-       return ret;
-}
+#if !defined(LWS_PLAT_FREERTOS)
 
+#if defined(WIN32)
+#include "../../win32port/dirent/dirent-win32.h"
 #else
-
-#if !defined(_WIN32) && !defined(LWS_WITH_ESP32)
-
 #include <dirent.h>
+#endif
 
 static int filter(const struct dirent *ent)
 {
@@ -80,12 +67,62 @@ static int filter(const struct dirent *ent)
        return 1;
 }
 
+
+#if !defined(WIN32)
+static char csep = '/';
+#else
+static char csep = '\\';
+#endif
+
+static void
+lws_dir_via_stat(char *combo, size_t l, const char *path, struct lws_dir_entry *lde)
+{
+        struct stat s;
+
+        lws_strncpy(combo + l, path, COMBO_SIZEOF - l);
+
+        lde->type = LDOT_UNKNOWN;
+
+        if (!stat(combo, &s)) {
+               switch (s.st_mode & S_IFMT) {
+               case S_IFBLK:
+                       lde->type = LDOT_BLOCK;
+                       break;
+               case S_IFCHR:
+                       lde->type = LDOT_CHAR;
+                       break;
+               case S_IFDIR:
+                       lde->type = LDOT_DIR;
+                       break;
+               case S_IFIFO:
+                       lde->type = LDOT_FIFO;
+                       break;
+#if !defined(WIN32)
+               case S_IFLNK:
+                       lde->type = LDOT_LINK;
+                       break;
+#endif
+               case S_IFREG:
+                       lde->type = LDOT_FILE;
+                       break;
+               default:
+                       break;
+               }
+        }
+}
+
 int
 lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb)
 {
        struct lws_dir_entry lde;
        struct dirent **namelist;
        int n, i, ret = 1;
+       char combo[COMBO_SIZEOF];
+       size_t l;
+
+       l = (size_t)(ssize_t)lws_snprintf(combo, COMBO_SIZEOF - 2, "%s", dirpath);
+       combo[l++] = csep;
+       combo[l] = '\0';
 
        n = scandir((char *)dirpath, &namelist, filter, alphasort);
        if (n < 0) {
@@ -94,6 +131,9 @@ lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb)
        }
 
        for (i = 0; i < n; i++) {
+#if !defined(__sun)
+               unsigned int type = namelist[i]->d_type;
+#endif
                if (strchr(namelist[i]->d_name, '~'))
                        goto skip;
                lde.name = namelist[i]->d_name;
@@ -103,78 +143,283 @@ lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb)
                 * files are LDOT_UNKNOWN
                 */
 
-#if defined(__smartos__)
-        struct stat s;
-        stat(namelist[i]->d_name, &s);
-               switch (s.st_mode) {
-               case S_IFBLK:
-                       lde.type = LDOT_BLOCK;
-                       break;
-               case S_IFCHR:
-                       lde.type = LDOT_CHAR;
-                       break;
-               case S_IFDIR:
-                       lde.type = LDOT_DIR;
-                       break;
-               case S_IFIFO:
-                       lde.type = LDOT_FIFO;
-                       break;
-               case S_IFLNK:
-                       lde.type = LDOT_LINK;
-                       break;
-               case S_IFREG:
-                       lde.type = LDOT_FILE;
-                       break;
-               default:
-                       lde.type = LDOT_UNKNOWN;
-                       break;
-               }
+#if defined(__sun)
+               lws_dir_via_stat(combo, l, namelist[i]->d_name, &lde);
 #else
-               switch (namelist[i]->d_type) {
-               case DT_BLK:
+               /*
+                * XFS on Linux doesn't fill in d_type at all, always zero.
+                */
+
+               if (DT_BLK != DT_UNKNOWN && type == DT_BLK)
                        lde.type = LDOT_BLOCK;
-                       break;
-               case DT_CHR:
+               else if (DT_CHR != DT_UNKNOWN && type == DT_CHR)
                        lde.type = LDOT_CHAR;
-                       break;
-               case DT_DIR:
+               else if (DT_DIR != DT_UNKNOWN && type == DT_DIR)
                        lde.type = LDOT_DIR;
-                       break;
-               case DT_FIFO:
+               else if (DT_FIFO != DT_UNKNOWN && type == DT_FIFO)
                        lde.type = LDOT_FIFO;
-                       break;
-               case DT_LNK:
+               else if (DT_LNK != DT_UNKNOWN && type == DT_LNK)
                        lde.type = LDOT_LINK;
-                       break;
-               case DT_REG:
+               else if (DT_REG != DT_UNKNOWN && type == DT_REG)
                        lde.type = LDOT_FILE;
-                       break;
-               case DT_SOCK:
+               else if (DT_SOCK != DT_UNKNOWN && type == DT_SOCK)
                        lde.type = LDOTT_SOCKET;
-                       break;
-               default:
+               else {
                        lde.type = LDOT_UNKNOWN;
-                       break;
+                       lws_dir_via_stat(combo, l, namelist[i]->d_name, &lde);
                }
 #endif
                if (cb(dirpath, user, &lde)) {
-                       while (i++ < n)
-                               free(namelist[i]);
+                       while (i < n)
+                               free(namelist[i++]);
+                       ret = 0; /* told to stop by cb */
                        goto bail;
                }
 skip:
                free(namelist[i]);
        }
 
-       ret = 0;
-
 bail:
        free(namelist);
 
        return ret;
 }
 
+/*
+ * Check filename against one globby filter
+ *
+ * We can support things like "*.rpm"
+ */
+
+static int
+lws_dir_glob_check(const char *nm, const char *filt)
+{
+       while (*nm) {
+               if (*filt == '*') {
+                       if (!strcmp(nm, filt + 1))
+                               return 1;
+               } else {
+                       if (*nm != *filt)
+                               return 0;
+                       filt++;
+               }
+               nm++;
+       }
+
+       return 0;
+}
+
+/*
+ * We get passed a single filter string, like "*.txt" or "mydir/\*.rpm" or so.
+ */
+
+int
+lws_dir_glob_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
+{
+       lws_dir_glob_t *filter = (lws_dir_glob_t*)user;
+       char path[384];
+
+       if (!strcmp(lde->name, ".") || !strcmp(lde->name, ".."))
+               return 0;
+
+       if (lde->type == LDOT_DIR)
+               return 0;
+
+       if (lws_dir_glob_check(lde->name, filter->filter)) {
+               lws_snprintf(path, sizeof(path), "%s%c%s", dirpath, csep,
+                                                          lde->name);
+               filter->cb(filter->user, path);
+       }
+
+       return 0;
+}
+
+int
+lws_dir_rm_rf_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
+{
+       char path[384];
+
+       if (!strcmp(lde->name, ".") || !strcmp(lde->name, ".."))
+               return 0;
+
+       lws_snprintf(path, sizeof(path), "%s%c%s", dirpath, csep, lde->name);
+
+       if (lde->type == LDOT_DIR) {
+#if !defined(WIN32) && !defined(_WIN32) && !defined(__COVERITY__)
+               char dummy[8];
+               /*
+                * hm... eg, recursive dir symlinks can show up a LDOT_DIR
+                * here.  If it's a symlink, don't recurse into it.
+                *
+                * Notice we immediately discard dummy without looking in it.
+                * There is no way to get into trouble from its lack of NUL
+                * termination in dummy[].  We just wanted to know if it was
+                * a symlink at all.
+                *
+                * Hide this from Coverity since it flags any use of readlink()
+                * even if safe.
+                */
+               if (readlink(path, dummy, sizeof(dummy)) < 0)
+#endif
+                       lws_dir(path, NULL, lws_dir_rm_rf_cb);
+
+               if (rmdir(path))
+                       lwsl_warn("%s: rmdir %s failed %d\n", __func__, path, errno);
+       } else {
+               if (unlink(path)) {
+#if defined(WIN32)
+                       SetFileAttributesA(path, FILE_ATTRIBUTE_NORMAL);
+                       if (unlink(path))
 #else
-#error "If you want lws_dir onw windows, you need libuv"
+                       if (rmdir(path))
 #endif
+                       lwsl_warn("%s: unlink %s failed %d (type %d)\n",
+                                       __func__, path, errno, lde->type);
+               }
+       }
+
+       return 0;
+}
+
+
+#endif
+
+#if defined(LWS_WITH_PLUGINS_API)
+
+struct lws_plugins_args {
+       struct lws_plugin       **pplugin;
+       const char              *_class;
+       const char              *filter;
+       each_plugin_cb_t        each;
+       void                    *each_user;
+};
+
+static int
+lws_plugins_dir_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
+{
+       struct lws_plugins_args *pa = (struct lws_plugins_args *)user;
+       char path[256], base[64], *q = base;
+       const lws_plugin_header_t *pl;
+       const char *p;
+
+       if (strlen(lde->name) < 7)
+               return 0; /* keep going */
+
+       /*
+        * The actual plugin names for protocol plugins look like
+        * "libprotocol_lws_ssh_base.so" and for event libs
+        * "libwebsockets-evlib_ev.so"... to recover the base name of
+        * "lws_ssh_base" and "evlib_ev" we strip from the left to after the
+        * first _ or -, and then truncate at the first .
+        */
+
+       p = lde->name;
+       while (*p && *p != '_' && *p != '-')
+               p++;
+       if (!*p)
+               return 0;
+       p++;
+       while (*p && *p != '.' && lws_ptr_diff(q, base) < (int)sizeof(base) - 1)
+               *q++ = *p++;
+       *q = '\0';
+
+       /* if he's given a filter, only match if base matches it */
+       if (pa->filter && strcmp(base, pa->filter))
+               return 0; /* keep going */
+
+       lws_snprintf(path, sizeof(path) - 1, "%s/%s", dirpath, lde->name);
+
+       pl = lws_plat_dlopen(pa->pplugin, path, base, pa->_class,
+                            pa->each, pa->each_user);
+
+       /*
+        * If we were looking for a specific plugin, finding it should make
+        * us stop looking (eg, to account for directory precedence of the
+        * same plugin).  If scanning for plugins in a dir, we always keep
+        * going.
+        */
+
+       return pa->filter && pl;
+}
+
+int
+lws_plugins_init(struct lws_plugin **pplugin, const char * const *d,
+                const char *_class, const char *filter,
+                each_plugin_cb_t each, void *each_user)
+{
+       struct lws_plugins_args pa;
+       char *ld_env;
+       int ret = 1;
+
+       pa.pplugin = pplugin;
+       pa._class = _class;
+       pa.each = each;
+       pa.each_user = each_user;
+       pa.filter = filter;
+
+       /*
+        * Check LD_LIBRARY_PATH override path first if present
+        */
+
+       ld_env = getenv("LD_LIBRARY_PATH");
+       if (ld_env) {
+               char temp[128];
+               struct lws_tokenize ts;
+
+               memset(&ts, 0, sizeof(ts));
+               ts.start = ld_env;
+               ts.len = strlen(ld_env);
+               ts.flags = LWS_TOKENIZE_F_SLASH_NONTERM |
+                          LWS_TOKENIZE_F_DOT_NONTERM |
+                          LWS_TOKENIZE_F_MINUS_NONTERM |
+                          LWS_TOKENIZE_F_NO_INTEGERS |
+                          LWS_TOKENIZE_F_NO_FLOATS;
+
+               do {
+                       ts.e = (int8_t)lws_tokenize(&ts);
+                       if (ts.e != LWS_TOKZE_TOKEN)
+                               continue;
+
+                       lws_strnncpy(temp, ts.token,
+                                    ts.token_len,
+                                    sizeof(temp));
+
+                       lwsl_info("%s: trying %s\n", __func__, temp);
+                       if (!lws_dir(temp, &pa, lws_plugins_dir_cb))
+                               ret = 0;
+
+               } while (ts.e > 0);
+       }
+
+       while (d && *d) {
+               lwsl_info("%s: trying %s\n", __func__, *d);
+               if (!lws_dir(*d, &pa, lws_plugins_dir_cb))
+                       ret = 0;
+
+               d++;
+       }
+
+       return ret;
+}
+
+int
+lws_plugins_destroy(struct lws_plugin **pplugin, each_plugin_cb_t each,
+                   void *each_user)
+{
+       struct lws_plugin *p = *pplugin, *p1;
+
+       while (p) {
+               if (each)
+                       each(p, each_user);
+               lws_plat_destroy_dl(p);
+               p1 = p->list;
+               p->list = NULL;
+               lws_free(p);
+               p = p1;
+       }
+
+       *pplugin = NULL;
+
+       return 0;
+}
 #endif
index 0a31810..bfc629a 100644 (file)
@@ -1,28 +1,34 @@
 /*
- * libwebsockets - disk cache helpers
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
+#endif
 #include <pthread.h>
 
-#include "core/private.h"
+#include <libwebsockets.h>
+#include "private-lib-core.h"
 
 #include <string.h>
 #include <stdio.h>
 #include <sys/time.h>
 #include <sys/types.h>
 
+#if defined(__APPLE__)
+#include <sys/dirent.h>
+/* Travis OSX does not have DT_REG... */
+#if !defined(DT_REG)
+#define DT_REG 8
+#endif
+#endif
+
 struct file_entry {
        lws_list_ptr sorted;
        lws_list_ptr prev;
@@ -75,7 +89,7 @@ fe_modified_sort(lws_list_ptr a, lws_list_ptr b)
 {
        struct file_entry *p1 = lp_to_fe(a, sorted), *p2 = lp_to_fe(b, sorted);
 
-       return p2->modified - p1->modified;
+       return (int)((long)p2->modified - (long)p1->modified);
 }
 
 struct lws_diskcache_scan *
@@ -104,27 +118,27 @@ lws_diskcache_destroy(struct lws_diskcache_scan **lds)
 }
 
 int
-lws_diskcache_prepare(const char *cache_base_dir, int mode, int uid)
+lws_diskcache_prepare(const char *cache_base_dir, int mode, uid_t uid)
 {
        char dir[256];
        int n, m;
 
-       (void)mkdir(cache_base_dir, mode);
-       if (chown(cache_base_dir, uid, -1))
+       (void)mkdir(cache_base_dir, (unsigned short)mode);
+       if (chown(cache_base_dir, uid, (gid_t)-1))
                lwsl_err("%s: %s: unable to chown %d\n", __func__,
                         cache_base_dir, uid);
 
        for (n = 0; n < 16; n++) {
                lws_snprintf(dir, sizeof(dir), "%s/%c", cache_base_dir, hex[n]);
-               (void)mkdir(dir, mode);
-               if (chown(dir, uid, -1))
+               (void)mkdir(dir, (mode_t)mode);
+               if (chown(dir, uid, (uid_t)-1))
                        lwsl_err("%s: %s: unable to chown %d\n", __func__,
                                                 dir, uid);
                for (m = 0; m < 16; m++) {
                        lws_snprintf(dir, sizeof(dir), "%s/%c/%c",
                                     cache_base_dir, hex[n], hex[m]);
-                       (void)mkdir(dir, mode);
-                       if (chown(dir, uid, -1))
+                       (void)mkdir(dir, (mode_t)mode);
+                       if (chown(dir, uid, (uid_t)-1))
                                lwsl_err("%s: %s: unable to chown %d\n",
                                         __func__, dir, uid);
                }
@@ -173,7 +187,7 @@ lws_diskcache_query(struct lws_diskcache_scan *lds, int is_bot,
        if (!is_bot)
                lds->cache_tries++;
 
-       n = lws_snprintf(cache, cache_len, "%s/%c/%c/%s", lds->cache_dir_base,
+       n = lws_snprintf(cache, (size_t)cache_len, "%s/%c/%c/%s", lds->cache_dir_base,
                         hash_hex[0], hash_hex[1], hash_hex);
 
        lwsl_info("%s: job cache %s\n", __func__, cache);
@@ -207,7 +221,7 @@ lws_diskcache_query(struct lws_diskcache_scan *lds, int is_bot,
 
        /* let's create it first with a unique temp name */
 
-       lws_snprintf(cache + n, cache_len - n, "~%d-%p", (int)getpid(),
+       lws_snprintf(cache + n, (size_t)cache_len - (unsigned int)n, "~%d-%p", (int)getpid(),
                     extant_cache_len);
 
        *_fd = open(cache, O_RDWR | O_CREAT | O_TRUNC, 0600);
@@ -257,7 +271,7 @@ lws_diskcache_secs_to_idle(struct lws_diskcache_scan *lds)
 int
 lws_diskcache_trim(struct lws_diskcache_scan *lds)
 {
-       size_t cache_size_limit = lds->cache_size_limit;
+       size_t cache_size_limit = (size_t)lds->cache_size_limit;
        char dirpath[132], filepath[132 + 32];
        lws_list_ptr lp, op = NULL;
        int files_trimmed = 0;
@@ -324,7 +338,7 @@ lws_diskcache_trim(struct lws_diskcache_scan *lds)
                        continue;
                }
 
-               lds->agg_size += s.st_size;
+               lds->agg_size += (uint64_t)s.st_size;
 
                if (lds->batch_in_use == BATCH_COUNT) {
                        /*
@@ -351,7 +365,7 @@ lws_diskcache_trim(struct lws_diskcache_scan *lds)
                strncpy(p->name, de->d_name, sizeof(p->name) - 1);
                p->name[sizeof(p->name) - 1] = '\0';
                p->modified = s.st_mtime;
-               p->size = s.st_size;
+               p->size = (size_t)s.st_size;
 
                lws_list_ptr_insert(&lds->head, &p->sorted, fe_modified_sort);
        } while (de);
@@ -415,7 +429,7 @@ lws_diskcache_trim(struct lws_diskcache_scan *lds)
        }
 
        if (lds->agg_size && lds->agg_file_count)
-               lds->avg_size = lds->agg_size / lds->agg_file_count;
+               lds->avg_size = lds->agg_size / (uint64_t)lds->agg_file_count;
 
        /*
         * estimate how long we can go before scanning again... default we need
@@ -430,7 +444,7 @@ lws_diskcache_trim(struct lws_diskcache_scan *lds)
 
                /* let's use 80% of the real average for margin */
                if (lds->agg_size && lds->agg_file_count)
-                       avg = ((lds->agg_size * 8) / lds->agg_file_count) / 10;
+                       avg = ((lds->agg_size * 8) / (uint64_t)lds->agg_file_count) / 10;
 
                /*
                 * if we collected BATCH_COUNT files of the average size,
@@ -445,8 +459,8 @@ lws_diskcache_trim(struct lws_diskcache_scan *lds)
                projected = (lds->agg_size * 11) / 10;
                if (projected < cache_size_limit)
                        /* no... */
-                       lds->secs_waiting  = (256 / 2) * ((cache_size_limit -
-                                                   projected) / capacity);
+                       lds->secs_waiting  = (int)((256 / 2) * ((cache_size_limit -
+                                                   projected) / capacity));
 
                /*
                 * large waits imply we may not have enough info yet, so
diff --git a/lib/misc/fsmount.c b/lib/misc/fsmount.c
new file mode 100644 (file)
index 0000000..bc9669a
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicefsme, and/or
+ * sell copies of the Software, and to permit persofsm to whom the Software is
+ * furnished to do so, subject to the following conditiofsm:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portiofsm of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Mount and unmount overlayfs mountpoints (linux only)
+ */
+
+#include "private-lib-core.h"
+#include <unistd.h>
+
+#include <libmount/libmount.h>
+
+#include <string.h>
+#include <signal.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static int
+rm_rf_cb(const char *dirpath, void *user, struct lws_dir_entry *lde)
+{
+       char path[384];
+
+       if (!strcmp(lde->name, ".") || !strcmp(lde->name, ".."))
+               return 0;
+
+       lws_snprintf(path, sizeof(path), "%s/%s", dirpath, lde->name);
+
+       if (lde->type == LDOT_DIR) {
+               lws_dir(path, NULL, rm_rf_cb);
+               rmdir(path);
+       } else
+               unlink(path);
+
+       return 0;
+}
+
+int
+lws_fsmount_mount(struct lws_fsmount *fsm)
+{
+       struct libmnt_context *ctx;
+       char opts[512], c;
+       int n, m;
+
+       /*
+        * For robustness, there are a couple of sticky situations caused by
+        * previous mounts not cleaning up... 1) still mounted on the mountpoint
+        * and 2) junk in the session dir from the dead session.
+        *
+        * For 1), do a gratuitous umount attempts until it feels nothing to
+        * umount...
+        */
+
+       c = fsm->mp[0];
+       while (!lws_fsmount_unmount(fsm))
+               fsm->mp[0] = c;
+       fsm->mp[0] = c;
+
+       /*
+        * ... for 2), generate the session dir basepath and destroy everything
+        * in it... it's less dangerous than it sounds because there are
+        * hardcoded unusual dir names in the base path, so it can't go wild
+        * even if the overlay path is empty or /
+        */
+
+       lws_snprintf(opts, sizeof(opts), "%s/overlays/%s/session",
+                    fsm->overlay_path, fsm->ovname);
+       lwsl_info("%s: emptying session dir %s\n", __func__, opts);
+       lws_dir(opts, NULL, rm_rf_cb);
+
+       /*
+        * Piece together the options for the overlay mount...
+        */
+
+       n = lws_snprintf(opts, sizeof(opts), "lowerdir=");
+       for (m = LWS_ARRAY_SIZE(fsm->layers) - 1; m >= 0; m--)
+               if (fsm->layers[m]) {
+                       if (n != 9)
+                               opts[n++] = ':';
+
+                       n += lws_snprintf(&opts[n], (size_t)(sizeof(opts) - (unsigned int)n),
+                                         "%s/%s/%s", fsm->layers_path,
+                                         fsm->distro, fsm->layers[m]);
+               }
+
+       n += lws_snprintf(&opts[n], (size_t)(sizeof(opts) - (unsigned int)n),
+                         ",upperdir=%s/overlays/%s/session",
+                         fsm->overlay_path, fsm->ovname);
+
+       n += lws_snprintf(&opts[n], (size_t)(sizeof(opts) - (unsigned int)n),
+                         ",workdir=%s/overlays/%s/work",
+                         fsm->overlay_path, fsm->ovname);
+
+       ctx = mnt_new_context();
+       if (!ctx)
+               return 1;
+
+       mnt_context_set_fstype(ctx, "overlay");
+       mnt_context_set_options(ctx, opts);
+       mnt_context_set_mflags(ctx, MS_NOATIME /* |MS_NOEXEC */);
+       mnt_context_set_target(ctx, fsm->mp);
+       mnt_context_set_source(ctx, "none");
+
+       lwsl_notice("%s: mount opts %s\n", __func__, opts);
+       puts(opts);
+
+       m = mnt_context_mount(ctx);
+       lwsl_notice("%s: mountpoint %s: %d\n", __func__, fsm->mp, m);
+
+       mnt_free_context(ctx);
+
+       return m;
+}
+
+int
+lws_fsmount_unmount(struct lws_fsmount *fsm)
+{
+       struct libmnt_context *ctx;
+       int m;
+
+       lwsl_notice("%s: %s\n", __func__, fsm->mp);
+
+       ctx = mnt_new_context();
+       if (!ctx)
+               return 1;
+
+       mnt_context_set_target(ctx, fsm->mp);
+
+       m = mnt_context_umount(ctx);
+       mnt_free_context(ctx);
+
+       fsm->mp[0] = '\0';
+
+       return m;
+}
index fcb225c..71c1eec 100644 (file)
@@ -112,7 +112,7 @@ more or less bytes according to the value.  So the peak memory requirements for
 large tries are much bigger than the size of the serialized trie file that is
 output.
 
-For the linux kernel at 4.14 and default indexing whitelist on a 2.8GHz AMD
+For the linux kernel at 4.14 and default indexing list on a 2.8GHz AMD
 threadripper (using one thread), the stats are:
 
 Name|Value
@@ -124,7 +124,7 @@ Peak alloc|78MiB
 Serialization time|202ms
 Trie File size|347MiB
 
-To index libwebsockets master under the same conditions:
+To index libwebsockets main branch under the same conditions:
 
 Name|Value
 ---|---
index cdb2e42..c67165b 100644 (file)
@@ -1,26 +1,29 @@
 /*
- * libjsongit2 - trie file functions
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-#include "misc/fts/private.h"
+#include "private-lib-core.h"
+#include "private-lib-misc-fts.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -69,13 +72,13 @@ struct linetable {
 static uint32_t
 b32(unsigned char *b)
 {
-       return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
+       return (uint32_t)((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
 }
 
 static uint16_t
 b16(unsigned char *b)
 {
-       return (b[0] << 8) | b[1];
+       return (uint16_t)((b[0] << 8) | b[1]);
 }
 
 static int
@@ -91,25 +94,25 @@ lws_fts_filepath(struct lws_fts_file *jtf, int filepath_index, char *result,
        if (filepath_index > jtf->filepaths)
                return 1;
 
-       if (lseek(jtf->fd, jtf->filepath_table + (4 * filepath_index),
+       if (lseek(jtf->fd, (off_t)(jtf->filepath_table + (4 * (unsigned int)filepath_index)),
                        SEEK_SET) < 0) {
                lwsl_err("%s: unable to seek\n", __func__);
 
                return 1;
        }
 
-       ra = read(jtf->fd, buf, 4);
+       ra = (int)read(jtf->fd, buf, 4);
        if (ra < 0)
                return 1;
 
-       o = (unsigned int)b32(buf);
+       o = (off_t)b32(buf);
        if (lseek(jtf->fd, o, SEEK_SET) < 0) {
                lwsl_err("%s: unable to seek\n", __func__);
 
                return 1;
        }
 
-       ra = read(jtf->fd, buf, sizeof(buf));
+       ra = (int)read(jtf->fd, buf, sizeof(buf));
        if (ra < 0)
                return 1;
 
@@ -167,7 +170,7 @@ lws_fts_adopt(struct lws_fts_file *jtf)
 
                goto bail;
        }
-       jtf->flen = ot;
+       jtf->flen = (jg2_file_offset)ot;
 
        if (jtf->flen != b32(&buf[8])) {
                lwsl_err("%s: file size doesn't match expected\n", __func__);
@@ -176,7 +179,7 @@ lws_fts_adopt(struct lws_fts_file *jtf)
        }
 
        jtf->filepath_table = b32(&buf[12]);
-       jtf->filepaths = b32(&buf[16]);
+       jtf->filepaths = (int)b32(&buf[16]);
 
        return jtf->fd;
 
@@ -221,13 +224,13 @@ lws_fts_close(struct lws_fts_file *jtf)
 
 #define grab(_pos, _size) { \
                bp = 0; \
-               if (lseek(jtf->fd, _pos, SEEK_SET) < 0) { \
+               if (lseek(jtf->fd, (off_t)(_pos), SEEK_SET) < 0) { \
                        lwsl_err("%s: unable to seek\n", __func__); \
 \
                        goto bail; \
                } \
 \
-               ra = read(jtf->fd, buf, _size); \
+               ra = (int)read(jtf->fd, buf, (size_t)(_size)); \
                if (ra < 0) \
                        goto bail; \
 }
@@ -259,12 +262,12 @@ lws_fts_cache_chunktable(struct lws_fts_file *jtf, uint32_t ofs_linetable,
 
                lt->chunk_line_number_start = line;
                lt->chunk_line_number_count = b16(&buf[bp + 2]);
-               lt->vli_ofs_in_index = ofs_linetable + 8;
+               lt->vli_ofs_in_index = (off_t)(ofs_linetable + 8);
                lt->chunk_filepos_start = cfs;
 
                line += lt->chunk_line_number_count;
 
-               cfs += b32(&buf[bp + 4]);
+               cfs += (int32_t)b32(&buf[bp + 4]);
                ofs_linetable += b16(&buf[bp]);
 
        } while (b16(&buf[bp]));
@@ -311,7 +314,7 @@ lws_fts_getfileoffset(struct lws_fts_file *jtf, struct linetable *ltstart,
        bp = 0;
        while (line) {
                bp += rq32(&buf[bp], &ll);
-               ofs += ll;
+               ofs += (int32_t)ll;
                line--;
        }
 
@@ -344,7 +347,7 @@ ac_record(struct lws_fts_file *jtf, struct lwsac **results_head,
        for (n = 1; n <= sp; n++)
                m += s[n].ch[s[n].child - 1].name_length;
 
-       ac = lwsac_use(results_head, sizeof(*ac) + m + 1, 0);
+       ac = lwsac_use(results_head, sizeof(*ac) + (unsigned int)m + 1, 0);
        if (!ac)
                return -1;
 
@@ -353,19 +356,19 @@ ac_record(struct lws_fts_file *jtf, struct lwsac **results_head,
        **ppac = ac;
        ac->next = NULL;
        *ppac = &ac->next;
-       ac->instances = instances;
-       ac->agg_instances = agg_instances;
+       ac->instances = (int)instances;
+       ac->agg_instances = (int)agg_instances;
        ac->ac_length = m;
        ac->has_children = !!children;
        ac->elided = 0;
 
-       memcpy(p, needle, pos);
+       memcpy(p, needle, (size_t)pos);
        p += pos;
 
        for (n = 1; n <= sp; n++) {
                int w = s[n].child - 1;
 
-               memcpy(p, s[n].ch[w].name, s[n].ch[w].name_length);
+               memcpy(p, s[n].ch[w].name, (size_t)s[n].ch[w].name_length);
                p += s[n].ch[w].name_length;
        }
        p = (char *)(ac + 1);
@@ -377,8 +380,8 @@ ac_record(struct lws_fts_file *jtf, struct lwsac **results_head,
         * best results (children are sorted best-first)
         */
        for (n = sp; n >= 0; n--) {
-               s[n].ch[s[n].child - 1].child_agg -= instances;
-               s[n].agg -= instances;
+               s[n].ch[s[n].child - 1].child_agg -= (int)instances;
+               s[n].agg -= (int)instances;
        }
 
        return 0;
@@ -390,7 +393,7 @@ lws_fts_search(struct lws_fts_file *jtf, struct lws_fts_search_params *ftsp)
        uint32_t children, instances, co, sl, agg, slt, chunk,
                 fileofs_tif_start, desc, agg_instances;
        int pos = 0, n, m, nl, bp, base = 0, ra, palm, budget, sp, ofd = -1;
-       unsigned long long tf = lws_now_usecs();
+       unsigned long long tf = (unsigned long long)lws_now_usecs();
        struct lws_fts_result_autocomplete **pac = NULL;
        char stasis, nac = 0, credible, needle[32];
        struct lws_fts_result_filepath *fp;
@@ -423,10 +426,10 @@ lws_fts_search(struct lws_fts_file *jtf, struct lws_fts_search_params *ftsp)
        palm = 0;
 
        for (n = 0; n < nl; n++)
-               needle[n] = tolower(ftsp->needle[n]);
+               needle[n] = (char)tolower(ftsp->needle[n]);
        needle[nl] = '\0';
 
-       o = jtf->root;
+       o = (off_t)jtf->root;
        do {
                bp = 0;
                base = 0;
@@ -455,7 +458,7 @@ lws_fts_search(struct lws_fts_file *jtf, struct lws_fts_search_params *ftsp)
 
                        /* we leave with bp positioned at the instance list */
 
-                       o = fileofs_tif_start;
+                       o = (off_t)fileofs_tif_start;
                        grab(o, sizeof(buf));
                        break;
                }
@@ -490,7 +493,7 @@ lws_fts_search(struct lws_fts_file *jtf, struct lws_fts_search_params *ftsp)
                                 * our needle string (but that leaves it as a
                                 * perfectly fine autocomplete candidate)
                                 */
-                               size_t g = nl - pos;
+                               size_t g = (size_t)(nl - pos);
 
                                /*
                                 * "credible" means at least one child matches
@@ -509,7 +512,7 @@ lws_fts_search(struct lws_fts_file *jtf, struct lws_fts_search_params *ftsp)
                                        agg_instances -= agg;
 
                                nac = 0;
-                               bp += sl;
+                               bp += (int)sl;
                                slt = 0;
                                pos = palm;
                                goto ensure;
@@ -528,7 +531,7 @@ lws_fts_search(struct lws_fts_file *jtf, struct lws_fts_search_params *ftsp)
                                 * not needed due to a match fail.
                                 */
 
-                               chunk = ra - bp;
+                               chunk = (uint32_t)(ra - bp);
                                if (chunk > slt)
                                        chunk = slt;
 
@@ -540,21 +543,21 @@ lws_fts_search(struct lws_fts_file *jtf, struct lws_fts_search_params *ftsp)
                                         * it doesn't match... so nothing can
                                         * autocomplete this...
                                         */
-                                       bp += slt;
+                                       bp += (int)slt;
                                        slt = 0;
                                        nac = 1;
                                        goto ensure;
                                }
 
                                slt -= chunk;
-                               pos += chunk;
-                               bp += chunk;
+                               pos += (int)chunk;
+                               bp += (int)chunk;
 
                                /* so far, it matches */
 
                                if (!slt) {
                                        /* we matched the whole thing */
-                                       o = co;
+                                       o = (int32_t)co;
                                        if (!co)
                                                goto bail;
                                        n = (int)children;
@@ -595,7 +598,7 @@ ensure:
                }
        } while(1);
 
-       result->duration_ms = (int)((lws_now_usecs() - tf) / 1000);
+       result->duration_ms = (int)(((uint64_t)lws_now_usecs() - tf) / 1000);
 
        if (!instances && !children)
                return result;
@@ -623,16 +626,16 @@ ensure:
                ofd = -1;
                grab(o, sizeof(buf));
 
-               ro = o;
+               ro = (uint32_t)o;
                bp += rq32(&buf[bp], &_o);
-               o = _o;
+               o = (off_t)_o;
 
                assert(!o || o > TRIE_FILE_HDR_SIZE);
 
                bp += rq32(&buf[bp], &fi);
                bp += rq32(&buf[bp], &tot);
 
-               if (lws_fts_filepath(jtf, fi, path, sizeof(path) - 1,
+               if (lws_fts_filepath(jtf, (int)fi, path, sizeof(path) - 1,
                                     &ofs_linetable, &lines)) {
                        lwsl_err("can't get filepath index %d\n", fi);
                        goto bail;
@@ -653,27 +656,27 @@ ensure:
                        }
                }
 
-               fplen = (int)strlen(path);
-               footprint = sizeof(*fp) + fplen + 1;
+               fplen = (uint32_t)strlen(path);
+               footprint = (int)(sizeof(*fp) + fplen + 1);
                if (ftsp->flags & LWSFTS_F_QUERY_FILE_LINES) {
                        /* line number and offset in file */
-                       footprint += 2 * sizeof(uint32_t) * tot;
+                       footprint += (int)(2 * sizeof(uint32_t) * tot);
 
                        if (ftsp->flags & LWSFTS_F_QUERY_QUOTE_LINE)
                                /* pointer to quote string */
-                               footprint += sizeof(void *) * tot;
+                               footprint += (int)(sizeof(void *) * tot);
                }
 
-               fp = lwsac_use(&ftsp->results_head, footprint, 0);
+               fp = lwsac_use(&ftsp->results_head, (unsigned int)footprint, 0);
                if (!fp) {
                        lwsac_free(&lt_head);
                        goto bail;
                }
 
-               fp->filepath_length = fplen;
-               fp->lines_in_file = lines;
-               fp->matches = tot;
-               fp->matches_length = footprint - sizeof(*fp) - (fplen + 1);
+               fp->filepath_length = (int)fplen;
+               fp->lines_in_file = (int)lines;
+               fp->matches = (int)tot;
+               fp->matches_length = footprint - (int)sizeof(*fp) - (int)(fplen + 1);
                fp->next = result->filepath_head;
                result->filepath_head = fp;
 
@@ -694,13 +697,13 @@ ensure:
 
                                if ((ra - bp) < 8) {
                                        base += bp;
-                                       grab(ro + base, sizeof(buf));
+                                       grab((int32_t)ro + base, sizeof(buf));
                                }
 
                                bp += rq32(&buf[bp], &line);
                                *u++ = line;
 
-                               if (lws_fts_getfileoffset(jtf, ltst, line, &fo))
+                               if (lws_fts_getfileoffset(jtf, ltst, (int)line, &fo))
                                        continue;
 
                                *u++ = (uint32_t)fo;
@@ -711,7 +714,7 @@ ensure:
                                if (lseek(ofd, fo, SEEK_SET) < 0)
                                        continue;
 
-                               m = read(ofd, lbuf, sizeof(lbuf) - 1);
+                               m = (int)read(ofd, lbuf, sizeof(lbuf) - 1);
                                if (m < 0)
                                        continue;
                                lbuf[sizeof(lbuf) - 1] = '\0';
@@ -726,16 +729,16 @@ ensure:
                                lbuf[m] = '\0';
 
                                lws_json_purify(ebuf, (const char *)lbuf,
-                                               sizeof(ebuf) - 1);
+                                               sizeof(ebuf) - 1, NULL);
                                m = (int)strlen(ebuf);
 
-                               p = lwsac_use(&ftsp->results_head, m + 1, 0);
+                               p = lwsac_use(&ftsp->results_head, (unsigned int)m + 1, 0);
                                if (!p) {
                                        lwsac_free(&lt_head);
                                        goto bail;
                                }
 
-                               memcpy(p, ebuf, m);
+                               memcpy(p, ebuf, (unsigned int)m);
                                p[m] = '\0';
                                v = (const char **)u;
                                *v = (const char *)p;
@@ -827,7 +830,7 @@ autocomp:
 
        s[sp].child = 1;
        s[sp].tifs = fileofs_tif_start;
-       s[sp].self = child_ofs;
+       s[sp].self = (jg2_file_offset)child_ofs;
        s[sp].ch[0].effpos = pos;
 
        if (pos == nl)
@@ -849,8 +852,8 @@ autocomp:
                    tch->effpos + tch->name_length >= nl &&
                    tch->inst && fileofs_tif_start) {
                        n = ac_record(jtf, &ftsp->results_head, needle, pos, s,
-                                     sp, tch->inst, tch->child_agg,
-                                     tch->descendents, &pac);
+                                     sp, (uint32_t)tch->inst, (uint32_t)tch->child_agg,
+                                     (uint32_t)tch->descendents, &pac);
                        if (n < 0)
                                goto bail;
                        if (!n)
@@ -863,7 +866,7 @@ autocomp:
                        sp++;
                        memset(&s[sp], 0, sizeof(s[sp]));
                        s[sp].tifs = fileofs_tif_start;
-                       s[sp].self = child_ofs;
+                       s[sp].self = (jg2_file_offset)child_ofs;
 
                        for (n = 0; n < (int)children && s[sp].child_count <
                                            (int)LWS_ARRAY_SIZE(s[0].ch); n++) {
@@ -883,16 +886,16 @@ autocomp:
                                        max = sizeof(ch->name) - 1;
 
                                strncpy(ch->name, (char *)&buf[bp], max);
-                               bp += slen;
+                               bp += (int)slen;
 
                                ch->name_length = (int)max;
                                ch->name[sizeof(ch->name) - 1] = '\0';
-                               ch->inst = inst;
+                               ch->inst = (int)inst;
                                ch->effpos =
                                       s[sp - 1].ch[s[sp - 1].child - 1].effpos;
 
-                               ch->child_agg = agg;
-                               ch->descendents = desc;
+                               ch->child_agg = (int)agg;
+                               ch->descendents = (int)desc;
 
                                /*
                                 * if we have more needle chars than we matched
@@ -906,7 +909,7 @@ autocomp:
                                        m = ch->name_length;
 
                                if (m > 0 &&
-                                   strncmp(&needle[ch->effpos], ch->name, m))
+                                   strncmp(&needle[ch->effpos], ch->name, (unsigned int)m))
                                        continue;
 
                                ch->effpos += m;
@@ -948,7 +951,7 @@ autocomp:
                                for (m = n; m < sp + 1; m++)
                                        s[m].done_children = 0;
                                sp = n;
-                               child_ofs = s[sp].ch[s[sp].child++].ofs;
+                               child_ofs = (off_t)s[sp].ch[s[sp].child++].ofs;
                                nobump = 1;
                        }
 
@@ -958,7 +961,7 @@ autocomp:
                if (nobump || sp < 0)
                        continue;
 
-               child_ofs = s[sp].ch[s[sp].child++].ofs;
+               child_ofs = (off_t)s[sp].ch[s[sp].child++].ofs;
        }
 
        /* let's do a final sort into agg order */
index d188165..8b4317e 100644 (file)
@@ -1,22 +1,25 @@
-/*
- * libwebsockets - trie
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * The functions allow
  *
@@ -30,8 +33,8 @@
  *    having to load it all in memory
  */
 
-#include "core/private.h"
-#include "misc/fts/private.h"
+#include "private-lib-core.h"
+#include "private-lib-misc-fts.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -165,23 +168,23 @@ struct lws_fts {
 #define TRIE_LWSAC_BLOCK_SIZE (1024 * 1024)
 
 #define spill(margin, force) \
-       if (bp && ((uint32_t)bp >= (sizeof(buf) - (margin)) || (force))) { \
-               if (write(t->fd, buf, bp) != bp) { \
+       if (bp && ((uint32_t)bp >= (sizeof(buf) - (size_t)(margin)) || (force))) { \
+               if ((int)write(t->fd, buf, (size_t)bp) != bp) { \
                        lwsl_err("%s: write %d failed (%d)\n", __func__, \
                                 bp, errno); \
                        return 1; \
                } \
-               t->c += bp; \
+               t->c += (unsigned int)bp; \
                bp = 0; \
        }
 
 static int
 g32(unsigned char *b, uint32_t d)
 {
-       *b++ = (d >> 24) & 0xff;
-       *b++ = (d >> 16) & 0xff;
-       *b++ = (d >> 8) & 0xff;
-       *b = d & 0xff;
+       *b++ = (uint8_t)((d >> 24) & 0xff);
+       *b++ = (uint8_t)((d >> 16) & 0xff);
+       *b++ = (uint8_t)((d >> 8) & 0xff);
+       *b = (uint8_t)(d & 0xff);
 
        return 4;
 }
@@ -189,8 +192,8 @@ g32(unsigned char *b, uint32_t d)
 static int
 g16(unsigned char *b, int d)
 {
-       *b++ = (d >> 8) & 0xff;
-       *b = d & 0xff;
+       *b++ = (uint8_t)((d >> 8) & 0xff);
+       *b = (uint8_t)(d & 0xff);
 
        return 2;
 }
@@ -201,20 +204,20 @@ wq32(unsigned char *b, uint32_t d)
        unsigned char *ob = b;
 
        if (d > (1 << 28) - 1)
-               *b++ = ((d >> 28) | 0x80) & 0xff;
+               *b++ = (uint8_t)(((d >> 28) | 0x80) & 0xff);
 
        if (d > (1 << 21) - 1)
-               *b++ = ((d >> 21) | 0x80) & 0xff;
+               *b++ = (uint8_t)(((d >> 21) | 0x80) & 0xff);
 
        if (d > (1 << 14) - 1)
-               *b++ = ((d >> 14) | 0x80) & 0xff;
+               *b++ = (uint8_t)(((d >> 14) | 0x80) & 0xff);
 
        if (d > (1 << 7) - 1)
-               *b++ = ((d >> 7) | 0x80) & 0xff;
+               *b++ = (uint8_t)(((d >> 7) | 0x80) & 0xff);
 
-       *b++ = d & 0x7f;
+       *b++ = (uint8_t)(d & 0x7f);
 
-       return (int)(b - ob);
+       return lws_ptr_diff(b, ob);
 }
 
 
@@ -400,9 +403,9 @@ finalize_per_input(struct lws_fts *t)
        bp += g16(&buf[bp], 0);
        bp += g16(&buf[bp], 0);
        bp += g32(&buf[bp], 0);
-       if (write(t->fd, buf, bp) != bp)
+       if ((int)write(t->fd, buf, (size_t)bp) != bp)
                return 1;
-       t->c += bp;
+       t->c += (unsigned int)bp;
        bp = 0;
 
        /*
@@ -429,7 +432,7 @@ finalize_per_input(struct lws_fts *t)
 
                temp = tif->owner->ofs_last_inst_file;
                if (tif->total)
-                       tif->owner->ofs_last_inst_file = t->c + bp;
+                       tif->owner->ofs_last_inst_file = t->c + (unsigned int)bp;
 
                assert(!temp || (temp > TRIE_FILE_HDR_SIZE && temp < t->c));
 
@@ -441,13 +444,13 @@ finalize_per_input(struct lws_fts *t)
                /* remove any pointers into this disposable lac footprint */
                tif->owner->inst_file_list = NULL;
 
-               memcpy(&buf[bp], &tif->vli, tif->count);
+               memcpy(&buf[bp], &tif->vli, (size_t)tif->count);
                bp += tif->count;
 
                i = tif->lines_list;
                while (i) {
                        spill(i->count, 0);
-                       memcpy(&buf[bp], &i->vli, i->count);
+                       memcpy(&buf[bp], &i->vli, (size_t)i->count);
                        bp += i->count;
 
                        i = i->lines_next;
@@ -540,7 +543,7 @@ int
 lws_fts_fill(struct lws_fts *t, uint32_t file_index, const char *buf,
             size_t len)
 {
-       unsigned long long tf = lws_now_usecs();
+       unsigned long long tf = (unsigned long long)lws_now_usecs();
        unsigned char c, linetable[256], vlibuf[8];
        struct lws_fts_entry *e, *e1, *dcl;
        struct lws_fts_instance_file *tif;
@@ -553,7 +556,7 @@ lws_fts_fill(struct lws_fts *t, uint32_t file_index, const char *buf,
        if ((int)file_index != t->last_file_index) {
                if (t->last_file_index >= 0)
                        finalize_per_input(t);
-               t->last_file_index = file_index;
+               t->last_file_index = (int)file_index;
                t->line_number = 1;
                t->chars_in_line = 0;
                t->lines_in_unsealed_linetable = 0;
@@ -564,7 +567,7 @@ lws_fts_fill(struct lws_fts *t, uint32_t file_index, const char *buf,
 resume:
 
        chars = 0;
-       lbh = t->c;
+       lbh = (off_t)t->c;
        sline = t->line_number;
        bp += g16(&linetable[bp], 0);
        bp += g16(&linetable[bp], 0);
@@ -586,14 +589,14 @@ resume:
                        t->lines_in_unsealed_linetable++;
                        t->line_number++;
 
-                       bp += wq32(&linetable[bp], t->chars_in_line);
+                       bp += wq32(&linetable[bp], (uint32_t)t->chars_in_line);
                        if ((unsigned int)bp > sizeof(linetable) - 6) {
-                               if (write(t->fd, linetable, bp) != bp) {
+                               if ((int)write(t->fd, linetable, (unsigned int)bp) != bp) {
                                        lwsl_err("%s: linetable write failed\n",
                                                        __func__);
                                        return 1;
                                }
-                               t->c += bp;
+                               t->c += (unsigned int)bp;
                                bp = 0;
                                // assert(lseek(t->fd, 0, SEEK_END) == t->c);
                        }
@@ -631,7 +634,7 @@ resume:
                if (!m)
                        goto seal;
                if (m == 2)
-                       c += 'a' - 'A';
+                       c = (unsigned char)((char)c + 'a' - 'A');
 
                if (t->aggregate) {
 
@@ -823,12 +826,12 @@ seal:
                         */
 
                        dcl = t->parser->child_list;
-                       m = t->parser->child_count;
+                       m = (int)t->parser->child_count;
 
                        t->parser->child_list = NULL;
                        t->parser->child_count = 0;
 
-                       e = lws_fts_entry_child_add(t,
+                       e = lws_fts_entry_child_add(t, (unsigned char)
                                        osuff[t->str_match_pos - 1], t->parser);
                        if (!e) {
                                lwsl_err("%s: lws_fts_entry_child_add fail1\n",
@@ -837,7 +840,7 @@ seal:
                        }
 
                        e->child_list = dcl;
-                       e->child_count = m;
+                       e->child_count = (uint32_t)m;
                        /*
                         * any children we took over must point to us as the
                         * parent now they appear on our child list
@@ -939,7 +942,7 @@ seal:
                        }
 
                        /* add the first char at the beginning */
-                       *t->parser->suffix = t->parser->c;
+                       *t->parser->suffix = (char)t->parser->c;
                        /* and then add the agg buffer stuff */
                        memcpy(t->parser->suffix + 1, t->agg, t->agg_pos);
                        t->parser->suffix_len = t->agg_pos + 1;
@@ -985,14 +988,14 @@ seal:
                 * more vli space and continues chaining those if needed.
                 */
 
-               n = wq32(vlibuf, t->line_number);
+               n = (unsigned int)wq32(vlibuf, (uint32_t)t->line_number);
                tif = t->parser->inst_file_list;
 
                if (!tif->lines_list) {
                        /* we are still trying to use the file inst vli */
-                       if (LWS_ARRAY_SIZE(tif->vli) - tif->count >= n) {
-                               tif->count += wq32(tif->vli + tif->count,
-                                                  t->line_number);
+                       if (LWS_ARRAY_SIZE(tif->vli) - (size_t)tif->count >= n) {
+                               tif->count = (char)((char)tif->count + (char)wq32(tif->vli + tif->count,
+                                                  (uint32_t)t->line_number));
                                goto after;
                        }
                        /* we are going to have to allocate */
@@ -1001,10 +1004,10 @@ seal:
                /* can we add to an existing line numbers struct? */
                if (tif->lines_tail &&
                    LWS_ARRAY_SIZE(tif->lines_tail->vli) -
-                           tif->lines_tail->count >= n) {
-                       tif->lines_tail->count += wq32(tif->lines_tail->vli +
+                               (unsigned char)tif->lines_tail->count >= n) {
+                       tif->lines_tail->count = (char)((char)tif->lines_tail->count + (char)wq32(tif->lines_tail->vli +
                                                       tif->lines_tail->count,
-                                                      t->line_number);
+                                                      (uint32_t)t->line_number));
                        goto after;
                }
 
@@ -1025,7 +1028,7 @@ seal:
                if (!tif->lines_list)
                        tif->lines_list = tl;
 
-               tl->count = wq32(tl->vli, t->line_number);
+               tl->count = (char)wq32(tl->vli, (uint32_t)t->line_number);
 after:
                tif->total++;
 #if 0
@@ -1047,9 +1050,9 @@ after:
        /* seal off the line length table block */
 
        if (bp) {
-               if (write(t->fd, linetable, bp) != bp)
+               if ((int)write(t->fd, linetable, (size_t)bp) != bp)
                        return 1;
-               t->c += bp;
+               t->c += (unsigned int)bp;
                bp = 0;
        }
 
@@ -1059,17 +1062,17 @@ after:
                return 1;
        }
 
-       g16(linetable, t->c - lbh);
-       g16(linetable + 2, t->line_number - sline);
-       g32(linetable + 4, chars);
-       if (write(t->fd, linetable, 8) != 8) {
+       g16(linetable, (uint16_t)(t->c - (jg2_file_offset)lbh));
+       g16(linetable + 2, (uint16_t)(t->line_number - sline));
+       g32(linetable + 4, (uint32_t)chars);
+       if ((int)write(t->fd, linetable, 8) != 8) {
                lwsl_err("%s: write linetable header failed\n", __func__);
                return 1;
        }
 
        assert(lseek(t->fd, 0, SEEK_END) == (off_t)t->c);
 
-       if (lseek(t->fd, t->c, SEEK_SET) < 0) {
+       if (lseek(t->fd, (off_t)t->c, SEEK_SET) < 0) {
                lwsl_err("%s: end seek failed\n", __func__);
                return 1;
        }
@@ -1083,7 +1086,7 @@ after:
 
        /* dump the collected per-input instance and line data, and free it */
 
-       t->agg_trie_creation_us += lws_now_usecs() - tf;
+       t->agg_trie_creation_us += (uint64_t)((uint64_t)lws_now_usecs() - tf);
 
        return 0;
 }
@@ -1094,7 +1097,7 @@ int
 lws_fts_serialize(struct lws_fts *t)
 {
        struct lws_fts_filepath *fp = t->filepath_list, *ofp;
-       unsigned long long tf = lws_now_usecs();
+       unsigned long long tf = (unsigned long long)lws_now_usecs();
        struct lws_fts_entry *e, *e1, *s[256];
        unsigned char buf[8192], stasis;
        int n, bp, sp = 0, do_parent;
@@ -1160,14 +1163,14 @@ lws_fts_serialize(struct lws_fts *t)
        bp = 0;
        while (fp) {
 
-               fp->ofs = t->c + bp;
+               fp->ofs = t->c + (unsigned int)bp;
                n = (int)strlen(fp->filepath);
                spill(15 + n, 0);
 
                bp += wq32(&buf[bp], fp->line_table_ofs);
-               bp += wq32(&buf[bp], fp->total_lines);
-               bp += wq32(&buf[bp], n);
-               memcpy(&buf[bp], fp->filepath, n);
+               bp += wq32(&buf[bp], (uint32_t)fp->total_lines);
+               bp += wq32(&buf[bp], (uint32_t)n);
+               memcpy(&buf[bp], fp->filepath, (unsigned int)n);
                bp += n;
 
                fp->prev = ofp;
@@ -1182,12 +1185,12 @@ lws_fts_serialize(struct lws_fts *t)
        if (lseek(t->fd, 0xc, SEEK_SET) < 0)
                goto bail_seek;
 
-       g32(buf, t->c + bp);
-       g32(buf + 4, t->next_file_index);
-       if (write(t->fd, buf, 8) != 8)
+       g32(buf, t->c + (unsigned int)bp);
+       g32(buf + 4, (uint32_t)t->next_file_index);
+       if ((int)write(t->fd, buf, 8) != 8)
                goto bail;
 
-       if (lseek(t->fd, t->c + bp, SEEK_SET) < 0)
+       if (lseek(t->fd, (off_t)(t->c + (unsigned int)bp), SEEK_SET) < 0)
                goto bail_seek;
 
        /* dump the filepath map, starting from index 0, which is at the tail */
@@ -1232,7 +1235,7 @@ lws_fts_serialize(struct lws_fts *t)
                /* leaf nodes with no children */
 
                e = s[sp];
-               e->ofs = t->c + bp;
+               e->ofs = t->c + (unsigned int)bp;
 
                /* write the trie entry header */
 
@@ -1286,7 +1289,7 @@ lws_fts_serialize(struct lws_fts *t)
                        if (e1->suffix) { /* string  */
                                bp += wq32(&buf[bp], e1->suffix_len);
                                memmove(&buf[bp], e1->suffix, e1->suffix_len);
-                               bp += e1->suffix_len;
+                               bp += (int)e1->suffix_len;
                        } else { /* char */
                                bp += wq32(&buf[bp], 1);
                                buf[bp++] = e1->c;
@@ -1354,7 +1357,7 @@ lws_fts_serialize(struct lws_fts *t)
                    (int)(t->agg_trie_creation_us / 1000),
                    (int)(lwsac_total_alloc(t->lwsac_head) / 1024),
                    (int)(t->worst_lwsac_input_size / 1024),
-                   (int)((lws_now_usecs() - tf) / 1000),
+                   (int)(((uint64_t)lws_now_usecs() - tf) / 1000),
                    (int)(t->c / 1024));
 
        return 0;
index 735b899..125088e 100644 (file)
@@ -43,7 +43,9 @@
 #include <string.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
-#include "core/private.h"
+
+#include <libwebsockets.h>
+#include "private-lib-core.h"
 
 #ifdef LWS_HAVE_SYS_SOCKIO_H
 #include <sys/sockio.h>
@@ -88,7 +90,11 @@ getifaddrs2(struct ifaddrs **ifap, int af, int siocgifconf, int siocgifflags,
                        ret = ENOMEM;
                        goto error_out;
                }
-               ifconf.ifc_len = buf_size;
+#if defined(__QNX__)
+               ifconf.ifc_len = (short)(int)buf_size;
+#else
+               ifconf.ifc_len = (int)buf_size;
+#endif
                ifconf.ifc_buf = buf;
 
                /*
@@ -139,7 +145,7 @@ getifaddrs2(struct ifaddrs **ifap, int af, int siocgifconf, int siocgifflags,
 
                (*end)->ifa_next = NULL;
                (*end)->ifa_name = strdup(ifr->ifr_name);
-               (*end)->ifa_flags = ifreq.ifr_flags;
+               (*end)->ifa_flags = (unsigned int)ifreq.ifr_flags;
                (*end)->ifa_addr = lws_malloc(salen, "getifaddrs");
                memcpy((*end)->ifa_addr, sa, salen);
                (*end)->ifa_netmask = NULL;
diff --git a/lib/misc/ieeehalfprecision.c b/lib/misc/ieeehalfprecision.c
new file mode 100644 (file)
index 0000000..075eb1d
--- /dev/null
@@ -0,0 +1,228 @@
+/******************************************************************************
+ *
+ * Filename:    ieeehalfprecision.c
+ * Programmer:  James Tursa
+ * Version:     1.0
+ * Date:        March 3, 2009
+ * Copyright:   (c) 2009 by James Tursa, All Rights Reserved
+ *
+ *  This code uses the BSD License:
+ *
+ *  Redistribution and use in source and binary forms, with or without 
+ *  modification, are permitted provided that the following conditions are 
+ *  met:
+ *
+ *     * Redistributions of source code must retain the above copyright 
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright 
+ *       notice, this list of conditions and the following disclaimer in 
+ *       the documentation and/or other materials provided with the distribution
+ *      
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ *  POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file contains C code to convert between IEEE double, single, and half
+ * precision floating point formats. The intended use is for standalone C code
+ * that does not rely on MATLAB mex.h. The bit pattern for the half precision
+ * floating point format is stored in a 16-bit unsigned int variable. The half
+ * precision bit pattern definition is:
+ *
+ * 1 bit sign bit
+ * 5 bits exponent, biased by 15
+ * 10 bits mantissa, hidden leading bit, normalized to 1.0
+ *
+ * Special floating point bit patterns recognized and supported:
+ *
+ * All exponent bits zero:
+ * - If all mantissa bits are zero, then number is zero (possibly signed)
+ * - Otherwise, number is a denormalized bit pattern
+ *
+ * All exponent bits set to 1:
+ * - If all mantissa bits are zero, then number is +Infinity or -Infinity
+ * - Otherwise, number is NaN (Not a Number)
+ *
+ * For the denormalized cases, note that 2^(-24) is the smallest number that can
+ * be represented in half precision exactly. 2^(-25) will convert to 2^(-24)
+ * because of the rounding algorithm used, and 2^(-26) is too small and
+ * underflows to zero.
+ *
+ ******************************************************************************/
+
+/*
+  changes by K. Rogovin:
+  - changed macros UINT16_TYPE, etc to types from stdint.h
+    (i.e. UINT16_TYPE-->uint16_t, INT16_TYPE-->int16_t, etc)
+
+  - removed double conversion routines.
+
+  - changed run time checks of endianness to compile time macro.
+
+  - removed return value from routines
+
+  - changed source parameter type from * to const *
+
+  - changed pointer types from void ot uint16_t and uint32_t 
+ */
+
+/*
+ * andy@warmcat.com:
+ *
+ *  - clean style and indenting
+ *  - convert to single operation
+ *  - export as lws_
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void
+lws_singles2halfp(uint16_t *hp, uint32_t x)
+{
+       uint32_t xs, xe, xm;
+       uint16_t hs, he, hm;
+       int hes;
+
+       if (!(x & 0x7FFFFFFFu)) {
+               /* Signed zero */
+               *hp = (uint16_t)(x >> 16);
+
+               return;
+       }
+
+       xs = x & 0x80000000u;  // Pick off sign bit
+       xe = x & 0x7F800000u;  // Pick off exponent bits
+       xm = x & 0x007FFFFFu;  // Pick off mantissa bits
+
+       if (xe == 0) {  // Denormal will underflow, return a signed zero
+               *hp = (uint16_t) (xs >> 16);
+               return;
+       }
+
+       if (xe == 0x7F800000u) {  // Inf or NaN (all the exponent bits are set)
+               if (!xm) { // If mantissa is zero ...
+                       *hp = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf
+                       return;
+               }
+
+               *hp = (uint16_t) 0xFE00u; // NaN, only 1st mantissa bit set
+
+               return;
+       }
+
+       /* Normalized number */
+
+       hs = (uint16_t) (xs >> 16); // Sign bit
+       /* Exponent unbias the single, then bias the halfp */
+       hes = ((int)(xe >> 23)) - 127 + 15;
+
+       if (hes >= 0x1F) {  // Overflow
+               *hp = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf
+               return;
+       }
+
+       if (hes <= 0) {  // Underflow
+               if ((14 - hes) > 24)
+                       /*
+                        * Mantissa shifted all the way off & no
+                        * rounding possibility
+                        */
+                       hm = (uint16_t) 0u;  // Set mantissa to zero
+               else {
+                       xm |= 0x00800000u;  // Add the hidden leading bit
+                       hm = (uint16_t) (xm >> (14 - hes)); // Mantissa
+                       if ((xm >> (13 - hes)) & 1u) // Check for rounding
+                               /* Round, might overflow into exp bit,
+                                * but this is OK */
+                               hm = (uint16_t)(hm + 1u);
+               }
+               /* Combine sign bit and mantissa bits, biased exponent is 0 */
+               *hp = hs | hm;
+
+               return;
+       }
+
+       he = (uint16_t)(hes << 10); // Exponent
+       hm = (uint16_t)(xm >> 13); // Mantissa
+
+       if (xm & 0x00001000u) // Check for rounding
+               /* Round, might overflow to inf, this is OK */
+               *hp = (uint16_t)((hs | he | hm) + (uint16_t)1u);
+       else
+               *hp = hs | he | hm;  // No rounding
+}
+
+void
+lws_halfp2singles(uint32_t *xp, uint16_t h)
+{
+       uint16_t hs, he, hm;
+       uint32_t xs, xe, xm;
+       int32_t xes;
+       int e;
+
+       if (!(h & 0x7FFFu)) {  // Signed zero
+               *xp = ((uint32_t)h) << 16;  // Return the signed zero
+
+               return;
+       }
+
+       hs = h & 0x8000u;  // Pick off sign bit
+       he = h & 0x7C00u;  // Pick off exponent bits
+       hm = h & 0x03FFu;  // Pick off mantissa bits
+
+       if (!he) {  // Denormal will convert to normalized
+               e = -1;
+
+               /* figure out how much extra to adjust the exponent */
+               do {
+                       e++;
+                       hm = (uint16_t)(hm << 1);
+                       /* Shift until leading bit overflows into exponent */
+               } while (!(hm & 0x0400u));
+
+               xs = ((uint32_t) hs) << 16; // Sign bit
+
+               /* Exponent unbias the halfp, then bias the single */
+               xes = ((int32_t)(he >> 10)) - 15 + 127 - e;
+               xe = (uint32_t)(xes << 23); // Exponent
+               xm = ((uint32_t)(hm & 0x03FFu)) << 13; // Mantissa
+
+               *xp = xs | xe | xm;
+
+               return;
+       }
+
+       if (he == 0x7C00u) {  /* Inf or NaN (all the exponent bits are set) */
+               if (!hm) { /* If mantissa is zero ...
+                         * Signed Inf
+                         */
+                       *xp = (((uint32_t)hs) << 16) | ((uint32_t)0x7F800000u);
+
+                       return;
+               }
+
+                /* ... NaN, only 1st mantissa bit set */
+               *xp = (uint32_t)0xFFC00000u;
+
+               return;
+       }
+
+       /* Normalized number */
+
+       xs = ((uint32_t)hs) << 16; // Sign bit
+       /* Exponent unbias the halfp, then bias the single */
+       xes = ((int32_t)(he >> 10)) - 15 + 127;
+       xe = (uint32_t)(xes << 23); // Exponent
+       xm = ((uint32_t)hm) << 13; // Mantissa
+
+       /* Combine sign bit, exponent bits, and mantissa bits */
+       *xp = xs | xe | xm;
+}
diff --git a/lib/misc/lecp.c b/lib/misc/lecp.c
new file mode 100644 (file)
index 0000000..4783241
--- /dev/null
@@ -0,0 +1,1686 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Stream parser for RFC8949 CBOR
+ */
+
+#include "private-lib-core.h"
+#include <string.h>
+#include <stdio.h>
+
+#if defined(LWS_WITH_CBOR_FLOAT)
+#include <math.h>
+#endif
+
+#define lwsl_lecp lwsl_debug
+
+static const char * const parser_errs[] = {
+       "",
+       "",
+       "Bad CBOR coding",
+       "Unknown",
+       "Parser callback errored (see earlier error)",
+       "Overflow"
+};
+
+enum lecp_states {
+       LECP_OPC,
+       LECP_COLLECT,
+       LECP_SIMPLEX8,
+       LECP_COLLATE,
+       LECP_ONLY_SAME
+};
+
+void
+lecp_construct(struct lecp_ctx *ctx, lecp_callback cb, void *user,
+              const char * const *paths, unsigned char count_paths)
+{
+       uint16_t x = 0x1234;
+
+       memset(ctx, 0, sizeof(*ctx) - sizeof(ctx->buf));
+
+       ctx->user               = user;
+       ctx->pst[0].cb          = cb;
+       ctx->pst[0].paths       = paths;
+       ctx->pst[0].count_paths = count_paths;
+       ctx->be                 = *((uint8_t *)&x) == 0x12;
+
+       ctx->st[0].s            = LECP_OPC;
+
+       ctx->pst[0].cb(ctx, LECPCB_CONSTRUCTED);
+}
+
+void
+lecp_destruct(struct lecp_ctx *ctx)
+{
+       /* no allocations... just let callback know what it happening */
+       if (ctx->pst[0].cb)
+               ctx->pst[0].cb(ctx, LECPCB_DESTRUCTED);
+}
+
+void
+lecp_change_callback(struct lecp_ctx *ctx, lecp_callback cb)
+{
+       ctx->pst[0].cb(ctx, LECPCB_DESTRUCTED);
+       ctx->pst[0].cb = cb;
+       ctx->pst[0].cb(ctx, LECPCB_CONSTRUCTED);
+}
+
+
+const char *
+lecp_error_to_string(int e)
+{
+       if (e > 0)
+               e = 0;
+       else
+               e = -e;
+
+       if (e >= (int)LWS_ARRAY_SIZE(parser_errs))
+               return "Unknown error";
+
+       return parser_errs[e];
+}
+
+static void
+ex(struct lecp_ctx *ctx, void *_start, size_t len)
+{
+       struct _lecp_stack *st = &ctx->st[ctx->sp];
+       uint8_t *start = (uint8_t *)_start;
+
+       st->s = LECP_COLLECT;
+       st->collect_rem = (uint8_t)len;
+
+       if (ctx->be)
+               ctx->collect_tgt = start;
+       else
+               ctx->collect_tgt = start + len - 1;
+}
+
+static void
+lecp_check_path_match(struct lecp_ctx *ctx)
+{
+       const char *p, *q;
+       size_t s = sizeof(char *);
+       int n;
+
+       if (ctx->path_stride)
+               s = ctx->path_stride;
+
+       /* we only need to check if a match is not active */
+       for (n = 0; !ctx->path_match &&
+            n < ctx->pst[ctx->pst_sp].count_paths; n++) {
+               ctx->wildcount = 0;
+               p = ctx->path;
+
+               q = *((char **)(((char *)ctx->pst[ctx->pst_sp].paths) +
+                                                       ((unsigned int)n * s)));
+
+               while (*p && *q) {
+                       if (*q != '*') {
+                               if (*p != *q)
+                                       break;
+                               p++;
+                               q++;
+                               continue;
+                       }
+                       ctx->wild[ctx->wildcount++] =
+                                   (uint16_t)lws_ptr_diff_size_t(p, ctx->path);
+                       q++;
+                       /*
+                        * if * has something after it, match to .
+                        * if ends with *, eat everything.
+                        * This implies match sequences must be ordered like
+                        *  x.*.*
+                        *  x.*
+                        * if both options are possible
+                        */
+                       while (*p && (*p != '.' || !*q))
+                               p++;
+               }
+               if (*p || *q)
+                       continue;
+
+               ctx->path_match = (uint8_t)(n + 1);
+               ctx->path_match_len = ctx->pst[ctx->pst_sp].ppos;
+               return;
+       }
+
+       if (!ctx->path_match)
+               ctx->wildcount = 0;
+}
+
+int
+lecp_push(struct lecp_ctx *ctx, char s_start, char s_end, char state)
+{
+       struct _lecp_stack *st = &ctx->st[ctx->sp];
+
+       if (ctx->sp + 1 == LWS_ARRAY_SIZE(ctx->st))
+               return LECP_STACK_OVERFLOW;
+
+       if (s_start && ctx->pst[ctx->pst_sp].cb(ctx, s_start))
+               return LECP_REJECT_CALLBACK;
+
+       lwsl_lecp("%s: pushing from sp %d, parent "
+                 "(opc %d, indet %d, collect_rem %d)\n",
+                 __func__, ctx->sp, st->opcode >> 5, st->indet,
+                 (int)st->collect_rem);
+
+
+       st->pop_iss = s_end; /* issue this when we pop back here */
+       ctx->st[ctx->sp + 1] = *st;
+       ctx->sp++;
+       st++;
+
+       st->s                   = state;
+       st->collect_rem         = 0;
+       st->intermediate        = 0;
+       st->indet               = 0;
+       st->ordinal             = 0;
+       st->send_new_array_item = 0;
+       st->barrier             = 0;
+
+       return 0;
+}
+
+int
+lecp_pop(struct lecp_ctx *ctx)
+{
+       struct _lecp_stack *st;
+
+       assert(ctx->sp);
+       ctx->sp--;
+
+       st = &ctx->st[ctx->sp];
+
+       if (st->pop_iss == LECPCB_ARRAY_END) {
+               assert(ctx->ipos);
+               ctx->ipos--;
+       }
+
+       ctx->pst[ctx->pst_sp].ppos = st->p;
+       ctx->path[st->p] = '\0';
+       lecp_check_path_match(ctx);
+
+       lwsl_lecp("%s: popping to sp %d, parent "
+                 "(opc %d, indet %d, collect_rem %d)\n",
+                  __func__, ctx->sp, st->opcode >> 5, st->indet,
+                  (int)st->collect_rem);
+
+       if (st->pop_iss && ctx->pst[ctx->pst_sp].cb(ctx, st->pop_iss))
+               return LECP_REJECT_CALLBACK;
+
+       return 0;
+}
+
+static struct _lecp_stack *
+lwcp_st_parent(struct lecp_ctx *ctx)
+{
+       assert(ctx->sp);
+
+       return &ctx->st[ctx->sp - 1];
+}
+
+int
+lwcp_completed(struct lecp_ctx *ctx, char indet)
+{
+       int r, il = ctx->ipos;
+
+       ctx->st[ctx->sp].s = LECP_OPC;
+
+       while (ctx->sp && !ctx->st[ctx->sp].barrier) {
+               struct _lecp_stack *parent = lwcp_st_parent(ctx);
+
+               lwsl_lecp("%s: sp %d, parent "
+                         "(opc %d, indet %d, collect_rem %d)\n",
+                         __func__, ctx->sp, parent->opcode >> 5, parent->indet,
+                         (int)parent->collect_rem);
+
+               parent->ordinal++;
+               if (parent->opcode == LWS_CBOR_MAJTYP_ARRAY) {
+                       assert(il);
+                       il--;
+                       ctx->i[il]++;
+                       if (!parent->send_new_array_item) {
+                               if (ctx->pst[ctx->pst_sp].cb(ctx,
+                                               LECPCB_ARRAY_ITEM_END))
+                                       return LECP_REJECT_CALLBACK;
+                               parent->send_new_array_item = 1;
+                       }
+               }
+
+               if (!indet && parent->indet) {
+                       lwsl_lecp("%s: abandoning walk as parent needs indet\n", __func__);
+                       break;
+               }
+
+               if (!parent->indet && parent->collect_rem) {
+                       parent->collect_rem--;
+                       lwsl_lecp("%s: sp %d, parent (opc %d, indet %d, collect_rem -> %d)\n",
+                                       __func__, ctx->sp, parent->opcode >> 5, parent->indet, (int)parent->collect_rem);
+
+                       if (parent->collect_rem) {
+                               /* more items to come */
+                               if (parent->opcode == LWS_CBOR_MAJTYP_ARRAY)
+                                       parent->send_new_array_item = 1;
+                               break;
+                       }
+               }
+
+               lwsl_lecp("%s: parent (opc %d) collect_rem became zero\n", __func__, parent->opcode >> 5);
+
+               ctx->st[ctx->sp - 1].s = LECP_OPC;
+               r = lecp_pop(ctx);
+               if (r)
+                       return r;
+               indet = 0;
+       }
+
+       return 0;
+}
+
+static int
+lwcp_is_indet_string(struct lecp_ctx *ctx)
+{
+       if (ctx->st[ctx->sp].indet)
+               return 1;
+
+       if (!ctx->sp)
+               return 0;
+
+       if (lwcp_st_parent(ctx)->opcode != LWS_CBOR_MAJTYP_BSTR &&
+           lwcp_st_parent(ctx)->opcode != LWS_CBOR_MAJTYP_TSTR)
+               return 0;
+
+       if (ctx->st[ctx->sp - 1].indet)
+               return 1;
+
+       return 0;
+}
+
+static int
+report_raw_cbor(struct lecp_ctx *ctx)
+{
+       struct _lecp_parsing_stack *pst = &ctx->pst[ctx->pst_sp];
+
+       if (!ctx->cbor_pos)
+               return 0;
+
+       if (pst->cb(ctx, LECPCB_LITERAL_CBOR))
+               return 1;
+
+       ctx->cbor_pos = 0;
+
+       return 0;
+}
+
+void
+lecp_parse_report_raw(struct lecp_ctx *ctx, int on)
+{
+       ctx->literal_cbor_report = (uint8_t)on;
+       report_raw_cbor(ctx);
+}
+
+int
+lecp_parse_map_is_key(struct lecp_ctx *ctx)
+{
+       return lwcp_st_parent(ctx)->opcode == LWS_CBOR_MAJTYP_MAP &&
+              !(lwcp_st_parent(ctx)->ordinal & 1);
+}
+
+int
+lecp_parse_subtree(struct lecp_ctx *ctx, const uint8_t *in, size_t len)
+{
+       struct _lecp_stack *st = &ctx->st[++ctx->sp];
+       int n;
+
+       st->s                   = 0;
+       st->collect_rem         = 0;
+       st->intermediate        = 0;
+       st->indet               = 0;
+       st->ordinal             = 0;
+       st->send_new_array_item = 0;
+       st->barrier             = 1;
+
+       n = lecp_parse(ctx, in, len);
+       ctx->sp--;
+
+       return n;
+}
+
+int
+lecp_parse(struct lecp_ctx *ctx, const uint8_t *cbor, size_t len)
+{
+       size_t olen = len;
+       int ret;
+
+       while (len--) {
+               struct _lecp_parsing_stack *pst = &ctx->pst[ctx->pst_sp];
+               struct _lecp_stack *st = &ctx->st[ctx->sp];
+               uint8_t c, sm, o;
+               char to;
+
+               c = *cbor++;
+
+               /*
+                * for, eg, cose_sign, we sometimes need to collect subtrees of
+                * raw CBOR.  Report buffers of it via the callback if we filled
+                * the buffer, or we stopped collecting.
+                */
+
+               if (ctx->literal_cbor_report) {
+                       ctx->cbor[ctx->cbor_pos++] = c;
+                       if (ctx->cbor_pos == sizeof(ctx->cbor) &&
+                           report_raw_cbor(ctx))
+                               goto reject_callback;
+               }
+
+               switch (st->s) {
+               /*
+                * We're getting the nex opcode
+                */
+               case LECP_OPC:
+                       st->opcode = ctx->item.opcode = c & LWS_CBOR_MAJTYP_MASK;
+                       sm = c & LWS_CBOR_SUBMASK;
+                       to = 0;
+
+                       lwsl_lecp("%s: %d: OPC %d|%d\n", __func__, ctx->sp,
+                                       c >> 5, sm);
+
+                       if (c != 0xff && ctx->sp &&
+                           ctx->st[ctx->sp - 1].send_new_array_item) {
+                               ctx->st[ctx->sp - 1].send_new_array_item = 0;
+                               if (ctx->pst[ctx->pst_sp].cb(ctx,
+                                               LECPCB_ARRAY_ITEM_START))
+                                       goto reject_callback;
+                       }
+
+                       switch (st->opcode) {
+                       case LWS_CBOR_MAJTYP_UINT:
+                               ctx->present = LECPCB_VAL_NUM_UINT;
+                               if (sm < LWS_CBOR_1) {
+                                       ctx->item.u.i64 = (int64_t)sm;
+                                       goto issue;
+                               }
+                               goto i2;
+
+                       case LWS_CBOR_MAJTYP_INT_NEG:
+                               ctx->present = LECPCB_VAL_NUM_INT;
+                               if (sm < 24) {
+                                       ctx->item.u.i64 = (-1ll) - (int64_t)sm;
+                                       goto issue;
+                               }
+i2:
+                               if (sm >= LWS_CBOR_RESERVED)
+                                       goto bad_coding;
+                               ctx->item.u.u64 = 0;
+                               o = (uint8_t)(1 << (sm - LWS_CBOR_1));
+                               ex(ctx, (uint8_t *)&ctx->item.u.u64, o);
+                               break;
+
+                       case LWS_CBOR_MAJTYP_BSTR:
+                               to = LECPCB_VAL_BLOB_END - LECPCB_VAL_STR_END;
+
+                               /* fallthru */
+
+                       case LWS_CBOR_MAJTYP_TSTR:
+                               /*
+                                * The first thing is the string length, it's
+                                * going to either be a byte count for the
+                                * string or the indefinite length marker
+                                * followed by determinite-length chunks of the
+                                * same MAJTYP
+                                */
+
+                               ctx->npos = 0;
+                               ctx->buf[0] = '\0';
+
+                               if (!sm) {
+                                       if ((!ctx->sp || (ctx->sp &&
+                                           !ctx->st[ctx->sp - 1].intermediate)) &&
+                                           pst->cb(ctx, (char)(LECPCB_VAL_STR_START + to)))
+                                               goto reject_callback;
+
+                                       if (pst->cb(ctx, (char)(LECPCB_VAL_STR_END + to)))
+                                               goto reject_callback;
+                                       lwcp_completed(ctx, 0);
+                                       break;
+                               }
+
+                               if (sm < LWS_CBOR_1) {
+                                       ctx->item.u.u64 = (uint64_t)sm;
+                                       if ((!ctx->sp || (ctx->sp &&
+                                           !ctx->st[ctx->sp - 1].intermediate)) &&
+                                           pst->cb(ctx, (char)(LECPCB_VAL_STR_START + to)))
+                                               goto reject_callback;
+
+                                       st->indet = 0;
+                                       st->collect_rem = sm;
+                                       st->s = LECP_COLLATE;
+                                       break;
+                               }
+
+                               if (sm < LWS_CBOR_RESERVED)
+                                       goto i2;
+
+                               if (sm != LWS_CBOR_INDETERMINITE)
+                                       goto bad_coding;
+
+                               if ((!ctx->sp || (ctx->sp &&
+                                   !ctx->st[ctx->sp - 1].intermediate)) &&
+                                   pst->cb(ctx, (char)(LECPCB_VAL_STR_START + to)))
+                                       goto reject_callback;
+
+                               st->indet = 1;
+
+                               st->p = pst->ppos;
+                               lecp_push(ctx, 0, (char)(LECPCB_VAL_STR_END + to),
+                                                 LECP_ONLY_SAME);
+                               break;
+
+                       case LWS_CBOR_MAJTYP_ARRAY:
+                               ctx->npos = 0;
+                               ctx->buf[0] = '\0';
+
+                               if (pst->ppos + 3u >= sizeof(ctx->path))
+                                       goto reject_overflow;
+
+                               st->p = pst->ppos;
+                               ctx->path[pst->ppos++] = '[';
+                               ctx->path[pst->ppos++] = ']';
+                               ctx->path[pst->ppos] = '\0';
+
+                               lecp_check_path_match(ctx);
+
+                               if (ctx->ipos + 1u >= LWS_ARRAY_SIZE(ctx->i))
+                                       goto reject_overflow;
+
+                               ctx->i[ctx->ipos++] = 0;
+
+                               if (pst->cb(ctx, LECPCB_ARRAY_START))
+                                       goto reject_callback;
+
+                               if (!sm) {
+                                       if (pst->cb(ctx, LECPCB_ARRAY_END))
+                                               goto reject_callback;
+                                       pst->ppos = st->p;
+                                       ctx->path[pst->ppos] = '\0';
+                                       ctx->ipos--;
+                                       lecp_check_path_match(ctx);
+                                       lwcp_completed(ctx, 0);
+                                       break;
+                               }
+
+                               ctx->st[ctx->sp].send_new_array_item = 1;
+
+                               if (sm < LWS_CBOR_1) {
+                                       st->indet = 0;
+                                       st->collect_rem = sm;
+                                       goto push_a;
+                               }
+
+                               if (sm < LWS_CBOR_RESERVED)
+                                       goto i2;
+
+                               if (sm != LWS_CBOR_INDETERMINITE)
+                                       goto bad_coding;
+
+                               st->indet = 1;
+push_a:
+                               lecp_push(ctx, 0, LECPCB_ARRAY_END, LECP_OPC);
+                               break;
+
+                       case LWS_CBOR_MAJTYP_MAP:
+                               ctx->npos = 0;
+                               ctx->buf[0] = '\0';
+
+                               if (pst->ppos + 1u >= sizeof(ctx->path))
+                                       goto reject_overflow;
+
+                               st->p = pst->ppos;
+                               ctx->path[pst->ppos++] = '.';
+                               ctx->path[pst->ppos] = '\0';
+
+                               lecp_check_path_match(ctx);
+
+                               if (pst->cb(ctx, LECPCB_OBJECT_START))
+                                       goto reject_callback;
+
+                               if (!sm) {
+                                       if (pst->cb(ctx, LECPCB_OBJECT_END))
+                                               goto reject_callback;
+                                       pst->ppos = st->p;
+                                       ctx->path[pst->ppos] = '\0';
+                                       lecp_check_path_match(ctx);
+                                       lwcp_completed(ctx, 0);
+                                       break;
+                               }
+                               if (sm < LWS_CBOR_1) {
+                                       st->indet = 0;
+                                       st->collect_rem = (uint64_t)(sm * 2);
+                                       goto push_m;
+                               }
+
+                               if (sm < LWS_CBOR_RESERVED)
+                                       goto i2;
+
+                               if (sm != LWS_CBOR_INDETERMINITE)
+                                       goto bad_coding;
+
+                               st->indet = 1;
+push_m:
+                               lecp_push(ctx, 0, LECPCB_OBJECT_END, LECP_OPC);
+                               break;
+
+                       case LWS_CBOR_MAJTYP_TAG:
+                               /* tag has one or another kind of int first */
+                               if (sm < LWS_CBOR_1) {
+                                       /*
+                                        * We have a literal tag number, push
+                                        * to decode the tag body
+                                        */
+                                       ctx->item.u.u64 = st->tag = (uint64_t)sm;
+                                       goto start_tag_enclosure;
+                               }
+                               /*
+                                * We have to do more stuff to get the tag
+                                * number...
+                                */
+                               goto i2;
+
+                       case LWS_CBOR_MAJTYP_FLOAT:
+                               /*
+                                * This can also be a bunch of specials as well
+                                * as sizes of float...
+                                */
+                               sm = c & LWS_CBOR_SUBMASK;
+
+                               switch (sm) {
+                               case LWS_CBOR_SWK_FALSE:
+                                       ctx->present = LECPCB_VAL_FALSE;
+                                       goto issue;
+
+                               case LWS_CBOR_SWK_TRUE:
+                                       ctx->present = LECPCB_VAL_TRUE;
+                                       goto issue;
+
+                               case LWS_CBOR_SWK_NULL:
+                                       ctx->present = LECPCB_VAL_NULL;
+                                       goto issue;
+
+                               case LWS_CBOR_SWK_UNDEFINED:
+                                       ctx->present = LECPCB_VAL_UNDEFINED;
+                                       goto issue;
+
+                               case LWS_CBOR_M7_SUBTYP_SIMPLE_X8:
+                                       st->s = LECP_SIMPLEX8;
+                                       break;
+
+                               case LWS_CBOR_M7_SUBTYP_FLOAT16:
+                                       ctx->present = LECPCB_VAL_FLOAT16;
+                                       ex(ctx, &ctx->item.u.hf, 2);
+                                       break;
+
+                               case LWS_CBOR_M7_SUBTYP_FLOAT32:
+                                       ctx->present = LECPCB_VAL_FLOAT32;
+                                       ex(ctx, &ctx->item.u.f, 4);
+                                       break;
+
+                               case LWS_CBOR_M7_SUBTYP_FLOAT64:
+                                       ctx->present = LECPCB_VAL_FLOAT64;
+                                       ex(ctx, &ctx->item.u.d, 8);
+                                       break;
+
+                               case LWS_CBOR_M7_BREAK:
+                                       if (!ctx->sp ||
+                                           !ctx->st[ctx->sp - 1].indet)
+                                               goto bad_coding;
+
+                                       lwcp_completed(ctx, 1);
+                                       break;
+
+                               default:
+                                       /* handle as simple */
+                                       ctx->item.u.u64 = (uint64_t)sm;
+                                       if (pst->cb(ctx, LECPCB_VAL_SIMPLE))
+                                               goto reject_callback;
+                                       break;
+                               }
+                               break;
+                       }
+                       break;
+
+               /*
+                * We're collecting int / float pieces
+                */
+               case LECP_COLLECT:
+                       if (ctx->be)
+                               *ctx->collect_tgt++ = c;
+                       else
+                               *ctx->collect_tgt-- = c;
+
+                       if (--st->collect_rem)
+                               break;
+
+                       /*
+                        * We collected whatever it was...
+                        */
+
+                       ctx->npos = 0;
+                       ctx->buf[0] = '\0';
+
+                       switch (st->opcode) {
+                       case LWS_CBOR_MAJTYP_BSTR:
+                       case LWS_CBOR_MAJTYP_TSTR:
+                               st->collect_rem = ctx->item.u.u64;
+                               if ((!ctx->sp || (ctx->sp &&
+                                   !ctx->st[ctx->sp - 1].intermediate)) &&
+                                   pst->cb(ctx, (char)((st->opcode ==
+                                                   LWS_CBOR_MAJTYP_TSTR) ?
+                                                       LECPCB_VAL_STR_START :
+                                                       LECPCB_VAL_BLOB_START)))
+                                       goto reject_callback;
+                               st->s = LECP_COLLATE;
+                               break;
+
+                       case LWS_CBOR_MAJTYP_ARRAY:
+                               st->collect_rem = ctx->item.u.u64;
+                               lecp_push(ctx, 0, LECPCB_ARRAY_END, LECP_OPC);
+                               break;
+
+                       case LWS_CBOR_MAJTYP_MAP:
+                               st->collect_rem = ctx->item.u.u64 * 2;
+                               lecp_push(ctx, 0, LECPCB_OBJECT_END, LECP_OPC);
+                               break;
+
+                       case LWS_CBOR_MAJTYP_TAG:
+                               st->tag = ctx->item.u.u64;
+                               goto start_tag_enclosure;
+
+                       default:
+                               /*
+                                * ... then issue what we collected as a
+                                * literal
+                                */
+
+                               if (st->opcode == LWS_CBOR_MAJTYP_INT_NEG)
+                                       ctx->item.u.i64 = (-1ll) - ctx->item.u.i64;
+
+                               goto issue;
+                       }
+                       break;
+
+               case LECP_SIMPLEX8:
+                       /*
+                        * Extended SIMPLE byte for 7|24 opcode, no uses
+                        * for it in RFC8949
+                        */
+                       if (c <= LWS_CBOR_INDETERMINITE)
+                               /*
+                                * Duplication of implicit simple values is
+                                * denied by RFC8949 3.3
+                                */
+                               goto bad_coding;
+
+                       ctx->item.u.u64 = (uint64_t)c;
+                       if (pst->cb(ctx, LECPCB_VAL_SIMPLE))
+                               goto reject_callback;
+
+                       lwcp_completed(ctx, 0);
+                       break;
+
+               case LECP_COLLATE:
+                       /*
+                        * let's grab b/t string content into the context
+                        * buffer, and issue chunks from there
+                        */
+
+                       ctx->buf[ctx->npos++] = (char)c;
+                       if (st->collect_rem)
+                               st->collect_rem--;
+
+                       /* spill at chunk boundaries, or if we filled the buf */
+                       if (ctx->npos != sizeof(ctx->buf) - 1 &&
+                           st->collect_rem)
+                               break;
+
+                       /* spill */
+                       ctx->buf[ctx->npos] = '\0';
+
+                       /* if it's a map name, deal with the path */
+                       if (ctx->sp && lecp_parse_map_is_key(ctx)) {
+                               if (lwcp_st_parent(ctx)->ordinal)
+                                       pst->ppos = st->p;
+                               st->p = pst->ppos;
+                               if (pst->ppos + ctx->npos > sizeof(ctx->path))
+                                       goto reject_overflow;
+                               memcpy(&ctx->path[pst->ppos], ctx->buf,
+                                      (size_t)(ctx->npos + 1));
+                               pst->ppos = (uint8_t)(pst->ppos + ctx->npos);
+                               lecp_check_path_match(ctx);
+                       }
+
+                       to = 0;
+                       if (ctx->item.opcode == LWS_CBOR_MAJTYP_BSTR)
+                               to = LECPCB_VAL_BLOB_END - LECPCB_VAL_STR_END;
+
+                       o = (uint8_t)(LECPCB_VAL_STR_END + to);
+                       c = (st->collect_rem /* more to come at this layer */ ||
+                           /* we or direct parent is indeterminite */
+                           lwcp_is_indet_string(ctx));
+
+                       if (ctx->sp)
+                               ctx->st[ctx->sp - 1].intermediate = !!c;
+                       if (c)
+                               o--;
+
+                       if (pst->cb(ctx, (char)o))
+                               goto reject_callback;
+                       ctx->npos = 0;
+                       ctx->buf[0] = '\0';
+
+                       if (ctx->sp && lwcp_st_parent(ctx)->indet)
+                               st->s = LECP_OPC;
+                       if (o == LECPCB_VAL_STR_END + to)
+                               lwcp_completed(ctx, 0);
+
+                       break;
+
+               case LECP_ONLY_SAME:
+                       /*
+                        * deterministic sized chunks same MAJTYP as parent
+                        * level only (BSTR and TSTR frags inside interderminite
+                        * BSTR or TSTR)
+                        *
+                        * Clean end when we see M7|31
+                        */
+                       if (!ctx->sp) {
+                               /*
+                                * We should only come here by pushing on stack
+                                */
+                               assert(0);
+                               return LECP_STACK_OVERFLOW;
+                       }
+
+                       if (c == (LWS_CBOR_MAJTYP_FLOAT | LWS_CBOR_M7_BREAK)) {
+                               /* if's the end of an interdetminite list */
+                               if (!ctx->sp || !ctx->st[ctx->sp - 1].indet)
+                                       /*
+                                        * Can't have a break without an
+                                        * indeterminite parent
+                                        */
+                                       goto bad_coding;
+
+                               if (lwcp_completed(ctx, 1))
+                                       goto reject_callback;
+                               break;
+                       }
+
+                       if (st->opcode != lwcp_st_parent(ctx)->opcode)
+                               /*
+                                * Fragments have to be of the same type as the
+                                * outer opcode
+                                */
+                               goto bad_coding;
+
+                       sm = c & LWS_CBOR_SUBMASK;
+
+                       if (sm == LWS_CBOR_INDETERMINITE)
+                               /* indeterminite length frags not allowed */
+                               goto bad_coding;
+
+                       if (sm < LWS_CBOR_1) {
+                               st->indet = 0;
+                               st->collect_rem = (uint64_t)sm;
+                               st->s = LECP_COLLATE;
+                               break;
+                       }
+
+                       if (sm >= LWS_CBOR_RESERVED)
+                               goto bad_coding;
+
+                       goto i2;
+
+               default:
+                       assert(0);
+                       return -1;
+               }
+
+               continue;
+
+start_tag_enclosure:
+               st->p = pst->ppos;
+               ret = lecp_push(ctx, LECPCB_TAG_START, LECPCB_TAG_END, LECP_OPC);
+               if (ret)
+                       return ret;
+
+               continue;
+
+issue:
+               if (ctx->item.opcode == LWS_CBOR_MAJTYP_TAG) {
+                       st->tag = ctx->item.u.u64;
+                       goto start_tag_enclosure;
+               }
+
+               /* we are just a number */
+
+               if (pst->cb(ctx, ctx->present))
+                       goto reject_callback;
+
+               lwcp_completed(ctx, 0);
+
+       }
+
+       ctx->used_in = olen - len;
+
+       if (!ctx->sp && ctx->st[0].s == LECP_OPC)
+               return 0;
+
+       return LECP_CONTINUE;
+
+reject_overflow:
+       ret = LECP_STACK_OVERFLOW;
+       goto reject;
+
+bad_coding:
+       ret = LECP_REJECT_BAD_CODING;
+       goto reject;
+
+reject_callback:
+       ret = LECP_REJECT_CALLBACK;
+
+reject:
+       ctx->pst[ctx->pst_sp].cb(ctx, LECPCB_FAILED);
+
+       return ret;
+}
+
+
+
+void
+lws_lec_init(lws_lec_pctx_t *ctx, uint8_t *buf, size_t len)
+{
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->start = ctx->buf = buf;
+       ctx->end = ctx->start + len;
+       ctx->fmt_pos = 0;
+}
+
+void
+lws_lec_setbuf(lws_lec_pctx_t *ctx, uint8_t *buf, size_t len)
+{
+       ctx->start = ctx->buf = buf;
+       ctx->end = ctx->start + len;
+       ctx->used = 0;
+       ctx->vaa_pos = 0;
+}
+
+enum lws_lec_pctx_ret
+lws_lec_printf(lws_lec_pctx_t *ctx, const char *format, ...)
+{
+       enum lws_lec_pctx_ret r;
+       va_list ap;
+
+       va_start(ap, format);
+       r = lws_lec_vsprintf(ctx, format, ap);
+       va_end(ap);
+
+       return r;
+}
+
+/*
+ * Report how many next-level elements inbetween fmt[0] and the matching
+ * closure, eg, [] returns 0,  [123] would return 1, [123,456] returns 2, and
+ * [123,{'a':[123,456]}] returns 2.  Counts for { } maps are in pairs, ie,
+ * {'a':1, 'b': 2} returns 2
+ *
+ * If there is no closure in the string it returns -1
+ *
+ * We use this to figure out if we should use indeterminite lengths or specific
+ * lengths for items in the format string
+ */
+
+#define bump(_r) count[sp]++
+//; lwsl_notice("%s: count[%d] -> %d\n", _r, sp, count[sp])
+
+static int
+format_scan(const char *fmt)
+{
+       char stack[12], literal = 0, numeric = 0;
+       int count[12], sp = 0, pc = 0, swallow = 0;
+
+       literal = *fmt == '\'';
+       stack[sp] = *fmt++;
+       count[sp] = 0;
+
+//     lwsl_notice("%s: start %s\n", __func__, fmt - 1);
+
+       while (*fmt) {
+
+//             lwsl_notice("%s: %c %d %d\n", __func__, *fmt, sp, literal);
+
+               if (swallow) {
+                       swallow--;
+                       fmt++;
+                       continue;
+               }
+
+               if (numeric) {
+                       if (*fmt >= '0' && *fmt <= '9')
+                               fmt++;
+                       numeric = 0;
+                       if (*fmt != '(')
+                               bump("a");
+               }
+
+               if (literal) {
+                       if (*fmt == '\\' && fmt[1]) {
+                               fmt += 2;
+                               continue;
+                       }
+                       if (*fmt == '\'') {
+                               literal = 0;
+                               if (!sp && stack[sp] == '\'')
+                                       return count[sp];
+
+                               if (sp)
+                                       sp--;
+                               fmt++;
+                               continue;
+                       }
+
+                       bump("b");
+                       fmt++;
+                       continue;
+               }
+
+               if (*fmt == '\'') {
+                       bump("c");
+                       sp++;
+                       literal = 1;
+                       fmt++;
+                       continue;
+               }
+
+               switch (pc) {
+               case 1:
+                       if (*fmt == '.') {
+                               pc++;
+                               fmt++;
+                               continue;
+                       }
+                       if (*fmt == 'l') {
+                               pc++;
+                               fmt++;
+                               continue;
+                       }
+                       /* fallthru */
+               case 2:
+                       if (*fmt == '*') {
+                               pc++;
+                               fmt++;
+                               continue;
+                       }
+                       if (*fmt == 'l') {
+                               pc++;
+                               fmt++;
+                               continue;
+                       }
+                       /* fallthru */
+               case 3:
+                       bump("pc");
+                       pc = 0;
+                       fmt++;
+                       continue;
+               }
+
+               switch (*fmt) {
+
+               case '<':
+                       swallow = 1;
+                       /* fallthru */
+               case '[':
+               case '(':
+               case '{':
+                       if (sp == sizeof(stack))
+                               return -2;
+
+                       bump("d");
+                       sp++;
+                       stack[sp] = *fmt;
+                       count[sp] = 0;
+                       break;
+               case ' ':
+                       break;
+               case ',':
+                       //count[sp]++;
+                       break;
+               case ':':
+                       if (stack[sp] != '{')
+                               goto mismatch;
+                       //count[sp]++;
+                       break;
+               case '%':
+                       pc = 1;
+                       break;
+               case ']':
+                       if (stack[sp] != '[')
+                               goto mismatch;
+                       goto pop;
+               case ')':
+                       if (stack[sp] != '(')
+                               goto mismatch;
+                       goto pop;
+               case '}':
+                       if (stack[sp] != '{')
+                               goto mismatch;
+                       goto pop;
+               case '>':
+                       if (stack[sp] != '<')
+                               goto mismatch;
+pop:
+                       if (sp) {
+                               sp--;
+                               break;
+                       }
+
+                       if (stack[0] == '{') {
+                               /* args have to come in pairs */
+                               if (count[0] & 1) {
+                                       lwsl_err("%s: odd map args %d %s\n",
+                                                       __func__, count[0], fmt);
+                                       return -2;
+                               }
+                               // lwsl_notice("%s: return %d pairs\n", __func__, count[0] >> 1);
+                               /* report how many pairs */
+                               return count[0] >> 1;
+                       }
+
+                       // lwsl_notice("%s: return %d items\n", __func__, count[0]);
+
+                       return count[0];
+
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       numeric = 1;
+
+                       break;
+
+               default:
+                       bump("e");
+                       break;
+               }
+               fmt++;
+       }
+
+       return -1;
+
+mismatch:
+       lwsl_err("%s: format mismatch %c %c\n", __func__, stack[sp], *fmt);
+
+       return -2;
+}
+
+void
+lws_lec_signed(lws_lec_pctx_t *ctx, int64_t num)
+{
+       if (num < 0)
+               lws_lec_int(ctx, LWS_CBOR_MAJTYP_INT_NEG, 0,
+                                       (uint64_t)(-1ll - num));
+       else
+               lws_lec_int(ctx, LWS_CBOR_MAJTYP_UINT, 0, (uint64_t)num);
+}
+
+void
+lws_lec_int(lws_lec_pctx_t *ctx, uint8_t opcode, uint8_t indet, uint64_t num)
+{
+       uint8_t hint = 0;
+       unsigned int n;
+
+       if (indet) {
+               ctx->scratch[ctx->scratch_len++] = (uint8_t)(opcode |
+                                                       LWS_CBOR_INDETERMINITE);
+               return;
+       }
+
+       if ((opcode & LWS_CBOR_MAJTYP_MASK) == LWS_CBOR_MAJTYP_FLOAT) {
+               hint = opcode & LWS_CBOR_SUBMASK;
+               switch (hint) {
+               case LWS_CBOR_M7_SUBTYP_FLOAT16:
+                       num <<= 48;
+                       break;
+               case LWS_CBOR_M7_SUBTYP_FLOAT32:
+                       num <<= 32;
+                       break;
+               }
+       } else {
+
+               if (num < LWS_CBOR_1) {
+                       ctx->scratch[ctx->scratch_len++] = (uint8_t)(opcode | num);
+                       return;
+               }
+
+               if (!(num & (uint64_t)(~0xffull))) {
+                       hint = LWS_CBOR_1;
+                       num <<= 56;
+               } else
+                       if (!(num & (uint64_t)(~0xffffull))) {
+                               hint = LWS_CBOR_2;
+                               num <<= 48;
+                       } else
+                               if (!(num & (uint64_t)(~0xffffffffull))) {
+                                       hint = LWS_CBOR_4;
+                                       num <<= 32;
+                               }
+                               else
+                                       hint = LWS_CBOR_8;
+       }
+
+       ctx->scratch[ctx->scratch_len++] = (uint8_t)(opcode | hint);
+       n = 1u << (hint - LWS_CBOR_1);
+       while (n--) {
+               ctx->scratch[ctx->scratch_len++] = (uint8_t)(num >> 56);
+               num <<= 8;
+       }
+}
+
+enum {
+       NATTYPE_INT,
+       NATTYPE_LONG,
+       NATTYPE_LONG_LONG,
+       NATTYPE_PTR,
+       NATTYPE_DOUBLE,
+};
+
+int
+lws_lec_scratch(lws_lec_pctx_t *ctx)
+{
+       size_t s;
+
+       if (!ctx->scratch_len)
+               return 0;
+
+       s = lws_ptr_diff_size_t(ctx->end, ctx->buf);
+       if (s > (size_t)ctx->scratch_len)
+               s = (size_t)ctx->scratch_len;
+
+       memcpy(ctx->buf, ctx->scratch, s);
+       ctx->buf += s;
+       ctx->scratch_len = (uint8_t)(ctx->scratch_len - (uint8_t)s);
+
+       return ctx->buf == ctx->end;
+}
+
+enum lws_lec_pctx_ret
+lws_lec_vsprintf(lws_lec_pctx_t *ctx, const char *fmt, va_list args)
+{
+       size_t fl = strlen(fmt);
+       uint64_t u64;
+       int64_t i64;
+#if defined(LWS_WITH_CBOR_FLOAT)
+       double dbl;
+#endif
+       size_t s;
+       char c;
+       int n;
+
+       /*
+        * We might be being called after the first time, since we had to emit
+        * output buffer(s) before we could move on in the format string.  For
+        * this case, reposition ourselves at the vaarg we got to from the last
+        * call.
+        */
+
+       for (n = 0; n < ctx->vaa_pos; n++) {
+
+               switch (ctx->vaa[n]) {
+               case NATTYPE_INT:
+                       (void)va_arg(args, int);
+                       break;
+               case NATTYPE_LONG:
+                       (void)va_arg(args, long);
+                       break;
+               case NATTYPE_LONG_LONG:
+                       (void)va_arg(args, long long);
+                       break;
+               case NATTYPE_PTR:
+                       (void)va_arg(args, const char *);
+                       break;
+               case NATTYPE_DOUBLE:
+                       (void)va_arg(args, double);
+                       break;
+               }
+               if (ctx->state == CBPS_STRING_BODY)
+                       /*
+                        * when copying out text or binary strings, we reload
+                        * the %s or %.*s pointer on subsequent calls, in case
+                        * it was on the stack.  The length and contents should
+                        * not change between calls, but it's OK if the source
+                        * address does.
+                        */
+                       ctx->ongoing_src = va_arg(args, uint8_t *);
+       }
+
+       while (ctx->buf != ctx->end) {
+
+               /*
+                * We write small things into the context scratch array, then
+                * copy that into the output buffer fragmenting as needed.  Next
+                * time we will finish emptying the scratch into the output
+                * buffer preferentially.
+                *
+                * Then we don't otherwise have to handle fragmentations in
+                * order to exactly fill the output buffer, simplifying
+                * everything else.
+                */
+
+               if (lws_lec_scratch(ctx))
+                       break;
+
+               if (ctx->fmt_pos >= fl) {
+                       if (ctx->state == CBPS_IDLE)
+                               break;
+                       c = 0;
+               } else
+                       c = fmt[ctx->fmt_pos];
+
+               // lwsl_notice("%s: %d %d %c\n", __func__, ctx->state, ctx->sp, c);
+
+               switch (ctx->state) {
+               case CBPS_IDLE:
+                       ctx->scratch_len = 0;
+                       switch (c) {
+                       case '[':
+                               n = format_scan(&fmt[ctx->fmt_pos]);
+                               if (n == -2)
+                                       return LWS_LECPCTX_RET_FAIL;
+                               lws_lec_int(ctx, LWS_CBOR_MAJTYP_ARRAY, n == -1,
+                                                       (uint64_t)n);
+                               goto stack_push;
+                       case '{':
+                               n = format_scan(&fmt[ctx->fmt_pos]);
+                               if (n == -2)
+                                       return LWS_LECPCTX_RET_FAIL;
+                               lws_lec_int(ctx, LWS_CBOR_MAJTYP_MAP, n == -1,
+                                                       (uint64_t)n);
+                               goto stack_push;
+                       case '(':
+                               /* must be preceded by a number */
+                               goto fail;
+
+                       case '<': /* <t or <b */
+                               ctx->state = CBPS_CONTYPE;
+                               break;
+
+                       case ']':
+                               if (!ctx->sp || ctx->stack[ctx->sp - 1] != '[')
+                                       return LWS_LECPCTX_RET_FAIL;
+                               ctx->sp--;
+                               break;
+                       case '}':
+                               if (!ctx->sp || ctx->stack[ctx->sp - 1] != '{')
+                                       return LWS_LECPCTX_RET_FAIL;
+                               ctx->sp--;
+                               break;
+                       case ')':
+                               if (!ctx->sp || ctx->stack[ctx->sp - 1] != '(') {
+                                       lwsl_notice("bad tag end %d %c\n",
+                                               ctx->sp, ctx->stack[ctx->sp - 1]);
+                                       goto fail;
+                               }
+                               ctx->sp--;
+                               break;
+                       case '>':
+                               if (!ctx->sp || ctx->stack[ctx->sp - 1] != '<')
+                                       return LWS_LECPCTX_RET_FAIL;
+                               ctx->scratch[ctx->scratch_len++] =
+                                               (uint8_t)(LWS_CBOR_MAJTYP_FLOAT |
+                                                       LWS_CBOR_M7_BREAK);
+                               ctx->sp--;
+                               break;
+                       case '\'':
+                               n = format_scan(&fmt[ctx->fmt_pos]);
+                               // lwsl_notice("%s: quote fs %d\n", __func__, n);
+                               if (n < 0)
+                                       return LWS_LECPCTX_RET_FAIL;
+                               lws_lec_int(ctx, LWS_CBOR_MAJTYP_TSTR, 0,
+                                                               (uint64_t)n);
+                               ctx->state = CBPS_STRING_LIT;
+                               break;
+                       case '%':
+                               if (ctx->vaa_pos >= sizeof(ctx->vaa) - 1) {
+                                       lwsl_err("%s: too many %%\n", __func__);
+                                       goto fail;
+                               }
+                               ctx->_long = 0;
+                               ctx->dotstar = 0;
+                               ctx->state = CBPS_PC1;
+                               break;
+                       case ':':
+                               break;
+                       case ',':
+                               break;
+                       case '-':
+                               ctx->item.opcode = LWS_CBOR_MAJTYP_INT_NEG;
+                               ctx->item.u.i64 = 0;
+                               ctx->state = CBPS_NUM_LIT;
+                               break;
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               ctx->item.opcode = LWS_CBOR_MAJTYP_UINT;
+                               ctx->item.u.u64 = (uint64_t)(c - '0');
+                               ctx->state = CBPS_NUM_LIT;
+                               break;
+                       }
+                       break;
+               case CBPS_PC1:
+                       if (c == 'l') {
+                               ctx->_long++;
+                               ctx->state = CBPS_PC2;
+                               break;
+                       }
+                       if (c == '.') {
+                               ctx->dotstar++;
+                               ctx->state = CBPS_PC2;
+                               break;
+                       }
+                       /* fallthru */
+
+               case CBPS_PC2:
+                       if (c == 'l') {
+                               ctx->_long++;
+                               ctx->state = CBPS_PC3;
+                               break;
+                       }
+                       if (c == '*') {
+                               ctx->dotstar++;
+                               ctx->state = CBPS_PC3;
+                               break;
+                       }
+                       /* fallthru */
+
+               case CBPS_PC3:
+                       switch (c) {
+                       case 'd':
+                               switch (ctx->_long) {
+                               case 0:
+                                       i64 = (int64_t)va_arg(args, int);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
+                                       break;
+                               case 1:
+                                       i64 = (int64_t)va_arg(args, long);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG;
+                                       break;
+                               case 2:
+                                       i64 = (int64_t)va_arg(args, long long);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG_LONG;
+                                       break;
+                               }
+                               if (i64 < 0)
+                                       lws_lec_int(ctx,
+                                                   LWS_CBOR_MAJTYP_INT_NEG, 0,
+                                                   (uint64_t)(-1ll - i64));
+                               else
+                                       lws_lec_int(ctx,
+                                                   LWS_CBOR_MAJTYP_UINT, 0,
+                                                   (uint64_t)i64);
+                               break;
+                       case 'u':
+                               switch (ctx->_long) {
+                               case 0:
+                                       u64 = (uint64_t)va_arg(args, unsigned int);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
+                                       break;
+                               case 1:
+                                       u64 = (uint64_t)va_arg(args, unsigned long);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG;
+                                       break;
+                               case 2:
+                                       u64 = (uint64_t)va_arg(args, unsigned long long);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG_LONG;
+                                       break;
+                               }
+                               lws_lec_int(ctx, LWS_CBOR_MAJTYP_UINT, 0, u64);
+                               break;
+                       case 's': /* text string */
+                               ctx->ongoing_done = 0;
+                               if (ctx->dotstar == 2) {
+                                       ctx->ongoing_len = (uint64_t)va_arg(args, int);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
+                               }
+                               /* vaa for ptr done at end of body copy */
+                               ctx->ongoing_src = va_arg(args, uint8_t *);
+                               if (ctx->dotstar != 2)
+                                       ctx->ongoing_len = (uint64_t)strlen(
+                                               (const char *)ctx->ongoing_src);
+                               lws_lec_int(ctx, LWS_CBOR_MAJTYP_TSTR, 0, ctx->ongoing_len);
+                               ctx->state = CBPS_STRING_BODY;
+                               ctx->fmt_pos++;
+                               continue;
+                       case 'b': /* binary string (%.*b only) */
+                               if (ctx->dotstar != 2)
+                                       goto fail;
+                               ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
+                               ctx->ongoing_done = 0;
+                               ctx->ongoing_len = (uint64_t)va_arg(args, int);
+                               /* vaa for ptr done at end of body copy */
+                               ctx->ongoing_src = va_arg(args, uint8_t *);
+                               lws_lec_int(ctx, LWS_CBOR_MAJTYP_BSTR, 0, ctx->ongoing_len);
+                               ctx->state = CBPS_STRING_BODY;
+                               ctx->fmt_pos++;
+                               continue;
+                       case 't': /* dynamic tag */
+                               switch (ctx->_long) {
+                               case 0:
+                                       ctx->item.u.u64 = (uint64_t)va_arg(args, int);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
+                                       break;
+                               case 1:
+                                       ctx->item.u.u64 = (uint64_t)va_arg(args, long);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG;
+                                       break;
+                               case 2:
+                                       ctx->item.u.u64 = (uint64_t)va_arg(args, long long);
+                                       ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG_LONG;
+                                       break;
+                               }
+                               ctx->item.opcode = LWS_CBOR_MAJTYP_UINT;
+                               ctx->fmt_pos++;
+                               if (ctx->fmt_pos >= fl)
+                                       continue;
+                               c = fmt[ctx->fmt_pos];
+                               if (c != '(')
+                                       goto fail;
+                               goto tag_body;
+#if defined(LWS_WITH_CBOR_FLOAT)
+                       case 'f': /* floating point double */
+                               dbl = va_arg(args, double);
+
+                               if (dbl == (float)dbl) {
+                                       uint16_t hf;
+                                       union {
+                                               uint32_t ui;
+                                               float f;
+                                       } u1, u2;
+
+                                       u1.f = (float)dbl;
+                                       lws_singles2halfp(&hf, u1.ui);
+                                       lws_halfp2singles(&u2.ui, hf);
+
+                                       if ((isinf(u1.f) && isinf(u2.f)) ||
+                                           (isnan(u1.f) && isnan(u2.f)) ||
+                                           u1.f == u2.f) {
+                                               lws_lec_int(ctx,
+                                                           LWS_CBOR_MAJTYP_FLOAT |
+                                                           LWS_CBOR_M7_SUBTYP_FLOAT16,
+                                                           0, hf);
+                                               break;
+                                       }
+                                       /* do it as 32-bit float */
+                                       lws_lec_int(ctx,
+                                                   LWS_CBOR_MAJTYP_FLOAT |
+                                                   LWS_CBOR_M7_SUBTYP_FLOAT32,
+                                                   0, u1.ui);
+                                       break;
+                               }
+
+                               /* do it as 64-bit double */
+
+                               {
+                                       union {
+                                               uint64_t ui;
+                                               double f;
+                                       } u3;
+
+                                       u3.f = dbl;
+                                       lws_lec_int(ctx,
+                                                   LWS_CBOR_MAJTYP_FLOAT |
+                                                   LWS_CBOR_M7_SUBTYP_FLOAT64,
+                                                   0, u3.ui);
+                               }
+                               break;
+#else
+                       case 'f':
+                               lwsl_err("%s: no FP support\n", __func__);
+                               goto fail;
+#endif
+                       }
+                       ctx->state = CBPS_IDLE;
+                       break;
+
+               case CBPS_STRING_BODY:
+                       s = lws_ptr_diff_size_t(ctx->end, ctx->buf);
+                       if (s > (size_t)(ctx->ongoing_len - ctx->ongoing_done))
+                               s = (size_t)(ctx->ongoing_len - ctx->ongoing_done);
+                       memcpy(ctx->buf, ctx->ongoing_src + ctx->ongoing_done, s);
+                       ctx->buf += s;
+                       ctx->ongoing_done += s;
+                       if (ctx->ongoing_len == ctx->ongoing_done) {
+                               /* vaa for ptr */
+                               ctx->vaa[ctx->vaa_pos++] = NATTYPE_PTR;
+                               ctx->state = CBPS_IDLE;
+                       }
+                       continue;
+
+               case CBPS_NUM_LIT:
+                       if (c >= '0' && c <= '9') {
+                               ctx->item.u.u64 = (ctx->item.u.u64 * 10) +
+                                                               (uint64_t)(c - '0');
+                               break;
+                       }
+
+                       if (ctx->item.opcode == LWS_CBOR_MAJTYP_INT_NEG)
+                               ctx->item.u.i64--;
+
+                       if (c == '(') { /* tag qualifier */
+tag_body:
+                               n = format_scan(&fmt[ctx->fmt_pos]);
+                               if (n == -2)
+                                       goto fail;
+                               /*
+                                * inteterminite length not possible for tag,
+                                * take it to mean that the closure is in a
+                                * later format string
+                                */
+
+                               lws_lec_int(ctx, LWS_CBOR_MAJTYP_TAG, 0,
+                                                       ctx->item.u.u64);
+
+stack_push:
+                               if (ctx->sp >= sizeof(ctx->stack))
+                                       return LWS_LECPCTX_RET_FAIL;
+                               ctx->stack[ctx->sp] = (uint8_t)c;
+                               ctx->indet[ctx->sp++] = (uint8_t)(n == -1);
+                               // lwsl_notice("%s: pushed %c\n", __func__, c);
+                               ctx->state = CBPS_IDLE;
+                               break;
+                       }
+
+                       lws_lec_int(ctx, ctx->item.opcode, 0, ctx->item.u.u64);
+
+                       ctx->state = CBPS_IDLE;
+                       /* deal with the terminating char fresh */
+                       continue;
+
+               case CBPS_STRING_LIT:
+                       if (!ctx->escflag && c == '\\') {
+                               ctx->escflag = 1;
+                               break;
+                       }
+                       if (!ctx->escflag && c == '\'') {
+                               ctx->state = CBPS_IDLE;
+                               break;
+                       }
+
+                       *ctx->buf++ = (uint8_t)c;
+                       ctx->escflag = 0;
+
+                       break;
+
+               case CBPS_CONTYPE:
+                       if (c != 't' && c != 'b')
+                               return LWS_LECPCTX_RET_FAIL;
+
+                       lws_lec_int(ctx, c == 't' ? LWS_CBOR_MAJTYP_TSTR :
+                                                   LWS_CBOR_MAJTYP_BSTR, 1, 0);
+                       c = '<';
+                       n = 0;
+                       goto stack_push;
+               }
+
+               ctx->fmt_pos++;
+       }
+
+       ctx->used = lws_ptr_diff_size_t(ctx->buf, ctx->start);
+       // lwsl_notice("%s: ctx->used %d\n", __func__, (int)ctx->used);
+
+       if (ctx->buf == ctx->end || ctx->scratch_len)
+               return LWS_LECPCTX_RET_AGAIN;
+
+       ctx->fmt_pos = 0;
+       ctx->vaa_pos = 0;
+
+       return LWS_LECPCTX_RET_FINISHED;
+
+fail:
+       lwsl_notice("%s: failed\n", __func__);
+
+       ctx->fmt_pos = 0;
+
+       return LWS_LECPCTX_RET_FAIL;
+}
index 2190413..cbce4ee 100644 (file)
@@ -1,26 +1,28 @@
 /*
- * Lightweight Embedded JSON Parser
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2013-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <libwebsockets.h>
-#include "core/private.h"
+#include "private-lib-core.h"
 #include <string.h>
 #include <stdio.h>
 
@@ -74,6 +76,7 @@ lejp_construct(struct lejp_ctx *ctx,
        ctx->st[0].b = 0;
        ctx->sp = 0;
        ctx->ipos = 0;
+       ctx->outer_array = 0;
        ctx->path_match = 0;
        ctx->path_stride = 0;
        ctx->path[0] = '\0';
@@ -104,7 +107,8 @@ void
 lejp_destruct(struct lejp_ctx *ctx)
 {
        /* no allocations... just let callback know what it happening */
-       ctx->pst[0].callback(ctx, LEJPCB_DESTRUCTED);
+       if (ctx && ctx->pst[0].callback)
+               ctx->pst[0].callback(ctx, LEJPCB_DESTRUCTED);
 }
 
 /**
@@ -143,7 +147,8 @@ void
 lejp_check_path_match(struct lejp_ctx *ctx)
 {
        const char *p, *q;
-       int n, s = sizeof(char *);
+       int n;
+       size_t s = sizeof(char *);
 
        if (ctx->path_stride)
                s = ctx->path_stride;
@@ -154,7 +159,7 @@ lejp_check_path_match(struct lejp_ctx *ctx)
                ctx->wildcount = 0;
                p = ctx->path;
 
-               q = *((char **)(((char *)ctx->pst[ctx->pst_sp].paths) + (n * s)));
+               q = *((char **)(((char *)ctx->pst[ctx->pst_sp].paths) + ((unsigned int)n * s)));
 
                while (*p && *q) {
                        if (*q != '*') {
@@ -164,7 +169,7 @@ lejp_check_path_match(struct lejp_ctx *ctx)
                                q++;
                                continue;
                        }
-                       ctx->wild[ctx->wildcount++] = lws_ptr_diff(p, ctx->path);
+                       ctx->wild[ctx->wildcount++] = (uint16_t)lws_ptr_diff_size_t(p, ctx->path);
                        q++;
                        /*
                         * if * has something after it, match to .
@@ -180,7 +185,7 @@ lejp_check_path_match(struct lejp_ctx *ctx)
                if (*p || *q)
                        continue;
 
-               ctx->path_match = n + 1;
+               ctx->path_match = (uint8_t)(n + 1);
                ctx->path_match_len = ctx->pst[ctx->pst_sp].ppos;
                return;
        }
@@ -225,26 +230,28 @@ lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)
  * unused.
  */
 
+static const char esc_char[] = "\"\\/bfnrt";
+static const char esc_tran[] = "\"\\/\b\f\n\r\t";
+static const char tokens[] = "rue alse ull ";
+
 int
 lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
 {
-       unsigned char c, n, s, ret = LEJP_REJECT_UNKNOWN;
-       static const char esc_char[] = "\"\\/bfnrt";
-       static const char esc_tran[] = "\"\\/\b\f\n\r\t";
-       static const char tokens[] = "rue alse ull ";
+       unsigned char c, n, s;
+       int ret = LEJP_REJECT_UNKNOWN;
 
        if (!ctx->sp && !ctx->pst[ctx->pst_sp].ppos)
                ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_START);
 
        while (len--) {
                c = *json++;
-               s = ctx->st[ctx->sp].s;
+               s = (unsigned char)ctx->st[ctx->sp].s;
 
                /* skip whitespace unless we should care */
                if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '#') {
                        if (c == '\n') {
                                ctx->line++;
-                               ctx->st[ctx->sp].s &= ~LEJP_FLAG_WS_COMMENTLINE;
+                               ctx->st[ctx->sp].s &= (char)~LEJP_FLAG_WS_COMMENTLINE;
                        }
                        if (!(s & LEJP_FLAG_WS_KEEP)) {
                                if (c == '#')
@@ -259,18 +266,37 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
 
                switch (s) {
                case LEJP_IDLE:
+                       if (!ctx->sp && c == '[') {
+                               /* push */
+                               ctx->outer_array = 1;
+                               ctx->st[ctx->sp].s = LEJP_MP_ARRAY_END;
+                               c = LEJP_MP_VALUE;
+                               ctx->path[ctx->pst[ctx->pst_sp].ppos++] = '[';
+                               ctx->path[ctx->pst[ctx->pst_sp].ppos++] = ']';
+                               ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
+                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_START))
+                                       goto reject_callback;
+                               ctx->i[ctx->ipos++] = 0;
+                               if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
+                                       ret = LEJP_REJECT_MP_DELIM_ISTACK;
+                                       goto reject;
+                               }
+                               goto add_stack_level;
+                       }
                        if (c != '{') {
                                ret = LEJP_REJECT_IDLE_NO_BRACE;
                                goto reject;
                        }
-                       if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_OBJECT_START)) {
-                               ret = LEJP_REJECT_CALLBACK;
-                               goto reject;
-                       }
+                       if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                          LEJPCB_OBJECT_START))
+                               goto reject_callback;
                        ctx->st[ctx->sp].s = LEJP_MEMBERS;
                        break;
                case LEJP_MEMBERS:
                        if (c == '}') {
+                               if (ctx->sp >= 1)
+                                       goto pop_level;
+
                                ctx->st[ctx->sp].s = LEJP_IDLE;
                                ret = LEJP_REJECT_MEMBERS_NO_CLOSE;
                                goto reject;
@@ -296,10 +322,8 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                if (ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
                                        ctx->buf[ctx->npos] = '\0';
                                        if (ctx->pst[ctx->pst_sp].callback(ctx,
-                                                     LEJPCB_VAL_STR_END) < 0) {
-                                               ret = LEJP_REJECT_CALLBACK;
-                                               goto reject;
-                                       }
+                                                     LEJPCB_VAL_STR_END) < 0)
+                                               goto reject_callback;
                                }
                                /* pop */
                                ctx->sp--;
@@ -325,7 +349,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                if (c != esc_char[n])
                                        continue;
                                /* found it */
-                               c = esc_tran[n];
+                               c = (unsigned char)esc_tran[n];
                                ctx->st[ctx->sp].s = LEJP_MP_STRING;
                                goto emit_string_char;
                        }
@@ -337,15 +361,15 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                case LEJP_MP_STRING_ESC_U2:
                case LEJP_MP_STRING_ESC_U3:
                case LEJP_MP_STRING_ESC_U4:
-                       ctx->uni <<= 4;
+                       ctx->uni = (uint16_t)(ctx->uni << 4);
                        if (c >= '0' && c <= '9')
-                               ctx->uni |= c - '0';
+                               ctx->uni |= (uint16_t)(c - '0');
                        else
                                if (c >= 'a' && c <= 'f')
-                                       ctx->uni = c - 'a' + 10;
+                                       ctx->uni |= (uint16_t)(c - 'a' + 10);
                                else
                                        if (c >= 'A' && c <= 'F')
-                                               ctx->uni = c - 'A' + 10;
+                                               ctx->uni |= (uint16_t)(c - 'A' + 10);
                                        else {
                                                ret = LEJP_REJECT_ILLEGAL_HEX;
                                                goto reject;
@@ -359,7 +383,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                 * 0x08-0xff (0x0800 - 0xffff)
                                 * emit 3-byte UTF-8
                                 */
-                               c = 0xe0 | ((ctx->uni >> 4) & 0xf);
+                               c = (unsigned char)(0xe0 | ((ctx->uni >> 4) & 0xf));
                                goto emit_string_char;
 
                        case LEJP_MP_STRING_ESC_U3:
@@ -369,7 +393,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                         * middle 3-byte seq
                                         * send ....XXXXXX..
                                         */
-                                       c = 0x80 | ((ctx->uni >> 2) & 0x3f);
+                                       c = (unsigned char)(0x80 | ((ctx->uni >> 2) & 0x3f));
                                        goto emit_string_char;
                                }
                                if (ctx->uni < 0x008)
@@ -378,13 +402,13 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                 * 0x008 - 0x7f (0x0080 - 0x07ff)
                                 * start 2-byte seq
                                 */
-                               c = 0xc0 | (ctx->uni >> 2);
+                               c = (unsigned char)(0xc0 | (ctx->uni >> 2));
                                goto emit_string_char;
 
                        case LEJP_MP_STRING_ESC_U4:
                                if (ctx->uni >= 0x0080)
                                        /* end of 2 or 3-byte seq */
-                                       c = 0x80 | (ctx->uni & 0x3f);
+                                       c = (unsigned char)(0x80 | (ctx->uni & 0x3f));
                                else
                                        /* literal */
                                        c = (unsigned char)ctx->uni;
@@ -405,14 +429,12 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                        ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
 
                        lejp_check_path_match(ctx);
-                       if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_PAIR_NAME)) {
-                               ret = LEJP_REJECT_CALLBACK;
-                               goto reject;
-                       }
+                       if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_PAIR_NAME))
+                               goto reject_callback;
                        break;
 
                case LEJP_MP_VALUE:
-                       if (c >= '0' && c <= '9') {
+                       if (c == '-' || (c >= '0' && c <= '9')) {
                                ctx->npos = 0;
                                ctx->dcount = 0;
                                ctx->f = 0;
@@ -426,10 +448,9 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                c = LEJP_MP_STRING;
                                ctx->npos = 0;
                                ctx->buf[0] = '\0';
-                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_STR_START)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
+                               if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                       LEJPCB_VAL_STR_START))
+                                       goto reject_callback;
                                goto add_stack_level;
 
                        case '{':
@@ -437,10 +458,9 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
                                c = LEJP_MEMBERS;
                                lejp_check_path_match(ctx);
-                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_OBJECT_START)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
+                               if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                       LEJPCB_OBJECT_START))
+                                       goto reject_callback;
                                ctx->path_match = 0;
                                goto add_stack_level;
 
@@ -448,13 +468,14 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                /* push */
                                ctx->st[ctx->sp].s = LEJP_MP_ARRAY_END;
                                c = LEJP_MP_VALUE;
+                               if (ctx->pst[ctx->pst_sp].ppos + 3u >=
+                                                       sizeof(ctx->path))
+                                       goto reject;
                                ctx->path[ctx->pst[ctx->pst_sp].ppos++] = '[';
                                ctx->path[ctx->pst[ctx->pst_sp].ppos++] = ']';
                                ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
-                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_START)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
+                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_START))
+                                       goto reject_callback;
                                ctx->i[ctx->ipos++] = 0;
                                if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
                                        ret = LEJP_REJECT_MP_DELIM_ISTACK;
@@ -475,8 +496,9 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                }
                                /* drop the path [n] bit */
                                if (ctx->sp) {
-                                       ctx->pst[ctx->pst_sp].ppos = ctx->st[ctx->sp - 1].p;
-                                       ctx->ipos = ctx->st[ctx->sp - 1].i;
+                                       ctx->pst[ctx->pst_sp].ppos = (unsigned char)
+                                                       ctx->st[ctx->sp - 1].p;
+                                       ctx->ipos = (unsigned char)ctx->st[ctx->sp - 1].i;
                                }
                                ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
                                if (ctx->path_match &&
@@ -486,6 +508,10 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                         * smaller than the matching point
                                         */
                                        ctx->path_match = 0;
+                               if (ctx->outer_array && !ctx->sp) { /* ended on ] */
+                                       n = LEJPCB_ARRAY_END;
+                                       goto completed;
+                               }
                                goto array_end;
 
                        case 't': /* true */
@@ -555,15 +581,13 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
 
                        ctx->buf[ctx->npos] = '\0';
                        if (ctx->f & LEJP_SEEN_POINT) {
-                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_NUM_FLOAT)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
+                               if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                       LEJPCB_VAL_NUM_FLOAT))
+                                       goto reject_callback;
                        } else {
-                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_NUM_INT)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
+                               if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                       LEJPCB_VAL_NUM_INT))
+                                       goto reject_callback;
                        }
 
                        /* then this is the post-number character, loop */
@@ -591,25 +615,22 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                        case 3:
                                ctx->buf[0] = '1';
                                ctx->buf[1] = '\0';
-                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_TRUE)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
+                               if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                               LEJPCB_VAL_TRUE))
+                                       goto reject_callback;
                                break;
                        case 8:
                                ctx->buf[0] = '0';
                                ctx->buf[1] = '\0';
-                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_FALSE)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
+                               if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                               LEJPCB_VAL_FALSE))
+                                       goto reject_callback;
                                break;
                        case 12:
                                ctx->buf[0] = '\0';
-                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_NULL)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
+                               if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                               LEJPCB_VAL_NULL))
+                                       goto reject_callback;
                                break;
                        }
                        ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
@@ -629,10 +650,10 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                        ctx->path_match = 0;
                                        break;
                                }
-                               ctx->pst[ctx->pst_sp].ppos = ctx->st[ctx->sp - 1].p;
+                               ctx->pst[ctx->pst_sp].ppos = (unsigned char)ctx->st[ctx->sp - 1].p;
                                ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
                                if (ctx->path_match &&
-                                               ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
+                                   ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
                                        /*
                                         * we shrank the path to be
                                         * smaller than the matching point
@@ -648,7 +669,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                break;
                        }
                        if (c == ']') {
-                               if (!ctx->sp) {  /* JSON can't end on ] */
+                               if (!ctx->sp) {
                                        ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
                                        goto reject;
                                }
@@ -658,66 +679,68 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
                                        ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
                                        goto reject;
                                }
+
                                /* drop the path [n] bit */
                                if (ctx->sp) {
-                                       ctx->pst[ctx->pst_sp].ppos = ctx->st[ctx->sp - 1].p;
-                                       ctx->ipos = ctx->st[ctx->sp - 1].i;
+                                       ctx->pst[ctx->pst_sp].ppos = (unsigned char)
+                                                       ctx->st[ctx->sp - 1].p;
+                                       ctx->ipos = (unsigned char)ctx->st[ctx->sp - 1].i;
                                }
                                ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
                                if (ctx->path_match &&
-                                               ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
+                                   ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
                                        /*
                                         * we shrank the path to be
                                         * smaller than the matching point
                                         */
                                        ctx->path_match = 0;
 
+                               if (ctx->outer_array && !ctx->sp) { /* ended on ] */
+                                       n = LEJPCB_ARRAY_END;
+                                       goto completed;
+                               }
+
                                /* do LEJP_MP_ARRAY_END processing */
                                goto redo_character;
                        }
-                       if (c == '}') {
-                               if (!ctx->sp) {
-                                       lejp_check_path_match(ctx);
-                                       if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_OBJECT_END)) {
-                                               ret = LEJP_REJECT_CALLBACK;
-                                               goto reject;
-                                       }
-                                       if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_COMPLETE))
-                                               goto reject;
-                                       else
-                                               /* done, return unused amount */
-                                               return len;
-                               }
-
-                               /* pop */
+                       if (c != '}') {
+                               ret = LEJP_REJECT_MP_C_OR_E_NEITHER;
+                               goto reject;
+                       }
+                       if (!ctx->sp) {
+                               n = LEJPCB_OBJECT_END;
+completed:
+                               lejp_check_path_match(ctx);
+                               if (ctx->pst[ctx->pst_sp].callback(ctx, (char)n) ||
+                                   ctx->pst[ctx->pst_sp].callback(ctx,
+                                                           LEJPCB_COMPLETE))
+                                       goto reject_callback;
 
-                               ctx->sp--;
-                               if (ctx->sp) {
-                                       ctx->pst[ctx->pst_sp].ppos =
-                                                       ctx->st[ctx->sp].p;
-                                       ctx->ipos = ctx->st[ctx->sp].i;
-                               }
-                               ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
-                               if (ctx->path_match &&
-                                   ctx->pst[ctx->pst_sp].ppos <=
-                                                   ctx->path_match_len)
-                                       /*
-                                        * we shrank the path to be
-                                        * smaller than the matching point
-                                        */
-                                       ctx->path_match = 0;
+                               /* done, return unused amount */
+                               return len;
+                       }
 
-                               lejp_check_path_match(ctx);
-                               if (ctx->pst[ctx->pst_sp].callback(ctx,
-                                                       LEJPCB_OBJECT_END)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
-                               break;
+                       /* pop */
+pop_level:
+                       ctx->sp--;
+                       if (ctx->sp) {
+                               ctx->pst[ctx->pst_sp].ppos = (unsigned char)ctx->st[ctx->sp].p;
+                               ctx->ipos = (unsigned char)ctx->st[ctx->sp].i;
                        }
+                       ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
+                       if (ctx->path_match &&
+                           ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
+                               /*
+                                * we shrank the path to be
+                                * smaller than the matching point
+                                */
+                               ctx->path_match = 0;
 
-                       ret = LEJP_REJECT_MP_C_OR_E_NEITHER;
-                       goto reject;
+                       lejp_check_path_match(ctx);
+                       if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                          LEJPCB_OBJECT_END))
+                               goto reject_callback;
+                       break;
 
                case LEJP_MP_ARRAY_END:
 array_end:
@@ -728,7 +751,8 @@ array_end:
                                        ctx->i[ctx->ipos - 1]++;
                                ctx->st[ctx->sp].s = LEJP_MP_VALUE;
                                if (ctx->sp)
-                                       ctx->pst[ctx->pst_sp].ppos = ctx->st[ctx->sp - 1].p;
+                                       ctx->pst[ctx->pst_sp].ppos = (unsigned char)
+                                                       ctx->st[ctx->sp - 1].p;
                                ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
                                break;
                        }
@@ -747,18 +771,17 @@ array_end:
 emit_string_char:
                if (!ctx->sp || ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
                        /* assemble the string value into chunks */
-                       ctx->buf[ctx->npos++] = c;
+                       ctx->buf[ctx->npos++] = (char)c;
                        if (ctx->npos == sizeof(ctx->buf) - 1) {
-                               if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_STR_CHUNK)) {
-                                       ret = LEJP_REJECT_CALLBACK;
-                                       goto reject;
-                               }
+                               if (ctx->pst[ctx->pst_sp].callback(ctx,
+                                                         LEJPCB_VAL_STR_CHUNK))
+                                       goto reject_callback;
                                ctx->npos = 0;
                        }
                        continue;
                }
                /* name part of name:value pair */
-               ctx->path[ctx->pst[ctx->pst_sp].ppos++] = c;
+               ctx->path[ctx->pst[ctx->pst_sp].ppos++] = (char)c;
                continue;
 
 add_stack_level:
@@ -768,14 +791,14 @@ add_stack_level:
                    ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END)
                        ctx->path[ctx->pst[ctx->pst_sp].ppos++] = '.';
 
-               ctx->st[ctx->sp].p = ctx->pst[ctx->pst_sp].ppos;
-               ctx->st[ctx->sp].i = ctx->ipos;
+               ctx->st[ctx->sp].p = (char)ctx->pst[ctx->pst_sp].ppos;
+               ctx->st[ctx->sp].i = (char)ctx->ipos;
                if (++ctx->sp == LWS_ARRAY_SIZE(ctx->st)) {
                        ret = LEJP_REJECT_STACK_OVERFLOW;
                        goto reject;
                }
                ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
-               ctx->st[ctx->sp].s = c;
+               ctx->st[ctx->sp].s = (char)c;
                ctx->st[ctx->sp].b = 0;
                continue;
 
@@ -784,7 +807,7 @@ append_npos:
                        ret = LEJP_REJECT_NUM_TOO_LONG;
                        goto reject;
                }
-               ctx->buf[ctx->npos++] = c;
+               ctx->buf[ctx->npos++] = (char)c;
                continue;
 
 redo_character:
@@ -794,6 +817,10 @@ redo_character:
 
        return LEJP_CONTINUE;
 
+
+reject_callback:
+       ret = LEJP_REJECT_CALLBACK;
+
 reject:
        ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_FAILED);
        return ret;
@@ -857,3 +884,4 @@ lejp_error_to_string(int e)
 
        return parser_errs[e];
 }
+
index bbd4df9..3c6a215 100644 (file)
@@ -1,27 +1,30 @@
 /*
- * libwebsockets - lws-ring multi-tail abstract ringbuffer api
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
-LWS_VISIBLE LWS_EXTERN struct lws_ring *
+struct lws_ring *
 lws_ring_create(size_t element_len, size_t count,
                void (*destroy_element)(void *))
 {
@@ -46,7 +49,7 @@ lws_ring_create(size_t element_len, size_t count,
        return ring;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_ring_destroy(struct lws_ring *ring)
 {
        if (ring->destroy_element)
@@ -63,7 +66,7 @@ lws_ring_destroy(struct lws_ring *ring)
        lws_free(ring);
 }
 
-LWS_VISIBLE LWS_EXTERN size_t
+size_t
 lws_ring_get_count_free_elements(struct lws_ring *ring)
 {
        int f;
@@ -78,22 +81,22 @@ lws_ring_get_count_free_elements(struct lws_ring *ring)
         * |*****ht*********|
         */
        if (ring->head == ring->oldest_tail)
-               f = ring->buflen - ring->element_len;
+               f = (int)(ring->buflen - ring->element_len);
        else
                if (ring->head < ring->oldest_tail)
-                       f = (ring->oldest_tail - ring->head) -
-                           ring->element_len;
+                       f = (int)((ring->oldest_tail - ring->head) -
+                           ring->element_len);
                else
-                       f = (ring->buflen - ring->head) + ring->oldest_tail -
-                           ring->element_len;
+                       f = (int)((ring->buflen - ring->head) + ring->oldest_tail -
+                           ring->element_len);
 
        if (f < 2)
                return 0;
 
-       return f / ring->element_len;
+       return (unsigned int)f / ring->element_len;
 }
 
-LWS_VISIBLE LWS_EXTERN size_t
+size_t
 lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail)
 {      int f;
 
@@ -112,14 +115,14 @@ lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail)
                f = 0;
        else
                if (ring->head > *tail)
-                       f = (ring->head - *tail);
+                       f = (int)(ring->head - *tail);
                else
-                       f = (ring->buflen - *tail) + ring->head;
+                       f = (int)((ring->buflen - *tail) + ring->head);
 
-       return f / ring->element_len;
+       return (unsigned int)f / ring->element_len;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,
                                  size_t *bytes)
 {
@@ -131,7 +134,7 @@ lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,
        if (!n)
                return 1;
 
-       if (ring->head + n > ring->buflen) {
+       if (ring->head + (unsigned int)n > ring->buflen) {
                *start = (void *)(((uint8_t *)ring->buf) + ring->head);
                *bytes = ring->buflen - ring->head;
 
@@ -139,22 +142,23 @@ lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,
        }
 
        *start = (void *)(((uint8_t *)ring->buf) + ring->head);
-       *bytes = n;
+       *bytes = (unsigned int)n;
 
        return 0;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_ring_bump_head(struct lws_ring *ring, size_t bytes)
 {
        ring->head = (ring->head + (uint32_t)bytes) % ring->buflen;
 }
 
-LWS_VISIBLE LWS_EXTERN size_t
+size_t
 lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count)
 {
        const uint8_t *osrc = src;
-       int m, n;
+       size_t m;
+       int n;
 
        /* n is how many bytes the whole fifo can take */
        n = (int)(lws_ring_get_count_free_elements(ring) * ring->element_len);
@@ -167,7 +171,7 @@ lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count)
         * n is legal to insert, but as an optimization we can cut the
         * insert into one or two memcpys, depending on if it wraps
         */
-       if (ring->head + n > ring->buflen) {
+       if (ring->head + (unsigned int)n > ring->buflen) {
 
                /*
                 * He does wrap.  The first memcpy should take us up to
@@ -182,16 +186,16 @@ lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count)
                /* adapt the second memcpy for what we already did */
 
                src = ((uint8_t *)src) + m;
-               n -= m;
+               n = n - (int)m;
        }
 
-       memcpy(((uint8_t *)ring->buf) + ring->head, src, n);
-       ring->head = (ring->head + n) % ring->buflen;
+       memcpy(((uint8_t *)ring->buf) + ring->head, src, (size_t)n);
+       ring->head = (ring->head + (unsigned int)n) % ring->buflen;
 
-       return (((uint8_t *)src + n) - osrc) / ring->element_len;
+       return (unsigned long)(((uint8_t *)src + (unsigned int)n) - osrc) / ring->element_len;
 }
 
-LWS_VISIBLE LWS_EXTERN size_t
+size_t
 lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,
                 size_t max_count)
 {
@@ -214,21 +218,21 @@ lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,
                n = (int)(max_count * ring->element_len);
 
        if (!dest) {
-               *tail = ((*tail) + n) % ring->buflen;
+               *tail = ((*tail) + (unsigned int)n) % ring->buflen;
                if (!orig_tail) /* single tail */
                        lws_ring_update_oldest_tail(ring, *tail);
 
-               return n / ring->element_len;
+               return (unsigned int)n / ring->element_len;
        }
-       if (*tail + n > ring->buflen) {
+       if (*tail + (unsigned int)n > ring->buflen) {
 
                /*
                 * He does wrap.  The first memcpy should take us up to
                 * the end of the buffer
                 */
 
-               m = ring->buflen - *tail;
-               memcpy(dest, ((uint8_t *)ring->buf) + *tail, m);
+               m = (int32_t)(ring->buflen - *tail);
+               memcpy(dest, ((uint8_t *)ring->buf) + *tail, (size_t)m);
                /* we know it will wrap exactly back to zero */
                *tail = 0;
 
@@ -238,16 +242,16 @@ lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,
                n -= m;
        }
 
-       memcpy(dest, ((uint8_t *)ring->buf) + *tail, n);
+       memcpy(dest, ((uint8_t *)ring->buf) + *tail, (size_t)n);
 
-       *tail = ((*tail) + n) % ring->buflen;
+       *tail = ((*tail) + (unsigned int)n) % ring->buflen;
        if (!orig_tail) /* single tail */
                lws_ring_update_oldest_tail(ring, *tail);
 
-       return (((uint8_t *)dest + n) - odest) / ring->element_len;
+       return (unsigned int)(((uint8_t *)dest + n) - odest) / (unsigned int)ring->element_len;
 }
 
-LWS_VISIBLE LWS_EXTERN const void *
+const void *
 lws_ring_get_element(struct lws_ring *ring, uint32_t *tail)
 {
        if (!tail)
@@ -259,7 +263,7 @@ lws_ring_get_element(struct lws_ring *ring, uint32_t *tail)
        return ((uint8_t *)ring->buf) + *tail;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail)
 {
        if (!ring->destroy_element) {
@@ -274,21 +278,21 @@ lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail)
        }
 }
 
-LWS_VISIBLE LWS_EXTERN uint32_t
+uint32_t
 lws_ring_get_oldest_tail(struct lws_ring *ring)
 {
        return ring->oldest_tail;
 }
 
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_ring_dump(struct lws_ring *ring, uint32_t *tail)
 {
        if (tail == NULL)
                tail = &ring->oldest_tail;
        lwsl_notice("ring %p: buflen %u, elem_len %u, head %u, oldest_tail %u\n"
                    "     free_elems: %u; for tail %u, waiting elements: %u\n",
-                   ring, ring->buflen, ring->element_len, ring->head,
-                   ring->oldest_tail,
-                   (int)lws_ring_get_count_free_elements(ring), *tail,
+                   ring, (int)ring->buflen, (int)ring->element_len,
+                   (int)ring->head, (int)ring->oldest_tail,
+                   (int)lws_ring_get_count_free_elements(ring), (int)*tail,
                    (int)lws_ring_get_count_waiting_elements(ring, tail));
 }
index af637cc..efb81c8 100644 (file)
@@ -1,26 +1,29 @@
 /*
- * libwebsockets - lws_struct JSON serialization helpers
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #include <libwebsockets.h>
-#include <core/private.h>
+#include <private-lib-core.h>
 
 #include <assert.h>
 
@@ -29,18 +32,62 @@ lws_struct_schema_only_lejp_cb(struct lejp_ctx *ctx, char reason)
 {
        lws_struct_args_t *a = (lws_struct_args_t *)ctx->user;
        const lws_struct_map_t *map = a->map_st[ctx->pst_sp];
-       int n = a->map_entries_st[ctx->pst_sp];
+       size_t n = a->map_entries_st[ctx->pst_sp], imp = 0;
        lejp_callback cb = map->lejp_cb;
 
+       if (reason == LEJPCB_PAIR_NAME && strcmp(ctx->path, "schema")) {
+               /*
+                * If not "schema", the schema is implicit rather than
+                * explicitly given, ie, he just goes ahead and starts using
+                * member names that imply a particular type.  For example, he
+                * may have an implicit type normally, and a different one for
+                * exceptions that just starts using "error-message" or whatever
+                * and we can understand that's the exception type now.
+                *
+                * Let's look into each of the maps in the top level array
+                * and match the first one that mentions the name he gave here,
+                * and bind to the associated type / create a toplevel object
+                * of that type.
+                */
+
+               while (n--) {
+                       int m, child_members = (int)map->child_map_size;
+
+                       for (m = 0; m < child_members; m++) {
+                               const lws_struct_map_t *child = &map->child_map[m];
+                               if (!strcmp(ctx->path, child->colname)) {
+                                       /*
+                                        * We matched on him... map is pointing
+                                        * to the right toplevel type, let's
+                                        * just pick up from there as if we
+                                        * matched the explicit schema name...
+                                        */
+                                       ctx->path_match = 1;
+                                       imp = 1;
+                                       goto matched;
+                               }
+                       }
+                       map++;
+               }
+               lwsl_notice("%s: can't match implicit schema %s\n",
+                           __func__, ctx->path);
+
+               return -1;
+       }
+
        if (reason != LEJPCB_VAL_STR_END || ctx->path_match != 1)
                return 0;
 
+       /* If "schema", then look for a matching name in the map array */
+
        while (n--) {
                if (strcmp(ctx->buf, map->colname)) {
                        map++;
                        continue;
                }
 
+matched:
+
                a->dest = lwsac_use_zero(&a->ac, map->aux, a->ac_block_size);
                if (!a->dest) {
                        lwsl_err("%s: OOT\n", __func__);
@@ -48,6 +95,8 @@ lws_struct_schema_only_lejp_cb(struct lejp_ctx *ctx, char reason)
                        return 1;
                }
                a->dest_len = map->aux;
+               if (!ctx->pst_sp)
+                       a->top_schema_index = (int)(map - a->map_st[ctx->pst_sp]);
 
                if (!cb)
                        cb = lws_struct_default_lejp_cb;
@@ -57,6 +106,12 @@ lws_struct_schema_only_lejp_cb(struct lejp_ctx *ctx, char reason)
                a->map_st[ctx->pst_sp] = map->child_map;
                a->map_entries_st[ctx->pst_sp] = map->child_map_size;
 
+               // lwsl_notice("%s: child map ofs_clist %d\n", __func__,
+               //              (int)a->map_st[ctx->pst_sp]->ofs_clist);
+
+               if (imp)
+                       return cb(ctx, reason);
+
                return 0;
        }
 
@@ -89,8 +144,8 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
        lws_struct_args_t *args = (lws_struct_args_t *)ctx->user;
        const lws_struct_map_t *map, *pmap = NULL;
        uint8_t *ch;
+       size_t n;
        char *u;
-       int n;
 
        if (reason == LEJPCB_ARRAY_END) {
                lejp_parser_pop(ctx);
@@ -99,8 +154,9 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
        }
 
        if (reason == LEJPCB_ARRAY_START) {
+               if (!ctx->path_match)
+                       lwsl_err("%s: ARRAY_START with ctx->path_match 0\n", __func__);
                map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
-               n = args->map_entries_st[ctx->pst_sp];
 
                if (map->type == LSMT_LIST)
                        lws_struct_lejp_push(ctx, args, map, NULL);
@@ -111,30 +167,47 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
        if (ctx->pst_sp)
                pmap = &args->map_st[ctx->pst_sp - 1]
                         [ctx->pst[ctx->pst_sp - 1].path_match - 1];
-       map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
-       n = args->map_entries_st[ctx->pst_sp];
 
        if (reason == LEJPCB_OBJECT_START) {
 
-               if (map->type != LSMT_CHILD_PTR) {
+               if (!ctx->path_match) {
                        ctx->pst[ctx->pst_sp].user = NULL;
 
                        return 0;
                }
-               pmap = map;
 
-               lws_struct_lejp_push(ctx, args, map, NULL);
                map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
                n = args->map_entries_st[ctx->pst_sp];
+
+               if (map->type != LSMT_CHILD_PTR && map->type != LSMT_LIST) {
+                       ctx->pst[ctx->pst_sp].user = NULL;
+
+                       return 0;
+               }
+               pmap = map;
+
+               lws_struct_lejp_push(ctx, args, map, NULL);
        }
 
-       if (reason == LEJPCB_OBJECT_END && pmap && pmap->type == LSMT_CHILD_PTR)
-               lejp_parser_pop(ctx);
+       if (reason == LEJPCB_OBJECT_END && pmap) {
+               if (pmap->type == LSMT_CHILD_PTR)
+                       lejp_parser_pop(ctx);
+
+               if (ctx->pst_sp)
+                       pmap = &args->map_st[ctx->pst_sp - 1]
+                                [ctx->pst[ctx->pst_sp - 1].path_match - 1];
+       }
+
+       if (!ctx->path_match)
+               return 0;
+
+       map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
+       n = args->map_entries_st[ctx->pst_sp];
 
        if (map->type == LSMT_SCHEMA) {
 
                while (n--) {
-                       if (strcmp(map->colname, ctx->buf)) {
+                       if (strncmp(map->colname, ctx->buf, ctx->npos)) {
                                map++;
                                continue;
                        }
@@ -153,7 +226,9 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
 
                        return 0;
                }
-               lwsl_notice("%s: unknown schema\n", __func__);
+               lwsl_notice("%s: unknown schema %.*s, tried %d\n", __func__,
+                               ctx->npos, ctx->buf,
+                               (int)args->map_entries_st[ctx->pst_sp]);
 
                goto cleanup;
        }
@@ -170,6 +245,9 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
                map = &args->map_st[ctx->pst_sp - 1][ctx->path_match - 1];
                n = args->map_entries_st[ctx->pst_sp - 1];
 
+               if (!ctx->pst_sp)
+                       return 0;
+
                if (pmap->type != LSMT_LIST && pmap->type != LSMT_CHILD_PTR)
                        return 1;
 
@@ -189,14 +267,23 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
 
                        return 1;
                }
-               lwsl_notice("%s: created child object size %d\n", __func__,
-                               (int)pmap->aux);
+               lwsl_info("%s: created '%s' object size %d\n", __func__,
+                               pmap->colname, (int)pmap->aux);
 
-               if (pmap->type == LSMT_LIST) {
-                       list = (struct lws_dll2 *)((char *)ctx->pst[ctx->pst_sp].user +
-                               map->ofs_clist);
+               switch (pmap->type) {
+               case LSMT_LIST:
+                       list = (struct lws_dll2 *)
+                                ((char *)ctx->pst[ctx->pst_sp].user +
+                                pmap->ofs_clist);
 
                        lws_dll2_add_tail(list, owner);
+                       break;
+               case LSMT_CHILD_PTR:
+                       *((void **)owner) = ctx->pst[ctx->pst_sp].user;
+                       break;
+               default:
+                       assert(0);
+                       break;
                }
        }
 
@@ -260,7 +347,7 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
                        if (map->aux == sizeof(signed char)) {
                                signed char *pc;
                                pc = (signed char *)(u + map->ofs);
-                               *pc = atoi(ctx->buf);
+                               *pc = (signed char)atoi(ctx->buf);
                                break;
                        }
                        if (map->aux == sizeof(int)) {
@@ -284,23 +371,23 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
                        if (map->aux == sizeof(unsigned char)) {
                                unsigned char *pc;
                                pc = (unsigned char *)(u + map->ofs);
-                               *pc = atoi(ctx->buf);
+                               *pc = (unsigned char)(unsigned int)atoi(ctx->buf);
                                break;
                        }
                        if (map->aux == sizeof(unsigned int)) {
                                unsigned int *pi;
                                pi = (unsigned int *)(u + map->ofs);
-                               *pi = atoi(ctx->buf);
+                               *pi = (unsigned int)atoi(ctx->buf);
                                break;
                        }
                        if (map->aux == sizeof(unsigned long)) {
                                unsigned long *pl;
                                pl = (unsigned long *)(u + map->ofs);
-                               *pl = atol(ctx->buf);
+                               *pl = (unsigned long)atol(ctx->buf);
                        } else {
                                unsigned long long *pll;
                                pll = (unsigned long long *)(u + map->ofs);
-                               *pll = atoll(ctx->buf);
+                               *pll = (unsigned long long)atoll(ctx->buf);
                        }
                        break;
 
@@ -319,7 +406,7 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
                        } else {
                                uint64_t *p64;
                                p64 = (uint64_t *)(u + map->ofs);
-                               *p64 = li;
+                               *p64 = (uint64_t)li;
                        }
                        break;
 
@@ -344,7 +431,7 @@ chunk_copy:
                                lejp_collation_t *coll = (lejp_collation_t *)p;
 
                                if (lim) {
-                                       b = coll->len;
+                                       b = (unsigned int)coll->len;
                                        if (b > lim)
                                                b = lim;
                                        memcpy(s, coll->buf, b);
@@ -363,6 +450,7 @@ chunk_copy:
                                if (b > lim)
                                        b = lim;
                                memcpy(s, ctx->buf, b);
+                               s[b] = '\0';
                        }
                        break;
                default:
@@ -390,6 +478,10 @@ static const char * schema[] = { "schema" };
 int
 lws_struct_json_init_parse(struct lejp_ctx *ctx, lejp_callback cb, void *user)
 {
+       /*
+        * By default we are looking to match on a toplevel member called
+        * "schema", against an LSM_SCHEMA
+        */
        if (!cb)
                cb = lws_struct_schema_only_lejp_cb;
        lejp_construct(ctx, cb, user, schema, 1);
@@ -402,7 +494,7 @@ lws_struct_json_init_parse(struct lejp_ctx *ctx, lejp_callback cb, void *user)
 lws_struct_serialize_t *
 lws_struct_json_serialize_create(const lws_struct_map_t *map,
                                 size_t map_entries, int flags,
-                                void *ptoplevel)
+                                const void *ptoplevel)
 {
        lws_struct_serialize_t *js = lws_zalloc(sizeof(*js), __func__);
        lws_struct_serialize_st_t *j;
@@ -453,14 +545,14 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
 {
        lws_struct_serialize_st_t *j;
        const lws_struct_map_t *map;
-       size_t budget = 0, olen = len;
+       size_t budget = 0, olen = len, m;
        struct lws_dll2_owner *o;
        unsigned long long uli;
        const char *q;
        const void *p;
        char dbuf[72];
        long long li;
-       int n;
+       int n, used;
 
        *written = 0;
        *buf = '\0';
@@ -473,6 +565,10 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                /* early check if the entry should be elided */
 
                switch (map->type) {
+               case LSMT_STRING_CHAR_ARRAY:
+                       if (!q)
+                               goto up;
+                       break;
                case LSMT_STRING_PTR:
                case LSMT_CHILD_PTR:
                        q = (char *)*(char **)q;
@@ -487,6 +583,9 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                                goto up;
                        break;
 
+               case LSMT_BLOB_PTR:
+                       goto up;
+
                default:
                        break;
                }
@@ -502,7 +601,7 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                        n = lws_snprintf((char *)buf, len, "\"%s\":",
                                            map->colname);
                        buf += n;
-                       len -= n;
+                       len = len - (unsigned int)n;
                        if (js->flags & LSSERJ_FLAG_PRETTY) {
                                *buf++ = ' ';
                                len--;
@@ -527,10 +626,10 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                        q = dbuf;
 
                        if (map->type == LSMT_BOOLEAN) {
-                               budget = lws_snprintf(dbuf, sizeof(dbuf),
+                               budget = (unsigned int)lws_snprintf(dbuf, sizeof(dbuf),
                                                "%s", uli ? "true" : "false");
                        } else
-                               budget = lws_snprintf(dbuf, sizeof(dbuf),
+                               budget = (unsigned int)lws_snprintf(dbuf, sizeof(dbuf),
                                                      "%llu", uli);
                        break;
 
@@ -548,24 +647,17 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                                }
                        }
                        q = dbuf;
-                       budget = lws_snprintf(dbuf, sizeof(dbuf), "%lld", li);
+                       budget = (unsigned int)lws_snprintf(dbuf, sizeof(dbuf), "%lld", li);
                        break;
 
                case LSMT_STRING_CHAR_ARRAY:
-                       budget = strlen(q);
-                       if (!js->offset) {
-                               *buf++ = '\"';
-                               len--;
-                       }
-                       break;
-
                case LSMT_STRING_PTR:
-                       budget = strlen(q);
                        if (!js->offset) {
                                *buf++ = '\"';
                                len--;
                        }
                        break;
+
                case LSMT_LIST:
                        *buf++ = '[';
                        len--;
@@ -585,7 +677,7 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
 
                        n = j->idt;
                        j = &js->st[++js->sp];
-                       j->idt = n + 2;
+                       j->idt = (char)(n + 2);
                        j->map = map->child_map;
                        j->map_entries = map->child_map_size;
                        j->size = map->aux;
@@ -606,11 +698,11 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                        if (js->sp + 1 == LEJP_MAX_PARSING_STACK_DEPTH)
                                return LSJS_RESULT_ERROR;
 
-                       /* add a stack level tto handle parsing child members */
+                       /* add a stack level to handle parsing child members */
 
                        n = j->idt;
                        j = &js->st[++js->sp];
-                       j->idt = n + 2;
+                       j->idt = (char)(n + 2);
                        j->map = map->child_map;
                        j->map_entries = map->child_map_size;
                        j->size = map->aux;
@@ -620,6 +712,7 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                        len--;
                        lws_struct_pretty(js, &buf, &len);
                        j->obj = q;
+
                        continue;
 
                case LSMT_SCHEMA:
@@ -628,13 +721,15 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                        len--;
                        j = &js->st[++js->sp];
                        lws_struct_pretty(js, &buf, &len);
-                       budget = lws_snprintf(dbuf, 15, "\"schema\":");
-                       if (js->flags & LSSERJ_FLAG_PRETTY)
-                               dbuf[budget++] = ' ';
-
-                       budget += lws_snprintf(dbuf + budget,
-                                              sizeof(dbuf) - budget,
-                                             "\"%s\"", map->colname);
+                       if (!(js->flags & LSSERJ_FLAG_OMIT_SCHEMA)) {
+                               budget = (unsigned int)lws_snprintf(dbuf, 15, "\"schema\":");
+                               if (js->flags & LSSERJ_FLAG_PRETTY)
+                                       dbuf[budget++] = ' ';
+
+                               budget += (unsigned int)lws_snprintf(dbuf + budget,
+                                                      sizeof(dbuf) - budget,
+                                                      "\"%s\"", map->colname);
+                       }
 
 
                        if (js->sp != 1)
@@ -646,28 +741,66 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
                        j->map_entry = 0;
                        j->obj = js->st[js->sp - 1].obj;
                        j->dllpos = NULL;
-                       /* we're actually at the same level */
-                       j->subsequent = 1;
+                       if (!(js->flags & LSSERJ_FLAG_OMIT_SCHEMA))
+                               /* we're actually at the same level */
+                               j->subsequent = 1;
                        j->idt = 1;
                        break;
+               default:
+                       break;
                }
 
-               q += js->offset;
-               budget -= js->remaining;
+               switch (map->type) {
+               case LSMT_STRING_CHAR_ARRAY:
+               case LSMT_STRING_PTR:
+                       /*
+                        * This is a bit tricky... we have to escape the string
+                        * which may 6x its length depending on what the
+                        * contents are.
+                        *
+                        * We offset the unescaped string starting point first
+                        */
 
-               if (budget > len) {
-                       js->remaining = budget - len;
-                       js->offset = len;
-                       budget = len;
-               } else {
-                       js->remaining = 0;
-                       js->offset = 0;
+                       q += js->offset;
+                       budget = strlen(q); /* how much unescaped is left */
+
+                       /*
+                        * This is going to escape as much as it can fit, and
+                        * let us know the amount of input that was consumed
+                        * in "used".
+                        */
+
+                       lws_json_purify((char *)buf, q, (int)len, &used);
+                       m = strlen((const char *)buf);
+                       buf += m;
+                       len -= m;
+                       js->remaining = budget - (unsigned int)used;
+                       js->offset = (unsigned int)used;
+                       if (!js->remaining)
+                               js->offset = 0;
+
+                       break;
+               default:
+                       q += js->offset;
+                       budget -= js->remaining;
+
+                       if (budget > len) {
+                               js->remaining = budget - len;
+                               js->offset = len;
+                               budget = len;
+                       } else {
+                               js->remaining = 0;
+                               js->offset = 0;
+                       }
+
+                       memcpy(buf, q, budget);
+                       buf += budget;
+                       *buf = '\0';
+                       len -= budget;
+                       break;
                }
 
-               memcpy(buf, q, budget);
-               buf += budget;
-               *buf = '\0';
-               len -= budget;
+
 
                switch (map->type) {
                case LSMT_STRING_CHAR_ARRAY:
@@ -727,7 +860,7 @@ up:
                if (j->dllpos) {
                        /*
                         * there was another item in the array to do... let's
-                        * move on to that nd do it
+                        * move on to that and do it
                         */
                        *buf++ = ',';
                        len--;
index e89343e..fbe8cf4 100644 (file)
@@ -1,26 +1,29 @@
 /*
- * libwebsockets - lws_struct JSON serialization helpers
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #include <libwebsockets.h>
-#include <core/private.h>
+#include <private-lib-core.h>
 
 #include <sqlite3.h>
 
@@ -32,10 +35,10 @@ static int
 lws_struct_sq3_deser_cb(void *priv, int cols, char **cv, char **cn)
 {
        lws_struct_args_t *a = (lws_struct_args_t *)priv;
-       const lws_struct_map_t *map = a->map_st[0];
-       int n, mems = a->map_entries_st[0];
-       lws_dll2_owner_t *o = (lws_dll2_owner_t *)a->cb_arg;
        char *u = lwsac_use_zero(&a->ac, a->dest_len, a->ac_block_size);
+       lws_dll2_owner_t *o = (lws_dll2_owner_t *)a->cb_arg;
+       const lws_struct_map_t *map = a->map_st[0];
+       int n, mems = (int)(ssize_t)a->map_entries_st[0];
        long long li;
        size_t lim;
        char **pp;
@@ -59,19 +62,25 @@ lws_struct_sq3_deser_cb(void *priv, int cols, char **cv, char **cn)
                                if (map->aux == sizeof(signed char)) {
                                        signed char *pc;
                                        pc = (signed char *)(u + map->ofs);
-                                       *pc = atoi(cv[n]);
+                                       *pc = (signed char)atoi(cv[n]);
+                                       break;
+                               }
+                               if (map->aux == sizeof(short)) {
+                                       short *ps;
+                                       ps = (short *)(u + map->ofs);
+                                       *ps = (short)atoi(cv[n]);
                                        break;
                                }
                                if (map->aux == sizeof(int)) {
                                        int *pi;
                                        pi = (int *)(u + map->ofs);
-                                       *pi = atoi(cv[n]);
+                                       *pi = (int)atoll(cv[n]); /* 32-bit OS */
                                        break;
                                }
                                if (map->aux == sizeof(long)) {
                                        long *pl;
                                        pl = (long *)(u + map->ofs);
-                                       *pl = atol(cv[n]);
+                                       *pl = (long)atoll(cv[n]); /* 32-bit OS */
                                        break;
                                }
                                {
@@ -85,25 +94,31 @@ lws_struct_sq3_deser_cb(void *priv, int cols, char **cv, char **cn)
                                if (map->aux == sizeof(unsigned char)) {
                                        unsigned char *pc;
                                        pc = (unsigned char *)(u + map->ofs);
-                                       *pc = atoi(cv[n]);
+                                       *pc = (unsigned char)(unsigned int)atoi(cv[n]);
+                                       break;
+                               }
+                               if (map->aux == sizeof(unsigned short)) {
+                                       unsigned short *ps;
+                                       ps = (unsigned short *)(u + map->ofs);
+                                       *ps = (unsigned short)atoi(cv[n]);
                                        break;
                                }
                                if (map->aux == sizeof(unsigned int)) {
                                        unsigned int *pi;
                                        pi = (unsigned int *)(u + map->ofs);
-                                       *pi = atoi(cv[n]);
+                                       *pi = (unsigned int)atoi(cv[n]);
                                        break;
                                }
                                if (map->aux == sizeof(unsigned long)) {
                                        unsigned long *pl;
                                        pl = (unsigned long *)(u + map->ofs);
-                                       *pl = atol(cv[n]);
+                                       *pl = (unsigned long)atol(cv[n]);
                                        break;
                                }
                                {
                                        unsigned long long *pll;
                                        pll = (unsigned long long *)(u + map->ofs);
-                                       *pll = atoll(cv[n]);
+                                       *pll = (unsigned long long)atoll(cv[n]);
                                }
                                break;
 
@@ -125,13 +140,13 @@ lws_struct_sq3_deser_cb(void *priv, int cols, char **cv, char **cn)
                                } else {
                                        uint64_t *p64;
                                        p64 = (uint64_t *)(u + map->ofs);
-                                       *p64 = li;
+                                       *p64 = (uint64_t)li;
                                }
                                break;
 
                        case LSMT_STRING_CHAR_ARRAY:
                                s = (char *)(u + map->ofs);
-                               lim = map->aux - 1;
+                               lim = map->aux;
                                lws_strncpy(s, cv[n], lim);
                                break;
 
@@ -162,14 +177,20 @@ lws_struct_sq3_deser_cb(void *priv, int cols, char **cv, char **cn)
  */
 
 int
-lws_struct_sq3_deserialize(sqlite3 *pdb, const lws_struct_map_t *schema,
-                          lws_dll2_owner_t *o, struct lwsac **ac,
-                          uint64_t start, int limit)
+lws_struct_sq3_deserialize(sqlite3 *pdb, const char *filter, const char *order,
+                          const lws_struct_map_t *schema, lws_dll2_owner_t *o,
+                          struct lwsac **ac, int start, int _limit)
 {
-       char s[150], where[32];
+       int limit = _limit < 0 ? -_limit : _limit;
+       char s[768], results[512], where[250];
        lws_struct_args_t a;
+       int n, m;
+
+       if (!order)
+               order = "_lws_idx";
 
        memset(&a, 0, sizeof(a));
+       a.ac = *ac;
        a.cb_arg = o; /* lws_dll2_owner tracking query result objects */
        a.map_st[0]  = schema->child_map;
        a.map_entries_st[0] = schema->child_map_size;
@@ -178,17 +199,29 @@ lws_struct_sq3_deserialize(sqlite3 *pdb, const lws_struct_map_t *schema,
 
        lws_dll2_owner_clear(o);
 
+       /*
+        * Explicitly list the columns instead of use *, so we can skip blobs
+        */
+
+       m = 0;
+       for (n = 0; n < (int)schema->child_map_size; n++)
+               m += lws_snprintf(&results[m], sizeof(results) - (unsigned int)n - 1,
+                                 "%s%c", schema->child_map[n].colname,
+                                 n + 1 == (int)schema->child_map_size ? ' ' : ',');
+
        where[0] = '\0';
-       if (start)
-               lws_snprintf(where, sizeof(where), " where when < %llu ",
-                               (unsigned long long)start);
+       lws_snprintf(where, sizeof(where), " where _lws_idx >= %llu %s",
+                            (unsigned long long)start, filter ? filter : "");
+
+       lws_snprintf(s, sizeof(s) - 1, "select %s "
+                    "from %s %s order by %s %slimit %d;", results,
+                    schema->colname, where, order,
+                                    _limit < 0 ? "desc " : "", limit);
+
 
-       lws_snprintf(s, sizeof(s) - 1, "select * "
-                    "from %s %s order by created desc limit %d;",
-                    schema->colname, where, limit);
 
        if (sqlite3_exec(pdb, s, lws_struct_sq3_deser_cb, &a, NULL) != SQLITE_OK) {
-               lwsl_err("%s: fail\n", sqlite3_errmsg(pdb));
+               lwsl_err("%s: %s: fail %s\n", __func__, sqlite3_errmsg(pdb), s);
                lwsac_free(&a.ac);
                return -1;
        }
@@ -198,35 +231,265 @@ lws_struct_sq3_deserialize(sqlite3 *pdb, const lws_struct_map_t *schema,
        return 0;
 }
 
+/*
+ * This takes a struct and turns it into an sqlite3 UPDATE, using the given
+ * schema... which has one LSM_SCHEMA_DLL2 entry wrapping the actual schema
+ */
+
+static int
+_lws_struct_sq3_ser_one(sqlite3 *pdb, const lws_struct_map_t *schema,
+                       uint32_t idx, void *st)
+{
+       const lws_struct_map_t *map = schema->child_map;
+       int n, m, pk = 0, nentries = (int)(ssize_t)schema->child_map_size, nef = 0, did;
+       size_t sql_est = 46 + strlen(schema->colname) + 1;
+               /* "insert into  (_lws_idx, ) values (00000001,);" ...
+                * plus the table name */
+       uint8_t *stb = (uint8_t *)st;
+       const char *p;
+       char *sql;
+
+       /*
+        * Figure out effective number of columns, exluding BLOB.
+        *
+        * The first UNSIGNED is a hidden index.  Blobs are not handled by
+        * lws_struct except to create the column in the schema.
+        */
+
+       pk = 0;
+       nef = 0;
+       for (n = 0; n < nentries; n++) {
+               if (!pk && map[n].type == LSMT_UNSIGNED) {
+                       pk = 1;
+                       continue;
+               }
+               if (map[n].type == LSMT_BLOB_PTR)
+                       continue;
+
+               nef++;
+       }
+
+       /*
+        * Figure out an estimate for the length of the populated sqlite
+        * command, and then malloc it up
+        */
+
+       for (n = 0; n < nentries; n++) {
+               sql_est += strlen(map[n].colname) + 2;
+               switch (map[n].type) {
+               case LSMT_SIGNED:
+               case LSMT_UNSIGNED:
+               case LSMT_BOOLEAN:
+
+                       switch (map[n].aux) {
+                       case 1:
+                               sql_est += 3 + 2;
+                               break;
+                       case 2:
+                               sql_est += 5 + 2;
+                               break;
+                       case 4:
+                               sql_est += 10 + 2;
+                               break;
+                       case 8:
+                               sql_est += 20 + 2;
+                               break;
+                       }
+
+                       if (map[n].type == LSMT_SIGNED)
+                               sql_est++; /* minus sign */
+
+                       break;
+               case LSMT_STRING_CHAR_ARRAY:
+                       sql_est += (unsigned int)lws_sql_purify_len((const char *)st +
+                                                       map[n].ofs) + 2;
+                       break;
+
+               case LSMT_STRING_PTR:
+                       p = *((const char * const *)&stb[map[n].ofs]);
+                       sql_est += (unsigned int)((p ? lws_sql_purify_len(p) : 0) + 2);
+                       break;
+
+               case LSMT_BLOB_PTR:
+                       /* we don't deal with blobs actually */
+                       sql_est -= strlen(map[n].colname) + 2;
+                       break;
+
+               default:
+                       lwsl_err("%s: unsupported type\n", __func__);
+                       assert(0);
+                       break;
+               }
+       }
+
+       sql = malloc(sql_est);
+       if (!sql)
+               return -1;
+
+       m = lws_snprintf(sql, sql_est, "insert into %s(_lws_idx, ",
+                        schema->colname);
+
+       /*
+        * First explicit integer type is primary key autoincrement, should
+        * not be specified
+        */
+
+       pk = 0;
+       did = 0;
+       for (n = 0; n < nentries; n++) {
+               if (!pk && map[n].type == LSMT_UNSIGNED) {
+                       pk = 1;
+                       continue;
+               }
+               if (map[n].type == LSMT_BLOB_PTR)
+                       continue;
+
+               did++;
+               m += lws_snprintf(sql + m, sql_est - (unsigned int)m,
+                                 did == nef ? "%s" : "%s, ",
+                                 map[n].colname);
+       }
+
+       m += lws_snprintf(sql + m, sql_est - (unsigned int)m, ") values(%u, ", idx);
+
+       pk = 0;
+       did = 0;
+       for (n = 0; n < nentries; n++) {
+               uint64_t uu64;
+               size_t q;
+
+               if (!pk && map[n].type == LSMT_UNSIGNED) {
+                       pk = 1;
+                       continue;
+               }
+
+               switch (map[n].type) {
+               case LSMT_SIGNED:
+               case LSMT_UNSIGNED:
+               case LSMT_BOOLEAN:
+
+                       uu64 = 0;
+                       for (q = 0; q < map[n].aux; q++)
+                               uu64 |= ((uint64_t)stb[map[n].ofs + q] <<
+                                                               (q << 3));
+
+                       if (map[n].type == LSMT_SIGNED)
+                               m += lws_snprintf(sql + m, sql_est - (unsigned int)m, "%lld",
+                                                 (long long)(int64_t)uu64);
+                       else
+                               m += lws_snprintf(sql + m, sql_est - (unsigned int)m, "%llu",
+                                                 (unsigned long long)uu64);
+                       break;
+
+               case LSMT_STRING_CHAR_ARRAY:
+                       sql[m++] = '\'';
+                       lws_sql_purify(sql + m, (const char *)&stb[map[n].ofs],
+                                      sql_est - (size_t)(ssize_t)m - 4);
+                       m += (int)(ssize_t)strlen(sql + m);
+                       sql[m++] = '\'';
+                       break;
+               case LSMT_STRING_PTR:
+                       p = *((const char * const *)&stb[map[n].ofs]);
+                       sql[m++] = '\'';
+                       if (p) {
+                               lws_sql_purify(sql + m, p, sql_est - (unsigned int)m - 4);
+                               m += (int)(ssize_t)strlen(sql + m);
+                       }
+                       sql[m++] = '\'';
+                       break;
+
+               case LSMT_BLOB_PTR:
+                       continue;
+
+               default:
+                       lwsl_err("%s: unsupported type\n", __func__);
+                       assert(0);
+                       break;
+               }
+
+               did++;
+               if (did != nef) {
+                       if (sql_est - (unsigned int)m < 6)
+                               return -1;
+                       sql[m++] = ',';
+                       sql[m++] = ' ';
+               }
+       }
+
+       lws_snprintf(sql + m, sql_est - (unsigned int)m, ");");
+
+       n = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
+       if (n != SQLITE_OK) {
+               lwsl_err("%s\n", sql);
+               free(sql);
+               lwsl_err("%s: %s: fail\n", __func__, sqlite3_errmsg(pdb));
+               return -1;
+       }
+       free(sql);
+
+       return 0;
+}
+
+int
+lws_struct_sq3_serialize(sqlite3 *pdb, const lws_struct_map_t *schema,
+                        lws_dll2_owner_t *owner, uint32_t manual_idx)
+{
+       uint32_t idx = manual_idx;
+
+       lws_start_foreach_dll(struct lws_dll2 *, p, owner->head) {
+               void *item = (void *)((uint8_t *)p - schema->ofs_clist);
+               if (_lws_struct_sq3_ser_one(pdb, schema, idx++, item))
+                       return 1;
+
+       } lws_end_foreach_dll(p);
+
+       return 0;
+}
+
 int
 lws_struct_sq3_create_table(sqlite3 *pdb, const lws_struct_map_t *schema)
 {
        const lws_struct_map_t *map = schema->child_map;
-       int map_size = schema->child_map_size, subsequent = 0;
-       char s[2048], *p = s, *end = &s[sizeof(s) - 1], *pri = "primary key";
+       int map_size = (int)(ssize_t)schema->child_map_size, subsequent = 0;
+       char s[2048], *p = s, *end = &s[sizeof(s) - 1],
+            *pri = " primary key autoincrement", *use;
 
-       p += lws_snprintf(p, end - p, "create table if not exists %s (",
+       p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p),
+                         "create table if not exists %s (_lws_idx integer, ",
                          schema->colname);
 
        while (map_size--) {
-               if (map->type > LSMT_STRING_PTR) {
+               if (map->type > LSMT_STRING_PTR && map->type != LSMT_BLOB_PTR) {
                        map++;
                        continue;
                }
-               if (subsequent && (end - p) > 3)
+               if (subsequent && (end - p) > 4) {
                        *p++ = ',';
+                       *p++ = ' ';
+               }
                subsequent = 1;
-               if (map->type < LSMT_STRING_CHAR_ARRAY)
-                       p += lws_snprintf(p, end - p, "%s integer %s",
-                                         map->colname, pri);
-               else
-                       p += lws_snprintf(p, end - p, "%s varchar %s",
-                                         map->colname, pri);
-               pri = "";
+               if (map->type == LSMT_BLOB_PTR) {
+
+                       p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p), "%s blob", map->colname);
+
+               } else {
+                       if (map->type < LSMT_STRING_CHAR_ARRAY) {
+                               use = "";
+                               if (map->colname[0] != '_') /* _lws_idx is not primary key */
+                                       use = pri;
+                               p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p), "%s integer%s",
+                                               map->colname, use);
+                               if (map->colname[0] != '_')
+                                       pri = "";
+                       } else
+                               p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p), "%s varchar",
+                                               map->colname);
+               }
+
                map++;
        }
 
-       p += lws_snprintf(p, end - p, ");");
+       p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p), ");");
 
        if (sqlite3_exec(pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
                lwsl_err("%s: %s: fail\n", __func__, sqlite3_errmsg(pdb));
@@ -239,27 +502,35 @@ lws_struct_sq3_create_table(sqlite3 *pdb, const lws_struct_map_t *schema)
 
 int
 lws_struct_sq3_open(struct lws_context *context, const char *sqlite3_path,
-                   sqlite3 **pdb)
+                   char create_if_missing, sqlite3 **pdb)
 {
-       int uid = 0, gid = 0;
+#if !defined(WIN32)
+       uid_t uid = 0;
+       gid_t gid = 0;
+#endif
 
        if (sqlite3_open_v2(sqlite3_path, pdb,
-                           SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+                           SQLITE_OPEN_READWRITE |
+                           (create_if_missing ? SQLITE_OPEN_CREATE : 0),
                            NULL) != SQLITE_OK) {
-               lwsl_err("%s: Unable to open db %s: %s\n",
+               lwsl_info("%s: Unable to open db %s: %s\n",
                         __func__, sqlite3_path, sqlite3_errmsg(*pdb));
 
                return 1;
        }
 
+#if !defined(WIN32)
        lws_get_effective_uid_gid(context, &uid, &gid);
        if (uid)
-               chown(sqlite3_path, uid, gid);
+               if (chown(sqlite3_path, uid, gid))
+                       lwsl_err("%s: failed to chown %s\n", __func__, sqlite3_path);
        chmod(sqlite3_path, 0600);
 
-       lwsl_notice("%s: created %s owned by %u:%u mode 0600\n", __func__,
+       lwsl_debug("%s: created %s owned by %u:%u mode 0600\n", __func__,
                        sqlite3_path, (unsigned int)uid, (unsigned int)gid);
-
+#else
+       lwsl_debug("%s: created %s\n", __func__, sqlite3_path);
+#endif
        sqlite3_extended_result_codes(*pdb, 1);
 
        return 0;
@@ -268,10 +539,19 @@ lws_struct_sq3_open(struct lws_context *context, const char *sqlite3_path,
 int
 lws_struct_sq3_close(sqlite3 **pdb)
 {
+       int n;
+
        if (!*pdb)
                return 0;
 
-       sqlite3_close(*pdb);
+       n = sqlite3_close(*pdb);
+       if (n != SQLITE_OK) {
+               /*
+                * trouble...
+                */
+               lwsl_err("%s: failed to close: %d\n", __func__, n);
+               return 1;
+       }
        *pdb = NULL;
 
        return 0;
index e33bc8e..4f94a10 100644 (file)
@@ -90,7 +90,7 @@ lwsac if they need to, avoiding any need to visit them during destroy.  It's
 like clearing up after a kids' party by gathering up a disposable tablecloth:
 no matter what was left on the table, it's all gone in one step.
 
-## lws_list_ptr helpers
+## `lws_list_ptr` helpers
 
 ```
 /* sort may be NULL if you don't care about order */
@@ -100,7 +100,49 @@ lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add,
 ```
 
 A common pattern needed with sub-allocated structs is they are on one or more
-linked-list.  To make that simple to do cleanly, lws_list... apis are provided
+linked-list.  To make that simple to do cleanly, `lws_list...` apis are provided
 along with a generic insertion function that can take a sort callback.  These
 allow a struct to participate on multiple linked-lists simultaneously.
 
+## common const string and blob folding
+
+In some cases the input to be stored in the lwsac may repeat the same tokens
+multiple times... if the pattern is to store the string or blob in the lwsac
+and then point to it, you can make use of a helper api
+
+```
+uint8_t *
+lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul);
+```
+
+This lets you check in all previous used parts of the lwsac for the same
+string or blob, plus optionally a terminal NUL afterwards.  If not found,
+it returns `NULL` and you can copy it into the lwsac as usual.  If it is
+found, a pointer is returned, and you can use this directly without copying
+the string or blob in again.
+
+## optimizations to minimize overhead
+
+If the lwsac will persist in the system for some time, it's desirable to reduce
+the memory needed as overhead.  Overhead is created
+
+ - once per chunk... in addition to the malloc overhead, there's an lwsac
+   chunk header of 2 x pointers and 2 x size_t
+   
+ - at the unused part at the end that was allocated but not used
+A good strategy is to make the initial allocation reflect the minimum expected
+size of the overall lwsac in one hit.  Then use a chunk size that is a tradeoff
+between the number of chunks that might be needed and the fact that on average,
+you can expect to waste half a chunk.  For example if the storage is typically
+between 4K - 6K, you could allocate 4K or 4.5K for the first chunk and then fill
+in using 256 or 512 byte chunks.
+
+You can measure the overhead in an lwsac using `lwsac_total_overhead()`.
+
+The lwsac apis look first in the unused part of previous chunks, if any, and
+will place new allocations there preferentially if they fit.  This helps for the
+case lwsac was forced to allocate a new chunk because you asked for something
+large, while there was actually significant free space left in the old chunk,
+just not enough for that particular allocation.  Subsequent lwsac use can then
+"backfill" smaller things there to make best use of allocated space.
index 6598201..9f3b723 100644 (file)
@@ -1,28 +1,31 @@
 /*
- * libwebsockets - lws alloc chunk live file caching
- *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
 
-#include "core/private.h"
-#include "misc/lwsac/private.h"
+#include "private-lib-core.h"
+#include "private-lib-misc-lwsac.h"
 
 /*
  * Helper for caching a file in memory in a lac, but also to check at intervals
 
 #define cache_file_to_lac(c) ((struct lwsac *)((char *)c - \
                              sizeof(struct cached_file_info) - \
+                             sizeof(struct lwsac_head) - \
                              sizeof(struct lwsac)))
 
 void
 lwsac_use_cached_file_start(lwsac_cached_file_t cache)
 {
        struct lwsac *lac = cache_file_to_lac(cache);
+       struct lwsac_head *lachead = (struct lwsac_head *)&lac->head[1];
 
-       lac->refcount++;
-       // lwsl_debug("%s: html refcount: %d\n", __func__, lac->refcount);
+       lachead->refcount++;
+       // lwsl_debug("%s: html refcount: %d\n", __func__, lachead->refcount);
 }
 
 void
 lwsac_use_cached_file_end(lwsac_cached_file_t *cache)
 {
        struct lwsac *lac;
+       struct lwsac_head *lachead;
 
        if (!cache || !*cache)
                return;
 
        lac = cache_file_to_lac(*cache);
+       lachead = (struct lwsac_head *)&lac->head[1];
 
-       if (!lac->refcount)
+       if (!lachead->refcount)
                lwsl_err("%s: html refcount zero on entry\n", __func__);
 
-       if (lac->refcount && !--lac->refcount && lac->detached) {
+       if (lachead->refcount && !--lachead->refcount && lachead->detached) {
                *cache = NULL; /* not usable any more */
                lwsac_free(&lac);
        }
@@ -102,10 +109,15 @@ void
 lwsac_use_cached_file_detach(lwsac_cached_file_t *cache)
 {
        struct lwsac *lac = cache_file_to_lac(*cache);
+       struct lwsac_head *lachead = NULL;
 
-       lac->detached = 1;
-       if (lac->refcount)
-               return;
+       if (lac) {
+               lachead = (struct lwsac_head *)&lac->head[1];
+
+               lachead->detached = 1;
+               if (lachead->refcount)
+                       return;
+       }
 
        *cache = NULL;
        lwsac_free(&lac);
@@ -165,7 +177,7 @@ lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache, size_t *len)
         * it... reload in a new lac and then detach the old lac.
         */
 
-       all = sizeof(*info) + s.st_size + 1;
+       all = sizeof(*info) + (unsigned long)s.st_size + 2;
 
        info = lwsac_use(&lac, all, all);
        if (!info)
@@ -176,10 +188,10 @@ lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache, size_t *len)
 
        a = (unsigned char *)(info + 1);
 
-       *len = s.st_size;
+       *len = (unsigned long)s.st_size;
        a[s.st_size] = '\0';
 
-       rd = read(fd, a, s.st_size);
+       rd = read(fd, a, (unsigned long)s.st_size);
        if (rd != s.st_size) {
                lwsl_err("%s: cannot read %s (%d)\n", __func__, filepath,
                         (int)rd);
index 6471c16..faa82f0 100644 (file)
@@ -1,26 +1,29 @@
 /*
- * libwebsockets - lws alloc chunk
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-#include "misc/lwsac/private.h"
+#include "private-lib-core.h"
+#include "private-lib-misc-lwsac.h"
 
 void
 lws_list_ptr_insert(lws_list_ptr *head, lws_list_ptr *add,
@@ -49,9 +52,9 @@ lwsac_align(size_t length)
 }
 
 size_t
-lwsac_sizeof(void)
+lwsac_sizeof(int first)
 {
-       return sizeof(struct lwsac);
+       return sizeof(struct lwsac) + (first ? sizeof(struct lwsac_head) : 0);
 }
 
 size_t
@@ -66,91 +69,193 @@ lwsac_get_next(struct lwsac *lac)
        return lac->next;
 }
 
-void *
-lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size)
+int
+lwsac_extend(struct lwsac *head, size_t amount)
+{
+       struct lwsac_head *lachead;
+       struct lwsac *bf;
+
+       assert(head);
+       lachead = (struct lwsac_head *)&head[1];
+
+       bf = lachead->curr;
+       assert(bf);
+
+       if (bf->alloc_size - bf->ofs < lwsac_align(amount))
+               return 1;
+
+       /* memset so constant folding never sees uninitialized data */
+
+       memset(((uint8_t *)bf) + bf->ofs, 0, lwsac_align(amount));
+       bf->ofs += lwsac_align(amount);
+
+       return 0;
+}
+
+static void *
+_lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size, char backfill)
 {
-       struct lwsac *chunk;
-       size_t ofs, alloc;
+       struct lwsac_head *lachead = NULL;
+       size_t ofs, alloc, al, hp;
+       struct lwsac *bf = *head;
 
-       /* ensure there's a chunk and enough space in it for this name */
+       if (bf)
+               lachead = (struct lwsac_head *)&bf[1];
 
-       if (!*head || (*head)->curr->alloc_size - (*head)->curr->ofs < ensure) {
+       al = lwsac_align(ensure);
 
-               if (!chunk_size)
-                       alloc = LWSAC_CHUNK_SIZE + sizeof(*chunk);
-               else
-                       alloc = chunk_size + sizeof(*chunk);
+       /* backfill into earlier chunks if that is allowed */
 
+       if (backfill)
                /*
-                * If we get asked for something outside our expectation,
-                * allocate to meet it
+                * check if anything can take it, from the start
                 */
+               while (bf) {
+                       if (bf->alloc_size - bf->ofs >= ensure)
+                               goto do_use;
 
-               if (ensure >= alloc - sizeof(*chunk))
-                       alloc = ensure + sizeof(*chunk);
-
-               chunk = malloc(alloc);
-               if (!chunk) {
-                       lwsl_err("%s: OOM trying to alloc %llud\n", __func__,
-                                       (unsigned long long)alloc);
-                       return NULL;
+                       bf = bf->next;
                }
-
-               if (!*head) {
-                       *head = chunk;
-                       chunk->total_alloc_size = 0;
-                       chunk->total_blocks = 0;
+       else {
+               /*
+                * If there's a current chunk, just check if he can take it
+                */
+               if (lachead && lachead->curr) {
+                       bf = lachead->curr;
+                       if (bf->alloc_size - bf->ofs >= ensure)
+                               goto do_use;
                }
-               else
-                       (*head)->curr->next = chunk;
+       }
 
-               (*head)->curr = chunk;
-               (*head)->curr->head = *head;
+       /* nothing can currently take it... so we must allocate */
 
-               chunk->next = NULL;
-               chunk->alloc_size = alloc;
-               chunk->detached = 0;
-               chunk->refcount = 0;
+       hp = sizeof(*bf); /* always need the normal header part... */
+       if (!*head)
+               hp += sizeof(struct lwsac_head);
+
+       if (!chunk_size)
+               alloc = LWSAC_CHUNK_SIZE + hp;
+       else
+               alloc = chunk_size + hp;
+
+       /*
+        * If we get asked for something outside our expectation,
+        * increase the allocation to meet it
+        */
+
+       if (al >= alloc - hp)
+               alloc = al + hp;
+
+       lwsl_debug("%s: alloc %d for %d\n", __func__, (int)alloc, (int)ensure);
+       bf = malloc(alloc);
+       if (!bf) {
+               lwsl_err("%s: OOM trying to alloc %llud\n", __func__,
+                               (unsigned long long)alloc);
+               return NULL;
+       }
 
-               (*head)->total_alloc_size += alloc;
-               (*head)->total_blocks++;
+       /*
+        * belabouring the point... ofs is aligned to the platform's
+        * generic struct alignment at the start then
+        */
+       bf->ofs = sizeof(*bf);
 
+       if (!*head) {
                /*
-                * belabouring the point... ofs is aligned to the platform's
-                * generic struct alignment at the start then
+                * We are the first, head, entry...
                 */
-               (*head)->curr->ofs = sizeof(*chunk);
-       }
+               *head = bf;
+               /*
+                * ... allocate for the special head block
+                */
+               bf->ofs += sizeof(*lachead);
+               lachead = (struct lwsac_head *)&bf[1];
+               memset(lachead, 0, sizeof(*lachead));
+       } else
+               if (lachead->curr)
+                       lachead->curr->next = bf;
+
+       lachead->curr = bf;
+       bf->head = *head;
+       bf->next = NULL;
+       bf->alloc_size = alloc;
+
+       lachead->total_alloc_size += alloc;
+       lachead->total_blocks++;
+
+do_use:
+
+       ofs = bf->ofs;
 
-       ofs = (*head)->curr->ofs;
+       if (al > ensure)
+               /* zero down the alignment padding part */
+               memset((char *)bf + ofs + ensure, 0, al - ensure);
 
-       (*head)->curr->ofs += lwsac_align(ensure);
-       if ((*head)->curr->ofs >= (*head)->curr->alloc_size)
-               (*head)->curr->ofs = (*head)->curr->alloc_size;
+       bf->ofs += al;
+       if (bf->ofs >= bf->alloc_size)
+               bf->ofs = bf->alloc_size;
 
-       return (char *)(*head)->curr + ofs;
+       return (char *)bf + ofs;
 }
 
 void *
-lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size)
+lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size)
 {
-       void *p = lwsac_use(head, ensure, chunk_size);
+       return _lwsac_use(head, ensure, chunk_size, 0);
+}
 
-       if (p)
-               memset(p, 0, ensure);
+void *
+lwsac_use_backfill(struct lwsac **head, size_t ensure, size_t chunk_size)
+{
+       return _lwsac_use(head, ensure, chunk_size, 1);
+}
 
-       return p;
+uint8_t *
+lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul)
+{
+       while (head) {
+               uint8_t *pos = (uint8_t *)&head[1],
+                       *end = ((uint8_t *)head) + head->ofs - len;
+
+               if (head->ofs - sizeof(*head) >= len)
+                       while (pos < end) {
+                               if (*pos == *find && (!nul || !pos[len]) &&
+                                   pos[len - 1] == find[len - 1] &&
+                                   !memcmp(pos, find, len))
+                                       /* found the blob */
+                                       return pos;
+                               pos++;
+                       }
+
+               head = head->next;
+       }
+
+       return NULL;
+}
+
+uint64_t
+lwsac_total_overhead(struct lwsac *head)
+{
+       uint64_t overhead = 0;
+
+       while (head) {
+               overhead += (head->alloc_size - head->ofs) + sizeof(*head);
+
+               head = head->next;
+       }
+
+       return overhead;
 }
 
 void *
-lwsac_use_zeroed(struct lwsac **head, size_t ensure, size_t chunk_size)
+lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size)
 {
-       void *r = lwsac_use(head, ensure, chunk_size);
+       void *p = lwsac_use(head, ensure, chunk_size);
 
-       if (r)
-               memset(r, 0, ensure);
+       if (p)
+               memset(p, 0, ensure);
 
-       return r;
+       return p;
 }
 
 void
@@ -172,42 +277,62 @@ lwsac_free(struct lwsac **head)
 void
 lwsac_info(struct lwsac *head)
 {
-       if (!head)
+#if _LWS_ENABLED_LOGS & LLL_DEBUG
+       struct lwsac_head *lachead;
+
+       if (!head) {
                lwsl_debug("%s: empty\n", __func__);
-       else
-               lwsl_debug("%s: lac %p: %dKiB in %d blocks\n", __func__, head,
-                  (int)(head->total_alloc_size >> 10), head->total_blocks);
+               return;
+       }
+
+       lachead = (struct lwsac_head *)&head[1];
+
+       lwsl_debug("%s: lac %p: %dKiB in %d blocks\n", __func__, head,
+                  (int)(lachead->total_alloc_size >> 10), lachead->total_blocks);
+#endif
 }
 
 uint64_t
 lwsac_total_alloc(struct lwsac *head)
 {
-       return head->total_alloc_size;
+       struct lwsac_head *lachead;
+
+       if (!head)
+               return 0;
+
+       lachead = (struct lwsac_head *)&head[1];
+       return lachead->total_alloc_size;
 }
 
 void
 lwsac_reference(struct lwsac *head)
 {
-       head->refcount++;
+       struct lwsac_head *lachead = (struct lwsac_head *)&head[1];
+
+       lachead->refcount++;
        lwsl_debug("%s: head %p: (det %d) refcount -> %d\n",
-                   __func__, head, head->detached, head->refcount);
+                   __func__, head, lachead->detached, lachead->refcount);
 }
 
 void
 lwsac_unreference(struct lwsac **head)
 {
+       struct lwsac_head *lachead;
+
        if (!(*head))
                return;
 
-       if (!(*head)->refcount)
+       lachead = (struct lwsac_head *)&(*head)[1];
+
+       if (!lachead->refcount)
                lwsl_warn("%s: refcount going below zero\n", __func__);
 
-       (*head)->refcount--;
+       lachead->refcount--;
 
        lwsl_debug("%s: head %p: (det %d) refcount -> %d\n",
-                   __func__, *head, (*head)->detached, (*head)->refcount);
+                   __func__, *head, lachead->detached, lachead->refcount);
 
-       if ((*head)->detached && !(*head)->refcount) {
+       if (lachead->detached && !lachead->refcount) {
                lwsl_debug("%s: head %p: FREED\n", __func__, *head);
                lwsac_free(head);
        }
@@ -216,11 +341,18 @@ lwsac_unreference(struct lwsac **head)
 void
 lwsac_detach(struct lwsac **head)
 {
-       (*head)->detached = 1;
-       if (!(*head)->refcount) {
+       struct lwsac_head *lachead;
+
+       if (!(*head))
+               return;
+
+       lachead = (struct lwsac_head *)&(*head)[1];
+
+       lachead->detached = 1;
+       if (!lachead->refcount) {
                lwsl_debug("%s: head %p: FREED\n", __func__, *head);
                lwsac_free(head);
        } else
                lwsl_debug("%s: head %p: refcount %d: Marked as detached\n",
-                           __func__, *head, (*head)->refcount);
+                           __func__, *head, lachead->refcount);
 }
diff --git a/lib/misc/lwsac/lwsac.cxx b/lib/misc/lwsac/lwsac.cxx
new file mode 100644 (file)
index 0000000..cea3fb2
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * C++ classes for Secure Streams - atomic heap messages
+ */
+
+#include <libwebsockets.hxx>
+#include "private-lib-misc-lwsac.h"
+
+void
+lssAc::start(bool atomic)
+{
+       if (atomic && ac->next) {
+               struct lwsac *ac2 = NULL, *i;
+               size_t total = (size_t)lwsac_total_alloc(ac);
+               uint8_t *p = (uint8_t *)lwsac_use(&ac2, total, total);
+
+               /*
+                * He wants a single linear buffer, and we have more than one
+                * piece... let's make a new, single one, copy the fragments
+                * in and replace the fragmented one with the unified copy.
+                */
+
+               i = ac;
+               while (i) {
+                       size_t bl = lwsac_get_tail_pos(i) -
+                                               lwsac_sizeof(i == ac);
+                       memcpy(p, (uint8_t *)i + lwsac_sizeof(i == ac), bl);
+                       p += bl;
+               }
+
+               lwsac_free(&ac);
+               ac = ac2;
+       }
+
+       iter = ac;
+}
+
+int
+lssAc::get(lssbuf_t *lb)
+{
+       if (!ac)
+               return 1;
+
+       lb->buf = (uint8_t *)iter + lwsac_sizeof(iter == ac);
+       lb->len = lwsac_get_tail_pos(iter) - lwsac_sizeof(iter == ac);
+       iter = iter->next;
+
+       return 0;
+}
+
+void
+lssAc::append(lssbuf_t *lb)
+{
+       uint8_t *p = (uint8_t *)lwsac_use(&ac, lb->len, lb->len);
+
+       if (!p)
+               throw lssException("oom");
+       memcpy(p, lb->buf, lb->len);
+}
diff --git a/lib/misc/lwsac/private-lib-misc-lwsac.h b/lib/misc/lwsac/private-lib-misc-lwsac.h
new file mode 100644 (file)
index 0000000..026e7ad
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(__LWS_PRIVATE_LIB_MISC_LWSAC_H__)
+#define __LWS_PRIVATE_LIB_MISC_LWSAC_H__
+
+#if !defined(LWS_PLAT_OPTEE)
+#include <sys/stat.h>
+#endif
+
+/* under page size of 4096 to allow overhead */
+#define LWSAC_CHUNK_SIZE 4000
+
+/*
+ * the chunk list members all point back to the head themselves so the list
+ * can be detached from the formal head and free itself when its reference
+ * count reaches zero.
+ */
+
+/*
+ * One of these per chunk
+ */
+
+struct lwsac {
+       struct lwsac *next;
+       struct lwsac *head; /* pointer back to the first chunk */
+       size_t alloc_size; /* alloc size of the whole chunk */
+       size_t ofs; /* next writeable position inside chunk */
+};
+
+/*
+ * One of these per lwsac, at start of first chunk
+ */
+
+struct lwsac_head {
+       struct lwsac *curr;
+       size_t total_alloc_size;
+       int refcount;
+       int total_blocks;
+       char detached; /* if our refcount gets to zero, free the chunk list */
+};
+
+#if !defined(LWS_PLAT_OPTEE)
+struct cached_file_info {
+       struct stat s;
+       time_t last_confirm;
+};
+#endif
+#endif
diff --git a/lib/misc/lwsac/private.h b/lib/misc/lwsac/private.h
deleted file mode 100644 (file)
index 827906e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * libwebsockets - lws alloc chunk
- *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#if !defined(LWS_PLAT_OPTEE)
-#include <sys/stat.h>
-#endif
-
-/* under page size of 4096 to allow overhead */
-#define LWSAC_CHUNK_SIZE 4000
-
-/*
- * the chunk list members all point back to the head themselves so the list
- * can be detached from the formal head and free itself when its reference
- * count reaches zero.
- */
-
-struct lwsac {
-       struct lwsac *next;
-       struct lwsac *head; /* pointer back to the first chunk */
-       struct lwsac *curr; /* applies to head chunk only */
-       size_t total_alloc_size; /* applies to head chunk only */
-       size_t alloc_size;
-       size_t ofs; /* next writeable position inside chunk */
-       int refcount; /* applies to head chunk only */
-       int total_blocks; /* applies to head chunk only */
-       char detached; /* if our refcount gets to zero, free the chunk list */
-};
-
-#if !defined(LWS_PLAT_OPTEE)
-struct cached_file_info {
-       struct stat s;
-       time_t last_confirm;
-};
-#endif
index 53d9421..f784546 100644 (file)
@@ -1,25 +1,29 @@
 /*
- * libwebsockets - peer limits tracking
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include <libwebsockets.h>
+#include "private-lib-core.h"
 
 /* requires context->lock */
 static void
@@ -35,11 +39,26 @@ __lws_peer_remove_from_peer_wait_list(struct lws_context *context,
                        *p = df->peer_wait_list;
                        df->peer_wait_list = NULL;
 
+                       if (!context->peer_wait_list)
+                               lws_sul_cancel(&context->pt[0].sul_peer_limits);
+
                        return;
                }
        } lws_end_foreach_llp(p, peer_wait_list);
 }
 
+void
+lws_sul_peer_limits_cb(lws_sorted_usec_list_t *sul)
+{
+       struct lws_context_per_thread *pt = lws_container_of(sul,
+                       struct lws_context_per_thread, sul_peer_limits);
+
+       lws_peer_cull_peer_wait_list(pt->context);
+
+       lws_sul_schedule(pt->context, 0, &pt->context->pt[0].sul_peer_limits,
+                        lws_sul_peer_limits_cb, 10 * LWS_US_PER_SEC);
+}
+
 /* requires context->lock */
 static void
 __lws_peer_add_to_peer_wait_list(struct lws_context *context,
@@ -49,6 +68,10 @@ __lws_peer_add_to_peer_wait_list(struct lws_context *context,
 
        peer->peer_wait_list = context->peer_wait_list;
        context->peer_wait_list = peer;
+
+       if (!context->pt[0].sul_peer_limits.list.owner)
+               lws_sul_schedule(context, 0, &context->pt[0].sul_peer_limits,
+                               lws_sul_peer_limits_cb, 10 * LWS_US_PER_SEC);
 }
 
 
@@ -56,46 +79,39 @@ struct lws_peer *
 lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd)
 {
        struct lws_context *context = vhost->context;
-       socklen_t rlen = 0;
-       void *q;
-       uint8_t *q8;
        struct lws_peer *peer;
+       lws_sockaddr46 sa46;
+       socklen_t rlen = 0;
        uint32_t hash = 0;
-       int n, af = AF_INET;
-       struct sockaddr_storage addr;
+       uint8_t *q8;
+       void *q;
+       int n;
 
        if (vhost->options & LWS_SERVER_OPTION_UNIX_SOCK)
                return NULL;
 
-#ifdef LWS_WITH_IPV6
-       if (LWS_IPV6_ENABLED(vhost)) {
-               af = AF_INET6;
-       }
-#endif
-       rlen = sizeof(addr);
-       if (getpeername(sockfd, (struct sockaddr*)&addr, &rlen))
+       rlen = sizeof(sa46);
+       if (getpeername(sockfd, (struct sockaddr*)&sa46, &rlen))
                /* eg, udp doesn't have to have a peer */
                return NULL;
 
 #ifdef LWS_WITH_IPV6
-       if (af == AF_INET)
+       if (sa46.sa4.sin_family == AF_INET6) {
+               q = &sa46.sa6.sin6_addr;
+               rlen = sizeof(sa46.sa6.sin6_addr);
+       } else
 #endif
        {
-               struct sockaddr_in *s = (struct sockaddr_in *)&addr;
-               q = &s->sin_addr;
-               rlen = sizeof(s->sin_addr);
-       }
-#ifdef LWS_WITH_IPV6
-       else {
-               struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
-               q = &s->sin6_addr;
-               rlen = sizeof(s->sin6_addr);
+               q = &sa46.sa4.sin_addr;
+               rlen = sizeof(sa46.sa4.sin_addr);
        }
-#endif
 
        q8 = q;
        for (n = 0; n < (int)rlen; n++)
-               hash = (((hash << 4) | (hash >> 28)) * n) ^ q8[n];
+               hash = (uint32_t)((((hash << 4) | (hash >> 28)) * (uint32_t)n) ^ q8[n]);
+
+       if (!context->pl_hash_elements)
+               return NULL;
 
        hash = hash % context->pl_hash_elements;
 
@@ -103,9 +119,21 @@ lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd)
 
        lws_start_foreach_ll(struct lws_peer *, peerx,
                             context->pl_hash_table[hash]) {
-               if (peerx->af == af && !memcmp(q, peerx->addr, rlen)) {
-                       lws_context_unlock(context); /* === */
-                       return peerx;
+               if (peerx->sa46.sa4.sin_family == sa46.sa4.sin_family) {
+#if defined(LWS_WITH_IPV6)
+                       if (sa46.sa4.sin_family == AF_INET6 &&
+                           !memcmp(q, &peerx->sa46.sa6.sin6_addr, rlen))
+                               goto hit;
+#endif
+                       if (sa46.sa4.sin_family == AF_INET &&
+                           !memcmp(q, &peerx->sa46.sa4.sin_addr, rlen)) {
+#if defined(LWS_WITH_IPV6)
+hit:
+#endif
+                               lws_context_unlock(context); /* === */
+
+                               return peerx;
+                       }
                }
        } lws_end_foreach_ll(peerx, next);
 
@@ -121,9 +149,8 @@ lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd)
        context->count_peers++;
        peer->next = context->pl_hash_table[hash];
        peer->hash = hash;
-       peer->af = af;
+       peer->sa46 = sa46;
        context->pl_hash_table[hash] = peer;
-       memcpy(peer->addr, q, rlen);
        time(&peer->time_created);
        /*
         * On creation, the peer has no wsi attached, so is created on the
@@ -214,14 +241,15 @@ lws_peer_dump_from_wsi(struct lws *wsi)
        peer = wsi->peer;
 
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       lwsl_notice("%s: wsi %p: created %llu: wsi: %d/%d, ah %d/%d\n",
-                       __func__,
-                       wsi, (unsigned long long)peer->time_created,
+       lwsl_notice("%s: %s: created %llu: wsi: %d/%d, ah %d/%d\n",
+                       __func__, lws_wsi_tag(wsi),
+                       (unsigned long long)peer->time_created,
                        peer->count_wsi, peer->total_wsi,
                        peer->http.count_ah, peer->http.total_ah);
 #else
-       lwsl_notice("%s: wsi %p: created %llu: wsi: %d/%d\n", __func__,
-                       wsi, (unsigned long long)peer->time_created,
+       lwsl_notice("%s: %s: created %llu: wsi: %d/%d\n", __func__,
+                       lws_wsi_tag(wsi),
+                       (unsigned long long)peer->time_created,
                        peer->count_wsi, peer->total_wsi);
 #endif
 }
diff --git a/lib/misc/prng.c b/lib/misc/prng.c
new file mode 100644 (file)
index 0000000..8f05fad
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * After Public Domain implementations
+ *
+ * https://github.com/svaarala/duktape/tree/master/misc
+ */
+
+#include <private-lib-core.h>
+
+static inline uint64_t rol64(uint64_t x, int k)
+{
+       return (x << k) | (x >> (64 - k));
+}
+
+uint64_t
+lws_xos(struct lws_xos *xos)
+{
+       uint64_t *s = &xos->s[0];
+       uint64_t const result = rol64(s[1] * 5, 7) * 9;
+       uint64_t const c = s[1] << 17;
+
+       s[2] ^= s[0];
+       s[3] ^= s[1];
+       s[1] ^= s[2];
+       s[0] ^= s[3];
+
+       s[2] ^= c;
+       s[3] = rol64(s[3], 45);
+
+       return result;
+}
+
+static uint64_t
+splitmix64(uint64_t *s)
+{
+       uint64_t r = *s;
+
+       *s = r + 0x9E3779B97F4A7C15ull;
+
+       r = (r ^ (r >> 30)) * 0xBF58476D1CE4E5B9ull;
+       r = (r ^ (r >> 27)) * 0x94D049BB133111EBull;
+
+       return r ^ (r >> 31);
+}
+
+void
+lws_xos_init(struct lws_xos *xos, uint64_t seed)
+{
+       int n;
+
+       for (n = 0; n < 4; n++)
+               xos->s[n] = splitmix64(&seed);
+}
+
+int
+lws_xos_percent(struct lws_xos *xos, int percent)
+{
+       return (int)(lws_xos(xos) % 100) < percent;
+}
index 814999a..2e871b7 100644 (file)
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <libwebsockets.h>
 #include <string.h>
 #include <stdint.h>
 #include <stdio.h>
 #include "romfs.h"
+#if defined(LWS_WITH_ESP32)
 #include "esp_spi_flash.h"
+#endif
 
 #define RFS_STRING_MAX 96
 
@@ -46,11 +49,13 @@ static romfs_t cr = (romfs_t)cache;
 static void
 set_cache(romfs_inode_t inode, size_t len)
 {
+#if defined(LWS_WITH_ESP32)
        spi_flash_read((uint32_t)inode, cache, len);
+#endif
 }
 
 static uint32_t
-ntohl(const u32_be_t be)
+untohl(const u32_be_t be)
 {
        return ((be >> 24) & 0xff) |
               ((be >> 16) & 0xff) << 8 |
@@ -91,7 +96,7 @@ romfs_mount_check(romfs_t romfs)
            cr->magic2 != 0x2d736631)
                return 0;
 
-       return ntohl(cr->size);
+       return untohl(cr->size);
 }
 
 static romfs_inode_t
@@ -112,7 +117,7 @@ dir_link(romfs_t romfs, romfs_inode_t i)
 {
        set_cache(i, sizeof(*i));
        return (romfs_inode_t)((const uint8_t *)romfs +
-                                               ntohl(ci->dir_start));
+                                               untohl(ci->dir_start));
 }
 
 static romfs_inode_t
@@ -148,16 +153,16 @@ romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
                        p++;
 
                if (!*cp && (!*p || *p == '/') &&
-                   (ntohl(next_be) & 7) == RFST_HARDLINK) {
+                   (untohl(next_be) & 7) == RFST_HARDLINK) {
                        set_cache(i, sizeof(*i));
                        return (romfs_inode_t)
                               ((const uint8_t *)romfs +
-                               (ntohl(ci->dir_start) & ~15));
+                               (untohl(ci->dir_start) & ~15));
                }
 
                if (!*p && !*cp) {
                        set_cache(i, sizeof(*i));
-                       if ((ntohl(ci->next) & 7) == RFST_SYMLINK) {
+                       if ((untohl(ci->next) & 7) == RFST_SYMLINK) {
                                i = romfs_symlink(romfs, level, i);
                                continue;
                        }
@@ -172,7 +177,7 @@ romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
 
                if (*p == '/' && !*cp) {
                        set_cache(i, sizeof(*i));
-                       switch (ntohl(ci->next) & 7) {
+                       switch (untohl(ci->next) & 7) {
                        case RFST_SYMLINK:
                                i = romfs_symlink(romfs, level, i);
                                if (!i)
@@ -198,11 +203,11 @@ romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
                }
 
                set_cache(i, sizeof(*i));
-               if (!(ntohl(ci->next) & ~15))
+               if (!(untohl(ci->next) & ~15))
                        return NULL;
 
                i = (romfs_inode_t)((const uint8_t *)romfs +
-                                   (ntohl(ci->next) & ~15));
+                                   (untohl(ci->next) & ~15));
                if (i == i_in)
                        return NULL;
        }
@@ -224,9 +229,9 @@ romfs_get_info(romfs_t romfs, const char *path, size_t *len, size_t *csum)
                return NULL;
 
        set_cache(i, sizeof(*i));
-       *len = ntohl(ci->size);
+       *len = untohl(ci->size);
        if (csum)
-               *csum = ntohl(ci->checksum);
+               *csum = untohl(ci->checksum);
 
        return (void *)skip_and_pad(i);
 }
index c17a437..22989e4 100644 (file)
@@ -32,7 +32,7 @@
  * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #ifdef LWS_HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -211,14 +211,14 @@ sha1_pad(struct sha1_ctxt *ctxt)
        padlen = 64 - padstart;
        if (padlen < 8) {
                memset(&ctxt->m.b8[padstart], 0, padlen);
-               COUNT += (unsigned char)padlen;
+               COUNT = (unsigned char)(COUNT + padlen);
                COUNT %= 64;
                sha1_step(ctxt);
                padstart = COUNT % 64;  /* should be 0 */
                padlen = 64 - padstart; /* should be 64 */
        }
        memset(&ctxt->m.b8[padstart], 0, padlen - 8);
-       COUNT += ((unsigned char)padlen - 8);
+       COUNT = (unsigned char)(COUNT + (padlen - 8));
        COUNT %= 64;
 #if BYTE_ORDER == BIG_ENDIAN
        PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]);
@@ -245,7 +245,7 @@ sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len)
                       copysiz = (gaplen < len - off) ? gaplen : len - off;
 
                memcpy(&ctxt->m.b8[gapstart], &input[off], copysiz);
-               COUNT += (unsigned char)copysiz;
+               COUNT = (unsigned char)(COUNT + copysiz);
                COUNT %= 64;
                ctxt->c.b64[0] += copysiz * 8;
                if (COUNT % 64 == 0)
@@ -281,7 +281,7 @@ sha1_result(struct sha1_ctxt *ctxt, void *digest0)
  * This should look and work like the libcrypto implementation
  */
 
-LWS_VISIBLE unsigned char *
+unsigned char *
 lws_SHA1(const unsigned char *d, size_t n, unsigned char *md)
 {
        struct sha1_ctxt ctx;
index de9bab7..40df5ba 100644 (file)
@@ -1,28 +1,40 @@
 /*
- * libwebsockets - threadpool api
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
+#endif
+
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #include <string.h>
 #include <stdio.h>
 struct lws_threadpool;
 
 struct lws_threadpool_task {
-       struct lws_threadpool_task *task_queue_next;
+       struct lws_threadpool_task      *task_queue_next;
 
-       struct lws_threadpool *tp;
-       char name[32];
+       struct lws_threadpool           *tp;
+       char                            name[32];
        struct lws_threadpool_task_args args;
 
-       lws_usec_t created;
-       lws_usec_t acquired;
-       lws_usec_t done;
-       lws_usec_t entered_state;
+       lws_dll2_t                      list;
 
-       lws_usec_t acc_running;
-       lws_usec_t acc_syncing;
+       lws_usec_t                      created;
+       lws_usec_t                      acquired;
+       lws_usec_t                      done;
+       lws_usec_t                      entered_state;
 
-       pthread_cond_t wake_idle;
+       lws_usec_t                      acc_running;
+       lws_usec_t                      acc_syncing;
+
+       pthread_cond_t                  wake_idle;
 
        enum lws_threadpool_task_status status;
 
-       int late_sync_retries;
+       int                             late_sync_retries;
 
-       char wanted_writeable_cb;
-       char outlive;
+       char                            wanted_writeable_cb;
+       char                            outlive;
 };
 
 struct lws_pool {
-       struct lws_threadpool *tp;
-       pthread_t thread;
-       pthread_mutex_t lock; /* part of task wake_idle */
-       struct lws_threadpool_task *task;
-       lws_usec_t acquired;
-       int worker_index;
+       struct lws_threadpool           *tp;
+       pthread_t                       thread;
+       pthread_mutex_t                 lock; /* part of task wake_idle */
+       struct lws_threadpool_task      *task;
+       lws_usec_t                      acquired;
+       int                             worker_index;
 };
 
 struct lws_threadpool {
-       pthread_mutex_t lock; /* protects all pool lists */
-       pthread_cond_t wake_idle;
-       struct lws_pool *pool_list;
+       pthread_mutex_t                 lock; /* protects all pool lists */
+       pthread_cond_t                  wake_idle;
+       struct lws_pool                 *pool_list;
 
-       struct lws_context *context;
-       struct lws_threadpool *tp_list; /* context list of threadpools */
+       struct lws_context              *context;
+       struct lws_threadpool           *tp_list; /* context list of threadpools */
 
-       struct lws_threadpool_task *task_queue_head;
-       struct lws_threadpool_task *task_done_head;
+       struct lws_threadpool_task      *task_queue_head;
+       struct lws_threadpool_task      *task_done_head;
 
-       char name[32];
+       char                            name[32];
 
-       int threads_in_pool;
-       int queue_depth;
-       int done_queue_depth;
-       int max_queue_depth;
-       int running_tasks;
+       int                             threads_in_pool;
+       int                             queue_depth;
+       int                             done_queue_depth;
+       int                             max_queue_depth;
+       int                             running_tasks;
 
-       unsigned int destroying:1;
+       unsigned int                    destroying:1;
 };
 
 static int
@@ -115,7 +129,7 @@ __lws_threadpool_task_dump(struct lws_threadpool_task *task, char *buf, int len)
        int syncms = 0, runms = 0;
 
        if (!task->acquired) {
-               buf += lws_snprintf(buf, end - buf,
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
                                    "task: %s, QUEUED queued: %dms",
                                    task->name, ms_delta(now, task->created));
 
@@ -123,13 +137,13 @@ __lws_threadpool_task_dump(struct lws_threadpool_task *task, char *buf, int len)
        }
 
        if (task->acc_running)
-               runms = task->acc_running;
+               runms = (int)task->acc_running;
 
        if (task->acc_syncing)
-               syncms = task->acc_syncing;
+               syncms = (int)task->acc_syncing;
 
        if (!task->done) {
-               buf += lws_snprintf(buf, end - buf,
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
                        "task: %s, ONGOING state %d (%dms) alive: %dms "
                        "(queued %dms, acquired: %dms, "
                        "run: %d%%, sync: %d%%)", task->name, task->status,
@@ -143,7 +157,7 @@ __lws_threadpool_task_dump(struct lws_threadpool_task *task, char *buf, int len)
                return;
        }
 
-       buf += lws_snprintf(buf, end - buf,
+       lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
                "task: %s, DONE state %d lived: %dms "
                "(queued %dms, on thread: %dms, "
                "ran: %d%%, synced: %d%%)", task->name, task->status,
@@ -157,7 +171,8 @@ __lws_threadpool_task_dump(struct lws_threadpool_task *task, char *buf, int len)
 void
 lws_threadpool_dump(struct lws_threadpool *tp)
 {
-#if defined(_DEBUG)
+#if 0
+       //defined(_DEBUG)
        struct lws_threadpool_task **c;
        char buf[160];
        int n, count;
@@ -226,17 +241,26 @@ state_transition(struct lws_threadpool_task *task,
        task->status = status;
 }
 
+static struct lws *
+task_to_wsi(struct lws_threadpool_task *task)
+{
+#if defined(LWS_WITH_SECURE_STREAMS)
+       if (task->args.ss)
+               return task->args.ss->wsi;
+#endif
+       return task->args.wsi;
+}
+
 static void
 lws_threadpool_task_cleanup_destroy(struct lws_threadpool_task *task)
 {
        if (task->args.cleanup)
-               task->args.cleanup(task->args.wsi, task->args.user);
+               task->args.cleanup(task_to_wsi(task), task->args.user);
 
-       if (task->args.wsi)
-               task->args.wsi->tp_task = NULL;
+       lws_dll2_remove(&task->list);
 
-       lwsl_thread("%s: tp %p: cleaned finished task for wsi %p\n",
-                   __func__, task->tp, task->args.wsi);
+       lwsl_thread("%s: tp %p: cleaned finished task for %s\n",
+                   __func__, task->tp, lws_wsi_tag(task_to_wsi(task)));
 
        lws_free(task);
 }
@@ -249,25 +273,34 @@ __lws_threadpool_reap(struct lws_threadpool_task *task)
 
        /* remove the task from the done queue */
 
-       c = &tp->task_done_head;
+       if (tp) {
+               c = &tp->task_done_head;
 
-       while (*c) {
-               if ((*c) == task) {
-                       t = *c;
-                       *c = t->task_queue_next;
-                       t->task_queue_next = NULL;
-                       tp->done_queue_depth--;
+               while (*c) {
+                       if ((*c) == task) {
+                               t = *c;
+                               *c = t->task_queue_next;
+                               t->task_queue_next = NULL;
+                               tp->done_queue_depth--;
 
-                       lwsl_thread("%s: tp %s: reaped task wsi %p\n", __func__,
-                                  tp->name, task->args.wsi);
+                               lwsl_thread("%s: tp %s: reaped task %s\n", __func__,
+                                          tp->name, lws_wsi_tag(task_to_wsi(task)));
 
-                       break;
+                               break;
+                       }
+                       c = &(*c)->task_queue_next;
                }
-               c = &(*c)->task_queue_next;
-       }
 
-       if (!t)
-               lwsl_err("%s: task %p not in done queue\n", __func__, task);
+               if (!t) {
+                       lwsl_err("%s: task %p not in done queue\n", __func__, task);
+                       /*
+                        * This shouldn't occur, but in this case not really
+                        * safe to assume there's a task to destroy
+                        */
+                       return;
+               }
+       } else
+               lwsl_err("%s: task->tp NULL already\n", __func__);
 
        /* call the task's cleanup and delete the task itself */
 
@@ -302,9 +335,10 @@ lws_threadpool_tsi_context(struct lws_context *context, int tsi)
                        if (!task)
                                continue;
 
-                       wsi = task->args.wsi;
+                       wsi = task_to_wsi(task);
                        if (!wsi || wsi->tsi != tsi ||
-                           !task->wanted_writeable_cb)
+                           (!task->wanted_writeable_cb &&
+                            task->status != LWS_TP_STATUS_SYNCING))
                                continue;
 
                        task->wanted_writeable_cb = 0;
@@ -325,10 +359,11 @@ lws_threadpool_tsi_context(struct lws_context *context, int tsi)
 
                while (*c) {
                        task = *c;
-                       wsi = task->args.wsi;
+                       wsi = task_to_wsi(task);
 
                        if (wsi && wsi->tsi == tsi &&
-                           task->wanted_writeable_cb) {
+                           (task->wanted_writeable_cb ||
+                            task->status == LWS_TP_STATUS_SYNCING)) {
 
                                task->wanted_writeable_cb = 0;
                                lws_memory_barrier();
@@ -366,13 +401,13 @@ lws_threadpool_worker_sync(struct lws_pool *pool,
        lwsl_debug("%s: %p: LWS_TP_RETURN_SYNC in\n", __func__, task);
        pthread_mutex_lock(&pool->lock); /* ======================= pool lock */
 
-       lwsl_info("%s: %s: task %p (%s): syncing with wsi %p\n", __func__,
-                   pool->tp->name, task, task->name, task->args.wsi);
+       lwsl_info("%s: %s: task %p (%s): syncing with %s\n", __func__,
+                   pool->tp->name, task, task->name, lws_wsi_tag(task_to_wsi(task)));
 
        temp = task->status;
        state_transition(task, LWS_TP_STATUS_SYNCING);
        while (tries--) {
-               wsi = task->args.wsi;
+               wsi = task_to_wsi(task);
 
                /*
                 * if the wsi is no longer attached to this task, there is
@@ -391,13 +426,13 @@ lws_threadpool_worker_sync(struct lws_pool *pool,
                }
 
                /*
-                * So tries times this is the maximum time between SYNC asking
+                * So "tries" times this is the maximum time between SYNC asking
                 * for a callback on writable and actually getting it we are
                 * willing to sit still for.
                 *
                 * If it is exceeded, we will stop the task.
                 */
-               abstime.tv_sec = time(NULL) + 2;
+               abstime.tv_sec = time(NULL) + 3;
                abstime.tv_nsec = 0;
 
                task->wanted_writeable_cb = 1;
@@ -423,12 +458,13 @@ lws_threadpool_worker_sync(struct lws_pool *pool,
                        task->late_sync_retries++;
                        if (!tries) {
                                lwsl_err("%s: %s: task %p (%s): SYNC timed out "
-                                        "(associated wsi %p)\n",
+                                        "(associated %s)\n",
                                         __func__, pool->tp->name, task,
-                                        task->name, task->args.wsi);
+                                        task->name, lws_wsi_tag(task_to_wsi(task)));
 
-                               state_transition(task, LWS_TP_STATUS_STOPPING);
-                               goto done;
+                               pthread_mutex_unlock(&pool->lock); /* ----------------- - pool unlock */
+                               lws_threadpool_dequeue_task(task);
+                               return 1; /* destroyed task */
                        }
 
                        continue;
@@ -447,6 +483,10 @@ done:
        return 0;
 }
 
+#if !defined(WIN32)
+static int dummy;
+#endif
+
 static void *
 lws_threadpool_worker(void *d)
 {
@@ -469,8 +509,8 @@ lws_threadpool_worker(void *d)
                        pthread_cond_wait(&tp->wake_idle, &tp->lock);
 
                if (tp->destroying) {
-                       pthread_mutex_unlock(&tp->lock);  /* ------ tp unlock */
-                       continue;
+                       lwsl_notice("%s: bailing\n", __func__);
+                       goto doneski;
                }
 
                c = &tp->task_queue_head;
@@ -541,13 +581,13 @@ lws_threadpool_worker(void *d)
                        lws_usec_t then;
                        int n;
 
-                       if (tp->destroying || !task->args.wsi) {
+                       if (tp->destroying || !task_to_wsi(task)) {
                                lwsl_info("%s: stopping on wsi gone\n", __func__);
                                state_transition(task, LWS_TP_STATUS_STOPPING);
                        }
 
                        then = lws_now_usecs();
-                       n = task->args.task(task->args.user, task->status);
+                       n = (int)task->args.task(task->args.user, task->status);
                        lwsl_debug("   %d, status %d\n", n, task->status);
                        us_accrue(&task->acc_running, then);
                        if (n & LWS_TP_RETURN_FLAG_OUTLIVE)
@@ -557,7 +597,7 @@ lws_threadpool_worker(void *d)
                                /* if not destroying the tp, continue */
                                break;
                        case LWS_TP_RETURN_SYNC:
-                               if (!task->args.wsi) {
+                               if (!task_to_wsi(task)) {
                                        lwsl_debug("%s: task that wants to "
                                                    "outlive lost wsi asked "
                                                    "to sync: bypassed\n",
@@ -566,7 +606,10 @@ lws_threadpool_worker(void *d)
                                }
                                /* block until writable acknowledges */
                                then = lws_now_usecs();
-                               lws_threadpool_worker_sync(pool, task);
+                               if (lws_threadpool_worker_sync(pool, task)) {
+                                       lwsl_notice("%s: Sync failed\n", __func__);
+                                       goto doneski;
+                               }
                                us_accrue(&task->acc_syncing, then);
                                break;
                        case LWS_TP_RETURN_FINISHED:
@@ -617,21 +660,25 @@ lws_threadpool_worker(void *d)
                        /* signal the associated wsi to take a fresh look at
                         * task status */
 
-                       if (pool->task->args.wsi) {
+                       if (task_to_wsi(pool->task)) {
                                task->wanted_writeable_cb = 1;
 
                                lws_cancel_service(
-                                       lws_get_context(pool->task->args.wsi));
+                                       lws_get_context(task_to_wsi(pool->task)));
                        }
                }
 
+doneski:
                pool->task = NULL;
                pthread_mutex_unlock(&tp->lock); /* --------------- tp unlock */
        }
 
-       /* threadpool is being destroyed */
+       lwsl_notice("%s: Exiting\n", __func__);
 
-       pthread_exit(NULL);
+       /* threadpool is being destroyed */
+#if !defined(WIN32)
+       pthread_exit(&dummy);
+#endif
 
        return NULL;
 }
@@ -645,12 +692,12 @@ lws_threadpool_create(struct lws_context *context,
        va_list ap;
        int n;
 
-       tp = lws_malloc(sizeof(*tp) + (sizeof(struct lws_pool) * args->threads),
+       tp = lws_malloc(sizeof(*tp) + (sizeof(struct lws_pool) * (unsigned int)args->threads),
                        "threadpool alloc");
        if (!tp)
                return NULL;
 
-       memset(tp, 0, sizeof(*tp) + (sizeof(struct lws_pool) * args->threads));
+       memset(tp, 0, sizeof(*tp) + (sizeof(struct lws_pool) * (unsigned int)args->threads));
        tp->pool_list = (struct lws_pool *)(tp + 1);
        tp->max_queue_depth = args->max_queue_depth;
 
@@ -718,9 +765,8 @@ lws_threadpool_finish(struct lws_threadpool *tp)
                c = &task->task_queue_next;
        }
 
-       pthread_mutex_unlock(&tp->lock); /* -------------------- tpool unlock */
-
        pthread_cond_broadcast(&tp->wake_idle);
+       pthread_mutex_unlock(&tp->lock); /* -------------------- tpool unlock */
 }
 
 void
@@ -734,8 +780,8 @@ lws_threadpool_destroy(struct lws_threadpool *tp)
        /* remove us from the context list of threadpools */
 
        lws_context_lock(tp->context, __func__);
-
        ptp = &tp->context->tp_list_head;
+
        while (*ptp) {
                if (*ptp == tp) {
                        *ptp = tp->tp_list;
@@ -746,27 +792,32 @@ lws_threadpool_destroy(struct lws_threadpool *tp)
 
        lws_context_unlock(tp->context);
 
+       /*
+        * Wake up the threadpool guys and tell them to exit
+        */
 
        pthread_mutex_lock(&tp->lock); /* ======================== tpool lock */
-
        tp->destroying = 1;
        pthread_cond_broadcast(&tp->wake_idle);
        pthread_mutex_unlock(&tp->lock); /* -------------------- tpool unlock */
 
        lws_threadpool_dump(tp);
 
+       lwsl_info("%s: waiting for threads to rejoin\n", __func__);
+#if defined(WIN32)
+       Sleep(1000);
+#endif
+
        for (n = 0; n < tp->threads_in_pool; n++) {
                task = tp->pool_list[n].task;
 
-               /* he could be sitting waiting for SYNC */
-
-               if (task != NULL)
-                       pthread_cond_broadcast(&task->wake_idle);
-
                pthread_join(tp->pool_list[n].thread, &retval);
                pthread_mutex_destroy(&tp->pool_list[n].lock);
        }
        lwsl_info("%s: all threadpools exited\n", __func__);
+#if defined(WIN32)
+       Sleep(1000);
+#endif
 
        task = tp->task_done_head;
        while (task) {
@@ -778,25 +829,21 @@ lws_threadpool_destroy(struct lws_threadpool *tp)
 
        pthread_mutex_destroy(&tp->lock);
 
+       memset(tp, 0xdd, sizeof(*tp));
        lws_free(tp);
 }
 
 /*
- * we want to stop and destroy the task and related priv.  The wsi may no
- * longer exist.
+ * We want to stop and destroy the tasks and related priv.
  */
 
 int
-lws_threadpool_dequeue(struct lws *wsi)
+lws_threadpool_dequeue_task(struct lws_threadpool_task *task)
 {
        struct lws_threadpool *tp;
-       struct lws_threadpool_task **c, *task;
+       struct lws_threadpool_task **c;
        int n;
 
-       task = wsi->tp_task;
-       if (!task)
-               return 0;
-
        tp = task->tp;
        pthread_mutex_lock(&tp->lock); /* ======================== tpool lock */
 
@@ -804,8 +851,11 @@ lws_threadpool_dequeue(struct lws *wsi)
 
                /* disconnect from wsi, and wsi from task */
 
-               wsi->tp_task = NULL;
+               lws_dll2_remove(&task->list);
                task->args.wsi = NULL;
+#if defined(LWS_WITH_SECURE_STREAMS)
+               task->args.ss = NULL;
+#endif
 
                goto bail;
        }
@@ -826,8 +876,8 @@ lws_threadpool_dequeue(struct lws *wsi)
                        tp->done_queue_depth++;
                        task->done = lws_now_usecs();
 
-                       lwsl_debug("%s: tp %p: removed queued task wsi %p\n",
-                                   __func__, tp, task->args.wsi);
+                       lwsl_debug("%s: tp %p: removed queued task %s\n",
+                                   __func__, tp, lws_wsi_tag(task_to_wsi(task)));
 
                        break;
                }
@@ -869,23 +919,30 @@ lws_threadpool_dequeue(struct lws *wsi)
 
                /* disconnect from wsi, and wsi from task */
 
-               task->args.wsi->tp_task = NULL;
+               lws_dll2_remove(&task->list);
                task->args.wsi = NULL;
+#if defined(LWS_WITH_SECURE_STREAMS)
+               task->args.ss = NULL;
+#endif
 
                pthread_mutex_unlock(&tp->pool_list[n].lock);
 
                lwsl_debug("%s: tp %p: request stop running task "
-                           "for wsi %p\n", __func__, tp, task->args.wsi);
+                           "for %s\n", __func__, tp,
+                           lws_wsi_tag(task_to_wsi(task)));
 
                break;
        }
 
        if (n == tp->threads_in_pool) {
                /* can't find it */
-               lwsl_notice("%s: tp %p: no task for wsi %p, decoupling\n",
-                           __func__, tp, task->args.wsi);
-               task->args.wsi->tp_task = NULL;
+               lwsl_notice("%s: tp %p: no task for %s, decoupling\n",
+                           __func__, tp, lws_wsi_tag(task_to_wsi(task)));
+               lws_dll2_remove(&task->list);
                task->args.wsi = NULL;
+#if defined(LWS_WITH_SECURE_STREAMS)
+               task->args.ss = NULL;
+#endif
        }
 
 bail:
@@ -894,6 +951,21 @@ bail:
        return 0;
 }
 
+int
+lws_threadpool_dequeue(struct lws *wsi) /* deprecated */
+{
+       struct lws_threadpool_task *task;
+
+       if (!wsi->tp_task_owner.count)
+               return 0;
+       assert(wsi->tp_task_owner.count != 1);
+
+       task = lws_container_of(wsi->tp_task_owner.head,
+                               struct lws_threadpool_task, list);
+
+       return lws_threadpool_dequeue_task(task);
+}
+
 struct lws_threadpool_task *
 lws_threadpool_enqueue(struct lws_threadpool *tp,
                       const struct lws_threadpool_task_args *args,
@@ -905,6 +977,10 @@ lws_threadpool_enqueue(struct lws_threadpool *tp,
        if (tp->destroying)
                return NULL;
 
+#if defined(LWS_WITH_SECURE_STREAMS)
+       assert(args->ss || args->wsi);
+#endif
+
        pthread_mutex_lock(&tp->lock); /* ======================== tpool lock */
 
        /*
@@ -951,11 +1027,16 @@ lws_threadpool_enqueue(struct lws_threadpool *tp,
         * whatever reason can clean up)
         */
 
-       args->wsi->tp_task = task;
+#if defined(LWS_WITH_SECURE_STREAMS)
+       if (args->ss)
+               lws_dll2_add_tail(&task->list, &args->ss->wsi->tp_task_owner);
+       else
+#endif
+               lws_dll2_add_tail(&task->list, &args->wsi->tp_task_owner);
 
-       lwsl_thread("%s: tp %s: enqueued task %p (%s) for wsi %p, depth %d\n",
-                   __func__, tp->name, task, task->name, args->wsi,
-                   tp->queue_depth);
+       lwsl_thread("%s: tp %s: enqueued task %p (%s) for %s, depth %d\n",
+                   __func__, tp->name, task, task->name,
+                   lws_wsi_tag(task_to_wsi(task)), tp->queue_depth);
 
        /* alert any idle thread there's something new on the task list */
 
@@ -971,29 +1052,26 @@ bail:
 /* this should be called from the service thread */
 
 enum lws_threadpool_task_status
-lws_threadpool_task_status_wsi(struct lws *wsi,
-                              struct lws_threadpool_task **task, void **user)
+lws_threadpool_task_status(struct lws_threadpool_task *task, void **user)
 {
        enum lws_threadpool_task_status status;
-       struct lws_threadpool *tp;
+       struct lws_threadpool *tp = task->tp;
 
-       *task = wsi->tp_task;
-       if (!*task)
-               return -1;
+       if (!tp)
+               return LWS_TP_STATUS_FINISHED;
 
-       tp = (*task)->tp;
-       *user = (*task)->args.user;
-       status = (*task)->status;
+       *user = task->args.user;
+       status = task->status;
 
        if (status == LWS_TP_STATUS_FINISHED ||
            status == LWS_TP_STATUS_STOPPED) {
                char buf[160];
 
                pthread_mutex_lock(&tp->lock); /* ================ tpool lock */
-               __lws_threadpool_task_dump(*task, buf, sizeof(buf));
+               __lws_threadpool_task_dump(task, buf, sizeof(buf));
                lwsl_thread("%s: %s: service thread REAPING: %s\n",
                            __func__, tp->name, buf);
-               __lws_threadpool_reap(*task);
+               __lws_threadpool_reap(task);
                lws_memory_barrier();
                pthread_mutex_unlock(&tp->lock); /* ------------ tpool unlock */
        }
@@ -1001,13 +1079,123 @@ lws_threadpool_task_status_wsi(struct lws *wsi,
        return status;
 }
 
+enum lws_threadpool_task_status
+lws_threadpool_task_status_noreap(struct lws_threadpool_task *task)
+{
+       return task->status;
+}
+
+enum lws_threadpool_task_status
+lws_threadpool_task_status_wsi(struct lws *wsi,
+                              struct lws_threadpool_task **_task, void **user)
+{
+       struct lws_threadpool_task *task;
+
+       if (!wsi->tp_task_owner.count) {
+               lwsl_notice("%s: wsi has no task, ~=FINISHED\n", __func__);
+               return LWS_TP_STATUS_FINISHED;
+       }
+
+       assert(wsi->tp_task_owner.count == 1); /* see deprecation docs in hdr */
+
+       task = lws_container_of(wsi->tp_task_owner.head,
+                               struct lws_threadpool_task, list);
+
+       *_task = task;
+
+       return lws_threadpool_task_status(task, user);
+}
+
 void
 lws_threadpool_task_sync(struct lws_threadpool_task *task, int stop)
 {
        lwsl_debug("%s\n", __func__);
+       if (!task)
+               return;
 
        if (stop)
                state_transition(task, LWS_TP_STATUS_STOPPING);
 
+       pthread_mutex_lock(&task->tp->lock);
        pthread_cond_signal(&task->wake_idle);
+       pthread_mutex_unlock(&task->tp->lock);
 }
+
+int
+lws_threadpool_foreach_task_wsi(struct lws *wsi, void *user,
+                               int (*cb)(struct lws_threadpool_task *task,
+                                         void *user))
+{
+       struct lws_threadpool_task *task1;
+
+       if (wsi->tp_task_owner.head == NULL)
+               return 0;
+
+       task1 = lws_container_of(wsi->tp_task_owner.head,
+                                struct lws_threadpool_task, list);
+
+       pthread_mutex_lock(&task1->tp->lock); /* ================ tpool lock */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  wsi->tp_task_owner.head) {
+               struct lws_threadpool_task *task = lws_container_of(d,
+                                       struct lws_threadpool_task, list);
+
+               if (cb(task, user)) {
+                       pthread_mutex_unlock(&task1->tp->lock); /* ------------ tpool unlock */
+                       return 1;
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       pthread_mutex_unlock(&task1->tp->lock); /* ------------ tpool unlock */
+
+       return 0;
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+int
+lws_threadpool_foreach_task_ss(struct lws_ss_handle *ss, void *user,
+                              int (*cb)(struct lws_threadpool_task *task,
+                                        void *user))
+{
+       if (!ss->wsi)
+               return 0;
+
+       return lws_threadpool_foreach_task_wsi(ss->wsi, user, cb);
+}
+#endif
+
+static int
+disassociate_wsi(struct lws_threadpool_task *task,
+                 void *user)
+{
+       task->args.wsi = NULL;
+       lws_dll2_remove(&task->list);
+
+       return 0;
+}
+
+void
+lws_threadpool_wsi_closing(struct lws *wsi)
+{
+       lws_threadpool_foreach_task_wsi(wsi, NULL, disassociate_wsi);
+}
+
+struct lws_threadpool_task *
+lws_threadpool_get_task_wsi(struct lws *wsi)
+{
+       if (wsi->tp_task_owner.head == NULL)
+               return NULL;
+
+       return lws_container_of(wsi->tp_task_owner.head,
+                                struct lws_threadpool_task, list);
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+struct lws_threadpool_task *
+lws_threadpool_get_task_ss(struct lws_ss_handle *ss)
+{
+       return lws_threadpool_get_task_wsi(ss->wsi);
+}
+#endif
diff --git a/lib/plat/esp32/esp32-fds.c b/lib/plat/esp32/esp32-fds.c
deleted file mode 100644 (file)
index a6fc86c..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * libwebsockets - lib/plat/lws-plat-esp32.c
- *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-void
-lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
-{
-       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-
-       pt->fds[pt->fds_count++].revents = 0;
-}
-
-void
-lws_plat_delete_socket_from_fds(struct lws_context *context,
-                                               struct lws *wsi, int m)
-{
-       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-
-       pt->fds_count--;
-}
-
-int
-lws_plat_change_pollfd(struct lws_context *context,
-                     struct lws *wsi, struct lws_pollfd *pfd)
-{
-       return 0;
-}
-
-int
-insert_wsi(const struct lws_context *context, struct lws *wsi)
-{
-    assert(context->lws_lookup[wsi->desc.sockfd -
-                               lws_plat_socket_offset()] == 0);
-
-    context->lws_lookup[wsi->desc.sockfd - \
-                      lws_plat_socket_offset()] = wsi;
-
-    return 0;
-}
\ No newline at end of file
diff --git a/lib/plat/esp32/esp32-helpers.c b/lib/plat/esp32/esp32-helpers.c
deleted file mode 100644 (file)
index 7ecaf6f..0000000
+++ /dev/null
@@ -1,1367 +0,0 @@
-/*
- * libwebsockets - lib/plat/lws-plat-esp32.c
- *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-#include "misc/romfs.h"
-#include <esp_ota_ops.h>
-#include <tcpip_adapter.h>
-#include <esp_image_format.h>
-#include <esp_task_wdt.h>
-#include "soc/ledc_reg.h"
-#include "driver/ledc.h"
-
-struct lws_esp32 lws_esp32 = {
-       .model = CONFIG_LWS_MODEL_NAME,
-       .serial = "unknown",
-};
-
-/*
- * Group AP / Station State
- */
-
-enum lws_gapss {
-       LWS_GAPSS_INITIAL,      /* just started up, init and move to
-                                * LWS_GAPSS_SCAN */
-       LWS_GAPSS_SCAN,         /*
-                                * Unconnected, scanning: AP known in one of the
-                                * config slots -> configure it, start timeout +
-                                * LWS_GAPSS_STAT, if no AP already up in same
-                                * group with lower MAC, after a random period
-                                * start up our AP (LWS_GAPSS_AP)
-                                */
-       LWS_GAPSS_AP,           /*
-                                * Trying to be the group AP... periodically do
-                                * a scan LWS_GAPSS_AP_SCAN, faster and then
-                                * slower
-                                        */
-       LWS_GAPSS_AP_SCAN,      /*
-                                * doing a scan while trying to be the group
-                                * AP... if we see a lower MAC being the AP for
-                                * the same group AP, abandon being an AP and
-                                * join that AP as a station
-                                */
-       LWS_GAPSS_STAT_GRP_AP,  /*
-                                * We have decided to join another group member
-                                * who is being the AP, as its MAC is lower than
-                                * ours.  This is a stable state, but we still
-                                * do periodic scans LWS_GAPSS_STAT_GRP_AP_SCAN
-                                * and will always prefer an AP configured in a
-                                * slot.
-                                */
-       LWS_GAPSS_STAT_GRP_AP_SCAN,
-                               /*
-                                * We have joined a group member who is doing
-                                * the AP job... we want to check every now and
-                                * then if a configured AP has appeared that we
-                                * should better use instead.  Otherwise stay in
-                                * LWS_GAPSS_STAT_GRP_AP
-                                */
-       LWS_GAPSS_STAT,         /*
-                                * trying to connect to another non-group AP.
-                                * If we don't get an IP within a timeout and
-                                * retries, blacklist it and go back
-                                */
-       LWS_GAPSS_STAT_HAPPY,
-};
-
-static const char *gapss_str[] = {
-       "LWS_GAPSS_INITIAL",
-        "LWS_GAPSS_SCAN",
-        "LWS_GAPSS_AP",
-        "LWS_GAPSS_AP_SCAN",
-        "LWS_GAPSS_STAT_GRP_AP",
-        "LWS_GAPSS_STAT_GRP_AP_SCAN",
-        "LWS_GAPSS_STAT",
-       "LWS_GAPSS_STAT_HAPPY",
-};
-
-static romfs_t lws_esp32_romfs;
-static TimerHandle_t leds_timer, scan_timer, debounce_timer, association_timer
-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
-, mdns_timer
-#endif
-;
-static enum lws_gapss gapss = LWS_GAPSS_INITIAL;
-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
-static mdns_result_t *mdns_results_head;
-#endif
-
-#define GPIO_SW 14
-
-struct esp32_file {
-       const struct inode *i;
-};
-
-static void lws_gapss_to(enum lws_gapss to)
-{
-       lwsl_notice("gapss from %s to %s\n", gapss_str[gapss], gapss_str[to]);
-       gapss = to;
-}
-
-uint32_t lws_esp32_get_reboot_type(void)
-{
-       uint32_t *p = (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS, val = *p;
-       nvs_handle nvh;
-       size_t s = 0;
-       int n = 0;
-
-       ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
-       if (nvs_get_blob(nvh, "ssl-pub.pem", NULL, &s) == ESP_OK)
-               n = 1;
-       if (nvs_get_blob(nvh, "ssl-pri.pem", NULL, &s) == ESP_OK)
-               n |= 2;
-       nvs_close(nvh);
-
-       /*
-        * in the case the SSL certs are not there, don't require
-        * the button to be down to access all features.
-        */
-       if (n != 3)
-               val = LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON;
-
-       return val;
-}
-
-static void render_ip(char *dest, int len, uint8_t *ip)
-{
-       snprintf(dest, len, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
-}
-
-void lws_esp32_restart_guided(uint32_t type)
-{
-        uint32_t *p_force_factory_magic = (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;
-
-       lwsl_notice("%s: %x\n", __func__, type);
-        *p_force_factory_magic = type;
-
-       esp_restart();
-}
-
-/*
- * esp-idf goes crazy with zero length str nvs.  Use this as a workaround
- * to delete the key in that case.
- */
-
-esp_err_t lws_nvs_set_str(nvs_handle handle, const char* key, const char* value)
-{
-       if (*value)
-               return nvs_set_str(handle, key, value);
-
-       return nvs_erase_key(handle, key);
-}
-
-static wifi_scan_config_t scan_config = {
-        .ssid = 0,
-        .bssid = 0,
-        .channel = 0,
-        .show_hidden = true
-};
-
-static char scan_ongoing = 0, scan_timer_exists = 0;
-static int try_slot = -1;
-
-static wifi_config_t config = {
-       .ap = {
-           .channel = 6,
-           .authmode = WIFI_AUTH_OPEN,
-           .max_connection = 1,
-       } }, sta_config = {
-       .sta = {
-               .bssid_set = 0,
-       } };
-
-static void lws_esp32_scan_timer_cb(TimerHandle_t th)
-{
-       int n;
-
-       lwsl_notice("%s\n", __func__);
-       scan_ongoing = 0;
-       n = esp_wifi_scan_start(&scan_config, false);
-       if (n != ESP_OK)
-               lwsl_err("scan start failed %d\n", n);
-}
-
-static void lws_esp32_assoc_timer_cb(TimerHandle_t th)
-{
-       int n;
-
-       xTimerStop(association_timer, 0);
-
-       if (gapss == LWS_GAPSS_STAT_HAPPY) {
-               lwsl_debug("%s: saw we were happy\n", __func__);
-
-               return;
-       }
-
-       lwsl_notice("%s: forcing rescan\n", __func__);
-
-       lws_gapss_to(LWS_GAPSS_SCAN);
-       scan_ongoing = 0;
-       n = esp_wifi_scan_start(&scan_config, false);
-       if (n != ESP_OK)
-               lwsl_err("scan start failed %d\n", n);
-}
-
-
-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
-
-void __attribute__(( weak ))
-lws_group_member_event(int e, void *p)
-{
-}
-
-void __attribute__(( weak ))
-lws_get_iframe_size(int *w, int *h)
-{
-       *w = 320;
-       *h = 160;
-}
-
-void lws_group_member_event_call(int e, void *p)
-{
-       lws_group_member_event(e, p);
-}
-
-static int
-get_txt_param(const mdns_result_t *mr, const char *param, char *result, int len)
-{
-       const char *p;
-
-       *result = '\0';
-
-       p = strstr(mr->txt->key, param);
-       if (!p) {
-               *result = '\0';
-               return 1;
-       }
-
-       lws_strncpy(result, mr->txt->value, len);
-
-       return 0;
-}
-
-static void lws_esp32_mdns_timer_cb(TimerHandle_t th)
-{
-       uint64_t now = lws_now_usecs();
-       struct lws_group_member *p, **p1;
-       const mdns_result_t *r = mdns_results_head;
-
-       while (r) {
-               char ch = 0, group[16];
-
-               get_txt_param(r, "group", group, sizeof(group));
-               if (strcmp(group, lws_esp32.group)) /* not our group */ {
-                       lwsl_notice("group %s vs %s  %s\n",
-                                       group, lws_esp32.group, r->txt->value);
-                       continue;
-               }
-
-               p = lws_esp32.first;
-               while (p) {
-                       if (strcmp(r->hostname, p->host))
-                               goto next;
-                       if (memcmp(&r->addr, &p->addr, sizeof(r->addr)))
-                               goto next;
-
-                       p->last_seen = now;
-                       break;
-next:
-                       p = p->next;
-               }
-               if (!p) { /* did not find */
-                       char temp[8];
-
-                       p = lws_malloc(sizeof(*p), "group");
-                       if (!p)
-                               continue;
-                       lws_strncpy(p->host, r->hostname, sizeof(p->host));
-
-                       get_txt_param(r, "model", p->model, sizeof(p->model));
-                       get_txt_param(r, "role", p->role, sizeof(p->role));
-                       get_txt_param(r, "mac", p->mac, sizeof(p->mac));
-                       get_txt_param(r, "width", temp, sizeof(temp));
-                       p->width = atoi(temp);
-                       get_txt_param(r, "height", temp, sizeof(temp));
-                       p->height = atoi(temp);
-
-                       memcpy(&p->addr, &r->addr, sizeof(p->addr));
-//                     memcpy(&p->addrv6, &r->addrv6, sizeof(p->addrv6));
-                       p->last_seen = now;
-                       p->flags = 0;
-                       p->next = lws_esp32.first;
-                       lws_esp32.first = p;
-                       lws_esp32.extant_group_members++;
-
-                       lws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_ADD, p);
-               } else {
-                       if (memcmp(&p->addr, &r->addr, sizeof(p->addr))) {
-                               memcpy(&p->addr, &r->addr, sizeof(p->addr));
-                               ch = 1;
-                       }
-/*                     if (memcmp(&p->addrv6, &r->addrv6, sizeof(p->addrv6))) {
-                               memcpy(&p->addrv6, &r->addrv6, sizeof(p->addrv6));
-                               ch = 1;
-                       } */
-                       if (ch)
-                               lws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_CHANGE, p);
-               }
-       }
-
-       mdns_query_results_free(mdns_results_head);
-
-       /* garbage-collect group members not seen for too long */
-       p1 = &lws_esp32.first;
-       while (*p1) {
-               p = *p1;
-               if (!(p->flags & LWS_GROUP_FLAG_SELF) &&
-                               now - p->last_seen > 60000000) {
-                       lws_esp32.extant_group_members--;
-                       *p1 = p->next;
-
-                       lws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_REMOVE, p);
-                       lws_free(p);
-                       continue;
-               }
-               p1 = &(*p1)->next;
-       }
-
-       mdns_query_txt(lws_esp32.group, "_lwsgrmem", "_tcp", 0,
-                              &mdns_results_head);
-       xTimerStart(mdns_timer, 0);
-}
-#endif
-
-void __attribute__(( weak ))
-lws_esp32_button(int down)
-{
-}
-
-void IRAM_ATTR
-gpio_irq(void *arg)
-{
-       gpio_set_intr_type(GPIO_SW, GPIO_INTR_DISABLE);
-       xTimerStart(debounce_timer, 0);
-}
-
-static void lws_esp32_debounce_timer_cb(TimerHandle_t th)
-{
-       if (lws_esp32.button_is_down)
-               gpio_set_intr_type(GPIO_SW, GPIO_INTR_POSEDGE);
-       else
-               gpio_set_intr_type(GPIO_SW, GPIO_INTR_NEGEDGE);
-
-       lws_esp32.button_is_down = gpio_get_level(GPIO_SW);
-
-       lws_esp32_button(lws_esp32.button_is_down);
-}
-
-
-static int
-start_scan()
-{
-       /* if no APs configured, no point... */
-
-       if (!lws_esp32.ssid[0][0] &&
-           !lws_esp32.ssid[1][0] &&
-           !lws_esp32.ssid[2][0] &&
-           !lws_esp32.ssid[3][0])
-               return 0;
-
-       if (scan_timer_exists && !scan_ongoing) {
-               // lwsl_notice("Starting scan timer...\n");
-               scan_ongoing = 1;
-               xTimerStart(scan_timer, 0);
-       }
-
-       return 0;
-}
-
-
-
-static void
-end_scan()
-{
-       wifi_ap_record_t ap_records[10];
-       uint16_t count_ap_records;
-       int n, m;
-
-       count_ap_records = LWS_ARRAY_SIZE(ap_records);
-       if (esp_wifi_scan_get_ap_records(&count_ap_records, ap_records)) {
-               lwsl_err("%s: failed\n", __func__);
-               return;
-       }
-
-       if (!count_ap_records)
-               goto passthru;
-
-       if (gapss != LWS_GAPSS_SCAN) {
-               lwsl_info("ignoring scan as gapss %s\n", gapss_str[gapss]);
-               goto passthru;
-       }
-
-       /* no point if no APs set up */
-       if (!lws_esp32.ssid[0][0] &&
-           !lws_esp32.ssid[1][0] &&
-           !lws_esp32.ssid[2][0] &&
-           !lws_esp32.ssid[3][0])
-               goto passthru;
-
-       lwsl_info("checking %d scan records\n", count_ap_records);
-
-       for (n = 0; n < 4; n++) {
-
-               if (!lws_esp32.ssid[(n + try_slot + 1) & 3][0])
-                       continue;
-
-               lwsl_debug("looking for %s\n",
-                           lws_esp32.ssid[(n + try_slot + 1) & 3]);
-
-               /* this ssid appears in scan results? */
-
-               for (m = 0; m < count_ap_records; m++) {
-                       // lwsl_notice("  %s\n", ap_records[m].ssid);
-                       if (!strcmp((char *)ap_records[m].ssid,
-                                   lws_esp32.ssid[(n + try_slot + 1) & 3]))
-                               goto hit;
-               }
-
-               continue;
-
-hit:
-               m = (n + try_slot + 1) & 3;
-               try_slot = m;
-               lwsl_info("Attempting connection with slot %d: %s:\n", m,
-                               lws_esp32.ssid[m]);
-               /* set the ssid we last tried to connect to */
-               lws_strncpy(lws_esp32.active_ssid, lws_esp32.ssid[m],
-                               sizeof(lws_esp32.active_ssid));
-
-               lws_strncpy((char *)sta_config.sta.ssid, lws_esp32.ssid[m],
-                       sizeof(sta_config.sta.ssid));
-               lws_strncpy((char *)sta_config.sta.password, lws_esp32.password[m],
-                       sizeof(sta_config.sta.password));
-
-               tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA,
-                                          (const char *)&config.ap.ssid[7]);
-               lws_gapss_to(LWS_GAPSS_STAT);
-               xTimerStop(association_timer, 0);
-               xTimerStart(association_timer, 0);
-
-               esp_wifi_set_config(WIFI_IF_STA, &sta_config);
-               esp_wifi_connect();
-               break;
-       }
-
-       if (n == 4)
-               start_scan();
-
-passthru:
-       if (lws_esp32.scan_consumer)
-               lws_esp32.scan_consumer(count_ap_records, ap_records,
-                                       lws_esp32.scan_consumer_arg);
-
-}
-
-static void
-lws_set_genled(int n)
-{
-       lws_esp32.genled_t = lws_now_usecs();
-       lws_esp32.genled = n;
-}
-
-int
-lws_esp32_leds_network_indication(void)
-{
-       uint64_t us, r;
-       int n, fadein = 100, speed = 1199, div = 1, base = 0;
-
-       r = lws_now_usecs();
-       us = r - lws_esp32.genled_t;
-
-       switch (lws_esp32.genled) {
-       case LWSESP32_GENLED__INIT:
-               lws_esp32.genled = LWSESP32_GENLED__LOST_NETWORK;
-               /* fallthru */
-       case LWSESP32_GENLED__LOST_NETWORK:
-               fadein = us / 10000; /* 100 steps in 1s */
-               if (fadein > 100) {
-                       fadein = 100;
-                       lws_esp32.genled = LWSESP32_GENLED__NO_NETWORK;
-               }
-               /* fallthru */
-       case LWSESP32_GENLED__NO_NETWORK:
-               break;
-       case LWSESP32_GENLED__CONN_AP:
-               base = 4096;
-               speed = 933;
-               div = 2;
-               break;
-       case LWSESP32_GENLED__GOT_IP:
-               fadein = us / 10000; /* 100 steps in 1s */
-               if (fadein > 100) {
-                       fadein = 100;
-                       lws_esp32.genled = LWSESP32_GENLED__OK;
-               }
-               fadein = 100 - fadein; /* we are fading out */
-               /* fallthru */
-       case LWSESP32_GENLED__OK:
-               if (lws_esp32.genled == LWSESP32_GENLED__OK)
-                       return 0;
-
-               base = 4096;
-               speed = 766;
-               div = 3;
-               break;
-       }
-
-       n = base + (lws_esp32_sine_interp(r / speed) / div);
-       return (n * fadein) / 100;
-}
-
-esp_err_t lws_esp32_event_passthru(void *ctx, system_event_t *event)
-{
-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
-       struct lws_group_member *mem;
-       int n;
-#endif
-       nvs_handle nvh;
-       uint32_t use;
-
-       switch((int)event->event_id) {
-       case SYSTEM_EVENT_STA_START:
-               //esp_wifi_connect();
-//             break;
-               /* fallthru */
-       case SYSTEM_EVENT_STA_DISCONNECTED:
-               lwsl_notice("SYSTEM_EVENT_STA_DISCONNECTED\n");
-               if (sntp_enabled())
-                       sntp_stop();
-               lws_esp32.conn_ap = 0;
-               lws_esp32.inet = 0;
-               lws_esp32.sta_ip[0] = '\0';
-               lws_esp32.sta_mask[0] = '\0';
-               lws_esp32.sta_gw[0] = '\0';
-               lws_gapss_to(LWS_GAPSS_SCAN);
-               mdns_free();
-               lws_set_genled(LWSESP32_GENLED__LOST_NETWORK);
-               start_scan();
-               esp_wifi_connect();
-               break;
-
-       case SYSTEM_EVENT_STA_CONNECTED:
-               lws_esp32.conn_ap = 1;
-               lws_set_genled(LWSESP32_GENLED__CONN_AP);
-               break;
-
-       case SYSTEM_EVENT_STA_GOT_IP:
-               lwsl_notice("SYSTEM_EVENT_STA_GOT_IP\n");
-
-               lws_esp32.inet = 1;
-               lws_set_genled(LWSESP32_GENLED__GOT_IP);
-
-               render_ip(lws_esp32.sta_ip, sizeof(lws_esp32.sta_ip) - 1,
-                               (uint8_t *)&event->event_info.got_ip.ip_info.ip);
-               render_ip(lws_esp32.sta_mask, sizeof(lws_esp32.sta_mask) - 1,
-                               (uint8_t *)&event->event_info.got_ip.ip_info.netmask);
-               render_ip(lws_esp32.sta_gw, sizeof(lws_esp32.sta_gw) - 1,
-                               (uint8_t *)&event->event_info.got_ip.ip_info.gw);
-
-               if (!nvs_open("lws-station", NVS_READWRITE, &nvh)) {
-                       char slot[8];
-
-                       lws_snprintf(slot, sizeof(slot) - 1, "%duse", try_slot);
-                       use = 0;
-                       nvs_get_u32(nvh, slot, &use);
-                       nvs_set_u32(nvh, slot, use + 1);
-                       nvs_commit(nvh);
-                       nvs_close(nvh);
-               }
-
-               lws_gapss_to(LWS_GAPSS_STAT_HAPPY);
-
-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
-               n = mdns_init();
-               if (!n) {
-                       static mdns_txt_item_t txta[6];
-                       static char wh[2][6];
-                       int w, h;
-
-                       mdns_hostname_set(lws_esp32.hostname);
-                       mdns_instance_name_set(lws_esp32.group);
-
-                       lws_get_iframe_size(&w, &h);
-
-                       txta[0].key = "model";
-                       txta[1].key = "group";
-                       txta[2].key = "role";
-                       txta[3].key = "mac";
-                       txta[4].key = "width";
-                       txta[5].key = "height";
-
-                       txta[0].value = lws_esp32.model;
-                       txta[1].value = lws_esp32.group;
-                       txta[2].value = lws_esp32.role;
-                       txta[3].value = lws_esp32.mac;
-                       txta[4].value = wh[0];
-                       txta[5].value = wh[1];
-
-                       lws_snprintf(wh[0], 6, "%d", w);
-                       lws_snprintf(wh[1], 6, "%d", h);
-
-                       mdns_service_add(lws_esp32.group,
-                                        "_lwsgrmem", "_tcp", 443, txta,
-                                        LWS_ARRAY_SIZE(txta));
-
-                       mem = lws_esp32.first;
-                       while (mem) {
-                               if (mem->flags & 1)
-                                       break;
-                               mem = mem->next;
-                       }
-
-                       if (!mem) {
-                               struct lws_group_member *mem =
-                                             lws_malloc(sizeof(*mem), "group");
-                               if (mem) {
-                                       mem->last_seen = ~(uint64_t)0;
-                                       strcpy(mem->model, lws_esp32.model);
-                                       strcpy(mem->role, lws_esp32.role);
-                                       strcpy(mem->host, lws_esp32.hostname);
-                                       strcpy(mem->mac, lws_esp32.mac);
-                                       mem->flags = LWS_GROUP_FLAG_SELF;
-                                       lws_get_iframe_size(&mem->width,
-                                                           &mem->height);
-                                       memcpy(&mem->addr,
-                                              &event->event_info.got_ip.ip_info.ip,
-                                              sizeof(mem->addr));
-                                       memcpy(&mem->addrv6,
-                                              &event->event_info.got_ip6.ip6_info.ip,
-                                              sizeof(mem->addrv6));
-                                       mem->next = lws_esp32.first;
-                                       lws_esp32.first = mem;
-                                       lws_esp32.extant_group_members++;
-
-                                       lws_group_member_event_call(
-                                             LWS_SYSTEM_GROUP_MEMBER_ADD, mem);
-                               }
-                       } else { /* update our IP */
-                               memcpy(&mem->addr,
-                                      &event->event_info.got_ip.ip_info.ip,
-                                      sizeof(mem->addr));
-                               memcpy(&mem->addrv6,
-                                      &event->event_info.got_ip6.ip6_info.ip,
-                                      sizeof(mem->addrv6));
-                               lws_group_member_event_call(
-                                          LWS_SYSTEM_GROUP_MEMBER_CHANGE, mem);
-                       }
-
-               } else
-                       lwsl_err("unable to init mdns on STA: %d\n", n);
-
-               mdns_query_txt(lws_esp32.group, "_lwsgrmem", "_tcp", 0,
-                              &mdns_results_head);
-               xTimerStart(mdns_timer, 0);
-#endif
-
-               lwsl_notice(" --- Got IP %s\n", lws_esp32.sta_ip);
-               if (!sntp_enabled()) {
-                       sntp_setoperatingmode(SNTP_OPMODE_POLL);
-                       sntp_setservername(0, "pool.ntp.org");
-                       sntp_init();
-               }
-               break;
-
-       case SYSTEM_EVENT_SCAN_DONE:
-               lwsl_notice("SYSTEM_EVENT_SCAN_DONE\n");
-               end_scan();
-               break;
-
-       default:
-               break;
-       }
-
-       return ESP_OK;
-}
-
-static lws_fop_fd_t IRAM_ATTR
-esp32_lws_fops_open(const struct lws_plat_file_ops *fops, const char *filename,
-                    const char *vfs_path, lws_fop_flags_t *flags)
-{
-       struct esp32_file *f = malloc(sizeof(*f));
-       lws_fop_fd_t fop_fd;
-       size_t len, csum;
-
-       lwsl_notice("%s: %s\n", __func__, filename);
-
-       if (!f)
-               return NULL;
-       f->i = romfs_get_info(lws_esp32_romfs, filename, &len, &csum);
-       if (!f->i)
-               goto bail;
-
-        fop_fd = malloc(sizeof(*fop_fd));
-        if (!fop_fd)
-                goto bail;
-
-        fop_fd->fops = fops;
-        fop_fd->filesystem_priv = f;
-       fop_fd->mod_time = csum;
-       *flags |= LWS_FOP_FLAG_MOD_TIME_VALID;
-       fop_fd->flags = *flags;
-
-       fop_fd->len = len;
-       fop_fd->pos = 0;
-
-       return fop_fd;
-
-bail:
-       free(f);
-
-       return NULL;
-}
-
-static int IRAM_ATTR
-esp32_lws_fops_close(lws_fop_fd_t *fop_fd)
-{
-       free((*fop_fd)->filesystem_priv);
-       free(*fop_fd);
-
-       *fop_fd = NULL;
-
-       return 0;
-}
-static lws_fileofs_t IRAM_ATTR
-esp32_lws_fops_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset_from_cur_pos)
-{
-       fop_fd->pos += offset_from_cur_pos;
-
-       if (fop_fd->pos > fop_fd->len)
-               fop_fd->pos = fop_fd->len;
-
-       return 0;
-}
-
-static int IRAM_ATTR
-esp32_lws_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount, uint8_t *buf,
-                   lws_filepos_t len)
-{
-       struct esp32_file *f = fop_fd->filesystem_priv;
-#if 0
-       if ((long)buf & 3) {
-               lwsl_err("misaligned buf\n");
-
-               return -1;
-       }
-#endif
-       if (fop_fd->pos >= fop_fd->len)
-               return 0;
-
-       if (len > fop_fd->len - fop_fd->pos)
-               len = fop_fd->len - fop_fd->pos;
-
-       spi_flash_read((uint32_t)(char *)f->i + fop_fd->pos, buf, len);
-
-       *amount = len;
-       fop_fd->pos += len;
-
-       return 0;
-}
-
-static const struct lws_plat_file_ops fops = {
-       .next = &fops_zip,
-       .LWS_FOP_OPEN = esp32_lws_fops_open,
-       .LWS_FOP_CLOSE = esp32_lws_fops_close,
-       .LWS_FOP_READ = esp32_lws_fops_read,
-       .LWS_FOP_SEEK_CUR = esp32_lws_fops_seek_cur,
-};
-
-int
-lws_esp32_wlan_nvs_get(int retry)
-{
-       nvs_handle nvh;
-       char lws_esp32_force_ap = 0, slot[12];
-       size_t s;
-       uint8_t mac[6];
-       int n;
-
-       esp_efuse_mac_get_default(mac);
-       mac[5] |= 1; /* match the AP MAC */
-       snprintf(lws_esp32.serial, sizeof(lws_esp32.serial) - 1,
-                "%02X%02X%02X", mac[3], mac[4], mac[5]);
-       snprintf(lws_esp32.mac, sizeof(lws_esp32.mac) - 1,
-                "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3],
-                mac[4], mac[5]);
-
-       ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
-
-       config.sta.ssid[0] = '\0';
-       config.sta.password[0] = '\0';
-
-       for (n = 0; n < 4; n++) {
-               lws_snprintf(slot, sizeof(slot) - 1, "%dssid", n);
-               s = sizeof(lws_esp32.ssid[0]) - 1;
-               lws_esp32.ssid[n][0] = '\0';
-               nvs_get_str(nvh, slot, lws_esp32.ssid[n], &s);
-
-               lws_snprintf(slot, sizeof(slot) - 1, "%dpassword", n);
-               s = sizeof(lws_esp32.password[0]) - 1;
-               lws_esp32.password[n][0] = '\0';
-               nvs_get_str(nvh, slot, lws_esp32.password[n], &s);
-       }
-
-       s = sizeof(lws_esp32.serial) - 1;
-       if (nvs_get_str(nvh, "serial", lws_esp32.serial, &s) != ESP_OK)
-               lws_esp32_force_ap = 1;
-       else
-               snprintf((char *)config.ap.ssid, sizeof(config.ap.ssid) - 1,
-                        "config-%s-%s", lws_esp32.model, lws_esp32.serial);
-       s = sizeof(lws_esp32.opts) - 1;
-       if (nvs_get_str(nvh, "opts", lws_esp32.opts, &s) != ESP_OK)
-               lws_esp32_force_ap = 1;
-
-       lws_esp32.access_pw[0] = '\0';
-       nvs_get_str(nvh, "access_pw", lws_esp32.access_pw, &s);
-
-       lws_esp32.group[0] = '\0';
-       s = sizeof(lws_esp32.group);
-       nvs_get_str(nvh, "group", lws_esp32.group, &s);
-
-       lws_esp32.role[0] = '\0';
-       s = sizeof(lws_esp32.role);
-       nvs_get_str(nvh, "role", lws_esp32.role, &s);
-
-       /* if group and role defined: group-role */
-       if (lws_esp32.group[0] && lws_esp32.role[0])
-               lws_snprintf(lws_esp32.hostname, sizeof(lws_esp32.hostname) - 1,
-                               "%s-%s", lws_esp32.group, lws_esp32.role);
-       else /* otherwise model-serial */
-               lws_snprintf(lws_esp32.hostname, sizeof(lws_esp32.hostname) - 1,
-                               "%s-%s", lws_esp32.model, lws_esp32.serial);
-
-       nvs_close(nvh);
-
-       lws_gapss_to(LWS_GAPSS_SCAN);
-       start_scan();
-
-       return lws_esp32_force_ap;
-}
-
-
-void
-lws_esp32_wlan_config(void)
-{
-       ledc_timer_config_t ledc_timer = {
-               .bit_num = LEDC_TIMER_13_BIT,
-               .freq_hz = 5000,
-               .speed_mode = LEDC_HIGH_SPEED_MODE,
-               .timer_num = LEDC_TIMER_0
-       };
-       int n;
-
-       lwsl_debug("%s\n", __func__);
-
-       ledc_timer_config(&ledc_timer);
-
-       lws_set_genled(LWSESP32_GENLED__INIT);
-
-       /* user code needs to provide lws_esp32_leds_timer_cb */
-
-        leds_timer = xTimerCreate("lws_leds", pdMS_TO_TICKS(25), 1, NULL,
-                          (TimerCallbackFunction_t)lws_esp32_leds_timer_cb);
-        scan_timer = xTimerCreate("lws_scan", pdMS_TO_TICKS(10000), 0, NULL,
-                          (TimerCallbackFunction_t)lws_esp32_scan_timer_cb);
-        debounce_timer = xTimerCreate("lws_db", pdMS_TO_TICKS(100), 0, NULL,
-                          (TimerCallbackFunction_t)lws_esp32_debounce_timer_cb);
-        association_timer = xTimerCreate("lws_assoc", pdMS_TO_TICKS(10000), 0, NULL,
-                          (TimerCallbackFunction_t)lws_esp32_assoc_timer_cb);
-
-#if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
-        mdns_timer = xTimerCreate("lws_mdns", pdMS_TO_TICKS(5000), 0, NULL,
-                          (TimerCallbackFunction_t)lws_esp32_mdns_timer_cb);
-#endif
-       scan_timer_exists = 1;
-        xTimerStart(leds_timer, 0);
-
-       *(volatile uint32_t *)PERIPHS_IO_MUX_MTMS_U = FUNC_MTMS_GPIO14;
-
-       gpio_output_set(0, 0, 0, (1 << GPIO_SW));
-
-       n = gpio_install_isr_service(0);
-       if (!n) {
-               gpio_config_t c;
-
-               c.intr_type = GPIO_INTR_NEGEDGE;
-               c.mode = GPIO_MODE_INPUT;
-               c.pin_bit_mask = 1 << GPIO_SW;
-               c.pull_down_en = 0;
-               c.pull_up_en = 0;
-               gpio_config(&c);
-
-               if (gpio_isr_handler_add(GPIO_SW, gpio_irq, NULL))
-                       lwsl_notice("isr handler add for 14 failed\n");
-       } else
-               lwsl_notice("failed to install gpio isr service: %d\n", n);
-
-       lws_esp32_wlan_nvs_get(0);
-       tcpip_adapter_init();
-}
-
-void
-lws_esp32_wlan_start_ap(void)
-{
-       wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
-
-       ESP_ERROR_CHECK( esp_wifi_init(&cfg));
-       ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));
-
-       ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_APSTA) );
-       ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_AP, &config) );
-       ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config));
-       ESP_ERROR_CHECK( esp_wifi_start());
-
-       esp_wifi_scan_start(&scan_config, false);
-
-       if (sta_config.sta.ssid[0]) {
-               tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA,
-                                          (const char *)&config.ap.ssid[7]);
-               // esp_wifi_set_auto_connect(1);
-               ESP_ERROR_CHECK( esp_wifi_connect());
-               ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config));
-               ESP_ERROR_CHECK( esp_wifi_connect());
-       }
-}
-
-void
-lws_esp32_wlan_start_station(void)
-{
-       wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
-
-       ESP_ERROR_CHECK( esp_wifi_init(&cfg));
-       ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));
-
-       ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA));
-       ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config));
-
-       ESP_ERROR_CHECK( esp_wifi_start());
-
-       tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA,
-                                  (const char *)&config.ap.ssid[7]);
-       //esp_wifi_set_auto_connect(1);
-       //ESP_ERROR_CHECK( esp_wifi_connect());
-
-       lws_esp32_scan_timer_cb(NULL);
-}
-
-const esp_partition_t *
-lws_esp_ota_get_boot_partition(void)
-{
-       const esp_partition_t *part = esp_ota_get_boot_partition(),
-                             *factory_part, *ota;
-       esp_image_header_t eih, ota_eih;
-       uint32_t *p_force_factory_magic = (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;
-
-       /* confirm what we are told is the boot part is sane */
-       spi_flash_read(part->address , &eih, sizeof(eih));
-       factory_part = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
-                       ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
-       ota = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
-                       ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL);
-       spi_flash_read(ota->address , &ota_eih, sizeof(ota_eih));
-
-       if (eih.spi_mode == 0xff ||
-           *p_force_factory_magic == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY ||
-           *p_force_factory_magic == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON
-       ) {
-               /*
-                * we believed we were going to boot OTA, but we fell
-                * back to FACTORY in the bootloader when we saw it
-                * had been erased.  esp_ota_get_boot_partition() still
-                * says the OTA partition then even if we are in the
-                * factory partition right now.
-                */
-               part = factory_part;
-       }
-
-#ifdef CONFIG_LWS_IS_FACTORY_APPLICATION
-       else
-               if (ota_eih.spi_mode != 0xff &&
-                   part->address != factory_part->address) {
-                       uint8_t buf[4096];
-                       uint32_t n;
-                       /*
-                        * we are a FACTORY image running in an OTA slot...
-                        * it means we were just written and need to copy
-                        * ourselves into the FACTORY slot.
-                        */
-                       lwsl_notice("Copying FACTORY update into place "
-                                   "0x%x len 0x%x\n", factory_part->address,
-                                   factory_part->size);
-                       esp_task_wdt_reset();
-                       if (spi_flash_erase_range(factory_part->address,
-                                                 factory_part->size)) {
-                               lwsl_err("spi: Failed to erase\n");
-                               goto retry;
-                       }
-
-                       for (n = 0; n < factory_part->size; n += sizeof(buf)) {
-                               esp_task_wdt_reset();
-                               spi_flash_read(part->address + n , buf,
-                                              sizeof(buf));
-                               if (spi_flash_write(factory_part->address + n,
-                                                   buf, sizeof(buf))) {
-                                       lwsl_err("spi: Failed to write\n");
-                                       goto retry;
-                               }
-                       }
-
-                       /*
-                        * We send a message to the bootloader to erase the OTA header, we will come back up in
-                        * factory where the user can reload the OTA image
-                        */
-                       lwsl_notice("  FACTORY copy successful, rebooting\n");
-                       lws_esp32_restart_guided(LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY_ERASE_OTA);
-retry:
-                       esp_restart();
-               }
-#endif
-
-       return part;
-}
-
-
-void
-lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)
-{
-       const esp_partition_t *part;
-
-       memset(info, 0, sizeof(*info));
-
-       lws_set_log_level(63, lwsl_emit_syslog);
-
-       part = lws_esp_ota_get_boot_partition();
-       (void)part;
-
-       info->vhost_name = "default";
-       info->port = 443;
-       info->fd_limit_per_thread = 16;
-       info->max_http_header_pool = 5;
-       info->max_http_header_data = 1024;
-       info->pt_serv_buf_size = 4096;
-       info->keepalive_timeout = 30;
-       info->timeout_secs = 30;
-       info->simultaneous_ssl_restriction = 2;
-       info->options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
-                       LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
-}
-
-int
-lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,
-                        char *json, int json_len)
-{
-       esp_image_segment_header_t eis;
-       esp_image_header_t eih;
-       uint32_t hdr;
-
-       spi_flash_read(part->address , &eih, sizeof(eih));
-       hdr = part->address + sizeof(eih);
-
-       if (eih.magic != ESP_IMAGE_HEADER_MAGIC) {
-               lwsl_notice("%s: bad image header magic\n", __func__);
-               return 1;
-       }
-
-       eis.data_len = 0;
-       while (eih.segment_count-- && eis.data_len != 0xffffffff) {
-               spi_flash_read(hdr, &eis, sizeof(eis));
-               hdr += sizeof(eis) + eis.data_len;
-       }
-       hdr += (~hdr & 15) + 1;
-
-       if (eih.hash_appended)
-               hdr += 0x20;
-
-//     lwsl_notice("romfs estimated at 0x%x\n", hdr);
-
-       i->romfs = hdr + 0x4;
-       spi_flash_read(hdr, &i->romfs_len, sizeof(i->romfs_len));
-       i->json = i->romfs + i->romfs_len + 4;
-       spi_flash_read(i->json - 4, &i->json_len, sizeof(i->json_len));
-
-       if (i->json_len < json_len - 1)
-               json_len = i->json_len;
-       spi_flash_read(i->json, json, json_len);
-       json[json_len] = '\0';
-
-       return 0;
-}
-
-static int
-_rngf(void *context, unsigned char *buf, size_t len)
-{
-       if ((size_t)lws_get_random(context, buf, len) == len)
-               return 0;
-
-       return -1;
-}
-
-int
-lws_esp32_selfsigned(struct lws_vhost *vhost)
-{
-       mbedtls_x509write_cert crt;
-       char subject[200];
-       mbedtls_pk_context mpk;
-       int buf_size = 4096, n;
-       uint8_t *buf = malloc(buf_size); /* malloc because given to user code */
-       mbedtls_mpi mpi;
-       nvs_handle nvh;
-       size_t s;
-
-       lwsl_notice("%s: %s\n", __func__, vhost->name);
-
-       if (!buf)
-               return -1;
-
-       if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
-               lwsl_notice("%s: can't open nvs\n", __func__);
-               free(buf);
-               return 1;
-       }
-
-       n = 0;
-       if (!nvs_get_blob(nvh, vhost->tls.alloc_cert_path, NULL, &s))
-               n |= 1;
-       if (!nvs_get_blob(nvh, vhost->tls.key_path, NULL, &s))
-               n |= 2;
-
-       nvs_close(nvh);
-       if (n == 3) {
-               lwsl_notice("%s: certs exist\n", __func__);
-               free(buf);
-               return 0; /* certs already exist */
-       }
-
-       lwsl_notice("%s: creating selfsigned initial certs\n", __func__);
-
-       mbedtls_x509write_crt_init(&crt);
-
-       mbedtls_pk_init(&mpk);
-       if (mbedtls_pk_setup(&mpk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))) {
-               lwsl_notice("%s: pk_setup failed\n", __func__);
-               goto fail;
-       }
-       lwsl_notice("%s: generating 2048-bit RSA keypair... "
-                   "this may take a minute or so...\n", __func__);
-       n = mbedtls_rsa_gen_key(mbedtls_pk_rsa(mpk), _rngf, vhost->context,
-                               2048, 65537);
-       if (n) {
-               lwsl_notice("%s: failed to generate keys\n", __func__);
-               goto fail1;
-       }
-       lwsl_notice("%s: keys done\n", __func__);
-
-       /* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
-
-       lws_snprintf(subject, sizeof(subject) - 1,
-                    "C=TW,ST=New Taipei City,L=Taipei,O=warmcat,CN=%s",
-                    lws_esp32.hostname);
-
-       if (mbedtls_x509write_crt_set_subject_name(&crt, subject)) {
-               lwsl_notice("set SN failed\n");
-               goto fail1;
-       }
-       mbedtls_x509write_crt_set_subject_key(&crt, &mpk);
-       if (mbedtls_x509write_crt_set_issuer_name(&crt, subject)) {
-               lwsl_notice("set IN failed\n");
-               goto fail1;
-       }
-       mbedtls_x509write_crt_set_issuer_key(&crt, &mpk);
-
-       lws_get_random(vhost->context, &n, sizeof(n));
-       lws_snprintf(subject, sizeof(subject), "%d", n);
-
-       mbedtls_mpi_init(&mpi);
-       mbedtls_mpi_read_string(&mpi, 10, subject);
-       mbedtls_x509write_crt_set_serial(&crt, &mpi);
-       mbedtls_mpi_free(&mpi);
-
-       mbedtls_x509write_crt_set_validity(&crt, "20171105235959",
-                                          "20491231235959");
-
-       mbedtls_x509write_crt_set_key_usage(&crt,
-                                           MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
-                                           MBEDTLS_X509_KU_KEY_ENCIPHERMENT);
-
-
-       mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);
-
-       n = mbedtls_x509write_crt_pem(&crt, buf, buf_size, _rngf,
-                                     vhost->context);
-       if (n < 0) {
-               lwsl_notice("%s: write crt der failed\n", __func__);
-               goto fail1;
-       }
-
-       lws_plat_write_cert(vhost, 0, 0, buf, strlen((const char *)buf));
-
-       if (mbedtls_pk_write_key_pem(&mpk, buf, buf_size)) {
-               lwsl_notice("write key pem failed\n");
-               goto fail1;
-       }
-
-       lws_plat_write_cert(vhost, 1, 0, buf, strlen((const char *)buf));
-
-       mbedtls_pk_free(&mpk);
-       mbedtls_x509write_crt_free(&crt);
-
-       lwsl_notice("%s: cert creation complete\n", __func__);
-
-       return n;
-
-fail1:
-       mbedtls_pk_free(&mpk);
-fail:
-       mbedtls_x509write_crt_free(&crt);
-       free(buf);
-
-       nvs_close(nvh);
-
-       return -1;
-}
-
-void
-lws_esp32_update_acme_info(void)
-{
-        int n;
-
-       n = lws_plat_read_file("acme-email", lws_esp32.le_email,
-                              sizeof(lws_esp32.le_email) - 1);
-       if (n >= 0)
-               lws_esp32.le_email[n] = '\0';
-
-       n = lws_plat_read_file("acme-cn", lws_esp32.le_dns,
-                              sizeof(lws_esp32.le_dns) - 1);
-       if (n >= 0)
-               lws_esp32.le_dns[n] = '\0';
-}
-
-struct lws_context *
-lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
-{
-       const esp_partition_t *part = lws_esp_ota_get_boot_partition();
-       struct lws_context *context;
-       struct lws_esp32_image i;
-       struct lws_vhost *vhost;
-       struct lws wsi;
-       char buf[512];
-
-       context = lws_create_context(info);
-       if (context == NULL) {
-               lwsl_err("Failed to create context\n");
-               return NULL;
-       }
-
-       lws_esp32_get_image_info(part, &i, buf, sizeof(buf) - 1);
-
-       lws_esp32_romfs = (romfs_t)i.romfs;
-       if (!romfs_mount_check(lws_esp32_romfs)) {
-               lwsl_err("mount error on ROMFS at %p 0x%x\n", lws_esp32_romfs,
-                        i.romfs);
-               return NULL;
-       }
-
-       lwsl_notice("ROMFS length %uKiB\n", i.romfs_len >> 10);
-
-       puts(buf);
-
-       /* set the lws vfs to use our romfs */
-
-       lws_set_fops(context, &fops);
-
-       info->options |= LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX |
-                        LWS_SERVER_OPTION_IGNORE_MISSING_CERT;
-
-       vhost = lws_create_vhost(context, info);
-       if (!vhost) {
-               lwsl_err("Failed to create vhost\n");
-               return NULL;
-       }
-
-       lws_esp32_update_acme_info();
-
-       lws_esp32_selfsigned(vhost);
-       wsi.context = vhost->context;
-       wsi.vhost = vhost;
-
-       lws_tls_server_certs_load(vhost, &wsi, info->ssl_cert_filepath,
-                       info->ssl_private_key_filepath, NULL, 0, NULL, 0);
-
-       lws_init_vhost_client_ssl(info, vhost);
-
-       if (pvh)
-               *pvh = vhost;
-
-       if (lws_protocol_init(context))
-               return NULL;
-
-       return context;
-}
-
-static const uint16_t sineq16[] = {
-        0x0000, 0x0191, 0x031e, 0x04a4, 0x061e, 0x0789, 0x08e2, 0x0a24,
-        0x0b4e, 0x0c5c, 0x0d4b, 0x0e1a, 0x0ec6, 0x0f4d, 0x0faf, 0x0fea,
-};
-
-static uint16_t sine_lu(int n)
-{
-        switch ((n >> 4) & 3) {
-        case 1:
-                return 4096 + sineq16[n & 15];
-        case 2:
-                return 4096 + sineq16[15 - (n & 15)];
-        case 3:
-                return 4096 - sineq16[n & 15];
-        default:
-                return  4096 - sineq16[15 - (n & 15)];
-        }
-}
-
-/* useful for sine led fade patterns */
-
-uint16_t lws_esp32_sine_interp(int n)
-{
-        /*
-         * 2: quadrant
-         * 4: table entry in quadrant
-         * 4: interp (LSB)
-         *
-         * total 10 bits / 1024 steps per cycle
-        *
-        * +   0: 0
-        * + 256: 4096
-        * + 512: 8192
-        * + 768: 4096
-        * +1023: 0
-         */
-
-        return (sine_lu(n >> 4) * (15 - (n & 15)) +
-                sine_lu((n >> 4) + 1) * (n & 15)) / 15;
-}
diff --git a/lib/plat/esp32/esp32-misc.c b/lib/plat/esp32/esp32-misc.c
deleted file mode 100644 (file)
index 65de064..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * libwebsockets - lib/plat/lws-plat-esp32.c
- *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-lws_usec_t
-lws_now_usecs(void)
-{
-       struct timeval tv;
-       gettimeofday(&tv, NULL);
-       return ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;
-}
-
-LWS_VISIBLE int
-lws_get_random(struct lws_context *context, void *buf, int len)
-{
-#if defined(LWS_AMAZON_RTOS)
-       int n;
-
-       n = mbedtls_ctr_drbg_random(&context->mcdc, buf, len);
-       if (!n)
-               return len;
-
-       /* failed */
-
-       lwsl_err("%s: mbedtls_ctr_drbg_random returned 0x%x\n", __func__, n);
-
-       return 0;
-#else
-       uint8_t *pb = buf;
-
-       while (len) {
-               uint32_t r = esp_random();
-               uint8_t *p = (uint8_t *)&r;
-               int b = 4;
-
-               if (len < b)
-                       b = len;
-
-               len -= b;
-
-               while (b--)
-                       *pb++ = p[b];
-       }
-
-       return pb - (uint8_t *)buf;
-#endif
-}
-
-
-LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
-{
-       lwsl_emit_stderr(level, line);
-}
-
-int
-lws_plat_drop_app_privileges(struct lws_context *context, int actually_init)
-{
-       return 0;
-}
-
-int
-lws_plat_recommended_rsa_bits(void)
-{
-       /*
-        * 2048-bit key generation takes up to a minute on ESP32, 4096
-        * is like 15 minutes +
-        */
-       return 2048;
-}
-
-void esp32_uvtimer_cb(TimerHandle_t t)
-{
-       struct timer_mapping *p = pvTimerGetTimerID(t);
-
-       p->cb(p->t);
-}
-
diff --git a/lib/plat/esp32/esp32-pipe.c b/lib/plat/esp32/esp32-pipe.c
deleted file mode 100644 (file)
index c8e11c8..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * libwebsockets - lib/plat/lws-plat-esp32.c
- *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-int
-lws_plat_pipe_create(struct lws *wsi)
-{
-       return 1;
-}
-
-int
-lws_plat_pipe_signal(struct lws *wsi)
-{
-       return 1;
-}
-
-void
-lws_plat_pipe_close(struct lws *wsi)
-{
-}
diff --git a/lib/plat/esp32/esp32-sockets.c b/lib/plat/esp32/esp32-sockets.c
deleted file mode 100644 (file)
index 80b50c8..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * libwebsockets - lib/plat/lws-plat-esp32.c
- *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-int
-lws_send_pipe_choked(struct lws *wsi)
-{
-       struct lws *wsi_eff = wsi;
-       fd_set writefds;
-       struct timeval tv = { 0, 0 };
-       int n;
-#if defined(LWS_WITH_HTTP2)
-       wsi_eff = lws_get_network_wsi(wsi);
-#endif
-
-       /* the fact we checked implies we avoided back-to-back writes */
-       wsi_eff->could_have_pending = 0;
-
-       /* treat the fact we got a truncated send pending as if we're choked */
-       if (lws_has_buffered_out(wsi)
-#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
-           || wsi->http.comp_ctx.buflist_comp ||
-              wsi->http.comp_ctx.may_have_more
-#endif
-       )
-               return 1;
-
-       FD_ZERO(&writefds);
-       FD_SET(wsi_eff->desc.sockfd, &writefds);
-
-       n = select(wsi_eff->desc.sockfd + 1, NULL, &writefds, NULL, &tv);
-       if (n < 0)
-               return 1; /* choked */
-
-       return !n; /* n = 0 = not writable = choked */
-}
-
-int
-lws_poll_listen_fd(struct lws_pollfd *fd)
-{
-       fd_set readfds;
-       struct timeval tv = { 0, 0 };
-
-       FD_ZERO(&readfds);
-       FD_SET(fd->fd, &readfds);
-
-       return select(fd->fd + 1, &readfds, NULL, NULL, &tv);
-}
-
-int
-lws_plat_check_connection_error(struct lws *wsi)
-{
-       return 0;
-}
-
-int
-lws_plat_set_nonblocking(int fd)
-{
-       return fcntl(fd, F_SETFL, O_NONBLOCK) < 0;
-}
-
-int
-lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
-{
-       int optval = 1;
-       socklen_t optlen = sizeof(optval);
-
-#if defined(__APPLE__) || \
-    defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
-    defined(__NetBSD__) || \
-    defined(__OpenBSD__)
-       struct protoent *tcp_proto;
-#endif
-
-       if (vhost->ka_time) {
-               /* enable keepalive on this socket */
-               optval = 1;
-               if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
-                              (const void *)&optval, optlen) < 0)
-                       return 1;
-
-#if defined(__APPLE__) || \
-    defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
-    defined(__NetBSD__) || \
-        defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun)
-
-               /*
-                * didn't find a way to set these per-socket, need to
-                * tune kernel systemwide values
-                */
-#else
-               /* set the keepalive conditions we want on it too */
-               optval = vhost->ka_time;
-               if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
-                              (const void *)&optval, optlen) < 0)
-                       return 1;
-
-               optval = vhost->ka_interval;
-               if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
-                              (const void *)&optval, optlen) < 0)
-                       return 1;
-
-               optval = vhost->ka_probes;
-               if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
-                              (const void *)&optval, optlen) < 0)
-                       return 1;
-#endif
-       }
-
-       /* Disable Nagle */
-       optval = 1;
-       if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, optlen) < 0)
-               return 1;
-
-       return lws_plat_set_nonblocking(fd);
-}
-
-/* cast a struct sockaddr_in6 * into addr for ipv6 */
-
-int
-lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
-                   size_t addrlen)
-{
-#if 0
-       int rc = LWS_ITOSA_NOT_EXIST;
-
-       struct ifaddrs *ifr;
-       struct ifaddrs *ifc;
-#ifdef LWS_WITH_IPV6
-       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
-#endif
-
-       getifaddrs(&ifr);
-       for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
-               if (!ifc->ifa_addr)
-                       continue;
-
-               lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
-
-               if (strcmp(ifc->ifa_name, ifname))
-                       continue;
-
-               switch (ifc->ifa_addr->sa_family) {
-               case AF_INET:
-#ifdef LWS_WITH_IPV6
-                       if (ipv6) {
-                               /* map IPv4 to IPv6 */
-                               memset((char *)&addr6->sin6_addr, 0,
-                                               sizeof(struct in6_addr));
-                               addr6->sin6_addr.s6_addr[10] = 0xff;
-                               addr6->sin6_addr.s6_addr[11] = 0xff;
-                               memcpy(&addr6->sin6_addr.s6_addr[12],
-                                       &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
-                                                       sizeof(struct in_addr));
-                       } else
-#endif
-                               memcpy(addr,
-                                       (struct sockaddr_in *)ifc->ifa_addr,
-                                                   sizeof(struct sockaddr_in));
-                       break;
-#ifdef LWS_WITH_IPV6
-               case AF_INET6:
-                       memcpy(&addr6->sin6_addr,
-                         &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
-                                                      sizeof(struct in6_addr));
-                       break;
-#endif
-               default:
-                       continue;
-               }
-               rc = LWS_ITOSA_USABLE;
-       }
-
-       freeifaddrs(ifr);
-
-       if (rc == LWS_ITOSA_NOT_EXIST) {
-               /* check if bind to IP address */
-#ifdef LWS_WITH_IPV6
-               if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
-                       rc = LWS_ITOSA_USABLE;
-               else
-#endif
-               if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
-                       rc = LWS_ITOSA_USABLE;
-       }
-
-       return rc;
-#endif
-
-       return LWS_ITOSA_NOT_EXIST;
-}
-
-const char *
-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
-{
-       return inet_ntop(af, src, dst, cnt);
-}
-
-int
-lws_plat_inet_pton(int af, const char *src, void *dst)
-{
-       return 1; //  inet_pton(af, src, dst);
-}
-
-
-
-
diff --git a/lib/plat/esp32/private.h b/lib/plat/esp32/private.h
deleted file mode 100644 (file)
index fa48c51..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  Included from lib/core/private.h if LWS_WITH_ESP32
- */
-
-#define MSG_NOSIGNAL 0
-#define SOMAXCONN 3
-
-#if defined(LWS_AMAZON_RTOS)
- int
- open(const char *path, int oflag, ...);
-#else
- #include <fcntl.h>
-#endif
-
- #include <strings.h>
- #include <unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <netdb.h>
-
- #ifndef __cplusplus
-  #include <errno.h>
- #endif
- #include <netdb.h>
- #include <signal.h>
-#if defined(LWS_AMAZON_RTOS)
-const char *
-gai_strerror(int);
-#else
- #include <sys/socket.h>
-#endif
-
-#if defined(LWS_AMAZON_RTOS)
- #include "FreeRTOS.h"
- #include "timers.h"
- #include <esp_attr.h>
-#else
- #include "freertos/timers.h"
- #include <esp_attr.h>
- #include <esp_system.h>
- #include <esp_task_wdt.h>
-#endif
-
-#include "lwip/apps/sntp.h"
-
-#include <lwip/sockets.h>
-
- #if defined(LWS_BUILTIN_GETIFADDRS)
-  #include "./misc/getifaddrs.h"
- #endif
-
- #define LWS_ERRNO errno
- #define LWS_EAGAIN EAGAIN
- #define LWS_EALREADY EALREADY
- #define LWS_EINPROGRESS EINPROGRESS
- #define LWS_EINTR EINTR
- #define LWS_EISCONN EISCONN
- #define LWS_ENOTCONN ENOTCONN
- #define LWS_EWOULDBLOCK EWOULDBLOCK
- #define LWS_EADDRINUSE EADDRINUSE
-
- #define lws_set_blocking_send(wsi)
-
- #ifndef LWS_NO_FORK
-  #ifdef LWS_HAVE_SYS_PRCTL_H
-   #include <sys/prctl.h>
-  #endif
- #endif
-
-#define compatible_close(x) close(x)
-#define lws_plat_socket_offset() LWIP_SOCKET_OFFSET
-#define wsi_from_fd(A,B)  A->lws_lookup[B - lws_plat_socket_offset()]
-
-struct lws_context;
-struct lws;
-
-int
-insert_wsi(const struct lws_context *context, struct lws *wsi);
-
-#define delete_from_fd(A,B) A->lws_lookup[B - lws_plat_socket_offset()] = 0
-
diff --git a/lib/plat/freertos/CMakeLists.txt b/lib/plat/freertos/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c0d92e9
--- /dev/null
@@ -0,0 +1,60 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(. esp32)
+
+list(APPEND SOURCES
+       plat/freertos/freertos-fds.c
+       plat/freertos/freertos-init.c
+       plat/freertos/freertos-misc.c
+       plat/freertos/freertos-pipe.c
+       plat/freertos/freertos-service.c
+       plat/freertos/freertos-sockets.c
+       misc/romfs.c)
+
+if (LWS_ESP_PLATFORM AND LWS_WITH_DRIVERS)
+       list(APPEND SOURCES plat/freertos/esp32/drivers/settings-esp32.c)
+       if (LWS_WITH_NETWORK)
+               list(APPEND SOURCES plat/freertos/esp32/drivers/netdev/wifi-esp32.c)
+       endif()
+endif()
+if (LWS_WITH_FILE_OPS)
+       list(APPEND SOURCES plat/freertos/freertos-file.c)
+endif()
+if (LWS_WITH_SYS_ASYNC_DNS OR LWS_WITH_SYS_NTPCLIENT)
+       list(APPEND SOURCES plat/freertos/freertos-resolv.c)
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
diff --git a/lib/plat/freertos/esp32/drivers/gpio-esp32.c b/lib/plat/freertos/esp32/drivers/gpio-esp32.c
new file mode 100644 (file)
index 0000000..163a140
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * esp32 / esp-idf gpio
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <libwebsockets.h>
+       
+static void
+lws_gpio_esp32_mode(_lws_plat_gpio_t gpio, int flags)
+{
+       int mode, pup = GPIO_FLOATING;
+
+       switch (flags & (LWSGGPIO_FL_READ | LWSGGPIO_FL_WRITE)) {
+       default:
+               lwsl_err("%s: neither read nor write\n", __func__);
+               return;
+       case LWSGGPIO_FL_READ:
+               mode = GPIO_MODE_INPUT;
+               break;
+       case LWSGGPIO_FL_WRITE:
+               mode = GPIO_MODE_OUTPUT;
+               break;
+       case LWSGGPIO_FL_READ | LWSGGPIO_FL_WRITE:
+               mode = GPIO_MODE_INPUT_OUTPUT;
+               break;
+       }
+
+       switch (flags & (LWSGGPIO_FL_PULLUP | LWSGGPIO_FL_PULLDOWN)) {
+       default:
+               break;
+       case LWSGGPIO_FL_PULLUP:
+               pup = GPIO_PULLUP_ONLY;
+               break;
+       case LWSGGPIO_FL_PULLDOWN:
+               pup = GPIO_PULLDOWN_ONLY;
+               break;
+       case LWSGGPIO_FL_PULLUP | LWSGGPIO_FL_PULLDOWN:
+               pup = GPIO_PULLUP_PULLDOWN;
+               break;
+       }
+
+       gpio_reset_pin(gpio);
+       gpio_set_direction(gpio, mode);
+       gpio_set_pull_mode(gpio, pup);
+       gpio_set_level(gpio, flags & LWSGGPIO_FL_START_LOW ? 0 : 1);
+}
+
+static int
+lws_gpio_esp32_read(_lws_plat_gpio_t gpio)
+{
+       return gpio_get_level(gpio);
+}
+static void
+lws_gpio_esp32_set(_lws_plat_gpio_t gpio, int val)
+{
+       gpio_set_level(gpio, val);
+}
+
+static int
+lws_gpio_esp32_irq_mode(_lws_plat_gpio_t gpio, lws_gpio_irq_t irq_type,
+                       lws_gpio_irq_cb_t cb, void *arg)
+{
+       if (gpio_set_intr_type(gpio, irq_type))
+               return 1;
+
+       if (cb)
+               return gpio_isr_handler_add(gpio, cb, arg);
+
+       return gpio_isr_handler_remove(gpio);
+}
+
+const lws_gpio_ops_t lws_gpio_plat = {
+       .mode                   = lws_gpio_esp32_mode,
+       .read                   = lws_gpio_esp32_read,
+       .set                    = lws_gpio_esp32_set,
+       .irq_mode               = lws_gpio_esp32_irq_mode,
+};
diff --git a/lib/plat/freertos/esp32/drivers/lws-plat-gpio.h b/lib/plat/freertos/esp32/drivers/lws-plat-gpio.h
new file mode 100644 (file)
index 0000000..257d13d
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * lws generic gpio - esp32 platform wrapper
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+extern const lws_gpio_ops_t lws_gpio_plat;
diff --git a/lib/plat/freertos/esp32/drivers/netdev/wifi-esp32.c b/lib/plat/freertos/esp32/drivers/netdev/wifi-esp32.c
new file mode 100644 (file)
index 0000000..c9300e0
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ * libwebsockets - esp32 wifi -> lws_netdev_wifi
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *
+ * These are the esp platform wifi-specific netdev pieces.  Nothing else should
+ * know any esp-specific apis.
+ *
+ * Operations happen via the generic lws_detdev instantiation for the platform
+ * wifi device, which point in here for operations.  We also set up native OS
+ * event hooks per device for wifi and IP stack events, and post them as lws_smd
+ * NETWORK events on the if in the "platform private" namespace.  We then
+ * service the events in the lws event loop thread context, which may again
+ * generate lws_smd NETWORK events in the public namespace depending on what
+ * happened.
+ *
+ * Scan requests go through a sul to make sure we don't get "piling on" from
+ * scheduled, timed scans.  Scan results go through the lws_smd "washing" and
+ * are actually parsed in lws thread context, where they are converted to lws
+ * netdev scan results and processed by generic code.
+ */
+
+#include "private-lib-core.h"
+
+#include "esp_system.h"
+#include "esp_spi_flash.h"
+#include "esp_wifi.h"
+#include <nvs_flash.h>
+#include <esp_netif.h>
+
+/*
+ * lws_netdev_instance_t:
+ *   lws_netdev_instance_wifi_t:
+ *     lws_netdev_instance_wifi_esp32_t
+ */
+
+typedef struct lws_netdev_instance_wifi_esp32 {
+       lws_netdev_instance_wifi_t              wnd;
+       esp_event_handler_instance_t            instance_any_id;
+       esp_event_handler_instance_t            instance_got_ip;
+       wifi_config_t                           sta_config;
+} lws_netdev_instance_wifi_esp32_t;
+
+/*
+static wifi_config_t config = {
+       .ap = {
+           .channel = 6,
+           .authmode = WIFI_AUTH_OPEN,
+           .max_connection = 1,
+       } };
+       */
+
+/*
+ * Platform-specific connect / associate
+ */
+
+int
+lws_netdev_wifi_connect_plat(lws_netdev_instance_t *nd, const char *ssid,
+                            const char *passphrase, uint8_t *bssid)
+{
+       lws_netdev_instance_wifi_esp32_t *wnde32 =
+                                       (lws_netdev_instance_wifi_esp32_t *)nd;
+
+       wnde32->wnd.inst.ops->up(&wnde32->wnd.inst);
+
+       wnde32->wnd.flags |= LNDIW_MODE_STA;
+       esp_wifi_set_mode(WIFI_MODE_STA);
+
+#if 0
+       /* we will do our own dhcp */
+       tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
+#endif
+
+       lws_strncpy((char *)wnde32->sta_config.sta.ssid, ssid,
+                   sizeof(wnde32->sta_config.sta.ssid));
+       lws_strncpy((char *)wnde32->sta_config.sta.password, passphrase,
+                   sizeof(wnde32->sta_config.sta.password));
+
+       esp_wifi_set_config(WIFI_IF_STA, &wnde32->sta_config);
+       esp_wifi_connect();
+
+       return 0;
+}
+
+/*
+ * This is called from the SMD / lws thread context, after we heard there were
+ * scan results on this netdev
+ */
+
+static void
+lws_esp32_scan_update(lws_netdev_instance_wifi_t *wnd)
+{
+//     lws_netdevs_t *netdevs = lws_netdevs_from_ndi(&wnd->inst);
+       wifi_ap_record_t ap_records[LWS_WIFI_MAX_SCAN_TRACK], *ar;
+       uint32_t now = lws_now_secs();
+       uint16_t count_ap_records;
+       int n;
+
+       count_ap_records = LWS_ARRAY_SIZE(ap_records);
+       if (esp_wifi_scan_get_ap_records(&count_ap_records, ap_records)) {
+               lwsl_err("%s: failed\n", __func__);
+               return;
+       }
+
+       if (!count_ap_records)
+               return;
+
+       if (wnd->state != LWSNDVWIFI_STATE_SCAN)
+               return;
+
+       /*
+        * ... let's collect the OS-specific scan results, and convert then to
+        * lws_netdev sorted by rssi.  If we already have it in the scan list,
+        * keep it and keep a little ringbuffer of its rssi along with an
+        * averaging.  If it's new, add it into the linked-list sorted by rssi.
+        */
+
+       ar = &ap_records[0];
+       for (n = 0; n < count_ap_records; n++) {
+               lws_wifi_sta_t *w;
+               int m;
+
+               m = strlen((const char *)ar->ssid);
+               if (!m)
+                       goto next;
+
+               /*
+                * We know this guy from before?
+                */
+
+               w = lws_netdev_wifi_scan_find(wnd, (const char *)ar->ssid,
+                                               ar->bssid);
+               if (!w) {
+                       w = lws_zalloc(sizeof(*w) + m + 1, __func__);
+                       if (!w)
+                               goto next;
+
+                       w->ssid = (char *)&w[1];
+                       memcpy(w->ssid, ar->ssid, m + 1);
+                       w->ssid_len = m;
+
+                       memcpy(w->bssid, ar->bssid, 6);
+
+                       lws_dll2_add_sorted(&w->list, &wnd->scan,
+                                           lws_netdev_wifi_rssi_sort_compare);
+               }
+
+               if (w->rssi_count == LWS_ARRAY_SIZE(w->rssi))
+                       w->rssi_avg -= w->rssi[w->rssi_next];
+               else
+                       w->rssi_count++;
+               w->rssi[w->rssi_next] = ar->rssi;
+               w->rssi_avg += w->rssi[w->rssi_next++];
+               w->rssi_next = w->rssi_next & (LWS_ARRAY_SIZE(w->rssi) - 1);
+
+               w->ch = ar->primary;
+               w->authmode = ar->authmode;
+               w->last_seen = now;
+
+next:
+               ar++;
+       }
+
+       /*
+        * We can do the rest of it using the generic scan list and credentials
+        */
+
+       lws_netdev_wifi_scan_select(wnd);
+}
+
+static wifi_scan_config_t scan_config = {
+        .ssid = 0,
+        .bssid = 0,
+        .channel = 0,
+        .show_hidden = true
+};
+
+void
+lws_netdev_wifi_scan_plat(lws_netdev_instance_t *nd)
+{
+       lws_netdev_instance_wifi_t *wnd = (lws_netdev_instance_wifi_t *)nd;
+
+       if (esp_wifi_scan_start(&scan_config, false))
+               lwsl_err("%s: %s scan failed\n", __func__, wnd->inst.name);
+}
+
+/*
+ * Platform-private interface events turn up here after going through SMD and
+ * passed down by matching network interface name via generic lws_netdev.  All
+ * that messing around gets us from an OS-specific thread with an event to back
+ * here in lws event loop thread context, with the same event bound to a the
+ * netdev it belongs to.
+ */
+
+int
+lws_netdev_wifi_event_plat(struct lws_netdev_instance *nd, lws_usec_t timestamp,
+                          void *buf, size_t len)
+{
+       lws_netdev_instance_wifi_t *wnd = (lws_netdev_instance_wifi_t *)nd;
+       struct lws_context *ctx = netdev_instance_to_ctx(&wnd->inst);
+       size_t al;
+
+       /*
+        * netdev-private sync messages?
+        */
+
+       if (!lws_json_simple_strcmp(buf, len, "\"type\":", "priv")) {
+               const char *ev = lws_json_simple_find(buf, len, "\"ev\":", &al);
+
+               if (!ev)
+                       return 0;
+
+               lwsl_notice("%s: smd priv ev %.*s\n", __func__, (int)al, ev);
+
+               switch (atoi(ev)) {
+               case WIFI_EVENT_STA_START:
+                       wnd->state = LWSNDVWIFI_STATE_INITIAL;
+                       if (!lws_netdev_wifi_redo_last(wnd))
+                               break;
+
+                       /*
+                        * if the "try last successful" one fails, start the
+                        * scan by falling through
+                        */
+
+               case WIFI_EVENT_STA_DISCONNECTED:
+                       lws_smd_msg_printf(ctx, LWSSMDCL_NETWORK,
+                                          "{\"type\":\"linkdown\","
+                                          "\"if\":\"%s\"}", wnd->inst.name);
+                       wnd->state = LWSNDVWIFI_STATE_SCAN;
+                       /*
+                        * We do it via the sul so we don't get timed scans
+                        * on top of each other
+                        */
+                       lws_sul_schedule(ctx, 0, &wnd->sul_scan,
+                                        lws_netdev_wifi_scan, 1);
+                       break;
+
+               case WIFI_EVENT_STA_CONNECTED:
+                       lws_smd_msg_printf(ctx, LWSSMDCL_NETWORK,
+                                          "{\"type\":\"linkup\","
+                                          "\"if\":\"%s\"}", wnd->inst.name);
+                       break;
+
+               case WIFI_EVENT_SCAN_DONE:
+                       lws_esp32_scan_update(wnd);
+                       break;
+               default:
+                       return 0;
+               }
+
+               return 0;
+       }
+
+       return 0;
+}
+
+/*
+ * This is coming from a thread context unrelated to lws... the first order is
+ * to turn these into lws_smd events synchronized on lws thread, since we want
+ * to change correspsonding lws netdev object states without locking.
+ */
+
+static void
+_event_handler_wifi(void *arg, esp_event_base_t event_base, int32_t event_id,
+                  void *event_data)
+{
+       lws_netdev_instance_wifi_t *wnd = (lws_netdev_instance_wifi_t *)arg;
+       struct lws_context *ctx = netdev_instance_to_ctx(&wnd->inst);
+
+       switch (event_id) {
+       case WIFI_EVENT_STA_START:
+       case WIFI_EVENT_STA_DISCONNECTED:
+       case WIFI_EVENT_SCAN_DONE:
+       case WIFI_EVENT_STA_CONNECTED:
+               /*
+                * These are events in the platform's private namespace,
+                * interpreted only by the lws_smd handler above, ** in the lws
+                * event thread context **.  The point of this is to requeue the
+                * event in the lws thread context like a bottom-half.
+                *
+                * To save on registrations, the context's NETWORK smd
+                * participant passes messages to lws_netdev, who passes ones
+                * that have if matching the netdev name to that netdev's
+                * (*event) handler.
+                *
+                * The other handler may emit generic network state SMD events
+                * for other things to consume.
+                */
+
+               lws_smd_msg_printf(ctx, LWSSMDCL_NETWORK,
+                                  "{\"type\":\"priv\",\"if\":\"%s\",\"ev\":%d}",
+                                  wnd->inst.name, (int)event_id);
+               break;
+       default:
+               return;
+       }
+}
+
+#if 0
+static int
+espip_to_sa46(lws_sockaddr46 *sa46, esp_ip_addr_t *eip)
+{
+       memset(sa46, 0, sizeof(sa46));
+
+       switch (eip->type) {
+       case ESP_IPADDR_TYPE_V4:
+               sa46->sa4.sin_family = AF_INET;
+               memcpy(sa46->sa4.sin_addr, &eip->u_addr.ip4.addr, );
+               return;
+       case ESP_IPADDR_TYPE_V6:
+       }
+}
+#endif
+
+/*
+ * This is coming from a thread context unrelated to lws
+ */
+
+static void
+_event_handler_ip(void *arg, esp_event_base_t event_base, int32_t event_id,
+             void *event_data)
+{
+       lws_netdev_instance_wifi_t *wnd = (lws_netdev_instance_wifi_t *)arg;
+       lws_netdevs_t *netdevs = lws_netdevs_from_ndi(&wnd->inst);
+       struct lws_context *ctx = lws_context_from_netdevs(netdevs);
+
+       if (event_id == IP_EVENT_STA_GOT_IP) {
+               ip_event_got_ip_t *e = (ip_event_got_ip_t *)event_data;
+               char ip[16];
+#if 0
+               tcpip_adapter_dns_info_t e32ip;
+
+               /*
+                * Since atm we get this via DHCP, presumably we can get ahold
+                * of related info set by the router
+                */
+
+               if (tcpip_adapter_get_dns_info(TCPIP_ADAPTER_IF_STA,
+                                          TCPIP_ADAPTER_DNS_MAIN,
+                                          /* also _BACKUP, _FALLBACK */
+                                          &e32ip)) {
+                       lwsl_err("%s: there's no dns server set\n", __func__);
+                       e32ip.ip.u_addr.ipv4 = 0x08080808;
+                       e32ip.ip.type = ESP_IPADDR_TYPE_V4;
+               }
+
+               netdevs->sa46_dns_resolver.
+#endif
+
+               lws_write_numeric_address((void *)&e->ip_info.ip, 4, ip,
+                               sizeof(ip));
+               lws_smd_msg_printf(ctx, LWSSMDCL_NETWORK,
+                                  "{\"type\":\"ipacq\",\"if\":\"%s\","
+                                  "\"ipv4\":\"%s\"}", wnd->inst.name, ip);
+       }
+}
+
+/*
+ * This is the platform (esp-idf) init for any kind of networking to be
+ * available at all
+ */
+int
+lws_netdev_plat_init(void)
+{
+        nvs_flash_init();
+       esp_netif_init();
+       ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+       return 0;
+}
+
+/*
+ * This is the platform (esp-idf) init for any wifi to be available at all
+ */
+int
+lws_netdev_plat_wifi_init(void)
+{
+       wifi_init_config_t wic = WIFI_INIT_CONFIG_DEFAULT();
+       int n;
+
+       esp_netif_create_default_wifi_sta();
+
+       n = esp_wifi_init(&wic);
+       if (n) {
+               lwsl_err("%s: wifi init fail: %d\n", __func__, n);
+               return 1;
+       }
+
+       return 0;
+}
+
+
+struct lws_netdev_instance *
+lws_netdev_wifi_create_plat(struct lws_context *ctx,
+                           const lws_netdev_ops_t *ops,
+                           const char *name, void *platinfo)
+{
+       lws_netdev_instance_wifi_esp32_t *wnde32 = lws_zalloc(
+                                               sizeof(*wnde32), __func__);
+
+       if (!wnde32)
+               return NULL;
+
+       wnde32->wnd.inst.type = LWSNDTYP_WIFI;
+       lws_netdev_instance_create(&wnde32->wnd.inst, ctx, ops, name, platinfo);
+
+       return &wnde32->wnd.inst;
+}
+
+int
+lws_netdev_wifi_configure_plat(struct lws_netdev_instance *nd,
+                              lws_netdev_config_t *config)
+{
+       return 0;
+}
+
+int
+lws_netdev_wifi_up_plat(struct lws_netdev_instance *nd)
+{
+       lws_netdev_instance_wifi_esp32_t *wnde32 =
+                                       (lws_netdev_instance_wifi_esp32_t *)nd;
+       struct lws_context *ctx = netdev_instance_to_ctx(&wnde32->wnd.inst);
+
+       if (wnde32->wnd.flags & LNDIW_UP)
+               return 0;
+
+       ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
+                         IP_EVENT_STA_GOT_IP, &_event_handler_ip, nd,
+                         &wnde32->instance_got_ip));
+
+       ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
+                         ESP_EVENT_ANY_ID, &_event_handler_wifi, nd,
+                         &wnde32->instance_any_id));
+
+       esp_wifi_start();
+       wnde32->wnd.flags |= LNDIW_UP;
+
+       lws_smd_msg_printf(ctx, LWSSMDCL_NETWORK,
+                          "{\"type\":\"up\",\"if\":\"%s\"}",
+                          wnde32->wnd.inst.name);
+
+       return 0;
+}
+
+int
+lws_netdev_wifi_down_plat(struct lws_netdev_instance *nd)
+{
+       lws_netdev_instance_wifi_esp32_t *wnde32 =
+                                       (lws_netdev_instance_wifi_esp32_t *)nd;
+       struct lws_context *ctx = netdev_instance_to_ctx(&wnde32->wnd.inst);
+
+       if (!(wnde32->wnd.flags & LNDIW_UP))
+               return 0;
+
+       lws_smd_msg_printf(ctx, LWSSMDCL_NETWORK,
+                          "{\"type\":\"down\",\"if\":\"%s\"}",
+                          wnde32->wnd.inst.name);
+
+       esp_wifi_stop();
+
+       esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,
+                                               &wnde32->instance_got_ip);
+       esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,
+                                               &wnde32->instance_any_id);
+
+       wnde32->wnd.flags &= ~LNDIW_UP;
+
+       return 0;
+}
+
+void
+lws_netdev_wifi_destroy_plat(struct lws_netdev_instance **pnd)
+{
+       lws_free(*pnd);
+       *pnd = NULL;
+}
diff --git a/lib/plat/freertos/esp32/drivers/pwm-esp32.c b/lib/plat/freertos/esp32/drivers/pwm-esp32.c
new file mode 100644 (file)
index 0000000..1950f2d
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * esp32 / esp-idf pwm
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "soc/ledc_reg.h"
+#include "driver/ledc.h"
+
+#define _LEDC_HIGH_SPEED_MODE 0
+
+static const ledc_timer_config_t tc = {
+       .speed_mode                     = _LEDC_HIGH_SPEED_MODE,
+       .duty_resolution                = LEDC_TIMER_13_BIT,
+       .timer_num                      = LEDC_TIMER_0,
+       .freq_hz                        = 5000,
+       .clk_cfg                        = LEDC_AUTO_CLK
+};
+
+int
+lws_pwm_plat_init(const struct lws_pwm_ops *lo)
+{
+       ledc_channel_config_t lc = {
+               .duty                   = 8191,
+               .intr_type              = LEDC_INTR_FADE_END,
+               .speed_mode             = _LEDC_HIGH_SPEED_MODE,
+               .timer_sel              = LEDC_TIMER_0,
+       };
+       size_t n;
+
+        ledc_timer_config(&tc);
+
+        for (n = 0; n < lo->count_pwm_map; n++) {
+               lc.channel = LEDC_CHANNEL_0 + lo->pwm_map[n].index;
+               lc.gpio_num = lo->pwm_map[n].gpio;
+               ledc_channel_config(&lc);
+                ledc_set_duty(_LEDC_HIGH_SPEED_MODE, lc.channel, 0);
+                ledc_update_duty(_LEDC_HIGH_SPEED_MODE, lc.channel);
+        }
+
+       return 0;
+}
+
+void
+lws_pwm_plat_intensity(const struct lws_pwm_ops *lo, _lws_plat_gpio_t gpio,
+                      lws_led_intensity_t inten)
+{
+       size_t n;
+
+       for (n = 0; n < lo->count_pwm_map; n++) {
+               if (lo->pwm_map[n].gpio == gpio) {
+                       if (!lo->pwm_map[n].active_level)
+                               inten = 65535 - inten;
+                       ledc_set_duty(_LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0 +
+                                       lo->pwm_map[n].index, inten >> 3);
+                       ledc_update_duty(_LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0 +
+                                       lo->pwm_map[n].index);
+                       return;
+               }
+       }
+
+       lwsl_err("%s: unknown gpio for pwm\n", __func__);
+}
diff --git a/lib/plat/freertos/esp32/drivers/settings-esp32.c b/lib/plat/freertos/esp32/drivers/settings-esp32.c
new file mode 100644 (file)
index 0000000..9e74a13
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * esp32 / esp-idf NV settings shim
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+#include <nvs_flash.h>
+
+int
+lws_settings_plat_get(lws_settings_instance_t *si, const char *name,
+                     uint8_t *dest, size_t *max_actual)
+{
+       int n;
+
+       n = nvs_flash_init_partition((const char *)si->opaque_plat);
+
+       lwsl_notice("%s: init partition %d\n", __func__, n);
+       if (n == ESP_ERR_NOT_FOUND)
+               return 1;
+
+       if (nvs_open_from_partition((const char *)si->opaque_plat,
+                                   "_lws_settings", NVS_READONLY,
+                                   (nvs_handle_t *)&si->handle_plat))
+               return 1;
+
+       n = nvs_get_blob((nvs_handle_t)si->handle_plat,
+                        name, dest, max_actual);
+
+       nvs_close((nvs_handle_t)si->handle_plat);
+
+       return !!n;
+}
+
+int
+lws_settings_plat_set(lws_settings_instance_t *si, const char *name,
+                     const uint8_t *src, size_t len)
+{
+       int n = nvs_flash_init_partition((const char *)si->opaque_plat);
+
+       lwsl_notice("%s: init partition %d\n", __func__, n);
+       if (n == ESP_ERR_NOT_FOUND)
+               return 1;
+
+       if (nvs_open_from_partition((const char *)si->opaque_plat,
+                                   "_lws_settings", NVS_READWRITE,
+                                   (nvs_handle_t *)&si->handle_plat))
+               return 1;
+
+       n = nvs_set_blob((nvs_handle_t)si->handle_plat, name, src, len);
+
+       nvs_commit((nvs_handle_t)si->handle_plat);
+       nvs_close((nvs_handle_t)si->handle_plat);
+
+       return 0;
+}
diff --git a/lib/plat/freertos/freertos-fds.c b/lib/plat/freertos/freertos-fds.c
new file mode 100644 (file)
index 0000000..a638309
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+void
+lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
+{
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+
+       pt->fds[pt->fds_count++].revents = 0;
+}
+
+void
+lws_plat_delete_socket_from_fds(struct lws_context *context,
+                                               struct lws *wsi, int m)
+{
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+
+       pt->fds_count--;
+}
+
+int
+lws_plat_change_pollfd(struct lws_context *context,
+                     struct lws *wsi, struct lws_pollfd *pfd)
+{
+       return 0;
+}
+
+int
+insert_wsi(const struct lws_context *context, struct lws *wsi)
+{
+    assert(context->lws_lookup[wsi->desc.sockfd -
+                               lws_plat_socket_offset()] == 0);
+
+    context->lws_lookup[wsi->desc.sockfd - \
+                      lws_plat_socket_offset()] = wsi;
+
+    return 0;
+}
similarity index 67%
rename from lib/plat/esp32/esp32-file.c
rename to lib/plat/freertos/freertos-file.c
index f2909bb..033d258 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * libwebsockets - lib/plat/lws-plat-esp32.c
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 int lws_plat_apply_FD_CLOEXEC(int n)
 {
@@ -27,7 +30,7 @@ int lws_plat_apply_FD_CLOEXEC(int n)
 }
 
 
-LWS_VISIBLE lws_fop_fd_t IRAM_ATTR
+lws_fop_fd_t IRAM_ATTR
 _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
                    const char *vpath, lws_fop_flags_t *flags)
 {
@@ -60,7 +63,7 @@ bail:
        return NULL;
 }
 
-LWS_VISIBLE int IRAM_ATTR
+int IRAM_ATTR
 _lws_plat_file_close(lws_fop_fd_t *fops_fd)
 {
        int fd = (*fops_fd)->fd;
@@ -71,13 +74,13 @@ _lws_plat_file_close(lws_fop_fd_t *fops_fd)
        return close(fd);
 }
 
-LWS_VISIBLE lws_fileofs_t IRAM_ATTR
+lws_fileofs_t IRAM_ATTR
 _lws_plat_file_seek_cur(lws_fop_fd_t fops_fd, lws_fileofs_t offset)
 {
        return lseek(fops_fd->fd, offset, SEEK_CUR);
 }
 
-LWS_VISIBLE int IRAM_ATTR
+int IRAM_ATTR
 _lws_plat_file_read(lws_fop_fd_t fops_fd, lws_filepos_t *amount,
                    uint8_t *buf, lws_filepos_t len)
 {
@@ -94,7 +97,7 @@ _lws_plat_file_read(lws_fop_fd_t fops_fd, lws_filepos_t *amount,
        return 0;
 }
 
-LWS_VISIBLE int IRAM_ATTR
+int IRAM_ATTR
 _lws_plat_file_write(lws_fop_fd_t fops_fd, lws_filepos_t *amount,
                     uint8_t *buf, lws_filepos_t len)
 {
@@ -132,7 +135,7 @@ lws_find_string_in_file(const char *filename, const char *string, int stringlen)
 
        q = string;
        n = 0;
-       while (n < sizeof(buf) - 1 && q != p)
+       while ((size_t)n < sizeof(buf) - 1 && q != p)
                buf[n++] = *q++;
        buf[n] = '\0';
 
@@ -150,8 +153,8 @@ lws_find_string_in_file(const char *filename, const char *string, int stringlen)
 #endif
 
 #if !defined(LWS_AMAZON_RTOS)
-LWS_VISIBLE int
-lws_plat_write_file(const char *filename, void *buf, int len)
+int
+lws_plat_write_file(const char *filename, void *buf, size_t len)
 {
        nvs_handle nvh;
        int n;
@@ -174,9 +177,9 @@ lws_plat_write_file(const char *filename, void *buf, int len)
 
 /* we write vhostname.cert.pem and vhostname.key.pem, 0 return means OK */
 
-LWS_VISIBLE int
+int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
-                       int len)
+                       size_t len)
 {
        const char *name = vhost->tls.alloc_cert_path;
 
@@ -186,8 +189,8 @@ lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
        return lws_plat_write_file(name, buf, len) < 0;
 }
 
-LWS_VISIBLE int
-lws_plat_read_file(const char *filename, void *buf, int len)
+int
+lws_plat_read_file(const char *filename, void *buf, size_t len)
 {
        nvs_handle nvh;
        size_t s = 0;
@@ -201,7 +204,7 @@ lws_plat_read_file(const char *filename, void *buf, int len)
        ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
        if (nvs_get_blob(nvh, filename, NULL, &s) != ESP_OK)
                goto bail;
-       if (s > (size_t)len)
+       if (s > len)
                goto bail;
 
        n = nvs_get_blob(nvh, filename, buf, &s);
similarity index 56%
rename from lib/plat/esp32/esp32-init.c
rename to lib/plat/freertos/freertos-init.c
index 2f537d0..49f5b5d 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * libwebsockets - lib/plat/lws-plat-esp32.c
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 int
 lws_plat_context_early_init(void)
@@ -30,7 +33,7 @@ lws_plat_context_early_init(void)
 void
 lws_plat_context_early_destroy(struct lws_context *context)
 {
-#if defined(LWS_AMAZON_RTOS)
+#if defined(LWS_AMAZON_RTOS) && defined(LWS_WITH_MBEDTLS)
        mbedtls_ctr_drbg_free(&context->mcdc);
        mbedtls_entropy_free(&context->mec);
 #endif
@@ -58,7 +61,7 @@ const struct http2_settings lws_h2_defaults_esp32 = { {
        /* H2SET_HEADER_TABLE_SIZE */                    512,
        /* H2SET_ENABLE_PUSH */                            0,
        /* H2SET_MAX_CONCURRENT_STREAMS */                 8,
-       /* H2SET_INITIAL_WINDOW_SIZE */                65535,
+       /* H2SET_INITIAL_WINDOW_SIZE */                    0,
        /* H2SET_MAX_FRAME_SIZE */                     16384,
        /* H2SET_MAX_HEADER_LIST_SIZE */                 512,
        /* H2SET_RESERVED7 */                              0,
@@ -70,7 +73,7 @@ int
 lws_plat_init(struct lws_context *context,
              const struct lws_context_creation_info *info)
 {
-#if defined(LWS_AMAZON_RTOS)
+#if defined(LWS_AMAZON_RTOS) && defined(LWS_WITH_MBEDTLS)
        int n;
 
        /* initialize platform random through mbedtls */
@@ -87,7 +90,7 @@ lws_plat_init(struct lws_context *context,
        }
 #endif
 
-       /* master context has the global fd lookup array */
+       /* context has the global fd lookup array */
        context->lws_lookup = lws_zalloc(sizeof(struct lws *) *
                                         context->max_fds, "esp32 lws_lookup");
        if (context->lws_lookup == NULL) {
@@ -108,5 +111,9 @@ lws_plat_init(struct lws_context *context,
        context->set = lws_h2_defaults_esp32;
 #endif
 
+#if defined(LWS_ESP_PLATFORM)
+       gpio_install_isr_service(0);
+#endif
+
        return 0;
 }
diff --git a/lib/plat/freertos/freertos-misc.c b/lib/plat/freertos/freertos-misc.c
new file mode 100644 (file)
index 0000000..07e4620
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+/*
+ * Normally you don't want this, use lws_sul instead inside the event loop.
+ * But sometimes for drivers it makes sense, so there's an internal-only
+ * crossplatform api for it.
+ */
+
+void
+lws_msleep(unsigned int ms)
+{
+       vTaskDelay(portTICK_PERIOD_MS > ms ? 1 : ms / portTICK_PERIOD_MS);
+}
+
+lws_usec_t
+lws_now_usecs(void)
+{
+       struct timeval tv;
+       gettimeofday(&tv, NULL);
+       return ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;
+}
+
+size_t
+lws_get_random(struct lws_context *context, void *buf, size_t len)
+{
+#if defined(LWS_WITH_ESP32)
+       uint8_t *pb = buf;
+
+       while (len) {
+               uint32_t r = esp_random();
+               uint8_t *p = (uint8_t *)&r;
+               int b = 4;
+
+               if (len < (size_t)b)
+                       b = len;
+
+               len -= b;
+
+               while (b--)
+                       *pb++ = p[b];
+       }
+
+       return pb - (uint8_t *)buf;
+#else
+#if defined(LWS_WITH_MBEDTLS)
+       int n;
+
+       n = mbedtls_ctr_drbg_random(&context->mcdc, buf, len);
+       if (!n)
+               return len;
+
+       /* failed */
+
+       lwsl_err("%s: mbedtls_ctr_drbg_random returned 0x%x\n", __func__, n);
+#endif
+       return 0;
+#endif
+}
+
+
+void lwsl_emit_syslog(int level, const char *line)
+{
+       lwsl_emit_stderr(level, line);
+}
+
+int
+lws_plat_drop_app_privileges(struct lws_context *context, int actually_init)
+{
+       return 0;
+}
+
+int
+lws_plat_recommended_rsa_bits(void)
+{
+       /*
+        * 2048-bit key generation takes up to a minute on ESP32, 4096
+        * is like 15 minutes +
+        */
+       return 2048;
+}
diff --git a/lib/plat/freertos/freertos-pipe.c b/lib/plat/freertos/freertos-pipe.c
new file mode 100644 (file)
index 0000000..e459bf0
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+int
+lws_plat_pipe_create(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct sockaddr_in *si = &wsi->a.context->frt_pipe_si;
+       lws_sockfd_type *fd = pt->dummy_pipe_fds;
+       socklen_t sl;
+
+       /*
+        * There's no pipe abstraction on lwip / freertos... use a UDP socket
+        * listening on 127.0.0.1:xxxx and send a byte to it from a second UDP
+        * socket to cancel the wait.
+        *
+        * Set the port to 0 at the bind, so lwip will choose a free one in the
+        * ephemeral range for us.
+        */
+
+       fd[0] = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd[0] < 0)
+               goto bail;
+
+       fd[1] = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd[1] < 0)
+               goto bail;
+
+       /*
+        * No need for memset since it's in zalloc'd context... it's in the
+        * context so we can reuse the prepared sockaddr to send tp fd[0] whem
+        * we want to cancel the wait
+        */
+
+       si->sin_family = AF_INET;
+       si->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       si->sin_port = 0;
+
+       if (bind(fd[0], (const struct sockaddr *)si, sizeof(*si)) < 0)
+               goto bail;
+
+       /*
+        * Query the socket to set context->frt_pipe_si to the full sockaddr it
+        * wants to be addressed by, including the port that lwip chose.
+        *
+        * Afterwards, we can use this prepared sockaddr stashed in the context
+        * to trigger the "pipe" without any other preliminaries.
+        */
+
+       sl = sizeof(*si);
+       if (getsockname(fd[0], (struct sockaddr *)si, &sl))
+               goto bail;
+
+       lwsl_info("%s: cancel UDP skt port %d\n", __func__,
+                 ntohs(si->sin_port));
+
+       return 0;
+
+bail:
+       lwsl_err("%s: failed\n", __func__);
+
+       return 1;
+}
+
+int
+lws_plat_pipe_signal(struct lws_context *ctx, int tsi)
+{
+       struct lws_context_per_thread *pt = &ctx->pt[tsi];
+       struct sockaddr_in *si = &ctx->frt_pipe_si;
+       lws_sockfd_type *fd = pt->dummy_pipe_fds;
+       uint8_t u = 0;
+       int n;
+
+       /*
+        * Send a single UDP byte payload to the listening socket fd[0], forcing
+        * the event loop wait to wake.  fd[1] and context->frt_pipe_si are
+        * set at context creation and are static, the UDP sendto is supposed to
+        * be threadsafe for lwip:
+        *
+        * https://lwip.fandom.com/wiki/LwIP_and_multithreading
+        *
+        * Sockets generally can't be used by more than one application thread
+        * (on udp/raw netconn, doing a sendto/recv is currently possible).
+        */
+
+       n = sendto(fd[1], &u, 1, 0, (struct sockaddr *)si, sizeof(*si));
+
+       return n != 1;
+}
+
+void
+lws_plat_pipe_close(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       lws_sockfd_type *fd = pt->dummy_pipe_fds;
+
+       if (fd[0] && fd[0] != -1)
+               close(fd[0]);
+       if (fd[1] && fd[1] != -1)
+               close(fd[1]);
+
+       fd[0] = fd[1] = -1;
+}
diff --git a/lib/plat/freertos/freertos-resolv.c b/lib/plat/freertos/freertos-resolv.c
new file mode 100644 (file)
index 0000000..5abdb54
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+lws_async_dns_server_check_t
+lws_plat_asyncdns_init(struct lws_context *context, lws_sockaddr46 *sa46)
+{
+       uint32_t ipv4;
+       lws_async_dns_server_check_t s = LADNS_CONF_SERVER_CHANGED;
+
+       FreeRTOS_GetAddressConfiguration(NULL, NULL, NULL, &ipv4);
+
+       sa46->sa4.sin_family = AF_INET;
+       if (sa46->sa4.sin_addr.s_addr == ipv4)
+               s = LADNS_CONF_SERVER_SAME;
+
+       sa46->sa4.sin_addr.s_addr = ipv4;
+
+       return s;
+}
+#endif
+
+int
+lws_plat_ntpclient_config(struct lws_context *context)
+{
+       lws_system_blob_heap_append(lws_system_get_blob(context,
+                                   LWS_SYSBLOB_TYPE_NTP_SERVER, 0),
+                                   (const uint8_t *)"pool.ntp.org", 13);
+
+       return 0;
+}
similarity index 63%
rename from lib/plat/esp32/esp32-service.c
rename to lib/plat/freertos/freertos-service.c
index bb89696..795e382 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * libwebsockets - lib/plat/lws-plat-esp32.c
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 int
 lws_plat_service(struct lws_context *context, int timeout_ms)
@@ -34,39 +37,40 @@ lws_plat_service(struct lws_context *context, int timeout_ms)
 }
 
 
-LWS_EXTERN int
+int
 _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
 {
+       volatile struct lws_context_per_thread *vpt;
        struct lws_context_per_thread *pt;
        lws_usec_t timeout_us;
        int n = -1, m, c, a = 0;
 
        /* stay dead once we are dead */
 
-       if (!context || !context->vhost_list)
+       if (!context)
                return 1;
 
        pt = &context->pt[tsi];
-       lws_stats_bump(pt, LWSSTATS_C_SERVICE_ENTRY, 1);
+       vpt = (volatile struct lws_context_per_thread *)pt;
 
        {
                unsigned long m = lws_now_secs();
 
                if (m > context->time_last_state_dump) {
                        context->time_last_state_dump = m;
-#if defined(LWS_AMAZON_RTOS)
-                       n = xPortGetFreeHeapSize();
-#else
+#if defined(LWS_ESP_PLATFORM)
                        n = esp_get_free_heap_size();
+#else
+                       n = xPortGetFreeHeapSize();
 #endif
                        if ((unsigned int)n != context->last_free_heap) {
                                if ((unsigned int)n > context->last_free_heap)
-                                       lwsl_notice(" heap :%ld (+%ld)\n",
+                                       lwsl_debug(" heap :%ld (+%ld)\n",
                                                    (unsigned long)n,
                                                    (unsigned long)(n -
                                                      context->last_free_heap));
                                else
-                                       lwsl_notice(" heap :%ld (-%ld)\n",
+                                       lwsl_debug(" heap :%ld (-%ld)\n",
                                                    (unsigned long)n,
                                                    (unsigned long)(
                                                      context->last_free_heap -
@@ -83,32 +87,38 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
                timeout_ms = 2000000000;
        timeout_us = ((lws_usec_t)timeout_ms) * LWS_US_PER_MS;
 
-       if (!pt->service_tid_detected) {
-               struct lws *_lws = lws_zalloc(sizeof(*_lws), "tid probe");
+       if (!pt->service_tid_detected && context->vhost_list) {
+               lws_fakewsi_def_plwsa(pt);
 
-               if (!_lws)
-                       return 1;
-               _lws->context = context;
+               lws_fakewsi_prep_plwsa_ctx(context);
 
                pt->service_tid = context->vhost_list->protocols[0].callback(
-                       _lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
+                       (struct lws *)plwsa, LWS_CALLBACK_GET_THREAD_ID,
+                       NULL, NULL, 0);
                pt->service_tid_detected = 1;
-               lws_free(_lws);
        }
 
        /*
         * is there anybody with pending stuff that needs service forcing?
         */
+#if !defined(LWS_AMAZON_RTOS)
+again:
+#endif
+       n = 0;
        if (lws_service_adjust_timeout(context, 1, tsi)) {
-
+#if defined(LWS_AMAZON_RTOS)
 again:
+#endif /* LWS_AMAZON_RTOS */
+
                a = 0;
                if (timeout_us) {
                        lws_usec_t us;
 
                        lws_pt_lock(pt, __func__);
                        /* don't stay in poll wait longer than next hr timeout */
-                       us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
+                       us = __lws_sul_service_ripe(pt->pt_sul_owner,
+                                                   LWS_COUNT_PT_SUL_OWNERS,
+                                                   lws_now_usecs());
                        if (us && us < timeout_us)
                                timeout_us = us;
 
@@ -136,18 +146,13 @@ again:
                                FD_SET(pt->fds[n].fd, &errfds);
                        }
 
+                       vpt->inside_poll = 1;
+                       lws_memory_barrier();
                        n = select(max_fd + 1, &readfds, &writefds, &errfds, ptv);
+                       vpt->inside_poll = 0;
+                       lws_memory_barrier();
                        n = 0;
 
-       #if defined(LWS_WITH_DETAILED_LATENCY)
-                       /*
-                        * so we can track how long it took before we actually read a POLLIN
-                        * that was signalled when we last exited poll()
-                        */
-                       if (context->detailed_latency_cb)
-                               pt->ust_left_poll = lws_now_usecs();
-       #endif
-
                        for (m = 0; m < (int)pt->fds_count; m++) {
                                c = 0;
                                if (FD_ISSET(pt->fds[m].fd, &readfds)) {
@@ -175,25 +180,18 @@ again:
                m |= !!pt->ws.rx_draining_ext_list;
        #endif
 
+#if defined(LWS_WITH_TLS)
                if (pt->context->tls_ops &&
                    pt->context->tls_ops->fake_POLLIN_for_buffered)
                        m |= pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
-
+#endif
                if (!m && !n)
                        return 0;
        } else
                a = 1;
 
        m = lws_service_flag_pending(context, tsi);
-       if (m)
-               c = -1; /* unknown limit */
-       else
-               if (n < 0) {
-                       if (LWS_ERRNO != LWS_EINTR)
-                               return -1;
-                       return 0;
-               } else
-                       c = n;
+       c = m ? -1 : n;
 
        /* any socket with events to service? */
        for (n = 0; n < (int)pt->fds_count && c; n++) {
diff --git a/lib/plat/freertos/freertos-sockets.c b/lib/plat/freertos/freertos-sockets.c
new file mode 100644 (file)
index 0000000..c6bfec3
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include <errno.h>
+#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_HAVE_MBEDTLS_NET_SOCKETS)
+#include "mbedtls/net_sockets.h"
+#else
+#include "mbedtls/net.h"
+#endif
+#endif
+
+int
+lws_send_pipe_choked(struct lws *wsi)
+{
+       struct lws *wsi_eff = wsi;
+       fd_set writefds;
+       struct timeval tv = { 0, 0 };
+       int n;
+#if defined(LWS_WITH_HTTP2)
+       wsi_eff = lws_get_network_wsi(wsi);
+#endif
+
+       /* the fact we checked implies we avoided back-to-back writes */
+       wsi_eff->could_have_pending = 0;
+
+       /* treat the fact we got a truncated send pending as if we're choked */
+       if (lws_has_buffered_out(wsi)
+#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
+           || wsi->http.comp_ctx.buflist_comp ||
+              wsi->http.comp_ctx.may_have_more
+#endif
+       )
+               return 1;
+
+       FD_ZERO(&writefds);
+       FD_SET(wsi_eff->desc.sockfd, &writefds);
+
+       n = select(wsi_eff->desc.sockfd + 1, NULL, &writefds, NULL, &tv);
+       if (n < 0)
+               return 1; /* choked */
+
+       return !n; /* n = 0 = not writable = choked */
+}
+
+int
+lws_poll_listen_fd(struct lws_pollfd *fd)
+{
+       fd_set readfds;
+       struct timeval tv = { 0, 0 };
+
+       FD_ZERO(&readfds);
+       FD_SET(fd->fd, &readfds);
+
+       return select(fd->fd + 1, &readfds, NULL, NULL, &tv);
+}
+
+int
+lws_plat_set_nonblocking(lws_sockfd_type fd)
+{
+       return fcntl(fd, F_SETFL, O_NONBLOCK) < 0;
+}
+
+int
+lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
+{
+       int optval = 1;
+       socklen_t optlen = sizeof(optval);
+
+#if defined(__APPLE__) || \
+    defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
+    defined(__NetBSD__) || \
+    defined(__OpenBSD__)
+       struct protoent *tcp_proto;
+#endif
+
+       if (vhost->ka_time) {
+               /* enable keepalive on this socket */
+               optval = 1;
+               if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
+                              (const void *)&optval, optlen) < 0)
+                       return 1;
+
+#if defined(__APPLE__) || \
+    defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
+    defined(__NetBSD__) || \
+        defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun)
+
+               /*
+                * didn't find a way to set these per-socket, need to
+                * tune kernel systemwide values
+                */
+#else
+               /* set the keepalive conditions we want on it too */
+               optval = vhost->ka_time;
+               if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
+                              (const void *)&optval, optlen) < 0)
+                       return 1;
+
+               optval = vhost->ka_interval;
+               if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
+                              (const void *)&optval, optlen) < 0)
+                       return 1;
+
+               optval = vhost->ka_probes;
+               if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
+                              (const void *)&optval, optlen) < 0)
+                       return 1;
+#endif
+       }
+
+       /* Disable Nagle */
+       optval = 1;
+       if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, optlen) < 0)
+               return 1;
+
+       return lws_plat_set_nonblocking(fd);
+}
+
+static const int ip_opt_lws_flags[] = {
+       LCCSCF_IP_LOW_LATENCY, LCCSCF_IP_HIGH_THROUGHPUT,
+       LCCSCF_IP_HIGH_RELIABILITY, LCCSCF_IP_LOW_COST
+}, ip_opt_val[] = {
+       IPTOS_LOWDELAY, IPTOS_THROUGHPUT, IPTOS_RELIABILITY, IPTOS_MINCOST
+};
+#if !defined(LWS_WITH_NO_LOGS)
+static const char *ip_opt_names[] = {
+       "LOWDELAY", "THROUGHPUT", "RELIABILITY", "MINCOST"
+};
+#endif
+
+int
+lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags)
+{
+       int optval = (int)pri, ret = 0, n;
+       socklen_t optlen = sizeof(optval);
+#if !defined(LWS_WITH_NO_LOGS)
+       int en;
+#endif
+
+#if defined(SO_PRIORITY)
+       if (pri) { /* 0 is the default already */
+               if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY,
+                               (const void *)&optval, optlen) < 0) {
+#if !defined(LWS_WITH_NO_LOGS)
+                       en = errno;
+                       lwsl_warn("%s: unable to set socket pri %d: errno %d\n",
+                                 __func__, (int)pri, en);
+#endif
+                       ret = 1;
+               } else
+                       lwsl_notice("%s: set pri %u\n", __func__, pri);
+       }
+#endif
+
+       for (n = 0; n < 4; n++) {
+               if (!(lws_flags & ip_opt_lws_flags[n]))
+                       continue;
+
+               optval = (int)ip_opt_val[n];
+               if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *)&optval,
+                              optlen) < 0) {
+#if !defined(LWS_WITH_NO_LOGS)
+                       en = errno;
+                       lwsl_warn("%s: unable to set %s: errno %d\n", __func__,
+                                 ip_opt_names[n], en);
+#endif
+                       ret = 1;
+               } else
+                       lwsl_notice("%s: set ip flag %s\n", __func__,
+                                   ip_opt_names[n]);
+       }
+
+       return ret;
+}
+
+/* cast a struct sockaddr_in6 * into addr for ipv6 */
+
+int
+lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
+                   size_t addrlen)
+{
+#if 0
+       int rc = LWS_ITOSA_NOT_EXIST;
+
+       struct ifaddrs *ifr;
+       struct ifaddrs *ifc;
+#ifdef LWS_WITH_IPV6
+       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
+#endif
+
+       getifaddrs(&ifr);
+       for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
+               if (!ifc->ifa_addr)
+                       continue;
+
+               lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
+
+               if (strcmp(ifc->ifa_name, ifname))
+                       continue;
+
+               switch (ifc->ifa_addr->sa_family) {
+               case AF_INET:
+#ifdef LWS_WITH_IPV6
+                       if (ipv6) {
+                               /* map IPv4 to IPv6 */
+                               memset((char *)&addr6->sin6_addr, 0,
+                                               sizeof(struct in6_addr));
+                               addr6->sin6_addr.s6_addr[10] = 0xff;
+                               addr6->sin6_addr.s6_addr[11] = 0xff;
+                               memcpy(&addr6->sin6_addr.s6_addr[12],
+                                       &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
+                                                       sizeof(struct in_addr));
+                       } else
+#endif
+                               memcpy(addr,
+                                       (struct sockaddr_in *)ifc->ifa_addr,
+                                                   sizeof(struct sockaddr_in));
+                       break;
+#ifdef LWS_WITH_IPV6
+               case AF_INET6:
+                       memcpy(&addr6->sin6_addr,
+                         &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
+                                                      sizeof(struct in6_addr));
+                       break;
+#endif
+               default:
+                       continue;
+               }
+               rc = LWS_ITOSA_USABLE;
+       }
+
+       freeifaddrs(ifr);
+
+       if (rc == LWS_ITOSA_NOT_EXIST) {
+               /* check if bind to IP address */
+#ifdef LWS_WITH_IPV6
+               if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
+                       rc = LWS_ITOSA_USABLE;
+               else
+#endif
+               if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
+                       rc = LWS_ITOSA_USABLE;
+       }
+
+       return rc;
+#endif
+
+       return LWS_ITOSA_NOT_EXIST;
+}
+
+const char *
+lws_plat_inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
+{
+       return inet_ntop(af, src, dst, cnt);
+}
+
+int
+lws_plat_inet_pton(int af, const char *src, void *dst)
+{
+       return 1; //  inet_pton(af, src, dst);
+}
+
+int
+lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+int
+lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, size_t canned_len,
+                         size_t n, int fd, const char *iface)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+int
+lws_plat_if_up(const char *ifname, int fd, int up)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+int
+lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+int
+lws_plat_ifconfig(int fd, lws_dhcpc_ifstate_t *is)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+int
+lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost)
+{
+       return 0;
+}
+
+#if defined(LWS_WITH_MBEDTLS)
+int
+lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len)
+{
+       int fd = ((mbedtls_net_context *) ctx)->fd;
+       int ret;
+
+       if (fd < 0)
+               return MBEDTLS_ERR_NET_INVALID_CONTEXT;
+
+       ret = write(fd, buf, len);
+       if (ret >= 0)
+               return ret;
+
+       if (errno == EAGAIN || errno == EWOULDBLOCK)
+               return MBEDTLS_ERR_SSL_WANT_WRITE;
+
+       if (errno == EPIPE || errno == ECONNRESET)
+               return MBEDTLS_ERR_NET_CONN_RESET;
+
+       if( errno == EINTR )
+               return MBEDTLS_ERR_SSL_WANT_WRITE;
+
+       return MBEDTLS_ERR_NET_SEND_FAILED;
+}
+
+int
+lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)
+{
+       int fd = ((mbedtls_net_context *) ctx)->fd;
+       int ret;
+
+       if (fd < 0)
+               return MBEDTLS_ERR_NET_INVALID_CONTEXT;
+
+       ret = (int)read(fd, buf, len);
+       if (ret >= 0)
+               return ret;
+
+       if (errno == EAGAIN || errno == EWOULDBLOCK)
+               return MBEDTLS_ERR_SSL_WANT_READ;
+
+       if (errno == EPIPE || errno == ECONNRESET)
+               return MBEDTLS_ERR_NET_CONN_RESET;
+
+       if (errno == EINTR || !errno)
+               return MBEDTLS_ERR_SSL_WANT_READ;
+
+       return MBEDTLS_ERR_NET_RECV_FAILED;
+}
+#endif
+
diff --git a/lib/plat/freertos/private-lib-plat-freertos.h b/lib/plat/freertos/private-lib-plat-freertos.h
new file mode 100644 (file)
index 0000000..d544e2b
--- /dev/null
@@ -0,0 +1,133 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Included from lib/private-lib-core.h if LWS_PLAT_FREERTOS
+ */
+
+#if !defined(LWS_ESP_PLATFORM)
+#define SOMAXCONN 3
+#endif
+
+#if defined(LWS_AMAZON_RTOS)
+ int
+ open(const char *path, int oflag, ...);
+#else
+ #include <fcntl.h>
+#endif
+
+ #include <strings.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <sys/time.h>
+ #include <netdb.h>
+
+ #ifndef __cplusplus
+  #include <errno.h>
+ #endif
+ #include <signal.h>
+#if defined(LWS_AMAZON_RTOS)
+const char *
+gai_strerror(int);
+#else
+ #include <sys/socket.h>
+#endif
+
+#if defined(LWS_AMAZON_RTOS)
+ #include "FreeRTOS.h"
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+ #include "FreeRTOS_IP.h"
+#endif
+ #include "timers.h"
+ #include <esp_attr.h>
+ #include <semphr.h>
+#else
+ #include "freertos/timers.h"
+ #include <esp_attr.h>
+ #include <esp_system.h>
+ #include <esp_task_wdt.h>
+#endif
+
+#if defined(LWS_WITH_ESP32)
+#include "lwip/apps/sntp.h"
+#include <errno.h>
+#endif
+
+typedef SemaphoreHandle_t lws_mutex_t;
+#define lws_mutex_init(x)      x = xSemaphoreCreateMutex()
+#define lws_mutex_destroy(x)   vSemaphoreDelete(x)
+#define lws_mutex_lock(x)      (!xSemaphoreTake(x, portMAX_DELAY)) /*0 = OK */
+#define lws_mutex_unlock(x)    xSemaphoreGive(x)
+
+#include <lwip/sockets.h>
+
+ #if defined(LWS_BUILTIN_GETIFADDRS)
+  #include "./misc/getifaddrs.h"
+ #endif
+
+ #define LWS_ERRNO errno
+ #define LWS_EAGAIN EAGAIN
+ #define LWS_EALREADY EALREADY
+ #define LWS_EINPROGRESS EINPROGRESS
+ #define LWS_EINTR EINTR
+ #define LWS_EISCONN EISCONN
+ #define LWS_ENOTCONN ENOTCONN
+ #define LWS_EWOULDBLOCK EWOULDBLOCK
+ #define LWS_EADDRINUSE EADDRINUSE
+ #define LWS_ECONNABORTED ECONNABORTED
+
+ #define lws_set_blocking_send(wsi)
+
+ #ifndef LWS_NO_FORK
+  #ifdef LWS_HAVE_SYS_PRCTL_H
+   #include <sys/prctl.h>
+  #endif
+ #endif
+
+#if !defined(MSG_NOSIGNAL)
+#define MSG_NOSIGNAL 0
+#endif
+
+#define compatible_close(x) close(x)
+#define lws_plat_socket_offset() LWIP_SOCKET_OFFSET
+#define wsi_from_fd(A,B)  A->lws_lookup[B - lws_plat_socket_offset()]
+
+struct lws_context;
+struct lws;
+
+int
+insert_wsi(const struct lws_context *context, struct lws *wsi);
+
+#define delete_from_fd(A,B) A->lws_lookup[B - lws_plat_socket_offset()] = 0
+
+#define LWS_PLAT_TIMER_TYPE            TimerHandle_t
+#define LWS_PLAT_TIMER_CB(name, var)   void name(TimerHandle_t var)
+#define LWS_PLAT_TIMER_CB_GET_OPAQUE(x) pvTimerGetTimerID(x)
+#define LWS_PLAT_TIMER_CREATE(name, interval, repeat, opaque, cb) \
+       xTimerCreate(name, pdMS_TO_TICKS(interval) ? pdMS_TO_TICKS(interval) : 1, \
+                       repeat ? pdTRUE : 0, opaque, cb)
+#define LWS_PLAT_TIMER_DELETE(ptr)     xTimerDelete(ptr, 0)
+#define LWS_PLAT_TIMER_START(ptr)      xTimerStart(ptr, 0)
+#define LWS_PLAT_TIMER_STOP(ptr)       xTimerStop(ptr, 0)
+
+
diff --git a/lib/plat/optee/CMakeLists.txt b/lib/plat/optee/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b7402f3
--- /dev/null
@@ -0,0 +1,49 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       plat/optee/lws-plat-optee.c
+)
+if (LWS_WITH_NETWORK)
+       list(APPEND SOURCES
+               plat/optee/network.c
+       )
+endif()
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --sysroot ../../../../lib/libutils/isoc/include -I../../../../lib/libutils/isoc/include -I../../../../lib/libutils/ext/include" )
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
index 21307fd..cc46d76 100644 (file)
@@ -1,4 +1,28 @@
-#include "core/private.h"
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
 
 #if !defined(LWS_WITH_NETWORK)
 #include <crypto/crypto.h>
@@ -49,8 +73,8 @@ lws_now_usecs(void)
 }
 #endif
 
-int
-lws_get_random(struct lws_context *context, void *buf, int len)
+size_t
+lws_get_random(struct lws_context *context, void *buf, size_t len)
 {
 #if defined(LWS_WITH_NETWORK)
        TEE_GenerateRandom(buf, len);
@@ -102,7 +126,7 @@ void lwsl_emit_optee(int level, const char *line)
 }
 
 int
-lws_plat_set_nonblocking(int fd)
+lws_plat_set_nonblocking(lws_sockfd_type fd)
 {
        return 0;
 }
@@ -174,7 +198,7 @@ lws_plat_init(struct lws_context *context,
              const struct lws_context_creation_info *info)
 {
 #if defined(LWS_WITH_NETWORK)
-       /* master context has the global fd lookup array */
+       /* context has the global fd lookup array */
        context->lws_lookup = lws_zalloc(sizeof(struct lws *) *
                                         context->max_fds, "lws_lookup");
        if (context->lws_lookup == NULL) {
@@ -195,7 +219,7 @@ lws_plat_init(struct lws_context *context,
 }
 
 int
-lws_plat_write_file(const char *filename, void *buf, int len)
+lws_plat_write_file(const char *filename, void *buf, size_t len)
 {
        return 1;
 }
@@ -211,3 +235,27 @@ lws_plat_recommended_rsa_bits(void)
 {
        return 4096;
 }
+
+int
+lws_plat_ntpclient_config(struct lws_context *context)
+{
+#if 0
+       char *ntpsrv = getenv("LWS_NTP_SERVER");
+
+       if (ntpsrv && strlen(ntpsrv) < 64) {
+               lws_system_blob_heap_append(lws_system_get_blob(context,
+                                           LWS_SYSBLOB_TYPE_NTP_SERVER, 0),
+                                           (const uint8_t *)ntpsrv,
+                                           strlen(ntpsrv));
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+void
+lws_msleep(unsigned int ms)
+{
+}
+
+
index 202d524..34f152f 100644 (file)
@@ -1,5 +1,36 @@
-#include "core/private.h"
-
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_HAVE_MBEDTLS_NET_SOCKETS)
+#include "mbedtls/net_sockets.h"
+#else
+#include "mbedtls/net.h"
+#endif
+#endif
 
 int
 lws_plat_pipe_create(struct lws *wsi)
@@ -18,7 +49,7 @@ lws_plat_pipe_close(struct lws *wsi)
 {
 }
 
-LWS_VISIBLE int
+int
 lws_send_pipe_choked(struct lws *wsi)
 {
        struct lws *wsi_eff;
@@ -55,7 +86,7 @@ lws_poll_listen_fd(struct lws_pollfd *fd)
 }
 
 
-LWS_EXTERN int
+int
 _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
 {
        lws_usec_t timeout_us = timeout_ms * LWS_US_PER_MS;
@@ -65,7 +96,7 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
 
        /* stay dead once we are dead */
 
-       if (!context || !context->vhost_list)
+       if (!context)
                return 1;
 
        pt = &context->pt[tsi];
@@ -75,7 +106,7 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
        else
                timeout_ms = 2000000000;
 
-       if (!pt->service_tid_detected) {
+       if (!pt->service_tid_detected && context->vhost_list) {
                struct lws _lws;
 
                memset(&_lws, 0, sizeof(_lws));
@@ -97,7 +128,9 @@ again:
 
                        lws_pt_lock(pt, __func__);
                        /* don't stay in poll wait longer than next hr timeout */
-                       us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
+                       us = __lws_sul_service_ripe(pt->pt_sul_owner,
+                                                   LWS_COUNT_PT_SUL_OWNERS,
+                                                   lws_now_usecs());
                        if (us && us < timeout_us)
                                timeout_us = us;
 
@@ -156,12 +189,6 @@ again:
 }
 
 int
-lws_plat_check_connection_error(struct lws *wsi)
-{
-       return 0;
-}
-
-int
 lws_plat_service(struct lws_context *context, int timeout_ms)
 {
        return _lws_plat_service_tsi(context, timeout_ms, 0);
@@ -176,7 +203,7 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
 
 int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
-                       int len)
+                       size_t len)
 {
        return 1;
 }
@@ -216,7 +243,7 @@ lws_plat_change_pollfd(struct lws_context *context,
 }
 
 const char *
-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
+lws_plat_inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
 {
        //return inet_ntop(af, src, dst, cnt);
        return "lws_plat_inet_ntop";
@@ -229,4 +256,67 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
        return 1;
 }
 
+int
+lws_plat_set_socket_options_ip(int fd, uint8_t pri, unsigned int lws_flags)
+{
+       return 0;
+}
+
+int
+lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost)
+{
+       return 0;
+}
 
+#if defined(LWS_WITH_MBEDTLS)
+int
+lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len)
+{
+       int fd = ((mbedtls_net_context *) ctx)->fd;
+       int ret;
+
+       if (fd < 0)
+               return MBEDTLS_ERR_NET_INVALID_CONTEXT;
+
+       ret = write(fd, buf, len);
+       if (ret >= 0)
+               return ret;
+
+       if (errno == EAGAIN || errno == EWOULDBLOCK)
+               return MBEDTLS_ERR_SSL_WANT_WRITE;
+
+       if (errno == EPIPE || errno == ECONNRESET)
+               return MBEDTLS_ERR_NET_CONN_RESET;
+
+       if( errno == EINTR )
+               return MBEDTLS_ERR_SSL_WANT_WRITE;
+
+       return MBEDTLS_ERR_NET_SEND_FAILED;
+}
+
+int
+lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)
+{
+       int fd = ((mbedtls_net_context *) ctx)->fd;
+       int ret;
+
+       if (fd < 0)
+               return MBEDTLS_ERR_NET_INVALID_CONTEXT;
+
+       ret = (int)read(fd, buf, len);
+       if (ret >= 0)
+               return ret;
+
+       if (errno == EAGAIN || errno == EWOULDBLOCK)
+               return MBEDTLS_ERR_SSL_WANT_READ;
+
+       if (errno == EPIPE || errno == ECONNRESET)
+               return MBEDTLS_ERR_NET_CONN_RESET;
+
+       if (errno == EINTR)
+               return MBEDTLS_ERR_SSL_WANT_READ;
+
+       return MBEDTLS_ERR_NET_RECV_FAILED;
+}
+
+#endif
diff --git a/lib/plat/optee/private-lib-plat-optee.h b/lib/plat/optee/private-lib-plat-optee.h
new file mode 100644 (file)
index 0000000..9fb570f
--- /dev/null
@@ -0,0 +1,50 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Included from lib/private-lib-core.h if LWS_WITH_OPTEE
+ */
+
+ #include <unistd.h>
+ #include <sys/types.h>
+
+ #define LWS_ERRNO errno
+ #define LWS_EAGAIN EAGAIN
+ #define LWS_EALREADY EALREADY
+ #define LWS_EINPROGRESS EINPROGRESS
+ #define LWS_EINTR EINTR
+ #define LWS_EISCONN EISCONN
+ #define LWS_ENOTCONN ENOTCONN
+ #define LWS_EWOULDBLOCK EWOULDBLOCK
+ #define LWS_EADDRINUSE EADDRINUSE
+
+ #define lws_set_blocking_send(wsi)
+
+#define compatible_close(x) close(x)
+#define lws_plat_socket_offset() (0)
+#define wsi_from_fd(A,B)  A->lws_lookup[B - lws_plat_socket_offset()]
+#define insert_wsi(A,B)   assert(A->lws_lookup[B->desc.sockfd - \
+                                 lws_plat_socket_offset()] == 0); \
+                                A->lws_lookup[B->desc.sockfd - \
+                                 lws_plat_socket_offset()] = B
+#define delete_from_fd(A,B) A->lws_lookup[B - lws_plat_socket_offset()] = 0
+
diff --git a/lib/plat/optee/private.h b/lib/plat/optee/private.h
deleted file mode 100644 (file)
index 256289f..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  Included from lib/core/private.h if LWS_WITH_OPTEE
- */
-
- #include <unistd.h>
- #include <sys/types.h>
-
- #define LWS_ERRNO errno
- #define LWS_EAGAIN EAGAIN
- #define LWS_EALREADY EALREADY
- #define LWS_EINPROGRESS EINPROGRESS
- #define LWS_EINTR EINTR
- #define LWS_EISCONN EISCONN
- #define LWS_ENOTCONN ENOTCONN
- #define LWS_EWOULDBLOCK EWOULDBLOCK
- #define LWS_EADDRINUSE EADDRINUSE
-
- #define lws_set_blocking_send(wsi)
-
-#define compatible_close(x) close(x)
-#define lws_plat_socket_offset() (0)
-#define wsi_from_fd(A,B)  A->lws_lookup[B - lws_plat_socket_offset()]
-#define insert_wsi(A,B)   assert(A->lws_lookup[B->desc.sockfd - \
-                                 lws_plat_socket_offset()] == 0); \
-                                A->lws_lookup[B->desc.sockfd - \
-                                 lws_plat_socket_offset()] = B
-#define delete_from_fd(A,B) A->lws_lookup[B - lws_plat_socket_offset()] = 0
-
diff --git a/lib/plat/unix/CMakeLists.txt b/lib/plat/unix/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b27bbb6
--- /dev/null
@@ -0,0 +1,109 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+execute_process( COMMAND grep -c illumos /lib/ld.so.1 
+                OUTPUT_VARIABLE ILLUMOS ERROR_QUIET )
+# Chomp the \n at end of output.
+string(REGEX REPLACE "[\n]+" "" ILLUMOS "${ILLUMOS}")
+
+if (NOT ${ILLUMOS} MATCHES "0")
+       set(ILLUMOS 1)
+endif()
+
+set(LWS_PLAT_UNIX 1)
+list(APPEND SOURCES
+       plat/unix/unix-caps.c
+       plat/unix/unix-misc.c
+       plat/unix/unix-init.c
+)
+if (LWS_WITH_FILE_OPS)
+       list(APPEND SOURCES plat/unix/unix-file.c)
+endif()
+if (LWS_WITH_NETWORK)
+       list(APPEND SOURCES
+               plat/unix/unix-pipe.c
+               plat/unix/unix-service.c
+               plat/unix/unix-sockets.c
+               plat/unix/unix-fds.c
+       )
+       if (LWS_WITH_SYS_ASYNC_DNS)
+               if (LWS_PLAT_ANDROID)
+                       list(APPEND SOURCES plat/unix/android/android-resolv.c)
+               else()
+                       list(APPEND SOURCES plat/unix/unix-resolv.c)
+               endif()
+       endif()
+endif()
+       
+if (LWS_WITH_PLUGINS_API)
+       list(APPEND SOURCES plat/unix/unix-plugins.c)
+endif()
+
+if (LWS_WITH_SPAWN)
+       list(APPEND SOURCES plat/unix/unix-spawn.c)
+endif()
+
+if (HAIKU)
+       set(CMAKE_REQUIRED_LIBRARIES network)
+       list(APPEND LIB_LIST_AT_END network)
+endif()
+
+IF (CMAKE_SYSTEM_NAME STREQUAL Linux AND NOT LWS_WITHOUT_EVENTFD)
+       CHECK_FUNCTION_EXISTS(eventfd_read LWS_HAVE_EVENTFD)
+endif()
+
+list(APPEND LIB_LIST_AT_END m)
+
+if (ILLUMOS)
+       list(APPEND LIB_LIST_AT_END socket)
+endif()
+
+if (LWS_HAVE_LIBCAP)
+       list(APPEND LIB_LIST_AT_END cap)
+endif()
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "QNX")
+       list(APPEND LIB_LIST_AT_END socket)
+endif()
+
+list(APPEND LIB_LIST_AT_END ${CMAKE_DL_LIBS})
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+set(LWS_PLAT_UNIX ${LWS_PLAT_UNIX} PARENT_SCOPE)
+set(ILLUMOS ${ILLUMOS} PARENT_SCOPE)
+set(LIB_LIST_AT_END ${LIB_LIST_AT_END} PARENT_SCOPE)
+set(LWS_PLAT_UNIX ${LWS_PLAT_UNIX} PARENT_SCOPE)
diff --git a/lib/plat/unix/android/android-resolv.c b/lib/plat/unix/android/android-resolv.c
new file mode 100644 (file)
index 0000000..3ae38d5
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include <sys/system_properties.h>
+
+lws_async_dns_server_check_t
+lws_plat_asyncdns_init(struct lws_context *context, lws_sockaddr46 *sa46)
+{
+       char d[PROP_VALUE_MAX], *p;
+       uint32_t ip32;
+       uint8_t i[4];
+       int n;
+
+       d[0] = '\0';
+       if (__system_property_get("net.dns1", d) <= 0)
+               return LADNS_CONF_SERVER_UNKNOWN;
+
+       for (n = 0; n < 4; n++) {
+               i[n] = (uint8_t)atoi(d);
+               p = strchr(d, '.');
+               if (n != 3 && !p)
+                       return LADNS_CONF_SERVER_UNKNOWN;
+       }
+
+       ip32 = (uint32_t) ((i[0] << 24) | (i[1] << 16) | (i[2] << 8) | i[3]);
+       n = ip32 == sa46->sa4.sin_addr.s_addr;
+       sa46->sa4.sin_family = AF_INET;
+       sa46->sa4.sin_addr.s_addr = ip32;
+
+       return n ? LADNS_CONF_SERVER_SAME : LADNS_CONF_SERVER_CHANGED;
+}
+
similarity index 63%
rename from lib/plat/unix/private.h
rename to lib/plat/unix/private-lib-plat-unix.h
index 5b3281d..1aa9e80 100644 (file)
@@ -1,24 +1,27 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
- *  Included from lib/core/private.h if no explicit platform
+ *  Included from lib/private-lib-core.h if no explicit platform
  */
 
 #include <fcntl.h>
@@ -55,6 +58,8 @@
 #endif
 #if defined(__linux__)
 #include <endian.h>
+#include <linux/if_packet.h>
+#include <net/if.h>
 #endif
 #if defined(__QNX__)
        #include <gulliver.h>
        #endif
 #endif
 
+#if defined(LWS_HAVE_PTHREAD_H)
+#include <pthread.h>
+typedef pthread_mutex_t lws_mutex_t;
+#define lws_mutex_init(x)      pthread_mutex_init(&(x), NULL)
+#define lws_mutex_destroy(x)   pthread_mutex_destroy(&(x))
+#define lws_mutex_lock(x)      pthread_mutex_lock(&(x))
+#define lws_mutex_unlock(x)    pthread_mutex_unlock(&(x))
+#endif
+
 #if defined(__sun) && defined(__GNUC__)
 
 #include <arpa/nameser_compat.h>
@@ -147,6 +161,10 @@ wsi_from_fd(const struct lws_context *context, int fd);
 int
 insert_wsi(const struct lws_context *context, struct lws *wsi);
 
+struct lws_dhcpc_ifstate;
+int
+lws_plat_ifconfig(int fd, struct lws_dhcpc_ifstate *is);
+
 void
 delete_from_fd(const struct lws_context *context, int fd);
 
@@ -157,6 +175,7 @@ delete_from_fd(const struct lws_context *context, int fd);
 #endif
 
 #define compatible_close(x) close(x)
+#define compatible_file_close(fd) close(fd)
 #define lws_plat_socket_offset() (0)
 
 /*
@@ -164,6 +183,8 @@ delete_from_fd(const struct lws_context *context, int fd);
  * but happily have something equivalent in the SO_NOSIGPIPE flag.
  */
 #ifdef __APPLE__
+/* iOS SDK 12+ seems to define it, undef it for compatibility both ways */
+#undef MSG_NOSIGNAL
 #define MSG_NOSIGNAL SO_NOSIGPIPE
 #endif
 
@@ -174,3 +195,10 @@ delete_from_fd(const struct lws_context *context, int fd);
 #if defined(__sun) && !defined(MSG_NOSIGNAL)
  #define MSG_NOSIGNAL 0
 #endif
+
+int
+lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, size_t canned_len,
+                         size_t n, int fd, const char *iface);
+
+int
+lws_plat_if_up(const char *ifname, int fd, int up);
index 3414e30..2f38854 100644 (file)
@@ -1,33 +1,38 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
-#include "core/private.h"
+#endif
+#include "private-lib-core.h"
 
 #include <pwd.h>
 #include <grp.h>
 
 #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
 static void
-_lws_plat_apply_caps(int mode, const cap_value_t *cv, int count)
+_lws_plat_apply_caps(unsigned int mode, const cap_value_t *cv, int count)
 {
        cap_t caps;
 
@@ -36,7 +41,7 @@ _lws_plat_apply_caps(int mode, const cap_value_t *cv, int count)
 
        caps = cap_get_proc();
 
-       cap_set_flag(caps, mode, count, cv, CAP_SET);
+       cap_set_flag(caps, (cap_flag_t)mode, count, cv, CAP_SET);
        cap_set_proc(caps);
        prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
        cap_free(caps);
@@ -47,15 +52,15 @@ int
 lws_plat_user_colon_group_to_ids(const char *u_colon_g, uid_t *puid, gid_t *pgid)
 {
        char *colon = strchr(u_colon_g, ':'), u[33];
-       struct passwd *p;
        struct group *g;
-       int ulen;
+       struct passwd *p;
+       size_t ulen;
 
        if (!colon)
                return 1;
 
-       ulen = lws_ptr_diff(colon, u_colon_g);
-       if (ulen < 2 || ulen > (int)sizeof(u) - 1)
+       ulen = (size_t)(unsigned int)lws_ptr_diff(colon, u_colon_g);
+       if (ulen < 2 || ulen > sizeof(u) - 1)
                return 1;
 
        memcpy(u, u_colon_g, ulen);
@@ -63,21 +68,41 @@ lws_plat_user_colon_group_to_ids(const char *u_colon_g, uid_t *puid, gid_t *pgid
 
        colon++;
 
-       g = getgrnam(colon);
-       if (!g) {
-               lwsl_err("%s: unknown group '%s'\n", __func__, colon);
+#if defined(LWS_HAVE_GETGRNAM_R)
+       {
+               struct group gr;
+               char strs[1024];
 
-               return 1;
+               if (getgrnam_r(colon, &gr, strs, sizeof(strs), &g) || !g) {
+#else
+       {
+               g = getgrnam(colon);
+               if (!g) {
+#endif
+                       lwsl_err("%s: unknown group '%s'\n", __func__, colon);
+
+                       return 1;
+               }
+               *pgid = g->gr_gid;
        }
-       *pgid = g->gr_gid;
 
-       p = getpwnam(u);
-       if (!p) {
-               lwsl_err("%s: unknown group '%s'\n", __func__, u);
+#if defined(LWS_HAVE_GETPWNAM_R)
+       {
+               struct passwd pr;
+               char strs[1024];
 
-               return 1;
+               if (getpwnam_r(u, &pr, strs, sizeof(strs), &p) || !p) {
+#else
+       {
+               p = getpwnam(u);
+               if (!p) {
+#endif
+                       lwsl_err("%s: unknown user '%s'\n", __func__, u);
+
+                       return 1;
+               }
+               *puid = p->pw_uid;
        }
-       *puid = p->pw_uid;
 
        return 0;
 }
@@ -91,14 +116,20 @@ lws_plat_drop_app_privileges(struct lws_context *context, int actually_drop)
        /* if he gave us the groupname, align gid to match it */
 
        if (context->groupname) {
-               g = getgrnam(context->groupname);
+#if defined(LWS_HAVE_GETGRNAM_R)
+               struct group gr;
+               char strs[1024];
 
+               if (!getgrnam_r(context->groupname, &gr, strs, sizeof(strs), &g) && g) {
+#else
+               g = getgrnam(context->groupname);
                if (g) {
-                       lwsl_info("%s: group %s -> gid %u\n", __func__,
+#endif
+                       lwsl_cx_info(context, "group %s -> gid %u",
                                  context->groupname, g->gr_gid);
                        context->gid = g->gr_gid;
                } else {
-                       lwsl_err("%s: unknown groupname '%s'\n", __func__,
+                       lwsl_cx_err(context, "unknown groupname '%s'",
                                 context->groupname);
 
                        return 1;
@@ -108,15 +139,21 @@ lws_plat_drop_app_privileges(struct lws_context *context, int actually_drop)
        /* if he gave us the username, align uid to match it */
 
        if (context->username) {
-               p = getpwnam(context->username);
+#if defined(LWS_HAVE_GETPWNAM_R)
+               struct passwd pr;
+               char strs[1024];
 
+               if (!getpwnam_r(context->username, &pr, strs, sizeof(strs), &p) && p) {
+#else
+               p = getpwnam(context->username);
                if (p) {
+#endif
                        context->uid = p->pw_uid;
 
-                       lwsl_info("%s: username %s -> uid %u\n", __func__,
+                       lwsl_cx_info(context, "username %s -> uid %u",
                                  context->username, (unsigned int)p->pw_uid);
                } else {
-                       lwsl_err("%s: unknown username %s\n", __func__,
+                       lwsl_cx_err(context, "unknown username %s",
                                 context->username);
 
                        return 1;
@@ -128,37 +165,48 @@ lws_plat_drop_app_privileges(struct lws_context *context, int actually_drop)
 
        /* if he gave us the gid or we have it from the groupname, set it */
 
-       if (context->gid && context->gid != -1) {
-               g = getgrgid(context->gid);
+       if (context->gid && context->gid != (gid_t)-1l) {
+#if defined(LWS_HAVE_GETGRGID_R)
+               struct group gr;
+               char strs[1024];
 
+               if (getgrgid_r(context->gid, &gr, strs, sizeof(strs), &g) || !g) {
+#else
+               g = getgrgid(context->gid);
                if (!g) {
-                       lwsl_err("%s: cannot find name for gid %d\n",
-                                 __func__, context->gid);
+#endif
+                       lwsl_cx_err(context, "cannot find name for gid %d",
+                                       context->gid);
 
                        return 1;
                }
 
                if (setgid(context->gid)) {
-                       lwsl_err("%s: setgid: %s failed\n", __func__,
-                                strerror(LWS_ERRNO));
+                       lwsl_cx_err(context, "setgid: %s failed",
+                                   strerror(LWS_ERRNO));
 
                        return 1;
                }
 
-               lwsl_notice("%s: effective group '%s'\n", __func__,
-                           g->gr_name);
+               lwsl_cx_notice(context, "effective group '%s'", g->gr_name);
        } else
-               lwsl_info("%s: not changing group\n", __func__);
+               lwsl_cx_info(context, "not changing group");
 
 
        /* if he gave us the uid or we have it from the username, set it */
 
-       if (context->uid && context->uid != -1) {
-               p = getpwuid(context->uid);
+       if (context->uid && context->uid != (uid_t)-1l) {
+#if defined(LWS_HAVE_GETPWUID_R)
+               struct passwd pr;
+               char strs[1024];
 
+               if (getpwuid_r(context->uid, &pr, strs, sizeof(strs), &p) || !p) {
+#else
+               p = getpwuid(context->uid);
                if (!p) {
-                       lwsl_err("%s: getpwuid: unable to find uid %d\n",
-                                __func__, context->uid);
+#endif
+                       lwsl_cx_err(context, "getpwuid: unable to find uid %d",
+                                context->uid);
                        return 1;
                }
 
@@ -167,15 +215,21 @@ lws_plat_drop_app_privileges(struct lws_context *context, int actually_drop)
                                     context->count_caps);
 #endif
 
-               initgroups(p->pw_name, context->gid);
+               if (initgroups(p->pw_name,
+#if defined(__APPLE__)
+                               (int)
+#endif
+                               context->gid))
+                       return 1;
+
                if (setuid(context->uid)) {
-                       lwsl_err("%s: setuid: %s failed\n", __func__,
-                                 strerror(LWS_ERRNO));
+                       lwsl_cx_err(context, "setuid: %s failed",
+                                   strerror(LWS_ERRNO));
 
                        return 1;
                } else
-                       lwsl_notice("%s: effective user '%s'\n",
-                                   __func__, p->pw_name);
+                       lwsl_cx_notice(context, "effective user '%s'",
+                                       p->pw_name);
 
 #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
                _lws_plat_apply_caps(CAP_EFFECTIVE, context->caps,
@@ -184,12 +238,12 @@ lws_plat_drop_app_privileges(struct lws_context *context, int actually_drop)
                if (context->count_caps) {
                        int n;
                        for (n = 0; n < context->count_caps; n++)
-                               lwsl_notice("   RETAINING CAP %d\n",
+                               lwsl_cx_notice(context, "   RETAINING CAP %d",
                                            (int)context->caps[n]);
                }
 #endif
        } else
-               lwsl_info("%s: not changing user\n", __func__);
+               lwsl_cx_info(context, "not changing user");
 
        return 0;
 }
index 221d967..d6cd64d 100644 (file)
@@ -1,26 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
-#include "core/private.h"
+#endif
+#include "private-lib-core.h"
 
 struct lws *
 wsi_from_fd(const struct lws_context *context, int fd)
@@ -44,11 +49,85 @@ wsi_from_fd(const struct lws_context *context, int fd)
        return NULL;
 }
 
+#if defined(_DEBUG)
+int
+sanity_assert_no_wsi_traces(const struct lws_context *context, struct lws *wsi)
+{
+       struct lws **p, **done;
+
+       if (!context->max_fds_unrelated_to_ulimit)
+               /* can't tell */
+               return 0;
+
+       /* slow fds handling */
+
+       p = context->lws_lookup;
+       done = &p[context->max_fds];
+
+       /* confirm the wsi doesn't already exist */
+
+       while (p != done && *p != wsi)
+               p++;
+
+       if (p == done)
+               return 0;
+
+       assert(0); /* this wsi is still mentioned inside lws */
+
+       return 1;
+}
+
+int
+sanity_assert_no_sockfd_traces(const struct lws_context *context,
+                              lws_sockfd_type sfd)
+{
+#if LWS_MAX_SMP > 1
+       /*
+        * We can't really do this test... another thread can accept and
+        * reuse the closed fd
+        */
+       return 0;
+#else
+       struct lws **p, **done;
+
+       if (sfd == LWS_SOCK_INVALID || !context->lws_lookup)
+               return 0;
+
+       if (!context->max_fds_unrelated_to_ulimit &&
+           context->lws_lookup[sfd - lws_plat_socket_offset()]) {
+               assert(0); /* the fd is still in use */
+               return 1;
+       }
+
+       /* slow fds handling */
+
+       p = context->lws_lookup;
+       done = &p[context->max_fds];
+
+       /* confirm the sfd not already in use */
+
+       while (p != done && (!*p || (*p)->desc.sockfd != sfd))
+               p++;
+
+       if (p == done)
+               return 0;
+
+       assert(0); /* this fd is still in the tables */
+
+       return 1;
+#endif
+}
+#endif
+
+
 int
 insert_wsi(const struct lws_context *context, struct lws *wsi)
 {
        struct lws **p, **done;
 
+       if (sanity_assert_no_wsi_traces(context, wsi))
+               return 0;
+
        if (!context->max_fds_unrelated_to_ulimit) {
                assert(context->lws_lookup[wsi->desc.sockfd -
                                           lws_plat_socket_offset()] == 0);
@@ -64,28 +143,12 @@ insert_wsi(const struct lws_context *context, struct lws *wsi)
        p = context->lws_lookup;
        done = &p[context->max_fds];
 
-#if defined(_DEBUG)
-
-       /* confirm it doesn't already exist */
-
-       while (p != done && *p != wsi)
-               p++;
+       /* confirm fd isn't already in use by a wsi */
 
-       assert(p == done);
-       p = context->lws_lookup;
-
-       /* confirm fd doesn't already exist */
-
-       while (p != done && (!*p || (*p && (*p)->desc.sockfd != wsi->desc.sockfd)))
-               p++;
+       if (sanity_assert_no_sockfd_traces(context, wsi->desc.sockfd))
+               return 0;
 
-       if (p != done) {
-               lwsl_err("%s: wsi %p already says it has fd %d\n",
-                               __func__, *p, wsi->desc.sockfd);
-               assert(0);
-       }
        p = context->lws_lookup;
-#endif
 
        /* find an empty slot */
 
@@ -102,6 +165,8 @@ insert_wsi(const struct lws_context *context, struct lws *wsi)
        return 0;
 }
 
+
+
 void
 delete_from_fd(const struct lws_context *context, int fd)
 {
@@ -109,7 +174,8 @@ delete_from_fd(const struct lws_context *context, int fd)
        struct lws **p, **done;
 
        if (!context->max_fds_unrelated_to_ulimit) {
-               context->lws_lookup[fd - lws_plat_socket_offset()] = NULL;
+               if (context->lws_lookup)
+                       context->lws_lookup[fd - lws_plat_socket_offset()] = NULL;
 
                return;
        }
@@ -117,21 +183,21 @@ delete_from_fd(const struct lws_context *context, int fd)
        /* slow fds handling */
 
        p = context->lws_lookup;
+       assert(p);
+
        done = &p[context->max_fds];
 
        /* find the match */
 
-       while (p != done && (!*p || (*p && (*p)->desc.sockfd != fd)))
+       while (p != done && (!*p || (*p)->desc.sockfd != fd))
                p++;
 
-       if (p == done)
-               lwsl_err("%s: fd %d not found\n", __func__, fd);
-       else
+       if (p != done)
                *p = NULL;
 
 #if defined(_DEBUG)
        p = context->lws_lookup;
-       while (p != done && (!*p || (*p && (*p)->desc.sockfd != fd)))
+       while (p != done && (!*p || (*p)->desc.sockfd != fd))
                p++;
 
        if (p != done) {
@@ -143,6 +209,30 @@ delete_from_fd(const struct lws_context *context, int fd)
 }
 
 void
+delete_from_fdwsi(const struct lws_context *context, struct lws *wsi)
+{
+
+       struct lws **p, **done;
+
+       if (!context->max_fds_unrelated_to_ulimit)
+               return;
+
+
+       /* slow fds handling */
+
+       p = context->lws_lookup;
+       done = &p[context->max_fds];
+
+       /* find the match */
+
+       while (p != done && (!*p || (*p) != wsi))
+               p++;
+
+       if (p != done)
+               *p = NULL;
+}
+
+void
 lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
 {
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
index bcdc213..81cbb22 100644 (file)
@@ -1,26 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
-#include "core/private.h"
+#endif
+#include "private-lib-core.h"
 
 #include <pwd.h>
 #include <grp.h>
@@ -39,9 +44,10 @@ int lws_plat_apply_FD_CLOEXEC(int n)
 }
 
 int
-lws_plat_write_file(const char *filename, void *buf, int len)
+lws_plat_write_file(const char *filename, void *buf, size_t len)
 {
-       int m, fd;
+       ssize_t m;
+       int fd;
 
        fd = lws_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
 
@@ -51,20 +57,25 @@ lws_plat_write_file(const char *filename, void *buf, int len)
        m = write(fd, buf, len);
        close(fd);
 
-       return m != len;
+       if (m < 0)
+               return 1;
+
+       return (size_t)m != len;
 }
 
 int
-lws_plat_read_file(const char *filename, void *buf, int len)
+lws_plat_read_file(const char *filename, void *buf, size_t len)
 {
-       int n, fd = lws_open(filename, O_RDONLY);
+       int fd = lws_open(filename, O_RDONLY);
+       ssize_t n;
+
        if (fd == -1)
                return -1;
 
        n = read(fd, buf, len);
        close(fd);
 
-       return n;
+       return (int)n;
 }
 
 lws_fop_fd_t
@@ -89,7 +100,7 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
        fop_fd->flags = *flags;
        fop_fd->fd = ret;
        fop_fd->filesystem_priv = NULL; /* we don't use it */
-       fop_fd->len = stat_buf.st_size;
+       fop_fd->len = (lws_filepos_t)stat_buf.st_size;
        fop_fd->pos = 0;
 
        return fop_fd;
@@ -117,15 +128,15 @@ _lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
 
        if (offset > 0 &&
            offset > (lws_fileofs_t)fop_fd->len - (lws_fileofs_t)fop_fd->pos)
-               offset = fop_fd->len - fop_fd->pos;
+               offset = (lws_fileofs_t)(fop_fd->len - fop_fd->pos);
 
        if ((lws_fileofs_t)fop_fd->pos + offset < 0)
-               offset = -fop_fd->pos;
+               offset = (lws_fileofs_t)(-fop_fd->pos);
 
-       r = lseek(fop_fd->fd, offset, SEEK_CUR);
+       r = lseek(fop_fd->fd, (off_t)offset, SEEK_CUR);
 
        if (r >= 0)
-               fop_fd->pos = r;
+               fop_fd->pos = (lws_filepos_t)r;
        else
                lwsl_err("error seeking from cur %ld, offset %ld\n",
                         (long)fop_fd->pos, (long)offset);
@@ -137,17 +148,18 @@ int
 _lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
                    uint8_t *buf, lws_filepos_t len)
 {
-       long n;
+       ssize_t n;
 
-       n = read((int)fop_fd->fd, buf, len);
-       if (n == -1) {
+       n = read((int)fop_fd->fd, buf, (size_t)len);
+       if (n == -1l) {
                *amount = 0;
                return -1;
        }
-       fop_fd->pos += n;
-       lwsl_debug("%s: read %ld of req %ld, pos %ld, len %ld\n", __func__, n,
-                  (long)len, (long)fop_fd->pos, (long)fop_fd->len);
-       *amount = n;
+       fop_fd->pos = (lws_filepos_t)(fop_fd->pos + (lws_filepos_t)n);
+       lwsl_debug("%s: read %ld of req %ld, pos %ld, len %ld\n", __func__,
+                       (long)n, (long)len, (long)fop_fd->pos,
+                       (long)fop_fd->len);
+       *amount = (lws_filepos_t)n;
 
        return 0;
 }
@@ -156,16 +168,16 @@ int
 _lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
                     uint8_t *buf, lws_filepos_t len)
 {
-       long n;
+       ssize_t n;
 
-       n = write((int)fop_fd->fd, buf, len);
+       n = write((int)fop_fd->fd, buf, (size_t)len);
        if (n == -1) {
                *amount = 0;
                return -1;
        }
 
-       fop_fd->pos += n;
-       *amount = n;
+       fop_fd->pos = (lws_filepos_t)(fop_fd->pos + (lws_filepos_t)n);
+       *amount = (lws_filepos_t)n;
 
        return 0;
 }
index 565c7ca..46f072f 100644 (file)
@@ -1,26 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
-#include "core/private.h"
+#endif
+#include "private-lib-core.h"
 
 #include <pwd.h>
 #include <grp.h>
@@ -37,9 +42,7 @@ lws_sul_plat_unix(lws_sorted_usec_list_t *sul)
        struct lws_context_per_thread *pt =
                lws_container_of(sul, struct lws_context_per_thread, sul_plat);
        struct lws_context *context = pt->context;
-#if defined(LWS_ROLE_CGI) || defined(LWS_ROLE_DBUS)
-       time_t now = time(NULL);
-#endif
+       int n = 0, m = 0;
 
 #if !defined(LWS_NO_DAEMONIZE)
        /* if our parent went down, don't linger around */
@@ -48,14 +51,16 @@ lws_sul_plat_unix(lws_sorted_usec_list_t *sul)
                kill(getpid(), SIGTERM);
 #endif
 
-       if (pt->context->deprecated && !pt->context->count_wsi_allocated) {
+       for (n = 0; n < context->count_threads; n++)
+               m = m | (int)pt->fds_count;
+
+       if (context->deprecated && !m) {
                lwsl_notice("%s: ending deprecated context\n", __func__);
                kill(getpid(), SIGINT);
                return;
        }
 
-       lws_check_deferred_free(context, 0, 0);
-
+#if defined(LWS_WITH_SERVER)
        lws_context_lock(context, "periodic checks");
        lws_start_foreach_llp(struct lws_vhost **, pv,
                              context->no_listener_vhost_list) {
@@ -70,15 +75,27 @@ lws_sul_plat_unix(lws_sorted_usec_list_t *sul)
                }
        } lws_end_foreach_llp(pv, no_listener_vhost_list);
        lws_context_unlock(context);
-
-#if defined(LWS_ROLE_CGI)
-       role_ops_cgi.periodic_checks(context, 0, now);
 #endif
-#if defined(LWS_ROLE_DBUS)
-       role_ops_dbus.periodic_checks(context, 0, now);
+
+       __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                           &pt->sul_plat, 30 * LWS_US_PER_SEC);
+}
 #endif
 
-       __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_plat, 30 * LWS_US_PER_SEC);
+#if defined(LWS_WITH_PLUGINS)
+static int
+protocol_plugin_cb(struct lws_plugin *pin, void *each_user)
+{
+       struct lws_context *context = (struct lws_context *)each_user;
+       const lws_plugin_protocol_t *plpr =
+                       (const lws_plugin_protocol_t *)pin->hdr;
+
+       context->plugin_protocol_count = (short)(context->plugin_protocol_count +
+                                                plpr->count_protocols);
+       context->plugin_extension_count = (short)(context->plugin_extension_count +
+                                                 plpr->count_extensions);
+
+       return 0;
 }
 #endif
 
@@ -89,7 +106,7 @@ lws_plat_init(struct lws_context *context,
        int fd;
 #if defined(LWS_WITH_NETWORK)
        /*
-        * master context has the process-global fd lookup array.  This can be
+        * context has the process-global fd lookup array.  This can be
         * done two different ways now; one or the other is done depending on if
         * info->fd_limit_per_thread was snonzero
         *
@@ -114,26 +131,71 @@ lws_plat_init(struct lws_context *context,
                                         context->max_fds, "lws_lookup");
 
        if (!context->lws_lookup) {
-               lwsl_err("%s: OOM on alloc lws_lookup array for %d conn\n",
-                        __func__, context->max_fds);
+               lwsl_cx_err(context, "OOM on alloc lws_lookup array for %d conn",
+                        context->max_fds);
                return 1;
        }
 
-       lwsl_info(" mem: platform fd map: %5lu B\n",
+#if defined(LWS_WITH_MBEDTLS)
+       {
+               int n;
+
+               /* initialize platform random through mbedtls */
+               mbedtls_entropy_init(&context->mec);
+               mbedtls_ctr_drbg_init(&context->mcdc);
+
+               n = mbedtls_ctr_drbg_seed(&context->mcdc, mbedtls_entropy_func,
+                                         &context->mec, NULL, 0);
+               if (n)
+                       lwsl_err("%s: mbedtls_ctr_drbg_seed() returned 0x%x\n",
+                                __func__, n);
+#if 0
+               else {
+                       uint8_t rtest[16];
+                       lwsl_notice("%s: started drbg\n", __func__);
+                       if (mbedtls_ctr_drbg_random(&context->mcdc, rtest,
+                                                       sizeof(rtest)))
+                               lwsl_err("%s: get random failed\n", __func__);
+                       else
+                               lwsl_hexdump_notice(rtest, sizeof(rtest));
+               }
+#endif
+       }
+#endif
+
+       lwsl_cx_info(context, " mem: platform fd map: %5lu B",
                    (unsigned long)(sizeof(struct lws *) * context->max_fds));
 #endif
+#if defined(LWS_WITH_FILE_OPS)
        fd = lws_open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
-
+#else
+       fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
+#endif
        context->fd_random = fd;
        if (context->fd_random < 0) {
-               lwsl_err("Unable to open random device %s %d\n",
-                        SYSTEM_RANDOM_FILEPATH, context->fd_random);
+               lwsl_err("Unable to open random device %s %d, errno %d\n",
+                        SYSTEM_RANDOM_FILEPATH, context->fd_random, errno);
                return 1;
        }
 
 #if defined(LWS_WITH_PLUGINS)
-       if (info->plugin_dirs)
-               lws_plat_plugins_init(context, info->plugin_dirs);
+       {
+               char *ld_env = getenv("LD_LIBRARY_PATH");
+
+               if (ld_env) {
+                       const char *pp[2] = { ld_env, NULL };
+
+                       lws_plugins_init(&context->plugin_list, pp,
+                                        "lws_protocol_plugin", NULL,
+                                        protocol_plugin_cb, context);
+               }
+
+               if (info->plugin_dirs)
+                       lws_plugins_init(&context->plugin_list,
+                                        info->plugin_dirs,
+                                        "lws_protocol_plugin", NULL,
+                                        protocol_plugin_cb, context);
+       }
 #endif
 
 
@@ -141,8 +203,8 @@ lws_plat_init(struct lws_context *context,
        /* we only need to do this on pt[0] */
 
        context->pt[0].sul_plat.cb = lws_sul_plat_unix;
-       __lws_sul_insert(&context->pt[0].pt_sul_owner, &context->pt[0].sul_plat,
-                        30 * LWS_US_PER_SEC);
+       __lws_sul_insert_us(&context->pt[0].pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                           &context->pt[0].sul_plat, 30 * LWS_US_PER_SEC);
 #endif
 
        return 0;
@@ -166,9 +228,9 @@ lws_plat_context_early_destroy(struct lws_context *context)
 void
 lws_plat_context_late_destroy(struct lws_context *context)
 {
-#ifdef LWS_WITH_PLUGINS
+#if defined(LWS_WITH_PLUGINS)
        if (context->plugin_list)
-               lws_plat_plugins_destroy(context);
+               lws_plugins_destroy(&context->plugin_list, NULL, NULL);
 #endif
 #if defined(LWS_WITH_NETWORK)
        if (context->lws_lookup)
index 6f8383a..fce5e42 100644 (file)
@@ -1,26 +1,43 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
-#include "core/private.h"
+#endif
+#include "private-lib-core.h"
+
+/*
+ * Normally you don't want this, use lws_sul instead inside the event loop.
+ * But sometimes for drivers it makes sense, so there's an internal-only
+ * crossplatform api for it.
+ */
+
+void
+lws_msleep(unsigned int ms)
+{
+        usleep((unsigned int)(ms * LWS_US_PER_MS));
+}
 
 lws_usec_t
 lws_now_usecs(void)
@@ -42,13 +59,19 @@ lws_now_usecs(void)
 #endif
 }
 
-LWS_VISIBLE int
-lws_get_random(struct lws_context *context, void *buf, int len)
+size_t
+lws_get_random(struct lws_context *context, void *buf, size_t len)
 {
-       return read(context->fd_random, (char *)buf, len);
+#if defined(__COVERITY__)
+       memset(buf, 0, len);
+       return len;
+#else
+       /* coverity[tainted_scalar] */
+       return (size_t)read(context->fd_random, (char *)buf, len);
+#endif
 }
 
-LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
+void lwsl_emit_syslog(int level, const char *line)
 {
        int syslog_level = LOG_DEBUG;
 
@@ -72,17 +95,18 @@ LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
 
 int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
-                       int len)
+                       size_t len)
 {
-       int n;
+       ssize_t n;
 
        n = write(fd, buf, len);
 
-       fsync(fd);
+       if (n < 0 || fsync(fd))
+               return 1;
        if (lseek(fd, 0, SEEK_SET) < 0)
                return 1;
 
-       return n != len;
+       return (size_t)n != len;
 }
 
 
@@ -91,3 +115,28 @@ lws_plat_recommended_rsa_bits(void)
 {
        return 4096;
 }
+
+/*
+ * Platform-specific ntpclient server configuration
+ */
+
+int
+lws_plat_ntpclient_config(struct lws_context *context)
+{
+#if defined(LWS_HAVE_GETENV)
+       char *ntpsrv = getenv("LWS_NTP_SERVER");
+
+       if (ntpsrv && strlen(ntpsrv) < 64) {
+               lws_system_blob_t *blob = lws_system_get_blob(context,
+                                            LWS_SYSBLOB_TYPE_NTP_SERVER, 0);
+               if (!blob)
+                       return 0;
+
+               lws_system_blob_direct_set(blob, (const uint8_t *)ntpsrv,
+                                           strlen(ntpsrv));
+               return 1;
+       }
+#endif
+       return 0;
+}
+
index f6d3d40..ad04acb 100644 (file)
@@ -1,55 +1,79 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
-#include "core/private.h"
-
+#endif
+#include "private-lib-core.h"
 
 int
 lws_plat_pipe_create(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       int n;
+
 #if defined(LWS_HAVE_EVENTFD)
-       pt->dummy_pipe_fds[0] = eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK);
+       pt->dummy_pipe_fds[0] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        pt->dummy_pipe_fds[1] = -1;
-       return pt->dummy_pipe_fds[0]<0?-1:0;
+
+       n = pt->dummy_pipe_fds[0] < 0 ? -1 : 0;
+       goto set;
+
 #elif defined(LWS_HAVE_PIPE2)
-       return pipe2(pt->dummy_pipe_fds, O_NONBLOCK);
+       n = pipe2(pt->dummy_pipe_fds, O_NONBLOCK);
 #else
-       return pipe(pt->dummy_pipe_fds);
+       n = pipe(pt->dummy_pipe_fds);
 #endif
+
+#if defined(LWS_HAVE_EVENTFD)
+set:
+#endif
+       if (n >= 0) {
+               if (fcntl(pt->dummy_pipe_fds[0], F_SETFL, O_NONBLOCK) < 0)
+                       n = -1;
+               else if (pt->dummy_pipe_fds[1] >= 0) {
+                       if (fcntl(pt->dummy_pipe_fds[1], F_SETFL, O_NONBLOCK) < 0)
+                               n = -1;
+               }
+       }
+
+       return n;
 }
 
 int
-lws_plat_pipe_signal(struct lws *wsi)
+lws_plat_pipe_signal(struct lws_context *ctx, int tsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &ctx->pt[tsi];
 #if defined(LWS_HAVE_EVENTFD)
        eventfd_t value = 1;
+
        return eventfd_write(pt->dummy_pipe_fds[0], value);
 #else
        char buf = 0;
        int n;
 
-       n = write(pt->dummy_pipe_fds[1], &buf, 1);
+       n = (int)write(pt->dummy_pipe_fds[1], &buf, 1);
 
        return n != 1;
 #endif
@@ -58,7 +82,7 @@ lws_plat_pipe_signal(struct lws *wsi)
 void
 lws_plat_pipe_close(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
 
        if (pt->dummy_pipe_fds[0] && pt->dummy_pipe_fds[0] != -1)
                close(pt->dummy_pipe_fds[0]);
@@ -67,4 +91,3 @@ lws_plat_pipe_close(struct lws *wsi)
 
        pt->dummy_pipe_fds[0] = pt->dummy_pipe_fds[1] = -1;
 }
-
index a56046a..55271bb 100644 (file)
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
-#include "core/private.h"
+#endif
+#include "private-lib-core.h"
 
 #include <pwd.h>
 #include <grp.h>
-
-#ifdef LWS_WITH_PLUGINS
 #include <dlfcn.h>
-#endif
-#include <dirent.h>
 
-static int filter(const struct dirent *ent)
+const lws_plugin_header_t *
+lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath,
+               const char *sofilename, const char *_class,
+               each_plugin_cb_t each, void *each_user)
 {
-       if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
-               return 0;
+       const lws_plugin_header_t *hdr;
+       struct lws_plugin *pin;
+       char sym[96];
+       void *l;
+       int m;
 
-       return 1;
-}
+       if (strlen(sofilename) < 6)
+               /* [lib]...[.so] */
+               return NULL;
 
-int
-lws_plat_plugins_init(struct lws_context * context, const char * const *d)
-{
-       struct lws_plugin_capability lcaps;
-       struct lws_plugin *plugin;
-       lws_plugin_init_func initfunc;
-       struct dirent **namelist;
-       int n, i, m, ret = 0;
-       char path[256];
-       void *l;
+       lwsl_info("   trying %s\n", libpath);
 
-#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
-       if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
-               return lws_uv_plugins_init(context, d);
-#endif
+       l = dlopen(libpath, RTLD_NOW);
+       if (!l) {
+               lwsl_info("%s: Error loading DSO: %s\n", __func__, dlerror());
 
-       lwsl_notice("  Plugins:\n");
-
-       while (d && *d) {
-               n = scandir(*d, &namelist, filter, alphasort);
-               if (n < 0) {
-                       lwsl_err("Scandir on %s failed\n", *d);
-                       return 1;
-               }
-
-               for (i = 0; i < n; i++) {
-                       if (strlen(namelist[i]->d_name) < 7)
-                               goto inval;
-
-                       lwsl_notice("   %s\n", namelist[i]->d_name);
-
-                       lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d,
-                                namelist[i]->d_name);
-                       l = dlopen(path, RTLD_NOW);
-                       if (!l) {
-                               lwsl_err("Error loading DSO: %s\n", dlerror());
-                               while (i++ < n)
-                                       free(namelist[i]);
-                               goto bail;
-                       }
-                       /* we could open it, can we get his init function? */
-                       m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
-                                    namelist[i]->d_name + 3 /* snip lib... */);
-                       path[m - 3] = '\0'; /* snip the .so */
-                       initfunc = dlsym(l, path);
-                       if (!initfunc) {
-                               lwsl_err("Failed to get init on %s: %s",
-                                               namelist[i]->d_name, dlerror());
-                               dlclose(l);
-                       }
-                       lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
-                       m = initfunc(context, &lcaps);
-                       if (m) {
-                               lwsl_err("Initializing %s failed %d\n",
-                                       namelist[i]->d_name, m);
-                               dlclose(l);
-                               goto skip;
-                       }
-
-                       plugin = lws_malloc(sizeof(*plugin), "plugin");
-                       if (!plugin) {
-                               lwsl_err("OOM\n");
-                               goto bail;
-                       }
-                       plugin->list = context->plugin_list;
-                       context->plugin_list = plugin;
-                       lws_strncpy(plugin->name, namelist[i]->d_name,
-                                   sizeof(plugin->name));
-                       plugin->l = l;
-                       plugin->caps = lcaps;
-                       context->plugin_protocol_count += lcaps.count_protocols;
-                       context->plugin_extension_count += lcaps.count_extensions;
-
-                       free(namelist[i]);
-                       continue;
-
-       skip:
-                       dlclose(l);
-       inval:
-                       free(namelist[i]);
-               }
-               free(namelist);
-               d++;
+               return NULL;
        }
 
-       return 0;
+       /* we could open it... can we get his export struct? */
+       m = lws_snprintf(sym, sizeof(sym) - 1, "%s", sofilename);
+       if (m < 4)
+               goto bail;
+       if (!strcmp(&sym[m - 3], ".so"))
+               sym[m - 3] = '\0'; /* snip the .so */
+
+       hdr = (const lws_plugin_header_t *)dlsym(l, sym);
+       if (!hdr) {
+               lwsl_info("%s: Failed to get export '%s' from %s: %s\n",
+                        __func__, sym, libpath, dlerror());
+               goto bail;
+       }
 
-bail:
-       free(namelist);
+       if (hdr->api_magic != LWS_PLUGIN_API_MAGIC) {
+               lwsl_info("%s: plugin %s has outdated api %d (vs %d)\n",
+                        __func__, libpath, hdr->api_magic,
+                        LWS_PLUGIN_API_MAGIC);
+               goto bail;
+       }
 
-       return ret;
-}
+       if (strcmp(hdr->lws_build_hash, LWS_BUILD_HASH))
+               goto bail;
 
-int
-lws_plat_plugins_destroy(struct lws_context * context)
-{
-       struct lws_plugin *plugin = context->plugin_list, *p;
-       lws_plugin_destroy_func func;
-       char path[256];
-       int m;
+       if (strcmp(hdr->_class, _class))
+               goto bail;
 
-#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
-       if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
-               return lws_uv_plugins_destroy(context);
-#endif
+       /*
+        * We don't already have one of these, right?
+        */
 
-       if (!plugin)
-               return 0;
-
-       lwsl_notice("%s\n", __func__);
-
-       while (plugin) {
-               p = plugin;
-               m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s",
-                                plugin->name + 3);
-               path[m - 3] = '\0';
-               func = dlsym(plugin->l, path);
-               if (!func) {
-                       lwsl_err("Failed to get destroy on %s: %s",
-                                       plugin->name, dlerror());
-                       goto next;
-               }
-               m = func(context);
-               if (m)
-                       lwsl_err("Initializing %s failed %d\n",
-                               plugin->name, m);
-next:
-               dlclose(p->l);
-               plugin = p->list;
-               p->list = NULL;
-               free(p);
+       pin = *pplugin;
+       while (pin) {
+               if (!strcmp(pin->hdr->name, hdr->name))
+                       goto bail;
+               pin = pin->list;
        }
 
-       context->plugin_list = NULL;
+       /*
+        * OK let's bring it in
+        */
+
+       pin = lws_malloc(sizeof(*pin), __func__);
+       if (!pin)
+               goto bail;
+
+       pin->list = *pplugin;
+       *pplugin = pin;
+
+       pin->u.l = l;
+       pin->hdr = hdr;
+
+       if (each)
+               each(pin, each_user);
+
+       lwsl_notice("   %s\n", libpath);
 
-       return 0;
+       return hdr;
+
+bail:
+       dlclose(l);
+
+       return NULL;
+}
+
+int
+lws_plat_destroy_dl(struct lws_plugin *p)
+{
+       return dlclose(p->u.l);
 }
diff --git a/lib/plat/unix/unix-resolv.c b/lib/plat/unix/unix-resolv.c
new file mode 100644 (file)
index 0000000..177ecad
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+lws_async_dns_server_check_t
+lws_plat_asyncdns_init(struct lws_context *context, lws_sockaddr46 *sa46)
+{
+       lws_async_dns_server_check_t s = LADNS_CONF_SERVER_CHANGED;
+       lws_sockaddr46 sa46t;
+       lws_tokenize_t ts;
+       char ads[48], *r;
+       int fd, ns = 0;
+       ssize_t n;
+
+       r = (char *)context->pt[0].serv_buf;
+
+       /* grab the first chunk of /etc/resolv.conf */
+
+       fd = open("/etc/resolv.conf", LWS_O_RDONLY);
+       if (fd < 0)
+               return LADNS_CONF_SERVER_UNKNOWN;
+
+       n = read(fd, r, context->pt_serv_buf_size - 1);
+       close(fd);
+       if (n < 0)
+               return LADNS_CONF_SERVER_UNKNOWN;
+
+       r[n] = '\0';
+       lws_tokenize_init(&ts, r, LWS_TOKENIZE_F_DOT_NONTERM |
+                                 LWS_TOKENIZE_F_NO_FLOATS |
+                                 LWS_TOKENIZE_F_NO_INTEGERS |
+                                 LWS_TOKENIZE_F_MINUS_NONTERM |
+                                 LWS_TOKENIZE_F_HASH_COMMENT);
+       do {
+               ts.e = (int8_t)lws_tokenize(&ts);
+               if (ts.e != LWS_TOKZE_TOKEN) {
+                       ns = 0;
+                       continue;
+               }
+
+               if (!ns && !strncmp("nameserver", ts.token, ts.token_len)) {
+                       ns = 1;
+                       continue;
+               }
+               if (!ns)
+                       continue;
+
+               /* we are a token just after the "nameserver" token */
+
+               ns = 0;
+               if (ts.token_len > (int)sizeof(ads) - 1)
+                       continue;
+
+               memcpy(ads, ts.token, ts.token_len);
+               ads[ts.token_len] = '\0';
+               if (lws_sa46_parse_numeric_address(ads, &sa46t) < 0)
+                       continue;
+
+               if (!lws_sa46_compare_ads(sa46, &sa46t))
+                       s = LADNS_CONF_SERVER_SAME;
+
+               *sa46 = sa46t;
+
+               return s;
+
+       } while (ts.e > 0);
+
+       return LADNS_CONF_SERVER_UNKNOWN;
+}
index 861ed14..7a38089 100644 (file)
@@ -1,26 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
-#include "core/private.h"
+#endif
+#include "private-lib-core.h"
 
 int
 lws_poll_listen_fd(struct lws_pollfd *fd)
@@ -32,12 +37,14 @@ int
 _lws_plat_service_forced_tsi(struct lws_context *context, int tsi)
 {
        struct lws_context_per_thread *pt = &context->pt[tsi];
-       int m, n;
+       int m, n, r;
 
-       lws_service_flag_pending(context, tsi);
+       r = lws_service_flag_pending(context, tsi);
 
        /* any socket with events to service? */
        for (n = 0; n < (int)pt->fds_count; n++) {
+               lws_sockfd_type fd = pt->fds[n].fd;
+
                if (!pt->fds[n].revents)
                        continue;
 
@@ -47,14 +54,16 @@ _lws_plat_service_forced_tsi(struct lws_context *context, int tsi)
                                 __func__, m);
                        return -1;
                }
-               /* if something closed, retry this slot */
-               if (m)
+
+               /* if something closed, retry this slot since may have been
+                * swapped with end fd */
+               if (m && pt->fds[n].fd != fd)
                        n--;
        }
 
        lws_service_do_ripe_rxflow(pt);
 
-       return 0;
+       return r;
 }
 
 #define LWS_POLL_WAIT_LIMIT 2000000000
@@ -66,21 +75,27 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
        volatile struct lws_context_per_thread *vpt;
        struct lws_context_per_thread *pt;
        lws_usec_t timeout_us, us;
-       int n = -1;
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_usec_t a, b;
+#endif
+       int n;
 #if (defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)) || defined(LWS_WITH_TLS)
        int m;
 #endif
 
        /* stay dead once we are dead */
 
-       if (!context || !context->vhost_list)
+       if (!context)
                return 1;
 
+#if defined(LWS_WITH_SYS_METRICS)
+       b =
+#endif
+                       us = lws_now_usecs();
+
        pt = &context->pt[tsi];
        vpt = (volatile struct lws_context_per_thread *)pt;
 
-       lws_stats_bump(pt, LWSSTATS_C_SERVICE_ENTRY, 1);
-
        if (timeout_ms < 0)
                timeout_ms = 0;
        else
@@ -91,26 +106,31 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
        if (context->event_loop_ops->run_pt)
                context->event_loop_ops->run_pt(context, tsi);
 
-       if (!pt->service_tid_detected) {
-               struct lws _lws;
+       if (!pt->service_tid_detected && context->vhost_list) {
+               lws_fakewsi_def_plwsa(pt);
 
-               memset(&_lws, 0, sizeof(_lws));
-               _lws.context = context;
+               lws_fakewsi_prep_plwsa_ctx(context);
 
                pt->service_tid = context->vhost_list->protocols[0].callback(
-                                       &_lws, LWS_CALLBACK_GET_THREAD_ID,
+                                       (struct lws *)plwsa,
+                                       LWS_CALLBACK_GET_THREAD_ID,
                                        NULL, NULL, 0);
                pt->service_tid_detected = 1;
        }
 
-       us = lws_now_usecs();
        lws_pt_lock(pt, __func__);
        /*
         * service ripe scheduled events, and limit wait to next expected one
         */
-       us = __lws_sul_service_ripe(&pt->pt_sul_owner, us);
+       us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, us);
        if (us && us < timeout_us)
-               timeout_us = us;
+               /*
+                * If something wants zero wait, that's OK, but if the next sul
+                * coming ripe is an interval less than our wait resolution,
+                * bump it to be the wait resolution.
+                */
+               timeout_us = us < context->us_wait_resolution ?
+                                       context->us_wait_resolution : us;
 
        lws_pt_unlock(pt);
 
@@ -123,24 +143,19 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
        /* ensure we don't wrap at 2^31 with poll()'s signed int ms */
 
        timeout_us /= LWS_US_PER_MS; /* ms now */
-       if (timeout_us > LWS_POLL_WAIT_LIMIT)
-               timeout_us = LWS_POLL_WAIT_LIMIT;
 
+#if defined(LWS_WITH_SYS_METRICS)
+       a = lws_now_usecs() - b;
+#endif
        vpt->inside_poll = 1;
        lws_memory_barrier();
-       n = poll(pt->fds, pt->fds_count, timeout_us /* ms now */ );
+       n = poll(pt->fds, pt->fds_count, (int)timeout_us /* ms now */ );
        vpt->inside_poll = 0;
        lws_memory_barrier();
 
-       #if defined(LWS_WITH_DETAILED_LATENCY)
-       /*
-        * so we can track how long it took before we actually read a
-        * POLLIN that was signalled when we last exited poll()
-        */
-       if (context->detailed_latency_cb)
-               pt->ust_left_poll = lws_now_usecs();
+#if defined(LWS_WITH_SYS_METRICS)
+       b = lws_now_usecs();
 #endif
-
        /* Collision will be rare and brief.  Spin until it completes */
        while (vpt->foreign_spinlock)
                ;
@@ -195,25 +210,26 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
 #if (defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)) || defined(LWS_WITH_TLS)
                !m &&
 #endif
-               !n) /* nothing to do */
+               !n) /* nothing to do */
                lws_service_do_ripe_rxflow(pt);
+       else
+               if (_lws_plat_service_forced_tsi(context, tsi) < 0)
+                       return -1;
 
-               return 0;
-       }
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_metric_event(context->mt_service, METRES_GO,
+                        (u_mt_t) (a + (lws_now_usecs() - b)));
+#endif
 
-       if (_lws_plat_service_forced_tsi(context, tsi))
+       if (pt->destroy_self) {
+               lws_context_destroy(pt->context);
                return -1;
+       }
 
        return 0;
 }
 
 int
-lws_plat_check_connection_error(struct lws *wsi)
-{
-       return 0;
-}
-
-int
 lws_plat_service(struct lws_context *context, int timeout_ms)
 {
        return _lws_plat_service_tsi(context, timeout_ms, 0);
index e356f91..07df994 100644 (file)
@@ -1,31 +1,52 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+#if !defined(_GNU_SOURCE)
 #define _GNU_SOURCE
-#include "core/private.h"
+#endif
+#include "private-lib-core.h"
+
+#include <sys/ioctl.h>
+
+#if !defined(LWS_DETECTED_PLAT_IOS)
+#include <net/route.h>
+#endif
+
+#include <net/if.h>
 
 #include <pwd.h>
 #include <grp.h>
 
+#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_HAVE_MBEDTLS_NET_SOCKETS)
+#include "mbedtls/net_sockets.h"
+#else
+#include "mbedtls/net.h"
+#endif
+#endif
 
+#include <netinet/ip.h>
 
 int
 lws_send_pipe_choked(struct lws *wsi)
@@ -72,7 +93,7 @@ lws_send_pipe_choked(struct lws *wsi)
 }
 
 int
-lws_plat_set_nonblocking(int fd)
+lws_plat_set_nonblocking(lws_sockfd_type fd)
 {
        return fcntl(fd, F_SETFL, O_NONBLOCK) < 0;
 }
@@ -141,7 +162,7 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
        if (!unix_skt && vhost->bind_iface && vhost->iface) {
                lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface);
                if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface,
-                               strlen(vhost->iface)) < 0) {
+                               (socklen_t)strlen(vhost->iface)) < 0) {
                        lwsl_warn("Failed to bind to device %s\n", vhost->iface);
                        return 1;
                }
@@ -169,9 +190,102 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
        return lws_plat_set_nonblocking(fd);
 }
 
+static const int ip_opt_lws_flags[] = {
+       LCCSCF_IP_LOW_LATENCY, LCCSCF_IP_HIGH_THROUGHPUT,
+       LCCSCF_IP_HIGH_RELIABILITY
+#if !defined(__OpenBSD__)
+       , LCCSCF_IP_LOW_COST
+#endif
+}, ip_opt_val[] = {
+       IPTOS_LOWDELAY, IPTOS_THROUGHPUT, IPTOS_RELIABILITY
+#if !defined(__OpenBSD__) && !defined(__sun)
+       , IPTOS_MINCOST
+#endif
+};
+#if !defined(LWS_WITH_NO_LOGS)
+static const char *ip_opt_names[] = {
+       "LOWDELAY", "THROUGHPUT", "RELIABILITY"
+#if !defined(__OpenBSD__) && !defined(__sun)
+       , "MINCOST"
+#endif
+};
+#endif
+
+int
+lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags)
+{
+       int optval = (int)pri, ret = 0, n;
+       socklen_t optlen = sizeof(optval);
+#if !defined(LWS_WITH_NO_LOGS)
+       int en;
+#endif
+
+#if 0
+#if defined(TCP_FASTOPEN_CONNECT)
+       optval = 1;
+       if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&optval,
+                      sizeof(optval)))
+               lwsl_warn("%s: FASTOPEN_CONNECT failed\n", __func__);
+       optval = (int)pri;
+#endif
+#endif
+
+#if !defined(__APPLE__) && \
+      !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) &&        \
+      !defined(__NetBSD__) && \
+      !defined(__OpenBSD__) && \
+      !defined(__sun) && \
+      !defined(__HAIKU__) && \
+      !defined(__CYGWIN__) && \
+      !defined(__QNX__)
+
+       /* the BSDs don't have SO_PRIORITY */
+
+       if (pri) { /* 0 is the default already */
+               if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY,
+                               (const void *)&optval, optlen) < 0) {
+#if !defined(LWS_WITH_NO_LOGS)
+                       en = errno;
+                       lwsl_warn("%s: unable to set socket pri %d: errno %d\n",
+                                 __func__, (int)pri, en);
+#endif
+                       ret = 1;
+               } else
+                       lwsl_notice("%s: set pri %u\n", __func__, pri);
+       }
+#endif
+
+       for (n = 0; n < 4; n++) {
+               if (!(lws_flags & ip_opt_lws_flags[n]))
+                       continue;
+
+               optval = (int)ip_opt_val[n];
+               if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *)&optval,
+                              optlen) < 0) {
+#if !defined(LWS_WITH_NO_LOGS)
+                       en = errno;
+                       lwsl_warn("%s: unable to set %s: errno %d\n", __func__,
+                                 ip_opt_names[n], en);
+#endif
+                       ret = 1;
+               } else
+                       lwsl_notice("%s: set ip flag %s\n", __func__,
+                                   ip_opt_names[n]);
+       }
+
+       return ret;
+}
 
 /* cast a struct sockaddr_in6 * into addr for ipv6 */
 
+enum {
+       IP_SCORE_NONE,
+       IP_SCORE_NONNATIVE,
+       IP_SCORE_IPV6_SCOPE_BASE,
+       /* ipv6 scopes */
+       IP_SCORE_GLOBAL_NATIVE = 18
+};
+
 int
 lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
                    size_t addrlen)
@@ -180,13 +294,20 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
 
        struct ifaddrs *ifr;
        struct ifaddrs *ifc;
-#ifdef LWS_WITH_IPV6
+#if defined(LWS_WITH_IPV6)
        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
+       unsigned long sco = IP_SCORE_NONE;
+       unsigned long ts;
+       const uint8_t *p;
 #endif
 
-       getifaddrs(&ifr);
-       for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
-               if (!ifc->ifa_addr)
+       if (getifaddrs(&ifr)) {
+               lwsl_err("%s: unable to getifaddrs: errno %d\n", __func__, errno);
+
+               return LWS_ITOSA_USABLE;
+       }
+       for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) {
+               if (!ifc->ifa_addr || !ifc->ifa_name)
                        continue;
 
                lwsl_debug(" interface %s vs %s (fam %d) ipv6 %d\n",
@@ -200,13 +321,19 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
 #if defined(AF_PACKET)
                case AF_PACKET:
                        /* interface exists but is not usable */
-                       rc = LWS_ITOSA_NOT_USABLE;
+                       if (rc == LWS_ITOSA_NOT_EXIST)
+                               rc = LWS_ITOSA_NOT_USABLE;
                        continue;
 #endif
 
                case AF_INET:
-#ifdef LWS_WITH_IPV6
+#if defined(LWS_WITH_IPV6)
                        if (ipv6) {
+                               /* any existing solution is better than this */
+                               if (sco != IP_SCORE_NONE)
+                                       break;
+                               sco = IP_SCORE_NONNATIVE;
+                               rc = LWS_ITOSA_USABLE;
                                /* map IPv4 to IPv6 */
                                memset((char *)&addr6->sin6_addr, 0,
                                                sizeof(struct in6_addr));
@@ -216,44 +343,51 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
                                       &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
                                                        sizeof(struct in_addr));
                                lwsl_debug("%s: uplevelling ipv4 bind to ipv6\n", __func__);
-                       } else
+                               break;
+                       }
+
+                       sco = IP_SCORE_GLOBAL_NATIVE;
 #endif
-                               memcpy(addr,
-                                       (struct sockaddr_in *)ifc->ifa_addr,
+                       rc = LWS_ITOSA_USABLE;
+                       memcpy(addr, (struct sockaddr_in *)ifc->ifa_addr,
                                                    sizeof(struct sockaddr_in));
                        break;
-#ifdef LWS_WITH_IPV6
+#if defined(LWS_WITH_IPV6)
                case AF_INET6:
+                       p = (const uint8_t *)
+                               &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr;
+                       ts = IP_SCORE_IPV6_SCOPE_BASE;
+                       if (p[0] == 0xff)
+                               ts = (unsigned long)(IP_SCORE_IPV6_SCOPE_BASE + (p[1] & 0xf));
+
+                       if (sco >= ts)
+                               break;
+
+                       sco = ts;
+                       rc = LWS_ITOSA_USABLE;
+
                        memcpy(&addr6->sin6_addr,
-                         &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
+                            &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
                                                       sizeof(struct in6_addr));
                        break;
 #endif
                default:
-                       continue;
+                       break;
                }
-               rc = LWS_ITOSA_USABLE;
        }
 
        freeifaddrs(ifr);
 
-       if (rc) {
-               /* check if bind to IP address */
-#ifdef LWS_WITH_IPV6
-               if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
-                       rc = LWS_ITOSA_USABLE;
-               else
-#endif
-               if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
-                       rc = LWS_ITOSA_USABLE;
-       }
+       if (rc &&
+           !lws_sa46_parse_numeric_address(ifname, (lws_sockaddr46 *)addr))
+               rc = LWS_ITOSA_USABLE;
 
        return rc;
 }
 
 
 const char *
-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
+lws_plat_inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
 {
        return inet_ntop(af, src, dst, cnt);
 }
@@ -263,3 +397,242 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
 {
        return inet_pton(af, src, dst);
 }
+
+int
+lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
+{
+#if defined(__linux__)
+       struct ifreq i;
+
+       memset(&i, 0, sizeof(i));
+       lws_strncpy(i.ifr_name, ifname, sizeof(i.ifr_name));
+
+       if (ioctl(fd, SIOCGIFHWADDR, &i) < 0)
+               return -1;
+
+       memcpy(hwaddr, &i.ifr_hwaddr.sa_data, 6);
+
+       return 6;
+#else
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+#endif
+}
+
+int
+lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, size_t canned_len,
+                         size_t n, int fd, const char *iface)
+{
+#if defined(__linux__)
+       struct sockaddr_ll sll;
+       uint16_t *p16 = (uint16_t *)p;
+       uint32_t ucs = 0;
+
+       memcpy(p, canned, canned_len);
+
+       p[2] = (uint8_t)(n >> 8);
+       p[3] = (uint8_t)(n);
+
+       while (p16 < (uint16_t *)(p + 20))
+               ucs += ntohs(*p16++);
+
+       ucs += ucs >> 16;
+       ucs ^= 0xffff;
+
+       p[10] = (uint8_t)(ucs >> 8);
+       p[11] = (uint8_t)(ucs);
+       p[24] = (uint8_t)((n - 20) >> 8);
+       p[25] = (uint8_t)((n - 20));
+
+       memset(&sll, 0, sizeof(sll));
+       sll.sll_family = AF_PACKET;
+       sll.sll_protocol = htons(0x800);
+       sll.sll_halen = 6;
+       sll.sll_ifindex = (int)if_nametoindex(iface);
+       memset(sll.sll_addr, 0xff, 6);
+
+       return (int)sendto(fd, p, n, 0, (struct sockaddr *)&sll, sizeof(sll));
+#else
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+#endif
+}
+
+int
+lws_plat_if_up(const char *ifname, int fd, int up)
+{
+#if defined(__linux__)
+       struct ifreq ifr;
+
+       memset(&ifr, 0, sizeof(ifr));
+       lws_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+       if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+               lwsl_err("%s: SIOCGIFFLAGS fail\n", __func__);
+               return 1;
+       }
+
+       if (up)
+               ifr.ifr_flags |= IFF_UP;
+       else
+               ifr.ifr_flags &= ~IFF_UP;
+
+       if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+               lwsl_err("%s: SIOCSIFFLAGS fail\n", __func__);
+               return 1;
+       }
+
+       return 0;
+#else
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+#endif
+}
+
+int
+lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname)
+{
+#if defined(__linux__)
+       struct ifreq i;
+
+       memset(&i, 0, sizeof(i));
+       i.ifr_addr.sa_family = AF_INET;
+       lws_strncpy(i.ifr_ifrn.ifrn_name, ifname,
+                   sizeof(i.ifr_ifrn.ifrn_name));
+       if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &i, sizeof(i)) < 0) {
+               lwsl_notice("%s: failed %d\n", __func__, LWS_ERRNO);
+               return 1;
+       }
+
+       return 0;
+#else
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+#endif
+}
+
+int
+lws_plat_ifconfig(int fd, lws_dhcpc_ifstate_t *is)
+{
+#if defined(__linux__)
+       struct rtentry route;
+       struct ifreq ifr;
+
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&route, 0, sizeof(route));
+
+       lws_strncpy(ifr.ifr_name, is->ifname, IFNAMSIZ);
+
+       lws_plat_if_up(is->ifname, fd, 0);
+
+       memcpy(&ifr.ifr_addr, &is->sa46[LWSDH_SA46_IP], sizeof(struct sockaddr));
+       if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
+               lwsl_err("%s: SIOCSIFADDR fail\n", __func__);
+               return 1;
+       }
+
+       if (is->sa46[LWSDH_SA46_IP].sa4.sin_family == AF_INET) {
+               struct sockaddr_in sin;
+
+               memset(&sin, 0, sizeof(sin));
+               sin.sin_family = AF_INET;
+               sin.sin_addr.s_addr = *(uint32_t *)&is->nums[LWSDH_IPV4_SUBNET_MASK];
+               memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
+               if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
+                       lwsl_err("%s: SIOCSIFNETMASK fail\n", __func__);
+                       return 1;
+               }
+
+               lws_plat_if_up(is->ifname, fd, 1);
+
+               memcpy(&route.rt_gateway,
+                      &is->sa46[LWSDH_SA46_IPV4_ROUTER].sa4,
+                      sizeof(struct sockaddr));
+
+               sin.sin_addr.s_addr = 0;
+               memcpy(&route.rt_dst, &sin, sizeof(struct sockaddr));
+               memcpy(&route.rt_genmask, &sin, sizeof(struct sockaddr));
+
+               route.rt_flags = RTF_UP | RTF_GATEWAY;
+               route.rt_metric = 100;
+               route.rt_dev = (char *)is->ifname;
+
+               if (ioctl(fd, SIOCADDRT, &route) < 0) {
+                       lwsl_err("%s: SIOCADDRT 0x%x fail: %d\n", __func__,
+                               (unsigned int)htonl(*(uint32_t *)&is->
+                                       sa46[LWSDH_SA46_IPV4_ROUTER].
+                                               sa4.sin_addr.s_addr), LWS_ERRNO);
+                       return 1;
+               }
+       } else
+               lws_plat_if_up(is->ifname, fd, 1);
+
+       return 0;
+#else
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+#endif
+}
+
+int
+lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost)
+{
+       return 0;
+}
+
+#if defined(LWS_WITH_MBEDTLS)
+int
+lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len)
+{
+       int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE(fd);
+       int ret;
+
+       if (fd < 0)
+               return MBEDTLS_ERR_NET_INVALID_CONTEXT;
+
+       ret = (int)write(fd, buf, len);
+       if (ret >= 0)
+               return ret;
+
+       if (errno == EAGAIN || errno == EWOULDBLOCK)
+               return MBEDTLS_ERR_SSL_WANT_WRITE;
+
+       if (errno == EPIPE || errno == ECONNRESET)
+               return MBEDTLS_ERR_NET_CONN_RESET;
+
+       if( errno == EINTR )
+               return MBEDTLS_ERR_SSL_WANT_WRITE;
+
+       return MBEDTLS_ERR_NET_SEND_FAILED;
+}
+
+int
+lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)
+{
+       int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE(fd);
+       int ret;
+
+       if (fd < 0)
+               return MBEDTLS_ERR_NET_INVALID_CONTEXT;
+
+       ret = (int)read(fd, buf, len);
+       if (ret >= 0)
+               return ret;
+
+       if (errno == EAGAIN || errno == EWOULDBLOCK)
+               return MBEDTLS_ERR_SSL_WANT_READ;
+
+       if (errno == EPIPE || errno == ECONNRESET)
+               return MBEDTLS_ERR_NET_CONN_RESET;
+
+       if (errno == EINTR)
+               return MBEDTLS_ERR_SSL_WANT_READ;
+
+       return MBEDTLS_ERR_NET_RECV_FAILED;
+}
+#endif
diff --git a/lib/plat/unix/unix-spawn.c b/lib/plat/unix/unix-spawn.c
new file mode 100644 (file)
index 0000000..1c68d45
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+
+#include "private-lib-core.h"
+#include <unistd.h>
+
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+#include <sys/resource.h>
+#include <sys/wait.h>
+#endif
+
+void
+lws_spawn_timeout(struct lws_sorted_usec_list *sul)
+{
+       struct lws_spawn_piped *lsp = lws_container_of(sul,
+                                       struct lws_spawn_piped, sul);
+
+       lwsl_warn("%s: spawn exceeded timeout, killing\n", __func__);
+
+       lws_spawn_piped_kill_child_process(lsp);
+}
+
+void
+lws_spawn_sul_reap(struct lws_sorted_usec_list *sul)
+{
+       struct lws_spawn_piped *lsp = lws_container_of(sul,
+                                       struct lws_spawn_piped, sul_reap);
+
+       lwsl_notice("%s: reaping spawn after last stdpipe, tries left %d\n",
+                   __func__, lsp->reap_retry_budget);
+       if (!lws_spawn_reap(lsp) && !lsp->pipes_alive) {
+               if (--lsp->reap_retry_budget) {
+                       lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
+                                        &lsp->sul_reap, lws_spawn_sul_reap,
+                                        250 * LWS_US_PER_MS);
+               } else {
+                       lwsl_err("%s: Unable to reap lsp %p, killing\n",
+                                __func__, lsp);
+                       lsp->reap_retry_budget = 20;
+                       lws_spawn_piped_kill_child_process(lsp);
+               }
+       }
+}
+
+static struct lws *
+lws_create_stdwsi(struct lws_context *context, int tsi,
+                    const struct lws_role_ops *ops)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws *new_wsi;
+
+       if (!context->vhost_list)
+               return NULL;
+
+       if ((unsigned int)pt->fds_count == context->fd_limit_per_thread - 1) {
+               lwsl_err("no space for new conn\n");
+               return NULL;
+       }
+
+       lws_context_lock(context, __func__);
+       new_wsi = __lws_wsi_create_with_role(context, tsi, ops, NULL);
+       lws_context_unlock(context);
+       if (new_wsi == NULL) {
+               lwsl_err("Out of memory for new connection\n");
+               return NULL;
+       }
+
+       new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
+
+       /* initialize the instance struct */
+
+       lws_role_transition(new_wsi, 0, LRS_ESTABLISHED, ops);
+
+       new_wsi->hdr_parsing_completed = 0;
+
+       /*
+        * these can only be set once the protocol is known
+        * we set an unestablished connection's protocol pointer
+        * to the start of the defauly vhost supported list, so it can look
+        * for matching ones during the handshake
+        */
+
+       new_wsi->user_space = NULL;
+
+       return new_wsi;
+}
+
+void
+lws_spawn_piped_destroy(struct lws_spawn_piped **_lsp)
+{
+       struct lws_spawn_piped *lsp = *_lsp;
+       int n;
+
+       if (!lsp)
+               return;
+
+       lws_dll2_remove(&lsp->dll);
+
+       lws_sul_cancel(&lsp->sul);
+       lws_sul_cancel(&lsp->sul_reap);
+
+       for (n = 0; n < 3; n++) {
+#if 0
+               if (lsp->pipe_fds[n][!!(n == 0)] == 0)
+                       lwsl_err("ZERO FD IN CGI CLOSE");
+
+               if (lsp->pipe_fds[n][!!(n == 0)] >= 0) {
+                       close(lsp->pipe_fds[n][!!(n == 0)]);
+                       lsp->pipe_fds[n][!!(n == 0)] = LWS_SOCK_INVALID;
+               }
+#endif
+               if (lsp->stdwsi[n]) {
+                       lws_set_timeout(lsp->stdwsi[n], 1, LWS_TO_KILL_ASYNC);
+                       lsp->stdwsi[n] = NULL;
+               }
+       }
+
+       lws_free_set_NULL((*_lsp));
+}
+
+int
+lws_spawn_reap(struct lws_spawn_piped *lsp)
+{
+       long hz = sysconf(_SC_CLK_TCK); /* accounting Hz */
+       void *opaque = lsp->info.opaque;
+       lsp_cb_t cb = lsp->info.reap_cb;
+       struct lws_spawn_piped temp;
+       struct tms tms;
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+       struct rusage rusa;
+       int status;
+#endif
+       int n;
+
+       if (lsp->child_pid < 1)
+               return 0;
+
+       /* check if exited, do not reap yet */
+
+       memset(&lsp->si, 0, sizeof(lsp->si));
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+       n = wait4(lsp->child_pid, &status, WNOHANG, &rusa);
+       if (!n)
+               return 0;
+       lsp->si.si_code = WIFEXITED(status);
+#else
+       n = waitid(P_PID, (id_t)lsp->child_pid, &lsp->si, WEXITED | WNOHANG | WNOWAIT);
+#endif
+       if (n < 0) {
+               lwsl_info("%s: child %d still running\n", __func__, lsp->child_pid);
+               return 0;
+       }
+
+       if (!lsp->si.si_code)
+               return 0;
+
+       /* his process has exited... */
+
+       if (!lsp->reaped) {
+               /* mark the earliest time we knew he had gone */
+               lsp->reaped = lws_now_usecs();
+
+               /*
+                * Switch the timeout to restrict the amount of grace time
+                * to drain stdwsi
+                */
+
+               lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
+                                &lsp->sul, lws_spawn_timeout,
+                                5 * LWS_US_PER_SEC);
+       }
+
+       /*
+        * Stage finalizing our reaction to the process going down until the
+        * stdwsi flushed whatever is in flight and all noticed they were
+        * closed.  For that reason, each stdwsi close must call lws_spawn_reap
+        * to check if that was the last one and we can proceed with the reap.
+        */
+
+       if (!lsp->ungraceful && lsp->pipes_alive) {
+               lwsl_info("%s: %d stdwsi alive, not reaping\n", __func__,
+                               lsp->pipes_alive);
+               return 0;
+       }
+
+       /* we reached the reap point, no need for timeout wait */
+
+       lws_sul_cancel(&lsp->sul);
+
+       /*
+        * All the stdwsi went down, nothing more is coming... it's over
+        * Collect the final information and then reap the dead process
+        */
+
+       if (times(&tms) != (clock_t) -1) {
+               /*
+                * Cpu accounting in us
+                */
+               lsp->accounting[0] = (lws_usec_t)((uint64_t)tms.tms_cstime * 1000000) / hz;
+               lsp->accounting[1] = (lws_usec_t)((uint64_t)tms.tms_cutime * 1000000) / hz;
+               lsp->accounting[2] = (lws_usec_t)((uint64_t)tms.tms_stime * 1000000) / hz;
+               lsp->accounting[3] = (lws_usec_t)((uint64_t)tms.tms_utime * 1000000) / hz;
+       }
+
+       temp = *lsp;
+#if defined(__OpenBSD__) || defined(__NetBSD__)
+       n = wait4(lsp->child_pid, &status, WNOHANG, &rusa);
+       if (!n)
+               return 0;
+       lsp->si.si_code = WIFEXITED(status);
+       if (lsp->si.si_code == CLD_EXITED)
+               temp.si.si_code = CLD_EXITED;
+       temp.si.si_status = WEXITSTATUS(status);
+#else
+       n = waitid(P_PID, (id_t)lsp->child_pid, &temp.si, WEXITED | WNOHANG);
+#endif
+       temp.si.si_status &= 0xff; /* we use b8 + for flags */
+       lwsl_info("%s: waitd says %d, process exit %d\n",
+                   __func__, n, temp.si.si_status);
+
+       lsp->child_pid = -1;
+
+       /* destroy the lsp itself first (it's freed and plsp set NULL */
+
+       if (lsp->info.plsp)
+               lws_spawn_piped_destroy(lsp->info.plsp);
+
+       /* then do the parent callback informing it's destroyed */
+
+       if (cb)
+               cb(opaque, temp.accounting, &temp.si,
+                  temp.we_killed_him_timeout |
+                          (temp.we_killed_him_spew << 1));
+
+       return 1; /* was reaped */
+}
+
+int
+lws_spawn_piped_kill_child_process(struct lws_spawn_piped *lsp)
+{
+       int status, n;
+
+       if (lsp->child_pid <= 0)
+               return 1;
+
+       lsp->ungraceful = 1; /* don't wait for flushing, just kill it */
+
+       if (lws_spawn_reap(lsp))
+               /* that may have invalidated lsp */
+               return 0;
+
+       /* kill the process group */
+       n = kill(-lsp->child_pid, SIGTERM);
+       lwsl_debug("%s: SIGTERM child PID %d says %d (errno %d)\n", __func__,
+                  lsp->child_pid, n, errno);
+       if (n < 0) {
+               /*
+                * hum seen errno=3 when process is listed in ps,
+                * it seems we don't always retain process grouping
+                *
+                * Direct these fallback attempt to the exact child
+                */
+               n = kill(lsp->child_pid, SIGTERM);
+               if (n < 0) {
+                       n = kill(lsp->child_pid, SIGPIPE);
+                       if (n < 0) {
+                               n = kill(lsp->child_pid, SIGKILL);
+                               if (n < 0)
+                                       lwsl_info("%s: SIGKILL PID %d "
+                                                "failed errno %d "
+                                                "(maybe zombie)\n", __func__,
+                                                lsp->child_pid, errno);
+                       }
+               }
+       }
+
+       /* He could be unkillable because he's a zombie */
+
+       n = 1;
+       while (n > 0) {
+               n = waitpid(-lsp->child_pid, &status, WNOHANG);
+               if (n > 0)
+                       lwsl_debug("%s: reaped PID %d\n", __func__, n);
+               if (n <= 0) {
+                       n = waitpid(lsp->child_pid, &status, WNOHANG);
+                       if (n > 0)
+                               lwsl_debug("%s: reaped PID %d\n", __func__, n);
+               }
+       }
+
+       lws_spawn_reap(lsp);
+       /* that may have invalidated lsp */
+
+       return 0;
+}
+
+/*
+ * Deals with spawning a subprocess and executing it securely with stdin/out/err
+ * diverted into pipes
+ */
+
+struct lws_spawn_piped *
+lws_spawn_piped(const struct lws_spawn_piped_info *i)
+{
+       const struct lws_protocols *pcol = i->vh->context->vhost_list->protocols;
+       struct lws_context *context = i->vh->context;
+       struct lws_spawn_piped *lsp;
+       const char *wd;
+       int n, m;
+
+       if (i->protocol_name)
+               pcol = lws_vhost_name_to_protocol(i->vh, i->protocol_name);
+       if (!pcol) {
+               lwsl_err("%s: unknown protocol %s\n", __func__,
+                        i->protocol_name ? i->protocol_name : "default");
+
+               return NULL;
+       }
+
+       lsp = lws_zalloc(sizeof(*lsp), __func__);
+       if (!lsp)
+               return NULL;
+
+       /* wholesale take a copy of info */
+       lsp->info = *i;
+       lsp->reap_retry_budget = 20;
+
+       /*
+        * Prepare the stdin / out / err pipes
+        */
+
+       for (n = 0; n < 3; n++) {
+               lsp->pipe_fds[n][0] = -1;
+               lsp->pipe_fds[n][1] = -1;
+       }
+
+       /* create pipes for [stdin|stdout] and [stderr] */
+
+       for (n = 0; n < 3; n++) {
+               if (pipe(lsp->pipe_fds[n]) == -1)
+                       goto bail1;
+               lws_plat_apply_FD_CLOEXEC(lsp->pipe_fds[n][n == 0]);
+       }
+
+       /*
+        * At this point, we have 6 pipe fds open on lws side and no wsis
+        * bound to them
+        */
+
+       /* create wsis for each stdin/out/err fd */
+
+       for (n = 0; n < 3; n++) {
+               lsp->stdwsi[n] = lws_create_stdwsi(i->vh->context, i->tsi,
+                                         i->ops ? i->ops : &role_ops_raw_file);
+               if (!lsp->stdwsi[n]) {
+                       lwsl_err("%s: unable to create lsp stdwsi\n", __func__);
+                       goto bail2;
+               }
+
+                __lws_lc_tag(i->vh->context, &i->vh->context->lcg[LWSLCG_WSI],
+                            &lsp->stdwsi[n]->lc, "nspawn-stdwsi-%d", n);
+
+               lsp->stdwsi[n]->lsp_channel = (uint8_t)n;
+               lws_vhost_bind_wsi(i->vh, lsp->stdwsi[n]);
+               lsp->stdwsi[n]->a.protocol = pcol;
+               lsp->stdwsi[n]->a.opaque_user_data = i->opaque;
+
+               lwsl_debug("%s: lsp stdwsi %p: pipe idx %d -> fd %d / %d\n", __func__,
+                          lsp->stdwsi[n], n, lsp->pipe_fds[n][n == 0],
+                          lsp->pipe_fds[n][n != 0]);
+
+               /* read side is 0, stdin we want the write side, others read */
+
+               lsp->stdwsi[n]->desc.sockfd = lsp->pipe_fds[n][n == 0];
+               if (fcntl(lsp->pipe_fds[n][n == 0], F_SETFL, O_NONBLOCK) < 0) {
+                       lwsl_err("%s: setting NONBLOCK failed\n", __func__);
+                       goto bail2;
+               }
+
+               /*
+                * We have bound 3 x pipe fds to wsis, wr side of stdin and rd
+                * side of stdout / stderr... those are marked CLOEXEC so they
+                * won't go through the fork
+                *
+                * rd side of stdin and wr side of stdout / stderr are open but
+                * not bound to anything on lws side.
+                */
+       }
+
+       /*
+        * Stitch the wsi fd into the poll wait
+        */
+
+       for (n = 0; n < 3; n++) {
+               if (context->event_loop_ops->sock_accept)
+                       if (context->event_loop_ops->sock_accept(lsp->stdwsi[n]))
+                               goto bail3;
+
+               if (__insert_wsi_socket_into_fds(context, lsp->stdwsi[n]))
+                       goto bail3;
+               if (i->opt_parent) {
+                       lsp->stdwsi[n]->parent = i->opt_parent;
+                       lsp->stdwsi[n]->sibling_list = i->opt_parent->child_list;
+                       i->opt_parent->child_list = lsp->stdwsi[n];
+               }
+       }
+
+       if (lws_change_pollfd(lsp->stdwsi[LWS_STDIN], LWS_POLLIN, LWS_POLLOUT))
+               goto bail3;
+       if (lws_change_pollfd(lsp->stdwsi[LWS_STDOUT], LWS_POLLOUT, LWS_POLLIN))
+               goto bail3;
+       if (lws_change_pollfd(lsp->stdwsi[LWS_STDERR], LWS_POLLOUT, LWS_POLLIN))
+               goto bail3;
+
+       lwsl_info("%s: fds in %d, out %d, err %d\n", __func__,
+                  lsp->stdwsi[LWS_STDIN]->desc.sockfd,
+                  lsp->stdwsi[LWS_STDOUT]->desc.sockfd,
+                  lsp->stdwsi[LWS_STDERR]->desc.sockfd);
+
+       /* we are ready with the redirection pipes... do the (v)fork */
+#if defined(__sun) || !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)
+       lsp->child_pid = fork();
+#else
+       lsp->child_pid = vfork();
+#endif
+       if (lsp->child_pid < 0) {
+               lwsl_err("%s: fork failed, errno %d", __func__, errno);
+               goto bail3;
+       }
+
+#if defined(__linux__)
+       if (!lsp->child_pid)
+               prctl(PR_SET_PDEATHSIG, SIGTERM);
+#endif
+
+       if (lsp->info.disable_ctrlc)
+               /* stops non-daemonized main processess getting SIGINT
+                * from TTY */
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+               setpgid(0, 0);
+#else
+               setpgrp();
+#endif
+
+       if (lsp->child_pid) {
+
+               /*
+                * We are the parent process.  We can close our copy of the
+                * "other" side of the pipe fds, ie, rd for stdin and wr for
+                * stdout / stderr.
+                */
+               for (n = 0; n < 3; n++)
+                       /* these guys didn't have any wsi footprint */
+                       close(lsp->pipe_fds[n][n != 0]);
+
+               lsp->pipes_alive = 3;
+               lsp->created = lws_now_usecs();
+
+               lwsl_info("%s: lsp %p spawned PID %d\n", __func__, lsp,
+                         lsp->child_pid);
+
+               lws_sul_schedule(context, i->tsi, &lsp->sul, lws_spawn_timeout,
+                                i->timeout_us ? i->timeout_us :
+                                                  300 * LWS_US_PER_SEC);
+
+               if (i->owner)
+                       lws_dll2_add_head(&lsp->dll, i->owner);
+
+               if (i->timeout_us)
+                       lws_sul_schedule(context, i->tsi, &lsp->sul,
+                                        lws_spawn_timeout, i->timeout_us);
+
+               return lsp;
+       }
+
+       /*
+        * We are the forked process, redirect and kill inherited things.
+        *
+        * Because of vfork(), we cannot do anything that changes pages in
+        * the parent environment.  Stuff that changes kernel state for the
+        * process is OK.  Stuff that happens after the execvpe() is OK.
+        */
+
+       if (i->chroot_path && chroot(i->chroot_path)) {
+               lwsl_err("%s: child chroot %s failed, errno %d\n",
+                        __func__, i->chroot_path, errno);
+
+               exit(2);
+       }
+
+       /* cwd: somewhere we can at least read things and enter it */
+
+       wd = i->wd;
+       if (!wd)
+               wd = "/tmp";
+       if (chdir(wd))
+               lwsl_notice("%s: Failed to cd to %s\n", __func__, wd);
+
+       /*
+        * Bind the child's stdin / out / err to its side of our pipes
+        */
+
+       for (m = 0; m < 3; m++) {
+               if (dup2(lsp->pipe_fds[m][m != 0], m) < 0) {
+                       lwsl_err("%s: stdin dup2 failed\n", __func__);
+                       goto bail3;
+               }
+               /*
+                * CLOEXEC on the lws-side of the pipe fds should have already
+                * dealt with closing those for the child perspective.
+                *
+                * Now it has done the dup, the child should close its original
+                * copies of its side of the pipes.
+                */
+
+               close(lsp->pipe_fds[m][m != 0]);
+       }
+
+#if defined(__sun) || !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)
+#if defined(__linux__) || defined(__APPLE__) || defined(__sun)
+       m = 0;
+       while (i->env_array[m]){
+               const char *p = strchr(i->env_array[m], '=');
+               int naml = lws_ptr_diff(p, i->env_array[m]);
+               char enam[32];
+
+               lws_strnncpy(enam, i->env_array[m], naml, sizeof(enam));
+               setenv(enam, p, 1);
+               m++;
+       }
+#endif
+       execvp(i->exec_array[0], (char * const *)&i->exec_array[0]);
+#else
+       execvpe(i->exec_array[0], (char * const *)&i->exec_array[0],
+               (char **)&i->env_array[0]);
+#endif
+
+       lwsl_err("%s: child exec of %s failed %d\n", __func__, i->exec_array[0],
+                LWS_ERRNO);
+
+       _exit(1);
+
+bail3:
+
+       while (--n >= 0)
+               __remove_wsi_socket_from_fds(lsp->stdwsi[n]);
+bail2:
+       for (n = 0; n < 3; n++)
+               if (lsp->stdwsi[n])
+                       __lws_free_wsi(lsp->stdwsi[n]);
+
+bail1:
+       for (n = 0; n < 3; n++) {
+               if (lsp->pipe_fds[n][0] >= 0)
+                       close(lsp->pipe_fds[n][0]);
+               if (lsp->pipe_fds[n][1] >= 0)
+                       close(lsp->pipe_fds[n][1]);
+       }
+
+       lws_free(lsp);
+
+       lwsl_err("%s: failed\n", __func__);
+
+       return NULL;
+}
+
+void
+lws_spawn_stdwsi_closed(struct lws_spawn_piped *lsp, struct lws *wsi)
+{
+       int n;
+
+       assert(lsp);
+       lsp->pipes_alive--;
+       lwsl_debug("%s: pipes alive %d\n", __func__, lsp->pipes_alive);
+       if (!lsp->pipes_alive)
+               lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
+                                &lsp->sul_reap, lws_spawn_sul_reap, 1);
+
+       for (n = 0; n < 3; n++)
+               if (lsp->stdwsi[n] == wsi)
+                       lsp->stdwsi[n] = NULL;
+}
+
+int
+lws_spawn_get_stdfd(struct lws *wsi)
+{
+       return wsi->lsp_channel;
+}
diff --git a/lib/plat/windows/CMakeLists.txt b/lib/plat/windows/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c26c8e7
--- /dev/null
@@ -0,0 +1,103 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       plat/windows/windows-fds.c
+       plat/windows/windows-file.c
+       plat/windows/windows-init.c
+       plat/windows/windows-misc.c
+       plat/windows/windows-pipe.c
+       plat/windows/windows-plugins.c
+       plat/windows/windows-service.c
+       plat/windows/windows-sockets.c
+       )
+if (LWS_WITH_SYS_ASYNC_DNS)
+       list(APPEND SOURCES plat/windows/windows-resolv.c)
+endif()
+
+if (LWS_WITH_SPAWN)
+       list(APPEND SOURCES plat/windows/windows-spawn.c)
+endif()
+
+if (LWS_WITH_ZLIB AND LWS_WITH_BUNDLED_ZLIB)
+       set(WIN32_ZLIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../win32port/zlib")
+       set(ZLIB_SRCS
+               ${WIN32_ZLIB_PATH}/adler32.c
+               ${WIN32_ZLIB_PATH}/compress.c
+               ${WIN32_ZLIB_PATH}/crc32.c
+               ${WIN32_ZLIB_PATH}/deflate.c
+               ${WIN32_ZLIB_PATH}/gzlib.c
+               ${WIN32_ZLIB_PATH}/gzread.c
+               ${WIN32_ZLIB_PATH}/gzwrite.c
+               ${WIN32_ZLIB_PATH}/infback.c
+               ${WIN32_ZLIB_PATH}/inffast.c
+               ${WIN32_ZLIB_PATH}/inflate.c
+               ${WIN32_ZLIB_PATH}/inftrees.c
+               ${WIN32_ZLIB_PATH}/trees.c
+               ${WIN32_ZLIB_PATH}/uncompr.c
+               ${WIN32_ZLIB_PATH}/zutil.c)
+       add_library(zlib_internal STATIC ${ZLIB_SRCS})
+       set(ZLIB_INCLUDE_DIRS ${WIN32_ZLIB_PATH})
+       set(ZLIB_LIBRARIES "")
+       set(ZLIB_FOUND 1)
+       # Make sure zlib_internal is compiled before the libs.
+       foreach (lib ${LWS_LIBRARIES})
+               add_dependencies(${lib} zlib_internal)
+       endforeach()
+endif()
+
+# Add helper files for Windows
+
+#  (from ./lib perspective)
+set(WIN32_HELPERS_PATH ../win32port/win32helpers)
+
+# from our perspective in ./lib/plat/windows
+include_directories(../../${WIN32_HELPERS_PATH})
+
+list(APPEND SOURCES
+       ${WIN32_HELPERS_PATH}/gettimeofday.c
+)
+
+list(APPEND HDR_PRIVATE
+       ${WIN32_HELPERS_PATH}/gettimeofday.h
+)
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+set(WIN32_HELPERS_PATH ${WIN32_HELPERS_PATH} PARENT_SCOPE)
+set(HDR_PRIVATE ${HDR_PRIVATE} PARENT_SCOPE)
+set(ZLIB_FOUND ${ZLIB_FOUND} PARENT_SCOPE)
+set(LIB_LIST_AT_END ${LIB_LIST_AT_END} PARENT_SCOPE)
similarity index 60%
rename from lib/plat/windows/private.h
rename to lib/plat/windows/private-lib-plat-windows.h
index a7756d8..18d87ac 100644 (file)
@@ -1,24 +1,27 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
- *  Included from lib/core/private.h if defined(WIN32) || defined(_WIN32)
+ * Included from lib/private-lib-core.h if defined(WIN32) || defined(_WIN32)
  */
 
  #ifndef WIN32_LEAN_AND_MEAN
@@ -48,6 +51,7 @@
  #define SHUT_WR SD_SEND
 
  #define compatible_close(fd) closesocket(fd)
+ #define compatible_file_close(fd) CloseHandle(fd)
  #define lws_set_blocking_send(wsi) wsi->sock_send_blocking = 1
 
  #include <winsock2.h>
  #include <mstcpip.h>
  #include <io.h>
 
+#if defined(LWS_WITH_UNIX_SOCK)
+#include <afunix.h>
+#endif
+
+#if defined(LWS_WITH_TLS)
+#include <wincrypt.h>
+#endif
+
+#if defined(LWS_HAVE_PTHREAD_H)
+#define lws_mutex_t            pthread_mutex_t
+#define lws_mutex_init(x)      pthread_mutex_init(&(x), NULL)
+#define lws_mutex_destroy(x)   pthread_mutex_destroy(&(x))
+#define lws_mutex_lock(x)      pthread_mutex_lock(&(x))
+#define lws_mutex_unlock(x)    pthread_mutex_unlock(&(x))
+#endif
+
  #if !defined(LWS_HAVE_ATOLL)
   #if defined(LWS_HAVE__ATOI64)
    #define atoll _atoi64
@@ -122,7 +142,7 @@ struct lws_fd_hashtable {
        int length;
 };
 
-
+#if !defined(LWS_EXTERN)
 #ifdef LWS_DLL
 #ifdef LWS_INTERNAL
 #define LWS_EXTERN extern __declspec(dllexport)
@@ -132,9 +152,14 @@ struct lws_fd_hashtable {
 #else
 #define LWS_EXTERN
 #endif
+#endif
 
 typedef SOCKET lws_sockfd_type;
+#if defined(__MINGW32__)
+typedef int lws_filefd_type;
+#else
 typedef HANDLE lws_filefd_type;
+#endif
 #define LWS_WIN32_HANDLE_TYPES
 
 LWS_EXTERN struct lws *
index 0d324e8..05a6620 100644 (file)
@@ -1,28 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 #define _WINSOCK_DEPRECATED_NO_WARNINGS
 #endif
-#include "core/private.h"
+#include "private-lib-core.h"
 
 struct lws *
 wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
@@ -70,7 +73,7 @@ delete_from_fd(struct lws_context *context, lws_sockfd_type fd)
                        return 0;
                }
 
-       lwsl_err("Failed to find fd %d requested for "
+       lwsl_debug("Failed to find fd %d requested for "
                 "delete in hashtable\n", fd);
        return 1;
 }
index 6516b70..27b0a9c 100644 (file)
@@ -1,28 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 #define _WINSOCK_DEPRECATED_NO_WARNINGS
 #endif
-#include "core/private.h"
+#include "private-lib-core.h"
 
 int lws_plat_apply_FD_CLOEXEC(int n)
 {
@@ -47,7 +50,7 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
                          CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        }
 
-       if (ret == LWS_INVALID_FILE)
+       if (ret == NULL)
                goto bail;
 
        fop_fd = malloc(sizeof(*fop_fd));
@@ -55,8 +58,13 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
                goto bail;
 
        fop_fd->fops = fops;
+#if defined(__MINGW32__)
+       /* we use filesystem_priv */
+       fop_fd->fd = (int)(intptr_t)ret;
+#else
        fop_fd->fd = ret;
-       fop_fd->filesystem_priv = NULL; /* we don't use it */
+#endif
+       fop_fd->filesystem_priv = ret;
        fop_fd->flags = *flags;
        fop_fd->len = GetFileSize(ret, NULL);
        if(GetFileSizeEx(ret, &llFileSize))
@@ -73,7 +81,7 @@ bail:
 int
 _lws_plat_file_close(lws_fop_fd_t *fop_fd)
 {
-       HANDLE fd = (*fop_fd)->fd;
+       HANDLE fd = (*fop_fd)->filesystem_priv;
 
        free(*fop_fd);
        *fop_fd = NULL;
@@ -89,7 +97,23 @@ _lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
        LARGE_INTEGER l;
 
        l.QuadPart = offset;
-       return SetFilePointerEx((HANDLE)fop_fd->fd, l, NULL, FILE_CURRENT);
+       if (!SetFilePointerEx((HANDLE)fop_fd->filesystem_priv, l, NULL, FILE_CURRENT))
+       {
+               lwsl_err("error seeking from cur %ld, offset %ld\n", (long)fop_fd->pos, (long)offset);
+               return -1;
+       }
+
+       LARGE_INTEGER zero;
+       zero.QuadPart = 0;
+       LARGE_INTEGER newPos;
+       if (!SetFilePointerEx((HANDLE)fop_fd->filesystem_priv, zero, &newPos, FILE_CURRENT))
+       {
+               lwsl_err("error seeking from cur %ld, offset %ld\n", (long)fop_fd->pos, (long)offset);
+               return -1;
+       }
+       fop_fd->pos = newPos.QuadPart;
+
+       return newPos.QuadPart;
 }
 
 int
@@ -98,7 +122,7 @@ _lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
 {
        DWORD _amount;
 
-       if (!ReadFile((HANDLE)fop_fd->fd, buf, (DWORD)len, &_amount, NULL)) {
+       if (!ReadFile((HANDLE)fop_fd->filesystem_priv, buf, (DWORD)len, &_amount, NULL)) {
                *amount = 0;
 
                return 1;
@@ -116,7 +140,7 @@ _lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
 {
        DWORD _amount;
 
-       if (!WriteFile((HANDLE)fop_fd->fd, buf, (DWORD)len, &_amount, NULL)) {
+       if (!WriteFile((HANDLE)fop_fd->filesystem_priv, buf, (DWORD)len, &_amount, NULL)) {
                *amount = 0;
 
                return 1;
@@ -131,19 +155,19 @@ _lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
 
 int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
-                       int len)
+                       size_t len)
 {
        int n;
 
-       n = write(fd, buf, len);
+       n = (int)write(fd, buf, (unsigned int)len);
 
        lseek(fd, 0, SEEK_SET);
 
-       return n != len;
+       return (size_t)n != len;
 }
 
 int
-lws_plat_write_file(const char *filename, void *buf, int len)
+lws_plat_write_file(const char *filename, void *buf, size_t len)
 {
        int m, fd;
 
@@ -152,20 +176,20 @@ lws_plat_write_file(const char *filename, void *buf, int len)
        if (fd == -1)
                return -1;
 
-       m = write(fd, buf, len);
+       m = (int)write(fd, buf, (unsigned int)len);
        close(fd);
 
-       return m != len;
+       return (size_t)m != len;
 }
 
 int
-lws_plat_read_file(const char *filename, void *buf, int len)
+lws_plat_read_file(const char *filename, void *buf, size_t len)
 {
        int n, fd = lws_open(filename, O_RDONLY);
        if (fd == -1)
                return -1;
 
-       n = read(fd, buf, len);
+       n = (int)read(fd, buf, (unsigned int)len);
        close(fd);
 
        return n;
index 5a2df0d..00190c7 100644 (file)
@@ -1,28 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 #define _WINSOCK_DEPRECATED_NO_WARNINGS
 #endif
-#include "core/private.h"
+#include "private-lib-core.h"
 
 int
 lws_plat_drop_app_privileges(struct lws_context *context, int actually_set)
@@ -52,6 +55,21 @@ lws_plat_context_early_init(void)
        return 1;
 }
 
+#if defined(LWS_WITH_PLUGINS)
+static int
+protocol_plugin_cb(struct lws_plugin *pin, void *each_user)
+{
+       struct lws_context *context = (struct lws_context *)each_user;
+       const lws_plugin_protocol_t *plpr =
+                       (const lws_plugin_protocol_t *)pin->hdr;
+
+       context->plugin_protocol_count += plpr->count_protocols;
+       context->plugin_extension_count += plpr->count_extensions;
+
+       return 0;
+}
+#endif
+
 int
 lws_plat_init(struct lws_context *context,
              const struct lws_context_creation_info *info)
@@ -59,6 +77,33 @@ lws_plat_init(struct lws_context *context,
        struct lws_context_per_thread *pt = &context->pt[0];
        int i, n = context->count_threads;
 
+#if defined(LWS_WITH_MBEDTLS)
+       {
+               int n;
+
+               /* initialize platform random through mbedtls */
+               mbedtls_entropy_init(&context->mec);
+               mbedtls_ctr_drbg_init(&context->mcdc);
+
+               n = mbedtls_ctr_drbg_seed(&context->mcdc, mbedtls_entropy_func,
+                                         &context->mec, NULL, 0);
+               if (n)
+                       lwsl_err("%s: mbedtls_ctr_drbg_seed() returned 0x%x\n",
+                                __func__, n);
+#if 0
+               else {
+                       uint8_t rtest[16];
+                       lwsl_notice("%s: started drbg\n", __func__);
+                       if (mbedtls_ctr_drbg_random(&context->mcdc, rtest,
+                                                       sizeof(rtest)))
+                               lwsl_err("%s: get random failed\n", __func__);
+                       else
+                               lwsl_hexdump_notice(rtest, sizeof(rtest));
+               }
+#endif
+       }
+#endif
+
        for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
                context->fd_hashtable[i].wsi =
                        lws_zalloc(sizeof(struct lws*) * context->max_fds,
@@ -70,17 +115,17 @@ lws_plat_init(struct lws_context *context,
 
        while (n--) {
                pt->fds_count = 0;
-               pt->events = WSACreateEvent(); /* the cancel event */
-               InitializeCriticalSection(&pt->interrupt_lock);
 
                pt++;
        }
 
        context->fd_random = 0;
 
-#ifdef LWS_WITH_PLUGINS
+#if defined(LWS_WITH_PLUGINS)
        if (info->plugin_dirs)
-               lws_plat_plugins_init(context, info->plugin_dirs);
+               lws_plat_plugins_init(&context->plugin_list, info->plugin_dirs,
+                                     "lws_protocol_plugin",
+                                     protocol_plugin_cb, context);
 #endif
 
        return 0;
@@ -89,14 +134,7 @@ lws_plat_init(struct lws_context *context,
 void
 lws_plat_context_early_destroy(struct lws_context *context)
 {
-       struct lws_context_per_thread *pt = &context->pt[0];
-       int n = context->count_threads;
 
-       while (n--) {
-               WSACloseEvent(pt->events);
-               DeleteCriticalSection(&pt->interrupt_lock);
-               pt++;
-       }
 }
 
 void
@@ -104,6 +142,11 @@ lws_plat_context_late_destroy(struct lws_context *context)
 {
        int n;
 
+#ifdef LWS_WITH_PLUGINS
+       if (context->plugin_list)
+               lws_plugins_destroy(&context->plugin_list, NULL, NULL);
+#endif
+
        for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
                if (context->fd_hashtable[n].wsi)
                        lws_free(context->fd_hashtable[n].wsi);
index 9059a73..02008c6 100644 (file)
@@ -1,29 +1,43 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 #define _WINSOCK_DEPRECATED_NO_WARNINGS
 #endif
-#include "core/private.h"
+#include "private-lib-core.h"
 
+/*
+ * Normally you don't want this, use lws_sul instead inside the event loop.
+ * But sometimes for drivers it makes sense, so there's an internal-only
+ * crossplatform api for it.
+ */
+
+void
+lws_msleep(unsigned int ms)
+{
+        Sleep(ms);
+}
 
 lws_usec_t
 lws_now_usecs(void)
@@ -65,10 +79,10 @@ time_t time(time_t *t)
 }
 #endif
 
-LWS_VISIBLE int
-lws_get_random(struct lws_context *context, void *buf, int len)
+size_t
+lws_get_random(struct lws_context *context, void *buf, size_t len)
 {
-       int n;
+       size_t n;
        char *p = (char *)buf;
 
        for (n = 0; n < len; n++)
@@ -78,7 +92,7 @@ lws_get_random(struct lws_context *context, void *buf, int len)
 }
 
 
-LWS_VISIBLE void
+void
 lwsl_emit_syslog(int level, const char *line)
 {
        lwsl_emit_stderr(level, line);
index 0953871..bbfa319 100644 (file)
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 #define _WINSOCK_DEPRECATED_NO_WARNINGS
 #endif
-#include "core/private.h"
+#include "private-lib-core.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
 
 int
 lws_plat_pipe_create(struct lws *wsi)
 {
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct sockaddr_in *si = &pt->frt_pipe_si;
+       lws_sockfd_type *fd = pt->dummy_pipe_fds;
+       socklen_t sl;
+
+       /*
+        * Non-WSA HANDLEs can't join the WSAPoll() wait... use a UDP socket
+        * listening on 127.0.0.1:xxxx and send a byte to it from a second UDP
+        * socket to cancel the wait.
+        *
+        * Set the port to 0 at the bind, so lwip will choose a free one in the
+        * ephemeral range for us.
+        */
+
+       fd[0] = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd[0] == INVALID_SOCKET)
+               goto bail;
+
+       fd[1] = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd[1] == INVALID_SOCKET)
+               goto bail;
+
+       /*
+        * No need for memset since it's in zalloc'd context... it's in the
+        * context so we can reuse the prepared sockaddr to send tp fd[0] whem
+        * we want to cancel the wait
+        */
+
+       si->sin_family = AF_INET;
+       si->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       si->sin_port = 0;
+
+       if (bind(fd[0], (const struct sockaddr *)si, sizeof(*si)) < 0)
+               goto bail;
+
+       /*
+        * Query the socket to set pt->frt_pipe_si to the full sockaddr it
+        * wants to be addressed by, including the port that the os chose.
+        *
+        * Afterwards, we can use this prepared sockaddr stashed in the context
+        * to trigger the "pipe" without any other preliminaries.
+        */
+
+       sl = sizeof(*si);
+       if (getsockname(fd[0], (struct sockaddr *)si, &sl))
+               goto bail;
+
+       lwsl_info("%s: cancel UDP skt port %d\n", __func__,
+                 ntohs(si->sin_port));
+
+       return 0;
+
+bail:
+       lwsl_err("%s: failed\n", __func__);
+
        return 1;
 }
 
 int
-lws_plat_pipe_signal(struct lws *wsi)
+lws_plat_pipe_signal(struct lws_context *ctx, int tsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &ctx->pt[tsi];
+       struct sockaddr_in *si = &pt->frt_pipe_si;
+       lws_sockfd_type *fd = pt->dummy_pipe_fds;
+       char u = 0;
+       int n;
 
-       EnterCriticalSection(&pt->interrupt_lock);
-       pt->interrupt_requested = 1;
-       LeaveCriticalSection(&pt->interrupt_lock);
-       WSASetEvent(pt->events); /* trigger the cancel event */
+       /*
+        * Send a single UDP byte payload to the listening socket fd[0], forcing
+        * the event loop wait to wake.  fd[1] and context->frt_pipe_si are
+        * set at pt creation and are static.
+        */
 
-       return 0;
+       n = sendto(fd[1], &u, 1, 0, (struct sockaddr *)si, sizeof(*si));
+
+       return n != 1;
 }
 
 void
 lws_plat_pipe_close(struct lws *wsi)
 {
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+
+       if (pt->dummy_pipe_fds[0] && pt->dummy_pipe_fds[0] != LWS_SOCK_INVALID)
+               closesocket(pt->dummy_pipe_fds[0]);
+       if (pt->dummy_pipe_fds[1] && pt->dummy_pipe_fds[1] != LWS_SOCK_INVALID)
+               closesocket(pt->dummy_pipe_fds[1]);
+
+       pt->dummy_pipe_fds[0] = pt->dummy_pipe_fds[1] = LWS_SOCK_INVALID;
 }
index 7f83524..b2153d6 100644 (file)
  *
  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 #define _WINSOCK_DEPRECATED_NO_WARNINGS
 #endif
-#include "core/private.h"
+#include "private-lib-core.h"
+
+/*
+ * ie, if the plugins api needed at all
+ */
+
+#if defined(LWS_WITH_PLUGINS_API) && (UV_VERSION_MAJOR > 0)
+
+const lws_plugin_header_t *
+lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath,
+               const char *sofilename, const char *_class,
+               each_plugin_cb_t each, void *each_user)
+{
+       const lws_plugin_header_t *hdr;
+       struct lws_plugin *pin;
+       char sym[96], *dot;
+       uv_lib_t lib;
+       void *v;
+       int m;
+
+       lib.errmsg = NULL;
+       lib.handle = NULL;
+
+       if (uv_dlopen(libpath, &lib)) {
+               uv_dlerror(&lib);
+               lwsl_err("Error loading DSO: %s\n", lib.errmsg);
+               uv_dlclose(&lib);
+               return NULL;
+       }
+
+       /* we could open it... can we get his export struct? */
+       m = lws_snprintf(sym, sizeof(sym) - 1, "%s", sofilename);
+       if (m < 4)
+               goto bail;
+       dot = strchr(sym, '.');
+       if (dot)
+               *dot = '\0'; /* snip the .so or .lib or what-have-you*/
+
+       if (uv_dlsym(&lib, sym, &v)) {
+               uv_dlerror(&lib);
+               lwsl_err("%s: Failed to get '%s' on %s: %s\n",
+                        __func__, path, dent.name, lib.errmsg);
+               goto bail;
+       }
+
+       hdr = (const lws_plugin_header_t *)v;
+       if (hdr->api_magic != LWS_PLUGIN_API_MAGIC) {
+               lwsl_info("%s: plugin %s has outdated api %d (vs %d)\n",
+                        __func__, libpath, hdr->api_magic,
+                        LWS_PLUGIN_API_MAGIC);
+               goto bail;
+       }
+
+       if (strcmp(hdr->lws_build_hash, LWS_BUILD_HASH))
+               goto bail;
+
+       if (strcmp(hdr->_class, _class))
+               goto bail;
+
+       /*
+        * We don't already have one of these, right?
+        */
+
+       pin = *pplugin;
+       while (pin) {
+               if (!strcmp(pin->hdr->name, hdr->name))
+                       goto bail;
+               pin = pin->list;
+       }
+
+       /*
+        * OK let's bring it in
+        */
+
+       pin = lws_malloc(sizeof(*pin), __func__);
+       if (!pin)
+               goto bail;
+
+       pin->list = *pplugin;
+       *pplugin = pin;
+
+       pin->u.lib = lib;
+       pin->hdr = hdr;
+
+       if (each)
+               each(pin, each_user);
+
+       return hdr;
+
+bail:
+       uv_dlclose(&lib);
+
+       return NULL;
+}
+
+int
+lws_plat_destroy_dl(struct lws_plugin *p)
+{
+       return uv_dlclose(&p->u.lib);
+}
+
+#endif
+
+/*
+ * Specifically for protocol plugins support
+ */
+
+#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
+
+static int
+protocol_plugin_cb(struct lws_plugin *pin, void *each_user)
+{
+       struct lws_context *context = (struct lws_context *)each_user;
+       const lws_plugin_protocol_t *plpr =
+                               (const lws_plugin_protocol_t *)pin->hdr;
+
+       context->plugin_protocol_count += plpr->count_protocols;
+       context->plugin_extension_count += plpr->count_extensions;
+
+       return 0;
+}
+#endif
 
 int
-lws_plat_plugins_init(struct lws_context * context, const char * const *d)
+lws_plat_plugins_init(struct lws_context *context, const char * const *d)
 {
 #if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
-       if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
-               return lws_uv_plugins_init(context, d);
+       if (info->plugin_dirs) {
+               uv_loop_init(&context->uv.loop);
+               lws_plugins_init(&context->plugin_list, info->plugin_dirs,
+                                "lws_protocol_plugin", NULL,
+                                protocol_plugin_cb, context);
+       }
 #endif
 
        return 0;
@@ -39,8 +167,12 @@ int
 lws_plat_plugins_destroy(struct lws_context * context)
 {
 #if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
-       if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
-               return lws_uv_plugins_destroy(context);
+       if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV) &&
+           context->plugin_list) {
+               lws_plugins_destroy(&context->plugin_list, NULL, NULL);
+               while (uv_loop_close(&context->uv.loop))
+                       ;
+       }
 #endif
 
        return 0;
diff --git a/lib/plat/windows/windows-resolv.c b/lib/plat/windows/windows-resolv.c
new file mode 100644 (file)
index 0000000..9fe81cf
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include <iphlpapi.h>
+
+lws_async_dns_server_check_t
+lws_plat_asyncdns_init(struct lws_context *context, lws_sockaddr46 *sa46)
+{
+       unsigned long ul;
+       FIXED_INFO *fi;
+       int n = 0;
+       DWORD dw;
+
+       ul = sizeof(fi);
+
+       do {
+               fi = (FIXED_INFO *)lws_malloc(ul, __func__);
+               if (!fi)
+                       goto oom;
+
+               dw = GetNetworkParams(fi, &ul);
+               if (dw == NO_ERROR)
+                       break;
+               if (dw != ERROR_BUFFER_OVERFLOW) {
+                       lwsl_err("%s: GetNetworkParams says 0x%x\n", __func__,
+                                (unsigned int)dw);
+
+                       return LADNS_CONF_SERVER_UNKNOWN;
+               }
+
+               lws_free(fi);
+               if (n++)
+                       /* not twice or more */
+                       goto oom;
+
+       } while (1);
+
+       /* if we got here, then we have it */
+
+       lwsl_info("%s: trying %s\n", __func__,
+                       fi->DnsServerList.IpAddress.String);
+       n = lws_sa46_parse_numeric_address(
+                       fi->DnsServerList.IpAddress.String, sa46);
+
+       lws_free(fi);
+
+       return n == 0 ? LADNS_CONF_SERVER_CHANGED :
+                       LADNS_CONF_SERVER_UNKNOWN;
+
+oom:
+       lwsl_err("%s: OOM\n", __func__);
+
+       return LADNS_CONF_SERVER_UNKNOWN;
+}
+
+int
+lws_plat_ntpclient_config(struct lws_context *context)
+{
+#if defined(LWS_HAVE_GETENV)
+       char *ntpsrv = getenv("LWS_NTP_SERVER");
+
+       if (ntpsrv && strlen(ntpsrv) < 64) {
+               lws_system_blob_heap_append(lws_system_get_blob(context,
+                                           LWS_SYSBLOB_TYPE_NTP_SERVER, 0),
+                                           (const uint8_t *)ntpsrv,
+                                           strlen(ntpsrv));
+               return 1;
+       }
+#endif
+       return 0;
+}
index 4036528..a64501d 100644 (file)
@@ -1,37 +1,40 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 #define _WINSOCK_DEPRECATED_NO_WARNINGS
 #endif
-#include "core/private.h"
+#include "private-lib-core.h"
 
 
 int
 _lws_plat_service_forced_tsi(struct lws_context *context, int tsi)
 {
        struct lws_context_per_thread *pt = &context->pt[tsi];
-       int m, n;
+       int m, n, r;
 
-       lws_service_flag_pending(context, tsi);
+       r = lws_service_flag_pending(context, tsi);
 
        /* any socket with events to service? */
        for (n = 0; n < (int)pt->fds_count; n++) {
@@ -48,38 +51,35 @@ _lws_plat_service_forced_tsi(struct lws_context *context, int tsi)
 
        lws_service_do_ripe_rxflow(pt);
 
-       return 0;
+       return r;
 }
 
+extern void lws_client_conn_wait_timeout(lws_sorted_usec_list_t *sul);
 
-LWS_EXTERN int
+int
 _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
 {
        struct lws_context_per_thread *pt;
-       WSANETWORKEVENTS networkevents;
        struct lws_pollfd *pfd;
        lws_usec_t timeout_us;
        struct lws *wsi;
        unsigned int i;
-       DWORD ev;
        int n;
-       unsigned int eIdx;
-       int interrupt_requested;
 
        /* stay dead once we are dead */
-       if (context == NULL || !context->vhost_list)
+       if (context == NULL)
                return 1;
 
        pt = &context->pt[tsi];
 
-       if (!pt->service_tid_detected) {
-               struct lws _lws;
+       if (!pt->service_tid_detected && context->vhost_list) {
+               lws_fakewsi_def_plwsa(pt);
 
-               memset(&_lws, 0, sizeof(_lws));
-               _lws.context = context;
+               lws_fakewsi_prep_plwsa_ctx(context);
 
                pt->service_tid = context->vhost_list->
-                       protocols[0].callback(&_lws, LWS_CALLBACK_GET_THREAD_ID,
+                       protocols[0].callback((struct lws *)plwsa,
+                                       LWS_CALLBACK_GET_THREAD_ID,
                                                  NULL, NULL, 0);
                pt->service_tid_detected = 1;
        }
@@ -122,100 +122,59 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
        }
 
        /*
-        * is there anybody with pending stuff that needs service forcing?
-        */
-       if (!lws_service_adjust_timeout(context, 1, tsi))
-               _lws_plat_service_forced_tsi(context, tsi);
-
-       /*
-        * service pending callbakcs and get maximum wait time
+        * service pending callbacks and get maximum wait time
         */
        {
                lws_usec_t us;
 
                lws_pt_lock(pt, __func__);
                /* don't stay in poll wait longer than next hr timeout */
-               us = __lws_sul_service_ripe(&pt->pt_sul_owner, lws_now_usecs());
+               us = __lws_sul_service_ripe(pt->pt_sul_owner,
+                                           LWS_COUNT_PT_SUL_OWNERS,
+                                           lws_now_usecs());
                if (us && us < timeout_us)
-                       timeout_us = us;
+                       /*
+                        * If something wants zero wait, that's OK, but if the next sul
+                        * coming ripe is an interval less than our wait resolution,
+                        * bump it to be the wait resolution.
+                        */
+                       timeout_us = us < context->us_wait_resolution ?
+                                       context->us_wait_resolution : us;
 
                lws_pt_unlock(pt);
        }
 
-       for (n = 0; n < (int)pt->fds_count; n++)
-               WSAEventSelect(pt->fds[n].fd, pt->events,
-                      FD_READ | (!!(pt->fds[n].events & LWS_POLLOUT) * FD_WRITE) |
-                      FD_OOB | FD_ACCEPT |
-                      FD_CONNECT | FD_CLOSE | FD_QOS |
-                      FD_ROUTING_INTERFACE_CHANGE |
-                      FD_ADDRESS_LIST_CHANGE);
-
-       ev = WSAWaitForMultipleEvents(1, &pt->events, FALSE,
-                                     (DWORD)(timeout_us / LWS_US_PER_MS), FALSE);
-       if (ev == WSA_WAIT_EVENT_0) {
-               EnterCriticalSection(&pt->interrupt_lock);
-               interrupt_requested = pt->interrupt_requested;
-               pt->interrupt_requested = 0;
-               LeaveCriticalSection(&pt->interrupt_lock);
-               if (interrupt_requested) {
-                       lws_broadcast(pt, LWS_CALLBACK_EVENT_WAIT_CANCELLED,
-                                     NULL, 0);
-                       return 0;
-               }
+       if (_lws_plat_service_forced_tsi(context, tsi))
+               timeout_us = 0;
 
-#if defined(LWS_WITH_TLS)
-               if (pt->context->tls_ops &&
-                   pt->context->tls_ops->fake_POLLIN_for_buffered)
-                       pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
-#endif
+       /*
+        * is there anybody with pending stuff that needs service forcing?
+        */
 
-               for (eIdx = 0; eIdx < pt->fds_count; ++eIdx) {
-                       unsigned int err;
-
-                       if (WSAEnumNetworkEvents(pt->fds[eIdx].fd, pt->events,
-                                       &networkevents) == SOCKET_ERROR) {
-                               lwsl_err("WSAEnumNetworkEvents() failed "
-                                        "with error %d\n", LWS_ERRNO);
-                               return -1;
-                       }
-
-                       if (!networkevents.lNetworkEvents)
-                               networkevents.lNetworkEvents = LWS_POLLOUT;
-
-                       pfd = &pt->fds[eIdx];
-                       pfd->revents = (short)networkevents.lNetworkEvents;
-
-                       err = networkevents.iErrorCode[FD_CONNECT_BIT];
-
-                       if ((networkevents.lNetworkEvents & FD_CONNECT) &&
-                            err && err != LWS_EALREADY &&
-                            err != LWS_EINPROGRESS && err != LWS_EWOULDBLOCK &&
-                            err != WSAEINVAL) {
-                               lwsl_debug("Unable to connect errno=%d\n", err);
-                               pfd->revents |= LWS_POLLHUP;
-                       }
-
-                       if (pfd->revents & LWS_POLLOUT) {
-                               wsi = wsi_from_fd(context, pfd->fd);
-                               if (wsi)
-                                       wsi->sock_send_blocking = 0;
-                       }
-                        /* if something closed, retry this slot */
-                       if (pfd->revents & LWS_POLLHUP)
-                               --eIdx;
-
-                       if (pfd->revents) {
-                               recv(pfd->fd, NULL, 0, 0);
-                               lws_service_fd_tsi(context, pfd, tsi);
-                       }
-               }
+       if (!lws_service_adjust_timeout(context, 1, tsi))
+               timeout_us = 0;
 
+//     lwsl_notice("%s: in %dms, count %d\n", __func__, (int)(timeout_us / 1000), pt->fds_count);
+//     for (n = 0; n < (int)pt->fds_count; n++)
+//             lwsl_notice("%s: fd %d ev 0x%x POLLIN %d, POLLOUT %d\n", __func__, (int)pt->fds[n].fd, (int)pt->fds[n].events, POLLIN, POLLOUT);
+       int d = WSAPoll((WSAPOLLFD *)&pt->fds[0], pt->fds_count, (int)(timeout_us / LWS_US_PER_MS));
+       if (d < 0) {
+               lwsl_err("%s: WSAPoll failed: count %d, err %d: %d\n", __func__, pt->fds_count, d, WSAGetLastError());
                return 0;
        }
+//     lwsl_notice("%s: out\n", __func__);
 
-       // if (ev == WSA_WAIT_TIMEOUT) { }
-       // if (ev == WSA_WAIT_FAILED)
-               // return 0;
+#if defined(LWS_WITH_TLS)
+       if (pt->context->tls_ops &&
+           pt->context->tls_ops->fake_POLLIN_for_buffered)
+               pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
+#endif
+
+       for (n = 0; n < (int)pt->fds_count; n++)
+               if (pt->fds[n].fd != LWS_SOCK_INVALID && pt->fds[n].revents) {
+//                     lwsl_notice("%s: idx %d, revents 0x%x\n", __func__, n, pt->fds[n].revents);
+                       lws_service_fd_tsi(context, &pt->fds[n], tsi);
+               }
 
        return 0;
 }
index 38910fc..ce9b719 100644 (file)
@@ -1,10 +1,42 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
 #define _WINSOCK_DEPRECATED_NO_WARNINGS
 #endif
-#include "core/private.h"
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+#include "private-lib-core.h"
 
+#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_HAVE_MBEDTLS_NET_SOCKETS)
+#include "mbedtls/net_sockets.h"
+#else
+#include "mbedtls/net.h"
+#endif
+#endif
 
-LWS_VISIBLE int
+int
 lws_send_pipe_choked(struct lws *wsi)
 {      struct lws *wsi_eff;
 
@@ -43,7 +75,7 @@ lws_poll_listen_fd(struct lws_pollfd *fd)
 }
 
 int
-lws_plat_set_nonblocking(int fd)
+lws_plat_set_nonblocking(lws_sockfd_type fd)
 {
        u_long optl = 1;
        int result = !!ioctlsocket(fd, FIONBIO, &optl);
@@ -109,15 +141,28 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd,
                lwsl_warn("setsockopt TCP_NODELAY 1 failed with error %d\n", error);
        }
 
-
        return lws_plat_set_nonblocking(fd);
 }
 
+int
+lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags)
+{
+       /*
+        * Seems to require "differeniated services" but no docs
+        *
+        * https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options
+        * https://docs.microsoft.com/en-us/previous-versions/windows/desktop/qos/differentiated-services
+        */
+       lwsl_warn("%s: not implemented on windows platform\n", __func__);
+
+       return 0;
+}
 
-LWS_EXTERN int
+int
 lws_interface_to_sa(int ipv6,
                const char *ifname, struct sockaddr_in *addr, size_t addrlen)
 {
+       long long address;
 #ifdef LWS_WITH_IPV6
        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
 
@@ -128,7 +173,7 @@ lws_interface_to_sa(int ipv6,
        }
 #endif
 
-       long long address = inet_addr(ifname);
+       address = inet_addr(ifname);
 
        if (address == INADDR_NONE) {
                struct hostent *entry = gethostbyname(ifname);
@@ -148,15 +193,20 @@ void
 lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
 {
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-       int n = LWS_POLLIN | LWS_POLLHUP | FD_CONNECT;
 
+#if defined(LWS_WITH_UDP)
        if (wsi->udp) {
                lwsl_info("%s: UDP\n", __func__);
-               = LWS_POLLIN;
+               pt->fds[pt->fds_count].events |= LWS_POLLIN;
        }
+#endif
+
+       if (context->event_loop_ops->io)
+               context->event_loop_ops->io(wsi, LWS_EV_START | LWS_EV_READ);
 
        pt->fds[pt->fds_count++].revents = 0;
-       WSAEventSelect(wsi->desc.sockfd, pt->events, n);
+
+       lws_plat_change_pollfd(context, wsi, &pt->fds[pt->fds_count - 1]);
 }
 
 void
@@ -187,31 +237,180 @@ lws_plat_check_connection_error(struct lws *wsi)
 }
 
 int
-lws_plat_change_pollfd(struct lws_context *context,
-                         struct lws *wsi, struct lws_pollfd *pfd)
+lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi,
+                      struct lws_pollfd *pfd)
 {
-       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-       long e = LWS_POLLHUP | FD_CONNECT;
+       //struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
 
-       if ((pfd->events & LWS_POLLIN))
-               e |= LWS_POLLIN;
+       return 0;
+}
 
-       if ((pfd->events & LWS_POLLOUT))
-               e |= LWS_POLLOUT;
+#if defined(LWS_WITH_TLS)
 
-       if (WSAEventSelect(wsi->desc.sockfd, pt->events, e) != SOCKET_ERROR)
+int
+lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost)
+{
+#if !defined(LWS_WITH_MBEDTLS) && defined(LWS_SSL_CLIENT_USE_OS_CA_CERTS)
+       PCCERT_CONTEXT pcc = NULL;
+       CERT_ENHKEY_USAGE* ceu = NULL;
+       DWORD ceu_alloc = 0;
+       X509_STORE* store;
+       HCERTSTORE hStore;
+       int imps = 0;
+
+       if (lws_check_opt(vhost->options,
+                         LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
                return 0;
 
-       lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO);
+       /*
+        * Windows Trust Store code adapted from curl (MIT) openssl.c
+        * https://github.com/warmcat/libwebsockets/pull/2233
+        */
+
+       store = SSL_CTX_get_cert_store(vhost->tls.ssl_client_ctx);
+       hStore = CertOpenSystemStore((HCRYPTPROV_LEGACY)NULL, TEXT("ROOT"));
 
-       return 1;
+       if (!hStore) {
+               lwsl_notice("%s: no store\n", __func__);
+               return 1;
+       }
+
+       do {
+               const unsigned char* ecert;
+               char cert_name[256];
+               DWORD req_size = 0;
+               BYTE key_usage[2];
+               FILETIME ft;
+               X509* x509;
+
+               pcc = CertEnumCertificatesInStore(hStore, pcc);
+               if (!pcc)
+                       break;
+
+               if (!CertGetNameStringA(pcc, CERT_NAME_SIMPLE_DISPLAY_TYPE,
+                                       0, NULL, cert_name, sizeof(cert_name)))
+                       strcpy(cert_name, "Unknown");
+
+               lwsl_debug("%s: Checking cert \"%s\"\n", __func__, cert_name);
+
+               ecert = (const unsigned char*)pcc->pbCertEncoded;
+               if (!ecert)
+                       continue;
+
+               GetSystemTimeAsFileTime(&ft);
+               if (CompareFileTime(&pcc->pCertInfo->NotBefore, &ft) > 0 ||
+                   CompareFileTime(&ft, &pcc->pCertInfo->NotAfter) > 0)
+                       continue;
+
+               /* If key usage exists check for signing attribute */
+               if (CertGetIntendedKeyUsage(pcc->dwCertEncodingType,
+                       pcc->pCertInfo,
+                       key_usage, sizeof(key_usage))) {
+                       if (!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
+                               continue;
+               } else
+                       if (GetLastError())
+                               continue;
+
+               /*
+                * If enhanced key usage exists check for server auth attribute.
+                *
+                * Note "In a Microsoft environment, a certificate might also
+                * have EKU extended properties that specify valid uses for the
+                * certificate."
+                * The call below checks both, and behavior varies depending on
+                * what is found. For more details see CertGetEnhancedKeyUsage
+                * doc.
+                */
+               if (!CertGetEnhancedKeyUsage(pcc, 0, NULL, &req_size))
+                       continue;
+
+               if (req_size && req_size > ceu_alloc) {
+                       void* tmp = lws_realloc(ceu, req_size, __func__);
+
+                       if (!tmp) {
+                               lwsl_err("%s: OOM", __func__);
+                               break;
+                       }
+
+                       ceu = (CERT_ENHKEY_USAGE*)tmp;
+                       ceu_alloc = req_size;
+               }
+
+               if (!CertGetEnhancedKeyUsage(pcc, 0, ceu, &req_size))
+                       continue;
+
+               if (!ceu || (ceu && !ceu->cUsageIdentifier)) {
+                       /*
+                        * "If GetLastError returns CRYPT_E_NOT_FOUND, the
+                        * certificate is good for all uses. If it returns
+                        * zero, the certificate has no valid uses."
+                        */
+                       if ((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
+                               continue;
+
+                       /* ... allow it... */
+
+               } else
+                       if (ceu) {
+                               BOOL found = FALSE;
+                               DWORD i;
+
+                               /*
+                                * If there is a CEU, check that it specifies
+                                * we can use the cert for server validation
+                                */
+
+                               for (i = 0; i < ceu->cUsageIdentifier; i++) {
+                                       if (strcmp("1.3.6.1.5.5.7.3.1"
+                                                  /* OID server auth */,
+                                                  ceu->rgpszUsageIdentifier[i]))
+                                               continue;
+
+                                       found = TRUE;
+                                       break;
+                               }
+
+                               if (!found)
+                                       /* Don't use cert if no usage match */
+                                       continue;
+                       }
+
+               x509 = d2i_X509(NULL, &ecert, pcc->cbCertEncoded);
+               if (!x509)
+                       /* We can't parse it as am X.509, skip it */
+                       continue;
+
+               if (X509_STORE_add_cert(store, x509) == 1) {
+                       lwsl_debug("%s: Imported cert \"%s\"\n", __func__,
+                                 cert_name);
+                       imps++;
+               }
+
+               /*
+                * Treat failure as nonfatal, eg, may be dupe
+                */
+
+               X509_free(x509);
+       } while (1);
+
+       lws_free(ceu);
+       CertFreeCertificateContext(pcc);
+       CertCloseStore(hStore, 0);
+
+       lwsl_notice("%s: Imported %d certs from plat store\n", __func__, imps);
+#endif
+
+       return 0;
 }
 
+#endif
+
 const char *
-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
+lws_plat_inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
 {
        WCHAR *buffer;
-       DWORD bufferlen = cnt;
+       size_t bufferlen = (size_t)cnt;
        BOOL ok = FALSE;
 
        buffer = lws_malloc(bufferlen * 2, "inet_ntop");
@@ -226,7 +425,9 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
                srcaddr.sin_family = AF_INET;
                memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
 
-               if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
+               if (!WSAAddressToStringW((struct sockaddr*)&srcaddr,
+                                       sizeof(srcaddr), 0, buffer,
+                                       (LPDWORD)&bufferlen))
                        ok = TRUE;
 #ifdef LWS_WITH_IPV6
        } else if (af == AF_INET6) {
@@ -235,7 +436,9 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
                srcaddr.sin6_family = AF_INET6;
                memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));
 
-               if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
+               if (!WSAAddressToStringW((struct sockaddr*)&srcaddr,
+                                        sizeof(srcaddr), 0, buffer,
+                                        (LPDWORD)&bufferlen))
                        ok = TRUE;
 #endif
        } else
@@ -245,7 +448,8 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
                int rv = WSAGetLastError();
                lwsl_err("WSAAddressToString() : %d\n", rv);
        } else {
-               if (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) <= 0)
+               if (WideCharToMultiByte(CP_ACP, 0, buffer, (int)bufferlen, dst,
+                                       cnt, 0, NULL) <= 0)
                        ok = FALSE;
        }
 
@@ -257,7 +461,7 @@ int
 lws_plat_inet_pton(int af, const char *src, void *dst)
 {
        WCHAR *buffer;
-       DWORD bufferlen = (int)strlen(src) + 1;
+       size_t bufferlen = strlen(src) + 1;
        BOOL ok = FALSE;
 
        buffer = lws_malloc(bufferlen * 2, "inet_pton");
@@ -266,7 +470,8 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
                return -1;
        }
 
-       if (MultiByteToWideChar(CP_ACP, 0, src, bufferlen, buffer, bufferlen) <= 0) {
+       if (MultiByteToWideChar(CP_ACP, 0, src, (int)bufferlen, buffer,
+                               (int)bufferlen) <= 0) {
                lwsl_err("Failed to convert multi byte to wide char\n");
                lws_free(buffer);
                return -1;
@@ -307,3 +512,98 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
        lws_free(buffer);
        return ok ? 1 : -1;
 }
+
+int
+lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+int
+lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, size_t canned_len,
+                         size_t n, int fd, const char *iface)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+int
+lws_plat_if_up(const char *ifname, int fd, int up)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+int
+lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+int
+lws_plat_ifconfig(int fd, uint8_t *ip, lws_dhcpc_ifstate_t *is)
+{
+       lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
+
+       return -1;
+}
+
+#if defined(LWS_WITH_MBEDTLS)
+int
+lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len)
+{
+       int fd = ((mbedtls_net_context *) ctx)->fd;
+       int ret, en;
+
+       if (fd < 0)
+               return MBEDTLS_ERR_NET_INVALID_CONTEXT;
+
+       ret = send(fd, buf, (unsigned int)len, 0);
+       if (ret >= 0)
+               return ret;
+
+       en = LWS_ERRNO;
+       if (en == EAGAIN || en == EWOULDBLOCK)
+               return MBEDTLS_ERR_SSL_WANT_WRITE;
+
+       ret = WSAGetLastError();
+       lwsl_notice("%s: errno %d, GLE %d\n", __func__, en, ret);
+       if (ret == WSAECONNRESET )
+            return( MBEDTLS_ERR_NET_CONN_RESET );
+
+       return MBEDTLS_ERR_NET_SEND_FAILED;
+}
+
+int
+lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)
+{
+       int fd = ((mbedtls_net_context *) ctx)->fd;
+       int ret, en;
+
+       if (fd < 0)
+               return MBEDTLS_ERR_NET_INVALID_CONTEXT;
+
+       ret = (int)recv(fd, buf, (unsigned int)len, 0);
+       if (ret >= 0)
+               return ret;
+
+       en = LWS_ERRNO;
+       if (en == EAGAIN || en == EWOULDBLOCK)
+               return MBEDTLS_ERR_SSL_WANT_READ;
+
+       ret = WSAGetLastError();
+       lwsl_notice("%s: errno %d, GLE %d\n", __func__, en, ret);
+
+        if (ret == WSAECONNRESET)
+            return MBEDTLS_ERR_NET_CONN_RESET;
+
+       return MBEDTLS_ERR_NET_RECV_FAILED;
+}
+#endif
+
diff --git a/lib/plat/windows/windows-spawn.c b/lib/plat/windows/windows-spawn.c
new file mode 100644 (file)
index 0000000..a7c0322
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+#include <tchar.h>
+#include <stdio.h>
+#include <strsafe.h>
+
+void
+lws_spawn_timeout(struct lws_sorted_usec_list *sul)
+{
+       struct lws_spawn_piped *lsp = lws_container_of(sul,
+                                       struct lws_spawn_piped, sul);
+
+       lwsl_warn("%s: spawn exceeded timeout, killing\n", __func__);
+
+       lws_spawn_piped_kill_child_process(lsp);
+}
+
+void
+lws_spawn_sul_reap(struct lws_sorted_usec_list *sul)
+{
+       struct lws_spawn_piped *lsp = lws_container_of(sul,
+                                       struct lws_spawn_piped, sul_reap);
+
+       lwsl_notice("%s: reaping spawn after last stdpipe, tries left %d\n",
+                   __func__, lsp->reap_retry_budget);
+       if (!lws_spawn_reap(lsp) && !lsp->pipes_alive) {
+               if (--lsp->reap_retry_budget) {
+                       lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
+                                        &lsp->sul_reap, lws_spawn_sul_reap,
+                                        250 * LWS_US_PER_MS);
+               } else {
+                       lwsl_err("%s: Unable to reap lsp %p, killing\n",
+                                __func__, lsp);
+                       lsp->reap_retry_budget = 20;
+                       lws_spawn_piped_kill_child_process(lsp);
+               }
+       }
+}
+
+static struct lws *
+lws_create_basic_wsi(struct lws_context *context, int tsi,
+                    const struct lws_role_ops *ops)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws *new_wsi;
+
+       if (!context->vhost_list)
+               return NULL;
+
+       if ((unsigned int)context->pt[tsi].fds_count ==
+           context->fd_limit_per_thread - 1) {
+               lwsl_err("no space for new conn\n");
+               return NULL;
+       }
+
+       lws_context_lock(context, __func__);
+       new_wsi = __lws_wsi_create_with_role(context, tsi, ops, NULL);
+       lws_context_unlock(context);
+       if (new_wsi == NULL) {
+               lwsl_err("Out of memory for new connection\n");
+               return NULL;
+       }
+
+       new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
+
+       /* initialize the instance struct */
+
+       lws_role_transition(new_wsi, 0, LRS_ESTABLISHED, ops);
+
+       new_wsi->hdr_parsing_completed = 0;
+       new_wsi->position_in_fds_table = LWS_NO_FDS_POS;
+
+       /*
+        * these can only be set once the protocol is known
+        * we set an unestablished connection's protocol pointer
+        * to the start of the defauly vhost supported list, so it can look
+        * for matching ones during the handshake
+        */
+
+       new_wsi->user_space = NULL;
+       new_wsi->desc.sockfd = LWS_SOCK_INVALID;
+
+       return new_wsi;
+}
+
+void
+lws_spawn_piped_destroy(struct lws_spawn_piped **_lsp)
+{
+       struct lws_spawn_piped *lsp = *_lsp;
+       struct lws *wsi;
+       int n;
+
+       if (!lsp)
+               return;
+
+       for (n = 0; n < 3; n++) {
+               if (lsp->pipe_fds[n][!!(n == 0)]) {
+                       CloseHandle(lsp->pipe_fds[n][n == 0]);
+                       lsp->pipe_fds[n][n == 0] = NULL;
+               }
+
+               for (n = 0; n < 3; n++) {
+                       if (lsp->stdwsi[n]) {
+                               lwsl_notice("%s: closing stdwsi %d\n", __func__, n);
+                               wsi = lsp->stdwsi[n];
+                               lsp->stdwsi[n]->desc.filefd = NULL;
+                               lsp->stdwsi[n] = NULL;
+                               lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
+                       }
+               }
+       }
+
+       lws_dll2_remove(&lsp->dll);
+
+       lws_sul_cancel(&lsp->sul);
+       lws_sul_cancel(&lsp->sul_reap);
+       lws_sul_cancel(&lsp->sul_poll);
+
+       lwsl_warn("%s: deleting lsp\n", __func__);
+
+       lws_free_set_NULL((*_lsp));
+}
+
+int
+lws_spawn_reap(struct lws_spawn_piped *lsp)
+{
+
+       void *opaque = lsp->info.opaque;
+       lsp_cb_t cb = lsp->info.reap_cb;
+       struct _lws_siginfo_t lsi;
+       lws_usec_t acct[4];
+       DWORD ex;
+
+       if (!lsp->child_pid)
+               return 0;
+
+       if (!GetExitCodeProcess(lsp->child_pid, &ex)) {
+               lwsl_notice("%s: GetExitCodeProcess failed\n", __func__);
+               return 0;
+       }
+
+       /* nonzero = success */
+
+       if (ex == STILL_ACTIVE) {
+               lwsl_notice("%s: still active\n", __func__);
+               return 0;
+       }
+
+       /* mark the earliest time we knew he had gone */
+       if (!lsp->reaped) {
+               lsp->reaped = lws_now_usecs();
+
+               /*
+                * Switch the timeout to restrict the amount of grace time
+                * to drain stdwsi
+                */
+
+               lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
+                                &lsp->sul, lws_spawn_timeout,
+                                5 * LWS_US_PER_SEC);
+       }
+
+       /*
+        * Stage finalizing our reaction to the process going down until the
+        * stdwsi flushed whatever is in flight and all noticed they were
+        * closed.  For that reason, each stdwsi close must call lws_spawn_reap
+        * to check if that was the last one and we can proceed with the reap.
+        */
+
+       if (!lsp->ungraceful && lsp->pipes_alive) {
+               lwsl_notice("%s: stdwsi alive, not reaping\n", __func__);
+               return 0;
+       }
+
+       /* we reached the reap point, no need for timeout wait */
+
+       lws_sul_cancel(&lsp->sul);
+
+       /*
+        * All the stdwsi went down, nothing more is coming... it's over
+        * Collect the final information and then reap the dead process
+        */
+
+       lsi.retcode = 0x10000 | (int)ex;
+       lwsl_notice("%s: process exit 0x%x\n", __func__, lsi.retcode);
+       lsp->child_pid = NULL;
+
+       /* destroy the lsp itself first (it's freed and plsp set NULL */
+
+       if (lsp->info.plsp)
+               lws_spawn_piped_destroy(lsp->info.plsp);
+
+       /* then do the parent callback informing it's destroyed */
+
+       memset(acct, 0, sizeof(acct));
+       if (cb)
+               cb(opaque, acct, &lsi, 0);
+
+       lwsl_notice("%s: completed reap\n", __func__);
+
+       return 1; /* was reaped */
+}
+
+int
+lws_spawn_piped_kill_child_process(struct lws_spawn_piped *lsp)
+{
+       if (!lsp->child_pid)
+               return 1;
+
+       lsp->ungraceful = 1; /* don't wait for flushing, just kill it */
+
+       if (lws_spawn_reap(lsp))
+               /* that may have invalidated lsp */
+               return 0;
+
+       lwsl_warn("%s: calling TerminateProcess on child pid\n", __func__);
+       TerminateProcess(lsp->child_pid, 252);
+       lws_spawn_reap(lsp);
+
+       /* that may have invalidated lsp */
+
+       return 0;
+}
+
+static void
+windows_pipe_poll_hack(lws_sorted_usec_list_t *sul)
+{
+       struct lws_spawn_piped *lsp = lws_container_of(sul,
+                                       struct lws_spawn_piped, sul_poll);
+       struct lws *wsi, *wsi1;
+       DWORD br;
+       char c;
+
+       /*
+        * Do it first, we know lsp exists and if it's destroyed inbetweentimes,
+        * it will already have cancelled this
+        */
+
+       lws_sul_schedule(lsp->context, 0, &lsp->sul_poll,
+                        windows_pipe_poll_hack, 50 * LWS_US_PER_MS);
+
+       wsi = lsp->stdwsi[LWS_STDOUT];
+       wsi1 = lsp->stdwsi[LWS_STDERR];
+       if (wsi && lsp->pipe_fds[LWS_STDOUT][0] != NULL) {
+               if (!PeekNamedPipe(lsp->pipe_fds[LWS_STDOUT][0], &c, 1, &br,
+                                  NULL, NULL)) {
+
+                       lwsl_notice("%s: stdout pipe errored\n", __func__);
+                       CloseHandle(lsp->stdwsi[LWS_STDOUT]->desc.filefd);
+                       lsp->pipe_fds[LWS_STDOUT][0] = NULL;
+                       lsp->stdwsi[LWS_STDOUT]->desc.filefd = NULL;
+                       lsp->stdwsi[LWS_STDOUT] = NULL;
+                       lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
+
+                       if (lsp->stdwsi[LWS_STDIN]) {
+                               lwsl_notice("%s: closing stdin from stdout close\n",
+                                               __func__);
+                               CloseHandle(lsp->stdwsi[LWS_STDIN]->desc.filefd);
+                               wsi = lsp->stdwsi[LWS_STDIN];
+                               lsp->stdwsi[LWS_STDIN]->desc.filefd = NULL;
+                               lsp->stdwsi[LWS_STDIN] = NULL;
+                               lsp->pipe_fds[LWS_STDIN][1] = NULL;
+                               lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
+                       }
+
+                       /*
+                        * lsp may be destroyed by here... if we wanted to
+                        * handle a still-extant stderr we'll get it next time
+                        */
+
+                       return;
+               } else
+                       if (br)
+                               wsi->a.protocol->callback(wsi,
+                                                       LWS_CALLBACK_RAW_RX_FILE,
+                                                       NULL, NULL, 0);
+       }
+
+       /*
+        * lsp may have been destroyed above
+        */
+
+       if (wsi1 && lsp->pipe_fds[LWS_STDERR][0]) {
+               if (!PeekNamedPipe(lsp->pipe_fds[LWS_STDERR][0], &c, 1, &br,
+                                  NULL, NULL)) {
+
+                       lwsl_notice("%s: stderr pipe errored\n", __func__);
+                       CloseHandle(wsi1->desc.filefd);
+                       /*
+                        * Assume is stderr still extant on entry, lsp can't
+                        * have been destroyed by stdout/stdin processing
+                        */
+                       lsp->stdwsi[LWS_STDERR]->desc.filefd = NULL;
+                       lsp->stdwsi[LWS_STDERR] = NULL;
+                       lsp->pipe_fds[LWS_STDERR][0] = NULL;
+                       lws_set_timeout(wsi1, 1, LWS_TO_KILL_SYNC);
+                       /*
+                        * lsp may have been destroyed above
+                        */
+               } else
+                       if (br)
+                               wsi1->a.protocol->callback(wsi1,
+                                                       LWS_CALLBACK_RAW_RX_FILE,
+                                                       NULL, NULL, 0);
+       }
+}
+
+
+
+/*
+ * Deals with spawning a subprocess and executing it securely with stdin/out/err
+ * diverted into pipes
+ */
+
+struct lws_spawn_piped *
+lws_spawn_piped(const struct lws_spawn_piped_info *i)
+{
+       const struct lws_protocols *pcol = i->vh->context->vhost_list->protocols;
+       struct lws_context *context = i->vh->context;
+       struct lws_spawn_piped *lsp;
+       PROCESS_INFORMATION pi;
+       SECURITY_ATTRIBUTES sa;
+       char cli[300], *p;
+       STARTUPINFO si;
+       int n;
+
+       if (i->protocol_name)
+               pcol = lws_vhost_name_to_protocol(i->vh, i->protocol_name);
+       if (!pcol) {
+               lwsl_err("%s: unknown protocol %s\n", __func__,
+                        i->protocol_name ? i->protocol_name : "default");
+
+               return NULL;
+       }
+
+       lsp = lws_zalloc(sizeof(*lsp), __func__);
+       if (!lsp) {
+               lwsl_err("%s: OOM\n", __func__);
+               return NULL;
+       }
+
+       /* wholesale take a copy of info */
+       lsp->info = *i;
+       lsp->context = context;
+       lsp->reap_retry_budget = 20;
+
+       /*
+        * Prepare the stdin / out / err pipes
+        */
+
+       for (n = 0; n < 3; n++) {
+               lsp->pipe_fds[n][0] = NULL;
+               lsp->pipe_fds[n][1] = NULL;
+       }
+
+       /* create pipes for [stdin|stdout] and [stderr] */
+
+       memset(&sa, 0, sizeof(sa));
+       sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+       sa.bInheritHandle = TRUE; /* inherit the pipes */
+       sa.lpSecurityDescriptor = NULL;
+
+       for (n = 0; n < 3; n++) {
+               DWORD waitmode = PIPE_NOWAIT;
+
+               if (!CreatePipe(&lsp->pipe_fds[n][0], &lsp->pipe_fds[n][1],
+                               &sa, 0)) {
+                       lwsl_err("%s: CreatePipe() failed\n", __func__);
+                       goto bail1;
+               }
+
+               SetNamedPipeHandleState(lsp->pipe_fds[1][0], &waitmode, NULL, NULL);
+               SetNamedPipeHandleState(lsp->pipe_fds[2][0], &waitmode, NULL, NULL);
+
+               /* don't inherit the pipe side that belongs to the parent */
+
+               if (!SetHandleInformation(&lsp->pipe_fds[n][!n],
+                                         HANDLE_FLAG_INHERIT, 0)) {
+                       lwsl_err("%s: SetHandleInformation() failed\n", __func__);
+                       //goto bail1;
+               }
+       }
+
+       /* create wsis for each stdin/out/err fd */
+
+       for (n = 0; n < 3; n++) {
+               lsp->stdwsi[n] = lws_create_basic_wsi(i->vh->context, i->tsi,
+                                         i->ops ? i->ops : &role_ops_raw_file);
+               if (!lsp->stdwsi[n]) {
+                       lwsl_err("%s: unable to create lsp stdwsi\n", __func__);
+                       goto bail2;
+               }
+
+                __lws_lc_tag(i->vh->context, &i->vh->context->lcg[LWSLCG_WSI],
+                            &lsp->stdwsi[n]->lc, "nspawn-stdwsi-%d", n);
+
+               lsp->stdwsi[n]->lsp_channel = n;
+               lws_vhost_bind_wsi(i->vh, lsp->stdwsi[n]);
+               lsp->stdwsi[n]->a.protocol = pcol;
+               lsp->stdwsi[n]->a.opaque_user_data = i->opaque;
+
+               lsp->stdwsi[n]->desc.filefd = lsp->pipe_fds[n][!n];
+               lsp->stdwsi[n]->file_desc = 1;
+
+               lwsl_debug("%s: lsp stdwsi %p: pipe idx %d -> fd %d / %d\n",
+                          __func__, lsp->stdwsi[n], n,
+                          lsp->pipe_fds[n][!!(n == 0)],
+                          lsp->pipe_fds[n][!(n == 0)]);
+
+#if 0
+
+               /* read side is 0, stdin we want the write side, others read */
+
+               lsp->stdwsi[n]->desc.filefd = lsp->pipe_fds[n][!!(n == 0)];
+               if (fcntl(lsp->pipe_fds[n][!!(n == 0)], F_SETFL, O_NONBLOCK) < 0) {
+                       lwsl_err("%s: setting NONBLOCK failed\n", __func__);
+                       goto bail2;
+               }
+#endif
+       }
+
+       for (n = 0; n < 3; n++)
+               if (i->opt_parent) {
+                       lsp->stdwsi[n]->parent = i->opt_parent;
+                       lsp->stdwsi[n]->sibling_list = i->opt_parent->child_list;
+                       i->opt_parent->child_list = lsp->stdwsi[n];
+               }
+
+       lwsl_notice("%s: pipe handles in %p, out %p, err %p\n", __func__,
+                  lsp->stdwsi[LWS_STDIN]->desc.sockfd,
+                  lsp->stdwsi[LWS_STDOUT]->desc.sockfd,
+                  lsp->stdwsi[LWS_STDERR]->desc.sockfd);
+
+       /*
+        * Windows nonblocking pipe handling is a mess that is unable
+        * to interoperate with WSA-based wait as far as I can tell.
+        *
+        * Let's set up a sul to poll the pipes and synthesize the
+        * protocol callbacks if anything coming.
+        */
+       lws_sul_schedule(context, 0, &lsp->sul_poll, windows_pipe_poll_hack,
+                        50 * LWS_US_PER_MS);
+
+
+       /*
+        * Windows wants a single string commandline
+        */
+       p = cli;
+       n = 0;
+       while (i->exec_array[n]) {
+               lws_strncpy(p, i->exec_array[n],
+                           sizeof(cli) - lws_ptr_diff(p, cli));
+               if (sizeof(cli) - lws_ptr_diff(p, cli) < 4)
+                       break;
+               p += strlen(p);
+               *p++ = ' ';
+               *p = '\0';
+               n++;
+       }
+
+       puts(cli);
+
+       memset(&pi, 0, sizeof(pi));
+       memset(&si, 0, sizeof(si));
+
+       si.cb           = sizeof(STARTUPINFO);
+       si.hStdInput    = lsp->pipe_fds[LWS_STDIN][0];
+       si.hStdOutput   = lsp->pipe_fds[LWS_STDOUT][1];
+       si.hStdError    = lsp->pipe_fds[LWS_STDERR][1];
+       si.dwFlags      = STARTF_USESTDHANDLES | CREATE_NO_WINDOW;
+       si.wShowWindow  = TRUE;
+
+       if (!CreateProcess(NULL, cli, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
+               lwsl_err("%s: CreateProcess failed 0x%x\n", __func__,
+                               (unsigned long)GetLastError());
+               goto bail3;
+       }
+
+       lsp->child_pid = pi.hProcess;
+
+       lwsl_notice("%s: lsp %p spawned PID %d\n", __func__, lsp, lsp->child_pid);
+
+       lws_sul_schedule(context, i->tsi, &lsp->sul, lws_spawn_timeout,
+                        i->timeout_us ? i->timeout_us : 300 * LWS_US_PER_SEC);
+
+       /*
+        *  close:                stdin:r, stdout:w, stderr:w
+        */
+       for (n = 0; n < 3; n++)
+               CloseHandle(lsp->pipe_fds[n][n != 0]);
+
+       lsp->pipes_alive = 3;
+       lsp->created = lws_now_usecs();
+
+       if (i->owner)
+               lws_dll2_add_head(&lsp->dll, i->owner);
+
+       if (i->timeout_us)
+               lws_sul_schedule(context, i->tsi, &lsp->sul,
+                                lws_spawn_timeout, i->timeout_us);
+
+       return lsp;
+
+bail3:
+
+       lws_sul_cancel(&lsp->sul_poll);
+
+       while (--n >= 0)
+               __remove_wsi_socket_from_fds(lsp->stdwsi[n]);
+bail2:
+       for (n = 0; n < 3; n++)
+               if (lsp->stdwsi[n])
+                       __lws_free_wsi(lsp->stdwsi[n]);
+
+bail1:
+       for (n = 0; n < 3; n++) {
+               if (lsp->pipe_fds[n][0] >= 0)
+                       CloseHandle(lsp->pipe_fds[n][0]);
+               if (lsp->pipe_fds[n][1] >= 0)
+                       CloseHandle(lsp->pipe_fds[n][1]);
+       }
+
+       lws_free(lsp);
+
+       lwsl_err("%s: failed\n", __func__);
+
+       return NULL;
+}
+
+void
+lws_spawn_stdwsi_closed(struct lws_spawn_piped *lsp, struct lws *wsi)
+{
+       int n;
+
+       assert(lsp);
+       lsp->pipes_alive--;
+       lwsl_debug("%s: pipes alive %d\n", __func__, lsp->pipes_alive);
+       if (!lsp->pipes_alive)
+               lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
+                               &lsp->sul_reap, lws_spawn_sul_reap, 1);
+
+       for (n = 0; n < 3; n++)
+               if (lsp->stdwsi[n] == wsi)
+                       lsp->stdwsi[n] = NULL;
+}
+
+int
+lws_spawn_get_stdfd(struct lws *wsi)
+{
+       return wsi->lsp_channel;
+}
diff --git a/lib/roles/CMakeLists.txt b/lib/roles/CMakeLists.txt
new file mode 100644 (file)
index 0000000..000cd93
--- /dev/null
@@ -0,0 +1,93 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+if (LWS_ROLE_MQTT)
+       add_subdir_include_directories(mqtt)
+endif()
+
+if (LWS_ROLE_DBUS AND NOT LWS_PLAT_FREERTOS)
+       add_subdir_include_directories(dbus)
+endif()
+
+if (LWS_ROLE_H1 OR LWS_ROLE_H2)
+       add_subdir_include_directories(http)
+endif()
+
+if (LWS_ROLE_H1)
+       add_subdir_include_directories(h1)
+endif()
+
+if (LWS_ROLE_H2)
+       add_subdir_include_directories(h2)
+endif()
+
+if (LWS_ROLE_WS)
+       add_subdir_include_directories(ws)
+endif()
+
+if (LWS_ROLE_RAW)
+       add_subdir_include_directories(raw-skt)
+endif()
+
+if (LWS_ROLE_RAW_FILE)
+       add_subdir_include_directories(raw-file)
+endif()
+
+if (LWS_WITH_CGI)
+       add_subdir_include_directories(cgi)
+endif()
+
+if (LWS_ROLE_RAW_PROXY)
+       add_subdir_include_directories(raw-proxy)
+endif()
+
+if (NOT LWS_WITHOUT_SERVER OR LWS_WITH_SECURE_STREAMS_PROCESS_API)
+       add_subdir_include_directories(listen)
+endif()
+
+if (LWS_WITH_CLIENT AND (LWS_ROLE_H1 OR LWS_ROLE_H2))
+       list(APPEND SOURCES
+               roles/http/client/client-http.c)
+endif()
+
+if (LWS_WITH_NETLINK)
+       list(APPEND SOURCES roles/netlink/ops-netlink.c)
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+set(LWS_DEPS_LIB_PATHS ${LWS_DEPS_LIB_PATHS} PARENT_SCOPE)
+
index 7905cfa..2119077 100644 (file)
@@ -16,7 +16,7 @@ You inherit all the well-maintained lws core functionality around:
 
  - connection lifecycle sequencing in a valgrind-clean way
 
- - proxy support, HTTP and Socks5
+ - client connection proxy support, for HTTP and Socks5
 
  - tls support working equally on mbedTLS and OpenSSL and derivatives without any code in the role
 
@@ -54,7 +54,7 @@ If the role is disabled in cmake, nothing in its directory is built.
 
 ### Role ops struct
 
-The role is defined by `struct lws_role_ops` in `lib/roles/private.h`,
+The role is defined by `struct lws_role_ops` in `lib/roles/private-lib-roles.h`,
 each role instantiates one of these and fills in the appropriate ops
 callbacks to perform its job.  By convention that lives in
 `./lib/roles/**role name**/ops-**role_name**.c`.
@@ -64,15 +64,15 @@ callbacks to perform its job.  By convention that lives in
 Truly private declarations for the role can go in the role directory as you like.
 However when the declarations must be accessible to other things in lws build, eg,
 the role adds members to `struct lws` when enabled, they should be in the role
-directory in a file `private.h`.
+directory in a file `private-lib-roles-myrole.h`.
 
-Search for "bring in role private declarations" in `./lib/roles/private.h
+Search for "bring in role private declarations" in `./lib/roles/private-lib-roles.h
 and add your private role file there following the style used for the other roles,
 eg,
 
 ```
 #if defined(LWS_ROLE_WS)
- #include "roles/ws/private.h"
+ #include "roles/ws/private-lib-roles-ws.h"
 #else
  #define lwsi_role_ws(wsi) (0)
 #endif
@@ -159,3 +159,12 @@ The core support for wsis in lws has some generic concepts
  - You set the initial binding, role flags and state using `lws_role_transition()`.  Afterwards
    you can adjust the state using `lwsi_set_state()`.
 
+### Role ops compression
+
+Since the role ops struct is typically only sparsely filled, rather than have 20 function
+pointers most of which may be NULL, there is a separate array of a union of function
+pointers that is just long enough for functions that exist in the role, and a nybble index
+table with a nybble for each possible op, either 0 indicating that the operation is not
+provided in this role, or 1 - 15 indicating the position of the function pointer in the
+array.
+
diff --git a/lib/roles/cgi/CMakeLists.txt b/lib/roles/cgi/CMakeLists.txt
new file mode 100644 (file)
index 0000000..12c83e3
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       roles/cgi/cgi-server.c
+       roles/cgi/ops-cgi.c)
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
index b064aae..cd039e8 100644 (file)
@@ -1,27 +1,32 @@
 /*
- * libwebsockets - CGI management
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#define  _GNU_SOURCE
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #if defined(WIN32) || defined(_WIN32)
 #else
@@ -30,6 +35,9 @@
 
 static const char *hex = "0123456789ABCDEF";
 
+void
+lws_cgi_sul_cb(lws_sorted_usec_list_t *sul);
+
 static int
 urlencode(const char *in, int inlen, char *out, int outlen)
 {
@@ -60,73 +68,63 @@ urlencode(const char *in, int inlen, char *out, int outlen)
        if (out >= end - 4)
                return -1;
 
-       return out - start;
+       return lws_ptr_diff(out, start);
 }
 
-static struct lws *
-lws_create_basic_wsi(struct lws_context *context, int tsi)
+static void
+lws_cgi_grace(lws_sorted_usec_list_t *sul)
 {
-       struct lws *new_wsi;
+       struct lws_cgi *cgi = lws_container_of(sul, struct lws_cgi, sul_grace);
 
-       if (!context->vhost_list)
-               return NULL;
+       /* act on the reap cb from earlier */
 
-       if ((unsigned int)context->pt[tsi].fds_count ==
-           context->fd_limit_per_thread - 1) {
-               lwsl_err("no space for new conn\n");
-               return NULL;
-       }
+       if (!cgi->wsi->http.cgi->post_in_expected)
+               cgi->wsi->http.cgi->cgi_transaction_over = 1;
 
-       new_wsi = lws_zalloc(sizeof(struct lws), "new wsi");
-       if (new_wsi == NULL) {
-               lwsl_err("Out of memory for new connection\n");
-               return NULL;
-       }
+       lws_callback_on_writable(cgi->wsi);
+}
 
-       new_wsi->tsi = tsi;
-       new_wsi->context = context;
-       new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
-       new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
 
-       /* initialize the instance struct */
+static void
+lws_cgi_reap_cb(void *opaque, lws_usec_t *accounting, siginfo_t *si,
+                int we_killed_him)
+{
+       struct lws *wsi = (struct lws *)opaque;
 
-       lws_role_transition(new_wsi, 0, LRS_ESTABLISHED, &role_ops_cgi);
+       /*
+        * The cgi has come to an end, by itself or with a signal...
+        */
 
-       new_wsi->hdr_parsing_completed = 0;
-       new_wsi->position_in_fds_table = LWS_NO_FDS_POS;
+       lwsl_wsi_info(wsi, "post_in_expected %d",
+                          (int)wsi->http.cgi->post_in_expected);
 
        /*
-        * these can only be set once the protocol is known
-        * we set an unestablished connection's protocol pointer
-        * to the start of the defauly vhost supported list, so it can look
-        * for matching ones during the handshake
+        * Grace period to handle the incoming stdout
         */
-       new_wsi->protocol = context->vhost_list->protocols;
-       new_wsi->user_space = NULL;
-       new_wsi->desc.sockfd = LWS_SOCK_INVALID;
-       context->count_wsi_allocated++;
 
-       return new_wsi;
+       lws_sul_schedule(wsi->a.context, wsi->tsi, &wsi->http.cgi->sul_grace,
+                        lws_cgi_grace, 1 * LWS_US_PER_SEC);
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_cgi(struct lws *wsi, const char * const *exec_array,
        int script_uri_path_len, int timeout_secs,
        const struct lws_protocol_vhost_options *mp_cgienv)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_spawn_piped_info info;
        char *env_array[30], cgi_path[500], e[1024], *p = e,
             *end = p + sizeof(e) - 1, tok[256], *t, *sum, *sumend;
        struct lws_cgi *cgi;
        int n, m = 0, i, uritok = -1, c;
 
        /*
-        * give the master wsi a cgi struct
+        * give the cgi stream wsi a cgi struct
         */
 
        wsi->http.cgi = lws_zalloc(sizeof(*wsi->http.cgi), "new cgi");
        if (!wsi->http.cgi) {
-               lwsl_err("%s: OOM\n", __func__);
+               lwsl_wsi_err(wsi, "OOM");
                return -1;
        }
 
@@ -137,65 +135,6 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
        sum = cgi->summary;
        sumend = sum + strlen(cgi->summary) - 1;
 
-       for (n = 0; n < 3; n++) {
-               cgi->pipe_fds[n][0] = -1;
-               cgi->pipe_fds[n][1] = -1;
-       }
-
-       /* create pipes for [stdin|stdout] and [stderr] */
-
-       for (n = 0; n < 3; n++)
-               if (pipe(cgi->pipe_fds[n]) == -1)
-                       goto bail1;
-
-       /* create cgi wsis for each stdin/out/err fd */
-
-       for (n = 0; n < 3; n++) {
-               cgi->stdwsi[n] = lws_create_basic_wsi(wsi->context, wsi->tsi);
-               if (!cgi->stdwsi[n]) {
-                       lwsl_err("%s: unable to create cgi stdwsi\n", __func__);
-                       goto bail2;
-               }
-               cgi->stdwsi[n]->cgi_channel = n;
-               lws_vhost_bind_wsi(wsi->vhost, cgi->stdwsi[n]);
-
-               lwsl_debug("%s: cgi stdwsi %p: pipe idx %d -> fd %d / %d\n", __func__,
-                          cgi->stdwsi[n], n, cgi->pipe_fds[n][!!(n == 0)],
-                          cgi->pipe_fds[n][!(n == 0)]);
-
-               /* read side is 0, stdin we want the write side, others read */
-               cgi->stdwsi[n]->desc.sockfd = cgi->pipe_fds[n][!!(n == 0)];
-               if (fcntl(cgi->pipe_fds[n][!!(n == 0)], F_SETFL,
-                   O_NONBLOCK) < 0) {
-                       lwsl_err("%s: setting NONBLOCK failed\n", __func__);
-                       goto bail2;
-               }
-       }
-
-       for (n = 0; n < 3; n++) {
-               if (wsi->context->event_loop_ops->accept)
-                       if (wsi->context->event_loop_ops->accept(cgi->stdwsi[n]))
-                               goto bail3;
-
-               if (__insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
-                       goto bail3;
-               cgi->stdwsi[n]->parent = wsi;
-               cgi->stdwsi[n]->sibling_list = wsi->child_list;
-               wsi->child_list = cgi->stdwsi[n];
-       }
-
-       if (lws_change_pollfd(cgi->stdwsi[LWS_STDIN], LWS_POLLIN, LWS_POLLOUT))
-               goto bail3;
-       if (lws_change_pollfd(cgi->stdwsi[LWS_STDOUT], LWS_POLLOUT, LWS_POLLIN))
-               goto bail3;
-       if (lws_change_pollfd(cgi->stdwsi[LWS_STDERR], LWS_POLLOUT, LWS_POLLIN))
-               goto bail3;
-
-       lwsl_debug("%s: fds in %d, out %d, err %d\n", __func__,
-                  cgi->stdwsi[LWS_STDIN]->desc.sockfd,
-                  cgi->stdwsi[LWS_STDOUT]->desc.sockfd,
-                  cgi->stdwsi[LWS_STDERR]->desc.sockfd);
-
        if (timeout_secs)
                lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);
 
@@ -203,11 +142,16 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
        wsi->hdr_state = LCHS_HEADER;
 
        /* add us to the pt list of active cgis */
-       lwsl_debug("%s: adding cgi %p to list\n", __func__, wsi->http.cgi);
+       lwsl_wsi_debug(wsi, "adding cgi %p to list", wsi->http.cgi);
        cgi->cgi_list = pt->http.cgi_list;
        pt->http.cgi_list = cgi;
 
-       sum += lws_snprintf(sum, sumend - sum, "%s ", exec_array[0]);
+       /* if it's not already running, start the cleanup timer */
+       if (!pt->sul_cgi.list.owner)
+               lws_sul_schedule(pt->context, (int)(pt - pt->context->pt), &pt->sul_cgi,
+                                lws_cgi_sul_cb, 3 * LWS_US_PER_SEC);
+
+       sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s ", exec_array[0]);
 
        if (0) {
                char *pct = lws_hdr_simple_ptr(wsi,
@@ -223,7 +167,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
 
        if (lws_is_ssl(wsi)) {
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "HTTPS=ON");
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTPS=ON");
                p++;
        }
 
@@ -231,10 +175,12 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
                static const unsigned char meths[] = {
                        WSI_TOKEN_GET_URI,
                        WSI_TOKEN_POST_URI,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
                        WSI_TOKEN_OPTIONS_URI,
                        WSI_TOKEN_PUT_URI,
                        WSI_TOKEN_PATCH_URI,
                        WSI_TOKEN_DELETE_URI,
+#endif
                        WSI_TOKEN_CONNECT,
                        WSI_TOKEN_HEAD_URI,
                #ifdef LWS_WITH_HTTP2
@@ -242,7 +188,10 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
                #endif
                };
                static const char * const meth_names[] = {
-                       "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE",
+                       "GET", "POST",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
+                       "OPTIONS", "PUT", "PATCH", "DELETE",
+#endif
                        "CONNECT", "HEAD", ":path"
                };
 
@@ -255,35 +204,37 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
                                }
 
                if (script_uri_path_len < 0 && uritok < 0)
-                       goto bail3;
+                       goto bail;
 //             if (script_uri_path_len < 0)
 //                     uritok = 0;
 
                if (m >= 0) {
                        env_array[n++] = p;
-                       if (m < 8) {
-                               p += lws_snprintf(p, end - p,
+                       if (m < (int)LWS_ARRAY_SIZE(meths) - 1) {
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
                                                  "REQUEST_METHOD=%s",
                                                  meth_names[m]);
-                               sum += lws_snprintf(sum, sumend - sum, "%s ",
+                               sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s ",
                                                    meth_names[m]);
+#if defined(LWS_ROLE_H2)
                        } else {
-                               p += lws_snprintf(p, end - p,
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
                                                  "REQUEST_METHOD=%s",
                          lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD));
-                               sum += lws_snprintf(sum, sumend - sum, "%s ",
+                               sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s ",
                                        lws_hdr_simple_ptr(wsi,
                                                  WSI_TOKEN_HTTP_COLON_METHOD));
+#endif
                        }
                        p++;
                }
 
                if (uritok >= 0)
-                       sum += lws_snprintf(sum, sumend - sum, "%s ",
-                                           lws_hdr_simple_ptr(wsi, uritok));
+                       sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s ",
+                                           lws_hdr_simple_ptr(wsi, (enum lws_token_indexes)uritok));
 
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "QUERY_STRING=");
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "QUERY_STRING=");
                /* dump the individual URI Arg parameters */
                m = 0;
                while (script_uri_path_len >= 0) {
@@ -296,7 +247,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
                                *p++ = *t++;
                        if (*t == '=')
                                *p++ = *t++;
-                       i = urlencode(t, i- (t - tok), p, end - p);
+                       i = urlencode(t, i - lws_ptr_diff(t, tok), p, lws_ptr_diff(end, p));
                        if (i > 0) {
                                p += i;
                                *p++ = '&';
@@ -310,71 +261,75 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
                if (uritok >= 0) {
                        strcpy(cgi_path, "REQUEST_URI=");
                        c = lws_hdr_copy(wsi, cgi_path + 12,
-                                        sizeof(cgi_path) - 12, uritok);
+                                        sizeof(cgi_path) - 12, (enum lws_token_indexes)uritok);
                        if (c < 0)
-                               goto bail3;
+                               goto bail;
 
                        cgi_path[sizeof(cgi_path) - 1] = '\0';
                        env_array[n++] = cgi_path;
                }
 
-               sum += lws_snprintf(sum, sumend - sum, "%s", env_array[n - 1]);
+               sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s", env_array[n - 1]);
 
                if (script_uri_path_len >= 0) {
                        env_array[n++] = p;
-                       p += lws_snprintf(p, end - p, "PATH_INFO=%s",
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "PATH_INFO=%s",
                                      cgi_path + 12 + script_uri_path_len);
                        p++;
                }
        }
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
        if (script_uri_path_len >= 0 &&
            lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) {
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "HTTP_REFERER=%s",
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_REFERER=%s",
                              lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_REFERER));
                p++;
        }
+#endif
        if (script_uri_path_len >= 0 &&
            lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "HTTP_HOST=%s",
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_HOST=%s",
                              lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
                p++;
        }
        if (script_uri_path_len >= 0 &&
            lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "HTTP_COOKIE=");
-               m = lws_hdr_copy(wsi, p, end - p, WSI_TOKEN_HTTP_COOKIE);
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_COOKIE=");
+               m = lws_hdr_copy(wsi, p, lws_ptr_diff(end, p), WSI_TOKEN_HTTP_COOKIE);
                if (m > 0)
                        p += lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE);
                *p++ = '\0';
        }
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
        if (script_uri_path_len >= 0 &&
            lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) {
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "HTTP_USER_AGENT=%s",
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_USER_AGENT=%s",
                            lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT));
                p++;
        }
+#endif
        if (script_uri_path_len >= 0 &&
            lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING)) {
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "HTTP_CONTENT_ENCODING=%s",
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_CONTENT_ENCODING=%s",
                      lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING));
                p++;
        }
        if (script_uri_path_len >= 0 &&
            lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT)) {
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "HTTP_ACCEPT=%s",
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_ACCEPT=%s",
                              lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT));
                p++;
        }
        if (script_uri_path_len >= 0 &&
            lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)) {
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "HTTP_ACCEPT_ENCODING=%s",
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_ACCEPT_ENCODING=%s",
                      lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING));
                p++;
        }
@@ -382,37 +337,37 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
            uritok == WSI_TOKEN_POST_URI) {
                if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
                        env_array[n++] = p;
-                       p += lws_snprintf(p, end - p, "CONTENT_TYPE=%s",
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "CONTENT_TYPE=%s",
                          lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE));
                        p++;
                }
                if (!wsi->http.cgi->gzip_inflate &&
                    lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
                        env_array[n++] = p;
-                       p += lws_snprintf(p, end - p, "CONTENT_LENGTH=%s",
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "CONTENT_LENGTH=%s",
                                          lws_hdr_simple_ptr(wsi,
                                          WSI_TOKEN_HTTP_CONTENT_LENGTH));
                        p++;
                }
 
                if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH))
-                       wsi->http.cgi->post_in_expected =
+                       wsi->http.cgi->post_in_expected = (lws_filepos_t)
                                atoll(lws_hdr_simple_ptr(wsi,
                                                WSI_TOKEN_HTTP_CONTENT_LENGTH));
        }
 
 
        env_array[n++] = p;
-       p += lws_snprintf(p, end - p, "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin");
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin");
        p++;
 
        env_array[n++] = p;
-       p += lws_snprintf(p, end - p, "SCRIPT_PATH=%s", exec_array[0]);
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "SCRIPT_PATH=%s", exec_array[0]);
        p++;
 
        while (mp_cgienv) {
                env_array[n++] = p;
-               p += lws_snprintf(p, end - p, "%s=%s", mp_cgienv->name,
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s=%s", mp_cgienv->name,
                              mp_cgienv->value);
                if (!strcmp(mp_cgienv->name, "GIT_PROJECT_ROOT")) {
                        wsi->http.cgi->implied_chunked = 1;
@@ -425,7 +380,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
        }
 
        env_array[n++] = p;
-       p += lws_snprintf(p, end - p, "SERVER_SOFTWARE=libwebsockets");
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "SERVER_SOFTWARE=lws");
        p++;
 
        env_array[n] = NULL;
@@ -435,108 +390,48 @@ lws_cgi(struct lws *wsi, const char * const *exec_array,
                lwsl_notice("    %s\n", env_array[m]);
 #endif
 
+       memset(&info, 0, sizeof(info));
+       info.env_array = (const char **)env_array;
+       info.exec_array = exec_array;
+       info.max_log_lines = 20000;
+       info.opt_parent = wsi;
+       info.timeout_us = 5 * 60 * LWS_US_PER_SEC;
+       info.tsi = wsi->tsi;
+       info.vh = wsi->a.vhost;
+       info.ops = &role_ops_cgi;
+       info.plsp = &wsi->http.cgi->lsp;
+       info.opaque = wsi;
+       info.reap_cb = lws_cgi_reap_cb;
+
        /*
         * Actually having made the env, as a cgi we don't need the ah
         * any more
         */
-       if (script_uri_path_len >= 0)
+       if (script_uri_path_len >= 0) {
                lws_header_table_detach(wsi, 0);
-
-       /* we are ready with the redirection pipes... run the thing */
-#if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)
-       cgi->pid = fork();
-#else
-       cgi->pid = vfork();
-#endif
-       if (cgi->pid < 0) {
-               lwsl_err("fork failed, errno %d", errno);
-               goto bail3;
+               info.disable_ctrlc = 1;
        }
 
-#if defined(__linux__)
-       prctl(PR_SET_PDEATHSIG, SIGTERM);
-#endif
-       if (script_uri_path_len >= 0)
-               /* stops non-daemonized main processess getting SIGINT
-                * from TTY */
-               setpgrp();
-
-       if (cgi->pid) {
-               /* we are the parent process */
-               wsi->context->count_cgi_spawned++;
-               lwsl_info("%s: cgi %p spawned PID %d\n", __func__,
-                          cgi, cgi->pid);
-
-               /*
-                *  close:                stdin:r, stdout:w, stderr:w
-                * hide from other forks: stdin:w, stdout:r, stderr:r
-                */
-               for (n = 0; n < 3; n++) {
-                       lws_plat_apply_FD_CLOEXEC(cgi->pipe_fds[n][!!(n == 0)]);
-                       close(cgi->pipe_fds[n][!(n == 0)]);
-               }
-
-               /* inform cgi owner of the child PID */
-               n = user_callback_handle_rxflow(wsi->protocol->callback, wsi,
-                                           LWS_CALLBACK_CGI_PROCESS_ATTACH,
-                                           wsi->user_space, NULL, cgi->pid);
-               (void)n;
-
-               return 0;
+       wsi->http.cgi->lsp = lws_spawn_piped(&info);
+       if (!wsi->http.cgi->lsp) {
+               lwsl_err("%s: spawn failed\n", __func__);
+               goto bail;
        }
 
-       /* somewhere we can at least read things and enter it */
-       if (chdir("/tmp"))
-               lwsl_notice("%s: Failed to chdir\n", __func__);
+       /* we are the parent process */
 
-       /* We are the forked process, redirect and kill inherited things.
-        *
-        * Because of vfork(), we cannot do anything that changes pages in
-        * the parent environment.  Stuff that changes kernel state for the
-        * process is OK.  Stuff that happens after the execvpe() is OK.
-        */
+       wsi->a.context->count_cgi_spawned++;
 
-       for (m = 0; m < 3; m++) {
-               if (dup2(cgi->pipe_fds[m][!(m == 0)], m) < 0) {
-                       lwsl_err("%s: stdin dup2 failed\n", __func__);
-                       goto bail3;
-               }
-               close(cgi->pipe_fds[m][0]);
-               close(cgi->pipe_fds[m][1]);
-       }
+       /* inform cgi owner of the child PID */
+       n = user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
+                                   LWS_CALLBACK_CGI_PROCESS_ATTACH,
+                                   wsi->user_space, NULL, (unsigned int)cgi->lsp->child_pid);
+       (void)n;
 
-#if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE)
-       for (m = 0; m < n; m++) {
-               p = strchr(env_array[m], '=');
-               *p++ = '\0';
-               setenv(env_array[m], p, 1);
-       }
-       execvp(exec_array[0], (char * const *)&exec_array[0]);
-#else
-       execvpe(exec_array[0], (char * const *)&exec_array[0], &env_array[0]);
-#endif
-
-       exit(1);
-
-bail3:
-       /* drop us from the pt cgi list */
-       pt->http.cgi_list = cgi->cgi_list;
-
-       while (--n >= 0)
-               __remove_wsi_socket_from_fds(wsi->http.cgi->stdwsi[n]);
-bail2:
-       for (n = 0; n < 3; n++)
-               if (wsi->http.cgi->stdwsi[n])
-                       __lws_free_wsi(cgi->stdwsi[n]);
-
-bail1:
-       for (n = 0; n < 3; n++) {
-               if (cgi->pipe_fds[n][0] >= 0)
-                       close(cgi->pipe_fds[n][0]);
-               if (cgi->pipe_fds[n][1] >= 0)
-                       close(cgi->pipe_fds[n][1]);
-       }
+       return 0;
 
+bail:
+       lws_sul_cancel(&wsi->http.cgi->sul_grace);
        lws_free_set_NULL(wsi->http.cgi);
 
        lwsl_err("%s: failed\n", __func__);
@@ -561,7 +456,7 @@ enum header_recode {
        HR_CRLF,
 };
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_cgi_write_split_stdout_headers(struct lws *wsi)
 {
        int n, m, cmd;
@@ -580,10 +475,10 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
                 */
                switch (wsi->hdr_state) {
                case LHCS_RESPONSE:
-                       lwsl_debug("LHCS_RESPONSE: issuing response %d\n",
-                                  wsi->http.cgi->response_code);
+                       lwsl_wsi_debug(wsi, "LHCS_RESPONSE: iss response %d",
+                                           wsi->http.cgi->response_code);
                        if (lws_add_http_header_status(wsi,
-                                                  wsi->http.cgi->response_code,
+                                                  (unsigned int)wsi->http.cgi->response_code,
                                                       &p, end))
                                return 1;
                        if (!wsi->http.cgi->explicitly_chunked &&
@@ -592,13 +487,13 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
                                        WSI_TOKEN_HTTP_TRANSFER_ENCODING,
                                        (unsigned char *)"chunked", 7, &p, end))
                                return 1;
-                       if (!(wsi->http2_substream))
+                       if (!(wsi->mux_substream))
                                if (lws_add_http_header_by_token(wsi,
                                                WSI_TOKEN_CONNECTION,
                                                (unsigned char *)"close", 5,
                                                &p, end))
                                        return 1;
-                       n = lws_write(wsi, start, p - start,
+                       n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
                                      LWS_WRITE_HTTP_HEADERS | LWS_WRITE_NO_FIN);
 
                        /*
@@ -610,7 +505,7 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
                         * Let's redo them at headers_pos forward using the
                         * correct coding for http/1 or http/2
                         */
-                       if (!wsi->http2_substream)
+                       if (!wsi->mux_substream)
                                goto post_hpack_recode;
 
                        p = wsi->http.cgi->headers_start;
@@ -633,8 +528,8 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
                                                return -1;
                                        if (*p != ':') {
                                                if (*p >= 'A' && *p <= 'Z')
-                                                       *name++ = (*p++) +
-                                                                 ('a' - 'A');
+                                                       *name++ = (unsigned char)((*p++) +
+                                                                 ('a' - 'A'));
                                                else
                                                        *name++ = *p++;
                                        } else {
@@ -672,7 +567,7 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
                                                                   buf, value);
                                                        if (
                                        lws_add_http_header_by_name(wsi, buf,
-                                       (unsigned char *)value, name - value,
+                                       (unsigned char *)value, lws_ptr_diff(name, value),
                                        (unsigned char **)&wsi->http.cgi->headers_pos,
                                        (unsigned char *)wsi->http.cgi->headers_end))
                                                                return 1;
@@ -703,25 +598,25 @@ post_hpack_recode:
 
                case LHCS_DUMP_HEADERS:
 
-                       n = wsi->http.cgi->headers_pos -
-                           wsi->http.cgi->headers_dumped;
+                       n = (int)(wsi->http.cgi->headers_pos -
+                           wsi->http.cgi->headers_dumped);
                        if (n > 512)
                                n = 512;
 
-                       lwsl_debug("LHCS_DUMP_HEADERS: %d\n", n);
+                       lwsl_wsi_debug(wsi, "LHCS_DUMP_HEADERS: %d", n);
 
                        cmd = LWS_WRITE_HTTP_HEADERS_CONTINUATION;
                        if (wsi->http.cgi->headers_dumped + n !=
-                           wsi->http.cgi->headers_pos) {
+                                               wsi->http.cgi->headers_pos) {
                                lwsl_notice("adding no fin flag\n");
                                cmd |= LWS_WRITE_NO_FIN;
                        }
 
                        m = lws_write(wsi,
                                 (unsigned char *)wsi->http.cgi->headers_dumped,
-                                     n, cmd);
+                                     (unsigned int)n, (enum lws_write_protocol)cmd);
                        if (m < 0) {
-                               lwsl_debug("%s: write says %d\n", __func__, m);
+                               lwsl_wsi_debug(wsi, "write says %d", m);
                                return -1;
                        }
                        wsi->http.cgi->headers_dumped += n;
@@ -729,14 +624,23 @@ post_hpack_recode:
                            wsi->http.cgi->headers_pos) {
                                wsi->hdr_state = LHCS_PAYLOAD;
                                lws_free_set_NULL(wsi->http.cgi->headers_buf);
-                               lwsl_debug("freed cgi headers\n");
+                               lwsl_wsi_debug(wsi, "freed cgi headers");
+
+                               if (wsi->http.cgi->post_in_expected) {
+                                       lwsl_wsi_info(wsi, "post data still "
+                                                          "expected, asking "
+                                                          "for writeable");
+                                       lws_callback_on_writable(wsi);
+                               }
+
                        } else {
                                wsi->reason_bf |=
                                        LWS_CB_REASON_AUX_BF__CGI_HEADERS;
                                lws_callback_on_writable(wsi);
                        }
 
-                       /* writeability becomes uncertain now we wrote
+                       /*
+                        * writeability becomes uncertain now we wrote
                         * something, we must return to the event loop
                         */
                        return 0;
@@ -745,16 +649,16 @@ post_hpack_recode:
                if (!wsi->http.cgi->headers_buf) {
                        /* if we don't already have a headers buf, cook one */
                        n = 2048;
-                       if (wsi->http2_substream)
+                       if (wsi->mux_substream)
                                n = 4096;
-                       wsi->http.cgi->headers_buf = lws_malloc(n + LWS_PRE,
+                       wsi->http.cgi->headers_buf = lws_malloc((unsigned int)n + LWS_PRE,
                                                           "cgi hdr buf");
                        if (!wsi->http.cgi->headers_buf) {
-                               lwsl_err("OOM\n");
+                               lwsl_wsi_err(wsi, "OOM");
                                return -1;
                        }
 
-                       lwsl_debug("allocated cgi hdrs\n");
+                       lwsl_wsi_debug(wsi, "allocated cgi hdrs");
                        wsi->http.cgi->headers_start =
                                        wsi->http.cgi->headers_buf + LWS_PRE;
                        wsi->http.cgi->headers_pos = wsi->http.cgi->headers_start;
@@ -768,13 +672,13 @@ post_hpack_recode:
                        }
                }
 
-               n = lws_get_socket_fd(wsi->http.cgi->stdwsi[LWS_STDOUT]);
+               n = lws_get_socket_fd(wsi->http.cgi->lsp->stdwsi[LWS_STDOUT]);
                if (n < 0)
                        return -1;
-               n = read(n, &c, 1);
+               n = (int)read(n, &c, 1);
                if (n < 0) {
                        if (errno != EAGAIN) {
-                               lwsl_debug("%s: read says %d\n", __func__, n);
+                               lwsl_wsi_debug(wsi, "read says %d", n);
                                return -1;
                        }
                        else
@@ -782,7 +686,7 @@ post_hpack_recode:
 
                        if (wsi->http.cgi->headers_pos >=
                                        wsi->http.cgi->headers_end - 4) {
-                               lwsl_notice("CGI hdrs > buf size\n");
+                               lwsl_wsi_notice(wsi, "CGI hdrs > buf size");
 
                                return -1;
                        }
@@ -790,8 +694,8 @@ post_hpack_recode:
                if (!n)
                        goto agin;
 
-               lwsl_debug("-- 0x%02X %c %d %d\n", (unsigned char)c, c,
-                          wsi->http.cgi->match[1], wsi->hdr_state);
+               lwsl_wsi_debug(wsi, "-- 0x%02X %c %d %d", (unsigned char)c, c,
+                                   wsi->http.cgi->match[1], wsi->hdr_state);
                if (!c)
                        return -1;
                switch (wsi->hdr_state) {
@@ -810,13 +714,13 @@ post_hpack_recode:
                                        switch (n) {
                                        case SIGNIFICANT_HDR_CONTENT_LENGTH:
                                                wsi->http.cgi->content_length =
-                                                       atoll(wsi->http.cgi->l);
+                                                       (lws_filepos_t)atoll(wsi->http.cgi->l);
                                                break;
                                        case SIGNIFICANT_HDR_STATUS:
                                                wsi->http.cgi->response_code =
-                                                       atol(wsi->http.cgi->l);
-                                               lwsl_debug("Status set to %d\n",
-                                                  wsi->http.cgi->response_code);
+                                                       atoi(wsi->http.cgi->l);
+                                               lwsl_wsi_debug(wsi, "Status set to %d",
+                                                               wsi->http.cgi->response_code);
                                                break;
                                        default:
                                                break;
@@ -837,7 +741,7 @@ post_hpack_recode:
                                wsi->hdr_state = LCHS_SINGLE_0A;
                                *wsi->http.cgi->headers_pos++ = '\x0d';
                        }
-                       *wsi->http.cgi->headers_pos++ = c;
+                       *wsi->http.cgi->headers_pos++ = (unsigned char)c;
                        if (c == '\x0d')
                                wsi->hdr_state = LCHS_LF1;
 
@@ -845,7 +749,7 @@ post_hpack_recode:
                            !significant_hdr[SIGNIFICANT_HDR_TRANSFER_ENCODING]
                                    [wsi->http.cgi->match[
                                         SIGNIFICANT_HDR_TRANSFER_ENCODING]]) {
-                               lwsl_info("cgi produced chunked\n");
+                               lwsl_wsi_info(wsi, "cgi produced chunked");
                                wsi->http.cgi->explicitly_chunked = 1;
                        }
 
@@ -853,19 +757,19 @@ post_hpack_recode:
                        if (wsi->hdr_state != LCHS_HEADER &&
                            !significant_hdr[SIGNIFICANT_HDR_LOCATION][
                              wsi->http.cgi->match[SIGNIFICANT_HDR_LOCATION]]) {
-                               lwsl_debug("CGI: Location hdr seen\n");
+                               lwsl_wsi_debug(wsi, "CGI: Location hdr seen");
                                wsi->http.cgi->response_code = 302;
                        }
                        break;
                case LCHS_LF1:
-                       *wsi->http.cgi->headers_pos++ = c;
+                       *wsi->http.cgi->headers_pos++ = (unsigned char)c;
                        if (c == '\x0a') {
                                wsi->hdr_state = LCHS_CR2;
                                break;
                        }
                        /* we got \r[^\n]... it's unreasonable */
-                       lwsl_debug("%s: funny CRLF 0x%02X\n", __func__,
-                                  (unsigned char)c);
+                       lwsl_wsi_debug(wsi, "funny CRLF 0x%02X",
+                                           (unsigned char)c);
                        return -1;
 
                case LCHS_CR2:
@@ -884,7 +788,7 @@ post_hpack_recode:
                case LCHS_SINGLE_0A:
                        m = wsi->hdr_state;
                        if (c == '\x0a') {
-                               lwsl_debug("Content-Length: %lld\n",
+                               lwsl_wsi_debug(wsi, "Content-Length: %lld",
                                        (unsigned long long)
                                        wsi->http.cgi->content_length);
                                wsi->hdr_state = LHCS_RESPONSE;
@@ -898,7 +802,7 @@ post_hpack_recode:
                                /* we got \r\n\r[^\n]... unreasonable */
                                return -1;
                        /* we got \x0anext header, it's reasonable */
-                       *wsi->http.cgi->headers_pos++ = c;
+                       *wsi->http.cgi->headers_pos++ = (unsigned char)c;
                        wsi->hdr_state = LCHS_HEADER;
                        for (n = 0; n < SIGNIFICANT_HDR_COUNT; n++)
                                wsi->http.cgi->match[n] = 0;
@@ -916,49 +820,34 @@ agin:
 
        /* payload processing */
 
-       m = !wsi->http.cgi->implied_chunked && !wsi->http2_substream &&
-           !wsi->http.cgi->explicitly_chunked &&
+       m = !wsi->http.cgi->implied_chunked && !wsi->mux_substream &&
+       //    !wsi->http.cgi->explicitly_chunked &&
            !wsi->http.cgi->content_length;
-       n = lws_get_socket_fd(wsi->http.cgi->stdwsi[LWS_STDOUT]);
+       n = lws_get_socket_fd(wsi->http.cgi->lsp->stdwsi[LWS_STDOUT]);
        if (n < 0)
                return -1;
-       if (m) {
-               uint8_t term[LWS_PRE + 6];
-
-               lwsl_info("%s: zero chunk\n", __func__);
-
-               memcpy(term + LWS_PRE, (uint8_t *)"0\x0d\x0a\x0d\x0a", 5);
-
-               if (lws_write(wsi, term + LWS_PRE, 5,
-                             LWS_WRITE_HTTP_FINAL) != 5)
-                       return -1;
-
-               wsi->http.cgi->cgi_transaction_over = 1;
-
-               return 0;
-       }
-
-       n = read(n, start, sizeof(buf) - LWS_PRE);
+       n = (int)read(n, start, sizeof(buf) - LWS_PRE);
 
        if (n < 0 && errno != EAGAIN) {
-               lwsl_debug("%s: stdout read says %d\n", __func__, n);
+               lwsl_wsi_debug(wsi, "stdout read says %d", n);
                return -1;
        }
        if (n > 0) {
-/*
-               if (!wsi->http2_substream && m) {
+               // lwsl_hexdump_notice(buf, n);
+
+               if (!wsi->mux_substream && m) {
                        char chdr[LWS_HTTP_CHUNK_HDR_SIZE];
                        m = lws_snprintf(chdr, LWS_HTTP_CHUNK_HDR_SIZE - 3,
                                         "%X\x0d\x0a", n);
-                       memmove(start + m, start, n);
-                       memcpy(start, chdr, m);
+                       memmove(start + m, start, (unsigned int)n);
+                       memcpy(start, chdr, (unsigned int)m);
                        memcpy(start + m + n, "\x0d\x0a", 2);
                        n += m + 2;
                }
-               */
+
 
 #if defined(LWS_WITH_HTTP2)
-               if (wsi->http2_substream) {
+               if (wsi->mux_substream) {
                        struct lws *nwsi = lws_get_network_wsi(wsi);
 
                        __lws_set_timeout(wsi,
@@ -971,21 +860,37 @@ agin:
 #endif
 
                cmd = LWS_WRITE_HTTP;
-               if (wsi->http.cgi->content_length_seen + n ==
+               if (wsi->http.cgi->content_length_seen + (unsigned int)n ==
                                                wsi->http.cgi->content_length)
                        cmd = LWS_WRITE_HTTP_FINAL;
 
-               m = lws_write(wsi, (unsigned char *)start, n, cmd);
+               m = lws_write(wsi, (unsigned char *)start, (unsigned int)n, (enum lws_write_protocol)cmd);
                //lwsl_notice("write %d\n", m);
                if (m < 0) {
-                       lwsl_debug("%s: stdout write says %d\n", __func__, m);
+                       lwsl_wsi_debug(wsi, "stdout write says %d\n", m);
                        return -1;
                }
-               wsi->http.cgi->content_length_seen += n;
+               wsi->http.cgi->content_length_seen += (unsigned int)n;
        } else {
+
+               if (!wsi->mux_substream && m) {
+                       uint8_t term[LWS_PRE + 6];
+
+                       lwsl_wsi_info(wsi, "sent trailer");
+                       memcpy(term + LWS_PRE, (uint8_t *)"0\x0d\x0a\x0d\x0a", 5);
+
+                       if (lws_write(wsi, term + LWS_PRE, 5,
+                                     LWS_WRITE_HTTP_FINAL) != 5)
+                               return -1;
+
+                       wsi->http.cgi->cgi_transaction_over = 1;
+
+                       return 0;
+               }
+
                if (wsi->cgi_stdout_zero_length) {
-                       lwsl_debug("%s: stdout is POLLHUP'd\n", __func__);
-                       if (wsi->http2_substream)
+                       lwsl_wsi_debug(wsi, "stdout is POLLHUP'd");
+                       if (wsi->mux_substream)
                                m = lws_write(wsi, (unsigned char *)start, 0,
                                              LWS_WRITE_HTTP_FINAL);
                        else
@@ -997,81 +902,36 @@ agin:
        return 0;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_cgi_kill(struct lws *wsi)
 {
        struct lws_cgi_args args;
-       int status, n;
-
-       lwsl_debug("%s: %p\n", __func__, wsi);
+       pid_t pid;
+       int n, m;
 
-       if (!wsi->http.cgi)
+       if (!wsi->http.cgi || !wsi->http.cgi->lsp)
                return 0;
 
-       if (wsi->http.cgi->pid > 0) {
-               n = waitpid(wsi->http.cgi->pid, &status, WNOHANG);
-               if (n > 0) {
-                       lwsl_debug("%s: PID %d reaped\n", __func__,
-                                   wsi->http.cgi->pid);
-                       goto handled;
-               }
-               /* kill the process group */
-               n = kill(-wsi->http.cgi->pid, SIGTERM);
-               lwsl_debug("%s: SIGTERM child PID %d says %d (errno %d)\n",
-                          __func__, wsi->http.cgi->pid, n, errno);
-               if (n < 0) {
-                       /*
-                        * hum seen errno=3 when process is listed in ps,
-                        * it seems we don't always retain process grouping
-                        *
-                        * Direct these fallback attempt to the exact child
-                        */
-                       n = kill(wsi->http.cgi->pid, SIGTERM);
-                       if (n < 0) {
-                               n = kill(wsi->http.cgi->pid, SIGPIPE);
-                               if (n < 0) {
-                                       n = kill(wsi->http.cgi->pid, SIGKILL);
-                                       if (n < 0)
-                                               lwsl_info("%s: SIGKILL PID %d "
-                                                        "failed errno %d "
-                                                        "(maybe zombie)\n",
-                                                        __func__,
-                                                wsi->http.cgi->pid, errno);
-                               }
-                       }
-               }
-               /* He could be unkillable because he's a zombie */
-               n = 1;
-               while (n > 0) {
-                       n = waitpid(-wsi->http.cgi->pid, &status, WNOHANG);
-                       if (n > 0)
-                               lwsl_debug("%s: reaped PID %d\n", __func__, n);
-                       if (n <= 0) {
-                               n = waitpid(wsi->http.cgi->pid, &status, WNOHANG);
-                               if (n > 0)
-                                       lwsl_debug("%s: reaped PID %d\n",
-                                                  __func__, n);
-                       }
-               }
-       }
+       pid = wsi->http.cgi->lsp->child_pid;
 
-handled:
-       args.stdwsi = &wsi->http.cgi->stdwsi[0];
+       args.stdwsi = &wsi->http.cgi->lsp->stdwsi[0];
+       lws_spawn_piped_kill_child_process(wsi->http.cgi->lsp);
+       /* that has invalidated and NULL'd wsi->http.cgi->lsp */
 
-       if (wsi->http.cgi->pid != -1) {
-               n = user_callback_handle_rxflow(wsi->protocol->callback, wsi,
+       if (pid != -1) {
+               m = wsi->http.cgi->being_closed;
+               n = user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
                                                LWS_CALLBACK_CGI_TERMINATED,
                                                wsi->user_space, (void *)&args,
-                                               wsi->http.cgi->pid);
-               wsi->http.cgi->pid = -1;
-               if (n && !wsi->http.cgi->being_closed)
+                                               (unsigned int)pid);
+               if (n && !m)
                        lws_close_free_wsi(wsi, 0, "lws_cgi_kill");
        }
 
        return 0;
 }
 
-LWS_EXTERN int
+int
 lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
 {
        struct lws_cgi **pcgi, *cgi = NULL;
@@ -1082,7 +942,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
                n = waitpid(-1, &status, WNOHANG);
                if (n <= 0)
                        continue;
-               lwsl_debug("%s: observed PID %d terminated\n", __func__, n);
+               lwsl_cx_debug(pt->context, "observed PID %d terminated", n);
 
                pcgi = &pt->http.cgi_list;
 
@@ -1092,7 +952,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
                        cgi = *pcgi;
                        pcgi = &(*pcgi)->cgi_list;
 
-                       if (cgi->pid <= 0)
+                       if (cgi->lsp->child_pid <= 0)
                                continue;
 
                        /* finish sending cached headers */
@@ -1104,9 +964,8 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
                                continue;
 
                        if (cgi->content_length) {
-                               lwsl_debug("%s: wsi %p: expected content "
-                                          "length seen: %lld\n", __func__,
-                                          cgi->wsi,
+                               lwsl_cx_debug(pt->context, "expected content "
+                                                          "length seen: %lld",
                                (unsigned long long)cgi->content_length_seen);
                        }
 
@@ -1117,9 +976,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
                         * but we should do the terminated cgi callback
                         * and close him if he's not already closing
                         */
-                       if (n == cgi->pid) {
-                               lwsl_debug("%s: found PID %d on cgi list\n",
-                                           __func__, n);
+                       if (n == cgi->lsp->child_pid) {
 
                                if (!cgi->content_length) {
                                        /*
@@ -1132,7 +989,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
                                }
 
                                /* defeat kill() */
-                               cgi->pid = 0;
+                               cgi->lsp->child_pid = 0;
                                lws_cgi_kill(cgi->wsi);
 
                                break;
@@ -1140,11 +997,9 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
                        cgi = NULL;
                }
                /* if not found on the cgi list, as he's one of ours, reap */
-               if (!cgi) {
-                       lwsl_debug("%s: reading PID %d although no cgi match\n",
-                                       __func__, n);
+               if (!cgi)
                        waitpid(n, &status, WNOHANG);
-               }
+
        }
 
        pcgi = &pt->http.cgi_list;
@@ -1155,7 +1010,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
                cgi = *pcgi;
                pcgi = &(*pcgi)->cgi_list;
 
-               if (cgi->pid <= 0)
+               if (!cgi || !cgi->lsp || cgi->lsp->child_pid <= 0)
                        continue;
 
                /* we deferred killing him after reaping his PID */
@@ -1175,13 +1030,11 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
                        continue;
 
                if (cgi->content_length)
-                       lwsl_debug("%s: wsi %p: expected "
-                                  "content len seen: %lld\n", __func__,
-                                  cgi->wsi,
-                               (unsigned long long)cgi->content_length_seen);
+                       lwsl_wsi_debug(cgi->wsi, "expected cont len seen: %lld",
+                                 (unsigned long long)cgi->content_length_seen);
 
                /* reap it */
-               if (waitpid(cgi->pid, &status, WNOHANG) > 0) {
+               if (waitpid(cgi->lsp->child_pid, &status, WNOHANG) > 0) {
 
                        if (!cgi->content_length) {
                                /*
@@ -1193,11 +1046,11 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
                                continue;
                        }
 finish_him:
-                       lwsl_debug("%s: found PID %d on cgi list\n",
-                                   __func__, cgi->pid);
+                       lwsl_cx_debug(pt->context, "found PID %d on cgi list",
+                                                  cgi->lsp->child_pid);
 
                        /* defeat kill() */
-                       cgi->pid = 0;
+                       cgi->lsp->child_pid = 0;
                        lws_cgi_kill(cgi->wsi);
 
                        break;
@@ -1207,23 +1060,23 @@ finish_him:
        return 0;
 }
 
-LWS_VISIBLE LWS_EXTERN struct lws *
+struct lws *
 lws_cgi_get_stdwsi(struct lws *wsi, enum lws_enum_stdinouterr ch)
 {
        if (!wsi->http.cgi)
                return NULL;
 
-       return wsi->http.cgi->stdwsi[ch];
+       return wsi->http.cgi->lsp->stdwsi[ch];
 }
 
 void
 lws_cgi_remove_and_kill(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        struct lws_cgi **pcgi = &pt->http.cgi_list;
 
        /* remove us from the cgi list */
-       lwsl_debug("%s: remove cgi %p from list\n", __func__, wsi->http.cgi);
+
        while (*pcgi) {
                if (*pcgi == wsi->http.cgi) {
                        /* drop us from the pt cgi list */
@@ -1232,11 +1085,13 @@ lws_cgi_remove_and_kill(struct lws *wsi)
                }
                pcgi = &(*pcgi)->cgi_list;
        }
-       if (wsi->http.cgi->headers_buf) {
-               lwsl_debug("close: freed cgi headers\n");
+       if (wsi->http.cgi->headers_buf)
                lws_free_set_NULL(wsi->http.cgi->headers_buf);
-       }
+
        /* we have a cgi going, we must kill it */
        wsi->http.cgi->being_closed = 1;
        lws_cgi_kill(wsi);
+
+       if (!pt->http.cgi_list)
+               lws_sul_cancel(&pt->sul_cgi);
 }
index 4880e21..d0dfc3c 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 static int
 rops_handle_POLLIN_cgi(struct lws_context_per_thread *pt, struct lws *wsi,
@@ -29,28 +32,46 @@ rops_handle_POLLIN_cgi(struct lws_context_per_thread *pt, struct lws *wsi,
 
        assert(wsi->role_ops == &role_ops_cgi);
 
-       if (wsi->cgi_channel >= LWS_STDOUT &&
+       if (wsi->lsp_channel >= LWS_STDOUT &&
            !(pollfd->revents & pollfd->events & LWS_POLLIN))
                return LWS_HPI_RET_HANDLED;
 
-       if (wsi->cgi_channel == LWS_STDIN &&
+       if (wsi->lsp_channel == LWS_STDIN &&
            !(pollfd->revents & pollfd->events & LWS_POLLOUT))
                return LWS_HPI_RET_HANDLED;
 
-       if (wsi->cgi_channel == LWS_STDIN &&
+       if (wsi->lsp_channel == LWS_STDIN &&
            lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
-               lwsl_info("failed at set pollfd\n");
+               lwsl_wsi_info(wsi, "failed at set pollfd");
                return LWS_HPI_RET_WSI_ALREADY_DIED;
        }
 
-       args.ch = wsi->cgi_channel;
-       args.stdwsi = &wsi->parent->http.cgi->stdwsi[0];
-       args.hdr_state = wsi->hdr_state;
+       if (!wsi->parent) {
+               lwsl_wsi_debug(wsi, "stdwsi content with parent");
 
-       lwsl_debug("CGI LWS_STDOUT %p wsistate 0x%x\n",
-                  wsi->parent, wsi->wsistate);
+               return LWS_HPI_RET_HANDLED;
+       }
+
+       if (!wsi->parent->http.cgi) {
+               lwsl_wsi_notice(wsi, "stdwsi content with deleted cgi object");
+
+               return LWS_HPI_RET_HANDLED;
+       }
+
+       if (!wsi->parent->http.cgi->lsp) {
+               lwsl_wsi_notice(wsi, "stdwsi content with reaped lsp");
+
+               return LWS_HPI_RET_HANDLED;
+       }
+
+       args.ch = wsi->lsp_channel;
+       args.stdwsi = &wsi->parent->http.cgi->lsp->stdwsi[0];
+       args.hdr_state = (enum lws_cgi_hdr_state)wsi->hdr_state;
 
-       if (user_callback_handle_rxflow(wsi->parent->protocol->callback,
+       lwsl_wsi_debug(wsi, "CGI LWS_STDOUT %p wsistate 0x%x",
+                           wsi->parent, wsi->wsistate);
+
+       if (user_callback_handle_rxflow(wsi->parent->a.protocol->callback,
                                        wsi->parent, LWS_CALLBACK_CGI,
                                        wsi->parent->user_space,
                                        (void *)&args, 0))
@@ -66,16 +87,6 @@ rops_handle_POLLOUT_cgi(struct lws *wsi)
 }
 
 static int
-rops_periodic_checks_cgi(struct lws_context *context, int tsi, time_t now)
-{
-       struct lws_context_per_thread *pt = &context->pt[tsi];
-
-       lws_cgi_kill_terminated(pt);
-
-       return 0;
-}
-
-static int
 rops_destroy_role_cgi(struct lws *wsi)
 {
 #if defined(LWS_WITH_ZLIB)
@@ -91,34 +102,81 @@ rops_destroy_role_cgi(struct lws *wsi)
        return 0;
 }
 
-struct lws_role_ops role_ops_cgi = {
+void
+lws_cgi_sul_cb(lws_sorted_usec_list_t *sul)
+{
+       struct lws_context_per_thread *pt = lws_container_of(sul,
+                       struct lws_context_per_thread, sul_cgi);
+
+       lws_cgi_kill_terminated(pt);
+
+       if (pt->http.cgi_list)
+               lws_sul_schedule(pt->context, (int)(pt - pt->context->pt),
+                                &pt->sul_cgi, lws_cgi_sul_cb, 3 * LWS_US_PER_SEC);
+}
+
+static int
+rops_pt_init_destroy_cgi(struct lws_context *context,
+                   const struct lws_context_creation_info *info,
+                   struct lws_context_per_thread *pt, int destroy)
+{
+
+       lws_sul_cancel(&pt->sul_cgi);
+
+       return 0;
+}
+
+static int
+rops_close_role_cgi(struct lws_context_per_thread *pt, struct lws *wsi)
+{
+       if (wsi->parent && wsi->parent->http.cgi && wsi->parent->http.cgi->lsp)
+               lws_spawn_stdwsi_closed(wsi->parent->http.cgi->lsp, wsi);
+
+       return 0;
+}
+
+static const lws_rops_t rops_table_cgi[] = {
+       /*  1 */ { .pt_init_destroy     = rops_pt_init_destroy_cgi },
+       /*  2 */ { .handle_POLLIN       = rops_handle_POLLIN_cgi },
+       /*  3 */ { .handle_POLLOUT      = rops_handle_POLLOUT_cgi },
+       /*  4 */ { .close_role          = rops_close_role_cgi },
+       /*  5 */ { .destroy_role        = rops_destroy_role_cgi },
+};
+
+const struct lws_role_ops role_ops_cgi = {
        /* role name */                 "cgi",
        /* alpn id */                   NULL,
-       /* check_upgrades */            NULL,
-       /* init_context */              NULL,
-       /* init_vhost */                NULL,
-       /* destroy_vhost */             NULL,
-       /* periodic_checks */           rops_periodic_checks_cgi,
-       /* service_flag_pending */      NULL,
-       /* handle_POLLIN */             rops_handle_POLLIN_cgi,
-       /* handle_POLLOUT */            rops_handle_POLLOUT_cgi,
-       /* perform_user_POLLOUT */      NULL,
-       /* callback_on_writable */      NULL,
-       /* tx_credit */                 NULL,
-       /* write_role_protocol */       NULL,
-       /* encapsulation_parent */      NULL,
-       /* alpn_negotiated */           NULL,
-       /* close_via_role_protocol */   NULL,
-       /* close_role */                NULL,
-       /* close_kill_connection */     NULL,
-       /* destroy_role */              rops_destroy_role_cgi,
-       /* adoption_bind */             NULL,
-       /* client_bind */               NULL,
+
+       /* rops_table */                rops_table_cgi,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x01,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x02,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x30,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x00,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x00,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x00,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x40,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0x50,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x00,
+                                       },
+
        /* adoption_cb clnt, srv */     { 0, 0 },
        /* rx_cb clnt, srv */           { 0, 0 },
        /* writeable cb clnt, srv */    { 0, 0 },
        /* close cb clnt, srv */        { 0, 0 },
        /* protocol_bind_cb c,s */      { 0, 0 },
        /* protocol_unbind_cb c,s */    { 0, 0 },
+
        /* file_handle */               0,
 };
diff --git a/lib/roles/cgi/private-lib-roles-cgi.h b/lib/roles/cgi/private-lib-roles-cgi.h
new file mode 100644 (file)
index 0000000..8eff589
--- /dev/null
@@ -0,0 +1,91 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is included from private-lib-core.h if LWS_ROLE_WS
+ */
+
+#if defined(LWS_WITH_ZLIB)
+#if defined(LWS_WITH_MINIZ)
+#include <miniz.h>
+#else
+#include <zlib.h>
+#endif
+#endif
+
+extern const struct lws_role_ops role_ops_cgi;
+
+#define lwsi_role_cgi(wsi) (wsi->role_ops == &role_ops_cgi)
+
+#define LWS_HTTP_CHUNK_HDR_SIZE 16
+
+enum {
+       SIGNIFICANT_HDR_CONTENT_LENGTH,         /* numeric */
+       SIGNIFICANT_HDR_LOCATION,
+       SIGNIFICANT_HDR_STATUS,                 /* numeric */
+       SIGNIFICANT_HDR_TRANSFER_ENCODING,
+       SIGNIFICANT_HDR_CONTENT_ENCODING_GZIP,
+
+       SIGNIFICANT_HDR_COUNT
+};
+
+struct lws;
+
+/* wsi who is owns the cgi points to an lws_cgi */
+
+struct lws_cgi {
+       struct lws_cgi *cgi_list;
+
+       struct lws_spawn_piped          *lsp;
+       lws_sorted_usec_list_t          sul_grace;
+
+       struct lws *wsi; /* owner */
+       unsigned char *headers_buf;
+       unsigned char *headers_start;
+       unsigned char *headers_pos;
+       unsigned char *headers_dumped;
+       unsigned char *headers_end;
+
+       char summary[128];
+#if defined(LWS_WITH_ZLIB)
+       z_stream inflate;
+       uint8_t inflate_buf[1024];
+#endif
+
+       lws_filepos_t post_in_expected;
+       lws_filepos_t content_length;
+       lws_filepos_t content_length_seen;
+
+       int match[SIGNIFICANT_HDR_COUNT];
+       char l[12];
+       int response_code;
+       int lp;
+
+       unsigned char being_closed:1;
+       unsigned char explicitly_chunked:1;
+       unsigned char cgi_transaction_over:1;
+       unsigned char implied_chunked:1;
+       unsigned char gzip_inflate:1;
+       unsigned char gzip_init:1;
+
+       unsigned char chunked_grace;
+};
diff --git a/lib/roles/cgi/private.h b/lib/roles/cgi/private.h
deleted file mode 100644 (file)
index 53e5f72..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h if LWS_ROLE_WS
- */
-
-#if defined(LWS_WITH_ZLIB)
-#if defined(LWS_WITH_MINIZ)
-#include <miniz.h>
-#else
-#include <zlib.h>
-#endif
-#endif
-
-extern struct lws_role_ops role_ops_cgi;
-
-#define lwsi_role_cgi(wsi) (wsi->role_ops == &role_ops_cgi)
-
-#define LWS_HTTP_CHUNK_HDR_SIZE 16
-
-enum {
-       SIGNIFICANT_HDR_CONTENT_LENGTH,         /* numeric */
-       SIGNIFICANT_HDR_LOCATION,
-       SIGNIFICANT_HDR_STATUS,                 /* numeric */
-       SIGNIFICANT_HDR_TRANSFER_ENCODING,
-       SIGNIFICANT_HDR_CONTENT_ENCODING_GZIP,
-
-       SIGNIFICANT_HDR_COUNT
-};
-
-struct lws;
-
-/* wsi who is master of the cgi points to an lws_cgi */
-
-struct lws_cgi {
-       struct lws_cgi *cgi_list;
-       struct lws *stdwsi[3]; /* points to the associated stdin/out/err wsis */
-       struct lws *wsi; /* owner */
-       unsigned char *headers_buf;
-       unsigned char *headers_start;
-       unsigned char *headers_pos;
-       unsigned char *headers_dumped;
-       unsigned char *headers_end;
-
-       char summary[128];
-#if defined(LWS_WITH_ZLIB)
-       z_stream inflate;
-       uint8_t inflate_buf[1024];
-#endif
-
-       lws_filepos_t post_in_expected;
-       lws_filepos_t content_length;
-       lws_filepos_t content_length_seen;
-
-       int pipe_fds[3][2];
-       int match[SIGNIFICANT_HDR_COUNT];
-       char l[12];
-       int pid;
-       int response_code;
-       int lp;
-
-       unsigned char being_closed:1;
-       unsigned char explicitly_chunked:1;
-       unsigned char cgi_transaction_over:1;
-       unsigned char implied_chunked:1;
-       unsigned char gzip_inflate:1;
-       unsigned char gzip_init:1;
-
-       unsigned char chunked_grace;
-};
diff --git a/lib/roles/dbus/CMakeLists.txt b/lib/roles/dbus/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c27cffc
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       roles/dbus/dbus.c)
+       
+if (NOT LWS_DBUS_LIB)
+       set(LWS_DBUS_LIB "dbus-1")
+endif()
+
+find_package(PkgConfig QUIET)
+pkg_check_modules(PC_DBUS1 dbus-1 QUIET)
+list(APPEND LWS_DBUS_INCLUDE1 ${PC_DBUS1_INCLUDE_DIRS})
+list(APPEND LWS_DBUS_LIB ${PC_DBUS1_LIBRARIES})
+list(APPEND LWS_DEPS_LIB_PATHS ${PC_DBUS1_LIBRARY_DIRS})
+
+set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_DBUS_INCLUDE1})
+
+CHECK_C_SOURCE_COMPILES("#include <dbus/dbus.h>
+int main(void) {
+       return 0;
+}" LWS_DBUS_CHECK_OK)
+
+message("dbus include dir 1: ${LWS_DBUS_INCLUDE1}")
+if (LWS_DBUS_INCLUDE1)
+include_directories("${LWS_DBUS_INCLUDE1}")
+endif()
+list(APPEND LIB_LIST ${LWS_DBUS_LIB})
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+set(LWS_DBUS_CHECK_OK ${LWS_DBUS_CHECK_OK} PARENT_SCOPE)
+set(LWS_DEPS_LIB_PATHS ${LWS_DEPS_LIB_PATHS} PARENT_SCOPE)
+
index 0b82125..3445792 100644 (file)
@@ -1,23 +1,25 @@
-/*
- * libwebsockets - dbus role
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  * This role for wrapping dbus fds in a wsi + role is unusual in that the
  * wsi it creates and binds to the role do not have control over the related fd
  * worries we create a new shadow wsi until it looks like it is closing again.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 #include <libwebsockets/lws-dbus.h>
 
 /*
  * retreives existing or creates new shadow wsi for fd owned by dbus stuff.
  *
- * Requires vhost lock
+ * Requires context + vhost lock
  */
 
 static struct lws *
@@ -66,7 +68,12 @@ __lws_shadow_wsi(struct lws_dbus_ctx *ctx, DBusWatch *w, int fd, int create_ok)
        if (!create_ok)
                return NULL;
 
-       wsi = lws_zalloc(sizeof(*wsi), "shadow wsi");
+       lws_context_assert_lock_held(wsi->a.context);
+       lws_vhost_assert_lock_held(wsi->a.vhost);
+
+       /* requires context lock */
+       wsi = __lws_wsi_create_with_role(ctx->vh->context, ctx->tsi, NULL,
+                                               ctx->vh->lc.log_cx);
        if (wsi == NULL) {
                lwsl_err("Out of mem\n");
                return NULL;
@@ -74,30 +81,29 @@ __lws_shadow_wsi(struct lws_dbus_ctx *ctx, DBusWatch *w, int fd, int create_ok)
 
        lwsl_info("%s: creating shadow wsi\n", __func__);
 
-       wsi->context = ctx->vh->context;
        wsi->desc.sockfd = fd;
        lws_role_transition(wsi, 0, LRS_ESTABLISHED, &role_ops_dbus);
-       wsi->protocol = ctx->vh->protocols;
-       wsi->tsi = ctx->tsi;
+       wsi->a.protocol = ctx->vh->protocols;
        wsi->shadow = 1;
        wsi->opaque_parent_data = ctx;
        ctx->w[0] = w;
 
+       __lws_lc_tag(ctx->vh->context, &ctx->vh->context->lcg[LWSLCG_WSI],
+                    &wsi->lc, "dbus|%s", ctx->vh->name);
+
        lws_vhost_bind_wsi(ctx->vh, wsi);
        if (__insert_wsi_socket_into_fds(ctx->vh->context, wsi)) {
                lwsl_err("inserting wsi socket into fds failed\n");
-               lws_vhost_unbind_wsi(wsi);
+               __lws_vhost_unbind_wsi(wsi); /* cx + vh lock */
                lws_free(wsi);
                return NULL;
        }
 
-       ctx->vh->context->count_wsi_allocated++;
-
        return wsi;
 }
 
 /*
- * Requires vhost lock
+ * Requires cx + vhost lock
  */
 
 static int
@@ -105,6 +111,9 @@ __lws_shadow_wsi_destroy(struct lws_dbus_ctx *ctx, struct lws *wsi)
 {
        lwsl_info("%s: destroying shadow wsi\n", __func__);
 
+       lws_context_assert_lock_held(wsi->a.context);
+       lws_vhost_assert_lock_held(wsi->a.vhost);
+
        if (__remove_wsi_socket_from_fds(wsi)) {
                lwsl_err("%s: unable to remove %d from fds\n", __func__,
                                wsi->desc.sockfd);
@@ -112,8 +121,7 @@ __lws_shadow_wsi_destroy(struct lws_dbus_ctx *ctx, struct lws *wsi)
                return 1;
        }
 
-       ctx->vh->context->count_wsi_allocated--;
-       lws_vhost_unbind_wsi(wsi);
+       __lws_vhost_unbind_wsi(wsi);
 
        lws_free(wsi);
 
@@ -146,11 +154,13 @@ lws_dbus_add_watch(DBusWatch *w, void *data)
        struct lws *wsi;
        int n;
 
+       lws_context_lock(pt->context, __func__);
        lws_pt_lock(pt, __func__);
 
        wsi = __lws_shadow_wsi(ctx, w, dbus_watch_get_unix_fd(w), 1);
        if (!wsi) {
                lws_pt_unlock(pt);
+               lws_context_unlock(pt->context);
                lwsl_err("%s: unable to get wsi\n", __func__);
 
                return FALSE;
@@ -168,7 +178,7 @@ lws_dbus_add_watch(DBusWatch *w, void *data)
                        }
 
        for (n = 0; n < (int)LWS_ARRAY_SIZE(ctx->w); n++)
-               if (ctx->w[n])
+               if (ctx->w[n] && dbus_watch_get_enabled(ctx->w[n]))
                        flags |= dbus_watch_get_flags(ctx->w[n]);
 
        if (flags & DBUS_WATCH_READABLE)
@@ -176,18 +186,22 @@ lws_dbus_add_watch(DBusWatch *w, void *data)
        if (flags & DBUS_WATCH_WRITABLE)
                lws_flags |= LWS_POLLOUT;
 
-       lwsl_info("%s: w %p, fd %d, data %p, flags %d\n", __func__, w,
-                 dbus_watch_get_unix_fd(w), data, lws_flags);
+       lwsl_info("%s: %s: %p, fd %d, data %p, fl %d\n", __func__,
+                 lws_wsi_tag(wsi), w, dbus_watch_get_unix_fd(w),
+                 data, lws_flags);
 
-       __lws_change_pollfd(wsi, 0, lws_flags);
+       if (lws_flags)
+               __lws_change_pollfd(wsi, 0, (int)lws_flags);
 
        lws_pt_unlock(pt);
+       lws_context_unlock(pt->context);
 
        return TRUE;
 }
 
+/* cx + vh lock */
 static int
-check_destroy_shadow_wsi(struct lws_dbus_ctx *ctx, struct lws *wsi)
+__check_destroy_shadow_wsi(struct lws_dbus_ctx *ctx, struct lws *wsi)
 {
        int n;
 
@@ -222,6 +236,7 @@ lws_dbus_remove_watch(DBusWatch *w, void *data)
        struct lws *wsi;
        int n;
 
+       lws_context_lock(pt->context, __func__);
        lws_pt_lock(pt, __func__);
 
        wsi = __lws_shadow_wsi(ctx, w, dbus_watch_get_unix_fd(w), 0);
@@ -243,13 +258,15 @@ lws_dbus_remove_watch(DBusWatch *w, void *data)
        if ((~flags) & DBUS_WATCH_WRITABLE)
                lws_flags |= LWS_POLLOUT;
 
-       lwsl_info("%s: w %p, fd %d, data %p, clearing lws flags %d\n",
-                 __func__, w, dbus_watch_get_unix_fd(w), data, lws_flags);
+       lwsl_info("%s: %p, fd %d, data %p, clearing lws flags %d\n",
+                 __func__, w, dbus_watch_get_unix_fd(w),
+                 data, lws_flags);
 
-       __lws_change_pollfd(wsi, lws_flags, 0);
+       __lws_change_pollfd(wsi, (int)lws_flags, 0);
 
 bail:
        lws_pt_unlock(pt);
+       lws_context_unlock(pt->context);
 }
 
 static void
@@ -261,6 +278,29 @@ lws_dbus_toggle_watch(DBusWatch *w, void *data)
                lws_dbus_remove_watch(w, data);
 }
 
+static void
+lws_dbus_sul_cb(lws_sorted_usec_list_t *sul)
+{
+       struct lws_context_per_thread *pt = lws_container_of(sul,
+                               struct lws_context_per_thread, dbus.sul);
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, rdt, nx,
+                        lws_dll2_get_head(&pt->dbus.timer_list_owner)) {
+               struct lws_role_dbus_timer *r = lws_container_of(rdt,
+                                       struct lws_role_dbus_timer, timer_list);
+
+               if (time(NULL) > r->fire) {
+                       lwsl_notice("%s: firing timer\n", __func__);
+                       dbus_timeout_handle(r->data);
+                       lws_dll2_remove(rdt);
+                       lws_free(rdt);
+               }
+       } lws_end_foreach_dll_safe(rdt, nx);
+
+       if (pt->dbus.timer_list_owner.count)
+               lws_sul_schedule(pt->context, pt->tid, &pt->dbus.sul,
+                                lws_dbus_sul_cb, 3 * LWS_US_PER_SEC);
+}
 
 static dbus_bool_t
 lws_dbus_add_timeout(DBusTimeout *t, void *data)
@@ -291,6 +331,10 @@ lws_dbus_add_timeout(DBusTimeout *t, void *data)
        dbt->timer_list.owner = NULL;
        lws_dll2_add_head(&dbt->timer_list, &pt->dbus.timer_list_owner);
 
+       if (!pt->dbus.sul.list.owner)
+               lws_sul_schedule(pt->context, pt->tid, &pt->dbus.sul,
+                                lws_dbus_sul_cb, 3 * LWS_US_PER_SEC);
+
        ctx->timeouts++;
 
        return TRUE;
@@ -315,6 +359,9 @@ lws_dbus_remove_timeout(DBusTimeout *t, void *data)
                        break;
                }
        } lws_end_foreach_dll_safe(rdt, nx);
+
+       if (!pt->dbus.timer_list_owner.count)
+               lws_sul_cancel(&pt->dbus.sul);
 }
 
 static void
@@ -461,7 +508,7 @@ rops_handle_POLLIN_dbus(struct lws_context_per_thread *pt, struct lws *wsi,
 
                handle_dispatch_status(NULL, DBUS_DISPATCH_DATA_REMAINS, NULL);
 
-               check_destroy_shadow_wsi(ctx, wsi);
+               __check_destroy_shadow_wsi(ctx, wsi);
        } else
                if (ctx->dbs)
                        /* ??? */
@@ -471,55 +518,49 @@ rops_handle_POLLIN_dbus(struct lws_context_per_thread *pt, struct lws *wsi,
 }
 
 static int
-rops_periodic_checks_dbus(struct lws_context *context, int tsi, time_t now)
+rops_pt_init_destroy_dbus(struct lws_context *context,
+                   const struct lws_context_creation_info *info,
+                   struct lws_context_per_thread *pt, int destroy)
 {
-       struct lws_context_per_thread *pt = &context->pt[tsi];
-
-       /*
-        * locking shouldn't be needed here, because periodic_checks is called
-        * from the tsi-specific service thread context, and only the same
-        * service thread can modify stuff on the same pt.
-        */
-
-       lws_start_foreach_dll_safe(struct lws_dll2 *, rdt, nx,
-                        lws_dll2_get_head(&pt->dbus.timer_list_owner)) {
-               struct lws_role_dbus_timer *r = lws_container_of(rdt,
-                                       struct lws_role_dbus_timer, timer_list);
-
-               if (now > r->fire) {
-                       lwsl_notice("%s: firing timer\n", __func__);
-                       dbus_timeout_handle(r->data);
-                       lws_dll2_remove(rdt);
-                       lws_free(rdt);
-               }
-       } lws_end_foreach_dll_safe(rdt, nx);
+       if (destroy)
+               lws_sul_cancel(&pt->dbus.sul);
 
        return 0;
 }
 
-struct lws_role_ops role_ops_dbus = {
+static const lws_rops_t rops_table_dbus[] = {
+       /*  1 */ { .pt_init_destroy     = rops_pt_init_destroy_dbus },
+       /*  2 */ { .handle_POLLIN       = rops_handle_POLLIN_dbus },
+};
+
+const struct lws_role_ops role_ops_dbus = {
        /* role name */                 "dbus",
        /* alpn id */                   NULL,
-       /* check_upgrades */            NULL,
-       /* init_context */              NULL,
-       /* init_vhost */                NULL,
-       /* destroy_vhost */             NULL,
-       /* periodic_checks */           rops_periodic_checks_dbus,
-       /* service_flag_pending */      NULL,
-       /* handle_POLLIN */             rops_handle_POLLIN_dbus,
-       /* handle_POLLOUT */            NULL,
-       /* perform_user_POLLOUT */      NULL,
-       /* callback_on_writable */      NULL,
-       /* tx_credit */                 NULL,
-       /* write_role_protocol */       NULL,
-       /* encapsulation_parent */      NULL,
-       /* alpn_negotiated */           NULL,
-       /* close_via_role_protocol */   NULL,
-       /* close_role */                NULL,
-       /* close_kill_connection */     NULL,
-       /* destroy_role */              NULL,
-       /* adoption_bind */             NULL,
-       /* client_bind */               NULL,
+
+       /* rops_table */                rops_table_dbus,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x01,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x02,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x00,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x00,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x00,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x00,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x00,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0x00,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x00,
+                                       },
+
        /* adoption_cb clnt, srv */     { 0, 0 },
        /* rx_cb clnt, srv */           { 0, 0 },
        /* writeable cb clnt, srv */    { 0, 0 },
diff --git a/lib/roles/dbus/private-lib-roles-dbus.h b/lib/roles/dbus/private-lib-roles-dbus.h
new file mode 100644 (file)
index 0000000..4606a22
--- /dev/null
@@ -0,0 +1,46 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is included from private-lib-core.h if LWS_ROLE_DBUS
+ */
+
+#include <dbus/dbus.h>
+
+extern const struct lws_role_ops role_ops_dbus;
+
+#define lwsi_role_dbus(wsi) (wsi->role_ops == &role_ops_dbus)
+
+struct lws_role_dbus_timer {
+       struct lws_dll2 timer_list;
+       void *data;
+       time_t fire;
+};
+
+struct lws_pt_role_dbus {
+       struct lws_dll2_owner timer_list_owner;
+       lws_sorted_usec_list_t sul;
+};
+
+struct _lws_dbus_mode_related {
+       DBusConnection *conn;
+};
diff --git a/lib/roles/dbus/private.h b/lib/roles/dbus/private.h
deleted file mode 100644 (file)
index 5d7a9ac..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h if LWS_ROLE_DBUS
- */
-
-#include <dbus/dbus.h>
-
-extern struct lws_role_ops role_ops_dbus;
-
-#define lwsi_role_dbus(wsi) (wsi->role_ops == &role_ops_dbus)
-
-struct lws_role_dbus_timer {
-       struct lws_dll2 timer_list;
-       void *data;
-       time_t fire;
-};
-
-struct lws_pt_role_dbus {
-       struct lws_dll2_owner timer_list_owner;
-};
-
-struct _lws_dbus_mode_related {
-       DBusConnection *conn;
-};
diff --git a/lib/roles/h1/CMakeLists.txt b/lib/roles/h1/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3e12972
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       roles/h1/ops-h1.c)
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
index e8a66b7..4590a49 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 #ifndef min
 #define min(a, b) ((a) < (b) ? (a) : (b))
@@ -67,7 +70,7 @@ lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
                        assert(0);
                }
                lwsl_parser("issuing %d bytes to parser\n", (int)len);
-#if defined(LWS_ROLE_WS) && !defined(LWS_NO_CLIENT)
+#if defined(LWS_ROLE_WS) && defined(LWS_WITH_CLIENT)
                if (lws_ws_handshake_client(wsi, &buf, (size_t)len))
                        goto bail;
 #endif
@@ -77,8 +80,12 @@ lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
                        goto bail;
 
                /* we might have transitioned to RAW */
-               if (wsi->role_ops == &role_ops_raw_skt ||
-                   wsi->role_ops == &role_ops_raw_file)
+               if (wsi->role_ops == &role_ops_raw_skt
+#if defined(LWS_ROLE_RAW_FILE)
+                               ||
+                   wsi->role_ops == &role_ops_raw_file
+#endif
+                   )
                         /* we gave the read buffer to RAW handler already */
                        goto read_ok;
 
@@ -89,7 +96,7 @@ lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
                 * Figure out how much was read, so that we can proceed
                 * appropriately:
                 */
-               len -= (buf - last_char);
+               len -= (unsigned int)lws_ptr_diff(buf, last_char);
 
                if (!wsi->hdr_parsing_completed)
                        /* More header content on the way */
@@ -118,18 +125,22 @@ lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
        case LRS_DISCARD_BODY:
        case LRS_BODY:
 http_postbody:
-               lwsl_debug("%s: http post body: remain %d\n", __func__,
-                           (int)wsi->http.rx_content_remain);
+               lwsl_info("%s: http post body: cl set %d, remain %d, len %d\n", __func__,
+                           (int)wsi->http.content_length_given,
+                           (int)wsi->http.rx_content_remain, (int)len);
 
-               if (!wsi->http.rx_content_remain)
+               if (wsi->http.content_length_given && !wsi->http.rx_content_remain)
                        goto postbody_completion;
 
-               while (len && wsi->http.rx_content_remain) {
+               while (len && (!wsi->http.content_length_given || wsi->http.rx_content_remain)) {
                        /* Copy as much as possible, up to the limit of:
                         * what we have in the read buffer (len)
                         * remaining portion of the POST body (content_remain)
                         */
-                       body_chunk_len = min(wsi->http.rx_content_remain, len);
+                       if (wsi->http.content_length_given)
+                               body_chunk_len = min(wsi->http.rx_content_remain, len);
+                       else
+                               body_chunk_len = len;
                        wsi->http.rx_content_remain -= body_chunk_len;
                        // len -= body_chunk_len;
 #ifdef LWS_WITH_CGI
@@ -137,13 +148,13 @@ http_postbody:
                                struct lws_cgi_args args;
 
                                args.ch = LWS_STDIN;
-                               args.stdwsi = &wsi->http.cgi->stdwsi[0];
+                               args.stdwsi = &wsi->http.cgi->lsp->stdwsi[0];
                                args.data = buf;
-                               args.len = body_chunk_len;
+                               args.len = (int)(unsigned int)body_chunk_len;
 
                                /* returns how much used */
-                               n = user_callback_handle_rxflow(
-                                       wsi->protocol->callback,
+                               n = (unsigned int)user_callback_handle_rxflow(
+                                       wsi->a.protocol->callback,
                                        wsi, LWS_CALLBACK_CGI_STDIN_DATA,
                                        wsi->user_space,
                                        (void *)&args, 0);
@@ -152,22 +163,43 @@ http_postbody:
                        } else {
 #endif
                                if (lwsi_state(wsi) != LRS_DISCARD_BODY) {
-                               n = wsi->protocol->callback(wsi,
-                                       LWS_CALLBACK_HTTP_BODY, wsi->user_space,
-                                       buf, (size_t)body_chunk_len);
-                               if (n)
-                                       goto bail;
+                                       lwsl_info("%s: HTTP_BODY %d\n", __func__, (int)body_chunk_len);
+                                       n = (unsigned int)wsi->a.protocol->callback(wsi,
+                                               LWS_CALLBACK_HTTP_BODY, wsi->user_space,
+                                               buf, (size_t)body_chunk_len);
+                                       if (n)
+                                               goto bail;
                                }
                                n = (size_t)body_chunk_len;
 #ifdef LWS_WITH_CGI
                        }
 #endif
+                       lwsl_info("%s: advancing buf by %d\n", __func__, (int)n);
                        buf += n;
 
+#if defined(LWS_ROLE_H2)
+                       if (lwsi_role_h2(wsi) && !wsi->http.content_length_given) {
+                               struct lws *w = lws_get_network_wsi(wsi);
+
+                               if (w)
+                                       lwsl_info("%s: h2: nwsi h2 flags %d\n", __func__,
+                                               w->h2.h2n ? w->h2.h2n->flags: -1);
+
+                               if (w && w->h2.h2n && !(w->h2.h2n->flags & 1)) {
+                                       lwsl_info("%s: h2, no cl, not END_STREAM, continuing\n", __func__);
+                                       lws_set_timeout(wsi,
+                                               PENDING_TIMEOUT_HTTP_CONTENT,
+                                               (int)wsi->a.context->timeout_secs);
+                                       break;
+                               }
+                               goto postbody_completion;
+                       }
+#endif
+
                        if (wsi->http.rx_content_remain)  {
                                lws_set_timeout(wsi,
                                                PENDING_TIMEOUT_HTTP_CONTENT,
-                                               wsi->context->timeout_secs);
+                                               (int)wsi->a.context->timeout_secs);
                                break;
                        }
                        /* he sent all the content in time */
@@ -179,7 +211,7 @@ postbody_completion:
                         */
                        if (wsi->http.cgi)
                                lws_set_timeout(wsi, PENDING_TIMEOUT_CGI,
-                                               wsi->context->timeout_secs);
+                                               (int)wsi->a.context->timeout_secs);
                        else
 #endif
                        lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
@@ -187,7 +219,7 @@ postbody_completion:
                        if (!wsi->http.cgi)
 #endif
                        {
-#if !defined(LWS_NO_SERVER)
+#if defined(LWS_WITH_SERVER)
                                if (lwsi_state(wsi) == LRS_DISCARD_BODY) {
                                        /*
                                         * repeat the transaction completed
@@ -196,20 +228,22 @@ postbody_completion:
                                         */
 
                                        if (lws_http_transaction_completed(wsi))
-                                               return -1;
+                                               goto bail;
                                        break;
                                }
 #endif
-                               lwsl_info("HTTP_BODY_COMPLETION: %p (%s)\n",
-                                         wsi, wsi->protocol->name);
+                               lwsl_info("HTTP_BODY_COMPLETION: %s (%s)\n",
+                                         lws_wsi_tag(wsi), wsi->a.protocol->name);
 
-                               n = wsi->protocol->callback(wsi,
+                               n = (unsigned int)wsi->a.protocol->callback(wsi,
                                        LWS_CALLBACK_HTTP_BODY_COMPLETION,
                                        wsi->user_space, NULL, 0);
-                               if (n)
+                               if (n) {
+                                       lwsl_info("%s: bailing after BODY_COMPLETION\n", __func__);
                                        goto bail;
+                               }
 
-                               if (wsi->http2_substream)
+                               if (wsi->mux_substream)
                                        lwsi_set_state(wsi, LRS_ESTABLISHED);
                        }
 
@@ -223,7 +257,7 @@ postbody_completion:
        case LRS_SHUTDOWN:
 
 ws_mode:
-#if !defined(LWS_NO_CLIENT) && defined(LWS_ROLE_WS)
+#if defined(LWS_WITH_CLIENT) && defined(LWS_ROLE_WS)
                // lwsl_notice("%s: ws_mode\n", __func__);
                if (lws_ws_handshake_client(wsi, &buf, (size_t)len))
                        goto bail;
@@ -290,11 +324,11 @@ bail:
 
        return -1;
 }
-#if !defined(LWS_NO_SERVER)
+#if defined(LWS_WITH_SERVER)
 static int
 lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        struct lws_tokens ebuf;
        int n, buffered;
 
@@ -333,12 +367,13 @@ lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
        if ((lwsi_state(wsi) == LRS_ESTABLISHED ||
             lwsi_state(wsi) == LRS_ISSUING_FILE ||
             lwsi_state(wsi) == LRS_HEADERS ||
+            lwsi_state(wsi) == LRS_DOING_TRANSACTION || /* at least, SSE */
             lwsi_state(wsi) == LRS_DISCARD_BODY ||
             lwsi_state(wsi) == LRS_BODY)) {
 
                if (!wsi->http.ah && lws_header_table_attach(wsi, 0)) {
-                       lwsl_info("%s: wsi %p: ah not available\n", __func__,
-                                 wsi);
+                       lwsl_info("%s: %s: ah not available\n", __func__,
+                                 lws_wsi_tag(wsi));
                        goto try_pollout;
                }
 
@@ -352,7 +387,9 @@ lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
                 * exhausted and we tried to do a read of some kind.
                 */
 
-               buffered = lws_buflist_aware_read(pt, wsi, &ebuf);
+               ebuf.token = NULL;
+               ebuf.len = 0;
+               buffered = lws_buflist_aware_read(pt, wsi, &ebuf, 0, __func__);
                switch (ebuf.len) {
                case 0:
                        lwsl_info("%s: read 0 len a\n", __func__);
@@ -389,7 +426,8 @@ lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
 
                if (lwsi_state(wsi) == LRS_ISSUING_FILE) {
                        // lwsl_notice("stashing: wsi %p: bd %d\n", wsi, buffered);
-                       if (lws_buflist_aware_consume(wsi, &ebuf, 0, buffered))
+                       if (lws_buflist_aware_finished_consuming(wsi, &ebuf, 0,
+                                                       buffered, __func__))
                                return LWS_HPI_RET_PLEASE_CLOSE_ME;
 
                        goto try_pollout;
@@ -401,16 +439,17 @@ lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
                 */
 #if defined(LWS_ROLE_H2)
                if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY)
-                       n = lws_read_h2(wsi, ebuf.token, ebuf.len);
+                       n = lws_read_h2(wsi, ebuf.token, (unsigned int)ebuf.len);
                else
 #endif
-                       n = lws_read_h1(wsi, ebuf.token, ebuf.len);
+                       n = lws_read_h1(wsi, ebuf.token, (unsigned int)ebuf.len);
                if (n < 0) /* we closed wsi */
                        return LWS_HPI_RET_WSI_ALREADY_DIED;
 
-               lwsl_debug("%s: consumed %d\n", __func__, n);
+               // lwsl_notice("%s: consumed %d\n", __func__, n);
 
-               if (lws_buflist_aware_consume(wsi, &ebuf, n, buffered))
+               if (lws_buflist_aware_finished_consuming(wsi, &ebuf, n,
+                                                        buffered, __func__))
                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
 
                /*
@@ -483,20 +522,7 @@ try_pollout:
                        return LWS_HPI_RET_HANDLED;
                }
 
-               lws_stats_bump(pt, LWSSTATS_C_WRITEABLE_CB, 1);
-#if defined(LWS_WITH_STATS)
-               if (wsi->active_writable_req_us) {
-                       uint64_t ul = lws_now_usecs() -
-                                       wsi->active_writable_req_us;
-
-                       lws_stats_bump(pt, LWSSTATS_US_WRITABLE_DELAY_AVG, ul);
-                       lws_stats_max(pt,
-                                 LWSSTATS_US_WORST_WRITABLE_DELAY, ul);
-                       wsi->active_writable_req_us = 0;
-               }
-#endif
-
-               n = user_callback_handle_rxflow(wsi->protocol->callback, wsi,
+               n = user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
                                                LWS_CALLBACK_HTTP_WRITEABLE,
                                                wsi->user_space, NULL, 0);
                if (n < 0) {
@@ -507,6 +533,8 @@ try_pollout:
                return LWS_HPI_RET_HANDLED;
        }
 
+#if defined(LWS_WITH_FILE_OPS)
+
        /* >0 == completion, <0 == error
         *
         * We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
@@ -516,6 +544,7 @@ try_pollout:
        n = lws_serve_http_file_fragment(wsi);
        if (n < 0)
                goto fail;
+#endif
 
        return LWS_HPI_RET_HANDLED;
 
@@ -560,28 +589,6 @@ rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi,
        }
 #endif
 
-#if 0
-
-       /*
-        * !!! lws_serve_http_file_fragment() seems to duplicate most of
-        * lws_handle_POLLOUT_event() in its own loop...
-        */
-       lwsl_debug("%s: %d %d\n", __func__, (pollfd->revents & LWS_POLLOUT),
-                       lwsi_state_can_handle_POLLOUT(wsi));
-
-       if ((pollfd->revents & LWS_POLLOUT) &&
-           lwsi_state_can_handle_POLLOUT(wsi) &&
-           lws_handle_POLLOUT_event(wsi, pollfd)) {
-               if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
-                       lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE);
-               /* the write failed... it's had it */
-               wsi->socket_is_permanently_unusable = 1;
-
-               return LWS_HPI_RET_PLEASE_CLOSE_ME;
-       }
-#endif
-
-
        /* Priority 2: pre- compression transform */
 
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
@@ -594,7 +601,9 @@ rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi,
                                wsi->http.comp_ctx.may_have_more
                                );
 
-               if (wsi->role_ops->write_role_protocol(wsi, NULL, 0, &wp) < 0) {
+               if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) &&
+                   lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol).
+                                       write_role_protocol(wsi, NULL, 0, &wp) < 0) {
                        lwsl_info("%s signalling to close\n", __func__);
                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
                }
@@ -618,25 +627,31 @@ rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi,
                  */
                return LWS_HPI_RET_HANDLED;
 
-#if !defined(LWS_NO_SERVER)
+#if defined(LWS_WITH_SERVER)
        if (!lwsi_role_client(wsi)) {
                int n;
 
-               lwsl_debug("%s: %p: wsistate 0x%x\n", __func__, wsi,
-                          wsi->wsistate);
+               lwsl_debug("%s: %s: wsistate 0x%x\n", __func__, lws_wsi_tag(wsi),
+                          (unsigned int)wsi->wsistate);
+
+               if (pollfd->revents & LWS_POLLHUP &&
+                   !lws_buflist_total_len(&wsi->buflist))
+                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
+
                n = lws_h1_server_socket_service(wsi, pollfd);
                if (n != LWS_HPI_RET_HANDLED)
                        return n;
                if (lwsi_state(wsi) != LRS_SSL_INIT)
                        if (lws_server_socket_service_ssl(wsi,
-                                                         LWS_SOCK_INVALID))
+                                                         LWS_SOCK_INVALID,
+                                       !!(pollfd->revents & LWS_POLLIN)))
                                return LWS_HPI_RET_PLEASE_CLOSE_ME;
 
                return LWS_HPI_RET_HANDLED;
        }
 #endif
 
-#ifndef LWS_NO_CLIENT
+#if defined(LWS_WITH_CLIENT)
        if ((pollfd->revents & LWS_POLLIN) &&
             wsi->hdr_parsing_completed && !wsi->told_user_closed) {
 
@@ -655,12 +670,12 @@ rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi,
                if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
 
-               //lwsl_notice("calling back %s\n", wsi->protocol->name);
+               //lwsl_notice("calling back %s\n", wsi->a.protocol->name);
 
                /* let user code know, he'll usually ask for writeable
                 * callback and drain / re-enable it there
                 */
-               if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
+               if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
                                               LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
                                                wsi->user_space, NULL, 0)) {
                        lwsl_info("RECEIVE_CLIENT_HTTP closed it\n");
@@ -674,17 +689,21 @@ rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi,
 //     if (lwsi_state(wsi) == LRS_ESTABLISHED)
 //             return LWS_HPI_RET_HANDLED;
 
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
        if ((pollfd->revents & LWS_POLLOUT) &&
            lws_handle_POLLOUT_event(wsi, pollfd)) {
                lwsl_debug("POLLOUT event closed it\n");
                return LWS_HPI_RET_PLEASE_CLOSE_ME;
        }
 
-       if (lws_client_socket_service(wsi, pollfd, NULL))
+       if (lws_http_client_socket_service(wsi, pollfd))
                return LWS_HPI_RET_WSI_ALREADY_DIED;
 #endif
 
+       if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
+           (pollfd->revents & LWS_POLLHUP))
+               return LWS_HPI_RET_PLEASE_CLOSE_ME;
+
        return LWS_HPI_RET_HANDLED;
 }
 
@@ -692,7 +711,9 @@ static int
 rops_handle_POLLOUT_h1(struct lws *wsi)
 {
 
-       if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY) {
+
+       if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY ||
+           lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY) {
 #if defined(LWS_WITH_HTTP_PROXY)
                if (wsi->http.proxy_clientside) {
                        unsigned char *buf, prebuf[LWS_PRE + 1024];
@@ -704,11 +725,10 @@ rops_handle_POLLOUT_h1(struct lws *wsi)
                                len = sizeof(prebuf) - LWS_PRE;
 
                        if (len) {
-
                                memcpy(prebuf + LWS_PRE, buf, len);
 
-                               lwsl_debug("%s: %p: proxying body %d %d %d %d %d\n",
-                                               __func__, wsi, (int)len,
+                               lwsl_debug("%s: %s: proxying body %d %d %d %d %d\n",
+                                               __func__, lws_wsi_tag(wsi), (int)len,
                                                (int)wsi->http.tx_content_length,
                                                (int)wsi->http.tx_content_remain,
                                                (int)wsi->http.rx_content_length,
@@ -723,23 +743,28 @@ rops_handle_POLLOUT_h1(struct lws *wsi)
                                }
 
                                lws_buflist_use_segment(&wsi->parent->http.buflist_post_body, len);
+
                        }
 
-                       if (wsi->parent->http.buflist_post_body)
+                       if (wsi->parent->http.buflist_post_body) {
                                lws_callback_on_writable(wsi);
-                       else {
+                               return LWS_HP_RET_DROP_POLLOUT;
+                       }
+
+                       lwsl_wsi_err(wsi, "nothing to send");
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-                               /* prepare ourselves to do the parsing */
-                               wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
-                               wsi->http.ah->lextable_pos = 0;
+                       /* prepare ourselves to do the parsing */
+                       wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
+                       wsi->http.ah->lextable_pos = 0;
 #if defined(LWS_WITH_CUSTOM_HEADERS)
-                               wsi->http.ah->unk_pos = 0;
+                       wsi->http.ah->unk_pos = 0;
 #endif
 #endif
-                               lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
-                               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
-                                               wsi->context->timeout_secs);
-                       }
+                       lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
+                       lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
+                                       (int)wsi->a.context->timeout_secs);
+
+                       return LWS_HP_RET_DROP_POLLOUT;
                }
 #endif
                return LWS_HP_RET_USER_SERVICE;
@@ -761,7 +786,7 @@ rops_write_role_protocol_h1(struct lws *wsi, unsigned char *buf, size_t len,
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
        if (wsi->http.lcs && (((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL ||
                              ((*wp) & 0x1f) == LWS_WRITE_HTTP)) {
-               unsigned char mtubuf[1400 + LWS_PRE +
+               unsigned char mtubuf[1500 + LWS_PRE +
                                     LWS_HTTP_CHUNK_HDR_MAX_SIZE +
                                     LWS_HTTP_CHUNK_TRL_MAX_SIZE],
                              *out = mtubuf + LWS_PRE +
@@ -774,12 +799,13 @@ rops_write_role_protocol_h1(struct lws *wsi, unsigned char *buf, size_t len,
                if (n)
                        return n;
 
-               lwsl_info("%s: %p: transformed %d bytes to %d "
-                          "(wp 0x%x, more %d)\n", __func__, wsi, (int)len,
+               lwsl_info("%s: %s: transformed %d bytes to %d "
+                          "(wp 0x%x, more %d)\n", __func__,
+                          lws_wsi_tag(wsi), (int)len,
                           (int)o, (int)*wp, wsi->http.comp_ctx.may_have_more);
 
                if (!o)
-                       return olen;
+                       return (int)olen;
 
                if (wsi->http.comp_ctx.chunking) {
                        char c[LWS_HTTP_CHUNK_HDR_MAX_SIZE + 2];
@@ -790,8 +816,8 @@ rops_write_role_protocol_h1(struct lws *wsi, unsigned char *buf, size_t len,
                        n = lws_snprintf(c, sizeof(c), "%X\x0d\x0a", (int)o);
                        lwsl_info("%s: chunk (%d) %s", __func__, (int)o, c);
                        out -= n;
-                       o += n;
-                       memcpy(out, c, n);
+                       o += (unsigned int)n;
+                       memcpy(out, c, (unsigned int)n);
                        out[o++] = '\x0d';
                        out[o++] = '\x0a';
 
@@ -823,7 +849,7 @@ static int
 rops_alpn_negotiated_h1(struct lws *wsi, const char *alpn)
 {
        lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi));
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
        if (lwsi_role_client(wsi)) {
                /*
                 * If alpn asserts it is http/1.1, server support for KA is
@@ -842,7 +868,7 @@ rops_alpn_negotiated_h1(struct lws *wsi, const char *alpn)
 static int
 rops_destroy_role_h1(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        struct allocated_headers *ah;
 
        /* we may not have an ah, but may be on the waiting list... */
@@ -853,7 +879,8 @@ rops_destroy_role_h1(struct lws *wsi)
 
        while (ah) {
                if (ah->in_use && ah->wsi == wsi) {
-                       lwsl_err("%s: ah leak: wsi %p\n", __func__, wsi);
+                       lwsl_err("%s: ah leak: wsi %s\n", __func__,
+                                       lws_wsi_tag(wsi));
                        ah->in_use = 0;
                        ah->wsi = NULL;
                        pt->http.ah_count_in_use--;
@@ -872,7 +899,7 @@ rops_destroy_role_h1(struct lws *wsi)
        return 0;
 }
 
-#if !defined(LWS_NO_SERVER)
+#if defined(LWS_WITH_SERVER)
 
 static int
 rops_adoption_bind_h1(struct lws *wsi, int type, const char *vh_prot_name)
@@ -892,35 +919,54 @@ rops_adoption_bind_h1(struct lws *wsi, int type, const char *vh_prot_name)
                return 1;
        }
 
-       lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ?
-                           LRS_SSL_INIT : LRS_HEADERS, &role_ops_h1);
+#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
+       if (wsi->a.vhost->ss_handle &&
+           wsi->a.vhost->ss_handle->policy->protocol == LWSSSP_RAW) {
+               lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ?
+                               LRS_SSL_INIT : LRS_ESTABLISHED, &role_ops_raw_skt);
+               return 1;
+       }
+#endif
+
+       /* If Non-TLS and HTTP2 prior knowledge is enabled, skip to clear text HTTP2 */
+
+#if defined(LWS_WITH_HTTP2)
+       if ((!(type & LWS_ADOPT_ALLOW_SSL)) && (wsi->a.vhost->options & LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE)) {
+               lwsl_info("http/2 prior knowledge\n");
+               lws_metrics_tag_wsi_add(wsi, "upg", "h2_prior");
+               lws_role_call_alpn_negotiated(wsi, "h2");
+       }
+       else
+#endif
+               lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ?
+                               LRS_SSL_INIT : LRS_HEADERS, &role_ops_h1);
 
        /*
-        * We have to bind to h1 as a default even when we're actually going to
+        * Otherwise, we have to bind to h1 as a default even when we're actually going to
         * replace it as an h2 bind later.  So don't take this seriously if the
         * default is disabled (ws upgrade caees properly about it)
         */
 
-       if (!vh_prot_name && wsi->vhost->default_protocol_index <
-                            wsi->vhost->count_protocols)
-               wsi->protocol = &wsi->vhost->protocols[
-                               wsi->vhost->default_protocol_index];
+       if (!vh_prot_name && wsi->a.vhost->default_protocol_index <
+                            wsi->a.vhost->count_protocols)
+               wsi->a.protocol = &wsi->a.vhost->protocols[
+                               wsi->a.vhost->default_protocol_index];
        else
-               wsi->protocol = &wsi->vhost->protocols[0];
+               wsi->a.protocol = &wsi->a.vhost->protocols[0];
 
        /* the transport is accepted... give him time to negotiate */
        lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
-                       wsi->context->timeout_secs);
+                       (int)wsi->a.context->timeout_secs);
 
        return 1; /* bound */
 }
 
 #endif
 
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
 
 static const char * const http_methods[] = {
-       "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", "CONNECT"
+       "GET", "POST", "OPTIONS", "HEAD", "PUT", "PATCH", "DELETE", "CONNECT"
 };
 
 static int
@@ -937,7 +983,7 @@ rops_client_bind_h1(struct lws *wsi, const struct lws_client_connect_info *i)
                 * we can assign the user space now, otherwise do it after the
                 * ws subprotocol negotiated
                 */
-               if (!wsi->user_space && wsi->stash->method)
+               if (!wsi->user_space && wsi->stash->cis[CIS_METHOD])
                        if (lws_ensure_user_space(wsi))
                                return 1;
 
@@ -951,11 +997,8 @@ rops_client_bind_h1(struct lws *wsi, const struct lws_client_connect_info *i)
                  * only try h2 if he assertively said to use h2 alpn, otherwise
                  * ws implies alpn restriction to h1.
                  */
-               if (!wsi->stash->method && !wsi->stash->alpn) {
-                       wsi->stash->alpn = lws_strdup("http/1.1");
-                       if (!wsi->stash->alpn)
-                               return 1;
-               }
+               if (!wsi->stash->cis[CIS_METHOD] && !wsi->stash->cis[CIS_ALPN])
+                       wsi->stash->cis[CIS_ALPN] = "http/1.1";
 
                /* if we went on the ah waiting list, it's ok, we can wait.
                 *
@@ -963,7 +1006,7 @@ rops_client_bind_h1(struct lws *wsi, const struct lws_client_connect_info *i)
                 * lws_http_client_connect_via_info2().
                 */
                if (lws_header_table_attach(wsi, 0)
-#ifndef LWS_NO_CLIENT
+#if defined(LWS_WITH_CLIENT)
                                < 0)
                        /*
                         * if we failed here, the connection is already closed
@@ -980,19 +1023,24 @@ rops_client_bind_h1(struct lws *wsi, const struct lws_client_connect_info *i)
 
        /*
         * Clients that want to be h1, h2, or ws all start out as h1
-        * (we don't yet know if the server supports h2 or ws)
+        * (we don't yet know if the server supports h2 or ws), unless their
+        * alpn is only "h2"
         */
 
+//     if (i->alpn && !strcmp(i->alpn, "h2"))
+//             return 0; /* we are h1, he only wants h2 */
+
        if (!i->method) { /* websockets */
 #if defined(LWS_ROLE_WS)
                if (lws_create_client_ws_object(i, wsi))
                        goto fail_wsi;
+
+               goto bind_h1;
 #else
                lwsl_err("%s: ws role not configured\n", __func__);
 
                goto fail_wsi;
 #endif
-               goto bind_h1;
        }
 
        /* if a recognized http method, bind to it */
@@ -1016,147 +1064,101 @@ fail_wsi:
 }
 #endif
 
-#if 0
-static int
-rops_perform_user_POLLOUT_h1(struct lws *wsi)
-{
-       volatile struct lws *vwsi = (volatile struct lws *)wsi;
-       int n;
-
-       /* priority 1: post compression-transform buffered output */
-
-       if (lws_has_buffered_out(wsi)) {
-               lwsl_debug("%s: completing partial\n", __func__);
-               if (lws_issue_raw(wsi, NULL, 0) < 0) {
-                       lwsl_info("%s signalling to close\n", __func__);
-                       return -1;
-               }
-               n = 0;
-               vwsi->leave_pollout_active = 1;
-               goto cleanup;
-       }
-
-       /* priority 2: pre compression-transform buffered output */
-
-#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
-       if (wsi->http.comp_ctx.buflist_comp ||
-           wsi->http.comp_ctx.may_have_more) {
-               enum lws_write_protocol wp = LWS_WRITE_HTTP;
-
-               lwsl_info("%s: completing comp partial"
-                          "(buflist_comp %p, may %d)\n",
-                          __func__, wsi->http.comp_ctx.buflist_comp,
-                           wsi->http.comp_ctx.may_have_more);
-
-               if (rops_write_role_protocol_h1(wsi, NULL, 0, &wp) < 0) {
-                       lwsl_info("%s signalling to close\n", __func__);
-                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
-                                          "comp write fail");
-               }
-               n = 0;
-               vwsi->leave_pollout_active = 1;
-               goto cleanup;
-       }
-#endif
-
-       /* priority 3: if no buffered out and waiting for that... */
-
-       if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) {
-               wsi->socket_is_permanently_unusable = 1;
-               return -1;
-       }
-
-       /* priority 4: user writeable callback */
-
-       vwsi = (volatile struct lws *)wsi;
-       vwsi->leave_pollout_active = 0;
-
-       n = lws_callback_as_writeable(wsi);
-
-cleanup:
-       vwsi->handling_pollout = 0;
-
-       if (vwsi->leave_pollout_active)
-               lws_change_pollfd(wsi, 0, LWS_POLLOUT);
-
-       return n;
-}
-#endif
-
 static int
 rops_close_kill_connection_h1(struct lws *wsi, enum lws_close_status reason)
 {
 #if defined(LWS_WITH_HTTP_PROXY)
-       struct lws *wsi_eff = lws_client_wsi_effective(wsi);
-
-       if (!wsi_eff->http.proxy_clientside)
+       if (!wsi->http.proxy_clientside)
                return 0;
 
-       wsi_eff->http.proxy_clientside = 0;
+       wsi->http.proxy_clientside = 0;
 
-       if (user_callback_handle_rxflow(wsi_eff->protocol->callback, wsi_eff,
+       if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
                                        LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
-                                       wsi_eff->user_space, NULL, 0))
+                                       wsi->user_space, NULL, 0))
                return 0;
 #endif
        return 0;
 }
 
 int
-rops_init_context_h1(struct lws_context *context,
-                    const struct lws_context_creation_info *info)
+rops_pt_init_destroy_h1(struct lws_context *context,
+                   const struct lws_context_creation_info *info,
+                   struct lws_context_per_thread *pt, int destroy)
 {
        /*
         * We only want to do this once... we will do it if no h2 support
         * otherwise let h2 ops do it.
         */
-#if !defined(LWS_ROLE_H2)
-       int n;
-
-       for (n = 0; n < context->count_threads; n++) {
-               struct lws_context_per_thread *pt = &context->pt[n];
+#if !defined(LWS_ROLE_H2) && defined(LWS_WITH_SERVER)
+       if (!destroy) {
 
                pt->sul_ah_lifecheck.cb = lws_sul_http_ah_lifecheck;
 
-               __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_ah_lifecheck,
-                                30 * LWS_US_PER_SEC);
-       }
+               __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                                &pt->sul_ah_lifecheck, 30 * LWS_US_PER_SEC);
+       } else
+               lws_dll2_remove(&pt->sul_ah_lifecheck.list);
 #endif
 
        return 0;
 }
 
-struct lws_role_ops role_ops_h1 = {
+static const lws_rops_t rops_table_h1[] = {
+       /*  1 */ { .pt_init_destroy       = rops_pt_init_destroy_h1 },
+       /*  2 */ { .handle_POLLIN         = rops_handle_POLLIN_h1 },
+       /*  3 */ { .handle_POLLOUT        = rops_handle_POLLOUT_h1 },
+       /*  4 */ { .write_role_protocol   = rops_write_role_protocol_h1 },
+       /*  5 */ { .alpn_negotiated       = rops_alpn_negotiated_h1 },
+       /*  6 */ { .close_kill_connection = rops_close_kill_connection_h1 },
+       /*  7 */ { .destroy_role          = rops_destroy_role_h1 },
+#if defined(LWS_WITH_SERVER)
+       /*  8 */ { .adoption_bind         = rops_adoption_bind_h1 },
+#endif
+#if defined(LWS_WITH_CLIENT)
+       /*  8 if client and no server */
+       /*  9 */ { .client_bind           = rops_client_bind_h1 },
+#endif
+};
+
+const struct lws_role_ops role_ops_h1 = {
        /* role name */                 "h1",
        /* alpn id */                   "http/1.1",
-       /* check_upgrades */            NULL,
-       /* init_context */              rops_init_context_h1,
-       /* init_vhost */                NULL,
-       /* destroy_vhost */             NULL,
-       /* periodic_checks */           NULL,
-       /* service_flag_pending */      NULL,
-       /* handle_POLLIN */             rops_handle_POLLIN_h1,
-       /* handle_POLLOUT */            rops_handle_POLLOUT_h1,
-       /* perform_user_POLLOUT */      NULL,
-       /* callback_on_writable */      NULL,
-       /* tx_credit */                 NULL,
-       /* write_role_protocol */       rops_write_role_protocol_h1,
-       /* encapsulation_parent */      NULL,
-       /* alpn_negotiated */           rops_alpn_negotiated_h1,
-       /* close_via_role_protocol */   NULL,
-       /* close_role */                NULL,
-       /* close_kill_connection */     rops_close_kill_connection_h1,
-       /* destroy_role */              rops_destroy_role_h1,
-#if !defined(LWS_NO_SERVER)
-       /* adoption_bind */             rops_adoption_bind_h1,
+       /* rops_table */                rops_table_h1,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x01,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x02,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x30,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x00,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x40,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x50,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x06,
+         /* LWS_ROPS_destroy_role */
+#if defined(LWS_WITH_SERVER)
+         /* LWS_ROPS_adoption_bind */                  0x78,
+#else
+         /* LWS_ROPS_adoption_bind */                  0x70,
+#endif
+         /* LWS_ROPS_client_bind */
+#if defined(LWS_WITH_CLIENT)
+#if defined(LWS_WITH_SERVER)
+         /* LWS_ROPS_issue_keepalive */                0x90,
 #else
-                                       NULL,
+         /* LWS_ROPS_issue_keepalive */                0x80,
 #endif
-#if !defined(LWS_NO_CLIENT)
-       /* client_bind */               rops_client_bind_h1,
 #else
-                                       NULL,
+         /* LWS_ROPS_issue_keepalive */                0x00,
 #endif
+                                       },
        /* adoption_cb clnt, srv */     { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
                                          LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
        /* rx_cb clnt, srv */           { LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
diff --git a/lib/roles/h1/private-lib-roles-h1.h b/lib/roles/h1/private-lib-roles-h1.h
new file mode 100644 (file)
index 0000000..f58ce7e
--- /dev/null
@@ -0,0 +1,30 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *  This is included from private-lib-core.h if LWS_ROLE_H1
+ *
+ *  Most of the h1 business is defined in the h1 / h2 common roles/http dir
+ */
+
+extern const struct lws_role_ops role_ops_h1;
+#define lwsi_role_h1(wsi) (wsi->role_ops == &role_ops_h1)
diff --git a/lib/roles/h1/private.h b/lib/roles/h1/private.h
deleted file mode 100644 (file)
index 3f53954..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h if LWS_ROLE_H1
- *
- *  Most of the h1 business is defined in the h1 / h2 common roles/http dir
- */
-
-extern struct lws_role_ops role_ops_h1;
-#define lwsi_role_h1(wsi) (wsi->role_ops == &role_ops_h1)
diff --git a/lib/roles/h2/CMakeLists.txt b/lib/roles/h2/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9714602
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       roles/h2/http2.c
+       roles/h2/hpack.c
+       roles/h2/ops-h2.c)
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+
index f8b89c3..f6aefd3 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * lib/hpack.c
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2014-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /*
  * Official static header table for HPACK
@@ -261,12 +264,6 @@ static int lws_frag_start(struct lws *wsi, int hdr_token_idx)
                        n = ah->frags[n].nfrag;
                /* and point it to continue in our continuation fragment */
                ah->frags[n].nfrag = ah->nfrag;
-
-               /* cookie continuations need a separator token of ';' */
-               if (hdr_token_idx == WSI_TOKEN_HTTP_COOKIE) {
-                       ah->data[ah->pos++] = ';';
-                       ah->frags[ah->nfrag].len++;
-               }
        } else
                ah->frag_index[hdr_token_idx] = ah->nfrag;
 
@@ -277,10 +274,10 @@ static int lws_frag_append(struct lws *wsi, unsigned char c)
 {
        struct allocated_headers *ah = wsi->http.ah;
 
-       ah->data[ah->pos++] = c;
+       ah->data[ah->pos++] = (char)c;
        ah->frags[ah->nfrag].len++;
 
-       return (int)ah->pos >= wsi->context->max_http_header_data;
+       return (unsigned int)ah->pos >= wsi->a.context->max_http_header_data;
 }
 
 static int lws_frag_end(struct lws *wsi)
@@ -325,14 +322,16 @@ static void lws_dump_header(struct lws *wsi, int hdr)
 
        (void)p;
 
-       len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
+       len = lws_hdr_copy(wsi, s, sizeof(s) - 1, (enum lws_token_indexes)hdr);
        if (len < 0)
                strcpy(s, "(too big to show)");
        else
                s[len] = '\0';
-       p = lws_token_to_string(hdr);
+#if defined(_DEBUG)
+       p = lws_token_to_string((enum lws_token_indexes)hdr);
        lwsl_header("  hdr tok %d (%s) = '%s' (len %d)\n", hdr,
                   p ? (char *)p : (char *)"null", s, len);
+#endif
 }
 
 /*
@@ -391,17 +390,16 @@ lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,
                return -1;
        }
 
-       if (index < (int)LWS_ARRAY_SIZE(static_token) ||
-           index >= (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries) {
+       if (index >= (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries) {
                lwsl_info("  %s: adjusted index %d >= %d\n", __func__, index,
-                           dyn->used_entries);
+                               (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries);
                lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
                              "index out of range");
                return -1;
        }
 
        index -= (int)LWS_ARRAY_SIZE(static_token);
-       index = (dyn->pos - 1 - index) % dyn->num_entries;
+       index = lws_safe_modulo(dyn->pos - 1 - index, dyn->num_entries);
        if (index < 0)
                index += dyn->num_entries;
 
@@ -432,14 +430,14 @@ lws_h2_dynamic_table_dump(struct lws *wsi)
                return 1;
        dyn = &nwsi->h2.h2n->hpack_dyn_table;
 
-       lwsl_header("Dump dyn table for nwsi %p (%d / %d members, pos = %d, "
-                   "start index %d, virt used %d / %d)\n", nwsi,
+       lwsl_header("Dump dyn table for nwsi %s (%d / %d members, pos = %d, "
+                   "start index %d, virt used %d / %d)\n", lws_wsi_tag(nwsi),
                    dyn->used_entries, dyn->num_entries, dyn->pos,
                    (uint32_t)LWS_ARRAY_SIZE(static_token),
                    dyn->virtual_payload_usage, dyn->virtual_payload_max);
 
        for (n = 0; n < dyn->used_entries; n++) {
-               m = (dyn->pos - 1 - n) % dyn->num_entries;
+               m = lws_safe_modulo(dyn->pos - 1 - n, dyn->num_entries);
                if (m < 0)
                        m += dyn->num_entries;
                if (dyn->entries[m].lws_hdr_idx != LWS_HPACK_IGNORE_ENTRY)
@@ -460,8 +458,8 @@ static void
 lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)
 {
        lwsl_header("freeing %d for reuse\n", idx);
-       dyn->virtual_payload_usage -=  dyn->entries[idx].value_len +
-                               dyn->entries[idx].hdr_len;
+       dyn->virtual_payload_usage = (uint32_t)((unsigned int)dyn->virtual_payload_usage - (unsigned int)(dyn->entries[idx].value_len +
+                               dyn->entries[idx].hdr_len));
        lws_free_set_NULL(dyn->entries[idx].value);
        dyn->entries[idx].value = NULL;
        dyn->entries[idx].value_len = 0;
@@ -486,7 +484,7 @@ lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)
 
 static int
 lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
-                        int lws_hdr_index, char *arg, int len)
+                        int lws_hdr_index, char *arg, size_t len)
 {
        struct hpack_dynamic_table *dyn;
        int new_index;
@@ -504,7 +502,7 @@ lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
        }
        lws_h2_dynamic_table_dump(wsi);
 
-       new_index = (dyn->pos) % dyn->num_entries;
+       new_index = lws_safe_modulo(dyn->pos, dyn->num_entries);
        if (dyn->num_entries && dyn->used_entries == dyn->num_entries) {
                if (dyn->virtual_payload_usage < dyn->virtual_payload_max)
                        lwsl_err("Dropping header content before limit!\n");
@@ -520,9 +518,10 @@ lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
 
        while (dyn->virtual_payload_usage &&
               dyn->used_entries &&
-              dyn->virtual_payload_usage + hdr_len + len >
+              dyn->virtual_payload_usage + (unsigned int)hdr_len + len >
                                dyn->virtual_payload_max + 1024) {
-               int n = (dyn->pos - dyn->used_entries) % dyn->num_entries;
+               int n = lws_safe_modulo(dyn->pos - dyn->used_entries,
+                                               dyn->num_entries);
                if (n < 0)
                        n += dyn->num_entries;
                lws_dynamic_free(dyn, n);
@@ -543,21 +542,22 @@ lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
 
                memcpy(dyn->entries[new_index].value, arg, len);
                dyn->entries[new_index].value[len] = '\0';
-               dyn->entries[new_index].value_len = len;
+               dyn->entries[new_index].value_len = (uint16_t)len;
        } else
                dyn->entries[new_index].value = NULL;
 
-       dyn->entries[new_index].lws_hdr_idx = lws_hdr_index;
-       dyn->entries[new_index].hdr_len = hdr_len;
+       dyn->entries[new_index].lws_hdr_idx = (uint16_t)lws_hdr_index;
+       dyn->entries[new_index].hdr_len = (uint16_t)hdr_len;
 
-       dyn->virtual_payload_usage += hdr_len + len;
+       dyn->virtual_payload_usage = (uint32_t)(dyn->virtual_payload_usage +
+                                       (unsigned int)hdr_len + len);
 
        lwsl_info("%s: index %ld: lws_hdr_index 0x%x, hdr len %d, '%s' len %d\n",
                  __func__, (long)LWS_ARRAY_SIZE(static_token),
                  lws_hdr_index, hdr_len, dyn->entries[new_index].value ?
-                                dyn->entries[new_index].value : "null", len);
+                                dyn->entries[new_index].value : "null", (int)len);
 
-       dyn->pos = (dyn->pos + 1) % dyn->num_entries;
+       dyn->pos = (uint16_t)lws_safe_modulo(dyn->pos + 1, dyn->num_entries);
 
        lws_h2_dynamic_table_dump(wsi);
 
@@ -593,32 +593,32 @@ lws_hpack_dynamic_size(struct lws *wsi, int size)
                goto bail;
 
        dyn = &nwsi->h2.h2n->hpack_dyn_table;
-       lwsl_info("%s: from %d to %d, lim %d\n", __func__,
+       lwsl_info("%s: from %d to %d, lim %u\n", __func__,
                  (int)dyn->num_entries, size,
-                 nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
+                 (unsigned int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
 
        if (!size) {
                size = dyn->num_entries * 8;
                lws_hpack_destroy_dynamic_header(wsi);
        }
 
-       if (size > (int)nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]) {
+       if (size > (int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]) {
                lwsl_info("rejecting hpack dyn size %u vs %u\n", size,
-                               nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
+                         (unsigned int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
 
                // this seems necessary to work with some browsers
 
-               if (nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE] == 65536 &&
+               if (nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE] == 65536 &&
                                size == 65537) { /* h2spec */
                        lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
                                  "Asked for header table bigger than we told");
                        goto bail;
                }
 
-               size = nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE];
+               size = (int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE];
        }
 
-       dyn->virtual_payload_max = size;
+       dyn->virtual_payload_max = (uint32_t)size;
 
        size = size / 8;
        min = size;
@@ -633,13 +633,13 @@ lws_hpack_dynamic_size(struct lws *wsi, int size)
 
        // lwsl_notice("dte requested size %d\n", size);
 
-       dte = lws_zalloc(sizeof(*dte) * (size + 1), "dynamic table entries");
+       dte = lws_zalloc(sizeof(*dte) * (unsigned int)(size + 1), "dynamic table entries");
        if (!dte)
                goto bail;
 
        while (dyn->virtual_payload_usage && dyn->used_entries &&
               dyn->virtual_payload_usage > dyn->virtual_payload_max) {
-               n = (dyn->pos - dyn->used_entries) % dyn->num_entries;
+               n = lws_safe_modulo(dyn->pos - dyn->used_entries, dyn->num_entries);
                if (n < 0)
                        n += dyn->num_entries;
                lws_dynamic_free(dyn, n);
@@ -661,10 +661,10 @@ lws_hpack_dynamic_size(struct lws *wsi, int size)
        }
 
        dyn->entries = dte;
-       dyn->num_entries = size;
-       dyn->used_entries = min;
+       dyn->num_entries = (uint16_t)size;
+       dyn->used_entries = (uint16_t)min;
        if (size)
-               dyn->pos = min % size;
+               dyn->pos = (uint16_t)lws_safe_modulo(min, size);
        else
                dyn->pos = 0;
 
@@ -725,7 +725,7 @@ lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)
                           tok);
        } else
                lwsl_header("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
-                               lws_token_to_string(tok));
+                               lws_token_to_string((enum lws_token_indexes)tok));
 
        if (tok == LWS_HPACK_IGNORE_ENTRY)
                return 0;
@@ -741,7 +741,7 @@ lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)
 
        if (p)
                while (*p && len--)
-                       if (lws_frag_append(wsi, *p++))
+                       if (lws_frag_append(wsi, (unsigned char)*p++))
                                return 1;
 
        if (lws_frag_end(wsi))
@@ -752,10 +752,47 @@ lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)
        return 0;
 }
 
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x03,0x00,0x80,0x0f,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x07,0x00,0x00,0x3e,0x00,0x00,0x00,0x80,0x03,0x09,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x03,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if defined(LWS_HTTP_HEADERS_ALL) || ( defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2))
 static uint8_t lws_header_implies_psuedoheader_map[] = {
-       0x07, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00 /* <-64 */,
-       0x0e /* <- 72 */, 0x04 /* <- 80 */, 0, 0, 0, 0
+       0x07,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x0e,0x24,0x00,0x00,0x00,0x00,0x00,
 };
+#endif
+
 
 static int
 lws_hpack_handle_pseudo_rules(struct lws *nwsi, struct lws *wsi, int m)
@@ -836,7 +873,7 @@ int lws_hpack_interpret(struct lws *wsi, unsigned char c)
                                        return 1;
                        }
 
-                       m = lws_token_from_index(wsi, h2n->hdr_idx,
+                       m = lws_token_from_index(wsi, (int)h2n->hdr_idx,
                                                 NULL, NULL, NULL);
                        if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
                                return 1;
@@ -941,27 +978,27 @@ int lws_hpack_interpret(struct lws *wsi, unsigned char c)
                                break;
                        }
                        h2n->last_action_dyntable_resize = 1;
-                       if (lws_hpack_dynamic_size(wsi, h2n->hpack_len))
+                       if (lws_hpack_dynamic_size(wsi, (int)h2n->hpack_len))
                                return 1;
                        break;
                }
                break;
 
        case HPKS_IDX_EXT:
-               h2n->hpack_len = h2n->hpack_len |
-                                ((c & 0x7f) << h2n->ext_count);
-               h2n->ext_count += 7;
+               h2n->hpack_len = (uint32_t)((unsigned int)h2n->hpack_len |
+                               (unsigned int)((c & 0x7f) << h2n->ext_count));
+               h2n->ext_count = (uint8_t)(h2n->ext_count + 7);
                if (c & 0x80) /* extended int not complete yet */
                        break;
 
                /* extended integer done */
                h2n->hpack_len += h2n->hpack_m;
-               lwsl_header("HPKS_IDX_EXT: hpack_len %d\n", h2n->hpack_len);
+               lwsl_header("HPKS_IDX_EXT: hpack_len %u\n", (unsigned int)h2n->hpack_len);
 
                switch (h2n->hpack_type) {
                case HPKT_INDEXED_HDR_7:
-                       if (lws_hpack_use_idx_hdr(wsi, h2n->hpack_len,
-                                                 h2n->hdr_idx)) {
+                       if (lws_hpack_use_idx_hdr(wsi, (int)h2n->hpack_len,
+                                                 (int)h2n->hdr_idx)) {
                                lwsl_notice("%s: hd7 use fail\n", __func__);
                                return 1;
                        }
@@ -970,7 +1007,7 @@ int lws_hpack_interpret(struct lws *wsi, unsigned char c)
 
                case HPKT_SIZE_5:
                        h2n->last_action_dyntable_resize = 1;
-                       if (lws_hpack_dynamic_size(wsi, h2n->hpack_len))
+                       if (lws_hpack_dynamic_size(wsi, (int)h2n->hpack_len))
                                return 1;
                        h2n->hpack = HPKS_TYPE;
                        break;
@@ -1000,6 +1037,13 @@ int lws_hpack_interpret(struct lws *wsi, unsigned char c)
                        h2n->hpack = HPKS_HLEN_EXT;
                        break;
                }
+
+               if (h2n->value && !h2n->hpack_len) {
+                       lwsl_debug("%s: zero-length header data\n", __func__);
+                       h2n->hpack = HPKS_TYPE;
+                       goto fin;
+               }
+
 pre_data:
                h2n->hpack = HPKS_DATA;
                if (!h2n->value || !h2n->hdr_idx) {
@@ -1015,14 +1059,14 @@ pre_data:
                        n = ah->parser_state;
                        if (n == 255) {
                                n = -1;
-                               h2n->hdr_idx = -1;
+                               h2n->hdr_idx = (uint32_t)-1;
                        } else
                                h2n->hdr_idx = 1;
                } else {
-                       n = lws_token_from_index(wsi, h2n->hdr_idx, NULL,
+                       n = lws_token_from_index(wsi, (int)h2n->hdr_idx, NULL,
                                                 NULL, NULL);
-                       lwsl_header("  lws_tok_from_idx(%d) says %d\n",
-                                  h2n->hdr_idx, n);
+                       lwsl_header("  lws_tok_from_idx(%u) says %d\n",
+                                  (unsigned int)h2n->hdr_idx, n);
                }
 
                if (n == LWS_HPACK_IGNORE_ENTRY || n == -1)
@@ -1051,9 +1095,9 @@ pre_data:
                break;
 
        case HPKS_HLEN_EXT:
-               h2n->hpack_len = h2n->hpack_len |
-                                ((c & 0x7f) << h2n->ext_count);
-               h2n->ext_count += 7;
+               h2n->hpack_len = (uint32_t)((unsigned int)h2n->hpack_len |
+                               (unsigned int)((c & 0x7f) << h2n->ext_count));
+               h2n->ext_count = (uint8_t)(h2n->ext_count + 7);
                if (c & 0x80) /* extended integer not complete yet */
                        break;
 
@@ -1068,9 +1112,9 @@ pre_data:
                        if (h2n->huff) {
                                char b = (c >> 7) & 1;
                                prev = h2n->hpack_pos;
-                               h2n->hpack_pos = huftable_decode(
-                                               h2n->hpack_pos, b);
-                               c <<= 1;
+                               h2n->hpack_pos = (uint16_t)huftable_decode(
+                                               (int)h2n->hpack_pos, b);
+                               c = (unsigned char)(c << 1);
                                if (h2n->hpack_pos == 0xffff) {
                                        lwsl_notice("Huffman err\n");
                                        return 1;
@@ -1081,7 +1125,7 @@ pre_data:
                                        h2n->huff_pad++;
                                        continue;
                                }
-                               c1 = h2n->hpack_pos & 0x7fff;
+                               c1 = (uint8_t)(h2n->hpack_pos & 0x7fff);
                                h2n->hpack_pos = 0;
                                h2n->huff_pad = 0;
                                h2n->zero_huff_padding = 0;
@@ -1142,7 +1186,7 @@ pre_data:
                                h2n->hpack_hdr_len++;
                                if (h2n->is_first_header_char) {
                                        h2n->is_first_header_char = 0;
-                                       h2n->first_hdr_char = c1;
+                                       h2n->first_hdr_char = (char)c1;
                                }
                                lwsl_header("parser: %c\n", c1);
                                /* uppercase header names illegal */
@@ -1177,7 +1221,7 @@ swallow:
                                      "Huffman padding excessive or wrong");
                        return 1;
                }
-
+fin:
                if (!h2n->value && (
                    h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
                    h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
@@ -1200,13 +1244,11 @@ swallow:
 #endif
                            ah->parser_state == WSI_TOKEN_SKIPPING) {
                                h2n->unknown_header = 1;
-                               ah->parser_state = -1;
+                               ah->parser_state = 0xff;
                                wsi->seen_nonpseudoheader = 1;
                        }
                }
 
-               n = 8;
-
                /* we have the header */
                if (!h2n->value) {
                        h2n->value = 1;
@@ -1229,8 +1271,15 @@ swallow:
                /* NEW indexed hdr with value */
                case HPKT_INDEXED_HDR_6_VALUE_INCR:
                        /* header length is determined by known index */
-                       m = lws_token_from_index(wsi, h2n->hdr_idx, NULL, NULL,
+                       m = lws_token_from_index(wsi, (int)h2n->hdr_idx, NULL, NULL,
                                        &h2n->hpack_hdr_len);
+                       if (m < 0)
+                               /*
+                                * The peer may only send known 6-bit indexes,
+                                * there's still the possibility it sends an unset
+                                * dynamic index that we can't succeed to look up
+                                */
+                               return 1;
                        goto add_it;
                /* NEW literal hdr with value */
                case HPKT_LITERAL_HDR_VALUE_INCR:
@@ -1262,7 +1311,7 @@ add_it:
                         */
                        ah->frags[ah->nfrag].flags |= 1;
 
-                       if (lws_dynamic_token_insert(wsi, h2n->hpack_hdr_len, m,
+                       if (lws_dynamic_token_insert(wsi, (int)h2n->hpack_hdr_len, m,
                                        &ah->data[ah->frags[ah->nfrag].offset],
                                        ah->frags[ah->nfrag].len)) {
                                lwsl_notice("%s: tok_insert fail\n", __func__);
@@ -1286,7 +1335,7 @@ add_it:
                                if (m == 255)
                                        m = -1;
                        } else
-                               m = lws_token_from_index(wsi, h2n->hdr_idx,
+                               m = lws_token_from_index(wsi, (int)h2n->hdr_idx,
                                                         NULL, NULL, NULL);
                }
 
@@ -1306,13 +1355,13 @@ add_it:
 
 
 
-static int
+static unsigned int
 lws_h2_num_start(int starting_bits, unsigned long num)
 {
-       unsigned int mask = (1 << starting_bits) - 1;
+       unsigned int mask = (unsigned int)((1 << starting_bits) - 1);
 
        if (num < mask)
-               return (int)num;
+               return (unsigned int)num;
 
        return mask;
 }
@@ -1321,7 +1370,7 @@ static int
 lws_h2_num(int starting_bits, unsigned long num,
                         unsigned char **p, unsigned char *end)
 {
-       unsigned int mask = (1 << starting_bits) - 1;
+       unsigned int mask = (unsigned int)((1 << starting_bits) - 1);
 
        if (num < mask)
                return 0;
@@ -1329,9 +1378,9 @@ lws_h2_num(int starting_bits, unsigned long num,
        num -= mask;
        do {
                if (num > 127)
-                       *((*p)++) = 0x80 | (num & 0x7f);
+                       *((*p)++) = (uint8_t)(0x80 | (num & 0x7f));
                else
-                       *((*p)++) = 0x00 | (num & 0x7f);
+                       *((*p)++) = (uint8_t)(0x00 | (num & 0x7f));
                if (*p >= end)
                        return 1;
                num >>= 7;
@@ -1346,15 +1395,27 @@ int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name,
 {
        int len;
 
-       lwsl_header("%s: %p  %s:%s\n", __func__, *p, name, value);
+#if defined(_DEBUG)
+       /* value does not have to be NUL-terminated... %.*s not available on
+        * all platforms */
+       if (value) {
+               lws_strnncpy((char *)*p, (const char *)value, length,
+                               lws_ptr_diff(end, (*p)));
+
+               lwsl_header("%s: %p  %s:%s (len %d)\n", __func__, *p, name,
+                               (const char *)*p, length);
+       } else {
+               lwsl_err("%s: %p dummy copy %s (len %d)\n", __func__, *p, name, length);
+       }
+#endif
 
        len = (int)strlen((char *)name);
        if (len)
                if (name[len - 1] == ':')
                        len--;
 
-       if (wsi->http2_substream && !strncmp((const char *)name,
-                                            "transfer-encoding", len)) {
+       if (wsi->mux_substream && !strncmp((const char *)name,
+                                            "transfer-encoding", (unsigned int)len)) {
                lwsl_header("rejecting %s\n", name);
 
                return 0;
@@ -1365,21 +1426,22 @@ int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name,
 
        *((*p)++) = 0; /* literal hdr, literal name,  */
 
-       *((*p)++) = 0 | lws_h2_num_start(7, len); /* non-HUF */
-       if (lws_h2_num(7, len, p, end))
+       *((*p)++) = (uint8_t)(0 | (uint8_t)lws_h2_num_start(7, (unsigned long)len)); /* non-HUF */
+       if (lws_h2_num(7, (unsigned long)len, p, end))
                return 1;
 
        /* upper-case header names are verboten in h2, but OK on h1, so
         * they're not illegal per se.  Silently convert them for h2... */
 
        while(len--)
-               *((*p)++) = tolower((int)*name++);
+               *((*p)++) = (uint8_t)tolower((int)*name++);
 
-       *((*p)++) = 0 | lws_h2_num_start(7, length); /* non-HUF */
-       if (lws_h2_num(7, length, p, end))
+       *((*p)++) = (uint8_t)(0 | (uint8_t)lws_h2_num_start(7, (unsigned long)length)); /* non-HUF */
+       if (lws_h2_num(7, (unsigned long)length, p, end))
                return 1;
 
-       memcpy(*p, value, length);
+       if (value)
+               memcpy(*p, value, (unsigned int)length);
        *p += length;
 
        return 0;
index 29cf079..a09b97f 100644 (file)
@@ -1,26 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /*
  * bitmap of control messages that are valid to receive for each http2 state
@@ -118,7 +120,7 @@ lws_h2_dump_settings(struct http2_settings *set)
 }
 #endif
 
-static struct lws_h2_protocol_send *
+struct lws_h2_protocol_send *
 lws_h2_new_pps(enum lws_h2_protocol_send_type type)
 {
        struct lws_h2_protocol_send *pps = lws_malloc(sizeof(*pps), "pps");
@@ -131,7 +133,8 @@ lws_h2_new_pps(enum lws_h2_protocol_send_type type)
 
 void lws_h2_init(struct lws *wsi)
 {
-       wsi->h2.h2n->set = wsi->vhost->h2.set;
+       wsi->h2.h2n->our_set = wsi->a.vhost->h2.set;
+       wsi->h2.h2n->peer_set = lws_h2_defaults;
 }
 
 void
@@ -139,7 +142,7 @@ lws_h2_state(struct lws *wsi, enum lws_h2_states s)
 {
        if (!wsi)
                return;
-       lwsl_info("%s: wsi %p: state %s -> %s\n", __func__, wsi,
+       lwsl_info("%s: %s: state %s -> %s\n", __func__, lws_wsi_tag(wsi),
                        h2_state_names[wsi->h2.h2_state],
                        h2_state_names[s]);
                
@@ -147,13 +150,81 @@ lws_h2_state(struct lws *wsi, enum lws_h2_states s)
        wsi->h2.h2_state = (uint8_t)s;
 }
 
-struct lws *
-lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
-                           unsigned int sid)
+int
+lws_h2_update_peer_txcredit(struct lws *wsi, unsigned int sid, int bump)
+{
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+       struct lws_h2_protocol_send *pps;
+
+       assert(wsi);
+
+       if (!bump)
+               return 0;
+
+       if (sid == (unsigned int)-1)
+               sid = wsi->mux.my_sid;
+
+       lwsl_info("%s: sid %d: bump %d -> %d\n", __func__, sid, bump,
+                       (int)wsi->txc.peer_tx_cr_est + bump);
+
+       pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
+       if (!pps)
+               return 1;
+
+       pps->u.update_window.sid = (unsigned int)sid;
+       pps->u.update_window.credit = (unsigned int)bump;
+       wsi->txc.peer_tx_cr_est += bump;
+
+       lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
+
+       lws_pps_schedule(wsi, pps);
+
+       pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
+       if (!pps)
+               return 1;
+
+       pps->u.update_window.sid = 0;
+       pps->u.update_window.credit = (unsigned int)bump;
+       nwsi->txc.peer_tx_cr_est += bump;
+
+       lws_wsi_txc_describe(&nwsi->txc, __func__, nwsi->mux.my_sid);
+
+       lws_pps_schedule(nwsi, pps);
+
+       return 0;
+}
+
+int
+lws_h2_get_peer_txcredit_estimate(struct lws *wsi)
+{
+       lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
+       return (int)wsi->txc.peer_tx_cr_est;
+}
+
+static int
+lws_h2_update_peer_txcredit_thresh(struct lws *wsi, unsigned int sid, int threshold, int bump)
+{
+       if (wsi->txc.peer_tx_cr_est > threshold)
+               return 0;
+
+       return lws_h2_update_peer_txcredit(wsi, sid, bump);
+}
+
+/* cx + vh lock */
+
+static struct lws *
+__lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
+                    unsigned int sid)
 {
-       struct lws *wsi;
        struct lws *nwsi = lws_get_network_wsi(parent_wsi);
        struct lws_h2_netconn *h2n = nwsi->h2.h2n;
+       char tmp[50], tmp1[50];
+       unsigned int n, b = 0;
+       struct lws *wsi;
+       const char *p;
+
+       lws_context_assert_lock_held(vh->context);
+       lws_vhost_assert_lock_held(vh);
 
        /*
         * The identifier of a newly established stream MUST be numerically
@@ -164,68 +235,88 @@ lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
         * connection error (Section 5.4.1) of type PROTOCOL_ERROR.
         */
        if (sid <= h2n->highest_sid_opened) {
-               lwsl_info("%s: tried to open lower sid %d\n", __func__, sid);
+               lwsl_info("%s: tried to open lower sid %d (%d)\n", __func__,
+                               sid, (int)h2n->highest_sid_opened);
                lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, "Bad sid");
                return NULL;
        }
 
        /* no more children allowed by parent */
-       if (parent_wsi->h2.child_count + 1 >
-           parent_wsi->h2.h2n->set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
+       if (parent_wsi->mux.child_count + 1 >
+           parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
                lwsl_notice("reached concurrent stream limit\n");
                return NULL;
        }
-       wsi = lws_create_new_server_wsi(vh, parent_wsi->tsi);
+
+       n = 0;
+       p = &parent_wsi->lc.gutag[1];
+       do {
+               if (*p == '|') {
+                       b++;
+                       if (b == 3)
+                               continue;
+               }
+               tmp1[n++] = *p++;
+       } while (b < 3 && n < sizeof(tmp1) - 2);
+       tmp1[n] = '\0';
+       lws_snprintf(tmp, sizeof(tmp), "h2_sid%u_(%s)", sid, tmp1);
+       wsi = lws_create_new_server_wsi(vh, parent_wsi->tsi, tmp);
        if (!wsi) {
-               lwsl_notice("new server wsi failed (vh %p)\n", vh);
+               lwsl_notice("new server wsi failed (%s)\n", lws_vh_tag(vh));
                return NULL;
        }
 
+#if defined(LWS_WITH_SERVER)
+       if (lwsi_role_server(parent_wsi)) {
+               lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mth_srv);
+       }
+#endif
+
        h2n->highest_sid_opened = sid;
-       wsi->h2.my_sid = sid;
-       wsi->http2_substream = 1;
-       wsi->seen_nonpseudoheader = 0;
 
-       wsi->h2.parent_wsi = parent_wsi;
-       wsi->role_ops = parent_wsi->role_ops;
-       /* new guy's sibling is whoever was the first child before */
-       wsi->h2.sibling_list = parent_wsi->h2.child_list;
-       /* first child is now the new guy */
-       parent_wsi->h2.child_list = wsi;
-       parent_wsi->h2.child_count++;
+       lws_wsi_mux_insert(wsi, parent_wsi, sid);
+       if (sid >= h2n->highest_sid)
+               h2n->highest_sid = sid + 2;
+
+       wsi->mux_substream = 1;
+       wsi->seen_nonpseudoheader = 0;
 
-       wsi->h2.my_priority = 16;
-       wsi->h2.tx_cr = nwsi->h2.h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
-       wsi->h2.peer_tx_cr_est =
-                       nwsi->vhost->h2.set.s[H2SET_INITIAL_WINDOW_SIZE];
+       wsi->txc.tx_cr = (int32_t)nwsi->h2.h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
+       wsi->txc.peer_tx_cr_est =
+                       (int32_t)nwsi->h2.h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE];
 
        lwsi_set_state(wsi, LRS_ESTABLISHED);
        lwsi_set_role(wsi, lwsi_role(parent_wsi));
 
-       wsi->protocol = &vh->protocols[0];
+       wsi->a.protocol = &vh->protocols[0];
        if (lws_ensure_user_space(wsi))
                goto bail1;
 
-       wsi->vhost->conn_stats.h2_subs++;
+#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
+       if (lws_adopt_ss_server_accept(wsi))
+               goto bail1;
+#endif
+
+       /* get the ball rolling */
+       lws_validity_confirmed(wsi);
 
-       lwsl_info("%s: %p new ch %p, sid %d, usersp=%p, tx cr %d, "
-                 "peer_credit %d (nwsi tx_cr %d)\n",
-                 __func__, parent_wsi, wsi, sid, wsi->user_space,
-                 wsi->h2.tx_cr, wsi->h2.peer_tx_cr_est, nwsi->h2.tx_cr);
+       lwsl_info("%s: %s new ch %s, sid %d, usersp=%p\n", __func__,
+                 lws_wsi_tag(parent_wsi), lws_wsi_tag(wsi), sid, wsi->user_space);
+
+       lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
+       lws_wsi_txc_describe(&nwsi->txc, __func__, 0);
 
        return wsi;
 
 bail1:
        /* undo the insert */
-       parent_wsi->h2.child_list = wsi->h2.sibling_list;
-       parent_wsi->h2.child_count--;
-
-       vh->context->count_wsi_allocated--;
+       parent_wsi->mux.child_list = wsi->mux.sibling_list;
+       parent_wsi->mux.child_count--;
 
        if (wsi->user_space)
                lws_free_set_NULL(wsi->user_space);
        vh->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
-       lws_vhost_unbind_wsi(wsi);
+       __lws_vhost_unbind_wsi(wsi);
        lws_free(wsi);
 
        return NULL;
@@ -237,8 +328,8 @@ lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi)
        struct lws *nwsi = lws_get_network_wsi(parent_wsi);
 
        /* no more children allowed by parent */
-       if (parent_wsi->h2.child_count + 1 >
-           parent_wsi->h2.h2n->set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
+       if (parent_wsi->mux.child_count + 1 >
+           parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
                lwsl_notice("reached concurrent stream limit\n");
                return NULL;
        }
@@ -246,22 +337,29 @@ lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi)
        /* sid is set just before issuing the headers, ensuring monoticity */
 
        wsi->seen_nonpseudoheader = 0;
-#if !defined(LWS_NO_CLIENT)
-       wsi->client_h2_substream = 1;
+#if defined(LWS_WITH_CLIENT)
+       wsi->client_mux_substream = 1;
 #endif
        wsi->h2.initialized = 1;
 
-       wsi->h2.parent_wsi = parent_wsi;
-       /* new guy's sibling is whoever was the first child before */
-       wsi->h2.sibling_list = parent_wsi->h2.child_list;
-       /* first child is now the new guy */
-       parent_wsi->h2.child_list = wsi;
-       parent_wsi->h2.child_count++;
+#if 0
+       /* only assign sid at header send time when we know it */
+       if (!wsi->mux.my_sid) {
+               wsi->mux.my_sid = nwsi->h2.h2n->highest_sid;
+               nwsi->h2.h2n->highest_sid += 2;
+       }
+#endif
+
+       lwsl_info("%s: binding wsi %s to sid %d (next %d)\n", __func__,
+               lws_wsi_tag(wsi), (int)wsi->mux.my_sid, (int)nwsi->h2.h2n->highest_sid);
 
-       wsi->h2.my_priority = 16;
-       wsi->h2.tx_cr = nwsi->h2.h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
-       wsi->h2.peer_tx_cr_est =
-                       nwsi->vhost->h2.set.s[H2SET_INITIAL_WINDOW_SIZE];
+       lws_wsi_mux_insert(wsi, parent_wsi, wsi->mux.my_sid);
+
+       wsi->txc.tx_cr = (int32_t)nwsi->h2.h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
+       wsi->txc.peer_tx_cr_est = (int32_t)
+                       nwsi->h2.h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE];
+
+       lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid);
 
        if (lws_ensure_user_space(wsi))
                goto bail1;
@@ -271,38 +369,49 @@ lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi)
 
        lws_callback_on_writable(wsi);
 
-       wsi->vhost->conn_stats.h2_subs++;
-
        return wsi;
 
 bail1:
        /* undo the insert */
-       parent_wsi->h2.child_list = wsi->h2.sibling_list;
-       parent_wsi->h2.child_count--;
+       parent_wsi->mux.child_list = wsi->mux.sibling_list;
+       parent_wsi->mux.child_count--;
 
        if (wsi->user_space)
                lws_free_set_NULL(wsi->user_space);
-       wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
+       wsi->a.protocol->callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
        lws_free(wsi);
 
        return NULL;
 }
 
 
-int lws_h2_issue_preface(struct lws *wsi)
+int
+lws_h2_issue_preface(struct lws *wsi)
 {
        struct lws_h2_netconn *h2n = wsi->h2.h2n;
        struct lws_h2_protocol_send *pps;
 
+       if (!h2n) {
+               lwsl_warn("%s: no valid h2n\n", __func__);
+               return 1;
+       }
+
+       if (h2n->sent_preface)
+               return 1;
+
+       lwsl_debug("%s: %s: fd %d\n", __func__, lws_wsi_tag(wsi), (int)wsi->desc.sockfd);
+
        if (lws_issue_raw(wsi, (uint8_t *)preface, strlen(preface)) !=
                (int)strlen(preface))
                return 1;
 
+       h2n->sent_preface = 1;
+
        lws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS,
                            &role_ops_h2);
 
        h2n->count = 0;
-       wsi->h2.tx_cr = 65535;
+       wsi->txc.tx_cr = 65535;
 
        /*
         * we must send a settings frame
@@ -316,32 +425,6 @@ int lws_h2_issue_preface(struct lws *wsi)
        return 0;
 }
 
-struct lws *
-lws_h2_wsi_from_id(struct lws *parent_wsi, unsigned int sid)
-{
-       lws_start_foreach_ll(struct lws *, wsi, parent_wsi->h2.child_list) {
-               if (wsi->h2.my_sid == sid)
-                       return wsi;
-       } lws_end_foreach_ll(wsi, h2.sibling_list);
-
-       return NULL;
-}
-
-int lws_remove_server_child_wsi(struct lws_context *context, struct lws *wsi)
-{
-       lws_start_foreach_llp(struct lws **, w, wsi->h2.child_list) {
-               if (*w == wsi) {
-                       *w = wsi->h2.sibling_list;
-                       (wsi->h2.parent_wsi)->h2.child_count--;
-                       return 0;
-               }
-       } lws_end_foreach_llp(w, h2.sibling_list);
-
-       lwsl_err("%s: can't find %p\n", __func__, wsi);
-
-       return 1;
-}
-
 void
 lws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pps)
 {
@@ -368,7 +451,7 @@ lws_h2_goaway(struct lws *wsi, uint32_t err, const char *reason)
        if (!pps)
                return 1;
 
-       lwsl_info("%s: %p: ERR 0x%x, '%s'\n", __func__, wsi, err, reason);
+       lwsl_info("%s: %s: ERR 0x%x, '%s'\n", __func__, lws_wsi_tag(wsi), (int)err, reason);
 
        pps->u.ga.err = err;
        pps->u.ga.highest_sid = h2n->highest_sid;
@@ -397,10 +480,10 @@ lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason)
        if (!pps)
                return 1;
 
-       lwsl_info("%s: RST_STREAM 0x%x, sid %d, REASON '%s'\n", __func__, err,
-                       wsi->h2.my_sid, reason);
+       lwsl_info("%s: RST_STREAM 0x%x, sid %d, REASON '%s'\n", __func__,
+                 (int)err, wsi->mux.my_sid, reason);
 
-       pps->u.rs.sid = wsi->h2.my_sid;
+       pps->u.rs.sid = wsi->mux.my_sid;
        pps->u.rs.err = err;
 
        lws_pps_schedule(wsi, pps);
@@ -413,7 +496,7 @@ lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason)
 
 int
 lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
-                       unsigned char *buf, int len)
+               unsigned char *buf, int len)
 {
        struct lws *nwsi = lws_get_network_wsi(wsi);
        unsigned int a, b;
@@ -425,10 +508,10 @@ lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
                return 1;
 
        while (len >= LWS_H2_SETTINGS_LEN) {
-               a = (buf[0] << 8) | buf[1];
+               a = (unsigned int)((buf[0] << 8) | buf[1]);
                if (!a || a >= H2SET_COUNT)
                        goto skip;
-               b = buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5];
+               b = (unsigned int)(buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5]);
 
                switch (a) {
                case H2SET_HEADER_TABLE_SIZE:
@@ -449,14 +532,17 @@ lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
                                return 1;
                        }
 
+#if defined(LWS_WITH_CLIENT)
 #if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
-                       //FIXME: Workaround for FIRMWARE-4632 until cloud-side issue is fixed.
-                       if (b == 0x7fffffff) {
-                               b = 65535;
-                               lwsl_info("init window size 0x7fffffff\n");
+                       if (
+#else
+                       if (wsi->flags & LCCSCF_H2_QUIRK_OVERFLOWS_TXCR &&
+#endif
+                           b == 0x7fffffff) {
+                               b >>= 4;
+
                                break;
                        }
-                       //FIXME: end of FIRMWARE-4632 workaround
 #endif
 
                        /*
@@ -473,21 +559,23 @@ lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
                         */
 
                        lws_start_foreach_ll(struct lws *, w,
-                                            nwsi->h2.child_list) {
+                                            nwsi->mux.child_list) {
                                lwsl_info("%s: adi child tc cr %d +%d -> %d",
-                                           __func__,
-                                           w->h2.tx_cr, b - settings->s[a],
-                                           w->h2.tx_cr + b - settings->s[a]);
-                               w->h2.tx_cr += b - settings->s[a];
-                               if (w->h2.tx_cr > 0 &&
-                                   w->h2.tx_cr <=
+                                         __func__, (int)w->txc.tx_cr,
+                                         b - (unsigned int)settings->s[a],
+                                         (int)(w->txc.tx_cr + (int)b -
+                                                 (int)settings->s[a]));
+                               w->txc.tx_cr += (int)b - (int)settings->s[a];
+                               if (w->txc.tx_cr > 0 &&
+                                   w->txc.tx_cr <=
                                                  (int32_t)(b - settings->s[a]))
+
                                        lws_callback_on_writable(w);
-                       } lws_end_foreach_ll(w, h2.sibling_list);
+                       } lws_end_foreach_ll(w, mux.sibling_list);
 
                        break;
                case H2SET_MAX_FRAME_SIZE:
-                       if (b < wsi->vhost->h2.set.s[H2SET_MAX_FRAME_SIZE]) {
+                       if (b < wsi->a.vhost->h2.set.s[H2SET_MAX_FRAME_SIZE]) {
                                lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
                                              "Frame size < initial");
                                return 1;
@@ -537,19 +625,17 @@ skip:
 int
 lws_h2_tx_cr_get(struct lws *wsi)
 {
-       int c = wsi->h2.tx_cr;
-       struct lws *nwsi;
+       int c = wsi->txc.tx_cr;
+       struct lws *nwsi = lws_get_network_wsi(wsi);
 
-       if (!wsi->http2_substream && !wsi->upgraded_to_http2)
+       if (!wsi->mux_substream && !nwsi->upgraded_to_http2)
                return ~0x80000000;
 
-       nwsi = lws_get_network_wsi(wsi);
+       lwsl_info ("%s: %s: own tx credit %d: nwsi credit %d\n",
+                    __func__, lws_wsi_tag(wsi), c, (int)nwsi->txc.tx_cr);
 
-       lwsl_info ("%s: %p: own tx credit %d: nwsi credit %d\n",
-                    __func__, wsi, c, nwsi->h2.tx_cr);
-
-       if (nwsi->h2.tx_cr < c)
-               c = nwsi->h2.tx_cr;
+       if (nwsi->txc.tx_cr < c)
+               c = nwsi->txc.tx_cr;
 
        if (c < 0)
                return 0;
@@ -562,10 +648,10 @@ lws_h2_tx_cr_consume(struct lws *wsi, int consumed)
 {
        struct lws *nwsi = lws_get_network_wsi(wsi);
 
-       wsi->h2.tx_cr -= consumed;
+       wsi->txc.tx_cr -= consumed;
 
        if (nwsi != wsi)
-               nwsi->h2.tx_cr -= consumed;
+               nwsi->txc.tx_cr -= consumed;
 }
 
 int lws_h2_frame_write(struct lws *wsi, int type, int flags,
@@ -578,26 +664,28 @@ int lws_h2_frame_write(struct lws *wsi, int type, int flags,
        //if (wsi->h2_stream_carries_ws)
        // lwsl_hexdump_level(LLL_NOTICE, buf, len);
 
-       *p++ = len >> 16;
-       *p++ = len >> 8;
-       *p++ = len;
-       *p++ = type;
-       *p++ = flags;
-       *p++ = sid >> 24;
-       *p++ = sid >> 16;
-       *p++ = sid >> 8;
-       *p++ = sid;
-
-       lwsl_debug("%s: %p (eff %p). typ %d, fl 0x%x, sid=%d, len=%d, "
-                  "txcr=%d, nwsi->txcr=%d\n", __func__, wsi, nwsi, type, flags,
-                  sid, len, wsi->h2.tx_cr, nwsi->h2.tx_cr);
+       *p++ = (uint8_t)(len >> 16);
+       *p++ = (uint8_t)(len >> 8);
+       *p++ = (uint8_t)len;
+       *p++ = (uint8_t)type;
+       *p++ = (uint8_t)flags;
+       *p++ = (uint8_t)(sid >> 24);
+       *p++ = (uint8_t)(sid >> 16);
+       *p++ = (uint8_t)(sid >> 8);
+       *p++ = (uint8_t)sid;
+
+       lwsl_debug("%s: %s (eff %s). typ %d, fl 0x%x, sid=%d, len=%d, "
+                  "txcr=%d, nwsi->txcr=%d\n", __func__, lws_wsi_tag(wsi),
+                  lws_wsi_tag(nwsi), type, flags,
+                  sid, len, (int)wsi->txc.tx_cr, (int)nwsi->txc.tx_cr);
 
        if (type == LWS_H2_FRAME_TYPE_DATA) {
-               if (wsi->h2.tx_cr < (int)len)
-                       lwsl_err("%s: %p: sending payload len %d"
-                                " but tx_cr only %d!\n", __func__, wsi,
-                                len, wsi->h2.tx_cr);
-               lws_h2_tx_cr_consume(wsi, len);
+               if (wsi->txc.tx_cr < (int)len)
+
+                       lwsl_info("%s: %s: sending payload len %d"
+                                " but tx_cr only %d!\n", __func__,
+                                lws_wsi_tag(wsi), len, (int)wsi->txc.tx_cr);
+                               lws_h2_tx_cr_consume(wsi, (int)len);
        }
 
        n = lws_issue_raw(nwsi, &buf[-LWS_H2_FRAME_HEADER_LENGTH],
@@ -613,12 +701,12 @@ int lws_h2_frame_write(struct lws *wsi, int type, int flags,
 
 static void lws_h2_set_bin(struct lws *wsi, int n, unsigned char *buf)
 {
-       *buf++ = n >> 8;
-       *buf++ = n;
-       *buf++ = wsi->h2.h2n->set.s[n] >> 24;
-       *buf++ = wsi->h2.h2n->set.s[n] >> 16;
-       *buf++ = wsi->h2.h2n->set.s[n] >> 8;
-       *buf = wsi->h2.h2n->set.s[n];
+       *buf++ = (uint8_t)(n >> 8);
+       *buf++ = (uint8_t)n;
+       *buf++ = (uint8_t)(wsi->h2.h2n->our_set.s[n] >> 24);
+       *buf++ = (uint8_t)(wsi->h2.h2n->our_set.s[n] >> 16);
+       *buf++ = (uint8_t)(wsi->h2.h2n->our_set.s[n] >> 8);
+       *buf = (uint8_t)wsi->h2.h2n->our_set.s[n];
 }
 
 /* we get called on the network connection */
@@ -647,7 +735,7 @@ int lws_h2_do_pps_send(struct lws *wsi)
        if (!pps)
                return 1;
 
-       lwsl_info("%s: %p: %d\n", __func__, wsi, pps->type);
+       lwsl_info("%s: %s: %d\n", __func__, lws_wsi_tag(wsi), pps->type);
 
        switch (pps->type) {
 
@@ -658,14 +746,16 @@ int lws_h2_do_pps_send(struct lws *wsi)
                 * then we must inform the peer
                 */
                for (n = 1; n < H2SET_COUNT; n++)
-                       if (h2n->set.s[n] != lws_h2_defaults.s[n]) {
+                       if (h2n->our_set.s[n] != lws_h2_defaults.s[n]) {
                                lwsl_debug("sending SETTING %d 0x%x\n", n,
-                                               wsi->h2.h2n->set.s[n]);
+                                          (unsigned int)
+                                                  wsi->h2.h2n->our_set.s[n]);
+
                                lws_h2_set_bin(wsi, n, &set[LWS_PRE + m]);
-                               m += sizeof(h2n->one_setting);
+                               m += (int)sizeof(h2n->one_setting);
                        }
                n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,
-                                      flags, LWS_H2_STREAM_ID_MASTER, m,
+                                      flags, LWS_H2_STREAM_ID_MASTER, (unsigned int)m,
                                       &set[LWS_PRE]);
                if (n != m) {
                        lwsl_info("send %d %d\n", n, m);
@@ -673,26 +763,63 @@ int lws_h2_do_pps_send(struct lws *wsi)
                }
                break;
 
+       case LWS_H2_PPS_SETTINGS_INITIAL_UPDATE_WINDOW:
+               q = &set[LWS_PRE];
+               *q++ = (uint8_t)(H2SET_INITIAL_WINDOW_SIZE >> 8);
+               *q++ = (uint8_t)(H2SET_INITIAL_WINDOW_SIZE);
+               *q++ = (uint8_t)(pps->u.update_window.credit >> 24);
+               *q++ = (uint8_t)(pps->u.update_window.credit >> 16);
+               *q++ = (uint8_t)(pps->u.update_window.credit >> 8);
+               *q = (uint8_t)(pps->u.update_window.credit);
+
+               lwsl_debug("%s: resetting initial window to %d\n", __func__,
+                               (int)pps->u.update_window.credit);
+
+               n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,
+                                      flags, LWS_H2_STREAM_ID_MASTER, 6,
+                                      &set[LWS_PRE]);
+               if (n != 6) {
+                       lwsl_info("send %d %d\n", n, m);
+                       goto bail;
+               }
+               break;
+
        case LWS_H2_PPS_ACK_SETTINGS:
                /* send ack ... always empty */
                n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS, 1,
                                       LWS_H2_STREAM_ID_MASTER, 0,
                                       &set[LWS_PRE]);
                if (n) {
-                       lwsl_err("ack tells %d\n", n);
+                       lwsl_err("%s: writing settings ack frame failed %d\n", __func__, n);
                        goto bail;
                }
+               wsi->h2_acked_settings = 0;
                /* this is the end of the preface dance then? */
                if (lwsi_state(wsi) == LRS_H2_AWAIT_SETTINGS) {
                        lwsi_set_state(wsi, LRS_ESTABLISHED);
+#if defined(LWS_WITH_FILE_OPS)
                        wsi->http.fop_fd = NULL;
+#endif
                        if (lws_is_ssl(lws_get_network_wsi(wsi)))
                                break;
+
+                       if (wsi->a.vhost->options &
+                               LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE)
+                               break;
+
                        /*
                         * we need to treat the headers from the upgrade as the
                         * first job.  So these need to get shifted to sid 1.
                         */
-                       h2n->swsi = lws_wsi_server_new(wsi->vhost, wsi, 1);
+
+                       lws_context_lock(wsi->a.context, "h2 mig");
+                       lws_vhost_lock(wsi->a.vhost);
+
+                       h2n->swsi = __lws_wsi_server_new(wsi->a.vhost, wsi, 1);
+
+                       lws_vhost_unlock(wsi->a.vhost);
+                       lws_context_unlock(wsi->a.context);
+
                        if (!h2n->swsi)
                                goto bail;
 
@@ -702,46 +829,56 @@ int lws_h2_do_pps_send(struct lws *wsi)
 
                        lwsl_info("%s: inherited headers %p\n", __func__,
                                  h2n->swsi->http.ah);
-                       h2n->swsi->h2.tx_cr =
-                               h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
-                       lwsl_info("initial tx credit on conn %p: %d\n",
-                                 h2n->swsi, h2n->swsi->h2.tx_cr);
+                       h2n->swsi->txc.tx_cr = (int32_t)
+                               h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE];
+                       lwsl_info("initial tx credit on %s: %d\n",
+                                 lws_wsi_tag(h2n->swsi),
+                                 (int)h2n->swsi->txc.tx_cr);
                        h2n->swsi->h2.initialized = 1;
                        /* demanded by HTTP2 */
                        h2n->swsi->h2.END_STREAM = 1;
                        lwsl_info("servicing initial http request\n");
 
-                       wsi->vhost->conn_stats.h2_trans++;
-
+#if defined(LWS_WITH_SERVER)
                        if (lws_http_action(h2n->swsi))
                                goto bail;
-
+#endif
                        break;
                }
                break;
+
+       /*
+        * h2 only has PING... ACK = 0 = ping, ACK = 1 = pong
+        */
+
+       case LWS_H2_PPS_PING:
        case LWS_H2_PPS_PONG:
-               lwsl_debug("sending PONG\n");
+               if (pps->type == LWS_H2_PPS_PING)
+                       lwsl_info("sending PING\n");
+               else {
+                       lwsl_info("sending PONG\n");
+                       flags = LWS_H2_FLAG_SETTINGS_ACK;
+               }
+
                memcpy(&set[LWS_PRE], pps->u.ping.ping_payload, 8);
-               n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING,
-                                      LWS_H2_FLAG_SETTINGS_ACK,
+               n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING, flags,
                                       LWS_H2_STREAM_ID_MASTER, 8,
                                       &set[LWS_PRE]);
-               if (n != 8) {
-                       lwsl_info("send %d %d\n", n, m);
+               if (n != 8)
                        goto bail;
-               }
+
                break;
 
        case LWS_H2_PPS_GOAWAY:
                lwsl_info("LWS_H2_PPS_GOAWAY\n");
-               *p++ = pps->u.ga.highest_sid >> 24;
-               *p++ = pps->u.ga.highest_sid >> 16;
-               *p++ = pps->u.ga.highest_sid >> 8;
-               *p++ = pps->u.ga.highest_sid;
-               *p++ = pps->u.ga.err >> 24;
-               *p++ = pps->u.ga.err >> 16;
-               *p++ = pps->u.ga.err >> 8;
-               *p++ = pps->u.ga.err;
+               *p++ = (uint8_t)(pps->u.ga.highest_sid >> 24);
+               *p++ = (uint8_t)(pps->u.ga.highest_sid >> 16);
+               *p++ = (uint8_t)(pps->u.ga.highest_sid >> 8);
+               *p++ = (uint8_t)(pps->u.ga.highest_sid);
+               *p++ = (uint8_t)(pps->u.ga.err >> 24);
+               *p++ = (uint8_t)(pps->u.ga.err >> 16);
+               *p++ = (uint8_t)(pps->u.ga.err >> 8);
+               *p++ = (uint8_t)(pps->u.ga.err);
                q = (unsigned char *)pps->u.ga.str;
                n = 0;
                while (*q && n++ < (int)sizeof(pps->u.ga.str))
@@ -749,7 +886,7 @@ int lws_h2_do_pps_send(struct lws *wsi)
                h2n->we_told_goaway = 1;
                n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_GOAWAY, 0,
                                       LWS_H2_STREAM_ID_MASTER,
-                                      lws_ptr_diff(p, &set[LWS_PRE]),
+                                      (unsigned int)lws_ptr_diff(p, &set[LWS_PRE]),
                                       &set[LWS_PRE]);
                if (n != 4) {
                        lwsl_info("send %d %d\n", n, m);
@@ -759,33 +896,34 @@ int lws_h2_do_pps_send(struct lws *wsi)
 
        case LWS_H2_PPS_RST_STREAM:
                lwsl_info("LWS_H2_PPS_RST_STREAM\n");
-               *p++ = pps->u.rs.err >> 24;
-               *p++ = pps->u.rs.err >> 16;
-               *p++ = pps->u.rs.err >> 8;
-               *p++ = pps->u.rs.err;
+               *p++ = (uint8_t)(pps->u.rs.err >> 24);
+               *p++ = (uint8_t)(pps->u.rs.err >> 16);
+               *p++ = (uint8_t)(pps->u.rs.err >> 8);
+               *p++ = (uint8_t)(pps->u.rs.err);
                n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_RST_STREAM,
                                       0, pps->u.rs.sid, 4, &set[LWS_PRE]);
                if (n != 4) {
                        lwsl_info("send %d %d\n", n, m);
                        goto bail;
                }
-               cwsi = lws_h2_wsi_from_id(wsi, pps->u.rs.sid);
+               cwsi = lws_wsi_mux_from_id(wsi, pps->u.rs.sid);
                if (cwsi) {
-                       lwsl_debug("%s: closing cwsi %p %s %s (wsi %p)\n",
-                                  __func__, cwsi, cwsi->role_ops->name,
-                                  cwsi->protocol->name, wsi);
+                       lwsl_debug("%s: closing cwsi %s %s %s (wsi %s)\n",
+                                  __func__, lws_wsi_tag(cwsi),
+                                  cwsi->role_ops->name,
+                                  cwsi->a.protocol->name, lws_wsi_tag(wsi));
                        lws_close_free_wsi(cwsi, 0, "reset stream");
                }
                break;
 
        case LWS_H2_PPS_UPDATE_WINDOW:
-               lwsl_debug("Issuing LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n",
-                           pps->u.update_window.sid,
-                           pps->u.update_window.credit);
-               *p++ = pps->u.update_window.credit >> 24;
-               *p++ = pps->u.update_window.credit >> 16;
-               *p++ = pps->u.update_window.credit >> 8;
-               *p++ = pps->u.update_window.credit;
+               lwsl_info("Issuing LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n",
+                           (int)pps->u.update_window.sid,
+                           (int)pps->u.update_window.credit);
+               *p++ = (uint8_t)((pps->u.update_window.credit >> 24) & 0x7f); /* 31b */
+               *p++ = (uint8_t)(pps->u.update_window.credit >> 16);
+               *p++ = (uint8_t)(pps->u.update_window.credit >> 8);
+               *p++ = (uint8_t)(pps->u.update_window.credit);
                n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_WINDOW_UPDATE,
                                       0, pps->u.update_window.sid, 4,
                                       &set[LWS_PRE]);
@@ -809,6 +947,9 @@ bail:
        return 1;
 }
 
+static int
+lws_h2_parse_end_of_frame(struct lws *wsi);
+
 /*
  * The frame header part has just completely arrived.
  * Perform actions for header completion.
@@ -829,7 +970,9 @@ lws_h2_parse_frame_header(struct lws *wsi)
        h2n->sid = h2n->sid & 0x7fffffff;
 
        if (h2n->sid && !(h2n->sid & 1)) {
-               lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "Even Stream ID");
+               char pes[32];
+               lws_snprintf(pes, sizeof(pes), "Even Stream ID 0x%x", (unsigned int)h2n->sid);
+               lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, pes);
 
                return 0;
        }
@@ -837,55 +980,68 @@ lws_h2_parse_frame_header(struct lws *wsi)
        /* let the network wsi live a bit longer if subs are active */
 
        if (!wsi->immortal_substream_count)
-#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
-               lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, wsi->vhost->keepalive_timeout);
-#else
-               lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
-#endif
+               lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
+                               wsi->a.vhost->keepalive_timeout ?
+                                       wsi->a.vhost->keepalive_timeout : 31);
 
        if (h2n->sid)
-               h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid);
+               h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid);
 
-       lwsl_debug("%p (%p): fr hdr: typ 0x%x, fla 0x%x, sid 0x%x, len 0x%x\n",
-                 wsi, h2n->swsi, h2n->type, h2n->flags, h2n->sid,
-                 h2n->length);
+       lwsl_debug("%s (%s): fr hdr: typ 0x%x, fla 0x%x, sid 0x%x, len 0x%x\n",
+                 lws_wsi_tag(wsi), lws_wsi_tag(h2n->swsi), h2n->type,
+                 h2n->flags, (unsigned int)h2n->sid, (unsigned int)h2n->length);
 
        if (h2n->we_told_goaway && h2n->sid > h2n->highest_sid)
                h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
 
-       if (h2n->type == LWS_H2_FRAME_TYPE_COUNT)
-               return 0;
+       if (h2n->type >= LWS_H2_FRAME_TYPE_COUNT) {
+               lwsl_info("%s: ignoring unknown frame type %d (len %d)\n", __func__, h2n->type, (unsigned int)h2n->length);
+               /* we MUST ignore frames we don't understand */
+               h2n->type = LWS_H2_FRAME_TYPE_COUNT;
+       }
+
+       /*
+        * Even if we have decided to logically ignore this frame, we must
+        * consume the correct "frame length" amount of data to retain sync
+        */
 
-       if (h2n->length > h2n->set.s[H2SET_MAX_FRAME_SIZE]) {
+       if (h2n->length > h2n->our_set.s[H2SET_MAX_FRAME_SIZE]) {
                /*
                 * peer sent us something bigger than we told
                 * it we would allow
                 */
-               lwsl_info("received oversize frame %d\n", h2n->length);
+               lwsl_info("%s: received oversize frame %d\n", __func__,
+                         (unsigned int)h2n->length);
                lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
                              "Peer ignored our frame size setting");
                return 1;
        }
 
        if (h2n->swsi)
-               lwsl_info("%s: wsi %p, State: %s, received cmd %d\n",
-                 __func__, h2n->swsi,
+               lwsl_info("%s: %s, State: %s, received cmd %d\n",
+                 __func__, lws_wsi_tag(h2n->swsi),
                  h2_state_names[h2n->swsi->h2.h2_state], h2n->type);
        else {
                /* if it's data, either way no swsi means CLOSED state */
                if (h2n->type == LWS_H2_FRAME_TYPE_DATA) {
                        if (h2n->sid <= h2n->highest_sid_opened
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
                                        && wsi->client_h2_alpn
 #endif
                        ) {
-                               lwsl_notice("ignoring straggling data\n");
+                               lwsl_notice("ignoring straggling data fl 0x%x\n",
+                                               h2n->flags);
                                /* ie, IGNORE */
                                h2n->type = LWS_H2_FRAME_TYPE_COUNT;
                        } else {
+                               lwsl_info("%s: received %d bytes data for unknown sid %d, highest known %d\n",
+                                               __func__, (int)h2n->length, (int)h2n->sid, (int)h2n->highest_sid_opened);
+
+//                             if (h2n->sid > h2n->highest_sid_opened) {
                                lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
                                      "Data for nonexistent sid");
                                return 0;
+//                             }
                        }
                }
                /* if the sid is credible, treat as wsi for it closed */
@@ -893,18 +1049,18 @@ lws_h2_parse_frame_header(struct lws *wsi)
                    h2n->type != LWS_H2_FRAME_TYPE_HEADERS &&
                    h2n->type != LWS_H2_FRAME_TYPE_PRIORITY) {
                        /* if not credible, reject it */
-                       lwsl_info("%s: wsi %p, No child for sid %d, rxcmd %d\n",
-                         __func__, h2n->swsi, h2n->sid, h2n->type);
+                       lwsl_info("%s: %s, No child for sid %d, rxcmd %d\n",
+                         __func__, lws_wsi_tag(h2n->swsi), (unsigned int)h2n->sid, h2n->type);
                        lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
                                     "Data for nonexistent sid");
                        return 0;
                }
        }
 
-       if (h2n->swsi && h2n->sid &&
+       if (h2n->swsi && h2n->sid && h2n->type != LWS_H2_FRAME_TYPE_COUNT &&
            !(http2_rx_validity[h2n->swsi->h2.h2_state] & (1 << h2n->type))) {
-               lwsl_info("%s: wsi %p, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\n",
-                         __func__, h2n->swsi,
+               lwsl_info("%s: %s, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\n",
+                         __func__, lws_wsi_tag(h2n->swsi),
                          h2_state_names[h2n->swsi->h2.h2_state], h2n->type,
                          http2_rx_validity[h2n->swsi->h2.h2_state]);
 
@@ -913,21 +1069,23 @@ lws_h2_parse_frame_header(struct lws *wsi)
                        n = H2_ERR_STREAM_CLOSED;
                else
                        n = H2_ERR_PROTOCOL_ERROR;
-               lws_h2_goaway(wsi, n, "invalid rx for state");
+               lws_h2_goaway(wsi, (unsigned int)n, "invalid rx for state");
 
                return 0;
        }
 
-       if (h2n->cont_exp && (h2n->cont_exp_sid != h2n->sid ||
+       if (h2n->cont_exp && h2n->type != LWS_H2_FRAME_TYPE_COUNT &&
+           (h2n->cont_exp_sid != h2n->sid ||
                              h2n->type != LWS_H2_FRAME_TYPE_CONTINUATION)) {
-               lwsl_info("%s: expected cont on sid %d (got %d on sid %d)\n",
-                         __func__, h2n->cont_exp_sid, h2n->type, h2n->sid);
+               lwsl_info("%s: expected cont on sid %u (got %d on sid %u)\n",
+                         __func__, (unsigned int)h2n->cont_exp_sid, h2n->type,
+                         (unsigned int)h2n->sid);
                h2n->cont_exp = 0;
                if (h2n->cont_exp_headers)
                        n = H2_ERR_COMPRESSION_ERROR;
                else
                        n = H2_ERR_PROTOCOL_ERROR;
-               lws_h2_goaway(wsi, n, "Continuation hdrs State");
+               lws_h2_goaway(wsi, (unsigned int)n, "Continuation hdrs State");
 
                return 0;
        }
@@ -940,7 +1098,9 @@ lws_h2_parse_frame_header(struct lws *wsi)
                        lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "DATA 0 sid");
                        break;
                }
-               lwsl_info("Frame header DATA: sid %d\n", h2n->sid);
+               lwsl_info("Frame header DATA: sid %u, flags 0x%x, len %u\n",
+                               (unsigned int)h2n->sid, h2n->flags,
+                               (unsigned int)h2n->length);
 
                if (!h2n->swsi) {
                        lwsl_notice("DATA: NULL swsi\n");
@@ -955,7 +1115,12 @@ lws_h2_parse_frame_header(struct lws *wsi)
                        lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, "conn closed");
                        break;
                }
+
+               if (h2n->length == 0)
+                       lws_h2_parse_end_of_frame(wsi);
+
                break;
+
        case LWS_H2_FRAME_TYPE_PRIORITY:
                lwsl_info("LWS_H2_FRAME_TYPE_PRIORITY complete frame\n");
                if (!h2n->sid) {
@@ -1006,7 +1171,7 @@ lws_h2_parse_frame_header(struct lws *wsi)
                }
 
                if (!(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) {
-                       if ((!h2n->length) || h2n->length % 6) {
+                       if (h2n->length % 6) {
                                lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
                                                 "Settings length error");
                                break;
@@ -1015,11 +1180,19 @@ lws_h2_parse_frame_header(struct lws *wsi)
                        if (h2n->type == LWS_H2_FRAME_TYPE_COUNT)
                                return 0;
 
-                       if (wsi->upgraded_to_http2) {
+                       if (wsi->upgraded_to_http2 &&
+#if defined(LWS_WITH_CLIENT)
+                           (!(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) ||
+#else
+                           (
+#endif
+                                           !wsi->h2_acked_settings)) {
+
                                pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);
                                if (!pps)
                                        return 1;
                                lws_pps_schedule(wsi, pps);
+                               wsi->h2_acked_settings = 1;
                        }
                        break;
                }
@@ -1044,8 +1217,9 @@ lws_h2_parse_frame_header(struct lws *wsi)
                }
                break;
        case LWS_H2_FRAME_TYPE_CONTINUATION:
-               lwsl_info("LWS_H2_FRAME_TYPE_CONTINUATION: sid = %d\n",
-                         h2n->sid);
+               lwsl_info("LWS_H2_FRAME_TYPE_CONTINUATION: sid = %u %d %d\n",
+                         (unsigned int)h2n->sid, (int)h2n->cont_exp,
+                         (int)h2n->cont_exp_sid);
 
                if (!h2n->cont_exp ||
                     h2n->cont_exp_sid != h2n->sid ||
@@ -1055,6 +1229,7 @@ lws_h2_parse_frame_header(struct lws *wsi)
                                      "unexpected CONTINUATION");
                        break;
                }
+
                if (h2n->swsi->h2.END_HEADERS) {
                        lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
                                      "END_HEADERS already seen");
@@ -1064,7 +1239,8 @@ lws_h2_parse_frame_header(struct lws *wsi)
                goto update_end_headers;
 
        case LWS_H2_FRAME_TYPE_HEADERS:
-               lwsl_info("HEADERS: frame header: sid = %d\n", h2n->sid);
+               lwsl_info("HEADERS: frame header: sid = %u\n",
+                               (unsigned int)h2n->sid);
                if (!h2n->sid) {
                        lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "sid 0");
                        return 1;
@@ -1078,13 +1254,14 @@ lws_h2_parse_frame_header(struct lws *wsi)
                        return 1;
                }
 
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
                if (wsi->client_h2_alpn) {
                        if (h2n->sid) {
-                               h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid);
-                               lwsl_info("HEADERS: nwsi %p: sid %d mapped "
-                                         "to wsi %p\n", wsi, h2n->sid,
-                                         h2n->swsi);
+                               h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid);
+                               lwsl_info("HEADERS: nwsi %s: sid %u mapped "
+                                         "to wsi %s\n", lws_wsi_tag(wsi),
+                                         (unsigned int)h2n->sid,
+                                         lws_wsi_tag(h2n->swsi));
                                if (!h2n->swsi)
                                        break;
                        }
@@ -1094,16 +1271,28 @@ lws_h2_parse_frame_header(struct lws *wsi)
 
                if (!h2n->swsi) {
                        /* no more children allowed by parent */
-                       if (wsi->h2.child_count + 1 >
-                           wsi->h2.h2n->set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
+                       if (wsi->mux.child_count + 1 >
+                           wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {
                                lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
                                "Another stream not allowed");
 
                                return 1;
                        }
 
-                       h2n->swsi = lws_wsi_server_new(wsi->vhost, wsi,
-                                                      h2n->sid);
+                       /*
+                        * The peer has sent us a HEADERS implying the creation
+                        * of a new stream
+                        */
+
+                       lws_context_lock(wsi->a.context, "h2 new str");
+                       lws_vhost_lock(wsi->a.vhost);
+
+                       h2n->swsi = __lws_wsi_server_new(wsi->a.vhost, wsi,
+                                                        h2n->sid);
+
+                       lws_vhost_unlock(wsi->a.vhost);
+                       lws_context_unlock(wsi->a.context);
+
                        if (!h2n->swsi) {
                                lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
                                              "OOM");
@@ -1111,22 +1300,14 @@ lws_h2_parse_frame_header(struct lws *wsi)
                                return 1;
                        }
 
-                       pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
-                       if (!pps)
-                               goto cleanup_wsi;
-                       pps->u.update_window.sid = h2n->sid;
-                       pps->u.update_window.credit = 4 * 65536;
-                       h2n->swsi->h2.peer_tx_cr_est +=
-                                               pps->u.update_window.credit;
-                       lws_pps_schedule(wsi, pps);
+                       if (h2n->sid >= h2n->highest_sid)
+                               h2n->highest_sid = h2n->sid + 2;
 
-                       pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
-                       if (!pps)
+                       h2n->swsi->h2.initialized = 1;
+
+                       if (lws_h2_update_peer_txcredit(h2n->swsi,
+                                       h2n->swsi->mux.my_sid, 4 * 65536))
                                goto cleanup_wsi;
-                       pps->u.update_window.sid = 0;
-                       pps->u.update_window.credit = 4 * 65536;
-                       wsi->h2.peer_tx_cr_est += pps->u.update_window.credit;
-                       lws_pps_schedule(wsi, pps);
                }
 
                /*
@@ -1149,19 +1330,12 @@ lws_h2_parse_frame_header(struct lws *wsi)
                 * transitions to the "closed" state when the first frame for
                 * stream 7 is sent or received.
                 */
-               lws_start_foreach_ll(struct lws *, w, wsi->h2.child_list) {
-                       if (w->h2.my_sid < h2n->sid &&
+               lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) {
+                       if (w->mux.my_sid < h2n->sid &&
                            w->h2.h2_state == LWS_H2_STATE_IDLE)
                                lws_close_free_wsi(w, 0, "h2 sid close");
-                       assert(w->h2.sibling_list != w);
-               } lws_end_foreach_ll(w, h2.sibling_list);
-
-
-               /* END_STREAM means after servicing this, close the stream */
-               h2n->swsi->h2.END_STREAM =
-                                       !!(h2n->flags & LWS_H2_FLAG_END_STREAM);
-               lwsl_info("%s: hdr END_STREAM = %d\n",__func__,
-                         h2n->swsi->h2.END_STREAM);
+                       assert(w->mux.sibling_list != w);
+               } lws_end_foreach_ll(w, mux.sibling_list);
 
                h2n->cont_exp = !(h2n->flags & LWS_H2_FLAG_END_HEADERS);
                h2n->cont_exp_sid = h2n->sid;
@@ -1169,10 +1343,29 @@ lws_h2_parse_frame_header(struct lws *wsi)
        //      lws_header_table_reset(h2n->swsi, 0);
 
 update_end_headers:
+               if (lws_check_opt(h2n->swsi->a.vhost->options,
+                              LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL)) {
+
+                       /*
+                        * We don't directly timeout streams that enter the
+                        * half-closed remote state, allowing immortal long
+                        * poll
+                        */
+                       lws_mux_mark_immortal(h2n->swsi);
+                       lwsl_info("%s: %s: h2 stream entering long poll\n",
+                                       __func__, lws_wsi_tag(h2n->swsi));
+
+               } else {
+                       h2n->swsi->h2.END_STREAM =
+                                       !!(h2n->flags & LWS_H2_FLAG_END_STREAM);
+                       lwsl_debug("%s: hdr END_STREAM = %d\n",__func__,
+                         h2n->swsi->h2.END_STREAM);
+               }
+
                /* no END_HEADERS means CONTINUATION must come */
                h2n->swsi->h2.END_HEADERS =
                                !!(h2n->flags & LWS_H2_FLAG_END_HEADERS);
-               lwsl_info("%p: END_HEADERS %d\n", h2n->swsi,
+               lwsl_info("%s: %s: END_HEADERS %d\n", __func__, lws_wsi_tag(h2n->swsi),
                          h2n->swsi->h2.END_HEADERS);
                if (h2n->swsi->h2.END_HEADERS)
                        h2n->cont_exp = 0;
@@ -1192,6 +1385,10 @@ cleanup_wsi:
                lwsl_info("LWS_H2_FRAME_TYPE_WINDOW_UPDATE\n");
                break;
        case LWS_H2_FRAME_TYPE_COUNT:
+               if (h2n->length == 0)
+                       lws_h2_parse_end_of_frame(wsi);
+               else
+                       lwsl_debug("%s: going on to deal with unknown frame remaining len %d\n", __func__, (unsigned int)h2n->length);
                break;
        default:
                lwsl_info("%s: ILLEGAL FRAME TYPE %d\n", __func__, h2n->type);
@@ -1205,15 +1402,21 @@ cleanup_wsi:
 }
 
 static const char * const method_names[] = {
-       "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", "CONNECT", "HEAD"
+       "GET", "POST",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
+       "OPTIONS", "PUT", "PATCH", "DELETE",
+#endif
+       "CONNECT", "HEAD"
 };
 static unsigned char method_index[] = {
        WSI_TOKEN_GET_URI,
        WSI_TOKEN_POST_URI,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
        WSI_TOKEN_OPTIONS_URI,
        WSI_TOKEN_PUT_URI,
        WSI_TOKEN_PATCH_URI,
        WSI_TOKEN_DELETE_URI,
+#endif
        WSI_TOKEN_CONNECT,
        WSI_TOKEN_HEAD_URI,
 };
@@ -1241,19 +1444,11 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
        h2n->count = 0;
 
        if (h2n->sid)
-               h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid);
+               h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid);
 
        if (h2n->sid > h2n->highest_sid)
                h2n->highest_sid = h2n->sid;
 
-       /* set our initial window size */
-       if (!wsi->h2.initialized) {
-               wsi->h2.tx_cr = h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
-               lwsl_info("initial tx credit on master %p: %d\n", wsi,
-                         wsi->h2.tx_cr);
-               wsi->h2.initialized = 1;
-       }
-
        if (h2n->collected_priority && (h2n->dep & ~(1u << 31)) == h2n->sid) {
                lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "depends on own sid");
                return 0;
@@ -1263,29 +1458,38 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
 
        case LWS_H2_FRAME_TYPE_SETTINGS:
 
-#if !defined(LWS_NO_CLIENT)
-               if (wsi->client_h2_alpn &&
+#if defined(LWS_WITH_CLIENT)
+               if (wsi->client_h2_alpn && !wsi->client_mux_migrated &&
                    !(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) {
                        struct lws_h2_protocol_send *pps;
 
                        /* migrate original client ask on to substream 1 */
-
+#if defined(LWS_WITH_FILE_OPS)
                        wsi->http.fop_fd = NULL;
-
+#endif
+                       lwsl_info("%s: migrating\n", __func__);
+                       wsi->client_mux_migrated = 1;
                        /*
                         * we need to treat the headers from the upgrade as the
                         * first job.  So these need to get shifted to sid 1.
                         */
-                       h2n->swsi = lws_wsi_server_new(wsi->vhost, wsi, 1);
+                       lws_context_lock(wsi->a.context, "h2 mig");
+                       lws_vhost_lock(wsi->a.vhost);
+
+                       h2n->swsi = __lws_wsi_server_new(wsi->a.vhost, wsi, 1);
+
+                       lws_vhost_unlock(wsi->a.vhost);
+                       lws_context_unlock(wsi->a.context);
+
                        if (!h2n->swsi)
                                return 1;
                        h2n->sid = 1;
 
-                       assert(lws_h2_wsi_from_id(wsi, 1) == h2n->swsi);
+                       assert(lws_wsi_mux_from_id(wsi, 1) == h2n->swsi);
 
-                       lws_role_transition(wsi, LWSIFR_CLIENT,
-                                           LRS_H2_WAITING_TO_SEND_HEADERS,
-                                           &role_ops_h2);
+               //      lws_role_transition(wsi, LWSIFR_CLIENT,
+               //                          LRS_H2_WAITING_TO_SEND_HEADERS,
+               //                          &role_ops_h2);
 
                        lws_role_transition(h2n->swsi, LWSIFR_CLIENT,
                                            LRS_H2_WAITING_TO_SEND_HEADERS,
@@ -1293,16 +1497,53 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
 
                        /* pass on the initial headers to SID 1 */
                        h2n->swsi->http.ah = wsi->http.ah;
-                       h2n->swsi->client_h2_substream = 1;
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+                       lws_fi_import(&h2n->swsi->fic, &wsi->fic);
+#endif
+                       h2n->swsi->client_mux_substream = 1;
+                       h2n->swsi->client_h2_alpn = 1;
+#if defined(LWS_WITH_CLIENT)
+                       h2n->swsi->flags = wsi->flags;
+#if defined(LWS_WITH_CONMON)
+                       /* sid1 needs to represent the connection experience
+                        * ... we take over responsibility for the DNS list
+                        * copy as well
+                        */
+                       h2n->swsi->conmon = wsi->conmon;
+                       h2n->swsi->conmon_datum = wsi->conmon_datum;
+                       h2n->swsi->sa46_peer = wsi->sa46_peer;
+                       wsi->conmon.dns_results_copy = NULL;
+#endif
+#endif /* CLIENT */
 
-                       h2n->swsi->protocol = wsi->protocol;
-                       if (h2n->swsi->user_space && !h2n->swsi->user_space_externally_allocated)
+#if defined(LWS_WITH_SECURE_STREAMS)
+                       if (wsi->for_ss) {
+                               lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+
+                               h2n->swsi->for_ss = 1;
+                               wsi->for_ss = 0;
+
+                               if (h->wsi == wsi)
+                                       h->wsi = h2n->swsi;
+                       }
+#endif
+
+                       h2n->swsi->a.protocol = wsi->a.protocol;
+                       if (h2n->swsi->user_space &&
+                           !h2n->swsi->user_space_externally_allocated)
                                lws_free(h2n->swsi->user_space);
                        h2n->swsi->user_space = wsi->user_space;
                        h2n->swsi->user_space_externally_allocated =
                                        wsi->user_space_externally_allocated;
-                       h2n->swsi->opaque_user_data = wsi->opaque_user_data;
-                       wsi->opaque_user_data = NULL;
+                       h2n->swsi->a.opaque_user_data = wsi->a.opaque_user_data;
+                       wsi->a.opaque_user_data = NULL;
+                       h2n->swsi->txc.manual_initial_tx_credit =
+                                       wsi->txc.manual_initial_tx_credit;
+
+#if defined(LWS_WITH_TLS)
+                       lws_strncpy(h2n->swsi->alpn, wsi->alpn,
+                                       sizeof(wsi->alpn));
+#endif
 
                        wsi->user_space = NULL;
 
@@ -1310,42 +1551,42 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                                h2n->swsi->http.ah->wsi = h2n->swsi;
                        wsi->http.ah = NULL;
 
-                       lwsl_info("%s: MIGRATING nwsi %p: swsi %p\n", __func__,
-                                 wsi, h2n->swsi);
-                       h2n->swsi->h2.tx_cr =
-                               h2n->set.s[H2SET_INITIAL_WINDOW_SIZE];
-                       lwsl_info("initial tx credit on conn %p: %d\n",
-                                 h2n->swsi, h2n->swsi->h2.tx_cr);
+                       lwsl_info("%s: MIGRATING nwsi %s -> swsi %s\n", __func__,
+                                 lws_wsi_tag(wsi), lws_wsi_tag(h2n->swsi));
+                       h2n->swsi->txc.tx_cr = (int32_t)
+                               h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
+                       lwsl_info("%s: initial tx credit on %s: %d\n",
+                                 __func__, lws_wsi_tag(h2n->swsi),
+                                 (int)h2n->swsi->txc.tx_cr);
                        h2n->swsi->h2.initialized = 1;
 
+                       /* set our initial window size */
+                       if (!wsi->h2.initialized) {
+                               wsi->txc.tx_cr = (int32_t)
+                                    h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE];
+
+                               lwsl_info("%s: initial tx credit for us to "
+                                         "write on nwsi %s: %d\n", __func__,
+                                         lws_wsi_tag(wsi), (int)wsi->txc.tx_cr);
+                               wsi->h2.initialized = 1;
+                       }
+
                        lws_callback_on_writable(h2n->swsi);
 
-                       pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);
-                       if (!pps)
-                               return 1;
-                       lws_pps_schedule(wsi, pps);
-                       lwsl_info("%s: scheduled settings ack PPS\n", __func__);
+                       if (!wsi->h2_acked_settings ||
+                           !(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM)
+                       ) {
+                               pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);
+                               if (!pps)
+                                       return 1;
+                               lws_pps_schedule(wsi, pps);
+                               lwsl_info("%s: SETTINGS ack PPS\n", __func__);
+                               wsi->h2_acked_settings = 1;
+                       }
 
                        /* also attach any queued guys */
 
-                       /* we have a transaction queue that wants to pipeline */
-                       lws_vhost_lock(wsi->vhost);
-                       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
-                                 wsi->dll2_cli_txn_queue_owner.head) {
-                               struct lws *w = lws_container_of(d, struct lws,
-                                               dll2_cli_txn_queue);
-
-                               if (lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2) {
-                                       lwsl_info("%s: cli pipeq %p to be h2\n",
-                                                       __func__, w);
-                                       /* remove ourselves from client queue */
-                                       lws_dll2_remove(&w->dll2_cli_txn_queue);
-
-                                       /* attach ourselves as an h2 stream */
-                                       lws_wsi_h2_adopt(wsi, w);
-                               }
-                       } lws_end_foreach_dll_safe(d, d1);
-                       lws_vhost_unlock(wsi->vhost);
+                       lws_wsi_mux_apply_queue(wsi);
                }
 #endif
                break;
@@ -1367,6 +1608,8 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                if (!h2n->swsi->h2.END_HEADERS) {
                        /* we are not finished yet */
                        lwsl_info("witholding http action for continuation\n");
+                       h2n->cont_exp_sid = h2n->sid;
+                       h2n->cont_exp = 1;
                        break;
                }
 
@@ -1374,8 +1617,9 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
 
                if (h2n->hpack != HPKS_TYPE) {
                        /* hpack incomplete */
-                       lwsl_info("hpack incomplete %d (type %d, len %d)\n",
-                                 h2n->hpack, h2n->type, h2n->hpack_len);
+                       lwsl_info("hpack incomplete %d (type %d, len %u)\n",
+                                 h2n->hpack, h2n->type,
+                                 (unsigned int)h2n->hpack_len);
                        lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
                                      "hpack incomplete");
                        break;
@@ -1391,26 +1635,37 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                        break;
                }
 
-               lwsl_info("http req, wsi=%p, h2n->swsi=%p\n", wsi, h2n->swsi);
+               lwsl_info("http req, %s, h2n->swsi=%s\n", lws_wsi_tag(wsi),
+                               lws_wsi_tag(h2n->swsi));
                h2n->swsi->hdr_parsing_completed = 1;
 
-#if !defined(LWS_NO_CLIENT)
-               if (h2n->swsi->client_h2_substream) {
-                       if (lws_client_interpret_server_handshake(h2n->swsi)) {
-                               lws_h2_rst_stream(h2n->swsi,
-                                                 H2_ERR_STREAM_CLOSED,
-                                                 "protocol CLI_EST closed it");
-                               break;
-                       }
+#if defined(LWS_WITH_CLIENT)
+               if (h2n->swsi->client_mux_substream &&
+                   lws_client_interpret_server_handshake(h2n->swsi)) {
+                       /*
+                        * This is more complicated than it looks, one exit from
+                        * interpret_server_handshake() is to do a close that
+                        * turns into a redirect.
+                        *
+                        * In that case, the wsi survives having being reset
+                        * and detached from any h2 identity.  We need to get
+                        * our parents out from touching it any more
+                        */
+                       lwsl_info("%s: cli int serv hs closed, or redir\n", __func__);
+                       return 2;
                }
 #endif
 
                if (lws_hdr_extant(h2n->swsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
-                       h2n->swsi->http.rx_content_length  = atoll(
-                               lws_hdr_simple_ptr(h2n->swsi,
-                                     WSI_TOKEN_HTTP_CONTENT_LENGTH));
+                       const char *simp = lws_hdr_simple_ptr(h2n->swsi,
+                                             WSI_TOKEN_HTTP_CONTENT_LENGTH);
+
+                       if (!simp) /* coverity */
+                               return 1;
+                       h2n->swsi->http.rx_content_length = (unsigned long long)atoll(simp);
                        h2n->swsi->http.rx_content_remain =
                                        h2n->swsi->http.rx_content_length;
+                       h2n->swsi->http.content_length_given = 1;
                        lwsl_info("setting rx_content_length %lld\n",
                                  (long long)h2n->swsi->http.rx_content_length);
                }
@@ -1421,20 +1676,20 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                        const unsigned char *c;
 
                        do {
-                               c = lws_token_to_string(n);
+                               c = lws_token_to_string((enum lws_token_indexes)n);
                                if (!c) {
                                        n++;
                                        continue;
                                }
 
-                               len = lws_hdr_total_length(h2n->swsi, n);
+                               len = lws_hdr_total_length(h2n->swsi, (enum lws_token_indexes)n);
                                if (!len || len > (int)sizeof(buf) - 1) {
                                        n++;
                                        continue;
                                }
 
                                if (lws_hdr_copy(h2n->swsi, buf, sizeof buf,
-                                                n) < 0) {
+                                               (enum lws_token_indexes)n) < 0) {
                                        lwsl_info("    %s !oversize!\n",
                                                  (char *)c);
                                } else {
@@ -1455,6 +1710,9 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                }
 
                switch (h2n->swsi->h2.h2_state) {
+               case LWS_H2_STATE_IDLE:
+                       lws_h2_state(h2n->swsi, LWS_H2_STATE_OPEN);
+                       break;
                case LWS_H2_STATE_OPEN:
                        if (h2n->swsi->h2.END_STREAM)
                                lws_h2_state(h2n->swsi,
@@ -1462,13 +1720,39 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                        break;
                case LWS_H2_STATE_HALF_CLOSED_LOCAL:
                        if (h2n->swsi->h2.END_STREAM)
+                               /*
+                                * action the END_STREAM
+                                */
                                lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
                        break;
                }
 
-#if !defined(LWS_NO_CLIENT)
-               if (h2n->swsi->client_h2_substream) {
-                       lwsl_info("%s: headers: client path\n", __func__);
+#if defined(LWS_WITH_CLIENT)
+
+               /*
+                * If we already had the END_STREAM along with the END_HEADERS,
+                * we have already transitioned to STATE_CLOSED and we are not
+                * going to be doing anything further on this stream.
+                *
+                * In that case handle the transaction completion and
+                * finalize the stream for the peer
+                */
+
+               if (h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED &&
+                       h2n->swsi->client_mux_substream) {
+
+                       lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR,
+                               "client done");
+
+                       if (lws_http_transaction_completed_client(h2n->swsi))
+                               lwsl_debug("tx completed returned close\n");
+                       break;
+               }
+
+               if (h2n->swsi->client_mux_substream) {
+                       lwsl_info("%s: %s: headers: client path (h2 state %s)\n",
+                                 __func__, lws_wsi_tag(wsi),
+                                 h2_state_names[h2n->swsi->h2.h2_state]);
                        break;
                }
 #endif
@@ -1483,13 +1767,13 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                        break;
                }
 
-
                if (lws_hdr_extant(h2n->swsi, WSI_TOKEN_TE)) {
                        n = lws_hdr_total_length(h2n->swsi, WSI_TOKEN_TE);
 
                        if (n != 8 ||
+                           !lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_TE) ||
                            strncmp(lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_TE),
-                                 "trailers", n)) {
+                                 "trailers", (unsigned int)n)) {
                                lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
                                              "Illegal transfer-encoding");
                                break;
@@ -1500,27 +1784,29 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                lws_http_compression_validate(h2n->swsi);
 #endif
 
-               wsi->vhost->conn_stats.h2_trans++;
                p = lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_HTTP_COLON_METHOD);
                /*
                 * duplicate :path into the individual method uri header
                 * index, so that it looks the same as h1 in the ah
                 */
                for (n = 0; n < (int)LWS_ARRAY_SIZE(method_names); n++)
-                       if (!strcasecmp(p, method_names[n])) {
+                       if (p && !strcasecmp(p, method_names[n])) {
                                h2n->swsi->http.ah->frag_index[method_index[n]] =
                                                h2n->swsi->http.ah->frag_index[
                                                     WSI_TOKEN_HTTP_COLON_PATH];
                                break;
                        }
 
-               lwsl_debug("%s: setting DEF_ACT from 0x%x\n", __func__,
-                          h2n->swsi->wsistate);
-               lwsi_set_state(h2n->swsi, LRS_DEFERRING_ACTION);
-               lws_callback_on_writable(h2n->swsi);
+               {
+                       lwsl_debug("%s: setting DEF_ACT from 0x%x\n", __func__,
+                                  (unsigned int)h2n->swsi->wsistate);
+                       lwsi_set_state(h2n->swsi, LRS_DEFERRING_ACTION);
+                       lws_callback_on_writable(h2n->swsi);
+               }
                break;
 
        case LWS_H2_FRAME_TYPE_DATA:
+               lwsl_info("%s: DATA flags 0x%x\n", __func__, h2n->flags);
                if (!h2n->swsi)
                        break;
 
@@ -1543,16 +1829,16 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                    h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_LOCAL)
                        lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED);
 
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
                /*
                 * client... remote END_STREAM implies we weren't going to
                 * send anything else anyway.
                 */
 
-               if (h2n->swsi->client_h2_substream &&
-                   h2n->flags & LWS_H2_FLAG_END_STREAM) {
-                       lwsl_info("%s: %p: DATA: end stream\n",
-                                 __func__, h2n->swsi);
+               if (h2n->swsi->client_mux_substream &&
+                   (h2n->flags & LWS_H2_FLAG_END_STREAM)) {
+                       lwsl_info("%s: %s: DATA: end stream\n",
+                                 __func__, lws_wsi_tag(h2n->swsi));
 
                        if (h2n->swsi->h2.h2_state == LWS_H2_STATE_OPEN) {
                                lws_h2_state(h2n->swsi,
@@ -1579,8 +1865,10 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                break;
 
        case LWS_H2_FRAME_TYPE_PING:
-               if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK) { // ack
-               } else {/* they're sending us a ping request */
+               if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)
+                       lws_validity_confirmed(wsi);
+               else {
+                       /* they're sending us a ping request */
                        struct lws_h2_protocol_send *pps =
                                        lws_h2_new_pps(LWS_H2_PPS_PONG);
                        if (!pps)
@@ -1595,9 +1883,14 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                break;
 
        case LWS_H2_FRAME_TYPE_WINDOW_UPDATE:
+               /*
+                * We only have an unsigned 31-bit (positive) increment possible
+                */
                h2n->hpack_e_dep &= ~(1u << 31);
-               lwsl_info("WINDOW_UPDATE: sid %d %u (0x%x)\n", h2n->sid,
-                           h2n->hpack_e_dep, h2n->hpack_e_dep);
+               lwsl_info("WINDOW_UPDATE: sid %u %u (0x%x)\n",
+                         (unsigned int)h2n->sid,
+                         (unsigned int)h2n->hpack_e_dep,
+                         (unsigned int)h2n->hpack_e_dep);
 
                if (h2n->sid)
                        eff_wsi = h2n->swsi;
@@ -1609,14 +1902,18 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                        break; /* ignore */
                }
 
-               if (eff_wsi->vhost->options &
+               if (eff_wsi->a.vhost->options &
                        LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW &&
-                   (uint64_t)eff_wsi->h2.tx_cr + (uint64_t)h2n->hpack_e_dep >
+                   (uint64_t)eff_wsi->txc.tx_cr + (uint64_t)h2n->hpack_e_dep >
                    (uint64_t)0x7fffffff)
-                       h2n->hpack_e_dep = 0x7fffffff - eff_wsi->h2.tx_cr;
+                       h2n->hpack_e_dep = (uint32_t)(0x7fffffff - eff_wsi->txc.tx_cr);
 
-               if ((uint64_t)eff_wsi->h2.tx_cr + (uint64_t)h2n->hpack_e_dep >
+               if ((uint64_t)eff_wsi->txc.tx_cr + (uint64_t)h2n->hpack_e_dep >
                    (uint64_t)0x7fffffff) {
+                       lwsl_warn("%s: WINDOW_UPDATE 0x%llx + 0x%llx = 0x%llx, too high\n",
+                                       __func__, (unsigned long long)eff_wsi->txc.tx_cr,
+                                       (unsigned long long)h2n->hpack_e_dep,
+                                       (unsigned long long)eff_wsi->txc.tx_cr + (unsigned long long)h2n->hpack_e_dep);
                        if (h2n->sid)
                                lws_h2_rst_stream(h2n->swsi,
                                                  H2_ERR_FLOW_CONTROL_ERROR,
@@ -1632,39 +1929,50 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
                                      "Zero length window update");
                        break;
                }
-               n = eff_wsi->h2.tx_cr;
-               eff_wsi->h2.tx_cr += h2n->hpack_e_dep;
+               n = eff_wsi->txc.tx_cr;
+               eff_wsi->txc.tx_cr += (int32_t)h2n->hpack_e_dep;
 
-               if (n <= 0 && eff_wsi->h2.tx_cr <= 0)
+               lws_wsi_txc_report_manual_txcr_in(eff_wsi,
+                                                 (int32_t)h2n->hpack_e_dep);
+
+               lws_wsi_txc_describe(&eff_wsi->txc, "WINDOW_UPDATE in",
+                                    eff_wsi->mux.my_sid);
+
+               if (n <= 0 && eff_wsi->txc.tx_cr <= 0)
                        /* it helps, but won't change sendability for anyone */
                        break;
 
                /*
-                * It did change sendability... for us and any children waiting
-                * on us... reassess blockage for all children first
+                * It may have changed sendability (depends on SID 0 tx credit
+                * too)... for us and any children waiting on us... reassess
+                * blockage for all children first
                 */
-               lws_start_foreach_ll(struct lws *, w, wsi->h2.child_list) {
+               lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) {
                        lws_callback_on_writable(w);
-               } lws_end_foreach_ll(w, h2.sibling_list);
+               } lws_end_foreach_ll(w, mux.sibling_list);
 
-               if (eff_wsi->h2.skint && lws_h2_tx_cr_get(eff_wsi)) {
-                       lwsl_info("%s: %p: skint\n", __func__, wsi);
-                       eff_wsi->h2.skint = 0;
+               if (eff_wsi->txc.skint &&
+                   !lws_wsi_txc_check_skint(&eff_wsi->txc,
+                                            lws_h2_tx_cr_get(eff_wsi)))
+                       /*
+                        * This one became un-skint, schedule a writeable
+                        * callback
+                        */
                        lws_callback_on_writable(eff_wsi);
-               }
+
                break;
 
        case LWS_H2_FRAME_TYPE_GOAWAY:
-               lwsl_info("GOAWAY: last sid %d, error 0x%08X, string '%s'\n",
-                         h2n->goaway_last_sid, h2n->goaway_err,
-                         h2n->goaway_str);
-               wsi->h2.GOING_AWAY = 1;
+               lwsl_notice("GOAWAY: last sid %u, error 0x%08X, string '%s'\n",
+                         (unsigned int)h2n->goaway_last_sid,
+                         (unsigned int)h2n->goaway_err, h2n->goaway_str);
 
                return 1;
 
        case LWS_H2_FRAME_TYPE_RST_STREAM:
-               lwsl_info("LWS_H2_FRAME_TYPE_RST_STREAM: sid %d: reason 0x%x\n",
-                         h2n->sid, h2n->hpack_e_dep);
+               lwsl_info("LWS_H2_FRAME_TYPE_RST_STREAM: sid %u: reason 0x%x\n",
+                         (unsigned int)h2n->sid,
+                         (unsigned int)h2n->hpack_e_dep);
                break;
 
        case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */
@@ -1691,23 +1999,21 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
  * close it all.  If it needs to close an swsi, it can do it here.
  */
 int
-lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
+lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t _inlen,
              lws_filepos_t *inused)
 {
        struct lws_h2_netconn *h2n = wsi->h2.h2n;
        struct lws_h2_protocol_send *pps;
-       unsigned char c, *oldin = in;
+       unsigned char c, *oldin = in, *iend = in + (size_t)_inlen;
        int n, m;
 
        if (!h2n)
                goto fail;
 
-       while (inlen--) {
+       while (in < iend) {
 
                c = *in++;
 
-               // lwsl_notice("%s: 0x%x\n", __func__, c);
-
                switch (lwsi_state(wsi)) {
                case LRS_H2_AWAIT_PREFACE:
                        if (preface[h2n->count++] != c)
@@ -1716,10 +2022,11 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                        if (preface[h2n->count])
                                break;
 
-                       lwsl_info("http2: %p: established\n", wsi);
+                       lwsl_info("http2: %s: established\n", lws_wsi_tag(wsi));
                        lwsi_set_state(wsi, LRS_H2_AWAIT_SETTINGS);
+                       lws_validity_confirmed(wsi);
                        h2n->count = 0;
-                       wsi->h2.tx_cr = 65535;
+                       wsi->txc.tx_cr = 65535;
 
                        /*
                         * we must send a settings frame -- empty one is OK...
@@ -1735,6 +2042,7 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                case LRS_H2_WAITING_TO_SEND_HEADERS:
                case LRS_ESTABLISHED:
                case LRS_H2_AWAIT_SETTINGS:
+
                        if (h2n->frame_state != LWS_H2_FRAME_HEADER_LENGTH)
                                goto try_frame_start;
 
@@ -1743,6 +2051,12 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                         */
                        h2n->count++;
 
+                       if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */
+                               //lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
+                               goto frame_end;
+                       }
+
+
                        if (h2n->flags & LWS_H2_FLAG_PADDED &&
                            !h2n->pad_length) {
                                /*
@@ -1773,14 +2087,14 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                                h2n->weight_temp = c;
                                h2n->collected_priority = 1;
                                lwsl_debug("PRI FL: dep 0x%x, weight 0x%02X\n",
-                                          h2n->dep, h2n->weight_temp);
+                                          (unsigned int)h2n->dep,
+                                          h2n->weight_temp);
                                break; /* we consumed this */
                        }
                        if (h2n->padding && h2n->count >
                            (h2n->length - h2n->padding)) {
                                if (c) {
-                                       lws_h2_goaway(wsi,
-                                                     H2_ERR_PROTOCOL_ERROR,
+                                       lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
                                                      "nonzero padding");
                                        break;
                                }
@@ -1791,12 +2105,12 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                        switch(h2n->type) {
 
                        case LWS_H2_FRAME_TYPE_SETTINGS:
-                               n = (h2n->count - 1 - h2n->preamble) %
+                               n = (int)(h2n->count - 1u - h2n->preamble) %
                                     LWS_H2_SETTINGS_LEN;
                                h2n->one_setting[n] = c;
                                if (n != LWS_H2_SETTINGS_LEN - 1)
                                        break;
-                               lws_h2_settings(wsi, &h2n->set,
+                               lws_h2_settings(wsi, &h2n->peer_set,
                                                h2n->one_setting,
                                                LWS_H2_SETTINGS_LEN);
                                break;
@@ -1835,7 +2149,7 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                                        if (h2n->inside - 9 <
                                            sizeof(h2n->goaway_str) - 1)
                                                h2n->goaway_str[
-                                                          h2n->inside - 9] = c;
+                                                          h2n->inside - 9] = (char)c;
                                        h2n->goaway_str[
                                            sizeof(h2n->goaway_str) - 1] = '\0';
                                        break;
@@ -1844,8 +2158,8 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
 
                        case LWS_H2_FRAME_TYPE_DATA:
 
-                               lwsl_info("%s: LWS_H2_FRAME_TYPE_DATA\n",
-                                         __func__);
+                       //      lwsl_info("%s: LWS_H2_FRAME_TYPE_DATA: fl 0x%x\n",
+                       //                __func__, h2n->flags);
 
                                /*
                                 * let the network wsi live a bit longer if
@@ -1854,12 +2168,9 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                                 */
                                if (!wsi->immortal_substream_count)
                                        lws_set_timeout(wsi,
-                                         PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
-#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
-                                         wsi->vhost->keepalive_timeout);
-#else
-                                         31);
-#endif
+                                       PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
+                                               wsi->a.vhost->keepalive_timeout ?
+                                           wsi->a.vhost->keepalive_timeout : 31);
 
                                if (!h2n->swsi)
                                        break;
@@ -1872,16 +2183,28 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                                if (lwsi_role_http(h2n->swsi) &&
                                    lwsi_state(h2n->swsi) == LRS_ESTABLISHED) {
                                        lwsi_set_state(h2n->swsi, LRS_BODY);
-                                       lwsl_info("%s: swsi %p to LRS_BODY\n",
-                                                       __func__, h2n->swsi);
+                                       lwsl_info("%s: %s to LRS_BODY\n",
+                                                       __func__, lws_wsi_tag(h2n->swsi));
                                }
 
+                               /*
+                                * in + length may cover multiple frames, we
+                                * can only consider the length of the DATA
+                                * in front of us
+                                */
+
                                if (lws_hdr_total_length(h2n->swsi,
                                             WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
                                    h2n->swsi->http.rx_content_length &&
                                    h2n->swsi->http.rx_content_remain <
-                                                   inlen + 1 && /* last */
+                                                    h2n->length && /* last */
                                    h2n->inside < h2n->length) {
+
+                                       lwsl_warn("%s: %lu %lu %lu %lu\n", __func__,
+                                                 (unsigned long)h2n->swsi->http.rx_content_remain,
+                                               (unsigned long)(lws_ptr_diff_size_t(iend, in) + 1),
+                                               (unsigned long)h2n->inside, (unsigned long)h2n->length);
+
                                        /* unread data in frame */
                                        lws_h2_goaway(wsi,
                                                      H2_ERR_PROTOCOL_ERROR,
@@ -1894,25 +2217,37 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                                 * hand may exceed the current frame.
                                 */
 
-                               n = (int)inlen + 1;
+                               n = (int)lws_ptr_diff_size_t(iend, in)  + 1;
                                if (n > (int)(h2n->length - h2n->count + 1)) {
-                                       n = h2n->length - h2n->count + 1;
-                                       lwsl_debug("---- restricting len to %d vs %ld\n", n, (long)inlen + 1);
+                                       if (h2n->count > h2n->length)
+                                               goto close_swsi_and_return;
+                                       n = (int)(h2n->length - h2n->count) + 1;
+                                       lwsl_debug("---- restricting len to %d "
+                                                  "\n", n);
                                }
-#if !defined(LWS_NO_CLIENT)
-                               if (h2n->swsi->client_h2_substream) {
-
+#if defined(LWS_WITH_CLIENT)
+                               if (h2n->swsi->client_mux_substream) {
+                                       if (!h2n->swsi->a.protocol) {
+                                               lwsl_err("%s: %p doesn't have protocol\n",
+                                                        __func__, lws_wsi_tag(h2n->swsi));
+                                               m = 1;
+                                       } else {
+                                               h2n->swsi->txc.peer_tx_cr_est -= n;
+                                               wsi->txc.peer_tx_cr_est -= n;
+                                               lws_wsi_txc_describe(&h2n->swsi->txc,
+                                                       __func__,
+                                                       h2n->swsi->mux.my_sid);
                                        m = user_callback_handle_rxflow(
-                                               h2n->swsi->protocol->callback,
+                                               h2n->swsi->a.protocol->callback,
                                                h2n->swsi,
                                          LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
                                                h2n->swsi->user_space,
-                                               in - 1, n);
+                                               in - 1, (unsigned int)n);
+                                       }
 
                                        in += n - 1;
-                                       h2n->inside += n;
-                                       h2n->count += n - 1;
-                                       inlen -= n - 1;
+                                       h2n->inside += (unsigned int)n;
+                                       h2n->count += (unsigned int)n - 1;
 
                                        if (m) {
                                                lwsl_info("RECEIVE_CLIENT_HTTP "
@@ -1920,111 +2255,122 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
                                                goto close_swsi_and_return;
                                        }
 
-                                       break;
-                               } else
+                                       goto do_windows;
+                               }
 #endif
-                               {
+                               if (lwsi_state(h2n->swsi) == LRS_DEFERRING_ACTION) {
+                                       m = lws_buflist_append_segment(
+                                               &h2n->swsi->buflist, in - 1, (unsigned int)n);
+                                       if (m < 0)
+                                               return -1;
 
-                                       if (lwsi_state(h2n->swsi) == LRS_DEFERRING_ACTION) {
-                                               // lwsl_notice("appending because we are in LRS_DEFERRING_ACTION\n");
-                                               m = lws_buflist_append_segment(
-                                                       &h2n->swsi->buflist,
-                                                               in - 1, n);
-                                               if (m < 0)
-                                                       return -1;
-                                               if (m) {
-                                                       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-                                                       lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
-                                                       lws_dll2_add_head(&h2n->swsi->dll_buflist, &pt->dll_buflist_owner);
-                                               }
-                                               in += n - 1;
-                                               h2n->inside += n;
-                                               h2n->count += n - 1;
-                                               inlen -= n - 1;
-
-                                               lwsl_debug("%s: deferred %d\n", __func__, n);
-                                               goto do_windows;
-                                       }
-
-                                       h2n->swsi->outer_will_close = 1;
-                                       /*
-                                        * choose the length for this go so that we end at
-                                        * the frame boundary, in the case there is already
-                                        * more waiting leave it for next time around
-                                        */
-
-                                       n = lws_read_h1(h2n->swsi, in - 1, n);
-                                       // lwsl_notice("%s: lws_read_h1 %d\n", __func__, n);
-                                       h2n->swsi->outer_will_close = 0;
                                        /*
-                                        * can return 0 in POST body with
-                                        * content len exhausted somehow.
+                                        * Since we're in an open-ended
+                                        * DEFERRING_ACTION, don't add this swsi
+                                        * to the pt list of wsi holding buflist
+                                        * content yet, we are not in a position
+                                        * to consume it until we get out of
+                                        * DEFERRING_ACTION.
                                         */
-                                       if (n < 0 ||
-                                           (!n && !lws_buflist_next_segment_len(&wsi->buflist, NULL))) {
-                                               lwsl_info("%s: lws_read_h1 told %d %d / %d\n",
-                                                       __func__, n, h2n->count, h2n->length);
-                                               in += h2n->length - h2n->count;
-                                               h2n->inside = h2n->length;
-                                               h2n->count = h2n->length - 1;
-
-                                               //if (n < 0)
-                                               //      goto already_closed_swsi;
-                                               goto close_swsi_and_return;
-                                       }
 
-                                       inlen -= n - 1;
                                        in += n - 1;
-                                       h2n->inside += n;
-                                       h2n->count += n - 1;
+                                       h2n->inside += (unsigned int)n;
+                                       h2n->count += (unsigned int)n - 1;
+
+                                       lwsl_debug("%s: deferred %d\n", __func__, n);
+                                       goto do_windows;
                                }
 
+                               h2n->swsi->outer_will_close = 1;
+                               /*
+                                * choose the length for this go so that we end at
+                                * the frame boundary, in the case there is already
+                                * more waiting leave it for next time around
+                                */
+
+                               n = lws_read_h1(h2n->swsi, in - 1, (unsigned int)n);
+                               // lwsl_notice("%s: lws_read_h1 %d\n", __func__, n);
+                               h2n->swsi->outer_will_close = 0;
+                               /*
+                                * can return 0 in POST body with
+                                * content len exhausted somehow.
+                                */
+                               if (n < 0 ||
+                                   (!n && h2n->swsi->http.content_length_given && !lws_buflist_next_segment_len(
+                                                   &wsi->buflist, NULL))) {
+                                       lwsl_info("%s: lws_read_h1 told %d %u / %u\n",
+                                               __func__, n,
+                                               (unsigned int)h2n->count,
+                                               (unsigned int)h2n->length);
+                                       in += h2n->length - h2n->count;
+                                       h2n->inside = h2n->length;
+                                       h2n->count = h2n->length - 1;
+
+                                       //if (n < 0)
+                                       //      goto already_closed_swsi;
+                                       goto close_swsi_and_return;
+                               }
+
+                               lwsl_info("%s: lws_read_h1 telling %d %u / %u\n",
+                                               __func__, n,
+                                               (unsigned int)h2n->count,
+                                               (unsigned int)h2n->length);
+
+                               in += (unsigned int)n - 1;
+                               h2n->inside += (unsigned int)n;
+                               h2n->count += (unsigned int)n - 1;
+
+                               h2n->swsi->txc.peer_tx_cr_est -= n;
+                               wsi->txc.peer_tx_cr_est -= n;
+
 do_windows:
-                               /* account for both network and stream wsi windows */
 
-                               wsi->h2.peer_tx_cr_est -= n;
-                               h2n->swsi->h2.peer_tx_cr_est -= n;
+#if defined(LWS_WITH_CLIENT)
+                               if (!(h2n->swsi->flags & LCCSCF_H2_MANUAL_RXFLOW))
+#endif
+                               {
+                                       /*
+                                        * The default behaviour is we just keep
+                                        * cranking the other side's tx credit
+                                        * back up, for simple bulk transfer as
+                                        * fast as we can take it
+                                        */
 
-       //                      lwsl_notice("   peer_tx_cr_est %d, parent %d\n",
-       //                                 h2n->swsi->h2.peer_tx_cr_est, wsi->h2.peer_tx_cr_est);
+                                       m = n  + 65536;
 
-                               if (h2n->swsi->h2.peer_tx_cr_est < (int)(2 * h2n->length) + 65536) {
-                                       pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
-                                       if (!pps)
-                                               return 1;
-                                       pps->u.update_window.sid = h2n->sid;
-                                       pps->u.update_window.credit = (2 * h2n->length + 65536);
-                                       h2n->swsi->h2.peer_tx_cr_est += pps->u.update_window.credit; 
-                                       lws_pps_schedule(wsi, pps);
+                                       /* update both the stream and nwsi */
+
+                                       lws_h2_update_peer_txcredit_thresh(h2n->swsi,
+                                                                   h2n->sid, m, m);
                                }
-                               if (wsi->h2.peer_tx_cr_est < (int)(2 * h2n->length) + 65536) {
-                                       pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
-                                       if (!pps)
-                                               return 1;
-                                       pps->u.update_window.sid = 0;
-                                       pps->u.update_window.credit = (2 * h2n->length + 65536);
-                                       wsi->h2.peer_tx_cr_est += pps->u.update_window.credit;
-                                       lws_pps_schedule(wsi, pps);
+#if defined(LWS_WITH_CLIENT)
+                               else {
+                                       /*
+                                        * If he's handling it himself, only
+                                        * repair the nwsi credit but allow the
+                                        * stream credit to run down until the
+                                        * user code deals with it
+                                        */
+                                       lws_h2_update_peer_txcredit(wsi, 0, n);
+                                       h2n->swsi->txc.manual = 1;
                                }
-
-                               // lwsl_notice("%s: count %d len %d\n", __func__, (int)h2n->count, (int)h2n->length);
-
+#endif
                                break;
 
                        case LWS_H2_FRAME_TYPE_PRIORITY:
                                if (h2n->count <= 4) {
                                        h2n->dep <<= 8;
                                        h2n->dep |= c;
-                               } else {
-                                       h2n->weight_temp = c;
-                                       lwsl_info("PRIORITY: dep 0x%x, weight 0x%02X\n",
-                                                 h2n->dep, h2n->weight_temp);
-
-                                       if ((h2n->dep & ~(1u << 31)) == h2n->sid) {
-                                               lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
-                                                             "cant depend on own sid");
-                                               break;
-                                       }
+                                       break;
+                               }
+                               h2n->weight_temp = c;
+                               lwsl_info("PRIORITY: dep 0x%x, weight 0x%02X\n",
+                                         (unsigned int)h2n->dep, h2n->weight_temp);
+
+                               if ((h2n->dep & ~(1u << 31)) == h2n->sid) {
+                                       lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
+                                                     "cant depend on own sid");
+                                       break;
                                }
                                break;
 
@@ -2051,6 +2397,8 @@ do_windows:
                                break;
 
                        case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */
+                               //lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
+                               h2n->count++;
                                break;
 
                        default:
@@ -2062,17 +2410,24 @@ do_windows:
 
 frame_end:
                        if (h2n->count > h2n->length) {
-                               lwsl_notice("%s: count > length %d %d\n",
-                                           __func__, h2n->count, h2n->length);
-                               goto fail;
-                       }
-                       if (h2n->count != h2n->length)
-                               break;
+                               lwsl_notice("%s: count > length %u %u (type %d)\n",
+                                           __func__, (unsigned int)h2n->count,
+                                           (unsigned int)h2n->length, h2n->type);
+
+                       } else
+                               if (h2n->count != h2n->length)
+                                       break;
 
                        /*
                         * end of frame just happened
                         */
-                       if (lws_h2_parse_end_of_frame(wsi))
+                       n = lws_h2_parse_end_of_frame(wsi);
+                       if (n == 2) {
+                               *inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);
+
+                               return 2;
+                       }
+                       if (n)
                                goto fail;
 
                        break;
@@ -2111,17 +2466,21 @@ try_frame_start:
                                }
                        }
 
-                       if (h2n->frame_state == LWS_H2_FRAME_HEADER_LENGTH)
-                               if (lws_h2_parse_frame_header(wsi))
-                                       goto fail;
+                       if (h2n->frame_state == LWS_H2_FRAME_HEADER_LENGTH &&
+                           lws_h2_parse_frame_header(wsi))
+                               goto fail;
                        break;
 
                default:
+                       if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */
+                               //lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length);
+                               h2n->count++;
+                       }
                        break;
                }
        }
 
-       *inused = in - oldin;
+       *inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);
 
        return 0;
 
@@ -2133,26 +2492,27 @@ close_swsi_and_return:
        h2n->count = 0;
 
 // already_closed_swsi:
-       *inused = in - oldin;
+       *inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);
 
        return 2;
 
 fail:
-       *inused = in - oldin;
+       *inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);
 
        return 1;
 }
 
+#if defined(LWS_WITH_CLIENT)
 int
 lws_h2_client_handshake(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-       uint8_t *buf, *start, *p, *end;
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       uint8_t *buf, *start, *p, *p1, *end;
        char *meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD),
-            *uri = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI);
+            *uri = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI), *simp;
        struct lws *nwsi = lws_get_network_wsi(wsi);
-       struct lws_h2_protocol_send *pps;
-       int n;
+       const char *path = "/";
+       int n, m;
        /*
         * The identifier of a newly established stream MUST be numerically
         * greater than all streams that the initiating endpoint has opened or
@@ -2161,38 +2521,36 @@ lws_h2_client_handshake(struct lws *wsi)
         * receives an unexpected stream identifier MUST respond with a
         * connection error (Section 5.4.1) of type PROTOCOL_ERROR.
         */
-       int sid = nwsi->h2.h2n->highest_sid_opened + 2;
+       unsigned int sid = nwsi->h2.h2n->highest_sid_opened + 2;
 
-       nwsi->h2.h2n->highest_sid_opened = sid;
-       wsi->h2.my_sid = sid;
+       lwsl_debug("%s\n", __func__);
 
-       lwsl_info("%s: CLIENT_WAITING_TO_SEND_HEADERS: pollout (sid %d)\n",
-                       __func__, wsi->h2.my_sid);
+       /*
+        * We MUST allocate our sid here at the point we're about to send the
+        * stream open.  It's because we don't know the order in which multiple
+        * open streams will send their headers... in h2, sending the headers
+        * is the point the stream is opened.  The peer requires that we only
+        * open streams in ascending sid order
+        */
 
-       pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
-       if (!pps)
-               return 1;
-       pps->u.update_window.sid = sid;
-       pps->u.update_window.credit = 4 * 65536;
-       wsi->h2.peer_tx_cr_est += pps->u.update_window.credit;
-       lws_pps_schedule(wsi, pps);
+       wsi->mux.my_sid = nwsi->h2.h2n->highest_sid_opened = sid;
+       lwsl_info("%s: %s: assigning SID %d at header send\n", __func__,
+                       lws_wsi_tag(wsi), sid);
 
-       pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
-       if (!pps)
-               return 1;
-       pps->u.update_window.sid = 0;
-       pps->u.update_window.credit = 4 * 65536;
-       wsi->h2.peer_tx_cr_est += pps->u.update_window.credit;
-       lws_pps_schedule(wsi, pps);
+
+       lwsl_info("%s: CLIENT_WAITING_TO_SEND_HEADERS: pollout (sid %d)\n",
+                       __func__, wsi->mux.my_sid);
 
        p = start = buf = pt->serv_buf + LWS_PRE;
-       end = start + wsi->context->pt_serv_buf_size - LWS_PRE - 1;
+       end = start + (wsi->a.context->pt_serv_buf_size / 2) - LWS_PRE - 1;
 
        /* it's time for us to send our client stream headers */
 
        if (!meth)
                meth = "GET";
 
+       /* h2 pseudoheaders must be in a bunch at the start */
+
        if (lws_add_http_header_by_token(wsi,
                                WSI_TOKEN_HTTP_COLON_METHOD,
                                (unsigned char *)meth,
@@ -2201,46 +2559,124 @@ lws_h2_client_handshake(struct lws *wsi)
 
        if (lws_add_http_header_by_token(wsi,
                                WSI_TOKEN_HTTP_COLON_SCHEME,
-                               (unsigned char *)"https", 4,
+                               (unsigned char *)"https", 5,
                                &p, end))
                goto fail_length;
 
-       if (lws_add_http_header_by_token(wsi,
+
+       n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI);
+       if (n)
+               path = uri;
+       else
+               if (wsi->stash && wsi->stash->cis[CIS_PATH]) {
+                       path = wsi->stash->cis[CIS_PATH];
+                       n = (int)strlen(path);
+               } else
+                       n = 1;
+
+       if (n > 1 && path[0] == '/' && path[1] == '/') {
+               path++;
+               n--;
+       }
+
+       if (n && lws_add_http_header_by_token(wsi,
                                WSI_TOKEN_HTTP_COLON_PATH,
-                               (unsigned char *)uri,
-                               lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI),
-                               &p, end))
+                               (unsigned char *)path, n, &p, end))
                goto fail_length;
 
-       if (lws_add_http_header_by_token(wsi,
+       n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_HOST);
+       simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST);
+       if (!n && wsi->stash && wsi->stash->cis[CIS_ADDRESS]) {
+               n = (int)strlen(wsi->stash->cis[CIS_ADDRESS]);
+               simp = wsi->stash->cis[CIS_ADDRESS];
+       }
+
+//     n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
+//     simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
+#if 0
+       if (n && simp && lws_add_http_header_by_token(wsi,
                                WSI_TOKEN_HTTP_COLON_AUTHORITY,
-                               (unsigned char *)lws_hdr_simple_ptr(wsi,
-                                               _WSI_TOKEN_CLIENT_ORIGIN),
-                       lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_ORIGIN),
-                               &p, end))
+                               (unsigned char *)simp, n, &p, end))
+               goto fail_length;
+#endif
+
+
+       if (/*!wsi->client_h2_alpn && */n && simp &&
+           lws_add_http_header_by_token(wsi, WSI_TOKEN_HOST,
+                               (unsigned char *)simp, n, &p, end))
                goto fail_length;
 
+
+       if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME) {
+               p1 = lws_http_multipart_headers(wsi, p);
+               if (!p1)
+                       goto fail_length;
+               p = p1;
+       }
+
+       if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED) {
+               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
+                          (unsigned char *)"application/x-www-form-urlencoded",
+                          33, &p, end))
+                       goto fail_length;
+               lws_client_http_body_pending(wsi, 1);
+       }
+
        /* give userland a chance to append, eg, cookies */
 
-       if (wsi->protocol->callback(wsi,
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
+       if (wsi->flags & LCCSCF_CACHE_COOKIES)
+               lws_cookie_send_cookies(wsi, (char **)&p, (char *)end);
+#endif
+
+       if (wsi->a.protocol->callback(wsi,
                                LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
-                               wsi->user_space, &p, (end - p) - 12))
+                               wsi->user_space, &p, lws_ptr_diff_size_t(end, p) - 12))
                goto fail_length;
 
        if (lws_finalize_http_header(wsi, &p, end))
                goto fail_length;
 
-       n = lws_write(wsi, start, p - start,
-                     LWS_WRITE_HTTP_HEADERS);
-       if (n != (p - start)) {
+       m = LWS_WRITE_HTTP_HEADERS;
+#if defined(LWS_WITH_CLIENT)
+       /* below is not needed in spec, indeed it destroys the long poll
+        * feature, but required by nghttp2 */
+       if ((wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) &&
+           !(wsi->client_http_body_pending  || lws_has_buffered_out(wsi)))
+               m |= LWS_WRITE_H2_STREAM_END;
+#endif
+
+       // lwsl_hexdump_notice(start, p - start);
+
+       n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), (enum lws_write_protocol)m);
+
+       if (n != lws_ptr_diff(p, start)) {
                lwsl_err("_write returned %d from %ld\n", n,
                         (long)(p - start));
                return -1;
        }
 
+       /*
+        * Normally let's charge up the peer tx credit a bit.  But if
+        * MANUAL_REFLOW is set, just set it to the initial credit given in
+        * the client create info
+        */
+
+       n = 4 * 65536;
+       if (wsi->flags & LCCSCF_H2_MANUAL_RXFLOW) {
+               n = wsi->txc.manual_initial_tx_credit;
+               wsi->txc.manual = 1;
+       }
+
+       if (lws_h2_update_peer_txcredit(wsi, wsi->mux.my_sid, n))
+               return 1;
+
        lws_h2_state(wsi, LWS_H2_STATE_OPEN);
        lwsi_set_state(wsi, LRS_ESTABLISHED);
 
+       if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME)
+               lws_callback_on_writable(wsi);
+
        return 0;
 
 fail_length:
@@ -2248,7 +2684,9 @@ fail_length:
 
        return -1;
 }
+#endif
 
+#if defined(LWS_ROLE_WS) && defined(LWS_WITH_SERVER)
 int
 lws_h2_ws_handshake(struct lws *wsi)
 {
@@ -2256,7 +2694,8 @@ lws_h2_ws_handshake(struct lws *wsi)
                *end = &buf[sizeof(buf) - 1];
        const struct lws_http_mount *hit;
        const char * uri_ptr;
-       int n, m;
+       size_t m;
+       int n;
 
        if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
                return -1;
@@ -2280,23 +2719,61 @@ lws_h2_ws_handshake(struct lws *wsi)
                 *  - one came in, and ... */
                if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) &&
                    /*  - it is not an empty string */
-                   wsi->protocol->name && wsi->protocol->name[0]) {
+                   wsi->a.protocol->name && wsi->a.protocol->name[0]) {
+
+#if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SERVER)
+
+               /*
+                * This is the h2 version of server-ws.c understanding that it
+                * did the ws upgrade on a ss server object, therefore it needs
+                * to pass back to the peer the policy ws-protocol name, not
+                * the generic ss-ws.c protocol name
+                */
+
+               if (wsi->a.vhost && wsi->a.vhost->ss_handle &&
+                   wsi->a.vhost->ss_handle->policy->u.http.u.ws.subprotocol) {
+                       lws_ss_handle_t *h =
+                               (lws_ss_handle_t *)wsi->a.opaque_user_data;
+
+                       lwsl_notice("%s: Server SS %s .wsi %s switching to ws protocol\n",
+                                       __func__, lws_ss_tag(h), lws_wsi_tag(h->wsi));
+
+                       wsi->a.protocol = &protocol_secstream_ws;
+
+                       /*
+                        * inform the SS user code that this has done a one-way
+                        * upgrade to some other protocol... it will likely
+                        * want to treat subsequent payloads differently
+                        */
+
+                       lws_ss_event_helper(h, LWSSSCS_SERVER_UPGRADE);
+
+                       lws_mux_mark_immortal(wsi);
+
                        if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
-                                                (unsigned char *)wsi->protocol->name,
-                                                (int)strlen(wsi->protocol->name),
-                                                &p, end))
-                       return -1;
+                               (unsigned char *)wsi->a.vhost->ss_handle->policy->
+                                               u.http.u.ws.subprotocol,
+                               (int)strlen(wsi->a.vhost->ss_handle->policy->
+                                               u.http.u.ws.subprotocol), &p, end))
+                                       return -1;
+               } else
+#endif
+
+                       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
+                               (unsigned char *)wsi->a.protocol->name,
+                               (int)strlen(wsi->a.protocol->name), &p, end))
+                                       return -1;
                }
        }
 
        if (lws_finalize_http_header(wsi, &p, end))
                return -1;
 
-       m = lws_ptr_diff(p, start);
+       m = lws_ptr_diff_size_t(p, start);
        // lwsl_hexdump_notice(start, m);
        n = lws_write(wsi, start, m, LWS_WRITE_HTTP_HEADERS);
-       if (n != m) {
-               lwsl_err("_write returned %d from %d\n", n, m);
+       if (n != (int)m) {
+               lwsl_err("_write returned %d from %d\n", n, (int)m);
 
                return -1;
        }
@@ -2314,12 +2791,15 @@ lws_h2_ws_handshake(struct lws *wsi)
        hit = lws_find_mount(wsi, uri_ptr, n);
 
        if (hit && hit->cgienv &&
-           wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO, wsi->user_space,
+           wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO, wsi->user_space,
                                    (void *)hit->cgienv, 0))
                return 1;
 
+       lws_validity_confirmed(wsi);
+
        return 0;
 }
+#endif
 
 int
 lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
@@ -2347,9 +2827,8 @@ lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
                 * we were accepting input but now we stopped doing so
                 */
                if (lws_is_flowcontrolled(wsi)) {
-                       lws_rxflow_cache(wsi, buf, 0, (int)len);
+                       lws_rxflow_cache(wsi, buf, 0, (size_t)len);
                        buf += len;
-                       len = 0;
                        break;
                }
 
@@ -2386,7 +2865,6 @@ lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
                if (m == 2) {
                        /* swsi has been closed */
                        buf += body_chunk_len;
-                       len -= body_chunk_len;
                        break;
                }
 
@@ -2397,3 +2875,23 @@ lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
        return lws_ptr_diff(buf, oldbuf);
 }
 
+int
+lws_h2_client_stream_long_poll_rxonly(struct lws *wsi)
+{
+
+       if (!wsi->mux_substream)
+               return 1;
+
+       /*
+        * Elect to send an empty DATA with END_STREAM, to force the stream
+        * into HALF_CLOSED LOCAL
+        */
+       wsi->h2.long_poll = 1;
+       wsi->h2.send_END_STREAM = 1;
+
+       // lws_header_table_detach(wsi, 0);
+
+       lws_callback_on_writable(wsi);
+
+       return 0;
+}
index ee19e37..cad0554 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (C)2011-2014 Andy Green <andy@warmcat.com>
  *
- * Licensed under LGPL2
+ * Licensed under MIT
  *
  * Usage: gcc minihuf.c -o minihuf && ./minihuf > huftable.h
  *
@@ -334,7 +334,6 @@ int main(void)
        int saw;
        int y;
        int j;
-       int q;
        int pos = 0;
        int biggest = 0;
        int fails = 0;
@@ -401,9 +400,8 @@ again:
 
        walk = 0;
        pos = 0;
-       q = 0;
+
        for (n = 0; n < next; n++) {
-               q = pos;
                for (m = 0; m < 2; m++) {
                        saw = state[n].state[m];
 
index eb87fce..989cb5b 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 /*
  * These are the standardized defaults.
@@ -68,9 +71,12 @@ const struct http2_settings lws_h2_stock_settings = { {
         *
         * Can't pass h2spec with less than 4096 here...
         */
-       /* H2SET_ENABLE_PUSH */                            1,
+       /* H2SET_ENABLE_PUSH */                            0,
        /* H2SET_MAX_CONCURRENT_STREAMS */                24,
-       /* H2SET_INITIAL_WINDOW_SIZE */                65535,
+       /* H2SET_INITIAL_WINDOW_SIZE */                    0,
+       /*< This is managed by explicit WINDOW_UPDATE.  Because otherwise no
+        * way to precisely control it when we do want to.
+        */
        /* H2SET_MAX_FRAME_SIZE */                     16384,
        /* H2SET_MAX_HEADER_LIST_SIZE */                4096,
        /*< This advisory setting informs a peer of the maximum size of
@@ -84,7 +90,8 @@ const struct http2_settings lws_h2_stock_settings = { {
 }};
 
 /*
- * The wsi at this level is the network wsi
+ * The wsi at this level is normally the network wsi... we can get called on
+ * another path via lws_service_do_ripe_rxflow() on mux children too tho...
  */
 
 static int
@@ -106,8 +113,20 @@ rops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi,
        }
 #endif
 
-        lwsl_info("%s: wsistate 0x%x, pollout %d\n", __func__,
-                  wsi->wsistate, pollfd->revents & LWS_POLLOUT);
+        lwsl_info("%s: %s wsistate 0x%x, events %d, revents %d, pollout %d\n", __func__,
+                  wsi->lc.gutag, (unsigned int)wsi->wsistate,
+                  pollfd->events, pollfd->revents,
+                  pollfd->revents & LWS_POLLOUT);
+
+        /* !!! */
+        if (wsi->wsistate == 0x10000013) {
+                wsi->bugcatcher++;
+                if (wsi->bugcatcher == 250) {
+                        lwsl_err("%s: BUGCATCHER\n", __func__);
+                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
+                }
+        } else
+                wsi->bugcatcher = 0;
 
        /*
         * something went wrong with parsing the handshake, and
@@ -119,14 +138,14 @@ rops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi,
        }
 
        if (lwsi_state(wsi) == LRS_WAITING_CONNECT) {
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
                if ((pollfd->revents & LWS_POLLOUT) &&
                    lws_handle_POLLOUT_event(wsi, pollfd)) {
                        lwsl_debug("POLLOUT event closed it\n");
                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
                }
 
-               n = lws_client_socket_service(wsi, pollfd, NULL);
+               n = lws_http_client_socket_service(wsi, pollfd);
                if (n)
                        return LWS_HPI_RET_WSI_ALREADY_DIED;
 #endif
@@ -161,9 +180,11 @@ rops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi,
 #endif
        }
 
-       if (wsi->http2_substream || wsi->upgraded_to_http2) {
+       if (wsi->mux_substream || wsi->upgraded_to_http2) {
                wsi1 = lws_get_network_wsi(wsi);
-               if (wsi1 && lws_has_buffered_out(wsi1))
+               if (wsi1 && lws_has_buffered_out(wsi1)) {
+
+                       lwsl_info("%s: has buffered out\n", __func__);
                        /*
                         * We cannot deal with any kind of new RX
                         * because we are dealing with a partial send
@@ -171,12 +192,13 @@ rops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi,
                         * expect to be able to send)
                         */
                        return LWS_HPI_RET_HANDLED;
+               }
        }
 
 read:
        /* 3: network wsi buflist needs to be drained */
 
-       // lws_buflist_describe(&wsi->buflist, wsi);
+       // lws_buflist_describe(&wsi->buflist, wsi, __func__);
 
        ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist,
                                                &ebuf.token);
@@ -184,20 +206,31 @@ read:
                lwsl_info("draining buflist (len %d)\n", ebuf.len);
                buffered = 1;
                goto drain;
+       } else {
+
+               if (wsi->mux_substream) {
+                       lwsl_warn("%s: uh... %s mux child with nothing to drain\n", __func__, lws_wsi_tag(wsi));
+                       // assert(0);
+                       lws_dll2_remove(&wsi->dll_buflist);
+                       return LWS_HPI_RET_HANDLED;
+               }
        }
 
        if (!lws_ssl_pending(wsi) &&
            !(pollfd->revents & pollfd->events & LWS_POLLIN))
                return LWS_HPI_RET_HANDLED;
 
+       /* We have something to read... */
+
        if (!(lwsi_role_client(wsi) &&
              (lwsi_state(wsi) != LRS_ESTABLISHED &&
+              // lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2 &&
               lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS))) {
 
                ebuf.token = pt->serv_buf;
                ebuf.len = lws_ssl_capable_read(wsi,
                                        ebuf.token,
-                                       wsi->context->pt_serv_buf_size);
+                                       wsi->a.context->pt_serv_buf_size);
                switch (ebuf.len) {
                case 0:
                        lwsl_info("%s: zero length read\n", __func__);
@@ -213,13 +246,14 @@ read:
                // lwsl_notice("%s: Actual RX %d\n", __func__, ebuf.len);
                // if (ebuf.len > 0)
                //      lwsl_hexdump_notice(ebuf.token, ebuf.len);
-       }
+       } else
+               lwsl_info("%s: skipped read\n", __func__);
 
        if (ebuf.len < 0)
                return LWS_HPI_RET_PLEASE_CLOSE_ME;
 
 drain:
-#ifndef LWS_NO_CLIENT
+#if defined(LWS_WITH_CLIENT)
        if (lwsi_role_http(wsi) && lwsi_role_client(wsi) &&
            wsi->hdr_parsing_completed && !wsi->told_user_closed) {
 
@@ -242,7 +276,7 @@ drain:
                 * callback and drain / re-enable it there
                 */
                if (user_callback_handle_rxflow(
-                               wsi->protocol->callback,
+                               wsi->a.protocol->callback,
                                wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
                                wsi->user_space, NULL, 0)) {
                        lwsl_info("RECEIVE_CLIENT_HTTP closed it\n");
@@ -259,42 +293,44 @@ drain:
                n = 0;
                if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY &&
                    lwsi_state(wsi) != LRS_DISCARD_BODY)
-                       n = lws_read_h2(wsi, ebuf.token, ebuf.len);
+                       n = lws_read_h2(wsi, ebuf.token, (unsigned int)ebuf.len);
                else
-                       n = lws_read_h1(wsi, ebuf.token, ebuf.len);
+                       n = lws_read_h1(wsi, ebuf.token, (unsigned int)ebuf.len);
 
                if (n < 0) {
                        /* we closed wsi */
-                       n = 0;
                        return LWS_HPI_RET_WSI_ALREADY_DIED;
                }
 
                if (n && buffered) {
-                       m = lws_buflist_use_segment(&wsi->buflist, n);
+                       // lwsl_notice("%s: h2 use %d\n", __func__, n);
+                       m = (int)lws_buflist_use_segment(&wsi->buflist, (size_t)n);
                        lwsl_info("%s: draining rxflow: used %d, next %d\n",
                                    __func__, n, m);
                        if (!m) {
-                               lwsl_notice("%s: removed %p from dll_buflist\n",
-                                           __func__, wsi);
+                               lwsl_notice("%s: removed %s from dll_buflist\n",
+                                           __func__, lws_wsi_tag(wsi));
                                lws_dll2_remove(&wsi->dll_buflist);
                        }
                } else
-                       if (n && n != ebuf.len) {
+                       if (n && n < ebuf.len && ebuf.len > 0) {
+                               // lwsl_notice("%s: h2 append seg %d\n", __func__, ebuf.len - n);
                                m = lws_buflist_append_segment(&wsi->buflist,
                                                ebuf.token + n,
-                                               ebuf.len - n);
+                                               (unsigned int)(ebuf.len - n));
                                if (m < 0)
                                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
                                if (m) {
-                                       lwsl_debug("%s: added %p to rxflow list\n",
-                                                       __func__, wsi);
-                                       lws_dll2_add_head(&wsi->dll_buflist,
+                                       lwsl_debug("%s: added %s to rxflow list\n",
+                                                  __func__, lws_wsi_tag(wsi));
+                                       if (lws_dll2_is_detached(&wsi->dll_buflist))
+                                               lws_dll2_add_head(&wsi->dll_buflist,
                                                         &pt->dll_buflist_owner);
                                }
                        }
        }
 
-       // lws_buflist_describe(&wsi->buflist, wsi);
+       // lws_buflist_describe(&wsi->buflist, wsi, __func__);
 
 #if 0
 
@@ -305,7 +341,7 @@ drain:
         */
 
        if (wsi->http.ah
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
                        && !wsi->client_h2_alpn
 #endif
                        ) {
@@ -315,7 +351,7 @@ drain:
        }
 #endif
 
-       pending = lws_ssl_pending(wsi);
+       pending = (unsigned int)lws_ssl_pending(wsi);
        if (pending) {
                // lwsl_info("going around\n");
                goto read;
@@ -332,10 +368,10 @@ int rops_handle_POLLOUT_h2(struct lws *wsi)
                return LWS_HP_RET_USER_SERVICE;
 
        /*
-        * Priority 2: H2 protocol packets
+        * Priority 1: H2 protocol packets
         */
        if ((wsi->upgraded_to_http2
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
                        || wsi->client_h2_alpn
 #endif
                        ) && wsi->h2.h2n->pps) {
@@ -358,7 +394,7 @@ int rops_handle_POLLOUT_h2(struct lws *wsi)
                return LWS_HP_RET_BAIL_OK; /* leave POLLOUT active */
        }
 
-       /* Priority 4: if we are closing, not allowed to send more data frags
+       /* Priority 2: if we are closing, not allowed to send more data frags
         *             which means user callback or tx ext flush banned now
         */
        if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
@@ -380,20 +416,24 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
 
        /* if not in a state to send stuff, then just send nothing */
 
-       if (!lwsi_role_ws(wsi) &&
+       if (!lwsi_role_ws(wsi) && !wsi->mux_stream_immortal &&
            base != LWS_WRITE_HTTP &&
            base != LWS_WRITE_HTTP_FINAL &&
            base != LWS_WRITE_HTTP_HEADERS_CONTINUATION &&
-           base != LWS_WRITE_HTTP_HEADERS &&
+           base != LWS_WRITE_HTTP_HEADERS && lwsi_state(wsi) != LRS_BODY &&
            ((lwsi_state(wsi) != LRS_RETURNED_CLOSE &&
              lwsi_state(wsi) != LRS_WAITING_TO_SEND_CLOSE &&
+             lwsi_state(wsi) != LRS_ESTABLISHED &&
              lwsi_state(wsi) != LRS_AWAITING_CLOSE_ACK)
 #if defined(LWS_ROLE_WS)
           || base != LWS_WRITE_CLOSE
 #endif
        )) {
                //assert(0);
-               lwsl_notice("binning wsistate 0x%x %d\n", wsi->wsistate, *wp);
+               lwsl_notice("%s: binning wsistate 0x%x %d: %s\n", __func__,
+                               (unsigned int)wsi->wsistate, *wp, wsi->a.protocol ?
+                                       wsi->a.protocol->name : "no protocol");
+
                return 0;
        }
 
@@ -408,9 +448,9 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
                if (n)
                        return n;
 
-               lwsl_info("%s: %p: transformed %d bytes to %d "
+               lwsl_info("%s: %s: transformed %d bytes to %d "
                           "(wp 0x%x, more %d)\n", __func__,
-                          wsi, (int)len, (int)o, (int)*wp,
+                          lws_wsi_tag(wsi), (int)len, (int)o, (int)*wp,
                           wsi->http.comp_ctx.may_have_more);
 
                buf = out;
@@ -418,7 +458,7 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
                base = (*wp) & 0x1f;
 
                if (!len)
-                       return olen;
+                       return (int)olen;
        }
 #endif
 
@@ -453,7 +493,8 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
             base == LWS_WRITE_HTTP_FINAL) &&
             wsi->http.tx_content_length) {
                wsi->http.tx_content_remain -= len;
-               lwsl_info("%s: wsi %p: tx_content_rem = %llu\n", __func__, wsi,
+               lwsl_info("%s: %s: tx_content_rem = %llu\n", __func__,
+                         lws_wsi_tag(wsi),
                          (unsigned long long)wsi->http.tx_content_remain);
                if (!wsi->http.tx_content_remain) {
                        lwsl_info("%s: selecting final write mode\n", __func__);
@@ -462,12 +503,13 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
        }
 
        if (base == LWS_WRITE_HTTP_FINAL || ((*wp) & LWS_WRITE_H2_STREAM_END)) {
-               lwsl_info("%s: %p: setting END_STREAM\n", __func__, wsi);
                flags |= LWS_H2_FLAG_END_STREAM;
+               lwsl_info("%s: %s: setting END_STREAM, 0x%x\n", __func__,
+                               lws_wsi_tag(wsi), flags);
                wsi->h2.send_END_STREAM = 1;
        }
 
-       n = lws_h2_frame_write(wsi, n, flags, wsi->h2.my_sid, (int)len, buf);
+       n = lws_h2_frame_write(wsi, n, flags, wsi->mux.my_sid, (unsigned int)len, buf);
        if (n < 0)
                return n;
 
@@ -476,11 +518,11 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
        return (int)olen;
 }
 
+#if defined(LWS_WITH_SERVER)
 static int
 rops_check_upgrades_h2(struct lws *wsi)
 {
 #if defined(LWS_ROLE_WS)
-       struct lws *nwsi;
        char *p;
 
        /*
@@ -490,27 +532,23 @@ rops_check_upgrades_h2(struct lws *wsi)
         * SETTINGS saying that we support it though.
         */
        p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
-       if (!wsi->vhost->h2.set.s[H2SET_ENABLE_CONNECT_PROTOCOL] ||
-           !wsi->http2_substream || !p || strcmp(p, "CONNECT"))
+       if (!wsi->a.vhost->h2.set.s[H2SET_ENABLE_CONNECT_PROTOCOL] ||
+           !wsi->mux_substream || !p || strcmp(p, "CONNECT"))
                return LWS_UPG_RET_CONTINUE;
 
        p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_COLON_PROTOCOL);
        if (!p || strcmp(p, "websocket"))
                return LWS_UPG_RET_CONTINUE;
 
-       nwsi = lws_get_network_wsi(wsi);
-
-       wsi->vhost->conn_stats.ws_upg++;
        lwsl_info("Upgrade h2 to ws\n");
+       lws_mux_mark_immortal(wsi);
        wsi->h2_stream_carries_ws = 1;
-       nwsi->immortal_substream_count++;
+
+       lws_metrics_tag_wsi_add(wsi, "upg", "ws_over_h2");
+
        if (lws_process_ws_upgrade(wsi))
                return LWS_UPG_RET_BAIL;
 
-       if (nwsi->immortal_substream_count == 1)
-               lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
-
-       lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
        lwsl_info("Upgraded h2 to ws OK\n");
 
        return LWS_UPG_RET_DONE;
@@ -518,6 +556,7 @@ rops_check_upgrades_h2(struct lws *wsi)
        return LWS_UPG_RET_CONTINUE;
 #endif
 }
+#endif
 
 static int
 rops_init_vhost_h2(struct lws_vhost *vh,
@@ -534,52 +573,85 @@ rops_init_vhost_h2(struct lws_vhost *vh,
        return 0;
 }
 
-static int
-rops_init_context_h2(struct lws_context *context,
-                    const struct lws_context_creation_info *info)
+int
+rops_pt_init_destroy_h2(struct lws_context *context,
+                   const struct lws_context_creation_info *info,
+                   struct lws_context_per_thread *pt, int destroy)
 {
-       int n;
-
-       context->set = lws_h2_stock_settings;
+       /* if not already set by plat, use lws default SETTINGS */
+       if (!context->set.s[0])
+               context->set = lws_h2_stock_settings;
 
        /*
         * We only want to do this once... we will do it if we are built
         * otherwise h1 ops will do it (or nobody if no http at all)
         */
-
-       for (n = 0; n < context->count_threads; n++) {
-               struct lws_context_per_thread *pt = &context->pt[n];
+#if !defined(LWS_ROLE_H2) && defined(LWS_WITH_SERVER)
+       if (!destroy) {
 
                pt->sul_ah_lifecheck.cb = lws_sul_http_ah_lifecheck;
 
-               __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_ah_lifecheck,
-                                30 * LWS_US_PER_SEC);
-       }
+               __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                                &pt->sul_ah_lifecheck, 30 * LWS_US_PER_SEC);
+       } else
+               lws_dll2_remove(&pt->sul_ah_lifecheck.list);
+#endif
 
        return 0;
 }
 
-static lws_fileofs_t
-rops_tx_credit_h2(struct lws *wsi)
+
+static int
+rops_tx_credit_h2(struct lws *wsi, char peer_to_us, int add)
 {
-       return lws_h2_tx_cr_get(wsi);
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+       int n;
+
+       if (add) {
+               if (peer_to_us == LWSTXCR_PEER_TO_US) {
+                       /*
+                        * We want to tell the peer they can write an additional
+                        * "add" bytes to us
+                        */
+                       return lws_h2_update_peer_txcredit(wsi, (unsigned int)-1, add);
+               }
+
+               /*
+                * We're being told we can write an additional "add" bytes
+                * to the peer
+                */
+
+               wsi->txc.tx_cr += add;
+               nwsi->txc.tx_cr += add;
+
+               return 0;
+       }
+
+       if (peer_to_us == LWSTXCR_US_TO_PEER)
+               return lws_h2_tx_cr_get(wsi);
+
+       n = wsi->txc.peer_tx_cr_est;
+       if (n > nwsi->txc.peer_tx_cr_est)
+               n = nwsi->txc.peer_tx_cr_est;
+
+       return n;
 }
 
 static int
 rops_destroy_role_h2(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        struct allocated_headers *ah;
 
        /* we may not have an ah, but may be on the waiting list... */
-       lwsl_info("%s: ah det due to close\n", __func__);
+       lwsl_info("%s: %s: ah det due to close\n", __func__, lws_wsi_tag(wsi));
        __lws_header_table_detach(wsi, 0);
 
        ah = pt->http.ah_list;
 
        while (ah) {
                if (ah->in_use && ah->wsi == wsi) {
-                       lwsl_err("%s: ah leak: wsi %p\n", __func__, wsi);
+                       lwsl_err("%s: ah leak: %s\n", __func__, lws_wsi_tag(wsi));
                        ah->in_use = 0;
                        ah->wsi = NULL;
                        pt->http.ah_count_in_use--;
@@ -592,7 +664,7 @@ rops_destroy_role_h2(struct lws *wsi)
        lws_http_compression_destroy(wsi);
 #endif
 
-       if (wsi->upgraded_to_http2 || wsi->http2_substream) {
+       if (wsi->upgraded_to_http2 || wsi->mux_substream) {
                lws_hpack_destroy_dynamic_header(wsi);
 
                if (wsi->h2.h2n)
@@ -605,65 +677,43 @@ rops_destroy_role_h2(struct lws *wsi)
 static int
 rops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason)
 {
-       struct lws *wsi2;
 
 #if defined(LWS_WITH_HTTP_PROXY)
        if (wsi->http.proxy_clientside) {
-               struct lws *wsi_eff = lws_client_wsi_effective(wsi);
 
                wsi->http.proxy_clientside = 0;
 
-               if (user_callback_handle_rxflow(wsi_eff->protocol->callback,
-                                               wsi_eff,
+               if (user_callback_handle_rxflow(wsi->a.protocol->callback,
+                                               wsi,
                                            LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
-                                               wsi_eff->user_space, NULL, 0))
+                                               wsi->user_space, NULL, 0))
                        wsi->http.proxy_clientside = 0;
        }
 #endif
 
-       if (wsi->http2_substream && wsi->h2_stream_carries_ws)
+       if (wsi->mux_substream && wsi->h2_stream_carries_ws)
                lws_h2_rst_stream(wsi, 0, "none");
+/*     else
+               if (wsi->mux_substream)
+                       lws_h2_rst_stream(wsi, H2_ERR_STREAM_CLOSED, "swsi got closed");
+*/
 
-       if (wsi->h2.parent_wsi && lwsl_visible(LLL_INFO)) {
-               lwsl_info(" wsi: %p, his parent %p: siblings:\n", wsi,
-                         wsi->h2.parent_wsi);
-               lws_start_foreach_llp(struct lws **, w,
-                                     wsi->h2.parent_wsi->h2.child_list) {
-                       lwsl_info("   \\---- child %s %p\n",
-                                 (*w)->role_ops ? (*w)->role_ops->name : "?", *w);
-               } lws_end_foreach_llp(w, h2.sibling_list);
-       }
+       lwsl_info(" %s, his parent %s: siblings:\n", lws_wsi_tag(wsi), lws_wsi_tag(wsi->mux.parent_wsi));
+       lws_wsi_mux_dump_children(wsi);
 
-       if (wsi->upgraded_to_http2 || wsi->http2_substream
-#if !defined(LWS_NO_CLIENT)
-                       || wsi->client_h2_substream
+       if (wsi->upgraded_to_http2 || wsi->mux_substream
+#if defined(LWS_WITH_CLIENT)
+                       || wsi->client_mux_substream
 #endif
        ) {
-               lwsl_info("closing %p: parent %p\n", wsi, wsi->h2.parent_wsi);
-
-               if (wsi->h2.child_list && lwsl_visible(LLL_INFO)) {
-                       lwsl_info(" parent %p: closing children: list:\n", wsi);
-                       lws_start_foreach_llp(struct lws **, w,
-                                             wsi->h2.child_list) {
-                               lwsl_info("   \\---- child %s %p\n",
-                                         (*w)->role_ops ? (*w)->role_ops->name : "?",
-                                         *w);
-                       } lws_end_foreach_llp(w, h2.sibling_list);
-               }
-               if (wsi->h2.child_list) {
-                       /* trigger closing of all of our http2 children first */
-                       lws_start_foreach_llp(struct lws **, w,
-                                             wsi->h2.child_list) {
-                               lwsl_info("   closing child %p\n", *w);
-                               /* disconnect from siblings */
-                               wsi2 = (*w)->h2.sibling_list;
-                               (*w)->h2.sibling_list = NULL;
-                               (*w)->socket_is_permanently_unusable = 1;
-                               __lws_close_free_wsi(*w, reason, "h2 child recurse");
-                               *w = wsi2;
-                               continue;
-                       } lws_end_foreach_llp(w, h2.sibling_list);
+               lwsl_info("closing %s: parent %s\n", lws_wsi_tag(wsi),
+                               lws_wsi_tag(wsi->mux.parent_wsi));
+
+               if (wsi->mux.child_list && lwsl_visible(LLL_INFO)) {
+                       lwsl_info(" parent %s: closing children: list:\n", lws_wsi_tag(wsi));
+                       lws_wsi_mux_dump_children(wsi);
                }
+               lws_wsi_mux_close_children(wsi, (int)reason);
        }
 
        if (wsi->upgraded_to_http2) {
@@ -679,99 +729,62 @@ rops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason)
        }
 
        if ((
-#if !defined(LWS_NO_CLIENT)
-                       wsi->client_h2_substream ||
+#if defined(LWS_WITH_CLIENT)
+                       wsi->client_mux_substream ||
 #endif
-                       wsi->http2_substream) &&
-            wsi->h2.parent_wsi) {
-               lwsl_info("  %p: disentangling from siblings\n", wsi);
-               lws_start_foreach_llp(struct lws **, w,
-                               wsi->h2.parent_wsi->h2.child_list) {
-                       /* disconnect from siblings */
-                       if (*w == wsi) {
-                               wsi2 = (*w)->h2.sibling_list;
-                               (*w)->h2.sibling_list = NULL;
-                               *w = wsi2;
-                               lwsl_info("  %p disentangled from sibling %p\n",
-                                         wsi, wsi2);
-                               break;
-                       }
-               } lws_end_foreach_llp(w, h2.sibling_list);
-               wsi->h2.parent_wsi->h2.child_count--;
-               wsi->h2.parent_wsi = NULL;
+                       wsi->mux_substream) &&
+            wsi->mux.parent_wsi) {
+               lws_wsi_mux_sibling_disconnect(wsi);
                if (wsi->h2.pending_status_body)
                        lws_free_set_NULL(wsi->h2.pending_status_body);
        }
 
-       if (wsi->h2_stream_carries_ws || wsi->h2_stream_carries_sse) {
-               struct lws *nwsi = lws_get_network_wsi(wsi);
-
-               nwsi->immortal_substream_count--;
-               /* if no ws, then put a timeout on the parent wsi */
-               if (!nwsi->immortal_substream_count)
-                       __lws_set_timeout(nwsi,
-                               PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
-       }
-
        return 0;
 }
 
 static int
 rops_callback_on_writable_h2(struct lws *wsi)
 {
-       struct lws *network_wsi, *wsi2;
+#if defined(LWS_WITH_CLIENT)
+       struct lws *network_wsi;
+#endif
        int already;
 
-       //lwsl_notice("%s: %p (wsistate 0x%x)\n", __func__, wsi, wsi->wsistate);
-
 //     if (!lwsi_role_h2(wsi) && !lwsi_role_h2_ENCAPSULATION(wsi))
 //             return 0;
 
-       if (wsi->h2.requested_POLLOUT
-#if !defined(LWS_NO_CLIENT)
+       if (wsi->mux.requested_POLLOUT
+#if defined(LWS_WITH_CLIENT)
                        && !wsi->client_h2_alpn
 #endif
        ) {
                lwsl_debug("already pending writable\n");
-               return 1;
+               // return 1;
        }
 
        /* is this for DATA or for control messages? */
+
        if (wsi->upgraded_to_http2 && !wsi->h2.h2n->pps &&
-           !lws_h2_tx_cr_get(wsi)) {
+           lws_wsi_txc_check_skint(&wsi->txc, lws_h2_tx_cr_get(wsi))) {
                /*
-                * other side is not able to cope with us sending DATA
-                * anything so no matter if we have POLLOUT on our side if it's
-                * DATA we want to send.
-                *
-                * Delay waiting for our POLLOUT until peer indicates he has
-                * space for more using tx window command in http2 layer
+                * refuse his efforts to get WRITABLE if we have no credit and
+                * no non-DATA pps to send
                 */
-               lwsl_notice("%s: %p: skint (%d)\n", __func__, wsi,
-                           wsi->h2.tx_cr);
-               wsi->h2.skint = 1;
+               lwsl_err("%s: skint\n", __func__);
                return 0;
        }
 
-       wsi->h2.skint = 0;
+#if defined(LWS_WITH_CLIENT)
        network_wsi = lws_get_network_wsi(wsi);
-       already = network_wsi->h2.requested_POLLOUT;
-
-       /* mark everybody above him as requesting pollout */
-
-       wsi2 = wsi;
-       while (wsi2) {
-               wsi2->h2.requested_POLLOUT = 1;
-               lwsl_info("mark %p pending writable\n", wsi2);
-               wsi2 = wsi2->h2.parent_wsi;
-       }
+#endif
+       already = lws_wsi_mux_mark_parents_needing_writeable(wsi);
 
        /* for network action, act only on the network wsi */
 
        if (already
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
                        && !network_wsi->client_h2_alpn
-                       && !network_wsi->client_h2_substream
+                       && !network_wsi->client_mux_substream
 #endif
                        )
                return 1;
@@ -779,65 +792,119 @@ rops_callback_on_writable_h2(struct lws *wsi)
        return 0;
 }
 
-static void
-lws_h2_dump_waiting_children(struct lws *wsi)
-{
-#if defined(_DEBUG)
-       lwsl_info("%s: %p: children waiting for POLLOUT service:\n",
-                 __func__, wsi);
-
-       wsi = wsi->h2.child_list;
-       while (wsi) {
-               lwsl_info("  %c %p %s %s\n",
-                         wsi->h2.requested_POLLOUT ? '*' : ' ',
-                         wsi, wsi->role_ops->name, wsi->protocol->name);
-
-               wsi = wsi->h2.sibling_list;
-       }
-#endif
-}
-
+#if defined(LWS_WITH_SERVER)
 static int
 lws_h2_bind_for_post_before_action(struct lws *wsi)
 {
+       const struct lws_http_mount *hit;
+       char *uri_ptr = NULL;
+       uint8_t *buffered;
+       int uri_len = 0;
        const char *p;
+       size_t blen;
 
        p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
-       if (p && !strcmp(p, "POST")) {
-               const struct lws_http_mount *hit =
-                               lws_find_mount(wsi,
-                                       lws_hdr_simple_ptr(wsi,
-                                           WSI_TOKEN_HTTP_COLON_PATH),
-                                       lws_hdr_total_length(wsi,
-                                           WSI_TOKEN_HTTP_COLON_PATH));
-
-               lwsl_debug("%s: %s: hit %p: %s\n", __func__,
-                           lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH),
-                           hit, hit ? hit->origin : "null");
-               if (hit) {
-                       const struct lws_protocols *pp;
-                       const char *name = hit->origin;
-
-                       if (hit->protocol)
-                               name = hit->protocol;
-
-                       pp = lws_vhost_name_to_protocol(wsi->vhost, name);
-                       if (!pp) {
-                               lwsl_info("Unable to find protocol '%s'\n", name);
-                               return 1;
-                       }
+       if (!p || strcmp(p, "POST"))
+               return 0;
 
-                       if (lws_bind_protocol(wsi, pp, __func__))
-                               return 1;
+
+       if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH) ||
+           !lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH))
+               /*
+                * There must be a path.  Actually this is checked at
+                * http2.c along with the other required header
+                * presence before we can get here.
+                *
+                * But Coverity insists to see us check it.
+                */
+               return 1;
+
+       hit = lws_find_mount(wsi,
+                 lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH),
+                 lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH));
+
+       lwsl_debug("%s: %s: hit %p: %s\n", __func__,
+                   lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH),
+                   hit, hit ? hit->origin : "null");
+       if (hit) {
+               const struct lws_protocols *pp;
+               const char *name = hit->origin;
+
+               if (hit->origin_protocol == LWSMPRO_CGI ||
+                   hit->origin_protocol == LWSMPRO_HTTP ||
+                   hit->origin_protocol == LWSMPRO_HTTPS)
+                       return 0;
+
+               if (hit->protocol)
+                       name = hit->protocol;
+               else
+                       if (hit->origin_protocol == LWSMPRO_FILE)
+                               return 0;
+
+               pp = lws_vhost_name_to_protocol(wsi->a.vhost, name);
+               if (!pp) {
+                       lwsl_info("Unable to find protocol '%s'\n", name);
+                       return 1;
                }
 
-               lwsl_info("%s: setting LRS_BODY from 0x%x (%s)\n", __func__,
-                           wsi->wsistate, wsi->protocol->name);
-               lwsi_set_state(wsi, LRS_BODY);
+               if (lws_bind_protocol(wsi, pp, __func__))
+                       return 1;
        }
+       if (lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len) >= 0)
+               if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
+                                             wsi->user_space,
+                                             hit ? uri_ptr +
+                                                 hit->mountpoint_len : uri_ptr,
+                                             (size_t)(hit ? uri_len -
+                                                         hit->mountpoint_len :
+                                                         uri_len)))
+                       return 1;
+
+       lwsl_info("%s: setting LRS_BODY from 0x%x (%s)\n", __func__,
+                   (int)wsi->wsistate, wsi->a.protocol->name);
+
+       lwsi_set_state(wsi, LRS_BODY);
+
+       if (wsi->http.content_length_explicitly_zero)
+               return 0;
+
+       /*
+        * Dump any stashed body
+        */
+
+       while (((!wsi->http.content_length_given) ||
+                 wsi->http.rx_content_length) &&
+              (blen = lws_buflist_next_segment_len(&wsi->buflist, &buffered))) {
+
+               if ((size_t)wsi->http.rx_content_length < blen)
+                       blen = (size_t)wsi->http.rx_content_length;
+
+               if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY,
+                               wsi->user_space, buffered, blen))
+                       return 1;
+               lws_buflist_use_segment(&wsi->buflist, blen);
+
+               wsi->http.rx_content_length -= blen;
+       }
+
+       if (!wsi->buflist)
+               /* Take us off the pt's "wsi holding input buflist" list */
+               lws_dll2_remove(&wsi->dll_buflist);
+
+       if (wsi->http.content_length_given && wsi->http.rx_content_length)
+               /* still a-ways to go */
+               return 0;
+
+       if (!wsi->http.content_length_given && !wsi->h2.END_STREAM)
+               return 0;
+
+       if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY_COMPLETION,
+                                     wsi->user_space, NULL, 0))
+               return 1;
 
        return 0;
 }
+#endif
 
 /*
  * we are the 'network wsi' for potentially many muxed child wsi with
@@ -855,7 +922,7 @@ lws_h2_bind_for_post_before_action(struct lws *wsi)
 static int
 rops_perform_user_POLLOUT_h2(struct lws *wsi)
 {
-       struct lws **wsi2, *wsi2a;
+       struct lws **wsi2;
 #if defined(LWS_ROLE_WS)
        int write_type = LWS_WRITE_PONG;
 #endif
@@ -863,23 +930,23 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
 
        wsi = lws_get_network_wsi(wsi);
 
-       wsi->h2.requested_POLLOUT = 0;
-       if (!wsi->h2.initialized) {
-               lwsl_info("pollout on uninitialized http2 conn\n");
-               return 0;
-       }
+       wsi->mux.requested_POLLOUT = 0;
+//     if (!wsi->h2.initialized) {
+//             lwsl_info("pollout on uninitialized http2 conn\n");
+//             return 0;
+//     }
 
-       lws_h2_dump_waiting_children(wsi);
+       lws_wsi_mux_dump_waiting_children(wsi);
 
-       wsi2 = &wsi->h2.child_list;
+       wsi2 = &wsi->mux.child_list;
        if (!*wsi2)
                return 0;
 
        do {
                struct lws *w, **wa;
 
-               wa = &(*wsi2)->h2.sibling_list;
-               if (!(*wsi2)->h2.requested_POLLOUT)
+               wa = &(*wsi2)->mux.sibling_list;
+               if (!(*wsi2)->mux.requested_POLLOUT)
                        goto next_child;
 
                /*
@@ -887,36 +954,18 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                 * move him to be the last child
                 */
 
-               lwsl_debug("servicing child %p\n", *wsi2);
+               lwsl_debug("servicing child %s\n", lws_wsi_tag(*wsi2));
 
-               w = *wsi2;
-               while (w) {
-                       if (!w->h2.sibling_list) { /* w is the current last */
-                               lwsl_debug("w=%p, *wsi2 = %p\n", w, *wsi2);
-                               if (w == *wsi2) /* we are already last */
-                                       break;
-                               /* last points to us as new last */
-                               w->h2.sibling_list = *wsi2;
-                               /* guy pointing to us until now points to
-                                * our old next */
-                               *wsi2 = (*wsi2)->h2.sibling_list;
-                               /* we point to nothing because we are last */
-                               w->h2.sibling_list->h2.sibling_list = NULL;
-                               /* w becomes us */
-                               w = w->h2.sibling_list;
-                               break;
-                       }
-                       w = w->h2.sibling_list;
-               }
+               w = lws_wsi_mux_move_child_to_tail(wsi2);
 
                if (!w) {
-                       wa = &wsi->h2.child_list;
+                       wa = &wsi->mux.child_list;
                        goto next_child;
                }
 
-               w->h2.requested_POLLOUT = 0;
-               lwsl_info("%s: child %p (wsistate 0x%x)\n", __func__, w,
-                         w->wsistate);
+               lwsl_info("%s: child %s, sid %d, (wsistate 0x%x)\n",
+                         __func__, lws_wsi_tag(w), w->mux.my_sid,
+                         (unsigned int)w->wsistate);
 
                /* priority 1: post compression-transform buffered output */
 
@@ -926,11 +975,11 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                                lwsl_info("%s signalling to close\n", __func__);
                                lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
                                                   "h2 end stream 1");
-                               wa = &wsi->h2.child_list;
+                               wa = &wsi->mux.child_list;
                                goto next_child;
                        }
                        lws_callback_on_writable(w);
-                       wa = &wsi->h2.child_list;
+                       wa = &wsi->mux.child_list;
                        goto next_child;
                }
 
@@ -952,7 +1001,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                                                   "comp write fail");
                        }
                        lws_callback_on_writable(w);
-                       wa = &wsi->h2.child_list;
+                       wa = &wsi->mux.child_list;
                        goto next_child;
                }
 #endif
@@ -963,7 +1012,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                        w->socket_is_permanently_unusable = 1;
                        lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
                                           "h2 end stream 1");
-                       wa = &wsi->h2.child_list;
+                       wa = &wsi->mux.child_list;
                        goto next_child;
                }
 
@@ -980,17 +1029,20 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                        lws_free_set_NULL(w->h2.pending_status_body);
                        lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
                                           "h2 end stream 1");
-                       wa = &wsi->h2.child_list;
+                       wa = &wsi->mux.child_list;
                        goto next_child;
                }
 
+#if defined(LWS_WITH_CLIENT)
                if (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS) {
                        if (lws_h2_client_handshake(w))
                                return -1;
 
                        goto next_child;
                }
+#endif
 
+#if defined(LWS_WITH_SERVER)
                if (lwsi_state(w) == LRS_DEFERRING_ACTION) {
 
                        /*
@@ -1002,7 +1054,31 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
 
                        lwsi_set_state(w, LRS_ESTABLISHED);
 
-                       lws_h2_bind_for_post_before_action(w);
+                       if (w->buflist) {
+                               struct lws_context_per_thread *pt;
+
+                               pt = &w->a.context->pt[(int)w->tsi];
+                               lwsl_debug("%s: added %s to rxflow list\n",
+                                          __func__, lws_wsi_tag(w));
+                               lws_dll2_add_head(
+                                       &w->dll_buflist,
+                                       &pt->dll_buflist_owner);
+                       }
+
+                       if (lws_h2_bind_for_post_before_action(w))
+                               return -1;
+
+                       /*
+                        * Well, we could be getting a POST from the client, it
+                        * may not have any content-length.  In that case, we
+                        * will be in LRS_BODY state, we can't actually start
+                        * the action until we had the body and the stream is
+                        * half-closed, indicating that we can reply
+                        */
+
+                       if (lwsi_state(w) == LRS_BODY &&
+                           w->h2.h2_state != LWS_H2_STATE_HALF_CLOSED_REMOTE)
+                               goto next_child;
 
                        lwsl_info("  h2 action start...\n");
                        n = lws_http_action(w);
@@ -1024,17 +1100,25 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                                lwsl_info("closing stream after h2 action\n");
                                lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
                                                   "h2 end stream");
-                               wa = &wsi->h2.child_list;
+                               wa = &wsi->mux.child_list;
                        }
 
                        if (n < 0)
-                               wa = &wsi->h2.child_list;
+                               wa = &wsi->mux.child_list;
 
                        goto next_child;
                }
 
+#if defined(LWS_WITH_FILE_OPS)
+
                if (lwsi_state(w) == LRS_ISSUING_FILE) {
 
+                       if (lws_wsi_txc_check_skint(&w->txc,
+                                                   lws_h2_tx_cr_get(w))) {
+                               wa = &wsi->mux.child_list;
+                               goto next_child;
+                       }
+
                        ((volatile struct lws *)w)->leave_pollout_active = 0;
 
                        /* >0 == completion, <0 == error
@@ -1051,10 +1135,11 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                         * DATA here... if so close the actual wsi
                         */
                        if (n < 0 || w->h2.send_END_STREAM) {
-                               lwsl_debug("Closing POLLOUT child %p\n", w);
+                               lwsl_debug("Closing POLLOUT child %s\n",
+                                               lws_wsi_tag(w));
                                lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
                                                   "h2 end stream file");
-                               wa = &wsi->h2.child_list;
+                               wa = &wsi->mux.child_list;
                                goto next_child;
                        }
                        if (n > 0)
@@ -1062,11 +1147,13 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                                        return -1;
                        if (!n) {
                                lws_callback_on_writable(w);
-                               (w)->h2.requested_POLLOUT = 1;
+                               (w)->mux.requested_POLLOUT = 1;
                        }
 
                        goto next_child;
                }
+#endif
+#endif
 
 #if defined(LWS_ROLE_WS)
 
@@ -1093,7 +1180,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                 * then logically close ourself
                 */
 
-               if ((lwsi_role_ws(w) && w->ws->ping_pending_flag) ||
+               if ((lwsi_role_ws(w) && w->ws->pong_pending_flag) ||
                    (lwsi_state(w) == LRS_RETURNED_CLOSE &&
                     w->ws->payload_is_close)) {
 
@@ -1101,13 +1188,13 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                                write_type = LWS_WRITE_CLOSE |
                                             LWS_WRITE_H2_STREAM_END;
 
-                       n = lws_write(w, &w->ws->ping_payload_buf[LWS_PRE],
-                                     w->ws->ping_payload_len, write_type);
+                       n = lws_write(w, &w->ws->pong_payload_buf[LWS_PRE],
+                                     w->ws->pong_payload_len, (enum lws_write_protocol)write_type);
                        if (n < 0)
                                return -1;
 
                        /* well he is sent, mark him done */
-                       w->ws->ping_pending_flag = 0;
+                       w->ws->pong_pending_flag = 0;
                        if (w->ws->payload_is_close) {
                                /* oh... a close frame... then we are done */
                                lwsl_debug("Ack'd peer's close packet\n");
@@ -1115,23 +1202,47 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
                                lwsi_set_state(w, LRS_RETURNED_CLOSE);
                                lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
                                                   "returned close packet");
-                               wa = &wsi->h2.child_list;
+                               wa = &wsi->mux.child_list;
                                goto next_child;
                        }
 
                        lws_callback_on_writable(w);
-                       (w)->h2.requested_POLLOUT = 1;
+                       (w)->mux.requested_POLLOUT = 1;
 
                        /* otherwise for PING, leave POLLOUT active both ways */
                        goto next_child;
                }
 #endif
+
+               /*
+                * set client wsi to immortal long-poll mode; send END_STREAM
+                * flag on headers to indicate to a server, that allows
+                * it, that you want them to leave the stream in a long poll
+                * ro immortal state.  We have to send headers so the client
+                * understands the http connection is ongoing.
+                */
+
+               if (w->h2.send_END_STREAM && w->h2.long_poll) {
+                       uint8_t buf[LWS_PRE + 1];
+                       enum lws_write_protocol wp = 0;
+
+                       if (!rops_write_role_protocol_h2(w, buf + LWS_PRE, 0,
+                                                        &wp)) {
+                               lwsl_info("%s: %s: entering ro long poll\n",
+                                         __func__, lws_wsi_tag(w));
+                               lws_mux_mark_immortal(w);
+                       } else
+                               lwsl_err("%s: %s: failed to set long poll\n",
+                                               __func__, lws_wsi_tag(w));
+                       goto next_child;
+               }
+
                if (lws_callback_as_writeable(w)) {
                        lwsl_info("Closing POLLOUT child (end stream %d)\n",
                                  w->h2.send_END_STREAM);
                        lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
                                           "h2 pollout handle");
-                       wa = &wsi->h2.child_list;
+                       wa = &wsi->mux.child_list;
                } else
                         if (w->h2.send_END_STREAM)
                                lws_h2_state(w, LWS_H2_STATE_HALF_CLOSED_LOCAL);
@@ -1140,17 +1251,10 @@ next_child:
                wsi2 = wa;
        } while (wsi2 && *wsi2 && !lws_send_pipe_choked(wsi));
 
-       // lws_h2_dump_waiting_children(wsi);
+       // lws_wsi_mux_dump_waiting_children(wsi);
 
-       wsi2a = wsi->h2.child_list;
-       while (wsi2a) {
-               if (wsi2a->h2.requested_POLLOUT) {
-                       if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
-                               return -1;
-                       break;
-               }
-               wsi2a = wsi2a->h2.sibling_list;
-       }
+       if (lws_wsi_mux_action_pending_writeable_reqs(wsi))
+               return -1;
 
        return 0;
 }
@@ -1158,8 +1262,8 @@ next_child:
 static struct lws *
 rops_encapsulation_parent_h2(struct lws *wsi)
 {
-       if (wsi->h2.parent_wsi)
-               return wsi->h2.parent_wsi;
+       if (wsi->mux.parent_wsi)
+               return wsi->mux.parent_wsi;
 
        return NULL;
 }
@@ -1170,7 +1274,7 @@ rops_alpn_negotiated_h2(struct lws *wsi, const char *alpn)
        struct allocated_headers *ah;
 
        lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi));
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
        if (lwsi_role_client(wsi)) {
                lwsl_info("%s: upgraded to H2\n", __func__);
                wsi->client_h2_alpn = 1;
@@ -1178,13 +1282,12 @@ rops_alpn_negotiated_h2(struct lws *wsi, const char *alpn)
 #endif
 
        wsi->upgraded_to_http2 = 1;
-       wsi->vhost->conn_stats.h2_alpn++;
 
        /* adopt the header info */
 
        ah = wsi->http.ah;
 
-       lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE,
+       lws_role_transition(wsi, lwsi_role_client(wsi) ? LWSIFR_CLIENT : LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE,
                            &role_ops_h2);
 
        /* http2 union member has http union struct at start */
@@ -1199,38 +1302,107 @@ rops_alpn_negotiated_h2(struct lws *wsi, const char *alpn)
 
        /* HTTP2 union */
 
-       lws_hpack_dynamic_size(wsi,
-                          wsi->h2.h2n->set.s[H2SET_HEADER_TABLE_SIZE]);
-       wsi->h2.tx_cr = 65535;
+       if (lws_hpack_dynamic_size(wsi,
+                          (int)wsi->h2.h2n->our_set.s[H2SET_HEADER_TABLE_SIZE]))
+               return 1;
+       wsi->txc.tx_cr = 65535;
+
+       lwsl_info("%s: %s: configured for h2\n", __func__, lws_wsi_tag(wsi));
+
+       return 0;
+}
+
+static int
+rops_issue_keepalive_h2(struct lws *wsi, int isvalid)
+{
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+       struct lws_h2_protocol_send *pps;
+       uint64_t us = (uint64_t)lws_now_usecs();
+
+       if (isvalid) {
+               _lws_validity_confirmed_role(nwsi);
+
+               return 0;
+       }
+
+       /*
+        * We can only send these frames on the network connection itself...
+        * we shouldn't be tracking validity on anything else
+        */
 
-       lwsl_info("%s: wsi %p: configured for h2\n", __func__, wsi);
+       assert(wsi == nwsi);
+
+       pps = lws_h2_new_pps(LWS_H2_PPS_PING);
+       if (!pps)
+               return 1;
+
+       /*
+        * The peer is defined to copy us back the unchanged payload in another
+        * PING frame this time with ACK set.  So by sending that out with the
+        * current time, it's an interesting opportunity to learn the effective
+        * RTT on the link when the PONG comes in, plus or minus the time to
+        * schedule the PPS.
+        */
+
+       memcpy(pps->u.ping.ping_payload, &us, 8);
+       lws_pps_schedule(nwsi, pps);
 
        return 0;
 }
 
-struct lws_role_ops role_ops_h2 = {
+static const lws_rops_t rops_table_h2[] = {
+#if defined(LWS_WITH_SERVER)
+       /*  1 */ { .check_upgrades        = rops_check_upgrades_h2 },
+#else
+       /*  1 */ { .check_upgrades        = NULL },
+#endif
+       /*  2 */ { .pt_init_destroy       = rops_pt_init_destroy_h2 },
+       /*  3 */ { .init_vhost            = rops_init_vhost_h2 },
+       /*  4 */ { .handle_POLLIN         = rops_handle_POLLIN_h2 },
+       /*  5 */ { .handle_POLLOUT        = rops_handle_POLLOUT_h2 },
+       /*  6 */ { .perform_user_POLLOUT  = rops_perform_user_POLLOUT_h2 },
+       /*  7 */ { .callback_on_writable  = rops_callback_on_writable_h2 },
+       /*  8 */ { .tx_credit             = rops_tx_credit_h2 },
+       /*  9 */ { .write_role_protocol   = rops_write_role_protocol_h2 },
+       /* 10 */ { .encapsulation_parent  = rops_encapsulation_parent_h2 },
+       /* 11 */ { .alpn_negotiated       = rops_alpn_negotiated_h2 },
+       /* 12 */ { .close_kill_connection = rops_close_kill_connection_h2 },
+       /* 13 */ { .destroy_role          = rops_destroy_role_h2 },
+       /* 14 */ { .issue_keepalive       = rops_issue_keepalive_h2 },
+};
+
+
+const struct lws_role_ops role_ops_h2 = {
        /* role name */                 "h2",
        /* alpn id */                   "h2",
-       /* check_upgrades */            rops_check_upgrades_h2,
-       /* init_context */              rops_init_context_h2,
-       /* init_vhost */                rops_init_vhost_h2,
-       /* destroy_vhost */             NULL,
-       /* periodic_checks */           NULL,
-       /* service_flag_pending */      NULL,
-       /* handle_POLLIN */             rops_handle_POLLIN_h2,
-       /* handle_POLLOUT */            rops_handle_POLLOUT_h2,
-       /* perform_user_POLLOUT */      rops_perform_user_POLLOUT_h2,
-       /* callback_on_writable */      rops_callback_on_writable_h2,
-       /* tx_credit */                 rops_tx_credit_h2,
-       /* write_role_protocol */       rops_write_role_protocol_h2,
-       /* encapsulation_parent */      rops_encapsulation_parent_h2,
-       /* alpn_negotiated */           rops_alpn_negotiated_h2,
-       /* close_via_role_protocol */   NULL,
-       /* close_role */                NULL,
-       /* close_kill_connection */     rops_close_kill_connection_h2,
-       /* destroy_role */              rops_destroy_role_h2,
-       /* adoption_bind */             NULL,
-       /* client_bind */               NULL,
+
+       /* rops_table */                rops_table_h2,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+#if defined(LWS_WITH_SERVER)
+         /* LWS_ROPS_pt_init_destroy */                0x12,
+#else
+         /* LWS_ROPS_pt_init_destroy */                0x02,
+#endif
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x30,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x04,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x56,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x78,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x9a,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0xb0,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x0c,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0xd0,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x0e,
+                                       },
        /* adoption_cb clnt, srv */     { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
                                          LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
        /* rx cb clnt, srv */           { LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
similarity index 79%
rename from lib/roles/h2/private.h
rename to lib/roles/h2/private-lib-roles-h2.h
index f649687..98b2aea 100644 (file)
@@ -1,42 +1,30 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h if LWS_ROLE_H2
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-extern struct lws_role_ops role_ops_h2;
+extern const struct lws_role_ops role_ops_h2;
 #define lwsi_role_h2(wsi) (wsi->role_ops == &role_ops_h2)
 
-enum lws_h2_settings {
-       H2SET_HEADER_TABLE_SIZE = 1,
-       H2SET_ENABLE_PUSH,
-       H2SET_MAX_CONCURRENT_STREAMS,
-       H2SET_INITIAL_WINDOW_SIZE,
-       H2SET_MAX_FRAME_SIZE,
-       H2SET_MAX_HEADER_LIST_SIZE,
-       H2SET_RESERVED7,
-       H2SET_ENABLE_CONNECT_PROTOCOL, /* defined in mcmanus-httpbis-h2-ws-02 */
-
-       H2SET_COUNT /* always last */
-};
-
 struct http2_settings {
        uint32_t s[H2SET_COUNT];
 };
@@ -210,10 +198,12 @@ enum lws_h2_protocol_send_type {
        LWS_PPS_NONE,
        LWS_H2_PPS_MY_SETTINGS,
        LWS_H2_PPS_ACK_SETTINGS,
+       LWS_H2_PPS_PING,
        LWS_H2_PPS_PONG,
        LWS_H2_PPS_GOAWAY,
        LWS_H2_PPS_RST_STREAM,
        LWS_H2_PPS_UPDATE_WINDOW,
+       LWS_H2_PPS_SETTINGS_INITIAL_UPDATE_WINDOW
 };
 
 struct lws_h2_protocol_send {
@@ -259,7 +249,8 @@ struct lws_h2_ghost_sid {
  * fills it but it belongs to the logical child.
  */
 struct lws_h2_netconn {
-       struct http2_settings set;
+       struct http2_settings our_set;
+       struct http2_settings peer_set;
        struct hpack_dynamic_table hpack_dyn_table;
        uint8_t ping_payload[8];
        uint8_t one_setting[LWS_H2_SETTINGS_LEN];
@@ -281,6 +272,7 @@ struct lws_h2_netconn {
        unsigned int is_first_header_char:1;
        unsigned int zero_huff_padding:1;
        unsigned int last_action_dyntable_resize:1;
+       unsigned int sent_preface:1;
 
        uint32_t hdr_idx;
        uint32_t hpack_len;
@@ -313,94 +305,80 @@ struct lws_h2_netconn {
 
 struct _lws_h2_related {
 
-       struct lws_h2_netconn *h2n; /* malloc'd for root net conn */
-       struct lws *parent_wsi;
-       struct lws *child_list;
-       struct lws *sibling_list;
-
-       char *pending_status_body;
-
-       int tx_cr;
-       int peer_tx_cr_est;
-       unsigned int my_sid;
-       unsigned int child_count;
-       int my_priority;
-       uint32_t dependent_on;
-
-       unsigned int END_STREAM:1;
-       unsigned int END_HEADERS:1;
-       unsigned int send_END_STREAM:1;
-       unsigned int GOING_AWAY;
-       unsigned int requested_POLLOUT:1;
-       unsigned int skint:1;
-
-       uint16_t round_robin_POLLOUT;
-       uint16_t count_POLLOUT_children;
-
-       uint8_t h2_state; /* the RFC7540 state of the connection */
-       uint8_t weight;
-       uint8_t initialized;
+       struct lws_h2_netconn   *h2n; /* malloc'd for root net conn */
+
+       char                    *pending_status_body;
+
+       uint8_t                 h2_state; /* RFC7540 state of the connection */
+
+       uint8_t                 END_STREAM:1;
+       uint8_t                 END_HEADERS:1;
+       uint8_t                 send_END_STREAM:1;
+       uint8_t                 long_poll:1;
+       uint8_t                 initialized:1;
 };
 
-#define HTTP2_IS_TOPLEVEL_WSI(wsi) (!wsi->h2.parent_wsi)
+#define HTTP2_IS_TOPLEVEL_WSI(wsi) (!wsi->mux.parent_wsi)
 
 int
 lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason);
 struct lws * lws_h2_get_nth_child(struct lws *wsi, int n);
-LWS_EXTERN void lws_h2_init(struct lws *wsi);
-LWS_EXTERN int
+void lws_h2_init(struct lws *wsi);
+int
 lws_h2_settings(struct lws *nwsi, struct http2_settings *settings,
                unsigned char *buf, int len);
-LWS_EXTERN int
+int
 lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
              lws_filepos_t *inused);
-LWS_EXTERN int
+int
 lws_h2_do_pps_send(struct lws *wsi);
-LWS_EXTERN int
+int
 lws_h2_frame_write(struct lws *wsi, int type, int flags, unsigned int sid,
                   unsigned int len, unsigned char *buf);
-LWS_EXTERN struct lws *
-lws_h2_wsi_from_id(struct lws *wsi, unsigned int sid);
-LWS_EXTERN int
+struct lws *
+lws_wsi_mux_from_id(struct lws *wsi, unsigned int sid);
+int
 lws_hpack_interpret(struct lws *wsi, unsigned char c);
-LWS_EXTERN int
+int
 lws_add_http2_header_by_name(struct lws *wsi,
                             const unsigned char *name,
                             const unsigned char *value, int length,
                             unsigned char **p, unsigned char *end);
-LWS_EXTERN int
+int
 lws_add_http2_header_by_token(struct lws *wsi,
                              enum lws_token_indexes token,
                              const unsigned char *value, int length,
                              unsigned char **p, unsigned char *end);
-LWS_EXTERN int
+int
 lws_add_http2_header_status(struct lws *wsi,
                            unsigned int code, unsigned char **p,
                            unsigned char *end);
-LWS_EXTERN void
+void
 lws_hpack_destroy_dynamic_header(struct lws *wsi);
-LWS_EXTERN int
+int
 lws_hpack_dynamic_size(struct lws *wsi, int size);
-LWS_EXTERN int
+int
 lws_h2_goaway(struct lws *wsi, uint32_t err, const char *reason);
-LWS_EXTERN int
+int
 lws_h2_tx_cr_get(struct lws *wsi);
-LWS_EXTERN void
+void
 lws_h2_tx_cr_consume(struct lws *wsi, int consumed);
-LWS_EXTERN int
+int
 lws_hdr_extant(struct lws *wsi, enum lws_token_indexes h);
-LWS_EXTERN void
+void
 lws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pss);
 
-LWS_EXTERN const struct http2_settings lws_h2_defaults;
-LWS_EXTERN int
+extern const struct http2_settings lws_h2_defaults;
+int
 lws_h2_ws_handshake(struct lws *wsi);
-LWS_EXTERN int lws_h2_issue_preface(struct lws *wsi);
-LWS_EXTERN int
+int lws_h2_issue_preface(struct lws *wsi);
+int
 lws_h2_client_handshake(struct lws *wsi);
-LWS_EXTERN struct lws *
+struct lws *
 lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi);
 int
 lws_handle_POLLOUT_event_h2(struct lws *wsi);
 int
 lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len);
+struct lws_h2_protocol_send *
+lws_h2_new_pps(enum lws_h2_protocol_send_type type);
diff --git a/lib/roles/http/CMakeLists.txt b/lib/roles/http/CMakeLists.txt
new file mode 100644 (file)
index 0000000..01ad79b
--- /dev/null
@@ -0,0 +1,96 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(. ./compression)
+
+list(APPEND SOURCES
+       roles/http/header.c
+       roles/http/date.c
+       roles/http/parsers.c)
+
+if (NOT LWS_WITHOUT_SERVER)
+       list(APPEND SOURCES
+               roles/http/server/server.c
+               roles/http/server/lws-spa.c)
+endif()
+
+if (LWS_WITH_CACHE_NSCOOKIEJAR AND LWS_WITH_CLIENT)
+       list(APPEND SOURCES
+               roles/http/cookie.c)
+endif()
+
+if (LWS_WITH_HTTP_PROXY AND LWS_WITH_HUBBUB)
+       list(APPEND SOURCES
+               roles/http/server/rewrite.c)
+endif()
+
+if (LWS_WITH_ACCESS_LOG)
+       list(APPEND SOURCES
+               roles/http/server/access-log.c)
+endif()
+       
+if (LWS_WITH_HTTP_STREAM_COMPRESSION)
+       list(APPEND SOURCES
+               roles/http/compression/stream.c
+               roles/http/compression/deflate/deflate.c)
+
+       if (LWS_WITH_HTTP_BROTLI)
+               list(APPEND SOURCES
+                       roles/http/compression/brotli/brotli.c)
+               list(APPEND LIB_LIST brotlienc brotlidec brotlidec)
+       endif()
+endif()
+
+if (LWS_WITH_LEJP_CONF AND LWS_WITH_NETWORK AND NOT LWS_PLAT_OPTEE)
+       list(APPEND SOURCES
+               roles/http/server/lejp-conf.c
+       )
+endif()
+
+if (LWS_WITH_RANGES)
+       list(APPEND SOURCES
+               roles/http/server/ranges.c)
+endif()
+
+if (LWS_WITH_ZIP_FOPS)
+       if (LWS_WITH_ZLIB)
+               list(APPEND SOURCES
+                       roles/http/server/fops-zip.c)
+       else()
+               message(FATAL_ERROR "Pre-zipped file support (LWS_WITH_ZIP_FOPS) requires ZLIB (LWS_WITH_ZLIB)")
+       endif()
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
diff --git a/lib/roles/http/client/client-handshake.c b/lib/roles/http/client/client-handshake.c
deleted file mode 100644 (file)
index 21df052..0000000
+++ /dev/null
@@ -1,1197 +0,0 @@
-#include "core/private.h"
-
-static int
-lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)
-{
-       struct addrinfo hints;
-
-       memset(&hints, 0, sizeof(hints));
-       *result = NULL;
-
-       hints.ai_socktype = SOCK_STREAM;
-
-#ifdef LWS_WITH_IPV6
-       if (wsi->ipv6) {
-
-#if !defined(__ANDROID__)
-               hints.ai_family = AF_INET6;
-               hints.ai_flags = AI_V4MAPPED;
-#endif
-       } else
-#endif
-       {
-               hints.ai_family = PF_UNSPEC;
-       }
-
-       return getaddrinfo(ads, NULL, &hints, result);
-}
-
-
-struct lws *
-lws_client_connect_3(struct lws *wsi, struct lws *wsi_piggyback, ssize_t plen)
-{
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-       const char *meth = NULL;
-       struct lws_pollfd pfd;
-       const char *cce = "";
-       int n, m, rawish = 0;
-
-       if (wsi->stash)
-               meth = wsi->stash->method;
-       else
-               meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
-
-       if (meth && !strcmp(meth, "RAW"))
-               rawish = 1;
-
-       if (wsi_piggyback)
-               goto send_hs;
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       /* we are connected to server, or proxy */
-
-       /* http proxy */
-       if (wsi->vhost->http.http_proxy_port) {
-
-               /*
-                * OK from now on we talk via the proxy, so connect to that
-                *
-                * (will overwrite existing pointer,
-                * leaving old string/frag there but unreferenced)
-                */
-               if (wsi->stash) {
-                       lws_free(wsi->stash->address);
-                       wsi->stash->address =
-                               lws_strdup(wsi->vhost->http.http_proxy_address);
-                       if (!wsi->stash->address)
-                               goto failed;
-               } else
-                       if (lws_hdr_simple_create(wsi,
-                                       _WSI_TOKEN_CLIENT_PEER_ADDRESS,
-                                         wsi->vhost->http.http_proxy_address))
-                       goto failed;
-               wsi->c_port = wsi->vhost->http.http_proxy_port;
-
-               n = send(wsi->desc.sockfd, (char *)pt->serv_buf, (int)plen,
-                        MSG_NOSIGNAL);
-               if (n < 0) {
-                       lwsl_debug("ERROR writing to proxy socket\n");
-                       cce = "proxy write failed";
-                       goto failed;
-               }
-
-               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
-                               AWAITING_TIMEOUT);
-
-               lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY);
-
-               return wsi;
-       }
-#endif
-#if defined(LWS_WITH_SOCKS5)
-       /* socks proxy */
-       else if (wsi->vhost->socks_proxy_port) {
-               n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
-                        MSG_NOSIGNAL);
-               if (n < 0) {
-                       lwsl_debug("ERROR writing socks greeting\n");
-                       cce = "socks write failed";
-                       goto failed;
-               }
-
-               lws_set_timeout(wsi,
-                               PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
-                               AWAITING_TIMEOUT);
-
-               lwsi_set_state(wsi, LRS_WAITING_SOCKS_GREETING_REPLY);
-
-               return wsi;
-       }
-#endif
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-send_hs:
-
-       if (wsi_piggyback &&
-           !lws_dll2_is_detached(&wsi->dll2_cli_txn_queue)) {
-               /*
-                * We are pipelining on an already-established connection...
-                * we can skip tls establishment.
-                */
-
-               lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
-
-               /*
-                * we can't send our headers directly, because they have to
-                * be sent when the parent is writeable.  The parent will check
-                * for anybody on his client transaction queue that is in
-                * LRS_H1C_ISSUE_HANDSHAKE2, and let them write.
-                *
-                * If we are trying to do this too early, before the master
-                * connection has written his own headers, then it will just
-                * wait in the queue until it's possible to send them.
-                */
-               lws_callback_on_writable(wsi_piggyback);
-               lwsl_info("%s: wsi %p: waiting to send hdrs (par state 0x%x)\n",
-                           __func__, wsi, lwsi_state(wsi_piggyback));
-       } else {
-               lwsl_info("%s: wsi %p: %s %s client created own conn (raw %d)\n",
-                           __func__, wsi, wsi->role_ops->name,
-                           wsi->protocol->name, rawish);
-
-               /* we are making our own connection */
-               if (!rawish)
-                       lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);
-               else {
-                       /* for a method = "RAW" connection, this makes us
-                        * established */
-
-                       /* clear his established timeout */
-                       lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
-
-                       m = wsi->role_ops->adoption_cb[0];
-                       if (m) {
-                               n = user_callback_handle_rxflow(
-                                               wsi->protocol->callback, wsi,
-                                               m, wsi->user_space, NULL, 0);
-                               if (n < 0) {
-                                       lwsl_info("LWS_CALLBACK_RAW_PROXY_CLI_ADOPT failed\n");
-                                       goto failed;
-                               }
-                       }
-
-                       /* service.c pollout processing wants this */
-                       wsi->hdr_parsing_completed = 1;
-                       lwsl_info("%s: setting ESTABLISHED\n", __func__);
-                       lwsi_set_state(wsi, LRS_ESTABLISHED);
-
-                       return wsi;
-               }
-
-               /*
-                * provoke service to issue the handshake directly.
-                *
-                * we need to do it this way because in the proxy case, this is
-                * the next state and executed only if and when we get a good
-                * proxy response inside the state machine... but notice in
-                * SSL case this may not have sent anything yet with 0 return,
-                * and won't until many retries from main loop.  To stop that
-                * becoming endless, cover with a timeout.
-                */
-
-               lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
-                               AWAITING_TIMEOUT);
-
-               assert(lws_socket_is_valid(wsi->desc.sockfd));
-
-               pfd.fd = wsi->desc.sockfd;
-               pfd.events = LWS_POLLIN;
-               pfd.revents = LWS_POLLIN;
-
-               n = lws_service_fd(wsi->context, &pfd);
-               if (n < 0) {
-                       cce = "first service failed";
-                       goto failed;
-               }
-               if (n) /* returns 1 on failure after closing wsi */
-                       return NULL;
-       }
-#endif
-       return wsi;
-
-failed:
-       lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
-
-       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
-
-       return NULL;
-}
-
-struct lws *
-lws_client_connect_2(struct lws *wsi)
-{
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       struct lws_context *context = wsi->context;
-       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-       const char *adsin;
-       ssize_t plen = 0;
-#endif
-#if defined(LWS_WITH_UNIX_SOCK)
-       struct sockaddr_un sau;
-       char unix_skt = 0;
-#endif
-       int n, m, port = 0;
-       const char *cce = "", *iface;
-       const struct sockaddr *psa;
-       const char *meth = NULL;
-       struct addrinfo *result;
-       const char *ads;
-       sockaddr46 sa46;
-
-#ifdef LWS_WITH_IPV6
-       char ipv6only = lws_check_opt(wsi->vhost->options,
-                       LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |
-                       LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
-       struct sockaddr_in addr;
-#if defined(__ANDROID__)
-       ipv6only = 0;
-#endif
-#endif
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       if (!wsi->http.ah && !wsi->stash) {
-               cce = "ah was NULL at cc2";
-               lwsl_err("%s\n", cce);
-               goto oom4;
-       }
-
-       /* we can only piggyback GET or POST */
-
-       if (wsi->stash)
-               meth = wsi->stash->method;
-       else
-               meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
-
-       if (meth && strcmp(meth, "GET") && strcmp(meth, "POST"))
-               goto create_new_conn;
-
-       /* we only pipeline connections that said it was okay */
-
-       if (!wsi->client_pipeline)
-               goto create_new_conn;
-
-       /*
-        * let's take a look first and see if there are any already-active
-        * client connections we can piggy-back on.
-        */
-
-       adsin = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
-
-       lws_vhost_lock(wsi->vhost); /* ----------------------------------- { */
-
-       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
-                       lws_dll2_get_head(&wsi->vhost->dll_cli_active_conns_owner)) {
-               struct lws *w = lws_container_of(d, struct lws,
-                                                dll_cli_active_conns);
-
-               lwsl_debug("%s: check %s %s %d %d\n", __func__, adsin,
-                          w->cli_hostname_copy, wsi->c_port, w->c_port);
-
-               if (w != wsi && w->cli_hostname_copy &&
-                   !strcmp(adsin, w->cli_hostname_copy) &&
-#if defined(LWS_WITH_TLS)
-                   (wsi->tls.use_ssl & LCCSCF_USE_SSL) ==
-                    (w->tls.use_ssl & LCCSCF_USE_SSL) &&
-#endif
-                   wsi->c_port == w->c_port) {
-
-                       /* someone else is already connected to the right guy */
-
-                       /* do we know for a fact pipelining won't fly? */
-                       if (w->keepalive_rejected) {
-                               lwsl_info("defeating pipelining due to no "
-                                           "keepalive on server\n");
-                               lws_vhost_unlock(wsi->vhost); /* } ---------- */
-                               goto create_new_conn;
-                       }
-#if defined (LWS_WITH_HTTP2)
-                       /*
-                        * h2: in usable state already: just use it without
-                        *     going through the queue
-                        */
-                       if (w->client_h2_alpn &&
-                           (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS ||
-                            lwsi_state(w) == LRS_ESTABLISHED)) {
-
-                               lwsl_info("%s: just join h2 directly\n",
-                                               __func__);
-
-                               wsi->client_h2_alpn = 1;
-                               lws_wsi_h2_adopt(w, wsi);
-                               lws_vhost_unlock(wsi->vhost); /* } ---------- */
-
-                               return wsi;
-                       }
-#endif
-
-                       lwsl_info("apply %p to txn queue on %p state 0x%lx\n",
-                                 wsi, w, (unsigned long)w->wsistate);
-                       /*
-                        * ...let's add ourselves to his transaction queue...
-                        * we are adding ourselves at the HEAD
-                        */
-                       lws_dll2_add_head(&wsi->dll2_cli_txn_queue,
-                                         &w->dll2_cli_txn_queue_owner);
-
-                       /*
-                        * h1: pipeline our headers out on him,
-                        * and wait for our turn at client transaction_complete
-                        * to take over parsing the rx.
-                        */
-                       lws_vhost_unlock(wsi->vhost); /* } ---------- */
-                       return lws_client_connect_3(wsi, w, plen);
-               }
-
-       } lws_end_foreach_dll_safe(d, d1);
-
-       lws_vhost_unlock(wsi->vhost); /* } ---------------------------------- */
-
-create_new_conn:
-#endif
-
-       /*
-        * clients who will create their own fresh connection keep a copy of
-        * the hostname they originally connected to, in case other connections
-        * want to use it too
-        */
-
-       if (!wsi->cli_hostname_copy) {
-               if (wsi->stash)
-                       wsi->cli_hostname_copy = lws_strdup(wsi->stash->host);
-               else {
-                       char *pa = lws_hdr_simple_ptr(wsi,
-                                             _WSI_TOKEN_CLIENT_PEER_ADDRESS);
-                       if (pa)
-                               wsi->cli_hostname_copy = lws_strdup(pa);
-               }
-       }
-
-       /*
-        * If we made our own connection, and we're doing a method that can take
-        * a pipeline, we are an "active client connection".
-        *
-        * Add ourselves to the vhost list of those so that others can
-        * piggyback on our transaction queue
-        */
-
-       if (meth && (!strcmp(meth, "GET") || !strcmp(meth, "POST")) &&
-           lws_dll2_is_detached(&wsi->dll2_cli_txn_queue) &&
-           lws_dll2_is_detached(&wsi->dll_cli_active_conns)) {
-               lws_vhost_lock(wsi->vhost);
-               /* caution... we will have to unpick this on oom4 path */
-               lws_dll2_add_head(&wsi->dll_cli_active_conns,
-                                &wsi->vhost->dll_cli_active_conns_owner);
-               lws_vhost_unlock(wsi->vhost);
-       }
-
-       /*
-        * unix socket destination?
-        */
-
-       if (wsi->stash)
-               ads = wsi->stash->address;
-       else
-               ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
-#if defined(LWS_WITH_UNIX_SOCK)
-       if (*ads == '+') {
-               ads++;
-               memset(&sau, 0, sizeof(sau));
-               sau.sun_family = AF_UNIX;
-               strncpy(sau.sun_path, ads, sizeof(sau.sun_path));
-               sau.sun_path[sizeof(sau.sun_path) - 1] = '\0';
-
-               lwsl_info("%s: Unix skt: %s\n", __func__, ads);
-
-               if (sau.sun_path[0] == '@')
-                       sau.sun_path[0] = '\0';
-
-               unix_skt = 1;
-               goto ads_known;
-       }
-#endif
-
-       /*
-        * start off allowing ipv6 on connection if vhost allows it
-        */
-       wsi->ipv6 = LWS_IPV6_ENABLED(wsi->vhost);
-#ifdef LWS_WITH_IPV6
-       if (wsi->stash)
-               iface = wsi->stash->iface;
-       else
-               iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
-
-       if (wsi->ipv6 && iface &&
-           inet_pton(AF_INET, iface, &addr.sin_addr) == 1) {
-               lwsl_notice("%s: client connection forced to IPv4\n", __func__);
-               wsi->ipv6 = 0;
-       }
-#endif
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-
-       /* Decide what it is we need to connect to:
-        *
-        * Priority 1: connect to http proxy */
-
-       if (wsi->vhost->http.http_proxy_port) {
-
-               lwsl_info("%s: going via proxy\n", __func__);
-
-               plen = lws_snprintf((char *)pt->serv_buf, 256,
-                       "CONNECT %s:%u HTTP/1.0\x0d\x0a"
-                       "Host: %s:%u\x0d\x0a"
-                       "User-agent: libwebsockets\x0d\x0a",
-                       ads, wsi->ocport, ads, wsi->ocport);
-
-               if (wsi->vhost->proxy_basic_auth_token[0])
-                       plen += lws_snprintf((char *)pt->serv_buf + plen, 256,
-                                       "Proxy-authorization: basic %s\x0d\x0a",
-                                       wsi->vhost->proxy_basic_auth_token);
-
-               plen += lws_snprintf((char *)pt->serv_buf + plen, 5, "\x0d\x0a");
-               ads = wsi->vhost->http.http_proxy_address;
-               port = wsi->vhost->http.http_proxy_port;
-#else
-               if (0) {
-#endif
-
-#if defined(LWS_WITH_SOCKS5)
-
-       /* Priority 2: Connect to SOCK5 Proxy */
-
-       } else if (wsi->vhost->socks_proxy_port) {
-               if (socks_generate_msg(wsi, SOCKS_MSG_GREETING, &plen)) {
-                       cce = "socks msg too large";
-                       goto oom4;
-               }
-
-               lwsl_client("Sending SOCKS Greeting\n");
-               ads = wsi->vhost->socks_proxy_address;
-               port = wsi->vhost->socks_proxy_port;
-#endif
-       } else {
-
-               /* Priority 3: Connect directly */
-
-               /* ads already set */
-               port = wsi->c_port;
-       }
-
-       /*
-        * prepare the actual connection
-        * to whatever we decided to connect to
-        */
-
-       lwsl_info("%s: %p: address %s:%u\n", __func__, wsi, ads, port);
-
-       n = lws_getaddrinfo46(wsi, ads, &result);
-       memset(&sa46, 0, sizeof(sa46));
-#ifdef LWS_WITH_IPV6
-       if (wsi->ipv6) {
-               struct sockaddr_in6 *sa6;
-
-               if (n || !result) {
-                       /* lws_getaddrinfo46 failed, there is no usable result */
-                       lwsl_notice("%s: lws_getaddrinfo46 failed %d\n",
-                                       __func__, n);
-                       cce = "ipv6 lws_getaddrinfo46 failed";
-                       goto oom4;
-               }
-
-               sa6 = ((struct sockaddr_in6 *)result->ai_addr);
-               sa46.sa6.sin6_family = AF_INET6;
-               switch (result->ai_family) {
-               case AF_INET:
-                       if (ipv6only)
-                               break;
-                       /* map IPv4 to IPv6 */
-                       memset((char *)&sa46.sa6.sin6_addr, 0,
-                                               sizeof(sa46.sa6.sin6_addr));
-                       sa46.sa6.sin6_addr.s6_addr[10] = 0xff;
-                       sa46.sa6.sin6_addr.s6_addr[11] = 0xff;
-                       memcpy(&sa46.sa6.sin6_addr.s6_addr[12],
-                               &((struct sockaddr_in *)result->ai_addr)->sin_addr,
-                                                       sizeof(struct in_addr));
-                       lwsl_notice("uplevelling AF_INET to AF_INET6\n");
-                       break;
-
-               case AF_INET6:
-                       memcpy(&sa46.sa6.sin6_addr, &sa6->sin6_addr,
-                                               sizeof(struct in6_addr));
-                       sa46.sa6.sin6_scope_id = sa6->sin6_scope_id;
-                       sa46.sa6.sin6_flowinfo = sa6->sin6_flowinfo;
-                       break;
-               default:
-                       lwsl_err("Unknown address family\n");
-                       freeaddrinfo(result);
-                       cce = "unknown address family";
-                       goto oom4;
-               }
-       } else
-#endif /* use ipv6 */
-
-       /* use ipv4 */
-       {
-               void *p = NULL;
-
-               if (!n) {
-                       struct addrinfo *res = result;
-
-                       /* pick the first AF_INET (IPv4) result */
-
-                       while (!p && res) {
-                               switch (res->ai_family) {
-                               case AF_INET:
-                                       p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
-                                       break;
-                               }
-
-                               res = res->ai_next;
-                       }
-#if defined(LWS_FALLBACK_GETHOSTBYNAME)
-               } else if (n == EAI_SYSTEM) {
-                       struct hostent *host;
-
-                       lwsl_info("ipv4 getaddrinfo err, try gethostbyname\n");
-                       host = gethostbyname(ads);
-                       if (host) {
-                               p = host->h_addr;
-                       } else {
-                               lwsl_err("gethostbyname failed\n");
-                               cce = "gethostbyname (ipv4) failed";
-                               goto oom4;
-                       }
-#endif
-               } else {
-                       lwsl_err("getaddrinfo failed: %d\n", n);
-                       cce = "getaddrinfo failed";
-                       goto oom4;
-               }
-
-               if (!p) {
-                       if (result)
-                               freeaddrinfo(result);
-                       lwsl_err("Couldn't identify address\n");
-                       cce = "unable to lookup address";
-                       goto oom4;
-               }
-
-               sa46.sa4.sin_family = AF_INET;
-               sa46.sa4.sin_addr = *((struct in_addr *)p);
-               memset(&sa46.sa4.sin_zero, 0, sizeof(sa46.sa4.sin_zero));
-       }
-
-       if (result)
-               freeaddrinfo(result);
-
-#if defined(LWS_WITH_UNIX_SOCK)
-ads_known:
-#endif
-
-       /* now we decided on ipv4 or ipv6, set the port */
-
-       if (!lws_socket_is_valid(wsi->desc.sockfd)) {
-
-               if (wsi->context->event_loop_ops->check_client_connect_ok &&
-                   wsi->context->event_loop_ops->check_client_connect_ok(wsi)) {
-                       cce = "waiting for event loop watcher to close";
-                       goto oom4;
-               }
-
-#if defined(LWS_WITH_UNIX_SOCK)
-               if (unix_skt) {
-                       wsi->unix_skt = 1;
-                       wsi->desc.sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
-               } else
-#endif
-               {
-
-#ifdef LWS_WITH_IPV6
-               if (wsi->ipv6)
-                       wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
-               else
-#endif
-                       wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
-               }
-
-               if (!lws_socket_is_valid(wsi->desc.sockfd)) {
-                       lwsl_warn("Unable to open socket\n");
-                       cce = "unable to open socket";
-                       goto oom4;
-               }
-
-               if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd,
-#if defined(LWS_WITH_UNIX_SOCK)
-                                               unix_skt)) {
-#else
-                                               0)) {
-#endif
-                       lwsl_err("Failed to set wsi socket options\n");
-                       compatible_close(wsi->desc.sockfd);
-                       cce = "set socket opts failed";
-                       goto oom4;
-               }
-
-               lwsi_set_state(wsi, LRS_WAITING_CONNECT);
-
-#if !defined(LWS_AMAZON_RTOS)
-               if (wsi->context->event_loop_ops->accept)
-                       if (wsi->context->event_loop_ops->accept(wsi)) {
-                               compatible_close(wsi->desc.sockfd);
-                               cce = "event loop accept failed";
-                               goto oom4;
-                       }
-#endif
-
-               if (__insert_wsi_socket_into_fds(wsi->context, wsi)) {
-                       compatible_close(wsi->desc.sockfd);
-                       cce = "insert wsi failed";
-                       goto oom4;
-               }
-
-               if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
-                       compatible_close(wsi->desc.sockfd);
-                       cce = "change_pollfd failed";
-                       goto oom4;
-               }
-
-               /*
-                * past here, we can't simply free the structs as error
-                * handling as oom4 does.  We have to run the whole close flow.
-                */
-
-               if (!wsi->protocol)
-                       wsi->protocol = &wsi->vhost->protocols[0];
-
-               wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
-                                       wsi->user_space, NULL, 0);
-
-               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
-                               AWAITING_TIMEOUT);
-
-               if (wsi->stash)
-                       iface = wsi->stash->iface;
-               else
-                       iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
-
-               if (iface && *iface) {
-                       m = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0,
-                                           iface, wsi->ipv6);
-                       if (m < 0) {
-                               cce = "unable to bind socket";
-                               goto failed;
-                       }
-               }
-       }
-
-#if defined(LWS_WITH_UNIX_SOCK)
-       if (unix_skt) {
-               psa = (const struct sockaddr *)&sau;
-               n = sizeof(sau);
-       } else
-#endif
-
-       {
-#ifdef LWS_WITH_IPV6
-               if (wsi->ipv6) {
-                       sa46.sa6.sin6_port = htons(port);
-                       n = sizeof(struct sockaddr_in6);
-                       psa = (const struct sockaddr *)&sa46;
-               } else
-#endif
-               {
-                       sa46.sa4.sin_port = htons(port);
-                       n = sizeof(struct sockaddr);
-                       psa = (const struct sockaddr *)&sa46;
-               }
-       }
-
-       if (connect(wsi->desc.sockfd, (const struct sockaddr *)psa, n) == -1 ||
-           LWS_ERRNO == LWS_EISCONN) {
-               if (LWS_ERRNO == LWS_EALREADY ||
-                   LWS_ERRNO == LWS_EINPROGRESS ||
-                   LWS_ERRNO == LWS_EWOULDBLOCK
-#ifdef _WIN32
-                       || LWS_ERRNO == WSAEINVAL
-#endif
-               ) {
-                       lwsl_client("nonblocking connect retry (errno = %d)\n",
-                                   LWS_ERRNO);
-
-                       if (lws_plat_check_connection_error(wsi)) {
-                               cce = "socket connect failed";
-                               goto failed;
-                       }
-
-                       /*
-                        * must do specifically a POLLOUT poll to hear
-                        * about the connect completion
-                        */
-                       if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
-                               cce = "POLLOUT set failed";
-                               goto failed;
-                       }
-
-                       return wsi;
-               }
-
-               if (LWS_ERRNO != LWS_EISCONN) {
-                       lwsl_notice("Connect failed errno=%d\n", LWS_ERRNO);
-                       cce = "connect failed";
-                       goto failed;
-               }
-       }
-
-
-
-       return lws_client_connect_3(wsi, NULL, plen);
-
-
-oom4:
-       if (lwsi_role_client(wsi) && wsi->protocol /* && lwsi_state_est(wsi) */)
-               lws_inform_client_conn_fail(wsi,(void *)cce, strlen(cce));
-
-       /* take care that we might be inserted in fds already */
-       if (wsi->position_in_fds_table != LWS_NO_FDS_POS)
-               goto failed1;
-
-       /*
-        * We can't be an active client connection any more, if we thought
-        * that was what we were going to be doing.  It should be if we are
-        * failing by oom4 path, we are still called by
-        * lws_client_connect_via_info() and will be returning NULL to that,
-        * so nobody else should have had a chance to queue on us.
-        */
-       {
-               struct lws_vhost *vhost = wsi->vhost;
-
-               lws_vhost_lock(vhost);
-               __lws_free_wsi(wsi);
-               lws_vhost_unlock(vhost);
-       }
-
-       return NULL;
-
-failed:
-       lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
-
-failed1:
-       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");
-
-       return NULL;
-}
-
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-
-/**
- * lws_client_reset() - retarget a connected wsi to start over with a new
- *                     connection (ie, redirect)
- *                     this only works if still in HTTP, ie, not upgraded yet
- * wsi:                connection to reset
- * address:    network address of the new server
- * port:       port to connect to
- * path:       uri path to connect to on the new server
- * host:       host header to send to the new server
- */
-LWS_VISIBLE struct lws *
-lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
-                const char *path, const char *host)
-{
-       char origin[300] = "", protocol[300] = "", method[32] = "",
-            iface[16] = "", alpn[32] = "", *p;
-       struct lws *wsi;
-
-       if (!pwsi)
-               return NULL;
-
-       wsi = *pwsi;
-
-       if (wsi->redirects == 3) {
-               lwsl_err("%s: Too many redirects\n", __func__);
-               return NULL;
-       }
-       wsi->redirects++;
-
-       p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
-       if (p)
-               lws_strncpy(origin, p, sizeof(origin));
-
-       p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
-       if (p)
-               lws_strncpy(protocol, p, sizeof(protocol));
-
-       p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
-       if (p)
-               lws_strncpy(method, p, sizeof(method));
-
-       p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
-       if (p)
-               lws_strncpy(iface, p, sizeof(iface));
-
-       p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ALPN);
-       if (p)
-               lws_strncpy(alpn, p, sizeof(alpn));
-
-       if (!port) {
-               port = 443;
-               ssl = 1;
-       }
-
-       lwsl_info("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
-                  address, port, path, ssl);
-
-       /* close the connection by hand */
-
-#if defined(LWS_WITH_TLS)
-       lws_ssl_close(wsi);
-#endif
-
-       __remove_wsi_socket_from_fds(wsi);
-
-       if (wsi->context->event_loop_ops->close_handle_manually)
-               wsi->context->event_loop_ops->close_handle_manually(wsi);
-       else
-               compatible_close(wsi->desc.sockfd);
-
-#if defined(LWS_WITH_TLS)
-       wsi->tls.use_ssl = ssl;
-#else
-       if (ssl) {
-               lwsl_err("%s: not configured for ssl\n", __func__);
-               return NULL;
-       }
-#endif
-
-       wsi->desc.sockfd = LWS_SOCK_INVALID;
-       lwsi_set_state(wsi, LRS_UNCONNECTED);
-       // wsi->protocol = NULL;
-       wsi->pending_timeout = NO_PENDING_TIMEOUT;
-       wsi->c_port = port;
-       wsi->hdr_parsing_completed = 0;
-       _lws_header_table_reset(wsi->http.ah);
-
-       if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
-               return NULL;
-
-       if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
-               return NULL;
-
-       if (origin[0])
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
-                                         origin))
-                       return NULL;
-       if (protocol[0])
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
-                                         protocol))
-                       return NULL;
-       if (method[0])
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
-                                         method))
-                       return NULL;
-
-       if (iface[0])
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
-                                         iface))
-                       return NULL;
-       if (alpn[0])
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ALPN,
-                                         alpn))
-                       return NULL;
-
-       origin[0] = '/';
-       strncpy(&origin[1], path, sizeof(origin) - 2);
-       if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))
-               return NULL;
-
-       *pwsi = lws_client_connect_2(wsi);
-
-       return *pwsi;
-}
-
-#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_WITH_HUBBUB)
-hubbub_error
-html_parser_cb(const hubbub_token *token, void *pw)
-{
-       struct lws_rewrite *r = (struct lws_rewrite *)pw;
-       char buf[1024], *start = buf + LWS_PRE, *p = start,
-            *end = &buf[sizeof(buf) - 1];
-       size_t i;
-
-       switch (token->type) {
-       case HUBBUB_TOKEN_DOCTYPE:
-
-               p += lws_snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
-                               (int) token->data.doctype.name.len,
-                               token->data.doctype.name.ptr,
-                               token->data.doctype.force_quirks ?
-                                               "(force-quirks) " : "");
-
-               if (token->data.doctype.public_missing)
-                       lwsl_debug("\tpublic: missing\n");
-               else
-                       p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
-                               (int) token->data.doctype.public_id.len,
-                               token->data.doctype.public_id.ptr);
-
-               if (token->data.doctype.system_missing)
-                       lwsl_debug("\tsystem: missing\n");
-               else
-                       p += lws_snprintf(p, end - p, " \"%.*s\">\n",
-                               (int) token->data.doctype.system_id.len,
-                               token->data.doctype.system_id.ptr);
-
-               break;
-       case HUBBUB_TOKEN_START_TAG:
-               p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
-                               token->data.tag.name.ptr);
-
-/*                             (token->data.tag.self_closing) ?
-                                               "(self-closing) " : "",
-                               (token->data.tag.n_attributes > 0) ?
-                                               "attributes:" : "");
-*/
-               for (i = 0; i < token->data.tag.n_attributes; i++) {
-                       if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) ||
-                           !hstrcmp(&token->data.tag.attributes[i].name, "action", 6) ||
-                           !hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) {
-                               const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
-                               int plen = (int) token->data.tag.attributes[i].value.len;
-
-                               if (strncmp(pp, "http:", 5) && strncmp(pp, "https:", 6)) {
-
-                                       if (!hstrcmp(&token->data.tag.attributes[i].value,
-                                                    r->from, r->from_len)) {
-                                               pp += r->from_len;
-                                               plen -= r->from_len;
-                                       }
-                                       p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
-                                              (int) token->data.tag.attributes[i].name.len,
-                                              token->data.tag.attributes[i].name.ptr,
-                                              r->to, plen, pp);
-                                       continue;
-                               }
-                       }
-
-                       p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
-                               (int) token->data.tag.attributes[i].name.len,
-                               token->data.tag.attributes[i].name.ptr,
-                               (int) token->data.tag.attributes[i].value.len,
-                               token->data.tag.attributes[i].value.ptr);
-               }
-               p += lws_snprintf(p, end - p, ">");
-               break;
-       case HUBBUB_TOKEN_END_TAG:
-               p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
-                               token->data.tag.name.ptr);
-/*
-                               (token->data.tag.self_closing) ?
-                                               "(self-closing) " : "",
-                               (token->data.tag.n_attributes > 0) ?
-                                               "attributes:" : "");
-*/
-               for (i = 0; i < token->data.tag.n_attributes; i++) {
-                       p += lws_snprintf(p, end - p, " %.*s='%.*s'\n",
-                               (int) token->data.tag.attributes[i].name.len,
-                               token->data.tag.attributes[i].name.ptr,
-                               (int) token->data.tag.attributes[i].value.len,
-                               token->data.tag.attributes[i].value.ptr);
-               }
-               p += lws_snprintf(p, end - p, ">");
-               break;
-       case HUBBUB_TOKEN_COMMENT:
-               p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
-                               (int) token->data.comment.len,
-                               token->data.comment.ptr);
-               break;
-       case HUBBUB_TOKEN_CHARACTER:
-               if (token->data.character.len == 1) {
-                       if (*token->data.character.ptr == '<') {
-                               p += lws_snprintf(p, end - p, "&lt;");
-                               break;
-                       }
-                       if (*token->data.character.ptr == '>') {
-                               p += lws_snprintf(p, end - p, "&gt;");
-                               break;
-                       }
-                       if (*token->data.character.ptr == '&') {
-                               p += lws_snprintf(p, end - p, "&amp;");
-                               break;
-                       }
-               }
-
-               p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
-                               token->data.character.ptr);
-               break;
-       case HUBBUB_TOKEN_EOF:
-               p += lws_snprintf(p, end - p, "\n");
-               break;
-       }
-
-       if (r->wsi->protocol_bind_balance &&
-           user_callback_handle_rxflow(r->wsi->protocol->callback,
-                       r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
-                       r->wsi->user_space, start, p - start))
-               return -1;
-
-       return HUBBUB_OK;
-}
-#endif
-
-#endif
-
-struct lws *
-lws_http_client_connect_via_info2(struct lws *wsi)
-{
-       struct client_info_stash *stash = wsi->stash;
-
-       lwsl_debug("%s: %p (stash %p)\n", __func__, wsi, stash);
-
-       if (!stash)
-               return wsi;
-
-       wsi->opaque_user_data = wsi->stash->opaque_user_data;
-
-       if (stash->method && !strcmp(stash->method, "RAW"))
-               goto no_ah;
-
-       /*
-        * we're not necessarily in a position to action these right away,
-        * stash them... we only need during connect phase so into a temp
-        * allocated stash
-        */
-       if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
-                                 stash->address))
-               goto bail1;
-
-       if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
-               goto bail1;
-
-       if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
-               goto bail1;
-
-       if (stash->origin)
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
-                                         stash->origin))
-                       goto bail1;
-       /*
-        * this is a list of protocols we tell the server we're okay with
-        * stash it for later when we compare server response with it
-        */
-       if (stash->protocol)
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
-                                         stash->protocol))
-                       goto bail1;
-       if (stash->method)
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
-                                         stash->method))
-                       goto bail1;
-       if (stash->iface)
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
-                                         stash->iface))
-                       goto bail1;
-       if (stash->alpn)
-               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ALPN,
-                                         stash->alpn))
-                       goto bail1;
-
-#if defined(LWS_WITH_SOCKS5)
-       if (!wsi->vhost->socks_proxy_port)
-               lws_client_stash_destroy(wsi);
-#endif
-
-no_ah:
-       wsi->context->count_wsi_allocated++;
-
-       return lws_client_connect_2(wsi);
-
-bail1:
-#if defined(LWS_WITH_SOCKS5)
-       if (!wsi->vhost->socks_proxy_port)
-               lws_free_set_NULL(wsi->stash);
-#endif
-
-       return NULL;
-}
-
-#if defined(LWS_WITH_SOCKS5)
-int
-socks_generate_msg(struct lws *wsi, enum socks_msg_type type, ssize_t *msg_len)
-{
-       struct lws_context *context = wsi->context;
-       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-       uint8_t *p = pt->serv_buf, *end = &p[context->pt_serv_buf_size];
-       ssize_t n, passwd_len;
-       short net_num;
-       char *cp;
-
-       switch (type) {
-       case SOCKS_MSG_GREETING:
-               if (lws_ptr_diff(end, p) < 4)
-                       return 1;
-               /* socks version, version 5 only */
-               *p++ = SOCKS_VERSION_5;
-               /* number of methods */
-               *p++ = 2;
-               /* username password method */
-               *p++ = SOCKS_AUTH_USERNAME_PASSWORD;
-               /* no authentication method */
-               *p++ = SOCKS_AUTH_NO_AUTH;
-               break;
-
-       case SOCKS_MSG_USERNAME_PASSWORD:
-               n = strlen(wsi->vhost->socks_user);
-               passwd_len = strlen(wsi->vhost->socks_password);
-
-               if (n > 254 || passwd_len > 254)
-                       return 1;
-
-               if (lws_ptr_diff(end, p) < 3 + n + passwd_len)
-                       return 1;
-
-               /* the subnegotiation version */
-               *p++ = SOCKS_SUBNEGOTIATION_VERSION_1;
-
-               /* length of the user name */
-               *p++ = n;
-               /* user name */
-               memcpy(p, wsi->vhost->socks_user, n);
-               p += n;
-
-               /* length of the password */
-               *p++ = passwd_len;
-
-               /* password */
-               memcpy(p, wsi->vhost->socks_password, passwd_len);
-               p += passwd_len;
-               break;
-
-       case SOCKS_MSG_CONNECT:
-               n = strlen(wsi->stash->address);
-
-               if (n > 254 || lws_ptr_diff(end, p) < 5 + n + 2)
-                       return 1;
-
-               cp = (char *)&net_num;
-
-               /* socks version */
-               *p++ = SOCKS_VERSION_5;
-               /* socks command */
-               *p++ = SOCKS_COMMAND_CONNECT;
-               /* reserved */
-               *p++ = 0;
-               /* address type */
-               *p++ = SOCKS_ATYP_DOMAINNAME;
-               /* length of ---> */
-               *p++ = n;
-
-               /* the address we tell SOCKS proxy to connect to */
-               memcpy(p, wsi->stash->address, n);
-               p += n;
-
-               net_num = htons(wsi->c_port);
-
-               /* the port we tell SOCKS proxy to connect to */
-               *p++ = cp[0];
-               *p++ = cp[1];
-
-               break;
-               
-       default:
-               return 1;
-       }
-
-       *msg_len = lws_ptr_diff(p, pt->serv_buf);
-
-       return 0;
-}
-#endif
diff --git a/lib/roles/http/client/client-http.c b/lib/roles/http/client/client-http.c
new file mode 100644 (file)
index 0000000..7dce850
--- /dev/null
@@ -0,0 +1,1695 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+void
+lws_client_http_body_pending(struct lws *wsi, int something_left_to_send)
+{
+       wsi->client_http_body_pending = !!something_left_to_send;
+}
+
+int
+lws_http_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd)
+{
+       struct lws_context *context = wsi->a.context;
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+       char *p = (char *)&pt->serv_buf[0];
+#if defined(LWS_WITH_TLS)
+       char ebuf[128];
+#endif
+       const char *cce = NULL;
+       char *sb = p;
+       int n = 0;
+
+       switch (lwsi_state(wsi)) {
+
+       case LRS_WAITING_DNS:
+               /*
+                * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
+                * timeout protection set in client-handshake.c
+                */
+               lwsl_err("%s: %s: WAITING_DNS\n", __func__, lws_wsi_tag(wsi));
+               if (!lws_client_connect_2_dnsreq(wsi)) {
+                       /* closed */
+                       lwsl_client("closed\n");
+                       return -1;
+               }
+
+               /* either still pending connection, or changed mode */
+               return 0;
+
+       case LRS_WAITING_CONNECT:
+
+               /*
+                * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
+                * timeout protection set in client-handshake.c
+                */
+               if (pollfd->revents & LWS_POLLOUT)
+                       if (lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL) == NULL) {
+                               lwsl_client("closed\n");
+                               return -1;
+                       }
+               break;
+
+#if defined(LWS_WITH_SOCKS5)
+       /* SOCKS Greeting Reply */
+       case LRS_WAITING_SOCKS_GREETING_REPLY:
+       case LRS_WAITING_SOCKS_AUTH_REPLY:
+       case LRS_WAITING_SOCKS_CONNECT_REPLY:
+
+               switch (lws_socks5c_handle_state(wsi, pollfd, &cce)) {
+               case LW5CHS_RET_RET0:
+                       return 0;
+               case LW5CHS_RET_BAIL3:
+                       goto bail3;
+               case LW5CHS_RET_STARTHS:
+                       goto start_ws_handshake;
+               default:
+                       break;
+               }
+               break;
+#endif
+
+#if defined(LWS_CLIENT_HTTP_PROXYING) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
+
+       case LRS_WAITING_PROXY_REPLY:
+
+               /* handle proxy hung up on us */
+
+               if (pollfd->revents & LWS_POLLHUP) {
+
+                       lwsl_warn("Proxy conn %s (fd=%d) dead\n",
+                                 lws_wsi_tag(wsi), pollfd->fd);
+
+                       cce = "proxy conn dead";
+                       goto bail3;
+               }
+
+               n = (int)recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
+               if (n < 0) {
+                       if (LWS_ERRNO == LWS_EAGAIN) {
+                               lwsl_debug("Proxy read EAGAIN... retrying\n");
+                               return 0;
+                       }
+                       lwsl_err("ERROR reading from proxy socket\n");
+                       cce = "proxy read err";
+                       goto bail3;
+               }
+
+               /* sanity check what we were sent... */
+
+               pt->serv_buf[13] = '\0';
+               if (n < 13 || strncmp(sb, "HTTP/1.", 7) ||
+                             (sb[7] != '0' && sb[7] != '1') || sb[8] != ' ') {
+                       /* lwsl_hexdump_notice(sb, n); */
+                       cce = "http_proxy fail";
+                       goto bail3;
+               }
+
+               /* it's h1 alright... what's his logical response code? */
+               n = atoi(&sb[9]);
+               if (n != 200) {
+                       lws_snprintf(sb, 20, "http_proxy -> %u",
+                                    (unsigned int)n);
+                       cce = sb;
+                       goto bail3;
+               }
+
+               lwsl_info("%s: proxy connection extablished\n", __func__);
+
+               /* clear his proxy connection timeout */
+
+               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+               /* fallthru */
+
+#endif
+
+               /* dummy fallthru to satisfy compiler */
+               /* fallthru */
+       case LRS_H1C_ISSUE_HANDSHAKE:
+
+               lwsl_debug("%s: LRS_H1C_ISSUE_HANDSHAKE\n", __func__);
+
+               /*
+                * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
+                * timeout protection set in client-handshake.c
+                *
+                * take care of our lws_callback_on_writable
+                * happening at a time when there's no real connection yet
+                */
+#if defined(LWS_WITH_SOCKS5)
+start_ws_handshake:
+#endif
+               if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
+                       return -1;
+
+#if defined(LWS_ROLE_H2) || defined(LWS_WITH_TLS)
+               if (
+#if defined(LWS_WITH_TLS)
+                   !(wsi->tls.use_ssl & LCCSCF_USE_SSL)
+#endif
+#if defined(LWS_ROLE_H2) && defined(LWS_WITH_TLS)
+                   &&
+#endif
+#if defined(LWS_ROLE_H2)
+                   !(wsi->flags & LCCSCF_H2_PRIOR_KNOWLEDGE)
+#endif
+                   )
+                       goto hs2;
+#endif
+
+#if defined(LWS_WITH_TLS)
+               n = lws_client_create_tls(wsi, &cce, 1);
+               if (n == CCTLS_RETURN_ERROR)
+                       goto bail3;
+               if (n == CCTLS_RETURN_RETRY)
+                       return 0;
+
+               /*
+                * lws_client_create_tls() can already have done the
+                * whole tls setup and preface send... if so he set our state
+                * to LRS_H1C_ISSUE_HANDSHAKE2... let's proceed but be prepared
+                * to notice our state and not resend the preface...
+                */
+
+               lwsl_debug("%s: LRS_H1C_ISSUE_HANDSHAKE fallthru\n", __func__);
+
+               /* fallthru */
+
+       case LRS_WAITING_SSL:
+
+               if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
+                       n = lws_ssl_client_connect2(wsi, ebuf, sizeof(ebuf));
+                       if (!n)
+                               return 0;
+                       if (n < 0) {
+                               cce = ebuf;
+                               goto bail3;
+                       }
+               } else {
+                       wsi->tls.ssl = NULL;
+                       if (wsi->flags & LCCSCF_H2_PRIOR_KNOWLEDGE) {
+                               lwsl_info("h2 prior knowledge\n");
+                               lws_role_call_alpn_negotiated(wsi, "h2");
+                       }
+               }
+#endif
+
+#if defined (LWS_WITH_HTTP2)
+               if (wsi->client_h2_alpn //&&
+                   //lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2
+                   ) {
+                       /*
+                        * We connected to the server and set up tls and
+                        * negotiated "h2" or connected as clear text
+                        * with http/2 prior knowledge.
+                        *
+                        * So this is it, we are an h2 nwsi client connection
+                        * now, not an h1 client connection.
+                        */
+
+                       lwsl_info("%s: doing h2 hello path\n", __func__);
+
+                       /*
+                        * send the H2 preface to legitimize the connection
+                        *
+                        * transitions us to LRS_H2_WAITING_TO_SEND_HEADERS
+                        */
+                       if (wsi->client_h2_alpn)
+                               if (lws_h2_issue_preface(wsi)) {
+                                       cce = "error sending h2 preface";
+                                       goto bail3;
+                               }
+
+               //      lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
+                       lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
+                                       (int)context->timeout_secs);
+
+                       break;
+               }
+#endif
+
+               /* fallthru */
+
+       case LRS_H1C_ISSUE_HANDSHAKE2:
+
+hs2:
+
+               p = lws_generate_client_handshake(wsi, p);
+               if (p == NULL) {
+                       if (wsi->role_ops == &role_ops_raw_skt
+#if defined(LWS_ROLE_RAW_FILE)
+                               || wsi->role_ops == &role_ops_raw_file
+#endif
+                           )
+                               return 0;
+
+                       lwsl_err("Failed to generate handshake for client\n");
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
+                                          "chs");
+                       return 0;
+               }
+
+               /* send our request to the server */
+
+               lwsl_info("%s: HANDSHAKE2: %s: sending headers "
+                         "(wsistate 0x%lx), w sock %d\n",
+                         __func__, lws_wsi_tag(wsi),
+                         (unsigned long)wsi->wsistate, wsi->desc.sockfd);
+
+               n = lws_ssl_capable_write(wsi, (unsigned char *)sb, lws_ptr_diff_size_t(p, sb));
+               switch (n) {
+               case LWS_SSL_CAPABLE_ERROR:
+                       lwsl_debug("ERROR writing to client socket\n");
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
+                                          "cws");
+                       return 0;
+               case LWS_SSL_CAPABLE_MORE_SERVICE:
+                       lws_callback_on_writable(wsi);
+                       break;
+               }
+
+               if (wsi->client_http_body_pending || lws_has_buffered_out(wsi)) {
+                       lwsl_debug("body pending\n");
+                       lwsi_set_state(wsi, LRS_ISSUE_HTTP_BODY);
+                       lws_set_timeout(wsi,
+                                       PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
+                                       (int)context->timeout_secs);
+
+                       if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED)
+                               lws_callback_on_writable(wsi);
+#if defined(LWS_WITH_HTTP_PROXY)
+                       if (wsi->http.proxy_clientside && wsi->parent &&
+                           wsi->parent->http.buflist_post_body)
+                               lws_callback_on_writable(wsi);
+#endif
+                       /* user code must ask for writable callback */
+                       break;
+               }
+
+               lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
+               wsi->hdr_parsing_completed = 0;
+
+               if (lwsi_state(wsi) == LRS_IDLING) {
+                       lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
+                       wsi->hdr_parsing_completed = 0;
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+                       wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
+                       wsi->http.ah->lextable_pos = 0;
+                       wsi->http.ah->unk_pos = 0;
+                       /* If we're (re)starting on hdr, need other implied init */
+                       wsi->http.ah->ues = URIES_IDLE;
+#endif
+               }
+
+               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
+                               (int)wsi->a.context->timeout_secs);
+
+               lws_callback_on_writable(wsi);
+
+               goto client_http_body_sent;
+
+       case LRS_ISSUE_HTTP_BODY:
+#if defined(LWS_WITH_HTTP_PROXY)
+                       if (wsi->http.proxy_clientside && wsi->parent &&
+                           wsi->parent->http.buflist_post_body)
+                               lws_callback_on_writable(wsi);
+#endif
+               if (wsi->client_http_body_pending || lws_has_buffered_out(wsi)) {
+                       //lws_set_timeout(wsi,
+                       //              PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
+                       //              context->timeout_secs);
+                       /* user code must ask for writable callback */
+                       break;
+               }
+client_http_body_sent:
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+               /* prepare ourselves to do the parsing */
+               wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
+               wsi->http.ah->lextable_pos = 0;
+               wsi->http.ah->unk_pos = 0;
+#endif
+               lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
+               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
+                               (int)context->timeout_secs);
+               break;
+
+       case LRS_WAITING_SERVER_REPLY:
+               /*
+                * handle server hanging up on us...
+                * but if there is POLLIN waiting, handle that first
+                */
+               if ((pollfd->revents & (LWS_POLLIN | LWS_POLLHUP)) ==
+                                                               LWS_POLLHUP) {
+
+                       if (lws_buflist_total_len(&wsi->buflist))
+                               lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 3);
+                       else {
+                               lwsl_debug("Server conn %s (fd=%d) dead\n",
+                                               lws_wsi_tag(wsi), pollfd->fd);
+                               cce = "Peer hung up";
+                               goto bail3;
+                       }
+               }
+
+               if (pollfd->revents & LWS_POLLOUT)
+                       if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
+                               return -1;
+
+               if (!(pollfd->revents & LWS_POLLIN))
+                       break;
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+               /* interpret the server response
+                *
+                *  HTTP/1.1 101 Switching Protocols
+                *  Upgrade: websocket
+                *  Connection: Upgrade
+                *  Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
+                *  Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
+                *  Sec-WebSocket-Protocol: chat
+                *
+                * we have to take some care here to only take from the
+                * socket bytewise.  The browser may (and has been seen to
+                * in the case that onopen() performs websocket traffic)
+                * coalesce both handshake response and websocket traffic
+                * in one packet, since at that point the connection is
+                * definitively ready from browser pov.
+                */
+               while (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE) {
+                       struct lws_tokens eb;
+                       int n, m, buffered;
+
+                       eb.token = NULL;
+                       eb.len = 0;
+                       buffered = lws_buflist_aware_read(pt, wsi, &eb, 0, __func__);
+                       lwsl_debug("%s: buflist-aware-read %d %d\n", __func__,
+                                       buffered, eb.len);
+                       if (eb.len == LWS_SSL_CAPABLE_MORE_SERVICE)
+                               return 0;
+                       if (buffered < 0 || eb.len < 0) {
+                               cce = "read failed";
+                               goto bail3;
+                       }
+                       if (!eb.len)
+                               return 0;
+
+                       n = eb.len;
+                       if (lws_parse(wsi, eb.token, &n)) {
+                               lwsl_warn("problems parsing header\n");
+                               cce = "problems parsing header";
+                               goto bail3;
+                       }
+
+                       m = eb.len - n;
+#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
+                       do {
+                               lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+                               if (!h)
+                                       break;
+
+                               if (h->info.dump) {
+                                       h->info.dump(ss_to_userobj(h),
+                                               (const uint8_t *)eb.token,
+                                               (size_t)m,
+                                               (wsi->http.ah->parser_state ==
+                                                WSI_PARSING_COMPLETE) ? 1 : 0);
+                               }
+                       } while (0);
+#endif
+                       if (lws_buflist_aware_finished_consuming(wsi, &eb, m,
+                                                                buffered,
+                                                                __func__))
+                               return -1;
+
+                       /*
+                        * coverity: uncomment if extended
+                        *
+                        * eb.token += m;
+                        * eb.len -= m;
+                        */
+
+                       if (n) {
+                               assert(wsi->http.ah->parser_state ==
+                                               WSI_PARSING_COMPLETE);
+
+                               break;
+                       }
+               }
+
+               /*
+                * hs may also be coming in multiple packets, there is a 5-sec
+                * libwebsocket timeout still active here too, so if parsing did
+                * not complete just wait for next packet coming in this state
+                */
+               if (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE)
+                       break;
+#endif
+
+               /*
+                * otherwise deal with the handshake.  If there's any
+                * packet traffic already arrived we'll trigger poll() again
+                * right away and deal with it that way
+                */
+               return lws_client_interpret_server_handshake(wsi);
+
+bail3:
+               lwsl_info("%s: closing conn at LWS_CONNMODE...SERVER_REPLY, %s, state 0x%x\n",
+                               __func__, lws_wsi_tag(wsi), lwsi_state(wsi));
+               if (cce)
+                       lwsl_info("reason: %s\n", cce);
+               else
+                       cce = "unknown";
+               lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
+
+               lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "cbail3");
+               return -1;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+
+int LWS_WARN_UNUSED_RESULT
+lws_http_transaction_completed_client(struct lws *wsi)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       int n;
+
+       lwsl_info("%s: %s (%s)\n", __func__, lws_wsi_tag(wsi),
+                       wsi->a.protocol->name);
+
+       // if (wsi->http.ah && wsi->http.ah->http_response)
+       /* we're only judging if any (200, or 500 etc) http txn completed */
+       lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
+
+       if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
+                                       LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
+                                       wsi->user_space, NULL, 0)) {
+               lwsl_debug("%s: Completed call returned nonzero (role 0x%lx)\n",
+                          __func__, (unsigned long)lwsi_role(wsi));
+               return -1;
+       }
+
+       wsi->http.rx_content_length = 0;
+
+       /*
+        * For h1, wsi may pass some assets on to a queued child and be
+        * destroyed during this.
+        */
+       lws_pt_lock(pt, __func__);
+       n = _lws_generic_transaction_completed_active_conn(&wsi, 1);
+       lws_pt_unlock(pt);
+
+       if (wsi->http.ah) {
+               if (wsi->client_mux_substream)
+                       /*
+                        * As an h2 client, once we did our transaction, that is
+                        * it for us.  Further transactions will happen as new
+                        * SIDs on the connection.
+                        */
+                       __lws_header_table_detach(wsi, 0);
+               else
+                       if (!n)
+                               _lws_header_table_reset(wsi->http.ah);
+       }
+
+       if (!n || !wsi->http.ah)
+               return 0;
+
+       /*
+        * H1: we can serialize the queued guys into the same ah
+        * H2: everybody needs their own ah until their own STREAM_END
+        */
+
+       /* otherwise set ourselves up ready to go again */
+       lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
+
+       wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
+       wsi->http.ah->lextable_pos = 0;
+       wsi->http.ah->unk_pos = 0;
+
+       lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
+                       (int)wsi->a.context->timeout_secs);
+
+       /* If we're (re)starting on headers, need other implied init */
+       wsi->http.ah->ues = URIES_IDLE;
+       lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
+
+       lwsl_info("%s: %s: new queued transaction\n", __func__, lws_wsi_tag(wsi));
+       lws_callback_on_writable(wsi);
+
+       return 0;
+}
+
+unsigned int
+lws_http_client_http_response(struct lws *wsi)
+{
+       if (wsi->http.ah && wsi->http.ah->http_response)
+               return wsi->http.ah->http_response;
+
+       return 0;
+}
+#endif
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+
+int
+lws_http_is_redirected_to_get(struct lws *wsi)
+{
+       return wsi->redirected_to_get;
+}
+
+int
+lws_client_interpret_server_handshake(struct lws *wsi)
+{
+       int n, port = 0, ssl = 0;
+       int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
+       const char *prot, *ads = NULL, *path, *cce = NULL;
+       struct allocated_headers *ah, *ah1;
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+       char *p = NULL, *q, *simp;
+       char new_path[300];
+       void *opaque;
+
+       // lws_free_set_NULL(wsi->stash);
+
+#if defined(LWS_WITH_CONMON)
+       wsi->conmon.ciu_txn_resp = (lws_conmon_interval_us_t)
+                                       (lws_now_usecs() - wsi->conmon_datum);
+#endif
+
+       ah = wsi->http.ah;
+       if (!wsi->do_ws) {
+               /* we are being an http client...
+                */
+#if defined(LWS_ROLE_H2)
+               if (wsi->client_h2_alpn || wsi->client_mux_substream) {
+                       lwsl_debug("%s: %s: transitioning to h2 client\n",
+                                  __func__, lws_wsi_tag(wsi));
+                       lws_role_transition(wsi, LWSIFR_CLIENT,
+                                           LRS_ESTABLISHED, &role_ops_h2);
+               } else
+#endif
+               {
+#if defined(LWS_ROLE_H1)
+                       {
+                       lwsl_debug("%s: %s: transitioning to h1 client\n",
+                                  __func__, lws_wsi_tag(wsi));
+                       lws_role_transition(wsi, LWSIFR_CLIENT,
+                                           LRS_ESTABLISHED, &role_ops_h1);
+                       }
+#else
+                       return -1;
+#endif
+               }
+
+               wsi->http.ah = ah;
+               ah->http_response = 0;
+       }
+
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
+
+       if ((wsi->flags & LCCSCF_CACHE_COOKIES) &&
+           lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_SET_COOKIE))
+               lws_parse_set_cookie(wsi);
+
+#endif
+       /*
+        * well, what the server sent looked reasonable for syntax.
+        * Now let's confirm it sent all the necessary headers
+        *
+        * http (non-ws) client will expect something like this
+        *
+        * HTTP/1.0.200
+        * server:.libwebsockets
+        * content-type:.text/html
+        * content-length:.17703
+        * set-cookie:.test=LWS_1456736240_336776_COOKIE;Max-Age=360000
+        */
+
+       wsi->http.conn_type = HTTP_CONNECTION_KEEP_ALIVE;
+       if (!wsi->client_mux_substream) {
+               p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
+               /*
+               if (wsi->do_ws && !p) {
+                       lwsl_info("no URI\n");
+                       cce = "HS: URI missing";
+                       goto bail3;
+               }
+               */
+               if (!p) {
+                       p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP1_0);
+                       wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
+               }
+               if (!p) {
+                       cce = "HS: URI missing";
+                       lwsl_info("no URI\n");
+                       goto bail3;
+               }
+#if defined(LWS_ROLE_H2)
+       } else {
+               p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_STATUS);
+               if (!p) {
+                       cce = "HS: :status missing";
+                       lwsl_info("no status\n");
+                       goto bail3;
+               }
+#endif
+       }
+#if !defined(LWS_ROLE_H2)
+       if (!p) {
+               cce = "HS: :status missing";
+               lwsl_info("no status\n");
+               goto bail3;
+       }
+#endif
+       n = atoi(p);
+       if (ah)
+               ah->http_response = (unsigned int)n;
+
+       if (!wsi->client_no_follow_redirect &&
+#if defined(LWS_WITH_HTTP_PROXY)
+           !wsi->http.proxy_clientside &&
+#endif
+           (n == 301 || n == 302 || n == 303 || n == 307 || n == 308)) {
+               p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);
+               if (!p) {
+                       cce = "HS: Redirect code but no Location";
+                       goto bail3;
+               }
+
+#if defined(LWS_WITH_CONMON)
+               if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
+                       wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
+                       wsi->conmon.protocol_specific.http.response = n;
+               }
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+               if (wsi->for_ss
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+                   && !wsi->client_bound_sspc
+#endif
+                  ) {
+       
+                       lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+
+                       if (h)
+                               lws_conmon_ss_json(h);
+               }
+#endif
+#endif
+
+               /* let's let the user code know, if he cares */
+
+               if (wsi->a.protocol->callback(wsi,
+                                           LWS_CALLBACK_CLIENT_HTTP_REDIRECT,
+                                           wsi->user_space, p, (unsigned int)n)) {
+                       cce = "HS: user code rejected redirect";
+                       goto bail3;
+               }
+
+               /*
+                * Some redirect codes imply we have to change the method
+                * used for the subsequent transaction, commonly POST ->
+                * 303 -> GET.
+                */
+
+               if (n == 303) {
+                       char *mp = lws_hdr_simple_ptr(wsi,_WSI_TOKEN_CLIENT_METHOD);
+                       int ml = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_METHOD);
+
+                       if (ml >= 3 && mp) {
+                               lwsl_info("%s: 303 switching to GET\n", __func__);
+                               memcpy(mp, "GET", 4);
+                               wsi->redirected_to_get = 1;
+                               wsi->http.ah->frags[wsi->http.ah->frag_index[
+                                            _WSI_TOKEN_CLIENT_METHOD]].len = 3;
+                       }
+               }
+
+               /* Relative reference absolute path */
+               if (p[0] == '/' || !strchr(p, ':')) {
+#if defined(LWS_WITH_TLS)
+                       ssl = nwsi->tls.use_ssl & LCCSCF_USE_SSL;
+#endif
+                       ads = lws_hdr_simple_ptr(wsi,
+                                                _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+                       port = nwsi->c_port;
+                       path = p;
+                       /* lws_client_reset expects leading / omitted */
+                       if (*path == '/')
+                               path++;
+               }
+               /* Absolute (Full) URI */
+               else if (strchr(p, ':')) {
+                       if (lws_parse_uri(p, &prot, &ads, &port, &path)) {
+                               cce = "HS: URI did not parse";
+                               goto bail3;
+                       }
+
+                       if (!strcmp(prot, "wss") || !strcmp(prot, "https"))
+                               ssl = LCCSCF_USE_SSL;
+               }
+               /* Relative reference relative path */
+               else {
+                       /* This doesn't try to calculate an absolute path,
+                        * that will be left to the server */
+#if defined(LWS_WITH_TLS)
+                       ssl = nwsi->tls.use_ssl & LCCSCF_USE_SSL;
+#endif
+                       ads = lws_hdr_simple_ptr(wsi,
+                                                _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+                       port = wsi->c_port;
+                       /* +1 as lws_client_reset expects leading / omitted */
+                       path = new_path + 1;
+                       if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI))
+                               lws_strncpy(new_path, lws_hdr_simple_ptr(wsi,
+                                  _WSI_TOKEN_CLIENT_URI), sizeof(new_path));
+                       else {
+                               new_path[0] = '/';
+                               new_path[1] = '\0';
+                       }
+                       q = strrchr(new_path, '/');
+                       if (q)
+                               lws_strncpy(q + 1, p, sizeof(new_path) -
+                                                       (unsigned int)(q - new_path) - 1);
+                       else
+                               path = p;
+               }
+
+#if defined(LWS_WITH_TLS)
+               if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) && !ssl &&
+                    !(wsi->flags & LCCSCF_ACCEPT_TLS_DOWNGRADE_REDIRECTS)) {
+                       cce = "HS: Redirect attempted SSL downgrade";
+                       goto bail3;
+               }
+#endif
+
+               if (!ads) /* make coverity happy */ {
+                       cce = "no ads";
+                       goto bail3;
+               }
+
+               if (!lws_client_reset(&wsi, ssl, ads, port, path, ads, 1)) {
+                       lwsl_err("Redirect failed\n");
+                       cce = "HS: Redirect failed";
+                       goto bail3;
+               }
+
+               /*
+                * We are redirecting, let's close in order to extricate
+                * ourselves from the current wsi usage, eg, h2 mux cleanly.
+                *
+                * We will notice close_is_redirect and switch to redirect
+                * flow late in the close action.
+                */
+
+               opaque = wsi->a.opaque_user_data;
+               lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "redir");
+               wsi->a.opaque_user_data = opaque;
+
+               return -1;
+       }
+
+       /* if h1 KA is allowed, enable the queued pipeline guys */
+
+       if (!wsi->client_h2_alpn && !wsi->client_mux_substream) {
+               /* ie, coming to this for the first time */
+               if (wsi->http.conn_type == HTTP_CONNECTION_KEEP_ALIVE)
+                       wsi->keepalive_active = 1;
+               else {
+                       /*
+                        * Ugh... now the main http connection has seen
+                        * both sides, we learn the server doesn't
+                        * support keepalive.
+                        *
+                        * That means any guys queued on us are going
+                        * to have to be restarted from connect2 with
+                        * their own connections.
+                        */
+
+                       /*
+                        * stick around telling any new guys they can't
+                        * pipeline to this server
+                        */
+                       wsi->keepalive_rejected = 1;
+
+                       lws_vhost_lock(wsi->a.vhost);
+                       lws_start_foreach_dll_safe(struct lws_dll2 *,
+                                                  d, d1,
+                         wsi->dll2_cli_txn_queue_owner.head) {
+                               struct lws *ww = lws_container_of(d,
+                                       struct lws,
+                                       dll2_cli_txn_queue);
+
+                               /* remove him from our queue */
+                               lws_dll2_remove(&ww->dll2_cli_txn_queue);
+                               /* give up on pipelining */
+                               ww->client_pipeline = 0;
+
+                               /* go back to "trying to connect" state */
+                               lws_role_transition(ww, LWSIFR_CLIENT,
+                                                   LRS_UNCONNECTED,
+#if defined(LWS_ROLE_H1)
+                                                   &role_ops_h1);
+#else
+#if defined (LWS_ROLE_H2)
+                                                   &role_ops_h2);
+#else
+                                                   &role_ops_raw);
+#endif
+#endif
+                               ww->user_space = NULL;
+                       } lws_end_foreach_dll_safe(d, d1);
+                       lws_vhost_unlock(wsi->a.vhost);
+               }
+       }
+
+#ifdef LWS_WITH_HTTP_PROXY
+       wsi->http.perform_rewrite = 0;
+       if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
+               if (!strncmp(lws_hdr_simple_ptr(wsi,
+                                       WSI_TOKEN_HTTP_CONTENT_TYPE),
+                                       "text/html", 9))
+                       wsi->http.perform_rewrite = 0;
+       }
+#endif
+
+       /* he may choose to send us stuff in chunked transfer-coding */
+       wsi->chunked = 0;
+       wsi->chunk_remaining = 0; /* ie, next thing is chunk size */
+       if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING)) {
+               simp = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING);
+
+               /* cannot be NULL, since it has nonzero length... coverity */
+               if (!simp)
+                       goto bail2;
+               wsi->chunked = !strcmp(simp, "chunked");
+               /* first thing is hex, after payload there is crlf */
+               wsi->chunk_parser = ELCP_HEX;
+       }
+
+       wsi->http.content_length_given = 0;
+       if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
+               simp = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH);
+
+               /* cannot be NULL, since it has nonzero length... coverity */
+               if (!simp)
+                       goto bail2;
+
+               wsi->http.rx_content_length = (lws_filepos_t)atoll(simp);
+               lwsl_info("%s: incoming content length %llu\n",
+                           __func__, (unsigned long long)
+                                   wsi->http.rx_content_length);
+               wsi->http.rx_content_remain =
+                               wsi->http.rx_content_length;
+               wsi->http.content_length_given = 1;
+       } else { /* can't do 1.1 without a content length or chunked */
+               if (!wsi->chunked)
+                       wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
+               lwsl_debug("%s: no content length\n", __func__);
+       }
+
+       if (wsi->do_ws) {
+               /*
+                * Give one last opportunity to ws protocols to inspect server reply
+                * before the ws upgrade code discard it. ie: download reply body in case
+                * of any other response code than 101.
+                */
+               if (wsi->a.protocol->callback(wsi,
+                                         LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
+                                         wsi->user_space, NULL, 0)) {
+
+                       cce = "HS: disallowed by client filter";
+                       goto bail2;
+               }
+       } else {
+               /* allocate the per-connection user memory (if any) */
+               if (lws_ensure_user_space(wsi)) {
+                       lwsl_err("Problem allocating wsi user mem\n");
+                       cce = "HS: OOM";
+                       goto bail2;
+               }
+
+
+               /*
+                * we seem to be good to go, give client last chance to check
+                * headers and OK it
+                */
+               ah1 = wsi->http.ah;
+               wsi->http.ah = ah;
+               if (wsi->a.protocol->callback(wsi,
+                               LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
+                                           wsi->user_space, NULL, 0)) {
+                       wsi->http.ah = ah1;
+                       cce = "HS: disallowed by client filter";
+                       goto bail2;
+               }
+
+               /* clear his proxy connection timeout */
+               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+               wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
+
+               /* call him back to inform him he is up */
+               if (wsi->a.protocol->callback(wsi,
+                                           LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
+                                           wsi->user_space, NULL, 0)) {
+                       wsi->http.ah = ah1;
+                       cce = "HS: disallowed at ESTABLISHED";
+                       goto bail3;
+               }
+
+               wsi->http.ah = ah1;
+
+               lwsl_info("%s: %s: client conn up\n", __func__, lws_wsi_tag(wsi));
+
+               /*
+                * Did we get a response from the server with an explicit
+                * content-length of zero?  If so, and it's not H2 which will
+                * notice it via END_STREAM, this transaction is already
+                * completed at the end of the header processing...
+                */
+               if (!wsi->mux_substream && !wsi->client_mux_substream &&
+                   lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
+                   !wsi->http.rx_content_length)
+                       return !!lws_http_transaction_completed_client(wsi);
+
+               /*
+                * We can also get a case where it's http/1 and there's no
+                * content-length at all, so anything that comes is the body
+                * until it hangs up on us.  With that situation, hanging up
+                * on us past this point should generate a valid
+                * LWS_CALLBACK_COMPLETED_CLIENT_HTTP.
+                *
+                * In that situation, he can't pipeline because in h1 there's
+                * no post-header in-band way to signal the end of the
+                * transaction except hangup.
+                *
+                * lws_http_transaction_completed_client() is the right guy to
+                * issue it when we see the peer has hung up on us.
+                */
+
+               return 0;
+       }
+
+#if defined(LWS_ROLE_WS)
+       switch (lws_client_ws_upgrade(wsi, &cce)) {
+       case 2:
+               goto bail2;
+       case 3:
+               goto bail3;
+       }
+
+       return 0;
+#endif
+
+bail3:
+       close_reason = LWS_CLOSE_STATUS_NOSTATUS;
+
+bail2:
+       if (wsi->a.protocol) {
+               n = 0;
+               if (cce)
+                       n = (int)strlen(cce);
+
+               lws_inform_client_conn_fail(wsi, (void *)cce, (unsigned int)n);
+       }
+
+       lwsl_info("closing connection (prot %s) "
+                 "due to bail2 connection error: %s\n", wsi->a.protocol ?
+                                 wsi->a.protocol->name : "unknown", cce);
+
+       /* closing will free up his parsing allocations */
+       lws_close_free_wsi(wsi, (enum lws_close_status)close_reason, "c hs interp");
+
+       return 1;
+}
+#endif
+
+/*
+ * set the boundary string and the content-type for client multipart mime
+ */
+
+uint8_t *
+lws_http_multipart_headers(struct lws *wsi, uint8_t *p)
+{
+       char buf[10], arg[48];
+       int n;
+
+       if (lws_get_random(wsi->a.context, (uint8_t *)buf, sizeof(buf)) !=
+                       sizeof(buf))
+               return NULL;
+
+       lws_b64_encode_string(buf, sizeof(buf),
+                              wsi->http.multipart_boundary,
+                              sizeof(wsi->http.multipart_boundary));
+
+       n = lws_snprintf(arg, sizeof(arg), "multipart/form-data; boundary=\"%s\"",
+                        wsi->http.multipart_boundary);
+
+       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
+                                        (uint8_t *)arg, n, &p, p + 100))
+               return NULL;
+
+       wsi->http.multipart = wsi->http.multipart_issue_boundary = 1;
+       lws_client_http_body_pending(wsi, 1);
+
+       return p;
+}
+
+int
+lws_client_http_multipart(struct lws *wsi, const char *name,
+                         const char *filename, const char *content_type,
+                         char **p, char *end)
+{
+       /*
+        * Client conn must have been created with LCCSCF_HTTP_MULTIPART_MIME
+        * flag to use this api
+        */
+       assert(wsi->http.multipart);
+
+       if (!name) {
+               *p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p),
+                                       "\xd\xa--%s--\xd\xa",
+                                       wsi->http.multipart_boundary);
+
+               return 0;
+       }
+
+       if (wsi->client_subsequent_mime_part)
+               *p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p), "\xd\xa");
+       wsi->client_subsequent_mime_part = 1;
+
+       *p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p), "--%s\xd\xa"
+                                   "Content-Disposition: form-data; "
+                                     "name=\"%s\"",
+                                     wsi->http.multipart_boundary, name);
+       if (filename)
+               *p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p),
+                                  "; filename=\"%s\"", filename);
+
+       if (content_type)
+               *p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p), "\xd\xa"
+                               "Content-Type: %s", content_type);
+
+       *p += lws_snprintf((char *)(*p), lws_ptr_diff_size_t(end, *p), "\xd\xa\xd\xa");
+
+       return *p == end;
+}
+
+char *
+lws_generate_client_handshake(struct lws *wsi, char *pkt)
+{
+       const char *meth, *pp = lws_hdr_simple_ptr(wsi,
+                               _WSI_TOKEN_CLIENT_SENT_PROTOCOLS), *path;
+       char *p = pkt, *p1, *end = p + wsi->a.context->pt_serv_buf_size;
+
+       meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
+       if (!meth) {
+               meth = "GET";
+               wsi->do_ws = 1;
+       } else {
+               wsi->do_ws = 0;
+       }
+
+       if (!strcmp(meth, "RAW")) {
+               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+               lwsl_notice("client transition to raw\n");
+
+               if (pp) {
+                       const struct lws_protocols *pr;
+
+                       pr = lws_vhost_name_to_protocol(wsi->a.vhost, pp);
+
+                       if (!pr) {
+                               lwsl_err("protocol %s not enabled on vhost\n",
+                                        pp);
+                               return NULL;
+                       }
+
+                       lws_bind_protocol(wsi, pr, __func__);
+               }
+
+               if ((wsi->a.protocol->callback)(wsi, LWS_CALLBACK_RAW_ADOPT,
+                                             wsi->user_space, NULL, 0))
+                       return NULL;
+
+               lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
+                                   &role_ops_raw_skt);
+               lws_header_table_detach(wsi, 1);
+
+               return NULL;
+       }
+
+       /*
+        * 04 example client handshake
+        *
+        * GET /chat HTTP/1.1
+        * Host: server.example.com
+        * Upgrade: websocket
+        * Connection: Upgrade
+        * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
+        * Sec-WebSocket-Origin: http://example.com
+        * Sec-WebSocket-Protocol: chat, superchat
+        * Sec-WebSocket-Version: 4
+        */
+
+       path = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI);
+       if (!path) {
+               if (wsi->stash && wsi->stash->cis[CIS_PATH] &&
+                       wsi->stash->cis[CIS_PATH][0])
+                       path = wsi->stash->cis[CIS_PATH];
+               else
+                       path = "/";
+       }
+
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                         "%s %s HTTP/1.1\x0d\x0a", meth, path);
+
+       p += lws_snprintf(p,  lws_ptr_diff_size_t(end, p),
+                         "Pragma: no-cache\x0d\x0a"
+                         "Cache-Control: no-cache\x0d\x0a");
+
+       p += lws_snprintf(p,  lws_ptr_diff_size_t(end, p),
+                         "Host: %s\x0d\x0a",
+                         lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
+
+       if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) {
+               if (lws_check_opt(wsi->a.context->options,
+                                 LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN))
+                       p += lws_snprintf(p,  lws_ptr_diff_size_t(end, p),
+                                         "Origin: %s\x0d\x0a",
+                                         lws_hdr_simple_ptr(wsi,
+                                                    _WSI_TOKEN_CLIENT_ORIGIN));
+               else
+                       p += lws_snprintf(p,  lws_ptr_diff_size_t(end, p),
+                                         "Origin: %s://%s\x0d\x0a",
+                                         wsi->flags & LCCSCF_USE_SSL ?
+                                                        "https" : "http",
+                                         lws_hdr_simple_ptr(wsi,
+                                                    _WSI_TOKEN_CLIENT_ORIGIN));
+       }
+
+       if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME) {
+               p1 = (char *)lws_http_multipart_headers(wsi, (uint8_t *)p);
+               if (!p1)
+                       return NULL;
+               p = p1;
+       }
+
+#if defined(LWS_WITH_HTTP_PROXY)
+       if (wsi->parent &&
+           lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                 "Content-Length: %s\x0d\x0a",
+                       lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH));
+               if (atoi(lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)))
+                       wsi->client_http_body_pending = 1;
+       }
+       if (wsi->parent &&
+           lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION)) {
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                 "Authorization: %s\x0d\x0a",
+                       lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION));
+       }
+       if (wsi->parent &&
+           lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                 "Content-Type: %s\x0d\x0a",
+                       lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE));
+       }
+#endif
+
+#if defined(LWS_ROLE_WS)
+       if (wsi->do_ws) {
+               const char *conn1 = "";
+       //      if (!wsi->client_pipeline)
+       //              conn1 = "close, ";
+               p = lws_generate_client_ws_handshake(wsi, p, conn1);
+       } else
+#endif
+       {
+               if (!wsi->client_pipeline)
+                       p += lws_snprintf(p, 64, "connection: close\x0d\x0a");
+       }
+
+       /* give userland a chance to append, eg, cookies */
+
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT)
+       if (wsi->flags & LCCSCF_CACHE_COOKIES)
+               lws_cookie_send_cookies(wsi, &p, end);
+#endif
+
+       if (wsi->a.protocol->callback(wsi,
+                       LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
+                       wsi->user_space, &p,
+                       (unsigned int)((pkt + wsi->a.context->pt_serv_buf_size) - p - 12)))
+               return NULL;
+
+       if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED) {
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "Content-Type: application/x-www-form-urlencoded\x0d\x0a");
+               p += lws_snprintf(p,  lws_ptr_diff_size_t(end, p), "Content-Length: %lu\x0d\x0a", wsi->http.writeable_len);
+               lws_client_http_body_pending(wsi, 1);
+       }
+
+       p += lws_snprintf(p,  lws_ptr_diff_size_t(end, p), "\x0d\x0a");
+
+       if (wsi->client_http_body_pending || lws_has_buffered_out(wsi))
+               lws_callback_on_writable(wsi);
+
+       lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mt_http_txn);
+#if defined(LWS_WITH_CONMON)
+       wsi->conmon_datum = lws_now_usecs();
+#endif
+
+       // puts(pkt);
+
+       return p;
+}
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+#if defined(LWS_WITH_HTTP_BASIC_AUTH)
+
+int
+lws_http_basic_auth_gen(const char *user, const char *pw, char *buf, size_t len)
+{
+       size_t n = strlen(user), m = strlen(pw);
+       char b[128];
+
+       if (len < 6 + ((4 * (n + m + 1)) / 3) + 1)
+               return 1;
+
+       memcpy(buf, "Basic ", 6);
+
+       n = (unsigned int)lws_snprintf(b, sizeof(b), "%s:%s", user, pw);
+       if (n >= sizeof(b) - 2)
+               return 2;
+
+       lws_b64_encode_string(b, (int)n, buf + 6, (int)len - 6);
+       buf[len - 1] = '\0';
+
+       return 0;
+}
+
+#endif
+
+int
+lws_http_client_read(struct lws *wsi, char **buf, int *len)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       struct lws_tokens eb;
+       int buffered, n, consumed = 0;
+
+       /*
+        * If the caller provided a non-NULL *buf and nonzero *len, we should
+        * use that as the buffer for the read action, limititing it to *len
+        * (actual payload will be less if chunked headers inside).
+        *
+        * If it's NULL / 0 length, buflist_aware_read will use the pt_serv_buf
+        */
+
+       eb.token = (unsigned char *)*buf;
+       eb.len = *len;
+
+       buffered = lws_buflist_aware_read(pt, wsi, &eb, 0, __func__);
+       *buf = (char *)eb.token; /* may be pointing to buflist or pt_serv_buf */
+       *len = 0;
+
+       /*
+        * we're taking on responsibility for handling used / unused eb
+        * when we leave, via lws_buflist_aware_finished_consuming()
+        */
+
+//     lwsl_notice("%s: eb.len %d ENTRY chunk remaining %d\n", __func__, eb.len,
+//                     wsi->chunk_remaining);
+
+       /* allow the source to signal he has data again next time */
+       if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
+               return -1;
+
+       if (buffered < 0) {
+               lwsl_debug("%s: SSL capable error\n", __func__);
+
+               if (wsi->http.ah &&
+                   wsi->http.ah->parser_state == WSI_PARSING_COMPLETE &&
+                   !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH))
+                       /*
+                        * We had the headers from this stream, but as there
+                        * was no content-length: we had to wait until the
+                        * stream ended to inform the user code the transaction
+                        * has completed to the best of our knowledge
+                        */
+                       if (lws_http_transaction_completed_client(wsi))
+                               /*
+                                * We're going to close anyway, but that api has
+                                * warn_unused_result
+                                */
+                               return -1;
+
+               return -1;
+       }
+
+       if (eb.len <= 0)
+               return 0;
+
+       *len = eb.len;
+       wsi->client_rx_avail = 0;
+
+       /*
+        * server may insist on transfer-encoding: chunked,
+        * so http client must deal with it
+        */
+spin_chunks:
+       //lwsl_notice("%s: len %d SPIN chunk remaining %d\n", __func__, *len,
+       //              wsi->chunk_remaining);
+       while (wsi->chunked && (wsi->chunk_parser != ELCP_CONTENT) && *len) {
+               switch (wsi->chunk_parser) {
+               case ELCP_HEX:
+                       if ((*buf)[0] == '\x0d') {
+                               wsi->chunk_parser = ELCP_CR;
+                               break;
+                       }
+                       n = char_to_hex((*buf)[0]);
+                       if (n < 0) {
+                               lwsl_err("%s: chunking failure A\n", __func__);
+                               return -1;
+                       }
+                       wsi->chunk_remaining <<= 4;
+                       wsi->chunk_remaining |= n;
+                       break;
+               case ELCP_CR:
+                       if ((*buf)[0] != '\x0a') {
+                               lwsl_err("%s: chunking failure B\n", __func__);
+                               return -1;
+                       }
+                       if (wsi->chunk_remaining) {
+                               wsi->chunk_parser = ELCP_CONTENT;
+                               //lwsl_notice("starting chunk size %d (block rem %d)\n",
+                               //              wsi->chunk_remaining, *len);
+                               break;
+                       }
+
+                       wsi->chunk_parser = ELCP_TRAILER_CR;
+                       break;
+
+               case ELCP_CONTENT:
+                       break;
+
+               case ELCP_POST_CR:
+                       if ((*buf)[0] != '\x0d') {
+                               lwsl_err("%s: chunking failure C\n", __func__);
+                               lwsl_hexdump_err(*buf, (unsigned int)*len);
+
+                               return -1;
+                       }
+
+                       wsi->chunk_parser = ELCP_POST_LF;
+                       break;
+
+               case ELCP_POST_LF:
+                       if ((*buf)[0] != '\x0a') {
+                               lwsl_err("%s: chunking failure D\n", __func__);
+
+                               return -1;
+                       }
+
+                       wsi->chunk_parser = ELCP_HEX;
+                       wsi->chunk_remaining = 0;
+                       break;
+
+               case ELCP_TRAILER_CR:
+                       if ((*buf)[0] != '\x0d') {
+                               lwsl_err("%s: chunking failure F\n", __func__);
+                               lwsl_hexdump_err(*buf, (unsigned int)*len);
+
+                               return -1;
+                       }
+
+                       wsi->chunk_parser = ELCP_TRAILER_LF;
+                       break;
+
+               case ELCP_TRAILER_LF:
+                       if ((*buf)[0] != '\x0a') {
+                               lwsl_err("%s: chunking failure F\n", __func__);
+                               lwsl_hexdump_err(*buf, (unsigned int)*len);
+
+                               return -1;
+                       }
+
+                       (*buf)++;
+                       (*len)--;
+                       consumed++;
+
+                       lwsl_info("final chunk\n");
+                       goto completed;
+               }
+               (*buf)++;
+               (*len)--;
+               consumed++;
+       }
+
+       if (wsi->chunked && !wsi->chunk_remaining)
+               goto account_and_ret;
+
+       if (wsi->http.rx_content_remain &&
+           wsi->http.rx_content_remain < (unsigned int)*len)
+               n = (int)wsi->http.rx_content_remain;
+       else
+               n = *len;
+
+       if (wsi->chunked && wsi->chunk_remaining &&
+           wsi->chunk_remaining < n)
+               n = wsi->chunk_remaining;
+
+#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_WITH_HUBBUB)
+       /* hubbub */
+       if (wsi->http.perform_rewrite)
+               lws_rewrite_parse(wsi->http.rw, (unsigned char *)*buf, n);
+       else
+#endif
+       {
+               if (
+#if defined(LWS_WITH_HTTP_PROXY)
+                   !wsi->protocol_bind_balance ==
+                   !!wsi->http.proxy_clientside
+#else
+                   !!wsi->protocol_bind_balance
+#endif
+                 ) {
+                       int q;
+
+                       q = user_callback_handle_rxflow(wsi->a.protocol->callback,
+                               wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
+                               wsi->user_space, *buf, (unsigned int)n);
+                       if (q) {
+                               lwsl_info("%s: RECEIVE_CLIENT_HTTP_READ returned %d\n",
+                                               __func__, q);
+
+                               return q;
+                       }
+               } else
+                       lwsl_notice("%s: swallowed read (%d)\n", __func__, n);
+       }
+
+       (*buf) += n;
+       *len -= n;
+       if (wsi->chunked && wsi->chunk_remaining)
+               wsi->chunk_remaining -= n;
+
+       //lwsl_notice("chunk_remaining <- %d, block remaining %d\n",
+       //              wsi->chunk_remaining, *len);
+
+       consumed += n;
+       //eb.token += n;
+       //eb.len -= n;
+
+       if (wsi->chunked && !wsi->chunk_remaining)
+               wsi->chunk_parser = ELCP_POST_CR;
+
+       if (wsi->chunked && *len)
+               goto spin_chunks;
+
+       if (wsi->chunked)
+               goto account_and_ret;
+
+       /* if we know the content length, decrement the content remaining */
+       if (wsi->http.rx_content_length > 0)
+               wsi->http.rx_content_remain -= (unsigned int)n;
+
+       // lwsl_notice("rx_content_remain %lld, rx_content_length %lld, giv %d\n",
+       //          wsi->http.rx_content_remain, wsi->http.rx_content_length,
+       //          wsi->http.content_length_given);
+
+       if (wsi->http.rx_content_remain || !wsi->http.content_length_given)
+               goto account_and_ret;
+
+completed:
+
+       if (lws_http_transaction_completed_client(wsi)) {
+               lwsl_info("%s: transaction completed says -1\n", __func__);
+               return -1;
+       }
+
+account_and_ret:
+//     lwsl_warn("%s: on way out, consuming %d / %d\n", __func__, consumed, eb.len);
+       if (lws_buflist_aware_finished_consuming(wsi, &eb, consumed, buffered,
+                                                       __func__))
+               return -1;
+
+       return 0;
+}
+
+#endif
+
+static uint8_t hnames2[] = {
+       _WSI_TOKEN_CLIENT_ORIGIN,
+       _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
+       _WSI_TOKEN_CLIENT_METHOD,
+       _WSI_TOKEN_CLIENT_IFACE
+};
+
+/**
+ * lws_client_reset() - retarget a connected wsi to start over with a new
+ *                     connection (ie, redirect)
+ *                     this only works if still in HTTP, ie, not upgraded yet
+ * wsi:                connection to reset
+ * address:    network address of the new server
+ * port:       port to connect to
+ * path:       uri path to connect to on the new server
+ * host:       host header to send to the new server
+ */
+struct lws *
+lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
+                const char *path, const char *host, char weak)
+{
+       struct lws_context_per_thread *pt;
+#if defined(LWS_ROLE_WS)
+       struct _lws_websocket_related *ws;
+#endif
+       const char *cisin[CIS_COUNT];
+       struct lws *wsi;
+       size_t o;
+       int n;
+
+       if (!pwsi)
+               return NULL;
+
+       wsi = *pwsi;
+       pt = &wsi->a.context->pt[(int)wsi->tsi];
+
+       lwsl_debug("%s: %s: redir %d: %s\n", __func__, lws_wsi_tag(wsi),
+                       wsi->redirects, address);
+
+       if (wsi->redirects == 4) {
+               lwsl_err("%s: Too many redirects\n", __func__);
+               return NULL;
+       }
+       wsi->redirects++;
+
+       /*
+        * goal is to close our role part, close the sockfd, detach the ah
+        * but leave our wsi extant and still bound to whatever vhost it was
+        */
+
+       o = path[0] == '/' && path[1] == '/';
+
+       memset((char *)cisin, 0, sizeof(cisin));
+
+       cisin[CIS_ADDRESS]      = address;
+       cisin[CIS_PATH]         = path + o;
+       cisin[CIS_HOST]         = host;
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(hnames2); n++)
+               cisin[n + 3] = lws_hdr_simple_ptr(wsi, hnames2[n]);
+
+#if defined(LWS_WITH_TLS)
+       cisin[CIS_ALPN]         = wsi->alpn;
+#endif
+
+       if (lws_client_stash_create(wsi, cisin))
+               return NULL;
+
+       if (!port) {
+               lwsl_info("%s: forcing port 443\n", __func__);
+
+               port = 443;
+               ssl = 1;
+       }
+
+       wsi->c_port = (uint16_t)port;
+
+       wsi->flags = (wsi->flags & (~LCCSCF_USE_SSL)) |
+                                       (ssl ? LCCSCF_USE_SSL : 0);
+
+       if (!cisin[CIS_ALPN] || !cisin[CIS_ALPN][0])
+#if defined(LWS_ROLE_H2)
+               cisin[CIS_ALPN] = "h2,http/1.1";
+#else
+               cisin[CIS_ALPN] = "http/1.1";
+#endif
+
+       lwsl_notice("%s: REDIRECT %s:%d, path='%s', ssl = %d, alpn='%s'\n",
+                   __func__, address, port, path, ssl, cisin[CIS_ALPN]);
+
+       lws_pt_lock(pt, __func__);
+       __remove_wsi_socket_from_fds(wsi);
+       lws_pt_unlock(pt);
+
+#if defined(LWS_ROLE_WS)
+       if (weak) {
+               ws = wsi->ws;
+               wsi->ws = NULL;
+       }
+#endif
+
+       /*
+        * After this point we can't trust the incoming strings like address,
+        * path any more, since they may have been pointing into the old ah.
+        *
+        * We must use the copies in the wsi->stash instead if we want them.
+        */
+
+       __lws_reset_wsi(wsi); /* detaches ah here */
+#if defined(LWS_ROLE_WS)
+       if (weak)
+               wsi->ws = ws;
+#endif
+       wsi->client_pipeline = 1;
+
+       /*
+        * Will complete at close flow
+        */
+
+       wsi->close_is_redirect = 1;
+
+       return *pwsi;
+}
diff --git a/lib/roles/http/client/client.c b/lib/roles/http/client/client.c
deleted file mode 100644 (file)
index c168fa0..0000000
+++ /dev/null
@@ -1,1337 +0,0 @@
-/*
- * libwebsockets - lib/client/client.c
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-
-LWS_VISIBLE LWS_EXTERN void
-lws_client_http_body_pending(struct lws *wsi, int something_left_to_send)
-{
-       wsi->client_http_body_pending = !!something_left_to_send;
-}
-
-/*
- * return self, or queued client wsi we are acting on behalf of
- *
- * That is the TAIL of the queue (new queue elements are added at the HEAD)
- */
-
-struct lws *
-lws_client_wsi_effective(struct lws *wsi)
-{
-       struct lws_dll2 *tail = lws_dll2_get_tail(&wsi->dll2_cli_txn_queue_owner);
-
-       if (!wsi->transaction_from_pipeline_queue || !tail)
-               return wsi;
-
-       return lws_container_of(tail, struct lws, dll2_cli_txn_queue);
-}
-
-/*
- * return self or the guy we are queued under
- *
- * REQUIRES VHOST LOCK HELD
- */
-
-static struct lws *
-_lws_client_wsi_master(struct lws *wsi)
-{
-       struct lws_dll2_owner *o = wsi->dll2_cli_txn_queue.owner;
-
-       if (!o)
-               return wsi;
-
-       return lws_container_of(o, struct lws, dll2_cli_txn_queue_owner);
-}
-
-int
-lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd,
-                         struct lws *wsi_conn)
-{
-       struct lws_context *context = wsi->context;
-       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-       char *p = (char *)&pt->serv_buf[0];
-       struct lws *w;
-#if defined(LWS_WITH_TLS)
-       char ebuf[128];
-#endif
-       const char *cce = NULL;
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       ssize_t len = 0;
-       unsigned char c;
-#endif
-       char *sb = p;
-       int n = 0;
-#if defined(LWS_WITH_SOCKS5)
-       int conn_mode = 0, pending_timeout = 0;
-#endif
-
-       if ((pollfd->revents & LWS_POLLOUT) &&
-            wsi->keepalive_active &&
-            wsi->dll2_cli_txn_queue_owner.head) {
-               struct lws *wfound = NULL;
-
-               lwsl_debug("%s: pollout HANDSHAKE2\n", __func__);
-
-               /*
-                * We have a transaction queued that wants to pipeline.
-                *
-                * We have to allow it to send headers strictly in the order
-                * that it was queued, ie, tail-first.
-                */
-               lws_vhost_lock(wsi->vhost);
-               lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
-                                 wsi->dll2_cli_txn_queue_owner.head) {
-                       struct lws *w = lws_container_of(d, struct lws,
-                                                 dll2_cli_txn_queue);
-
-                       lwsl_debug("%s: %p states 0x%lx\n", __func__, w,
-                                  (unsigned long)w->wsistate);
-                       if (lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2)
-                               wfound = w;
-               } lws_end_foreach_dll_safe(d, d1);
-
-               if (wfound) {
-                       /*
-                        * pollfd has the master sockfd in it... we
-                        * need to use that in HANDSHAKE2 to understand
-                        * which wsi to actually write on
-                        */
-                       if (lws_client_socket_service(wfound, pollfd, wsi) < 0) {
-                               /* closed */
-
-                               lws_vhost_unlock(wsi->vhost);
-
-                               return -1;
-                       }
-
-                       lws_callback_on_writable(wsi);
-               } else
-                       lwsl_debug("%s: didn't find anything in txn q in HS2\n",
-                                                          __func__);
-
-               lws_vhost_unlock(wsi->vhost);
-
-               return 0;
-       }
-
-       switch (lwsi_state(wsi)) {
-
-       case LRS_WAITING_CONNECT:
-
-               /*
-                * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
-                * timeout protection set in client-handshake.c
-                */
-
-               if (!lws_client_connect_2(wsi)) {
-                       /* closed */
-                       lwsl_client("closed\n");
-                       return -1;
-               }
-
-               /* either still pending connection, or changed mode */
-               return 0;
-
-#if defined(LWS_WITH_SOCKS5)
-       /* SOCKS Greeting Reply */
-       case LRS_WAITING_SOCKS_GREETING_REPLY:
-       case LRS_WAITING_SOCKS_AUTH_REPLY:
-       case LRS_WAITING_SOCKS_CONNECT_REPLY:
-
-               /* handle proxy hung up on us */
-
-               if (pollfd->revents & LWS_POLLHUP) {
-                       lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
-                                 (void *)wsi, pollfd->fd);
-                       cce = "socks conn dead";
-                       goto bail3;
-               }
-
-               n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
-               if (n < 0) {
-                       if (LWS_ERRNO == LWS_EAGAIN) {
-                               lwsl_debug("SOCKS read EAGAIN, retrying\n");
-                               return 0;
-                       }
-                       lwsl_err("ERROR reading from SOCKS socket\n");
-                       cce = "socks recv fail";
-                       goto bail3;
-               }
-
-               switch (lwsi_state(wsi)) {
-
-               case LRS_WAITING_SOCKS_GREETING_REPLY:
-                       if (pt->serv_buf[0] != SOCKS_VERSION_5)
-                               goto socks_reply_fail;
-
-                       if (pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH) {
-                               lwsl_client("SOCKS GR: No Auth Method\n");
-                               if (socks_generate_msg(wsi, SOCKS_MSG_CONNECT, &len))
-                                       goto socks_send_msg_fail;
-                               conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY;
-                               pending_timeout =
-                                  PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
-                               goto socks_send;
-                       }
-
-                       if (pt->serv_buf[1] == SOCKS_AUTH_USERNAME_PASSWORD) {
-                               lwsl_client("SOCKS GR: User/Pw Method\n");
-                               if (socks_generate_msg(wsi,
-                                                  SOCKS_MSG_USERNAME_PASSWORD,
-                                                  &len))
-                                       goto socks_send_msg_fail;
-                               conn_mode = LRS_WAITING_SOCKS_AUTH_REPLY;
-                               pending_timeout =
-                                     PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY;
-                               goto socks_send;
-                       }
-                       goto socks_reply_fail;
-
-               case LRS_WAITING_SOCKS_AUTH_REPLY:
-                       if (pt->serv_buf[0] != SOCKS_SUBNEGOTIATION_VERSION_1 ||
-                           pt->serv_buf[1] !=
-                                           SOCKS_SUBNEGOTIATION_STATUS_SUCCESS)
-                               goto socks_reply_fail;
-
-                       lwsl_client("SOCKS password OK, sending connect\n");
-                       if (socks_generate_msg(wsi, SOCKS_MSG_CONNECT, &len)) {
-socks_send_msg_fail:
-                               cce = "socks gen msg fail";
-                               goto bail3;
-                       }
-                       conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY;
-                       pending_timeout =
-                                  PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
-socks_send:
-                       n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len,
-                                MSG_NOSIGNAL);
-                       if (n < 0) {
-                               lwsl_debug("ERROR writing to socks proxy\n");
-                               cce = "socks write fail";
-                               goto bail3;
-                       }
-
-                       lws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);
-                       lwsi_set_state(wsi, conn_mode);
-                       break;
-
-socks_reply_fail:
-                       lwsl_notice("socks reply: v%d, err %d\n",
-                                   pt->serv_buf[0], pt->serv_buf[1]);
-                       cce = "socks reply fail";
-                       goto bail3;
-
-               case LRS_WAITING_SOCKS_CONNECT_REPLY:
-                       if (pt->serv_buf[0] != SOCKS_VERSION_5 ||
-                           pt->serv_buf[1] != SOCKS_REQUEST_REPLY_SUCCESS)
-                               goto socks_reply_fail;
-
-                       lwsl_client("socks connect OK\n");
-
-                       /* free stash since we are done with it */
-                       lws_client_stash_destroy(wsi);
-                       if (lws_hdr_simple_create(wsi,
-                                                _WSI_TOKEN_CLIENT_PEER_ADDRESS,
-                                              wsi->vhost->socks_proxy_address)) {
-                               cce = "socks connect fail";
-                               goto bail3;
-                       }
-
-                       wsi->c_port = wsi->vhost->socks_proxy_port;
-
-                       /* clear his proxy connection timeout */
-                       lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
-                       goto start_ws_handshake;
-               default:
-                       break;
-               }
-               break;
-#endif
-
-       case LRS_WAITING_PROXY_REPLY:
-
-               /* handle proxy hung up on us */
-
-               if (pollfd->revents & LWS_POLLHUP) {
-
-                       lwsl_warn("Proxy connection %p (fd=%d) dead\n",
-                                 (void *)wsi, pollfd->fd);
-
-                       cce = "proxy conn dead";
-                       goto bail3;
-               }
-
-               n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
-               if (n < 0) {
-                       if (LWS_ERRNO == LWS_EAGAIN) {
-                               lwsl_debug("Proxy read EAGAIN... retrying\n");
-                               return 0;
-                       }
-                       lwsl_err("ERROR reading from proxy socket\n");
-                       cce = "proxy read err";
-                       goto bail3;
-               }
-
-               pt->serv_buf[13] = '\0';
-               if (n < 13 || (strncmp(sb, "HTTP/1.0 200 ", 13) &&
-                   strncmp(sb, "HTTP/1.1 200 ", 13))) {
-                       lwsl_err("%s: ERROR proxy did not reply with h1\n",
-                                       __func__);
-                       /* lwsl_hexdump_notice(sb, n); */
-                       cce = "proxy not h1";
-                       goto bail3;
-               }
-
-               lwsl_info("%s: proxy connection extablished\n", __func__);
-
-               /* clear his proxy connection timeout */
-
-               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
-
-               /* fallthru */
-
-       case LRS_H1C_ISSUE_HANDSHAKE:
-
-               /*
-                * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
-                * timeout protection set in client-handshake.c
-                *
-                * take care of our lws_callback_on_writable
-                * happening at a time when there's no real connection yet
-                */
-#if defined(LWS_WITH_SOCKS5)
-start_ws_handshake:
-#endif
-               if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
-                       return -1;
-
-#if defined(LWS_WITH_TLS)
-               /* we can retry this... just cook the SSL BIO the first time */
-
-               if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) && !wsi->tls.ssl &&
-                   lws_ssl_client_bio_create(wsi) < 0) {
-                       cce = "bio_create failed";
-                       goto bail3;
-               }
-
-               if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
-                       n = lws_ssl_client_connect1(wsi);
-                       if (!n)
-                               return 0;
-                       if (n < 0) {
-                               cce = "lws_ssl_client_connect1 failed";
-                               goto bail3;
-                       }
-               } else
-                       wsi->tls.ssl = NULL;
-
-               /* fallthru */
-
-       case LRS_WAITING_SSL:
-
-               if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
-                       n = lws_ssl_client_connect2(wsi, ebuf, sizeof(ebuf));
-                       if (!n)
-                               return 0;
-                       if (n < 0) {
-                               cce = ebuf;
-                               goto bail3;
-                       }
-               } else
-                       wsi->tls.ssl = NULL;
-#endif
-#if defined (LWS_WITH_HTTP2)
-               if (wsi->client_h2_alpn) {
-                       /*
-                        * We connected to the server and set up tls, and
-                        * negotiated "h2".
-                        *
-                        * So this is it, we are an h2 master client connection
-                        * now, not an h1 client connection.
-                        */
-#if defined (LWS_WITH_TLS)
-                       lws_tls_server_conn_alpn(wsi);
-#endif
-
-                       /* send the H2 preface to legitimize the connection */
-                       if (lws_h2_issue_preface(wsi)) {
-                               cce = "error sending h2 preface";
-                               goto bail3;
-                       }
-
-                       break;
-               }
-#endif
-               lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
-               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
-                               context->timeout_secs);
-
-               /* fallthru */
-
-       case LRS_H1C_ISSUE_HANDSHAKE2:
-               p = lws_generate_client_handshake(wsi, p);
-               if (p == NULL) {
-                       if (wsi->role_ops == &role_ops_raw_skt ||
-                           wsi->role_ops == &role_ops_raw_file)
-                               return 0;
-
-                       lwsl_err("Failed to generate handshake for client\n");
-                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
-                                          "chs");
-                       return 0;
-               }
-
-               /* send our request to the server */
-               lws_latency_pre(context, wsi);
-
-               w = _lws_client_wsi_master(wsi);
-               lwsl_info("%s: HANDSHAKE2: %p: sending headers on %p "
-                         "(wsistate 0x%lx 0x%lx), w sock %d, wsi sock %d\n",
-                         __func__, wsi, w, (unsigned long)wsi->wsistate,
-                         (unsigned long)w->wsistate, w->desc.sockfd,
-                         wsi->desc.sockfd);
-
-               n = lws_ssl_capable_write(w, (unsigned char *)sb, (int)(p - sb));
-               lws_latency(context, wsi, "send lws_issue_raw", n,
-                           n == p - sb);
-               switch (n) {
-               case LWS_SSL_CAPABLE_ERROR:
-                       lwsl_debug("ERROR writing to client socket\n");
-                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
-                                          "cws");
-                       return 0;
-               case LWS_SSL_CAPABLE_MORE_SERVICE:
-                       lws_callback_on_writable(wsi);
-                       break;
-               }
-
-               if (wsi->client_http_body_pending) {
-                       lwsl_debug("body pending\n");
-                       lwsi_set_state(wsi, LRS_ISSUE_HTTP_BODY);
-                       lws_set_timeout(wsi,
-                                       PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
-                                       context->timeout_secs);
-#if defined(LWS_WITH_HTTP_PROXY)
-                       if (wsi->http.proxy_clientside)
-                               lws_callback_on_writable(wsi);
-#endif
-                       /* user code must ask for writable callback */
-                       break;
-               }
-
-               lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
-               wsi->hdr_parsing_completed = 0;
-
-               if (lwsi_state(w) == LRS_IDLING) {
-                       lwsi_set_state(w, LRS_WAITING_SERVER_REPLY);
-                       w->hdr_parsing_completed = 0;
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-                       w->http.ah->parser_state = WSI_TOKEN_NAME_PART;
-                       w->http.ah->lextable_pos = 0;
-#if defined(LWS_WITH_CUSTOM_HEADERS)
-                       w->http.ah->unk_pos = 0;
-#endif
-                       /* If we're (re)starting on hdr, need other implied init */
-                       wsi->http.ah->ues = URIES_IDLE;
-#endif
-               }
-
-               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
-                               wsi->context->timeout_secs);
-
-               lws_callback_on_writable(w);
-
-               goto client_http_body_sent;
-
-       case LRS_ISSUE_HTTP_BODY:
-#if defined(LWS_WITH_HTTP_PROXY)
-                       if (wsi->http.proxy_clientside) {
-                               lws_callback_on_writable(wsi);
-                               break;
-                       }
-#endif
-               if (wsi->client_http_body_pending) {
-                       //lws_set_timeout(wsi,
-                       //              PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
-                       //              context->timeout_secs);
-                       /* user code must ask for writable callback */
-                       break;
-               }
-client_http_body_sent:
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-               /* prepare ourselves to do the parsing */
-               wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
-               wsi->http.ah->lextable_pos = 0;
-#if defined(LWS_WITH_CUSTOM_HEADERS)
-               wsi->http.ah->unk_pos = 0;
-#endif
-#endif
-               lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
-               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
-                               context->timeout_secs);
-               break;
-
-       case LRS_WAITING_SERVER_REPLY:
-               /*
-                * handle server hanging up on us...
-                * but if there is POLLIN waiting, handle that first
-                */
-               if ((pollfd->revents & (LWS_POLLIN | LWS_POLLHUP)) ==
-                                                               LWS_POLLHUP) {
-
-                       lwsl_debug("Server connection %p (fd=%d) dead\n",
-                               (void *)wsi, pollfd->fd);
-                       cce = "Peer hung up";
-                       goto bail3;
-               }
-
-               if (!(pollfd->revents & LWS_POLLIN))
-                       break;
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-               /* interpret the server response
-                *
-                *  HTTP/1.1 101 Switching Protocols
-                *  Upgrade: websocket
-                *  Connection: Upgrade
-                *  Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
-                *  Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
-                *  Sec-WebSocket-Protocol: chat
-                *
-                * we have to take some care here to only take from the
-                * socket bytewise.  The browser may (and has been seen to
-                * in the case that onopen() performs websocket traffic)
-                * coalesce both handshake response and websocket traffic
-                * in one packet, since at that point the connection is
-                * definitively ready from browser pov.
-                */
-               len = 1;
-               while (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE &&
-                      len > 0) {
-                       int plen = 1;
-
-                       n = lws_ssl_capable_read(wsi, &c, 1);
-                       lws_latency(context, wsi, "send lws_issue_raw", n,
-                                   n == 1);
-                       switch (n) {
-                       case 0:
-                       case LWS_SSL_CAPABLE_ERROR:
-                               cce = "read failed";
-                               goto bail3;
-                       case LWS_SSL_CAPABLE_MORE_SERVICE:
-                               return 0;
-                       }
-
-                       if (lws_parse(wsi, &c, &plen)) {
-                               lwsl_warn("problems parsing header\n");
-                               cce = "problems parsing header";
-                               goto bail3;
-                       }
-               }
-
-               /*
-                * hs may also be coming in multiple packets, there is a 5-sec
-                * libwebsocket timeout still active here too, so if parsing did
-                * not complete just wait for next packet coming in this state
-                */
-               if (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE)
-                       break;
-
-#endif
-
-               /*
-                * otherwise deal with the handshake.  If there's any
-                * packet traffic already arrived we'll trigger poll() again
-                * right away and deal with it that way
-                */
-               return lws_client_interpret_server_handshake(wsi);
-
-bail3:
-               lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
-               if (cce)
-                       lwsl_info("reason: %s\n", cce);
-               lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
-
-               lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "cbail3");
-               return -1;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-
-int LWS_WARN_UNUSED_RESULT
-lws_http_transaction_completed_client(struct lws *wsi)
-{
-       struct lws *wsi_eff = lws_client_wsi_effective(wsi);
-
-       lwsl_info("%s: wsi: %p, wsi_eff: %p (%s)\n", __func__, wsi, wsi_eff,
-                   wsi_eff->protocol->name);
-
-       if (user_callback_handle_rxflow(wsi_eff->protocol->callback, wsi_eff,
-                                       LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
-                                       wsi_eff->user_space, NULL, 0)) {
-               lwsl_debug("%s: Completed call returned nonzero (role 0x%lx)\n",
-                          __func__, (unsigned long)lwsi_role(wsi_eff));
-               return -1;
-       }
-
-       /*
-        * Are we constitutionally capable of having a queue, ie, we are on
-        * the "active client connections" list?
-        *
-        * If not, that's it for us.
-        */
-
-       if (lws_dll2_is_detached(&wsi->dll_cli_active_conns))
-               return -1;
-
-       /* if this was a queued guy, close him and remove from queue */
-
-       if (wsi->transaction_from_pipeline_queue) {
-               lwsl_debug("closing queued wsi %p\n", wsi_eff);
-               /* so the close doesn't trigger a CCE */
-               wsi_eff->already_did_cce = 1;
-               __lws_close_free_wsi(wsi_eff,
-                       LWS_CLOSE_STATUS_CLIENT_TRANSACTION_DONE,
-                       "queued client done");
-       }
-
-       _lws_header_table_reset(wsi->http.ah);
-
-       /* after the first one, they can only be coming from the queue */
-       wsi->transaction_from_pipeline_queue = 1;
-
-       wsi->http.rx_content_length = 0;
-       wsi->hdr_parsing_completed = 0;
-
-       /* is there a new tail after removing that one? */
-       wsi_eff = lws_client_wsi_effective(wsi);
-
-       /*
-        * Do we have something pipelined waiting?
-        * it's OK if he hasn't managed to send his headers yet... he's next
-        * in line to do that...
-        */
-       if (wsi_eff == wsi) {
-               /*
-                * Nothing pipelined... we should hang around a bit
-                * in case something turns up...
-                */
-               lwsl_info("%s: nothing pipelined waiting\n", __func__);
-               lwsi_set_state(wsi, LRS_IDLING);
-
-               lws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE, 5);
-
-               return 0;
-       }
-
-       /*
-        * H1: we can serialize the queued guys into the same ah
-        * H2: everybody needs their own ah until their own STREAM_END
-        */
-
-       /* otherwise set ourselves up ready to go again */
-       lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
-
-       wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
-       wsi->http.ah->lextable_pos = 0;
-#if defined(LWS_WITH_CUSTOM_HEADERS)
-       wsi->http.ah->unk_pos = 0;
-#endif
-
-       lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
-                       wsi->context->timeout_secs);
-
-       /* If we're (re)starting on headers, need other implied init */
-       wsi->http.ah->ues = URIES_IDLE;
-
-       lwsl_info("%s: %p: new queued transaction as %p\n", __func__, wsi,
-                 wsi_eff);
-       lws_callback_on_writable(wsi);
-
-       return 0;
-}
-
-LWS_VISIBLE LWS_EXTERN unsigned int
-lws_http_client_http_response(struct lws *_wsi)
-{
-       struct lws *wsi;
-       unsigned int resp;
-
-       if (_wsi->http.ah && _wsi->http.ah->http_response)
-               return _wsi->http.ah->http_response;
-
-       lws_vhost_lock(_wsi->vhost);
-       wsi = _lws_client_wsi_master(_wsi);
-       resp = wsi->http.ah->http_response;
-       lws_vhost_unlock(_wsi->vhost);
-
-       return resp;
-}
-#endif
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-int
-lws_client_interpret_server_handshake(struct lws *wsi)
-{
-       int n, port = 0, ssl = 0;
-       int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
-       const char *prot, *ads = NULL, *path, *cce = NULL;
-       struct allocated_headers *ah;
-       struct lws *w = lws_client_wsi_effective(wsi);
-       char *p, *q;
-       char new_path[300];
-
-       lws_client_stash_destroy(wsi);
-
-       ah = wsi->http.ah;
-       if (!wsi->do_ws) {
-               /* we are being an http client...
-                */
-#if defined(LWS_ROLE_H2)
-               if (wsi->client_h2_alpn || wsi->client_h2_substream) {
-                       lwsl_debug("%s: %p: transitioning to h2 client\n",
-                                  __func__, wsi);
-                       lws_role_transition(wsi, LWSIFR_CLIENT,
-                                           LRS_ESTABLISHED, &role_ops_h2);
-               } else
-#endif
-               {
-#if defined(LWS_ROLE_H1)
-                       {
-                       lwsl_debug("%s: %p: transitioning to h1 client\n",
-                                  __func__, wsi);
-                       lws_role_transition(wsi, LWSIFR_CLIENT,
-                                           LRS_ESTABLISHED, &role_ops_h1);
-                       }
-#else
-                       return -1;
-#endif
-               }
-
-               wsi->http.ah = ah;
-               ah->http_response = 0;
-       }
-
-       /*
-        * well, what the server sent looked reasonable for syntax.
-        * Now let's confirm it sent all the necessary headers
-        *
-        * http (non-ws) client will expect something like this
-        *
-        * HTTP/1.0.200
-        * server:.libwebsockets
-        * content-type:.text/html
-        * content-length:.17703
-        * set-cookie:.test=LWS_1456736240_336776_COOKIE;Max-Age=360000
-        */
-
-       wsi->http.conn_type = HTTP_CONNECTION_KEEP_ALIVE;
-       if (!wsi->client_h2_substream) {
-               p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
-               if (wsi->do_ws && !p) {
-                       lwsl_info("no URI\n");
-                       cce = "HS: URI missing";
-                       goto bail3;
-               }
-               if (!p) {
-                       p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP1_0);
-                       wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
-               }
-               if (!p) {
-                       cce = "HS: URI missing";
-                       lwsl_info("no URI\n");
-                       goto bail3;
-               }
-       } else {
-               p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_STATUS);
-               if (!p) {
-                       cce = "HS: :status missing";
-                       lwsl_info("no status\n");
-                       goto bail3;
-               }
-       }
-       n = atoi(p);
-       if (ah)
-               ah->http_response = n;
-
-       if (
-#if defined(LWS_WITH_HTTP_PROXY)
-           !wsi->http.proxy_clientside &&
-#endif
-           (n == 301 || n == 302 || n == 303 || n == 307 || n == 308)) {
-               p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);
-               if (!p) {
-                       cce = "HS: Redirect code but no Location";
-                       goto bail3;
-               }
-
-               /* Relative reference absolute path */
-               if (p[0] == '/') {
-#if defined(LWS_WITH_TLS)
-                       ssl = wsi->tls.use_ssl & LCCSCF_USE_SSL;
-#endif
-                       ads = lws_hdr_simple_ptr(wsi,
-                                                _WSI_TOKEN_CLIENT_PEER_ADDRESS);
-                       port = wsi->c_port;
-                       /* +1 as lws_client_reset expects leading / omitted */
-                       path = p + 1;
-               }
-               /* Absolute (Full) URI */
-               else if (strchr(p, ':')) {
-                       if (lws_parse_uri(p, &prot, &ads, &port, &path)) {
-                               cce = "HS: URI did not parse";
-                               goto bail3;
-                       }
-
-                       if (!strcmp(prot, "wss") || !strcmp(prot, "https"))
-                               ssl = 1;
-               }
-               /* Relative reference relative path */
-               else {
-                       /* This doesn't try to calculate an absolute path,
-                        * that will be left to the server */
-#if defined(LWS_WITH_TLS)
-                       ssl = wsi->tls.use_ssl & LCCSCF_USE_SSL;
-#endif
-                       ads = lws_hdr_simple_ptr(wsi,
-                                                _WSI_TOKEN_CLIENT_PEER_ADDRESS);
-                       port = wsi->c_port;
-                       /* +1 as lws_client_reset expects leading / omitted */
-                       path = new_path + 1;
-                       if (lws_hdr_simple_ptr(wsi,_WSI_TOKEN_CLIENT_URI))
-                               lws_strncpy(new_path, lws_hdr_simple_ptr(wsi,
-                                  _WSI_TOKEN_CLIENT_URI), sizeof(new_path));
-                       else {
-                               new_path[0] = '/';
-                               new_path[1] = '\0';
-                       }
-                       q = strrchr(new_path, '/');
-                       if (q)
-                               lws_strncpy(q + 1, p, sizeof(new_path) -
-                                                       (q - new_path) - 1);
-                       else
-                               path = p;
-               }
-
-#if defined(LWS_WITH_TLS)
-               if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) && !ssl) {
-                       cce = "HS: Redirect attempted SSL downgrade";
-                       goto bail3;
-               }
-#endif
-
-               if (!ads) /* make coverity happy */ {
-                       cce = "no ads";
-                       goto bail3;
-               }
-
-               if (!lws_client_reset(&wsi, ssl, ads, port, path, ads)) {
-                       /* there are two ways to fail out with NULL return...
-                        * simple, early problem where the wsi is intact, or
-                        * we went through with the reconnect attempt and the
-                        * wsi is already closed.  In the latter case, the wsi
-                        * has beet set to NULL additionally.
-                        */
-                       lwsl_err("Redirect failed\n");
-                       cce = "HS: Redirect failed";
-                       if (wsi)
-                               goto bail3;
-
-                       return 1;
-               }
-               return 0;
-       }
-
-       if (!wsi->do_ws) {
-
-               /* if h1 KA is allowed, enable the queued pipeline guys */
-
-               if (!wsi->client_h2_alpn && !wsi->client_h2_substream &&
-                   w == wsi) { /* ie, coming to this for the first time */
-                       if (wsi->http.conn_type == HTTP_CONNECTION_KEEP_ALIVE)
-                               wsi->keepalive_active = 1;
-                       else {
-                               /*
-                                * Ugh... now the main http connection has seen
-                                * both sides, we learn the server doesn't
-                                * support keepalive.
-                                *
-                                * That means any guys queued on us are going
-                                * to have to be restarted from connect2 with
-                                * their own connections.
-                                */
-
-                               /*
-                                * stick around telling any new guys they can't
-                                * pipeline to this server
-                                */
-                               wsi->keepalive_rejected = 1;
-
-                               lws_vhost_lock(wsi->vhost);
-                               lws_start_foreach_dll_safe(struct lws_dll2 *,
-                                                          d, d1,
-                                 wsi->dll2_cli_txn_queue_owner.head) {
-                                       struct lws *ww = lws_container_of(d,
-                                               struct lws,
-                                               dll2_cli_txn_queue);
-
-                                       /* remove him from our queue */
-                                       lws_dll2_remove(&ww->dll2_cli_txn_queue);
-                                       /* give up on pipelining */
-                                       ww->client_pipeline = 0;
-
-                                       /* go back to "trying to connect" state */
-                                       lws_role_transition(ww, LWSIFR_CLIENT,
-                                                           LRS_UNCONNECTED,
-#if defined(LWS_ROLE_H1)
-                                                           &role_ops_h1);
-#else
-#if defined (LWS_ROLE_H2)
-                                                           &role_ops_h2);
-#else
-                                                           &role_ops_raw);
-#endif
-#endif
-                                       ww->user_space = NULL;
-                               } lws_end_foreach_dll_safe(d, d1);
-                               lws_vhost_unlock(wsi->vhost);
-                       }
-               }
-
-#ifdef LWS_WITH_HTTP_PROXY
-               wsi->http.perform_rewrite = 0;
-               if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
-                       if (!strncmp(lws_hdr_simple_ptr(wsi,
-                                               WSI_TOKEN_HTTP_CONTENT_TYPE),
-                                               "text/html", 9))
-                               wsi->http.perform_rewrite = 0;
-               }
-#endif
-
-               /* allocate the per-connection user memory (if any) */
-               if (lws_ensure_user_space(wsi)) {
-                       lwsl_err("Problem allocating wsi user mem\n");
-                       cce = "HS: OOM";
-                       goto bail2;
-               }
-
-               /* he may choose to send us stuff in chunked transfer-coding */
-               wsi->chunked = 0;
-               wsi->chunk_remaining = 0; /* ie, next thing is chunk size */
-               if (lws_hdr_total_length(wsi,
-                                       WSI_TOKEN_HTTP_TRANSFER_ENCODING)) {
-                       wsi->chunked = !strcmp(lws_hdr_simple_ptr(wsi,
-                                              WSI_TOKEN_HTTP_TRANSFER_ENCODING),
-                                               "chunked");
-                       /* first thing is hex, after payload there is crlf */
-                       wsi->chunk_parser = ELCP_HEX;
-               }
-
-               if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
-                       wsi->http.rx_content_length =
-                                       atoll(lws_hdr_simple_ptr(wsi,
-                                               WSI_TOKEN_HTTP_CONTENT_LENGTH));
-                       lwsl_info("%s: incoming content length %llu\n",
-                                   __func__, (unsigned long long)
-                                           wsi->http.rx_content_length);
-                       wsi->http.rx_content_remain =
-                                       wsi->http.rx_content_length;
-               } else /* can't do 1.1 without a content length or chunked */
-                       if (!wsi->chunked)
-                               wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
-
-               /*
-                * we seem to be good to go, give client last chance to check
-                * headers and OK it
-                */
-               if (w->protocol->callback(w,
-                               LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
-                                           w->user_space, NULL, 0)) {
-
-                       cce = "HS: disallowed by client filter";
-                       goto bail2;
-               }
-
-               /* clear his proxy connection timeout */
-               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
-
-               wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
-
-               /* call him back to inform him he is up */
-               if (w->protocol->callback(w,
-                                           LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
-                                           w->user_space, NULL, 0)) {
-                       cce = "HS: disallowed at ESTABLISHED";
-                       goto bail3;
-               }
-
-               /*
-                * for pipelining, master needs to keep his ah... guys who
-                * queued on him can drop it now though.
-                */
-
-               if (w != wsi)
-                       /* free up parsing allocations for queued guy */
-                       lws_header_table_detach(w, 0);
-
-               lwsl_info("%s: client connection up\n", __func__);
-
-               /*
-                * Did we get a response from the server with an explicit
-                * content-length of zero?  If so, this transaction is already
-                * completed at the end of the header processing...
-                */
-               if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
-                   !wsi->http.rx_content_length)
-                       return !!lws_http_transaction_completed_client(wsi);
-
-               return 0;
-       }
-
-#if defined(LWS_ROLE_WS)
-       switch (lws_client_ws_upgrade(wsi, &cce)) {
-       case 2:
-               goto bail2;
-       case 3:
-               goto bail3;
-       }
-
-       return 0;
-#endif
-
-bail3:
-       close_reason = LWS_CLOSE_STATUS_NOSTATUS;
-
-bail2:
-       if (wsi->protocol) {
-               n = 0;
-               if (cce)
-                       n = (int)strlen(cce);
-
-               lws_inform_client_conn_fail(wsi, (void *)cce, (unsigned int)n);
-       }
-
-       lwsl_info("closing connection (prot %s) "
-                 "due to bail2 connection error: %s\n", wsi->protocol ?
-                                 wsi->protocol->name : "unknown", cce);
-
-       /* closing will free up his parsing allocations */
-       lws_close_free_wsi(wsi, close_reason, "c hs interp");
-
-       return 1;
-}
-#endif
-
-char *
-lws_generate_client_handshake(struct lws *wsi, char *pkt)
-{
-       char *p = pkt;
-       const char *meth;
-       const char *pp = lws_hdr_simple_ptr(wsi,
-                               _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
-
-       meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
-       if (!meth) {
-               meth = "GET";
-               wsi->do_ws = 1;
-       } else {
-               wsi->do_ws = 0;
-       }
-
-       if (!strcmp(meth, "RAW")) {
-               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
-               lwsl_notice("client transition to raw\n");
-
-               if (pp) {
-                       const struct lws_protocols *pr;
-
-                       pr = lws_vhost_name_to_protocol(wsi->vhost, pp);
-
-                       if (!pr) {
-                               lwsl_err("protocol %s not enabled on vhost\n",
-                                        pp);
-                               return NULL;
-                       }
-
-                       lws_bind_protocol(wsi, pr, __func__);
-               }
-
-               if ((wsi->protocol->callback)(wsi, LWS_CALLBACK_RAW_ADOPT,
-                                             wsi->user_space, NULL, 0))
-                       return NULL;
-
-               lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
-                                   &role_ops_raw_skt);
-               lws_header_table_detach(wsi, 1);
-
-               return NULL;
-       }
-
-       /*
-        * 04 example client handshake
-        *
-        * GET /chat HTTP/1.1
-        * Host: server.example.com
-        * Upgrade: websocket
-        * Connection: Upgrade
-        * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
-        * Sec-WebSocket-Origin: http://example.com
-        * Sec-WebSocket-Protocol: chat, superchat
-        * Sec-WebSocket-Version: 4
-        */
-
-       p += lws_snprintf(p, 2048, "%s %s HTTP/1.1\x0d\x0a", meth,
-                    lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));
-
-       p += lws_snprintf(p, 64, "Pragma: no-cache\x0d\x0a"
-                       "Cache-Control: no-cache\x0d\x0a");
-
-       p += lws_snprintf(p, 128, "Host: %s\x0d\x0a",
-                    lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
-
-       if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) {
-               if (lws_check_opt(wsi->context->options,
-                                 LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN))
-                       p += lws_snprintf(p, 128, "Origin: %s\x0d\x0a",
-                                    lws_hdr_simple_ptr(wsi,
-                                                    _WSI_TOKEN_CLIENT_ORIGIN));
-               else
-                       p += lws_snprintf(p, 128, "Origin: http://%s\x0d\x0a",
-                                    lws_hdr_simple_ptr(wsi,
-                                                    _WSI_TOKEN_CLIENT_ORIGIN));
-       }
-
-#if defined(LWS_WITH_HTTP_PROXY)
-       if (wsi->parent &&
-           lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
-               p += lws_snprintf(p, 128, "Content-Length: %s\x0d\x0a",
-                       lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH));
-               if (atoi(lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)))
-                       wsi->client_http_body_pending = 1;
-       }
-       if (wsi->parent &&
-           lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION)) {
-               p += lws_snprintf(p, 128, "Authorization: %s\x0d\x0a",
-                       lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION));
-       }
-       if (wsi->parent &&
-           lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
-               p += lws_snprintf(p, 128, "Content-Type: %s\x0d\x0a",
-                       lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE));
-       }
-#endif
-
-#if defined(LWS_ROLE_WS)
-       if (wsi->do_ws) {
-               const char *conn1 = "";
-       //      if (!wsi->client_pipeline)
-       //              conn1 = "close, ";
-               p = lws_generate_client_ws_handshake(wsi, p, conn1);
-       } else
-#endif
-       {
-               if (!wsi->client_pipeline)
-                       p += lws_snprintf(p, 64, "connection: close\x0d\x0a");
-       }
-
-       /* give userland a chance to append, eg, cookies */
-
-       if (wsi->protocol->callback(wsi,
-                       LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
-                       wsi->user_space, &p,
-                       (pkt + wsi->context->pt_serv_buf_size) - p - 12))
-               return NULL;
-
-       p += lws_snprintf(p, 4, "\x0d\x0a");
-
-       // puts(pkt);
-
-       return p;
-}
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-
-LWS_VISIBLE int
-lws_http_client_read(struct lws *wsi, char **buf, int *len)
-{
-       int rlen, n;
-
-       rlen = lws_ssl_capable_read(wsi, (unsigned char *)*buf, *len);
-       *len = 0;
-
-       // lwsl_notice("%s: rlen %d\n", __func__, rlen);
-
-       /* allow the source to signal he has data again next time */
-       if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
-               return -1;
-
-       if (rlen == LWS_SSL_CAPABLE_ERROR) {
-               lwsl_debug("%s: SSL capable error\n", __func__);
-               return -1;
-       }
-
-       if (rlen <= 0)
-               return 0;
-
-       *len = rlen;
-       wsi->client_rx_avail = 0;
-
-       /*
-        * server may insist on transfer-encoding: chunked,
-        * so http client must deal with it
-        */
-spin_chunks:
-       while (wsi->chunked && (wsi->chunk_parser != ELCP_CONTENT) && *len) {
-               switch (wsi->chunk_parser) {
-               case ELCP_HEX:
-                       if ((*buf)[0] == '\x0d') {
-                               wsi->chunk_parser = ELCP_CR;
-                               break;
-                       }
-                       n = char_to_hex((*buf)[0]);
-                       if (n < 0) {
-                               lwsl_info("%s: chunking failure\n", __func__);
-                               return -1;
-                       }
-                       wsi->chunk_remaining <<= 4;
-                       wsi->chunk_remaining |= n;
-                       break;
-               case ELCP_CR:
-                       if ((*buf)[0] != '\x0a') {
-                               lwsl_info("%s: chunking failure\n", __func__);
-                               return -1;
-                       }
-                       wsi->chunk_parser = ELCP_CONTENT;
-                       lwsl_info("chunk %d\n", wsi->chunk_remaining);
-                       if (wsi->chunk_remaining)
-                               break;
-                       lwsl_info("final chunk\n");
-                       goto completed;
-
-               case ELCP_CONTENT:
-                       break;
-
-               case ELCP_POST_CR:
-                       if ((*buf)[0] != '\x0d') {
-                               lwsl_info("%s: chunking failure\n", __func__);
-
-                               return -1;
-                       }
-
-                       wsi->chunk_parser = ELCP_POST_LF;
-                       break;
-
-               case ELCP_POST_LF:
-                       if ((*buf)[0] != '\x0a') {
-                               lwsl_info("%s: chunking failure\n", __func__);
-
-                               return -1;
-                       }
-
-                       wsi->chunk_parser = ELCP_HEX;
-                       wsi->chunk_remaining = 0;
-                       break;
-               }
-               (*buf)++;
-               (*len)--;
-       }
-
-       if (wsi->chunked && !wsi->chunk_remaining)
-               return 0;
-
-       if (wsi->http.rx_content_remain &&
-           wsi->http.rx_content_remain < (unsigned int)*len)
-               n = (int)wsi->http.rx_content_remain;
-       else
-               n = *len;
-
-       if (wsi->chunked && wsi->chunk_remaining &&
-           wsi->chunk_remaining < n)
-               n = wsi->chunk_remaining;
-
-#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_WITH_HUBBUB)
-       /* hubbub */
-       if (wsi->http.perform_rewrite)
-               lws_rewrite_parse(wsi->http.rw, (unsigned char *)*buf, n);
-       else
-#endif
-       {
-               struct lws *wsi_eff = lws_client_wsi_effective(wsi);
-
-               if (
-#if defined(LWS_WITH_HTTP_PROXY)
-                   !wsi_eff->protocol_bind_balance ==
-                   !!wsi_eff->http.proxy_clientside &&
-#else
-                   !!wsi_eff->protocol_bind_balance &&
-#endif
-                   user_callback_handle_rxflow(wsi_eff->protocol->callback,
-                               wsi_eff, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
-                               wsi_eff->user_space, *buf, n)) {
-                       lwsl_info("%s: RECEIVE_CLIENT_HTTP_READ returned -1\n",
-                                  __func__);
-
-                       return -1;
-               }
-       }
-
-       if (wsi->chunked && wsi->chunk_remaining) {
-               (*buf) += n;
-               wsi->chunk_remaining -= n;
-               *len -= n;
-       }
-
-       if (wsi->chunked && !wsi->chunk_remaining)
-               wsi->chunk_parser = ELCP_POST_CR;
-
-       if (wsi->chunked && *len)
-               goto spin_chunks;
-
-       if (wsi->chunked)
-               return 0;
-
-       /* if we know the content length, decrement the content remaining */
-       if (wsi->http.rx_content_length > 0)
-               wsi->http.rx_content_remain -= n;
-
-       // lwsl_notice("rx_content_remain %lld, rx_content_length %lld\n",
-       //      wsi->http.rx_content_remain, wsi->http.rx_content_length);
-
-       if (wsi->http.rx_content_remain || !wsi->http.rx_content_length)
-               return 0;
-
-completed:
-
-       if (lws_http_transaction_completed_client(wsi)) {
-               lwsl_notice("%s: transaction completed says -1\n", __func__);
-               return -1;
-       }
-
-       return 0;
-}
-
-#endif
index 8d9d57f..ad42872 100644 (file)
@@ -6,7 +6,7 @@ specifically HTTP content streams, after the header, be it h1 or h2.
 
 The compression transforms expose an "ops" type struct and a compressor name
 as used by `content-encoding`... the ops struct definition can be found in
-./private.h.
+./private-lib-roles-http-compression.h.
 
 Because the compression transform depends on being able to send on its output
 before it can process new input, the transform adds a new kind of buflist
index 0c977de..36d7766 100644 (file)
@@ -1,31 +1,33 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-
+#include "private-lib-core.h"
 
 static int
 lcs_init_compression_brotli(lws_comp_ctx_t *ctx, int decomp)
 {
-       ctx->is_decompression = decomp;
+       ctx->is_decompression = (unsigned char)!!decomp;
 
        if (!decomp) {
                ctx->u.br_en = BrotliEncoderCreateInstance(NULL, NULL, NULL);
index c092ec5..8e9a1ca 100644 (file)
@@ -1,32 +1,35 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 static int
 lcs_init_compression_deflate(lws_comp_ctx_t *ctx, int decomp)
 {
        int n;
 
-       ctx->is_decompression = decomp;
+       ctx->is_decompression = !!decomp;
        ctx->u.deflate = lws_malloc(sizeof(*ctx->u.deflate), __func__);
 
        if (!ctx->u.deflate)
@@ -60,10 +63,10 @@ lcs_process_deflate(lws_comp_ctx_t *ctx, const void *in, size_t *ilen_iused,
        int n;
 
        ctx->u.deflate->next_in = (void *)in;
-       ctx->u.deflate->avail_in = *ilen_iused;
+       ctx->u.deflate->avail_in = (unsigned int)*ilen_iused;
 
        ctx->u.deflate->next_out = out;
-       ctx->u.deflate->avail_out = *olen_oused;
+       ctx->u.deflate->avail_out = (unsigned int)*olen_oused;
 
        if (!ctx->is_decompression)
                n = deflate(ctx->u.deflate, Z_SYNC_FLUSH);
@@ -1,24 +1,27 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
- *  This is included from core/private.h if LWS_WITH_HTTP_STREAM_COMPRESSION
+ *  This is included from private-lib-core.h if LWS_WITH_HTTP_STREAM_COMPRESSION
  */
 
 #if defined(LWS_WITH_MINIZ)
index 7acb58e..9898b76 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /* compression methods listed in order of preference */
 
@@ -49,12 +52,12 @@ lws_http_compression_validate(struct lws *wsi)
 
        for (n = 0; n < LWS_ARRAY_SIZE(lcs_available); n++)
                if (strstr(a, lcs_available[n]->encoding_name))
-                       wsi->http.comp_accept_mask |= 1 << n;
+                       wsi->http.comp_accept_mask = (uint8_t)(wsi->http.comp_accept_mask | (1 << n));
 
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_http_compression_apply(struct lws *wsi, const char *name,
                           unsigned char **p, unsigned char *end, char decomp)
 {
@@ -88,15 +91,15 @@ lws_http_compression_apply(struct lws *wsi, const char *name,
        wsi->http.comp_ctx.may_have_more = 0;
        wsi->http.comp_ctx.final_on_input_side = 0;
        wsi->http.comp_ctx.chunking = 0;
-       wsi->http.comp_ctx.is_decompression = decomp;
+       wsi->http.comp_ctx.is_decompression = !!decomp;
 
        if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING,
                        (unsigned char *)lcs_available[n]->encoding_name,
-                       strlen(lcs_available[n]->encoding_name), p, end))
+                       (int)strlen(lcs_available[n]->encoding_name), p, end))
                return -1;
 
-       lwsl_info("%s: wsi %p: applied %s content-encoding\n", __func__,
-                   wsi, lcs_available[n]->encoding_name);
+       lwsl_info("%s: %s: applied %s content-encoding\n", __func__,
+                   lws_wsi_tag(wsi), lcs_available[n]->encoding_name);
 
        return 0;
 }
@@ -148,10 +151,10 @@ lws_http_compression_transform(struct lws *wsi, unsigned char *buf,
                 * to a non-final for now.
                 */
                ctx->final_on_input_side = 1;
-               *wp = LWS_WRITE_HTTP | ((*wp) & ~0x1f);
+               *wp = (unsigned int)(LWS_WRITE_HTTP | ((*wp) & ~0x1fu));
        }
 
-       if (ctx->buflist_comp || ctx->may_have_more) {
+       if (ctx->buflist_comp) {
                /*
                 * we can't send this new stuff when we have old stuff
                 * buffered and not compressed yet.  Add it to the tail
@@ -161,22 +164,22 @@ lws_http_compression_transform(struct lws *wsi, unsigned char *buf,
                        if (lws_buflist_append_segment(
                                        &ctx->buflist_comp, buf, len) < 0)
                                return -1;
-                       lwsl_debug("%s: %p: adding %d to comp buflist\n",
-                                  __func__,wsi, (int)len);
+                       lwsl_debug("%s: %s: adding %d to comp buflist\n",
+                                  __func__, lws_wsi_tag(wsi), (int)len);
                }
 
                len = lws_buflist_next_segment_len(&ctx->buflist_comp, &buf);
                ilen_iused = len;
                use = 1;
-               lwsl_debug("%s: %p: trying comp buflist %d\n", __func__, wsi,
-                          (int)len);
+               lwsl_debug("%s: %s: trying comp buflist %d\n", __func__,
+                               lws_wsi_tag(wsi), (int)len);
        }
 
        if (!buf && ilen_iused)
                return 0;
 
-       lwsl_debug("%s: %p: pre-process: ilen_iused %d, olen_oused %d\n",
-                  __func__, wsi, (int)ilen_iused, (int)*olen_oused);
+       lwsl_debug("%s: %s: pre-process: ilen_iused %d, olen_oused %d\n",
+                  __func__, lws_wsi_tag(wsi), (int)ilen_iused, (int)*olen_oused);
 
        n = wsi->http.lcs->process(ctx, buf, &ilen_iused, *outbuf, olen_oused);
 
@@ -187,9 +190,10 @@ lws_http_compression_transform(struct lws *wsi, unsigned char *buf,
        }
 
        if (!ctx->may_have_more && ctx->final_on_input_side)
-               *wp = LWS_WRITE_HTTP_FINAL | ((*wp) & ~0x1f);
 
-       lwsl_debug("%s: %p: more %d, ilen_iused %d\n", __func__, wsi,
+               *wp = (unsigned int)(LWS_WRITE_HTTP_FINAL | ((*wp) & ~0x1fu));
+
+       lwsl_debug("%s: %s: more %d, ilen_iused %d\n", __func__, lws_wsi_tag(wsi),
                   ctx->may_have_more, (int)ilen_iused);
 
        if (use && ilen_iused) {
@@ -199,9 +203,9 @@ lws_http_compression_transform(struct lws *wsi, unsigned char *buf,
                 * transform
                 */
                lws_buflist_use_segment(&ctx->buflist_comp, ilen_iused);
-               lwsl_debug("%s: %p: marking %d of comp buflist as used "
-                          "(ctx->buflist_comp %p)\n", __func__, wsi,
-                          (int)len, ctx->buflist_comp);
+               lwsl_debug("%s: %s: marking %d of comp buflist as used "
+                          "(ctx->buflist_comp %p)\n", __func__,
+                          lws_wsi_tag(wsi), (int)len, ctx->buflist_comp);
        }
 
        if (!use && ilen_iused != len) {
diff --git a/lib/roles/http/cookie.c b/lib/roles/http/cookie.c
new file mode 100644 (file)
index 0000000..03b88ae
--- /dev/null
@@ -0,0 +1,729 @@
+
+#include <libwebsockets.h>
+#include "private-lib-core.h"
+
+//#define LWS_COOKIE_DEBUG
+
+#if defined(LWS_COOKIE_DEBUG)
+       #define lwsl_cookie lwsl_notice
+#else
+       #define lwsl_cookie lwsl_debug
+#endif
+
+#define LWS_COOKIE_MAX_CACHE_NAME_LEN  128
+
+#define lws_tolower(_c) (((_c) >= 'A' && (_c) <= 'Z') ? \
+                                           (char)((_c) + 'a' - 'A') : \
+                                           (char)(_c))
+
+#define LWS_COOKIE_NSC_FORMAT            "%.*s\t"\
+                                         "%s\t"\
+                                         "%.*s\t"\
+                                         "%s\t"\
+                                         "%llu\t"\
+                                         "%.*s\t"\
+                                         "%.*s"
+
+static const char *const mon = "janfebmaraprnayjunjulaugsepoctnovdec";
+
+enum lws_cookie_nsc_f {
+       LWSC_NSC_DOMAIN,
+       LWSC_NSC_HOSTONLY,
+       LWSC_NSC_PATH,
+       LWSC_NSC_SECURE,
+       LWSC_NSC_EXPIRES,
+       LWSC_NSC_NAME,
+       LWSC_NSC_VALUE,
+
+       LWSC_NSC_COUNT,
+};
+
+enum lws_cookie_elements {
+       CE_DOMAIN,
+       CE_PATH,
+       CE_EXPIRES,
+       CE_MAXAGE,
+       CE_NAME,
+       CE_VALUE,
+
+       CE_HOSTONLY, /* these are bool, NULL = 0, non-NULL = 1 */
+       CE_SECURE,
+
+       CE_COUNT
+};
+
+struct lws_cookie {
+       const char      *f[CE_COUNT];
+       size_t          l[CE_COUNT];
+
+       unsigned int httponly:1;
+};
+
+static int
+lws_cookie_parse_date(const char *d, size_t len, time_t *t)
+{
+       struct tm date;
+       int offset = 0, i;
+
+       memset(&date, 0, sizeof(date));
+
+       while (len) {
+               if (isalnum((int)*d)) {
+                       offset++;
+                       goto next;
+               }
+               switch (offset) {
+               case 2:
+                       if (*d == ':' && len >= 6) {
+                               date.tm_hour = atoi(d - 2);
+                               if (date.tm_hour < 0 || date.tm_hour > 23)
+                                       return -1;
+                               date.tm_min = atoi(d + 1);
+                               if (date.tm_min < 0 || date.tm_min > 60)
+                                       return -1;
+                               date.tm_sec = atoi(d + 4);
+                               if (date.tm_sec < 0 || date.tm_sec > 61)
+                                       /* leap second */
+                                       return -1;
+
+                               d += 6;
+                               len -= 6;
+                               offset = 0;
+                               continue;
+                       }
+
+                       if (!date.tm_mday) {
+                               date.tm_mday = atoi(d - 2);
+                               if (date.tm_mday < 1 || date.tm_mday > 31)
+                                       return -1;
+                               goto next2;
+                       }
+
+                       if (!date.tm_year) {
+                               date.tm_year = atoi(d - 2);
+                               if (date.tm_year < 0 || date.tm_year > 99)
+                                       return -1;
+                               if (date.tm_year < 70)
+                                       date.tm_year += 100;
+                       }
+                       goto next2;
+
+               case 3:
+                       for (i = 0; i < 36; i += 3) {
+                               if (lws_tolower(*(d - 3)) == mon[i] &&
+                                   lws_tolower(*(d - 2)) == mon[i + 1] &&
+                                   lws_tolower(*(d - 1)) == mon[i + 2]) {
+                                       date.tm_mon = i / 3;
+                                       break;
+                               }
+                       }
+                       goto next2;
+
+               case 4:
+                       if (!date.tm_year) {
+                               date.tm_year = atoi(d - 4);
+                               if (date.tm_year < 1601)
+                                       return -1;
+                               date.tm_year -= 1900;
+                       }
+                       goto next2;
+
+               default:
+                       goto next2;
+               }
+
+next2:
+               offset = 0;
+next:
+               d++;
+               len--;
+       }
+
+       *t = mktime(&date);
+
+       if (*t < 0)
+               return -1;
+
+       return 0;
+}
+
+static void
+lws_cookie_rm_sws(const char **buf_p, size_t *len_p)
+{
+       const char *buf;
+       size_t len;
+
+       if (!buf_p || !*buf_p || !len_p || !*len_p) {
+               lwsl_err("%s: false parameter\n", __func__);
+               return;
+       }
+
+       buf = *buf_p;
+       len = *len_p;
+       while (buf[0] == ' ' && len > 0) {
+               buf++;
+               len--;
+       }
+       while (buf[len - 1] == ' ' && len > 0)
+               len--;
+
+       *buf_p = buf;
+       *len_p = len;
+}
+
+static int
+is_iprefix(const char *h, size_t hl, const char *n, size_t nl)
+{
+       if (!h || !n || nl > hl)
+               return 0;
+
+       while (nl) {
+               nl--;
+               if (lws_tolower(h[nl]) != lws_tolower(n[nl]))
+                       return 0;
+       }
+       return 1;
+}
+
+static int
+lws_cookie_compile_cache_name(char *buf, size_t buf_len, struct lws_cookie *c)
+{
+       if (!buf || !c->f[CE_DOMAIN] || !c->f[CE_PATH] || !c->f[CE_NAME] ||
+           c->l[CE_DOMAIN] + c->l[CE_PATH] + c->l[CE_NAME] + 6 > buf_len)
+               return -1;
+
+       memcpy(buf, c->f[CE_DOMAIN], c->l[CE_DOMAIN]);
+       buf += c->l[CE_DOMAIN];
+       *buf++ = '|';
+
+       memcpy(buf, c->f[CE_PATH], c->l[CE_PATH]);
+       buf += c->l[CE_PATH];
+       *buf++ = '|';
+
+       memcpy(buf, c->f[CE_NAME], c->l[CE_NAME]);
+       buf += c->l[CE_NAME];
+       *buf = '\0';
+
+       return 0;
+}
+
+static int
+lws_cookie_parse_nsc(struct lws_cookie *c, const char *b, size_t l)
+{
+       enum lws_cookie_nsc_f state = LWSC_NSC_DOMAIN;
+       size_t n = 0;
+
+       if (!c || !b || l < 13)
+               return -1;
+
+       memset(c, 0, sizeof(*c));
+       lwsl_cookie("%s: parsing (%.*s) \n", __func__, (int)l, b);
+
+       while (l) {
+               l--;
+               if (b[n] != '\t' && l) {
+                       n++;
+                       continue;
+               }
+               switch (state) {
+               case LWSC_NSC_DOMAIN:
+                       c->f[CE_DOMAIN] = b;
+                       c->l[CE_DOMAIN] = n;
+                       break;
+               case LWSC_NSC_PATH:
+                       c->f[CE_PATH] = b;
+                       c->l[CE_PATH] = n;
+                       break;
+               case LWSC_NSC_EXPIRES:
+                       c->f[CE_EXPIRES] = b;
+                       c->l[CE_EXPIRES] = n;
+                       break;
+               case LWSC_NSC_NAME:
+                       c->f[CE_NAME] = b;
+                       c->l[CE_NAME] = n;
+                       break;
+
+               case LWSC_NSC_HOSTONLY:
+                       if (b[0] == 'T') {
+                               c->f[CE_HOSTONLY] = b;
+                               c->l[CE_HOSTONLY] = 1;
+                       }
+                       break;
+               case LWSC_NSC_SECURE:
+                       if (b[0] == 'T') {
+                               c->f[CE_SECURE] = b;
+                               c->l[CE_SECURE] = 1;
+                       }
+                       break;
+
+               case LWSC_NSC_VALUE:
+                       c->f[CE_VALUE] = b;
+                       c->l[CE_VALUE] = n + 1;
+
+                       for (n = 0; n < LWS_ARRAY_SIZE(c->f); n++)
+                               lwsl_cookie("%s: %d: %.*s\n", __func__,
+                                               (int)n, (int)c->l[n], c->f[n]);
+
+                       return 0;
+               default:
+                       return -1;
+               }
+
+               b += n + 1;
+               n = 0;
+               state++;
+       }
+
+       return -1;
+}
+
+static int
+lws_cookie_write_nsc(struct lws *wsi, struct lws_cookie *c)
+{
+       char cache_name[LWS_COOKIE_MAX_CACHE_NAME_LEN];
+       struct lws_cache_ttl_lru *l1;
+       struct client_info_stash *stash;
+       char *cookie_string = NULL, *dl;
+        /* 6 tabs + 20 for max time_t + 2 * TRUE/FALSE + null */
+       size_t size = 6 + 20 + 10 + 1;
+       time_t expires = 0;
+       int ret = 0;
+
+       if (!wsi || !c)
+               return -1;
+
+       l1 = wsi->a.context->l1;
+       if (!l1 || !wsi->a.context->nsc)
+               return -1;
+
+       stash = wsi->stash ? wsi->stash : lws_get_network_wsi(wsi)->stash;
+       if (!stash || !stash->cis[CIS_ADDRESS] ||
+                          !stash->cis[CIS_PATH])
+               return -1;
+
+
+       if (!c->f[CE_NAME] || !c->f[CE_VALUE]) {
+               lwsl_err("%s: malformed c\n", __func__);
+
+               return -1;
+       }
+
+       if (!c->f[CE_EXPIRES]) {
+               /*
+                * Currently we just take the approach to reject session cookies
+                */
+               lwsl_warn("%s: reject session cookies\n", __func__);
+
+               return 0;
+       }
+
+       if (!c->f[CE_DOMAIN]) {
+               c->f[CE_HOSTONLY] = "T";
+               c->l[CE_HOSTONLY] = 1;
+               c->f[CE_DOMAIN] = stash->cis[CIS_ADDRESS];
+               c->l[CE_DOMAIN] = strlen(c->f[CE_DOMAIN]);
+       }
+
+       if (!c->f[CE_PATH]) {
+               c->f[CE_PATH] = stash->cis[CIS_PATH];
+               c->l[CE_PATH] = strlen(c->f[CE_PATH]);
+               dl = memchr(c->f[CE_PATH], '?', c->l[CE_PATH]);
+               if (dl)
+                       c->l[CE_PATH] = (size_t)(dl - c->f[CE_PATH]);
+       }
+
+       if (lws_cookie_compile_cache_name(cache_name, sizeof(cache_name), c))
+               return -1;
+
+       if (c->f[CE_EXPIRES] &&
+           lws_cookie_parse_date(c->f[CE_EXPIRES], c->l[CE_EXPIRES], &expires)) {
+               lwsl_err("%s: can't parse date %.*s\n", __func__,
+                        (int)c->l[CE_EXPIRES], c->f[CE_EXPIRES]);
+               return -1;
+       }
+
+       size += c->l[CE_NAME] + c->l[CE_VALUE] + c->l[CE_DOMAIN] + c->l[CE_PATH];
+       cookie_string = (char *)lws_malloc(size, __func__);
+       if (!cookie_string) {
+               lwsl_err("%s: OOM\n",__func__);
+
+               return -1;      
+       }
+
+       lws_snprintf(cookie_string, size, LWS_COOKIE_NSC_FORMAT,
+                       (int)c->l[CE_DOMAIN], c->f[CE_DOMAIN],
+                       c->f[CE_HOSTONLY] ? "TRUE" : "FALSE",
+                       (int)c->l[CE_PATH], c->f[CE_PATH],
+                       c->f[CE_SECURE] ? "TRUE" : "FALSE",
+                       (unsigned long long)expires,
+                       (int)c->l[CE_NAME], c->f[CE_NAME],
+                       (int)c->l[CE_VALUE], c->f[CE_VALUE]);
+
+       lwsl_cookie("%s: name %s\n", __func__, cache_name);
+       lwsl_cookie("%s: c %s\n", __func__, cookie_string);
+
+       if (lws_cache_write_through(l1, cache_name,
+                                   (const uint8_t *)cookie_string,
+                                   strlen(cookie_string),
+                                   (lws_usec_t)((unsigned long long)expires *
+                                          (lws_usec_t)LWS_US_PER_SEC), NULL)) {
+               ret = -1;
+               goto exit;
+       }
+
+#if defined(LWS_COOKIE_DEBUG)
+       char *po;
+       if (lws_cache_item_get(l1, cache_name, (const void **)&po, &size) ||
+           size != strlen(cookie_string) || memcmp(po, cookie_string, size)) {
+               lwsl_err("%s: L1 '%s' missing\n", __func__, cache_name);
+       }
+
+       if (lws_cache_item_get(wsi->a.context->nsc, cache_name,
+                              (const void **)&po, &size) ||
+                              size != strlen(cookie_string) ||
+                              memcmp(po, cookie_string, size)) {
+               lwsl_err("%s: NSC '%s' missing, size %llu, po %s\n", __func__,
+                        cache_name, (unsigned long long)size, po);
+       }
+#endif
+
+exit:
+       lws_free(cookie_string);
+
+       return ret;
+}
+
+static int
+lws_cookie_attach_cookies(struct lws *wsi, char *buf, char *end)
+{
+       const char *domain, *path, *dl_domain, *dl_path, *po;
+       char cache_name[LWS_COOKIE_MAX_CACHE_NAME_LEN];
+       size_t domain_len, path_len, size, ret = 0;
+       struct lws_cache_ttl_lru *l1;
+       struct client_info_stash *stash;
+       lws_cache_results_t cr;
+       struct lws_cookie c;
+       int hostdomain = 1;
+       char *p, *p1;
+
+       if (!wsi)
+               return -1;
+
+       stash = wsi->stash ? wsi->stash : lws_get_network_wsi(wsi)->stash;
+       if (!stash || !stash->cis[CIS_ADDRESS] ||
+                          !stash->cis[CIS_PATH])
+               return -1;
+
+       l1 = wsi->a.context->l1;
+       if (!l1 || !wsi->a.context->nsc){
+               lwsl_err("%s:no cookiejar\n", __func__);
+               return -1;
+       }
+
+       memset(&c, 0, sizeof(c));
+
+       domain = stash->cis[CIS_ADDRESS];
+       path = stash->cis[CIS_PATH];
+
+       if (!domain || !path)
+               return -1;
+
+       path_len = strlen(path);
+
+       /* remove query string if exist */
+       dl_path = memchr(path, '?', path_len);
+       if (dl_path)
+               path_len = lws_ptr_diff_size_t(dl_path,  path);
+
+       /* remove last slash if exist */
+       if (path_len != 1 && path[path_len - 1] == '/')
+               path_len--;
+
+       if (!path_len)
+               return -1;
+
+       lwsl_cookie("%s: path %.*s len %d\n", __func__, (int)path_len, path, (int)path_len);
+
+       /* when dest buf is not provided, we only return size of cookie string */
+       if (!buf || !end)
+               p = NULL;
+       else
+               p = buf;
+
+       /* iterate through domain and path levels to find matching cookies */
+       dl_domain = domain;
+       while (dl_domain) {
+               domain_len = strlen(domain);
+               dl_domain = memchr(domain, '.', domain_len);
+               /* don't match top level domain */
+               if (!dl_domain)
+                       break;
+
+               if (domain_len + path_len + 6 > sizeof(cache_name))
+                       return -1;
+
+               /* compile key string "[domain]|[path]|*"" */
+               p1 = cache_name;
+               memcpy(p1, domain, domain_len);
+               p1 += domain_len;
+               *p1 = '|';
+               p1++;
+               memcpy(p1, path, path_len);
+               p1 += path_len;
+               *p1 = '|';
+               p1++;
+               *p1 = '*';
+               p1++;
+               *p1 = '\0';
+
+               lwsl_cookie("%s: looking for %s\n", __func__, cache_name);
+
+               if (!lws_cache_lookup(l1, cache_name,
+                                     (const void **)&cr.ptr, &cr.size)) {
+
+                       while (!lws_cache_results_walk(&cr)) {
+                               lwsl_cookie(" %s (%d)\n", (const char *)cr.tag,
+                                               (int)cr.payload_len);
+
+                               if (lws_cache_item_get(l1, (const char *)cr.tag,
+                                                  (const void **)&po, &size) ||
+                                       lws_cookie_parse_nsc(&c, po, size)) {
+                                       lwsl_err("%s: failed to get c '%s'\n",
+                                                       __func__, cr.tag);
+                                       break;
+                               }
+
+                               if (c.f[CE_HOSTONLY] && !hostdomain){
+                                       lwsl_cookie("%s: not sending this\n",
+                                                       __func__);
+                                       continue;
+                               }
+
+                               if (p) {
+                                       if (ret) {
+                                               *p = ';';
+                                               p++;
+                                               *p = ' ';
+                                               p++;
+                                       }
+
+                                       memcpy(p, c.f[CE_NAME], c.l[CE_NAME]);
+                                       p += c.l[CE_NAME];
+                                       *p = '=';
+                                       p++;
+                                       memcpy(p, c.f[CE_VALUE], c.l[CE_VALUE]);
+                                       p += c.l[CE_VALUE];
+                               }
+
+                               if (ret)
+                                       ret += 2;
+                               ret += c.l[CE_NAME] + 1 + c.l[CE_VALUE];
+
+                       }
+               }
+
+               domain = dl_domain + 1;
+               hostdomain = 0;
+       }
+
+       lwsl_notice("%s: c len (%d)\n", __func__, (int)ret);
+
+       return (int)ret;
+}
+
+static struct {
+       const char              *const name;
+       uint8_t                 len;
+} cft[] = {
+       { "domain=",  7 },
+       { "path=",    5 },
+       { "expires=", 8 },
+       { "max-age=", 8 },
+       { "httponly", 8 },
+       { "secure",   6 }
+};
+
+int
+lws_parse_set_cookie(struct lws *wsi)
+{
+       char *tk_head, *tk_end, *buf_head, *buf_end, *cookiep, *dl;
+       struct lws_cache_ttl_lru *l1;
+       struct lws_cookie c;
+       size_t fl;
+       int f, n;
+
+       if (!wsi)
+               return -1;
+
+       l1 = wsi->a.context->l1;
+       if (!l1)
+               return -1;
+
+       f = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_SET_COOKIE];
+
+       while (f) {
+               cookiep = wsi->http.ah->data + wsi->http.ah->frags[f].offset;
+               fl = wsi->http.ah->frags[f].len;
+               f = wsi->http.ah->frags[f].nfrag;
+
+               if (!cookiep || !fl)
+                       continue;
+
+#if defined(LWS_COOKIE_DEBUG)
+               lwsl_notice("%s:parsing: %.*s\n", __func__, (int)fl, cookiep);
+#endif
+
+               buf_head = cookiep;
+               buf_end = cookiep + fl - 1;
+               memset(&c, 0, sizeof(struct lws_cookie));
+
+               do {
+                       tk_head = buf_head;
+                       tk_end = memchr(buf_head, ';',
+                                       (size_t)(buf_end - buf_head + 1));
+                       if (!tk_end) {
+                               tk_end = buf_end;
+                               buf_head = buf_end;
+                       } else {
+                               buf_head = tk_end + 1;
+                               tk_end--;
+                       }
+
+                       if (c.f[CE_NAME])
+                               goto parse_av;
+
+                       /*
+                        * find name value, remove leading trailing
+                        * WS and DQ for value
+                        */
+
+                       dl = memchr(tk_head, '=', lws_ptr_diff_size_t(tk_end,
+                                                       tk_head + 1));
+                       if (!dl || dl == tk_head)
+                               return -1;
+
+                       c.f[CE_NAME] = tk_head;
+                       c.l[CE_NAME] = lws_ptr_diff_size_t(dl, tk_head);
+                       lws_cookie_rm_sws(&c.f[CE_NAME], &c.l[CE_NAME]);
+
+                       if (!c.l[CE_NAME])
+                               return -1;
+
+                       lwsl_cookie("%s: c name l %d v:%.*s\n", __func__,
+                                       (int)c.l[CE_NAME],
+                                       (int)c.l[CE_NAME], c.f[CE_NAME]);
+                       c.f[CE_VALUE] = dl + 1;
+                       c.l[CE_VALUE] = lws_ptr_diff_size_t(tk_end,
+                                                  c.f[CE_VALUE]) + 1;
+
+                       lws_cookie_rm_sws(&c.f[CE_VALUE], &c.l[CE_VALUE]);
+                       if (c.l[CE_VALUE] >= 2 && c.f[CE_VALUE][0] == '\"') {
+                               c.f[CE_VALUE]++;
+                               c.l[CE_VALUE] -= 2;
+                       }
+                       lwsl_cookie("%s: c value l %d v:%.*s\n", __func__,
+                                   (int)c.l[CE_VALUE], (int)c.l[CE_VALUE],
+                                   c.f[CE_VALUE]);
+                       continue;
+
+parse_av:
+                       while (*tk_head == ' ') {
+                               if (tk_head == tk_end)
+                                       return -1;
+
+                               tk_head++;
+                       }
+
+                       for (n = 0; n < (int)LWS_ARRAY_SIZE(cft); n++) {
+                               if (lws_tolower(*tk_head) != cft[n].name[0])
+                                       continue;
+
+                               if (!is_iprefix(tk_head,
+                                               lws_ptr_diff_size_t(tk_end,
+                                                                  tk_head) + 1,
+                                               cft[n].name, cft[n].len))
+                                       continue;
+
+                               if (n == 4 || n == 5) {
+                                       c.f[n] = "T";
+                                       c.l[n] = 1;
+                                       break;
+                               }
+
+                               c.f[n] = tk_head + cft[n].len;
+                               c.l[n] = lws_ptr_diff_size_t(tk_end, c.f[n]) + 1;
+                               lws_cookie_rm_sws(&c.f[n], &c.l[n]);
+
+                               if (n == CE_DOMAIN && c.l[0] &&
+                                   c.f[n][0] == '.'){
+                                       c.f[n]++;
+                                       c.l[n]--;
+                               }
+
+                               lwsl_cookie("%s: %s l %d v:%.*s\n", __func__,
+                                           cft[n].name, (int)c.l[n],
+                                           (int)c.l[n], c.f[n]);
+                               break;
+                       }
+
+               } while (tk_end != buf_end);
+
+               if (lws_cookie_write_nsc(wsi, &c))
+                       lwsl_err("%s:failed to write nsc\n", __func__);
+       }
+
+       return 0;
+}
+
+int
+lws_cookie_send_cookies(struct lws *wsi, char **pp, char *end)
+{
+       char *p;
+       int size;
+
+       if (!wsi || !pp || !(*pp) || !end)
+               return -1;
+
+       size = lws_cookie_attach_cookies(wsi, NULL, NULL);
+
+       if (!size)
+               return 0;
+       if (size < 0) {
+               lwsl_err("%s:failed to get cookie string size\n", __func__);
+               return -1;
+       }
+
+       lwsl_notice("%s: size %d\n", __func__, size);
+
+#if defined(LWS_COOKIE_DEBUG)
+               char *p_dbg = *pp;
+#endif
+
+       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_COOKIE, NULL, size,
+                                                               (unsigned char **)pp, (unsigned char *)end))
+               return -1;
+
+#if defined(LWS_COOKIE_DEBUG)
+               lwsl_notice("%s: dummy copy (%.*s) \n", __func__, (int)(*pp - p_dbg), p_dbg);
+#endif
+
+
+#ifdef LWS_WITH_HTTP2
+       if (lws_wsi_is_h2(wsi))
+               p = *pp - size;
+       else
+#endif
+               p = *pp - size - 2;
+
+       if (lws_cookie_attach_cookies(wsi, p, p + size) <= 0) {
+               lwsl_err("%s:failed to attach cookies\n", __func__);
+               return -1;
+       }
+
+#if defined(LWS_COOKIE_DEBUG)
+               lwsl_notice("%s: real copy (%.*s) total len %d\n", __func__, (int)(*pp - p_dbg), p_dbg, (int)(*pp - p_dbg));
+               lwsl_hexdump_notice(p_dbg, (size_t)(*pp - p_dbg));
+#endif
+
+       return 0;
+}
diff --git a/lib/roles/http/date.c b/lib/roles/http/date.c
new file mode 100644 (file)
index 0000000..6ac42ba
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * RFC7231 date string generation and parsing
+ */
+
+#include "private-lib-core.h"
+
+/*
+ * To avoid needless pointers, we encode these in one string using the fact
+ * they're 3 chars each to index it
+ */
+
+static const char *const s =
+               "JanFebMarAprMayJunJulAugSepOctNovDecMonTueWedThuFriSatSun";
+
+static int
+lws_http_date_render(char *buf, size_t len, const struct tm *tm)
+{
+       const char *w = s + 36 + (3 * tm->tm_wday), *m = s + (3 * tm->tm_mon);
+
+       if (len < 29)
+               return -1;
+
+       lws_snprintf(buf, len, "%c%c%c, %02d %c%c%c %d %02d:%02d:%02d GMT",
+                    w[0], w[1], w[2], tm->tm_mday, m[0], m[1], m[2],
+                    1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       return 0;
+}
+
+
+int
+lws_http_date_render_from_unix(char *buf, size_t len, const time_t *t)
+{
+#if defined(LWS_HAVE_GMTIME_R)
+       struct tm tmp;
+       struct tm *tm = gmtime_r(t, &tmp);
+#else
+       struct tm *tm = gmtime(t);
+#endif
+       if (!tm)
+               return -1;
+
+       if (lws_http_date_render(buf, len, tm))
+               return -1;
+
+       return 0;
+}
+
+static int
+lws_http_date_parse(const char *b, size_t len, struct tm *tm)
+{
+       int n;
+
+       if (len < 29)
+               return -1;
+
+       /*
+        * We reject anything that isn't a properly-formatted RFC7231 date, eg
+        *
+        *     Tue, 15 Nov 1994 08:12:31 GMT
+        */
+
+       if (b[3] != ','  || b[4] != ' '  || b[7] != ' '  || b[11] != ' ' ||
+           b[16] != ' ' || b[19] != ':' || b[22] != ':' || b[25] != ' ' ||
+           b[26] != 'G' || b[27] != 'M' || b[28] != 'T')
+               return -1;
+
+       memset(tm, 0, sizeof(*tm));
+
+       for (n = 36; n < 57; n += 3)
+               if (b[0] == s[n] && b[1] == s[n + 1] && b[2] == s[n + 2])
+                       break;
+               else
+                       tm->tm_wday++;
+
+       if (n == 57)
+               return -1;
+
+       for (n = 0; n < 36; n += 3)
+               if (b[8] == s[n] && b[9] == s[n + 1] && b[10] == s[n + 2])
+                       break;
+               else
+                       tm->tm_mon++;
+
+       if (n == 36)
+               return -1;
+
+       tm->tm_mday = atoi(b + 5);
+       n = atoi(b + 12);
+       if (n < 1900)
+               return -1;
+       tm->tm_year = n - 1900;
+
+       n = atoi(b + 17);
+       if (n < 0 || n > 23)
+               return -1;
+       tm->tm_hour = n;
+
+       n = atoi(b + 20);
+       if (n < 0 || n > 60)
+               return -1;
+       tm->tm_min = n;
+
+       n = atoi(b + 23);
+       if (n < 0 || n > 61) /* leap second */
+               return -1;
+       tm->tm_sec = n;
+
+       return 0;
+}
+
+int
+lws_http_date_parse_unix(const char *b, size_t len, time_t *t)
+{
+       struct tm tm;
+
+       if (lws_http_date_parse(b, len, &tm))
+               return -1;
+
+#if defined(WIN32)
+       *t = _mkgmtime(&tm);
+#else
+#if defined(LWS_HAVE_TIMEGM)
+       *t = timegm(&tm);
+#else
+       /* this is a poor fallback since it uses localtime zone */
+       *t = mktime(&tm);
+#endif
+#endif
+
+       return (int)*t == -1 ? -1 : 0;
+}
+
+#if defined(LWS_WITH_CLIENT)
+
+int
+lws_http_check_retry_after(struct lws *wsi, lws_usec_t *us_interval_in_out)
+{
+       size_t len = (unsigned int)lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_RETRY_AFTER);
+       char *p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_RETRY_AFTER);
+       lws_usec_t u;
+       time_t t, td;
+
+       if (!p)
+               return 1;
+
+       /*
+        * There are two arg styles for RETRY_AFTER specified in RFC7231 7.1.3,
+        * either a full absolute second-resolution date/time, or an integer
+        * interval
+        *
+        *      Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
+         *      Retry-After: 120
+        */
+
+       if (len < 9)
+               u = ((lws_usec_t)(time_t)atoi(p)) * LWS_USEC_PER_SEC;
+       else {
+
+               if (lws_http_date_parse_unix(p, len, &t))
+                       return 1;
+
+               /*
+                * If possible, look for DATE from the server as well, so we
+                * can calculate the interval it thinks it is giving us,
+                * eliminating problems from server - client clock skew
+                */
+
+               time(&td);
+               len = (unsigned int)lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_DATE);
+               if (len) {
+                       p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_DATE);
+                       /* if this fails, it leaves td as client time */
+                       (void)lws_http_date_parse_unix(p, len, &td);
+               }
+
+               if (td >= t)
+                       /*
+                        * if he's effectively giving us a 0 or negative
+                        * interval, just ignore the whole thing and keep the
+                        * incoming interval
+                        */
+                       return 1;
+
+               u = ((lws_usec_t)(t - td)) * LWS_USEC_PER_SEC;
+       }
+
+       /*
+        * We are only willing to increase the incoming interval, not
+        * decrease it
+        */
+
+       if (u < *us_interval_in_out)
+               /* keep the incoming interval */
+               return 1;
+
+       /* use the computed interval */
+       *us_interval_in_out = u;
+
+       return 0;
+}
+
+#endif
index d161d78..b0d5477 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 #include "lextable-strings.h"
 
 
@@ -32,13 +35,43 @@ lws_token_to_string(enum lws_token_indexes token)
        return (unsigned char *)set[token];
 }
 
+/*
+ * Return http header index if one matches slen chars of s, or -1
+ */
+
+int
+lws_http_string_to_known_header(const char *s, size_t slen)
+{
+       int n;
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(set); n++)
+               if (!strncmp(set[n], s, slen))
+                       return n;
+
+       return LWS_HTTP_NO_KNOWN_HEADER;
+}
+
+#ifdef LWS_WITH_HTTP2
+int
+lws_wsi_is_h2(struct lws *wsi)
+{
+       return wsi->upgraded_to_http2 ||
+              wsi->mux_substream ||
+#if defined(LWS_WITH_CLIENT)
+              wsi->client_mux_substream ||
+#endif
+              lwsi_role_h2(wsi) ||
+              lwsi_role_h2_ENCAPSULATION(wsi);
+}
+#endif
+
 int
 lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name,
                            const unsigned char *value, int length,
                            unsigned char **p, unsigned char *end)
 {
 #ifdef LWS_WITH_HTTP2
-       if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi))
+       if (lws_wsi_is_h2(wsi))
                return lws_add_http2_header_by_name(wsi, name,
                                                    value, length, p, end);
 #else
@@ -54,7 +87,8 @@ lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name,
        if (*p + length + 3 >= end)
                return 1;
 
-       memcpy(*p, value, length);
+       if (value)
+               memcpy(*p, value, (unsigned int)length);
        *p += length;
        *((*p)++) = '\x0d';
        *((*p)++) = '\x0a';
@@ -66,7 +100,7 @@ int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
                             unsigned char *end)
 {
 #ifdef LWS_WITH_HTTP2
-       if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi))
+       if (lws_wsi_is_h2(wsi))
                return 0;
 #else
        (void)wsi;
@@ -92,7 +126,7 @@ lws_finalize_write_http_header(struct lws *wsi, unsigned char *start,
        p = *pp;
        len = lws_ptr_diff(p, start);
 
-       if (lws_write(wsi, start, len, LWS_WRITE_HTTP_HEADERS) != len)
+       if (lws_write(wsi, start, (unsigned int)len, LWS_WRITE_HTTP_HEADERS) != len)
                return 1;
 
        return 0;
@@ -105,7 +139,7 @@ lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
 {
        const unsigned char *name;
 #ifdef LWS_WITH_HTTP2
-       if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi))
+       if (lws_wsi_is_h2(wsi))
                return lws_add_http2_header_by_token(wsi, token, value,
                                                     length, p, end);
 #endif
@@ -131,12 +165,14 @@ lws_add_http_header_content_length(struct lws *wsi,
        wsi->http.tx_content_length = content_length;
        wsi->http.tx_content_remain = content_length;
 
-       lwsl_info("%s: wsi %p: tx_content_length/remain %llu\n", __func__,
-                       wsi, (unsigned long long)content_length);
+       lwsl_info("%s: %s: tx_content_length/remain %llu\n", __func__,
+                 lws_wsi_tag(wsi), (unsigned long long)content_length);
 
        return 0;
 }
 
+#if defined(LWS_WITH_SERVER)
+
 int
 lws_add_http_common_headers(struct lws *wsi, unsigned int code,
                            const char *content_type, lws_filepos_t content_len,
@@ -149,13 +185,14 @@ lws_add_http_common_headers(struct lws *wsi, unsigned int code,
        if (lws_add_http_header_status(wsi, code, p, end))
                return 1;
 
-       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
+       if (content_type &&
+           lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
                                        (unsigned char *)content_type,
                                        (int)strlen(content_type), p, end))
                return 1;
 
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
-       if (!wsi->http.lcs &&
+       if (!wsi->http.lcs && content_type &&
            (!strncmp(content_type, "text/", 5) ||
             !strcmp(content_type, "application/javascript") ||
             !strcmp(content_type, "image/svg+xml")))
@@ -178,7 +215,7 @@ lws_add_http_common_headers(struct lws *wsi, unsigned int code,
                /* there was no length... it normally means CONNECTION_CLOSE */
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
 
-               if (!wsi->http2_substream && wsi->http.lcs) {
+               if (!wsi->mux_substream && wsi->http.lcs) {
                        /* so...
                         *  - h1 connection
                         *  - http compression transform active
@@ -200,14 +237,14 @@ lws_add_http_common_headers(struct lws *wsi, unsigned int code,
                                t = 1;
                }
 #endif
-               if (!wsi->http2_substream) {
+               if (!wsi->mux_substream) {
                        if (lws_add_http_header_by_token(wsi,
                                                 WSI_TOKEN_CONNECTION,
                                                 (unsigned char *)ka[t],
                                                 (int)strlen(ka[t]), p, end))
                                return 1;
 
-                       wsi->http.conn_type = types[t];
+                       wsi->http.conn_type = (enum http_conn_type)types[t];
                }
        }
 
@@ -259,7 +296,7 @@ struct lws_protocol_vhost_options pvo_hsbph[] = {{
        &pvo_hsbph[3], NULL, "content-security-policy:",
        "default-src 'none'; img-src 'self' data: ; "
                "script-src 'self'; font-src 'self'; "
-               "style-src 'self'; connect-src 'self'; "
+               "style-src 'self'; connect-src 'self' ws: wss:; "
                "frame-ancestors 'none'; base-uri 'none';"
                "form-action 'self';"
 }};
@@ -277,12 +314,13 @@ lws_add_http_header_status(struct lws *wsi, unsigned int _code,
        unsigned char code_and_desc[60];
        int n;
 
+       wsi->http.response_code = code;
 #ifdef LWS_WITH_ACCESS_LOG
-       wsi->http.access_log.response = code;
+       wsi->http.access_log.response = (int)code;
 #endif
 
 #ifdef LWS_WITH_HTTP2
-       if (lwsi_role_h2(wsi) || lwsi_role_h2_ENCAPSULATION(wsi)) {
+       if (lws_wsi_is_h2(wsi)) {
                n = lws_add_http2_header_status(wsi, code, p, end);
                if (n)
                        return n;
@@ -309,15 +347,16 @@ lws_add_http_header_status(struct lws *wsi, unsigned int _code,
                else
                        p1 = hver[0];
 
-               n = lws_snprintf((char *)code_and_desc, sizeof(code_and_desc) - 1, "%s %u %s", p1, code,
-                           description);
+               n = lws_snprintf((char *)code_and_desc,
+                                sizeof(code_and_desc) - 1, "%s %u %s",
+                                p1, code, description);
 
                if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p,
                                                end))
                        return 1;
        }
 
-       headers = wsi->vhost->headers;
+       headers = wsi->a.vhost->headers;
        while (headers) {
                if (lws_add_http_header_by_name(wsi,
                                (const unsigned char *)headers->name,
@@ -328,7 +367,7 @@ lws_add_http_header_status(struct lws *wsi, unsigned int _code,
                headers = headers->next;
        }
 
-       if (wsi->vhost->options &
+       if (wsi->a.vhost->options &
            LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE) {
                headers = &pvo_hsbph[LWS_ARRAY_SIZE(pvo_hsbph) - 1];
                while (headers) {
@@ -342,14 +381,16 @@ lws_add_http_header_status(struct lws *wsi, unsigned int _code,
                }
        }
 
-       if (wsi->context->server_string &&
-           !(_code & LWSAHH_FLAG_NO_SERVER_NAME))
+       if (wsi->a.context->server_string &&
+           !(_code & LWSAHH_FLAG_NO_SERVER_NAME)) {
+               assert(wsi->a.context->server_string_len > 0);
                if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
-                               (unsigned char *)wsi->context->server_string,
-                               wsi->context->server_string_len, p, end))
+                               (unsigned char *)wsi->a.context->server_string,
+                               wsi->a.context->server_string_len, p, end))
                        return 1;
+       }
 
-       if (wsi->vhost->options & LWS_SERVER_OPTION_STS)
+       if (wsi->a.vhost->options & LWS_SERVER_OPTION_STS)
                if (lws_add_http_header_by_name(wsi, (unsigned char *)
                                "Strict-Transport-Security:",
                                (unsigned char *)"max-age=15768000 ; "
@@ -365,7 +406,7 @@ lws_add_http_header_status(struct lws *wsi, unsigned int _code,
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_return_http_status(struct lws *wsi, unsigned int code,
                       const char *html_body)
 {
@@ -378,19 +419,19 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
        int n = 0, m = 0, len;
        char slen[20];
 
-       if (!wsi->vhost) {
+       if (!wsi->a.vhost) {
                lwsl_err("%s: wsi not bound to vhost\n", __func__);
 
                return 1;
        }
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
        if (!wsi->handling_404 &&
-           wsi->vhost->http.error_document_404 &&
+           wsi->a.vhost->http.error_document_404 &&
            code == HTTP_STATUS_NOT_FOUND)
                /* we should do a redirect, and do the 404 there */
                if (lws_http_redirect(wsi, HTTP_STATUS_FOUND,
-                              (uint8_t *)wsi->vhost->http.error_document_404,
-                              (int)strlen(wsi->vhost->http.error_document_404),
+                              (uint8_t *)wsi->a.vhost->http.error_document_404,
+                              (int)strlen(wsi->a.vhost->http.error_document_404),
                               &p, end) > 0)
                        return 0;
 #endif
@@ -426,7 +467,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
                return 1;
 
 #if defined(LWS_WITH_HTTP2)
-       if (wsi->http2_substream) {
+       if (wsi->mux_substream) {
 
                /*
                 * for HTTP/2, the headers must be sent separately, since they
@@ -440,7 +481,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
                 *
                 * Solve it by writing the headers now...
                 */
-               m = lws_write(wsi, start, lws_ptr_diff(p, start),
+               m = lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
                              LWS_WRITE_HTTP_HEADERS);
                if (m != lws_ptr_diff(p, start))
                        return 1;
@@ -449,10 +490,10 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
                 * ... but stash the body and send it as a priority next
                 * handle_POLLOUT
                 */
-               wsi->http.tx_content_length = len;
-               wsi->http.tx_content_remain = len;
+               wsi->http.tx_content_length = (unsigned int)len;
+               wsi->http.tx_content_remain = (unsigned int)len;
 
-               wsi->h2.pending_status_body = lws_malloc(len + LWS_PRE + 1,
+               wsi->h2.pending_status_body = lws_malloc((unsigned int)len + LWS_PRE + 1,
                                                        "pending status body");
                if (!wsi->h2.pending_status_body)
                        return -1;
@@ -470,8 +511,8 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
                 */
 
                n = lws_ptr_diff(p, start) + len;
-               memcpy(p, body, len);
-               m = lws_write(wsi, start, n, LWS_WRITE_HTTP);
+               memcpy(p, body, (unsigned int)len);
+               m = lws_write(wsi, start, (unsigned int)n, LWS_WRITE_HTTP);
                if (m != n)
                        return 1;
        }
@@ -479,13 +520,13 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
        return m != n;
 }
 
-LWS_VISIBLE int
+int
 lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
                  unsigned char **p, unsigned char *end)
 {
        unsigned char *start = *p;
 
-       if (lws_add_http_header_status(wsi, code, p, end))
+       if (lws_add_http_header_status(wsi, (unsigned int)code, p, end))
                return -1;
 
        if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION, loc, len,
@@ -507,12 +548,13 @@ lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
        if (lws_finalize_http_header(wsi, p, end))
                return -1;
 
-       return lws_write(wsi, start, *p - start, LWS_WRITE_HTTP_HEADERS |
-                                                LWS_WRITE_H2_STREAM_END);
+       return lws_write(wsi, start, lws_ptr_diff_size_t(*p, start),
+                        LWS_WRITE_HTTP_HEADERS | LWS_WRITE_H2_STREAM_END);
 }
+#endif
 
 #if !defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
-LWS_VISIBLE int
+int
 lws_http_compression_apply(struct lws *wsi, const char *name,
                           unsigned char **p, unsigned char *end, char decomp)
 {
@@ -532,6 +574,8 @@ lws_http_headers_detach(struct lws *wsi)
        return lws_header_table_detach(wsi, 0);
 }
 
+#if defined(LWS_WITH_SERVER)
+
 void
 lws_sul_http_ah_lifecheck(lws_sorted_usec_list_t *sul)
 {
@@ -553,9 +597,9 @@ lws_sul_http_ah_lifecheck(lws_sorted_usec_list_t *sul)
                const unsigned char *c;
 
                if (!ah->in_use || !ah->wsi || !ah->assigned ||
-                   (ah->wsi->vhost &&
+                   (ah->wsi->a.vhost &&
                     (now - ah->assigned) <
-                    ah->wsi->vhost->timeout_secs_ah_idle + 360)) {
+                    ah->wsi->a.vhost->timeout_secs_ah_idle + 360)) {
                        ah = ah->next;
                        continue;
                }
@@ -573,26 +617,26 @@ lws_sul_http_ah_lifecheck(lws_sorted_usec_list_t *sul)
 #else
                buf[0] = '\0';
 #endif
-               lwsl_notice("ah excessive hold: wsi %p\n"
+               lwsl_notice("%s: ah excessive hold: wsi %p\n"
                            "  peer address: %s\n"
-                           "  ah pos %lu\n",
-                           wsi, buf, (unsigned long)ah->pos);
+                           "  ah pos %lu\n", __func__, lws_wsi_tag(wsi),
+                           buf, (unsigned long)ah->pos);
                buf[0] = '\0';
                m = 0;
                do {
-                       c = lws_token_to_string(m);
+                       c = lws_token_to_string((enum lws_token_indexes)m);
                        if (!c)
                                break;
                        if (!(*c))
                                break;
 
-                       len = lws_hdr_total_length(wsi, m);
+                       len = lws_hdr_total_length(wsi, (enum lws_token_indexes)m);
                        if (!len || len > (int)sizeof(buf) - 1) {
                                m++;
                                continue;
                        }
 
-                       if (lws_hdr_copy(wsi, buf, sizeof buf, m) > 0) {
+                       if (lws_hdr_copy(wsi, buf, sizeof buf, (enum lws_token_indexes)m) > 0) {
                                buf[sizeof(buf) - 1] = '\0';
 
                                lwsl_notice("   %s = %s\n",
@@ -614,3 +658,4 @@ lws_sul_http_ah_lifecheck(lws_sorted_usec_list_t *sul)
 
        lws_pt_unlock(pt);
 }
+#endif
index 02d05eb..b8d6865 100644 (file)
@@ -3,14 +3,19 @@
 static const char * const set[] = {
        "get ",
        "post ",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
        "options ",
+#endif
        "host:",
        "connection:",
        "upgrade:",
        "origin:",
+#if defined(LWS_ROLE_WS) || defined(LWS_HTTP_HEADERS_ALL)
        "sec-websocket-draft:",
+#endif
        "\x0d\x0a",
 
+#if defined(LWS_ROLE_WS) || defined(LWS_HTTP_HEADERS_ALL)
        "sec-websocket-extensions:",
        "sec-websocket-key1:",
        "sec-websocket-key2:",
@@ -18,11 +23,16 @@ static const char * const set[] = {
 
        "sec-websocket-accept:",
        "sec-websocket-nonce:",
+#endif
        "http/1.1 ",
+#if defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        "http2-settings:",
+#endif
 
        "accept:",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
        "access-control-request-headers:",
+#endif
        "if-modified-since:",
        "if-none-match:",
        "accept-encoding:",
@@ -35,20 +45,28 @@ static const char * const set[] = {
        "content-type:",
        "date:",
        "range:",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        "referer:",
+#endif
+#if defined(LWS_ROLE_WS) || defined(LWS_HTTP_HEADERS_ALL)
        "sec-websocket-key:",
        "sec-websocket-version:",
        "sec-websocket-origin:",
-
+#endif
+#if defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        ":authority",
        ":method",
        ":path",
        ":scheme",
        ":status",
-
+#endif
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        "accept-charset:",
+#endif
        "accept-ranges:",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        "access-control-allow-origin:",
+#endif
        "age:",
        "allow:",
        "content-disposition:",
@@ -66,38 +84,52 @@ static const char * const set[] = {
        "last-modified:",
        "link:",
        "location:",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        "max-forwards:",
        "proxy-authenticate:",
        "proxy-authorization:",
+#endif
        "refresh:",
        "retry-after:",
        "server:",
        "set-cookie:",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        "strict-transport-security:",
+#endif
        "transfer-encoding:",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        "user-agent:",
        "vary:",
        "via:",
        "www-authenticate:",
-
+#endif
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
        "patch",
        "put",
        "delete",
+#endif
 
        "uri-args", /* fake header used for uri-only storage */
 
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
        "proxy ",
        "x-real-ip:",
+#endif
        "http/1.0 ",
 
        "x-forwarded-for:",
        "connect ",
        "head ",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        "te:",          /* http/2 wants it to reject it */
        "replay-nonce:", /* ACME */
+#endif
+#if defined(LWS_ROLE_H2) || defined(LWS_HTTP_HEADERS_ALL)
        ":protocol",            /* defined in mcmanus-httpbis-h2-ws-02 */
+#endif
 
        "x-auth-token:",
+       "x-amzn-dss-signature:",
 
        "", /* not matchable */
 
index 0bb05c2..e6ded39 100644 (file)
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+       /* 0: 0: get  */
+       /* 1: 1: post  */
+       /* 2: 3: host: */
+       /* 3: 4: connection: */
+       /* 4: 5: upgrade: */
+       /* 5: 6: origin: */
+       /* 6: 8: \r
+ */
+       /* 7: 15: http/1.1  */
+       /* 8: 17: accept: */
+       /* 9: 19: if-modified-since: */
+       /* 10: 20: if-none-match: */
+       /* 11: 21: accept-encoding: */
+       /* 12: 22: accept-language: */
+       /* 13: 23: pragma: */
+       /* 14: 24: cache-control: */
+       /* 15: 25: authorization: */
+       /* 16: 26: cookie: */
+       /* 17: 27: content-length: */
+       /* 18: 28: content-type: */
+       /* 19: 29: date: */
+       /* 20: 30: range: */
+       /* 21: 41: accept-ranges: */
+       /* 22: 43: age: */
+       /* 23: 44: allow: */
+       /* 24: 45: content-disposition: */
+       /* 25: 46: content-encoding: */
+       /* 26: 47: content-language: */
+       /* 27: 48: content-location: */
+       /* 28: 49: content-range: */
+       /* 29: 50: etag: */
+       /* 30: 51: expect: */
+       /* 31: 52: expires: */
+       /* 32: 53: from: */
+       /* 33: 54: if-match: */
+       /* 34: 55: if-range: */
+       /* 35: 56: if-unmodified-since: */
+       /* 36: 57: last-modified: */
+       /* 37: 58: link: */
+       /* 38: 59: location: */
+       /* 39: 63: refresh: */
+       /* 40: 64: retry-after: */
+       /* 41: 65: server: */
+       /* 42: 66: set-cookie: */
+       /* 43: 68: transfer-encoding: */
+       /* 44: 76: uri-args */
+       /* 45: 79: http/1.0  */
+       /* 46: 80: x-forwarded-for: */
+       /* 47: 81: connect  */
+       /* 48: 82: head  */
+       /* 49: 86: x-auth-token: */
+       /* 50: 87: x-amzn-dss-signature: */
+       /* 51: 88:  */
+/* pos 0000:   0 */    0x67 /* 'g' */, 0x34, 0x00  /* (to 0x0034 state   1) */,
+                       0x70 /* 'p' */, 0x36, 0x00  /* (to 0x0039 state   5) */,
+                       0x68 /* 'h' */, 0x3F, 0x00  /* (to 0x0045 state  10) */,
+                       0x63 /* 'c' */, 0x4B, 0x00  /* (to 0x0054 state  15) */,
+                       0x75 /* 'u' */, 0x6C, 0x00  /* (to 0x0078 state  26) */,
+                       0x6F /* 'o' */, 0x78, 0x00  /* (to 0x0087 state  34) */,
+                       0x0D /* '.' */, 0x7D, 0x00  /* (to 0x008F state  41) */,
+                       0x61 /* 'a' */, 0x8C, 0x00  /* (to 0x00A1 state  51) */,
+                       0x69 /* 'i' */, 0xA3, 0x00  /* (to 0x00BB state  58) */,
+                       0x64 /* 'd' */, 0x43, 0x01  /* (to 0x015E state 160) */,
+                       0x72 /* 'r' */, 0x46, 0x01  /* (to 0x0164 state 165) */,
+                       0x65 /* 'e' */, 0x92, 0x01  /* (to 0x01B3 state 229) */,
+                       0x66 /* 'f' */, 0xAE, 0x01  /* (to 0x01D2 state 245) */,
+                       0x6C /* 'l' */, 0xD0, 0x01  /* (to 0x01F7 state 278) */,
+                       0x73 /* 's' */, 0x0C, 0x02  /* (to 0x0236 state 321) */,
+                       0x74 /* 't' */, 0x21, 0x02  /* (to 0x024E state 337) */,
+                       0x78 /* 'x' */, 0x3C, 0x02  /* (to 0x026C state 364) */,
+                       0x08, /* fail */
+/* pos 0034:   1 */    0xE5 /* 'e' -> */,
+/* pos 0035:   2 */    0xF4 /* 't' -> */,
+/* pos 0036:   3 */    0xA0 /* ' ' -> */,
+/* pos 0037:   4 */    0x00, 0x00                  /* - terminal marker  0 - */,
+/* pos 0039:   5 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x0040 state   6) */,
+                       0x72 /* 'r' */, 0xCE, 0x00  /* (to 0x010A state 106) */,
+                       0x08, /* fail */
+/* pos 0040:   6 */    0xF3 /* 's' -> */,
+/* pos 0041:   7 */    0xF4 /* 't' -> */,
+/* pos 0042:   8 */    0xA0 /* ' ' -> */,
+/* pos 0043:   9 */    0x00, 0x01                  /* - terminal marker  1 - */,
+/* pos 0045:  10 */    0x6F /* 'o' */, 0x0A, 0x00  /* (to 0x004F state  11) */,
+                       0x74 /* 't' */, 0x4A, 0x00  /* (to 0x0092 state  43) */,
+                       0x65 /* 'e' */, 0x3A, 0x02  /* (to 0x0285 state 381) */,
+                       0x08, /* fail */
+/* pos 004f:  11 */    0xF3 /* 's' -> */,
+/* pos 0050:  12 */    0xF4 /* 't' -> */,
+/* pos 0051:  13 */    0xBA /* ':' -> */,
+/* pos 0052:  14 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 0054:  15 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x005B state  16) */,
+                       0x61 /* 'a' */, 0xBA, 0x00  /* (to 0x0111 state 112) */,
+                       0x08, /* fail */
+/* pos 005b:  16 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0062 state  17) */,
+                       0x6F /* 'o' */, 0xCF, 0x00  /* (to 0x012D state 138) */,
+                       0x08, /* fail */
+/* pos 0062:  17 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0069 state  18) */,
+                       0x74 /* 't' */, 0xCE, 0x00  /* (to 0x0133 state 143) */,
+                       0x08, /* fail */
+/* pos 0069:  18 */    0xE5 /* 'e' -> */,
+/* pos 006a:  19 */    0xE3 /* 'c' -> */,
+/* pos 006b:  20 */    0xF4 /* 't' -> */,
+/* pos 006c:  21 */    0x69 /* 'i' */, 0x07, 0x00  /* (to 0x0073 state  22) */,
+                       0x20 /* ' ' */, 0x14, 0x02  /* (to 0x0283 state 380) */,
+                       0x08, /* fail */
+/* pos 0073:  22 */    0xEF /* 'o' -> */,
+/* pos 0074:  23 */    0xEE /* 'n' -> */,
+/* pos 0075:  24 */    0xBA /* ':' -> */,
+/* pos 0076:  25 */    0x00, 0x03                  /* - terminal marker  3 - */,
+/* pos 0078:  26 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x007F state  27) */,
+                       0x72 /* 'r' */, 0xE6, 0x01  /* (to 0x0261 state 355) */,
+                       0x08, /* fail */
+/* pos 007f:  27 */    0xE7 /* 'g' -> */,
+/* pos 0080:  28 */    0xF2 /* 'r' -> */,
+/* pos 0081:  29 */    0xE1 /* 'a' -> */,
+/* pos 0082:  30 */    0xE4 /* 'd' -> */,
+/* pos 0083:  31 */    0xE5 /* 'e' -> */,
+/* pos 0084:  32 */    0xBA /* ':' -> */,
+/* pos 0085:  33 */    0x00, 0x04                  /* - terminal marker  4 - */,
+/* pos 0087:  34 */    0xF2 /* 'r' -> */,
+/* pos 0088:  35 */    0xE9 /* 'i' -> */,
+/* pos 0089:  36 */    0xE7 /* 'g' -> */,
+/* pos 008a:  37 */    0xE9 /* 'i' -> */,
+/* pos 008b:  38 */    0xEE /* 'n' -> */,
+/* pos 008c:  39 */    0xBA /* ':' -> */,
+/* pos 008d:  40 */    0x00, 0x05                  /* - terminal marker  5 - */,
+/* pos 008f:  41 */    0x8A /* '.' -> */,
+/* pos 0090:  42 */    0x00, 0x06                  /* - terminal marker  6 - */,
+/* pos 0092:  43 */    0xF4 /* 't' -> */,
+/* pos 0093:  44 */    0xF0 /* 'p' -> */,
+/* pos 0094:  45 */    0xAF /* '/' -> */,
+/* pos 0095:  46 */    0xB1 /* '1' -> */,
+/* pos 0096:  47 */    0xAE /* '.' -> */,
+/* pos 0097:  48 */    0x31 /* '1' */, 0x07, 0x00  /* (to 0x009E state  49) */,
+                       0x30 /* '0' */, 0xCF, 0x01  /* (to 0x0269 state 362) */,
+                       0x08, /* fail */
+/* pos 009e:  49 */    0xA0 /* ' ' -> */,
+/* pos 009f:  50 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 00a1:  51 */    0x63 /* 'c' */, 0x0D, 0x00  /* (to 0x00AE state  52) */,
+                       0x75 /* 'u' */, 0x7B, 0x00  /* (to 0x011F state 125) */,
+                       0x67 /* 'g' */, 0xD2, 0x00  /* (to 0x0179 state 178) */,
+                       0x6C /* 'l' */, 0xD3, 0x00  /* (to 0x017D state 181) */,
+                       0x08, /* fail */
+/* pos 00ae:  52 */    0xE3 /* 'c' -> */,
+/* pos 00af:  53 */    0xE5 /* 'e' -> */,
+/* pos 00b0:  54 */    0xF0 /* 'p' -> */,
+/* pos 00b1:  55 */    0xF4 /* 't' -> */,
+/* pos 00b2:  56 */    0x3A /* ':' */, 0x07, 0x00  /* (to 0x00B9 state  57) */,
+                       0x2D /* '-' */, 0x37, 0x00  /* (to 0x00EC state  87) */,
+                       0x08, /* fail */
+/* pos 00b9:  57 */    0x00, 0x08                  /* - terminal marker  8 - */,
+/* pos 00bb:  58 */    0xE6 /* 'f' -> */,
+/* pos 00bc:  59 */    0xAD /* '-' -> */,
+/* pos 00bd:  60 */    0x6D /* 'm' */, 0x0D, 0x00  /* (to 0x00CA state  61) */,
+                       0x6E /* 'n' */, 0x20, 0x00  /* (to 0x00E0 state  76) */,
+                       0x72 /* 'r' */, 0x1B, 0x01  /* (to 0x01DE state 255) */,
+                       0x75 /* 'u' */, 0x1F, 0x01  /* (to 0x01E5 state 261) */,
+                       0x08, /* fail */
+/* pos 00ca:  61 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x00D1 state  62) */,
+                       0x61 /* 'a' */, 0x0B, 0x01  /* (to 0x01D8 state 250) */,
+                       0x08, /* fail */
+/* pos 00d1:  62 */    0xE4 /* 'd' -> */,
+/* pos 00d2:  63 */    0xE9 /* 'i' -> */,
+/* pos 00d3:  64 */    0xE6 /* 'f' -> */,
+/* pos 00d4:  65 */    0xE9 /* 'i' -> */,
+/* pos 00d5:  66 */    0xE5 /* 'e' -> */,
+/* pos 00d6:  67 */    0xE4 /* 'd' -> */,
+/* pos 00d7:  68 */    0xAD /* '-' -> */,
+/* pos 00d8:  69 */    0xF3 /* 's' -> */,
+/* pos 00d9:  70 */    0xE9 /* 'i' -> */,
+/* pos 00da:  71 */    0xEE /* 'n' -> */,
+/* pos 00db:  72 */    0xE3 /* 'c' -> */,
+/* pos 00dc:  73 */    0xE5 /* 'e' -> */,
+/* pos 00dd:  74 */    0xBA /* ':' -> */,
+/* pos 00de:  75 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 00e0:  76 */    0xEF /* 'o' -> */,
+/* pos 00e1:  77 */    0xEE /* 'n' -> */,
+/* pos 00e2:  78 */    0xE5 /* 'e' -> */,
+/* pos 00e3:  79 */    0xAD /* '-' -> */,
+/* pos 00e4:  80 */    0xED /* 'm' -> */,
+/* pos 00e5:  81 */    0xE1 /* 'a' -> */,
+/* pos 00e6:  82 */    0xF4 /* 't' -> */,
+/* pos 00e7:  83 */    0xE3 /* 'c' -> */,
+/* pos 00e8:  84 */    0xE8 /* 'h' -> */,
+/* pos 00e9:  85 */    0xBA /* ':' -> */,
+/* pos 00ea:  86 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 00ec:  87 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x00F6 state  88) */,
+                       0x6C /* 'l' */, 0x11, 0x00  /* (to 0x0100 state  97) */,
+                       0x72 /* 'r' */, 0x7F, 0x00  /* (to 0x0171 state 171) */,
+                       0x08, /* fail */
+/* pos 00f6:  88 */    0xEE /* 'n' -> */,
+/* pos 00f7:  89 */    0xE3 /* 'c' -> */,
+/* pos 00f8:  90 */    0xEF /* 'o' -> */,
+/* pos 00f9:  91 */    0xE4 /* 'd' -> */,
+/* pos 00fa:  92 */    0xE9 /* 'i' -> */,
+/* pos 00fb:  93 */    0xEE /* 'n' -> */,
+/* pos 00fc:  94 */    0xE7 /* 'g' -> */,
+/* pos 00fd:  95 */    0xBA /* ':' -> */,
+/* pos 00fe:  96 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 0100:  97 */    0xE1 /* 'a' -> */,
+/* pos 0101:  98 */    0xEE /* 'n' -> */,
+/* pos 0102:  99 */    0xE7 /* 'g' -> */,
+/* pos 0103: 100 */    0xF5 /* 'u' -> */,
+/* pos 0104: 101 */    0xE1 /* 'a' -> */,
+/* pos 0105: 102 */    0xE7 /* 'g' -> */,
+/* pos 0106: 103 */    0xE5 /* 'e' -> */,
+/* pos 0107: 104 */    0xBA /* ':' -> */,
+/* pos 0108: 105 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 010a: 106 */    0xE1 /* 'a' -> */,
+/* pos 010b: 107 */    0xE7 /* 'g' -> */,
+/* pos 010c: 108 */    0xED /* 'm' -> */,
+/* pos 010d: 109 */    0xE1 /* 'a' -> */,
+/* pos 010e: 110 */    0xBA /* ':' -> */,
+/* pos 010f: 111 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 0111: 112 */    0xE3 /* 'c' -> */,
+/* pos 0112: 113 */    0xE8 /* 'h' -> */,
+/* pos 0113: 114 */    0xE5 /* 'e' -> */,
+/* pos 0114: 115 */    0xAD /* '-' -> */,
+/* pos 0115: 116 */    0xE3 /* 'c' -> */,
+/* pos 0116: 117 */    0xEF /* 'o' -> */,
+/* pos 0117: 118 */    0xEE /* 'n' -> */,
+/* pos 0118: 119 */    0xF4 /* 't' -> */,
+/* pos 0119: 120 */    0xF2 /* 'r' -> */,
+/* pos 011a: 121 */    0xEF /* 'o' -> */,
+/* pos 011b: 122 */    0xEC /* 'l' -> */,
+/* pos 011c: 123 */    0xBA /* ':' -> */,
+/* pos 011d: 124 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 011f: 125 */    0xF4 /* 't' -> */,
+/* pos 0120: 126 */    0xE8 /* 'h' -> */,
+/* pos 0121: 127 */    0xEF /* 'o' -> */,
+/* pos 0122: 128 */    0xF2 /* 'r' -> */,
+/* pos 0123: 129 */    0xE9 /* 'i' -> */,
+/* pos 0124: 130 */    0xFA /* 'z' -> */,
+/* pos 0125: 131 */    0xE1 /* 'a' -> */,
+/* pos 0126: 132 */    0xF4 /* 't' -> */,
+/* pos 0127: 133 */    0xE9 /* 'i' -> */,
+/* pos 0128: 134 */    0xEF /* 'o' -> */,
+/* pos 0129: 135 */    0xEE /* 'n' -> */,
+/* pos 012a: 136 */    0xBA /* ':' -> */,
+/* pos 012b: 137 */    0x00, 0x0F                  /* - terminal marker 15 - */,
+/* pos 012d: 138 */    0xEB /* 'k' -> */,
+/* pos 012e: 139 */    0xE9 /* 'i' -> */,
+/* pos 012f: 140 */    0xE5 /* 'e' -> */,
+/* pos 0130: 141 */    0xBA /* ':' -> */,
+/* pos 0131: 142 */    0x00, 0x10                  /* - terminal marker 16 - */,
+/* pos 0133: 143 */    0xE5 /* 'e' -> */,
+/* pos 0134: 144 */    0xEE /* 'n' -> */,
+/* pos 0135: 145 */    0xF4 /* 't' -> */,
+/* pos 0136: 146 */    0xAD /* '-' -> */,
+/* pos 0137: 147 */    0x6C /* 'l' */, 0x10, 0x00  /* (to 0x0147 state 148) */,
+                       0x74 /* 't' */, 0x1E, 0x00  /* (to 0x0158 state 155) */,
+                       0x64 /* 'd' */, 0x46, 0x00  /* (to 0x0183 state 186) */,
+                       0x65 /* 'e' */, 0x50, 0x00  /* (to 0x0190 state 198) */,
+                       0x72 /* 'r' */, 0x69, 0x00  /* (to 0x01AC state 223) */,
+                       0x08, /* fail */
+/* pos 0147: 148 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x0151 state 149) */,
+                       0x61 /* 'a' */, 0x50, 0x00  /* (to 0x019A state 207) */,
+                       0x6F /* 'o' */, 0x56, 0x00  /* (to 0x01A3 state 215) */,
+                       0x08, /* fail */
+/* pos 0151: 149 */    0xEE /* 'n' -> */,
+/* pos 0152: 150 */    0xE7 /* 'g' -> */,
+/* pos 0153: 151 */    0xF4 /* 't' -> */,
+/* pos 0154: 152 */    0xE8 /* 'h' -> */,
+/* pos 0155: 153 */    0xBA /* ':' -> */,
+/* pos 0156: 154 */    0x00, 0x11                  /* - terminal marker 17 - */,
+/* pos 0158: 155 */    0xF9 /* 'y' -> */,
+/* pos 0159: 156 */    0xF0 /* 'p' -> */,
+/* pos 015a: 157 */    0xE5 /* 'e' -> */,
+/* pos 015b: 158 */    0xBA /* ':' -> */,
+/* pos 015c: 159 */    0x00, 0x12                  /* - terminal marker 18 - */,
+/* pos 015e: 160 */    0xE1 /* 'a' -> */,
+/* pos 015f: 161 */    0xF4 /* 't' -> */,
+/* pos 0160: 162 */    0xE5 /* 'e' -> */,
+/* pos 0161: 163 */    0xBA /* ':' -> */,
+/* pos 0162: 164 */    0x00, 0x13                  /* - terminal marker 19 - */,
+/* pos 0164: 165 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x016B state 166) */,
+                       0x65 /* 'e' */, 0xB6, 0x00  /* (to 0x021D state 304) */,
+                       0x08, /* fail */
+/* pos 016b: 166 */    0xEE /* 'n' -> */,
+/* pos 016c: 167 */    0xE7 /* 'g' -> */,
+/* pos 016d: 168 */    0xE5 /* 'e' -> */,
+/* pos 016e: 169 */    0xBA /* ':' -> */,
+/* pos 016f: 170 */    0x00, 0x14                  /* - terminal marker 20 - */,
+/* pos 0171: 171 */    0xE1 /* 'a' -> */,
+/* pos 0172: 172 */    0xEE /* 'n' -> */,
+/* pos 0173: 173 */    0xE7 /* 'g' -> */,
+/* pos 0174: 174 */    0xE5 /* 'e' -> */,
+/* pos 0175: 175 */    0xF3 /* 's' -> */,
+/* pos 0176: 176 */    0xBA /* ':' -> */,
+/* pos 0177: 177 */    0x00, 0x15                  /* - terminal marker 21 - */,
+/* pos 0179: 178 */    0xE5 /* 'e' -> */,
+/* pos 017a: 179 */    0xBA /* ':' -> */,
+/* pos 017b: 180 */    0x00, 0x16                  /* - terminal marker 22 - */,
+/* pos 017d: 181 */    0xEC /* 'l' -> */,
+/* pos 017e: 182 */    0xEF /* 'o' -> */,
+/* pos 017f: 183 */    0xF7 /* 'w' -> */,
+/* pos 0180: 184 */    0xBA /* ':' -> */,
+/* pos 0181: 185 */    0x00, 0x17                  /* - terminal marker 23 - */,
+/* pos 0183: 186 */    0xE9 /* 'i' -> */,
+/* pos 0184: 187 */    0xF3 /* 's' -> */,
+/* pos 0185: 188 */    0xF0 /* 'p' -> */,
+/* pos 0186: 189 */    0xEF /* 'o' -> */,
+/* pos 0187: 190 */    0xF3 /* 's' -> */,
+/* pos 0188: 191 */    0xE9 /* 'i' -> */,
+/* pos 0189: 192 */    0xF4 /* 't' -> */,
+/* pos 018a: 193 */    0xE9 /* 'i' -> */,
+/* pos 018b: 194 */    0xEF /* 'o' -> */,
+/* pos 018c: 195 */    0xEE /* 'n' -> */,
+/* pos 018d: 196 */    0xBA /* ':' -> */,
+/* pos 018e: 197 */    0x00, 0x18                  /* - terminal marker 24 - */,
+/* pos 0190: 198 */    0xEE /* 'n' -> */,
+/* pos 0191: 199 */    0xE3 /* 'c' -> */,
+/* pos 0192: 200 */    0xEF /* 'o' -> */,
+/* pos 0193: 201 */    0xE4 /* 'd' -> */,
+/* pos 0194: 202 */    0xE9 /* 'i' -> */,
+/* pos 0195: 203 */    0xEE /* 'n' -> */,
+/* pos 0196: 204 */    0xE7 /* 'g' -> */,
+/* pos 0197: 205 */    0xBA /* ':' -> */,
+/* pos 0198: 206 */    0x00, 0x19                  /* - terminal marker 25 - */,
+/* pos 019a: 207 */    0xEE /* 'n' -> */,
+/* pos 019b: 208 */    0xE7 /* 'g' -> */,
+/* pos 019c: 209 */    0xF5 /* 'u' -> */,
+/* pos 019d: 210 */    0xE1 /* 'a' -> */,
+/* pos 019e: 211 */    0xE7 /* 'g' -> */,
+/* pos 019f: 212 */    0xE5 /* 'e' -> */,
+/* pos 01a0: 213 */    0xBA /* ':' -> */,
+/* pos 01a1: 214 */    0x00, 0x1A                  /* - terminal marker 26 - */,
+/* pos 01a3: 215 */    0xE3 /* 'c' -> */,
+/* pos 01a4: 216 */    0xE1 /* 'a' -> */,
+/* pos 01a5: 217 */    0xF4 /* 't' -> */,
+/* pos 01a6: 218 */    0xE9 /* 'i' -> */,
+/* pos 01a7: 219 */    0xEF /* 'o' -> */,
+/* pos 01a8: 220 */    0xEE /* 'n' -> */,
+/* pos 01a9: 221 */    0xBA /* ':' -> */,
+/* pos 01aa: 222 */    0x00, 0x1B                  /* - terminal marker 27 - */,
+/* pos 01ac: 223 */    0xE1 /* 'a' -> */,
+/* pos 01ad: 224 */    0xEE /* 'n' -> */,
+/* pos 01ae: 225 */    0xE7 /* 'g' -> */,
+/* pos 01af: 226 */    0xE5 /* 'e' -> */,
+/* pos 01b0: 227 */    0xBA /* ':' -> */,
+/* pos 01b1: 228 */    0x00, 0x1C                  /* - terminal marker 28 - */,
+/* pos 01b3: 229 */    0x74 /* 't' */, 0x07, 0x00  /* (to 0x01BA state 230) */,
+                       0x78 /* 'x' */, 0x09, 0x00  /* (to 0x01BF state 234) */,
+                       0x08, /* fail */
+/* pos 01ba: 230 */    0xE1 /* 'a' -> */,
+/* pos 01bb: 231 */    0xE7 /* 'g' -> */,
+/* pos 01bc: 232 */    0xBA /* ':' -> */,
+/* pos 01bd: 233 */    0x00, 0x1D                  /* - terminal marker 29 - */,
+/* pos 01bf: 234 */    0xF0 /* 'p' -> */,
+/* pos 01c0: 235 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x01C7 state 236) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x01CC state 240) */,
+                       0x08, /* fail */
+/* pos 01c7: 236 */    0xE3 /* 'c' -> */,
+/* pos 01c8: 237 */    0xF4 /* 't' -> */,
+/* pos 01c9: 238 */    0xBA /* ':' -> */,
+/* pos 01ca: 239 */    0x00, 0x1E                  /* - terminal marker 30 - */,
+/* pos 01cc: 240 */    0xF2 /* 'r' -> */,
+/* pos 01cd: 241 */    0xE5 /* 'e' -> */,
+/* pos 01ce: 242 */    0xF3 /* 's' -> */,
+/* pos 01cf: 243 */    0xBA /* ':' -> */,
+/* pos 01d0: 244 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 01d2: 245 */    0xF2 /* 'r' -> */,
+/* pos 01d3: 246 */    0xEF /* 'o' -> */,
+/* pos 01d4: 247 */    0xED /* 'm' -> */,
+/* pos 01d5: 248 */    0xBA /* ':' -> */,
+/* pos 01d6: 249 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 01d8: 250 */    0xF4 /* 't' -> */,
+/* pos 01d9: 251 */    0xE3 /* 'c' -> */,
+/* pos 01da: 252 */    0xE8 /* 'h' -> */,
+/* pos 01db: 253 */    0xBA /* ':' -> */,
+/* pos 01dc: 254 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* pos 01de: 255 */    0xE1 /* 'a' -> */,
+/* pos 01df: 256 */    0xEE /* 'n' -> */,
+/* pos 01e0: 257 */    0xE7 /* 'g' -> */,
+/* pos 01e1: 258 */    0xE5 /* 'e' -> */,
+/* pos 01e2: 259 */    0xBA /* ':' -> */,
+/* pos 01e3: 260 */    0x00, 0x22                  /* - terminal marker 34 - */,
+/* pos 01e5: 261 */    0xEE /* 'n' -> */,
+/* pos 01e6: 262 */    0xED /* 'm' -> */,
+/* pos 01e7: 263 */    0xEF /* 'o' -> */,
+/* pos 01e8: 264 */    0xE4 /* 'd' -> */,
+/* pos 01e9: 265 */    0xE9 /* 'i' -> */,
+/* pos 01ea: 266 */    0xE6 /* 'f' -> */,
+/* pos 01eb: 267 */    0xE9 /* 'i' -> */,
+/* pos 01ec: 268 */    0xE5 /* 'e' -> */,
+/* pos 01ed: 269 */    0xE4 /* 'd' -> */,
+/* pos 01ee: 270 */    0xAD /* '-' -> */,
+/* pos 01ef: 271 */    0xF3 /* 's' -> */,
+/* pos 01f0: 272 */    0xE9 /* 'i' -> */,
+/* pos 01f1: 273 */    0xEE /* 'n' -> */,
+/* pos 01f2: 274 */    0xE3 /* 'c' -> */,
+/* pos 01f3: 275 */    0xE5 /* 'e' -> */,
+/* pos 01f4: 276 */    0xBA /* ':' -> */,
+/* pos 01f5: 277 */    0x00, 0x23                  /* - terminal marker 35 - */,
+/* pos 01f7: 278 */    0x61 /* 'a' */, 0x0A, 0x00  /* (to 0x0201 state 279) */,
+                       0x69 /* 'i' */, 0x15, 0x00  /* (to 0x020F state 292) */,
+                       0x6F /* 'o' */, 0x17, 0x00  /* (to 0x0214 state 296) */,
+                       0x08, /* fail */
+/* pos 0201: 279 */    0xF3 /* 's' -> */,
+/* pos 0202: 280 */    0xF4 /* 't' -> */,
+/* pos 0203: 281 */    0xAD /* '-' -> */,
+/* pos 0204: 282 */    0xED /* 'm' -> */,
+/* pos 0205: 283 */    0xEF /* 'o' -> */,
+/* pos 0206: 284 */    0xE4 /* 'd' -> */,
+/* pos 0207: 285 */    0xE9 /* 'i' -> */,
+/* pos 0208: 286 */    0xE6 /* 'f' -> */,
+/* pos 0209: 287 */    0xE9 /* 'i' -> */,
+/* pos 020a: 288 */    0xE5 /* 'e' -> */,
+/* pos 020b: 289 */    0xE4 /* 'd' -> */,
+/* pos 020c: 290 */    0xBA /* ':' -> */,
+/* pos 020d: 291 */    0x00, 0x24                  /* - terminal marker 36 - */,
+/* pos 020f: 292 */    0xEE /* 'n' -> */,
+/* pos 0210: 293 */    0xEB /* 'k' -> */,
+/* pos 0211: 294 */    0xBA /* ':' -> */,
+/* pos 0212: 295 */    0x00, 0x25                  /* - terminal marker 37 - */,
+/* pos 0214: 296 */    0xE3 /* 'c' -> */,
+/* pos 0215: 297 */    0xE1 /* 'a' -> */,
+/* pos 0216: 298 */    0xF4 /* 't' -> */,
+/* pos 0217: 299 */    0xE9 /* 'i' -> */,
+/* pos 0218: 300 */    0xEF /* 'o' -> */,
+/* pos 0219: 301 */    0xEE /* 'n' -> */,
+/* pos 021a: 302 */    0xBA /* ':' -> */,
+/* pos 021b: 303 */    0x00, 0x26                  /* - terminal marker 38 - */,
+/* pos 021d: 304 */    0x66 /* 'f' */, 0x07, 0x00  /* (to 0x0224 state 305) */,
+                       0x74 /* 't' */, 0x0B, 0x00  /* (to 0x022B state 311) */,
+                       0x08, /* fail */
+/* pos 0224: 305 */    0xF2 /* 'r' -> */,
+/* pos 0225: 306 */    0xE5 /* 'e' -> */,
+/* pos 0226: 307 */    0xF3 /* 's' -> */,
+/* pos 0227: 308 */    0xE8 /* 'h' -> */,
+/* pos 0228: 309 */    0xBA /* ':' -> */,
+/* pos 0229: 310 */    0x00, 0x27                  /* - terminal marker 39 - */,
+/* pos 022b: 311 */    0xF2 /* 'r' -> */,
+/* pos 022c: 312 */    0xF9 /* 'y' -> */,
+/* pos 022d: 313 */    0xAD /* '-' -> */,
+/* pos 022e: 314 */    0xE1 /* 'a' -> */,
+/* pos 022f: 315 */    0xE6 /* 'f' -> */,
+/* pos 0230: 316 */    0xF4 /* 't' -> */,
+/* pos 0231: 317 */    0xE5 /* 'e' -> */,
+/* pos 0232: 318 */    0xF2 /* 'r' -> */,
+/* pos 0233: 319 */    0xBA /* ':' -> */,
+/* pos 0234: 320 */    0x00, 0x28                  /* - terminal marker 40 - */,
+/* pos 0236: 321 */    0xE5 /* 'e' -> */,
+/* pos 0237: 322 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x023E state 323) */,
+                       0x74 /* 't' */, 0x0A, 0x00  /* (to 0x0244 state 328) */,
+                       0x08, /* fail */
+/* pos 023e: 323 */    0xF6 /* 'v' -> */,
+/* pos 023f: 324 */    0xE5 /* 'e' -> */,
+/* pos 0240: 325 */    0xF2 /* 'r' -> */,
+/* pos 0241: 326 */    0xBA /* ':' -> */,
+/* pos 0242: 327 */    0x00, 0x29                  /* - terminal marker 41 - */,
+/* pos 0244: 328 */    0xAD /* '-' -> */,
+/* pos 0245: 329 */    0xE3 /* 'c' -> */,
+/* pos 0246: 330 */    0xEF /* 'o' -> */,
+/* pos 0247: 331 */    0xEF /* 'o' -> */,
+/* pos 0248: 332 */    0xEB /* 'k' -> */,
+/* pos 0249: 333 */    0xE9 /* 'i' -> */,
+/* pos 024a: 334 */    0xE5 /* 'e' -> */,
+/* pos 024b: 335 */    0xBA /* ':' -> */,
+/* pos 024c: 336 */    0x00, 0x2A                  /* - terminal marker 42 - */,
+/* pos 024e: 337 */    0xF2 /* 'r' -> */,
+/* pos 024f: 338 */    0xE1 /* 'a' -> */,
+/* pos 0250: 339 */    0xEE /* 'n' -> */,
+/* pos 0251: 340 */    0xF3 /* 's' -> */,
+/* pos 0252: 341 */    0xE6 /* 'f' -> */,
+/* pos 0253: 342 */    0xE5 /* 'e' -> */,
+/* pos 0254: 343 */    0xF2 /* 'r' -> */,
+/* pos 0255: 344 */    0xAD /* '-' -> */,
+/* pos 0256: 345 */    0xE5 /* 'e' -> */,
+/* pos 0257: 346 */    0xEE /* 'n' -> */,
+/* pos 0258: 347 */    0xE3 /* 'c' -> */,
+/* pos 0259: 348 */    0xEF /* 'o' -> */,
+/* pos 025a: 349 */    0xE4 /* 'd' -> */,
+/* pos 025b: 350 */    0xE9 /* 'i' -> */,
+/* pos 025c: 351 */    0xEE /* 'n' -> */,
+/* pos 025d: 352 */    0xE7 /* 'g' -> */,
+/* pos 025e: 353 */    0xBA /* ':' -> */,
+/* pos 025f: 354 */    0x00, 0x2B                  /* - terminal marker 43 - */,
+/* pos 0261: 355 */    0xE9 /* 'i' -> */,
+/* pos 0262: 356 */    0xAD /* '-' -> */,
+/* pos 0263: 357 */    0xE1 /* 'a' -> */,
+/* pos 0264: 358 */    0xF2 /* 'r' -> */,
+/* pos 0265: 359 */    0xE7 /* 'g' -> */,
+/* pos 0266: 360 */    0xF3 /* 's' -> */,
+/* pos 0267: 361 */    0x00, 0x2C                  /* - terminal marker 44 - */,
+/* pos 0269: 362 */    0xA0 /* ' ' -> */,
+/* pos 026a: 363 */    0x00, 0x2D                  /* - terminal marker 45 - */,
+/* pos 026c: 364 */    0xAD /* '-' -> */,
+/* pos 026d: 365 */    0x66 /* 'f' */, 0x07, 0x00  /* (to 0x0274 state 366) */,
+                       0x61 /* 'a' */, 0x1A, 0x00  /* (to 0x028A state 385) */,
+                       0x08, /* fail */
+/* pos 0274: 366 */    0xEF /* 'o' -> */,
+/* pos 0275: 367 */    0xF2 /* 'r' -> */,
+/* pos 0276: 368 */    0xF7 /* 'w' -> */,
+/* pos 0277: 369 */    0xE1 /* 'a' -> */,
+/* pos 0278: 370 */    0xF2 /* 'r' -> */,
+/* pos 0279: 371 */    0xE4 /* 'd' -> */,
+/* pos 027a: 372 */    0xE5 /* 'e' -> */,
+/* pos 027b: 373 */    0xE4 /* 'd' -> */,
+/* pos 027c: 374 */    0xAD /* '-' -> */,
+/* pos 027d: 375 */    0xE6 /* 'f' -> */,
+/* pos 027e: 376 */    0xEF /* 'o' -> */,
+/* pos 027f: 377 */    0xF2 /* 'r' -> */,
+/* pos 0280: 378 */    0xBA /* ':' -> */,
+/* pos 0281: 379 */    0x00, 0x2E                  /* - terminal marker 46 - */,
+/* pos 0283: 380 */    0x00, 0x2F                  /* - terminal marker 47 - */,
+/* pos 0285: 381 */    0xE1 /* 'a' -> */,
+/* pos 0286: 382 */    0xE4 /* 'd' -> */,
+/* pos 0287: 383 */    0xA0 /* ' ' -> */,
+/* pos 0288: 384 */    0x00, 0x30                  /* - terminal marker 48 - */,
+/* pos 028a: 385 */    0x75 /* 'u' */, 0x07, 0x00  /* (to 0x0291 state 386) */,
+                       0x6D /* 'm' */, 0x0F, 0x00  /* (to 0x029C state 396) */,
+                       0x08, /* fail */
+/* pos 0291: 386 */    0xF4 /* 't' -> */,
+/* pos 0292: 387 */    0xE8 /* 'h' -> */,
+/* pos 0293: 388 */    0xAD /* '-' -> */,
+/* pos 0294: 389 */    0xF4 /* 't' -> */,
+/* pos 0295: 390 */    0xEF /* 'o' -> */,
+/* pos 0296: 391 */    0xEB /* 'k' -> */,
+/* pos 0297: 392 */    0xE5 /* 'e' -> */,
+/* pos 0298: 393 */    0xEE /* 'n' -> */,
+/* pos 0299: 394 */    0xBA /* ':' -> */,
+/* pos 029a: 395 */    0x00, 0x31                  /* - terminal marker 49 - */,
+/* pos 029c: 396 */    0xFA /* 'z' -> */,
+/* pos 029d: 397 */    0xEE /* 'n' -> */,
+/* pos 029e: 398 */    0xAD /* '-' -> */,
+/* pos 029f: 399 */    0xE4 /* 'd' -> */,
+/* pos 02a0: 400 */    0xF3 /* 's' -> */,
+/* pos 02a1: 401 */    0xF3 /* 's' -> */,
+/* pos 02a2: 402 */    0xAD /* '-' -> */,
+/* pos 02a3: 403 */    0xF3 /* 's' -> */,
+/* pos 02a4: 404 */    0xE9 /* 'i' -> */,
+/* pos 02a5: 405 */    0xE7 /* 'g' -> */,
+/* pos 02a6: 406 */    0xEE /* 'n' -> */,
+/* pos 02a7: 407 */    0xE1 /* 'a' -> */,
+/* pos 02a8: 408 */    0xF4 /* 't' -> */,
+/* pos 02a9: 409 */    0xF5 /* 'u' -> */,
+/* pos 02aa: 410 */    0xF2 /* 'r' -> */,
+/* pos 02ab: 411 */    0xE5 /* 'e' -> */,
+/* pos 02ac: 412 */    0xBA /* ':' -> */,
+/* pos 02ad: 413 */    0x00, 0x32                  /* - terminal marker 50 - */,
+/* total size 687 bytes */
+#endif
+
+#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+       /* 0: 0: get  */
+       /* 1: 1: post  */
+       /* 2: 2: options  */
+       /* 3: 3: host: */
+       /* 4: 4: connection: */
+       /* 5: 5: upgrade: */
+       /* 6: 6: origin: */
+       /* 7: 8: \r
+ */
+       /* 8: 15: http/1.1  */
+       /* 9: 17: accept: */
+       /* 10: 18: access-control-request-headers: */
+       /* 11: 19: if-modified-since: */
+       /* 12: 20: if-none-match: */
+       /* 13: 21: accept-encoding: */
+       /* 14: 22: accept-language: */
+       /* 15: 23: pragma: */
+       /* 16: 24: cache-control: */
+       /* 17: 25: authorization: */
+       /* 18: 26: cookie: */
+       /* 19: 27: content-length: */
+       /* 20: 28: content-type: */
+       /* 21: 29: date: */
+       /* 22: 30: range: */
+       /* 23: 31: referer: */
+       /* 24: 40: accept-charset: */
+       /* 25: 41: accept-ranges: */
+       /* 26: 42: access-control-allow-origin: */
+       /* 27: 43: age: */
+       /* 28: 44: allow: */
+       /* 29: 45: content-disposition: */
+       /* 30: 46: content-encoding: */
+       /* 31: 47: content-language: */
+       /* 32: 48: content-location: */
+       /* 33: 49: content-range: */
+       /* 34: 50: etag: */
+       /* 35: 51: expect: */
+       /* 36: 52: expires: */
+       /* 37: 53: from: */
+       /* 38: 54: if-match: */
+       /* 39: 55: if-range: */
+       /* 40: 56: if-unmodified-since: */
+       /* 41: 57: last-modified: */
+       /* 42: 58: link: */
+       /* 43: 59: location: */
+       /* 44: 60: max-forwards: */
+       /* 45: 61: proxy-authenticate: */
+       /* 46: 62: proxy-authorization: */
+       /* 47: 63: refresh: */
+       /* 48: 64: retry-after: */
+       /* 49: 65: server: */
+       /* 50: 66: set-cookie: */
+       /* 51: 67: strict-transport-security: */
+       /* 52: 68: transfer-encoding: */
+       /* 53: 69: user-agent: */
+       /* 54: 70: vary: */
+       /* 55: 71: via: */
+       /* 56: 72: www-authenticate: */
+       /* 57: 73: patch */
+       /* 58: 74: put */
+       /* 59: 75: delete */
+       /* 60: 76: uri-args */
+       /* 61: 77: proxy  */
+       /* 62: 78: x-real-ip: */
+       /* 63: 79: http/1.0  */
+       /* 64: 80: x-forwarded-for: */
+       /* 65: 81: connect  */
+       /* 66: 82: head  */
+       /* 67: 83: te: */
+       /* 68: 84: replay-nonce: */
+       /* 69: 86: x-auth-token: */
+       /* 70: 87: x-amzn-dss-signature: */
+       /* 71: 88:  */
+/* pos 0000:   0 */    0x67 /* 'g' */, 0x3D, 0x00  /* (to 0x003D state   1) */,
+                       0x70 /* 'p' */, 0x3F, 0x00  /* (to 0x0042 state   5) */,
+                       0x68 /* 'h' */, 0x4E, 0x00  /* (to 0x0054 state  10) */,
+                       0x63 /* 'c' */, 0x5A, 0x00  /* (to 0x0063 state  15) */,
+                       0x75 /* 'u' */, 0x7B, 0x00  /* (to 0x0087 state  26) */,
+                       0x6F /* 'o' */, 0x8A, 0x00  /* (to 0x0099 state  34) */,
+                       0x0D /* '.' */, 0x95, 0x00  /* (to 0x00A7 state  41) */,
+                       0x61 /* 'a' */, 0xA4, 0x00  /* (to 0x00B9 state  51) */,
+                       0x69 /* 'i' */, 0xC1, 0x00  /* (to 0x00D9 state  58) */,
+                       0x64 /* 'd' */, 0x6A, 0x01  /* (to 0x0185 state 160) */,
+                       0x72 /* 'r' */, 0x73, 0x01  /* (to 0x0191 state 165) */,
+                       0x65 /* 'e' */, 0xBF, 0x01  /* (to 0x01E0 state 229) */,
+                       0x66 /* 'f' */, 0xDB, 0x01  /* (to 0x01FF state 245) */,
+                       0x6C /* 'l' */, 0xFD, 0x01  /* (to 0x0224 state 278) */,
+                       0x73 /* 's' */, 0x42, 0x02  /* (to 0x026C state 321) */,
+                       0x74 /* 't' */, 0x5D, 0x02  /* (to 0x028A state 337) */,
+                       0x78 /* 'x' */, 0x7E, 0x02  /* (to 0x02AE state 364) */,
+                       0x6D /* 'm' */, 0x08, 0x03  /* (to 0x033B state 474) */,
+                       0x76 /* 'v' */, 0x61, 0x03  /* (to 0x0397 state 549) */,
+                       0x77 /* 'w' */, 0x6E, 0x03  /* (to 0x03A7 state 557) */,
+                       0x08, /* fail */
+/* pos 003d:   1 */    0xE5 /* 'e' -> */,
+/* pos 003e:   2 */    0xF4 /* 't' -> */,
+/* pos 003f:   3 */    0xA0 /* ' ' -> */,
+/* pos 0040:   4 */    0x00, 0x00                  /* - terminal marker  0 - */,
+/* pos 0042:   5 */    0x6F /* 'o' */, 0x0D, 0x00  /* (to 0x004F state   6) */,
+                       0x72 /* 'r' */, 0xE6, 0x00  /* (to 0x012B state 106) */,
+                       0x61 /* 'a' */, 0x71, 0x03  /* (to 0x03B9 state 574) */,
+                       0x75 /* 'u' */, 0x73, 0x03  /* (to 0x03BE state 578) */,
+                       0x08, /* fail */
+/* pos 004f:   6 */    0xF3 /* 's' -> */,
+/* pos 0050:   7 */    0xF4 /* 't' -> */,
+/* pos 0051:   8 */    0xA0 /* ' ' -> */,
+/* pos 0052:   9 */    0x00, 0x01                  /* - terminal marker  1 - */,
+/* pos 0054:  10 */    0x6F /* 'o' */, 0x0A, 0x00  /* (to 0x005E state  11) */,
+                       0x74 /* 't' */, 0x53, 0x00  /* (to 0x00AA state  43) */,
+                       0x65 /* 'e' */, 0x70, 0x02  /* (to 0x02CA state 381) */,
+                       0x08, /* fail */
+/* pos 005e:  11 */    0xF3 /* 's' -> */,
+/* pos 005f:  12 */    0xF4 /* 't' -> */,
+/* pos 0060:  13 */    0xBA /* ':' -> */,
+/* pos 0061:  14 */    0x00, 0x03                  /* - terminal marker  3 - */,
+/* pos 0063:  15 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x006A state  16) */,
+                       0x61 /* 'a' */, 0xD2, 0x00  /* (to 0x0138 state 112) */,
+                       0x08, /* fail */
+/* pos 006a:  16 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0071 state  17) */,
+                       0x6F /* 'o' */, 0xE7, 0x00  /* (to 0x0154 state 138) */,
+                       0x08, /* fail */
+/* pos 0071:  17 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0078 state  18) */,
+                       0x74 /* 't' */, 0xE6, 0x00  /* (to 0x015A state 143) */,
+                       0x08, /* fail */
+/* pos 0078:  18 */    0xE5 /* 'e' -> */,
+/* pos 0079:  19 */    0xE3 /* 'c' -> */,
+/* pos 007a:  20 */    0xF4 /* 't' -> */,
+/* pos 007b:  21 */    0x69 /* 'i' */, 0x07, 0x00  /* (to 0x0082 state  22) */,
+                       0x20 /* ' ' */, 0x4A, 0x02  /* (to 0x02C8 state 380) */,
+                       0x08, /* fail */
+/* pos 0082:  22 */    0xEF /* 'o' -> */,
+/* pos 0083:  23 */    0xEE /* 'n' -> */,
+/* pos 0084:  24 */    0xBA /* ':' -> */,
+/* pos 0085:  25 */    0x00, 0x04                  /* - terminal marker  4 - */,
+/* pos 0087:  26 */    0x70 /* 'p' */, 0x0A, 0x00  /* (to 0x0091 state  27) */,
+                       0x72 /* 'r' */, 0x19, 0x02  /* (to 0x02A3 state 355) */,
+                       0x73 /* 's' */, 0xFF, 0x02  /* (to 0x038C state 539) */,
+                       0x08, /* fail */
+/* pos 0091:  27 */    0xE7 /* 'g' -> */,
+/* pos 0092:  28 */    0xF2 /* 'r' -> */,
+/* pos 0093:  29 */    0xE1 /* 'a' -> */,
+/* pos 0094:  30 */    0xE4 /* 'd' -> */,
+/* pos 0095:  31 */    0xE5 /* 'e' -> */,
+/* pos 0096:  32 */    0xBA /* ':' -> */,
+/* pos 0097:  33 */    0x00, 0x05                  /* - terminal marker  5 - */,
+/* pos 0099:  34 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x00A0 state  35) */,
+                       0x70 /* 'p' */, 0x58, 0x02  /* (to 0x02F4 state 414) */,
+                       0x08, /* fail */
+/* pos 00a0:  35 */    0xE9 /* 'i' -> */,
+/* pos 00a1:  36 */    0xE7 /* 'g' -> */,
+/* pos 00a2:  37 */    0xE9 /* 'i' -> */,
+/* pos 00a3:  38 */    0xEE /* 'n' -> */,
+/* pos 00a4:  39 */    0xBA /* ':' -> */,
+/* pos 00a5:  40 */    0x00, 0x06                  /* - terminal marker  6 - */,
+/* pos 00a7:  41 */    0x8A /* '.' -> */,
+/* pos 00a8:  42 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 00aa:  43 */    0xF4 /* 't' -> */,
+/* pos 00ab:  44 */    0xF0 /* 'p' -> */,
+/* pos 00ac:  45 */    0xAF /* '/' -> */,
+/* pos 00ad:  46 */    0xB1 /* '1' -> */,
+/* pos 00ae:  47 */    0xAE /* '.' -> */,
+/* pos 00af:  48 */    0x31 /* '1' */, 0x07, 0x00  /* (to 0x00B6 state  49) */,
+                       0x30 /* '0' */, 0xF9, 0x01  /* (to 0x02AB state 362) */,
+                       0x08, /* fail */
+/* pos 00b6:  49 */    0xA0 /* ' ' -> */,
+/* pos 00b7:  50 */    0x00, 0x08                  /* - terminal marker  8 - */,
+/* pos 00b9:  51 */    0x63 /* 'c' */, 0x0D, 0x00  /* (to 0x00C6 state  52) */,
+                       0x75 /* 'u' */, 0x8A, 0x00  /* (to 0x0146 state 125) */,
+                       0x67 /* 'g' */, 0xE7, 0x00  /* (to 0x01A6 state 178) */,
+                       0x6C /* 'l' */, 0xE8, 0x00  /* (to 0x01AA state 181) */,
+                       0x08, /* fail */
+/* pos 00c6:  52 */    0xE3 /* 'c' -> */,
+/* pos 00c7:  53 */    0xE5 /* 'e' -> */,
+/* pos 00c8:  54 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x00CF state  55) */,
+                       0x73 /* 's' */, 0x31, 0x02  /* (to 0x02FC state 421) */,
+                       0x08, /* fail */
+/* pos 00cf:  55 */    0xF4 /* 't' -> */,
+/* pos 00d0:  56 */    0x3A /* ':' */, 0x07, 0x00  /* (to 0x00D7 state  57) */,
+                       0x2D /* '-' */, 0x37, 0x00  /* (to 0x010A state  87) */,
+                       0x08, /* fail */
+/* pos 00d7:  57 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 00d9:  58 */    0xE6 /* 'f' -> */,
+/* pos 00da:  59 */    0xAD /* '-' -> */,
+/* pos 00db:  60 */    0x6D /* 'm' */, 0x0D, 0x00  /* (to 0x00E8 state  61) */,
+                       0x6E /* 'n' */, 0x20, 0x00  /* (to 0x00FE state  76) */,
+                       0x72 /* 'r' */, 0x2A, 0x01  /* (to 0x020B state 255) */,
+                       0x75 /* 'u' */, 0x2E, 0x01  /* (to 0x0212 state 261) */,
+                       0x08, /* fail */
+/* pos 00e8:  61 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x00EF state  62) */,
+                       0x61 /* 'a' */, 0x1A, 0x01  /* (to 0x0205 state 250) */,
+                       0x08, /* fail */
+/* pos 00ef:  62 */    0xE4 /* 'd' -> */,
+/* pos 00f0:  63 */    0xE9 /* 'i' -> */,
+/* pos 00f1:  64 */    0xE6 /* 'f' -> */,
+/* pos 00f2:  65 */    0xE9 /* 'i' -> */,
+/* pos 00f3:  66 */    0xE5 /* 'e' -> */,
+/* pos 00f4:  67 */    0xE4 /* 'd' -> */,
+/* pos 00f5:  68 */    0xAD /* '-' -> */,
+/* pos 00f6:  69 */    0xF3 /* 's' -> */,
+/* pos 00f7:  70 */    0xE9 /* 'i' -> */,
+/* pos 00f8:  71 */    0xEE /* 'n' -> */,
+/* pos 00f9:  72 */    0xE3 /* 'c' -> */,
+/* pos 00fa:  73 */    0xE5 /* 'e' -> */,
+/* pos 00fb:  74 */    0xBA /* ':' -> */,
+/* pos 00fc:  75 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 00fe:  76 */    0xEF /* 'o' -> */,
+/* pos 00ff:  77 */    0xEE /* 'n' -> */,
+/* pos 0100:  78 */    0xE5 /* 'e' -> */,
+/* pos 0101:  79 */    0xAD /* '-' -> */,
+/* pos 0102:  80 */    0xED /* 'm' -> */,
+/* pos 0103:  81 */    0xE1 /* 'a' -> */,
+/* pos 0104:  82 */    0xF4 /* 't' -> */,
+/* pos 0105:  83 */    0xE3 /* 'c' -> */,
+/* pos 0106:  84 */    0xE8 /* 'h' -> */,
+/* pos 0107:  85 */    0xBA /* ':' -> */,
+/* pos 0108:  86 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 010a:  87 */    0x65 /* 'e' */, 0x0D, 0x00  /* (to 0x0117 state  88) */,
+                       0x6C /* 'l' */, 0x14, 0x00  /* (to 0x0121 state  97) */,
+                       0x72 /* 'r' */, 0x8E, 0x00  /* (to 0x019E state 171) */,
+                       0x63 /* 'c' */, 0x11, 0x02  /* (to 0x0324 state 453) */,
+                       0x08, /* fail */
+/* pos 0117:  88 */    0xEE /* 'n' -> */,
+/* pos 0118:  89 */    0xE3 /* 'c' -> */,
+/* pos 0119:  90 */    0xEF /* 'o' -> */,
+/* pos 011a:  91 */    0xE4 /* 'd' -> */,
+/* pos 011b:  92 */    0xE9 /* 'i' -> */,
+/* pos 011c:  93 */    0xEE /* 'n' -> */,
+/* pos 011d:  94 */    0xE7 /* 'g' -> */,
+/* pos 011e:  95 */    0xBA /* ':' -> */,
+/* pos 011f:  96 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 0121:  97 */    0xE1 /* 'a' -> */,
+/* pos 0122:  98 */    0xEE /* 'n' -> */,
+/* pos 0123:  99 */    0xE7 /* 'g' -> */,
+/* pos 0124: 100 */    0xF5 /* 'u' -> */,
+/* pos 0125: 101 */    0xE1 /* 'a' -> */,
+/* pos 0126: 102 */    0xE7 /* 'g' -> */,
+/* pos 0127: 103 */    0xE5 /* 'e' -> */,
+/* pos 0128: 104 */    0xBA /* ':' -> */,
+/* pos 0129: 105 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 012b: 106 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0132 state 107) */,
+                       0x6F /* 'o' */, 0x1B, 0x02  /* (to 0x0349 state 487) */,
+                       0x08, /* fail */
+/* pos 0132: 107 */    0xE7 /* 'g' -> */,
+/* pos 0133: 108 */    0xED /* 'm' -> */,
+/* pos 0134: 109 */    0xE1 /* 'a' -> */,
+/* pos 0135: 110 */    0xBA /* ':' -> */,
+/* pos 0136: 111 */    0x00, 0x0F                  /* - terminal marker 15 - */,
+/* pos 0138: 112 */    0xE3 /* 'c' -> */,
+/* pos 0139: 113 */    0xE8 /* 'h' -> */,
+/* pos 013a: 114 */    0xE5 /* 'e' -> */,
+/* pos 013b: 115 */    0xAD /* '-' -> */,
+/* pos 013c: 116 */    0xE3 /* 'c' -> */,
+/* pos 013d: 117 */    0xEF /* 'o' -> */,
+/* pos 013e: 118 */    0xEE /* 'n' -> */,
+/* pos 013f: 119 */    0xF4 /* 't' -> */,
+/* pos 0140: 120 */    0xF2 /* 'r' -> */,
+/* pos 0141: 121 */    0xEF /* 'o' -> */,
+/* pos 0142: 122 */    0xEC /* 'l' -> */,
+/* pos 0143: 123 */    0xBA /* ':' -> */,
+/* pos 0144: 124 */    0x00, 0x10                  /* - terminal marker 16 - */,
+/* pos 0146: 125 */    0xF4 /* 't' -> */,
+/* pos 0147: 126 */    0xE8 /* 'h' -> */,
+/* pos 0148: 127 */    0xEF /* 'o' -> */,
+/* pos 0149: 128 */    0xF2 /* 'r' -> */,
+/* pos 014a: 129 */    0xE9 /* 'i' -> */,
+/* pos 014b: 130 */    0xFA /* 'z' -> */,
+/* pos 014c: 131 */    0xE1 /* 'a' -> */,
+/* pos 014d: 132 */    0xF4 /* 't' -> */,
+/* pos 014e: 133 */    0xE9 /* 'i' -> */,
+/* pos 014f: 134 */    0xEF /* 'o' -> */,
+/* pos 0150: 135 */    0xEE /* 'n' -> */,
+/* pos 0151: 136 */    0xBA /* ':' -> */,
+/* pos 0152: 137 */    0x00, 0x11                  /* - terminal marker 17 - */,
+/* pos 0154: 138 */    0xEB /* 'k' -> */,
+/* pos 0155: 139 */    0xE9 /* 'i' -> */,
+/* pos 0156: 140 */    0xE5 /* 'e' -> */,
+/* pos 0157: 141 */    0xBA /* ':' -> */,
+/* pos 0158: 142 */    0x00, 0x12                  /* - terminal marker 18 - */,
+/* pos 015a: 143 */    0xE5 /* 'e' -> */,
+/* pos 015b: 144 */    0xEE /* 'n' -> */,
+/* pos 015c: 145 */    0xF4 /* 't' -> */,
+/* pos 015d: 146 */    0xAD /* '-' -> */,
+/* pos 015e: 147 */    0x6C /* 'l' */, 0x10, 0x00  /* (to 0x016E state 148) */,
+                       0x74 /* 't' */, 0x1E, 0x00  /* (to 0x017F state 155) */,
+                       0x64 /* 'd' */, 0x4C, 0x00  /* (to 0x01B0 state 186) */,
+                       0x65 /* 'e' */, 0x56, 0x00  /* (to 0x01BD state 198) */,
+                       0x72 /* 'r' */, 0x6F, 0x00  /* (to 0x01D9 state 223) */,
+                       0x08, /* fail */
+/* pos 016e: 148 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x0178 state 149) */,
+                       0x61 /* 'a' */, 0x56, 0x00  /* (to 0x01C7 state 207) */,
+                       0x6F /* 'o' */, 0x5C, 0x00  /* (to 0x01D0 state 215) */,
+                       0x08, /* fail */
+/* pos 0178: 149 */    0xEE /* 'n' -> */,
+/* pos 0179: 150 */    0xE7 /* 'g' -> */,
+/* pos 017a: 151 */    0xF4 /* 't' -> */,
+/* pos 017b: 152 */    0xE8 /* 'h' -> */,
+/* pos 017c: 153 */    0xBA /* ':' -> */,
+/* pos 017d: 154 */    0x00, 0x13                  /* - terminal marker 19 - */,
+/* pos 017f: 155 */    0xF9 /* 'y' -> */,
+/* pos 0180: 156 */    0xF0 /* 'p' -> */,
+/* pos 0181: 157 */    0xE5 /* 'e' -> */,
+/* pos 0182: 158 */    0xBA /* ':' -> */,
+/* pos 0183: 159 */    0x00, 0x14                  /* - terminal marker 20 - */,
+/* pos 0185: 160 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x018C state 161) */,
+                       0x65 /* 'e' */, 0x39, 0x02  /* (to 0x03C1 state 580) */,
+                       0x08, /* fail */
+/* pos 018c: 161 */    0xF4 /* 't' -> */,
+/* pos 018d: 162 */    0xE5 /* 'e' -> */,
+/* pos 018e: 163 */    0xBA /* ':' -> */,
+/* pos 018f: 164 */    0x00, 0x15                  /* - terminal marker 21 - */,
+/* pos 0191: 165 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0198 state 166) */,
+                       0x65 /* 'e' */, 0xB6, 0x00  /* (to 0x024A state 304) */,
+                       0x08, /* fail */
+/* pos 0198: 166 */    0xEE /* 'n' -> */,
+/* pos 0199: 167 */    0xE7 /* 'g' -> */,
+/* pos 019a: 168 */    0xE5 /* 'e' -> */,
+/* pos 019b: 169 */    0xBA /* ':' -> */,
+/* pos 019c: 170 */    0x00, 0x16                  /* - terminal marker 22 - */,
+/* pos 019e: 171 */    0xE1 /* 'a' -> */,
+/* pos 019f: 172 */    0xEE /* 'n' -> */,
+/* pos 01a0: 173 */    0xE7 /* 'g' -> */,
+/* pos 01a1: 174 */    0xE5 /* 'e' -> */,
+/* pos 01a2: 175 */    0xF3 /* 's' -> */,
+/* pos 01a3: 176 */    0xBA /* ':' -> */,
+/* pos 01a4: 177 */    0x00, 0x19                  /* - terminal marker 25 - */,
+/* pos 01a6: 178 */    0xE5 /* 'e' -> */,
+/* pos 01a7: 179 */    0xBA /* ':' -> */,
+/* pos 01a8: 180 */    0x00, 0x1B                  /* - terminal marker 27 - */,
+/* pos 01aa: 181 */    0xEC /* 'l' -> */,
+/* pos 01ab: 182 */    0xEF /* 'o' -> */,
+/* pos 01ac: 183 */    0xF7 /* 'w' -> */,
+/* pos 01ad: 184 */    0xBA /* ':' -> */,
+/* pos 01ae: 185 */    0x00, 0x1C                  /* - terminal marker 28 - */,
+/* pos 01b0: 186 */    0xE9 /* 'i' -> */,
+/* pos 01b1: 187 */    0xF3 /* 's' -> */,
+/* pos 01b2: 188 */    0xF0 /* 'p' -> */,
+/* pos 01b3: 189 */    0xEF /* 'o' -> */,
+/* pos 01b4: 190 */    0xF3 /* 's' -> */,
+/* pos 01b5: 191 */    0xE9 /* 'i' -> */,
+/* pos 01b6: 192 */    0xF4 /* 't' -> */,
+/* pos 01b7: 193 */    0xE9 /* 'i' -> */,
+/* pos 01b8: 194 */    0xEF /* 'o' -> */,
+/* pos 01b9: 195 */    0xEE /* 'n' -> */,
+/* pos 01ba: 196 */    0xBA /* ':' -> */,
+/* pos 01bb: 197 */    0x00, 0x1D                  /* - terminal marker 29 - */,
+/* pos 01bd: 198 */    0xEE /* 'n' -> */,
+/* pos 01be: 199 */    0xE3 /* 'c' -> */,
+/* pos 01bf: 200 */    0xEF /* 'o' -> */,
+/* pos 01c0: 201 */    0xE4 /* 'd' -> */,
+/* pos 01c1: 202 */    0xE9 /* 'i' -> */,
+/* pos 01c2: 203 */    0xEE /* 'n' -> */,
+/* pos 01c3: 204 */    0xE7 /* 'g' -> */,
+/* pos 01c4: 205 */    0xBA /* ':' -> */,
+/* pos 01c5: 206 */    0x00, 0x1E                  /* - terminal marker 30 - */,
+/* pos 01c7: 207 */    0xEE /* 'n' -> */,
+/* pos 01c8: 208 */    0xE7 /* 'g' -> */,
+/* pos 01c9: 209 */    0xF5 /* 'u' -> */,
+/* pos 01ca: 210 */    0xE1 /* 'a' -> */,
+/* pos 01cb: 211 */    0xE7 /* 'g' -> */,
+/* pos 01cc: 212 */    0xE5 /* 'e' -> */,
+/* pos 01cd: 213 */    0xBA /* ':' -> */,
+/* pos 01ce: 214 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 01d0: 215 */    0xE3 /* 'c' -> */,
+/* pos 01d1: 216 */    0xE1 /* 'a' -> */,
+/* pos 01d2: 217 */    0xF4 /* 't' -> */,
+/* pos 01d3: 218 */    0xE9 /* 'i' -> */,
+/* pos 01d4: 219 */    0xEF /* 'o' -> */,
+/* pos 01d5: 220 */    0xEE /* 'n' -> */,
+/* pos 01d6: 221 */    0xBA /* ':' -> */,
+/* pos 01d7: 222 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 01d9: 223 */    0xE1 /* 'a' -> */,
+/* pos 01da: 224 */    0xEE /* 'n' -> */,
+/* pos 01db: 225 */    0xE7 /* 'g' -> */,
+/* pos 01dc: 226 */    0xE5 /* 'e' -> */,
+/* pos 01dd: 227 */    0xBA /* ':' -> */,
+/* pos 01de: 228 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* pos 01e0: 229 */    0x74 /* 't' */, 0x07, 0x00  /* (to 0x01E7 state 230) */,
+                       0x78 /* 'x' */, 0x09, 0x00  /* (to 0x01EC state 234) */,
+                       0x08, /* fail */
+/* pos 01e7: 230 */    0xE1 /* 'a' -> */,
+/* pos 01e8: 231 */    0xE7 /* 'g' -> */,
+/* pos 01e9: 232 */    0xBA /* ':' -> */,
+/* pos 01ea: 233 */    0x00, 0x22                  /* - terminal marker 34 - */,
+/* pos 01ec: 234 */    0xF0 /* 'p' -> */,
+/* pos 01ed: 235 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x01F4 state 236) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x01F9 state 240) */,
+                       0x08, /* fail */
+/* pos 01f4: 236 */    0xE3 /* 'c' -> */,
+/* pos 01f5: 237 */    0xF4 /* 't' -> */,
+/* pos 01f6: 238 */    0xBA /* ':' -> */,
+/* pos 01f7: 239 */    0x00, 0x23                  /* - terminal marker 35 - */,
+/* pos 01f9: 240 */    0xF2 /* 'r' -> */,
+/* pos 01fa: 241 */    0xE5 /* 'e' -> */,
+/* pos 01fb: 242 */    0xF3 /* 's' -> */,
+/* pos 01fc: 243 */    0xBA /* ':' -> */,
+/* pos 01fd: 244 */    0x00, 0x24                  /* - terminal marker 36 - */,
+/* pos 01ff: 245 */    0xF2 /* 'r' -> */,
+/* pos 0200: 246 */    0xEF /* 'o' -> */,
+/* pos 0201: 247 */    0xED /* 'm' -> */,
+/* pos 0202: 248 */    0xBA /* ':' -> */,
+/* pos 0203: 249 */    0x00, 0x25                  /* - terminal marker 37 - */,
+/* pos 0205: 250 */    0xF4 /* 't' -> */,
+/* pos 0206: 251 */    0xE3 /* 'c' -> */,
+/* pos 0207: 252 */    0xE8 /* 'h' -> */,
+/* pos 0208: 253 */    0xBA /* ':' -> */,
+/* pos 0209: 254 */    0x00, 0x26                  /* - terminal marker 38 - */,
+/* pos 020b: 255 */    0xE1 /* 'a' -> */,
+/* pos 020c: 256 */    0xEE /* 'n' -> */,
+/* pos 020d: 257 */    0xE7 /* 'g' -> */,
+/* pos 020e: 258 */    0xE5 /* 'e' -> */,
+/* pos 020f: 259 */    0xBA /* ':' -> */,
+/* pos 0210: 260 */    0x00, 0x27                  /* - terminal marker 39 - */,
+/* pos 0212: 261 */    0xEE /* 'n' -> */,
+/* pos 0213: 262 */    0xED /* 'm' -> */,
+/* pos 0214: 263 */    0xEF /* 'o' -> */,
+/* pos 0215: 264 */    0xE4 /* 'd' -> */,
+/* pos 0216: 265 */    0xE9 /* 'i' -> */,
+/* pos 0217: 266 */    0xE6 /* 'f' -> */,
+/* pos 0218: 267 */    0xE9 /* 'i' -> */,
+/* pos 0219: 268 */    0xE5 /* 'e' -> */,
+/* pos 021a: 269 */    0xE4 /* 'd' -> */,
+/* pos 021b: 270 */    0xAD /* '-' -> */,
+/* pos 021c: 271 */    0xF3 /* 's' -> */,
+/* pos 021d: 272 */    0xE9 /* 'i' -> */,
+/* pos 021e: 273 */    0xEE /* 'n' -> */,
+/* pos 021f: 274 */    0xE3 /* 'c' -> */,
+/* pos 0220: 275 */    0xE5 /* 'e' -> */,
+/* pos 0221: 276 */    0xBA /* ':' -> */,
+/* pos 0222: 277 */    0x00, 0x28                  /* - terminal marker 40 - */,
+/* pos 0224: 278 */    0x61 /* 'a' */, 0x0A, 0x00  /* (to 0x022E state 279) */,
+                       0x69 /* 'i' */, 0x15, 0x00  /* (to 0x023C state 292) */,
+                       0x6F /* 'o' */, 0x17, 0x00  /* (to 0x0241 state 296) */,
+                       0x08, /* fail */
+/* pos 022e: 279 */    0xF3 /* 's' -> */,
+/* pos 022f: 280 */    0xF4 /* 't' -> */,
+/* pos 0230: 281 */    0xAD /* '-' -> */,
+/* pos 0231: 282 */    0xED /* 'm' -> */,
+/* pos 0232: 283 */    0xEF /* 'o' -> */,
+/* pos 0233: 284 */    0xE4 /* 'd' -> */,
+/* pos 0234: 285 */    0xE9 /* 'i' -> */,
+/* pos 0235: 286 */    0xE6 /* 'f' -> */,
+/* pos 0236: 287 */    0xE9 /* 'i' -> */,
+/* pos 0237: 288 */    0xE5 /* 'e' -> */,
+/* pos 0238: 289 */    0xE4 /* 'd' -> */,
+/* pos 0239: 290 */    0xBA /* ':' -> */,
+/* pos 023a: 291 */    0x00, 0x29                  /* - terminal marker 41 - */,
+/* pos 023c: 292 */    0xEE /* 'n' -> */,
+/* pos 023d: 293 */    0xEB /* 'k' -> */,
+/* pos 023e: 294 */    0xBA /* ':' -> */,
+/* pos 023f: 295 */    0x00, 0x2A                  /* - terminal marker 42 - */,
+/* pos 0241: 296 */    0xE3 /* 'c' -> */,
+/* pos 0242: 297 */    0xE1 /* 'a' -> */,
+/* pos 0243: 298 */    0xF4 /* 't' -> */,
+/* pos 0244: 299 */    0xE9 /* 'i' -> */,
+/* pos 0245: 300 */    0xEF /* 'o' -> */,
+/* pos 0246: 301 */    0xEE /* 'n' -> */,
+/* pos 0247: 302 */    0xBA /* ':' -> */,
+/* pos 0248: 303 */    0x00, 0x2B                  /* - terminal marker 43 - */,
+/* pos 024a: 304 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x0254 state 305) */,
+                       0x74 /* 't' */, 0x14, 0x00  /* (to 0x0261 state 311) */,
+                       0x70 /* 'p' */, 0x85, 0x01  /* (to 0x03D5 state 596) */,
+                       0x08, /* fail */
+/* pos 0254: 305 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x025B state 306) */,
+                       0x65 /* 'e' */, 0xC7, 0x00  /* (to 0x031E state 448) */,
+                       0x08, /* fail */
+/* pos 025b: 306 */    0xE5 /* 'e' -> */,
+/* pos 025c: 307 */    0xF3 /* 's' -> */,
+/* pos 025d: 308 */    0xE8 /* 'h' -> */,
+/* pos 025e: 309 */    0xBA /* ':' -> */,
+/* pos 025f: 310 */    0x00, 0x2F                  /* - terminal marker 47 - */,
+/* pos 0261: 311 */    0xF2 /* 'r' -> */,
+/* pos 0262: 312 */    0xF9 /* 'y' -> */,
+/* pos 0263: 313 */    0xAD /* '-' -> */,
+/* pos 0264: 314 */    0xE1 /* 'a' -> */,
+/* pos 0265: 315 */    0xE6 /* 'f' -> */,
+/* pos 0266: 316 */    0xF4 /* 't' -> */,
+/* pos 0267: 317 */    0xE5 /* 'e' -> */,
+/* pos 0268: 318 */    0xF2 /* 'r' -> */,
+/* pos 0269: 319 */    0xBA /* ':' -> */,
+/* pos 026a: 320 */    0x00, 0x30                  /* - terminal marker 48 - */,
+/* pos 026c: 321 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0273 state 322) */,
+                       0x74 /* 't' */, 0x03, 0x01  /* (to 0x0372 state 514) */,
+                       0x08, /* fail */
+/* pos 0273: 322 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x027A state 323) */,
+                       0x74 /* 't' */, 0x0A, 0x00  /* (to 0x0280 state 328) */,
+                       0x08, /* fail */
+/* pos 027a: 323 */    0xF6 /* 'v' -> */,
+/* pos 027b: 324 */    0xE5 /* 'e' -> */,
+/* pos 027c: 325 */    0xF2 /* 'r' -> */,
+/* pos 027d: 326 */    0xBA /* ':' -> */,
+/* pos 027e: 327 */    0x00, 0x31                  /* - terminal marker 49 - */,
+/* pos 0280: 328 */    0xAD /* '-' -> */,
+/* pos 0281: 329 */    0xE3 /* 'c' -> */,
+/* pos 0282: 330 */    0xEF /* 'o' -> */,
+/* pos 0283: 331 */    0xEF /* 'o' -> */,
+/* pos 0284: 332 */    0xEB /* 'k' -> */,
+/* pos 0285: 333 */    0xE9 /* 'i' -> */,
+/* pos 0286: 334 */    0xE5 /* 'e' -> */,
+/* pos 0287: 335 */    0xBA /* ':' -> */,
+/* pos 0288: 336 */    0x00, 0x32                  /* - terminal marker 50 - */,
+/* pos 028a: 337 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0291 state 338) */,
+                       0x65 /* 'e' */, 0x45, 0x01  /* (to 0x03D2 state 594) */,
+                       0x08, /* fail */
+/* pos 0291: 338 */    0xE1 /* 'a' -> */,
+/* pos 0292: 339 */    0xEE /* 'n' -> */,
+/* pos 0293: 340 */    0xF3 /* 's' -> */,
+/* pos 0294: 341 */    0xE6 /* 'f' -> */,
+/* pos 0295: 342 */    0xE5 /* 'e' -> */,
+/* pos 0296: 343 */    0xF2 /* 'r' -> */,
+/* pos 0297: 344 */    0xAD /* '-' -> */,
+/* pos 0298: 345 */    0xE5 /* 'e' -> */,
+/* pos 0299: 346 */    0xEE /* 'n' -> */,
+/* pos 029a: 347 */    0xE3 /* 'c' -> */,
+/* pos 029b: 348 */    0xEF /* 'o' -> */,
+/* pos 029c: 349 */    0xE4 /* 'd' -> */,
+/* pos 029d: 350 */    0xE9 /* 'i' -> */,
+/* pos 029e: 351 */    0xEE /* 'n' -> */,
+/* pos 029f: 352 */    0xE7 /* 'g' -> */,
+/* pos 02a0: 353 */    0xBA /* ':' -> */,
+/* pos 02a1: 354 */    0x00, 0x34                  /* - terminal marker 52 - */,
+/* pos 02a3: 355 */    0xE9 /* 'i' -> */,
+/* pos 02a4: 356 */    0xAD /* '-' -> */,
+/* pos 02a5: 357 */    0xE1 /* 'a' -> */,
+/* pos 02a6: 358 */    0xF2 /* 'r' -> */,
+/* pos 02a7: 359 */    0xE7 /* 'g' -> */,
+/* pos 02a8: 360 */    0xF3 /* 's' -> */,
+/* pos 02a9: 361 */    0x00, 0x3C                  /* - terminal marker 60 - */,
+/* pos 02ab: 362 */    0xA0 /* ' ' -> */,
+/* pos 02ac: 363 */    0x00, 0x3F                  /* - terminal marker 63 - */,
+/* pos 02ae: 364 */    0xAD /* '-' -> */,
+/* pos 02af: 365 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x02B9 state 366) */,
+                       0x61 /* 'a' */, 0x1D, 0x00  /* (to 0x02CF state 385) */,
+                       0x72 /* 'r' */, 0x14, 0x01  /* (to 0x03C9 state 586) */,
+                       0x08, /* fail */
+/* pos 02b9: 366 */    0xEF /* 'o' -> */,
+/* pos 02ba: 367 */    0xF2 /* 'r' -> */,
+/* pos 02bb: 368 */    0xF7 /* 'w' -> */,
+/* pos 02bc: 369 */    0xE1 /* 'a' -> */,
+/* pos 02bd: 370 */    0xF2 /* 'r' -> */,
+/* pos 02be: 371 */    0xE4 /* 'd' -> */,
+/* pos 02bf: 372 */    0xE5 /* 'e' -> */,
+/* pos 02c0: 373 */    0xE4 /* 'd' -> */,
+/* pos 02c1: 374 */    0xAD /* '-' -> */,
+/* pos 02c2: 375 */    0xE6 /* 'f' -> */,
+/* pos 02c3: 376 */    0xEF /* 'o' -> */,
+/* pos 02c4: 377 */    0xF2 /* 'r' -> */,
+/* pos 02c5: 378 */    0xBA /* ':' -> */,
+/* pos 02c6: 379 */    0x00, 0x40                  /* - terminal marker 64 - */,
+/* pos 02c8: 380 */    0x00, 0x41                  /* - terminal marker 65 - */,
+/* pos 02ca: 381 */    0xE1 /* 'a' -> */,
+/* pos 02cb: 382 */    0xE4 /* 'd' -> */,
+/* pos 02cc: 383 */    0xA0 /* ' ' -> */,
+/* pos 02cd: 384 */    0x00, 0x42                  /* - terminal marker 66 - */,
+/* pos 02cf: 385 */    0x75 /* 'u' */, 0x07, 0x00  /* (to 0x02D6 state 386) */,
+                       0x6D /* 'm' */, 0x0F, 0x00  /* (to 0x02E1 state 396) */,
+                       0x08, /* fail */
+/* pos 02d6: 386 */    0xF4 /* 't' -> */,
+/* pos 02d7: 387 */    0xE8 /* 'h' -> */,
+/* pos 02d8: 388 */    0xAD /* '-' -> */,
+/* pos 02d9: 389 */    0xF4 /* 't' -> */,
+/* pos 02da: 390 */    0xEF /* 'o' -> */,
+/* pos 02db: 391 */    0xEB /* 'k' -> */,
+/* pos 02dc: 392 */    0xE5 /* 'e' -> */,
+/* pos 02dd: 393 */    0xEE /* 'n' -> */,
+/* pos 02de: 394 */    0xBA /* ':' -> */,
+/* pos 02df: 395 */    0x00, 0x45                  /* - terminal marker 69 - */,
+/* pos 02e1: 396 */    0xFA /* 'z' -> */,
+/* pos 02e2: 397 */    0xEE /* 'n' -> */,
+/* pos 02e3: 398 */    0xAD /* '-' -> */,
+/* pos 02e4: 399 */    0xE4 /* 'd' -> */,
+/* pos 02e5: 400 */    0xF3 /* 's' -> */,
+/* pos 02e6: 401 */    0xF3 /* 's' -> */,
+/* pos 02e7: 402 */    0xAD /* '-' -> */,
+/* pos 02e8: 403 */    0xF3 /* 's' -> */,
+/* pos 02e9: 404 */    0xE9 /* 'i' -> */,
+/* pos 02ea: 405 */    0xE7 /* 'g' -> */,
+/* pos 02eb: 406 */    0xEE /* 'n' -> */,
+/* pos 02ec: 407 */    0xE1 /* 'a' -> */,
+/* pos 02ed: 408 */    0xF4 /* 't' -> */,
+/* pos 02ee: 409 */    0xF5 /* 'u' -> */,
+/* pos 02ef: 410 */    0xF2 /* 'r' -> */,
+/* pos 02f0: 411 */    0xE5 /* 'e' -> */,
+/* pos 02f1: 412 */    0xBA /* ':' -> */,
+/* pos 02f2: 413 */    0x00, 0x46                  /* - terminal marker 70 - */,
+/* pos 02f4: 414 */    0xF4 /* 't' -> */,
+/* pos 02f5: 415 */    0xE9 /* 'i' -> */,
+/* pos 02f6: 416 */    0xEF /* 'o' -> */,
+/* pos 02f7: 417 */    0xEE /* 'n' -> */,
+/* pos 02f8: 418 */    0xF3 /* 's' -> */,
+/* pos 02f9: 419 */    0xA0 /* ' ' -> */,
+/* pos 02fa: 420 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 02fc: 421 */    0xF3 /* 's' -> */,
+/* pos 02fd: 422 */    0xAD /* '-' -> */,
+/* pos 02fe: 423 */    0xE3 /* 'c' -> */,
+/* pos 02ff: 424 */    0xEF /* 'o' -> */,
+/* pos 0300: 425 */    0xEE /* 'n' -> */,
+/* pos 0301: 426 */    0xF4 /* 't' -> */,
+/* pos 0302: 427 */    0xF2 /* 'r' -> */,
+/* pos 0303: 428 */    0xEF /* 'o' -> */,
+/* pos 0304: 429 */    0xEC /* 'l' -> */,
+/* pos 0305: 430 */    0xAD /* '-' -> */,
+/* pos 0306: 431 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x030D state 432) */,
+                       0x61 /* 'a' */, 0x24, 0x00  /* (to 0x032D state 461) */,
+                       0x08, /* fail */
+/* pos 030d: 432 */    0xE5 /* 'e' -> */,
+/* pos 030e: 433 */    0xF1 /* 'q' -> */,
+/* pos 030f: 434 */    0xF5 /* 'u' -> */,
+/* pos 0310: 435 */    0xE5 /* 'e' -> */,
+/* pos 0311: 436 */    0xF3 /* 's' -> */,
+/* pos 0312: 437 */    0xF4 /* 't' -> */,
+/* pos 0313: 438 */    0xAD /* '-' -> */,
+/* pos 0314: 439 */    0xE8 /* 'h' -> */,
+/* pos 0315: 440 */    0xE5 /* 'e' -> */,
+/* pos 0316: 441 */    0xE1 /* 'a' -> */,
+/* pos 0317: 442 */    0xE4 /* 'd' -> */,
+/* pos 0318: 443 */    0xE5 /* 'e' -> */,
+/* pos 0319: 444 */    0xF2 /* 'r' -> */,
+/* pos 031a: 445 */    0xF3 /* 's' -> */,
+/* pos 031b: 446 */    0xBA /* ':' -> */,
+/* pos 031c: 447 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 031e: 448 */    0xF2 /* 'r' -> */,
+/* pos 031f: 449 */    0xE5 /* 'e' -> */,
+/* pos 0320: 450 */    0xF2 /* 'r' -> */,
+/* pos 0321: 451 */    0xBA /* ':' -> */,
+/* pos 0322: 452 */    0x00, 0x17                  /* - terminal marker 23 - */,
+/* pos 0324: 453 */    0xE8 /* 'h' -> */,
+/* pos 0325: 454 */    0xE1 /* 'a' -> */,
+/* pos 0326: 455 */    0xF2 /* 'r' -> */,
+/* pos 0327: 456 */    0xF3 /* 's' -> */,
+/* pos 0328: 457 */    0xE5 /* 'e' -> */,
+/* pos 0329: 458 */    0xF4 /* 't' -> */,
+/* pos 032a: 459 */    0xBA /* ':' -> */,
+/* pos 032b: 460 */    0x00, 0x18                  /* - terminal marker 24 - */,
+/* pos 032d: 461 */    0xEC /* 'l' -> */,
+/* pos 032e: 462 */    0xEC /* 'l' -> */,
+/* pos 032f: 463 */    0xEF /* 'o' -> */,
+/* pos 0330: 464 */    0xF7 /* 'w' -> */,
+/* pos 0331: 465 */    0xAD /* '-' -> */,
+/* pos 0332: 466 */    0xEF /* 'o' -> */,
+/* pos 0333: 467 */    0xF2 /* 'r' -> */,
+/* pos 0334: 468 */    0xE9 /* 'i' -> */,
+/* pos 0335: 469 */    0xE7 /* 'g' -> */,
+/* pos 0336: 470 */    0xE9 /* 'i' -> */,
+/* pos 0337: 471 */    0xEE /* 'n' -> */,
+/* pos 0338: 472 */    0xBA /* ':' -> */,
+/* pos 0339: 473 */    0x00, 0x1A                  /* - terminal marker 26 - */,
+/* pos 033b: 474 */    0xE1 /* 'a' -> */,
+/* pos 033c: 475 */    0xF8 /* 'x' -> */,
+/* pos 033d: 476 */    0xAD /* '-' -> */,
+/* pos 033e: 477 */    0xE6 /* 'f' -> */,
+/* pos 033f: 478 */    0xEF /* 'o' -> */,
+/* pos 0340: 479 */    0xF2 /* 'r' -> */,
+/* pos 0341: 480 */    0xF7 /* 'w' -> */,
+/* pos 0342: 481 */    0xE1 /* 'a' -> */,
+/* pos 0343: 482 */    0xF2 /* 'r' -> */,
+/* pos 0344: 483 */    0xE4 /* 'd' -> */,
+/* pos 0345: 484 */    0xF3 /* 's' -> */,
+/* pos 0346: 485 */    0xBA /* ':' -> */,
+/* pos 0347: 486 */    0x00, 0x2C                  /* - terminal marker 44 - */,
+/* pos 0349: 487 */    0xF8 /* 'x' -> */,
+/* pos 034a: 488 */    0xF9 /* 'y' -> */,
+/* pos 034b: 489 */    0x2D /* '-' */, 0x07, 0x00  /* (to 0x0352 state 490) */,
+                       0x20 /* ' ' */, 0x79, 0x00  /* (to 0x03C7 state 585) */,
+                       0x08, /* fail */
+/* pos 0352: 490 */    0xE1 /* 'a' -> */,
+/* pos 0353: 491 */    0xF5 /* 'u' -> */,
+/* pos 0354: 492 */    0xF4 /* 't' -> */,
+/* pos 0355: 493 */    0xE8 /* 'h' -> */,
+/* pos 0356: 494 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x035D state 495) */,
+                       0x6F /* 'o' */, 0x0E, 0x00  /* (to 0x0367 state 504) */,
+                       0x08, /* fail */
+/* pos 035d: 495 */    0xEE /* 'n' -> */,
+/* pos 035e: 496 */    0xF4 /* 't' -> */,
+/* pos 035f: 497 */    0xE9 /* 'i' -> */,
+/* pos 0360: 498 */    0xE3 /* 'c' -> */,
+/* pos 0361: 499 */    0xE1 /* 'a' -> */,
+/* pos 0362: 500 */    0xF4 /* 't' -> */,
+/* pos 0363: 501 */    0xE5 /* 'e' -> */,
+/* pos 0364: 502 */    0xBA /* ':' -> */,
+/* pos 0365: 503 */    0x00, 0x2D                  /* - terminal marker 45 - */,
+/* pos 0367: 504 */    0xF2 /* 'r' -> */,
+/* pos 0368: 505 */    0xE9 /* 'i' -> */,
+/* pos 0369: 506 */    0xFA /* 'z' -> */,
+/* pos 036a: 507 */    0xE1 /* 'a' -> */,
+/* pos 036b: 508 */    0xF4 /* 't' -> */,
+/* pos 036c: 509 */    0xE9 /* 'i' -> */,
+/* pos 036d: 510 */    0xEF /* 'o' -> */,
+/* pos 036e: 511 */    0xEE /* 'n' -> */,
+/* pos 036f: 512 */    0xBA /* ':' -> */,
+/* pos 0370: 513 */    0x00, 0x2E                  /* - terminal marker 46 - */,
+/* pos 0372: 514 */    0xF2 /* 'r' -> */,
+/* pos 0373: 515 */    0xE9 /* 'i' -> */,
+/* pos 0374: 516 */    0xE3 /* 'c' -> */,
+/* pos 0375: 517 */    0xF4 /* 't' -> */,
+/* pos 0376: 518 */    0xAD /* '-' -> */,
+/* pos 0377: 519 */    0xF4 /* 't' -> */,
+/* pos 0378: 520 */    0xF2 /* 'r' -> */,
+/* pos 0379: 521 */    0xE1 /* 'a' -> */,
+/* pos 037a: 522 */    0xEE /* 'n' -> */,
+/* pos 037b: 523 */    0xF3 /* 's' -> */,
+/* pos 037c: 524 */    0xF0 /* 'p' -> */,
+/* pos 037d: 525 */    0xEF /* 'o' -> */,
+/* pos 037e: 526 */    0xF2 /* 'r' -> */,
+/* pos 037f: 527 */    0xF4 /* 't' -> */,
+/* pos 0380: 528 */    0xAD /* '-' -> */,
+/* pos 0381: 529 */    0xF3 /* 's' -> */,
+/* pos 0382: 530 */    0xE5 /* 'e' -> */,
+/* pos 0383: 531 */    0xE3 /* 'c' -> */,
+/* pos 0384: 532 */    0xF5 /* 'u' -> */,
+/* pos 0385: 533 */    0xF2 /* 'r' -> */,
+/* pos 0386: 534 */    0xE9 /* 'i' -> */,
+/* pos 0387: 535 */    0xF4 /* 't' -> */,
+/* pos 0388: 536 */    0xF9 /* 'y' -> */,
+/* pos 0389: 537 */    0xBA /* ':' -> */,
+/* pos 038a: 538 */    0x00, 0x33                  /* - terminal marker 51 - */,
+/* pos 038c: 539 */    0xE5 /* 'e' -> */,
+/* pos 038d: 540 */    0xF2 /* 'r' -> */,
+/* pos 038e: 541 */    0xAD /* '-' -> */,
+/* pos 038f: 542 */    0xE1 /* 'a' -> */,
+/* pos 0390: 543 */    0xE7 /* 'g' -> */,
+/* pos 0391: 544 */    0xE5 /* 'e' -> */,
+/* pos 0392: 545 */    0xEE /* 'n' -> */,
+/* pos 0393: 546 */    0xF4 /* 't' -> */,
+/* pos 0394: 547 */    0xBA /* ':' -> */,
+/* pos 0395: 548 */    0x00, 0x35                  /* - terminal marker 53 - */,
+/* pos 0397: 549 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x039E state 550) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x03A3 state 554) */,
+                       0x08, /* fail */
+/* pos 039e: 550 */    0xF2 /* 'r' -> */,
+/* pos 039f: 551 */    0xF9 /* 'y' -> */,
+/* pos 03a0: 552 */    0xBA /* ':' -> */,
+/* pos 03a1: 553 */    0x00, 0x36                  /* - terminal marker 54 - */,
+/* pos 03a3: 554 */    0xE1 /* 'a' -> */,
+/* pos 03a4: 555 */    0xBA /* ':' -> */,
+/* pos 03a5: 556 */    0x00, 0x37                  /* - terminal marker 55 - */,
+/* pos 03a7: 557 */    0xF7 /* 'w' -> */,
+/* pos 03a8: 558 */    0xF7 /* 'w' -> */,
+/* pos 03a9: 559 */    0xAD /* '-' -> */,
+/* pos 03aa: 560 */    0xE1 /* 'a' -> */,
+/* pos 03ab: 561 */    0xF5 /* 'u' -> */,
+/* pos 03ac: 562 */    0xF4 /* 't' -> */,
+/* pos 03ad: 563 */    0xE8 /* 'h' -> */,
+/* pos 03ae: 564 */    0xE5 /* 'e' -> */,
+/* pos 03af: 565 */    0xEE /* 'n' -> */,
+/* pos 03b0: 566 */    0xF4 /* 't' -> */,
+/* pos 03b1: 567 */    0xE9 /* 'i' -> */,
+/* pos 03b2: 568 */    0xE3 /* 'c' -> */,
+/* pos 03b3: 569 */    0xE1 /* 'a' -> */,
+/* pos 03b4: 570 */    0xF4 /* 't' -> */,
+/* pos 03b5: 571 */    0xE5 /* 'e' -> */,
+/* pos 03b6: 572 */    0xBA /* ':' -> */,
+/* pos 03b7: 573 */    0x00, 0x38                  /* - terminal marker 56 - */,
+/* pos 03b9: 574 */    0xF4 /* 't' -> */,
+/* pos 03ba: 575 */    0xE3 /* 'c' -> */,
+/* pos 03bb: 576 */    0xE8 /* 'h' -> */,
+/* pos 03bc: 577 */    0x00, 0x39                  /* - terminal marker 57 - */,
+/* pos 03be: 578 */    0xF4 /* 't' -> */,
+/* pos 03bf: 579 */    0x00, 0x3A                  /* - terminal marker 58 - */,
+/* pos 03c1: 580 */    0xEC /* 'l' -> */,
+/* pos 03c2: 581 */    0xE5 /* 'e' -> */,
+/* pos 03c3: 582 */    0xF4 /* 't' -> */,
+/* pos 03c4: 583 */    0xE5 /* 'e' -> */,
+/* pos 03c5: 584 */    0x00, 0x3B                  /* - terminal marker 59 - */,
+/* pos 03c7: 585 */    0x00, 0x3D                  /* - terminal marker 61 - */,
+/* pos 03c9: 586 */    0xE5 /* 'e' -> */,
+/* pos 03ca: 587 */    0xE1 /* 'a' -> */,
+/* pos 03cb: 588 */    0xEC /* 'l' -> */,
+/* pos 03cc: 589 */    0xAD /* '-' -> */,
+/* pos 03cd: 590 */    0xE9 /* 'i' -> */,
+/* pos 03ce: 591 */    0xF0 /* 'p' -> */,
+/* pos 03cf: 592 */    0xBA /* ':' -> */,
+/* pos 03d0: 593 */    0x00, 0x3E                  /* - terminal marker 62 - */,
+/* pos 03d2: 594 */    0xBA /* ':' -> */,
+/* pos 03d3: 595 */    0x00, 0x43                  /* - terminal marker 67 - */,
+/* pos 03d5: 596 */    0xEC /* 'l' -> */,
+/* pos 03d6: 597 */    0xE1 /* 'a' -> */,
+/* pos 03d7: 598 */    0xF9 /* 'y' -> */,
+/* pos 03d8: 599 */    0xAD /* '-' -> */,
+/* pos 03d9: 600 */    0xEE /* 'n' -> */,
+/* pos 03da: 601 */    0xEF /* 'o' -> */,
+/* pos 03db: 602 */    0xEE /* 'n' -> */,
+/* pos 03dc: 603 */    0xE3 /* 'c' -> */,
+/* pos 03dd: 604 */    0xE5 /* 'e' -> */,
+/* pos 03de: 605 */    0xBA /* ':' -> */,
+/* pos 03df: 606 */    0x00, 0x44                  /* - terminal marker 68 - */,
+/* total size 993 bytes */
+#endif
+
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+       /* 0: 0: get  */
+       /* 1: 1: post  */
+       /* 2: 3: host: */
+       /* 3: 4: connection: */
+       /* 4: 5: upgrade: */
+       /* 5: 6: origin: */
+       /* 6: 7: sec-websocket-draft: */
+       /* 7: 8: \r
+ */
+       /* 8: 9: sec-websocket-extensions: */
+       /* 9: 10: sec-websocket-key1: */
+       /* 10: 11: sec-websocket-key2: */
+       /* 11: 12: sec-websocket-protocol: */
+       /* 12: 13: sec-websocket-accept: */
+       /* 13: 14: sec-websocket-nonce: */
+       /* 14: 15: http/1.1  */
+       /* 15: 17: accept: */
+       /* 16: 19: if-modified-since: */
+       /* 17: 20: if-none-match: */
+       /* 18: 21: accept-encoding: */
+       /* 19: 22: accept-language: */
+       /* 20: 23: pragma: */
+       /* 21: 24: cache-control: */
+       /* 22: 25: authorization: */
+       /* 23: 26: cookie: */
+       /* 24: 27: content-length: */
+       /* 25: 28: content-type: */
+       /* 26: 29: date: */
+       /* 27: 30: range: */
+       /* 28: 32: sec-websocket-key: */
+       /* 29: 33: sec-websocket-version: */
+       /* 30: 34: sec-websocket-origin: */
+       /* 31: 41: accept-ranges: */
+       /* 32: 43: age: */
+       /* 33: 44: allow: */
+       /* 34: 45: content-disposition: */
+       /* 35: 46: content-encoding: */
+       /* 36: 47: content-language: */
+       /* 37: 48: content-location: */
+       /* 38: 49: content-range: */
+       /* 39: 50: etag: */
+       /* 40: 51: expect: */
+       /* 41: 52: expires: */
+       /* 42: 53: from: */
+       /* 43: 54: if-match: */
+       /* 44: 55: if-range: */
+       /* 45: 56: if-unmodified-since: */
+       /* 46: 57: last-modified: */
+       /* 47: 58: link: */
+       /* 48: 59: location: */
+       /* 49: 63: refresh: */
+       /* 50: 64: retry-after: */
+       /* 51: 65: server: */
+       /* 52: 66: set-cookie: */
+       /* 53: 68: transfer-encoding: */
+       /* 54: 76: uri-args */
+       /* 55: 79: http/1.0  */
+       /* 56: 80: x-forwarded-for: */
+       /* 57: 81: connect  */
+       /* 58: 82: head  */
+       /* 59: 86: x-auth-token: */
+       /* 60: 87: x-amzn-dss-signature: */
+       /* 61: 88:  */
+/* pos 0000:   0 */    0x67 /* 'g' */, 0x3D, 0x00  /* (to 0x003D state   1) */,
+                       0x70 /* 'p' */, 0x3F, 0x00  /* (to 0x0042 state   5) */,
+                       0x68 /* 'h' */, 0x4E, 0x00  /* (to 0x0054 state  10) */,
+                       0x63 /* 'c' */, 0x5A, 0x00  /* (to 0x0063 state  15) */,
+                       0x75 /* 'u' */, 0x7B, 0x00  /* (to 0x0087 state  26) */,
+                       0x6F /* 'o' */, 0x8A, 0x00  /* (to 0x0099 state  34) */,
+                       0x0D /* '.' */, 0x95, 0x00  /* (to 0x00A7 state  41) */,
+                       0x61 /* 'a' */, 0xA4, 0x00  /* (to 0x00B9 state  51) */,
+                       0x69 /* 'i' */, 0xC1, 0x00  /* (to 0x00D9 state  58) */,
+                       0x64 /* 'd' */, 0x6A, 0x01  /* (to 0x0185 state 160) */,
+                       0x72 /* 'r' */, 0x73, 0x01  /* (to 0x0191 state 165) */,
+                       0x65 /* 'e' */, 0xBF, 0x01  /* (to 0x01E0 state 229) */,
+                       0x66 /* 'f' */, 0xDB, 0x01  /* (to 0x01FF state 245) */,
+                       0x6C /* 'l' */, 0xFD, 0x01  /* (to 0x0224 state 278) */,
+                       0x73 /* 's' */, 0x42, 0x02  /* (to 0x026C state 321) */,
+                       0x74 /* 't' */, 0x60, 0x02  /* (to 0x028D state 337) */,
+                       0x78 /* 'x' */, 0x81, 0x02  /* (to 0x02B1 state 364) */,
+                       0x6D /* 'm' */, 0x0B, 0x03  /* (to 0x033E state 474) */,
+                       0x76 /* 'v' */, 0x64, 0x03  /* (to 0x039A state 549) */,
+                       0x77 /* 'w' */, 0x71, 0x03  /* (to 0x03AA state 557) */,
+                       0x08, /* fail */
+/* pos 003d:   1 */    0xE5 /* 'e' -> */,
+/* pos 003e:   2 */    0xF4 /* 't' -> */,
+/* pos 003f:   3 */    0xA0 /* ' ' -> */,
+/* pos 0040:   4 */    0x00, 0x00                  /* - terminal marker  0 - */,
+/* pos 0042:   5 */    0x6F /* 'o' */, 0x0D, 0x00  /* (to 0x004F state   6) */,
+                       0x72 /* 'r' */, 0xE6, 0x00  /* (to 0x012B state 106) */,
+                       0x61 /* 'a' */, 0x74, 0x03  /* (to 0x03BC state 574) */,
+                       0x75 /* 'u' */, 0x76, 0x03  /* (to 0x03C1 state 578) */,
+                       0x08, /* fail */
+/* pos 004f:   6 */    0xF3 /* 's' -> */,
+/* pos 0050:   7 */    0xF4 /* 't' -> */,
+/* pos 0051:   8 */    0xA0 /* ' ' -> */,
+/* pos 0052:   9 */    0x00, 0x01                  /* - terminal marker  1 - */,
+/* pos 0054:  10 */    0x6F /* 'o' */, 0x0A, 0x00  /* (to 0x005E state  11) */,
+                       0x74 /* 't' */, 0x53, 0x00  /* (to 0x00AA state  43) */,
+                       0x65 /* 'e' */, 0x73, 0x02  /* (to 0x02CD state 381) */,
+                       0x08, /* fail */
+/* pos 005e:  11 */    0xF3 /* 's' -> */,
+/* pos 005f:  12 */    0xF4 /* 't' -> */,
+/* pos 0060:  13 */    0xBA /* ':' -> */,
+/* pos 0061:  14 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 0063:  15 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x006A state  16) */,
+                       0x61 /* 'a' */, 0xD2, 0x00  /* (to 0x0138 state 112) */,
+                       0x08, /* fail */
+/* pos 006a:  16 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0071 state  17) */,
+                       0x6F /* 'o' */, 0xE7, 0x00  /* (to 0x0154 state 138) */,
+                       0x08, /* fail */
+/* pos 0071:  17 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0078 state  18) */,
+                       0x74 /* 't' */, 0xE6, 0x00  /* (to 0x015A state 143) */,
+                       0x08, /* fail */
+/* pos 0078:  18 */    0xE5 /* 'e' -> */,
+/* pos 0079:  19 */    0xE3 /* 'c' -> */,
+/* pos 007a:  20 */    0xF4 /* 't' -> */,
+/* pos 007b:  21 */    0x69 /* 'i' */, 0x07, 0x00  /* (to 0x0082 state  22) */,
+                       0x20 /* ' ' */, 0x4D, 0x02  /* (to 0x02CB state 380) */,
+                       0x08, /* fail */
+/* pos 0082:  22 */    0xEF /* 'o' -> */,
+/* pos 0083:  23 */    0xEE /* 'n' -> */,
+/* pos 0084:  24 */    0xBA /* ':' -> */,
+/* pos 0085:  25 */    0x00, 0x03                  /* - terminal marker  3 - */,
+/* pos 0087:  26 */    0x70 /* 'p' */, 0x0A, 0x00  /* (to 0x0091 state  27) */,
+                       0x72 /* 'r' */, 0x1C, 0x02  /* (to 0x02A6 state 355) */,
+                       0x73 /* 's' */, 0x02, 0x03  /* (to 0x038F state 539) */,
+                       0x08, /* fail */
+/* pos 0091:  27 */    0xE7 /* 'g' -> */,
+/* pos 0092:  28 */    0xF2 /* 'r' -> */,
+/* pos 0093:  29 */    0xE1 /* 'a' -> */,
+/* pos 0094:  30 */    0xE4 /* 'd' -> */,
+/* pos 0095:  31 */    0xE5 /* 'e' -> */,
+/* pos 0096:  32 */    0xBA /* ':' -> */,
+/* pos 0097:  33 */    0x00, 0x04                  /* - terminal marker  4 - */,
+/* pos 0099:  34 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x00A0 state  35) */,
+                       0x70 /* 'p' */, 0x5B, 0x02  /* (to 0x02F7 state 414) */,
+                       0x08, /* fail */
+/* pos 00a0:  35 */    0xE9 /* 'i' -> */,
+/* pos 00a1:  36 */    0xE7 /* 'g' -> */,
+/* pos 00a2:  37 */    0xE9 /* 'i' -> */,
+/* pos 00a3:  38 */    0xEE /* 'n' -> */,
+/* pos 00a4:  39 */    0xBA /* ':' -> */,
+/* pos 00a5:  40 */    0x00, 0x05                  /* - terminal marker  5 - */,
+/* pos 00a7:  41 */    0x8A /* '.' -> */,
+/* pos 00a8:  42 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 00aa:  43 */    0xF4 /* 't' -> */,
+/* pos 00ab:  44 */    0xF0 /* 'p' -> */,
+/* pos 00ac:  45 */    0xAF /* '/' -> */,
+/* pos 00ad:  46 */    0xB1 /* '1' -> */,
+/* pos 00ae:  47 */    0xAE /* '.' -> */,
+/* pos 00af:  48 */    0x31 /* '1' */, 0x07, 0x00  /* (to 0x00B6 state  49) */,
+                       0x30 /* '0' */, 0xFC, 0x01  /* (to 0x02AE state 362) */,
+                       0x08, /* fail */
+/* pos 00b6:  49 */    0xA0 /* ' ' -> */,
+/* pos 00b7:  50 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 00b9:  51 */    0x63 /* 'c' */, 0x0D, 0x00  /* (to 0x00C6 state  52) */,
+                       0x75 /* 'u' */, 0x8A, 0x00  /* (to 0x0146 state 125) */,
+                       0x67 /* 'g' */, 0xE7, 0x00  /* (to 0x01A6 state 178) */,
+                       0x6C /* 'l' */, 0xE8, 0x00  /* (to 0x01AA state 181) */,
+                       0x08, /* fail */
+/* pos 00c6:  52 */    0xE3 /* 'c' -> */,
+/* pos 00c7:  53 */    0xE5 /* 'e' -> */,
+/* pos 00c8:  54 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x00CF state  55) */,
+                       0x73 /* 's' */, 0x34, 0x02  /* (to 0x02FF state 421) */,
+                       0x08, /* fail */
+/* pos 00cf:  55 */    0xF4 /* 't' -> */,
+/* pos 00d0:  56 */    0x3A /* ':' */, 0x07, 0x00  /* (to 0x00D7 state  57) */,
+                       0x2D /* '-' */, 0x37, 0x00  /* (to 0x010A state  87) */,
+                       0x08, /* fail */
+/* pos 00d7:  57 */    0x00, 0x0F                  /* - terminal marker 15 - */,
+/* pos 00d9:  58 */    0xE6 /* 'f' -> */,
+/* pos 00da:  59 */    0xAD /* '-' -> */,
+/* pos 00db:  60 */    0x6D /* 'm' */, 0x0D, 0x00  /* (to 0x00E8 state  61) */,
+                       0x6E /* 'n' */, 0x20, 0x00  /* (to 0x00FE state  76) */,
+                       0x72 /* 'r' */, 0x2A, 0x01  /* (to 0x020B state 255) */,
+                       0x75 /* 'u' */, 0x2E, 0x01  /* (to 0x0212 state 261) */,
+                       0x08, /* fail */
+/* pos 00e8:  61 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x00EF state  62) */,
+                       0x61 /* 'a' */, 0x1A, 0x01  /* (to 0x0205 state 250) */,
+                       0x08, /* fail */
+/* pos 00ef:  62 */    0xE4 /* 'd' -> */,
+/* pos 00f0:  63 */    0xE9 /* 'i' -> */,
+/* pos 00f1:  64 */    0xE6 /* 'f' -> */,
+/* pos 00f2:  65 */    0xE9 /* 'i' -> */,
+/* pos 00f3:  66 */    0xE5 /* 'e' -> */,
+/* pos 00f4:  67 */    0xE4 /* 'd' -> */,
+/* pos 00f5:  68 */    0xAD /* '-' -> */,
+/* pos 00f6:  69 */    0xF3 /* 's' -> */,
+/* pos 00f7:  70 */    0xE9 /* 'i' -> */,
+/* pos 00f8:  71 */    0xEE /* 'n' -> */,
+/* pos 00f9:  72 */    0xE3 /* 'c' -> */,
+/* pos 00fa:  73 */    0xE5 /* 'e' -> */,
+/* pos 00fb:  74 */    0xBA /* ':' -> */,
+/* pos 00fc:  75 */    0x00, 0x10                  /* - terminal marker 16 - */,
+/* pos 00fe:  76 */    0xEF /* 'o' -> */,
+/* pos 00ff:  77 */    0xEE /* 'n' -> */,
+/* pos 0100:  78 */    0xE5 /* 'e' -> */,
+/* pos 0101:  79 */    0xAD /* '-' -> */,
+/* pos 0102:  80 */    0xED /* 'm' -> */,
+/* pos 0103:  81 */    0xE1 /* 'a' -> */,
+/* pos 0104:  82 */    0xF4 /* 't' -> */,
+/* pos 0105:  83 */    0xE3 /* 'c' -> */,
+/* pos 0106:  84 */    0xE8 /* 'h' -> */,
+/* pos 0107:  85 */    0xBA /* ':' -> */,
+/* pos 0108:  86 */    0x00, 0x11                  /* - terminal marker 17 - */,
+/* pos 010a:  87 */    0x65 /* 'e' */, 0x0D, 0x00  /* (to 0x0117 state  88) */,
+                       0x6C /* 'l' */, 0x14, 0x00  /* (to 0x0121 state  97) */,
+                       0x72 /* 'r' */, 0x8E, 0x00  /* (to 0x019E state 171) */,
+                       0x63 /* 'c' */, 0x14, 0x02  /* (to 0x0327 state 453) */,
+                       0x08, /* fail */
+/* pos 0117:  88 */    0xEE /* 'n' -> */,
+/* pos 0118:  89 */    0xE3 /* 'c' -> */,
+/* pos 0119:  90 */    0xEF /* 'o' -> */,
+/* pos 011a:  91 */    0xE4 /* 'd' -> */,
+/* pos 011b:  92 */    0xE9 /* 'i' -> */,
+/* pos 011c:  93 */    0xEE /* 'n' -> */,
+/* pos 011d:  94 */    0xE7 /* 'g' -> */,
+/* pos 011e:  95 */    0xBA /* ':' -> */,
+/* pos 011f:  96 */    0x00, 0x12                  /* - terminal marker 18 - */,
+/* pos 0121:  97 */    0xE1 /* 'a' -> */,
+/* pos 0122:  98 */    0xEE /* 'n' -> */,
+/* pos 0123:  99 */    0xE7 /* 'g' -> */,
+/* pos 0124: 100 */    0xF5 /* 'u' -> */,
+/* pos 0125: 101 */    0xE1 /* 'a' -> */,
+/* pos 0126: 102 */    0xE7 /* 'g' -> */,
+/* pos 0127: 103 */    0xE5 /* 'e' -> */,
+/* pos 0128: 104 */    0xBA /* ':' -> */,
+/* pos 0129: 105 */    0x00, 0x13                  /* - terminal marker 19 - */,
+/* pos 012b: 106 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0132 state 107) */,
+                       0x6F /* 'o' */, 0x1E, 0x02  /* (to 0x034C state 487) */,
+                       0x08, /* fail */
+/* pos 0132: 107 */    0xE7 /* 'g' -> */,
+/* pos 0133: 108 */    0xED /* 'm' -> */,
+/* pos 0134: 109 */    0xE1 /* 'a' -> */,
+/* pos 0135: 110 */    0xBA /* ':' -> */,
+/* pos 0136: 111 */    0x00, 0x14                  /* - terminal marker 20 - */,
+/* pos 0138: 112 */    0xE3 /* 'c' -> */,
+/* pos 0139: 113 */    0xE8 /* 'h' -> */,
+/* pos 013a: 114 */    0xE5 /* 'e' -> */,
+/* pos 013b: 115 */    0xAD /* '-' -> */,
+/* pos 013c: 116 */    0xE3 /* 'c' -> */,
+/* pos 013d: 117 */    0xEF /* 'o' -> */,
+/* pos 013e: 118 */    0xEE /* 'n' -> */,
+/* pos 013f: 119 */    0xF4 /* 't' -> */,
+/* pos 0140: 120 */    0xF2 /* 'r' -> */,
+/* pos 0141: 121 */    0xEF /* 'o' -> */,
+/* pos 0142: 122 */    0xEC /* 'l' -> */,
+/* pos 0143: 123 */    0xBA /* ':' -> */,
+/* pos 0144: 124 */    0x00, 0x15                  /* - terminal marker 21 - */,
+/* pos 0146: 125 */    0xF4 /* 't' -> */,
+/* pos 0147: 126 */    0xE8 /* 'h' -> */,
+/* pos 0148: 127 */    0xEF /* 'o' -> */,
+/* pos 0149: 128 */    0xF2 /* 'r' -> */,
+/* pos 014a: 129 */    0xE9 /* 'i' -> */,
+/* pos 014b: 130 */    0xFA /* 'z' -> */,
+/* pos 014c: 131 */    0xE1 /* 'a' -> */,
+/* pos 014d: 132 */    0xF4 /* 't' -> */,
+/* pos 014e: 133 */    0xE9 /* 'i' -> */,
+/* pos 014f: 134 */    0xEF /* 'o' -> */,
+/* pos 0150: 135 */    0xEE /* 'n' -> */,
+/* pos 0151: 136 */    0xBA /* ':' -> */,
+/* pos 0152: 137 */    0x00, 0x16                  /* - terminal marker 22 - */,
+/* pos 0154: 138 */    0xEB /* 'k' -> */,
+/* pos 0155: 139 */    0xE9 /* 'i' -> */,
+/* pos 0156: 140 */    0xE5 /* 'e' -> */,
+/* pos 0157: 141 */    0xBA /* ':' -> */,
+/* pos 0158: 142 */    0x00, 0x17                  /* - terminal marker 23 - */,
+/* pos 015a: 143 */    0xE5 /* 'e' -> */,
+/* pos 015b: 144 */    0xEE /* 'n' -> */,
+/* pos 015c: 145 */    0xF4 /* 't' -> */,
+/* pos 015d: 146 */    0xAD /* '-' -> */,
+/* pos 015e: 147 */    0x6C /* 'l' */, 0x10, 0x00  /* (to 0x016E state 148) */,
+                       0x74 /* 't' */, 0x1E, 0x00  /* (to 0x017F state 155) */,
+                       0x64 /* 'd' */, 0x4C, 0x00  /* (to 0x01B0 state 186) */,
+                       0x65 /* 'e' */, 0x56, 0x00  /* (to 0x01BD state 198) */,
+                       0x72 /* 'r' */, 0x6F, 0x00  /* (to 0x01D9 state 223) */,
+                       0x08, /* fail */
+/* pos 016e: 148 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x0178 state 149) */,
+                       0x61 /* 'a' */, 0x56, 0x00  /* (to 0x01C7 state 207) */,
+                       0x6F /* 'o' */, 0x5C, 0x00  /* (to 0x01D0 state 215) */,
+                       0x08, /* fail */
+/* pos 0178: 149 */    0xEE /* 'n' -> */,
+/* pos 0179: 150 */    0xE7 /* 'g' -> */,
+/* pos 017a: 151 */    0xF4 /* 't' -> */,
+/* pos 017b: 152 */    0xE8 /* 'h' -> */,
+/* pos 017c: 153 */    0xBA /* ':' -> */,
+/* pos 017d: 154 */    0x00, 0x18                  /* - terminal marker 24 - */,
+/* pos 017f: 155 */    0xF9 /* 'y' -> */,
+/* pos 0180: 156 */    0xF0 /* 'p' -> */,
+/* pos 0181: 157 */    0xE5 /* 'e' -> */,
+/* pos 0182: 158 */    0xBA /* ':' -> */,
+/* pos 0183: 159 */    0x00, 0x19                  /* - terminal marker 25 - */,
+/* pos 0185: 160 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x018C state 161) */,
+                       0x65 /* 'e' */, 0x3C, 0x02  /* (to 0x03C4 state 580) */,
+                       0x08, /* fail */
+/* pos 018c: 161 */    0xF4 /* 't' -> */,
+/* pos 018d: 162 */    0xE5 /* 'e' -> */,
+/* pos 018e: 163 */    0xBA /* ':' -> */,
+/* pos 018f: 164 */    0x00, 0x1A                  /* - terminal marker 26 - */,
+/* pos 0191: 165 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0198 state 166) */,
+                       0x65 /* 'e' */, 0xB6, 0x00  /* (to 0x024A state 304) */,
+                       0x08, /* fail */
+/* pos 0198: 166 */    0xEE /* 'n' -> */,
+/* pos 0199: 167 */    0xE7 /* 'g' -> */,
+/* pos 019a: 168 */    0xE5 /* 'e' -> */,
+/* pos 019b: 169 */    0xBA /* ':' -> */,
+/* pos 019c: 170 */    0x00, 0x1B                  /* - terminal marker 27 - */,
+/* pos 019e: 171 */    0xE1 /* 'a' -> */,
+/* pos 019f: 172 */    0xEE /* 'n' -> */,
+/* pos 01a0: 173 */    0xE7 /* 'g' -> */,
+/* pos 01a1: 174 */    0xE5 /* 'e' -> */,
+/* pos 01a2: 175 */    0xF3 /* 's' -> */,
+/* pos 01a3: 176 */    0xBA /* ':' -> */,
+/* pos 01a4: 177 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 01a6: 178 */    0xE5 /* 'e' -> */,
+/* pos 01a7: 179 */    0xBA /* ':' -> */,
+/* pos 01a8: 180 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 01aa: 181 */    0xEC /* 'l' -> */,
+/* pos 01ab: 182 */    0xEF /* 'o' -> */,
+/* pos 01ac: 183 */    0xF7 /* 'w' -> */,
+/* pos 01ad: 184 */    0xBA /* ':' -> */,
+/* pos 01ae: 185 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* pos 01b0: 186 */    0xE9 /* 'i' -> */,
+/* pos 01b1: 187 */    0xF3 /* 's' -> */,
+/* pos 01b2: 188 */    0xF0 /* 'p' -> */,
+/* pos 01b3: 189 */    0xEF /* 'o' -> */,
+/* pos 01b4: 190 */    0xF3 /* 's' -> */,
+/* pos 01b5: 191 */    0xE9 /* 'i' -> */,
+/* pos 01b6: 192 */    0xF4 /* 't' -> */,
+/* pos 01b7: 193 */    0xE9 /* 'i' -> */,
+/* pos 01b8: 194 */    0xEF /* 'o' -> */,
+/* pos 01b9: 195 */    0xEE /* 'n' -> */,
+/* pos 01ba: 196 */    0xBA /* ':' -> */,
+/* pos 01bb: 197 */    0x00, 0x22                  /* - terminal marker 34 - */,
+/* pos 01bd: 198 */    0xEE /* 'n' -> */,
+/* pos 01be: 199 */    0xE3 /* 'c' -> */,
+/* pos 01bf: 200 */    0xEF /* 'o' -> */,
+/* pos 01c0: 201 */    0xE4 /* 'd' -> */,
+/* pos 01c1: 202 */    0xE9 /* 'i' -> */,
+/* pos 01c2: 203 */    0xEE /* 'n' -> */,
+/* pos 01c3: 204 */    0xE7 /* 'g' -> */,
+/* pos 01c4: 205 */    0xBA /* ':' -> */,
+/* pos 01c5: 206 */    0x00, 0x23                  /* - terminal marker 35 - */,
+/* pos 01c7: 207 */    0xEE /* 'n' -> */,
+/* pos 01c8: 208 */    0xE7 /* 'g' -> */,
+/* pos 01c9: 209 */    0xF5 /* 'u' -> */,
+/* pos 01ca: 210 */    0xE1 /* 'a' -> */,
+/* pos 01cb: 211 */    0xE7 /* 'g' -> */,
+/* pos 01cc: 212 */    0xE5 /* 'e' -> */,
+/* pos 01cd: 213 */    0xBA /* ':' -> */,
+/* pos 01ce: 214 */    0x00, 0x24                  /* - terminal marker 36 - */,
+/* pos 01d0: 215 */    0xE3 /* 'c' -> */,
+/* pos 01d1: 216 */    0xE1 /* 'a' -> */,
+/* pos 01d2: 217 */    0xF4 /* 't' -> */,
+/* pos 01d3: 218 */    0xE9 /* 'i' -> */,
+/* pos 01d4: 219 */    0xEF /* 'o' -> */,
+/* pos 01d5: 220 */    0xEE /* 'n' -> */,
+/* pos 01d6: 221 */    0xBA /* ':' -> */,
+/* pos 01d7: 222 */    0x00, 0x25                  /* - terminal marker 37 - */,
+/* pos 01d9: 223 */    0xE1 /* 'a' -> */,
+/* pos 01da: 224 */    0xEE /* 'n' -> */,
+/* pos 01db: 225 */    0xE7 /* 'g' -> */,
+/* pos 01dc: 226 */    0xE5 /* 'e' -> */,
+/* pos 01dd: 227 */    0xBA /* ':' -> */,
+/* pos 01de: 228 */    0x00, 0x26                  /* - terminal marker 38 - */,
+/* pos 01e0: 229 */    0x74 /* 't' */, 0x07, 0x00  /* (to 0x01E7 state 230) */,
+                       0x78 /* 'x' */, 0x09, 0x00  /* (to 0x01EC state 234) */,
+                       0x08, /* fail */
+/* pos 01e7: 230 */    0xE1 /* 'a' -> */,
+/* pos 01e8: 231 */    0xE7 /* 'g' -> */,
+/* pos 01e9: 232 */    0xBA /* ':' -> */,
+/* pos 01ea: 233 */    0x00, 0x27                  /* - terminal marker 39 - */,
+/* pos 01ec: 234 */    0xF0 /* 'p' -> */,
+/* pos 01ed: 235 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x01F4 state 236) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x01F9 state 240) */,
+                       0x08, /* fail */
+/* pos 01f4: 236 */    0xE3 /* 'c' -> */,
+/* pos 01f5: 237 */    0xF4 /* 't' -> */,
+/* pos 01f6: 238 */    0xBA /* ':' -> */,
+/* pos 01f7: 239 */    0x00, 0x28                  /* - terminal marker 40 - */,
+/* pos 01f9: 240 */    0xF2 /* 'r' -> */,
+/* pos 01fa: 241 */    0xE5 /* 'e' -> */,
+/* pos 01fb: 242 */    0xF3 /* 's' -> */,
+/* pos 01fc: 243 */    0xBA /* ':' -> */,
+/* pos 01fd: 244 */    0x00, 0x29                  /* - terminal marker 41 - */,
+/* pos 01ff: 245 */    0xF2 /* 'r' -> */,
+/* pos 0200: 246 */    0xEF /* 'o' -> */,
+/* pos 0201: 247 */    0xED /* 'm' -> */,
+/* pos 0202: 248 */    0xBA /* ':' -> */,
+/* pos 0203: 249 */    0x00, 0x2A                  /* - terminal marker 42 - */,
+/* pos 0205: 250 */    0xF4 /* 't' -> */,
+/* pos 0206: 251 */    0xE3 /* 'c' -> */,
+/* pos 0207: 252 */    0xE8 /* 'h' -> */,
+/* pos 0208: 253 */    0xBA /* ':' -> */,
+/* pos 0209: 254 */    0x00, 0x2B                  /* - terminal marker 43 - */,
+/* pos 020b: 255 */    0xE1 /* 'a' -> */,
+/* pos 020c: 256 */    0xEE /* 'n' -> */,
+/* pos 020d: 257 */    0xE7 /* 'g' -> */,
+/* pos 020e: 258 */    0xE5 /* 'e' -> */,
+/* pos 020f: 259 */    0xBA /* ':' -> */,
+/* pos 0210: 260 */    0x00, 0x2C                  /* - terminal marker 44 - */,
+/* pos 0212: 261 */    0xEE /* 'n' -> */,
+/* pos 0213: 262 */    0xED /* 'm' -> */,
+/* pos 0214: 263 */    0xEF /* 'o' -> */,
+/* pos 0215: 264 */    0xE4 /* 'd' -> */,
+/* pos 0216: 265 */    0xE9 /* 'i' -> */,
+/* pos 0217: 266 */    0xE6 /* 'f' -> */,
+/* pos 0218: 267 */    0xE9 /* 'i' -> */,
+/* pos 0219: 268 */    0xE5 /* 'e' -> */,
+/* pos 021a: 269 */    0xE4 /* 'd' -> */,
+/* pos 021b: 270 */    0xAD /* '-' -> */,
+/* pos 021c: 271 */    0xF3 /* 's' -> */,
+/* pos 021d: 272 */    0xE9 /* 'i' -> */,
+/* pos 021e: 273 */    0xEE /* 'n' -> */,
+/* pos 021f: 274 */    0xE3 /* 'c' -> */,
+/* pos 0220: 275 */    0xE5 /* 'e' -> */,
+/* pos 0221: 276 */    0xBA /* ':' -> */,
+/* pos 0222: 277 */    0x00, 0x2D                  /* - terminal marker 45 - */,
+/* pos 0224: 278 */    0x61 /* 'a' */, 0x0A, 0x00  /* (to 0x022E state 279) */,
+                       0x69 /* 'i' */, 0x15, 0x00  /* (to 0x023C state 292) */,
+                       0x6F /* 'o' */, 0x17, 0x00  /* (to 0x0241 state 296) */,
+                       0x08, /* fail */
+/* pos 022e: 279 */    0xF3 /* 's' -> */,
+/* pos 022f: 280 */    0xF4 /* 't' -> */,
+/* pos 0230: 281 */    0xAD /* '-' -> */,
+/* pos 0231: 282 */    0xED /* 'm' -> */,
+/* pos 0232: 283 */    0xEF /* 'o' -> */,
+/* pos 0233: 284 */    0xE4 /* 'd' -> */,
+/* pos 0234: 285 */    0xE9 /* 'i' -> */,
+/* pos 0235: 286 */    0xE6 /* 'f' -> */,
+/* pos 0236: 287 */    0xE9 /* 'i' -> */,
+/* pos 0237: 288 */    0xE5 /* 'e' -> */,
+/* pos 0238: 289 */    0xE4 /* 'd' -> */,
+/* pos 0239: 290 */    0xBA /* ':' -> */,
+/* pos 023a: 291 */    0x00, 0x2E                  /* - terminal marker 46 - */,
+/* pos 023c: 292 */    0xEE /* 'n' -> */,
+/* pos 023d: 293 */    0xEB /* 'k' -> */,
+/* pos 023e: 294 */    0xBA /* ':' -> */,
+/* pos 023f: 295 */    0x00, 0x2F                  /* - terminal marker 47 - */,
+/* pos 0241: 296 */    0xE3 /* 'c' -> */,
+/* pos 0242: 297 */    0xE1 /* 'a' -> */,
+/* pos 0243: 298 */    0xF4 /* 't' -> */,
+/* pos 0244: 299 */    0xE9 /* 'i' -> */,
+/* pos 0245: 300 */    0xEF /* 'o' -> */,
+/* pos 0246: 301 */    0xEE /* 'n' -> */,
+/* pos 0247: 302 */    0xBA /* ':' -> */,
+/* pos 0248: 303 */    0x00, 0x30                  /* - terminal marker 48 - */,
+/* pos 024a: 304 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x0254 state 305) */,
+                       0x74 /* 't' */, 0x14, 0x00  /* (to 0x0261 state 311) */,
+                       0x70 /* 'p' */, 0x88, 0x01  /* (to 0x03D8 state 596) */,
+                       0x08, /* fail */
+/* pos 0254: 305 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x025B state 306) */,
+                       0x65 /* 'e' */, 0xCA, 0x00  /* (to 0x0321 state 448) */,
+                       0x08, /* fail */
+/* pos 025b: 306 */    0xE5 /* 'e' -> */,
+/* pos 025c: 307 */    0xF3 /* 's' -> */,
+/* pos 025d: 308 */    0xE8 /* 'h' -> */,
+/* pos 025e: 309 */    0xBA /* ':' -> */,
+/* pos 025f: 310 */    0x00, 0x31                  /* - terminal marker 49 - */,
+/* pos 0261: 311 */    0xF2 /* 'r' -> */,
+/* pos 0262: 312 */    0xF9 /* 'y' -> */,
+/* pos 0263: 313 */    0xAD /* '-' -> */,
+/* pos 0264: 314 */    0xE1 /* 'a' -> */,
+/* pos 0265: 315 */    0xE6 /* 'f' -> */,
+/* pos 0266: 316 */    0xF4 /* 't' -> */,
+/* pos 0267: 317 */    0xE5 /* 'e' -> */,
+/* pos 0268: 318 */    0xF2 /* 'r' -> */,
+/* pos 0269: 319 */    0xBA /* ':' -> */,
+/* pos 026a: 320 */    0x00, 0x32                  /* - terminal marker 50 - */,
+/* pos 026c: 321 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0273 state 322) */,
+                       0x74 /* 't' */, 0x06, 0x01  /* (to 0x0375 state 514) */,
+                       0x08, /* fail */
+/* pos 0273: 322 */    0x72 /* 'r' */, 0x0A, 0x00  /* (to 0x027D state 323) */,
+                       0x74 /* 't' */, 0x0D, 0x00  /* (to 0x0283 state 328) */,
+                       0x63 /* 'c' */, 0x6B, 0x01  /* (to 0x03E4 state 607) */,
+                       0x08, /* fail */
+/* pos 027d: 323 */    0xF6 /* 'v' -> */,
+/* pos 027e: 324 */    0xE5 /* 'e' -> */,
+/* pos 027f: 325 */    0xF2 /* 'r' -> */,
+/* pos 0280: 326 */    0xBA /* ':' -> */,
+/* pos 0281: 327 */    0x00, 0x33                  /* - terminal marker 51 - */,
+/* pos 0283: 328 */    0xAD /* '-' -> */,
+/* pos 0284: 329 */    0xE3 /* 'c' -> */,
+/* pos 0285: 330 */    0xEF /* 'o' -> */,
+/* pos 0286: 331 */    0xEF /* 'o' -> */,
+/* pos 0287: 332 */    0xEB /* 'k' -> */,
+/* pos 0288: 333 */    0xE9 /* 'i' -> */,
+/* pos 0289: 334 */    0xE5 /* 'e' -> */,
+/* pos 028a: 335 */    0xBA /* ':' -> */,
+/* pos 028b: 336 */    0x00, 0x34                  /* - terminal marker 52 - */,
+/* pos 028d: 337 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0294 state 338) */,
+                       0x65 /* 'e' */, 0x45, 0x01  /* (to 0x03D5 state 594) */,
+                       0x08, /* fail */
+/* pos 0294: 338 */    0xE1 /* 'a' -> */,
+/* pos 0295: 339 */    0xEE /* 'n' -> */,
+/* pos 0296: 340 */    0xF3 /* 's' -> */,
+/* pos 0297: 341 */    0xE6 /* 'f' -> */,
+/* pos 0298: 342 */    0xE5 /* 'e' -> */,
+/* pos 0299: 343 */    0xF2 /* 'r' -> */,
+/* pos 029a: 344 */    0xAD /* '-' -> */,
+/* pos 029b: 345 */    0xE5 /* 'e' -> */,
+/* pos 029c: 346 */    0xEE /* 'n' -> */,
+/* pos 029d: 347 */    0xE3 /* 'c' -> */,
+/* pos 029e: 348 */    0xEF /* 'o' -> */,
+/* pos 029f: 349 */    0xE4 /* 'd' -> */,
+/* pos 02a0: 350 */    0xE9 /* 'i' -> */,
+/* pos 02a1: 351 */    0xEE /* 'n' -> */,
+/* pos 02a2: 352 */    0xE7 /* 'g' -> */,
+/* pos 02a3: 353 */    0xBA /* ':' -> */,
+/* pos 02a4: 354 */    0x00, 0x35                  /* - terminal marker 53 - */,
+/* pos 02a6: 355 */    0xE9 /* 'i' -> */,
+/* pos 02a7: 356 */    0xAD /* '-' -> */,
+/* pos 02a8: 357 */    0xE1 /* 'a' -> */,
+/* pos 02a9: 358 */    0xF2 /* 'r' -> */,
+/* pos 02aa: 359 */    0xE7 /* 'g' -> */,
+/* pos 02ab: 360 */    0xF3 /* 's' -> */,
+/* pos 02ac: 361 */    0x00, 0x36                  /* - terminal marker 54 - */,
+/* pos 02ae: 362 */    0xA0 /* ' ' -> */,
+/* pos 02af: 363 */    0x00, 0x37                  /* - terminal marker 55 - */,
+/* pos 02b1: 364 */    0xAD /* '-' -> */,
+/* pos 02b2: 365 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x02BC state 366) */,
+                       0x61 /* 'a' */, 0x1D, 0x00  /* (to 0x02D2 state 385) */,
+                       0x72 /* 'r' */, 0x14, 0x01  /* (to 0x03CC state 586) */,
+                       0x08, /* fail */
+/* pos 02bc: 366 */    0xEF /* 'o' -> */,
+/* pos 02bd: 367 */    0xF2 /* 'r' -> */,
+/* pos 02be: 368 */    0xF7 /* 'w' -> */,
+/* pos 02bf: 369 */    0xE1 /* 'a' -> */,
+/* pos 02c0: 370 */    0xF2 /* 'r' -> */,
+/* pos 02c1: 371 */    0xE4 /* 'd' -> */,
+/* pos 02c2: 372 */    0xE5 /* 'e' -> */,
+/* pos 02c3: 373 */    0xE4 /* 'd' -> */,
+/* pos 02c4: 374 */    0xAD /* '-' -> */,
+/* pos 02c5: 375 */    0xE6 /* 'f' -> */,
+/* pos 02c6: 376 */    0xEF /* 'o' -> */,
+/* pos 02c7: 377 */    0xF2 /* 'r' -> */,
+/* pos 02c8: 378 */    0xBA /* ':' -> */,
+/* pos 02c9: 379 */    0x00, 0x38                  /* - terminal marker 56 - */,
+/* pos 02cb: 380 */    0x00, 0x39                  /* - terminal marker 57 - */,
+/* pos 02cd: 381 */    0xE1 /* 'a' -> */,
+/* pos 02ce: 382 */    0xE4 /* 'd' -> */,
+/* pos 02cf: 383 */    0xA0 /* ' ' -> */,
+/* pos 02d0: 384 */    0x00, 0x3A                  /* - terminal marker 58 - */,
+/* pos 02d2: 385 */    0x75 /* 'u' */, 0x07, 0x00  /* (to 0x02D9 state 386) */,
+                       0x6D /* 'm' */, 0x0F, 0x00  /* (to 0x02E4 state 396) */,
+                       0x08, /* fail */
+/* pos 02d9: 386 */    0xF4 /* 't' -> */,
+/* pos 02da: 387 */    0xE8 /* 'h' -> */,
+/* pos 02db: 388 */    0xAD /* '-' -> */,
+/* pos 02dc: 389 */    0xF4 /* 't' -> */,
+/* pos 02dd: 390 */    0xEF /* 'o' -> */,
+/* pos 02de: 391 */    0xEB /* 'k' -> */,
+/* pos 02df: 392 */    0xE5 /* 'e' -> */,
+/* pos 02e0: 393 */    0xEE /* 'n' -> */,
+/* pos 02e1: 394 */    0xBA /* ':' -> */,
+/* pos 02e2: 395 */    0x00, 0x3B                  /* - terminal marker 59 - */,
+/* pos 02e4: 396 */    0xFA /* 'z' -> */,
+/* pos 02e5: 397 */    0xEE /* 'n' -> */,
+/* pos 02e6: 398 */    0xAD /* '-' -> */,
+/* pos 02e7: 399 */    0xE4 /* 'd' -> */,
+/* pos 02e8: 400 */    0xF3 /* 's' -> */,
+/* pos 02e9: 401 */    0xF3 /* 's' -> */,
+/* pos 02ea: 402 */    0xAD /* '-' -> */,
+/* pos 02eb: 403 */    0xF3 /* 's' -> */,
+/* pos 02ec: 404 */    0xE9 /* 'i' -> */,
+/* pos 02ed: 405 */    0xE7 /* 'g' -> */,
+/* pos 02ee: 406 */    0xEE /* 'n' -> */,
+/* pos 02ef: 407 */    0xE1 /* 'a' -> */,
+/* pos 02f0: 408 */    0xF4 /* 't' -> */,
+/* pos 02f1: 409 */    0xF5 /* 'u' -> */,
+/* pos 02f2: 410 */    0xF2 /* 'r' -> */,
+/* pos 02f3: 411 */    0xE5 /* 'e' -> */,
+/* pos 02f4: 412 */    0xBA /* ':' -> */,
+/* pos 02f5: 413 */    0x00, 0x3C                  /* - terminal marker 60 - */,
+/* pos 02f7: 414 */    0xF4 /* 't' -> */,
+/* pos 02f8: 415 */    0xE9 /* 'i' -> */,
+/* pos 02f9: 416 */    0xEF /* 'o' -> */,
+/* pos 02fa: 417 */    0xEE /* 'n' -> */,
+/* pos 02fb: 418 */    0xF3 /* 's' -> */,
+/* pos 02fc: 419 */    0xA0 /* ' ' -> */,
+/* pos 02fd: 420 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 02ff: 421 */    0xF3 /* 's' -> */,
+/* pos 0300: 422 */    0xAD /* '-' -> */,
+/* pos 0301: 423 */    0xE3 /* 'c' -> */,
+/* pos 0302: 424 */    0xEF /* 'o' -> */,
+/* pos 0303: 425 */    0xEE /* 'n' -> */,
+/* pos 0304: 426 */    0xF4 /* 't' -> */,
+/* pos 0305: 427 */    0xF2 /* 'r' -> */,
+/* pos 0306: 428 */    0xEF /* 'o' -> */,
+/* pos 0307: 429 */    0xEC /* 'l' -> */,
+/* pos 0308: 430 */    0xAD /* '-' -> */,
+/* pos 0309: 431 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0310 state 432) */,
+                       0x61 /* 'a' */, 0x24, 0x00  /* (to 0x0330 state 461) */,
+                       0x08, /* fail */
+/* pos 0310: 432 */    0xE5 /* 'e' -> */,
+/* pos 0311: 433 */    0xF1 /* 'q' -> */,
+/* pos 0312: 434 */    0xF5 /* 'u' -> */,
+/* pos 0313: 435 */    0xE5 /* 'e' -> */,
+/* pos 0314: 436 */    0xF3 /* 's' -> */,
+/* pos 0315: 437 */    0xF4 /* 't' -> */,
+/* pos 0316: 438 */    0xAD /* '-' -> */,
+/* pos 0317: 439 */    0xE8 /* 'h' -> */,
+/* pos 0318: 440 */    0xE5 /* 'e' -> */,
+/* pos 0319: 441 */    0xE1 /* 'a' -> */,
+/* pos 031a: 442 */    0xE4 /* 'd' -> */,
+/* pos 031b: 443 */    0xE5 /* 'e' -> */,
+/* pos 031c: 444 */    0xF2 /* 'r' -> */,
+/* pos 031d: 445 */    0xF3 /* 's' -> */,
+/* pos 031e: 446 */    0xBA /* ':' -> */,
+/* pos 031f: 447 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 0321: 448 */    0xF2 /* 'r' -> */,
+/* pos 0322: 449 */    0xE5 /* 'e' -> */,
+/* pos 0323: 450 */    0xF2 /* 'r' -> */,
+/* pos 0324: 451 */    0xBA /* ':' -> */,
+/* pos 0325: 452 */    0x00, 0x17                  /* - terminal marker 23 - */,
+/* pos 0327: 453 */    0xE8 /* 'h' -> */,
+/* pos 0328: 454 */    0xE1 /* 'a' -> */,
+/* pos 0329: 455 */    0xF2 /* 'r' -> */,
+/* pos 032a: 456 */    0xF3 /* 's' -> */,
+/* pos 032b: 457 */    0xE5 /* 'e' -> */,
+/* pos 032c: 458 */    0xF4 /* 't' -> */,
+/* pos 032d: 459 */    0xBA /* ':' -> */,
+/* pos 032e: 460 */    0x00, 0x18                  /* - terminal marker 24 - */,
+/* pos 0330: 461 */    0xEC /* 'l' -> */,
+/* pos 0331: 462 */    0xEC /* 'l' -> */,
+/* pos 0332: 463 */    0xEF /* 'o' -> */,
+/* pos 0333: 464 */    0xF7 /* 'w' -> */,
+/* pos 0334: 465 */    0xAD /* '-' -> */,
+/* pos 0335: 466 */    0xEF /* 'o' -> */,
+/* pos 0336: 467 */    0xF2 /* 'r' -> */,
+/* pos 0337: 468 */    0xE9 /* 'i' -> */,
+/* pos 0338: 469 */    0xE7 /* 'g' -> */,
+/* pos 0339: 470 */    0xE9 /* 'i' -> */,
+/* pos 033a: 471 */    0xEE /* 'n' -> */,
+/* pos 033b: 472 */    0xBA /* ':' -> */,
+/* pos 033c: 473 */    0x00, 0x1A                  /* - terminal marker 26 - */,
+/* pos 033e: 474 */    0xE1 /* 'a' -> */,
+/* pos 033f: 475 */    0xF8 /* 'x' -> */,
+/* pos 0340: 476 */    0xAD /* '-' -> */,
+/* pos 0341: 477 */    0xE6 /* 'f' -> */,
+/* pos 0342: 478 */    0xEF /* 'o' -> */,
+/* pos 0343: 479 */    0xF2 /* 'r' -> */,
+/* pos 0344: 480 */    0xF7 /* 'w' -> */,
+/* pos 0345: 481 */    0xE1 /* 'a' -> */,
+/* pos 0346: 482 */    0xF2 /* 'r' -> */,
+/* pos 0347: 483 */    0xE4 /* 'd' -> */,
+/* pos 0348: 484 */    0xF3 /* 's' -> */,
+/* pos 0349: 485 */    0xBA /* ':' -> */,
+/* pos 034a: 486 */    0x00, 0x2C                  /* - terminal marker 44 - */,
+/* pos 034c: 487 */    0xF8 /* 'x' -> */,
+/* pos 034d: 488 */    0xF9 /* 'y' -> */,
+/* pos 034e: 489 */    0x2D /* '-' */, 0x07, 0x00  /* (to 0x0355 state 490) */,
+                       0x20 /* ' ' */, 0x79, 0x00  /* (to 0x03CA state 585) */,
+                       0x08, /* fail */
+/* pos 0355: 490 */    0xE1 /* 'a' -> */,
+/* pos 0356: 491 */    0xF5 /* 'u' -> */,
+/* pos 0357: 492 */    0xF4 /* 't' -> */,
+/* pos 0358: 493 */    0xE8 /* 'h' -> */,
+/* pos 0359: 494 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0360 state 495) */,
+                       0x6F /* 'o' */, 0x0E, 0x00  /* (to 0x036A state 504) */,
+                       0x08, /* fail */
+/* pos 0360: 495 */    0xEE /* 'n' -> */,
+/* pos 0361: 496 */    0xF4 /* 't' -> */,
+/* pos 0362: 497 */    0xE9 /* 'i' -> */,
+/* pos 0363: 498 */    0xE3 /* 'c' -> */,
+/* pos 0364: 499 */    0xE1 /* 'a' -> */,
+/* pos 0365: 500 */    0xF4 /* 't' -> */,
+/* pos 0366: 501 */    0xE5 /* 'e' -> */,
+/* pos 0367: 502 */    0xBA /* ':' -> */,
+/* pos 0368: 503 */    0x00, 0x2D                  /* - terminal marker 45 - */,
+/* pos 036a: 504 */    0xF2 /* 'r' -> */,
+/* pos 036b: 505 */    0xE9 /* 'i' -> */,
+/* pos 036c: 506 */    0xFA /* 'z' -> */,
+/* pos 036d: 507 */    0xE1 /* 'a' -> */,
+/* pos 036e: 508 */    0xF4 /* 't' -> */,
+/* pos 036f: 509 */    0xE9 /* 'i' -> */,
+/* pos 0370: 510 */    0xEF /* 'o' -> */,
+/* pos 0371: 511 */    0xEE /* 'n' -> */,
+/* pos 0372: 512 */    0xBA /* ':' -> */,
+/* pos 0373: 513 */    0x00, 0x2E                  /* - terminal marker 46 - */,
+/* pos 0375: 514 */    0xF2 /* 'r' -> */,
+/* pos 0376: 515 */    0xE9 /* 'i' -> */,
+/* pos 0377: 516 */    0xE3 /* 'c' -> */,
+/* pos 0378: 517 */    0xF4 /* 't' -> */,
+/* pos 0379: 518 */    0xAD /* '-' -> */,
+/* pos 037a: 519 */    0xF4 /* 't' -> */,
+/* pos 037b: 520 */    0xF2 /* 'r' -> */,
+/* pos 037c: 521 */    0xE1 /* 'a' -> */,
+/* pos 037d: 522 */    0xEE /* 'n' -> */,
+/* pos 037e: 523 */    0xF3 /* 's' -> */,
+/* pos 037f: 524 */    0xF0 /* 'p' -> */,
+/* pos 0380: 525 */    0xEF /* 'o' -> */,
+/* pos 0381: 526 */    0xF2 /* 'r' -> */,
+/* pos 0382: 527 */    0xF4 /* 't' -> */,
+/* pos 0383: 528 */    0xAD /* '-' -> */,
+/* pos 0384: 529 */    0xF3 /* 's' -> */,
+/* pos 0385: 530 */    0xE5 /* 'e' -> */,
+/* pos 0386: 531 */    0xE3 /* 'c' -> */,
+/* pos 0387: 532 */    0xF5 /* 'u' -> */,
+/* pos 0388: 533 */    0xF2 /* 'r' -> */,
+/* pos 0389: 534 */    0xE9 /* 'i' -> */,
+/* pos 038a: 535 */    0xF4 /* 't' -> */,
+/* pos 038b: 536 */    0xF9 /* 'y' -> */,
+/* pos 038c: 537 */    0xBA /* ':' -> */,
+/* pos 038d: 538 */    0x00, 0x33                  /* - terminal marker 51 - */,
+/* pos 038f: 539 */    0xE5 /* 'e' -> */,
+/* pos 0390: 540 */    0xF2 /* 'r' -> */,
+/* pos 0391: 541 */    0xAD /* '-' -> */,
+/* pos 0392: 542 */    0xE1 /* 'a' -> */,
+/* pos 0393: 543 */    0xE7 /* 'g' -> */,
+/* pos 0394: 544 */    0xE5 /* 'e' -> */,
+/* pos 0395: 545 */    0xEE /* 'n' -> */,
+/* pos 0396: 546 */    0xF4 /* 't' -> */,
+/* pos 0397: 547 */    0xBA /* ':' -> */,
+/* pos 0398: 548 */    0x00, 0x35                  /* - terminal marker 53 - */,
+/* pos 039a: 549 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x03A1 state 550) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x03A6 state 554) */,
+                       0x08, /* fail */
+/* pos 03a1: 550 */    0xF2 /* 'r' -> */,
+/* pos 03a2: 551 */    0xF9 /* 'y' -> */,
+/* pos 03a3: 552 */    0xBA /* ':' -> */,
+/* pos 03a4: 553 */    0x00, 0x36                  /* - terminal marker 54 - */,
+/* pos 03a6: 554 */    0xE1 /* 'a' -> */,
+/* pos 03a7: 555 */    0xBA /* ':' -> */,
+/* pos 03a8: 556 */    0x00, 0x37                  /* - terminal marker 55 - */,
+/* pos 03aa: 557 */    0xF7 /* 'w' -> */,
+/* pos 03ab: 558 */    0xF7 /* 'w' -> */,
+/* pos 03ac: 559 */    0xAD /* '-' -> */,
+/* pos 03ad: 560 */    0xE1 /* 'a' -> */,
+/* pos 03ae: 561 */    0xF5 /* 'u' -> */,
+/* pos 03af: 562 */    0xF4 /* 't' -> */,
+/* pos 03b0: 563 */    0xE8 /* 'h' -> */,
+/* pos 03b1: 564 */    0xE5 /* 'e' -> */,
+/* pos 03b2: 565 */    0xEE /* 'n' -> */,
+/* pos 03b3: 566 */    0xF4 /* 't' -> */,
+/* pos 03b4: 567 */    0xE9 /* 'i' -> */,
+/* pos 03b5: 568 */    0xE3 /* 'c' -> */,
+/* pos 03b6: 569 */    0xE1 /* 'a' -> */,
+/* pos 03b7: 570 */    0xF4 /* 't' -> */,
+/* pos 03b8: 571 */    0xE5 /* 'e' -> */,
+/* pos 03b9: 572 */    0xBA /* ':' -> */,
+/* pos 03ba: 573 */    0x00, 0x38                  /* - terminal marker 56 - */,
+/* pos 03bc: 574 */    0xF4 /* 't' -> */,
+/* pos 03bd: 575 */    0xE3 /* 'c' -> */,
+/* pos 03be: 576 */    0xE8 /* 'h' -> */,
+/* pos 03bf: 577 */    0x00, 0x39                  /* - terminal marker 57 - */,
+/* pos 03c1: 578 */    0xF4 /* 't' -> */,
+/* pos 03c2: 579 */    0x00, 0x3A                  /* - terminal marker 58 - */,
+/* pos 03c4: 580 */    0xEC /* 'l' -> */,
+/* pos 03c5: 581 */    0xE5 /* 'e' -> */,
+/* pos 03c6: 582 */    0xF4 /* 't' -> */,
+/* pos 03c7: 583 */    0xE5 /* 'e' -> */,
+/* pos 03c8: 584 */    0x00, 0x3B                  /* - terminal marker 59 - */,
+/* pos 03ca: 585 */    0x00, 0x3D                  /* - terminal marker 61 - */,
+/* pos 03cc: 586 */    0xE5 /* 'e' -> */,
+/* pos 03cd: 587 */    0xE1 /* 'a' -> */,
+/* pos 03ce: 588 */    0xEC /* 'l' -> */,
+/* pos 03cf: 589 */    0xAD /* '-' -> */,
+/* pos 03d0: 590 */    0xE9 /* 'i' -> */,
+/* pos 03d1: 591 */    0xF0 /* 'p' -> */,
+/* pos 03d2: 592 */    0xBA /* ':' -> */,
+/* pos 03d3: 593 */    0x00, 0x3E                  /* - terminal marker 62 - */,
+/* pos 03d5: 594 */    0xBA /* ':' -> */,
+/* pos 03d6: 595 */    0x00, 0x43                  /* - terminal marker 67 - */,
+/* pos 03d8: 596 */    0xEC /* 'l' -> */,
+/* pos 03d9: 597 */    0xE1 /* 'a' -> */,
+/* pos 03da: 598 */    0xF9 /* 'y' -> */,
+/* pos 03db: 599 */    0xAD /* '-' -> */,
+/* pos 03dc: 600 */    0xEE /* 'n' -> */,
+/* pos 03dd: 601 */    0xEF /* 'o' -> */,
+/* pos 03de: 602 */    0xEE /* 'n' -> */,
+/* pos 03df: 603 */    0xE3 /* 'c' -> */,
+/* pos 03e0: 604 */    0xE5 /* 'e' -> */,
+/* pos 03e1: 605 */    0xBA /* ':' -> */,
+/* pos 03e2: 606 */    0x00, 0x44                  /* - terminal marker 68 - */,
+/* pos 03e4: 607 */    0xAD /* '-' -> */,
+/* pos 03e5: 608 */    0xF7 /* 'w' -> */,
+/* pos 03e6: 609 */    0xE5 /* 'e' -> */,
+/* pos 03e7: 610 */    0xE2 /* 'b' -> */,
+/* pos 03e8: 611 */    0xF3 /* 's' -> */,
+/* pos 03e9: 612 */    0xEF /* 'o' -> */,
+/* pos 03ea: 613 */    0xE3 /* 'c' -> */,
+/* pos 03eb: 614 */    0xEB /* 'k' -> */,
+/* pos 03ec: 615 */    0xE5 /* 'e' -> */,
+/* pos 03ed: 616 */    0xF4 /* 't' -> */,
+/* pos 03ee: 617 */    0xAD /* '-' -> */,
+/* pos 03ef: 618 */    0x64 /* 'd' */, 0x19, 0x00  /* (to 0x0408 state 619) */,
+                       0x65 /* 'e' */, 0x1D, 0x00  /* (to 0x040F state 625) */,
+                       0x6B /* 'k' */, 0x26, 0x00  /* (to 0x041B state 636) */,
+                       0x70 /* 'p' */, 0x35, 0x00  /* (to 0x042D state 643) */,
+                       0x61 /* 'a' */, 0x3C, 0x00  /* (to 0x0437 state 652) */,
+                       0x6E /* 'n' */, 0x41, 0x00  /* (to 0x043F state 659) */,
+                       0x76 /* 'v' */, 0x47, 0x00  /* (to 0x0448 state 666) */,
+                       0x6F /* 'o' */, 0x4D, 0x00  /* (to 0x0451 state 674) */,
+                       0x08, /* fail */
+/* pos 0408: 619 */    0xF2 /* 'r' -> */,
+/* pos 0409: 620 */    0xE1 /* 'a' -> */,
+/* pos 040a: 621 */    0xE6 /* 'f' -> */,
+/* pos 040b: 622 */    0xF4 /* 't' -> */,
+/* pos 040c: 623 */    0xBA /* ':' -> */,
+/* pos 040d: 624 */    0x00, 0x06                  /* - terminal marker  6 - */,
+/* pos 040f: 625 */    0xF8 /* 'x' -> */,
+/* pos 0410: 626 */    0xF4 /* 't' -> */,
+/* pos 0411: 627 */    0xE5 /* 'e' -> */,
+/* pos 0412: 628 */    0xEE /* 'n' -> */,
+/* pos 0413: 629 */    0xF3 /* 's' -> */,
+/* pos 0414: 630 */    0xE9 /* 'i' -> */,
+/* pos 0415: 631 */    0xEF /* 'o' -> */,
+/* pos 0416: 632 */    0xEE /* 'n' -> */,
+/* pos 0417: 633 */    0xF3 /* 's' -> */,
+/* pos 0418: 634 */    0xBA /* ':' -> */,
+/* pos 0419: 635 */    0x00, 0x08                  /* - terminal marker  8 - */,
+/* pos 041b: 636 */    0xE5 /* 'e' -> */,
+/* pos 041c: 637 */    0xF9 /* 'y' -> */,
+/* pos 041d: 638 */    0x31 /* '1' */, 0x0A, 0x00  /* (to 0x0427 state 639) */,
+                       0x32 /* '2' */, 0x0A, 0x00  /* (to 0x042A state 641) */,
+                       0x3A /* ':' */, 0x23, 0x00  /* (to 0x0446 state 665) */,
+                       0x08, /* fail */
+/* pos 0427: 639 */    0xBA /* ':' -> */,
+/* pos 0428: 640 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 042a: 641 */    0xBA /* ':' -> */,
+/* pos 042b: 642 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 042d: 643 */    0xF2 /* 'r' -> */,
+/* pos 042e: 644 */    0xEF /* 'o' -> */,
+/* pos 042f: 645 */    0xF4 /* 't' -> */,
+/* pos 0430: 646 */    0xEF /* 'o' -> */,
+/* pos 0431: 647 */    0xE3 /* 'c' -> */,
+/* pos 0432: 648 */    0xEF /* 'o' -> */,
+/* pos 0433: 649 */    0xEC /* 'l' -> */,
+/* pos 0434: 650 */    0xBA /* ':' -> */,
+/* pos 0435: 651 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 0437: 652 */    0xE3 /* 'c' -> */,
+/* pos 0438: 653 */    0xE3 /* 'c' -> */,
+/* pos 0439: 654 */    0xE5 /* 'e' -> */,
+/* pos 043a: 655 */    0xF0 /* 'p' -> */,
+/* pos 043b: 656 */    0xF4 /* 't' -> */,
+/* pos 043c: 657 */    0xBA /* ':' -> */,
+/* pos 043d: 658 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 043f: 659 */    0xEF /* 'o' -> */,
+/* pos 0440: 660 */    0xEE /* 'n' -> */,
+/* pos 0441: 661 */    0xE3 /* 'c' -> */,
+/* pos 0442: 662 */    0xE5 /* 'e' -> */,
+/* pos 0443: 663 */    0xBA /* ':' -> */,
+/* pos 0444: 664 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 0446: 665 */    0x00, 0x1C                  /* - terminal marker 28 - */,
+/* pos 0448: 666 */    0xE5 /* 'e' -> */,
+/* pos 0449: 667 */    0xF2 /* 'r' -> */,
+/* pos 044a: 668 */    0xF3 /* 's' -> */,
+/* pos 044b: 669 */    0xE9 /* 'i' -> */,
+/* pos 044c: 670 */    0xEF /* 'o' -> */,
+/* pos 044d: 671 */    0xEE /* 'n' -> */,
+/* pos 044e: 672 */    0xBA /* ':' -> */,
+/* pos 044f: 673 */    0x00, 0x1D                  /* - terminal marker 29 - */,
+/* pos 0451: 674 */    0xF2 /* 'r' -> */,
+/* pos 0452: 675 */    0xE9 /* 'i' -> */,
+/* pos 0453: 676 */    0xE7 /* 'g' -> */,
+/* pos 0454: 677 */    0xE9 /* 'i' -> */,
+/* pos 0455: 678 */    0xEE /* 'n' -> */,
+/* pos 0456: 679 */    0xBA /* ':' -> */,
+/* pos 0457: 680 */    0x00, 0x1E                  /* - terminal marker 30 - */,
+/* total size 1113 bytes */
+#endif
+
+#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+       /* 0: 0: get  */
+       /* 1: 1: post  */
+       /* 2: 2: options  */
+       /* 3: 3: host: */
+       /* 4: 4: connection: */
+       /* 5: 5: upgrade: */
+       /* 6: 6: origin: */
+       /* 7: 7: sec-websocket-draft: */
+       /* 8: 8: \r
+ */
+       /* 9: 9: sec-websocket-extensions: */
+       /* 10: 10: sec-websocket-key1: */
+       /* 11: 11: sec-websocket-key2: */
+       /* 12: 12: sec-websocket-protocol: */
+       /* 13: 13: sec-websocket-accept: */
+       /* 14: 14: sec-websocket-nonce: */
+       /* 15: 15: http/1.1  */
+       /* 16: 17: accept: */
+       /* 17: 18: access-control-request-headers: */
+       /* 18: 19: if-modified-since: */
+       /* 19: 20: if-none-match: */
+       /* 20: 21: accept-encoding: */
+       /* 21: 22: accept-language: */
+       /* 22: 23: pragma: */
+       /* 23: 24: cache-control: */
+       /* 24: 25: authorization: */
+       /* 25: 26: cookie: */
+       /* 26: 27: content-length: */
+       /* 27: 28: content-type: */
+       /* 28: 29: date: */
+       /* 29: 30: range: */
+       /* 30: 31: referer: */
+       /* 31: 32: sec-websocket-key: */
+       /* 32: 33: sec-websocket-version: */
+       /* 33: 34: sec-websocket-origin: */
+       /* 34: 40: accept-charset: */
+       /* 35: 41: accept-ranges: */
+       /* 36: 42: access-control-allow-origin: */
+       /* 37: 43: age: */
+       /* 38: 44: allow: */
+       /* 39: 45: content-disposition: */
+       /* 40: 46: content-encoding: */
+       /* 41: 47: content-language: */
+       /* 42: 48: content-location: */
+       /* 43: 49: content-range: */
+       /* 44: 50: etag: */
+       /* 45: 51: expect: */
+       /* 46: 52: expires: */
+       /* 47: 53: from: */
+       /* 48: 54: if-match: */
+       /* 49: 55: if-range: */
+       /* 50: 56: if-unmodified-since: */
+       /* 51: 57: last-modified: */
+       /* 52: 58: link: */
+       /* 53: 59: location: */
+       /* 54: 60: max-forwards: */
+       /* 55: 61: proxy-authenticate: */
+       /* 56: 62: proxy-authorization: */
+       /* 57: 63: refresh: */
+       /* 58: 64: retry-after: */
+       /* 59: 65: server: */
+       /* 60: 66: set-cookie: */
+       /* 61: 67: strict-transport-security: */
+       /* 62: 68: transfer-encoding: */
+       /* 63: 69: user-agent: */
+       /* 64: 70: vary: */
+       /* 65: 71: via: */
+       /* 66: 72: www-authenticate: */
+       /* 67: 73: patch */
+       /* 68: 74: put */
+       /* 69: 75: delete */
+       /* 70: 76: uri-args */
+       /* 71: 77: proxy  */
+       /* 72: 78: x-real-ip: */
+       /* 73: 79: http/1.0  */
+       /* 74: 80: x-forwarded-for: */
+       /* 75: 81: connect  */
+       /* 76: 82: head  */
+       /* 77: 83: te: */
+       /* 78: 84: replay-nonce: */
+       /* 79: 86: x-auth-token: */
+       /* 80: 87: x-amzn-dss-signature: */
+/* pos 0000:   0 */    0x67 /* 'g' */, 0x3D, 0x00  /* (to 0x003D state   1) */,
+                       0x70 /* 'p' */, 0x3F, 0x00  /* (to 0x0042 state   5) */,
+                       0x68 /* 'h' */, 0x4E, 0x00  /* (to 0x0054 state  10) */,
+                       0x63 /* 'c' */, 0x5A, 0x00  /* (to 0x0063 state  15) */,
+                       0x75 /* 'u' */, 0x7B, 0x00  /* (to 0x0087 state  26) */,
+                       0x6F /* 'o' */, 0x8A, 0x00  /* (to 0x0099 state  34) */,
+                       0x0D /* '.' */, 0x95, 0x00  /* (to 0x00A7 state  41) */,
+                       0x61 /* 'a' */, 0xA4, 0x00  /* (to 0x00B9 state  51) */,
+                       0x69 /* 'i' */, 0xC1, 0x00  /* (to 0x00D9 state  58) */,
+                       0x64 /* 'd' */, 0x6A, 0x01  /* (to 0x0185 state 160) */,
+                       0x72 /* 'r' */, 0x73, 0x01  /* (to 0x0191 state 165) */,
+                       0x65 /* 'e' */, 0xBF, 0x01  /* (to 0x01E0 state 229) */,
+                       0x66 /* 'f' */, 0xDB, 0x01  /* (to 0x01FF state 245) */,
+                       0x6C /* 'l' */, 0xFD, 0x01  /* (to 0x0224 state 278) */,
+                       0x73 /* 's' */, 0x42, 0x02  /* (to 0x026C state 321) */,
+                       0x74 /* 't' */, 0x60, 0x02  /* (to 0x028D state 337) */,
+                       0x78 /* 'x' */, 0x81, 0x02  /* (to 0x02B1 state 364) */,
+                       0x6D /* 'm' */, 0x0B, 0x03  /* (to 0x033E state 474) */,
+                       0x76 /* 'v' */, 0x64, 0x03  /* (to 0x039A state 549) */,
+                       0x77 /* 'w' */, 0x71, 0x03  /* (to 0x03AA state 557) */,
+                       0x08, /* fail */
+/* pos 003d:   1 */    0xE5 /* 'e' -> */,
+/* pos 003e:   2 */    0xF4 /* 't' -> */,
+/* pos 003f:   3 */    0xA0 /* ' ' -> */,
+/* pos 0040:   4 */    0x00, 0x00                  /* - terminal marker  0 - */,
+/* pos 0042:   5 */    0x6F /* 'o' */, 0x0D, 0x00  /* (to 0x004F state   6) */,
+                       0x72 /* 'r' */, 0xE6, 0x00  /* (to 0x012B state 106) */,
+                       0x61 /* 'a' */, 0x74, 0x03  /* (to 0x03BC state 574) */,
+                       0x75 /* 'u' */, 0x76, 0x03  /* (to 0x03C1 state 578) */,
+                       0x08, /* fail */
+/* pos 004f:   6 */    0xF3 /* 's' -> */,
+/* pos 0050:   7 */    0xF4 /* 't' -> */,
+/* pos 0051:   8 */    0xA0 /* ' ' -> */,
+/* pos 0052:   9 */    0x00, 0x01                  /* - terminal marker  1 - */,
+/* pos 0054:  10 */    0x6F /* 'o' */, 0x0A, 0x00  /* (to 0x005E state  11) */,
+                       0x74 /* 't' */, 0x53, 0x00  /* (to 0x00AA state  43) */,
+                       0x65 /* 'e' */, 0x73, 0x02  /* (to 0x02CD state 381) */,
+                       0x08, /* fail */
+/* pos 005e:  11 */    0xF3 /* 's' -> */,
+/* pos 005f:  12 */    0xF4 /* 't' -> */,
+/* pos 0060:  13 */    0xBA /* ':' -> */,
+/* pos 0061:  14 */    0x00, 0x03                  /* - terminal marker  3 - */,
+/* pos 0063:  15 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x006A state  16) */,
+                       0x61 /* 'a' */, 0xD2, 0x00  /* (to 0x0138 state 112) */,
+                       0x08, /* fail */
+/* pos 006a:  16 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0071 state  17) */,
+                       0x6F /* 'o' */, 0xE7, 0x00  /* (to 0x0154 state 138) */,
+                       0x08, /* fail */
+/* pos 0071:  17 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0078 state  18) */,
+                       0x74 /* 't' */, 0xE6, 0x00  /* (to 0x015A state 143) */,
+                       0x08, /* fail */
+/* pos 0078:  18 */    0xE5 /* 'e' -> */,
+/* pos 0079:  19 */    0xE3 /* 'c' -> */,
+/* pos 007a:  20 */    0xF4 /* 't' -> */,
+/* pos 007b:  21 */    0x69 /* 'i' */, 0x07, 0x00  /* (to 0x0082 state  22) */,
+                       0x20 /* ' ' */, 0x4D, 0x02  /* (to 0x02CB state 380) */,
+                       0x08, /* fail */
+/* pos 0082:  22 */    0xEF /* 'o' -> */,
+/* pos 0083:  23 */    0xEE /* 'n' -> */,
+/* pos 0084:  24 */    0xBA /* ':' -> */,
+/* pos 0085:  25 */    0x00, 0x04                  /* - terminal marker  4 - */,
+/* pos 0087:  26 */    0x70 /* 'p' */, 0x0A, 0x00  /* (to 0x0091 state  27) */,
+                       0x72 /* 'r' */, 0x1C, 0x02  /* (to 0x02A6 state 355) */,
+                       0x73 /* 's' */, 0x02, 0x03  /* (to 0x038F state 539) */,
+                       0x08, /* fail */
+/* pos 0091:  27 */    0xE7 /* 'g' -> */,
+/* pos 0092:  28 */    0xF2 /* 'r' -> */,
+/* pos 0093:  29 */    0xE1 /* 'a' -> */,
+/* pos 0094:  30 */    0xE4 /* 'd' -> */,
+/* pos 0095:  31 */    0xE5 /* 'e' -> */,
+/* pos 0096:  32 */    0xBA /* ':' -> */,
+/* pos 0097:  33 */    0x00, 0x05                  /* - terminal marker  5 - */,
+/* pos 0099:  34 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x00A0 state  35) */,
+                       0x70 /* 'p' */, 0x5B, 0x02  /* (to 0x02F7 state 414) */,
+                       0x08, /* fail */
+/* pos 00a0:  35 */    0xE9 /* 'i' -> */,
+/* pos 00a1:  36 */    0xE7 /* 'g' -> */,
+/* pos 00a2:  37 */    0xE9 /* 'i' -> */,
+/* pos 00a3:  38 */    0xEE /* 'n' -> */,
+/* pos 00a4:  39 */    0xBA /* ':' -> */,
+/* pos 00a5:  40 */    0x00, 0x06                  /* - terminal marker  6 - */,
+/* pos 00a7:  41 */    0x8A /* '.' -> */,
+/* pos 00a8:  42 */    0x00, 0x08                  /* - terminal marker  8 - */,
+/* pos 00aa:  43 */    0xF4 /* 't' -> */,
+/* pos 00ab:  44 */    0xF0 /* 'p' -> */,
+/* pos 00ac:  45 */    0xAF /* '/' -> */,
+/* pos 00ad:  46 */    0xB1 /* '1' -> */,
+/* pos 00ae:  47 */    0xAE /* '.' -> */,
+/* pos 00af:  48 */    0x31 /* '1' */, 0x07, 0x00  /* (to 0x00B6 state  49) */,
+                       0x30 /* '0' */, 0xFC, 0x01  /* (to 0x02AE state 362) */,
+                       0x08, /* fail */
+/* pos 00b6:  49 */    0xA0 /* ' ' -> */,
+/* pos 00b7:  50 */    0x00, 0x0F                  /* - terminal marker 15 - */,
+/* pos 00b9:  51 */    0x63 /* 'c' */, 0x0D, 0x00  /* (to 0x00C6 state  52) */,
+                       0x75 /* 'u' */, 0x8A, 0x00  /* (to 0x0146 state 125) */,
+                       0x67 /* 'g' */, 0xE7, 0x00  /* (to 0x01A6 state 178) */,
+                       0x6C /* 'l' */, 0xE8, 0x00  /* (to 0x01AA state 181) */,
+                       0x08, /* fail */
+/* pos 00c6:  52 */    0xE3 /* 'c' -> */,
+/* pos 00c7:  53 */    0xE5 /* 'e' -> */,
+/* pos 00c8:  54 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x00CF state  55) */,
+                       0x73 /* 's' */, 0x34, 0x02  /* (to 0x02FF state 421) */,
+                       0x08, /* fail */
+/* pos 00cf:  55 */    0xF4 /* 't' -> */,
+/* pos 00d0:  56 */    0x3A /* ':' */, 0x07, 0x00  /* (to 0x00D7 state  57) */,
+                       0x2D /* '-' */, 0x37, 0x00  /* (to 0x010A state  87) */,
+                       0x08, /* fail */
+/* pos 00d7:  57 */    0x00, 0x10                  /* - terminal marker 16 - */,
+/* pos 00d9:  58 */    0xE6 /* 'f' -> */,
+/* pos 00da:  59 */    0xAD /* '-' -> */,
+/* pos 00db:  60 */    0x6D /* 'm' */, 0x0D, 0x00  /* (to 0x00E8 state  61) */,
+                       0x6E /* 'n' */, 0x20, 0x00  /* (to 0x00FE state  76) */,
+                       0x72 /* 'r' */, 0x2A, 0x01  /* (to 0x020B state 255) */,
+                       0x75 /* 'u' */, 0x2E, 0x01  /* (to 0x0212 state 261) */,
+                       0x08, /* fail */
+/* pos 00e8:  61 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x00EF state  62) */,
+                       0x61 /* 'a' */, 0x1A, 0x01  /* (to 0x0205 state 250) */,
+                       0x08, /* fail */
+/* pos 00ef:  62 */    0xE4 /* 'd' -> */,
+/* pos 00f0:  63 */    0xE9 /* 'i' -> */,
+/* pos 00f1:  64 */    0xE6 /* 'f' -> */,
+/* pos 00f2:  65 */    0xE9 /* 'i' -> */,
+/* pos 00f3:  66 */    0xE5 /* 'e' -> */,
+/* pos 00f4:  67 */    0xE4 /* 'd' -> */,
+/* pos 00f5:  68 */    0xAD /* '-' -> */,
+/* pos 00f6:  69 */    0xF3 /* 's' -> */,
+/* pos 00f7:  70 */    0xE9 /* 'i' -> */,
+/* pos 00f8:  71 */    0xEE /* 'n' -> */,
+/* pos 00f9:  72 */    0xE3 /* 'c' -> */,
+/* pos 00fa:  73 */    0xE5 /* 'e' -> */,
+/* pos 00fb:  74 */    0xBA /* ':' -> */,
+/* pos 00fc:  75 */    0x00, 0x12                  /* - terminal marker 18 - */,
+/* pos 00fe:  76 */    0xEF /* 'o' -> */,
+/* pos 00ff:  77 */    0xEE /* 'n' -> */,
+/* pos 0100:  78 */    0xE5 /* 'e' -> */,
+/* pos 0101:  79 */    0xAD /* '-' -> */,
+/* pos 0102:  80 */    0xED /* 'm' -> */,
+/* pos 0103:  81 */    0xE1 /* 'a' -> */,
+/* pos 0104:  82 */    0xF4 /* 't' -> */,
+/* pos 0105:  83 */    0xE3 /* 'c' -> */,
+/* pos 0106:  84 */    0xE8 /* 'h' -> */,
+/* pos 0107:  85 */    0xBA /* ':' -> */,
+/* pos 0108:  86 */    0x00, 0x13                  /* - terminal marker 19 - */,
+/* pos 010a:  87 */    0x65 /* 'e' */, 0x0D, 0x00  /* (to 0x0117 state  88) */,
+                       0x6C /* 'l' */, 0x14, 0x00  /* (to 0x0121 state  97) */,
+                       0x72 /* 'r' */, 0x8E, 0x00  /* (to 0x019E state 171) */,
+                       0x63 /* 'c' */, 0x14, 0x02  /* (to 0x0327 state 453) */,
+                       0x08, /* fail */
+/* pos 0117:  88 */    0xEE /* 'n' -> */,
+/* pos 0118:  89 */    0xE3 /* 'c' -> */,
+/* pos 0119:  90 */    0xEF /* 'o' -> */,
+/* pos 011a:  91 */    0xE4 /* 'd' -> */,
+/* pos 011b:  92 */    0xE9 /* 'i' -> */,
+/* pos 011c:  93 */    0xEE /* 'n' -> */,
+/* pos 011d:  94 */    0xE7 /* 'g' -> */,
+/* pos 011e:  95 */    0xBA /* ':' -> */,
+/* pos 011f:  96 */    0x00, 0x14                  /* - terminal marker 20 - */,
+/* pos 0121:  97 */    0xE1 /* 'a' -> */,
+/* pos 0122:  98 */    0xEE /* 'n' -> */,
+/* pos 0123:  99 */    0xE7 /* 'g' -> */,
+/* pos 0124: 100 */    0xF5 /* 'u' -> */,
+/* pos 0125: 101 */    0xE1 /* 'a' -> */,
+/* pos 0126: 102 */    0xE7 /* 'g' -> */,
+/* pos 0127: 103 */    0xE5 /* 'e' -> */,
+/* pos 0128: 104 */    0xBA /* ':' -> */,
+/* pos 0129: 105 */    0x00, 0x15                  /* - terminal marker 21 - */,
+/* pos 012b: 106 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0132 state 107) */,
+                       0x6F /* 'o' */, 0x1E, 0x02  /* (to 0x034C state 487) */,
+                       0x08, /* fail */
+/* pos 0132: 107 */    0xE7 /* 'g' -> */,
+/* pos 0133: 108 */    0xED /* 'm' -> */,
+/* pos 0134: 109 */    0xE1 /* 'a' -> */,
+/* pos 0135: 110 */    0xBA /* ':' -> */,
+/* pos 0136: 111 */    0x00, 0x16                  /* - terminal marker 22 - */,
+/* pos 0138: 112 */    0xE3 /* 'c' -> */,
+/* pos 0139: 113 */    0xE8 /* 'h' -> */,
+/* pos 013a: 114 */    0xE5 /* 'e' -> */,
+/* pos 013b: 115 */    0xAD /* '-' -> */,
+/* pos 013c: 116 */    0xE3 /* 'c' -> */,
+/* pos 013d: 117 */    0xEF /* 'o' -> */,
+/* pos 013e: 118 */    0xEE /* 'n' -> */,
+/* pos 013f: 119 */    0xF4 /* 't' -> */,
+/* pos 0140: 120 */    0xF2 /* 'r' -> */,
+/* pos 0141: 121 */    0xEF /* 'o' -> */,
+/* pos 0142: 122 */    0xEC /* 'l' -> */,
+/* pos 0143: 123 */    0xBA /* ':' -> */,
+/* pos 0144: 124 */    0x00, 0x17                  /* - terminal marker 23 - */,
+/* pos 0146: 125 */    0xF4 /* 't' -> */,
+/* pos 0147: 126 */    0xE8 /* 'h' -> */,
+/* pos 0148: 127 */    0xEF /* 'o' -> */,
+/* pos 0149: 128 */    0xF2 /* 'r' -> */,
+/* pos 014a: 129 */    0xE9 /* 'i' -> */,
+/* pos 014b: 130 */    0xFA /* 'z' -> */,
+/* pos 014c: 131 */    0xE1 /* 'a' -> */,
+/* pos 014d: 132 */    0xF4 /* 't' -> */,
+/* pos 014e: 133 */    0xE9 /* 'i' -> */,
+/* pos 014f: 134 */    0xEF /* 'o' -> */,
+/* pos 0150: 135 */    0xEE /* 'n' -> */,
+/* pos 0151: 136 */    0xBA /* ':' -> */,
+/* pos 0152: 137 */    0x00, 0x18                  /* - terminal marker 24 - */,
+/* pos 0154: 138 */    0xEB /* 'k' -> */,
+/* pos 0155: 139 */    0xE9 /* 'i' -> */,
+/* pos 0156: 140 */    0xE5 /* 'e' -> */,
+/* pos 0157: 141 */    0xBA /* ':' -> */,
+/* pos 0158: 142 */    0x00, 0x19                  /* - terminal marker 25 - */,
+/* pos 015a: 143 */    0xE5 /* 'e' -> */,
+/* pos 015b: 144 */    0xEE /* 'n' -> */,
+/* pos 015c: 145 */    0xF4 /* 't' -> */,
+/* pos 015d: 146 */    0xAD /* '-' -> */,
+/* pos 015e: 147 */    0x6C /* 'l' */, 0x10, 0x00  /* (to 0x016E state 148) */,
+                       0x74 /* 't' */, 0x1E, 0x00  /* (to 0x017F state 155) */,
+                       0x64 /* 'd' */, 0x4C, 0x00  /* (to 0x01B0 state 186) */,
+                       0x65 /* 'e' */, 0x56, 0x00  /* (to 0x01BD state 198) */,
+                       0x72 /* 'r' */, 0x6F, 0x00  /* (to 0x01D9 state 223) */,
+                       0x08, /* fail */
+/* pos 016e: 148 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x0178 state 149) */,
+                       0x61 /* 'a' */, 0x56, 0x00  /* (to 0x01C7 state 207) */,
+                       0x6F /* 'o' */, 0x5C, 0x00  /* (to 0x01D0 state 215) */,
+                       0x08, /* fail */
+/* pos 0178: 149 */    0xEE /* 'n' -> */,
+/* pos 0179: 150 */    0xE7 /* 'g' -> */,
+/* pos 017a: 151 */    0xF4 /* 't' -> */,
+/* pos 017b: 152 */    0xE8 /* 'h' -> */,
+/* pos 017c: 153 */    0xBA /* ':' -> */,
+/* pos 017d: 154 */    0x00, 0x1A                  /* - terminal marker 26 - */,
+/* pos 017f: 155 */    0xF9 /* 'y' -> */,
+/* pos 0180: 156 */    0xF0 /* 'p' -> */,
+/* pos 0181: 157 */    0xE5 /* 'e' -> */,
+/* pos 0182: 158 */    0xBA /* ':' -> */,
+/* pos 0183: 159 */    0x00, 0x1B                  /* - terminal marker 27 - */,
+/* pos 0185: 160 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x018C state 161) */,
+                       0x65 /* 'e' */, 0x3C, 0x02  /* (to 0x03C4 state 580) */,
+                       0x08, /* fail */
+/* pos 018c: 161 */    0xF4 /* 't' -> */,
+/* pos 018d: 162 */    0xE5 /* 'e' -> */,
+/* pos 018e: 163 */    0xBA /* ':' -> */,
+/* pos 018f: 164 */    0x00, 0x1C                  /* - terminal marker 28 - */,
+/* pos 0191: 165 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0198 state 166) */,
+                       0x65 /* 'e' */, 0xB6, 0x00  /* (to 0x024A state 304) */,
+                       0x08, /* fail */
+/* pos 0198: 166 */    0xEE /* 'n' -> */,
+/* pos 0199: 167 */    0xE7 /* 'g' -> */,
+/* pos 019a: 168 */    0xE5 /* 'e' -> */,
+/* pos 019b: 169 */    0xBA /* ':' -> */,
+/* pos 019c: 170 */    0x00, 0x1D                  /* - terminal marker 29 - */,
+/* pos 019e: 171 */    0xE1 /* 'a' -> */,
+/* pos 019f: 172 */    0xEE /* 'n' -> */,
+/* pos 01a0: 173 */    0xE7 /* 'g' -> */,
+/* pos 01a1: 174 */    0xE5 /* 'e' -> */,
+/* pos 01a2: 175 */    0xF3 /* 's' -> */,
+/* pos 01a3: 176 */    0xBA /* ':' -> */,
+/* pos 01a4: 177 */    0x00, 0x23                  /* - terminal marker 35 - */,
+/* pos 01a6: 178 */    0xE5 /* 'e' -> */,
+/* pos 01a7: 179 */    0xBA /* ':' -> */,
+/* pos 01a8: 180 */    0x00, 0x25                  /* - terminal marker 37 - */,
+/* pos 01aa: 181 */    0xEC /* 'l' -> */,
+/* pos 01ab: 182 */    0xEF /* 'o' -> */,
+/* pos 01ac: 183 */    0xF7 /* 'w' -> */,
+/* pos 01ad: 184 */    0xBA /* ':' -> */,
+/* pos 01ae: 185 */    0x00, 0x26                  /* - terminal marker 38 - */,
+/* pos 01b0: 186 */    0xE9 /* 'i' -> */,
+/* pos 01b1: 187 */    0xF3 /* 's' -> */,
+/* pos 01b2: 188 */    0xF0 /* 'p' -> */,
+/* pos 01b3: 189 */    0xEF /* 'o' -> */,
+/* pos 01b4: 190 */    0xF3 /* 's' -> */,
+/* pos 01b5: 191 */    0xE9 /* 'i' -> */,
+/* pos 01b6: 192 */    0xF4 /* 't' -> */,
+/* pos 01b7: 193 */    0xE9 /* 'i' -> */,
+/* pos 01b8: 194 */    0xEF /* 'o' -> */,
+/* pos 01b9: 195 */    0xEE /* 'n' -> */,
+/* pos 01ba: 196 */    0xBA /* ':' -> */,
+/* pos 01bb: 197 */    0x00, 0x27                  /* - terminal marker 39 - */,
+/* pos 01bd: 198 */    0xEE /* 'n' -> */,
+/* pos 01be: 199 */    0xE3 /* 'c' -> */,
+/* pos 01bf: 200 */    0xEF /* 'o' -> */,
+/* pos 01c0: 201 */    0xE4 /* 'd' -> */,
+/* pos 01c1: 202 */    0xE9 /* 'i' -> */,
+/* pos 01c2: 203 */    0xEE /* 'n' -> */,
+/* pos 01c3: 204 */    0xE7 /* 'g' -> */,
+/* pos 01c4: 205 */    0xBA /* ':' -> */,
+/* pos 01c5: 206 */    0x00, 0x28                  /* - terminal marker 40 - */,
+/* pos 01c7: 207 */    0xEE /* 'n' -> */,
+/* pos 01c8: 208 */    0xE7 /* 'g' -> */,
+/* pos 01c9: 209 */    0xF5 /* 'u' -> */,
+/* pos 01ca: 210 */    0xE1 /* 'a' -> */,
+/* pos 01cb: 211 */    0xE7 /* 'g' -> */,
+/* pos 01cc: 212 */    0xE5 /* 'e' -> */,
+/* pos 01cd: 213 */    0xBA /* ':' -> */,
+/* pos 01ce: 214 */    0x00, 0x29                  /* - terminal marker 41 - */,
+/* pos 01d0: 215 */    0xE3 /* 'c' -> */,
+/* pos 01d1: 216 */    0xE1 /* 'a' -> */,
+/* pos 01d2: 217 */    0xF4 /* 't' -> */,
+/* pos 01d3: 218 */    0xE9 /* 'i' -> */,
+/* pos 01d4: 219 */    0xEF /* 'o' -> */,
+/* pos 01d5: 220 */    0xEE /* 'n' -> */,
+/* pos 01d6: 221 */    0xBA /* ':' -> */,
+/* pos 01d7: 222 */    0x00, 0x2A                  /* - terminal marker 42 - */,
+/* pos 01d9: 223 */    0xE1 /* 'a' -> */,
+/* pos 01da: 224 */    0xEE /* 'n' -> */,
+/* pos 01db: 225 */    0xE7 /* 'g' -> */,
+/* pos 01dc: 226 */    0xE5 /* 'e' -> */,
+/* pos 01dd: 227 */    0xBA /* ':' -> */,
+/* pos 01de: 228 */    0x00, 0x2B                  /* - terminal marker 43 - */,
+/* pos 01e0: 229 */    0x74 /* 't' */, 0x07, 0x00  /* (to 0x01E7 state 230) */,
+                       0x78 /* 'x' */, 0x09, 0x00  /* (to 0x01EC state 234) */,
+                       0x08, /* fail */
+/* pos 01e7: 230 */    0xE1 /* 'a' -> */,
+/* pos 01e8: 231 */    0xE7 /* 'g' -> */,
+/* pos 01e9: 232 */    0xBA /* ':' -> */,
+/* pos 01ea: 233 */    0x00, 0x2C                  /* - terminal marker 44 - */,
+/* pos 01ec: 234 */    0xF0 /* 'p' -> */,
+/* pos 01ed: 235 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x01F4 state 236) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x01F9 state 240) */,
+                       0x08, /* fail */
+/* pos 01f4: 236 */    0xE3 /* 'c' -> */,
+/* pos 01f5: 237 */    0xF4 /* 't' -> */,
+/* pos 01f6: 238 */    0xBA /* ':' -> */,
+/* pos 01f7: 239 */    0x00, 0x2D                  /* - terminal marker 45 - */,
+/* pos 01f9: 240 */    0xF2 /* 'r' -> */,
+/* pos 01fa: 241 */    0xE5 /* 'e' -> */,
+/* pos 01fb: 242 */    0xF3 /* 's' -> */,
+/* pos 01fc: 243 */    0xBA /* ':' -> */,
+/* pos 01fd: 244 */    0x00, 0x2E                  /* - terminal marker 46 - */,
+/* pos 01ff: 245 */    0xF2 /* 'r' -> */,
+/* pos 0200: 246 */    0xEF /* 'o' -> */,
+/* pos 0201: 247 */    0xED /* 'm' -> */,
+/* pos 0202: 248 */    0xBA /* ':' -> */,
+/* pos 0203: 249 */    0x00, 0x2F                  /* - terminal marker 47 - */,
+/* pos 0205: 250 */    0xF4 /* 't' -> */,
+/* pos 0206: 251 */    0xE3 /* 'c' -> */,
+/* pos 0207: 252 */    0xE8 /* 'h' -> */,
+/* pos 0208: 253 */    0xBA /* ':' -> */,
+/* pos 0209: 254 */    0x00, 0x30                  /* - terminal marker 48 - */,
+/* pos 020b: 255 */    0xE1 /* 'a' -> */,
+/* pos 020c: 256 */    0xEE /* 'n' -> */,
+/* pos 020d: 257 */    0xE7 /* 'g' -> */,
+/* pos 020e: 258 */    0xE5 /* 'e' -> */,
+/* pos 020f: 259 */    0xBA /* ':' -> */,
+/* pos 0210: 260 */    0x00, 0x31                  /* - terminal marker 49 - */,
+/* pos 0212: 261 */    0xEE /* 'n' -> */,
+/* pos 0213: 262 */    0xED /* 'm' -> */,
+/* pos 0214: 263 */    0xEF /* 'o' -> */,
+/* pos 0215: 264 */    0xE4 /* 'd' -> */,
+/* pos 0216: 265 */    0xE9 /* 'i' -> */,
+/* pos 0217: 266 */    0xE6 /* 'f' -> */,
+/* pos 0218: 267 */    0xE9 /* 'i' -> */,
+/* pos 0219: 268 */    0xE5 /* 'e' -> */,
+/* pos 021a: 269 */    0xE4 /* 'd' -> */,
+/* pos 021b: 270 */    0xAD /* '-' -> */,
+/* pos 021c: 271 */    0xF3 /* 's' -> */,
+/* pos 021d: 272 */    0xE9 /* 'i' -> */,
+/* pos 021e: 273 */    0xEE /* 'n' -> */,
+/* pos 021f: 274 */    0xE3 /* 'c' -> */,
+/* pos 0220: 275 */    0xE5 /* 'e' -> */,
+/* pos 0221: 276 */    0xBA /* ':' -> */,
+/* pos 0222: 277 */    0x00, 0x32                  /* - terminal marker 50 - */,
+/* pos 0224: 278 */    0x61 /* 'a' */, 0x0A, 0x00  /* (to 0x022E state 279) */,
+                       0x69 /* 'i' */, 0x15, 0x00  /* (to 0x023C state 292) */,
+                       0x6F /* 'o' */, 0x17, 0x00  /* (to 0x0241 state 296) */,
+                       0x08, /* fail */
+/* pos 022e: 279 */    0xF3 /* 's' -> */,
+/* pos 022f: 280 */    0xF4 /* 't' -> */,
+/* pos 0230: 281 */    0xAD /* '-' -> */,
+/* pos 0231: 282 */    0xED /* 'm' -> */,
+/* pos 0232: 283 */    0xEF /* 'o' -> */,
+/* pos 0233: 284 */    0xE4 /* 'd' -> */,
+/* pos 0234: 285 */    0xE9 /* 'i' -> */,
+/* pos 0235: 286 */    0xE6 /* 'f' -> */,
+/* pos 0236: 287 */    0xE9 /* 'i' -> */,
+/* pos 0237: 288 */    0xE5 /* 'e' -> */,
+/* pos 0238: 289 */    0xE4 /* 'd' -> */,
+/* pos 0239: 290 */    0xBA /* ':' -> */,
+/* pos 023a: 291 */    0x00, 0x33                  /* - terminal marker 51 - */,
+/* pos 023c: 292 */    0xEE /* 'n' -> */,
+/* pos 023d: 293 */    0xEB /* 'k' -> */,
+/* pos 023e: 294 */    0xBA /* ':' -> */,
+/* pos 023f: 295 */    0x00, 0x34                  /* - terminal marker 52 - */,
+/* pos 0241: 296 */    0xE3 /* 'c' -> */,
+/* pos 0242: 297 */    0xE1 /* 'a' -> */,
+/* pos 0243: 298 */    0xF4 /* 't' -> */,
+/* pos 0244: 299 */    0xE9 /* 'i' -> */,
+/* pos 0245: 300 */    0xEF /* 'o' -> */,
+/* pos 0246: 301 */    0xEE /* 'n' -> */,
+/* pos 0247: 302 */    0xBA /* ':' -> */,
+/* pos 0248: 303 */    0x00, 0x35                  /* - terminal marker 53 - */,
+/* pos 024a: 304 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x0254 state 305) */,
+                       0x74 /* 't' */, 0x14, 0x00  /* (to 0x0261 state 311) */,
+                       0x70 /* 'p' */, 0x88, 0x01  /* (to 0x03D8 state 596) */,
+                       0x08, /* fail */
+/* pos 0254: 305 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x025B state 306) */,
+                       0x65 /* 'e' */, 0xCA, 0x00  /* (to 0x0321 state 448) */,
+                       0x08, /* fail */
+/* pos 025b: 306 */    0xE5 /* 'e' -> */,
+/* pos 025c: 307 */    0xF3 /* 's' -> */,
+/* pos 025d: 308 */    0xE8 /* 'h' -> */,
+/* pos 025e: 309 */    0xBA /* ':' -> */,
+/* pos 025f: 310 */    0x00, 0x39                  /* - terminal marker 57 - */,
+/* pos 0261: 311 */    0xF2 /* 'r' -> */,
+/* pos 0262: 312 */    0xF9 /* 'y' -> */,
+/* pos 0263: 313 */    0xAD /* '-' -> */,
+/* pos 0264: 314 */    0xE1 /* 'a' -> */,
+/* pos 0265: 315 */    0xE6 /* 'f' -> */,
+/* pos 0266: 316 */    0xF4 /* 't' -> */,
+/* pos 0267: 317 */    0xE5 /* 'e' -> */,
+/* pos 0268: 318 */    0xF2 /* 'r' -> */,
+/* pos 0269: 319 */    0xBA /* ':' -> */,
+/* pos 026a: 320 */    0x00, 0x3A                  /* - terminal marker 58 - */,
+/* pos 026c: 321 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0273 state 322) */,
+                       0x74 /* 't' */, 0x06, 0x01  /* (to 0x0375 state 514) */,
+                       0x08, /* fail */
+/* pos 0273: 322 */    0x72 /* 'r' */, 0x0A, 0x00  /* (to 0x027D state 323) */,
+                       0x74 /* 't' */, 0x0D, 0x00  /* (to 0x0283 state 328) */,
+                       0x63 /* 'c' */, 0x6B, 0x01  /* (to 0x03E4 state 607) */,
+                       0x08, /* fail */
+/* pos 027d: 323 */    0xF6 /* 'v' -> */,
+/* pos 027e: 324 */    0xE5 /* 'e' -> */,
+/* pos 027f: 325 */    0xF2 /* 'r' -> */,
+/* pos 0280: 326 */    0xBA /* ':' -> */,
+/* pos 0281: 327 */    0x00, 0x3B                  /* - terminal marker 59 - */,
+/* pos 0283: 328 */    0xAD /* '-' -> */,
+/* pos 0284: 329 */    0xE3 /* 'c' -> */,
+/* pos 0285: 330 */    0xEF /* 'o' -> */,
+/* pos 0286: 331 */    0xEF /* 'o' -> */,
+/* pos 0287: 332 */    0xEB /* 'k' -> */,
+/* pos 0288: 333 */    0xE9 /* 'i' -> */,
+/* pos 0289: 334 */    0xE5 /* 'e' -> */,
+/* pos 028a: 335 */    0xBA /* ':' -> */,
+/* pos 028b: 336 */    0x00, 0x3C                  /* - terminal marker 60 - */,
+/* pos 028d: 337 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0294 state 338) */,
+                       0x65 /* 'e' */, 0x45, 0x01  /* (to 0x03D5 state 594) */,
+                       0x08, /* fail */
+/* pos 0294: 338 */    0xE1 /* 'a' -> */,
+/* pos 0295: 339 */    0xEE /* 'n' -> */,
+/* pos 0296: 340 */    0xF3 /* 's' -> */,
+/* pos 0297: 341 */    0xE6 /* 'f' -> */,
+/* pos 0298: 342 */    0xE5 /* 'e' -> */,
+/* pos 0299: 343 */    0xF2 /* 'r' -> */,
+/* pos 029a: 344 */    0xAD /* '-' -> */,
+/* pos 029b: 345 */    0xE5 /* 'e' -> */,
+/* pos 029c: 346 */    0xEE /* 'n' -> */,
+/* pos 029d: 347 */    0xE3 /* 'c' -> */,
+/* pos 029e: 348 */    0xEF /* 'o' -> */,
+/* pos 029f: 349 */    0xE4 /* 'd' -> */,
+/* pos 02a0: 350 */    0xE9 /* 'i' -> */,
+/* pos 02a1: 351 */    0xEE /* 'n' -> */,
+/* pos 02a2: 352 */    0xE7 /* 'g' -> */,
+/* pos 02a3: 353 */    0xBA /* ':' -> */,
+/* pos 02a4: 354 */    0x00, 0x3E                  /* - terminal marker 62 - */,
+/* pos 02a6: 355 */    0xE9 /* 'i' -> */,
+/* pos 02a7: 356 */    0xAD /* '-' -> */,
+/* pos 02a8: 357 */    0xE1 /* 'a' -> */,
+/* pos 02a9: 358 */    0xF2 /* 'r' -> */,
+/* pos 02aa: 359 */    0xE7 /* 'g' -> */,
+/* pos 02ab: 360 */    0xF3 /* 's' -> */,
+/* pos 02ac: 361 */    0x00, 0x46                  /* - terminal marker 70 - */,
+/* pos 02ae: 362 */    0xA0 /* ' ' -> */,
+/* pos 02af: 363 */    0x00, 0x49                  /* - terminal marker 73 - */,
+/* pos 02b1: 364 */    0xAD /* '-' -> */,
+/* pos 02b2: 365 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x02BC state 366) */,
+                       0x61 /* 'a' */, 0x1D, 0x00  /* (to 0x02D2 state 385) */,
+                       0x72 /* 'r' */, 0x14, 0x01  /* (to 0x03CC state 586) */,
+                       0x08, /* fail */
+/* pos 02bc: 366 */    0xEF /* 'o' -> */,
+/* pos 02bd: 367 */    0xF2 /* 'r' -> */,
+/* pos 02be: 368 */    0xF7 /* 'w' -> */,
+/* pos 02bf: 369 */    0xE1 /* 'a' -> */,
+/* pos 02c0: 370 */    0xF2 /* 'r' -> */,
+/* pos 02c1: 371 */    0xE4 /* 'd' -> */,
+/* pos 02c2: 372 */    0xE5 /* 'e' -> */,
+/* pos 02c3: 373 */    0xE4 /* 'd' -> */,
+/* pos 02c4: 374 */    0xAD /* '-' -> */,
+/* pos 02c5: 375 */    0xE6 /* 'f' -> */,
+/* pos 02c6: 376 */    0xEF /* 'o' -> */,
+/* pos 02c7: 377 */    0xF2 /* 'r' -> */,
+/* pos 02c8: 378 */    0xBA /* ':' -> */,
+/* pos 02c9: 379 */    0x00, 0x4A                  /* - terminal marker 74 - */,
+/* pos 02cb: 380 */    0x00, 0x4B                  /* - terminal marker 75 - */,
+/* pos 02cd: 381 */    0xE1 /* 'a' -> */,
+/* pos 02ce: 382 */    0xE4 /* 'd' -> */,
+/* pos 02cf: 383 */    0xA0 /* ' ' -> */,
+/* pos 02d0: 384 */    0x00, 0x4C                  /* - terminal marker 76 - */,
+/* pos 02d2: 385 */    0x75 /* 'u' */, 0x07, 0x00  /* (to 0x02D9 state 386) */,
+                       0x6D /* 'm' */, 0x0F, 0x00  /* (to 0x02E4 state 396) */,
+                       0x08, /* fail */
+/* pos 02d9: 386 */    0xF4 /* 't' -> */,
+/* pos 02da: 387 */    0xE8 /* 'h' -> */,
+/* pos 02db: 388 */    0xAD /* '-' -> */,
+/* pos 02dc: 389 */    0xF4 /* 't' -> */,
+/* pos 02dd: 390 */    0xEF /* 'o' -> */,
+/* pos 02de: 391 */    0xEB /* 'k' -> */,
+/* pos 02df: 392 */    0xE5 /* 'e' -> */,
+/* pos 02e0: 393 */    0xEE /* 'n' -> */,
+/* pos 02e1: 394 */    0xBA /* ':' -> */,
+/* pos 02e2: 395 */    0x00, 0x4F                  /* - terminal marker 79 - */,
+/* pos 02e4: 396 */    0xFA /* 'z' -> */,
+/* pos 02e5: 397 */    0xEE /* 'n' -> */,
+/* pos 02e6: 398 */    0xAD /* '-' -> */,
+/* pos 02e7: 399 */    0xE4 /* 'd' -> */,
+/* pos 02e8: 400 */    0xF3 /* 's' -> */,
+/* pos 02e9: 401 */    0xF3 /* 's' -> */,
+/* pos 02ea: 402 */    0xAD /* '-' -> */,
+/* pos 02eb: 403 */    0xF3 /* 's' -> */,
+/* pos 02ec: 404 */    0xE9 /* 'i' -> */,
+/* pos 02ed: 405 */    0xE7 /* 'g' -> */,
+/* pos 02ee: 406 */    0xEE /* 'n' -> */,
+/* pos 02ef: 407 */    0xE1 /* 'a' -> */,
+/* pos 02f0: 408 */    0xF4 /* 't' -> */,
+/* pos 02f1: 409 */    0xF5 /* 'u' -> */,
+/* pos 02f2: 410 */    0xF2 /* 'r' -> */,
+/* pos 02f3: 411 */    0xE5 /* 'e' -> */,
+/* pos 02f4: 412 */    0xBA /* ':' -> */,
+/* pos 02f5: 413 */    0x00, 0x50                  /* - terminal marker 80 - */,
+/* pos 02f7: 414 */    0xF4 /* 't' -> */,
+/* pos 02f8: 415 */    0xE9 /* 'i' -> */,
+/* pos 02f9: 416 */    0xEF /* 'o' -> */,
+/* pos 02fa: 417 */    0xEE /* 'n' -> */,
+/* pos 02fb: 418 */    0xF3 /* 's' -> */,
+/* pos 02fc: 419 */    0xA0 /* ' ' -> */,
+/* pos 02fd: 420 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 02ff: 421 */    0xF3 /* 's' -> */,
+/* pos 0300: 422 */    0xAD /* '-' -> */,
+/* pos 0301: 423 */    0xE3 /* 'c' -> */,
+/* pos 0302: 424 */    0xEF /* 'o' -> */,
+/* pos 0303: 425 */    0xEE /* 'n' -> */,
+/* pos 0304: 426 */    0xF4 /* 't' -> */,
+/* pos 0305: 427 */    0xF2 /* 'r' -> */,
+/* pos 0306: 428 */    0xEF /* 'o' -> */,
+/* pos 0307: 429 */    0xEC /* 'l' -> */,
+/* pos 0308: 430 */    0xAD /* '-' -> */,
+/* pos 0309: 431 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0310 state 432) */,
+                       0x61 /* 'a' */, 0x24, 0x00  /* (to 0x0330 state 461) */,
+                       0x08, /* fail */
+/* pos 0310: 432 */    0xE5 /* 'e' -> */,
+/* pos 0311: 433 */    0xF1 /* 'q' -> */,
+/* pos 0312: 434 */    0xF5 /* 'u' -> */,
+/* pos 0313: 435 */    0xE5 /* 'e' -> */,
+/* pos 0314: 436 */    0xF3 /* 's' -> */,
+/* pos 0315: 437 */    0xF4 /* 't' -> */,
+/* pos 0316: 438 */    0xAD /* '-' -> */,
+/* pos 0317: 439 */    0xE8 /* 'h' -> */,
+/* pos 0318: 440 */    0xE5 /* 'e' -> */,
+/* pos 0319: 441 */    0xE1 /* 'a' -> */,
+/* pos 031a: 442 */    0xE4 /* 'd' -> */,
+/* pos 031b: 443 */    0xE5 /* 'e' -> */,
+/* pos 031c: 444 */    0xF2 /* 'r' -> */,
+/* pos 031d: 445 */    0xF3 /* 's' -> */,
+/* pos 031e: 446 */    0xBA /* ':' -> */,
+/* pos 031f: 447 */    0x00, 0x11                  /* - terminal marker 17 - */,
+/* pos 0321: 448 */    0xF2 /* 'r' -> */,
+/* pos 0322: 449 */    0xE5 /* 'e' -> */,
+/* pos 0323: 450 */    0xF2 /* 'r' -> */,
+/* pos 0324: 451 */    0xBA /* ':' -> */,
+/* pos 0325: 452 */    0x00, 0x1E                  /* - terminal marker 30 - */,
+/* pos 0327: 453 */    0xE8 /* 'h' -> */,
+/* pos 0328: 454 */    0xE1 /* 'a' -> */,
+/* pos 0329: 455 */    0xF2 /* 'r' -> */,
+/* pos 032a: 456 */    0xF3 /* 's' -> */,
+/* pos 032b: 457 */    0xE5 /* 'e' -> */,
+/* pos 032c: 458 */    0xF4 /* 't' -> */,
+/* pos 032d: 459 */    0xBA /* ':' -> */,
+/* pos 032e: 460 */    0x00, 0x22                  /* - terminal marker 34 - */,
+/* pos 0330: 461 */    0xEC /* 'l' -> */,
+/* pos 0331: 462 */    0xEC /* 'l' -> */,
+/* pos 0332: 463 */    0xEF /* 'o' -> */,
+/* pos 0333: 464 */    0xF7 /* 'w' -> */,
+/* pos 0334: 465 */    0xAD /* '-' -> */,
+/* pos 0335: 466 */    0xEF /* 'o' -> */,
+/* pos 0336: 467 */    0xF2 /* 'r' -> */,
+/* pos 0337: 468 */    0xE9 /* 'i' -> */,
+/* pos 0338: 469 */    0xE7 /* 'g' -> */,
+/* pos 0339: 470 */    0xE9 /* 'i' -> */,
+/* pos 033a: 471 */    0xEE /* 'n' -> */,
+/* pos 033b: 472 */    0xBA /* ':' -> */,
+/* pos 033c: 473 */    0x00, 0x24                  /* - terminal marker 36 - */,
+/* pos 033e: 474 */    0xE1 /* 'a' -> */,
+/* pos 033f: 475 */    0xF8 /* 'x' -> */,
+/* pos 0340: 476 */    0xAD /* '-' -> */,
+/* pos 0341: 477 */    0xE6 /* 'f' -> */,
+/* pos 0342: 478 */    0xEF /* 'o' -> */,
+/* pos 0343: 479 */    0xF2 /* 'r' -> */,
+/* pos 0344: 480 */    0xF7 /* 'w' -> */,
+/* pos 0345: 481 */    0xE1 /* 'a' -> */,
+/* pos 0346: 482 */    0xF2 /* 'r' -> */,
+/* pos 0347: 483 */    0xE4 /* 'd' -> */,
+/* pos 0348: 484 */    0xF3 /* 's' -> */,
+/* pos 0349: 485 */    0xBA /* ':' -> */,
+/* pos 034a: 486 */    0x00, 0x36                  /* - terminal marker 54 - */,
+/* pos 034c: 487 */    0xF8 /* 'x' -> */,
+/* pos 034d: 488 */    0xF9 /* 'y' -> */,
+/* pos 034e: 489 */    0x2D /* '-' */, 0x07, 0x00  /* (to 0x0355 state 490) */,
+                       0x20 /* ' ' */, 0x79, 0x00  /* (to 0x03CA state 585) */,
+                       0x08, /* fail */
+/* pos 0355: 490 */    0xE1 /* 'a' -> */,
+/* pos 0356: 491 */    0xF5 /* 'u' -> */,
+/* pos 0357: 492 */    0xF4 /* 't' -> */,
+/* pos 0358: 493 */    0xE8 /* 'h' -> */,
+/* pos 0359: 494 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0360 state 495) */,
+                       0x6F /* 'o' */, 0x0E, 0x00  /* (to 0x036A state 504) */,
+                       0x08, /* fail */
+/* pos 0360: 495 */    0xEE /* 'n' -> */,
+/* pos 0361: 496 */    0xF4 /* 't' -> */,
+/* pos 0362: 497 */    0xE9 /* 'i' -> */,
+/* pos 0363: 498 */    0xE3 /* 'c' -> */,
+/* pos 0364: 499 */    0xE1 /* 'a' -> */,
+/* pos 0365: 500 */    0xF4 /* 't' -> */,
+/* pos 0366: 501 */    0xE5 /* 'e' -> */,
+/* pos 0367: 502 */    0xBA /* ':' -> */,
+/* pos 0368: 503 */    0x00, 0x37                  /* - terminal marker 55 - */,
+/* pos 036a: 504 */    0xF2 /* 'r' -> */,
+/* pos 036b: 505 */    0xE9 /* 'i' -> */,
+/* pos 036c: 506 */    0xFA /* 'z' -> */,
+/* pos 036d: 507 */    0xE1 /* 'a' -> */,
+/* pos 036e: 508 */    0xF4 /* 't' -> */,
+/* pos 036f: 509 */    0xE9 /* 'i' -> */,
+/* pos 0370: 510 */    0xEF /* 'o' -> */,
+/* pos 0371: 511 */    0xEE /* 'n' -> */,
+/* pos 0372: 512 */    0xBA /* ':' -> */,
+/* pos 0373: 513 */    0x00, 0x38                  /* - terminal marker 56 - */,
+/* pos 0375: 514 */    0xF2 /* 'r' -> */,
+/* pos 0376: 515 */    0xE9 /* 'i' -> */,
+/* pos 0377: 516 */    0xE3 /* 'c' -> */,
+/* pos 0378: 517 */    0xF4 /* 't' -> */,
+/* pos 0379: 518 */    0xAD /* '-' -> */,
+/* pos 037a: 519 */    0xF4 /* 't' -> */,
+/* pos 037b: 520 */    0xF2 /* 'r' -> */,
+/* pos 037c: 521 */    0xE1 /* 'a' -> */,
+/* pos 037d: 522 */    0xEE /* 'n' -> */,
+/* pos 037e: 523 */    0xF3 /* 's' -> */,
+/* pos 037f: 524 */    0xF0 /* 'p' -> */,
+/* pos 0380: 525 */    0xEF /* 'o' -> */,
+/* pos 0381: 526 */    0xF2 /* 'r' -> */,
+/* pos 0382: 527 */    0xF4 /* 't' -> */,
+/* pos 0383: 528 */    0xAD /* '-' -> */,
+/* pos 0384: 529 */    0xF3 /* 's' -> */,
+/* pos 0385: 530 */    0xE5 /* 'e' -> */,
+/* pos 0386: 531 */    0xE3 /* 'c' -> */,
+/* pos 0387: 532 */    0xF5 /* 'u' -> */,
+/* pos 0388: 533 */    0xF2 /* 'r' -> */,
+/* pos 0389: 534 */    0xE9 /* 'i' -> */,
+/* pos 038a: 535 */    0xF4 /* 't' -> */,
+/* pos 038b: 536 */    0xF9 /* 'y' -> */,
+/* pos 038c: 537 */    0xBA /* ':' -> */,
+/* pos 038d: 538 */    0x00, 0x3D                  /* - terminal marker 61 - */,
+/* pos 038f: 539 */    0xE5 /* 'e' -> */,
+/* pos 0390: 540 */    0xF2 /* 'r' -> */,
+/* pos 0391: 541 */    0xAD /* '-' -> */,
+/* pos 0392: 542 */    0xE1 /* 'a' -> */,
+/* pos 0393: 543 */    0xE7 /* 'g' -> */,
+/* pos 0394: 544 */    0xE5 /* 'e' -> */,
+/* pos 0395: 545 */    0xEE /* 'n' -> */,
+/* pos 0396: 546 */    0xF4 /* 't' -> */,
+/* pos 0397: 547 */    0xBA /* ':' -> */,
+/* pos 0398: 548 */    0x00, 0x3F                  /* - terminal marker 63 - */,
+/* pos 039a: 549 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x03A1 state 550) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x03A6 state 554) */,
+                       0x08, /* fail */
+/* pos 03a1: 550 */    0xF2 /* 'r' -> */,
+/* pos 03a2: 551 */    0xF9 /* 'y' -> */,
+/* pos 03a3: 552 */    0xBA /* ':' -> */,
+/* pos 03a4: 553 */    0x00, 0x40                  /* - terminal marker 64 - */,
+/* pos 03a6: 554 */    0xE1 /* 'a' -> */,
+/* pos 03a7: 555 */    0xBA /* ':' -> */,
+/* pos 03a8: 556 */    0x00, 0x41                  /* - terminal marker 65 - */,
+/* pos 03aa: 557 */    0xF7 /* 'w' -> */,
+/* pos 03ab: 558 */    0xF7 /* 'w' -> */,
+/* pos 03ac: 559 */    0xAD /* '-' -> */,
+/* pos 03ad: 560 */    0xE1 /* 'a' -> */,
+/* pos 03ae: 561 */    0xF5 /* 'u' -> */,
+/* pos 03af: 562 */    0xF4 /* 't' -> */,
+/* pos 03b0: 563 */    0xE8 /* 'h' -> */,
+/* pos 03b1: 564 */    0xE5 /* 'e' -> */,
+/* pos 03b2: 565 */    0xEE /* 'n' -> */,
+/* pos 03b3: 566 */    0xF4 /* 't' -> */,
+/* pos 03b4: 567 */    0xE9 /* 'i' -> */,
+/* pos 03b5: 568 */    0xE3 /* 'c' -> */,
+/* pos 03b6: 569 */    0xE1 /* 'a' -> */,
+/* pos 03b7: 570 */    0xF4 /* 't' -> */,
+/* pos 03b8: 571 */    0xE5 /* 'e' -> */,
+/* pos 03b9: 572 */    0xBA /* ':' -> */,
+/* pos 03ba: 573 */    0x00, 0x42                  /* - terminal marker 66 - */,
+/* pos 03bc: 574 */    0xF4 /* 't' -> */,
+/* pos 03bd: 575 */    0xE3 /* 'c' -> */,
+/* pos 03be: 576 */    0xE8 /* 'h' -> */,
+/* pos 03bf: 577 */    0x00, 0x43                  /* - terminal marker 67 - */,
+/* pos 03c1: 578 */    0xF4 /* 't' -> */,
+/* pos 03c2: 579 */    0x00, 0x44                  /* - terminal marker 68 - */,
+/* pos 03c4: 580 */    0xEC /* 'l' -> */,
+/* pos 03c5: 581 */    0xE5 /* 'e' -> */,
+/* pos 03c6: 582 */    0xF4 /* 't' -> */,
+/* pos 03c7: 583 */    0xE5 /* 'e' -> */,
+/* pos 03c8: 584 */    0x00, 0x45                  /* - terminal marker 69 - */,
+/* pos 03ca: 585 */    0x00, 0x47                  /* - terminal marker 71 - */,
+/* pos 03cc: 586 */    0xE5 /* 'e' -> */,
+/* pos 03cd: 587 */    0xE1 /* 'a' -> */,
+/* pos 03ce: 588 */    0xEC /* 'l' -> */,
+/* pos 03cf: 589 */    0xAD /* '-' -> */,
+/* pos 03d0: 590 */    0xE9 /* 'i' -> */,
+/* pos 03d1: 591 */    0xF0 /* 'p' -> */,
+/* pos 03d2: 592 */    0xBA /* ':' -> */,
+/* pos 03d3: 593 */    0x00, 0x48                  /* - terminal marker 72 - */,
+/* pos 03d5: 594 */    0xBA /* ':' -> */,
+/* pos 03d6: 595 */    0x00, 0x4D                  /* - terminal marker 77 - */,
+/* pos 03d8: 596 */    0xEC /* 'l' -> */,
+/* pos 03d9: 597 */    0xE1 /* 'a' -> */,
+/* pos 03da: 598 */    0xF9 /* 'y' -> */,
+/* pos 03db: 599 */    0xAD /* '-' -> */,
+/* pos 03dc: 600 */    0xEE /* 'n' -> */,
+/* pos 03dd: 601 */    0xEF /* 'o' -> */,
+/* pos 03de: 602 */    0xEE /* 'n' -> */,
+/* pos 03df: 603 */    0xE3 /* 'c' -> */,
+/* pos 03e0: 604 */    0xE5 /* 'e' -> */,
+/* pos 03e1: 605 */    0xBA /* ':' -> */,
+/* pos 03e2: 606 */    0x00, 0x4E                  /* - terminal marker 78 - */,
+/* pos 03e4: 607 */    0xAD /* '-' -> */,
+/* pos 03e5: 608 */    0xF7 /* 'w' -> */,
+/* pos 03e6: 609 */    0xE5 /* 'e' -> */,
+/* pos 03e7: 610 */    0xE2 /* 'b' -> */,
+/* pos 03e8: 611 */    0xF3 /* 's' -> */,
+/* pos 03e9: 612 */    0xEF /* 'o' -> */,
+/* pos 03ea: 613 */    0xE3 /* 'c' -> */,
+/* pos 03eb: 614 */    0xEB /* 'k' -> */,
+/* pos 03ec: 615 */    0xE5 /* 'e' -> */,
+/* pos 03ed: 616 */    0xF4 /* 't' -> */,
+/* pos 03ee: 617 */    0xAD /* '-' -> */,
+/* pos 03ef: 618 */    0x64 /* 'd' */, 0x19, 0x00  /* (to 0x0408 state 619) */,
+                       0x65 /* 'e' */, 0x1D, 0x00  /* (to 0x040F state 625) */,
+                       0x6B /* 'k' */, 0x26, 0x00  /* (to 0x041B state 636) */,
+                       0x70 /* 'p' */, 0x35, 0x00  /* (to 0x042D state 643) */,
+                       0x61 /* 'a' */, 0x3C, 0x00  /* (to 0x0437 state 652) */,
+                       0x6E /* 'n' */, 0x41, 0x00  /* (to 0x043F state 659) */,
+                       0x76 /* 'v' */, 0x47, 0x00  /* (to 0x0448 state 666) */,
+                       0x6F /* 'o' */, 0x4D, 0x00  /* (to 0x0451 state 674) */,
+                       0x08, /* fail */
+/* pos 0408: 619 */    0xF2 /* 'r' -> */,
+/* pos 0409: 620 */    0xE1 /* 'a' -> */,
+/* pos 040a: 621 */    0xE6 /* 'f' -> */,
+/* pos 040b: 622 */    0xF4 /* 't' -> */,
+/* pos 040c: 623 */    0xBA /* ':' -> */,
+/* pos 040d: 624 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 040f: 625 */    0xF8 /* 'x' -> */,
+/* pos 0410: 626 */    0xF4 /* 't' -> */,
+/* pos 0411: 627 */    0xE5 /* 'e' -> */,
+/* pos 0412: 628 */    0xEE /* 'n' -> */,
+/* pos 0413: 629 */    0xF3 /* 's' -> */,
+/* pos 0414: 630 */    0xE9 /* 'i' -> */,
+/* pos 0415: 631 */    0xEF /* 'o' -> */,
+/* pos 0416: 632 */    0xEE /* 'n' -> */,
+/* pos 0417: 633 */    0xF3 /* 's' -> */,
+/* pos 0418: 634 */    0xBA /* ':' -> */,
+/* pos 0419: 635 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 041b: 636 */    0xE5 /* 'e' -> */,
+/* pos 041c: 637 */    0xF9 /* 'y' -> */,
+/* pos 041d: 638 */    0x31 /* '1' */, 0x0A, 0x00  /* (to 0x0427 state 639) */,
+                       0x32 /* '2' */, 0x0A, 0x00  /* (to 0x042A state 641) */,
+                       0x3A /* ':' */, 0x23, 0x00  /* (to 0x0446 state 665) */,
+                       0x08, /* fail */
+/* pos 0427: 639 */    0xBA /* ':' -> */,
+/* pos 0428: 640 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 042a: 641 */    0xBA /* ':' -> */,
+/* pos 042b: 642 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 042d: 643 */    0xF2 /* 'r' -> */,
+/* pos 042e: 644 */    0xEF /* 'o' -> */,
+/* pos 042f: 645 */    0xF4 /* 't' -> */,
+/* pos 0430: 646 */    0xEF /* 'o' -> */,
+/* pos 0431: 647 */    0xE3 /* 'c' -> */,
+/* pos 0432: 648 */    0xEF /* 'o' -> */,
+/* pos 0433: 649 */    0xEC /* 'l' -> */,
+/* pos 0434: 650 */    0xBA /* ':' -> */,
+/* pos 0435: 651 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 0437: 652 */    0xE3 /* 'c' -> */,
+/* pos 0438: 653 */    0xE3 /* 'c' -> */,
+/* pos 0439: 654 */    0xE5 /* 'e' -> */,
+/* pos 043a: 655 */    0xF0 /* 'p' -> */,
+/* pos 043b: 656 */    0xF4 /* 't' -> */,
+/* pos 043c: 657 */    0xBA /* ':' -> */,
+/* pos 043d: 658 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 043f: 659 */    0xEF /* 'o' -> */,
+/* pos 0440: 660 */    0xEE /* 'n' -> */,
+/* pos 0441: 661 */    0xE3 /* 'c' -> */,
+/* pos 0442: 662 */    0xE5 /* 'e' -> */,
+/* pos 0443: 663 */    0xBA /* ':' -> */,
+/* pos 0444: 664 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 0446: 665 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 0448: 666 */    0xE5 /* 'e' -> */,
+/* pos 0449: 667 */    0xF2 /* 'r' -> */,
+/* pos 044a: 668 */    0xF3 /* 's' -> */,
+/* pos 044b: 669 */    0xE9 /* 'i' -> */,
+/* pos 044c: 670 */    0xEF /* 'o' -> */,
+/* pos 044d: 671 */    0xEE /* 'n' -> */,
+/* pos 044e: 672 */    0xBA /* ':' -> */,
+/* pos 044f: 673 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 0451: 674 */    0xF2 /* 'r' -> */,
+/* pos 0452: 675 */    0xE9 /* 'i' -> */,
+/* pos 0453: 676 */    0xE7 /* 'g' -> */,
+/* pos 0454: 677 */    0xE9 /* 'i' -> */,
+/* pos 0455: 678 */    0xEE /* 'n' -> */,
+/* pos 0456: 679 */    0xBA /* ':' -> */,
+/* pos 0457: 680 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* total size 1113 bytes */
+#endif
+
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
+       /* 0: 0: get  */
+       /* 1: 1: post  */
+       /* 2: 3: host: */
+       /* 3: 4: connection: */
+       /* 4: 5: upgrade: */
+       /* 5: 6: origin: */
+       /* 6: 8: \r
+ */
+       /* 7: 15: http/1.1  */
+       /* 8: 16: http2-settings: */
+       /* 9: 17: accept: */
+       /* 10: 19: if-modified-since: */
+       /* 11: 20: if-none-match: */
+       /* 12: 21: accept-encoding: */
+       /* 13: 22: accept-language: */
+       /* 14: 23: pragma: */
+       /* 15: 24: cache-control: */
+       /* 16: 25: authorization: */
+       /* 17: 26: cookie: */
+       /* 18: 27: content-length: */
+       /* 19: 28: content-type: */
+       /* 20: 29: date: */
+       /* 21: 30: range: */
+       /* 22: 31: referer: */
+       /* 23: 35: :authority */
+       /* 24: 36: :method */
+       /* 25: 37: :path */
+       /* 26: 38: :scheme */
+       /* 27: 39: :status */
+       /* 28: 40: accept-charset: */
+       /* 29: 41: accept-ranges: */
+       /* 30: 42: access-control-allow-origin: */
+       /* 31: 43: age: */
+       /* 32: 44: allow: */
+       /* 33: 45: content-disposition: */
+       /* 34: 46: content-encoding: */
+       /* 35: 47: content-language: */
+       /* 36: 48: content-location: */
+       /* 37: 49: content-range: */
+       /* 38: 50: etag: */
+       /* 39: 51: expect: */
+       /* 40: 52: expires: */
+       /* 41: 53: from: */
+       /* 42: 54: if-match: */
+       /* 43: 55: if-range: */
+       /* 44: 56: if-unmodified-since: */
+       /* 45: 57: last-modified: */
+       /* 46: 58: link: */
+       /* 47: 59: location: */
+       /* 48: 60: max-forwards: */
+       /* 49: 61: proxy-authenticate: */
+       /* 50: 62: proxy-authorization: */
+       /* 51: 63: refresh: */
+       /* 52: 64: retry-after: */
+       /* 53: 65: server: */
+       /* 54: 66: set-cookie: */
+       /* 55: 67: strict-transport-security: */
+       /* 56: 68: transfer-encoding: */
+       /* 57: 69: user-agent: */
+       /* 58: 70: vary: */
+       /* 59: 71: via: */
+       /* 60: 72: www-authenticate: */
+       /* 61: 76: uri-args */
+       /* 62: 79: http/1.0  */
+       /* 63: 80: x-forwarded-for: */
+       /* 64: 81: connect  */
+       /* 65: 82: head  */
+       /* 66: 83: te: */
+       /* 67: 84: replay-nonce: */
+       /* 68: 85: :protocol */
+       /* 69: 86: x-auth-token: */
+       /* 70: 87: x-amzn-dss-signature: */
 /* pos 0000:   0 */    0x67 /* 'g' */, 0x40, 0x00  /* (to 0x0040 state   1) */,
                        0x70 /* 'p' */, 0x42, 0x00  /* (to 0x0045 state   5) */,
-                       0x6F /* 'o' */, 0x51, 0x00  /* (to 0x0057 state  10) */,
-                       0x68 /* 'h' */, 0x5D, 0x00  /* (to 0x0066 state  18) */,
-                       0x63 /* 'c' */, 0x69, 0x00  /* (to 0x0075 state  23) */,
-                       0x75 /* 'u' */, 0x8A, 0x00  /* (to 0x0099 state  34) */,
-                       0x73 /* 's' */, 0xA0, 0x00  /* (to 0x00B2 state  48) */,
-                       0x0D /* '.' */, 0xD9, 0x00  /* (to 0x00EE state  68) */,
-                       0x61 /* 'a' */, 0x31, 0x01  /* (to 0x0149 state 129) */,
-                       0x69 /* 'i' */, 0x70, 0x01  /* (to 0x018B state 163) */,
-                       0x64 /* 'd' */, 0x19, 0x02  /* (to 0x0237 state 265) */,
-                       0x72 /* 'r' */, 0x22, 0x02  /* (to 0x0243 state 270) */,
-                       0x3A /* ':' */, 0x56, 0x02  /* (to 0x027A state 299) */,
-                       0x65 /* 'e' */, 0xE8, 0x02  /* (to 0x030F state 409) */,
-                       0x66 /* 'f' */, 0x04, 0x03  /* (to 0x032E state 425) */,
-                       0x6C /* 'l' */, 0x26, 0x03  /* (to 0x0353 state 458) */,
-                       0x6D /* 'm' */, 0x49, 0x03  /* (to 0x0379 state 484) */,
-                       0x74 /* 't' */, 0xB8, 0x03  /* (to 0x03EB state 578) */,
-                       0x76 /* 'v' */, 0xD9, 0x03  /* (to 0x040F state 606) */,
-                       0x77 /* 'w' */, 0xE6, 0x03  /* (to 0x041F state 614) */,
-                       0x78 /* 'x' */, 0x0D, 0x04  /* (to 0x0449 state 650) */,
+                       0x68 /* 'h' */, 0x51, 0x00  /* (to 0x0057 state  10) */,
+                       0x63 /* 'c' */, 0x5D, 0x00  /* (to 0x0066 state  15) */,
+                       0x75 /* 'u' */, 0x7E, 0x00  /* (to 0x008A state  26) */,
+                       0x6F /* 'o' */, 0x8D, 0x00  /* (to 0x009C state  34) */,
+                       0x0D /* '.' */, 0x98, 0x00  /* (to 0x00AA state  41) */,
+                       0x61 /* 'a' */, 0xAD, 0x00  /* (to 0x00C2 state  51) */,
+                       0x69 /* 'i' */, 0xCA, 0x00  /* (to 0x00E2 state  58) */,
+                       0x64 /* 'd' */, 0x73, 0x01  /* (to 0x018E state 160) */,
+                       0x72 /* 'r' */, 0x7C, 0x01  /* (to 0x019A state 165) */,
+                       0x65 /* 'e' */, 0xC8, 0x01  /* (to 0x01E9 state 229) */,
+                       0x66 /* 'f' */, 0xE4, 0x01  /* (to 0x0208 state 245) */,
+                       0x6C /* 'l' */, 0x06, 0x02  /* (to 0x022D state 278) */,
+                       0x73 /* 's' */, 0x4B, 0x02  /* (to 0x0275 state 321) */,
+                       0x74 /* 't' */, 0x69, 0x02  /* (to 0x0296 state 337) */,
+                       0x78 /* 'x' */, 0x8A, 0x02  /* (to 0x02BA state 364) */,
+                       0x6D /* 'm' */, 0x14, 0x03  /* (to 0x0347 state 474) */,
+                       0x76 /* 'v' */, 0x6D, 0x03  /* (to 0x03A3 state 549) */,
+                       0x77 /* 'w' */, 0x7A, 0x03  /* (to 0x03B3 state 557) */,
+                       0x3A /* ':' */, 0x32, 0x04  /* (to 0x046E state 692) */,
                        0x08, /* fail */
 /* pos 0040:   1 */    0xE5 /* 'e' -> */,
 /* pos 0041:   2 */    0xF4 /* 't' -> */,
 /* pos 0042:   3 */    0xA0 /* ' ' -> */,
 /* pos 0043:   4 */    0x00, 0x00                  /* - terminal marker  0 - */,
 /* pos 0045:   5 */    0x6F /* 'o' */, 0x0D, 0x00  /* (to 0x0052 state   6) */,
-                       0x72 /* 'r' */, 0x95, 0x01  /* (to 0x01DD state 211) */,
-                       0x61 /* 'a' */, 0xE6, 0x03  /* (to 0x0431 state 631) */,
-                       0x75 /* 'u' */, 0xE8, 0x03  /* (to 0x0436 state 635) */,
+                       0x72 /* 'r' */, 0xEC, 0x00  /* (to 0x0134 state 106) */,
+                       0x61 /* 'a' */, 0x7A, 0x03  /* (to 0x03C5 state 574) */,
+                       0x75 /* 'u' */, 0x7C, 0x03  /* (to 0x03CA state 578) */,
                        0x08, /* fail */
 /* pos 0052:   6 */    0xF3 /* 's' -> */,
 /* pos 0053:   7 */    0xF4 /* 't' -> */,
 /* pos 0054:   8 */    0xA0 /* ' ' -> */,
 /* pos 0055:   9 */    0x00, 0x01                  /* - terminal marker  1 - */,
-/* pos 0057:  10 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x005E state  11) */,
-                       0x72 /* 'r' */, 0x51, 0x00  /* (to 0x00AB state  42) */,
-                       0x08, /* fail */
-/* pos 005e:  11 */    0xF4 /* 't' -> */,
-/* pos 005f:  12 */    0xE9 /* 'i' -> */,
-/* pos 0060:  13 */    0xEF /* 'o' -> */,
-/* pos 0061:  14 */    0xEE /* 'n' -> */,
-/* pos 0062:  15 */    0xF3 /* 's' -> */,
-/* pos 0063:  16 */    0xA0 /* ' ' -> */,
-/* pos 0064:  17 */    0x00, 0x02                  /* - terminal marker  2 - */,
-/* pos 0066:  18 */    0x6F /* 'o' */, 0x0A, 0x00  /* (to 0x0070 state  19) */,
-                       0x74 /* 't' */, 0xBF, 0x00  /* (to 0x0128 state 110) */,
-                       0x65 /* 'e' */, 0x05, 0x04  /* (to 0x0471 state 677) */,
-                       0x08, /* fail */
-/* pos 0070:  19 */    0xF3 /* 's' -> */,
-/* pos 0071:  20 */    0xF4 /* 't' -> */,
-/* pos 0072:  21 */    0xBA /* ':' -> */,
-/* pos 0073:  22 */    0x00, 0x03                  /* - terminal marker  3 - */,
-/* pos 0075:  23 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x007C state  24) */,
-                       0x61 /* 'a' */, 0x72, 0x01  /* (to 0x01EA state 217) */,
-                       0x08, /* fail */
-/* pos 007c:  24 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0083 state  25) */,
-                       0x6F /* 'o' */, 0x87, 0x01  /* (to 0x0206 state 243) */,
-                       0x08, /* fail */
-/* pos 0083:  25 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x008A state  26) */,
-                       0x74 /* 't' */, 0x86, 0x01  /* (to 0x020C state 248) */,
-                       0x08, /* fail */
-/* pos 008a:  26 */    0xE5 /* 'e' -> */,
-/* pos 008b:  27 */    0xE3 /* 'c' -> */,
-/* pos 008c:  28 */    0xF4 /* 't' -> */,
-/* pos 008d:  29 */    0x69 /* 'i' */, 0x07, 0x00  /* (to 0x0094 state  30) */,
-                       0x20 /* ' ' */, 0xDF, 0x03  /* (to 0x046F state 676) */,
-                       0x08, /* fail */
-/* pos 0094:  30 */    0xEF /* 'o' -> */,
-/* pos 0095:  31 */    0xEE /* 'n' -> */,
-/* pos 0096:  32 */    0xBA /* ':' -> */,
-/* pos 0097:  33 */    0x00, 0x04                  /* - terminal marker  4 - */,
-/* pos 0099:  34 */    0x70 /* 'p' */, 0x0A, 0x00  /* (to 0x00A3 state  35) */,
-                       0x73 /* 's' */, 0x68, 0x03  /* (to 0x0404 state 596) */,
-                       0x72 /* 'r' */, 0xA0, 0x03  /* (to 0x043F state 642) */,
-                       0x08, /* fail */
-/* pos 00a3:  35 */    0xE7 /* 'g' -> */,
-/* pos 00a4:  36 */    0xF2 /* 'r' -> */,
-/* pos 00a5:  37 */    0xE1 /* 'a' -> */,
-/* pos 00a6:  38 */    0xE4 /* 'd' -> */,
-/* pos 00a7:  39 */    0xE5 /* 'e' -> */,
-/* pos 00a8:  40 */    0xBA /* ':' -> */,
-/* pos 00a9:  41 */    0x00, 0x05                  /* - terminal marker  5 - */,
-/* pos 00ab:  42 */    0xE9 /* 'i' -> */,
-/* pos 00ac:  43 */    0xE7 /* 'g' -> */,
-/* pos 00ad:  44 */    0xE9 /* 'i' -> */,
-/* pos 00ae:  45 */    0xEE /* 'n' -> */,
-/* pos 00af:  46 */    0xBA /* ':' -> */,
-/* pos 00b0:  47 */    0x00, 0x06                  /* - terminal marker  6 - */,
-/* pos 00b2:  48 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x00B9 state  49) */,
-                       0x74 /* 't' */, 0x1C, 0x03  /* (to 0x03D1 state 553) */,
-                       0x08, /* fail */
-/* pos 00b9:  49 */    0x63 /* 'c' */, 0x0A, 0x00  /* (to 0x00C3 state  50) */,
-                       0x72 /* 'r' */, 0x05, 0x03  /* (to 0x03C1 state 539) */,
-                       0x74 /* 't' */, 0x08, 0x03  /* (to 0x03C7 state 544) */,
-                       0x08, /* fail */
-/* pos 00c3:  50 */    0xAD /* '-' -> */,
-/* pos 00c4:  51 */    0xF7 /* 'w' -> */,
-/* pos 00c5:  52 */    0xE5 /* 'e' -> */,
-/* pos 00c6:  53 */    0xE2 /* 'b' -> */,
-/* pos 00c7:  54 */    0xF3 /* 's' -> */,
-/* pos 00c8:  55 */    0xEF /* 'o' -> */,
-/* pos 00c9:  56 */    0xE3 /* 'c' -> */,
-/* pos 00ca:  57 */    0xEB /* 'k' -> */,
-/* pos 00cb:  58 */    0xE5 /* 'e' -> */,
-/* pos 00cc:  59 */    0xF4 /* 't' -> */,
-/* pos 00cd:  60 */    0xAD /* '-' -> */,
-/* pos 00ce:  61 */    0x64 /* 'd' */, 0x19, 0x00  /* (to 0x00E7 state  62) */,
-                       0x65 /* 'e' */, 0x20, 0x00  /* (to 0x00F1 state  70) */,
-                       0x6B /* 'k' */, 0x29, 0x00  /* (to 0x00FD state  81) */,
-                       0x70 /* 'p' */, 0x38, 0x00  /* (to 0x010F state  88) */,
-                       0x61 /* 'a' */, 0x3F, 0x00  /* (to 0x0119 state  97) */,
-                       0x6E /* 'n' */, 0x44, 0x00  /* (to 0x0121 state 104) */,
-                       0x76 /* 'v' */, 0x89, 0x01  /* (to 0x0269 state 284) */,
-                       0x6F /* 'o' */, 0x8F, 0x01  /* (to 0x0272 state 292) */,
-                       0x08, /* fail */
-/* pos 00e7:  62 */    0xF2 /* 'r' -> */,
-/* pos 00e8:  63 */    0xE1 /* 'a' -> */,
-/* pos 00e9:  64 */    0xE6 /* 'f' -> */,
-/* pos 00ea:  65 */    0xF4 /* 't' -> */,
-/* pos 00eb:  66 */    0xBA /* ':' -> */,
-/* pos 00ec:  67 */    0x00, 0x07                  /* - terminal marker  7 - */,
-/* pos 00ee:  68 */    0x8A /* '.' -> */,
-/* pos 00ef:  69 */    0x00, 0x08                  /* - terminal marker  8 - */,
-/* pos 00f1:  70 */    0xF8 /* 'x' -> */,
-/* pos 00f2:  71 */    0xF4 /* 't' -> */,
-/* pos 00f3:  72 */    0xE5 /* 'e' -> */,
-/* pos 00f4:  73 */    0xEE /* 'n' -> */,
-/* pos 00f5:  74 */    0xF3 /* 's' -> */,
-/* pos 00f6:  75 */    0xE9 /* 'i' -> */,
-/* pos 00f7:  76 */    0xEF /* 'o' -> */,
-/* pos 00f8:  77 */    0xEE /* 'n' -> */,
-/* pos 00f9:  78 */    0xF3 /* 's' -> */,
-/* pos 00fa:  79 */    0xBA /* ':' -> */,
-/* pos 00fb:  80 */    0x00, 0x09                  /* - terminal marker  9 - */,
-/* pos 00fd:  81 */    0xE5 /* 'e' -> */,
-/* pos 00fe:  82 */    0xF9 /* 'y' -> */,
-/* pos 00ff:  83 */    0x31 /* '1' */, 0x0A, 0x00  /* (to 0x0109 state  84) */,
-                       0x32 /* '2' */, 0x0A, 0x00  /* (to 0x010C state  86) */,
-                       0x3A /* ':' */, 0x62, 0x01  /* (to 0x0267 state 283) */,
-                       0x08, /* fail */
-/* pos 0109:  84 */    0xBA /* ':' -> */,
-/* pos 010a:  85 */    0x00, 0x0A                  /* - terminal marker 10 - */,
-/* pos 010c:  86 */    0xBA /* ':' -> */,
-/* pos 010d:  87 */    0x00, 0x0B                  /* - terminal marker 11 - */,
-/* pos 010f:  88 */    0xF2 /* 'r' -> */,
-/* pos 0110:  89 */    0xEF /* 'o' -> */,
-/* pos 0111:  90 */    0xF4 /* 't' -> */,
-/* pos 0112:  91 */    0xEF /* 'o' -> */,
-/* pos 0113:  92 */    0xE3 /* 'c' -> */,
-/* pos 0114:  93 */    0xEF /* 'o' -> */,
-/* pos 0115:  94 */    0xEC /* 'l' -> */,
-/* pos 0116:  95 */    0xBA /* ':' -> */,
-/* pos 0117:  96 */    0x00, 0x0C                  /* - terminal marker 12 - */,
-/* pos 0119:  97 */    0xE3 /* 'c' -> */,
-/* pos 011a:  98 */    0xE3 /* 'c' -> */,
-/* pos 011b:  99 */    0xE5 /* 'e' -> */,
-/* pos 011c: 100 */    0xF0 /* 'p' -> */,
-/* pos 011d: 101 */    0xF4 /* 't' -> */,
-/* pos 011e: 102 */    0xBA /* ':' -> */,
-/* pos 011f: 103 */    0x00, 0x0D                  /* - terminal marker 13 - */,
-/* pos 0121: 104 */    0xEF /* 'o' -> */,
-/* pos 0122: 105 */    0xEE /* 'n' -> */,
-/* pos 0123: 106 */    0xE3 /* 'c' -> */,
-/* pos 0124: 107 */    0xE5 /* 'e' -> */,
-/* pos 0125: 108 */    0xBA /* ':' -> */,
-/* pos 0126: 109 */    0x00, 0x0E                  /* - terminal marker 14 - */,
-/* pos 0128: 110 */    0xF4 /* 't' -> */,
-/* pos 0129: 111 */    0xF0 /* 'p' -> */,
-/* pos 012a: 112 */    0x2F /* '/' */, 0x07, 0x00  /* (to 0x0131 state 113) */,
-                       0x32 /* '2' */, 0x10, 0x00  /* (to 0x013D state 118) */,
-                       0x08, /* fail */
-/* pos 0131: 113 */    0xB1 /* '1' -> */,
-/* pos 0132: 114 */    0xAE /* '.' -> */,
-/* pos 0133: 115 */    0x31 /* '1' */, 0x07, 0x00  /* (to 0x013A state 116) */,
-                       0x30 /* '0' */, 0x27, 0x03  /* (to 0x045D state 660) */,
-                       0x08, /* fail */
-/* pos 013a: 116 */    0xA0 /* ' ' -> */,
-/* pos 013b: 117 */    0x00, 0x0F                  /* - terminal marker 15 - */,
-/* pos 013d: 118 */    0xAD /* '-' -> */,
-/* pos 013e: 119 */    0xF3 /* 's' -> */,
-/* pos 013f: 120 */    0xE5 /* 'e' -> */,
-/* pos 0140: 121 */    0xF4 /* 't' -> */,
-/* pos 0141: 122 */    0xF4 /* 't' -> */,
-/* pos 0142: 123 */    0xE9 /* 'i' -> */,
-/* pos 0143: 124 */    0xEE /* 'n' -> */,
-/* pos 0144: 125 */    0xE7 /* 'g' -> */,
-/* pos 0145: 126 */    0xF3 /* 's' -> */,
-/* pos 0146: 127 */    0xBA /* ':' -> */,
-/* pos 0147: 128 */    0x00, 0x10                  /* - terminal marker 16 - */,
-/* pos 0149: 129 */    0x63 /* 'c' */, 0x0D, 0x00  /* (to 0x0156 state 130) */,
-                       0x75 /* 'u' */, 0xAC, 0x00  /* (to 0x01F8 state 230) */,
-                       0x67 /* 'g' */, 0x86, 0x01  /* (to 0x02D5 state 358) */,
-                       0x6C /* 'l' */, 0x87, 0x01  /* (to 0x02D9 state 361) */,
-                       0x08, /* fail */
-/* pos 0156: 130 */    0xE3 /* 'c' -> */,
-/* pos 0157: 131 */    0xE5 /* 'e' -> */,
-/* pos 0158: 132 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x015F state 133) */,
-                       0x73 /* 's' */, 0x0E, 0x00  /* (to 0x0169 state 136) */,
-                       0x08, /* fail */
-/* pos 015f: 133 */    0xF4 /* 't' -> */,
-/* pos 0160: 134 */    0x3A /* ':' */, 0x07, 0x00  /* (to 0x0167 state 135) */,
-                       0x2D /* '-' */, 0x59, 0x00  /* (to 0x01BC state 192) */,
-                       0x08, /* fail */
-/* pos 0167: 135 */    0x00, 0x11                  /* - terminal marker 17 - */,
-/* pos 0169: 136 */    0xF3 /* 's' -> */,
-/* pos 016a: 137 */    0xAD /* '-' -> */,
-/* pos 016b: 138 */    0xE3 /* 'c' -> */,
-/* pos 016c: 139 */    0xEF /* 'o' -> */,
-/* pos 016d: 140 */    0xEE /* 'n' -> */,
-/* pos 016e: 141 */    0xF4 /* 't' -> */,
-/* pos 016f: 142 */    0xF2 /* 'r' -> */,
-/* pos 0170: 143 */    0xEF /* 'o' -> */,
-/* pos 0171: 144 */    0xEC /* 'l' -> */,
-/* pos 0172: 145 */    0xAD /* '-' -> */,
-/* pos 0173: 146 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x017A state 147) */,
-                       0x61 /* 'a' */, 0x51, 0x01  /* (to 0x02C7 state 345) */,
-                       0x08, /* fail */
-/* pos 017a: 147 */    0xE5 /* 'e' -> */,
-/* pos 017b: 148 */    0xF1 /* 'q' -> */,
-/* pos 017c: 149 */    0xF5 /* 'u' -> */,
-/* pos 017d: 150 */    0xE5 /* 'e' -> */,
-/* pos 017e: 151 */    0xF3 /* 's' -> */,
-/* pos 017f: 152 */    0xF4 /* 't' -> */,
-/* pos 0180: 153 */    0xAD /* '-' -> */,
-/* pos 0181: 154 */    0xE8 /* 'h' -> */,
-/* pos 0182: 155 */    0xE5 /* 'e' -> */,
-/* pos 0183: 156 */    0xE1 /* 'a' -> */,
-/* pos 0184: 157 */    0xE4 /* 'd' -> */,
-/* pos 0185: 158 */    0xE5 /* 'e' -> */,
-/* pos 0186: 159 */    0xF2 /* 'r' -> */,
-/* pos 0187: 160 */    0xF3 /* 's' -> */,
-/* pos 0188: 161 */    0xBA /* ':' -> */,
-/* pos 0189: 162 */    0x00, 0x12                  /* - terminal marker 18 - */,
-/* pos 018b: 163 */    0xE6 /* 'f' -> */,
-/* pos 018c: 164 */    0xAD /* '-' -> */,
-/* pos 018d: 165 */    0x6D /* 'm' */, 0x0D, 0x00  /* (to 0x019A state 166) */,
-                       0x6E /* 'n' */, 0x20, 0x00  /* (to 0x01B0 state 181) */,
-                       0x72 /* 'r' */, 0xA7, 0x01  /* (to 0x033A state 435) */,
-                       0x75 /* 'u' */, 0xAB, 0x01  /* (to 0x0341 state 441) */,
-                       0x08, /* fail */
-/* pos 019a: 166 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x01A1 state 167) */,
-                       0x61 /* 'a' */, 0x97, 0x01  /* (to 0x0334 state 430) */,
-                       0x08, /* fail */
-/* pos 01a1: 167 */    0xE4 /* 'd' -> */,
-/* pos 01a2: 168 */    0xE9 /* 'i' -> */,
-/* pos 01a3: 169 */    0xE6 /* 'f' -> */,
-/* pos 01a4: 170 */    0xE9 /* 'i' -> */,
-/* pos 01a5: 171 */    0xE5 /* 'e' -> */,
-/* pos 01a6: 172 */    0xE4 /* 'd' -> */,
-/* pos 01a7: 173 */    0xAD /* '-' -> */,
-/* pos 01a8: 174 */    0xF3 /* 's' -> */,
-/* pos 01a9: 175 */    0xE9 /* 'i' -> */,
-/* pos 01aa: 176 */    0xEE /* 'n' -> */,
-/* pos 01ab: 177 */    0xE3 /* 'c' -> */,
-/* pos 01ac: 178 */    0xE5 /* 'e' -> */,
-/* pos 01ad: 179 */    0xBA /* ':' -> */,
-/* pos 01ae: 180 */    0x00, 0x13                  /* - terminal marker 19 - */,
-/* pos 01b0: 181 */    0xEF /* 'o' -> */,
-/* pos 01b1: 182 */    0xEE /* 'n' -> */,
-/* pos 01b2: 183 */    0xE5 /* 'e' -> */,
-/* pos 01b3: 184 */    0xAD /* '-' -> */,
-/* pos 01b4: 185 */    0xED /* 'm' -> */,
-/* pos 01b5: 186 */    0xE1 /* 'a' -> */,
-/* pos 01b6: 187 */    0xF4 /* 't' -> */,
-/* pos 01b7: 188 */    0xE3 /* 'c' -> */,
-/* pos 01b8: 189 */    0xE8 /* 'h' -> */,
-/* pos 01b9: 190 */    0xBA /* ':' -> */,
-/* pos 01ba: 191 */    0x00, 0x14                  /* - terminal marker 20 - */,
-/* pos 01bc: 192 */    0x65 /* 'e' */, 0x0D, 0x00  /* (to 0x01C9 state 193) */,
-                       0x6C /* 'l' */, 0x14, 0x00  /* (to 0x01D3 state 202) */,
-                       0x63 /* 'c' */, 0xF4, 0x00  /* (to 0x02B6 state 330) */,
-                       0x72 /* 'r' */, 0xFA, 0x00  /* (to 0x02BF state 338) */,
-                       0x08, /* fail */
-/* pos 01c9: 193 */    0xEE /* 'n' -> */,
-/* pos 01ca: 194 */    0xE3 /* 'c' -> */,
-/* pos 01cb: 195 */    0xEF /* 'o' -> */,
-/* pos 01cc: 196 */    0xE4 /* 'd' -> */,
-/* pos 01cd: 197 */    0xE9 /* 'i' -> */,
-/* pos 01ce: 198 */    0xEE /* 'n' -> */,
-/* pos 01cf: 199 */    0xE7 /* 'g' -> */,
-/* pos 01d0: 200 */    0xBA /* ':' -> */,
-/* pos 01d1: 201 */    0x00, 0x15                  /* - terminal marker 21 - */,
-/* pos 01d3: 202 */    0xE1 /* 'a' -> */,
-/* pos 01d4: 203 */    0xEE /* 'n' -> */,
-/* pos 01d5: 204 */    0xE7 /* 'g' -> */,
-/* pos 01d6: 205 */    0xF5 /* 'u' -> */,
-/* pos 01d7: 206 */    0xE1 /* 'a' -> */,
-/* pos 01d8: 207 */    0xE7 /* 'g' -> */,
-/* pos 01d9: 208 */    0xE5 /* 'e' -> */,
-/* pos 01da: 209 */    0xBA /* ':' -> */,
-/* pos 01db: 210 */    0x00, 0x16                  /* - terminal marker 22 - */,
-/* pos 01dd: 211 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x01E4 state 212) */,
-                       0x6F /* 'o' */, 0xA7, 0x01  /* (to 0x0387 state 497) */,
-                       0x08, /* fail */
-/* pos 01e4: 212 */    0xE7 /* 'g' -> */,
-/* pos 01e5: 213 */    0xED /* 'm' -> */,
-/* pos 01e6: 214 */    0xE1 /* 'a' -> */,
-/* pos 01e7: 215 */    0xBA /* ':' -> */,
-/* pos 01e8: 216 */    0x00, 0x17                  /* - terminal marker 23 - */,
-/* pos 01ea: 217 */    0xE3 /* 'c' -> */,
-/* pos 01eb: 218 */    0xE8 /* 'h' -> */,
-/* pos 01ec: 219 */    0xE5 /* 'e' -> */,
-/* pos 01ed: 220 */    0xAD /* '-' -> */,
-/* pos 01ee: 221 */    0xE3 /* 'c' -> */,
-/* pos 01ef: 222 */    0xEF /* 'o' -> */,
-/* pos 01f0: 223 */    0xEE /* 'n' -> */,
-/* pos 01f1: 224 */    0xF4 /* 't' -> */,
-/* pos 01f2: 225 */    0xF2 /* 'r' -> */,
-/* pos 01f3: 226 */    0xEF /* 'o' -> */,
-/* pos 01f4: 227 */    0xEC /* 'l' -> */,
-/* pos 01f5: 228 */    0xBA /* ':' -> */,
-/* pos 01f6: 229 */    0x00, 0x18                  /* - terminal marker 24 - */,
-/* pos 01f8: 230 */    0xF4 /* 't' -> */,
-/* pos 01f9: 231 */    0xE8 /* 'h' -> */,
-/* pos 01fa: 232 */    0xEF /* 'o' -> */,
-/* pos 01fb: 233 */    0xF2 /* 'r' -> */,
-/* pos 01fc: 234 */    0xE9 /* 'i' -> */,
-/* pos 01fd: 235 */    0xFA /* 'z' -> */,
-/* pos 01fe: 236 */    0xE1 /* 'a' -> */,
-/* pos 01ff: 237 */    0xF4 /* 't' -> */,
-/* pos 0200: 238 */    0xE9 /* 'i' -> */,
-/* pos 0201: 239 */    0xEF /* 'o' -> */,
-/* pos 0202: 240 */    0xEE /* 'n' -> */,
-/* pos 0203: 241 */    0xBA /* ':' -> */,
-/* pos 0204: 242 */    0x00, 0x19                  /* - terminal marker 25 - */,
-/* pos 0206: 243 */    0xEB /* 'k' -> */,
-/* pos 0207: 244 */    0xE9 /* 'i' -> */,
-/* pos 0208: 245 */    0xE5 /* 'e' -> */,
-/* pos 0209: 246 */    0xBA /* ':' -> */,
-/* pos 020a: 247 */    0x00, 0x1A                  /* - terminal marker 26 - */,
-/* pos 020c: 248 */    0xE5 /* 'e' -> */,
-/* pos 020d: 249 */    0xEE /* 'n' -> */,
+/* pos 0057:  10 */    0x6F /* 'o' */, 0x0A, 0x00  /* (to 0x0061 state  11) */,
+                       0x74 /* 't' */, 0x53, 0x00  /* (to 0x00AD state  43) */,
+                       0x65 /* 'e' */, 0x79, 0x02  /* (to 0x02D6 state 381) */,
+                       0x08, /* fail */
+/* pos 0061:  11 */    0xF3 /* 's' -> */,
+/* pos 0062:  12 */    0xF4 /* 't' -> */,
+/* pos 0063:  13 */    0xBA /* ':' -> */,
+/* pos 0064:  14 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 0066:  15 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x006D state  16) */,
+                       0x61 /* 'a' */, 0xD8, 0x00  /* (to 0x0141 state 112) */,
+                       0x08, /* fail */
+/* pos 006d:  16 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0074 state  17) */,
+                       0x6F /* 'o' */, 0xED, 0x00  /* (to 0x015D state 138) */,
+                       0x08, /* fail */
+/* pos 0074:  17 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x007B state  18) */,
+                       0x74 /* 't' */, 0xEC, 0x00  /* (to 0x0163 state 143) */,
+                       0x08, /* fail */
+/* pos 007b:  18 */    0xE5 /* 'e' -> */,
+/* pos 007c:  19 */    0xE3 /* 'c' -> */,
+/* pos 007d:  20 */    0xF4 /* 't' -> */,
+/* pos 007e:  21 */    0x69 /* 'i' */, 0x07, 0x00  /* (to 0x0085 state  22) */,
+                       0x20 /* ' ' */, 0x53, 0x02  /* (to 0x02D4 state 380) */,
+                       0x08, /* fail */
+/* pos 0085:  22 */    0xEF /* 'o' -> */,
+/* pos 0086:  23 */    0xEE /* 'n' -> */,
+/* pos 0087:  24 */    0xBA /* ':' -> */,
+/* pos 0088:  25 */    0x00, 0x03                  /* - terminal marker  3 - */,
+/* pos 008a:  26 */    0x70 /* 'p' */, 0x0A, 0x00  /* (to 0x0094 state  27) */,
+                       0x72 /* 'r' */, 0x22, 0x02  /* (to 0x02AF state 355) */,
+                       0x73 /* 's' */, 0x08, 0x03  /* (to 0x0398 state 539) */,
+                       0x08, /* fail */
+/* pos 0094:  27 */    0xE7 /* 'g' -> */,
+/* pos 0095:  28 */    0xF2 /* 'r' -> */,
+/* pos 0096:  29 */    0xE1 /* 'a' -> */,
+/* pos 0097:  30 */    0xE4 /* 'd' -> */,
+/* pos 0098:  31 */    0xE5 /* 'e' -> */,
+/* pos 0099:  32 */    0xBA /* ':' -> */,
+/* pos 009a:  33 */    0x00, 0x04                  /* - terminal marker  4 - */,
+/* pos 009c:  34 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x00A3 state  35) */,
+                       0x70 /* 'p' */, 0x61, 0x02  /* (to 0x0300 state 414) */,
+                       0x08, /* fail */
+/* pos 00a3:  35 */    0xE9 /* 'i' -> */,
+/* pos 00a4:  36 */    0xE7 /* 'g' -> */,
+/* pos 00a5:  37 */    0xE9 /* 'i' -> */,
+/* pos 00a6:  38 */    0xEE /* 'n' -> */,
+/* pos 00a7:  39 */    0xBA /* ':' -> */,
+/* pos 00a8:  40 */    0x00, 0x05                  /* - terminal marker  5 - */,
+/* pos 00aa:  41 */    0x8A /* '.' -> */,
+/* pos 00ab:  42 */    0x00, 0x06                  /* - terminal marker  6 - */,
+/* pos 00ad:  43 */    0xF4 /* 't' -> */,
+/* pos 00ae:  44 */    0xF0 /* 'p' -> */,
+/* pos 00af:  45 */    0x2F /* '/' */, 0x07, 0x00  /* (to 0x00B6 state  46) */,
+                       0x32 /* '2' */, 0xB0, 0x03  /* (to 0x0462 state 681) */,
+                       0x08, /* fail */
+/* pos 00b6:  46 */    0xB1 /* '1' -> */,
+/* pos 00b7:  47 */    0xAE /* '.' -> */,
+/* pos 00b8:  48 */    0x31 /* '1' */, 0x07, 0x00  /* (to 0x00BF state  49) */,
+                       0x30 /* '0' */, 0xFC, 0x01  /* (to 0x02B7 state 362) */,
+                       0x08, /* fail */
+/* pos 00bf:  49 */    0xA0 /* ' ' -> */,
+/* pos 00c0:  50 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 00c2:  51 */    0x63 /* 'c' */, 0x0D, 0x00  /* (to 0x00CF state  52) */,
+                       0x75 /* 'u' */, 0x8A, 0x00  /* (to 0x014F state 125) */,
+                       0x67 /* 'g' */, 0xE7, 0x00  /* (to 0x01AF state 178) */,
+                       0x6C /* 'l' */, 0xE8, 0x00  /* (to 0x01B3 state 181) */,
+                       0x08, /* fail */
+/* pos 00cf:  52 */    0xE3 /* 'c' -> */,
+/* pos 00d0:  53 */    0xE5 /* 'e' -> */,
+/* pos 00d1:  54 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x00D8 state  55) */,
+                       0x73 /* 's' */, 0x34, 0x02  /* (to 0x0308 state 421) */,
+                       0x08, /* fail */
+/* pos 00d8:  55 */    0xF4 /* 't' -> */,
+/* pos 00d9:  56 */    0x3A /* ':' */, 0x07, 0x00  /* (to 0x00E0 state  57) */,
+                       0x2D /* '-' */, 0x37, 0x00  /* (to 0x0113 state  87) */,
+                       0x08, /* fail */
+/* pos 00e0:  57 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 00e2:  58 */    0xE6 /* 'f' -> */,
+/* pos 00e3:  59 */    0xAD /* '-' -> */,
+/* pos 00e4:  60 */    0x6D /* 'm' */, 0x0D, 0x00  /* (to 0x00F1 state  61) */,
+                       0x6E /* 'n' */, 0x20, 0x00  /* (to 0x0107 state  76) */,
+                       0x72 /* 'r' */, 0x2A, 0x01  /* (to 0x0214 state 255) */,
+                       0x75 /* 'u' */, 0x2E, 0x01  /* (to 0x021B state 261) */,
+                       0x08, /* fail */
+/* pos 00f1:  61 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x00F8 state  62) */,
+                       0x61 /* 'a' */, 0x1A, 0x01  /* (to 0x020E state 250) */,
+                       0x08, /* fail */
+/* pos 00f8:  62 */    0xE4 /* 'd' -> */,
+/* pos 00f9:  63 */    0xE9 /* 'i' -> */,
+/* pos 00fa:  64 */    0xE6 /* 'f' -> */,
+/* pos 00fb:  65 */    0xE9 /* 'i' -> */,
+/* pos 00fc:  66 */    0xE5 /* 'e' -> */,
+/* pos 00fd:  67 */    0xE4 /* 'd' -> */,
+/* pos 00fe:  68 */    0xAD /* '-' -> */,
+/* pos 00ff:  69 */    0xF3 /* 's' -> */,
+/* pos 0100:  70 */    0xE9 /* 'i' -> */,
+/* pos 0101:  71 */    0xEE /* 'n' -> */,
+/* pos 0102:  72 */    0xE3 /* 'c' -> */,
+/* pos 0103:  73 */    0xE5 /* 'e' -> */,
+/* pos 0104:  74 */    0xBA /* ':' -> */,
+/* pos 0105:  75 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 0107:  76 */    0xEF /* 'o' -> */,
+/* pos 0108:  77 */    0xEE /* 'n' -> */,
+/* pos 0109:  78 */    0xE5 /* 'e' -> */,
+/* pos 010a:  79 */    0xAD /* '-' -> */,
+/* pos 010b:  80 */    0xED /* 'm' -> */,
+/* pos 010c:  81 */    0xE1 /* 'a' -> */,
+/* pos 010d:  82 */    0xF4 /* 't' -> */,
+/* pos 010e:  83 */    0xE3 /* 'c' -> */,
+/* pos 010f:  84 */    0xE8 /* 'h' -> */,
+/* pos 0110:  85 */    0xBA /* ':' -> */,
+/* pos 0111:  86 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 0113:  87 */    0x65 /* 'e' */, 0x0D, 0x00  /* (to 0x0120 state  88) */,
+                       0x6C /* 'l' */, 0x14, 0x00  /* (to 0x012A state  97) */,
+                       0x72 /* 'r' */, 0x8E, 0x00  /* (to 0x01A7 state 171) */,
+                       0x63 /* 'c' */, 0x14, 0x02  /* (to 0x0330 state 453) */,
+                       0x08, /* fail */
+/* pos 0120:  88 */    0xEE /* 'n' -> */,
+/* pos 0121:  89 */    0xE3 /* 'c' -> */,
+/* pos 0122:  90 */    0xEF /* 'o' -> */,
+/* pos 0123:  91 */    0xE4 /* 'd' -> */,
+/* pos 0124:  92 */    0xE9 /* 'i' -> */,
+/* pos 0125:  93 */    0xEE /* 'n' -> */,
+/* pos 0126:  94 */    0xE7 /* 'g' -> */,
+/* pos 0127:  95 */    0xBA /* ':' -> */,
+/* pos 0128:  96 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 012a:  97 */    0xE1 /* 'a' -> */,
+/* pos 012b:  98 */    0xEE /* 'n' -> */,
+/* pos 012c:  99 */    0xE7 /* 'g' -> */,
+/* pos 012d: 100 */    0xF5 /* 'u' -> */,
+/* pos 012e: 101 */    0xE1 /* 'a' -> */,
+/* pos 012f: 102 */    0xE7 /* 'g' -> */,
+/* pos 0130: 103 */    0xE5 /* 'e' -> */,
+/* pos 0131: 104 */    0xBA /* ':' -> */,
+/* pos 0132: 105 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 0134: 106 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x013B state 107) */,
+                       0x6F /* 'o' */, 0x1E, 0x02  /* (to 0x0355 state 487) */,
+                       0x08, /* fail */
+/* pos 013b: 107 */    0xE7 /* 'g' -> */,
+/* pos 013c: 108 */    0xED /* 'm' -> */,
+/* pos 013d: 109 */    0xE1 /* 'a' -> */,
+/* pos 013e: 110 */    0xBA /* ':' -> */,
+/* pos 013f: 111 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 0141: 112 */    0xE3 /* 'c' -> */,
+/* pos 0142: 113 */    0xE8 /* 'h' -> */,
+/* pos 0143: 114 */    0xE5 /* 'e' -> */,
+/* pos 0144: 115 */    0xAD /* '-' -> */,
+/* pos 0145: 116 */    0xE3 /* 'c' -> */,
+/* pos 0146: 117 */    0xEF /* 'o' -> */,
+/* pos 0147: 118 */    0xEE /* 'n' -> */,
+/* pos 0148: 119 */    0xF4 /* 't' -> */,
+/* pos 0149: 120 */    0xF2 /* 'r' -> */,
+/* pos 014a: 121 */    0xEF /* 'o' -> */,
+/* pos 014b: 122 */    0xEC /* 'l' -> */,
+/* pos 014c: 123 */    0xBA /* ':' -> */,
+/* pos 014d: 124 */    0x00, 0x0F                  /* - terminal marker 15 - */,
+/* pos 014f: 125 */    0xF4 /* 't' -> */,
+/* pos 0150: 126 */    0xE8 /* 'h' -> */,
+/* pos 0151: 127 */    0xEF /* 'o' -> */,
+/* pos 0152: 128 */    0xF2 /* 'r' -> */,
+/* pos 0153: 129 */    0xE9 /* 'i' -> */,
+/* pos 0154: 130 */    0xFA /* 'z' -> */,
+/* pos 0155: 131 */    0xE1 /* 'a' -> */,
+/* pos 0156: 132 */    0xF4 /* 't' -> */,
+/* pos 0157: 133 */    0xE9 /* 'i' -> */,
+/* pos 0158: 134 */    0xEF /* 'o' -> */,
+/* pos 0159: 135 */    0xEE /* 'n' -> */,
+/* pos 015a: 136 */    0xBA /* ':' -> */,
+/* pos 015b: 137 */    0x00, 0x10                  /* - terminal marker 16 - */,
+/* pos 015d: 138 */    0xEB /* 'k' -> */,
+/* pos 015e: 139 */    0xE9 /* 'i' -> */,
+/* pos 015f: 140 */    0xE5 /* 'e' -> */,
+/* pos 0160: 141 */    0xBA /* ':' -> */,
+/* pos 0161: 142 */    0x00, 0x11                  /* - terminal marker 17 - */,
+/* pos 0163: 143 */    0xE5 /* 'e' -> */,
+/* pos 0164: 144 */    0xEE /* 'n' -> */,
+/* pos 0165: 145 */    0xF4 /* 't' -> */,
+/* pos 0166: 146 */    0xAD /* '-' -> */,
+/* pos 0167: 147 */    0x6C /* 'l' */, 0x10, 0x00  /* (to 0x0177 state 148) */,
+                       0x74 /* 't' */, 0x1E, 0x00  /* (to 0x0188 state 155) */,
+                       0x64 /* 'd' */, 0x4C, 0x00  /* (to 0x01B9 state 186) */,
+                       0x65 /* 'e' */, 0x56, 0x00  /* (to 0x01C6 state 198) */,
+                       0x72 /* 'r' */, 0x6F, 0x00  /* (to 0x01E2 state 223) */,
+                       0x08, /* fail */
+/* pos 0177: 148 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x0181 state 149) */,
+                       0x61 /* 'a' */, 0x56, 0x00  /* (to 0x01D0 state 207) */,
+                       0x6F /* 'o' */, 0x5C, 0x00  /* (to 0x01D9 state 215) */,
+                       0x08, /* fail */
+/* pos 0181: 149 */    0xEE /* 'n' -> */,
+/* pos 0182: 150 */    0xE7 /* 'g' -> */,
+/* pos 0183: 151 */    0xF4 /* 't' -> */,
+/* pos 0184: 152 */    0xE8 /* 'h' -> */,
+/* pos 0185: 153 */    0xBA /* ':' -> */,
+/* pos 0186: 154 */    0x00, 0x12                  /* - terminal marker 18 - */,
+/* pos 0188: 155 */    0xF9 /* 'y' -> */,
+/* pos 0189: 156 */    0xF0 /* 'p' -> */,
+/* pos 018a: 157 */    0xE5 /* 'e' -> */,
+/* pos 018b: 158 */    0xBA /* ':' -> */,
+/* pos 018c: 159 */    0x00, 0x13                  /* - terminal marker 19 - */,
+/* pos 018e: 160 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0195 state 161) */,
+                       0x65 /* 'e' */, 0x3C, 0x02  /* (to 0x03CD state 580) */,
+                       0x08, /* fail */
+/* pos 0195: 161 */    0xF4 /* 't' -> */,
+/* pos 0196: 162 */    0xE5 /* 'e' -> */,
+/* pos 0197: 163 */    0xBA /* ':' -> */,
+/* pos 0198: 164 */    0x00, 0x14                  /* - terminal marker 20 - */,
+/* pos 019a: 165 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x01A1 state 166) */,
+                       0x65 /* 'e' */, 0xB6, 0x00  /* (to 0x0253 state 304) */,
+                       0x08, /* fail */
+/* pos 01a1: 166 */    0xEE /* 'n' -> */,
+/* pos 01a2: 167 */    0xE7 /* 'g' -> */,
+/* pos 01a3: 168 */    0xE5 /* 'e' -> */,
+/* pos 01a4: 169 */    0xBA /* ':' -> */,
+/* pos 01a5: 170 */    0x00, 0x15                  /* - terminal marker 21 - */,
+/* pos 01a7: 171 */    0xE1 /* 'a' -> */,
+/* pos 01a8: 172 */    0xEE /* 'n' -> */,
+/* pos 01a9: 173 */    0xE7 /* 'g' -> */,
+/* pos 01aa: 174 */    0xE5 /* 'e' -> */,
+/* pos 01ab: 175 */    0xF3 /* 's' -> */,
+/* pos 01ac: 176 */    0xBA /* ':' -> */,
+/* pos 01ad: 177 */    0x00, 0x1D                  /* - terminal marker 29 - */,
+/* pos 01af: 178 */    0xE5 /* 'e' -> */,
+/* pos 01b0: 179 */    0xBA /* ':' -> */,
+/* pos 01b1: 180 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 01b3: 181 */    0xEC /* 'l' -> */,
+/* pos 01b4: 182 */    0xEF /* 'o' -> */,
+/* pos 01b5: 183 */    0xF7 /* 'w' -> */,
+/* pos 01b6: 184 */    0xBA /* ':' -> */,
+/* pos 01b7: 185 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 01b9: 186 */    0xE9 /* 'i' -> */,
+/* pos 01ba: 187 */    0xF3 /* 's' -> */,
+/* pos 01bb: 188 */    0xF0 /* 'p' -> */,
+/* pos 01bc: 189 */    0xEF /* 'o' -> */,
+/* pos 01bd: 190 */    0xF3 /* 's' -> */,
+/* pos 01be: 191 */    0xE9 /* 'i' -> */,
+/* pos 01bf: 192 */    0xF4 /* 't' -> */,
+/* pos 01c0: 193 */    0xE9 /* 'i' -> */,
+/* pos 01c1: 194 */    0xEF /* 'o' -> */,
+/* pos 01c2: 195 */    0xEE /* 'n' -> */,
+/* pos 01c3: 196 */    0xBA /* ':' -> */,
+/* pos 01c4: 197 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* pos 01c6: 198 */    0xEE /* 'n' -> */,
+/* pos 01c7: 199 */    0xE3 /* 'c' -> */,
+/* pos 01c8: 200 */    0xEF /* 'o' -> */,
+/* pos 01c9: 201 */    0xE4 /* 'd' -> */,
+/* pos 01ca: 202 */    0xE9 /* 'i' -> */,
+/* pos 01cb: 203 */    0xEE /* 'n' -> */,
+/* pos 01cc: 204 */    0xE7 /* 'g' -> */,
+/* pos 01cd: 205 */    0xBA /* ':' -> */,
+/* pos 01ce: 206 */    0x00, 0x22                  /* - terminal marker 34 - */,
+/* pos 01d0: 207 */    0xEE /* 'n' -> */,
+/* pos 01d1: 208 */    0xE7 /* 'g' -> */,
+/* pos 01d2: 209 */    0xF5 /* 'u' -> */,
+/* pos 01d3: 210 */    0xE1 /* 'a' -> */,
+/* pos 01d4: 211 */    0xE7 /* 'g' -> */,
+/* pos 01d5: 212 */    0xE5 /* 'e' -> */,
+/* pos 01d6: 213 */    0xBA /* ':' -> */,
+/* pos 01d7: 214 */    0x00, 0x23                  /* - terminal marker 35 - */,
+/* pos 01d9: 215 */    0xE3 /* 'c' -> */,
+/* pos 01da: 216 */    0xE1 /* 'a' -> */,
+/* pos 01db: 217 */    0xF4 /* 't' -> */,
+/* pos 01dc: 218 */    0xE9 /* 'i' -> */,
+/* pos 01dd: 219 */    0xEF /* 'o' -> */,
+/* pos 01de: 220 */    0xEE /* 'n' -> */,
+/* pos 01df: 221 */    0xBA /* ':' -> */,
+/* pos 01e0: 222 */    0x00, 0x24                  /* - terminal marker 36 - */,
+/* pos 01e2: 223 */    0xE1 /* 'a' -> */,
+/* pos 01e3: 224 */    0xEE /* 'n' -> */,
+/* pos 01e4: 225 */    0xE7 /* 'g' -> */,
+/* pos 01e5: 226 */    0xE5 /* 'e' -> */,
+/* pos 01e6: 227 */    0xBA /* ':' -> */,
+/* pos 01e7: 228 */    0x00, 0x25                  /* - terminal marker 37 - */,
+/* pos 01e9: 229 */    0x74 /* 't' */, 0x07, 0x00  /* (to 0x01F0 state 230) */,
+                       0x78 /* 'x' */, 0x09, 0x00  /* (to 0x01F5 state 234) */,
+                       0x08, /* fail */
+/* pos 01f0: 230 */    0xE1 /* 'a' -> */,
+/* pos 01f1: 231 */    0xE7 /* 'g' -> */,
+/* pos 01f2: 232 */    0xBA /* ':' -> */,
+/* pos 01f3: 233 */    0x00, 0x26                  /* - terminal marker 38 - */,
+/* pos 01f5: 234 */    0xF0 /* 'p' -> */,
+/* pos 01f6: 235 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x01FD state 236) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x0202 state 240) */,
+                       0x08, /* fail */
+/* pos 01fd: 236 */    0xE3 /* 'c' -> */,
+/* pos 01fe: 237 */    0xF4 /* 't' -> */,
+/* pos 01ff: 238 */    0xBA /* ':' -> */,
+/* pos 0200: 239 */    0x00, 0x27                  /* - terminal marker 39 - */,
+/* pos 0202: 240 */    0xF2 /* 'r' -> */,
+/* pos 0203: 241 */    0xE5 /* 'e' -> */,
+/* pos 0204: 242 */    0xF3 /* 's' -> */,
+/* pos 0205: 243 */    0xBA /* ':' -> */,
+/* pos 0206: 244 */    0x00, 0x28                  /* - terminal marker 40 - */,
+/* pos 0208: 245 */    0xF2 /* 'r' -> */,
+/* pos 0209: 246 */    0xEF /* 'o' -> */,
+/* pos 020a: 247 */    0xED /* 'm' -> */,
+/* pos 020b: 248 */    0xBA /* ':' -> */,
+/* pos 020c: 249 */    0x00, 0x29                  /* - terminal marker 41 - */,
 /* pos 020e: 250 */    0xF4 /* 't' -> */,
-/* pos 020f: 251 */    0xAD /* '-' -> */,
-/* pos 0210: 252 */    0x6C /* 'l' */, 0x10, 0x00  /* (to 0x0220 state 253) */,
-                       0x74 /* 't' */, 0x1E, 0x00  /* (to 0x0231 state 260) */,
-                       0x64 /* 'd' */, 0xC9, 0x00  /* (to 0x02DF state 366) */,
-                       0x65 /* 'e' */, 0xD3, 0x00  /* (to 0x02EC state 378) */,
-                       0x72 /* 'r' */, 0xEC, 0x00  /* (to 0x0308 state 403) */,
-                       0x08, /* fail */
-/* pos 0220: 253 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x022A state 254) */,
-                       0x61 /* 'a' */, 0xD3, 0x00  /* (to 0x02F6 state 387) */,
-                       0x6F /* 'o' */, 0xD9, 0x00  /* (to 0x02FF state 395) */,
-                       0x08, /* fail */
-/* pos 022a: 254 */    0xEE /* 'n' -> */,
-/* pos 022b: 255 */    0xE7 /* 'g' -> */,
-/* pos 022c: 256 */    0xF4 /* 't' -> */,
-/* pos 022d: 257 */    0xE8 /* 'h' -> */,
-/* pos 022e: 258 */    0xBA /* ':' -> */,
-/* pos 022f: 259 */    0x00, 0x1B                  /* - terminal marker 27 - */,
-/* pos 0231: 260 */    0xF9 /* 'y' -> */,
-/* pos 0232: 261 */    0xF0 /* 'p' -> */,
-/* pos 0233: 262 */    0xE5 /* 'e' -> */,
-/* pos 0234: 263 */    0xBA /* ':' -> */,
-/* pos 0235: 264 */    0x00, 0x1C                  /* - terminal marker 28 - */,
-/* pos 0237: 265 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x023E state 266) */,
-                       0x65 /* 'e' */, 0xFF, 0x01  /* (to 0x0439 state 637) */,
-                       0x08, /* fail */
-/* pos 023e: 266 */    0xF4 /* 't' -> */,
-/* pos 023f: 267 */    0xE5 /* 'e' -> */,
-/* pos 0240: 268 */    0xBA /* ':' -> */,
-/* pos 0241: 269 */    0x00, 0x1D                  /* - terminal marker 29 - */,
-/* pos 0243: 270 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x024A state 271) */,
-                       0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x0250 state 276) */,
-                       0x08, /* fail */
-/* pos 024a: 271 */    0xEE /* 'n' -> */,
-/* pos 024b: 272 */    0xE7 /* 'g' -> */,
-/* pos 024c: 273 */    0xE5 /* 'e' -> */,
-/* pos 024d: 274 */    0xBA /* ':' -> */,
-/* pos 024e: 275 */    0x00, 0x1E                  /* - terminal marker 30 - */,
-/* pos 0250: 276 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x025A state 277) */,
-                       0x74 /* 't' */, 0x63, 0x01  /* (to 0x03B6 state 529) */,
-                       0x70 /* 'p' */, 0x23, 0x02  /* (to 0x0479 state 683) */,
-                       0x08, /* fail */
-/* pos 025a: 277 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0261 state 278) */,
-                       0x72 /* 'r' */, 0x53, 0x01  /* (to 0x03B0 state 524) */,
-                       0x08, /* fail */
-/* pos 0261: 278 */    0xF2 /* 'r' -> */,
-/* pos 0262: 279 */    0xE5 /* 'e' -> */,
-/* pos 0263: 280 */    0xF2 /* 'r' -> */,
-/* pos 0264: 281 */    0xBA /* ':' -> */,
-/* pos 0265: 282 */    0x00, 0x1F                  /* - terminal marker 31 - */,
-/* pos 0267: 283 */    0x00, 0x20                  /* - terminal marker 32 - */,
-/* pos 0269: 284 */    0xE5 /* 'e' -> */,
-/* pos 026a: 285 */    0xF2 /* 'r' -> */,
-/* pos 026b: 286 */    0xF3 /* 's' -> */,
-/* pos 026c: 287 */    0xE9 /* 'i' -> */,
-/* pos 026d: 288 */    0xEF /* 'o' -> */,
-/* pos 026e: 289 */    0xEE /* 'n' -> */,
-/* pos 026f: 290 */    0xBA /* ':' -> */,
-/* pos 0270: 291 */    0x00, 0x21                  /* - terminal marker 33 - */,
-/* pos 0272: 292 */    0xF2 /* 'r' -> */,
-/* pos 0273: 293 */    0xE9 /* 'i' -> */,
-/* pos 0274: 294 */    0xE7 /* 'g' -> */,
-/* pos 0275: 295 */    0xE9 /* 'i' -> */,
-/* pos 0276: 296 */    0xEE /* 'n' -> */,
-/* pos 0277: 297 */    0xBA /* ':' -> */,
-/* pos 0278: 298 */    0x00, 0x22                  /* - terminal marker 34 - */,
-/* pos 027a: 299 */    0x61 /* 'a' */, 0x0D, 0x00  /* (to 0x0287 state 300) */,
-                       0x6D /* 'm' */, 0x14, 0x00  /* (to 0x0291 state 309) */,
-                       0x70 /* 'p' */, 0x18, 0x00  /* (to 0x0298 state 315) */,
-                       0x73 /* 's' */, 0x20, 0x00  /* (to 0x02A3 state 319) */,
-                       0x08, /* fail */
-/* pos 0287: 300 */    0xF5 /* 'u' -> */,
-/* pos 0288: 301 */    0xF4 /* 't' -> */,
-/* pos 0289: 302 */    0xE8 /* 'h' -> */,
-/* pos 028a: 303 */    0xEF /* 'o' -> */,
-/* pos 028b: 304 */    0xF2 /* 'r' -> */,
-/* pos 028c: 305 */    0xE9 /* 'i' -> */,
-/* pos 028d: 306 */    0xF4 /* 't' -> */,
-/* pos 028e: 307 */    0xF9 /* 'y' -> */,
-/* pos 028f: 308 */    0x00, 0x23                  /* - terminal marker 35 - */,
-/* pos 0291: 309 */    0xE5 /* 'e' -> */,
-/* pos 0292: 310 */    0xF4 /* 't' -> */,
-/* pos 0293: 311 */    0xE8 /* 'h' -> */,
-/* pos 0294: 312 */    0xEF /* 'o' -> */,
-/* pos 0295: 313 */    0xE4 /* 'd' -> */,
-/* pos 0296: 314 */    0x00, 0x24                  /* - terminal marker 36 - */,
-/* pos 0298: 315 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x029F state 316) */,
-                       0x72 /* 'r' */, 0xEA, 0x01  /* (to 0x0485 state 694) */,
-                       0x08, /* fail */
-/* pos 029f: 316 */    0xF4 /* 't' -> */,
-/* pos 02a0: 317 */    0xE8 /* 'h' -> */,
-/* pos 02a1: 318 */    0x00, 0x25                  /* - terminal marker 37 - */,
-/* pos 02a3: 319 */    0x63 /* 'c' */, 0x07, 0x00  /* (to 0x02AA state 320) */,
-                       0x74 /* 't' */, 0x0A, 0x00  /* (to 0x02B0 state 325) */,
-                       0x08, /* fail */
-/* pos 02aa: 320 */    0xE8 /* 'h' -> */,
-/* pos 02ab: 321 */    0xE5 /* 'e' -> */,
-/* pos 02ac: 322 */    0xED /* 'm' -> */,
-/* pos 02ad: 323 */    0xE5 /* 'e' -> */,
-/* pos 02ae: 324 */    0x00, 0x26                  /* - terminal marker 38 - */,
-/* pos 02b0: 325 */    0xE1 /* 'a' -> */,
-/* pos 02b1: 326 */    0xF4 /* 't' -> */,
-/* pos 02b2: 327 */    0xF5 /* 'u' -> */,
-/* pos 02b3: 328 */    0xF3 /* 's' -> */,
-/* pos 02b4: 329 */    0x00, 0x27                  /* - terminal marker 39 - */,
-/* pos 02b6: 330 */    0xE8 /* 'h' -> */,
-/* pos 02b7: 331 */    0xE1 /* 'a' -> */,
-/* pos 02b8: 332 */    0xF2 /* 'r' -> */,
-/* pos 02b9: 333 */    0xF3 /* 's' -> */,
-/* pos 02ba: 334 */    0xE5 /* 'e' -> */,
-/* pos 02bb: 335 */    0xF4 /* 't' -> */,
-/* pos 02bc: 336 */    0xBA /* ':' -> */,
-/* pos 02bd: 337 */    0x00, 0x28                  /* - terminal marker 40 - */,
-/* pos 02bf: 338 */    0xE1 /* 'a' -> */,
-/* pos 02c0: 339 */    0xEE /* 'n' -> */,
-/* pos 02c1: 340 */    0xE7 /* 'g' -> */,
-/* pos 02c2: 341 */    0xE5 /* 'e' -> */,
-/* pos 02c3: 342 */    0xF3 /* 's' -> */,
-/* pos 02c4: 343 */    0xBA /* ':' -> */,
-/* pos 02c5: 344 */    0x00, 0x29                  /* - terminal marker 41 - */,
-/* pos 02c7: 345 */    0xEC /* 'l' -> */,
-/* pos 02c8: 346 */    0xEC /* 'l' -> */,
-/* pos 02c9: 347 */    0xEF /* 'o' -> */,
-/* pos 02ca: 348 */    0xF7 /* 'w' -> */,
-/* pos 02cb: 349 */    0xAD /* '-' -> */,
-/* pos 02cc: 350 */    0xEF /* 'o' -> */,
-/* pos 02cd: 351 */    0xF2 /* 'r' -> */,
-/* pos 02ce: 352 */    0xE9 /* 'i' -> */,
-/* pos 02cf: 353 */    0xE7 /* 'g' -> */,
-/* pos 02d0: 354 */    0xE9 /* 'i' -> */,
-/* pos 02d1: 355 */    0xEE /* 'n' -> */,
-/* pos 02d2: 356 */    0xBA /* ':' -> */,
-/* pos 02d3: 357 */    0x00, 0x2A                  /* - terminal marker 42 - */,
-/* pos 02d5: 358 */    0xE5 /* 'e' -> */,
-/* pos 02d6: 359 */    0xBA /* ':' -> */,
-/* pos 02d7: 360 */    0x00, 0x2B                  /* - terminal marker 43 - */,
-/* pos 02d9: 361 */    0xEC /* 'l' -> */,
-/* pos 02da: 362 */    0xEF /* 'o' -> */,
-/* pos 02db: 363 */    0xF7 /* 'w' -> */,
-/* pos 02dc: 364 */    0xBA /* ':' -> */,
-/* pos 02dd: 365 */    0x00, 0x2C                  /* - terminal marker 44 - */,
-/* pos 02df: 366 */    0xE9 /* 'i' -> */,
-/* pos 02e0: 367 */    0xF3 /* 's' -> */,
-/* pos 02e1: 368 */    0xF0 /* 'p' -> */,
-/* pos 02e2: 369 */    0xEF /* 'o' -> */,
-/* pos 02e3: 370 */    0xF3 /* 's' -> */,
-/* pos 02e4: 371 */    0xE9 /* 'i' -> */,
-/* pos 02e5: 372 */    0xF4 /* 't' -> */,
-/* pos 02e6: 373 */    0xE9 /* 'i' -> */,
-/* pos 02e7: 374 */    0xEF /* 'o' -> */,
-/* pos 02e8: 375 */    0xEE /* 'n' -> */,
-/* pos 02e9: 376 */    0xBA /* ':' -> */,
-/* pos 02ea: 377 */    0x00, 0x2D                  /* - terminal marker 45 - */,
-/* pos 02ec: 378 */    0xEE /* 'n' -> */,
-/* pos 02ed: 379 */    0xE3 /* 'c' -> */,
-/* pos 02ee: 380 */    0xEF /* 'o' -> */,
-/* pos 02ef: 381 */    0xE4 /* 'd' -> */,
-/* pos 02f0: 382 */    0xE9 /* 'i' -> */,
-/* pos 02f1: 383 */    0xEE /* 'n' -> */,
-/* pos 02f2: 384 */    0xE7 /* 'g' -> */,
-/* pos 02f3: 385 */    0xBA /* ':' -> */,
-/* pos 02f4: 386 */    0x00, 0x2E                  /* - terminal marker 46 - */,
-/* pos 02f6: 387 */    0xEE /* 'n' -> */,
-/* pos 02f7: 388 */    0xE7 /* 'g' -> */,
-/* pos 02f8: 389 */    0xF5 /* 'u' -> */,
-/* pos 02f9: 390 */    0xE1 /* 'a' -> */,
-/* pos 02fa: 391 */    0xE7 /* 'g' -> */,
-/* pos 02fb: 392 */    0xE5 /* 'e' -> */,
-/* pos 02fc: 393 */    0xBA /* ':' -> */,
-/* pos 02fd: 394 */    0x00, 0x2F                  /* - terminal marker 47 - */,
-/* pos 02ff: 395 */    0xE3 /* 'c' -> */,
-/* pos 0300: 396 */    0xE1 /* 'a' -> */,
-/* pos 0301: 397 */    0xF4 /* 't' -> */,
-/* pos 0302: 398 */    0xE9 /* 'i' -> */,
-/* pos 0303: 399 */    0xEF /* 'o' -> */,
-/* pos 0304: 400 */    0xEE /* 'n' -> */,
-/* pos 0305: 401 */    0xBA /* ':' -> */,
-/* pos 0306: 402 */    0x00, 0x30                  /* - terminal marker 48 - */,
-/* pos 0308: 403 */    0xE1 /* 'a' -> */,
-/* pos 0309: 404 */    0xEE /* 'n' -> */,
-/* pos 030a: 405 */    0xE7 /* 'g' -> */,
-/* pos 030b: 406 */    0xE5 /* 'e' -> */,
-/* pos 030c: 407 */    0xBA /* ':' -> */,
-/* pos 030d: 408 */    0x00, 0x31                  /* - terminal marker 49 - */,
-/* pos 030f: 409 */    0x74 /* 't' */, 0x07, 0x00  /* (to 0x0316 state 410) */,
-                       0x78 /* 'x' */, 0x09, 0x00  /* (to 0x031B state 414) */,
-                       0x08, /* fail */
-/* pos 0316: 410 */    0xE1 /* 'a' -> */,
-/* pos 0317: 411 */    0xE7 /* 'g' -> */,
-/* pos 0318: 412 */    0xBA /* ':' -> */,
-/* pos 0319: 413 */    0x00, 0x32                  /* - terminal marker 50 - */,
-/* pos 031b: 414 */    0xF0 /* 'p' -> */,
-/* pos 031c: 415 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0323 state 416) */,
-                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x0328 state 420) */,
-                       0x08, /* fail */
-/* pos 0323: 416 */    0xE3 /* 'c' -> */,
-/* pos 0324: 417 */    0xF4 /* 't' -> */,
-/* pos 0325: 418 */    0xBA /* ':' -> */,
-/* pos 0326: 419 */    0x00, 0x33                  /* - terminal marker 51 - */,
-/* pos 0328: 420 */    0xF2 /* 'r' -> */,
-/* pos 0329: 421 */    0xE5 /* 'e' -> */,
-/* pos 032a: 422 */    0xF3 /* 's' -> */,
-/* pos 032b: 423 */    0xBA /* ':' -> */,
-/* pos 032c: 424 */    0x00, 0x34                  /* - terminal marker 52 - */,
-/* pos 032e: 425 */    0xF2 /* 'r' -> */,
-/* pos 032f: 426 */    0xEF /* 'o' -> */,
-/* pos 0330: 427 */    0xED /* 'm' -> */,
-/* pos 0331: 428 */    0xBA /* ':' -> */,
-/* pos 0332: 429 */    0x00, 0x35                  /* - terminal marker 53 - */,
-/* pos 0334: 430 */    0xF4 /* 't' -> */,
-/* pos 0335: 431 */    0xE3 /* 'c' -> */,
-/* pos 0336: 432 */    0xE8 /* 'h' -> */,
-/* pos 0337: 433 */    0xBA /* ':' -> */,
-/* pos 0338: 434 */    0x00, 0x36                  /* - terminal marker 54 - */,
-/* pos 033a: 435 */    0xE1 /* 'a' -> */,
-/* pos 033b: 436 */    0xEE /* 'n' -> */,
-/* pos 033c: 437 */    0xE7 /* 'g' -> */,
-/* pos 033d: 438 */    0xE5 /* 'e' -> */,
-/* pos 033e: 439 */    0xBA /* ':' -> */,
-/* pos 033f: 440 */    0x00, 0x37                  /* - terminal marker 55 - */,
-/* pos 0341: 441 */    0xEE /* 'n' -> */,
-/* pos 0342: 442 */    0xED /* 'm' -> */,
-/* pos 0343: 443 */    0xEF /* 'o' -> */,
-/* pos 0344: 444 */    0xE4 /* 'd' -> */,
-/* pos 0345: 445 */    0xE9 /* 'i' -> */,
-/* pos 0346: 446 */    0xE6 /* 'f' -> */,
-/* pos 0347: 447 */    0xE9 /* 'i' -> */,
-/* pos 0348: 448 */    0xE5 /* 'e' -> */,
-/* pos 0349: 449 */    0xE4 /* 'd' -> */,
-/* pos 034a: 450 */    0xAD /* '-' -> */,
-/* pos 034b: 451 */    0xF3 /* 's' -> */,
-/* pos 034c: 452 */    0xE9 /* 'i' -> */,
-/* pos 034d: 453 */    0xEE /* 'n' -> */,
-/* pos 034e: 454 */    0xE3 /* 'c' -> */,
-/* pos 034f: 455 */    0xE5 /* 'e' -> */,
-/* pos 0350: 456 */    0xBA /* ':' -> */,
-/* pos 0351: 457 */    0x00, 0x38                  /* - terminal marker 56 - */,
-/* pos 0353: 458 */    0x61 /* 'a' */, 0x0A, 0x00  /* (to 0x035D state 459) */,
-                       0x69 /* 'i' */, 0x15, 0x00  /* (to 0x036B state 472) */,
-                       0x6F /* 'o' */, 0x17, 0x00  /* (to 0x0370 state 476) */,
-                       0x08, /* fail */
-/* pos 035d: 459 */    0xF3 /* 's' -> */,
-/* pos 035e: 460 */    0xF4 /* 't' -> */,
-/* pos 035f: 461 */    0xAD /* '-' -> */,
-/* pos 0360: 462 */    0xED /* 'm' -> */,
-/* pos 0361: 463 */    0xEF /* 'o' -> */,
-/* pos 0362: 464 */    0xE4 /* 'd' -> */,
-/* pos 0363: 465 */    0xE9 /* 'i' -> */,
-/* pos 0364: 466 */    0xE6 /* 'f' -> */,
-/* pos 0365: 467 */    0xE9 /* 'i' -> */,
-/* pos 0366: 468 */    0xE5 /* 'e' -> */,
-/* pos 0367: 469 */    0xE4 /* 'd' -> */,
-/* pos 0368: 470 */    0xBA /* ':' -> */,
-/* pos 0369: 471 */    0x00, 0x39                  /* - terminal marker 57 - */,
-/* pos 036b: 472 */    0xEE /* 'n' -> */,
-/* pos 036c: 473 */    0xEB /* 'k' -> */,
-/* pos 036d: 474 */    0xBA /* ':' -> */,
-/* pos 036e: 475 */    0x00, 0x3A                  /* - terminal marker 58 - */,
-/* pos 0370: 476 */    0xE3 /* 'c' -> */,
-/* pos 0371: 477 */    0xE1 /* 'a' -> */,
-/* pos 0372: 478 */    0xF4 /* 't' -> */,
-/* pos 0373: 479 */    0xE9 /* 'i' -> */,
-/* pos 0374: 480 */    0xEF /* 'o' -> */,
-/* pos 0375: 481 */    0xEE /* 'n' -> */,
-/* pos 0376: 482 */    0xBA /* ':' -> */,
-/* pos 0377: 483 */    0x00, 0x3B                  /* - terminal marker 59 - */,
-/* pos 0379: 484 */    0xE1 /* 'a' -> */,
-/* pos 037a: 485 */    0xF8 /* 'x' -> */,
-/* pos 037b: 486 */    0xAD /* '-' -> */,
-/* pos 037c: 487 */    0xE6 /* 'f' -> */,
-/* pos 037d: 488 */    0xEF /* 'o' -> */,
-/* pos 037e: 489 */    0xF2 /* 'r' -> */,
-/* pos 037f: 490 */    0xF7 /* 'w' -> */,
-/* pos 0380: 491 */    0xE1 /* 'a' -> */,
-/* pos 0381: 492 */    0xF2 /* 'r' -> */,
-/* pos 0382: 493 */    0xE4 /* 'd' -> */,
-/* pos 0383: 494 */    0xF3 /* 's' -> */,
-/* pos 0384: 495 */    0xBA /* ':' -> */,
-/* pos 0385: 496 */    0x00, 0x3C                  /* - terminal marker 60 - */,
-/* pos 0387: 497 */    0xF8 /* 'x' -> */,
-/* pos 0388: 498 */    0xF9 /* 'y' -> */,
-/* pos 0389: 499 */    0x2D /* '-' */, 0x07, 0x00  /* (to 0x0390 state 500) */,
-                       0x20 /* ' ' */, 0xBB, 0x00  /* (to 0x0447 state 649) */,
-                       0x08, /* fail */
-/* pos 0390: 500 */    0xE1 /* 'a' -> */,
-/* pos 0391: 501 */    0xF5 /* 'u' -> */,
-/* pos 0392: 502 */    0xF4 /* 't' -> */,
-/* pos 0393: 503 */    0xE8 /* 'h' -> */,
-/* pos 0394: 504 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x039B state 505) */,
-                       0x6F /* 'o' */, 0x0E, 0x00  /* (to 0x03A5 state 514) */,
-                       0x08, /* fail */
-/* pos 039b: 505 */    0xEE /* 'n' -> */,
-/* pos 039c: 506 */    0xF4 /* 't' -> */,
-/* pos 039d: 507 */    0xE9 /* 'i' -> */,
-/* pos 039e: 508 */    0xE3 /* 'c' -> */,
-/* pos 039f: 509 */    0xE1 /* 'a' -> */,
-/* pos 03a0: 510 */    0xF4 /* 't' -> */,
-/* pos 03a1: 511 */    0xE5 /* 'e' -> */,
-/* pos 03a2: 512 */    0xBA /* ':' -> */,
-/* pos 03a3: 513 */    0x00, 0x3D                  /* - terminal marker 61 - */,
-/* pos 03a5: 514 */    0xF2 /* 'r' -> */,
-/* pos 03a6: 515 */    0xE9 /* 'i' -> */,
-/* pos 03a7: 516 */    0xFA /* 'z' -> */,
-/* pos 03a8: 517 */    0xE1 /* 'a' -> */,
-/* pos 03a9: 518 */    0xF4 /* 't' -> */,
-/* pos 03aa: 519 */    0xE9 /* 'i' -> */,
-/* pos 03ab: 520 */    0xEF /* 'o' -> */,
-/* pos 03ac: 521 */    0xEE /* 'n' -> */,
-/* pos 03ad: 522 */    0xBA /* ':' -> */,
-/* pos 03ae: 523 */    0x00, 0x3E                  /* - terminal marker 62 - */,
-/* pos 03b0: 524 */    0xE5 /* 'e' -> */,
-/* pos 03b1: 525 */    0xF3 /* 's' -> */,
-/* pos 03b2: 526 */    0xE8 /* 'h' -> */,
-/* pos 03b3: 527 */    0xBA /* ':' -> */,
-/* pos 03b4: 528 */    0x00, 0x3F                  /* - terminal marker 63 - */,
-/* pos 03b6: 529 */    0xF2 /* 'r' -> */,
-/* pos 03b7: 530 */    0xF9 /* 'y' -> */,
-/* pos 03b8: 531 */    0xAD /* '-' -> */,
-/* pos 03b9: 532 */    0xE1 /* 'a' -> */,
-/* pos 03ba: 533 */    0xE6 /* 'f' -> */,
-/* pos 03bb: 534 */    0xF4 /* 't' -> */,
-/* pos 03bc: 535 */    0xE5 /* 'e' -> */,
-/* pos 03bd: 536 */    0xF2 /* 'r' -> */,
-/* pos 03be: 537 */    0xBA /* ':' -> */,
-/* pos 03bf: 538 */    0x00, 0x40                  /* - terminal marker 64 - */,
-/* pos 03c1: 539 */    0xF6 /* 'v' -> */,
-/* pos 03c2: 540 */    0xE5 /* 'e' -> */,
-/* pos 03c3: 541 */    0xF2 /* 'r' -> */,
-/* pos 03c4: 542 */    0xBA /* ':' -> */,
-/* pos 03c5: 543 */    0x00, 0x41                  /* - terminal marker 65 - */,
-/* pos 03c7: 544 */    0xAD /* '-' -> */,
-/* pos 03c8: 545 */    0xE3 /* 'c' -> */,
-/* pos 03c9: 546 */    0xEF /* 'o' -> */,
-/* pos 03ca: 547 */    0xEF /* 'o' -> */,
-/* pos 03cb: 548 */    0xEB /* 'k' -> */,
-/* pos 03cc: 549 */    0xE9 /* 'i' -> */,
-/* pos 03cd: 550 */    0xE5 /* 'e' -> */,
-/* pos 03ce: 551 */    0xBA /* ':' -> */,
-/* pos 03cf: 552 */    0x00, 0x42                  /* - terminal marker 66 - */,
-/* pos 03d1: 553 */    0xF2 /* 'r' -> */,
-/* pos 03d2: 554 */    0xE9 /* 'i' -> */,
-/* pos 03d3: 555 */    0xE3 /* 'c' -> */,
-/* pos 03d4: 556 */    0xF4 /* 't' -> */,
-/* pos 03d5: 557 */    0xAD /* '-' -> */,
-/* pos 03d6: 558 */    0xF4 /* 't' -> */,
-/* pos 03d7: 559 */    0xF2 /* 'r' -> */,
-/* pos 03d8: 560 */    0xE1 /* 'a' -> */,
-/* pos 03d9: 561 */    0xEE /* 'n' -> */,
-/* pos 03da: 562 */    0xF3 /* 's' -> */,
-/* pos 03db: 563 */    0xF0 /* 'p' -> */,
-/* pos 03dc: 564 */    0xEF /* 'o' -> */,
-/* pos 03dd: 565 */    0xF2 /* 'r' -> */,
-/* pos 03de: 566 */    0xF4 /* 't' -> */,
-/* pos 03df: 567 */    0xAD /* '-' -> */,
-/* pos 03e0: 568 */    0xF3 /* 's' -> */,
-/* pos 03e1: 569 */    0xE5 /* 'e' -> */,
-/* pos 03e2: 570 */    0xE3 /* 'c' -> */,
-/* pos 03e3: 571 */    0xF5 /* 'u' -> */,
-/* pos 03e4: 572 */    0xF2 /* 'r' -> */,
-/* pos 03e5: 573 */    0xE9 /* 'i' -> */,
-/* pos 03e6: 574 */    0xF4 /* 't' -> */,
-/* pos 03e7: 575 */    0xF9 /* 'y' -> */,
-/* pos 03e8: 576 */    0xBA /* ':' -> */,
-/* pos 03e9: 577 */    0x00, 0x43                  /* - terminal marker 67 - */,
-/* pos 03eb: 578 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x03F2 state 579) */,
-                       0x65 /* 'e' */, 0x88, 0x00  /* (to 0x0476 state 681) */,
-                       0x08, /* fail */
-/* pos 03f2: 579 */    0xE1 /* 'a' -> */,
-/* pos 03f3: 580 */    0xEE /* 'n' -> */,
-/* pos 03f4: 581 */    0xF3 /* 's' -> */,
-/* pos 03f5: 582 */    0xE6 /* 'f' -> */,
-/* pos 03f6: 583 */    0xE5 /* 'e' -> */,
-/* pos 03f7: 584 */    0xF2 /* 'r' -> */,
-/* pos 03f8: 585 */    0xAD /* '-' -> */,
-/* pos 03f9: 586 */    0xE5 /* 'e' -> */,
-/* pos 03fa: 587 */    0xEE /* 'n' -> */,
-/* pos 03fb: 588 */    0xE3 /* 'c' -> */,
-/* pos 03fc: 589 */    0xEF /* 'o' -> */,
-/* pos 03fd: 590 */    0xE4 /* 'd' -> */,
-/* pos 03fe: 591 */    0xE9 /* 'i' -> */,
-/* pos 03ff: 592 */    0xEE /* 'n' -> */,
-/* pos 0400: 593 */    0xE7 /* 'g' -> */,
-/* pos 0401: 594 */    0xBA /* ':' -> */,
-/* pos 0402: 595 */    0x00, 0x44                  /* - terminal marker 68 - */,
-/* pos 0404: 596 */    0xE5 /* 'e' -> */,
-/* pos 0405: 597 */    0xF2 /* 'r' -> */,
-/* pos 0406: 598 */    0xAD /* '-' -> */,
-/* pos 0407: 599 */    0xE1 /* 'a' -> */,
-/* pos 0408: 600 */    0xE7 /* 'g' -> */,
-/* pos 0409: 601 */    0xE5 /* 'e' -> */,
-/* pos 040a: 602 */    0xEE /* 'n' -> */,
-/* pos 040b: 603 */    0xF4 /* 't' -> */,
-/* pos 040c: 604 */    0xBA /* ':' -> */,
-/* pos 040d: 605 */    0x00, 0x45                  /* - terminal marker 69 - */,
-/* pos 040f: 606 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0416 state 607) */,
-                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x041B state 611) */,
-                       0x08, /* fail */
-/* pos 0416: 607 */    0xF2 /* 'r' -> */,
-/* pos 0417: 608 */    0xF9 /* 'y' -> */,
-/* pos 0418: 609 */    0xBA /* ':' -> */,
-/* pos 0419: 610 */    0x00, 0x46                  /* - terminal marker 70 - */,
-/* pos 041b: 611 */    0xE1 /* 'a' -> */,
-/* pos 041c: 612 */    0xBA /* ':' -> */,
-/* pos 041d: 613 */    0x00, 0x47                  /* - terminal marker 71 - */,
-/* pos 041f: 614 */    0xF7 /* 'w' -> */,
-/* pos 0420: 615 */    0xF7 /* 'w' -> */,
-/* pos 0421: 616 */    0xAD /* '-' -> */,
-/* pos 0422: 617 */    0xE1 /* 'a' -> */,
-/* pos 0423: 618 */    0xF5 /* 'u' -> */,
-/* pos 0424: 619 */    0xF4 /* 't' -> */,
-/* pos 0425: 620 */    0xE8 /* 'h' -> */,
-/* pos 0426: 621 */    0xE5 /* 'e' -> */,
-/* pos 0427: 622 */    0xEE /* 'n' -> */,
-/* pos 0428: 623 */    0xF4 /* 't' -> */,
-/* pos 0429: 624 */    0xE9 /* 'i' -> */,
-/* pos 042a: 625 */    0xE3 /* 'c' -> */,
-/* pos 042b: 626 */    0xE1 /* 'a' -> */,
-/* pos 042c: 627 */    0xF4 /* 't' -> */,
-/* pos 042d: 628 */    0xE5 /* 'e' -> */,
-/* pos 042e: 629 */    0xBA /* ':' -> */,
-/* pos 042f: 630 */    0x00, 0x48                  /* - terminal marker 72 - */,
-/* pos 0431: 631 */    0xF4 /* 't' -> */,
-/* pos 0432: 632 */    0xE3 /* 'c' -> */,
-/* pos 0433: 633 */    0xE8 /* 'h' -> */,
-/* pos 0434: 634 */    0x00, 0x49                  /* - terminal marker 73 - */,
-/* pos 0436: 635 */    0xF4 /* 't' -> */,
-/* pos 0437: 636 */    0x00, 0x4A                  /* - terminal marker 74 - */,
-/* pos 0439: 637 */    0xEC /* 'l' -> */,
-/* pos 043a: 638 */    0xE5 /* 'e' -> */,
-/* pos 043b: 639 */    0xF4 /* 't' -> */,
-/* pos 043c: 640 */    0xE5 /* 'e' -> */,
-/* pos 043d: 641 */    0x00, 0x4B                  /* - terminal marker 75 - */,
-/* pos 043f: 642 */    0xE9 /* 'i' -> */,
-/* pos 0440: 643 */    0xAD /* '-' -> */,
-/* pos 0441: 644 */    0xE1 /* 'a' -> */,
-/* pos 0442: 645 */    0xF2 /* 'r' -> */,
-/* pos 0443: 646 */    0xE7 /* 'g' -> */,
-/* pos 0444: 647 */    0xF3 /* 's' -> */,
-/* pos 0445: 648 */    0x00, 0x4C                  /* - terminal marker 76 - */,
-/* pos 0447: 649 */    0x00, 0x4D                  /* - terminal marker 77 - */,
-/* pos 0449: 650 */    0xAD /* '-' -> */,
-/* pos 044a: 651 */    0x72 /* 'r' */, 0x0A, 0x00  /* (to 0x0454 state 652) */,
-                       0x66 /* 'f' */, 0x13, 0x00  /* (to 0x0460 state 662) */,
-                       0x61 /* 'a' */, 0x3D, 0x00  /* (to 0x048D state 701) */,
-                       0x08, /* fail */
-/* pos 0454: 652 */    0xE5 /* 'e' -> */,
-/* pos 0455: 653 */    0xE1 /* 'a' -> */,
-/* pos 0456: 654 */    0xEC /* 'l' -> */,
-/* pos 0457: 655 */    0xAD /* '-' -> */,
-/* pos 0458: 656 */    0xE9 /* 'i' -> */,
-/* pos 0459: 657 */    0xF0 /* 'p' -> */,
-/* pos 045a: 658 */    0xBA /* ':' -> */,
-/* pos 045b: 659 */    0x00, 0x4E                  /* - terminal marker 78 - */,
-/* pos 045d: 660 */    0xA0 /* ' ' -> */,
-/* pos 045e: 661 */    0x00, 0x4F                  /* - terminal marker 79 - */,
-/* pos 0460: 662 */    0xEF /* 'o' -> */,
-/* pos 0461: 663 */    0xF2 /* 'r' -> */,
-/* pos 0462: 664 */    0xF7 /* 'w' -> */,
-/* pos 0463: 665 */    0xE1 /* 'a' -> */,
-/* pos 0464: 666 */    0xF2 /* 'r' -> */,
-/* pos 0465: 667 */    0xE4 /* 'd' -> */,
-/* pos 0466: 668 */    0xE5 /* 'e' -> */,
-/* pos 0467: 669 */    0xE4 /* 'd' -> */,
-/* pos 0468: 670 */    0xAD /* '-' -> */,
-/* pos 0469: 671 */    0xE6 /* 'f' -> */,
-/* pos 046a: 672 */    0xEF /* 'o' -> */,
-/* pos 046b: 673 */    0xF2 /* 'r' -> */,
-/* pos 046c: 674 */    0xBA /* ':' -> */,
-/* pos 046d: 675 */    0x00, 0x50                  /* - terminal marker 80 - */,
-/* pos 046f: 676 */    0x00, 0x51                  /* - terminal marker 81 - */,
-/* pos 0471: 677 */    0xE1 /* 'a' -> */,
-/* pos 0472: 678 */    0xE4 /* 'd' -> */,
-/* pos 0473: 679 */    0xA0 /* ' ' -> */,
-/* pos 0474: 680 */    0x00, 0x52                  /* - terminal marker 82 - */,
-/* pos 0476: 681 */    0xBA /* ':' -> */,
-/* pos 0477: 682 */    0x00, 0x53                  /* - terminal marker 83 - */,
-/* pos 0479: 683 */    0xEC /* 'l' -> */,
-/* pos 047a: 684 */    0xE1 /* 'a' -> */,
-/* pos 047b: 685 */    0xF9 /* 'y' -> */,
-/* pos 047c: 686 */    0xAD /* '-' -> */,
-/* pos 047d: 687 */    0xEE /* 'n' -> */,
-/* pos 047e: 688 */    0xEF /* 'o' -> */,
-/* pos 047f: 689 */    0xEE /* 'n' -> */,
-/* pos 0480: 690 */    0xE3 /* 'c' -> */,
-/* pos 0481: 691 */    0xE5 /* 'e' -> */,
-/* pos 0482: 692 */    0xBA /* ':' -> */,
-/* pos 0483: 693 */    0x00, 0x54                  /* - terminal marker 84 - */,
-/* pos 0485: 694 */    0xEF /* 'o' -> */,
-/* pos 0486: 695 */    0xF4 /* 't' -> */,
-/* pos 0487: 696 */    0xEF /* 'o' -> */,
-/* pos 0488: 697 */    0xE3 /* 'c' -> */,
-/* pos 0489: 698 */    0xEF /* 'o' -> */,
-/* pos 048a: 699 */    0xEC /* 'l' -> */,
-/* pos 048b: 700 */    0x00, 0x55                  /* - terminal marker 85 - */,
-/* pos 048d: 701 */    0xF5 /* 'u' -> */,
-/* pos 048e: 702 */    0xF4 /* 't' -> */,
-/* pos 048f: 703 */    0xE8 /* 'h' -> */,
-/* pos 0490: 704 */    0xAD /* '-' -> */,
-/* pos 0491: 705 */    0xF4 /* 't' -> */,
-/* pos 0492: 706 */    0xEF /* 'o' -> */,
-/* pos 0493: 707 */    0xEB /* 'k' -> */,
-/* pos 0494: 708 */    0xE5 /* 'e' -> */,
-/* pos 0495: 709 */    0xEE /* 'n' -> */,
-/* pos 0496: 710 */    0xBA /* ':' -> */,
-/* pos 0497: 711 */    0x00, 0x56                  /* - terminal marker 86 - */,
-/* total size 1177 bytes */
+/* pos 020f: 251 */    0xE3 /* 'c' -> */,
+/* pos 0210: 252 */    0xE8 /* 'h' -> */,
+/* pos 0211: 253 */    0xBA /* ':' -> */,
+/* pos 0212: 254 */    0x00, 0x2A                  /* - terminal marker 42 - */,
+/* pos 0214: 255 */    0xE1 /* 'a' -> */,
+/* pos 0215: 256 */    0xEE /* 'n' -> */,
+/* pos 0216: 257 */    0xE7 /* 'g' -> */,
+/* pos 0217: 258 */    0xE5 /* 'e' -> */,
+/* pos 0218: 259 */    0xBA /* ':' -> */,
+/* pos 0219: 260 */    0x00, 0x2B                  /* - terminal marker 43 - */,
+/* pos 021b: 261 */    0xEE /* 'n' -> */,
+/* pos 021c: 262 */    0xED /* 'm' -> */,
+/* pos 021d: 263 */    0xEF /* 'o' -> */,
+/* pos 021e: 264 */    0xE4 /* 'd' -> */,
+/* pos 021f: 265 */    0xE9 /* 'i' -> */,
+/* pos 0220: 266 */    0xE6 /* 'f' -> */,
+/* pos 0221: 267 */    0xE9 /* 'i' -> */,
+/* pos 0222: 268 */    0xE5 /* 'e' -> */,
+/* pos 0223: 269 */    0xE4 /* 'd' -> */,
+/* pos 0224: 270 */    0xAD /* '-' -> */,
+/* pos 0225: 271 */    0xF3 /* 's' -> */,
+/* pos 0226: 272 */    0xE9 /* 'i' -> */,
+/* pos 0227: 273 */    0xEE /* 'n' -> */,
+/* pos 0228: 274 */    0xE3 /* 'c' -> */,
+/* pos 0229: 275 */    0xE5 /* 'e' -> */,
+/* pos 022a: 276 */    0xBA /* ':' -> */,
+/* pos 022b: 277 */    0x00, 0x2C                  /* - terminal marker 44 - */,
+/* pos 022d: 278 */    0x61 /* 'a' */, 0x0A, 0x00  /* (to 0x0237 state 279) */,
+                       0x69 /* 'i' */, 0x15, 0x00  /* (to 0x0245 state 292) */,
+                       0x6F /* 'o' */, 0x17, 0x00  /* (to 0x024A state 296) */,
+                       0x08, /* fail */
+/* pos 0237: 279 */    0xF3 /* 's' -> */,
+/* pos 0238: 280 */    0xF4 /* 't' -> */,
+/* pos 0239: 281 */    0xAD /* '-' -> */,
+/* pos 023a: 282 */    0xED /* 'm' -> */,
+/* pos 023b: 283 */    0xEF /* 'o' -> */,
+/* pos 023c: 284 */    0xE4 /* 'd' -> */,
+/* pos 023d: 285 */    0xE9 /* 'i' -> */,
+/* pos 023e: 286 */    0xE6 /* 'f' -> */,
+/* pos 023f: 287 */    0xE9 /* 'i' -> */,
+/* pos 0240: 288 */    0xE5 /* 'e' -> */,
+/* pos 0241: 289 */    0xE4 /* 'd' -> */,
+/* pos 0242: 290 */    0xBA /* ':' -> */,
+/* pos 0243: 291 */    0x00, 0x2D                  /* - terminal marker 45 - */,
+/* pos 0245: 292 */    0xEE /* 'n' -> */,
+/* pos 0246: 293 */    0xEB /* 'k' -> */,
+/* pos 0247: 294 */    0xBA /* ':' -> */,
+/* pos 0248: 295 */    0x00, 0x2E                  /* - terminal marker 46 - */,
+/* pos 024a: 296 */    0xE3 /* 'c' -> */,
+/* pos 024b: 297 */    0xE1 /* 'a' -> */,
+/* pos 024c: 298 */    0xF4 /* 't' -> */,
+/* pos 024d: 299 */    0xE9 /* 'i' -> */,
+/* pos 024e: 300 */    0xEF /* 'o' -> */,
+/* pos 024f: 301 */    0xEE /* 'n' -> */,
+/* pos 0250: 302 */    0xBA /* ':' -> */,
+/* pos 0251: 303 */    0x00, 0x2F                  /* - terminal marker 47 - */,
+/* pos 0253: 304 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x025D state 305) */,
+                       0x74 /* 't' */, 0x14, 0x00  /* (to 0x026A state 311) */,
+                       0x70 /* 'p' */, 0x88, 0x01  /* (to 0x03E1 state 596) */,
+                       0x08, /* fail */
+/* pos 025d: 305 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0264 state 306) */,
+                       0x65 /* 'e' */, 0xCA, 0x00  /* (to 0x032A state 448) */,
+                       0x08, /* fail */
+/* pos 0264: 306 */    0xE5 /* 'e' -> */,
+/* pos 0265: 307 */    0xF3 /* 's' -> */,
+/* pos 0266: 308 */    0xE8 /* 'h' -> */,
+/* pos 0267: 309 */    0xBA /* ':' -> */,
+/* pos 0268: 310 */    0x00, 0x33                  /* - terminal marker 51 - */,
+/* pos 026a: 311 */    0xF2 /* 'r' -> */,
+/* pos 026b: 312 */    0xF9 /* 'y' -> */,
+/* pos 026c: 313 */    0xAD /* '-' -> */,
+/* pos 026d: 314 */    0xE1 /* 'a' -> */,
+/* pos 026e: 315 */    0xE6 /* 'f' -> */,
+/* pos 026f: 316 */    0xF4 /* 't' -> */,
+/* pos 0270: 317 */    0xE5 /* 'e' -> */,
+/* pos 0271: 318 */    0xF2 /* 'r' -> */,
+/* pos 0272: 319 */    0xBA /* ':' -> */,
+/* pos 0273: 320 */    0x00, 0x34                  /* - terminal marker 52 - */,
+/* pos 0275: 321 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x027C state 322) */,
+                       0x74 /* 't' */, 0x06, 0x01  /* (to 0x037E state 514) */,
+                       0x08, /* fail */
+/* pos 027c: 322 */    0x72 /* 'r' */, 0x0A, 0x00  /* (to 0x0286 state 323) */,
+                       0x74 /* 't' */, 0x0D, 0x00  /* (to 0x028C state 328) */,
+                       0x63 /* 'c' */, 0x6B, 0x01  /* (to 0x03ED state 607) */,
+                       0x08, /* fail */
+/* pos 0286: 323 */    0xF6 /* 'v' -> */,
+/* pos 0287: 324 */    0xE5 /* 'e' -> */,
+/* pos 0288: 325 */    0xF2 /* 'r' -> */,
+/* pos 0289: 326 */    0xBA /* ':' -> */,
+/* pos 028a: 327 */    0x00, 0x35                  /* - terminal marker 53 - */,
+/* pos 028c: 328 */    0xAD /* '-' -> */,
+/* pos 028d: 329 */    0xE3 /* 'c' -> */,
+/* pos 028e: 330 */    0xEF /* 'o' -> */,
+/* pos 028f: 331 */    0xEF /* 'o' -> */,
+/* pos 0290: 332 */    0xEB /* 'k' -> */,
+/* pos 0291: 333 */    0xE9 /* 'i' -> */,
+/* pos 0292: 334 */    0xE5 /* 'e' -> */,
+/* pos 0293: 335 */    0xBA /* ':' -> */,
+/* pos 0294: 336 */    0x00, 0x36                  /* - terminal marker 54 - */,
+/* pos 0296: 337 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x029D state 338) */,
+                       0x65 /* 'e' */, 0x45, 0x01  /* (to 0x03DE state 594) */,
+                       0x08, /* fail */
+/* pos 029d: 338 */    0xE1 /* 'a' -> */,
+/* pos 029e: 339 */    0xEE /* 'n' -> */,
+/* pos 029f: 340 */    0xF3 /* 's' -> */,
+/* pos 02a0: 341 */    0xE6 /* 'f' -> */,
+/* pos 02a1: 342 */    0xE5 /* 'e' -> */,
+/* pos 02a2: 343 */    0xF2 /* 'r' -> */,
+/* pos 02a3: 344 */    0xAD /* '-' -> */,
+/* pos 02a4: 345 */    0xE5 /* 'e' -> */,
+/* pos 02a5: 346 */    0xEE /* 'n' -> */,
+/* pos 02a6: 347 */    0xE3 /* 'c' -> */,
+/* pos 02a7: 348 */    0xEF /* 'o' -> */,
+/* pos 02a8: 349 */    0xE4 /* 'd' -> */,
+/* pos 02a9: 350 */    0xE9 /* 'i' -> */,
+/* pos 02aa: 351 */    0xEE /* 'n' -> */,
+/* pos 02ab: 352 */    0xE7 /* 'g' -> */,
+/* pos 02ac: 353 */    0xBA /* ':' -> */,
+/* pos 02ad: 354 */    0x00, 0x38                  /* - terminal marker 56 - */,
+/* pos 02af: 355 */    0xE9 /* 'i' -> */,
+/* pos 02b0: 356 */    0xAD /* '-' -> */,
+/* pos 02b1: 357 */    0xE1 /* 'a' -> */,
+/* pos 02b2: 358 */    0xF2 /* 'r' -> */,
+/* pos 02b3: 359 */    0xE7 /* 'g' -> */,
+/* pos 02b4: 360 */    0xF3 /* 's' -> */,
+/* pos 02b5: 361 */    0x00, 0x3D                  /* - terminal marker 61 - */,
+/* pos 02b7: 362 */    0xA0 /* ' ' -> */,
+/* pos 02b8: 363 */    0x00, 0x3E                  /* - terminal marker 62 - */,
+/* pos 02ba: 364 */    0xAD /* '-' -> */,
+/* pos 02bb: 365 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x02C5 state 366) */,
+                       0x61 /* 'a' */, 0x1D, 0x00  /* (to 0x02DB state 385) */,
+                       0x72 /* 'r' */, 0x14, 0x01  /* (to 0x03D5 state 586) */,
+                       0x08, /* fail */
+/* pos 02c5: 366 */    0xEF /* 'o' -> */,
+/* pos 02c6: 367 */    0xF2 /* 'r' -> */,
+/* pos 02c7: 368 */    0xF7 /* 'w' -> */,
+/* pos 02c8: 369 */    0xE1 /* 'a' -> */,
+/* pos 02c9: 370 */    0xF2 /* 'r' -> */,
+/* pos 02ca: 371 */    0xE4 /* 'd' -> */,
+/* pos 02cb: 372 */    0xE5 /* 'e' -> */,
+/* pos 02cc: 373 */    0xE4 /* 'd' -> */,
+/* pos 02cd: 374 */    0xAD /* '-' -> */,
+/* pos 02ce: 375 */    0xE6 /* 'f' -> */,
+/* pos 02cf: 376 */    0xEF /* 'o' -> */,
+/* pos 02d0: 377 */    0xF2 /* 'r' -> */,
+/* pos 02d1: 378 */    0xBA /* ':' -> */,
+/* pos 02d2: 379 */    0x00, 0x3F                  /* - terminal marker 63 - */,
+/* pos 02d4: 380 */    0x00, 0x40                  /* - terminal marker 64 - */,
+/* pos 02d6: 381 */    0xE1 /* 'a' -> */,
+/* pos 02d7: 382 */    0xE4 /* 'd' -> */,
+/* pos 02d8: 383 */    0xA0 /* ' ' -> */,
+/* pos 02d9: 384 */    0x00, 0x41                  /* - terminal marker 65 - */,
+/* pos 02db: 385 */    0x75 /* 'u' */, 0x07, 0x00  /* (to 0x02E2 state 386) */,
+                       0x6D /* 'm' */, 0x0F, 0x00  /* (to 0x02ED state 396) */,
+                       0x08, /* fail */
+/* pos 02e2: 386 */    0xF4 /* 't' -> */,
+/* pos 02e3: 387 */    0xE8 /* 'h' -> */,
+/* pos 02e4: 388 */    0xAD /* '-' -> */,
+/* pos 02e5: 389 */    0xF4 /* 't' -> */,
+/* pos 02e6: 390 */    0xEF /* 'o' -> */,
+/* pos 02e7: 391 */    0xEB /* 'k' -> */,
+/* pos 02e8: 392 */    0xE5 /* 'e' -> */,
+/* pos 02e9: 393 */    0xEE /* 'n' -> */,
+/* pos 02ea: 394 */    0xBA /* ':' -> */,
+/* pos 02eb: 395 */    0x00, 0x45                  /* - terminal marker 69 - */,
+/* pos 02ed: 396 */    0xFA /* 'z' -> */,
+/* pos 02ee: 397 */    0xEE /* 'n' -> */,
+/* pos 02ef: 398 */    0xAD /* '-' -> */,
+/* pos 02f0: 399 */    0xE4 /* 'd' -> */,
+/* pos 02f1: 400 */    0xF3 /* 's' -> */,
+/* pos 02f2: 401 */    0xF3 /* 's' -> */,
+/* pos 02f3: 402 */    0xAD /* '-' -> */,
+/* pos 02f4: 403 */    0xF3 /* 's' -> */,
+/* pos 02f5: 404 */    0xE9 /* 'i' -> */,
+/* pos 02f6: 405 */    0xE7 /* 'g' -> */,
+/* pos 02f7: 406 */    0xEE /* 'n' -> */,
+/* pos 02f8: 407 */    0xE1 /* 'a' -> */,
+/* pos 02f9: 408 */    0xF4 /* 't' -> */,
+/* pos 02fa: 409 */    0xF5 /* 'u' -> */,
+/* pos 02fb: 410 */    0xF2 /* 'r' -> */,
+/* pos 02fc: 411 */    0xE5 /* 'e' -> */,
+/* pos 02fd: 412 */    0xBA /* ':' -> */,
+/* pos 02fe: 413 */    0x00, 0x46                  /* - terminal marker 70 - */,
+/* pos 0300: 414 */    0xF4 /* 't' -> */,
+/* pos 0301: 415 */    0xE9 /* 'i' -> */,
+/* pos 0302: 416 */    0xEF /* 'o' -> */,
+/* pos 0303: 417 */    0xEE /* 'n' -> */,
+/* pos 0304: 418 */    0xF3 /* 's' -> */,
+/* pos 0305: 419 */    0xA0 /* ' ' -> */,
+/* pos 0306: 420 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 0308: 421 */    0xF3 /* 's' -> */,
+/* pos 0309: 422 */    0xAD /* '-' -> */,
+/* pos 030a: 423 */    0xE3 /* 'c' -> */,
+/* pos 030b: 424 */    0xEF /* 'o' -> */,
+/* pos 030c: 425 */    0xEE /* 'n' -> */,
+/* pos 030d: 426 */    0xF4 /* 't' -> */,
+/* pos 030e: 427 */    0xF2 /* 'r' -> */,
+/* pos 030f: 428 */    0xEF /* 'o' -> */,
+/* pos 0310: 429 */    0xEC /* 'l' -> */,
+/* pos 0311: 430 */    0xAD /* '-' -> */,
+/* pos 0312: 431 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0319 state 432) */,
+                       0x61 /* 'a' */, 0x24, 0x00  /* (to 0x0339 state 461) */,
+                       0x08, /* fail */
+/* pos 0319: 432 */    0xE5 /* 'e' -> */,
+/* pos 031a: 433 */    0xF1 /* 'q' -> */,
+/* pos 031b: 434 */    0xF5 /* 'u' -> */,
+/* pos 031c: 435 */    0xE5 /* 'e' -> */,
+/* pos 031d: 436 */    0xF3 /* 's' -> */,
+/* pos 031e: 437 */    0xF4 /* 't' -> */,
+/* pos 031f: 438 */    0xAD /* '-' -> */,
+/* pos 0320: 439 */    0xE8 /* 'h' -> */,
+/* pos 0321: 440 */    0xE5 /* 'e' -> */,
+/* pos 0322: 441 */    0xE1 /* 'a' -> */,
+/* pos 0323: 442 */    0xE4 /* 'd' -> */,
+/* pos 0324: 443 */    0xE5 /* 'e' -> */,
+/* pos 0325: 444 */    0xF2 /* 'r' -> */,
+/* pos 0326: 445 */    0xF3 /* 's' -> */,
+/* pos 0327: 446 */    0xBA /* ':' -> */,
+/* pos 0328: 447 */    0x00, 0x11                  /* - terminal marker 17 - */,
+/* pos 032a: 448 */    0xF2 /* 'r' -> */,
+/* pos 032b: 449 */    0xE5 /* 'e' -> */,
+/* pos 032c: 450 */    0xF2 /* 'r' -> */,
+/* pos 032d: 451 */    0xBA /* ':' -> */,
+/* pos 032e: 452 */    0x00, 0x16                  /* - terminal marker 22 - */,
+/* pos 0330: 453 */    0xE8 /* 'h' -> */,
+/* pos 0331: 454 */    0xE1 /* 'a' -> */,
+/* pos 0332: 455 */    0xF2 /* 'r' -> */,
+/* pos 0333: 456 */    0xF3 /* 's' -> */,
+/* pos 0334: 457 */    0xE5 /* 'e' -> */,
+/* pos 0335: 458 */    0xF4 /* 't' -> */,
+/* pos 0336: 459 */    0xBA /* ':' -> */,
+/* pos 0337: 460 */    0x00, 0x1C                  /* - terminal marker 28 - */,
+/* pos 0339: 461 */    0xEC /* 'l' -> */,
+/* pos 033a: 462 */    0xEC /* 'l' -> */,
+/* pos 033b: 463 */    0xEF /* 'o' -> */,
+/* pos 033c: 464 */    0xF7 /* 'w' -> */,
+/* pos 033d: 465 */    0xAD /* '-' -> */,
+/* pos 033e: 466 */    0xEF /* 'o' -> */,
+/* pos 033f: 467 */    0xF2 /* 'r' -> */,
+/* pos 0340: 468 */    0xE9 /* 'i' -> */,
+/* pos 0341: 469 */    0xE7 /* 'g' -> */,
+/* pos 0342: 470 */    0xE9 /* 'i' -> */,
+/* pos 0343: 471 */    0xEE /* 'n' -> */,
+/* pos 0344: 472 */    0xBA /* ':' -> */,
+/* pos 0345: 473 */    0x00, 0x1E                  /* - terminal marker 30 - */,
+/* pos 0347: 474 */    0xE1 /* 'a' -> */,
+/* pos 0348: 475 */    0xF8 /* 'x' -> */,
+/* pos 0349: 476 */    0xAD /* '-' -> */,
+/* pos 034a: 477 */    0xE6 /* 'f' -> */,
+/* pos 034b: 478 */    0xEF /* 'o' -> */,
+/* pos 034c: 479 */    0xF2 /* 'r' -> */,
+/* pos 034d: 480 */    0xF7 /* 'w' -> */,
+/* pos 034e: 481 */    0xE1 /* 'a' -> */,
+/* pos 034f: 482 */    0xF2 /* 'r' -> */,
+/* pos 0350: 483 */    0xE4 /* 'd' -> */,
+/* pos 0351: 484 */    0xF3 /* 's' -> */,
+/* pos 0352: 485 */    0xBA /* ':' -> */,
+/* pos 0353: 486 */    0x00, 0x30                  /* - terminal marker 48 - */,
+/* pos 0355: 487 */    0xF8 /* 'x' -> */,
+/* pos 0356: 488 */    0xF9 /* 'y' -> */,
+/* pos 0357: 489 */    0x2D /* '-' */, 0x07, 0x00  /* (to 0x035E state 490) */,
+                       0x20 /* ' ' */, 0x79, 0x00  /* (to 0x03D3 state 585) */,
+                       0x08, /* fail */
+/* pos 035e: 490 */    0xE1 /* 'a' -> */,
+/* pos 035f: 491 */    0xF5 /* 'u' -> */,
+/* pos 0360: 492 */    0xF4 /* 't' -> */,
+/* pos 0361: 493 */    0xE8 /* 'h' -> */,
+/* pos 0362: 494 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0369 state 495) */,
+                       0x6F /* 'o' */, 0x0E, 0x00  /* (to 0x0373 state 504) */,
+                       0x08, /* fail */
+/* pos 0369: 495 */    0xEE /* 'n' -> */,
+/* pos 036a: 496 */    0xF4 /* 't' -> */,
+/* pos 036b: 497 */    0xE9 /* 'i' -> */,
+/* pos 036c: 498 */    0xE3 /* 'c' -> */,
+/* pos 036d: 499 */    0xE1 /* 'a' -> */,
+/* pos 036e: 500 */    0xF4 /* 't' -> */,
+/* pos 036f: 501 */    0xE5 /* 'e' -> */,
+/* pos 0370: 502 */    0xBA /* ':' -> */,
+/* pos 0371: 503 */    0x00, 0x31                  /* - terminal marker 49 - */,
+/* pos 0373: 504 */    0xF2 /* 'r' -> */,
+/* pos 0374: 505 */    0xE9 /* 'i' -> */,
+/* pos 0375: 506 */    0xFA /* 'z' -> */,
+/* pos 0376: 507 */    0xE1 /* 'a' -> */,
+/* pos 0377: 508 */    0xF4 /* 't' -> */,
+/* pos 0378: 509 */    0xE9 /* 'i' -> */,
+/* pos 0379: 510 */    0xEF /* 'o' -> */,
+/* pos 037a: 511 */    0xEE /* 'n' -> */,
+/* pos 037b: 512 */    0xBA /* ':' -> */,
+/* pos 037c: 513 */    0x00, 0x32                  /* - terminal marker 50 - */,
+/* pos 037e: 514 */    0xF2 /* 'r' -> */,
+/* pos 037f: 515 */    0xE9 /* 'i' -> */,
+/* pos 0380: 516 */    0xE3 /* 'c' -> */,
+/* pos 0381: 517 */    0xF4 /* 't' -> */,
+/* pos 0382: 518 */    0xAD /* '-' -> */,
+/* pos 0383: 519 */    0xF4 /* 't' -> */,
+/* pos 0384: 520 */    0xF2 /* 'r' -> */,
+/* pos 0385: 521 */    0xE1 /* 'a' -> */,
+/* pos 0386: 522 */    0xEE /* 'n' -> */,
+/* pos 0387: 523 */    0xF3 /* 's' -> */,
+/* pos 0388: 524 */    0xF0 /* 'p' -> */,
+/* pos 0389: 525 */    0xEF /* 'o' -> */,
+/* pos 038a: 526 */    0xF2 /* 'r' -> */,
+/* pos 038b: 527 */    0xF4 /* 't' -> */,
+/* pos 038c: 528 */    0xAD /* '-' -> */,
+/* pos 038d: 529 */    0xF3 /* 's' -> */,
+/* pos 038e: 530 */    0xE5 /* 'e' -> */,
+/* pos 038f: 531 */    0xE3 /* 'c' -> */,
+/* pos 0390: 532 */    0xF5 /* 'u' -> */,
+/* pos 0391: 533 */    0xF2 /* 'r' -> */,
+/* pos 0392: 534 */    0xE9 /* 'i' -> */,
+/* pos 0393: 535 */    0xF4 /* 't' -> */,
+/* pos 0394: 536 */    0xF9 /* 'y' -> */,
+/* pos 0395: 537 */    0xBA /* ':' -> */,
+/* pos 0396: 538 */    0x00, 0x37                  /* - terminal marker 55 - */,
+/* pos 0398: 539 */    0xE5 /* 'e' -> */,
+/* pos 0399: 540 */    0xF2 /* 'r' -> */,
+/* pos 039a: 541 */    0xAD /* '-' -> */,
+/* pos 039b: 542 */    0xE1 /* 'a' -> */,
+/* pos 039c: 543 */    0xE7 /* 'g' -> */,
+/* pos 039d: 544 */    0xE5 /* 'e' -> */,
+/* pos 039e: 545 */    0xEE /* 'n' -> */,
+/* pos 039f: 546 */    0xF4 /* 't' -> */,
+/* pos 03a0: 547 */    0xBA /* ':' -> */,
+/* pos 03a1: 548 */    0x00, 0x39                  /* - terminal marker 57 - */,
+/* pos 03a3: 549 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x03AA state 550) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x03AF state 554) */,
+                       0x08, /* fail */
+/* pos 03aa: 550 */    0xF2 /* 'r' -> */,
+/* pos 03ab: 551 */    0xF9 /* 'y' -> */,
+/* pos 03ac: 552 */    0xBA /* ':' -> */,
+/* pos 03ad: 553 */    0x00, 0x3A                  /* - terminal marker 58 - */,
+/* pos 03af: 554 */    0xE1 /* 'a' -> */,
+/* pos 03b0: 555 */    0xBA /* ':' -> */,
+/* pos 03b1: 556 */    0x00, 0x3B                  /* - terminal marker 59 - */,
+/* pos 03b3: 557 */    0xF7 /* 'w' -> */,
+/* pos 03b4: 558 */    0xF7 /* 'w' -> */,
+/* pos 03b5: 559 */    0xAD /* '-' -> */,
+/* pos 03b6: 560 */    0xE1 /* 'a' -> */,
+/* pos 03b7: 561 */    0xF5 /* 'u' -> */,
+/* pos 03b8: 562 */    0xF4 /* 't' -> */,
+/* pos 03b9: 563 */    0xE8 /* 'h' -> */,
+/* pos 03ba: 564 */    0xE5 /* 'e' -> */,
+/* pos 03bb: 565 */    0xEE /* 'n' -> */,
+/* pos 03bc: 566 */    0xF4 /* 't' -> */,
+/* pos 03bd: 567 */    0xE9 /* 'i' -> */,
+/* pos 03be: 568 */    0xE3 /* 'c' -> */,
+/* pos 03bf: 569 */    0xE1 /* 'a' -> */,
+/* pos 03c0: 570 */    0xF4 /* 't' -> */,
+/* pos 03c1: 571 */    0xE5 /* 'e' -> */,
+/* pos 03c2: 572 */    0xBA /* ':' -> */,
+/* pos 03c3: 573 */    0x00, 0x3C                  /* - terminal marker 60 - */,
+/* pos 03c5: 574 */    0xF4 /* 't' -> */,
+/* pos 03c6: 575 */    0xE3 /* 'c' -> */,
+/* pos 03c7: 576 */    0xE8 /* 'h' -> */,
+/* pos 03c8: 577 */    0x00, 0x43                  /* - terminal marker 67 - */,
+/* pos 03ca: 578 */    0xF4 /* 't' -> */,
+/* pos 03cb: 579 */    0x00, 0x44                  /* - terminal marker 68 - */,
+/* pos 03cd: 580 */    0xEC /* 'l' -> */,
+/* pos 03ce: 581 */    0xE5 /* 'e' -> */,
+/* pos 03cf: 582 */    0xF4 /* 't' -> */,
+/* pos 03d0: 583 */    0xE5 /* 'e' -> */,
+/* pos 03d1: 584 */    0x00, 0x45                  /* - terminal marker 69 - */,
+/* pos 03d3: 585 */    0x00, 0x47                  /* - terminal marker 71 - */,
+/* pos 03d5: 586 */    0xE5 /* 'e' -> */,
+/* pos 03d6: 587 */    0xE1 /* 'a' -> */,
+/* pos 03d7: 588 */    0xEC /* 'l' -> */,
+/* pos 03d8: 589 */    0xAD /* '-' -> */,
+/* pos 03d9: 590 */    0xE9 /* 'i' -> */,
+/* pos 03da: 591 */    0xF0 /* 'p' -> */,
+/* pos 03db: 592 */    0xBA /* ':' -> */,
+/* pos 03dc: 593 */    0x00, 0x48                  /* - terminal marker 72 - */,
+/* pos 03de: 594 */    0xBA /* ':' -> */,
+/* pos 03df: 595 */    0x00, 0x42                  /* - terminal marker 66 - */,
+/* pos 03e1: 596 */    0xEC /* 'l' -> */,
+/* pos 03e2: 597 */    0xE1 /* 'a' -> */,
+/* pos 03e3: 598 */    0xF9 /* 'y' -> */,
+/* pos 03e4: 599 */    0xAD /* '-' -> */,
+/* pos 03e5: 600 */    0xEE /* 'n' -> */,
+/* pos 03e6: 601 */    0xEF /* 'o' -> */,
+/* pos 03e7: 602 */    0xEE /* 'n' -> */,
+/* pos 03e8: 603 */    0xE3 /* 'c' -> */,
+/* pos 03e9: 604 */    0xE5 /* 'e' -> */,
+/* pos 03ea: 605 */    0xBA /* ':' -> */,
+/* pos 03eb: 606 */    0x00, 0x43                  /* - terminal marker 67 - */,
+/* pos 03ed: 607 */    0xAD /* '-' -> */,
+/* pos 03ee: 608 */    0xF7 /* 'w' -> */,
+/* pos 03ef: 609 */    0xE5 /* 'e' -> */,
+/* pos 03f0: 610 */    0xE2 /* 'b' -> */,
+/* pos 03f1: 611 */    0xF3 /* 's' -> */,
+/* pos 03f2: 612 */    0xEF /* 'o' -> */,
+/* pos 03f3: 613 */    0xE3 /* 'c' -> */,
+/* pos 03f4: 614 */    0xEB /* 'k' -> */,
+/* pos 03f5: 615 */    0xE5 /* 'e' -> */,
+/* pos 03f6: 616 */    0xF4 /* 't' -> */,
+/* pos 03f7: 617 */    0xAD /* '-' -> */,
+/* pos 03f8: 618 */    0x64 /* 'd' */, 0x19, 0x00  /* (to 0x0411 state 619) */,
+                       0x65 /* 'e' */, 0x1D, 0x00  /* (to 0x0418 state 625) */,
+                       0x6B /* 'k' */, 0x26, 0x00  /* (to 0x0424 state 636) */,
+                       0x70 /* 'p' */, 0x35, 0x00  /* (to 0x0436 state 643) */,
+                       0x61 /* 'a' */, 0x3C, 0x00  /* (to 0x0440 state 652) */,
+                       0x6E /* 'n' */, 0x41, 0x00  /* (to 0x0448 state 659) */,
+                       0x76 /* 'v' */, 0x47, 0x00  /* (to 0x0451 state 666) */,
+                       0x6F /* 'o' */, 0x4D, 0x00  /* (to 0x045A state 674) */,
+                       0x08, /* fail */
+/* pos 0411: 619 */    0xF2 /* 'r' -> */,
+/* pos 0412: 620 */    0xE1 /* 'a' -> */,
+/* pos 0413: 621 */    0xE6 /* 'f' -> */,
+/* pos 0414: 622 */    0xF4 /* 't' -> */,
+/* pos 0415: 623 */    0xBA /* ':' -> */,
+/* pos 0416: 624 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 0418: 625 */    0xF8 /* 'x' -> */,
+/* pos 0419: 626 */    0xF4 /* 't' -> */,
+/* pos 041a: 627 */    0xE5 /* 'e' -> */,
+/* pos 041b: 628 */    0xEE /* 'n' -> */,
+/* pos 041c: 629 */    0xF3 /* 's' -> */,
+/* pos 041d: 630 */    0xE9 /* 'i' -> */,
+/* pos 041e: 631 */    0xEF /* 'o' -> */,
+/* pos 041f: 632 */    0xEE /* 'n' -> */,
+/* pos 0420: 633 */    0xF3 /* 's' -> */,
+/* pos 0421: 634 */    0xBA /* ':' -> */,
+/* pos 0422: 635 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 0424: 636 */    0xE5 /* 'e' -> */,
+/* pos 0425: 637 */    0xF9 /* 'y' -> */,
+/* pos 0426: 638 */    0x31 /* '1' */, 0x0A, 0x00  /* (to 0x0430 state 639) */,
+                       0x32 /* '2' */, 0x0A, 0x00  /* (to 0x0433 state 641) */,
+                       0x3A /* ':' */, 0x23, 0x00  /* (to 0x044F state 665) */,
+                       0x08, /* fail */
+/* pos 0430: 639 */    0xBA /* ':' -> */,
+/* pos 0431: 640 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 0433: 641 */    0xBA /* ':' -> */,
+/* pos 0434: 642 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 0436: 643 */    0xF2 /* 'r' -> */,
+/* pos 0437: 644 */    0xEF /* 'o' -> */,
+/* pos 0438: 645 */    0xF4 /* 't' -> */,
+/* pos 0439: 646 */    0xEF /* 'o' -> */,
+/* pos 043a: 647 */    0xE3 /* 'c' -> */,
+/* pos 043b: 648 */    0xEF /* 'o' -> */,
+/* pos 043c: 649 */    0xEC /* 'l' -> */,
+/* pos 043d: 650 */    0xBA /* ':' -> */,
+/* pos 043e: 651 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 0440: 652 */    0xE3 /* 'c' -> */,
+/* pos 0441: 653 */    0xE3 /* 'c' -> */,
+/* pos 0442: 654 */    0xE5 /* 'e' -> */,
+/* pos 0443: 655 */    0xF0 /* 'p' -> */,
+/* pos 0444: 656 */    0xF4 /* 't' -> */,
+/* pos 0445: 657 */    0xBA /* ':' -> */,
+/* pos 0446: 658 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 0448: 659 */    0xEF /* 'o' -> */,
+/* pos 0449: 660 */    0xEE /* 'n' -> */,
+/* pos 044a: 661 */    0xE3 /* 'c' -> */,
+/* pos 044b: 662 */    0xE5 /* 'e' -> */,
+/* pos 044c: 663 */    0xBA /* ':' -> */,
+/* pos 044d: 664 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 044f: 665 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 0451: 666 */    0xE5 /* 'e' -> */,
+/* pos 0452: 667 */    0xF2 /* 'r' -> */,
+/* pos 0453: 668 */    0xF3 /* 's' -> */,
+/* pos 0454: 669 */    0xE9 /* 'i' -> */,
+/* pos 0455: 670 */    0xEF /* 'o' -> */,
+/* pos 0456: 671 */    0xEE /* 'n' -> */,
+/* pos 0457: 672 */    0xBA /* ':' -> */,
+/* pos 0458: 673 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 045a: 674 */    0xF2 /* 'r' -> */,
+/* pos 045b: 675 */    0xE9 /* 'i' -> */,
+/* pos 045c: 676 */    0xE7 /* 'g' -> */,
+/* pos 045d: 677 */    0xE9 /* 'i' -> */,
+/* pos 045e: 678 */    0xEE /* 'n' -> */,
+/* pos 045f: 679 */    0xBA /* ':' -> */,
+/* pos 0460: 680 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* pos 0462: 681 */    0xAD /* '-' -> */,
+/* pos 0463: 682 */    0xF3 /* 's' -> */,
+/* pos 0464: 683 */    0xE5 /* 'e' -> */,
+/* pos 0465: 684 */    0xF4 /* 't' -> */,
+/* pos 0466: 685 */    0xF4 /* 't' -> */,
+/* pos 0467: 686 */    0xE9 /* 'i' -> */,
+/* pos 0468: 687 */    0xEE /* 'n' -> */,
+/* pos 0469: 688 */    0xE7 /* 'g' -> */,
+/* pos 046a: 689 */    0xF3 /* 's' -> */,
+/* pos 046b: 690 */    0xBA /* ':' -> */,
+/* pos 046c: 691 */    0x00, 0x08                  /* - terminal marker  8 - */,
+/* pos 046e: 692 */    0x61 /* 'a' */, 0x0D, 0x00  /* (to 0x047B state 693) */,
+                       0x6D /* 'm' */, 0x14, 0x00  /* (to 0x0485 state 702) */,
+                       0x70 /* 'p' */, 0x18, 0x00  /* (to 0x048C state 708) */,
+                       0x73 /* 's' */, 0x20, 0x00  /* (to 0x0497 state 712) */,
+                       0x08, /* fail */
+/* pos 047b: 693 */    0xF5 /* 'u' -> */,
+/* pos 047c: 694 */    0xF4 /* 't' -> */,
+/* pos 047d: 695 */    0xE8 /* 'h' -> */,
+/* pos 047e: 696 */    0xEF /* 'o' -> */,
+/* pos 047f: 697 */    0xF2 /* 'r' -> */,
+/* pos 0480: 698 */    0xE9 /* 'i' -> */,
+/* pos 0481: 699 */    0xF4 /* 't' -> */,
+/* pos 0482: 700 */    0xF9 /* 'y' -> */,
+/* pos 0483: 701 */    0x00, 0x17                  /* - terminal marker 23 - */,
+/* pos 0485: 702 */    0xE5 /* 'e' -> */,
+/* pos 0486: 703 */    0xF4 /* 't' -> */,
+/* pos 0487: 704 */    0xE8 /* 'h' -> */,
+/* pos 0488: 705 */    0xEF /* 'o' -> */,
+/* pos 0489: 706 */    0xE4 /* 'd' -> */,
+/* pos 048a: 707 */    0x00, 0x18                  /* - terminal marker 24 - */,
+/* pos 048c: 708 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0493 state 709) */,
+                       0x72 /* 'r' */, 0x1B, 0x00  /* (to 0x04AA state 723) */,
+                       0x08, /* fail */
+/* pos 0493: 709 */    0xF4 /* 't' -> */,
+/* pos 0494: 710 */    0xE8 /* 'h' -> */,
+/* pos 0495: 711 */    0x00, 0x19                  /* - terminal marker 25 - */,
+/* pos 0497: 712 */    0x63 /* 'c' */, 0x07, 0x00  /* (to 0x049E state 713) */,
+                       0x74 /* 't' */, 0x0A, 0x00  /* (to 0x04A4 state 718) */,
+                       0x08, /* fail */
+/* pos 049e: 713 */    0xE8 /* 'h' -> */,
+/* pos 049f: 714 */    0xE5 /* 'e' -> */,
+/* pos 04a0: 715 */    0xED /* 'm' -> */,
+/* pos 04a1: 716 */    0xE5 /* 'e' -> */,
+/* pos 04a2: 717 */    0x00, 0x1A                  /* - terminal marker 26 - */,
+/* pos 04a4: 718 */    0xE1 /* 'a' -> */,
+/* pos 04a5: 719 */    0xF4 /* 't' -> */,
+/* pos 04a6: 720 */    0xF5 /* 'u' -> */,
+/* pos 04a7: 721 */    0xF3 /* 's' -> */,
+/* pos 04a8: 722 */    0x00, 0x1B                  /* - terminal marker 27 - */,
+/* pos 04aa: 723 */    0xEF /* 'o' -> */,
+/* pos 04ab: 724 */    0xF4 /* 't' -> */,
+/* pos 04ac: 725 */    0xEF /* 'o' -> */,
+/* pos 04ad: 726 */    0xE3 /* 'c' -> */,
+/* pos 04ae: 727 */    0xEF /* 'o' -> */,
+/* pos 04af: 728 */    0xEC /* 'l' -> */,
+/* pos 04b0: 729 */    0x00, 0x44                  /* - terminal marker 68 - */,
+/* total size 1202 bytes */
+#endif
+
+#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
+       /* 0: 0: get  */
+       /* 1: 1: post  */
+       /* 2: 2: options  */
+       /* 3: 3: host: */
+       /* 4: 4: connection: */
+       /* 5: 5: upgrade: */
+       /* 6: 6: origin: */
+       /* 7: 8: \r
+ */
+       /* 8: 15: http/1.1  */
+       /* 9: 16: http2-settings: */
+       /* 10: 17: accept: */
+       /* 11: 18: access-control-request-headers: */
+       /* 12: 19: if-modified-since: */
+       /* 13: 20: if-none-match: */
+       /* 14: 21: accept-encoding: */
+       /* 15: 22: accept-language: */
+       /* 16: 23: pragma: */
+       /* 17: 24: cache-control: */
+       /* 18: 25: authorization: */
+       /* 19: 26: cookie: */
+       /* 20: 27: content-length: */
+       /* 21: 28: content-type: */
+       /* 22: 29: date: */
+       /* 23: 30: range: */
+       /* 24: 31: referer: */
+       /* 25: 35: :authority */
+       /* 26: 36: :method */
+       /* 27: 37: :path */
+       /* 28: 38: :scheme */
+       /* 29: 39: :status */
+       /* 30: 40: accept-charset: */
+       /* 31: 41: accept-ranges: */
+       /* 32: 42: access-control-allow-origin: */
+       /* 33: 43: age: */
+       /* 34: 44: allow: */
+       /* 35: 45: content-disposition: */
+       /* 36: 46: content-encoding: */
+       /* 37: 47: content-language: */
+       /* 38: 48: content-location: */
+       /* 39: 49: content-range: */
+       /* 40: 50: etag: */
+       /* 41: 51: expect: */
+       /* 42: 52: expires: */
+       /* 43: 53: from: */
+       /* 44: 54: if-match: */
+       /* 45: 55: if-range: */
+       /* 46: 56: if-unmodified-since: */
+       /* 47: 57: last-modified: */
+       /* 48: 58: link: */
+       /* 49: 59: location: */
+       /* 50: 60: max-forwards: */
+       /* 51: 61: proxy-authenticate: */
+       /* 52: 62: proxy-authorization: */
+       /* 53: 63: refresh: */
+       /* 54: 64: retry-after: */
+       /* 55: 65: server: */
+       /* 56: 66: set-cookie: */
+       /* 57: 67: strict-transport-security: */
+       /* 58: 68: transfer-encoding: */
+       /* 59: 69: user-agent: */
+       /* 60: 70: vary: */
+       /* 61: 71: via: */
+       /* 62: 72: www-authenticate: */
+       /* 63: 73: patch */
+       /* 64: 74: put */
+       /* 65: 75: delete */
+       /* 66: 76: uri-args */
+       /* 67: 77: proxy  */
+       /* 68: 78: x-real-ip: */
+       /* 69: 79: http/1.0  */
+       /* 70: 80: x-forwarded-for: */
+       /* 71: 81: connect  */
+       /* 72: 82: head  */
+       /* 73: 83: te: */
+       /* 74: 84: replay-nonce: */
+       /* 75: 85: :protocol */
+       /* 76: 86: x-auth-token: */
+       /* 77: 87: x-amzn-dss-signature: */
+/* pos 0000:   0 */    0x67 /* 'g' */, 0x40, 0x00  /* (to 0x0040 state   1) */,
+                       0x70 /* 'p' */, 0x42, 0x00  /* (to 0x0045 state   5) */,
+                       0x68 /* 'h' */, 0x51, 0x00  /* (to 0x0057 state  10) */,
+                       0x63 /* 'c' */, 0x5D, 0x00  /* (to 0x0066 state  15) */,
+                       0x75 /* 'u' */, 0x7E, 0x00  /* (to 0x008A state  26) */,
+                       0x6F /* 'o' */, 0x8D, 0x00  /* (to 0x009C state  34) */,
+                       0x0D /* '.' */, 0x98, 0x00  /* (to 0x00AA state  41) */,
+                       0x61 /* 'a' */, 0xAD, 0x00  /* (to 0x00C2 state  51) */,
+                       0x69 /* 'i' */, 0xCA, 0x00  /* (to 0x00E2 state  58) */,
+                       0x64 /* 'd' */, 0x73, 0x01  /* (to 0x018E state 160) */,
+                       0x72 /* 'r' */, 0x7C, 0x01  /* (to 0x019A state 165) */,
+                       0x65 /* 'e' */, 0xC8, 0x01  /* (to 0x01E9 state 229) */,
+                       0x66 /* 'f' */, 0xE4, 0x01  /* (to 0x0208 state 245) */,
+                       0x6C /* 'l' */, 0x06, 0x02  /* (to 0x022D state 278) */,
+                       0x73 /* 's' */, 0x4B, 0x02  /* (to 0x0275 state 321) */,
+                       0x74 /* 't' */, 0x69, 0x02  /* (to 0x0296 state 337) */,
+                       0x78 /* 'x' */, 0x8A, 0x02  /* (to 0x02BA state 364) */,
+                       0x6D /* 'm' */, 0x14, 0x03  /* (to 0x0347 state 474) */,
+                       0x76 /* 'v' */, 0x6D, 0x03  /* (to 0x03A3 state 549) */,
+                       0x77 /* 'w' */, 0x7A, 0x03  /* (to 0x03B3 state 557) */,
+                       0x3A /* ':' */, 0x32, 0x04  /* (to 0x046E state 692) */,
+                       0x08, /* fail */
+/* pos 0040:   1 */    0xE5 /* 'e' -> */,
+/* pos 0041:   2 */    0xF4 /* 't' -> */,
+/* pos 0042:   3 */    0xA0 /* ' ' -> */,
+/* pos 0043:   4 */    0x00, 0x00                  /* - terminal marker  0 - */,
+/* pos 0045:   5 */    0x6F /* 'o' */, 0x0D, 0x00  /* (to 0x0052 state   6) */,
+                       0x72 /* 'r' */, 0xEC, 0x00  /* (to 0x0134 state 106) */,
+                       0x61 /* 'a' */, 0x7A, 0x03  /* (to 0x03C5 state 574) */,
+                       0x75 /* 'u' */, 0x7C, 0x03  /* (to 0x03CA state 578) */,
+                       0x08, /* fail */
+/* pos 0052:   6 */    0xF3 /* 's' -> */,
+/* pos 0053:   7 */    0xF4 /* 't' -> */,
+/* pos 0054:   8 */    0xA0 /* ' ' -> */,
+/* pos 0055:   9 */    0x00, 0x01                  /* - terminal marker  1 - */,
+/* pos 0057:  10 */    0x6F /* 'o' */, 0x0A, 0x00  /* (to 0x0061 state  11) */,
+                       0x74 /* 't' */, 0x53, 0x00  /* (to 0x00AD state  43) */,
+                       0x65 /* 'e' */, 0x79, 0x02  /* (to 0x02D6 state 381) */,
+                       0x08, /* fail */
+/* pos 0061:  11 */    0xF3 /* 's' -> */,
+/* pos 0062:  12 */    0xF4 /* 't' -> */,
+/* pos 0063:  13 */    0xBA /* ':' -> */,
+/* pos 0064:  14 */    0x00, 0x03                  /* - terminal marker  3 - */,
+/* pos 0066:  15 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x006D state  16) */,
+                       0x61 /* 'a' */, 0xD8, 0x00  /* (to 0x0141 state 112) */,
+                       0x08, /* fail */
+/* pos 006d:  16 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0074 state  17) */,
+                       0x6F /* 'o' */, 0xED, 0x00  /* (to 0x015D state 138) */,
+                       0x08, /* fail */
+/* pos 0074:  17 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x007B state  18) */,
+                       0x74 /* 't' */, 0xEC, 0x00  /* (to 0x0163 state 143) */,
+                       0x08, /* fail */
+/* pos 007b:  18 */    0xE5 /* 'e' -> */,
+/* pos 007c:  19 */    0xE3 /* 'c' -> */,
+/* pos 007d:  20 */    0xF4 /* 't' -> */,
+/* pos 007e:  21 */    0x69 /* 'i' */, 0x07, 0x00  /* (to 0x0085 state  22) */,
+                       0x20 /* ' ' */, 0x53, 0x02  /* (to 0x02D4 state 380) */,
+                       0x08, /* fail */
+/* pos 0085:  22 */    0xEF /* 'o' -> */,
+/* pos 0086:  23 */    0xEE /* 'n' -> */,
+/* pos 0087:  24 */    0xBA /* ':' -> */,
+/* pos 0088:  25 */    0x00, 0x04                  /* - terminal marker  4 - */,
+/* pos 008a:  26 */    0x70 /* 'p' */, 0x0A, 0x00  /* (to 0x0094 state  27) */,
+                       0x72 /* 'r' */, 0x22, 0x02  /* (to 0x02AF state 355) */,
+                       0x73 /* 's' */, 0x08, 0x03  /* (to 0x0398 state 539) */,
+                       0x08, /* fail */
+/* pos 0094:  27 */    0xE7 /* 'g' -> */,
+/* pos 0095:  28 */    0xF2 /* 'r' -> */,
+/* pos 0096:  29 */    0xE1 /* 'a' -> */,
+/* pos 0097:  30 */    0xE4 /* 'd' -> */,
+/* pos 0098:  31 */    0xE5 /* 'e' -> */,
+/* pos 0099:  32 */    0xBA /* ':' -> */,
+/* pos 009a:  33 */    0x00, 0x05                  /* - terminal marker  5 - */,
+/* pos 009c:  34 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x00A3 state  35) */,
+                       0x70 /* 'p' */, 0x61, 0x02  /* (to 0x0300 state 414) */,
+                       0x08, /* fail */
+/* pos 00a3:  35 */    0xE9 /* 'i' -> */,
+/* pos 00a4:  36 */    0xE7 /* 'g' -> */,
+/* pos 00a5:  37 */    0xE9 /* 'i' -> */,
+/* pos 00a6:  38 */    0xEE /* 'n' -> */,
+/* pos 00a7:  39 */    0xBA /* ':' -> */,
+/* pos 00a8:  40 */    0x00, 0x06                  /* - terminal marker  6 - */,
+/* pos 00aa:  41 */    0x8A /* '.' -> */,
+/* pos 00ab:  42 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 00ad:  43 */    0xF4 /* 't' -> */,
+/* pos 00ae:  44 */    0xF0 /* 'p' -> */,
+/* pos 00af:  45 */    0x2F /* '/' */, 0x07, 0x00  /* (to 0x00B6 state  46) */,
+                       0x32 /* '2' */, 0xB0, 0x03  /* (to 0x0462 state 681) */,
+                       0x08, /* fail */
+/* pos 00b6:  46 */    0xB1 /* '1' -> */,
+/* pos 00b7:  47 */    0xAE /* '.' -> */,
+/* pos 00b8:  48 */    0x31 /* '1' */, 0x07, 0x00  /* (to 0x00BF state  49) */,
+                       0x30 /* '0' */, 0xFC, 0x01  /* (to 0x02B7 state 362) */,
+                       0x08, /* fail */
+/* pos 00bf:  49 */    0xA0 /* ' ' -> */,
+/* pos 00c0:  50 */    0x00, 0x08                  /* - terminal marker  8 - */,
+/* pos 00c2:  51 */    0x63 /* 'c' */, 0x0D, 0x00  /* (to 0x00CF state  52) */,
+                       0x75 /* 'u' */, 0x8A, 0x00  /* (to 0x014F state 125) */,
+                       0x67 /* 'g' */, 0xE7, 0x00  /* (to 0x01AF state 178) */,
+                       0x6C /* 'l' */, 0xE8, 0x00  /* (to 0x01B3 state 181) */,
+                       0x08, /* fail */
+/* pos 00cf:  52 */    0xE3 /* 'c' -> */,
+/* pos 00d0:  53 */    0xE5 /* 'e' -> */,
+/* pos 00d1:  54 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x00D8 state  55) */,
+                       0x73 /* 's' */, 0x34, 0x02  /* (to 0x0308 state 421) */,
+                       0x08, /* fail */
+/* pos 00d8:  55 */    0xF4 /* 't' -> */,
+/* pos 00d9:  56 */    0x3A /* ':' */, 0x07, 0x00  /* (to 0x00E0 state  57) */,
+                       0x2D /* '-' */, 0x37, 0x00  /* (to 0x0113 state  87) */,
+                       0x08, /* fail */
+/* pos 00e0:  57 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 00e2:  58 */    0xE6 /* 'f' -> */,
+/* pos 00e3:  59 */    0xAD /* '-' -> */,
+/* pos 00e4:  60 */    0x6D /* 'm' */, 0x0D, 0x00  /* (to 0x00F1 state  61) */,
+                       0x6E /* 'n' */, 0x20, 0x00  /* (to 0x0107 state  76) */,
+                       0x72 /* 'r' */, 0x2A, 0x01  /* (to 0x0214 state 255) */,
+                       0x75 /* 'u' */, 0x2E, 0x01  /* (to 0x021B state 261) */,
+                       0x08, /* fail */
+/* pos 00f1:  61 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x00F8 state  62) */,
+                       0x61 /* 'a' */, 0x1A, 0x01  /* (to 0x020E state 250) */,
+                       0x08, /* fail */
+/* pos 00f8:  62 */    0xE4 /* 'd' -> */,
+/* pos 00f9:  63 */    0xE9 /* 'i' -> */,
+/* pos 00fa:  64 */    0xE6 /* 'f' -> */,
+/* pos 00fb:  65 */    0xE9 /* 'i' -> */,
+/* pos 00fc:  66 */    0xE5 /* 'e' -> */,
+/* pos 00fd:  67 */    0xE4 /* 'd' -> */,
+/* pos 00fe:  68 */    0xAD /* '-' -> */,
+/* pos 00ff:  69 */    0xF3 /* 's' -> */,
+/* pos 0100:  70 */    0xE9 /* 'i' -> */,
+/* pos 0101:  71 */    0xEE /* 'n' -> */,
+/* pos 0102:  72 */    0xE3 /* 'c' -> */,
+/* pos 0103:  73 */    0xE5 /* 'e' -> */,
+/* pos 0104:  74 */    0xBA /* ':' -> */,
+/* pos 0105:  75 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 0107:  76 */    0xEF /* 'o' -> */,
+/* pos 0108:  77 */    0xEE /* 'n' -> */,
+/* pos 0109:  78 */    0xE5 /* 'e' -> */,
+/* pos 010a:  79 */    0xAD /* '-' -> */,
+/* pos 010b:  80 */    0xED /* 'm' -> */,
+/* pos 010c:  81 */    0xE1 /* 'a' -> */,
+/* pos 010d:  82 */    0xF4 /* 't' -> */,
+/* pos 010e:  83 */    0xE3 /* 'c' -> */,
+/* pos 010f:  84 */    0xE8 /* 'h' -> */,
+/* pos 0110:  85 */    0xBA /* ':' -> */,
+/* pos 0111:  86 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 0113:  87 */    0x65 /* 'e' */, 0x0D, 0x00  /* (to 0x0120 state  88) */,
+                       0x6C /* 'l' */, 0x14, 0x00  /* (to 0x012A state  97) */,
+                       0x72 /* 'r' */, 0x8E, 0x00  /* (to 0x01A7 state 171) */,
+                       0x63 /* 'c' */, 0x14, 0x02  /* (to 0x0330 state 453) */,
+                       0x08, /* fail */
+/* pos 0120:  88 */    0xEE /* 'n' -> */,
+/* pos 0121:  89 */    0xE3 /* 'c' -> */,
+/* pos 0122:  90 */    0xEF /* 'o' -> */,
+/* pos 0123:  91 */    0xE4 /* 'd' -> */,
+/* pos 0124:  92 */    0xE9 /* 'i' -> */,
+/* pos 0125:  93 */    0xEE /* 'n' -> */,
+/* pos 0126:  94 */    0xE7 /* 'g' -> */,
+/* pos 0127:  95 */    0xBA /* ':' -> */,
+/* pos 0128:  96 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 012a:  97 */    0xE1 /* 'a' -> */,
+/* pos 012b:  98 */    0xEE /* 'n' -> */,
+/* pos 012c:  99 */    0xE7 /* 'g' -> */,
+/* pos 012d: 100 */    0xF5 /* 'u' -> */,
+/* pos 012e: 101 */    0xE1 /* 'a' -> */,
+/* pos 012f: 102 */    0xE7 /* 'g' -> */,
+/* pos 0130: 103 */    0xE5 /* 'e' -> */,
+/* pos 0131: 104 */    0xBA /* ':' -> */,
+/* pos 0132: 105 */    0x00, 0x0F                  /* - terminal marker 15 - */,
+/* pos 0134: 106 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x013B state 107) */,
+                       0x6F /* 'o' */, 0x1E, 0x02  /* (to 0x0355 state 487) */,
+                       0x08, /* fail */
+/* pos 013b: 107 */    0xE7 /* 'g' -> */,
+/* pos 013c: 108 */    0xED /* 'm' -> */,
+/* pos 013d: 109 */    0xE1 /* 'a' -> */,
+/* pos 013e: 110 */    0xBA /* ':' -> */,
+/* pos 013f: 111 */    0x00, 0x10                  /* - terminal marker 16 - */,
+/* pos 0141: 112 */    0xE3 /* 'c' -> */,
+/* pos 0142: 113 */    0xE8 /* 'h' -> */,
+/* pos 0143: 114 */    0xE5 /* 'e' -> */,
+/* pos 0144: 115 */    0xAD /* '-' -> */,
+/* pos 0145: 116 */    0xE3 /* 'c' -> */,
+/* pos 0146: 117 */    0xEF /* 'o' -> */,
+/* pos 0147: 118 */    0xEE /* 'n' -> */,
+/* pos 0148: 119 */    0xF4 /* 't' -> */,
+/* pos 0149: 120 */    0xF2 /* 'r' -> */,
+/* pos 014a: 121 */    0xEF /* 'o' -> */,
+/* pos 014b: 122 */    0xEC /* 'l' -> */,
+/* pos 014c: 123 */    0xBA /* ':' -> */,
+/* pos 014d: 124 */    0x00, 0x11                  /* - terminal marker 17 - */,
+/* pos 014f: 125 */    0xF4 /* 't' -> */,
+/* pos 0150: 126 */    0xE8 /* 'h' -> */,
+/* pos 0151: 127 */    0xEF /* 'o' -> */,
+/* pos 0152: 128 */    0xF2 /* 'r' -> */,
+/* pos 0153: 129 */    0xE9 /* 'i' -> */,
+/* pos 0154: 130 */    0xFA /* 'z' -> */,
+/* pos 0155: 131 */    0xE1 /* 'a' -> */,
+/* pos 0156: 132 */    0xF4 /* 't' -> */,
+/* pos 0157: 133 */    0xE9 /* 'i' -> */,
+/* pos 0158: 134 */    0xEF /* 'o' -> */,
+/* pos 0159: 135 */    0xEE /* 'n' -> */,
+/* pos 015a: 136 */    0xBA /* ':' -> */,
+/* pos 015b: 137 */    0x00, 0x12                  /* - terminal marker 18 - */,
+/* pos 015d: 138 */    0xEB /* 'k' -> */,
+/* pos 015e: 139 */    0xE9 /* 'i' -> */,
+/* pos 015f: 140 */    0xE5 /* 'e' -> */,
+/* pos 0160: 141 */    0xBA /* ':' -> */,
+/* pos 0161: 142 */    0x00, 0x13                  /* - terminal marker 19 - */,
+/* pos 0163: 143 */    0xE5 /* 'e' -> */,
+/* pos 0164: 144 */    0xEE /* 'n' -> */,
+/* pos 0165: 145 */    0xF4 /* 't' -> */,
+/* pos 0166: 146 */    0xAD /* '-' -> */,
+/* pos 0167: 147 */    0x6C /* 'l' */, 0x10, 0x00  /* (to 0x0177 state 148) */,
+                       0x74 /* 't' */, 0x1E, 0x00  /* (to 0x0188 state 155) */,
+                       0x64 /* 'd' */, 0x4C, 0x00  /* (to 0x01B9 state 186) */,
+                       0x65 /* 'e' */, 0x56, 0x00  /* (to 0x01C6 state 198) */,
+                       0x72 /* 'r' */, 0x6F, 0x00  /* (to 0x01E2 state 223) */,
+                       0x08, /* fail */
+/* pos 0177: 148 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x0181 state 149) */,
+                       0x61 /* 'a' */, 0x56, 0x00  /* (to 0x01D0 state 207) */,
+                       0x6F /* 'o' */, 0x5C, 0x00  /* (to 0x01D9 state 215) */,
+                       0x08, /* fail */
+/* pos 0181: 149 */    0xEE /* 'n' -> */,
+/* pos 0182: 150 */    0xE7 /* 'g' -> */,
+/* pos 0183: 151 */    0xF4 /* 't' -> */,
+/* pos 0184: 152 */    0xE8 /* 'h' -> */,
+/* pos 0185: 153 */    0xBA /* ':' -> */,
+/* pos 0186: 154 */    0x00, 0x14                  /* - terminal marker 20 - */,
+/* pos 0188: 155 */    0xF9 /* 'y' -> */,
+/* pos 0189: 156 */    0xF0 /* 'p' -> */,
+/* pos 018a: 157 */    0xE5 /* 'e' -> */,
+/* pos 018b: 158 */    0xBA /* ':' -> */,
+/* pos 018c: 159 */    0x00, 0x15                  /* - terminal marker 21 - */,
+/* pos 018e: 160 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0195 state 161) */,
+                       0x65 /* 'e' */, 0x3C, 0x02  /* (to 0x03CD state 580) */,
+                       0x08, /* fail */
+/* pos 0195: 161 */    0xF4 /* 't' -> */,
+/* pos 0196: 162 */    0xE5 /* 'e' -> */,
+/* pos 0197: 163 */    0xBA /* ':' -> */,
+/* pos 0198: 164 */    0x00, 0x16                  /* - terminal marker 22 - */,
+/* pos 019a: 165 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x01A1 state 166) */,
+                       0x65 /* 'e' */, 0xB6, 0x00  /* (to 0x0253 state 304) */,
+                       0x08, /* fail */
+/* pos 01a1: 166 */    0xEE /* 'n' -> */,
+/* pos 01a2: 167 */    0xE7 /* 'g' -> */,
+/* pos 01a3: 168 */    0xE5 /* 'e' -> */,
+/* pos 01a4: 169 */    0xBA /* ':' -> */,
+/* pos 01a5: 170 */    0x00, 0x17                  /* - terminal marker 23 - */,
+/* pos 01a7: 171 */    0xE1 /* 'a' -> */,
+/* pos 01a8: 172 */    0xEE /* 'n' -> */,
+/* pos 01a9: 173 */    0xE7 /* 'g' -> */,
+/* pos 01aa: 174 */    0xE5 /* 'e' -> */,
+/* pos 01ab: 175 */    0xF3 /* 's' -> */,
+/* pos 01ac: 176 */    0xBA /* ':' -> */,
+/* pos 01ad: 177 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 01af: 178 */    0xE5 /* 'e' -> */,
+/* pos 01b0: 179 */    0xBA /* ':' -> */,
+/* pos 01b1: 180 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* pos 01b3: 181 */    0xEC /* 'l' -> */,
+/* pos 01b4: 182 */    0xEF /* 'o' -> */,
+/* pos 01b5: 183 */    0xF7 /* 'w' -> */,
+/* pos 01b6: 184 */    0xBA /* ':' -> */,
+/* pos 01b7: 185 */    0x00, 0x22                  /* - terminal marker 34 - */,
+/* pos 01b9: 186 */    0xE9 /* 'i' -> */,
+/* pos 01ba: 187 */    0xF3 /* 's' -> */,
+/* pos 01bb: 188 */    0xF0 /* 'p' -> */,
+/* pos 01bc: 189 */    0xEF /* 'o' -> */,
+/* pos 01bd: 190 */    0xF3 /* 's' -> */,
+/* pos 01be: 191 */    0xE9 /* 'i' -> */,
+/* pos 01bf: 192 */    0xF4 /* 't' -> */,
+/* pos 01c0: 193 */    0xE9 /* 'i' -> */,
+/* pos 01c1: 194 */    0xEF /* 'o' -> */,
+/* pos 01c2: 195 */    0xEE /* 'n' -> */,
+/* pos 01c3: 196 */    0xBA /* ':' -> */,
+/* pos 01c4: 197 */    0x00, 0x23                  /* - terminal marker 35 - */,
+/* pos 01c6: 198 */    0xEE /* 'n' -> */,
+/* pos 01c7: 199 */    0xE3 /* 'c' -> */,
+/* pos 01c8: 200 */    0xEF /* 'o' -> */,
+/* pos 01c9: 201 */    0xE4 /* 'd' -> */,
+/* pos 01ca: 202 */    0xE9 /* 'i' -> */,
+/* pos 01cb: 203 */    0xEE /* 'n' -> */,
+/* pos 01cc: 204 */    0xE7 /* 'g' -> */,
+/* pos 01cd: 205 */    0xBA /* ':' -> */,
+/* pos 01ce: 206 */    0x00, 0x24                  /* - terminal marker 36 - */,
+/* pos 01d0: 207 */    0xEE /* 'n' -> */,
+/* pos 01d1: 208 */    0xE7 /* 'g' -> */,
+/* pos 01d2: 209 */    0xF5 /* 'u' -> */,
+/* pos 01d3: 210 */    0xE1 /* 'a' -> */,
+/* pos 01d4: 211 */    0xE7 /* 'g' -> */,
+/* pos 01d5: 212 */    0xE5 /* 'e' -> */,
+/* pos 01d6: 213 */    0xBA /* ':' -> */,
+/* pos 01d7: 214 */    0x00, 0x25                  /* - terminal marker 37 - */,
+/* pos 01d9: 215 */    0xE3 /* 'c' -> */,
+/* pos 01da: 216 */    0xE1 /* 'a' -> */,
+/* pos 01db: 217 */    0xF4 /* 't' -> */,
+/* pos 01dc: 218 */    0xE9 /* 'i' -> */,
+/* pos 01dd: 219 */    0xEF /* 'o' -> */,
+/* pos 01de: 220 */    0xEE /* 'n' -> */,
+/* pos 01df: 221 */    0xBA /* ':' -> */,
+/* pos 01e0: 222 */    0x00, 0x26                  /* - terminal marker 38 - */,
+/* pos 01e2: 223 */    0xE1 /* 'a' -> */,
+/* pos 01e3: 224 */    0xEE /* 'n' -> */,
+/* pos 01e4: 225 */    0xE7 /* 'g' -> */,
+/* pos 01e5: 226 */    0xE5 /* 'e' -> */,
+/* pos 01e6: 227 */    0xBA /* ':' -> */,
+/* pos 01e7: 228 */    0x00, 0x27                  /* - terminal marker 39 - */,
+/* pos 01e9: 229 */    0x74 /* 't' */, 0x07, 0x00  /* (to 0x01F0 state 230) */,
+                       0x78 /* 'x' */, 0x09, 0x00  /* (to 0x01F5 state 234) */,
+                       0x08, /* fail */
+/* pos 01f0: 230 */    0xE1 /* 'a' -> */,
+/* pos 01f1: 231 */    0xE7 /* 'g' -> */,
+/* pos 01f2: 232 */    0xBA /* ':' -> */,
+/* pos 01f3: 233 */    0x00, 0x28                  /* - terminal marker 40 - */,
+/* pos 01f5: 234 */    0xF0 /* 'p' -> */,
+/* pos 01f6: 235 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x01FD state 236) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x0202 state 240) */,
+                       0x08, /* fail */
+/* pos 01fd: 236 */    0xE3 /* 'c' -> */,
+/* pos 01fe: 237 */    0xF4 /* 't' -> */,
+/* pos 01ff: 238 */    0xBA /* ':' -> */,
+/* pos 0200: 239 */    0x00, 0x29                  /* - terminal marker 41 - */,
+/* pos 0202: 240 */    0xF2 /* 'r' -> */,
+/* pos 0203: 241 */    0xE5 /* 'e' -> */,
+/* pos 0204: 242 */    0xF3 /* 's' -> */,
+/* pos 0205: 243 */    0xBA /* ':' -> */,
+/* pos 0206: 244 */    0x00, 0x2A                  /* - terminal marker 42 - */,
+/* pos 0208: 245 */    0xF2 /* 'r' -> */,
+/* pos 0209: 246 */    0xEF /* 'o' -> */,
+/* pos 020a: 247 */    0xED /* 'm' -> */,
+/* pos 020b: 248 */    0xBA /* ':' -> */,
+/* pos 020c: 249 */    0x00, 0x2B                  /* - terminal marker 43 - */,
+/* pos 020e: 250 */    0xF4 /* 't' -> */,
+/* pos 020f: 251 */    0xE3 /* 'c' -> */,
+/* pos 0210: 252 */    0xE8 /* 'h' -> */,
+/* pos 0211: 253 */    0xBA /* ':' -> */,
+/* pos 0212: 254 */    0x00, 0x2C                  /* - terminal marker 44 - */,
+/* pos 0214: 255 */    0xE1 /* 'a' -> */,
+/* pos 0215: 256 */    0xEE /* 'n' -> */,
+/* pos 0216: 257 */    0xE7 /* 'g' -> */,
+/* pos 0217: 258 */    0xE5 /* 'e' -> */,
+/* pos 0218: 259 */    0xBA /* ':' -> */,
+/* pos 0219: 260 */    0x00, 0x2D                  /* - terminal marker 45 - */,
+/* pos 021b: 261 */    0xEE /* 'n' -> */,
+/* pos 021c: 262 */    0xED /* 'm' -> */,
+/* pos 021d: 263 */    0xEF /* 'o' -> */,
+/* pos 021e: 264 */    0xE4 /* 'd' -> */,
+/* pos 021f: 265 */    0xE9 /* 'i' -> */,
+/* pos 0220: 266 */    0xE6 /* 'f' -> */,
+/* pos 0221: 267 */    0xE9 /* 'i' -> */,
+/* pos 0222: 268 */    0xE5 /* 'e' -> */,
+/* pos 0223: 269 */    0xE4 /* 'd' -> */,
+/* pos 0224: 270 */    0xAD /* '-' -> */,
+/* pos 0225: 271 */    0xF3 /* 's' -> */,
+/* pos 0226: 272 */    0xE9 /* 'i' -> */,
+/* pos 0227: 273 */    0xEE /* 'n' -> */,
+/* pos 0228: 274 */    0xE3 /* 'c' -> */,
+/* pos 0229: 275 */    0xE5 /* 'e' -> */,
+/* pos 022a: 276 */    0xBA /* ':' -> */,
+/* pos 022b: 277 */    0x00, 0x2E                  /* - terminal marker 46 - */,
+/* pos 022d: 278 */    0x61 /* 'a' */, 0x0A, 0x00  /* (to 0x0237 state 279) */,
+                       0x69 /* 'i' */, 0x15, 0x00  /* (to 0x0245 state 292) */,
+                       0x6F /* 'o' */, 0x17, 0x00  /* (to 0x024A state 296) */,
+                       0x08, /* fail */
+/* pos 0237: 279 */    0xF3 /* 's' -> */,
+/* pos 0238: 280 */    0xF4 /* 't' -> */,
+/* pos 0239: 281 */    0xAD /* '-' -> */,
+/* pos 023a: 282 */    0xED /* 'm' -> */,
+/* pos 023b: 283 */    0xEF /* 'o' -> */,
+/* pos 023c: 284 */    0xE4 /* 'd' -> */,
+/* pos 023d: 285 */    0xE9 /* 'i' -> */,
+/* pos 023e: 286 */    0xE6 /* 'f' -> */,
+/* pos 023f: 287 */    0xE9 /* 'i' -> */,
+/* pos 0240: 288 */    0xE5 /* 'e' -> */,
+/* pos 0241: 289 */    0xE4 /* 'd' -> */,
+/* pos 0242: 290 */    0xBA /* ':' -> */,
+/* pos 0243: 291 */    0x00, 0x2F                  /* - terminal marker 47 - */,
+/* pos 0245: 292 */    0xEE /* 'n' -> */,
+/* pos 0246: 293 */    0xEB /* 'k' -> */,
+/* pos 0247: 294 */    0xBA /* ':' -> */,
+/* pos 0248: 295 */    0x00, 0x30                  /* - terminal marker 48 - */,
+/* pos 024a: 296 */    0xE3 /* 'c' -> */,
+/* pos 024b: 297 */    0xE1 /* 'a' -> */,
+/* pos 024c: 298 */    0xF4 /* 't' -> */,
+/* pos 024d: 299 */    0xE9 /* 'i' -> */,
+/* pos 024e: 300 */    0xEF /* 'o' -> */,
+/* pos 024f: 301 */    0xEE /* 'n' -> */,
+/* pos 0250: 302 */    0xBA /* ':' -> */,
+/* pos 0251: 303 */    0x00, 0x31                  /* - terminal marker 49 - */,
+/* pos 0253: 304 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x025D state 305) */,
+                       0x74 /* 't' */, 0x14, 0x00  /* (to 0x026A state 311) */,
+                       0x70 /* 'p' */, 0x88, 0x01  /* (to 0x03E1 state 596) */,
+                       0x08, /* fail */
+/* pos 025d: 305 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0264 state 306) */,
+                       0x65 /* 'e' */, 0xCA, 0x00  /* (to 0x032A state 448) */,
+                       0x08, /* fail */
+/* pos 0264: 306 */    0xE5 /* 'e' -> */,
+/* pos 0265: 307 */    0xF3 /* 's' -> */,
+/* pos 0266: 308 */    0xE8 /* 'h' -> */,
+/* pos 0267: 309 */    0xBA /* ':' -> */,
+/* pos 0268: 310 */    0x00, 0x35                  /* - terminal marker 53 - */,
+/* pos 026a: 311 */    0xF2 /* 'r' -> */,
+/* pos 026b: 312 */    0xF9 /* 'y' -> */,
+/* pos 026c: 313 */    0xAD /* '-' -> */,
+/* pos 026d: 314 */    0xE1 /* 'a' -> */,
+/* pos 026e: 315 */    0xE6 /* 'f' -> */,
+/* pos 026f: 316 */    0xF4 /* 't' -> */,
+/* pos 0270: 317 */    0xE5 /* 'e' -> */,
+/* pos 0271: 318 */    0xF2 /* 'r' -> */,
+/* pos 0272: 319 */    0xBA /* ':' -> */,
+/* pos 0273: 320 */    0x00, 0x36                  /* - terminal marker 54 - */,
+/* pos 0275: 321 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x027C state 322) */,
+                       0x74 /* 't' */, 0x06, 0x01  /* (to 0x037E state 514) */,
+                       0x08, /* fail */
+/* pos 027c: 322 */    0x72 /* 'r' */, 0x0A, 0x00  /* (to 0x0286 state 323) */,
+                       0x74 /* 't' */, 0x0D, 0x00  /* (to 0x028C state 328) */,
+                       0x63 /* 'c' */, 0x6B, 0x01  /* (to 0x03ED state 607) */,
+                       0x08, /* fail */
+/* pos 0286: 323 */    0xF6 /* 'v' -> */,
+/* pos 0287: 324 */    0xE5 /* 'e' -> */,
+/* pos 0288: 325 */    0xF2 /* 'r' -> */,
+/* pos 0289: 326 */    0xBA /* ':' -> */,
+/* pos 028a: 327 */    0x00, 0x37                  /* - terminal marker 55 - */,
+/* pos 028c: 328 */    0xAD /* '-' -> */,
+/* pos 028d: 329 */    0xE3 /* 'c' -> */,
+/* pos 028e: 330 */    0xEF /* 'o' -> */,
+/* pos 028f: 331 */    0xEF /* 'o' -> */,
+/* pos 0290: 332 */    0xEB /* 'k' -> */,
+/* pos 0291: 333 */    0xE9 /* 'i' -> */,
+/* pos 0292: 334 */    0xE5 /* 'e' -> */,
+/* pos 0293: 335 */    0xBA /* ':' -> */,
+/* pos 0294: 336 */    0x00, 0x38                  /* - terminal marker 56 - */,
+/* pos 0296: 337 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x029D state 338) */,
+                       0x65 /* 'e' */, 0x45, 0x01  /* (to 0x03DE state 594) */,
+                       0x08, /* fail */
+/* pos 029d: 338 */    0xE1 /* 'a' -> */,
+/* pos 029e: 339 */    0xEE /* 'n' -> */,
+/* pos 029f: 340 */    0xF3 /* 's' -> */,
+/* pos 02a0: 341 */    0xE6 /* 'f' -> */,
+/* pos 02a1: 342 */    0xE5 /* 'e' -> */,
+/* pos 02a2: 343 */    0xF2 /* 'r' -> */,
+/* pos 02a3: 344 */    0xAD /* '-' -> */,
+/* pos 02a4: 345 */    0xE5 /* 'e' -> */,
+/* pos 02a5: 346 */    0xEE /* 'n' -> */,
+/* pos 02a6: 347 */    0xE3 /* 'c' -> */,
+/* pos 02a7: 348 */    0xEF /* 'o' -> */,
+/* pos 02a8: 349 */    0xE4 /* 'd' -> */,
+/* pos 02a9: 350 */    0xE9 /* 'i' -> */,
+/* pos 02aa: 351 */    0xEE /* 'n' -> */,
+/* pos 02ab: 352 */    0xE7 /* 'g' -> */,
+/* pos 02ac: 353 */    0xBA /* ':' -> */,
+/* pos 02ad: 354 */    0x00, 0x3A                  /* - terminal marker 58 - */,
+/* pos 02af: 355 */    0xE9 /* 'i' -> */,
+/* pos 02b0: 356 */    0xAD /* '-' -> */,
+/* pos 02b1: 357 */    0xE1 /* 'a' -> */,
+/* pos 02b2: 358 */    0xF2 /* 'r' -> */,
+/* pos 02b3: 359 */    0xE7 /* 'g' -> */,
+/* pos 02b4: 360 */    0xF3 /* 's' -> */,
+/* pos 02b5: 361 */    0x00, 0x42                  /* - terminal marker 66 - */,
+/* pos 02b7: 362 */    0xA0 /* ' ' -> */,
+/* pos 02b8: 363 */    0x00, 0x45                  /* - terminal marker 69 - */,
+/* pos 02ba: 364 */    0xAD /* '-' -> */,
+/* pos 02bb: 365 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x02C5 state 366) */,
+                       0x61 /* 'a' */, 0x1D, 0x00  /* (to 0x02DB state 385) */,
+                       0x72 /* 'r' */, 0x14, 0x01  /* (to 0x03D5 state 586) */,
+                       0x08, /* fail */
+/* pos 02c5: 366 */    0xEF /* 'o' -> */,
+/* pos 02c6: 367 */    0xF2 /* 'r' -> */,
+/* pos 02c7: 368 */    0xF7 /* 'w' -> */,
+/* pos 02c8: 369 */    0xE1 /* 'a' -> */,
+/* pos 02c9: 370 */    0xF2 /* 'r' -> */,
+/* pos 02ca: 371 */    0xE4 /* 'd' -> */,
+/* pos 02cb: 372 */    0xE5 /* 'e' -> */,
+/* pos 02cc: 373 */    0xE4 /* 'd' -> */,
+/* pos 02cd: 374 */    0xAD /* '-' -> */,
+/* pos 02ce: 375 */    0xE6 /* 'f' -> */,
+/* pos 02cf: 376 */    0xEF /* 'o' -> */,
+/* pos 02d0: 377 */    0xF2 /* 'r' -> */,
+/* pos 02d1: 378 */    0xBA /* ':' -> */,
+/* pos 02d2: 379 */    0x00, 0x46                  /* - terminal marker 70 - */,
+/* pos 02d4: 380 */    0x00, 0x47                  /* - terminal marker 71 - */,
+/* pos 02d6: 381 */    0xE1 /* 'a' -> */,
+/* pos 02d7: 382 */    0xE4 /* 'd' -> */,
+/* pos 02d8: 383 */    0xA0 /* ' ' -> */,
+/* pos 02d9: 384 */    0x00, 0x48                  /* - terminal marker 72 - */,
+/* pos 02db: 385 */    0x75 /* 'u' */, 0x07, 0x00  /* (to 0x02E2 state 386) */,
+                       0x6D /* 'm' */, 0x0F, 0x00  /* (to 0x02ED state 396) */,
+                       0x08, /* fail */
+/* pos 02e2: 386 */    0xF4 /* 't' -> */,
+/* pos 02e3: 387 */    0xE8 /* 'h' -> */,
+/* pos 02e4: 388 */    0xAD /* '-' -> */,
+/* pos 02e5: 389 */    0xF4 /* 't' -> */,
+/* pos 02e6: 390 */    0xEF /* 'o' -> */,
+/* pos 02e7: 391 */    0xEB /* 'k' -> */,
+/* pos 02e8: 392 */    0xE5 /* 'e' -> */,
+/* pos 02e9: 393 */    0xEE /* 'n' -> */,
+/* pos 02ea: 394 */    0xBA /* ':' -> */,
+/* pos 02eb: 395 */    0x00, 0x4C                  /* - terminal marker 76 - */,
+/* pos 02ed: 396 */    0xFA /* 'z' -> */,
+/* pos 02ee: 397 */    0xEE /* 'n' -> */,
+/* pos 02ef: 398 */    0xAD /* '-' -> */,
+/* pos 02f0: 399 */    0xE4 /* 'd' -> */,
+/* pos 02f1: 400 */    0xF3 /* 's' -> */,
+/* pos 02f2: 401 */    0xF3 /* 's' -> */,
+/* pos 02f3: 402 */    0xAD /* '-' -> */,
+/* pos 02f4: 403 */    0xF3 /* 's' -> */,
+/* pos 02f5: 404 */    0xE9 /* 'i' -> */,
+/* pos 02f6: 405 */    0xE7 /* 'g' -> */,
+/* pos 02f7: 406 */    0xEE /* 'n' -> */,
+/* pos 02f8: 407 */    0xE1 /* 'a' -> */,
+/* pos 02f9: 408 */    0xF4 /* 't' -> */,
+/* pos 02fa: 409 */    0xF5 /* 'u' -> */,
+/* pos 02fb: 410 */    0xF2 /* 'r' -> */,
+/* pos 02fc: 411 */    0xE5 /* 'e' -> */,
+/* pos 02fd: 412 */    0xBA /* ':' -> */,
+/* pos 02fe: 413 */    0x00, 0x4D                  /* - terminal marker 77 - */,
+/* pos 0300: 414 */    0xF4 /* 't' -> */,
+/* pos 0301: 415 */    0xE9 /* 'i' -> */,
+/* pos 0302: 416 */    0xEF /* 'o' -> */,
+/* pos 0303: 417 */    0xEE /* 'n' -> */,
+/* pos 0304: 418 */    0xF3 /* 's' -> */,
+/* pos 0305: 419 */    0xA0 /* ' ' -> */,
+/* pos 0306: 420 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 0308: 421 */    0xF3 /* 's' -> */,
+/* pos 0309: 422 */    0xAD /* '-' -> */,
+/* pos 030a: 423 */    0xE3 /* 'c' -> */,
+/* pos 030b: 424 */    0xEF /* 'o' -> */,
+/* pos 030c: 425 */    0xEE /* 'n' -> */,
+/* pos 030d: 426 */    0xF4 /* 't' -> */,
+/* pos 030e: 427 */    0xF2 /* 'r' -> */,
+/* pos 030f: 428 */    0xEF /* 'o' -> */,
+/* pos 0310: 429 */    0xEC /* 'l' -> */,
+/* pos 0311: 430 */    0xAD /* '-' -> */,
+/* pos 0312: 431 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0319 state 432) */,
+                       0x61 /* 'a' */, 0x24, 0x00  /* (to 0x0339 state 461) */,
+                       0x08, /* fail */
+/* pos 0319: 432 */    0xE5 /* 'e' -> */,
+/* pos 031a: 433 */    0xF1 /* 'q' -> */,
+/* pos 031b: 434 */    0xF5 /* 'u' -> */,
+/* pos 031c: 435 */    0xE5 /* 'e' -> */,
+/* pos 031d: 436 */    0xF3 /* 's' -> */,
+/* pos 031e: 437 */    0xF4 /* 't' -> */,
+/* pos 031f: 438 */    0xAD /* '-' -> */,
+/* pos 0320: 439 */    0xE8 /* 'h' -> */,
+/* pos 0321: 440 */    0xE5 /* 'e' -> */,
+/* pos 0322: 441 */    0xE1 /* 'a' -> */,
+/* pos 0323: 442 */    0xE4 /* 'd' -> */,
+/* pos 0324: 443 */    0xE5 /* 'e' -> */,
+/* pos 0325: 444 */    0xF2 /* 'r' -> */,
+/* pos 0326: 445 */    0xF3 /* 's' -> */,
+/* pos 0327: 446 */    0xBA /* ':' -> */,
+/* pos 0328: 447 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 032a: 448 */    0xF2 /* 'r' -> */,
+/* pos 032b: 449 */    0xE5 /* 'e' -> */,
+/* pos 032c: 450 */    0xF2 /* 'r' -> */,
+/* pos 032d: 451 */    0xBA /* ':' -> */,
+/* pos 032e: 452 */    0x00, 0x18                  /* - terminal marker 24 - */,
+/* pos 0330: 453 */    0xE8 /* 'h' -> */,
+/* pos 0331: 454 */    0xE1 /* 'a' -> */,
+/* pos 0332: 455 */    0xF2 /* 'r' -> */,
+/* pos 0333: 456 */    0xF3 /* 's' -> */,
+/* pos 0334: 457 */    0xE5 /* 'e' -> */,
+/* pos 0335: 458 */    0xF4 /* 't' -> */,
+/* pos 0336: 459 */    0xBA /* ':' -> */,
+/* pos 0337: 460 */    0x00, 0x1E                  /* - terminal marker 30 - */,
+/* pos 0339: 461 */    0xEC /* 'l' -> */,
+/* pos 033a: 462 */    0xEC /* 'l' -> */,
+/* pos 033b: 463 */    0xEF /* 'o' -> */,
+/* pos 033c: 464 */    0xF7 /* 'w' -> */,
+/* pos 033d: 465 */    0xAD /* '-' -> */,
+/* pos 033e: 466 */    0xEF /* 'o' -> */,
+/* pos 033f: 467 */    0xF2 /* 'r' -> */,
+/* pos 0340: 468 */    0xE9 /* 'i' -> */,
+/* pos 0341: 469 */    0xE7 /* 'g' -> */,
+/* pos 0342: 470 */    0xE9 /* 'i' -> */,
+/* pos 0343: 471 */    0xEE /* 'n' -> */,
+/* pos 0344: 472 */    0xBA /* ':' -> */,
+/* pos 0345: 473 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 0347: 474 */    0xE1 /* 'a' -> */,
+/* pos 0348: 475 */    0xF8 /* 'x' -> */,
+/* pos 0349: 476 */    0xAD /* '-' -> */,
+/* pos 034a: 477 */    0xE6 /* 'f' -> */,
+/* pos 034b: 478 */    0xEF /* 'o' -> */,
+/* pos 034c: 479 */    0xF2 /* 'r' -> */,
+/* pos 034d: 480 */    0xF7 /* 'w' -> */,
+/* pos 034e: 481 */    0xE1 /* 'a' -> */,
+/* pos 034f: 482 */    0xF2 /* 'r' -> */,
+/* pos 0350: 483 */    0xE4 /* 'd' -> */,
+/* pos 0351: 484 */    0xF3 /* 's' -> */,
+/* pos 0352: 485 */    0xBA /* ':' -> */,
+/* pos 0353: 486 */    0x00, 0x32                  /* - terminal marker 50 - */,
+/* pos 0355: 487 */    0xF8 /* 'x' -> */,
+/* pos 0356: 488 */    0xF9 /* 'y' -> */,
+/* pos 0357: 489 */    0x2D /* '-' */, 0x07, 0x00  /* (to 0x035E state 490) */,
+                       0x20 /* ' ' */, 0x79, 0x00  /* (to 0x03D3 state 585) */,
+                       0x08, /* fail */
+/* pos 035e: 490 */    0xE1 /* 'a' -> */,
+/* pos 035f: 491 */    0xF5 /* 'u' -> */,
+/* pos 0360: 492 */    0xF4 /* 't' -> */,
+/* pos 0361: 493 */    0xE8 /* 'h' -> */,
+/* pos 0362: 494 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0369 state 495) */,
+                       0x6F /* 'o' */, 0x0E, 0x00  /* (to 0x0373 state 504) */,
+                       0x08, /* fail */
+/* pos 0369: 495 */    0xEE /* 'n' -> */,
+/* pos 036a: 496 */    0xF4 /* 't' -> */,
+/* pos 036b: 497 */    0xE9 /* 'i' -> */,
+/* pos 036c: 498 */    0xE3 /* 'c' -> */,
+/* pos 036d: 499 */    0xE1 /* 'a' -> */,
+/* pos 036e: 500 */    0xF4 /* 't' -> */,
+/* pos 036f: 501 */    0xE5 /* 'e' -> */,
+/* pos 0370: 502 */    0xBA /* ':' -> */,
+/* pos 0371: 503 */    0x00, 0x33                  /* - terminal marker 51 - */,
+/* pos 0373: 504 */    0xF2 /* 'r' -> */,
+/* pos 0374: 505 */    0xE9 /* 'i' -> */,
+/* pos 0375: 506 */    0xFA /* 'z' -> */,
+/* pos 0376: 507 */    0xE1 /* 'a' -> */,
+/* pos 0377: 508 */    0xF4 /* 't' -> */,
+/* pos 0378: 509 */    0xE9 /* 'i' -> */,
+/* pos 0379: 510 */    0xEF /* 'o' -> */,
+/* pos 037a: 511 */    0xEE /* 'n' -> */,
+/* pos 037b: 512 */    0xBA /* ':' -> */,
+/* pos 037c: 513 */    0x00, 0x34                  /* - terminal marker 52 - */,
+/* pos 037e: 514 */    0xF2 /* 'r' -> */,
+/* pos 037f: 515 */    0xE9 /* 'i' -> */,
+/* pos 0380: 516 */    0xE3 /* 'c' -> */,
+/* pos 0381: 517 */    0xF4 /* 't' -> */,
+/* pos 0382: 518 */    0xAD /* '-' -> */,
+/* pos 0383: 519 */    0xF4 /* 't' -> */,
+/* pos 0384: 520 */    0xF2 /* 'r' -> */,
+/* pos 0385: 521 */    0xE1 /* 'a' -> */,
+/* pos 0386: 522 */    0xEE /* 'n' -> */,
+/* pos 0387: 523 */    0xF3 /* 's' -> */,
+/* pos 0388: 524 */    0xF0 /* 'p' -> */,
+/* pos 0389: 525 */    0xEF /* 'o' -> */,
+/* pos 038a: 526 */    0xF2 /* 'r' -> */,
+/* pos 038b: 527 */    0xF4 /* 't' -> */,
+/* pos 038c: 528 */    0xAD /* '-' -> */,
+/* pos 038d: 529 */    0xF3 /* 's' -> */,
+/* pos 038e: 530 */    0xE5 /* 'e' -> */,
+/* pos 038f: 531 */    0xE3 /* 'c' -> */,
+/* pos 0390: 532 */    0xF5 /* 'u' -> */,
+/* pos 0391: 533 */    0xF2 /* 'r' -> */,
+/* pos 0392: 534 */    0xE9 /* 'i' -> */,
+/* pos 0393: 535 */    0xF4 /* 't' -> */,
+/* pos 0394: 536 */    0xF9 /* 'y' -> */,
+/* pos 0395: 537 */    0xBA /* ':' -> */,
+/* pos 0396: 538 */    0x00, 0x39                  /* - terminal marker 57 - */,
+/* pos 0398: 539 */    0xE5 /* 'e' -> */,
+/* pos 0399: 540 */    0xF2 /* 'r' -> */,
+/* pos 039a: 541 */    0xAD /* '-' -> */,
+/* pos 039b: 542 */    0xE1 /* 'a' -> */,
+/* pos 039c: 543 */    0xE7 /* 'g' -> */,
+/* pos 039d: 544 */    0xE5 /* 'e' -> */,
+/* pos 039e: 545 */    0xEE /* 'n' -> */,
+/* pos 039f: 546 */    0xF4 /* 't' -> */,
+/* pos 03a0: 547 */    0xBA /* ':' -> */,
+/* pos 03a1: 548 */    0x00, 0x3B                  /* - terminal marker 59 - */,
+/* pos 03a3: 549 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x03AA state 550) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x03AF state 554) */,
+                       0x08, /* fail */
+/* pos 03aa: 550 */    0xF2 /* 'r' -> */,
+/* pos 03ab: 551 */    0xF9 /* 'y' -> */,
+/* pos 03ac: 552 */    0xBA /* ':' -> */,
+/* pos 03ad: 553 */    0x00, 0x3C                  /* - terminal marker 60 - */,
+/* pos 03af: 554 */    0xE1 /* 'a' -> */,
+/* pos 03b0: 555 */    0xBA /* ':' -> */,
+/* pos 03b1: 556 */    0x00, 0x3D                  /* - terminal marker 61 - */,
+/* pos 03b3: 557 */    0xF7 /* 'w' -> */,
+/* pos 03b4: 558 */    0xF7 /* 'w' -> */,
+/* pos 03b5: 559 */    0xAD /* '-' -> */,
+/* pos 03b6: 560 */    0xE1 /* 'a' -> */,
+/* pos 03b7: 561 */    0xF5 /* 'u' -> */,
+/* pos 03b8: 562 */    0xF4 /* 't' -> */,
+/* pos 03b9: 563 */    0xE8 /* 'h' -> */,
+/* pos 03ba: 564 */    0xE5 /* 'e' -> */,
+/* pos 03bb: 565 */    0xEE /* 'n' -> */,
+/* pos 03bc: 566 */    0xF4 /* 't' -> */,
+/* pos 03bd: 567 */    0xE9 /* 'i' -> */,
+/* pos 03be: 568 */    0xE3 /* 'c' -> */,
+/* pos 03bf: 569 */    0xE1 /* 'a' -> */,
+/* pos 03c0: 570 */    0xF4 /* 't' -> */,
+/* pos 03c1: 571 */    0xE5 /* 'e' -> */,
+/* pos 03c2: 572 */    0xBA /* ':' -> */,
+/* pos 03c3: 573 */    0x00, 0x3E                  /* - terminal marker 62 - */,
+/* pos 03c5: 574 */    0xF4 /* 't' -> */,
+/* pos 03c6: 575 */    0xE3 /* 'c' -> */,
+/* pos 03c7: 576 */    0xE8 /* 'h' -> */,
+/* pos 03c8: 577 */    0x00, 0x3F                  /* - terminal marker 63 - */,
+/* pos 03ca: 578 */    0xF4 /* 't' -> */,
+/* pos 03cb: 579 */    0x00, 0x40                  /* - terminal marker 64 - */,
+/* pos 03cd: 580 */    0xEC /* 'l' -> */,
+/* pos 03ce: 581 */    0xE5 /* 'e' -> */,
+/* pos 03cf: 582 */    0xF4 /* 't' -> */,
+/* pos 03d0: 583 */    0xE5 /* 'e' -> */,
+/* pos 03d1: 584 */    0x00, 0x41                  /* - terminal marker 65 - */,
+/* pos 03d3: 585 */    0x00, 0x43                  /* - terminal marker 67 - */,
+/* pos 03d5: 586 */    0xE5 /* 'e' -> */,
+/* pos 03d6: 587 */    0xE1 /* 'a' -> */,
+/* pos 03d7: 588 */    0xEC /* 'l' -> */,
+/* pos 03d8: 589 */    0xAD /* '-' -> */,
+/* pos 03d9: 590 */    0xE9 /* 'i' -> */,
+/* pos 03da: 591 */    0xF0 /* 'p' -> */,
+/* pos 03db: 592 */    0xBA /* ':' -> */,
+/* pos 03dc: 593 */    0x00, 0x44                  /* - terminal marker 68 - */,
+/* pos 03de: 594 */    0xBA /* ':' -> */,
+/* pos 03df: 595 */    0x00, 0x49                  /* - terminal marker 73 - */,
+/* pos 03e1: 596 */    0xEC /* 'l' -> */,
+/* pos 03e2: 597 */    0xE1 /* 'a' -> */,
+/* pos 03e3: 598 */    0xF9 /* 'y' -> */,
+/* pos 03e4: 599 */    0xAD /* '-' -> */,
+/* pos 03e5: 600 */    0xEE /* 'n' -> */,
+/* pos 03e6: 601 */    0xEF /* 'o' -> */,
+/* pos 03e7: 602 */    0xEE /* 'n' -> */,
+/* pos 03e8: 603 */    0xE3 /* 'c' -> */,
+/* pos 03e9: 604 */    0xE5 /* 'e' -> */,
+/* pos 03ea: 605 */    0xBA /* ':' -> */,
+/* pos 03eb: 606 */    0x00, 0x4A                  /* - terminal marker 74 - */,
+/* pos 03ed: 607 */    0xAD /* '-' -> */,
+/* pos 03ee: 608 */    0xF7 /* 'w' -> */,
+/* pos 03ef: 609 */    0xE5 /* 'e' -> */,
+/* pos 03f0: 610 */    0xE2 /* 'b' -> */,
+/* pos 03f1: 611 */    0xF3 /* 's' -> */,
+/* pos 03f2: 612 */    0xEF /* 'o' -> */,
+/* pos 03f3: 613 */    0xE3 /* 'c' -> */,
+/* pos 03f4: 614 */    0xEB /* 'k' -> */,
+/* pos 03f5: 615 */    0xE5 /* 'e' -> */,
+/* pos 03f6: 616 */    0xF4 /* 't' -> */,
+/* pos 03f7: 617 */    0xAD /* '-' -> */,
+/* pos 03f8: 618 */    0x64 /* 'd' */, 0x19, 0x00  /* (to 0x0411 state 619) */,
+                       0x65 /* 'e' */, 0x1D, 0x00  /* (to 0x0418 state 625) */,
+                       0x6B /* 'k' */, 0x26, 0x00  /* (to 0x0424 state 636) */,
+                       0x70 /* 'p' */, 0x35, 0x00  /* (to 0x0436 state 643) */,
+                       0x61 /* 'a' */, 0x3C, 0x00  /* (to 0x0440 state 652) */,
+                       0x6E /* 'n' */, 0x41, 0x00  /* (to 0x0448 state 659) */,
+                       0x76 /* 'v' */, 0x47, 0x00  /* (to 0x0451 state 666) */,
+                       0x6F /* 'o' */, 0x4D, 0x00  /* (to 0x045A state 674) */,
+                       0x08, /* fail */
+/* pos 0411: 619 */    0xF2 /* 'r' -> */,
+/* pos 0412: 620 */    0xE1 /* 'a' -> */,
+/* pos 0413: 621 */    0xE6 /* 'f' -> */,
+/* pos 0414: 622 */    0xF4 /* 't' -> */,
+/* pos 0415: 623 */    0xBA /* ':' -> */,
+/* pos 0416: 624 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 0418: 625 */    0xF8 /* 'x' -> */,
+/* pos 0419: 626 */    0xF4 /* 't' -> */,
+/* pos 041a: 627 */    0xE5 /* 'e' -> */,
+/* pos 041b: 628 */    0xEE /* 'n' -> */,
+/* pos 041c: 629 */    0xF3 /* 's' -> */,
+/* pos 041d: 630 */    0xE9 /* 'i' -> */,
+/* pos 041e: 631 */    0xEF /* 'o' -> */,
+/* pos 041f: 632 */    0xEE /* 'n' -> */,
+/* pos 0420: 633 */    0xF3 /* 's' -> */,
+/* pos 0421: 634 */    0xBA /* ':' -> */,
+/* pos 0422: 635 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 0424: 636 */    0xE5 /* 'e' -> */,
+/* pos 0425: 637 */    0xF9 /* 'y' -> */,
+/* pos 0426: 638 */    0x31 /* '1' */, 0x0A, 0x00  /* (to 0x0430 state 639) */,
+                       0x32 /* '2' */, 0x0A, 0x00  /* (to 0x0433 state 641) */,
+                       0x3A /* ':' */, 0x23, 0x00  /* (to 0x044F state 665) */,
+                       0x08, /* fail */
+/* pos 0430: 639 */    0xBA /* ':' -> */,
+/* pos 0431: 640 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 0433: 641 */    0xBA /* ':' -> */,
+/* pos 0434: 642 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 0436: 643 */    0xF2 /* 'r' -> */,
+/* pos 0437: 644 */    0xEF /* 'o' -> */,
+/* pos 0438: 645 */    0xF4 /* 't' -> */,
+/* pos 0439: 646 */    0xEF /* 'o' -> */,
+/* pos 043a: 647 */    0xE3 /* 'c' -> */,
+/* pos 043b: 648 */    0xEF /* 'o' -> */,
+/* pos 043c: 649 */    0xEC /* 'l' -> */,
+/* pos 043d: 650 */    0xBA /* ':' -> */,
+/* pos 043e: 651 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 0440: 652 */    0xE3 /* 'c' -> */,
+/* pos 0441: 653 */    0xE3 /* 'c' -> */,
+/* pos 0442: 654 */    0xE5 /* 'e' -> */,
+/* pos 0443: 655 */    0xF0 /* 'p' -> */,
+/* pos 0444: 656 */    0xF4 /* 't' -> */,
+/* pos 0445: 657 */    0xBA /* ':' -> */,
+/* pos 0446: 658 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 0448: 659 */    0xEF /* 'o' -> */,
+/* pos 0449: 660 */    0xEE /* 'n' -> */,
+/* pos 044a: 661 */    0xE3 /* 'c' -> */,
+/* pos 044b: 662 */    0xE5 /* 'e' -> */,
+/* pos 044c: 663 */    0xBA /* ':' -> */,
+/* pos 044d: 664 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 044f: 665 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 0451: 666 */    0xE5 /* 'e' -> */,
+/* pos 0452: 667 */    0xF2 /* 'r' -> */,
+/* pos 0453: 668 */    0xF3 /* 's' -> */,
+/* pos 0454: 669 */    0xE9 /* 'i' -> */,
+/* pos 0455: 670 */    0xEF /* 'o' -> */,
+/* pos 0456: 671 */    0xEE /* 'n' -> */,
+/* pos 0457: 672 */    0xBA /* ':' -> */,
+/* pos 0458: 673 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 045a: 674 */    0xF2 /* 'r' -> */,
+/* pos 045b: 675 */    0xE9 /* 'i' -> */,
+/* pos 045c: 676 */    0xE7 /* 'g' -> */,
+/* pos 045d: 677 */    0xE9 /* 'i' -> */,
+/* pos 045e: 678 */    0xEE /* 'n' -> */,
+/* pos 045f: 679 */    0xBA /* ':' -> */,
+/* pos 0460: 680 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* pos 0462: 681 */    0xAD /* '-' -> */,
+/* pos 0463: 682 */    0xF3 /* 's' -> */,
+/* pos 0464: 683 */    0xE5 /* 'e' -> */,
+/* pos 0465: 684 */    0xF4 /* 't' -> */,
+/* pos 0466: 685 */    0xF4 /* 't' -> */,
+/* pos 0467: 686 */    0xE9 /* 'i' -> */,
+/* pos 0468: 687 */    0xEE /* 'n' -> */,
+/* pos 0469: 688 */    0xE7 /* 'g' -> */,
+/* pos 046a: 689 */    0xF3 /* 's' -> */,
+/* pos 046b: 690 */    0xBA /* ':' -> */,
+/* pos 046c: 691 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 046e: 692 */    0x61 /* 'a' */, 0x0D, 0x00  /* (to 0x047B state 693) */,
+                       0x6D /* 'm' */, 0x14, 0x00  /* (to 0x0485 state 702) */,
+                       0x70 /* 'p' */, 0x18, 0x00  /* (to 0x048C state 708) */,
+                       0x73 /* 's' */, 0x20, 0x00  /* (to 0x0497 state 712) */,
+                       0x08, /* fail */
+/* pos 047b: 693 */    0xF5 /* 'u' -> */,
+/* pos 047c: 694 */    0xF4 /* 't' -> */,
+/* pos 047d: 695 */    0xE8 /* 'h' -> */,
+/* pos 047e: 696 */    0xEF /* 'o' -> */,
+/* pos 047f: 697 */    0xF2 /* 'r' -> */,
+/* pos 0480: 698 */    0xE9 /* 'i' -> */,
+/* pos 0481: 699 */    0xF4 /* 't' -> */,
+/* pos 0482: 700 */    0xF9 /* 'y' -> */,
+/* pos 0483: 701 */    0x00, 0x19                  /* - terminal marker 25 - */,
+/* pos 0485: 702 */    0xE5 /* 'e' -> */,
+/* pos 0486: 703 */    0xF4 /* 't' -> */,
+/* pos 0487: 704 */    0xE8 /* 'h' -> */,
+/* pos 0488: 705 */    0xEF /* 'o' -> */,
+/* pos 0489: 706 */    0xE4 /* 'd' -> */,
+/* pos 048a: 707 */    0x00, 0x1A                  /* - terminal marker 26 - */,
+/* pos 048c: 708 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0493 state 709) */,
+                       0x72 /* 'r' */, 0x1B, 0x00  /* (to 0x04AA state 723) */,
+                       0x08, /* fail */
+/* pos 0493: 709 */    0xF4 /* 't' -> */,
+/* pos 0494: 710 */    0xE8 /* 'h' -> */,
+/* pos 0495: 711 */    0x00, 0x1B                  /* - terminal marker 27 - */,
+/* pos 0497: 712 */    0x63 /* 'c' */, 0x07, 0x00  /* (to 0x049E state 713) */,
+                       0x74 /* 't' */, 0x0A, 0x00  /* (to 0x04A4 state 718) */,
+                       0x08, /* fail */
+/* pos 049e: 713 */    0xE8 /* 'h' -> */,
+/* pos 049f: 714 */    0xE5 /* 'e' -> */,
+/* pos 04a0: 715 */    0xED /* 'm' -> */,
+/* pos 04a1: 716 */    0xE5 /* 'e' -> */,
+/* pos 04a2: 717 */    0x00, 0x1C                  /* - terminal marker 28 - */,
+/* pos 04a4: 718 */    0xE1 /* 'a' -> */,
+/* pos 04a5: 719 */    0xF4 /* 't' -> */,
+/* pos 04a6: 720 */    0xF5 /* 'u' -> */,
+/* pos 04a7: 721 */    0xF3 /* 's' -> */,
+/* pos 04a8: 722 */    0x00, 0x1D                  /* - terminal marker 29 - */,
+/* pos 04aa: 723 */    0xEF /* 'o' -> */,
+/* pos 04ab: 724 */    0xF4 /* 't' -> */,
+/* pos 04ac: 725 */    0xEF /* 'o' -> */,
+/* pos 04ad: 726 */    0xE3 /* 'c' -> */,
+/* pos 04ae: 727 */    0xEF /* 'o' -> */,
+/* pos 04af: 728 */    0xEC /* 'l' -> */,
+/* pos 04b0: 729 */    0x00, 0x4B                  /* - terminal marker 75 - */,
+/* total size 1202 bytes */
+#endif
+
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
+       /* 0: 0: get  */
+       /* 1: 1: post  */
+       /* 2: 3: host: */
+       /* 3: 4: connection: */
+       /* 4: 5: upgrade: */
+       /* 5: 6: origin: */
+       /* 6: 7: sec-websocket-draft: */
+       /* 7: 8: \r
+ */
+       /* 8: 9: sec-websocket-extensions: */
+       /* 9: 10: sec-websocket-key1: */
+       /* 10: 11: sec-websocket-key2: */
+       /* 11: 12: sec-websocket-protocol: */
+       /* 12: 13: sec-websocket-accept: */
+       /* 13: 14: sec-websocket-nonce: */
+       /* 14: 15: http/1.1  */
+       /* 15: 16: http2-settings: */
+       /* 16: 17: accept: */
+       /* 17: 19: if-modified-since: */
+       /* 18: 20: if-none-match: */
+       /* 19: 21: accept-encoding: */
+       /* 20: 22: accept-language: */
+       /* 21: 23: pragma: */
+       /* 22: 24: cache-control: */
+       /* 23: 25: authorization: */
+       /* 24: 26: cookie: */
+       /* 25: 27: content-length: */
+       /* 26: 28: content-type: */
+       /* 27: 29: date: */
+       /* 28: 30: range: */
+       /* 29: 31: referer: */
+       /* 30: 32: sec-websocket-key: */
+       /* 31: 33: sec-websocket-version: */
+       /* 32: 34: sec-websocket-origin: */
+       /* 33: 35: :authority */
+       /* 34: 36: :method */
+       /* 35: 37: :path */
+       /* 36: 38: :scheme */
+       /* 37: 39: :status */
+       /* 38: 40: accept-charset: */
+       /* 39: 41: accept-ranges: */
+       /* 40: 42: access-control-allow-origin: */
+       /* 41: 43: age: */
+       /* 42: 44: allow: */
+       /* 43: 45: content-disposition: */
+       /* 44: 46: content-encoding: */
+       /* 45: 47: content-language: */
+       /* 46: 48: content-location: */
+       /* 47: 49: content-range: */
+       /* 48: 50: etag: */
+       /* 49: 51: expect: */
+       /* 50: 52: expires: */
+       /* 51: 53: from: */
+       /* 52: 54: if-match: */
+       /* 53: 55: if-range: */
+       /* 54: 56: if-unmodified-since: */
+       /* 55: 57: last-modified: */
+       /* 56: 58: link: */
+       /* 57: 59: location: */
+       /* 58: 60: max-forwards: */
+       /* 59: 61: proxy-authenticate: */
+       /* 60: 62: proxy-authorization: */
+       /* 61: 63: refresh: */
+       /* 62: 64: retry-after: */
+       /* 63: 65: server: */
+       /* 64: 66: set-cookie: */
+       /* 65: 67: strict-transport-security: */
+       /* 66: 68: transfer-encoding: */
+       /* 67: 69: user-agent: */
+       /* 68: 70: vary: */
+       /* 69: 71: via: */
+       /* 70: 72: www-authenticate: */
+       /* 71: 76: uri-args */
+       /* 72: 79: http/1.0  */
+       /* 73: 80: x-forwarded-for: */
+       /* 74: 81: connect  */
+       /* 75: 82: head  */
+       /* 76: 83: te: */
+       /* 77: 84: replay-nonce: */
+       /* 78: 85: :protocol */
+       /* 79: 86: x-auth-token: */
+       /* 80: 87: x-amzn-dss-signature: */
+/* pos 0000:   0 */    0x67 /* 'g' */, 0x40, 0x00  /* (to 0x0040 state   1) */,
+                       0x70 /* 'p' */, 0x42, 0x00  /* (to 0x0045 state   5) */,
+                       0x68 /* 'h' */, 0x51, 0x00  /* (to 0x0057 state  10) */,
+                       0x63 /* 'c' */, 0x5D, 0x00  /* (to 0x0066 state  15) */,
+                       0x75 /* 'u' */, 0x7E, 0x00  /* (to 0x008A state  26) */,
+                       0x6F /* 'o' */, 0x8D, 0x00  /* (to 0x009C state  34) */,
+                       0x0D /* '.' */, 0x98, 0x00  /* (to 0x00AA state  41) */,
+                       0x61 /* 'a' */, 0xAD, 0x00  /* (to 0x00C2 state  51) */,
+                       0x69 /* 'i' */, 0xCA, 0x00  /* (to 0x00E2 state  58) */,
+                       0x64 /* 'd' */, 0x73, 0x01  /* (to 0x018E state 160) */,
+                       0x72 /* 'r' */, 0x7C, 0x01  /* (to 0x019A state 165) */,
+                       0x65 /* 'e' */, 0xC8, 0x01  /* (to 0x01E9 state 229) */,
+                       0x66 /* 'f' */, 0xE4, 0x01  /* (to 0x0208 state 245) */,
+                       0x6C /* 'l' */, 0x06, 0x02  /* (to 0x022D state 278) */,
+                       0x73 /* 's' */, 0x4B, 0x02  /* (to 0x0275 state 321) */,
+                       0x74 /* 't' */, 0x69, 0x02  /* (to 0x0296 state 337) */,
+                       0x78 /* 'x' */, 0x8A, 0x02  /* (to 0x02BA state 364) */,
+                       0x6D /* 'm' */, 0x14, 0x03  /* (to 0x0347 state 474) */,
+                       0x76 /* 'v' */, 0x6D, 0x03  /* (to 0x03A3 state 549) */,
+                       0x77 /* 'w' */, 0x7A, 0x03  /* (to 0x03B3 state 557) */,
+                       0x3A /* ':' */, 0x32, 0x04  /* (to 0x046E state 692) */,
+                       0x08, /* fail */
+/* pos 0040:   1 */    0xE5 /* 'e' -> */,
+/* pos 0041:   2 */    0xF4 /* 't' -> */,
+/* pos 0042:   3 */    0xA0 /* ' ' -> */,
+/* pos 0043:   4 */    0x00, 0x00                  /* - terminal marker  0 - */,
+/* pos 0045:   5 */    0x6F /* 'o' */, 0x0D, 0x00  /* (to 0x0052 state   6) */,
+                       0x72 /* 'r' */, 0xEC, 0x00  /* (to 0x0134 state 106) */,
+                       0x61 /* 'a' */, 0x7A, 0x03  /* (to 0x03C5 state 574) */,
+                       0x75 /* 'u' */, 0x7C, 0x03  /* (to 0x03CA state 578) */,
+                       0x08, /* fail */
+/* pos 0052:   6 */    0xF3 /* 's' -> */,
+/* pos 0053:   7 */    0xF4 /* 't' -> */,
+/* pos 0054:   8 */    0xA0 /* ' ' -> */,
+/* pos 0055:   9 */    0x00, 0x01                  /* - terminal marker  1 - */,
+/* pos 0057:  10 */    0x6F /* 'o' */, 0x0A, 0x00  /* (to 0x0061 state  11) */,
+                       0x74 /* 't' */, 0x53, 0x00  /* (to 0x00AD state  43) */,
+                       0x65 /* 'e' */, 0x79, 0x02  /* (to 0x02D6 state 381) */,
+                       0x08, /* fail */
+/* pos 0061:  11 */    0xF3 /* 's' -> */,
+/* pos 0062:  12 */    0xF4 /* 't' -> */,
+/* pos 0063:  13 */    0xBA /* ':' -> */,
+/* pos 0064:  14 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 0066:  15 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x006D state  16) */,
+                       0x61 /* 'a' */, 0xD8, 0x00  /* (to 0x0141 state 112) */,
+                       0x08, /* fail */
+/* pos 006d:  16 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0074 state  17) */,
+                       0x6F /* 'o' */, 0xED, 0x00  /* (to 0x015D state 138) */,
+                       0x08, /* fail */
+/* pos 0074:  17 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x007B state  18) */,
+                       0x74 /* 't' */, 0xEC, 0x00  /* (to 0x0163 state 143) */,
+                       0x08, /* fail */
+/* pos 007b:  18 */    0xE5 /* 'e' -> */,
+/* pos 007c:  19 */    0xE3 /* 'c' -> */,
+/* pos 007d:  20 */    0xF4 /* 't' -> */,
+/* pos 007e:  21 */    0x69 /* 'i' */, 0x07, 0x00  /* (to 0x0085 state  22) */,
+                       0x20 /* ' ' */, 0x53, 0x02  /* (to 0x02D4 state 380) */,
+                       0x08, /* fail */
+/* pos 0085:  22 */    0xEF /* 'o' -> */,
+/* pos 0086:  23 */    0xEE /* 'n' -> */,
+/* pos 0087:  24 */    0xBA /* ':' -> */,
+/* pos 0088:  25 */    0x00, 0x03                  /* - terminal marker  3 - */,
+/* pos 008a:  26 */    0x70 /* 'p' */, 0x0A, 0x00  /* (to 0x0094 state  27) */,
+                       0x72 /* 'r' */, 0x22, 0x02  /* (to 0x02AF state 355) */,
+                       0x73 /* 's' */, 0x08, 0x03  /* (to 0x0398 state 539) */,
+                       0x08, /* fail */
+/* pos 0094:  27 */    0xE7 /* 'g' -> */,
+/* pos 0095:  28 */    0xF2 /* 'r' -> */,
+/* pos 0096:  29 */    0xE1 /* 'a' -> */,
+/* pos 0097:  30 */    0xE4 /* 'd' -> */,
+/* pos 0098:  31 */    0xE5 /* 'e' -> */,
+/* pos 0099:  32 */    0xBA /* ':' -> */,
+/* pos 009a:  33 */    0x00, 0x04                  /* - terminal marker  4 - */,
+/* pos 009c:  34 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x00A3 state  35) */,
+                       0x70 /* 'p' */, 0x61, 0x02  /* (to 0x0300 state 414) */,
+                       0x08, /* fail */
+/* pos 00a3:  35 */    0xE9 /* 'i' -> */,
+/* pos 00a4:  36 */    0xE7 /* 'g' -> */,
+/* pos 00a5:  37 */    0xE9 /* 'i' -> */,
+/* pos 00a6:  38 */    0xEE /* 'n' -> */,
+/* pos 00a7:  39 */    0xBA /* ':' -> */,
+/* pos 00a8:  40 */    0x00, 0x05                  /* - terminal marker  5 - */,
+/* pos 00aa:  41 */    0x8A /* '.' -> */,
+/* pos 00ab:  42 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 00ad:  43 */    0xF4 /* 't' -> */,
+/* pos 00ae:  44 */    0xF0 /* 'p' -> */,
+/* pos 00af:  45 */    0x2F /* '/' */, 0x07, 0x00  /* (to 0x00B6 state  46) */,
+                       0x32 /* '2' */, 0xB0, 0x03  /* (to 0x0462 state 681) */,
+                       0x08, /* fail */
+/* pos 00b6:  46 */    0xB1 /* '1' -> */,
+/* pos 00b7:  47 */    0xAE /* '.' -> */,
+/* pos 00b8:  48 */    0x31 /* '1' */, 0x07, 0x00  /* (to 0x00BF state  49) */,
+                       0x30 /* '0' */, 0xFC, 0x01  /* (to 0x02B7 state 362) */,
+                       0x08, /* fail */
+/* pos 00bf:  49 */    0xA0 /* ' ' -> */,
+/* pos 00c0:  50 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 00c2:  51 */    0x63 /* 'c' */, 0x0D, 0x00  /* (to 0x00CF state  52) */,
+                       0x75 /* 'u' */, 0x8A, 0x00  /* (to 0x014F state 125) */,
+                       0x67 /* 'g' */, 0xE7, 0x00  /* (to 0x01AF state 178) */,
+                       0x6C /* 'l' */, 0xE8, 0x00  /* (to 0x01B3 state 181) */,
+                       0x08, /* fail */
+/* pos 00cf:  52 */    0xE3 /* 'c' -> */,
+/* pos 00d0:  53 */    0xE5 /* 'e' -> */,
+/* pos 00d1:  54 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x00D8 state  55) */,
+                       0x73 /* 's' */, 0x34, 0x02  /* (to 0x0308 state 421) */,
+                       0x08, /* fail */
+/* pos 00d8:  55 */    0xF4 /* 't' -> */,
+/* pos 00d9:  56 */    0x3A /* ':' */, 0x07, 0x00  /* (to 0x00E0 state  57) */,
+                       0x2D /* '-' */, 0x37, 0x00  /* (to 0x0113 state  87) */,
+                       0x08, /* fail */
+/* pos 00e0:  57 */    0x00, 0x10                  /* - terminal marker 16 - */,
+/* pos 00e2:  58 */    0xE6 /* 'f' -> */,
+/* pos 00e3:  59 */    0xAD /* '-' -> */,
+/* pos 00e4:  60 */    0x6D /* 'm' */, 0x0D, 0x00  /* (to 0x00F1 state  61) */,
+                       0x6E /* 'n' */, 0x20, 0x00  /* (to 0x0107 state  76) */,
+                       0x72 /* 'r' */, 0x2A, 0x01  /* (to 0x0214 state 255) */,
+                       0x75 /* 'u' */, 0x2E, 0x01  /* (to 0x021B state 261) */,
+                       0x08, /* fail */
+/* pos 00f1:  61 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x00F8 state  62) */,
+                       0x61 /* 'a' */, 0x1A, 0x01  /* (to 0x020E state 250) */,
+                       0x08, /* fail */
+/* pos 00f8:  62 */    0xE4 /* 'd' -> */,
+/* pos 00f9:  63 */    0xE9 /* 'i' -> */,
+/* pos 00fa:  64 */    0xE6 /* 'f' -> */,
+/* pos 00fb:  65 */    0xE9 /* 'i' -> */,
+/* pos 00fc:  66 */    0xE5 /* 'e' -> */,
+/* pos 00fd:  67 */    0xE4 /* 'd' -> */,
+/* pos 00fe:  68 */    0xAD /* '-' -> */,
+/* pos 00ff:  69 */    0xF3 /* 's' -> */,
+/* pos 0100:  70 */    0xE9 /* 'i' -> */,
+/* pos 0101:  71 */    0xEE /* 'n' -> */,
+/* pos 0102:  72 */    0xE3 /* 'c' -> */,
+/* pos 0103:  73 */    0xE5 /* 'e' -> */,
+/* pos 0104:  74 */    0xBA /* ':' -> */,
+/* pos 0105:  75 */    0x00, 0x11                  /* - terminal marker 17 - */,
+/* pos 0107:  76 */    0xEF /* 'o' -> */,
+/* pos 0108:  77 */    0xEE /* 'n' -> */,
+/* pos 0109:  78 */    0xE5 /* 'e' -> */,
+/* pos 010a:  79 */    0xAD /* '-' -> */,
+/* pos 010b:  80 */    0xED /* 'm' -> */,
+/* pos 010c:  81 */    0xE1 /* 'a' -> */,
+/* pos 010d:  82 */    0xF4 /* 't' -> */,
+/* pos 010e:  83 */    0xE3 /* 'c' -> */,
+/* pos 010f:  84 */    0xE8 /* 'h' -> */,
+/* pos 0110:  85 */    0xBA /* ':' -> */,
+/* pos 0111:  86 */    0x00, 0x12                  /* - terminal marker 18 - */,
+/* pos 0113:  87 */    0x65 /* 'e' */, 0x0D, 0x00  /* (to 0x0120 state  88) */,
+                       0x6C /* 'l' */, 0x14, 0x00  /* (to 0x012A state  97) */,
+                       0x72 /* 'r' */, 0x8E, 0x00  /* (to 0x01A7 state 171) */,
+                       0x63 /* 'c' */, 0x14, 0x02  /* (to 0x0330 state 453) */,
+                       0x08, /* fail */
+/* pos 0120:  88 */    0xEE /* 'n' -> */,
+/* pos 0121:  89 */    0xE3 /* 'c' -> */,
+/* pos 0122:  90 */    0xEF /* 'o' -> */,
+/* pos 0123:  91 */    0xE4 /* 'd' -> */,
+/* pos 0124:  92 */    0xE9 /* 'i' -> */,
+/* pos 0125:  93 */    0xEE /* 'n' -> */,
+/* pos 0126:  94 */    0xE7 /* 'g' -> */,
+/* pos 0127:  95 */    0xBA /* ':' -> */,
+/* pos 0128:  96 */    0x00, 0x13                  /* - terminal marker 19 - */,
+/* pos 012a:  97 */    0xE1 /* 'a' -> */,
+/* pos 012b:  98 */    0xEE /* 'n' -> */,
+/* pos 012c:  99 */    0xE7 /* 'g' -> */,
+/* pos 012d: 100 */    0xF5 /* 'u' -> */,
+/* pos 012e: 101 */    0xE1 /* 'a' -> */,
+/* pos 012f: 102 */    0xE7 /* 'g' -> */,
+/* pos 0130: 103 */    0xE5 /* 'e' -> */,
+/* pos 0131: 104 */    0xBA /* ':' -> */,
+/* pos 0132: 105 */    0x00, 0x14                  /* - terminal marker 20 - */,
+/* pos 0134: 106 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x013B state 107) */,
+                       0x6F /* 'o' */, 0x1E, 0x02  /* (to 0x0355 state 487) */,
+                       0x08, /* fail */
+/* pos 013b: 107 */    0xE7 /* 'g' -> */,
+/* pos 013c: 108 */    0xED /* 'm' -> */,
+/* pos 013d: 109 */    0xE1 /* 'a' -> */,
+/* pos 013e: 110 */    0xBA /* ':' -> */,
+/* pos 013f: 111 */    0x00, 0x15                  /* - terminal marker 21 - */,
+/* pos 0141: 112 */    0xE3 /* 'c' -> */,
+/* pos 0142: 113 */    0xE8 /* 'h' -> */,
+/* pos 0143: 114 */    0xE5 /* 'e' -> */,
+/* pos 0144: 115 */    0xAD /* '-' -> */,
+/* pos 0145: 116 */    0xE3 /* 'c' -> */,
+/* pos 0146: 117 */    0xEF /* 'o' -> */,
+/* pos 0147: 118 */    0xEE /* 'n' -> */,
+/* pos 0148: 119 */    0xF4 /* 't' -> */,
+/* pos 0149: 120 */    0xF2 /* 'r' -> */,
+/* pos 014a: 121 */    0xEF /* 'o' -> */,
+/* pos 014b: 122 */    0xEC /* 'l' -> */,
+/* pos 014c: 123 */    0xBA /* ':' -> */,
+/* pos 014d: 124 */    0x00, 0x16                  /* - terminal marker 22 - */,
+/* pos 014f: 125 */    0xF4 /* 't' -> */,
+/* pos 0150: 126 */    0xE8 /* 'h' -> */,
+/* pos 0151: 127 */    0xEF /* 'o' -> */,
+/* pos 0152: 128 */    0xF2 /* 'r' -> */,
+/* pos 0153: 129 */    0xE9 /* 'i' -> */,
+/* pos 0154: 130 */    0xFA /* 'z' -> */,
+/* pos 0155: 131 */    0xE1 /* 'a' -> */,
+/* pos 0156: 132 */    0xF4 /* 't' -> */,
+/* pos 0157: 133 */    0xE9 /* 'i' -> */,
+/* pos 0158: 134 */    0xEF /* 'o' -> */,
+/* pos 0159: 135 */    0xEE /* 'n' -> */,
+/* pos 015a: 136 */    0xBA /* ':' -> */,
+/* pos 015b: 137 */    0x00, 0x17                  /* - terminal marker 23 - */,
+/* pos 015d: 138 */    0xEB /* 'k' -> */,
+/* pos 015e: 139 */    0xE9 /* 'i' -> */,
+/* pos 015f: 140 */    0xE5 /* 'e' -> */,
+/* pos 0160: 141 */    0xBA /* ':' -> */,
+/* pos 0161: 142 */    0x00, 0x18                  /* - terminal marker 24 - */,
+/* pos 0163: 143 */    0xE5 /* 'e' -> */,
+/* pos 0164: 144 */    0xEE /* 'n' -> */,
+/* pos 0165: 145 */    0xF4 /* 't' -> */,
+/* pos 0166: 146 */    0xAD /* '-' -> */,
+/* pos 0167: 147 */    0x6C /* 'l' */, 0x10, 0x00  /* (to 0x0177 state 148) */,
+                       0x74 /* 't' */, 0x1E, 0x00  /* (to 0x0188 state 155) */,
+                       0x64 /* 'd' */, 0x4C, 0x00  /* (to 0x01B9 state 186) */,
+                       0x65 /* 'e' */, 0x56, 0x00  /* (to 0x01C6 state 198) */,
+                       0x72 /* 'r' */, 0x6F, 0x00  /* (to 0x01E2 state 223) */,
+                       0x08, /* fail */
+/* pos 0177: 148 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x0181 state 149) */,
+                       0x61 /* 'a' */, 0x56, 0x00  /* (to 0x01D0 state 207) */,
+                       0x6F /* 'o' */, 0x5C, 0x00  /* (to 0x01D9 state 215) */,
+                       0x08, /* fail */
+/* pos 0181: 149 */    0xEE /* 'n' -> */,
+/* pos 0182: 150 */    0xE7 /* 'g' -> */,
+/* pos 0183: 151 */    0xF4 /* 't' -> */,
+/* pos 0184: 152 */    0xE8 /* 'h' -> */,
+/* pos 0185: 153 */    0xBA /* ':' -> */,
+/* pos 0186: 154 */    0x00, 0x19                  /* - terminal marker 25 - */,
+/* pos 0188: 155 */    0xF9 /* 'y' -> */,
+/* pos 0189: 156 */    0xF0 /* 'p' -> */,
+/* pos 018a: 157 */    0xE5 /* 'e' -> */,
+/* pos 018b: 158 */    0xBA /* ':' -> */,
+/* pos 018c: 159 */    0x00, 0x1A                  /* - terminal marker 26 - */,
+/* pos 018e: 160 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0195 state 161) */,
+                       0x65 /* 'e' */, 0x3C, 0x02  /* (to 0x03CD state 580) */,
+                       0x08, /* fail */
+/* pos 0195: 161 */    0xF4 /* 't' -> */,
+/* pos 0196: 162 */    0xE5 /* 'e' -> */,
+/* pos 0197: 163 */    0xBA /* ':' -> */,
+/* pos 0198: 164 */    0x00, 0x1B                  /* - terminal marker 27 - */,
+/* pos 019a: 165 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x01A1 state 166) */,
+                       0x65 /* 'e' */, 0xB6, 0x00  /* (to 0x0253 state 304) */,
+                       0x08, /* fail */
+/* pos 01a1: 166 */    0xEE /* 'n' -> */,
+/* pos 01a2: 167 */    0xE7 /* 'g' -> */,
+/* pos 01a3: 168 */    0xE5 /* 'e' -> */,
+/* pos 01a4: 169 */    0xBA /* ':' -> */,
+/* pos 01a5: 170 */    0x00, 0x1C                  /* - terminal marker 28 - */,
+/* pos 01a7: 171 */    0xE1 /* 'a' -> */,
+/* pos 01a8: 172 */    0xEE /* 'n' -> */,
+/* pos 01a9: 173 */    0xE7 /* 'g' -> */,
+/* pos 01aa: 174 */    0xE5 /* 'e' -> */,
+/* pos 01ab: 175 */    0xF3 /* 's' -> */,
+/* pos 01ac: 176 */    0xBA /* ':' -> */,
+/* pos 01ad: 177 */    0x00, 0x27                  /* - terminal marker 39 - */,
+/* pos 01af: 178 */    0xE5 /* 'e' -> */,
+/* pos 01b0: 179 */    0xBA /* ':' -> */,
+/* pos 01b1: 180 */    0x00, 0x29                  /* - terminal marker 41 - */,
+/* pos 01b3: 181 */    0xEC /* 'l' -> */,
+/* pos 01b4: 182 */    0xEF /* 'o' -> */,
+/* pos 01b5: 183 */    0xF7 /* 'w' -> */,
+/* pos 01b6: 184 */    0xBA /* ':' -> */,
+/* pos 01b7: 185 */    0x00, 0x2A                  /* - terminal marker 42 - */,
+/* pos 01b9: 186 */    0xE9 /* 'i' -> */,
+/* pos 01ba: 187 */    0xF3 /* 's' -> */,
+/* pos 01bb: 188 */    0xF0 /* 'p' -> */,
+/* pos 01bc: 189 */    0xEF /* 'o' -> */,
+/* pos 01bd: 190 */    0xF3 /* 's' -> */,
+/* pos 01be: 191 */    0xE9 /* 'i' -> */,
+/* pos 01bf: 192 */    0xF4 /* 't' -> */,
+/* pos 01c0: 193 */    0xE9 /* 'i' -> */,
+/* pos 01c1: 194 */    0xEF /* 'o' -> */,
+/* pos 01c2: 195 */    0xEE /* 'n' -> */,
+/* pos 01c3: 196 */    0xBA /* ':' -> */,
+/* pos 01c4: 197 */    0x00, 0x2B                  /* - terminal marker 43 - */,
+/* pos 01c6: 198 */    0xEE /* 'n' -> */,
+/* pos 01c7: 199 */    0xE3 /* 'c' -> */,
+/* pos 01c8: 200 */    0xEF /* 'o' -> */,
+/* pos 01c9: 201 */    0xE4 /* 'd' -> */,
+/* pos 01ca: 202 */    0xE9 /* 'i' -> */,
+/* pos 01cb: 203 */    0xEE /* 'n' -> */,
+/* pos 01cc: 204 */    0xE7 /* 'g' -> */,
+/* pos 01cd: 205 */    0xBA /* ':' -> */,
+/* pos 01ce: 206 */    0x00, 0x2C                  /* - terminal marker 44 - */,
+/* pos 01d0: 207 */    0xEE /* 'n' -> */,
+/* pos 01d1: 208 */    0xE7 /* 'g' -> */,
+/* pos 01d2: 209 */    0xF5 /* 'u' -> */,
+/* pos 01d3: 210 */    0xE1 /* 'a' -> */,
+/* pos 01d4: 211 */    0xE7 /* 'g' -> */,
+/* pos 01d5: 212 */    0xE5 /* 'e' -> */,
+/* pos 01d6: 213 */    0xBA /* ':' -> */,
+/* pos 01d7: 214 */    0x00, 0x2D                  /* - terminal marker 45 - */,
+/* pos 01d9: 215 */    0xE3 /* 'c' -> */,
+/* pos 01da: 216 */    0xE1 /* 'a' -> */,
+/* pos 01db: 217 */    0xF4 /* 't' -> */,
+/* pos 01dc: 218 */    0xE9 /* 'i' -> */,
+/* pos 01dd: 219 */    0xEF /* 'o' -> */,
+/* pos 01de: 220 */    0xEE /* 'n' -> */,
+/* pos 01df: 221 */    0xBA /* ':' -> */,
+/* pos 01e0: 222 */    0x00, 0x2E                  /* - terminal marker 46 - */,
+/* pos 01e2: 223 */    0xE1 /* 'a' -> */,
+/* pos 01e3: 224 */    0xEE /* 'n' -> */,
+/* pos 01e4: 225 */    0xE7 /* 'g' -> */,
+/* pos 01e5: 226 */    0xE5 /* 'e' -> */,
+/* pos 01e6: 227 */    0xBA /* ':' -> */,
+/* pos 01e7: 228 */    0x00, 0x2F                  /* - terminal marker 47 - */,
+/* pos 01e9: 229 */    0x74 /* 't' */, 0x07, 0x00  /* (to 0x01F0 state 230) */,
+                       0x78 /* 'x' */, 0x09, 0x00  /* (to 0x01F5 state 234) */,
+                       0x08, /* fail */
+/* pos 01f0: 230 */    0xE1 /* 'a' -> */,
+/* pos 01f1: 231 */    0xE7 /* 'g' -> */,
+/* pos 01f2: 232 */    0xBA /* ':' -> */,
+/* pos 01f3: 233 */    0x00, 0x30                  /* - terminal marker 48 - */,
+/* pos 01f5: 234 */    0xF0 /* 'p' -> */,
+/* pos 01f6: 235 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x01FD state 236) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x0202 state 240) */,
+                       0x08, /* fail */
+/* pos 01fd: 236 */    0xE3 /* 'c' -> */,
+/* pos 01fe: 237 */    0xF4 /* 't' -> */,
+/* pos 01ff: 238 */    0xBA /* ':' -> */,
+/* pos 0200: 239 */    0x00, 0x31                  /* - terminal marker 49 - */,
+/* pos 0202: 240 */    0xF2 /* 'r' -> */,
+/* pos 0203: 241 */    0xE5 /* 'e' -> */,
+/* pos 0204: 242 */    0xF3 /* 's' -> */,
+/* pos 0205: 243 */    0xBA /* ':' -> */,
+/* pos 0206: 244 */    0x00, 0x32                  /* - terminal marker 50 - */,
+/* pos 0208: 245 */    0xF2 /* 'r' -> */,
+/* pos 0209: 246 */    0xEF /* 'o' -> */,
+/* pos 020a: 247 */    0xED /* 'm' -> */,
+/* pos 020b: 248 */    0xBA /* ':' -> */,
+/* pos 020c: 249 */    0x00, 0x33                  /* - terminal marker 51 - */,
+/* pos 020e: 250 */    0xF4 /* 't' -> */,
+/* pos 020f: 251 */    0xE3 /* 'c' -> */,
+/* pos 0210: 252 */    0xE8 /* 'h' -> */,
+/* pos 0211: 253 */    0xBA /* ':' -> */,
+/* pos 0212: 254 */    0x00, 0x34                  /* - terminal marker 52 - */,
+/* pos 0214: 255 */    0xE1 /* 'a' -> */,
+/* pos 0215: 256 */    0xEE /* 'n' -> */,
+/* pos 0216: 257 */    0xE7 /* 'g' -> */,
+/* pos 0217: 258 */    0xE5 /* 'e' -> */,
+/* pos 0218: 259 */    0xBA /* ':' -> */,
+/* pos 0219: 260 */    0x00, 0x35                  /* - terminal marker 53 - */,
+/* pos 021b: 261 */    0xEE /* 'n' -> */,
+/* pos 021c: 262 */    0xED /* 'm' -> */,
+/* pos 021d: 263 */    0xEF /* 'o' -> */,
+/* pos 021e: 264 */    0xE4 /* 'd' -> */,
+/* pos 021f: 265 */    0xE9 /* 'i' -> */,
+/* pos 0220: 266 */    0xE6 /* 'f' -> */,
+/* pos 0221: 267 */    0xE9 /* 'i' -> */,
+/* pos 0222: 268 */    0xE5 /* 'e' -> */,
+/* pos 0223: 269 */    0xE4 /* 'd' -> */,
+/* pos 0224: 270 */    0xAD /* '-' -> */,
+/* pos 0225: 271 */    0xF3 /* 's' -> */,
+/* pos 0226: 272 */    0xE9 /* 'i' -> */,
+/* pos 0227: 273 */    0xEE /* 'n' -> */,
+/* pos 0228: 274 */    0xE3 /* 'c' -> */,
+/* pos 0229: 275 */    0xE5 /* 'e' -> */,
+/* pos 022a: 276 */    0xBA /* ':' -> */,
+/* pos 022b: 277 */    0x00, 0x36                  /* - terminal marker 54 - */,
+/* pos 022d: 278 */    0x61 /* 'a' */, 0x0A, 0x00  /* (to 0x0237 state 279) */,
+                       0x69 /* 'i' */, 0x15, 0x00  /* (to 0x0245 state 292) */,
+                       0x6F /* 'o' */, 0x17, 0x00  /* (to 0x024A state 296) */,
+                       0x08, /* fail */
+/* pos 0237: 279 */    0xF3 /* 's' -> */,
+/* pos 0238: 280 */    0xF4 /* 't' -> */,
+/* pos 0239: 281 */    0xAD /* '-' -> */,
+/* pos 023a: 282 */    0xED /* 'm' -> */,
+/* pos 023b: 283 */    0xEF /* 'o' -> */,
+/* pos 023c: 284 */    0xE4 /* 'd' -> */,
+/* pos 023d: 285 */    0xE9 /* 'i' -> */,
+/* pos 023e: 286 */    0xE6 /* 'f' -> */,
+/* pos 023f: 287 */    0xE9 /* 'i' -> */,
+/* pos 0240: 288 */    0xE5 /* 'e' -> */,
+/* pos 0241: 289 */    0xE4 /* 'd' -> */,
+/* pos 0242: 290 */    0xBA /* ':' -> */,
+/* pos 0243: 291 */    0x00, 0x37                  /* - terminal marker 55 - */,
+/* pos 0245: 292 */    0xEE /* 'n' -> */,
+/* pos 0246: 293 */    0xEB /* 'k' -> */,
+/* pos 0247: 294 */    0xBA /* ':' -> */,
+/* pos 0248: 295 */    0x00, 0x38                  /* - terminal marker 56 - */,
+/* pos 024a: 296 */    0xE3 /* 'c' -> */,
+/* pos 024b: 297 */    0xE1 /* 'a' -> */,
+/* pos 024c: 298 */    0xF4 /* 't' -> */,
+/* pos 024d: 299 */    0xE9 /* 'i' -> */,
+/* pos 024e: 300 */    0xEF /* 'o' -> */,
+/* pos 024f: 301 */    0xEE /* 'n' -> */,
+/* pos 0250: 302 */    0xBA /* ':' -> */,
+/* pos 0251: 303 */    0x00, 0x39                  /* - terminal marker 57 - */,
+/* pos 0253: 304 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x025D state 305) */,
+                       0x74 /* 't' */, 0x14, 0x00  /* (to 0x026A state 311) */,
+                       0x70 /* 'p' */, 0x88, 0x01  /* (to 0x03E1 state 596) */,
+                       0x08, /* fail */
+/* pos 025d: 305 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0264 state 306) */,
+                       0x65 /* 'e' */, 0xCA, 0x00  /* (to 0x032A state 448) */,
+                       0x08, /* fail */
+/* pos 0264: 306 */    0xE5 /* 'e' -> */,
+/* pos 0265: 307 */    0xF3 /* 's' -> */,
+/* pos 0266: 308 */    0xE8 /* 'h' -> */,
+/* pos 0267: 309 */    0xBA /* ':' -> */,
+/* pos 0268: 310 */    0x00, 0x3D                  /* - terminal marker 61 - */,
+/* pos 026a: 311 */    0xF2 /* 'r' -> */,
+/* pos 026b: 312 */    0xF9 /* 'y' -> */,
+/* pos 026c: 313 */    0xAD /* '-' -> */,
+/* pos 026d: 314 */    0xE1 /* 'a' -> */,
+/* pos 026e: 315 */    0xE6 /* 'f' -> */,
+/* pos 026f: 316 */    0xF4 /* 't' -> */,
+/* pos 0270: 317 */    0xE5 /* 'e' -> */,
+/* pos 0271: 318 */    0xF2 /* 'r' -> */,
+/* pos 0272: 319 */    0xBA /* ':' -> */,
+/* pos 0273: 320 */    0x00, 0x3E                  /* - terminal marker 62 - */,
+/* pos 0275: 321 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x027C state 322) */,
+                       0x74 /* 't' */, 0x06, 0x01  /* (to 0x037E state 514) */,
+                       0x08, /* fail */
+/* pos 027c: 322 */    0x72 /* 'r' */, 0x0A, 0x00  /* (to 0x0286 state 323) */,
+                       0x74 /* 't' */, 0x0D, 0x00  /* (to 0x028C state 328) */,
+                       0x63 /* 'c' */, 0x6B, 0x01  /* (to 0x03ED state 607) */,
+                       0x08, /* fail */
+/* pos 0286: 323 */    0xF6 /* 'v' -> */,
+/* pos 0287: 324 */    0xE5 /* 'e' -> */,
+/* pos 0288: 325 */    0xF2 /* 'r' -> */,
+/* pos 0289: 326 */    0xBA /* ':' -> */,
+/* pos 028a: 327 */    0x00, 0x3F                  /* - terminal marker 63 - */,
+/* pos 028c: 328 */    0xAD /* '-' -> */,
+/* pos 028d: 329 */    0xE3 /* 'c' -> */,
+/* pos 028e: 330 */    0xEF /* 'o' -> */,
+/* pos 028f: 331 */    0xEF /* 'o' -> */,
+/* pos 0290: 332 */    0xEB /* 'k' -> */,
+/* pos 0291: 333 */    0xE9 /* 'i' -> */,
+/* pos 0292: 334 */    0xE5 /* 'e' -> */,
+/* pos 0293: 335 */    0xBA /* ':' -> */,
+/* pos 0294: 336 */    0x00, 0x40                  /* - terminal marker 64 - */,
+/* pos 0296: 337 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x029D state 338) */,
+                       0x65 /* 'e' */, 0x45, 0x01  /* (to 0x03DE state 594) */,
+                       0x08, /* fail */
+/* pos 029d: 338 */    0xE1 /* 'a' -> */,
+/* pos 029e: 339 */    0xEE /* 'n' -> */,
+/* pos 029f: 340 */    0xF3 /* 's' -> */,
+/* pos 02a0: 341 */    0xE6 /* 'f' -> */,
+/* pos 02a1: 342 */    0xE5 /* 'e' -> */,
+/* pos 02a2: 343 */    0xF2 /* 'r' -> */,
+/* pos 02a3: 344 */    0xAD /* '-' -> */,
+/* pos 02a4: 345 */    0xE5 /* 'e' -> */,
+/* pos 02a5: 346 */    0xEE /* 'n' -> */,
+/* pos 02a6: 347 */    0xE3 /* 'c' -> */,
+/* pos 02a7: 348 */    0xEF /* 'o' -> */,
+/* pos 02a8: 349 */    0xE4 /* 'd' -> */,
+/* pos 02a9: 350 */    0xE9 /* 'i' -> */,
+/* pos 02aa: 351 */    0xEE /* 'n' -> */,
+/* pos 02ab: 352 */    0xE7 /* 'g' -> */,
+/* pos 02ac: 353 */    0xBA /* ':' -> */,
+/* pos 02ad: 354 */    0x00, 0x42                  /* - terminal marker 66 - */,
+/* pos 02af: 355 */    0xE9 /* 'i' -> */,
+/* pos 02b0: 356 */    0xAD /* '-' -> */,
+/* pos 02b1: 357 */    0xE1 /* 'a' -> */,
+/* pos 02b2: 358 */    0xF2 /* 'r' -> */,
+/* pos 02b3: 359 */    0xE7 /* 'g' -> */,
+/* pos 02b4: 360 */    0xF3 /* 's' -> */,
+/* pos 02b5: 361 */    0x00, 0x47                  /* - terminal marker 71 - */,
+/* pos 02b7: 362 */    0xA0 /* ' ' -> */,
+/* pos 02b8: 363 */    0x00, 0x48                  /* - terminal marker 72 - */,
+/* pos 02ba: 364 */    0xAD /* '-' -> */,
+/* pos 02bb: 365 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x02C5 state 366) */,
+                       0x61 /* 'a' */, 0x1D, 0x00  /* (to 0x02DB state 385) */,
+                       0x72 /* 'r' */, 0x14, 0x01  /* (to 0x03D5 state 586) */,
+                       0x08, /* fail */
+/* pos 02c5: 366 */    0xEF /* 'o' -> */,
+/* pos 02c6: 367 */    0xF2 /* 'r' -> */,
+/* pos 02c7: 368 */    0xF7 /* 'w' -> */,
+/* pos 02c8: 369 */    0xE1 /* 'a' -> */,
+/* pos 02c9: 370 */    0xF2 /* 'r' -> */,
+/* pos 02ca: 371 */    0xE4 /* 'd' -> */,
+/* pos 02cb: 372 */    0xE5 /* 'e' -> */,
+/* pos 02cc: 373 */    0xE4 /* 'd' -> */,
+/* pos 02cd: 374 */    0xAD /* '-' -> */,
+/* pos 02ce: 375 */    0xE6 /* 'f' -> */,
+/* pos 02cf: 376 */    0xEF /* 'o' -> */,
+/* pos 02d0: 377 */    0xF2 /* 'r' -> */,
+/* pos 02d1: 378 */    0xBA /* ':' -> */,
+/* pos 02d2: 379 */    0x00, 0x49                  /* - terminal marker 73 - */,
+/* pos 02d4: 380 */    0x00, 0x4A                  /* - terminal marker 74 - */,
+/* pos 02d6: 381 */    0xE1 /* 'a' -> */,
+/* pos 02d7: 382 */    0xE4 /* 'd' -> */,
+/* pos 02d8: 383 */    0xA0 /* ' ' -> */,
+/* pos 02d9: 384 */    0x00, 0x4B                  /* - terminal marker 75 - */,
+/* pos 02db: 385 */    0x75 /* 'u' */, 0x07, 0x00  /* (to 0x02E2 state 386) */,
+                       0x6D /* 'm' */, 0x0F, 0x00  /* (to 0x02ED state 396) */,
+                       0x08, /* fail */
+/* pos 02e2: 386 */    0xF4 /* 't' -> */,
+/* pos 02e3: 387 */    0xE8 /* 'h' -> */,
+/* pos 02e4: 388 */    0xAD /* '-' -> */,
+/* pos 02e5: 389 */    0xF4 /* 't' -> */,
+/* pos 02e6: 390 */    0xEF /* 'o' -> */,
+/* pos 02e7: 391 */    0xEB /* 'k' -> */,
+/* pos 02e8: 392 */    0xE5 /* 'e' -> */,
+/* pos 02e9: 393 */    0xEE /* 'n' -> */,
+/* pos 02ea: 394 */    0xBA /* ':' -> */,
+/* pos 02eb: 395 */    0x00, 0x4F                  /* - terminal marker 79 - */,
+/* pos 02ed: 396 */    0xFA /* 'z' -> */,
+/* pos 02ee: 397 */    0xEE /* 'n' -> */,
+/* pos 02ef: 398 */    0xAD /* '-' -> */,
+/* pos 02f0: 399 */    0xE4 /* 'd' -> */,
+/* pos 02f1: 400 */    0xF3 /* 's' -> */,
+/* pos 02f2: 401 */    0xF3 /* 's' -> */,
+/* pos 02f3: 402 */    0xAD /* '-' -> */,
+/* pos 02f4: 403 */    0xF3 /* 's' -> */,
+/* pos 02f5: 404 */    0xE9 /* 'i' -> */,
+/* pos 02f6: 405 */    0xE7 /* 'g' -> */,
+/* pos 02f7: 406 */    0xEE /* 'n' -> */,
+/* pos 02f8: 407 */    0xE1 /* 'a' -> */,
+/* pos 02f9: 408 */    0xF4 /* 't' -> */,
+/* pos 02fa: 409 */    0xF5 /* 'u' -> */,
+/* pos 02fb: 410 */    0xF2 /* 'r' -> */,
+/* pos 02fc: 411 */    0xE5 /* 'e' -> */,
+/* pos 02fd: 412 */    0xBA /* ':' -> */,
+/* pos 02fe: 413 */    0x00, 0x50                  /* - terminal marker 80 - */,
+/* pos 0300: 414 */    0xF4 /* 't' -> */,
+/* pos 0301: 415 */    0xE9 /* 'i' -> */,
+/* pos 0302: 416 */    0xEF /* 'o' -> */,
+/* pos 0303: 417 */    0xEE /* 'n' -> */,
+/* pos 0304: 418 */    0xF3 /* 's' -> */,
+/* pos 0305: 419 */    0xA0 /* ' ' -> */,
+/* pos 0306: 420 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 0308: 421 */    0xF3 /* 's' -> */,
+/* pos 0309: 422 */    0xAD /* '-' -> */,
+/* pos 030a: 423 */    0xE3 /* 'c' -> */,
+/* pos 030b: 424 */    0xEF /* 'o' -> */,
+/* pos 030c: 425 */    0xEE /* 'n' -> */,
+/* pos 030d: 426 */    0xF4 /* 't' -> */,
+/* pos 030e: 427 */    0xF2 /* 'r' -> */,
+/* pos 030f: 428 */    0xEF /* 'o' -> */,
+/* pos 0310: 429 */    0xEC /* 'l' -> */,
+/* pos 0311: 430 */    0xAD /* '-' -> */,
+/* pos 0312: 431 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0319 state 432) */,
+                       0x61 /* 'a' */, 0x24, 0x00  /* (to 0x0339 state 461) */,
+                       0x08, /* fail */
+/* pos 0319: 432 */    0xE5 /* 'e' -> */,
+/* pos 031a: 433 */    0xF1 /* 'q' -> */,
+/* pos 031b: 434 */    0xF5 /* 'u' -> */,
+/* pos 031c: 435 */    0xE5 /* 'e' -> */,
+/* pos 031d: 436 */    0xF3 /* 's' -> */,
+/* pos 031e: 437 */    0xF4 /* 't' -> */,
+/* pos 031f: 438 */    0xAD /* '-' -> */,
+/* pos 0320: 439 */    0xE8 /* 'h' -> */,
+/* pos 0321: 440 */    0xE5 /* 'e' -> */,
+/* pos 0322: 441 */    0xE1 /* 'a' -> */,
+/* pos 0323: 442 */    0xE4 /* 'd' -> */,
+/* pos 0324: 443 */    0xE5 /* 'e' -> */,
+/* pos 0325: 444 */    0xF2 /* 'r' -> */,
+/* pos 0326: 445 */    0xF3 /* 's' -> */,
+/* pos 0327: 446 */    0xBA /* ':' -> */,
+/* pos 0328: 447 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 032a: 448 */    0xF2 /* 'r' -> */,
+/* pos 032b: 449 */    0xE5 /* 'e' -> */,
+/* pos 032c: 450 */    0xF2 /* 'r' -> */,
+/* pos 032d: 451 */    0xBA /* ':' -> */,
+/* pos 032e: 452 */    0x00, 0x1D                  /* - terminal marker 29 - */,
+/* pos 0330: 453 */    0xE8 /* 'h' -> */,
+/* pos 0331: 454 */    0xE1 /* 'a' -> */,
+/* pos 0332: 455 */    0xF2 /* 'r' -> */,
+/* pos 0333: 456 */    0xF3 /* 's' -> */,
+/* pos 0334: 457 */    0xE5 /* 'e' -> */,
+/* pos 0335: 458 */    0xF4 /* 't' -> */,
+/* pos 0336: 459 */    0xBA /* ':' -> */,
+/* pos 0337: 460 */    0x00, 0x26                  /* - terminal marker 38 - */,
+/* pos 0339: 461 */    0xEC /* 'l' -> */,
+/* pos 033a: 462 */    0xEC /* 'l' -> */,
+/* pos 033b: 463 */    0xEF /* 'o' -> */,
+/* pos 033c: 464 */    0xF7 /* 'w' -> */,
+/* pos 033d: 465 */    0xAD /* '-' -> */,
+/* pos 033e: 466 */    0xEF /* 'o' -> */,
+/* pos 033f: 467 */    0xF2 /* 'r' -> */,
+/* pos 0340: 468 */    0xE9 /* 'i' -> */,
+/* pos 0341: 469 */    0xE7 /* 'g' -> */,
+/* pos 0342: 470 */    0xE9 /* 'i' -> */,
+/* pos 0343: 471 */    0xEE /* 'n' -> */,
+/* pos 0344: 472 */    0xBA /* ':' -> */,
+/* pos 0345: 473 */    0x00, 0x28                  /* - terminal marker 40 - */,
+/* pos 0347: 474 */    0xE1 /* 'a' -> */,
+/* pos 0348: 475 */    0xF8 /* 'x' -> */,
+/* pos 0349: 476 */    0xAD /* '-' -> */,
+/* pos 034a: 477 */    0xE6 /* 'f' -> */,
+/* pos 034b: 478 */    0xEF /* 'o' -> */,
+/* pos 034c: 479 */    0xF2 /* 'r' -> */,
+/* pos 034d: 480 */    0xF7 /* 'w' -> */,
+/* pos 034e: 481 */    0xE1 /* 'a' -> */,
+/* pos 034f: 482 */    0xF2 /* 'r' -> */,
+/* pos 0350: 483 */    0xE4 /* 'd' -> */,
+/* pos 0351: 484 */    0xF3 /* 's' -> */,
+/* pos 0352: 485 */    0xBA /* ':' -> */,
+/* pos 0353: 486 */    0x00, 0x3A                  /* - terminal marker 58 - */,
+/* pos 0355: 487 */    0xF8 /* 'x' -> */,
+/* pos 0356: 488 */    0xF9 /* 'y' -> */,
+/* pos 0357: 489 */    0x2D /* '-' */, 0x07, 0x00  /* (to 0x035E state 490) */,
+                       0x20 /* ' ' */, 0x79, 0x00  /* (to 0x03D3 state 585) */,
+                       0x08, /* fail */
+/* pos 035e: 490 */    0xE1 /* 'a' -> */,
+/* pos 035f: 491 */    0xF5 /* 'u' -> */,
+/* pos 0360: 492 */    0xF4 /* 't' -> */,
+/* pos 0361: 493 */    0xE8 /* 'h' -> */,
+/* pos 0362: 494 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0369 state 495) */,
+                       0x6F /* 'o' */, 0x0E, 0x00  /* (to 0x0373 state 504) */,
+                       0x08, /* fail */
+/* pos 0369: 495 */    0xEE /* 'n' -> */,
+/* pos 036a: 496 */    0xF4 /* 't' -> */,
+/* pos 036b: 497 */    0xE9 /* 'i' -> */,
+/* pos 036c: 498 */    0xE3 /* 'c' -> */,
+/* pos 036d: 499 */    0xE1 /* 'a' -> */,
+/* pos 036e: 500 */    0xF4 /* 't' -> */,
+/* pos 036f: 501 */    0xE5 /* 'e' -> */,
+/* pos 0370: 502 */    0xBA /* ':' -> */,
+/* pos 0371: 503 */    0x00, 0x3B                  /* - terminal marker 59 - */,
+/* pos 0373: 504 */    0xF2 /* 'r' -> */,
+/* pos 0374: 505 */    0xE9 /* 'i' -> */,
+/* pos 0375: 506 */    0xFA /* 'z' -> */,
+/* pos 0376: 507 */    0xE1 /* 'a' -> */,
+/* pos 0377: 508 */    0xF4 /* 't' -> */,
+/* pos 0378: 509 */    0xE9 /* 'i' -> */,
+/* pos 0379: 510 */    0xEF /* 'o' -> */,
+/* pos 037a: 511 */    0xEE /* 'n' -> */,
+/* pos 037b: 512 */    0xBA /* ':' -> */,
+/* pos 037c: 513 */    0x00, 0x3C                  /* - terminal marker 60 - */,
+/* pos 037e: 514 */    0xF2 /* 'r' -> */,
+/* pos 037f: 515 */    0xE9 /* 'i' -> */,
+/* pos 0380: 516 */    0xE3 /* 'c' -> */,
+/* pos 0381: 517 */    0xF4 /* 't' -> */,
+/* pos 0382: 518 */    0xAD /* '-' -> */,
+/* pos 0383: 519 */    0xF4 /* 't' -> */,
+/* pos 0384: 520 */    0xF2 /* 'r' -> */,
+/* pos 0385: 521 */    0xE1 /* 'a' -> */,
+/* pos 0386: 522 */    0xEE /* 'n' -> */,
+/* pos 0387: 523 */    0xF3 /* 's' -> */,
+/* pos 0388: 524 */    0xF0 /* 'p' -> */,
+/* pos 0389: 525 */    0xEF /* 'o' -> */,
+/* pos 038a: 526 */    0xF2 /* 'r' -> */,
+/* pos 038b: 527 */    0xF4 /* 't' -> */,
+/* pos 038c: 528 */    0xAD /* '-' -> */,
+/* pos 038d: 529 */    0xF3 /* 's' -> */,
+/* pos 038e: 530 */    0xE5 /* 'e' -> */,
+/* pos 038f: 531 */    0xE3 /* 'c' -> */,
+/* pos 0390: 532 */    0xF5 /* 'u' -> */,
+/* pos 0391: 533 */    0xF2 /* 'r' -> */,
+/* pos 0392: 534 */    0xE9 /* 'i' -> */,
+/* pos 0393: 535 */    0xF4 /* 't' -> */,
+/* pos 0394: 536 */    0xF9 /* 'y' -> */,
+/* pos 0395: 537 */    0xBA /* ':' -> */,
+/* pos 0396: 538 */    0x00, 0x41                  /* - terminal marker 65 - */,
+/* pos 0398: 539 */    0xE5 /* 'e' -> */,
+/* pos 0399: 540 */    0xF2 /* 'r' -> */,
+/* pos 039a: 541 */    0xAD /* '-' -> */,
+/* pos 039b: 542 */    0xE1 /* 'a' -> */,
+/* pos 039c: 543 */    0xE7 /* 'g' -> */,
+/* pos 039d: 544 */    0xE5 /* 'e' -> */,
+/* pos 039e: 545 */    0xEE /* 'n' -> */,
+/* pos 039f: 546 */    0xF4 /* 't' -> */,
+/* pos 03a0: 547 */    0xBA /* ':' -> */,
+/* pos 03a1: 548 */    0x00, 0x43                  /* - terminal marker 67 - */,
+/* pos 03a3: 549 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x03AA state 550) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x03AF state 554) */,
+                       0x08, /* fail */
+/* pos 03aa: 550 */    0xF2 /* 'r' -> */,
+/* pos 03ab: 551 */    0xF9 /* 'y' -> */,
+/* pos 03ac: 552 */    0xBA /* ':' -> */,
+/* pos 03ad: 553 */    0x00, 0x44                  /* - terminal marker 68 - */,
+/* pos 03af: 554 */    0xE1 /* 'a' -> */,
+/* pos 03b0: 555 */    0xBA /* ':' -> */,
+/* pos 03b1: 556 */    0x00, 0x45                  /* - terminal marker 69 - */,
+/* pos 03b3: 557 */    0xF7 /* 'w' -> */,
+/* pos 03b4: 558 */    0xF7 /* 'w' -> */,
+/* pos 03b5: 559 */    0xAD /* '-' -> */,
+/* pos 03b6: 560 */    0xE1 /* 'a' -> */,
+/* pos 03b7: 561 */    0xF5 /* 'u' -> */,
+/* pos 03b8: 562 */    0xF4 /* 't' -> */,
+/* pos 03b9: 563 */    0xE8 /* 'h' -> */,
+/* pos 03ba: 564 */    0xE5 /* 'e' -> */,
+/* pos 03bb: 565 */    0xEE /* 'n' -> */,
+/* pos 03bc: 566 */    0xF4 /* 't' -> */,
+/* pos 03bd: 567 */    0xE9 /* 'i' -> */,
+/* pos 03be: 568 */    0xE3 /* 'c' -> */,
+/* pos 03bf: 569 */    0xE1 /* 'a' -> */,
+/* pos 03c0: 570 */    0xF4 /* 't' -> */,
+/* pos 03c1: 571 */    0xE5 /* 'e' -> */,
+/* pos 03c2: 572 */    0xBA /* ':' -> */,
+/* pos 03c3: 573 */    0x00, 0x46                  /* - terminal marker 70 - */,
+/* pos 03c5: 574 */    0xF4 /* 't' -> */,
+/* pos 03c6: 575 */    0xE3 /* 'c' -> */,
+/* pos 03c7: 576 */    0xE8 /* 'h' -> */,
+/* pos 03c8: 577 */    0x00, 0x3F                  /* - terminal marker 63 - */,
+/* pos 03ca: 578 */    0xF4 /* 't' -> */,
+/* pos 03cb: 579 */    0x00, 0x40                  /* - terminal marker 64 - */,
+/* pos 03cd: 580 */    0xEC /* 'l' -> */,
+/* pos 03ce: 581 */    0xE5 /* 'e' -> */,
+/* pos 03cf: 582 */    0xF4 /* 't' -> */,
+/* pos 03d0: 583 */    0xE5 /* 'e' -> */,
+/* pos 03d1: 584 */    0x00, 0x41                  /* - terminal marker 65 - */,
+/* pos 03d3: 585 */    0x00, 0x43                  /* - terminal marker 67 - */,
+/* pos 03d5: 586 */    0xE5 /* 'e' -> */,
+/* pos 03d6: 587 */    0xE1 /* 'a' -> */,
+/* pos 03d7: 588 */    0xEC /* 'l' -> */,
+/* pos 03d8: 589 */    0xAD /* '-' -> */,
+/* pos 03d9: 590 */    0xE9 /* 'i' -> */,
+/* pos 03da: 591 */    0xF0 /* 'p' -> */,
+/* pos 03db: 592 */    0xBA /* ':' -> */,
+/* pos 03dc: 593 */    0x00, 0x44                  /* - terminal marker 68 - */,
+/* pos 03de: 594 */    0xBA /* ':' -> */,
+/* pos 03df: 595 */    0x00, 0x4C                  /* - terminal marker 76 - */,
+/* pos 03e1: 596 */    0xEC /* 'l' -> */,
+/* pos 03e2: 597 */    0xE1 /* 'a' -> */,
+/* pos 03e3: 598 */    0xF9 /* 'y' -> */,
+/* pos 03e4: 599 */    0xAD /* '-' -> */,
+/* pos 03e5: 600 */    0xEE /* 'n' -> */,
+/* pos 03e6: 601 */    0xEF /* 'o' -> */,
+/* pos 03e7: 602 */    0xEE /* 'n' -> */,
+/* pos 03e8: 603 */    0xE3 /* 'c' -> */,
+/* pos 03e9: 604 */    0xE5 /* 'e' -> */,
+/* pos 03ea: 605 */    0xBA /* ':' -> */,
+/* pos 03eb: 606 */    0x00, 0x4D                  /* - terminal marker 77 - */,
+/* pos 03ed: 607 */    0xAD /* '-' -> */,
+/* pos 03ee: 608 */    0xF7 /* 'w' -> */,
+/* pos 03ef: 609 */    0xE5 /* 'e' -> */,
+/* pos 03f0: 610 */    0xE2 /* 'b' -> */,
+/* pos 03f1: 611 */    0xF3 /* 's' -> */,
+/* pos 03f2: 612 */    0xEF /* 'o' -> */,
+/* pos 03f3: 613 */    0xE3 /* 'c' -> */,
+/* pos 03f4: 614 */    0xEB /* 'k' -> */,
+/* pos 03f5: 615 */    0xE5 /* 'e' -> */,
+/* pos 03f6: 616 */    0xF4 /* 't' -> */,
+/* pos 03f7: 617 */    0xAD /* '-' -> */,
+/* pos 03f8: 618 */    0x64 /* 'd' */, 0x19, 0x00  /* (to 0x0411 state 619) */,
+                       0x65 /* 'e' */, 0x1D, 0x00  /* (to 0x0418 state 625) */,
+                       0x6B /* 'k' */, 0x26, 0x00  /* (to 0x0424 state 636) */,
+                       0x70 /* 'p' */, 0x35, 0x00  /* (to 0x0436 state 643) */,
+                       0x61 /* 'a' */, 0x3C, 0x00  /* (to 0x0440 state 652) */,
+                       0x6E /* 'n' */, 0x41, 0x00  /* (to 0x0448 state 659) */,
+                       0x76 /* 'v' */, 0x47, 0x00  /* (to 0x0451 state 666) */,
+                       0x6F /* 'o' */, 0x4D, 0x00  /* (to 0x045A state 674) */,
+                       0x08, /* fail */
+/* pos 0411: 619 */    0xF2 /* 'r' -> */,
+/* pos 0412: 620 */    0xE1 /* 'a' -> */,
+/* pos 0413: 621 */    0xE6 /* 'f' -> */,
+/* pos 0414: 622 */    0xF4 /* 't' -> */,
+/* pos 0415: 623 */    0xBA /* ':' -> */,
+/* pos 0416: 624 */    0x00, 0x06                  /* - terminal marker  6 - */,
+/* pos 0418: 625 */    0xF8 /* 'x' -> */,
+/* pos 0419: 626 */    0xF4 /* 't' -> */,
+/* pos 041a: 627 */    0xE5 /* 'e' -> */,
+/* pos 041b: 628 */    0xEE /* 'n' -> */,
+/* pos 041c: 629 */    0xF3 /* 's' -> */,
+/* pos 041d: 630 */    0xE9 /* 'i' -> */,
+/* pos 041e: 631 */    0xEF /* 'o' -> */,
+/* pos 041f: 632 */    0xEE /* 'n' -> */,
+/* pos 0420: 633 */    0xF3 /* 's' -> */,
+/* pos 0421: 634 */    0xBA /* ':' -> */,
+/* pos 0422: 635 */    0x00, 0x08                  /* - terminal marker  8 - */,
+/* pos 0424: 636 */    0xE5 /* 'e' -> */,
+/* pos 0425: 637 */    0xF9 /* 'y' -> */,
+/* pos 0426: 638 */    0x31 /* '1' */, 0x0A, 0x00  /* (to 0x0430 state 639) */,
+                       0x32 /* '2' */, 0x0A, 0x00  /* (to 0x0433 state 641) */,
+                       0x3A /* ':' */, 0x23, 0x00  /* (to 0x044F state 665) */,
+                       0x08, /* fail */
+/* pos 0430: 639 */    0xBA /* ':' -> */,
+/* pos 0431: 640 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 0433: 641 */    0xBA /* ':' -> */,
+/* pos 0434: 642 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 0436: 643 */    0xF2 /* 'r' -> */,
+/* pos 0437: 644 */    0xEF /* 'o' -> */,
+/* pos 0438: 645 */    0xF4 /* 't' -> */,
+/* pos 0439: 646 */    0xEF /* 'o' -> */,
+/* pos 043a: 647 */    0xE3 /* 'c' -> */,
+/* pos 043b: 648 */    0xEF /* 'o' -> */,
+/* pos 043c: 649 */    0xEC /* 'l' -> */,
+/* pos 043d: 650 */    0xBA /* ':' -> */,
+/* pos 043e: 651 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 0440: 652 */    0xE3 /* 'c' -> */,
+/* pos 0441: 653 */    0xE3 /* 'c' -> */,
+/* pos 0442: 654 */    0xE5 /* 'e' -> */,
+/* pos 0443: 655 */    0xF0 /* 'p' -> */,
+/* pos 0444: 656 */    0xF4 /* 't' -> */,
+/* pos 0445: 657 */    0xBA /* ':' -> */,
+/* pos 0446: 658 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 0448: 659 */    0xEF /* 'o' -> */,
+/* pos 0449: 660 */    0xEE /* 'n' -> */,
+/* pos 044a: 661 */    0xE3 /* 'c' -> */,
+/* pos 044b: 662 */    0xE5 /* 'e' -> */,
+/* pos 044c: 663 */    0xBA /* ':' -> */,
+/* pos 044d: 664 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 044f: 665 */    0x00, 0x1E                  /* - terminal marker 30 - */,
+/* pos 0451: 666 */    0xE5 /* 'e' -> */,
+/* pos 0452: 667 */    0xF2 /* 'r' -> */,
+/* pos 0453: 668 */    0xF3 /* 's' -> */,
+/* pos 0454: 669 */    0xE9 /* 'i' -> */,
+/* pos 0455: 670 */    0xEF /* 'o' -> */,
+/* pos 0456: 671 */    0xEE /* 'n' -> */,
+/* pos 0457: 672 */    0xBA /* ':' -> */,
+/* pos 0458: 673 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 045a: 674 */    0xF2 /* 'r' -> */,
+/* pos 045b: 675 */    0xE9 /* 'i' -> */,
+/* pos 045c: 676 */    0xE7 /* 'g' -> */,
+/* pos 045d: 677 */    0xE9 /* 'i' -> */,
+/* pos 045e: 678 */    0xEE /* 'n' -> */,
+/* pos 045f: 679 */    0xBA /* ':' -> */,
+/* pos 0460: 680 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 0462: 681 */    0xAD /* '-' -> */,
+/* pos 0463: 682 */    0xF3 /* 's' -> */,
+/* pos 0464: 683 */    0xE5 /* 'e' -> */,
+/* pos 0465: 684 */    0xF4 /* 't' -> */,
+/* pos 0466: 685 */    0xF4 /* 't' -> */,
+/* pos 0467: 686 */    0xE9 /* 'i' -> */,
+/* pos 0468: 687 */    0xEE /* 'n' -> */,
+/* pos 0469: 688 */    0xE7 /* 'g' -> */,
+/* pos 046a: 689 */    0xF3 /* 's' -> */,
+/* pos 046b: 690 */    0xBA /* ':' -> */,
+/* pos 046c: 691 */    0x00, 0x0F                  /* - terminal marker 15 - */,
+/* pos 046e: 692 */    0x61 /* 'a' */, 0x0D, 0x00  /* (to 0x047B state 693) */,
+                       0x6D /* 'm' */, 0x14, 0x00  /* (to 0x0485 state 702) */,
+                       0x70 /* 'p' */, 0x18, 0x00  /* (to 0x048C state 708) */,
+                       0x73 /* 's' */, 0x20, 0x00  /* (to 0x0497 state 712) */,
+                       0x08, /* fail */
+/* pos 047b: 693 */    0xF5 /* 'u' -> */,
+/* pos 047c: 694 */    0xF4 /* 't' -> */,
+/* pos 047d: 695 */    0xE8 /* 'h' -> */,
+/* pos 047e: 696 */    0xEF /* 'o' -> */,
+/* pos 047f: 697 */    0xF2 /* 'r' -> */,
+/* pos 0480: 698 */    0xE9 /* 'i' -> */,
+/* pos 0481: 699 */    0xF4 /* 't' -> */,
+/* pos 0482: 700 */    0xF9 /* 'y' -> */,
+/* pos 0483: 701 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* pos 0485: 702 */    0xE5 /* 'e' -> */,
+/* pos 0486: 703 */    0xF4 /* 't' -> */,
+/* pos 0487: 704 */    0xE8 /* 'h' -> */,
+/* pos 0488: 705 */    0xEF /* 'o' -> */,
+/* pos 0489: 706 */    0xE4 /* 'd' -> */,
+/* pos 048a: 707 */    0x00, 0x22                  /* - terminal marker 34 - */,
+/* pos 048c: 708 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0493 state 709) */,
+                       0x72 /* 'r' */, 0x1B, 0x00  /* (to 0x04AA state 723) */,
+                       0x08, /* fail */
+/* pos 0493: 709 */    0xF4 /* 't' -> */,
+/* pos 0494: 710 */    0xE8 /* 'h' -> */,
+/* pos 0495: 711 */    0x00, 0x23                  /* - terminal marker 35 - */,
+/* pos 0497: 712 */    0x63 /* 'c' */, 0x07, 0x00  /* (to 0x049E state 713) */,
+                       0x74 /* 't' */, 0x0A, 0x00  /* (to 0x04A4 state 718) */,
+                       0x08, /* fail */
+/* pos 049e: 713 */    0xE8 /* 'h' -> */,
+/* pos 049f: 714 */    0xE5 /* 'e' -> */,
+/* pos 04a0: 715 */    0xED /* 'm' -> */,
+/* pos 04a1: 716 */    0xE5 /* 'e' -> */,
+/* pos 04a2: 717 */    0x00, 0x24                  /* - terminal marker 36 - */,
+/* pos 04a4: 718 */    0xE1 /* 'a' -> */,
+/* pos 04a5: 719 */    0xF4 /* 't' -> */,
+/* pos 04a6: 720 */    0xF5 /* 'u' -> */,
+/* pos 04a7: 721 */    0xF3 /* 's' -> */,
+/* pos 04a8: 722 */    0x00, 0x25                  /* - terminal marker 37 - */,
+/* pos 04aa: 723 */    0xEF /* 'o' -> */,
+/* pos 04ab: 724 */    0xF4 /* 't' -> */,
+/* pos 04ac: 725 */    0xEF /* 'o' -> */,
+/* pos 04ad: 726 */    0xE3 /* 'c' -> */,
+/* pos 04ae: 727 */    0xEF /* 'o' -> */,
+/* pos 04af: 728 */    0xEC /* 'l' -> */,
+/* pos 04b0: 729 */    0x00, 0x4E                  /* - terminal marker 78 - */,
+/* total size 1202 bytes */
+#endif
+
+#if defined(LWS_HTTP_HEADERS_ALL) || ( defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2))
+       /* 0: 0: get  */
+       /* 1: 1: post  */
+       /* 2: 2: options  */
+       /* 3: 3: host: */
+       /* 4: 4: connection: */
+       /* 5: 5: upgrade: */
+       /* 6: 6: origin: */
+       /* 7: 7: sec-websocket-draft: */
+       /* 8: 8: \r
+ */
+       /* 9: 9: sec-websocket-extensions: */
+       /* 10: 10: sec-websocket-key1: */
+       /* 11: 11: sec-websocket-key2: */
+       /* 12: 12: sec-websocket-protocol: */
+       /* 13: 13: sec-websocket-accept: */
+       /* 14: 14: sec-websocket-nonce: */
+       /* 15: 15: http/1.1  */
+       /* 16: 16: http2-settings: */
+       /* 17: 17: accept: */
+       /* 18: 18: access-control-request-headers: */
+       /* 19: 19: if-modified-since: */
+       /* 20: 20: if-none-match: */
+       /* 21: 21: accept-encoding: */
+       /* 22: 22: accept-language: */
+       /* 23: 23: pragma: */
+       /* 24: 24: cache-control: */
+       /* 25: 25: authorization: */
+       /* 26: 26: cookie: */
+       /* 27: 27: content-length: */
+       /* 28: 28: content-type: */
+       /* 29: 29: date: */
+       /* 30: 30: range: */
+       /* 31: 31: referer: */
+       /* 32: 32: sec-websocket-key: */
+       /* 33: 33: sec-websocket-version: */
+       /* 34: 34: sec-websocket-origin: */
+       /* 35: 35: :authority */
+       /* 36: 36: :method */
+       /* 37: 37: :path */
+       /* 38: 38: :scheme */
+       /* 39: 39: :status */
+       /* 40: 40: accept-charset: */
+       /* 41: 41: accept-ranges: */
+       /* 42: 42: access-control-allow-origin: */
+       /* 43: 43: age: */
+       /* 44: 44: allow: */
+       /* 45: 45: content-disposition: */
+       /* 46: 46: content-encoding: */
+       /* 47: 47: content-language: */
+       /* 48: 48: content-location: */
+       /* 49: 49: content-range: */
+       /* 50: 50: etag: */
+       /* 51: 51: expect: */
+       /* 52: 52: expires: */
+       /* 53: 53: from: */
+       /* 54: 54: if-match: */
+       /* 55: 55: if-range: */
+       /* 56: 56: if-unmodified-since: */
+       /* 57: 57: last-modified: */
+       /* 58: 58: link: */
+       /* 59: 59: location: */
+       /* 60: 60: max-forwards: */
+       /* 61: 61: proxy-authenticate: */
+       /* 62: 62: proxy-authorization: */
+       /* 63: 63: refresh: */
+       /* 64: 64: retry-after: */
+       /* 65: 65: server: */
+       /* 66: 66: set-cookie: */
+       /* 67: 67: strict-transport-security: */
+       /* 68: 68: transfer-encoding: */
+       /* 69: 69: user-agent: */
+       /* 70: 70: vary: */
+       /* 71: 71: via: */
+       /* 72: 72: www-authenticate: */
+       /* 73: 73: patch */
+       /* 74: 74: put */
+       /* 75: 75: delete */
+       /* 76: 76: uri-args */
+       /* 77: 77: proxy  */
+       /* 78: 78: x-real-ip: */
+       /* 79: 79: http/1.0  */
+       /* 80: 80: x-forwarded-for: */
+       /* 81: 81: connect  */
+       /* 82: 82: head  */
+       /* 83: 83: te: */
+       /* 84: 84: replay-nonce: */
+       /* 85: 85: :protocol */
+       /* 86: 86: x-auth-token: */
+       /* 87: 87: x-amzn-dss-signature: */
+/* pos 0000:   0 */    0x67 /* 'g' */, 0x40, 0x00  /* (to 0x0040 state   1) */,
+                       0x70 /* 'p' */, 0x42, 0x00  /* (to 0x0045 state   5) */,
+                       0x68 /* 'h' */, 0x51, 0x00  /* (to 0x0057 state  10) */,
+                       0x63 /* 'c' */, 0x5D, 0x00  /* (to 0x0066 state  15) */,
+                       0x75 /* 'u' */, 0x7E, 0x00  /* (to 0x008A state  26) */,
+                       0x6F /* 'o' */, 0x8D, 0x00  /* (to 0x009C state  34) */,
+                       0x0D /* '.' */, 0x98, 0x00  /* (to 0x00AA state  41) */,
+                       0x61 /* 'a' */, 0xAD, 0x00  /* (to 0x00C2 state  51) */,
+                       0x69 /* 'i' */, 0xCA, 0x00  /* (to 0x00E2 state  58) */,
+                       0x64 /* 'd' */, 0x73, 0x01  /* (to 0x018E state 160) */,
+                       0x72 /* 'r' */, 0x7C, 0x01  /* (to 0x019A state 165) */,
+                       0x65 /* 'e' */, 0xC8, 0x01  /* (to 0x01E9 state 229) */,
+                       0x66 /* 'f' */, 0xE4, 0x01  /* (to 0x0208 state 245) */,
+                       0x6C /* 'l' */, 0x06, 0x02  /* (to 0x022D state 278) */,
+                       0x73 /* 's' */, 0x4B, 0x02  /* (to 0x0275 state 321) */,
+                       0x74 /* 't' */, 0x69, 0x02  /* (to 0x0296 state 337) */,
+                       0x78 /* 'x' */, 0x8A, 0x02  /* (to 0x02BA state 364) */,
+                       0x6D /* 'm' */, 0x14, 0x03  /* (to 0x0347 state 474) */,
+                       0x76 /* 'v' */, 0x6D, 0x03  /* (to 0x03A3 state 549) */,
+                       0x77 /* 'w' */, 0x7A, 0x03  /* (to 0x03B3 state 557) */,
+                       0x3A /* ':' */, 0x32, 0x04  /* (to 0x046E state 692) */,
+                       0x08, /* fail */
+/* pos 0040:   1 */    0xE5 /* 'e' -> */,
+/* pos 0041:   2 */    0xF4 /* 't' -> */,
+/* pos 0042:   3 */    0xA0 /* ' ' -> */,
+/* pos 0043:   4 */    0x00, 0x00                  /* - terminal marker  0 - */,
+/* pos 0045:   5 */    0x6F /* 'o' */, 0x0D, 0x00  /* (to 0x0052 state   6) */,
+                       0x72 /* 'r' */, 0xEC, 0x00  /* (to 0x0134 state 106) */,
+                       0x61 /* 'a' */, 0x7A, 0x03  /* (to 0x03C5 state 574) */,
+                       0x75 /* 'u' */, 0x7C, 0x03  /* (to 0x03CA state 578) */,
+                       0x08, /* fail */
+/* pos 0052:   6 */    0xF3 /* 's' -> */,
+/* pos 0053:   7 */    0xF4 /* 't' -> */,
+/* pos 0054:   8 */    0xA0 /* ' ' -> */,
+/* pos 0055:   9 */    0x00, 0x01                  /* - terminal marker  1 - */,
+/* pos 0057:  10 */    0x6F /* 'o' */, 0x0A, 0x00  /* (to 0x0061 state  11) */,
+                       0x74 /* 't' */, 0x53, 0x00  /* (to 0x00AD state  43) */,
+                       0x65 /* 'e' */, 0x79, 0x02  /* (to 0x02D6 state 381) */,
+                       0x08, /* fail */
+/* pos 0061:  11 */    0xF3 /* 's' -> */,
+/* pos 0062:  12 */    0xF4 /* 't' -> */,
+/* pos 0063:  13 */    0xBA /* ':' -> */,
+/* pos 0064:  14 */    0x00, 0x03                  /* - terminal marker  3 - */,
+/* pos 0066:  15 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x006D state  16) */,
+                       0x61 /* 'a' */, 0xD8, 0x00  /* (to 0x0141 state 112) */,
+                       0x08, /* fail */
+/* pos 006d:  16 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x0074 state  17) */,
+                       0x6F /* 'o' */, 0xED, 0x00  /* (to 0x015D state 138) */,
+                       0x08, /* fail */
+/* pos 0074:  17 */    0x6E /* 'n' */, 0x07, 0x00  /* (to 0x007B state  18) */,
+                       0x74 /* 't' */, 0xEC, 0x00  /* (to 0x0163 state 143) */,
+                       0x08, /* fail */
+/* pos 007b:  18 */    0xE5 /* 'e' -> */,
+/* pos 007c:  19 */    0xE3 /* 'c' -> */,
+/* pos 007d:  20 */    0xF4 /* 't' -> */,
+/* pos 007e:  21 */    0x69 /* 'i' */, 0x07, 0x00  /* (to 0x0085 state  22) */,
+                       0x20 /* ' ' */, 0x53, 0x02  /* (to 0x02D4 state 380) */,
+                       0x08, /* fail */
+/* pos 0085:  22 */    0xEF /* 'o' -> */,
+/* pos 0086:  23 */    0xEE /* 'n' -> */,
+/* pos 0087:  24 */    0xBA /* ':' -> */,
+/* pos 0088:  25 */    0x00, 0x04                  /* - terminal marker  4 - */,
+/* pos 008a:  26 */    0x70 /* 'p' */, 0x0A, 0x00  /* (to 0x0094 state  27) */,
+                       0x72 /* 'r' */, 0x22, 0x02  /* (to 0x02AF state 355) */,
+                       0x73 /* 's' */, 0x08, 0x03  /* (to 0x0398 state 539) */,
+                       0x08, /* fail */
+/* pos 0094:  27 */    0xE7 /* 'g' -> */,
+/* pos 0095:  28 */    0xF2 /* 'r' -> */,
+/* pos 0096:  29 */    0xE1 /* 'a' -> */,
+/* pos 0097:  30 */    0xE4 /* 'd' -> */,
+/* pos 0098:  31 */    0xE5 /* 'e' -> */,
+/* pos 0099:  32 */    0xBA /* ':' -> */,
+/* pos 009a:  33 */    0x00, 0x05                  /* - terminal marker  5 - */,
+/* pos 009c:  34 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x00A3 state  35) */,
+                       0x70 /* 'p' */, 0x61, 0x02  /* (to 0x0300 state 414) */,
+                       0x08, /* fail */
+/* pos 00a3:  35 */    0xE9 /* 'i' -> */,
+/* pos 00a4:  36 */    0xE7 /* 'g' -> */,
+/* pos 00a5:  37 */    0xE9 /* 'i' -> */,
+/* pos 00a6:  38 */    0xEE /* 'n' -> */,
+/* pos 00a7:  39 */    0xBA /* ':' -> */,
+/* pos 00a8:  40 */    0x00, 0x06                  /* - terminal marker  6 - */,
+/* pos 00aa:  41 */    0x8A /* '.' -> */,
+/* pos 00ab:  42 */    0x00, 0x08                  /* - terminal marker  8 - */,
+/* pos 00ad:  43 */    0xF4 /* 't' -> */,
+/* pos 00ae:  44 */    0xF0 /* 'p' -> */,
+/* pos 00af:  45 */    0x2F /* '/' */, 0x07, 0x00  /* (to 0x00B6 state  46) */,
+                       0x32 /* '2' */, 0xB0, 0x03  /* (to 0x0462 state 681) */,
+                       0x08, /* fail */
+/* pos 00b6:  46 */    0xB1 /* '1' -> */,
+/* pos 00b7:  47 */    0xAE /* '.' -> */,
+/* pos 00b8:  48 */    0x31 /* '1' */, 0x07, 0x00  /* (to 0x00BF state  49) */,
+                       0x30 /* '0' */, 0xFC, 0x01  /* (to 0x02B7 state 362) */,
+                       0x08, /* fail */
+/* pos 00bf:  49 */    0xA0 /* ' ' -> */,
+/* pos 00c0:  50 */    0x00, 0x0F                  /* - terminal marker 15 - */,
+/* pos 00c2:  51 */    0x63 /* 'c' */, 0x0D, 0x00  /* (to 0x00CF state  52) */,
+                       0x75 /* 'u' */, 0x8A, 0x00  /* (to 0x014F state 125) */,
+                       0x67 /* 'g' */, 0xE7, 0x00  /* (to 0x01AF state 178) */,
+                       0x6C /* 'l' */, 0xE8, 0x00  /* (to 0x01B3 state 181) */,
+                       0x08, /* fail */
+/* pos 00cf:  52 */    0xE3 /* 'c' -> */,
+/* pos 00d0:  53 */    0xE5 /* 'e' -> */,
+/* pos 00d1:  54 */    0x70 /* 'p' */, 0x07, 0x00  /* (to 0x00D8 state  55) */,
+                       0x73 /* 's' */, 0x34, 0x02  /* (to 0x0308 state 421) */,
+                       0x08, /* fail */
+/* pos 00d8:  55 */    0xF4 /* 't' -> */,
+/* pos 00d9:  56 */    0x3A /* ':' */, 0x07, 0x00  /* (to 0x00E0 state  57) */,
+                       0x2D /* '-' */, 0x37, 0x00  /* (to 0x0113 state  87) */,
+                       0x08, /* fail */
+/* pos 00e0:  57 */    0x00, 0x11                  /* - terminal marker 17 - */,
+/* pos 00e2:  58 */    0xE6 /* 'f' -> */,
+/* pos 00e3:  59 */    0xAD /* '-' -> */,
+/* pos 00e4:  60 */    0x6D /* 'm' */, 0x0D, 0x00  /* (to 0x00F1 state  61) */,
+                       0x6E /* 'n' */, 0x20, 0x00  /* (to 0x0107 state  76) */,
+                       0x72 /* 'r' */, 0x2A, 0x01  /* (to 0x0214 state 255) */,
+                       0x75 /* 'u' */, 0x2E, 0x01  /* (to 0x021B state 261) */,
+                       0x08, /* fail */
+/* pos 00f1:  61 */    0x6F /* 'o' */, 0x07, 0x00  /* (to 0x00F8 state  62) */,
+                       0x61 /* 'a' */, 0x1A, 0x01  /* (to 0x020E state 250) */,
+                       0x08, /* fail */
+/* pos 00f8:  62 */    0xE4 /* 'd' -> */,
+/* pos 00f9:  63 */    0xE9 /* 'i' -> */,
+/* pos 00fa:  64 */    0xE6 /* 'f' -> */,
+/* pos 00fb:  65 */    0xE9 /* 'i' -> */,
+/* pos 00fc:  66 */    0xE5 /* 'e' -> */,
+/* pos 00fd:  67 */    0xE4 /* 'd' -> */,
+/* pos 00fe:  68 */    0xAD /* '-' -> */,
+/* pos 00ff:  69 */    0xF3 /* 's' -> */,
+/* pos 0100:  70 */    0xE9 /* 'i' -> */,
+/* pos 0101:  71 */    0xEE /* 'n' -> */,
+/* pos 0102:  72 */    0xE3 /* 'c' -> */,
+/* pos 0103:  73 */    0xE5 /* 'e' -> */,
+/* pos 0104:  74 */    0xBA /* ':' -> */,
+/* pos 0105:  75 */    0x00, 0x13                  /* - terminal marker 19 - */,
+/* pos 0107:  76 */    0xEF /* 'o' -> */,
+/* pos 0108:  77 */    0xEE /* 'n' -> */,
+/* pos 0109:  78 */    0xE5 /* 'e' -> */,
+/* pos 010a:  79 */    0xAD /* '-' -> */,
+/* pos 010b:  80 */    0xED /* 'm' -> */,
+/* pos 010c:  81 */    0xE1 /* 'a' -> */,
+/* pos 010d:  82 */    0xF4 /* 't' -> */,
+/* pos 010e:  83 */    0xE3 /* 'c' -> */,
+/* pos 010f:  84 */    0xE8 /* 'h' -> */,
+/* pos 0110:  85 */    0xBA /* ':' -> */,
+/* pos 0111:  86 */    0x00, 0x14                  /* - terminal marker 20 - */,
+/* pos 0113:  87 */    0x65 /* 'e' */, 0x0D, 0x00  /* (to 0x0120 state  88) */,
+                       0x6C /* 'l' */, 0x14, 0x00  /* (to 0x012A state  97) */,
+                       0x72 /* 'r' */, 0x8E, 0x00  /* (to 0x01A7 state 171) */,
+                       0x63 /* 'c' */, 0x14, 0x02  /* (to 0x0330 state 453) */,
+                       0x08, /* fail */
+/* pos 0120:  88 */    0xEE /* 'n' -> */,
+/* pos 0121:  89 */    0xE3 /* 'c' -> */,
+/* pos 0122:  90 */    0xEF /* 'o' -> */,
+/* pos 0123:  91 */    0xE4 /* 'd' -> */,
+/* pos 0124:  92 */    0xE9 /* 'i' -> */,
+/* pos 0125:  93 */    0xEE /* 'n' -> */,
+/* pos 0126:  94 */    0xE7 /* 'g' -> */,
+/* pos 0127:  95 */    0xBA /* ':' -> */,
+/* pos 0128:  96 */    0x00, 0x15                  /* - terminal marker 21 - */,
+/* pos 012a:  97 */    0xE1 /* 'a' -> */,
+/* pos 012b:  98 */    0xEE /* 'n' -> */,
+/* pos 012c:  99 */    0xE7 /* 'g' -> */,
+/* pos 012d: 100 */    0xF5 /* 'u' -> */,
+/* pos 012e: 101 */    0xE1 /* 'a' -> */,
+/* pos 012f: 102 */    0xE7 /* 'g' -> */,
+/* pos 0130: 103 */    0xE5 /* 'e' -> */,
+/* pos 0131: 104 */    0xBA /* ':' -> */,
+/* pos 0132: 105 */    0x00, 0x16                  /* - terminal marker 22 - */,
+/* pos 0134: 106 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x013B state 107) */,
+                       0x6F /* 'o' */, 0x1E, 0x02  /* (to 0x0355 state 487) */,
+                       0x08, /* fail */
+/* pos 013b: 107 */    0xE7 /* 'g' -> */,
+/* pos 013c: 108 */    0xED /* 'm' -> */,
+/* pos 013d: 109 */    0xE1 /* 'a' -> */,
+/* pos 013e: 110 */    0xBA /* ':' -> */,
+/* pos 013f: 111 */    0x00, 0x17                  /* - terminal marker 23 - */,
+/* pos 0141: 112 */    0xE3 /* 'c' -> */,
+/* pos 0142: 113 */    0xE8 /* 'h' -> */,
+/* pos 0143: 114 */    0xE5 /* 'e' -> */,
+/* pos 0144: 115 */    0xAD /* '-' -> */,
+/* pos 0145: 116 */    0xE3 /* 'c' -> */,
+/* pos 0146: 117 */    0xEF /* 'o' -> */,
+/* pos 0147: 118 */    0xEE /* 'n' -> */,
+/* pos 0148: 119 */    0xF4 /* 't' -> */,
+/* pos 0149: 120 */    0xF2 /* 'r' -> */,
+/* pos 014a: 121 */    0xEF /* 'o' -> */,
+/* pos 014b: 122 */    0xEC /* 'l' -> */,
+/* pos 014c: 123 */    0xBA /* ':' -> */,
+/* pos 014d: 124 */    0x00, 0x18                  /* - terminal marker 24 - */,
+/* pos 014f: 125 */    0xF4 /* 't' -> */,
+/* pos 0150: 126 */    0xE8 /* 'h' -> */,
+/* pos 0151: 127 */    0xEF /* 'o' -> */,
+/* pos 0152: 128 */    0xF2 /* 'r' -> */,
+/* pos 0153: 129 */    0xE9 /* 'i' -> */,
+/* pos 0154: 130 */    0xFA /* 'z' -> */,
+/* pos 0155: 131 */    0xE1 /* 'a' -> */,
+/* pos 0156: 132 */    0xF4 /* 't' -> */,
+/* pos 0157: 133 */    0xE9 /* 'i' -> */,
+/* pos 0158: 134 */    0xEF /* 'o' -> */,
+/* pos 0159: 135 */    0xEE /* 'n' -> */,
+/* pos 015a: 136 */    0xBA /* ':' -> */,
+/* pos 015b: 137 */    0x00, 0x19                  /* - terminal marker 25 - */,
+/* pos 015d: 138 */    0xEB /* 'k' -> */,
+/* pos 015e: 139 */    0xE9 /* 'i' -> */,
+/* pos 015f: 140 */    0xE5 /* 'e' -> */,
+/* pos 0160: 141 */    0xBA /* ':' -> */,
+/* pos 0161: 142 */    0x00, 0x1A                  /* - terminal marker 26 - */,
+/* pos 0163: 143 */    0xE5 /* 'e' -> */,
+/* pos 0164: 144 */    0xEE /* 'n' -> */,
+/* pos 0165: 145 */    0xF4 /* 't' -> */,
+/* pos 0166: 146 */    0xAD /* '-' -> */,
+/* pos 0167: 147 */    0x6C /* 'l' */, 0x10, 0x00  /* (to 0x0177 state 148) */,
+                       0x74 /* 't' */, 0x1E, 0x00  /* (to 0x0188 state 155) */,
+                       0x64 /* 'd' */, 0x4C, 0x00  /* (to 0x01B9 state 186) */,
+                       0x65 /* 'e' */, 0x56, 0x00  /* (to 0x01C6 state 198) */,
+                       0x72 /* 'r' */, 0x6F, 0x00  /* (to 0x01E2 state 223) */,
+                       0x08, /* fail */
+/* pos 0177: 148 */    0x65 /* 'e' */, 0x0A, 0x00  /* (to 0x0181 state 149) */,
+                       0x61 /* 'a' */, 0x56, 0x00  /* (to 0x01D0 state 207) */,
+                       0x6F /* 'o' */, 0x5C, 0x00  /* (to 0x01D9 state 215) */,
+                       0x08, /* fail */
+/* pos 0181: 149 */    0xEE /* 'n' -> */,
+/* pos 0182: 150 */    0xE7 /* 'g' -> */,
+/* pos 0183: 151 */    0xF4 /* 't' -> */,
+/* pos 0184: 152 */    0xE8 /* 'h' -> */,
+/* pos 0185: 153 */    0xBA /* ':' -> */,
+/* pos 0186: 154 */    0x00, 0x1B                  /* - terminal marker 27 - */,
+/* pos 0188: 155 */    0xF9 /* 'y' -> */,
+/* pos 0189: 156 */    0xF0 /* 'p' -> */,
+/* pos 018a: 157 */    0xE5 /* 'e' -> */,
+/* pos 018b: 158 */    0xBA /* ':' -> */,
+/* pos 018c: 159 */    0x00, 0x1C                  /* - terminal marker 28 - */,
+/* pos 018e: 160 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0195 state 161) */,
+                       0x65 /* 'e' */, 0x3C, 0x02  /* (to 0x03CD state 580) */,
+                       0x08, /* fail */
+/* pos 0195: 161 */    0xF4 /* 't' -> */,
+/* pos 0196: 162 */    0xE5 /* 'e' -> */,
+/* pos 0197: 163 */    0xBA /* ':' -> */,
+/* pos 0198: 164 */    0x00, 0x1D                  /* - terminal marker 29 - */,
+/* pos 019a: 165 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x01A1 state 166) */,
+                       0x65 /* 'e' */, 0xB6, 0x00  /* (to 0x0253 state 304) */,
+                       0x08, /* fail */
+/* pos 01a1: 166 */    0xEE /* 'n' -> */,
+/* pos 01a2: 167 */    0xE7 /* 'g' -> */,
+/* pos 01a3: 168 */    0xE5 /* 'e' -> */,
+/* pos 01a4: 169 */    0xBA /* ':' -> */,
+/* pos 01a5: 170 */    0x00, 0x1E                  /* - terminal marker 30 - */,
+/* pos 01a7: 171 */    0xE1 /* 'a' -> */,
+/* pos 01a8: 172 */    0xEE /* 'n' -> */,
+/* pos 01a9: 173 */    0xE7 /* 'g' -> */,
+/* pos 01aa: 174 */    0xE5 /* 'e' -> */,
+/* pos 01ab: 175 */    0xF3 /* 's' -> */,
+/* pos 01ac: 176 */    0xBA /* ':' -> */,
+/* pos 01ad: 177 */    0x00, 0x29                  /* - terminal marker 41 - */,
+/* pos 01af: 178 */    0xE5 /* 'e' -> */,
+/* pos 01b0: 179 */    0xBA /* ':' -> */,
+/* pos 01b1: 180 */    0x00, 0x2B                  /* - terminal marker 43 - */,
+/* pos 01b3: 181 */    0xEC /* 'l' -> */,
+/* pos 01b4: 182 */    0xEF /* 'o' -> */,
+/* pos 01b5: 183 */    0xF7 /* 'w' -> */,
+/* pos 01b6: 184 */    0xBA /* ':' -> */,
+/* pos 01b7: 185 */    0x00, 0x2C                  /* - terminal marker 44 - */,
+/* pos 01b9: 186 */    0xE9 /* 'i' -> */,
+/* pos 01ba: 187 */    0xF3 /* 's' -> */,
+/* pos 01bb: 188 */    0xF0 /* 'p' -> */,
+/* pos 01bc: 189 */    0xEF /* 'o' -> */,
+/* pos 01bd: 190 */    0xF3 /* 's' -> */,
+/* pos 01be: 191 */    0xE9 /* 'i' -> */,
+/* pos 01bf: 192 */    0xF4 /* 't' -> */,
+/* pos 01c0: 193 */    0xE9 /* 'i' -> */,
+/* pos 01c1: 194 */    0xEF /* 'o' -> */,
+/* pos 01c2: 195 */    0xEE /* 'n' -> */,
+/* pos 01c3: 196 */    0xBA /* ':' -> */,
+/* pos 01c4: 197 */    0x00, 0x2D                  /* - terminal marker 45 - */,
+/* pos 01c6: 198 */    0xEE /* 'n' -> */,
+/* pos 01c7: 199 */    0xE3 /* 'c' -> */,
+/* pos 01c8: 200 */    0xEF /* 'o' -> */,
+/* pos 01c9: 201 */    0xE4 /* 'd' -> */,
+/* pos 01ca: 202 */    0xE9 /* 'i' -> */,
+/* pos 01cb: 203 */    0xEE /* 'n' -> */,
+/* pos 01cc: 204 */    0xE7 /* 'g' -> */,
+/* pos 01cd: 205 */    0xBA /* ':' -> */,
+/* pos 01ce: 206 */    0x00, 0x2E                  /* - terminal marker 46 - */,
+/* pos 01d0: 207 */    0xEE /* 'n' -> */,
+/* pos 01d1: 208 */    0xE7 /* 'g' -> */,
+/* pos 01d2: 209 */    0xF5 /* 'u' -> */,
+/* pos 01d3: 210 */    0xE1 /* 'a' -> */,
+/* pos 01d4: 211 */    0xE7 /* 'g' -> */,
+/* pos 01d5: 212 */    0xE5 /* 'e' -> */,
+/* pos 01d6: 213 */    0xBA /* ':' -> */,
+/* pos 01d7: 214 */    0x00, 0x2F                  /* - terminal marker 47 - */,
+/* pos 01d9: 215 */    0xE3 /* 'c' -> */,
+/* pos 01da: 216 */    0xE1 /* 'a' -> */,
+/* pos 01db: 217 */    0xF4 /* 't' -> */,
+/* pos 01dc: 218 */    0xE9 /* 'i' -> */,
+/* pos 01dd: 219 */    0xEF /* 'o' -> */,
+/* pos 01de: 220 */    0xEE /* 'n' -> */,
+/* pos 01df: 221 */    0xBA /* ':' -> */,
+/* pos 01e0: 222 */    0x00, 0x30                  /* - terminal marker 48 - */,
+/* pos 01e2: 223 */    0xE1 /* 'a' -> */,
+/* pos 01e3: 224 */    0xEE /* 'n' -> */,
+/* pos 01e4: 225 */    0xE7 /* 'g' -> */,
+/* pos 01e5: 226 */    0xE5 /* 'e' -> */,
+/* pos 01e6: 227 */    0xBA /* ':' -> */,
+/* pos 01e7: 228 */    0x00, 0x31                  /* - terminal marker 49 - */,
+/* pos 01e9: 229 */    0x74 /* 't' */, 0x07, 0x00  /* (to 0x01F0 state 230) */,
+                       0x78 /* 'x' */, 0x09, 0x00  /* (to 0x01F5 state 234) */,
+                       0x08, /* fail */
+/* pos 01f0: 230 */    0xE1 /* 'a' -> */,
+/* pos 01f1: 231 */    0xE7 /* 'g' -> */,
+/* pos 01f2: 232 */    0xBA /* ':' -> */,
+/* pos 01f3: 233 */    0x00, 0x32                  /* - terminal marker 50 - */,
+/* pos 01f5: 234 */    0xF0 /* 'p' -> */,
+/* pos 01f6: 235 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x01FD state 236) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x0202 state 240) */,
+                       0x08, /* fail */
+/* pos 01fd: 236 */    0xE3 /* 'c' -> */,
+/* pos 01fe: 237 */    0xF4 /* 't' -> */,
+/* pos 01ff: 238 */    0xBA /* ':' -> */,
+/* pos 0200: 239 */    0x00, 0x33                  /* - terminal marker 51 - */,
+/* pos 0202: 240 */    0xF2 /* 'r' -> */,
+/* pos 0203: 241 */    0xE5 /* 'e' -> */,
+/* pos 0204: 242 */    0xF3 /* 's' -> */,
+/* pos 0205: 243 */    0xBA /* ':' -> */,
+/* pos 0206: 244 */    0x00, 0x34                  /* - terminal marker 52 - */,
+/* pos 0208: 245 */    0xF2 /* 'r' -> */,
+/* pos 0209: 246 */    0xEF /* 'o' -> */,
+/* pos 020a: 247 */    0xED /* 'm' -> */,
+/* pos 020b: 248 */    0xBA /* ':' -> */,
+/* pos 020c: 249 */    0x00, 0x35                  /* - terminal marker 53 - */,
+/* pos 020e: 250 */    0xF4 /* 't' -> */,
+/* pos 020f: 251 */    0xE3 /* 'c' -> */,
+/* pos 0210: 252 */    0xE8 /* 'h' -> */,
+/* pos 0211: 253 */    0xBA /* ':' -> */,
+/* pos 0212: 254 */    0x00, 0x36                  /* - terminal marker 54 - */,
+/* pos 0214: 255 */    0xE1 /* 'a' -> */,
+/* pos 0215: 256 */    0xEE /* 'n' -> */,
+/* pos 0216: 257 */    0xE7 /* 'g' -> */,
+/* pos 0217: 258 */    0xE5 /* 'e' -> */,
+/* pos 0218: 259 */    0xBA /* ':' -> */,
+/* pos 0219: 260 */    0x00, 0x37                  /* - terminal marker 55 - */,
+/* pos 021b: 261 */    0xEE /* 'n' -> */,
+/* pos 021c: 262 */    0xED /* 'm' -> */,
+/* pos 021d: 263 */    0xEF /* 'o' -> */,
+/* pos 021e: 264 */    0xE4 /* 'd' -> */,
+/* pos 021f: 265 */    0xE9 /* 'i' -> */,
+/* pos 0220: 266 */    0xE6 /* 'f' -> */,
+/* pos 0221: 267 */    0xE9 /* 'i' -> */,
+/* pos 0222: 268 */    0xE5 /* 'e' -> */,
+/* pos 0223: 269 */    0xE4 /* 'd' -> */,
+/* pos 0224: 270 */    0xAD /* '-' -> */,
+/* pos 0225: 271 */    0xF3 /* 's' -> */,
+/* pos 0226: 272 */    0xE9 /* 'i' -> */,
+/* pos 0227: 273 */    0xEE /* 'n' -> */,
+/* pos 0228: 274 */    0xE3 /* 'c' -> */,
+/* pos 0229: 275 */    0xE5 /* 'e' -> */,
+/* pos 022a: 276 */    0xBA /* ':' -> */,
+/* pos 022b: 277 */    0x00, 0x38                  /* - terminal marker 56 - */,
+/* pos 022d: 278 */    0x61 /* 'a' */, 0x0A, 0x00  /* (to 0x0237 state 279) */,
+                       0x69 /* 'i' */, 0x15, 0x00  /* (to 0x0245 state 292) */,
+                       0x6F /* 'o' */, 0x17, 0x00  /* (to 0x024A state 296) */,
+                       0x08, /* fail */
+/* pos 0237: 279 */    0xF3 /* 's' -> */,
+/* pos 0238: 280 */    0xF4 /* 't' -> */,
+/* pos 0239: 281 */    0xAD /* '-' -> */,
+/* pos 023a: 282 */    0xED /* 'm' -> */,
+/* pos 023b: 283 */    0xEF /* 'o' -> */,
+/* pos 023c: 284 */    0xE4 /* 'd' -> */,
+/* pos 023d: 285 */    0xE9 /* 'i' -> */,
+/* pos 023e: 286 */    0xE6 /* 'f' -> */,
+/* pos 023f: 287 */    0xE9 /* 'i' -> */,
+/* pos 0240: 288 */    0xE5 /* 'e' -> */,
+/* pos 0241: 289 */    0xE4 /* 'd' -> */,
+/* pos 0242: 290 */    0xBA /* ':' -> */,
+/* pos 0243: 291 */    0x00, 0x39                  /* - terminal marker 57 - */,
+/* pos 0245: 292 */    0xEE /* 'n' -> */,
+/* pos 0246: 293 */    0xEB /* 'k' -> */,
+/* pos 0247: 294 */    0xBA /* ':' -> */,
+/* pos 0248: 295 */    0x00, 0x3A                  /* - terminal marker 58 - */,
+/* pos 024a: 296 */    0xE3 /* 'c' -> */,
+/* pos 024b: 297 */    0xE1 /* 'a' -> */,
+/* pos 024c: 298 */    0xF4 /* 't' -> */,
+/* pos 024d: 299 */    0xE9 /* 'i' -> */,
+/* pos 024e: 300 */    0xEF /* 'o' -> */,
+/* pos 024f: 301 */    0xEE /* 'n' -> */,
+/* pos 0250: 302 */    0xBA /* ':' -> */,
+/* pos 0251: 303 */    0x00, 0x3B                  /* - terminal marker 59 - */,
+/* pos 0253: 304 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x025D state 305) */,
+                       0x74 /* 't' */, 0x14, 0x00  /* (to 0x026A state 311) */,
+                       0x70 /* 'p' */, 0x88, 0x01  /* (to 0x03E1 state 596) */,
+                       0x08, /* fail */
+/* pos 025d: 305 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0264 state 306) */,
+                       0x65 /* 'e' */, 0xCA, 0x00  /* (to 0x032A state 448) */,
+                       0x08, /* fail */
+/* pos 0264: 306 */    0xE5 /* 'e' -> */,
+/* pos 0265: 307 */    0xF3 /* 's' -> */,
+/* pos 0266: 308 */    0xE8 /* 'h' -> */,
+/* pos 0267: 309 */    0xBA /* ':' -> */,
+/* pos 0268: 310 */    0x00, 0x3F                  /* - terminal marker 63 - */,
+/* pos 026a: 311 */    0xF2 /* 'r' -> */,
+/* pos 026b: 312 */    0xF9 /* 'y' -> */,
+/* pos 026c: 313 */    0xAD /* '-' -> */,
+/* pos 026d: 314 */    0xE1 /* 'a' -> */,
+/* pos 026e: 315 */    0xE6 /* 'f' -> */,
+/* pos 026f: 316 */    0xF4 /* 't' -> */,
+/* pos 0270: 317 */    0xE5 /* 'e' -> */,
+/* pos 0271: 318 */    0xF2 /* 'r' -> */,
+/* pos 0272: 319 */    0xBA /* ':' -> */,
+/* pos 0273: 320 */    0x00, 0x40                  /* - terminal marker 64 - */,
+/* pos 0275: 321 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x027C state 322) */,
+                       0x74 /* 't' */, 0x06, 0x01  /* (to 0x037E state 514) */,
+                       0x08, /* fail */
+/* pos 027c: 322 */    0x72 /* 'r' */, 0x0A, 0x00  /* (to 0x0286 state 323) */,
+                       0x74 /* 't' */, 0x0D, 0x00  /* (to 0x028C state 328) */,
+                       0x63 /* 'c' */, 0x6B, 0x01  /* (to 0x03ED state 607) */,
+                       0x08, /* fail */
+/* pos 0286: 323 */    0xF6 /* 'v' -> */,
+/* pos 0287: 324 */    0xE5 /* 'e' -> */,
+/* pos 0288: 325 */    0xF2 /* 'r' -> */,
+/* pos 0289: 326 */    0xBA /* ':' -> */,
+/* pos 028a: 327 */    0x00, 0x41                  /* - terminal marker 65 - */,
+/* pos 028c: 328 */    0xAD /* '-' -> */,
+/* pos 028d: 329 */    0xE3 /* 'c' -> */,
+/* pos 028e: 330 */    0xEF /* 'o' -> */,
+/* pos 028f: 331 */    0xEF /* 'o' -> */,
+/* pos 0290: 332 */    0xEB /* 'k' -> */,
+/* pos 0291: 333 */    0xE9 /* 'i' -> */,
+/* pos 0292: 334 */    0xE5 /* 'e' -> */,
+/* pos 0293: 335 */    0xBA /* ':' -> */,
+/* pos 0294: 336 */    0x00, 0x42                  /* - terminal marker 66 - */,
+/* pos 0296: 337 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x029D state 338) */,
+                       0x65 /* 'e' */, 0x45, 0x01  /* (to 0x03DE state 594) */,
+                       0x08, /* fail */
+/* pos 029d: 338 */    0xE1 /* 'a' -> */,
+/* pos 029e: 339 */    0xEE /* 'n' -> */,
+/* pos 029f: 340 */    0xF3 /* 's' -> */,
+/* pos 02a0: 341 */    0xE6 /* 'f' -> */,
+/* pos 02a1: 342 */    0xE5 /* 'e' -> */,
+/* pos 02a2: 343 */    0xF2 /* 'r' -> */,
+/* pos 02a3: 344 */    0xAD /* '-' -> */,
+/* pos 02a4: 345 */    0xE5 /* 'e' -> */,
+/* pos 02a5: 346 */    0xEE /* 'n' -> */,
+/* pos 02a6: 347 */    0xE3 /* 'c' -> */,
+/* pos 02a7: 348 */    0xEF /* 'o' -> */,
+/* pos 02a8: 349 */    0xE4 /* 'd' -> */,
+/* pos 02a9: 350 */    0xE9 /* 'i' -> */,
+/* pos 02aa: 351 */    0xEE /* 'n' -> */,
+/* pos 02ab: 352 */    0xE7 /* 'g' -> */,
+/* pos 02ac: 353 */    0xBA /* ':' -> */,
+/* pos 02ad: 354 */    0x00, 0x44                  /* - terminal marker 68 - */,
+/* pos 02af: 355 */    0xE9 /* 'i' -> */,
+/* pos 02b0: 356 */    0xAD /* '-' -> */,
+/* pos 02b1: 357 */    0xE1 /* 'a' -> */,
+/* pos 02b2: 358 */    0xF2 /* 'r' -> */,
+/* pos 02b3: 359 */    0xE7 /* 'g' -> */,
+/* pos 02b4: 360 */    0xF3 /* 's' -> */,
+/* pos 02b5: 361 */    0x00, 0x4C                  /* - terminal marker 76 - */,
+/* pos 02b7: 362 */    0xA0 /* ' ' -> */,
+/* pos 02b8: 363 */    0x00, 0x4F                  /* - terminal marker 79 - */,
+/* pos 02ba: 364 */    0xAD /* '-' -> */,
+/* pos 02bb: 365 */    0x66 /* 'f' */, 0x0A, 0x00  /* (to 0x02C5 state 366) */,
+                       0x61 /* 'a' */, 0x1D, 0x00  /* (to 0x02DB state 385) */,
+                       0x72 /* 'r' */, 0x14, 0x01  /* (to 0x03D5 state 586) */,
+                       0x08, /* fail */
+/* pos 02c5: 366 */    0xEF /* 'o' -> */,
+/* pos 02c6: 367 */    0xF2 /* 'r' -> */,
+/* pos 02c7: 368 */    0xF7 /* 'w' -> */,
+/* pos 02c8: 369 */    0xE1 /* 'a' -> */,
+/* pos 02c9: 370 */    0xF2 /* 'r' -> */,
+/* pos 02ca: 371 */    0xE4 /* 'd' -> */,
+/* pos 02cb: 372 */    0xE5 /* 'e' -> */,
+/* pos 02cc: 373 */    0xE4 /* 'd' -> */,
+/* pos 02cd: 374 */    0xAD /* '-' -> */,
+/* pos 02ce: 375 */    0xE6 /* 'f' -> */,
+/* pos 02cf: 376 */    0xEF /* 'o' -> */,
+/* pos 02d0: 377 */    0xF2 /* 'r' -> */,
+/* pos 02d1: 378 */    0xBA /* ':' -> */,
+/* pos 02d2: 379 */    0x00, 0x50                  /* - terminal marker 80 - */,
+/* pos 02d4: 380 */    0x00, 0x51                  /* - terminal marker 81 - */,
+/* pos 02d6: 381 */    0xE1 /* 'a' -> */,
+/* pos 02d7: 382 */    0xE4 /* 'd' -> */,
+/* pos 02d8: 383 */    0xA0 /* ' ' -> */,
+/* pos 02d9: 384 */    0x00, 0x52                  /* - terminal marker 82 - */,
+/* pos 02db: 385 */    0x75 /* 'u' */, 0x07, 0x00  /* (to 0x02E2 state 386) */,
+                       0x6D /* 'm' */, 0x0F, 0x00  /* (to 0x02ED state 396) */,
+                       0x08, /* fail */
+/* pos 02e2: 386 */    0xF4 /* 't' -> */,
+/* pos 02e3: 387 */    0xE8 /* 'h' -> */,
+/* pos 02e4: 388 */    0xAD /* '-' -> */,
+/* pos 02e5: 389 */    0xF4 /* 't' -> */,
+/* pos 02e6: 390 */    0xEF /* 'o' -> */,
+/* pos 02e7: 391 */    0xEB /* 'k' -> */,
+/* pos 02e8: 392 */    0xE5 /* 'e' -> */,
+/* pos 02e9: 393 */    0xEE /* 'n' -> */,
+/* pos 02ea: 394 */    0xBA /* ':' -> */,
+/* pos 02eb: 395 */    0x00, 0x56                  /* - terminal marker 86 - */,
+/* pos 02ed: 396 */    0xFA /* 'z' -> */,
+/* pos 02ee: 397 */    0xEE /* 'n' -> */,
+/* pos 02ef: 398 */    0xAD /* '-' -> */,
+/* pos 02f0: 399 */    0xE4 /* 'd' -> */,
+/* pos 02f1: 400 */    0xF3 /* 's' -> */,
+/* pos 02f2: 401 */    0xF3 /* 's' -> */,
+/* pos 02f3: 402 */    0xAD /* '-' -> */,
+/* pos 02f4: 403 */    0xF3 /* 's' -> */,
+/* pos 02f5: 404 */    0xE9 /* 'i' -> */,
+/* pos 02f6: 405 */    0xE7 /* 'g' -> */,
+/* pos 02f7: 406 */    0xEE /* 'n' -> */,
+/* pos 02f8: 407 */    0xE1 /* 'a' -> */,
+/* pos 02f9: 408 */    0xF4 /* 't' -> */,
+/* pos 02fa: 409 */    0xF5 /* 'u' -> */,
+/* pos 02fb: 410 */    0xF2 /* 'r' -> */,
+/* pos 02fc: 411 */    0xE5 /* 'e' -> */,
+/* pos 02fd: 412 */    0xBA /* ':' -> */,
+/* pos 02fe: 413 */    0x00, 0x57                  /* - terminal marker 87 - */,
+/* pos 0300: 414 */    0xF4 /* 't' -> */,
+/* pos 0301: 415 */    0xE9 /* 'i' -> */,
+/* pos 0302: 416 */    0xEF /* 'o' -> */,
+/* pos 0303: 417 */    0xEE /* 'n' -> */,
+/* pos 0304: 418 */    0xF3 /* 's' -> */,
+/* pos 0305: 419 */    0xA0 /* ' ' -> */,
+/* pos 0306: 420 */    0x00, 0x02                  /* - terminal marker  2 - */,
+/* pos 0308: 421 */    0xF3 /* 's' -> */,
+/* pos 0309: 422 */    0xAD /* '-' -> */,
+/* pos 030a: 423 */    0xE3 /* 'c' -> */,
+/* pos 030b: 424 */    0xEF /* 'o' -> */,
+/* pos 030c: 425 */    0xEE /* 'n' -> */,
+/* pos 030d: 426 */    0xF4 /* 't' -> */,
+/* pos 030e: 427 */    0xF2 /* 'r' -> */,
+/* pos 030f: 428 */    0xEF /* 'o' -> */,
+/* pos 0310: 429 */    0xEC /* 'l' -> */,
+/* pos 0311: 430 */    0xAD /* '-' -> */,
+/* pos 0312: 431 */    0x72 /* 'r' */, 0x07, 0x00  /* (to 0x0319 state 432) */,
+                       0x61 /* 'a' */, 0x24, 0x00  /* (to 0x0339 state 461) */,
+                       0x08, /* fail */
+/* pos 0319: 432 */    0xE5 /* 'e' -> */,
+/* pos 031a: 433 */    0xF1 /* 'q' -> */,
+/* pos 031b: 434 */    0xF5 /* 'u' -> */,
+/* pos 031c: 435 */    0xE5 /* 'e' -> */,
+/* pos 031d: 436 */    0xF3 /* 's' -> */,
+/* pos 031e: 437 */    0xF4 /* 't' -> */,
+/* pos 031f: 438 */    0xAD /* '-' -> */,
+/* pos 0320: 439 */    0xE8 /* 'h' -> */,
+/* pos 0321: 440 */    0xE5 /* 'e' -> */,
+/* pos 0322: 441 */    0xE1 /* 'a' -> */,
+/* pos 0323: 442 */    0xE4 /* 'd' -> */,
+/* pos 0324: 443 */    0xE5 /* 'e' -> */,
+/* pos 0325: 444 */    0xF2 /* 'r' -> */,
+/* pos 0326: 445 */    0xF3 /* 's' -> */,
+/* pos 0327: 446 */    0xBA /* ':' -> */,
+/* pos 0328: 447 */    0x00, 0x12                  /* - terminal marker 18 - */,
+/* pos 032a: 448 */    0xF2 /* 'r' -> */,
+/* pos 032b: 449 */    0xE5 /* 'e' -> */,
+/* pos 032c: 450 */    0xF2 /* 'r' -> */,
+/* pos 032d: 451 */    0xBA /* ':' -> */,
+/* pos 032e: 452 */    0x00, 0x1F                  /* - terminal marker 31 - */,
+/* pos 0330: 453 */    0xE8 /* 'h' -> */,
+/* pos 0331: 454 */    0xE1 /* 'a' -> */,
+/* pos 0332: 455 */    0xF2 /* 'r' -> */,
+/* pos 0333: 456 */    0xF3 /* 's' -> */,
+/* pos 0334: 457 */    0xE5 /* 'e' -> */,
+/* pos 0335: 458 */    0xF4 /* 't' -> */,
+/* pos 0336: 459 */    0xBA /* ':' -> */,
+/* pos 0337: 460 */    0x00, 0x28                  /* - terminal marker 40 - */,
+/* pos 0339: 461 */    0xEC /* 'l' -> */,
+/* pos 033a: 462 */    0xEC /* 'l' -> */,
+/* pos 033b: 463 */    0xEF /* 'o' -> */,
+/* pos 033c: 464 */    0xF7 /* 'w' -> */,
+/* pos 033d: 465 */    0xAD /* '-' -> */,
+/* pos 033e: 466 */    0xEF /* 'o' -> */,
+/* pos 033f: 467 */    0xF2 /* 'r' -> */,
+/* pos 0340: 468 */    0xE9 /* 'i' -> */,
+/* pos 0341: 469 */    0xE7 /* 'g' -> */,
+/* pos 0342: 470 */    0xE9 /* 'i' -> */,
+/* pos 0343: 471 */    0xEE /* 'n' -> */,
+/* pos 0344: 472 */    0xBA /* ':' -> */,
+/* pos 0345: 473 */    0x00, 0x2A                  /* - terminal marker 42 - */,
+/* pos 0347: 474 */    0xE1 /* 'a' -> */,
+/* pos 0348: 475 */    0xF8 /* 'x' -> */,
+/* pos 0349: 476 */    0xAD /* '-' -> */,
+/* pos 034a: 477 */    0xE6 /* 'f' -> */,
+/* pos 034b: 478 */    0xEF /* 'o' -> */,
+/* pos 034c: 479 */    0xF2 /* 'r' -> */,
+/* pos 034d: 480 */    0xF7 /* 'w' -> */,
+/* pos 034e: 481 */    0xE1 /* 'a' -> */,
+/* pos 034f: 482 */    0xF2 /* 'r' -> */,
+/* pos 0350: 483 */    0xE4 /* 'd' -> */,
+/* pos 0351: 484 */    0xF3 /* 's' -> */,
+/* pos 0352: 485 */    0xBA /* ':' -> */,
+/* pos 0353: 486 */    0x00, 0x3C                  /* - terminal marker 60 - */,
+/* pos 0355: 487 */    0xF8 /* 'x' -> */,
+/* pos 0356: 488 */    0xF9 /* 'y' -> */,
+/* pos 0357: 489 */    0x2D /* '-' */, 0x07, 0x00  /* (to 0x035E state 490) */,
+                       0x20 /* ' ' */, 0x79, 0x00  /* (to 0x03D3 state 585) */,
+                       0x08, /* fail */
+/* pos 035e: 490 */    0xE1 /* 'a' -> */,
+/* pos 035f: 491 */    0xF5 /* 'u' -> */,
+/* pos 0360: 492 */    0xF4 /* 't' -> */,
+/* pos 0361: 493 */    0xE8 /* 'h' -> */,
+/* pos 0362: 494 */    0x65 /* 'e' */, 0x07, 0x00  /* (to 0x0369 state 495) */,
+                       0x6F /* 'o' */, 0x0E, 0x00  /* (to 0x0373 state 504) */,
+                       0x08, /* fail */
+/* pos 0369: 495 */    0xEE /* 'n' -> */,
+/* pos 036a: 496 */    0xF4 /* 't' -> */,
+/* pos 036b: 497 */    0xE9 /* 'i' -> */,
+/* pos 036c: 498 */    0xE3 /* 'c' -> */,
+/* pos 036d: 499 */    0xE1 /* 'a' -> */,
+/* pos 036e: 500 */    0xF4 /* 't' -> */,
+/* pos 036f: 501 */    0xE5 /* 'e' -> */,
+/* pos 0370: 502 */    0xBA /* ':' -> */,
+/* pos 0371: 503 */    0x00, 0x3D                  /* - terminal marker 61 - */,
+/* pos 0373: 504 */    0xF2 /* 'r' -> */,
+/* pos 0374: 505 */    0xE9 /* 'i' -> */,
+/* pos 0375: 506 */    0xFA /* 'z' -> */,
+/* pos 0376: 507 */    0xE1 /* 'a' -> */,
+/* pos 0377: 508 */    0xF4 /* 't' -> */,
+/* pos 0378: 509 */    0xE9 /* 'i' -> */,
+/* pos 0379: 510 */    0xEF /* 'o' -> */,
+/* pos 037a: 511 */    0xEE /* 'n' -> */,
+/* pos 037b: 512 */    0xBA /* ':' -> */,
+/* pos 037c: 513 */    0x00, 0x3E                  /* - terminal marker 62 - */,
+/* pos 037e: 514 */    0xF2 /* 'r' -> */,
+/* pos 037f: 515 */    0xE9 /* 'i' -> */,
+/* pos 0380: 516 */    0xE3 /* 'c' -> */,
+/* pos 0381: 517 */    0xF4 /* 't' -> */,
+/* pos 0382: 518 */    0xAD /* '-' -> */,
+/* pos 0383: 519 */    0xF4 /* 't' -> */,
+/* pos 0384: 520 */    0xF2 /* 'r' -> */,
+/* pos 0385: 521 */    0xE1 /* 'a' -> */,
+/* pos 0386: 522 */    0xEE /* 'n' -> */,
+/* pos 0387: 523 */    0xF3 /* 's' -> */,
+/* pos 0388: 524 */    0xF0 /* 'p' -> */,
+/* pos 0389: 525 */    0xEF /* 'o' -> */,
+/* pos 038a: 526 */    0xF2 /* 'r' -> */,
+/* pos 038b: 527 */    0xF4 /* 't' -> */,
+/* pos 038c: 528 */    0xAD /* '-' -> */,
+/* pos 038d: 529 */    0xF3 /* 's' -> */,
+/* pos 038e: 530 */    0xE5 /* 'e' -> */,
+/* pos 038f: 531 */    0xE3 /* 'c' -> */,
+/* pos 0390: 532 */    0xF5 /* 'u' -> */,
+/* pos 0391: 533 */    0xF2 /* 'r' -> */,
+/* pos 0392: 534 */    0xE9 /* 'i' -> */,
+/* pos 0393: 535 */    0xF4 /* 't' -> */,
+/* pos 0394: 536 */    0xF9 /* 'y' -> */,
+/* pos 0395: 537 */    0xBA /* ':' -> */,
+/* pos 0396: 538 */    0x00, 0x43                  /* - terminal marker 67 - */,
+/* pos 0398: 539 */    0xE5 /* 'e' -> */,
+/* pos 0399: 540 */    0xF2 /* 'r' -> */,
+/* pos 039a: 541 */    0xAD /* '-' -> */,
+/* pos 039b: 542 */    0xE1 /* 'a' -> */,
+/* pos 039c: 543 */    0xE7 /* 'g' -> */,
+/* pos 039d: 544 */    0xE5 /* 'e' -> */,
+/* pos 039e: 545 */    0xEE /* 'n' -> */,
+/* pos 039f: 546 */    0xF4 /* 't' -> */,
+/* pos 03a0: 547 */    0xBA /* ':' -> */,
+/* pos 03a1: 548 */    0x00, 0x45                  /* - terminal marker 69 - */,
+/* pos 03a3: 549 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x03AA state 550) */,
+                       0x69 /* 'i' */, 0x09, 0x00  /* (to 0x03AF state 554) */,
+                       0x08, /* fail */
+/* pos 03aa: 550 */    0xF2 /* 'r' -> */,
+/* pos 03ab: 551 */    0xF9 /* 'y' -> */,
+/* pos 03ac: 552 */    0xBA /* ':' -> */,
+/* pos 03ad: 553 */    0x00, 0x46                  /* - terminal marker 70 - */,
+/* pos 03af: 554 */    0xE1 /* 'a' -> */,
+/* pos 03b0: 555 */    0xBA /* ':' -> */,
+/* pos 03b1: 556 */    0x00, 0x47                  /* - terminal marker 71 - */,
+/* pos 03b3: 557 */    0xF7 /* 'w' -> */,
+/* pos 03b4: 558 */    0xF7 /* 'w' -> */,
+/* pos 03b5: 559 */    0xAD /* '-' -> */,
+/* pos 03b6: 560 */    0xE1 /* 'a' -> */,
+/* pos 03b7: 561 */    0xF5 /* 'u' -> */,
+/* pos 03b8: 562 */    0xF4 /* 't' -> */,
+/* pos 03b9: 563 */    0xE8 /* 'h' -> */,
+/* pos 03ba: 564 */    0xE5 /* 'e' -> */,
+/* pos 03bb: 565 */    0xEE /* 'n' -> */,
+/* pos 03bc: 566 */    0xF4 /* 't' -> */,
+/* pos 03bd: 567 */    0xE9 /* 'i' -> */,
+/* pos 03be: 568 */    0xE3 /* 'c' -> */,
+/* pos 03bf: 569 */    0xE1 /* 'a' -> */,
+/* pos 03c0: 570 */    0xF4 /* 't' -> */,
+/* pos 03c1: 571 */    0xE5 /* 'e' -> */,
+/* pos 03c2: 572 */    0xBA /* ':' -> */,
+/* pos 03c3: 573 */    0x00, 0x48                  /* - terminal marker 72 - */,
+/* pos 03c5: 574 */    0xF4 /* 't' -> */,
+/* pos 03c6: 575 */    0xE3 /* 'c' -> */,
+/* pos 03c7: 576 */    0xE8 /* 'h' -> */,
+/* pos 03c8: 577 */    0x00, 0x49                  /* - terminal marker 73 - */,
+/* pos 03ca: 578 */    0xF4 /* 't' -> */,
+/* pos 03cb: 579 */    0x00, 0x4A                  /* - terminal marker 74 - */,
+/* pos 03cd: 580 */    0xEC /* 'l' -> */,
+/* pos 03ce: 581 */    0xE5 /* 'e' -> */,
+/* pos 03cf: 582 */    0xF4 /* 't' -> */,
+/* pos 03d0: 583 */    0xE5 /* 'e' -> */,
+/* pos 03d1: 584 */    0x00, 0x4B                  /* - terminal marker 75 - */,
+/* pos 03d3: 585 */    0x00, 0x4D                  /* - terminal marker 77 - */,
+/* pos 03d5: 586 */    0xE5 /* 'e' -> */,
+/* pos 03d6: 587 */    0xE1 /* 'a' -> */,
+/* pos 03d7: 588 */    0xEC /* 'l' -> */,
+/* pos 03d8: 589 */    0xAD /* '-' -> */,
+/* pos 03d9: 590 */    0xE9 /* 'i' -> */,
+/* pos 03da: 591 */    0xF0 /* 'p' -> */,
+/* pos 03db: 592 */    0xBA /* ':' -> */,
+/* pos 03dc: 593 */    0x00, 0x4E                  /* - terminal marker 78 - */,
+/* pos 03de: 594 */    0xBA /* ':' -> */,
+/* pos 03df: 595 */    0x00, 0x53                  /* - terminal marker 83 - */,
+/* pos 03e1: 596 */    0xEC /* 'l' -> */,
+/* pos 03e2: 597 */    0xE1 /* 'a' -> */,
+/* pos 03e3: 598 */    0xF9 /* 'y' -> */,
+/* pos 03e4: 599 */    0xAD /* '-' -> */,
+/* pos 03e5: 600 */    0xEE /* 'n' -> */,
+/* pos 03e6: 601 */    0xEF /* 'o' -> */,
+/* pos 03e7: 602 */    0xEE /* 'n' -> */,
+/* pos 03e8: 603 */    0xE3 /* 'c' -> */,
+/* pos 03e9: 604 */    0xE5 /* 'e' -> */,
+/* pos 03ea: 605 */    0xBA /* ':' -> */,
+/* pos 03eb: 606 */    0x00, 0x54                  /* - terminal marker 84 - */,
+/* pos 03ed: 607 */    0xAD /* '-' -> */,
+/* pos 03ee: 608 */    0xF7 /* 'w' -> */,
+/* pos 03ef: 609 */    0xE5 /* 'e' -> */,
+/* pos 03f0: 610 */    0xE2 /* 'b' -> */,
+/* pos 03f1: 611 */    0xF3 /* 's' -> */,
+/* pos 03f2: 612 */    0xEF /* 'o' -> */,
+/* pos 03f3: 613 */    0xE3 /* 'c' -> */,
+/* pos 03f4: 614 */    0xEB /* 'k' -> */,
+/* pos 03f5: 615 */    0xE5 /* 'e' -> */,
+/* pos 03f6: 616 */    0xF4 /* 't' -> */,
+/* pos 03f7: 617 */    0xAD /* '-' -> */,
+/* pos 03f8: 618 */    0x64 /* 'd' */, 0x19, 0x00  /* (to 0x0411 state 619) */,
+                       0x65 /* 'e' */, 0x1D, 0x00  /* (to 0x0418 state 625) */,
+                       0x6B /* 'k' */, 0x26, 0x00  /* (to 0x0424 state 636) */,
+                       0x70 /* 'p' */, 0x35, 0x00  /* (to 0x0436 state 643) */,
+                       0x61 /* 'a' */, 0x3C, 0x00  /* (to 0x0440 state 652) */,
+                       0x6E /* 'n' */, 0x41, 0x00  /* (to 0x0448 state 659) */,
+                       0x76 /* 'v' */, 0x47, 0x00  /* (to 0x0451 state 666) */,
+                       0x6F /* 'o' */, 0x4D, 0x00  /* (to 0x045A state 674) */,
+                       0x08, /* fail */
+/* pos 0411: 619 */    0xF2 /* 'r' -> */,
+/* pos 0412: 620 */    0xE1 /* 'a' -> */,
+/* pos 0413: 621 */    0xE6 /* 'f' -> */,
+/* pos 0414: 622 */    0xF4 /* 't' -> */,
+/* pos 0415: 623 */    0xBA /* ':' -> */,
+/* pos 0416: 624 */    0x00, 0x07                  /* - terminal marker  7 - */,
+/* pos 0418: 625 */    0xF8 /* 'x' -> */,
+/* pos 0419: 626 */    0xF4 /* 't' -> */,
+/* pos 041a: 627 */    0xE5 /* 'e' -> */,
+/* pos 041b: 628 */    0xEE /* 'n' -> */,
+/* pos 041c: 629 */    0xF3 /* 's' -> */,
+/* pos 041d: 630 */    0xE9 /* 'i' -> */,
+/* pos 041e: 631 */    0xEF /* 'o' -> */,
+/* pos 041f: 632 */    0xEE /* 'n' -> */,
+/* pos 0420: 633 */    0xF3 /* 's' -> */,
+/* pos 0421: 634 */    0xBA /* ':' -> */,
+/* pos 0422: 635 */    0x00, 0x09                  /* - terminal marker  9 - */,
+/* pos 0424: 636 */    0xE5 /* 'e' -> */,
+/* pos 0425: 637 */    0xF9 /* 'y' -> */,
+/* pos 0426: 638 */    0x31 /* '1' */, 0x0A, 0x00  /* (to 0x0430 state 639) */,
+                       0x32 /* '2' */, 0x0A, 0x00  /* (to 0x0433 state 641) */,
+                       0x3A /* ':' */, 0x23, 0x00  /* (to 0x044F state 665) */,
+                       0x08, /* fail */
+/* pos 0430: 639 */    0xBA /* ':' -> */,
+/* pos 0431: 640 */    0x00, 0x0A                  /* - terminal marker 10 - */,
+/* pos 0433: 641 */    0xBA /* ':' -> */,
+/* pos 0434: 642 */    0x00, 0x0B                  /* - terminal marker 11 - */,
+/* pos 0436: 643 */    0xF2 /* 'r' -> */,
+/* pos 0437: 644 */    0xEF /* 'o' -> */,
+/* pos 0438: 645 */    0xF4 /* 't' -> */,
+/* pos 0439: 646 */    0xEF /* 'o' -> */,
+/* pos 043a: 647 */    0xE3 /* 'c' -> */,
+/* pos 043b: 648 */    0xEF /* 'o' -> */,
+/* pos 043c: 649 */    0xEC /* 'l' -> */,
+/* pos 043d: 650 */    0xBA /* ':' -> */,
+/* pos 043e: 651 */    0x00, 0x0C                  /* - terminal marker 12 - */,
+/* pos 0440: 652 */    0xE3 /* 'c' -> */,
+/* pos 0441: 653 */    0xE3 /* 'c' -> */,
+/* pos 0442: 654 */    0xE5 /* 'e' -> */,
+/* pos 0443: 655 */    0xF0 /* 'p' -> */,
+/* pos 0444: 656 */    0xF4 /* 't' -> */,
+/* pos 0445: 657 */    0xBA /* ':' -> */,
+/* pos 0446: 658 */    0x00, 0x0D                  /* - terminal marker 13 - */,
+/* pos 0448: 659 */    0xEF /* 'o' -> */,
+/* pos 0449: 660 */    0xEE /* 'n' -> */,
+/* pos 044a: 661 */    0xE3 /* 'c' -> */,
+/* pos 044b: 662 */    0xE5 /* 'e' -> */,
+/* pos 044c: 663 */    0xBA /* ':' -> */,
+/* pos 044d: 664 */    0x00, 0x0E                  /* - terminal marker 14 - */,
+/* pos 044f: 665 */    0x00, 0x20                  /* - terminal marker 32 - */,
+/* pos 0451: 666 */    0xE5 /* 'e' -> */,
+/* pos 0452: 667 */    0xF2 /* 'r' -> */,
+/* pos 0453: 668 */    0xF3 /* 's' -> */,
+/* pos 0454: 669 */    0xE9 /* 'i' -> */,
+/* pos 0455: 670 */    0xEF /* 'o' -> */,
+/* pos 0456: 671 */    0xEE /* 'n' -> */,
+/* pos 0457: 672 */    0xBA /* ':' -> */,
+/* pos 0458: 673 */    0x00, 0x21                  /* - terminal marker 33 - */,
+/* pos 045a: 674 */    0xF2 /* 'r' -> */,
+/* pos 045b: 675 */    0xE9 /* 'i' -> */,
+/* pos 045c: 676 */    0xE7 /* 'g' -> */,
+/* pos 045d: 677 */    0xE9 /* 'i' -> */,
+/* pos 045e: 678 */    0xEE /* 'n' -> */,
+/* pos 045f: 679 */    0xBA /* ':' -> */,
+/* pos 0460: 680 */    0x00, 0x22                  /* - terminal marker 34 - */,
+/* pos 0462: 681 */    0xAD /* '-' -> */,
+/* pos 0463: 682 */    0xF3 /* 's' -> */,
+/* pos 0464: 683 */    0xE5 /* 'e' -> */,
+/* pos 0465: 684 */    0xF4 /* 't' -> */,
+/* pos 0466: 685 */    0xF4 /* 't' -> */,
+/* pos 0467: 686 */    0xE9 /* 'i' -> */,
+/* pos 0468: 687 */    0xEE /* 'n' -> */,
+/* pos 0469: 688 */    0xE7 /* 'g' -> */,
+/* pos 046a: 689 */    0xF3 /* 's' -> */,
+/* pos 046b: 690 */    0xBA /* ':' -> */,
+/* pos 046c: 691 */    0x00, 0x10                  /* - terminal marker 16 - */,
+/* pos 046e: 692 */    0x61 /* 'a' */, 0x0D, 0x00  /* (to 0x047B state 693) */,
+                       0x6D /* 'm' */, 0x14, 0x00  /* (to 0x0485 state 702) */,
+                       0x70 /* 'p' */, 0x18, 0x00  /* (to 0x048C state 708) */,
+                       0x73 /* 's' */, 0x20, 0x00  /* (to 0x0497 state 712) */,
+                       0x08, /* fail */
+/* pos 047b: 693 */    0xF5 /* 'u' -> */,
+/* pos 047c: 694 */    0xF4 /* 't' -> */,
+/* pos 047d: 695 */    0xE8 /* 'h' -> */,
+/* pos 047e: 696 */    0xEF /* 'o' -> */,
+/* pos 047f: 697 */    0xF2 /* 'r' -> */,
+/* pos 0480: 698 */    0xE9 /* 'i' -> */,
+/* pos 0481: 699 */    0xF4 /* 't' -> */,
+/* pos 0482: 700 */    0xF9 /* 'y' -> */,
+/* pos 0483: 701 */    0x00, 0x23                  /* - terminal marker 35 - */,
+/* pos 0485: 702 */    0xE5 /* 'e' -> */,
+/* pos 0486: 703 */    0xF4 /* 't' -> */,
+/* pos 0487: 704 */    0xE8 /* 'h' -> */,
+/* pos 0488: 705 */    0xEF /* 'o' -> */,
+/* pos 0489: 706 */    0xE4 /* 'd' -> */,
+/* pos 048a: 707 */    0x00, 0x24                  /* - terminal marker 36 - */,
+/* pos 048c: 708 */    0x61 /* 'a' */, 0x07, 0x00  /* (to 0x0493 state 709) */,
+                       0x72 /* 'r' */, 0x1B, 0x00  /* (to 0x04AA state 723) */,
+                       0x08, /* fail */
+/* pos 0493: 709 */    0xF4 /* 't' -> */,
+/* pos 0494: 710 */    0xE8 /* 'h' -> */,
+/* pos 0495: 711 */    0x00, 0x25                  /* - terminal marker 37 - */,
+/* pos 0497: 712 */    0x63 /* 'c' */, 0x07, 0x00  /* (to 0x049E state 713) */,
+                       0x74 /* 't' */, 0x0A, 0x00  /* (to 0x04A4 state 718) */,
+                       0x08, /* fail */
+/* pos 049e: 713 */    0xE8 /* 'h' -> */,
+/* pos 049f: 714 */    0xE5 /* 'e' -> */,
+/* pos 04a0: 715 */    0xED /* 'm' -> */,
+/* pos 04a1: 716 */    0xE5 /* 'e' -> */,
+/* pos 04a2: 717 */    0x00, 0x26                  /* - terminal marker 38 - */,
+/* pos 04a4: 718 */    0xE1 /* 'a' -> */,
+/* pos 04a5: 719 */    0xF4 /* 't' -> */,
+/* pos 04a6: 720 */    0xF5 /* 'u' -> */,
+/* pos 04a7: 721 */    0xF3 /* 's' -> */,
+/* pos 04a8: 722 */    0x00, 0x27                  /* - terminal marker 39 - */,
+/* pos 04aa: 723 */    0xEF /* 'o' -> */,
+/* pos 04ab: 724 */    0xF4 /* 't' -> */,
+/* pos 04ac: 725 */    0xEF /* 'o' -> */,
+/* pos 04ad: 726 */    0xE3 /* 'c' -> */,
+/* pos 04ae: 727 */    0xEF /* 'o' -> */,
+/* pos 04af: 728 */    0xEC /* 'l' -> */,
+/* pos 04b0: 729 */    0x00, 0x55                  /* - terminal marker 85 - */,
+/* total size 1202 bytes */
+#endif
+
+
+/*
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x03,0x00,0x80,0x0f,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) &&  defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x07,0x00,0x00,0x3e,0x00,0x00,0x00,0x80,0x03,0x09,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2)
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x03,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+#if defined(LWS_HTTP_HEADERS_ALL) || ( defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) &&  defined(LWS_ROLE_WS) &&  defined(LWS_ROLE_H2))
+static uint8_t lws_header_implies_psuedoheader_map[] = {
+       0x07,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x0e,0x24,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+*/
index 3cb1e33..f831529 100644 (file)
  *
  * High efficiency lexical state parser
  *
- * Copyright (C)2011-2014 Andy Green <andy@warmcat.com>
+ * Copyright (C)2011-2020 Andy Green <andy@warmcat.com>
  *
- * Licensed under LGPL2
+ * Licensed under MIT
  *
  * Usage: gcc minilex.c -o minilex && ./minilex > lextable.h
  *
  * Run it twice to test parsing on the generated table on stderr
+ *
+ * Whoo this got a bit complicated by lws-buildtime deselection of some
+ * headers optionally.  There are 3 x vars, UNCOMMON, WS, H2 so we make
+ * eight copies of the lextable selected by the appropriate #if defined()
  */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+/* get all the strings */
+
+#define LWS_ROLE_WS 1
+#define LWS_WITH_HTTP_UNCOMMON_HEADERS 1
+#define LWS_ROLE_H2 1
+
 #include "lextable-strings.h"
 
+#undef LWS_ROLE_WS
+#undef LWS_WITH_HTTP_UNCOMMON_HEADERS
+#undef LWS_ROLE_H2
+
+/* bitfield for the 8 versions as to which strings exist... index layout
+ *
+ *        b0      b1 b2
+ *  0 =
+ *  1 = uncommon
+ *  2 =           ws
+ *  3 = uncommon  ws
+ *  4 =              h2
+ *  5 = uncommon     h2
+ *  6 =           ws h2
+ *  7 = uncommon  ws h2
+ */
+
+unsigned char filter_array[] = {
+       0xff, /* get */
+       0xff, /* post */
+       0xaa, /* options */
+       0xff, /* host */
+       0xff, /* connection */
+       0xff, /* upgrade */
+       0xff, /* origin */
+       0xcc, /* sec-ws-draft */
+       0xff, /* crlf */
+       0xcc, /* sec-ws-ext */
+       0xcc, /* sec-ws-key1 */
+       0xcc, /* sec-ws-key2 */
+       0xcc, /* sec-ws-protocol */
+       0xcc, /* sec-ws-accept */
+       0xcc, /* sec-ws-nonce */
+       0xff, /* http/1.1 */
+       0xf0, /* http2-settings */
+       0xff, /* accept */
+       0xaa, /* access-control-req-hdrs */
+       0xff, /* if-modified-since */
+       0xff, /* if-none-match */
+       0xff, /* accept-encoding */
+       0xff, /* accept-language */
+       0xff, /* pragma */
+       0xff, /* cache-control */
+       0xff, /* authorization */
+       0xff, /* cookie */
+       0xff, /* content-length */
+       0xff, /* content-type */
+       0xff, /* date */
+       0xff, /* range */
+       0xfa, /* referer */
+       0xcc, /* sec-ws-key */
+       0xcc, /* sec-ws-version */
+       0xcc, /* sec-sc-origin */
+       0xf0, /* authority */
+       0xf0, /* method */
+       0xf0, /* path */
+       0xf0, /* scheme */
+       0xf0, /* status */
+       0xfa, /* accept-charset */
+       0xff, /* accept-ranges */
+       0xfa, /* access-control-allow-origin */
+       0xff, /* age */
+       0xff, /* allow */
+       0xff, /* content-disposition */
+       0xff, /* content-encoding */
+       0xff, /* content-language */
+       0xff, /* content-location */
+       0xff, /* content-range */
+       0xff, /* etag */
+       0xff, /* expect */
+       0xff, /* expires */
+       0xff, /* from */
+       0xff, /* if-match */
+       0xff, /* if-range */
+       0xff, /* if-unmodified-since */
+       0xff, /* last-modified */
+       0xff, /* link */
+       0xff, /* location */
+       0xfa, /* max-forwards */
+       0xfa, /* proxy-authenticate */
+       0xfa, /* proxy-authorization */
+       0xff, /* refresh */
+       0xff, /* retry-after */
+       0xff, /* server */
+       0xff, /* set-cookie */
+       0xfa, /* strict-transport-security */
+       0xff, /* transfer-encoding */
+       0xfa, /* user-agent */
+       0xfa, /* vary */
+       0xfa, /* via */
+       0xfa, /* www-authenticate */
+       0xaa, /* patch */
+       0xaa, /* put */
+       0xaa, /* delete */
+       0xff, /* uri-args */
+       0xaa, /* proxy */
+       0xaa, /* x-real-ip */
+       0xff, /* http/1.0 */
+       0xff, /* x-forwarded-for */
+       0xff, /* connect */
+       0xff, /* head */
+       0xfa, /* te */
+       0xfa, /* replay-nonce */
+       0xf0, /* protocol */
+       0xff, /* x-auth-token */
+       0xff /* not matchable */
+};
+
+static unsigned char lws_header_implies_psuedoheader_map[] = {
+       0x07, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00 /* <-64 */,
+       0x0e /* <- 72 */, 0x24 /* <- 80 */, 0, 0, 0, 0
+};
+
 /*
  * b7 = 0 = 1-byte seq
  *         0x08 = fail
  *         no match: die, match go fwd 1 byte
  */
 
-unsigned char lextable[] = {
-       #include "lextable.h"
+unsigned char lextable[][2000] = {
+       {
+                       #include "lextable.h"
+       },
+#define LWS_WITH_HTTP_UNCOMMON_HEADERS
+       {
+                       #include "lextable.h"
+       },
+#undef LWS_WITH_HTTP_UNCOMMON_HEADERS
+#define LWS_ROLE_WS 1
+       {
+                       #include "lextable.h"
+       },
+#define LWS_WITH_HTTP_UNCOMMON_HEADERS
+       {
+                       #include "lextable.h"
+       },
+#undef LWS_ROLE_WS
+#undef LWS_WITH_HTTP_UNCOMMON_HEADERS
+#define LWS_ROLE_H2 1
+       {
+                       #include "lextable.h"
+       },
+#define LWS_WITH_HTTP_UNCOMMON_HEADERS
+       {
+                       #include "lextable.h"
+       },
+#undef LWS_WITH_HTTP_UNCOMMON_HEADERS
+#define LWS_ROLE_WS 1
+       {
+                       #include "lextable.h"
+       },
+#define LWS_WITH_HTTP_UNCOMMON_HEADERS 1
+       {
+                       #include "lextable.h"
+       },
 };
 
 #define PARALLEL 30
@@ -44,29 +201,31 @@ struct state {
        int real_pos;
 };
 
+static unsigned char pseudomap[8][16];
+
 struct state state[1000];
 int next = 1;
 
 #define FAIL_CHAR 0x08
 
-int lextable_decode(int pos, char c)
+int lextable_decode(int version, int pos, char c)
 {
        while (1) {
-               if (lextable[pos] & (1 << 7)) { /* 1-byte, fail on mismatch */
-                       if ((lextable[pos] & 0x7f) != c)
+               if (lextable[version][pos] & (1 << 7)) { /* 1-byte, fail on mismatch */
+                       if ((lextable[version][pos] & 0x7f) != c)
                                return -1;
                        /* fall thru */
                        pos++;
-                       if (lextable[pos] == FAIL_CHAR)
+                       if (lextable[version][pos] == FAIL_CHAR)
                                return -1;
                        return pos;
                } else { /* b7 = 0, end or 3-byte */
-                       if (lextable[pos] < FAIL_CHAR) /* terminal marker */
+                       if (lextable[version][pos] < FAIL_CHAR) /* terminal marker */
                                return pos;
 
-                       if (lextable[pos] == c) /* goto */
-                               return pos + (lextable[pos + 1]) +
-                                               (lextable[pos + 2] << 8);
+                       if (lextable[version][pos] == c) /* goto */
+                               return pos + (lextable[version][pos + 1]) +
+                                               (lextable[version][pos + 2] << 8);
                        /* fall thru goto */
                        pos += 3;
                        /* continue */
@@ -74,34 +233,62 @@ int lextable_decode(int pos, char c)
        }
 }
 
-int main(void)
+int issue(int version)
 {
+       const char *rset[200];
        int n = 0;
-       int m = 0;
+       int m;
        int prev;
-       char c;
        int walk;
        int saw;
        int y;
        int j;
        int pos = 0;
 
-       while (n < sizeof(set) / sizeof(set[0])) {
+       int setmembers = 0;
+
+       memset(rset, 0, sizeof(rset));
+
+       if (version == 7)
+               printf("#if defined(LWS_HTTP_HEADERS_ALL) || (%cdefined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && "
+                        "%cdefined(LWS_ROLE_WS) && "
+                        "%cdefined(LWS_ROLE_H2))\n", version & 1 ? ' ' : '!',
+                            version & 2 ? ' ' : '!', version & 4 ? ' ' : '!');
+       else
+               printf("#if !defined(LWS_HTTP_HEADERS_ALL) && %cdefined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && "
+                        "%cdefined(LWS_ROLE_WS) && "
+                        "%cdefined(LWS_ROLE_H2)\n", version & 1 ? ' ' : '!',
+                            version & 2 ? ' ' : '!', version & 4 ? ' ' : '!');
+
+       /*
+        * let's create version's view of the set of strings
+        */
+
+       for (n = 0; n < sizeof(set) / sizeof(set[0]); n++)
+               if (filter_array[n] & (1 << version)) {
+                       printf("\t/* %d: %d: %s */\n", setmembers, n, set[n]);
+                       if (lws_header_implies_psuedoheader_map[n >> 3] & (1 << (n & 7)))
+                               pseudomap[version][(setmembers >> 3)] |= 1 << (setmembers & 7);
+                       rset[setmembers++] = set[n];
+               }
+
+       n = 0;
+       while (n < setmembers) {
 
                m = 0;
                walk = 0;
                prev = 0;
 
-               if (set[n][0] == '\0') {
+               if (rset[n][0] == '\0') {
                        n++;
                        continue;
                }
 
-               while (set[n][m]) {
+               while (rset[n][m]) {
 
                        saw = 0;
                        for (y = 0; y < state[walk].count; y++)
-                               if (state[walk].c[y] == set[n][m]) {
+                               if (state[walk].c[y] == rset[n][m]) {
                                        /* exists -- go forward */
                                        walk = state[walk].state[y];
                                        saw = 1;
@@ -113,7 +300,7 @@ int main(void)
 
                        /* something we didn't see before */
 
-                       state[walk].c[state[walk].count] = set[n][m];
+                       state[walk].c[state[walk].count] = rset[n][m];
 
                        state[walk].state[state[walk].count] = next;
                        state[walk].count++;
@@ -232,29 +419,32 @@ again:
 
        fprintf(stdout, "/* total size %d bytes */\n", pos);
 
+       printf("#endif\n\n");
+
        /*
         * Try to parse every legal input string
         */
 
-       for (n = 0; n < sizeof(set) / sizeof(set[0]); n++) {
+       for (n = 0; n < setmembers; n++) {
                walk = 0;
                m = 0;
                y = -1;
 
-               if (set[n][0] == '\0')
+               if (rset[n][0] == '\0')
                        continue;
 
-               fprintf(stderr, "  trying '%s'\n", set[n]);
+               fprintf(stderr, "  trying %d '%s'\n", n, rset[n]);
 
-               while (set[n][m]) {
-                       walk = lextable_decode(walk, set[n][m]);
+               while (rset[n][m]) {
+                       walk = lextable_decode(version, walk, rset[n][m]);
                        if (walk < 0) {
                                fprintf(stderr, "failed\n");
                                return 3;
                        }
 
-                       if (lextable[walk] < FAIL_CHAR) {
-                               y = (lextable[walk] << 8) + lextable[walk + 1];
+                       if (lextable[version][walk] < FAIL_CHAR) {
+                               y = (lextable[version][walk] << 8) +
+                                    lextable[version][walk + 1];
                                break;
                        }
                        m++;
@@ -270,3 +460,41 @@ again:
 
        return 0;
 }
+
+int main(void)
+{
+       int m, n;
+
+       for (n = 0; n < 8; n++) {
+               issue(n);
+       }
+
+       printf("\n/*\n");
+
+       for (n = 0; n < 8; n++) {
+
+               if (n == 7)
+                       printf("#if defined(LWS_HTTP_HEADERS_ALL) || (%cdefined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && "
+                                "%cdefined(LWS_ROLE_WS) && "
+                                "%cdefined(LWS_ROLE_H2))\n", n & 1 ? ' ' : '!',
+                                    n & 2 ? ' ' : '!', n & 4 ? ' ' : '!');
+               else
+               printf("#if !defined(LWS_HTTP_HEADERS_ALL) && %cdefined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && "
+                        "%cdefined(LWS_ROLE_WS) && "
+                        "%cdefined(LWS_ROLE_H2)\n", n & 1 ? ' ' : '!',
+                            n & 2 ? ' ' : '!', n & 4 ? ' ' : '!');
+
+               printf("static uint8_t lws_header_implies_psuedoheader_map[] = {\n\t");
+
+               for (m = 0; m < sizeof(pseudomap[n]); m++)
+                       printf("0x%02x,", pseudomap[n][m]);
+
+               printf("\n};\n");
+
+               printf("#endif\n");
+       }
+
+       printf("*/\n");
+
+       fprintf(stderr, "did all the variants\n");
+}
similarity index 63%
rename from lib/roles/http/server/parsers.c
rename to lib/roles/http/parsers.c
index 795b53b..220f9cf 100644 (file)
@@ -1,32 +1,31 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
-static const unsigned char lextable[] = {
-#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)
-       #include "roles/http/lextable.h"
-#else
-       #include "../lextable.h"
-#endif
+static const unsigned char lextable_h1[] = {
+       #include "lextable.h"
 };
 
 #define FAIL_CHAR 0x08
@@ -38,41 +37,6 @@ static const unsigned char lextable[] = {
 #define UHO_LL         4
 #define UHO_NAME       8
 
-static uint16_t
-lws_un16be_get(const void *_p)
-{
-       const uint8_t *p = _p;
-
-       return ((uint16_t)p[0] << 8) | p[1];
-}
-
-static void
-lws_un16be_set(void *_p, uint16_t v)
-{
-       uint8_t *p = _p;
-
-       *p++ = (uint8_t)(v >> 8);
-       *p++ = (uint8_t)v;
-}
-
-static uint32_t
-lws_un32be_get(const void *_p)
-{
-       const uint8_t *p = _p;
-
-       return (uint32_t)((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
-}
-
-static void
-lws_un32be_set(void *_p, uint32_t v)
-{
-       uint8_t *p = _p;
-
-       *p++ = (uint8_t)(v >> 24);
-       *p++ = (uint8_t)(v >> 16);
-       *p++ = (uint8_t)(v >> 8);
-       *p = (uint8_t)v;
-}
 #endif
 
 static struct allocated_headers *
@@ -94,8 +58,8 @@ _lws_create_ah(struct lws_context_per_thread *pt, ah_data_idx_t data_size)
        ah->data_length = data_size;
        pt->http.ah_pool_length++;
 
-       lwsl_info("%s: created ah %p (size %d): pool length %ld\n", __func__,
-                   ah, (int)data_size, (unsigned long)pt->http.ah_pool_length);
+       lwsl_info("%s: created ah %p (size %d): pool length %u\n", __func__,
+                   ah, (int)data_size, (unsigned int)pt->http.ah_pool_length);
 
        return ah;
 }
@@ -107,9 +71,9 @@ _lws_destroy_ah(struct lws_context_per_thread *pt, struct allocated_headers *ah)
                if ((*a) == ah) {
                        *a = ah->next;
                        pt->http.ah_pool_length--;
-                       lwsl_info("%s: freed ah %p : pool length %ld\n",
+                       lwsl_info("%s: freed ah %p : pool length %u\n",
                                    __func__, ah,
-                                   (unsigned long)pt->http.ah_pool_length);
+                                   (unsigned int)pt->http.ah_pool_length);
                        if (ah->data)
                                lws_free(ah->data);
                        lws_free(ah);
@@ -132,8 +96,8 @@ _lws_header_table_reset(struct allocated_headers *ah)
        ah->http_response = 0;
        ah->parser_state = WSI_TOKEN_NAME_PART;
        ah->lextable_pos = 0;
-#if defined(LWS_WITH_CUSTOM_HEADERS)
        ah->unk_pos = 0;
+#if defined(LWS_WITH_CUSTOM_HEADERS)
        ah->unk_ll_head = 0;
        ah->unk_ll_tail = 0;
 #endif
@@ -160,7 +124,7 @@ __lws_header_table_reset(struct lws *wsi, int autoservice)
 
        /* while we hold the ah, keep a timeout on the wsi */
        __lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,
-                         wsi->vhost->timeout_secs_ah_idle);
+                         wsi->a.vhost->timeout_secs_ah_idle);
 
        time(&ah->assigned);
 
@@ -169,7 +133,7 @@ __lws_header_table_reset(struct lws *wsi, int autoservice)
            autoservice) {
                lwsl_debug("%s: service on readbuf ah\n", __func__);
 
-               pt = &wsi->context->pt[(int)wsi->tsi];
+               pt = &wsi->a.context->pt[(int)wsi->tsi];
                /*
                 * Unlike a normal connect, we have the headers already
                 * (or the first part of them anyway)
@@ -177,14 +141,14 @@ __lws_header_table_reset(struct lws *wsi, int autoservice)
                pfd = &pt->fds[wsi->position_in_fds_table];
                pfd->revents |= LWS_POLLIN;
                lwsl_err("%s: calling service\n", __func__);
-               lws_service_fd_tsi(wsi->context, pfd, wsi->tsi);
+               lws_service_fd_tsi(wsi->a.context, pfd, wsi->tsi);
        }
 }
 
 void
 lws_header_table_reset(struct lws *wsi, int autoservice)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
 
        lws_pt_lock(pt, __func__);
 
@@ -196,7 +160,7 @@ lws_header_table_reset(struct lws *wsi, int autoservice)
 static void
 _lws_header_ensure_we_are_on_waiting_list(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        struct lws_pollargs pa;
        struct lws **pwsi = &pt->http.ah_wait_list;
 
@@ -206,7 +170,7 @@ _lws_header_ensure_we_are_on_waiting_list(struct lws *wsi)
                pwsi = &(*pwsi)->http.ah_wait_list;
        }
 
-       lwsl_info("%s: wsi: %p\n", __func__, wsi);
+       lwsl_info("%s: wsi: %s\n", __func__, lws_wsi_tag(wsi));
        wsi->http.ah_wait_list = pt->http.ah_wait_list;
        pt->http.ah_wait_list = wsi;
        pt->http.ah_wait_list_length++;
@@ -219,12 +183,12 @@ _lws_header_ensure_we_are_on_waiting_list(struct lws *wsi)
 static int
 __lws_remove_from_ah_waiting_list(struct lws *wsi)
 {
-        struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+        struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        struct lws **pwsi =&pt->http.ah_wait_list;
 
        while (*pwsi) {
                if (*pwsi == wsi) {
-                       lwsl_info("%s: wsi %p\n", __func__, wsi);
+                       lwsl_info("%s: wsi %s\n", __func__, lws_wsi_tag(wsi));
                        /* point prev guy to our next */
                        *pwsi = wsi->http.ah_wait_list;
                        /* we shouldn't point anywhere now */
@@ -242,13 +206,18 @@ __lws_remove_from_ah_waiting_list(struct lws *wsi)
 int LWS_WARN_UNUSED_RESULT
 lws_header_table_attach(struct lws *wsi, int autoservice)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        struct lws_pollargs pa;
        int n;
 
-       lwsl_info("%s: wsi %p: ah %p (tsi %d, count = %d) in\n", __func__,
-                 (void *)wsi, (void *)wsi->http.ah, wsi->tsi,
+#if defined(LWS_ROLE_MQTT) && defined(LWS_WITH_CLIENT)
+       if (lwsi_role_mqtt(wsi))
+               goto connect_via_info2;
+#endif
+
+       lwsl_info("%s: %s: ah %p (tsi %d, count = %d) in\n", __func__,
+                 lws_wsi_tag(wsi), (void *)wsi->http.ah, wsi->tsi,
                  pt->http.ah_count_in_use);
 
        if (!lwsi_role_http(wsi)) {
@@ -265,13 +234,10 @@ lws_header_table_attach(struct lws *wsi, int autoservice)
                goto reset;
        }
 
-       n = pt->http.ah_count_in_use == context->max_http_header_pool;
+       n = pt->http.ah_count_in_use == (int)context->max_http_header_pool;
 #if defined(LWS_WITH_PEER_LIMITS)
-       if (!n) {
+       if (!n)
                n = lws_peer_confirm_ah_attach_ok(context, wsi->peer);
-               if (n)
-                       lws_stats_bump(pt, LWSSTATS_C_PEER_LIMIT_AH_DENIED, 1);
-       }
 #endif
        if (n) {
                /*
@@ -309,15 +275,18 @@ lws_header_table_attach(struct lws *wsi, int autoservice)
 
        _lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa);
 
-       lwsl_info("%s: did attach wsi %p: ah %p: count %d (on exit)\n", __func__,
-                 (void *)wsi, (void *)wsi->http.ah, pt->http.ah_count_in_use);
+       lwsl_info("%s: did attach wsi %s: ah %p: count %d (on exit)\n", __func__,
+                 lws_wsi_tag(wsi), (void *)wsi->http.ah, pt->http.ah_count_in_use);
 
 reset:
        __lws_header_table_reset(wsi, autoservice);
 
        lws_pt_unlock(pt);
 
-#ifndef LWS_NO_CLIENT
+#if defined(LWS_WITH_CLIENT)
+#if defined(LWS_ROLE_MQTT)
+connect_via_info2:
+#endif
        if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED)
                if (!lws_http_client_connect_via_info2(wsi))
                        /* our client connect has failed, the wsi
@@ -336,7 +305,7 @@ bail:
 
 int __lws_header_table_detach(struct lws *wsi, int autoservice)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct allocated_headers *ah = wsi->http.ah;
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        struct lws_pollargs pa;
@@ -348,8 +317,8 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice)
        if (!ah)
                return 0;
 
-       lwsl_info("%s: wsi %p: ah %p (tsi=%d, count = %d)\n", __func__,
-                 (void *)wsi, (void *)ah, wsi->tsi,
+       lwsl_info("%s: %s: ah %p (tsi=%d, count = %d)\n", __func__,
+                 lws_wsi_tag(wsi), (void *)ah, wsi->tsi,
                  pt->http.ah_count_in_use);
 
        /* we did have an ah attached */
@@ -359,8 +328,9 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice)
                 * we're detaching the ah, but it was held an
                 * unreasonably long time
                 */
-               lwsl_debug("%s: wsi %p: ah held %ds, role/state 0x%lx 0x%x,"
-                           "\n", __func__, wsi, (int)(now - ah->assigned),
+               lwsl_debug("%s: %s: ah held %ds, role/state 0x%lx 0x%x,"
+                           "\n", __func__, lws_wsi_tag(wsi),
+                           (int)(now - ah->assigned),
                            (unsigned long)lwsi_role(wsi), lwsi_state(wsi));
        }
 
@@ -377,6 +347,7 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice)
                lws_peer_track_ah_detach(context, wsi->peer);
 #endif
        ah->wsi = NULL; /* no owner */
+       wsi->http.ah = NULL;
 
        pwsi = &pt->http.ah_wait_list;
 
@@ -388,7 +359,7 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice)
         * at least one wsi on the same tsi is waiting, give it to oldest guy
         * who is allowed to take it (if any)
         */
-       lwsl_info("pt wait list %p\n", *pwsi);
+       lwsl_info("%s: pt wait list %s\n", __func__, lws_wsi_tag(*pwsi));
        wsi = NULL;
        pwsi_eligible = NULL;
 
@@ -401,12 +372,7 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice)
                        wsi = *pwsi;
                        pwsi_eligible = pwsi;
                }
-#if defined(LWS_WITH_PEER_LIMITS)
-               else
-                       if (!(*pwsi)->http.ah_wait_list)
-                               lws_stats_bump(pt,
-                                       LWSSTATS_C_PEER_LIMIT_AH_DENIED, 1);
-#endif
+
                pwsi = &(*pwsi)->http.ah_wait_list;
        }
 
@@ -414,7 +380,7 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice)
                goto nobody_usable_waiting;
 
        lwsl_info("%s: transferring ah to last eligible wsi in wait list "
-                 "%p (wsistate 0x%lx)\n", __func__, wsi,
+                 "%s (wsistate 0x%lx)\n", __func__, lws_wsi_tag(wsi),
                  (unsigned long)wsi->wsistate);
 
        wsi->http.ah = ah;
@@ -431,7 +397,7 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice)
 
        /* clients acquire the ah and then insert themselves in fds table... */
        if (wsi->position_in_fds_table != LWS_NO_FDS_POS) {
-               lwsl_info("%s: Enabling %p POLLIN\n", __func__, wsi);
+               lwsl_info("%s: Enabling %s POLLIN\n", __func__, lws_wsi_tag(wsi));
 
                /* he has been stuck waiting for an ah, but now his wait is
                 * over, let him progress */
@@ -445,7 +411,7 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice)
        wsi->http.ah_wait_list = NULL;
        pt->http.ah_wait_list_length--;
 
-#ifndef LWS_NO_CLIENT
+#if defined(LWS_WITH_CLIENT)
        if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED) {
                lws_pt_unlock(pt);
 
@@ -463,8 +429,8 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice)
        assert(!!pt->http.ah_wait_list_length ==
                        !!(lws_intptr_t)pt->http.ah_wait_list);
 bail:
-       lwsl_info("%s: wsi %p: ah %p (tsi=%d, count = %d)\n", __func__,
-                 (void *)wsi, (void *)ah, pt->tid, pt->http.ah_count_in_use);
+       lwsl_info("%s: %s: ah %p (tsi=%d, count = %d)\n", __func__,
+                 lws_wsi_tag(wsi), (void *)ah, pt->tid, pt->http.ah_count_in_use);
 
        return 0;
 
@@ -478,7 +444,7 @@ nobody_usable_waiting:
 
 int lws_header_table_detach(struct lws *wsi, int autoservice)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        int n;
 
@@ -489,7 +455,7 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)
 {
        int n;
@@ -509,7 +475,7 @@ lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)
        return 0;
 }
 
-LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
+int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
 {
        int n;
        int len = 0;
@@ -524,15 +490,15 @@ LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
                len += wsi->http.ah->frags[n].len;
                n = wsi->http.ah->frags[n].nfrag;
 
-               if (n && h != WSI_TOKEN_HTTP_COOKIE)
-                       ++len;
+               if (n)
+                       len++;
 
        } while (n);
 
        return len;
 }
 
-LWS_VISIBLE int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,
+int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,
                                      enum lws_token_indexes h, int frag_idx)
 {
        int n = 0;
@@ -563,12 +529,10 @@ LWS_VISIBLE int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,
        return wsi->http.ah->frags[f].len;
 }
 
-LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len,
+int lws_hdr_copy(struct lws *wsi, char *dst, int len,
                             enum lws_token_indexes h)
 {
-       int toklen = lws_hdr_total_length(wsi, h);
-       int n;
-       int comma;
+       int toklen = lws_hdr_total_length(wsi, h), n, comma;
 
        *dst = '\0';
        if (!toklen)
@@ -583,59 +547,85 @@ LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len,
        n = wsi->http.ah->frag_index[h];
        if (!n)
                return 0;
-
        do {
-               comma = (wsi->http.ah->frags[n].nfrag &&
-                       h != WSI_TOKEN_HTTP_COOKIE) ? 1 : 0;
+               comma = (wsi->http.ah->frags[n].nfrag) ? 1 : 0;
+
+               if (h == WSI_TOKEN_HTTP_URI_ARGS)
+                       lwsl_notice("%s: WSI_TOKEN_HTTP_URI_ARGS '%.*s'\n",
+                                   __func__, (int)wsi->http.ah->frags[n].len,
+                                   &wsi->http.ah->data[
+                                               wsi->http.ah->frags[n].offset]);
 
-               if (wsi->http.ah->frags[n].len + comma >= len)
+               if (wsi->http.ah->frags[n].len + comma >= len) {
+                       lwsl_notice("blowout len\n");
                        return -1;
+               }
                strncpy(dst, &wsi->http.ah->data[wsi->http.ah->frags[n].offset],
                        wsi->http.ah->frags[n].len);
                dst += wsi->http.ah->frags[n].len;
                len -= wsi->http.ah->frags[n].len;
                n = wsi->http.ah->frags[n].nfrag;
 
-               if (comma)
-                       *dst++ = ',';
+               /*
+                * Note if you change this logic, take care about updating len
+                * and make sure lws_hdr_total_length() gives the same resulting
+                * length
+                */
+
+               if (comma) {
+                       if (h == WSI_TOKEN_HTTP_COOKIE ||
+                           h == WSI_TOKEN_HTTP_SET_COOKIE)
+                               *dst++ = ';';
+                       else
+                               if (h == WSI_TOKEN_HTTP_URI_ARGS)
+                                       *dst++ = '&';
+                               else
+                                       *dst++ = ',';
+                       len--;
+               }
                                
        } while (n);
        *dst = '\0';
 
+       if (h == WSI_TOKEN_HTTP_URI_ARGS)
+               lwsl_err("%s: WSI_TOKEN_HTTP_URI_ARGS toklen %d\n", __func__, (int)toklen);
+
        return toklen;
 }
 
 #if defined(LWS_WITH_CUSTOM_HEADERS)
-LWS_VISIBLE int
+int
 lws_hdr_custom_length(struct lws *wsi, const char *name, int nlen)
 {
        ah_data_idx_t ll;
 
-       if (!wsi->http.ah || wsi->http2_substream)
+       if (!wsi->http.ah || wsi->mux_substream)
                return -1;
 
        ll = wsi->http.ah->unk_ll_head;
        while (ll) {
                if (ll >= wsi->http.ah->data_length)
                        return -1;
-               if (nlen == lws_un16be_get(&wsi->http.ah->data[ll + UHO_NLEN]) &&
-                   !strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], nlen))
-                       return lws_un16be_get(&wsi->http.ah->data[ll + UHO_VLEN]);
+               if (nlen == lws_ser_ru16be(
+                       (uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]) &&
+                   !strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], (unsigned int)nlen))
+                       return lws_ser_ru16be(
+                               (uint8_t *)&wsi->http.ah->data[ll + UHO_VLEN]);
 
-               ll = lws_un32be_get(&wsi->http.ah->data[ll + UHO_LL]);
+               ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]);
        }
 
        return -1;
 }
 
-LWS_VISIBLE int
+int
 lws_hdr_custom_copy(struct lws *wsi, char *dst, int len, const char *name,
                    int nlen)
 {
        ah_data_idx_t ll;
        int n;
 
-       if (!wsi->http.ah || wsi->http2_substream)
+       if (!wsi->http.ah || wsi->mux_substream)
                return -1;
 
        *dst = '\0';
@@ -644,21 +634,48 @@ lws_hdr_custom_copy(struct lws *wsi, char *dst, int len, const char *name,
        while (ll) {
                if (ll >= wsi->http.ah->data_length)
                        return -1;
-               if (nlen == lws_un16be_get(&wsi->http.ah->data[ll + UHO_NLEN]) &&
-                   !strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], nlen)) {
-                       n = lws_un16be_get(&wsi->http.ah->data[ll + UHO_VLEN]);
+               if (nlen == lws_ser_ru16be(
+                       (uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]) &&
+                   !strncmp(name, &wsi->http.ah->data[ll + UHO_NAME], (unsigned int)nlen)) {
+                       n = lws_ser_ru16be(
+                               (uint8_t *)&wsi->http.ah->data[ll + UHO_VLEN]);
                        if (n + 1 > len)
                                return -1;
-                       strncpy(dst, &wsi->http.ah->data[ll + UHO_NAME + nlen], n);
+                       strncpy(dst, &wsi->http.ah->data[ll + UHO_NAME + (unsigned int)nlen], (unsigned int)n);
                        dst[n] = '\0';
 
                        return n;
                }
-               ll = lws_un32be_get(&wsi->http.ah->data[ll + UHO_LL]);
+               ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]);
        }
 
        return -1;
 }
+
+int
+lws_hdr_custom_name_foreach(struct lws *wsi, lws_hdr_custom_fe_cb_t cb,
+                           void *custom)
+{
+       ah_data_idx_t ll;
+
+       if (!wsi->http.ah || wsi->mux_substream)
+               return -1;
+
+       ll = wsi->http.ah->unk_ll_head;
+
+       while (ll) {
+               if (ll >= wsi->http.ah->data_length)
+                       return -1;
+
+               cb(&wsi->http.ah->data[ll + UHO_NAME],
+                  lws_ser_ru16be((uint8_t *)&wsi->http.ah->data[ll + UHO_NLEN]),
+                  custom);
+
+               ll = lws_ser_ru32be((uint8_t *)&wsi->http.ah->data[ll + UHO_LL]);
+       }
+
+       return 0;
+}
 #endif
 
 char *lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h)
@@ -682,10 +699,10 @@ lws_pos_in_bounds(struct lws *wsi)
                return -1;
 
        if (wsi->http.ah->pos <
-           (unsigned int)wsi->context->max_http_header_data)
+           (unsigned int)wsi->a.context->max_http_header_data)
                return 0;
 
-       if ((int)wsi->http.ah->pos == wsi->context->max_http_header_data) {
+       if ((int)wsi->http.ah->pos >= (int)wsi->a.context->max_http_header_data - 1) {
                lwsl_err("Ran out of header data space\n");
                return 1;
        }
@@ -696,7 +713,7 @@ lws_pos_in_bounds(struct lws *wsi)
         */
        lwsl_err("%s: pos %ld, limit %ld\n", __func__,
                 (unsigned long)wsi->http.ah->pos,
-                (unsigned long)wsi->context->max_http_header_data);
+                (unsigned long)wsi->a.context->max_http_header_data);
        assert(0);
 
        return 1;
@@ -705,6 +722,16 @@ lws_pos_in_bounds(struct lws *wsi)
 int LWS_WARN_UNUSED_RESULT
 lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s)
 {
+       if (!*s) {
+               /*
+                * If we get an empty string, then remove any entry for the
+                * header
+                */
+               wsi->http.ah->frag_index[h] = 0;
+
+               return 0;
+       }
+
        wsi->http.ah->nfrag++;
        if (wsi->http.ah->nfrag == LWS_ARRAY_SIZE(wsi->http.ah->frags)) {
                lwsl_warn("More hdr frags than we can deal with, dropping\n");
@@ -744,9 +771,8 @@ issue_char(struct lws *wsi, unsigned char c)
         */
        if (!wsi->http.ah->current_token_limit ||
            frag_len < wsi->http.ah->current_token_limit) {
-               wsi->http.ah->data[wsi->http.ah->pos++] = c;
-               if (c)
-                       wsi->http.ah->frags[wsi->http.ah->nfrag].len++;
+               wsi->http.ah->data[wsi->http.ah->pos++] = (char)c;
+               wsi->http.ah->frags[wsi->http.ah->nfrag].len++;
                return 0;
        }
 
@@ -785,21 +811,21 @@ lws_parse_urldecode(struct lws *wsi, uint8_t *_c)
                }
                break;
        case URIES_SEEN_PERCENT:
-               if (char_to_hex(c) < 0)
+               if (char_to_hex((char)c) < 0)
                        /* illegal post-% char */
                        goto forbid;
 
-               ah->esc_stash = c;
+               ah->esc_stash = (char)c;
                ah->ues = URIES_SEEN_PERCENT_H1;
                goto swallow;
 
        case URIES_SEEN_PERCENT_H1:
-               if (char_to_hex(c) < 0)
+               if (char_to_hex((char)c) < 0)
                        /* illegal post-% char */
                        goto forbid;
 
-               *_c = (char_to_hex(ah->esc_stash) << 4) |
-                               char_to_hex(c);
+               *_c = (uint8_t)(unsigned int)((char_to_hex(ah->esc_stash) << 4) |
+                               char_to_hex((char)c));
                c = *_c;
                enc = 1;
                ah->ues = URIES_IDLE;
@@ -815,16 +841,31 @@ lws_parse_urldecode(struct lws *wsi, uint8_t *_c)
         *  leave /.dir or whatever alone
         */
 
+       if (!c && (!ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] ||
+                  !ah->post_literal_equal)) {
+               /*
+                * Since user code is typically going to parse the path using
+                * NUL-terminated apis, it's too dangerous to allow NUL
+                * injection here.
+                *
+                * It's allowed in the urlargs, because the apis to access
+                * those only allow retreival with explicit length.
+                */
+               lwsl_warn("%s: saw NUL outside of uri args\n", __func__);
+               return -1;
+       }
+
        switch (ah->ups) {
        case URIPS_IDLE:
-               if (!c)
-                       return -1;
+
                /* genuine delimiter */
                if ((c == '&' || c == ';') && !enc) {
                        if (issue_char(wsi, '\0') < 0)
                                return -1;
+                       /* don't account for it */
+                       wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
                        /* link to next fragment */
-                       ah->frags[ah->nfrag].nfrag = ah->nfrag + 1;
+                       ah->frags[ah->nfrag].nfrag = (uint8_t)(ah->nfrag + 1);
                        ah->nfrag++;
                        if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
                                goto excessive;
@@ -927,6 +968,9 @@ lws_parse_urldecode(struct lws *wsi, uint8_t *_c)
                if (issue_char(wsi, '\0') < 0)
                        return -1;
 
+               /* don't account for it */
+               wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
+
                /* move to using WSI_TOKEN_HTTP_URI_ARGS */
                ah->nfrag++;
                if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frags))
@@ -956,10 +1000,12 @@ excessive:
 static const unsigned char methods[] = {
        WSI_TOKEN_GET_URI,
        WSI_TOKEN_POST_URI,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
        WSI_TOKEN_OPTIONS_URI,
        WSI_TOKEN_PUT_URI,
        WSI_TOKEN_PATCH_URI,
        WSI_TOKEN_DELETE_URI,
+#endif
        WSI_TOKEN_CONNECT,
        WSI_TOKEN_HEAD_URI,
 };
@@ -968,11 +1014,11 @@ static const unsigned char methods[] = {
  * possible returns:, -1 fail, 0 ok or 2, transition to raw
  */
 
-int LWS_WARN_UNUSED_RESULT
+lws_parser_return_t LWS_WARN_UNUSED_RESULT
 lws_parse(struct lws *wsi, unsigned char *buf, int *len)
 {
        struct allocated_headers *ah = wsi->http.ah;
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        unsigned int n, m;
        unsigned char c;
        int r, pos;
@@ -990,8 +1036,8 @@ lws_parse(struct lws *wsi, unsigned char *buf, int *len)
                        if (c == '\r')
                                break;
                        if (c == '\n') {
-                               lws_un16be_set(&ah->data[ah->unk_pos + 2],
-                                              ah->pos - ah->unk_value_pos);
+                               lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos + 2],
+                                              (uint16_t)(ah->pos - ah->unk_value_pos));
                                ah->parser_state = WSI_TOKEN_NAME_PART;
                                ah->unk_pos = 0;
                                ah->lextable_pos = 0;
@@ -1003,9 +1049,9 @@ lws_parse(struct lws *wsi, unsigned char *buf, int *len)
                            (c != ' ' && c != '\t')) {
 
                                if (lws_pos_in_bounds(wsi))
-                                       return -1;
+                                       return LPR_FAIL;
 
-                               ah->data[ah->pos++] = c;
+                               ah->data[ah->pos++] = (char)c;
                        }
                        pos = ah->lextable_pos;
                        break;
@@ -1033,7 +1079,7 @@ lws_parse(struct lws *wsi, unsigned char *buf, int *len)
                                /* enforce starting with / */
                                if (!ah->frags[ah->nfrag].len)
                                        if (issue_char(wsi, '/') < 0)
-                                               return -1;
+                                               return LPR_FAIL;
 
                                if (ah->ups == URIPS_SEEN_SLASH_DOT_DOT) {
                                        /*
@@ -1055,7 +1101,9 @@ lws_parse(struct lws *wsi, unsigned char *buf, int *len)
 
                                /* begin parsing HTTP version: */
                                if (issue_char(wsi, '\0') < 0)
-                                       return -1;
+                                       return LPR_FAIL;
+                               /* don't account for it */
+                               wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
                                ah->parser_state = WSI_TOKEN_HTTP;
                                goto start_fragment;
                        }
@@ -1076,20 +1124,38 @@ lws_parse(struct lws *wsi, unsigned char *buf, int *len)
 check_eol:
                        /* bail at EOL */
                        if (ah->parser_state != WSI_TOKEN_CHALLENGE &&
-                           c == '\x0d') {
+                           (c == '\x0d' || c == '\x0a')) {
                                if (ah->ues != URIES_IDLE)
                                        goto forbid;
 
+                               if (c == '\x0a') {
+                                       /* broken peer */
+                                       ah->parser_state = WSI_TOKEN_NAME_PART;
+                                       ah->unk_pos = 0;
+                                       ah->lextable_pos = 0;
+                               } else
+                                       ah->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
+
                                c = '\0';
-                               ah->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
                                lwsl_parser("*\n");
                        }
 
-                       n = issue_char(wsi, c);
+                       n = (unsigned int)issue_char(wsi, c);
                        if ((int)n < 0)
                                return LPR_FAIL;
                        if (n > 0)
                                ah->parser_state = WSI_TOKEN_SKIPPING;
+                       else {
+                               /*
+                                * Explicit zeroes are legal in URI ARGS.
+                                * They can only exist as a safety terminator
+                                * after the valid part of the token contents
+                                * for other types.
+                                */
+                               if (!c && ah->parser_state != WSI_TOKEN_HTTP_URI_ARGS)
+                                       /* don't account for safety terminator */
+                                       wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
+                       }
 
 swallow:
                        /* per-protocol end of headers management */
@@ -1106,18 +1172,22 @@ swallow:
                                    (unsigned long)lwsi_role(wsi),
                                    ah->lextable_pos);
 
-                       if (c >= 'A' && c <= 'Z')
-                               c += 'a' - 'A';
+                       if (!ah->unk_pos && c == '\x0a')
+                               /* broken peer */
+                               goto set_parsing_complete;
 
-#if defined(LWS_WITH_CUSTOM_HEADERS)
+                       if (c >= 'A' && c <= 'Z')
+                               c = (unsigned char)(c + 'a' - 'A');
                        /*
                         * ...in case it's an unknown header, speculatively
                         * store it as the name comes in.  If we recognize it as
                         * a known header, we'll snip this.
                         */
 
-                       if (!ah->unk_pos) {
+                       if (!wsi->mux_substream && !ah->unk_pos) {
                                ah->unk_pos = ah->pos;
+
+#if defined(LWS_WITH_CUSTOM_HEADERS)
                                /*
                                 * Prepare new unknown header linked-list entry
                                 *
@@ -1128,17 +1198,22 @@ swallow:
                                for (n = 0; n < 8; n++)
                                        if (!lws_pos_in_bounds(wsi))
                                                ah->data[ah->pos++] = 0;
-                       }
 #endif
+                       }
 
                        if (lws_pos_in_bounds(wsi))
-                               return -1;
+                               return LPR_FAIL;
 
-                       ah->data[ah->pos++] = c;
+                       ah->data[ah->pos++] = (char)c;
                        pos = ah->lextable_pos;
 
 #if defined(LWS_WITH_CUSTOM_HEADERS)
-                       if (pos < 0 && c == ':') {
+                       if (!wsi->mux_substream && pos < 0 && c == ':') {
+#if defined(_DEBUG)
+                               char dotstar[64];
+                               int uhlen;
+#endif
+
                                /*
                                 * process unknown headers
                                 *
@@ -1149,21 +1224,27 @@ swallow:
                                        ah->unk_ll_head = ah->unk_pos;
 
                                if (ah->unk_ll_tail)
-                                       lws_un32be_set(&ah->data[ah->unk_ll_tail + UHO_LL],
+                                       lws_ser_wu32be(
+                               (uint8_t *)&ah->data[ah->unk_ll_tail + UHO_LL],
                                                       ah->unk_pos);
 
                                ah->unk_ll_tail = ah->unk_pos;
 
-                               lwsl_debug("%s: unk header %d '%.*s'\n",
-                                          __func__,
-                                          ah->pos - (ah->unk_pos + UHO_NAME),
-                                          ah->pos - (ah->unk_pos + UHO_NAME),
-                                          &ah->data[ah->unk_pos + UHO_NAME]);
+#if defined(_DEBUG)
+                               uhlen = (int)(ah->pos - (ah->unk_pos + UHO_NAME));
+                               lws_strnncpy(dotstar,
+                                       &ah->data[ah->unk_pos + UHO_NAME],
+                                       uhlen, sizeof(dotstar));
+                               lwsl_debug("%s: unk header %d '%s'\n",
+                                           __func__,
+                                           ah->pos - (ah->unk_pos + UHO_NAME),
+                                           dotstar);
+#endif
 
                                /* set the unknown header name part length */
 
-                               lws_un16be_set(&ah->data[ah->unk_pos],
-                                              (ah->pos - ah->unk_pos) - UHO_NAME);
+                               lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos],
+                                              (uint16_t)((ah->pos - ah->unk_pos) - UHO_NAME));
 
                                ah->unk_value_pos = ah->pos;
 
@@ -1179,44 +1260,46 @@ swallow:
                                break;
 
                        while (1) {
-                               if (lextable[pos] & (1 << 7)) {
+                               if (lextable_h1[pos] & (1 << 7)) {
                                        /* 1-byte, fail on mismatch */
-                                       if ((lextable[pos] & 0x7f) != c) {
+                                       if ((lextable_h1[pos] & 0x7f) != c) {
 nope:
                                                ah->lextable_pos = -1;
                                                break;
                                        }
                                        /* fall thru */
                                        pos++;
-                                       if (lextable[pos] == FAIL_CHAR)
+                                       if (lextable_h1[pos] == FAIL_CHAR)
                                                goto nope;
 
-                                       ah->lextable_pos = pos;
+                                       ah->lextable_pos = (int16_t)pos;
                                        break;
                                }
 
-                               if (lextable[pos] == FAIL_CHAR)
+                               if (lextable_h1[pos] == FAIL_CHAR)
                                        goto nope;
 
                                /* b7 = 0, end or 3-byte */
-                               if (lextable[pos] < FAIL_CHAR) {
-#if defined(LWS_WITH_CUSTOM_HEADERS)
-                                       /*
-                                        * We hit a terminal marker, so we
-                                        * recognized this header... drop the
-                                        * speculative name part storage
-                                        */
-                                       ah->pos = ah->unk_pos;
-                                       ah->unk_pos = 0;
-#endif
-                                       ah->lextable_pos = pos;
+                               if (lextable_h1[pos] < FAIL_CHAR) {
+                                       if (!wsi->mux_substream) {
+                                               /*
+                                                * We hit a terminal marker, so
+                                                * we recognized this header...
+                                                * drop the speculative name
+                                                * part storage
+                                                */
+                                               ah->pos = ah->unk_pos;
+                                               ah->unk_pos = 0;
+                                       }
+
+                                       ah->lextable_pos = (int16_t)pos;
                                        break;
                                }
 
-                               if (lextable[pos] == c) { /* goto */
-                                       ah->lextable_pos = pos +
-                                               (lextable[pos + 1]) +
-                                               (lextable[pos + 2] << 8);
+                               if (lextable_h1[pos] == c) { /* goto */
+                                       ah->lextable_pos = (int16_t)(pos +
+                                               (lextable_h1[pos + 1]) +
+                                               (lextable_h1[pos + 2] << 8));
                                        break;
                                }
 
@@ -1244,19 +1327,25 @@ nope:
 #if !defined(LWS_WITH_CUSTOM_HEADERS)
                                                ah->parser_state = WSI_TOKEN_SKIPPING;
 #endif
+                                               if (wsi->mux_substream)
+                                                       ah->parser_state = WSI_TOKEN_SKIPPING;
                                                break;
                                        }
 
-                               if (m != LWS_ARRAY_SIZE(methods))
+                               if (m != LWS_ARRAY_SIZE(methods)) {
 #if defined(LWS_WITH_CUSTOM_HEADERS)
                                        /*
                                         * We have the method, this is just an
                                         * unknown header then
                                         */
-                                       goto unknown_hdr;
+                                       if (!wsi->mux_substream)
+                                               goto unknown_hdr;
+                                       else
+                                               break;
 #else
                                        break;
 #endif
+                               }
                                /*
                                 * ...it's an unknown http method from a client
                                 * in fact, it cannot be valid http.
@@ -1264,7 +1353,7 @@ nope:
                                 * Are we set up to transition to another role
                                 * in these cases?
                                 */
-                               if (lws_check_opt(wsi->vhost->options,
+                               if (lws_check_opt(wsi->a.vhost->options,
                    LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG)) {
                                        lwsl_notice("%s: http fail fallback\n",
                                                    __func__);
@@ -1276,23 +1365,26 @@ nope:
                                goto forbid;
                        }
                        if (ah->lextable_pos < 0) {
+                               /*
+                                * It's not a header that lws knows about...
+                                */
 #if defined(LWS_WITH_CUSTOM_HEADERS)
-                               goto unknown_hdr;
-#else
+                               if (!wsi->mux_substream)
+                                       goto unknown_hdr;
+#endif
                                /*
                                 * ...otherwise for a client, let him ignore
                                 * unknown headers coming from the server
                                 */
                                ah->parser_state = WSI_TOKEN_SKIPPING;
                                break;
-#endif
                        }
 
-                       if (lextable[ah->lextable_pos] < FAIL_CHAR) {
+                       if (lextable_h1[ah->lextable_pos] < FAIL_CHAR) {
                                /* terminal state */
 
-                               n = ((unsigned int)lextable[ah->lextable_pos] << 8) |
-                                               lextable[ah->lextable_pos + 1];
+                               n = ((unsigned int)lextable_h1[ah->lextable_pos] << 8) |
+                                               lextable_h1[ah->lextable_pos + 1];
 
                                lwsl_parser("known hdr %d\n", n);
                                for (m = 0; m < LWS_ARRAY_SIZE(methods); m++)
@@ -1302,14 +1394,26 @@ nope:
                                                return LPR_FAIL;
                                        }
 
+                               if (!wsi->mux_substream) {
+                                       /*
+                                        * Whether we are collecting unknown names or not,
+                                        * if we matched an internal header we can dispense
+                                        * with the header name part we were keeping
+                                        */
+                                       ah->pos = ah->unk_pos;
+                                       ah->unk_pos = 0;
+                               }
+
+#if defined(LWS_ROLE_WS)
                                /*
                                 * WSORIGIN is protocol equiv to ORIGIN,
                                 * JWebSocket likes to send it, map to ORIGIN
                                 */
                                if (n == WSI_TOKEN_SWORIGIN)
                                        n = WSI_TOKEN_ORIGIN;
+#endif
 
-                               ah->parser_state = (enum lws_token_indexes)
+                               ah->parser_state = (uint8_t)
                                                        (WSI_TOKEN_GET_URI + n);
                                ah->ups = URIPS_IDLE;
 
@@ -1319,7 +1423,7 @@ nope:
                                                              ah->parser_state];
                                else
                                        ah->current_token_limit =
-                                               wsi->context->max_http_header_data;
+                                               wsi->a.context->max_http_header_data;
 
                                if (ah->parser_state == WSI_TOKEN_CHALLENGE)
                                        goto set_parsing_complete;
@@ -1332,7 +1436,8 @@ nope:
 unknown_hdr:
                        //ah->parser_state = WSI_TOKEN_SKIPPING;
                        //break;
-                       break;
+                       if (!wsi->mux_substream)
+                               break;
 #endif
 
 start_fragment:
@@ -1367,6 +1472,13 @@ excessive:
                case WSI_TOKEN_SKIPPING:
                        lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
 
+                       if (c == '\x0a') {
+                               /* broken peer */
+                               ah->parser_state = WSI_TOKEN_NAME_PART;
+                               ah->unk_pos = 0;
+                               ah->lextable_pos = 0;
+                       }
+
                        if (c == '\x0d')
                                ah->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
                        break;
@@ -1377,9 +1489,7 @@ excessive:
                                goto forbid;
                        if (c == '\x0a') {
                                ah->parser_state = WSI_TOKEN_NAME_PART;
-#if defined(LWS_WITH_CUSTOM_HEADERS)
                                ah->unk_pos = 0;
-#endif
                                ah->lextable_pos = 0;
                        } else
                                ah->parser_state = WSI_TOKEN_SKIPPING;
@@ -1400,11 +1510,13 @@ set_parsing_complete:
                goto forbid;
 
        if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
-               if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
-                       wsi->rx_frame_type = /* temp for ws version index */
-                              atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
+#if defined(LWS_ROLE_WS)
+               const char *pv = lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION);
+               if (pv)
+                       wsi->rx_frame_type = (char)atoi(pv);
 
                lwsl_parser("v%02d hdrs done\n", wsi->rx_frame_type);
+#endif
        }
        ah->parser_state = WSI_PARSING_COMPLETE;
        wsi->hdr_parsing_completed = 1;
@@ -1412,9 +1524,203 @@ set_parsing_complete:
        return LPR_OK;
 
 forbid:
-       lwsl_notice(" forbidding on uri sanitation\n");
+       lwsl_info(" forbidding on uri sanitation\n");
+#if defined(LWS_WITH_SERVER)
        lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
+#endif
 
        return LPR_FORBIDDEN;
 }
 
+int
+lws_http_cookie_get(struct lws *wsi, const char *name, char *buf,
+                   size_t *max_len)
+{
+       size_t max = *max_len, bl = strlen(name);
+       char *p, *bo = buf;
+       int n;
+
+       n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE);
+       if ((unsigned int)n < bl + 1)
+               return 1;
+
+       /*
+        * This can come to us two ways, in ah fragments (h2) or as a single
+        * semicolon-delimited string (h1)
+        */
+
+#if defined(LWS_ROLE_H2)
+       if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_METHOD)) {
+
+               /*
+                * The h2 way...
+                */
+
+               int f = wsi->http.ah->frag_index[WSI_TOKEN_HTTP_COOKIE];
+               size_t fl;
+
+               while (f) {
+                       p = wsi->http.ah->data + wsi->http.ah->frags[f].offset;
+                       fl = (size_t)wsi->http.ah->frags[f].len;
+                       if (fl >= bl + 1 &&
+                           p[bl] == '=' &&
+                           !memcmp(p, name, bl)) {
+                               fl -= bl + 1;
+                               if (max - 1 < fl)
+                                       fl = max - 1;
+                               if (fl)
+                                       memcpy(buf, p + bl + 1, fl);
+                               *max_len = fl;
+                               buf[fl] = '\0';
+
+                               return 0;
+                       }
+                       f = wsi->http.ah->frags[f].nfrag;
+               }
+
+               return -1;
+       }
+#endif
+
+       /*
+        * The h1 way...
+        */
+
+       p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COOKIE);
+       if (!p)
+               return 1;
+
+       p += bl;
+       n -= (int)bl;
+       while (n-- > 0) {
+               if (*p == '=' && !memcmp(p - bl, name, (unsigned int)bl)) {
+                       p++;
+                       while (*p != ';' && n-- && max) {
+                               *buf++ = *p++;
+                               max--;
+                       }
+                       if (!max)
+                               return 2;
+
+                       *buf = '\0';
+                       *max_len = lws_ptr_diff_size_t(buf, bo);
+
+                       return 0;
+               }
+               p++;
+       }
+
+       return 1;
+}
+
+#if defined(LWS_WITH_JOSE)
+
+#define MAX_JWT_SIZE 1024
+
+int
+lws_jwt_get_http_cookie_validate_jwt(struct lws *wsi,
+                                    struct lws_jwt_sign_set_cookie *i,
+                                    char *out, size_t *out_len)
+{
+       char temp[MAX_JWT_SIZE * 2];
+       size_t cml = *out_len;
+       const char *cp;
+
+       /* first use out to hold the encoded JWT */
+
+       if (lws_http_cookie_get(wsi, i->cookie_name, out, out_len)) {
+               lwsl_debug("%s: cookie %s not provided\n", __func__,
+                               i->cookie_name);
+               return 1;
+       }
+
+       /* decode the JWT into temp */
+
+       if (lws_jwt_signed_validate(wsi->a.context, i->jwk, i->alg, out,
+                                   *out_len, temp, sizeof(temp), out, &cml)) {
+               lwsl_info("%s: jwt validation failed\n", __func__);
+               return 1;
+       }
+
+       /*
+        * Copy out the decoded JWT payload into out, overwriting the
+        * original encoded JWT taken from the cookie (that has long ago been
+        * translated into allocated buffers in the JOSE object)
+        */
+
+       if (lws_jwt_token_sanity(out, cml, i->iss, i->aud, i->csrf_in,
+                                i->sub, sizeof(i->sub),
+                                &i->expiry_unix_time)) {
+               lwsl_notice("%s: jwt sanity failed\n", __func__);
+               return 1;
+       }
+
+       /*
+        * If he's interested in his private JSON part, point him to that in
+        * the args struct (it's pointing to the data in out
+        */
+
+       cp = lws_json_simple_find(out, cml, "\"ext\":", &i->extra_json_len);
+       if (cp)
+               i->extra_json = cp;
+
+       if (!cp)
+               lwsl_notice("%s: no ext JWT payload\n", __func__);
+
+       return 0;
+}
+
+int
+lws_jwt_sign_token_set_http_cookie(struct lws *wsi,
+                                  const struct lws_jwt_sign_set_cookie *i,
+                                  uint8_t **p, uint8_t *end)
+{
+       char plain[MAX_JWT_SIZE + 1], temp[MAX_JWT_SIZE * 2], csrf[17];
+       size_t pl = sizeof(plain);
+       unsigned long long ull;
+       int n;
+
+       /*
+        * Create a 16-char random csrf token with the same lifetime as the JWT
+        */
+
+       lws_hex_random(wsi->a.context, csrf, sizeof(csrf));
+       ull = lws_now_secs();
+       if (lws_jwt_sign_compact(wsi->a.context, i->jwk, i->alg, plain, &pl,
+                                temp, sizeof(temp),
+                                "{\"iss\":\"%s\",\"aud\":\"%s\","
+                                 "\"iat\":%llu,\"nbf\":%llu,\"exp\":%llu,"
+                                 "\"csrf\":\"%s\",\"sub\":\"%s\"%s%s%s}",
+                                i->iss, i->aud, ull, ull - 60,
+                                ull + i->expiry_unix_time,
+                                csrf, i->sub,
+                                i->extra_json ? ",\"ext\":{" : "",
+                                i->extra_json ? i->extra_json : "",
+                                i->extra_json ? "}" : "")) {
+               lwsl_err("%s: failed to create JWT\n", __func__);
+
+               return 1;
+       }
+
+       /*
+        * There's no point the browser holding on to a JWT beyond the JWT's
+        * expiry time, so set it to be the same.
+        */
+
+       n = lws_snprintf(temp, sizeof(temp), "__Host-%s=%s;"
+                        "HttpOnly;"
+                        "Secure;"
+                        "SameSite=strict;"
+                        "Path=/;"
+                        "Max-Age=%lu",
+                        i->cookie_name, plain, i->expiry_unix_time);
+
+       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SET_COOKIE,
+                                        (uint8_t *)temp, n, p, end)) {
+               lwsl_err("%s: failed to add JWT cookie header\n", __func__);
+               return 1;
+       }
+
+       return 0;
+}
+#endif
similarity index 72%
rename from lib/roles/http/private.h
rename to lib/roles/http/private-lib-roles-http.h
index 1cc9960..94ee876 100644 (file)
@@ -1,24 +1,27 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
- *  This is included from core/private.h if either H1 or H2 roles are
+ *  This is included from private-lib-core.h if either H1 or H2 roles are
  *  enabled
  */
 
@@ -28,7 +31,7 @@
  #endif
 
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
-#include "roles/http/compression/private.h"
+#include "private-lib-roles-http-compression.h"
 #endif
 
 #define lwsi_role_http(wsi) (lwsi_role_h1(wsi) || lwsi_role_h2(wsi))
@@ -50,7 +53,7 @@ enum http_conn_type {
  * other APIs to get information out of it.
  */
 
-#if defined(LWS_WITH_ESP32)
+#if defined(LWS_PLAT_FREERTOS)
 typedef uint16_t ah_data_idx_t;
 #else
 typedef uint32_t ah_data_idx_t;
@@ -91,6 +94,8 @@ void
 lws_ranges_reset(struct lws_range_parsing *rp);
 #endif
 
+#define LWS_HTTP_NO_KNOWN_HEADER 0xff
+
 /*
  * these are assigned from a pool held in the context.
  * Both client and server mode uses them for http header analysis
@@ -114,7 +119,7 @@ struct allocated_headers {
         */
        uint8_t frag_index[WSI_TOKEN_COUNT];
 
-#ifndef LWS_NO_CLIENT
+#if defined(LWS_WITH_CLIENT)
        char initial_handshake_hash_base64[30];
 #endif
        int hdr_token_idx;
@@ -122,9 +127,9 @@ struct allocated_headers {
        ah_data_idx_t pos;
        ah_data_idx_t http_response;
        ah_data_idx_t current_token_limit;
+       ah_data_idx_t unk_pos; /* to undo speculative unknown header */
 
 #if defined(LWS_WITH_CUSTOM_HEADERS)
-       ah_data_idx_t unk_pos; /* to undo speculative unknown header */
        ah_data_idx_t unk_value_pos;
 
        ah_data_idx_t unk_ll_head;
@@ -188,10 +193,14 @@ struct lws_peer_role_http {
 };
 
 struct lws_vhost_role_http {
+#if defined(LWS_CLIENT_HTTP_PROXYING)
        char http_proxy_address[128];
+#endif
        const struct lws_http_mount *mount_list;
        const char *error_document_404;
+#if defined(LWS_CLIENT_HTTP_PROXYING)
        unsigned int http_proxy_port;
+#endif
 };
 
 #ifdef LWS_WITH_ACCESS_LOG
@@ -221,10 +230,16 @@ struct _lws_http_mode_related {
        struct allocated_headers *ah;
        struct lws *ah_wait_list;
 
+       unsigned long           writeable_len;
+
+#if defined(LWS_WITH_FILE_OPS)
        lws_filepos_t filepos;
        lws_filepos_t filelen;
        lws_fop_fd_t fop_fd;
-
+#endif
+#if defined(LWS_WITH_CLIENT)
+       char multipart_boundary[16];
+#endif
 #if defined(LWS_WITH_RANGES)
        struct lws_range_parsing range;
        char multipart_content_type[64];
@@ -233,8 +248,11 @@ struct _lws_http_mode_related {
 #ifdef LWS_WITH_ACCESS_LOG
        struct lws_access_log access_log;
 #endif
+#if defined(LWS_WITH_SERVER)
+       unsigned int response_code;
+#endif
 #ifdef LWS_WITH_CGI
-       struct lws_cgi *cgi; /* wsi being cgi master have one of these */
+       struct lws_cgi *cgi; /* wsi being cgi stream have one of these */
 #endif
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
        struct lws_compression_support *lcs;
@@ -256,17 +274,23 @@ struct _lws_http_mode_related {
 #endif
        unsigned int deferred_transaction_completed:1;
        unsigned int content_length_explicitly_zero:1;
+       unsigned int content_length_given:1;
        unsigned int did_stream_close:1;
+       unsigned int multipart:1;
+       unsigned int cgi_transaction_complete:1;
+       unsigned int multipart_issue_boundary:1;
 };
 
 
-#ifndef LWS_NO_CLIENT
+#if defined(LWS_WITH_CLIENT)
 enum lws_chunk_parser {
        ELCP_HEX,
        ELCP_CR,
        ELCP_CONTENT,
        ELCP_POST_CR,
        ELCP_POST_LF,
+       ELCP_TRAILER_CR,
+       ELCP_TRAILER_LF
 };
 #endif
 
@@ -284,7 +308,7 @@ enum lws_check_basic_auth_results {
 };
 
 enum lws_check_basic_auth_results
-lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file);
+lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file, unsigned int auth_mode);
 
 int
 lws_unauthorised_basic_auth(struct lws *wsi);
@@ -304,3 +328,24 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
 
 void
 lws_sul_http_ah_lifecheck(lws_sorted_usec_list_t *sul);
+
+uint8_t *
+lws_http_multipart_headers(struct lws *wsi, uint8_t *p);
+
+int
+lws_http_string_to_known_header(const char *s, size_t slen);
+
+int
+lws_http_date_render_from_unix(char *buf, size_t len, const time_t *t);
+
+int
+lws_http_date_parse_unix(const char *b, size_t len, time_t *t);
+
+enum {
+       CCTLS_RETURN_ERROR              = -1,
+       CCTLS_RETURN_DONE               = 0,
+       CCTLS_RETURN_RETRY              = 1,
+};
+
+int
+lws_client_create_tls(struct lws *wsi, const char **pcce, int do_c1);
index 74ae30e..1552019 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * libwebsockets - server access log handling
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /*
  * Produce Apache-compatible log string for wsi, like this:
@@ -40,45 +43,47 @@ static const char * const hver[] = {
 void
 lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int uri_len, int meth)
 {
-       char da[64], uri[256];
-       const char *pa, *me;
+       char da[64], uri[256], ta[64];
        time_t t = time(NULL);
+       struct lws *nwsi;
+       const char *me;
        int l = 256, m;
-#ifdef LWS_WITH_IPV6
-       char ads[INET6_ADDRSTRLEN];
-#else
-       char ads[INET_ADDRSTRLEN];
+       struct tm *ptm = NULL;
+#if defined(LWS_HAVE_LOCALTIME_R)
+       struct tm tm;
 #endif
-       struct tm *tmp;
 
-       if (!wsi->vhost)
+       if (!wsi->a.vhost)
                return;
 
        /* only worry about preparing it if we store it */
-       if (wsi->vhost->log_fd == (int)LWS_INVALID_FILE)
+       if (wsi->a.vhost->log_fd == (int)LWS_INVALID_FILE)
                return;
 
        if (wsi->access_log_pending)
                lws_access_log(wsi);
 
-       wsi->http.access_log.header_log = lws_malloc(l, "access log");
+       wsi->http.access_log.header_log = lws_malloc((unsigned int)l, "access log");
        if (!wsi->http.access_log.header_log)
                return;
 
-       tmp = localtime(&t);
-       if (tmp)
-               strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", tmp);
+#if defined(LWS_HAVE_LOCALTIME_R)
+       ptm = localtime_r(&t, &tm);
+#else
+       ptm = localtime(&t);
+#endif
+       if (ptm)
+               strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", ptm);
        else
                strcpy(da, "01/Jan/1970:00:00:00 +0000");
 
-       pa = lws_get_peer_simple(wsi, ads, sizeof(ads));
-       if (!pa)
-               pa = "(unknown)";
-
-       if (wsi->http2_substream)
+#if defined(LWS_ROLE_H2)
+       if (wsi->mux_substream)
                me = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
        else
+#endif
                me = method_names[meth];
+
        if (!me)
                me = "(null)";
 
@@ -86,19 +91,26 @@ lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int uri_len, int met
        if (m > (int)sizeof(uri) - 1)
                m = sizeof(uri) - 1;
 
-       strncpy(uri, uri_ptr, m);
+       strncpy(uri, uri_ptr, (unsigned int)m);
        uri[m] = '\0';
 
-       lws_snprintf(wsi->http.access_log.header_log, l,
+       nwsi = lws_get_network_wsi(wsi);
+
+       if (nwsi->sa46_peer.sa4.sin_family)
+               lws_sa46_write_numeric_address(&nwsi->sa46_peer, ta, sizeof(ta));
+       else
+               strncpy(ta, "unknown", sizeof(ta));
+
+       lws_snprintf(wsi->http.access_log.header_log, (size_t)l,
                     "%s - - [%s] \"%s %s %s\"",
-                    pa, da, me, uri, hver[wsi->http.request_version]);
+                    ta, da, me, uri, hver[wsi->http.request_version]);
 
        //lwsl_notice("%s\n", wsi->http.access_log.header_log);
 
        l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
        if (l) {
                wsi->http.access_log.user_agent =
-                               lws_malloc(l + 5, "access log");
+                               lws_malloc((unsigned int)l + 5, "access log");
                if (!wsi->http.access_log.user_agent) {
                        lwsl_err("OOM getting user agent\n");
                        lws_free_set_NULL(wsi->http.access_log.header_log);
@@ -114,7 +126,7 @@ lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int uri_len, int met
        }
        l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER);
        if (l) {
-               wsi->http.access_log.referrer = lws_malloc(l + 5, "referrer");
+               wsi->http.access_log.referrer = lws_malloc((unsigned int)l + 5, "referrer");
                if (!wsi->http.access_log.referrer) {
                        lwsl_err("OOM getting referrer\n");
                        lws_free_set_NULL(wsi->http.access_log.user_agent);
@@ -140,10 +152,10 @@ lws_access_log(struct lws *wsi)
             *p1 = wsi->http.access_log.referrer;
        int l;
 
-       if (!wsi->vhost)
+       if (!wsi->a.vhost)
                return 0;
 
-       if (wsi->vhost->log_fd == (int)LWS_INVALID_FILE)
+       if (wsi->a.vhost->log_fd == (int)LWS_INVALID_FILE)
                return 0;
 
        if (!wsi->access_log_pending)
@@ -167,15 +179,15 @@ lws_access_log(struct lws *wsi)
                         wsi->http.access_log.header_log,
                         wsi->http.access_log.response,
                         wsi->http.access_log.sent, p1);
-       if (strlen(p) > sizeof(ass) - 6 - l) {
-               p[sizeof(ass) - 6 - l] = '\0';
+       if (strlen(p) > sizeof(ass) - 6 - (unsigned int)l) {
+               p[sizeof(ass) - 6 - (unsigned int)l] = '\0';
                l--;
        }
-       l += lws_snprintf(ass + l, sizeof(ass) - 1 - l, "\" \"%s\"\n", p);
+       l += lws_snprintf(ass + (unsigned int)l, sizeof(ass) - 1 - (unsigned int)l, "\" \"%s\"\n", p);
 
        ass[sizeof(ass) - 1] = '\0';
 
-       if (write(wsi->vhost->log_fd, ass, l) != l)
+       if ((int)write(wsi->a.vhost->log_fd, ass, (size_t)l) != l)
                lwsl_err("Failed to write log\n");
 
        if (wsi->http.access_log.header_log) {
index 5c1d482..832dcfc 100644 (file)
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- *
- * lws rewrite:
- *
- * Copyright (C) 2017  Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * Somewhat rewritten by AG
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #if defined(LWS_WITH_MINIZ)
 #include <miniz.h>
@@ -162,6 +144,9 @@ enum {
        LWS_FZ_ERR_SEEK_COMPRESSED,
 };
 
+#define eff_size(_priv) (_priv->hdr.method == ZIP_COMPRESSION_METHOD_STORE ? \
+                                 _priv->hdr.uncomp_size : _priv->hdr.comp_size)
+
 static uint16_t
 get_u16(void *p)
 {
@@ -249,7 +234,7 @@ lws_fops_zip_scan(lws_fops_zip_t priv, const char *name, int len)
                        return LWS_FZ_ERR_NAME_TOO_LONG;
 
                if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
-                                                       &amount, buf, len))
+                                                       &amount, buf, (unsigned int)len))
                        return LWS_FZ_ERR_NAME_READ;
                if ((int)amount != len)
                        return LWS_FZ_ERR_NAME_READ;
@@ -282,7 +267,7 @@ lws_fops_zip_scan(lws_fops_zip_t priv, const char *name, int len)
                        return LWS_FZ_ERR_CONTENT_SANITY;
 
                if (lws_vfs_file_seek_set(priv->zip_fop_fd,
-                                         priv->content_start) < 0)
+                                         (lws_fileofs_t)priv->content_start) < 0)
                        return LWS_FZ_ERR_CONTENT_SEEK;
 
                /* we are aligned at the start of the content */
@@ -293,11 +278,11 @@ lws_fops_zip_scan(lws_fops_zip_t priv, const char *name, int len)
 
 next:
                if (i && lws_vfs_file_seek_set(priv->zip_fop_fd,
-                                              priv->content_start +
-                                              ZC_DIRECTORY_LENGTH +
+                                              (lws_fileofs_t)priv->content_start +
+                                              (ZC_DIRECTORY_LENGTH +
                                               priv->hdr.filename_len +
                                               priv->hdr.extra +
-                                              priv->hdr.file_com_len) < 0)
+                                              priv->hdr.file_com_len)) < 0)
                        return LWS_FZ_ERR_SCAN_SEEK;
        }
 
@@ -321,7 +306,7 @@ lws_fops_zip_reset_inflate(lws_fops_zip_t priv)
                return LWS_FZ_ERR_ZLIB_INIT;
        }
 
-       if (lws_vfs_file_seek_set(priv->zip_fop_fd, priv->content_start) < 0)
+       if (lws_vfs_file_seek_set(priv->zip_fop_fd, (lws_fileofs_t)priv->content_start) < 0)
                return LWS_FZ_ERR_CONTENT_SEEK;
 
        priv->exp_uncomp_pos = 0;
@@ -353,13 +338,13 @@ lws_fops_zip_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
        m = sizeof(rp) - 1;
        if ((vpath - vfs_path - 1) < m)
                m = lws_ptr_diff(vpath, vfs_path) - 1;
-       lws_strncpy(rp, vfs_path, m + 1);
+       lws_strncpy(rp, vfs_path, (unsigned int)m + 1);
 
        /* open the zip file itself using the incoming fops, not fops_zip */
 
        priv->zip_fop_fd = fops->LWS_FOP_OPEN(fops, rp, NULL, &local_flags);
        if (!priv->zip_fop_fd) {
-               lwsl_err("unable to open zip %s\n", rp);
+               lwsl_err("%s: unable to open zip %s\n", __func__, rp);
                goto bail1;
        }
 
@@ -503,9 +488,9 @@ lws_fops_zip_close(lws_fop_fd_t *fd)
 static lws_fileofs_t
 lws_fops_zip_seek_cur(lws_fop_fd_t fd, lws_fileofs_t offset_from_cur_pos)
 {
-       fd->pos += offset_from_cur_pos;
+       fd->pos = (lws_filepos_t)((lws_fileofs_t)fd->pos + offset_from_cur_pos);
 
-       return fd->pos;
+       return (lws_fileofs_t)fd->pos;
 }
 
 static int
@@ -544,11 +529,8 @@ lws_fops_zip_read(lws_fop_fd_t fd, lws_filepos_t *amount, uint8_t *buf,
 spin:
                if (!priv->inflate.avail_in) {
                        rlen = sizeof(priv->rbuf);
-                       if (rlen > priv->hdr.comp_size -
-                                  (cur - priv->content_start))
-                               rlen = priv->hdr.comp_size -
-                                      (priv->hdr.comp_size -
-                                       priv->content_start);
+                       if (rlen > eff_size(priv) - (cur - priv->content_start))
+                               rlen = eff_size(priv) - (cur - priv->content_start);
 
                        if (priv->zip_fop_fd->fops->LWS_FOP_READ(
                                        priv->zip_fop_fd, &ramount, priv->rbuf,
@@ -650,14 +632,15 @@ spin:
 
        lwsl_info("%s: store\n", __func__);
 
-       if (len > priv->hdr.uncomp_size - (cur - priv->content_start))
-               len = priv->hdr.comp_size - (priv->hdr.comp_size -
-                                            priv->content_start);
+       if (len > eff_size(priv) - cur)
+               len = eff_size(priv) - cur;
 
        if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
                                                 amount, buf, len))
                return LWS_FZ_ERR_READ_CONTENT;
 
+       fd->pos += *amount;
+
        return 0;
 }
 
index e8dfffd..98392d4 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * libwebsockets web server application
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #ifndef _WIN32
 /* this is needed for Travis CI */
@@ -37,11 +40,14 @@ static const char * const paths_global[] = {
        "global.init-ssl",
        "global.server-string",
        "global.plugin-dir",
-       "global.ws-pingpong-secs",
+       "global.ws-pingpong-secs", /* deprecated */
        "global.timeout-secs",
        "global.reject-service-keywords[].*",
        "global.reject-service-keywords[]",
        "global.default-alpn",
+       "global.ip-limit-ah",
+       "global.ip-limit-wsi",
+       "global.rlimit-nofile",
 };
 
 enum lejp_global_paths {
@@ -58,6 +64,9 @@ enum lejp_global_paths {
        LWJPGP_REJECT_SERVICE_KEYWORDS_NAME,
        LWJPGP_REJECT_SERVICE_KEYWORDS,
        LWJPGP_DEFAULT_ALPN,
+       LWJPGP_IP_LIMIT_AH,
+       LWJPGP_IP_LIMIT_WSI,
+       LWJPGP_FD_LIMIT_PT,
 };
 
 static const char * const paths_vhosts[] = {
@@ -110,6 +119,7 @@ static const char * const paths_vhosts[] = {
        "vhosts[].ignore-missing-cert",
        "vhosts[].error-document-404",
        "vhosts[].alpn",
+       "vhosts[].fo-listen-queue",
        "vhosts[].ssl-client-option-set",
        "vhosts[].ssl-client-option-clear",
        "vhosts[].tls13-ciphers",
@@ -125,6 +135,7 @@ static const char * const paths_vhosts[] = {
        "vhosts[].allow-http-on-https",
 
        "vhosts[].disable-no-protocol-ws-upgrades",
+       "vhosts[].h2-half-closed-long-poll",
 };
 
 enum lejp_vhost_paths {
@@ -177,6 +188,7 @@ enum lejp_vhost_paths {
        LEJPVP_IGNORE_MISSING_CERT,
        LEJPVP_ERROR_DOCUMENT_404,
        LEJPVP_ALPN,
+       LWJPVP_FO_LISTEN_QUEUE,
        LEJPVP_SSL_CLIENT_OPTION_SET,
        LEJPVP_SSL_CLIENT_OPTION_CLEAR,
        LEJPVP_TLS13_CIPHERS,
@@ -192,6 +204,7 @@ enum lejp_vhost_paths {
        LEJPVP_FLAG_ALLOW_HTTP_ON_HTTPS,
 
        LEJPVP_FLAG_DISABLE_NO_PROTOCOL_WS_UPGRADES,
+       LEJPVP_FLAG_H2_HALF_CLOSED_LONG_POLL,
 };
 
 #define MAX_PLUGIN_DIRS 10
@@ -247,7 +260,7 @@ arg_to_bool(const char *s)
 }
 
 static void
-set_reset_flag(unsigned int *p, const char *state, unsigned int flag)
+set_reset_flag(uint64_t *p, const char *state, uint64_t flag)
 {
        if (arg_to_bool(state))
                *p |= flag;
@@ -286,10 +299,10 @@ lejp_globals_cb(struct lejp_ctx *ctx, char reason)
 
        switch (ctx->path_match - 1) {
        case LEJPGP_UID:
-               a->info->uid = atoi(ctx->buf);
+               a->info->uid = (unsigned int)atoi(ctx->buf);
                return 0;
        case LEJPGP_GID:
-               a->info->gid = atoi(ctx->buf);
+               a->info->gid = (unsigned int)atoi(ctx->buf);
                return 0;
        case LEJPGP_USERNAME:
                a->info->username = a->p;
@@ -298,14 +311,16 @@ lejp_globals_cb(struct lejp_ctx *ctx, char reason)
                a->info->groupname = a->p;
                break;
        case LEJPGP_COUNT_THREADS:
-               a->info->count_threads = atoi(ctx->buf);
+               a->info->count_threads = (unsigned int)atoi(ctx->buf);
                return 0;
        case LWJPGP_INIT_SSL:
                if (arg_to_bool(ctx->buf))
                        a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                return 0;
        case LEJPGP_SERVER_STRING:
+#if defined(LWS_WITH_SERVER)
                a->info->server_string = a->p;
+#endif
                break;
        case LEJPGP_PLUGIN_DIR:
                if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
@@ -315,24 +330,39 @@ lejp_globals_cb(struct lejp_ctx *ctx, char reason)
                a->plugin_dirs[a->count_plugin_dirs++] = a->p;
                break;
 
-       case LWJPGP_PINGPONG_SECS:
-               a->info->ws_ping_pong_interval = atoi(ctx->buf);
+       case LWJPGP_PINGPONG_SECS: /* deprecated */
                return 0;
 
        case LWJPGP_TIMEOUT_SECS:
-               a->info->timeout_secs = atoi(ctx->buf);
+               a->info->timeout_secs = (unsigned int)atoi(ctx->buf);
                return 0;
 
+#if defined(LWS_WITH_TLS)
        case LWJPGP_DEFAULT_ALPN:
                a->info->alpn = a->p;
                break;
+#endif
+
+#if defined(LWS_WITH_PEER_LIMITS)
+       case LWJPGP_IP_LIMIT_AH:
+               a->info->ip_limit_ah = (uint16_t)atoi(ctx->buf);
+               return 0;
+
+       case LWJPGP_IP_LIMIT_WSI:
+               a->info->ip_limit_wsi = (uint16_t)atoi(ctx->buf);
+               return 0;
+#endif
+
+       case LWJPGP_FD_LIMIT_PT:
+               a->info->rlimit_nofile = atoi(ctx->buf);
+               return 0;
 
        default:
                return 0;
        }
 
 dostring:
-       a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf);
+       a->p += lws_snprintf(a->p, lws_ptr_diff_size_t(a->end, a->p), "%s", ctx->buf);
        *(a->p)++ = '\0';
 
        return 0;
@@ -355,7 +385,9 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
 
        if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
                uint32_t i[4];
+#if defined(LWS_WITH_SERVER)
                const char *ss;
+#endif
 
                /* set the defaults for this vhost */
                a->reject_ws_with_no_protocol = 0;
@@ -373,22 +405,27 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                        LWS_SERVER_OPTION_LIBEVENT |
                        LWS_SERVER_OPTION_LIBEV
                                );
+#if defined(LWS_WITH_SERVER)
                ss = a->info->server_string;
-               i[2] = a->info->ws_ping_pong_interval;
+#endif
                i[3] = a->info->timeout_secs;
 
                memset(a->info, 0, sizeof(*a->info));
 
                a->info->count_threads = i[0];
                a->info->options = i[1];
+#if defined(LWS_WITH_SERVER)
                a->info->server_string = ss;
-               a->info->ws_ping_pong_interval = i[2];
+#endif
                a->info->timeout_secs = i[3];
 
                a->info->protocols = a->protocols;
                a->info->pprotocols = a->pprotocols;
+#if defined(LWS_ROLE_WS)
                a->info->extensions = a->extensions;
+#endif
 #if defined(LWS_WITH_TLS)
+#if defined(LWS_WITH_CLIENT)
                a->info->client_ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
                        "ECDHE-RSA-AES256-GCM-SHA384:"
                        "DHE-RSA-AES256-GCM-SHA384:"
@@ -403,6 +440,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                        "!AES256-GCM-SHA384:"
                        "!AES256-SHA256";
 #endif
+#if defined(LWS_WITH_SERVER)
                a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
                                       "ECDHE-RSA-AES256-GCM-SHA384:"
                                       "DHE-RSA-AES256-GCM-SHA384:"
@@ -416,6 +454,8 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                                       "!DHE-RSA-AES256-SHA256:"
                                       "!AES256-GCM-SHA384:"
                                       "!AES256-SHA256";
+#endif
+#endif
                a->info->keepalive_timeout = 5;
        }
 
@@ -501,7 +541,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                        vhost->default_protocol_index = 255;
                }
 
-#if defined(LWS_WITH_TLS)
+#if defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
                if (a->enable_client_ssl) {
                        const char *cert_filepath =
                                        a->info->client_ssl_cert_filepath;
@@ -556,7 +596,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                        if (!strncmp(a->m.origin, mount_protocols[n],
                             strlen(mount_protocols[n]))) {
                                lwsl_info("----%s\n", a->m.origin);
-                               m->origin_protocol = n;
+                               m->origin_protocol = (uint8_t)(unsigned int)n;
                                m->origin = a->m.origin +
                                            strlen(mount_protocols[n]);
                                break;
@@ -591,19 +631,20 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                break;
        case LEJPVP_UNIXSKT:
                if (arg_to_bool(ctx->buf))
-                       a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
+                       a->info->options |= (uint64_t)LWS_SERVER_OPTION_UNIX_SOCK;
                else
-                       a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
+                       a->info->options &= (uint64_t)~(LWS_SERVER_OPTION_UNIX_SOCK);
                return 0;
        case LEJPVP_UNIXSKT_PERMS:
                a->info->unix_socket_perms = a->p;
                break;
        case LEJPVP_STS:
                if (arg_to_bool(ctx->buf))
-                       a->info->options |= LWS_SERVER_OPTION_STS;
+                       a->info->options |= (uint64_t)LWS_SERVER_OPTION_STS;
                else
-                       a->info->options &= ~(LWS_SERVER_OPTION_STS);
+                       a->info->options &= (uint64_t)~(LWS_SERVER_OPTION_STS);
                return 0;
+#if defined(LWS_WITH_TLS)
        case LEJPVP_HOST_SSL_KEY:
                a->info->ssl_private_key_filepath = a->p;
                break;
@@ -613,6 +654,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
        case LEJPVP_HOST_SSL_CA:
                a->info->ssl_ca_filepath = a->p;
                break;
+#endif
        case LEJPVP_ACCESS_LOG:
                a->info->log_filepath = a->p;
                break;
@@ -631,47 +673,54 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                a->m.def = a->p;
                break;
        case LEJPVP_DEFAULT_AUTH_MASK:
-               a->m.auth_mask = atoi(ctx->buf);
+               a->m.auth_mask = (unsigned int)atoi(ctx->buf);
                return 0;
        case LEJPVP_MOUNT_CACHE_MAX_AGE:
                a->m.cache_max_age = atoi(ctx->buf);
                return 0;
        case LEJPVP_MOUNT_CACHE_REUSE:
-               a->m.cache_reusable = arg_to_bool(ctx->buf);
+               a->m.cache_reusable = !!arg_to_bool(ctx->buf);
                return 0;
        case LEJPVP_MOUNT_CACHE_REVALIDATE:
-               a->m.cache_revalidate = arg_to_bool(ctx->buf);
+               a->m.cache_revalidate = !!arg_to_bool(ctx->buf);
                return 0;
        case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
-               a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
+               a->m.cache_intermediaries = !!arg_to_bool(ctx->buf);;
                return 0;
        case LEJPVP_MOUNT_BASIC_AUTH:
+#if defined(LWS_WITH_HTTP_BASIC_AUTH)
                a->m.basic_auth_login_file = a->p;
+#endif
                break;
        case LEJPVP_CGI_TIMEOUT:
                a->m.cgi_timeout = atoi(ctx->buf);
                return 0;
+       case LWJPVP_FO_LISTEN_QUEUE:
+               a->info->fo_listen_queue = atoi(ctx->buf);
+               return 0;
        case LEJPVP_KEEPALIVE_TIMEOUT:
                a->info->keepalive_timeout = atoi(ctx->buf);
                return 0;
 #if defined(LWS_WITH_TLS)
+#if defined(LWS_WITH_CLIENT)
        case LEJPVP_CLIENT_CIPHERS:
                a->info->client_ssl_cipher_list = a->p;
                break;
+       case LEJPVP_CLIENT_TLS13_CIPHERS:
+               a->info->client_tls_1_3_plus_cipher_list = a->p;
+               break;
 #endif
+
        case LEJPVP_CIPHERS:
                a->info->ssl_cipher_list = a->p;
                break;
        case LEJPVP_TLS13_CIPHERS:
                a->info->tls1_3_plus_cipher_list = a->p;
                break;
-       case LEJPVP_CLIENT_TLS13_CIPHERS:
-               a->info->client_tls_1_3_plus_cipher_list = a->p;
-               break;
-
        case LEJPVP_ECDH_CURVE:
                a->info->ecdh_curve = a->p;
                break;
+#endif
        case LEJPVP_PMO:
        case LEJPVP_CGI_ENV:
                mp_cgienv = lwsws_align(a);
@@ -739,9 +788,9 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                break;
 
        case LEJPVP_ENABLE_CLIENT_SSL:
-               a->enable_client_ssl = arg_to_bool(ctx->buf);
+               a->enable_client_ssl = !!arg_to_bool(ctx->buf);
                return 0;
-#if defined(LWS_WITH_TLS)
+#if defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
        case LEJPVP_CLIENT_SSL_KEY:
                a->info->client_ssl_private_key_filepath = a->p;
                break;
@@ -789,6 +838,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                a->info->error_document_404 = a->p;
                break;
 
+#if defined(LWS_WITH_TLS)
        case LEJPVP_SSL_OPTION_SET:
                a->info->ssl_options_set |= atol(ctx->buf);
                return 0;
@@ -796,16 +846,19 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                a->info->ssl_options_clear |= atol(ctx->buf);
                return 0;
 
+#if defined(LWS_WITH_CLIENT)
        case LEJPVP_SSL_CLIENT_OPTION_SET:
                a->info->ssl_client_options_set |= atol(ctx->buf);
                return 0;
        case LEJPVP_SSL_CLIENT_OPTION_CLEAR:
                a->info->ssl_client_options_clear |= atol(ctx->buf);
                return 0;
+#endif
 
        case LEJPVP_ALPN:
                a->info->alpn = a->p;
                break;
+#endif
 
        case LEJPVP_LISTEN_ACCEPT_ROLE:
                a->info->listen_accept_role = a->p;
@@ -841,6 +894,11 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
                a->reject_ws_with_no_protocol = 1;
                return 0;
 
+       case LEJPVP_FLAG_H2_HALF_CLOSED_LONG_POLL:
+               set_reset_flag(&a->info->options, ctx->buf,
+                               LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL);
+               return 0;
+
        default:
                return 0;
        }
@@ -853,14 +911,14 @@ dostring:
                n = lws_ptr_diff(p1, p);
                if (n > a->end - a->p)
                        n = lws_ptr_diff(a->end, a->p);
-               lws_strncpy(a->p, p, n + 1);
+               lws_strncpy(a->p, p, (unsigned int)n + 1u);
                a->p += n;
-               a->p += lws_snprintf(a->p, a->end - a->p, "%s",
+               a->p += lws_snprintf(a->p, lws_ptr_diff_size_t(a->end, a->p), "%s",
                                     LWS_INSTALL_DATADIR);
-               p += n + strlen(ESC_INSTALL_DATADIR);
+               p += n + (int)strlen(ESC_INSTALL_DATADIR);
        }
 
-       a->p += lws_snprintf(a->p, a->end - a->p, "%s", p);
+       a->p += lws_snprintf(a->p, lws_ptr_diff_size_t(a->end, a->p), "%s", p);
        if (reason == LEJPCB_VAL_STR_END)
                *(a->p)++ = '\0';
 
@@ -885,18 +943,18 @@ lwsws_get_config(void *user, const char *f, const char * const *paths,
                return 2;
        }
        lwsl_info("%s: %s\n", __func__, f);
-       lejp_construct(&ctx, cb, user, paths, count_paths);
+       lejp_construct(&ctx, cb, user, paths, (uint8_t)(unsigned int)count_paths);
 
        do {
-               n = read(fd, buf, sizeof(buf));
+               n = (int)read(fd, buf, sizeof(buf));
                if (!n)
                        break;
 
-               m = (int)(signed char)lejp_parse(&ctx, buf, n);
+               m = lejp_parse(&ctx, buf, n);
        } while (m == LEJP_CONTINUE);
 
        close(fd);
-       n = ctx.line;
+       n = (int32_t)ctx.line;
        lejp_destruct(&ctx);
 
        if (m < 0) {
@@ -937,7 +995,9 @@ lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
 {
        struct lws_dir_args da;
        struct jpargs a;
+#if defined(LWS_WITH_PLUGINS)
        const char * const *old = info->plugin_dirs;
+#endif
        char dd[128];
 
        memset(&a, 0, sizeof(a));
@@ -948,16 +1008,20 @@ lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
        a.valid = 0;
 
        lwsws_align(&a);
+#if defined(LWS_WITH_PLUGINS)
        info->plugin_dirs = (void *)a.p;
+#endif
        a.plugin_dirs = (void *)a.p; /* writeable version */
        a.p += MAX_PLUGIN_DIRS * sizeof(void *);
 
+#if defined(LWS_WITH_PLUGINS)
        /* copy any default paths */
 
        while (old && *old) {
                a.plugin_dirs[a.count_plugin_dirs++] = *old;
                old++;
        }
+#endif
 
        lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
        if (lwsws_get_config(&a, dd, paths_global,
@@ -999,7 +1063,9 @@ lwsws_get_config_vhosts(struct lws_context *context,
        a.context = context;
        a.protocols = info->protocols;
        a.pprotocols = info->pprotocols;
+#if defined(LWS_ROLE_WS)
        a.extensions = info->extensions;
+#endif
 
        lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
        if (lwsws_get_config(&a, dd, paths_vhosts,
index 0414016..a39c661 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * libwebsockets - Stateful urldecode for POST
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #define LWS_MAX_ELEM_NAME 32
 
@@ -123,7 +126,8 @@ lws_urldecode_s_create(struct lws_spa *spa, struct lws *wsi, char *out,
        /* multipart/form-data;
         * boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */
 
-               if (!strncmp(buf, "multipart/form-data", 19)) {
+               if (!strncmp(buf, "multipart/form-data", 19) ||
+                   !strncmp(buf, "multipart/related", 17)) {
                        s->multipart_form_data = 1;
                        s->state = MT_LOOK_BOUND_IN;
                        s->mp = 2;
@@ -134,13 +138,14 @@ lws_urldecode_s_create(struct lws_spa *spa, struct lws *wsi, char *out,
                                s->mime_boundary[m++] = '\x0a';
                                s->mime_boundary[m++] = '-';
                                s->mime_boundary[m++] = '-';
+                               if (*p == '\"')
+                                       p++;
                                while (m < (int)sizeof(s->mime_boundary) - 1 &&
-                                      *p && *p != ' ')
+                                      *p && *p != ' ' && *p != ';' && *p != '\"')
                                        s->mime_boundary[m++] = *p++;
-
                                s->mime_boundary[m] = '\0';
 
-                               lwsl_info("boundary '%s'\n", s->mime_boundary);
+                               // lwsl_notice("boundary '%s'\n", s->mime_boundary);
                        }
                }
        }
@@ -153,7 +158,7 @@ lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in,
                        int len)
 {
        int n, hit;
-       char c, was_end = 0;
+       char c;
 
        while (len--) {
                if (s->pos == s->out_len - s->mp - 1) {
@@ -161,7 +166,6 @@ lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in,
                                      LWS_UFS_CONTENT))
                                return -1;
 
-                       was_end = s->pos;
                        s->pos = 0;
                }
 
@@ -189,7 +193,8 @@ lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in,
                                continue;
                        }
                        if (s->pos >= (int)sizeof(s->name) - 1) {
-                               lwsl_notice("Name too long\n");
+                               lwsl_hexdump_notice(s->name, (size_t)s->pos);
+                               lwsl_notice("Name too long...\n");
                                return -1;
                        }
                        s->name[s->pos++] = *in++;
@@ -233,7 +238,7 @@ lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in,
                                return -1;
 
                        in++;
-                       s->out[s->pos++] = s->sum | n;
+                       s->out[s->pos++] = (char)(s->sum | n);
                        s->state = US_IDLE;
                        break;
 
@@ -250,11 +255,10 @@ retry_as_first:
                                        s->mp = 0;
                                        s->state = MT_IGNORE1;
 
-                                       if (s->pos || was_end)
-                                               if (s->output(s->data, s->name,
+                                       if (s->output(s->data, s->name,
                                                      &s->out, s->pos,
                                                      LWS_UFS_FINAL_CONTENT))
-                                                       return -1;
+                                               return -1;
 
                                        s->pos = 0;
 
@@ -271,7 +275,8 @@ retry_as_first:
                                        n = 2;
                                if (s->mp >= n) {
                                        memcpy(s->out + s->pos,
-                                              s->mime_boundary + n, s->mp - n);
+                                              s->mime_boundary + n,
+                                              (unsigned int)(s->mp - n));
                                        s->pos += s->mp;
                                        s->mp = 0;
                                        goto retry_as_first;
@@ -286,7 +291,7 @@ retry_as_first:
                case MT_HNAME:
                        c =*in;
                        if (c >= 'A' && c <= 'Z')
-                               c += 'a' - 'A';
+                               c = (char)(c + 'a' - 'A');
                        if (!s->mp)
                                /* initially, any of them might match */
                                s->matchable = (1 << LWS_ARRAY_SIZE(mp_hdrs)) - 1; 
@@ -300,13 +305,13 @@ retry_as_first:
 
                                if (s->mp >= mp_hdrs[n].hdr_len) {
                                        /* he went past the end of it */
-                                       s->matchable &= ~(1 << n);
+                                       s->matchable &= (uint8_t)~(1 << n);
                                        continue;
                                }
 
                                if (c != mp_hdrs[n].hdr[s->mp]) {
                                        /* mismatched a char */
-                                       s->matchable &= ~(1 << n);
+                                       s->matchable &= (uint8_t)~(1 << n);
                                        continue;
                                }
 
@@ -338,7 +343,7 @@ retry_as_first:
                        if (hit == 2)
                                s->state = MT_LOOK_BOUND_IN;
                        else
-                               s->state += hit + 1;
+                               s->state += (unsigned int)hit + 1u;
                        break;
 
                case MT_DISP:
@@ -361,7 +366,7 @@ retry_as_first:
                        }
 
                        if (*in == '\"') {
-                               s->inside_quote ^= 1;
+                               s->inside_quote = !!((s->inside_quote ^ 1) & 1);
                                goto done;
                        }
 
@@ -434,11 +439,11 @@ done:
                case MT_IGNORE3:
                        if (*in == '\x0d')
                                s->state = MT_IGNORE1;
-                       if (*in == '-') {
+                       else if (*in == '-') {
                                s->state = MT_COMPLETED;
                                s->wsi->http.rx_content_remain = 0;
                        }
-                       in++;
+                       else in++;
                        break;
                case MT_COMPLETED:
                        break;
@@ -499,7 +504,7 @@ lws_urldecode_spa_cb(struct lws_spa *spa, const char *name, char **buf, int len,
                if (spa->i.opt_cb) {
                        n = spa->i.opt_cb(spa->i.opt_data, name,
                                        spa->s->content_disp_filename,
-                                       buf ? *buf : NULL, len, final);
+                                       buf ? *buf : NULL, len, (enum lws_spa_fileupload_states)final);
 
                        if (n < 0)
                                return -1;
@@ -525,12 +530,12 @@ lws_urldecode_spa_cb(struct lws_spa *spa, const char *name, char **buf, int len,
 
                spa->s->out_len -= len + 1;
        } else {
-               spa->params[n] = lwsac_use(spa->i.ac, len + 1,
+               spa->params[n] = lwsac_use(spa->i.ac, (unsigned int)len + 1,
                                           spa->i.ac_chunk_size);
                if (!spa->params[n])
                        return -1;
 
-               memcpy(spa->params[n], *buf, len);
+               memcpy(spa->params[n], *buf, (unsigned int)len);
                spa->params[n][len] = '\0';
        }
 
@@ -557,10 +562,10 @@ lws_spa_create_via_info(struct lws *wsi, const lws_spa_create_info_t *i)
                spa->i.max_storage = 512;
 
        if (i->ac)
-               spa->storage = lwsac_use(i->ac, spa->i.max_storage,
+               spa->storage = lwsac_use(i->ac, (unsigned int)spa->i.max_storage,
                                         i->ac_chunk_size);
        else
-               spa->storage = lws_malloc(spa->i.max_storage, "spa");
+               spa->storage = lws_malloc((unsigned int)spa->i.max_storage, "spa");
 
        if (!spa->storage)
                goto bail2;
@@ -570,9 +575,9 @@ lws_spa_create_via_info(struct lws *wsi, const lws_spa_create_info_t *i)
        if (i->count_params) {
                if (i->ac)
                        spa->params = lwsac_use_zero(i->ac,
-                               sizeof(char *) * i->count_params, i->ac_chunk_size);
+                               sizeof(char *) * (unsigned int)i->count_params, i->ac_chunk_size);
                else
-                       spa->params = lws_zalloc(sizeof(char *) * i->count_params,
+                       spa->params = lws_zalloc(sizeof(char *) * (unsigned int)i->count_params,
                                         "spa params");
                if (!spa->params)
                        goto bail3;
@@ -586,15 +591,15 @@ lws_spa_create_via_info(struct lws *wsi, const lws_spa_create_info_t *i)
        if (i->count_params) {
                if (i->ac)
                        spa->param_length = lwsac_use_zero(i->ac,
-                               sizeof(int) * i->count_params, i->ac_chunk_size);
+                               sizeof(int) * (unsigned int)i->count_params, i->ac_chunk_size);
                else
-                       spa->param_length = lws_zalloc(sizeof(int) * i->count_params,
+                       spa->param_length = lws_zalloc(sizeof(int) * (unsigned int)i->count_params,
                                                "spa param len");
                if (!spa->param_length)
                        goto bail5;
        }
 
-       lwsl_info("%s: Created SPA %p\n", __func__, spa);
+       // lwsl_notice("%s: Created SPA %p\n", __func__, spa);
 
        return spa;
 
index 56ba748..15026b5 100644 (file)
@@ -1,27 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * RFC7233 ranges parser
- *
- * Copyright (C) 2016 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /*
  * RFC7233 examples
@@ -110,7 +111,7 @@ lws_ranges_next(struct lws_range_parsing *rp)
                                rp->state = LWSRS_SYNTAX;
                                return 0;
                        }
-                       rp->start = (rp->start * 10) + (c - '0');
+                       rp->start = (unsigned long long)(((unsigned long long)rp->start * 10) + (unsigned long long)(c - '0'));
                        rp->start_valid = 1;
                        break;
 
@@ -152,7 +153,7 @@ lws_ranges_next(struct lws_range_parsing *rp)
                                rp->state = LWSRS_SYNTAX;
                                return 0;
                        }
-                       rp->end = (rp->end * 10) + (c - '0');
+                       rp->end = (unsigned long long)(((unsigned long long)rp->end * 10) + (unsigned long long)(c - '0'));
                        rp->end_valid = 1;
                        break;
                }
index eca443a..16aaabd 100644 (file)
@@ -1,8 +1,8 @@
-#include "core/private.h"
+#include "private-lib-core.h"
 
 #if defined(LWS_WITH_HUBBUB)
 
-LWS_EXTERN struct lws_rewrite *
+struct lws_rewrite *
 lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from,
                   const char *to)
 {
@@ -35,7 +35,7 @@ lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from,
        return r;
 }
 
-LWS_EXTERN int
+int
 lws_rewrite_parse(struct lws_rewrite *r,
                  const unsigned char *in, int in_len)
 {
@@ -45,7 +45,7 @@ lws_rewrite_parse(struct lws_rewrite *r,
        return 0;
 }
 
-LWS_EXTERN void
+void
 lws_rewrite_destroy(struct lws_rewrite *r)
 {
        hubbub_parser_destroy(r->parser);
index 6bec745..c7eb94c 100644 (file)
@@ -1,34 +1,47 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
+
+#if !defined(SOL_TCP) && defined(IPPROTO_TCP)
+#define SOL_TCP IPPROTO_TCP
+#endif
 
 const char * const method_names[] = {
-       "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", "CONNECT", "HEAD",
+       "GET", "POST",
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
+       "OPTIONS", "PUT", "PATCH", "DELETE",
+#endif
+       "CONNECT", "HEAD",
 #ifdef LWS_WITH_HTTP2
        ":path",
 #endif
        };
 
+#if defined(LWS_WITH_FILE_OPS)
 static const char * const intermediates[] = { "private", "public" };
+#endif
 
 /*
  * return 0: all done
@@ -38,73 +51,85 @@ static const char * const intermediates[] = { "private", "public" };
  *       REQUIRES CONTEXT LOCK HELD
  */
 
-#ifndef LWS_NO_SERVER
+#if defined(LWS_WITH_SERVER)
+
+struct vh_sock_args {
+       const struct lws_context_creation_info  *info;
+       struct lws_vhost                        *vhost;
+       int                                     af;
+};
+
+
+static int
+check_extant(struct lws_dll2 *d, void *user)
+{
+       struct lws *wsi = lws_container_of(d, struct lws, listen_list);
+       struct vh_sock_args *a = (struct vh_sock_args *)user;
+
+       if (!lws_vhost_compare_listen(wsi->a.vhost, a->vhost))
+               return 0;
+
+       if (wsi->af != a ->af)
+               return 0;
+
+       lwsl_notice(" using listen skt from vhost %s\n", wsi->a.vhost->name);
+
+       return 1;
+}
+
+/*
+ * Creates a single listen socket of a specific AF
+ */
+
 int
-_lws_vhost_init_server(const struct lws_context_creation_info *info,
-                      struct lws_vhost *vhost)
+_lws_vhost_init_server_af(struct vh_sock_args *a)
 {
+       struct lws_context *cx = a->vhost->context;
+       struct lws_context_per_thread *pt;
        int n, opt = 1, limit = 1;
        lws_sockfd_type sockfd;
-       struct lws_vhost *vh;
        struct lws *wsi;
        int m = 0, is;
+#if defined(LWS_WITH_IPV6)
+       int value = 1;
+#endif
 
        (void)method_names;
        (void)opt;
 
-       if (info) {
-               vhost->iface = info->iface;
-               vhost->listen_port = info->port;
-       }
-
-       /* set up our external listening socket we serve on */
+       lwsl_info("%s: af %d\n", __func__, (int)a->af);
 
-       if (vhost->listen_port == CONTEXT_PORT_NO_LISTEN ||
-           vhost->listen_port == CONTEXT_PORT_NO_LISTEN_SERVER)
+       if (lws_vhost_foreach_listen_wsi(a->vhost->context, a, check_extant))
                return 0;
 
-       vh = vhost->context->vhost_list;
-       while (vh) {
-               if (vh->listen_port == vhost->listen_port) {
-                       if (((!vhost->iface && !vh->iface) ||
-                           (vhost->iface && vh->iface &&
-                           !strcmp(vhost->iface, vh->iface))) &&
-                          vh->lserv_wsi
-                       ) {
-                               lwsl_notice(" using listen skt from vhost %s\n",
-                                           vh->name);
-                               return 0;
-                       }
-               }
-               vh = vh->vhost_next;
-       }
+deal:
+
+       if (a->vhost->iface) {
 
-       if (vhost->iface) {
                /*
                 * let's check before we do anything else about the disposition
                 * of the interface he wants to bind to...
                 */
-               is = lws_socket_bind(vhost, LWS_SOCK_INVALID, vhost->listen_port,
-                               vhost->iface, 1);
+               is = lws_socket_bind(a->vhost, NULL, LWS_SOCK_INVALID,
+                                    a->vhost->listen_port, a->vhost->iface,
+                                    a->af);
                lwsl_debug("initial if check says %d\n", is);
 
                if (is == LWS_ITOSA_BUSY)
                        /* treat as fatal */
                        return -1;
 
-deal:
-
                lws_start_foreach_llp(struct lws_vhost **, pv,
-                                     vhost->context->no_listener_vhost_list) {
-                       if (is >= LWS_ITOSA_USABLE && *pv == vhost) {
+                                     cx->no_listener_vhost_list) {
+                       if (is >= LWS_ITOSA_USABLE && *pv == a->vhost) {
                                /* on the list and shouldn't be: remove it */
                                lwsl_debug("deferred iface: removing vh %s\n",
                                                (*pv)->name);
-                               *pv = vhost->no_listener_vhost_list;
-                               vhost->no_listener_vhost_list = NULL;
+                               *pv = a->vhost->no_listener_vhost_list;
+                               a->vhost->no_listener_vhost_list = NULL;
                                goto done_list;
                        }
-                       if (is < LWS_ITOSA_USABLE && *pv == vhost)
+                       if (is < LWS_ITOSA_USABLE && *pv == a->vhost)
                                goto done_list;
                } lws_end_foreach_llp(pv, no_listener_vhost_list);
 
@@ -114,10 +139,11 @@ deal:
 
                        /* ... but needs to be: so add it */
 
-                       lwsl_debug("deferred iface: adding vh %s\n", vhost->name);
-                       vhost->no_listener_vhost_list =
-                                       vhost->context->no_listener_vhost_list;
-                       vhost->context->no_listener_vhost_list = vhost;
+                       lwsl_debug("deferred iface: adding vh %s\n",
+                                       a->vhost->name);
+                       a->vhost->no_listener_vhost_list =
+                                       cx->no_listener_vhost_list;
+                       cx->no_listener_vhost_list = a->vhost;
                }
 
 done_list:
@@ -127,59 +153,62 @@ done_list:
                        break;
                case LWS_ITOSA_NOT_EXIST:
                        /* can't add it */
-                       if (info) /* first time */
-                               lwsl_err("VH %s: iface %s port %d DOESN'T EXIST\n",
-                                vhost->name, vhost->iface, vhost->listen_port);
-                       else
+                       if (!a->info)
                                return -1;
-                       return (info->options & LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) == LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND?
+
+                       /* first time */
+                       lwsl_err("%s: VH %s: iface %s port %d DOESN'T EXIST\n",
+                                __func__, a->vhost->name, a->vhost->iface,
+                                a->vhost->listen_port);
+
+                       return (a->info->options &
+                               LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
+                               LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ?
                                -1 : 1;
+
                case LWS_ITOSA_NOT_USABLE:
                        /* can't add it */
-                       if (info) /* first time */
-                               lwsl_err("VH %s: iface %s port %d NOT USABLE\n",
-                                vhost->name, vhost->iface, vhost->listen_port);
-                       else
+                       if (!a->info) /* first time */
                                return -1;
-                       return (info->options & LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) == LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND?
+
+                       lwsl_err("%s: VH %s: iface %s port %d NOT USABLE\n",
+                                __func__, a->vhost->name, a->vhost->iface,
+                                a->vhost->listen_port);
+
+                       return (a->info->options &
+                               LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
+                               LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ?
                                -1 : 1;
                }
        }
 
        (void)n;
 #if defined(__linux__)
-#ifdef LWS_WITH_UNIX_SOCK
        /*
-        * A Unix domain sockets cannot be bound for several times, even if we set
-        * the SO_REUSE* options on.
-        * However, fortunately, each thread is able to independently listen when
-        * running on a reasonably new Linux kernel. So we can safely assume
-        * creating just one listening socket for a multi-threaded environment won't
-        * fail in most cases.
+        * A Unix domain sockets cannot be bound multiple times, even if we
+        * set the SO_REUSE* options on.
+        *
+        * However on recent linux, each thread is able to independently listen.
+        *
+        * So we can assume creating just one listening socket for a multi-
+        * threaded environment will typically work.
         */
-       if (!LWS_UNIX_SOCK_ENABLED(vhost))
-#endif
-       limit = vhost->context->count_threads;
+       if (a->af != AF_UNIX)
+               limit = cx->count_threads;
 #endif
 
        for (m = 0; m < limit; m++) {
-#ifdef LWS_WITH_UNIX_SOCK
-               if (LWS_UNIX_SOCK_ENABLED(vhost))
-                       sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
-               else
-#endif
-#ifdef LWS_WITH_IPV6
-               if (LWS_IPV6_ENABLED(vhost))
-                       sockfd = socket(AF_INET6, SOCK_STREAM, 0);
-               else
-#endif
-                       sockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+               sockfd = lws_fi(&a->vhost->fic, "listenskt") ?
+                                       LWS_SOCK_INVALID :
+                                       socket(a->af, SOCK_STREAM, 0);
 
                if (sockfd == LWS_SOCK_INVALID) {
                        lwsl_err("ERROR opening socket\n");
                        return 1;
                }
-#if !defined(LWS_WITH_ESP32)
+
+#if !defined(LWS_PLAT_FREERTOS)
 #if (defined(WIN32) || defined(_WIN32)) && defined(SO_EXCLUSIVEADDRUSE)
                /*
                 * only accept that we are the only listener on the port
@@ -188,7 +217,7 @@ done_list:
                 *
                 * for lws, to match Linux, we default to exclusive listen
                 */
-               if (!lws_check_opt(vhost->options,
+               if (!lws_check_opt(a->vhost->options,
                                LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE)) {
                        if (setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
                                       (const void *)&opt, sizeof(opt)) < 0) {
@@ -210,15 +239,17 @@ done_list:
                }
 
 #if defined(LWS_WITH_IPV6) && defined(IPV6_V6ONLY)
-               if (LWS_IPV6_ENABLED(vhost) &&
-                   vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) {
-                       int value = (vhost->options &
-                               LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE) ? 1 : 0;
-                       if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
-                                     (const void*)&value, sizeof(value)) < 0) {
-                               compatible_close(sockfd);
-                               return -1;
-                       }
+               /*
+                * If we have an ipv6 listen socket, it only accepts ipv6.
+                *
+                * There will be a separate ipv4 listen socket if that's
+                * enabled.
+                */
+               if (a->af == AF_INET6 &&
+                   setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
+                              (const void*)&value, sizeof(value)) < 0) {
+                       compatible_close(sockfd);
+                       return -1;
                }
 #endif
 
@@ -227,10 +258,10 @@ done_list:
 #if LWS_MAX_SMP > 1
                n = 1;
 #else
-               n = lws_check_opt(vhost->options,
+               n = lws_check_opt(a->vhost->options,
                                  LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE);
 #endif
-               if (n && vhost->context->count_threads > 1)
+               if (n || cx->count_threads > 1) /* ... also implied by threads > 1 */
                        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
                                        (const void *)&opt, sizeof(opt)) < 0) {
                                compatible_close(sockfd);
@@ -238,9 +269,12 @@ done_list:
                        }
 #endif
 #endif
-               lws_plat_set_socket_options(vhost, sockfd, 0);
+               lws_plat_set_socket_options(a->vhost, sockfd, 0);
+
+               is = lws_socket_bind(a->vhost, NULL, sockfd,
+                                    a->vhost->listen_port,
+                                    a->vhost->iface, a->af);
 
-               is = lws_socket_bind(vhost, sockfd, vhost->listen_port, vhost->iface, 1);
                if (is == LWS_ITOSA_BUSY) {
                        /* treat as fatal */
                        compatible_close(sockfd);
@@ -256,61 +290,105 @@ done_list:
                if (is < 0) {
                        lwsl_info("%s: lws_socket_bind says %d\n", __func__, is);
                        compatible_close(sockfd);
-                       goto deal;
+                       if (a->vhost->iface)
+                               goto deal;
+                       return -1;
                }
 
-               wsi = lws_zalloc(sizeof(struct lws), "listen wsi");
+               /*
+                * Create the listen wsi and customize it
+                */
+
+               lws_context_lock(cx, __func__);
+               wsi = __lws_wsi_create_with_role(cx, m, &role_ops_listen, NULL);
+               lws_context_unlock(cx);
                if (wsi == NULL) {
                        lwsl_err("Out of mem\n");
                        goto bail;
                }
 
+               wsi->af = (uint8_t)a->af;
+
 #ifdef LWS_WITH_UNIX_SOCK
-               if (!LWS_UNIX_SOCK_ENABLED(vhost))
+               if (!LWS_UNIX_SOCK_ENABLED(a->vhost))
 #endif
                {
                        wsi->unix_skt = 1;
-                       vhost->listen_port = is;
+                       a->vhost->listen_port = is;
 
                        lwsl_debug("%s: lws_socket_bind says %d\n", __func__, is);
                }
 
-               wsi->context = vhost->context;
                wsi->desc.sockfd = sockfd;
-               lws_role_transition(wsi, 0, LRS_UNCONNECTED, &role_ops_listen);
-               wsi->protocol = vhost->protocols;
-               wsi->tsi = m;
-               lws_vhost_bind_wsi(vhost, wsi);
+               wsi->a.protocol = a->vhost->protocols;
+               lws_vhost_bind_wsi(a->vhost, wsi);
                wsi->listener = 1;
 
-               if (wsi->context->event_loop_ops->init_vhost_listen_wsi)
-                       wsi->context->event_loop_ops->init_vhost_listen_wsi(wsi);
+               if (wsi->a.context->event_loop_ops->init_vhost_listen_wsi)
+                       wsi->a.context->event_loop_ops->init_vhost_listen_wsi(wsi);
 
-               if (__insert_wsi_socket_into_fds(vhost->context, wsi)) {
+               pt = &cx->pt[m];
+               lws_pt_lock(pt, __func__);
+
+               if (__insert_wsi_socket_into_fds(cx, wsi)) {
                        lwsl_notice("inserting wsi socket into fds failed\n");
+                       lws_pt_unlock(pt);
                        goto bail;
                }
 
-               vhost->context->count_wsi_allocated++;
-               vhost->lserv_wsi = wsi;
+               lws_dll2_add_tail(&wsi->listen_list, &a->vhost->listen_wsi);
+               lws_pt_unlock(pt);
+
+#if defined(WIN32) && defined(TCP_FASTOPEN)
+               if (a->vhost->fo_listen_queue) {
+                       int optval = 1;
+                       if (setsockopt(wsi->desc.sockfd, IPPROTO_TCP,
+                                      TCP_FASTOPEN,
+                                      (const char*)&optval, sizeof(optval)) < 0) {
+                               int error = LWS_ERRNO;
+                               lwsl_warn("%s: TCP_NODELAY failed with error %d\n",
+                                               __func__, error);
+                       }
+               }
+#else
+#if defined(TCP_FASTOPEN)
+               if (a->vhost->fo_listen_queue) {
+                       int qlen = a->vhost->fo_listen_queue;
+
+                       if (setsockopt(wsi->desc.sockfd, SOL_TCP, TCP_FASTOPEN,
+                                      &qlen, sizeof(qlen)))
+                               lwsl_warn("%s: TCP_FASTOPEN failed\n", __func__);
+               }
+#endif
+#endif
 
                n = listen(wsi->desc.sockfd, LWS_SOMAXCONN);
                if (n < 0) {
                        lwsl_err("listen failed with error %d\n", LWS_ERRNO);
-                       vhost->lserv_wsi = NULL;
-                       vhost->context->count_wsi_allocated--;
+                       lws_dll2_remove(&wsi->listen_list);
                        __remove_wsi_socket_from_fds(wsi);
                        goto bail;
                }
+
+               if (wsi)
+                       __lws_lc_tag(a->vhost->context,
+                                    &a->vhost->context->lcg[LWSLCG_WSI],
+                                    &wsi->lc, "listen|%s|%s|%d",
+                                    a->vhost->name,
+                                    a->vhost->iface ? a->vhost->iface : "",
+                                    (int)a->vhost->listen_port);
+
        } /* for each thread able to independently listen */
 
-       if (!lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
+       if (!lws_check_opt(cx->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
 #ifdef LWS_WITH_UNIX_SOCK
-               if (LWS_UNIX_SOCK_ENABLED(vhost))
-                       lwsl_info(" Listening on \"%s\"\n", vhost->iface);
+               if (a->af == AF_UNIX)
+                       lwsl_info(" Listening on \"%s\"\n", a->vhost->iface);
                else
 #endif
-                       lwsl_info(" Listening on port %d\n", vhost->listen_port);
+                       lwsl_info(" Listening on %s:%d\n",
+                                       a->vhost->iface,
+                                       a->vhost->listen_port);
         }
 
        // info->port = vhost->listen_port;
@@ -322,6 +400,102 @@ bail:
 
        return -1;
 }
+
+
+int
+_lws_vhost_init_server(const struct lws_context_creation_info *info,
+                      struct lws_vhost *vhost)
+{
+       struct vh_sock_args a;
+
+       a.info = info;
+       a.vhost = vhost;
+
+       if (info) {
+               vhost->iface = info->iface;
+               vhost->listen_port = info->port;
+       }
+
+       /* set up our external listening socket we serve on */
+
+       if (vhost->listen_port == CONTEXT_PORT_NO_LISTEN ||
+           vhost->listen_port == CONTEXT_PORT_NO_LISTEN_SERVER)
+               return 0;
+
+       /*
+        * Let's figure out what AF(s) we want this vhost to listen on.
+        *
+        * We want AF_UNIX alone if that's what's told
+        */
+
+#if defined(LWS_WITH_UNIX_SOCK)
+       /*
+        * If unix socket, ask for that and we are done
+        */
+       if (LWS_UNIX_SOCK_ENABLED(vhost)) {
+               a.af = AF_UNIX;
+               goto single;
+       }
+#endif
+
+       /*
+        * We may support both ipv4 and ipv6, but get a numeric vhost listen
+        * iface that is unambiguously ipv4 or ipv6, meaning we can only listen
+        * for the related AF then.
+        */
+
+       if (vhost->iface) {
+               uint8_t buf[16];
+               int q;
+
+               q = lws_parse_numeric_address(vhost->iface, buf, sizeof(buf));
+
+               if (q == 4) {
+                       a.af = AF_INET;
+                       goto single;
+               }
+
+               if (q == 16) {
+#if defined(LWS_WITH_IPV6)
+                       if (LWS_IPV6_ENABLED(vhost)) {
+                               a.af = AF_INET6;
+                               goto single;
+                       }
+#endif
+                       lwsl_err("%s: ipv6 not supported on %s\n", __func__,
+                                       vhost->name);
+                       return 1;
+               }
+       }
+
+       /*
+        * ... if we make it here, we would want to listen on AF_INET and
+        * AF_INET6 unless one or the other is forbidden
+        */
+
+#if defined(LWS_WITH_IPV6)
+       if (!(LWS_IPV6_ENABLED(vhost) &&
+             (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) &&
+             (vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE))) {
+#endif
+               a.af = AF_INET;
+               if (_lws_vhost_init_server_af(&a))
+                       return 1;
+
+#if defined(LWS_WITH_IPV6)
+       }
+       if (LWS_IPV6_ENABLED(vhost)) {
+               a.af = AF_INET6;
+               goto single;
+       }
+#endif
+
+       return 0;
+
+single:
+       return _lws_vhost_init_server_af(&a);
+}
+
 #endif
 
 struct lws_vhost *
@@ -341,7 +515,7 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername)
 
        while (vhost) {
                if (port == vhost->listen_port &&
-                   !strncmp(vhost->name, servername, colon)) {
+                   !strncmp(vhost->name, servername, (unsigned int)colon)) {
                        lwsl_info("SNI: Found: %s\n", servername);
                        return vhost;
                }
@@ -361,7 +535,7 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername)
                if (port && port == vhost->listen_port &&
                    m <= (colon - 2) &&
                    servername[colon - m - 1] == '.' &&
-                   !strncmp(vhost->name, servername + colon - m, m)) {
+                   !strncmp(vhost->name, servername + colon - m, (unsigned int)m)) {
                        lwsl_info("SNI: Found %s on wildcard: %s\n",
                                    servername, vhost->name);
                        return vhost;
@@ -408,9 +582,10 @@ static const struct lws_mimetype {
        { ".txt", "text/plain" },
        { ".xml", "application/xml" },
        { ".json", "application/json" },
+       { ".mjs", "text/javascript" },
 };
 
-LWS_VISIBLE LWS_EXTERN const char *
+const char *
 lws_get_mimetype(const char *file, const struct lws_http_mount *m)
 {
        const struct lws_protocol_vhost_options *pvo;
@@ -428,7 +603,8 @@ lws_get_mimetype(const char *file, const struct lws_http_mount *m)
 
                len = strlen(pvo->name);
                if (n > len && !strcasecmp(&file[n - len], pvo->name)) {
-                       lwsl_info("%s: match to user mimetype: %s\n", __func__, pvo->value);
+                       lwsl_info("%s: match to user mimetype: %s\n", __func__,
+                                 pvo->value);
                        return pvo->value;
                }
        }
@@ -439,20 +615,23 @@ lws_get_mimetype(const char *file, const struct lws_http_mount *m)
 
                len = strlen(mt->extension);
                if (n > len && !strcasecmp(&file[n - len], mt->extension)) {
-                       lwsl_info("%s: match to server mimetype: %s\n", __func__, mt->mimetype);
+                       lwsl_info("%s: match to server mimetype: %s\n", __func__,
+                                 mt->mimetype);
                        return mt->mimetype;
                }
        }
 
        /* fallback to '*' if defined */
        if (fallback_mimetype) {
-               lwsl_info("%s: match to any mimetype: %s\n", __func__, fallback_mimetype);
+               lwsl_info("%s: match to any mimetype: %s\n", __func__,
+                         fallback_mimetype);
                return fallback_mimetype;
        }
 
        return NULL;
 }
 
+#if defined(LWS_WITH_FILE_OPS)
 static lws_fop_flags_t
 lws_vfs_prepare_flags(struct lws *wsi)
 {
@@ -470,7 +649,6 @@ lws_vfs_prepare_flags(struct lws *wsi)
        return f;
 }
 
-#if !defined(LWS_AMAZON_RTOS)
 static int
 lws_http_serve(struct lws *wsi, char *uri, const char *origin,
               const struct lws_http_mount *m)
@@ -492,18 +670,18 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
        char path[256], sym[2048];
        unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
        unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
-#if !defined(WIN32) && !defined(LWS_WITH_ESP32)
+#if !defined(WIN32) && !defined(LWS_PLAT_FREERTOS)
        size_t len;
 #endif
        int n;
 
        wsi->handling_404 = 0;
-       if (!wsi->vhost)
+       if (!wsi->a.vhost)
                return -1;
 
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       if (wsi->vhost->http.error_document_404 &&
-           !strcmp(uri, wsi->vhost->http.error_document_404))
+       if (wsi->a.vhost->http.error_document_404 &&
+           !strcmp(uri, wsi->a.vhost->http.error_document_404))
                wsi->handling_404 = 1;
 #endif
 
@@ -515,12 +693,12 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
 
        do {
                spin++;
-               fops = lws_vfs_select_fops(wsi->context->fops, path, &vpath);
+               fops = lws_vfs_select_fops(wsi->a.context->fops, path, &vpath);
 
                if (wsi->http.fop_fd)
                        lws_vfs_file_close(&wsi->http.fop_fd);
 
-               wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->context->fops,
+               wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->a.context->fops,
                                                        path, vpath, &fflags);
                if (!wsi->http.fop_fd) {
                        lwsl_info("%s: Unable to open '%s': errno %d\n",
@@ -532,7 +710,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
                /* if it can't be statted, don't try */
                if (fflags & LWS_FOP_FLAG_VIRTUAL)
                        break;
-#if defined(LWS_WITH_ESP32)
+#if defined(LWS_PLAT_FREERTOS)
                break;
 #endif
 #if !defined(WIN32)
@@ -542,9 +720,13 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
                }
 #else
 #if defined(LWS_HAVE__STAT32I64)
-               if (_stat32i64(path, &st)) {
-                       lwsl_info("unable to stat %s\n", path);
-                       goto notfound;
+               {
+                       WCHAR buf[MAX_PATH];
+                       MultiByteToWideChar(CP_UTF8, 0, path, -1, buf, LWS_ARRAY_SIZE(buf));
+                       if (_wstat32i64(buf, &st)) {
+                               lwsl_info("unable to stat %s\n", path);
+                               goto notfound;
+                       }
                }
 #else
                if (stat(path, &st)) {
@@ -557,9 +739,9 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
                wsi->http.fop_fd->mod_time = (uint32_t)st.st_mtime;
                fflags |= LWS_FOP_FLAG_MOD_TIME_VALID;
 
-#if !defined(WIN32) && !defined(LWS_WITH_ESP32)
+#if !defined(WIN32) && !defined(LWS_PLAT_FREERTOS)
                if ((S_IFMT & st.st_mode) == S_IFLNK) {
-                       len = readlink(path, sym, sizeof(sym) - 1);
+                       len = (size_t)readlink(path, sym, sizeof(sym) - 1);
                        if (len) {
                                lwsl_err("Failed to read link %s\n", path);
                                goto notfound;
@@ -571,8 +753,8 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
 #endif
                if ((S_IFMT & st.st_mode) == S_IFDIR) {
                        lwsl_debug("default filename append to dir\n");
-                       lws_snprintf(path, sizeof(path) - 1, "%s/%s/index.html",
-                                origin, uri);
+                       lws_snprintf(path, sizeof(path) - 1, "%s/%s/%s",
+                                origin, uri, m->def ? m->def : "index.html");
                }
 
        } while ((S_IFMT & st.st_mode) != S_IFREG && spin < 5);
@@ -644,10 +826,10 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
                        if (lws_finalize_http_header(wsi, &p, end))
                                return -1;
 
-                       n = lws_write(wsi, start, p - start,
+                       n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
                                      LWS_WRITE_HTTP_HEADERS |
                                      LWS_WRITE_H2_STREAM_END);
-                       if (n != (p - start)) {
+                       if (n != lws_ptr_diff(p, start)) {
                                lwsl_err("_write returned %d from %ld\n", n,
                                         (long)(p - start));
                                return -1;
@@ -690,21 +872,21 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
        while (pvo) {
                n = (int)strlen(path);
                if (n > (int)strlen(pvo->name) &&
-                   !strcmp(&path[n - strlen(pvo->name)], pvo->name)) {
+                   !strcmp(&path[(unsigned int)n - strlen(pvo->name)], pvo->name)) {
                        wsi->interpreting = 1;
-                       if (!wsi->http2_substream)
+                       if (!wsi->mux_substream)
                                wsi->sending_chunked = 1;
 
                        wsi->protocol_interpret_idx = (char)(
-                               lws_vhost_name_to_protocol(wsi->vhost,
+                               lws_vhost_name_to_protocol(wsi->a.vhost,
                                                           pvo->value) -
                                &lws_get_vhost(wsi)->protocols[0]);
 
                        lwsl_debug("want %s interpreted by %s (pcol is %s)\n", path,
-                                   wsi->vhost->protocols[
+                                   wsi->a.vhost->protocols[
                                             (int)wsi->protocol_interpret_idx].name,
-                                            wsi->protocol->name);
-                       if (lws_bind_protocol(wsi, &wsi->vhost->protocols[
+                                            wsi->a.protocol->name);
+                       if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[
                                  (int)wsi->protocol_interpret_idx], __func__))
                                return -1;
 
@@ -725,7 +907,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
 
        if (m->protocol) {
                const struct lws_protocols *pp = lws_vhost_name_to_protocol(
-                                                      wsi->vhost, m->protocol);
+                                                      wsi->a.vhost, m->protocol);
 
                if (lws_bind_protocol(wsi, pp, __func__))
                        return -1;
@@ -759,7 +941,7 @@ lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)
        const struct lws_http_mount *hm, *hit = NULL;
        int best = 0;
 
-       hm = wsi->vhost->http.mount_list;
+       hm = wsi->a.vhost->http.mount_list;
        while (hm) {
                if (uri_len >= hm->mountpoint_len &&
                    !strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len) &&
@@ -767,14 +949,25 @@ lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)
                     uri_ptr[hm->mountpoint_len] == '/' ||
                     hm->mountpoint_len == 1)
                    ) {
+#if defined(LWS_WITH_SYS_METRICS)
+                       lws_metrics_tag_wsi_add(wsi, "mnt", hm->mountpoint);
+#endif
+
                        if (hm->origin_protocol == LWSMPRO_CALLBACK ||
                            ((hm->origin_protocol == LWSMPRO_CGI ||
                             lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||
                             lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
+                            lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI) ||
+                            lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
+                            lws_hdr_total_length(wsi, WSI_TOKEN_DELETE_URI) ||
+#endif
                             lws_hdr_total_length(wsi, WSI_TOKEN_HEAD_URI) ||
-                            (wsi->http2_substream &&
+#if defined(LWS_ROLE_H2)
+                            (wsi->mux_substream &&
                                lws_hdr_total_length(wsi,
                                                WSI_TOKEN_HTTP_COLON_PATH)) ||
+#endif
                             hm->protocol) &&
                            hm->mountpoint_len > best)) {
                                best = hm->mountpoint_len;
@@ -788,7 +981,7 @@ lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)
 }
 #endif
 
-#if !defined(LWS_WITH_ESP32)
+#if defined(LWS_WITH_HTTP_BASIC_AUTH) && !defined(LWS_PLAT_FREERTOS) && defined(LWS_WITH_FILE_OPS)
 static int
 lws_find_string_in_file(const char *filename, const char *string, int stringlen)
 {
@@ -803,7 +996,7 @@ lws_find_string_in_file(const char *filename, const char *string, int stringlen)
 
        while (1) {
                if (pos == n) {
-                       n = read(fd, buf, sizeof(buf));
+                       n = (int)read(fd, buf, sizeof(buf));
                        if (n <= 0) {
                                if (match == stringlen)
                                        hit = 1;
@@ -834,10 +1027,12 @@ lws_find_string_in_file(const char *filename, const char *string, int stringlen)
 }
 #endif
 
+#if defined(LWS_WITH_HTTP_BASIC_AUTH)
+
 int
 lws_unauthorised_basic_auth(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        unsigned char *start = pt->serv_buf + LWS_PRE,
                      *p = start, *end = p + 2048;
        char buf[64];
@@ -860,7 +1055,7 @@ lws_unauthorised_basic_auth(struct lws *wsi)
        if (lws_finalize_http_header(wsi, &p, end))
                return -1;
 
-       n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS |
+       n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_HTTP_HEADERS |
                                             LWS_WRITE_H2_STREAM_END);
        if (n < 0)
                return -1;
@@ -869,6 +1064,8 @@ lws_unauthorised_basic_auth(struct lws *wsi)
 
 }
 
+#endif
+
 int lws_clean_url(char *p)
 {
        if (p[0] == 'h' && p[1] == 't' && p[2] == 't' && p[3] == 'p') {
@@ -900,10 +1097,12 @@ int lws_clean_url(char *p)
 static const unsigned char methods[] = {
        WSI_TOKEN_GET_URI,
        WSI_TOKEN_POST_URI,
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
        WSI_TOKEN_OPTIONS_URI,
        WSI_TOKEN_PUT_URI,
        WSI_TOKEN_PATCH_URI,
        WSI_TOKEN_DELETE_URI,
+#endif
        WSI_TOKEN_CONNECT,
        WSI_TOKEN_HEAD_URI,
 #ifdef LWS_WITH_HTTP2
@@ -925,8 +1124,12 @@ lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)
        }
 
        if (count != 1 &&
-           !((wsi->http2_substream || wsi->h2_stream_carries_ws) &&
-             lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH))) {
+           !((wsi->mux_substream || wsi->h2_stream_carries_ws)
+#if defined(LWS_ROLE_H2)
+                           &&
+             lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH)
+#endif
+             )) {
                lwsl_warn("multiple methods?\n");
                return -1;
        }
@@ -941,13 +1144,17 @@ lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len)
        return -1;
 }
 
+#if defined(LWS_WITH_HTTP_BASIC_AUTH)
+
 enum lws_check_basic_auth_results
-lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file)
+lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file,
+                    unsigned int auth_mode)
 {
+#if defined(LWS_WITH_FILE_OPS)
        char b64[160], plain[(sizeof(b64) * 3) / 4], *pcolon;
-       int m, ml, fi;
+       int m, ml, fi, bar;
 
-       if (!basic_auth_login_file)
+       if (!basic_auth_login_file && auth_mode == LWSAUTHM_DEFAULT)
                return LCBA_CONTINUE;
 
        /* Did he send auth? */
@@ -990,8 +1197,23 @@ lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file)
                lwsl_err("basic auth format broken\n");
                return LCBA_END_TRANSACTION;
        }
-       if (!lws_find_string_in_file(basic_auth_login_file, plain, m)) {
-               lwsl_err("basic auth lookup failed\n");
+
+       switch (auth_mode) {
+       case LWSAUTHM_DEFAULT:
+               if (lws_find_string_in_file(basic_auth_login_file, plain, m))
+                       break;
+               lwsl_err("%s: basic auth lookup failed\n", __func__);
+               return LCBA_FAILED_AUTH;
+
+       case LWSAUTHM_BASIC_AUTH_CALLBACK:
+               bar = wsi->a.protocol->callback(wsi,
+                               LWS_CALLBACK_VERIFY_BASIC_AUTHORIZATION,
+                               wsi->user_space, plain, (unsigned int)m);
+               if (!bar)
+                       return LCBA_FAILED_AUTH;
+               break;
+       default:
+               /* Invalid auth mode so lets fail all authentication attempts */
                return LCBA_FAILED_AUTH;
        }
 
@@ -1001,16 +1223,21 @@ lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file)
         */
 
        *pcolon = '\0';
-       wsi->http.ah->frags[fi].len = lws_ptr_diff(pcolon, plain);
+       wsi->http.ah->frags[fi].len = (uint16_t)lws_ptr_diff_size_t(pcolon, &plain[0]);
        pcolon = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_AUTHORIZATION);
-       strncpy(pcolon, plain, ml - 1);
+       strncpy(pcolon, plain, (unsigned int)(ml - 1));
        pcolon[ml - 1] = '\0';
        lwsl_info("%s: basic auth accepted for %s\n", __func__,
                 lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_AUTHORIZATION));
 
        return LCBA_CONTINUE;
+#else
+       return LCBA_FAILED_AUTH;
+#endif
 }
 
+#endif
+
 #if defined(LWS_WITH_HTTP_PROXY)
 /*
  * Set up an onward http proxy connection according to the mount this
@@ -1021,11 +1248,14 @@ int
 lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
                     char *uri_ptr, char ws)
 {
-       char ads[96], rpath[256], host[96], *pcolon, *pslash, unix_skt = 0;
+       char ads[96], host[96], *pcolon, *pslash, unix_skt = 0;
        struct lws_client_connect_info i;
        struct lws *cwsi;
        int n, na;
+       unsigned int max_http_header_data = wsi->a.context->max_http_header_data > 256 ? wsi->a.context->max_http_header_data : 256;
+       char rpath[max_http_header_data];
 
+#if defined(LWS_ROLE_WS)
        if (ws)
                /*
                 * Neither our inbound ws upgrade request side, nor our onward
@@ -1042,7 +1272,7 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
                 * the .local_protocol_name.
                 */
                lws_bind_protocol(wsi, &lws_ws_proxy, __func__);
-
+#endif
        memset(&i, 0, sizeof(i));
        i.context = lws_get_context(wsi);
 
@@ -1078,7 +1308,7 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
                        n = sizeof(ads) - 2;
        }
 
-       memcpy(ads, hit->origin, n);
+       memcpy(ads, hit->origin, (unsigned int)n);
        ads[n] = '\0';
 
        i.address = ads;
@@ -1090,14 +1320,24 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
        if (pcolon)
                i.port = atoi(pcolon + 1);
 
-       n = lws_snprintf(rpath, sizeof(rpath) - 1, "/%s/%s",
-                        pslash + 1, uri_ptr + hit->mountpoint_len) - 2;
+       n = lws_snprintf(rpath, max_http_header_data - 1, "/%s/%s",
+                        pslash + 1, uri_ptr + hit->mountpoint_len) - 1;
        lws_clean_url(rpath);
+       n = (int)strlen(rpath);
+       if (n && rpath[n - 1] == '/')
+               n--;
+
        na = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_URI_ARGS);
        if (na) {
-               char *p = rpath + n;
+               char *p;
+               int budg;
+
+               if (!n) /* don't start with the ?... use the first / if so */
+                       n++;
 
-               if (na >= (int)sizeof(rpath) - n - 2) {
+               p = rpath + n;
+
+               if (na >= (int)max_http_header_data - n - 2) {
                        lwsl_info("%s: query string %d longer "
                                  "than we can handle\n", __func__,
                                  na);
@@ -1106,28 +1346,30 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
                }
 
                *p++ = '?';
-               if (lws_hdr_copy(wsi, p,
-                            (int)(&rpath[sizeof(rpath) - 1] - p),
-                            WSI_TOKEN_HTTP_URI_ARGS) > 0)
-                       while (na--) {
-                               if (*p == '\0')
-                                       *p = '&';
-                               p++;
-                       }
+               budg = lws_hdr_copy(wsi, p,
+                            (int)(&rpath[max_http_header_data - 1] - p),
+                            WSI_TOKEN_HTTP_URI_ARGS);
+              if (budg > 0)
+                      p += budg;
+
                *p = '\0';
        }
 
        i.path = rpath;
+       lwsl_notice("%s: proxied path '%s'\n", __func__, i.path);
 
        /* incoming may be h1 or h2... if he sends h1 HOST, use that
         * directly, otherwise we must convert h2 :authority to h1
         * host */
 
        i.host = NULL;
+#if defined(LWS_ROLE_H2)
        n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY);
        if (n > 0)
                i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_AUTHORITY);
-       else {
+       else
+#endif
+       {
                n = lws_hdr_total_length(wsi, WSI_TOKEN_HOST);
                if (n > 0) {
                        i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST);
@@ -1147,18 +1389,49 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
 #if defined(LWS_WITH_HTTP2)
                                                                || (
                        lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
-                       !strcmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD), "post")
+                       !strcmp(lws_hdr_simple_ptr(wsi,
+                                       WSI_TOKEN_HTTP_COLON_METHOD), "post")
                        )
 #endif
                )
                        i.method = "POST";
+               else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PUT_URI)
+#if defined(LWS_WITH_HTTP2)
+                                                               || (
+                       lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
+                       !strcmp(lws_hdr_simple_ptr(wsi,
+                                       WSI_TOKEN_HTTP_COLON_METHOD), "put")
+                       )
+#endif
+               )
+                       i.method = "PUT";
+               else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PATCH_URI)
+#if defined(LWS_WITH_HTTP2)
+                                                               || (
+                       lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
+                       !strcmp(lws_hdr_simple_ptr(wsi,
+                                       WSI_TOKEN_HTTP_COLON_METHOD), "patch")
+                       )
+#endif
+               )
+                       i.method = "PATCH";
+               else if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_DELETE_URI)
+#if defined(LWS_WITH_HTTP2)
+                                                               || (
+                       lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
+                       !strcmp(lws_hdr_simple_ptr(wsi,
+                                       WSI_TOKEN_HTTP_COLON_METHOD), "delete")
+                       )
+#endif
+               )
+                       i.method = "DELETE";
                else
                        i.method = "GET";
        }
 
        if (i.host)
                lws_snprintf(host, sizeof(host), "%s:%u", i.host,
-                                       wsi->vhost->listen_port);
+                                       wsi->a.vhost->listen_port);
        else
                lws_snprintf(host, sizeof(host), "%s:%d", i.address, i.port);
 
@@ -1167,9 +1440,11 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
        i.alpn = "http/1.1";
        i.parent_wsi = wsi;
        i.pwsi = &cwsi;
+#if defined(LWS_ROLE_WS)
        i.protocol = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);
        if (ws)
                i.local_protocol_name = "lws-ws-proxy";
+#endif
 
 //     i.uri_replace_from = hit->origin;
 //     i.uri_replace_to = hit->mountpoint;
@@ -1196,15 +1471,16 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
                return 1;
        }
 
-       lwsl_info("%s: setting proxy clientside on %p (parent %p)\n",
-                 __func__, cwsi, lws_get_parent(cwsi));
+       lwsl_info("%s: setting proxy clientside on %s (parent %s)\n",
+                 __func__, lws_wsi_tag(cwsi), lws_wsi_tag(lws_get_parent(cwsi)));
 
        cwsi->http.proxy_clientside = 1;
        if (ws) {
                wsi->proxied_ws_parent = 1;
                cwsi->h1_ws_proxied = 1;
                if (i.protocol) {
-                       lwsl_debug("%s: (requesting '%s')\n", __func__, i.protocol);
+                       lwsl_debug("%s: (requesting '%s')\n",
+                                       __func__, i.protocol);
                }
        }
 
@@ -1212,30 +1488,125 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
 }
 #endif
 
+
 static const char * const oprot[] = {
        "http://", "https://"
 };
 
+
+static int
+lws_http_redirect_hit(struct lws_context_per_thread *pt, struct lws *wsi,
+                     const struct lws_http_mount *hit, char *uri_ptr,
+                     int uri_len, int *h)
+{
+       char *s;
+       int n;
+
+       *h = 0;
+       s = uri_ptr + hit->mountpoint_len;
+
+       /*
+        * if we have a mountpoint like https://xxx.com/yyy
+        * there is an implied / at the end for our purposes since
+        * we can only mount on a "directory".
+        *
+        * But if we just go with that, the browser cannot understand
+        * that he is actually looking down one "directory level", so
+        * even though we give him /yyy/abc.html he acts like the
+        * current directory level is /.  So relative urls like "x.png"
+        * wrongly look outside the mountpoint.
+        *
+        * Therefore if we didn't come in on a url with an explicit
+        * / at the end, we must redirect to add it so the browser
+        * understands he is one "directory level" down.
+        */
+       if ((hit->mountpoint_len > 1 ||
+            (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
+             hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
+           (*s != '/' ||
+            (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
+             hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
+           (hit->origin_protocol != LWSMPRO_CGI &&
+            hit->origin_protocol != LWSMPRO_CALLBACK)) {
+               unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
+                             *end = p + wsi->a.context->pt_serv_buf_size -
+                                       LWS_PRE - 512;
+
+               *h = 1;
+
+               lwsl_info("Doing 301 '%s' org %s\n", s, hit->origin);
+
+               /* > at start indicates deal with by redirect */
+               if (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
+                   hit->origin_protocol == LWSMPRO_REDIR_HTTPS)
+                       n = lws_snprintf((char *)end, 256, "%s%s",
+                                   oprot[hit->origin_protocol & 1],
+                                   hit->origin);
+               else {
+                       if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
+#if defined(LWS_ROLE_H2)
+                               if (!lws_hdr_total_length(wsi,
+                                               WSI_TOKEN_HTTP_COLON_AUTHORITY))
+#endif
+                                       goto bail_nuke_ah;
+#if defined(LWS_ROLE_H2)
+                               n = lws_snprintf((char *)end, 256,
+                                   "%s%s%s/", oprot[!!lws_is_ssl(wsi)],
+                                   lws_hdr_simple_ptr(wsi,
+                                               WSI_TOKEN_HTTP_COLON_AUTHORITY),
+                                   uri_ptr);
+#else
+                               ;
+#endif
+                       } else
+                               n = lws_snprintf((char *)end, 256,
+                                   "%s%s%s/", oprot[!!lws_is_ssl(wsi)],
+                                   lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
+                                   uri_ptr);
+               }
+
+               lws_clean_url((char *)end);
+               n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
+                                     end, n, &p, end);
+               if ((int)n < 0)
+                       goto bail_nuke_ah;
+
+               return lws_http_transaction_completed(wsi);
+       }
+
+       return 0;
+
+bail_nuke_ah:
+       lws_header_table_detach(wsi, 1);
+
+       return 1;
+}
+
 int
 lws_http_action(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       int uri_len = 0, meth, m, http_version_len, ha;
        const struct lws_http_mount *hit = NULL;
        enum http_version request_version;
        struct lws_process_html_args args;
        enum http_conn_type conn_type;
        char content_length_str[32];
        char http_version_str[12];
-       char *uri_ptr = NULL, *s;
-       int uri_len = 0, meth, m;
        char http_conn_str[25];
-       int http_version_len;
+       char *uri_ptr = NULL;
+#if defined(LWS_WITH_FILE_OPS)
+       char *s;
+#endif
        unsigned int n;
 
        meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
        if (meth < 0 || meth >= (int)LWS_ARRAY_SIZE(method_names))
                goto bail_nuke_ah;
 
+       lws_metrics_tag_wsi_add(wsi, "vh", wsi->a.vhost->name);
+       lws_metrics_tag_wsi_add(wsi, "meth", method_names[meth]);
+
        /* we insist on absolute paths */
 
        if (!uri_ptr || uri_ptr[0] != '/') {
@@ -1247,8 +1618,11 @@ lws_http_action(struct lws *wsi)
        lwsl_info("Method: '%s' (%d), request for '%s'\n", method_names[meth],
                  meth, uri_ptr);
 
-       if (wsi->role_ops && wsi->role_ops->check_upgrades)
-               switch (wsi->role_ops->check_upgrades(wsi)) {
+       if (wsi->role_ops &&
+           lws_rops_fidx(wsi->role_ops, LWS_ROPS_check_upgrades))
+               switch (lws_rops_func_fidx(wsi->role_ops,
+                                          LWS_ROPS_check_upgrades).
+                                                       check_upgrades(wsi)) {
                case LWS_UPG_RET_DONE:
                        return 0;
                case LWS_UPG_RET_CONTINUE:
@@ -1264,9 +1638,13 @@ lws_http_action(struct lws *wsi)
 
        wsi->http.rx_content_length = 0;
        wsi->http.content_length_explicitly_zero = 0;
-       if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||
+       if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
+                       ||
            lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) ||
-           lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))
+           lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI)
+#endif
+           )
                wsi->http.rx_content_length = 100 * 1024 * 1024;
 
        if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
@@ -1274,14 +1652,14 @@ lws_http_action(struct lws *wsi)
                         sizeof(content_length_str) - 1,
                         WSI_TOKEN_HTTP_CONTENT_LENGTH) > 0) {
                wsi->http.rx_content_remain = wsi->http.rx_content_length =
-                                               atoll(content_length_str);
+                               (lws_filepos_t)atoll(content_length_str);
                if (!wsi->http.rx_content_length) {
                        wsi->http.content_length_explicitly_zero = 1;
                        lwsl_debug("%s: explicit 0 content-length\n", __func__);
                }
        }
 
-       if (wsi->http2_substream) {
+       if (wsi->mux_substream) {
                wsi->http.request_version = HTTP_VERSION_2;
        } else {
                /* http_version? Default to 1.0, override with token: */
@@ -1318,8 +1696,8 @@ lws_http_action(struct lws *wsi)
                wsi->http.conn_type = conn_type;
        }
 
-       n = wsi->protocol->callback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,
-                                   wsi->user_space, uri_ptr, uri_len);
+       n = (unsigned int)wsi->a.protocol->callback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION,
+                                   wsi->user_space, uri_ptr, (unsigned int)uri_len);
        if (n) {
                lwsl_info("LWS_CALLBACK_HTTP closing\n");
 
@@ -1329,32 +1707,56 @@ lws_http_action(struct lws *wsi)
         * if there is content supposed to be coming,
         * put a timeout on it having arrived
         */
-       lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
-                       wsi->context->timeout_secs);
-#ifdef LWS_WITH_TLS
+       if (!wsi->mux_stream_immortal)
+               lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
+                               (int)wsi->a.context->timeout_secs);
+#if defined(LWS_WITH_TLS)
        if (wsi->tls.redirect_to_https) {
                /*
-                * we accepted http:// only so we could redirect to
+                * We accepted http:// only so we could redirect to
                 * https://, so issue the redirect.  Create the redirection
-                * URI from the host: header and ignore the path part
+                * URI from the host: header, and regenerate the path part from
+                * the parsed pieces
                 */
                unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
-                             *end = p + wsi->context->pt_serv_buf_size - LWS_PRE;
+                             *end = p + wsi->a.context->pt_serv_buf_size -
+                                    LWS_PRE;
 
-               n = lws_hdr_total_length(wsi, WSI_TOKEN_HOST);
+               n = (unsigned int)lws_hdr_total_length(wsi, WSI_TOKEN_HOST);
                if (!n || n > 128)
                        goto bail_nuke_ah;
 
-               p += lws_snprintf((char *)p, lws_ptr_diff(end, p), "https://");
+               if (!lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST))
+                       goto bail_nuke_ah;
+
+               p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "https://");
                memcpy(p, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST), n);
                p += n;
                *p++ = '/';
-               *p = '\0';
-               n = lws_ptr_diff(p, start);
+               if (uri_len >= lws_ptr_diff(end, p))
+                       goto bail_nuke_ah;
+
+               if (uri_ptr[0])
+                       p--;
+               memcpy(p, uri_ptr, (unsigned int)uri_len);
+               p += uri_len;
+
+               n = 0;
+               while (lws_hdr_copy_fragment(wsi, (char *)p + 1,
+                                            lws_ptr_diff(end, p) - 2,
+                                            WSI_TOKEN_HTTP_URI_ARGS, (int)n) > 0) {
+                       *p = n ? '&' : '?';
+                       p += strlen((char *)p);
+                       if (p >= end - 2)
+                               goto bail_nuke_ah;
+                       n++;
+               }
+
+               n = (unsigned int)lws_ptr_diff(p, start);
 
                p += LWS_PRE;
-               n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
-                                     start, n, &p, end);
+               n = (unsigned int)lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
+                                     start, (int)n, &p, end);
                if ((int)n < 0)
                        goto bail_nuke_ah;
 
@@ -1374,84 +1776,31 @@ lws_http_action(struct lws *wsi)
 
                lwsl_info("no hit\n");
 
-               if (lws_bind_protocol(wsi, &wsi->vhost->protocols[0],
+               if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[0],
                                      "no mount hit"))
                        return 1;
 
                lwsi_set_state(wsi, LRS_DOING_TRANSACTION);
 
-               m = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
-                                   wsi->user_space, uri_ptr, uri_len);
+               m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
+                                   wsi->user_space, uri_ptr, (unsigned int)uri_len);
 
                goto after;
        }
 
+#if defined(LWS_WITH_FILE_OPS)
        s = uri_ptr + hit->mountpoint_len;
+#endif
+       n = (unsigned int)lws_http_redirect_hit(pt, wsi, hit, uri_ptr, uri_len, &ha);
+       if (ha)
+               return (int)n;
 
-       /*
-        * if we have a mountpoint like https://xxx.com/yyy
-        * there is an implied / at the end for our purposes since
-        * we can only mount on a "directory".
-        *
-        * But if we just go with that, the browser cannot understand
-        * that he is actually looking down one "directory level", so
-        * even though we give him /yyy/abc.html he acts like the
-        * current directory level is /.  So relative urls like "x.png"
-        * wrongly look outside the mountpoint.
-        *
-        * Therefore if we didn't come in on a url with an explicit
-        * / at the end, we must redirect to add it so the browser
-        * understands he is one "directory level" down.
-        */
-       if ((hit->mountpoint_len > 1 ||
-            (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
-             hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
-           (*s != '/' ||
-            (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
-             hit->origin_protocol == LWSMPRO_REDIR_HTTPS)) &&
-           (hit->origin_protocol != LWSMPRO_CGI &&
-            hit->origin_protocol != LWSMPRO_CALLBACK)) {
-               unsigned char *start = pt->serv_buf + LWS_PRE, *p = start,
-                             *end = p + wsi->context->pt_serv_buf_size -
-                                    LWS_PRE - 512;
-
-               lwsl_info("Doing 301 '%s' org %s\n", s, hit->origin);
-
-               /* > at start indicates deal with by redirect */
-               if (hit->origin_protocol == LWSMPRO_REDIR_HTTP ||
-                   hit->origin_protocol == LWSMPRO_REDIR_HTTPS)
-                       n = lws_snprintf((char *)end, 256, "%s%s",
-                                   oprot[hit->origin_protocol & 1],
-                                   hit->origin);
-               else {
-                       if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
-                               if (!lws_hdr_total_length(wsi,
-                                               WSI_TOKEN_HTTP_COLON_AUTHORITY))
-                                       goto bail_nuke_ah;
-                               n = lws_snprintf((char *)end, 256,
-                                   "%s%s%s/", oprot[!!lws_is_ssl(wsi)],
-                                   lws_hdr_simple_ptr(wsi,
-                                               WSI_TOKEN_HTTP_COLON_AUTHORITY),
-                                   uri_ptr);
-                       } else
-                               n = lws_snprintf((char *)end, 256,
-                                   "%s%s%s/", oprot[!!lws_is_ssl(wsi)],
-                                   lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
-                                   uri_ptr);
-               }
-
-               lws_clean_url((char *)end);
-               n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
-                                     end, n, &p, end);
-               if ((int)n < 0)
-                       goto bail_nuke_ah;
-
-               return lws_http_transaction_completed(wsi);
-       }
+#if defined(LWS_WITH_HTTP_BASIC_AUTH)
 
        /* basic auth? */
 
-       switch(lws_check_basic_auth(wsi, hit->basic_auth_login_file)) {
+       switch (lws_check_basic_auth(wsi, hit->basic_auth_login_file,
+                                    hit->auth_mask & AUTH_MODE_MASK)) {
        case LCBA_CONTINUE:
                break;
        case LCBA_FAILED_AUTH:
@@ -1460,6 +1809,7 @@ lws_http_action(struct lws *wsi)
                lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
                return lws_http_transaction_completed(wsi);
        }
+#endif
 
 #if defined(LWS_WITH_HTTP_PROXY)
        /*
@@ -1473,10 +1823,10 @@ lws_http_action(struct lws *wsi)
 
        if (hit->origin_protocol == LWSMPRO_HTTPS ||
            hit->origin_protocol == LWSMPRO_HTTP) {
-               n = lws_http_proxy_start(wsi, hit, uri_ptr, 0);
+               n = (unsigned int)lws_http_proxy_start(wsi, hit, uri_ptr, 0);
                // lwsl_notice("proxy start says %d\n", n);
                if (n)
-                       return n;
+                       return (int)n;
 
                goto deal_body;
        }
@@ -1494,9 +1844,8 @@ lws_http_action(struct lws *wsi)
                if (hit->protocol)
                        name = hit->protocol;
 
-               pp = lws_vhost_name_to_protocol(wsi->vhost, name);
+               pp = lws_vhost_name_to_protocol(wsi->a.vhost, name);
                if (!pp) {
-                       n = -1;
                        lwsl_err("Unable to find plugin '%s'\n",
                                 hit->origin);
                        return 1;
@@ -1505,16 +1854,16 @@ lws_http_action(struct lws *wsi)
                if (lws_bind_protocol(wsi, pp, "http action CALLBACK bind"))
                        return 1;
 
-               lwsl_notice("%s: %s, checking access rights for mask 0x%x\n",
+               lwsl_debug("%s: %s, checking access rights for mask 0x%x\n",
                                __func__, hit->origin, hit->auth_mask);
 
                args.p = uri_ptr;
                args.len = uri_len;
-               args.max_len = hit->auth_mask;
+               args.max_len = hit->auth_mask & ~AUTH_MODE_MASK;
                args.final = 0; /* used to signal callback dealt with it */
                args.chunked = 0;
 
-               n = wsi->protocol->callback(wsi,
+               n = (unsigned int)wsi->a.protocol->callback(wsi,
                                            LWS_CALLBACK_CHECK_ACCESS_RIGHTS,
                                            wsi->user_space, &args, 0);
                if (n) {
@@ -1525,16 +1874,16 @@ lws_http_action(struct lws *wsi)
                if (args.final) /* callback completely handled it well */
                        return 0;
 
-               if (hit->cgienv && wsi->protocol->callback(wsi,
+               if (hit->cgienv && wsi->a.protocol->callback(wsi,
                                LWS_CALLBACK_HTTP_PMO,
                                wsi->user_space, (void *)hit->cgienv, 0))
                        return 1;
 
                if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
-                       m = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
+                       m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
                                            wsi->user_space,
                                            uri_ptr + hit->mountpoint_len,
-                                           uri_len - hit->mountpoint_len);
+                                           (unsigned int)uri_len - hit->mountpoint_len);
                        goto after;
                }
        }
@@ -1552,9 +1901,9 @@ lws_http_action(struct lws *wsi)
 
                n = 5;
                if (hit->cgi_timeout)
-                       n = hit->cgi_timeout;
+                       n = (unsigned int)hit->cgi_timeout;
 
-               n = lws_cgi(wsi, cmd, hit->mountpoint_len, n,
+               n = (unsigned int)lws_cgi(wsi, cmd, hit->mountpoint_len, (int)n,
                            hit->cgienv);
                if (n) {
                        lwsl_err("%s: cgi failed\n", __func__);
@@ -1565,31 +1914,38 @@ lws_http_action(struct lws *wsi)
        }
 #endif
 
-       n = uri_len - lws_ptr_diff(s, uri_ptr); // (int)strlen(s);
+#if defined(LWS_WITH_FILE_OPS)
+       n = (unsigned int)(uri_len - lws_ptr_diff(s, uri_ptr));
        if (s[0] == '\0' || (n == 1 && s[n - 1] == '/'))
                s = (char *)hit->def;
        if (!s)
                s = "index.html";
+#endif
 
-       wsi->cache_secs = hit->cache_max_age;
+       wsi->cache_secs = (unsigned int)hit->cache_max_age;
        wsi->cache_reuse = hit->cache_reusable;
        wsi->cache_revalidate = hit->cache_revalidate;
        wsi->cache_intermediaries = hit->cache_intermediaries;
 
+#if defined(LWS_WITH_FILE_OPS)
        m = 1;
-#if !defined(LWS_AMAZON_RTOS)
        if (hit->origin_protocol == LWSMPRO_FILE)
                m = lws_http_serve(wsi, s, hit->origin, hit);
-#endif
 
-       if (m > 0) {
+       if (m > 0)
+#endif
+       {
                /*
                 * lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
                 */
                if (hit->protocol) {
                        const struct lws_protocols *pp =
                                        lws_vhost_name_to_protocol(
-                                               wsi->vhost, hit->protocol);
+                                               wsi->a.vhost, hit->protocol);
+
+                       /* coverity */
+                       if (!pp)
+                               return 1;
 
                        lwsi_set_state(wsi, LRS_DOING_TRANSACTION);
 
@@ -1599,10 +1955,10 @@ lws_http_action(struct lws *wsi)
                        m = pp->callback(wsi, LWS_CALLBACK_HTTP,
                                         wsi->user_space,
                                         uri_ptr + hit->mountpoint_len,
-                                        uri_len - hit->mountpoint_len);
+                                        (size_t)(uri_len - hit->mountpoint_len));
                } else
-                       m = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
-                                   wsi->user_space, uri_ptr, uri_len);
+                       m = wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP,
+                                   wsi->user_space, uri_ptr, (size_t)uri_len);
        }
 
 after:
@@ -1623,76 +1979,72 @@ deal_body:
         * In any case, return 0 and let lws_read decide how to
         * proceed based on state
         */
-       if (lwsi_state(wsi) != LRS_ISSUING_FILE) {
-               /* Prepare to read body if we have a content length: */
-               lwsl_debug("wsi->http.rx_content_length %lld %d %d\n",
-                          (long long)wsi->http.rx_content_length,
-                          wsi->upgraded_to_http2, wsi->http2_substream);
+       if (lwsi_state(wsi) == LRS_ISSUING_FILE)
+               return 0;
 
-               if (wsi->http.content_length_explicitly_zero &&
-                   lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
+       /* Prepare to read body if we have a content length: */
+       lwsl_debug("wsi->http.rx_content_length %lld %d %d\n",
+                  (long long)wsi->http.rx_content_length,
+                  wsi->upgraded_to_http2, wsi->mux_substream);
 
-                       /*
-                        * POST with an explicit content-length of zero
-                        *
-                        * If we don't give the user code the empty HTTP_BODY
-                        * callback, he may become confused to hear the
-                        * HTTP_BODY_COMPLETION (due to, eg, instantiation of
-                        * lws_spa never happened).
-                        *
-                        * HTTP_BODY_COMPLETION is responsible for sending the
-                        * result status code and result body if any, and
-                        * do the transaction complete processing.
-                        */
-                       if (wsi->protocol->callback(wsi,
-                                       LWS_CALLBACK_HTTP_BODY,
-                                       wsi->user_space, NULL, 0))
-                               return 1;
-                       if (wsi->protocol->callback(wsi,
-                                       LWS_CALLBACK_HTTP_BODY_COMPLETION,
-                                       wsi->user_space, NULL, 0))
-                               return 1;
+       if (wsi->http.content_length_explicitly_zero &&
+           lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
 
-                       return 0;
-               }
+               /*
+                * POST with an explicit content-length of zero
+                *
+                * If we don't give the user code the empty HTTP_BODY callback,
+                * he may become confused to hear the HTTP_BODY_COMPLETION (due
+                * to, eg, instantiation of lws_spa never happened).
+                *
+                * HTTP_BODY_COMPLETION is responsible for sending the result
+                * status code and result body if any, and to do the transaction
+                * complete processing.
+                */
+               if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY,
+                                           wsi->user_space, NULL, 0))
+                       return 1;
+               if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY_COMPLETION,
+                                           wsi->user_space, NULL, 0))
+                       return 1;
 
-               if (wsi->http.rx_content_length > 0) {
+               return 0;
+       }
 
-                       if (lwsi_state(wsi) != LRS_DISCARD_BODY) {
-                               lwsi_set_state(wsi, LRS_BODY);
-                               lwsl_info("%s: %p: LRS_BODY state set (0x%x)\n",
-                                   __func__, wsi, wsi->wsistate);
-                       }
-                       wsi->http.rx_content_remain =
-                                       wsi->http.rx_content_length;
+       if (wsi->http.rx_content_length <= 0)
+               return 0;
 
-                       /*
-                        * At this point we have transitioned from deferred
-                        * action to expecting BODY on the stream wsi, if it's
-                        * in a bundle like h2.  So if the stream wsi has its
-                        * own buflist, we need to deal with that first.
-                        */
+       if (lwsi_state(wsi) != LRS_DISCARD_BODY) {
+               lwsi_set_state(wsi, LRS_BODY);
+               lwsl_info("%s: %s: LRS_BODY state set (0x%x)\n", __func__,
+                         lws_wsi_tag(wsi), (int)wsi->wsistate);
+       }
+       wsi->http.rx_content_remain = wsi->http.rx_content_length;
 
-                       while (1) {
-                               struct lws_tokens ebuf;
-                               int m;
-
-                               ebuf.len = (int)lws_buflist_next_segment_len(
-                                               &wsi->buflist,
-                                               &ebuf.token);
-                               if (!ebuf.len)
-                                       break;
-                               lwsl_debug("%s: consuming %d\n", __func__,
-                                                       (int)ebuf.len);
-                               m = lws_read_h1(wsi, ebuf.token,
-                                               ebuf.len);
-                               if (m < 0)
-                                       return -1;
-
-                               if (lws_buflist_aware_consume(wsi, &ebuf, m, 1))
-                                       return -1;
-                       }
-               }
+       /*
+        * At this point we have transitioned from deferred
+        * action to expecting BODY on the stream wsi, if it's
+        * in a bundle like h2.  So if the stream wsi has its
+        * own buflist, we need to deal with that first.
+        */
+
+       while (1) {
+               struct lws_tokens ebuf;
+               int m;
+
+               ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist,
+                                                            &ebuf.token);
+               if (!ebuf.len)
+                       break;
+
+               lwsl_debug("%s: consuming %d\n", __func__, (int)ebuf.len);
+               m = lws_read_h1(wsi, ebuf.token, (lws_filepos_t)ebuf.len);
+               if (m < 0)
+                       return -1;
+
+               if (lws_buflist_aware_finished_consuming(wsi, &ebuf, m, 1,
+                                                        __func__))
+                       return -1;
        }
 
        return 0;
@@ -1708,8 +2060,8 @@ lws_confirm_host_header(struct lws *wsi)
 {
        struct lws_tokenize ts;
        lws_tokenize_elem e;
+       int port = 80, n;
        char buf[128];
-       int port = 80;
 
        /*
         * this vhost wants us to validate what the
@@ -1727,22 +2079,23 @@ lws_confirm_host_header(struct lws *wsi)
                port = 443;
 #endif
 
-       lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_DOT_NONTERM /* server.com */|
-                                   LWS_TOKENIZE_F_NO_FLOATS /* 1.server.com */|
-                                   LWS_TOKENIZE_F_MINUS_NONTERM /* a-b.com */);
-       ts.len = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_HOST);
-       if (ts.len <= 0) {
+       n = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_HOST);
+       if (n <= 0) {
                lwsl_info("%s: missing or oversize host header\n", __func__);
                return 1;
        }
+       ts.len = (size_t)n;
+       lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_DOT_NONTERM /* server.com */|
+                                   LWS_TOKENIZE_F_NO_FLOATS /* 1.server.com */|
+                                   LWS_TOKENIZE_F_MINUS_NONTERM /* a-b.com */);
 
        if (lws_tokenize(&ts) != LWS_TOKZE_TOKEN)
                goto bad_format;
 
-       if (strncmp(ts.token, wsi->vhost->name, ts.token_len)) {
-               buf[(ts.token - buf) + ts.token_len] = '\0';
+       if (strncmp(ts.token, wsi->a.vhost->name, ts.token_len)) {
+               buf[(size_t)(ts.token - buf) + ts.token_len] = '\0';
                lwsl_info("%s: '%s' in host hdr but vhost name %s\n",
-                         __func__, ts.token, wsi->vhost->name);
+                         __func__, ts.token, wsi->a.vhost->name);
                return 1;
        }
 
@@ -1756,9 +2109,9 @@ lws_confirm_host_header(struct lws *wsi)
                if (e != LWS_TOKZE_ENDED)
                        goto bad_format;
 
-       if (wsi->vhost->listen_port != port) {
+       if (wsi->a.vhost->listen_port != port) {
                lwsl_info("%s: host port %d mismatches vhost port %d\n",
-                         __func__, port, wsi->vhost->listen_port);
+                         __func__, port, wsi->a.vhost->listen_port);
                return 1;
        }
 
@@ -1772,23 +2125,23 @@ bad_format:
        return 1;
 }
 
-#if !defined(LWS_NO_SERVER)
+#if defined(LWS_WITH_SERVER)
 int
 lws_http_to_fallback(struct lws *wsi, unsigned char *obuf, size_t olen)
 {
        const struct lws_role_ops *role = &role_ops_raw_skt;
        const struct lws_protocols *p1, *protocol =
-                        &wsi->vhost->protocols[wsi->vhost->raw_protocol_index];
+                        &wsi->a.vhost->protocols[wsi->a.vhost->raw_protocol_index];
        char ipbuf[64];
        int n;
 
-       if (wsi->vhost->listen_accept_role &&
-           lws_role_by_name(wsi->vhost->listen_accept_role))
-               role = lws_role_by_name(wsi->vhost->listen_accept_role);
+       if (wsi->a.vhost->listen_accept_role &&
+           lws_role_by_name(wsi->a.vhost->listen_accept_role))
+               role = lws_role_by_name(wsi->a.vhost->listen_accept_role);
 
-       if (wsi->vhost->listen_accept_protocol) {
-               p1 = lws_vhost_name_to_protocol(wsi->vhost,
-                           wsi->vhost->listen_accept_protocol);
+       if (wsi->a.vhost->listen_accept_protocol) {
+               p1 = lws_vhost_name_to_protocol(wsi->a.vhost,
+                           wsi->a.vhost->listen_accept_protocol);
                if (p1)
                        protocol = p1;
        }
@@ -1801,8 +2154,8 @@ lws_http_to_fallback(struct lws *wsi, unsigned char *obuf, size_t olen)
        lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
 
        n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
-       if (wsi->role_ops->adoption_cb[lwsi_role_server(wsi)])
-               n = wsi->role_ops->adoption_cb[lwsi_role_server(wsi)];
+       if (wsi->role_ops->adoption_cb[1])
+               n = wsi->role_ops->adoption_cb[1];
 
        ipbuf[0] = '\0';
 #if !defined(LWS_PLAT_OPTEE)
@@ -1810,16 +2163,17 @@ lws_http_to_fallback(struct lws *wsi, unsigned char *obuf, size_t olen)
 #endif
 
        lwsl_notice("%s: vh %s, peer: %s, role %s, "
-                   "protocol %s, cb %d, ah %p\n", __func__, wsi->vhost->name,
-                   ipbuf, role->name, protocol->name, n, wsi->http.ah);
+                   "protocol %s, cb %d, ah %p\n", __func__, wsi->a.vhost->name,
+                   ipbuf, role ? role->name : "null", protocol->name, n,
+                   wsi->http.ah);
 
-       if ((wsi->protocol->callback)(wsi, n, wsi->user_space, NULL, 0))
+       if ((wsi->a.protocol->callback)(wsi, (enum lws_callback_reasons)n, wsi->user_space, NULL, 0))
                return 1;
 
        n = LWS_CALLBACK_RAW_RX;
        if (wsi->role_ops->rx_cb[lwsi_role_server(wsi)])
                n = wsi->role_ops->rx_cb[lwsi_role_server(wsi)];
-       if (wsi->protocol->callback(wsi, n, wsi->user_space, obuf, olen))
+       if (wsi->a.protocol->callback(wsi, (enum lws_callback_reasons)n, wsi->user_space, obuf, olen))
                return 1;
 
        return 0;
@@ -1829,6 +2183,7 @@ int
 lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
 {
        struct lws_context *context = lws_get_context(wsi);
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
 #if defined(LWS_WITH_HTTP2)
        struct allocated_headers *ah;
 #endif
@@ -1852,7 +2207,7 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
        while (len) {
                if (!lwsi_role_server(wsi) || !lwsi_role_http(wsi)) {
                        lwsl_err("%s: bad wsi role 0x%x\n", __func__,
-                                       lwsi_role(wsi));
+                                       (int)lwsi_role(wsi));
                        goto bail_nuke_ah;
                }
 
@@ -1860,7 +2215,7 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
                m = lws_parse(wsi, *buf, &i);
                lwsl_info("%s: parsed count %d\n", __func__, (int)len - i);
                (*buf) += (int)len - i;
-               len = i;
+               len = (unsigned int)i;
 
                if (m == LPR_DO_FALLBACK) {
 
@@ -1890,6 +2245,10 @@ raw_transition:
                        goto bail_nuke_ah;
                }
 
+               /* coverity... */
+               if (!wsi->http.ah)
+                       goto bail_nuke_ah;
+
                if (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE)
                        continue;
 
@@ -1897,10 +2256,10 @@ raw_transition:
 
                /* select vhost */
 
-               if (wsi->vhost->listen_port &&
+               if (wsi->a.vhost->listen_port &&
                    lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
                        struct lws_vhost *vhost = lws_select_vhost(
-                               context, wsi->vhost->listen_port,
+                               context, wsi->a.vhost->listen_port,
                                lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
 
                        if (vhost)
@@ -1908,19 +2267,15 @@ raw_transition:
                } else
                        lwsl_info("no host\n");
 
-               if (!lwsi_role_h2(wsi) || !lwsi_role_server(wsi)) {
-                       wsi->vhost->conn_stats.h1_trans++;
-                       if (!wsi->conn_stat_done) {
-                               wsi->vhost->conn_stats.h1_conn++;
-                               wsi->conn_stat_done = 1;
-                       }
-               }
+               if ((!lwsi_role_h2(wsi) || !lwsi_role_server(wsi)) &&
+                   (!wsi->conn_stat_done))
+                       wsi->conn_stat_done = 1;
 
                /* check for unwelcome guests */
-
-               if (wsi->context->reject_service_keywords) {
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
+               if (wsi->a.context->reject_service_keywords) {
                        const struct lws_protocol_vhost_options *rej =
-                                       wsi->context->reject_service_keywords;
+                                       wsi->a.context->reject_service_keywords;
                        char ua[384], *msg = NULL;
 
                        if (lws_hdr_copy(wsi, ua, sizeof(ua) - 1,
@@ -1940,7 +2295,7 @@ raw_transition:
                                        if (msg)
                                                msg++;
                                        lws_return_http_status(wsi,
-                                               atoi(rej->value), msg);
+                                               (unsigned int)atoi(rej->value), msg);
 #ifdef LWS_WITH_ACCESS_LOG
                                        meth = lws_http_get_uri_and_method(wsi,
                                                        &uri_ptr, &uri_len);
@@ -1950,7 +2305,6 @@ raw_transition:
 
                                        /* wsi close will do the log */
 #endif
-                                       wsi->vhost->conn_stats.rejected++;
                                        /*
                                         * We don't want anything from
                                         * this rejected guy.  Follow
@@ -1961,11 +2315,36 @@ raw_transition:
                                }
                        }
                }
+#endif
+               /*
+                * So he may have come to us requesting one or another kind
+                * of upgrade from http... but we may want to redirect him at
+                * http level.  In that case, we need to check the redirect
+                * situation even though he's not actually wanting http and
+                * prioritize returning that if there is one.
+                */
+
+               {
+                       const struct lws_http_mount *hit = NULL;
+                       int uri_len = 0, ha, n;
+                       char *uri_ptr = NULL;
+
+                       n = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
+                       if (n >= 0) {
+                               hit = lws_find_mount(wsi, uri_ptr, uri_len);
+                               if (hit) {
+                                       n = lws_http_redirect_hit(pt, wsi, hit, uri_ptr,
+                                                                 uri_len, &ha);
+                                       if (ha)
+                                               return n;
+                               }
+                       }
+               }
+
 
 
                if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) {
                        lwsl_info("Changing to RAW mode\n");
-                       m = 0;
                        goto raw_transition;
                }
 
@@ -1987,7 +2366,7 @@ raw_transition:
                                        goto bail_nuke_ah;
                        }
 
-                       n = user_callback_handle_rxflow(wsi->protocol->callback,
+                       n = user_callback_handle_rxflow(wsi->a.protocol->callback,
                                        wsi, LWS_CALLBACK_HTTP_CONFIRM_UPGRADE,
                                        wsi->user_space, (char *)up, 0);
 
@@ -2009,21 +2388,21 @@ raw_transition:
 
                        /* callback said 0, it was allowed */
 
-                       if (wsi->vhost->options &
+                       if (wsi->a.vhost->options &
                            LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK &&
                            lws_confirm_host_header(wsi))
                                goto bail_nuke_ah;
 
                        if (!strcasecmp(up, "websocket")) {
 #if defined(LWS_ROLE_WS)
-                               wsi->vhost->conn_stats.ws_upg++;
+                               lws_metrics_tag_wsi_add(wsi, "upg", "ws");
                                lwsl_info("Upgrade to ws\n");
                                goto upgrade_ws;
 #endif
                        }
 #if defined(LWS_WITH_HTTP2)
                        if (!strcasecmp(up, "h2c")) {
-                               wsi->vhost->conn_stats.h2_upg++;
+                               lws_metrics_tag_wsi_add(wsi, "upg", "h2c");
                                lwsl_info("Upgrade to h2c\n");
                                goto upgrade_h2c;
                        }
@@ -2032,16 +2411,18 @@ raw_transition:
 
                /* no upgrade ack... he remained as HTTP */
 
-               lwsl_info("%s: %p: No upgrade\n", __func__, wsi);
+               lwsl_info("%s: %s: No upgrade\n", __func__, lws_wsi_tag(wsi));
 
                lwsi_set_state(wsi, LRS_ESTABLISHED);
+#if defined(LWS_WITH_FILE_OPS)
                wsi->http.fop_fd = NULL;
+#endif
 
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
                lws_http_compression_validate(wsi);
 #endif
 
-               lwsl_debug("%s: wsi %p: ah %p\n", __func__, (void *)wsi,
+               lwsl_debug("%s: %s: ah %p\n", __func__, lws_wsi_tag(wsi),
                           (void *)wsi->http.ah);
 
                n = lws_http_action(wsi);
@@ -2077,8 +2458,7 @@ upgrade_h2c:
                wsi->http.ah = ah;
 
                if (!wsi->h2.h2n) {
-                       wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n),
-                                                  "h2n");
+                       wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n");
                        if (!wsi->h2.h2n)
                                return 1;
                }
@@ -2087,16 +2467,17 @@ upgrade_h2c:
 
                /* HTTP2 union */
 
-               lws_h2_settings(wsi, &wsi->h2.h2n->set, (unsigned char *)tbuf, n);
+               lws_h2_settings(wsi, &wsi->h2.h2n->peer_set, (uint8_t *)tbuf, n);
 
-               lws_hpack_dynamic_size(wsi, wsi->h2.h2n->set.s[
-                                                     H2SET_HEADER_TABLE_SIZE]);
+               if (lws_hpack_dynamic_size(wsi, (int)wsi->h2.h2n->peer_set.s[
+                                                     H2SET_HEADER_TABLE_SIZE]))
+                       return 1;
 
                strcpy(tbuf, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
                              "Connection: Upgrade\x0d\x0a"
                              "Upgrade: h2c\x0d\x0a\x0d\x0a");
                m = (int)strlen(tbuf);
-               n = lws_issue_raw(wsi, (unsigned char *)tbuf, m);
+               n = lws_issue_raw(wsi, (unsigned char *)tbuf, (unsigned int)m);
                if (n != m) {
                        lwsl_debug("http2 switch: ERROR writing to socket\n");
                        return 1;
@@ -2123,10 +2504,13 @@ bail_nuke_ah:
 }
 #endif
 
-LWS_VISIBLE int LWS_WARN_UNUSED_RESULT
+int LWS_WARN_UNUSED_RESULT
 lws_http_transaction_completed(struct lws *wsi)
 {
-       int n = NO_PENDING_TIMEOUT;
+       int n;
+
+       if (wsi->http.cgi_transaction_complete)
+               return 0;
 
        if (lws_has_buffered_out(wsi)
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
@@ -2142,7 +2526,8 @@ lws_http_transaction_completed(struct lws *wsi)
                 * Defer the transaction completed until the last part of the
                 * partial is sent.
                 */
-               lwsl_debug("%s: %p: deferring due to partial\n", __func__, wsi);
+               lwsl_debug("%s: %s: deferring due to partial\n", __func__,
+                               lws_wsi_tag(wsi));
                wsi->http.deferred_transaction_completed = 1;
                lws_callback_on_writable(wsi);
 
@@ -2171,14 +2556,27 @@ lws_http_transaction_completed(struct lws *wsi)
                return 0;
        }
 
-       lwsl_info("%s: wsi %p\n", __func__, wsi);
+#if defined(LWS_WITH_SYS_METRICS)
+       {
+               char tmp[10];
+
+               lws_snprintf(tmp, sizeof(tmp), "%u", wsi->http.response_code);
+               lws_metrics_tag_wsi_add(wsi, "status", tmp);
+       }
+#endif
+
+       lwsl_info("%s: %s\n", __func__, lws_wsi_tag(wsi));
 
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
        lws_http_compression_destroy(wsi);
 #endif
        lws_access_log(wsi);
 
-       if (!wsi->hdr_parsing_completed) {
+       if (!wsi->hdr_parsing_completed
+#if defined(LWS_WITH_CGI)
+                       && !wsi->http.cgi
+#endif
+       ) {
                char peer[64];
 
 #if !defined(LWS_PLAT_OPTEE)
@@ -2187,24 +2585,37 @@ lws_http_transaction_completed(struct lws *wsi)
                peer[0] = '\0';
 #endif
                peer[sizeof(peer) - 1] = '\0';
-               lwsl_notice("%s: (from %s) ignoring, ah parsing incomplete\n",
+               lwsl_info("%s: (from %s) ignoring, ah parsing incomplete\n",
                                __func__, peer);
                return 0;
        }
 
+#if defined(LWS_WITH_CGI)
+       if (wsi->http.cgi) {
+               lwsl_debug("%s: cleaning cgi\n", __func__);
+               wsi->http.cgi_transaction_complete = 1;
+               lws_cgi_remove_and_kill(wsi);
+               lws_spawn_piped_destroy(&wsi->http.cgi->lsp);
+               lws_sul_cancel(&wsi->http.cgi->sul_grace);
+
+               lws_free_set_NULL(wsi->http.cgi);
+               wsi->http.cgi_transaction_complete = 0;
+       }
+#endif
+
        /* if we can't go back to accept new headers, drop the connection */
-       if (wsi->http2_substream)
+       if (wsi->mux_substream)
                return 1;
 
        if (wsi->seen_zero_length_recv)
                return 1;
 
        if (wsi->http.conn_type != HTTP_CONNECTION_KEEP_ALIVE) {
-               lwsl_info("%s: %p: close connection\n", __func__, wsi);
+               lwsl_info("%s: %s: close connection\n", __func__, lws_wsi_tag(wsi));
                return 1;
        }
 
-       if (lws_bind_protocol(wsi, &wsi->vhost->protocols[0], __func__))
+       if (lws_bind_protocol(wsi, &wsi->a.vhost->protocols[0], __func__))
                return 1;
 
        /*
@@ -2213,8 +2624,8 @@ lws_http_transaction_completed(struct lws *wsi)
         * until we can verify POLLOUT.  The part of this that confirms POLLOUT
         * with no partials is in lws_server_socket_service() below.
         */
-       lwsl_debug("%s: %p: setting DEF_ACT from 0x%x\n", __func__,
-                  wsi, wsi->wsistate);
+       lwsl_debug("%s: %s: setting DEF_ACT from 0x%x: %p\n", __func__,
+                  lws_wsi_tag(wsi), (int)wsi->wsistate, wsi->buflist);
        lwsi_set_state(wsi, LRS_DEFERRING_ACTION);
        wsi->http.tx_content_length = 0;
        wsi->http.tx_content_remain = 0;
@@ -2223,16 +2634,16 @@ lws_http_transaction_completed(struct lws *wsi)
 #ifdef LWS_WITH_ACCESS_LOG
        wsi->http.access_log.sent = 0;
 #endif
-
 #if defined(LWS_WITH_FILE_OPS) && (defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2))
-       if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
-           wsi->http.fop_fd != NULL)
-              lws_vfs_file_close(&wsi->http.fop_fd);
+       if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
+           wsi->http.fop_fd != NULL)
+               lws_vfs_file_close(&wsi->http.fop_fd);
 #endif
 
-       if (wsi->vhost->keepalive_timeout)
+       n = NO_PENDING_TIMEOUT;
+       if (wsi->a.vhost->keepalive_timeout)
                n = PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE;
-       lws_set_timeout(wsi, n, wsi->vhost->keepalive_timeout);
+       lws_set_timeout(wsi, (enum pending_timeout)n, wsi->a.vhost->keepalive_timeout);
 
        /*
         * We already know we are on http1.1 / keepalive and the next thing
@@ -2247,10 +2658,10 @@ lws_http_transaction_completed(struct lws *wsi)
         * reset the existing header table and keep it.
         */
        if (wsi->http.ah) {
-               // lws_buflist_describe(&wsi->buflist, wsi);
+               // lws_buflist_describe(&wsi->buflist, wsi, __func__);
                if (!lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
-                       lwsl_debug("%s: %p: nothing in buflist, detaching ah\n",
-                                 __func__, wsi);
+                       lwsl_debug("%s: %s: nothing in buflist, detaching ah\n",
+                                 __func__, lws_wsi_tag(wsi));
                        lws_header_table_detach(wsi, 1);
 #ifdef LWS_WITH_TLS
                        /*
@@ -2259,18 +2670,18 @@ lws_http_transaction_completed(struct lws *wsi)
                         * SSL is scarce, drop this connection without waiting
                         */
 
-                       if (wsi->vhost->tls.use_ssl &&
-                           wsi->context->simultaneous_ssl_restriction &&
-                           wsi->context->simultaneous_ssl ==
-                                  wsi->context->simultaneous_ssl_restriction) {
+                       if (wsi->a.vhost->tls.use_ssl &&
+                           wsi->a.context->simultaneous_ssl_restriction &&
+                           wsi->a.context->simultaneous_ssl ==
+                                  wsi->a.context->simultaneous_ssl_restriction) {
                                lwsl_info("%s: simultaneous_ssl_restriction\n",
                                          __func__);
                                return 1;
                        }
 #endif
                } else {
-                       lwsl_info("%s: %p: resetting/keeping ah as pipeline\n",
-                                 __func__, wsi);
+                       lwsl_info("%s: %s: resetting/keeping ah as pipeline\n",
+                                 __func__, lws_wsi_tag(wsi));
                        lws_header_table_reset(wsi, 0);
                        /*
                         * If we kept the ah, we should restrict the amount
@@ -2279,7 +2690,7 @@ lws_http_transaction_completed(struct lws *wsi)
                         * open.
                         */
                        lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,
-                                       wsi->vhost->keepalive_timeout);
+                                       wsi->a.vhost->keepalive_timeout);
                }
                /* If we're (re)starting on headers, need other implied init */
                if (wsi->http.ah)
@@ -2291,15 +2702,15 @@ lws_http_transaction_completed(struct lws *wsi)
                        if (lws_header_table_attach(wsi, 0))
                                lwsl_debug("acquired ah\n");
 
-       lwsl_debug("%s: %p: keep-alive await new transaction (state 0x%x)\n",
-                       __func__, wsi, wsi->wsistate);
+       lwsl_debug("%s: %s: keep-alive await new transaction (state 0x%x)\n",
+                  __func__, lws_wsi_tag(wsi), (int)wsi->wsistate);
        lws_callback_on_writable(wsi);
 
        return 0;
 }
 
-#if !defined(LWS_AMAZON_RTOS)
-LWS_VISIBLE int
+#if defined(LWS_WITH_FILE_OPS)
+int
 lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
                    const char *other_headers, int other_headers_len)
 {
@@ -2332,9 +2743,9 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
         * If wsi->http.fop_fd is already set, the caller already opened it
         */
        if (!wsi->http.fop_fd) {
-               fops = lws_vfs_select_fops(wsi->context->fops, file, &vpath);
+               fops = lws_vfs_select_fops(wsi->a.context->fops, file, &vpath);
                fflags |= lws_vfs_prepare_flags(wsi);
-               wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->context->fops,
+               wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->a.context->fops,
                                                        file, vpath, &fflags);
                if (!wsi->http.fop_fd) {
                        lwsl_info("%s: Unable to open: '%s': errno %d\n",
@@ -2342,7 +2753,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
                        if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND,
                                                   NULL))
                                                return -1;
-                       return !wsi->http2_substream;
+                       return !wsi->mux_substream;
                }
        }
 
@@ -2379,7 +2790,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
                n = HTTP_STATUS_PARTIAL_CONTENT;
 #endif
 
-       if (lws_add_http_header_status(wsi, n, &p, end))
+       if (lws_add_http_header_status(wsi, (unsigned int)n, &p, end))
                goto bail;
 
        if ((wsi->http.fop_fd->flags & (LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP |
@@ -2453,13 +2864,14 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
                                        "bytes %llu-%llu/%llu",
                                        rp->start, rp->end, rp->extent);
 
-                       total_content_length +=
+                       total_content_length = total_content_length +
+                                       (lws_filepos_t)(
                                6 /* header _lws\r\n */ +
                                /* Content-Type: xxx/xxx\r\n */
-                               14 + strlen(content_type) + 2 +
+                               14 + (int)strlen(content_type) + 2 +
                                /* Content-Range: xxxx\r\n */
                                15 + n + 2 +
-                               2; /* /r/n */
+                               2); /* /r/n */
                }
 
                lws_ranges_reset(rp);
@@ -2486,7 +2898,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
                goto bail;
 #endif
 
-       if (!wsi->http2_substream) {
+       if (!wsi->mux_substream) {
                /* for http/1.1 ... */
                if (!wsi->sending_chunked
 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
@@ -2563,14 +2975,14 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
        if (other_headers) {
                if ((end - p) < other_headers_len)
                        goto bail;
-               memcpy(p, other_headers, other_headers_len);
+               memcpy(p, other_headers, (unsigned int)other_headers_len);
                p += other_headers_len;
        }
 
        if (lws_finalize_http_header(wsi, &p, end))
                goto bail;
 
-       ret = lws_write(wsi, response, p - response, LWS_WRITE_HTTP_HEADERS);
+       ret = lws_write(wsi, response, lws_ptr_diff_size_t(p, response), LWS_WRITE_HTTP_HEADERS);
        if (ret != (p - response)) {
                lwsl_err("_write returned %d from %ld\n", ret,
                         (long)(p - response));
@@ -2600,9 +3012,11 @@ bail:
 }
 #endif
 
-LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
+#if defined(LWS_WITH_FILE_OPS)
+
+int lws_serve_http_file_fragment(struct lws *wsi)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        struct lws_process_html_args args;
        lws_filepos_t amount, poss;
@@ -2610,9 +3024,12 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
 #if defined(LWS_WITH_RANGES)
        unsigned char finished = 0;
 #endif
+#if defined(LWS_ROLE_H2)
+       struct lws *nwsi;
+#endif
        int n, m;
 
-       lwsl_debug("wsi->http2_substream %d\n", wsi->http2_substream);
+       lwsl_debug("wsi->mux_substream %d\n", wsi->mux_substream);
 
        do {
 
@@ -2637,7 +3054,9 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
                           __func__, wsi->http.comp_ctx.buflist_comp,
                           wsi->http.comp_ctx.may_have_more);
 
-               if (wsi->role_ops->write_role_protocol(wsi, NULL, 0, &wp) < 0) {
+               if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) &&
+                   lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol).
+                                       write_role_protocol(wsi, NULL, 0, &wp) < 0) {
                        lwsl_info("%s signalling to close\n", __func__);
                        goto file_had_it;
                }
@@ -2651,10 +3070,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
                        goto all_sent;
 
                n = 0;
-
-               pstart = pt->serv_buf + LWS_H2_FRAME_HEADER_LENGTH;
-
-               p = pstart;
+               p = pstart = pt->serv_buf + LWS_H2_FRAME_HEADER_LENGTH;
 
 #if defined(LWS_WITH_RANGES)
                if (wsi->http.range.count_ranges && !wsi->http.range.inside) {
@@ -2663,8 +3079,8 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
                                    wsi->http.range.start);
 
                        if ((long long)lws_vfs_file_seek_cur(wsi->http.fop_fd,
-                                                  wsi->http.range.start -
-                                                  wsi->http.filepos) < 0)
+                                                  (lws_fileofs_t)wsi->http.range.start -
+                                                  (lws_fileofs_t)wsi->http.filepos) < 0)
                                goto file_had_it;
 
                        wsi->http.filepos = wsi->http.range.start;
@@ -2691,35 +3107,54 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
                }
 #endif
 
-               poss = context->pt_serv_buf_size - n -
-                               LWS_H2_FRAME_HEADER_LENGTH;
+               poss = context->pt_serv_buf_size;
+
+#if defined(LWS_ROLE_H2)
+               /*
+                * If it's h2, restrict any lump that we are sending to the
+                * max h2 frame size the peer indicated he could handle in
+                * his SETTINGS
+                */
+               nwsi = lws_get_network_wsi(wsi);
+               if (nwsi->h2.h2n &&
+                   poss > (lws_filepos_t)nwsi->h2.h2n->peer_set.s[H2SET_MAX_FRAME_SIZE])
+                       poss = (lws_filepos_t)nwsi->h2.h2n->peer_set.s[H2SET_MAX_FRAME_SIZE];
+#endif
+               poss = poss - (lws_filepos_t)(n + LWS_H2_FRAME_HEADER_LENGTH);
 
                if (wsi->http.tx_content_length)
                        if (poss > wsi->http.tx_content_remain)
                                poss = wsi->http.tx_content_remain;
 
                /*
-                * if there is a hint about how much we will do well to send at
+                * If there is a hint about how much we will do well to send at
                 * one time, restrict ourselves to only trying to send that.
                 */
-               if (wsi->protocol->tx_packet_size &&
-                   poss > wsi->protocol->tx_packet_size)
-                       poss = wsi->protocol->tx_packet_size;
+               if (wsi->a.protocol->tx_packet_size &&
+                   poss > wsi->a.protocol->tx_packet_size)
+                       poss = wsi->a.protocol->tx_packet_size;
 
-               if (wsi->role_ops->tx_credit) {
-                       lws_filepos_t txc = wsi->role_ops->tx_credit(wsi);
+               if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_tx_credit)) {
+                       lws_filepos_t txc = (unsigned int)lws_rops_func_fidx(wsi->role_ops,
+                                                              LWS_ROPS_tx_credit).
+                                       tx_credit(wsi, LWSTXCR_US_TO_PEER, 0);
 
                        if (!txc) {
-                               lwsl_info("%s: came here with no tx credit\n",
-                                               __func__);
+                               /*
+                                * We shouldn't've been able to get the
+                                * WRITEABLE if we are skint
+                                */
+                               lwsl_notice("%s: %s: no tx credit\n", __func__,
+                                               lws_wsi_tag(wsi));
+
                                return 0;
                        }
                        if (txc < poss)
                                poss = txc;
 
                        /*
-                        * consumption of the actual payload amount sent will be
-                        * handled when the role data frame is sent
+                        * Tracking consumption of the actual payload amount
+                        * will be handled when the role data frame is sent...
                         */
                }
 
@@ -2738,6 +3173,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
                        poss -= 10 + 128;
                }
 
+               amount = 0;
                if (lws_vfs_file_read(wsi->http.fop_fd, &amount, p, poss) < 0)
                        goto file_had_it; /* caller will close */
 
@@ -2750,17 +3186,17 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
 
                if (n) {
                        lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
-                                       context->timeout_secs);
+                                       (int)context->timeout_secs);
 
                        if (wsi->interpreting) {
                                args.p = (char *)p;
                                args.len = n;
-                               args.max_len = (unsigned int)poss + 128;
-                               args.final = wsi->http.filepos + n ==
-                                            wsi->http.filelen;
+                               args.max_len = (int)(unsigned int)poss + 128;
+                               args.final = wsi->http.filepos + (unsigned int)n ==
+                                                       wsi->http.filelen;
                                args.chunked = wsi->sending_chunked;
                                if (user_callback_handle_rxflow(
-                                    wsi->vhost->protocols[
+                                    wsi->a.vhost->protocols[
                                     (int)wsi->protocol_interpret_idx].callback,
                                     wsi, LWS_CALLBACK_PROCESS_HTML,
                                     wsi->user_space, &args, 0) < 0)
@@ -2780,7 +3216,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
                                lwsl_debug("added trailing boundary\n");
                        }
 #endif
-                       m = lws_write(wsi, p, n, wsi->http.filepos + amount ==
+                       m = lws_write(wsi, p, (unsigned int)n, wsi->http.filepos + amount ==
                                        wsi->http.filelen ?
                                         LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP);
                        if (m < 0)
@@ -2832,8 +3268,8 @@ all_sent:
 
                        lwsl_debug("file completed\n");
 
-                       if (wsi->protocol->callback &&
-                           user_callback_handle_rxflow(wsi->protocol->callback,
+                       if (wsi->a.protocol->callback &&
+                           user_callback_handle_rxflow(wsi->a.protocol->callback,
                                        wsi, LWS_CALLBACK_HTTP_FILE_COMPLETION,
                                        wsi->user_space, NULL, 0) < 0) {
                                        /*
@@ -2850,7 +3286,7 @@ all_sent:
                                         * state, not the root connection at the
                                         * network level
                                         */
-                                       if (wsi->http2_substream)
+                                       if (wsi->mux_substream)
                                                return 1;
                                        else
                                                return -1;
@@ -2875,27 +3311,32 @@ file_had_it:
        return -1;
 }
 
-#ifndef LWS_NO_SERVER
-LWS_VISIBLE void
+#endif
+
+#if defined(LWS_WITH_SERVER)
+void
 lws_server_get_canonical_hostname(struct lws_context *context,
                                  const struct lws_context_creation_info *info)
 {
        if (lws_check_opt(info->options,
                        LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME))
                return;
-#if !defined(LWS_WITH_ESP32)
+#if !defined(LWS_PLAT_FREERTOS)
        /* find canonical hostname */
-       gethostname((char *)context->canonical_hostname,
-                   sizeof(context->canonical_hostname) - 1);
+       if (gethostname((char *)context->canonical_hostname,
+                       sizeof(context->canonical_hostname) - 1))
+               lws_strncpy((char *)context->canonical_hostname, "unknown",
+                           sizeof(context->canonical_hostname));
 
-       lwsl_info(" canonical_hostname = %s\n", context->canonical_hostname);
+       lwsl_cx_info(context, " canonical_hostname = %s\n",
+                                       context->canonical_hostname);
 #else
        (void)context;
 #endif
 }
 #endif
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_chunked_html_process(struct lws_process_html_args *args,
                         struct lws_process_html_state *s)
 {
@@ -2924,14 +3365,14 @@ lws_chunked_html_process(struct lws_process_html_args *args,
                        if (s->pos == sizeof(s->swallow) - 1)
                                goto skip;
                        for (n = 0; n < s->count_vars; n++)
-                               if (!strncmp(s->swallow, s->vars[n], s->pos)) {
+                               if (!strncmp(s->swallow, s->vars[n], (unsigned int)s->pos)) {
                                        hits++;
                                        hit = n;
                                }
                        if (!hits) {
 skip:
                                s->swallow[s->pos] = '\0';
-                               memcpy(s->start, s->swallow, s->pos);
+                               memcpy(s->start, s->swallow, (unsigned int)s->pos);
                                args->len++;
                                s->pos = 0;
                                sp = s->start + 1;
@@ -2945,10 +3386,10 @@ skip:
                                s->swallow[s->pos] = '\0';
                                if (n != s->pos) {
                                        memmove(s->start + n, s->start + s->pos,
-                                               old_len - (sp - args->p) - 1);
+                                               (unsigned int)(old_len - (sp - args->p) - 1));
                                        old_len += (n - s->pos) + 1;
                                }
-                               memcpy(s->start, pc, n);
+                               memcpy(s->start, pc, (unsigned int)n);
                                args->len++;
                                sp = s->start + 1;
 
@@ -2970,7 +3411,7 @@ skip:
                n = sprintf(buffer, "%X\x0d\x0a", args->len);
 
                args->p -= n;
-               memcpy(args->p, buffer, n);
+               memcpy(args->p, buffer, (unsigned int)n);
                args->len += n;
 
                if (args->final) {
diff --git a/lib/roles/listen/CMakeLists.txt b/lib/roles/listen/CMakeLists.txt
new file mode 100644 (file)
index 0000000..035b283
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       roles/listen/ops-listen.c)
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+
index 2f405c7..a4bbaa3 100644 (file)
@@ -1,39 +1,42 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 static int
 rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
                          struct lws_pollfd *pollfd)
 {
-       struct lws_context *context = wsi->context;
-       lws_sockfd_type accept_fd = LWS_SOCK_INVALID;
+       struct lws_context *context = wsi->a.context;
+       struct lws_filter_network_conn_args filt;
        lws_sock_file_fd_type fd;
-       struct sockaddr_storage cli_addr;
-       socklen_t clilen;
+
+       memset(&filt, 0, sizeof(filt));
 
        /* if our vhost is going down, ignore it */
 
-       if (wsi->vhost->being_destroyed)
+       if (wsi->a.vhost->being_destroyed)
                return LWS_HPI_RET_HANDLED;
 
        /* pollin means a client has connected to us then
@@ -56,7 +59,7 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
                 * another vhost may also have had POLLIN on his
                 * listener this round and used it up already
                 */
-               if (wsi->vhost->tls.use_ssl &&
+               if (wsi->a.vhost->tls.use_ssl &&
                    context->simultaneous_ssl_restriction &&
                    context->simultaneous_ssl ==
                                  context->simultaneous_ssl_restriction)
@@ -69,8 +72,7 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
 #endif
                /* listen socket got an unencrypted connection... */
 
-               clilen = sizeof(cli_addr);
-               lws_latency_pre(context, wsi);
+               filt.clilen = sizeof(filt.cli_addr);
 
                /*
                 * We cannot identify the peer who is in the listen
@@ -79,39 +81,41 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
                 * block the connect queue for other legit peers.
                 */
 
-               accept_fd = accept((int)pollfd->fd,
-                                  (struct sockaddr *)&cli_addr, &clilen);
-               lws_latency(context, wsi, "listener accept",
-                           (int)accept_fd, accept_fd != LWS_SOCK_INVALID);
-               if (accept_fd == LWS_SOCK_INVALID) {
+               filt.accept_fd = accept((int)pollfd->fd,
+                                       (struct sockaddr *)&filt.cli_addr,
+                                       &filt.clilen);
+               if (filt.accept_fd == LWS_SOCK_INVALID) {
                        if (LWS_ERRNO == LWS_EAGAIN ||
                            LWS_ERRNO == LWS_EWOULDBLOCK) {
                                break;
                        }
-                       lwsl_err("accept: %s\n", strerror(LWS_ERRNO));
+                       lwsl_err("accept: errno %d\n", LWS_ERRNO);
+
                        return LWS_HPI_RET_HANDLED;
                }
 
                if (context->being_destroyed) {
-                       compatible_close(accept_fd);
+                       compatible_close(filt.accept_fd);
+
                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
                }
 
-               lws_plat_set_socket_options(wsi->vhost, accept_fd, 0);
+               lws_plat_set_socket_options(wsi->a.vhost, filt.accept_fd, 0);
 
 #if defined(LWS_WITH_IPV6)
                lwsl_debug("accepted new conn port %u on fd=%d\n",
-                       ((cli_addr.ss_family == AF_INET6) ?
-                       ntohs(((struct sockaddr_in6 *) &cli_addr)->sin6_port) :
-                       ntohs(((struct sockaddr_in *) &cli_addr)->sin_port)),
-                       accept_fd);
+                       ((filt.cli_addr.ss_family == AF_INET6) ?
+                       ntohs(((struct sockaddr_in6 *) &filt.cli_addr)->sin6_port) :
+                       ntohs(((struct sockaddr_in *) &filt.cli_addr)->sin_port)),
+                       filt.accept_fd);
 #else
                {
                struct sockaddr_in sain;
-               memcpy(&sain, &cli_addr, sizeof(sain));
+
+               memcpy(&sain, &filt.cli_addr, sizeof(sain));
                lwsl_debug("accepted new conn port %u on fd=%d\n",
                           ntohs(sain.sin_port),
-                          accept_fd);
+                          filt.accept_fd);
                }
 #endif
 
@@ -121,42 +125,43 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
                 * protocol selected yet so we issue this to
                 * protocols[0]
                 */
-               if ((wsi->vhost->protocols[0].callback)(wsi,
+               if ((wsi->a.vhost->protocols[0].callback)(wsi,
                                LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
-                               NULL,
-                               (void *)(lws_intptr_t)accept_fd, 0)) {
+                               (void *)&filt,
+                               (void *)(lws_intptr_t)filt.accept_fd, 0)) {
                        lwsl_debug("Callback denied net connection\n");
-                       compatible_close(accept_fd);
-                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
+                       compatible_close(filt.accept_fd);
+                       return LWS_HPI_RET_HANDLED;
                }
 
-               if (!(wsi->vhost->options &
+               if (!(wsi->a.vhost->options &
                        LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG))
                        opts |= LWS_ADOPT_HTTP;
 
 #if defined(LWS_WITH_TLS)
-               if (!wsi->vhost->tls.use_ssl)
+               if (!wsi->a.vhost->tls.use_ssl)
 #endif
                        opts &= ~LWS_ADOPT_ALLOW_SSL;
 
-               fd.sockfd = accept_fd;
-               cwsi = lws_adopt_descriptor_vhost(wsi->vhost, opts, fd,
-                                                 NULL, NULL);
+               fd.sockfd = filt.accept_fd;
+               cwsi = lws_adopt_descriptor_vhost(wsi->a.vhost, (lws_adoption_type)opts, fd,
+                               wsi->a.vhost->listen_accept_protocol, NULL);
                if (!cwsi) {
-                       lwsl_err("%s: lws_adopt_descriptor_vhost failed\n",
-                                       __func__);
+                       lwsl_info("%s: vh %s: adopt failed\n", __func__,
+                                       wsi->a.vhost->name);
+
                        /* already closed cleanly as necessary */
                        return LWS_HPI_RET_WSI_ALREADY_DIED;
                }
 /*
-               if (lws_server_socket_service_ssl(cwsi, accept_fd)) {
+               if (lws_server_socket_service_ssl(cwsi, accept_fd, 1)) {
                        lws_close_free_wsi(cwsi, LWS_CLOSE_STATUS_NOSTATUS,
                                           "listen svc fail");
                        return LWS_HPI_RET_WSI_ALREADY_DIED;
                }
 
-               lwsl_info("%s: new wsi %p: wsistate 0x%lx, role_ops %s\n",
-                           __func__, cwsi, (unsigned long)cwsi->wsistate,
+               lwsl_info("%s: new %s: wsistate 0x%lx, role_ops %s\n",
+                           __func__, lws_wsi_tag(cwsi), (unsigned long)cwsi->wsistate,
                            cwsi->role_ops->name);
 */
 
@@ -172,29 +177,39 @@ int rops_handle_POLLOUT_listen(struct lws *wsi)
        return LWS_HP_RET_USER_SERVICE;
 }
 
-struct lws_role_ops role_ops_listen = {
+static const lws_rops_t rops_table_listen[] = {
+       /*  1 */ { .handle_POLLIN         = rops_handle_POLLIN_listen },
+       /*  2 */ { .handle_POLLOUT        = rops_handle_POLLOUT_listen },
+};
+
+const struct lws_role_ops role_ops_listen = {
        /* role name */                 "listen",
        /* alpn id */                   NULL,
-       /* check_upgrades */            NULL,
-       /* init_context */              NULL,
-       /* init_vhost */                NULL,
-       /* destroy_vhost */             NULL,
-       /* periodic_checks */           NULL,
-       /* service_flag_pending */      NULL,
-       /* handle_POLLIN */             rops_handle_POLLIN_listen,
-       /* handle_POLLOUT */            rops_handle_POLLOUT_listen,
-       /* perform_user_POLLOUT */      NULL,
-       /* callback_on_writable */      NULL,
-       /* tx_credit */                 NULL,
-       /* write_role_protocol */       NULL,
-       /* encapsulation_parent */      NULL,
-       /* alpn_negotiated */           NULL,
-       /* close_via_role_protocol */   NULL,
-       /* close_role */                NULL,
-       /* close_kill_connection */     NULL,
-       /* destroy_role */              NULL,
-       /* adoption_bind */             NULL,
-       /* client_bind */               NULL,
+
+       /* rops_table */                rops_table_listen,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x00,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x01,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x20,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x00,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x00,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x00,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x00,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0x00,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x00,
+                                       },
+
        /* adoption_cb clnt, srv */     { 0, 0 },
        /* rx_cb clnt, srv */           { 0, 0 },
        /* writeable cb clnt, srv */    { 0, 0 },
diff --git a/lib/roles/mqtt/CMakeLists.txt b/lib/roles/mqtt/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a9cfa54
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+if (LWS_WITH_CLIENT)
+       list(APPEND SOURCES
+              roles/mqtt/mqtt.c
+              roles/mqtt/ops-mqtt.c
+              roles/mqtt/primitives.c
+              roles/mqtt/client/client-mqtt.c
+              roles/mqtt/client/client-mqtt-handshake.c
+       )
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
diff --git a/lib/roles/mqtt/client/client-mqtt-handshake.c b/lib/roles/mqtt/client/client-mqtt-handshake.c
new file mode 100644 (file)
index 0000000..ffdf262
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *                           Sakthi Kannan <saktr@amazon.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+#define MQTT_CONNECT_MSG_BASE_LEN (12)
+
+struct lws *
+lws_mqtt_client_send_connect(struct lws *wsi)
+{
+       /* static int */
+       /*      lws_mqttc_abs_writeable(lws_abs_protocol_inst_t *api, size_t budget) */
+       const lws_mqttc_t *c = &wsi->mqtt->client;
+       uint8_t b[256 + LWS_PRE], *start = b + LWS_PRE, *p = start;
+       unsigned int len = MQTT_CONNECT_MSG_BASE_LEN;
+
+       switch (lwsi_state(wsi)) {
+       case LRS_MQTTC_IDLE:
+               /*
+                * Transport connected - this is our chance to do the
+                * protocol connect action.
+                */
+
+               /* 1. Fixed Headers */
+               if (lws_mqtt_fill_fixed_header(p++, LMQCP_CTOS_CONNECT, 0, 0, 0)) {
+                       lwsl_err("%s: Failled to fill fixed header\n", __func__);
+                       return NULL;
+               }
+
+               /*
+                * 2. Remaining length - Add the lengths of client ID,
+                * username and password and their length fields if
+                * the respective flags are set.
+                */
+               len +=  c->id->len;
+               if (c->conn_flags & LMQCFT_USERNAME && c->username) {
+                       len = len + (unsigned int)c->username->len + 2;
+                       if (c->conn_flags & LMQCFT_PASSWORD)
+                               len += (unsigned int)(c->password ? c->password->len : 0) + 2u;
+               }
+               if (c->conn_flags & LMQCFT_WILL_FLAG && c->will.topic) {
+                       len = len + (unsigned int)c->will.topic->len + 2;
+                       len += (c->will.message ? c->will.message->len : 0) + 2u;
+               }
+               p += lws_mqtt_vbi_encode(len, p);
+
+               /*
+                * 3. Variable Header - Protocol name & level, Connect
+                * flags and keep alive time (in secs).
+                */
+               lws_ser_wu16be(p, 4); /* Length of protocol name */
+               p += 2;
+               *p++ = 'M';
+               *p++ = 'Q';
+               *p++ = 'T';
+               *p++ = 'T';
+               *p++ = MQTT_VER_3_1_1;
+               *p++ = (uint8_t)c->conn_flags;
+               lws_ser_wu16be(p, c->keep_alive_secs);
+               p += 2;
+
+               /*
+                * 4. Payload - Client ID, Will topic & message,
+                * Username & password.
+                */
+               if (lws_mqtt_str_is_not_empty(c->id)) {
+                       lws_ser_wu16be(p, c->id->len);
+                       p += 2;
+                       memcpy(p, c->id->buf, c->id->len);
+                       p += c->id->len;
+               } else {
+                       /*
+                        * If the Client supplies a zero-byte
+                        * ClientId, the Client MUST also set
+                        * CleanSession to 1 [MQTT-3.1.3-7].
+                        */
+                       if (!(c->conn_flags & LMQCFT_CLEAN_START)) {
+                               lwsl_err("%s: Empty client ID needs a clean start\n",
+                                        __func__);
+                               return NULL;
+                       }
+                       *p++ = 0;
+               }
+
+               if (c->conn_flags & LMQCFT_WILL_FLAG) {
+                       if (lws_mqtt_str_is_not_empty(c->will.topic)) {
+                               lws_ser_wu16be(p, c->will.topic->len);
+                               p += 2;
+                               memcpy(p, c->will.topic->buf, c->will.topic->len);
+                               p += c->will.topic->len;
+                               if (lws_mqtt_str_is_not_empty(c->will.message)) {
+                                       lws_ser_wu16be(p, c->will.message->len);
+                                       p += 2;
+                                       memcpy(p, c->will.message->buf,
+                                              c->will.message->len);
+                                       p += c->will.message->len;
+                               } else {
+                                       lws_ser_wu16be(p, 0);
+                                       p += 2;
+                               }
+                       } else {
+                               lwsl_err("%s: Missing Will Topic\n", __func__);
+                               return NULL;
+                       }
+               }
+               if (c->conn_flags & LMQCFT_USERNAME) {
+                       /*
+                        * Detailed sanity check on the username and
+                        * password strings.
+                        */
+                       if (lws_mqtt_str_is_not_empty(c->username)) {
+                               lws_ser_wu16be(p, c->username->len);
+                               p += 2;
+                               memcpy(p, c->username->buf, c->username->len);
+                               p += c->username->len;
+                       } else {
+                               lwsl_err("%s: Empty / missing Username!\n",
+                                        __func__);
+                               return NULL;
+                       }
+                       if (c->conn_flags & LMQCFT_PASSWORD) {
+                               if (lws_mqtt_str_is_not_empty(c->password)) {
+                                       lws_ser_wu16be(p, c->password->len);
+                                       p += 2;
+                                       memcpy(p, c->password->buf,
+                                              c->password->len);
+                                       p += c->password->len;
+                               } else {
+                                       lws_ser_wu16be(p, 0);
+                                       p += 2;
+                               }
+                       }
+               } else if (c->conn_flags & LMQCFT_PASSWORD) {
+                       lwsl_err("%s: Unsupported - Password without username\n",
+                                __func__);
+                       return NULL;
+               }
+               break;
+       default:
+               lwsl_err("%s: unexpected state %d\n", __func__, lwsi_state(wsi));
+
+               return NULL;
+       }
+
+       /*
+        * Perform the actual write
+        */
+       if (lws_write(wsi, (unsigned char *)&b[LWS_PRE], lws_ptr_diff_size_t(p, start),
+                 LWS_WRITE_BINARY) != lws_ptr_diff(p, start)) {
+               lwsl_notice("%s: write failed\n", __func__);
+
+               return NULL;
+       }
+
+       return wsi;
+}
+
+struct lws *
+lws_mqtt_client_send_disconnect(struct lws *wsi)
+{
+       uint8_t b[256 + LWS_PRE], *start = b + LWS_PRE, *p = start;
+
+       /* 1. Fixed Headers */
+       if (lws_mqtt_fill_fixed_header(p++, LMQCP_DISCONNECT, 0, 0, 0))
+       {
+               lwsl_err("%s: Failled to fill fixed header\n", __func__);
+               return NULL;
+       }
+       *p++ = 0;
+       if (lws_write(wsi, (unsigned char *)&b[LWS_PRE], lws_ptr_diff_size_t(p, start),
+                               LWS_WRITE_BINARY) != lws_ptr_diff(p, start)) {
+               lwsl_err("%s: write failed\n", __func__);
+
+               return NULL;
+       }
+
+       return wsi;
+}
diff --git a/lib/roles/mqtt/client/client-mqtt.c b/lib/roles/mqtt/client/client-mqtt.c
new file mode 100644 (file)
index 0000000..5324286
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * You can leave buf NULL, if so it will be allocated on the heap once the
+ * actual length is known.  nf should be 0, it will be set at allocation time.
+ *
+ * Or you can ensure no allocation and use an external buffer by setting buf
+ * and lim.  But buf must be in the ep context somehow, since it may have to
+ * survive returns to the event loop unchanged.  Set nf to 0 in this case.
+ *
+ * Or you can set buf to an externally allocated buffer, in which case you may
+ * set nf so it will be freed when the string is "freed".
+ */
+
+#include "private-lib-core.h"
+/* #include "lws-mqtt.h" */
+/* 3.1.3.1-5: MUST allow... that contain only the characters... */
+
+static const uint8_t *code = (const uint8_t *)
+       "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+static int
+lws_mqtt_generate_id(struct lws* wsi, lws_mqtt_str_t **ms, const char *client_id)
+{
+       struct lws_context *context = wsi->a.context;
+       uint16_t ran[24]; /* 16-bit so wrap bias from %62 diluted by ~1000 */
+       size_t n, len;
+       uint8_t *buf;
+
+       if (client_id)
+               len = strlen(client_id);
+       else
+               len = LWS_MQTT_RANDOM_CIDLEN;
+
+       *ms = lws_mqtt_str_create((uint16_t)(len + 1));
+       if (!*ms)
+               return 1;
+
+       buf = lws_mqtt_str_next(*ms, NULL);
+
+       if (client_id) {
+               lws_strnncpy((char *)buf, client_id, len, len + 1);
+               lwsl_notice("%s: User space provided a client ID '%s'\n",
+                           __func__, (const char *)buf);
+       } else {
+               lwsl_notice("%s: generating random client id\n", __func__);
+               n = len * sizeof(ran[0]);
+               if (lws_get_random(context, ran, n) != n) {
+                       lws_mqtt_str_free(ms);
+
+                       return 1;
+               }
+
+               for (n = 0; n < len; n++)
+                       buf[n] = code[ran[n] % 62];
+               buf[len] = '\0';
+       }
+
+       if (lws_mqtt_str_advance(*ms, (uint16_t)len)) {
+               lws_mqtt_str_free(ms);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+lws_read_mqtt(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
+{
+       lws_mqttc_t *c = &wsi->mqtt->client;
+
+       return _lws_mqtt_rx_parser(wsi, &c->par, buf, (size_t)len);
+}
+
+int
+lws_create_client_mqtt_object(const struct lws_client_connect_info *i,
+                             struct lws *wsi)
+{
+       lws_mqttc_t *c;
+       const lws_mqtt_client_connect_param_t *cp = i->mqtt_cp;
+
+       /* allocate the ws struct for the wsi */
+       wsi->mqtt = lws_zalloc(sizeof(*wsi->mqtt), "client mqtt struct");
+       if (!wsi->mqtt)
+               goto oom;
+
+       wsi->mqtt->wsi = wsi;
+       c = &wsi->mqtt->client;
+
+       if (lws_mqtt_generate_id(wsi, &c->id, cp->client_id)) {
+               lwsl_err("%s: Error generating client ID\n", __func__);
+               return 1;
+       }
+       lwsl_info("%s: using client id '%.*s'\n", __func__, c->id->len,
+                       (const char *)c->id->buf);
+
+       if (cp->clean_start || !(cp->client_id &&
+                                cp->client_id[0]))
+               c->conn_flags = LMQCFT_CLEAN_START;
+       if (cp->client_id_nofree)
+               c->conn_flags |= LMQCFT_CLIENT_ID_NOFREE;
+       if (cp->username_nofree)
+               c->conn_flags |= LMQCFT_USERNAME_NOFREE;
+       if (cp->password_nofree)
+               c->conn_flags |= LMQCFT_PASSWORD_NOFREE;
+
+       if (!(c->conn_flags & LMQCFT_CLIENT_ID_NOFREE))
+               lws_free((void *)cp->client_id);
+
+       c->keep_alive_secs = cp->keep_alive;
+       c->aws_iot = cp->aws_iot;
+
+       if (cp->will_param.topic &&
+           *cp->will_param.topic) {
+               c->will.topic = lws_mqtt_str_create_cstr_dup(
+                                               cp->will_param.topic, 0);
+               if (!c->will.topic)
+                       goto oom1;
+               c->conn_flags |= LMQCFT_WILL_FLAG;
+               if (cp->will_param.message) {
+                       c->will.message = lws_mqtt_str_create_cstr_dup(
+                                               cp->will_param.message, 0);
+                       if (!c->will.message)
+                               goto oom2;
+               }
+               c->conn_flags = (uint16_t)(unsigned int)(c->conn_flags | ((cp->will_param.qos << 3) & LMQCFT_WILL_QOS_MASK));
+               c->conn_flags |= (uint16_t)((!!cp->will_param.retain) * LMQCFT_WILL_RETAIN);
+       }
+
+       if (cp->username &&
+           *cp->username) {
+               c->username = lws_mqtt_str_create_cstr_dup(cp->username, 0);
+               if (!c->username)
+                       goto oom3;
+               c->conn_flags |= LMQCFT_USERNAME;
+               if (!(c->conn_flags & LMQCFT_USERNAME_NOFREE))
+                       lws_free((void *)cp->username);
+               if (cp->password) {
+                       c->password =
+                               lws_mqtt_str_create_cstr_dup(cp->password, 0);
+                       if (!c->password)
+                               goto oom4;
+                       c->conn_flags |= LMQCFT_PASSWORD;
+                       if (!(c->conn_flags & LMQCFT_PASSWORD_NOFREE))
+                               lws_free((void *)cp->password);
+               }
+       }
+
+       return 0;
+oom4:
+       lws_mqtt_str_free(&c->username);
+oom3:
+       lws_mqtt_str_free(&c->will.message);
+oom2:
+       lws_mqtt_str_free(&c->will.topic);
+oom1:
+       lws_mqtt_str_free(&c->id);
+oom:
+       lwsl_err("%s: OOM!\n", __func__);
+       return 1;
+}
+
+int
+lws_mqtt_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd,
+                         struct lws *wsi_conn)
+{
+       struct lws_context *context = wsi->a.context;
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+       int n = 0, m = 0;
+       struct lws_tokens ebuf;
+       int buffered = 0;
+       int pending = 0;
+#if defined(LWS_WITH_TLS)
+       char erbuf[128];
+#endif
+       const char *cce = NULL;
+
+       switch (lwsi_state(wsi)) {
+#if defined(LWS_WITH_SOCKS5)
+       /* SOCKS Greeting Reply */
+       case LRS_WAITING_SOCKS_GREETING_REPLY:
+       case LRS_WAITING_SOCKS_AUTH_REPLY:
+       case LRS_WAITING_SOCKS_CONNECT_REPLY:
+
+               switch (lws_socks5c_handle_state(wsi, pollfd, &cce)) {
+               case LW5CHS_RET_RET0:
+                       return 0;
+               case LW5CHS_RET_BAIL3:
+                       goto bail3;
+               case LW5CHS_RET_STARTHS:
+
+                       /*
+                        * Now we got the socks5 connection, we need to go down
+                        * the tls path on it if that's what we want
+                        */
+
+                       if (!(wsi->tls.use_ssl & LCCSCF_USE_SSL))
+                               goto start_ws_handshake;
+
+                       switch (lws_client_create_tls(wsi, &cce, 0)) {
+                       case 0:
+                               break;
+                       case 1:
+                               return 0;
+                       default:
+                               goto bail3;
+                       }
+
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+#endif
+       case LRS_WAITING_DNS:
+               /*
+                * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
+                * timeout protection set in client-handshake.c
+                */
+               if (!lws_client_connect_2_dnsreq(wsi)) {
+                       /* closed */
+                       lwsl_client("closed\n");
+                       return -1;
+               }
+
+               /* either still pending connection, or changed mode */
+               return 0;
+
+       case LRS_WAITING_CONNECT:
+
+               /*
+                * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
+                * timeout protection set in client-handshake.c
+                */
+               if (pollfd->revents & LWS_POLLOUT)
+                       lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL);
+               break;
+
+#if defined(LWS_WITH_TLS)
+       case LRS_WAITING_SSL:
+
+               if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
+                       n = lws_ssl_client_connect2(wsi, erbuf, sizeof(erbuf));
+                       if (!n)
+                               return 0;
+                       if (n < 0) {
+                               cce = erbuf;
+                               goto bail3;
+                       }
+               } else
+                       wsi->tls.ssl = NULL;
+#endif /* LWS_WITH_TLS */
+
+               /* fallthru */
+
+#if defined(LWS_WITH_SOCKS5)
+start_ws_handshake:
+#endif
+               lwsi_set_state(wsi, LRS_MQTTC_IDLE);
+               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
+                               (int)context->timeout_secs);
+
+               /* fallthru */
+
+       case LRS_MQTTC_IDLE:
+               /*
+                * we should be ready to send out MQTT CONNECT
+                */
+               lwsl_info("%s: %s: Transport established, send out CONNECT\n",
+                               __func__, lws_wsi_tag(wsi));
+               if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
+                       return -1;
+               if (!lws_mqtt_client_send_connect(wsi)) {
+                       lwsl_err("%s: Unable to send MQTT CONNECT\n", __func__);
+                       return -1;
+               }
+               if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
+                       return -1;
+
+               lwsi_set_state(wsi, LRS_MQTTC_AWAIT_CONNACK);
+               return 0;
+
+       case LRS_ESTABLISHED:
+       case LRS_MQTTC_AWAIT_CONNACK:
+               buffered = 0;
+               ebuf.token = pt->serv_buf;
+               ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
+
+               if ((unsigned int)ebuf.len > wsi->a.context->pt_serv_buf_size)
+                       ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
+
+               if ((int)pending > ebuf.len)
+                       pending = (char)ebuf.len;
+
+               ebuf.len = lws_ssl_capable_read(wsi, ebuf.token,
+                                               (unsigned int)(pending ? pending :
+                                               ebuf.len));
+               switch (ebuf.len) {
+               case 0:
+                       lwsl_info("%s: zero length read\n",
+                                 __func__);
+                       goto fail;
+               case LWS_SSL_CAPABLE_MORE_SERVICE:
+                       lwsl_info("SSL Capable more service\n");
+                       return 0;
+               case LWS_SSL_CAPABLE_ERROR:
+                       lwsl_info("%s: LWS_SSL_CAPABLE_ERROR\n",
+                                       __func__);
+                       goto fail;
+               }
+
+               if (ebuf.len < 0)
+                       n = -1;
+               else
+                       n = lws_read_mqtt(wsi, ebuf.token, (unsigned int)ebuf.len);
+               if (n < 0) {
+                       lwsl_err("%s: Parsing packet failed\n", __func__);
+                       goto fail;
+               }
+
+               m = ebuf.len - n;
+               // lws_buflist_describe(&wsi->buflist, wsi, __func__);
+               lwsl_debug("%s: consuming %d / %d\n", __func__, n, ebuf.len);
+               if (lws_buflist_aware_finished_consuming(wsi, &ebuf, m,
+                                                        buffered,
+                                                        __func__))
+                       return -1;
+
+               return 0;
+
+#if defined(LWS_WITH_TLS) || defined(LWS_WITH_SOCKS5)
+bail3:
+#endif
+               lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
+               if (cce)
+                       lwsl_info("reason: %s\n", cce);
+               lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
+
+               lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "cbail3");
+               return -1;
+
+       default:
+               break;
+       }
+
+       return 0;
+fail:
+       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "mqtt svc fail");
+
+       return LWS_HPI_RET_WSI_ALREADY_DIED;
+}
diff --git a/lib/roles/mqtt/mqtt.c b/lib/roles/mqtt/mqtt.c
new file mode 100644 (file)
index 0000000..67d64db
--- /dev/null
@@ -0,0 +1,2478 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * MQTT v5
+ *
+ * http://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html
+ *
+ * Control Packet structure
+ *
+ *  - Always:           2+ byte:  Fixed Hdr
+ *  - Required in some: variable: Variable Hdr + [(CONNECT)Will Props] + Props
+ *  - Required in some: variable: Payload
+ *
+ * For CONNECT, the props if present MUST be in the order [MQTT-3.1.3-1]
+ *
+ *  - Client Identifier
+ *  - Will Properties
+ *  - Will Topic
+ *  - Will Payload
+ *  - User Name
+ *  - Password
+ */
+
+#include "private-lib-core.h"
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+
+typedef enum {
+       LMQPRS_AWAITING_CONNECT,
+
+} lws_mqtt_protocol_server_connstate_t;
+
+const char * const reason_names_g1[] = {
+       "Success / Normal disconnection / QoS0",
+       "QoS1",
+       "QoS2",
+       "Disconnect Will",
+       "No matching subscriber",
+       "No subscription existed",
+       "Continue authentication",
+       "Re-authenticate"
+};
+
+const char * const reason_names_g2[] = {
+       "Unspecified error",
+       "Malformed packet",
+       "Protocol error",
+       "Implementation specific error",
+       "Unsupported protocol",
+       "Client ID invalid",
+       "Bad credentials",
+       "Not Authorized",
+       "Server Unavailable",
+       "Server Busy",
+       "Banned",
+       "Server Shutting Down",
+       "Bad Authentication Method",
+       "Keepalive Timeout",
+       "Session taken over",
+       "Topic Filter Invalid",
+       "Packet ID in use",
+       "Packet ID not found",
+       "Max RX Exceeded",
+       "Topic Alias Invalid",
+       "Packet too large",
+       "Ratelimit",
+       "Quota Exceeded",
+       "Administrative Action",
+       "Payload format invalid",
+       "Retain not supported",
+       "QoS not supported",
+       "Use another server",
+       "Server Moved",
+       "Shared subscriptions not supported",
+       "Connection rate exceeded",
+       "Maximum Connect Time",
+       "Subscription IDs not supported",
+       "Wildcard subscriptions not supported"
+};
+
+#define LMQCP_WILL_PROPERTIES 0
+
+/* For each property, a bitmap describing which commands it is valid for */
+
+static const uint16_t property_valid[] = {
+       [LMQPROP_PAYLOAD_FORMAT_INDICATOR]      = (1 << LMQCP_PUBLISH) |
+                                                 (1 << LMQCP_WILL_PROPERTIES),
+       [LMQPROP_MESSAGE_EXPIRY_INTERVAL]       = (1 << LMQCP_PUBLISH) |
+                                                 (1 << LMQCP_WILL_PROPERTIES),
+       [LMQPROP_CONTENT_TYPE]                  = (1 << LMQCP_PUBLISH) |
+                                                 (1 << LMQCP_WILL_PROPERTIES),
+       [LMQPROP_RESPONSE_TOPIC]                = (1 << LMQCP_PUBLISH) |
+                                                 (1 << LMQCP_WILL_PROPERTIES),
+       [LMQPROP_CORRELATION_DATA]              = (1 << LMQCP_PUBLISH) |
+                                                 (1 << LMQCP_WILL_PROPERTIES),
+       [LMQPROP_SUBSCRIPTION_IDENTIFIER]       = (1 << LMQCP_PUBLISH) |
+                                                 (1 << LMQCP_CTOS_SUBSCRIBE),
+       [LMQPROP_SESSION_EXPIRY_INTERVAL]       = (1 << LMQCP_CTOS_CONNECT) |
+                                                 (1 << LMQCP_STOC_CONNACK) |
+                                                 (1 << LMQCP_DISCONNECT),
+       [LMQPROP_ASSIGNED_CLIENT_IDENTIFIER]    = (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_SERVER_KEEP_ALIVE]             = (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_AUTHENTICATION_METHOD]         = (1 << LMQCP_CTOS_CONNECT) |
+                                                 (1 << LMQCP_STOC_CONNACK) |
+                                                 (1 << LMQCP_AUTH),
+       [LMQPROP_AUTHENTICATION_DATA]           = (1 << LMQCP_CTOS_CONNECT) |
+                                                 (1 << LMQCP_STOC_CONNACK) |
+                                                 (1 << LMQCP_AUTH),
+       [LMQPROP_REQUEST_PROBLEM_INFORMATION]   = (1 << LMQCP_CTOS_CONNECT),
+       [LMQPROP_WILL_DELAY_INTERVAL]           = (1 << LMQCP_WILL_PROPERTIES),
+       [LMQPROP_REQUEST_RESPONSE_INFORMATION]  = (1 << LMQCP_CTOS_CONNECT),
+       [LMQPROP_RESPONSE_INFORMATION]          = (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_SERVER_REFERENCE]              = (1 << LMQCP_STOC_CONNACK) |
+                                                 (1 << LMQCP_DISCONNECT),
+       [LMQPROP_REASON_STRING]                 = (1 << LMQCP_STOC_CONNACK) |
+                                                 (1 << LMQCP_PUBACK) |
+                                                 (1 << LMQCP_PUBREC) |
+                                                 (1 << LMQCP_PUBREL) |
+                                                 (1 << LMQCP_PUBCOMP) |
+                                                 (1 << LMQCP_STOC_SUBACK) |
+                                                 (1 << LMQCP_STOC_UNSUBACK) |
+                                                 (1 << LMQCP_DISCONNECT) |
+                                                 (1 << LMQCP_AUTH),
+       [LMQPROP_RECEIVE_MAXIMUM]               = (1 << LMQCP_CTOS_CONNECT) |
+                                                 (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_TOPIC_ALIAS_MAXIMUM]           = (1 << LMQCP_CTOS_CONNECT) |
+                                                 (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_TOPIC_ALIAS]                   = (1 << LMQCP_PUBLISH),
+       [LMQPROP_MAXIMUM_QOS]                   = (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_RETAIN_AVAILABLE]              = (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_USER_PROPERTY]                 = (1 << LMQCP_CTOS_CONNECT) |
+                                                 (1 << LMQCP_STOC_CONNACK) |
+                                                 (1 << LMQCP_PUBLISH) |
+                                                 (1 << LMQCP_WILL_PROPERTIES) |
+                                                 (1 << LMQCP_PUBACK) |
+                                                 (1 << LMQCP_PUBREC) |
+                                                 (1 << LMQCP_PUBREL) |
+                                                 (1 << LMQCP_PUBCOMP) |
+                                                 (1 << LMQCP_CTOS_SUBSCRIBE) |
+                                                 (1 << LMQCP_STOC_SUBACK) |
+                                                 (1 << LMQCP_CTOS_UNSUBSCRIBE) |
+                                                 (1 << LMQCP_STOC_UNSUBACK) |
+                                                 (1 << LMQCP_DISCONNECT) |
+                                                 (1 << LMQCP_AUTH),
+       [LMQPROP_MAXIMUM_PACKET_SIZE]           = (1 << LMQCP_CTOS_CONNECT) |
+                                                 (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_WILDCARD_SUBSCRIPTION_AVAIL]   = (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_SUBSCRIPTION_IDENTIFIER_AVAIL] = (1 << LMQCP_STOC_CONNACK),
+       [LMQPROP_SHARED_SUBSCRIPTION_AVAIL]     = (1 << LMQCP_STOC_CONNACK)
+};
+
+
+/*
+ * For each command index, maps flags, id, qos and payload legality
+ * notice in most cases PUBLISH requires further processing
+ */
+static const uint8_t map_flags[] = {
+       [LMQCP_RESERVED]                = 0x00,
+       [LMQCP_CTOS_CONNECT]            = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PAYLOAD |
+                                         LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
+       [LMQCP_STOC_CONNACK]            = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
+       [LMQCP_PUBLISH]                 = LMQCP_LUT_FLAG_PAYLOAD | /* option */
+                                         LMQCP_LUT_FLAG_PACKET_ID_QOS12 | 0x00,
+       [LMQCP_PUBACK]                  = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x00,
+       [LMQCP_PUBREC]                  = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x00,
+       [LMQCP_PUBREL]                  = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x02,
+       [LMQCP_PUBCOMP]                 = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x00,
+       [LMQCP_CTOS_SUBSCRIBE]          = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PAYLOAD |
+                                         LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x02,
+       [LMQCP_STOC_SUBACK]             = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PAYLOAD |
+                                         LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x00,
+       [LMQCP_CTOS_UNSUBSCRIBE]        = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PAYLOAD |
+                                         LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x02,
+       [LMQCP_STOC_UNSUBACK]           = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PAYLOAD |
+                                         LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
+       [LMQCP_CTOS_PINGREQ]            = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
+       [LMQCP_STOC_PINGRESP]           = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
+       [LMQCP_DISCONNECT]              = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
+       [LMQCP_AUTH]                    = LMQCP_LUT_FLAG_RESERVED_FLAGS |
+                                         LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
+};
+
+void
+lws_mqttc_state_transition(lws_mqttc_t *c, lwsgs_mqtt_states_t s)
+{
+       lwsl_debug("%s: ep %p: state %d -> %d\n", __func__, c, c->estate, s);
+       c->estate = s;
+}
+
+static int
+lws_mqtt_pconsume(lws_mqtt_parser_t *par, int consumed)
+{
+       par->consumed += (unsigned int)consumed;
+
+       if (par->consumed > par->props_len)
+               return -1;
+
+       /* more properties coming */
+
+       if (par->consumed < par->props_len) {
+               par->state = LMQCPP_PROP_ID_VBI;
+               return 0;
+       }
+
+       /* properties finished: are we headed for payload or idle? */
+
+       if ((map_flags[ctl_pkt_type(par)] & LMQCP_LUT_FLAG_PAYLOAD) &&
+               /* A PUBLISH packet MUST NOT contain a Packet Identifier if
+                * its QoS value is set to 0 [MQTT-2.2.1-2]. */
+           (ctl_pkt_type(par) != LMQCP_PUBLISH ||
+            (par->packet_type_flags & 6))) {
+               par->state = LMQCPP_PAYLOAD;
+               return 0;
+       }
+
+       par->state = LMQCPP_IDLE;
+
+       return 0;
+}
+
+static int
+lws_mqtt_set_client_established(struct lws *wsi)
+{
+       lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
+                           &role_ops_mqtt);
+
+       if (user_callback_handle_rxflow(wsi->a.protocol->callback,
+                                       wsi, LWS_CALLBACK_MQTT_CLIENT_ESTABLISHED,
+                                       wsi->user_space, NULL, 0) < 0) {
+               lwsl_err("%s: MQTT_ESTABLISHED failed\n", __func__);
+
+               return -1;
+       }
+       /*
+        * If we made a new connection and got the ACK, our connection is
+        * definitely working in both directions at the moment
+        */
+       lws_validity_confirmed(wsi);
+
+       /* clear connection timeout */
+       lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+       return 0;
+}
+
+
+static lws_mqtt_match_topic_return_t
+lws_mqtt_is_topic_matched(const char* sub, const char* pub)
+{
+       const char *ppos = pub, *spos = sub;
+
+       if (!ppos || !spos) {
+               return LMMTR_TOPIC_MATCH_ERROR;
+       }
+
+       while (*spos) {
+               if (*ppos == '#' || *ppos == '+') {
+                       lwsl_err("%s: PUBLISH to wildcard "
+                                "topic \"%s\" not supported\n",
+                                __func__, pub);
+                       return LMMTR_TOPIC_MATCH_ERROR;
+               }
+               /* foo/+/bar == foo/xyz/bar ? */
+               if (*spos == '+') {
+                       /* Skip ahead */
+                       while (*ppos != '\0' && *ppos != '/') {
+                               ppos++;
+                       }
+               } else if (*spos == '#') {
+                       return LMMTR_TOPIC_MATCH;
+               } else {
+                       if (*ppos == '\0') {
+                               /* foo/bar == foo/bar/# ? */
+                               if (!strncmp(spos, "/#", 2))
+                                       return LMMTR_TOPIC_MATCH;
+                               return LMMTR_TOPIC_NOMATCH;
+                       /* Non-matching character */
+                       } else if (*ppos != *spos) {
+                               return LMMTR_TOPIC_NOMATCH;
+                       }
+                       ppos++;
+               }
+               spos++;
+       }
+
+       if (*spos == '\0' && *ppos == '\0')
+               return LMMTR_TOPIC_MATCH;
+
+       return LMMTR_TOPIC_NOMATCH;
+}
+
+lws_mqtt_subs_t* lws_mqtt_find_sub(struct _lws_mqtt_related* mqtt,
+                                  const char* ptopic) {
+       lws_mqtt_subs_t *s = mqtt->subs_head;
+
+       while (s) {
+               /*  SUB topic  ==   PUB topic  ? */
+               /* foo/bar/xyz ==  foo/bar/xyz ? */
+               if (!s->wildcard) {
+                       if (!strcmp((const char*)s->topic, ptopic))
+                               return s;
+               } else {
+                       if (lws_mqtt_is_topic_matched(
+                           s->topic, ptopic) == LMMTR_TOPIC_MATCH)
+                               return s;
+               }
+
+               s = s->next;
+       }
+
+       return NULL;
+}
+
+static lws_mqtt_validate_topic_return_t
+lws_mqtt_validate_topic(const char *topic, size_t topiclen, uint8_t awsiot)
+{
+       size_t spos = 0;
+       const char *sub = topic;
+       int8_t slashes = 0;
+       lws_mqtt_validate_topic_return_t ret = LMVTR_VALID;
+
+       if (awsiot) {
+               if (topiclen > LWS_MQTT_MAX_AWSIOT_TOPICLEN)
+                       return LMVTR_FAILED_OVERSIZE;
+               if (topic[0] == '$') {
+                       ret = LMVTR_VALID_SHADOW;
+                       slashes = -3;
+               }
+       } else {
+               if (topiclen > LWS_MQTT_MAX_TOPICLEN)
+                       return LMVTR_FAILED_OVERSIZE;
+               if (topic[0] == '$')
+                       return LMVTR_FAILED_WILDCARD_FORMAT;
+       }
+
+       while (*sub != 0) {
+               if (sub[0] == '+') {
+                       /* topic == "+foo" || "a/+foo" ? */
+                       if (spos > 0 && sub[-1] != '/')
+                               return LMVTR_FAILED_WILDCARD_FORMAT;
+
+                       /* topic == "foo+" or "foo+/a" ? */
+                       if (sub[1] != 0 && sub[1] != '/')
+                               return LMVTR_FAILED_WILDCARD_FORMAT;
+
+                       ret = LMVTR_VALID_WILDCARD;
+               } else if (sub[0] == '#') {
+                       /* topic == "foo#" ? */
+                       if (spos > 0 && sub[-1] != '/')
+                               return LMVTR_FAILED_WILDCARD_FORMAT;
+
+                       /* topic == "#foo" ? */
+                       if (sub[1] != 0)
+                               return LMVTR_FAILED_WILDCARD_FORMAT;
+
+                       ret = LMVTR_VALID_WILDCARD;
+               } else if (sub[0] == '/') {
+                       slashes++;
+               }
+               spos++;
+               sub++;
+       }
+
+       if (awsiot && (slashes < 0 || slashes > 7))
+               return LMVTR_FAILED_SHADOW_FORMAT;
+
+       return ret;
+}
+
+static lws_mqtt_subs_t *
+lws_mqtt_create_sub(struct _lws_mqtt_related *mqtt, const char *topic)
+{
+       lws_mqtt_subs_t *mysub;
+       size_t topiclen = strlen(topic);
+       lws_mqtt_validate_topic_return_t flag;
+
+       flag = lws_mqtt_validate_topic(topic, topiclen, mqtt->client.aws_iot);
+       switch (flag) {
+       case LMVTR_FAILED_OVERSIZE:
+               lwsl_err("%s: Topic is too long\n",
+                        __func__);
+               return NULL;
+       case LMVTR_FAILED_SHADOW_FORMAT:
+       case LMVTR_FAILED_WILDCARD_FORMAT:
+               lwsl_err("%s: Invalid topic format \"%s\"\n",
+                        __func__, topic);
+               return NULL;
+
+       case LMVTR_VALID:
+       case LMVTR_VALID_WILDCARD:
+       case LMVTR_VALID_SHADOW:
+               mysub = lws_malloc(sizeof(*mysub) + topiclen + 1, "sub");
+               if (!mysub) {
+                       lwsl_err("%s: Error allocating mysub\n",
+                                __func__);
+                       return NULL;
+               }
+               mysub->wildcard = (flag == LMVTR_VALID_WILDCARD);
+               mysub->shadow = (flag == LMVTR_VALID_SHADOW);
+               break;
+
+       default:
+               lwsl_err("%s: Unknown flag - %d\n",
+                        __func__, flag);
+               return NULL;
+       }
+
+       mysub->next = mqtt->subs_head;
+       mqtt->subs_head = mysub;
+       memcpy(mysub->topic, topic, strlen(topic) + 1);
+       mysub->ref_count = 1;
+
+       lwsl_info("%s: Created mysub %p for wsi->mqtt %p\n",
+                 __func__, mysub, mqtt);
+
+       return mysub;
+}
+
+static int
+lws_mqtt_client_remove_subs(struct _lws_mqtt_related *mqtt)
+{
+       lws_mqtt_subs_t *s = mqtt->subs_head;
+       lws_mqtt_subs_t *temp = NULL;
+
+
+       lwsl_info("%s: Called to remove subs from wsi->mqtt %p\n",
+                 __func__, mqtt);
+
+       while (s && s->next) {
+               if (s->next->ref_count == 0)
+                       break;
+               s = s->next;
+       }
+
+       if (s && s->next) {
+               temp = s->next;
+               lwsl_info("%s: Removing sub %p from wsi->mqtt %p\n",
+                         __func__, temp, mqtt);
+               s->next = temp->next;
+               lws_free(temp);
+               return 0;
+       }
+       return 1;
+}
+
+int
+_lws_mqtt_rx_parser(struct lws *wsi, lws_mqtt_parser_t *par,
+                   const uint8_t *buf, size_t len)
+{
+       struct lws *w;
+       int n;
+
+       if (par->flag_pending_send_reason_close)
+               return 0;
+
+       /*
+        * Stateful, fragmentation-immune parser
+        *
+        * Notice that len can always be 1 if under attack, even over tls if
+        * the server is compromised or malicious.
+        */
+
+       while (len) {
+               lwsl_debug("%s: %d, len = %d\n", __func__, par->state, (int)len);
+               switch (par->state) {
+               case LMQCPP_IDLE:
+                       par->packet_type_flags = *buf++;
+                       len--;
+
+#if defined(LWS_WITH_CLIENT)
+                       /*
+                        * The case where we sent the connect, but we received
+                        * something else before any CONNACK
+                        */
+                       if (lwsi_state(wsi) == LRS_MQTTC_AWAIT_CONNACK &&
+                           par->packet_type_flags >> 4 != LMQCP_STOC_CONNACK) {
+                               lwsl_notice("%s: server sent non-CONNACK\n",
+                                               __func__);
+                               goto send_protocol_error_and_close;
+                       }
+#endif /* LWS_WITH_CLIENT */
+
+                       n = map_flags[par->packet_type_flags >> 4];
+                       /*
+                        *  Where a flag bit is marked as “Reserved”, it is
+                        *  reserved for future use and MUST be set to the value
+                        *  listed [MQTT-2.1.3-1].
+                        */
+                       if ((n & LMQCP_LUT_FLAG_RESERVED_FLAGS) &&
+                           ((par->packet_type_flags & 0x0f) != (n & 0x0f))) {
+                               lwsl_notice("%s: %s: bad flags, 0x%02x mask 0x%02x (len %d)\n",
+                                           __func__, lws_wsi_tag(wsi),
+                                           par->packet_type_flags, n, (int)len + 1);
+                               lwsl_hexdump_err(buf - 1, len + 1);
+                               goto send_protocol_error_and_close;
+                       }
+
+                       lwsl_debug("%s: received pkt type 0x%x / flags 0x%x\n",
+                                  __func__, par->packet_type_flags >> 4,
+                                  par->packet_type_flags & 0xf);
+
+                       /* allows us to know if a property that can only be
+                        * given once, appears twice */
+                       memset(par->props_seen, 0, sizeof(par->props_seen));
+                       par->state = par->packet_type_flags & 0xf0;
+                       break;
+
+               case LMQCPP_CONNECT_PACKET:
+                       lwsl_debug("%s: received CONNECT pkt\n", __func__);
+                       par->state = LMQCPP_CONNECT_REMAINING_LEN_VBI;
+                       lws_mqtt_vbi_init(&par->vbit);
+                       break;
+
+               case LMQCPP_CONNECT_REMAINING_LEN_VBI:
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->cpkt_remlen = par->vbit.value;
+                               n = map_flags[ctl_pkt_type(par)];
+                               lws_mqtt_str_init(&par->s_temp, par->temp,
+                                                 sizeof(par->temp), 0);
+                               par->state = LMQCPP_CONNECT_VH_PNAME;
+                               break;
+                       default:
+                               lwsl_notice("%s: bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_CONNECT_VH_PNAME:
+                       switch (lws_mqtt_str_parse(&par->s_temp, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               if (par->s_temp.len != 4 ||
+                                   memcmp(par->s_temp.buf, "MQTT",
+                                          par->s_temp.len)) {
+                                       lwsl_notice("%s: protocol name: %.*s\n",
+                                                 __func__, par->s_temp.len,
+                                                 par->s_temp.buf);
+                                       goto send_unsupp_connack_and_close;
+                               }
+                               par->state = LMQCPP_CONNECT_VH_PVERSION;
+                               break;
+                       default:
+                               lwsl_notice("%s: bad protocol name\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_CONNECT_VH_PVERSION:
+                       par->conn_protocol_version = *buf++;
+                       len--;
+                       if (par->conn_protocol_version != 5) {
+                               lwsl_info("%s: unsupported MQTT version %d\n",
+                                         __func__, par->conn_protocol_version);
+                               goto send_unsupp_connack_and_close;
+                       }
+                       par->state = LMQCPP_CONNECT_VH_FLAGS;
+                       break;
+
+               case LMQCPP_CONNECT_VH_FLAGS:
+                       par->cpkt_flags = *buf++;
+                       len--;
+                       if (par->cpkt_flags & 1) {
+                               /*
+                                * The Server MUST validate that the reserved
+                                * flag in the CONNECT packet is set to 0
+                                * [MQTT-3.1.2-3].
+                                */
+                               par->reason = LMQCP_REASON_MALFORMED_PACKET;
+                               goto send_reason_and_close;
+                       }
+                       /*
+                        * conn_flags specifies the Will Properties that should
+                        * appear in the payload section
+                        */
+                       lws_mqtt_2byte_init(&par->vbit);
+                       par->state = LMQCPP_CONNECT_VH_KEEPALIVE;
+                       break;
+
+               case LMQCPP_CONNECT_VH_KEEPALIVE:
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->keepalive = (uint16_t)par->vbit.value;
+                               lws_mqtt_vbi_init(&par->vbit);
+                               par->state = LMQCPP_CONNECT_VH_PROPERTIES_VBI_LEN;
+                               break;
+                       default:
+                               lwsl_notice("%s: ka bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_PINGRESP_ZERO:
+                       len--;
+                       /* second byte of PINGRESP must be zero */
+                       if (*buf++)
+                               goto send_protocol_error_and_close;
+                       goto cmd_completion;
+
+               case LMQCPP_CONNECT_VH_PROPERTIES_VBI_LEN:
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               /* reset consumption counter */
+                               par->consumed = 0;
+                               par->props_len = par->vbit.value;
+                               lws_mqtt_vbi_init(&par->vbit);
+                               par->state = LMQCPP_PROP_ID_VBI;
+                               break;
+                       default:
+                               lwsl_notice("%s: connpr bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               /* PUBREC */
+               case LMQCPP_PUBREC_PACKET:
+                       lwsl_debug("%s: received PUBREC pkt\n", __func__);
+                       lws_mqtt_vbi_init(&par->vbit);
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->cpkt_remlen = par->vbit.value;
+                               lwsl_debug("%s: PUBREC pkt len = %d\n",
+                                          __func__, (int)par->cpkt_remlen);
+                               if (par->cpkt_remlen < 2)
+                                       goto send_protocol_error_and_close;
+                               par->state = LMQCPP_PUBREC_VH_PKT_ID;
+                               break;
+                       default:
+                               lwsl_notice("%s: pubrec bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_PUBREC_VH_PKT_ID:
+                       if (len < 2) {
+                               lwsl_notice("%s: len breakage 3\n", __func__);
+                               return -1;
+                       }
+
+                       par->cpkt_id = lws_ser_ru16be(buf);
+                       wsi->mqtt->ack_pkt_id = par->cpkt_id;
+                       buf += 2;
+                       len -= 2;
+                       par->cpkt_remlen -= 2;
+                       par->n = 0;
+
+                       goto cmd_completion;
+
+               /* PUBREL */
+               case LMQCPP_PUBREL_PACKET:
+                       lwsl_debug("%s: received PUBREL pkt\n", __func__);
+                       lws_mqtt_vbi_init(&par->vbit);
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->cpkt_remlen = par->vbit.value;
+                               lwsl_debug("%s: PUBREL pkt len = %d\n",
+                                          __func__, (int)par->cpkt_remlen);
+                               if (par->cpkt_remlen < 2)
+                                       goto send_protocol_error_and_close;
+                               par->state = LMQCPP_PUBREL_VH_PKT_ID;
+                               break;
+                       default:
+                               lwsl_err("%s: pubrel bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_PUBREL_VH_PKT_ID:
+                       if (len < 2) {
+                               lwsl_notice("%s: len breakage 3\n", __func__);
+                               return -1;
+                       }
+
+                       par->cpkt_id = lws_ser_ru16be(buf);
+                       wsi->mqtt->ack_pkt_id = par->cpkt_id;
+                       buf += 2;
+                       len -= 2;
+                       par->cpkt_remlen -= 2;
+                       par->n = 0;
+
+                       goto cmd_completion;
+
+               /* PUBCOMP */
+               case LMQCPP_PUBCOMP_PACKET:
+                       lwsl_debug("%s: received PUBCOMP pkt\n", __func__);
+                       lws_mqtt_vbi_init(&par->vbit);
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->cpkt_remlen = par->vbit.value;
+                               lwsl_debug("%s: PUBCOMP pkt len = %d\n",
+                                          __func__, (int)par->cpkt_remlen);
+                               if (par->cpkt_remlen < 2)
+                                       goto send_protocol_error_and_close;
+                               par->state = LMQCPP_PUBCOMP_VH_PKT_ID;
+                               break;
+                       default:
+                               lwsl_err("%s: pubcmp bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_PUBCOMP_VH_PKT_ID:
+                       if (len < 2) {
+                               lwsl_notice("%s: len breakage 3\n", __func__);
+                               return -1;
+                       }
+
+                       par->cpkt_id = lws_ser_ru16be(buf);
+                       wsi->mqtt->ack_pkt_id = par->cpkt_id;
+                       buf += 2;
+                       len -= 2;
+                       par->cpkt_remlen -= 2;
+                       par->n = 0;
+
+                       goto cmd_completion;
+
+               case LMQCPP_PUBLISH_PACKET:
+                       if (lwsi_role_client(wsi) && wsi->mqtt->inside_subscribe) {
+                               lwsl_notice("%s: Topic rx before subscribing\n",
+                                           __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       lwsl_info("%s: received PUBLISH pkt\n", __func__);
+                       par->state = LMQCPP_PUBLISH_REMAINING_LEN_VBI;
+                       lws_mqtt_vbi_init(&par->vbit);
+                       break;
+               case LMQCPP_PUBLISH_REMAINING_LEN_VBI:
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->cpkt_remlen = par->vbit.value;
+                               lwsl_debug("%s: PUBLISH pkt len = %d\n",
+                                          __func__, (int)par->cpkt_remlen);
+                               /* Move on to PUBLISH's variable header */
+                               par->state = LMQCPP_PUBLISH_VH_TOPIC;
+                               break;
+                       default:
+                               lwsl_notice("%s: pubrem bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_PUBLISH_VH_TOPIC:
+               {
+                       lws_mqtt_publish_param_t *pub = NULL;
+
+                       if (len < 2) {
+                               lwsl_notice("%s: topic too short\n", __func__);
+                               return -1;
+                       }
+
+                       /* Topic len */
+                       par->n = lws_ser_ru16be(buf);
+                       buf += 2;
+                       len -= 2;
+
+                       if (len < par->n) {/* the way this is written... */
+                               lwsl_notice("%s: len breakage\n", __func__);
+                               return -1;
+                       }
+
+                       /* Invalid topic len */
+                       if (par->n == 0) {
+                               lwsl_notice("%s: zero topic len\n", __func__);
+                               par->reason = LMQCP_REASON_MALFORMED_PACKET;
+                               goto send_reason_and_close;
+                       }
+                       lwsl_debug("%s: PUBLISH topic len %d\n",
+                                  __func__, (int)par->n);
+                       assert(!wsi->mqtt->rx_cpkt_param);
+                       wsi->mqtt->rx_cpkt_param = lws_zalloc(
+                               sizeof(lws_mqtt_publish_param_t), "rx pub param");
+                       if (!wsi->mqtt->rx_cpkt_param)
+                               goto oom;
+                       pub = (lws_mqtt_publish_param_t *)wsi->mqtt->rx_cpkt_param;
+
+                       pub->topic_len = (uint16_t)par->n;
+
+                       /* Topic Name */
+                       pub->topic = (char *)lws_zalloc((size_t)pub->topic_len + 1,
+                                                       "rx publish topic");
+                       if (!pub->topic)
+                               goto oom;
+                       lws_strncpy(pub->topic, (const char *)buf,
+                                   (size_t)pub->topic_len + 1);
+                       buf += pub->topic_len;
+                       len -= pub->topic_len;
+
+                       /* Extract QoS Level from Fixed Header Flags */
+                       pub->qos = (lws_mqtt_qos_levels_t)
+                                       ((par->packet_type_flags >> 1) & 0x3);
+
+                       pub->payload_pos = 0;
+
+                       pub->payload_len = par->cpkt_remlen -
+                               (unsigned int)(2 + pub->topic_len + ((pub->qos) ? 2 : 0));
+
+                       switch (pub->qos) {
+                       case QOS0:
+                               par->state = LMQCPP_PAYLOAD;
+                               if (pub->payload_len == 0)
+                                       goto cmd_completion;
+
+                               break;
+                       case QOS1:
+                       case QOS2:
+                               par->state = LMQCPP_PUBLISH_VH_PKT_ID;
+                               break;
+                       default:
+                               par->reason = LMQCP_REASON_MALFORMED_PACKET;
+                               lws_free_set_NULL(pub->topic);
+                               lws_free_set_NULL(wsi->mqtt->rx_cpkt_param);
+                               goto send_reason_and_close;
+                       }
+                       break;
+               }
+               case LMQCPP_PUBLISH_VH_PKT_ID:
+               {
+                       lws_mqtt_publish_param_t *pub =
+                               (lws_mqtt_publish_param_t *)wsi->mqtt->rx_cpkt_param;
+
+                       if (len < 2) {
+                               lwsl_notice("%s: len breakage 2\n", __func__);
+                               return -1;
+                       }
+
+                       par->cpkt_id = lws_ser_ru16be(buf);
+                       buf += 2;
+                       len -= 2;
+                       wsi->mqtt->peer_ack_pkt_id = par->cpkt_id;
+                       lwsl_debug("%s: Packet ID %d\n",
+                                       __func__, (int)par->cpkt_id);
+                       par->state = LMQCPP_PAYLOAD;
+                       pub->payload_pos = 0;
+                       pub->payload_len = par->cpkt_remlen -
+                               (unsigned int)(2 + pub->topic_len + ((pub->qos) ? 2 : 0));
+                       if (pub->payload_len == 0)
+                               goto cmd_completion;
+
+                       break;
+               }
+               case LMQCPP_PAYLOAD:
+               {
+                       lws_mqtt_publish_param_t *pub =
+                               (lws_mqtt_publish_param_t *)wsi->mqtt->rx_cpkt_param;
+                       if (pub == NULL) {
+                               lwsl_err("%s: Uninitialized pub_param\n",
+                                               __func__);
+                               goto send_protocol_error_and_close;
+                       }
+
+                       pub->payload = buf;
+                       goto cmd_completion;
+               }
+
+               case LMQCPP_CONNACK_PACKET:
+                       if (!lwsi_role_client(wsi)) {
+                               lwsl_err("%s: CONNACK is only Server to Client",
+                                               __func__);
+                               goto send_unsupp_connack_and_close;
+                       }
+
+                       lwsl_debug("%s: received CONNACK pkt\n", __func__);
+                       lws_mqtt_vbi_init(&par->vbit);
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->cpkt_remlen = par->vbit.value;
+                               lwsl_debug("%s: CONNACK pkt len = %d\n",
+                                          __func__, (int)par->cpkt_remlen);
+                               if (par->cpkt_remlen != 2)
+                                       goto send_protocol_error_and_close;
+
+                               par->state = LMQCPP_CONNACK_VH_FLAGS;
+                               break;
+                       default:
+                               lwsl_notice("%s: connack bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_CONNACK_VH_FLAGS:
+               {
+                       lws_mqttc_t *c = &wsi->mqtt->client;
+                       par->cpkt_flags = *buf++;
+                       len--;
+
+                       if (par->cpkt_flags & ~LMQCFT_SESSION_PRESENT) {
+                               /*
+                                * Byte 1 is the "Connect Acknowledge
+                                * Flags". Bits 7-1 are reserved and
+                                * MUST be set to 0.
+                                */
+                               par->reason = LMQCP_REASON_MALFORMED_PACKET;
+                               goto send_reason_and_close;
+                       }
+                       /*
+                        * If the Server accepts a connection with
+                        * CleanSession set to 1, the Server MUST set
+                        * Session Present to 0 in the CONNACK packet
+                        * in addition to setting a zero return code
+                        * in the CONNACK packet [MQTT-3.2.2-1]. If
+                        * the Server accepts a connection with
+                        * CleanSession set to 0, the value set in
+                        * Session Present depends on whether the
+                        * Server already has stored Session state for
+                        * the supplied client ID. If the Server has
+                        * stored Session state, it MUST set
+                        * SessionPresent to 1 in the CONNACK packet
+                        * [MQTT-3.2.2-2]. If the Server does not have
+                        * stored Session state, it MUST set Session
+                        * Present to 0 in the CONNACK packet. This is
+                        * in addition to setting a zero return code
+                        * in the CONNACK packet [MQTT-3.2.2-3].
+                        */
+                       if ((c->conn_flags & LMQCFT_CLEAN_START) &&
+                           (par->cpkt_flags & LMQCFT_SESSION_PRESENT))
+                               goto send_protocol_error_and_close;
+
+                       wsi->mqtt->session_resumed = ((unsigned int)par->cpkt_flags &
+                                                     LMQCFT_SESSION_PRESENT);
+
+                       /* Move on to Connect Return Code */
+                       par->state = LMQCPP_CONNACK_VH_RETURN_CODE;
+                       break;
+               }
+               case LMQCPP_CONNACK_VH_RETURN_CODE:
+                       par->conn_rc = *buf++;
+                       len--;
+                       /*
+                        * If a server sends a CONNACK packet containing a
+                        * non-zero return code it MUST then close the Network
+                        * Connection [MQTT-3.2.2-5]
+                        */
+                       switch (par->conn_rc) {
+                       case 0:
+                               goto cmd_completion;
+                       case 1:
+                       case 2:
+                       case 3:
+                       case 4:
+                       case 5:
+                               par->reason = LMQCP_REASON_UNSUPPORTED_PROTOCOL +
+                                               par->conn_rc - 1;
+                               goto send_reason_and_close;
+                       default:
+                               lwsl_notice("%s: bad connack retcode\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               /* SUBACK */
+               case LMQCPP_SUBACK_PACKET:
+                       if (!lwsi_role_client(wsi)) {
+                               lwsl_err("%s: SUBACK is only Server to Client",
+                                               __func__);
+                               goto send_unsupp_connack_and_close;
+                       }
+
+                       lwsl_debug("%s: received SUBACK pkt\n", __func__);
+                       lws_mqtt_vbi_init(&par->vbit);
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->cpkt_remlen = par->vbit.value;
+                               lwsl_debug("%s: SUBACK pkt len = %d\n",
+                                          __func__, (int)par->cpkt_remlen);
+                               if (par->cpkt_remlen <= 2)
+                                       goto send_protocol_error_and_close;
+                               par->state = LMQCPP_SUBACK_VH_PKT_ID;
+                               break;
+                       default:
+                               lwsl_notice("%s: suback bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_SUBACK_VH_PKT_ID:
+
+                       if (len < 2) {
+                               lwsl_notice("%s: len breakage 4\n", __func__);
+                               return -1;
+                       }
+
+                       par->cpkt_id = lws_ser_ru16be(buf);
+                       wsi->mqtt->ack_pkt_id = par->cpkt_id;
+                       buf += 2;
+                       len -= 2;
+                       par->cpkt_remlen -= 2;
+                       par->n = 0;
+                       par->state = LMQCPP_SUBACK_PAYLOAD;
+                       *par->temp = 0;
+                       break;
+
+               case LMQCPP_SUBACK_PAYLOAD:
+               {
+                       lws_mqtt_qos_levels_t qos = (lws_mqtt_qos_levels_t)*buf++;
+
+                       len--;
+                       switch (qos) {
+                               case QOS0:
+                               case QOS1:
+                               case QOS2:
+                                       break;
+                               case FAILURE_QOS_LEVEL:
+                                       goto send_protocol_error_and_close;
+
+                               default:
+                                       par->reason = LMQCP_REASON_MALFORMED_PACKET;
+                                       goto send_reason_and_close;
+                       }
+
+                       if (++(par->n) == par->cpkt_remlen) {
+                               par->n = 0;
+                               goto cmd_completion;
+                       }
+
+                       break;
+               }
+
+               /* UNSUBACK */
+               case LMQCPP_UNSUBACK_PACKET:
+                       if (!lwsi_role_client(wsi)) {
+                               lwsl_err("%s: UNSUBACK is only Server to Client",
+                                               __func__);
+                               goto send_unsupp_connack_and_close;
+                       }
+
+                       lwsl_debug("%s: received UNSUBACK pkt\n", __func__);
+                       lws_mqtt_vbi_init(&par->vbit);
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->cpkt_remlen = par->vbit.value;
+                               lwsl_debug("%s: UNSUBACK pkt len = %d\n",
+                                          __func__, (int)par->cpkt_remlen);
+                               if (par->cpkt_remlen < 2)
+                                       goto send_protocol_error_and_close;
+                               par->state = LMQCPP_UNSUBACK_VH_PKT_ID;
+                               break;
+                       default:
+                               lwsl_notice("%s: unsuback bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_UNSUBACK_VH_PKT_ID:
+
+                       if (len < 2) {
+                               lwsl_notice("%s: len breakage 3\n", __func__);
+                               return -1;
+                       }
+
+                       par->cpkt_id = lws_ser_ru16be(buf);
+                       wsi->mqtt->ack_pkt_id = par->cpkt_id;
+                       buf += 2;
+                       len -= 2;
+                       par->cpkt_remlen -= 2;
+                       par->n = 0;
+
+                       goto cmd_completion;
+
+               case LMQCPP_PUBACK_PACKET:
+                       lws_mqtt_vbi_init(&par->vbit);
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->cpkt_remlen = par->vbit.value;
+                               lwsl_info("%s: PUBACK pkt len = %d\n", __func__,
+                                         (int)par->cpkt_remlen);
+                               /*
+                                * must be 4 or more, with special case that 2
+                                * means success with no reason code or props
+                                */
+                               if (par->cpkt_remlen <= 1 ||
+                                   par->cpkt_remlen == 3)
+                                       goto send_protocol_error_and_close;
+
+                               par->state = LMQCPP_PUBACK_VH_PKT_ID;
+                               par->fixed_seen[2] = par->fixed_seen[3] = 0;
+                               par->fixed = 0;
+                               par->n = 0;
+                               break;
+                       default:
+                               lwsl_notice("%s: puback bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_PUBACK_VH_PKT_ID:
+                       /*
+                        * There are 3 fixed bytes and then a VBI for the
+                        * property section length
+                        */
+                       par->fixed_seen[par->fixed++] = *buf++;
+                       if (len < par->cpkt_remlen - par->n) {
+                               lwsl_notice("%s: len breakage 4\n", __func__);
+                               return -1;
+                       }
+                       len--;
+                       par->n++;
+                       if (par->fixed == 2)
+                               par->cpkt_id = lws_ser_ru16be(par->fixed_seen);
+
+                       if (par->fixed == 3) {
+                               lws_mqtt_vbi_init(&par->vbit);
+                               par->props_consumed = 0;
+                               par->state = LMQCPP_PUBACK_PROPERTIES_LEN_VBI;
+                       }
+                       /* length of 2 is truncated packet and we completed it */
+                       if (par->cpkt_remlen == par->fixed)
+                               goto cmd_completion;
+                       break;
+
+               case LMQCPP_PUBACK_PROPERTIES_LEN_VBI:
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->props_len = par->vbit.value;
+                               lwsl_info("%s: PUBACK props len = %d\n",
+                                         __func__, (int)par->cpkt_remlen);
+                               /*
+                                * If there are no properties, this is a
+                                * command completion event in itself
+                                */
+                               if (!par->props_len)
+                                       goto cmd_completion;
+
+                               /*
+                                * Otherwise consume the properties before
+                                * completing the command
+                                */
+                               lws_mqtt_vbi_init(&par->vbit);
+                               par->state = LMQCPP_PUBACK_VH_PKT_ID;
+                               break;
+                       default:
+                               lwsl_notice("%s: puback pr bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_EAT_PROPERTIES_AND_COMPLETE:
+                       /*
+                        * TODO: stash the props
+                        */
+                       par->props_consumed++;
+                       len--;
+                       buf++;
+                       if (par->props_len != par->props_consumed)
+                               break;
+
+cmd_completion:
+                       /*
+                        * We come here when we understood we just processed
+                        * the last byte of a command packet, regardless of the
+                        * packet type
+                        */
+                       par->state = LMQCPP_IDLE;
+
+                       switch (par->packet_type_flags >> 4) {
+                       case LMQCP_STOC_CONNACK:
+                               lwsl_info("%s: cmd_completion: CONNACK\n",
+                                         __func__);
+
+                               /*
+                                * Getting the CONNACK means we are the first,
+                                * the nwsi, and we succeeded to create a new
+                                * network connection ourselves.
+                                *
+                                * Since others may join us sharing the nwsi,
+                                * and we may close while they still want to use
+                                * it, our wsi lifecycle alone can no longer
+                                * define the lifecycle of the nwsi... it means
+                                * we need to do a "magic trick" and instead of
+                                * being both the nwsi and act like a child
+                                * stream, create a new wsi to take over the
+                                * nwsi duties and turn our wsi into a child of
+                                * the nwsi with its own lifecycle.
+                                *
+                                * The nwsi gets a mostly empty wsi->nwsi used
+                                * to track already-subscribed topics globally
+                                * for the connection.
+                                */
+
+                               /* we were under SENT_CLIENT_HANDSHAKE timeout */
+                               lws_set_timeout(wsi, 0, 0);
+
+                               w = lws_create_new_server_wsi(wsi->a.vhost,
+                                                             wsi->tsi, "mqtt_sid1");
+                               if (!w) {
+                                       lwsl_notice("%s: sid 1 migrate failed\n",
+                                                       __func__);
+                                       return -1;
+                               }
+
+                               wsi->mux.highest_sid = 1;
+                               lws_wsi_mux_insert(w, wsi, wsi->mux.highest_sid++);
+
+                               wsi->mux_substream = 1;
+                               w->mux_substream = 1;
+                               w->client_mux_substream = 1;
+                               wsi->client_mux_migrated = 1;
+                               wsi->told_user_closed = 1; /* don't tell nwsi closed */
+
+                               lwsi_set_state(w, LRS_ESTABLISHED);
+                               lwsi_set_state(wsi, LRS_ESTABLISHED);
+                               lwsi_set_role(w, lwsi_role(wsi));
+
+#if defined(LWS_WITH_CLIENT)
+                               w->flags = wsi->flags;
+#endif
+
+                               w->mqtt = wsi->mqtt;
+                               wsi->mqtt = lws_zalloc(sizeof(*wsi->mqtt), "nwsi mqtt");
+                               if (!wsi->mqtt)
+                                       return -1;
+                               w->mqtt->wsi = w;
+                               w->a.protocol = wsi->a.protocol;
+                               if (w->user_space &&
+                                   !w->user_space_externally_allocated)
+                                       lws_free_set_NULL(w->user_space);
+                               w->user_space = wsi->user_space;
+                               wsi->user_space = NULL;
+                               w->user_space_externally_allocated =
+                                       wsi->user_space_externally_allocated;
+                               if (lws_ensure_user_space(w))
+                                       goto bail1;
+                               w->a.opaque_user_data = wsi->a.opaque_user_data;
+                               wsi->a.opaque_user_data = NULL;
+                               w->stash = wsi->stash;
+                               wsi->stash = NULL;
+
+                               lws_mux_mark_immortal(w);
+
+                               lwsl_notice("%s: migrated nwsi %s to sid 1 %s\n",
+                                               __func__, lws_wsi_tag(wsi),
+                                               lws_wsi_tag(w));
+
+                               /*
+                                * It was the last thing we were waiting for
+                                * before we can be fully ESTABLISHED
+                                */
+                               if (lws_mqtt_set_client_established(w)) {
+                                       lwsl_notice("%s: set EST fail\n", __func__);
+                                       return -1;
+                               }
+
+                               /* get the ball rolling */
+                               lws_validity_confirmed(wsi);
+
+                               /* well, add the queued guys as children */
+                               lws_wsi_mux_apply_queue(wsi);
+                               break;
+
+bail1:
+                               /* undo the insert */
+                               wsi->mux.child_list = w->mux.sibling_list;
+                               wsi->mux.child_count--;
+
+                               if (w->user_space)
+                                       lws_free_set_NULL(w->user_space);
+                               w->a.vhost->protocols[0].callback(w,
+                                                       LWS_CALLBACK_WSI_DESTROY,
+                                                       NULL, NULL, 0);
+                               __lws_vhost_unbind_wsi(w); /* cx + vh lock */
+                               lws_free(w);
+
+                               return 0;
+
+                       case LMQCP_PUBREC:
+                               lwsl_err("%s: cmd_completion: PUBREC\n",
+                                               __func__);
+                               /*
+                                * Figure out which child asked for this
+                                */
+                               n = 0;
+                               lws_start_foreach_ll(struct lws *, w,
+                                                    wsi->mux.child_list) {
+                                       if (w->mqtt->unacked_publish &&
+                                           w->mqtt->ack_pkt_id == par->cpkt_id) {
+                                               char requested_close = 0;
+
+                                               w->mqtt->unacked_publish = 0;
+                                               w->mqtt->unacked_pubrel = 1;
+
+                                               if (user_callback_handle_rxflow(
+                                                           w->a.protocol->callback,
+                                                           w, LWS_CALLBACK_MQTT_ACK,
+                                                           w->user_space, NULL, 0) < 0) {
+                                                       lwsl_info("%s: MQTT_ACK requests close\n",
+                                                                __func__);
+                                                       requested_close = 1;
+                                               }
+                                               n = 1;
+
+                                               /*
+                                                * We got an assertive PUBREC,
+                                                * no need for timeout wait
+                                                * any more
+                                                */
+                                               lws_sul_cancel(&w->mqtt->
+                                                         sul_qos_puback_pubrec_wait);
+
+                                               if (requested_close) {
+                                                       __lws_close_free_wsi(w,
+                                                               0, "ack cb");
+                                                       break;
+                                               }
+
+                                               break;
+                                       }
+                               } lws_end_foreach_ll(w, mux.sibling_list);
+
+                               if (!n) {
+                                       lwsl_err("%s: unsolicited PUBREC\n",
+                                                       __func__);
+                                       return -1;
+                               }
+                               wsi->mqtt->send_pubrel = 1;
+                               lws_callback_on_writable(wsi);
+                               break;
+
+                       case LMQCP_PUBCOMP:
+                               lwsl_err("%s: cmd_completion: PUBCOMP\n",
+                                               __func__);
+                               n = 0;
+                               lws_start_foreach_ll(struct lws *, w,
+                                                    wsi->mux.child_list) {
+                                       if (w->mqtt->unacked_pubrel > 0 &&
+                                           w->mqtt->ack_pkt_id == par->cpkt_id) {
+                                               w->mqtt->unacked_pubrel = 0;
+                                               n = 1;
+                                       }
+                               } lws_end_foreach_ll(w, mux.sibling_list);
+
+                               if (!n) {
+                                       lwsl_err("%s: unsolicited PUBCOMP\n",
+                                                       __func__);
+                                       return -1;
+                               }
+
+                               /*
+                                * If we published something and PUBCOMP arrived,
+                                * our connection is definitely working in both
+                                * directions at the moment.
+                                */
+                               lws_validity_confirmed(wsi);
+                               break;
+
+                       case LMQCP_PUBREL:
+                               lwsl_err("%s: cmd_completion: PUBREL\n",
+                                               __func__);
+                               wsi->mqtt->send_pubcomp = 1;
+                               lws_callback_on_writable(wsi);
+                               break;
+
+                       case LMQCP_PUBACK:
+                               lwsl_info("%s: cmd_completion: PUBACK\n",
+                                               __func__);
+
+                               /*
+                                * Figure out which child asked for this
+                                */
+
+                               n = 0;
+                               lws_start_foreach_ll(struct lws *, w,
+                                                     wsi->mux.child_list) {
+                                       if (w->mqtt->unacked_publish &&
+                                           w->mqtt->ack_pkt_id == par->cpkt_id) {
+                                               char requested_close = 0;
+
+                                               w->mqtt->unacked_publish = 0;
+                                               if (user_callback_handle_rxflow(
+                                                           w->a.protocol->callback,
+                                                           w, LWS_CALLBACK_MQTT_ACK,
+                                                           w->user_space, NULL, 0) < 0) {
+                                                       lwsl_info("%s: MQTT_ACK requests close\n",
+                                                                __func__);
+                                                       requested_close = 1;
+                                               }
+                                               n = 1;
+
+                                               /*
+                                                * We got an assertive PUBACK,
+                                                * no need for ACK timeout wait
+                                                * any more
+                                                */
+                                               lws_sul_cancel(&w->mqtt->sul_qos_puback_pubrec_wait);
+
+                                               if (requested_close) {
+                                                       __lws_close_free_wsi(w,
+                                                               0, "ack cb");
+                                                       break;
+                                               }
+
+                                               break;
+                                       }
+                               } lws_end_foreach_ll(w, mux.sibling_list);
+
+                               if (!n) {
+                                       lwsl_err("%s: unsolicited PUBACK\n",
+                                                       __func__);
+                                       return -1;
+                               }
+
+                               /*
+                                * If we published something and it was acked,
+                                * our connection is definitely working in both
+                                * directions at the moment.
+                                */
+                               lws_validity_confirmed(wsi);
+                               break;
+
+                       case LMQCP_STOC_PINGRESP:
+                               lwsl_info("%s: cmd_completion: PINGRESP\n",
+                                               __func__);
+                               /*
+                                * If we asked for a PINGRESP and it came,
+                                * our connection is definitely working in both
+                                * directions at the moment.
+                                */
+                               lws_validity_confirmed(wsi);
+                               break;
+
+                       case LMQCP_STOC_SUBACK:
+                               lwsl_info("%s: cmd_completion: SUBACK\n",
+                                               __func__);
+
+                               /*
+                                * Figure out which child asked for this
+                                */
+
+                               n = 0;
+                               lws_start_foreach_ll(struct lws *, w,
+                                                     wsi->mux.child_list) {
+                                       if (w->mqtt->inside_subscribe &&
+                                           w->mqtt->ack_pkt_id == par->cpkt_id) {
+                                               w->mqtt->inside_subscribe = 0;
+                                               if (user_callback_handle_rxflow(
+                                                           w->a.protocol->callback,
+                                                           w, LWS_CALLBACK_MQTT_SUBSCRIBED,
+                                                           w->user_space, NULL, 0) < 0) {
+                                                       lwsl_err("%s: MQTT_SUBSCRIBE failed\n",
+                                                                __func__);
+                                                       return -1;
+                                               }
+                                               n = 1;
+                                               break;
+                                       }
+                               } lws_end_foreach_ll(w, mux.sibling_list);
+
+                               if (!n) {
+                                       lwsl_err("%s: unsolicited SUBACK\n",
+                                                       __func__);
+                                       return -1;
+                               }
+
+                               /*
+                                * If we subscribed to something and SUBACK came,
+                                * our connection is definitely working in both
+                                * directions at the moment.
+                                */
+                               lws_validity_confirmed(wsi);
+
+                               break;
+
+                       case LMQCP_STOC_UNSUBACK:
+                       {
+                               char requested_close = 0;
+                               lwsl_info("%s: cmd_completion: UNSUBACK\n",
+                                               __func__);
+                               /*
+                                * Figure out which child asked for this
+                                */
+                               n = 0;
+                               lws_start_foreach_ll(struct lws *, w,
+                                                     wsi->mux.child_list) {
+                                       if (w->mqtt->inside_unsubscribe &&
+                                           w->mqtt->ack_pkt_id == par->cpkt_id) {
+                                               struct lws *nwsi = lws_get_network_wsi(w);
+
+                                               /*
+                                                * No more subscribers left,
+                                                * remove the topic from nwsi
+                                                */
+                                               lws_mqtt_client_remove_subs(nwsi->mqtt);
+
+                                               w->mqtt->inside_unsubscribe = 0;
+                                               if (user_callback_handle_rxflow(
+                                                           w->a.protocol->callback,
+                                                           w, LWS_CALLBACK_MQTT_UNSUBSCRIBED,
+                                                           w->user_space, NULL, 0) < 0) {
+                                                       lwsl_info("%s: MQTT_UNSUBACK requests close\n",
+                                                                __func__);
+                                                       requested_close = 1;
+                                               }
+                                               n = 1;
+
+                                               lws_sul_cancel(&w->mqtt->sul_unsuback_wait);
+                                               if (requested_close) {
+                                                       __lws_close_free_wsi(w,
+                                                                            0, "unsub ack cb");
+                                                       break;
+                                               }
+                                               break;
+                                       }
+                               } lws_end_foreach_ll(w, mux.sibling_list);
+
+                               if (!n) {
+                                       lwsl_err("%s: unsolicited UNSUBACK\n",
+                                                       __func__);
+                                       return -1;
+                               }
+
+
+                               /*
+                                * If we unsubscribed to something and
+                                * UNSUBACK came, our connection is
+                                * definitely working in both
+                                * directions at the moment.
+                                */
+                               lws_validity_confirmed(wsi);
+
+                               break;
+                       }
+                       case LMQCP_PUBLISH:
+                       {
+                               lws_mqtt_publish_param_t *pub =
+                                               (lws_mqtt_publish_param_t *)
+                                                       wsi->mqtt->rx_cpkt_param;
+                               size_t chunk;
+
+                               if (pub == NULL) {
+                                       lwsl_notice("%s: no pub\n", __func__);
+                                       return -1;
+                               }
+
+                               /*
+                                * RX PUBLISH is delivered to any children that
+                                * registered for the related topic
+                                */
+
+                               n = wsi->role_ops->rx_cb[lwsi_role_server(wsi)];
+
+                               chunk = pub->payload_len - pub->payload_pos;
+                               if (chunk > len)
+                                       chunk = len;
+
+                               lws_start_foreach_ll(struct lws *, w,
+                                                     wsi->mux.child_list) {
+                                       if (lws_mqtt_find_sub(w->mqtt,
+                                                             pub->topic))
+                                               if (w->a.protocol->callback(
+                                                           w, (enum lws_callback_reasons)n,
+                                                           w->user_space,
+                                                           (void *)pub,
+                                                           chunk)) {
+                                                               par->payload_consumed = 0;
+                                                               lws_free_set_NULL(pub->topic);
+                                                               lws_free_set_NULL(wsi->mqtt->rx_cpkt_param);
+                                                               return 1;
+                                                       }
+                               } lws_end_foreach_ll(w, mux.sibling_list);
+
+
+                               pub->payload_pos += (uint32_t)chunk;
+                               len -= chunk;
+                               buf += chunk;
+
+                               lwsl_debug("%s: post pos %d, plen %d, len %d\n",
+                                           __func__, (int)pub->payload_pos,
+                                           (int)pub->payload_len, (int)len);
+
+                               if (pub->payload_pos != pub->payload_len) {
+                                       /*
+                                        * More chunks of the payload pending,
+                                        * blocking this connection from doing
+                                        * anything else
+                                        */
+                                       par->state = LMQCPP_PAYLOAD;
+                                       break;
+                               }
+
+                               if (pub->qos == 1) {
+                               /* For QOS = 1, send out PUBACK */
+                                       wsi->mqtt->send_puback = 1;
+                                       lws_callback_on_writable(wsi);
+                               } else if (pub->qos == 2) {
+                               /* For QOS = 2, send out PUBREC */
+                                       wsi->mqtt->send_pubrec = 1;
+                                       lws_callback_on_writable(wsi);
+                               }
+
+                               par->payload_consumed = 0;
+                               lws_free_set_NULL(pub->topic);
+                               lws_free_set_NULL(wsi->mqtt->rx_cpkt_param);
+
+                               break;
+                       }
+                       default:
+                               break;
+                       }
+
+                       break;
+
+
+               case LMQCPP_PROP_ID_VBI:
+                       switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               par->consumed = (uint32_t)((unsigned int)par->consumed + (unsigned int)(unsigned char)par->vbit.consumed);
+                               if (par->vbit.value >
+                                   LWS_ARRAY_SIZE(property_valid)) {
+                                       lwsl_notice("%s: undef prop id 0x%x\n",
+                                                 __func__, (int)par->vbit.value);
+                                       goto send_protocol_error_and_close;
+                               }
+                               if (!(property_valid[par->vbit.value] &
+                                       (1 << ctl_pkt_type(par)))) {
+                                       lwsl_notice("%s: prop id 0x%x invalid for"
+                                                 " control pkt %d\n", __func__,
+                                                 (int)par->vbit.value,
+                                                 ctl_pkt_type(par));
+                                       goto send_protocol_error_and_close;
+                               }
+                               par->prop_id = par->vbit.value;
+                               par->flag_prop_multi = !!(
+                                       par->props_seen[par->prop_id >> 3] &
+                                       (1 << (par->prop_id & 7)));
+                               par->props_seen[par->prop_id >> 3] =
+                                               (uint8_t)((par->props_seen[par->prop_id >> 3]) | (1 << (par->prop_id & 7)));
+                               /*
+                                *  even if it's not a vbi property arg,
+                                * .consumed of this will be zero the first time
+                                */
+                               lws_mqtt_vbi_init(&par->vbit);
+                               /*
+                                * if it's a string, next state must set the
+                                * destination and size limit itself.  But
+                                * resetting it generically here lets it use
+                                * lws_mqtt_str_first() to understand it's the
+                                * first time around.
+                                */
+                                lws_mqtt_str_init(&par->s_temp, NULL, 0, 0);
+
+                               /* property arg state enums are so encoded */
+                               par->state = 0x100 | par->vbit.value;
+                               break;
+                       default:
+                               lwsl_notice("%s: prop id bad vbi\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               /*
+                * All possible property payloads... restricting which ones
+                * can appear in which control packets is already done above
+                * in LMQCPP_PROP_ID_VBI
+                */
+
+               case LMQCPP_PROP_REQUEST_PROBLEM_INFO_1BYTE:
+               case LMQCPP_PROP_REQUEST_REPSONSE_INFO_1BYTE:
+               case LMQCPP_PROP_MAXIMUM_QOS_1BYTE:
+               case LMQCPP_PROP_RETAIN_AVAILABLE_1BYTE:
+               case LMQCPP_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE_1BYTE:
+               case LMQCPP_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE_1BYTE:
+               case LMQCPP_PROP_SHARED_SUBSCRIPTION_AVAILABLE_1BYTE:
+               case LMQCPP_PROP_PAYLOAD_FORMAT_INDICATOR_1BYTE: /* 3.3.2.3.2 */
+                       if (par->flag_prop_multi)
+                               goto singular_prop_seen_twice;
+                       par->payload_format = *buf++;
+                       len--;
+                       if (lws_mqtt_pconsume(par, 1))
+                               goto send_protocol_error_and_close;
+                       break;
+
+               case LMQCPP_PROP_MAXIMUM_PACKET_SIZE_4BYTE:
+               case LMQCPP_PROP_WILL_DELAY_INTERVAL_4BYTE:
+               case LMQCPP_PROP_SESSION_EXPIRY_INTERVAL_4BYTE:
+               case LMQCPP_PROP_MSG_EXPIRY_INTERVAL_4BYTE:
+                       if (par->flag_prop_multi)
+                               goto singular_prop_seen_twice;
+
+                       if (lws_mqtt_mb_first(&par->vbit))
+                               lws_mqtt_4byte_init(&par->vbit);
+
+                       switch (lws_mqtt_mb_parse(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               if (lws_mqtt_pconsume(par, par->vbit.consumed))
+                                       goto send_protocol_error_and_close;
+                               break;
+                       default:
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_PROP_SERVER_KEEPALIVE_2BYTE:
+               case LMQCPP_PROP_RECEIVE_MAXIMUM_2BYTE:
+               case LMQCPP_PROP_TOPIC_MAXIMUM_2BYTE:
+               case LMQCPP_PROP_TOPIC_ALIAS_2BYTE:
+                       if (par->flag_prop_multi)
+                               goto singular_prop_seen_twice;
+
+                       if (lws_mqtt_mb_first(&par->vbit))
+                               lws_mqtt_2byte_init(&par->vbit);
+
+                       switch (lws_mqtt_mb_parse(&par->vbit, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               if (lws_mqtt_pconsume(par, par->vbit.consumed))
+                                       goto send_protocol_error_and_close;
+                               break;
+                       default:
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_PROP_ASSIGNED_CLIENTID_UTF8S:
+               case LMQCPP_PROP_AUTH_METHOD_UTF8S:
+               case LMQCPP_PROP_USER_PROPERTY_NAME_UTF8S:
+               case LMQCPP_PROP_USER_PROPERTY_VALUE_UTF8S:
+               case LMQCPP_PROP_RESPONSE_INFO_UTF8S:
+               case LMQCPP_PROP_SERVER_REFERENCE_UTF8S:
+               case LMQCPP_PROP_REASON_STRING_UTF8S:
+               case LMQCPP_PROP_RESPONSE_TOPIC_UTF8S:
+               case LMQCPP_PROP_CONTENT_TYPE_UTF8S:
+                       if (par->flag_prop_multi)
+                               goto singular_prop_seen_twice;
+
+                       if (lws_mqtt_str_first(&par->s_temp))
+                               lws_mqtt_str_init(&par->s_temp, par->temp,
+                                                 sizeof(par->temp), 0);
+
+                       switch (lws_mqtt_str_parse(&par->s_temp, &buf, &len)) {
+                       case LMSPR_NEED_MORE:
+                               break;
+                       case LMSPR_COMPLETED:
+                               if (lws_mqtt_pconsume(par, par->s_temp.len))
+                                       goto send_protocol_error_and_close;
+                               break;
+
+                       default:
+                               lwsl_info("%s: bad protocol name\n", __func__);
+                               goto send_protocol_error_and_close;
+                       }
+                       break;
+
+               case LMQCPP_PROP_SUBSCRIPTION_ID_VBI:
+
+               case LMQCPP_PROP_CORRELATION_BINDATA:
+               case LMQCPP_PROP_AUTH_DATA_BINDATA:
+
+               /* TODO */
+                       lwsl_err("%s: Unimplemented packet state 0x%x\n",
+                                       __func__, par->state);
+                       return -1;
+               }
+       }
+
+       return 0;
+
+oom:
+       lwsl_err("%s: OOM!\n", __func__);
+       goto send_protocol_error_and_close;
+
+singular_prop_seen_twice:
+       lwsl_info("%s: property appears twice\n", __func__);
+
+send_protocol_error_and_close:
+       lwsl_notice("%s: peac\n", __func__);
+       par->reason = LMQCP_REASON_PROTOCOL_ERROR;
+
+send_reason_and_close:
+       lwsl_notice("%s: srac\n", __func__);
+       par->flag_pending_send_reason_close = 1;
+       goto ask;
+
+send_unsupp_connack_and_close:
+       lwsl_notice("%s: unsupac\n", __func__);
+       par->reason = LMQCP_REASON_UNSUPPORTED_PROTOCOL;
+       par->flag_pending_send_connack_close = 1;
+
+ask:
+       /* Should we ask for clients? */
+       lws_callback_on_writable(wsi);
+
+       return -1;
+}
+
+int
+lws_mqtt_fill_fixed_header(uint8_t *p, lws_mqtt_control_packet_t ctrl_pkt_type,
+                          uint8_t dup, lws_mqtt_qos_levels_t qos,
+                          uint8_t retain)
+{
+       lws_mqtt_fixed_hdr_t hdr;
+
+       hdr.bits = 0;
+       hdr.flags.ctrl_pkt_type = ctrl_pkt_type & 0xf;
+
+       switch(ctrl_pkt_type) {
+       case LMQCP_PUBLISH:
+               hdr.flags.dup = !!dup;
+               /*
+                * A PUBLISH Packet MUST NOT have both QoS bits set to
+                * 1. If a Server or Client receives a PUBLISH Packet
+                * which has both QoS bits set to 1 it MUST close the
+                * Network Connection [MQTT-3.3.1-4].
+                */
+               if (qos >= RESERVED_QOS_LEVEL) {
+                       lwsl_err("%s: Unsupport QoS level 0x%x\n",
+                                __func__, qos);
+                       return -1;
+               }
+               hdr.flags.qos = qos & 3;
+               hdr.flags.retain = !!retain;
+               break;
+
+       case LMQCP_CTOS_CONNECT:
+       case LMQCP_STOC_CONNACK:
+       case LMQCP_PUBACK:
+       case LMQCP_PUBREC:
+       case LMQCP_PUBCOMP:
+       case LMQCP_STOC_SUBACK:
+       case LMQCP_STOC_UNSUBACK:
+       case LMQCP_CTOS_PINGREQ:
+       case LMQCP_STOC_PINGRESP:
+       case LMQCP_DISCONNECT:
+       case LMQCP_AUTH:
+               hdr.bits &= 0xf0;
+               break;
+
+       /*
+        * Bits 3,2,1 and 0 of the fixed header of the PUBREL,
+        * SUBSCRIBE, UNSUBSCRIBE Control Packets are reserved and
+        * MUST be set to 0,0,1 and 0 respectively. The Server MUST
+        * treat any other value as malformed and close the Network
+        * Connection [MQTT-3.6.1-1], [MQTT-3.8.1-1], [MQTT-3.10.1-1].
+        */
+       case LMQCP_PUBREL:
+       case LMQCP_CTOS_SUBSCRIBE:
+       case LMQCP_CTOS_UNSUBSCRIBE:
+               hdr.bits |= 0x02;
+               break;
+
+       default:
+               return -1;
+       }
+
+       *p = hdr.bits;
+
+       return 0;
+}
+
+/*
+ * This fires if the wsi did a PUBLISH under QoS1 or QoS2, but no PUBACK or
+ * PUBREC came before the timeout period
+ */
+
+static void
+lws_mqtt_publish_resend(struct lws_sorted_usec_list *sul)
+{
+       struct _lws_mqtt_related *mqtt = lws_container_of(sul,
+                       struct _lws_mqtt_related, sul_qos_puback_pubrec_wait);
+
+       lwsl_notice("%s: %s\n", __func__, lws_wsi_tag(mqtt->wsi));
+
+       if (mqtt->wsi->a.protocol->callback(mqtt->wsi, LWS_CALLBACK_MQTT_RESEND,
+                               mqtt->wsi->user_space, NULL, 0))
+               lws_set_timeout(mqtt->wsi, 1, LWS_TO_KILL_ASYNC);
+}
+
+static void
+lws_mqtt_unsuback_timeout(struct lws_sorted_usec_list *sul)
+{
+       struct _lws_mqtt_related *mqtt = lws_container_of(sul,
+                       struct _lws_mqtt_related, sul_unsuback_wait);
+
+       lwsl_debug("%s: %s\n", __func__, lws_wsi_tag(mqtt->wsi));
+
+       if (mqtt->wsi->a.protocol->callback(mqtt->wsi,
+                                          LWS_CALLBACK_MQTT_UNSUBSCRIBE_TIMEOUT,
+                                          mqtt->wsi->user_space, NULL, 0))
+               lws_set_timeout(mqtt->wsi, 1, LWS_TO_KILL_ASYNC);
+}
+
+int
+lws_mqtt_client_send_publish(struct lws *wsi, lws_mqtt_publish_param_t *pub,
+                            const void *buf, uint32_t len, int is_complete)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       uint8_t *b = (uint8_t *)pt->serv_buf, *start, *p;
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+       lws_mqtt_str_t mqtt_vh_payload;
+       uint32_t vh_len, rem_len;
+
+       assert(pub->topic);
+
+       lwsl_debug("%s: len = %d, is_complete = %d\n",
+                  __func__, (int)len, (int)is_complete);
+
+       if (lwsi_state(wsi) != LRS_ESTABLISHED) {
+               lwsl_err("%s: %s: unknown state 0x%x\n", __func__,
+                               lws_wsi_tag(wsi), lwsi_state(wsi));
+               assert(0);
+               return 1;
+       }
+
+       if (wsi->mqtt->inside_payload) {
+               /*
+                * Headers are filled, we are sending
+                * the payload - a buffer with LWS_PRE
+                * in front it.
+                */
+               start = (uint8_t *)buf;
+               p = start + len;
+               if (is_complete)
+                       wsi->mqtt->inside_payload = 0;
+               goto do_write;
+       }
+
+       start = b + LWS_PRE;
+       p = start;
+       /*
+        * Fill headers and the first chunk of the
+        * payload (if any)
+        */
+       if (lws_mqtt_fill_fixed_header(p++, LMQCP_PUBLISH,
+                                      0, pub->qos, 0)) {
+               lwsl_err("%s: Failed to fill fixed header\n", __func__);
+               return 1;
+       }
+
+       /*
+        * Topic len field + Topic len + Packet ID
+        * (for QOS>0) + Payload len
+        */
+       vh_len = (unsigned int)(2 + pub->topic_len + ((pub->qos) ? 2 : 0));
+       rem_len = vh_len + pub->payload_len;
+       lwsl_debug("%s: Remaining len = %d\n", __func__, (int) rem_len);
+
+       /* Will the chunk of payload fit? */
+       if ((vh_len + len) >=
+           (wsi->a.context->pt_serv_buf_size - LWS_PRE)) {
+               lwsl_err("%s: Payload is too big\n", __func__);
+               return 1;
+       }
+
+       p += lws_mqtt_vbi_encode(rem_len, p);
+
+       /* Topic's Len */
+       lws_ser_wu16be(p, pub->topic_len);
+       p += 2;
+
+       /*
+        * Init lws_mqtt_str for "MQTT Variable
+        * Headers + payload" (only the supplied
+        * chuncked payload)
+        */
+       lws_mqtt_str_init(&mqtt_vh_payload, (uint8_t *)p,
+                         (uint16_t)(unsigned int)(pub->topic_len + ((pub->qos) ? 2u : 0u) + len),
+                         0);
+
+       p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+       lws_strncpy((char *)p, pub->topic, (size_t)pub->topic_len+1);
+       if (lws_mqtt_str_advance(&mqtt_vh_payload, pub->topic_len)) {
+               lwsl_err("%s: a\n", __func__);
+               return 1;
+       }
+
+       /* Packet ID */
+       if (pub->qos != QOS0) {
+               p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+               wsi->mqtt->ack_pkt_id = pub->packet_id = ++nwsi->mqtt->pkt_id;
+               lwsl_debug("%s: pkt_id = %d\n", __func__,
+                          (int)wsi->mqtt->ack_pkt_id);
+               lws_ser_wu16be(p, pub->packet_id);
+               if (lws_mqtt_str_advance(&mqtt_vh_payload, 2)) {
+                       lwsl_err("%s: b\n", __func__);
+                       return 1;
+               }
+       }
+
+       p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+       memcpy(p, buf, len);
+       if (lws_mqtt_str_advance(&mqtt_vh_payload, (int)len))
+               return 1;
+       p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+
+       if (!is_complete)
+               nwsi->mqtt->inside_payload = wsi->mqtt->inside_payload = 1;
+
+do_write:
+
+       // lwsl_hexdump_err(start, lws_ptr_diff(p, start));
+
+       if (lws_write(nwsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_BINARY) !=
+                       lws_ptr_diff(p, start)) {
+               lwsl_err("%s: write failed\n", __func__);
+               return 1;
+       }
+
+       if (!is_complete) {
+               /* still some more chunks to come... */
+               lws_callback_on_writable(wsi);
+
+               return 0;
+       }
+
+       wsi->mqtt->inside_payload = nwsi->mqtt->inside_payload = 0;
+
+       if (pub->qos != QOS0)
+               wsi->mqtt->unacked_publish = 1;
+
+       /* this was the last part of the publish message */
+
+       if (pub->qos == QOS0) {
+               /*
+                * There won't be any real PUBACK, act like we got one
+                * so the user callback logic is the same for QoS0 or
+                * QoS1
+                */
+               if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_MQTT_ACK,
+                                           wsi->user_space, NULL, 0)) {
+                       lwsl_err("%s: ACK callback exited\n", __func__);
+                       return 1;
+               }
+       } else if (pub->qos == QOS1 || pub->qos == QOS2) {
+               /* For QoS1 or QoS2, if no PUBACK or PUBREC coming after 3s,
+                * we must RETRY the publish
+                */
+               wsi->mqtt->sul_qos_puback_pubrec_wait.cb = lws_mqtt_publish_resend;
+               __lws_sul_insert_us(&pt->pt_sul_owner[wsi->conn_validity_wakesuspend],
+                                   &wsi->mqtt->sul_qos_puback_pubrec_wait,
+                                   3 * LWS_USEC_PER_SEC);
+       }
+
+       return 0;
+}
+
+int
+lws_mqtt_client_send_subcribe(struct lws *wsi, lws_mqtt_subscribe_param_t *sub)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       uint8_t *b = (uint8_t *)pt->serv_buf + LWS_PRE, *start = b, *p = start;
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+       lws_mqtt_str_t mqtt_vh_payload;
+       uint8_t exists[8], extant;
+       lws_mqtt_subs_t *mysub;
+       uint32_t rem_len;
+#if defined(_DEBUG)
+       uint32_t tops;
+#endif
+       uint32_t n;
+
+       assert(sub->num_topics);
+       assert(sub->num_topics < sizeof(exists));
+
+       switch (lwsi_state(wsi)) {
+       case LRS_ESTABLISHED: /* Protocol connection established */
+               if (lws_mqtt_fill_fixed_header(p++, LMQCP_CTOS_SUBSCRIBE,
+                                              0, 0, 0)) {
+                       lwsl_err("%s: Failed to fill fixed header\n", __func__);
+                       return 1;
+               }
+
+               /*
+                * The stream wants to subscribe to one or more topic, but
+                * the shared nwsi may already be subscribed to some or all of
+                * them from interactions with other streams.  For those cases,
+                * we filter them from the list the child wants until we just
+                * have ones that are new to the nwsi.  If nothing left, we just
+                * synthesize the callback to the child as if SUBACK had come
+                * and we're done, otherwise just ask the server for topics that
+                * are new to the wsi.
+                */
+
+               extant = 0;
+               memset(&exists, 0, sizeof(exists));
+               for (n = 0; n < sub->num_topics; n++) {
+                       lwsl_info("%s: Subscribing to topic[%d] = \"%s\"\n",
+                                 __func__, (int)n, sub->topic[n].name);
+
+                       mysub = lws_mqtt_find_sub(nwsi->mqtt, sub->topic[n].name);
+                       if (mysub && mysub->ref_count) {
+                               mysub->ref_count++; /* another stream using it */
+                               exists[n] = 1;
+                               extant++;
+                       }
+
+                       /*
+                        * Attach the topic we're subscribing to, to wsi->mqtt
+                        */
+                       if (!lws_mqtt_create_sub(wsi->mqtt, sub->topic[n].name)) {
+                               lwsl_err("%s: create sub fail\n", __func__);
+                               return 1;
+                       }
+               }
+
+               if (extant == sub->num_topics) {
+                       /*
+                        * It turns out there's nothing to do here, the nwsi has
+                        * already subscribed to all the topics this stream
+                        * wanted.  Just tell it it can have them.
+                        */
+                       lwsl_notice("%s: all topics already subscribed\n", __func__);
+                       if (user_callback_handle_rxflow(
+                                   wsi->a.protocol->callback,
+                                   wsi, LWS_CALLBACK_MQTT_SUBSCRIBED,
+                                   wsi->user_space, NULL, 0) < 0) {
+                               lwsl_err("%s: MQTT_SUBSCRIBE failed\n",
+                                        __func__);
+                               return -1;
+                       }
+
+                       return 0;
+               }
+
+#if defined(_DEBUG)
+               /*
+                * zero or more of the topics already existed, but not all,
+                * so we must go to the server with a filtered list of the
+                * new ones only
+                */
+
+               tops = sub->num_topics - extant;
+#endif
+
+               /*
+                * Pid + (Topic len field + Topic len + Req. QoS) x Num of Topics
+                */
+               rem_len = 2;
+               for (n = 0; n < sub->num_topics; n++)
+                       if (!exists[n])
+                               rem_len += (2 + (uint32_t)strlen(sub->topic[n].name) + (uint32_t)1);
+
+               wsi->mqtt->sub_size = (uint16_t)rem_len;
+
+#if defined(_DEBUG)
+               lwsl_debug("%s: Number of topics = %d, Remaining len = %d\n",
+                          __func__, (int)tops, (int)rem_len);
+#endif
+
+               p += lws_mqtt_vbi_encode(rem_len, p);
+
+               if ((rem_len + lws_ptr_diff_size_t(p, start)) >=
+                                              wsi->a.context->pt_serv_buf_size) {
+                       lwsl_err("%s: Payload is too big\n", __func__);
+                       return 1;
+               }
+
+               /* Init lws_mqtt_str */
+               lws_mqtt_str_init(&mqtt_vh_payload, (uint8_t *)p, (uint16_t)rem_len, 0);
+               p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+
+               /* Packet ID */
+               wsi->mqtt->ack_pkt_id = sub->packet_id = ++nwsi->mqtt->pkt_id;
+               lwsl_debug("%s: pkt_id = %d\n", __func__,
+                          (int)sub->packet_id);
+               lws_ser_wu16be(p, wsi->mqtt->ack_pkt_id);
+
+               if (lws_mqtt_str_advance(&mqtt_vh_payload, 2))
+                       return 1;
+
+               p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+
+               for (n = 0; n < sub->num_topics; n++) {
+                       lwsl_info("%s: topics[%d] = %s\n", __func__,
+                                  (int)n, sub->topic[n].name);
+
+                       /* if the nwsi already has it, don't ask server for it */
+                       if (exists[n]) {
+                               lwsl_info("%s: topics[%d] \"%s\" exists in nwsi\n",
+                                           __func__, (int)n, sub->topic[n].name);
+                               continue;
+                       }
+
+                       /*
+                        * Attach the topic we're subscribing to, to nwsi->mqtt
+                        * so we know the nwsi itself has a subscription to it
+                        */
+
+                       if (!lws_mqtt_create_sub(nwsi->mqtt, sub->topic[n].name))
+                               return 1;
+
+                       /* Topic's Len */
+                       lws_ser_wu16be(p, (uint16_t)strlen(sub->topic[n].name));
+                       if (lws_mqtt_str_advance(&mqtt_vh_payload, 2))
+                               return 1;
+                       p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+
+                       /* Topic Name */
+                       lws_strncpy((char *)p, sub->topic[n].name,
+                                   strlen(sub->topic[n].name) + 1);
+                       if (lws_mqtt_str_advance(&mqtt_vh_payload,
+                                                (int)strlen(sub->topic[n].name)))
+                               return 1;
+                       p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+
+                       /* QoS */
+                       *p = (uint8_t)sub->topic[n].qos;
+                       if (lws_mqtt_str_advance(&mqtt_vh_payload, 1))
+                               return 1;
+                       p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+               }
+               break;
+
+       default:
+               return 1;
+       }
+
+       if (wsi->mqtt->inside_resume_session)
+               return 0;
+
+       if (lws_write(nwsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_BINARY) !=
+                                       lws_ptr_diff(p, start))
+               return 1;
+
+       wsi->mqtt->inside_subscribe = 1;
+
+       return 0;
+}
+
+int
+lws_mqtt_client_send_unsubcribe(struct lws *wsi,
+                               const lws_mqtt_subscribe_param_t *unsub)
+{
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       uint8_t *b = (uint8_t *)pt->serv_buf + LWS_PRE, *start = b, *p = start;
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+       lws_mqtt_str_t mqtt_vh_payload;
+       uint8_t send_unsub[8], orphaned;
+       uint32_t rem_len, n;
+       lws_mqtt_subs_t *mysub;
+#if defined(_DEBUG)
+       uint32_t tops;
+#endif
+
+       lwsl_info("%s: Enter\n", __func__);
+
+       switch (lwsi_state(wsi)) {
+       case LRS_ESTABLISHED: /* Protocol connection established */
+               orphaned = 0;
+               memset(&send_unsub, 0, sizeof(send_unsub));
+               for (n = 0; n < unsub->num_topics; n++) {
+                       mysub = lws_mqtt_find_sub(nwsi->mqtt,
+                                                 unsub->topic[n].name);
+                       assert(mysub);
+
+                       if (mysub && --mysub->ref_count == 0) {
+                               lwsl_notice("%s: Need to send UNSUB\n", __func__);
+                               send_unsub[n] = 1;
+                               orphaned++;
+                       }
+               }
+
+               if (!orphaned) {
+                       /*
+                        * The nwsi still has other subscribers bound to the
+                        * topics.
+                        *
+                        * So, don't send UNSUB to server, and just fake the
+                        * UNSUB ACK event for the guy going away.
+                        */
+                       lwsl_notice("%s: unsubscribed!\n", __func__);
+                       if (user_callback_handle_rxflow(
+                                   wsi->a.protocol->callback,
+                                   wsi, LWS_CALLBACK_MQTT_UNSUBSCRIBED,
+                                   wsi->user_space, NULL, 0) < 0) {
+                               /*
+                                * We can't directly close here, because the
+                                * caller still has the wsi.  Inform the
+                                * caller that we want to close
+                                */
+
+                               return 1;
+                       }
+
+                       return 0;
+               }
+#if defined(_DEBUG)
+               /*
+                * one or more of the topics needs to be unsubscribed
+                * from, so we must go to the server with a filtered
+                * list of the new ones only
+                */
+
+               tops = orphaned;
+#endif
+
+               if (lws_mqtt_fill_fixed_header(p++, LMQCP_CTOS_UNSUBSCRIBE,
+                                              0, 0, 0)) {
+                       lwsl_err("%s: Failed to fill fixed header\n", __func__);
+                       return 1;
+               }
+
+               /*
+                * Pid + (Topic len field + Topic len) x Num of Topics
+                */
+               rem_len = 2;
+               for (n = 0; n < unsub->num_topics; n++)
+                       if (send_unsub[n])
+                               rem_len += (2 + (uint32_t)strlen(unsub->topic[n].name));
+
+               wsi->mqtt->sub_size = (uint16_t)rem_len;
+
+#if defined(_DEBUG)
+               lwsl_debug("%s: Number of topics = %d, Remaining len = %d\n",
+                          __func__, (int)tops, (int)rem_len);
+#endif
+
+               p += lws_mqtt_vbi_encode(rem_len, p);
+
+               if ((rem_len + lws_ptr_diff_size_t(p, start)) >=
+                                              wsi->a.context->pt_serv_buf_size) {
+                       lwsl_err("%s: Payload is too big\n", __func__);
+                       return 1;
+               }
+
+               /* Init lws_mqtt_str */
+               lws_mqtt_str_init(&mqtt_vh_payload, (uint8_t *)p, (uint16_t)rem_len, 0);
+               p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+
+               /* Packet ID */
+               wsi->mqtt->ack_pkt_id = ++nwsi->mqtt->pkt_id;
+               lwsl_debug("%s: pkt_id = %d\n", __func__,
+                          (int)wsi->mqtt->ack_pkt_id);
+               lws_ser_wu16be(p, wsi->mqtt->ack_pkt_id);
+
+               if (lws_mqtt_str_advance(&mqtt_vh_payload, 2))
+                       return 1;
+
+               p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+
+               for (n = 0; n < unsub->num_topics; n++) {
+                       lwsl_info("%s: topics[%d] = %s\n", __func__,
+                                  (int)n, unsub->topic[n].name);
+
+                       /*
+                        * Subscriber still bound to it, don't UBSUB
+                        * from the server
+                        */
+                       if (!send_unsub[n])
+                               continue;
+
+                       /* Topic's Len */
+                       lws_ser_wu16be(p, (uint16_t)strlen(unsub->topic[n].name));
+                       if (lws_mqtt_str_advance(&mqtt_vh_payload, 2))
+                               return 1;
+                       p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+
+                       /* Topic Name */
+                       lws_strncpy((char *)p, unsub->topic[n].name,
+                                   strlen(unsub->topic[n].name) + 1);
+                       if (lws_mqtt_str_advance(&mqtt_vh_payload,
+                                                (int)strlen(unsub->topic[n].name)))
+                               return 1;
+                       p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
+               }
+               break;
+
+       default:
+               return 1;
+       }
+
+       if (lws_write(nwsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_BINARY) !=
+                                       lws_ptr_diff(p, start))
+               return 1;
+
+       wsi->mqtt->inside_unsubscribe = 1;
+
+       wsi->mqtt->sul_unsuback_wait.cb = lws_mqtt_unsuback_timeout;
+       __lws_sul_insert_us(&pt->pt_sul_owner[wsi->conn_validity_wakesuspend],
+                           &wsi->mqtt->sul_unsuback_wait,
+                           3 * LWS_USEC_PER_SEC);
+
+       return 0;
+}
+
+/*
+ * This is called when child streams bind to an already-existing and compatible
+ * MQTT stream
+ */
+
+struct lws *
+lws_wsi_mqtt_adopt(struct lws *parent_wsi, struct lws *wsi)
+{
+       /* no more children allowed by parent? */
+
+       if (parent_wsi->mux.child_count + 1 > LWS_MQTT_MAX_CHILDREN) {
+               lwsl_err("%s: reached concurrent stream limit\n", __func__);
+               return NULL;
+       }
+
+#if defined(LWS_WITH_CLIENT)
+       wsi->client_mux_substream = 1;
+#endif
+
+       lws_wsi_mux_insert(wsi, parent_wsi, wsi->mux.my_sid);
+
+       if (lws_ensure_user_space(wsi))
+               goto bail1;
+
+       lws_mqtt_set_client_established(wsi);
+       lws_callback_on_writable(wsi);
+
+       return wsi;
+
+bail1:
+       /* undo the insert */
+       parent_wsi->mux.child_list = wsi->mux.sibling_list;
+       parent_wsi->mux.child_count--;
+
+       if (wsi->user_space)
+               lws_free_set_NULL(wsi->user_space);
+
+       wsi->a.protocol->callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
+       lws_free(wsi);
+
+       return NULL;
+}
+
diff --git a/lib/roles/mqtt/ops-mqtt.c b/lib/roles/mqtt/ops-mqtt.c
new file mode 100644 (file)
index 0000000..ceac2f5
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+static int
+rops_handle_POLLIN_mqtt(struct lws_context_per_thread *pt, struct lws *wsi,
+                          struct lws_pollfd *pollfd)
+{
+       unsigned int pending = 0;
+       struct lws_tokens ebuf;
+       int n = 0;
+       char buffered = 0;
+
+       lwsl_debug("%s: wsistate 0x%x, %s pollout %d\n", __func__,
+                  (unsigned int)wsi->wsistate,  wsi->a.protocol->name,
+                  pollfd->revents);
+
+       /*
+        * After the CONNACK and nwsi establishment, the first logical
+        * stream is migrated out of the nwsi to be child sid 1, and the
+        * nwsi no longer has a wsi->mqtt of its own.
+        *
+        * RX events on the nwsi must be converted to events seen or not
+        * seen by one or more child streams.
+        *
+        * SUBACK - reflected to child stream that asked for it
+        * PUBACK - routed to child that did the related publish
+        */
+
+       ebuf.token = NULL;
+       ebuf.len = 0;
+
+       if (lwsi_state(wsi) != LRS_ESTABLISHED) {
+#if defined(LWS_WITH_CLIENT)
+
+               if (lwsi_state(wsi) == LRS_WAITING_SSL &&
+                   ((pollfd->revents & LWS_POLLOUT)) &&
+                   lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
+                       lwsl_info("failed at set pollfd\n");
+                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
+               }
+
+               if ((pollfd->revents & LWS_POLLOUT) &&
+                   lws_handle_POLLOUT_event(wsi, pollfd)) {
+                       lwsl_debug("POLLOUT event closed it\n");
+                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
+               }
+
+               n = lws_mqtt_client_socket_service(wsi, pollfd, NULL);
+               if (n)
+                       return LWS_HPI_RET_WSI_ALREADY_DIED;
+#endif
+               return LWS_HPI_RET_HANDLED;
+       }
+
+       /* 1: something requested a callback when it was OK to write */
+
+       if ((pollfd->revents & LWS_POLLOUT) &&
+           lwsi_state_can_handle_POLLOUT(wsi) &&
+           lws_handle_POLLOUT_event(wsi, pollfd)) {
+               if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
+                       lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE);
+
+               return LWS_HPI_RET_PLEASE_CLOSE_ME;
+       }
+
+       /* 3: buflist needs to be drained
+        */
+read:
+       // lws_buflist_describe(&wsi->buflist, wsi, __func__);
+       ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist, &ebuf.token);
+       if (ebuf.len) {
+               lwsl_info("draining buflist (len %d)\n", ebuf.len);
+               buffered = 1;
+               goto drain;
+       }
+
+       if (!(pollfd->revents & pollfd->events & LWS_POLLIN))
+               return LWS_HPI_RET_HANDLED;
+
+       /* if (lws_is_flowcontrolled(wsi)) { */
+       /*      lwsl_info("%s: %p should be rxflow (bm 0x%x)..\n", */
+       /*                  __func__, wsi, wsi->rxflow_bitmap); */
+       /*      return LWS_HPI_RET_HANDLED; */
+       /* } */
+
+       if (!(lwsi_role_client(wsi) && lwsi_state(wsi) != LRS_ESTABLISHED)) {
+               /*
+                * In case we are going to react to this rx by scheduling
+                * writes, we need to restrict the amount of rx to the size
+                * the protocol reported for rx buffer.
+                *
+                * Otherwise we get a situation we have to absorb possibly a
+                * lot of reads before we get a chance to drain them by writing
+                * them, eg, with echo type tests in autobahn.
+                */
+
+               buffered = 0;
+               ebuf.token = pt->serv_buf;
+               ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
+
+               if ((unsigned int)ebuf.len > wsi->a.context->pt_serv_buf_size)
+                       ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
+
+               if ((int)pending > ebuf.len)
+                       pending = (unsigned int)ebuf.len;
+
+               ebuf.len = lws_ssl_capable_read(wsi, ebuf.token,
+                                               pending ? pending :
+                                               (unsigned int)ebuf.len);
+               switch (ebuf.len) {
+               case 0:
+                       lwsl_info("%s: zero length read\n",
+                                 __func__);
+                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
+               case LWS_SSL_CAPABLE_MORE_SERVICE:
+                       lwsl_info("SSL Capable more service\n");
+                       return LWS_HPI_RET_HANDLED;
+               case LWS_SSL_CAPABLE_ERROR:
+                       lwsl_info("%s: LWS_SSL_CAPABLE_ERROR\n",
+                                       __func__);
+                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
+               }
+
+               /*
+                * coverity thinks ssl_capable_read() may read over
+                * 2GB.  Dissuade it...
+                */
+               ebuf.len &= 0x7fffffff;
+       }
+
+drain:
+       /* service incoming data */
+       //lws_buflist_describe(&wsi->buflist, wsi, __func__);
+       if (ebuf.len) {
+               n = lws_read_mqtt(wsi, ebuf.token, (unsigned int)ebuf.len);
+               if (n < 0) {
+                       lwsl_notice("%s: lws_read_mqtt returned %d\n",
+                                       __func__, n);
+                       /* we closed wsi */
+                       goto fail;
+                }
+               // lws_buflist_describe(&wsi->buflist, wsi, __func__);
+               lwsl_debug("%s: consuming %d / %d\n", __func__, n, ebuf.len);
+               if (lws_buflist_aware_finished_consuming(wsi, &ebuf, ebuf.len,
+                                                        buffered, __func__))
+                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
+       }
+
+       ebuf.token = NULL;
+       ebuf.len = 0;
+
+       pending = (unsigned int)lws_ssl_pending(wsi);
+       if (pending) {
+               pending = pending > wsi->a.context->pt_serv_buf_size ?
+                       wsi->a.context->pt_serv_buf_size : pending;
+               goto read;
+       }
+
+       if (buffered && /* were draining, now nothing left */
+           !lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
+               lwsl_info("%s: %s flow buf: drained\n", __func__, lws_wsi_tag(wsi));
+               /* having drained the rxflow buffer, can rearm POLLIN */
+#if !defined(LWS_WITH_SERVER)
+               n =
+#endif
+               __lws_rx_flow_control(wsi);
+               /* n ignored, needed for NO_SERVER case */
+       }
+
+       /* n = 0 */
+       return LWS_HPI_RET_HANDLED;
+
+fail:
+       lwsl_err("%s: Failed, bailing\n", __func__);
+       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "mqtt svc fail");
+
+       return LWS_HPI_RET_WSI_ALREADY_DIED;
+}
+
+#if 0 /* defined(LWS_WITH_SERVER) */
+
+static int
+rops_adoption_bind_mqtt(struct lws *wsi, int type, const char *vh_prot_name)
+{
+       /* no http but socket... must be mqtt */
+       if ((type & LWS_ADOPT_HTTP) || !(type & LWS_ADOPT_SOCKET) ||
+           (type & _LWS_ADOPT_FINISH))
+               return 0; /* no match */
+
+       lws_role_transition(wsi, 0, (type & LWS_ADOPT_ALLOW_SSL) ? LRS_SSL_INIT :
+                               LRS_ESTABLISHED, &role_ops_mqtt);
+
+       if (vh_prot_name)
+               lws_bind_protocol(wsi, wsi->a.protocol, __func__);
+       else
+               /* this is the only time he will transition */
+               lws_bind_protocol(wsi,
+                       &wsi->a.vhost->protocols[wsi->a.vhost->mqtt_protocol_index],
+                       __func__);
+
+       return 1; /* bound */
+}
+#endif
+
+static int
+rops_client_bind_mqtt(struct lws *wsi, const struct lws_client_connect_info *i)
+{
+       lwsl_debug("%s: i = %p\n", __func__, i);
+       if (!i) {
+
+               /* finalize */
+
+               if (!wsi->user_space && wsi->stash->cis[CIS_METHOD])
+                       if (lws_ensure_user_space(wsi))
+                               return 1;
+
+               if (!wsi->stash->cis[CIS_METHOD] && !wsi->stash->cis[CIS_ALPN])
+                       wsi->stash->cis[CIS_ALPN] = "x-amzn-mqtt-ca";
+
+               /* if we went on the ah waiting list, it's ok, we can
+                * wait.
+                *
+                * When we do get the ah, now or later, he will end up
+                * at lws_http_client_connect_via_info2().
+                */
+#if defined(LWS_WITH_CLIENT)
+               if (lws_header_table_attach(wsi, 0) < 0)
+                       /*
+                        * if we failed here, the connection is already closed
+                        * and freed.
+                        */
+                       return -1;
+#else
+               if (lws_header_table_attach(wsi, 0))
+                       return 0;
+#endif
+               return 0;
+       }
+
+       /* if a recognized mqtt method, bind to it */
+       if (strcmp(i->method, "MQTT"))
+               return 0; /* no match */
+
+       if (lws_create_client_mqtt_object(i, wsi))
+               return 1;
+
+       lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
+                               &role_ops_mqtt);
+       return 1; /* matched */
+}
+
+static int
+rops_handle_POLLOUT_mqtt(struct lws *wsi)
+{
+       struct lws **wsi2;
+
+       lwsl_debug("%s\n", __func__);
+
+#if defined(LWS_WITH_CLIENT)
+       if (wsi->mqtt && wsi->mqtt->send_pingreq && !wsi->mqtt->inside_payload) {
+               uint8_t buf[LWS_PRE + 2];
+
+               /*
+                * We are swallowing this POLLOUT in order to send a PINGREQ
+                * autonomously
+                */
+
+               wsi->mqtt->send_pingreq = 0;
+
+               lwsl_notice("%s: issuing PINGREQ\n", __func__);
+
+               buf[LWS_PRE] = LMQCP_CTOS_PINGREQ << 4;
+               buf[LWS_PRE + 1] = 0;
+
+               if (lws_write(wsi, (uint8_t *)&buf[LWS_PRE], 2,
+                             LWS_WRITE_BINARY) != 2)
+                       return LWS_HP_RET_BAIL_DIE;
+
+               return LWS_HP_RET_BAIL_OK;
+       }
+#endif
+       if (wsi->mqtt && !wsi->mqtt->inside_payload &&
+           (wsi->mqtt->send_pubrec || wsi->mqtt->send_pubrel ||
+            wsi->mqtt->send_pubcomp)) {
+               uint8_t buf[LWS_PRE + 4];
+               /* Remaining len = 2 */
+               buf[LWS_PRE + 1] = 2;
+               if (wsi->mqtt->send_pubrec) {
+                       lwsl_notice("%s: issuing PUBREC for pkt id: %d\n",
+                                   __func__, wsi->mqtt->peer_ack_pkt_id);
+                       buf[LWS_PRE] = LMQCP_PUBREC << 4 | 0x2;
+                       /* Packet ID */
+                       lws_ser_wu16be(&buf[LWS_PRE + 2],
+                                      wsi->mqtt->peer_ack_pkt_id);
+                       wsi->mqtt->send_pubrec = 0;
+               } else if (wsi->mqtt->send_pubrel) {
+                       lwsl_notice("%s: issuing PUBREL for pkt id: %d\n",
+                                   __func__, wsi->mqtt->ack_pkt_id);
+                       buf[LWS_PRE] = LMQCP_PUBREL << 4 | 0x2;
+                       lws_ser_wu16be(&buf[LWS_PRE + 2],
+                                      wsi->mqtt->ack_pkt_id);
+                       wsi->mqtt->send_pubrel = 0;
+               } else {
+                       lwsl_notice("%s: issuing PUBCOMP for pkt id: %d\n",
+                                   __func__, wsi->mqtt->peer_ack_pkt_id);
+                       buf[LWS_PRE] = LMQCP_PUBCOMP << 4 | 0x2;
+                       lws_ser_wu16be(&buf[LWS_PRE + 2],
+                                      wsi->mqtt->peer_ack_pkt_id);
+                       wsi->mqtt->send_pubcomp = 0;
+               }
+               if (lws_write(wsi, (uint8_t *)&buf[LWS_PRE], 4,
+                             LWS_WRITE_BINARY) != 4)
+                       return LWS_HP_RET_BAIL_DIE;
+               return LWS_HP_RET_BAIL_OK;
+       }
+
+       wsi = lws_get_network_wsi(wsi);
+
+       wsi->mux.requested_POLLOUT = 0;
+
+       wsi2 = &wsi->mux.child_list;
+       if (!*wsi2) {
+               lwsl_debug("%s: no children\n", __func__);
+               return LWS_HP_RET_DROP_POLLOUT;
+       }
+
+       if (!wsi->mqtt)
+               return LWS_HP_RET_BAIL_DIE;
+
+       lws_wsi_mux_dump_waiting_children(wsi);
+
+       do {
+               struct lws *w, **wa;
+
+               wa = &(*wsi2)->mux.sibling_list;
+               if (!(*wsi2)->mux.requested_POLLOUT)
+                       goto next_child;
+
+               if (!lwsi_state_can_handle_POLLOUT(wsi))
+                       goto next_child;
+
+               /*
+                * If the nwsi is in the middle of a frame, we can only
+                * continue to send that
+                */
+
+               if (wsi->mqtt->inside_payload && !(*wsi2)->mqtt->inside_payload)
+                       goto next_child;
+
+               /*
+                * we're going to do writable callback for this child.
+                * move him to be the last child
+                */
+               w = lws_wsi_mux_move_child_to_tail(wsi2);
+               if (!w) {
+                       wa = &wsi->mux.child_list;
+                       goto next_child;
+               }
+
+               lwsl_debug("%s: child %s (wsistate 0x%x)\n", __func__,
+                          lws_wsi_tag(w), (unsigned int)w->wsistate);
+
+               if (lwsi_state(wsi) == LRS_ESTABLISHED &&
+                   !wsi->mqtt->inside_payload &&
+                   wsi->mqtt->send_puback) {
+                       uint8_t buf[LWS_PRE + 4];
+                       lwsl_notice("%s: issuing PUBACK for pkt id: %d\n",
+                                   __func__, wsi->mqtt->ack_pkt_id);
+
+                       /* Fixed header */
+                       buf[LWS_PRE] = LMQCP_PUBACK << 4;
+                       /* Remaining len = 2 */
+                       buf[LWS_PRE + 1] = 2;
+                       /* Packet ID */
+                       lws_ser_wu16be(&buf[LWS_PRE + 2], wsi->mqtt->peer_ack_pkt_id);
+
+                       if (lws_write(wsi, (uint8_t *)&buf[LWS_PRE], 4,
+                                     LWS_WRITE_BINARY) != 4)
+                               return LWS_HP_RET_BAIL_DIE;
+
+                       wsi->mqtt->send_puback = 0;
+                       w->mux.requested_POLLOUT = 1;
+
+                       wa = &wsi->mux.child_list;
+                       goto next_child;
+               }
+
+               if (lws_callback_as_writeable(w)) {
+                       lwsl_notice("%s: Closing child %s\n", __func__, lws_wsi_tag(w));
+                       lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
+                                          "mqtt pollout handle");
+                       wa = &wsi->mux.child_list;
+               }
+
+next_child:
+               wsi2 = wa;
+       } while (wsi2 && *wsi2 && !lws_send_pipe_choked(wsi));
+
+       // lws_wsi_mux_dump_waiting_children(wsi);
+
+       if (lws_wsi_mux_action_pending_writeable_reqs(wsi))
+               return LWS_HP_RET_BAIL_DIE;
+
+       return LWS_HP_RET_BAIL_OK;
+}
+
+#if defined(LWS_WITH_CLIENT)
+static int
+rops_issue_keepalive_mqtt(struct lws *wsi, int isvalid)
+{
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+
+       if (isvalid) {
+               _lws_validity_confirmed_role(nwsi);
+
+               return 0;
+       }
+
+       nwsi->mqtt->send_pingreq = 1;
+       lws_callback_on_writable(nwsi);
+
+       return 0;
+}
+#endif
+
+static int
+rops_close_role_mqtt(struct lws_context_per_thread *pt, struct lws *wsi)
+{
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+       lws_mqtt_subs_t *s, *s1, *mysub;
+       lws_mqttc_t *c;
+
+       if (!wsi->mqtt)
+               return 0;
+
+       c = &wsi->mqtt->client;
+
+       lws_sul_cancel(&wsi->mqtt->sul_qos_puback_pubrec_wait);
+
+       lws_mqtt_str_free(&c->username);
+       lws_mqtt_str_free(&c->password);
+       lws_mqtt_str_free(&c->will.message);
+       lws_mqtt_str_free(&c->will.topic);
+       lws_mqtt_str_free(&c->id);
+
+       /* clean up any subscription allocations */
+
+       s = wsi->mqtt->subs_head;
+       wsi->mqtt->subs_head = NULL;
+       while (s) {
+               s1 = s->next;
+               /*
+                * Account for children no longer using nwsi subscription
+                */
+               mysub = lws_mqtt_find_sub(nwsi->mqtt, (const char *)&s[1]);
+//             assert(mysub); /* if child subscribed, nwsi must feel the same */
+               if (mysub) {
+                       assert(mysub->ref_count);
+                       mysub->ref_count--;
+               }
+               lws_free(s);
+               s = s1;
+       }
+
+       lws_mqtt_publish_param_t *pub =
+                       (lws_mqtt_publish_param_t *)
+                               wsi->mqtt->rx_cpkt_param;
+
+       if (pub)
+               lws_free_set_NULL(pub->topic);
+
+       lws_free_set_NULL(wsi->mqtt->rx_cpkt_param);
+
+       lws_free_set_NULL(wsi->mqtt);
+
+       return 0;
+}
+
+static int
+rops_callback_on_writable_mqtt(struct lws *wsi)
+{
+#if defined(LWS_WITH_CLIENT)
+       struct lws *network_wsi;
+#endif
+       int already;
+
+       lwsl_debug("%s: %s (wsistate 0x%x)\n", __func__, lws_wsi_tag(wsi),
+                       (unsigned int)wsi->wsistate);
+
+       if (wsi->mux.requested_POLLOUT
+#if defined(LWS_WITH_CLIENT)
+                       && !wsi->client_h2_alpn
+#endif
+       ) {
+               lwsl_debug("already pending writable\n");
+               return 1;
+       }
+#if 0
+       /* is this for DATA or for control messages? */
+       if (wsi->upgraded_to_http2 && !wsi->h2.h2n->pps &&
+           !lws_h2_tx_cr_get(wsi)) {
+               /*
+                * other side is not able to cope with us sending DATA
+                * anything so no matter if we have POLLOUT on our side if it's
+                * DATA we want to send.
+                *
+                * Delay waiting for our POLLOUT until peer indicates he has
+                * space for more using tx window command in http2 layer
+                */
+               lwsl_notice("%s: %p: skint (%d)\n", __func__, wsi,
+                           wsi->h2.tx_cr);
+               wsi->h2.skint = 1;
+               return 0;
+       }
+
+       wsi->h2.skint = 0;
+#endif
+#if defined(LWS_WITH_CLIENT)
+       network_wsi = lws_get_network_wsi(wsi);
+#endif
+       already = lws_wsi_mux_mark_parents_needing_writeable(wsi);
+
+       /* for network action, act only on the network wsi */
+
+       if (already
+#if defined(LWS_WITH_CLIENT)
+                       && !network_wsi->client_mux_substream
+#endif
+                       )
+               return 1;
+
+       return 0;
+}
+
+static int
+rops_close_kill_connection_mqtt(struct lws *wsi, enum lws_close_status reason)
+{
+       lwsl_info(" %s, his parent %s: child list %p, siblings:\n",
+                       lws_wsi_tag(wsi),
+                       lws_wsi_tag(wsi->mux.parent_wsi), wsi->mux.child_list);
+       //lws_wsi_mux_dump_children(wsi);
+
+       if (wsi->mux_substream
+#if defined(LWS_WITH_CLIENT)
+                       || wsi->client_mux_substream
+#endif
+       ) {
+               lwsl_info("closing %s: parent %s: first child %p\n",
+                               lws_wsi_tag(wsi),
+                               lws_wsi_tag(wsi->mux.parent_wsi),
+                               wsi->mux.child_list);
+
+               if (wsi->mux.child_list && lwsl_visible(LLL_INFO)) {
+                       lwsl_info(" parent %s: closing children: list:\n", lws_wsi_tag(wsi));
+                       lws_wsi_mux_dump_children(wsi);
+               }
+
+               lws_wsi_mux_close_children(wsi, (int)reason);
+       }
+
+       if ((
+#if defined(LWS_WITH_CLIENT)
+                       wsi->client_mux_substream ||
+#endif
+                       wsi->mux_substream) &&
+            wsi->mux.parent_wsi) {
+               lws_wsi_mux_sibling_disconnect(wsi);
+       }
+
+       return 0;
+}
+
+static const lws_rops_t rops_table_mqtt[] = {
+       /*  1 */ { .handle_POLLIN         = rops_handle_POLLIN_mqtt },
+       /*  2 */ { .handle_POLLOUT        = rops_handle_POLLOUT_mqtt },
+       /*  3 */ { .callback_on_writable  = rops_callback_on_writable_mqtt },
+       /*  4 */ { .close_role            = rops_close_role_mqtt },
+       /*  5 */ { .close_kill_connection = rops_close_kill_connection_mqtt },
+#if defined(LWS_WITH_CLIENT)
+       /*  6 */ { .client_bind           = rops_client_bind_mqtt },
+       /*  7 */ { .issue_keepalive       = rops_issue_keepalive_mqtt },
+#endif
+};
+
+struct lws_role_ops role_ops_mqtt = {
+       /* role name */                 "mqtt",
+       /* alpn id */                   "x-amzn-mqtt-ca", /* "mqtt/3.1.1" */
+
+       /* rops_table */                rops_table_mqtt,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x00,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x01,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x20,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x30,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x00,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x00,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x45,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0x00,
+
+         /* LWS_ROPS_client_bind */
+#if defined(LWS_WITH_CLIENT)
+         /* LWS_ROPS_issue_keepalive */                0x67,
+#else
+         /* LWS_ROPS_issue_keepalive */                0x00,
+#endif
+                                       },
+
+       .adoption_cb =                  { LWS_CALLBACK_MQTT_NEW_CLIENT_INSTANTIATED,
+                                         LWS_CALLBACK_MQTT_NEW_CLIENT_INSTANTIATED },
+       .rx_cb =                        { LWS_CALLBACK_MQTT_CLIENT_RX,
+                                         LWS_CALLBACK_MQTT_CLIENT_RX },
+       .writeable_cb =                 { LWS_CALLBACK_MQTT_CLIENT_WRITEABLE,
+                                         LWS_CALLBACK_MQTT_CLIENT_WRITEABLE },
+       .close_cb =                     { LWS_CALLBACK_MQTT_CLIENT_CLOSED,
+                                         LWS_CALLBACK_MQTT_CLIENT_CLOSED },
+       .protocol_bind_cb =             { LWS_CALLBACK_MQTT_IDLE,
+                                         LWS_CALLBACK_MQTT_IDLE },
+       .protocol_unbind_cb =           { LWS_CALLBACK_MQTT_DROP_PROTOCOL,
+                                         LWS_CALLBACK_MQTT_DROP_PROTOCOL },
+       .file_handle =                  0,
+};
diff --git a/lib/roles/mqtt/primitives.c b/lib/roles/mqtt/primitives.c
new file mode 100644 (file)
index 0000000..7842187
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * MQTT v5
+ *
+ * http://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html
+ */
+
+#include "private-lib-core.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+
+
+/*
+ * Encode is done into a buffer of at least 4 bytes space.
+ *
+ * Returns -1 for error, or number of bytes used
+ */
+
+int
+lws_mqtt_vbi_encode(uint32_t value, void *buf)
+{
+       uint8_t *p = (uint8_t *)buf, b;
+
+       if (value > 0xfffffff) {
+               assert(0);
+               return -1;
+       }
+
+       do {
+               b = value & 0x7f;
+               value >>= 7;
+               if (value)
+                       *p++ = (0x80 | b);
+               else
+                       *p++ = b;
+       } while (value);
+
+       return lws_ptr_diff(p, (uint8_t *)buf);
+}
+
+void
+lws_mqtt_vbi_init(lws_mqtt_vbi *vbi)
+{
+       vbi->value = 0;
+       vbi->consumed = 0;
+       vbi->budget = 4;
+}
+
+void
+lws_mqtt_2byte_init(lws_mqtt_vbi *vbi)
+{
+       vbi->value = 0;
+       vbi->consumed = 0;
+       vbi->budget = 2;
+}
+
+void
+lws_mqtt_4byte_init(lws_mqtt_vbi *vbi)
+{
+       vbi->value = 0;
+       vbi->consumed = 0;
+       vbi->budget = 4;
+}
+
+lws_mqtt_stateful_primitive_return_t
+lws_mqtt_vbi_r(lws_mqtt_vbi *vbi, const uint8_t **in, size_t *len)
+{
+       uint8_t multiplier = 0;
+       if (!vbi->budget) {
+               lwsl_info("%s: bad vbi\n", __func__);
+
+               return LMSPR_FAILED_ALREADY_COMPLETED;
+       }
+
+       while (*len && vbi->budget--) {
+               uint8_t u = *((*in)++);
+
+               (*len)--;
+               vbi->consumed++;
+               vbi->value = vbi->value + (uint32_t)((u & 0x7f) << multiplier);
+               multiplier = (uint8_t)(multiplier + 7);
+               if (!(u & 0x80))
+                       return LMSPR_COMPLETED; /* finished */
+       }
+
+       if (!vbi->budget) { /* should have ended on b7 = 0 and exited then... */
+               lwsl_info("%s: bad vbi\n", __func__);
+
+               return LMSPR_FAILED_FORMAT;
+       }
+
+       return LMSPR_NEED_MORE;
+}
+
+lws_mqtt_stateful_primitive_return_t
+lws_mqtt_mb_parse(lws_mqtt_vbi *vbi, const uint8_t **in, size_t *len)
+{
+       if (!vbi->budget)
+               return LMSPR_FAILED_ALREADY_COMPLETED;
+
+       while (*len && vbi->budget--) {
+               vbi->value = (vbi->value << 8) | *((*in)++);
+               (*len)--;
+               vbi->consumed++;
+       }
+
+       return vbi->budget ? LMSPR_NEED_MORE : LMSPR_COMPLETED;
+}
+
+/*
+ * You can leave buf NULL, if so it will be allocated on the heap once the
+ * actual length is known.  nf should be 0, it will be set at allocation time.
+ *
+ * Or you can ensure no allocation and use an external buffer by setting buf
+ * and lim.  But buf must be in the ep context somehow, since it may have to
+ * survive returns to the event loop unchanged.  Set nf to 0 in this case.
+ *
+ * Or you can set buf to an externally allocated buffer, in which case you may
+ * set nf so it will be freed when the string is "freed".
+ */
+
+void
+lws_mqtt_str_init(lws_mqtt_str_t *s, uint8_t *buf, uint16_t lim, char nf)
+{
+       s->len = 0;     /* at COMPLETED, consumed count is s->len + 2 */
+       s->pos = 0;
+       s->buf = buf;
+       s->limit = lim;
+       s->len_valid = 0;
+       s->needs_freeing = nf;
+}
+
+lws_mqtt_str_t *
+lws_mqtt_str_create(uint16_t lim)
+{
+       lws_mqtt_str_t *s = lws_malloc(sizeof(*s) + lim + 1, __func__);
+
+       if (!s)
+               return NULL;
+
+       s->len = 0;
+       s->pos = 0;
+       s->buf = (uint8_t *)&s[1];
+       s->limit = lim;
+       s->len_valid = 0;
+       s->needs_freeing = 1;
+
+       return s;
+}
+
+lws_mqtt_str_t *
+lws_mqtt_str_create_init(uint8_t *buf, uint16_t len, uint16_t lim)
+{
+       lws_mqtt_str_t *s;
+
+       if (!lim)
+               lim = len;
+
+       s = lws_mqtt_str_create(lim);
+
+       if (!s)
+               return NULL;
+
+       memcpy(s->buf, buf, len);
+       s->len = len;
+       s->len_valid = 1;
+       s->pos = len;
+
+       return s;
+}
+
+
+lws_mqtt_str_t *
+lws_mqtt_str_create_cstr_dup(const char *buf, uint16_t lim)
+{
+       size_t len = strlen(buf);
+
+       if (!lim)
+               lim = (uint16_t)len;
+
+       return lws_mqtt_str_create_init((uint8_t *)buf, (uint16_t)len, lim);
+}
+
+uint8_t *
+lws_mqtt_str_next(lws_mqtt_str_t *s, uint16_t *budget)
+{
+       if (budget)
+               *budget = (uint16_t)(s->limit - s->pos);
+
+       return &s->buf[s->pos];
+}
+
+int
+lws_mqtt_str_advance(lws_mqtt_str_t *s, int n)
+{
+       if (n > s->limit - s->pos) {
+               lwsl_err("%s: attempted overflow %d vs %d\n", __func__,
+                        n, s->limit - s->pos);
+               return 1;
+       }
+
+       s->pos = (uint16_t)(s->pos + (uint16_t)n);
+       s->len = (uint16_t)(s->len + (uint16_t)n);
+
+       return 0;
+}
+
+void
+lws_mqtt_str_free(lws_mqtt_str_t **ps)
+{
+       lws_mqtt_str_t *s = *ps;
+
+       if (!s || !s->needs_freeing)
+               return;
+
+       /* buf may be independently allocated or allocated along with the
+        * lws_mqtt_str_t at the end... if so the whole lws_mqtt_str_t is freed.
+        */
+
+       if (s->buf != (uint8_t *)&s[1])
+               lws_free_set_NULL(s->buf);
+       else
+               lws_free_set_NULL(*ps);
+}
+
+/*
+ * Parses and allocates for lws_mqtt_str_t in a fragmentation-immune, but
+ * efficient for bulk data way.
+ *
+ * Returns: LMSPR_NEED_MORE if needs more data,
+ *         LMSPR_COMPLETED if complete, <0 for error
+ *
+ * *len is reduced by, and *in is advanced by, the amount of data actually used,
+ * except in error case
+ *
+ * lws_mqtt_str_free() must be called after calling this successfully
+ * or not.
+ */
+lws_mqtt_stateful_primitive_return_t
+lws_mqtt_str_parse(lws_mqtt_str_t *s, const uint8_t **in, size_t *len)
+{
+       const uint8_t *oin = *in;
+
+       /* handle the length + allocation if needed */
+       while (*len && !s->len_valid && s->pos < 2) {
+               s->len = (uint16_t)((s->len << 8) | *((*in)++));
+               (*len)--;
+               oin = *in;
+               if (++s->pos == 2) {
+                       if (s->len > s->limit)
+                               return LMSPR_FAILED_OVERSIZE;
+
+                       s->pos = 0;
+                       s->len_valid = 1;
+
+                       if (!s->len) /* do not need to allocate */
+                               return LMSPR_COMPLETED;
+
+                       if (!s->buf) {
+                               s->buf = lws_malloc(s->len, __func__);
+                               if (!s->buf)
+                                       return LMSPR_FAILED_OOM;
+
+                               s->needs_freeing = 1;
+                       }
+               }
+       }
+
+       /* handle copying bulk data into allocation */
+       if (s->len_valid && *len) {
+               uint16_t span = (uint16_t)(s->len - s->pos);
+
+               if (span > *len)
+                       span = (uint16_t)*len;
+
+               memcpy(s->buf + s->pos, *in, span);
+               *in += span;
+               s->pos = (uint16_t)(s->pos + (uint16_t)span);
+       }
+
+       *len -= (unsigned long)(*in - oin);
+
+       return s->buf && s->pos == s->len ? LMSPR_COMPLETED : LMSPR_NEED_MORE;
+}
+
+int
+lws_mqtt_bindata_cmp(const lws_mqtt_str_t *bd1,
+                    const lws_mqtt_str_t *bd2)
+{
+       if (bd1->len != bd2->len)
+               return 1;
+
+       if (!!bd1->buf != !!bd2->buf)
+               return 1;
+
+       if (!bd1->buf && !bd2->buf)
+               return 0;
+
+       return memcmp(bd1->buf, bd2->buf, bd1->len);
+}
+
diff --git a/lib/roles/mqtt/private-lib-roles-mqtt.h b/lib/roles/mqtt/private-lib-roles-mqtt.h
new file mode 100644 (file)
index 0000000..d89f371
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _PRIVATE_LIB_ROLES_MQTT
+#define _PRIVATE_LIB_ROLES_MQTT 1
+
+extern struct lws_role_ops role_ops_mqtt;
+
+#define lwsi_role_mqtt(wsi) (wsi->role_ops == &role_ops_mqtt)
+
+#define LWS_MQTT_MAX_CHILDREN 8 /* max child streams on same parent */
+
+#define LMQCP_LUT_FLAG_RESERVED_FLAGS  0x10
+#define LMQCP_LUT_FLAG_PACKET_ID_NONE  0x00
+#define LMQCP_LUT_FLAG_PACKET_ID_HAS   0x20
+#define LMQCP_LUT_FLAG_PACKET_ID_QOS12 0x40
+#define LMQCP_LUT_FLAG_PACKET_ID_MASK  0x60
+#define LMQCP_LUT_FLAG_PAYLOAD        0x80     /* payload req (publish = opt)*/
+
+#define lws_mqtt_str_is_not_empty(s) ( ((s)) &&                \
+                                      ((s))->len &&    \
+                                      ((s))->buf &&    \
+                                      *((s))->buf )
+
+#define LWS_MQTT_RESPONSE_TIMEOUT      (3 * LWS_US_PER_SEC)
+#define LWS_MQTT_RETRY_CEILING         (60 * LWS_US_PER_SEC)
+
+typedef enum {
+       LMSPR_COMPLETED                 =  0,
+       LMSPR_NEED_MORE                 =  1,
+
+       LMSPR_FAILED_OOM                = -1,
+       LMSPR_FAILED_OVERSIZE           = -2,
+       LMSPR_FAILED_FORMAT             = -3,
+       LMSPR_FAILED_ALREADY_COMPLETED  = -4,
+} lws_mqtt_stateful_primitive_return_t;
+
+typedef struct {
+       uint32_t value;
+       char budget;
+       char consumed;
+} lws_mqtt_vbi;
+
+/* works for vbi, 2-byte and 4-byte fixed length */
+static inline int
+lws_mqtt_mb_first(lws_mqtt_vbi *vbi) { return !vbi->consumed; }
+
+int
+lws_mqtt_vbi_encode(uint32_t value, void *buf);
+
+/*
+ * Decode is done statefully on an arbitrary amount of input data (which may
+ * be one byte).  It's like this so it can continue seamlessly if a buffer ends
+ * partway through the primitive, and the api matches the bulk binary data case.
+ *
+ * VBI decode:
+ *
+ * Initialize the lws_mqtt_vbi state by calling lws_mqtt_vbi_init() on it, then
+ * feed lws_mqtt_vbi_r() bytes to decode.
+ *
+ * Returns <0 for error, LMSPR_COMPLETED if done (vbi->value is valid), or
+ * LMSPR_NEED_MORE if more calls to lws_mqtt_vbi_r() with subsequent bytes
+ * needed.
+ *
+ * *in and *len are updated accordingly.
+ *
+ * 2-byte and 4-byte decode:
+ *
+ * Initialize the lws_mqtt_vbi state by calling lws_mqtt_2byte_init() or
+ * lws_mqtt_4byte_init() on it, then feed lws_mqtt_mb_parse() bytes
+ * to decode.
+ *
+ * Returns <0 for error, LMSPR_COMPLETED if done (vbi->value is valid), or
+ * LMSPR_NEED_MORE if more calls to lws_mqtt_mb_parse() with subsequent
+ * bytes needed.
+ *
+ * *in and *len are updated accordingly.
+ */
+
+void
+lws_mqtt_vbi_init(lws_mqtt_vbi *vbi);
+
+void
+lws_mqtt_2byte_init(lws_mqtt_vbi *vbi);
+
+void
+lws_mqtt_4byte_init(lws_mqtt_vbi *vbi);
+
+lws_mqtt_stateful_primitive_return_t
+lws_mqtt_vbi_r(lws_mqtt_vbi *vbi, const uint8_t **in, size_t *len);
+
+lws_mqtt_stateful_primitive_return_t
+lws_mqtt_mb_parse(lws_mqtt_vbi *vbi, const uint8_t **in, size_t *len);
+
+struct lws_mqtt_str_st {
+       uint8_t         *buf;
+       uint16_t        len;
+
+       uint16_t        limit; /* it's cheaper to add the state here than
+                               * the pointer to point to it elsewhere */
+       uint16_t        pos;
+       char            len_valid;
+       char            needs_freeing;
+};
+
+static inline int
+lws_mqtt_str_first(struct lws_mqtt_str_st *s) { return !s->buf && !s->pos; }
+
+
+lws_mqtt_stateful_primitive_return_t
+lws_mqtt_str_parse(struct lws_mqtt_str_st *bd, const uint8_t **in, size_t *len);
+
+typedef enum {
+       LMQCPP_IDLE,
+
+       /* receive packet type part of fixed header took us out of idle... */
+       LMQCPP_CONNECT_PACKET = LMQCP_CTOS_CONNECT << 4,
+       LMQCPP_CONNECT_REMAINING_LEN_VBI,
+       LMQCPP_CONNECT_VH_PNAME,
+       LMQCPP_CONNECT_VH_PVERSION,
+       LMQCPP_CONNECT_VH_FLAGS,
+       LMQCPP_CONNECT_VH_KEEPALIVE,
+       LMQCPP_CONNECT_VH_PROPERTIES_VBI_LEN,
+
+       LMQCPP_CONNACK_PACKET = LMQCP_STOC_CONNACK << 4,
+       LMQCPP_CONNACK_VH_FLAGS,
+       LMQCPP_CONNACK_VH_RETURN_CODE,
+
+       LMQCPP_PUBLISH_PACKET = LMQCP_PUBLISH << 4,
+       LMQCPP_PUBLISH_REMAINING_LEN_VBI,
+       LMQCPP_PUBLISH_VH_TOPIC,
+       LMQCPP_PUBLISH_VH_PKT_ID,
+
+       LMQCPP_PUBACK_PACKET = LMQCP_PUBACK << 4,
+       LMQCPP_PUBACK_VH_PKT_ID,
+       LMQCPP_PUBACK_PROPERTIES_LEN_VBI,
+
+       LMQCPP_PUBREC_PACKET = LMQCP_PUBREC << 4,
+       LMQCPP_PUBREC_VH_PKT_ID,
+
+       LMQCPP_PUBREL_PACKET = LMQCP_PUBREL << 4,
+       LMQCPP_PUBREL_VH_PKT_ID,
+
+       LMQCPP_PUBCOMP_PACKET = LMQCP_PUBCOMP << 4,
+       LMQCPP_PUBCOMP_VH_PKT_ID,
+
+       LMQCPP_SUBACK_PACKET = LMQCP_STOC_SUBACK << 4,
+       LMQCPP_SUBACK_VH_PKT_ID,
+       LMQCPP_SUBACK_PAYLOAD,
+
+       LMQCPP_UNSUBACK_PACKET = LMQCP_STOC_UNSUBACK << 4,
+       LMQCPP_UNSUBACK_VH_PKT_ID,
+
+       LMQCPP_PINGRESP_ZERO = LMQCP_STOC_PINGRESP << 4,
+
+       LMQCPP_PAYLOAD,
+
+       LMQCPP_EAT_PROPERTIES_AND_COMPLETE,
+
+       LMQCPP_PROP_ID_VBI,
+
+       /* all possible property payloads */
+
+       /* 3.3.2.3.2 */
+       LMQCPP_PROP_PAYLOAD_FORMAT_INDICATOR_1BYTE                      = 0x101,
+
+       LMQCPP_PROP_MSG_EXPIRY_INTERVAL_4BYTE                           = 0x102,
+
+       LMQCPP_PROP_CONTENT_TYPE_UTF8S                                  = 0x103,
+
+       LMQCPP_PROP_RESPONSE_TOPIC_UTF8S                                = 0x108,
+
+       LMQCPP_PROP_CORRELATION_BINDATA                                 = 0x109,
+
+       LMQCPP_PROP_SUBSCRIPTION_ID_VBI                                 = 0x10b,
+
+       LMQCPP_PROP_SESSION_EXPIRY_INTERVAL_4BYTE                       = 0x111,
+
+       LMQCPP_PROP_ASSIGNED_CLIENTID_UTF8S                             = 0x112,
+
+       LMQCPP_PROP_SERVER_KEEPALIVE_2BYTE                              = 0x113,
+
+       LMQCPP_PROP_AUTH_METHOD_UTF8S                                   = 0x115,
+
+       LMQCPP_PROP_AUTH_DATA_BINDATA                                   = 0x116,
+
+       LMQCPP_PROP_REQUEST_PROBLEM_INFO_1BYTE                          = 0x117,
+
+       LMQCPP_PROP_WILL_DELAY_INTERVAL_4BYTE                           = 0x118,
+
+       LMQCPP_PROP_REQUEST_REPSONSE_INFO_1BYTE                         = 0x119,
+
+       LMQCPP_PROP_RESPONSE_INFO_UTF8S                                 = 0x11a,
+
+       LMQCPP_PROP_SERVER_REFERENCE_UTF8S                              = 0x11c,
+
+       LMQCPP_PROP_REASON_STRING_UTF8S                                 = 0x11f,
+
+       LMQCPP_PROP_RECEIVE_MAXIMUM_2BYTE                               = 0x121,
+
+       LMQCPP_PROP_TOPIC_MAXIMUM_2BYTE                                 = 0x122,
+
+       LMQCPP_PROP_TOPIC_ALIAS_2BYTE                                   = 0x123,
+
+       LMQCPP_PROP_MAXIMUM_QOS_1BYTE                                   = 0x124,
+
+       LMQCPP_PROP_RETAIN_AVAILABLE_1BYTE                              = 0x125,
+
+       LMQCPP_PROP_USER_PROPERTY_NAME_UTF8S                            = 0x126,
+       LMQCPP_PROP_USER_PROPERTY_VALUE_UTF8S                           = 0x226,
+
+       LMQCPP_PROP_MAXIMUM_PACKET_SIZE_4BYTE                           = 0x127,
+
+       LMQCPP_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE_1BYTE               = 0x128,
+
+       LMQCPP_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE_1BYTE             = 0x129,
+
+       LMQCPP_PROP_SHARED_SUBSCRIPTION_AVAILABLE_1BYTE                 = 0x12a,
+
+} lws_mqtt_packet_parse_state_t;
+
+/*
+ * the states an MQTT connection can be in
+ */
+
+typedef enum {
+       LGSMQTT_UNKNOWN,
+       LGSMQTT_IDLE,
+       LGSMQTT_TRANSPORT_CONNECTED,
+
+       LGSMQTT_SENT_CONNECT,
+       LGSMQTT_ESTABLISHED,
+
+       LGSMQTT_SENT_SUBSCRIBE,
+       LGSMQTT_SUBSCRIBED,
+
+} lwsgs_mqtt_states_t;
+
+typedef struct lws_mqtt_parser_st {
+       /* struct lws_mqtt_str_st s_content_type; */
+       lws_mqtt_packet_parse_state_t state;
+       lws_mqtt_vbi vbit;
+
+       lws_mqtt_reason_t reason;
+
+       lws_mqtt_str_t s_temp;
+
+       uint8_t fixed_seen[4];
+       uint8_t props_seen[8];
+
+       uint8_t cpkt_flags;
+       uint32_t cpkt_remlen;
+
+       uint32_t props_len;
+       uint32_t consumed;
+       uint32_t prop_id;
+       uint32_t props_consumed;
+       uint32_t payload_consumed;
+
+       uint16_t keepalive;
+       uint16_t cpkt_id;
+       uint32_t n;
+
+       uint8_t temp[32];
+       uint8_t conn_rc;
+       uint8_t payload_format;
+       uint8_t packet_type_flags;
+       uint8_t conn_protocol_version;
+       uint8_t fixed;
+
+       uint8_t flag_pending_send_connack_close:1;
+       uint8_t flag_pending_send_reason_close:1;
+       uint8_t flag_prop_multi:1;
+       uint8_t flag_server:1;
+
+} lws_mqtt_parser_t;
+
+typedef enum {
+       LMVTR_VALID                             =  0,
+       LMVTR_VALID_WILDCARD                    =  1,
+       LMVTR_VALID_SHADOW                      =  2,
+
+       LMVTR_FAILED_OVERSIZE                   = -1,
+       LMVTR_FAILED_WILDCARD_FORMAT            = -2,
+       LMVTR_FAILED_SHADOW_FORMAT              = -3,
+} lws_mqtt_validate_topic_return_t;
+
+typedef enum {
+       LMMTR_TOPIC_NOMATCH                     = 0,
+       LMMTR_TOPIC_MATCH                       = 1,
+
+       LMMTR_TOPIC_MATCH_ERROR                 = -1
+} lws_mqtt_match_topic_return_t;
+
+typedef struct lws_mqtt_subs {
+       struct lws_mqtt_subs    *next;
+
+       uint8_t                 ref_count; /* number of children referencing */
+
+       /* Flags */
+       uint8_t                 wildcard:1;
+       uint8_t                 shadow:1;
+
+       /* subscription name + NUL overallocated here */
+       char                    topic[];
+} lws_mqtt_subs_t;
+
+typedef struct lws_mqtts {
+       lws_mqtt_parser_t       par;
+       lwsgs_mqtt_states_t     estate;
+       struct lws_dll2         active_session_list_head;
+       struct lws_dll2         limbo_session_list_head;
+} lws_mqtts_t;
+
+typedef struct lws_mqttc {
+       lws_mqtt_parser_t       par;
+       lwsgs_mqtt_states_t     estate;
+       struct lws_mqtt_str_st  *id;
+       struct lws_mqtt_str_st  *username;
+       struct lws_mqtt_str_st  *password;
+       struct {
+               struct lws_mqtt_str_st  *topic;
+               struct lws_mqtt_str_st  *message;
+               lws_mqtt_qos_levels_t qos;
+               uint8_t         retain;
+       } will;
+       uint16_t                keep_alive_secs;
+       uint16_t                        conn_flags;
+       uint8_t                 aws_iot;
+} lws_mqttc_t;
+
+struct _lws_mqtt_related {
+       lws_mqttc_t             client;
+       lws_sorted_usec_list_t  sul_qos_puback_pubrec_wait; /* QoS1 puback or QoS2 pubrec wait TO */
+       lws_sorted_usec_list_t  sul_qos1_puback_wait; /* QoS1 puback wait TO */
+       lws_sorted_usec_list_t  sul_unsuback_wait; /* QoS1 unsuback wait TO */
+       lws_sorted_usec_list_t  sul_qos2_pubrec_wait; /* QoS2 pubrec wait TO */
+       struct lws              *wsi; /**< so sul can use lws_container_of */
+       lws_mqtt_subs_t         *subs_head; /**< Linked-list of heap-allocated subscription objects */
+       void                    *rx_cpkt_param;
+       uint16_t                pkt_id;
+       uint16_t                ack_pkt_id;
+       uint16_t                peer_ack_pkt_id;
+       uint16_t                sub_size;
+
+#if defined(LWS_WITH_CLIENT)
+       uint8_t                 send_pingreq:1;
+       uint8_t                 session_resumed:1;
+#endif
+       uint8_t                 inside_payload:1;
+       uint8_t                 inside_subscribe:1;
+       uint8_t                 inside_unsubscribe:1;
+       uint8_t                 inside_birth:1;
+       uint8_t                 inside_resume_session:1;
+       uint8_t                 send_puback:1;
+       uint8_t                 send_pubrel:1;
+       uint8_t                 send_pubrec:1;
+       uint8_t                 send_pubcomp:1;
+       uint8_t                 unacked_publish:1;
+       uint8_t                 unacked_pubrel:1;
+
+       uint8_t                 done_subscribe:1;
+       uint8_t                 done_birth:1;
+};
+
+/*
+ * New sessions are created by starting CONNECT.  If the ClientID sent
+ * by the client matches a different, extant session, then the
+ * existing one is taken over and the new one created for duration of
+ * CONNECT processing is destroyed.
+ *
+ * On the server side, bearing in mind multiple simultaneous,
+ * fragmented CONNECTs may be interleaved ongoing, all state and
+ * parsing temps for a session must live in the session object.
+ */
+
+struct lws_mqtt_endpoint_st;
+
+typedef struct lws_mqtts_session_st {
+       struct lws_dll2 session_list;
+
+} lws_mqtts_session_t;
+
+#define ctl_pkt_type(x) (x->packet_type_flags >> 4)
+
+
+void
+lws_mqttc_state_transition(lws_mqttc_t *ep, lwsgs_mqtt_states_t s);
+
+int
+_lws_mqtt_rx_parser(struct lws *wsi, lws_mqtt_parser_t *par,
+                   const uint8_t *buf, size_t len);
+
+int
+lws_mqtt_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd,
+                              struct lws *wsi_conn);
+
+int
+lws_create_client_mqtt_object(const struct lws_client_connect_info *i,
+                             struct lws *wsi);
+
+struct lws *
+lws_mqtt_client_send_connect(struct lws *wsi);
+
+struct lws *
+lws_mqtt_client_send_disconnect(struct lws *wsi);
+
+int
+lws_mqtt_fill_fixed_header(uint8_t *p, lws_mqtt_control_packet_t ctrl_pkt_type,
+                          uint8_t dup, lws_mqtt_qos_levels_t qos,
+                          uint8_t retain);
+
+struct lws *
+lws_wsi_mqtt_adopt(struct lws *parent_wsi, struct lws *wsi);
+
+lws_mqtt_subs_t *
+lws_mqtt_find_sub(struct _lws_mqtt_related *mqtt, const char *topic);
+
+#endif /* _PRIVATE_LIB_ROLES_MQTT */
+
diff --git a/lib/roles/netlink/ops-netlink.c b/lib/roles/netlink/ops-netlink.c
new file mode 100644 (file)
index 0000000..bb32048
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * We mainly focus on the routing table / gateways because those are the
+ * elements that decide if we can get on to the internet or not.
+ *
+ * We also need to understand the source addresses of possible outgoing routes,
+ * and follow LINK down (ifconfig down) to clean up routes on the interface idx
+ * going down that are not otherwise cleaned.
+ */
+
+#include <private-lib-core.h>
+
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+/* work around CentOS 7 -Wconversion problem */
+#undef RTA_ALIGNTO
+#define RTA_ALIGNTO 4U
+
+//#define lwsl_netlink lwsl_notice
+#define lwsl_cx_netlink lwsl_cx_info
+
+static void
+lws_netlink_coldplug_done_cb(lws_sorted_usec_list_t *sul)
+{
+       struct lws_context *ctx = lws_container_of(sul, struct lws_context,
+                                                  sul_nl_coldplug);
+       ctx->nl_initial_done = 1;
+#if defined(LWS_WITH_SYS_STATE)
+       /* if nothing is there to intercept anything, go all the way */
+       lws_state_transition_steps(&ctx->mgr_system, LWS_SYSTATE_OPERATIONAL);
+#endif
+}
+
+static int
+rops_handle_POLLIN_netlink(struct lws_context_per_thread *pt, struct lws *wsi,
+                          struct lws_pollfd *pollfd)
+{
+       struct lws_context      *cx = pt->context;
+       uint8_t s[4096]
+#if defined(_DEBUG)
+               , route_change = 0
+#endif
+#if defined(LWS_WITH_SYS_SMD)
+               , gateway_change = 0
+#endif
+                       ;
+       struct sockaddr_nl      nladdr;
+       lws_route_t             robj, *rou, *rmat;
+       struct nlmsghdr         *h;
+       struct msghdr           msg;
+       struct iovec            iov;
+       unsigned int            n;
+       char                    buf[72];
+
+       if (!(pollfd->revents & LWS_POLLIN))
+               return LWS_HPI_RET_HANDLED;
+
+       memset(&msg, 0, sizeof(msg));
+
+       iov.iov_base            = (void *)s;
+       iov.iov_len             = sizeof(s);
+
+       msg.msg_name            = (void *)&(nladdr);
+       msg.msg_namelen         = sizeof(nladdr);
+
+       msg.msg_iov             = &iov;
+       msg.msg_iovlen          = 1;
+
+       n = (unsigned int)recvmsg(wsi->desc.sockfd, &msg, 0);
+       if ((int)n < 0) {
+               lwsl_cx_notice(cx, "recvmsg failed");
+               return LWS_HPI_RET_PLEASE_CLOSE_ME;
+       }
+
+       // lwsl_hexdump_notice(s, (size_t)n);
+
+       h = (struct nlmsghdr *)s;
+
+       /* we can get a bunch of messages coalesced in one read*/
+
+       for ( ; NLMSG_OK(h, n); h = NLMSG_NEXT(h, n)) {
+               struct ifaddrmsg *ifam;
+               struct rtattr *ra;
+               struct rtmsg *rm;
+#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
+               struct ndmsg *nd;
+#endif
+               unsigned int ra_len;
+               uint8_t *p;
+
+               struct ifinfomsg *ifi;
+               struct rtattr *attribute;
+               unsigned int len;
+
+               lwsl_cx_netlink(cx, "RTM %d", h->nlmsg_type);
+
+               memset(&robj, 0, sizeof(robj));
+               robj.if_idx = -1;
+               robj.priority = -1;
+               rm = (struct rtmsg *)NLMSG_DATA(h);
+
+               /*
+                * We have to care about NEWLINK so we can understand when a
+                * network interface went down, and clear the related routes.
+                *
+                * We don't get individual DELROUTEs for these.
+                */
+
+               switch (h->nlmsg_type) {
+               case RTM_NEWLINK:
+
+                       ifi = NLMSG_DATA(h);
+                       len = (unsigned int)(h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
+
+                       /* loop over all attributes for the NEWLINK message */
+                       for (attribute = IFLA_RTA(ifi); RTA_OK(attribute, len);
+                                        attribute = RTA_NEXT(attribute, len)) {
+                               lwsl_cx_netlink(cx, "if attr %d",
+                                           (int)attribute->rta_type);
+                               switch(attribute->rta_type) {
+                               case IFLA_IFNAME:
+                                       lwsl_cx_netlink(cx, "NETLINK ifidx %d : %s",
+                                                    ifi->ifi_index,
+                                                    (char *)RTA_DATA(attribute));
+                                       break;
+                               default:
+                                       break;
+                               } /* switch */
+                       } /* for loop */
+
+                       lwsl_cx_netlink(cx, "NEWLINK ifi_index %d, flags 0x%x",
+                                       ifi->ifi_index, ifi->ifi_flags);
+
+                       /*
+                        * Despite "New"link this is actually telling us there
+                        * is some change on the network interface IFF_ state
+                        */
+
+                       if (!(ifi->ifi_flags & IFF_UP)) {
+                               /*
+                                * Interface is down, so scrub all routes that
+                                * applied to it
+                                */
+                               lwsl_cx_netlink(cx, "NEWLINK: ifdown %d",
+                                               ifi->ifi_index);
+                               lws_pt_lock(pt, __func__);
+                               _lws_route_table_ifdown(pt, ifi->ifi_index);
+                               lws_pt_unlock(pt);
+                       }
+                       continue; /* ie, not break, no second half */
+
+               case RTM_NEWADDR:
+               case RTM_DELADDR:
+
+                       ifam = (struct ifaddrmsg *)NLMSG_DATA(h);
+
+                       robj.source_ads = 1;
+                       robj.dest_len = ifam->ifa_prefixlen;
+                       robj.if_idx = (int)ifam->ifa_index;
+                       robj.scope = ifam->ifa_scope;
+                       robj.ifa_flags = ifam->ifa_flags;
+                       robj.dest.sa4.sin_family = ifam->ifa_family;
+
+                       /* address attributes */
+                       ra = (struct rtattr *)IFA_RTA(ifam);
+                       ra_len = (unsigned int)IFA_PAYLOAD(h);
+
+                       lwsl_cx_netlink(cx, "%s",
+                                    h->nlmsg_type == RTM_NEWADDR ?
+                                                    "NEWADDR" : "DELADDR");
+
+                       /*
+                        * almost nothing interesting within IFA_* attributes:
+                        * so skip it and goto to the second half
+                        */
+                       goto second_half;
+
+               case RTM_NEWROUTE:
+               case RTM_DELROUTE:
+
+                       lwsl_cx_netlink(cx, "%s",
+                                    h->nlmsg_type == RTM_NEWROUTE ?
+                                                    "NEWROUTE" : "DELROUTE");
+
+                       /* route attributes */
+                       ra = (struct rtattr *)RTM_RTA(rm);
+                       ra_len = (unsigned int)RTM_PAYLOAD(h);
+                       break;
+
+               case RTM_DELNEIGH:
+               case RTM_NEWNEIGH:
+                       lwsl_cx_netlink(cx, "%s", h->nlmsg_type ==
+                                               RTM_NEWNEIGH ? "NEWNEIGH" :
+                                                              "DELNEIGH");
+#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
+                       nd = (struct ndmsg *)rm;
+                       lwsl_cx_netlink(cx, "fam %u, ifidx %u, flags 0x%x",
+                                   nd->ndm_family, nd->ndm_ifindex,
+                                   nd->ndm_flags);
+#endif
+                       ra = (struct rtattr *)RTM_RTA(rm);
+                       ra_len = (unsigned int)RTM_PAYLOAD(h);
+                       for ( ; RTA_OK(ra, ra_len); ra = RTA_NEXT(ra, ra_len)) {
+                               lwsl_cx_netlink(cx, "atr %d", ra->rta_type);
+                               switch (ra->rta_type) {
+                               case NDA_DST:
+                                       lwsl_cx_netlink(cx, "dst len %d",
+                                                       ra->rta_len);
+                                       break;
+                               }
+                       }
+                       lws_pt_lock(pt, __func__);
+                       _lws_route_pt_close_unroutable(pt);
+                       lws_pt_unlock(pt);
+                       continue;
+
+               default:
+                       lwsl_cx_netlink(cx, "*** Unknown RTM_%d",
+                                       h->nlmsg_type);
+                       continue;
+               } /* switch */
+
+               robj.proto = rm->rtm_protocol;
+
+               // iterate over route attributes
+               for ( ; RTA_OK(ra, ra_len); ra = RTA_NEXT(ra, ra_len)) {
+                       // lwsl_netlink("%s: atr %d\n", __func__, ra->rta_type);
+                       switch (ra->rta_type) {
+                       case RTA_PREFSRC: /* protocol ads: preferred src ads */
+                       case RTA_SRC:
+                               lws_sa46_copy_address(&robj.src, RTA_DATA(ra),
+                                                       rm->rtm_family);
+                               robj.src_len = rm->rtm_src_len;
+                               lws_sa46_write_numeric_address(&robj.src, buf, sizeof(buf));
+                               lwsl_cx_netlink(cx, "RTA_SRC: %s", buf);
+                               break;
+                       case RTA_DST:
+                               lws_sa46_copy_address(&robj.dest, RTA_DATA(ra),
+                                                       rm->rtm_family);
+                               robj.dest_len = rm->rtm_dst_len;
+                               lws_sa46_write_numeric_address(&robj.dest, buf, sizeof(buf));
+                               lwsl_cx_netlink(cx, "RTA_DST: %s", buf);
+                               break;
+                       case RTA_GATEWAY:
+                               lws_sa46_copy_address(&robj.gateway,
+                                                     RTA_DATA(ra),
+                                                     rm->rtm_family);
+#if defined(LWS_WITH_SYS_SMD)
+                               gateway_change = 1;
+#endif
+                               break;
+                       case RTA_IIF: /* int: input interface index */
+                       case RTA_OIF: /* int: output interface index */
+                               robj.if_idx = *(int *)RTA_DATA(ra);
+                               lwsl_cx_netlink(cx, "ifidx %d", robj.if_idx);
+                               break;
+                       case RTA_PRIORITY: /* int: priority of route */
+                               p = RTA_DATA(ra);
+                               robj.priority = p[3] << 24 | p[2] << 16 |
+                                                p[1] << 8  | p[0];
+                               break;
+                       case RTA_CACHEINFO: /* struct rta_cacheinfo */
+                               break;
+#if defined(LWS_HAVE_RTA_PREF)
+                       case RTA_PREF: /* char: RFC4191 v6 router preference */
+                               break;
+#endif
+                       case RTA_TABLE: /* int */
+                               break;
+
+                       default:
+                               lwsl_cx_info(cx, "unknown attr type %d",
+                                            ra->rta_type);
+                               break;
+                       }
+               } /* for */
+
+               /*
+                * the second half, once all the attributes were collected
+                */
+second_half:
+               switch (h->nlmsg_type) {
+
+               case RTM_DELROUTE:
+                       /*
+                        * This will also take down wsi marked as using it
+                        */
+                       lwsl_cx_netlink(cx, "DELROUTE: if_idx %d",
+                                       robj.if_idx);
+                       lws_pt_lock(pt, __func__);
+                       _lws_route_remove(pt, &robj, 0);
+                       lws_pt_unlock(pt);
+                       goto inform;
+
+               case RTM_NEWROUTE:
+
+                       lwsl_cx_netlink(cx, "NEWROUTE rtm_type %d",
+                                       rm->rtm_type);
+
+                       /*
+                        * We don't want any routing debris like /32 or broadcast
+                        * in our routing table... we will collect source addresses
+                        * bound to interfaces via NEWADDR
+                        */
+
+                       if (rm->rtm_type != RTN_UNICAST &&
+                           rm->rtm_type != RTN_LOCAL)
+                               break;
+
+                       if (rm->rtm_flags & RTM_F_CLONED)
+                               break;
+
+                       goto ana;
+
+               case RTM_DELADDR:
+                       lwsl_cx_notice(cx, "DELADDR");
+#if defined(_DEBUG)
+                       _lws_routing_entry_dump(cx, &robj);
+#endif
+                       lws_pt_lock(pt, __func__);
+                       _lws_route_remove(pt, &robj, LRR_MATCH_SRC | LRR_IGNORE_PRI);
+                       _lws_route_pt_close_unroutable(pt);
+                       lws_pt_unlock(pt);
+                       break;
+
+               case RTM_NEWADDR:
+
+                       lwsl_cx_netlink(cx, "NEWADDR");
+ana:
+
+                       /*
+                        * Is robj a dupe in the routing table already?
+                        *
+                        * match on pri ignore == set pri and skip
+                        * no match == add
+                        */
+
+                       lws_pt_lock(pt, __func__);
+
+                       /* returns zero on match already in table */
+                       rmat = _lws_route_remove(pt, &robj, LRR_MATCH_SRC |
+                                                           LRR_JUST_CHECK |
+                                                           LRR_IGNORE_PRI);
+                       lws_pt_unlock(pt);
+
+                       if (rmat) {
+                               rmat->priority = robj.priority;
+                               break;
+                       }
+
+                       rou = lws_malloc(sizeof(*rou), __func__);
+                       if (!rou) {
+                               lwsl_cx_err(cx, "oom");
+                               return LWS_HPI_RET_HANDLED;
+                       }
+
+                       *rou = robj;
+
+                       lws_pt_lock(pt, __func__);
+
+                       /*
+                        * We lock the pt before getting the uidx, so it
+                        * cannot race
+                        */
+
+                       rou->uidx = _lws_route_get_uidx(cx);
+                       lws_dll2_add_tail(&rou->list, &cx->routing_table);
+                       lwsl_cx_info(cx, "route list size %u",
+                                       cx->routing_table.count);
+
+                       _lws_route_pt_close_unroutable(pt);
+
+                       lws_pt_unlock(pt);
+
+inform:
+#if defined(_DEBUG)
+                       route_change = 1;
+#endif
+#if defined(LWS_WITH_SYS_SMD)
+                       /*
+                        * Reflect the route add / del event using SMD.
+                        * Participants interested can refer to the pt
+                        * routing table
+                        */
+                       (void)lws_smd_msg_printf(cx, LWSSMDCL_NETWORK,
+                                  "{\"rt\":\"%s\"}\n",
+                                  (h->nlmsg_type == RTM_DELROUTE) ?
+                                               "del" : "add");
+#endif
+
+                       break;
+
+               default:
+                       // lwsl_info("%s: unknown msg type %d\n", __func__,
+                       //              h->nlmsg_type);
+                       break;
+               }
+       } /* message iterator */
+
+#if defined(LWS_WITH_SYS_SMD)
+       if (gateway_change)
+               /*
+                * If a route with a gw was added or deleted, retrigger captive
+                * portal detection if we have that
+                */
+               (void)lws_smd_msg_printf(cx, LWSSMDCL_NETWORK,
+                                  "{\"trigger\": \"cpdcheck\", "
+                                  "\"src\":\"gw-change\"}");
+#endif
+
+#if defined(_DEBUG)
+       if (route_change) {
+               lws_context_lock(cx, __func__);
+               _lws_routing_table_dump(cx);
+               lws_context_unlock(cx);
+       }
+#endif
+
+       if (!cx->nl_initial_done &&
+           pt == &cx->pt[0] &&
+           cx->routing_table.count) {
+               /*
+                * While netlink info still coming, keep moving the timer for
+                * calling it "done" to +100ms until after it stops coming
+                */
+               lws_context_lock(cx, __func__);
+               lws_sul_schedule(cx, 0, &cx->sul_nl_coldplug,
+                                lws_netlink_coldplug_done_cb,
+                                100 * LWS_US_PER_MS);
+               lws_context_unlock(cx);
+       }
+
+       return LWS_HPI_RET_HANDLED;
+}
+
+struct nl_req_s {
+       struct nlmsghdr hdr;
+       struct rtmsg gen;
+};
+
+int
+rops_pt_init_destroy_netlink(struct lws_context *context,
+                            const struct lws_context_creation_info *info,
+                            struct lws_context_per_thread *pt, int destroy)
+{
+       struct sockaddr_nl sanl;
+       struct nl_req_s req;
+       struct msghdr msg;
+       struct iovec iov;
+       struct lws *wsi;
+       int n, ret = 1;
+
+       if (destroy) {
+
+               /*
+                * pt netlink wsi closed + freed as part of pt's destroy
+                * wsi mass close, just need to take down the routing table
+                */
+               _lws_route_table_empty(pt);
+
+               return 0;
+       }
+
+       if (context->netlink)
+               return 0;
+
+       if (pt > &context->pt[0])
+               /* we can only have one netlink socket */
+               return 0;
+
+       lwsl_cx_info(context, "creating netlink skt");
+
+       /*
+        * We want a netlink socket per pt as well
+        */
+
+       lws_context_lock(context, __func__);
+       wsi = __lws_wsi_create_with_role(context, (int)(pt - &context->pt[0]),
+                                      &role_ops_netlink, NULL);
+       lws_context_unlock(context);
+       if (!wsi)
+               goto bail;
+
+       wsi->desc.sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       if (wsi->desc.sockfd == LWS_SOCK_INVALID) {
+               lwsl_cx_err(context, "unable to open netlink");
+               goto bail1;
+       }
+
+       lws_plat_set_nonblocking(wsi->desc.sockfd);
+
+       __lws_lc_tag(context, &context->lcg[LWSLCG_VHOST], &wsi->lc,
+                       "netlink");
+
+       memset(&sanl, 0, sizeof(sanl));
+       sanl.nl_family          = AF_NETLINK;
+       sanl.nl_pid             = (uint32_t)getpid();
+       sanl.nl_groups          = (1 << (RTNLGRP_LINK - 1)) |
+                                 (1 << (RTNLGRP_IPV4_ROUTE - 1)) |
+                                 (1 << (RTNLGRP_IPV4_IFADDR - 1))
+#if defined(LWS_WITH_IPV6)
+                                 | (1 << (RTNLGRP_IPV6_ROUTE - 1)) |
+                                   (1 << (RTNLGRP_IPV6_IFADDR - 1))
+#endif
+                                ;
+
+       if (lws_fi(&context->fic, "netlink_bind") ||
+           bind(wsi->desc.sockfd, (struct sockaddr*)&sanl, sizeof(sanl)) < 0) {
+               lwsl_cx_warn(context, "netlink bind failed");
+               ret = 0; /* some systems deny access, just ignore */
+               goto bail2;
+       }
+
+       context->netlink = wsi;
+       if (lws_wsi_inject_to_loop(pt, wsi))
+               goto bail2;
+
+/*     if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
+               lwsl_err("%s: pollfd in fail\n", __func__);
+               goto bail2;
+       }
+*/
+       /*
+        * Since we're starting the PT, ask to be sent all the existing routes.
+        *
+        * This requires CAP_ADMIN, or root... we do this early before dropping
+        * privs
+        */
+
+       memset(&sanl, 0, sizeof(sanl));
+       memset(&msg, 0, sizeof(msg));
+       memset(&req, 0, sizeof(req));
+
+       sanl.nl_family          = AF_NETLINK;
+
+       req.hdr.nlmsg_len       = NLMSG_LENGTH(sizeof(req.gen));
+       req.hdr.nlmsg_type      = RTM_GETROUTE;
+       req.hdr.nlmsg_flags     = NLM_F_REQUEST | NLM_F_DUMP;
+       req.hdr.nlmsg_seq       = 1;
+       req.hdr.nlmsg_pid       = (uint32_t)getpid();
+       req.gen.rtm_family      = AF_PACKET;
+       req.gen.rtm_table       = RT_TABLE_DEFAULT;
+
+       iov.iov_base            = &req;
+       iov.iov_len             = req.hdr.nlmsg_len;
+       msg.msg_iov             = &iov;
+       msg.msg_iovlen          = 1;
+       msg.msg_name            = &sanl;
+       msg.msg_namelen         = sizeof(sanl);
+
+       n = (int)sendmsg(wsi->desc.sockfd, (struct msghdr *)&msg, 0);
+       if (n < 0) {
+               lwsl_cx_notice(context, "rt dump req failed... permissions? errno %d",
+                               LWS_ERRNO);
+       }
+
+       /*
+        * Responses are going to come asynchronously, let's block moving
+        * off state IFACE_COLDPLUG until we have had them.  This is important
+        * since if we don't hold there, when we do get the responses we may
+        * cull any ongoing connections as unroutable otherwise
+        */
+
+       lwsl_cx_debug(context, "starting netlink coldplug wait");
+
+       return 0;
+
+bail2:
+       __lws_lc_untag(wsi->a.context, &wsi->lc);
+       compatible_close(wsi->desc.sockfd);
+bail1:
+       lws_free(wsi);
+bail:
+       return ret;
+}
+
+static const lws_rops_t rops_table_netlink[] = {
+       /*  1 */ { .pt_init_destroy     = rops_pt_init_destroy_netlink },
+       /*  2 */ { .handle_POLLIN       = rops_handle_POLLIN_netlink },
+};
+
+const struct lws_role_ops role_ops_netlink = {
+       /* role name */                 "netlink",
+       /* alpn id */                   NULL,
+
+       /* rops_table */                rops_table_netlink,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x01,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x02,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x00,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x00,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x00,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x00,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x00,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0x00,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x00,
+                                       },
+
+       /* adoption_cb clnt, srv */     { 0, 0 },
+       /* rx_cb clnt, srv */           { 0, 0 },
+       /* writeable cb clnt, srv */    { 0, 0 },
+       /* close cb clnt, srv */        { 0, 0 },
+       /* protocol_bind_cb c,s */      { 0, 0 },
+       /* protocol_unbind_cb c,s */    { 0, 0 },
+       /* file_handle */               0,
+};
index 88aab5f..4d39d31 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 static int
 rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi,
@@ -27,8 +30,14 @@ rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi,
 {
 #if defined(LWS_HAVE_EVENTFD)
        eventfd_t value;
-       if (eventfd_read(wsi->desc.sockfd, &value) < 0)
+       int n;
+
+       n = eventfd_read(wsi->desc.sockfd, &value);
+       if (n < 0) {
+               lwsl_notice("%s: eventfd read %d bailed errno %d\n", __func__,
+                               wsi->desc.sockfd, LWS_ERRNO);
                return LWS_HPI_RET_PLEASE_CLOSE_ME;
+       }
 #elif !defined(WIN32) && !defined(_WIN32)
        char s[100];
        int n;
@@ -38,10 +47,17 @@ rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi,
         * We really don't care about the number of bytes, but coverity
         * thinks we should.
         */
-       n = read(wsi->desc.sockfd, s, sizeof(s));
+       n = (int)read(wsi->desc.sockfd, s, sizeof(s));
        (void)n;
        if (n < 0)
                return LWS_HPI_RET_PLEASE_CLOSE_ME;
+#elif defined(WIN32)
+       char s[100];
+       int n;
+
+       n = recv(wsi->desc.sockfd, s, sizeof(s), 0);
+       if (n == SOCKET_ERROR)
+               return LWS_HPI_RET_PLEASE_CLOSE_ME;
 #endif
 
 #if defined(LWS_WITH_THREADPOOL)
@@ -55,6 +71,37 @@ rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi,
        lws_threadpool_tsi_context(pt->context, pt->tid);
 #endif
 
+#if LWS_MAX_SMP > 1
+
+       /*
+        * Other pts need to take care of their own wsi bound to a vhost that
+        * is going down
+        */
+
+       if (pt->context->owner_vh_being_destroyed.head) {
+
+               lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                     pt->context->owner_vh_being_destroyed.head) {
+                       struct lws_vhost *v =
+                               lws_container_of(d, struct lws_vhost,
+                                                vh_being_destroyed_list);
+
+                       lws_vhost_lock(v); /* -------------- vh { */
+                       __lws_vhost_destroy_pt_wsi_dieback_start(v);
+                       lws_vhost_unlock(v); /* } vh -------------- */
+
+               } lws_end_foreach_dll_safe(d, d1);
+       }
+
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       lws_dll2_foreach_safe(&pt->ss_owner, NULL, lws_ss_cancel_notify_dll);
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) && defined(LWS_WITH_CLIENT)
+       lws_dll2_foreach_safe(&pt->ss_client_owner, NULL, lws_sspc_cancel_notify_dll);
+#endif
+#endif
+
        /*
         * the poll() wait, or the event loop for libuv etc is a
         * process-wide resource that we interrupted.  So let every
@@ -69,34 +116,48 @@ rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi,
        return LWS_HPI_RET_HANDLED;
 }
 
-struct lws_role_ops role_ops_pipe = {
+static const lws_rops_t rops_table_pipe[] = {
+       /*  1 */ { .handle_POLLIN       = rops_handle_POLLIN_pipe },
+};
+
+
+const struct lws_role_ops role_ops_pipe = {
        /* role name */                 "pipe",
        /* alpn id */                   NULL,
-       /* check_upgrades */            NULL,
-       /* init_context */              NULL,
-       /* init_vhost */                NULL,
-       /* destroy_vhost */             NULL,
-       /* periodic_checks */           NULL,
-       /* service_flag_pending */      NULL,
-       /* handle_POLLIN */             rops_handle_POLLIN_pipe,
-       /* handle_POLLOUT */            NULL,
-       /* perform_user_POLLOUT */      NULL,
-       /* callback_on_writable */      NULL,
-       /* tx_credit */                 NULL,
-       /* write_role_protocol */       NULL,
-       /* encapsulation_parent */      NULL,
-       /* alpn_negotiated */           NULL,
-       /* close_via_role_protocol */   NULL,
-       /* close_role */                NULL,
-       /* close_kill_connection */     NULL,
-       /* destroy_role */              NULL,
-       /* adoption_bind */             NULL,
-       /* client_bind */               NULL,
+
+       /* rops_table */                rops_table_pipe,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x00,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x01,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x00,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x00,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x00,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x00,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x00,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0x00,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x00,
+                                       },
+
        /* adoption_cb clnt, srv */     { 0, 0 },
        /* rx_cb clnt, srv */           { 0, 0 },
        /* writeable cb clnt, srv */    { 0, 0 },
        /* close cb clnt, srv */        { 0, 0 },
        /* protocol_bind_cb c,s */      { 0, 0 },
        /* protocol_unbind_cb c,s */    { 0, 0 },
+#if defined(WIN32)
+       /* file_handle (no, UDP) */     0,
+#else
        /* file_handle */               1,
+#endif
 };
diff --git a/lib/roles/private-lib-roles.h b/lib/roles/private-lib-roles.h
new file mode 100644 (file)
index 0000000..1c7adb6
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+typedef uint32_t lws_wsi_state_t;
+
+/*
+ * The wsi->role_ops pointer decides almost everything about what role the wsi
+ * will play, h2, raw, ws, etc.
+ *
+ * However there are a few additional flags needed that vary, such as if the
+ * role is a client or server side, if it has that concept.  And the connection
+ * fulfilling the role, has a separate dynamic state.
+ *
+ *   31           16 15      0
+ *   [  role flags ] [ state ]
+ *
+ * The role flags part is generally invariant for the lifetime of the wsi,
+ * although it can change if the connection role itself does, eg, if the
+ * connection upgrades from H1 -> WS1 the role flags may be changed at that
+ * point.
+ *
+ * The state part reflects the dynamic connection state, and the states are
+ * reused between roles.
+ *
+ * None of the internal role or state representations are made available outside
+ * of lws internals.  Even for lws internals, if you add stuff here, please keep
+ * the constants inside this header only by adding necessary helpers here and
+ * use the helpers in the actual code.  This is to ease any future refactors.
+ *
+ * Notice LWSIFR_ENCAP means we have a parent wsi that actually carries our
+ * data as a stream inside a different protocol.
+ */
+
+#define _RS 16
+
+#define LWSIFR_CLIENT          (0x1000 << _RS) /* client side */
+#define LWSIFR_SERVER          (0x2000 << _RS) /* server side */
+
+#define LWSIFR_P_ENCAP_H2      (0x0100 << _RS) /* we are encapsulated by h2 */
+
+enum lwsi_role {
+       LWSI_ROLE_MASK          =                            (0xffff << _RS),
+       LWSI_ROLE_ENCAP_MASK    =                            (0x0f00 << _RS),
+};
+
+#define lwsi_role(wsi) (wsi->wsistate & (unsigned int)LWSI_ROLE_MASK)
+#if !defined (_DEBUG)
+#define lwsi_set_role(wsi, role) wsi->wsistate = \
+                               (wsi->wsistate & (~LWSI_ROLE_MASK)) | role
+#else
+void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role);
+#endif
+
+#define lwsi_role_client(wsi) (!!(wsi->wsistate & LWSIFR_CLIENT))
+#define lwsi_role_server(wsi) (!!(wsi->wsistate & LWSIFR_SERVER))
+#define lwsi_role_h2_ENCAPSULATION(wsi) \
+               ((wsi->wsistate & LWSI_ROLE_ENCAP_MASK) == LWSIFR_P_ENCAP_H2)
+
+/* Pollout wants a callback in this state */
+#define LWSIFS_POCB            (0x100)
+/* Before any protocol connection was established */
+#define LWSIFS_NOT_EST         (0x200)
+
+enum lwsi_state {
+
+       /* Phase 1: pre-transport */
+
+       LRS_UNCONNECTED                         = LWSIFS_NOT_EST | 0,
+       LRS_WAITING_DNS                         = LWSIFS_NOT_EST | 1,
+       LRS_WAITING_CONNECT                     = LWSIFS_NOT_EST | 2,
+
+       /* Phase 2: establishing intermediaries on top of transport */
+
+       LRS_WAITING_PROXY_REPLY                 = LWSIFS_NOT_EST | 3,
+       LRS_WAITING_SSL                         = LWSIFS_NOT_EST | 4,
+       LRS_WAITING_SOCKS_GREETING_REPLY        = LWSIFS_NOT_EST | 5,
+       LRS_WAITING_SOCKS_CONNECT_REPLY         = LWSIFS_NOT_EST | 6,
+       LRS_WAITING_SOCKS_AUTH_REPLY            = LWSIFS_NOT_EST | 7,
+
+       /* Phase 3: establishing tls tunnel */
+
+       LRS_SSL_INIT                            = LWSIFS_NOT_EST | 8,
+       LRS_SSL_ACK_PENDING                     = LWSIFS_NOT_EST | 9,
+       LRS_PRE_WS_SERVING_ACCEPT               = LWSIFS_NOT_EST | 10,
+
+       /* Phase 4: connected */
+
+       LRS_WAITING_SERVER_REPLY                = LWSIFS_NOT_EST | 11,
+       LRS_H2_AWAIT_PREFACE                    = LWSIFS_NOT_EST | 12,
+       LRS_H2_AWAIT_SETTINGS                   = LWSIFS_NOT_EST |
+                                                 LWSIFS_POCB | 13,
+       LRS_MQTTC_IDLE                          = LWSIFS_POCB | 33,
+       LRS_MQTTC_AWAIT_CONNACK                 = 34,
+
+       /* Phase 5: protocol logically established */
+
+       LRS_H2_CLIENT_SEND_SETTINGS             = LWSIFS_POCB | 14,
+       LRS_H2_WAITING_TO_SEND_HEADERS          = LWSIFS_POCB | 15,
+       LRS_DEFERRING_ACTION                    = LWSIFS_POCB | 16,
+       LRS_IDLING                              = 17,
+       LRS_H1C_ISSUE_HANDSHAKE                 = 18,
+       LRS_H1C_ISSUE_HANDSHAKE2                = 19,
+       LRS_ISSUE_HTTP_BODY                     = 20,
+       LRS_ISSUING_FILE                        = 21,
+       LRS_HEADERS                             = 22,
+       LRS_BODY                                = 23,
+       LRS_DISCARD_BODY                        = 24,
+       LRS_ESTABLISHED                         = LWSIFS_POCB | 25,
+
+       /* we are established, but we have embarked on serving a single
+        * transaction.  Other transaction input may be pending, but we will
+        * not service it while we are busy dealing with the current
+        * transaction.
+        *
+        * When we complete the current transaction, we would reset our state
+        * back to ESTABLISHED and start to process the next transaction.
+        */
+       LRS_DOING_TRANSACTION                   = LWSIFS_POCB | 26,
+
+       /* Phase 6: finishing */
+
+       LRS_WAITING_TO_SEND_CLOSE               = LWSIFS_POCB | 27,
+       LRS_RETURNED_CLOSE                      = LWSIFS_POCB | 28,
+       LRS_AWAITING_CLOSE_ACK                  = LWSIFS_POCB | 29,
+       LRS_FLUSHING_BEFORE_CLOSE               = LWSIFS_POCB | 30,
+       LRS_SHUTDOWN                            = 31,
+
+       /* Phase 7: dead */
+
+       LRS_DEAD_SOCKET                         = 32,
+
+       LRS_MASK                                = 0xffff
+};
+
+#define lwsi_state(wsi) ((enum lwsi_state)(wsi->wsistate & LRS_MASK))
+#define lwsi_state_PRE_CLOSE(wsi) \
+               ((enum lwsi_state)(wsi->wsistate_pre_close & LRS_MASK))
+#define lwsi_state_est(wsi) (!(wsi->wsistate & LWSIFS_NOT_EST))
+#define lwsi_state_est_PRE_CLOSE(wsi) \
+               (!(wsi->wsistate_pre_close & LWSIFS_NOT_EST))
+#define lwsi_state_can_handle_POLLOUT(wsi) (wsi->wsistate & LWSIFS_POCB)
+#if !defined (_DEBUG)
+#define lwsi_set_state(wsi, lrs) wsi->wsistate = \
+                         (wsi->wsistate & (lws_wsi_state_t)(~LRS_MASK)) | lrs
+#else
+void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs);
+#endif
+
+#define _LWS_ADOPT_FINISH (1 << 24)
+
+/*
+ * Internal role-specific ops
+ *
+ * Many roles are sparsely filled with callbacks, rather than has 20 x
+ * function pointers in the ops struct, let's have a 20 nybble array telling us
+ * if the pointer doesn't exist, or its offset in a smaller "just pointers that
+ * exist" array.
+ *
+ * We can support up to 15 valid pointers in the role that way and only have to
+ * provide pointers that exist for that role, at the cost of a 10-byte nybble
+ * table.
+ *
+ * For x86_64, a set 196 byte allocation becomes 60 + 8 bytes per defined ptr,
+ * where the ops table is sparse this is a considable .rodata saving, for 32-bit
+ * 52 + 4 bytes per defined ptr accounting for padding.
+ */
+
+/*
+ * After http headers have parsed, this is the last chance for a role
+ * to upgrade the connection to something else using the headers.
+ * ws-over-h2 is upgraded from h2 like this.
+ */
+typedef int (*lws_rops_check_upgrades_t)(struct lws *wsi);
+/* role-specific context init during context creation */
+typedef int (*lws_rops_pt_init_destroy_t)(struct lws_context *context,
+                               const struct lws_context_creation_info *info,
+                               struct lws_context_per_thread *pt, int destroy);
+/* role-specific per-vhost init during vhost creation */
+typedef int (*lws_rops_init_vhost_t)(struct lws_vhost *vh,
+                                 const struct lws_context_creation_info *info);
+/* role-specific per-vhost destructor during vhost destroy */
+typedef int (*lws_rops_destroy_vhost_t)(struct lws_vhost *vh);
+/* chance for the role to force POLLIN without network activity */
+typedef int (*lws_rops_service_flag_pending_t)(struct lws_context *context,
+                                              int tsi);
+/* an fd using this role has POLLIN signalled */
+typedef int (*lws_rops_handle_POLLIN_t)(struct lws_context_per_thread *pt,
+                                       struct lws *wsi,
+                                       struct lws_pollfd *pollfd);
+/* an fd using the role wanted a POLLOUT callback and now has it */
+typedef int (*lws_rops_handle_POLLOUT_t)(struct lws *wsi);
+/* perform user pollout */
+typedef int (*lws_rops_perform_user_POLLOUT_t)(struct lws *wsi);
+/* do effective callback on writeable */
+typedef int (*lws_rops_callback_on_writable_t)(struct lws *wsi);
+/* connection-specific tx credit in bytes */
+typedef int (*lws_rops_tx_credit_t)(struct lws *wsi, char peer_to_us, int add);
+/* role-specific write formatting */
+typedef int (*lws_rops_write_role_protocol_t)(struct lws *wsi,
+                                             unsigned char *buf, size_t len,
+                                             enum lws_write_protocol *wp);
+
+/* get encapsulation parent */
+typedef struct lws * (*lws_rops_encapsulation_parent_t)(struct lws *wsi);
+
+/* role-specific destructor */
+typedef int (*lws_rops_alpn_negotiated_t)(struct lws *wsi, const char *alpn);
+
+/* chance for the role to handle close in the protocol */
+typedef int (*lws_rops_close_via_role_protocol_t)(struct lws *wsi,
+                                                 enum lws_close_status reason);
+/* role-specific close processing */
+typedef int (*lws_rops_close_role_t)(struct lws_context_per_thread *pt,
+                                    struct lws *wsi);
+/* role-specific connection close processing */
+typedef int (*lws_rops_close_kill_connection_t)(struct lws *wsi,
+                                               enum lws_close_status reason);
+/* role-specific destructor */
+typedef int (*lws_rops_destroy_role_t)(struct lws *wsi);
+
+/* role-specific socket-adopt */
+typedef int (*lws_rops_adoption_bind_t)(struct lws *wsi, int type,
+                                       const char *prot);
+/* role-specific client-bind:
+ * ret 1 = bound, 0 = not bound, -1 = fail out
+ * i may be NULL, indicating client_bind is being called after
+ * a successful bind earlier, to finalize the binding.  In that
+ * case ret 0 = OK, 1 = fail, wsi needs freeing, -1 = fail, wsi freed */
+typedef int (*lws_rops_client_bind_t)(struct lws *wsi,
+                                     const struct lws_client_connect_info *i);
+/* isvalid = 0: request a role-specific keepalive (PING etc)
+ *         = 1: reset any related validity timer */
+typedef int (*lws_rops_issue_keepalive_t)(struct lws *wsi, int isvalid);
+
+#define LWS_COUNT_ROLE_OPS                     20
+
+typedef union lws_rops {
+       lws_rops_check_upgrades_t               check_upgrades;
+       lws_rops_pt_init_destroy_t              pt_init_destroy;
+       lws_rops_init_vhost_t                   init_vhost;
+       lws_rops_destroy_vhost_t                destroy_vhost;
+       lws_rops_service_flag_pending_t         service_flag_pending;
+       lws_rops_handle_POLLIN_t                handle_POLLIN;
+       lws_rops_handle_POLLOUT_t               handle_POLLOUT;
+       lws_rops_perform_user_POLLOUT_t         perform_user_POLLOUT;
+       lws_rops_callback_on_writable_t         callback_on_writable;
+       lws_rops_tx_credit_t                    tx_credit;
+       lws_rops_write_role_protocol_t          write_role_protocol;
+       lws_rops_encapsulation_parent_t         encapsulation_parent;
+       lws_rops_alpn_negotiated_t              alpn_negotiated;
+       lws_rops_close_via_role_protocol_t      close_via_role_protocol;
+       lws_rops_close_role_t                   close_role;
+       lws_rops_close_kill_connection_t        close_kill_connection;
+       lws_rops_destroy_role_t                 destroy_role;
+       lws_rops_adoption_bind_t                adoption_bind;
+       lws_rops_client_bind_t                  client_bind;
+       lws_rops_issue_keepalive_t              issue_keepalive;
+} lws_rops_t;
+
+typedef enum {
+       LWS_ROPS_check_upgrades,
+       LWS_ROPS_pt_init_destroy,
+       LWS_ROPS_init_vhost,
+       LWS_ROPS_destroy_vhost,
+       LWS_ROPS_service_flag_pending,
+       LWS_ROPS_handle_POLLIN,
+       LWS_ROPS_handle_POLLOUT,
+       LWS_ROPS_perform_user_POLLOUT,
+       LWS_ROPS_callback_on_writable,
+       LWS_ROPS_tx_credit,
+       LWS_ROPS_write_role_protocol,
+       LWS_ROPS_encapsulation_parent,
+       LWS_ROPS_alpn_negotiated,
+       LWS_ROPS_close_via_role_protocol,
+       LWS_ROPS_close_role,
+       LWS_ROPS_close_kill_connection,
+       LWS_ROPS_destroy_role,
+       LWS_ROPS_adoption_bind,
+       LWS_ROPS_client_bind,
+       LWS_ROPS_issue_keepalive,
+} lws_rops_func_idx_t;
+
+struct lws_context_per_thread;
+
+struct lws_role_ops {
+       const char              *name;
+       const char              *alpn;
+
+       const lws_rops_t        *rops_table;
+       /**< the occupied role ops func ptrs */
+       uint8_t                 rops_idx[(LWS_COUNT_ROLE_OPS + 1) / 2];
+       /**< translates role index into .rops[] offset */
+
+       /*
+        * the callback reasons for adoption for client, server
+        * (just client applies if no concept of client or server)
+        */
+       uint8_t                 adoption_cb[2];
+       /*
+        * the callback reasons for adoption for client, server
+        * (just client applies if no concept of client or server)
+        */
+       uint8_t                 rx_cb[2];
+       /*
+        * the callback reasons for WRITEABLE for client, server
+        * (just client applies if no concept of client or server)
+        */
+       uint8_t                 writeable_cb[2];
+       /*
+        * the callback reasons for CLOSE for client, server
+        * (just client applies if no concept of client or server)
+        */
+       uint8_t                 close_cb[2];
+       /*
+        * the callback reasons for protocol bind for client, server
+        * (just client applies if no concept of client or server)
+        */
+       uint8_t                 protocol_bind_cb[2];
+       /*
+        * the callback reasons for protocol unbind for client, server
+        * (just client applies if no concept of client or server)
+        */
+       uint8_t                 protocol_unbind_cb[2];
+
+       uint8_t                 file_handle:1;
+       /* role operates on files not sockets */
+};
+
+#define lws_rops_fidx(_rops, fidx) \
+               ((fidx & 1) ? (_rops)->rops_idx[fidx / 2] & 0xf : \
+                             (_rops)->rops_idx[fidx / 2] >> 4)
+
+#define lws_rops_func_fidx(_rops, fidx) \
+               ((_rops)->rops_table[lws_rops_fidx(_rops, fidx) - 1])
+
+/* core roles */
+extern const struct lws_role_ops role_ops_raw_skt, role_ops_raw_file,
+                                role_ops_listen, role_ops_pipe,
+                                role_ops_netlink;
+
+/* bring in role private declarations */
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+ #include "private-lib-roles-http.h"
+#else
+ #define lwsi_role_http(wsi) (0)
+#endif
+
+#if defined(LWS_ROLE_H1)
+ #include "private-lib-roles-h1.h"
+#else
+ #define lwsi_role_h1(wsi) (0)
+#endif
+
+#if defined(LWS_ROLE_H2)
+ #include "private-lib-roles-h2.h"
+#else
+ #define lwsi_role_h2(wsi) (0)
+#endif
+
+#if defined(LWS_ROLE_WS)
+ #include "private-lib-roles-ws.h"
+#else
+ #define lwsi_role_ws(wsi) (0)
+#endif
+
+#if defined(LWS_ROLE_CGI)
+ #include "private-lib-roles-cgi.h"
+#else
+ #define lwsi_role_cgi(wsi) (0)
+#endif
+
+#if defined(LWS_ROLE_DBUS)
+ #include "private-lib-roles-dbus.h"
+#else
+ #define lwsi_role_dbus(wsi) (0)
+#endif
+
+#if defined(LWS_ROLE_RAW_PROXY)
+ #include "private-lib-roles-raw-proxy.h"
+#else
+ #define lwsi_role_raw_proxy(wsi) (0)
+#endif
+
+#if defined(LWS_ROLE_MQTT)
+ #include "mqtt/private-lib-roles-mqtt.h"
+#else
+ #define lwsi_role_mqtt(wsi) (0)
+#endif
+
+enum {
+       LWS_HP_RET_BAIL_OK,
+       LWS_HP_RET_BAIL_DIE,
+       LWS_HP_RET_USER_SERVICE,
+       LWS_HP_RET_DROP_POLLOUT,
+
+       LWS_HPI_RET_WSI_ALREADY_DIED,   /* we closed it */
+       LWS_HPI_RET_HANDLED,            /* no probs */
+       LWS_HPI_RET_PLEASE_CLOSE_ME,    /* close it for us */
+
+       LWS_UPG_RET_DONE,
+       LWS_UPG_RET_CONTINUE,
+       LWS_UPG_RET_BAIL
+};
+
+#define LWS_CONNECT_COMPLETION_GOOD (-99)
+
+int
+lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot);
+
+struct lws *
+lws_client_connect_4_established(struct lws *wsi, struct lws *wsi_piggyback,
+                                ssize_t plen);
+
+struct lws *
+lws_client_connect_3_connect(struct lws *wsi, const char *ads,
+                            const struct addrinfo *result, int n, void *opaque);
diff --git a/lib/roles/private.h b/lib/roles/private.h
deleted file mode 100644 (file)
index 55d9550..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h
- */
-
-typedef uint32_t lws_wsi_state_t;
-
-/*
- * The wsi->role_ops pointer decides almost everything about what role the wsi
- * will play, h2, raw, ws, etc.
- *
- * However there are a few additional flags needed that vary, such as if the
- * role is a client or server side, if it has that concept.  And the connection
- * fulfilling the role, has a separate dynamic state.
- *
- *   31           16 15      0
- *   [  role flags ] [ state ]
- *
- * The role flags part is generally invariant for the lifetime of the wsi,
- * although it can change if the connection role itself does, eg, if the
- * connection upgrades from H1 -> WS1 the role flags may be changed at that
- * point.
- *
- * The state part reflects the dynamic connection state, and the states are
- * reused between roles.
- *
- * None of the internal role or state representations are made available outside
- * of lws internals.  Even for lws internals, if you add stuff here, please keep
- * the constants inside this header only by adding necessary helpers here and
- * use the helpers in the actual code.  This is to ease any future refactors.
- *
- * Notice LWSIFR_ENCAP means we have a parent wsi that actually carries our
- * data as a stream inside a different protocol.
- */
-
-#define _RS 16
-
-#define LWSIFR_CLIENT          (0x1000 << _RS) /* client side */
-#define LWSIFR_SERVER          (0x2000 << _RS) /* server side */
-
-#define LWSIFR_P_ENCAP_H2      (0x0100 << _RS) /* we are encapsulated by h2 */
-
-enum lwsi_role {
-       LWSI_ROLE_MASK          =                            (0xffff << _RS),
-       LWSI_ROLE_ENCAP_MASK    =                            (0x0f00 << _RS),
-};
-
-#define lwsi_role(wsi) (wsi->wsistate & LWSI_ROLE_MASK)
-#if !defined (_DEBUG)
-#define lwsi_set_role(wsi, role) wsi->wsistate = \
-                               (wsi->wsistate & (~LWSI_ROLE_MASK)) | role
-#else
-void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role);
-#endif
-
-#define lwsi_role_client(wsi) (!!(wsi->wsistate & LWSIFR_CLIENT))
-#define lwsi_role_server(wsi) (!!(wsi->wsistate & LWSIFR_SERVER))
-#define lwsi_role_h2_ENCAPSULATION(wsi) \
-               ((wsi->wsistate & LWSI_ROLE_ENCAP_MASK) == LWSIFR_P_ENCAP_H2)
-
-/* Pollout wants a callback in this state */
-#define LWSIFS_POCB            (0x100)
-/* Before any protocol connection was established */
-#define LWSIFS_NOT_EST         (0x200)
-
-enum lwsi_state {
-
-       /* Phase 1: pre-transport */
-
-       LRS_UNCONNECTED                         = LWSIFS_NOT_EST | 0,
-       LRS_WAITING_CONNECT                     = LWSIFS_NOT_EST | 1,
-
-       /* Phase 2: establishing intermediaries on top of transport */
-
-       LRS_WAITING_PROXY_REPLY                 = LWSIFS_NOT_EST | 2,
-       LRS_WAITING_SSL                         = LWSIFS_NOT_EST | 3,
-       LRS_WAITING_SOCKS_GREETING_REPLY        = LWSIFS_NOT_EST | 4,
-       LRS_WAITING_SOCKS_CONNECT_REPLY         = LWSIFS_NOT_EST | 5,
-       LRS_WAITING_SOCKS_AUTH_REPLY            = LWSIFS_NOT_EST | 6,
-
-       /* Phase 3: establishing tls tunnel */
-
-       LRS_SSL_INIT                            = LWSIFS_NOT_EST | 7,
-       LRS_SSL_ACK_PENDING                     = LWSIFS_NOT_EST | 8,
-       LRS_PRE_WS_SERVING_ACCEPT               = LWSIFS_NOT_EST | 9,
-
-       /* Phase 4: connected */
-
-       LRS_WAITING_SERVER_REPLY                = LWSIFS_NOT_EST | 10,
-       LRS_H2_AWAIT_PREFACE                    = LWSIFS_NOT_EST | 11,
-       LRS_H2_AWAIT_SETTINGS                   = LWSIFS_NOT_EST |
-                                                 LWSIFS_POCB | 12,
-
-       /* Phase 5: protocol logically established */
-
-       LRS_H2_CLIENT_SEND_SETTINGS             = LWSIFS_POCB | 13,
-       LRS_H2_WAITING_TO_SEND_HEADERS          = LWSIFS_POCB | 14,
-       LRS_DEFERRING_ACTION                    = LWSIFS_POCB | 15,
-       LRS_IDLING                              = 16,
-       LRS_H1C_ISSUE_HANDSHAKE                 = 17,
-       LRS_H1C_ISSUE_HANDSHAKE2                = 18,
-       LRS_ISSUE_HTTP_BODY                     = 19,
-       LRS_ISSUING_FILE                        = 20,
-       LRS_HEADERS                             = 21,
-       LRS_BODY                                = 22,
-       LRS_DISCARD_BODY                        = 31,
-       LRS_ESTABLISHED                         = LWSIFS_POCB | 23,
-       /* we are established, but we have embarked on serving a single
-        * transaction.  Other transaction input may be pending, but we will
-        * not service it while we are busy dealing with the current
-        * transaction.
-        *
-        * When we complete the current transaction, we would reset our state
-        * back to ESTABLISHED and start to process the next transaction.
-        */
-       LRS_DOING_TRANSACTION                   = LWSIFS_POCB | 24,
-
-       /* Phase 6: finishing */
-
-       LRS_WAITING_TO_SEND_CLOSE               = LWSIFS_POCB | 25,
-       LRS_RETURNED_CLOSE                      = LWSIFS_POCB | 26,
-       LRS_AWAITING_CLOSE_ACK                  = LWSIFS_POCB | 27,
-       LRS_FLUSHING_BEFORE_CLOSE               = LWSIFS_POCB | 28,
-       LRS_SHUTDOWN                            = 29,
-
-       /* Phase 7: dead */
-
-       LRS_DEAD_SOCKET                         = 30,
-
-       LRS_MASK                                = 0xffff
-};
-
-#define lwsi_state(wsi) ((enum lwsi_state)(wsi->wsistate & LRS_MASK))
-#define lwsi_state_PRE_CLOSE(wsi) \
-               ((enum lwsi_state)(wsi->wsistate_pre_close & LRS_MASK))
-#define lwsi_state_est(wsi) (!(wsi->wsistate & LWSIFS_NOT_EST))
-#define lwsi_state_est_PRE_CLOSE(wsi) \
-               (!(wsi->wsistate_pre_close & LWSIFS_NOT_EST))
-#define lwsi_state_can_handle_POLLOUT(wsi) (wsi->wsistate & LWSIFS_POCB)
-#if !defined (_DEBUG)
-#define lwsi_set_state(wsi, lrs) wsi->wsistate = \
-                         (wsi->wsistate & (~LRS_MASK)) | lrs
-#else
-void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs);
-#endif
-
-#define _LWS_ADOPT_FINISH (1 << 24)
-
-/*
- * internal role-specific ops
- */
-struct lws_context_per_thread;
-struct lws_role_ops {
-       const char *name;
-       const char *alpn;
-       /*
-        * After http headers have parsed, this is the last chance for a role
-        * to upgrade the connection to something else using the headers.
-        * ws-over-h2 is upgraded from h2 like this.
-        */
-       int (*check_upgrades)(struct lws *wsi);
-       /* role-specific context init during context creation */
-       int (*init_context)(struct lws_context *context,
-                           const struct lws_context_creation_info *info);
-       /* role-specific per-vhost init during vhost creation */
-       int (*init_vhost)(struct lws_vhost *vh,
-                         const struct lws_context_creation_info *info);
-       /* role-specific per-vhost destructor during vhost destroy */
-       int (*destroy_vhost)(struct lws_vhost *vh);
-       /* generic 1Hz callback for the role itself */
-       int (*periodic_checks)(struct lws_context *context, int tsi,
-                              time_t now);
-       /* chance for the role to force POLLIN without network activity */
-       int (*service_flag_pending)(struct lws_context *context, int tsi);
-       /* an fd using this role has POLLIN signalled */
-       int (*handle_POLLIN)(struct lws_context_per_thread *pt, struct lws *wsi,
-                            struct lws_pollfd *pollfd);
-       /* an fd using the role wanted a POLLOUT callback and now has it */
-       int (*handle_POLLOUT)(struct lws *wsi);
-       /* perform user pollout */
-       int (*perform_user_POLLOUT)(struct lws *wsi);
-       /* do effective callback on writeable */
-       int (*callback_on_writable)(struct lws *wsi);
-       /* connection-specific tx credit in bytes */
-       lws_fileofs_t (*tx_credit)(struct lws *wsi);
-       /* role-specific write formatting */
-       int (*write_role_protocol)(struct lws *wsi, unsigned char *buf,
-                                  size_t len, enum lws_write_protocol *wp);
-
-       /* get encapsulation parent */
-       struct lws * (*encapsulation_parent)(struct lws *wsi);
-
-       /* role-specific destructor */
-       int (*alpn_negotiated)(struct lws *wsi, const char *alpn);
-
-       /* chance for the role to handle close in the protocol */
-       int (*close_via_role_protocol)(struct lws *wsi,
-                                      enum lws_close_status reason);
-       /* role-specific close processing */
-       int (*close_role)(struct lws_context_per_thread *pt, struct lws *wsi);
-       /* role-specific connection close processing */
-       int (*close_kill_connection)(struct lws *wsi,
-                                    enum lws_close_status reason);
-       /* role-specific destructor */
-       int (*destroy_role)(struct lws *wsi);
-
-       /* role-specific socket-adopt */
-       int (*adoption_bind)(struct lws *wsi, int type, const char *prot);
-       /* role-specific client-bind:
-        * ret 1 = bound, 0 = not bound, -1 = fail out
-        * i may be NULL, indicating client_bind is being called after
-        * a successful bind earlier, to finalize the binding.  In that
-        * case ret 0 = OK, 1 = fail, wsi needs freeing, -1 = fail, wsi freed */
-       int (*client_bind)(struct lws *wsi,
-                          const struct lws_client_connect_info *i);
-
-       /*
-        * the callback reasons for adoption for client, server
-        * (just client applies if no concept of client or server)
-        */
-       uint16_t adoption_cb[2];
-       /*
-        * the callback reasons for adoption for client, server
-        * (just client applies if no concept of client or server)
-        */
-       uint16_t rx_cb[2];
-       /*
-        * the callback reasons for WRITEABLE for client, server
-        * (just client applies if no concept of client or server)
-        */
-       uint16_t writeable_cb[2];
-       /*
-        * the callback reasons for CLOSE for client, server
-        * (just client applies if no concept of client or server)
-        */
-       uint16_t close_cb[2];
-       /*
-        * the callback reasons for protocol bind for client, server
-        * (just client applies if no concept of client or server)
-        */
-       uint16_t protocol_bind_cb[2];
-       /*
-        * the callback reasons for protocol unbind for client, server
-        * (just client applies if no concept of client or server)
-        */
-       uint16_t protocol_unbind_cb[2];
-
-       unsigned int file_handle:1; /* role operates on files not sockets */
-};
-
-/* core roles */
-extern struct lws_role_ops role_ops_raw_skt, role_ops_raw_file, role_ops_listen,
-                          role_ops_pipe;
-
-/* bring in role private declarations */
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- #include "roles/http/private.h"
-#else
- #define lwsi_role_http(wsi) (0)
-#endif
-
-#if defined(LWS_ROLE_H1)
- #include "roles/h1/private.h"
-#else
- #define lwsi_role_h1(wsi) (0)
-#endif
-
-#if defined(LWS_ROLE_H2)
- #include "roles/h2/private.h"
-#else
- #define lwsi_role_h2(wsi) (0)
-#endif
-
-#if defined(LWS_ROLE_WS)
- #include "roles/ws/private.h"
-#else
- #define lwsi_role_ws(wsi) (0)
-#endif
-
-#if defined(LWS_ROLE_CGI)
- #include "roles/cgi/private.h"
-#else
- #define lwsi_role_cgi(wsi) (0)
-#endif
-
-#if defined(LWS_ROLE_DBUS)
- #include "roles/dbus/private.h"
-#else
- #define lwsi_role_dbus(wsi) (0)
-#endif
-
-#if defined(LWS_ROLE_RAW_PROXY)
- #include "roles/raw-proxy/private.h"
-#else
- #define lwsi_role_raw_proxy(wsi) (0)
-#endif
-
-enum {
-       LWS_HP_RET_BAIL_OK,
-       LWS_HP_RET_BAIL_DIE,
-       LWS_HP_RET_USER_SERVICE,
-
-       LWS_HPI_RET_WSI_ALREADY_DIED,   /* we closed it */
-       LWS_HPI_RET_HANDLED,            /* no probs */
-       LWS_HPI_RET_PLEASE_CLOSE_ME,    /* close it for us */
-
-       LWS_UPG_RET_DONE,
-       LWS_UPG_RET_CONTINUE,
-       LWS_UPG_RET_BAIL
-};
-
-int
-lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot);
-
-struct lws *
-lws_client_connect_3(struct lws *wsi, struct lws *wsi_piggyback, ssize_t plen);
diff --git a/lib/roles/raw-file/CMakeLists.txt b/lib/roles/raw-file/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4d9834c
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES roles/raw-file/ops-raw-file.c)
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
\ No newline at end of file
index e19bd2a..0f75327 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 static int
 rops_handle_POLLIN_raw_file(struct lws_context_per_thread *pt, struct lws *wsi,
@@ -28,31 +31,31 @@ rops_handle_POLLIN_raw_file(struct lws_context_per_thread *pt, struct lws *wsi,
        int n;
 
        if (pollfd->revents & LWS_POLLOUT) {
-               n = lws_callback_as_writeable(wsi);
                if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
-                       lwsl_info("failed at set pollfd\n");
+                       lwsl_wsi_info(wsi, "failed at set pollfd");
                        return LWS_HPI_RET_WSI_ALREADY_DIED;
                }
+               n = lws_callback_as_writeable(wsi);
                if (n)
                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
        }
 
        if (pollfd->revents & LWS_POLLIN) {
-               if (user_callback_handle_rxflow(wsi->protocol->callback,
+               if (user_callback_handle_rxflow(wsi->a.protocol->callback,
                                                wsi, LWS_CALLBACK_RAW_RX_FILE,
                                                wsi->user_space, NULL, 0)) {
-                       lwsl_debug("raw rx callback closed it\n");
+                       lwsl_wsi_debug(wsi, "raw rx callback closed it");
                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
                }
        }
 
        if (pollfd->revents & LWS_POLLHUP)
-               return LWS_HPI_RET_PLEASE_CLOSE_ME;
+               if (!(pollfd->revents & LWS_POLLIN))
+                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
 
        return LWS_HPI_RET_HANDLED;
 }
 
-//#if !defined(LWS_NO_SERVER)
 static int
 rops_adoption_bind_raw_file(struct lws *wsi, int type, const char *vh_prot_name)
 {
@@ -64,45 +67,50 @@ rops_adoption_bind_raw_file(struct lws *wsi, int type, const char *vh_prot_name)
        lws_role_transition(wsi, 0, LRS_ESTABLISHED, &role_ops_raw_file);
 
        if (!vh_prot_name) {
-               if (wsi->vhost->default_protocol_index >=
-                   wsi->vhost->count_protocols)
+               if (wsi->a.vhost->default_protocol_index >=
+                   wsi->a.vhost->count_protocols)
                        return 0;
 
-               wsi->protocol = &wsi->vhost->protocols[
-                                       wsi->vhost->default_protocol_index];
+               wsi->a.protocol = &wsi->a.vhost->protocols[
+                                       wsi->a.vhost->default_protocol_index];
        }
 
        return 1; /* bound */
 }
-//#endif
 
-struct lws_role_ops role_ops_raw_file = {
+static const lws_rops_t rops_table_raw_file[] = {
+       /*  1 */ { .handle_POLLIN       = rops_handle_POLLIN_raw_file },
+       /*  2 */ { .adoption_bind       = rops_adoption_bind_raw_file },
+};
+
+const struct lws_role_ops role_ops_raw_file = {
        /* role name */                 "raw-file",
        /* alpn id */                   NULL,
-       /* check_upgrades */            NULL,
-       /* init_context */              NULL,
-       /* init_vhost */                NULL,
-       /* destroy_vhost */             NULL,
-       /* periodic_checks */           NULL,
-       /* service_flag_pending */      NULL,
-       /* handle_POLLIN */             rops_handle_POLLIN_raw_file,
-       /* handle_POLLOUT */            NULL,
-       /* perform_user_POLLOUT */      NULL,
-       /* callback_on_writable */      NULL,
-       /* tx_credit */                 NULL,
-       /* write_role_protocol */       NULL,
-       /* encapsulation_parent */      NULL,
-       /* alpn_negotiated */           NULL,
-       /* close_via_role_protocol */   NULL,
-       /* close_role */                NULL,
-       /* close_kill_connection */     NULL,
-       /* destroy_role */              NULL,
-//#if !defined(LWS_NO_SERVER)
-       /* adoption_bind */             rops_adoption_bind_raw_file,
-//#else
-//                                     NULL,
-//#endif
-       /* client_bind */               NULL,
+
+       /* rops_table */                rops_table_raw_file,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x00,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x01,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x00,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x00,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x00,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x00,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x00,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0x02,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x00,
+                                       },
+
        /* adoption_cb clnt, srv */     { LWS_CALLBACK_RAW_ADOPT_FILE,
                                          LWS_CALLBACK_RAW_ADOPT_FILE },
        /* rx_cb clnt, srv */           { LWS_CALLBACK_RAW_RX_FILE,
diff --git a/lib/roles/raw-proxy/CMakeLists.txt b/lib/roles/raw-proxy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..64f4eef
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+               roles/raw-proxy/ops-raw-proxy.c)
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+
index 9deb9c1..cac95a6 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 static int
 rops_handle_POLLIN_raw_proxy(struct lws_context_per_thread *pt, struct lws *wsi,
@@ -45,13 +48,21 @@ rops_handle_POLLIN_raw_proxy(struct lws_context_per_thread *pt, struct lws *wsi,
                return LWS_HPI_RET_HANDLED;
        }
 
+       if (lwsi_state(wsi) == LRS_WAITING_CONNECT)
+               goto try_pollout;
+
        if ((pollfd->revents & pollfd->events & LWS_POLLIN) &&
            /* any tunnel has to have been established... */
            lwsi_state(wsi) != LRS_SSL_ACK_PENDING &&
            !(wsi->favoured_pollin &&
              (pollfd->revents & pollfd->events & LWS_POLLOUT))) {
 
-               buffered = lws_buflist_aware_read(pt, wsi, &ebuf);
+               ebuf.token = NULL;
+               ebuf.len = 0;
+               buffered = lws_buflist_aware_read(pt, wsi, &ebuf, 1, __func__);
+               if (buffered < 0)
+                       goto fail;
+
                switch (ebuf.len) {
                case 0:
                        lwsl_info("%s: read 0 len\n", __func__);
@@ -72,18 +83,19 @@ rops_handle_POLLIN_raw_proxy(struct lws_context_per_thread *pt, struct lws *wsi,
                case LWS_SSL_CAPABLE_MORE_SERVICE:
                        goto try_pollout;
                }
-               n = user_callback_handle_rxflow(wsi->protocol->callback,
+               n = user_callback_handle_rxflow(wsi->a.protocol->callback,
                                                wsi, lwsi_role_client(wsi) ?
                                                 LWS_CALLBACK_RAW_PROXY_CLI_RX :
                                                 LWS_CALLBACK_RAW_PROXY_SRV_RX,
                                                wsi->user_space, ebuf.token,
-                                               ebuf.len);
+                                               (size_t)ebuf.len);
                if (n < 0) {
                        lwsl_info("LWS_CALLBACK_RAW_PROXY_*_RX fail\n");
                        goto fail;
                }
 
-               if (lws_buflist_aware_consume(wsi, &ebuf, ebuf.len, buffered))
+               if (lws_buflist_aware_finished_consuming(wsi, &ebuf, ebuf.len,
+                                                        buffered, __func__))
                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
        } else
                if (wsi->favoured_pollin &&
@@ -101,8 +113,8 @@ try_pollout:
                return LWS_HPI_RET_PLEASE_CLOSE_ME;
        }
 
-#if !defined(LWS_NO_CLIENT)
-       if (lws_client_socket_service(wsi, pollfd, NULL))
+#if defined(LWS_WITH_CLIENT)
+       if (lws_http_client_socket_service(wsi, pollfd))
                return LWS_HPI_RET_WSI_ALREADY_DIED;
 #endif
 
@@ -123,22 +135,24 @@ rops_adoption_bind_raw_proxy(struct lws *wsi, int type,
            (!(type & LWS_ADOPT_FLAG_RAW_PROXY)) || (type & _LWS_ADOPT_FINISH))
                return 0; /* no match */
 
+#if defined(LWS_WITH_UDP)
        if (type & LWS_ADOPT_FLAG_UDP)
                /*
                 * these can be >128 bytes, so just alloc for UDP
                 */
                wsi->udp = lws_malloc(sizeof(*wsi->udp), "udp struct");
+#endif
 
        lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ?
                                    LRS_SSL_INIT : LRS_ESTABLISHED,
                            &role_ops_raw_proxy);
 
        if (vh_prot_name)
-               lws_bind_protocol(wsi, wsi->protocol, __func__);
+               lws_bind_protocol(wsi, wsi->a.protocol, __func__);
        else
                /* this is the only time he will transition */
                lws_bind_protocol(wsi,
-                       &wsi->vhost->protocols[wsi->vhost->raw_protocol_index],
+                       &wsi->a.vhost->protocols[wsi->a.vhost->raw_protocol_index],
                        __func__);
 
        return 1; /* bound */
@@ -152,7 +166,7 @@ rops_client_bind_raw_proxy(struct lws *wsi,
 
                /* finalize */
 
-               if (!wsi->user_space && wsi->stash->method)
+               if (!wsi->user_space && wsi->stash->cis[CIS_METHOD])
                        if (lws_ensure_user_space(wsi))
                                return 1;
 
@@ -161,8 +175,9 @@ rops_client_bind_raw_proxy(struct lws *wsi,
 
        /* we are a fallback if nothing else matched */
 
-//     lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
-//                         &role_ops_raw_proxy);
+       if (i->local_protocol_name && !strcmp(i->local_protocol_name, "raw-proxy"))
+               lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
+                                   &role_ops_raw_proxy);
 
        return 0;
 }
@@ -179,29 +194,42 @@ rops_handle_POLLOUT_raw_proxy(struct lws *wsi)
        return LWS_HP_RET_BAIL_OK;
 }
 
-struct lws_role_ops role_ops_raw_proxy = {
+static const lws_rops_t rops_table_raw_proxy[] = {
+       /*  1 */ { .handle_POLLIN       = rops_handle_POLLIN_raw_proxy },
+       /*  2 */ { .handle_POLLOUT      = rops_handle_POLLOUT_raw_proxy },
+       /*  3 */ { .adoption_bind       = rops_adoption_bind_raw_proxy },
+       /*  4 */ { .client_bind         = rops_client_bind_raw_proxy },
+};
+
+
+const struct lws_role_ops role_ops_raw_proxy = {
        /* role name */                 "raw-proxy",
        /* alpn id */                   NULL,
-       /* check_upgrades */            NULL,
-       /* init_context */              NULL,
-       /* init_vhost */                NULL,
-       /* destroy_vhost */             NULL,
-       /* periodic_checks */           NULL,
-       /* service_flag_pending */      NULL,
-       /* handle_POLLIN */             rops_handle_POLLIN_raw_proxy,
-       /* handle_POLLOUT */            rops_handle_POLLOUT_raw_proxy,
-       /* perform_user_POLLOUT */      NULL,
-       /* callback_on_writable */      NULL,
-       /* tx_credit */                 NULL,
-       /* write_role_protocol */       NULL,
-       /* encapsulation_parent */      NULL,
-       /* alpn_negotiated */           NULL,
-       /* close_via_role_protocol */   NULL,
-       /* close_role */                NULL,
-       /* close_kill_connection */     NULL,
-       /* destroy_role */              NULL,
-       /* adoption_bind */             rops_adoption_bind_raw_proxy,
-       /* client_bind */               rops_client_bind_raw_proxy,
+
+       /* rops_table */                rops_table_raw_proxy,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x00,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x01,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x20,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x00,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x00,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x00,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x00,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0x03,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x40,
+                                       },
+
        /* adoption_cb clnt, srv */     { LWS_CALLBACK_RAW_PROXY_CLI_ADOPT,
                                          LWS_CALLBACK_RAW_PROXY_SRV_ADOPT },
        /* rx_cb clnt, srv */           { LWS_CALLBACK_RAW_PROXY_CLI_RX,
diff --git a/lib/roles/raw-proxy/private-lib-roles-raw-proxy.h b/lib/roles/raw-proxy/private-lib-roles-raw-proxy.h
new file mode 100644 (file)
index 0000000..cae5a34
--- /dev/null
@@ -0,0 +1,44 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *  This is included from private-lib-core.h if LWS_ROLE_RAW_PROXY
+ */
+
+extern const struct lws_role_ops role_ops_raw_proxy;
+
+#define lwsi_role_raw_proxy(wsi) (wsi->role_ops == &role_ops_raw_proxy)
+
+#if 0
+struct lws_vhost_role_ws {
+       const struct lws_extension *extensions;
+};
+
+struct lws_pt_role_ws {
+       struct lws *rx_draining_ext_list;
+       struct lws *tx_draining_ext_list;
+};
+
+struct _lws_raw_proxy_related {
+       struct lws *wsi_onward;
+};
+#endif
diff --git a/lib/roles/raw-proxy/private.h b/lib/roles/raw-proxy/private.h
deleted file mode 100644 (file)
index 6f169d9..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  This is included from core/private.h if LWS_ROLE_RAW_PROXY
- */
-
-extern struct lws_role_ops role_ops_raw_proxy;
-
-#define lwsi_role_raw_proxy(wsi) (wsi->role_ops == &role_ops_raw_proxy)
-
-#if 0
-struct lws_vhost_role_ws {
-       const struct lws_extension *extensions;
-};
-
-struct lws_pt_role_ws {
-       struct lws *rx_draining_ext_list;
-       struct lws *tx_draining_ext_list;
-};
-
-struct _lws_raw_proxy_related {
-       struct lws *wsi_onward;
-};
-#endif
diff --git a/lib/roles/raw-skt/CMakeLists.txt b/lib/roles/raw-skt/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d618bb0
--- /dev/null
@@ -0,0 +1,46 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       roles/raw-skt/ops-raw-skt.c)
+
+if (LWS_WITH_ABSTRACT)
+       list(APPEND SOURCES
+               abstract/transports/raw-skt.c)
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
index ab3429c..fd4fd34 100644 (file)
@@ -1,32 +1,38 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 static int
 rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi,
                           struct lws_pollfd *pollfd)
 {
+#if defined(LWS_WITH_SOCKS5)
+       const char *cce = NULL;
+#endif
        struct lws_tokens ebuf;
-       int n, buffered;
+       int n = 0, buffered = 0;
 
        /* pending truncated sends have uber priority */
 
@@ -46,15 +52,15 @@ rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi,
        }
 
 
-#if !defined(LWS_NO_SERVER)
+#if defined(LWS_WITH_SERVER)
        if (!lwsi_role_client(wsi) &&  lwsi_state(wsi) != LRS_ESTABLISHED) {
 
-               lwsl_debug("%s: %p: wsistate 0x%x\n", __func__, wsi,
-                          wsi->wsistate);
+               lwsl_wsi_debug(wsi, "wsistate 0x%x\n", (int)wsi->wsistate);
 
                if (lwsi_state(wsi) != LRS_SSL_INIT)
                        if (lws_server_socket_service_ssl(wsi,
-                                                         LWS_SOCK_INVALID))
+                                                         LWS_SOCK_INVALID,
+                               !!(pollfd->revents & pollfd->events & LWS_POLLIN)))
                                return LWS_HPI_RET_PLEASE_CLOSE_ME;
 
                return LWS_HPI_RET_HANDLED;
@@ -62,58 +68,118 @@ rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi,
 #endif
 
        if ((pollfd->revents & pollfd->events & LWS_POLLIN) &&
-           /* any tunnel has to have been established... */
-           lwsi_state(wsi) != LRS_SSL_ACK_PENDING &&
            !(wsi->favoured_pollin &&
              (pollfd->revents & pollfd->events & LWS_POLLOUT))) {
 
-               buffered = lws_buflist_aware_read(pt, wsi, &ebuf);
-               switch (ebuf.len) {
-               case 0:
-                       lwsl_info("%s: read 0 len\n", __func__);
-                       wsi->seen_zero_length_recv = 1;
-                       if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
+               lwsl_wsi_debug(wsi, "POLLIN: state 0x%x", lwsi_state(wsi));
+
+               switch (lwsi_state(wsi)) {
+
+                   /* any tunnel has to have been established... */
+               case LRS_SSL_ACK_PENDING:
+                       goto nope;
+                   /* we are actually connected */
+               case LRS_WAITING_CONNECT:
+                       goto nope;
+
+#if defined(LWS_WITH_SOCKS5)
+
+               /* SOCKS Greeting Reply */
+               case LRS_WAITING_SOCKS_GREETING_REPLY:
+               case LRS_WAITING_SOCKS_AUTH_REPLY:
+               case LRS_WAITING_SOCKS_CONNECT_REPLY:
+
+                       switch (lws_socks5c_handle_state(wsi, pollfd, &cce)) {
+                       case LW5CHS_RET_RET0:
+                               goto nope;
+                       case LW5CHS_RET_BAIL3:
+                               lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
+                               goto fail;
+                       case LW5CHS_RET_STARTHS:
+                               lwsi_set_state(wsi, LRS_ESTABLISHED);
+                               lws_client_connect_4_established(wsi, NULL, 0);
+
+                               /*
+                                * Now we got the socks5 connection, we need to
+                                * go down the tls path on it now if that's what
+                                * we want
+                                */
+                               goto post_rx;
+
+                       default:
+                               break;
+                       }
+                       goto post_rx;
+#endif
+               default:
+                       ebuf.token = NULL;
+                       ebuf.len = 0;
+
+                       buffered = lws_buflist_aware_read(pt, wsi, &ebuf, 1, __func__);
+                       switch (ebuf.len) {
+                       case 0:
+                               if (wsi->unix_skt)
+                                       break;
+                               lwsl_wsi_info(wsi, "read 0 len");
+                               wsi->seen_zero_length_recv = 1;
+                               if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
+                                       goto fail;
+
+                               /*
+                                * we need to go to fail here, since it's the only
+                                * chance we get to understand that the socket has
+                                * closed
+                                */
+                               // goto try_pollout;
                                goto fail;
 
-                       /*
-                        * we need to go to fail here, since it's the only
-                        * chance we get to understand that the socket has
-                        * closed
-                        */
-                       // goto try_pollout;
-                       goto fail;
+                       case LWS_SSL_CAPABLE_ERROR:
+                               goto fail;
+                       case LWS_SSL_CAPABLE_MORE_SERVICE:
+                               goto try_pollout;
+                       }
+
+#if defined(LWS_WITH_UDP)
+                       if (lws_fi(&wsi->fic, "udp_rx_loss")) {
+                               n = ebuf.len;
+                               goto post_rx;
+                       }
+#endif
 
-               case LWS_SSL_CAPABLE_ERROR:
-                       goto fail;
-               case LWS_SSL_CAPABLE_MORE_SERVICE:
-                       goto try_pollout;
-               }
+                       n = user_callback_handle_rxflow(wsi->a.protocol->callback,
+                                                       wsi, LWS_CALLBACK_RAW_RX,
+                                                       wsi->user_space, ebuf.token,
+                                                       (unsigned int)ebuf.len);
+#if defined(LWS_WITH_UDP) || defined(LWS_WITH_SOCKS5)
+post_rx:
+#endif
+                       if (n < 0) {
+                               lwsl_wsi_info(wsi, "LWS_CALLBACK_RAW_RX_fail");
+                               goto fail;
+                       }
 
-               n = user_callback_handle_rxflow(wsi->protocol->callback,
-                                               wsi, LWS_CALLBACK_RAW_RX,
-                                               wsi->user_space, ebuf.token,
-                                               ebuf.len);
-               if (n < 0) {
-                       lwsl_info("LWS_CALLBACK_RAW_RX_fail\n");
-                       goto fail;
-               }
+                       if (lws_buflist_aware_finished_consuming(wsi, &ebuf, ebuf.len,
+                                                                buffered, __func__))
+                               return LWS_HPI_RET_PLEASE_CLOSE_ME;
 
-               if (lws_buflist_aware_consume(wsi, &ebuf, ebuf.len, buffered))
-                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
-       } else
-               if (wsi->favoured_pollin &&
-                   (pollfd->revents & pollfd->events & LWS_POLLOUT))
-                       /* we balanced the last favouring of pollin */
-                       wsi->favoured_pollin = 0;
+                       goto try_pollout;
+               }
+       }
+nope:
+       if (wsi->favoured_pollin &&
+           (pollfd->revents & pollfd->events & LWS_POLLOUT))
+               /* we balanced the last favouring of pollin */
+               wsi->favoured_pollin = 0;
 
 try_pollout:
 
        if (!(pollfd->revents & LWS_POLLOUT))
                return LWS_HPI_RET_HANDLED;
 
-#if !defined(LWS_WITHOUT_CLIENT)
-       if (lwsi_state(wsi) == LRS_WAITING_CONNECT)
-               lws_client_connect_3(wsi, NULL, 0);
+#if defined(LWS_WITH_CLIENT)
+       if (lwsi_state(wsi) == LRS_WAITING_CONNECT &&
+           !lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL))
+               return LWS_HPI_RET_WSI_ALREADY_DIED;
 #endif
 
        /* one shot */
@@ -125,19 +191,7 @@ try_pollout:
        /* clear back-to-back write detection */
        wsi->could_have_pending = 0;
 
-       lws_stats_bump(pt, LWSSTATS_C_WRITEABLE_CB, 1);
-#if defined(LWS_WITH_STATS)
-       if (wsi->active_writable_req_us) {
-               uint64_t ul = lws_now_usecs() -
-                               wsi->active_writable_req_us;
-
-               lws_stats_bump(pt, LWSSTATS_US_WRITABLE_DELAY_AVG, ul);
-               lws_stats_max(pt,
-                         LWSSTATS_US_WORST_WRITABLE_DELAY, ul);
-               wsi->active_writable_req_us = 0;
-       }
-#endif
-       n = user_callback_handle_rxflow(wsi->protocol->callback,
+       n = user_callback_handle_rxflow(wsi->a.protocol->callback,
                        wsi, LWS_CALLBACK_RAW_WRITEABLE,
                        wsi->user_space, NULL, 0);
        if (n < 0) {
@@ -153,39 +207,46 @@ fail:
        return LWS_HPI_RET_WSI_ALREADY_DIED;
 }
 
-#if !defined(LWS_NO_SERVER)
+#if defined(LWS_WITH_SERVER)
 static int
 rops_adoption_bind_raw_skt(struct lws *wsi, int type, const char *vh_prot_name)
 {
+
+       // lwsl_notice("%s: bind type %d\n", __func__, type);
+
        /* no http but socket... must be raw skt */
        if ((type & LWS_ADOPT_HTTP) || !(type & LWS_ADOPT_SOCKET) ||
-           (type & _LWS_ADOPT_FINISH))
+           ((type & _LWS_ADOPT_FINISH) && (!(type & LWS_ADOPT_FLAG_UDP))))
                return 0; /* no match */
 
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
-       if (type & LWS_ADOPT_FLAG_UDP)
+#if defined(LWS_WITH_UDP)
+       if ((type & LWS_ADOPT_FLAG_UDP) && !wsi->udp) {
                /*
                 * these can be >128 bytes, so just alloc for UDP
                 */
                wsi->udp = lws_malloc(sizeof(*wsi->udp), "udp struct");
+               if (!wsi->udp)
+                       return 0;
+               memset(wsi->udp, 0, sizeof(*wsi->udp));
+       }
 #endif
 
        lws_role_transition(wsi, 0, (type & LWS_ADOPT_ALLOW_SSL) ? LRS_SSL_INIT :
                                LRS_ESTABLISHED, &role_ops_raw_skt);
 
        if (vh_prot_name)
-               lws_bind_protocol(wsi, wsi->protocol, __func__);
+               lws_bind_protocol(wsi, wsi->a.protocol, __func__);
        else
                /* this is the only time he will transition */
                lws_bind_protocol(wsi,
-                       &wsi->vhost->protocols[wsi->vhost->raw_protocol_index],
+                       &wsi->a.vhost->protocols[wsi->a.vhost->raw_protocol_index],
                        __func__);
 
        return 1; /* bound */
 }
 #endif
 
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
 static int
 rops_client_bind_raw_skt(struct lws *wsi,
                         const struct lws_client_connect_info *i)
@@ -194,7 +255,7 @@ rops_client_bind_raw_skt(struct lws *wsi,
 
                /* finalize */
 
-               if (!wsi->user_space && wsi->stash->method)
+               if (!wsi->user_space && wsi->stash->cis[CIS_METHOD])
                        if (lws_ensure_user_space(wsi))
                                return 1;
 
@@ -203,44 +264,64 @@ rops_client_bind_raw_skt(struct lws *wsi,
 
        /* we are a fallback if nothing else matched */
 
-       lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
+       if (!i->local_protocol_name ||
+           strcmp(i->local_protocol_name, "raw-proxy"))
+               lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED,
                            &role_ops_raw_skt);
 
        return 1; /* matched */
 }
 #endif
 
-struct lws_role_ops role_ops_raw_skt = {
+static const lws_rops_t rops_table_raw_skt[] = {
+       /*  1 */ { .handle_POLLIN         = rops_handle_POLLIN_raw_skt },
+#if defined(LWS_WITH_SERVER)
+       /*  2 */ { .adoption_bind         = rops_adoption_bind_raw_skt },
+#else
+       /*  2 */ { .adoption_bind         = NULL },
+#endif
+#if defined(LWS_WITH_CLIENT)
+       /*  3 */ { .client_bind           = rops_client_bind_raw_skt },
+#endif
+};
+
+const struct lws_role_ops role_ops_raw_skt = {
        /* role name */                 "raw-skt",
        /* alpn id */                   NULL,
-       /* check_upgrades */            NULL,
-       /* init_context */              NULL,
-       /* init_vhost */                NULL,
-       /* destroy_vhost */             NULL,
-       /* periodic_checks */           NULL,
-       /* service_flag_pending */      NULL,
-       /* handle_POLLIN */             rops_handle_POLLIN_raw_skt,
-       /* handle_POLLOUT */            NULL,
-       /* perform_user_POLLOUT */      NULL,
-       /* callback_on_writable */      NULL,
-       /* tx_credit */                 NULL,
-       /* write_role_protocol */       NULL,
-       /* encapsulation_parent */      NULL,
-       /* alpn_negotiated */           NULL,
-       /* close_via_role_protocol */   NULL,
-       /* close_role */                NULL,
-       /* close_kill_connection */     NULL,
-       /* destroy_role */              NULL,
-#if !defined(LWS_NO_SERVER)
-       /* adoption_bind */             rops_adoption_bind_raw_skt,
+
+       /* rops_table */                rops_table_raw_skt,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x00,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x00,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x01,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x00,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x00,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x00,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x00,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x00,
+         /* LWS_ROPS_destroy_role */
+#if defined(LWS_WITH_SERVER)
+         /* LWS_ROPS_adoption_bind */                  0x02,
 #else
-                                       NULL,
+         /* LWS_ROPS_adoption_bind */                  0x00,
 #endif
-#if !defined(LWS_NO_CLIENT)
-       /* client_bind */               rops_client_bind_raw_skt,
+#if defined(LWS_WITH_CLIENT)
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x30,
 #else
-                                       NULL,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x00,
 #endif
+                                       },
+
        /* adoption_cb clnt, srv */     { LWS_CALLBACK_RAW_CONNECTED,
                                          LWS_CALLBACK_RAW_ADOPT },
        /* rx_cb clnt, srv */           { LWS_CALLBACK_RAW_RX,
diff --git a/lib/roles/ws/CMakeLists.txt b/lib/roles/ws/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0384064
--- /dev/null
@@ -0,0 +1,61 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(.)
+
+list(APPEND SOURCES
+       roles/ws/ops-ws.c)
+
+if (NOT LWS_WITHOUT_CLIENT)
+       list(APPEND SOURCES
+               roles/ws/client-ws.c
+               roles/ws/client-parser-ws.c)
+endif()
+
+if (NOT LWS_WITHOUT_SERVER)
+       list(APPEND SOURCES
+               roles/ws/server-ws.c)
+endif()
+
+if (NOT LWS_WITHOUT_EXTENSIONS)
+       list(APPEND HDR_PRIVATE
+               roles/ws/ext/extension-permessage-deflate.h)
+       list(APPEND SOURCES
+               roles/ws/ext/extension.c
+               roles/ws/ext/extension-permessage-deflate.c)
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+
index 299ba03..f569532 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /*
  * parsers.c: lws_ws_rx_sm() needs to be roughly kept in
@@ -28,7 +31,6 @@
 
 int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
        int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
        struct lws_ext_pm_deflate_rx_ebufs pmdrx;
        unsigned short close_code;
@@ -49,15 +51,12 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
 
                lws_remove_wsi_from_draining_ext_list(wsi);
                rx_draining_ext = 1;
-               lwsl_debug("%s: doing draining flow\n", __func__);
+               lwsl_wsi_debug(wsi, "doing draining flow");
 
                goto drain_extension;
        }
 #endif
 
-       if (wsi->socket_is_permanently_unusable)
-               return -1;
-
        switch (wsi->lws_rx_parse_state) {
        case LWS_RXPS_NEW:
                /* control frames (PING) may interrupt checkable sequences */
@@ -80,7 +79,7 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
 #endif
                                wsi->ws->continuation_possible = 1;
                                wsi->ws->check_utf8 = lws_check_opt(
-                                       wsi->context->options,
+                                       wsi->a.context->options,
                                        LWS_SERVER_OPTION_VALIDATE_UTF8);
                                wsi->ws->utf8 = 0;
                                wsi->ws->first_fragment = 1;
@@ -101,7 +100,7 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
                                break;
                        case LWSWSOPC_CONTINUATION:
                                if (!wsi->ws->continuation_possible) {
-                                       lwsl_info("disordered continuation\n");
+                                       lwsl_wsi_info(wsi, "disordered continuation");
                                        return -1;
                                }
                                wsi->ws->first_fragment = 0;
@@ -120,7 +119,7 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
                        case 0xd:
                        case 0xe:
                        case 0xf:
-                               lwsl_info("illegal opcode\n");
+                               lwsl_wsi_info(wsi, "illegal opcode");
                                return -1;
                        default:
                                wsi->ws->defeat_check_utf8 = 1;
@@ -133,17 +132,17 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
                                !wsi->ws->count_act_ext &&
 #endif
                                wsi->ws->rsv) {
-                               lwsl_info("illegal rsv bits set\n");
+                               lwsl_wsi_info(wsi, "illegal rsv bits set");
                                return -1;
                        }
                        wsi->ws->final = !!((c >> 7) & 1);
-                       lwsl_ext("%s:    This RX frame Final %d\n", __func__,
+                       lwsl_wsi_ext(wsi, "    This RX frame Final %d",
                                 wsi->ws->final);
 
                        if (wsi->ws->owed_a_fin &&
                            (wsi->ws->opcode == LWSWSOPC_TEXT_FRAME ||
                             wsi->ws->opcode == LWSWSOPC_BINARY_FRAME)) {
-                               lwsl_info("hey you owed us a FIN\n");
+                               lwsl_wsi_info(wsi, "hey you owed us a FIN");
                                return -1;
                        }
                        if ((!(wsi->ws->opcode & 8)) && wsi->ws->final) {
@@ -152,7 +151,7 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
                        }
 
                        if ((wsi->ws->opcode & 8) && !wsi->ws->final) {
-                               lwsl_info("control msg can't be fragmented\n");
+                               lwsl_wsi_info(wsi, "control msg can't be fragmented");
                                return -1;
                        }
                        if (!wsi->ws->final)
@@ -169,7 +168,7 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
                        break;
 
                default:
-                       lwsl_err("unknown spec version %02d\n",
+                       lwsl_wsi_err(wsi, "unknown spec version %02d",
                                 wsi->ws->ietf_spec_revision);
                        break;
                }
@@ -178,6 +177,8 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
        case LWS_RXPS_04_FRAME_HDR_LEN:
 
                wsi->ws->this_frame_masked = !!(c & 0x80);
+               if (wsi->ws->this_frame_masked)
+                       goto server_cannot_mask;
 
                switch (c & 0x7f) {
                case 126:
@@ -211,7 +212,7 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
                break;
 
        case LWS_RXPS_04_FRAME_HDR_LEN16_2:
-               wsi->ws->rx_packet_length = c << 8;
+               wsi->ws->rx_packet_length = (size_t)((unsigned int)c << 8);
                wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
                break;
 
@@ -232,7 +233,7 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
 
        case LWS_RXPS_04_FRAME_HDR_LEN64_8:
                if (c & 0x80) {
-                       lwsl_warn("b63 of length must be zero\n");
+                       lwsl_wsi_warn(wsi, "b63 of length must be zero");
                        /* kill the connection */
                        return -1;
                }
@@ -351,8 +352,7 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
                if (--wsi->ws->rx_packet_length == 0) {
                        /* spill because we have the whole frame */
                        wsi->lws_rx_parse_state = LWS_RXPS_NEW;
-                       lwsl_debug("%s: spilling as we have the whole frame\n",
-                                       __func__);
+                       lwsl_wsi_debug(wsi, "spilling as we have the whole frame");
                        goto spill;
                }
 
@@ -360,18 +360,17 @@ int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
                 * if there's no protocol max frame size given, we are
                 * supposed to default to context->pt_serv_buf_size
                 */
-               if (!wsi->protocol->rx_buffer_size &&
-                   wsi->ws->rx_ubuf_head != wsi->context->pt_serv_buf_size)
+               if (!wsi->a.protocol->rx_buffer_size &&
+                   wsi->ws->rx_ubuf_head != wsi->a.context->pt_serv_buf_size)
                        break;
 
-               if (wsi->protocol->rx_buffer_size &&
-                   wsi->ws->rx_ubuf_head != wsi->protocol->rx_buffer_size)
+               if (wsi->a.protocol->rx_buffer_size &&
+                   wsi->ws->rx_ubuf_head != wsi->a.protocol->rx_buffer_size)
                        break;
 
                /* spill because we filled our rx buffer */
 
-               lwsl_debug("%s: spilling as we filled our rx buffer\n",
-                               __func__);
+               lwsl_wsi_debug(wsi, "spilling as we filled our rx buffer");
 spill:
 
                handled = 0;
@@ -384,7 +383,7 @@ spill:
                switch (wsi->ws->opcode) {
                case LWSWSOPC_CLOSE:
                        pp = &wsi->ws->rx_ubuf[LWS_PRE];
-                       if (lws_check_opt(wsi->context->options,
+                       if (lws_check_opt(wsi->a.context->options,
                                          LWS_SERVER_OPTION_VALIDATE_UTF8) &&
                            wsi->ws->rx_ubuf_head > 2 &&
                            lws_check_utf8(&wsi->ws->utf8, pp + 2,
@@ -397,22 +396,18 @@ spill:
                                 * fine he has told us he is closing too, let's
                                 * finish our close
                                 */
-                               lwsl_parser("seen server's close ack\n");
+                               lwsl_wsi_parser(wsi, "seen server's close ack");
                                return -1;
                        }
 
-                       lwsl_parser("client sees server close len = %d\n",
-                                                wsi->ws->rx_ubuf_head);
+                       lwsl_wsi_parser(wsi, "client sees server close len = %d",
+                                                (int)wsi->ws->rx_ubuf_head);
                        if (wsi->ws->rx_ubuf_head >= 2) {
-                               close_code = (pp[0] << 8) | pp[1];
+                               close_code = (unsigned short)((pp[0] << 8) | pp[1]);
                                if (close_code < 1000 ||
                                    close_code == 1004 ||
                                    close_code == 1005 ||
                                    close_code == 1006 ||
-                                   close_code == 1012 ||
-                                   close_code == 1013 ||
-                                   close_code == 1014 ||
-                                   close_code == 1015 ||
                                    (close_code >= 1016 && close_code < 3000)
                                ) {
                                        pp[0] = (LWS_CLOSE_STATUS_PROTOCOL_ERR >> 8) & 0xff;
@@ -420,7 +415,7 @@ spill:
                                }
                        }
                        if (user_callback_handle_rxflow(
-                                       wsi->protocol->callback, wsi,
+                                       wsi->a.protocol->callback, wsi,
                                        LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
                                        wsi->user_space, pp,
                                        wsi->ws->rx_ubuf_head))
@@ -429,10 +424,9 @@ spill:
                        memcpy(wsi->ws->ping_payload_buf + LWS_PRE, pp,
                               wsi->ws->rx_ubuf_head);
                        wsi->ws->close_in_ping_buffer_len =
-                                       wsi->ws->rx_ubuf_head;
+                                       (uint8_t)wsi->ws->rx_ubuf_head;
 
-                       lwsl_info("%s: scheduling return close as ack\n",
-                                 __func__);
+                       lwsl_wsi_info(wsi, "scheduling return close as ack");
                        __lws_change_pollfd(wsi, LWS_POLLIN, 0);
                        lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 3);
                        wsi->waiting_to_send_close_frame = 1;
@@ -443,35 +437,35 @@ spill:
                        break;
 
                case LWSWSOPC_PING:
-                       lwsl_info("received %d byte ping, sending pong\n",
-                                 wsi->ws->rx_ubuf_head);
+                       lwsl_wsi_info(wsi, "received %d byte ping, sending pong",
+                                 (int)wsi->ws->rx_ubuf_head);
 
                        /* he set a close reason on this guy, ignore PING */
                        if (wsi->ws->close_in_ping_buffer_len)
                                goto ping_drop;
 
-                       if (wsi->ws->ping_pending_flag) {
+                       if (wsi->ws->pong_pending_flag) {
                                /*
-                                * there is already a pending ping payload
+                                * there is already a pending pong payload
                                 * we should just log and drop
                                 */
-                               lwsl_parser("DROP PING since one pending\n");
+                               lwsl_wsi_parser(wsi, "DROP PING since one pending");
                                goto ping_drop;
                        }
 
                        /* control packets can only be < 128 bytes long */
                        if (wsi->ws->rx_ubuf_head > 128 - 3) {
-                               lwsl_parser("DROP PING payload too large\n");
+                               lwsl_wsi_parser(wsi, "DROP PING payload too large");
                                goto ping_drop;
                        }
 
                        /* stash the pong payload */
-                       memcpy(wsi->ws->ping_payload_buf + LWS_PRE,
+                       memcpy(wsi->ws->pong_payload_buf + LWS_PRE,
                               &wsi->ws->rx_ubuf[LWS_PRE],
                               wsi->ws->rx_ubuf_head);
 
-                       wsi->ws->ping_payload_len = wsi->ws->rx_ubuf_head;
-                       wsi->ws->ping_pending_flag = 1;
+                       wsi->ws->pong_payload_len = (uint8_t)wsi->ws->rx_ubuf_head;
+                       wsi->ws->pong_pending_flag = 1;
 
                        /* get it sent as soon as possible */
                        lws_callback_on_writable(wsi);
@@ -481,24 +475,11 @@ ping_drop:
                        break;
 
                case LWSWSOPC_PONG:
-                       lwsl_info("%s: client %p received pong\n", __func__, wsi);
-                       lwsl_hexdump(&wsi->ws->rx_ubuf[LWS_PRE],
+                       lwsl_wsi_info(wsi, "Received pong");
+                       lwsl_hexdump_wsi_debug(wsi, &wsi->ws->rx_ubuf[LWS_PRE],
                                     wsi->ws->rx_ubuf_head);
 
-                       if (wsi->ws->await_pong) {
-                               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
-                               wsi->ws->await_pong = 0;
-
-                               /*
-                                * prepare to send the ping again if nothing
-                                * sent to countermand it
-                                */
-
-                               __lws_sul_insert(&pt->pt_sul_owner,
-                                                &wsi->sul_ping,
-                                       (lws_usec_t)wsi->context->ws_ping_pong_interval *
-                                        LWS_USEC_PER_SEC);
-                       }
+                       lws_validity_confirmed(wsi);
                        /* issue it */
                        callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
                        break;
@@ -510,7 +491,7 @@ ping_drop:
 
                default:
                        /* not handled or failed */
-                       lwsl_ext("Unhandled ext opc 0x%x\n", wsi->ws->opcode);
+                       lwsl_wsi_ext(wsi, "Unhandled ext opc 0x%x", wsi->ws->opcode);
                        wsi->ws->rx_ubuf_head = 0;
 
                        return -1;
@@ -534,56 +515,55 @@ ping_drop:
                        goto already_done;
 
                pmdrx.eb_in.token = &wsi->ws->rx_ubuf[LWS_PRE];
-               pmdrx.eb_in.len = wsi->ws->rx_ubuf_head;
+               pmdrx.eb_in.len = (int)wsi->ws->rx_ubuf_head;
 
                /* for the non-pm-deflate case */
 
                pmdrx.eb_out = pmdrx.eb_in;
 
-               lwsl_debug("%s: starting disbursal of %d deframed rx\n",
-                               __func__, wsi->ws->rx_ubuf_head);
+               lwsl_wsi_debug(wsi, "starting disbursal of %d deframed rx",
+                               (int)wsi->ws->rx_ubuf_head);
 
 #if !defined(LWS_WITHOUT_EXTENSIONS)
 drain_extension:
 #endif
                do {
 
-               //      lwsl_notice("%s: pmdrx.eb_in.len: %d\n", __func__,
+               //      lwsl_wsi_notice("pmdrx.eb_in.len: %d",
                //                  (int)pmdrx.eb_in.len);
 
                        n = PMDR_DID_NOTHING;
 
 #if !defined(LWS_WITHOUT_EXTENSIONS)
-                       lwsl_ext("%s: +++ passing %d %p to ext\n", __func__,
+                       lwsl_wsi_ext(wsi, "+++ passing %d %p to ext",
                                 pmdrx.eb_in.len, pmdrx.eb_in.token);
 
                        n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX,
                                              &pmdrx, 0);
-                       lwsl_ext("Ext RX returned %d\n", n);
+                       lwsl_wsi_ext(wsi, "Ext RX returned %d", n);
                        if (n < 0) {
                                wsi->socket_is_permanently_unusable = 1;
                                return -1;
                        }
                        if (n == PMDR_DID_NOTHING)
+                               /* ie, not PMDR_NOTHING_WE_SHOULD_DO */
                                break;
 #endif
-                       lwsl_ext("%s: post inflate ebuf in len %d / out len %d\n",
-                                   __func__, pmdrx.eb_in.len, pmdrx.eb_out.len);
+                       lwsl_wsi_ext(wsi, "post inflate ebuf in len %d / out len %d",
+                                   pmdrx.eb_in.len, pmdrx.eb_out.len);
 
 #if !defined(LWS_WITHOUT_EXTENSIONS)
                        if (rx_draining_ext && !pmdrx.eb_out.len) {
-                               lwsl_debug("   --- ending drain on 0 read result\n");
+                               lwsl_wsi_debug(wsi, "   --- ending drain on 0 read result");
                                goto already_done;
                        }
 
                        if (n == PMDR_HAS_PENDING) {    /* 1 means stuff to drain */
                                /* extension had more... main loop will come back */
-                               lwsl_ext("%s: adding to draining ext list\n",
-                                           __func__);
+                               lwsl_wsi_ext(wsi, "adding to draining ext list");
                                lws_add_wsi_to_draining_ext_list(wsi);
                        } else {
-                               lwsl_ext("%s: removing from draining ext list\n",
-                                           __func__);
+                               lwsl_wsi_ext(wsi, "removing from draining ext list");
                                lws_remove_wsi_from_draining_ext_list(wsi);
                        }
                        rx_draining_ext = wsi->ws->rx_draining_ext;
@@ -593,7 +573,7 @@ drain_extension:
 
                                if (lws_check_utf8(&wsi->ws->utf8,
                                                   pmdrx.eb_out.token,
-                                                  pmdrx.eb_out.len)) {
+                                                  (unsigned int)pmdrx.eb_out.len)) {
                                        lws_close_reason(wsi,
                                                LWS_CLOSE_STATUS_INVALID_PAYLOAD,
                                                (uint8_t *)"bad utf8", 8);
@@ -608,14 +588,14 @@ drain_extension:
                                    && (n == PMDR_EMPTY_FINAL || n == PMDR_UNKNOWN)
 #endif
                                    ) {
-                                       lwsl_info("FINAL utf8 error\n");
+                                       lwsl_wsi_info(wsi, "FINAL utf8 error");
                                        lws_close_reason(wsi,
                                                LWS_CLOSE_STATUS_INVALID_PAYLOAD,
                                                (uint8_t *)"partial utf8", 12);
 utf8_fail:
-                                       lwsl_info("utf8 error\n");
-                                       lwsl_hexdump_info(pmdrx.eb_out.token,
-                                                         pmdrx.eb_out.len);
+                                       lwsl_wsi_info(wsi, "utf8 error");
+                                       lwsl_hexdump_wsi_info(wsi, pmdrx.eb_out.token,
+                                                         (unsigned int)pmdrx.eb_out.len);
 
                                        return -1;
                                }
@@ -630,11 +610,11 @@ utf8_fail:
 
                        pmdrx.eb_out.token[pmdrx.eb_out.len] = '\0';
 
-                       if (!wsi->protocol->callback)
+                       if (!wsi->a.protocol->callback)
                                goto already_done;
 
                        if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
-                               lwsl_info("Client doing pong callback\n");
+                               lwsl_wsi_info(wsi, "Client doing pong callback");
 
 #if !defined(LWS_WITHOUT_EXTENSIONS)
                        if (n == PMDR_HAS_PENDING)
@@ -662,16 +642,16 @@ utf8_fail:
                        )
                                pmdrx.eb_in.len -= pmdrx.eb_out.len;
 
-                       m = wsi->protocol->callback(wsi,
+                       m = wsi->a.protocol->callback(wsi,
                                        (enum lws_callback_reasons)callback_action,
                                        wsi->user_space, pmdrx.eb_out.token,
-                                       pmdrx.eb_out.len);
+                                       (unsigned int)pmdrx.eb_out.len);
 
                        wsi->ws->first_fragment = 0;
 
-                       lwsl_debug("%s: bulk ws rx: inp used %d, output %d\n",
-                                   __func__, wsi->ws->rx_ubuf_head,
-                                   pmdrx.eb_out.len);
+                       lwsl_wsi_debug(wsi, "bulk ws rx: inp used %d, output %d",
+                                   (int)wsi->ws->rx_ubuf_head,
+                                   (int)pmdrx.eb_out.len);
 
                        /* if user code wants to close, let caller know */
                        if (m)
@@ -687,14 +667,24 @@ already_done:
                wsi->ws->rx_ubuf_head = 0;
                break;
        default:
-               lwsl_err("client rx illegal state\n");
+               lwsl_wsi_err(wsi, "client rx illegal state");
                return 1;
        }
 
        return 0;
 
 illegal_ctl_length:
-       lwsl_warn("Control frame asking for extended length is illegal\n");
+       lwsl_wsi_warn(wsi, "Control frame asking for extended length is illegal");
+
+       /* kill the connection */
+       return -1;
+
+server_cannot_mask:
+       lws_close_reason(wsi,
+                       LWS_CLOSE_STATUS_PROTOCOL_ERR,
+                       (uint8_t *)"srv mask", 8);
+
+       lwsl_wsi_warn(wsi, "Server must not mask");
 
        /* kill the connection */
        return -1;
index 17a6036..bc2a846 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 /*
  * In-place str to lower case
@@ -33,7 +36,7 @@ strtolower(char *s)
                int tolower_optee(int c);
                *s = tolower_optee((int)*s);
 #else
-               *s = tolower((int)*s);
+               *s = (char)tolower((int)*s);
 #endif
                s++;
        }
@@ -48,7 +51,7 @@ lws_create_client_ws_object(const struct lws_client_connect_info *i,
        /* allocate the ws struct for the wsi */
        wsi->ws = lws_zalloc(sizeof(*wsi->ws), "client ws struct");
        if (!wsi->ws) {
-               lwsl_notice("OOM\n");
+               lwsl_wsi_notice(wsi, "OOM");
                return 1;
        }
 
@@ -57,12 +60,12 @@ lws_create_client_ws_object(const struct lws_client_connect_info *i,
            i->ietf_version_or_minus_one)
                v = i->ietf_version_or_minus_one;
 
-       wsi->ws->ietf_spec_revision = v;
+       wsi->ws->ietf_spec_revision = (uint8_t)v;
 
        return 0;
 }
 
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
 int
 lws_ws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)
 {
@@ -74,14 +77,14 @@ lws_ws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)
            !lwsi_role_client(wsi))
                return 0;
 
-       lwsl_debug("%s: hs client feels it has %d in\n", __func__, (int)len);
+       lwsl_wsi_debug(wsi, "hs client feels it has %d in", (int)len);
 
        while (len) {
                /*
                 * we were accepting input but now we stopped doing so
                 */
                if (lws_is_flowcontrolled(wsi)) {
-                       lwsl_debug("%s: caching %ld\n", __func__, (long)len);
+                       lwsl_wsi_debug(wsi, "caching %ld", (long)len);
                        /*
                         * Since we cached the remaining available input, we
                         * can say we "consumed" it.
@@ -91,7 +94,7 @@ lws_ws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)
                         * effectively "putting it back in the cache", we have
                         * to place it at the cache head, not the tail as usual.
                         */
-                       if (lws_rxflow_cache(wsi, *buf, 0, (int)len) ==
+                       if (lws_rxflow_cache(wsi, *buf, 0, len) ==
                                                        LWSRXFC_TRIMMED) {
                                /*
                                 * we dealt with it by trimming the existing
@@ -100,8 +103,7 @@ lws_ws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)
                                 * indicate we didn't use anything to the caller
                                 * so he doesn't do any consumed processing
                                 */
-                               lwsl_info("%s: trimming inside rxflow cache\n",
-                                               __func__);
+                               lwsl_wsi_info(wsi, "trimming inside rxflow cache");
                                *buf = bufin;
                        } else
                                *buf += len;
@@ -112,7 +114,7 @@ lws_ws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)
                if (wsi->ws->rx_draining_ext) {
                        int m;
 
-                       lwsl_info("%s: draining ext\n", __func__);
+                       lwsl_wsi_info(wsi, "draining ext");
                        if (lwsi_role_client(wsi))
                                m = lws_ws_client_rx_sm(wsi, 0);
                        else
@@ -128,13 +130,13 @@ lws_ws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)
                 */
 
                if (lws_ws_client_rx_sm(wsi, *(*buf)++)) {
-                       lwsl_notice("%s: client_rx_sm exited, DROPPING %d\n",
-                                   __func__, (int)len);
+                       lwsl_wsi_info(wsi, "client_rx_sm exited, DROPPING %d",
+                                     (int)len);
                        return -1;
                }
                len--;
        }
-       // lwsl_notice("%s: finished with %ld\n", __func__, (long)len);
+       // lwsl_wsi_notice(wsi, "finished with %ld", (long)len);
 
        return 0;
 }
@@ -153,13 +155,13 @@ lws_generate_client_ws_handshake(struct lws *wsi, char *p, const char *conn1)
        /*
         * create the random key
         */
-       n = lws_get_random(wsi->context, hash, 16);
-       if (n != 16) {
-               lwsl_err("Unable to read from random dev %s\n",
+       if (lws_get_random(wsi->a.context, hash, 16) != 16) {
+               lwsl_wsi_err(wsi, "Unable to read from random dev %s",
                         SYSTEM_RANDOM_FILEPATH);
                return NULL;
        }
 
+       /* coverity[tainted_scalar] */
        lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));
 
        p += sprintf(p, "Upgrade: websocket\x0d\x0a"
@@ -176,10 +178,10 @@ lws_generate_client_ws_handshake(struct lws *wsi, char *p, const char *conn1)
        /* tell the server what extensions we could support */
 
 #if !defined(LWS_WITHOUT_EXTENSIONS)
-       ext = wsi->vhost->ws.extensions;
+       ext = wsi->a.vhost->ws.extensions;
        while (ext && ext->callback) {
 
-               n = wsi->vhost->protocols[0].callback(wsi,
+               n = wsi->a.vhost->protocols[0].callback(wsi,
                        LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
                                wsi->user_space, (char *)ext->name, 0);
 
@@ -219,7 +221,7 @@ lws_generate_client_ws_handshake(struct lws *wsi, char *p, const char *conn1)
        n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
                          key_b64);
 
-       lws_SHA1((unsigned char *)buf, n, (unsigned char *)hash);
+       lws_SHA1((unsigned char *)buf, (unsigned int)n, (unsigned char *)hash);
 
        lws_b64_encode_string(hash, 20,
                  wsi->http.ah->initial_handshake_hash_base64,
@@ -231,14 +233,14 @@ lws_generate_client_ws_handshake(struct lws *wsi, char *p, const char *conn1)
 int
 lws_client_ws_upgrade(struct lws *wsi, const char **cce)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct lws_tokenize ts;
        int n, len, okay = 0;
        lws_tokenize_elem e;
        char *p, buf[64];
        const char *pc;
 #if !defined(LWS_WITHOUT_EXTENSIONS)
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        char *sb = (char *)&pt->serv_buf[0];
        const struct lws_ext_options *opts;
        const struct lws_extension *ext;
@@ -248,45 +250,41 @@ lws_client_ws_upgrade(struct lws *wsi, const char **cce)
        char ignore;
 #endif
 
-       if (wsi->client_h2_substream) {/* !!! client ws-over-h2 not there yet */
-               lwsl_warn("%s: client ws-over-h2 upgrade not supported yet\n",
-                         __func__);
+       if (wsi->client_mux_substream) {/* !!! client ws-over-h2 not there yet */
+               lwsl_wsi_warn(wsi, "client ws-over-h2 upgrade not supported yet");
                *cce = "HS: h2 / ws upgrade unsupported";
                goto bail3;
        }
 
        if (wsi->http.ah->http_response == 401) {
-               lwsl_warn(
-                      "lws_client_handshake: got bad HTTP response '%d'\n",
-                      wsi->http.ah->http_response);
+               lwsl_wsi_warn(wsi, "got bad HTTP response '%d'",
+                             wsi->http.ah->http_response);
                *cce = "HS: ws upgrade unauthorized";
                goto bail3;
        }
 
        if (wsi->http.ah->http_response != 101) {
-               lwsl_warn(
-                      "lws_client_handshake: got bad HTTP response '%d'\n",
-                      wsi->http.ah->http_response);
+               lwsl_wsi_warn(wsi, "got bad HTTP response '%d'",
+                             wsi->http.ah->http_response);
                *cce = "HS: ws upgrade response not 101";
                goto bail3;
        }
 
        if (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) == 0) {
-               lwsl_info("no ACCEPT\n");
+               lwsl_wsi_info(wsi, "no ACCEPT");
                *cce = "HS: ACCEPT missing";
                goto bail3;
        }
 
        p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE);
        if (!p) {
-               lwsl_info("no UPGRADE\n");
+               lwsl_wsi_info(wsi, "no UPGRADE");
                *cce = "HS: UPGRADE missing";
                goto bail3;
        }
        strtolower(p);
        if (strcmp(p, "websocket")) {
-               lwsl_warn(
-                     "lws_client_handshake: got bad Upgrade header '%s'\n", p);
+               lwsl_wsi_warn(wsi, "got bad Upgrade header '%s'", p);
                *cce = "HS: Upgrade to something other than websocket";
                goto bail3;
        }
@@ -295,9 +293,10 @@ lws_client_ws_upgrade(struct lws *wsi, const char **cce)
 
        lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_COMMA_SEP_LIST |
                                    LWS_TOKENIZE_F_MINUS_NONTERM);
-       ts.len = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_CONNECTION);
-       if (ts.len <= 0) /* won't fit, or absent */
+       n = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_CONNECTION);
+       if (n <= 0) /* won't fit, or absent */
                goto bad_conn_format;
+       ts.len = (unsigned int)n;
 
        do {
                e = lws_tokenize(&ts);
@@ -312,8 +311,7 @@ lws_client_ws_upgrade(struct lws *wsi, const char **cce)
 
                default: /* includes ENDED found by the tokenizer itself */
 bad_conn_format:
-                       lwsl_info("%s: malfored connection '%s'\n",
-                                 __func__, buf);
+                       lwsl_wsi_info(wsi, "malformed connection '%s'", buf);
                        *cce = "HS: UPGRADE malformed";
                        goto bail3;
                }
@@ -321,10 +319,10 @@ bad_conn_format:
 
        pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
 #if defined(_DEBUG)
-       if (!pc) {
-               lwsl_parser("lws_client_int_s_hs: no protocol list\n");
-       else
-               lwsl_parser("lws_client_int_s_hs: protocol list '%s'\n", pc);
+       if (!pc)
+               lwsl_wsi_parser(wsi, "lws_client_int_s_hs: no protocol list");
+       else
+               lwsl_wsi_parser(wsi, "lws_client_int_s_hs: protocol list '%s'", pc);
 #endif
 
        /*
@@ -334,21 +332,21 @@ bad_conn_format:
 
        len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
        if (!len) {
-               lwsl_info("%s: WSI_TOKEN_PROTOCOL is null\n", __func__);
+               lwsl_wsi_info(wsi, "WSI_TOKEN_PROTOCOL is null");
                /*
                 * no protocol name to work from, if we don't already have one
                 * default to first protocol
                 */
 
-               if (wsi->protocol) {
-                       p = (char *)wsi->protocol->name;
+               if (wsi->a.protocol) {
+                       p = (char *)wsi->a.protocol->name;
                        goto identify_protocol;
                }
 
                /* no choice but to use the default protocol */
 
                n = 0;
-               wsi->protocol = &wsi->vhost->protocols[0];
+               wsi->a.protocol = &wsi->a.vhost->protocols[0];
                goto check_extensions;
        }
 
@@ -356,7 +354,7 @@ bad_conn_format:
        len = (int)strlen(p);
 
        while (pc && *pc && !okay) {
-               if (!strncmp(pc, p, len) &&
+               if (!strncmp(pc, p, (unsigned int)len) &&
                    (pc[len] == ',' || pc[len] == '\0')) {
                        okay = 1;
                        continue;
@@ -368,7 +366,7 @@ bad_conn_format:
        }
 
        if (!okay) {
-               lwsl_info("%s: got bad protocol %s\n", __func__, p);
+               lwsl_wsi_info(wsi, "got bad protocol %s", p);
                *cce = "HS: PROTOCOL malformed";
                goto bail2;
        }
@@ -386,21 +384,21 @@ identify_protocol:
        n = 0;
        /* keep client connection pre-bound protocol */
        if (!lwsi_role_client(wsi))
-               wsi->protocol = NULL;
+               wsi->a.protocol = NULL;
 
-       while (wsi->vhost->protocols[n].callback) {
-               if (!wsi->protocol &&
-                   strcmp(p, wsi->vhost->protocols[n].name) == 0) {
-                       wsi->protocol = &wsi->vhost->protocols[n];
+       while (n < wsi->a.vhost->count_protocols) {
+               if (!wsi->a.protocol &&
+                   strcmp(p, wsi->a.vhost->protocols[n].name) == 0) {
+                       wsi->a.protocol = &wsi->a.vhost->protocols[n];
                        break;
                }
                n++;
        }
 
-       if (!wsi->vhost->protocols[n].callback) { /* no match */
+       if (n == wsi->a.vhost->count_protocols) { /* no match */
                /* if server, that's already fatal */
                if (!lwsi_role_client(wsi)) {
-                       lwsl_info("%s: fail protocol %s\n", __func__, p);
+                       lwsl_wsi_info(wsi, "fail protocol %s", p);
                        *cce = "HS: Cannot match protocol";
                        goto bail2;
                }
@@ -408,27 +406,28 @@ identify_protocol:
                /* for client, find the index of our pre-bound protocol */
 
                n = 0;
-               while (wsi->vhost->protocols[n].callback) {
-                       if (wsi->protocol && strcmp(wsi->protocol->name,
-                                  wsi->vhost->protocols[n].name) == 0) {
-                               wsi->protocol = &wsi->vhost->protocols[n];
+               while (wsi->a.vhost->protocols[n].callback) {
+                       if (wsi->a.protocol && strcmp(wsi->a.protocol->name,
+                                  wsi->a.vhost->protocols[n].name) == 0) {
+                               wsi->a.protocol = &wsi->a.vhost->protocols[n];
                                break;
                        }
                        n++;
                }
 
-               if (!wsi->vhost->protocols[n].callback) {
-                       if (wsi->protocol)
-                               lwsl_err("Failed to match protocol %s\n",
-                                               wsi->protocol->name);
+               if (!wsi->a.vhost->protocols[n].callback) {
+                       if (wsi->a.protocol)
+                               lwsl_wsi_err(wsi, "Failed to match protocol %s",
+                                               wsi->a.protocol->name);
                        else
-                               lwsl_err("No protocol on client\n");
+                               lwsl_wsi_err(wsi, "No protocol on client");
                        *cce = "ws protocol no match";
                        goto bail2;
                }
        }
 
-       lwsl_debug("Selected protocol %s\n", wsi->protocol->name);
+       lwsl_wsi_debug(wsi, "Selected protocol %s", wsi->a.protocol ?
+                                            wsi->a.protocol->name : "no pcol");
 
 check_extensions:
        /*
@@ -445,7 +444,7 @@ check_extensions:
        /* instantiate the accepted extensions */
 
        if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {
-               lwsl_ext("no client extensions allowed by server\n");
+               lwsl_wsi_ext(wsi, "no client extensions allowed by server");
                goto check_accept;
        }
 
@@ -454,9 +453,9 @@ check_extensions:
         * and go through matching them or identifying bogons
         */
 
-       if (lws_hdr_copy(wsi, sb, context->pt_serv_buf_size,
+       if (lws_hdr_copy(wsi, sb, (int)context->pt_serv_buf_size,
                         WSI_TOKEN_EXTENSIONS) < 0) {
-               lwsl_warn("ext list from server failed to copy\n");
+               lwsl_wsi_warn(wsi, "ext list from server failed to copy");
                *cce = "HS: EXT: list too big";
                goto bail2;
        }
@@ -495,10 +494,10 @@ check_extensions:
 
                /* check we actually support it */
 
-               lwsl_notice("checking client ext %s\n", ext_name);
+               lwsl_wsi_notice(wsi, "checking client ext %s", ext_name);
 
                n = 0;
-               ext = wsi->vhost->ws.extensions;
+               ext = wsi->a.vhost->ws.extensions;
                while (ext && ext->callback) {
                        if (strcmp(ext_name, ext->name)) {
                                ext++;
@@ -506,7 +505,7 @@ check_extensions:
                        }
 
                        n = 1;
-                       lwsl_notice("instantiating client ext %s\n", ext_name);
+                       lwsl_wsi_notice(wsi, "instantiating client ext %s", ext_name);
 
                        /* instantiate the extension on this conn */
 
@@ -519,7 +518,7 @@ check_extensions:
                                   (void *)&wsi->ws->act_ext_user[
                                                        wsi->ws->count_act_ext],
                                   (void *)&opts, 0)) {
-                               lwsl_info(" ext %s failed construction\n",
+                               lwsl_wsi_info(wsi, " ext %s failed construction",
                                          ext_name);
                                ext++;
                                continue;
@@ -530,7 +529,7 @@ check_extensions:
                         * wants to
                         */
                        ext_name[0] = '\0';
-                       if (user_callback_handle_rxflow(wsi->protocol->callback,
+                       if (user_callback_handle_rxflow(wsi->a.protocol->callback,
                                        wsi, LWS_CALLBACK_WS_EXT_DEFAULTS,
                                        (char *)ext->name, ext_name,
                                        sizeof(ext_name))) {
@@ -544,8 +543,8 @@ check_extensions:
                                                        wsi->ws->count_act_ext],
                                                  opts, ext_name,
                                                  (int)strlen(ext_name))) {
-                               lwsl_err("%s: unable to parse user defaults '%s'",
-                                        __func__, ext_name);
+                               lwsl_wsi_err(wsi, "unable to parse user defaults '%s'",
+                                            ext_name);
                                *cce = "HS: EXT: failed parsing defaults";
                                goto bail2;
                        }
@@ -557,8 +556,7 @@ check_extensions:
                                        wsi->ws->act_ext_user[
                                                        wsi->ws->count_act_ext],
                                        opts, a, lws_ptr_diff(c, a))) {
-                               lwsl_err("%s: unable to parse remote def '%s'",
-                                        __func__, a);
+                               lwsl_wsi_err(wsi, "unable to parse remote def '%s'", a);
                                *cce = "HS: EXT: failed parsing options";
                                goto bail2;
                        }
@@ -567,8 +565,8 @@ check_extensions:
                                        LWS_EXT_CB_OPTION_CONFIRM,
                                      wsi->ws->act_ext_user[wsi->ws->count_act_ext],
                                      NULL, 0)) {
-                               lwsl_err("%s: ext %s rejects server options %s",
-                                        __func__, ext->name, a);
+                               lwsl_wsi_err(wsi, "ext %s rejects server options %s",
+                                            ext->name, a);
                                *cce = "HS: EXT: Rejects server options";
                                goto bail2;
                        }
@@ -579,7 +577,7 @@ check_extensions:
                }
 
                if (n == 0) {
-                       lwsl_warn("Unknown ext '%s'!\n", ext_name);
+                       lwsl_wsi_warn(wsi, "Unknown ext '%s'!", ext_name);
                        *cce = "HS: EXT: unknown ext";
                        goto bail2;
                }
@@ -597,7 +595,7 @@ check_accept:
 
        p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT);
        if (strcmp(p, wsi->http.ah->initial_handshake_hash_base64)) {
-               lwsl_warn("lws_client_int_s_hs: accept '%s' wrong vs '%s'\n", p,
+               lwsl_wsi_warn(wsi, "lws_client_int_s_hs: accept '%s' wrong vs '%s'", p,
                                  wsi->http.ah->initial_handshake_hash_base64);
                *cce = "HS: Accept hash wrong";
                goto bail2;
@@ -605,7 +603,7 @@ check_accept:
 
        /* allocate the per-connection user memory (if any) */
        if (lws_ensure_user_space(wsi)) {
-               lwsl_err("Problem allocating wsi user mem\n");
+               lwsl_wsi_err(wsi, "Problem allocating wsi user mem");
                *cce = "HS: OOM";
                goto bail2;
        }
@@ -614,7 +612,7 @@ check_accept:
         * we seem to be good to go, give client last chance to check
         * headers and OK it
         */
-       if (wsi->protocol->callback(wsi,
+       if (wsi->a.protocol->callback(wsi,
                                    LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
                                    wsi->user_space, NULL, 0)) {
                *cce = "HS: Rejected by filter cb";
@@ -627,15 +625,8 @@ check_accept:
        /* free up his parsing allocations */
        lws_header_table_detach(wsi, 0);
 
-       lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
-                           &role_ops_ws);
-
-       if (wsi->context->ws_ping_pong_interval && !wsi->http2_substream ) {
-               wsi->sul_ping.cb = lws_sul_wsping_cb;
-               __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_ping,
-                                (lws_usec_t)wsi->context->ws_ping_pong_interval *
-                                LWS_USEC_PER_SEC);
-       }
+       lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED, &role_ops_ws);
+       lws_validity_confirmed(wsi);
 
        wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
 
@@ -644,34 +635,24 @@ check_accept:
         * size mentioned in the protocol definition.  If 0 there, then
         * use a big default for compatibility
         */
-       n = (int)wsi->protocol->rx_buffer_size;
+       n = (int)wsi->a.protocol->rx_buffer_size;
        if (!n)
-               n = context->pt_serv_buf_size;
+               n = (int)context->pt_serv_buf_size;
        n += LWS_PRE;
-       wsi->ws->rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */,
+       wsi->ws->rx_ubuf = lws_malloc((unsigned int)n + 4 /* 0x0000ffff zlib */,
                                "client frame buffer");
        if (!wsi->ws->rx_ubuf) {
-               lwsl_err("Out of Mem allocating rx buffer %d\n", n);
+               lwsl_wsi_err(wsi, "OOM allocating rx buffer %d", n);
                *cce = "HS: OOM";
                goto bail2;
        }
-       wsi->ws->rx_ubuf_alloc = n;
-       lwsl_info("Allocating client RX buffer %d\n", n);
-
-#if !defined(LWS_WITH_ESP32)
-       if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
-                      (const char *)&n, sizeof n)) {
-               lwsl_warn("Failed to set SNDBUF to %d", n);
-               *cce = "HS: SO_SNDBUF failed";
-               goto bail3;
-       }
-#endif
+       wsi->ws->rx_ubuf_alloc = (unsigned int)n;
 
-       lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name);
+       lwsl_wsi_debug(wsi, "handshake OK for protocol %s", wsi->a.protocol->name);
 
        /* call him back to inform him he is up */
 
-       if (wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_ESTABLISHED,
+       if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_CLIENT_ESTABLISHED,
                                    wsi->user_space, NULL, 0)) {
                *cce = "HS: Rejected at CLIENT_ESTABLISHED";
                goto bail3;
index b18efe1..79c70ea 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * ./lib/extension-permessage-deflate.c
+ * libwebsockets - small server side websockets and web server implementation
  *
- *  Copyright (C) 2016 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 #include "extension-permessage-deflate.h"
 #include <stdio.h>
 #include <string.h>
@@ -49,17 +52,17 @@ lws_extension_pmdeflate_restrict_args(struct lws *wsi,
 
        /* cap the RX buf at the nearest power of 2 to protocol rx buf */
 
-       n = wsi->context->pt_serv_buf_size;
-       if (wsi->protocol->rx_buffer_size)
-               n = (int)wsi->protocol->rx_buffer_size;
+       n = (int)wsi->a.context->pt_serv_buf_size;
+       if (wsi->a.protocol->rx_buffer_size)
+               n = (int)wsi->a.protocol->rx_buffer_size;
 
        extra = 7;
        while (n >= 1 << (extra + 1))
                extra++;
 
        if (extra < priv->args[PMD_RX_BUF_PWR2]) {
-               priv->args[PMD_RX_BUF_PWR2] = extra;
-               lwsl_info(" Capping pmd rx to %d\n", 1 << extra);
+               priv->args[PMD_RX_BUF_PWR2] = (unsigned char)extra;
+               lwsl_wsi_info(wsi, " Capping pmd rx to %d", 1 << extra);
        }
 }
 
@@ -86,8 +89,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                oa = in;
                if (!oa->option_name)
                        break;
-               lwsl_ext("%s: named option set: %s\n", __func__,
-                        oa->option_name);
+               lwsl_wsi_ext(wsi, "named option set: %s", oa->option_name);
                for (n = 0; n < (int)LWS_ARRAY_SIZE(lws_ext_pm_deflate_options);
                     n++)
                        if (!strcmp(lws_ext_pm_deflate_options[n].name,
@@ -102,10 +104,10 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 
        case LWS_EXT_CB_OPTION_SET:
                oa = in;
-               lwsl_ext("%s: option set: idx %d, %s, len %d\n", __func__,
+               lwsl_wsi_ext(wsi, "option set: idx %d, %s, len %d",
                         oa->option_index, oa->start, oa->len);
                if (oa->start)
-                       priv->args[oa->option_index] = atoi(oa->start);
+                       priv->args[oa->option_index] = (unsigned char)atoi(oa->start);
                else
                        priv->args[oa->option_index] = 1;
 
@@ -126,21 +128,21 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
        case LWS_EXT_CB_CLIENT_CONSTRUCT:
        case LWS_EXT_CB_CONSTRUCT:
 
-               n = context->pt_serv_buf_size;
-               if (wsi->protocol->rx_buffer_size)
-                       n = (int)wsi->protocol->rx_buffer_size;
+               n = (int)context->pt_serv_buf_size;
+               if (wsi->a.protocol->rx_buffer_size)
+                       n = (int)wsi->a.protocol->rx_buffer_size;
 
                if (n < 128) {
-                       lwsl_info(" permessage-deflate requires the protocol "
-                                 "(%s) to have an RX buffer >= 128\n",
-                                 wsi->protocol->name);
+                       lwsl_wsi_info(wsi, " permessage-deflate requires the protocol "
+                                 "(%s) to have an RX buffer >= 128",
+                                 wsi->a.protocol->name);
                        return -1;
                }
 
                /* fill in **user */
                priv = lws_zalloc(sizeof(*priv), "pmd priv");
                *((void **)user) = priv;
-               lwsl_ext("%s: LWS_EXT_CB_*CONSTRUCT\n", __func__);
+               lwsl_wsi_ext(wsi, "LWS_EXT_CB_*CONSTRUCT");
                memset(priv, 0, sizeof(*priv));
 
                /* fill in pointer to options list */
@@ -170,7 +172,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                break;
 
        case LWS_EXT_CB_DESTROY:
-               lwsl_ext("%s: LWS_EXT_CB_DESTROY\n", __func__);
+               lwsl_wsi_ext(wsi, "LWS_EXT_CB_DESTROY");
                lws_free(priv->buf_rx_inflated);
                lws_free(priv->buf_tx_deflated);
                if (priv->rx_init)
@@ -183,13 +185,26 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 
 
        case LWS_EXT_CB_PAYLOAD_RX:
-               lwsl_ext(" %s: LWS_EXT_CB_PAYLOAD_RX: in %d, existing in %d\n",
-                        __func__, pmdrx->eb_in.len, priv->rx.avail_in);
+               /*
+                * ie, we are INFLATING
+                */
+               lwsl_wsi_ext(wsi, " LWS_EXT_CB_PAYLOAD_RX: in %d, existing in %d",
+                        pmdrx->eb_in.len, priv->rx.avail_in);
 
-               /* if this frame is not marked as compressed, we ignore it */
+               /*
+                * If this frame is not marked as compressed,
+                * there is nothing we should do with it
+                */
 
                if (!(wsi->ws->rsv_first_msg & 0x40) || (wsi->ws->opcode & 8))
-                       return PMDR_DID_NOTHING;
+                       /*
+                        * This is a bit different than DID_NOTHING... we have
+                        * identified using ext-private bits in the packet, or
+                        * by it being a control fragment that we SHOULD not do
+                        * anything to it, parent should continue as if we
+                        * processed it
+                        */
+                       return PMDR_NOTHING_WE_SHOULD_DO;
 
                /*
                 * we shouldn't come back in here if we already applied the
@@ -200,27 +215,26 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 
                pmdrx->eb_out.len = 0;
 
-               lwsl_ext("%s: LWS_EXT_CB_PAYLOAD_RX: in %d, "
-                           "existing avail in %d, pkt fin: %d\n", __func__,
-                                   pmdrx->eb_in.len, priv->rx.avail_in,
-                                   wsi->ws->final);
+               lwsl_wsi_ext(wsi, "LWS_EXT_CB_PAYLOAD_RX: in %d, "
+                        "existing avail in %d, pkt fin: %d",
+                        pmdrx->eb_in.len, priv->rx.avail_in, wsi->ws->final);
 
                /* if needed, initialize the inflator */
 
                if (!priv->rx_init) {
                        if (inflateInit2(&priv->rx,
                             -priv->args[PMD_SERVER_MAX_WINDOW_BITS]) != Z_OK) {
-                               lwsl_err("%s: iniflateInit failed\n", __func__);
+                               lwsl_wsi_err(wsi, "iniflateInit failed");
                                return PMDR_FAILED;
                        }
                        priv->rx_init = 1;
                        if (!priv->buf_rx_inflated)
                                priv->buf_rx_inflated = lws_malloc(
-                                       LWS_PRE + 7 + 5 +
-                                           (1 << priv->args[PMD_RX_BUF_PWR2]),
+                                       (unsigned int)(LWS_PRE + 7 + 5 +
+                                           (1 << priv->args[PMD_RX_BUF_PWR2])),
                                            "pmd rx inflate buf");
                        if (!priv->buf_rx_inflated) {
-                               lwsl_err("%s: OOM\n", __func__);
+                               lwsl_wsi_err(wsi, "OOM");
                                return PMDR_FAILED;
                        }
                }
@@ -233,28 +247,26 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 
                if (priv->rx.avail_in && pmdrx->eb_in.token &&
                                         pmdrx->eb_in.len) {
-                       lwsl_warn("%s: priv->rx.avail_in %d while getting new in\n",
-                                       __func__, priv->rx.avail_in);
+                       lwsl_wsi_warn(wsi, "priv->rx.avail_in %d while getting new in",
+                                       priv->rx.avail_in);
        //              assert(0);
                }
 #endif
                if (!priv->rx.avail_in && pmdrx->eb_in.token && pmdrx->eb_in.len) {
                        priv->rx.next_in = (unsigned char *)pmdrx->eb_in.token;
-                       priv->rx.avail_in = pmdrx->eb_in.len;
+                       priv->rx.avail_in = (uInt)pmdrx->eb_in.len;
                }
 
                priv->rx.next_out = priv->buf_rx_inflated + LWS_PRE;
                pmdrx->eb_out.token = priv->rx.next_out;
-               priv->rx.avail_out = 1 << priv->args[PMD_RX_BUF_PWR2];
-
-               pen = penbits = 0;
-               deflatePending(&priv->rx, &pen, &penbits);
-               pen |= penbits;
+               priv->rx.avail_out = (uInt)(1 << priv->args[PMD_RX_BUF_PWR2]);
 
                /* so... if...
                 *
                 *  - he has no remaining input content for this message, and
+                *
                 *  - and this is the final fragment, and
+                *
                 *  - we used everything that could be drained on the input side
                 *
                 * ...then put back the 00 00 FF FF the sender stripped as our
@@ -264,7 +276,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                    wsi->ws->final &&
                    !wsi->ws->rx_packet_length &&
                    wsi->ws->pmd_trailer_application) {
-                       lwsl_ext("%s: trailer apply 1\n", __func__);
+                       lwsl_wsi_ext(wsi, "trailer apply 1");
                        was_fin = 1;
                        wsi->ws->pmd_trailer_application = 0;
                        priv->rx.next_in = trail;
@@ -276,19 +288,19 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                 * him right now, bail without having done anything
                 */
 
-               if (!priv->rx.avail_in && !pen)
+               if (!priv->rx.avail_in)
                        return PMDR_DID_NOTHING;
 
                n = inflate(&priv->rx, was_fin ? Z_SYNC_FLUSH : Z_NO_FLUSH);
-               lwsl_ext("inflate ret %d, avi %d, avo %d, wsifinal %d\n", n,
+               lwsl_wsi_ext(wsi, "inflate ret %d, avi %d, avo %d, wsifinal %d", n,
                         priv->rx.avail_in, priv->rx.avail_out, wsi->ws->final);
                switch (n) {
                case Z_NEED_DICT:
                case Z_STREAM_ERROR:
                case Z_DATA_ERROR:
                case Z_MEM_ERROR:
-                       lwsl_err("%s: zlib error inflate %d: \"%s\"\n",
-                                 __func__, n, priv->rx.msg);
+                       lwsl_wsi_err(wsi, "zlib error inflate %d: \"%s\"",
+                                 n, priv->rx.msg);
                        return PMDR_FAILED;
                }
 
@@ -297,29 +309,22 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                 */
 
                pmdrx->eb_in.token = pmdrx->eb_in.token +
-                                        (pmdrx->eb_in.len - priv->rx.avail_in);
-               pmdrx->eb_in.len = priv->rx.avail_in;
+                                        ((unsigned int)pmdrx->eb_in.len - (unsigned int)priv->rx.avail_in);
+               pmdrx->eb_in.len = (int)priv->rx.avail_in;
 
-               pen = penbits = 0;
-               deflatePending(&priv->rx, &pen, &penbits);
-               pen |= penbits;
-
-               lwsl_debug("%s: %d %d %d %d %d %d\n", __func__,
+               lwsl_wsi_debug(wsi, "%d %d %d %d %d",
                                priv->rx.avail_in,
                                wsi->ws->final,
                                (int)wsi->ws->rx_packet_length,
                                was_fin,
-                               wsi->ws->pmd_trailer_application,
-                               pen);
+                               wsi->ws->pmd_trailer_application);
 
                if (!priv->rx.avail_in &&
                    wsi->ws->final &&
                    !wsi->ws->rx_packet_length &&
                    !was_fin &&
-                   wsi->ws->pmd_trailer_application &&
-                   !pen
-               ) {
-                       lwsl_ext("%s: RX trailer apply 2\n", __func__);
+                   wsi->ws->pmd_trailer_application) {
+                       lwsl_wsi_ext(wsi, "RX trailer apply 2");
 
                        /* we overallocated just for this situation where
                         * we might issue something */
@@ -330,39 +335,35 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                        priv->rx.next_in = trail;
                        priv->rx.avail_in = sizeof(trail);
                        n = inflate(&priv->rx, Z_SYNC_FLUSH);
-                       lwsl_ext("RX trailer infl ret %d, avi %d, avo %d\n",
-                                   n, priv->rx.avail_in, priv->rx.avail_out);
+                       lwsl_wsi_ext(wsi, "RX trailer infl ret %d, avi %d, avo %d",
+                                n, priv->rx.avail_in, priv->rx.avail_out);
                        switch (n) {
                        case Z_NEED_DICT:
                        case Z_STREAM_ERROR:
                        case Z_DATA_ERROR:
                        case Z_MEM_ERROR:
-                               lwsl_info("zlib error inflate %d: %s\n",
+                               lwsl_wsi_info(wsi, "zlib error inflate %d: %s",
                                          n, priv->rx.msg);
                                return -1;
                        }
 
                        assert(priv->rx.avail_out);
-
-                       pen = penbits = 0;
-                       deflatePending(&priv->rx, &pen, &penbits);
-                       pen |= penbits;
                }
 
                pmdrx->eb_out.len = lws_ptr_diff(priv->rx.next_out,
                                                 pmdrx->eb_out.token);
-               priv->count_rx_between_fin += pmdrx->eb_out.len;
+               priv->count_rx_between_fin = priv->count_rx_between_fin + (size_t)pmdrx->eb_out.len;
 
-               lwsl_ext("  %s: RX leaving with new effbuff len %d, "
-                        "rx.avail_in=%d, TOTAL RX since FIN %lu\n",
-                        __func__, pmdrx->eb_out.len, priv->rx.avail_in,
+               lwsl_wsi_ext(wsi, "  RX leaving with new effbuff len %d, "
+                        "rx.avail_in=%d, TOTAL RX since FIN %lu",
+                        pmdrx->eb_out.len, priv->rx.avail_in,
                         (unsigned long)priv->count_rx_between_fin);
 
-               if (was_fin && !pen) {
-                       lwsl_ext("%s: was_fin\n", __func__);
+               if (was_fin) {
+                       lwsl_wsi_ext(wsi, "was_fin");
                        priv->count_rx_between_fin = 0;
                        if (priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER]) {
-                               lwsl_ext("PMD_SERVER_NO_CONTEXT_TAKEOVER\n");
+                               lwsl_wsi_ext(wsi, "PMD_SERVER_NO_CONTEXT_TAKEOVER");
                                (void)inflateEnd(&priv->rx);
                                priv->rx_init = 0;
                        }
@@ -370,35 +371,39 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                        return PMDR_EMPTY_FINAL;
                }
 
-               if (pen || priv->rx.avail_in)
+               if (priv->rx.avail_in)
                        return PMDR_HAS_PENDING;
 
                return PMDR_EMPTY_NONFINAL;
 
        case LWS_EXT_CB_PAYLOAD_TX:
 
-               /* initialize us if needed */
+               /*
+                * ie, we are DEFLATING
+                *
+                * initialize us if needed
+                */
 
                if (!priv->tx_init) {
                        n = deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
                                         Z_DEFLATED,
                                         -priv->args[PMD_SERVER_MAX_WINDOW_BITS +
-                                               (wsi->vhost->listen_port <= 0)],
+                                               (wsi->a.vhost->listen_port <= 0)],
                                         priv->args[PMD_MEM_LEVEL],
                                         Z_DEFAULT_STRATEGY);
                        if (n != Z_OK) {
-                               lwsl_ext("inflateInit2 failed %d\n", n);
+                               lwsl_wsi_ext(wsi, "inflateInit2 failed %d", n);
                                return PMDR_FAILED;
                        }
                        priv->tx_init = 1;
                }
 
                if (!priv->buf_tx_deflated)
-                       priv->buf_tx_deflated = lws_malloc(LWS_PRE + 7 + 5 +
-                                           (1 << priv->args[PMD_TX_BUF_PWR2]),
+                       priv->buf_tx_deflated = lws_malloc((unsigned int)(LWS_PRE + 7 + 5 +
+                                           (1 << priv->args[PMD_TX_BUF_PWR2])),
                                            "pmd tx deflate buf");
                if (!priv->buf_tx_deflated) {
-                       lwsl_err("%s: OOM\n", __func__);
+                       lwsl_wsi_err(wsi, "OOM");
                        return PMDR_FAILED;
                }
 
@@ -408,25 +413,26 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 
                        assert(!priv->tx.avail_in);
 
-                       priv->count_tx_between_fin += pmdrx->eb_in.len;
-                       lwsl_ext("%s: TX: eb_in length %d, "
-                                   "TOTAL TX since FIN: %d\n", __func__,
+                       priv->count_tx_between_fin = priv->count_tx_between_fin + (size_t)pmdrx->eb_in.len;
+                       lwsl_wsi_ext(wsi, "TX: eb_in length %d, "
+                                   "TOTAL TX since FIN: %d",
                                    pmdrx->eb_in.len,
                                    (int)priv->count_tx_between_fin);
                        priv->tx.next_in = (unsigned char *)pmdrx->eb_in.token;
-                       priv->tx.avail_in = pmdrx->eb_in.len;
+                       priv->tx.avail_in = (uInt)pmdrx->eb_in.len;
                }
 
                priv->tx.next_out = priv->buf_tx_deflated + LWS_PRE + 5;
                pmdrx->eb_out.token = priv->tx.next_out;
-               priv->tx.avail_out = 1 << priv->args[PMD_TX_BUF_PWR2];
+               priv->tx.avail_out = (uInt)(1 << priv->args[PMD_TX_BUF_PWR2]);
 
-               pen = penbits = 0;
+               pen = 0;
+               penbits = 0;
                deflatePending(&priv->tx, &pen, &penbits);
-               pen |= penbits;
+               pen = pen | (unsigned int)penbits;
 
                if (!priv->tx.avail_in && (len & LWS_WRITE_NO_FIN)) {
-                       lwsl_ext("%s: no available in, pen: %u\n", __func__, pen);
+                       lwsl_wsi_ext(wsi, "no available in, pen: %u", pen);
 
                        if (!pen)
                                return PMDR_DID_NOTHING;
@@ -434,20 +440,20 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 
                m = Z_NO_FLUSH;
                if (!(len & LWS_WRITE_NO_FIN)) {
-                       lwsl_ext("%s: deflate with SYNC_FLUSH, pkt len %d\n",
-                                       __func__, (int)wsi->ws->rx_packet_length);
+                       lwsl_wsi_ext(wsi, "deflate with SYNC_FLUSH, pkt len %d",
+                                       (int)wsi->ws->rx_packet_length);
                        m = Z_SYNC_FLUSH;
                }
 
                n = deflate(&priv->tx, m);
                if (n == Z_STREAM_ERROR) {
-                       lwsl_notice("%s: Z_STREAM_ERROR\n", __func__);
+                       lwsl_wsi_notice(wsi, "Z_STREAM_ERROR");
                        return PMDR_FAILED;
                }
 
                pen = (!priv->tx.avail_out) && n != Z_STREAM_END;
 
-               lwsl_ext("%s: deflate ret %d, len 0x%x\n", __func__, n,
+               lwsl_wsi_ext(wsi, "deflate ret %d, len 0x%x", n,
                                (unsigned int)len);
 
                if ((len & 0xf) == LWS_WRITE_TEXT)
@@ -460,8 +466,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
 
                if (m == Z_SYNC_FLUSH && !(len & LWS_WRITE_NO_FIN) && !pen &&
                    pmdrx->eb_out.len < 4) {
-                       lwsl_err("%s: FAIL want to trim out length %d\n",
-                                       __func__, (int)pmdrx->eb_out.len);
+                       lwsl_wsi_err(wsi, "FAIL want to trim out length %d",
+                                       (int)pmdrx->eb_out.len);
                        assert(0);
                }
 
@@ -469,7 +475,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                    m == Z_SYNC_FLUSH &&
                    !pen &&
                    pmdrx->eb_out.len >= 4) {
-                       // lwsl_err("%s: Trimming 4 from end of write\n", __func__);
+                       // lwsl_wsi_err(wsi, "Trimming 4 from end of write");
                        priv->tx.next_out -= 4;
                        priv->tx.avail_out += 4;
                        priv->count_tx_between_fin = 0;
@@ -486,15 +492,15 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                 */
 
                pmdrx->eb_in.token = pmdrx->eb_in.token +
-                                       (pmdrx->eb_in.len - priv->tx.avail_in);
-               pmdrx->eb_in.len = priv->tx.avail_in;
+                                       ((unsigned int)pmdrx->eb_in.len - (unsigned int)priv->tx.avail_in);
+               pmdrx->eb_in.len = (int)priv->tx.avail_in;
 
                priv->compressed_out = 1;
                pmdrx->eb_out.len = lws_ptr_diff(priv->tx.next_out,
                                                 pmdrx->eb_out.token);
 
-               lwsl_ext("  TX rewritten with new eb_in len %d, "
-                               "eb_out len %d, deflatePending %d\n",
+               lwsl_wsi_ext(wsi, "  TX rewritten with new eb_in len %d, "
+                               "eb_out len %d, deflatePending %d",
                                pmdrx->eb_in.len, pmdrx->eb_out.len, pen);
 
                if (pmdrx->eb_in.len || pen)
@@ -516,8 +522,8 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                 * use of CONTINUATION when the first real write does come.
                 */
                if (priv->tx_first_frame_type & 0xf) {
-                       *pmdrx->eb_in.token = ((*pmdrx->eb_in.token) & ~0xf) |
-                                       (priv->tx_first_frame_type & 0xf);
+                       *pmdrx->eb_in.token = (unsigned char)((((unsigned char)*pmdrx->eb_in.token) & (unsigned char)~0xf) |
+                               ((unsigned char)priv->tx_first_frame_type & (unsigned char)0xf));
                        /*
                         * We have now written the "first" fragment, only
                         * do that once
@@ -531,13 +537,13 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
                if (n == LWSWSOPC_TEXT_FRAME || n == LWSWSOPC_BINARY_FRAME)
                        *pmdrx->eb_in.token |= 0x40;
 
-               lwsl_ext("%s: PRESEND compressed: ws frame 0x%02X, len %d\n",
-                           __func__, ((*pmdrx->eb_in.token) & 0xff),
+               lwsl_wsi_ext(wsi, "PRESEND compressed: ws frame 0x%02X, len %d",
+                           ((*pmdrx->eb_in.token) & 0xff),
                            pmdrx->eb_in.len);
 
                if (((*pmdrx->eb_in.token) & 0x80) &&   /* fin */
                    priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {
-                       lwsl_debug("PMD_CLIENT_NO_CONTEXT_TAKEOVER\n");
+                       lwsl_wsi_debug(wsi, "PMD_CLIENT_NO_CONTEXT_TAKEOVER");
                        (void)deflateEnd(&priv->tx);
                        priv->tx_init = 0;
                }
index 7c56020..aa10c1e 100644 (file)
@@ -1,3 +1,26 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
 
 #if defined(LWS_WITH_MINIZ)
 #include <miniz.h>
index a8bb1c7..dd6539b 100644 (file)
@@ -1,12 +1,36 @@
-#include "core/private.h"
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
 
 #include "extension-permessage-deflate.h"
 
-LWS_VISIBLE void
+void
 lws_context_init_extensions(const struct lws_context_creation_info *info,
                            struct lws_context *context)
 {
-       lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE);
+       lwsl_cx_info(context, " LWS_MAX_EXTENSIONS_ACTIVE: %u", LWS_MAX_EXTENSIONS_ACTIVE);
 }
 
 enum lws_ext_option_parser_states {
@@ -17,7 +41,7 @@ enum lws_ext_option_parser_states {
        LEAPS_SEEK_ARG_TERM
 };
 
-LWS_VISIBLE int
+int
 lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
                      void *ext_user, const struct lws_ext_options *opts,
                      const char *in, int len)
@@ -32,7 +56,7 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
        while (opts[count_options].name)
                count_options++;
        while (len) {
-               lwsl_ext("'%c' %d", *in, leap);
+               lwsl_wsi_ext(wsi, "'%c' %d", *in, leap);
                switch (leap) {
                case LEAPS_SEEK_NAME:
                        if (*in == ' ')
@@ -41,7 +65,7 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
                                len = 1;
                                break;
                        }
-                       match_map = (1 << count_options) - 1;
+                       match_map = (unsigned int)(1 << count_options) - 1;
                        leap = LEAPS_EAT_NAME;
                        w = 0;
 
@@ -59,12 +83,12 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
                                        n++;
                                        continue;
                                }
-                               lwsl_ext("    m=%d, n=%d, w=%d\n", m, n, w);
+                               lwsl_wsi_ext(wsi, "    m=%d, n=%d, w=%d", m, n, w);
 
                                if (*in == opts[n].name[w]) {
                                        if (!opts[n].name[w + 1]) {
-                                               oa.option_index = n;
-                                               lwsl_ext("hit %d\n",
+                                               oa.option_index = (int)n;
+                                               lwsl_wsi_ext(wsi, "hit %d",
                                                         oa.option_index);
                                                leap = LEAPS_SEEK_VAL;
                                                if (len == 1)
@@ -72,9 +96,9 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
                                                break;
                                        }
                                } else {
-                                       match_map &= ~(1 << n);
+                                       match_map &= (unsigned int)~(1 << n);
                                        if (!match_map) {
-                                               lwsl_ext("empty match map\n");
+                                               lwsl_wsi_ext(wsi, "empty match map");
                                                return -1;
                                        }
                                }
@@ -174,9 +198,9 @@ int lws_ext_cb_active(struct lws *wsi, int reason, void *arg, int len)
        for (n = 0; n < wsi->ws->count_act_ext; n++) {
                m = wsi->ws->active_extensions[n]->callback(
                        lws_get_context(wsi), wsi->ws->active_extensions[n],
-                       wsi, reason, wsi->ws->act_ext_user[n], arg, len);
+                       wsi, (enum lws_extension_callback_reasons)reason, wsi->ws->act_ext_user[n], arg, (size_t)len);
                if (m < 0) {
-                       lwsl_ext("Ext '%s' failed to handle callback %d!\n",
+                       lwsl_wsi_ext(wsi, "Ext '%s' failed to handle callback %d!",
                                 wsi->ws->active_extensions[n]->name, reason);
                        return -1;
                }
@@ -196,16 +220,16 @@ int lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi,
        int n = 0, m, handled = 0;
        const struct lws_extension *ext;
 
-       if (!wsi || !wsi->vhost || !wsi->ws)
+       if (!wsi || !wsi->a.vhost || !wsi->ws)
                return 0;
 
-       ext = wsi->vhost->ws.extensions;
+       ext = wsi->a.vhost->ws.extensions;
 
        while (ext && ext->callback && !handled) {
-               m = ext->callback(context, ext, wsi, reason,
-                                 (void *)(lws_intptr_t)n, arg, len);
+               m = ext->callback(context, ext, wsi, (enum lws_extension_callback_reasons)reason,
+                                 (void *)(lws_intptr_t)n, arg, (size_t)len);
                if (m < 0) {
-                       lwsl_ext("Ext '%s' failed to handle callback %d!\n",
+                       lwsl_wsi_ext(wsi, "Ext '%s' failed to handle callback %d!",
                                 wsi->ws->active_extensions[n]->name, reason);
                        return -1;
                }
@@ -258,18 +282,17 @@ lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len)
                /* assuming they left us something to send, send it */
 
                if (ebuf.len) {
-                       n = lws_issue_raw(wsi, ebuf.token, ebuf.len);
+                       n = lws_issue_raw(wsi, ebuf.token, (size_t)ebuf.len);
                        if (n < 0) {
-                               lwsl_info("closing from ext access\n");
+                               lwsl_wsi_info(wsi, "closing from ext access");
                                return -1;
                        }
 
                        /* always either sent it all or privately buffered */
                        if (wsi->ws->clean_buffer)
-                               len = n;
+                               len = (size_t)n;
 
-                       lwsl_ext("%s: written %d bytes to client\n",
-                                __func__, n);
+                       lwsl_wsi_ext(wsi, "written %d bytes to client", n);
                }
 
                /* no extension has more to spill?  Then we can go */
@@ -291,7 +314,7 @@ lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len)
                        /* no we could add more, lets's do that */
                        continue;
 
-               lwsl_debug("choked\n");
+               lwsl_wsi_debug(wsi, "choked");
 
                /*
                 * Yes, he's choked.  Don't spill the rest now get a callback
@@ -309,7 +332,7 @@ int
 lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r,
                          void *v, size_t len)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        int n, handled = 0;
 
        if (!wsi->ws)
@@ -352,7 +375,7 @@ lws_set_extension_option(struct lws *wsi, const char *ext_name,
        oa.start = opt_val;
        oa.len = 0;
 
-       return wsi->ws->active_extensions[idx]->callback(wsi->context,
+       return wsi->ws->active_extensions[idx]->callback(wsi->a.context,
                        wsi->ws->active_extensions[idx], wsi,
                        LWS_EXT_CB_NAMED_OPTION_SET, wsi->ws->act_ext_user[idx],
                        &oa, 0);
index b959384..37fbd34 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 #define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
 
@@ -31,7 +34,6 @@
 int
 lws_ws_rx_sm(struct lws *wsi, char already_processed, unsigned char c)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
        int callback_action = LWS_CALLBACK_RECEIVE;
        struct lws_ext_pm_deflate_rx_ebufs pmdrx;
        unsigned short close_code;
@@ -48,9 +50,6 @@ lws_ws_rx_sm(struct lws *wsi, char already_processed, unsigned char c)
        pmdrx.eb_out.token = NULL;
        pmdrx.eb_out.len = 0;
 
-       if (wsi->socket_is_permanently_unusable)
-               return -1;
-
        switch (wsi->lws_rx_parse_state) {
        case LWS_RXPS_NEW:
 #if !defined(LWS_WITHOUT_EXTENSIONS)
@@ -154,7 +153,7 @@ handle_first:
                switch (wsi->ws->opcode) {
                case LWSWSOPC_TEXT_FRAME:
                        wsi->ws->check_utf8 = lws_check_opt(
-                               wsi->context->options,
+                               wsi->a.context->options,
                                LWS_SERVER_OPTION_VALIDATE_UTF8);
                        /* fallthru */
                case LWSWSOPC_BINARY_FRAME:
@@ -276,7 +275,7 @@ handle_first:
                break;
 
        case LWS_RXPS_04_FRAME_HDR_LEN16_2:
-               wsi->ws->rx_packet_length = c << 8;
+               wsi->ws->rx_packet_length = (size_t)(c << 8);
                wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
                break;
 
@@ -420,12 +419,12 @@ handle_first:
                 * if there's no protocol max frame size given, we are
                 * supposed to default to context->pt_serv_buf_size
                 */
-               if (!wsi->protocol->rx_buffer_size &&
-                   wsi->ws->rx_ubuf_head != wsi->context->pt_serv_buf_size)
+               if (!wsi->a.protocol->rx_buffer_size &&
+                   wsi->ws->rx_ubuf_head != wsi->a.context->pt_serv_buf_size)
                        break;
 
-               if (wsi->protocol->rx_buffer_size &&
-                   wsi->ws->rx_ubuf_head != wsi->protocol->rx_buffer_size)
+               if (wsi->a.protocol->rx_buffer_size &&
+                   wsi->ws->rx_ubuf_head != wsi->a.protocol->rx_buffer_size)
                        break;
 
                /* spill because we filled our rx buffer */
@@ -435,7 +434,7 @@ spill:
                 * layer?  If so service it and hide it from the user callback
                 */
 
-               lwsl_parser("spill on %s\n", wsi->protocol->name);
+               lwsl_parser("spill on %s\n", wsi->a.protocol->name);
 
                switch (wsi->ws->opcode) {
                case LWSWSOPC_CLOSE:
@@ -446,7 +445,7 @@ spill:
                        wsi->ws->peer_has_sent_close = 1;
 
                        pp = &wsi->ws->rx_ubuf[LWS_PRE];
-                       if (lws_check_opt(wsi->context->options,
+                       if (lws_check_opt(wsi->a.context->options,
                                          LWS_SERVER_OPTION_VALIDATE_UTF8) &&
                            wsi->ws->rx_ubuf_head > 2 &&
                            lws_check_utf8(&wsi->ws->utf8, pp + 2,
@@ -479,7 +478,7 @@ spill:
                        }
 
                        if (wsi->ws->rx_ubuf_head >= 2) {
-                               close_code = (pp[0] << 8) | pp[1];
+                               close_code = (unsigned short)((pp[0] << 8) | pp[1]);
                                if (close_code < 1000 ||
                                    close_code == 1004 ||
                                    close_code == 1005 ||
@@ -496,7 +495,7 @@ spill:
                        }
 
                        if (user_callback_handle_rxflow(
-                                       wsi->protocol->callback, wsi,
+                                       wsi->a.protocol->callback, wsi,
                                        LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
                                        wsi->user_space,
                                        &wsi->ws->rx_ubuf[LWS_PRE],
@@ -511,11 +510,11 @@ spill:
 
                case LWSWSOPC_PING:
                        lwsl_info("received %d byte ping, sending pong\n",
-                                                wsi->ws->rx_ubuf_head);
+                                                (int)wsi->ws->rx_ubuf_head);
 
-                       if (wsi->ws->ping_pending_flag) {
+                       if (wsi->ws->pong_pending_flag) {
                                /*
-                                * there is already a pending ping payload
+                                * there is already a pending pong payload
                                 * we should just log and drop
                                 */
                                lwsl_parser("DROP PING since one pending\n");
@@ -529,12 +528,12 @@ process_as_ping:
                        }
 
                        /* stash the pong payload */
-                       memcpy(wsi->ws->ping_payload_buf + LWS_PRE,
+                       memcpy(wsi->ws->pong_payload_buf + LWS_PRE,
                               &wsi->ws->rx_ubuf[LWS_PRE],
                                wsi->ws->rx_ubuf_head);
 
-                       wsi->ws->ping_payload_len = wsi->ws->rx_ubuf_head;
-                       wsi->ws->ping_pending_flag = 1;
+                       wsi->ws->pong_payload_len = (uint8_t)wsi->ws->rx_ubuf_head;
+                       wsi->ws->pong_pending_flag = 1;
 
                        /* get it sent as soon as possible */
                        lws_callback_on_writable(wsi);
@@ -547,22 +546,7 @@ ping_drop:
                        lwsl_hexdump(&wsi->ws->rx_ubuf[LWS_PRE],
                                     wsi->ws->rx_ubuf_head);
 
-                       if (wsi->ws->await_pong) {
-                               lwsl_info("received expected PONG on wsi %p\n",
-                                               wsi);
-                               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
-                               wsi->ws->await_pong = 0;
-
-                               /*
-                                * prepare to send the ping again if nothing
-                                * sent to countermand it
-                                */
-
-                               __lws_sul_insert(&pt->pt_sul_owner,
-                                                &wsi->sul_ping,
-                                       (lws_usec_t)wsi->context->ws_ping_pong_interval *
-                                        LWS_USEC_PER_SEC);
-                       }
+                       lws_validity_confirmed(wsi);
 
                        /* issue it */
                        callback_action = LWS_CALLBACK_RECEIVE_PONG;
@@ -595,7 +579,7 @@ ping_drop:
                 */
 
                pmdrx.eb_in.token = &wsi->ws->rx_ubuf[LWS_PRE];
-               pmdrx.eb_in.len = wsi->ws->rx_ubuf_head;
+               pmdrx.eb_in.len = (int)wsi->ws->rx_ubuf_head;
 
                /* for the non-pm-deflate case */
 
@@ -629,7 +613,7 @@ drain_extension:
                        lwsl_debug("%s: ext says %d / ebuf.len %d\n", __func__,
                                   n, pmdrx.eb_out.len);
                        if (wsi->ws->rx_draining_ext)
-                               already_processed &= ~ALREADY_PROCESSED_NO_CB;
+                               already_processed &= (char)~ALREADY_PROCESSED_NO_CB;
 #endif
 
                        /*
@@ -646,6 +630,7 @@ drain_extension:
                                return -1;
                        }
                        if (n == PMDR_DID_NOTHING)
+                               /* ie, not PMDR_NOTHING_WE_SHOULD_DO */
                                break;
 #endif
                        lwsl_debug("%s: post ext ret %d, ebuf in %d / out %d\n",
@@ -674,7 +659,7 @@ drain_extension:
                            wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) {
                                if (lws_check_utf8(&wsi->ws->utf8,
                                                   pmdrx.eb_out.token,
-                                                  pmdrx.eb_out.len)) {
+                                                  (size_t)pmdrx.eb_out.len)) {
                                        lws_close_reason(wsi,
                                                LWS_CLOSE_STATUS_INVALID_PAYLOAD,
                                                (uint8_t *)"bad utf8", 8);
@@ -696,7 +681,7 @@ drain_extension:
 utf8_fail:
                                        lwsl_notice("utf8 error\n");
                                        lwsl_hexdump_notice(pmdrx.eb_out.token,
-                                                           pmdrx.eb_out.len);
+                                                           (size_t)pmdrx.eb_out.len);
 
                                        return -1;
                                }
@@ -706,7 +691,8 @@ utf8_fail:
 
                        if (n == PMDR_DID_NOTHING
 #if !defined(LWS_WITHOUT_EXTENSIONS)
-                                       ||
+                                       ||
+                           n == PMDR_NOTHING_WE_SHOULD_DO ||
                            n == PMDR_UNKNOWN
 #endif
                            )
@@ -719,19 +705,19 @@ utf8_fail:
                                if (pmdrx.eb_out.len)
                                        pmdrx.eb_out.token[pmdrx.eb_out.len] = '\0';
 
-                               if (wsi->protocol->callback &&
+                               if (wsi->a.protocol->callback &&
                                    !(already_processed & ALREADY_PROCESSED_NO_CB)) {
                                        if (callback_action ==
                                                      LWS_CALLBACK_RECEIVE_PONG)
                                                lwsl_info("Doing pong callback\n");
 
                                        ret = user_callback_handle_rxflow(
-                                               wsi->protocol->callback, wsi,
+                                               wsi->a.protocol->callback, wsi,
                                                (enum lws_callback_reasons)
                                                             callback_action,
                                                wsi->user_space,
                                                pmdrx.eb_out.token,
-                                               pmdrx.eb_out.len);
+                                               (size_t)pmdrx.eb_out.len);
                                }
                                wsi->ws->first_fragment = 0;
                        }
@@ -762,13 +748,13 @@ illegal_ctl_length:
 }
 
 
-LWS_VISIBLE size_t
+size_t
 lws_remaining_packet_payload(struct lws *wsi)
 {
        return wsi->ws->rx_packet_length;
 }
 
-LWS_VISIBLE int lws_frame_is_binary(struct lws *wsi)
+int lws_frame_is_binary(struct lws *wsi)
 {
        return wsi->ws->frame_is_binary;
 }
@@ -777,7 +763,7 @@ void
 lws_add_wsi_to_draining_ext_list(struct lws *wsi)
 {
 #if !defined(LWS_WITHOUT_EXTENSIONS)
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
 
        if (wsi->ws->rx_draining_ext)
                return;
@@ -794,7 +780,7 @@ void
 lws_remove_wsi_from_draining_ext_list(struct lws *wsi)
 {
 #if !defined(LWS_WITHOUT_EXTENSIONS)
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        struct lws **w = &pt->ws.rx_draining_ext_list;
 
        if (!wsi->ws->rx_draining_ext)
@@ -820,13 +806,13 @@ lws_remove_wsi_from_draining_ext_list(struct lws *wsi)
 static int
 lws_0405_frame_mask_generate(struct lws *wsi)
 {
-       int n;
+       size_t n;
        /* fetch the per-frame nonce */
 
        n = lws_get_random(lws_get_context(wsi), wsi->ws->mask, 4);
        if (n != 4) {
                lwsl_parser("Unable to read from random device %s %d\n",
-                           SYSTEM_RANDOM_FILEPATH, n);
+                           SYSTEM_RANDOM_FILEPATH, (int)n);
                return 1;
        }
 
@@ -836,86 +822,34 @@ lws_0405_frame_mask_generate(struct lws *wsi)
        return 0;
 }
 
-void
-lws_sul_wsping_cb(lws_sorted_usec_list_t *sul)
-{
-       struct lws *wsi = lws_container_of(sul, struct lws, sul_ping);
-
-       if (!wsi->ws)
-               return;
-
-       /*
-        * The sul_ping timer came up... either it's time to send a PING
-        * (!wsi->ws->send_check_ping), or we didn't get the PONG in time
-        * (wsi->ws->send_check_ping)
-        */
-
-       if (!wsi->ws->send_check_ping) {
-               lwsl_info("%s: req pp on wsi %p\n", __func__, wsi);
-
-               wsi->ws->send_check_ping = 1;
-               lws_set_timeout(wsi, PENDING_TIMEOUT_WS_PONG_CHECK_SEND_PING,
-                               wsi->context->timeout_secs);
-               lws_callback_on_writable(wsi);
-
-               return;
-       }
-
-       if (wsi->ws->await_pong) {
-               /* it didn't return the PONG in time */
-
-               lwsl_info("%s: wsi %p: failed to send PONG\n", __func__, wsi);
-               __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
-                                    "PONG timeout");
-       }
-}
-
 int
 lws_server_init_wsi_for_ws(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
        int n;
 
        lwsi_set_state(wsi, LRS_ESTABLISHED);
 
-       if (wsi->context->ws_ping_pong_interval && !wsi->http2_substream ) {
-               wsi->sul_ping.cb = lws_sul_wsping_cb;
-               __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_ping,
-                                (lws_usec_t)wsi->context->ws_ping_pong_interval *
-                                LWS_USEC_PER_SEC);
-       }
-
        /*
         * create the frame buffer for this connection according to the
         * size mentioned in the protocol definition.  If 0 there, use
         * a big default for compatibility
         */
 
-       n = (int)wsi->protocol->rx_buffer_size;
+       n = (int)wsi->a.protocol->rx_buffer_size;
        if (!n)
-               n = wsi->context->pt_serv_buf_size;
+               n = (int)wsi->a.context->pt_serv_buf_size;
        n += LWS_PRE;
-       wsi->ws->rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */, "rx_ubuf");
+       wsi->ws->rx_ubuf = lws_malloc((unsigned int)n + 4 /* 0x0000ffff zlib */, "rx_ubuf");
        if (!wsi->ws->rx_ubuf) {
                lwsl_err("Out of Mem allocating rx buffer %d\n", n);
                return 1;
        }
-       wsi->ws->rx_ubuf_alloc = n;
-       lwsl_debug("Allocating RX buffer %d\n", n);
-
-#if !defined(LWS_WITH_ESP32)
-       if (!wsi->h2_stream_carries_ws)
-               if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
-                      (const char *)&n, sizeof n)) {
-                       lwsl_warn("Failed to set SNDBUF to %d", n);
-                       return 1;
-               }
-#endif
+       wsi->ws->rx_ubuf_alloc = (uint32_t)n;
 
        /* notify user code that we're ready to roll */
 
-       if (wsi->protocol->callback)
-               if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
+       if (wsi->a.protocol->callback)
+               if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
                                            wsi->user_space,
 #ifdef LWS_WITH_TLS
                                            wsi->tls.ssl,
@@ -925,6 +859,7 @@ lws_server_init_wsi_for_ws(struct lws *wsi)
                                            wsi->h2_stream_carries_ws))
                        return 1;
 
+       lws_validity_confirmed(wsi);
        lwsl_debug("ws established\n");
 
        return 0;
@@ -932,7 +867,7 @@ lws_server_init_wsi_for_ws(struct lws *wsi)
 
 
 
-LWS_VISIBLE int
+int
 lws_is_final_fragment(struct lws *wsi)
 {
 #if !defined(LWS_WITHOUT_EXTENSIONS)
@@ -946,31 +881,31 @@ lws_is_final_fragment(struct lws *wsi)
 #endif
 }
 
-LWS_VISIBLE int
+int
 lws_is_first_fragment(struct lws *wsi)
 {
        return wsi->ws->first_fragment;
 }
 
-LWS_VISIBLE unsigned char
+unsigned char
 lws_get_reserved_bits(struct lws *wsi)
 {
        return wsi->ws->rsv;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_get_close_length(struct lws *wsi)
 {
        return wsi->ws->close_in_ping_buffer_len;
 }
 
-LWS_VISIBLE LWS_EXTERN unsigned char *
+unsigned char *
 lws_get_close_payload(struct lws *wsi)
 {
        return &wsi->ws->ping_payload_buf[LWS_PRE];
 }
 
-LWS_VISIBLE LWS_EXTERN void
+void
 lws_close_reason(struct lws *wsi, enum lws_close_status status,
                 unsigned char *buf, size_t len)
 {
@@ -981,14 +916,14 @@ lws_close_reason(struct lws *wsi, enum lws_close_status status,
 
        start = p = &wsi->ws->ping_payload_buf[LWS_PRE];
 
-       *p++ = (((int)status) >> 8) & 0xff;
-       *p++ = ((int)status) & 0xff;
+       *p++ = (uint8_t)((((int)status) >> 8) & 0xff);
+       *p++ = (uint8_t)(((int)status) & 0xff);
 
        if (buf)
                while (len-- && p < start + budget)
                        *p++ = *buf++;
 
-       wsi->ws->close_in_ping_buffer_len = lws_ptr_diff(p, start);
+       wsi->ws->close_in_ping_buffer_len = (uint8_t)lws_ptr_diff(p, start);
 }
 
 static int
@@ -1008,7 +943,7 @@ rops_handle_POLLIN_ws(struct lws_context_per_thread *pt, struct lws *wsi,
        unsigned int pending = 0;
        struct lws_tokens ebuf;
        char buffered = 0;
-       int n = 0, m;
+       int n = 0, m, sanity = 10;
 #if defined(LWS_WITH_HTTP2)
        struct lws *wsi1;
 #endif
@@ -1018,7 +953,7 @@ rops_handle_POLLIN_ws(struct lws_context_per_thread *pt, struct lws *wsi,
                return LWS_HPI_RET_PLEASE_CLOSE_ME;
        }
 
-       // lwsl_notice("%s: %s\n", __func__, wsi->protocol->name);
+       // lwsl_notice("%s: %s\n", __func__, wsi->a.protocol->name);
 
        //lwsl_info("%s: wsistate 0x%x, pollout %d\n", __func__,
        //         wsi->wsistate, pollfd->revents & LWS_POLLOUT);
@@ -1036,14 +971,14 @@ rops_handle_POLLIN_ws(struct lws_context_per_thread *pt, struct lws *wsi,
        ebuf.len = 0;
 
        if (lwsi_state(wsi) == LRS_WAITING_CONNECT) {
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
                if ((pollfd->revents & LWS_POLLOUT) &&
                    lws_handle_POLLOUT_event(wsi, pollfd)) {
                        lwsl_debug("POLLOUT event closed it\n");
                        return LWS_HPI_RET_PLEASE_CLOSE_ME;
                }
 
-               n = lws_client_socket_service(wsi, pollfd, NULL);
+               n = lws_http_client_socket_service(wsi, pollfd);
                if (n)
                        return LWS_HPI_RET_WSI_ALREADY_DIED;
 #endif
@@ -1106,7 +1041,7 @@ rops_handle_POLLIN_ws(struct lws_context_per_thread *pt, struct lws *wsi,
                return LWS_HPI_RET_HANDLED;
 
 #if defined(LWS_WITH_HTTP2)
-       if (wsi->http2_substream || wsi->upgraded_to_http2) {
+       if (wsi->mux_substream || wsi->upgraded_to_http2) {
                wsi1 = lws_get_network_wsi(wsi);
                if (wsi1 && lws_has_buffered_out(wsi1))
                        /* We cannot deal with any kind of new RX
@@ -1125,7 +1060,7 @@ rops_handle_POLLIN_ws(struct lws_context_per_thread *pt, struct lws *wsi,
        if (wsi->ws->rx_draining_ext) {
 
                lwsl_debug("%s: RX EXT DRAINING: Service\n", __func__);
-#ifndef LWS_NO_CLIENT
+#if defined(LWS_WITH_CLIENT)
                if (lwsi_role_client(wsi)) {
                        n = lws_ws_client_rx_sm(wsi, 0);
                        if (n < 0)
@@ -1150,7 +1085,7 @@ rops_handle_POLLIN_ws(struct lws_context_per_thread *pt, struct lws *wsi,
        /* 3: buflist needs to be drained
         */
 read:
-       //lws_buflist_describe(&wsi->buflist, wsi);
+       //lws_buflist_describe(&wsi->buflist, wsi, __func__);
        ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist,
                                                     &ebuf.token);
        if (ebuf.len) {
@@ -1185,19 +1120,19 @@ read:
                buffered = 0;
                ebuf.token = pt->serv_buf;
                if (lwsi_role_ws(wsi))
-                       ebuf.len = wsi->ws->rx_ubuf_alloc;
+                       ebuf.len = (int)wsi->ws->rx_ubuf_alloc;
                else
-                       ebuf.len = wsi->context->pt_serv_buf_size;
+                       ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
 
-               if ((unsigned int)ebuf.len > wsi->context->pt_serv_buf_size)
-                       ebuf.len = wsi->context->pt_serv_buf_size;
+               if ((unsigned int)ebuf.len > wsi->a.context->pt_serv_buf_size)
+                       ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
 
                if ((int)pending > ebuf.len)
-                       pending = ebuf.len;
+                       pending = (unsigned int)ebuf.len;
 
                ebuf.len = lws_ssl_capable_read(wsi, ebuf.token,
-                                               pending ? (int)pending :
-                                               ebuf.len);
+                                               (size_t)(pending ? pending :
+                                               (unsigned int)ebuf.len));
                switch (ebuf.len) {
                case 0:
                        lwsl_info("%s: zero length read\n",
@@ -1236,26 +1171,27 @@ drain:
        do {
 
                /* service incoming data */
-               //lws_buflist_describe(&wsi->buflist, wsi);
-               if (ebuf.len) {
+               //lws_buflist_describe(&wsi->buflist, wsi, __func__);
+               if (ebuf.len > 0) {
 #if defined(LWS_ROLE_H2)
                        if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY &&
                            lwsi_state(wsi) != LRS_DISCARD_BODY)
                                n = lws_read_h2(wsi, ebuf.token,
-                                            ebuf.len);
+                                            (unsigned int)ebuf.len);
                        else
 #endif
                                n = lws_read_h1(wsi, ebuf.token,
-                                            ebuf.len);
+                                            (unsigned int)ebuf.len);
 
                        if (n < 0) {
                                /* we closed wsi */
-                               n = 0;
                                return LWS_HPI_RET_WSI_ALREADY_DIED;
                        }
-                       //lws_buflist_describe(&wsi->buflist, wsi);
+                       //lws_buflist_describe(&wsi->buflist, wsi, __func__);
                        //lwsl_notice("%s: consuming %d / %d\n", __func__, n, ebuf.len);
-                       if (lws_buflist_aware_consume(wsi, &ebuf, n, buffered))
+                       if (ebuf.len < 0 ||
+                           lws_buflist_aware_finished_consuming(wsi, &ebuf, n,
+                                                       buffered, __func__))
                                return LWS_HPI_RET_PLEASE_CLOSE_ME;
                }
 
@@ -1264,7 +1200,7 @@ drain:
        } while (m);
 
        if (wsi->http.ah
-#if !defined(LWS_NO_CLIENT)
+#if defined(LWS_WITH_CLIENT)
                        && !wsi->client_h2_alpn
 #endif
                        ) {
@@ -1272,22 +1208,36 @@ drain:
                lws_header_table_detach(wsi, 0);
        }
 
-       pending = lws_ssl_pending(wsi);
+       pending = (unsigned int)lws_ssl_pending(wsi);
+
+#if defined(LWS_WITH_CLIENT)
+       if (!pending && (wsi->flags & LCCSCF_PRIORITIZE_READS) &&
+           lws_buflist_total_len(&wsi->buflist))
+               pending = 9999999;
+#endif
+
        if (pending) {
                if (lws_is_ws_with_ext(wsi))
                        pending = pending > wsi->ws->rx_ubuf_alloc ?
                                wsi->ws->rx_ubuf_alloc : pending;
                else
-                       pending = pending > wsi->context->pt_serv_buf_size ?
-                               wsi->context->pt_serv_buf_size : pending;
-               goto read;
+                       pending = pending > wsi->a.context->pt_serv_buf_size ?
+                               wsi->a.context->pt_serv_buf_size : pending;
+               if (--sanity)
+                       goto read;
+               else
+                       /*
+                        * Something has gone wrong, we are spinning...
+                        * let's bail on this connection
+                        */
+                       return LWS_HPI_RET_PLEASE_CLOSE_ME;
        }
 
        if (buffered && /* were draining, now nothing left */
            !lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
                lwsl_info("%s: %p flow buf: drained\n", __func__, wsi);
                /* having drained the rxflow buffer, can rearm POLLIN */
-#ifdef LWS_NO_SERVER
+#if !defined(LWS_WITH_SERVER)
                n =
 #endif
                __lws_rx_flow_control(wsi);
@@ -1301,7 +1251,6 @@ drain:
 
 int rops_handle_POLLOUT_ws(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
        int write_type = LWS_WRITE_PONG;
 #if !defined(LWS_WITHOUT_EXTENSIONS)
        struct lws_ext_pm_deflate_rx_ebufs pmdrx;
@@ -1311,7 +1260,7 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
 
 #if !defined(LWS_WITHOUT_EXTENSIONS)
        lwsl_debug("%s: %s: wsi->ws->tx_draining_ext %d\n", __func__,
-                       wsi->protocol->name, wsi->ws->tx_draining_ext);
+                       wsi->a.protocol->name, wsi->ws->tx_draining_ext);
 #endif
 
        /* Priority 3: pending control packets (pong or close)
@@ -1345,7 +1294,7 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
 
        /* else, the send failed and we should just hang up */
 
-       if ((lwsi_role_ws(wsi) && wsi->ws->ping_pending_flag) ||
+       if ((lwsi_role_ws(wsi) && wsi->ws->pong_pending_flag) ||
            (lwsi_state(wsi) == LRS_RETURNED_CLOSE &&
             wsi->ws->payload_is_close)) {
 
@@ -1354,20 +1303,20 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
                else {
                        if (wsi->wsistate_pre_close) {
                                /* we started close flow, forget pong */
-                               wsi->ws->ping_pending_flag = 0;
+                               wsi->ws->pong_pending_flag = 0;
                                return LWS_HP_RET_BAIL_OK;
                        }
-                       lwsl_info("issuing pong %d on wsi %p\n",
-                                 wsi->ws->ping_payload_len, wsi);
+                       lwsl_info("issuing pong %d on %s\n",
+                                 wsi->ws->pong_payload_len, lws_wsi_tag(wsi));
                }
 
-               n = lws_write(wsi, &wsi->ws->ping_payload_buf[LWS_PRE],
-                             wsi->ws->ping_payload_len, write_type);
+               n = lws_write(wsi, &wsi->ws->pong_payload_buf[LWS_PRE],
+                             wsi->ws->pong_payload_len, (enum lws_write_protocol)write_type);
                if (n < 0)
                        return LWS_HP_RET_BAIL_DIE;
 
                /* well he is sent, mark him done */
-               wsi->ws->ping_pending_flag = 0;
+               wsi->ws->pong_pending_flag = 0;
                if (wsi->ws->payload_is_close) {
                        // assert(0);
                        /* oh... a close frame was it... then we are done */
@@ -1379,24 +1328,18 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
        }
 
        if (!wsi->socket_is_permanently_unusable &&
-           wsi->ws->send_check_ping && wsi->context->ws_ping_pong_interval) {
+           wsi->ws->send_check_ping) {
 
-               lwsl_info("%s: issuing ping on wsi %p: %s %s h2: %d\n", __func__, wsi,
-                               wsi->role_ops->name, wsi->protocol->name,
-                               wsi->http2_substream);
+               lwsl_info("%s: issuing ping on wsi %s: %s %s h2: %d\n", __func__,
+                               lws_wsi_tag(wsi),
+                               wsi->role_ops->name, wsi->a.protocol->name,
+                               wsi->mux_substream);
                wsi->ws->send_check_ping = 0;
-               wsi->ws->await_pong = 1;
                n = lws_write(wsi, &wsi->ws->ping_payload_buf[LWS_PRE],
                              0, LWS_WRITE_PING);
                if (n < 0)
                        return LWS_HP_RET_BAIL_DIE;
 
-               /* give it a few seconds to respond with the PONG */
-
-               __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_ping,
-                                (lws_usec_t)wsi->context->timeout_secs *
-                                LWS_USEC_PER_SEC);
-
                return LWS_HP_RET_BAIL_OK;
        }
 
@@ -1438,8 +1381,11 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
         */
 
        ret = 1;
-       if (wsi->role_ops == &role_ops_raw_skt ||
-           wsi->role_ops == &role_ops_raw_file)
+       if (wsi->role_ops == &role_ops_raw_skt
+#if defined(LWS_ROLE_RAW_FILE)
+               || wsi->role_ops == &role_ops_raw_file
+#endif
+           )
                ret = 0;
 
        while (ret == 1) {
@@ -1469,7 +1415,7 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
 
                if (pmdrx.eb_in.len) {
                        n = lws_issue_raw(wsi, (unsigned char *)pmdrx.eb_in.token,
-                                       pmdrx.eb_in.len);
+                                       (unsigned int)pmdrx.eb_in.len);
                        if (n < 0) {
                                lwsl_info("closing from POLLOUT spill\n");
                                return LWS_HP_RET_BAIL_DIE;
@@ -1533,8 +1479,9 @@ rops_service_flag_pending_ws(struct lws_context *context, int tsi)
         */
        wsi = pt->ws.rx_draining_ext_list;
        while (wsi && wsi->position_in_fds_table != LWS_NO_FDS_POS) {
-               pt->fds[wsi->position_in_fds_table].revents |=
-                       pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
+               pt->fds[wsi->position_in_fds_table].revents =
+                       (short)((short)pt->fds[wsi->position_in_fds_table].revents |
+                       (short)(pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN));
                if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN)
                        forced = 1;
 
@@ -1618,8 +1565,8 @@ rops_close_role_ws(struct lws_context_per_thread *pt, struct lws *wsi)
 #endif
        lws_free_set_NULL(wsi->ws->rx_ubuf);
 
-       wsi->ws->ping_payload_len = 0;
-       wsi->ws->ping_pending_flag = 0;
+       wsi->ws->pong_payload_len = 0;
+       wsi->ws->pong_pending_flag = 0;
 
        /* deallocate any active extension contexts */
 
@@ -1633,8 +1580,8 @@ static int
 rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
                            enum lws_write_protocol *wp)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
 #if !defined(LWS_WITHOUT_EXTENSIONS)
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        enum lws_write_protocol wpt;
 #endif
        struct lws_ext_pm_deflate_rx_ebufs pmdrx;
@@ -1673,7 +1620,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
                 */
 
                if (!(wpt & LWS_WRITE_NO_FIN) && len)
-                       *wp &= ~LWS_WRITE_NO_FIN;
+                       *wp &= (enum lws_write_protocol)~LWS_WRITE_NO_FIN;
 
                lwsl_ext("FORCED draining wp to 0x%02X "
                         "(stashed 0x%02X, incoming 0x%02X)\n", *wp,
@@ -1681,13 +1628,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
                // assert(0);
        }
 #endif
-       /* reset the ping wait */
-       if (wsi->context->ws_ping_pong_interval) {
-               wsi->sul_ping.cb = lws_sul_wsping_cb;
-               __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_ping,
-                               (lws_usec_t)wsi->context->ws_ping_pong_interval *
-                                                               LWS_USEC_PER_SEC);
-       }
+
        if (((*wp) & 0x1f) == LWS_WRITE_HTTP ||
            ((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL ||
            ((*wp) & 0x1f) == LWS_WRITE_HTTP_HEADERS_CONTINUATION ||
@@ -1733,7 +1674,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
                break;
        default:
 #if !defined(LWS_WITHOUT_EXTENSIONS)
-               n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_TX, &pmdrx, *wp);
+               n = lws_ext_cb_active(wsi, (int)LWS_EXT_CB_PAYLOAD_TX, &pmdrx, (int)*wp);
                if (n < 0)
                        return -1;
                lwsl_ext("%s: defl ext ret %d, ext in remaining %d, "
@@ -1758,7 +1699,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
                         * action that has provoked generation of these
                         * fragments, so the last guy can use its FIN state.
                         */
-                       wsi->ws->tx_draining_stashed_wp = *wp;
+                       wsi->ws->tx_draining_stashed_wp = (uint8_t)*wp;
                        /*
                         * Despite what we may have thought, this is definitely
                         * NOT the last fragment, because the extension asserted
@@ -1774,7 +1715,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
 #endif
                if (pmdrx.eb_out.len && wsi->ws->stashed_write_pending) {
                        wsi->ws->stashed_write_pending = 0;
-                       *wp = ((*wp) & 0xc0) | (int)wsi->ws->stashed_write_type;
+                       *wp = (unsigned int)(((*wp) & 0xc0) | (unsigned int)wsi->ws->stashed_write_type);
                }
        }
 
@@ -1804,7 +1745,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
        }
 
        buf = pmdrx.eb_out.token;
-       len = pmdrx.eb_out.len;
+       len = (unsigned int)pmdrx.eb_out.len;
 
        if (!buf) {
                lwsl_err("null buf (%d)\n", (int)len);
@@ -1849,24 +1790,24 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
 
                if (len < 126) {
                        pre += 2;
-                       buf[-pre] = n;
+                       buf[-pre] = (uint8_t)n;
                        buf[-pre + 1] = (unsigned char)(len | is_masked_bit);
                } else {
                        if (len < 65536) {
                                pre += 4;
-                               buf[-pre] = n;
-                               buf[-pre + 1] = 126 | is_masked_bit;
+                               buf[-pre] = (uint8_t)n;
+                               buf[-pre + 1] = (uint8_t)(126 | is_masked_bit);
                                buf[-pre + 2] = (unsigned char)(len >> 8);
                                buf[-pre + 3] = (unsigned char)len;
                        } else {
                                pre += 10;
-                               buf[-pre] = n;
-                               buf[-pre + 1] = 127 | is_masked_bit;
+                               buf[-pre] = (uint8_t)n;
+                               buf[-pre + 1] = (uint8_t)(127 | is_masked_bit);
 #if defined __LP64__
                                        buf[-pre + 2] = (len >> 56) & 0x7f;
-                                       buf[-pre + 3] = len >> 48;
-                                       buf[-pre + 4] = len >> 40;
-                                       buf[-pre + 5] = len >> 32;
+                                       buf[-pre + 3] = (uint8_t)(len >> 48);
+                                       buf[-pre + 4] = (uint8_t)(len >> 40);
+                                       buf[-pre + 5] = (uint8_t)(len >> 32);
 #else
                                        buf[-pre + 2] = 0;
                                        buf[-pre + 3] = 0;
@@ -1913,8 +1854,11 @@ do_more_inside_frame:
                struct lws *encap = lws_get_network_wsi(wsi);
 
                assert(encap != wsi);
-               return encap->role_ops->write_role_protocol(wsi, buf - pre,
-                                                           len + pre, wp);
+
+               return lws_rops_func_fidx(encap->role_ops,
+                                  LWS_ROPS_write_role_protocol).
+                                       write_role_protocol(wsi, buf - pre,
+                                                           len + (unsigned int)pre, wp);
        }
 
        switch ((*wp) & 0x1f) {
@@ -1946,7 +1890,7 @@ do_more_inside_frame:
                         * consumed.
                         */
 
-                       n = lws_issue_raw_ext_access(wsi, buf - pre, len + pre);
+                       n = lws_issue_raw_ext_access(wsi, buf - pre, len + (unsigned int)pre);
                        wsi->ws->inside_frame = 1;
                        if (n <= 0)
                                return n;
@@ -1973,17 +1917,18 @@ do_more_inside_frame:
        }
 
 send_raw:
-       return lws_issue_raw(wsi, (unsigned char *)buf - pre, len + pre);
+       return lws_issue_raw(wsi, (unsigned char *)buf - pre, len + (unsigned int)pre);
 }
 
 static int
 rops_close_kill_connection_ws(struct lws *wsi, enum lws_close_status reason)
 {
-       lws_dll2_remove(&wsi->sul_ping.list);
        /* deal with ws encapsulation in h2 */
 #if defined(LWS_WITH_HTTP2)
-       if (wsi->http2_substream && wsi->h2_stream_carries_ws)
-               return role_ops_h2.close_kill_connection(wsi, reason);
+       if (wsi->mux_substream && wsi->h2_stream_carries_ws)
+               return lws_rops_func_fidx(&role_ops_h2,
+                                  LWS_ROPS_close_kill_connection).
+                               close_kill_connection(wsi, reason);
 
        return 0;
 #else
@@ -1997,10 +1942,14 @@ rops_callback_on_writable_ws(struct lws *wsi)
 #if defined(LWS_WITH_HTTP2)
        if (lwsi_role_h2_ENCAPSULATION(wsi)) {
                /* we know then that it has an h2 parent */
-               struct lws *enc = role_ops_h2.encapsulation_parent(wsi);
+               struct lws *enc = lws_rops_func_fidx(&role_ops_h2,
+                                                    LWS_ROPS_encapsulation_parent).
+                                                    encapsulation_parent(wsi);
 
                assert(enc);
-               if (enc->role_ops->callback_on_writable(wsi))
+               if (lws_rops_func_fidx(enc->role_ops,
+                                      LWS_ROPS_callback_on_writable).
+                                               callback_on_writable(wsi))
                        return 1;
        }
 #endif
@@ -2013,7 +1962,7 @@ rops_init_vhost_ws(struct lws_vhost *vh,
 {
 #if !defined(LWS_WITHOUT_EXTENSIONS)
 #ifdef LWS_WITH_PLUGINS
-       struct lws_plugin *plugin = vh->context->plugin_list;
+       struct lws_plugin *plugin;
        int m;
 
        if (vh->context->plugin_extension_count) {
@@ -2027,20 +1976,23 @@ rops_init_vhost_ws(struct lws_vhost *vh,
                 * ones that came from plugins
                 */
                vh->ws.extensions = lws_zalloc(sizeof(struct lws_extension) *
-                                    (m + vh->context->plugin_extension_count + 1),
+                                    (unsigned int)(m + vh->context->plugin_extension_count + 1),
                                     "extensions");
                if (!vh->ws.extensions)
                        return 1;
 
                memcpy((struct lws_extension *)vh->ws.extensions, info->extensions,
-                      sizeof(struct lws_extension) * m);
+                      sizeof(struct lws_extension) * (unsigned int)m);
                plugin = vh->context->plugin_list;
                while (plugin) {
+                       const lws_plugin_protocol_t *plpr =
+                               (const lws_plugin_protocol_t *)plugin->hdr;
+
                        memcpy((struct lws_extension *)&vh->ws.extensions[m],
-                               plugin->caps.extensions,
+                               plpr->extensions,
                               sizeof(struct lws_extension) *
-                              plugin->caps.count_extensions);
-                       m += plugin->caps.count_extensions;
+                              (unsigned int)plpr->count_extensions);
+                       m += plpr->count_extensions;
                        plugin = plugin->list;
                }
        } else
@@ -2086,29 +2038,80 @@ rops_destroy_role_ws(struct lws *wsi)
        return 0;
 }
 
-struct lws_role_ops role_ops_ws = {
+static int
+rops_issue_keepalive_ws(struct lws *wsi, int isvalid)
+{
+       uint64_t us;
+
+#if defined(LWS_WITH_HTTP2)
+       if (lwsi_role_h2_ENCAPSULATION(wsi)) {
+               /* we know then that it has an h2 parent */
+               struct lws *enc = lws_rops_func_fidx(&role_ops_h2,
+                                                    LWS_ROPS_encapsulation_parent).
+                                                    encapsulation_parent(wsi);
+
+               assert(enc);
+               if (lws_rops_func_fidx(enc->role_ops, LWS_ROPS_issue_keepalive).
+                                                 issue_keepalive(enc, isvalid))
+                       return 1;
+       }
+#endif
+
+       if (isvalid)
+               _lws_validity_confirmed_role(wsi);
+       else {
+               us = (uint64_t)lws_now_usecs();
+               memcpy(&wsi->ws->ping_payload_buf[LWS_PRE], &us, 8);
+               wsi->ws->send_check_ping = 1;
+               lws_callback_on_writable(wsi);
+       }
+
+       return 0;
+}
+
+static const lws_rops_t rops_table_ws[] = {
+       /*  1 */ { .init_vhost              = rops_init_vhost_ws },
+       /*  2 */ { .destroy_vhost           = rops_destroy_vhost_ws },
+       /*  3 */ { .service_flag_pending    = rops_service_flag_pending_ws },
+       /*  4 */ { .handle_POLLIN           = rops_handle_POLLIN_ws },
+       /*  5 */ { .handle_POLLOUT          = rops_handle_POLLOUT_ws },
+       /*  6 */ { .callback_on_writable    = rops_callback_on_writable_ws },
+       /*  7 */ { .write_role_protocol     = rops_write_role_protocol_ws },
+       /*  8 */ { .close_via_role_protocol = rops_close_via_role_protocol_ws },
+       /*  9 */ { .close_role              = rops_close_role_ws },
+       /* 10 */ { .close_kill_connection   = rops_close_kill_connection_ws },
+       /* 11 */ { .destroy_role            = rops_destroy_role_ws },
+       /* 12 */ { .issue_keepalive         = rops_issue_keepalive_ws },
+};
+
+const struct lws_role_ops role_ops_ws = {
        /* role name */                 "ws",
        /* alpn id */                   NULL,
-       /* check_upgrades */            NULL,
-       /* init_context */              NULL,
-       /* init_vhost */                rops_init_vhost_ws,
-       /* destroy_vhost */             rops_destroy_vhost_ws,
-       /* periodic_checks */           NULL,
-       /* service_flag_pending */      rops_service_flag_pending_ws,
-       /* handle_POLLIN */             rops_handle_POLLIN_ws,
-       /* handle_POLLOUT */            rops_handle_POLLOUT_ws,
-       /* perform_user_POLLOUT */      NULL,
-       /* callback_on_writable */      rops_callback_on_writable_ws,
-       /* tx_credit */                 NULL,
-       /* write_role_protocol */       rops_write_role_protocol_ws,
-       /* encapsulation_parent */      NULL,
-       /* alpn_negotiated */           NULL,
-       /* close_via_role_protocol */   rops_close_via_role_protocol_ws,
-       /* close_role */                rops_close_role_ws,
-       /* close_kill_connection */     rops_close_kill_connection_ws,
-       /* destroy_role */              rops_destroy_role_ws,
-       /* adoption_bind */             NULL,
-       /* client_bind */               NULL,
+
+       /* rops_table */                rops_table_ws,
+       /* rops_idx */                  {
+         /* LWS_ROPS_check_upgrades */
+         /* LWS_ROPS_pt_init_destroy */                0x00,
+         /* LWS_ROPS_init_vhost */
+         /* LWS_ROPS_destroy_vhost */                  0x12,
+         /* LWS_ROPS_service_flag_pending */
+         /* LWS_ROPS_handle_POLLIN */                  0x34,
+         /* LWS_ROPS_handle_POLLOUT */
+         /* LWS_ROPS_perform_user_POLLOUT */           0x50,
+         /* LWS_ROPS_callback_on_writable */
+         /* LWS_ROPS_tx_credit */                      0x60,
+         /* LWS_ROPS_write_role_protocol */
+         /* LWS_ROPS_encapsulation_parent */           0x70,
+         /* LWS_ROPS_alpn_negotiated */
+         /* LWS_ROPS_close_via_role_protocol */        0x08,
+         /* LWS_ROPS_close_role */
+         /* LWS_ROPS_close_kill_connection */          0x9a,
+         /* LWS_ROPS_destroy_role */
+         /* LWS_ROPS_adoption_bind */                  0xb0,
+         /* LWS_ROPS_client_bind */
+         /* LWS_ROPS_issue_keepalive */                0x0c,
+                                       },
+
        /* adoption_cb clnt, srv */     { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
                                          LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
        /* rx_cb clnt, srv */           { LWS_CALLBACK_CLIENT_RECEIVE,
similarity index 74%
rename from lib/roles/ws/private.h
rename to lib/roles/ws/private-lib-roles-ws.h
index 001b8f1..d0b0870 100644 (file)
@@ -1,27 +1,30 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
- *  This is included from core/private.h if LWS_ROLE_WS
+ *  This is included from private-lib-core.h if LWS_ROLE_WS
  */
 
-extern struct lws_role_ops role_ops_ws;
+extern const struct lws_role_ops role_ops_ws;
 
 #define lwsi_role_ws(wsi) (wsi->role_ops == &role_ops_ws)
 
@@ -84,6 +87,8 @@ struct lws_pt_role_ws {
 };
 #endif
 
+#define PAYLOAD_BUF_SIZE 128 - 3 + LWS_PRE
+
 struct _lws_websocket_related {
        unsigned char *rx_ubuf;
 #if !defined(LWS_WITHOUT_EXTENSIONS)
@@ -100,24 +105,8 @@ struct _lws_websocket_related {
 #endif
 
        /* Also used for close content... control opcode == < 128 */
-       uint8_t ping_payload_buf[128 - 3 + LWS_PRE];
-       uint8_t mask[4];
-
-       size_t rx_packet_length;
-       uint32_t rx_ubuf_head;
-       uint32_t rx_ubuf_alloc;
-
-       uint8_t ping_payload_len;
-       uint8_t mask_idx;
-       uint8_t opcode;
-       uint8_t rsv;
-       uint8_t rsv_first_msg;
-       /* zero if no info, or length including 2-byte close code */
-       uint8_t close_in_ping_buffer_len;
-       uint8_t utf8;
-       uint8_t stashed_write_type;
-       uint8_t tx_draining_stashed_wp;
-       uint8_t ietf_spec_revision;
+       uint8_t ping_payload_buf[PAYLOAD_BUF_SIZE];
+       uint8_t pong_payload_buf[PAYLOAD_BUF_SIZE];
 
        unsigned int final:1;
        unsigned int frame_is_binary:1;
@@ -126,7 +115,7 @@ struct _lws_websocket_related {
        unsigned int inside_frame:1; /* next write will be more of frame */
        unsigned int clean_buffer:1; /* buffer not rewritten by extension */
        unsigned int payload_is_close:1; /* process as PONG, but it is close */
-       unsigned int ping_pending_flag:1;
+       unsigned int pong_pending_flag:1;
        unsigned int continuation_possible:1;
        unsigned int owed_a_fin:1;
        unsigned int check_utf8:1;
@@ -135,13 +124,31 @@ struct _lws_websocket_related {
        unsigned int send_check_ping:1;
        unsigned int first_fragment:1;
        unsigned int peer_has_sent_close:1;
-       unsigned int await_pong;
 #if !defined(LWS_WITHOUT_EXTENSIONS)
        unsigned int extension_data_pending:1;
        unsigned int rx_draining_ext:1;
        unsigned int tx_draining_ext:1;
        unsigned int pmd_trailer_application:1;
+#endif
+
+       uint8_t mask[4];
 
+       size_t rx_packet_length;
+       uint32_t rx_ubuf_head;
+       uint32_t rx_ubuf_alloc;
+
+       uint8_t pong_payload_len;
+       uint8_t mask_idx;
+       uint8_t opcode;
+       uint8_t rsv;
+       uint8_t rsv_first_msg;
+       /* zero if no info, or length including 2-byte close code */
+       uint8_t close_in_ping_buffer_len;
+       uint8_t utf8;
+       uint8_t stashed_write_type;
+       uint8_t tx_draining_stashed_wp;
+       uint8_t ietf_spec_revision;
+#if !defined(LWS_WITHOUT_EXTENSIONS)
        uint8_t count_act_ext;
 #endif
 };
index 680c2e6..b8469a4 100644 (file)
@@ -1,25 +1,28 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include <core/private.h>
+#include <private-lib-core.h>
 
 #define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
 
@@ -27,7 +30,7 @@
 static int
 lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        char ext_name[64], *args, *end = (*p) + budget - 1;
        const struct lws_ext_options *opts, *po;
@@ -50,7 +53,7 @@ lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
         * and go through them
         */
 
-       if (lws_hdr_copy(wsi, (char *)pt->serv_buf, context->pt_serv_buf_size,
+       if (lws_hdr_copy(wsi, (char *)pt->serv_buf, (int)context->pt_serv_buf_size,
                         WSI_TOKEN_EXTENSIONS) < 0)
                return 1;
 
@@ -109,7 +112,7 @@ lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
 
                /* check a client's extension against our support */
 
-               ext = wsi->vhost->ws.extensions;
+               ext = wsi->a.vhost->ws.extensions;
 
                while (ext && ext->callback) {
 
@@ -132,7 +135,7 @@ lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
                         * ask user code if it's OK to apply it on this
                         * particular connection + protocol
                         */
-                       m = (wsi->protocol->callback)(wsi,
+                       m = (wsi->a.protocol->callback)(wsi,
                                LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
                                wsi->user_space, ext_name, 0);
 
@@ -174,7 +177,7 @@ lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
                        else
                                LWS_CPYAPP(*p,
                                          "\x0d\x0aSec-WebSocket-Extensions: ");
-                       *p += lws_snprintf(*p, (end - *p), "%s", ext_name);
+                       *p += lws_snprintf(*p, lws_ptr_diff_size_t(end, *p), "%s", ext_name);
 
                        /*
                         * The client may send a bunch of different option
@@ -213,10 +216,10 @@ lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
                                                LWS_EXT_CB_OPTION_SET,
                                                wsi->ws->act_ext_user[
                                                        wsi->ws->count_act_ext],
-                                                         &oa, (end - *p))) {
+                                                         &oa, lws_ptr_diff_size_t(end, *p))) {
 
                                                *p += lws_snprintf(*p,
-                                                                  (end - *p),
+                                                                  lws_ptr_diff_size_t(end, *p),
                                                              "; %s", po->name);
                                                lwsl_debug("adding option %s\n",
                                                           po->name);
@@ -251,10 +254,12 @@ lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
 int
 lws_process_ws_upgrade2(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+#if defined(LWS_WITH_HTTP_BASIC_AUTH)
        const struct lws_protocol_vhost_options *pvos = NULL;
        const char *ws_prot_basic_auth = NULL;
 
+
        /*
         * Allow basic auth a look-in now we bound the wsi to the protocol.
         *
@@ -263,12 +268,13 @@ lws_process_ws_upgrade2(struct lws *wsi)
         * section, as a pvo.
         */
 
-       pvos = lws_vhost_protocol_options(wsi->vhost, wsi->protocol->name);
+       pvos = lws_vhost_protocol_options(wsi->a.vhost, wsi->a.protocol->name);
        if (pvos && pvos->options &&
            !lws_pvo_get_str((void *)pvos->options, "basic-auth",
                             &ws_prot_basic_auth)) {
                lwsl_info("%s: ws upgrade requires basic auth\n", __func__);
-               switch(lws_check_basic_auth(wsi, ws_prot_basic_auth)) {
+               switch (lws_check_basic_auth(wsi, ws_prot_basic_auth, LWSAUTHM_DEFAULT
+                                               /* no callback based auth here */)) {
                case LCBA_CONTINUE:
                        break;
                case LCBA_FAILED_AUTH:
@@ -278,6 +284,7 @@ lws_process_ws_upgrade2(struct lws *wsi)
                        return lws_http_transaction_completed(wsi);
                }
        }
+#endif
 
        /*
         * We are upgrading to ws, so http/1.1 + h2 and keepalive + pipelined
@@ -290,10 +297,37 @@ lws_process_ws_upgrade2(struct lws *wsi)
 
        lws_pt_lock(pt, __func__);
 
-       if (!wsi->h2_stream_carries_ws)
+       /*
+        * Switch roles if we're upgrading away from http
+        */
+
+       if (!wsi->h2_stream_carries_ws) {
                lws_role_transition(wsi, LWSIFR_SERVER, LRS_ESTABLISHED,
                                    &role_ops_ws);
 
+#if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SERVER)
+
+               /*
+                * If we're a SS server object, we have to switch to ss-ws
+                * protocol handler too
+                */
+               if (wsi->a.vhost->ss_handle) {
+                       lwsl_info("%s: %s switching to ws protocol\n",
+                                 __func__, lws_ss_tag(wsi->a.vhost->ss_handle));
+                       wsi->a.protocol = &protocol_secstream_ws;
+
+                       /*
+                        * inform the SS user code that this has done a one-way
+                        * upgrade to some other protocol... it will likely
+                        * want to treat subsequent payloads differently
+                        */
+
+                       (void)lws_ss_event_helper(wsi->a.vhost->ss_handle,
+                                               LWSSSCS_SERVER_UPGRADE);
+               }
+#endif
+       }
+
        lws_pt_unlock(pt);
 
        /* allocate the ws struct for the wsi */
@@ -305,7 +339,7 @@ lws_process_ws_upgrade2(struct lws *wsi)
        }
 
        if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
-               wsi->ws->ietf_spec_revision =
+               wsi->ws->ietf_spec_revision = (uint8_t)
                               atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
 
        /* allocate wsi->user storage */
@@ -318,7 +352,7 @@ lws_process_ws_upgrade2(struct lws *wsi)
         * Give the user code a chance to study the request and
         * have the opportunity to deny it
         */
-       if ((wsi->protocol->callback)(wsi,
+       if ((wsi->a.protocol->callback)(wsi,
                        LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
                        wsi->user_space,
                      lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
@@ -348,11 +382,19 @@ lws_process_ws_upgrade2(struct lws *wsi)
                        lws_role_transition(wsi,
                                            LWSIFR_SERVER | LWSIFR_P_ENCAP_H2,
                                            LRS_ESTABLISHED, &role_ops_ws);
+
+                       /*
+                        * There should be no validity checking since we
+                        * are encapsulated in something else with its own
+                        * validity checking
+                        */
+
+                       lws_sul_cancel(&wsi->sul_validity);
                } else
 #endif
                {
                        lwsl_parser("lws_parse calling handshake_04\n");
-                       if (handshake_0405(wsi->context, wsi)) {
+                       if (handshake_0405(wsi->a.context, wsi)) {
                                lwsl_notice("hs0405 has failed the connection\n");
                                return 1;
                        }
@@ -360,28 +402,34 @@ lws_process_ws_upgrade2(struct lws *wsi)
                break;
        }
 
-       lws_server_init_wsi_for_ws(wsi);
+       if (lws_server_init_wsi_for_ws(wsi)) {
+               lwsl_notice("%s: user ESTABLISHED failed connection\n", __func__);
+               return 1;
+       }
        lwsl_parser("accepted v%02d connection\n", wsi->ws->ietf_spec_revision);
 
 #if defined(LWS_WITH_ACCESS_LOG)
        {
-               char *uptr = NULL, combo[128];
-               int l, meth = lws_http_get_uri_and_method(wsi, &uptr, &l);
+               char *uptr = "unknown method", combo[128], dotstar[64];
+               int l = 14, meth = lws_http_get_uri_and_method(wsi, &uptr, &l);
 
                if (wsi->h2_stream_carries_ws)
                        wsi->http.request_version = HTTP_VERSION_2;
 
                wsi->http.access_log.response = 101;
 
-               l = lws_snprintf(combo, sizeof(combo), "%.*s (%s)", l, uptr,
-                                wsi->protocol->name);
+               lws_strnncpy(dotstar, uptr, l, sizeof(dotstar));
+               l = lws_snprintf(combo, sizeof(combo), "%s (%s)", dotstar,
+                                wsi->a.protocol->name);
 
+               if (meth < 0)
+                       meth = 0;
                lws_prepare_access_log_info(wsi, combo, l, meth);
                lws_access_log(wsi);
        }
 #endif
 
-       lwsl_info("%s: %p: dropping ah on ws upgrade\n", __func__, wsi);
+       lwsl_info("%s: %s: dropping ah on ws upgrade\n", __func__, lws_wsi_tag(wsi));
        lws_header_table_detach(wsi, 1);
 
        return 0;
@@ -394,8 +442,9 @@ lws_process_ws_upgrade(struct lws *wsi)
        char buf[128], name[64];
        struct lws_tokenize ts;
        lws_tokenize_elem e;
+       int n;
 
-       if (!wsi->protocol)
+       if (!wsi->a.protocol)
                lwsl_err("NULL protocol at lws_read\n");
 
        /*
@@ -406,17 +455,17 @@ lws_process_ws_upgrade(struct lws *wsi)
         */
 
 #if defined(LWS_WITH_HTTP2)
-       if (!wsi->http2_substream) {
+       if (!wsi->mux_substream) {
 #endif
 
                lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_COMMA_SEP_LIST |
                                            LWS_TOKENIZE_F_DOT_NONTERM |
                                            LWS_TOKENIZE_F_RFC7230_DELIMS |
                                            LWS_TOKENIZE_F_MINUS_NONTERM);
-               ts.len = lws_hdr_copy(wsi, buf, sizeof(buf) - 1,
-                                     WSI_TOKEN_CONNECTION);
-               if (ts.len <= 0)
+               n = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_CONNECTION);
+               if (n <= 0)
                        goto bad_conn_format;
+               ts.len = (unsigned int)n;
 
                do {
                        e = lws_tokenize(&ts);
@@ -451,7 +500,9 @@ lws_process_ws_upgrade(struct lws *wsi)
                meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
                hit = lws_find_mount(wsi, uri_ptr, uri_len);
 
-               if (hit && (meth == 0 || meth == 8) &&
+               if (hit && (meth == LWSHUMETH_GET ||
+                           meth == LWSHUMETH_CONNECT ||
+                           meth == LWSHUMETH_COLON_PATH) &&
                    (hit->origin_protocol == LWSMPRO_HTTPS ||
                     hit->origin_protocol == LWSMPRO_HTTP))
                        /*
@@ -478,13 +529,14 @@ lws_process_ws_upgrade(struct lws *wsi)
                                    LWS_TOKENIZE_F_MINUS_NONTERM |
                                    LWS_TOKENIZE_F_DOT_NONTERM |
                                    LWS_TOKENIZE_F_RFC7230_DELIMS);
-       ts.len = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_PROTOCOL);
-       if (ts.len < 0) {
+       n = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_PROTOCOL);
+       if (n < 0) {
                lwsl_err("%s: protocol list too long\n", __func__);
                return 1;
        }
+       ts.len = (unsigned int)n;
        if (!ts.len) {
-               int n = wsi->vhost->default_protocol_index;
+               int n = wsi->a.vhost->default_protocol_index;
                /*
                 * Some clients only have one protocol and do not send the
                 * protocol list header... allow it and match to the vhost's
@@ -495,7 +547,7 @@ lws_process_ws_upgrade(struct lws *wsi)
                 * these "no protocol" ws connections to be rejected.
                 */
 
-               if (n >= wsi->vhost->count_protocols) {
+               if (n >= wsi->a.vhost->count_protocols) {
                        lwsl_notice("%s: rejecting ws upg with no protocol\n",
                                    __func__);
 
@@ -504,12 +556,39 @@ lws_process_ws_upgrade(struct lws *wsi)
 
                lwsl_info("%s: defaulting to prot handler %d\n", __func__, n);
 
-               lws_bind_protocol(wsi, &wsi->vhost->protocols[n],
+               lws_bind_protocol(wsi, &wsi->a.vhost->protocols[n],
                                  "ws upgrade default pcol");
 
                goto alloc_ws;
        }
 
+#if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SERVER)
+       if (wsi->a.vhost->ss_handle) {
+               lws_ss_handle_t *sssh = wsi->a.vhost->ss_handle;
+
+               /*
+                * At the moment, once we see it's a ss ws server, whatever
+                * he asked for we bind him to the ss-ws protocol handler.
+                *
+                * In the response subprotocol header, we need to name
+                *
+                * sssh->policy->u.http.u.ws.subprotocol
+                *
+                * though...
+                */
+
+               if (sssh->policy->u.http.u.ws.subprotocol) {
+                       pcol = lws_vhost_name_to_protocol(wsi->a.vhost,
+                                                         "lws-secstream-ws");
+                       if (pcol) {
+                               lws_bind_protocol(wsi, pcol, "ss ws upg pcol");
+
+                               goto alloc_ws;
+                       }
+               }
+       }
+#endif
+
        /* otherwise go through the user-provided protocol list */
 
        do {
@@ -523,7 +602,7 @@ lws_process_ws_upgrade(struct lws *wsi)
                                return 1;
                        }
                        lwsl_debug("checking %s\n", name);
-                       pcol = lws_vhost_name_to_protocol(wsi->vhost, name);
+                       pcol = lws_vhost_name_to_protocol(wsi->a.vhost, name);
                        if (pcol) {
                                /* if we know it, bind to it and stop looking */
                                lws_bind_protocol(wsi, pcol, "ws upg pcol");
@@ -586,10 +665,10 @@ handshake_0405(struct lws_context *context, struct lws *wsi)
                    "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
                    lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY));
 
-       lws_SHA1(pt->serv_buf, n, hash);
+       lws_SHA1(pt->serv_buf, (unsigned int)n, hash);
 
        accept_len = lws_b64_encode_string((char *)hash, 20,
-                       (char *)pt->serv_buf, context->pt_serv_buf_size);
+                       (char *)pt->serv_buf, (int)context->pt_serv_buf_size);
        if (accept_len < 0) {
                lwsl_warn("Base64 encoded hash too long\n");
                goto bail;
@@ -617,15 +696,36 @@ handshake_0405(struct lws_context *context, struct lws *wsi)
         *  - one came in, and ... */
        if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) &&
            /*  - it is not an empty string */
-           wsi->protocol->name &&
-           wsi->protocol->name[0]) {
-               const char *prot = wsi->protocol->name;
+           wsi->a.protocol->name &&
+           wsi->a.protocol->name[0]) {
+               const char *prot = wsi->a.protocol->name;
 
 #if defined(LWS_WITH_HTTP_PROXY)
                if (wsi->proxied_ws_parent && wsi->child_list)
                        prot = wsi->child_list->ws->actual_protocol;
 #endif
 
+#if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SERVER)
+               {
+                       lws_ss_handle_t *sssh = wsi->a.vhost->ss_handle;
+
+                       /*
+                        * At the moment, once we see it's a ss ws server, whatever
+                        * he asked for we bind him to the ss-ws protocol handler.
+                        *
+                        * In the response subprotocol header, we need to name
+                        *
+                        * sssh->policy->u.http.u.ws.subprotocol
+                        *
+                        * though...
+                        */
+
+                       if (sssh && sssh->policy &&
+                           sssh->policy->u.http.u.ws.subprotocol)
+                               prot = sssh->policy->u.http.u.ws.subprotocol;
+               }
+#endif
+
                LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
                p += lws_snprintf(p, 128, "%s", prot);
        }
@@ -645,7 +745,7 @@ handshake_0405(struct lws_context *context, struct lws *wsi)
        args.p = p;
        args.max_len = lws_ptr_diff((char *)pt->serv_buf +
                                    context->pt_serv_buf_size, p);
-       if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
+       if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
                                        LWS_CALLBACK_ADD_HEADERS,
                                        wsi->user_space, &args, 0))
                goto bail;
@@ -663,9 +763,9 @@ handshake_0405(struct lws_context *context, struct lws *wsi)
 #if defined(DEBUG)
        fwrite(response, 1,  p - response, stderr);
 #endif
-       n = lws_write(wsi, (unsigned char *)response, p - response,
+       n = lws_write(wsi, (unsigned char *)response, lws_ptr_diff_size_t(p, response),
                      LWS_WRITE_HTTP_HEADERS);
-       if (n != (p - response)) {
+       if (n != lws_ptr_diff(p, response)) {
                lwsl_info("%s: ERROR writing to socket %d\n", __func__, n);
                goto bail;
        }
@@ -682,7 +782,7 @@ handshake_0405(struct lws_context *context, struct lws *wsi)
                const struct lws_http_mount *hit =
                        lws_find_mount(wsi, uri_ptr, uri_len);
                if (hit && hit->cgienv &&
-                   wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO,
+                   wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO,
                        wsi->user_space, (void *)hit->cgienv, 0))
                        return 1;
        }
@@ -708,7 +808,7 @@ lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
        unsigned int avail = (unsigned int)len;
        uint8_t *buffer = *buf, mask[4];
 #if !defined(LWS_WITHOUT_EXTENSIONS)
-       unsigned int old_packet_length = (int)wsi->ws->rx_packet_length;
+       unsigned int old_packet_length = (unsigned int)wsi->ws->rx_packet_length;
 #endif
        int n = 0;
 
@@ -724,10 +824,10 @@ lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
        if (!wsi->ws->count_act_ext)
 #endif
        {
-               if (wsi->protocol->rx_buffer_size)
-                       avail = (int)wsi->protocol->rx_buffer_size;
+               if (wsi->a.protocol->rx_buffer_size)
+                       avail = (unsigned int)wsi->a.protocol->rx_buffer_size;
                else
-                       avail = wsi->context->pt_serv_buf_size;
+                       avail = wsi->a.context->pt_serv_buf_size;
        }
 
        /* do not consume more than we should */
@@ -742,9 +842,9 @@ lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
                return 0;
 
        pmdrx.eb_in.token = buffer;
-       pmdrx.eb_in.len = avail;
+       pmdrx.eb_in.len = (int)avail;
        pmdrx.eb_out.token = buffer;
-       pmdrx.eb_out.len = avail;
+       pmdrx.eb_out.len = (int)avail;
 
        if (!wsi->ws->all_zero_nonce) {
 
@@ -752,7 +852,7 @@ lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
                        mask[n] = wsi->ws->mask[(wsi->ws->mask_idx + n) & 3];
 
                /* deal with 4-byte chunks using unwrapped loop */
-               n = avail >> 2;
+               n = (int)(avail >> 2);
                while (n--) {
                        *(buffer) = *(buffer) ^ mask[0];
                        buffer++;
@@ -814,17 +914,17 @@ lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
            old_packet_length &&            /* we gave the inflator new input */
            !wsi->ws->rx_packet_length &&   /* raw ws packet payload all gone */
            wsi->ws->final &&               /* the raw ws packet is a FIN guy */
-           wsi->protocol->callback &&
+           wsi->a.protocol->callback &&
            !wsi->wsistate_pre_close) {
 
                lwsl_ext("%s: issuing zero length FIN pkt\n", __func__);
 
-               if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
+               if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
                                                LWS_CALLBACK_RECEIVE,
                                                wsi->user_space, NULL, 0))
                        return -1;
 
-               return avail;
+               return (int)avail;
        }
 
        /*
@@ -832,7 +932,7 @@ lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
         * length receive.  Otherwise we're more willing.
         */
        if (wsi->ws->count_act_ext && !pmdrx.eb_out.len)
-               return avail;
+               return (int)avail;
 
        if (n == PMDR_HAS_PENDING)
                /* extension had more... main loop will come back */
@@ -845,7 +945,7 @@ lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
            wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) {
                if (lws_check_utf8(&wsi->ws->utf8,
                                   pmdrx.eb_out.token,
-                                  pmdrx.eb_out.len)) {
+                                  (unsigned int)pmdrx.eb_out.len)) {
                        lws_close_reason(wsi, LWS_CLOSE_STATUS_INVALID_PAYLOAD,
                                         (uint8_t *)"bad utf8", 8);
                        goto utf8_fail;
@@ -860,18 +960,18 @@ lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
 
 utf8_fail:
                        lwsl_info("utf8 error\n");
-                       lwsl_hexdump_info(pmdrx.eb_out.token, pmdrx.eb_out.len);
+                       lwsl_hexdump_info(pmdrx.eb_out.token, (size_t)pmdrx.eb_out.len);
 
                        return -1;
                }
        }
 
-       if (wsi->protocol->callback && !wsi->wsistate_pre_close)
-               if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
+       if (wsi->a.protocol->callback && !wsi->wsistate_pre_close)
+               if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi,
                                                LWS_CALLBACK_RECEIVE,
                                                wsi->user_space,
                                                pmdrx.eb_out.token,
-                                               pmdrx.eb_out.len))
+                                               (unsigned int)pmdrx.eb_out.len))
                        return -1;
 
        wsi->ws->first_fragment = 0;
@@ -882,7 +982,7 @@ utf8_fail:
                  wsi->ws->rx_draining_ext);
 #endif
 
-       return avail; /* how much we used from the input */
+       return (int)avail; /* how much we used from the input */
 }
 
 
@@ -914,13 +1014,12 @@ lws_parse_ws(struct lws *wsi, unsigned char **buf, size_t len)
                         * effectively "putting it back in the cache", we have
                         * leave it where it is, already pointed to by the head.
                         */
-                       if (lws_rxflow_cache(wsi, *buf, 0, (int)len) ==
+                       if (lws_rxflow_cache(wsi, *buf, 0, len) ==
                                                        LWSRXFC_TRIMMED) {
                                /*
                                 * We dealt with it by trimming the existing
                                 * rxflow cache HEAD to account for what we used.
                                 *
-                                * indicate we didn't use anything to the caller
                                 * so he doesn't do any consumed processing
                                 */
                                lwsl_info("%s: trimming inside rxflow cache\n",
@@ -952,7 +1051,7 @@ lws_parse_ws(struct lws *wsi, unsigned char **buf, size_t len)
                        bulk = 1;
                        m = lws_ws_frame_rest_is_payload(wsi, buf, len);
                        assert((int)lws_ptr_diff(*buf, bin) <= (int)len);
-                       len -= lws_ptr_diff(*buf, bin);
+                       len -= lws_ptr_diff_size_t(*buf, bin);
 
                        if (!m) {
 
diff --git a/lib/secure-streams/CMakeLists.txt b/lib/secure-streams/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2513e3b
--- /dev/null
@@ -0,0 +1,151 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+include_directories(.)
+
+if (LWS_WITH_CLIENT)
+       list(APPEND SOURCES
+                       secure-streams/secure-streams.c
+                       secure-streams/policy-common.c
+                       secure-streams/system/captive-portal-detect/captive-portal-detect.c
+                       secure-streams/protocols/ss-raw.c
+               )
+               if (NOT LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+                       list(APPEND SOURCES
+                               secure-streams/policy-json.c
+                               secure-streams/system/fetch-policy/fetch-policy.c
+                       )
+               endif()
+               if (LWS_ROLE_H1)
+                       list(APPEND SOURCES
+                               secure-streams/protocols/ss-h1.c
+                       )
+               endif()
+               if (LWS_ROLE_H2)
+                       list(APPEND SOURCES
+                               secure-streams/protocols/ss-h2.c
+                       )
+               endif()
+               if (LWS_ROLE_WS)
+                       list(APPEND SOURCES
+                               secure-streams/protocols/ss-ws.c
+                       )
+               endif()
+               if (LWS_ROLE_MQTT)
+                       list(APPEND SOURCES
+                               secure-streams/protocols/ss-mqtt.c
+                       )
+               endif()
+
+               if (LWS_WITH_SECURE_STREAMS_PROXY_API)
+                       list(APPEND SOURCES
+                               secure-streams/secure-streams-serialize.c
+                               secure-streams/secure-streams-client.c
+                       )
+               endif()
+
+               if (LWS_WITH_SECURE_STREAMS_PROXY_API)
+                       list(APPEND SOURCES
+                               secure-streams/secure-streams-process.c
+                       )
+               endif()
+
+               if (LWS_WITH_SECURE_STREAMS_SYS_AUTH_API_AMAZON_COM AND
+                   LWS_WITH_SYS_STATE)
+                       list(APPEND SOURCES
+                               secure-streams/system/auth-api.amazon.com/auth.c
+                       )
+               endif()
+
+               if (LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+                       list(APPEND SOURCES
+                               secure-streams/system/auth-sigv4/sign.c
+                       )
+               endif()
+
+
+               if (LWS_WITH_SECURE_STREAMS_CPP)
+                       list(APPEND SOURCES secure-streams/cpp/lss.cxx)
+
+                       if (LWS_ROLE_H1 OR LWS_ROLE_H2)
+                               list(APPEND SOURCES secure-streams/cpp/lssFile.cxx)
+                       endif()
+
+                       if (LWS_ROLE_WS)
+                               list(APPEND SOURCES secure-streams/cpp/lssMsg.cxx)
+                       endif()
+               endif()
+
+       #
+       # Helper function for adding a secure stream plugin
+       #
+       macro(create_ss_plugin NAME S2 S3 S4 S5 S6)
+
+               set(SSP_SRCS)
+               set(SSP_PUBLIC_HDR)
+               set(SSP_HDR)
+
+               if ("${S2}" STREQUAL "")
+               else()
+                       list(APPEND SSP_SRCS plugins/${NAME}/${S2})
+               endif()
+               if ("${S3}" STREQUAL "")
+               else()
+                       list(APPEND SSP_SRCS plugins/${NAME}/${S3})
+               endif()
+               if ("${S4}" STREQUAL "")
+               else()
+                       list(APPEND SSP_SRCS plugins/${NAME}/${S4})
+               endif()
+               if ("${S5}" STREQUAL "")
+               else()
+                       list(APPEND SSP_SRCS plugins/${NAME}/${S5})
+               endif()
+               if ("${S6}" STREQUAL "")
+               else()
+                       list(APPEND SSP_SRCS plugins/${NAME}/${S6})
+               endif()
+
+               source_group("Headers Private"  FILES ${SSP_HDR})
+               source_group("Sources"          FILES ${SSP_SRCS})
+
+               add_library( ${NAME} STATIC
+                            ${SSP_HDR} ${SSP_PUBLIC_HDR} ${SSP_SRCS} )
+
+               target_include_directories(${NAME} PRIVATE "${LWS_LIB_INCLUDES}" ${LWS_LIB_BUILD_INC_PATHS})
+
+               if (NOT LWS_PLAT_FREERTOS)
+                       add_dependencies(${NAME} websockets_shared)
+               endif()
+               list(APPEND SS_PLUGINS_LIST ${NAME})
+       endmacro()
+
+       #       create_ss_plugin(ssp-h1url "h1url.c" "" "" "" "")
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
diff --git a/lib/secure-streams/README.md b/lib/secure-streams/README.md
new file mode 100644 (file)
index 0000000..b7a9c3d
--- /dev/null
@@ -0,0 +1,920 @@
+# Secure Streams
+
+Secure Streams is a networking api that strictly separates payload from any
+metadata.  That includes the client endpoint address for the connection, the tls
+trust chain and even the protocol used to connect to the endpoint.
+
+The user api just receives and transmits payload, and receives advisory
+connection state information.
+
+The details about how the connections for different types of secure stream should
+be made are held in JSON "policy database" initially passed in to the context
+creation, but able to be updated from a remote copy.
+
+Both client and server networking can be handled using Secure Streams APIS.
+
+![overview](/doc-assets/ss-operation-modes.png)
+
+## Secure Streams CLIENT State lifecycle
+
+![overview](/doc-assets/ss-state-flow.png)
+
+Secure Streams are created using `lws_ss_create()`, after that they may acquire
+underlying connections, and lose them, but the lifecycle of the Secure Stream
+itself is not directly related to any underlying connection.
+
+Once created, Secure Streams may attempt connections, these may fail and once
+the number of failures exceeds the count of attempts to conceal in the retry /
+backoff policy, the stream reaches `LWSSSCS_ALL_RETRIES_FAILED`.  The stream becomes
+idle again until another explicit connection attempt is given.
+
+Once connected, the user code can use `lws_ss_request_tx()` to ask for a slot
+to write to the peer, when this if forthcoming the tx handler can send a message.
+If the underlying protocol gives indications of transaction success, such as,
+eg, a 200 for http, or an ACK from MQTT, the stream state is called back with
+an `LWSSSCS_QOS_ACK_REMOTE` or `LWSSSCS_QOS_NACK_REMOTE`.
+
+## SS Callback return handling
+
+SS state(), rx() and tx() can indicate with their return code some common
+situations that should be handled by the caller.
+
+Constant|Scope|Meaning
+---|---|---
+LWSSSSRET_TX_DONT_SEND|tx|This opportunity to send something was passed on
+LWSSSSRET_OK|state, rx, tx|No error, continue doing what we're doing
+LWSSSSRET_DISCONNECT_ME|state, rx|assertively disconnect from peer
+LWSSSSRET_DESTROY_ME|state, rx|Caller should now destroy the stream itself
+LWSSSSRET_SS_HANDLE_DESTROYED|state|Something handled a request to destroy the stream
+
+Destruction of the stream we're calling back on inside the callback is tricky,
+it's preferable to return `LWSSSSRET_DESTROY_ME` if it is required, and let the
+caller handle it.  But in some cases, helpers called from the callbacks may
+destroy the handle themselves, in that case the handler should return
+`LWSSSSRET_SS_HANDLE_DESTROYED` indicating that the handle is already destroyed.
+
+## Secure Streams SERVER State lifecycle
+
+![overview](/doc-assets/ss-state-flow-server.png)
+
+You can also run servers defined using Secure Streams, the main difference is
+that the user code must assertively create a secure stream of the server type
+in order to create the vhost and listening socket.  When this stream is
+destroyed, the vhost is destroyed and the listen socket closed, otherwise it
+does not perform any rx or tx, it just represents the server lifecycle.
+
+When client connections randomly arrive at the listen socket, new Secure Stream
+objects are created along with accept sockets to represent each client
+connection.  As they represent the incoming connection, their lifecycle is the
+same as that of the underlying connection.  There is no retry concept since as
+with eg, http servers, the clients may typically not be routable for new
+connections initiated by the server.
+
+Since connections at socket level are already established, new connections are
+immediately taken through CREATING, CONNECTING, CONNECTED states for
+consistency.
+
+Some underlying protocols like http are "transactional", the server receives
+a logical request and must reply with a logical response.  The additional
+state `LWSSSCS_SERVER_TXN` provides a point where the user code can set
+transaction metadata before or in place of sending any payload.  It's also
+possible to defer this until any rx related to the transaction was received,
+but commonly with http requests, there is no rx / body.  Configuring the
+response there may look like
+
+```
+               /*
+                * We do want to ack the transaction...
+                */
+               lws_ss_server_ack(m->ss, 0);
+               /*
+                * ... it's going to be text/html...
+                */
+               lws_ss_set_metadata(m->ss, "mime", "text/html", 9);
+               /*
+                * ...it's going to be 128 byte (and request tx)
+                */
+               lws_ss_request_tx_len(m->ss, 128);
+```
+
+Otherwise the general api usage is very similar to client usage.
+
+## Convention for rx and tx callback return
+
+Function|Return|Meaning
+---|---|---
+tx|`LWSSSSRET_OK`|Send the amount of `buf` stored in `*len`
+tx|`LWSSSSRET_TX_DONT_SEND`|Do not send anything
+tx|`LWSSSSRET_DISCONNECT_ME`|Close the current connection
+tx|`LWSSSSRET_DESTROY_ME`|Destroy the Secure Stream
+rx|>=0|accepted
+rx|<0|Close the current connection
+
+# JSON Policy Database
+
+Example JSON policy... formatting is shown for clarity but whitespace can be
+omitted in the actual policy.
+
+Ordering is not critical in itself, but forward references are not allowed,
+things must be defined before they are allowed to be referenced later in the
+JSON.
+
+
+```
+{
+       "release": "01234567",
+       "product": "myproduct",
+       "schema-version": 1,
+       "retry": [{
+               "default": {
+                       "backoff": [1000, 2000, 3000, 5000, 10000],
+                       "conceal": 5,
+                       "jitterpc": 20
+               }
+       }],
+       "certs": [{
+               "isrg_root_x1": "MIIFazCCA1OgAw...AnX5iItreGCc="
+       }, {
+               "LEX3_isrg_root_x1": "MIIFjTCCA3WgAwIB...WEsikxqEt"
+       }],
+       "trust_stores": [{
+               "le_via_isrg": ["isrg_root_x1", "LEX3_isrg_root_x1"]
+       }],
+       "s": [{
+               "mintest": {
+                       "endpoint": "warmcat.com",
+                       "port": 4443,
+                       "protocol": "h1get",
+                       "aux": "index.html",
+                       "plugins": [],
+                       "tls": true,
+                       "opportunistic": true,
+                       "retry": "default",
+                       "tls_trust_store": "le_via_isrg"
+               }
+       }]
+}
+```
+
+### `Release`
+
+Identifies the policy version
+
+### `Product`
+
+Identifies the product the policy should apply to
+
+### `Schema-version`
+
+The minimum version of the policy parser required to parse this policy
+
+### `via-socks5`
+
+Optional redirect for Secure Streams client traffic through a socks5
+proxy given in the format `address:port`, eg, `127.0.0.1:12345`.
+
+### `retry`
+
+A list of backoff schemes referred to in the policy
+
+### `backoff`
+
+An array of ms delays for each retry in turn
+
+### `conceal`
+
+The number of retries to conceal from higher layers before giving errors.  If
+this is larger than the number of times in the backoff array, then the last time
+is used for the extra delays.  65535 means never stop trying.
+
+### `jitterpc`
+
+Percentage of the delay times mentioned in the backoff array that may be
+randomly added to the figure from the array.  For example with an array entry of
+1000ms, and jitterpc of 20%, actual delays will be chosen randomly from 1000ms
+through 1200ms.  This is to stop retry storms triggered by a single event like
+an outage becoming synchronized into a DoS.
+
+### `certs`
+
+Certificates needed for validation should be listed here each with a name.  The
+format is base64 DER, which is the same as the part of PEM that is inside the
+start and end lines.
+
+### `trust_stores`
+
+Chains of certificates given in the `certs` section may be named and described
+inside the `trust_stores` section.  Each entry in `trust_stores` is created as
+a vhost + tls context with the given name.  Stream types can later be associated
+with one of these to enforce validity checking of the remote server.
+
+Entries should be named using "name" and the stack array defined using "stack"
+
+### `auth`
+
+Optional section describing a map of available authentication streamtypes to
+auth token blob indexes.
+
+```
+...
+ "auth": [{"name":"newauth","type":"sigv4", "blob":0}]
+...
+```
+
+Streams can indicate they depend on a valid auth token from one of these schemes
+by using the `"use_auth": "name"` member in the streamtype definition, where name
+is, eg, "sigv4" in the example above.  If "use_auth" is not in the streamtype
+definition, default auth is lwa if "http_auth_header" is there.
+
+### `auth[].name`
+
+This is the name of the authentication scheme used by other streamtypes
+
+### `auth[].type`
+
+Indicate the auth type, e.g. sigv4
+
+### `auth[].streamtype`
+
+This is the auth streamtype to be used to refresh the authentication token
+
+### `auth[].blob`
+
+This is the auth blob index the authentication token is stored into and retreived
+from system blob, currently up to 4 blobs.
+
+
+### `s`
+
+These are an array of policies for the supported stream type names.
+
+### `server`
+
+**SERVER ONLY**: if set to `true`, the policy describes a secure streams
+server.
+
+### `endpoint`
+
+**CLIENT**: The DNS address the secure stream should connect to.
+
+This may contain string symbols which will be replaced with the
+corresponding streamtype metadata value at runtime.  Eg, if the
+streamtype lists a metadata name "region", it's then possible to
+define the endpoint as, eg, `${region}.mysite.com`, and before
+attempting the connection setting the stream's metadata item
+"region" to the desired value, eg, "uk".
+
+If the endpoint string begins with `+`, then it's understood to
+mean a connection to a Unix Domain Socket, for Linux `+@` means
+the following Unix Domain Socket is in the Linux Abstract
+Namespace and doesn't have a filesystem footprint.  This is only
+supported on unix-type and windows platforms and when lws was
+configured with `-DLWS_UNIX_SOCK=1`
+
+**SERVER**: If given, the network interface name or IP address the listen socket
+should bind to.
+
+**SERVER**: If begins with '!', the rest of the endpoint name is the
+vhost name of an existing vhost to bind to, instead of creating a new
+one.  This is useful when the vhost layout is already being managed by
+lejp-conf JSON and it's more convenient to put the details in there.
+
+### `port`
+
+**CLIENT**: The port number as an integer on the endpoint to connect to
+
+**SERVER**: The port number the server will listen on
+
+### `protocol`
+
+**CLIENT**: The wire protocol to connect to the endpoint with.  Currently
+supported streamtypes are
+
+|Wire protocol|Description|
+|---|---|
+|h1|http/1|
+|h2|http/2|
+|ws|http/1 Websockets|
+|mqtt|mqtt 3.1.1|
+|raw||
+
+Raw protocol is a bit different than the others in that there is no protocol framing,
+whatever is received on the connection is passed to the user rx callback and whatever
+the tx callback provides is issued on to the connection.  Because tcp can be
+arbitrarily fragmented by any intermediary, such streams have to be regarded as an
+ordered bytestream that may be fragmented at any byte without any meaning in terms
+of message boundaries, for that reason SOM and EOM are ignored with raw.
+
+### `allow_redirects`
+
+By default redirects are not followed, if you wish a streamtype to observe them, eg,
+because that's how it responds to a POST, set `"allow_redirects": true`
+
+### `tls`
+
+Set to `true` to enforce the stream travelling in a tls tunnel
+
+### `client cert`
+
+Set if the stream needs to authenticate itself using a tls client certificate.
+Set to the certificate index counting from 0+.  The certificates are managed
+using lws_sytstem blobs.
+
+### `opportunistic`
+
+Set to `true` if the connection may be left dropped except when in use
+
+### `nailed_up`
+
+Set to `true` to have lws retry if the connection carrying this stream should
+ever drop.
+
+### `retry`
+
+The name of the policy described in the `retry` section to apply to this
+connection for retry + backoff
+
+### `timeout_ms`
+
+Optional timeout associated with streams of this streamtype.
+
+If user code applies the `lws_ss_start_timeout()` api on a stream with a
+timeout of LWSSS_TIMEOUT_FROM_POLICY, the `timeout_ms` entry given in the
+policy is applied.
+
+### `perf`
+
+If set to true, and lws was built with `LWS_WITH_CONMON`, causes this streamtype
+to receive additional rx payload with the `LWSSS_FLAG_PERF_JSON` flag set on it,
+that is JSON representing the onward connection performance information.
+
+These are based on the information captured in the struct defined in
+libwebsockets/lws-conmon.h, represented in JSON
+
+```
+       {
+         "peer": "46.105.127.147",
+         "dns_us": 1234,
+         "sockconn_us": 1234,
+         "tls_us": 1234,
+         "txn_resp_us": 1234,
+         "dns":["46.105.127.147", "2001:41d0:2:ee93::1"]
+       }
+```
+
+Streamtypes without "perf": true will never see the special rx payloads.
+Notice that the `LWSSS_FLAG_PERF_JSON` payloads must be handled out of band
+for the normal payloads, as they can appear inside normal payload messages.
+
+### `tls_trust_store`
+
+The name of the trust store described in the `trust_stores` section to apply
+to validate the remote server cert.
+
+If missing and tls is enabled on the streamtype, then validation is
+attempted using the OS trust store, otherwise the connection fails.
+
+### `use_auth`
+
+Indicate that the streamtype should use the named auth type from the `auth`
+array in the policy
+
+### `aws_region`
+
+Indicate which metadata should be used to set aws region for certain streamtype
+
+### `aws_service`
+
+Indicate which metadata should be used to set aws service for certain streamtype
+
+### `direct_proto_str`
+
+If set to `true`, application can use `lws_ss_set_metadata()` to directly set protocol related string and use `lws_ss_get_metadata` to fetch certain protocol related string.  Please note that currently HTTP header is the supported protocol string.  The `name` parameter is the name of HTTP header name (**with ':'**, e.g. `"Content-Type:"`) and `value` is the header's value. `LWS_WITH_SS_DIRECT_PROTOCOL_STR` flag needs to be configured during compilation for this.  Currently it's only work for non-proxy case.
+
+### `server_cert`
+
+**SERVER ONLY**: subject to change... the name of the x.509 cert that is the
+server's tls certificate
+
+### `server_key`
+
+**SERVER ONLY**: subject to change... the name of the x.509 cert that is the
+server's tls key
+
+### `swake_validity`
+
+Set to `true` if this streamtype is important enough for the functioning of the
+device that its locally-initiated periodic connection validity checks of the
+interval described in the associated retry / backoff selection, are important
+enough to wake the whole system from low power suspend so they happen on
+schedule.
+
+### `proxy_buflen`
+
+Only used when the streamtype is proxied... sets the maximum size of the
+payload buffering (in bytes) the proxy will hold for this type of stream.  If
+the endpoint dumps a lot of data without any flow control, this may need to
+be correspondingly large.  Default is 32KB.
+
+### `proxy_buflen_rxflow_on_above`, `proxy_buflen_rxflow_off_below`
+
+When `proxy_buflen` is set, you can also wire up the amount of buffered
+data intended for the client held at the proxy, to the onward ss wsi
+rx flow control state.  If more than `proxy_buflen_rxflow_on_above`
+bytes are buffered, rx flow control is set stopping further rx.  Once
+the dsh is drained below `proxy_buflen_rxflow_off_below`, the rx flow
+control is released and RX resumes.
+
+### `client_buflen`
+
+Only used when the streamtype is proxied... sets the maximum size of the
+payload buffering (in bytes) the client will hold for this type of stream.  If
+the client sends a lot of data without any flow control, this may need to
+be correspondingly large.  Default is 32KB.
+
+### `attr_priority`
+
+A number between 0 (normal priority) and 6 (very high priority).  7 is also
+possible, but requires CAP_NET_ADMIN on Linux and is reserved for network
+administration packets.  Normally default priority is fine, but under some
+conditions when transporting over IP packets, you may want to control the
+IP packet ToS priority for the streamtype by using this.
+
+### `attr_low_latency`
+
+This is a flag indicating that the streamtype packets should be transported
+in a way that results in lower latency where there is a choice.  For IP packets,
+this sets the ToS "low delay" flag on packets from this streamtype.
+
+### `attr_high_throughput`
+
+This is a flag indicating that this streamtype should be expected to produce
+bulk content that requires high throughput.  For IP packets,
+this sets the ToS "high throughput" flag on packets from this streamtype.
+
+### `attr_high_reliability`
+
+This is a flag indicating that extra efforts should be made to deliver packets
+from this streamtype where possible.  For IP packets, this sets the ToS "high
+reliability" flag on packets from this streamtype.
+
+### `attr_low_cost`
+
+This is a flag indicating that packets from this streamtype should be routed as
+inexpensively as possible by trading off latency and reliability where there is
+a choice.  For IP packets, this sets the ToS "low cost" flag on packets from
+this streamtype.
+
+### `metadata`
+
+This allows declaring basically dynamic symbol names to be used by the streamtype,
+along with an optional mapping to a protocol-specific entity such as a given
+http header.  Eg:
+
+```
+               "metadata": [ { "myname": "" }, { "ctype": "content-type:" } ],
+```
+
+In this example "ctype" is associated with the http header "content-type" while
+"myname" doesn't have any association to a header.
+
+Symbol names may be used in the other policy for the streamtype for string
+substitution using the syntax like `xxx${myname}yyy`, forward references are
+valid but the scope of the symbols is just the streamtype the metadata is
+defined for.
+
+Client code can set metadata by name, using the `lws_ss_set_metadata()` api, this
+should be done before a transaction.  And for metadata associated with a
+protocol-specific entity, like http headers, if incoming responses contain the
+mentioned header, the metadata symbol is set to that value at the client before
+any rx proceeds.
+
+Metadata continues to work the same for the client in the case it is proxying its
+connectivity, metadata is passed in both directions serialized over the proxy link.
+
+## http transport
+
+### `http_method`
+
+HTTP method to use with http-related protocols, like GET or POST.
+Not required for ws.
+
+### `http_expect`
+
+Optionally indicates that success for HTTP transactions using this
+streamtype is different than the default 200 - 299.
+
+Eg, you may choose to set this to 204 for Captive Portal Detect usage
+if that's what you expect the server to reply with to indicate
+success.  In that case, anything other than 204 will be treated as a
+connection failure.
+
+### `http_fail_redirect`
+
+Set to `true` if you want to fail the connection on meeting an
+http redirect.  This is needed to, eg, detect Captive Portals
+correctly.  Normally, if on https, you would want the default behaviour
+of following the redirect.
+
+### `http_url`
+
+Url path to use with http-related protocols
+
+The URL path can include metatadata like this
+
+"/mypath?whatever=${metadataname}"
+
+${metadataname} will be replaced by the current value of the
+same metadata name.  The metadata names must be listed in the
+"metadata": [ ] section.
+
+### `http_resp_map`
+
+If your server overloads the meaning of the http transport response code with
+server-custom application codes, you can map these to discrete Secure Streams
+state callbacks using a JSON map, eg
+
+```
+               "http_resp_map": [ { "530": 1530 }, { "531": 1531 } ],
+```
+
+It's not recommended to abuse the transport layer http response code by
+mixing it with application state information like this, but if it's dealing
+with legacy serverside that takes this approach, it's possible to handle it
+in SS this way while removing the dependency on http.
+
+### `http_auth_header`
+
+The name of the header that takes the auth token, with a trailing ':', eg
+
+```
+  "http_auth_header": "authorization:"
+```
+
+### `http_dsn_header`
+
+The name of the header that takes the dsn token, with a trailing ':', eg
+
+```
+  "http_dsn_header": "x-dsn:"
+```
+
+### `http_fwv_header`
+
+The name of the header that takes the firmware version token, with a trailing ':', eg
+
+```
+  "http_fwv_header": "x-fw-version:"
+```
+
+### `http_devtype_header`
+
+The name of the header that takes the device type token, with a trailing ':', eg
+
+```
+  "http_devtype_header": "x-device-type:"
+```
+
+### `http_auth_preamble`
+
+An optional string that precedes the auth token, eg
+
+```
+ "http_auth_preamble": "bearer "
+```
+
+### `auth_hexify`
+
+Convert the auth token to hex ('A' -> "41") before transporting.  Not necessary if the
+auth token is already in printable string format suitable for transport.  Needed if the
+auth token is a chunk of 8-bit binary.
+
+### `nghttp2_quirk_end_stream`
+
+Set this to `true` if the peer server has the quirk it won't send a response until we have
+sent an `END_STREAM`, even though we have sent headers with `END_HEADERS`.
+
+### `h2q_oflow_txcr`
+
+Set this to `true` if the peer server has the quirk it sends an maximum initial tx credit
+of 0x7fffffff and then later increments it illegally.
+
+### `http_multipart_ss_in`
+
+Indicates that SS should parse any incoming multipart mime on this stream
+
+### `http_multipart_name`
+
+Indicates this stream goes out using multipart mime, and provides the name part of the
+multipart header
+
+### `http_multipart_filename`
+
+Indicates this stream goes out using multipart mime, and provides the filename part of the
+multipart header
+
+### `http_multipart_content_type`
+
+The `content-type` to mark up the multipart mime section with if present
+
+### `http_www_form_urlencoded`
+
+Indicate the data is sent in `x-www-form-urlencoded` form
+
+### `http_cookies`
+
+This streamtype should store and bring out http cookies from the peer.
+
+### `rideshare`
+
+For special cases where one logically separate stream travels with another when using this
+protocol.  Eg, a single multipart mime transaction carries content from two or more streams.
+
+## ws transport
+
+### `ws_subprotocol`
+
+** CLIENT **: Name of the ws subprotocol to request from the server
+
+** SERVER **: Name of the subprotocol we will accept
+
+### `ws_binary`
+
+Use if the ws messages are binary
+
+### `ws_prioritize_reads`
+
+Set `true` if the event loop should prioritize keeping up with input at the
+potential expense of output latency.
+
+## MQTT transport
+
+### `mqtt_topic`
+
+Set the topic this streamtype uses for writes
+
+### `mqtt_subscribe`
+
+Set the topic this streamtype subscribes to
+
+### `mqtt qos`
+
+Set the QOS level for this streamtype
+
+### `mqtt_keep_alive`
+
+16-bit number representing MQTT keep alive for the stream.
+
+This is applied at connection time... where different streams may bind to the
+same underlying MQTT connection, all the streams should have an identical
+setting for this.
+
+### `mqtt_clean_start`
+
+Set to true if the connection should use MQTT's "clean start" feature.
+
+This is applied at connection time... where different streams may bind to the
+same underlying MQTT connection, all the streams should have an identical
+setting for this.
+
+### `mqtt_will_topic`
+
+Set the topic of the connection's will message, if any (there is none by default).
+
+This is applied at connection time... where different streams may bind to the
+same underlying MQTT connection, all the streams should have an identical
+setting for this.
+
+### `mqtt_will_message`
+
+Set the content of the connect's will message, if any (there is none by default).
+
+This is applied at connection time... where different streams may bind to the
+same underlying MQTT connection, all the streams should have an identical
+setting for this.
+
+### `mqtt_will_qos`
+
+Set the QoS of the will message, if any (there is none by default).
+
+This is applied at connection time... where different streams may bind to the
+same underlying MQTT connection, all the streams should have an identical
+setting for this.
+
+### `mqtt_will_retain`
+
+Set to true if the connection should use MQTT's "will retain" feature, if there
+is a will message (there is none by default).
+
+This is applied at connection time... where different streams may bind to the
+same underlying MQTT connection, all the streams should have an identical
+setting for this.
+
+## Loading and using updated remote policy
+
+If the default, hardcoded policy includes a streamtype `fetch_policy`,
+during startup when lws_system reaches the POLICY state, lws will use
+a Secure Stream of type `fetch_policy` to download, parse and update
+the policy to use it.
+
+The secure-streams-proxy minimal example shows how this is done and
+fetches its real policy from warmcat.com at startup using the built-in
+one.
+
+## Applying streamtype policy overlays
+
+This is intended for modifying policies at runtime for testing, eg, to
+force error paths to be taken.  After the main policy is processed, you
+may parse additional, usually smaller policy fragments on top of it.
+
+Where streamtype names in the new fragment already exist in the current
+parsed policy, the settings in the fragment are applied over the parsed
+policy, overriding settings.  There's a simple api to enable this by
+giving it the override JSON in one string
+
+```
+int
+lws_ss_policy_overlay(struct lws_context *context, const char *overlay);
+```
+
+but there are also other apis available that can statefully process
+larger overlay fragments if needed.
+
+An example overlay fragment looks like this
+
+```
+       { "s": [{ "captive_portal_detect": {
+               "endpoint": "google.com",
+               "http_url": "/",
+               "port": 80
+       }}]}
+```
+
+ie the overlay fragment completely follows the structure of the main policy,
+just misses out anything it doesn't override.
+
+Currently ONLY streamtypes may be overridden.
+
+You can see an example of this in use in `minimal-secure-streams` example
+where `--force-portal` and `--force-no-internet` options cause the captive
+portal detect streamtype to be overridden to force the requested kind of
+outcome.
+
+## Captive Portal Detection
+
+If the policy contains a streamtype `captive_portal_detect` then the
+type of transaction described there is automatically performed after
+acquiring a DHCP address to try to determine the captive portal
+situation.
+
+```
+               "captive_portal_detect": {
+                        "endpoint": "connectivitycheck.android.com",
+                        "port": 80,
+                        "protocol": "h1",
+                        "http_method": "GET",
+                        "http_url": "generate_204",
+                        "opportunistic": true,
+                        "http_expect": 204,
+                       "http_fail_redirect": true
+                }
+```
+
+## Stream serialization and proxying
+
+By default Secure Streams expects to make the outgoing connection described in
+the policy in the same process / thread, this suits the case where all the
+participating clients are in the same statically-linked image.
+
+In this case the `lws_ss_` apis are fulfilled locally by secure-streams.c and
+policy.c for policy lookups.
+
+However it also supports serialization, where the SS api can be streamed over
+another transport such as a Unix Domain Socket connection.  This suits the case
+where the clients are actually in different processes in, eg, Linux or Android.
+
+In those cases, you run a proxy process (minimal-secure-streams-proxy) that
+listens on a Unix Domain Socket and is connected to by one or more other
+processes that pass their SS API activity to the proxy for fulfilment (or
+onward proxying).
+
+Each Secure Stream that is created then in turn creates a private Unix Domain
+Socket connection to the proxy for each stream.
+
+In this case the proxy uses secure-streams.c and policy.c as before to fulfil
+the inbound proxy streams, but uses secure-streams-serialize.c to serialize and
+deserialize the proxied SS API activity.  The proxy clients define
+LWS_SS_USE_SSPC either very early in their sources before the includes, or on
+the compiler commandline... this causes the lws_ss_ apis to be replaced at
+preprocessor time with lws_sspc_ equivalents.  These serialize the api action
+and pass it to the proxy over a Unix Domain Socket for fulfilment, the results
+and state changes etc are streamed over the Unix Domain Socket and presented to
+the application exactly the same as if it was being fulfilled locally.
+
+To demonstrate this, some minimal examples, eg, minimal-secure-streams and
+mimimal-secure-streams-avs build themselves both ways, once with direct SS API
+fulfilment and once with Unix Domain Socket proxying and -client appended on the
+executable name.  To test the -client variants, run minimal-secure-streams-proxy
+on the same machine.
+
+## Complicated scenarios with secure streams proxy
+
+As mentioned above, Secure Streams has two modes, by default the application
+directly parses the policy and makes the outgoing connections itself.
+However when configured at cmake with
+
+```
+-DLWS_WITH_SOCKS5=1 -DLWS_WITH_SECURE_STREAMS=1 -DLWS_WITH_SECURE_STREAMS_PROXY_API=1 -DLWS_WITH_MINIMAL_EXAMPLES=1
+```
+
+and define `LWS_SS_USE_SSPC` when building the application, applications forward
+their network requests to a local or remote SS proxy for fulfilment... and only
+the SS proxy has the system policy.  By default, the SS proxy is on the local
+machine and is connected to via a Unix Domain Socket, but tcp links are also
+possible.  (Note the proxied traffic is not encrypyed by default.)
+
+Using the configuration above, the example SS applications are built two ways,
+once for direct connection fulfilment (eg, `./bin/lws-minimal-secure-streams`),
+and once with `LWS_SS_USE_SSPC` also defined so it connects via an SS proxy,
+(eg, `./bin/lws-minimal-secure-streams-client`).
+
+## Testing an example scenario with SS Proxy and socks5 proxy
+
+```
+ [ SS application ] --- tcp --- [ socks 5 proxy ] --- tcp --- [ SS proxy ] --- internet
+```
+
+In this scenario, everything is on localhost, the socks5 proxy listens on :1337 and
+the SS proxy listens on :1234.  The SS application connects to the socks5
+proxy to get to the SS proxy, which then goes out to the internet
+
+### 1 Start the SS proxy
+
+Tell it to listen on lo interface on port 1234
+
+```
+$ ./bin/lws-minimal-secure-streams-proxy -p 1234 -i lo
+```
+
+### 2 Start the SOCKS5 proxy
+
+```
+$ ssh -D 1337 -N -v localhost
+```
+
+The -v makes connections to the proxy visible in the terminal for testing
+
+### 3 Run the SS application
+
+The application is told to make all connections via the socks5 proxy at
+127.0.0.1:1337, and to fulfil its SS connections via an SS proxy, binding
+connections to 127.0.0.1 (ipv4 lo interface, -1), to 127.0.0.1:1234 (-a/-p).
+
+```
+socks_proxy=127.0.0.1:1337 ./bin/lws-minimal-secure-streams-client -p 1234 -i 127.0.0.1 -a 127.0.0.1
+```
+
+You can confirm this goes through the ssh socks5 proxy to get to the SS proxy
+and fulfil the connection.
+
+## Using static policies
+
+If one of your targets is too constrained to make use of dynamic JSON policies, but
+using SS and the policies is attractive for wider reasons, you can use a static policy
+built into the firmware for the constrained target.
+
+The secure-streams example "policy2c" (which runs on the build machine, not the device)
+
+https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/secure-streams/minimal-secure-streams-policy2c
+
+accepts a normal JSON policy on stdin, and emits a C code representation that can be
+included directly in the firmware.
+
+https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/static-policy.h
+
+Using this technique it's possible to standardize on maintaining JSON policies across a
+range of devices with different contraints, and use the C conversion of the policy on devices
+that are too small.
+
+The Cmake option `LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY` should be enabled to use this
+mode, it will not build the JSON parser (and the option for LEJP can also be disabled if
+you're not otherwise using it, saving an additional couple of KB).
+
+Notice policy2c example tool must be built with `LWS_ROLE_H1`, `LWS_ROLE_H2`, `LWS_ROLE_WS`
+and `LWS_ROLE_MQTT` enabled so it can handle any kind of policy.
+
+## HTTP and ws serving
+
+All ws servers start out as http servers... for that reason ws serving is
+handled as part of http serving, if you give the `ws_subprotocol` entry to the
+streamtype additionally, the server will also accept upgrades to ws.
+
+To help the user code understand if the upgrade occurred, there's a special
+state `LWSSSCS_SERVER_UPGRADE`, so subsequent rx and tx can be understood to
+have come from the upgraded protocol.  To allow separation of rx and tx
+handling between http and ws, there's a ss api `lws_ss_change_handlers()`
+which allows dynamically setting SS handlers.
+
+Since the http and ws upgrade identity is encapsulated in one streamtype, the
+user object for the server streamtype should contain related user data for both
+http and ws underlying protocol identity.
diff --git a/lib/secure-streams/cpp/README.md b/lib/secure-streams/cpp/README.md
new file mode 100644 (file)
index 0000000..975c92e
--- /dev/null
@@ -0,0 +1,29 @@
+## Secure Streams client C++ API
+
+Enable for build by selecting `-DLWS_WITH_SECURE_STREAMS=1 -DLWS_WITH_SECURE_STREAMS_CPP=1` at
+cmake.
+
+Because it's designed for OpenSSL + system trust bundle, the minimal
+example minimal-secure-streams-cpp requires `-DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_MBEDTLS=0`
+
+By default the -cpp example downloads https://warmcat.com/test-a.bin to the local
+file /tmp/test-a.bin.  By giving, eg, -c 4, you can run four concurrent downloads of
+files test-a.bin through test-d.bin... up to 12 files may be downloaded concurrently.
+
+By default it will connect over h2 and share the single connection between all the
+downloads.
+
+### File level api
+
+```
+#include <libwebsockets.hxx>
+
+...
+
+       new lssFile(context, "https://warmcat.com/index.html",
+                       "/tmp/index.html", lss_completion, 0);
+```
+
+This will copy the remote url to the given local file, and call the
+completion callback when it has succeeded or failed.
+
diff --git a/lib/secure-streams/cpp/lss.cxx b/lib/secure-streams/cpp/lss.cxx
new file mode 100644 (file)
index 0000000..d25eed5
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * C++ classes for Secure Streams
+ */
+
+#include <libwebsockets.hxx>
+
+static const char *pcols[] = {
+       "http://",      /* LWSSSP_H1 */
+       "https://",
+       "h2://",        /* LWSSSP_H2 */
+       "h2s://",
+       "ws://",        /* LWSSSP_WS */
+       "wss://",
+       "mqtt://",      /* LWSSSP_MQTT */
+       "mqtts://",
+       "raw://",       /* LWSSSP_RAW */
+       "raws://",
+};
+
+static const uint8_t pcols_len[] = {
+       7, 8, 5, 6, 5, 6, 7, 8, 6, 7
+};
+
+static const uint16_t pcols_port[] = {
+       80, 443, 443, 443, 80, 443, 1883, 8883, 80, 443
+};
+
+lss::lss(lws_ctx_t _ctx, std::string _uri, lsscomp_t _comp, bool _psh,
+        lws_sscb_rx rx, lws_sscb_tx tx, lws_sscb_state state)
+{
+       const char *p, *urlpath;
+       lws_ss_info_t ssi;
+       int n, port;
+
+       memset(&ssi, 0, sizeof(ssi));
+       memset(&pol, 0, sizeof(pol));
+
+       ctx             = _ctx;
+       comp            = _comp;
+       comp_done       = 0;
+       rxlen           = 0;
+
+       /*
+        * We have a common stub userdata, our "real" userdata is in the
+        * derived class members.   The Opaque user pointer points to the
+        * lss itself.
+        */
+
+       ssi.handle_offset           = offsetof(lssPriv, lssPriv::m_ss);
+       ssi.opaque_user_data_offset = offsetof(lssPriv, lssPriv::m_plss);
+
+       ssi.user_alloc  = sizeof(lssPriv);
+       ssi.rx          = rx;
+       ssi.tx          = tx;
+       ssi.state       = state;
+       ssi.policy      = &pol; /* we will provide our own policy */
+
+       /*
+        * _uri is like "https://warmcat.com:443/index.html"... we need to
+        * deconstruct it into its policy implications
+        */
+
+       uri = strdup(_uri.c_str());
+
+       for (n = 0; n < LWS_ARRAY_SIZE(pcols); n++)
+               if (!strncmp(uri, pcols[n], pcols_len[n]))
+                       break;
+
+       if (n == LWS_ARRAY_SIZE(pcols))
+               throw lssException("unknown uri protocol://");
+
+       pol.protocol = n >> 1;
+       if (n & 1)
+               pol.flags |= LWSSSPOLF_TLS;
+
+       n = pcols_port[n];
+
+       if (lws_parse_uri(uri, &p, &pol.endpoint, &n, &urlpath))
+               throw lssException("unable to parse uri://");
+
+       pol.port = (uint16_t)n;
+
+       if (pol.protocol <= LWSSSP_WS) {
+               pol.u.http.url = urlpath;
+
+               /*
+                * These are workarounds for common h2 server noncompliances
+                */
+
+               pol.flags |= LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM |
+                            LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR |
+                            LWSSSPOLF_H2_QUIRK_UNCLEAN_HPACK_STATE;
+
+               if (pol.protocol < LWSSSP_WS)
+                       pol.u.http.method = _psh ? "POST" : "GET";
+       }
+
+       us_start = lws_now_usecs();
+
+       if (lws_ss_create(ctx, 0, &ssi, (void *)this, &m_ss, NULL, NULL))
+               goto blow;
+
+       if (pol.protocol <= LWSSSP_WS)
+               lws_ss_client_connect(m_ss);
+
+       return;
+
+blow:
+       if (uri)
+               free(uri);
+       throw lssException("ss creation failed");
+}
+
+lss::~lss()
+{
+       if (uri)
+               free(uri);
+       if (m_ss)
+               lws_ss_destroy(&m_ss);
+}
+
+int lss::call_completion(lws_ss_constate_t state)
+{
+       if (comp_done)
+               return 0;
+       if (!comp)
+               return 0;
+
+       comp_done = 1;
+
+       return comp(this, state, NULL);
+}
diff --git a/lib/secure-streams/cpp/lssFile.cxx b/lib/secure-streams/cpp/lssFile.cxx
new file mode 100644 (file)
index 0000000..838a89d
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * C++ classes for Secure Streams - file transaction
+ */
+
+#include <libwebsockets.hxx>
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+static lws_ss_state_return_t
+lssfile_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       lssFile *lf = (lssFile *)userobj_to_lss(userobj);
+
+       return lf->write(buf, len, flags);
+}
+
+static lws_ss_state_return_t
+lssfile_tx(void *userobj, lws_ss_tx_ordinal_t ord,uint8_t *buf, size_t *len,
+   int *flags)
+{
+       /*
+        * TODO: we don't know how to send things yet
+        */
+       return LWSSSSRET_TX_DONT_SEND;
+}
+
+static lws_ss_state_return_t
+lssfile_state(void *userobj, void *h_src, lws_ss_constate_t state,
+      lws_ss_tx_ordinal_t ack)
+{
+       lssFile *lf = (lssFile *)userobj_to_lss(userobj);
+
+       lwsl_info("%s: state %s\n", __func__, lws_ss_state_name(state));
+
+       switch (state) {
+
+       /*
+        * These reflect some kind of final disposition for the transaction,
+        * that we want to report along with the completion.  If no other chance
+        * we'll report DESTROYING
+        */
+
+       case LWSSSCS_DESTROYING:
+       case LWSSSCS_ALL_RETRIES_FAILED:
+       case LWSSSCS_QOS_ACK_REMOTE:
+       case LWSSSCS_QOS_NACK_REMOTE:
+               lf->call_completion(state);
+
+               if (state == LWSSSCS_DESTROYING) {
+                       /*
+                        * we get DESTROYING because we are already in the
+                        * middle of destroying the m_ss, unlink the C++ lss
+                        * from the ss handle so it won't recursively try to
+                        * destroy it
+                        */
+                       lf->m_ss = NULL;
+                       delete lf;
+               }
+
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+lws_ss_state_return_t lssFile::write(const uint8_t *buf, size_t len, int flags)
+{
+       if (fd == LWS_INVALID_FILE) {
+
+               fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0640);
+               if (fd == LWS_INVALID_FILE)
+                       return LWSSSSRET_DESTROY_ME;
+       }
+
+       if (::write(fd, buf, len) != len) {
+               close(fd);
+               fd = LWS_INVALID_FILE;
+
+               return LWSSSSRET_DESTROY_ME;
+       }
+
+       rxlen += len;
+
+       if (flags & LWSSS_FLAG_EOM) {
+               close(fd);
+               fd = LWS_INVALID_FILE;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+lssFile::lssFile(lws_ctx_t ctx, std::string uri, std::string _path,
+                lsscomp_t comp, bool _psh) :
+        lss(ctx, uri, comp, _psh, lssfile_rx, lssfile_tx, lssfile_state)
+{
+       path = _path;
+       push = _psh;
+       fd = LWS_INVALID_FILE;
+}
+
+lssFile::~lssFile()
+{
+       if (fd == LWS_INVALID_FILE)
+               return;
+
+       close(fd);
+       fd = LWS_INVALID_FILE;
+}
diff --git a/lib/secure-streams/cpp/lssMsg.cxx b/lib/secure-streams/cpp/lssMsg.cxx
new file mode 100644 (file)
index 0000000..13092d7
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * C++ classes for Secure Streams - atomic heap messages
+ */
+
+#include <libwebsockets.hxx>
+
+static lws_ss_state_return_t
+lssmsg_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+lssmsg_tx(void *userobj, lws_ss_tx_ordinal_t ord,uint8_t *buf, size_t *len,
+   int *flags)
+{
+       /*
+        * TODO: we don't know how to send things yet
+        */
+       return LWSSSSRET_TX_DONT_SEND;
+}
+
+static lws_ss_state_return_t
+lssmsg_state(void *userobj, void *h_src, lws_ss_constate_t state,
+               lws_ss_tx_ordinal_t ack)
+{
+       return LWSSSSRET_OK;
+}
+
+
+lssMsg::lssMsg(lws_ctx_t ctx, lsscomp_t _comp, std::string uri) :
+       lss(ctx, uri, comp, 0, lssmsg_rx, lssmsg_tx, lssmsg_state)
+{
+}
+
+lssMsg::~lssMsg()
+{
+}
diff --git a/lib/secure-streams/plugins/ssp-h1url/h1url.c b/lib/secure-streams/plugins/ssp-h1url/h1url.c
new file mode 100644 (file)
index 0000000..2e47c71
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * ssp-h1url plugin
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * CC0 so it can be used as a template for your own secure streams plugins
+ * licensed how you like.
+ */
+
+#include <libwebsockets.h>
+
+static int
+ssp_h1url_create(struct lws_ss_handle *ss, void *info, plugin_auth_status_cb status)
+{
+       return 0;
+}
+
+static int
+ssp_h1url_destroy(struct lws_ss_handle *ss)
+{
+       return 0;
+}
+
+static int
+ssp_h1url_munge(struct lws_ss_handle *ss, char *path, size_t path_len)
+{
+       return 0;
+}
+
+/* this is the only exported symbol */
+const lws_ss_plugin_t ssp_h1url = {
+       .name                   = "h1url",
+       .alloc                  = 0,
+       .create                 = ssp_h1url_create,
+       .destroy                = ssp_h1url_destroy,
+       .munge                  = ssp_h1url_munge
+};
diff --git a/lib/secure-streams/policy-common.c b/lib/secure-streams/policy-common.c
new file mode 100644 (file)
index 0000000..b782c1e
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This file contains the stuff related to secure streams policy, it's always
+ * built if LWS_WITH_SECURE_STREAMS enabled.
+ */
+
+#include <private-lib-core.h>
+
+#if defined(LWS_WITH_SYS_SMD)
+const lws_ss_policy_t pol_smd = {
+       .flags                  = 0, /* have to set something for windows */
+};
+#endif
+
+const lws_ss_policy_t *
+lws_ss_policy_lookup(const struct lws_context *context, const char *streamtype)
+{
+       const lws_ss_policy_t *p = context->pss_policies;
+
+       if (!streamtype)
+               return NULL;
+
+#if defined(LWS_WITH_SYS_SMD)
+       if (!strcmp(streamtype, LWS_SMD_STREAMTYPENAME))
+               return &pol_smd;
+#endif
+
+       while (p) {
+               if (!strcmp(p->streamtype, streamtype))
+                       return p;
+               p = p->next;
+       }
+
+       return NULL;
+}
+
+int
+_lws_ss_set_metadata(lws_ss_metadata_t *omd, const char *name,
+                    const void *value, size_t len)
+{
+       /*
+        * If there was already a heap-based value, it's about to go out of
+        * scope due to us trashing the pointer.  So free it first and clear
+        * its flag indicating it's heap-based.
+        */
+
+       if (omd->value_on_lws_heap) {
+               lws_free_set_NULL(omd->value__may_own_heap);
+               omd->value_on_lws_heap = 0;
+       }
+
+       // lwsl_notice("%s: %s %s\n", __func__, name, (const char *)value);
+
+       omd->name = name;
+       omd->value__may_own_heap = (void *)value;
+       omd->length = len;
+
+       return 0;
+}
+
+int
+lws_ss_set_metadata(struct lws_ss_handle *h, const char *name,
+                   const void *value, size_t len)
+{
+       lws_ss_metadata_t *omd = lws_ss_get_handle_metadata(h, name);
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (omd)
+               return _lws_ss_set_metadata(omd, name, value, len);
+
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       if (h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR) {
+               omd = lws_ss_get_handle_instant_metadata(h, name);
+               if (!omd) {
+                       omd = lws_zalloc(sizeof(*omd), "imetadata");
+                       if (!omd) {
+                               lwsl_err("%s OOM\n", __func__);
+                               return 1;
+                       }
+                       omd->name = name;
+                       omd->next = h->instant_metadata;
+                       h->instant_metadata = omd;
+               }
+               omd->value__may_own_heap = (void *)value;
+               omd->length = len;
+
+               return 0;
+       }
+#endif
+
+       lwsl_info("%s: unknown metadata %s\n", __func__, name);
+       return 1;
+}
+
+int
+_lws_ss_alloc_set_metadata(lws_ss_metadata_t *omd, const char *name,
+                          const void *value, size_t len)
+{
+       uint8_t *p;
+       int n;
+
+       if (omd->value_on_lws_heap) {
+               lws_free_set_NULL(omd->value__may_own_heap);
+               omd->value_on_lws_heap = 0;
+       }
+
+       p = lws_malloc(len, __func__);
+       if (!p)
+               return 1;
+
+       n = _lws_ss_set_metadata(omd, name, p, len);
+       if (n) {
+               lws_free(p);
+               return n;
+       }
+
+       memcpy(p, value, len);
+
+       omd->value_on_lws_heap = 1;
+
+       return 0;
+}
+
+int
+lws_ss_alloc_set_metadata(struct lws_ss_handle *h, const char *name,
+                         const void *value, size_t len)
+{
+       lws_ss_metadata_t *omd = lws_ss_get_handle_metadata(h, name);
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (!omd) {
+               lwsl_info("%s: unknown metadata %s\n", __func__, name);
+               return 1;
+       }
+
+       return _lws_ss_alloc_set_metadata(omd, name, value, len);
+}
+
+int
+lws_ss_get_metadata(struct lws_ss_handle *h, const char *name,
+                   const void **value, size_t *len)
+{
+       lws_ss_metadata_t *omd = lws_ss_get_handle_metadata(h, name);
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       int n;
+#endif
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (omd) {
+               *value = omd->value__may_own_heap;
+               *len = omd->length;
+
+               return 0;
+       }
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       if (!(h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR))
+               goto bail;
+
+       n = lws_http_string_to_known_header(name, strlen(name));
+       if (n != LWS_HTTP_NO_KNOWN_HEADER) {
+               *len = (size_t)lws_hdr_total_length(h->wsi, n);
+               if (!*len)
+                       goto bail;
+               *value = lws_hdr_simple_ptr(h->wsi, n);
+               if (!*value)
+                       goto bail;
+
+               return 0;
+       }
+#if defined(LWS_WITH_CUSTOM_HEADERS)
+       n = lws_hdr_custom_length(h->wsi, (const char *)name,
+                                 (int)strlen(name));
+       if (n <= 0)
+               goto bail;
+       *value = lwsac_use(&h->imd_ac, (size_t)(n+1), (size_t)(n+1));
+       if (!*value) {
+               lwsl_err("%s ac OOM\n", __func__);
+               return 1;
+       }
+       if (lws_hdr_custom_copy(h->wsi, (char *)(*value), n+1, name,
+                               (int)strlen(name))) {
+               /* waste n+1 bytes until ss is destryed */
+               goto bail;
+       }
+       *len = (size_t)n;
+
+       return 0;
+#endif
+
+bail:
+#endif
+       lwsl_info("%s: unknown metadata %s\n", __func__, name);
+
+       return 1;
+}
+
+lws_ss_metadata_t *
+lws_ss_get_handle_metadata(struct lws_ss_handle *h, const char *name)
+{
+       int n;
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       for (n = 0; n < h->policy->metadata_count; n++)
+               if (!strcmp(name, h->metadata[n].name))
+                       return &h->metadata[n];
+
+       return NULL;
+}
+
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+lws_ss_metadata_t *
+lws_ss_get_handle_instant_metadata(struct lws_ss_handle *h, const char *name)
+{
+       lws_ss_metadata_t *imd = h->instant_metadata;
+
+       while (imd) {
+               if (!strcmp(name, imd->name))
+                       return imd;
+               imd = imd->next;
+       }
+
+       return NULL;
+}
+
+#endif
+
+
+lws_ss_metadata_t *
+lws_ss_policy_metadata(const lws_ss_policy_t *p, const char *name)
+{
+       lws_ss_metadata_t *pmd = p->metadata;
+
+       while (pmd) {
+               if (pmd->name && !strcmp(name, pmd->name))
+                       return pmd;
+               pmd = pmd->next;
+       }
+
+       return NULL;
+}
+
+lws_ss_metadata_t *
+lws_ss_policy_metadata_index(const lws_ss_policy_t *p, size_t index)
+{
+       lws_ss_metadata_t *pmd = p->metadata;
+
+       while (pmd) {
+               if (pmd->length == index)
+                       return pmd;
+               pmd = pmd->next;
+       }
+
+       return NULL;
+}
+
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+static int
+fe_lws_ss_destroy(struct lws_dll2 *d, void *user)
+{
+       lws_ss_handle_t *h = lws_container_of(d, lws_ss_handle_t, list);
+
+       lws_ss_destroy(&h);
+
+       return 0;
+}
+#endif
+
+/*
+ * Dynamic policy: we want to one-time create the vhost for the policy and the
+ * trust store behind it.
+ *
+ * Static policy: We want to make use of a trust store / vhost from the policy and add to its
+ * ss-refcount.
+ */
+
+struct lws_vhost *
+lws_ss_policy_ref_trust_store(struct lws_context *context,
+                             const lws_ss_policy_t *pol, char doref)
+{
+       struct lws_context_creation_info i;
+       struct lws_vhost *v;
+       int n;
+
+       memset(&i, 0, sizeof(i));
+
+       if (!pol->trust.store) {
+               v = lws_get_vhost_by_name(context, "_ss_default");
+               if (!v) {
+                       /* corner case... there's no trust store used */
+                       i.options = context->options;
+                       i.vhost_name = "_ss_default";
+                       i.port = CONTEXT_PORT_NO_LISTEN;
+                       v = lws_create_vhost(context, &i);
+                       if (!v) {
+                               lwsl_err("%s: failed to create vhost %s\n",
+                                        __func__, i.vhost_name);
+
+                               return NULL;
+                       }
+               }
+
+               goto accepted;
+       }
+       v = lws_get_vhost_by_name(context, pol->trust.store->name);
+       if (v) {
+               lwsl_debug("%s: vh already exists\n", __func__);
+               goto accepted;
+       }
+
+       i.options = context->options;
+       i.vhost_name = pol->trust.store->name;
+       lwsl_debug("%s: %s\n", __func__, i.vhost_name);
+#if defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
+       i.client_ssl_ca_mem = pol->trust.store->ssx509[0]->ca_der;
+       i.client_ssl_ca_mem_len = (unsigned int)
+                       pol->trust.store->ssx509[0]->ca_der_len;
+#endif
+       i.port = CONTEXT_PORT_NO_LISTEN;
+       lwsl_info("%s: %s trust store initial '%s'\n", __func__,
+                 i.vhost_name, pol->trust.store->ssx509[0]->vhost_name);
+
+       v = lws_create_vhost(context, &i);
+       if (!v) {
+               lwsl_err("%s: failed to create vhost %s\n",
+                        __func__, i.vhost_name);
+               return NULL;
+       } else
+               v->from_ss_policy = 1;
+
+       for (n = 1; v && n < pol->trust.store->count; n++) {
+               lwsl_info("%s: add '%s' to trust store\n", __func__,
+                         pol->trust.store->ssx509[n]->vhost_name);
+#if defined(LWS_WITH_TLS)
+               if (lws_tls_client_vhost_extra_cert_mem(v,
+                               pol->trust.store->ssx509[n]->ca_der,
+                               pol->trust.store->ssx509[n]->ca_der_len)) {
+                       lwsl_err("%s: add extra cert failed\n",
+                                       __func__);
+                       return NULL;
+               }
+#endif
+       }
+
+accepted:
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) || defined(LWS_WITH_SECURE_STREAMS_CPP)
+       if (doref)
+               v->ss_refcount++;
+#endif
+
+       return v;
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) || defined(LWS_WITH_SECURE_STREAMS_CPP)
+int
+lws_ss_policy_unref_trust_store(struct lws_context *context,
+                               const lws_ss_policy_t *pol)
+{
+       struct lws_vhost *v;
+       const char *name = "_ss_default";
+
+       if (pol->trust.store)
+               name = pol->trust.store->name;
+
+       v = lws_get_vhost_by_name(context, name);
+       if (!v || !v->from_ss_policy)
+               return 0;
+
+       assert(v->ss_refcount);
+
+       v->ss_refcount--;
+       if (!v->ss_refcount) {
+               lwsl_notice("%s: destroying vh %s\n", __func__, name);
+               lws_vhost_destroy(v);
+       }
+
+       return 1;
+}
+#endif
+
+int
+lws_ss_policy_set(struct lws_context *context, const char *name)
+{
+       int ret = 0;
+
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
+       const lws_ss_policy_t *pol;
+       struct lws_vhost *v;
+       lws_ss_x509_t *x;
+       char buf[16];
+       int m;
+
+       /*
+        * Parsing seems to have succeeded, and we're going to use the new
+        * policy that's laid out in args->ac
+        */
+
+       if (!args)
+               return 1;
+
+       lejp_destruct(&args->jctx);
+
+       if (context->ac_policy) {
+               int n;
+
+#if defined(LWS_WITH_SYS_METRICS)
+               lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                          context->owner_mtr_dynpol.head) {
+                       lws_metric_policy_dyn_t *dm =
+                               lws_container_of(d, lws_metric_policy_dyn_t, list);
+
+                       lws_metric_policy_dyn_destroy(dm, 1); /* keep */
+
+               } lws_end_foreach_dll_safe(d, d1);
+#endif
+
+               /*
+                * any existing ss created with the old policy have to go away
+                * now, since they point to the shortly-to-be-destroyed old
+                * policy
+                */
+
+               for (n = 0; n < context->count_threads; n++) {
+                       struct lws_context_per_thread *pt = &context->pt[n];
+
+                       lws_dll2_foreach_safe(&pt->ss_owner, NULL, fe_lws_ss_destroy);
+               }
+
+               /*
+                * So this is a bit fun-filled, we already had a policy in
+                * force, perhaps it was the default policy that's just good for
+                * fetching the real policy, and we're doing that now.
+                *
+                * We can destroy all the policy-related direct allocations
+                * easily because they're cleanly in a single lwsac...
+                */
+               lwsac_free(&context->ac_policy);
+
+               /*
+                * ...but when we did the trust stores, we created vhosts for
+                * each.  We need to destroy those now too, and recreate new
+                * ones from the new policy, perhaps with different X.509s.
+                *
+                * Vhost destruction is inherently async, it can't be destroyed
+                * until all of the wsi bound to it have closed, and, eg, libuv
+                * means their closure is deferred until a later go around the
+                * event loop.  SMP means we also have to wait for all the pts
+                * to close their wsis that are bound on the vhost too.
+                *
+                * This marks the vhost as being destroyed so new things won't
+                * use it, and starts the close of all wsi on this pt that are
+                * bound to the wsi, and deals with the listen socket if any.
+                * "being-destroyed" vhosts can't be found using get_vhost_by_
+                * name(), so if a new vhost of the same name exists that isn't
+                * being destroyed that will be the one found.
+                *
+                * When the number of wsi bound to the vhost gets to zero a
+                * short time later, the vhost is actually destroyed.
+                */
+
+               v = context->vhost_list;
+               while (v) {
+                       if (v->from_ss_policy) {
+                               struct lws_vhost *vh = v->vhost_next;
+                               lwsl_debug("%s: destroying %s\n", __func__, lws_vh_tag(v));
+                               lws_vhost_destroy(v);
+                               v = vh;
+                               continue;
+                       }
+                       v = v->vhost_next;
+               }
+       }
+
+       context->pss_policies = args->heads[LTY_POLICY].p;
+       context->ac_policy = args->ac;
+
+       lws_humanize(buf, sizeof(buf), lwsac_total_alloc(args->ac),
+                       humanize_schema_si_bytes);
+       if (lwsac_total_alloc(args->ac))
+               m = (int)((lwsac_total_overhead(args->ac) * 100) /
+                               lwsac_total_alloc(args->ac));
+       else
+               m = 0;
+
+       (void)m;
+       lwsl_info("%s: %s, pad %d%c: %s\n", __func__, buf, m, '%', name);
+
+       /* Create vhosts for each type of trust store */
+
+       /*
+        * We get called from context creation... instantiates
+        * vhosts with client tls contexts set up for each unique CA.
+        *
+        * We create the vhosts by walking streamtype list and create vhosts
+        * using trust store name if it's a client connection that doesn't
+        * already exist.
+        */
+
+       pol = context->pss_policies;
+       while (pol) {
+               if (!(pol->flags & LWSSSPOLF_SERVER)) {
+                       v = lws_ss_policy_ref_trust_store(context, pol,
+                                                 0 /* no refcount inc */);
+                       if (!v)
+                               ret = 1;
+               }
+
+               pol = pol->next;
+       }
+
+#if defined(LWS_WITH_SOCKS5)
+
+       /*
+        * ... we need to go through every vhost updating its understanding of
+        * which socks5 proxy to use...
+        */
+
+       v = context->vhost_list;
+       while (v) {
+               lws_set_socks(v, args->socks5_proxy);
+               v = v->vhost_next;
+       }
+       if (context->vhost_system)
+               lws_set_socks(context->vhost_system, args->socks5_proxy);
+
+       if (args->socks5_proxy)
+               lwsl_notice("%s: global socks5 proxy: %s\n", __func__,
+                           args->socks5_proxy);
+#endif
+
+       /*
+        * For dynamic policy case, now we processed the x.509 CAs, we can free
+        * all of our originals.  For static policy, they're in .rodata, nothing
+        * to free.
+        */
+
+       x = args->heads[LTY_X509].x;
+       while (x) {
+               /*
+                * Free all the client DER buffers now they have been parsed
+                * into tls library X.509 objects
+                */
+               if (!x->keep) { /* used for server */
+                       lws_free((void *)x->ca_der);
+                       x->ca_der = NULL;
+               }
+
+               x = x->next;
+       }
+
+       context->last_policy = time(NULL);
+#if defined(LWS_WITH_SYS_METRICS)
+       if (context->pss_policies)
+               ((lws_ss_policy_t *)context->pss_policies)->metrics =
+                                               args->heads[LTY_METRICS].m;
+#endif
+
+       /* and we can discard the parsing args object now, invalidating args */
+
+       lws_free_set_NULL(context->pol_args);
+#endif
+
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_metric_rebind_policies(context);
+#endif
+
+#if defined(LWS_WITH_SYS_SMD)
+       (void)lws_smd_msg_printf(context, LWSSMDCL_SYSTEM_STATE,
+                                "{\"policy\":\"updated\",\"ts\":%lu}",
+                                  (long)context->last_policy);
+#endif
+
+       return ret;
+}
diff --git a/lib/secure-streams/policy-json.c b/lib/secure-streams/policy-json.c
new file mode 100644 (file)
index 0000000..7e5656f
--- /dev/null
@@ -0,0 +1,1294 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This file contains the stuff related to JSON-provided policy, it's not built
+ * if LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY enabled.
+ */
+
+#include <private-lib-core.h>
+
+static const char * const lejp_tokens_policy[] = {
+       "release",
+       "product",
+       "schema-version",
+       "via-socks5",
+       "retry[].*.backoff",
+       "retry[].*.conceal",
+       "retry[].*.jitterpc",
+       "retry[].*.svalidping",
+       "retry[].*.svalidhup",
+       "retry[].*",
+       "certs[].*",
+       "trust_stores[].name",
+       "trust_stores[].stack",
+       "metrics[].name",
+       "metrics[].us_schedule",
+       "metrics[].us_halflife",
+       "metrics[].min_outlier",
+       "metrics[].report",
+       "s[].*.endpoint",
+       "s[].*.via-socks5",
+       "s[].*.protocol",
+       "s[].*.port",
+       "s[].*.plugins",
+       "s[].*.tls",
+       "s[].*.client_cert",
+       "s[].*.opportunistic",
+       "s[].*.nailed_up",
+       "s[].*.allow_redirects",
+       "s[].*.urgent_tx",
+       "s[].*.urgent_rx",
+       "s[].*.attr_priority",
+       "s[].*.attr_low_latency",
+       "s[].*.attr_high_throughput",
+       "s[].*.attr_high_reliability",
+       "s[].*.attr_low_cost",
+       "s[].*.long_poll",
+       "s[].*.ws_prioritize_reads",
+       "s[].*.retry",
+       "s[].*.timeout_ms",
+       "s[].*.perf",
+       "s[].*.tls_trust_store",
+       "s[].*.proxy_buflen",
+       "s[].*.proxy_buflen_rxflow_on_above",
+       "s[].*.proxy_buflen_rxflow_off_below",
+       "s[].*.client_buflen",
+       "s[].*.client_buflen_rxflow_on_above",
+       "s[].*.client_buflen_rxflow_off_below",
+       "s[].*.metadata",
+       "s[].*.metadata[].*",
+       "s[].*.http_resp_map",
+       "s[].*.http_resp_map[].*",
+
+       "s[].*.http_auth_header",
+       "s[].*.http_dsn_header",
+       "s[].*.http_fwv_header",
+       "s[].*.http_devtype_header",
+
+       "s[].*.http_auth_preamble",
+
+       "s[].*.http_no_content_length",
+       "s[].*.rideshare",      /* streamtype name this rides shotgun with */
+       "s[].*.payload_fmt",
+       "s[].*.http_method",
+       "s[].*.http_url",
+       "s[].*.nghttp2_quirk_end_stream",
+       "s[].*.h2q_oflow_txcr",
+       "s[].*.http_multipart_name",
+       "s[].*.http_multipart_filename",
+       "s[].*.http_mime_content_type",
+       "s[].*.http_www_form_urlencoded",
+       "s[].*.http_expect",
+       "s[].*.http_cookies",
+       "s[].*.http_fail_redirect",
+       "s[].*.http_multipart_ss_in",
+       "s[].*.ws_subprotocol",
+       "s[].*.ws_binary",
+       "s[].*.local_sink",
+       "s[].*.server",
+       "s[].*.server_cert",
+       "s[].*.server_key",
+       "s[].*.mqtt_topic",
+       "s[].*.mqtt_subscribe",
+       "s[].*.mqtt_qos",
+       "s[].*.mqtt_keep_alive",
+       "s[].*.mqtt_clean_start",
+       "s[].*.mqtt_will_topic",
+       "s[].*.mqtt_will_message",
+       "s[].*.mqtt_will_qos",
+       "s[].*.mqtt_will_retain",
+       "s[].*.mqtt_birth_topic",
+       "s[].*.mqtt_birth_message",
+       "s[].*.mqtt_birth_qos",
+       "s[].*.mqtt_birth_retain",
+       "s[].*.aws_iot",
+       "s[].*.swake_validity",
+       "s[].*.use_auth",
+       "s[].*.aws_region",
+       "s[].*.aws_service",
+       "s[].*.direct_proto_str",
+       "s[].*",
+       "auth[].name",
+       "auth[].type",
+       "auth[].streamtype",
+       "auth[].blob",
+       "auth[]",
+};
+
+typedef enum {
+       LSSPPT_RELEASE,
+       LSSPPT_PRODUCT,
+       LSSPPT_SCHEMA_VERSION,
+       LSSPPT_VIA_SOCKS5,
+       LSSPPT_BACKOFF,
+       LSSPPT_CONCEAL,
+       LSSPPT_JITTERPC,
+       LSSPPT_VALIDPING_S,
+       LSSPPT_VALIDHUP_S,
+       LSSPPT_RETRY,
+       LSSPPT_CERTS,
+       LSSPPT_TRUST_STORES_NAME,
+       LSSPPT_TRUST_STORES_STACK,
+       LSSPPT_METRICS_NAME,
+       LSSPPT_METRICS_US_SCHEDULE,
+       LSSPPT_METRICS_US_HALFLIFE,
+       LSSPPT_METRICS_MIN_OUTLIER,
+       LSSPPT_METRICS_REPORT,
+       LSSPPT_ENDPOINT,
+       LSSPPT_VH_VIA_SOCKS5,
+       LSSPPT_PROTOCOL,
+       LSSPPT_PORT,
+       LSSPPT_PLUGINS,
+       LSSPPT_TLS,
+       LSSPPT_TLS_CLIENT_CERT,
+       LSSPPT_OPPORTUNISTIC,
+       LSSPPT_NAILED_UP,
+       LSSPPT_ALLOW_REDIRECTS,
+       LSSPPT_URGENT_TX,
+       LSSPPT_URGENT_RX,
+       LSSPPT_ATTR_PRIORITY,
+       LSSPPT_ATTR_LOW_LATENCY,
+       LSSPPT_ATTR_HIGH_THROUGHPUT,
+       LSSPPT_ATTR_HIGH_RELIABILITY,
+       LSSPPT_ATTR_LOW_COST,
+       LSSPPT_LONG_POLL,
+       LSSPPT_PRIORITIZE_READS,
+       LSSPPT_RETRYPTR,
+       LSSPPT_DEFAULT_TIMEOUT_MS,
+       LSSPPT_PERF,
+       LSSPPT_TRUST,
+       LSSPPT_PROXY_BUFLEN,
+       LSSPPT_PROXY_BUFLEN_RXFLOW_ON_ABOVE,
+       LSSPPT_PROXY_BUFLEN_RXFLOW_OFF_BELOW,
+       LSSPPT_CLIENT_BUFLEN,
+       LSSPPT_CLIENT_BUFLEN_RXFLOW_ON_ABOVE,
+       LSSPPT_CLIENT_BUFLEN_RXFLOW_OFF_BELOW,
+       LSSPPT_METADATA,
+       LSSPPT_METADATA_ITEM,
+       LSSPPT_HTTPRESPMAP,
+       LSSPPT_HTTPRESPMAP_ITEM,
+
+       LSSPPT_HTTP_AUTH_HEADER,
+       LSSPPT_HTTP_DSN_HEADER,
+       LSSPPT_HTTP_FWV_HEADER,
+       LSSPPT_HTTP_TYPE_HEADER,
+
+       LSSPPT_HTTP_AUTH_PREAMBLE,
+       LSSPPT_HTTP_NO_CONTENT_LENGTH,
+       LSSPPT_RIDESHARE,
+       LSSPPT_PAYLOAD_FORMAT,
+       LSSPPT_HTTP_METHOD,
+       LSSPPT_HTTP_URL,
+       LSSPPT_NGHTTP2_QUIRK_END_STREAM,
+       LSSPPT_H2_QUIRK_OVERFLOWS_TXCR,
+       LSSPPT_HTTP_MULTIPART_NAME,
+       LSSPPT_HTTP_MULTIPART_FILENAME,
+       LSSPPT_HTTP_MULTIPART_CONTENT_TYPE,
+       LSSPPT_HTTP_WWW_FORM_URLENCODED,
+       LSSPPT_HTTP_EXPECT,
+       LSSPPT_HTTP_COOKIES,
+       LSSPPT_HTTP_FAIL_REDIRECT,
+       LSSPPT_HTTP_MULTIPART_SS_IN,
+       LSSPPT_WS_SUBPROTOCOL,
+       LSSPPT_WS_BINARY,
+       LSSPPT_LOCAL_SINK,
+       LSSPPT_SERVER,
+       LSSPPT_SERVER_CERT,
+       LSSPPT_SERVER_KEY,
+       LSSPPT_MQTT_TOPIC,
+       LSSPPT_MQTT_SUBSCRIBE,
+       LSSPPT_MQTT_QOS,
+       LSSPPT_MQTT_KEEPALIVE,
+       LSSPPT_MQTT_CLEAN_START,
+       LSSPPT_MQTT_WILL_TOPIC,
+       LSSPPT_MQTT_WILL_MESSAGE,
+       LSSPPT_MQTT_WILL_QOS,
+       LSSPPT_MQTT_WILL_RETAIN,
+       LSSPPT_MQTT_BIRTH_TOPIC,
+       LSSPPT_MQTT_BIRTH_MESSAGE,
+       LSSPPT_MQTT_BIRTH_QOS,
+       LSSPPT_MQTT_BIRTH_RETAIN,
+       LSSPPT_MQTT_AWS_IOT,
+       LSSPPT_SWAKE_VALIDITY,
+       LSSPPT_USE_AUTH,
+       LSSPPT_AWS_REGION,
+       LSSPPT_AWS_SERVICE,
+       LSSPPT_DIRECT_PROTO_STR,
+       LSSPPT_STREAMTYPES,
+       LSSPPT_AUTH_NAME,
+       LSSPPT_AUTH_TYPE,
+       LSSPPT_AUTH_STREAMTYPE,
+       LSSPPT_AUTH_BLOB,
+       LSSPPT_AUTH,
+
+} policy_token_t;
+
+#define POL_AC_INITIAL 2048
+#define POL_AC_GRAIN   800
+#define MAX_CERT_TEMP  3072 /* used to discover actual cert size for realloc */
+
+static uint16_t sizes[] = {
+       sizeof(backoff_t),
+       sizeof(lws_ss_x509_t),
+       sizeof(lws_ss_trust_store_t),
+       sizeof(lws_ss_policy_t),
+       sizeof(lws_ss_auth_t),
+       sizeof(lws_metric_policy_t),
+};
+
+static const char * const protonames[] = {
+       "h1",           /* LWSSSP_H1 */
+       "h2",           /* LWSSSP_H2 */
+       "ws",           /* LWSSSP_WS */
+       "mqtt",         /* LWSSSP_MQTT */
+       "raw",          /* LWSSSP_RAW */
+};
+
+static const lws_ss_auth_t *
+lws_ss_policy_find_auth_by_name(struct policy_cb_args *a,
+                               const char *name, size_t len)
+{
+       const lws_ss_auth_t *auth = a->heads[LTY_AUTH].a;
+
+       while (auth) {
+               if (auth->name &&
+                   len == strlen(auth->name) &&
+                   !strncmp(auth->name, name, len))
+                       return auth;
+
+               auth = auth->next;
+       }
+
+       return NULL;
+}
+
+static int
+lws_ss_policy_alloc_helper(struct policy_cb_args *a, int type)
+{
+       /*
+        * We do the pointers always as .b union member, all of the
+        * participating structs begin with .next and .name the same
+        */
+
+       a->curr[type].b = lwsac_use_zero(&a->ac,
+                               sizes[type], POL_AC_GRAIN);
+       if (!a->curr[type].b)
+               return 1;
+
+       a->curr[type].b->next = a->heads[type].b;
+       a->heads[type].b = a->curr[type].b;
+
+       return 0;
+}
+
+static signed char
+lws_ss_policy_parser_cb(struct lejp_ctx *ctx, char reason)
+{
+       struct policy_cb_args *a = (struct policy_cb_args *)ctx->user;
+#if defined(LWS_WITH_SSPLUGINS)
+       const lws_ss_plugin_t **pin;
+#endif
+       char **pp, dotstar[32], *q;
+       lws_ss_trust_store_t *ts;
+       lws_ss_metadata_t *pmd;
+       lws_ss_x509_t *x, **py;
+       lws_ss_policy_t *p2;
+       lws_retry_bo_t *b;
+       size_t inl, outl;
+       uint8_t *extant;
+       backoff_t *bot;
+       int n = -1;
+
+//     lwsl_debug("%s: %d %d %s\n", __func__, reason, ctx->path_match - 1,
+//                ctx->path);
+
+       switch (ctx->path_match - 1) {
+       case LSSPPT_RETRY:
+               n = LTY_BACKOFF;
+               break;
+       case LSSPPT_CERTS:
+               n = LTY_X509;
+               break;
+       case LSSPPT_TRUST_STORES_NAME:
+       case LSSPPT_TRUST_STORES_STACK:
+               n = LTY_TRUSTSTORE;
+               break;
+       case LSSPPT_STREAMTYPES:
+               n = LTY_POLICY;
+               break;
+       case LSSPPT_AUTH:
+               n = LTY_AUTH;
+               break;
+       case LSSPPT_METRICS_NAME:
+       case LSSPPT_METRICS_US_SCHEDULE:
+       case LSSPPT_METRICS_US_HALFLIFE:
+       case LSSPPT_METRICS_MIN_OUTLIER:
+       case LSSPPT_METRICS_REPORT:
+               n = LTY_METRICS;
+               break;
+       }
+
+       if (reason == LEJPCB_ARRAY_START &&
+           (ctx->path_match - 1 == LSSPPT_PLUGINS ||
+            ctx->path_match - 1 == LSSPPT_METADATA ||
+            ctx->path_match - 1 == LSSPPT_HTTPRESPMAP))
+               a->count = 0;
+
+       if (reason == LEJPCB_OBJECT_START && n == LTY_AUTH) {
+               if (lws_ss_policy_alloc_helper(a, LTY_AUTH))
+                       goto oom;
+               return 0;
+       }
+
+       if (reason == LEJPCB_ARRAY_END &&
+           ctx->path_match - 1 == LSSPPT_TRUST_STORES_STACK && !a->count) {
+               lwsl_err("%s: at least one cert required in trust store\n",
+                               __func__);
+               goto oom;
+       }
+
+       if (reason == LEJPCB_ARRAY_END && a->count && a->pending_respmap) {
+
+               // lwsl_notice("%s: allocating respmap %d\n", __func__, a->count);
+
+               a->curr[LTY_POLICY].p->u.http.respmap = lwsac_use_zero(&a->ac,
+                       sizeof(lws_ss_http_respmap_t) * (unsigned int)a->count, POL_AC_GRAIN);
+
+               if (!a->curr[LTY_POLICY].p->u.http.respmap)
+                       goto oom;
+
+               memcpy((void *)a->curr[LTY_POLICY].p->u.http.respmap,
+                      a->respmap, sizeof(lws_ss_http_respmap_t) * (unsigned int)a->count);
+               a->curr[LTY_POLICY].p->u.http.count_respmap = (uint8_t)a->count;
+               a->count = 0;
+               a->pending_respmap = 0;
+
+               return 0;
+       }
+
+       if (reason == LEJPCB_OBJECT_END && a->p) {
+               /*
+                * Allocate a just-the-right-size buf for the cert DER now
+                * we decoded it into the a->p temp buffer and know the exact
+                * size.
+                *
+                * The struct *x is in the lwsac... the ca_der it points to
+                * is individually allocated from the heap
+                */
+               a->curr[LTY_X509].x->ca_der = lws_malloc((unsigned int)a->count, "ssx509");
+               if (!a->curr[LTY_X509].x->ca_der)
+                       goto oom;
+               memcpy((uint8_t *)a->curr[LTY_X509].x->ca_der, a->p, (unsigned int)a->count);
+               a->curr[LTY_X509].x->ca_der_len = (unsigned int)a->count;
+
+               /*
+                * ... and then we can free the temp buffer
+                */
+               lws_free_set_NULL(a->p);
+
+               return 0;
+       }
+
+       if (reason == LEJPCB_PAIR_NAME && n != -1 &&
+           (n != LTY_TRUSTSTORE && n != LTY_AUTH && n != LTY_METRICS)) {
+
+               p2 = NULL;
+               if (n == LTY_POLICY) {
+                       /*
+                        * We want to allow for the possibility of overlays...
+                        * eg, we come later with a JSON snippet that overrides
+                        * select streamtype members of a streamtype that was
+                        * already defined
+                        */
+                       p2 = (lws_ss_policy_t *)a->context->pss_policies;
+
+                       while (p2) {
+                               if (!strncmp(p2->streamtype,
+                                            ctx->path + ctx->st[ctx->sp].p,
+                                            (unsigned int)(ctx->path_match_len -
+                                                         ctx->st[ctx->sp].p))) {
+                                       lwsl_info("%s: overriding s[] %s\n",
+                                                 __func__, p2->streamtype);
+                                       break;
+                               }
+
+                               p2 = p2->next;
+                       }
+               }
+
+               /*
+                * We do the pointers always as .b union member, all of the
+                * participating structs begin with .next and .name the same
+                */
+               if (p2) /* we may be overriding existing streamtype... */
+                       a->curr[n].b = (backoff_t *)p2;
+               else
+                       a->curr[n].b = lwsac_use_zero(&a->ac, sizes[n],
+                                                       POL_AC_GRAIN);
+               if (!a->curr[n].b)
+                       goto oom;
+
+               if (n == LTY_X509) {
+                       a->p = lws_malloc(MAX_CERT_TEMP, "cert temp");
+                       if (!a->p)
+                               goto oom;
+                       memset(&a->b64, 0, sizeof(a->b64));
+               }
+
+               a->count = 0;
+               if (!p2) {
+                       a->curr[n].b->next = a->heads[n].b;
+                       a->heads[n].b = a->curr[n].b;
+                       pp = (char **)&a->curr[n].b->name;
+
+                       goto string1;
+               }
+
+               return 0; /* overriding */
+       }
+
+       if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
+               return 0;
+
+       switch (ctx->path_match - 1) {
+
+       /* strings */
+
+       case LSSPPT_RELEASE:
+               break;
+
+       case LSSPPT_PRODUCT:
+               break;
+
+       case LSSPPT_SCHEMA_VERSION:
+               break;
+
+       case LSSPPT_VIA_SOCKS5:
+               /* the global / default proxy */
+               pp = (char **)&a->socks5_proxy;
+               goto string2;
+
+       case LSSPPT_BACKOFF:
+               b = &a->curr[LTY_BACKOFF].b->r;
+               if (b->retry_ms_table_count == 8) {
+                       lwsl_err("%s: > 8 backoff levels\n", __func__);
+                       return 1;
+               }
+               if (!b->retry_ms_table_count) {
+                       b->retry_ms_table = (uint32_t *)lwsac_use_zero(&a->ac,
+                                          sizeof(uint32_t) * 8, POL_AC_GRAIN);
+                       if (!b->retry_ms_table)
+                               goto oom;
+               }
+
+               ((uint32_t *)b->retry_ms_table)
+                               [b->retry_ms_table_count++] = (uint32_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_CONCEAL:
+               a->curr[LTY_BACKOFF].b->r.conceal_count = (uint16_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_JITTERPC:
+               a->curr[LTY_BACKOFF].b->r.jitter_percent = (uint8_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_VALIDPING_S:
+               a->curr[LTY_BACKOFF].b->r.secs_since_valid_ping = (uint16_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_VALIDHUP_S:
+               a->curr[LTY_BACKOFF].b->r.secs_since_valid_hangup = (uint16_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_CERTS:
+               if (a->count + ctx->npos >= MAX_CERT_TEMP) {
+                       lwsl_err("%s: cert too big\n", __func__);
+                       goto oom;
+               }
+               inl = ctx->npos;
+               outl = MAX_CERT_TEMP - (unsigned int)a->count;
+
+               lws_b64_decode_stateful(&a->b64, ctx->buf, &inl,
+                                       a->p + a->count, &outl,
+                                       reason == LEJPCB_VAL_STR_END);
+               a->count += (int)outl;
+               if (inl != ctx->npos) {
+                       lwsl_err("%s: b64 decode fail\n", __func__);
+                       goto oom;
+               }
+               break;
+
+       case LSSPPT_TRUST_STORES_NAME:
+               if (lws_ss_policy_alloc_helper(a, LTY_TRUSTSTORE))
+                       goto oom;
+
+               a->count = 0;
+               pp = (char **)&a->curr[LTY_TRUSTSTORE].b->name;
+
+               goto string2;
+
+       case LSSPPT_TRUST_STORES_STACK:
+               if (a->count >= (int)LWS_ARRAY_SIZE(
+                                       a->curr[LTY_TRUSTSTORE].t->ssx509)) {
+                       lwsl_err("%s: trust store too big\n", __func__);
+                       goto oom;
+               }
+               lwsl_debug("%s: trust stores stack %.*s\n", __func__,
+                          ctx->npos, ctx->buf);
+               x = a->heads[LTY_X509].x;
+               while (x) {
+                       if (!strncmp(x->vhost_name, ctx->buf, ctx->npos)) {
+                               a->curr[LTY_TRUSTSTORE].t->ssx509[a->count++] = x;
+                               a->curr[LTY_TRUSTSTORE].t->count++;
+
+                               return 0;
+                       }
+                       x = x->next;
+               }
+               lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
+               lwsl_err("%s: unknown trust store entry %s\n", __func__,
+                        dotstar);
+               goto oom;
+#if defined(LWS_WITH_SYS_METRICS)
+       case LSSPPT_METRICS_NAME:
+               if (lws_ss_policy_alloc_helper(a, LTY_METRICS))
+                       goto oom;
+
+               pp = (char **)&a->curr[LTY_METRICS].b->name;
+
+               goto string2;
+
+       case LSSPPT_METRICS_US_SCHEDULE:
+               a->curr[LTY_METRICS].m->us_schedule = (uint64_t)atoll(ctx->buf);
+               break;
+
+       case LSSPPT_METRICS_US_HALFLIFE:
+               a->curr[LTY_METRICS].m->us_decay_unit = (uint32_t)atol(ctx->buf);
+               break;
+
+       case LSSPPT_METRICS_MIN_OUTLIER:
+               a->curr[LTY_METRICS].m->min_contributors = (uint8_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_METRICS_REPORT:
+               pp = (char **)&a->curr[LTY_METRICS].m->report;
+               goto string2;
+#endif
+
+       case LSSPPT_SERVER_CERT:
+       case LSSPPT_SERVER_KEY:
+
+               /* iterate through the certs */
+
+               py = &a->heads[LTY_X509].x;
+               x = a->heads[LTY_X509].x;
+               while (x) {
+                       if (!strncmp(x->vhost_name, ctx->buf, ctx->npos) &&
+                                       !x->vhost_name[ctx->npos]) {
+                               if ((ctx->path_match - 1) == LSSPPT_SERVER_CERT)
+                                       a->curr[LTY_POLICY].p->trust.server.cert = x;
+                               else
+                                       a->curr[LTY_POLICY].p->trust.server.key = x;
+                               /*
+                                * Certs that are for servers need to stick
+                                * around in DER form, so the vhost can be
+                                * instantiated when the server is brought up
+                                */
+                               x->keep = 1;
+                               lwsl_notice("%s: server '%s' keep %d %p\n",
+                                           __func__, x->vhost_name,
+                                               ctx->path_match - 1, x);
+
+                               /*
+                                * Server DER we need to move it to another
+                                * list just for destroying it when the context
+                                * is destroyed... snip us out of the live
+                                * X.509 list
+                                */
+
+                               *py = x->next;
+
+                               /*
+                                * ... and instead put us on the list of things
+                                * to keep hold of for context destruction
+                                */
+
+                               x->next = a->context->server_der_list;
+                               a->context->server_der_list = x;
+
+                               return 0;
+                       }
+                       py = &x->next;
+                       x = x->next;
+               }
+               lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
+               lwsl_err("%s: unknown cert / key %s\n", __func__, dotstar);
+               goto oom;
+
+       case LSSPPT_ENDPOINT:
+               pp = (char **)&a->curr[LTY_POLICY].p->endpoint;
+               goto string2;
+
+       case LSSPPT_VH_VIA_SOCKS5:
+               pp = (char **)&a->curr[LTY_POLICY].p->socks5_proxy;
+               goto string2;
+
+       case LSSPPT_PORT:
+               a->curr[LTY_POLICY].p->port = (uint16_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_PROXY_BUFLEN:
+               a->curr[LTY_POLICY].p->proxy_buflen = (uint32_t)atol(ctx->buf);
+               break;
+
+       case LSSPPT_PROXY_BUFLEN_RXFLOW_ON_ABOVE:
+               a->curr[LTY_POLICY].p->proxy_buflen_rxflow_on_above =
+                                               (uint32_t)atol(ctx->buf);
+               break;
+       case LSSPPT_PROXY_BUFLEN_RXFLOW_OFF_BELOW:
+               a->curr[LTY_POLICY].p->proxy_buflen_rxflow_off_below =
+                                               (uint32_t)atol(ctx->buf);
+               break;
+
+       case LSSPPT_CLIENT_BUFLEN:
+               a->curr[LTY_POLICY].p->client_buflen = (uint32_t)atol(ctx->buf);
+               break;
+
+       case LSSPPT_CLIENT_BUFLEN_RXFLOW_ON_ABOVE:
+               a->curr[LTY_POLICY].p->client_buflen_rxflow_on_above =
+                                               (uint32_t)atol(ctx->buf);
+               break;
+       case LSSPPT_CLIENT_BUFLEN_RXFLOW_OFF_BELOW:
+               a->curr[LTY_POLICY].p->client_buflen_rxflow_off_below =
+                                               (uint32_t)atol(ctx->buf);
+               break;
+
+       case LSSPPT_HTTP_METHOD:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.http.method;
+               goto string2;
+
+       case LSSPPT_HTTP_URL:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.http.url;
+               goto string2;
+
+       case LSSPPT_RIDESHARE:
+               pp = (char **)&a->curr[LTY_POLICY].p->rideshare_streamtype;
+               goto string2;
+
+       case LSSPPT_PAYLOAD_FORMAT:
+               pp = (char **)&a->curr[LTY_POLICY].p->payload_fmt;
+               goto string2;
+
+       case LSSPPT_PLUGINS:
+#if defined(LWS_WITH_SSPLUGINS)
+               pin = a->context->pss_plugins;
+               if (a->count ==
+                         (int)LWS_ARRAY_SIZE(a->curr[LTY_POLICY].p->plugins)) {
+                       lwsl_err("%s: too many plugins\n", __func__);
+
+                       goto oom;
+               }
+               if (!pin)
+                       break;
+               while (*pin) {
+                       if (!strncmp((*pin)->name, ctx->buf, ctx->npos)) {
+                               a->curr[LTY_POLICY].p->plugins[a->count++] = *pin;
+                               return 0;
+                       }
+                       pin++;
+               }
+               lwsl_err("%s: unknown plugin\n", __func__);
+               goto oom;
+#else
+               break;
+#endif
+
+       case LSSPPT_TLS:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_TLS;
+               break;
+
+       case LSSPPT_TLS_CLIENT_CERT:
+               a->curr[LTY_POLICY].p->client_cert = (uint8_t)(atoi(ctx->buf) + 1);
+               break;
+
+       case LSSPPT_AUTH_BLOB:
+               a->curr[LTY_AUTH].a->blob_index = (uint8_t)atoi(ctx->buf);
+               break;
+       case LSSPPT_HTTP_EXPECT:
+               a->curr[LTY_POLICY].p->u.http.resp_expect = (uint16_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_DEFAULT_TIMEOUT_MS:
+               a->curr[LTY_POLICY].p->timeout_ms = (uint32_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_ATTR_PRIORITY:
+               a->curr[LTY_POLICY].p->priority = (uint8_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_OPPORTUNISTIC:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_OPPORTUNISTIC;
+               break;
+       case LSSPPT_NAILED_UP:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_NAILED_UP;
+               break;
+       case LSSPPT_URGENT_TX:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_URGENT_TX;
+               break;
+       case LSSPPT_URGENT_RX:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_URGENT_RX;
+               break;
+       case LSSPPT_LONG_POLL:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_LONG_POLL;
+               break;
+       case LSSPPT_PRIORITIZE_READS:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_PRIORITIZE_READS;
+               break;
+
+       case LSSPPT_HTTP_WWW_FORM_URLENCODED:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                       LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED;
+               break;
+       case LSSPPT_SWAKE_VALIDITY:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                       LWSSSPOLF_WAKE_SUSPEND__VALIDITY;
+               break;
+       case LSSPPT_ALLOW_REDIRECTS:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                               LWSSSPOLF_ALLOW_REDIRECTS;
+               break;
+       case LSSPPT_HTTP_COOKIES:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                               LWSSSPOLF_HTTP_CACHE_COOKIES;
+               break;
+       case LSSPPT_HTTP_MULTIPART_SS_IN:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                               LWSSSPOLF_HTTP_MULTIPART_IN;
+               return 0;
+
+       case LSSPPT_ATTR_LOW_LATENCY:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                               LWSSSPOLF_ATTR_LOW_LATENCY;
+               return 0;
+
+       case LSSPPT_ATTR_HIGH_THROUGHPUT:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                               LWSSSPOLF_ATTR_HIGH_THROUGHPUT;
+               return 0;
+
+       case LSSPPT_ATTR_HIGH_RELIABILITY:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                               LWSSSPOLF_ATTR_HIGH_RELIABILITY;
+               return 0;
+
+       case LSSPPT_ATTR_LOW_COST:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_ATTR_LOW_COST;
+               return 0;
+
+       case LSSPPT_PERF:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_PERF;
+               return 0;
+
+       case LSSPPT_RETRYPTR:
+               bot = a->heads[LTY_BACKOFF].b;
+               while (bot) {
+                       if (!strncmp(ctx->buf, bot->name, ctx->npos)) {
+                               a->curr[LTY_POLICY].p->retry_bo = &bot->r;
+
+                               return 0;
+                       }
+                       bot = bot->next;
+               }
+               lwsl_err("%s: unknown backoff scheme\n", __func__);
+
+               return -1;
+
+       case LSSPPT_TRUST:
+               ts = a->heads[LTY_TRUSTSTORE].t;
+               while (ts) {
+                       if (!strncmp(ctx->buf, ts->name, ctx->npos)) {
+                               a->curr[LTY_POLICY].p->trust.store = ts;
+                               return 0;
+                       }
+                       ts = ts->next;
+               }
+               lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
+               lwsl_err("%s: unknown trust store name %s\n", __func__,
+                        dotstar);
+
+               return -1;
+
+       case LSSPPT_METADATA:
+               break;
+
+       case LSSPPT_USE_AUTH:
+               a->curr[LTY_POLICY].p->auth =
+                       lws_ss_policy_find_auth_by_name(a, ctx->buf, ctx->npos);
+               if (!a->curr[LTY_POLICY].p->auth) {
+                       lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
+                       lwsl_err("%s: unknown auth '%s'\n", __func__, dotstar);
+                       return -1;
+               }
+               break;
+
+
+       case LSSPPT_METADATA_ITEM:
+               pmd = a->curr[LTY_POLICY].p->metadata;
+               a->curr[LTY_POLICY].p->metadata = lwsac_use_zero(&a->ac,
+                       sizeof(lws_ss_metadata_t) + ctx->npos +
+                       (unsigned int)(ctx->path_match_len - ctx->st[ctx->sp - 2].p + 1) + 2,
+                       POL_AC_GRAIN);
+               a->curr[LTY_POLICY].p->metadata->next = pmd;
+
+               q = (char *)a->curr[LTY_POLICY].p->metadata +
+                               sizeof(lws_ss_metadata_t);
+               a->curr[LTY_POLICY].p->metadata->name = q;
+               memcpy(q, ctx->path + ctx->st[ctx->sp - 2].p + 1,
+                      (unsigned int)(ctx->path_match_len - ctx->st[ctx->sp - 2].p));
+
+               q += ctx->path_match_len - ctx->st[ctx->sp - 2].p;
+               a->curr[LTY_POLICY].p->metadata->value__may_own_heap = q;
+               memcpy(q, ctx->buf, ctx->npos);
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+               /*
+                * Check the metadata value part to see if it's a well-known
+                * http header... if so, LWS_HTTP_NO_KNOWN_HEADER (0xff) means
+                * no header string match else it's the well-known header index
+                */
+               a->curr[LTY_POLICY].p->metadata->value_is_http_token = (uint8_t)
+                       lws_http_string_to_known_header(ctx->buf, ctx->npos);
+#endif
+
+               a->curr[LTY_POLICY].p->metadata->length = /* the index in handle->metadata */
+                               a->curr[LTY_POLICY].p->metadata_count++;
+
+               a->curr[LTY_POLICY].p->metadata->value_length = ctx->npos;
+               break;
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+
+       case LSSPPT_HTTPRESPMAP_ITEM:
+               if (a->count >= (int)LWS_ARRAY_SIZE(a->respmap)) {
+                       lwsl_err("%s: respmap too big\n", __func__);
+                       return -1;
+               }
+               a->respmap[a->count].resp = (uint16_t)
+                               atoi(ctx->path + ctx->st[ctx->sp - 2].p + 1);
+               a->respmap[a->count].state = (uint16_t)atoi(ctx->buf);
+               a->pending_respmap = 1;
+               a->count++;
+               break;
+
+       case LSSPPT_HTTP_AUTH_HEADER:
+       case LSSPPT_HTTP_DSN_HEADER:
+       case LSSPPT_HTTP_FWV_HEADER:
+       case LSSPPT_HTTP_TYPE_HEADER:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.http.blob_header[
+                              (ctx->path_match - 1) - LSSPPT_HTTP_AUTH_HEADER];
+               goto string2;
+
+       case LSSPPT_HTTP_AUTH_PREAMBLE:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.http.auth_preamble;
+               goto string2;
+
+       case LSSPPT_HTTP_NO_CONTENT_LENGTH:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                       LWSSSPOLF_HTTP_NO_CONTENT_LENGTH;
+               break;
+
+       case LSSPPT_NGHTTP2_QUIRK_END_STREAM:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                       LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM;
+               break;
+       case LSSPPT_H2_QUIRK_OVERFLOWS_TXCR:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                       LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR;
+               break;
+       case LSSPPT_HTTP_MULTIPART_NAME:
+               a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_HTTP_MULTIPART;
+               pp = (char **)&a->curr[LTY_POLICY].p->u.http.multipart_name;
+               goto string2;
+       case LSSPPT_HTTP_MULTIPART_FILENAME:
+               a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_HTTP_MULTIPART;
+               pp = (char **)&a->curr[LTY_POLICY].p->u.http.multipart_filename;
+               goto string2;
+       case LSSPPT_HTTP_MULTIPART_CONTENT_TYPE:
+               a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_HTTP_MULTIPART;
+               pp = (char **)&a->curr[LTY_POLICY].p->u.http.multipart_content_type;
+               goto string2;
+
+       case LSSPPT_AUTH_NAME:
+               pp = (char **)&a->curr[LTY_AUTH].a->name;
+               goto string2;
+
+       case LSSPPT_AUTH_STREAMTYPE:
+               pp = (char **)&a->curr[LTY_AUTH].a->streamtype;
+               goto string2;
+       case LSSPPT_AUTH_TYPE:
+               pp = (char **)&a->curr[LTY_AUTH].a->type;
+               goto string2;
+       case LSSPPT_HTTP_FAIL_REDIRECT:
+               a->curr[LTY_POLICY].p->u.http.fail_redirect =
+                                               reason == LEJPCB_VAL_TRUE;
+               break;
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+       case LSSPPT_AWS_REGION:
+               pp = (char **)&a->curr[LTY_POLICY].p->aws_region;
+               goto string2;
+
+       case LSSPPT_AWS_SERVICE:
+               pp = (char **)&a->curr[LTY_POLICY].p->aws_service;
+               goto string2;
+#endif
+
+#endif
+
+#if defined(LWS_ROLE_WS)
+
+       case LSSPPT_WS_SUBPROTOCOL:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.http.u.ws.subprotocol;
+               goto string2;
+
+       case LSSPPT_WS_BINARY:
+               a->curr[LTY_POLICY].p->u.http.u.ws.binary =
+                                               reason == LEJPCB_VAL_TRUE;
+               break;
+#endif
+
+       case LSSPPT_LOCAL_SINK:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_LOCAL_SINK;
+               break;
+
+       case LSSPPT_SERVER:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |= LWSSSPOLF_SERVER;
+               break;
+
+#if defined(LWS_ROLE_MQTT)
+       case LSSPPT_MQTT_TOPIC:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.topic;
+               goto string2;
+
+       case LSSPPT_MQTT_SUBSCRIBE:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.subscribe;
+               goto string2;
+
+       case LSSPPT_MQTT_QOS:
+               a->curr[LTY_POLICY].p->u.mqtt.qos = (uint8_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_MQTT_KEEPALIVE:
+               a->curr[LTY_POLICY].p->u.mqtt.keep_alive = (uint16_t)atoi(ctx->buf);
+               break;
+
+       case LSSPPT_MQTT_CLEAN_START:
+               a->curr[LTY_POLICY].p->u.mqtt.clean_start =
+                                               reason == LEJPCB_VAL_TRUE;
+               break;
+       case LSSPPT_MQTT_WILL_TOPIC:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.will_topic;
+               goto string2;
+
+       case LSSPPT_MQTT_WILL_MESSAGE:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.will_message;
+               goto string2;
+
+       case LSSPPT_MQTT_WILL_QOS:
+               a->curr[LTY_POLICY].p->u.mqtt.will_qos = (uint8_t)atoi(ctx->buf);
+               break;
+       case LSSPPT_MQTT_WILL_RETAIN:
+               a->curr[LTY_POLICY].p->u.mqtt.will_retain =
+                                               reason == LEJPCB_VAL_TRUE;
+               break;
+       case LSSPPT_MQTT_BIRTH_TOPIC:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.birth_topic;
+               goto string2;
+
+       case LSSPPT_MQTT_BIRTH_MESSAGE:
+               pp = (char **)&a->curr[LTY_POLICY].p->u.mqtt.birth_message;
+               goto string2;
+
+       case LSSPPT_MQTT_BIRTH_QOS:
+               a->curr[LTY_POLICY].p->u.mqtt.birth_qos = (uint8_t)atoi(ctx->buf);
+               break;
+       case LSSPPT_MQTT_BIRTH_RETAIN:
+               a->curr[LTY_POLICY].p->u.mqtt.birth_retain =
+                                               reason == LEJPCB_VAL_TRUE;
+               break;
+       case LSSPPT_MQTT_AWS_IOT:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->u.mqtt.aws_iot =
+                                               reason == LEJPCB_VAL_TRUE;
+               break;
+#endif
+       case LSSPPT_DIRECT_PROTO_STR:
+               if (reason == LEJPCB_VAL_TRUE)
+                       a->curr[LTY_POLICY].p->flags |=
+                                       LWSSSPOLF_DIRECT_PROTO_STR;
+               break;
+
+
+       case LSSPPT_PROTOCOL:
+               a->curr[LTY_POLICY].p->protocol = 0xff;
+               for (n = 0; n < (int)LWS_ARRAY_SIZE(protonames); n++)
+                       if (strlen(protonames[n]) == ctx->npos &&
+                           !strncmp(ctx->buf, protonames[n], ctx->npos))
+                               a->curr[LTY_POLICY].p->protocol = (uint8_t)n;
+
+               if (a->curr[LTY_POLICY].p->protocol != 0xff)
+                       break;
+               lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
+               lwsl_err("%s: unknown protocol name %s\n", __func__, dotstar);
+               return -1;
+
+       default:
+               break;
+       }
+
+       return 0;
+
+string2:
+       /*
+        * If we can do const string folding, reuse the existing string rather
+        * than make a new entry
+        */
+       extant = lwsac_scan_extant(a->ac, (uint8_t *)ctx->buf, (size_t)ctx->npos, 1);
+       if (extant) {
+               *pp = (char *)extant;
+
+               return 0;
+       }
+       *pp = lwsac_use_backfill(&a->ac, (size_t)(ctx->npos + 1), POL_AC_GRAIN);
+       if (!*pp)
+               goto oom;
+       memcpy(*pp, ctx->buf, ctx->npos);
+       (*pp)[ctx->npos] = '\0';
+
+       return 0;
+
+string1:
+       n = ctx->st[ctx->sp].p;
+       *pp = lwsac_use_backfill(&a->ac, (size_t)ctx->path_match_len + (size_t)1 - (size_t)n,
+                                POL_AC_GRAIN);
+       if (!*pp)
+               goto oom;
+       memcpy(*pp, ctx->path + n, ctx->path_match_len - (unsigned int)n);
+       (*pp)[ctx->path_match_len - n] = '\0';
+
+       return 0;
+
+oom:
+       lwsl_err("%s: OOM\n", __func__);
+       lws_free_set_NULL(a->p);
+       lwsac_free(&a->ac);
+
+       return -1;
+}
+
+int
+lws_ss_policy_parse_begin(struct lws_context *context, int overlay)
+{
+       struct policy_cb_args *args;
+       char *p;
+
+       args = lws_zalloc(sizeof(struct policy_cb_args), __func__);
+       if (!args) {
+               lwsl_err("%s: OOM\n", __func__);
+
+               return 1;
+       }
+       if (overlay)
+               /* continue to use the existing lwsac */
+               args->ac = context->ac_policy;
+       else
+               /* we don't want to see any old policy */
+               context->pss_policies = NULL;
+
+       context->pol_args = args;
+       args->context = context;
+       p = lwsac_use(&args->ac, 1, POL_AC_INITIAL);
+       if (!p) {
+               lwsl_err("%s: OOM\n", __func__);
+               lws_free_set_NULL(context->pol_args);
+
+               return -1;
+       }
+       *p = 0;
+       lejp_construct(&args->jctx, lws_ss_policy_parser_cb, args,
+                      lejp_tokens_policy, LWS_ARRAY_SIZE(lejp_tokens_policy));
+
+       return 0;
+}
+
+int
+lws_ss_policy_parse_abandon(struct lws_context *context)
+{
+       struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
+       lws_ss_x509_t *x;
+
+       x = args->heads[LTY_X509].x;
+       while (x) {
+               /*
+                * Free all the client DER buffers now they have been parsed
+                * into tls library X.509 objects
+                */
+               lws_free((void *)x->ca_der);
+               x->ca_der = NULL;
+
+               x = x->next;
+       }
+
+       x = context->server_der_list;
+       while (x) {
+               lws_free((void *)x->ca_der);
+               x->ca_der = NULL;
+
+               x = x->next;
+       }
+
+       lejp_destruct(&args->jctx);
+       lwsac_free(&args->ac);
+       lws_free_set_NULL(context->pol_args);
+
+       context->server_der_list = NULL;
+
+       return 0;
+}
+
+#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
+int
+lws_ss_policy_parse_file(struct lws_context *cx, const char *filepath)
+{
+       struct policy_cb_args *args = (struct policy_cb_args *)cx->pol_args;
+       uint8_t buf[512];
+       int n, m, fd = lws_open(filepath, LWS_O_RDONLY);
+
+       if (fd < 0)
+               return LEJP_REJECT_UNKNOWN;
+
+       do {
+               n = (int)read(fd, buf, sizeof(buf));
+               if (n < 0) {
+                       m = -1;
+                       goto bail;
+               }
+
+               m = lejp_parse(&args->jctx, buf, n);
+               if (m != LEJP_CONTINUE && m < 0) {
+                       lwsl_err("%s: parse failed line %u: %d: %s\n", __func__,
+                                (unsigned int)args->jctx.line, m,
+                                lejp_error_to_string(m));
+                       lws_ss_policy_parse_abandon(cx);
+
+                       m = -1;
+                       goto bail;
+               }
+
+               if (m != LEJP_CONTINUE)
+                       break;
+       } while (n);
+
+       m = 0;
+bail:
+       close(fd);
+
+       return m;
+}
+#endif
+
+int
+lws_ss_policy_parse(struct lws_context *context, const uint8_t *buf, size_t len)
+{
+       struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
+       int m;
+
+#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
+       if (args->jctx.line < 2 && buf[0] != '{' && !args->parse_data)
+               return lws_ss_policy_parse_file(context, (const char *)buf);
+#endif
+
+       args->parse_data = 1;
+       m = lejp_parse(&args->jctx, buf, (int)len);
+       if (m == LEJP_CONTINUE || m >= 0)
+               return m;
+
+       lwsl_err("%s: parse failed line %u: %d: %s\n", __func__,
+                (unsigned int)args->jctx.line, m, lejp_error_to_string(m));
+       lws_ss_policy_parse_abandon(context);
+       assert(0);
+
+       return m;
+}
+
+int
+lws_ss_policy_overlay(struct lws_context *context, const char *overlay)
+{
+       lws_ss_policy_parse_begin(context, 1);
+       return lws_ss_policy_parse(context, (const uint8_t *)overlay,
+                                  strlen(overlay));
+}
+
+const lws_ss_policy_t *
+lws_ss_policy_get(struct lws_context *context)
+{
+       struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
+
+       if (!args)
+               return NULL;
+
+       return args->heads[LTY_POLICY].p;
+}
+
+const lws_ss_auth_t *
+lws_ss_auth_get(struct lws_context *context)
+{
+       struct policy_cb_args *args = (struct policy_cb_args *)context->pol_args;
+
+       if (!args)
+               return NULL;
+
+       return args->heads[LTY_AUTH].a;
+}
diff --git a/lib/secure-streams/private-lib-secure-streams.h b/lib/secure-streams/private-lib-secure-streams.h
new file mode 100644 (file)
index 0000000..6af59e4
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* current SS Serialization protocol version */
+#define LWS_SSS_CLIENT_PROTOCOL_VERSION 1
+
+/*
+ * Secure Stream state
+ */
+
+typedef enum {
+       SSSEQ_IDLE,
+       SSSEQ_TRY_CONNECT,
+       SSSEQ_TRY_CONNECT_NAUTH,
+       SSSEQ_TRY_CONNECT_SAUTH,
+       SSSEQ_RECONNECT_WAIT,
+       SSSEQ_DO_RETRY,
+       SSSEQ_CONNECTED,
+} lws_ss_seq_state_t;
+
+struct conn;
+
+/**
+ * lws_ss_handle_t: publicly-opaque secure stream object implementation
+ */
+
+typedef struct lws_ss_handle {
+       lws_ss_info_t           info;     /**< copy of stream creation info */
+
+       lws_lifecycle_t         lc;
+
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_metrics_caliper_compose(cal_txn)
+#endif
+
+       struct lws_dll2         list;     /**< pt lists active ss */
+       struct lws_dll2         to_list;  /**< pt lists ss with pending to-s */
+#if defined(LWS_WITH_SERVER)
+       struct lws_dll2         cli_list;  /**< same server clients list */
+#endif
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_ctx_t            fic;    /**< Fault Injection context */
+#endif
+
+       struct lws_dll2_owner   src_list; /**< sink's list of bound sources */
+
+       struct lws_context      *context; /**< lws context we are created on */
+       const lws_ss_policy_t   *policy;  /**< system policy for stream */
+
+       struct lws_sequencer    *seq;     /**< owning sequencer if any */
+       struct lws              *wsi;     /**< the stream wsi if any */
+
+       struct conn             *conn_if_sspc_onw;
+
+#if defined(LWS_WITH_SSPLUGINS)
+       void                    *nauthi;  /**< the nauth plugin instance data */
+       void                    *sauthi;  /**< the sauth plugin instance data */
+#endif
+
+       lws_ss_metadata_t       *metadata;
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       lws_ss_metadata_t       *instant_metadata; /**< for set instant metadata */
+       struct lwsac            *imd_ac;           /**< for get custom header */
+#endif
+       const lws_ss_policy_t   *rideshare;
+       struct lws_ss_handle    *h_in_svc;
+
+#if defined(LWS_WITH_CONMON)
+       char                    *conmon_json;
+#endif
+
+       //struct lws_ss_handle  *h_sink;  /**< sink we are bound to, or NULL */
+       //void                  *sink_obj;/**< sink's private object representing us */
+
+       lws_sorted_usec_list_t  sul_timeout;
+       lws_sorted_usec_list_t  sul;
+       lws_ss_tx_ordinal_t     txord;
+
+       /* protocol-specific connection helpers */
+
+       union {
+
+               /* ...for http-related protocols... */
+
+               struct {
+
+                       /* common to all http-related protocols */
+
+                       /* incoming multipart parsing */
+
+                       char boundary[24];      /* --boundary from headers */
+                       uint8_t boundary_len;   /* length of --boundary */
+                       uint8_t boundary_seq;   /* current match amount */
+                       uint8_t boundary_dashes; /* check for -- after */
+                       uint8_t boundary_post; /* swallow post CRLF */
+
+                       uint8_t som:1;  /* SOM has been sent */
+                       uint8_t eom:1;  /* EOM has been sent */
+                       uint8_t any:1;  /* any content has been sent */
+
+
+                       uint8_t good_respcode:1; /* 200 type response code */
+
+                       union {
+                               struct { /* LWSSSP_H1 */
+#if defined(WIN32)
+                                       uint8_t dummy;
+#endif
+                               } h1;
+                               struct { /* LWSSSP_H2 */
+#if defined(WIN32)
+                                       uint8_t dummy;
+#endif
+                               } h2;
+                               struct { /* LWSSSP_WS */
+#if defined(WIN32)
+                                       uint8_t dummy;
+#endif
+                               } ws;
+                       } u;
+               } http;
+
+               /* details for non-http related protocols... */
+#if defined(LWS_ROLE_MQTT)
+               struct {
+                       lws_mqtt_topic_elem_t           topic_qos;
+                       lws_mqtt_topic_elem_t           sub_top;
+                       lws_mqtt_subscribe_param_t      sub_info;
+                       /* allocation that must be destroyed with conn */
+                       void                            *heap_baggage;
+                       const char                      *subscribe_to;
+                       size_t                          subscribe_to_len;
+               } mqtt;
+#endif
+#if defined(LWS_WITH_SYS_SMD)
+               struct {
+                       struct lws_smd_peer             *smd_peer;
+                       lws_sorted_usec_list_t          sul_write;
+               } smd;
+#endif
+       } u;
+
+       unsigned long           writeable_len;
+
+       lws_ss_constate_t       connstate;/**< public connection state */
+       lws_ss_seq_state_t      seqstate; /**< private connection state */
+       lws_ss_state_return_t   pending_ret; /**< holds desired disposition
+                                               * for ss during CCE */
+
+#if defined(LWS_WITH_SERVER)
+       int                     txn_resp;
+#endif
+
+       uint16_t                retry;    /**< retry / backoff tracking */
+#if defined(LWS_WITH_CONMON)
+       uint16_t                conmon_len;
+#endif
+       int16_t                 temp16;
+
+       uint8_t                 tsi;      /**< service thread idx, usually 0 */
+       uint8_t                 subseq;   /**< emulate SOM tracking */
+       uint8_t                 txn_ok;   /**< 1 = transaction was OK */
+       uint8_t                 prev_ss_state;
+
+       uint8_t                 txn_resp_set:1; /**< user code set one */
+       uint8_t                 txn_resp_pending:1; /**< we have yet to send */
+       uint8_t                 hanging_som:1;
+       uint8_t                 inside_msg:1;
+       uint8_t                 being_serialized:1; /* we are not the consumer */
+       uint8_t                 destroying:1;
+       uint8_t                 ss_dangling_connected:1;
+       uint8_t                 proxy_onward:1; /* opaque is conn */
+       uint8_t                 inside_connect:1; /* set if we are currently
+                                                  * creating the onward
+                                                  * connect */
+} lws_ss_handle_t;
+
+/* connection helper that doesn't need to hang around after connection starts */
+
+union lws_ss_contemp {
+#if defined(LWS_ROLE_MQTT)
+       lws_mqtt_client_connect_param_t ccp;
+#else
+#if defined(WIN32)
+       uint8_t dummy;
+#endif
+#endif
+};
+
+/*
+ * When allocating the opaque handle, we overallocate for:
+ *
+ *  1) policy->nauth_plugin->alloc (.nauthi) if any
+ *  2) policy->sauth_plugin->alloc (.sauthi) if any
+ *  3) copy of creation info stream type pointed to by info.streamtype... this
+ *     may be arbitrarily long and since it may be coming from socket ipc and be
+ *     temporary at creation time, we need a place for the copy to stay in scope
+ *  4) copy of info->streamtype contents
+ */
+
+
+/* the user object allocation is immediately after the ss object allocation */
+#define ss_to_userobj(ss) ((void *)&(ss)[1])
+
+/*
+ * serialization parser state
+ */
+
+enum {
+       KIND_C_TO_P,
+       KIND_SS_TO_P,
+};
+
+struct lws_ss_serialization_parser {
+       char                    streamtype[32];
+       char                    rideshare[32];
+       char                    metadata_name[32];
+
+       uint64_t                ust_pwait;
+
+       lws_ss_metadata_t       *ssmd;
+       uint8_t                 *rxmetaval;
+
+       int                     ps;
+       int                     ctr;
+
+       uint32_t                usd_phandling;
+       uint32_t                flags;
+       uint32_t                client_pid;
+       int32_t                 temp32;
+
+       int32_t                 txcr_out;
+       int32_t                 txcr_in;
+       uint16_t                rem;
+
+       uint8_t                 type;
+       uint8_t                 frag1;
+       uint8_t                 slen;
+       uint8_t                 rsl_pos;
+       uint8_t                 rsl_idx;
+       uint8_t                 protocol_version;
+};
+
+/*
+ * Unlike locally-fulfilled SS, SSS doesn't have to hold metadata on client side
+ * but pass it through to the proxy.  The client side doesn't know the real
+ * metadata names that are available in the policy (since it's hardcoded in code
+ * no point passing them back to the client from the policy).  Because of that,
+ * it doesn't know how many to allocate when we create the sspc_handle either.
+ *
+ * So we use a linked-list of changed-but-not-yet-proxied metadata allocated
+ * on the heap and items removed as they are proxied out.  Anything on the list
+ * is sent to the proxy before any requested tx is handled.
+ *
+ * This is also used to queue tx credit changes
+ */
+
+typedef struct lws_sspc_metadata {
+       lws_dll2_t      list;
+       char            name[32];  /* empty string, then actually TCXR */
+       size_t          len;
+       int             tx_cr_adjust;
+
+       /* the value of length .len is overallocated after this */
+} lws_sspc_metadata_t;
+
+/* state of the upstream proxy onward connection */
+
+enum {
+       LWSSSPC_ONW_NONE,
+       LWSSSPC_ONW_REQ,
+       LWSSSPC_ONW_ONGOING,
+       LWSSSPC_ONW_CONN,
+};
+
+typedef struct lws_sspc_handle {
+       char                    rideshare_list[128];
+
+       lws_lifecycle_t         lc;
+
+       lws_ss_info_t           ssi;
+       lws_sorted_usec_list_t  sul_retry;
+
+       struct lws_ss_serialization_parser parser;
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_ctx_t            fic;    /**< Fault Injection context */
+#endif
+
+       lws_dll2_owner_t        metadata_owner;
+       lws_dll2_owner_t        metadata_owner_rx;
+
+       struct lws_dll2         client_list;
+       struct lws_tx_credit    txc;
+
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_metrics_caliper_compose(cal_txn)
+#endif
+
+       struct lws              *cwsi;
+
+       struct lws_dsh          *dsh;
+       struct lws_context      *context;
+
+       struct lws_sspc_handle  *h_in_svc;
+       /*
+        * Used to detect illegal lws_sspc_destroy() calls while still
+        * being serviced
+        */
+
+       lws_usec_t              us_earliest_write_req;
+       lws_usec_t              us_start_upstream;
+
+       unsigned long           writeable_len;
+
+       lws_ss_conn_states_t    state;
+
+       uint32_t                timeout_ms;
+       uint32_t                ord;
+
+       int16_t                 temp16;
+
+       uint8_t                 rideshare_ofs[4];
+       uint8_t                 rsidx;
+
+       uint8_t                 prev_ss_state;
+
+       uint8_t                 conn_req_state:2;
+       uint8_t                 destroying:1;
+       uint8_t                 non_wsi:1;
+       uint8_t                 ignore_txc:1;
+       uint8_t                 pending_timeout_update:1;
+       uint8_t                 pending_writeable_len:1;
+       uint8_t                 creating_cb_done:1;
+       uint8_t                 ss_dangling_connected:1;
+} lws_sspc_handle_t;
+
+typedef struct backoffs {
+       struct backoffs *next;
+       const char *name;
+       lws_retry_bo_t r;
+} backoff_t;
+
+union u {
+       backoff_t               *b;
+       lws_ss_x509_t           *x;
+       lws_ss_trust_store_t    *t;
+       lws_ss_policy_t         *p;
+       lws_ss_auth_t           *a;
+       lws_metric_policy_t     *m;
+};
+
+enum {
+       LTY_BACKOFF,
+       LTY_X509,
+       LTY_TRUSTSTORE,
+       LTY_POLICY,
+       LTY_AUTH,
+       LTY_METRICS,
+
+       _LTY_COUNT /* always last */
+};
+
+
+struct policy_cb_args {
+       struct lejp_ctx jctx;
+       struct lws_context *context;
+       struct lwsac *ac;
+
+       const char *socks5_proxy;
+
+       struct lws_b64state b64;
+
+       lws_ss_http_respmap_t respmap[16];
+
+       union u heads[_LTY_COUNT];
+       union u curr[_LTY_COUNT];
+
+       uint8_t *p;
+
+       int count;
+       char pending_respmap;
+
+       uint8_t parse_data:1;
+};
+
+#if defined(LWS_WITH_SYS_SMD)
+extern const lws_ss_policy_t pol_smd;
+#endif
+
+
+/*
+ * returns one of
+ *
+ *     LWSSSSRET_OK
+ *     LWSSSSRET_DISCONNECT_ME
+ *     LWSSSSRET_DESTROY_ME
+ */
+int
+lws_ss_deserialize_parse(struct lws_ss_serialization_parser *par,
+                        struct lws_context *context,
+                        struct lws_dsh *dsh, const uint8_t *cp, size_t len,
+                        lws_ss_conn_states_t *state, void *parconn,
+                        lws_ss_handle_t **pss, lws_ss_info_t *ssi, char client);
+int
+lws_ss_serialize_rx_payload(struct lws_dsh *dsh, const uint8_t *buf,
+                           size_t len, int flags, const char *rsp);
+int
+lws_ss_deserialize_tx_payload(struct lws_dsh *dsh, struct lws *wsi,
+                             lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                             size_t *len, int *flags);
+int
+lws_ss_serialize_state(struct lws *wsi, struct lws_dsh *dsh, lws_ss_constate_t state,
+                      lws_ss_tx_ordinal_t ack);
+
+const lws_ss_policy_t *
+lws_ss_policy_lookup(const struct lws_context *context, const char *streamtype);
+
+/* can be used as a cb from lws_dll2_foreach_safe() to destroy ss */
+int
+lws_ss_destroy_dll(struct lws_dll2 *d, void *user);
+
+int
+lws_sspc_destroy_dll(struct lws_dll2 *d, void *user);
+
+void
+lws_sspc_rxmetadata_destroy(lws_sspc_handle_t *h);
+
+int
+lws_ss_policy_set(struct lws_context *context, const char *name);
+
+int
+lws_ss_sys_fetch_policy(struct lws_context *context);
+
+lws_ss_state_return_t
+lws_ss_event_helper(lws_ss_handle_t *h, lws_ss_constate_t cs);
+
+lws_ss_state_return_t
+_lws_ss_backoff(lws_ss_handle_t *h, lws_usec_t us_override);
+
+lws_ss_state_return_t
+lws_ss_backoff(lws_ss_handle_t *h);
+
+int
+_lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(lws_ss_state_return_t r, struct lws *wsi,
+                        lws_ss_handle_t **ph);
+
+int
+lws_ss_set_timeout_us(lws_ss_handle_t *h, lws_usec_t us);
+
+void
+ss_proxy_onward_txcr(void *userobj, int bump);
+
+int
+lws_ss_serialize_txcr(struct lws_dsh *dsh, int txcr);
+
+int
+lws_ss_sys_auth_api_amazon_com(struct lws_context *context);
+
+lws_ss_metadata_t *
+lws_ss_get_handle_metadata(struct lws_ss_handle *h, const char *name);
+lws_ss_metadata_t *
+lws_ss_policy_metadata_index(const lws_ss_policy_t *p, size_t index);
+
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+lws_ss_metadata_t *
+lws_ss_get_handle_instant_metadata(struct lws_ss_handle *h, const char *name);
+#endif
+
+lws_ss_metadata_t *
+lws_ss_policy_metadata(const lws_ss_policy_t *p, const char *name);
+
+int
+lws_ss_exp_cb_metadata(void *priv, const char *name, char *out, size_t *pos,
+                       size_t olen, size_t *exp_ofs);
+
+int
+_lws_ss_set_metadata(lws_ss_metadata_t *omd, const char *name,
+                    const void *value, size_t len);
+
+int
+_lws_ss_alloc_set_metadata(lws_ss_metadata_t *omd, const char *name,
+                          const void *value, size_t len);
+
+lws_ss_state_return_t
+_lws_ss_client_connect(lws_ss_handle_t *h, int is_retry, void *conn_if_sspc_onw);
+
+lws_ss_state_return_t
+_lws_ss_request_tx(lws_ss_handle_t *h);
+
+int
+__lws_ss_proxy_bind_ss_to_conn_wsi(void *parconn, size_t dsh_size);
+
+struct lws_vhost *
+lws_ss_policy_ref_trust_store(struct lws_context *context,
+                             const lws_ss_policy_t *pol, char doref);
+
+lws_ss_state_return_t
+lws_sspc_event_helper(lws_sspc_handle_t *h, lws_ss_constate_t cs,
+                     lws_ss_tx_ordinal_t flags);
+
+int
+lws_ss_check_next_state(lws_lifecycle_t *lc, uint8_t *prevstate,
+                       lws_ss_constate_t cs);
+
+int
+lws_ss_check_next_state_ss(lws_ss_handle_t *ss, uint8_t *prevstate,
+                          lws_ss_constate_t cs);
+
+int
+lws_ss_check_next_state_sspc(lws_sspc_handle_t *ss, uint8_t *prevstate,
+                            lws_ss_constate_t cs);
+
+void
+lws_proxy_clean_conn_ss(struct lws *wsi);
+
+int
+lws_ss_cancel_notify_dll(struct lws_dll2 *d, void *user);
+
+int
+lws_sspc_cancel_notify_dll(struct lws_dll2 *d, void *user);
+
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) || defined(LWS_WITH_SECURE_STREAMS_CPP)
+int
+lws_ss_policy_unref_trust_store(struct lws_context *context,
+                               const lws_ss_policy_t *pol);
+#endif
+
+int
+lws_ss_sys_cpd(struct lws_context *cx);
+
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+int lws_ss_apply_sigv4(struct lws *wsi, struct lws_ss_handle *h,
+                      unsigned char **p, unsigned char *end);
+#endif
+
+#if defined(_DEBUG)
+void
+lws_ss_assert_extant(struct lws_context *cx, int tsi, struct lws_ss_handle *h);
+#else
+#define lws_ss_assert_extant(_a, _b, _c)
+#endif
+
+typedef int (* const secstream_protocol_connect_munge_t)(lws_ss_handle_t *h,
+               char *buf, size_t len, struct lws_client_connect_info *i,
+               union lws_ss_contemp *ct);
+
+typedef int (* const secstream_protocol_add_txcr_t)(lws_ss_handle_t *h, int add);
+
+typedef int (* const secstream_protocol_get_txcr_t)(lws_ss_handle_t *h);
+
+struct ss_pcols {
+       const char                                      *name;
+       const char                                      *alpn;
+       const struct lws_protocols                      *protocol;
+       secstream_protocol_connect_munge_t              munge;
+       secstream_protocol_add_txcr_t                   tx_cr_add;
+       secstream_protocol_get_txcr_t                   tx_cr_est;
+};
+
+/*
+ * Because both sides of the connection share the conn, we allocate it
+ * during accepted adoption, and both sides point to it.
+ *
+ * When .ss or .wsi close, they must NULL their entry here so no dangling
+ * refereneces.
+ *
+ * The last one of the accepted side and the onward side to close frees it.
+ */
+
+lws_ss_state_return_t
+lws_conmon_ss_json(lws_ss_handle_t *h);
+
+void
+ss_proxy_onward_link_req_writeable(lws_ss_handle_t *h_onward);
+
+struct conn {
+       struct lws_ss_serialization_parser parser;
+
+       lws_dsh_t               *dsh;   /* unified buffer for both sides */
+       struct lws              *wsi;   /* the proxy's client side */
+       lws_ss_handle_t         *ss;    /* the onward, ss side */
+
+       lws_ss_conn_states_t    state;
+
+       char                    onward_in_flow_control;
+};
+
+extern const struct ss_pcols ss_pcol_h1;
+extern const struct ss_pcols ss_pcol_h2;
+extern const struct ss_pcols ss_pcol_ws;
+extern const struct ss_pcols ss_pcol_mqtt;
+extern const struct ss_pcols ss_pcol_raw;
+
+extern const struct lws_protocols protocol_secstream_h1;
+extern const struct lws_protocols protocol_secstream_h2;
+extern const struct lws_protocols protocol_secstream_ws;
+extern const struct lws_protocols protocol_secstream_mqtt;
+extern const struct lws_protocols protocol_secstream_raw;
+
diff --git a/lib/secure-streams/protocols/README.md b/lib/secure-streams/protocols/README.md
new file mode 100644 (file)
index 0000000..3c02e8b
--- /dev/null
@@ -0,0 +1,38 @@
+# Lws Protocol bindings for Secure Streams
+
+This directory contains the code wiring up normal lws protocols
+to Secure Streams.
+
+## The lws_protocols callback
+
+This is the normal lws struct lws_protocols callback that handles events and
+traffic on the lws protocol being supported.
+
+The various events and traffic are converted into calls using the Secure
+Streams api, and Secure Streams events.
+
+## The connect_munge helper
+
+Different protocols have different semantics in the arguments to the client
+connect function, this protocol-specific helper is called to munge the
+connect_info struct to match the details of the protocol selected.
+
+The `ss->policy->aux` string is used to hold protocol-specific information
+passed in the from the policy, eg, the URL path or websockets subprotocol
+name.
+
+## The (library-private) ss_pcols export
+
+Each protocol binding exports two things to other parts of lws (they
+are not exported to user code)
+
+ - a struct lws_protocols, including a pointer to the callback
+
+ - a struct ss_pcols describing how secure_streams should use, including
+   a pointer to the related connect_munge helper.
+
+In ./lib/core-net/vhost.c, enabled protocols are added to vhost protcols
+lists so they may be used.  And in ./lib/secure-streams/secure-streams.c,
+enabled struct ss_pcols are listed and checked for matches when the user
+creates a new Secure Stream.
+
diff --git a/lib/secure-streams/protocols/ss-h1.c b/lib/secure-streams/protocols/ss-h1.c
new file mode 100644 (file)
index 0000000..9bfed47
--- /dev/null
@@ -0,0 +1,1201 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is the glue that wires up h1 to Secure Streams.
+ */
+
+#include <private-lib-core.h>
+
+#if !defined(LWS_PLAT_FREERTOS) || defined(LWS_ROLE_H2)
+#define LWS_WITH_SS_RIDESHARE
+#endif
+
+#if defined(LWS_WITH_SS_RIDESHARE)
+static int
+ss_http_multipart_parser(lws_ss_handle_t *h, void *in, size_t len)
+{
+       uint8_t *q = (uint8_t *)in;
+       int pending_issue = 0, n = 0;
+
+
+       /* let's stick it in the boundary state machine first */
+       while (n < (int)len) {
+               if (h->u.http.boundary_seq != h->u.http.boundary_len) {
+                       if (q[n] == h->u.http.boundary[h->u.http.boundary_seq])
+                               h->u.http.boundary_seq++;
+                       else {
+                               h->u.http.boundary_seq = 0;
+                               h->u.http.boundary_dashes = 0;
+                               h->u.http.boundary_post = 0;
+                       }
+                       goto around;
+               }
+
+               /*
+                * We already matched the boundary string, now we're
+                * looking if there's a -- afterwards
+                */
+               if (h->u.http.boundary_dashes < 2) {
+                       if (q[n] == '-') {
+                               h->u.http.boundary_dashes++;
+                               goto around;
+                       }
+                       /* there was no final -- ... */
+               }
+
+               if (h->u.http.boundary_dashes == 2) {
+                       /*
+                        * It's an EOM boundary: issue pending + multipart EOP
+                        */
+                       lwsl_debug("%s: seen EOP, n %d pi %d\n",
+                                   __func__, n, pending_issue);
+                       /*
+                        * It's possible we already started the decode before
+                        * the end of the last packet.  Then there is no
+                        * remainder to send.
+                        */
+                       if (n >= pending_issue + h->u.http.boundary_len +
+                           (h->u.http.any ? 2 : 0) + 1) {
+                               h->info.rx(ss_to_userobj(h),
+                                          &q[pending_issue],
+                                          (unsigned int)(n - pending_issue -
+                                          h->u.http.boundary_len - 1 -
+                                          (h->u.http.any ? 2 : 0) /* crlf */),
+                                  (!h->u.http.som ? LWSSS_FLAG_SOM : 0) |
+                                  LWSSS_FLAG_EOM | LWSSS_FLAG_RELATED_END);
+                               h->u.http.eom = 1;
+                       }
+
+                       /*
+                        * Peer may not END_STREAM us
+                        */
+                       return 0;
+                       //return -1;
+               }
+
+               /* how about --boundaryCRLF */
+
+               if (h->u.http.boundary_post < 2) {
+                       if ((!h->u.http.boundary_post && q[n] == '\x0d') ||
+                           (h->u.http.boundary_post && q[n] == '\x0a')) {
+                               h->u.http.boundary_post++;
+                               goto around;
+                       }
+                       /* there was no final CRLF ... it's wrong */
+
+                       return -1;
+               }
+               if (h->u.http.boundary_post != 2)
+                       goto around;
+
+               /*
+                * We have a starting "--boundaryCRLF" or intermediate
+                * "CRLF--boundaryCRLF" boundary
+                */
+               lwsl_debug("%s: b_post = 2 (pi %d)\n", __func__, pending_issue);
+               h->u.http.boundary_seq = 0;
+               h->u.http.boundary_post = 0;
+
+               if (n >= pending_issue && (h->u.http.any || !h->u.http.som)) {
+                       /* Intermediate... do the EOM */
+                       lwsl_debug("%s: seen interm EOP n %d pi %d\n", __func__,
+                                  n, pending_issue);
+                       /*
+                        * It's possible we already started the decode before
+                        * the end of the last packet.  Then there is no
+                        * remainder to send.
+                        */
+                       if (n >= pending_issue + h->u.http.boundary_len +
+                           (h->u.http.any ? 2 : 0)) {
+                               h->info.rx(ss_to_userobj(h), &q[pending_issue],
+                                          (unsigned int)(n - pending_issue -
+                                              h->u.http.boundary_len -
+                                              (h->u.http.any ? 2 /* crlf */ : 0)),
+                                          (!h->u.http.som ? LWSSS_FLAG_SOM : 0) |
+                                          LWSSS_FLAG_EOM);
+                               h->u.http.eom = 1;
+                       }
+               }
+
+               /* Next message starts after this boundary */
+
+               pending_issue = n;
+               if (h->u.http.eom) {
+                       /* reset only if we have sent eom */
+                       h->u.http.som = 0;
+                       h->u.http.eom = 0;
+               }
+
+around:
+               n++;
+       }
+
+       if (pending_issue != n) {
+               uint8_t oh = 0;
+
+               /*
+                * handle the first or last "--boundaryCRLF" case which is not captured in the
+                * previous loop, on the Bob downchannel (/directive)
+                *
+                * probably does not cover the case that one boundary term is separated in multipile
+                * one callbacks though never see such case
+                */
+
+               if ((n >= h->u.http.boundary_len) &&
+                       h->u.http.boundary_seq == h->u.http.boundary_len &&
+                       h->u.http.boundary_post == 2) {
+
+                       oh = 1;
+               }
+
+               h->info.rx(ss_to_userobj(h), &q[pending_issue],
+                               (unsigned int)(oh ?
+                               (n - pending_issue - h->u.http.boundary_len -
+                                       (h->u.http.any ? 2 : 0)) :
+                               (n - pending_issue)),
+                          (!h->u.http.som ? LWSSS_FLAG_SOM : 0) |
+                            (oh && h->u.http.any ? LWSSS_FLAG_EOM : 0));
+
+               if (oh && h->u.http.any)
+                       h->u.http.eom = 1;
+
+               h->u.http.any = 1;
+               h->u.http.som = 1;
+       }
+
+       return 0;
+}
+#endif
+
+/*
+ * Returns 0, or the ss state resp maps on to
+ */
+
+static int
+lws_ss_http_resp_to_state(lws_ss_handle_t *h, int resp)
+{
+       const lws_ss_http_respmap_t *r = h->policy->u.http.respmap;
+       int n = h->policy->u.http.count_respmap;
+
+       while (n--)
+               if (resp == r->resp)
+                       return r->state;
+               else
+                       r++;
+
+       return 0; /* no hit */
+}
+
+/*
+ * This converts any set metadata items into outgoing http headers
+ */
+
+static int
+lws_apply_metadata(lws_ss_handle_t *h, struct lws *wsi, uint8_t *buf,
+                  uint8_t **pp, uint8_t *end)
+{
+       lws_ss_metadata_t *polmd = h->policy->metadata;
+       int m = 0;
+
+       while (polmd) {
+
+               /* has to have a non-empty header string */
+
+               if (polmd->value__may_own_heap &&
+                   ((uint8_t *)polmd->value__may_own_heap)[0] &&
+                   h->metadata[m].value__may_own_heap) {
+                       if (lws_add_http_header_by_name(wsi,
+                                       polmd->value__may_own_heap,
+                                       h->metadata[m].value__may_own_heap,
+                                       (int)h->metadata[m].length, pp, end))
+                       return -1;
+
+                       /*
+                        * Check for the case he's setting a non-zero
+                        * content-length "via the backdoor" metadata-
+                        * driven headers, and set the body_pending()
+                        * state if so...
+                        */
+
+                       if (!strncmp(polmd->value__may_own_heap,
+                                    "content-length", 14) &&
+                           atoi(h->metadata[m].value__may_own_heap))
+                               lws_client_http_body_pending(wsi, 1);
+               }
+
+               m++;
+               polmd = polmd->next;
+       }
+
+       /*
+        * Content-length on POST / PUT if we have the length information
+        */
+
+       if (h->policy->u.http.method && (
+               (!strcmp(h->policy->u.http.method, "POST") ||
+                !strcmp(h->policy->u.http.method, "PUT"))) &&
+           wsi->http.writeable_len) {
+               if (!(h->policy->flags &
+                       LWSSSPOLF_HTTP_NO_CONTENT_LENGTH)) {
+                       int n = lws_snprintf((char *)buf, 20, "%u",
+                               (unsigned int)wsi->http.writeable_len);
+                       if (lws_add_http_header_by_token(wsi,
+                                       WSI_TOKEN_HTTP_CONTENT_LENGTH,
+                                       buf, n, pp, end))
+                               return -1;
+               }
+               lws_client_http_body_pending(wsi, 1);
+       }
+
+       return 0;
+}
+
+
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+static int
+lws_apply_instant_metadata(lws_ss_handle_t *h, struct lws *wsi, uint8_t *buf,
+                  uint8_t **pp, uint8_t *end)
+{
+       lws_ss_metadata_t *imd = h->instant_metadata;
+
+       while (imd) {
+               if (imd->name && imd->value__may_own_heap) {
+                       lwsl_debug("%s add header %s %s %d\n", __func__,
+                                                  imd->name,
+                                                  (char *)imd->value__may_own_heap,
+                                                  imd->length);
+                       if (lws_add_http_header_by_name(wsi,
+                                       (const unsigned char *)imd->name,
+                                       (const unsigned char *)imd->value__may_own_heap,
+                                       (int)imd->length, pp, end))
+                       return -1;
+
+                       /* it's possible user set content-length directly */
+                       if (!strncmp(imd->name,
+                                    "content-length", 14) &&
+                           atoi(imd->value__may_own_heap))
+                               lws_client_http_body_pending(wsi, 1);
+
+               }
+
+               imd = imd->next;
+       }
+
+       return 0;
+}
+#endif
+/*
+ * Check if any metadata headers present in the server headers, and record
+ * them into the associated metadata item if so.
+ */
+
+static int
+lws_extract_metadata(lws_ss_handle_t *h, struct lws *wsi)
+{
+       lws_ss_metadata_t *polmd = h->policy->metadata, *omd;
+       int n, m = 0;
+
+       while (polmd) {
+
+               if (polmd->value_is_http_token != LWS_HTTP_NO_KNOWN_HEADER) {
+
+                       /* it's a well-known header token */
+
+                       n = lws_hdr_total_length(wsi, polmd->value_is_http_token);
+                       if (n) {
+                               const char *cp = lws_hdr_simple_ptr(wsi,
+                                               polmd->value_is_http_token);
+                               omd = lws_ss_get_handle_metadata(h, polmd->name);
+                               if (!omd || !cp)
+                                       return 1;
+
+                               assert(!strcmp(omd->name, polmd->name));
+
+                               /*
+                                * it's present on the wsi, we want to
+                                * set the related metadata name to it then
+                                */
+
+                               _lws_ss_alloc_set_metadata(omd, polmd->name, cp,
+                                                          (unsigned int)n);
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+                               /*
+                                * ...and because we are doing it from parsing
+                                * onward rx, we want to mark the metadata as
+                                * needing passing to the client
+                                */
+                               omd->pending_onward = 1;
+#endif
+                       }
+               }
+
+#if defined(LWS_WITH_CUSTOM_HEADERS)
+               else
+
+                       /* has to have a non-empty header string */
+
+                       if (polmd->value__may_own_heap &&
+                           ((uint8_t *)polmd->value__may_own_heap)[0]) {
+                               char *p;
+
+                               /*
+                                * Can it be a custom header?
+                                */
+
+                               n = lws_hdr_custom_length(wsi, (const char *)
+                                                   polmd->value__may_own_heap,
+                                                   polmd->value_length);
+                               if (n > 0) {
+
+                                       p = lws_malloc((unsigned int)n + 1, __func__);
+                                       if (!p)
+                                               return 1;
+
+                                       /* if needed, free any previous value */
+
+                                       if (polmd->value_on_lws_heap) {
+                                               lws_free(
+                                                   polmd->value__may_own_heap);
+                                               polmd->value_on_lws_heap = 0;
+                                       }
+
+                                       /*
+                                        * copy the named custom header value
+                                        * into the malloc'd buffer
+                                        */
+
+                                       if (lws_hdr_custom_copy(wsi, p, n + 1,
+                                                    (const char *)
+                                                    polmd->value__may_own_heap,
+                                                    polmd->value_length) < 0) {
+                                               lws_free(p);
+
+                                               return 1;
+                                       }
+
+                                       omd = lws_ss_get_handle_metadata(h,
+                                                                  polmd->name);
+                                       if (omd) {
+
+                                               _lws_ss_set_metadata(omd,
+                                                       polmd->name, p, (size_t)n);
+                                               omd->value_on_lws_heap = 1;
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+                                               omd->pending_onward = 1;
+#endif
+                                       }
+                               }
+                       }
+#endif
+
+               m++;
+               polmd = polmd->next;
+       }
+
+       return 0;
+}
+
+static const uint8_t blob_idx[] = {
+       LWS_SYSBLOB_TYPE_AUTH,
+       LWS_SYSBLOB_TYPE_DEVICE_SERIAL,
+       LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION,
+       LWS_SYSBLOB_TYPE_DEVICE_TYPE,
+};
+
+int
+secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+            void *in, size_t len)
+{
+#if defined(LWS_WITH_SERVER)
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+#endif
+       lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+       uint8_t buf[LWS_PRE + 1520], *p = &buf[LWS_PRE],
+#if defined(LWS_WITH_SERVER)
+                       *start = p,
+#endif
+               *end = &buf[sizeof(buf) - 1];
+       lws_ss_state_return_t r;
+       int f = 0, m, status;
+       char conceal_eom = 0;
+       lws_usec_t inter;
+       size_t buflen;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               if (!h) {
+                       lwsl_err("%s: CCE with no ss handle %s\n", __func__, lws_wsi_tag(wsi));
+                       break;
+               }
+
+               lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
+
+               assert(h->policy);
+
+#if defined(LWS_WITH_CONMON)
+               lws_conmon_ss_json(h);
+#endif
+
+               lws_metrics_caliper_report_hist(h->cal_txn, wsi);
+               lwsl_info("%s: %s CLIENT_CONNECTION_ERROR: %s\n", __func__,
+                         h->lc.gutag, in ? (const char *)in : "none");
+               if (h->ss_dangling_connected) {
+                       /* already disconnected, no action for DISCONNECT_ME */
+                       r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
+                       if (r != LWSSSSRET_OK)
+                               return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               }
+               /* already disconnected, no action for DISCONNECT_ME */
+               r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
+               if (r) {
+                       if (h->inside_connect) {
+                               h->pending_ret = r;
+                               break;
+                       }
+
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               }
+
+               h->wsi = NULL;
+               r = lws_ss_backoff(h);
+               if (r != LWSSSSRET_OK) {
+                       if (h->inside_connect) {
+                               h->pending_ret = r;
+                               break;
+                       }
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               }
+               break;
+
+       case LWS_CALLBACK_CLIENT_HTTP_REDIRECT:
+
+               if (!h)
+                       return -1;
+
+               if (h->policy->u.http.fail_redirect)
+                       lws_system_cpd_set(lws_get_context(wsi),
+                                          LWS_CPD_CAPTIVE_PORTAL);
+               /* unless it's explicitly allowed, reject to follow it */
+               return !(h->policy->flags & LWSSSPOLF_ALLOW_REDIRECTS);
+
+       case LWS_CALLBACK_CLOSED_HTTP: /* server */
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               if (!h)
+                       break;
+
+               lws_sul_cancel(&h->sul_timeout);
+
+               lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
+
+#if defined(LWS_WITH_CONMON)
+               if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
+                       wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
+                       wsi->conmon.protocol_specific.http.response =
+                                       (int)lws_http_client_http_response(wsi);
+               }
+
+               lws_conmon_ss_json(h);
+#endif
+
+               lws_metrics_caliper_report_hist(h->cal_txn, wsi);
+               //lwsl_notice("%s: %s LWS_CALLBACK_CLOSED_CLIENT_HTTP\n",
+               //              __func__, wsi->lc.gutag);
+
+               h->wsi = NULL;
+               h->hanging_som = 0;
+               h->subseq = 0;
+
+#if defined(LWS_WITH_SERVER)
+               lws_pt_lock(pt, __func__);
+               lws_dll2_remove(&h->cli_list);
+               lws_pt_unlock(pt);
+#endif
+
+               if (h->policy && !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
+#if defined(LWS_WITH_SERVER)
+                   !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
+#endif
+                   !h->txn_ok && !wsi->a.context->being_destroyed) {
+                       r = lws_ss_backoff(h);
+                       if (r != LWSSSSRET_OK)
+                               return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+                       break;
+               } else
+                       h->seqstate = SSSEQ_IDLE;
+
+               if (h->ss_dangling_connected) {
+                       /* already disconnected, no action for DISCONNECT_ME */
+                       r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
+                       if (r != LWSSSSRET_OK)
+                               return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               }
+               break;
+
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+
+               if (!h)
+                       return -1;
+
+               lws_ss_assert_extant(wsi->a.context, wsi->tsi, h);
+
+#if defined(LWS_WITH_CONMON)
+               if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) {
+                       wsi->conmon.pcol = LWSCONMON_PCOL_HTTP;
+                       wsi->conmon.protocol_specific.http.response =
+                                       (int)lws_http_client_http_response(wsi);
+               }
+
+               lws_conmon_ss_json(h);
+#endif
+
+               status = (int)lws_http_client_http_response(wsi);
+               lwsl_info("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: %d\n", __func__, status);
+       //      if (!status)
+                       /* it's just telling use we connected / joined the nwsi */
+       //              break;
+
+#if defined(LWS_WITH_SYS_METRICS)
+               if (status) {
+                       lws_snprintf((char *)buf, 10, "%d", status);
+                       lws_metrics_tag_ss_add(h, "http_resp", (char *)buf);
+               }
+#endif
+
+               if (status == HTTP_STATUS_SERVICE_UNAVAILABLE /* 503 */ ||
+                   status == 429 /* Too many requests */) {
+                       /*
+                        * We understand this attempt failed, and that we should
+                        * conceal this attempt.  If there's a specified
+                        * retry-after, we should use that if larger than our
+                        * computed backoff
+                        */
+
+                       inter = 0;
+                       lws_http_check_retry_after(wsi, &inter);
+
+                       r = _lws_ss_backoff(h, inter);
+                       if (r != LWSSSSRET_OK)
+                               return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+                       return -1; /* end this stream */
+               }
+
+               if (h->policy->u.http.resp_expect)
+                       h->u.http.good_respcode =
+                                       status == h->policy->u.http.resp_expect;
+               else
+                       h->u.http.good_respcode = (status >= 200 && status < 300);
+               // lwsl_err("%s: good resp %d %d\n", __func__, status, h->u.http.good_respcode);
+
+               if (lws_extract_metadata(h, wsi)) {
+                       lwsl_info("%s: rx metadata extract failed\n", __func__);
+
+                       return -1;
+               }
+
+               if (status) {
+                       /*
+                        * Check and see if it's something from the response
+                        * map, if so, generate the requested status.  If we're
+                        * the proxy onward connection, metadata has priority
+                        * over state updates on the serialization, so the
+                        * state callback will see the right metadata.
+                        */
+                       int n = lws_ss_http_resp_to_state(h, status);
+                       if (n) {
+                               r = lws_ss_event_helper(h, (lws_ss_constate_t)n);
+                               if (r != LWSSSSRET_OK)
+                                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi,
+                                                                       &h);
+                       }
+               }
+
+               if (h->u.http.good_respcode)
+                       lwsl_info("%s: Connected streamtype %s, %d\n", __func__,
+                                 h->policy->streamtype, status);
+               else
+                       if (h->u.http.good_respcode)
+                               lwsl_warn("%s: Connected streamtype %s, BAD %d\n",
+                                         __func__, h->policy->streamtype,
+                                         status);
+
+               h->hanging_som = 0;
+
+               h->retry = 0;
+               h->seqstate = SSSEQ_CONNECTED;
+               lws_sul_cancel(&h->sul);
+
+               if (h->prev_ss_state != LWSSSCS_CONNECTED) {
+                       wsi->client_suppress_CONNECTION_ERROR = 1;
+                       if (h->prev_ss_state != LWSSSCS_CONNECTED) {
+                               r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
+                               if (r != LWSSSSRET_OK)
+                                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+                       }
+               }
+
+               /*
+                * Since it's an http transaction we initiated... this is
+                * proof of connection validity
+                */
+               lws_validity_confirmed(wsi);
+
+#if defined(LWS_WITH_SS_RIDESHARE)
+
+               /*
+                * There are two ways we might want to deal with multipart,
+                * one is pass it through raw (although the user code needs
+                * a helping hand for learning the boundary), and the other
+                * is to deframe it and provide basically submessages in the
+                * different parts.
+                */
+
+               if (lws_hdr_copy(wsi, (char *)buf, sizeof(buf),
+                                WSI_TOKEN_HTTP_CONTENT_TYPE) > 0 &&
+               /* multipart/form-data;
+                * boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */
+
+                   (!strncmp((char *)buf, "multipart/form-data", 19) ||
+                    !strncmp((char *)buf, "multipart/related", 17))) {
+                       struct lws_tokenize ts;
+                       lws_tokenize_elem e;
+
+                       // puts((const char *)buf);
+
+                       memset(&ts, 0, sizeof(ts));
+                       ts.start = (char *)buf;
+                       ts.len = strlen(ts.start);
+                       ts.flags = LWS_TOKENIZE_F_RFC7230_DELIMS |
+                                       LWS_TOKENIZE_F_SLASH_NONTERM |
+                                       LWS_TOKENIZE_F_MINUS_NONTERM;
+
+                       h->u.http.boundary[0] = '\0';
+                       do {
+                               e = lws_tokenize(&ts);
+                               if (e == LWS_TOKZE_TOKEN_NAME_EQUALS &&
+                                   !strncmp(ts.token, "boundary", 8) &&
+                                   ts.token_len == 8) {
+                                       e = lws_tokenize(&ts);
+                                       if (e != LWS_TOKZE_TOKEN)
+                                               goto malformed;
+                                       h->u.http.boundary[0] = '\x0d';
+                                       h->u.http.boundary[1] = '\x0a';
+                                       h->u.http.boundary[2] = '-';
+                                       h->u.http.boundary[3] = '-';
+                                       lws_strnncpy(h->u.http.boundary + 4,
+                                                    ts.token, ts.token_len,
+                                                    sizeof(h->u.http.boundary) - 4);
+                                       h->u.http.boundary_len =
+                                               (uint8_t)(ts.token_len + 4);
+                                       h->u.http.boundary_seq = 2;
+                                       h->u.http.boundary_dashes = 0;
+                               }
+                       } while (e > 0);
+                       lwsl_info("%s: multipart boundary '%s' len %d\n", __func__,
+                                       h->u.http.boundary, h->u.http.boundary_len);
+
+                       /* inform the ss that a related message group begins */
+
+                       if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
+                           h->u.http.boundary[0])
+                               h->info.rx(ss_to_userobj(h), NULL, 0,
+                                          LWSSS_FLAG_RELATED_START);
+
+                       // lws_header_table_detach(wsi, 0);
+               }
+               break;
+malformed:
+               lwsl_notice("%s: malformed multipart header\n", __func__);
+               return -1;
+#else
+               break;
+#endif
+
+       case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
+               if (!h)
+                       return -1;
+               if (h->writeable_len)
+                       wsi->http.writeable_len = h->writeable_len;
+
+               {
+                       uint8_t **p = (uint8_t **)in, *end = (*p) + len,
+                               *oin = *(uint8_t **)in;
+
+               /*
+                * blob-based headers
+                */
+
+               for (m = 0; m < _LWSSS_HBI_COUNT; m++) {
+                       lws_system_blob_t *ab;
+                       int o = 0, n;
+
+                       if (!h->policy->u.http.blob_header[m])
+                               continue;
+
+                       /*
+                        * To be backward compatible, default is system-wide LWA auth,
+                        * and "http_auth_header" is for default LWA auth, current users do not
+                        * need any change in their policy.
+                        * If user wants different auth/token, need to specify the "use_auth"
+                        * and will be handled after metadata headers are applied.
+                        */
+
+                       if (m == LWSSS_HBI_AUTH &&
+                           h->policy->u.http.auth_preamble)
+                               o = lws_snprintf((char *)buf, sizeof(buf), "%s",
+                                       h->policy->u.http.auth_preamble);
+
+                       if (o > (int)sizeof(buf) - 2)
+                               return -1;
+
+                       ab = lws_system_get_blob(wsi->a.context, blob_idx[m], 0);
+                       if (!ab)
+                               return -1;
+
+                       buflen = sizeof(buf) - (unsigned int)o - 2u;
+                       n = lws_system_blob_get(ab, buf + o, &buflen, 0);
+                       if (n < 0)
+                               return -1;
+
+                       buf[(unsigned int)o + buflen] = '\0';
+                       lwsl_debug("%s: adding blob %d: %s\n", __func__, m, buf);
+
+                       if (lws_add_http_header_by_name(wsi,
+                                (uint8_t *)h->policy->u.http.blob_header[m],
+                                buf, (int)((int)buflen + o), p, end))
+                               return -1;
+               }
+
+               /*
+                * metadata-based headers
+                */
+
+               if (lws_apply_metadata(h, wsi, buf, p, end))
+                       return -1;
+
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+               if (h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR) {
+                       if (lws_apply_instant_metadata(h, wsi, buf, p, end))
+                               return -1;
+               }
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+               if (h->policy->auth && h->policy->auth->type &&
+                               !strcmp(h->policy->auth->type, "sigv4")) {
+
+                       if (lws_ss_apply_sigv4(wsi, h, p, end))
+                               return -1;
+               }
+#endif
+
+
+               (void)oin;
+               //if (*p != oin)
+               //      lwsl_hexdump_notice(oin, lws_ptr_diff_size_t(*p, oin));
+
+               }
+
+               /*
+                * So when proxied, for POST we have to synthesize a CONNECTED
+                * state, so it can request a writeable and deliver the POST
+                * body
+                */
+               if ((h->policy->protocol == LWSSSP_H1 ||
+                    h->policy->protocol == LWSSSP_H2) &&
+                    h->being_serialized && (
+                               !strcmp(h->policy->u.http.method, "PUT") ||
+                               !strcmp(h->policy->u.http.method, "POST"))) {
+
+                       wsi->client_suppress_CONNECTION_ERROR = 1;
+                       if (h->prev_ss_state != LWSSSCS_CONNECTED) {
+                               r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
+                               if (r)
+                                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+                       }
+               }
+
+               break;
+
+       /* chunks of chunked content, with header removed */
+       case LWS_CALLBACK_HTTP_BODY:
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+               lwsl_debug("%s: RECEIVE_CLIENT_HTTP_READ: read %d\n",
+                               __func__, (int)len);
+               if (!h || !h->info.rx)
+                       return 0;
+
+#if defined(LWS_WITH_SS_RIDESHARE)
+               if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
+                   h->u.http.boundary[0])
+                       return ss_http_multipart_parser(h, in, len);
+#endif
+
+               if (!h->subseq) {
+                       f |= LWSSS_FLAG_SOM;
+                       h->hanging_som = 1;
+                       h->subseq = 1;
+               }
+
+       //      lwsl_notice("%s: HTTP_READ: client side sent len %d fl 0x%x\n",
+       //                  __func__, (int)len, (int)f);
+
+               r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, f);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               return 0; /* don't passthru */
+
+       /* uninterpreted http content */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+               {
+                       char *px = (char *)buf + LWS_PRE; /* guarantees LWS_PRE */
+                       int lenx = sizeof(buf) - LWS_PRE;
+
+                       m = lws_http_client_read(wsi, &px, &lenx);
+                       if (m < 0)
+                               return m;
+               }
+               lws_set_timeout(wsi, 99, 30);
+
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
+               // lwsl_debug("%s: LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n", __func__);
+
+               if (!h)
+                       return -1;
+
+               if (h->hanging_som) {
+                       h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM);
+                       h->hanging_som = 0;
+                       h->subseq = 0;
+               }
+
+               wsi->http.writeable_len = h->writeable_len = 0;
+               lws_sul_cancel(&h->sul_timeout);
+
+               h->txn_ok = 1;
+
+#if defined(LWS_WITH_SYS_METRICS)
+               lws_metrics_tag_ss_add(h, "result",
+                                      h->u.http.good_respcode ?
+                                      "SS_ACK_REMOTE" : "SS_NACK_REMOTE");
+#endif
+
+               r = lws_ss_event_helper(h, h->u.http.good_respcode ?
+                                               LWSSSCS_QOS_ACK_REMOTE :
+                                               LWSSSCS_QOS_NACK_REMOTE);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       case LWS_CALLBACK_HTTP_WRITEABLE:
+       case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
+
+               if (!h || !h->info.tx) {
+                       lwsl_notice("%s: no handle / tx\n", __func__);
+                       return 0;
+               }
+
+#if defined(LWS_WITH_SERVER)
+               if (h->txn_resp_pending) {
+                       /*
+                        * If we're going to start sending something, we need to
+                        * to take care of the http response header for it first
+                        */
+                       h->txn_resp_pending = 0;
+
+                       if (lws_add_http_common_headers(wsi,
+                                       (unsigned int)(h->txn_resp_set ?
+                                               (h->txn_resp ? h->txn_resp : 200) :
+                                               HTTP_STATUS_NOT_FOUND),
+                                       NULL, h->wsi->http.writeable_len,
+                                       &p, end))
+                               return 1;
+
+                       /*
+                        * metadata-based headers
+                        */
+
+                       if (lws_apply_metadata(h, wsi, buf, &p, end))
+                               return -1;
+
+                       if (lws_finalize_write_http_header(wsi, start, &p, end))
+                               return 1;
+
+                       /* write the body separately */
+                       lws_callback_on_writable(wsi);
+
+                       return 0;
+               }
+#endif
+
+               if (
+#if defined(LWS_WITH_SERVER)
+                   !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not accepted */
+#endif
+                   !h->rideshare)
+
+                       h->rideshare = h->policy;
+
+#if defined(LWS_WITH_SS_RIDESHARE)
+               if (
+#if defined(LWS_WITH_SERVER)
+                   !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not accepted */
+#endif
+                   !h->inside_msg && h->rideshare->u.http.multipart_name)
+                       lws_client_http_multipart(wsi,
+                               h->rideshare->u.http.multipart_name,
+                               h->rideshare->u.http.multipart_filename,
+                               h->rideshare->u.http.multipart_content_type,
+                               (char **)&p, (char *)end);
+
+               buflen = lws_ptr_diff_size_t(end, p);
+               if (h->policy->u.http.multipart_name)
+                       buflen -= 24; /* allow space for end of multipart */
+#else
+               buflen = lws_ptr_diff_size_t(end, p);
+#endif
+               r = h->info.tx(ss_to_userobj(h), h->txord++, p, &buflen, &f);
+               if (r == LWSSSSRET_TX_DONT_SEND)
+                       return 0;
+               if (r < 0)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               // lwsl_notice("%s: WRITEABLE: user tx says len %d fl 0x%x\n",
+               //          __func__, (int)buflen, (int)f);
+
+               p += buflen;
+
+               if (f & LWSSS_FLAG_EOM) {
+#if defined(LWS_WITH_SERVER)
+                   if (!(h->info.flags & LWSSSINFLAGS_ACCEPTED)) {
+#endif
+                       conceal_eom = 1;
+                       /* end of rideshares */
+                       if (!h->rideshare->rideshare_streamtype) {
+                               lws_client_http_body_pending(wsi, 0);
+#if defined(LWS_WITH_SS_RIDESHARE)
+                               if (h->rideshare->u.http.multipart_name)
+                                       lws_client_http_multipart(wsi, NULL, NULL, NULL,
+                                               (char **)&p, (char *)end);
+                               conceal_eom = 0;
+#endif
+                       } else {
+                               h->rideshare = lws_ss_policy_lookup(wsi->a.context,
+                                               h->rideshare->rideshare_streamtype);
+                               lws_callback_on_writable(wsi);
+                       }
+#if defined(LWS_WITH_SERVER)
+                   }
+#endif
+
+                       h->inside_msg = 0;
+               } else {
+                       /* otherwise we can spin with zero length writes */
+                       if (!f && !lws_ptr_diff(p, buf + LWS_PRE))
+                               break;
+                       h->inside_msg = 1;
+                       lws_callback_on_writable(wsi);
+               }
+
+               lwsl_info("%s: lws_write %d %d\n", __func__,
+                         lws_ptr_diff(p, buf + LWS_PRE), f);
+
+               if (lws_write(wsi, buf + LWS_PRE, lws_ptr_diff_size_t(p, buf + LWS_PRE),
+                        (!conceal_eom && (f & LWSSS_FLAG_EOM)) ?
+                                   LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP) !=
+                               (int)lws_ptr_diff(p, buf + LWS_PRE)) {
+                       lwsl_err("%s: write failed\n", __func__);
+                       return -1;
+               }
+
+#if defined(LWS_WITH_SERVER)
+               if ((h->info.flags & LWSSSINFLAGS_ACCEPTED) /* server */ &&
+                   (f & LWSSS_FLAG_EOM) &&
+                    lws_http_transaction_completed(wsi))
+                       return -1;
+#else
+               lws_set_timeout(wsi, 0, 0);
+#endif
+               break;
+
+#if defined(LWS_WITH_SERVER)
+       case LWS_CALLBACK_HTTP:
+
+               if (!h)
+                       return -1;
+
+               lwsl_info("%s: LWS_CALLBACK_HTTP\n", __func__);
+               {
+
+                       h->txn_resp_set = 0;
+                       h->txn_resp_pending = 1;
+                       h->writeable_len = 0;
+
+#if defined(LWS_ROLE_H2)
+                       m = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
+                       if (m) {
+                               if (lws_ss_alloc_set_metadata(h, "method",
+                                                   lws_hdr_simple_ptr(wsi,
+                                                    WSI_TOKEN_HTTP_COLON_METHOD), (unsigned int)m))
+                                       return -1;
+                               m = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH);
+                               if (m && lws_ss_alloc_set_metadata(h, "path",
+                                                   lws_hdr_simple_ptr(wsi,
+                                                    WSI_TOKEN_HTTP_COLON_PATH), (unsigned int)m))
+                                       return -1;
+                       } else
+#endif
+                       {
+                               m = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
+                               if (m) {
+                                       if (lws_ss_alloc_set_metadata(h, "path",
+                                                       lws_hdr_simple_ptr(wsi,
+                                                               WSI_TOKEN_GET_URI), (unsigned int)m))
+                                               return -1;
+                                       if (lws_ss_alloc_set_metadata(h, "method", "GET", 3))
+                                               return -1;
+                               } else {
+                                       m = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
+                                       if (m) {
+                                               if (lws_ss_alloc_set_metadata(h, "path",
+                                                               lws_hdr_simple_ptr(wsi,
+                                                                       WSI_TOKEN_POST_URI), (unsigned int)m))
+                                                       return -1;
+                                               if (lws_ss_alloc_set_metadata(h, "method", "POST", 4))
+                                                       return -1;
+                                       }
+                               }
+                       }
+               }
+
+               if (!h->ss_dangling_connected) {
+#if defined(LWS_WITH_SYS_METRICS)
+                       /*
+                        * If any hanging caliper measurement, dump it, and free any tags
+                        */
+                       lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+                       wsi->client_suppress_CONNECTION_ERROR = 1;
+                       if (h->prev_ss_state != LWSSSCS_CONNECTED) {
+                               r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
+                               if (r)
+                                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+                       }
+               }
+
+               r = lws_ss_event_helper(h, LWSSSCS_SERVER_TXN);
+               if (r)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r,
+                                                               wsi, &h);
+
+               return 0;
+#endif
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+const struct lws_protocols protocol_secstream_h1 = {
+       "lws-secstream-h1",
+       secstream_h1,
+       0, 0, 0, NULL, 0
+};
+
+/*
+ * Munge connect info according to protocol-specific considerations... this
+ * usually means interpreting aux in a protocol-specific way and using the
+ * pieces at connection setup time, eg, http url pieces.
+ *
+ * len bytes of buf can be used for things with scope until after the actual
+ * connect.
+ */
+
+static int
+secstream_connect_munge_h1(lws_ss_handle_t *h, char *buf, size_t len,
+                          struct lws_client_connect_info *i,
+                          union lws_ss_contemp *ct)
+{
+       const char *pbasis = h->policy->u.http.url;
+       size_t used_in, used_out;
+       lws_strexp_t exp;
+
+       /* i.path on entry is used to override the policy urlpath if not "" */
+
+       if (i->path[0])
+               pbasis = i->path;
+
+       if (!pbasis)
+               return 0;
+
+       /* uncomment to force h1 */
+       // i->alpn = "http/1.1";
+
+#if defined(LWS_WITH_SS_RIDESHARE)
+       if (h->policy->flags & LWSSSPOLF_HTTP_MULTIPART)
+               i->ssl_connection |= LCCSCF_HTTP_MULTIPART_MIME;
+
+       if (h->policy->flags & LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED)
+               i->ssl_connection |= LCCSCF_HTTP_X_WWW_FORM_URLENCODED;
+#endif
+
+       if (h->policy->flags & LWSSSPOLF_HTTP_CACHE_COOKIES)
+               i->ssl_connection |= LCCSCF_CACHE_COOKIES;
+
+       /* protocol aux is the path part */
+
+       i->path = buf;
+
+       /* skip the unnessary '/' */
+       if (*pbasis == '/')
+               pbasis = pbasis + 1;
+
+       buf[0] = '/';
+
+       lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1);
+
+       if (lws_strexp_expand(&exp, pbasis, strlen(pbasis),
+                             &used_in, &used_out) != LSTRX_DONE)
+               return 1;
+
+       return 0;
+}
+
+
+const struct ss_pcols ss_pcol_h1 = {
+       "h1",
+       "http/1.1",
+       &protocol_secstream_h1,
+       secstream_connect_munge_h1,
+       NULL, NULL
+};
diff --git a/lib/secure-streams/protocols/ss-h2.c b/lib/secure-streams/protocols/ss-h2.c
new file mode 100644 (file)
index 0000000..3d1aa9c
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+extern int
+secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+            void *in, size_t len);
+
+static int
+secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+            void *in, size_t len)
+{
+       lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+       lws_ss_state_return_t r;
+       int n;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+
+               if (!h)
+                       return -1;
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+               if (h->being_serialized) {
+                       /*
+                        * We are the proxy-side SS for a remote client... we
+                        * need to inform the client about the initial tx credit
+                        * to write to it that the remote h2 server set up
+                        */
+                       lwsl_info("%s: reporting initial tx cr from server %d\n",
+                                 __func__, wsi->txc.tx_cr);
+                       ss_proxy_onward_txcr((void *)&h[1], wsi->txc.tx_cr);
+               }
+#endif
+
+               n = secstream_h1(wsi, reason, user, in, len);
+
+               if (!n && (h->policy->flags & LWSSSPOLF_LONG_POLL)) {
+                       lwsl_notice("%s: h2 client %s entering LONG_POLL\n",
+                                       __func__, lws_wsi_tag(wsi));
+                       lws_h2_client_stream_long_poll_rxonly(wsi);
+               }
+               return n;
+
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               /*
+                * Only allow the wsi that the handle believes is representing
+                * him to report closure up to h1
+                */
+               if (!h || h->wsi != wsi)
+                       return 0;
+
+               break;
+
+       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
+
+               if (!h)
+                       return -1;
+
+               // lwsl_err("%s: h2 COMPLETED_CLIENT_HTTP\n", __func__);
+               r = 0;
+               if (h->hanging_som)
+                       r = h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM);
+
+               h->txn_ok = 1;
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               if (h->hanging_som && r == LWSSSSRET_DESTROY_ME)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               h->hanging_som = 0;
+               break;
+
+       case LWS_CALLBACK_WSI_TX_CREDIT_GET:
+
+               if (!h)
+                       return -1;
+
+               /*
+                * The peer has sent us additional tx credit...
+                */
+               lwsl_info("%s: LWS_CALLBACK_WSI_TX_CREDIT_GET: %d\n",
+                           __func__, (int)len);
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+               if (h->being_serialized)
+                       /* we are the proxy-side SS for a remote client */
+                       ss_proxy_onward_txcr((void *)&h[1], (int)len);
+#endif
+               break;
+
+       default:
+               break;
+       }
+
+       return secstream_h1(wsi, reason, user, in, len);
+}
+
+const struct lws_protocols protocol_secstream_h2 = {
+       "lws-secstream-h2",
+       secstream_h2,
+       0, 0, 0, NULL, 0
+};
+
+/*
+ * Munge connect info according to protocol-specific considerations... this
+ * usually means interpreting aux in a protocol-specific way and using the
+ * pieces at connection setup time, eg, http url pieces.
+ *
+ * len bytes of buf can be used for things with scope until after the actual
+ * connect.
+ */
+
+int
+secstream_connect_munge_h2(lws_ss_handle_t *h, char *buf, size_t len,
+                          struct lws_client_connect_info *i,
+                          union lws_ss_contemp *ct)
+{
+       const char *pbasis = h->policy->u.http.url;
+       size_t used_in, used_out;
+       lws_strexp_t exp;
+
+       /* i.path on entry is used to override the policy urlpath if not "" */
+
+       if (i->path[0])
+               pbasis = i->path;
+
+       if (h->policy->flags & LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM)
+               i->ssl_connection |= LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
+
+       if (h->policy->flags & LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR)
+               i->ssl_connection |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR;
+
+       if (h->policy->flags & LWSSSPOLF_HTTP_MULTIPART)
+               i->ssl_connection |= LCCSCF_HTTP_MULTIPART_MIME;
+
+       if (h->policy->flags & LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED)
+               i->ssl_connection |= LCCSCF_HTTP_X_WWW_FORM_URLENCODED;
+
+       if (h->policy->flags & LWSSSPOLF_HTTP_CACHE_COOKIES)
+               i->ssl_connection |= LCCSCF_CACHE_COOKIES;
+
+       i->ssl_connection |= LCCSCF_PIPELINE;
+
+       i->alpn = "h2";
+
+       /* initial peer tx credit */
+
+       if (h->info.manual_initial_tx_credit) {
+               i->ssl_connection |= LCCSCF_H2_MANUAL_RXFLOW;
+               i->manual_initial_tx_credit = h->info.manual_initial_tx_credit;
+               lwsl_info("%s: initial txcr %d\n", __func__,
+                               i->manual_initial_tx_credit);
+       }
+
+       if (!pbasis)
+               return 0;
+
+       /* protocol aux is the path part */
+
+       i->path = buf;
+       buf[0] = '/';
+
+       lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1);
+
+       if (lws_strexp_expand(&exp, pbasis, strlen(pbasis),
+                             &used_in, &used_out) != LSTRX_DONE)
+               return 1;
+
+       return 0;
+}
+
+static int
+secstream_tx_credit_add_h2(lws_ss_handle_t *h, int add)
+{
+       lwsl_info("%s: %s: add %d\n", __func__, lws_ss_tag(h), add);
+       if (h->wsi)
+               return lws_h2_update_peer_txcredit(h->wsi, (unsigned int)LWS_H2_STREAM_SID, add);
+
+       return 0;
+}
+
+static int
+secstream_tx_credit_est_h2(lws_ss_handle_t *h)
+{
+       if (h->wsi) {
+               lwsl_info("%s: %s: est %d\n", __func__, lws_ss_tag(h),
+                               lws_h2_get_peer_txcredit_estimate(h->wsi));
+
+               return lws_h2_get_peer_txcredit_estimate(h->wsi);
+       }
+
+       lwsl_info("%s: %s: Unknown (0)\n", __func__, lws_ss_tag(h));
+
+       return 0;
+}
+
+const struct ss_pcols ss_pcol_h2 = {
+       "h2",
+       "h2",
+       &protocol_secstream_h2,
+       secstream_connect_munge_h2,
+       secstream_tx_credit_add_h2,
+       secstream_tx_credit_est_h2
+};
diff --git a/lib/secure-streams/protocols/ss-mqtt.c b/lib/secure-streams/protocols/ss-mqtt.c
new file mode 100644 (file)
index 0000000..f13eea4
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+static void
+secstream_mqtt_cleanup(lws_ss_handle_t *h)
+{
+       uint32_t i;
+
+       if (h->u.mqtt.heap_baggage) {
+               lws_free(h->u.mqtt.heap_baggage);
+               h->u.mqtt.heap_baggage = NULL;
+       }
+
+       if (h->u.mqtt.sub_info.topic) {
+               for (i = 0; i < h->u.mqtt.sub_info.num_topics; i++) {
+                       if (h->u.mqtt.sub_info.topic[i].name) {
+                               lws_free((void*)h->u.mqtt.sub_info.topic[i].name);
+                               h->u.mqtt.sub_info.topic[i].name = NULL;
+                       }
+               }
+               lws_free(h->u.mqtt.sub_info.topic);
+               h->u.mqtt.sub_info.topic = NULL;
+       }
+}
+
+static int
+secstream_mqtt_subscribe(struct lws *wsi)
+{
+       size_t used_in, used_out, topic_limit;
+       lws_strexp_t exp;
+       char* expbuf;
+       lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+
+       if (!h || !h->policy)
+               return -1;
+
+       if (h->policy->u.mqtt.aws_iot)
+               topic_limit = LWS_MQTT_MAX_AWSIOT_TOPICLEN;
+       else
+               topic_limit = LWS_MQTT_MAX_TOPICLEN;
+
+       if (!h->policy->u.mqtt.subscribe || wsi->mqtt->done_subscribe)
+               return 0;
+
+       lws_strexp_init(&exp, (void*)h, lws_ss_exp_cb_metadata, NULL,
+                       topic_limit);
+       /*
+        * Expand with no output first to calculate the size of
+        * expanded string then, allocate new buffer and expand
+        * again with the buffer
+        */
+       if (lws_strexp_expand(&exp, h->policy->u.mqtt.subscribe,
+                             strlen(h->policy->u.mqtt.subscribe), &used_in,
+                             &used_out) != LSTRX_DONE) {
+               lwsl_err(
+                       "%s, failed to expand MQTT subscribe"
+                       " topic with no output\n",
+                       __func__);
+               return 1;
+       }
+
+       expbuf = lws_malloc(used_out + 1, __func__);
+       if (!expbuf) {
+               lwsl_err(
+                        "%s, failed to allocate MQTT subscribe"
+                        "topic",
+                        __func__);
+               return 1;
+       }
+
+       lws_strexp_init(&exp, (void*)h, lws_ss_exp_cb_metadata, expbuf,
+                       used_out + 1);
+
+       if (lws_strexp_expand(&exp, h->policy->u.mqtt.subscribe,
+                             strlen(h->policy->u.mqtt.subscribe), &used_in,
+                             &used_out) != LSTRX_DONE) {
+               lwsl_err("%s, failed to expand MQTT subscribe topic\n",
+                        __func__);
+               lws_free(expbuf);
+               return 1;
+       }
+       lwsl_notice("%s, expbuf - %s\n", __func__, expbuf);
+       h->u.mqtt.sub_top.name = expbuf;
+
+       /*
+        * The policy says to subscribe to something, and we
+        * haven't done it yet.  Do it using the pre-prepared
+        * string-substituted version of the policy string.
+        */
+
+       lwsl_notice("%s: subscribing %s\n", __func__,
+                   h->u.mqtt.sub_top.name);
+
+       h->u.mqtt.sub_top.qos = h->policy->u.mqtt.qos;
+       memset(&h->u.mqtt.sub_info, 0, sizeof(h->u.mqtt.sub_info));
+       h->u.mqtt.sub_info.num_topics = 1;
+       h->u.mqtt.sub_info.topic = &h->u.mqtt.sub_top;
+       h->u.mqtt.sub_info.topic =
+                           lws_malloc(sizeof(lws_mqtt_topic_elem_t), __func__);
+       h->u.mqtt.sub_info.topic[0].name = lws_strdup(expbuf);
+       h->u.mqtt.sub_info.topic[0].qos = h->policy->u.mqtt.qos;
+
+       if (lws_mqtt_client_send_subcribe(wsi, &h->u.mqtt.sub_info)) {
+               lwsl_notice("%s: unable to subscribe", __func__);
+               lws_free(expbuf);
+               h->u.mqtt.sub_top.name = NULL;
+               return -1;
+       }
+       lws_free(expbuf);
+       h->u.mqtt.sub_top.name = NULL;
+
+       /* Expect a SUBACK */
+       if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
+               lwsl_err("%s: Unable to set LWS_POLLIN\n", __func__);
+               return -1;
+       }
+       return 0;
+}
+
+static int
+secstream_mqtt_publish(struct lws *wsi, uint8_t *buf, size_t buflen,
+                       const char* topic,
+                       lws_mqtt_qos_levels_t qos,  int f)
+{
+       lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+       size_t used_in, used_out, topic_limit;
+       lws_strexp_t exp;
+       char *expbuf;
+       lws_mqtt_publish_param_t mqpp;
+
+       if (h->policy->u.mqtt.aws_iot)
+               topic_limit = LWS_MQTT_MAX_AWSIOT_TOPICLEN;
+       else
+               topic_limit = LWS_MQTT_MAX_TOPICLEN;
+
+       memset(&mqpp, 0, sizeof(mqpp));
+
+       lws_strexp_init(&exp, h, lws_ss_exp_cb_metadata, NULL,
+                       topic_limit);
+
+       if (lws_strexp_expand(&exp, topic, strlen(topic), &used_in,
+                             &used_out) != LSTRX_DONE) {
+               lwsl_err("%s, failed to expand MQTT publish"
+                        " topic with no output\n", __func__);
+               return 1;
+       }
+       expbuf = lws_malloc(used_out + 1, __func__);
+       if (!expbuf) {
+               lwsl_err("%s, failed to allocate MQTT publish topic",
+                         __func__);
+               return 1;
+       }
+
+       lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, expbuf,
+                       used_out + 1);
+
+       if (lws_strexp_expand(&exp, topic, strlen(topic), &used_in,
+                             &used_out) != LSTRX_DONE) {
+               lws_free(expbuf);
+               return 1;
+       }
+       lwsl_notice("%s, expbuf - %s\n", __func__, expbuf);
+       mqpp.topic = (char *)expbuf;
+
+       mqpp.topic_len = (uint16_t)strlen(mqpp.topic);
+       mqpp.packet_id = (uint16_t)(h->txord - 1);
+       mqpp.payload = buf;
+       if (h->writeable_len)
+               mqpp.payload_len = (uint32_t)h->writeable_len;
+       else
+               mqpp.payload_len = (uint32_t)buflen;
+
+       lwsl_notice("%s: payload len %d\n", __func__,
+                   (int)mqpp.payload_len);
+
+       mqpp.qos = h->policy->u.mqtt.qos;
+
+       if (lws_mqtt_client_send_publish(wsi, &mqpp,
+                                        (const char *)buf,
+                                        (uint32_t)buflen,
+                                        f & LWSSS_FLAG_EOM)) {
+               lwsl_notice("%s: failed to publish\n", __func__);
+               lws_free(expbuf);
+               return -1;
+       }
+       lws_free(expbuf);
+       return 0;
+}
+
+static int
+secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+            void *in, size_t len)
+{
+       lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+       lws_mqtt_publish_param_t *pmqpp;
+       uint8_t buf[LWS_PRE + 1400];
+       lws_ss_state_return_t r;
+       size_t buflen = sizeof(buf) - LWS_PRE;
+       int f = 0;
+
+       switch (reason) {
+
+       /* because we are protocols[0] ... */
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_info("%s: CLIENT_CONNECTION_ERROR: %s\n", __func__,
+                        in ? (char *)in : "(null)");
+               if (!h)
+                       break;
+
+#if defined(LWS_WITH_CONMON)
+               lws_conmon_ss_json(h);
+#endif
+
+               r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
+               h->wsi = NULL;
+
+               secstream_mqtt_cleanup(h);
+
+               if (r == LWSSSSRET_DESTROY_ME)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               r = lws_ss_backoff(h);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_CLOSED:
+               if (!h)
+                       break;
+               lws_sul_cancel(&h->sul_timeout);
+#if defined(LWS_WITH_CONMON)
+               lws_conmon_ss_json(h);
+#endif
+               if (h->ss_dangling_connected)
+                       r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
+               else
+                       r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
+               if (h->wsi)
+                       lws_set_opaque_user_data(h->wsi, NULL);
+               h->wsi = NULL;
+
+               secstream_mqtt_cleanup(h);
+
+               if (r)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               if (h->policy && !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
+                   !h->txn_ok && !wsi->a.context->being_destroyed) {
+                       r = lws_ss_backoff(h);
+                       if (r != LWSSSSRET_OK)
+                               return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               }
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_ESTABLISHED:
+               /*
+                * Make sure the handle wsi points to the stream wsi not the
+                * original nwsi, in the case it was migrated
+                */
+               h->wsi = wsi;
+               h->retry = 0;
+               h->seqstate = SSSEQ_CONNECTED;
+
+               if (!h->policy->u.mqtt.subscribe ||
+                   !h->policy->u.mqtt.subscribe[0]) {
+                       /*
+                        * If subscribe is empty in the policy, then,
+                        * skip sending SUBSCRIBE and signal the user
+                        * application.
+                        */
+                       wsi->mqtt->done_subscribe = 1;
+               } else if (!h->policy->u.mqtt.clean_start &&
+                          wsi->mqtt->session_resumed) {
+                       wsi->mqtt->inside_resume_session = 1;
+                       /*
+                        * If the previous session is resumed and Server has
+                        * stored session, then, do not subscribe.
+                        */
+                       if (!secstream_mqtt_subscribe(wsi))
+                               wsi->mqtt->done_subscribe = 1;
+                       wsi->mqtt->inside_resume_session = 0;
+               } else if (h->policy->u.mqtt.subscribe &&
+                          !wsi->mqtt->done_subscribe) {
+                       /*
+                        * If a subscribe is pending on the stream, then make
+                        * sure the SUBSCRIBE is done before signaling the
+                        * user application.
+                        */
+                       lws_callback_on_writable(wsi);
+                       break;
+               }
+               lws_sul_cancel(&h->sul);
+#if defined(LWS_WITH_SYS_METRICS)
+               /*
+                * If any hanging caliper measurement, dump it, and free any tags
+                */
+               lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+               r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               if (h->policy->u.mqtt.topic)
+                       lws_callback_on_writable(wsi);
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_RX:
+               // lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE: read %d\n", (int)len);
+               if (!h || !h->info.rx)
+                       return 0;
+
+               pmqpp = (lws_mqtt_publish_param_t *)in;
+
+               f = 0;
+               if (!pmqpp->payload_pos)
+                       f |= LWSSS_FLAG_SOM;
+               if (pmqpp->payload_pos + len == pmqpp->payload_len)
+                       f |= LWSSS_FLAG_EOM;
+
+               h->subseq = 1;
+
+               r = h->info.rx(ss_to_userobj(h), (const uint8_t *)pmqpp->payload,
+                          len, f);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_MQTT_SUBSCRIBED:
+               /*
+                * Stream demanded a subscribe while connecting, once
+                * done notify CONNECTED event to the application.
+                */
+               if (wsi->mqtt->done_subscribe == 0) {
+                       lws_sul_cancel(&h->sul);
+                       r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
+                       if (r != LWSSSSRET_OK)
+                               return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               }
+               wsi->mqtt->done_subscribe = 1;
+               lws_callback_on_writable(wsi);
+               break;
+
+       case LWS_CALLBACK_MQTT_ACK:
+               lws_sul_cancel(&h->sul_timeout);
+               if (wsi->mqtt->inside_birth) {
+                       /*
+                        * Skip LWSSSCS_QOS_ACK_REMOTE for birth topic.
+                        */
+                       wsi->mqtt->inside_birth = 0;
+                       wsi->mqtt->done_birth = 1;
+                       break;
+               }
+               r = lws_ss_event_helper(h, LWSSSCS_QOS_ACK_REMOTE);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_WRITEABLE:
+       {
+               if (!h || !h->info.tx)
+                       return 0;
+               lwsl_notice("%s: %s: WRITEABLE\n", __func__, lws_ss_tag(h));
+
+               if (h->seqstate != SSSEQ_CONNECTED) {
+                       lwsl_warn("%s: seqstate %d\n", __func__, h->seqstate);
+                       break;
+               }
+
+               if (!wsi->mqtt->done_subscribe && h->policy->u.mqtt.subscribe)
+                       return secstream_mqtt_subscribe(wsi);
+
+               if (!wsi->mqtt->done_birth && h->policy->u.mqtt.birth_topic) {
+                       lws_strexp_t exp;
+                       size_t used_in, used_out = 0;
+                       if (h->policy->u.mqtt.birth_message) {
+                               lws_strexp_init(&exp, h, lws_ss_exp_cb_metadata,
+                                               (char *)(buf + LWS_PRE), buflen);
+                               if (lws_strexp_expand(&exp, h->policy->u.mqtt.birth_message,
+                                                     strlen(h->policy->u.mqtt.birth_message),
+                                                     &used_in, &used_out) != LSTRX_DONE) {
+                                       return 1;
+                               }
+                       }
+                       wsi->mqtt->inside_birth = 1;
+                       return secstream_mqtt_publish(wsi, buf + LWS_PRE,
+                                       used_out, h->policy->u.mqtt.birth_topic,
+                                       h->policy->u.mqtt.birth_qos, LWSSS_FLAG_EOM);
+               }
+               r = h->info.tx(ss_to_userobj(h),  h->txord++,  buf + LWS_PRE,
+                              &buflen, &f);
+               if (r == LWSSSSRET_TX_DONT_SEND)
+                       return 0;
+
+               if (r == LWSSSSRET_DISCONNECT_ME) {
+                       lws_mqtt_subscribe_param_t lmsp;
+                       if (h->u.mqtt.sub_info.num_topics) {
+                               lmsp.num_topics = h->u.mqtt.sub_info.num_topics;
+                               lmsp.topic = h->u.mqtt.sub_info.topic;
+                               lmsp.packet_id = (uint16_t)(h->txord - 1);
+                               if (lws_mqtt_client_send_unsubcribe(wsi,
+                                                                   &lmsp)) {
+                                       lwsl_err("%s, failed to send"
+                                                " MQTT unsubsribe", __func__);
+                                       return -1;
+                               }
+                               return 0;
+                       }
+               }
+
+               if (r < 0)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               return secstream_mqtt_publish(wsi, buf + LWS_PRE, buflen,
+                                             h->policy->u.mqtt.topic,
+                                             h->policy->u.mqtt.qos, f);
+       }
+
+       case LWS_CALLBACK_MQTT_UNSUBSCRIBED:
+       {
+               struct lws *nwsi = lws_get_network_wsi(wsi);
+               if (nwsi && (nwsi->mux.child_count == 1))
+                       lws_mqtt_client_send_disconnect(nwsi);
+               return -1;
+       }
+
+       case LWS_CALLBACK_MQTT_UNSUBSCRIBE_TIMEOUT:
+               if (wsi->mqtt->inside_unsubscribe) {
+                       lwsl_warn("%s: %s: Unsubscribe timout.\n", __func__,
+                                 lws_ss_tag(h));
+                       return -1;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+const struct lws_protocols protocol_secstream_mqtt = {
+       "lws-secstream-mqtt",
+       secstream_mqtt,
+       0, 0, 0, NULL, 0
+};
+/*
+ * Munge connect info according to protocol-specific considerations... this
+ * usually means interpreting aux in a protocol-specific way and using the
+ * pieces at connection setup time, eg, http url pieces.
+ *
+ * len bytes of buf can be used for things with scope until after the actual
+ * connect.
+ *
+ * For ws, protocol aux is <url path>;<ws subprotocol name>
+ */
+
+enum {
+       SSCMM_STRSUB_WILL_TOPIC,
+       SSCMM_STRSUB_WILL_MESSAGE,
+       SSCMM_STRSUB_SUBSCRIBE,
+       SSCMM_STRSUB_TOPIC,
+       SSCMM_STRSUB_BIRTH_TOPIC,
+       SSCMM_STRSUB_BIRTH_MESSAGE
+};
+
+static int
+secstream_connect_munge_mqtt(lws_ss_handle_t *h, char *buf, size_t len,
+                            struct lws_client_connect_info *i,
+                            union lws_ss_contemp *ct)
+{
+       const char *sources[6] = {
+               /* we're going to string-substitute these before use */
+               h->policy->u.mqtt.will_topic,
+               h->policy->u.mqtt.will_message,
+               h->policy->u.mqtt.subscribe,
+               h->policy->u.mqtt.topic,
+               h->policy->u.mqtt.birth_topic,
+               h->policy->u.mqtt.birth_message
+       };
+       size_t used_in, olen[6] = { 0, 0, 0, 0, 0, 0 }, tot = 0;
+       lws_strexp_t exp;
+       char *ps[6];
+       uint8_t *p = NULL;
+       int n = -1;
+       size_t blen;
+       lws_system_blob_t *b = NULL;
+
+       memset(&ct->ccp, 0, sizeof(ct->ccp));
+       b = lws_system_get_blob(i->context,
+                               LWS_SYSBLOB_TYPE_MQTT_CLIENT_ID, 0);
+
+       /* If LWS_SYSBLOB_TYPE_MQTT_CLIENT_ID is set */
+       if (b && (blen = lws_system_blob_get_size(b))) {
+               if (blen > LWS_MQTT_MAX_CIDLEN) {
+                       lwsl_err("%s - Client ID too long.\n",
+                                __func__);
+                       return -1;
+               }
+               p = (uint8_t *)lws_zalloc(blen+1, __func__);
+               if (!p)
+                       return -1;
+               n = lws_system_blob_get(b, p, &blen, 0);
+               if (n) {
+                       ct->ccp.client_id = NULL;
+               } else {
+                       ct->ccp.client_id = (const char *)p;
+                       lwsl_notice("%s - Client ID = %s\n",
+                                   __func__, ct->ccp.client_id);
+               }
+       } else {
+               /* Default (Random) client ID */
+               ct->ccp.client_id = NULL;
+       }
+
+       b = lws_system_get_blob(i->context,
+                               LWS_SYSBLOB_TYPE_MQTT_USERNAME, 0);
+
+       /* If LWS_SYSBLOB_TYPE_MQTT_USERNAME is set */
+       if (b && (blen = lws_system_blob_get_size(b))) {
+               p = (uint8_t *)lws_zalloc(blen+1, __func__);
+               if (!p)
+                       return -1;
+               n = lws_system_blob_get(b, p, &blen, 0);
+               if (n) {
+                       ct->ccp.username = NULL;
+               } else {
+                       ct->ccp.username = (const char *)p;
+                       lwsl_notice("%s - Username ID = %s\n",
+                                   __func__, ct->ccp.username);
+               }
+       }
+
+       b = lws_system_get_blob(i->context,
+                               LWS_SYSBLOB_TYPE_MQTT_PASSWORD, 0);
+
+       /* If LWS_SYSBLOB_TYPE_MQTT_PASSWORD is set */
+       if (b && (blen = lws_system_blob_get_size(b))) {
+               p = (uint8_t *)lws_zalloc(blen+1, __func__);
+               if (!p)
+                       return -1;
+               n = lws_system_blob_get(b, p, &blen, 0);
+               if (n) {
+                       ct->ccp.password = NULL;
+               } else {
+                       ct->ccp.password = (const char *)p;
+                       lwsl_notice("%s - Password ID = %s\n",
+                                   __func__, ct->ccp.password);
+               }
+       }
+
+       ct->ccp.keep_alive              = h->policy->u.mqtt.keep_alive;
+       ct->ccp.clean_start             = (h->policy->u.mqtt.clean_start & 1u);
+       ct->ccp.will_param.qos          = h->policy->u.mqtt.will_qos;
+       ct->ccp.will_param.retain       = h->policy->u.mqtt.will_retain;
+       ct->ccp.birth_param.qos         = h->policy->u.mqtt.birth_qos;
+       ct->ccp.birth_param.retain      = h->policy->u.mqtt.birth_retain;
+       ct->ccp.aws_iot                 = h->policy->u.mqtt.aws_iot;
+       h->u.mqtt.topic_qos.qos         = h->policy->u.mqtt.qos;
+
+       /*
+        * We're going to string-substitute several of these parameters, which
+        * have unknown, possibly large size.  And, as their usage is deferred
+        * inside the asynchronous lifetime of the MQTT connection, they need
+        * to live on the heap.
+        *
+        * Notice these allocations at h->u.mqtt.heap_baggage belong to the
+        * underlying MQTT stream lifetime, not the logical SS lifetime, and
+        * are destroyed if present at connection error or close of the
+        * underlying connection.
+        *
+        *
+        * First, compute the length of each without producing strsubst output,
+        * and keep a running total.
+        */
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(sources); n++) {
+               if (!sources[n])
+                       continue;
+
+               lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata,
+                               NULL, (size_t)-1);
+               if (lws_strexp_expand(&exp, sources[n], strlen(sources[n]),
+                                     &used_in, &olen[n]) != LSTRX_DONE) {
+                       lwsl_err("%s: failed to subsitute %s\n", __func__,
+                                       sources[n]);
+                       return 1;
+               }
+               tot += olen[n] + 1;
+       }
+
+       /*
+        * Then, allocate enough space on the heap for the total of the
+        * substituted results
+        */
+
+       h->u.mqtt.heap_baggage = lws_malloc(tot, __func__);
+       if (!h->u.mqtt.heap_baggage)
+               return 1;
+
+       /*
+        * Finally, issue the subsitutions one after the other into the single
+        * allocated result buffer and prepare pointers into them
+        */
+
+       p = h->u.mqtt.heap_baggage;
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(sources); n++) {
+               lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata,
+                               (char *)p, (size_t)-1);
+               if (!sources[n]) {
+                       ps[n] = NULL;
+                       continue;
+               }
+               ps[n] = (char *)p;
+               if (lws_strexp_expand(&exp, sources[n], strlen(sources[n]),
+                                     &used_in, &olen[n]) != LSTRX_DONE)
+                       return 1;
+
+               p += olen[n] + 1;
+       }
+
+       /*
+        * Point the guys who want the substituted content at the substituted
+        * strings
+        */
+
+       ct->ccp.will_param.topic        = ps[SSCMM_STRSUB_WILL_TOPIC];
+       ct->ccp.will_param.message      = ps[SSCMM_STRSUB_WILL_MESSAGE];
+       h->u.mqtt.subscribe_to          = ps[SSCMM_STRSUB_SUBSCRIBE];
+       h->u.mqtt.subscribe_to_len      = olen[SSCMM_STRSUB_SUBSCRIBE];
+       h->u.mqtt.topic_qos.name        = ps[SSCMM_STRSUB_TOPIC];
+       ct->ccp.birth_param.topic       = ps[SSCMM_STRSUB_BIRTH_TOPIC];
+       ct->ccp.birth_param.message     = ps[SSCMM_STRSUB_BIRTH_MESSAGE];
+
+       i->method = "MQTT";
+       i->mqtt_cp = &ct->ccp;
+
+       i->alpn = "x-amzn-mqtt-ca";
+
+       /* share connections where possible */
+       i->ssl_connection |= LCCSCF_PIPELINE;
+
+       return 0;
+}
+
+const struct ss_pcols ss_pcol_mqtt = {
+       "MQTT",
+       "x-amzn-mqtt-ca", //"mqtt/3.1.1",
+       &protocol_secstream_mqtt,
+       secstream_connect_munge_mqtt,
+       NULL, NULL
+};
diff --git a/lib/secure-streams/protocols/ss-raw.c b/lib/secure-streams/protocols/ss-raw.c
new file mode 100644 (file)
index 0000000..76b11ea
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * This is the glue that wires up raw-socket to Secure Streams.
+ */
+
+#include <private-lib-core.h>
+
+int
+secstream_raw(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+             void *in, size_t len)
+{
+#if defined(LWS_WITH_SERVER)
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+#endif
+       lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+       uint8_t buf[LWS_PRE + 1520], *p = &buf[LWS_PRE],
+               *end = &buf[sizeof(buf) - 1];
+       lws_ss_state_return_t r;
+       size_t buflen;
+       int f = 0;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               assert(h);
+               assert(h->policy);
+               lwsl_info("%s: %s, %s CLIENT_CONNECTION_ERROR: %s\n", __func__,
+                         lws_ss_tag(h), h->policy->streamtype, in ? (char *)in : "(null)");
+
+#if defined(LWS_WITH_CONMON)
+               lws_conmon_ss_json(h);
+#endif
+
+               r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
+               if (r == LWSSSSRET_DESTROY_ME)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               h->wsi = NULL;
+               r = lws_ss_backoff(h);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               break;
+
+       case LWS_CALLBACK_RAW_CLOSE:
+               if (!h)
+                       break;
+               lws_sul_cancel(&h->sul_timeout);
+
+#if defined(LWS_WITH_CONMON)
+               lws_conmon_ss_json(h);
+#endif
+
+               lwsl_info("%s: %s, %s RAW_CLOSE\n", __func__, lws_ss_tag(h),
+                         h->policy ? h->policy->streamtype : "no policy");
+               h->wsi = NULL;
+#if defined(LWS_WITH_SERVER)
+               lws_pt_lock(pt, __func__);
+               lws_dll2_remove(&h->cli_list);
+               lws_pt_unlock(pt);
+#endif
+
+               /* wsi is going down anyway */
+               r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
+               if (r == LWSSSSRET_DESTROY_ME)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               if (h->policy && !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
+#if defined(LWS_WITH_SERVER)
+                           !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
+#endif
+                   !h->txn_ok && !wsi->a.context->being_destroyed) {
+                       r = lws_ss_backoff(h);
+                       if (r != LWSSSSRET_OK)
+                               return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+                       break;
+               }
+
+               break;
+
+       case LWS_CALLBACK_RAW_CONNECTED:
+               lwsl_info("%s: RAW_CONNECTED\n", __func__);
+
+               h->retry = 0;
+               h->seqstate = SSSEQ_CONNECTED;
+               lws_sul_cancel(&h->sul);
+#if defined(LWS_WITH_SYS_METRICS)
+               /*
+                * If any hanging caliper measurement, dump it, and free any tags
+                */
+               lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+               r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               lws_validity_confirmed(wsi);
+               break;
+
+       case LWS_CALLBACK_RAW_ADOPT:
+               lwsl_info("%s: RAW_ADOPT\n", __func__);
+               break;
+
+       /* chunks of chunked content, with header removed */
+       case LWS_CALLBACK_RAW_RX:
+               if (!h || !h->info.rx)
+                       return 0;
+
+               r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, 0);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_RAW_WRITEABLE:
+               lwsl_info("%s: RAW_WRITEABLE\n", __func__);
+               if (!h || !h->info.tx)
+                       return 0;
+
+               buflen = lws_ptr_diff_size_t(end, p);
+               r = h->info.tx(ss_to_userobj(h),  h->txord++, p, &buflen, &f);
+               if (r == LWSSSSRET_TX_DONT_SEND)
+                       return 0;
+               if (r < 0)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               /*
+                * flags are ignored with raw, there are no protocol payload
+                * boundaries, just an arbitrarily-fragmented bytestream
+                */
+
+               p += buflen;
+               if (lws_write(wsi, buf + LWS_PRE, lws_ptr_diff_size_t(p, buf + LWS_PRE),
+                        LWS_WRITE_HTTP) != lws_ptr_diff(p, buf + LWS_PRE)) {
+                       lwsl_err("%s: write failed\n", __func__);
+                       return -1;
+               }
+
+               lws_set_timeout(wsi, 0, 0);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int
+secstream_connect_munge_raw(lws_ss_handle_t *h, char *buf, size_t len,
+                          struct lws_client_connect_info *i,
+                          union lws_ss_contemp *ct)
+{
+       i->method = "RAW";
+
+       return 0;
+}
+
+
+const struct lws_protocols protocol_secstream_raw = {
+       "lws-secstream-raw",
+       secstream_raw,
+       0,
+       0,
+       0, NULL, 0
+};
+
+const struct ss_pcols ss_pcol_raw = {
+       "raw",
+       "",
+       &protocol_secstream_raw,
+       secstream_connect_munge_raw,
+       NULL, NULL
+};
diff --git a/lib/secure-streams/protocols/ss-ws.c b/lib/secure-streams/protocols/ss-ws.c
new file mode 100644 (file)
index 0000000..eed62c5
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+static int
+secstream_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+            void *in, size_t len)
+{
+#if defined(LWS_WITH_SERVER)
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+#endif
+       lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
+       uint8_t buf[LWS_PRE + 1400];
+       lws_ss_state_return_t r;
+       int f = 0, f1, n;
+       size_t buflen;
+
+       switch (reason) {
+
+       /* because we are protocols[0] ... */
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_info("%s: CLIENT_CONNECTION_ERROR: %s\n", __func__,
+                        in ? (char *)in : "(null)");
+               if (!h)
+                       break;
+
+#if defined(LWS_WITH_CONMON)
+               lws_conmon_ss_json(h);
+#endif
+
+               r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
+               if (r == LWSSSSRET_DESTROY_ME)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               h->wsi = NULL;
+               r = lws_ss_backoff(h);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               break;
+
+       case LWS_CALLBACK_CLOSED: /* server */
+       case LWS_CALLBACK_CLIENT_CLOSED:
+               if (!h)
+                       break;
+               lws_sul_cancel(&h->sul_timeout);
+
+#if defined(LWS_WITH_CONMON)
+               lws_conmon_ss_json(h);
+#endif
+
+               r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
+               if (r == LWSSSSRET_DESTROY_ME)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               if (h->wsi)
+                       lws_set_opaque_user_data(h->wsi, NULL);
+               h->wsi = NULL;
+
+#if defined(LWS_WITH_SERVER)
+               lws_pt_lock(pt, __func__);
+               lws_dll2_remove(&h->cli_list);
+               lws_pt_unlock(pt);
+#endif
+
+               if (reason == LWS_CALLBACK_CLIENT_CLOSED) {
+                       if (h->policy &&
+                           !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
+#if defined(LWS_WITH_SERVER)
+                           !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
+#endif
+                           !wsi->a.context->being_destroyed) {
+                               r = lws_ss_backoff(h);
+                               if (r != LWSSSSRET_OK)
+                                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+                               break;
+                       }
+
+#if defined(LWS_WITH_SERVER)
+                       if (h->info.flags & LWSSSINFLAGS_ACCEPTED) {
+                               /*
+                                * was an accepted client connection to
+                                * our server, so the stream is over now
+                                */
+                               lws_ss_destroy(&h);
+                               return 0;
+                       }
+#endif
+
+               }
+               break;
+
+       case LWS_CALLBACK_ESTABLISHED:
+       case LWS_CALLBACK_CLIENT_ESTABLISHED:
+               h->retry = 0;
+               h->seqstate = SSSEQ_CONNECTED;
+               lws_sul_cancel(&h->sul);
+#if defined(LWS_WITH_SYS_METRICS)
+               /*
+                * If any hanging caliper measurement, dump it, and free any tags
+                */
+               lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+               r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+               break;
+
+       case LWS_CALLBACK_RECEIVE:
+       case LWS_CALLBACK_CLIENT_RECEIVE:
+               // lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE: read %d\n", (int)len);
+               if (!h || !h->info.rx)
+                       return 0;
+               if (lws_is_first_fragment(wsi))
+                       f |= LWSSS_FLAG_SOM;
+               if (lws_is_final_fragment(wsi))
+                       f |= LWSSS_FLAG_EOM;
+               // lws_frame_is_binary(wsi);
+
+               h->subseq = 1;
+
+               r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, f);
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_SERVER_WRITEABLE:
+       case LWS_CALLBACK_CLIENT_WRITEABLE:
+               // lwsl_notice("%s: %s: WRITEABLE\n", __func__, lws_ss_tag(h));
+               if (!h || !h->info.tx)
+                       return 0;
+
+               if (h->seqstate != SSSEQ_CONNECTED) {
+                       lwsl_warn("%s: seqstate %d\n", __func__, h->seqstate);
+                       break;
+               }
+
+               buflen = sizeof(buf) - LWS_PRE;
+               r = h->info.tx(ss_to_userobj(h),  h->txord++, buf + LWS_PRE,
+                                 &buflen, &f);
+               if (r == LWSSSSRET_TX_DONT_SEND)
+                       return 0;
+               if (r != LWSSSSRET_OK)
+                       return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
+
+               f1 = lws_write_ws_flags(h->policy->u.http.u.ws.binary ?
+                                          LWS_WRITE_BINARY : LWS_WRITE_TEXT,
+                                       !!(f & LWSSS_FLAG_SOM),
+                                       !!(f & LWSSS_FLAG_EOM));
+
+               n = lws_write(wsi, buf + LWS_PRE, buflen, (enum lws_write_protocol)f1);
+               if (n < (int)buflen) {
+                       lwsl_info("%s: write failed %d %d\n", __func__,
+                                       n, (int)buflen);
+
+                       return -1;
+               }
+
+               return 0;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+const struct lws_protocols protocol_secstream_ws = {
+       "lws-secstream-ws",
+       secstream_ws,
+       0, 0, 0, NULL, 0
+};
+/*
+ * Munge connect info according to protocol-specific considerations... this
+ * usually means interpreting aux in a protocol-specific way and using the
+ * pieces at connection setup time, eg, http url pieces.
+ *
+ * len bytes of buf can be used for things with scope until after the actual
+ * connect.
+ *
+ * For ws, protocol aux is <url path>;<ws subprotocol name>
+ */
+
+static int
+secstream_connect_munge_ws(lws_ss_handle_t *h, char *buf, size_t len,
+                          struct lws_client_connect_info *i,
+                          union lws_ss_contemp *ct)
+{
+       const char *pbasis = h->policy->u.http.url;
+       size_t used_in, used_out;
+       lws_strexp_t exp;
+
+       /* i.path on entry is used to override the policy urlpath if not "" */
+
+       if (i->path[0])
+               pbasis = i->path;
+
+       if (!pbasis)
+               return 0;
+
+       if (h->policy->flags & LWSSSPOLF_HTTP_CACHE_COOKIES)
+               i->ssl_connection |= LCCSCF_CACHE_COOKIES;
+
+       if (h->policy->flags & LWSSSPOLF_PRIORITIZE_READS)
+               i->ssl_connection |= LCCSCF_PRIORITIZE_READS;
+
+       /* protocol aux is the path part ; ws subprotocol name */
+
+       i->path = buf;
+       buf[0] = '/';
+
+       lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1);
+
+       if (lws_strexp_expand(&exp, pbasis, strlen(pbasis),
+                             &used_in, &used_out) != LSTRX_DONE)
+               return 1;
+
+       i->protocol = h->policy->u.http.u.ws.subprotocol;
+
+       lwsl_ss_info(h, "url %s, ws subprotocol %s", buf, i->protocol);
+
+       return 0;
+}
+
+const struct ss_pcols ss_pcol_ws = {
+       "ws",  "http/1.1",  &protocol_secstream_ws, secstream_connect_munge_ws, 0, 0
+};
diff --git a/lib/secure-streams/secure-streams-client.c b/lib/secure-streams/secure-streams-client.c
new file mode 100644 (file)
index 0000000..76ea952
--- /dev/null
@@ -0,0 +1,1109 @@
+/*
+ * lws-minimal-secure-streams-client
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This client does not perform any INET networking... instead it opens a unix
+ * domain socket on a proxy that is listening for it, and that creates the
+ * actual secure stream connection.
+ *
+ * We are able to use the usual secure streams api in the client process, with
+ * payloads and connection state information proxied over the unix domain
+ * socket and fulfilled in the proxy process.
+ *
+ * The public client helper pieces are built as part of lws
+ */
+#include <private-lib-core.h>
+
+extern const uint32_t ss_state_txn_validity[17];
+
+int
+lws_ss_check_next_state_sspc(lws_sspc_handle_t *ss, uint8_t *prevstate,
+                            lws_ss_constate_t cs)
+{
+       if (cs >= LWSSSCS_USER_BASE || cs == LWSSSCS_EVENT_WAIT_CANCELLED)
+               /*
+                * we can't judge user or transient states, leave the old state
+                * and just wave them through
+                */
+               return 0;
+
+       if (cs >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
+               /* we don't recognize this state as usable */
+               lwsl_sspc_err(ss, "bad new state %u", cs);
+               assert(0);
+               return 1;
+       }
+
+       if (*prevstate >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
+               /* existing state is broken */
+               lwsl_sspc_err(ss, "bad existing state %u",
+                               (unsigned int)*prevstate);
+               assert(0);
+               return 1;
+       }
+
+       if (ss_state_txn_validity[*prevstate] & (1u << cs)) {
+
+               lwsl_sspc_notice(ss, "%s -> %s",
+                              lws_ss_state_name((int)*prevstate),
+                              lws_ss_state_name((int)cs));
+
+               /* this is explicitly allowed, update old state to new */
+               *prevstate = (uint8_t)cs;
+
+               return 0;
+       }
+
+       lwsl_sspc_err(ss, "transition from %s -> %s is illegal",
+                   lws_ss_state_name((int)*prevstate),
+                   lws_ss_state_name((int)cs));
+
+       assert(0);
+
+       return 1;
+}
+
+lws_ss_state_return_t
+lws_sspc_event_helper(lws_sspc_handle_t *h, lws_ss_constate_t cs,
+                     lws_ss_tx_ordinal_t flags)
+{
+       lws_ss_state_return_t ret;
+
+       if (!h)
+               return LWSSSSRET_OK;
+
+       if (lws_ss_check_next_state_sspc(h, &h->prev_ss_state, cs))
+               return LWSSSSRET_DESTROY_ME;
+
+       if (!h->ssi.state)
+               return LWSSSSRET_OK;
+
+       h->h_in_svc = h;
+       ret = h->ssi.state((void *)((uint8_t *)&h[1]), NULL, cs, flags);
+       h->h_in_svc = NULL;
+
+       return ret;
+}
+
+static void
+lws_sspc_sul_retry_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_sspc_handle_t *h = lws_container_of(sul, lws_sspc_handle_t, sul_retry);
+       static struct lws_client_connect_info i;
+
+       /*
+        * We may have started up before the system proxy, so be prepared with
+        * a sul to retry at 1Hz
+        */
+
+       memset(&i, 0, sizeof i);
+       i.context = h->context;
+       if (h->context->ss_proxy_port) { /* tcp */
+               i.address = h->context->ss_proxy_address;
+               i.port = h->context->ss_proxy_port;
+               i.iface = h->context->ss_proxy_bind;
+       } else {
+               if (h->context->ss_proxy_bind)
+                       i.address = h->context->ss_proxy_bind;
+               else
+#if defined(__linux__)
+                       i.address = "+@proxy.ss.lws";
+#else
+                       i.address = "+/tmp/proxy.ss.lws";
+#endif
+       }
+       i.host = i.address;
+       i.origin = i.address;
+       i.method = "RAW";
+       i.protocol = lws_sspc_protocols[0].name;
+       i.local_protocol_name = lws_sspc_protocols[0].name;
+       i.path = "";
+       i.pwsi = &h->cwsi;
+       i.opaque_user_data = (void *)h;
+       i.ssl_connection = LCCSCF_SECSTREAM_PROXY_LINK;
+
+       lws_metrics_caliper_bind(h->cal_txn, h->context->mt_ss_cliprox_conn);
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_metrics_tag_add(&h->cal_txn.mtags_owner, "ss", h->ssi.streamtype);
+#endif
+
+       /* this wsi is the link to the proxy */
+
+       if (!lws_client_connect_via_info(&i)) {
+
+#if defined(LWS_WITH_SYS_METRICS)
+               /*
+                * If any hanging caliper measurement, dump it, and free any tags
+                */
+               lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+
+               lws_sul_schedule(h->context, 0, &h->sul_retry,
+                                lws_sspc_sul_retry_cb, LWS_US_PER_SEC);
+
+               return;
+       }
+
+       lwsl_sspc_notice(h, "%s", h->cwsi->lc.gutag);
+}
+
+static int
+lws_sspc_serialize_metadata(lws_sspc_handle_t *h, lws_sspc_metadata_t *md,
+                               uint8_t *p, uint8_t *end)
+{
+       int n, txc;
+
+       if (md->name[0] == '\0') {
+
+               lwsl_info("sending tx credit update %d\n",
+                               md->tx_cr_adjust);
+
+               p[0] = LWSSS_SER_TXPRE_TXCR_UPDATE;
+               lws_ser_wu16be(&p[1], 4);
+               lws_ser_wu32be(&p[3], (uint32_t)md->tx_cr_adjust);
+
+               n = 7;
+
+       } else {
+
+               lwsl_sspc_info(h, "sending metadata");
+
+               p[0] = LWSSS_SER_TXPRE_METADATA;
+               txc = (int)strlen(md->name);
+               n = txc + 1 + (int)md->len;
+               if (n > 0xffff)
+                       /* we can't serialize this metadata in 16b length */
+                       return -1;
+               if (n > lws_ptr_diff(end, &p[4]))
+                       /* we don't have space for this metadata */
+                       return -1;
+               lws_ser_wu16be(&p[1], (uint16_t)n);
+               p[3] = (uint8_t)txc;
+               memcpy(&p[4], md->name, (unsigned int)txc);
+               memcpy(&p[4 + txc], &md[1], md->len);
+               n = 4 + txc + (int)md->len;
+       }
+
+       lws_dll2_remove(&md->list);
+       lws_free(md);
+
+       return n;
+}
+
+static int
+callback_sspc_client(struct lws *wsi, enum lws_callback_reasons reason,
+                    void *user, void *in, size_t len)
+{
+       lws_sspc_handle_t *h = (lws_sspc_handle_t *)lws_get_opaque_user_data(wsi);
+       size_t pktsize = wsi->a.context->max_http_header_data;
+       void *m = (void *)((uint8_t *)&h[1]);
+       uint8_t *pkt = NULL, *p = NULL, *end = NULL;
+       lws_ss_state_return_t r;
+       uint64_t interval;
+       const uint8_t *cp;
+       uint8_t s[64];
+       lws_usec_t us;
+       int flags, n;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_CONNECTING:
+               /*
+                * In our particular case, we want CCEs even inside the
+                * initial connect loop time
+                */
+               wsi->client_suppress_CONNECTION_ERROR = 0;
+               break;
+
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_warn("%s: CCE: %s\n", __func__,
+                         in ? (const char *)in : "null");
+#if defined(LWS_WITH_SYS_METRICS)
+               /*
+                * If any hanging caliper measurement, dump it, and free any tags
+                */
+               lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+               lws_set_opaque_user_data(wsi, NULL);
+               h->cwsi = NULL;
+               lws_sul_schedule(h->context, 0, &h->sul_retry,
+                                lws_sspc_sul_retry_cb, LWS_US_PER_SEC);
+               if (h->ssi.state) {
+                       interval = (uint64_t)(lws_now_usecs() - h->us_start_upstream) /
+                                                               LWS_US_PER_MS;
+                       if (interval > 0xffffffffull)
+                               interval = 0xffffffffull;
+                       r = h->ssi.state(lws_sspc_to_user_object(h), NULL,
+                                         LWSSSCS_UPSTREAM_LINK_RETRY,
+                                         (uint32_t)interval);
+                       if (r == LWSSSSRET_DESTROY_ME)
+                               lws_sspc_destroy(&h);
+               }
+               break;
+
+        case LWS_CALLBACK_RAW_CONNECTED:
+               if (!h || lws_fi(&h->fic, "sspc_fail_on_linkup"))
+                       return -1;
+               lwsl_sspc_info(h, "CONNECTED (%s)", h->ssi.streamtype);
+
+               h->state = LPCSCLI_SENDING_INITIAL_TX;
+               /*
+                * We create the dsh at the response to the initial tx, which
+                * will let us know the policy's max size for it... let's
+                * protect the connection with a promise to complete the
+                * SS serialization streamtype negotation within a short period,
+                * we will cancel this timeout when we have the proxy's ack
+                * of the streamtype serialization, eg, it exists in the proxy
+                * policy etc
+                */
+               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, 3);
+               lws_callback_on_writable(wsi);
+               h->us_start_upstream = 0;
+                break;
+
+       case LWS_CALLBACK_RAW_CLOSE:
+               /*
+                * our ss proxy Unix Domain socket has closed...
+                */
+               if (!h) {
+                       lwsl_info("%s: no sspc on client proxy link close", __func__);
+                       break;
+               }
+               lwsl_sspc_info(h, "LWS_CALLBACK_RAW_CLOSE: proxy conn down, wsi %s",
+                               lws_wsi_tag(wsi));
+
+               lws_dsh_destroy(&h->dsh);
+               if (h->ss_dangling_connected && h->ssi.state) {
+
+                       lwsl_sspc_notice(h, "setting _DISCONNECTED");
+                       h->ss_dangling_connected = 0;
+                       h->prev_ss_state = LWSSSCS_DISCONNECTED;
+                       r = h->ssi.state(ss_to_userobj(h), NULL,
+                                                LWSSSCS_DISCONNECTED, 0);
+                       if (r == LWSSSSRET_DESTROY_ME) {
+                               h->cwsi = NULL;
+                               lws_set_opaque_user_data(wsi, NULL);
+                               lws_sspc_destroy(&h);
+                               break;
+                       }
+               }
+
+               h->cwsi = NULL;
+               /*
+                * schedule a reconnect in 1s
+                */
+               lws_sul_schedule(h->context, 0, &h->sul_retry,
+                                lws_sspc_sul_retry_cb, LWS_US_PER_SEC);
+
+               break;
+
+       case LWS_CALLBACK_RAW_RX:
+               /*
+                * ie, the proxy has sent us something
+                */
+
+               if (!h || !h->cwsi) {
+                       lwsl_info("%s: rx when client ss destroyed\n", __func__);
+
+                       return -1;
+               }
+
+               lwsl_sspc_info(h, "%s: RAW_RX: rx %d\n", __func__, (int)len);
+
+               if (!len) {
+                       lwsl_sspc_notice(h, "RAW_RX: zero len");
+
+                       return -1;
+               }
+
+               if (lws_fi(&h->fic, "sspc_fake_rxparse_disconnect_me"))
+                       n = LWSSSSRET_DISCONNECT_ME;
+               else
+                       if (lws_fi(&h->fic, "sspc_fake_rxparse_destroy_me"))
+                               n = LWSSSSRET_DESTROY_ME;
+                       else
+                               n = lws_ss_deserialize_parse(&h->parser,
+                                                            lws_get_context(wsi),
+                                                            h->dsh, in, len,
+                                                            &h->state, h,
+                                                            (lws_ss_handle_t **)m,
+                                                            &h->ssi, 1);
+               switch (n) {
+               case LWSSSSRET_OK:
+                       break;
+               case LWSSSSRET_DISCONNECT_ME:
+                       lwsl_info("%s: proxlicent RX ended with DISCONNECT_ME\n",
+                                       __func__);
+                       return -1;
+               case LWSSSSRET_DESTROY_ME:
+                       lwsl_info("%s: proxlicent RX ended with DESTROY_ME\n",
+                                       __func__);
+                       lws_set_opaque_user_data(wsi, NULL);
+                       lws_sspc_destroy(&h);
+                       return -1;
+               }
+
+               if (h->state == LPCSCLI_LOCAL_CONNECTED ||
+                   h->state == LPCSCLI_ONWARD_CONNECT)
+                       lws_set_timeout(wsi, 0, 0);
+
+               break;
+
+       case LWS_CALLBACK_RAW_WRITEABLE:
+
+               /*
+                * We can transmit something to the proxy...
+                */
+
+               if (!h)
+                       break;
+
+               lwsl_sspc_debug(h, "WRITEABLE %s, state %d",
+                               wsi->lc.gutag, h->state);
+
+               /*
+                * Management of ss timeout can happen any time and doesn't
+                * depend on wsi existence or state
+                */
+
+               n = 0;
+               cp = s;
+
+               if (h->pending_timeout_update) {
+                       s[0] = LWSSS_SER_TXPRE_TIMEOUT_UPDATE;
+                       s[1] = 0;
+                       s[2] = 4;
+                       /*
+                        *          0: use policy timeout value
+                        * 0xffffffff: cancel the timeout
+                        */
+                       lws_ser_wu32be(&s[3], h->timeout_ms);
+                       /* in case anything else to write */
+                       lws_callback_on_writable(h->cwsi);
+                       h->pending_timeout_update = 0;
+                       n = 7;
+                       goto do_write;
+               }
+
+               s[1] = 0;
+               /*
+                * This is the state of the link that connects us to the onward
+                * proxy
+                */
+               switch (h->state) {
+               case LPCSCLI_SENDING_INITIAL_TX:
+                       /*
+                        * We are negotating the opening of a particular
+                        * streamtype
+                        */
+                       n = (int)strlen(h->ssi.streamtype) + 1 + 4 + 4;
+
+                       s[0] = LWSSS_SER_TXPRE_STREAMTYPE;
+                       lws_ser_wu16be(&s[1], (uint16_t)n);
+                       /* SSSv1: add protocol version byte (initially 1) */
+                       s[3] = (uint8_t)LWS_SSS_CLIENT_PROTOCOL_VERSION;
+                       lws_ser_wu32be(&s[4], (uint32_t)getpid());
+                       lws_ser_wu32be(&s[8], (uint32_t)h->txc.peer_tx_cr_est);
+                       //h->txcr_out = txc;
+                       lws_strncpy((char *)&s[12], h->ssi.streamtype, sizeof(s) - 12);
+                       n += 3;
+                       h->state = LPCSCLI_WAITING_CREATE_RESULT;
+
+                       break;
+
+               case LPCSCLI_LOCAL_CONNECTED:
+
+                       // lwsl_notice("%s: LPCSCLI_LOCAL_CONNECTED\n", __func__);
+
+                       /*
+                        * Do we need to prioritize sending any metadata
+                        * changes?
+                        */
+
+                       if (h->metadata_owner.count) {
+                               lws_sspc_metadata_t *md = lws_container_of(
+                                       lws_dll2_get_tail(&h->metadata_owner),
+                                       lws_sspc_metadata_t, list);
+
+                               pkt = lws_malloc(pktsize + LWS_PRE, __func__);
+                               if (!pkt)
+                                       goto hangup;
+                               cp = p = pkt + LWS_PRE;
+                               end = p + pktsize;
+
+                               n = lws_sspc_serialize_metadata(h, md, p, end);
+                               if (n < 0)
+                                       goto metadata_hangup;
+
+                               lwsl_sspc_debug(h, "(local_conn) metadata");
+
+                               goto req_write_and_issue;
+                       }
+
+                       if (h->pending_writeable_len) {
+                               lwsl_sspc_debug(h, "(local_conn) PAYLOAD_LENGTH_HINT %u",
+                                          (unsigned int)h->writeable_len);
+                               s[0] = LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT;
+                               lws_ser_wu16be(&s[1], 4);
+                               lws_ser_wu32be(&s[3], (uint32_t)h->writeable_len);
+                               h->pending_writeable_len = 0;
+                               n = 7;
+                               goto req_write_and_issue;
+                       }
+
+                       if (h->conn_req_state >= LWSSSPC_ONW_ONGOING) {
+                               lwsl_sspc_info(h, "conn_req_state %d",
+                                               h->conn_req_state);
+                               break;
+                       }
+
+                       lwsl_sspc_info(h, "(local_conn) onward connect");
+
+                       h->conn_req_state = LWSSSPC_ONW_ONGOING;
+
+                       s[0] = LWSSS_SER_TXPRE_ONWARD_CONNECT;
+                       s[1] = 0;
+                       s[2] = 0;
+                       n = 3;
+                       break;
+
+               case LPCSCLI_OPERATIONAL:
+
+                       /*
+                        *
+                        * - Do we need to prioritize sending any metadata
+                        *   changes?  (includes txcr updates)
+                        *
+                        * - Do we need to forward a hint about the payload
+                        *   length?
+                        */
+
+                       pkt = lws_malloc(pktsize + LWS_PRE, __func__);
+                       if (!pkt)
+                               goto hangup;
+                       cp = p = pkt + LWS_PRE;
+                       end = p + pktsize;
+
+                       if (h->metadata_owner.count) {
+                               lws_sspc_metadata_t *md = lws_container_of(
+                                       lws_dll2_get_tail(&h->metadata_owner),
+                                       lws_sspc_metadata_t, list);
+
+                               n = lws_sspc_serialize_metadata(h, md, p, end);
+                               if (n < 0)
+                                       goto metadata_hangup;
+
+                               goto req_write_and_issue;
+                       }
+
+                       if (h->pending_writeable_len) {
+                               lwsl_sspc_info(h, "PAYLOAD_LENGTH_HINT %u",
+                                         (unsigned int)h->writeable_len);
+                               s[0] = LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT;
+                               lws_ser_wu16be(&s[1], 4);
+                               lws_ser_wu32be(&s[3], (uint32_t)h->writeable_len);
+                               h->pending_writeable_len = 0;
+                               n = 7;
+                               goto req_write_and_issue;
+                       }
+
+                       /* we can't write anything if we don't have credit */
+                       if (!h->ignore_txc && h->txc.tx_cr <= 0) {
+                               lwsl_sspc_info(h, "WRITEABLE / OPERATIONAL:"
+                                           " lack credit (%d)",
+                                           h->txc.tx_cr);
+                               // break;
+                       }
+
+                       len = pktsize - LWS_PRE - 19;
+                       flags = 0;
+                       if (!h->ssi.tx) {
+                               n = 0;
+                               goto do_write_nz;
+                       }
+
+                       n = h->ssi.tx(m, h->ord++, pkt + LWS_PRE + 19, &len,
+                                     &flags);
+                       switch (n) {
+                       case LWSSSSRET_TX_DONT_SEND:
+                               n = 0;
+                               goto do_write_nz;
+       
+                       case LWSSSSRET_DISCONNECT_ME:
+                       case LWSSSSRET_DESTROY_ME:
+                               lwsl_notice("%s: sspc tx DISCONNECT/DESTROY unimplemented\n", __func__);
+                               break;
+                       default:
+                               break;
+                       }
+
+                       h->txc.tx_cr = h->txc.tx_cr - (int)len;
+
+                       cp = p;
+                       n = (int)(len + 19);
+                       us = lws_now_usecs();
+                       p[0] = LWSSS_SER_TXPRE_TX_PAYLOAD;
+                       lws_ser_wu16be(&p[1], (uint16_t)(len + 19 - 3));
+                       lws_ser_wu32be(&p[3], (uint32_t)flags);
+                       /* time spent here waiting to send this */
+                       lws_ser_wu32be(&p[7], (uint32_t)(us - h->us_earliest_write_req));
+                       /* ust that the client write happened */
+                       lws_ser_wu64be(&p[11], (uint64_t)us);
+                       h->us_earliest_write_req = 0;
+
+                       if (flags & LWSSS_FLAG_EOM)
+                               if (h->rsidx + 1 < (int)LWS_ARRAY_SIZE(h->rideshare_ofs) &&
+                                   h->rideshare_ofs[h->rsidx + 1])
+                                       h->rsidx++;
+
+                       break;
+               default:
+                       break;
+               }
+
+do_write_nz:
+
+               if (!n)
+                       break;
+
+do_write:
+               if (lws_fi(&h->fic, "sspc_link_write_fail"))
+                       n = -1;
+               else
+                       n = lws_write(wsi, (uint8_t *)cp, (unsigned int)n, LWS_WRITE_RAW);
+               if (n < 0) {
+                       lwsl_sspc_notice(h, "WRITEABLE: %d", n);
+
+                       goto hangup;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       lws_free(pkt);
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+
+metadata_hangup:
+       lwsl_sspc_err(h, "metadata too large");
+
+hangup:
+       lws_free(pkt);
+       lwsl_warn("hangup\n");
+       /* hang up on him */
+       return -1;
+
+req_write_and_issue:
+       /* in case anything else to write */
+       lws_callback_on_writable(h->cwsi);
+       goto do_write_nz;
+}
+
+const struct lws_protocols lws_sspc_protocols[] = {
+       {
+               "ssproxy-protocol",
+               callback_sspc_client,
+               0,
+               2048, 2048, NULL, 0
+       },
+       { NULL, NULL, 0, 0, 0, NULL, 0 }
+};
+
+int
+lws_sspc_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
+               void *opaque_user_data, lws_sspc_handle_t **ppss,
+               struct lws_sequencer *seq_owner, const char **ppayload_fmt)
+{
+       lws_sspc_handle_t *h;
+       uint8_t *ua;
+       char *p;
+
+       lws_service_assert_loop_thread(context, tsi);
+
+       /* allocate the handle (including ssi), the user alloc,
+        * and the streamname */
+
+       h = malloc(sizeof(lws_sspc_handle_t) + ssi->user_alloc +
+                               strlen(ssi->streamtype) + 1);
+       if (!h)
+               return 1;
+       memset(h, 0, sizeof(*h));
+
+       h->lc.log_cx = context->log_cx;
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       h->fic.name = "sspc";
+       lws_xos_init(&h->fic.xos, lws_xos(&context->fic.xos));
+       if (ssi->fic.fi_owner.count)
+               lws_fi_import(&h->fic, &ssi->fic);
+
+       lws_fi_inherit_copy(&h->fic, &context->fic, "ss", ssi->streamtype);
+#endif
+
+       if (lws_fi(&h->fic, "sspc_create_oom")) {
+               /*
+                * We have to do this a litte later, so we can cleanly inherit
+                * the OOM pieces and drain the info fic
+                */
+               lws_fi_destroy(&h->fic);
+               free(h);
+               return 1;
+       }
+
+       __lws_lc_tag(context, &context->lcg[LWSLCG_SSP_CLIENT], &h->lc,
+                       ssi->streamtype);
+
+       memcpy(&h->ssi, ssi, sizeof(*ssi));
+       ua = (uint8_t *)&h[1];
+       memset(ua, 0, ssi->user_alloc);
+       p = (char *)ua + ssi->user_alloc;
+       memcpy(p, ssi->streamtype, strlen(ssi->streamtype) + 1);
+       h->ssi.streamtype = (const char *)p;
+       h->context = context;
+       h->us_start_upstream = lws_now_usecs();
+
+       if (!ssi->manual_initial_tx_credit)
+               h->txc.peer_tx_cr_est = 500000000;
+       else
+               h->txc.peer_tx_cr_est = ssi->manual_initial_tx_credit;
+
+       if (!strcmp(ssi->streamtype, LWS_SMD_STREAMTYPENAME))
+               h->ignore_txc = 1;
+
+       lws_dll2_add_head(&h->client_list, &context->pt[tsi].ss_client_owner);
+
+       /* fill in the things the real api does for the caller */
+
+       *((void **)(ua + ssi->opaque_user_data_offset)) = opaque_user_data;
+       *((void **)(ua + ssi->handle_offset)) = h;
+
+       if (ppss)
+               *ppss = h;
+
+       /* try the actual connect */
+
+       lws_sspc_sul_retry_cb(&h->sul_retry);
+
+       return 0;
+}
+
+/* used on context destroy when iterating listed lws_ss on a pt */
+
+int
+lws_sspc_destroy_dll(struct lws_dll2 *d, void *user)
+{
+       lws_sspc_handle_t *h = lws_container_of(d, lws_sspc_handle_t, client_list);
+
+       lws_sspc_destroy(&h);
+
+       return 0;
+}
+
+void
+lws_sspc_rxmetadata_destroy(lws_sspc_handle_t *h)
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                       lws_dll2_get_head(&h->metadata_owner_rx)) {
+               lws_sspc_metadata_t *md =
+                               lws_container_of(d, lws_sspc_metadata_t, list);
+
+               lws_dll2_remove(&md->list);
+               lws_free(md);
+
+       } lws_end_foreach_dll_safe(d, d1);
+}
+
+void
+lws_sspc_destroy(lws_sspc_handle_t **ph)
+{
+       lws_sspc_handle_t *h;
+
+       if (!*ph)
+               return;
+
+       h = *ph;
+       if (h == h->h_in_svc) {
+               lwsl_err("%s: illegal destroy, return LWSSSSRET_DESTROY_ME instead\n",
+                               __func__);
+               assert(0);
+               return;
+       }
+
+       lws_service_assert_loop_thread(h->context, 0);
+
+       if (h->destroying)
+               return;
+
+       h->destroying = 1;
+
+       /* if this caliper is still dangling at destroy, we failed */
+#if defined(LWS_WITH_SYS_METRICS)
+       /*
+        * If any hanging caliper measurement, dump it, and free any tags
+        */
+       lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+       if (h->ss_dangling_connected && h->ssi.state) {
+               lws_sspc_event_helper(h, LWSSSCS_DISCONNECTED, 0);
+               h->ss_dangling_connected = 0;
+       }
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_destroy(&h->fic);
+#endif
+
+       lws_sul_cancel(&h->sul_retry);
+       lws_dll2_remove(&h->client_list);
+
+       if (h->dsh)
+               lws_dsh_destroy(&h->dsh);
+       if (h->cwsi) {
+               lws_set_opaque_user_data(h->cwsi, NULL);
+               lws_wsi_close(h->cwsi, LWS_TO_KILL_ASYNC);
+               h->cwsi = NULL;
+       }
+
+       /* clean out any pending metadata changes that didn't make it */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                       lws_dll2_get_head(&(*ph)->metadata_owner)) {
+               lws_sspc_metadata_t *md =
+                               lws_container_of(d, lws_sspc_metadata_t, list);
+
+               lws_dll2_remove(&md->list);
+               lws_free(md);
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       lws_sspc_rxmetadata_destroy(h);
+
+       lws_sspc_event_helper(h, LWSSSCS_DESTROYING, 0);
+       *ph = NULL;
+
+       lws_sul_cancel(&h->sul_retry);
+
+
+       /* confirm no sul left scheduled in handle or user allocation object */
+       lws_sul_debug_zombies(h->context, h, sizeof(*h) + h->ssi.user_alloc,
+                             __func__);
+
+       __lws_lc_untag(h->context, &h->lc);
+
+       free(h);
+}
+
+lws_ss_state_return_t
+lws_sspc_request_tx(lws_sspc_handle_t *h)
+{
+       if (!h || !h->cwsi)
+               return LWSSSSRET_OK;
+
+       lws_service_assert_loop_thread(h->context, 0);
+
+       if (!h->us_earliest_write_req)
+               h->us_earliest_write_req = lws_now_usecs();
+
+       if (h->state == LPCSCLI_LOCAL_CONNECTED &&
+           h->conn_req_state == LWSSSPC_ONW_NONE)
+               h->conn_req_state = LWSSSPC_ONW_REQ;
+
+       lws_callback_on_writable(h->cwsi);
+
+       return LWSSSSRET_OK;
+}
+
+/*
+ * Currently we fulfil the writeable part locally by just enabling POLLOUT on
+ * the UDS link, without serialization footprint, which is reasonable as far as
+ * it goes.
+ *
+ * But for the ..._len() variant, the expected payload length hint we are being
+ * told is something that must be serialized to the onward peer, since either
+ * that guy or someone upstream of him is the guy who will compose the framing
+ * with it that actually goes out.
+ *
+ * This information is needed at the upstream guy before we have sent any
+ * payload, eg, for http POST, he has to prepare the content-length in the
+ * headers, before any payload.  So we have to issue a serialization of the
+ * length at this point.
+ */
+
+lws_ss_state_return_t
+lws_sspc_request_tx_len(lws_sspc_handle_t *h, unsigned long len)
+{
+       /*
+        * for client conns, they cannot even complete creation of the handle
+        * without the onwared connection to the proxy, it's not legal to start
+        * using it until it's operation and has the onward connection (and the
+        * link has called CREATED state)
+        */
+
+       if (!h)
+               return LWSSSSRET_OK;
+
+       lws_service_assert_loop_thread(h->context, 0);
+
+       lwsl_sspc_notice(h, "setting writeable_len %u", (unsigned int)len);
+       h->writeable_len = len;
+       h->pending_writeable_len = 1;
+
+       if (!h->us_earliest_write_req)
+               h->us_earliest_write_req = lws_now_usecs();
+
+       if (h->state == LPCSCLI_LOCAL_CONNECTED &&
+           h->conn_req_state == LWSSSPC_ONW_NONE)
+               h->conn_req_state = LWSSSPC_ONW_REQ;
+
+       /*
+        * We're going to use this up with serializing h->writeable_len... that
+        * will request again.
+        */
+
+       if (h->cwsi)
+               lws_callback_on_writable(h->cwsi);
+
+       return LWSSSSRET_OK;
+}
+
+int
+lws_sspc_client_connect(lws_sspc_handle_t *h)
+{
+       if (!h || h->state == LPCSCLI_OPERATIONAL)
+               return 0;
+
+       lws_service_assert_loop_thread(h->context, 0);
+
+       assert(h->state == LPCSCLI_LOCAL_CONNECTED);
+       if (h->state == LPCSCLI_LOCAL_CONNECTED &&
+           h->conn_req_state == LWSSSPC_ONW_NONE)
+               h->conn_req_state = LWSSSPC_ONW_REQ;
+       if (h->cwsi)
+               lws_callback_on_writable(h->cwsi);
+
+       return 0;
+}
+
+struct lws_context *
+lws_sspc_get_context(struct lws_sspc_handle *h)
+{
+       return h->context;
+}
+
+const char *
+lws_sspc_rideshare(struct lws_sspc_handle *h)
+{
+       /*
+        * ...the serialized RX rideshare name if any...
+        */
+
+       if (h->parser.rideshare[0]) {
+               lwsl_sspc_info(h, "parser %s", h->parser.rideshare);
+
+               return h->parser.rideshare;
+       }
+
+       /*
+        * The tx rideshare index
+        */
+
+       if (h->rideshare_list[0]) {
+               lwsl_sspc_info(h, "tx list %s",
+                         &h->rideshare_list[h->rideshare_ofs[h->rsidx]]);
+               return &h->rideshare_list[h->rideshare_ofs[h->rsidx]];
+       }
+
+       /*
+        * ... otherwise default to our stream type name
+        */
+
+       lwsl_sspc_info(h, "def %s\n", h->ssi.streamtype);
+
+       return h->ssi.streamtype;
+}
+
+static int
+_lws_sspc_set_metadata(struct lws_sspc_handle *h, const char *name,
+                      const void *value, size_t len, int tx_cr_adjust)
+{
+       lws_sspc_metadata_t *md;
+
+       lws_service_assert_loop_thread(h->context, 0);
+
+       /*
+        * Are we replacing a pending metadata of the same name?  It's not
+        * efficient to do this but user code can do what it likes... let's
+        * optimize away the old one.
+        *
+        * Tx credit adjust always has name ""
+        */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  lws_dll2_get_head(&h->metadata_owner)) {
+               md = lws_container_of(d, lws_sspc_metadata_t, list);
+
+               if (!strcmp(name, md->name)) {
+                       lws_dll2_remove(&md->list);
+                       lws_free(md);
+                       break;
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       /*
+        * We have to stash the metadata and pass it to the proxy
+        */
+
+       if (lws_fi(&h->fic, "sspc_fail_metadata_set"))
+               md = NULL;
+       else
+               md = lws_malloc(sizeof(*md) + len, "set metadata");
+       if (!md) {
+               lwsl_sspc_err(h, "OOM");
+
+               return 1;
+       }
+
+       memset(md, 0, sizeof(*md));
+
+       md->tx_cr_adjust = tx_cr_adjust;
+       h->txc.peer_tx_cr_est += tx_cr_adjust;
+
+       lws_strncpy(md->name, name, sizeof(md->name));
+       md->len = len;
+       if (len)
+               memcpy(&md[1], value, len);
+
+       lws_dll2_add_tail(&md->list, &h->metadata_owner);
+
+       if (len) {
+               lwsl_sspc_info(h, "set metadata %s", name);
+               lwsl_hexdump_sspc_info(h, value, len);
+       } else
+               lwsl_sspc_info(h, "serializing tx cr adj %d",
+                           (int)tx_cr_adjust);
+
+       if (h->cwsi)
+               lws_callback_on_writable(h->cwsi);
+
+       return 0;
+}
+
+int
+lws_sspc_set_metadata(struct lws_sspc_handle *h, const char *name,
+                     const void *value, size_t len)
+{
+       return _lws_sspc_set_metadata(h, name, value, len, 0);
+}
+
+int
+lws_sspc_get_metadata(struct lws_sspc_handle *h, const char *name,
+                     const void **value, size_t *len)
+{
+       lws_sspc_metadata_t *md;
+
+       /*
+        * client side does not have access to policy
+        * and any metadata are new to it each time,
+        * we allocate them, removing any existing with
+        * the same name first
+        */
+
+       lws_service_assert_loop_thread(h->context, 0);
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                       lws_dll2_get_head(&h->metadata_owner_rx)) {
+               md = lws_container_of(d,
+                          lws_sspc_metadata_t, list);
+
+               if (!strcmp(md->name, name)) {
+                       *len = md->len;
+                       *value = &md[1];
+
+                       return 0;
+               }
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       return 1;
+}
+
+int
+lws_sspc_add_peer_tx_credit(struct lws_sspc_handle *h, int32_t bump)
+{
+       lws_service_assert_loop_thread(h->context, 0);
+       lwsl_sspc_notice(h, "%d\n", bump);
+       return _lws_sspc_set_metadata(h, "", NULL, 0, (int)bump);
+}
+
+int
+lws_sspc_get_est_peer_tx_credit(struct lws_sspc_handle *h)
+{
+       lws_service_assert_loop_thread(h->context, 0);
+       return h->txc.peer_tx_cr_est;
+}
+
+void
+lws_sspc_start_timeout(struct lws_sspc_handle *h, unsigned int timeout_ms)
+{
+       lws_service_assert_loop_thread(h->context, 0);
+       if (!h->cwsi)
+               /* we can't fulfil it */
+               return;
+       h->timeout_ms = (uint32_t)timeout_ms;
+       h->pending_timeout_update = 1;
+       lws_callback_on_writable(h->cwsi);
+}
+
+void
+lws_sspc_cancel_timeout(struct lws_sspc_handle *h)
+{
+       lws_sspc_start_timeout(h, (unsigned int)-1);
+}
+
+void *
+lws_sspc_to_user_object(struct lws_sspc_handle *h)
+{
+       return (void *)&h[1];
+}
+
+void
+lws_sspc_change_handlers(struct lws_sspc_handle *h,
+       lws_ss_state_return_t (*rx)(void *userobj, const uint8_t *buf, size_t len, int flags),
+       lws_ss_state_return_t (*tx)(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                 size_t *len, int *flags),
+       lws_ss_state_return_t (*state)(void *userobj, void *h_src /* ss handle type */,
+                    lws_ss_constate_t state, lws_ss_tx_ordinal_t ack))
+{
+       if (rx)
+               h->ssi.rx = rx;
+       if (tx)
+               h->ssi.tx = tx;
+       if (state)
+               h->ssi.state = state;
+}
+
+const char *
+lws_sspc_tag(struct lws_sspc_handle *h)
+{
+       if (!h)
+               return "[null sspc]";
+       return lws_lc_tag(&h->lc);
+}
+
+int
+lws_sspc_cancel_notify_dll(struct lws_dll2 *d, void *user)
+{
+       lws_sspc_handle_t *h = lws_container_of(d, lws_sspc_handle_t, client_list);
+
+       lws_sspc_event_helper(h, LWSSSCS_EVENT_WAIT_CANCELLED, 0);
+
+       return 0;
+}
+
diff --git a/lib/secure-streams/secure-streams-process.c b/lib/secure-streams/secure-streams-process.c
new file mode 100644 (file)
index 0000000..d5822b6
--- /dev/null
@@ -0,0 +1,801 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *
+ * When the user code is in a different process, a non-tls unix domain socket
+ * proxy is used to asynchronusly transfer buffers in each direction via the
+ * network stack, without explicit IPC
+ *
+ *     user_process{ [user code] | shim | socket-}------ lws_process{ lws }
+ *
+ * Lws exposes a listening unix domain socket in this case, the user processes
+ * connect to it and pass just info.streamtype in an initial tx packet.  All
+ * packets are prepended by a 1-byte type field when used in this mode.  See
+ * lws-secure-streams.h for documentation and definitions.
+ *
+ * Proxying in either direction can face the situation it cannot send the onward
+ * packet immediately and is subject to separating the write request from the
+ * write action.  To make the best use of memory, a single preallocated buffer
+ * stashes pending packets in all four directions (c->p, p->c, p->ss, ss->p).
+ * This allows it to adapt to different traffic patterns without wasted areas
+ * dedicated to traffic that isn't coming in a particular application.
+ *
+ * A shim is provided to monitor the process' unix domain socket and regenerate
+ * the secure sockets api there with callbacks happening in the process thread
+ * context.
+ *
+ * This file implements the listening unix domain socket proxy... this code is
+ * only going to run on a Linux-class device with its implications about memory
+ * availability.
+ */
+
+#include <private-lib-core.h>
+
+struct raw_pss {
+       struct conn             *conn;
+};
+
+/*
+ * Proxy - onward secure-stream handler
+ */
+
+typedef struct ss_proxy_onward {
+       lws_ss_handle_t         *ss;
+       struct conn             *conn;
+} ss_proxy_t;
+
+void
+lws_proxy_clean_conn_ss(struct lws *wsi)
+{
+#if 0
+       lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data;
+       struct conn *conn = h->conn_if_sspc_onw;
+
+       if (!wsi)
+               return;
+
+       if (conn && conn->ss)
+               conn->ss->wsi = NULL;
+#endif
+}
+
+
+void
+ss_proxy_onward_link_req_writeable(lws_ss_handle_t *h_onward)
+{
+       ss_proxy_t *m = (ss_proxy_t *)&h_onward[1];
+
+       if (m->conn->wsi) /* if possible, request client conn write */
+               lws_callback_on_writable(m->conn->wsi);
+}
+
+int
+__lws_ss_proxy_bind_ss_to_conn_wsi(void *parconn, size_t dsh_size)
+{
+       struct conn *conn = (struct conn *)parconn;
+       struct lws_context_per_thread *pt;
+
+       if (!conn || !conn->wsi || !conn->ss)
+               return -1;
+
+       pt = &conn->wsi->a.context->pt[(int)conn->wsi->tsi];
+
+       if (lws_fi(&conn->ss->fic, "ssproxy_dsh_create_oom"))
+               return -1;
+       conn->dsh = lws_dsh_create(&pt->ss_dsh_owner, dsh_size, 2);
+       if (!conn->dsh)
+               return -1;
+
+       __lws_lc_tag_append(&conn->wsi->lc, lws_ss_tag(conn->ss));
+
+       return 0;
+}
+
+/* Onward secure streams payload interface */
+
+static lws_ss_state_return_t
+ss_proxy_onward_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       ss_proxy_t *m = (ss_proxy_t *)userobj;
+       const char *rsp = NULL;
+       int n;
+
+       // lwsl_notice("%s: len %d\n", __func__, (int)len);
+
+       /*
+        * The onward secure stream connection has received something.
+        */
+
+       if (m->ss->rideshare != m->ss->policy && m->ss->rideshare) {
+               rsp = m->ss->rideshare->streamtype;
+               flags |= LWSSS_FLAG_RIDESHARE;
+       }
+
+       /*
+        * Apply SSS framing around this chunk of RX and stash it in the dsh
+        * in ss -> proxy [ -> client] direction.  This can fail...
+        */
+
+       if (lws_fi(&m->ss->fic, "ssproxy_dsh_rx_queue_oom"))
+               n = 1;
+       else
+               n = lws_ss_serialize_rx_payload(m->conn->dsh, buf, len,
+                                               flags, rsp);
+       if (n)
+               /*
+                * We couldn't buffer this rx, eg due to OOM, let's escalate it
+                * to be a "loss of connection", which it basically is...
+                */
+               return LWSSSSRET_DISCONNECT_ME;
+
+       /*
+        * Manage rx flow on the SS (onward) side according to our situation
+        * in the dsh holding proxy->client serialized forwarding rx
+        */
+
+       if (!m->conn->onward_in_flow_control && m->ss->wsi &&
+           m->ss->policy->proxy_buflen_rxflow_on_above &&
+           lws_dsh_get_size(m->conn->dsh, KIND_SS_TO_P) >=
+                               m->ss->policy->proxy_buflen_rxflow_on_above) {
+               lwsl_info("%s: %s: rxflow disabling rx (%lu / %lu, hwm %lu)\n", __func__,
+                               lws_wsi_tag(m->ss->wsi),
+                               (unsigned long)lws_dsh_get_size(m->conn->dsh, KIND_SS_TO_P),
+                               (unsigned long)m->ss->policy->proxy_buflen,
+                               (unsigned long)m->ss->policy->proxy_buflen_rxflow_on_above);
+               /*
+                * stop taking in rx once the onward wsi rx is above the
+                * high water mark
+                */
+               lws_rx_flow_control(m->ss->wsi, 0);
+               m->conn->onward_in_flow_control = 1;
+       }
+
+       if (m->conn->wsi) /* if possible, request client conn write */
+               lws_callback_on_writable(m->conn->wsi);
+
+       return LWSSSSRET_OK;
+}
+
+/*
+ * we are transmitting buffered payload originally from the client on to the ss
+ */
+
+static lws_ss_state_return_t
+ss_proxy_onward_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                  size_t *len, int *flags)
+{
+       ss_proxy_t *m = (ss_proxy_t *)userobj;
+       void *p;
+       size_t si;
+
+       if (!m->conn->ss || m->conn->state != LPCSPROX_OPERATIONAL) {
+               lwsl_notice("%s: ss not ready\n", __func__);
+               *len = 0;
+
+               return LWSSSSRET_TX_DONT_SEND;
+       }
+
+       /*
+        * The onward secure stream says that we could send something to it
+        * (by putting it in buf, and setting *len and *flags)... dredge the
+        * next thing out of the dsh
+        */
+
+       if (lws_ss_deserialize_tx_payload(m->conn->dsh, m->ss->wsi,
+                                         ord, buf, len, flags))
+               return LWSSSSRET_TX_DONT_SEND;
+
+       /* ... there's more we want to send? */
+       if (!lws_dsh_get_head(m->conn->dsh, KIND_C_TO_P, (void **)&p, &si))
+               _lws_ss_request_tx(m->conn->ss);
+
+       if (!*len && !*flags)
+               /* we don't actually want to send anything */
+               return LWSSSSRET_TX_DONT_SEND;
+
+       lwsl_info("%s: onward tx %d fl 0x%x\n", __func__, (int)*len, *flags);
+
+#if 0
+       {
+               int ff = open("/tmp/z", O_RDWR | O_CREAT | O_APPEND, 0666);
+               if (ff == -1)
+                       lwsl_err("%s: errno %d\n", __func__, errno);
+               write(ff, buf, *len);
+               close(ff);
+       }
+#endif
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+ss_proxy_onward_state(void *userobj, void *sh,
+                     lws_ss_constate_t state, lws_ss_tx_ordinal_t ack)
+{
+       ss_proxy_t *m = (ss_proxy_t *)userobj;
+       size_t dsh_size;
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+
+               /*
+                * conn is private to -process.c, call thru to a) adjust
+                * the accepted incoming proxy link wsi tag name to be
+                * appended with the onward ss tag information now we
+                * have it, and b) allocate the dsh buffer now we
+                * can find out the policy about it for the streamtype.
+                */
+
+               dsh_size = m->ss->policy->proxy_buflen ?
+                               m->ss->policy->proxy_buflen : 32768;
+
+               lwsl_notice("%s: %s: initializing dsh max len %lu\n",
+                               __func__, lws_ss_tag(m->ss),
+                               (unsigned long)dsh_size);
+
+               /* this includes ssproxy_dsh_create_oom fault generation */
+
+               if (__lws_ss_proxy_bind_ss_to_conn_wsi(m->conn, dsh_size)) {
+
+                       /* failed to allocate the dsh */
+
+                       lwsl_notice("%s: dsh init failed\n", __func__);
+
+                       return LWSSSSRET_DESTROY_ME;
+               }
+               break;
+
+       case LWSSSCS_DESTROYING:
+               if (!m->conn)
+                       break;
+               if (!m->conn->wsi) {
+                       /*
+                        * Our onward secure stream is closing and our client
+                        * connection has already gone away... destroy the conn.
+                        */
+                       lwsl_info("%s: Destroying conn\n", __func__);
+                       lws_dsh_destroy(&m->conn->dsh);
+                       free(m->conn);
+                       m->conn = NULL;
+                       return 0;
+               } else
+                       lwsl_info("%s: ss DESTROYING, wsi up\n", __func__);
+               break;
+
+       default:
+               break;
+       }
+       if (!m->conn) {
+               lwsl_warn("%s: dropping state due to conn not up\n", __func__);
+
+               return LWSSSSRET_OK;
+       }
+
+       if (lws_ss_serialize_state(m->conn->wsi, m->conn->dsh, state, ack))
+               /*
+                * Failed to alloc state packet that we want to send in dsh,
+                * we will lose coherence and have to disconnect the link
+                */
+               return LWSSSSRET_DISCONNECT_ME;
+
+       if (m->conn->wsi) /* if possible, request client conn write */
+               lws_callback_on_writable(m->conn->wsi);
+
+       return LWSSSSRET_OK;
+}
+
+void
+ss_proxy_onward_txcr(void *userobj, int bump)
+{
+       ss_proxy_t *m = (ss_proxy_t *)userobj;
+
+       if (!m->conn)
+               return;
+
+       lws_ss_serialize_txcr(m->conn->dsh, bump);
+
+       if (m->conn->wsi) /* if possible, request client conn write */
+               lws_callback_on_writable(m->conn->wsi);
+}
+
+/*
+ * Client <-> Proxy connection, usually on Unix Domain Socket
+ */
+
+static int
+callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason,
+                 void *user, void *in, size_t len)
+{
+       struct raw_pss *pss = (struct raw_pss *)user;
+       const lws_ss_policy_t *rsp;
+       struct conn *conn = NULL;
+       lws_ss_metadata_t *md;
+       lws_ss_info_t ssi;
+       const uint8_t *cp;
+       char s[512];
+       uint8_t *p;
+       size_t si;
+       char pay;
+       int n;
+
+       if (pss)
+               conn = pss->conn;
+
+       switch (reason) {
+       case LWS_CALLBACK_PROTOCOL_INIT:
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               break;
+
+       /* callbacks related to raw socket descriptor "accepted side" */
+
+        case LWS_CALLBACK_RAW_ADOPT:
+               lwsl_info("LWS_CALLBACK_RAW_ADOPT\n");
+               if (!pss)
+                       return -1;
+
+               if (lws_fi(&wsi->fic, "ssproxy_client_adopt_oom"))
+                       pss->conn = NULL;
+               else
+                       pss->conn = malloc(sizeof(struct conn));
+               if (!pss->conn)
+                       return -1;
+
+               memset(pss->conn, 0, sizeof(*pss->conn));
+
+               /* dsh is allocated when the onward ss is done */
+
+               pss->conn->wsi = wsi;
+               wsi->bound_ss_proxy_conn = 1; /* opaque is conn */
+
+               pss->conn->state = LPCSPROX_WAIT_INITIAL_TX;
+
+               /*
+                * Client is expected to follow the unix domain socket
+                * acceptance up rapidly with an initial tx containing the
+                * streamtype name.  We can't create the stream until then.
+                */
+               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, 3);
+                break;
+
+       case LWS_CALLBACK_RAW_CLOSE:
+               lwsl_info("LWS_CALLBACK_RAW_CLOSE:\n");
+
+               if (!conn)
+                       break;
+
+               /*
+                * the client unix domain socket connection (wsi / conn->wsi)
+                * has closed... eg, client has exited or otherwise has
+                * definitively finished with the proxying and onward connection
+                *
+                * But right now, the SS and possibly the SS onward wsi are
+                * still live...
+                */
+
+               assert(conn->wsi == wsi);
+               conn->wsi = NULL;
+
+               lwsl_notice("%s: cli->prox link %s closing\n", __func__,
+                               lws_wsi_tag(wsi));
+
+               /* sever relationship with conn */
+               lws_set_opaque_user_data(wsi, NULL);
+
+               /*
+                * The current wsi is decoupled from the pss / conn and
+                * the conn no longer has a pointer on it.
+                *
+                * If there's an outgoing, proxied SS conn on our behalf, we
+                * have to destroy those
+                */
+
+               if (conn->ss) {
+                       struct lws *cw = conn->ss->wsi;
+                       /*
+                        * conn->ss is the onward connection SS
+                        */
+
+                       lwsl_info("%s: destroying %s, wsi %s\n",
+                                       __func__, lws_ss_tag(conn->ss),
+                                       lws_wsi_tag(conn->ss->wsi));
+
+                       /* sever conn relationship with ss about to be deleted */
+
+                       conn->ss->wsi = NULL;
+
+                       if (cw && wsi != cw) {
+
+                               /* disconnect onward SS from its wsi */
+
+                               lws_set_opaque_user_data(cw, NULL);
+
+                               /*
+                                * The wsi doing the onward connection can no
+                                * longer relate to the conn... otherwise when
+                                * he gets callbacks he wants to bind to
+                                * the ss we are about to delete
+                                */
+                               lws_wsi_close(cw, LWS_TO_KILL_ASYNC);
+                       }
+
+                       lws_ss_destroy(&conn->ss);
+                       /*
+                        * Conn may have gone, at ss destroy handler in
+                        * ssi.state for proxied ss
+                        */
+                       break;
+               }
+
+               if (conn->state == LPCSPROX_DESTROYED || !conn->ss) {
+                       /*
+                        * There's no onward secure stream and our client
+                        * connection is closing.  Destroy the conn.
+                        */
+                       lws_dsh_destroy(&conn->dsh);
+                       free(conn);
+                       pss->conn = NULL;
+               } else
+                       lwsl_debug("%s: CLOSE; %s\n", __func__, lws_ss_tag(conn->ss));
+
+               break;
+
+       case LWS_CALLBACK_RAW_RX:
+               /*
+                * ie, the proxy is receiving something from a client
+                */
+               lwsl_info("%s: RX: rx %d\n", __func__, (int)len);
+
+               if (!conn || !conn->wsi) {
+                       lwsl_err("%s: rx with bad conn state\n", __func__);
+
+                       return -1;
+               }
+
+               // lwsl_hexdump_info(in, len);
+
+               if (conn->state == LPCSPROX_WAIT_INITIAL_TX) {
+                       memset(&ssi, 0, sizeof(ssi));
+                       ssi.user_alloc = sizeof(ss_proxy_t);
+                       ssi.handle_offset = offsetof(ss_proxy_t, ss);
+                       ssi.opaque_user_data_offset =
+                                       offsetof(ss_proxy_t, conn);
+                       ssi.rx = ss_proxy_onward_rx;
+                       ssi.tx = ss_proxy_onward_tx;
+               }
+               ssi.state = ss_proxy_onward_state;
+               ssi.flags = 0;
+
+               n = lws_ss_deserialize_parse(&conn->parser,
+                               lws_get_context(wsi), conn->dsh, in, len,
+                               &conn->state, conn, &conn->ss, &ssi, 0);
+               switch (n) {
+               case LWSSSSRET_OK:
+                       break;
+               case LWSSSSRET_DISCONNECT_ME:
+                       return -1;
+               case LWSSSSRET_DESTROY_ME:
+                       if (conn->ss)
+                               lws_ss_destroy(&conn->ss);
+                       return -1;
+               }
+
+               if (conn->state == LPCSPROX_REPORTING_FAIL ||
+                   conn->state == LPCSPROX_REPORTING_OK)
+                       lws_callback_on_writable(conn->wsi);
+
+               break;
+
+       case LWS_CALLBACK_RAW_WRITEABLE:
+
+               lwsl_debug("%s: %s: LWS_CALLBACK_RAW_WRITEABLE, state 0x%x\n",
+                               __func__, lws_wsi_tag(wsi), lwsi_state(wsi));
+
+               /*
+                * We can transmit something back to the client from the dsh
+                * of stuff we received on its behalf from the ss
+                */
+
+               if (!conn || !conn->wsi)
+                       break;
+
+               n = 0;
+               pay = 0;
+
+               s[3] = 0;
+               cp = (const uint8_t *)s;
+               switch (conn->state) {
+               case LPCSPROX_REPORTING_FAIL:
+                       s[3] = 1;
+                       /* fallthru */
+               case LPCSPROX_REPORTING_OK:
+                       s[0] = LWSSS_SER_RXPRE_CREATE_RESULT;
+                       s[1] = 0;
+                       s[2] = 1;
+
+                       n = 8;
+
+                       lws_ser_wu32be((uint8_t *)&s[4], conn->ss &&
+                                                        conn->ss->policy ?
+                                       conn->ss->policy->client_buflen : 0);
+
+                       /*
+                        * If there's rideshare sequencing, it's added after the
+                        * first 4 bytes or the create result, comma-separated
+                        */
+
+                       if (conn->ss) {
+                               rsp = conn->ss->policy;
+
+                               while (rsp) {
+                                       if (n != 4 && n < (int)sizeof(s) - 2)
+                                               s[n++] = ',';
+                                       n += lws_snprintf(&s[n], sizeof(s) - (unsigned int)n,
+                                                       "%s", rsp->streamtype);
+                                       rsp = lws_ss_policy_lookup(wsi->a.context,
+                                               rsp->rideshare_streamtype);
+                               }
+                       }
+                       s[2] = (char)(n - 3);
+                       conn->state = LPCSPROX_OPERATIONAL;
+                       lws_set_timeout(wsi, 0, 0);
+                       break;
+
+               case LPCSPROX_OPERATIONAL:
+
+                       /*
+                        * returning [onward -> ] proxy]-> client
+                        * rx metadata has priority 1
+                        */
+
+                       md = conn->ss->metadata;
+                       while (md) {
+                               // lwsl_notice("%s: check %s: %d\n", __func__,
+                               // md->name, md->pending_onward);
+                               if (md->pending_onward) {
+                                       size_t naml = strlen(md->name);
+
+                                       // lwsl_notice("%s: proxy issuing rxmd\n", __func__);
+
+                                       if (4 + naml + md->length > sizeof(s)) {
+                                               lwsl_err("%s: rxmdata too big\n",
+                                                               __func__);
+                                               goto hangup;
+                                       }
+                                       md->pending_onward = 0;
+                                       p = (uint8_t *)s;
+                                       p[0] = LWSSS_SER_RXPRE_METADATA;
+                                       lws_ser_wu16be(&p[1], (uint16_t)(1 + naml +
+                                                             md->length));
+                                       p[3] = (uint8_t)naml;
+                                       memcpy(&p[4], md->name, naml);
+                                       p += 4 + naml;
+                                       memcpy(p, md->value__may_own_heap,
+                                              md->length);
+                                       p += md->length;
+
+                                       n = lws_ptr_diff(p, cp);
+                                       goto again;
+                               }
+
+                               md = md->next;
+                       }
+
+                       /*
+                        * If we have performance data, render it in JSON
+                        * and send that in LWSSS_SER_RXPRE_PERF has
+                        * priority 2
+                        */
+
+#if defined(LWS_WITH_CONMON)
+                       if (conn->ss->conmon_json) {
+                               unsigned int xlen = conn->ss->conmon_len;
+
+                               if (xlen > sizeof(s) - 3)
+                                       xlen = sizeof(s) - 3;
+                               cp = (uint8_t *)s;
+                               p = (uint8_t *)s;
+                               p[0] = LWSSS_SER_RXPRE_PERF;
+                               lws_ser_wu16be(&p[1], (uint16_t)xlen);
+                               memcpy(&p[3], conn->ss->conmon_json, xlen);
+
+                               lws_free_set_NULL(conn->ss->conmon_json);
+                               n = (int)(xlen + 3);
+
+                               pay = 0;
+                               goto again;
+                       }
+#endif
+                       /*
+                        * if no fresh rx metadata, just pass through incoming
+                        * dsh
+                        */
+
+                       if (lws_dsh_get_head(conn->dsh, KIND_SS_TO_P,
+                                            (void **)&p, &si))
+                               break;
+
+                       cp = p;
+
+#if 0
+                       if (cp[0] == LWSSS_SER_RXPRE_RX_PAYLOAD &&
+                           wsi->a.context->detailed_latency_cb) {
+
+                               /*
+                                * we're fulfilling rx that came in on ss
+                                * by sending it back out to the client on
+                                * the Unix Domain Socket
+                                *
+                                * +  7  u32  write will compute latency here...
+                                * + 11  u32  ust we received from ss
+                                *
+                                * lws_write will report it and fill in
+                                * LAT_DUR_PROXY_CLIENT_REQ_TO_WRITE
+                                */
+
+                               us = lws_now_usecs();
+                               lws_ser_wu32be(&p[7], us -
+                                                     lws_ser_ru64be(&p[11]));
+                               lws_ser_wu64be(&p[11], us);
+
+                               wsi->detlat.acc_size =
+                                       wsi->detlat.req_size = si - 19;
+                               /* time proxy held it */
+                               wsi->detlat.latencies[
+                                           LAT_DUR_PROXY_RX_TO_ONWARD_TX] =
+                                                       lws_ser_ru32be(&p[7]);
+                       }
+#endif
+                       pay = 1;
+                       n = (int)si;
+                       break;
+               default:
+                       break;
+               }
+again:
+               if (!n)
+                       break;
+
+               if (lws_fi(&wsi->fic, "ssproxy_client_write_fail"))
+                       n = -1;
+               else
+                       n = lws_write(wsi, (uint8_t *)cp, (unsigned int)n, LWS_WRITE_RAW);
+               if (n < 0) {
+                       lwsl_info("%s: WRITEABLE: %d\n", __func__, n);
+
+                       goto hangup;
+               }
+
+               switch (conn->state) {
+               case LPCSPROX_REPORTING_FAIL:
+                       goto hangup;
+               case LPCSPROX_OPERATIONAL:
+                       if (!conn)
+                               break;
+                       if (pay) {
+                               lws_dsh_free((void **)&p);
+
+                               /*
+                                * Did we go below the rx flow threshold for
+                                * this dsh?
+                                */
+
+                               if (conn->onward_in_flow_control &&
+                                   conn->ss->policy->proxy_buflen_rxflow_on_above &&
+                                   conn->ss->wsi &&
+                                   lws_dsh_get_size(conn->dsh, KIND_SS_TO_P) <
+                                     conn->ss->policy->proxy_buflen_rxflow_off_below) {
+                                       lwsl_info("%s: %s: rxflow enabling rx (%lu / %lu, lwm %lu)\n", __func__,
+                                                       lws_wsi_tag(conn->ss->wsi),
+                                                       (unsigned long)lws_dsh_get_size(conn->dsh, KIND_SS_TO_P),
+                                                       (unsigned long)conn->ss->policy->proxy_buflen,
+                                                       (unsigned long)conn->ss->policy->proxy_buflen_rxflow_off_below);
+                                       /*
+                                        * Resume receiving taking in rx once
+                                        * below the low threshold
+                                        */
+                                       lws_rx_flow_control(conn->ss->wsi,
+                                                           LWS_RXFLOW_ALLOW);
+                                       conn->onward_in_flow_control = 0;
+                               }
+                       }
+                       if (!lws_dsh_get_head(conn->dsh, KIND_SS_TO_P,
+                                            (void **)&p, &si)) {
+                               if (!lws_send_pipe_choked(wsi)) {
+                                       cp = p;
+                                       pay = 1;
+                                       n = (int)si;
+                                       goto again;
+                               }
+                               lws_callback_on_writable(wsi);
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+
+hangup:
+       /* hang up on him */
+
+       return -1;
+}
+
+static const struct lws_protocols protocols[] = {
+       {
+               "ssproxy-protocol",
+               callback_ss_proxy,
+               sizeof(struct raw_pss),
+               2048, 2048, NULL, 0
+       },
+       { NULL, NULL, 0, 0, 0, NULL, 0 }
+};
+
+/*
+ * called from create_context()
+ */
+
+int
+lws_ss_proxy_create(struct lws_context *context, const char *bind, int port)
+{
+       struct lws_context_creation_info info;
+
+       memset(&info, 0, sizeof(info));
+
+       info.vhost_name                 = "ssproxy";
+       info.options = LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG |
+                       LWS_SERVER_OPTION_SS_PROXY;
+       info.port = port;
+       if (!port) {
+               if (!bind)
+#if defined(__linux__)
+                       bind = "@proxy.ss.lws";
+#else
+                       bind = "/tmp/proxy.ss.lws";
+#endif
+               info.options |= LWS_SERVER_OPTION_UNIX_SOCK;
+       }
+       info.iface                      = bind;
+#if defined(__linux__)
+       info.unix_socket_perms          = "root:root";
+#else
+#endif
+       info.listen_accept_role         = "raw-skt";
+       info.listen_accept_protocol     = "ssproxy-protocol";
+       info.protocols                  = protocols;
+
+       if (!lws_create_vhost(context, &info)) {
+               lwsl_err("%s: Failed to create ss proxy vhost\n", __func__);
+
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/lib/secure-streams/secure-streams-serialize.c b/lib/secure-streams/secure-streams-serialize.c
new file mode 100644 (file)
index 0000000..53a9ed8
--- /dev/null
@@ -0,0 +1,1542 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *
+ * In the case Secure Streams protocol needs to pass through a buffer,
+ * or a streamed connection, the protocol metadata must be serialized.  This
+ * file provides internal apis to perform the serialization and deserialization
+ * in and out of an lws_dsh fifo-type buffer.
+ */
+
+#include <private-lib-core.h>
+
+typedef enum {
+       RPAR_TYPE,
+       RPAR_LEN_MSB,
+       RPAR_LEN_LSB,
+
+       RPAR_FLAG_B3,
+       RPAR_FLAG_B2,
+       RPAR_FLAG_B1,
+       RPAR_FLAG_B0,
+
+       RPAR_LATA3,
+       RPAR_LATA2,
+       RPAR_LATA1,
+       RPAR_LATA0,
+
+       RPAR_LATB7,
+       RPAR_LATB6,
+       RPAR_LATB5,
+       RPAR_LATB4,
+       RPAR_LATB3,
+       RPAR_LATB2,
+       RPAR_LATB1,
+       RPAR_LATB0,
+
+       RPAR_RIDESHARE_LEN,
+       RPAR_RIDESHARE,
+
+       RPAR_PERF,
+
+       RPAR_RESULT_CREATION_DSH,
+       RPAR_RESULT_CREATION_RIDESHARE,
+
+       RPAR_METADATA_NAMELEN,
+       RPAR_METADATA_NAME,
+       RPAR_METADATA_VALUE,
+
+       RPAR_PAYLOAD,
+
+       RPAR_RX_TXCR_UPDATE,
+
+       RPAR_STREAMTYPE,
+       RPAR_INIT_PROVERS,
+       RPAR_INIT_PID,
+       RPAR_INITTXC0,
+
+       RPAR_TXCR0,
+
+       RPAR_TIMEOUT0,
+
+       RPAR_PAYLEN0,
+
+       RPAR_RESULT_CREATION,
+
+       RPAR_STATEINDEX,
+       RPAR_ORD3,
+       RPAR_ORD2,
+       RPAR_ORD1,
+       RPAR_ORD0,
+} rx_parser_t;
+
+#if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
+static const char *sn[] = {
+       "unset",
+
+       "LPCSPROX_WAIT_INITIAL_TX",
+       "LPCSPROX_REPORTING_FAIL",
+       "LPCSPROX_REPORTING_OK",
+       "LPCSPROX_OPERATIONAL",
+       "LPCSPROX_DESTROYED",
+
+       "LPCSCLI_SENDING_INITIAL_TX",
+       "LPCSCLI_WAITING_CREATE_RESULT",
+       "LPCSCLI_LOCAL_CONNECTED",
+       "LPCSCLI_ONWARD_CONNECT",
+       "LPCSCLI_OPERATIONAL",
+};
+#endif
+
+struct lws_log_cx *
+lwsl_sspc_get_cx(struct lws_sspc_handle *sspc)
+{
+       if (!sspc)
+               return NULL;
+
+       return sspc->lc.log_cx;
+}
+
+
+void
+lws_log_prepend_sspc(struct lws_log_cx *cx, void *obj, char **p, char *e)
+{
+       struct lws_sspc_handle *h = (struct lws_sspc_handle *)obj;
+
+       *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
+                       lws_sspc_tag(h));
+}
+
+static void
+lws_ss_serialize_state_transition(lws_sspc_handle_t *h,
+                                 lws_ss_conn_states_t *state, int new_state)
+{
+#if defined(_DEBUG)
+       lwsl_sspc_info(h, "%s -> %s", sn[*state], sn[new_state]);
+#endif
+       *state = (lws_ss_conn_states_t)new_state;
+}
+
+
+/*
+ * event loop received something and is queueing it for the foreign side of
+ * the dsh to consume later as serialized rx
+ */
+
+int
+lws_ss_serialize_rx_payload(struct lws_dsh *dsh, const uint8_t *buf,
+                           size_t len, int flags, const char *rsp)
+{
+       lws_usec_t us = lws_now_usecs();
+       uint8_t pre[128];
+       int est = 19, l = 0;
+
+       if (flags & LWSSS_FLAG_RIDESHARE) {
+               /*
+                * We should have the rideshare name if we have been told it's
+                * on a non-default rideshare
+                */
+               assert(rsp);
+               if (!rsp)
+                       return 1;
+               l = (int)strlen(rsp);
+               est += 1 + l;
+       } else
+               assert(!rsp);
+
+       // lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       // lwsl_hexdump_info(buf, len);
+
+       pre[0] = LWSSS_SER_RXPRE_RX_PAYLOAD;
+       lws_ser_wu16be(&pre[1], (uint16_t)(len + (size_t)est - 3));
+       lws_ser_wu32be(&pre[3], (uint32_t)flags);
+       lws_ser_wu32be(&pre[7], 0);     /* write will compute latency here... */
+       lws_ser_wu64be(&pre[11], (uint64_t)us); /* ... and set this to the write time */
+
+       /*
+        * If we are on a non-default rideshare, append the non-default name to
+        * the headers of the payload part, 1-byte length first
+        */
+
+       if (flags & LWSSS_FLAG_RIDESHARE) {
+               pre[19] = (uint8_t)l;
+               memcpy(&pre[20], rsp, (unsigned int)l);
+       }
+
+       if (lws_dsh_alloc_tail(dsh, KIND_SS_TO_P, pre, (unsigned int)est, buf, len)) {
+               lwsl_err("%s: unable to alloc in dsh 1\n", __func__);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * event loop is consuming dsh-buffered, already-serialized tx from the
+ * foreign side
+ */
+
+int
+lws_ss_deserialize_tx_payload(struct lws_dsh *dsh, struct lws *wsi,
+                             lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                             size_t *len, int *flags)
+{
+       uint8_t *p;
+       size_t si;
+
+       if (lws_dsh_get_head(dsh, KIND_C_TO_P, (void **)&p, &si)) {
+               *len = 0;
+               return 0;
+       }
+
+       /*
+        * The packet in the dsh has a proxying serialization header, process
+        * and strip it so we just forward the payload
+        */
+
+       if (*len <= si - 23 || si < 23) {
+               /*
+                * What comes out of the dsh needs to fit in the tx buffer...
+                * we have arrangements at the proxy rx of the client UDS to
+                * chop chunks larger than 1380 into seuqential lumps of 1380
+                */
+               lwsl_err("%s: *len = %d, si = %d\n", __func__, (int)*len, (int)si);
+               assert(0);
+               return 1;
+       }
+       if (p[0] != LWSSS_SER_TXPRE_TX_PAYLOAD) {
+               assert(0);
+               return 1;
+       }
+
+       *len = (size_t)(lws_ser_ru16be(&p[1]) - (23 - 3));
+       if (*len != si - 23) {
+               /*
+                * We cannot accept any length that doesn't reflect the actual
+                * length of what came in from the dsh, either something nasty
+                * happened with truncation or we are being attacked
+                */
+               assert(0);
+
+               return 1;
+       }
+
+       memcpy(buf, p + 23, si - 23);
+
+       *flags = (int)lws_ser_ru32be(&p[3]);
+
+       lws_dsh_free((void **)&p);
+
+       return 0;
+}
+
+/*
+ * event loop side is issuing state, serialize and put it in the dbuf for
+ * the foreign side to consume later
+ */
+
+int
+lws_ss_serialize_state(struct lws *wsi, struct lws_dsh *dsh, lws_ss_constate_t state,
+                      lws_ss_tx_ordinal_t ack)
+{
+       uint8_t pre[12];
+       int n = 4;
+
+       if (state == LWSSSCS_EVENT_WAIT_CANCELLED)
+               return 0;
+
+       lwsl_info("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
+                 (unsigned int)ack);
+
+       pre[0] = LWSSS_SER_RXPRE_CONNSTATE;
+       pre[1] = 0;
+
+       if (state > 255) {
+               pre[2] = 8;
+               lws_ser_wu32be(&pre[3], state);
+               n = 7;
+       } else {
+               pre[2] = 5;
+               pre[3] = (uint8_t)state;
+       }
+
+       lws_ser_wu32be(&pre[n], ack);
+
+       if (lws_dsh_alloc_tail(dsh, KIND_SS_TO_P, pre, (unsigned int)n + 4, NULL, 0) ||
+           (wsi && lws_fi(&wsi->fic, "sspc_dsh_ss2p_oom"))) {
+               lwsl_err("%s: unable to alloc in dsh 2\n", __func__);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * event loop side was told about remote peer tx credit window update, serialize
+ * and put it in the dbuf for the foreign side to consume later
+ */
+
+int
+lws_ss_serialize_txcr(struct lws_dsh *dsh, int txcr)
+{
+       uint8_t pre[7];
+
+       lwsl_info("%s: %d\n", __func__, txcr);
+
+       pre[0] = LWSSS_SER_RXPRE_TXCR_UPDATE;
+       pre[1] = 0;
+       pre[2] = 4;
+       lws_ser_wu32be(&pre[3], (uint32_t)txcr);
+
+       if (lws_dsh_alloc_tail(dsh, KIND_SS_TO_P, pre, 7, NULL, 0)) {
+               lwsl_err("%s: unable to alloc in dsh 2\n", __func__);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * event loop side is consuming serialized data from the client via dsh, parse
+ * it using a bytewise parser for the serialization header(s)...
+ * it's possibly coalesced
+ *
+ * client: pss is pointing to the start of userdata.  We can use
+ *         pss_to_sspc_h(_pss, _ssi) to convert that to a pointer to the sspc
+ *         handle
+ *
+ * proxy: pss is pointing to &conn->ss, a pointer to the ss handle
+ *
+ * Returns one of
+ *
+ *     LWSSSSRET_OK
+ *     LWSSSSRET_DISCONNECT_ME
+ *     LWSSSSRET_DESTROY_ME
+ */
+
+/* convert userdata ptr _pss to handle pointer, allowing for any layout in
+ * userdata */
+#define client_pss_to_sspc_h(_pss, _ssi) (*((lws_sspc_handle_t **) \
+                                    ((uint8_t *)_pss) + _ssi->handle_offset))
+/* client pss to sspc userdata */
+#define client_pss_to_userdata(_pss) ((void *)_pss)
+/* proxy convert pss to ss handle */
+#define proxy_pss_to_ss_h(_pss) (*_pss)
+
+/* convert userdata ptr _pss to handle pointer, allowing for any layout in
+ * userdata */
+#define client_pss_to_sspc_h(_pss, _ssi) (*((lws_sspc_handle_t **) \
+                                    ((uint8_t *)_pss) + _ssi->handle_offset))
+/* client pss to sspc userdata */
+#define client_pss_to_userdata(_pss) ((void *)_pss)
+/* proxy convert pss to ss handle */
+#define proxy_pss_to_ss_h(_pss) (*_pss)
+
+int
+lws_ss_deserialize_parse(struct lws_ss_serialization_parser *par,
+                        struct lws_context *context,
+                        struct lws_dsh *dsh, const uint8_t *cp, size_t len,
+                        lws_ss_conn_states_t *state, void *parconn,
+                        lws_ss_handle_t **pss, lws_ss_info_t *ssi, char client)
+{
+       lws_ss_state_return_t r;
+       lws_ss_metadata_t *pm;
+       lws_sspc_handle_t *h;
+       uint8_t pre[23];
+       uint32_t flags;
+       lws_usec_t us;
+       uint8_t *p;
+       int n;
+
+       while (len--) {
+
+               switch (par->ps) {
+               case RPAR_TYPE:
+                       par->type = *cp++;
+                       par->ps++;
+                       break;
+
+               case RPAR_LEN_MSB: /* this is remaining frame length */
+                       par->rem = (uint16_t)((*cp++) << 8);
+                       par->ps++;
+                       break;
+
+               case RPAR_LEN_LSB:
+                       par->rem = (uint16_t)(par->rem | *cp++);
+                       switch (par->type) {
+
+                       /* event loop side */
+
+                       case LWSSS_SER_TXPRE_TX_PAYLOAD:
+                               if (client)
+                                       goto hangup;
+                               if (*state != LPCSPROX_OPERATIONAL)
+                                       goto hangup;
+
+                               par->ps = RPAR_FLAG_B3;
+                               break;
+
+                       case LWSSS_SER_TXPRE_DESTROYING:
+                               if (client)
+                                       goto hangup;
+                               par->ps = RPAR_TYPE;
+                               lwsl_cx_notice(context, "DESTROYING");
+                               goto hangup;
+
+                       case LWSSS_SER_TXPRE_ONWARD_CONNECT:
+                               if (client)
+                                       goto hangup;
+
+                               if (*state != LPCSPROX_OPERATIONAL)
+                                       goto hangup;
+
+                               par->ps = RPAR_TYPE;
+                               lwsl_cx_notice(context, "ONWARD_CONNECT");
+
+                               /*
+                                * Shrug it off if we are already connecting or
+                                * connected
+                                */
+
+                               if (!proxy_pss_to_ss_h(pss) ||
+                                   proxy_pss_to_ss_h(pss)->wsi)
+                                       break;
+
+                               /*
+                                * We're going to try to do the onward connect
+                                */
+
+                               if ((proxy_pss_to_ss_h(pss) &&
+                                    lws_fi(&proxy_pss_to_ss_h(pss)->fic, "ssproxy_onward_conn_fail")) ||
+                                   _lws_ss_client_connect(proxy_pss_to_ss_h(pss),
+                                                          0, parconn) ==
+                                                          LWSSSSRET_DESTROY_ME)
+                                       goto hangup;
+                               break;
+
+                       case LWSSS_SER_TXPRE_STREAMTYPE:
+                               if (client)
+                                       goto hangup;
+                               if (*state != LPCSPROX_WAIT_INITIAL_TX)
+                                       goto hangup;
+                               if (par->rem < 1 + 4 + 1)
+                                       goto hangup;
+                               par->ps = RPAR_INIT_PROVERS;
+                               break;
+
+                       case LWSSS_SER_TXPRE_METADATA:
+                               if (client)
+                                       goto hangup;
+                               if (par->rem < 3)
+                                       goto hangup;
+                               par->ctr = 0;
+                               par->ps = RPAR_METADATA_NAMELEN;
+                               break;
+
+                       case LWSSS_SER_TXPRE_TXCR_UPDATE:
+                               par->ps = RPAR_TXCR0;
+                               par->ctr = 0;
+                               break;
+
+                       case LWSSS_SER_TXPRE_TIMEOUT_UPDATE:
+                               if (client)
+                                       goto hangup;
+                               if (par->rem != 4)
+                                       goto hangup;
+                               par->ps = RPAR_TIMEOUT0;
+                               par->ctr = 0;
+                               break;
+
+                       case LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT:
+                               if (client)
+                                       goto hangup;
+                               if (par->rem != 4)
+                                       goto hangup;
+                               par->ps = RPAR_PAYLEN0;
+                               par->ctr = 0;
+                               break;
+
+                       /* client side */
+
+                       case LWSSS_SER_RXPRE_RX_PAYLOAD:
+                               if (!client)
+                                       goto hangup;
+                               if (*state != LPCSCLI_OPERATIONAL &&
+                                   *state != LPCSCLI_LOCAL_CONNECTED)
+                                       goto hangup;
+
+                               par->rideshare[0] = '\0';
+                               par->ps = RPAR_FLAG_B3;
+                               break;
+
+                       case LWSSS_SER_RXPRE_CREATE_RESULT:
+                               if (!client)
+                                       goto hangup;
+                               if (*state != LPCSCLI_WAITING_CREATE_RESULT)
+                                       goto hangup;
+
+                               if (par->rem < 1)
+                                       goto hangup;
+
+                               par->ps = RPAR_RESULT_CREATION;
+                               break;
+
+                       case LWSSS_SER_RXPRE_CONNSTATE:
+                               if (!client)
+                                       goto hangup;
+                               if (*state != LPCSCLI_LOCAL_CONNECTED &&
+                                   *state != LPCSCLI_OPERATIONAL)
+                                       goto hangup;
+
+                               if (par->rem < 5 || par->rem > 8)
+                                       goto hangup;
+
+                               par->ps = RPAR_STATEINDEX;
+                               par->ctr = 0;
+                               break;
+
+                       case LWSSS_SER_RXPRE_METADATA:
+                               if (!client)
+                                       goto hangup;
+                               if (par->rem < 3)
+                                       goto hangup;
+                               par->ctr = 0;
+                               par->ps = RPAR_METADATA_NAMELEN;
+                               break;
+
+                       case LWSSS_SER_RXPRE_TXCR_UPDATE:
+                               par->ctr = 0;
+                               par->ps = RPAR_RX_TXCR_UPDATE;
+                               break;
+
+                       case LWSSS_SER_RXPRE_PERF:
+                               par->ctr = 0;
+                               if (!par->rem)
+                                       goto hangup;
+                               par->ps = RPAR_PERF;
+                               break;
+
+                       default:
+                               lwsl_cx_notice(context, "bad type 0x%x",
+                                              par->type);
+                               goto hangup;
+                       }
+                       break;
+
+                       case RPAR_FLAG_B3:
+                       case RPAR_FLAG_B2:
+                       case RPAR_FLAG_B1:
+                       case RPAR_FLAG_B0:
+                               par->flags <<= 8;
+                               par->flags |= *cp++;
+                               par->ps++;
+                               if (!par->rem--)
+                                       goto hangup;
+                               break;
+
+                       case RPAR_LATA3:
+                       case RPAR_LATA2:
+                       case RPAR_LATA1:
+                       case RPAR_LATA0:
+                               par->usd_phandling <<= 8;
+                               par->usd_phandling |= *cp++;
+                               par->ps++;
+                               if (!par->rem--)
+                                       goto hangup;
+                               break;
+
+                       case RPAR_LATB7:
+                       case RPAR_LATB6:
+                       case RPAR_LATB5:
+                       case RPAR_LATB4:
+                       case RPAR_LATB3:
+                       case RPAR_LATB2:
+                       case RPAR_LATB1:
+                       case RPAR_LATB0:
+                               par->ust_pwait <<= 8;
+                               par->ust_pwait |= *cp++;
+                               par->ps++;
+                               par->frag1 = 1;
+                               if (!par->rem--)
+                                       goto hangup;
+
+                               if (par->ps == RPAR_RIDESHARE_LEN &&
+                                   !(par->flags & LWSSS_FLAG_RIDESHARE))
+                                       par->ps = RPAR_PAYLOAD;
+
+                               if (par->rem)
+                                       break;
+
+                               /* fallthru - handle 0-length payload */
+
+                               if (!(par->flags & LWSSS_FLAG_RIDESHARE))
+                                       goto payload_ff;
+                               goto hangup;
+
+                       /*
+                        * Inbound rideshare info is provided on the RX packet
+                        * itself
+                        */
+
+               case RPAR_RIDESHARE_LEN:
+                       par->slen = *cp++;
+                       par->ctr = 0;
+                       par->ps++;
+                       if (par->rem-- < par->slen)
+                               goto hangup;
+                       break;
+
+               case RPAR_PERF:
+                       n = (int)len + 1;
+                       if (n > par->rem)
+                               n = par->rem;
+
+                       if (client &&
+                           client_pss_to_sspc_h(pss, ssi) &&
+                           ssi->rx) {
+                               int ret;
+
+                               /* we still have an sspc handle */
+                               ret = ssi->rx(client_pss_to_userdata(pss),
+                                       (uint8_t *)cp, (unsigned int)n,
+                                       (int)(LWSSS_FLAG_SOM | LWSSS_FLAG_EOM |
+                                                       LWSSS_FLAG_PERF_JSON));
+
+                               if (lws_fi(&client_pss_to_sspc_h(pss, ssi)->fic,
+                                                   "sspc_perf_rx_fake_destroy_me"))
+                                       ret = LWSSSSRET_DESTROY_ME;
+
+                               switch (ret) {
+                               case LWSSSSRET_OK:
+                                       break;
+                               case LWSSSSRET_DISCONNECT_ME:
+                                       goto hangup;
+                               case LWSSSSRET_DESTROY_ME:
+                                       return LWSSSSRET_DESTROY_ME;
+                               }
+                       }
+                       if (n) {
+                               cp += n;
+                               par->rem = (uint16_t)(par->rem - (uint16_t)(unsigned int)n);
+                               len = (len + 1) - (unsigned int)n;
+                       }
+                       if (!par->rem)
+                               par->ps = RPAR_TYPE;
+                       break;
+
+               case RPAR_RIDESHARE:
+                       par->rideshare[par->ctr++] = (char)*cp++;
+                       if (!par->rem--)
+                               goto hangup;
+                       if (par->ctr != par->slen)
+                               break;
+                       par->ps = RPAR_PAYLOAD;
+                       if (par->rem)
+                               break;
+
+                       /* fallthru - handle 0-length payload */
+
+               case RPAR_PAYLOAD:
+payload_ff:
+                       n = (int)len + 1;
+                       if (n > par->rem)
+                               n = par->rem;
+                       /*
+                        * We get called with a serialized buffer of a size
+                        * chosen by the client.  We can only create dsh entries
+                        * with up to 1380 payload, to guarantee we can emit
+                        * them on the onward connection atomically.
+                        *
+                        * If 1380 isn't enough to cover what was handed to us,
+                        * we'll stop at 1380 and go around again and create
+                        * more dsh entries for the rest, with their own
+                        * headers.
+                        */
+
+                       if (n > 1380)
+                               n = 1380;
+
+                       /*
+                        * Since we're in the business of fragmenting client
+                        * serialized payloads at 1380, we have to deal with
+                        * refragmenting the SOM / EOM flags that covered the
+                        * whole client serialized packet, so they apply to
+                        * each dsh entry we split it into correctly
+                        */
+
+                       flags = par->flags & LWSSS_FLAG_RELATED_START;
+                       if (par->frag1)
+                               /*
+                                * Only set the first time we came to this
+                                * state after deserialization of the header
+                                */
+                               flags |= par->flags &
+                                   (LWSSS_FLAG_SOM | LWSSS_FLAG_POLL);
+
+                       if (par->rem == n)
+                               /*
+                                * We are going to complete the advertised
+                                * payload length from the client on this dsh,
+                                * so give him the EOM type flags if any
+                                */
+                               flags |= par->flags & (LWSSS_FLAG_EOM |
+                                               LWSSS_FLAG_RELATED_END);
+
+                       par->frag1 = 0;
+                       us = lws_now_usecs();
+
+                       if (!client) {
+                               lws_ss_handle_t *hss;
+
+                               /*
+                                * Proxy - we received some serialized tx from
+                                * the client.
+                                *
+                                * The header for buffering private to the
+                                * proxy is 23 bytes vs 19, so we can hold the
+                                * current time when it was buffered
+                                * additionally
+                                */
+
+                               hss = proxy_pss_to_ss_h(pss);
+                               if (hss)
+                                       lwsl_ss_info(hss, "C2P RX: len %d", (int)n);
+
+                               p = pre;
+                               pre[0] = LWSSS_SER_TXPRE_TX_PAYLOAD;
+                               lws_ser_wu16be(&p[1], (uint16_t)((unsigned int)n + 23 - 3));
+                               lws_ser_wu32be(&p[3], flags);
+                               /* us held at client before written */
+                               lws_ser_wu32be(&p[7], par->usd_phandling);
+                               /* us taken for transit to proxy */
+                               lws_ser_wu32be(&p[11], (uint32_t)(us - (lws_usec_t)par->ust_pwait));
+                               /* time used later to find proxy hold time */
+                               lws_ser_wu64be(&p[15], (uint64_t)us);
+
+                               if ((hss &&
+                                   lws_fi(&hss->fic, "ssproxy_dsh_c2p_pay_oom")) ||
+                                   lws_dsh_alloc_tail(dsh, KIND_C_TO_P, pre,
+                                                      23, cp, (unsigned int)n)) {
+                                       lwsl_ss_err(hss, "unable to alloc in dsh 3");
+
+                                       return LWSSSSRET_DISCONNECT_ME;
+                               }
+
+                               if (hss)
+                                       _lws_ss_request_tx(hss);
+                       } else {
+
+                               /*
+                                * Client receives some RX from proxy
+                                *
+                                * Pass whatever payload we have to ss user
+                                */
+
+                               h = lws_container_of(par, lws_sspc_handle_t,
+                                                    parser);
+                               h->txc.peer_tx_cr_est -= n;
+
+                               lwsl_sspc_info(h, "P2C RX: len %d", (int)n);
+
+                               if (ssi->rx && client_pss_to_sspc_h(pss, ssi)) {
+                                       /* we still have an sspc handle */
+                                       int ret;
+
+                                       ret = ssi->rx(client_pss_to_userdata(pss),
+                                               (uint8_t *)cp, (unsigned int)n, (int)flags);
+
+                                       if (client_pss_to_sspc_h(pss, ssi) &&
+                                           lws_fi(&client_pss_to_sspc_h(pss, ssi)->fic, "sspc_rx_fake_destroy_me"))
+                                               ret = LWSSSSRET_DESTROY_ME;
+
+                                       switch (ret) {
+                                       case LWSSSSRET_OK:
+                                               break;
+                                       case LWSSSSRET_DISCONNECT_ME:
+                                               goto hangup;
+                                       case LWSSSSRET_DESTROY_ME:
+                                               return LWSSSSRET_DESTROY_ME;
+                                       }
+                               }
+
+#if 0
+                               if (lws_det_lat_active(context)) {
+                                       lws_detlat_t d;
+
+                                       d.type = LDLT_READ;
+                                       d.acc_size = d.req_size = n;
+                                       d.latencies[LAT_DUR_USERCB] =
+                                                       lws_now_usecs() - us;
+                                       d.latencies[LAT_DUR_PROXY_CLIENT_REQ_TO_WRITE] =
+                                                       par->usd_phandling;
+                                       d.latencies[LAT_DUR_PROXY_CLIENT_WRITE_TO_PROXY_RX] =
+                                               us - par->ust_pwait;
+
+                                       lws_det_lat_cb(context, &d);
+                               }
+#endif
+                       }
+
+                       if (n) {
+                               cp += n;
+                               par->rem = (uint16_t)(par->rem - (uint16_t)(unsigned int)n);
+                               len = (len + 1) - (unsigned int)n;
+                               /*
+                                * if we didn't consume it all, we'll come
+                                * around again and produce more dsh entries up
+                                * to 1380 each until it is gone
+                                */
+                       }
+                       if (!par->rem)
+                               par->ps = RPAR_TYPE;
+                       break;
+
+               case RPAR_RX_TXCR_UPDATE:
+                       if (!--par->rem && par->ctr != 3)
+                               goto hangup;
+
+                       par->temp32 = (par->temp32 << 8) | *cp++;
+                       if (++par->ctr < 4)
+                               break;
+
+                       /*
+                        * Proxy is telling us remote endpoint is allowing us
+                        * par->temp32 more bytes tx credit to write to it
+                        */
+
+                       h = lws_container_of(par, lws_sspc_handle_t, parser);
+                       h->txc.tx_cr += par->temp32;
+                       lwsl_info("%s: RX_PEER_TXCR: %d\n", __func__, par->temp32);
+                       lws_sspc_request_tx(h); /* in case something waiting */
+                       par->ctr = 0;
+                       par->ps = RPAR_TYPE;
+                       break;
+
+               case RPAR_INIT_PROVERS:
+                       /* Protocol version byte for this connection */
+                       par->protocol_version = *cp++;
+
+                       /*
+                        * So we have to know what versions of the serialization
+                        * protocol we can support at the proxy side, and
+                        * reject anythng we don't know how to deal with
+                        * noisily in the logs.
+                        */
+
+                       if (par->protocol_version != 1) {
+                               lwsl_err("%s: Rejecting client with "
+                                        "unsupported SSv%d protocol\n",
+                                        __func__, par->protocol_version);
+
+                               goto hangup;
+                       }
+
+                       if (!--par->rem)
+                               goto hangup;
+                       par->ctr = 0;
+                       par->ps = RPAR_INIT_PID;
+                       break;
+
+
+               case RPAR_INIT_PID:
+                       if (!--par->rem)
+                               goto hangup;
+
+                       par->temp32 = (par->temp32 << 8) | *cp++;
+                       if (++par->ctr < 4)
+                               break;
+
+                       par->client_pid = (uint32_t)par->temp32;
+                       par->ctr = 0;
+                       par->ps = RPAR_INITTXC0;
+                       break;
+
+               case RPAR_INITTXC0:
+                       if (!--par->rem)
+                               goto hangup;
+
+                       par->temp32 = (par->temp32 << 8) | *cp++;
+                       if (++par->ctr < 4)
+                               break;
+
+                       par->txcr_out = par->temp32;
+                       par->ctr = 0;
+                       par->ps = RPAR_STREAMTYPE;
+                       break;
+
+               /*
+                * These are the client adjusting our / the remote peer ability
+                * to send back to him. He's sending a signed u32 BE
+                */
+
+               case RPAR_TXCR0:
+
+                       par->temp32 = (par->temp32 << 8) | *cp++;
+                       if (++par->ctr < 4) {
+                               if (!--par->rem)
+                                       goto hangup;
+                               break;
+                       }
+
+                       if (--par->rem)
+                               goto hangup;
+
+                       if (!client) {
+                               /*
+                                * We're the proxy, being told by the client
+                                * that it wants to allow more tx from the peer
+                                * on the onward connection towards it.
+                                */
+#if defined(LWS_ROLE_H2) || defined(LWS_ROLE_MQTT)
+                               if (proxy_pss_to_ss_h(pss) &&
+                                   proxy_pss_to_ss_h(pss)->wsi) {
+                                       lws_wsi_tx_credit(
+                                               proxy_pss_to_ss_h(pss)->wsi,
+                                                         LWSTXCR_PEER_TO_US,
+                                                         par->temp32);
+                                       lwsl_notice("%s: proxy RX_PEER_TXCR: +%d (est %d)\n",
+                                                __func__, par->temp32,
+                                                proxy_pss_to_ss_h(pss)->wsi->
+                                                        txc.peer_tx_cr_est);
+                                       _lws_ss_request_tx(proxy_pss_to_ss_h(pss));
+                               } else
+#endif
+                                       lwsl_info("%s: dropping TXCR\n", __func__);
+                       } else {
+                               /*
+                                * We're the client, being told by the proxy
+                                * about tx credit being given to us from the
+                                * remote peer, allowing the client to write to
+                                * it.
+                                */
+                               h = lws_container_of(par, lws_sspc_handle_t,
+                                                    parser);
+                               h->txc.tx_cr += par->temp32;
+                               lwsl_info("%s: client RX_PEER_TXCR: %d\n",
+                                                       __func__, par->temp32);
+                               lws_sspc_request_tx(h); /* in case something waiting */
+                       }
+                       par->ps = RPAR_TYPE;
+                       break;
+
+               case RPAR_TIMEOUT0:
+
+                       par->temp32 = (par->temp32 << 8) | *cp++;
+                       if (++par->ctr < 4) {
+                               if (!--par->rem)
+                                       goto hangup;
+                               break;
+                       }
+
+                       if (--par->rem)
+                               goto hangup;
+
+                       /*
+                        * Proxy...
+                        *
+                        * *pss may have gone away asynchronously inbetweentimes
+                        */
+
+                       if (proxy_pss_to_ss_h(pss)) {
+
+                               if ((unsigned int)par->temp32 == 0xffffffff) {
+                                       lwsl_notice("%s: cancel ss timeout\n",
+                                                       __func__);
+                                       lws_ss_cancel_timeout(
+                                               proxy_pss_to_ss_h(pss));
+                               } else {
+
+                                       if (!par->temp32)
+                                               par->temp32 = (int)
+                                                  proxy_pss_to_ss_h(pss)->
+                                                          policy->timeout_ms;
+
+                                       lwsl_notice("%s: set ss timeout for +%ums\n",
+                                               __func__, par->temp32);
+
+                                       lws_ss_start_timeout(
+                                               proxy_pss_to_ss_h(pss), (unsigned int)
+                                                               par->temp32);
+                               }
+                       }
+
+                       par->ps = RPAR_TYPE;
+                       break;
+
+               case RPAR_PAYLEN0:
+                       /*
+                        * It's the length from lws_ss_request_tx_len() being
+                        * passed up to the proxy
+                        */
+                       par->temp32 = (par->temp32 << 8) | *cp++;
+                       if (++par->ctr < 4) {
+                               if (!--par->rem)
+                                       goto hangup;
+                               break;
+                       }
+
+                       if (--par->rem)
+                               goto hangup;
+
+                       lwsl_notice("%s: set payload len %u\n", __func__,
+                                   par->temp32);
+
+                       par->ps = RPAR_TYPE;
+
+                       if (proxy_pss_to_ss_h(pss)) {
+                               r = lws_ss_request_tx_len(proxy_pss_to_ss_h(pss),
+                                                       (unsigned long)par->temp32);
+                               if (r == LWSSSSRET_DESTROY_ME)
+                                       goto hangup;
+                       }
+                       break;
+
+               case RPAR_METADATA_NAMELEN:
+                       /* both client and proxy */
+                       if (!--par->rem)
+                               goto hangup;
+                       par->slen = *cp++;
+                       if (par->slen >= sizeof(par->metadata_name) - 1)
+                               goto hangup;
+                       par->ctr = 0;
+                       par->ps++;
+                       break;
+
+               case RPAR_METADATA_NAME:
+                       /* both client and proxy */
+                       if (!--par->rem)
+                               goto hangup;
+                       par->metadata_name[par->ctr++] = (char)*cp++;
+                       if (par->ctr != par->slen)
+                               break;
+                       par->metadata_name[par->ctr] = '\0';
+                       par->ps = RPAR_METADATA_VALUE;
+
+                       if (client) {
+                               lws_sspc_metadata_t *md;
+                               lws_sspc_handle_t *h =
+                                               client_pss_to_sspc_h(pss, ssi);
+
+                               /*
+                                * client side does not have access to policy
+                                * and any metadata are new to it each time,
+                                * we allocate them, removing any existing with
+                                * the same name first
+                                */
+
+                               lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                               lws_dll2_get_head(
+                                                       &h->metadata_owner_rx)) {
+                                       md = lws_container_of(d,
+                                                  lws_sspc_metadata_t, list);
+
+                                       if (!strcmp(md->name,
+                                                   par->metadata_name)) {
+                                               lws_dll2_remove(&md->list);
+                                               lws_free(md);
+                                       }
+
+                               } lws_end_foreach_dll_safe(d, d1);
+
+                               /*
+                                * Create the client's rx metadata entry
+                                */
+
+                               if (h && lws_fi(&h->fic, "sspc_rx_metadata_oom"))
+                                       md = NULL;
+                               else
+                                       md = lws_malloc(sizeof(lws_sspc_metadata_t) +
+                                               par->rem + 1, "rxmeta");
+                               if (!md) {
+                                       lwsl_err("%s: OOM\n", __func__);
+                                       goto hangup;
+                               }
+
+                               if (!h)
+                                       /* coverity */
+                                       goto hangup;
+
+                               memset(md, 0, sizeof(lws_sspc_metadata_t));
+
+                               lws_strncpy(md->name, par->metadata_name,
+                                               sizeof(md->name));
+                               md->len = par->rem;
+                               par->rxmetaval = (uint8_t *)&md[1];
+                               /*
+                                * Overallocate by 1 and put a NUL just beyond
+                                * the official md->len, so value can be easily
+                                * dereferenced safely for NUL-terminated string
+                                * apis that's the most common usage
+                                */
+                               par->rxmetaval[md->len] = '\0';
+                               lws_dll2_add_tail(&md->list,
+                                                 &h->metadata_owner_rx);
+                               par->ctr = 0;
+                               break;
+                       }
+
+                       /* proxy side is receiving it */
+
+                       if (!proxy_pss_to_ss_h(pss))
+                               goto hangup;
+
+                       if (!proxy_pss_to_ss_h(pss)->policy) {
+                               lwsl_err("%s: null policy\n", __func__);
+                               goto hangup;
+                       }
+
+                       /*
+                        * This is the policy's metadata list for the given
+                        * name
+                        */
+                       pm = lws_ss_policy_metadata(
+                                       proxy_pss_to_ss_h(pss)->policy,
+                                       par->metadata_name);
+                       if (!pm) {
+                               lwsl_err("%s: metadata %s not in proxy policy\n",
+                                        __func__, par->metadata_name);
+
+                               goto hangup;
+                       }
+
+                       par->ssmd = lws_ss_get_handle_metadata(
+                                       proxy_pss_to_ss_h(pss),
+                                       par->metadata_name);
+
+                       if (par->ssmd) {
+
+                               if (par->ssmd->value_on_lws_heap)
+                                       lws_free_set_NULL(par->ssmd->value__may_own_heap);
+                               par->ssmd->value_on_lws_heap = 0;
+
+                               if (proxy_pss_to_ss_h(pss) &&
+                                   lws_fi(&proxy_pss_to_ss_h(pss)->fic, "ssproxy_rx_metadata_oom"))
+                                       par->ssmd->value__may_own_heap = NULL;
+                               else
+                                       par->ssmd->value__may_own_heap =
+                                               lws_malloc((unsigned int)par->rem + 1, "metadata");
+
+                               if (!par->ssmd->value__may_own_heap) {
+                                       lwsl_err("%s: OOM mdv\n", __func__);
+                                       goto hangup;
+                               }
+                               par->ssmd->length = par->rem;
+                               ((uint8_t *)par->ssmd->value__may_own_heap)[par->rem] = '\0';
+                               /* mark it as needing cleanup */
+                               par->ssmd->value_on_lws_heap = 1;
+                       }
+                       par->ctr = 0;
+                       break;
+
+               case RPAR_METADATA_VALUE:
+                       /* both client and proxy */
+
+                       if (client) {
+                               *par->rxmetaval++ = *cp++;
+                       } else {
+
+                               if (!par->ssmd) {
+                                       /* we don't recognize the name */
+
+                                       cp++;
+
+                                       if (--par->rem)
+                                               break;
+
+                                       par->ps = RPAR_TYPE;
+                                       break;
+                               }
+
+                               ((uint8_t *)(par->ssmd->value__may_own_heap))[par->ctr++] = *cp++;
+                       }
+
+                       if (--par->rem)
+                               break;
+
+                       /* we think we got all the value */
+                       if (client) {
+                               h = lws_container_of(par, lws_sspc_handle_t, parser);
+                               lwsl_sspc_notice(h, "RX METADATA %s",
+                                                       par->metadata_name);
+                       } else {
+                               lwsl_ss_info(proxy_pss_to_ss_h(pss),
+                                            "RPAR_METADATA_VALUE for %s (len %d)",
+                                            par->ssmd->name,
+                                            (int)par->ssmd->length);
+                               lwsl_hexdump_ss_info(proxy_pss_to_ss_h(pss),
+                                               par->ssmd->value__may_own_heap,
+                                               par->ssmd->length);
+                       }
+                       par->ps = RPAR_TYPE;
+                       break;
+
+               case RPAR_STREAMTYPE:
+
+                       /* only the proxy can get these */
+
+                       if (client)
+                               goto hangup;
+                       if (par->ctr == sizeof(par->streamtype) - 1)
+                               goto hangup;
+
+                       /*
+                        * We can only expect to get this if we ourselves are
+                        * in the state that we're waiting for it.  If it comes
+                        * later it's a protocol error.
+                        */
+
+                       if (*state != LPCSPROX_WAIT_INITIAL_TX)
+                               goto hangup;
+
+                       /*
+                        * We're the proxy, creating an SS on behalf of a
+                        * client
+                        */
+
+                       par->streamtype[par->ctr++] = (char)*cp++;
+                       if (--par->rem)
+                               break;
+
+                       par->ps = RPAR_TYPE;
+                       par->streamtype[par->ctr] = '\0';
+                       lwsl_info("%s: proxy ss '%s', sssv%d, txcr %d\n",
+                                   __func__, par->streamtype,
+                                   par->protocol_version, par->txcr_out);
+
+                       ssi->streamtype = par->streamtype;
+                       if (par->txcr_out) // !!!
+                               ssi->manual_initial_tx_credit = par->txcr_out;
+
+                       /*
+                        * Even for a synthetic SS proxing action like _lws_smd,
+                        * we create an actual SS in the proxy representing the
+                        * connection
+                        */
+
+                       ssi->flags |= LWSSSINFLAGS_PROXIED;
+                       ssi->sss_protocol_version = par->protocol_version;
+                       ssi->client_pid = par->client_pid;
+
+                       if (lws_ss_create(context, 0, ssi, parconn, pss,
+                                         NULL, NULL)) {
+                               /*
+                                * We're unable to create the onward secure
+                                * stream he asked for... schedule a chance to
+                                * inform him
+                                */
+                               lwsl_err("%s: create '%s' fail\n", __func__,
+                                        par->streamtype);
+                               *state = LPCSPROX_REPORTING_FAIL;
+                               break;
+                       } else {
+                               lwsl_debug("%s: create '%s' OK\n",
+                                       __func__, par->streamtype);
+                               *state = LPCSPROX_REPORTING_OK;
+                       }
+
+                       if (*pss) {
+                               (*pss)->being_serialized = 1;
+#if defined(LWS_WITH_SYS_SMD)
+                               if ((*pss)->policy != &pol_smd)
+                                       /*
+                                        * In SMD case we overloaded the
+                                        * initial credit to be the class mask
+                                        */
+#endif
+                               {
+                                       lwsl_info("%s: Created SS initial credit %d\n",
+                                               __func__, par->txcr_out);
+
+                                       (*pss)->info.manual_initial_tx_credit = par->txcr_out;
+                               }
+                       }
+
+                       /* parent needs to schedule write on client conn */
+                       break;
+
+               /* clientside states */
+
+               case RPAR_RESULT_CREATION:
+                       if (*cp++) {
+                               lwsl_err("%s: stream creation failed\n",
+                                        __func__);
+                               goto hangup;
+                       }
+
+                       if (--par->rem < 4)
+                               goto hangup;
+
+                       par->ps = RPAR_RESULT_CREATION_DSH;
+                       par->ctr = 0;
+                       break;
+
+               case RPAR_RESULT_CREATION_DSH:
+
+                       par->temp32 = (par->temp32 << 8) | (*cp++);
+                       if (!par->rem--)
+                               goto hangup;
+                       if (++par->ctr < 4)
+                               break;
+
+                       /*
+                        * Client (par->temp32 == dsh alloc)
+                        */
+
+                       h = lws_container_of(par, lws_sspc_handle_t, parser);
+
+                       lws_ss_serialize_state_transition(h, state,
+                                                         LPCSCLI_LOCAL_CONNECTED);
+
+                       lws_set_timeout(h->cwsi, NO_PENDING_TIMEOUT, 0);
+
+                       if (h->dsh)
+                               goto hangup;
+
+                       /*
+                        * This is telling us that the streamtype could be (and
+                        * was) created at the proxy.  It's not telling us that
+                        * the onward peer connection could be connected.
+                        *
+                        * We'll get a proxied state() coming later that informs
+                        * us about the situation with that.
+                        *
+                        * However at this point, we should choose to inform
+                        * the client that his stream was created... we will
+                        * later get a proxied CREATING state from the peer
+                        * but we should do it now and suppress the later one.
+                        *
+                        * The reason is he may set metadata in CREATING, and
+                        * we will try to do writeables to sync the stream to
+                        * proxy and ultimately bring up the onward connection
+                        * now we are in LOCAL_CONNECTED.  We need to do the
+                        * CREATING now so we'll know the metadata to sync.
+                        */
+
+#if defined(LWS_WITH_SYS_METRICS)
+                       /*
+                        * If any hanging caliper measurement, dump it, and free any tags
+                        */
+                       lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+
+                       if (!h->creating_cb_done) {
+                               if (lws_ss_check_next_state_sspc(h,
+                                                              &h->prev_ss_state,
+                                                              LWSSSCS_CREATING))
+                                       return LWSSSSRET_DESTROY_ME;
+                               h->prev_ss_state = (uint8_t)LWSSSCS_CREATING;
+                               h->creating_cb_done = 1;
+                       } else
+                               h->prev_ss_state = LWSSSCS_DISCONNECTED;
+
+                       if (ssi->state) {
+                               n = ssi->state(client_pss_to_userdata(pss),
+                                              NULL, h->prev_ss_state, 0);
+                               switch (n) {
+                               case LWSSSSRET_OK:
+                                       break;
+                               case LWSSSSRET_DISCONNECT_ME:
+                                       goto hangup;
+                               case LWSSSSRET_DESTROY_ME:
+                                       return LWSSSSRET_DESTROY_ME;
+                               }
+                       }
+
+                       h->dsh = lws_dsh_create(NULL, (size_t)(par->temp32 ?
+                                               par->temp32 : 32768), 1);
+                       if (!h->dsh)
+                               goto hangup;
+
+                       lws_callback_on_writable(h->cwsi);
+
+                       par->rsl_pos = 0;
+                       par->rsl_idx = 0;
+
+                       memset(&h->rideshare_ofs[0], 0, sizeof(h->rideshare_ofs[0]));
+                       h->rideshare_list[0] = '\0';
+                       h->rsidx = 0;
+
+                       /* no rideshare data is OK */
+                       par->ps = RPAR_TYPE;
+
+                       if (par->rem) {
+                               par->ps = RPAR_RESULT_CREATION_RIDESHARE;
+                               if (par->rem >= sizeof(h->rideshare_list))
+                                       goto hangup;
+                       }
+                       break;
+
+               case RPAR_RESULT_CREATION_RIDESHARE:
+                       h = lws_container_of(par, lws_sspc_handle_t, parser);
+                       if (*cp == ',') {
+                               cp++;
+                               h->rideshare_list[par->rsl_pos++] = '\0';
+                               if (par->rsl_idx == LWS_ARRAY_SIZE(h->rideshare_ofs))
+                                       goto hangup;
+                               h->rideshare_ofs[++par->rsl_idx] = par->rsl_pos;
+                       } else
+                               h->rideshare_list[par->rsl_pos++] = (char)*cp++;
+                       if (!--par->rem)
+                               par->ps = RPAR_TYPE;
+                       break;
+
+               case RPAR_STATEINDEX:
+                       par->ctr = (par->ctr << 8) | (*cp++);
+                       if (--par->rem == 4)
+                               par->ps = RPAR_ORD3;
+                       break;
+
+               case RPAR_ORD3:
+                       par->flags = (uint32_t)((*cp++) << 24);
+                       par->ps++;
+                       break;
+
+               case RPAR_ORD2:
+                       par->flags |= (uint32_t)((*cp++) << 16);
+                       par->ps++;
+                       break;
+
+               case RPAR_ORD1:
+                       par->flags |= (uint32_t)((*cp++) << 8);
+                       par->ps++;
+                       break;
+
+               case RPAR_ORD0:
+                       par->flags |= (uint32_t)(*cp++);
+                       par->ps++;
+                       par->ps = RPAR_TYPE;
+
+                       /*
+                        * Client received a proxied state change
+                        */
+
+                       h = client_pss_to_sspc_h(pss, ssi);
+                       if (!h)
+                               /*
+                                * Since we're being informed we need to have
+                                * a stream to inform.  Assume whatever set this
+                                * to NULL has started to close it.
+                                */
+                               break;
+
+                       switch (par->ctr) {
+                       case LWSSSCS_DISCONNECTED:
+                       case LWSSSCS_UNREACHABLE:
+                       case LWSSSCS_AUTH_FAILED:
+                               lws_ss_serialize_state_transition(h, state,
+                                               LPCSCLI_LOCAL_CONNECTED);
+                               h->conn_req_state = LWSSSPC_ONW_NONE;
+                               break;
+
+                       case LWSSSCS_CONNECTED:
+                               lwsl_sspc_info(h, "CONNECTED %s",
+                                                       ssi->streamtype);
+                               if (*state == LPCSCLI_OPERATIONAL)
+                                       /*
+                                        * Don't allow to see connected more
+                                        * than once for one connection
+                                        */
+                                       goto swallow;
+
+                               lws_ss_serialize_state_transition(h, state,
+                                                       LPCSCLI_OPERATIONAL);
+
+                               h->conn_req_state = LWSSSPC_ONW_CONN;
+                               break;
+                       case LWSSSCS_TIMEOUT:
+                               break;
+                       default:
+                               break;
+                       }
+
+                       if (par->ctr < 0)
+                               goto hangup;
+
+#if defined(_DEBUG)
+                       lwsl_sspc_info(h, "forwarding proxied state %s",
+                                       lws_ss_state_name(par->ctr));
+#endif
+
+                       if (par->ctr == LWSSSCS_CREATING) {
+                               h = lws_container_of(par, lws_sspc_handle_t, parser);
+                               if (h->creating_cb_done)
+                                       /*
+                                        * We have told him he's CREATING when
+                                        * we heard we had linked up to the
+                                        * proxy, so suppress the remote
+                                        * CREATING so that he only sees it once
+                                        */
+                               break;
+
+                               h->creating_cb_done = 1;
+                       }
+
+                       if (ssi->state) {
+                               h = lws_container_of(par, lws_sspc_handle_t, parser);
+                               lws_ss_constate_t cs = (lws_ss_constate_t)par->ctr;
+
+                               if (cs == LWSSSCS_CONNECTED)
+                                       h->ss_dangling_connected = 1;
+                               if (cs == LWSSSCS_DISCONNECTED)
+                                       h->ss_dangling_connected = 0;
+
+                               if (lws_ss_check_next_state_sspc(h,
+                                                           &h->prev_ss_state, cs))
+                                       return LWSSSSRET_DESTROY_ME;
+
+                               if (cs < LWSSSCS_USER_BASE)
+                                       h->prev_ss_state = (uint8_t)cs;
+
+                               h->h_in_svc = h;
+                               n = ssi->state(client_pss_to_userdata(pss),
+                                       NULL, cs, par->flags);
+                               h->h_in_svc = NULL;
+                               switch (n) {
+                               case LWSSSSRET_OK:
+                                       break;
+                               case LWSSSSRET_DISCONNECT_ME:
+                                       goto hangup;
+                               case LWSSSSRET_DESTROY_ME:
+                                       return LWSSSSRET_DESTROY_ME;
+                               }
+                       }
+
+swallow:
+                       break;
+
+               default:
+                       goto hangup;
+               }
+       }
+
+       return LWSSSSRET_OK;
+
+hangup:
+
+       lwsl_cx_notice(context, "hangup");
+
+       return LWSSSSRET_DISCONNECT_ME;
+}
diff --git a/lib/secure-streams/secure-streams.c b/lib/secure-streams/secure-streams.c
new file mode 100644 (file)
index 0000000..489543d
--- /dev/null
@@ -0,0 +1,1839 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+static const struct ss_pcols *ss_pcols[] = {
+#if defined(LWS_ROLE_H1)
+       &ss_pcol_h1,            /* LWSSSP_H1 */
+#else
+       NULL,
+#endif
+#if defined(LWS_ROLE_H2)
+       &ss_pcol_h2,            /* LWSSSP_H2 */
+#else
+       NULL,
+#endif
+#if defined(LWS_ROLE_WS)
+       &ss_pcol_ws,            /* LWSSSP_WS */
+#else
+       NULL,
+#endif
+#if defined(LWS_ROLE_MQTT)
+       &ss_pcol_mqtt,          /* LWSSSP_MQTT */
+#else
+       NULL,
+#endif
+       &ss_pcol_raw,           /* LWSSSP_RAW */
+       NULL,
+};
+
+static const char *state_names[] = {
+       "(unset)",
+       "LWSSSCS_CREATING",
+       "LWSSSCS_DISCONNECTED",
+       "LWSSSCS_UNREACHABLE",
+       "LWSSSCS_AUTH_FAILED",
+       "LWSSSCS_CONNECTED",
+       "LWSSSCS_CONNECTING",
+       "LWSSSCS_DESTROYING",
+       "LWSSSCS_POLL",
+       "LWSSSCS_ALL_RETRIES_FAILED",
+       "LWSSSCS_QOS_ACK_REMOTE",
+       "LWSSSCS_QOS_NACK_REMOTE",
+       "LWSSSCS_QOS_ACK_LOCAL",
+       "LWSSSCS_QOS_NACK_LOCAL",
+       "LWSSSCS_TIMEOUT",
+       "LWSSSCS_SERVER_TXN",
+       "LWSSSCS_SERVER_UPGRADE",
+       "LWSSSCS_EVENT_WAIT_CANCELLED",
+       "LWSSSCS_UPSTREAM_LINK_RETRY",
+};
+
+/*
+ * For each "current state", set bit offsets for valid "next states".
+ *
+ * Since there are complicated ways to arrive at state transitions like proxying
+ * and asynchronous destruction etc, so we monitor the state transitions we are
+ * giving the ss user code to ensure we never deliver illegal state transitions
+ * (because we will assert if we have bugs that do it)
+ */
+
+const uint32_t ss_state_txn_validity[] = {
+
+       /* if we was last in this state...  we can legally go to these states */
+
+       [0]                             = (1 << LWSSSCS_CREATING) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_CREATING]              = (1 << LWSSSCS_CONNECTING) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_POLL) |
+                                         (1 << LWSSSCS_SERVER_UPGRADE) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_DISCONNECTED]          = (1 << LWSSSCS_CONNECTING) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_POLL) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_UNREACHABLE]           = (1 << LWSSSCS_ALL_RETRIES_FAILED) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_POLL) |
+                                         (1 << LWSSSCS_CONNECTING) |
+                                         /* win conn failure > retry > succ */
+                                         (1 << LWSSSCS_CONNECTED) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_AUTH_FAILED]           = (1 << LWSSSCS_ALL_RETRIES_FAILED) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_CONNECTING) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_CONNECTED]             = (1 << LWSSSCS_SERVER_UPGRADE) |
+                                         (1 << LWSSSCS_SERVER_TXN) |
+                                         (1 << LWSSSCS_AUTH_FAILED) |
+                                         (1 << LWSSSCS_QOS_ACK_REMOTE) |
+                                         (1 << LWSSSCS_QOS_NACK_REMOTE) |
+                                         (1 << LWSSSCS_QOS_ACK_LOCAL) |
+                                         (1 << LWSSSCS_QOS_NACK_LOCAL) |
+                                         (1 << LWSSSCS_DISCONNECTED) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_POLL) | /* proxy retry */
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_CONNECTING]            = (1 << LWSSSCS_UNREACHABLE) |
+                                         (1 << LWSSSCS_AUTH_FAILED) |
+                                         (1 << LWSSSCS_CONNECTING) |
+                                         (1 << LWSSSCS_CONNECTED) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_POLL) |
+                                         (1 << LWSSSCS_DISCONNECTED) | /* proxy retry */
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_DESTROYING]            = 0,
+
+       [LWSSSCS_POLL]                  = (1 << LWSSSCS_CONNECTING) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_ALL_RETRIES_FAILED]    = (1 << LWSSSCS_CONNECTING) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_QOS_ACK_REMOTE]        = (1 << LWSSSCS_DISCONNECTED) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+#if defined(LWS_ROLE_MQTT)
+                                         (1 << LWSSSCS_QOS_ACK_REMOTE) |
+#endif
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_QOS_NACK_REMOTE]       = (1 << LWSSSCS_DISCONNECTED) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_QOS_ACK_LOCAL]         = (1 << LWSSSCS_DISCONNECTED) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_QOS_NACK_LOCAL]        = (1 << LWSSSCS_DESTROYING) |
+                                         (1 << LWSSSCS_TIMEOUT),
+
+       /* he can get the timeout at any point and take no action... */
+       [LWSSSCS_TIMEOUT]               = (1 << LWSSSCS_CONNECTING) |
+                                         (1 << LWSSSCS_CONNECTED) |
+                                         (1 << LWSSSCS_QOS_ACK_REMOTE) |
+                                         (1 << LWSSSCS_QOS_NACK_REMOTE) |
+                                         (1 << LWSSSCS_POLL) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_DISCONNECTED) |
+                                         (1 << LWSSSCS_UNREACHABLE) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_SERVER_TXN]            = (1 << LWSSSCS_DISCONNECTED) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_DESTROYING),
+
+       [LWSSSCS_SERVER_UPGRADE]        = (1 << LWSSSCS_SERVER_TXN) |
+                                         (1 << LWSSSCS_TIMEOUT) |
+                                         (1 << LWSSSCS_DISCONNECTED) |
+                                         (1 << LWSSSCS_DESTROYING),
+};
+
+#if defined(LWS_WITH_CONMON)
+
+/*
+ * Convert any conmon data to JSON and attach to the ss handle.
+ */
+
+lws_ss_state_return_t
+lws_conmon_ss_json(lws_ss_handle_t *h)
+{
+       char ads[48], *end, *buf, *obuf;
+       const struct addrinfo *ai;
+       lws_ss_state_return_t ret = LWSSSSRET_OK;
+       struct lws_conmon cm;
+       size_t len = 500;
+
+       if (!h->policy || !(h->policy->flags & LWSSSPOLF_PERF) || !h->wsi ||
+           h->wsi->perf_done)
+               return LWSSSSRET_OK;
+
+       if (h->conmon_json)
+               lws_free_set_NULL(h->conmon_json);
+
+       h->conmon_json = lws_malloc(len, __func__);
+       if (!h->conmon_json)
+               return LWSSSSRET_OK;
+
+       obuf = buf = h->conmon_json;
+       end = buf + len - 1;
+
+       lws_conmon_wsi_take(h->wsi, &cm);
+
+       lws_sa46_write_numeric_address(&cm.peer46, ads, sizeof(ads));
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                    "{\"peer\":\"%s\","
+                     "\"dns_us\":%u,"
+                     "\"dns_disp\":%u,"
+                     "\"sockconn_us\":%u,"
+                     "\"tls_us\":%u,"
+                     "\"txn_resp_us\":%u,"
+                     "\"dns\":[",
+                   ads,
+                   (unsigned int)cm.ciu_dns,
+                   (unsigned int)cm.dns_disposition,
+                   (unsigned int)cm.ciu_sockconn,
+                   (unsigned int)cm.ciu_tls,
+                   (unsigned int)cm.ciu_txn_resp);
+
+       ai = cm.dns_results_copy;
+       while (ai) {
+               lws_sa46_write_numeric_address((lws_sockaddr46 *)ai->ai_addr, ads, sizeof(ads));
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "\"%s\"", ads);
+               if (ai->ai_next && buf < end - 2)
+                       *buf++ = ',';
+               ai = ai->ai_next;
+       }
+
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "]");
+
+       switch (cm.pcol) {
+       case LWSCONMON_PCOL_HTTP:
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                          ",\"prot_specific\":{\"protocol\":\"http\",\"resp\":%u}",
+                          (unsigned int)cm.protocol_specific.http.response);
+               break;
+       default:
+               break;
+       }
+
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "}");
+
+       /*
+        * This destroys the DNS list in the lws_conmon that we took
+        * responsibility for when we used lws_conmon_wsi_take()
+        */
+
+       lws_conmon_release(&cm);
+
+       h->conmon_len = (uint16_t)lws_ptr_diff(buf, obuf);
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       if (h->proxy_onward) {
+
+               /*
+                * ask to forward it on the proxy link
+                */
+
+               ss_proxy_onward_link_req_writeable(h);
+               return LWSSSSRET_OK;
+       }
+#endif
+
+       /*
+        * We can deliver it directly
+        */
+
+       if (h->info.rx)
+               ret = h->info.rx(ss_to_userobj(h), (uint8_t *)h->conmon_json,
+                                (unsigned int)h->conmon_len,
+                                (int)(LWSSS_FLAG_SOM | LWSSS_FLAG_EOM |
+                                                LWSSS_FLAG_PERF_JSON));
+
+       lws_free_set_NULL(h->conmon_json);
+
+       return ret;
+}
+#endif
+
+int
+lws_ss_check_next_state(lws_lifecycle_t *lc, uint8_t *prevstate,
+                       lws_ss_constate_t cs)
+{
+       if (cs >= LWSSSCS_USER_BASE ||
+           cs == LWSSSCS_EVENT_WAIT_CANCELLED ||
+           cs == LWSSSCS_SERVER_TXN ||
+           cs == LWSSSCS_UPSTREAM_LINK_RETRY)
+               /*
+                * we can't judge user or transient states, leave the old state
+                * and just wave them through
+                */
+               return 0;
+
+       if (cs >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
+               /* we don't recognize this state as usable */
+               lwsl_err("%s: %s: bad new state %u\n", __func__, lc->gutag, cs);
+               assert(0);
+               return 1;
+       }
+
+       if (*prevstate >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
+               /* existing state is broken */
+               lwsl_err("%s: %s: bad existing state %u\n", __func__,
+                        lc->gutag, (unsigned int)*prevstate);
+               assert(0);
+               return 1;
+       }
+
+       if (ss_state_txn_validity[*prevstate] & (1u << cs)) {
+
+               lwsl_notice("%s: %s: %s -> %s\n", __func__, lc->gutag,
+                           lws_ss_state_name((int)*prevstate),
+                           lws_ss_state_name((int)cs));
+
+               /* this is explicitly allowed, update old state to new */
+               *prevstate = (uint8_t)cs;
+
+               return 0;
+       }
+
+       lwsl_err("%s: %s: transition from %s -> %s is illegal\n", __func__,
+                lc->gutag, lws_ss_state_name((int)*prevstate),
+                lws_ss_state_name((int)cs));
+
+       assert(0);
+
+       return 1;
+}
+
+int
+lws_ss_check_next_state_ss(lws_ss_handle_t *ss, uint8_t *prevstate,
+                          lws_ss_constate_t cs)
+{
+       if (cs >= LWSSSCS_USER_BASE ||
+           cs == LWSSSCS_EVENT_WAIT_CANCELLED ||
+           cs == LWSSSCS_UPSTREAM_LINK_RETRY)
+               /*
+                * we can't judge user or transient states, leave the old state
+                * and just wave them through
+                */
+               return 0;
+
+       if (cs >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
+               /* we don't recognize this state as usable */
+               lwsl_ss_err(ss, "bad new state %u", cs);
+               assert(0);
+               return 1;
+       }
+
+       if (*prevstate >= LWS_ARRAY_SIZE(ss_state_txn_validity)) {
+               /* existing state is broken */
+               lwsl_ss_err(ss, "bad existing state %u",
+                               (unsigned int)*prevstate);
+               assert(0);
+               return 1;
+       }
+
+       if (ss_state_txn_validity[*prevstate] & (1u << cs)) {
+
+               lwsl_ss_notice(ss, "%s -> %s",
+                              lws_ss_state_name((int)*prevstate),
+                              lws_ss_state_name((int)cs));
+
+               /* this is explicitly allowed, update old state to new */
+               *prevstate = (uint8_t)cs;
+
+               return 0;
+       }
+
+       lwsl_ss_err(ss, "transition from %s -> %s is illegal",
+                   lws_ss_state_name((int)*prevstate),
+                   lws_ss_state_name((int)cs));
+
+       assert(0);
+
+       return 1;
+}
+
+const char *
+lws_ss_state_name(int state)
+{
+       if (state >= LWSSSCS_USER_BASE)
+               return "user state";
+
+       if (state >= (int)LWS_ARRAY_SIZE(state_names))
+               return "unknown";
+
+       return state_names[state];
+}
+
+lws_ss_state_return_t
+lws_ss_event_helper(lws_ss_handle_t *h, lws_ss_constate_t cs)
+{
+       lws_ss_state_return_t r;
+
+       if (!h)
+               return LWSSSSRET_OK;
+
+       if (lws_ss_check_next_state_ss(h, &h->prev_ss_state, cs))
+               return LWSSSSRET_DESTROY_ME;
+
+       if (cs == LWSSSCS_CONNECTED)
+               h->ss_dangling_connected = 1;
+       if (cs == LWSSSCS_DISCONNECTED)
+               h->ss_dangling_connected = 0;
+
+#if defined(LWS_WITH_SEQUENCER)
+       /*
+        * A parent sequencer for the ss is optional, if we have one, keep it
+        * informed of state changes on the ss connection
+        */
+       if (h->seq && cs != LWSSSCS_DESTROYING)
+               lws_seq_queue_event(h->seq, LWSSEQ_SS_STATE_BASE + cs,
+                                   (void *)h, NULL);
+#endif
+
+       if (h->info.state) {
+               h->h_in_svc = h;
+               r = h->info.state(ss_to_userobj(h), NULL, cs,
+                       cs == LWSSSCS_UNREACHABLE &&
+                       h->wsi && h->wsi->dns_reachability);
+               h->h_in_svc = NULL;
+#if defined(LWS_WITH_SERVER)
+               if ((h->info.flags & LWSSSINFLAGS_ACCEPTED) &&
+                   cs == LWSSSCS_DISCONNECTED)
+                       r = LWSSSSRET_DESTROY_ME;
+#endif
+               return r;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+int
+_lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(lws_ss_state_return_t r, struct lws *wsi,
+                        lws_ss_handle_t **ph)
+{
+       if (r == LWSSSSRET_DESTROY_ME) {
+               lwsl_info("%s: DESTROY ME: %s, %s\n", __func__,
+                               lws_wsi_tag(wsi), lws_ss_tag(*ph));
+               if (wsi) {
+                       lws_set_opaque_user_data(wsi, NULL);
+                       lws_set_timeout(wsi, 1, LWS_TO_KILL_ASYNC);
+               } else {
+                       if ((*ph)->wsi) {
+                               lws_set_opaque_user_data((*ph)->wsi, NULL);
+                               lws_set_timeout((*ph)->wsi, 1, LWS_TO_KILL_ASYNC);
+                       }
+               }
+               (*ph)->wsi = NULL;
+               lws_ss_destroy(ph);
+       }
+
+       return -1; /* close connection */
+}
+
+static void
+lws_ss_timeout_sul_check_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_ss_state_return_t r;
+       lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, sul);
+
+       lwsl_info("%s: retrying %s after backoff\n", __func__, lws_ss_tag(h));
+       /* we want to retry... */
+       h->seqstate = SSSEQ_DO_RETRY;
+
+       r = _lws_ss_request_tx(h);
+       _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, NULL, &h);
+}
+
+int
+lws_ss_exp_cb_metadata(void *priv, const char *name, char *out, size_t *pos,
+                       size_t olen, size_t *exp_ofs)
+{
+       lws_ss_handle_t *h = (lws_ss_handle_t *)priv;
+       const char *replace = NULL;
+       size_t total, budget;
+       lws_ss_metadata_t *md = lws_ss_policy_metadata(h->policy, name),
+                         *hmd = lws_ss_get_handle_metadata(h, name);
+
+       if (!md) {
+               lwsl_err("%s: Unknown metadata %s\n", __func__, name);
+
+               return LSTRX_FATAL_NAME_UNKNOWN;
+       }
+
+       if (!hmd)
+               return LSTRX_FILLED_OUT;
+
+       replace = hmd->value__may_own_heap;
+
+       if (!replace)
+               return LSTRX_DONE;
+
+       total = hmd->length;
+
+       budget = olen - *pos;
+       total -= *exp_ofs;
+       if (total < budget)
+               budget = total;
+
+       if (out)
+               memcpy(out + *pos, replace + (*exp_ofs), budget);
+       *exp_ofs += budget;
+       *pos += budget;
+
+       if (budget == total)
+               return LSTRX_DONE;
+
+       return LSTRX_FILLED_OUT;
+}
+
+int
+lws_ss_set_timeout_us(lws_ss_handle_t *h, lws_usec_t us)
+{
+       struct lws_context_per_thread *pt = &h->context->pt[h->tsi];
+
+       h->sul.cb = lws_ss_timeout_sul_check_cb;
+       __lws_sul_insert_us(&pt->pt_sul_owner[
+                   !!(h->policy->flags & LWSSSPOLF_WAKE_SUSPEND__VALIDITY)],
+                   &h->sul, us);
+
+       return 0;
+}
+
+lws_ss_state_return_t
+_lws_ss_backoff(lws_ss_handle_t *h, lws_usec_t us_override)
+{
+       uint64_t ms;
+       char conceal;
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (h->seqstate == SSSEQ_RECONNECT_WAIT)
+               return LWSSSSRET_OK;
+
+       /* figure out what we should do about another retry */
+
+       lwsl_info("%s: %s: retry backoff after failure\n", __func__, lws_ss_tag(h));
+       ms = lws_retry_get_delay_ms(h->context, h->policy->retry_bo,
+                                   &h->retry, &conceal);
+       if (!conceal) {
+               lwsl_info("%s: %s: abandon conn attempt \n",__func__, lws_ss_tag(h));
+
+               if (h->seqstate == SSSEQ_IDLE) /* been here? */
+                       return LWSSSSRET_OK;
+
+               h->seqstate = SSSEQ_IDLE;
+
+               return lws_ss_event_helper(h, LWSSSCS_ALL_RETRIES_FAILED);
+       }
+
+       /* Only increase our planned backoff, or go with it */
+
+       if (us_override < (lws_usec_t)ms * LWS_US_PER_MS)
+               us_override = (lws_usec_t)(ms * LWS_US_PER_MS);
+
+       h->seqstate = SSSEQ_RECONNECT_WAIT;
+       lws_ss_set_timeout_us(h, us_override);
+
+       lwsl_info("%s: %s: retry wait %dms\n", __func__, lws_ss_tag(h),
+                                                 (int)(us_override / 1000));
+
+       return LWSSSSRET_OK;
+}
+
+lws_ss_state_return_t
+lws_ss_backoff(lws_ss_handle_t *h)
+{
+       return _lws_ss_backoff(h, 0);
+}
+
+#if defined(LWS_WITH_SYS_SMD)
+
+/*
+ * Local SMD <-> SS
+ *
+ * We pass received messages through to the SS handler synchronously, using the
+ * lws service thread context.
+ *
+ * After the SS is created and registered, still nothing is going to come here
+ * until the peer sends us his rx_class_mask and we update his registration with
+ * it, because from SS creation his rx_class_mask defaults to 0.
+ */
+
+static int
+lws_smd_ss_cb(void *opaque, lws_smd_class_t _class,
+             lws_usec_t timestamp, void *buf, size_t len)
+{
+       lws_ss_handle_t *h = (lws_ss_handle_t *)opaque;
+       uint8_t *p = (uint8_t *)buf - LWS_SMD_SS_RX_HEADER_LEN;
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       /*
+        * When configured with SS enabled, lws over-allocates
+        * LWS_SMD_SS_RX_HEADER_LEN bytes behind the payload of the queued
+        * message, for prepending serialized class and timestamp data in-band
+        * with the payload.
+        */
+
+       lws_ser_wu64be(p, _class);
+       lws_ser_wu64be(p + 8, (uint64_t)timestamp);
+
+       if (h->info.rx)
+               h->info.rx((void *)&h[1], p, len + LWS_SMD_SS_RX_HEADER_LEN,
+                     LWSSS_FLAG_SOM | LWSSS_FLAG_EOM);
+
+       return 0;
+}
+
+static void
+lws_ss_smd_tx_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, u.smd.sul_write);
+       uint8_t buf[LWS_SMD_SS_RX_HEADER_LEN + LWS_SMD_MAX_PAYLOAD], *p;
+       size_t len = sizeof(buf);
+       lws_smd_class_t _class;
+       int flags = 0, n;
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (!h->info.tx)
+               return;
+
+       n = h->info.tx(&h[1], h->txord++, buf, &len, &flags);
+       if (n)
+               /* nonzero return means don't want to send anything */
+               return;
+
+       // lwsl_notice("%s: (SS %p bound to _lws_smd creates message) tx len %d\n", __func__, h, (int)len);
+       // lwsl_hexdump_notice(buf, len);
+
+       assert(len >= LWS_SMD_SS_RX_HEADER_LEN);
+       _class = (lws_smd_class_t)lws_ser_ru64be(buf);
+       p = lws_smd_msg_alloc(h->context, _class, len - LWS_SMD_SS_RX_HEADER_LEN);
+       if (!p) {
+               // this can be rejected if nobody listening for this class
+               //lwsl_notice("%s: failed to alloc\n", __func__);
+               return;
+       }
+
+       memcpy(p, buf + LWS_SMD_SS_RX_HEADER_LEN, len - LWS_SMD_SS_RX_HEADER_LEN);
+       if (lws_smd_msg_send(h->context, p)) {
+               lwsl_notice("%s: failed to queue\n", __func__);
+               return;
+       }
+}
+
+#endif
+
+lws_ss_state_return_t
+_lws_ss_client_connect(lws_ss_handle_t *h, int is_retry, void *conn_if_sspc_onw)
+{
+       const char *prot, *_prot, *ipath, *_ipath, *ads, *_ads;
+       struct lws_client_connect_info i;
+       const struct ss_pcols *ssp;
+       size_t used_in, used_out;
+       union lws_ss_contemp ct;
+       lws_ss_state_return_t r;
+       int port, _port, tls;
+       char *path, ep[96];
+       lws_strexp_t exp;
+       struct lws *wsi;
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (!h->policy) {
+               lwsl_err("%s: ss with no policy\n", __func__);
+
+               return LWSSSSRET_OK;
+       }
+
+       /*
+        * We are already bound to a sink?
+        */
+
+//     if (h->h_sink)
+//             return 0;
+
+       if (!is_retry)
+               h->retry = 0;
+
+#if defined(LWS_WITH_SYS_SMD)
+       if (h->policy == &pol_smd) {
+
+               if (h->u.smd.smd_peer)
+                       return LWSSSSRET_OK;
+
+               // lwsl_notice("%s: received connect for _lws_smd, registering for class mask 0x%x\n",
+               //              __func__, h->info.manual_initial_tx_credit);
+
+               h->u.smd.smd_peer = lws_smd_register(h->context, h,
+                                       (h->info.flags & LWSSSINFLAGS_PROXIED) ?
+                                               LWSSMDREG_FLAG_PROXIED_SS : 0,
+                                       (lws_smd_class_t)h->info.manual_initial_tx_credit,
+                                       lws_smd_ss_cb);
+               if (!h->u.smd.smd_peer)
+                       return LWSSSSRET_TX_DONT_SEND;
+
+               if (lws_ss_event_helper(h, LWSSSCS_CONNECTING))
+                       return LWSSSSRET_TX_DONT_SEND;
+
+               if (lws_ss_event_helper(h, LWSSSCS_CONNECTED))
+                       return LWSSSSRET_TX_DONT_SEND;
+               return LWSSSSRET_OK;
+       }
+#endif
+
+       /*
+        * We're going to substitute ${metadata} in the endpoint at connection-
+        * time, so this can be set dynamically...
+        */
+
+       lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, ep, sizeof(ep));
+
+       if (lws_strexp_expand(&exp, h->policy->endpoint,
+                             strlen(h->policy->endpoint),
+                             &used_in, &used_out) != LSTRX_DONE) {
+               lwsl_err("%s: address strexp failed\n", __func__);
+
+               return LWSSSSRET_TX_DONT_SEND;
+       }
+
+       /*
+        * ... in some cases, we might want the user to be able to override
+        * some policy settings by what he provided in there.  For example,
+        * if he set the endpoint to "https://myendpoint.com:4443/mypath" it
+        * might be quite convenient to override the policy to follow the info
+        * that was given for at least server, port and the url path.
+        */
+
+       _port = port = h->policy->port;
+       _prot = prot = NULL;
+       _ipath = ipath = "";
+       _ads = ads = ep;
+
+       if (strchr(ep, ':') &&
+           !lws_parse_uri(ep, &_prot, &_ads, &_port, &_ipath)) {
+               lwsl_debug("%s: using uri parse results '%s' '%s' %d '%s'\n",
+                               __func__, _prot, _ads, _port, _ipath);
+               prot = _prot;
+               ads = _ads;
+               port = _port;
+               ipath = _ipath;
+       }
+
+       memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
+       i.context = h->context;
+       tls = !!(h->policy->flags & LWSSSPOLF_TLS);
+
+       if (prot && (!strcmp(prot, "http") || !strcmp(prot, "ws") ||
+                    !strcmp(prot, "mqtt")))
+               tls = 0;
+
+       if (tls) {
+               lwsl_info("%s: using tls\n", __func__);
+               i.ssl_connection = LCCSCF_USE_SSL;
+
+               if (!h->policy->trust.store)
+                       lwsl_info("%s: using platform trust store\n", __func__);
+               else {
+
+                       i.vhost = lws_get_vhost_by_name(h->context,
+                                       h->policy->trust.store->name);
+                       if (!i.vhost) {
+                               lwsl_err("%s: missing vh for policy %s\n",
+                                        __func__,
+                                        h->policy->trust.store->name);
+
+                               return -1;
+                       }
+               }
+       }
+
+       if (h->policy->flags & LWSSSPOLF_WAKE_SUSPEND__VALIDITY)
+               i.ssl_connection |= LCCSCF_WAKE_SUSPEND__VALIDITY;
+
+       /* translate policy attributes to IP ToS flags */
+
+       if (h->policy->flags & LWSSSPOLF_ATTR_LOW_LATENCY)
+               i.ssl_connection |= LCCSCF_IP_LOW_LATENCY;
+       if (h->policy->flags & LWSSSPOLF_ATTR_HIGH_THROUGHPUT)
+               i.ssl_connection |= LCCSCF_IP_HIGH_THROUGHPUT;
+       if (h->policy->flags & LWSSSPOLF_ATTR_HIGH_RELIABILITY)
+               i.ssl_connection |= LCCSCF_IP_HIGH_RELIABILITY;
+       if (h->policy->flags & LWSSSPOLF_ATTR_LOW_COST)
+               i.ssl_connection |= LCCSCF_IP_LOW_COST;
+       if (h->policy->flags & LWSSSPOLF_PERF) /* collect conmon stats on this */
+               i.ssl_connection |= LCCSCF_CONMON;
+
+       /* mark the connection with the streamtype priority from the policy */
+
+       i.priority = h->policy->priority;
+
+       i.ssl_connection |= LCCSCF_SECSTREAM_CLIENT;
+
+       if (conn_if_sspc_onw) {
+               i.ssl_connection |= LCCSCF_SECSTREAM_PROXY_ONWARD;
+               h->conn_if_sspc_onw = conn_if_sspc_onw;
+       }
+
+
+       i.address               = ads;
+       i.port                  = port;
+       i.host                  = i.address;
+       i.origin                = i.address;
+       i.opaque_user_data      = h;
+       i.seq                   = h->seq;
+       i.retry_and_idle_policy = h->policy->retry_bo;
+       i.sys_tls_client_cert   = h->policy->client_cert;
+
+       i.path                  = ipath;
+               /* if this is not "", munge should use it instead of policy
+                * url path
+                */
+
+       ssp = ss_pcols[(int)h->policy->protocol];
+       if (!ssp) {
+               lwsl_err("%s: unsupported protocol\n", __func__);
+
+               return LWSSSSRET_TX_DONT_SEND;
+       }
+       i.alpn = ssp->alpn;
+
+       /*
+        * For http, we can get the method from the http object, override in
+        * the protocol-specific munge callback below if not http
+        */
+       i.method = h->policy->u.http.method;
+       i.protocol = ssp->protocol->name; /* lws protocol name */
+       i.local_protocol_name = i.protocol;
+
+       path = lws_malloc(h->context->max_http_header_data, __func__);
+       if (!path) {
+               lwsl_warn("%s: OOM on path prealloc\n", __func__);
+               return LWSSSSRET_TX_DONT_SEND;
+       }
+
+       if (ssp->munge) /* eg, raw doesn't use; endpoint strexp already done */
+               ssp->munge(h, path, h->context->max_http_header_data, &i, &ct);
+
+       i.pwsi = &h->wsi;
+
+#if defined(LWS_WITH_SSPLUGINS)
+       if (h->policy->plugins[0] && h->policy->plugins[0]->munge)
+               h->policy->plugins[0]->munge(h, path, h->context->max_http_header_data);
+#endif
+
+       lwsl_info("%s: connecting %s, '%s' '%s' %s\n", __func__, i.method,
+                       i.alpn, i.address, i.path);
+
+#if defined(LWS_WITH_SYS_METRICS)
+       /* possibly already hanging connect retry... */
+       if (!h->cal_txn.mt)
+               lws_metrics_caliper_bind(h->cal_txn, h->context->mth_ss_conn);
+
+       if (h->policy->streamtype)
+               lws_metrics_tag_add(&h->cal_txn.mtags_owner, "ss",
+                                   h->policy->streamtype);
+#endif
+
+       h->txn_ok = 0;
+       r = lws_ss_event_helper(h, LWSSSCS_CONNECTING);
+       if (r) {
+               lws_free(path);
+               return r;
+       }
+
+       h->inside_connect = 1;
+       h->pending_ret = LWSSSSRET_OK;
+       wsi = lws_client_connect_via_info(&i);
+       h->inside_connect = 0;
+       lws_free(path);
+       if (!wsi) {
+               /*
+                * We already found that we could not connect, without even
+                * having to go around the event loop
+                */
+
+               if (h->pending_ret)
+                       return h->pending_ret;
+
+               if (h->prev_ss_state != LWSSSCS_UNREACHABLE &&
+                   h->prev_ss_state != LWSSSCS_ALL_RETRIES_FAILED) {
+                       /*
+                        * blocking DNS failure can get to unreachable via
+                        * CCE, and unreachable can get to ALL_RETRIES_FAILED
+                        */
+                       r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
+                       if (r)
+                               return r;
+
+                       r = lws_ss_backoff(h);
+                       if (r)
+                               return r;
+               }
+
+               return LWSSSSRET_TX_DONT_SEND;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+lws_ss_state_return_t
+lws_ss_client_connect(lws_ss_handle_t *h)
+{
+       lws_ss_state_return_t r;
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       r = _lws_ss_client_connect(h, 0, 0);
+
+       return r;
+}
+
+/*
+ * Public API
+ */
+
+/*
+ * Create either a stream or a sink
+ */
+
+int
+lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
+             void *opaque_user_data, lws_ss_handle_t **ppss,
+             struct lws_sequencer *seq_owner, const char **ppayload_fmt)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       const lws_ss_policy_t *pol;
+       lws_ss_state_return_t r;
+       lws_ss_metadata_t *smd;
+       lws_ss_handle_t *h;
+       size_t size;
+       void **v;
+       char *p;
+       int n;
+
+       lws_service_assert_loop_thread(context, tsi);
+
+#if defined(LWS_WITH_SECURE_STREAMS_CPP)
+       pol = ssi->policy;
+       if (!pol) {
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+               lws_fi_ctx_t temp_fic;
+
+               /*
+                * We have to do a temp inherit from context to find out
+                * early if we are supposed to inject a fault concealing
+                * the policy
+                */
+
+               memset(&temp_fic, 0, sizeof(temp_fic));
+               lws_xos_init(&temp_fic.xos, lws_xos(&context->fic.xos));
+               lws_fi_inherit_copy(&temp_fic, &context->fic, "ss", ssi->streamtype);
+
+               if (lws_fi(&temp_fic, "ss_no_streamtype_policy"))
+                       pol = NULL;
+               else
+                       pol = lws_ss_policy_lookup(context, ssi->streamtype);
+
+               lws_fi_destroy(&temp_fic);
+#else
+               pol = lws_ss_policy_lookup(context, ssi->streamtype);
+#endif
+               if (!pol) {
+                       lwsl_cx_info(context, "unknown stream type %s",
+                                 ssi->streamtype);
+                       return 1;
+               }
+#if defined(LWS_WITH_SECURE_STREAMS_CPP)
+       }
+#endif
+
+#if 0
+       if (ssi->flags & LWSSSINFLAGS_REGISTER_SINK) {
+               /*
+                * This can register a secure streams sink as well as normal
+                * secure streams connections.  If that's what's happening,
+                * confirm the policy agrees that this streamtype should be
+                * directed to a sink.
+                */
+               if (!(pol->flags & LWSSSPOLF_LOCAL_SINK)) {
+                       /*
+                        * Caller wanted to create a sink for this streamtype,
+                        * but the policy does not agree the streamtype should
+                        * be routed to a local sink.
+                        */
+                       lwsl_err("%s: %s policy does not allow local sink\n",
+                                __func__, ssi->streamtype);
+
+                       return 1;
+               }
+       } else {
+
+               if (!(pol->flags & LWSSSPOLF_LOCAL_SINK)) {
+
+               }
+//             lws_dll2_foreach_safe(&pt->ss_owner, NULL, lws_ss_destroy_dll);
+       }
+#endif
+
+       /*
+        * We overallocate and point to things in the overallocation...
+        *
+        * 1) the user_alloc from the stream info
+        * 2) network auth plugin instantiation data
+        * 3) stream auth plugin instantiation data
+        * 4) as many metadata pointer structs as the policy tells
+        * 5) the streamtype name (length is not aligned)
+        *
+        * ... when we come to destroy it, just one free to do.
+        */
+
+       size = sizeof(*h) + ssi->user_alloc +
+                       (ssi->streamtype ? strlen(ssi->streamtype): 0) + 1;
+#if defined(LWS_WITH_SSPLUGINS)
+       if (pol->plugins[0])
+               size += pol->plugins[0]->alloc;
+       if (pol->plugins[1])
+               size += pol->plugins[1]->alloc;
+#endif
+       size += pol->metadata_count * sizeof(lws_ss_metadata_t);
+
+       h = lws_zalloc(size, __func__);
+       if (!h)
+               return 2;
+
+       h->lc.log_cx = context->log_cx;
+
+       if (ssi->sss_protocol_version)
+               __lws_lc_tag(context, &context->lcg[LWSLCG_WSI_SS_CLIENT],
+                            &h->lc, "%s|v%u|%u",
+                            ssi->streamtype ? ssi->streamtype : "nostreamtype",
+                            (unsigned int)ssi->sss_protocol_version,
+                            (unsigned int)ssi->client_pid);
+       else
+               __lws_lc_tag(context, &context->lcg[LWSLCG_WSI_SS_CLIENT],
+                            &h->lc, "%s",
+                            ssi->streamtype ? ssi->streamtype : "nostreamtype");
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       h->fic.name = "ss";
+       lws_xos_init(&h->fic.xos, lws_xos(&context->fic.xos));
+       if (ssi->fic.fi_owner.count)
+               lws_fi_import(&h->fic, &ssi->fic);
+
+       lws_fi_inherit_copy(&h->fic, &context->fic, "ss", ssi->streamtype);
+#endif
+
+       h->info = *ssi;
+       h->policy = pol;
+       h->context = context;
+       h->tsi = (uint8_t)tsi;
+       h->seq = seq_owner;
+
+       if (h->info.flags & LWSSSINFLAGS_PROXIED)
+               h->proxy_onward = 1;
+
+       /* start of overallocated area */
+       p = (char *)&h[1];
+
+       /* set the handle pointer in the user data struct */
+       v = (void **)(p + ssi->handle_offset);
+       *v = h;
+
+       /* set the opaque user data in the user data struct */
+       v = (void **)(p + ssi->opaque_user_data_offset);
+       *v = opaque_user_data;
+
+       p += ssi->user_alloc;
+
+#if defined(LWS_WITH_SSPLUGINS)
+       if (pol->plugins[0]) {
+               h->nauthi = p;
+               p += pol->plugins[0]->alloc;
+       }
+       if (pol->plugins[1]) {
+               h->sauthi = p;
+               p += pol->plugins[1]->alloc;
+       }
+#endif
+
+       if (pol->metadata_count) {
+               h->metadata = (lws_ss_metadata_t *)p;
+               p += pol->metadata_count * sizeof(lws_ss_metadata_t);
+
+               lwsl_cx_info(context, "%s metadata count %d",
+                         pol->streamtype, pol->metadata_count);
+       }
+
+       smd = pol->metadata;
+       for (n = 0; n < pol->metadata_count; n++) {
+               h->metadata[n].name = smd->name;
+               if (n + 1 == pol->metadata_count)
+                       h->metadata[n].next = NULL;
+               else
+                       h->metadata[n].next = &h->metadata[n + 1];
+               smd = smd->next;
+       }
+
+       if (ssi->streamtype)
+               memcpy(p, ssi->streamtype, strlen(ssi->streamtype) + 1);
+       /* don't mark accepted ss as being the server */
+       if (ssi->flags & LWSSSINFLAGS_SERVER)
+               h->info.flags &= (uint8_t)~LWSSSINFLAGS_SERVER;
+       h->info.streamtype = p;
+
+       lws_pt_lock(pt, __func__);
+       lws_dll2_add_head(&h->list, &pt->ss_owner);
+       lws_pt_unlock(pt);
+
+       if (ppss)
+               *ppss = h;
+
+       if (ppayload_fmt)
+               *ppayload_fmt = pol->payload_fmt;
+
+       if (ssi->flags & LWSSSINFLAGS_SERVER)
+               /*
+                * return early for accepted connection flow
+                */
+               return 0;
+
+#if defined(LWS_WITH_SYS_SMD)
+       /*
+        * For a local Secure Streams connection
+        */
+       if (!(ssi->flags & LWSSSINFLAGS_PROXIED) &&
+           pol == &pol_smd) {
+
+               /*
+                * So he has asked to be wired up to SMD over a SS link.
+                * Register him as an smd participant in his own right.
+                *
+                * Just for this case, ssi->manual_initial_tx_credit is used
+                * to set the rx class mask (this is part of the SS serialization
+                * format as well)
+                */
+               h->u.smd.smd_peer = lws_smd_register(context, h, 0,
+                                                    (lws_smd_class_t)ssi->manual_initial_tx_credit,
+                                                    lws_smd_ss_cb);
+               if (!h->u.smd.smd_peer || lws_fi(&h->fic, "ss_create_smd"))
+                       goto fail_creation;
+               lwsl_cx_info(context, "registered SS SMD");
+       }
+#endif
+
+#if defined(LWS_WITH_SERVER)
+       if (h->policy->flags & LWSSSPOLF_SERVER) {
+               const struct lws_protocols *pprot[3], **ppp = &pprot[0];
+               struct lws_context_creation_info i;
+               struct lws_vhost *vho = NULL;
+
+               lwsl_cx_info(context, "creating server");
+
+               if (h->policy->endpoint &&
+                   h->policy->endpoint[0] == '!') {
+                       /*
+                        * There's already a vhost existing that we want to
+                        * bind to, we don't have to specify and create one.
+                        *
+                        * The vhost must enable any protocols that we want.
+                        */
+
+                       vho = lws_get_vhost_by_name(context,
+                                                   &h->policy->endpoint[1]);
+                       if (!vho || lws_fi(&h->fic, "ss_create_vhost")) {
+                               lwsl_err("%s: no vhost %s\n", __func__,
+                                               &h->policy->endpoint[1]);
+                               goto fail_creation;
+                       }
+
+                       goto extant;
+               }
+
+               /*
+                * This streamtype represents a server, we're being asked to
+                * instantiate a corresponding vhost for it
+                */
+
+               memset(&i, 0, sizeof i);
+
+               i.iface         = h->policy->endpoint;
+               i.vhost_name    = h->policy->streamtype;
+               i.port          = h->policy->port;
+
+               if (i.iface && i.iface[0] == '+') {
+                       i.iface++;
+                       i.options |= LWS_SERVER_OPTION_UNIX_SOCK;
+               }
+
+               if (!ss_pcols[h->policy->protocol] ||
+                   lws_fi(&h->fic, "ss_create_pcol")) {
+                       lwsl_err("%s: unsupp protocol", __func__);
+                       goto fail_creation;
+               }
+
+               *ppp++ = ss_pcols[h->policy->protocol]->protocol;
+#if defined(LWS_ROLE_WS)
+               if (h->policy->u.http.u.ws.subprotocol)
+                       /*
+                        * He names a ws subprotocol, ie, we want to support
+                        * ss-ws protocol in this vhost
+                        */
+                       *ppp++ = &protocol_secstream_ws;
+#endif
+               *ppp = NULL;
+               i.pprotocols = pprot;
+
+#if defined(LWS_WITH_TLS)
+               if (h->policy->flags & LWSSSPOLF_TLS) {
+                       i.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+                       i.server_ssl_cert_mem =
+                               h->policy->trust.server.cert->ca_der;
+                       i.server_ssl_cert_mem_len = (unsigned int)
+                               h->policy->trust.server.cert->ca_der_len;
+                       i.server_ssl_private_key_mem =
+                               h->policy->trust.server.key->ca_der;
+                       i.server_ssl_private_key_mem_len = (unsigned int)
+                               h->policy->trust.server.key->ca_der_len;
+               }
+#endif
+
+               if (!lws_fi(&h->fic, "ss_srv_vh_fail"))
+                       vho = lws_create_vhost(context, &i);
+               else
+                       vho = NULL;
+               if (!vho) {
+                       lwsl_cx_err(context, "failed to create vh");
+                       goto fail_creation;
+               }
+
+extant:
+
+               /*
+                * Mark this vhost as having to apply ss server semantics to
+                * any incoming accepted connection
+                */
+               vho->ss_handle = h;
+
+               r = lws_ss_event_helper(h, LWSSSCS_CREATING);
+               lwsl_cx_info(context, "CREATING returned status %d", (int)r);
+               if (r == LWSSSSRET_DESTROY_ME ||
+                   lws_fi(&h->fic, "ss_create_destroy_me"))
+                       goto fail_creation;
+
+               lwsl_cx_notice(context, "created server %s",
+                               h->policy->streamtype);
+
+               return 0;
+       }
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+
+       /*
+        * For static policy case, dynamically ref / instantiate the related
+        * trust store and vhost.  We do it by logical ss rather than connection
+        * because we don't want to expose the latency of creating the x.509
+        * trust store at the first connection.
+        *
+        * But it might be given the tls linkup takes time anyway, it can move
+        * to the ss connect code instead.
+        */
+
+       if (!lws_ss_policy_ref_trust_store(context, h->policy, 1 /* do the ref */) ||
+           lws_fi(&h->fic, "ss_create_no_ts")) {
+               lwsl_err("%s: unable to get vhost / trust store\n", __func__);
+               goto fail_creation;
+       }
+#else
+#if defined(LWS_WITH_SECURE_STREAMS_CPP)
+        if (!ssi->streamtype &&
+           !lws_ss_policy_ref_trust_store(context, h->policy, 1 /* do the ref */)) {
+               lwsl_err("%s: unable to get vhost / trust store\n", __func__);
+               goto fail_creation;
+       }
+#endif
+#endif
+
+       r = lws_ss_event_helper(h, LWSSSCS_CREATING);
+       lwsl_ss_info(h, "CREATING returned status %d", (int)r);
+       if (r == LWSSSSRET_DESTROY_ME ||
+           lws_fi(&h->fic, "ss_create_destroy_me"))
+               goto fail_creation;
+
+#if defined(LWS_WITH_SYS_SMD)
+       if (!(ssi->flags & LWSSSINFLAGS_PROXIED) &&
+           pol == &pol_smd) {
+               r = lws_ss_event_helper(h, LWSSSCS_CONNECTING);
+               if (r || lws_fi(&h->fic, "ss_create_smd_1"))
+                       goto fail_creation;
+               r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
+               if (r || lws_fi(&h->fic, "ss_create_smd_2"))
+                       goto fail_creation;
+       }
+#endif
+
+       if (!(ssi->flags & LWSSSINFLAGS_REGISTER_SINK) &&
+           ((h->policy->flags & LWSSSPOLF_NAILED_UP)
+#if defined(LWS_WITH_SYS_SMD)
+               || ((h->policy == &pol_smd) //&&
+                   //(ssi->flags & LWSSSINFLAGS_PROXIED))
+                               )
+#endif
+                           )) {
+               r = _lws_ss_client_connect(h, 0, 0);
+               if (lws_fi(&h->fic, "ss_create_conn"))
+                       r = LWSSSSRET_DESTROY_ME;
+               switch (r) {
+               case LWSSSSRET_OK:
+                       break;
+               case LWSSSSRET_TX_DONT_SEND:
+               case LWSSSSRET_DISCONNECT_ME:
+                       if (lws_ss_backoff(h) == LWSSSSRET_DESTROY_ME)
+                               goto fail_creation;
+                       break;
+               case LWSSSSRET_DESTROY_ME:
+                       goto fail_creation;
+               }
+       }
+
+       return 0;
+
+fail_creation:
+
+       if (ppss)
+               *ppss = NULL;
+
+       lws_ss_destroy(&h);
+
+       return 1;
+}
+
+void *
+lws_ss_to_user_object(struct lws_ss_handle *h)
+{
+       return (void *)&h[1];
+}
+
+void
+lws_ss_destroy(lws_ss_handle_t **ppss)
+{
+       struct lws_context_per_thread *pt;
+#if defined(LWS_WITH_SERVER)
+       struct lws_vhost *v = NULL;
+#endif
+       lws_ss_handle_t *h = *ppss;
+       lws_ss_metadata_t *pmd;
+
+       if (!h)
+               return;
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (h == h->h_in_svc) {
+               lwsl_err("%s: illegal destroy, return LWSSSSRET_DESTROY_ME instead\n",
+                               __func__);
+               assert(0);
+               return;
+       }
+
+       if (h->destroying) {
+               lwsl_info("%s: reentrant destroy\n", __func__);
+               return;
+       }
+       h->destroying = 1;
+
+#if defined(LWS_WITH_CONMON)
+       if (h->conmon_json)
+               lws_free_set_NULL(h->conmon_json);
+#endif
+
+       if (h->wsi) {
+               /*
+                * Don't let the wsi point to us any more,
+                * we (the ss object bound to the wsi) are going away now
+                */
+               lws_set_opaque_user_data(h->wsi, NULL);
+               lws_set_timeout(h->wsi, 1, LWS_TO_KILL_SYNC);
+       }
+
+       /*
+        * if we bound an smd registration to the SS, unregister it
+        */
+
+#if defined(LWS_WITH_SYS_SMD)
+       if (h->policy == &pol_smd) {
+               lws_sul_cancel(&h->u.smd.sul_write);
+
+               if (h->u.smd.smd_peer) {
+                       lws_smd_unregister(h->u.smd.smd_peer);
+                       h->u.smd.smd_peer = NULL;
+               }
+       }
+#endif
+
+       pt = &h->context->pt[h->tsi];
+
+       lws_pt_lock(pt, __func__);
+       *ppss = NULL;
+       lws_dll2_remove(&h->list);
+#if defined(LWS_WITH_SERVER)
+               lws_dll2_remove(&h->cli_list);
+#endif
+       lws_dll2_remove(&h->to_list);
+       lws_sul_cancel(&h->sul_timeout);
+
+       /*
+        * for lss, DESTROYING deletes the C++ lss object, making the
+        * self-defined h->policy radioactive
+        */
+
+#if defined(LWS_WITH_SERVER)
+       if (h->policy && (h->policy->flags & LWSSSPOLF_SERVER))
+               v = lws_get_vhost_by_name(h->context, h->policy->streamtype);
+#endif
+
+       /*
+        * Since we also come here to unpick create, it's possible we failed
+        * the creation before issuing any states, even CREATING.  We should
+        * only issue cleanup states on destroy if we previously got as far as
+        * issuing CREATING.
+        */
+
+       if (h->prev_ss_state) {
+               if (h->ss_dangling_connected)
+                       (void)lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
+
+               (void)lws_ss_event_helper(h, LWSSSCS_DESTROYING);
+       }
+
+       lws_pt_unlock(pt);
+
+       /* in proxy case, metadata value on heap may need cleaning up */
+
+       pmd = h->metadata;
+       while (pmd) {
+               lwsl_info("%s: pmd %p\n", __func__, pmd);
+               if (pmd->value_on_lws_heap)
+                       lws_free_set_NULL(pmd->value__may_own_heap);
+
+               pmd = pmd->next;
+       }
+
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       {
+
+               lws_ss_metadata_t *imd;
+              
+               pmd = h->instant_metadata;
+
+               while (pmd) {
+                       imd = pmd;
+                       pmd = pmd->next;
+
+                       lwsl_info("%s: instant md %p\n", __func__, imd);
+                       lws_free(imd);
+               }
+               h->instant_metadata = NULL;
+
+               if (h->imd_ac)
+                       lwsac_free(&h->imd_ac);
+       }
+#endif
+
+       lws_sul_cancel(&h->sul);
+
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+
+       /*
+        * For static policy case, dynamically ref / instantiate the related
+        * trust store and vhost.  We do it by logical ss rather than connection
+        * because we don't want to expose the latency of creating the x.509
+        * trust store at the first connection.
+        *
+        * But it might be given the tls linkup takes time anyway, it can move
+        * to the ss connect code instead.
+        */
+
+       if (h->policy)
+               lws_ss_policy_unref_trust_store(h->context, h->policy);
+#else
+#if defined(LWS_WITH_SECURE_STREAMS_CPP)
+       if (!h->info.streamtype || !*(h->info.streamtype))
+               lws_ss_policy_unref_trust_store(h->context, h->policy);
+#endif
+#endif
+
+#if defined(LWS_WITH_SERVER)
+       if (v)
+               /*
+                * For server, the policy describes a vhost that implements the
+                * server, when we take down the ss, we take down the related
+                * vhost (if it got that far)
+                */
+               lws_vhost_destroy(v);
+#endif
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       lws_fi_destroy(&h->fic);
+#endif
+
+#if defined(LWS_WITH_SYS_METRICS)
+       /*
+        * If any hanging caliper measurement, dump it, and free any tags
+        */
+       lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
+#endif
+
+       lws_sul_cancel(&h->sul_timeout);
+
+       /* confirm no sul left scheduled in handle or user allocation object */
+       lws_sul_debug_zombies(h->context, h, sizeof(*h) + h->info.user_alloc,
+                             __func__);
+
+       __lws_lc_untag(h->context, &h->lc);
+
+       lws_explicit_bzero((void *)h, sizeof(*h) + h->info.user_alloc);
+
+       lws_free_set_NULL(h);
+}
+
+#if defined(LWS_WITH_SERVER)
+void
+lws_ss_server_ack(struct lws_ss_handle *h, int nack)
+{
+       h->txn_resp = nack;
+       h->txn_resp_set = 1;
+}
+
+void
+lws_ss_server_foreach_client(struct lws_ss_handle *h, lws_sssfec_cb cb,
+                            void *arg)
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, h->src_list.head) {
+               struct lws_ss_handle *h =
+                       lws_container_of(d, struct lws_ss_handle, cli_list);
+
+               cb(h, arg);
+
+       } lws_end_foreach_dll_safe(d, d1);
+}
+#endif
+
+lws_ss_state_return_t
+lws_ss_request_tx(lws_ss_handle_t *h)
+{
+       lws_ss_state_return_t r;
+
+       r = _lws_ss_request_tx(h);
+
+       return r;
+}
+
+lws_ss_state_return_t
+_lws_ss_request_tx(lws_ss_handle_t *h)
+{
+       lws_ss_state_return_t r;
+
+       // lwsl_notice("%s: h %p, wsi %p\n", __func__, h, h->wsi);
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (h->wsi) {
+               lws_callback_on_writable(h->wsi);
+
+               return LWSSSSRET_OK;
+       }
+
+       if (!h->policy) {
+               /* avoid crash */
+               lwsl_err("%s: null policy\n", __func__);
+               return LWSSSSRET_OK;
+       }
+
+       if (h->policy->flags & LWSSSPOLF_SERVER)
+               return LWSSSSRET_OK;
+
+       /*
+        * there's currently no wsi / connection associated with the ss handle
+        */
+
+#if defined(LWS_WITH_SYS_SMD)
+       if (h->policy == &pol_smd) {
+               /*
+                * He's an _lws_smd... and no wsi... since we're just going
+                * to queue it, we could call his tx() right here, but rather
+                * than surprise him let's set a sul to do it next time around
+                * the event loop
+                */
+
+               lws_sul_schedule(h->context, 0, &h->u.smd.sul_write,
+                                lws_ss_smd_tx_cb, 1);
+
+               return LWSSSSRET_OK;
+       }
+#endif
+
+       if (h->seqstate != SSSEQ_IDLE &&
+           h->seqstate != SSSEQ_DO_RETRY)
+               return LWSSSSRET_OK;
+
+       h->seqstate = SSSEQ_TRY_CONNECT;
+       r = lws_ss_event_helper(h, LWSSSCS_POLL);
+       if (r)
+               return r;
+
+       /*
+        * Retries operate via lws_ss_request_tx(), explicitly ask for a
+        * reconnection to clear the retry limit
+        */
+       r = _lws_ss_client_connect(h, 1, 0);
+       if (r == LWSSSSRET_DESTROY_ME)
+               return r;
+
+       if (r)
+               return lws_ss_backoff(h);
+
+       return LWSSSSRET_OK;
+}
+
+lws_ss_state_return_t
+lws_ss_request_tx_len(lws_ss_handle_t *h, unsigned long len)
+{
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (h->wsi && h->policy &&
+           (h->policy->protocol == LWSSSP_H1 ||
+            h->policy->protocol == LWSSSP_H2 ||
+            h->policy->protocol == LWSSSP_WS))
+               h->wsi->http.writeable_len = len;
+       else
+               h->writeable_len = len;
+
+       return lws_ss_request_tx(h);
+}
+
+/*
+ * private helpers
+ */
+
+/* used on context destroy when iterating listed lws_ss on a pt */
+
+int
+lws_ss_destroy_dll(struct lws_dll2 *d, void *user)
+{
+       lws_ss_handle_t *h = lws_container_of(d, lws_ss_handle_t, list);
+
+       lws_ss_destroy(&h);
+
+       return 0;
+}
+
+int
+lws_ss_cancel_notify_dll(struct lws_dll2 *d, void *user)
+{
+       lws_ss_handle_t *h = lws_container_of(d, lws_ss_handle_t, list);
+
+       if (lws_ss_event_helper(h, LWSSSCS_EVENT_WAIT_CANCELLED))
+               lwsl_warn("%s: cancel event ignores return\n", __func__);
+
+       return 0;
+}
+
+struct lws_sequencer *
+lws_ss_get_sequencer(lws_ss_handle_t *h)
+{
+       return h->seq;
+}
+
+struct lws_context *
+lws_ss_get_context(struct lws_ss_handle *h)
+{
+       return h->context;
+}
+
+const char *
+lws_ss_rideshare(struct lws_ss_handle *h)
+{
+       if (!h->rideshare)
+               return h->policy->streamtype;
+
+       return h->rideshare->streamtype;
+}
+
+int
+lws_ss_add_peer_tx_credit(struct lws_ss_handle *h, int32_t bump)
+{
+       const struct ss_pcols *ssp;
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       ssp = ss_pcols[(int)h->policy->protocol];
+
+       if (h->wsi && ssp && ssp->tx_cr_add)
+               return ssp->tx_cr_add(h, bump);
+
+       return 0;
+}
+
+int
+lws_ss_get_est_peer_tx_credit(struct lws_ss_handle *h)
+{
+       const struct ss_pcols *ssp;
+
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       ssp = ss_pcols[(int)h->policy->protocol];
+
+       if (h->wsi && ssp && ssp->tx_cr_add)
+               return ssp->tx_cr_est(h);
+
+       return 0;
+}
+
+/*
+ * protocol-independent handler for ss timeout
+ */
+
+static void
+lws_ss_to_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_ss_handle_t *h = lws_container_of(sul, lws_ss_handle_t, sul_timeout);
+       lws_ss_state_return_t r;
+
+       lwsl_info("%s: %s timeout fired\n", __func__, lws_ss_tag(h));
+
+       r = lws_ss_event_helper(h, LWSSSCS_TIMEOUT);
+       if (r != LWSSSSRET_DISCONNECT_ME && r != LWSSSSRET_DESTROY_ME)
+               return;
+
+       if (h->wsi)
+               lws_set_timeout(h->wsi, 1, LWS_TO_KILL_ASYNC);
+
+       _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, h->wsi, &h);
+}
+
+void
+lws_ss_start_timeout(struct lws_ss_handle *h, unsigned int timeout_ms)
+{
+       lws_service_assert_loop_thread(h->context, h->tsi);
+
+       if (!timeout_ms && !h->policy->timeout_ms)
+               return;
+
+       lws_sul_schedule(h->context, 0, &h->sul_timeout, lws_ss_to_cb,
+                        (timeout_ms ? timeout_ms : h->policy->timeout_ms) *
+                        LWS_US_PER_MS);
+}
+
+void
+lws_ss_cancel_timeout(struct lws_ss_handle *h)
+{
+       lws_service_assert_loop_thread(h->context, h->tsi);
+       lws_sul_cancel(&h->sul_timeout);
+}
+
+void
+lws_ss_change_handlers(struct lws_ss_handle *h,
+       lws_ss_state_return_t (*rx)(void *userobj, const uint8_t *buf,
+                                   size_t len, int flags),
+       lws_ss_state_return_t (*tx)(void *userobj, lws_ss_tx_ordinal_t ord,
+                                   uint8_t *buf, size_t *len, int *flags),
+       lws_ss_state_return_t (*state)(void *userobj, void *h_src /* ss handle type */,
+                                      lws_ss_constate_t state,
+                                      lws_ss_tx_ordinal_t ack))
+{
+       if (rx)
+               h->info.rx = rx;
+       if (tx)
+               h->info.tx = tx;
+       if (state)
+               h->info.state = state;
+}
+
+const char *
+lws_ss_tag(struct lws_ss_handle *h)
+{
+       if (!h)
+               return "[null ss]";
+       return lws_lc_tag(&h->lc);
+}
+
+struct lws_log_cx *
+lwsl_ss_get_cx(struct lws_ss_handle *ss)
+{
+       if (!ss)
+               return NULL;
+
+       return ss->lc.log_cx;
+}
+
+void
+lws_log_prepend_ss(struct lws_log_cx *cx, void *obj, char **p, char *e)
+{
+       struct lws_ss_handle *h = (struct lws_ss_handle *)obj;
+
+       *p += lws_snprintf(*p, lws_ptr_diff_size_t(e, (*p)), "%s: ",
+                       lws_ss_tag(h));
+}
+
+#if defined(_DEBUG)
+void
+lws_ss_assert_extant(struct lws_context *cx, int tsi, struct lws_ss_handle *h)
+{
+       struct lws_context_per_thread *pt = &cx->pt[tsi];
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, pt->ss_owner.head) {
+               struct lws_ss_handle *h1 = lws_container_of(d,
+                                               struct lws_ss_handle, list);
+
+               if (h == h1)
+                       return; /* okay */
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       /*
+        * The ss handle is not listed in the pt ss handle owner...
+        */
+
+       assert(0);
+}
+#endif
diff --git a/lib/secure-streams/system/auth-api.amazon.com/auth.c b/lib/secure-streams/system/auth-api.amazon.com/auth.c
new file mode 100644 (file)
index 0000000..af297d8
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * LWA auth support for Secure Streams
+ *
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+typedef struct ss_api_amazon_auth {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+       struct lejp_ctx         jctx;
+       size_t                  pos;
+       int                     expires_secs;
+} ss_api_amazon_auth_t;
+
+static const char * const lejp_tokens_lwa[] = {
+       "access_token",
+       "expires_in",
+};
+
+typedef enum {
+       LSSPPT_ACCESS_TOKEN,
+       LSSPPT_EXPIRES_IN,
+} lejp_tokens_t;
+
+enum {
+       AUTH_IDX_LWA,
+       AUTH_IDX_ROOT,
+};
+
+static void
+lws_ss_sys_auth_api_amazon_com_kick(lws_sorted_usec_list_t *sul)
+{
+       struct lws_context *context = lws_container_of(sul, struct lws_context,
+                                                      sul_api_amazon_com_kick);
+
+       lws_state_transition_steps(&context->mgr_system,
+                                  LWS_SYSTATE_OPERATIONAL);
+}
+
+static void
+lws_ss_sys_auth_api_amazon_com_renew(lws_sorted_usec_list_t *sul)
+{
+       struct lws_context *context = lws_container_of(sul, struct lws_context,
+                                                      sul_api_amazon_com);
+
+       lws_ss_sys_auth_api_amazon_com(context);
+}
+
+static signed char
+auth_api_amazon_com_parser_cb(struct lejp_ctx *ctx, char reason)
+{
+       ss_api_amazon_auth_t *m = (ss_api_amazon_auth_t *)ctx->user;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       lws_system_blob_t *blob;
+
+       if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
+               return 0;
+
+       switch (ctx->path_match - 1) {
+       case LSSPPT_ACCESS_TOKEN:
+               if (!ctx->npos)
+                       break;
+
+               blob = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH,
+                                          AUTH_IDX_LWA);
+               if (!blob)
+                       return -1;
+
+               if (lws_system_blob_heap_append(blob,
+                                               (const uint8_t *)ctx->buf,
+                                               ctx->npos)) {
+                       lwsl_err("%s: unable to store auth token\n", __func__);
+
+                       return -1;
+               }
+               break;
+       case LSSPPT_EXPIRES_IN:
+               m->expires_secs = atoi(ctx->buf);
+               lws_sul_schedule(context, 0, &context->sul_api_amazon_com,
+                                lws_ss_sys_auth_api_amazon_com_renew,
+                                (lws_usec_t)m->expires_secs * LWS_US_PER_SEC);
+               break;
+       }
+
+       return 0;
+}
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+ss_api_amazon_auth_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       ss_api_amazon_auth_t *m = (ss_api_amazon_auth_t *)userobj;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       lws_system_blob_t *ab;
+#if !defined(LWS_WITH_NO_LOGS)
+       size_t total;
+#endif
+       int n;
+
+       ab = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, AUTH_IDX_LWA);
+       /* coverity */
+       if (!ab)
+               return LWSSSSRET_DISCONNECT_ME;
+
+       if (buf) {
+               if (flags & LWSSS_FLAG_SOM) {
+                       lejp_construct(&m->jctx, auth_api_amazon_com_parser_cb,
+                                      m, lejp_tokens_lwa,
+                                      LWS_ARRAY_SIZE(lejp_tokens_lwa));
+                       lws_system_blob_heap_empty(ab);
+               }
+
+               n = lejp_parse(&m->jctx, buf, (int)len);
+               if (n < 0) {
+                       lejp_destruct(&m->jctx);
+                       lws_system_blob_destroy(
+                               lws_system_get_blob(context,
+                                                   LWS_SYSBLOB_TYPE_AUTH,
+                                                   AUTH_IDX_LWA));
+
+                       return LWSSSSRET_DISCONNECT_ME;
+               }
+       }
+       if (!(flags & LWSSS_FLAG_EOM))
+               return LWSSSSRET_OK;
+
+       /* we should have the auth token now */
+
+#if !defined(LWS_WITH_NO_LOGS)
+       total = lws_system_blob_get_size(ab);
+       lwsl_notice("%s: acquired %u-byte api.amazon.com auth token, exp %ds\n",
+                       __func__, (unsigned int)total, m->expires_secs);
+#endif
+
+       lejp_destruct(&m->jctx);
+
+       /* we move the system state at auth connection close */
+
+       return LWSSSSRET_DISCONNECT_ME;
+}
+
+static lws_ss_state_return_t
+ss_api_amazon_auth_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                     size_t *len, int *flags)
+{
+       ss_api_amazon_auth_t *m = (ss_api_amazon_auth_t *)userobj;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       lws_system_blob_t *ab;
+       size_t total;
+       int n;
+
+       /*
+        * We send out auth slot AUTH_IDX_ROOT, it's the LWA user / device
+        * identity token
+        */
+
+       ab = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, AUTH_IDX_ROOT);
+       if (!ab)
+               return LWSSSSRET_DESTROY_ME;
+
+       total = lws_system_blob_get_size(ab);
+
+       n = lws_system_blob_get(ab, buf, len, m->pos);
+       if (n < 0)
+               return LWSSSSRET_TX_DONT_SEND;
+
+       if (!m->pos)
+               *flags |= LWSSS_FLAG_SOM;
+
+       m->pos += *len;
+
+       if (m->pos == total) {
+               *flags |= LWSSS_FLAG_EOM;
+               m->pos = 0; /* for next time */
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+ss_api_amazon_auth_state(void *userobj, void *sh, lws_ss_constate_t state,
+                        lws_ss_tx_ordinal_t ack)
+{
+       ss_api_amazon_auth_t *m = (ss_api_amazon_auth_t *)userobj;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       lws_system_blob_t *ab;
+       size_t s;
+
+       lwsl_info("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
+                 (unsigned int)ack);
+
+       ab = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, AUTH_IDX_ROOT);
+       /* coverity */
+       if (!ab)
+               return LWSSSSRET_DESTROY_ME;
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               //if (lws_ss_set_metadata(m->ss, "ctype", "application/json", 16))
+               //      return LWSSSSRET_DESTROY_ME;
+               /* fallthru */
+       case LWSSSCS_CONNECTING:
+               s = lws_system_blob_get_size(ab);
+               if (!s)
+                       lwsl_debug("%s: no auth blob\n", __func__);
+               m->pos = 0;
+               return lws_ss_request_tx_len(m->ss, (unsigned long)s);
+
+       case LWSSSCS_DISCONNECTED:
+               /*
+                * We defer moving the system state forward until we have
+                * closed our connection + tls for the auth action... this is
+                * because on small systems, we need that memory recovered
+                * before we can make another connection subsequently.
+                *
+                * At this point, we're ultimately being called from within
+                * the wsi close process, the tls tunnel is not freed yet.
+                * Use a sul to actually do it next time around the event loop
+                * when the close process for the auth wsi has completed and
+                * the related tls is already freed.
+                */
+               s = lws_system_blob_get_size(ab);
+
+               if (s && context->mgr_system.state != LWS_SYSTATE_OPERATIONAL)
+                       lws_sul_schedule(context, 0,
+                                        &context->sul_api_amazon_com_kick,
+                                        lws_ss_sys_auth_api_amazon_com_kick, 1);
+
+               context->hss_auth = NULL;
+               return LWSSSSRET_DESTROY_ME;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+int
+lws_ss_sys_auth_api_amazon_com(struct lws_context *context)
+{
+       lws_ss_info_t ssi;
+
+       if (context->hss_auth) /* already exists */
+               return 0;
+
+       /* We're making an outgoing secure stream ourselves */
+
+       memset(&ssi, 0, sizeof(ssi));
+       ssi.handle_offset           = offsetof(ss_api_amazon_auth_t, ss);
+       ssi.opaque_user_data_offset = offsetof(ss_api_amazon_auth_t, opaque_data);
+       ssi.rx                      = ss_api_amazon_auth_rx;
+       ssi.tx                      = ss_api_amazon_auth_tx;
+       ssi.state                   = ss_api_amazon_auth_state;
+       ssi.user_alloc              = sizeof(ss_api_amazon_auth_t);
+       ssi.streamtype              = "api_amazon_com_auth";
+
+       if (lws_ss_create(context, 0, &ssi, context, &context->hss_auth,
+                         NULL, NULL)) {
+               lwsl_info("%s: Create LWA auth ss failed (policy?)\n", __func__);
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/lib/secure-streams/system/auth-sigv4/sign.c b/lib/secure-streams/system/auth-sigv4/sign.c
new file mode 100644 (file)
index 0000000..b1c2bf2
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ * Sigv4 support for Secure Streams
+ *
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2020 Andy Green <andy@warmcat.com>
+ *                    securestreams-dev@amazon.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+struct sigv4_header {
+       const char * name;
+       const char * value;
+};
+
+#define MAX_HEADER_NUM 8
+struct sigv4 {
+       struct sigv4_header headers[MAX_HEADER_NUM];
+       uint8_t hnum;
+       char    ymd[10];     /*YYYYMMDD*/
+       const char *timestamp;
+       const char *payload_hash;
+       const char *region;
+       const char *service;
+};
+
+static const uint8_t blob_idx[] = {
+       LWS_SYSBLOB_TYPE_EXT_AUTH1,
+       LWS_SYSBLOB_TYPE_EXT_AUTH2,
+       LWS_SYSBLOB_TYPE_EXT_AUTH3,
+       LWS_SYSBLOB_TYPE_EXT_AUTH4,
+};
+
+enum {
+       LWS_SS_SIGV4_KEYID,
+       LWS_SS_SIGV4_KEY,
+       LWS_SS_SIGV4_BLOB_SLOTS
+};
+
+static inline int add_header(struct sigv4 *s, const char *name, const char *value)
+{
+       if (s->hnum >= MAX_HEADER_NUM) {
+               lwsl_err("%s too many sigv4 headers\n", __func__);
+               return -1;
+       }
+
+       s->headers[s->hnum].name = name;
+       s->headers[s->hnum].value = value;
+       s->hnum++;
+
+       if (!strncmp(name, "x-amz-content-sha256", strlen("x-amz-content-sha256")))
+               s->payload_hash = value;
+
+       if (!strncmp(name, "x-amz-date", strlen("x-amz-date"))) {
+               s->timestamp = value;
+               strncpy(s->ymd, value, 8);
+       }
+
+       return 0;
+}
+
+static int
+cmp_header(const void * a, const void * b)
+{
+       return strcmp(((struct sigv4_header *)a)->name,
+                       ((struct sigv4_header *)b)->name);
+}
+
+static int
+init_sigv4(struct lws *wsi, struct lws_ss_handle *h, struct sigv4 *s)
+{
+       lws_ss_metadata_t *polmd = h->policy->metadata;
+       int m = 0;
+
+       add_header(s, "host:", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
+
+       while (polmd) {
+               if (polmd->value__may_own_heap &&
+                   ((uint8_t *)polmd->value__may_own_heap)[0] &&
+                   h->metadata[m].value__may_own_heap) {
+                       /* consider all headers start with "x-amz-" need to be signed */
+                       if (!strncmp(polmd->value__may_own_heap, "x-amz-",
+                                    strlen("x-amz-"))) {
+                               if (add_header(s, polmd->value__may_own_heap,
+                                              h->metadata[m].value__may_own_heap))
+                                       return -1;
+                       }
+               }
+               if (!strcmp(h->metadata[m].name, h->policy->aws_region) &&
+                   h->metadata[m].value__may_own_heap)
+                       s->region = h->metadata[m].value__may_own_heap;
+
+               if (!strcmp(h->metadata[m].name, h->policy->aws_service) &&
+                   h->metadata[m].value__may_own_heap)
+                       s->service = h->metadata[m].value__may_own_heap;
+
+               m++;
+               polmd = polmd->next;
+       }
+
+       qsort(s->headers, s->hnum, sizeof(struct sigv4_header), cmp_header);
+
+#if 0
+       do {
+               int i;
+               for (i= 0; i<s->hnum; i++)
+                       lwsl_debug("%s hdr %s %s\n", __func__,
+                                       s->headers[i].name, s->headers[i].value);
+
+               lwsl_debug("%s service: %s region: %s\n", __func__,
+                               s->service, s->region);
+       } while(0);
+#endif
+
+       return 0;
+}
+
+static void
+bin2hex(uint8_t *in, size_t len, char *out)
+{
+       static const char *hex = "0123456789abcdef";
+       size_t n;
+
+       for (n = 0; n < len; n++) {
+               *out++ = hex[(in[n] >> 4) & 0xf];
+               *out++ = hex[in[n] & 15];
+       }
+       *out = '\0';
+}
+
+static int
+hmacsha256(const uint8_t *key, size_t keylen, const uint8_t *txt,
+                       size_t txtlen, uint8_t *digest)
+{
+       struct lws_genhmac_ctx hmacctx;
+
+       if (lws_genhmac_init(&hmacctx, LWS_GENHMAC_TYPE_SHA256,
+                               key, keylen))
+               return -1;
+
+       if (lws_genhmac_update(&hmacctx, txt, txtlen)) {
+               lwsl_err("%s: hmac computation failed\n", __func__);
+               lws_genhmac_destroy(&hmacctx, NULL);
+               return -1;
+       }
+
+       if (lws_genhmac_destroy(&hmacctx, digest)) {
+               lwsl_err("%s: problem destroying hmac\n", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* cut the last byte of the str */
+static inline int hash_update_bite_str(struct lws_genhash_ctx *ctx, const char * str)
+{
+       int ret = 0;
+       if ((ret = lws_genhash_update(ctx, (void *)str, strlen(str)-1))) {
+               lws_genhash_destroy(ctx, NULL);
+               lwsl_err("%s err %d line \n", __func__, ret);
+       }
+       return ret;
+}
+
+static inline int hash_update_str(struct lws_genhash_ctx *ctx, const char * str)
+{
+       int ret = 0;
+       if ((ret = lws_genhash_update(ctx, (void *)str, strlen(str)))) {
+               lws_genhash_destroy(ctx, NULL);
+               lwsl_err("%s err %d \n", __func__, ret);
+       }
+       return ret;
+}
+
+static int
+build_sign_string(struct lws *wsi, char *buf, size_t bufsz,
+               struct lws_ss_handle *h, struct sigv4 *s)
+{
+       char hash[65], *end = &buf[bufsz - 1], *start;
+       struct lws_genhash_ctx hash_ctx;
+       uint8_t hash_bin[32];
+       int i, ret = 0;
+
+       start = buf;
+
+       if ((ret = lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256))) {
+               lws_genhash_destroy(&hash_ctx, NULL);
+               lwsl_err("%s genhash init err %d \n", __func__, ret);
+               return -1;
+       }
+       /*
+        * hash canonical_request
+        */
+
+       if (hash_update_str(&hash_ctx, h->policy->u.http.method) ||
+                       hash_update_str(&hash_ctx, "\n"))
+               return -1;
+       if (hash_update_str(&hash_ctx, lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI)) ||
+                       hash_update_str(&hash_ctx, "\n"))
+               return -1;
+
+       /* TODO, append query string */
+       if (hash_update_str(&hash_ctx, "\n"))
+               return -1;
+
+       for (i = 0; i < s->hnum; i++) {
+               if (hash_update_str(&hash_ctx, s->headers[i].name) ||
+                   hash_update_str(&hash_ctx, s->headers[i].value) ||
+                   hash_update_str(&hash_ctx, "\n"))
+               return -1;
+
+       }
+       if (hash_update_str(&hash_ctx, "\n"))
+               return -1;
+
+       for (i = 0; i < s->hnum-1; i++) {
+               if (hash_update_bite_str(&hash_ctx, s->headers[i].name) ||
+                   hash_update_str(&hash_ctx, ";"))
+                       return -1;
+       }
+       if (hash_update_bite_str(&hash_ctx, s->headers[i].name) ||
+           hash_update_str(&hash_ctx, "\n") ||
+           hash_update_str(&hash_ctx, s->payload_hash))
+               return -1;
+
+       if ((ret = lws_genhash_destroy(&hash_ctx, hash_bin))) {
+               lws_genhash_destroy(&hash_ctx, NULL);
+               lwsl_err("%s lws_genhash error \n", __func__);
+               return -1;
+       }
+
+       bin2hex(hash_bin, sizeof(hash_bin), hash);
+       /*
+        * build sign string like the following
+        *
+        * "AWS4-HMAC-SHA256" + "\n" +
+        * timeStampISO8601Format + "\n" +
+        * date.Format(<YYYYMMDD>) + "/" + <region> + "/" + <service> + "/aws4_request" + "\n" +
+        * Hex(SHA256Hash(<CanonicalRequest>))
+        */
+       buf = start;
+
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s\n",
+                                                       "AWS4-HMAC-SHA256");
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s\n",
+                                                       s->timestamp);
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s/%s/%s/%s\n",
+                               s->ymd, s->region, s->service, "aws4_request");
+
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s", hash);
+       *buf++ = '\0';
+
+       assert(buf <= start + bufsz);
+
+       return 0;
+}
+
+/*
+ * DateKey              = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>")
+ * DateRegionKey        = HMAC-SHA256(<DateKey>, "<aws-region>")
+ * DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>")
+ * SigningKey           = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")
+ */
+static int
+calc_signing_key(struct lws *wsi, struct lws_ss_handle *h,
+               struct sigv4 *s, uint8_t *sign_key)
+{
+       uint8_t key[128], date_key[32], and_region_key[32],
+               and_service_key[32], *kb;
+       lws_system_blob_t *ab;
+       size_t keylen;
+       int n;
+
+       ab = lws_system_get_blob(wsi->a.context,
+                                blob_idx[h->policy->auth->blob_index],
+                                LWS_SS_SIGV4_KEY);
+       if (!ab)
+               return -1;
+
+       kb = key;
+
+       *kb++ = 'A';
+       *kb++ = 'W';
+       *kb++ = 'S';
+       *kb++ = '4';
+
+       keylen = sizeof(key) - 4;
+       if (lws_system_blob_get_size(ab) > keylen - 1)
+               return -1;
+
+       n = lws_system_blob_get(ab, kb, &keylen, 0);
+       if (n < 0)
+               return -1;
+
+       kb[keylen] = '\0';
+
+       hmacsha256((const uint8_t *)key, strlen((const char *)key),
+                  (const uint8_t *)s->ymd, strlen(s->ymd), date_key);
+
+       hmacsha256(date_key, sizeof(date_key), (const uint8_t *)s->region,
+                  strlen(s->region), and_region_key);
+
+       hmacsha256(and_region_key, sizeof(and_region_key),
+                  (const uint8_t *)s->service,
+                  strlen(s->service), and_service_key);
+
+       hmacsha256(and_service_key, sizeof(and_service_key),
+                  (uint8_t *)"aws4_request",
+                  strlen("aws4_request"), sign_key);
+
+       return 0;
+}
+
+/* Sample auth string:
+ *
+ * 'Authorization: AWS4-HMAC-SHA256 Credential=AKIAVHWASOFE7TJ7ZUQY/20200731/us-west-2/s3/aws4_request,
+* SignedHeaders=host;x-amz-content-sha256;x-amz-date, \
+* Signature=ad9fb75ff3b46c7990e3e8f090abfdd6c01fd67761a517111694377e20698377'
+*/
+static int
+build_auth_string(struct lws *wsi, char * buf, size_t bufsz,
+               struct lws_ss_handle *h, struct sigv4 *s,
+               uint8_t *signature_bin)
+{
+       char *start = buf, *end = &buf[bufsz - 1];
+       char *c;
+       lws_system_blob_t *ab;
+       size_t keyidlen = 128; // max keyid len is 128
+       int n;
+
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s",
+                           "AWS4-HMAC-SHA256 ");
+
+       ab = lws_system_get_blob(wsi->a.context,
+                                blob_idx[h->policy->auth->blob_index],
+                                LWS_SS_SIGV4_KEYID);
+       if (!ab)
+               return -1;
+
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s",
+                                                       "Credential=");
+       n = lws_system_blob_get(ab,(uint8_t *)buf, &keyidlen, 0);
+       if (n < 0)
+               return -1;
+       buf += keyidlen;
+
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "/%s/%s/%s/%s, ",
+                               s->ymd, s->region, s->service, "aws4_request");
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s",
+                                                       "SignedHeaders=");
+       for (n = 0; n < s->hnum; n++) {
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                                       "%s",s->headers[n].name);
+               buf--; /* remove ':' */
+               *buf++ = ';';
+       }
+       c = buf - 1;
+       *c = ','; /* overwrite ';' back to ',' */
+
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                           "%s", " Signature=");
+       bin2hex(signature_bin, 32, buf);
+
+       assert(buf+65 <= start + bufsz);
+
+       lwsl_debug("%s %s\n", __func__, start);
+
+       return 0;
+
+}
+
+int
+lws_ss_apply_sigv4(struct lws *wsi, struct lws_ss_handle *h,
+                    unsigned char **p, unsigned char *end)
+{
+       uint8_t buf[512], sign_key[32], signature_bin[32], *bp;
+       struct sigv4 s;
+
+       memset(&s, 0, sizeof(s));
+
+       bp = buf;
+
+       init_sigv4(wsi, h, &s);
+       if (!s.timestamp || !s.payload_hash) {
+               lwsl_err("%s missing headers\n", __func__);
+               return -1;
+       }
+
+       if (build_sign_string(wsi, (char *)bp, sizeof(buf), h, &s))
+               return -1;
+
+       if (calc_signing_key(wsi, h, &s, sign_key))
+               return -1;
+
+       hmacsha256(sign_key, sizeof(sign_key), (const uint8_t *)buf,
+                             strlen((const char *)buf), signature_bin);
+
+       bp = buf; /* reuse for auth_str */
+       if (build_auth_string(wsi, (char *)bp, sizeof(buf), h, &s,
+                               signature_bin))
+               return -1;
+
+       if (lws_add_http_header_by_name(wsi,
+                                       (const uint8_t *)"Authorization:", buf,
+                                       (int)strlen((const char*)buf), p, end))
+               return -1;
+
+       return 0;
+}
+
+int
+lws_ss_sigv4_set_aws_key(struct lws_context* context, uint8_t idx,
+                               const char * keyid, const char * key)
+{
+       const char * s[] = { keyid, key };
+       lws_system_blob_t *ab;
+       int i;
+
+       if (idx > LWS_ARRAY_SIZE(blob_idx))
+               return -1;
+
+       for (i = 0; i < LWS_SS_SIGV4_BLOB_SLOTS; i++) {
+               ab = lws_system_get_blob(context, blob_idx[idx], i);
+               if (!ab)
+                       return -1;
+
+               lws_system_blob_heap_empty(ab);
+
+               if (lws_system_blob_heap_append(ab, (const uint8_t *)s[i],
+                                               strlen(s[i]))) {
+                       lwsl_err("%s: can't store %d \n", __func__, i);
+
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+#if defined(__linux__) || defined(__APPLE__) || defined(WIN32) || \
+       defined(__FreeBSD__) || defined(__NetBSD__) || defined(__ANDROID__) || \
+       defined(__sun) || defined(__OpenBSD__)
+
+/* ie, if we have filesystem ops */
+
+int
+lws_aws_filesystem_credentials_helper(const char *path, const char *kid,
+                                     const char *ak, char **aws_keyid,
+                                     char **aws_key)
+{
+       char *str = NULL, *val = NULL, *line = NULL, sth[128];
+       size_t len = sizeof(sth);
+       const char *home = "";
+       int i, poff = 0;
+       ssize_t rd;
+       FILE *fp;
+
+       *aws_keyid = *aws_key = NULL;
+
+       if (path[0] == '~') {
+               home = getenv("HOME");
+               if (home && strlen(home) > sizeof(sth) - 1) /* coverity */
+                       return -1;
+               else {
+                       if (!home)
+                               home = "";
+
+                       poff = 1;
+               }
+       }
+       lws_snprintf(sth, sizeof(sth), "%s%s", home, path + poff);
+
+       fp = fopen(sth, "r");
+       if (!fp) {
+               lwsl_err("%s can't open '%s'\n", __func__, sth);
+
+               return -1;
+       }
+
+       while ((rd = getline(&line, &len, fp)) != -1) {
+               for (i = 0; i < 2; i++) {
+                       size_t slen;
+
+                       if (strncmp(line, i ? kid : ak, strlen(i ? kid : ak)))
+                               continue;
+
+                       str = strchr(line, '=');
+                       if (!str)
+                               continue;
+
+                       str++;
+
+                       /* only read the first key for each */
+                       if (*(i ? aws_keyid : aws_key))
+                               continue;
+
+                       /*
+                        * Trim whitespace from the start and end
+                        */
+
+                       slen = (size_t)(rd - lws_ptr_diff(str, line));
+
+                       while (slen && *str == ' ') {
+                               str++;
+                               slen--;
+                       }
+
+                       while (slen && (str[slen - 1] == '\r' ||
+                                       str[slen - 1] == '\n' ||
+                                       str[slen - 1] == ' '))
+                               slen--;
+
+                       val = malloc(slen + 1);
+                       if (!val)
+                               goto bail;
+
+                       strncpy(val, str, slen);
+                       val[slen] = '\0';
+
+                       *(i ? aws_keyid : aws_key) = val;
+
+               }
+       }
+
+bail:
+       fclose(fp);
+
+       if (line)
+               free(line);
+
+       if (!*aws_keyid || !*aws_key) {
+               if (*aws_keyid) {
+                       free(*aws_keyid);
+                       *aws_keyid = NULL;
+               }
+               if (*aws_key) {
+                       free(*aws_key);
+                       *aws_key = NULL;
+               }
+               lwsl_err("%s can't find aws credentials! \
+                               please check %s\n", __func__, path);
+               return -1;
+       }
+
+       lwsl_info("%s: '%s' '%s'\n", __func__, *aws_keyid, *aws_key);
+
+       return 0;
+}
+#endif
diff --git a/lib/secure-streams/system/captive-portal-detect/captive-portal-detect.c b/lib/secure-streams/system/captive-portal-detect/captive-portal-detect.c
new file mode 100644 (file)
index 0000000..4de54bf
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Captive portal detect for Secure Streams
+ *
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+typedef struct ss_cpd {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+
+       lws_sorted_usec_list_t  sul;
+} ss_cpd_t;
+
+static lws_ss_state_return_t
+ss_cpd_state(void *userobj, void *sh, lws_ss_constate_t state,
+            lws_ss_tx_ordinal_t ack)
+{
+       ss_cpd_t *m = (ss_cpd_t *)userobj;
+       struct lws_context *cx = (struct lws_context *)m->opaque_data;
+
+       lwsl_ss_info(m->ss, "%s, ord 0x%x\n", lws_ss_state_name((int)state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               lws_ss_start_timeout(m->ss, 3 * LWS_US_PER_SEC);
+               return lws_ss_request_tx(m->ss);
+
+       case LWSSSCS_QOS_ACK_REMOTE:
+               lws_system_cpd_set(cx, LWS_CPD_INTERNET_OK);
+               cx->ss_cpd = NULL;
+               return LWSSSSRET_DESTROY_ME;
+
+       case LWSSSCS_TIMEOUT:
+       case LWSSSCS_ALL_RETRIES_FAILED:
+       case LWSSSCS_DISCONNECTED:
+               /*
+                * First result reported sticks... if nothing else, this will
+                * cover the situation we didn't connect to anything
+                */
+               lws_system_cpd_set(cx, LWS_CPD_NO_INTERNET);
+               cx->ss_cpd = NULL;
+               return LWSSSSRET_DESTROY_ME;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static const lws_ss_info_t ssi_cpd = {
+       .handle_offset                  = offsetof(ss_cpd_t, ss),
+       .opaque_user_data_offset        = offsetof(ss_cpd_t, opaque_data),
+       .state                          = ss_cpd_state,
+       .user_alloc                     = sizeof(ss_cpd_t),
+       .streamtype                     = "captive_portal_detect",
+};
+
+int
+lws_ss_sys_cpd(struct lws_context *cx)
+{
+       if (cx->ss_cpd) {
+               lwsl_cx_notice(cx, "CPD already ongoing");
+               return 0;
+       }
+
+       if (lws_ss_create(cx, 0, &ssi_cpd, cx, &cx->ss_cpd, NULL, NULL)) {
+               lwsl_cx_info(cx, "Create stream failed (policy?)");
+
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/lib/secure-streams/system/fetch-policy/fetch-policy.c b/lib/secure-streams/system/fetch-policy/fetch-policy.c
new file mode 100644 (file)
index 0000000..ee4b139
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Policy fetching for Secure Streams
+ *
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+typedef struct ss_fetch_policy {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+
+       lws_sorted_usec_list_t  sul;
+
+       uint8_t                 partway;
+} ss_fetch_policy_t;
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+ss_fetch_policy_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       ss_fetch_policy_t *m = (ss_fetch_policy_t *)userobj;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+
+       if (flags & LWSSS_FLAG_SOM) {
+               if (lws_ss_policy_parse_begin(context, 0))
+                       return LWSSSSRET_OK;
+               m->partway = 1;
+       }
+
+       if (len && lws_ss_policy_parse(context, buf, len) < 0)
+               return LWSSSSRET_OK;
+
+       if (flags & LWSSS_FLAG_EOM)
+               m->partway = 2;
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+ss_fetch_policy_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                  size_t *len, int *flags)
+{
+       return LWSSSSRET_TX_DONT_SEND;
+}
+
+static void
+policy_set(lws_sorted_usec_list_t *sul)
+{
+       ss_fetch_policy_t *m = lws_container_of(sul, ss_fetch_policy_t, sul);
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+
+       /*
+        * We get called if the policy parse was successful, just after the
+        * ss connection close that was using the vhost from the old policy
+        */
+
+       lws_ss_destroy(&m->ss);
+
+       if (lws_ss_policy_set(context, "updated"))
+               lwsl_err("%s: policy set failed\n", __func__);
+       else {
+               context->policy_updated = 1;
+#if defined(LWS_WITH_SYS_STATE)
+               lws_state_transition_steps(&context->mgr_system,
+                                          LWS_SYSTATE_OPERATIONAL);
+#endif
+       }
+}
+
+static lws_ss_state_return_t
+ss_fetch_policy_state(void *userobj, void *sh, lws_ss_constate_t state,
+                     lws_ss_tx_ordinal_t ack)
+{
+       ss_fetch_policy_t *m = (ss_fetch_policy_t *)userobj;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+
+       lwsl_info("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_request_tx(m->ss);
+
+       case LWSSSCS_CONNECTING:
+               break;
+
+       case LWSSSCS_QOS_ACK_REMOTE:
+               switch (m->partway) {
+               case 2:
+                       lws_sul_schedule(context, 0, &m->sul, policy_set, 1);
+                       m->partway = 0;
+                       break;
+               }
+               break;
+
+       case LWSSSCS_DISCONNECTED:
+               if (m->partway == 1) {
+                       lws_ss_policy_parse_abandon(context);
+                       break;
+               }
+               m->partway = 0;
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+int
+lws_ss_sys_fetch_policy(struct lws_context *context)
+{
+       lws_ss_info_t ssi;
+
+       if (context->hss_fetch_policy) /* already exists */
+               return 0;
+
+       /* We're making an outgoing secure stream ourselves */
+
+       memset(&ssi, 0, sizeof(ssi));
+       ssi.handle_offset           = offsetof(ss_fetch_policy_t, ss);
+       ssi.opaque_user_data_offset = offsetof(ss_fetch_policy_t, opaque_data);
+       ssi.rx                      = ss_fetch_policy_rx;
+       ssi.tx                      = ss_fetch_policy_tx;
+       ssi.state                   = ss_fetch_policy_state;
+       ssi.user_alloc              = sizeof(ss_fetch_policy_t);
+       ssi.streamtype              = "fetch_policy";
+
+       if (lws_ss_create(context, 0, &ssi, context, &context->hss_fetch_policy,
+                         NULL, NULL)) {
+               /*
+                * If there's no fetch_policy streamtype, it can just be we're
+                * running on a proxied client with no policy of its own,
+                * it's OK.
+                */
+               lwsl_info("%s: Policy fetch ss failed (stub policy?)\n", __func__);
+
+               return 0;
+       }
+
+       lwsl_info("%s: policy fetching ongoing\n", __func__);
+
+       /* fetching it is ongoing */
+
+       return 1;
+}
diff --git a/lib/system/CMakeLists.txt b/lib/system/CMakeLists.txt
new file mode 100644 (file)
index 0000000..654264b
--- /dev/null
@@ -0,0 +1,74 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(./async-dns)
+
+list(APPEND SOURCES
+       system/system.c)
+       
+if (LWS_WITH_NETWORK)
+
+       if (LWS_WITH_SYS_ASYNC_DNS)
+               list(APPEND SOURCES
+                       system/async-dns/async-dns.c
+                       system/async-dns/async-dns-parse.c)
+       endif()
+
+       if (LWS_WITH_SYS_NTPCLIENT)
+               list(APPEND SOURCES
+                       system/ntpclient/ntpclient.c)
+       endif()
+
+       if (LWS_WITH_SYS_DHCP_CLIENT)
+               list(APPEND SOURCES
+                       system/dhcpclient/dhcpclient.c
+                       system/dhcpclient/dhcpc4.c)
+       endif()
+
+       if (LWS_WITH_SYS_SMD)
+               add_subdir_include_dirs(smd)
+       endif()
+       
+       if (LWS_WITH_SYS_FAULT_INJECTION)
+               include_directories(./fault-injection)
+               list(APPEND SOURCES
+                       system/fault-injection/fault-injection.c)
+       endif()
+
+       add_subdir_include_dirs(metrics)
+
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
diff --git a/lib/system/README.md b/lib/system/README.md
new file mode 100644 (file)
index 0000000..6bf1bad
--- /dev/null
@@ -0,0 +1,68 @@
+# LWS System Helpers
+
+Lws now has a little collection of helper utilities for common network-based
+functions necessary for normal device operation, eg, async DNS, ntpclient
+(necessary for tls validation), and DHCP client.
+
+## Conventions
+
+If any system helper is enabled for build, lws creates an additional vhost
+"system" at Context Creation time.  Wsi that are created for the system
+features are bound to this.  In the context object, this is available as
+`.vhost_system`.
+
+# Attaching to an existing context from other threads
+
+To simplify the case different pieces of code want to attach to a single
+lws_context at runtime, from different thread contexts, lws_system has an api
+via an lws_system operation function pointer where the other threads can use
+platform-specific locking to request callbacks to their own code from the
+lws event loop thread context safely.
+
+For convenience, the callback can be delayed until the system has entered or
+passed a specified system state, eg, LWS_SYSTATE_OPERATIONAL so the code will
+only get called back after the network, ntpclient and auth have been done.
+Additionally an opaque pointer can be passed to the callback when it is called
+from the lws event loop context.
+
+## Implementing the system-specific locking
+
+`lws_system_ops_t` struct has a member `.attach`
+
+```
+       int (*attach)(struct lws_context *context, int tsi, lws_attach_cb_t *cb,
+                     lws_system_states_t state, void *opaque,
+                     struct lws_attach_item **get);
+```
+
+This should be defined in user code as setting locking, then passing the
+arguments through to a non-threadsafe helper
+
+```
+int
+__lws_system_attach(struct lws_context *context, int tsi, lws_attach_cb_t *cb,
+                   lws_system_states_t state, void *opaque,
+                   struct lws_attach_item **get);
+```
+
+that does the actual attach work.  When it returns, the locking should be
+unlocked and the return passed back.
+
+## Attaching the callback request
+
+User code should call the lws_system_ops_t `.attach` function like
+
+```
+       lws_system_get_ops(context)->attach(...);
+```
+
+The callback function which will be called from the lws event loop context
+should look like this
+
+```
+void my_callback(struct lws_context *context, int tsi, void *opaque);
+```
+
+with the callback function name passed into the (*attach)() call above.  When
+the callback happens, the opaque user pointer set at the (*attach)() call is
+passed back to it as an argument.
diff --git a/lib/system/async-dns/async-dns-parse.c b/lib/system/async-dns/async-dns-parse.c
new file mode 100644 (file)
index 0000000..bdfe205
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-async-dns.h"
+
+
+/* updates *dest, returns chars used from ls directly, else -1 for fail */
+
+static int
+lws_adns_parse_label(const uint8_t *pkt, int len, const uint8_t *ls, int budget,
+                    char **dest, size_t dl)
+{
+       const uint8_t *e = pkt + len, *ols = ls;
+       char pointer = 0, first = 1;
+       uint8_t ll;
+       int n;
+
+       if (budget < 1)
+               return 0;
+
+       /* caller must catch end of labels */
+       assert(*ls);
+
+again1:
+       if (ls >= e)
+               return -1;
+
+       if (((*ls) & 0xc0) == 0xc0) {
+               if (budget < 2)
+                       return -1;
+               /* pointer into message pkt to name to actually use */
+               n = lws_ser_ru16be(ls) & 0x3fff;
+               if (n >= len) {
+                       lwsl_notice("%s: illegal name pointer\n", __func__);
+
+                       return -1;
+               }
+
+               /* dereference the label pointer */
+               ls = pkt + n;
+
+               /* are we being fuzzed or messed with? */
+               if (((*ls) & 0xc0) == 0xc0) {
+                       /* ... pointer to pointer is unreasonable */
+                       lwsl_notice("%s: label ptr to ptr invalid\n", __func__);
+
+                       return -1;
+               }
+               pointer = 1;
+       }
+
+       if (ls >= e)
+               return -1;
+
+       ll = *ls++;
+       if (ls + ll + 1 > e) {
+               lwsl_notice("%s: label len invalid, %d vs %d\n", __func__,
+                           lws_ptr_diff((ls + ll + 1), pkt), lws_ptr_diff(e, pkt));
+
+               return -1;
+       }
+
+       if (ls + ll > ols + budget) {
+               lwsl_notice("%s: label too long %d vs %d\n", __func__, ll, budget);
+
+               return -1;
+       }
+
+       if ((unsigned int)ll + 2 > dl) {
+               lwsl_notice("%s: qname too large\n", __func__);
+
+               return -1;
+       }
+
+       /* copy the label content into place */
+
+       memcpy(*dest, ls, ll);
+       (*dest)[ll] = '.';
+       (*dest)[ll + 1] = '\0';
+       *dest += ll + 1;
+       ls += ll;
+
+       if (pointer) {
+               if (*ls)
+                       goto again1;
+
+               /*
+                * special fun rule... if whole qname was a pointer label,
+                * it has no 00 terminator afterwards
+                */
+               if (first)
+                       return 2; /* we just took the 16-bit pointer */
+
+               return 3;
+       }
+
+       first = 0;
+
+       if (*ls)
+               goto again1;
+
+       ls++;
+
+       return lws_ptr_diff(ls, ols);
+}
+
+typedef int (*lws_async_dns_find_t)(const char *name, void *opaque,
+                                   uint32_t ttl, adns_query_type_t type,
+                                   const uint8_t *payload);
+
+/* locally query the response packet */
+
+struct label_stack {
+       char name[DNS_MAX];
+       int enl;
+       const uint8_t *p;
+};
+
+/*
+ * Walk the response packet, calling back to the user-provided callback for each
+ * A (and AAAA if LWS_IPV6=1) record with a matching name found in there.
+ *
+ * Able to recurse using an explicit non-CPU stack to resolve CNAME usages
+ *
+ * Return -1: unexpectedly failed
+ *         0: found
+ *         1: didn't find anything matching
+ */
+
+static int
+lws_adns_iterate(lws_adns_q_t *q, const uint8_t *pkt, int len,
+                const char *expname, lws_async_dns_find_t cb, void *opaque)
+{
+       const uint8_t *e = pkt + len, *p, *pay;
+       struct label_stack stack[4];
+       int n = 0, stp = 0, ansc, m;
+       uint16_t rrtype, rrpaylen;
+       char *sp, inq;
+       uint32_t ttl;
+
+       lws_strncpy(stack[0].name, expname, sizeof(stack[0].name));
+       stack[0].enl = (int)strlen(expname);
+
+start:
+       ansc = lws_ser_ru16be(pkt + DHO_NANSWERS);
+       p = pkt + DHO_SIZEOF;
+       inq = 1;
+
+       /*
+        * The response also includes the query... and we have to parse it
+        * so we can understand we reached the response... there's a QNAME
+        * made up of labels and then 2 x 16-bit fields, for query type and
+        * query class
+        */
+
+
+       while (p + 14 < e && (inq || ansc)) {
+
+               if (!inq && !stp)
+                       ansc--;
+
+               /*
+                * First is the name the query applies to... two main
+                * formats can appear here, one is a pointer to
+                * elsewhere in the message, the other separately
+                * provides len / data for each dotted "label", so for
+                * "warmcat.com" warmcat and com are given each with a
+                * prepended length byte.  Any of those may be a pointer
+                * to somewhere else in the packet :-/
+                *
+                * Paranoia is appropriate since the name length must be
+                * parsed out before the rest of the RR can be used and
+                * we can be attacked with absolutely any crafted
+                * content easily via UDP.
+                *
+                * So parse the name and additionally confirm it matches
+                * what the query the TID belongs to actually asked for.
+                */
+
+               sp = stack[0].name;
+
+               /* while we have more labels */
+
+               n = lws_adns_parse_label(pkt, len, p, len, &sp,
+                                        sizeof(stack[0].name) -
+                                        lws_ptr_diff_size_t(sp, stack[0].name));
+               /* includes case name won't fit */
+               if (n < 0)
+                       return -1;
+
+               p += n;
+
+               if (p + (inq ? 5 : 14) > e)
+                       return -1;
+
+               /*
+                * p is now just after the decoded RR name, pointing at: type
+                *
+                * We sent class = 1 = IN query... response must match
+                */
+
+               if (lws_ser_ru16be(&p[2]) != 1) {
+                       lwsl_err("%s: non-IN response 0x%x\n", __func__,
+                                               lws_ser_ru16be(&p[2]));
+
+                       return -1;
+               }
+
+               if (inq) {
+                       lwsl_debug("%s: reached end of inq\n", __func__);
+                       inq = 0;
+                       p += 4;
+                       continue;
+               }
+
+               /* carefully validate the claimed RR payload length */
+
+               rrpaylen = lws_ser_ru16be(&p[8]);
+               if (p + 10 + rrpaylen > e) { /* it may be == e */
+                       lwsl_notice("%s: invalid RR data length\n", __func__);
+
+                       return -1;
+               }
+
+               ttl = lws_ser_ru32be(&p[4]);
+               rrtype = lws_ser_ru16be(&p[0]);
+               p += 10; /* point to the payload */
+               pay = p;
+
+               /*
+                * Compare the RR names, allowing for the decoded labelname
+                * to have an extra '.' at the end.
+                */
+
+               n = lws_ptr_diff(sp, stack[0].name);
+               if (stack[0].name[n - 1] == '.')
+                       n--;
+
+               m = stack[stp].enl;
+               if (stack[stp].name[m - 1] == '.')
+                       m--;
+
+               if (n < 1 || n != m ||
+                   strncmp(stack[0].name, stack[stp].name, (unsigned int)n)) {
+                       //lwsl_notice("%s: skipping %s vs %s\n", __func__,
+                       //              stack[0].name, stack[stp].name);
+                       goto skip;
+               }
+
+               /*
+                * It's something we could be interested in...
+                *
+                * We can skip RRs we don't understand.  But we need to deal
+                * with at least these and their payloads:
+                *
+                *    A:      4: ipv4 address
+                *    AAAA:  16: ipv6 address (if asked for AAAA)
+                *    CNAME:  ?: labelized name
+                *
+                * If we hit a CNAME we need to try to dereference it with
+                * stuff that is in the same response packet and judge it
+                * from that, without losing our place here.  CNAMEs may
+                * point to CNAMEs to whatever depth we're willing to handle.
+                */
+
+               switch (rrtype) {
+
+               case LWS_ADNS_RECORD_AAAA:
+                       if (rrpaylen != 16) {
+                               lwsl_err("%s: unexpected rrpaylen\n", __func__);
+                               return -1;
+                       }
+#if defined(LWS_WITH_IPV6)
+                       goto do_cb;
+#else
+                       break;
+#endif
+
+               case LWS_ADNS_RECORD_A:
+                       if (rrpaylen != 4) {
+                               lwsl_err("%s: unexpected rrpaylen4\n", __func__);
+
+                               return -1;
+                       }
+#if defined(LWS_WITH_IPV6)
+do_cb:
+#endif
+                       cb(stack[0].name, opaque, ttl, rrtype, p);
+                       break;
+
+               case LWS_ADNS_RECORD_CNAME:
+                       /*
+                        * The name the CNAME refers to MAY itself be
+                        * included elsewhere in the response packet.
+                        *
+                        * So switch tack, stack where to resume from and
+                        * search for the decoded CNAME label name definition
+                        * instead.
+                        *
+                        * First decode the CNAME label payload into the next
+                        * stack level buffer for it.
+                        */
+
+                       if (++stp == (int)LWS_ARRAY_SIZE(stack)) {
+                               lwsl_notice("%s: CNAMEs too deep\n", __func__);
+
+                               return -1;
+                       }
+                       sp = stack[stp].name;
+                       /* get the cname alias */
+                       n = lws_adns_parse_label(pkt, len, p, rrpaylen, &sp,
+                                                sizeof(stack[stp].name) -
+                                                lws_ptr_diff_size_t(sp, stack[stp].name));
+                       /* includes case name won't fit */
+                       if (n < 0)
+                               return -1;
+
+                       p += n;
+
+                       if (p + 14 > e)
+                               return -1;
+#if 0
+                       /* it should have exactly reached rrpaylen if only one
+                        * CNAME, else somewhere in the middle */
+
+                       if (p != pay + rrpaylen) {
+                               lwsl_err("%s: cname name bad len %d\n", __func__, rrpaylen);
+
+                               return -1;
+                       }
+#endif
+                       lwsl_notice("%s: recursing looking for %s\n", __func__, stack[stp].name);
+
+                       lwsl_info("%s: recursing looking for %s\n", __func__,
+                                       stack[stp].name);
+
+                       stack[stp].enl = lws_ptr_diff(sp, stack[stp].name);
+                       /* when we unstack, resume from here */
+                       stack[stp].p = pay + rrpaylen;
+                       goto start;
+
+               default:
+                       break;
+               }
+
+skip:
+               p += rrpaylen;
+       }
+
+       if (!stp)
+               return 1; /* we didn't find anything, but we didn't error */
+
+       lwsl_info("%s: '%s' -> CNAME '%s' resolution not provided, recursing\n",
+                       __func__, ((const char *)&q[1]) + DNS_MAX,
+                       stack[stp].name);
+
+       /*
+        * This implies there wasn't any usable definition for the
+        * CNAME in the end, eg, only AAAA when we needed an A.
+        *
+        * It's also legit if the DNS just returns the CNAME, and that server
+        * did not directly know the next step in resolution of the CNAME, so
+        * instead of putting the resolution elsewhere in the response, has
+        * told us just the CNAME and left it to us to find out its resolution
+        * separately.
+        *
+        * Reset this request to be for the CNAME, and restart the request
+        * action with a new tid.
+        */
+
+       if (lws_async_dns_get_new_tid(q->context, q))
+               return -1;
+
+       LADNS_MOST_RECENT_TID(q) &= 0xfffe;
+       q->asked = q->responded = 0;
+#if defined(LWS_WITH_IPV6)
+       q->sent[1] = 0;
+#endif
+       q->sent[0] = 0;
+       q->recursion++;
+       if (q->recursion == DNS_RECURSION_LIMIT) {
+               lwsl_err("%s: recursion overflow\n", __func__);
+
+               return -1;
+       }
+
+       if (q->firstcache)
+               lws_adns_cache_destroy(q->firstcache);
+       q->firstcache = NULL;
+
+       /* overwrite the query name with the CNAME */
+
+       n = 0;
+       {
+               char *cp = (char *)&q[1];
+
+               while (stack[stp].name[n])
+                       *cp++ = (char)tolower(stack[stp].name[n++]);
+               /* trim the following . if any */
+               if (n && cp[-1] == '.')
+                       cp--;
+               *cp = '\0';
+       }
+
+       lws_callback_on_writable(q->dns->wsi);
+
+       return 2;
+}
+
+int
+lws_async_dns_estimate(const char *name, void *opaque, uint32_t ttl,
+                       adns_query_type_t type, const uint8_t *payload)
+{
+       size_t *est = (size_t *)opaque, my;
+
+       my = sizeof(struct addrinfo);
+       if (type == LWS_ADNS_RECORD_AAAA)
+               my += sizeof(struct sockaddr_in6);
+       else
+               my += sizeof(struct sockaddr_in);
+
+       *est += my;
+
+       return 0;
+}
+
+struct adstore {
+       const char *name;
+       struct addrinfo *pos;
+       struct addrinfo *prev;
+       int ctr;
+       uint32_t smallest_ttl;
+       uint8_t flags;
+};
+
+/*
+ * Callback for each A or AAAA record, creating getaddrinfo-compatible results
+ * into the preallocated exact-sized storage.
+ */
+int
+lws_async_dns_store(const char *name, void *opaque, uint32_t ttl,
+                   adns_query_type_t type, const uint8_t *payload)
+{
+       struct adstore *adst = (struct adstore *)opaque;
+#if defined(_DEBUG)
+       char buf[48];
+#endif
+       size_t i;
+
+       if (ttl < adst->smallest_ttl || !adst->ctr)
+               adst->smallest_ttl = ttl;
+
+       if (adst->prev)
+               adst->prev->ai_next = adst->pos;
+       adst->prev = adst->pos;
+
+       adst->pos->ai_flags = 0;
+       adst->pos->ai_family = type == LWS_ADNS_RECORD_AAAA ?
+                                               AF_INET6 : AF_INET;
+       adst->pos->ai_socktype = SOCK_STREAM;
+       adst->pos->ai_protocol = IPPROTO_UDP; /* no meaning */
+       adst->pos->ai_addrlen = type == LWS_ADNS_RECORD_AAAA ?
+                                               sizeof(struct sockaddr_in6) :
+                                               sizeof(struct sockaddr_in);
+       adst->pos->ai_canonname = (char *)adst->name;
+       adst->pos->ai_addr = (struct sockaddr *)&adst->pos[1];
+       adst->pos->ai_next = NULL;
+
+#if defined(LWS_WITH_IPV6)
+       if (type == LWS_ADNS_RECORD_AAAA) {
+               struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&adst->pos[1];
+
+               i = sizeof(*in6);
+               memset(in6, 0, i);
+               in6->sin6_family = (sa_family_t)adst->pos->ai_family;
+               memcpy(in6->sin6_addr.s6_addr, payload, 16);
+               adst->flags |= 2;
+       } else
+#endif
+       {
+               struct sockaddr_in *in = (struct sockaddr_in *)&adst->pos[1];
+
+               i = sizeof(*in);
+               memset(in, 0, i);
+               in->sin_family = (sa_family_t)adst->pos->ai_family;
+               memcpy(&in->sin_addr.s_addr, payload, 4);
+               adst->flags |= 1;
+       }
+
+       adst->pos = (struct addrinfo *)((uint8_t *)adst->pos +
+                                       sizeof(struct addrinfo) + i);
+
+#if defined(_DEBUG)
+       if (lws_write_numeric_address(payload,
+                               type == LWS_ADNS_RECORD_AAAA ? 16 : 4,
+                                                       buf, sizeof(buf)) > 0)
+               lwsl_info("%s: %d: %s: %s\n", __func__, adst->ctr,
+                               adst->name, buf);
+#endif
+       adst->ctr++;
+
+       return 0;
+}
+
+/*
+ * We want to parse out all A or AAAA records
+ */
+
+void
+lws_adns_parse_udp(lws_async_dns_t *dns, const uint8_t *pkt, size_t len)
+{
+       const char *nm, *nmcname;
+       lws_adns_cache_t *c;
+       struct adstore adst;
+       lws_adns_q_t *q;
+       int n, ncname;
+       size_t est;
+
+       // lwsl_hexdump_notice(pkt, len);
+
+       /* we have to at least have the header */
+
+       if (len < DHO_SIZEOF)
+               return;
+
+       /* we asked with one query, so anything else is bogus */
+
+       if (lws_ser_ru16be(pkt + DHO_NQUERIES) != 1)
+               return;
+
+       /* match both A and AAAA queries if any */
+
+       q = lws_adns_get_query(dns, 0, &dns->waiting,
+                              lws_ser_ru16be(pkt + DHO_TID), NULL);
+       if (!q) {
+               lwsl_info("%s: dropping unknown query tid 0x%x\n",
+                           __func__, lws_ser_ru16be(pkt + DHO_TID));
+
+               return;
+       }
+
+       /* we can get dups... drop any that have already happened */
+
+       n = 1 << (lws_ser_ru16be(pkt + DHO_TID) & 1);
+       if (q->responded & n) {
+               lwsl_notice("%s: dup\n", __func__);
+               goto fail_out;
+       }
+
+       q->responded = (uint8_t)(q->responded | n);
+
+       /* we want to confirm the results against what we last requested... */
+
+       nmcname = ((const char *)&q[1]);
+
+       /*
+        * First walk the packet figuring out the allocation needed for all
+        * the results.  Produce the following layout at c
+        *
+        *  lws_adns_cache_t: new cache object
+        *  [struct addrinfo + struct sockaddr_in or _in6]: for each A or AAAA
+        *  char []: copy of resolved name
+        */
+
+       ncname = (int)strlen(nmcname) + 1;
+
+       est = sizeof(lws_adns_cache_t) + (unsigned int)ncname;
+       if (lws_ser_ru16be(pkt + DHO_NANSWERS)) {
+               int ir = lws_adns_iterate(q, pkt, (int)len, nmcname,
+                                         lws_async_dns_estimate, &est);
+               if (ir < 0)
+                       goto fail_out;
+
+               if (ir == 2) /* CNAME recursive resolution */
+                       return;
+       }
+
+       /* but we want to create the cache entry against the original request */
+
+       nm = ((const char *)&q[1]) + DNS_MAX;
+       n = (int)strlen(nm) + 1;
+
+       lwsl_info("%s: create cache entry for %s, %zu\n", __func__, nm,
+                       est - sizeof(lws_adns_cache_t));
+       c = lws_malloc(est + 1, "async-dns-entry");
+       if (!c) {
+               lwsl_err("%s: OOM %zu\n", __func__, est);
+               goto fail_out;
+       }
+       memset(c, 0, sizeof(*c));
+
+       /* place it at end, no need to care about alignment padding */
+       c->name = adst.name = ((const char *)c) + est - n;
+       memcpy((char *)c->name, nm, (unsigned int)n);
+
+       /*
+        * Then walk the packet again, placing the objects we accounted for
+        * the first time into the result allocation after the cache object
+        * and copy of the name
+        */
+
+       adst.pos = (struct addrinfo *)&c[1];
+       adst.prev = NULL;
+       adst.ctr = 0;
+       adst.smallest_ttl = 3600;
+       adst.flags = 0;
+
+       /*
+        * smallest_ttl applies as it is to empty results (NXDOMAIN), or is
+        * set to the minimum ttl seen in all the results.
+        */
+
+       if (lws_ser_ru16be(pkt + DHO_NANSWERS) &&
+           lws_adns_iterate(q, pkt, (int)len, nmcname, lws_async_dns_store, &adst) < 0) {
+               lws_free(c);
+               goto fail_out;
+       }
+
+       if (lws_ser_ru16be(pkt + DHO_NANSWERS)) {
+               c->results = (struct addrinfo *)&c[1];
+               if (q->last) /* chain the second one on */
+                       *q->last = c->results;
+               else /* first one had no results, set first guy's c->results */
+                       if (q->firstcache)
+                               q->firstcache->results = c->results;
+       }
+
+       if (adst.prev) /* so we know where to continue the addrinfo list */
+               /* can be NULL if first resp empty */
+               q->last = &adst.prev->ai_next;
+
+       if (q->firstcache) { /* also need to free chain when we free this guy */
+               q->firstcache->chain = c;
+               c->firstcache = q->firstcache;
+       } else {
+
+               q->firstcache = c;
+               c->incomplete = !q->responded;// != q->asked;
+
+               /*
+                * Only register the first one into the cache...
+                * Trim the oldest cache entry if necessary
+                */
+
+               lws_async_dns_trim_cache(dns);
+
+               /*
+                * cache the first results object... if a second one comes,
+                * we won't directly register it but will chain it on to this
+                * first one and continue to addinfo ai_next linked list from
+                * the first into the second
+                */
+
+               c->flags = adst.flags;
+               lws_dll2_add_head(&c->list, &dns->cached);
+               lws_sul_schedule(q->context, 0, &c->sul, sul_cb_expire,
+                                lws_now_usecs() +
+                                (adst.smallest_ttl * LWS_US_PER_SEC));
+       }
+
+       if (q->responded != q->asked)
+               return;
+
+       /*
+        * Now we captured everything into the new object, return the
+        * addrinfo results, if any, to all interested wsi, if any...
+        */
+
+       c->incomplete = 0;
+       lws_async_dns_complete(q, q->firstcache);
+
+       q->go_nogo = METRES_GO;
+
+       /*
+        * the query is completely finished with
+        */
+
+fail_out:
+       lws_adns_q_destroy(q);
+}
+
diff --git a/lib/system/async-dns/async-dns.c b/lib/system/async-dns/async-dns.c
new file mode 100644 (file)
index 0000000..e722214
--- /dev/null
@@ -0,0 +1,904 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-async-dns.h"
+
+static const uint32_t botable[] = { 300, 500, 700, 1250, 5000
+                               /* in case everything just dog slow */ };
+static const lws_retry_bo_t retry_policy = {
+       botable, LWS_ARRAY_SIZE(botable), LWS_RETRY_CONCEAL_ALWAYS,
+       /* don't conceal after the last table entry */ 0, 0, 20 };
+
+void
+lws_adns_q_destroy(lws_adns_q_t *q)
+{
+       lws_metrics_caliper_report(q->metcal, (char)q->go_nogo);
+
+       lws_sul_cancel(&q->sul);
+       lws_sul_cancel(&q->write_sul);
+       lws_dll2_remove(&q->list);
+       lws_free(q);
+}
+
+lws_adns_q_t *
+lws_adns_get_query(lws_async_dns_t *dns, adns_query_type_t qtype,
+                  lws_dll2_owner_t *owner, uint16_t tid, const char *name)
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  lws_dll2_get_head(owner)) {
+               lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
+               int n = 0, nmax = q->tids >= LWS_ARRAY_SIZE(q->tid) ?
+                                 LWS_ARRAY_SIZE(q->tid) : q->tids;
+
+               if (!name)
+                       for (n = 0; n < nmax; n++)
+                               if ((tid & 0xfffe) == (q->tid[n] & 0xfffe))
+                                       return q;
+
+               if (name && q->qtype == ((tid & 1) ? LWS_ADNS_RECORD_AAAA :
+                                                    LWS_ADNS_RECORD_A) &&
+                   !strcasecmp(name, (const char *)&q[1])) {
+                       if (owner == &dns->cached) {
+                               /* Keep sorted by LRU: move to the head */
+                               lws_dll2_remove(&q->list);
+                               lws_dll2_add_head(&q->list, &dns->cached);
+                       }
+
+                       return q;
+               }
+       } lws_end_foreach_dll_safe(d, d1);
+
+       return NULL;
+}
+
+void
+lws_async_dns_drop_server(struct lws_context *context)
+{
+       context->async_dns.dns_server_set = 0;
+       lws_set_timeout(context->async_dns.wsi, 1, LWS_TO_KILL_ASYNC);
+       context->async_dns.wsi = NULL;
+       context->async_dns.dns_server_connected = 0;
+}
+
+int
+lws_async_dns_complete(lws_adns_q_t *q, lws_adns_cache_t *c)
+{
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  lws_dll2_get_head(&q->wsi_adns)) {
+               struct lws *w = lws_container_of(d, struct lws, adns);
+
+               lws_dll2_remove(d);
+               if (c && c->results) {
+                       lwsl_wsi_debug(w, "q: %p, c: %p, refcount %d -> %d",
+                                   q, c, c->refcount, c->refcount + 1);
+                       c->refcount++;
+               }
+               lws_set_timeout(w, NO_PENDING_TIMEOUT, 0);
+               /*
+                * This may decide to close / delete w
+                */
+               if (w->adns_cb(w, (const char *)&q[1], c ? c->results : NULL, 0,
+                               q->opaque) == NULL)
+                       lwsl_info("%s: failed\n", __func__);
+       //              lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
+       //                                 "adopt udp2 fail");
+
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       if (q->standalone_cb) {
+               if (c && c->results) {
+                       lwsl_wsi_debug(q->dns ? q->dns->wsi : NULL, "q: %p, c: %p, refcount %d -> %d",
+                                   q, c, c->refcount, c->refcount + 1);
+                       c->refcount++;
+               }
+
+               q->standalone_cb(NULL, (const char *)&q[1],
+                                c ? c->results : NULL, 0, q->opaque);
+       }
+
+       lws_adns_dump(q->dns);
+
+       return 0;
+}
+
+static void
+lws_async_dns_sul_cb_retry(struct lws_sorted_usec_list *sul)
+{
+       lws_adns_q_t *q = lws_container_of(sul, lws_adns_q_t, sul);
+
+       lwsl_wsi_info(q->dns ? q->dns->wsi : NULL, "in");
+       lws_adns_dump(q->dns);
+
+       if (q->dns && q->dns->wsi) {
+               q->is_retry = 1;
+               lws_callback_on_writable(q->dns->wsi);
+       }
+}
+
+static void
+lws_async_dns_writeable(struct lws *wsi, lws_adns_q_t *q)
+{
+       uint8_t pkt[LWS_PRE + DNS_PACKET_LEN], *e = &pkt[sizeof(pkt)], *p, *pl;
+       int m, n, which;
+       const char *name;
+
+       /*
+        * We managed to get to the point of being WRITEABLE, which is not a
+        * given if no routes.  So call off the write_sul timeout for that.
+        */
+       lws_sul_cancel(&q->write_sul);
+
+       if (!q->is_retry && q->sent[0]
+#if defined(LWS_WITH_IPV6)
+                && q->sent[0] == q->sent[1]
+#endif
+       )
+               return;
+
+       q->is_retry = 0;
+
+       /*
+        * UDP is not reliable, it can be locally dropped, or dropped
+        * by any intermediary or the remote peer.  So even though we
+        * will do the write in a moment, we schedule another request
+        * for rewrite according to the wsi retry policy.
+        *
+        * If the result came before, we'll cancel it as part of the
+        * wsi close.
+        *
+        * If we have already reached the end of our concealed retries
+        * in the policy, just close without another write.
+        */
+       if (lws_dll2_is_detached(&q->sul.list) &&
+           lws_retry_sul_schedule_retry_wsi(wsi, &q->sul,
+                                      lws_async_dns_sul_cb_retry, &q->retry)) {
+               /* we have reached the end of our concealed retries */
+               lwsl_wsi_info(wsi, "failing query");
+               /*
+                * our policy is to force reloading the dns server info
+                * if our connection ever timed out, in case it or the
+                * routing state changed
+                */
+
+               lws_async_dns_drop_server(q->context);
+               goto qfail;
+       }
+
+       name = (const char *)&q[1];
+
+       p = &pkt[LWS_PRE];
+       memset(p, 0, DHO_SIZEOF);
+
+#if defined(LWS_WITH_IPV6)
+       if (!q->responded) {
+               /* must pick between ipv6 and ipv4 */
+               which = q->sent[0] >= q->sent[1];
+               q->sent[which]++;
+               q->asked = 3; /* want results for 4 & 6 before done */
+       } else
+               which = q->responded & 1;
+#else
+       which = 0;
+       q->asked = 1;
+#endif
+
+       lwsl_wsi_info(wsi, "%s, which %d", name, which);
+
+       /* we hack b0 of the tid to be 0 = A, 1 = AAAA */
+
+       lws_ser_wu16be(&p[DHO_TID],
+#if defined(LWS_WITH_IPV6)
+                       which ? (LADNS_MOST_RECENT_TID(q) | 1) :
+#endif
+                                       LADNS_MOST_RECENT_TID(q));
+       lws_ser_wu16be(&p[DHO_FLAGS], (1 << 8));
+       lws_ser_wu16be(&p[DHO_NQUERIES], 1);
+
+       p += DHO_SIZEOF;
+
+       /* start of label-formatted qname */
+
+       pl = p++;
+
+       do {
+               if (*name == '.' || !*name) {
+                       *pl = (uint8_t)(unsigned int)lws_ptr_diff(p, pl + 1);
+                       pl = p;
+                       *p++ = 0; /* also serves as terminal length */
+                       if (!*name++)
+                               break;
+               } else
+                       *p++ = (uint8_t)*name++;
+       } while (p + 6 < e);
+
+       if (p + 6 >= e) {
+               assert(0);
+               lwsl_wsi_err(wsi, "name too big");
+               goto qfail;
+       }
+
+       lws_ser_wu16be(p, which ? LWS_ADNS_RECORD_AAAA : LWS_ADNS_RECORD_A);
+       p += 2;
+
+       lws_ser_wu16be(p, 1); /* IN class */
+       p += 2;
+
+       assert(p < pkt + sizeof(pkt) - LWS_PRE);
+       n = lws_ptr_diff(p, pkt + LWS_PRE);
+
+       m = lws_write(wsi, pkt + LWS_PRE, (unsigned int)n, 0);
+       if (m != n) {
+               lwsl_wsi_notice(wsi, "dns write failed %d %d errno %d",
+                           m, n, errno);
+               goto qfail;
+       }
+
+#if defined(LWS_WITH_IPV6)
+       if (!q->responded && q->sent[0] != q->sent[1]) {
+               lwsl_wsi_debug(wsi, "request writeable for ipv6");
+               lws_callback_on_writable(wsi);
+       }
+#endif
+
+       return;
+
+qfail:
+       lwsl_wsi_warn(wsi, "failing query doing NULL completion");
+       /*
+        * in ipv6 case, we made a cache entry for the first response but
+        * evidently the second response didn't come in time, purge the
+        * incomplete cache entry
+        */
+       if (q->firstcache) {
+               lwsl_wsi_debug(wsi, "destroy firstcache");
+               lws_adns_cache_destroy(q->firstcache);
+               q->firstcache = NULL;
+       }
+       lws_async_dns_complete(q, NULL);
+       lws_adns_q_destroy(q);
+}
+
+static int
+callback_async_dns(struct lws *wsi, enum lws_callback_reasons reason,
+                  void *user, void *in, size_t len)
+{
+       struct lws_async_dns *dns = &(lws_get_context(wsi)->async_dns);
+
+       switch (reason) {
+
+       /* callbacks related to raw socket descriptor */
+
+        case LWS_CALLBACK_RAW_ADOPT:
+               //lwsl_wsi_user(wsi, "LWS_CALLBACK_RAW_ADOPT");
+                break;
+
+       case LWS_CALLBACK_RAW_CLOSE:
+               //lwsl_wsi_user(wsi, "LWS_CALLBACK_RAW_CLOSE");
+               break;
+
+       case LWS_CALLBACK_RAW_RX:
+               //lwsl_wsi_user(wsi, "LWS_CALLBACK_RAW_RX (%d)", (int)len);
+               // lwsl_hexdump_wsi_notice(wsi, in, len);
+               lws_adns_parse_udp(dns, in, len);
+               break;
+
+       case LWS_CALLBACK_RAW_WRITEABLE:
+               //lwsl_wsi_user(wsi, "LWS_CALLBACK_RAW_WRITEABLE");
+               lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                          dns->waiting.head) {
+                       lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t,
+                                                          list);
+
+                       if (//lws_dll2_is_detached(&q->sul.list) &&
+                           (!q->asked || q->responded != q->asked))
+                               lws_async_dns_writeable(wsi, q);
+               } lws_end_foreach_dll_safe(d, d1);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+struct lws_protocols lws_async_dns_protocol = {
+       "lws-async-dns", callback_async_dns, 0, 0, 0, NULL, 0
+};
+
+int
+lws_async_dns_init(struct lws_context *context)
+{
+       lws_async_dns_t *dns = &context->async_dns;
+       char ads[48];
+       int n;
+
+       if (dns->wsi)
+               return 0;
+
+       if (!context->vhost_list) { /* coverity... system vhost always present */
+               lwsl_cx_err(context, "no system vhost");
+               return 1;
+       }
+
+       memset(&dns->sa46, 0, sizeof(dns->sa46));
+
+#if defined(LWS_WITH_SYS_DHCP_CLIENT)
+       if (lws_dhcpc_status(context, &dns->sa46))
+               goto ok;
+#endif
+
+       n = lws_plat_asyncdns_init(context, &dns->sa46);
+       if (n < 0) {
+               lwsl_cx_warn(context, "no valid dns server, retry");
+
+               return 1;
+       }
+
+       if (n != LADNS_CONF_SERVER_CHANGED)
+               return 0;
+
+#if defined(LWS_WITH_SYS_DHCP_CLIENT)
+ok:
+#endif
+       dns->sa46.sa4.sin_port = htons(53);
+       lws_write_numeric_address((uint8_t *)&dns->sa46.sa4.sin_addr.s_addr, 4,
+                                 ads, sizeof(ads));
+
+       dns->wsi = lws_create_adopt_udp(context->vhost_list, ads, 53, 0,
+                                       lws_async_dns_protocol.name, NULL,
+                                       NULL, NULL, &retry_policy, "asyncdns");
+       if (!dns->wsi) {
+               lwsl_cx_err(context, "foreign socket adoption failed");
+               return 1;
+       }
+
+       context->async_dns.wsi->udp->sa46 = dns->sa46;
+
+       dns->dns_server_set = 1;
+
+       return 0;
+}
+
+lws_adns_cache_t *
+lws_adns_get_cache(lws_async_dns_t *dns, const char *name)
+{
+       lws_adns_cache_t *c;
+
+       if (!name) {
+               assert(0);
+               return NULL;
+       }
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  lws_dll2_get_head(&dns->cached)) {
+               c = lws_container_of(d, lws_adns_cache_t, list);
+
+               // lwsl_wsi_notice(dns->wsi, "%s vs %s (inc %d)", name, c->name, c->incomplete);
+
+               if (!c->incomplete && !strcasecmp(name, c->name)) {
+                       /* Keep sorted by LRU: move to the head */
+                       lws_dll2_remove(&c->list);
+                       lws_dll2_add_head(&c->list, &dns->cached);
+
+                       return c;
+               }
+       } lws_end_foreach_dll_safe(d, d1);
+
+       return NULL;
+}
+
+#if defined(_DEBUG)
+void
+lws_adns_dump(lws_async_dns_t *dns)
+{
+       lws_adns_cache_t *c;
+
+       if (!dns)
+               return;
+
+       lwsl_wsi_info(dns->wsi, "ADNS cache %u entries",
+                       (unsigned int)dns->cached.count);
+
+       lws_start_foreach_dll(struct lws_dll2 *, d,
+                             lws_dll2_get_head(&dns->cached)) {
+               c = lws_container_of(d, lws_adns_cache_t, list);
+
+               lwsl_wsi_info(dns->wsi, "cache: '%s', exp: %lldus, incomp %d, "
+                         "fl 0x%x, refc %d, res %p\n", c->name,
+                         (long long)(c->sul.us - lws_now_usecs()),
+                         c->incomplete, c->flags, c->refcount, c->results);
+       } lws_end_foreach_dll(d);
+
+       lws_start_foreach_dll(struct lws_dll2 *, d,
+                                  lws_dll2_get_head(&dns->waiting)) {
+               lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
+
+               lwsl_wsi_info(dns->wsi, "q: '%s', sent %d, resp %d",
+                           (const char *)&q[1], q->sent[0],
+                           q->responded);
+       } lws_end_foreach_dll(d);
+}
+#endif
+
+void
+lws_adns_cache_destroy(lws_adns_cache_t *c)
+{
+       lws_dll2_remove(&c->sul.list);
+       lws_dll2_remove(&c->list);
+       if (c->chain)
+               lws_free(c->chain);
+       lws_free(c);
+}
+
+static int
+cache_clean(struct lws_dll2 *d, void *user)
+{
+       lws_adns_cache_destroy(lws_container_of(d, lws_adns_cache_t, list));
+
+       return 0;
+}
+
+void
+sul_cb_expire(struct lws_sorted_usec_list *sul)
+{
+       lws_adns_cache_t *c = lws_container_of(sul, lws_adns_cache_t, sul);
+
+       lws_adns_cache_destroy(c);
+}
+
+void
+sul_cb_write(struct lws_sorted_usec_list *sul)
+{
+       lws_adns_q_t *q = lws_container_of(sul, lws_adns_q_t, write_sul);
+
+       /*
+        * Something's up, we couldn't even get from write request to
+        * WRITEABLE within the timeout, let alone the result... fail
+        * the query and everyone riding on it...
+        */
+
+       lwsl_wsi_info(q->dns ? q->dns->wsi : NULL, "failing");
+       lws_adns_dump(q->dns);
+
+       lws_async_dns_complete(q, NULL); /* no cache to relate to */
+       lws_adns_q_destroy(q);
+}
+
+void
+lws_async_dns_freeaddrinfo(const struct addrinfo **pai)
+{
+       lws_adns_cache_t *c;
+
+       if (!*pai)
+               return;
+
+       /*
+        * First query may have been empty... if second has something, we
+        * fixed up the first result to point to second... but it means
+        * looking backwards from ai, which is c->result, which is the second
+        * packet's results, doesn't get us to the firstcache pointer.
+        *
+        * Adjust c to the firstcache in this case.
+        */
+
+       c = &((lws_adns_cache_t *)(*pai))[-1];
+       if (c->firstcache)
+               c = c->firstcache;
+
+       lwsl_debug("%s: c %p, %s, refcount %d -> %d\n", __func__, c,
+                  (c->results && c->results->ai_canonname) ?
+                               c->results->ai_canonname : "none",
+                                               c->refcount, c->refcount - 1);
+
+       assert(c->refcount > 0);
+       c->refcount--;
+       *pai = NULL;
+}
+
+void
+lws_async_dns_trim_cache(lws_async_dns_t *dns)
+{
+       lws_adns_cache_t *c1;
+
+       if (dns->cached.count + 1< MAX_CACHE_ENTRIES)
+               return;
+
+       c1 = lws_container_of(lws_dll2_get_tail(&dns->cached),
+                                               lws_adns_cache_t, list);
+       if (c1->refcount)
+               lwsl_wsi_info(dns->wsi, "acache %p: refcount %d on purge",
+                               c1, c1->refcount);
+       else
+               lws_adns_cache_destroy(c1);
+}
+
+
+static int
+clean(struct lws_dll2 *d, void *user)
+{
+       lws_adns_q_destroy(lws_container_of(d, lws_adns_q_t, list));
+
+       return 0;
+}
+
+void
+lws_async_dns_deinit(lws_async_dns_t *dns)
+{
+       lws_dll2_foreach_safe(&dns->waiting, NULL, clean);
+       lws_dll2_foreach_safe(&dns->cached, NULL, cache_clean);
+
+       if (dns->wsi && !dns->dns_server_connected) {
+               lwsl_wsi_notice(dns->wsi, "late free of incomplete dns wsi");
+               __lws_lc_untag(dns->wsi->a.context, &dns->wsi->lc);
+#if defined(LWS_WITH_SYS_METRICS)
+               lws_metrics_tags_destroy(&dns->wsi->cal_conn.mtags_owner);
+#endif
+               lws_free_set_NULL(dns->wsi->udp);
+               lws_free_set_NULL(dns->wsi);
+       }
+}
+
+
+static int
+cancel(struct lws_dll2 *d, void *user)
+{
+       lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d3, d4,
+                                  lws_dll2_get_head(&q->wsi_adns)) {
+               struct lws *w = lws_container_of(d3, struct lws, adns);
+
+               if (user == w) {
+                       lws_dll2_remove(d3);
+                       if (!q->wsi_adns.count)
+                               lws_adns_q_destroy(q);
+                       return 1;
+               }
+       } lws_end_foreach_dll_safe(d3, d4);
+
+       return 0;
+}
+
+void
+lws_async_dns_cancel(struct lws *wsi)
+{
+       lws_async_dns_t *dns = &wsi->a.context->async_dns;
+
+       lws_dll2_foreach_safe(&dns->waiting, wsi, cancel);
+}
+
+
+static int
+check_tid(struct lws_dll2 *d, void *user)
+{
+       lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
+       int n = 0, nmax = q->tids >= LWS_ARRAY_SIZE(q->tid) ?
+                         LWS_ARRAY_SIZE(q->tid) : q->tids;
+       uint16_t check = (uint16_t)(intptr_t)user;
+
+       for (n = 0; n < nmax; n++)
+               if (check == q->tid[n])
+                       return 1;
+
+       return 0;
+}
+
+int
+lws_async_dns_get_new_tid(struct lws_context *context, lws_adns_q_t *q)
+{
+       lws_async_dns_t *dns = &context->async_dns;
+       int budget = 10;
+
+       /*
+        * Make the TID unpredictable, but must be unique amongst ongoing ones
+        */
+       do {
+               uint16_t tid;
+
+               if (lws_get_random(context, &tid, 2) != 2)
+                       return -1;
+
+               if (lws_dll2_foreach_safe(&dns->waiting,
+                                         (void *)(intptr_t)tid, check_tid))
+                       continue;
+
+               q->tids++;
+               LADNS_MOST_RECENT_TID(q) = tid;
+
+               return 0;
+
+       } while (budget--);
+
+       lwsl_cx_err(context, "unable to get unique tid");
+
+       return -1;
+}
+
+struct temp_q {
+       lws_adns_q_t tq;
+       char name[48];
+};
+
+lws_async_dns_retcode_t
+lws_async_dns_query(struct lws_context *context, int tsi, const char *name,
+                   adns_query_type_t qtype, lws_async_dns_cb_t cb,
+                   struct lws *wsi, void *opaque)
+{
+       lws_async_dns_t *dns = &context->async_dns;
+       size_t nlen = strlen(name);
+       lws_sockaddr46 *sa46;
+       lws_adns_cache_t *c;
+       struct addrinfo *ai;
+       struct temp_q tmq;
+       lws_adns_q_t *q;
+       uint8_t ads[16];
+       char *p;
+       int m;
+
+       lwsl_cx_info(context, "entry %s", name);
+       lws_adns_dump(dns);
+
+#if !defined(LWS_WITH_IPV6)
+       if (qtype == LWS_ADNS_RECORD_AAAA) {
+               lwsl_cx_err(context, "ipv6 not enabled");
+               goto failed;
+       }
+#endif
+
+       if (nlen >= DNS_MAX - 1)
+               goto failed;
+
+       /*
+        * we magically know 'localhost' and 'localhost6' if IPv6, this is a
+        * sort of canned /etc/hosts
+        */
+
+       if (!strcmp(name, "localhost"))
+               name = "127.0.0.1";
+
+#if defined(LWS_WITH_IPV6)
+       if (!strcmp(name, "localhost6"))
+               name = "::1";
+#endif
+
+       if (wsi) {
+               if (!lws_dll2_is_detached(&wsi->adns)) {
+                       lwsl_cx_err(context, "%s already bound to query %p",
+                                       lws_wsi_tag(wsi), wsi->adns.owner);
+                       goto failed;
+               }
+               wsi->adns_cb = cb;
+       }
+
+       /* there's a done, cached query we can just reuse? */
+
+       c = lws_adns_get_cache(dns, name);
+       if (c) {
+               lwsl_cx_info(context, "%s: using cached, c->results %p",
+                         name, c->results);
+               m = c->results ? LADNS_RET_FOUND : LADNS_RET_FAILED;
+               if (c->results)
+                       c->refcount++;
+
+#if defined(LWS_WITH_SYS_METRICS)
+               lws_metric_event(context->mt_adns_cache,  METRES_GO, 0);
+#endif
+
+               if (cb(wsi, name, c->results, m, opaque) == NULL)
+                       return LADNS_RET_FAILED_WSI_CLOSED;
+
+               return m;
+       } else
+               lwsl_cx_info(context, "%s uncached", name);
+
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_metric_event(context->mt_adns_cache, METRES_NOGO, 0);
+#endif
+
+       /*
+        * It's a 1.2.3.4 or ::1 type IP address already?  We don't need a dns
+        * server set up to be able to create an addrinfo result for that.
+        *
+        * Create it as a cached object so it follows the refcount lifecycle
+        * of any other result
+        */
+
+       m = lws_parse_numeric_address(name, ads, sizeof(ads));
+       if (m == 4
+#if defined(LWS_WITH_IPV6)
+               || m == 16
+#endif
+       ) {
+               lws_async_dns_trim_cache(dns);
+
+               c = lws_zalloc(sizeof(lws_adns_cache_t) +
+                              sizeof(struct addrinfo) +
+                              sizeof(lws_sockaddr46) + nlen + 1, "adns-numip");
+               if (!c)
+                       goto failed;
+
+               ai = (struct addrinfo *)&c[1];
+               sa46 = (lws_sockaddr46 *)&ai[1];
+
+               ai->ai_socktype = SOCK_STREAM;
+               c->name = (const char *)&sa46[1];
+               memcpy((char *)c->name, name, nlen + 1);
+               ai->ai_canonname = (char *)&sa46[1];
+
+               c->results = ai;
+               memset(&tmq.tq, 0, sizeof(tmq.tq));
+               tmq.tq.opaque = opaque;
+               if (wsi) {
+                       wsi->adns_cb = cb;
+                       lws_dll2_add_head(&wsi->adns, &tmq.tq.wsi_adns);
+               } else
+                       tmq.tq.standalone_cb = cb;
+               lws_strncpy(tmq.name, name, sizeof(tmq.name));
+
+               lws_dll2_add_head(&c->list, &dns->cached);
+               lws_sul_schedule(context, 0, &c->sul, sul_cb_expire,
+                                3600ll * LWS_US_PER_SEC);
+
+               lws_adns_dump(dns);
+       }
+
+       if (m == 4) {
+               ai = (struct addrinfo *)&c[1];
+               sa46 = (lws_sockaddr46 *)&ai[1];
+               ai->ai_family = sa46->sa4.sin_family = AF_INET;
+               ai->ai_addrlen = sizeof(sa46->sa4);
+               ai->ai_addr = (struct sockaddr *)&sa46->sa4;
+               memcpy(&sa46->sa4.sin_addr, ads, (unsigned int)m);
+
+               lws_async_dns_complete(&tmq.tq, c);
+
+               return LADNS_RET_FOUND;
+       }
+
+#if defined(LWS_WITH_IPV6)
+       if (m == 16) {
+               ai->ai_family = sa46->sa6.sin6_family = AF_INET6;
+               ai->ai_addrlen = sizeof(sa46->sa6);
+               ai->ai_addr = (struct sockaddr *)&sa46->sa6;
+               memcpy(&sa46->sa6.sin6_addr, ads, (unsigned int)m);
+
+               lws_async_dns_complete(&tmq.tq, c);
+
+               return LADNS_RET_FOUND;
+       }
+#endif
+
+       /*
+        * to try anything else we need a remote server configured...
+        */
+
+       if (!context->async_dns.dns_server_set &&
+           lws_async_dns_init(context)) {
+               lwsl_cx_notice(context, "init failed");
+               goto failed;
+       }
+
+       /* there's an ongoing query we can share the result of */
+
+       q = lws_adns_get_query(dns, qtype, &dns->waiting, 0, name);
+       if (q) {
+               lwsl_cx_debug(context, "dns piggybacking: %d:%s",
+                               qtype, name);
+               if (wsi)
+                       lws_dll2_add_head(&wsi->adns, &q->wsi_adns);
+
+               return LADNS_RET_CONTINUING;
+       }
+
+       /*
+        * Allocate new query / queries... this is a bit complicated because
+        * multiple queries in one packet are not supported peoperly in DNS
+        * itself, and there's no reliable other way to get both ipv6 and ipv4
+        * (AAAA and A) responses in one hit.
+        *
+        * If we don't support ipv6, it's simple, we just ask for A and that's
+        * it.  But if we do support ipv6, we need to ask twice, once for A
+        * and in a separate query, again for AAAA.
+        *
+        * For ipv6, A / ipv4 is routable over ipv6.  So we always ask for A
+        * first and then if ipv6, AAAA separately.
+        *
+        * Allocate for DNS_MAX, because we may recurse and alter what we're
+        * looking for.
+        *
+        * 0             sizeof(*q)                  sizeof(*q) + DNS_MAX
+        * [lws_adns_q_t][ name (DNS_MAX reserved) ] [ name \0 ]
+        */
+
+       q = (lws_adns_q_t *)lws_malloc(sizeof(*q) + DNS_MAX + nlen + 1,
+                                       __func__);
+       if (!q)
+               goto failed;
+       memset(q, 0, sizeof(*q));
+
+       if (wsi)
+               lws_dll2_add_head(&wsi->adns, &q->wsi_adns);
+
+       q->qtype = (uint16_t)qtype;
+
+       if (lws_async_dns_get_new_tid(context, q)) {
+               lwsl_cx_err(context, "tid fail");
+               goto failed;
+       }
+
+       LADNS_MOST_RECENT_TID(q) &= 0xfffe;
+       q->context = context;
+       q->tsi = (uint8_t)tsi;
+       q->opaque = opaque;
+       q->dns = dns;
+
+       if (!wsi)
+               q->standalone_cb = cb;
+
+       /* schedule a retry according to the retry policy on the wsi */
+       if (lws_retry_sul_schedule_retry_wsi(dns->wsi, &q->sul,
+                                        lws_async_dns_sul_cb_retry, &q->retry))
+               goto failed;
+
+       /* fail us if we can't write by this timeout */
+       lws_sul_schedule(context, 0, &q->write_sul, sul_cb_write, LWS_US_PER_SEC);
+
+       /*
+        * We may rewrite the copy at +sizeof(*q) for CNAME recursion.  Keep
+        * a second copy at + sizeof(*q) + DNS_MAX so we can create the cache
+        * entry for the original name, not the last CNAME we met.
+        */
+
+       p = (char *)&q[1];
+       while (nlen--) {
+               *p++ = (char)tolower(*name++);
+               p[DNS_MAX - 1] = p[-1];
+       }
+       *p = '\0';
+       p[DNS_MAX] = '\0';
+
+       lws_callback_on_writable(dns->wsi);
+
+       lws_dll2_add_head(&q->list, &dns->waiting);
+
+       lws_metrics_caliper_bind(q->metcal, context->mt_conn_dns);
+       q->go_nogo = METRES_NOGO;
+       /* caliper is reported in lws_adns_q_destroy */
+
+       lwsl_cx_info(context, "created new query: %s", name);
+       lws_adns_dump(dns);
+
+       return LADNS_RET_CONTINUING;
+
+failed:
+       lwsl_cx_notice(context, "failed");
+       if (!cb(wsi, NULL, NULL, LADNS_RET_FAILED, opaque))
+               return LADNS_RET_FAILED_WSI_CLOSED;
+
+       return LADNS_RET_FAILED;
+}
diff --git a/lib/system/async-dns/private-lib-async-dns.h b/lib/system/async-dns/private-lib-async-dns.h
new file mode 100644 (file)
index 0000000..f213448
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#define DNS_MAX                        96      /* Maximum host name            */
+#define DNS_RECURSION_LIMIT    3
+#define DNS_PACKET_LEN         1400    /* Buffer size for DNS packet   */
+#define MAX_CACHE_ENTRIES      10      /* Dont cache more than that    */
+#define DNS_QUERY_TIMEOUT      30      /* Query timeout, seconds       */
+
+/*
+ * ... when we completed a query then the query object is destroyed and a
+ * cache object below is created with the results in getaddrinfo format
+ * appended to the allocation
+ */
+
+typedef struct lws_adns_cache {
+       lws_sorted_usec_list_t  sul;    /* for cache TTL management */
+       lws_dll2_t              list;
+
+       struct lws_adns_cache   *firstcache;
+       struct lws_adns_cache   *chain;
+       struct addrinfo         *results;
+       const char              *name;
+       uint8_t                 flags;  /* b0 = has ipv4, b1 = has ipv6 */
+       char                    refcount;
+       char                    incomplete;
+       /* addrinfo, lws_sa46, then name overallocated here */
+} lws_adns_cache_t;
+
+/*
+ * these objects are used while a query is ongoing...
+ */
+
+typedef struct {
+       lws_sorted_usec_list_t  sul;    /* per-query write retry timer */
+       lws_sorted_usec_list_t  write_sul;      /* fail if unable to write by this time */
+       lws_dll2_t              list;
+
+       lws_metrics_caliper_compose(metcal)
+
+       lws_dll2_owner_t        wsi_adns;
+       lws_async_dns_cb_t      standalone_cb;  /* if not associated to wsi */
+       struct lws_context      *context;
+       void                    *opaque;
+       struct addrinfo         **last;
+       lws_async_dns_t         *dns;
+
+       lws_adns_cache_t        *firstcache;
+
+       lws_async_dns_retcode_t ret;
+       uint16_t                tid[3]; /* last 3 sent tid */
+       uint16_t                qtype;
+       uint16_t                retry;
+       uint8_t                 tsi;
+
+#if defined(LWS_WITH_IPV6)
+       uint8_t                 sent[2];
+#else
+       uint8_t                 sent[1];
+#endif
+       uint8_t                 asked;
+       uint8_t                 responded;
+
+       uint8_t                 recursion;
+       uint8_t                 tids;
+       uint8_t                 go_nogo;
+
+       uint8_t                 is_retry:1;
+
+       /* name overallocated here */
+} lws_adns_q_t;
+
+#define LADNS_MOST_RECENT_TID(_q) \
+               q->tid[(int)(_q->tids - 1) % (int)LWS_ARRAY_SIZE(q->tid)]
+
+enum {
+       DHO_TID,
+       DHO_FLAGS = 2,
+       DHO_NQUERIES = 4,
+       DHO_NANSWERS = 6,
+       DHO_NAUTH = 8,
+       DHO_NOTHER = 10,
+
+       DHO_SIZEOF = 12 /* last */
+};
+
+void
+lws_adns_q_destroy(lws_adns_q_t *q);
+
+void
+sul_cb_expire(struct lws_sorted_usec_list *sul);
+
+void
+lws_adns_cache_destroy(lws_adns_cache_t *c);
+
+int
+lws_async_dns_complete(lws_adns_q_t *q, lws_adns_cache_t *c);
+
+lws_adns_cache_t *
+lws_adns_get_cache(lws_async_dns_t *dns, const char *name);
+
+void
+lws_adns_parse_udp(lws_async_dns_t *dns, const uint8_t *pkt, size_t len);
+
+lws_adns_q_t *
+lws_adns_get_query(lws_async_dns_t *dns, adns_query_type_t qtype,
+                  lws_dll2_owner_t *owner, uint16_t tid, const char *name);
+
+void
+lws_async_dns_trim_cache(lws_async_dns_t *dns);
+
+int
+lws_async_dns_get_new_tid(struct lws_context *context, lws_adns_q_t *q);
+
+
+#if defined(_DEBUG)
+void
+lws_adns_dump(lws_async_dns_t *dns);
+#else
+#define lws_adns_dump(_d)
+#endif
diff --git a/lib/system/dhcpclient/dhcpc4.c b/lib/system/dhcpclient/dhcpc4.c
new file mode 100644 (file)
index 0000000..d7f9199
--- /dev/null
@@ -0,0 +1,532 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * The protocol part of dhcp4 client
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-system-dhcpclient.h"
+
+#define LDHC_OP_BOOTREQUEST 1
+#define LDHC_OP_BOOTREPLY 2
+
+/*
+ *  IPv4... max total 576
+ *
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |     op (1)    |   htype (1)   |   hlen (1)    |   hops (1)    |
+ * +---------------+---------------+---------------+---------------+
+ * |  +04                       xid (4)                            |
+ * +-------------------------------+-------------------------------+
+ * |  +08      secs (2)            |  +0a         flags (2)        |
+ * +-------------------------------+-------------------------------+
+ * |  +0C                     ciaddr  (4)      client IP           |
+ * +---------------------------------------------------------------+
+ * |  +10                     yiaddr  (4)      your IP             |
+ * +---------------------------------------------------------------+
+ * |  +14                     siaddr  (4)      server IP           |
+ * +---------------------------------------------------------------+
+ * |  +18                     giaddr  (4)      gateway IP          |
+ * +---------------------------------------------------------------+
+ * |                                                               |
+ * |  +1C                     chaddr  (16)     client HWADDR       |
+ * +---------------------------------------------------------------+
+ * |                                                               |
+ * |  +2C                     sname   (64)                         |
+ * +---------------------------------------------------------------+
+ * |                                                               |
+ * |  +6C                     file    (128)                        |
+ * +---------------------------------------------------------------+
+ * |                                                               |
+ * |  +EC                     options (variable)                   |
+ * +---------------------------------------------------------------+
+ */
+
+static const uint8_t rawdisc4[] = {
+       0x45, 0x00, 0, 0, 0, 0, 0x40, 0, 0x2e, IPPROTO_UDP,
+       0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff,
+       0, 68, 0, 67, 0, 0, 0, 0
+};
+
+static const uint32_t botable2[] = { 1500, 1750, 5000 /* in case dog slow */ };
+static const lws_retry_bo_t bo2 = {
+       botable2, LWS_ARRAY_SIZE(botable2), LWS_RETRY_CONCEAL_ALWAYS, 0, 0, 20 };
+
+static int
+lws_dhcpc4_prep(uint8_t *start, unsigned int bufsiz, lws_dhcpc_req_t *r, int op)
+{
+       uint8_t *p = start;
+
+       memset(start, 0, bufsiz);
+
+       *p++ = 1;
+       *p++ = 1;
+       *p++ = 6; /* sizeof ethernet MAC */
+
+       memcpy(p + 1, r->xid, 4);
+
+//     p[7] = 0x80; /* broadcast flag */
+
+       p += 0x1c - 3;
+
+       if (lws_plat_ifname_to_hwaddr(r->wsi_raw->desc.sockfd,
+                                     (const char *)&r[1], r->is.mac, 6) < 0)
+               return -1;
+
+       memcpy(p, r->is.mac, 6);
+
+       p += 16 + 64 + 128;
+
+       *p++ = 0x63; /* RFC2132 Magic Cookie indicates start of options */
+       *p++ = 0x82;
+       *p++ = 0x53;
+       *p++ = 0x63;
+
+       *p++ = LWSDHC4POPT_MESSAGE_TYPE;
+       *p++ = 1;       /* length */
+       *p++ = (uint8_t)op;
+
+       switch (op) {
+       case LWSDHC4PDISCOVER:
+               *p++ = LWSDHC4POPT_PARAM_REQ_LIST;
+               *p++ = 4;       /* length */
+               *p++ = LWSDHC4POPT_SUBNET_MASK;
+               *p++ = LWSDHC4POPT_ROUTER;
+               *p++ = LWSDHC4POPT_DNSERVER;
+               *p++ = LWSDHC4POPT_DOMAIN_NAME;
+               break;
+
+       case LWSDHC4PREQUEST:
+               if (r->is.sa46[LWSDH_SA46_IP].sa4.sin_family != AF_INET)
+                       break;
+               *p++ = LWSDHC4POPT_REQUESTED_ADS;
+               *p++ = 4;       /* length */
+               lws_ser_wu32be(p, r->is.sa46[LWSDH_SA46_IP].sa4.sin_addr.s_addr);
+               p += 4;
+               *p++ = LWSDHC4POPT_SERVER_ID;
+               *p++ = 4;       /* length */
+               lws_ser_wu32be(p, r->is.sa46[LWSDH_SA46_DHCP_SERVER].sa4.sin_addr.s_addr);
+               p += 4;
+               break;
+       }
+
+       *p++ = LWSDHC4POPT_END_OPTIONS;
+
+       return lws_ptr_diff(p, start);
+}
+
+static int
+callback_dhcpc4(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+              void *in, size_t len)
+{
+       lws_dhcpc_req_t *r = (lws_dhcpc_req_t *)user;
+       uint8_t pkt[LWS_PRE + 576], *p = pkt + LWS_PRE;
+       int n, m;
+
+       switch (reason) {
+
+        case LWS_CALLBACK_RAW_ADOPT:
+               lwsl_debug("%s: LWS_CALLBACK_RAW_ADOPT\n", __func__);
+               lws_callback_on_writable(wsi);
+               break;
+
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("%s: udp conn failed\n", __func__);
+
+               /* fallthru */
+       case LWS_CALLBACK_RAW_CLOSE:
+               lwsl_debug("%s: LWS_CALLBACK_RAW_CLOSE\n", __func__);
+               if (!r)
+                       break;
+               r->wsi_raw = NULL;
+               lws_sul_cancel(&r->sul_write);
+               if (r->state != LDHC_BOUND) {
+                       r->state = LDHC_INIT;
+                       lws_retry_sul_schedule(r->context, 0, &r->sul_conn,
+                                              &bo2, lws_dhcpc4_retry_conn,
+                                              &r->retry_count_conn);
+               }
+               break;
+
+       case LWS_CALLBACK_RAW_RX:
+
+               if (lws_dhcpc4_parse(r, in, len))
+                       break;
+
+               /*
+                * that's it... commit to the configuration
+                */
+
+               /* set up our network interface as offered */
+
+               if (lws_plat_ifconfig(r->wsi_raw->desc.sockfd, &r->is))
+                       /*
+                        * Problem setting the IP... maybe something
+                        * transient like racing with NetworkManager?
+                        * Since the sul retries are still around it
+                        * will retry
+                        */
+                       return -1;
+
+               /* clear timeouts related to the broadcast socket */
+
+               lws_sul_cancel(&r->sul_write);
+               lws_sul_cancel(&r->sul_conn);
+
+               lwsl_notice("%s: DHCP configured %s\n", __func__,
+                               (const char *)&r[1]);
+               r->state = LDHC_BOUND;
+
+               lws_state_transition_steps(&wsi->a.context->mgr_system,
+                                          LWS_SYSTATE_OPERATIONAL);
+
+               r->cb(r->opaque, &r->is);
+
+               r->wsi_raw = NULL;
+
+               return -1; /* close the broadcast wsi */
+
+       case LWS_CALLBACK_RAW_WRITEABLE:
+
+               if (!r)
+                       break;
+
+               /*
+                * UDP is not reliable, it can be locally dropped, or dropped
+                * by any intermediary or the remote peer.  So even though we
+                * will do the write in a moment, we schedule another request
+                * for rewrite according to the wsi retry policy.
+                *
+                * If the result came before, we'll cancel it in the close flow.
+                *
+                * If we have already reached the end of our concealed retries
+                * in the policy, just close without another write.
+                */
+               if (lws_dll2_is_detached(&r->sul_write.list) &&
+                   lws_retry_sul_schedule_retry_wsi(wsi, &r->sul_write,
+                                                    lws_dhcpc_retry_write,
+                                                    &r->retry_count_write)) {
+                       /* we have reached the end of our concealed retries */
+                       lwsl_warn("%s: concealed retries done, failing\n",
+                                 __func__);
+                       goto retry_conn;
+               }
+
+               switch (r->state) {
+               case LDHC_INIT:
+                       n = LWSDHC4PDISCOVER;
+                       goto bcast;
+
+               case LDHC_REQUESTING:
+                       n = LWSDHC4PREQUEST;
+
+                       /* fallthru */
+bcast:
+                       n = lws_dhcpc4_prep(p + 28, (unsigned int)
+                                       (sizeof(pkt) - LWS_PRE - 28), r, n);
+                       if (n < 0) {
+                               lwsl_err("%s: failed to prep\n", __func__);
+                               break;
+                       }
+
+                       m = lws_plat_rawudp_broadcast(p, rawdisc4,
+                                                     LWS_ARRAY_SIZE(rawdisc4),
+                                                     (size_t)(n + 28),
+                                                     r->wsi_raw->desc.sockfd,
+                                                     (const char *)&r[1]);
+                       if (m < 0)
+                               lwsl_err("%s: Failed to write dhcp client req: "
+                                        "%d %d, errno %d\n", __func__,
+                                        n, m, LWS_ERRNO);
+                       break;
+               default:
+                       break;
+               }
+
+               return 0;
+
+retry_conn:
+               lws_retry_sul_schedule(wsi->a.context, 0, &r->sul_conn, &bo2,
+                                      lws_dhcpc4_retry_conn,
+                                      &r->retry_count_conn);
+
+               return -1;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+struct lws_protocols lws_system_protocol_dhcpc4 =
+       { "lws-dhcp4client", callback_dhcpc4, 0, 128, 0, NULL, 0 };
+
+void
+lws_dhcpc4_retry_conn(struct lws_sorted_usec_list *sul)
+{
+       lws_dhcpc_req_t *r = lws_container_of(sul, lws_dhcpc_req_t, sul_conn);
+
+       if (r->wsi_raw || !lws_dll2_is_detached(&r->sul_conn.list))
+               return;
+
+       /* create the UDP socket aimed at the server */
+
+       r->retry_count_write = 0;
+       r->wsi_raw = lws_create_adopt_udp(r->context->vhost_system, "0.0.0.0",
+                                         68, LWS_CAUDP_PF_PACKET |
+                                             LWS_CAUDP_BROADCAST,
+                                         "lws-dhcp4client", (const char *)&r[1],
+                                         NULL, NULL, &bo2, "dhcpc");
+       lwsl_debug("%s: created wsi_raw: %s\n", __func__, lws_wsi_tag(r->wsi_raw));
+       if (!r->wsi_raw) {
+               lwsl_err("%s: unable to create udp skt\n", __func__);
+
+               lws_retry_sul_schedule(r->context, 0, &r->sul_conn, &bo2,
+                                      lws_dhcpc4_retry_conn,
+                                      &r->retry_count_conn);
+
+               return;
+       }
+
+       /* force the network if up */
+       lws_plat_if_up((const char *)&r[1], r->wsi_raw->desc.sockfd, 0);
+       lws_plat_if_up((const char *)&r[1], r->wsi_raw->desc.sockfd, 1);
+
+       r->wsi_raw->user_space = r;
+       r->wsi_raw->user_space_externally_allocated = 1;
+
+       lws_get_random(r->wsi_raw->a.context, r->xid, 4);
+}
+
+static void
+lws_sa46_set_ipv4(lws_dhcpc_req_t *r, unsigned int which, uint8_t *p)
+{
+       r->is.sa46[which].sa4.sin_family = AF_INET;
+       r->is.sa46[which].sa4.sin_addr.s_addr = ntohl(lws_ser_ru32be(p));
+}
+
+int
+lws_dhcpc4_parse(lws_dhcpc_req_t *r, void *in, size_t len)
+{
+       uint8_t pkt[LWS_PRE + 576], *p = pkt + LWS_PRE, *end;
+       int n, m;
+
+       switch (r->state) {
+       case LDHC_INIT:         /* expect DHCPOFFER */
+       case LDHC_REQUESTING:   /* expect DHCPACK */
+               /*
+                * We should check carefully if we like what we were
+                * sent... anything can spam us with crafted replies
+                */
+               if (len < 0x100)
+                       break;
+
+               p = (uint8_t *)in + 28; /* skip to UDP payload */
+               if (p[0] != 2 || p[1] != 1 || p[2] != 6)
+                       break;
+
+               if (memcmp(&p[4], r->xid, 4))   /* must be our xid */
+                       break;
+
+               if (memcmp(&p[0x1c], r->is.mac, 6)) /* our netif mac? */
+                       break;
+
+               /* the DHCP magic cookie must be in place */
+               if (lws_ser_ru32be(&p[0xec]) != 0x63825363)
+                       break;
+
+               /* "your" client IP address */
+               lws_sa46_set_ipv4(r, LWSDH_SA46_IP, p + 0x10);
+               /* IP of next server used in bootstrap */
+               lws_sa46_set_ipv4(r, LWSDH_SA46_DHCP_SERVER, p + 0x14);
+
+               /* it looks legit so far... look at the options */
+
+               end = (uint8_t *)in + len;
+               p += 0xec + 4;
+               while (p < end) {
+                       uint8_t c = *p++;
+                       uint8_t l = 0;
+
+                       if (c && c != 0xff) {
+                               /* pad 0 and EOT 0xff have no length */
+                               l = *p++;
+                               if (!l) {
+                                       lwsl_err("%s: zero length\n",
+                                                       __func__);
+                                       goto broken;
+                               }
+                               if (p + l > end) {
+                                       /* ...nice try... */
+                                       lwsl_err("%s: bad len\n",
+                                                       __func__);
+                                       goto broken;
+                               }
+                       }
+
+                       if (c == 0xff) /* end of options */
+                               break;
+
+                       m = 0;
+                       switch (c) {
+                       case LWSDHC4POPT_SUBNET_MASK:
+                               n = LWSDH_IPV4_SUBNET_MASK;
+                               goto get_ipv4;
+
+                       case LWSDHC4POPT_ROUTER:
+                               lws_sa46_set_ipv4(r, LWSDH_SA46_IPV4_ROUTER, p);
+                               break;
+
+                       case LWSDHC4POPT_TIME_SERVER:
+                               lws_sa46_set_ipv4(r, LWSDH_SA46_NTP_SERVER, p);
+                               break;
+
+                       case LWSDHC4POPT_BROADCAST_ADS:
+                               n = LWSDH_IPV4_BROADCAST;
+                               goto get_ipv4;
+
+                       case LWSDHC4POPT_LEASE_TIME:
+                               n = LWSDH_LEASE_SECS;
+                               goto get_ipv4;
+
+                       case LWSDHC4POPT_RENEWAL_TIME: /* AKA T1 */
+                               n = LWSDH_RENEWAL_SECS;
+                               goto get_ipv4;
+
+                       case LWSDHC4POPT_REBINDING_TIME: /* AKA T2 */
+                               n = LWSDH_REBINDING_SECS;
+                               goto get_ipv4;
+
+                       case LWSDHC4POPT_DNSERVER:
+                               if (l & 3)
+                                       break;
+                               m = LWSDH_SA46_DNS_SRV_1;
+                               while (l && m - LWSDH_SA46_DNS_SRV_1 < 4) {
+                                       lws_sa46_set_ipv4(r, (unsigned int)m++, p);
+                                       l = (uint8_t)(l - 4);
+                                       p += 4;
+                               }
+                               break;
+
+                       case LWSDHC4POPT_DOMAIN_NAME:
+                               m = l;
+                               if (m > (int)sizeof(r->is.domain) - 1)
+                                       m = sizeof(r->is.domain) - 1;
+                               lws_strnncpy(r->is.domain, (const char *)p,
+                                        (unsigned int)m, sizeof(r->is.domain));
+                               break;
+
+                       case LWSDHC4POPT_MESSAGE_TYPE:
+                               /*
+                                * Confirm this is the right message
+                                * for the state of the negotiation
+                                */
+                               if (r->state == LDHC_INIT && *p != LWSDHC4POFFER)
+                                       goto broken;
+                               if (r->state == LDHC_REQUESTING &&
+                                   *p != LWSDHC4PACK)
+                                       goto broken;
+                               break;
+
+                       default:
+                               break;
+                       }
+
+                       p += l;
+                       continue;
+get_ipv4:
+                       if (l >= 4)
+                               r->is.nums[n] = ntohl(lws_ser_ru32be(p));
+                       p += l;
+                       continue;
+broken:
+                       memset(r->is.sa46, 0, sizeof(r->is.sa46));
+                       break;
+               }
+
+#if defined(_DEBUG)
+               /* dump what we have parsed out */
+
+               for (n = 0; n < (int)_LWSDH_NUMS_COUNT; n++) {
+                       m = (int)ntohl(r->is.nums[n]);
+                       lwsl_info("%s: %d: 0x%x\n", __func__, n, m);
+               }
+
+               for (n = 0; n < (int)_LWSDH_SA46_COUNT; n++) {
+                       lws_sa46_write_numeric_address(&r->is.sa46[n],
+                                                      (char *)pkt, 48);
+                       lwsl_info("%s: %d: %s\n", __func__, n, pkt);
+               }
+#endif
+
+               /*
+                * Having seen everything in there... do we really feel
+                * we could use it?  Everything critical is there?
+                */
+
+               if (!r->is.sa46[LWSDH_SA46_IP].sa4.sin_family ||
+                   !r->is.sa46[LWSDH_SA46_DHCP_SERVER].sa4.sin_family ||
+                   !r->is.sa46[LWSDH_SA46_IPV4_ROUTER].sa4.sin_family ||
+                   !r->is.nums[LWSDH_IPV4_SUBNET_MASK] ||
+                   !r->is.nums[LWSDH_LEASE_SECS] ||
+                   !r->is.sa46[LWSDH_SA46_DNS_SRV_1].sa4.sin_family) {
+                       lwsl_notice("%s: rejecting on incomplete\n", __func__);
+                       memset(r->is.sa46, 0, sizeof(r->is.sa46));
+                       break;
+               }
+
+               /*
+                * Network layout has to be internally consistent...
+                * DHCP server has to be reachable by broadcast and
+                * default route has to be on same subnet
+                */
+
+               if ((r->is.sa46[LWSDH_SA46_IP].sa4.sin_addr.s_addr &
+                                       r->is.nums[LWSDH_IPV4_SUBNET_MASK]) !=
+                   (r->is.sa46[LWSDH_SA46_DHCP_SERVER].sa4.sin_addr.s_addr &
+                                       r->is.nums[LWSDH_IPV4_SUBNET_MASK])) {
+                       lwsl_notice("%s: rejecting on srv %x reachable on mask %x\n",
+                                       __func__, r->is.sa46[LWSDH_SA46_IP].sa4.sin_addr.s_addr,
+                                       r->is.nums[LWSDH_IPV4_SUBNET_MASK]);
+                       break;
+               }
+
+               if (r->state == LDHC_INIT) {
+                       lwsl_info("%s: moving to REQ\n", __func__);
+                       r->state = LDHC_REQUESTING;
+                       lws_callback_on_writable(r->wsi_raw);
+                       //break;
+               }
+
+               return 0;
+
+       default:
+               break;
+       }
+
+       return 1;
+}
+
diff --git a/lib/system/dhcpclient/dhcpclient.c b/lib/system/dhcpclient/dhcpclient.c
new file mode 100644 (file)
index 0000000..ca628e3
--- /dev/null
@@ -0,0 +1,156 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-system-dhcpclient.h"
+
+void
+lws_dhcpc_retry_write(struct lws_sorted_usec_list *sul)
+{
+       lws_dhcpc_req_t *r = lws_container_of(sul, lws_dhcpc_req_t, sul_write);
+
+       lwsl_debug("%s\n", __func__);
+
+       if (r && r->wsi_raw)
+               lws_callback_on_writable(r->wsi_raw);
+}
+
+static void
+lws_dhcpc_destroy(lws_dhcpc_req_t **pr)
+{
+       lws_dhcpc_req_t *r = *pr;
+
+       lws_sul_cancel(&r->sul_conn);
+       lws_sul_cancel(&r->sul_write);
+       lws_sul_cancel(&r->sul_renew);
+
+       if (r->wsi_raw)
+               lws_set_timeout(r->wsi_raw, 1, LWS_TO_KILL_ASYNC);
+
+       lws_dll2_remove(&r->list);
+
+       lws_free_set_NULL(r);
+}
+
+int
+lws_dhcpc_status(struct lws_context *context, lws_sockaddr46 *sa46)
+{
+       lws_dhcpc_req_t *r;
+
+       lws_start_foreach_dll(struct lws_dll2 *, p, context->dhcpc_owner.head) {
+               r = (lws_dhcpc_req_t *)p;
+
+               if (r->state == LDHC_BOUND) {
+                       if (sa46) {
+                               memcpy(sa46, &r->is.sa46[LWSDH_SA46_DNS_SRV_1],
+                                      sizeof(*sa46));
+                       }
+                       return 1;
+               }
+
+       } lws_end_foreach_dll(p);
+
+       return 0;
+}
+
+static lws_dhcpc_req_t *
+lws_dhcpc_find(struct lws_context *context, const char *iface, int af)
+{
+       lws_dhcpc_req_t *r;
+
+       /* see if we are already looking after this af / iface combination */
+
+       lws_start_foreach_dll(struct lws_dll2 *, p, context->dhcpc_owner.head) {
+               r = (lws_dhcpc_req_t *)p;
+
+               if (!strcmp((const char *)&r[1], iface) && af == r->af)
+                       return r; /* yes...  */
+
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
+/*
+ * Create a persistent dhcp client entry for network interface "iface" and AF
+ * type "af"
+ */
+
+int
+lws_dhcpc_request(struct lws_context *context, const char *iface, int af,
+                 dhcpc_cb_t cb, void *opaque)
+{
+       lws_dhcpc_req_t *r = lws_dhcpc_find(context, iface, af);
+       int n;
+
+       /* see if we are already looking after this af / iface combination */
+
+       if (r)
+               return 0;
+
+       /* nope... let's create a request object as he asks */
+
+       n = (int)strlen(iface);
+       r = lws_zalloc(sizeof(*r) + (unsigned int)n + 1u, __func__);
+       if (!r)
+               return 1;
+
+       memcpy(&r[1], iface, (unsigned int)n + 1);
+       r->af = (uint8_t)af;
+       r->cb = cb;
+       r->opaque = opaque;
+       r->context = context;
+       r->state = LDHC_INIT;
+
+       lws_strncpy(r->is.ifname, iface, sizeof(r->is.ifname));
+
+       lws_dll2_add_head(&r->list, &context->dhcpc_owner); /* add him to list */
+
+       lws_dhcpc4_retry_conn(&r->sul_conn);
+
+       return 0;
+}
+
+/*
+ * Destroy every DHCP client object related to interface "iface"
+ */
+
+static int
+_remove_if(struct lws_dll2 *d, void *opaque)
+{
+       lws_dhcpc_req_t *r = lws_container_of(d, lws_dhcpc_req_t, list);
+
+       if (!opaque || !strcmp((const char *)&r[1], (const char *)opaque))
+               lws_dhcpc_destroy(&r);
+
+       return 0;
+}
+
+int
+lws_dhcpc_remove(struct lws_context *context, const char *iface)
+{
+       lws_dll2_foreach_safe(&context->dhcpc_owner, (void *)iface, _remove_if);
+
+       return 0;
+}
diff --git a/lib/system/dhcpclient/private-lib-system-dhcpclient.h b/lib/system/dhcpclient/private-lib-system-dhcpclient.h
new file mode 100644 (file)
index 0000000..3d278ef
--- /dev/null
@@ -0,0 +1,112 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+typedef enum {
+       LDHC_INIT_REBOOT,
+       LDHC_REBOOTING,         /* jitterwait */
+       LDHC_INIT,              /* issue DHCPDISCOVER */
+       LDHC_SELECTING,
+       LDHC_REQUESTING,
+       LDHC_REBINDING,
+       LDHC_BOUND,
+       LDHC_RENEWING
+} lws_dhcpc_state_t;
+
+enum {
+       LWSDHC4PDISCOVER                = 1,
+       LWSDHC4POFFER,
+       LWSDHC4PREQUEST,
+       LWSDHC4PDECLINE,
+       LWSDHC4PACK,
+       LWSDHC4PNACK,
+       LWSDHC4PRELEASE,
+
+       LWSDHC4POPT_PAD                 = 0,
+       LWSDHC4POPT_SUBNET_MASK         = 1,
+       LWSDHC4POPT_TIME_OFFSET         = 2,
+       LWSDHC4POPT_ROUTER              = 3,
+       LWSDHC4POPT_TIME_SERVER         = 4,
+       LWSDHC4POPT_NAME_SERVER         = 5,
+       LWSDHC4POPT_DNSERVER            = 6,
+       LWSDHC4POPT_LOG_SERVER          = 7,
+       LWSDHC4POPT_COOKIE_SERVER       = 8,
+       LWSDHC4POPT_LPR_SERVER          = 9,
+       LWSDHC4POPT_IMPRESS_SERVER      = 10,
+       LWSDHC4POPT_RESLOC_SERVER       = 11,
+       LWSDHC4POPT_HOST_NAME           = 12,
+       LWSDHC4POPT_BOOTFILE_SIZE       = 13,
+       LWSDHC4POPT_MERIT_DUMP_FILE     = 14,
+       LWSDHC4POPT_DOMAIN_NAME         = 15,
+       LWSDHC4POPT_SWAP_SERVER         = 16,
+       LWSDHC4POPT_ROOT_PATH           = 17,
+       LWSDHC4POPT_EXTENSIONS_PATH     = 18,
+       LWSDHC4POPT_BROADCAST_ADS       = 28,
+
+       LWSDHC4POPT_REQUESTED_ADS       = 50,
+       LWSDHC4POPT_LEASE_TIME          = 51,
+       LWSDHC4POPT_OPTION_OVERLOAD     = 52,
+       LWSDHC4POPT_MESSAGE_TYPE                = 53,
+       LWSDHC4POPT_SERVER_ID           = 54,
+       LWSDHC4POPT_PARAM_REQ_LIST      = 55,
+       LWSDHC4POPT_MESSAGE             = 56,
+       LWSDHC4POPT_MAX_DHCP_MSG_SIZE   = 57,
+       LWSDHC4POPT_RENEWAL_TIME                = 58, /* AKA T1 */
+       LWSDHC4POPT_REBINDING_TIME      = 59, /* AKA T2 */
+       LWSDHC4POPT_VENDOR_CLASS_ID     = 60,
+       LWSDHC4POPT_CLIENT_ID           = 61,
+
+       LWSDHC4POPT_END_OPTIONS         = 255
+};
+
+typedef struct lws_dhcpc_req {
+       lws_dll2_t              list;
+
+       struct lws_context      *context;
+       lws_sorted_usec_list_t  sul_renew;
+       lws_sorted_usec_list_t  sul_conn;
+       lws_sorted_usec_list_t  sul_write;
+       dhcpc_cb_t              cb;         /* cb on completion / failure */
+       void                    *opaque;    /* ignored by lws, give to cb */
+
+       /* these are separated so we can close the bcast one asynchronously */
+       struct lws              *wsi_raw;   /* for broadcast */
+       lws_dhcpc_state_t       state;
+
+       lws_dhcpc_ifstate_t     is;
+
+       uint16_t                retry_count_conn;
+       uint16_t                retry_count_write;
+       uint8_t                 xid[4];
+       uint8_t                 af;         /* address family */
+} lws_dhcpc_req_t;
+/* interface name is overallocated here */
+
+void
+lws_dhcpc4_retry_conn(struct lws_sorted_usec_list *sul);
+
+int
+lws_dhcpc4_parse(lws_dhcpc_req_t *r, void *in, size_t len);
+
+void
+lws_dhcpc_retry_write(struct lws_sorted_usec_list *sul);
diff --git a/lib/system/fault-injection/fault-injection.c b/lib/system/fault-injection/fault-injection.c
new file mode 100644 (file)
index 0000000..70c2a9f
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * lws System Fault Injection
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+#include <assert.h>
+
+static lws_fi_priv_t *
+lws_fi_lookup(const lws_fi_ctx_t *fic, const char *name)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, p, fic->fi_owner.head) {
+               lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
+
+               if (!strcmp(pv->fi.name, name))
+                       return pv;
+
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
+int
+lws_fi(const lws_fi_ctx_t *fic, const char *name)
+{
+       lws_fi_priv_t *pv;
+       int n;
+
+       pv = lws_fi_lookup(fic, name);
+
+       if (!pv)
+               return 0;
+
+       switch (pv->fi.type) {
+       case LWSFI_ALWAYS:
+               goto inject;
+
+       case LWSFI_DETERMINISTIC:
+               pv->fi.times++;
+               if (pv->fi.times >= pv->fi.pre)
+                       if (pv->fi.times < pv->fi.pre + pv->fi.count)
+                               goto inject;
+               return 0;
+
+       case LWSFI_PROBABILISTIC:
+               if (lws_xos_percent((lws_xos_t *)&fic->xos, (int)pv->fi.pre))
+                       goto inject;
+               return 0;
+
+       case LWSFI_PATTERN:
+       case LWSFI_PATTERN_ALLOC:
+               n = (int)((pv->fi.times++) % pv->fi.count);
+               if (pv->fi.pattern[n >> 3] & (1 << (n & 7)))
+                       goto inject;
+
+               return 0;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+
+inject:
+       lwsl_warn("%s: Injecting fault %s->%s\n", __func__,
+                       fic->name ? fic->name : "unk", pv->fi.name);
+
+       return 1;
+}
+
+int
+lws_fi_range(const lws_fi_ctx_t *fic, const char *name, uint64_t *result)
+{
+       lws_fi_priv_t *pv;
+       uint64_t d;
+
+       pv = lws_fi_lookup(fic, name);
+
+       if (!pv)
+               return 1;
+
+       if (pv->fi.type != LWSFI_RANGE) {
+               lwsl_err("%s: fault %s is not a 123..456 range\n",
+                        __func__, name);
+               return 1;
+       }
+
+       d = pv->fi.count - pv->fi.pre;
+
+       *result = pv->fi.pre + (lws_xos((lws_xos_t *)&fic->xos) % d);
+
+       return 0;
+}
+
+int
+_lws_fi_user_wsi_fi(struct lws *wsi, const char *name)
+{
+       return lws_fi(&wsi->fic, name);
+}
+
+int
+_lws_fi_user_context_fi(struct lws_context *ctx, const char *name)
+{
+       return lws_fi(&ctx->fic, name);
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+int
+_lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *name)
+{
+       return lws_fi(&h->fic, name);
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+int
+_lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *name)
+{
+       return lws_fi(&h->fic, name);
+}
+#endif
+#endif
+
+int
+lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi)
+{
+       lws_fi_priv_t *pv;
+       size_t n = strlen(fi->name);
+
+       pv = lws_malloc(sizeof(*pv) + n + 1, __func__);
+       if (!pv)
+               return 1;
+
+       lws_dll2_clear(&pv->list);
+
+       memcpy(&pv->fi, fi, sizeof(*fi));
+       pv->fi.name = (const char *)&pv[1];
+       memcpy(&pv[1], fi->name, n + 1);
+
+       lws_dll2_add_tail(&pv->list, &fic->fi_owner);
+
+       return 0;
+}
+
+void
+lws_fi_remove(lws_fi_ctx_t *fic, const char *name)
+{
+       lws_fi_priv_t *pv = lws_fi_lookup(fic, name);
+
+       if (!pv)
+               return;
+
+       lws_dll2_remove(&pv->list);
+       lws_free(pv);
+}
+
+void
+lws_fi_import(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src)
+{
+
+       /* inherit the PRNG seed for our context from source guy too */
+       lws_xos_init(&fic_dest->xos, lws_xos((lws_xos_t *)&fic_src->xos));
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  fic_src->fi_owner.head) {
+               lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
+
+               lws_dll2_remove(&pv->list);
+               lws_dll2_add_tail(&pv->list, &fic_dest->fi_owner);
+
+       } lws_end_foreach_dll_safe(p, p1);
+}
+
+static void
+do_inherit(lws_fi_ctx_t *fic_dest, lws_fi_t *pfi, size_t trim)
+{
+       lws_fi_t fi = *pfi;
+
+       fi.name += trim;
+
+       lwsl_info("%s: %s: %s inherited as %s\n", __func__, fic_dest->name,
+                 pfi->name, fi.name);
+
+       if (fi.type == LWSFI_PATTERN_ALLOC) {
+               fi.pattern = lws_malloc((size_t)((fi.count >> 3) + 1), __func__);
+               if (!fi.pattern)
+                       return;
+               memcpy((uint8_t *)fi.pattern, pfi->pattern,
+                      (size_t)((fi.count >> 3) + 1));
+       }
+
+       lws_fi_add(fic_dest, &fi);
+}
+
+void
+lws_fi_inherit_copy(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src,
+                   const char *scope, const char *value)
+{
+       size_t sl = 0, vl = 0;
+
+       if (scope)
+               sl = strlen(scope);
+
+       if (value)
+               vl = strlen(value);
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  fic_src->fi_owner.head) {
+               lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
+               size_t nl = strlen(pv->fi.name);
+
+               if (!scope)
+                       do_inherit(fic_dest, &pv->fi, 0);
+               else
+                       if (nl > sl + 2 &&
+                           !strncmp(pv->fi.name, scope, sl) &&
+                           pv->fi.name[sl] == '/')
+                               do_inherit(fic_dest, &pv->fi, sl + 1);
+                       else {
+                               if (value && nl > sl + vl + 2 &&
+                                   pv->fi.name[sl] == '=' &&
+                                   !strncmp(pv->fi.name + sl + 1, value, vl) &&
+                                   pv->fi.name[sl + 1 + vl] == '/')
+                                       do_inherit(fic_dest, &pv->fi, sl + vl + 2);
+                       }
+
+       } lws_end_foreach_dll_safe(p, p1);
+}
+
+void
+lws_fi_destroy(const lws_fi_ctx_t *fic)
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  fic->fi_owner.head) {
+               lws_fi_priv_t *pv = lws_container_of(p, lws_fi_priv_t, list);
+
+               if (pv->fi.type == LWSFI_PATTERN_ALLOC && pv->fi.pattern) {
+                       lws_free((void *)pv->fi.pattern);
+                       pv->fi.pattern = NULL;
+               }
+
+               lws_dll2_remove(&pv->list);
+               lws_free(pv);
+
+       } lws_end_foreach_dll_safe(p, p1);
+}
+
+/*
+ * We want to support these kinds of qualifier
+ *
+ * myfault            true always
+ * myfault(10%)       true 10% of the time
+ * myfault(....X X)   true when X
+ * myfault2(20..3000)  pick a number between 20 and 3000
+ */
+
+enum {
+       PARSE_NAME,
+       PARSE_WHEN,
+       PARSE_PC,
+       PARSE_ENDBR,
+       PARSE_COMMA
+};
+
+void
+lws_fi_deserialize(lws_fi_ctx_t *fic, const char *sers)
+{
+       int state = PARSE_NAME, m;
+       struct lws_tokenize ts;
+       lws_fi_t fi;
+       char nm[64];
+
+       /*
+        * Go through the comma-separated list of faults
+        * creating them and adding to the lws_context info
+        */
+
+       lws_tokenize_init(&ts, sers, LWS_TOKENIZE_F_DOT_NONTERM |
+                                    LWS_TOKENIZE_F_NO_INTEGERS |
+                                    LWS_TOKENIZE_F_NO_FLOATS |
+                                    LWS_TOKENIZE_F_EQUALS_NONTERM |
+                                    LWS_TOKENIZE_F_SLASH_NONTERM |
+                                    LWS_TOKENIZE_F_MINUS_NONTERM);
+       ts.len = (unsigned int)strlen(sers);
+       if (ts.len < 1 || ts.len > 10240)
+               return;
+
+       do {
+               ts.e = (int8_t)lws_tokenize(&ts);
+               switch (ts.e) {
+               case LWS_TOKZE_TOKEN:
+
+                       if (state == PARSE_NAME) {
+                               /*
+                                * One fault to inject looks like, eg,
+                                *
+                                *   vh=xxx/listenskt
+                                */
+
+                               memset(&fi, 0, sizeof(fi));
+
+                               lws_strnncpy(nm, ts.token, ts.token_len,
+                                            sizeof(nm));
+                               fi.name = nm;
+                               fi.type = LWSFI_ALWAYS;
+
+                               lwsl_notice("%s: name %.*s\n", __func__,
+                                           (int)ts.token_len, ts.token);
+
+                               /* added later, potentially after (when) */
+                               break;
+                       }
+                       if (state == PARSE_WHEN) {
+                               /* it's either numeric (then % or ..num2), or
+                                * .X pattern */
+
+                               lwsl_notice("%s: when\n", __func__);
+
+                               if (*ts.token == '.' || *ts.token == 'X') {
+                                       uint8_t *pat;
+                                       size_t n;
+
+                                       /*
+                                        * pattern... we need to allocate it
+                                        */
+                                       fi.type = LWSFI_PATTERN_ALLOC;
+                                       pat = lws_zalloc((ts.token_len >> 3) + 1,
+                                                        __func__);
+                                       if (!pat)
+                                               return;
+                                       fi.pattern = pat;
+                                       fi.count = (uint64_t)ts.token_len;
+
+                                       for (n = 0; n < ts.token_len; n++)
+                                               if (ts.token[n] == 'X')
+                                                       pat[n >> 3] = (uint8_t)(
+                                                               pat[n >> 3] |
+                                                               (1 << (n & 7)));
+
+                                       lwsl_hexdump_notice(pat,
+                                                      (ts.token_len >> 3) + 1);
+
+                                       state = PARSE_ENDBR;
+                                       break;
+                               }
+
+                               fi.pre = (uint64_t)atoll(ts.token);
+
+                               for (m = 0; m < (int)ts.token_len - 1; m++)
+                                       if (ts.token[m] < '0' ||
+                                           ts.token[m] > '9')
+                                               break;
+
+                               /*
+                                * We can understand num% or num..num
+                                */
+
+                               if (m != (int)ts.token_len &&
+                                   ts.token[m] == '.' &&
+                                   ts.token[m + 1] == '.') {
+                                       fi.count = (uint64_t)atoll(
+                                               &ts.token[m + 2]);
+                                       fi.type = LWSFI_RANGE;
+                                       state = PARSE_ENDBR;
+
+                                       if (fi.pre >= fi.count) {
+                                               lwsl_err("%s: range must have "
+                                                        "smaller first!\n",
+                                                        __func__);
+                                       }
+
+                                       lwsl_notice("%s: range %llx .."
+                                                   "%llx\n", __func__,
+                                                   (unsigned long long)fi.pre,
+                                                   (unsigned long long)fi.count);
+                                       break;
+                               }
+
+                               lwsl_notice("%s: prob %d%%\n", __func__,
+                                           (int)fi.pre);
+                               fi.type = LWSFI_PROBABILISTIC;
+                               state = PARSE_PC;
+                               break;
+                       }
+                       break;
+
+               case LWS_TOKZE_DELIMITER:
+                       if (*ts.token == ',') {
+                               lws_fi_add(fic, &fi);
+                               state = PARSE_NAME;
+                               break;
+                       }
+                       if (*ts.token == '(') {
+                               lwsl_notice("%s: (\n", __func__);
+                               if (state != PARSE_NAME) {
+                                       lwsl_err("%s: misplaced (\n", __func__);
+                                       return;
+                               }
+                               state = PARSE_WHEN;
+                               break;
+                       }
+                       if (*ts.token == ')') {
+                               if (state != PARSE_ENDBR) {
+                                       lwsl_err("%s: misplaced )\n", __func__);
+                                       return;
+                               }
+                               state = PARSE_NAME;
+                               break;
+                       }
+                       if (*ts.token == '%') {
+                               if (state != PARSE_PC) {
+                                       lwsl_err("%s: misplaced %%\n", __func__);
+                                       return;
+                               }
+                               state = PARSE_ENDBR;
+                               break;
+                       }
+                       break;
+
+               case LWS_TOKZE_ENDED:
+                       lws_fi_add(fic, &fi);
+                       return;
+
+               default:
+                       return;
+               }
+       } while (ts.e > 0);
+}
diff --git a/lib/system/fault-injection/private-lib-system-fault-injection.h b/lib/system/fault-injection/private-lib-system-fault-injection.h
new file mode 100644 (file)
index 0000000..ea01dc8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * lws System Message Distribution
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+
+typedef struct lws_fi_priv {
+       lws_dll2_t              list;
+       lws_fi_t                fi;
+} lws_fi_priv_t;
+
+void
+lws_fi_import(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src);
+
+#endif
diff --git a/lib/system/metrics/CMakeLists.txt b/lib/system/metrics/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3ed7f3f
--- /dev/null
@@ -0,0 +1,10 @@
+include_directories(.)
+
+if (LWS_WITH_SYS_METRICS)
+       list(APPEND SOURCES
+               system/metrics/metrics.c
+       )
+endif()
+
+exports_to_parent_scope()
+
diff --git a/lib/system/metrics/metrics.c b/lib/system/metrics/metrics.c
new file mode 100644 (file)
index 0000000..92d5e0d
--- /dev/null
@@ -0,0 +1,892 @@
+/*
+ * lws Generic Metrics
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include <assert.h>
+
+int
+lws_metrics_tag_add(lws_dll2_owner_t *owner, const char *name, const char *val)
+{
+       size_t vl = strlen(val);
+       lws_metrics_tag_t *tag;
+
+       // lwsl_notice("%s: adding %s=%s\n", __func__, name, val);
+
+       /*
+        * Remove (in order to replace) any existing tag of same name
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, d, owner->head) {
+               tag = lws_container_of(d, lws_metrics_tag_t, list);
+
+               if (!strcmp(name, tag->name)) {
+                       lws_dll2_remove(&tag->list);
+                       lws_free(tag);
+                       break;
+               }
+
+       } lws_end_foreach_dll(d);
+
+       /*
+        * Create the new tag
+        */
+
+       tag = lws_malloc(sizeof(*tag) + vl + 1, __func__);
+       if (!tag)
+               return 1;
+
+       lws_dll2_clear(&tag->list);
+       tag->name = name;
+       memcpy(&tag[1], val, vl + 1);
+
+       lws_dll2_add_tail(&tag->list, owner);
+
+       return 0;
+}
+
+int
+lws_metrics_tag_wsi_add(struct lws *wsi, const char *name, const char *val)
+{
+       __lws_lc_tag(wsi->a.context, NULL, &wsi->lc, "|%s", val);
+
+       return lws_metrics_tag_add(&wsi->cal_conn.mtags_owner, name, val);
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+int
+lws_metrics_tag_ss_add(struct lws_ss_handle *ss, const char *name, const char *val)
+{
+       __lws_lc_tag(ss->context, NULL, &ss->lc, "|%s", val);
+       return lws_metrics_tag_add(&ss->cal_txn.mtags_owner, name, val);
+}
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+int
+lws_metrics_tag_sspc_add(struct lws_sspc_handle *sspc, const char *name,
+                        const char *val)
+{
+       __lws_lc_tag(sspc->context, NULL, &sspc->lc, "|%s", val);
+       return lws_metrics_tag_add(&sspc->cal_txn.mtags_owner, name, val);
+}
+#endif
+#endif
+
+void
+lws_metrics_tags_destroy(lws_dll2_owner_t *owner)
+{
+       lws_metrics_tag_t *t;
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, owner->head) {
+               t = lws_container_of(d, lws_metrics_tag_t, list);
+
+               lws_dll2_remove(&t->list);
+               lws_free(t);
+
+       } lws_end_foreach_dll_safe(d, d1);
+}
+
+size_t
+lws_metrics_tags_serialize(lws_dll2_owner_t *owner, char *buf, size_t len)
+{
+       char *end = buf + len - 1, *p = buf;
+       lws_metrics_tag_t *t;
+
+       lws_start_foreach_dll(struct lws_dll2 *, d, owner->head) {
+               t = lws_container_of(d, lws_metrics_tag_t, list);
+
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                 "%s=\"%s\"", t->name, (const char *)&t[1]);
+
+               if (d->next && p + 2 < end)
+                       *p++ = ',';
+
+       } lws_end_foreach_dll(d);
+
+       *p = '\0';
+
+       return lws_ptr_diff_size_t(p, buf);
+}
+
+const char *
+lws_metrics_tag_get(lws_dll2_owner_t *owner, const char *name)
+{
+       lws_metrics_tag_t *t;
+
+       lws_start_foreach_dll(struct lws_dll2 *, d, owner->head) {
+               t = lws_container_of(d, lws_metrics_tag_t, list);
+
+               if (!strcmp(name, t->name))
+                       return (const char *)&t[1];
+
+       } lws_end_foreach_dll(d);
+
+       return NULL;
+}
+
+static int
+lws_metrics_dump_cb(lws_metric_pub_t *pub, void *user);
+
+static void
+lws_metrics_report_and_maybe_clear(struct lws_context *ctx, lws_metric_pub_t *pub)
+{
+       if (!pub->us_first || pub->us_last == pub->us_dumped)
+               return;
+
+       lws_metrics_dump_cb(pub, ctx);
+}
+
+static void
+lws_metrics_periodic_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_metric_policy_dyn_t *dmp = lws_container_of(sul,
+                                               lws_metric_policy_dyn_t, sul);
+       struct lws_context *ctx = lws_container_of(dmp->list.owner,
+                                       struct lws_context, owner_mtr_dynpol);
+
+       if (!ctx->system_ops || !ctx->system_ops->metric_report)
+               return;
+
+       lws_start_foreach_dll(struct lws_dll2 *, d, dmp->owner.head) {
+               lws_metric_t *mt = lws_container_of(d, lws_metric_t, list);
+               lws_metric_pub_t *pub = lws_metrics_priv_to_pub(mt);
+
+               lws_metrics_report_and_maybe_clear(ctx, pub);
+
+       } lws_end_foreach_dll(d);
+
+#if defined(LWS_WITH_SYS_SMD) && defined(LWS_WITH_SECURE_STREAMS)
+       (void)lws_smd_msg_printf(ctx, LWSSMDCL_METRICS,
+                                "{\"dump\":\"%s\",\"ts\":%lu}",
+                                  dmp->policy->name,
+                                  (long)ctx->last_policy);
+#endif
+
+       if (dmp->policy->us_schedule)
+               lws_sul_schedule(ctx, 0, &dmp->sul,
+                                lws_metrics_periodic_cb,
+                                (lws_usec_t)dmp->policy->us_schedule);
+}
+
+/*
+ * Policies are in two pieces, a const policy and a dynamic part that contains
+ * lists and sul timers for the policy etc.  This creates a dynmic part
+ * corresponding to the static part.
+ *
+ * Metrics can exist detached from being bound to any policy about how to
+ * report them, these are collected but not reported unless they later become
+ * bound to a reporting policy dynamically.
+ */
+
+lws_metric_policy_dyn_t *
+lws_metrics_policy_dyn_create(struct lws_context *ctx,
+                             const lws_metric_policy_t *po)
+{
+       lws_metric_policy_dyn_t *dmet;
+
+       dmet = lws_zalloc(sizeof(*dmet), __func__);
+       if (!dmet)
+               return NULL;
+
+       dmet->policy = po;
+       lws_dll2_add_tail(&dmet->list, &ctx->owner_mtr_dynpol);
+
+       if (po->us_schedule)
+               lws_sul_schedule(ctx, 0, &dmet->sul,
+                                lws_metrics_periodic_cb,
+                                (lws_usec_t)po->us_schedule);
+
+       return dmet;
+}
+
+/*
+ * Get a dynamic metrics policy from the const one, may return NULL if OOM
+ */
+
+lws_metric_policy_dyn_t *
+lws_metrics_policy_get_dyn(struct lws_context *ctx,
+                          const lws_metric_policy_t *po)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, d, ctx->owner_mtr_dynpol.head) {
+               lws_metric_policy_dyn_t *dm =
+                       lws_container_of(d, lws_metric_policy_dyn_t, list);
+
+               if (dm->policy == po)
+                       return dm;
+
+       } lws_end_foreach_dll(d);
+
+       /*
+        * no dyn policy part for this const policy --> create one
+        *
+        * We want a dynamic part for listing metrics that bound to the policy
+        */
+
+       return lws_metrics_policy_dyn_create(ctx, po);
+}
+
+static int
+lws_metrics_check_in_policy(const char *polstring, const char *name)
+{
+       struct lws_tokenize ts;
+
+       memset(&ts, 0, sizeof(ts));
+
+       ts.start = polstring;
+       ts.len = strlen(polstring);
+       ts.flags = (uint16_t)(LWS_TOKENIZE_F_MINUS_NONTERM |
+                             LWS_TOKENIZE_F_ASTERISK_NONTERM |
+                             LWS_TOKENIZE_F_COMMA_SEP_LIST |
+                             LWS_TOKENIZE_F_NO_FLOATS |
+                             LWS_TOKENIZE_F_DOT_NONTERM);
+
+       do {
+               ts.e = (int8_t)lws_tokenize(&ts);
+
+               if (ts.e == LWS_TOKZE_TOKEN) {
+                       if (!lws_strcmp_wildcard(ts.token, ts.token_len, name,
+                                                strlen(name)))
+                               /* yes, we are mentioned in this guy's policy */
+                               return 0;
+               }
+       } while (ts.e > 0);
+
+       /* no, this policy doesn't apply to a metric with our name */
+
+       return 1;
+}
+
+static const lws_metric_policy_t *
+lws_metrics_find_policy(struct lws_context *ctx, const char *name)
+{
+       const lws_metric_policy_t *mp = ctx->metrics_policies;
+
+       if (!mp) {
+#if defined(LWS_WITH_SECURE_STREAMS)
+               if (ctx->pss_policies)
+                       mp = ctx->pss_policies->metrics;
+#endif
+               if (!mp)
+                       return NULL;
+       }
+
+       while (mp) {
+               if (mp->report && !lws_metrics_check_in_policy(mp->report, name))
+                       return mp;
+
+               mp = mp->next;
+       }
+
+       return NULL;
+}
+
+/*
+ * Create a lws_metric_t, bind to a named policy if possible (or add to the
+ * context list of unbound metrics) and set its lws_system
+ * idx.  The metrics objects themselves are typically composed into other
+ * objects and are well-known composed members of them.
+ */
+
+lws_metric_t *
+lws_metric_create(struct lws_context *ctx, uint8_t flags, const char *name)
+{
+       const lws_metric_policy_t *po;
+       lws_metric_policy_dyn_t *dmp;
+       lws_metric_pub_t *pub;
+       lws_metric_t *mt;
+       char pname[32];
+       size_t nl;
+
+       if (ctx->metrics_prefix) {
+
+               /*
+                * In multi-process case, we want to prefix metrics from this
+                * process / context with a string distinguishing which
+                * application they came from
+                */
+
+               nl = (size_t)lws_snprintf(pname, sizeof(pname) - 1, "%s.%s",
+                                 ctx->metrics_prefix, name);
+               name = pname;
+       } else
+               nl = strlen(name);
+
+       mt = (lws_metric_t *)lws_zalloc(sizeof(*mt) /* private */ +
+                                       sizeof(lws_metric_pub_t) +
+                                       nl + 1 /* copy of metric name */,
+                                       __func__);
+       if (!mt)
+               return NULL;
+
+       pub = lws_metrics_priv_to_pub(mt);
+       pub->name = (char *)pub + sizeof(lws_metric_pub_t);
+       memcpy((char *)pub->name, name, nl + 1);
+       pub->flags = flags;
+
+       /* after these common members, we have to use the right type */
+
+       if (!(flags & LWSMTFL_REPORT_HIST)) {
+               /* anything is smaller or equal to this */
+               pub->u.agg.min = ~(u_mt_t)0;
+               pub->us_first = lws_now_usecs();
+       }
+
+       mt->ctx = ctx;
+
+       /*
+        * Let's see if we can bind to a reporting policy straight away
+        */
+
+       po = lws_metrics_find_policy(ctx, name);
+       if (po) {
+               dmp = lws_metrics_policy_get_dyn(ctx, po);
+               if (dmp) {
+                       lwsl_notice("%s: metpol %s\n", __func__, name);
+                       lws_dll2_add_tail(&mt->list, &dmp->owner);
+
+                       return 0;
+               }
+       }
+
+       /*
+        * If not, well, let's go on without and maybe later at runtime, he'll
+        * get interested in us and apply a reporting policy
+        */
+
+       lws_dll2_add_tail(&mt->list, &ctx->owner_mtr_no_pol);
+
+       return mt;
+}
+
+/*
+ * If our metric is bound to a reporting policy, return a pointer to it,
+ * otherwise NULL
+ */
+
+const lws_metric_policy_t *
+lws_metric_get_policy(lws_metric_t *mt)
+{
+       lws_metric_policy_dyn_t *dp;
+
+       /*
+        * Our metric must either be on the "no policy" context list or
+        * listed by the dynamic part of the policy it is bound to
+        */
+       assert(mt->list.owner);
+
+       if ((char *)mt->list.owner >= (char *)mt->ctx &&
+           (char *)mt->list.owner < (char *)mt->ctx + sizeof(struct lws_context))
+               /* we are on the "no policy" context list */
+               return NULL;
+
+       /* we are listed by a dynamic policy owner */
+
+       dp = lws_container_of(mt->list.owner, lws_metric_policy_dyn_t, owner);
+
+       /* return the const policy the dynamic policy represents */
+
+       return dp->policy;
+}
+
+void
+lws_metric_rebind_policies(struct lws_context *ctx)
+{
+       const lws_metric_policy_t *po;
+       lws_metric_policy_dyn_t *dmp;
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  ctx->owner_mtr_no_pol.head) {
+               lws_metric_t *mt = lws_container_of(d, lws_metric_t, list);
+               lws_metric_pub_t *pub = lws_metrics_priv_to_pub(mt);
+
+               po = lws_metrics_find_policy(ctx, pub->name);
+               if (po) {
+                       dmp = lws_metrics_policy_get_dyn(ctx, po);
+                       if (dmp) {
+                               lwsl_info("%s: %s <- pol %s\n", __func__,
+                                               pub->name, po->name);
+                               lws_dll2_remove(&mt->list);
+                               lws_dll2_add_tail(&mt->list, &dmp->owner);
+                       }
+               } else
+                       lwsl_debug("%s: no pol for %s\n", __func__, pub->name);
+
+       } lws_end_foreach_dll_safe(d, d1);
+}
+
+int
+lws_metric_destroy(lws_metric_t **pmt, int keep)
+{
+       lws_metric_t *mt = *pmt;
+       lws_metric_pub_t *pub = lws_metrics_priv_to_pub(mt);
+
+       if (!mt)
+               return 0;
+
+       lws_dll2_remove(&mt->list);
+
+       if (keep) {
+               lws_dll2_add_tail(&mt->list, &mt->ctx->owner_mtr_no_pol);
+
+               return 0;
+       }
+
+       if (pub->flags & LWSMTFL_REPORT_HIST) {
+               lws_metric_bucket_t *b = pub->u.hist.head, *b1;
+
+               pub->u.hist.head = NULL;
+
+               while (b) {
+                       b1 = b->next;
+                       lws_free(b);
+                       b = b1;
+               }
+       }
+
+       lws_free(mt);
+       *pmt = NULL;
+
+       return 0;
+}
+
+/*
+ * Allow an existing metric to have its reporting policy changed at runtime
+ */
+
+int
+lws_metric_switch_policy(lws_metric_t *mt, const char *polname)
+{
+       const lws_metric_policy_t *po;
+       lws_metric_policy_dyn_t *dmp;
+
+       po = lws_metrics_find_policy(mt->ctx, polname);
+       if (!po)
+               return 1;
+
+       dmp = lws_metrics_policy_get_dyn(mt->ctx, po);
+       if (!dmp)
+               return 1;
+
+       lws_dll2_remove(&mt->list);
+       lws_dll2_add_tail(&mt->list, &dmp->owner);
+
+       return 0;
+}
+
+/*
+ * If keep is set, don't destroy existing metrics objects, just detach them
+ * from the policy being deleted and keep track of them on ctx->
+ * owner_mtr_no_pol
+ */
+
+void
+lws_metric_policy_dyn_destroy(lws_metric_policy_dyn_t *dm, int keep)
+{
+       lws_sul_cancel(&dm->sul);
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, dm->owner.head) {
+               lws_metric_t *m = lws_container_of(d, lws_metric_t, list);
+
+               lws_metric_destroy(&m, keep);
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       lws_sul_cancel(&dm->sul);
+
+       lws_dll2_remove(&dm->list);
+       lws_free(dm);
+}
+
+/*
+ * Destroy all dynamic metrics policies, deinit any metrics still using them
+ */
+
+void
+lws_metrics_destroy(struct lws_context *ctx)
+{
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  ctx->owner_mtr_dynpol.head) {
+               lws_metric_policy_dyn_t *dm =
+                       lws_container_of(d, lws_metric_policy_dyn_t, list);
+
+               lws_metric_policy_dyn_destroy(dm, 0); /* don't keep */
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       /* destroy metrics with no current policy too... */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  ctx->owner_mtr_no_pol.head) {
+               lws_metric_t *mt = lws_container_of(d, lws_metric_t, list);
+
+               lws_metric_destroy(&mt, 0); /* don't keep */
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       /* ... that's the whole allocated metrics footprint gone... */
+}
+
+int
+lws_metrics_hist_bump_(lws_metric_pub_t *pub, const char *name)
+{
+       lws_metric_bucket_t *buck = pub->u.hist.head;
+       size_t nl = strlen(name);
+       char *nm;
+
+       if (!(pub->flags & LWSMTFL_REPORT_HIST)) {
+               lwsl_err("%s: %s not histogram: flags %d\n", __func__,
+                               pub->name, pub->flags);
+               assert(0);
+       }
+       assert(nl < 255);
+
+       pub->us_last = lws_now_usecs();
+       if (!pub->us_first)
+               pub->us_first = pub->us_last;
+
+       while (buck) {
+               if (lws_metric_bucket_name_len(buck) == nl &&
+                   !strcmp(name, lws_metric_bucket_name(buck))) {
+                       buck->count++;
+                       goto happy;
+               }
+               buck = buck->next;
+       }
+
+       buck = lws_malloc(sizeof(*buck) + nl + 2, __func__);
+       if (!buck)
+               return 1;
+
+       nm = (char *)buck + sizeof(*buck);
+       /* length byte at beginning of name, avoid struct alignment overhead */
+       *nm = (char)nl;
+       memcpy(nm + 1, name, nl + 1);
+
+       buck->next = pub->u.hist.head;
+       pub->u.hist.head = buck;
+       buck->count = 1;
+       pub->u.hist.list_size++;
+
+happy:
+       pub->u.hist.total_count++;
+
+       return 0;
+}
+
+int
+lws_metrics_hist_bump_describe_wsi(struct lws *wsi, lws_metric_pub_t *pub,
+                                  const char *name)
+{
+       char desc[192], d1[48], *p = desc, *end = desc + sizeof(desc);
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       if (wsi->client_bound_sspc) {
+               lws_sspc_handle_t *h = (lws_sspc_handle_t *)wsi->a.opaque_user_data;
+               if (h)
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "ss=\"%s\",",
+                                 h->ssi.streamtype);
+       } else
+               if (wsi->client_proxy_onward) {
+                       lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data;
+                       struct conn *conn = h->conn_if_sspc_onw;
+
+                       if (conn && conn->ss)
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                                 "ss=\"%s\",",
+                                                 conn->ss->info.streamtype);
+               } else
+#endif
+       if (wsi->for_ss) {
+               lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data;
+               if (h)
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "ss=\"%s\",",
+                                 h->info.streamtype);
+       }
+#endif
+
+#if defined(LWS_WITH_CLIENT)
+       if (wsi->stash && wsi->stash->cis[CIS_HOST])
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "hostname=\"%s\",",
+                               wsi->stash->cis[CIS_HOST]);
+#endif
+
+       lws_sa46_write_numeric_address(&wsi->sa46_peer, d1, sizeof(d1));
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "peer=\"%s\",", d1);
+
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s", name);
+
+       lws_metrics_hist_bump_(pub, desc);
+
+       return 0;
+}
+
+int
+lws_metrics_foreach(struct lws_context *ctx, void *user,
+                   int (*cb)(lws_metric_pub_t *pub, void *user))
+{
+       int n;
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+                                  ctx->owner_mtr_no_pol.head) {
+               lws_metric_t *mt = lws_container_of(d, lws_metric_t, list);
+
+               n = cb(lws_metrics_priv_to_pub(mt), user);
+               if (n)
+                       return n;
+
+       } lws_end_foreach_dll_safe(d, d1);
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, d2, d3,
+                                  ctx->owner_mtr_dynpol.head) {
+               lws_metric_policy_dyn_t *dm =
+                       lws_container_of(d2, lws_metric_policy_dyn_t, list);
+
+               lws_start_foreach_dll_safe(struct lws_dll2 *, e, e1,
+                                          dm->owner.head) {
+
+                       lws_metric_t *mt = lws_container_of(e, lws_metric_t, list);
+
+                       n = cb(lws_metrics_priv_to_pub(mt), user);
+                       if (n)
+                               return n;
+
+               } lws_end_foreach_dll_safe(e, e1);
+
+       } lws_end_foreach_dll_safe(d2, d3);
+
+       return 0;
+}
+
+static int
+lws_metrics_dump_cb(lws_metric_pub_t *pub, void *user)
+{
+       struct lws_context *ctx = (struct lws_context *)user;
+       int n;
+
+       if (!ctx->system_ops || !ctx->system_ops->metric_report)
+               return 0;
+
+       /*
+        * return nonzero to reset stats
+        */
+
+       n = ctx->system_ops->metric_report(pub);
+
+       /* track when we dumped it... */
+
+       pub->us_first = pub->us_dumped = lws_now_usecs();
+       pub->us_last = 0;
+
+       if (!n)
+               return 0;
+
+       /* ... and clear it back to 0 */
+
+       if (pub->flags & LWSMTFL_REPORT_HIST) {
+               lws_metric_bucket_t *b = pub->u.hist.head, *b1;
+               pub->u.hist.head = NULL;
+
+               while (b) {
+                       b1 = b->next;
+                       lws_free(b);
+                       b = b1;
+               }
+               pub->u.hist.total_count = 0;
+               pub->u.hist.list_size = 0;
+       } else
+               memset(&pub->u.agg, 0, sizeof(pub->u.agg));
+
+       return 0;
+}
+
+void
+lws_metrics_dump(struct lws_context *ctx)
+{
+       lws_metrics_foreach(ctx, ctx, lws_metrics_dump_cb);
+}
+
+static int
+_lws_metrics_format(lws_metric_pub_t *pub, lws_usec_t now, int gng,
+                   char *buf, size_t len)
+{
+       const lws_humanize_unit_t *schema = humanize_schema_si;
+       char *end = buf + len - 1, *obuf = buf;
+
+       if (pub->flags & LWSMTFL_REPORT_DUTY_WALLCLOCK_US)
+               schema = humanize_schema_us;
+
+       if (!(pub->flags & LWSMTFL_REPORT_MEAN)) {
+               /* only the sum is meaningful */
+               if (pub->flags & LWSMTFL_REPORT_DUTY_WALLCLOCK_US) {
+
+                       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), " %u, ",
+                                               (unsigned int)pub->u.agg.count[gng]);
+
+                       buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf),
+                                           (uint64_t)pub->u.agg.sum[gng],
+                                           humanize_schema_us);
+
+                       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), " / ");
+
+                       buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf),
+                                           (uint64_t)(now - pub->us_first),
+                                           humanize_schema_us);
+
+                       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                                           " (%d%%)", (int)((100 * pub->u.agg.sum[gng]) /
+                                               (unsigned long)(now - pub->us_first)));
+               } else {
+                       /* it's a monotonic ordinal, like total tx */
+                       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "(%u) ",
+                                       (unsigned int)pub->u.agg.count[gng]);
+                       buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf),
+                                           (uint64_t)pub->u.agg.sum[gng],
+                                           humanize_schema_si);
+               }
+
+       } else {
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%u, mean: ", (unsigned int)pub->u.agg.count[gng]);
+               /* the average over the period is meaningful */
+               buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf),
+                                   (uint64_t)(pub->u.agg.count[gng] ?
+                                        pub->u.agg.sum[gng] / pub->u.agg.count[gng] : 0),
+                                   schema);
+       }
+
+       return lws_ptr_diff(buf, obuf);
+}
+
+int
+lws_metrics_format(lws_metric_pub_t *pub, lws_metric_bucket_t **sub, char *buf, size_t len)
+{
+       char *end = buf + len - 1, *obuf = buf;
+       lws_usec_t t = lws_now_usecs();
+       const lws_humanize_unit_t *schema = humanize_schema_si;
+
+       if (pub->flags & LWSMTFL_REPORT_DUTY_WALLCLOCK_US)
+               schema = humanize_schema_us;
+
+       if (pub->flags & LWSMTFL_REPORT_HIST) {
+
+               if (*sub == NULL)
+                       return 0;
+
+               if (*sub) {
+                       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                                           "%s{%s} %llu", pub->name,
+                                           lws_metric_bucket_name(*sub),
+                                           (unsigned long long)(*sub)->count);
+
+                       *sub = (*sub)->next;
+               }
+
+               goto happy;
+       }
+
+       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s: ",
+                               pub->name);
+
+       if (!pub->u.agg.count[METRES_GO] && !pub->u.agg.count[METRES_NOGO])
+               return 0;
+
+       if (pub->u.agg.count[METRES_GO]) {
+               if (!(pub->flags & LWSMTFL_REPORT_ONLY_GO))
+                       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                                           "Go: ");
+               buf += _lws_metrics_format(pub, t, METRES_GO, buf,
+                                          lws_ptr_diff_size_t(end, buf));
+       }
+
+       if (!(pub->flags & LWSMTFL_REPORT_ONLY_GO) && pub->u.agg.count[METRES_NOGO]) {
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), ", NoGo: ");
+               buf += _lws_metrics_format(pub, t, METRES_NOGO, buf,
+                                          lws_ptr_diff_size_t(end, buf));
+       }
+
+       if (pub->flags & LWSMTFL_REPORT_MEAN) {
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), ", min: ");
+               buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf), pub->u.agg.min,
+                                   schema);
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), ", max: ");
+               buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf), pub->u.agg.max,
+                                   schema);
+       }
+
+happy:
+       if (pub->flags & LWSMTFL_REPORT_HIST)
+               return 1;
+
+       *sub = NULL;
+
+       return lws_ptr_diff(buf, obuf);
+}
+
+/*
+ * We want to, at least internally, record an event... depending on the policy,
+ * that might cause us to call through to the lws_system apis, or just update
+ * our local stats about it and dump at the next periodic chance (also set by
+ * the policy)
+ */
+
+void
+lws_metric_event(lws_metric_t *mt, char go_nogo, u_mt_t val)
+{
+       lws_metric_pub_t *pub;
+
+       assert((go_nogo & 0xfe) == 0);
+
+       if (!mt)
+               return;
+
+       pub = lws_metrics_priv_to_pub(mt);
+       assert(!(pub->flags & LWSMTFL_REPORT_HIST));
+
+       pub->us_last = lws_now_usecs();
+       if (!pub->us_first)
+               pub->us_first = pub->us_last;
+       pub->u.agg.count[(int)go_nogo]++;
+       pub->u.agg.sum[(int)go_nogo] += val;
+       if (val > pub->u.agg.max)
+               pub->u.agg.max = val;
+       if (val < pub->u.agg.min)
+               pub->u.agg.min = val;
+
+       if (pub->flags & LWSMTFL_REPORT_OOB)
+               lws_metrics_report_and_maybe_clear(mt->ctx, pub);
+}
+
+
+void
+lws_metrics_hist_bump_priv_tagged(lws_metric_pub_t *mt, lws_dll2_owner_t *tow,
+                                 lws_dll2_owner_t *tow2)
+{
+       char qual[192];
+       size_t p;
+
+       p = lws_metrics_tags_serialize(tow, qual, sizeof(qual));
+       if (tow2)
+               lws_metrics_tags_serialize(tow2, qual + p,
+                               sizeof(qual) - p);
+
+       lws_metrics_hist_bump(mt, qual);
+}
diff --git a/lib/system/metrics/private-lib-system-metrics.h b/lib/system/metrics/private-lib-system-metrics.h
new file mode 100644 (file)
index 0000000..07f4daf
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * lws System Metrics
+ *
+ * Copyright (C) 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * Const struct that describes a policy for processing raw metrics to turn them
+ * into events.
+ *
+ * Typically although we want to monitor every event, the data produced can be
+ * too large, and many events that are "normal" just need to be counted as such;
+ * outliers or change-to-continuous outliers may deserve closer recording as
+ * events in their own right.
+ *
+ * Mean computation must "decay" as it ages, we do this by halving the sum and
+ * count after .us_decay_unit us.
+ *
+ * We don't acknowledge outliers until there are at least .min_contributors
+ * in the current mean (which is subject to decaying)
+ *
+ * We decide something is an outlier event if it deviates from the mean by
+ * .pc_outlier_deviation %.
+ */
+
+/*
+ * The dynamic counterpart for each static metric policy, this is on heap
+ * one per const lws_metric_policy_t.  It's listed in context->owner_mtr_dynpol
+ */
+
+typedef struct lws_metric_policy_dyn {
+       const lws_metric_policy_t       *policy;
+       /**< the static part of the policy we belong to... can be NULL if no
+        * policy matches or the policy was invalidated */
+
+       lws_dll2_owner_t                owner;
+       /**< list of metrics that are using this policy */
+
+       lws_dll2_t                      list;
+       /**< context owns us */
+
+       lws_sorted_usec_list_t          sul;
+       /**< schedule periodic reports for metrics using this policy */
+} lws_metric_policy_dyn_t;
+
+/*
+ * A metrics private part, encapsulating the public part
+ */
+
+typedef struct lws_metric {
+
+       lws_dll2_t                      list;
+       /**< owned by either 1) ctx.lws_metric_policy_dyn_t.owner, or
+        * 2) ctx.owner_mtr_no_pol */
+
+       struct lws_context              *ctx;
+
+       /* public part overallocated */
+} lws_metric_t;
+
+
+#if defined(LWS_WITH_SYS_METRICS)
+#define lws_metrics_hist_bump_priv(_mt, _name) \
+               lws_metrics_hist_bump_(lws_metrics_priv_to_pub(_mt), _name)
+#define lws_metrics_hist_bump_priv_wsi(_wsi, _hist, _name) \
+               lws_metrics_hist_bump_(lws_metrics_priv_to_pub(_wsi->a.context->_hist), _name)
+#define lws_metrics_hist_bump_priv_ss(_ss, _hist, _name) \
+               lws_metrics_hist_bump_(lws_metrics_priv_to_pub(_ss->context->_hist), _name)
+#define lws_metrics_priv_to_pub(_x) ((lws_metric_pub_t *)&(_x)[1])
+#else
+#define lws_metrics_hist_bump_priv(_mt, _name)
+#define lws_metrics_hist_bump_priv_wsi(_wsi, _hist, _name)
+#define lws_metrics_hist_bump_priv_ss(_ss, _hist, _name)
+#define lws_metrics_priv_to_pub(_x) ((lws_metric_pub_t *)NULL)
+#endif
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+/*
+ * sspc-specific version that also appends the tag value to the lifecycle tag
+ * used for logging the sspc identity
+ */
+int
+lws_metrics_tag_sspc_add(struct lws_sspc_handle *ss, const char *name, const char *val);
+#endif
+
+int
+lws_metrics_register_policy(struct lws_context *ctx,
+                           const lws_metric_policy_t *head);
+
+void
+lws_metrics_destroy(struct lws_context *ctx);
+
+void
+lws_metric_event(lws_metric_t *mt, char go_nogo, u_mt_t val);
+
+lws_metric_t *
+lws_metric_create(struct lws_context *ctx, uint8_t flags, const char *name);
+
+int
+lws_metric_destroy(lws_metric_t **mt, int keep);
+
+void
+lws_metric_policy_dyn_destroy(lws_metric_policy_dyn_t *dm, int keep);
+
+void
+lws_metric_rebind_policies(struct lws_context *ctx);
diff --git a/lib/system/ntpclient/ntpclient.c b/lib/system/ntpclient/ntpclient.c
new file mode 100644 (file)
index 0000000..b7ea660
--- /dev/null
@@ -0,0 +1,310 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+#define LWSNTPC_LI_NONE                        0
+#define LWSNTPC_VN_3                   3
+#define LWSNTPC_MODE_CLIENT            3
+
+struct vhd_ntpc {
+       struct lws_context              *context;
+       struct lws_vhost                *vhost;
+       const struct lws_protocols      *protocol;
+       lws_sorted_usec_list_t          sul_conn;
+       lws_sorted_usec_list_t          sul_write; /* track write retries */
+       const char                      *ntp_server_ads;
+       struct lws                      *wsi_udp;
+       uint16_t                        retry_count_conn;
+       uint16_t                        retry_count_write;
+
+       char                            set_time;
+};
+
+/*
+ * Without a valid ntp we won't be able to do anything requiring client tls.
+ *
+ * We have our own outer backoff scheme that just keeps retrying dns lookup
+ * and the transaction forever.
+ */
+
+static const uint32_t botable[] =
+               { 300, 500, 650, 800, 800, 900, 1000, 1100, 1500 };
+static const lws_retry_bo_t bo = {
+       botable, LWS_ARRAY_SIZE(botable), LWS_RETRY_CONCEAL_ALWAYS, 0, 0, 20 };
+
+/*
+ * Once we resolved the remote server (implying we should have network),
+ * we use a different policy on the wsi itself that gives it a few tries before
+ * failing the wsi and using to outer retry policy to get dns to a different
+ * server in the pool and try fresh
+ */
+
+static const uint32_t botable2[] = { 1000, 1250, 5000 /* in case dog slow */ };
+static const lws_retry_bo_t bo2 = {
+       botable2, LWS_ARRAY_SIZE(botable2), LWS_ARRAY_SIZE(botable2),
+       /* don't conceal after the last table entry */ 0, 0, 20 };
+
+static void
+lws_ntpc_retry_conn(struct lws_sorted_usec_list *sul)
+{
+       struct vhd_ntpc *v = lws_container_of(sul, struct vhd_ntpc, sul_conn);
+
+       lwsl_debug("%s: wsi_udp: %s\n", __func__, lws_wsi_tag(v->wsi_udp));
+
+       if (v->wsi_udp || !lws_dll2_is_detached(&v->sul_conn.list))
+               return;
+
+       /* create the UDP socket aimed at the server */
+
+       lwsl_notice("%s: server %s\n", __func__, v->ntp_server_ads);
+
+       v->retry_count_write = 0;
+       v->wsi_udp = lws_create_adopt_udp(v->vhost, v->ntp_server_ads, 123, 0,
+                                         v->protocol->name, NULL, NULL, NULL,
+                                         &bo2, "ntpclient");
+       lwsl_debug("%s: created wsi_udp: %s\n", __func__, lws_wsi_tag(v->wsi_udp));
+       if (!v->wsi_udp) {
+               lwsl_err("%s: unable to create udp skt\n", __func__);
+
+               lws_retry_sul_schedule(v->context, 0, &v->sul_conn, &bo,
+                                      lws_ntpc_retry_conn, &v->retry_count_conn);
+       }
+}
+
+static void
+lws_ntpc_retry_write(struct lws_sorted_usec_list *sul)
+{
+       struct vhd_ntpc *v = lws_container_of(sul, struct vhd_ntpc, sul_write);
+
+       lwsl_debug("%s\n", __func__);
+
+       if (v && v->wsi_udp)
+               lws_callback_on_writable(v->wsi_udp);
+}
+
+static int
+callback_ntpc(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+             void *in, size_t len)
+{
+       struct vhd_ntpc *v = (struct vhd_ntpc *)
+                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
+                                                lws_get_protocol(wsi));
+       uint8_t pkt[LWS_PRE + 48];
+       struct timeval t1;
+       int64_t delta_us;
+       uint64_t ns;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
+               if (v)
+                       break;
+
+               lwsl_debug("%s: LWS_CALLBACK_PROTOCOL_INIT:\n", __func__);
+               lws_protocol_vh_priv_zalloc(wsi->a.vhost, wsi->a.protocol,
+                                           sizeof(*v));
+               v = (struct vhd_ntpc *)lws_protocol_vh_priv_get(wsi->a.vhost,
+                                                               wsi->a.protocol);
+               v->context = lws_get_context(wsi);
+               v->vhost = lws_get_vhost(wsi);
+               v->protocol = lws_get_protocol(wsi);
+
+               v->context->ntpclient_priv = v;
+
+               if (!lws_system_get_ops(wsi->a.context) ||
+                   !lws_system_get_ops(wsi->a.context)->set_clock) {
+#if !defined(LWS_ESP_PLATFORM)
+                       lwsl_err("%s: set up system ops for set_clock\n",
+                                       __func__);
+#endif
+
+               //      return -1;
+               }
+
+               /* register our lws_system notifier */
+
+               v->ntp_server_ads = "pool.ntp.org";
+               lws_plat_ntpclient_config(v->context);
+               lws_system_blob_get_single_ptr(lws_system_get_blob(
+                               v->context, LWS_SYSBLOB_TYPE_NTP_SERVER, 0),
+                               (const uint8_t **)&v->ntp_server_ads);
+               if (!v->ntp_server_ads || v->ntp_server_ads[0] == '\0')
+                       v->ntp_server_ads = "pool.ntp.org";
+
+               lwsl_notice("%s: using ntp server %s\n", __func__,
+                         v->ntp_server_ads);
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
+               if (!v)
+                       break;
+               if (v->wsi_udp)
+                       lws_set_timeout(v->wsi_udp, 1, LWS_TO_KILL_ASYNC);
+               v->wsi_udp = NULL;
+               goto cancel_conn_timer;
+
+       /* callbacks related to raw socket descriptor */
+
+        case LWS_CALLBACK_RAW_ADOPT:
+               lwsl_debug("%s: LWS_CALLBACK_RAW_ADOPT\n", __func__);
+               lws_callback_on_writable(wsi);
+               break;
+
+        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_info("%s: CONNECTION_ERROR\n", __func__);
+               goto do_close;
+
+       case LWS_CALLBACK_RAW_CLOSE:
+               lwsl_debug("%s: LWS_CALLBACK_RAW_CLOSE\n", __func__);
+do_close:
+               v->wsi_udp = NULL;
+
+               /* cancel any pending write retry */
+               lws_sul_cancel(&v->sul_write);
+
+               if (v->set_time)
+                       goto cancel_conn_timer;
+
+               lws_retry_sul_schedule(v->context, 0, &v->sul_conn, &bo,
+                                      lws_ntpc_retry_conn,
+                                      &v->retry_count_conn);
+               break;
+
+       case LWS_CALLBACK_RAW_RX:
+
+               if (len != 48)
+                       return 0; /* ignore it */
+
+               /*
+                * First get the seconds, corrected for the ntp epoch of 1900
+                * vs the unix epoch of 1970.  Then shift the seconds up by 1bn
+                * and add in the ns
+                */
+
+               ns = (uint64_t)lws_ser_ru32be(((uint8_t *)in) + 40) - (uint64_t)2208988800;
+               ns = (ns * 1000000000) + lws_ser_ru32be(((uint8_t *)in) + 44);
+
+               /*
+                * Compute the step
+                */
+
+               gettimeofday(&t1, NULL);
+
+               delta_us = ((int64_t)ns / 1000) -
+                               ((t1.tv_sec * LWS_US_PER_SEC) + t1.tv_usec);
+
+               lwsl_notice("%s: Unix time: %llu, step: %lldus\n", __func__,
+                               (unsigned long long)ns / 1000000000,
+                               (long long)delta_us);
+
+#if defined(LWS_PLAT_FREERTOS)
+               {
+                       struct timeval t;
+
+                       t.tv_sec = (unsigned long long)ns / 1000000000;
+                       t.tv_usec = (ns % 1000000000) / 1000;
+
+                       lws_sul_nonmonotonic_adjust(wsi->a.context, delta_us);
+
+                       settimeofday(&t, NULL);
+               }
+#endif
+               if (lws_system_get_ops(wsi->a.context) &&
+                   lws_system_get_ops(wsi->a.context)->set_clock)
+                       lws_system_get_ops(wsi->a.context)->set_clock((int64_t)ns / 1000);
+
+               v->set_time = 1;
+               lws_state_transition_steps(&wsi->a.context->mgr_system,
+                                          LWS_SYSTATE_OPERATIONAL);
+
+               /* close the wsi */
+               return -1;
+
+       case LWS_CALLBACK_RAW_WRITEABLE:
+
+               /*
+                * UDP is not reliable, it can be locally dropped, or dropped
+                * by any intermediary or the remote peer.  So even though we
+                * will do the write in a moment, we schedule another request
+                * for rewrite according to the wsi retry policy.
+                *
+                * If the result came before, we'll cancel it in the close flow.
+                *
+                * If we have already reached the end of our concealed retries
+                * in the policy, just close without another write.
+                */
+               if (lws_dll2_is_detached(&v->sul_write.list) &&
+                   lws_retry_sul_schedule_retry_wsi(wsi, &v->sul_write,
+                                                    lws_ntpc_retry_write,
+                                                    &v->retry_count_write)) {
+                       /* we have reached the end of our concealed retries */
+                       lwsl_warn("%s: concealed retries done, failing\n", __func__);
+                       goto retry_conn;
+               }
+
+               memset(pkt + LWS_PRE, 0, sizeof(pkt) - LWS_PRE);
+               pkt[LWS_PRE] = (LWSNTPC_LI_NONE << 6) |
+                              (LWSNTPC_VN_3 << 3) |
+                              (LWSNTPC_MODE_CLIENT << 0);
+
+               if (lws_write(wsi, pkt + LWS_PRE, sizeof(pkt) - LWS_PRE, 0) ==
+                                                 sizeof(pkt) - LWS_PRE)
+                       break;
+
+               lwsl_err("%s: Failed to write ntp client req\n", __func__);
+
+retry_conn:
+               lws_retry_sul_schedule(wsi->a.context, 0, &v->sul_conn, &bo,
+                                      lws_ntpc_retry_conn,
+                                      &v->retry_count_conn);
+
+               return -1;
+
+       default:
+               break;
+       }
+
+       return 0;
+
+
+cancel_conn_timer:
+       lws_sul_cancel(&v->sul_conn);
+
+       return 0;
+}
+
+void
+lws_ntpc_trigger(struct lws_context *ctx)
+{
+       struct vhd_ntpc *v = (struct vhd_ntpc *)ctx->ntpclient_priv;
+
+       lwsl_notice("%s\n", __func__);
+       v->retry_count_conn = 0;
+       lws_ntpc_retry_conn(&v->sul_conn);
+}
+
+struct lws_protocols lws_system_protocol_ntpc =
+       { "lws-ntpclient", callback_ntpc, 0, 128, 0, NULL, 0 };
+
diff --git a/lib/system/smd/CMakeLists.txt b/lib/system/smd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e05f6c1
--- /dev/null
@@ -0,0 +1,8 @@
+include_directories(.)
+
+list(APPEND SOURCES
+       system/smd/smd.c
+)
+
+exports_to_parent_scope()
+
diff --git a/lib/system/smd/README.md b/lib/system/smd/README.md
new file mode 100644 (file)
index 0000000..570e21c
--- /dev/null
@@ -0,0 +1,282 @@
+# LWS System Message Distribution
+
+## Overview
+
+Independent pieces of a system may need to become aware of events and state
+changes in the other pieces quickly, along with the new state if it is small.
+These messages are local to inside a system, although they may be triggered by
+events outside of it.  Examples include keypresses, or networking state changes.
+Individual OSes and frameworks typically have their own fragmented apis for
+message-passing, but the lws apis operate the same across any platforms
+including, eg, Windows and RTOS and allow crossplatform code to be written once.
+
+Message payloads are short, less than 384 bytes, below system limits for atomic
+pipe or UDS datagrams and consistent with heap usage on smaller systems, but
+large enough to carry JSON usefully.  Messages are typically low duty cycle.
+
+![SMD message](/doc-assets/smd-message.png)
+
+Messages may be sent by any registered participant, they are allocated on heap
+in a linked-list, and delivered to all other registered participants for that
+message class no sooner than next time around the event loop.  This retains the
+ability to handle multiple event queuing in one event loop trip while
+guaranteeing message handling is nonrecursive and so with modest stack usage.
+Messages are passed to all other registered participants before being destroyed.
+
+Messages are delivered to all particpants on the same lws_context by default.
+
+![SMD message](/doc-assets/smd-single-process.png)
+
+`lws_smd` apis allow publication and subscription of message objects between
+participants that are in a single process and are informed by callback from lws
+service thread context.
+
+SMD messages can also broadcast between particpants in different lws_contexts in
+different processes, using existing Secure Streams proxying.  In this way
+different application processes can intercommunicate and all observe any system
+smd messages they are interested in.
+
+![SMD message](/doc-assets/smd-proxy.png)
+
+Registering as a participant and sending messages are threadsafe APIs.
+
+## Message Class
+
+Message class is a bitfield messages use to indicate their general type, eg,
+network status, or UI event like a keypress.  Participants set a bitmask to
+filter what kind of messages they care about, classes that are 0 in the peer's
+filter are never delivered to the peer.   A message usually indicates it is a
+single class, but it's possible to set multiple class bits and match on any.  If
+so, care must be taken the payload can be parsed by readers expecting any of the
+indicated classes, eg, by using JSON.
+
+`lws_smd` tracks a global union mask for all participants' class mask.  Requests
+to allocate a message of a class that no participant listens for are rejected,
+not at distribution-time but at message allocation-time, so no heap or cpu is
+wasted on things that are not currently interesting; but such messages start to
+appear as soon as a participant appears that wants them.  The message generation
+action should be bypassed without error in the case lws_smd_msg_alloc()
+returns NULL.
+
+Various well-known high level classes are defined but also a bit index
+`LWSSMDCL_USER_BASE_BITNUM`, which can be used by user code to define up to 8
+private classes, with class bit values `(1 << LWSSMDCL_USER_BASE_BITNUM)` thru
+`(1 << (LWSSMDCL_USER_BASE_BITNUM + 7))`
+
+## Messaging guarantees
+
+Sent messages are delivered to all registered participants whose class mask
+indicates they want it, including the sender.  The send apis are threadsafe.
+
+Locally-delivered message delivery callbacks occur from lws event loop thread
+context 0 (the only one in the default case `LWS_MAX_SMP` = 1).  Clients in
+different processes receive callbacks from the thread context of their UDS
+networking thread.
+
+The message payload may be destroyed immediately when you return from the
+callback, you can't store references to it or expect it to be there later.
+
+Messages are timestamped with a systemwide monotonic timestamp.  When
+participants are on the lws event loop, messages are delivered in-order.  When
+participants are on different threads, delivery order depends on platform lock
+acquisition.  External process participants are connected by the Unix Domain
+Socket capability of Secure Streams, and may be delivered out-of-order;
+receivers that care must consult the message creation timestamps.
+
+## Message Refcounting
+
+To avoid keeping a list of the length of the number of participants for each
+message, a refcount is used in the message, computed at the time the message
+arrived considering the number of active participants that indicated a desire to
+receive messages of that class.
+
+Since peers may detach / close their link asynchronously, the logical peer
+objects at the distributor defer destroying themselves until there is no more
+possibility of messages arriving timestamped with the period they were active.
+A grace period (default 2s) is used to ensure departing peers correctly account
+for message refcounts before being destroyed.
+
+## Message creation
+
+Messages may contain arbitrary text or binary data depending on the class.  JSON
+is recommended since lws_smd messages are small and low duty cycle but have
+open-ended content: JSON is maintainable, extensible, debuggable and self-
+documenting and avoids, eg, fragile dependencies on header versions shared
+between teams.  To simplify issuing JSON, a threadsafe api to create and send
+messages in one step using format strings is provided:
+
+```
+int
+lws_smd_msg_printf(struct lws_context *ctx, lws_smd_class_t _class,
+                  const char *format, ...);
+```
+
+## Secure Streams `lws_smd` streamtype
+
+When built with LWS_WITH_SECURE_STREAMS, lws_smd exposes a built-in streamtype
+`_lws_smd` which user Secure Streams may use to interoperate with lws_smd using
+SS payload semantics.
+
+When using `_lws_smd`, the SS info struct member `manual_initial_tx_credit`
+provided by the user when creating the Secure Stream is overloaded to be used as
+the RX class mask for the SMD connection associated with the Secure Stream.
+
+Both RX and TX payloads have a 16-byte binary header before the actual payload.
+For TX, although the header is 16-bytes, only the first 64-bit class bitfield
+needs setting, the timestamp is fetched and added by lws.
+
+ - MSB-first 64-bit class bitfield (currently only 32 least-sig in use) 
+ - MSB-First Order 64-bit us-resolution timestamp
+A helper `lws_smd_ss_msg_printf()` is provided to format and create and smd
+message from the SS tx() callback in one step, using the same api layout as
+for direct messages via `lws_smd_msg_printf()`
+
+```
+int
+lws_smd_ss_msg_printf(const char *tag, uint8_t *buf, size_t *len,
+                     lws_smd_class_t _class, const char *format, ...);
+```
+
+## Well-known message schema
+
+Class|Schema
+---|---
+LWSSMDCL_INTERACTION|lws_button events
+LWSSMDCL_NETWORK|captive portal detection requests and results
+LWSSMDCL_SYSTEM_STATE|lws_system state progression
+
+### User interaction Button events
+
+Class: `LWSSMDCL_INTERACTION`
+
+Produced by lws_button when a user interacts with a defined button.
+
+Click-related events are produced alongside up and down related events, the
+participant can choose which to attend to according to the meaning of the
+interaction.
+
+Both kinds of event go through sophisticated filtering before being issued, see
+`./lib/drivers/button/README.md` for details.
+
+#### SMD Button interaction event
+
+Schema:
+```
+{
+       "type":  "button",
+       "src":   "<controller-name>/<button-name>",
+       "event": "<event-name>"
+}
+```
+
+For example, `{"type":"button","src":"bc/user","event":"doubleclick"}`
+
+Event name|Meaning
+---|---
+down|The button passes a filter for being down, useful for duration-based response
+up|The button has come up, useful for duration-based response
+click|The button activity resulted in a classification as a single-click
+longclick|The button activity resulted in a classification as a long-click
+doubleclick|The button activity resulted in a classification as a double-click
+
+### Routing Table Change
+
+Class: `LWSSMDCL_NETWORK`
+
+If able to subscribe to OS routing table changes (eg, by rtnetlink on Linux
+which is supported), lws announces there have been changes using SMD.
+
+If Captive Portal Detect is enabled, and routing tables changes can be seen,
+then a new CPD is requested automatically and the results will be seen over SMD
+when that completes.
+
+Schema:
+
+```
+       {
+         "rt":      "add|del",   "add" if being added
+       }
+```
+
+When the context / pts are created, if linux then lws attempts to get the
+routing table sent, which requires root.  This is done before the permissions
+are dropped after protocols init.
+
+Lws maintains a cache of the routing table in each pt.  Upon changes, existing
+connections are reassessed to see if their peer can still be routed to, if not
+the connection is closed.
+
+If a gateway route changes, `{"trigger":"cpdcheck","src":"gw-change"}` is
+issued on SMD as well.
+
+### Captive Portal Detection
+
+Class: `LWSSMDCL_NETWORK`
+
+Actively detects if the network can reach the internet or if it is
+intercepted by a captive portal.  The detection steps are programmable
+via the Secure Streams Policy for a streamtype `captive_portal_detect`, eg
+
+```
+       "captive_portal_detect": {
+               "endpoint":             "connectivitycheck.android.com",
+               "http_url":             "generate_204",
+               "port":                 80,
+               "protocol":             "h1",
+               "http_method":          "GET",
+               "opportunistic":        true,
+               "http_expect":          204,
+               "http_fail_redirect":   true
+       }
+```
+
+#### SMD Report Result
+
+Schema: `{"type": "cpd", "result":"<result>"}`
+
+result|meaning
+---|---
+OK|Internet is reachable
+Captive|Internet is behind a captive portal
+No internet|There is no connectivity
+
+#### SMD Request re-detection
+
+Schema: `{"trigger": "cpdcheck"}`
+
+### lws_system state progression
+
+Class: `LWSSMDCL_SYSTEM_STATE`
+
+Lws system state changes are forwarded to lws_smd messages so participants not
+on the lws event loop directly can be aware of progress.  Code registering a
+lws_system notifier callback, on the main lws loop, can synchronously veto state
+changes and hook proposed state changes, lws_smd events are asynchronous
+notifications of state changes after they were decided only... however they are
+available over the whole system.
+
+It's not possible to make validated TLS connections until the system has
+acquired the date as well as acquired an IP on a non-captive portal connection,
+for that reason user code will usually be dependent on the system reaching
+"OPERATIONAL" state if lws is responsible for managing the boot process.
+
+#### System state event
+
+Schema: `{"state":"<state>"}"`
+
+State|Meaning
+---|---
+CONTEXT_CREATED|We're creating the lws_context
+INITIALIZED|Initial vhosts and protocols initialized
+IFACE_COLDPLUG|Network interfaces discovered
+DHCP|DHCP acquired
+CPD_PRE_TIME|Captive portal detect hook before we have system time
+TIME_VALID|Ntpclient has run
+CPD_POST_TIME|Captive portal detect hook after system time (tls-based check)
+POLICY_VALID|The system policy has been acquired and parsed
+REGISTERED|This device is registered with an authority
+AUTH1|We acquired auth1 from the authority using our registration info
+AUTH2|We acquired auth2 from the authority using our registration info
+OPERATIONAL|We are active and able to make authenticated tls connections
+POLICY_INVALID|The policy is being changed
diff --git a/lib/system/smd/private-lib-system-smd.h b/lib/system/smd/private-lib-system-smd.h
new file mode 100644 (file)
index 0000000..452ba15
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * lws System Message Distribution
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+#define LWS_SMD_SS_RX_HEADER_LEN_EFF   (LWS_SMD_SS_RX_HEADER_LEN)
+#else
+#define LWS_SMD_SS_RX_HEADER_LEN_EFF   (0)
+#endif
+
+struct lws_smd_peer;
+
+typedef struct lws_smd_msg {
+       lws_dll2_t                      list;
+
+       struct lws_smd_peer             *exc;
+
+       lws_usec_t                      timestamp;
+       lws_smd_class_t                 _class;
+
+       uint16_t                        length;
+       uint16_t                        refcount;
+
+       /* message itself is over-allocated after this */
+} lws_smd_msg_t;
+
+typedef struct lws_smd_peer {
+       lws_dll2_t                      list;
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+       lws_ss_handle_t                 *ss_handle; /* LSMDT_SECURE_STREAMS */
+#endif
+
+       lws_smd_notification_cb_t       cb;   /* LSMDT_<other> */
+       struct lws_context              *ctx;
+       void                            *opaque;
+
+       /* NULL, or next message we will handle */
+       lws_smd_msg_t                   *tail;
+
+       lws_smd_class_t                 _class_filter;
+} lws_smd_peer_t;
+
+/*
+ * Manages message distribution
+ *
+ * There is one of these in the lws_context, but the distribution action also
+ * gets involved in delivering to pt event loops individually for SMP case
+ */
+
+typedef struct lws_smd {
+       lws_dll2_owner_t                owner_messages; /* lws_smd_msg_t */
+       lws_mutex_t                     lock_messages;
+       lws_dll2_owner_t                owner_peers;    /* lws_smd_peer_t */
+       lws_mutex_t                     lock_peers;
+
+       /* union of peer class filters, suppress creation of msg classes not set */
+       lws_smd_class_t                 _class_filter;
+
+       char                            delivering;
+} lws_smd_t;
+
+/* check if this tsi has pending messages to deliver */
+
+int
+lws_smd_message_pending(struct lws_context *ctx);
+
+int
+lws_smd_msg_distribute(struct lws_context *ctx);
+
+int
+_lws_smd_destroy(struct lws_context *ctx);
+
diff --git a/lib/system/smd/smd.c b/lib/system/smd/smd.c
new file mode 100644 (file)
index 0000000..13ccadb
--- /dev/null
@@ -0,0 +1,804 @@
+/*
+ * lws System Message Distribution
+ *
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include <assert.h>
+
+/* comment me to remove extra debug and sanity checks */
+// #define LWS_SMD_DEBUG
+
+
+#if defined(LWS_SMD_DEBUG)
+#define lwsl_smd lwsl_notice
+#else
+#define lwsl_smd(_s, ...)
+#endif
+
+void *
+lws_smd_msg_alloc(struct lws_context *ctx, lws_smd_class_t _class, size_t len)
+{
+       lws_smd_msg_t *msg;
+
+       /* only allow it if someone wants to consume this class of event */
+
+       if (!(ctx->smd._class_filter & _class)) {
+               lwsl_cx_info(ctx, "rejecting class 0x%x as no participant wants",
+                               (unsigned int)_class);
+               return NULL;
+       }
+
+       assert(len <= LWS_SMD_MAX_PAYLOAD);
+
+
+       /*
+        * If SS configured, over-allocate LWS_SMD_SS_RX_HEADER_LEN behind
+        * payload, ie,  msg_t (gap LWS_SMD_SS_RX_HEADER_LEN) payload
+        */
+       msg = lws_malloc(sizeof(*msg) + LWS_SMD_SS_RX_HEADER_LEN_EFF + len,
+                        __func__);
+       if (!msg)
+               return NULL;
+
+       memset(msg, 0, sizeof(*msg));
+       msg->timestamp = lws_now_usecs();
+       msg->length = (uint16_t)len;
+       msg->_class = _class;
+
+       return ((uint8_t *)&msg[1]) + LWS_SMD_SS_RX_HEADER_LEN_EFF;
+}
+
+void
+lws_smd_msg_free(void **ppay)
+{
+       lws_smd_msg_t *msg = (lws_smd_msg_t *)(((uint8_t *)*ppay) -
+                               LWS_SMD_SS_RX_HEADER_LEN_EFF - sizeof(*msg));
+
+       /* if SS configured, actual alloc is LWS_SMD_SS_RX_HEADER_LEN behind */
+       lws_free(msg);
+       *ppay = NULL;
+}
+
+#if defined(LWS_SMD_DEBUG)
+static void
+lws_smd_dump(lws_smd_t *smd)
+{
+       int n = 1;
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  smd->owner_messages.head) {
+               lws_smd_msg_t *msg = lws_container_of(p, lws_smd_msg_t, list);
+
+               lwsl_info(" msg %d: %p: ref %d, lat %dms, cls: 0x%x, len %u: '%s'\n",
+                           n++, msg, msg->refcount,
+                           (unsigned int)((lws_now_usecs() - msg->timestamp) / 1000),
+                           msg->length, msg->_class,
+                           (const char *)&msg[1] + LWS_SMD_SS_RX_HEADER_LEN_EFF);
+
+       } lws_end_foreach_dll_safe(p, p1);
+
+       n = 1;
+       lws_start_foreach_dll(struct lws_dll2 *, p, smd->owner_peers.head) {
+               lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
+
+               lwsl_info(" peer %d: %p: tail: %p, filt 0x%x\n",
+                           n++, pr, pr->tail, pr->_class_filter);
+       } lws_end_foreach_dll(p);
+}
+#endif
+
+static int
+_lws_smd_msg_peer_interested_in_msg(lws_smd_peer_t *pr, lws_smd_msg_t *msg)
+{
+    return !!(msg->_class & pr->_class_filter);
+}
+
+/*
+ * Figure out what to set the initial refcount for the message to
+ */
+
+static int
+_lws_smd_msg_assess_peers_interested(lws_smd_t *smd, lws_smd_msg_t *msg,
+                                    struct lws_smd_peer *exc)
+{
+       struct lws_context *ctx = lws_container_of(smd, struct lws_context, smd);
+       int interested = 0;
+
+       lws_start_foreach_dll(struct lws_dll2 *, p, ctx->smd.owner_peers.head) {
+               lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
+
+               if (pr != exc && _lws_smd_msg_peer_interested_in_msg(pr, msg))
+                       /*
+                        * This peer wants to consume it
+                        */
+                       interested++;
+
+       } lws_end_foreach_dll(p);
+
+       return interested;
+}
+
+static int
+_lws_smd_class_mask_union(lws_smd_t *smd)
+{
+       uint32_t mask = 0;
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  smd->owner_peers.head) {
+               lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
+
+               mask |= pr->_class_filter;
+
+       } lws_end_foreach_dll_safe(p, p1);
+
+       smd->_class_filter = mask;
+
+       return 0;
+}
+
+/* Call with message lock held */
+
+static void
+_lws_smd_msg_destroy(struct lws_context *cx, lws_smd_t *smd, lws_smd_msg_t *msg)
+{
+       /*
+        * We think we gave the message to everyone and can destroy it.
+        * Sanity check that no peer holds a pointer to this guy
+        */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  smd->owner_peers.head) {
+               lws_smd_peer_t *xpr = lws_container_of(p, lws_smd_peer_t, list);
+
+               if (xpr->tail == msg) {
+                       lwsl_cx_err(cx, "peer %p has msg %p "
+                                "we are about to destroy as tail", xpr, msg);
+#if !defined(LWS_PLAT_FREERTOS)
+                       assert(0);
+#endif
+               }
+
+       } lws_end_foreach_dll_safe(p, p1);
+
+       /*
+        * We have fully delivered the message now, it
+        * can be unlinked and destroyed
+        */
+       lwsl_cx_info(cx, "destroy msg %p", msg);
+       lws_dll2_remove(&msg->list);
+       lws_free(msg);
+}
+
+/*
+ * This is wanting to be threadsafe, limiting the apis we can call
+ */
+
+int
+_lws_smd_msg_send(struct lws_context *ctx, void *pay, struct lws_smd_peer *exc)
+{
+       lws_smd_msg_t *msg = (lws_smd_msg_t *)(((uint8_t *)pay) -
+                               LWS_SMD_SS_RX_HEADER_LEN_EFF - sizeof(*msg));
+
+       if (ctx->smd.owner_messages.count >= ctx->smd_queue_depth) {
+               lwsl_cx_warn(ctx, "rejecting message on queue depth %d",
+                                 (int)ctx->smd.owner_messages.count);
+               /* reject the message due to max queue depth reached */
+               return 1;
+       }
+
+       if (!ctx->smd.delivering &&
+           lws_mutex_lock(ctx->smd.lock_peers)) /* +++++++++++++++ peers */
+               return 1; /* For Coverity */
+
+       if (lws_mutex_lock(ctx->smd.lock_messages)) /* +++++++++++++++++ messages */
+               goto bail;
+
+       msg->refcount = (uint16_t)_lws_smd_msg_assess_peers_interested(
+                                                       &ctx->smd, msg, exc);
+       if (!msg->refcount) {
+               /* possible, condsidering exc and no other participants */
+               lws_mutex_unlock(ctx->smd.lock_messages); /* --------------- messages */
+
+               lws_free(msg);
+               if (!ctx->smd.delivering)
+                       lws_mutex_unlock(ctx->smd.lock_peers); /* ------------- peers */
+
+               return 0;
+       }
+
+       msg->exc = exc;
+
+       /* let's add him on the queue... */
+
+       lws_dll2_add_tail(&msg->list, &ctx->smd.owner_messages);
+
+       /*
+        * Any peer with no active tail needs to check our class to see if we
+        * should become his tail
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, p, ctx->smd.owner_peers.head) {
+               lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
+
+               if (pr != exc &&
+                   !pr->tail && _lws_smd_msg_peer_interested_in_msg(pr, msg)) {
+                       pr->tail = msg;
+                       /* tail message has to actually be of interest to the peer */
+                       assert(!pr->tail || (pr->tail->_class & pr->_class_filter));
+               }
+
+       } lws_end_foreach_dll(p);
+
+#if defined(LWS_SMD_DEBUG)
+       lwsl_smd("%s: added %p (refc %u) depth now %d\n", __func__,
+                msg, msg->refcount, ctx->smd.owner_messages.count);
+       lws_smd_dump(&ctx->smd);
+#endif
+
+       lws_mutex_unlock(ctx->smd.lock_messages); /* --------------- messages */
+
+bail:
+       if (!ctx->smd.delivering)
+               lws_mutex_unlock(ctx->smd.lock_peers); /* ------------- peers */
+
+       /* we may be happening from another thread context */
+       lws_cancel_service(ctx);
+
+       return 0;
+}
+
+/*
+ * This is wanting to be threadsafe, limiting the apis we can call
+ */
+
+int
+lws_smd_msg_send(struct lws_context *ctx, void *pay)
+{
+       return _lws_smd_msg_send(ctx, pay, NULL);
+}
+
+/*
+ * This is wanting to be threadsafe, limiting the apis we can call
+ */
+
+int
+lws_smd_msg_printf(struct lws_context *ctx, lws_smd_class_t _class,
+                  const char *format, ...)
+{
+       lws_smd_msg_t *msg;
+       va_list ap;
+       void *p;
+       int n;
+
+       if (!(ctx->smd._class_filter & _class))
+               /*
+                * There's nobody interested in messages of this class atm.
+                * Don't bother generating it, and act like all is well.
+                */
+               return 0;
+
+       va_start(ap, format);
+       n = vsnprintf(NULL, 0, format, ap);
+       va_end(ap);
+       if (n > LWS_SMD_MAX_PAYLOAD)
+               /* too large to send */
+               return 1;
+
+       p = lws_smd_msg_alloc(ctx, _class, (size_t)n + 2);
+       if (!p)
+               return 1;
+       msg = (lws_smd_msg_t *)(((uint8_t *)p) - LWS_SMD_SS_RX_HEADER_LEN_EFF -
+                                                               sizeof(*msg));
+       msg->length = (uint16_t)n;
+       va_start(ap, format);
+       vsnprintf((char *)p, (unsigned int)n + 2, format, ap);
+       va_end(ap);
+
+       /*
+        * locks taken and released in here
+        */
+
+       if (lws_smd_msg_send(ctx, p)) {
+               lws_smd_msg_free(&p);
+               return 1;
+       }
+
+       return 0;
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS)
+int
+lws_smd_ss_msg_printf(const char *tag, uint8_t *buf, size_t *len,
+                     lws_smd_class_t _class, const char *format, ...)
+{
+       char *content = (char *)buf + LWS_SMD_SS_RX_HEADER_LEN;
+       va_list ap;
+       int n;
+
+       if (*len < LWS_SMD_SS_RX_HEADER_LEN)
+               return 1;
+
+       lws_ser_wu64be(buf, _class);
+       lws_ser_wu64be(buf + 8, 0); /* valgrind notices uninitialized if left */
+
+       va_start(ap, format);
+       n = vsnprintf(content, (*len) - LWS_SMD_SS_RX_HEADER_LEN, format, ap);
+       va_end(ap);
+
+       if (n > LWS_SMD_MAX_PAYLOAD ||
+           (unsigned int)n > (*len) - LWS_SMD_SS_RX_HEADER_LEN)
+               /* too large to send */
+               return 1;
+
+       *len = LWS_SMD_SS_RX_HEADER_LEN + (unsigned int)n;
+
+       lwsl_info("%s: %s send cl 0x%x, len %u\n", __func__, tag, (unsigned int)_class,
+                       (unsigned int)n);
+
+       return 0;
+}
+
+/*
+ * This is a helper that user rx handler for LWS_SMD_STREAMTYPENAME SS can
+ * call through to with the payload it received from the proxy.  It will then
+ * forward the recieved SMD message to all local (same-context) participants
+ * that are interested in that class (except ones with callback skip_cb, so
+ * we don't loop).
+ */
+
+static int
+_lws_smd_ss_rx_forward(struct lws_context *ctx, const char *tag,
+                      struct lws_smd_peer *pr, const uint8_t *buf, size_t len)
+{
+       lws_smd_class_t _class;
+       lws_smd_msg_t *msg;
+       void *p;
+
+       if (len < LWS_SMD_SS_RX_HEADER_LEN_EFF)
+               return 1;
+
+       if (len >= LWS_SMD_MAX_PAYLOAD + LWS_SMD_SS_RX_HEADER_LEN_EFF)
+               return 1;
+
+       _class = (lws_smd_class_t)lws_ser_ru64be(buf);
+
+       if (_class == LWSSMDCL_METRICS) {
+
+       }
+
+       /* only locally forward messages that we care about in this process */
+
+       if (!(ctx->smd._class_filter & _class))
+               /*
+                * There's nobody interested in messages of this class atm.
+                * Don't bother generating it, and act like all is well.
+                */
+               return 0;
+
+       p = lws_smd_msg_alloc(ctx, _class, len);
+       if (!p)
+               return 1;
+
+       msg = (lws_smd_msg_t *)(((uint8_t *)p) - LWS_SMD_SS_RX_HEADER_LEN_EFF -
+                                                               sizeof(*msg));
+       msg->length = (uint16_t)(len - LWS_SMD_SS_RX_HEADER_LEN_EFF);
+       /* adopt the original source timestamp, not time we forwarded it */
+       msg->timestamp = (lws_usec_t)lws_ser_ru64be(buf + 8);
+
+       /* copy the message payload in */
+       memcpy(p, buf + LWS_SMD_SS_RX_HEADER_LEN_EFF, msg->length);
+
+       /*
+        * locks taken and released in here
+        */
+
+       if (_lws_smd_msg_send(ctx, p, pr)) {
+               /* we couldn't send it after all that... */
+               lws_smd_msg_free(&p);
+
+               return 1;
+       }
+
+       lwsl_info("%s: %s send cl 0x%x, len %u, ts %llu\n", __func__,
+                   tag, (unsigned int)_class, msg->length,
+                   (unsigned long long)msg->timestamp);
+
+       return 0;
+}
+
+int
+lws_smd_ss_rx_forward(void *ss_user, const uint8_t *buf, size_t len)
+{
+       struct lws_ss_handle *h = (struct lws_ss_handle *)
+                                       (((char *)ss_user) - sizeof(*h));
+       struct lws_context *ctx = lws_ss_get_context(h);
+
+       return _lws_smd_ss_rx_forward(ctx, lws_ss_tag(h), h->u.smd.smd_peer, buf, len);
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+int
+lws_smd_sspc_rx_forward(void *ss_user, const uint8_t *buf, size_t len)
+{
+       struct lws_sspc_handle *h = (struct lws_sspc_handle *)
+                                       (((char *)ss_user) - sizeof(*h));
+       struct lws_context *ctx = lws_sspc_get_context(h);
+
+       return _lws_smd_ss_rx_forward(ctx, lws_sspc_tag(h), NULL, buf, len);
+}
+#endif
+
+#endif
+
+/*
+ * Peers that deregister need to adjust the refcount of messages they would
+ * have been interested in, but didn't take delivery of yet
+ */
+
+static void
+_lws_smd_peer_destroy(lws_smd_peer_t *pr)
+{
+       lws_smd_t *smd = lws_container_of(pr->list.owner, lws_smd_t,
+                                         owner_peers);
+
+       if (lws_mutex_lock(smd->lock_messages)) /* +++++++++ messages */
+               return; /* For Coverity */
+
+       lws_dll2_remove(&pr->list);
+
+       /*
+        * We take the approach to adjust the refcount of every would-have-been
+        * delivered message we were interested in
+        */
+
+       while (pr->tail) {
+
+               lws_smd_msg_t *m1 = lws_container_of(pr->tail->list.next,
+                                                       lws_smd_msg_t, list);
+
+               if (_lws_smd_msg_peer_interested_in_msg(pr, pr->tail)) {
+                       if (!--pr->tail->refcount)
+                               _lws_smd_msg_destroy(pr->ctx, smd, pr->tail);
+               }
+
+               pr->tail = m1;
+       }
+
+       lws_free(pr);
+
+       lws_mutex_unlock(smd->lock_messages); /* messages ------- */
+}
+
+static lws_smd_msg_t *
+_lws_smd_msg_next_matching_filter(lws_smd_peer_t *pr)
+{
+       lws_dll2_t *tail = &pr->tail->list;
+       lws_smd_msg_t *msg;
+
+       do {
+               tail = tail->next;
+               if (!tail)
+                       return NULL;
+
+               msg = lws_container_of(tail, lws_smd_msg_t, list);
+               if (msg->exc != pr &&
+                   _lws_smd_msg_peer_interested_in_msg(pr, msg))
+                       return msg;
+       } while (1);
+
+       return NULL;
+}
+
+/*
+ * Delivers only one message to the peer and advances the tail, or sets to NULL
+ * if no more filtered queued messages.  Returns nonzero if tail non-NULL.
+ *
+ * For Proxied SS, only asks for writeable and does not advance or change the
+ * tail.
+ *
+ * This is done so if multiple messages queued, we don't get a situation where
+ * one participant gets them all spammed, then the next etc.  Instead they are
+ * delivered round-robin.
+ *
+ * Requires peer lock, may take message lock
+ */
+
+static int
+_lws_smd_msg_deliver_peer(struct lws_context *ctx, lws_smd_peer_t *pr)
+{
+       lws_smd_msg_t *msg;
+
+       if (!pr->tail)
+               return 0;
+
+       msg = lws_container_of(pr->tail, lws_smd_msg_t, list);
+
+
+       lwsl_cx_info(ctx, "deliver cl 0x%x, len %d, refc %d, to peer %p",
+                   (unsigned int)msg->_class, (int)msg->length,
+                   (int)msg->refcount, pr);
+
+       pr->cb(pr->opaque, msg->_class, msg->timestamp,
+              ((uint8_t *)&msg[1]) + LWS_SMD_SS_RX_HEADER_LEN_EFF,
+              (size_t)msg->length);
+
+       assert(msg->refcount);
+
+       /*
+        * If there is one, move forward to the next queued
+        * message that meets the filters of this peer
+        */
+       pr->tail = _lws_smd_msg_next_matching_filter(pr);
+
+       /* tail message has to actually be of interest to the peer */
+       assert(!pr->tail || (pr->tail->_class & pr->_class_filter));
+
+       if (lws_mutex_lock(ctx->smd.lock_messages)) /* +++++++++ messages */
+               return 1; /* For Coverity */
+
+       if (!--msg->refcount)
+               _lws_smd_msg_destroy(ctx, &ctx->smd, msg);
+       lws_mutex_unlock(ctx->smd.lock_messages); /* messages ------- */
+
+       return !!pr->tail;
+}
+
+/*
+ * Called when the event loop could deliver messages synchronously, eg, on
+ * entry to idle
+ */
+
+int
+lws_smd_msg_distribute(struct lws_context *ctx)
+{
+       char more;
+
+       /* commonly, no messages and nothing to do... */
+
+       if (!ctx->smd.owner_messages.count)
+               return 0;
+
+       ctx->smd.delivering = 1;
+
+       do {
+               more = 0;
+               if (lws_mutex_lock(ctx->smd.lock_peers)) /* +++++++++++++++ peers */
+                       return 1; /* For Coverity */
+
+               lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                          ctx->smd.owner_peers.head) {
+                       lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
+
+                       more = (char)(more | !!_lws_smd_msg_deliver_peer(ctx, pr));
+
+               } lws_end_foreach_dll_safe(p, p1);
+
+               lws_mutex_unlock(ctx->smd.lock_peers); /* ------------- peers */
+       } while (more);
+
+       ctx->smd.delivering = 0;
+
+       return 0;
+}
+
+struct lws_smd_peer *
+lws_smd_register(struct lws_context *ctx, void *opaque, int flags,
+                lws_smd_class_t _class_filter, lws_smd_notification_cb_t cb)
+{
+       lws_smd_peer_t *pr = lws_zalloc(sizeof(*pr), __func__);
+
+       if (!pr)
+               return NULL;
+
+       pr->cb = cb;
+       pr->opaque = opaque;
+       pr->_class_filter = _class_filter;
+       pr->ctx = ctx;
+
+       if (!ctx->smd.delivering &&
+           lws_mutex_lock(ctx->smd.lock_peers)) { /* +++++++++++++++ peers */
+                       lws_free(pr);
+                       return NULL; /* For Coverity */
+               }
+
+       /*
+        * Let's lock the message list before adding this peer... because...
+        */
+
+       if (lws_mutex_lock(ctx->smd.lock_messages)) { /* +++++++++ messages */
+               lws_free(pr);
+               pr = NULL;
+               goto bail1; /* For Coverity */
+       }
+
+       lws_dll2_add_tail(&pr->list, &ctx->smd.owner_peers);
+
+       /* update the global class mask union to account for new peer mask */
+       _lws_smd_class_mask_union(&ctx->smd);
+
+       /*
+        * Now there's a new peer added, any messages we have stashed will try
+        * to deliver to this guy too, if he's interested in that class.  So we
+        * have to update the message refcounts for queued messages-he's-
+        * interested-in accordingly.
+        */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  ctx->smd.owner_messages.head) {
+               lws_smd_msg_t *msg = lws_container_of(p, lws_smd_msg_t, list);
+
+               if (_lws_smd_msg_peer_interested_in_msg(pr, msg))
+                       msg->refcount++;
+
+       } lws_end_foreach_dll_safe(p, p1);
+
+       /* ... ok we are done adding the peer */
+
+       lws_mutex_unlock(ctx->smd.lock_messages); /* messages ------- */
+
+       lwsl_cx_info(ctx, "peer %p (count %u) registered", pr,
+                       (unsigned int)ctx->smd.owner_peers.count);
+
+bail1:
+       if (!ctx->smd.delivering)
+               lws_mutex_unlock(ctx->smd.lock_peers); /* ------------- peers */
+
+       return pr;
+}
+
+void
+lws_smd_unregister(struct lws_smd_peer *pr)
+{
+       lws_smd_t *smd = lws_container_of(pr->list.owner, lws_smd_t, owner_peers);
+
+       if (!smd->delivering &&
+           lws_mutex_lock(smd->lock_peers)) /* +++++++++++++++++++ peers */
+               return; /* For Coverity */
+       lwsl_cx_notice(pr->ctx, "destroying peer %p", pr);
+       _lws_smd_peer_destroy(pr);
+       if (!smd->delivering)
+               lws_mutex_unlock(smd->lock_peers); /* ----------------- peers */
+}
+
+int
+lws_smd_message_pending(struct lws_context *ctx)
+{
+       int ret = 1;
+
+       /*
+        * First cheaply check the common case no messages pending, so there's
+        * definitely nothing for this tsi or anything else
+        */
+
+       if (!ctx->smd.owner_messages.count)
+               return 0;
+
+       /*
+        * If there are any messages, check their age and expire ones that
+        * have been hanging around too long
+        */
+
+       if (lws_mutex_lock(ctx->smd.lock_peers)) /* +++++++++++++++++++++++ peers */
+               return 1; /* For Coverity */
+       if (lws_mutex_lock(ctx->smd.lock_messages)) /* +++++++++++++++++ messages */
+               goto bail; /* For Coverity */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  ctx->smd.owner_messages.head) {
+               lws_smd_msg_t *msg = lws_container_of(p, lws_smd_msg_t, list);
+
+               if ((lws_now_usecs() - msg->timestamp) > ctx->smd_ttl_us) {
+                       lwsl_cx_warn(ctx, "timing out queued message %p",
+                                       msg);
+
+                       /*
+                        * We're forcibly yanking this guy, we can expect that
+                        * there might be peers that point to it as their tail.
+                        *
+                        * In that case, move their tails on to the next guy
+                        * they are interested in, if any.
+                        */
+
+                       lws_start_foreach_dll_safe(struct lws_dll2 *, pp, pp1,
+                                                  ctx->smd.owner_peers.head) {
+                               lws_smd_peer_t *pr = lws_container_of(pp,
+                                                       lws_smd_peer_t, list);
+
+                               if (pr->tail == msg)
+                                       pr->tail = _lws_smd_msg_next_matching_filter(pr);
+
+                       } lws_end_foreach_dll_safe(pp, pp1);
+
+                       /*
+                        * No peer should fall foul of the peer tail checks
+                        * when destroying the message now.
+                        */
+
+                       _lws_smd_msg_destroy(ctx, &ctx->smd, msg);
+               }
+       } lws_end_foreach_dll_safe(p, p1);
+
+       lws_mutex_unlock(ctx->smd.lock_messages); /* --------------- messages */
+
+       /*
+        * Walk the peer list
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, p, ctx->smd.owner_peers.head) {
+               lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
+
+               if (pr->tail)
+                       goto bail;
+
+       } lws_end_foreach_dll(p);
+
+       /*
+        * There's no message pending that we need to handle
+        */
+
+       ret = 0;
+
+bail:
+       lws_mutex_unlock(ctx->smd.lock_peers); /* --------------------- peers */
+
+       return ret;
+}
+
+int
+_lws_smd_destroy(struct lws_context *ctx)
+{
+       /* stop any message creation */
+
+       ctx->smd._class_filter = 0;
+
+       /*
+        * Walk the message list, destroying them
+        */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  ctx->smd.owner_messages.head) {
+               lws_smd_msg_t *msg = lws_container_of(p, lws_smd_msg_t, list);
+
+               lws_dll2_remove(&msg->list);
+               lws_free(msg);
+
+       } lws_end_foreach_dll_safe(p, p1);
+
+       /*
+        * Walk the peer list, destroying them
+        */
+
+       lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
+                                  ctx->smd.owner_peers.head) {
+               lws_smd_peer_t *pr = lws_container_of(p, lws_smd_peer_t, list);
+
+               pr->tail = NULL; /* we just nuked all the messages, ignore */
+               _lws_smd_peer_destroy(pr);
+
+       } lws_end_foreach_dll_safe(p, p1);
+
+       lws_mutex_destroy(ctx->smd.lock_messages);
+       lws_mutex_destroy(ctx->smd.lock_peers);
+
+       return 0;
+}
diff --git a/lib/system/system.c b/lib/system/system.c
new file mode 100644 (file)
index 0000000..824ac68
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <private-lib-core.h>
+
+/*
+ * It's either a buflist (.is_direct = 0) or
+ * a direct pointer + len (.is_direct = 1)
+ */
+
+const lws_system_ops_t *
+lws_system_get_ops(struct lws_context *context)
+{
+       return context->system_ops;
+}
+
+
+void
+lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len)
+{
+       b->is_direct = 1;
+       b->u.direct.ptr = ptr;
+       b->u.direct.len = len;
+}
+
+void
+lws_system_blob_heap_empty(lws_system_blob_t *b)
+{
+       b->is_direct = 0;
+       lws_buflist_destroy_all_segments(&b->u.bl);
+}
+
+int
+lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *buf, size_t len)
+{
+       assert(!b->is_direct);
+
+       lwsl_debug("%s: blob %p\n", __func__, b);
+
+       if (lws_buflist_append_segment(&b->u.bl, buf, len) < 0)
+               return -1;
+
+       return 0;
+}
+
+size_t
+lws_system_blob_get_size(lws_system_blob_t *b)
+{
+       if (b->is_direct)
+               return b->u.direct.len;
+
+       return lws_buflist_total_len(&b->u.bl);
+}
+
+int
+lws_system_blob_get(lws_system_blob_t *b, uint8_t *buf, size_t *len, size_t ofs)
+{
+       int n;
+
+       if (b->is_direct) {
+
+               assert(b->u.direct.ptr);
+
+               if (ofs >= b->u.direct.len) {
+                       *len = 0;
+                       return 1;
+               }
+
+               if (*len > b->u.direct.len - ofs)
+                       *len = b->u.direct.len - ofs;
+
+               memcpy(buf, b->u.direct.ptr + ofs, *len);
+
+               return 0;
+       }
+
+       n = lws_buflist_linear_copy(&b->u.bl, ofs, buf, *len);
+       if (n < 0)
+               return -2;
+
+       *len = (unsigned int)n;
+
+       return 0;
+}
+
+int
+lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr)
+{
+       if (b->is_direct) {
+               *ptr = b->u.direct.ptr;
+               return 0;
+       }
+
+       if (!b->u.bl)
+               return -1;
+
+       if (b->u.bl->next)
+               return -1;  /* multipart buflist, no single pointer to it all */
+
+       *ptr = (const uint8_t *)&b->u.bl[1] + LWS_PRE;
+
+       return 0;
+}
+
+void
+lws_system_blob_destroy(lws_system_blob_t *b)
+{
+       if (!b)
+               return;
+       // lwsl_info("%s: blob %p\n", __func__, b);
+       if (!b->is_direct)
+               lws_buflist_destroy_all_segments(&b->u.bl);
+}
+
+lws_system_blob_t *
+lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
+                   int idx)
+{
+       if (idx < 0 ||
+           idx >= (int)LWS_ARRAY_SIZE(context->system_blobs))
+               return NULL;
+
+       return &context->system_blobs[type + (unsigned int)idx];
+}
+
+#if defined(LWS_WITH_NETWORK)
+
+/*
+ * Caller must protect the whole call with system-specific locking
+ */
+
+int
+__lws_system_attach(struct lws_context *context, int tsi, lws_attach_cb_t cb,
+                   lws_system_states_t state, void *opaque,
+                   struct lws_attach_item **get)
+{
+       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_attach_item *item;
+
+       if (!get) {
+               /*
+                * allocate and add to the head of the pt's attach list
+                */
+
+               item = lws_zalloc(sizeof(*item), __func__);
+               if (!item)
+                       return 1;
+
+               item->cb = cb;
+               item->opaque = opaque;
+               item->state = state;
+
+               lws_dll2_add_head(&item->list, &pt->attach_owner);
+
+               lws_cancel_service(context);
+
+               return 0;
+       }
+
+       *get = NULL;
+#if defined(LWS_WITH_SYS_STATE)
+       if (!pt->attach_owner.count)
+               return 0;
+
+       /*
+        * If any, return the first guy whose state requirement matches
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, d,
+                             lws_dll2_get_head(&pt->attach_owner)) {
+               item = lws_container_of(d, lws_attach_item_t, list);
+
+               if (pt->context->mgr_system.state >= (int)item->state) {
+                       *get = item;
+                       lws_dll2_remove(d);
+
+                       /*
+                        * We detached it, but the caller now has the
+                        * responsibility to lws_free() *get.
+                        */
+
+                       return 0;
+               }
+       } lws_end_foreach_dll(d);
+#endif
+
+       /* nobody ready to go... leave *get as NULL and return cleanly */
+
+       return 0;
+}
+
+int
+lws_system_do_attach(struct lws_context_per_thread *pt)
+{
+       /*
+        * If nothing to do, we just return immediately
+        */
+
+       while (pt->attach_owner.count) {
+
+               struct lws_attach_item *item;
+
+               /*
+                * If anybody used the attach apis, there must be an
+                * implementation of the (*attach) lws_system op function
+                */
+
+               assert(pt->context->system_ops->attach);
+               if (!pt->context->system_ops->attach) {
+                       lwsl_err("%s: define (*attach)\n", __func__);
+                       return 1;
+               }
+
+               /*
+                * System locking is applied only around this next call, while
+                * we detach and get a pointer to the tail attach item.  We
+                * become responsible to free what we have detached.
+                */
+
+               if (pt->context->system_ops->attach(pt->context, pt->tid, NULL,
+                                                   0, NULL, &item)) {
+                       lwsl_err("%s: attach problem\n", __func__);
+                       return 1;
+               }
+
+               if (!item)
+                       /* there's nothing more to do at the moment */
+                       return 0;
+
+               /*
+                * Do the callback from the lws event loop thread
+                */
+
+               item->cb(pt->context, pt->tid, item->opaque);
+
+               /* it's done, destroy the item */
+
+               lws_free(item);
+       }
+
+       return 0;
+}
+
+#endif
diff --git a/lib/tls/CMakeLists.txt b/lib/tls/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fd3c27f
--- /dev/null
@@ -0,0 +1,554 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+#
+# This converts everything about the tls support into
+#
+# - entries on SOURCES (modifications set back in PARENT_SCOPE)
+# - entries on LIB_LIST (modifications set back in PARENT_SCOPE)
+# - include_directories()
+# - Api build-time discovery results set in PARENT_SCOPE
+#
+# Everything else is handled privately here.
+
+include_directories(.)
+
+# Allow the user to use the old CyaSSL options/library in stead of wolfSSL
+if (LWS_WITH_CYASSL AND LWS_WITH_WOLFSSL)
+       message(FATAL_ERROR "LWS_WITH_CYASSL and LWS_WITH_WOLFSSL are mutually exclusive!")
+endif()
+
+if (LWS_WITH_CYASSL)
+       # Copy CyaSSL options to the wolfSSL options
+       set(LWS_WITH_WOLFSSL ${LWS_WITH_CYASSL} CACHE BOOL "Use wolfSSL/CyaSSL instead of OpenSSL" FORCE PARENT_SCOPE)
+       set(LWS_WOLFSSL_LIBRARIES ${LWS_CYASSL_LIBRARIES} CACHE PATH "Path to wolfSSL/CyaSSL libraries" FORCE PARENT_SCOPE)
+       set(LWS_WOLFSSL_INCLUDE_DIRS ${LWS_CYASSL_INCLUDE_DIRS} CACHE PATH "Path to wolfSSL/CyaSSL header files" FORCE PARENT_SCOPE)
+endif()
+
+set(LWS_OPENSSL_LIBRARIES CACHE PATH "Path to the OpenSSL library" )
+set(LWS_OPENSSL_INCLUDE_DIRS CACHE PATH "Path to the OpenSSL include directory" )
+set(LWS_WOLFSSL_LIBRARIES CACHE PATH "Path to the wolfSSL library" )
+set(LWS_WOLFSSL_INCLUDE_DIRS CACHE PATH "Path to the wolfSSL include directory" )
+
+
+if (LWS_WITH_BORINGSSL)
+       # boringssl deprecated EVP_PKEY
+       set (LWS_WITH_GENHASH OFF PARENT_SCOPE)
+endif()
+
+if (LWS_WITH_SSL AND NOT LWS_WITH_WOLFSSL AND NOT LWS_WITH_MBEDTLS)
+       if ("${LWS_OPENSSL_LIBRARIES}" STREQUAL "" OR "${LWS_OPENSSL_INCLUDE_DIRS}" STREQUAL "")
+       else()
+               if (NOT LWS_PLAT_FREERTOS)
+                       set(OPENSSL_LIBRARIES ${LWS_OPENSSL_LIBRARIES})
+               endif()
+               set(OPENSSL_INCLUDE_DIRS ${LWS_OPENSSL_INCLUDE_DIRS})
+               set(OPENSSL_FOUND 1)
+       endif()
+endif()
+
+if (LWS_WITH_SSL AND LWS_WITH_WOLFSSL)
+       if ("${LWS_WOLFSSL_LIBRARIES}" STREQUAL "" OR "${LWS_WOLFSSL_INCLUDE_DIRS}" STREQUAL "")
+               if (NOT WOLFSSL_FOUND)
+                       if (LWS_WITH_CYASSL)
+                               message(FATAL_ERROR "You must set LWS_CYASSL_LIBRARIES and LWS_CYASSL_INCLUDE_DIRS when LWS_WITH_CYASSL is turned on.")
+                       else()
+                               message(FATAL_ERROR "You must set LWS_WOLFSSL_LIBRARIES and LWS_WOLFSSL_INCLUDE_DIRS when LWS_WITH_WOLFSSL is turned on.")
+                       endif()
+               endif()
+       else()
+               set(WOLFSSL_LIBRARIES ${LWS_WOLFSSL_LIBRARIES})
+               set(WOLFSSL_INCLUDE_DIRS ${LWS_WOLFSSL_INCLUDE_DIRS})
+               set(WOLFSSL_FOUND 1)
+       endif()
+       set(USE_WOLFSSL 1)
+       set(USE_WOLFSSL 1 PARENT_SCOPE)
+       set(LWS_WITH_TLS 1 PARENT_SCOPE)
+       if (LWS_WITH_CYASSL)
+               set(USE_OLD_CYASSL 1)
+       endif()
+endif()
+
+if (LWS_SSL_CLIENT_USE_OS_CA_CERTS)
+       set(LWS_SSL_CLIENT_USE_OS_CA_CERTS 1 PARENT_SCOPE)
+endif()
+
+if (LWS_WITH_MBEDTLS)
+       add_subdirectory(mbedtls)
+       include_directories(${_CMAKE_INC_LIST})
+endif()
+
+# The base dir where the test-apps look for the SSL certs.
+set(LWS_OPENSSL_CLIENT_CERTS ../share CACHE PATH "Server SSL certificate directory")
+if (WIN32)
+       set(LWS_OPENSSL_CLIENT_CERTS . CACHE PATH "Client SSL certificate directory" PARENT_SCOPE)
+else()
+       set(LWS_OPENSSL_CLIENT_CERTS /etc/pki/tls/certs/ CACHE PATH "Client SSL certificate directory")
+endif()
+
+if (LWS_WITH_SSL)
+       list(APPEND SOURCES
+               tls/tls.c)
+       if (LWS_WITH_NETWORK)
+               list(APPEND SOURCES
+                       tls/tls-network.c)
+       endif()
+       if (LWS_WITH_TLS_SESSIONS)
+               list(APPEND SOURCES
+                       tls/tls-sessions.c)
+       endif()
+       if (LWS_WITH_TLS_JIT_TRUST)
+               list(APPEND SOURCES
+                       tls/tls-jit-trust.c)
+       endif()
+       
+       if (LWS_WITH_MBEDTLS)
+               list(APPEND SOURCES
+                       tls/mbedtls/mbedtls-tls.c
+                       tls/mbedtls/mbedtls-extensions.c
+                       tls/mbedtls/mbedtls-x509.c)
+               if (LWS_WITH_NETWORK)
+                       list(APPEND SOURCES
+                               tls/mbedtls/mbedtls-ssl.c)
+               endif()
+               if (LWS_WITH_TLS_JIT_TRUST)
+                       list(APPEND SOURCES
+                               tls/mbedtls/mbedtls-extensions.c)
+               endif()
+               if (LWS_WITH_TLS_SESSIONS)
+                       list(APPEND SOURCES
+                               tls/mbedtls/mbedtls-session.c)
+               endif()
+               if (LWS_WITH_GENCRYPTO)
+                       list(APPEND SOURCES
+                               tls/mbedtls/lws-genhash.c
+                               tls/mbedtls/lws-genrsa.c
+                               tls/mbedtls/lws-genaes.c
+                               tls/lws-genec-common.c
+                               tls/mbedtls/lws-genec.c
+                               tls/mbedtls/lws-gencrypto.c)
+               endif()
+       else()
+               list(APPEND SOURCES
+                       tls/openssl/openssl-tls.c
+                       tls/openssl/openssl-x509.c)
+               if (LWS_WITH_NETWORK)
+                       list(APPEND SOURCES
+                               tls/openssl/openssl-ssl.c)
+               endif()
+               if (LWS_WITH_TLS_SESSIONS)
+                       list(APPEND SOURCES
+                               tls/openssl/openssl-session.c)
+               endif()
+               if (LWS_WITH_GENCRYPTO)
+                       list(APPEND SOURCES
+                               tls/openssl/lws-genhash.c
+                               tls/openssl/lws-genrsa.c
+                               tls/openssl/lws-genaes.c
+                               tls/lws-genec-common.c
+                               tls/openssl/lws-genec.c
+                               tls/openssl/lws-gencrypto.c)
+               endif()
+       endif()
+               
+       if (NOT LWS_WITHOUT_SERVER)
+               list(APPEND SOURCES
+                       tls/tls-server.c)
+               if (LWS_WITH_MBEDTLS)
+                       list(APPEND SOURCES
+                               tls/mbedtls/mbedtls-server.c)
+               else()
+                       list(APPEND SOURCES
+                               tls/openssl/openssl-server.c)
+               endif()
+       endif()
+       if (NOT LWS_WITHOUT_CLIENT)
+               list(APPEND SOURCES
+                       tls/tls-client.c)
+               if (LWS_WITH_MBEDTLS)
+                       list(APPEND SOURCES
+                               tls/mbedtls/mbedtls-client.c)
+               else()
+                       list(APPEND SOURCES
+                               tls/openssl/openssl-client.c)
+               endif()
+               
+       endif()
+endif()
+
+set(SOURCES ${SOURCES} PARENT_SCOPE)
+
+#
+# OpenSSL
+#
+if (LWS_WITH_SSL)
+       message("Compiling with SSL support")
+       set(chose_ssl 0)
+       if (LWS_WITH_WOLFSSL)
+               # Use wolfSSL as OpenSSL replacement.
+               # TODO: Add a find_package command for this also.
+               message("wolfSSL include dir: ${WOLFSSL_INCLUDE_DIRS}")
+               message("wolfSSL libraries: ${WOLFSSL_LIBRARIES}")
+
+               # Additional to the root directory we need to include
+               # the wolfssl/ subdirectory which contains the OpenSSL
+               # compatibility layer headers.
+
+               if (LWS_WITH_CYASSL)
+                       foreach(inc ${WOLFSSL_INCLUDE_DIRS})
+                               set(OPENSSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIRS} ${inc} ${inc}/cyassl)
+                               set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} "${inc}" "${inc}/cyassl")
+                               set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} PARENT_SCOPE)
+                       endforeach()
+               else()
+                       foreach(inc ${WOLFSSL_INCLUDE_DIRS})
+                               set(OPENSSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIRS} ${inc} ${inc}/wolfssl)
+                               set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} "${inc}" "${inc}/wolfssl")
+                               set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} PARENT_SCOPE)
+                       endforeach()
+               endif()
+               set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${OPENSSL_INCLUDE_DIRS})
+               set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} PARENT_SCOPE)
+               set(OPENSSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIRS} PARENT_SCOPE)
+               set(VARIA wolfSSL_)
+
+               list(INSERT LIB_LIST 0 "${WOLFSSL_LIBRARIES}")
+               message("LIB_LIST ${LIB_LIST}")
+               set(chose_ssl 1)
+       endif()
+
+       if (LWS_WITH_MBEDTLS AND DEFINED MBEDTLS_INCLUDE_DIRS AND DEFINED MBEDTLS_LIBRARIES)
+               message("MBEDTLS include dir: ${MBEDTLS_INCLUDE_DIRS}")
+               message("MBEDTLS libraries: ${MBEDTLS_LIBRARIES}")
+
+               foreach(inc ${MBEDTLS_INCLUDE_DIRS})
+                               set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} "${inc}" "${inc}/mbedtls")
+                               set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} PARENT_SCOPE)
+               endforeach()
+
+               list(INSERT LIB_LIST 0 "${MBEDTLS_LIBRARIES}")
+       endif()
+       
+       if (LWS_WITH_MBEDTLS)
+               set(chose_ssl 1)
+       endif()
+
+       if (NOT chose_ssl)
+               if (OPENSSL_FOUND AND "${OPENSSL_INCLUDE_DIRS}" STREQUAL "")
+                       set(OPENSSL_INCLUDE_DIRS "${OPENSSL_INCLUDE_DIR}")
+               endif()
+
+               if (NOT OPENSSL_FOUND AND NOT LWS_WITH_BORINGSSL)
+                       # TODO: Add support for STATIC also.
+                       if (NOT LWS_PLAT_FREERTOS)
+                               find_package(PkgConfig QUIET)
+                               pkg_check_modules(PC_OPENSSL openssl QUIET)
+                               find_package(OpenSSL REQUIRED)
+                               list(APPEND OPENSSL_LIBRARIES ${PC_OPENSSL_LIBRARIES})
+                               set(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} PARENT_SCOPE)
+                       endif()
+                       set(OPENSSL_INCLUDE_DIRS "${OPENSSL_INCLUDE_DIR}")
+               endif()
+
+               message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIRS}")
+               if (NOT LWS_PLAT_FREERTOS)
+                       message("OpenSSL libraries: ${OPENSSL_LIBRARIES}")
+               endif()
+
+               if (OPENSSL_INCLUDE_DIRS)
+                       set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} "${OPENSSL_INCLUDE_DIRS}")
+                       set(LWS_PUBLIC_INCLUDES ${LWS_PUBLIC_INCLUDES} PARENT_SCOPE)
+               endif()
+               if (NOT LWS_PLAT_FREERTOS)
+                       list(INSERT LIB_LIST 0 ${OPENSSL_LIBRARIES})
+               endif()
+
+               if (NOT LWS_WITH_MBEDTLS)
+                       # older (0.98) Openssl lacks this
+                       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${OPENSSL_INCLUDE_DIRS} PARENT_SCOPE)
+                       check_include_file(openssl/ecdh.h LWS_HAVE_OPENSSL_ECDH_H)
+
+                       if (LWS_SSL_SERVER_WITH_ECDH_CERT AND NOT LWS_HAVE_OPENSSL_ECDH_H)
+                               message(FATAL_ERROR "Missing openssl/ecdh.h, so cannot use LWS_SSL_SERVER_WITH_ECDH_CERT")
+                       endif()
+               else()
+                       unset(LWS_HAVE_OPENSSL_ECDH_H PARENT_SCOPE)
+               endif(NOT LWS_WITH_MBEDTLS)
+       endif()
+
+endif(LWS_WITH_SSL)
+
+if (DEFINED OPENSSL_INCLUDE_DIRS)
+       set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
+endif()
+if (DEFINED LIB_LIST)
+       set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST})
+endif()
+if (UNIX AND NOT (${CMAKE_SYSTEM_NAME} MATCHES "QNX"))
+       set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${CMAKE_DL_LIBS})
+endif()
+if ((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT (${CMAKE_SYSTEM_NAME} MATCHES "QNX"))
+       set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} pthread)
+endif()
+
+if (NOT VARIA)
+       set(VARIA "")
+endif()
+
+CHECK_FUNCTION_EXISTS(${VARIA}SSL_CTX_set1_param LWS_HAVE_SSL_CTX_set1_param PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}SSL_set_info_callback LWS_HAVE_SSL_SET_INFO_CALLBACK PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}X509_VERIFY_PARAM_set1_host LWS_HAVE_X509_VERIFY_PARAM_set1_host PARENT_SCOPE)
+CHECK_SYMBOL_EXISTS(${VARIA}X509_VERIFY_PARAM_set1_host LWS_HAVE_X509_VERIFY_PARAM_set1_host_sym PARENT_SCOPE)
+if (LWS_HAVE_X509_VERIFY_PARAM_set1_host_sym)
+       set(LWS_HAVE_X509_VERIFY_PARAM_set1_host 1 PARENT_SCOPE)
+endif()
+
+CHECK_FUNCTION_EXISTS(${VARIA}RSA_set0_key LWS_HAVE_RSA_SET0_KEY PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}X509_get_key_usage LWS_HAVE_X509_get_key_usage PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}SSL_CTX_EVP_PKEY_new_raw_private_key LWS_HAVE_SSL_CTX_EVP_PKEY_new_raw_private_key PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}SSL_CTX_get0_certificate LWS_HAVE_SSL_CTX_get0_certificate PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}SSL_get0_alpn_selected LWS_HAVE_SSL_get0_alpn_selected PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}SSL_set_alpn_protos LWS_HAVE_SSL_set_alpn_protos PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_128_cfb8 LWS_HAVE_EVP_aes_128_cfb8 PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_128_cfb128 LWS_HAVE_EVP_aes_128_cfb128 PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_192_cfb8 LWS_HAVE_EVP_aes_192_cfb8 PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_192_cfb128 LWS_HAVE_EVP_aes_192_cfb128 PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_256_cfb8 LWS_HAVE_EVP_aes_256_cfb8 PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_256_cfb128 LWS_HAVE_EVP_aes_256_cfb128 PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_128_xts LWS_HAVE_EVP_aes_128_xts PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_128_ofb LWS_HAVE_EVP_aes_128_ofb PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_128_ecb LWS_HAVE_EVP_aes_128_ecb PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_128_ctr LWS_HAVE_EVP_aes_128_ctr PARENT_SCOPE)
+
+
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_128_xts LWS_HAVE_EVP_aes_128_xts PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}RSA_verify_pss_mgf1 LWS_HAVE_RSA_verify_pss_mgf1 PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}HMAC_CTX_new LWS_HAVE_HMAC_CTX_new PARENT_SCOPE)
+CHECK_SYMBOL_EXISTS(${VARIA}SSL_CTX_set_ciphersuites LWS_HAVE_SSL_CTX_set_ciphersuites PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_PKEY_new_raw_private_key LWS_HAVE_EVP_PKEY_new_raw_private_key PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}SSL_SESSION_set_time LWS_HAVE_SSL_SESSION_set_time PARENT_SCOPE)
+CHECK_SYMBOL_EXISTS(${VARIA}SSL_SESSION_up_ref LWS_HAVE_SSL_SESSION_up_ref PARENT_SCOPE)
+
+
+# deprecated in openssl v3
+CHECK_FUNCTION_EXISTS(${VARIA}EC_KEY_new_by_curve_name LWS_HAVE_EC_KEY_new_by_curve_name PARENT_SCOPE)
+
+if (LWS_WITH_SSL AND NOT LWS_WITH_MBEDTLS)
+       # we don't want to confuse what's in or out of the wrapper with
+       # what's in an openssl also installed on the build host
+CHECK_C_SOURCE_COMPILES("#include <openssl/ssl.h>\nint main(void) { STACK_OF(X509) *c = NULL; SSL_CTX *ctx = NULL; return (int)SSL_CTX_get_extra_chain_certs_only(ctx, &c); }\n" LWS_HAVE_SSL_EXTRA_CHAIN_CERTS)
+CHECK_C_SOURCE_COMPILES("#include <openssl/ssl.h>\nint main(void) { EVP_MD_CTX *md_ctx = NULL; EVP_MD_CTX_free(md_ctx); return 0; }\n" LWS_HAVE_EVP_MD_CTX_free)
+CHECK_C_SOURCE_COMPILES("#include <openssl/ssl.h>\nint main(void) { OPENSSL_STACK *x = NULL; return !x; } \n" LWS_HAVE_OPENSSL_STACK)
+set(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS ${LWS_HAVE_SSL_EXTRA_CHAIN_CERTS} PARENT_SCOPE)
+set(LWS_HAVE_EVP_MD_CTX_free ${LWS_HAVE_EVP_MD_CTX_free} PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}ECDSA_SIG_set0 LWS_HAVE_ECDSA_SIG_set0 PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}BN_bn2binpad LWS_HAVE_BN_bn2binpad PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EVP_aes_128_wrap LWS_HAVE_EVP_aes_128_wrap PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}EC_POINT_get_affine_coordinates LWS_HAVE_EC_POINT_get_affine_coordinates PARENT_SCOPE)
+CHECK_SYMBOL_EXISTS(${VARIA}SSL_CTX_load_verify_file LWS_HAVE_SSL_CTX_load_verify_file PARENT_SCOPE)
+CHECK_SYMBOL_EXISTS(${VARIA}SSL_CTX_load_verify_dir LWS_HAVE_SSL_CTX_load_verify_dir PARENT_SCOPE)
+endif()
+
+if (LWS_WITH_MBEDTLS)
+       set(LWS_HAVE_TLS_CLIENT_METHOD 1 PARENT_SCOPE)
+       if (NOT LWS_PLAT_FREERTOS)
+               # not supported in esp-idf openssl wrapper yet, but is in our version
+               set(LWS_HAVE_X509_VERIFY_PARAM_set1_host 1 PARENT_SCOPE)
+       endif()
+       set(CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY})
+
+       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${MBEDTLS_INCLUDE_DIRS})
+       CHECK_C_SOURCE_COMPILES("#include <mbedtls/x509_crt.h>\nint main(void) { struct mbedtls_x509_crt c; c.authority_key_id.keyIdentifier.tag = MBEDTLS_ASN1_OCTET_STRING; return c.authority_key_id.keyIdentifier.tag; }\n" LWS_HAVE_MBEDTLS_AUTH_KEY_ID)
+       CHECK_C_SOURCE_COMPILES("#include <mbedtls/ssl.h>\nint main(void) { void *v = (void *)mbedtls_ssl_set_verify; return !!v; }\n" LWS_HAVE_mbedtls_ssl_set_verify)
+       CHECK_FUNCTION_EXISTS(mbedtls_ssl_conf_alpn_protocols LWS_HAVE_mbedtls_ssl_conf_alpn_protocols PARENT_SCOPE)
+       CHECK_FUNCTION_EXISTS(mbedtls_ssl_get_alpn_protocol LWS_HAVE_mbedtls_ssl_get_alpn_protocol PARENT_SCOPE)
+       CHECK_FUNCTION_EXISTS(mbedtls_ssl_conf_sni LWS_HAVE_mbedtls_ssl_conf_sni PARENT_SCOPE)
+       CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_ca_chain LWS_HAVE_mbedtls_ssl_set_hs_ca_chain PARENT_SCOPE)
+       CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_own_cert LWS_HAVE_mbedtls_ssl_set_hs_own_cert PARENT_SCOPE)
+       CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_authmode LWS_HAVE_mbedtls_ssl_set_hs_authmode PARENT_SCOPE)
+       CHECK_FUNCTION_EXISTS(mbedtls_net_init LWS_HAVE_mbedtls_net_init PARENT_SCOPE)
+       CHECK_FUNCTION_EXISTS(mbedtls_x509_crt_parse_file LWS_HAVE_mbedtls_x509_crt_parse_file PARENT_SCOPE) # some embedded may lack filesystem
+       CHECK_FUNCTION_EXISTS(mbedtls_md_setup LWS_HAVE_mbedtls_md_setup PARENT_SCOPE) # not on xenial 2.2
+       CHECK_FUNCTION_EXISTS(mbedtls_rsa_complete LWS_HAVE_mbedtls_rsa_complete PARENT_SCOPE) # not on xenial 2.2
+       CHECK_FUNCTION_EXISTS(mbedtls_internal_aes_encrypt LWS_HAVE_mbedtls_internal_aes_encrypt PARENT_SCOPE) # not on xenial 2.2
+else()
+CHECK_FUNCTION_EXISTS(${VARIA}TLS_client_method LWS_HAVE_TLS_CLIENT_METHOD PARENT_SCOPE)
+CHECK_FUNCTION_EXISTS(${VARIA}TLSv1_2_client_method LWS_HAVE_TLSV1_2_CLIENT_METHOD PARENT_SCOPE)
+endif()
+
+# Generate self-signed SSL certs for the test-server.
+
+if (LWS_WITH_SSL AND NOT LWS_WITH_WOLFSSL)
+       message("Searching for OpenSSL executable and dlls")
+       find_package(OpenSSLbins)
+       if (DEFINED OPENSSL_EXECUTABLE)
+               message("OpenSSL executable: ${OPENSSL_EXECUTABLE}")
+               
+               if (OPENSSL_EXECUTABLE MATCHES "^$")
+                       set(OPENSSL_EXECUTABLE openssl)
+               endif()
+       endif()
+       if (NOT DEFINED OPENSSL_EXECUTABLE)
+               set(OPENSSL_EXECUTABLE openssl)
+       endif()
+
+endif()
+
+set(GENCERTS 0)
+
+if (LWS_WITH_SSL AND OPENSSL_EXECUTABLE AND NOT LWS_WITHOUT_TEST_SERVER AND NOT LWS_WITHOUT_SERVER AND NOT LWS_WITHOUT_TESTAPPS)
+       set(GENCERTS 1)
+endif()
+if (LWS_PLAT_FREERTOS AND LWS_WITH_SSL)
+       set(GENCERTS 1)
+endif()
+message(" GENCERTS = ${GENCERTS}")
+if (GENCERTS)
+       message("Generating SSL Certificates for the test-server...")
+
+       set(TEST_SERVER_SSL_KEY "${PROJECT_BINARY_DIR}/libwebsockets-test-server.key.pem")
+       set(TEST_SERVER_SSL_CERT "${PROJECT_BINARY_DIR}/libwebsockets-test-server.pem")
+
+       if (WIN32)
+               if (MINGW)
+                       message("cmd = \"${OPENSSL_EXECUTABLE}\" req -new -newkey rsa:2048 -days 10000 -nodes -x509 -subj \"/C=GB/ST=Erewhon/L=All around/O=libwebsockets-test/CN=localhost\" -keyout \"${TEST_SERVER_SSL_KEY}\" -out \"${TEST_SERVER_SSL_CERT}\"")
+                       execute_process(
+                               COMMAND "${OPENSSL_EXECUTABLE}" req -new -newkey rsa:2048 -days 10000 -nodes -x509 -subj "/C=GB/ST=Erewhon/L=All around/O=libwebsockets-test/CN=localhost" -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
+                               RESULT_VARIABLE OPENSSL_RETURN_CODE)
+               else()
+                       file(WRITE "${PROJECT_BINARY_DIR}/openssl_input.txt"
+                               "GB\n"
+                               "Erewhon\n"
+                               "All around\n"
+                               "libwebsockets-test\n"
+                               "localhost\n"
+                               "none@invalid.org\n\n"
+                               )
+
+                       # The "type" command is a bit picky with paths.
+                       file(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/openssl_input.txt" OPENSSL_INPUT_WIN_PATH)
+                       message("OPENSSL_INPUT_WIN_PATH = ${OPENSSL_INPUT_WIN_PATH}")
+                       message("cmd = \"${OPENSSL_EXECUTABLE}\" req -new -newkey rsa:2048 -days 10000 -nodes -x509 -keyout \"${TEST_SERVER_SSL_KEY}\" -out \"${TEST_SERVER_SSL_CERT}\"")
+
+                       if(OPENSSL_CONFIG_FILE)
+                               execute_process(
+                                       COMMAND cmd /c type "${OPENSSL_INPUT_WIN_PATH}"
+                                       COMMAND "${OPENSSL_EXECUTABLE}" req -config ${OPENSSL_CONFIG_FILE} -new -newkey rsa:2048 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
+                                       RESULT_VARIABLE OPENSSL_RETURN_CODE
+                                       OUTPUT_QUIET ERROR_QUIET)
+                       else()
+                               execute_process(
+                                       COMMAND cmd /c type "${OPENSSL_INPUT_WIN_PATH}"
+                                       COMMAND "${OPENSSL_EXECUTABLE}" req -new -newkey rsa:2048 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
+                                       RESULT_VARIABLE OPENSSL_RETURN_CODE
+                                       OUTPUT_QUIET ERROR_QUIET)
+                       endif()
+
+                       message("\n")
+               endif()
+
+               if (OPENSSL_RETURN_CODE)
+                       message(WARNING "!!! Failed to generate SSL certificate for Test Server using cmd.exe !!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")
+               else()
+                       message("SUCCSESFULLY generated SSL certificate")
+               endif()
+       else()
+               if (CMAKE_HOST_SYSTEM_NAME MATCHES "NetBSD")
+                execute_process(
+                        COMMAND "${OPENSSL_EXECUTABLE}"
+                                req -new -newkey rsa:2048 -days 10000 -nodes -x509 -subj "/O=lws/CN=localhost" -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
+                        RESULT_VARIABLE OPENSSL_RETURN_CODE
+                        #               OUTPUT_QUIET ERROR_QUIET
+                        )
+
+               else()
+       
+               # Unix.
+               execute_process(
+                       COMMAND printf "GB\\nErewhon\\nAll around\\nlibwebsockets-test\\n\\nlocalhost\\nnone@invalid.org\\n"
+                       COMMAND "${OPENSSL_EXECUTABLE}"
+                               req -new -newkey rsa:2048 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
+                       RESULT_VARIABLE OPENSSL_RETURN_CODE
+                       #               OUTPUT_QUIET ERROR_QUIET
+                       )
+                       
+               endif()
+
+               if (OPENSSL_RETURN_CODE)
+                       message(WARNING "!!! Failed to generate SSL certificate for Test Server!!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")
+               else()
+                       message("SUCCESSFULLY generated SSL certificate")
+               endif()
+       endif()
+
+       list(APPEND TEST_SERVER_DATA 
+               "${TEST_SERVER_SSL_KEY}"
+               "${TEST_SERVER_SSL_CERT}")
+endif()
+
+#
+# Copy OpenSSL dlls to the output directory on Windows.
+# (Otherwise we'll get an error when trying to run)
+#
+if (MSVC AND LWS_WITH_SSL AND NOT LWS_WITH_WOLFSSL)
+       if(OPENSSL_BIN_FOUND)
+               message("OpenSSL dlls found:")
+               message("  Libeay: ${LIBEAY_BIN}")
+               message("  SSLeay: ${SSLEAY_BIN}")
+
+               foreach(TARGET_BIN ${TEST_APP_LIST})
+                       add_custom_command(TARGET ${TARGET_BIN}
+                               POST_BUILD
+                               COMMAND "${CMAKE_COMMAND}" -E copy "${LIBEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
+                       add_custom_command(TARGET ${TARGET_BIN}
+                               POST_BUILD
+                               COMMAND "${CMAKE_COMMAND}" -E copy "${SSLEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
+
+                       #
+                       # Win32: if we are using libuv, also need to copy it in the output dir
+                       #
+                       if (MSVC AND LWS_WITH_LIBUV)
+                               STRING(REPLACE ".lib" ".dll" LIBUV_BIN ${LIBUV_LIBRARIES})
+                               add_custom_command(TARGET ${TARGET_BIN}
+                                       POST_BUILD
+                                       COMMAND "${CMAKE_COMMAND}" -E copy "${LIBUV_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
+                       endif()
+               endforeach()
+       endif()
+endif()
+
+if (LWS_WITH_TLS AND (LWS_WITH_JOSE OR LWS_WITH_GENCRYPTO))
+       list(APPEND SOURCES
+               tls/lws-gencrypto-common.c)
+endif()
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+set(LWS_HAVE_MBEDTLS_NET_SOCKETS ${LWS_HAVE_MBEDTLS_NET_SOCKETS} PARENT_SCOPE)
+set(TEST_SERVER_SSL_KEY "${TEST_SERVER_SSL_KEY}" PARENT_SCOPE)
+set(TEST_SERVER_SSL_CERT "${TEST_SERVER_SSL_CERT}" PARENT_SCOPE)
+set(TEST_SERVER_DATA ${TEST_SERVER_DATA} PARENT_SCOPE)
+
index d2c8a0c..7b32872 100644 (file)
@@ -1,24 +1,28 @@
 /*
- * libwebsockets - generic crypto hiding the backend - common parts
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
-#include "core/private.h"
+
+#include "private-lib-core.h"
 
 /*
  * These came from RFC7518 (JSON Web Algorithms) Section 3
@@ -456,7 +460,7 @@ static const struct lws_jose_jwe_alg lws_gencrypto_jwe_alg_map[] = {
        },
 
        /* list terminator */
-       { 0, 0, 0, 0, NULL, NULL }
+       { 0, 0, 0, 0, NULL, NULL, 0, 0, 0 }
 };
 
 /*
@@ -568,7 +572,7 @@ static const struct lws_jose_jwe_alg lws_gencrypto_jwe_enc_map[] = {
        { 0, 0, 0, 0, NULL, NULL, 0, 0, 0 } /* sentinel */
 };
 
-LWS_VISIBLE int
+int
 lws_gencrypto_jws_alg_to_definition(const char *alg,
                                    const struct lws_jose_jwe_alg **jose)
 {
@@ -586,7 +590,7 @@ lws_gencrypto_jws_alg_to_definition(const char *alg,
        return 1;
 }
 
-LWS_VISIBLE int
+int
 lws_gencrypto_jwe_alg_to_definition(const char *alg,
                                    const struct lws_jose_jwe_alg **jose)
 {
@@ -604,7 +608,7 @@ lws_gencrypto_jwe_alg_to_definition(const char *alg,
        return 1;
 }
 
-LWS_VISIBLE int
+int
 lws_gencrypto_jwe_enc_to_definition(const char *enc,
                                    const struct lws_jose_jwe_alg **jose)
 {
@@ -684,3 +688,8 @@ lws_gencrypto_destroy_elements(struct lws_gencrypto_keyelem *el, int m)
                if (el[n].buf)
                        lws_free_set_NULL(el[n].buf);
 }
+
+size_t lws_gencrypto_padded_length(size_t pad_block_size, size_t len)
+{
+       return (len / pad_block_size + 1) * pad_block_size;
+}
index 0df1c8b..0ea3fb0 100644 (file)
@@ -1,27 +1,30 @@
-/*
- * libwebsockets - generic EC api hiding the backend - common parts
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws_genec provides an EC abstraction api in lws that works the
  *  same whether you are using openssl or mbedtls crypto functions underneath.
  */
-#include "core/private.h"
+#include "private-lib-core.h"
 
 const struct lws_ec_curves *
 lws_genec_curve(const struct lws_ec_curves *table, const char *name)
@@ -48,7 +51,8 @@ lws_genec_confirm_curve_allowed_by_tls_id(const char *allowed, int id,
 {
        struct lws_tokenize ts;
        lws_tokenize_elem e;
-       int n, len;
+       size_t len;
+       int n;
 
        lws_tokenize_init(&ts, allowed, LWS_TOKENIZE_F_COMMA_SEP_LIST |
                                       LWS_TOKENIZE_F_MINUS_NONTERM);
@@ -66,7 +70,7 @@ lws_genec_confirm_curve_allowed_by_tls_id(const char *allowed, int id,
                                lwsl_info("match curve %s\n",
                                          lws_ec_curves[n].name);
                                len = strlen(lws_ec_curves[n].name);
-                               jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].len = len;
+                               jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].len = (uint32_t)len;
                                jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf =
                                                lws_malloc(len + 1, "cert crv");
                                if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) {
@@ -95,7 +99,7 @@ lws_genec_confirm_curve_allowed_by_tls_id(const char *allowed, int id,
        return -1;
 }
 
-LWS_VISIBLE void
+void
 lws_genec_destroy_elements(struct lws_gencrypto_keyelem *el)
 {
        int n;
@@ -107,7 +111,7 @@ lws_genec_destroy_elements(struct lws_gencrypto_keyelem *el)
 
 static const char *enames[] = { "crv", "x", "d", "y" };
 
-LWS_VISIBLE int
+int
 lws_genec_dump(struct lws_gencrypto_keyelem *el)
 {
        int n;
diff --git a/lib/tls/mbedtls/CMakeLists.txt b/lib/tls/mbedtls/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e341517
--- /dev/null
@@ -0,0 +1,133 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# The strategy is to only export to PARENT_SCOPE
+#
+#  - changes to LIB_LIST
+#  - changes to SOURCES
+#  - includes via include_directories
+#
+# and keep everything else private
+
+include_directories(wrapper/include wrapper/include/internal)
+
+       set(LWS_WITH_SSL ON)
+       
+       include_directories(wrapper/include)
+       include_directories(wrapper/include/platform)
+       include_directories(wrapper/include/internal)
+       include_directories(wrapper/include/openssl)
+       
+       if (LWS_WITH_NETWORK)
+               list(APPEND HDR_PRIVATE
+                       tls/mbedtls/wrapper/include/internal/ssl3.h
+                       tls/mbedtls/wrapper/include/internal/ssl_cert.h
+                       tls/mbedtls/wrapper/include/internal/ssl_code.h
+                       tls/mbedtls/wrapper/include/internal/ssl_dbg.h
+                       tls/mbedtls/wrapper/include/internal/ssl_lib.h
+                       tls/mbedtls/wrapper/include/internal/ssl_methods.h
+                       tls/mbedtls/wrapper/include/internal/ssl_pkey.h
+                       tls/mbedtls/wrapper/include/internal/ssl_stack.h
+                       tls/mbedtls/wrapper/include/internal/ssl_types.h
+                       tls/mbedtls/wrapper/include/internal/ssl_x509.h
+                       tls/mbedtls/wrapper/include/internal/tls1.h
+                       tls/mbedtls/wrapper/include/internal/x509_vfy.h)
+       
+               list(APPEND HDR_PRIVATE
+                       tls/mbedtls/wrapper/include/openssl/ssl.h)
+       
+               list(APPEND HDR_PRIVATE
+                       tls/mbedtls/wrapper/include/platform/ssl_pm.h
+                       tls/mbedtls/wrapper/include/platform/ssl_port.h)
+       
+               list(APPEND SOURCES
+                       tls/mbedtls/wrapper/library/ssl_cert.c
+                       tls/mbedtls/wrapper/library/ssl_lib.c
+                       tls/mbedtls/wrapper/library/ssl_methods.c
+                       tls/mbedtls/wrapper/library/ssl_pkey.c
+                       tls/mbedtls/wrapper/library/ssl_stack.c
+                       tls/mbedtls/wrapper/library/ssl_x509.c)
+       
+               list(APPEND SOURCES
+                       tls/mbedtls/wrapper/platform/ssl_pm.c
+                       tls/mbedtls/wrapper/platform/ssl_port.c)
+       endif()
+
+       set(_WANT_MBT 0)
+       if (NOT LWS_PLAT_FREERTOS)
+               if (NOT DEFINED LWS_MBEDTLS_LIBRARIES)
+                       set(_WANT_MBT 1)
+               endif()
+               if (NOT DEFINED LWS_MBEDTLS_INCLUDE_DIRS)
+                       set(_WANT_MBT 1)
+               endif()
+       endif()
+
+       if (_WANT_MBT)
+
+               find_path(LWS_MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h)
+
+               find_library(MBEDTLS_LIBRARY mbedtls)
+               find_library(MBEDX509_LIBRARY mbedx509)
+               find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
+
+               set(LWS_MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
+
+               include(FindPackageHandleStandardArgs)
+               find_package_handle_standard_args(MBEDTLS DEFAULT_MSG
+                       LWS_MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+
+               mark_as_advanced(LWS_MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+
+               if ("${LWS_MBEDTLS_LIBRARIES}" STREQUAL "" OR "${LWS_MBEDTLS_INCLUDE_DIRS}" STREQUAL "")
+                       message(FATAL_ERROR "You must set LWS_MBEDTLS_LIBRARIES and LWS_MBEDTLS_INCLUDE_DIRS when LWS_WITH_MBEDTLS is turned on.")
+               endif()
+       endif()
+       if (LWS_MBEDTLS_LIBRARIES)
+               set(MBEDTLS_LIBRARIES ${LWS_MBEDTLS_LIBRARIES})
+               set(MBEDTLS_LIBRARIES ${LWS_MBEDTLS_LIBRARIES} PARENT_SCOPE)
+       endif()
+       if (LWS_MBEDTLS_INCLUDE_DIRS)
+               set(MBEDTLS_INCLUDE_DIRS ${LWS_MBEDTLS_INCLUDE_DIRS})
+               set(MBEDTLS_INCLUDE_DIRS ${LWS_MBEDTLS_INCLUDE_DIRS} PARENT_SCOPE)
+       endif()
+       set(USE_MBEDTLS 1 PARENT_SCOPE)
+       if (DEFINED MBEDTLS_INCLUDE_DIRS)
+               include_directories(${MBEDTLS_INCLUDE_DIRS})
+               set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${MBEDTLS_INCLUDE_DIRS})
+       endif()
+
+       if (DEFINED MBEDTLS_LIBRARIES)
+               list(APPEND LIB_LIST ${MBEDTLS_LIBRARIES})
+       endif()
+
+# old mbedtls has everything in mbedtls/net.h
+
+CHECK_C_SOURCE_COMPILES("#include <mbedtls/net_sockets.h>\nint main(void) { return 0;}\n" LWS_HAVE_MBEDTLS_NET_SOCKETS)
+
+#
+# Keep explicit parent scope exports at end
+#
+
+exports_to_parent_scope()
+set(LWS_HAVE_MBEDTLS_NET_SOCKETS ${LWS_HAVE_MBEDTLS_NET_SOCKETS} PARENT_SCOPE)
index 0e4da81..f6a4ebd 100644 (file)
@@ -1,32 +1,51 @@
-/*
- * libwebsockets - generic AES api hiding the backend
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws_genaes provides an abstraction api for AES in lws that works the
  *  same whether you are using openssl or mbedtls hash functions underneath.
  */
-#include "core/private.h"
-#include "../../jose/private.h"
+#include "private-lib-core.h"
+#if defined(LWS_WITH_JOSE)
+#include "private-lib-jose.h"
+#endif
 
 static int operation_map[] = { MBEDTLS_AES_ENCRYPT, MBEDTLS_AES_DECRYPT };
 
-LWS_VISIBLE int
+static unsigned int
+_write_pkcs7_pad(uint8_t *p, int len)
+{
+       unsigned int n = 0, padlen = LWS_AES_CBC_BLOCKLEN * ((unsigned int)len /
+                                       LWS_AES_CBC_BLOCKLEN + 1) - (unsigned int)len;
+
+       p += len;
+
+       while (n++ < padlen)
+               *p++ = (uint8_t)padlen;
+
+       return padlen;
+}
+
+int
 lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
                  enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el,
                  enum enum_aes_padding padding, void *engine)
@@ -35,8 +54,9 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
 
        ctx->mode = mode;
        ctx->k = el;
-       ctx->op = operation_map[op];
+       ctx->op = (enum enum_aes_operation)operation_map[op];
        ctx->underway = 0;
+       ctx->padding = padding == LWS_GAESP_WITH_PADDING;
 
        switch (ctx->mode) {
        case LWS_GAESM_XTS:
@@ -108,23 +128,33 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen)
 {
-       int n = 0;
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+       size_t last_len = 0;
+       uint8_t last[16];
+#endif
+       int n;
 
        if (ctx->mode == LWS_GAESM_GCM) {
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+               n = mbedtls_gcm_finish(&ctx->u.ctx_gcm, last, sizeof(last),
+                                       &last_len, tag, tlen);
+#else
                n = mbedtls_gcm_finish(&ctx->u.ctx_gcm, tag, tlen);
+#endif
+
                if (n)
                        lwsl_notice("%s: mbedtls_gcm_finish: -0x%x\n",
                                    __func__, -n);
                if (tag && ctx->op == MBEDTLS_AES_DECRYPT && !n) {
-                       if (lws_timingsafe_bcmp(ctx->tag, tag, ctx->taglen)) {
+                       if (lws_timingsafe_bcmp(ctx->tag, tag, (unsigned int)ctx->taglen)) {
                                lwsl_err("%s: lws_genaes_crypt tag "
                                         "mismatch (bad first)\n",
                                                __func__);
                                lwsl_hexdump_notice(tag, tlen);
-                               lwsl_hexdump_notice(ctx->tag, ctx->taglen);
+                               lwsl_hexdump_notice(ctx->tag, (unsigned int)ctx->taglen);
                                n = -1;
                        }
                }
@@ -143,6 +173,7 @@ lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen)
        return 0;
 }
 
+#if defined(LWS_HAVE_mbedtls_internal_aes_encrypt)
 static int
 lws_genaes_rfc3394_wrap(int wrap, int cek_bits, const uint8_t *kek,
                        int kek_bits, const uint8_t *in, uint8_t *out)
@@ -179,8 +210,8 @@ lws_genaes_rfc3394_wrap(int wrap, int cek_bits, const uint8_t *kek,
                 * A[0] = IV = A6A6A6A6A6A6A6A6
                 */
                memset(out, 0xa6, 8);
-               memcpy(out + 8, in, 8 * c64);
-               n = mbedtls_aes_setkey_enc(&ctx, kek, kek_bits);
+               memcpy(out + 8, in, 8 * (unsigned int)c64);
+               n = mbedtls_aes_setkey_enc(&ctx, kek, (unsigned int)kek_bits);
        } else {
                /*
                 * 2.2.2 Key Unwrap
@@ -196,8 +227,8 @@ lws_genaes_rfc3394_wrap(int wrap, int cek_bits, const uint8_t *kek,
                 * Outputs: Plaintext, n 64-bit values {P1, P2, ..., Pn}.
                 */
                memcpy(a, in, 8);
-               memcpy(out, in + 8, 8 * c64);
-               n = mbedtls_aes_setkey_dec(&ctx, kek, kek_bits);
+               memcpy(out, in + 8, 8 * (unsigned int)c64);
+               n = mbedtls_aes_setkey_dec(&ctx, kek, (unsigned int)kek_bits);
        }
 
        if (n < 0) {
@@ -215,7 +246,7 @@ lws_genaes_rfc3394_wrap(int wrap, int cek_bits, const uint8_t *kek,
                                        goto bail;
 
                                memcpy(out, b, 8);
-                               out[7] ^= c64 * n + m;
+                               out[7] ^= (uint8_t)(c64 * n + m);
                                memcpy(r, b + 8, 8);
                                r += 8;
                        }
@@ -229,7 +260,7 @@ lws_genaes_rfc3394_wrap(int wrap, int cek_bits, const uint8_t *kek,
                        uint8_t *r = out + (c64 - 1) * 8;
                        for (m = c64; m >= 1; m--) {
                                memcpy(b, a, 8);
-                               b[7] ^= c64 * n + m;
+                               b[7] ^= (uint8_t)(c64 * n + m);
                                memcpy(b + 8, r, 8);
                                if (mbedtls_internal_aes_decrypt(&ctx, b, b))
                                        goto bail;
@@ -253,8 +284,9 @@ bail:
 
        return ret;
 }
+#endif
 
-LWS_VISIBLE int
+int
 lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len,
                 uint8_t *out, uint8_t *iv_or_nonce_ctr_or_data_unit_16,
                 uint8_t *stream_block_16, size_t *nc_or_iv_off, int taglen)
@@ -264,28 +296,58 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len,
 
        switch (ctx->mode) {
        case LWS_GAESM_KW:
+#if defined(LWS_HAVE_mbedtls_internal_aes_encrypt)
                /* a key of length ctx->k->len is wrapped by a 128-bit KEK */
                n = lws_genaes_rfc3394_wrap(ctx->op == MBEDTLS_AES_ENCRYPT,
-                               ctx->op == MBEDTLS_AES_ENCRYPT ? len * 8 :
-                                               (len - 8) * 8, ctx->k->buf,
-                                               ctx->k->len * 8,
+                               (ctx->op == MBEDTLS_AES_ENCRYPT ? (int)len * 8 :
+                                               ((int)len - 8) * 8), ctx->k->buf,
+                                               (int)ctx->k->len * 8,
                                in, out);
                break;
+#else
+               lwsl_err("%s: your mbedtls is too old\n", __func__);
+               return -1;
+#endif
        case LWS_GAESM_CBC:
                memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
-               n = mbedtls_aes_crypt_cbc(&ctx->u.ctx, ctx->op, len, iv,
-                                         in, out);
+
+               /*
+                * If encrypting, we do the PKCS#7 padding.
+                * During decryption, the caller will need to unpad.
+                */
+               if (ctx->padding && ctx->op == MBEDTLS_AES_ENCRYPT) {
+                       /*
+                        * Since we don't want to burden the caller with
+                        * the over-allocation at the end of the input,
+                        * we have to allocate a temp with space for it
+                        */
+                       uint8_t *padin = (uint8_t *)lws_malloc(
+                               lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN, len),
+                                                               __func__);
+
+                       if (!padin)
+                               return -1;
+
+                       memcpy(padin, in, len);
+                       len += _write_pkcs7_pad((uint8_t *)padin, (int)len);
+                       n = mbedtls_aes_crypt_cbc(&ctx->u.ctx, (int)ctx->op, len, iv,
+                                                 padin, out);
+                       lws_free(padin);
+               } else
+                       n = mbedtls_aes_crypt_cbc(&ctx->u.ctx, (int)ctx->op, len, iv,
+                                      in, out);
+
                break;
 
        case LWS_GAESM_CFB128:
                memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
-               n = mbedtls_aes_crypt_cfb128(&ctx->u.ctx, ctx->op, len,
+               n = mbedtls_aes_crypt_cfb128(&ctx->u.ctx, (int)ctx->op, len,
                                             nc_or_iv_off, iv, in, out);
                break;
 
        case LWS_GAESM_CFB8:
                memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
-               n = mbedtls_aes_crypt_cfb8(&ctx->u.ctx, ctx->op, len, iv,
+               n = mbedtls_aes_crypt_cfb8(&ctx->u.ctx, (int)ctx->op, len, iv,
                                           in, out);
                break;
 
@@ -299,7 +361,7 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len,
                break;
 
        case LWS_GAESM_ECB:
-               n = mbedtls_aes_crypt_ecb(&ctx->u.ctx, ctx->op, in, out);
+               n = mbedtls_aes_crypt_ecb(&ctx->u.ctx, (int)ctx->op, in, out);
                break;
 
        case LWS_GAESM_OFB:
@@ -315,7 +377,7 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len,
        case LWS_GAESM_XTS:
 #if defined(MBEDTLS_CIPHER_MODE_XTS)
                memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16);
-               n = mbedtls_aes_crypt_xts(&ctx->u.ctx_xts, ctx->op, len, iv,
+               n = mbedtls_aes_crypt_xts(&ctx->u.ctx_xts, (int)ctx->op, len, iv,
                                          in, out);
                break;
 #else
@@ -325,7 +387,7 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len,
                if (!ctx->underway) {
                        ctx->underway = 1;
 
-                       memcpy(ctx->tag, stream_block_16, taglen);
+                       memcpy(ctx->tag, stream_block_16, (unsigned int)taglen);
                        ctx->taglen = taglen;
 
                        /*
@@ -336,9 +398,18 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len,
                         * additional data len:  len
                         */
 
-                       n = mbedtls_gcm_starts(&ctx->u.ctx_gcm, ctx->op,
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+                       n = mbedtls_gcm_starts(&ctx->u.ctx_gcm, (int)ctx->op,
+                                              iv_or_nonce_ctr_or_data_unit_16,
+                                              *nc_or_iv_off);
+                       if (!n)
+                               n = mbedtls_gcm_update_ad(&ctx->u.ctx_gcm,
+                                                         in, len);
+#else
+                       n = mbedtls_gcm_starts(&ctx->u.ctx_gcm, (int)ctx->op,
                                               iv_or_nonce_ctr_or_data_unit_16,
                                               *nc_or_iv_off, in, len);
+#endif
                        if (n) {
                                lwsl_notice("%s: mbedtls_gcm_starts: -0x%x\n",
                                            __func__, -n);
@@ -348,7 +419,15 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len,
                        break;
                }
 
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+               {
+                       size_t al;
+
+                       n = mbedtls_gcm_update(&ctx->u.ctx_gcm, in, len, out, len, &al);
+               }
+#else
                n = mbedtls_gcm_update(&ctx->u.ctx_gcm, len, in, out);
+#endif
                if (n) {
                        lwsl_notice("%s: mbedtls_gcm_update: -0x%x\n",
                                    __func__, -n);
index dd91ad5..c5d5f3d 100644 (file)
@@ -1,33 +1,36 @@
-/*
- * libwebsockets - generic crypto api hiding the backend
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws-gencrypto openssl-specific common code
  */
 
-#include "core/private.h"
-#include "tls/mbedtls/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls-mbedtls.h"
 
 mbedtls_md_type_t
 lws_gencrypto_mbedtls_hash_to_MD_TYPE(enum lws_genhash_types hash_type)
 {
-       mbedtls_md_type_t h = -1;
+       mbedtls_md_type_t h = (mbedtls_md_type_t)-1;
 
        switch (hash_type) {
        case LWS_GENHASH_TYPE_MD5:
index f4dad88..bae22e9 100644 (file)
@@ -1,28 +1,40 @@
-/*
- * libwebsockets - generic EC api hiding the backend - mbedtls implementation
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws_genec provides an EC abstraction api in lws that works the
  *  same whether you are using openssl or mbedtls crypto functions underneath.
  */
-#include "core/private.h"
-#include "tls/mbedtls/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls-mbedtls.h"
+
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+#define ECDHCTX(_c, _ins) _c->u.ctx_ecdh->MBEDTLS_PRIVATE(ctx).\
+                       MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(_ins)
+#define ECDSACTX(_c, _ins) _c->u.ctx_ecdsa->MBEDTLS_PRIVATE(_ins)
+#else
+#define ECDHCTX(_c, _ins) _c->u.ctx_ecdh->_ins
+#define ECDSACTX(_c, _ins) _c->u.ctx_ecdsa->_ins
+#endif
 
 const struct lws_ec_curves lws_ec_curves[] = {
        /*
@@ -41,7 +53,7 @@ const struct lws_ec_curves lws_ec_curves[] = {
 
 static int
 lws_genec_keypair_import(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
-                        struct lws_gencrypto_keyelem *el)
+                        const struct lws_gencrypto_keyelem *el)
 {
        const struct lws_ec_curves *curve;
        mbedtls_ecp_keypair kp;
@@ -73,7 +85,8 @@ lws_genec_keypair_import(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
                return -23;
 
        mbedtls_ecp_keypair_init(&kp);
-       if (mbedtls_ecp_group_load(&kp.grp, curve->tls_lib_nid))
+       if (mbedtls_ecp_group_load(&kp.MBEDTLS_PRIVATE(grp),
+                                  (mbedtls_ecp_group_id)curve->tls_lib_nid))
                goto bail1;
 
        ctx->has_private = !!el[LWS_GENCRYPTO_EC_KEYEL_D].len;
@@ -81,21 +94,24 @@ lws_genec_keypair_import(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
        /* d (the private key) is directly an mpi */
 
        if (ctx->has_private &&
-           mbedtls_mpi_read_binary(&kp.d, el[LWS_GENCRYPTO_EC_KEYEL_D].buf,
+           mbedtls_mpi_read_binary(&kp.MBEDTLS_PRIVATE(d),
+                                   el[LWS_GENCRYPTO_EC_KEYEL_D].buf,
                                    el[LWS_GENCRYPTO_EC_KEYEL_D].len))
                goto bail1;
 
-       mbedtls_ecp_set_zero(&kp.Q);
+       mbedtls_ecp_set_zero(&kp.MBEDTLS_PRIVATE(Q));
 
-       if (mbedtls_mpi_read_binary(&kp.Q.X, el[LWS_GENCRYPTO_EC_KEYEL_X].buf,
+       if (mbedtls_mpi_read_binary(&kp.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X),
+                                   el[LWS_GENCRYPTO_EC_KEYEL_X].buf,
                                    el[LWS_GENCRYPTO_EC_KEYEL_X].len))
                goto bail1;
 
-       if (mbedtls_mpi_read_binary(&kp.Q.Y, el[LWS_GENCRYPTO_EC_KEYEL_Y].buf,
+       if (mbedtls_mpi_read_binary(&kp.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y),
+                                   el[LWS_GENCRYPTO_EC_KEYEL_Y].buf,
                                    el[LWS_GENCRYPTO_EC_KEYEL_Y].len))
                goto bail1;
 
-       mbedtls_mpi_lset(&kp.Q.Z, 1);
+       mbedtls_mpi_lset(&kp.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1);
 
        switch (ctx->genec_alg) {
        case LEGENEC_ECDH:
@@ -104,11 +120,11 @@ lws_genec_keypair_import(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
                        goto bail1;
                /* verify the key is consistent with the claimed curve */
                if (ctx->has_private &&
-                   mbedtls_ecp_check_privkey(&ctx->u.ctx_ecdh->grp,
-                                             &ctx->u.ctx_ecdh->d))
+                   mbedtls_ecp_check_privkey(&ECDHCTX(ctx, grp),
+                                             &ECDHCTX(ctx, d)))
                        goto bail1;
-               if (mbedtls_ecp_check_pubkey(&ctx->u.ctx_ecdh->grp,
-                                            &ctx->u.ctx_ecdh->Q))
+               if (mbedtls_ecp_check_pubkey(&ECDHCTX(ctx, grp),
+                                            &ECDHCTX(ctx, Q)))
                        goto bail1;
                break;
        case LEGENEC_ECDSA:
@@ -116,11 +132,11 @@ lws_genec_keypair_import(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
                        goto bail1;
                /* verify the key is consistent with the claimed curve */
                if (ctx->has_private &&
-                   mbedtls_ecp_check_privkey(&ctx->u.ctx_ecdsa->grp,
-                                             &ctx->u.ctx_ecdsa->d))
+                   mbedtls_ecp_check_privkey(&ECDSACTX(ctx, grp),
+                                             &ECDSACTX(ctx, d)))
                        goto bail1;
-               if (mbedtls_ecp_check_pubkey(&ctx->u.ctx_ecdsa->grp,
-                                            &ctx->u.ctx_ecdsa->Q))
+               if (mbedtls_ecp_check_pubkey(&ECDSACTX(ctx, grp),
+                                            &ECDSACTX(ctx, Q)))
                        goto bail1;
                break;
        default:
@@ -135,7 +151,7 @@ bail1:
        return ret;
 }
 
-LWS_VISIBLE int
+int
 lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context,
                   const struct lws_ec_curves *curve_table)
 {
@@ -154,7 +170,7 @@ lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context,
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context,
                    const struct lws_ec_curves *curve_table)
 {
@@ -174,7 +190,7 @@ lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context,
 }
 
 
-LWS_VISIBLE int
+int
 lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el,
                    enum enum_lws_dh_side side)
 {
@@ -184,9 +200,9 @@ lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el,
        return lws_genec_keypair_import(ctx, side, el);
 }
 
-LWS_VISIBLE int
+int
 lws_genecdsa_set_key(struct lws_genec_ctx *ctx,
-                    struct lws_gencrypto_keyelem *el)
+                    const struct lws_gencrypto_keyelem *el)
 {
        if (ctx->genec_alg != LEGENEC_ECDSA)
                return -1;
@@ -194,7 +210,7 @@ lws_genecdsa_set_key(struct lws_genec_ctx *ctx,
        return lws_genec_keypair_import(ctx, 0, el);
 }
 
-LWS_VISIBLE void
+void
 lws_genec_destroy(struct lws_genec_ctx *ctx)
 {
        switch (ctx->genec_alg) {
@@ -217,7 +233,7 @@ lws_genec_destroy(struct lws_genec_ctx *ctx)
        }
 }
 
-LWS_VISIBLE int
+int
 lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
                        const char *curve_name,
                        struct lws_gencrypto_keyelem *el)
@@ -240,7 +256,7 @@ lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
        }
 
        mbedtls_ecdsa_init(&ecdsa);
-       n = mbedtls_ecdsa_genkey(&ecdsa, curve->tls_lib_nid,
+       n = mbedtls_ecdsa_genkey(&ecdsa, (mbedtls_ecp_group_id)curve->tls_lib_nid,
                                 lws_gencrypto_mbedtls_rngf,
                                 ctx->context);
        if (n) {
@@ -262,11 +278,11 @@ lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
         * lws_gencrypto_keyelem, so they can be serialized, used in jwk etc
         */
 
-       mpi[0] = &kp->Q.X;
-       mpi[1] = &kp->d;
-       mpi[2] = &kp->Q.Y;
+       mpi[0] = &kp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X);
+       mpi[1] = &kp->MBEDTLS_PRIVATE(d);
+       mpi[2] = &kp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y);
 
-       el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = strlen(curve_name) + 1;
+       el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = (uint32_t)strlen(curve_name) + 1;
        el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf =
                        lws_malloc(el[LWS_GENCRYPTO_EC_KEYEL_CRV].len, "ec");
        if (!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
@@ -301,7 +317,7 @@ bail1:
        return -1;
 }
 
-LWS_VISIBLE int
+int
 lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name,
                         struct lws_gencrypto_keyelem *el)
 {
@@ -322,7 +338,7 @@ lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name,
        }
 
        //mbedtls_ecdsa_init(ctx->u.ctx_ecdsa);
-       n = mbedtls_ecdsa_genkey(ctx->u.ctx_ecdsa, curve->tls_lib_nid,
+       n = mbedtls_ecdsa_genkey(ctx->u.ctx_ecdsa, (mbedtls_ecp_group_id)curve->tls_lib_nid,
                                 lws_gencrypto_mbedtls_rngf, ctx->context);
        if (n) {
                lwsl_err("mbedtls_ecdsa_genkey failed 0x%x\n", -n);
@@ -336,11 +352,11 @@ lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name,
 
        kp = (mbedtls_ecp_keypair *)ctx->u.ctx_ecdsa;
 
-       mpi[0] = &kp->Q.X;
-       mpi[1] = &kp->d;
-       mpi[2] = &kp->Q.Y;
+       mpi[0] = &kp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X);
+       mpi[1] = &kp->MBEDTLS_PRIVATE(d);
+       mpi[2] = &kp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y);
 
-       el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = strlen(curve_name) + 1;
+       el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = (uint32_t)strlen(curve_name) + 1;
        el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf =
                        lws_malloc(el[LWS_GENCRYPTO_EC_KEYEL_CRV].len, "ec");
        if (!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf)
@@ -374,7 +390,7 @@ bail1:
        return -1;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
                           enum lws_genhash_types hash_type, int keybits,
                           uint8_t *sig, size_t sig_len)
@@ -409,8 +425,8 @@ lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
        mbedtls_mpi_init(&mpi_r);
        mbedtls_mpi_init(&mpi_s);
 
-       n = mbedtls_ecdsa_sign(&ctx->u.ctx_ecdsa->grp, &mpi_r, &mpi_s,
-                              &ctx->u.ctx_ecdsa->d, in, hlen,
+       n = mbedtls_ecdsa_sign(&ECDSACTX(ctx, grp), &mpi_r, &mpi_s,
+                              &ECDSACTX(ctx, d), in, hlen,
                        lws_gencrypto_mbedtls_rngf, ctx->context);
        if (n) {
                lwsl_err("%s: mbedtls_ecdsa_sign failed: -0x%x\n",
@@ -419,10 +435,10 @@ lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
                goto bail2;
        }
 
-       if (mbedtls_mpi_write_binary(&mpi_r, sig, keybytes))
+       if (mbedtls_mpi_write_binary(&mpi_r, sig, (unsigned int)keybytes))
                goto bail2;
        mbedtls_mpi_free(&mpi_r);
-       if (mbedtls_mpi_write_binary(&mpi_s, sig + keybytes, keybytes))
+       if (mbedtls_mpi_write_binary(&mpi_s, sig + keybytes, (unsigned int)keybytes))
                goto bail1;
        mbedtls_mpi_free(&mpi_s);
 
@@ -436,7 +452,7 @@ bail1:
        return -3;
 }
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
                                 enum lws_genhash_types hash_type, int keybits,
                                 const uint8_t *sig, size_t sig_len)
@@ -468,13 +484,13 @@ lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
        mbedtls_mpi_init(&mpi_r);
        mbedtls_mpi_init(&mpi_s);
 
-       if (mbedtls_mpi_read_binary(&mpi_r, sig, keybytes))
+       if (mbedtls_mpi_read_binary(&mpi_r, sig, (unsigned int)keybytes))
                return -1;
-       if (mbedtls_mpi_read_binary(&mpi_s, sig + keybytes, keybytes))
+       if (mbedtls_mpi_read_binary(&mpi_s, sig + keybytes, (unsigned int)keybytes))
                goto bail1;
 
-       n = mbedtls_ecdsa_verify(&ctx->u.ctx_ecdsa->grp, in, hlen,
-                                &ctx->u.ctx_ecdsa->Q, &mpi_r, &mpi_s);
+       n = mbedtls_ecdsa_verify(&ECDSACTX(ctx, grp), in, hlen,
+                                &ECDSACTX(ctx, Q), &mpi_r, &mpi_s);
 
        mbedtls_mpi_free(&mpi_s);
        mbedtls_mpi_free(&mpi_r);
@@ -501,14 +517,14 @@ lws_genecdh_compute_shared_secret(struct lws_genec_ctx *ctx, uint8_t *ss,
 {
        int n;
        size_t st;
-       if (mbedtls_ecp_check_pubkey(&ctx->u.ctx_ecdh->grp, &ctx->u.ctx_ecdh->Q) ||
-           mbedtls_ecp_check_pubkey(&ctx->u.ctx_ecdh->grp, &ctx->u.ctx_ecdh->Qp)) {
+       if (mbedtls_ecp_check_pubkey(&ECDHCTX(ctx, grp), &ECDHCTX(ctx, Q)) ||
+           mbedtls_ecp_check_pubkey(&ECDHCTX(ctx, grp), &ECDHCTX(ctx, Qp))) {
                lwsl_err("%s: both sides must be set up\n", __func__);
 
                return -1;
        }
 
-       n = mbedtls_ecdh_calc_secret(ctx->u.ctx_ecdh, &st, ss, *ss_len,
+       n = mbedtls_ecdh_calc_secret(ctx->u.ctx_ecdh, &st, ss, (size_t)*ss_len,
                        lws_gencrypto_mbedtls_rngf, ctx->context);
        if (n)
                return -1;
index 7fee589..c9ea366 100644 (file)
@@ -1,22 +1,25 @@
-/*
- * libwebsockets - generic hash and HMAC api hiding the backend
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws_genhash provides a hash / hmac abstraction api in lws that works the
  *  same whether you are using openssl or mbedtls hash functions underneath.
 #include "libwebsockets.h"
 #include <mbedtls/version.h>
 
-#if (MBEDTLS_VERSION_NUMBER >= 0x02070000)
-#define MBA(fn) fn##_ret
-#else
-#define MBA(fn) fn
+#if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x03000000)
+#define mbedtls_md5_starts_ret mbedtls_md5_starts
+#define mbedtls_md5_update_ret mbedtls_md5_update
+#define mbedtls_md5_finish_ret mbedtls_md5_finish
+#define mbedtls_sha1_finish_ret mbedtls_sha1_finish
+#define mbedtls_sha1_update_ret mbedtls_sha1_update
+#define mbedtls_sha1_starts_ret mbedtls_sha1_starts
+#define mbedtls_sha256_starts_ret mbedtls_sha256_starts
+#define mbedtls_sha256_update_ret mbedtls_sha256_update
+#define mbedtls_sha256_finish_ret mbedtls_sha256_finish
+#define mbedtls_sha512_starts_ret mbedtls_sha512_starts
+#define mbedtls_sha512_update_ret mbedtls_sha512_update
+#define mbedtls_sha512_finish_ret mbedtls_sha512_finish
 #endif
 
+#if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x02070000)
+
+/*
+ * We have the _ret variants available, check the return codes on everything
+ */
+
+int
+lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type)
+{
+       ctx->type = (uint8_t)type;
+
+       switch (ctx->type) {
+       case LWS_GENHASH_TYPE_MD5:
+               mbedtls_md5_init(&ctx->u.md5);
+               if (mbedtls_md5_starts_ret(&ctx->u.md5))
+                       return 1;
+               break;
+       case LWS_GENHASH_TYPE_SHA1:
+               mbedtls_sha1_init(&ctx->u.sha1);
+               if (mbedtls_sha1_starts_ret(&ctx->u.sha1))
+                       return 1;
+               break;
+       case LWS_GENHASH_TYPE_SHA256:
+               mbedtls_sha256_init(&ctx->u.sha256);
+               if (mbedtls_sha256_starts_ret(&ctx->u.sha256, 0))
+                       return 1;
+               break;
+       case LWS_GENHASH_TYPE_SHA384:
+               mbedtls_sha512_init(&ctx->u.sha512);
+               if (mbedtls_sha512_starts_ret(&ctx->u.sha512, 1 /* is384 */))
+                       return 1;
+               break;
+       case LWS_GENHASH_TYPE_SHA512:
+               mbedtls_sha512_init(&ctx->u.sha512);
+               if (mbedtls_sha512_starts_ret(&ctx->u.sha512, 0))
+                       return 1;
+               break;
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len)
+{
+       if (!len)
+               return 0;
+
+       switch (ctx->type) {
+       case LWS_GENHASH_TYPE_MD5:
+               if (mbedtls_md5_update_ret(&ctx->u.md5, in, len))
+                       return 1;
+               break;
+       case LWS_GENHASH_TYPE_SHA1:
+               if (mbedtls_sha1_update_ret(&ctx->u.sha1, in, len))
+                       return 1;
+               break;
+       case LWS_GENHASH_TYPE_SHA256:
+               if (mbedtls_sha256_update_ret(&ctx->u.sha256, in, len))
+                       return 1;
+               break;
+       case LWS_GENHASH_TYPE_SHA384:
+               if (mbedtls_sha512_update_ret(&ctx->u.sha512, in, len))
+                       return 1;
+               break;
+       case LWS_GENHASH_TYPE_SHA512:
+               if (mbedtls_sha512_update_ret(&ctx->u.sha512, in, len))
+                       return 1;
+               break;
+       }
+
+       return 0;
+}
+
+int
+lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result)
+{
+       switch (ctx->type) {
+       case LWS_GENHASH_TYPE_MD5:
+               if (mbedtls_md5_finish_ret(&ctx->u.md5, result))
+                       return 1;
+               mbedtls_md5_free(&ctx->u.md5);
+               break;
+       case LWS_GENHASH_TYPE_SHA1:
+               if (mbedtls_sha1_finish_ret(&ctx->u.sha1, result))
+                       return 1;
+               mbedtls_sha1_free(&ctx->u.sha1);
+               break;
+       case LWS_GENHASH_TYPE_SHA256:
+               if (mbedtls_sha256_finish_ret(&ctx->u.sha256, result))
+                       return 1;
+               mbedtls_sha256_free(&ctx->u.sha256);
+               break;
+       case LWS_GENHASH_TYPE_SHA384:
+               if (mbedtls_sha512_finish_ret(&ctx->u.sha512, result))
+                       return 1;
+               mbedtls_sha512_free(&ctx->u.sha512);
+               break;
+       case LWS_GENHASH_TYPE_SHA512:
+               if (mbedtls_sha512_finish_ret(&ctx->u.sha512, result))
+                       return 1;
+               mbedtls_sha512_free(&ctx->u.sha512);
+               break;
+       }
+
+       return 0;
+}
+
+#else
+
+/*
+ * mbedtls is too old to have the _ret variants
+ */
+
 int
 lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type)
 {
@@ -38,23 +166,23 @@ lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type)
        switch (ctx->type) {
        case LWS_GENHASH_TYPE_MD5:
                mbedtls_md5_init(&ctx->u.md5);
-               MBA(mbedtls_md5_starts)(&ctx->u.md5);
+               mbedtls_md5_starts(&ctx->u.md5);
                break;
        case LWS_GENHASH_TYPE_SHA1:
                mbedtls_sha1_init(&ctx->u.sha1);
-               MBA(mbedtls_sha1_starts)(&ctx->u.sha1);
+               mbedtls_sha1_starts(&ctx->u.sha1);
                break;
        case LWS_GENHASH_TYPE_SHA256:
                mbedtls_sha256_init(&ctx->u.sha256);
-               MBA(mbedtls_sha256_starts)(&ctx->u.sha256, 0);
+               mbedtls_sha256_starts(&ctx->u.sha256, 0);
                break;
        case LWS_GENHASH_TYPE_SHA384:
                mbedtls_sha512_init(&ctx->u.sha512);
-               MBA(mbedtls_sha512_starts)(&ctx->u.sha512, 1 /* is384 */);
+               mbedtls_sha512_starts(&ctx->u.sha512, 1 /* is384 */);
                break;
        case LWS_GENHASH_TYPE_SHA512:
                mbedtls_sha512_init(&ctx->u.sha512);
-               MBA(mbedtls_sha512_starts)(&ctx->u.sha512, 0);
+               mbedtls_sha512_starts(&ctx->u.sha512, 0);
                break;
        default:
                return 1;
@@ -71,19 +199,19 @@ lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len)
 
        switch (ctx->type) {
        case LWS_GENHASH_TYPE_MD5:
-               MBA(mbedtls_md5_update)(&ctx->u.md5, in, len);
+               mbedtls_md5_update(&ctx->u.md5, in, len);
                break;
        case LWS_GENHASH_TYPE_SHA1:
-               MBA(mbedtls_sha1_update)(&ctx->u.sha1, in, len);
+               mbedtls_sha1_update(&ctx->u.sha1, in, len);
                break;
        case LWS_GENHASH_TYPE_SHA256:
-               MBA(mbedtls_sha256_update)(&ctx->u.sha256, in, len);
+               mbedtls_sha256_update(&ctx->u.sha256, in, len);
                break;
        case LWS_GENHASH_TYPE_SHA384:
-               MBA(mbedtls_sha512_update)(&ctx->u.sha512, in, len);
+               mbedtls_sha512_update(&ctx->u.sha512, in, len);
                break;
        case LWS_GENHASH_TYPE_SHA512:
-               MBA(mbedtls_sha512_update)(&ctx->u.sha512, in, len);
+               mbedtls_sha512_update(&ctx->u.sha512, in, len);
                break;
        }
 
@@ -95,23 +223,23 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result)
 {
        switch (ctx->type) {
        case LWS_GENHASH_TYPE_MD5:
-               MBA(mbedtls_md5_finish)(&ctx->u.md5, result);
+               mbedtls_md5_finish(&ctx->u.md5, result);
                mbedtls_md5_free(&ctx->u.md5);
                break;
        case LWS_GENHASH_TYPE_SHA1:
-               MBA(mbedtls_sha1_finish)(&ctx->u.sha1, result);
+               mbedtls_sha1_finish(&ctx->u.sha1, result);
                mbedtls_sha1_free(&ctx->u.sha1);
                break;
        case LWS_GENHASH_TYPE_SHA256:
-               MBA(mbedtls_sha256_finish)(&ctx->u.sha256, result);
+               mbedtls_sha256_finish(&ctx->u.sha256, result);
                mbedtls_sha256_free(&ctx->u.sha256);
                break;
        case LWS_GENHASH_TYPE_SHA384:
-               MBA(mbedtls_sha512_finish)(&ctx->u.sha512, result);
+               mbedtls_sha512_finish(&ctx->u.sha512, result);
                mbedtls_sha512_free(&ctx->u.sha512);
                break;
        case LWS_GENHASH_TYPE_SHA512:
-               MBA(mbedtls_sha512_finish)(&ctx->u.sha512, result);
+               mbedtls_sha512_finish(&ctx->u.sha512, result);
                mbedtls_sha512_free(&ctx->u.sha512);
                break;
        }
@@ -119,13 +247,15 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result)
        return 0;
 }
 
+#endif
+
 int
 lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
                 const uint8_t *key, size_t key_len)
 {
        int t;
 
-       ctx->type = type;
+       ctx->type = (uint8_t)type;
 
        switch (type) {
        case LWS_GENHMAC_TYPE_SHA256:
@@ -141,12 +271,17 @@ lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
                return -1;
        }
 
-       ctx->hmac = mbedtls_md_info_from_type(t);
+       ctx->hmac = mbedtls_md_info_from_type((mbedtls_md_type_t)t);
        if (!ctx->hmac)
                return -1;
 
+#if !defined(LWS_HAVE_mbedtls_md_setup)
        if (mbedtls_md_init_ctx(&ctx->ctx, ctx->hmac))
                return -1;
+#else
+       if (mbedtls_md_setup(&ctx->ctx, ctx->hmac, 1))
+               return -1;
+#endif
 
        if (mbedtls_md_hmac_starts(&ctx->ctx, key, key_len)) {
                mbedtls_md_free(&ctx->ctx);
index 2589064..292b1ac 100644 (file)
@@ -1,31 +1,34 @@
-/*
- * libwebsockets - generic RSA api hiding the backend
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws_genrsa provides an RSA abstraction api in lws that works the
  *  same whether you are using openssl or mbedtls crypto functions underneath.
  */
-#include "core/private.h"
-#include "tls/mbedtls/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls-mbedtls.h"
 #include <mbedtls/rsa.h>
 
-LWS_VISIBLE void
+void
 lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el)
 {
        int n;
@@ -37,8 +40,9 @@ lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el)
 
 static int mode_map[] = { MBEDTLS_RSA_PKCS_V15, MBEDTLS_RSA_PKCS_V21 };
 
-LWS_VISIBLE int
-lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
+int
+lws_genrsa_create(struct lws_genrsa_ctx *ctx,
+                 const struct lws_gencrypto_keyelem *el,
                  struct lws_context *context, enum enum_genrsa_mode mode,
                  enum lws_genhash_types oaep_hashid)
 {
@@ -53,18 +57,29 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
        if (mode >= LGRSAM_COUNT)
                return -1;
 
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
        mbedtls_rsa_init(ctx->ctx, mode_map[mode], 0);
+#else
+       mbedtls_rsa_init(ctx->ctx);
+       mbedtls_rsa_set_padding(ctx->ctx, mode_map[mode], 0);
+#endif
 
-       ctx->ctx->padding = mode_map[mode];
-       ctx->ctx->hash_id = lws_gencrypto_mbedtls_hash_to_MD_TYPE(oaep_hashid);
+       ctx->ctx->MBEDTLS_PRIVATE(padding) = mode_map[mode];
+       ctx->ctx->MBEDTLS_PRIVATE(hash_id) =
+                       (int)lws_gencrypto_mbedtls_hash_to_MD_TYPE(oaep_hashid);
 
        {
                int n;
 
                mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT] = {
-                       &ctx->ctx->E, &ctx->ctx->N, &ctx->ctx->D, &ctx->ctx->P,
-                       &ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ,
-                       &ctx->ctx->QP,
+                       &ctx->ctx->MBEDTLS_PRIVATE(E),
+                       &ctx->ctx->MBEDTLS_PRIVATE(N),
+                       &ctx->ctx->MBEDTLS_PRIVATE(D),
+                       &ctx->ctx->MBEDTLS_PRIVATE(P),
+                       &ctx->ctx->MBEDTLS_PRIVATE(Q),
+                       &ctx->ctx->MBEDTLS_PRIVATE(DP),
+                       &ctx->ctx->MBEDTLS_PRIVATE(DQ),
+                       &ctx->ctx->MBEDTLS_PRIVATE(QP),
                };
 
                for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++)
@@ -82,8 +97,13 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
                if ( el[LWS_GENCRYPTO_RSA_KEYEL_D].len &&
                    !el[LWS_GENCRYPTO_RSA_KEYEL_P].len &&
                    !el[LWS_GENCRYPTO_RSA_KEYEL_Q].len) {
+#if defined(LWS_HAVE_mbedtls_rsa_complete)
                        if (mbedtls_rsa_complete(ctx->ctx)) {
                                lwsl_notice("mbedtls_rsa_complete failed\n");
+#else
+                       {
+                               lwsl_notice("%s: you have to provide P and Q\n", __func__);
+#endif
                                lws_free_set_NULL(ctx->ctx);
 
                                return -1;
@@ -92,7 +112,7 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
                }
        }
 
-       ctx->ctx->len = el[LWS_GENCRYPTO_RSA_KEYEL_N].len;
+       ctx->ctx->MBEDTLS_PRIVATE(len) = el[LWS_GENCRYPTO_RSA_KEYEL_N].len;
 
        return 0;
 }
@@ -106,7 +126,7 @@ _rngf(void *context, unsigned char *buf, size_t len)
        return -1;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
                       enum enum_genrsa_mode mode, struct lws_gencrypto_keyelem *el,
                       int bits)
@@ -124,9 +144,14 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
        if (mode >= LGRSAM_COUNT)
                return -1;
 
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
        mbedtls_rsa_init(ctx->ctx, mode_map[mode], 0);
+#else
+       mbedtls_rsa_init(ctx->ctx);
+       mbedtls_rsa_set_padding(ctx->ctx, mode_map[mode], 0);
+#endif
 
-       n = mbedtls_rsa_gen_key(ctx->ctx, _rngf, context, bits, 65537);
+       n = mbedtls_rsa_gen_key(ctx->ctx, _rngf, context, (unsigned int)bits, 65537);
        if (n) {
                lwsl_err("mbedtls_rsa_gen_key failed 0x%x\n", -n);
                goto cleanup_1;
@@ -134,18 +159,23 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
 
        {
                mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT] = {
-                       &ctx->ctx->E, &ctx->ctx->N, &ctx->ctx->D, &ctx->ctx->P,
-                       &ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ,
-                       &ctx->ctx->QP,
+                       &ctx->ctx->MBEDTLS_PRIVATE(E),
+                       &ctx->ctx->MBEDTLS_PRIVATE(N),
+                       &ctx->ctx->MBEDTLS_PRIVATE(D),
+                       &ctx->ctx->MBEDTLS_PRIVATE(P),
+                       &ctx->ctx->MBEDTLS_PRIVATE(Q),
+                       &ctx->ctx->MBEDTLS_PRIVATE(DP),
+                       &ctx->ctx->MBEDTLS_PRIVATE(DQ),
+                       &ctx->ctx->MBEDTLS_PRIVATE(QP),
                };
 
                for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++)
-                       if (mbedtls_mpi_size(mpi[n])) {
+                       if (mpi[n] && mbedtls_mpi_size(mpi[n])) {
                                el[n].buf = lws_malloc(
                                        mbedtls_mpi_size(mpi[n]), "genrsakey");
                                if (!el[n].buf)
                                        goto cleanup;
-                               el[n].len = mbedtls_mpi_size(mpi[n]);
+                               el[n].len = (uint32_t)mbedtls_mpi_size(mpi[n]);
                                if (mbedtls_mpi_write_binary(mpi[n], el[n].buf,
                                                         el[n].len))
                                        goto cleanup;
@@ -164,29 +194,35 @@ cleanup_1:
        return -1;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                          size_t in_len, uint8_t *out, size_t out_max)
 {
        size_t olen = 0;
        int n;
 
-       ctx->ctx->len = in_len;
+       ctx->ctx->MBEDTLS_PRIVATE(len) = in_len;
 
+#if defined(LWS_HAVE_mbedtls_rsa_complete)
        mbedtls_rsa_complete(ctx->ctx);
+#endif
 
        switch(ctx->mode) {
        case LGRSAM_PKCS1_1_5:
                n = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx->ctx, _rngf,
                                                        ctx->context,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
                                                        MBEDTLS_RSA_PUBLIC,
+#endif
                                                        &olen, in, out,
                                                        out_max);
                break;
        case LGRSAM_PKCS1_OAEP_PSS:
                n = mbedtls_rsa_rsaes_oaep_decrypt(ctx->ctx, _rngf,
                                                   ctx->context,
-                                                  MBEDTLS_RSA_PUBLIC,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
+                                                       MBEDTLS_RSA_PUBLIC,
+#endif
                                                   NULL, 0,
                                                   &olen, in, out, out_max);
                break;
@@ -199,32 +235,38 @@ lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                return -1;
        }
 
-       return olen;
+       return (int)olen;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                           size_t in_len, uint8_t *out, size_t out_max)
 {
        size_t olen = 0;
        int n;
 
-       ctx->ctx->len = in_len;
+       ctx->ctx->MBEDTLS_PRIVATE(len) = in_len;
 
+#if defined(LWS_HAVE_mbedtls_rsa_complete)
        mbedtls_rsa_complete(ctx->ctx);
+#endif
 
        switch(ctx->mode) {
        case LGRSAM_PKCS1_1_5:
                n = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx->ctx, _rngf,
                                                        ctx->context,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
                                                        MBEDTLS_RSA_PRIVATE,
+#endif
                                                        &olen, in, out,
                                                        out_max);
                break;
        case LGRSAM_PKCS1_OAEP_PSS:
                n = mbedtls_rsa_rsaes_oaep_decrypt(ctx->ctx, _rngf,
                                                   ctx->context,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
                                                   MBEDTLS_RSA_PRIVATE,
+#endif
                                                   NULL, 0,
                                                   &olen, in, out, out_max);
                break;
@@ -237,28 +279,34 @@ lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                return -1;
        }
 
-       return olen;
+       return (int)olen;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                          size_t in_len, uint8_t *out)
 {
        int n;
 
+#if defined(LWS_HAVE_mbedtls_rsa_complete)
        mbedtls_rsa_complete(ctx->ctx);
+#endif
 
        switch(ctx->mode) {
        case LGRSAM_PKCS1_1_5:
                n = mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx->ctx, _rngf,
                                                        ctx->context,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
                                                        MBEDTLS_RSA_PUBLIC,
+#endif
                                                        in_len, in, out);
                break;
        case LGRSAM_PKCS1_OAEP_PSS:
                n = mbedtls_rsa_rsaes_oaep_encrypt(ctx->ctx, _rngf,
                                                   ctx->context,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
                                                   MBEDTLS_RSA_PUBLIC,
+#endif
                                                   NULL, 0,
                                                   in_len, in, out);
                break;
@@ -272,28 +320,34 @@ lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                return -1;
        }
 
-       return mbedtls_mpi_size(&ctx->ctx->N);
+       return (int)mbedtls_mpi_size(&ctx->ctx->MBEDTLS_PRIVATE(N));
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                           size_t in_len, uint8_t *out)
 {
        int n;
 
+#if defined(LWS_HAVE_mbedtls_rsa_complete)
        mbedtls_rsa_complete(ctx->ctx);
+#endif
 
        switch(ctx->mode) {
        case LGRSAM_PKCS1_1_5:
                n = mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx->ctx, _rngf,
                                                        ctx->context,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
                                                        MBEDTLS_RSA_PRIVATE,
+#endif
                                                        in_len, in, out);
                break;
        case LGRSAM_PKCS1_OAEP_PSS:
                n = mbedtls_rsa_rsaes_oaep_encrypt(ctx->ctx, _rngf,
                                                   ctx->context,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
                                                   MBEDTLS_RSA_PRIVATE,
+#endif
                                                   NULL, 0,
                                                   in_len, in, out);
                break;
@@ -307,37 +361,49 @@ lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                return -1;
        }
 
-       return mbedtls_mpi_size(&ctx->ctx->N);
+       return (int)mbedtls_mpi_size(&ctx->ctx->MBEDTLS_PRIVATE(N));
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                         enum lws_genhash_types hash_type, const uint8_t *sig,
                         size_t sig_len)
 {
-       int n, h = lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type);
+       int n, h = (int)lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type);
 
        if (h < 0)
                return -1;
 
+#if defined(LWS_HAVE_mbedtls_rsa_complete)
        mbedtls_rsa_complete(ctx->ctx);
+#endif
 
        switch(ctx->mode) {
        case LGRSAM_PKCS1_1_5:
-               n = mbedtls_rsa_rsassa_pkcs1_v15_verify(ctx->ctx, NULL, NULL,
+               n = mbedtls_rsa_rsassa_pkcs1_v15_verify(ctx->ctx,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
+                                                       NULL, NULL,
                                                        MBEDTLS_RSA_PUBLIC,
-                                                       h, 0, in, sig);
+#endif
+                                                       (mbedtls_md_type_t)h,
+                                                       (unsigned int)lws_genhash_size(hash_type),
+                                                       in, sig);
                break;
        case LGRSAM_PKCS1_OAEP_PSS:
-               n = mbedtls_rsa_rsassa_pss_verify(ctx->ctx, NULL, NULL,
+               n = mbedtls_rsa_rsassa_pss_verify(ctx->ctx,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
+                                                 NULL, NULL,
                                                  MBEDTLS_RSA_PUBLIC,
-                                                 h, 0, in, sig);
+#endif
+                                                 (mbedtls_md_type_t)h,
+                                                 (unsigned int)lws_genhash_size(hash_type),
+                                                 in, sig);
                break;
        default:
                return -1;
        }
        if (n < 0) {
-               lwsl_notice("%s: -0x%x\n", __func__, -n);
+               lwsl_notice("%s: (mode %d) -0x%x\n", __func__, ctx->mode, -n);
 
                return -1;
        }
@@ -345,35 +411,49 @@ lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in,
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                       enum lws_genhash_types hash_type, uint8_t *sig,
                       size_t sig_len)
 {
-       int n, h = lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type);
+       int n, h = (int)lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type);
 
        if (h < 0)
                return -1;
 
+#if defined(LWS_HAVE_mbedtls_rsa_complete)
        mbedtls_rsa_complete(ctx->ctx);
+#endif
 
        /*
         * The "sig" buffer must be as large as the size of ctx->N
         * (eg. 128 bytes if RSA-1024 is used).
         */
-       if (sig_len < ctx->ctx->len)
+       if (sig_len < ctx->ctx->MBEDTLS_PRIVATE(len))
                return -1;
 
        switch(ctx->mode) {
        case LGRSAM_PKCS1_1_5:
-               n = mbedtls_rsa_rsassa_pkcs1_v15_sign(ctx->ctx, NULL, NULL,
+               n = mbedtls_rsa_rsassa_pkcs1_v15_sign(ctx->ctx,
+                                                     mbedtls_ctr_drbg_random,
+                                                     &ctx->context->mcdc,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
                                                      MBEDTLS_RSA_PRIVATE,
-                                                     h, 0, in, sig);
+#endif
+                                                     (mbedtls_md_type_t)h,
+                                                     (unsigned int)lws_genhash_size(hash_type),
+                                                     in, sig);
                break;
        case LGRSAM_PKCS1_OAEP_PSS:
-               n = mbedtls_rsa_rsassa_pss_sign(ctx->ctx, NULL, NULL,
+               n = mbedtls_rsa_rsassa_pss_sign(ctx->ctx,
+                                               mbedtls_ctr_drbg_random,
+                                               &ctx->context->mcdc,
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
                                                MBEDTLS_RSA_PRIVATE,
-                                               h, 0, in, sig);
+#endif
+                                               (mbedtls_md_type_t)h,
+                                               (unsigned int)lws_genhash_size(hash_type),
+                                               in, sig);
                break;
        default:
                return -1;
@@ -385,18 +465,23 @@ lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                return -1;
        }
 
-       return ctx->ctx->len;
+       return (int)ctx->ctx->MBEDTLS_PRIVATE(len);
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_render_pkey_asn1(struct lws_genrsa_ctx *ctx, int _private,
                            uint8_t *pkey_asn1, size_t pkey_asn1_len)
 {
        uint8_t *p = pkey_asn1, *totlen, *end = pkey_asn1 + pkey_asn1_len - 1;
        mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT] = {
-               &ctx->ctx->N, &ctx->ctx->E, &ctx->ctx->D, &ctx->ctx->P,
-               &ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ,
-               &ctx->ctx->QP,
+               &ctx->ctx->MBEDTLS_PRIVATE(N),
+               &ctx->ctx->MBEDTLS_PRIVATE(E),
+               &ctx->ctx->MBEDTLS_PRIVATE(D),
+               &ctx->ctx->MBEDTLS_PRIVATE(P),
+               &ctx->ctx->MBEDTLS_PRIVATE(Q),
+               &ctx->ctx->MBEDTLS_PRIVATE(DP),
+               &ctx->ctx->MBEDTLS_PRIVATE(DQ),
+               &ctx->ctx->MBEDTLS_PRIVATE(QP),
        };
        int n;
 
@@ -426,49 +511,49 @@ lws_genrsa_render_pkey_asn1(struct lws_genrsa_ctx *ctx, int _private,
        *p++ = 0x00;
 
        for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) {
-               int m = mbedtls_mpi_size(mpi[n]);
+               int m = (int)mbedtls_mpi_size(mpi[n]);
                uint8_t *elen;
 
                *p++ = 0x02;
                elen = p;
                if (m < 0x7f)
-                       *p++ = m;
+                       *p++ = (uint8_t)m;
                else {
                        *p++ = 0x82;
-                       *p++ = m >> 8;
-                       *p++ = m & 0xff;
+                       *p++ = (uint8_t)(m >> 8);
+                       *p++ = (uint8_t)(m & 0xff);
                }
 
                if (p + m > end)
                        return -1;
 
-               if (mbedtls_mpi_write_binary(mpi[n], p, m))
+               if (mbedtls_mpi_write_binary(mpi[n], p, (unsigned int)m))
                        return -1;
                if (p[0] & 0x80) {
                        p[0] = 0x00;
-                       if (mbedtls_mpi_write_binary(mpi[n], &p[1], m))
+                       if (mbedtls_mpi_write_binary(mpi[n], &p[1], (unsigned int)m))
                                return -1;
                        m++;
                }
                if (m < 0x7f)
-                       *elen = m;
+                       *elen = (uint8_t)m;
                else {
                        *elen++ = 0x82;
-                       *elen++ = m >> 8;
-                       *elen = m & 0xff;
+                       *elen++ = (uint8_t)(m >> 8);
+                       *elen = (uint8_t)(m & 0xff);
                }
                p += m;
        }
 
        n = lws_ptr_diff(p, pkey_asn1);
 
-       *totlen++ = (n - 4) >> 8;
-       *totlen = (n - 4) & 0xff;
+       *totlen++ = (uint8_t)((n - 4) >> 8);
+       *totlen = (uint8_t)((n - 4) & 0xff);
 
        return n;
 }
 
-LWS_VISIBLE void
+void
 lws_genrsa_destroy(struct lws_genrsa_ctx *ctx)
 {
        if (!ctx->ctx)
index d3de991..c12bbd5 100644 (file)
@@ -1,45 +1,90 @@
 /*
- * libwebsockets - mbedtls-specific client TLS code
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls-mbedtls.h"
+
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+
+/*
+ * We get called for each peer certificate that was provided in turn.
+ *
+ * Our job is just to collect the AKID and SKIDs into ssl->kid_chain, and walk
+ * later at verification result time if it failed.
+ *
+ * None of these should be trusted, even if a misconfigured server sends us
+ * his root CA.
+ */
 
 static int
-OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+lws_mbedtls_client_verify_callback(SSL *ssl, mbedtls_x509_crt *x509)
 {
+       union lws_tls_cert_info_results ci;
+
+       /* we reached the max we can hold? */
+
+       if (ssl->kid_chain.count == LWS_ARRAY_SIZE(ssl->kid_chain.akid))
+               return 0;
+
+       /* if not, stash the SKID and AKID into the next kid slot */
+
+       if (!lws_tls_mbedtls_cert_info(x509, LWS_TLS_CERT_INFO_SUBJECT_KEY_ID,
+                                      &ci, 0))
+               lws_tls_kid_copy(&ci,
+                                &ssl->kid_chain.skid[ssl->kid_chain.count]);
+
+       if (!lws_tls_mbedtls_cert_info(x509, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID,
+                                      &ci, 0))
+               lws_tls_kid_copy(&ci,
+                                &ssl->kid_chain.akid[ssl->kid_chain.count]);
+
+       ssl->kid_chain.count++;
+
+       // lwsl_notice("%s: %u\n", __func__, ssl->kid_chain.count);
+
        return 0;
 }
 
+#endif
+
 int
 lws_ssl_client_bio_create(struct lws *wsi)
 {
        char hostname[128], *p;
-       const char *alpn_comma = wsi->context->tls.alpn_default;
+       const char *alpn_comma = wsi->a.context->tls.alpn_default;
        struct alpn_ctx protos;
+       int fl = SSL_VERIFY_PEER;
 
-       if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
-                        _WSI_TOKEN_CLIENT_HOST) <= 0) {
-               lwsl_err("%s: Unable to get hostname\n", __func__);
+       if (wsi->stash)
+               lws_strncpy(hostname, wsi->stash->cis[CIS_HOST], sizeof(hostname));
+       else
+               if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
+                               _WSI_TOKEN_CLIENT_HOST) <= 0) {
+                       lwsl_err("%s: Unable to get hostname\n", __func__);
 
-               return -1;
-       }
+                       return -1;
+               }
 
        /*
         * remove any :port part on the hostname... necessary for network
@@ -54,13 +99,18 @@ lws_ssl_client_bio_create(struct lws *wsi)
                p++;
        }
 
-       wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_client_ctx);
+       wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_client_ctx);
        if (!wsi->tls.ssl) {
                lwsl_info("%s: SSL_new() failed\n", __func__);
                return -1;
        }
 
-       if (wsi->vhost->tls.ssl_info_event_mask)
+#if defined(LWS_WITH_TLS_SESSIONS)
+       if (!(wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE))
+               lws_tls_reuse_session(wsi);
+#endif
+
+       if (wsi->a.vhost->tls.ssl_info_event_mask)
                SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
 
        if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
@@ -68,35 +118,127 @@ lws_ssl_client_bio_create(struct lws *wsi)
                /* Enable automatic hostname checks */
        //      X509_VERIFY_PARAM_set_hostflags(param,
        //                              X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
-               X509_VERIFY_PARAM_set1_host(param, hostname, 0);
+               lwsl_info("%s: setting hostname %s\n", __func__, hostname);
+               if (X509_VERIFY_PARAM_set1_host(param, hostname, 0) != 1)
+                       return -1;
        }
 
-       if (wsi->vhost->tls.alpn)
-               alpn_comma = wsi->vhost->tls.alpn;
+       if (wsi->a.vhost->tls.alpn)
+               alpn_comma = wsi->a.vhost->tls.alpn;
 
-       if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
-                        _WSI_TOKEN_CLIENT_ALPN) > 0)
-               alpn_comma = hostname;
+       if (wsi->stash) {
+               lws_strncpy(hostname, wsi->stash->cis[CIS_HOST],
+                               sizeof(hostname));
+               if (wsi->stash->cis[CIS_ALPN])
+                       alpn_comma = wsi->stash->cis[CIS_ALPN];
+       } else {
+               if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
+                               _WSI_TOKEN_CLIENT_ALPN) > 0)
+                       alpn_comma = hostname;
+       }
 
-       lwsl_info("%s: %p: client conn sending ALPN list '%s'\n",
-                 __func__, wsi, alpn_comma);
+       lwsl_info("%s: %s: client conn sending ALPN list '%s'\n",
+                 __func__, lws_wsi_tag(wsi), alpn_comma);
 
-       protos.len = lws_alpn_comma_to_openssl(alpn_comma, protos.data,
+       protos.len = (uint8_t)lws_alpn_comma_to_openssl(alpn_comma, protos.data,
                                               sizeof(protos.data) - 1);
 
        /* with mbedtls, protos is not pointed to after exit from this call */
        SSL_set_alpn_select_cb(wsi->tls.ssl, &protos);
 
+       if (wsi->flags & LCCSCF_ALLOW_SELFSIGNED) {
+               lwsl_notice("%s: allowing selfsigned\n", __func__);
+               fl = SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+       }
+
+       if (wsi->flags & LCCSCF_ALLOW_INSECURE)
+               fl = SSL_VERIFY_NONE;
+
        /*
         * use server name indication (SNI), if supported,
         * when establishing connection
         */
+#if defined(LWS_WITH_TLS_JIT_TRUST)
        SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER,
-                      OpenSSL_client_verify_callback);
+                       lws_mbedtls_client_verify_callback);
+       (void)fl;
+#else
+       SSL_set_verify(wsi->tls.ssl, fl, NULL);
+#endif
 
-       SSL_set_fd(wsi->tls.ssl, wsi->desc.sockfd);
+       SSL_set_fd(wsi->tls.ssl, (int)wsi->desc.sockfd);
+
+       if (wsi->sys_tls_client_cert) {
+               lws_system_blob_t *b = lws_system_get_blob(wsi->a.context,
+                                       LWS_SYSBLOB_TYPE_CLIENT_CERT_DER,
+                                       wsi->sys_tls_client_cert - 1);
+               const uint8_t *pem_data = NULL;
+               uint8_t *data = NULL;
+               lws_filepos_t flen;
+               size_t size;
+               int err = 0;
+
+               if (!b)
+                       goto no_client_cert;
+
+               /*
+                * Set up the per-connection client cert
+                */
+
+               size = lws_system_blob_get_size(b);
+               if (!size)
+                       goto no_client_cert;
+
+               if (lws_system_blob_get_single_ptr(b, &pem_data))
+                       goto no_client_cert;
+
+               if (lws_tls_alloc_pem_to_der_file(wsi->a.context, NULL,
+                                                 (const char *)pem_data, size,
+                                                 &data, &flen))
+                       goto no_client_cert;
+               size = (size_t) flen;
+
+               err = SSL_use_certificate_ASN1(wsi->tls.ssl, data, (int)size);
+               lws_free_set_NULL(data);
+               if (err != 1)
+                       goto no_client_cert;
+
+               b = lws_system_get_blob(wsi->a.context,
+                                       LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
+                                       wsi->sys_tls_client_cert - 1);
+               if (!b)
+                       goto no_client_cert;
+               size = lws_system_blob_get_size(b);
+               if (!size)
+                       goto no_client_cert;
+
+               if (lws_system_blob_get_single_ptr(b, &pem_data))
+                       goto no_client_cert;
+
+               if (lws_tls_alloc_pem_to_der_file(wsi->a.context, NULL,
+                                                 (const char *)pem_data, size,
+                                                 &data, &flen))
+                       goto no_client_cert;
+               size = (size_t) flen;
+
+               err = SSL_use_PrivateKey_ASN1(0, wsi->tls.ssl, data, (int)size);
+               lws_free_set_NULL(data);
+               if (err != 1)
+                       goto no_client_cert;
+
+               /* no wrapper api for check key */
+
+               lwsl_notice("%s: set system client cert %u\n", __func__,
+                               wsi->sys_tls_client_cert - 1);
+       }
 
        return 0;
+
+no_client_cert:
+       lwsl_err("%s: unable to set up system client cert %d\n", __func__,
+                       wsi->sys_tls_client_cert - 1);
+
+       return 1;
 }
 
 int ERR_get_error(void)
@@ -105,19 +247,20 @@ int ERR_get_error(void)
 }
 
 enum lws_ssl_capable_status
-lws_tls_client_connect(struct lws *wsi)
+lws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen)
 {
-       int m, n = SSL_connect(wsi->tls.ssl);
-       const unsigned char *prot;
-       unsigned int len;
+       int m, n = SSL_connect(wsi->tls.ssl), en;
 
        if (n == 1) {
-               SSL_get0_alpn_selected(wsi->tls.ssl, &prot, &len);
-               lws_role_call_alpn_negotiated(wsi, (const char *)prot);
-               lwsl_info("client connect OK\n");
+               lws_tls_server_conn_alpn(wsi);
+#if defined(LWS_WITH_TLS_SESSIONS)
+               lws_tls_session_new_mbedtls(wsi);
+#endif
+               lwsl_info("%s: client connect OK\n", __func__);
                return LWS_SSL_CAPABLE_DONE;
        }
 
+       en = (int)LWS_ERRNO;
        m = SSL_get_error(wsi->tls.ssl, n);
 
        if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl))
@@ -129,57 +272,91 @@ lws_tls_client_connect(struct lws *wsi)
        if (!n) /* we don't know what he wants, but he says to retry */
                return LWS_SSL_CAPABLE_MORE_SERVICE;
 
+       if (m == SSL_ERROR_SYSCALL && !en)
+               return LWS_SSL_CAPABLE_MORE_SERVICE;
+
+       lws_snprintf(errbuf, elen, "mbedtls connect %d %d %d", n, m, en);
+
        return LWS_SSL_CAPABLE_ERROR;
 }
 
 int
-lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len)
+lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, size_t ebuf_len)
 {
        int n;
+       unsigned int avoid = 0;
        X509 *peer = SSL_get_peer_certificate(wsi->tls.ssl);
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
+       const char *type = "";
        char *sb = (char *)&pt->serv_buf[0];
 
        if (!peer) {
+#if defined(LWS_WITH_SYS_METRICS)
+               lws_metrics_hist_bump_describe_wsi(wsi, lws_metrics_priv_to_pub(
+                                       wsi->a.context->mth_conn_failures),
+                                                  "tls=\"nocert\"");
+#endif
                lwsl_info("peer did not provide cert\n");
                lws_snprintf(ebuf, ebuf_len, "no peer cert");
 
                return -1;
        }
-       lwsl_info("peer provided cert\n");
 
-       n = SSL_get_verify_result(wsi->tls.ssl);
-       lws_latency(wsi->context, wsi,
-                       "SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0);
+       n = (int)SSL_get_verify_result(wsi->tls.ssl);
+       lwsl_debug("get_verify says %d\n", n);
 
-        lwsl_debug("get_verify says %d\n", n);
-
-       if (n == X509_V_OK)
+       switch (n) {
+       case X509_V_OK:
                return 0;
 
-       if (n == X509_V_ERR_HOSTNAME_MISMATCH &&
-           (wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
-               lwsl_info("accepting certificate for invalid hostname\n");
-               return 0;
+       case X509_V_ERR_HOSTNAME_MISMATCH:
+               type = "hostname";
+               avoid = LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
+               break;
+
+       case X509_V_ERR_INVALID_CA:
+               type = "invalidca";
+               avoid = LCCSCF_ALLOW_SELFSIGNED;
+               break;
+
+       case X509_V_ERR_CERT_NOT_YET_VALID:
+               type = "notyetvalid";
+               avoid = LCCSCF_ALLOW_EXPIRED;
+               break;
+
+       case X509_V_ERR_CERT_HAS_EXPIRED:
+               type = "expired";
+               avoid = LCCSCF_ALLOW_EXPIRED;
+               break;
        }
 
-       if (n == X509_V_ERR_INVALID_CA &&
-           (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)) {
-               lwsl_info("accepting certificate from untrusted CA\n");
-               return 0;
+       lwsl_info("%s: cert problem: %s\n", __func__, type);
+#if defined(LWS_WITH_SYS_METRICS)
+       {
+               char buckname[64];
+               lws_snprintf(buckname, sizeof(buckname), "tls=\"%s\"", type);
+               lws_metrics_hist_bump_describe_wsi(wsi,
+                    lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures),
+                             buckname);
        }
-
-       if ((n == X509_V_ERR_CERT_NOT_YET_VALID ||
-            n == X509_V_ERR_CERT_HAS_EXPIRED) &&
-            (wsi->tls.use_ssl & LCCSCF_ALLOW_EXPIRED)) {
-               lwsl_info("accepting expired or not yet valid certificate\n");
+#endif
+       if (wsi->tls.use_ssl & avoid) {
+               lwsl_info("%s: allowing anyway\n", __func__);
 
                return 0;
        }
+
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       if (n == X509_V_ERR_INVALID_CA)
+           lws_tls_jit_trust_sort_kids(wsi, &wsi->tls.ssl->kid_chain);
+#endif
        lws_snprintf(ebuf, ebuf_len,
-               "server's cert didn't look good, X509_V_ERR = %d: %s\n",
-                n, ERR_error_string(n, sb));
+               "server's cert didn't look good, %s (use_ssl 0x%x) X509_V_ERR = %d: %s\n",
+               type, (unsigned int)wsi->tls.use_ssl, n,
+               ERR_error_string((unsigned long)n, sb));
+
        lwsl_info("%s\n", ebuf);
+
        lws_tls_err_describe_clear();
 
        return -1;
@@ -195,24 +372,33 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                                    const char *cert_filepath,
                                    const void *cert_mem,
                                    unsigned int cert_mem_len,
-                                   const char *private_key_filepath)
+                                   const char *private_key_filepath,
+                                       const void *key_mem,
+                                       unsigned int key_mem_len
+                                       )
 {
        X509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len);
        SSL_METHOD *method = (SSL_METHOD *)TLS_client_method();
        unsigned long error;
        int n;
 
+#if defined(LWS_WITH_TLS_SESSIONS)
+       vh->tls_session_cache_max = info->tls_session_cache_max ?
+                                   info->tls_session_cache_max : 10;
+       lws_tls_session_cache(vh, info->tls_session_timeout);
+#endif
+
        if (!method) {
-               error = ERR_get_error();
+               error = (unsigned long)ERR_get_error();
                lwsl_err("problem creating ssl method %lu: %s\n",
                        error, ERR_error_string(error,
                                      (char *)vh->context->pt[0].serv_buf));
                return 1;
        }
        /* create context */
-       vh->tls.ssl_client_ctx = SSL_CTX_new(method);
+       vh->tls.ssl_client_ctx = SSL_CTX_new(method, &vh->context->mcdc);
        if (!vh->tls.ssl_client_ctx) {
-               error = ERR_get_error();
+               error = (unsigned long)ERR_get_error();
                lwsl_err("problem creating ssl context %lu: %s\n",
                        error, ERR_error_string(error,
                                      (char *)vh->context->pt[0].serv_buf));
@@ -231,13 +417,14 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                        lwsl_err("Load CA cert file %s failed\n", ca_filepath);
                        return 1;
                }
-               vh->tls.x509_client_CA = d2i_X509(NULL, buf, len);
+               vh->tls.x509_client_CA = d2i_X509(NULL, buf, (long)len);
                free(buf);
-               lwsl_notice("Loading client CA for verification %s\n", ca_filepath);
+
+               lwsl_info("Loading vh %s client CA for verification %s\n", vh->name, ca_filepath);
 #endif
        } else {
-               vh->tls.x509_client_CA = d2i_X509(NULL, (uint8_t*)ca_mem, ca_mem_len);
-               lwsl_notice("%s: using mem client CA cert %d\n",
+               vh->tls.x509_client_CA = d2i_X509(NULL, (uint8_t*)ca_mem, (long)ca_mem_len);
+               lwsl_info("%s: using mem client CA cert %d\n",
                            __func__, ca_mem_len);
        }
 
@@ -270,11 +457,8 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
 
                buf[amount++] = '\0';
 
-               SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx,
-                               buf, amount);
-
                n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx,
-                               amount, buf);
+                               (int)amount, buf);
                lws_free(buf);
                if (n < 1) {
                        lwsl_err("problem %d getting cert '%s'\n", n,
@@ -283,23 +467,75 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                        return 1;
                }
 
-               lwsl_notice("Loaded client cert %s\n", cert_filepath);
+               lwsl_info("Loaded client cert %s\n", cert_filepath);
 #endif
        } else if (cert_mem && cert_mem_len) {
-               // lwsl_hexdump_notice(cert_mem, cert_mem_len - 1);
-               SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx,
-                               cert_mem, cert_mem_len - 1);
+               /* lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); */
                n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx,
-                                                cert_mem_len, cert_mem);
+                                                (int)cert_mem_len, cert_mem);
                if (n < 1) {
-                       lwsl_err("%s: problem interpreting client cert\n",
+                       lwsl_err("%s: (mbedtls) problem interpreting client cert\n",
                                 __func__);
                        lws_tls_err_describe_clear();
                        return 1;
                }
-               lwsl_notice("%s: using mem client cert %d\n",
+               lwsl_info("%s: using mem client cert %d\n",
                            __func__, cert_mem_len);
        }
 
+       if (private_key_filepath) {
+#if !defined(LWS_PLAT_OPTEE)
+
+               uint8_t *buf;
+               lws_filepos_t amount;
+
+               lwsl_notice("%s: doing private key filepath %s\n", __func__,
+                               private_key_filepath);
+               if (alloc_file(vh->context, private_key_filepath, &buf, &amount))
+                       return 1;
+
+               buf[amount++] = '\0';
+
+               n = SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx,
+                               buf, (long)amount);
+
+               lws_free(buf);
+               if (n < 1) {
+                       lwsl_err("problem %d getting private key '%s'\n", n,
+                                private_key_filepath);
+                       lws_tls_err_describe_clear();
+                       return 1;
+               }
+
+               lwsl_notice("Loaded private key %s\n", private_key_filepath);
+#endif
+       } else if (key_mem && key_mem_len) {
+               /* lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); */
+               n = SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx,
+                               key_mem, (long)key_mem_len - 1);
+
+               if (n < 1) {
+                       lwsl_err("%s: (mbedtls) problem interpreting private key\n",
+                                __func__);
+                       lws_tls_err_describe_clear();
+                       return 1;
+               }
+               lwsl_info("%s: using mem private key %d\n",
+                           __func__, key_mem_len);
+
+       }
+       return 0;
+}
+
+int
+lws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh,
+                const uint8_t *der, size_t der_len)
+{
+       if (SSL_CTX_add_client_CA_ASN1(vh->tls.ssl_client_ctx, (int)der_len, der) != 1) {
+               lwsl_err("%s: failed\n", __func__);
+                       return 1;
+       }
+
        return 0;
 }
+
diff --git a/lib/tls/mbedtls/mbedtls-extensions.c b/lib/tls/mbedtls/mbedtls-extensions.c
new file mode 100644 (file)
index 0000000..dc406e8
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * These are additional apis that belong in mbedtls but do not yet exist there.
+ * Alternaives are provided for lws to use that understand additional standard
+ * v3 tls extensions.  Error results are simplified to lws style.
+ *
+ * This file includes code taken from mbedtls and modified, and from an as of
+ * 2021-06-11 unaccepted-upstream patch for mbedtls contributed by Gábor Tóth
+ * <toth92g@gmail.com>.  Gabor has graciously allowed use of his patch with more
+ * liberal terms but to not complicate matters I provide it here under the same
+ * Apache 2.0 terms as the mbedtls pieces.
+ *
+ * Those original pieces are licensed Apache-2.0 as follows
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-tls-mbedtls.h"
+#include <mbedtls/oid.h>
+#include <mbedtls/x509.h>
+
+/*
+ * This section from mbedtls oid.c
+ */
+
+typedef struct {
+    mbedtls_oid_descriptor_t    descriptor;
+    int                        ext_type;
+} oid_x509_ext_t;
+
+#define ADD_LEN(s)      s, MBEDTLS_OID_SIZE(s)
+
+#define LWS_MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER    MBEDTLS_OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 } */
+#define LWS_MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER      MBEDTLS_OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 14 } */
+
+#define LWS_MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER    (1 << 0)
+#define LWS_MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER      (1 << 1)
+
+#define LWS_MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER LWS_MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER
+#define LWS_MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER LWS_MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER
+
+#define LWS_MBEDTLS_X509_SAN_OTHER_NAME                      0
+#define LWS_MBEDTLS_X509_SAN_RFC822_NAME                     1
+#define LWS_MBEDTLS_X509_SAN_DNS_NAME                        2
+
+#define LWS_MBEDTLS_ASN1_TAG_CLASS_MASK          0xC0
+#define LWS_MBEDTLS_ASN1_TAG_VALUE_MASK                 0x1F
+
+static const oid_x509_ext_t oid_x509_ext[] = {
+    { {ADD_LEN( LWS_MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ),
+               "id-ce-subjectKeyIdentifier",
+               "Subject Key Identifier" },
+        LWS_MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER,
+    },
+    { {ADD_LEN( LWS_MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ),
+               "id-ce-authorityKeyIdentifier",
+               "Authority Key Identifier" },
+        LWS_MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER,
+    },
+    { { NULL, 0, NULL, NULL }, 0 },
+};
+
+#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST )                    \
+    static const TYPE_T * oid_ ## NAME ## _from_asn1(                   \
+                                      const mbedtls_asn1_buf *oid )     \
+    {                                                                   \
+        const TYPE_T *p = (LIST);                                       \
+        const mbedtls_oid_descriptor_t *cur =                           \
+            (const mbedtls_oid_descriptor_t *) p;                       \
+        if( p == NULL || oid == NULL ) return( NULL );                  \
+        while( cur->MBEDTLS_PRIVATE(asn1) != NULL ) {                          \
+            if( cur->MBEDTLS_PRIVATE(asn1_len) == oid->MBEDTLS_PRIVATE(len) && \
+                memcmp( cur->MBEDTLS_PRIVATE(asn1), oid->MBEDTLS_PRIVATE(p), oid->MBEDTLS_PRIVATE(len) ) == 0 ) {          \
+                return( p );                                            \
+            }                                                           \
+            p++;                                                        \
+            cur = (const mbedtls_oid_descriptor_t *) p;                 \
+        }                                                               \
+        return( NULL );                                                 \
+    }
+
+
+#define FN_OID_GET_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \
+int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 )                  \
+{                                                                       \
+    const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid );        \
+    if (!data) return 1;            \
+    *ATTR1 = data->ATTR1;                                               \
+    return 0;                                                        \
+}
+
+FN_OID_TYPED_FROM_ASN1(oid_x509_ext_t, x509_ext, oid_x509_ext)
+FN_OID_GET_ATTR1(lws_mbedtls_oid_get_x509_ext_type,
+                oid_x509_ext_t, x509_ext, int, ext_type)
+
+typedef struct lws_mbedtls_x509_san_other_name
+{
+    /**
+     * The type_id is an OID as deifned in RFC 5280.
+     * To check the value of the type id, you should use
+     * \p MBEDTLS_OID_CMP with a known OID mbedtls_x509_buf.
+     */
+    mbedtls_x509_buf type_id;                   /**< The type id. */
+    union
+    {
+        /**
+         * From RFC 4108 section 5:
+         * HardwareModuleName ::= SEQUENCE {
+         *                         hwType OBJECT IDENTIFIER,
+         *                         hwSerialNum OCTET STRING }
+         */
+        struct
+        {
+            mbedtls_x509_buf oid;               /**< The object identifier. */
+            mbedtls_x509_buf val;               /**< The named value. */
+        }
+        hardware_module_name;
+    }
+    value;
+}
+lws_mbedtls_x509_san_other_name;
+
+
+typedef struct lws_mbedtls_x509_subject_alternative_name
+{
+       int type;                              /**< The SAN type, value of LWS_MBEDTLS_X509_SAN_XXX. */
+       union {
+        lws_mbedtls_x509_san_other_name other_name; /**< The otherName supported type. */
+        mbedtls_x509_buf   unstructured_name; /**< The buffer for the un constructed types. Only dnsName currently supported */
+       }
+       san; /**< A union of the supported SAN types */
+}
+lws_mbedtls_x509_subject_alternative_name;
+
+static int
+x509_get_skid(uint8_t **p, const uint8_t *end, mbedtls_x509_buf *skid)
+{
+       int ret = 1;
+       size_t len = 0u;
+
+       ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
+       if (ret)
+               return ret;
+
+       skid->MBEDTLS_PRIVATE(len)      = len;
+       skid->MBEDTLS_PRIVATE(tag)      = MBEDTLS_ASN1_OCTET_STRING;
+       skid->MBEDTLS_PRIVATE(p)        = *p;
+       *p              += len;
+
+       return *p != end;
+}
+
+/*
+ * Names may have multiple allocated segments in a linked-list, when the mbedtls
+ * api mbedtls_x509_get_name() fails, it doesn't clean up any already-allocated
+ * segments, wrongly leaving it to the caller to handle.  This helper takes care
+ * of the missing cleaning for allocation error path.
+ *
+ * name.next must be set to NULL by user code before calling ...get_name(...,
+ * &name), since not every error exit sets it and it will contain garbage if
+ * defined on stack as is usual.
+ */
+
+static void
+lws_x509_clean_name(mbedtls_x509_name *name)
+{
+       mbedtls_x509_name *n1;
+
+       if (!name)
+               return;
+
+       n1 = name->MBEDTLS_PRIVATE(next);
+
+       while (n1) {
+               name = n1->MBEDTLS_PRIVATE(next);
+               free(n1);
+               n1 = name;
+       }
+}
+
+static int
+lws_mbedtls_x509_parse_general_name(const mbedtls_x509_buf *name_buf,
+                                   lws_mbedtls_x509_subject_alternative_name *name)
+{
+       // mbedtls_x509_name_other_name other_name;
+       uint8_t *bufferPointer, **p, *end;
+       mbedtls_x509_name rfc822Name;
+       int ret;
+
+       switch (name_buf->MBEDTLS_PRIVATE(tag) &
+                               (LWS_MBEDTLS_ASN1_TAG_CLASS_MASK |
+                                LWS_MBEDTLS_ASN1_TAG_VALUE_MASK)) {
+
+#if 0
+       case MBEDTLS_ASN1_CONTEXT_SPECIFIC | LWS_MBEDTLS_X509_SAN_OTHER_NAME:
+               ret = x509_get_other_name( name_buf, &other_name );
+               if (ret)
+                       return ret;
+
+               memset(name, 0, sizeof(*name));
+               name->type = LWS_MBEDTLS_X509_SAN_OTHER_NAME;
+               memcpy(&name->name.other_name, &other_name, sizeof(other_name));
+               return 0;
+#endif
+       case MBEDTLS_ASN1_SEQUENCE | LWS_MBEDTLS_X509_SAN_RFC822_NAME:
+
+               bufferPointer = name_buf->MBEDTLS_PRIVATE(p);
+               p = &bufferPointer;
+               end = name_buf->MBEDTLS_PRIVATE(p) +
+                     name_buf->MBEDTLS_PRIVATE(len);
+
+               /* The leading ASN1 tag and length has been processed.
+                * Stepping back with 2 bytes, because mbedtls_x509_get_name
+                * expects the beginning of the SET tag */
+               *p = *p - 2;
+
+               rfc822Name.MBEDTLS_PRIVATE(next) = NULL;
+               ret = mbedtls_x509_get_name( p, end, &rfc822Name );
+               if (ret) {
+                       lws_x509_clean_name(&rfc822Name);
+                       return ret;
+               }
+
+               memset(name, 0, sizeof(*name));
+               name->type = LWS_MBEDTLS_X509_SAN_OTHER_NAME;
+               memcpy(&name->san.other_name,
+                      &rfc822Name, sizeof(rfc822Name));
+               return 0;
+
+       case MBEDTLS_ASN1_CONTEXT_SPECIFIC | LWS_MBEDTLS_X509_SAN_DNS_NAME:
+               memset(name, 0, sizeof(*name));
+               name->type = LWS_MBEDTLS_X509_SAN_DNS_NAME;
+
+               memcpy(&name->san.unstructured_name,
+                      name_buf, sizeof(*name_buf) );
+               return 0;
+
+       default:
+               return 1;
+       }
+
+       return 1;
+}
+
+static int
+lws_x509_get_general_names(uint8_t **p, const uint8_t *end,
+                          mbedtls_x509_sequence *name )
+{
+       mbedtls_asn1_sequence *cur = name;
+       mbedtls_asn1_buf *buf;
+       size_t len, tag_len;
+       unsigned char tag;
+       int r;
+
+       /* Get main sequence tag */
+       r = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+                                              MBEDTLS_ASN1_SEQUENCE);
+       if (r)
+               return r;
+
+       if (*p + len != end)
+               return 1;
+
+       while (*p < end) {
+               lws_mbedtls_x509_subject_alternative_name dnb;
+               memset(&dnb, 0, sizeof(dnb));
+
+               tag = **p;
+               (*p)++;
+
+               r = mbedtls_asn1_get_len(p, end, &tag_len);
+               if (r)
+                   return r;
+
+               /* Tag shall be CONTEXT_SPECIFIC or SET */
+               if ((tag & LWS_MBEDTLS_ASN1_TAG_CLASS_MASK) !=
+                                               MBEDTLS_ASN1_CONTEXT_SPECIFIC &&
+                   (tag & (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) !=
+                          (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE))
+                       return 1;
+
+               /*
+                * Check that the name is structured correctly.
+                */
+               r = lws_mbedtls_x509_parse_general_name(
+                                       &cur->MBEDTLS_PRIVATE(buf), &dnb);
+               /*
+                * In case the extension is malformed, return an error,
+                * and clear the allocated sequences.
+                */
+               if (r && r != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) {
+                   mbedtls_x509_sequence *seq_cur = name->MBEDTLS_PRIVATE(next);
+                   mbedtls_x509_sequence *seq_prv;
+
+                       while( seq_cur != NULL ) {
+                               seq_prv = seq_cur;
+                               seq_cur = seq_cur->MBEDTLS_PRIVATE(next);
+                               lws_explicit_bzero(seq_prv, sizeof(*seq_cur));
+                               lws_free(seq_prv);
+                       }
+
+                       name->MBEDTLS_PRIVATE(next) = NULL;
+
+                       return r;
+               }
+
+               /* Allocate and assign next pointer */
+               if (cur->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(p)) {
+                       if (cur->MBEDTLS_PRIVATE(next))
+                               return 1;
+
+                       cur->MBEDTLS_PRIVATE(next) =
+                                       lws_zalloc(sizeof(*cur), __func__);
+
+                       if (!cur->MBEDTLS_PRIVATE(next))
+                               return 1;
+
+                       cur = cur->MBEDTLS_PRIVATE(next);
+               }
+
+               buf = &(cur->MBEDTLS_PRIVATE(buf));
+               buf->MBEDTLS_PRIVATE(tag) = tag;
+               buf->MBEDTLS_PRIVATE(p) = *p;
+               buf->MBEDTLS_PRIVATE(len) = tag_len;
+
+               *p += buf->MBEDTLS_PRIVATE(len);
+       }
+
+       /* Set final sequence entry's next pointer to NULL */
+       cur->MBEDTLS_PRIVATE(next) = NULL;
+
+       return *p != end;
+}
+
+static int
+x509_get_akid(uint8_t **p, uint8_t *end, lws_mbedtls_x509_authority *akid)
+{
+       size_t len = 0u;
+       int r;
+
+       r = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+                                                MBEDTLS_ASN1_SEQUENCE);
+       if (r)
+               return r;
+
+       r = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC);
+       if (!r) {
+               akid->keyIdentifier.MBEDTLS_PRIVATE(len) = len;
+               akid->keyIdentifier.MBEDTLS_PRIVATE(p) = *p;
+               akid->keyIdentifier.MBEDTLS_PRIVATE(tag) = MBEDTLS_ASN1_OCTET_STRING;
+
+               *p += len;
+       }
+
+       if (*p < end) {
+               /* Getting authorityCertIssuer using the required specific
+                * class tag [1] */
+               r = mbedtls_asn1_get_tag(p, end, &len,
+                                          MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+                                          MBEDTLS_ASN1_CONSTRUCTED | 1 );
+               if (!r) {
+                       /* Getting directoryName using the required specific
+                        * class tag [4] */
+                       r = mbedtls_asn1_get_tag(p, end, &len,
+                                                MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+                                                MBEDTLS_ASN1_CONSTRUCTED | 4);
+                       if (r)
+                               return(r);
+
+                       /* "end" also includes the CertSerialNumber field
+                        * so "len" shall be used */
+                       r = lws_x509_get_general_names(p, (*p + len),
+                                                   &akid->authorityCertIssuer);
+               }
+       }
+
+       if (*p < end) {
+               r = mbedtls_asn1_get_tag(p, end, &len,
+                                          MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+                                          MBEDTLS_ASN1_INTEGER );
+               if (r)
+                       return r;
+
+               akid->authorityCertSerialNumber.MBEDTLS_PRIVATE(len) = len;
+               akid->authorityCertSerialNumber.MBEDTLS_PRIVATE(p) = *p;
+               akid->authorityCertSerialNumber.MBEDTLS_PRIVATE(tag) = MBEDTLS_ASN1_OCTET_STRING;
+               *p += len;
+       }
+
+       return *p != end;
+}
+
+/*
+ * Work around lack of this in mbedtls... we don't need to do sanity checks
+ * sanity checks because they will be done at x509 validation time
+ */
+
+int
+lws_x509_get_crt_ext(mbedtls_x509_crt *crt, mbedtls_x509_buf *skid,
+                    lws_mbedtls_x509_authority *akid)
+{
+       uint8_t *p = crt->MBEDTLS_PRIVATE(v3_ext).MBEDTLS_PRIVATE(p),
+                                       *end_ext_data, *end_ext_octet;
+       const uint8_t *end = p + crt->MBEDTLS_PRIVATE(v3_ext).MBEDTLS_PRIVATE(len);
+       size_t len;
+       int r = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+                                                     MBEDTLS_ASN1_SEQUENCE);
+       if (r)
+               return r;
+
+       while (p < end) {
+               mbedtls_x509_buf extn_oid = { 0, 0, NULL };
+               int is_critical = 0; /* DEFAULT FALSE */
+               int ext_type = 0;
+
+               r = mbedtls_asn1_get_tag(&p, end, &len,
+                                          MBEDTLS_ASN1_CONSTRUCTED |
+                                          MBEDTLS_ASN1_SEQUENCE);
+               if (r)
+                       return r;
+
+               end_ext_data = p + len;
+
+               /* Get extension ID */
+               r = mbedtls_asn1_get_tag(&p, end_ext_data, &extn_oid.MBEDTLS_PRIVATE(len),
+                                          MBEDTLS_ASN1_OID);
+               if (r)
+                       return r;
+
+               extn_oid.MBEDTLS_PRIVATE(tag) = MBEDTLS_ASN1_OID;
+               extn_oid.MBEDTLS_PRIVATE(p) = p;
+               p += extn_oid.MBEDTLS_PRIVATE(len);
+
+               /* Get optional critical */
+               r = mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical);
+               if (r && r != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)
+                       return r;
+
+               /* Data should be octet string type */
+               r = mbedtls_asn1_get_tag(&p, end_ext_data, &len,
+                                          MBEDTLS_ASN1_OCTET_STRING);
+               if (r)
+                       return r;
+
+               end_ext_octet = p + len;
+
+               if (end_ext_octet != end_ext_data)
+                       return 1;
+
+               r = lws_mbedtls_oid_get_x509_ext_type(&extn_oid, &ext_type);
+               if (r) {
+                       p = end_ext_octet;
+                       continue;
+               }
+
+               switch (ext_type) {
+               case LWS_MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER:
+                       /* Parse subject key identifier */
+                       r = x509_get_skid(&p, end_ext_data, skid);
+                       if (r)
+                               return r;
+                       break;
+
+               case LWS_MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER:
+                       /* Parse authority key identifier */
+                       r = x509_get_akid(&p, end_ext_octet, akid);
+                       if (r)
+                               return r;
+                       break;
+
+               default:
+                       p = end_ext_octet;
+               }
+       }
+
+       return 0;
+}
index f993a54..ca703c5 100644 (file)
@@ -1,26 +1,30 @@
 /*
- * libwebsockets - mbedTLS-specific server functions
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 #include <mbedtls/x509_csr.h>
+#include <errno.h>
 
 int
 lws_tls_server_client_cert_verify_config(struct lws_vhost *vh)
@@ -34,15 +38,7 @@ lws_tls_server_client_cert_verify_config(struct lws_vhost *vh)
                return 0;
        }
 
-       /*
-        * The wrapper has this messed-up mapping:
-        *
-        *         else if (ctx->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
-        *     mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
-        *
-        * ie the meaning is inverted.  So where we should test for ! we don't
-        */
-       if (lws_check_opt(vh->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
+       if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
                verify_options = SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
 
        lwsl_notice("%s: vh %s requires client cert %d\n", __func__, vh->name,
@@ -121,7 +117,7 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                return 0;
        }
 
-       n = lws_tls_generic_cert_checks(vhost, cert, private_key);
+       n = (int)lws_tls_generic_cert_checks(vhost, cert, private_key);
 
        if (n == LWS_TLS_EXTANT_NO && (!mem_cert || !mem_privkey))
                return 0;
@@ -149,9 +145,6 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                 */
                cert = NULL;
                private_key = NULL;
-
-               if (!mem_cert)
-                       return 1;
        }
        if (lws_tls_alloc_pem_to_der_file(vhost->context, cert, mem_cert,
                                          mem_cert_len, &p, &flen)) {
@@ -160,7 +153,7 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                return 1;
        }
 
-       err = SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx, flen, p);
+       err = SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx, (int)flen, p);
        lws_free_set_NULL(p);
        if (!err) {
                lwsl_err("Problem loading cert\n");
@@ -175,7 +168,7 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                return 1;
        }
 
-       err = SSL_CTX_use_PrivateKey_ASN1(0, vhost->tls.ssl_ctx, p, flen);
+       err = SSL_CTX_use_PrivateKey_ASN1(0, vhost->tls.ssl_ctx, p, (long)flen);
        lws_free_set_NULL(p);
        if (!err) {
                lwsl_err("Problem loading key\n");
@@ -183,14 +176,6 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                return 1;
        }
 
-       if (!private_key && !mem_privkey && vhost->protocols[0].callback(wsi,
-                       LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
-                       vhost->tls.ssl_ctx, NULL, 0)) {
-               lwsl_err("ssl private key not set\n");
-
-               return 1;
-       }
-
        vhost->tls.skipped_certs = 0;
 
        return 0;
@@ -205,7 +190,7 @@ lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info,
        lws_filepos_t flen;
        int n;
 
-       vhost->tls.ssl_ctx = SSL_CTX_new(method);       /* create context */
+       vhost->tls.ssl_ctx = SSL_CTX_new(method, &vhost->context->mcdc);        /* create context */
        if (!vhost->tls.ssl_ctx) {
                lwsl_err("problem creating ssl context\n");
                return 1;
@@ -261,7 +246,7 @@ int
 lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
 {
        errno = 0;
-       wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_ctx);
+       wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_ctx);
        if (wsi->tls.ssl == NULL) {
                lwsl_err("SSL_new failed: errno %d\n", errno);
 
@@ -269,12 +254,12 @@ lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
                return 1;
        }
 
-       SSL_set_fd(wsi->tls.ssl, accept_fd);
+       SSL_set_fd(wsi->tls.ssl, (int)accept_fd);
 
-       if (wsi->vhost->tls.ssl_info_event_mask)
+       if (wsi->a.vhost->tls.ssl_info_event_mask)
                SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
 
-       SSL_set_sni_callback(wsi->tls.ssl, lws_mbedtls_sni_cb, wsi->context);
+       SSL_set_sni_callback(wsi->tls.ssl, lws_mbedtls_sni_cb, wsi->a.context);
 
        return 0;
 }
@@ -286,7 +271,9 @@ int
 #endif
 lws_tls_server_abort_connection(struct lws *wsi)
 {
-       __lws_tls_shutdown(wsi);
+       if (wsi->tls.use_ssl)
+               __lws_tls_shutdown(wsi);
+       
        SSL_free(wsi->tls.ssl);
 
        return 0;
@@ -299,9 +286,11 @@ lws_tls_server_accept(struct lws *wsi)
        int m, n;
 
        n = SSL_accept(wsi->tls.ssl);
+
+       wsi->skip_fallback = 1;
        if (n == 1) {
 
-               if (strstr(wsi->vhost->name, ".invalid")) {
+               if (strstr(wsi->a.vhost->name, ".invalid")) {
                        lwsl_notice("%s: vhost has .invalid, "
                                    "rejecting accept\n", __func__);
 
@@ -320,13 +309,18 @@ lws_tls_server_accept(struct lws *wsi)
        }
 
        m = SSL_get_error(wsi->tls.ssl, n);
-       lwsl_debug("%s: %p: accept SSL_get_error %d errno %d\n", __func__,
-                  wsi, m, errno);
+       lwsl_debug("%s: %s: accept SSL_get_error %d errno %d\n", __func__,
+                   lws_wsi_tag(wsi), m, errno);
 
        // mbedtls wrapper only
        if (m == SSL_ERROR_SYSCALL && errno == 11)
                return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
 
+#if defined(__APPLE__)
+       if (m == SSL_ERROR_SYSCALL && errno == 35)
+               return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+#endif
+
 #if defined(WIN32)
        if (m == SSL_ERROR_SYSCALL && errno == 0)
                return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
@@ -459,14 +453,14 @@ static uint8_t ss_cert_leadin[] = {
 
 #define SAN_A_LENGTH 78
 
-LWS_VISIBLE int
+int
 lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
                             const char *san_b)
 {
        int buflen = 0x560;
-       uint8_t *buf = lws_malloc(buflen, "tmp cert buf"), *p = buf, *pkey_asn1;
+       uint8_t *buf = lws_malloc((unsigned int)buflen, "tmp cert buf"), *p = buf, *pkey_asn1;
        struct lws_genrsa_ctx ctx;
-       struct lws_gencrypto_keyelem el;
+       struct lws_gencrypto_keyelem el[LWS_GENCRYPTO_RSA_KEYEL_COUNT];
        uint8_t digest[32];
        struct lws_genhash_ctx hash_ctx;
        int pkey_asn1_len = 3 * 1024;
@@ -475,44 +469,45 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
        if (!buf)
                return 1;
 
-       n = lws_genrsa_new_keypair(vhost->context, &ctx, &el, keybits);
+       n = lws_genrsa_new_keypair(vhost->context, &ctx, LGRSAM_PKCS1_1_5,
+                                  &el[0], keybits);
        if (n < 0) {
-               lws_genrsa_destroy_elements(&el);
+               lws_genrsa_destroy_elements(&el[0]);
                goto bail1;
        }
 
        n = sizeof(ss_cert_leadin);
-       memcpy(p, ss_cert_leadin, n);
+       memcpy(p, ss_cert_leadin, (unsigned int)n);
        p += n;
 
        adj = (0x0556 - 0x401) + (keybits / 4) + 1;
-       buf[2] = adj >> 8;
-       buf[3] = adj & 0xff;
+       buf[2] = (uint8_t)(adj >> 8);
+       buf[3] = (uint8_t)(adj & 0xff);
 
        adj = (0x033e - 0x201) + (keybits / 8) + 1;
-       buf[6] = adj >> 8;
-       buf[7] = adj & 0xff;
+       buf[6] = (uint8_t)(adj >> 8);
+       buf[7] = (uint8_t)(adj & 0xff);
 
        adj = (0x0222 - 0x201) + (keybits / 8) + 1;
-       buf[0xc3] = adj >> 8;
-       buf[0xc4] = adj & 0xff;
+       buf[0xc3] = (uint8_t)(adj >> 8);
+       buf[0xc4] = (uint8_t)(adj & 0xff);
 
        adj = (0x020f - 0x201) + (keybits / 8) + 1;
-       buf[0xd6] = adj >> 8;
-       buf[0xd7] = adj & 0xff;
+       buf[0xd6] = (uint8_t)(adj >> 8);
+       buf[0xd7] = (uint8_t)(adj & 0xff);
 
        adj = (0x020a - 0x201) + (keybits / 8) + 1;
-       buf[0xdb] = adj >> 8;
-       buf[0xdc] = adj & 0xff;
+       buf[0xdb] = (uint8_t)(adj >> 8);
+       buf[0xdc] = (uint8_t)(adj & 0xff);
 
-       *p++ = ((keybits / 8) + 1) >> 8;
-       *p++ = ((keybits / 8) + 1) & 0xff;
+       *p++ = (uint8_t)(((keybits / 8) + 1) >> 8);
+       *p++ = (uint8_t)(((keybits / 8) + 1) & 0xff);
 
        /* we need to drop 1 + (keybits / 8) bytes of n in here, 00 + key */
 
        *p++ = 0x00;
-       memcpy(p, el.e[LWS_GENCRYPTO_RSA_KEYEL_N].buf, el.e[LWS_GENCRYPTO_RSA_KEYEL_N].len);
-       p += el.e[LWS_GENCRYPTO_RSA_KEYEL_N].len;
+       memcpy(p, el[LWS_GENCRYPTO_RSA_KEYEL_N].buf, el[LWS_GENCRYPTO_RSA_KEYEL_N].len);
+       p += el[LWS_GENCRYPTO_RSA_KEYEL_N].len;
 
        memcpy(p, ss_cert_san_leadin, sizeof(ss_cert_san_leadin));
        p += sizeof(ss_cert_san_leadin);
@@ -523,8 +518,8 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
        p += SAN_A_LENGTH;
        memcpy(p, ss_cert_sig_leadin, sizeof(ss_cert_sig_leadin));
 
-       p[17] = ((keybits / 8) + 1) >> 8;
-       p[18] = ((keybits / 8) + 1) & 0xff;
+       p[17] = (uint8_t)(((keybits / 8) + 1) >> 8);
+       p[18] = (uint8_t)(((keybits / 8) + 1) & 0xff);
 
        p += sizeof(ss_cert_sig_leadin);
 
@@ -533,7 +528,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
        if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256))
                goto bail2;
 
-       if (lws_genhash_update(&hash_ctx, buf, lws_ptr_diff(p, buf))) {
+       if (lws_genhash_update(&hash_ctx, buf, lws_ptr_diff_size_t(p, buf))) {
                lws_genhash_destroy(&hash_ctx, NULL);
 
                goto bail2;
@@ -544,16 +539,16 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
        /* sign the hash */
 
        n = lws_genrsa_hash_sign(&ctx, digest, LWS_GENHASH_TYPE_SHA256, p,
-                                buflen - lws_ptr_diff(p, buf));
+                                (size_t)((size_t)buflen - lws_ptr_diff_size_t(p, buf)));
        if (n < 0)
                goto bail2;
        p += n;
 
-       pkey_asn1 = lws_malloc(pkey_asn1_len, "mbed crt tmp");
+       pkey_asn1 = lws_malloc((unsigned int)pkey_asn1_len, "mbed crt tmp");
        if (!pkey_asn1)
                goto bail2;
 
-       m = lws_genrsa_render_pkey_asn1(&ctx, 1, pkey_asn1, pkey_asn1_len);
+       m = lws_genrsa_render_pkey_asn1(&ctx, 1, pkey_asn1, (size_t)pkey_asn1_len);
        if (m < 0) {
                lws_free(pkey_asn1);
                goto bail2;
@@ -581,7 +576,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
        }
 
        lws_genrsa_destroy(&ctx);
-       lws_genrsa_destroy_elements(&el);
+       lws_genrsa_destroy_elements(&el[0]);
 
        lws_free(buf);
 
@@ -589,7 +584,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
 
 bail2:
        lws_genrsa_destroy(&ctx);
-       lws_genrsa_destroy_elements(&el);
+       lws_genrsa_destroy_elements(&el[0]);
 bail1:
        lws_free(buf);
 
@@ -617,7 +612,7 @@ static const char *x5[] = { "C", "ST", "L", "O", "CN" };
  * CSR is output formatted as b64url(DER)
  * Private key is output as a PEM in memory
  */
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
                            uint8_t *dcsr, size_t csr_len, char **privkey_pem,
                            size_t *privkey_len)
@@ -626,7 +621,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
        mbedtls_pk_context mpk;
        int buf_size = 4096, n;
        char subject[200], *p = subject, *end = p + sizeof(subject) - 1;
-       uint8_t *buf = malloc(buf_size); /* malloc because given to user code */
+       uint8_t *buf = malloc((unsigned int)buf_size); /* malloc because given to user code */
 
        if (!buf)
                return -1;
@@ -640,7 +635,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
        }
 
        n = mbedtls_rsa_gen_key(mbedtls_pk_rsa(mpk), _rngf, context,
-                               lws_plat_recommended_rsa_bits(), 65537);
+                               (unsigned int)lws_plat_recommended_rsa_bits(), 65537);
        if (n) {
                lwsl_notice("%s: failed to generate keys\n", __func__);
 
@@ -653,7 +648,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
                if (p != subject)
                        *p++ = ',';
                if (elements[n])
-                       p += lws_snprintf(p, end - p, "%s=%s", x5[n],
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s=%s", x5[n],
                                          elements[n]);
        }
 
@@ -668,7 +663,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
         * return value to determine where you should start
         * using the buffer
         */
-       n = mbedtls_x509write_csr_der(&csr, buf, buf_size, _rngf, context);
+       n = mbedtls_x509write_csr_der(&csr, buf, (size_t)buf_size, _rngf, context);
        if (n < 0) {
                lwsl_notice("%s: write csr der failed\n", __func__);
                goto fail1;
@@ -676,7 +671,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
 
        /* we have it in DER, we need it in b64URL */
 
-       n = lws_jws_base64_enc((char *)(buf + buf_size) - n, n,
+       n = lws_jws_base64_enc((char *)(buf + buf_size) - n, (size_t)n,
                               (char *)dcsr, csr_len);
        if (n < 0)
                goto fail1;
@@ -687,7 +682,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
         * one step
         */
 
-       if (mbedtls_pk_write_key_pem(&mpk, buf, buf_size)) {
+       if (mbedtls_pk_write_key_pem(&mpk, buf, (size_t)buf_size)) {
                lwsl_notice("write key pem failed\n");
                goto fail1;
        }
diff --git a/lib/tls/mbedtls/mbedtls-session.c b/lib/tls/mbedtls/mbedtls-session.c
new file mode 100644 (file)
index 0000000..a774ffb
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+typedef struct lws_tls_session_cache_mbedtls {
+       lws_dll2_t                      list;
+
+       mbedtls_ssl_session             session;
+       lws_sorted_usec_list_t          sul_ttl;
+
+       /* name is overallocated here */
+} lws_tls_scm_t;
+
+#define lwsl_tlssess lwsl_info
+
+
+
+static void
+__lws_tls_session_destroy(lws_tls_scm_t *ts)
+{
+       lwsl_tlssess("%s: %s (%u)\n", __func__, (const char *)&ts[1],
+                                    (unsigned int)(ts->list.owner->count - 1));
+
+       lws_sul_cancel(&ts->sul_ttl);
+       mbedtls_ssl_session_free(&ts->session);
+       lws_dll2_remove(&ts->list);             /* vh lock */
+
+       lws_free(ts);
+}
+
+static lws_tls_scm_t *
+__lws_tls_session_lookup_by_name(struct lws_vhost *vh, const char *name)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, p,
+                             lws_dll2_get_head(&vh->tls_sessions)) {
+               lws_tls_scm_t *ts = lws_container_of(p, lws_tls_scm_t, list);
+               const char *ts_name = (const char *)&ts[1];
+
+               if (!strcmp(name, ts_name))
+                       return ts;
+
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
+/*
+ * If possible, reuse an existing, cached session
+ */
+
+void
+lws_tls_reuse_session(struct lws *wsi)
+{
+       char buf[LWS_SESSION_TAG_LEN];
+       mbedtls_ssl_context *msc;
+       lws_tls_scm_t *ts;
+
+       if (!wsi->a.vhost ||
+           wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
+               return;
+
+       lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */
+       lws_vhost_lock(wsi->a.vhost); /* -------------- vh { */
+
+       if (lws_tls_session_tag_from_wsi(wsi, buf, sizeof(buf)))
+               goto bail;
+
+       ts = __lws_tls_session_lookup_by_name(wsi->a.vhost, buf);
+
+       if (!ts) {
+               lwsl_tlssess("%s: no existing session for %s\n", __func__, buf);
+               goto bail;
+       }
+
+       lwsl_tlssess("%s: %s\n", __func__, (const char *)&ts[1]);
+       wsi->tls_session_reused = 1;
+
+       msc = SSL_mbedtls_ssl_context_from_SSL(wsi->tls.ssl);
+       mbedtls_ssl_set_session(msc, &ts->session);
+
+       /* keep our session list sorted in lru -> mru order */
+
+       lws_dll2_remove(&ts->list);
+       lws_dll2_add_tail(&ts->list, &wsi->a.vhost->tls_sessions);
+
+bail:
+       lws_vhost_unlock(wsi->a.vhost); /* } vh --------------  */
+       lws_context_unlock(wsi->a.context); /* } cx --------------  */
+}
+
+int
+lws_tls_session_is_reused(struct lws *wsi)
+{
+#if defined(LWS_WITH_CLIENT)
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+
+       if (!nwsi)
+               return 0;
+
+       return nwsi->tls_session_reused;
+#else
+       return 0;
+#endif
+}
+
+static int
+lws_tls_session_destroy_dll(struct lws_dll2 *d, void *user)
+{
+       lws_tls_scm_t *ts = lws_container_of(d, lws_tls_scm_t, list);
+
+       __lws_tls_session_destroy(ts);
+
+       return 0;
+}
+
+void
+lws_tls_session_vh_destroy(struct lws_vhost *vh)
+{
+       lws_dll2_foreach_safe(&vh->tls_sessions, NULL,
+                             lws_tls_session_destroy_dll);
+}
+
+static void
+lws_tls_session_expiry_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_tls_scm_t *ts = lws_container_of(sul, lws_tls_scm_t, sul_ttl);
+       struct lws_vhost *vh = lws_container_of(ts->list.owner,
+                                               struct lws_vhost, tls_sessions);
+
+       lws_context_lock(vh->context, __func__); /* -------------- cx { */
+       lws_vhost_lock(vh); /* -------------- vh { */
+       __lws_tls_session_destroy(ts);
+       lws_vhost_unlock(vh); /* } vh --------------  */
+       lws_context_unlock(vh->context); /* } cx --------------  */
+}
+
+/*
+ * Called after SSL_accept on the wsi
+ */
+
+int
+lws_tls_session_new_mbedtls(struct lws *wsi)
+{
+       char buf[LWS_SESSION_TAG_LEN];
+       mbedtls_ssl_context *msc;
+       struct lws_vhost *vh;
+       lws_tls_scm_t *ts;
+       size_t nl;
+#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
+       const char *disposition = "reuse";
+#endif
+
+       vh = wsi->a.vhost;
+       if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
+               return 0;
+
+       if (lws_tls_session_tag_from_wsi(wsi, buf, sizeof(buf)))
+               return 0;
+
+       nl = strlen(buf);
+
+       msc = SSL_mbedtls_ssl_context_from_SSL(wsi->tls.ssl);
+
+       lws_context_lock(vh->context, __func__); /* -------------- cx { */
+       lws_vhost_lock(vh); /* -------------- vh { */
+
+       ts = __lws_tls_session_lookup_by_name(vh, buf);
+
+       if (!ts) {
+               /*
+                * We have to make our own, new session
+                */
+
+               if (vh->tls_sessions.count == vh->tls_session_cache_max) {
+
+                       /*
+                        * We have reached the vhost's session cache limit,
+                        * prune the LRU / head
+                        */
+                       ts = lws_container_of(vh->tls_sessions.head,
+                                             lws_tls_scm_t, list);
+
+                       lwsl_tlssess("%s: pruning oldest session (hit max %u)\n",
+                                    __func__,
+                                    (unsigned int)vh->tls_session_cache_max);
+
+                       lws_vhost_lock(vh); /* -------------- vh { */
+                       __lws_tls_session_destroy(ts);
+                       lws_vhost_unlock(vh); /* } vh --------------  */
+               }
+
+               ts = lws_malloc(sizeof(*ts) + nl + 1, __func__);
+
+               if (!ts)
+                       goto bail;
+
+               memset(ts, 0, sizeof(*ts));
+               memcpy(&ts[1], buf, nl + 1);
+
+               if (mbedtls_ssl_get_session(msc, &ts->session)) {
+                       lws_free(ts);
+                       /* no joy for whatever reason */
+                       goto bail;
+               }
+
+               lws_dll2_add_tail(&ts->list, &vh->tls_sessions);
+
+               lws_sul_schedule(wsi->a.context, wsi->tsi, &ts->sul_ttl,
+                                lws_tls_session_expiry_cb,
+                                (int64_t)vh->tls.tls_session_cache_ttl *
+                                                        LWS_US_PER_SEC);
+
+#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
+               disposition = "new";
+#endif
+       } else {
+
+               mbedtls_ssl_session_free(&ts->session);
+
+               if (mbedtls_ssl_get_session(msc, &ts->session))
+                       /* no joy for whatever reason */
+                       goto bail;
+
+               /* keep our session list sorted in lru -> mru order */
+
+               lws_dll2_remove(&ts->list);
+               lws_dll2_add_tail(&ts->list, &vh->tls_sessions);
+       }
+
+       lws_vhost_unlock(vh); /* } vh --------------  */
+       lws_context_unlock(vh->context); /* } cx --------------  */
+
+       lwsl_tlssess("%s: %s: %s %s, (%s:%u)\n", __func__,
+                    wsi->lc.gutag, disposition, buf, vh->name,
+                    (unsigned int)vh->tls_sessions.count);
+
+       /*
+        * indicate we will hold on to the SSL_SESSION reference, and take
+        * responsibility to call SSL_SESSION_free() on it ourselves
+        */
+
+       return 1;
+
+bail:
+       lws_vhost_unlock(vh); /* } vh --------------  */
+       lws_context_unlock(vh->context); /* } cx --------------  */
+
+       return 0;
+}
+
+#if defined(LWS_TLS_SYNTHESIZE_CB)
+
+/*
+ * On openssl, there is an async cb coming when the server issues the session
+ * information on the link, so we can pick it up and update the cache at the
+ * right time.
+ *
+ * On mbedtls and some version at least of borning ssl, this cb is either not
+ * part of the tls library apis or fails to arrive.
+ */
+
+void
+lws_sess_cache_synth_cb(lws_sorted_usec_list_t *sul)
+{
+       struct lws_lws_tls *tls = lws_container_of(sul, struct lws_lws_tls,
+                                                  sul_cb_synth);
+       struct lws *wsi = lws_container_of(tls, struct lws, tls);
+
+       lws_tls_session_new_mbedtls(wsi);
+}
+#endif
+
+void
+lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl)
+{
+       /* Default to 1hr max recommendation from RFC5246 F.1.4 */
+       vh->tls.tls_session_cache_ttl = !ttl ? 3600 : ttl;
+}
+
+int
+lws_tls_session_dump_save(struct lws_vhost *vh, const char *host, uint16_t port,
+                         lws_tls_sess_cb_t cb_save, void *opq)
+{
+       /* there seems no serialization / deserialization helper in mbedtls */
+       lwsl_warn("%s: only supported on openssl atm\n", __func__);
+
+       return 1;
+}
+
+int
+lws_tls_session_dump_load(struct lws_vhost *vh, const char *host, uint16_t port,
+                         lws_tls_sess_cb_t cb_load, void *opq)
+{
+       /* there seems no serialization / deserialization helper in mbedtls */
+       lwsl_warn("%s: only supported on openssl atm\n", __func__);
+
+       return 1;
+}
similarity index 56%
rename from lib/tls/mbedtls/ssl.c
rename to lib/tls/mbedtls/mbedtls-ssl.c
index 4e8d20b..5fe9220 100644 (file)
@@ -1,29 +1,31 @@
 /*
- * libwebsockets - mbedTLS-specific lws apis
+ * libwebsockets - small server side websockets and web server implementation
  *
  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-#include "tls/mbedtls/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls-mbedtls.h"
 
-
-LWS_VISIBLE void
+void
 lws_ssl_destroy(struct lws_vhost *vhost)
 {
        if (!lws_check_opt(vhost->context->options,
@@ -39,37 +41,26 @@ lws_ssl_destroy(struct lws_vhost *vhost)
                X509_free(vhost->tls.x509_client_CA);
 }
 
-LWS_VISIBLE int
-lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
+int
+lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, size_t len)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        int n = 0, m;
 
        if (!wsi->tls.ssl)
                return lws_ssl_capable_read_no_ssl(wsi, buf, len);
 
-       lws_stats_bump(pt, LWSSTATS_C_API_READ, 1);
-
        errno = 0;
-       n = SSL_read(wsi->tls.ssl, buf, len);
-#if defined(LWS_WITH_ESP32)
+       n = SSL_read(wsi->tls.ssl, buf, (int)len);
+#if defined(LWS_PLAT_FREERTOS)
        if (!n && errno == LWS_ENOTCONN) {
-               lwsl_debug("%p: SSL_read ENOTCONN\n", wsi);
+               lwsl_debug("%s: SSL_read ENOTCONN\n", lws_wsi_tag(wsi));
                return LWS_SSL_CAPABLE_ERROR;
        }
 #endif
-#if defined(LWS_WITH_STATS)
-       if (!wsi->seen_rx && wsi->accept_start_us) {
-                lws_stats_bump(pt, LWSSTATS_US_SSL_RX_DELAY_AVG,
-                       lws_now_usecs() - wsi->accept_start_us);
-                lws_stats_bump(pt, LWSSTATS_C_SSL_CONNS_HAD_RX, 1);
-               wsi->seen_rx = 1;
-       }
-#endif
-
 
-       lwsl_debug("%p: SSL_read says %d\n", wsi, n);
+       lwsl_debug("%s: %s: SSL_read says %d\n", __func__, lws_wsi_tag(wsi), n);
        /* manpage: returning 0 means connection shut down */
        if (!n) {
                wsi->socket_is_permanently_unusable = 1;
@@ -79,35 +70,59 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
 
        if (n < 0) {
                m = SSL_get_error(wsi->tls.ssl, n);
-               lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno);
-               if (errno == LWS_ENOTCONN) {
+               lwsl_debug("%s: %s: ssl err %d errno %d\n", __func__, lws_wsi_tag(wsi), m, errno);
+               if (errno == LWS_ENOTCONN)
                        /* If the socket isn't connected anymore, bail out. */
-                       wsi->socket_is_permanently_unusable = 1;
-                       return LWS_SSL_CAPABLE_ERROR;
-               }
+                       goto do_err1;
+
+#if defined(LWS_PLAT_FREERTOS)
+               if (errno == LWS_ECONNABORTED)
+                       goto do_err1;
+#endif
+
                if (m == SSL_ERROR_ZERO_RETURN ||
                    m == SSL_ERROR_SYSCALL)
-                       return LWS_SSL_CAPABLE_ERROR;
+                       goto do_err;
 
                if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) {
                        lwsl_debug("%s: WANT_READ\n", __func__);
-                       lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
+                       lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi));
                        return LWS_SSL_CAPABLE_MORE_SERVICE;
                }
                if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) {
-                       lwsl_debug("%s: WANT_WRITE\n", __func__);
-                       lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
+                       lwsl_info("%s: WANT_WRITE\n", __func__);
+                       lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi));
+                       wsi->tls_read_wanted_write = 1;
+                       lws_callback_on_writable(wsi);
                        return LWS_SSL_CAPABLE_MORE_SERVICE;
                }
+
+do_err1:
                wsi->socket_is_permanently_unusable = 1;
 
+do_err:
+#if defined(LWS_WITH_SYS_METRICS)
+       if (wsi->a.vhost)
+               lws_metric_event(wsi->a.vhost->mt_traffic_rx, METRES_NOGO, 0);
+#endif
+
                return LWS_SSL_CAPABLE_ERROR;
        }
 
-       lws_stats_bump(pt, LWSSTATS_B_READ, n);
+#if defined(LWS_TLS_LOG_PLAINTEXT_RX)
+       /*
+        * If using mbedtls type tls library, this is the earliest point for all
+        * paths to dump what was received as decrypted data from the tls tunnel
+        */
+       lwsl_notice("%s: len %d\n", __func__, n);
+       lwsl_hexdump_notice(buf, (size_t)n);
+#endif
 
-       if (wsi->vhost)
-               wsi->vhost->conn_stats.rx += n;
+#if defined(LWS_WITH_SYS_METRICS)
+       if (wsi->a.vhost)
+               lws_metric_event(wsi->a.vhost->mt_traffic_rx,
+                                METRES_GO /* rx */, (u_mt_t)n);
+#endif
 
        /*
         * if it was our buffer that limited what we read,
@@ -116,15 +131,17 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
         * Because these won't signal at the network layer with POLLIN
         * and if we don't realize, this data will sit there forever
         */
-       if (n != len)
+       if (n != (int)len)
                goto bail;
        if (!wsi->tls.ssl)
                goto bail;
 
-       if (SSL_pending(wsi->tls.ssl) &&
-           lws_dll2_is_detached(&wsi->tls.dll_pending_tls))
-               lws_dll2_add_head(&wsi->tls.dll_pending_tls,
-                                &pt->tls.dll_pending_tls_owner);
+       if (SSL_pending(wsi->tls.ssl)) {
+               if (lws_dll2_is_detached(&wsi->tls.dll_pending_tls))
+                       lws_dll2_add_head(&wsi->tls.dll_pending_tls,
+                                         &pt->tls.dll_pending_tls_owner);
+       } else
+               __lws_ssl_remove_wsi_from_buffered_list(wsi);
 
        return n;
 bail:
@@ -133,7 +150,7 @@ bail:
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_ssl_pending(struct lws *wsi)
 {
        if (!wsi->tls.ssl)
@@ -142,17 +159,33 @@ lws_ssl_pending(struct lws *wsi)
        return SSL_pending(wsi->tls.ssl);
 }
 
-LWS_VISIBLE int
-lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
+int
+lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, size_t len)
 {
        int n, m;
 
+#if defined(LWS_TLS_LOG_PLAINTEXT_TX)
+       /*
+        * If using mbedtls type tls library, this is the last point for all
+        * paths before sending data into the tls tunnel, where you can dump it
+        * and see what is being sent.
+        */
+       lwsl_notice("%s: len %d\n", __func__, (int)len);
+       lwsl_hexdump_notice(buf, len);
+#endif
+
        if (!wsi->tls.ssl)
                return lws_ssl_capable_write_no_ssl(wsi, buf, len);
 
-       n = SSL_write(wsi->tls.ssl, buf, len);
-       if (n > 0)
+       n = SSL_write(wsi->tls.ssl, buf, (int)len);
+       if (n > 0) {
+#if defined(LWS_WITH_SYS_METRICS)
+               if (wsi->a.vhost)
+                       lws_metric_event(wsi->a.vhost->mt_traffic_tx,
+                                        METRES_GO, (u_mt_t)n);
+#endif
                return n;
+       }
 
        m = SSL_get_error(wsi->tls.ssl, n);
        if (m != SSL_ERROR_SYSCALL) {
@@ -173,6 +206,12 @@ lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
        lwsl_debug("%s failed: %d\n",__func__, m);
        wsi->socket_is_permanently_unusable = 1;
 
+#if defined(LWS_WITH_SYS_METRICS)
+               if (wsi->a.vhost)
+                       lws_metric_event(wsi->a.vhost->mt_traffic_tx,
+                                        METRES_NOGO, (u_mt_t)n);
+#endif
+
        return LWS_SSL_CAPABLE_ERROR;
 }
 
@@ -194,20 +233,20 @@ lws_ssl_info_callback(const SSL *ssl, int where, int ret)
        if (!wsi)
                return;
 
-       if (!(where & wsi->vhost->tls.ssl_info_event_mask))
+       if (!(where & wsi->a.vhost->tls.ssl_info_event_mask))
                return;
 
        si.where = where;
        si.ret = ret;
 
-       if (user_callback_handle_rxflow(wsi->protocol->callback,
+       if (user_callback_handle_rxflow(wsi->a.protocol->callback,
                                        wsi, LWS_CALLBACK_SSL_INFO,
                                        wsi->user_space, &si, 0))
                lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
 }
 
 
-LWS_VISIBLE int
+int
 lws_ssl_close(struct lws *wsi)
 {
        lws_sockfd_type n;
@@ -219,10 +258,19 @@ lws_ssl_close(struct lws *wsi)
        /* kill ssl callbacks, becausse we will remove the fd from the
         * table linking it to the wsi
         */
-       if (wsi->vhost->tls.ssl_info_event_mask)
+       if (wsi->a.vhost->tls.ssl_info_event_mask)
                SSL_set_info_callback(wsi->tls.ssl, NULL);
 #endif
 
+#if defined(LWS_TLS_SYNTHESIZE_CB)
+       lws_sul_cancel(&wsi->tls.sul_cb_synth);
+       /*
+        * ... check the session in case it did not live long enough to get
+        * the scheduled callback to sample it
+        */
+       lws_sess_cache_synth_cb(&wsi->tls.sul_cb_synth);
+#endif
+
        n = SSL_get_fd(wsi->tls.ssl);
        if (!wsi->socket_is_permanently_unusable)
                SSL_shutdown(wsi->tls.ssl);
@@ -230,16 +278,7 @@ lws_ssl_close(struct lws *wsi)
        SSL_free(wsi->tls.ssl);
        wsi->tls.ssl = NULL;
 
-       if (!lwsi_role_client(wsi) &&
-           wsi->context->simultaneous_ssl_restriction &&
-           wsi->context->simultaneous_ssl-- ==
-                           wsi->context->simultaneous_ssl_restriction)
-               /* we made space and can do an accept */
-               lws_gate_accepts(wsi->context, 1);
-
-#if defined(LWS_WITH_STATS)
-       wsi->context->updated = 1;
-#endif
+       lws_tls_restrict_return(wsi);
 
        return 1; /* handled */
 }
@@ -280,7 +319,7 @@ __lws_tls_shutdown(struct lws *wsi)
 
        switch (n) {
        case 1: /* successful completion */
-               n = shutdown(wsi->desc.sockfd, SHUT_WR);
+               (void)shutdown(wsi->desc.sockfd, SHUT_WR);
                return LWS_SSL_CAPABLE_DONE;
 
        case 0: /* needs a retry */
diff --git a/lib/tls/mbedtls/mbedtls-tls.c b/lib/tls/mbedtls/mbedtls-tls.c
new file mode 100644 (file)
index 0000000..6ae4039
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-tls-mbedtls.h"
+
+void
+lws_tls_err_describe_clear(void)
+{
+}
+
+int
+lws_context_init_ssl_library(struct lws_context *cx,
+                            const struct lws_context_creation_info *info)
+{
+       lwsl_info(" Compiled with MbedTLS support");
+
+       if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
+               lwsl_info(" SSL disabled: no "
+                         "LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT");
+
+       return 0;
+}
+
+void
+lws_context_deinit_ssl_library(struct lws_context *context)
+{
+
+}
diff --git a/lib/tls/mbedtls/mbedtls-x509.c b/lib/tls/mbedtls/mbedtls-x509.c
new file mode 100644 (file)
index 0000000..2dad865
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-tls-mbedtls.h"
+#include <mbedtls/oid.h>
+
+#if defined(LWS_PLAT_OPTEE) || defined(OPTEE_DEV_KIT)
+struct tm {
+int    tm_sec; //   seconds [0,61]
+int    tm_min; //   minutes [0,59]
+int    tm_hour; //  hour [0,23]
+int    tm_mday; //  day of month [1,31]
+int    tm_mon; //   month of year [0,11]
+int    tm_year; //  years since 1900
+int    tm_wday; //  day of week [0,6] (Sunday = 0)
+int    tm_yday; //  day of year [0,365]
+int    tm_isdst; // daylight savings flag
+};
+time_t mktime(struct tm *t)
+{
+       return (time_t)0;
+}
+#endif
+
+static time_t
+lws_tls_mbedtls_time_to_unix(mbedtls_x509_time *xtime)
+{
+       struct tm t;
+
+       if (!xtime || !xtime->MBEDTLS_PRIVATE(year) || xtime->MBEDTLS_PRIVATE(year) < 0)
+               return (time_t)(long long)-1;
+
+       memset(&t, 0, sizeof(t));
+
+       t.tm_year = xtime->MBEDTLS_PRIVATE(year) - 1900;
+       t.tm_mon = xtime->MBEDTLS_PRIVATE(mon) - 1; /* mbedtls months are 1+, tm are 0+ */
+       t.tm_mday = xtime->MBEDTLS_PRIVATE(day) - 1; /* mbedtls days are 1+, tm are 0+ */
+       t.tm_hour = xtime->MBEDTLS_PRIVATE(hour);
+       t.tm_min = xtime->MBEDTLS_PRIVATE(min);
+       t.tm_sec = xtime->MBEDTLS_PRIVATE(sec);
+       t.tm_isdst = -1;
+
+       return mktime(&t);
+}
+
+static int
+lws_tls_mbedtls_get_x509_name(mbedtls_x509_name *name,
+                             union lws_tls_cert_info_results *buf, size_t len)
+{
+       int r = -1;
+
+       buf->ns.len = 0;
+
+       while (name) {
+               /*
+               if (MBEDTLS_OID_CMP(type, &name->oid)) {
+                       name = name->next;
+                       continue;
+               }
+*/
+               lws_strnncpy(&buf->ns.name[buf->ns.len],
+                            (const char *)name->MBEDTLS_PRIVATE(val).MBEDTLS_PRIVATE(p),
+                            name->MBEDTLS_PRIVATE(val).MBEDTLS_PRIVATE(len),
+                            len - (size_t)buf->ns.len);
+               buf->ns.len = (int)strlen(buf->ns.name);
+
+               r = 0;
+               name = name->MBEDTLS_PRIVATE(next);
+       }
+
+       return r;
+}
+
+
+int
+lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type,
+                         union lws_tls_cert_info_results *buf, size_t len)
+{
+       mbedtls_x509_buf skid;
+       lws_mbedtls_x509_authority akid;
+
+       if (!x509)
+               return -1;
+
+       if (!len)
+               len = sizeof(buf->ns.name);
+
+       switch (type) {
+       case LWS_TLS_CERT_INFO_VALIDITY_FROM:
+               buf->time = lws_tls_mbedtls_time_to_unix(&x509->MBEDTLS_PRIVATE(valid_from));
+               if (buf->time == (time_t)(long long)-1)
+                       return -1;
+               break;
+
+       case LWS_TLS_CERT_INFO_VALIDITY_TO:
+               buf->time = lws_tls_mbedtls_time_to_unix(&x509->MBEDTLS_PRIVATE(valid_to));
+               if (buf->time == (time_t)(long long)-1)
+                       return -1;
+               break;
+
+       case LWS_TLS_CERT_INFO_COMMON_NAME:
+               return lws_tls_mbedtls_get_x509_name(&x509->MBEDTLS_PRIVATE(subject), buf, len);
+
+       case LWS_TLS_CERT_INFO_ISSUER_NAME:
+               return lws_tls_mbedtls_get_x509_name(&x509->MBEDTLS_PRIVATE(issuer), buf, len);
+
+       case LWS_TLS_CERT_INFO_USAGE:
+               buf->usage = x509->MBEDTLS_PRIVATE(key_usage);
+               break;
+
+       case LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY:
+       {
+               char *p = buf->ns.name;
+               size_t r = len, u;
+
+               switch (mbedtls_pk_get_type(&x509->MBEDTLS_PRIVATE(pk))) {
+               case MBEDTLS_PK_RSA:
+               {
+                       mbedtls_rsa_context *rsa = mbedtls_pk_rsa(x509->MBEDTLS_PRIVATE(pk));
+
+                       if (mbedtls_mpi_write_string(&rsa->MBEDTLS_PRIVATE(N), 16, p, r, &u))
+                               return -1;
+                       r -= u;
+                       p += u;
+                       if (mbedtls_mpi_write_string(&rsa->MBEDTLS_PRIVATE(E), 16, p, r, &u))
+                               return -1;
+
+                       p += u;
+                       buf->ns.len = lws_ptr_diff(p, buf->ns.name);
+                       break;
+               }
+               case MBEDTLS_PK_ECKEY:
+               {
+                       mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(x509->MBEDTLS_PRIVATE(pk));
+
+                       if (mbedtls_mpi_write_string(&ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), 16, p, r, &u))
+                                return -1;
+                       r -= u;
+                       p += u;
+                       if (mbedtls_mpi_write_string(&ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), 16, p, r, &u))
+                                return -1;
+                       r -= u;
+                       p += u;
+                       if (mbedtls_mpi_write_string(&ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 16, p, r, &u))
+                                return -1;
+                       p += u;
+                       buf->ns.len = lws_ptr_diff(p, buf->ns.name);
+                       break;
+               }
+               default:
+                       lwsl_notice("%s: x509 has unsupported pubkey type %d\n",
+                                   __func__,
+                                   mbedtls_pk_get_type(&x509->MBEDTLS_PRIVATE(pk)));
+
+                       return -1;
+               }
+               break;
+       }
+       case LWS_TLS_CERT_INFO_DER_RAW:
+
+               buf->ns.len = (int)x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len);
+
+               if (len < x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))
+                       /*
+                        * The buffer is too small and the attempt failed, but
+                        * the required object length is in buf->ns.len
+                        */
+                       return -1;
+
+               memcpy(buf->ns.name, x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
+                               x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len));
+               break;
+
+       case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID:
+
+               memset(&akid, 0, sizeof(akid));
+               memset(&skid, 0, sizeof(skid));
+
+               lws_x509_get_crt_ext(x509, &skid, &akid);
+               if (akid.keyIdentifier.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING)
+                       return 1;
+               buf->ns.len = (int)akid.keyIdentifier.MBEDTLS_PRIVATE(len);
+               if (!akid.keyIdentifier.MBEDTLS_PRIVATE(p) ||
+                   len < (size_t)buf->ns.len)
+                       return -1;
+               memcpy(buf->ns.name, akid.keyIdentifier.MBEDTLS_PRIVATE(p), (size_t)buf->ns.len);
+               break;
+
+       case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER: {
+               mbedtls_x509_sequence * ip;
+
+               memset(&akid, 0, sizeof(akid));
+               memset(&skid, 0, sizeof(skid));
+
+               lws_x509_get_crt_ext(x509, &skid, &akid);
+
+               ip = &akid.authorityCertIssuer;
+
+               buf->ns.len = 0;
+
+               while (ip) {
+                       if (akid.keyIdentifier.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING ||
+                           !ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(p) ||
+                           ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) < 9 ||
+                           len < (size_t)ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) - 9u)
+                       break;
+
+                       memcpy(buf->ns.name + buf->ns.len, ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(p),
+                                       (size_t)ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) - 9);
+                       buf->ns.len = buf->ns.len + (int)ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) - 9;
+
+                       ip = ip->MBEDTLS_PRIVATE(next);
+               }
+               break;
+       }
+       case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_SERIAL:
+
+               memset(&akid, 0, sizeof(akid));
+               memset(&skid, 0, sizeof(skid));
+
+               lws_x509_get_crt_ext(x509, &skid, &akid);
+
+               if (akid.authorityCertSerialNumber.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING)
+                       return 1;
+               buf->ns.len = (int)akid.authorityCertSerialNumber.MBEDTLS_PRIVATE(len);
+               if (!akid.authorityCertSerialNumber.MBEDTLS_PRIVATE(p) ||
+                   len < (size_t)buf->ns.len)
+                       return -1;
+               memcpy(buf->ns.name, akid.authorityCertSerialNumber.
+                                       MBEDTLS_PRIVATE(p), (size_t)buf->ns.len);
+               break;
+
+       case LWS_TLS_CERT_INFO_SUBJECT_KEY_ID:
+
+               memset(&akid, 0, sizeof(akid));
+               memset(&skid, 0, sizeof(skid));
+
+               lws_x509_get_crt_ext(x509, &skid, &akid);
+
+               if (skid.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING)
+                       return 1;
+               buf->ns.len = (int)skid.MBEDTLS_PRIVATE(len);
+               if (len < (size_t)buf->ns.len)
+                       return -1;
+               memcpy(buf->ns.name, skid.MBEDTLS_PRIVATE(p), (size_t)buf->ns.len);
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+#if defined(LWS_WITH_NETWORK)
+int
+lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
+                       union lws_tls_cert_info_results *buf, size_t len)
+{
+       mbedtls_x509_crt *x509;
+
+       x509 = ssl_ctx_get_mbedtls_x509_crt(vhost->tls.ssl_ctx);
+
+       return lws_tls_mbedtls_cert_info(x509, type, buf, len);
+}
+
+int
+lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
+                      union lws_tls_cert_info_results *buf, size_t len)
+{
+       mbedtls_x509_crt *x509;
+
+       wsi = lws_get_network_wsi(wsi);
+
+       x509 = ssl_get_peer_mbedtls_x509_crt(wsi->tls.ssl);
+
+       if (!x509)
+               return -1;
+
+       switch (type) {
+       case LWS_TLS_CERT_INFO_VERIFIED:
+               buf->verified = SSL_get_verify_result(wsi->tls.ssl) == X509_V_OK;
+               return 0;
+       default:
+               return lws_tls_mbedtls_cert_info(x509, type, buf, len);
+       }
+
+       return -1;
+}
+#endif
+
+int
+lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type,
+             union lws_tls_cert_info_results *buf, size_t len)
+{
+       return lws_tls_mbedtls_cert_info(&x509->cert, type, buf, len);
+}
+
+int
+lws_x509_create(struct lws_x509_cert **x509)
+{
+       *x509 = lws_malloc(sizeof(**x509), __func__);
+
+       return !(*x509);
+}
+
+/*
+ * Parse one DER-encoded or one or more concatenated PEM-encoded certificates
+ * and add them to the chained list.
+ */
+
+int
+lws_x509_parse_from_pem(struct lws_x509_cert *x509, const void *pem, size_t len)
+{
+       int ret;
+
+       mbedtls_x509_crt_init(&x509->cert);
+
+       ret = mbedtls_x509_crt_parse(&x509->cert, pem, len);
+       if (ret) {
+               if (ret > 0)
+                       mbedtls_x509_crt_free(&x509->cert);
+               lwsl_err("%s: unable to parse PEM cert: -0x%x\n",
+                        __func__, -ret);
+
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+lws_x509_verify(struct lws_x509_cert *x509, struct lws_x509_cert *trusted,
+               const char *common_name)
+{
+       uint32_t flags = 0;
+       int ret;
+
+       ret = mbedtls_x509_crt_verify_with_profile(&x509->cert, &trusted->cert,
+                                                  NULL,
+                                                  &mbedtls_x509_crt_profile_next,
+                                                  common_name, &flags, NULL,
+                                                  NULL);
+
+       if (ret) {
+               lwsl_err("%s: unable to parse PEM cert: -0x%x\n",
+                        __func__, -ret);
+
+               return -1;
+       }
+
+       return 0;
+}
+
+#if defined(LWS_WITH_JOSE)
+
+int
+lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509,
+                      const char *curves, int rsa_min_bits)
+{
+       int kt = (int)mbedtls_pk_get_type(&x509->cert.MBEDTLS_PRIVATE(pk)),
+                       n, count = 0, ret = -1;
+       mbedtls_rsa_context *rsactx;
+       mbedtls_ecp_keypair *ecpctx;
+       mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT];
+
+       memset(jwk, 0, sizeof(*jwk));
+
+       switch (kt) {
+       case MBEDTLS_PK_RSA:
+               lwsl_notice("%s: RSA key\n", __func__);
+               jwk->kty = LWS_GENCRYPTO_KTY_RSA;
+               rsactx = mbedtls_pk_rsa(x509->cert.MBEDTLS_PRIVATE(pk));
+
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_E] = &rsactx->MBEDTLS_PRIVATE(E);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_N] = &rsactx->MBEDTLS_PRIVATE(N);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_D] = &rsactx->MBEDTLS_PRIVATE(D);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_P] = &rsactx->MBEDTLS_PRIVATE(P);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_Q] = &rsactx->MBEDTLS_PRIVATE(Q);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_DP] = &rsactx->MBEDTLS_PRIVATE(DP);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_DQ] = &rsactx->MBEDTLS_PRIVATE(DQ);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_QI] = &rsactx->MBEDTLS_PRIVATE(QP);
+
+               count = LWS_GENCRYPTO_RSA_KEYEL_QI + 1;
+               n = LWS_GENCRYPTO_RSA_KEYEL_E;
+               break;
+
+       case MBEDTLS_PK_ECKEY:
+               lwsl_notice("%s: EC key\n", __func__);
+               jwk->kty = LWS_GENCRYPTO_KTY_EC;
+               ecpctx = mbedtls_pk_ec(x509->cert.MBEDTLS_PRIVATE(pk));
+               mpi[LWS_GENCRYPTO_EC_KEYEL_X] = &ecpctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X);
+               mpi[LWS_GENCRYPTO_EC_KEYEL_D] = &ecpctx->MBEDTLS_PRIVATE(d);
+               mpi[LWS_GENCRYPTO_EC_KEYEL_Y] = &ecpctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y);
+
+               if (lws_genec_confirm_curve_allowed_by_tls_id(curves,
+                               (int)ecpctx->MBEDTLS_PRIVATE(grp).id, jwk))
+                       /* already logged */
+                       goto bail;
+
+               count = LWS_GENCRYPTO_EC_KEYEL_COUNT;
+               n = LWS_GENCRYPTO_EC_KEYEL_X;
+               break;
+       default:
+               lwsl_err("%s: key type %d not supported\n", __func__, kt);
+
+               return -1;
+       }
+
+       for (; n < count; n++) {
+               if (!mbedtls_mpi_size(mpi[n]))
+                       continue;
+
+               jwk->e[n].buf = lws_malloc(mbedtls_mpi_size(mpi[n]), "certjwk");
+               if (!jwk->e[n].buf)
+                       goto bail;
+               jwk->e[n].len = (uint32_t)mbedtls_mpi_size(mpi[n]);
+               mbedtls_mpi_write_binary(mpi[n], jwk->e[n].buf, jwk->e[n].len);
+       }
+
+       ret = 0;
+
+bail:
+       /* jwk destroy will clean up partials */
+       if (ret)
+               lws_jwk_destroy(jwk);
+
+       return ret;
+}
+
+int
+lws_x509_jwk_privkey_pem(struct lws_context *cx, struct lws_jwk *jwk,
+                        void *pem, size_t len, const char *passphrase)
+{
+       mbedtls_rsa_context *rsactx;
+       mbedtls_ecp_keypair *ecpctx;
+       mbedtls_pk_context pk;
+       mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT];
+       int n, ret = -1, count = 0;
+
+       mbedtls_pk_init(&pk);
+
+       n = 0;
+       if (passphrase)
+               n = (int)strlen(passphrase);
+       n = mbedtls_pk_parse_key(&pk, pem, len, (uint8_t *)passphrase, (unsigned int)n
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+                                       , mbedtls_ctr_drbg_random, &cx->mcdc
+#endif
+                       );
+       if (n) {
+               lwsl_err("%s: parse PEM key failed: -0x%x\n", __func__, -n);
+
+               return -1;
+       }
+
+       /* the incoming private key type */
+       switch (mbedtls_pk_get_type(&pk)) {
+       case MBEDTLS_PK_RSA:
+               if (jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
+                       lwsl_err("%s: RSA privkey, non-RSA jwk\n", __func__);
+                       goto bail;
+               }
+               rsactx = mbedtls_pk_rsa(pk);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_D] = &rsactx->MBEDTLS_PRIVATE(D);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_P] = &rsactx->MBEDTLS_PRIVATE(P);
+               mpi[LWS_GENCRYPTO_RSA_KEYEL_Q] = &rsactx->MBEDTLS_PRIVATE(Q);
+               n = LWS_GENCRYPTO_RSA_KEYEL_D;
+               count = LWS_GENCRYPTO_RSA_KEYEL_Q + 1;
+               break;
+       case MBEDTLS_PK_ECKEY:
+               if (jwk->kty != LWS_GENCRYPTO_KTY_EC) {
+                       lwsl_err("%s: EC privkey, non-EC jwk\n", __func__);
+                       goto bail;
+               }
+               ecpctx = mbedtls_pk_ec(pk);
+               mpi[LWS_GENCRYPTO_EC_KEYEL_D] = &ecpctx->MBEDTLS_PRIVATE(d);
+               n = LWS_GENCRYPTO_EC_KEYEL_D;
+               count = n + 1;
+               break;
+       default:
+               lwsl_err("%s: unusable key type %d\n", __func__,
+                               mbedtls_pk_get_type(&pk));
+               goto bail;
+       }
+
+       for (; n < count; n++) {
+               if (!mbedtls_mpi_size(mpi[n])) {
+                       lwsl_err("%s: empty privkey\n", __func__);
+                       goto bail;
+               }
+
+               jwk->e[n].buf = lws_malloc(mbedtls_mpi_size(mpi[n]), "certjwk");
+               if (!jwk->e[n].buf)
+                       goto bail;
+               jwk->e[n].len = (uint32_t)mbedtls_mpi_size(mpi[n]);
+               mbedtls_mpi_write_binary(mpi[n], jwk->e[n].buf, jwk->e[n].len);
+       }
+
+       ret = 0;
+
+bail:
+       mbedtls_pk_free(&pk);
+
+       return ret;
+}
+#endif
+
+void
+lws_x509_destroy(struct lws_x509_cert **x509)
+{
+       if (!*x509)
+               return;
+
+       mbedtls_x509_crt_free(&(*x509)->cert);
+
+       lws_free_set_NULL(*x509);
+}
diff --git a/lib/tls/mbedtls/private-lib-tls-mbedtls.h b/lib/tls/mbedtls/private-lib-tls-mbedtls.h
new file mode 100644 (file)
index 0000000..162d972
--- /dev/null
@@ -0,0 +1,59 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *  gencrypto mbedtls-specific helper declarations
+ */
+
+#include <mbedtls/x509_crl.h>
+#include <errno.h>
+
+struct lws_x509_cert {
+       mbedtls_x509_crt cert; /* has a .next for linked-list / chain */
+};
+
+typedef struct lws_mbedtls_x509_authority
+{
+       mbedtls_x509_buf        keyIdentifier;
+       mbedtls_x509_sequence   authorityCertIssuer;
+       mbedtls_x509_buf        authorityCertSerialNumber;
+       mbedtls_x509_buf        raw;
+}
+lws_mbedtls_x509_authority;
+
+
+mbedtls_md_type_t
+lws_gencrypto_mbedtls_hash_to_MD_TYPE(enum lws_genhash_types hash_type);
+
+int
+lws_gencrypto_mbedtls_rngf(void *context, unsigned char *buf, size_t len);
+
+int
+lws_tls_session_new_mbedtls(struct lws *wsi);
+
+int
+lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type,
+                         union lws_tls_cert_info_results *buf, size_t len);
+
+int
+lws_x509_get_crt_ext(mbedtls_x509_crt *crt, mbedtls_x509_buf *skid,
+                    lws_mbedtls_x509_authority *akid);
diff --git a/lib/tls/mbedtls/private.h b/lib/tls/mbedtls/private.h
deleted file mode 100644 (file)
index a87a4a4..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  gencrypto mbedtls-specific helper declarations
- */
-
-#include <mbedtls/x509_crl.h>
-
-struct lws_x509_cert {
-       mbedtls_x509_crt cert; /* has a .next for linked-list / chain */
-};
-
-mbedtls_md_type_t
-lws_gencrypto_mbedtls_hash_to_MD_TYPE(enum lws_genhash_types hash_type);
-
-int
-lws_gencrypto_mbedtls_rngf(void *context, unsigned char *buf, size_t len);
diff --git a/lib/tls/mbedtls/tls.c b/lib/tls/mbedtls/tls.c
deleted file mode 100644 (file)
index ecb0949..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * libwebsockets - mbedTLS-specific lws apis
- *
- * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-#include "tls/mbedtls/private.h"
-
-void
-lws_tls_err_describe_clear(void)
-{
-}
-
-int
-lws_context_init_ssl_library(const struct lws_context_creation_info *info)
-{
-       lwsl_info(" Compiled with MbedTLS support\n");
-
-       if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
-               lwsl_info(" SSL disabled: no "
-                         "LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
-
-       return 0;
-}
-
-void
-lws_context_deinit_ssl_library(struct lws_context *context)
-{
-
-}
index 86cf31a..ab344f4 100644 (file)
@@ -28,7 +28,7 @@
  *
  * @return certification object point
  */
-CERT *__ssl_cert_new(CERT *ic);
+CERT *__ssl_cert_new(CERT *ic, void *rngctx);
 
 /**
  * @brief create a certification object include private key object
@@ -37,7 +37,7 @@ CERT *__ssl_cert_new(CERT *ic);
  *
  * @return certification object point
  */
-CERT* ssl_cert_new(void);
+CERT* ssl_cert_new(void *rngctx);
 
 /**
  * @brief free a certification object
index ad32cb9..3b342db 100644 (file)
@@ -15,7 +15,7 @@
 #ifndef _SSL_DEBUG_H_
 #define _SSL_DEBUG_H_
 
-#include "platform/ssl_port.h"
+#include "ssl_port.h"
 
 #ifdef __cplusplus
  extern "C" {
index e790fcc..edb7446 100644 (file)
@@ -28,7 +28,7 @@
  *
  * @return new private key object point
  */
-EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk);
+EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk, void *rngctx);
 
 /**
  * @brief create a private key object
@@ -37,7 +37,7 @@ EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk);
  *
  * @return private key object point
  */
-EVP_PKEY* EVP_PKEY_new(void);
+EVP_PKEY* EVP_PKEY_new(void *rngctx);
 
 /**
  * @brief load a character key context into system context. If '*a' is pointed to the
@@ -53,7 +53,7 @@ EVP_PKEY* EVP_PKEY_new(void);
 EVP_PKEY* d2i_PrivateKey(int type,
                          EVP_PKEY **a,
                          const unsigned char **pp,
-                         long length);
+                         long length, void *rngctx);
 
 /**
  * @brief free a private key object
index 1f5f948..564a94d 100644 (file)
@@ -19,9 +19,9 @@
  extern "C" {
 #endif
 
-//#include "core/private.h"
+//#include "private-lib-core.h"
 #include <lws_config.h>
-#if defined(LWS_WITH_ESP32)
+#if defined(LWS_PLAT_FREERTOS)
  /* AMAZON RTOS has its own setting via MTK_MBEDTLS_CONFIG_FILE */
  #if !defined(LWS_AMAZON_RTOS)
   #undef MBEDTLS_CONFIG_FILE
 
 #include "ssl_code.h"
 
+#include <mbedtls/x509_crt.h>
+
+#include "private-jit-trust.h"
+
 typedef void SSL_CIPHER;
 
 typedef void X509_STORE_CTX;
@@ -183,7 +187,7 @@ struct ssl_ctx_st
 
     int verify_mode;
 
-    int (*default_verify_callback) (int ok, X509_STORE_CTX *ctx);
+    int (*default_verify_callback) (SSL *, mbedtls_x509_crt *);
 
     long session_timeout;
 
@@ -192,6 +196,8 @@ struct ssl_ctx_st
     int read_buffer_len;
 
     X509_VERIFY_PARAM param;
+
+    void *rngctx;
 };
 
 struct ssl_st
@@ -223,7 +229,11 @@ struct ssl_st
 
     int verify_mode;
 
-    int (*verify_callback) (int ok, X509_STORE_CTX *ctx);
+    int (*verify_callback) (SSL *, mbedtls_x509_crt *);
+
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+    lws_tls_kid_chain_t                kid_chain;
+#endif
 
     int rwstate;
     int interrupted_remaining_write;
@@ -292,7 +302,7 @@ struct x509_method_st {
 
 struct pkey_method_st {
 
-    int (*pkey_new)(EVP_PKEY *pkey, EVP_PKEY *m_pkey);
+    int (*pkey_new)(EVP_PKEY *pkey, EVP_PKEY *m_pkey, void *rngctx);
 
     void (*pkey_free)(EVP_PKEY *pkey);
 
index 7594d06..98e0268 100644 (file)
@@ -99,7 +99,8 @@ int SSL_add_client_CA(SSL *ssl, X509 *x);
  *     1 : OK
  *
  */
-int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d);
+
+int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
 
 const char *X509_verify_cert_error_string(long n);
 
index 9427283..8ff1e77 100755 (executable)
@@ -20,8 +20,8 @@
 #endif\r
 \r
 #include <stdlib.h>\r
-#include "internal/ssl_x509.h"\r
-#include "internal/ssl_pkey.h"\r
+#include "ssl_x509.h"\r
+#include "ssl_pkey.h"\r
 \r
 /*\r
 {\r
@@ -51,6 +51,8 @@
 \r
  SSL *SSL_SSL_from_mbedtls_ssl_context(mbedtls_ssl_context *msc);\r
 \r
+ mbedtls_ssl_context *SSL_mbedtls_ssl_context_from_SSL(SSL *ssl);\r
+\r
 /**\r
  * @brief create a SSL context\r
  *\r
@@ -58,7 +60,7 @@
  *\r
  * @return the context point\r
  */\r
-SSL_CTX* SSL_CTX_new(const SSL_METHOD *method);\r
+SSL_CTX* SSL_CTX_new(const SSL_METHOD *method, void *rngctx);\r
 \r
 /**\r
  * @brief free a SSL context\r
@@ -706,7 +708,7 @@ int SSL_CTX_get_verify_depth(const SSL_CTX *ctx);
  *\r
  * @return none\r
  */\r
-void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *));\r
+void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(SSL *, mbedtls_x509_crt *));\r
 \r
 /**\r
  * @brief set the SSL verifying of the SSL context\r
@@ -717,7 +719,7 @@ void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509
  *\r
  * @return none\r
  */\r
-void SSL_set_verify(SSL *s, int mode, int (*verify_callback)(int, X509_STORE_CTX *));\r
+void SSL_set_verify(SSL *s, int mode, int (*verify_callback)(SSL *, mbedtls_x509_crt *));\r
 \r
 /**\r
  * @brief set the SSL verify depth of the SSL context\r
@@ -737,7 +739,7 @@ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth);
  *\r
  * @return verifying result\r
  */\r
-int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx);\r
+int verify_callback(SSL *, mbedtls_x509_crt *);\r
 \r
 /**\r
  * @brief set the session timeout time\r
index cbbe3aa..874d2d1 100644 (file)
@@ -48,7 +48,7 @@ int x509_pm_new(X509 *x, X509 *m_x);
 void x509_pm_free(X509 *x);
 int x509_pm_load(X509 *x, const unsigned char *buffer, int len);
 
-int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pk);
+int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pk, void *rngctx);
 void pkey_pm_free(EVP_PKEY *pk);
 int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len);
 
index 5c60812..dab197c 100644 (file)
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "private-lib-core.h"
+
 #include "ssl_cert.h"
 #include "ssl_pkey.h"
 #include "ssl_x509.h"
@@ -21,7 +23,7 @@
 /**
  * @brief create a certification object according to input certification
  */
-CERT *__ssl_cert_new(CERT *ic)
+CERT *__ssl_cert_new(CERT *ic, void *rngctx)
 {
     CERT *cert;
 
@@ -42,7 +44,7 @@ CERT *__ssl_cert_new(CERT *ic)
         ix = NULL;
     }
 
-    cert->pkey = __EVP_PKEY_new(ipk);
+    cert->pkey = __EVP_PKEY_new(ipk, rngctx);
     if (!cert->pkey) {
         SSL_DEBUG(SSL_CERT_ERROR_LEVEL, "__EVP_PKEY_new() return NULL");
         goto pkey_err;
@@ -67,9 +69,9 @@ no_mem:
 /**
  * @brief create a certification object include private key object
  */
-CERT *ssl_cert_new(void)
+CERT *ssl_cert_new(void *rngctx)
 {
-    return __ssl_cert_new(NULL);
+    return __ssl_cert_new(NULL, rngctx);
 }
 
 /**
index ec46fd8..d751d78 100644 (file)
@@ -12,6 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+
+#include "private-lib-core.h"
+
 #include "ssl_lib.h"
 #include "ssl_pkey.h"
 #include "ssl_x509.h"
@@ -19,8 +22,6 @@
 #include "ssl_dbg.h"
 #include "ssl_port.h"
 
-#include "core/private.h"
-
 char *
 lws_strncpy(char *dest, const char *src, size_t size);
 
@@ -179,14 +180,19 @@ OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl)
     return state;
 }
 
+const char *mbedtls_client_preload_filepath;
+
 /**
  * @brief create a SSL context
  */
-SSL_CTX* SSL_CTX_new(const SSL_METHOD *method)
+SSL_CTX* SSL_CTX_new(const SSL_METHOD *method, void *rngctx)
 {
     SSL_CTX *ctx;
     CERT *cert;
     X509 *client_ca;
+#if defined(LWS_HAVE_mbedtls_x509_crt_parse_file)
+    int n;
+#endif
 
     if (!method) {
         SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "no no_method");
@@ -199,7 +205,7 @@ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method)
         goto failed1;
     }
 
-    cert = ssl_cert_new();
+    cert = ssl_cert_new(rngctx);
     if (!cert) {
         SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "ssl_cert_new() return NULL");
         goto failed2;
@@ -214,9 +220,24 @@ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method)
     ctx->method = method;
     ctx->client_CA = client_ca;
     ctx->cert = cert;
+    ctx->rngctx = rngctx;
 
     ctx->version = method->version;
 
+#if defined(LWS_HAVE_mbedtls_x509_crt_parse_file)
+    if (mbedtls_client_preload_filepath) {
+       mbedtls_x509_crt **px = (mbedtls_x509_crt **)ctx->client_CA->x509_pm;
+
+       *px = malloc(sizeof(**px));
+       mbedtls_x509_crt_init(*px);
+       n = mbedtls_x509_crt_parse_file(*px, mbedtls_client_preload_filepath);
+       if (n < 0)
+               lwsl_err("%s: unable to load cert bundle 0x%x\n", __func__, -n);
+       else
+               lwsl_info("%s: loaded cert bundle %d\n", __func__, n);
+    }
+#endif
+
     return ctx;
 
 failed3:
@@ -238,8 +259,10 @@ void SSL_CTX_free(SSL_CTX* ctx)
 
     X509_free(ctx->client_CA);
 
-    if (ctx->alpn_protos)
-           ssl_mem_free(ctx->alpn_protos);
+    if (ctx->alpn_protos) {
+           ssl_mem_free((void *)ctx->alpn_protos);
+           ctx->alpn_protos = NULL;
+    }
 
     ssl_mem_free(ctx);
 }
@@ -294,7 +317,7 @@ SSL *SSL_new(SSL_CTX *ctx)
         goto failed2;
     }
 
-    ssl->cert = __ssl_cert_new(ctx->cert);
+    ssl->cert = __ssl_cert_new(ctx->cert, ctx->rngctx);
     if (!ssl->cert) {
         SSL_DEBUG(SSL_LIB_ERROR_LEVEL, "__ssl_cert_new() return NULL");
         goto failed3;
@@ -353,8 +376,10 @@ void SSL_free(SSL *ssl)
 
     SSL_SESSION_free(ssl->session);
 
-    if (ssl->alpn_protos)
-           ssl_mem_free(ssl->alpn_protos);
+    if (ssl->alpn_protos) {
+           ssl_mem_free((void *)ssl->alpn_protos);
+           ssl->alpn_protos = NULL;
+    }
 
     ssl_mem_free(ssl);
 }
@@ -805,220 +830,6 @@ const char *SSL_get_version(const SSL *ssl)
 }
 
 /**
- * @brief get alert description string
- */
-const char* SSL_alert_desc_string(int value)
-{
-    const char *str;
-
-    switch (value & 0xff)
-    {
-        case SSL3_AD_CLOSE_NOTIFY:
-            str = "CN";
-            break;
-        case SSL3_AD_UNEXPECTED_MESSAGE:
-            str = "UM";
-            break;
-        case SSL3_AD_BAD_RECORD_MAC:
-            str = "BM";
-            break;
-        case SSL3_AD_DECOMPRESSION_FAILURE:
-            str = "DF";
-            break;
-        case SSL3_AD_HANDSHAKE_FAILURE:
-            str = "HF";
-            break;
-        case SSL3_AD_NO_CERTIFICATE:
-            str = "NC";
-            break;
-        case SSL3_AD_BAD_CERTIFICATE:
-            str = "BC";
-            break;
-        case SSL3_AD_UNSUPPORTED_CERTIFICATE:
-            str = "UC";
-            break;
-        case SSL3_AD_CERTIFICATE_REVOKED:
-            str = "CR";
-            break;
-        case SSL3_AD_CERTIFICATE_EXPIRED:
-            str = "CE";
-            break;
-        case SSL3_AD_CERTIFICATE_UNKNOWN:
-            str = "CU";
-            break;
-        case SSL3_AD_ILLEGAL_PARAMETER:
-            str = "IP";
-            break;
-        case TLS1_AD_DECRYPTION_FAILED:
-            str = "DC";
-            break;
-        case TLS1_AD_RECORD_OVERFLOW:
-            str = "RO";
-            break;
-        case TLS1_AD_UNKNOWN_CA:
-            str = "CA";
-            break;
-        case TLS1_AD_ACCESS_DENIED:
-            str = "AD";
-            break;
-        case TLS1_AD_DECODE_ERROR:
-            str = "DE";
-            break;
-        case TLS1_AD_DECRYPT_ERROR:
-            str = "CY";
-            break;
-        case TLS1_AD_EXPORT_RESTRICTION:
-            str = "ER";
-            break;
-        case TLS1_AD_PROTOCOL_VERSION:
-            str = "PV";
-            break;
-        case TLS1_AD_INSUFFICIENT_SECURITY:
-            str = "IS";
-            break;
-        case TLS1_AD_INTERNAL_ERROR:
-            str = "IE";
-            break;
-        case TLS1_AD_USER_CANCELLED:
-            str = "US";
-            break;
-        case TLS1_AD_NO_RENEGOTIATION:
-            str = "NR";
-            break;
-        case TLS1_AD_UNSUPPORTED_EXTENSION:
-            str = "UE";
-            break;
-        case TLS1_AD_CERTIFICATE_UNOBTAINABLE:
-            str = "CO";
-            break;
-        case TLS1_AD_UNRECOGNIZED_NAME:
-            str = "UN";
-            break;
-        case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
-            str = "BR";
-            break;
-        case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE:
-            str = "BH";
-            break;
-        case TLS1_AD_UNKNOWN_PSK_IDENTITY:
-            str = "UP";
-            break;
-        default:
-            str = "UK";
-            break;
-    }
-
-    return str;
-}
-
-/**
- * @brief get alert description long string
- */
-const char* SSL_alert_desc_string_long(int value)
-{
-    const char *str;
-
-    switch (value & 0xff)
-    {
-        case SSL3_AD_CLOSE_NOTIFY:
-            str = "close notify";
-            break;
-        case SSL3_AD_UNEXPECTED_MESSAGE:
-            str = "unexpected_message";
-            break;
-        case SSL3_AD_BAD_RECORD_MAC:
-            str = "bad record mac";
-            break;
-        case SSL3_AD_DECOMPRESSION_FAILURE:
-            str = "decompression failure";
-            break;
-        case SSL3_AD_HANDSHAKE_FAILURE:
-            str = "handshake failure";
-            break;
-        case SSL3_AD_NO_CERTIFICATE:
-            str = "no certificate";
-            break;
-        case SSL3_AD_BAD_CERTIFICATE:
-            str = "bad certificate";
-            break;
-        case SSL3_AD_UNSUPPORTED_CERTIFICATE:
-            str = "unsupported certificate";
-            break;
-        case SSL3_AD_CERTIFICATE_REVOKED:
-            str = "certificate revoked";
-            break;
-        case SSL3_AD_CERTIFICATE_EXPIRED:
-            str = "certificate expired";
-            break;
-        case SSL3_AD_CERTIFICATE_UNKNOWN:
-            str = "certificate unknown";
-            break;
-        case SSL3_AD_ILLEGAL_PARAMETER:
-            str = "illegal parameter";
-            break;
-        case TLS1_AD_DECRYPTION_FAILED:
-            str = "decryption failed";
-            break;
-        case TLS1_AD_RECORD_OVERFLOW:
-            str = "record overflow";
-            break;
-        case TLS1_AD_UNKNOWN_CA:
-            str = "unknown CA";
-            break;
-        case TLS1_AD_ACCESS_DENIED:
-            str = "access denied";
-            break;
-        case TLS1_AD_DECODE_ERROR:
-            str = "decode error";
-            break;
-        case TLS1_AD_DECRYPT_ERROR:
-            str = "decrypt error";
-            break;
-        case TLS1_AD_EXPORT_RESTRICTION:
-            str = "export restriction";
-            break;
-        case TLS1_AD_PROTOCOL_VERSION:
-            str = "protocol version";
-            break;
-        case TLS1_AD_INSUFFICIENT_SECURITY:
-            str = "insufficient security";
-            break;
-        case TLS1_AD_INTERNAL_ERROR:
-            str = "internal error";
-            break;
-        case TLS1_AD_USER_CANCELLED:
-            str = "user canceled";
-            break;
-        case TLS1_AD_NO_RENEGOTIATION:
-            str = "no renegotiation";
-            break;
-        case TLS1_AD_UNSUPPORTED_EXTENSION:
-            str = "unsupported extension";
-            break;
-        case TLS1_AD_CERTIFICATE_UNOBTAINABLE:
-            str = "certificate unobtainable";
-            break;
-        case TLS1_AD_UNRECOGNIZED_NAME:
-            str = "unrecognized name";
-            break;
-        case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
-            str = "bad certificate status response";
-            break;
-        case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE:
-            str = "bad certificate hash value";
-            break;
-        case TLS1_AD_UNKNOWN_PSK_IDENTITY:
-            str = "unknown PSK identity";
-            break;
-        default:
-            str = "unknown";
-            break;
-    }
-
-    return str;
-}
-
-/**
  * @brief get alert type string
  */
 const char *SSL_alert_type_string(int value)
@@ -1042,313 +853,13 @@ const char *SSL_alert_type_string(int value)
 }
 
 /**
- * @brief get alert type long string
- */
-const char *SSL_alert_type_string_long(int value)
-{
-    const char *str;
-
-    switch (value >> 8)
-    {
-        case SSL3_AL_WARNING:
-            str = "warning";
-            break;
-        case SSL3_AL_FATAL:
-            str = "fatal";
-            break;
-        default:
-            str = "unknown";
-            break;
-    }
-
-    return str;
-}
-
-/**
- * @brief get the state string where SSL is reading
- */
-const char *SSL_rstate_string(SSL *ssl)
-{
-    const char *str;
-
-    SSL_ASSERT2(ssl);
-
-    switch (ssl->rlayer.rstate)
-    {
-        case SSL_ST_READ_HEADER:
-            str = "RH";
-            break;
-        case SSL_ST_READ_BODY:
-            str = "RB";
-            break;
-        case SSL_ST_READ_DONE:
-            str = "RD";
-            break;
-        default:
-            str = "unknown";
-            break;
-    }
-
-    return str;
-}
-
-/**
- * @brief get the statement long string where SSL is reading
- */
-const char *SSL_rstate_string_long(SSL *ssl)
-{
-    const char *str = "unknown";
-
-    SSL_ASSERT2(ssl);
-
-    switch (ssl->rlayer.rstate)
-    {
-        case SSL_ST_READ_HEADER:
-            str = "read header";
-            break;
-        case SSL_ST_READ_BODY:
-            str = "read body";
-            break;
-        case SSL_ST_READ_DONE:
-            str = "read done";
-            break;
-        default:
-            break;
-    }
-
-    return str;
-}
-
-/**
- * @brief get SSL statement string
- */
-char *SSL_state_string(const SSL *ssl)
-{
-    char *str = "UNKWN ";
-
-    SSL_ASSERT2(ssl);
-
-    if (ossl_statem_in_error(ssl))
-        str = "SSLERR";
-    else
-    {
-        switch (SSL_get_state(ssl))
-        {
-            case TLS_ST_BEFORE:
-                str = "PINIT ";
-                break;
-            case TLS_ST_OK:
-                str =  "SSLOK ";
-                break;
-            case TLS_ST_CW_CLNT_HELLO:
-                str = "TWCH";
-                break;
-            case TLS_ST_CR_SRVR_HELLO:
-                str = "TRSH";
-                break;
-            case TLS_ST_CR_CERT:
-                str = "TRSC";
-                break;
-            case TLS_ST_CR_KEY_EXCH:
-                str = "TRSKE";
-                break;
-            case TLS_ST_CR_CERT_REQ:
-                str = "TRCR";
-                break;
-            case TLS_ST_CR_SRVR_DONE:
-                str = "TRSD";
-                break;
-            case TLS_ST_CW_CERT:
-                str = "TWCC";
-                break;
-            case TLS_ST_CW_KEY_EXCH:
-                str = "TWCKE";
-                break;
-            case TLS_ST_CW_CERT_VRFY:
-                str = "TWCV";
-                break;
-            case TLS_ST_SW_CHANGE:
-            case TLS_ST_CW_CHANGE:
-                str = "TWCCS";
-                break;
-            case TLS_ST_SW_FINISHED:
-            case TLS_ST_CW_FINISHED:
-                str = "TWFIN";
-                break;
-            case TLS_ST_SR_CHANGE:
-            case TLS_ST_CR_CHANGE:
-                str = "TRCCS";
-                break;
-            case TLS_ST_SR_FINISHED:
-            case TLS_ST_CR_FINISHED:
-                str = "TRFIN";
-                break;
-            case TLS_ST_SW_HELLO_REQ:
-                str = "TWHR";
-                break;
-            case TLS_ST_SR_CLNT_HELLO:
-                str = "TRCH";
-                break;
-            case TLS_ST_SW_SRVR_HELLO:
-                str = "TWSH";
-                break;
-            case TLS_ST_SW_CERT:
-                str = "TWSC";
-                break;
-            case TLS_ST_SW_KEY_EXCH:
-                str = "TWSKE";
-                break;
-            case TLS_ST_SW_CERT_REQ:
-                str = "TWCR";
-                break;
-            case TLS_ST_SW_SRVR_DONE:
-                str = "TWSD";
-                break;
-            case TLS_ST_SR_CERT:
-                str = "TRCC";
-                break;
-            case TLS_ST_SR_KEY_EXCH:
-                str = "TRCKE";
-                break;
-            case TLS_ST_SR_CERT_VRFY:
-                str = "TRCV";
-                break;
-            case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
-                str = "DRCHV";
-                break;
-            case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-                str = "DWCHV";
-                break;
-            default:
-                break;
-        }
-    }
-
-    return str;
-}
-
-/**
- * @brief get SSL statement long string
- */
-char *SSL_state_string_long(const SSL *ssl)
-{
-    char *str = "UNKWN ";
-
-    SSL_ASSERT2(ssl);
-
-    if (ossl_statem_in_error(ssl))
-        str = "SSLERR";
-    else
-    {
-        switch (SSL_get_state(ssl))
-        {
-            case TLS_ST_BEFORE:
-                str = "before SSL initialization";
-                break;
-            case TLS_ST_OK:
-                str = "SSL negotiation finished successfully";
-                break;
-            case TLS_ST_CW_CLNT_HELLO:
-                str = "SSLv3/TLS write client hello";
-                break;
-            case TLS_ST_CR_SRVR_HELLO:
-                str = "SSLv3/TLS read server hello";
-                break;
-            case TLS_ST_CR_CERT:
-                str = "SSLv3/TLS read server certificate";
-                break;
-            case TLS_ST_CR_KEY_EXCH:
-                str = "SSLv3/TLS read server key exchange";
-                break;
-            case TLS_ST_CR_CERT_REQ:
-                str = "SSLv3/TLS read server certificate request";
-                break;
-            case TLS_ST_CR_SESSION_TICKET:
-                str = "SSLv3/TLS read server session ticket";
-                break;
-            case TLS_ST_CR_SRVR_DONE:
-                str = "SSLv3/TLS read server done";
-                break;
-            case TLS_ST_CW_CERT:
-                str = "SSLv3/TLS write client certificate";
-                break;
-            case TLS_ST_CW_KEY_EXCH:
-                str = "SSLv3/TLS write client key exchange";
-                break;
-            case TLS_ST_CW_CERT_VRFY:
-                str = "SSLv3/TLS write certificate verify";
-                break;
-            case TLS_ST_CW_CHANGE:
-            case TLS_ST_SW_CHANGE:
-                str = "SSLv3/TLS write change cipher spec";
-                break;
-            case TLS_ST_CW_FINISHED:
-            case TLS_ST_SW_FINISHED:
-                str = "SSLv3/TLS write finished";
-                break;
-            case TLS_ST_CR_CHANGE:
-            case TLS_ST_SR_CHANGE:
-                str = "SSLv3/TLS read change cipher spec";
-                break;
-            case TLS_ST_CR_FINISHED:
-            case TLS_ST_SR_FINISHED:
-                str = "SSLv3/TLS read finished";
-                break;
-            case TLS_ST_SR_CLNT_HELLO:
-                str = "SSLv3/TLS read client hello";
-                break;
-            case TLS_ST_SW_HELLO_REQ:
-                str = "SSLv3/TLS write hello request";
-                break;
-            case TLS_ST_SW_SRVR_HELLO:
-                str = "SSLv3/TLS write server hello";
-                break;
-            case TLS_ST_SW_CERT:
-                str = "SSLv3/TLS write certificate";
-                break;
-            case TLS_ST_SW_KEY_EXCH:
-                str = "SSLv3/TLS write key exchange";
-                break;
-            case TLS_ST_SW_CERT_REQ:
-                str = "SSLv3/TLS write certificate request";
-                break;
-            case TLS_ST_SW_SESSION_TICKET:
-                str = "SSLv3/TLS write session ticket";
-                break;
-            case TLS_ST_SW_SRVR_DONE:
-                str = "SSLv3/TLS write server done";
-                break;
-            case TLS_ST_SR_CERT:
-                str = "SSLv3/TLS read client certificate";
-                break;
-            case TLS_ST_SR_KEY_EXCH:
-                str = "SSLv3/TLS read client key exchange";
-                break;
-            case TLS_ST_SR_CERT_VRFY:
-                str = "SSLv3/TLS read certificate verify";
-                break;
-            case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
-                str = "DTLS1 read hello verify request";
-                break;
-            case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-                str = "DTLS1 write hello verify request";
-                break;
-            default:
-                break;
-        }
-    }
-
-    return str;
-}
-
-/**
  * @brief set the SSL context read buffer length
  */
 void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len)
 {
     SSL_ASSERT3(ctx);
 
-    ctx->read_buffer_len = len;
+    ctx->read_buffer_len = (int)len;
 }
 
 /**
@@ -1359,7 +870,7 @@ void SSL_set_default_read_buffer_len(SSL *ssl, size_t len)
     SSL_ASSERT3(ssl);
     SSL_ASSERT3(len);
 
-    SSL_METHOD_CALL(set_bufflen, ssl, len);
+    SSL_METHOD_CALL(set_bufflen, ssl, (int)len);
 }
 
 /**
@@ -1569,7 +1080,7 @@ void SSL_set_verify_depth(SSL *ssl, int depth)
 /**
  * @brief set the SSL context verifying of the SSL context
  */
-void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *))
+void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(SSL *, mbedtls_x509_crt *))
 {
     SSL_ASSERT3(ctx);
 
@@ -1580,7 +1091,7 @@ void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509
 /**
  * @brief set the SSL verifying of the SSL context
  */
-void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *))
+void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(SSL *, mbedtls_x509_crt *))
 {
     SSL_ASSERT3(ssl);
 
@@ -1660,27 +1171,28 @@ _openssl_alpn_to_mbedtls(struct alpn_ctx *ac, char ***palpn_protos)
 
        /* find out how many entries he gave us */
 
-       len = *p++;
-       while (p - ac->data < ac->len) {
-               if (len--) {
-                       p++;
-                       continue;
-               }
-               count++;
+       if (ac->len) {
                len = *p++;
-               if (!len)
-                       break;
+               if (len)
+                       count++;
+               while (p - ac->data < ac->len) {
+                       if (len--) {
+                               p++;
+                               continue;
+                       }
+                       len = *p++;
+                       if (!len)
+                               break;
+                       count++;
+               }
        }
 
-       if (!len)
-               count++;
-
        if (!count)
                return;
 
        /* allocate space for count + 1 pointers and the data afterwards */
 
-       alpn_protos = ssl_mem_zalloc((count + 1) * sizeof(char *) + ac->len + 1);
+       alpn_protos = ssl_mem_zalloc((unsigned int)(count + 1) * sizeof(char *) + ac->len + 1);
        if (!alpn_protos)
                return;
 
@@ -1688,7 +1200,7 @@ _openssl_alpn_to_mbedtls(struct alpn_ctx *ac, char ***palpn_protos)
 
        /* convert to mbedtls format */
 
-       q = (unsigned char *)alpn_protos + (count + 1) * sizeof(char *);
+       q = (unsigned char *)alpn_protos + (unsigned int)(count + 1) * sizeof(char *);
        p = ac->data;
        count = 0;
 
index 0002360..bfa9c9b 100644 (file)
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "private-lib-core.h"
+
 #include "ssl_methods.h"
 #include "ssl_pm.h"
 
@@ -34,24 +36,28 @@ IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 0, TLS_method_func, TLS_client_method);
 
 IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 0, TLS_method_func, TLSv1_2_client_method);
 
+#if 0
 IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 0, TLS_method_func, TLSv1_1_client_method);
 
 IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_client_method);
 
 IMPLEMENT_SSL_METHOD(SSL3_VERSION, 0, TLS_method_func, SSLv3_client_method);
+#endif
 
 /**
  * TLS or SSL server method collection
  */
 IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 1, TLS_method_func, TLS_server_method);
 
-IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 1, TLS_method_func, TLSv1_1_server_method);
-
 IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 1, TLS_method_func, TLSv1_2_server_method);
 
+#if 0
+IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 1, TLS_method_func, TLSv1_1_server_method);
+
 IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_server_method);
 
 IMPLEMENT_SSL_METHOD(SSL3_VERSION, 1, TLS_method_func, SSLv3_server_method);
+#endif
 
 /**
  * TLS or SSL method collection
@@ -60,11 +66,13 @@ IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, -1, TLS_method_func, TLS_method);
 
 IMPLEMENT_SSL_METHOD(TLS1_2_VERSION, -1, TLS_method_func, TLSv1_2_method);
 
+#if 0
 IMPLEMENT_SSL_METHOD(TLS1_1_VERSION, -1, TLS_method_func, TLSv1_1_method);
 
 IMPLEMENT_SSL_METHOD(TLS1_VERSION, -1, TLS_method_func, TLSv1_method);
 
 IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method);
+#endif
 
 /**
  * @brief get X509 object method
index 567a33e..18436a2 100644 (file)
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "private-lib-core.h"
+
 #include "ssl_pkey.h"
 #include "ssl_methods.h"
 #include "ssl_dbg.h"
@@ -20,7 +22,7 @@
 /**
  * @brief create a private key object according to input private key
  */
-EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk)
+EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk, void *rngctx)
 {
     int ret;
     EVP_PKEY *pkey;
@@ -37,7 +39,7 @@ EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk)
         pkey->method = EVP_PKEY_method();
     }
 
-    ret = EVP_PKEY_METHOD_CALL(new, pkey, ipk);
+    ret = EVP_PKEY_METHOD_CALL(new, pkey, ipk, rngctx);
     if (ret) {
         SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(new) return %d", ret);
         goto failed;
@@ -54,9 +56,9 @@ no_mem:
 /**
  * @brief create a private key object
  */
-EVP_PKEY* EVP_PKEY_new(void)
+EVP_PKEY* EVP_PKEY_new(void *rngctx)
 {
-    return __EVP_PKEY_new(NULL);
+    return __EVP_PKEY_new(NULL, rngctx);
 }
 
 /**
@@ -78,7 +80,7 @@ void EVP_PKEY_free(EVP_PKEY *pkey)
 EVP_PKEY *d2i_PrivateKey(int type,
                          EVP_PKEY **a,
                          const unsigned char **pp,
-                         long length)
+                         long length, void *rngctx)
 {
     int m = 0;
     int ret;
@@ -91,7 +93,7 @@ EVP_PKEY *d2i_PrivateKey(int type,
     if (a && *a) {
         pkey = *a;
     } else {
-        pkey = EVP_PKEY_new();;
+        pkey = EVP_PKEY_new(rngctx);
         if (!pkey) {
             SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_new() return NULL");
             goto failed1;
@@ -100,7 +102,7 @@ EVP_PKEY *d2i_PrivateKey(int type,
         m = 1;
     }
 
-    ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, length);
+    ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, (int)length);
     if (ret) {
         SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(load) return %d", ret);
         goto failed2;
@@ -165,7 +167,7 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx,
     int ret;
     EVP_PKEY *pk;
 
-    pk = d2i_PrivateKey(0, NULL, &d, len);
+    pk = d2i_PrivateKey(0, NULL, &d, len, ctx->rngctx);
     if (!pk) {
         SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL");
         goto failed1;
@@ -194,7 +196,7 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl,
     int ret;
     EVP_PKEY *pk;
 
-    pk = d2i_PrivateKey(0, NULL, &d, len);
+    pk = d2i_PrivateKey(0, NULL, &d, len, ssl->ctx->rngctx);
     if (!pk) {
         SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_PrivateKey() return NULL");
         goto failed1;
index da836da..78634c4 100644 (file)
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "private-lib-core.h"
+
 #include "ssl_stack.h"
 #include "ssl_dbg.h"
 #include "ssl_port.h"
index ed79150..7d8bbff 100644 (file)
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "private-lib-core.h"
+
 #include "ssl_x509.h"
 #include "ssl_methods.h"
 #include "ssl_dbg.h"
@@ -104,7 +106,7 @@ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len)
         m = 1;
     }
 
-    ret = X509_METHOD_CALL(load, x, buffer, len);
+    ret = X509_METHOD_CALL(load, x, buffer, (int)len);
     if (ret) {
         SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(load) return %d", ret);
         goto failed2;
@@ -174,20 +176,14 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x)
 int SSL_CTX_add_client_CA_ASN1(SSL_CTX *ctx, int len,
                 const unsigned char *d)
 {
-       X509 *x;
+       SSL_ASSERT1(ctx);
 
-       x = d2i_X509(NULL, d, len);
-       if (!x) {
+       if (!d2i_X509(&ctx->client_CA, d, len)) {
                SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL");
                return 0;
        }
-    SSL_ASSERT1(ctx);
-
-    X509_free(ctx->client_CA);
 
-    ctx->client_CA = x;
-
-    return 1;
+       return 1;
 }
 
 /**
@@ -286,8 +282,7 @@ failed1:
 /**
  * @brief load certification into the SSL
  */
-int SSL_use_certificate_ASN1(SSL *ssl, int len,
-                             const unsigned char *d)
+int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len)
 {
     int ret;
     X509 *x;
index dea6894..04354f6 100755 (executable)
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "private-lib-core.h"
+
 #include "ssl_pm.h"
 #include "ssl_port.h"
 #include "ssl_dbg.h"
 
 /* mbedtls include */
 #include "mbedtls/platform.h"
+#if defined(LWS_HAVE_MBEDTLS_NET_SOCKETS)
 #include "mbedtls/net_sockets.h"
+#else
+#include "mbedtls/net.h"
+#endif
 #include "mbedtls/debug.h"
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
 #include "mbedtls/error.h"
-#include "mbedtls/certs.h"
 
-#include "core/private.h"
 
 #define X509_INFO_STRING_LENGTH 8192
 
@@ -59,10 +63,13 @@ struct pkey_pm
     mbedtls_pk_context *pkey;
 
     mbedtls_pk_context *ex_pkey;
+
+    void *rngctx;
 };
 
 unsigned int max_content_len;
 
+
 /*********************************************************************************************/
 /************************************ SSL arch interface *************************************/
 
@@ -91,6 +98,19 @@ static void ssl_platform_debug(void *ctx, int level,
 }
 //#endif
 
+#if defined(LWS_HAVE_mbedtls_ssl_set_verify)
+static int
+lws_mbedtls_f_vrfy(void *opaque, mbedtls_x509_crt *x509, int state, uint32_t *pflags)
+{
+       struct ssl_pm *ssl_pm = (struct ssl_pm *)opaque;
+
+       if (ssl_pm->owner->verify_callback)
+               (ssl_pm->owner->verify_callback)(ssl_pm->owner, x509);
+
+       return 0;
+}
+#endif
+
 /**
  * @brief create SSL low-level object
  */
@@ -118,7 +138,7 @@ int ssl_pm_new(SSL *ssl)
     if (!ssl->ctx->read_buffer_len)
            ssl->ctx->read_buffer_len = 2048;
 
-    max_content_len = ssl->ctx->read_buffer_len;
+    max_content_len = (unsigned int)ssl->ctx->read_buffer_len;
     // printf("ssl->ctx->read_buffer_len = %d ++++++++++++++++++++\n", ssl->ctx->read_buffer_len);
 
     mbedtls_net_init(&ssl_pm->fd);
@@ -129,6 +149,10 @@ int ssl_pm_new(SSL *ssl)
     mbedtls_entropy_init(&ssl_pm->entropy);
     mbedtls_ssl_init(&ssl_pm->ssl);
 
+#if defined(LWS_HAVE_mbedtls_ssl_set_verify)
+    mbedtls_ssl_set_verify(&ssl_pm->ssl, lws_mbedtls_f_vrfy, ssl_pm);
+#endif
+
     ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, pers, pers_len);
     if (ret) {
         lwsl_notice("%s: mbedtls_ctr_drbg_seed() return -0x%x", __func__, -ret);
@@ -151,17 +175,15 @@ int ssl_pm_new(SSL *ssl)
         if (TLS1_2_VERSION == ssl->version)
             version = MBEDTLS_SSL_MINOR_VERSION_3;
         else if (TLS1_1_VERSION == ssl->version)
-            version = MBEDTLS_SSL_MINOR_VERSION_2;
-        else if (TLS1_VERSION == ssl->version)
-            version = MBEDTLS_SSL_MINOR_VERSION_1;
+            version = 2;
         else
-            version = MBEDTLS_SSL_MINOR_VERSION_0;
+            version = 1;
 
         mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version);
         mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version);
     } else {
         mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
-        mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0);
+        mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, 1);
     }
 
     mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg);
@@ -181,7 +203,9 @@ int ssl_pm_new(SSL *ssl)
         goto mbedtls_err2;
     }
 
-    mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL);
+    mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd,
+                       lws_plat_mbedtls_net_send,
+                       lws_plat_mbedtls_net_recv, NULL);
 
     ssl->ssl_pm = ssl_pm;
 
@@ -218,16 +242,16 @@ void ssl_pm_free(SSL *ssl)
  */
 static int ssl_pm_reload_crt(SSL *ssl)
 {
-    int ret;
-    int mode;
-    struct ssl_pm *ssl_pm = ssl->ssl_pm;
     struct x509_pm *ca_pm = (struct x509_pm *)ssl->client_CA->x509_pm;
+    struct ssl_pm *ssl_pm = ssl->ssl_pm;
+    int ret = 0;
+    int mode;
 
     struct pkey_pm *pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm;
     struct x509_pm *crt_pm = (struct x509_pm *)ssl->cert->x509->x509_pm;
 
     if (ssl->verify_mode == SSL_VERIFY_PEER)
-        mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
+        mode = MBEDTLS_SSL_VERIFY_REQUIRED;
     else if (ssl->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
         mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
     else if (ssl->verify_mode == SSL_VERIFY_CLIENT_ONCE)
@@ -237,19 +261,15 @@ static int ssl_pm_reload_crt(SSL *ssl)
 
     mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode);
 
-    if (ca_pm->x509_crt) {
+    if (ca_pm->x509_crt)
         mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->x509_crt, NULL);
-    } else if (ca_pm->ex_crt) {
+    else if (ca_pm->ex_crt)
         mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->ex_crt, NULL);
-    }
 
-    if (crt_pm->x509_crt && pkey_pm->pkey) {
+    if (crt_pm->x509_crt && pkey_pm->pkey)
         ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->x509_crt, pkey_pm->pkey);
-    } else if (crt_pm->ex_crt && pkey_pm->ex_pkey) {
+    else if (crt_pm->ex_crt && pkey_pm->ex_pkey)
         ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->ex_crt, pkey_pm->ex_pkey);
-    } else {
-        ret = 0;
-    }
 
     if (ret) {
         SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_conf_own_cert() return -0x%x", -ret);
@@ -267,10 +287,10 @@ static int mbedtls_handshake( mbedtls_ssl_context *ssl )
 {
     int ret = 0;
 
-    while (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER) {
+    while (ssl->MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) {
         ret = mbedtls_ssl_handshake_step(ssl);
 
-        lwsl_info("%s: ssl ret -%x state %d\n", __func__, -ret, ssl->state);
+        lwsl_info("%s: ssl ret -%x state %d\n", __func__, -ret, ssl->MBEDTLS_PRIVATE(state));
 
         if (ret != 0)
             break;
@@ -297,7 +317,7 @@ int ssl_pm_handshake(SSL *ssl)
         return 0;
     }
 
-    if (ssl_pm->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER) {
+    if (ssl_pm->ssl.MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) {
            ssl_speed_up_enter();
 
           /* mbedtls return codes
@@ -329,6 +349,7 @@ int ssl_pm_handshake(SSL *ssl)
     }
 
     if (errno == 11) {
+           lwsl_info("%s: ambiguous EAGAIN taken as WANT_READ\n", __func__);
            ssl->err = ret == MBEDTLS_ERR_SSL_WANT_READ;
 
            return 0;
@@ -398,12 +419,16 @@ int ssl_pm_read(SSL *ssl, void *buffer, int len)
     int ret;
     struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
 
-    ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len);
+    ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, (size_t)len);
     if (ret < 0) {
         //   lwsl_notice("%s: mbedtls_ssl_read says -0x%x\n", __func__, -ret);
         SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_read() return -0x%x", -ret);
         if (ret == MBEDTLS_ERR_NET_CONN_RESET ||
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+           ret <= MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE) /* fatal errors */
+#else
             ret <= MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) /* fatal errors */
+#endif
                ssl->err = SSL_ERROR_SYSCALL;
         ret = -1;
     }
@@ -421,7 +446,7 @@ int ssl_pm_send(SSL *ssl, const void *buffer, int len)
     int ret;
     struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
 
-    ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, len);
+    ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, (size_t)len);
     /*
      * We can get a positive number, which may be less than len... that
      * much was sent successfully and you can call again to send more.
@@ -467,21 +492,21 @@ int ssl_pm_pending(const SSL *ssl)
 {
     struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
 
-    return mbedtls_ssl_get_bytes_avail(&ssl_pm->ssl);
+    return (int)mbedtls_ssl_get_bytes_avail(&ssl_pm->ssl);
 }
 
 void ssl_pm_set_fd(SSL *ssl, int fd, int mode)
 {
     struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
 
-    ssl_pm->fd.fd = fd;
+    ssl_pm->fd.MBEDTLS_PRIVATE(fd) = fd;
 }
 
 int ssl_pm_get_fd(const SSL *ssl, int mode)
 {
     struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
 
-    return ssl_pm->fd.fd;
+    return ssl_pm->fd.MBEDTLS_PRIVATE(fd);
 }
 
 OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl)
@@ -490,7 +515,7 @@ OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl)
 
     struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
 
-    switch (ssl_pm->ssl.state)
+    switch (ssl_pm->ssl.MBEDTLS_PRIVATE(state))
     {
         case MBEDTLS_SSL_CLIENT_HELLO:
             state = TLS_ST_CW_CLNT_HELLO;
@@ -544,6 +569,7 @@ OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl)
 
 int x509_pm_show_info(X509 *x)
 {
+#if 0
     int ret;
     char *buf;
     mbedtls_x509_crt *x509_crt;
@@ -583,6 +609,9 @@ mbedtls_err1:
     ssl_mem_free(buf);
 no_mem:
     return -1;
+#else
+    return 0;
+#endif
 }
 
 int x509_pm_new(X509 *x, X509 *m_x)
@@ -630,35 +659,29 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len)
     unsigned char *load_buf;
     struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm;
 
-       if (x509_pm->x509_crt)
-        mbedtls_x509_crt_free(x509_pm->x509_crt);
-
     if (!x509_pm->x509_crt) {
         x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt));
         if (!x509_pm->x509_crt) {
             SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm->x509_crt)");
             goto no_mem;
         }
+        mbedtls_x509_crt_init(x509_pm->x509_crt);
     }
 
-    mbedtls_x509_crt_init(x509_pm->x509_crt);
     if (buffer[0] != 0x30) {
-           load_buf = ssl_mem_malloc(len + 1);
+           load_buf = ssl_mem_malloc((unsigned int)len + 1);
            if (!load_buf) {
                SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)");
                goto failed;
            }
 
-           ssl_memcpy(load_buf, buffer, len);
+           ssl_memcpy(load_buf, buffer, (unsigned int)len);
            load_buf[len] = '\0';
 
-           ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len + 1);
+           ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, (unsigned int)len + 1);
            ssl_mem_free(load_buf);
-    } else {
-           // printf("parsing as der\n");
-
-           ret = mbedtls_x509_crt_parse_der(x509_pm->x509_crt, buffer, len);
-    }
+    } else
+           ret = mbedtls_x509_crt_parse_der(x509_pm->x509_crt, buffer, (unsigned int)len);
 
     if (ret) {
         printf("mbedtls_x509_crt_parse return -0x%x", -ret);
@@ -675,7 +698,7 @@ no_mem:
     return -1;
 }
 
-int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pkey)
+int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pkey, void *rngctx)
 {
     struct pkey_pm *pkey_pm;
 
@@ -684,6 +707,7 @@ int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pkey)
         return -1;
 
     pk->pkey_pm = pkey_pm;
+    pkey_pm->rngctx = rngctx;
 
     if (m_pkey) {
         struct pkey_pm *m_pkey_pm = (struct pkey_pm *)m_pkey->pkey_pm;
@@ -726,18 +750,23 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len)
         }
     }
 
-    load_buf = ssl_mem_malloc(len + 1);
+    load_buf = ssl_mem_malloc((unsigned int)len + 1);
     if (!load_buf) {
         SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)");
         goto failed;
     }
 
-    ssl_memcpy(load_buf, buffer, len);
+    ssl_memcpy(load_buf, buffer, (unsigned int)len);
     load_buf[len] = '\0';
 
     mbedtls_pk_init(pkey_pm->pkey);
 
-    ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len + 1, NULL, 0);
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+    ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, (unsigned int)len + 1, NULL, 0,
+                   mbedtls_ctr_drbg_random, pkey_pm->rngctx);
+#else
+    ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, (unsigned int)len + 1, NULL, 0);
+#endif
     ssl_mem_free(load_buf);
 
     if (ret) {
@@ -759,7 +788,7 @@ no_mem:
 
 void ssl_pm_set_bufflen(SSL *ssl, int len)
 {
-    max_content_len = len;
+    max_content_len = (unsigned int)len;
 }
 
 long ssl_pm_get_verify_result(const SSL *ssl)
@@ -856,9 +885,11 @@ void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
 
        *data = (const unsigned char *)alp;
        if (alp)
-               *len = strlen(alp);
+               *len = (unsigned int)strlen(alp);
        else
                *len = 0;
+#else
+       *len = 0;
 #endif
 }
 
@@ -880,6 +911,13 @@ SSL *SSL_SSL_from_mbedtls_ssl_context(mbedtls_ssl_context *msc)
        return ssl_pm->owner;
 }
 
+mbedtls_ssl_context *SSL_mbedtls_ssl_context_from_SSL(SSL *ssl)
+{
+       struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
+
+       return &ssl_pm->ssl;
+}
+
 #include "ssl_cert.h"
 
 void SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
@@ -922,13 +960,14 @@ void SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
        if (ssl->cert)
                ssl_cert_free(ssl->cert);
        ssl->ctx = ctx;
-       ssl->cert = __ssl_cert_new(ctx->cert);
+       ssl->cert = __ssl_cert_new(ctx->cert, ctx->rngctx);
 
 #if defined(LWS_HAVE_mbedtls_ssl_set_hs_authmode)
+
        if (ctx->verify_mode == SSL_VERIFY_PEER)
-               mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
+               mode = MBEDTLS_SSL_VERIFY_REQUIRED;
        else if (ctx->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
-               mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
+               mode = MBEDTLS_SSL_VERIFY_REQUIRED;
        else if (ctx->verify_mode == SSL_VERIFY_CLIENT_ONCE)
                mode = MBEDTLS_SSL_VERIFY_UNSET;
        else
diff --git a/lib/tls/mbedtls/x509.c b/lib/tls/mbedtls/x509.c
deleted file mode 100644 (file)
index 9c0ac05..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * libwebsockets - mbedTLS-specific lws apis
- *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-#include "tls/mbedtls/private.h"
-#include <mbedtls/oid.h>
-
-#if defined(LWS_PLAT_OPTEE) || defined(OPTEE_DEV_KIT)
-struct tm {
-int    tm_sec; //   seconds [0,61]
-int    tm_min; //   minutes [0,59]
-int    tm_hour; //  hour [0,23]
-int    tm_mday; //  day of month [1,31]
-int    tm_mon; //   month of year [0,11]
-int    tm_year; //  years since 1900
-int    tm_wday; //  day of week [0,6] (Sunday = 0)
-int    tm_yday; //  day of year [0,365]
-int    tm_isdst; // daylight savings flag
-};
-time_t mktime(struct tm *t)
-{
-       return (time_t)0;
-}
-#endif
-
-static time_t
-lws_tls_mbedtls_time_to_unix(mbedtls_x509_time *xtime)
-{
-       struct tm t;
-
-       if (!xtime || !xtime->year || xtime->year < 0)
-               return (time_t)(long long)-1;
-
-       memset(&t, 0, sizeof(t));
-
-       t.tm_year = xtime->year - 1900;
-       t.tm_mon = xtime->mon - 1; /* mbedtls months are 1+, tm are 0+ */
-       t.tm_mday = xtime->day - 1; /* mbedtls days are 1+, tm are 0+ */
-       t.tm_hour = xtime->hour;
-       t.tm_min = xtime->min;
-       t.tm_sec = xtime->sec;
-       t.tm_isdst = -1;
-
-       return mktime(&t);
-}
-
-static int
-lws_tls_mbedtls_get_x509_name(mbedtls_x509_name *name,
-                             union lws_tls_cert_info_results *buf, size_t len)
-{
-       while (name) {
-               if (MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid)) {
-                       name = name->next;
-                       continue;
-               }
-
-               if (len - 1 < name->val.len)
-                       return -1;
-
-               memcpy(&buf->ns.name[0], name->val.p, name->val.len);
-               buf->ns.name[name->val.len] = '\0';
-               buf->ns.len = name->val.len;
-
-               return 0;
-       }
-
-       return -1;
-}
-
-static int
-lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type,
-                         union lws_tls_cert_info_results *buf, size_t len)
-{
-       if (!x509)
-               return -1;
-
-       switch (type) {
-       case LWS_TLS_CERT_INFO_VALIDITY_FROM:
-               buf->time = lws_tls_mbedtls_time_to_unix(&x509->valid_from);
-               if (buf->time == (time_t)(long long)-1)
-                       return -1;
-               break;
-
-       case LWS_TLS_CERT_INFO_VALIDITY_TO:
-               buf->time = lws_tls_mbedtls_time_to_unix(&x509->valid_to);
-               if (buf->time == (time_t)(long long)-1)
-                       return -1;
-               break;
-
-       case LWS_TLS_CERT_INFO_COMMON_NAME:
-               return lws_tls_mbedtls_get_x509_name(&x509->subject, buf, len);
-
-       case LWS_TLS_CERT_INFO_ISSUER_NAME:
-               return lws_tls_mbedtls_get_x509_name(&x509->issuer, buf, len);
-
-       case LWS_TLS_CERT_INFO_USAGE:
-               buf->usage = x509->key_usage;
-               break;
-
-       case LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY:
-       {
-               char *p = buf->ns.name;
-               size_t r = len, u;
-
-               switch (mbedtls_pk_get_type(&x509->pk)) {
-               case MBEDTLS_PK_RSA:
-               {
-                       mbedtls_rsa_context *rsa = mbedtls_pk_rsa(x509->pk);
-
-                       if (mbedtls_mpi_write_string(&rsa->N, 16, p, r, &u))
-                               return -1;
-                       r -= u;
-                       p += u;
-                       if (mbedtls_mpi_write_string(&rsa->E, 16, p, r, &u))
-                               return -1;
-
-                       p += u;
-                       buf->ns.len = lws_ptr_diff(p, buf->ns.name);
-                       break;
-               }
-               case MBEDTLS_PK_ECKEY:
-               {
-                       mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(x509->pk);
-
-                       if (mbedtls_mpi_write_string(&ecp->Q.X, 16, p, r, &u))
-                                return -1;
-                       r -= u;
-                       p += u;
-                       if (mbedtls_mpi_write_string(&ecp->Q.Y, 16, p, r, &u))
-                                return -1;
-                       r -= u;
-                       p += u;
-                       if (mbedtls_mpi_write_string(&ecp->Q.Z, 16, p, r, &u))
-                                return -1;
-                       p += u;
-                       buf->ns.len = lws_ptr_diff(p, buf->ns.name);
-                       break;
-               }
-               default:
-                       lwsl_notice("%s: x509 has unsupported pubkey type %d\n",
-                                   __func__,
-                                   mbedtls_pk_get_type(&x509->pk));
-
-                       return -1;
-               }
-               break;
-       }
-
-       default:
-               return -1;
-       }
-
-       return 0;
-}
-
-#if defined(LWS_WITH_NETWORK)
-int
-lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
-                       union lws_tls_cert_info_results *buf, size_t len)
-{
-       mbedtls_x509_crt *x509;
-
-       x509 = ssl_ctx_get_mbedtls_x509_crt(vhost->tls.ssl_ctx);
-
-       return lws_tls_mbedtls_cert_info(x509, type, buf, len);
-}
-
-int
-lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
-                      union lws_tls_cert_info_results *buf, size_t len)
-{
-       mbedtls_x509_crt *x509;
-
-       wsi = lws_get_network_wsi(wsi);
-
-       x509 = ssl_get_peer_mbedtls_x509_crt(wsi->tls.ssl);
-
-       if (!x509)
-               return -1;
-
-       switch (type) {
-       case LWS_TLS_CERT_INFO_VERIFIED:
-               buf->verified = SSL_get_verify_result(wsi->tls.ssl) == X509_V_OK;
-               return 0;
-       default:
-               return lws_tls_mbedtls_cert_info(x509, type, buf, len);
-       }
-
-       return -1;
-}
-#endif
-
-int
-lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type,
-             union lws_tls_cert_info_results *buf, size_t len)
-{
-       return lws_tls_mbedtls_cert_info(&x509->cert, type, buf, len);
-}
-
-int
-lws_x509_create(struct lws_x509_cert **x509)
-{
-       *x509 = lws_malloc(sizeof(**x509), __func__);
-
-       return !(*x509);
-}
-
-/*
- * Parse one DER-encoded or one or more concatenated PEM-encoded certificates
- * and add them to the chained list.
- */
-
-int
-lws_x509_parse_from_pem(struct lws_x509_cert *x509, const void *pem, size_t len)
-{
-       int ret;
-
-       mbedtls_x509_crt_init(&x509->cert);
-
-       ret = mbedtls_x509_crt_parse(&x509->cert, pem, len);
-       if (ret) {
-               mbedtls_x509_crt_free(&x509->cert);
-               lwsl_err("%s: unable to parse PEM cert: -0x%x\n",
-                        __func__, -ret);
-
-               return -1;
-       }
-
-       return 0;
-}
-
-int
-lws_x509_verify(struct lws_x509_cert *x509, struct lws_x509_cert *trusted,
-               const char *common_name)
-{
-       uint32_t flags = 0;
-       int ret;
-
-       ret = mbedtls_x509_crt_verify_with_profile(&x509->cert, &trusted->cert,
-                                                  NULL,
-                                                  &mbedtls_x509_crt_profile_next,
-                                                  common_name, &flags, NULL,
-                                                  NULL);
-
-       if (ret) {
-               lwsl_err("%s: unable to parse PEM cert: -0x%x\n",
-                        __func__, -ret);
-
-               return -1;
-       }
-
-       return 0;
-}
-
-#if defined(LWS_WITH_JOSE)
-
-int
-lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509,
-                      const char *curves, int rsa_min_bits)
-{
-       int kt = mbedtls_pk_get_type(&x509->cert.pk), n, count = 0, ret = -1;
-       mbedtls_rsa_context *rsactx;
-       mbedtls_ecp_keypair *ecpctx;
-       mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT];
-
-       memset(jwk, 0, sizeof(*jwk));
-
-       switch (kt) {
-       case MBEDTLS_PK_RSA:
-               lwsl_notice("%s: RSA key\n", __func__);
-               jwk->kty = LWS_GENCRYPTO_KTY_RSA;
-               rsactx = mbedtls_pk_rsa(x509->cert.pk);
-
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_E] = &rsactx->E;
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_N] = &rsactx->N;
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_D] = &rsactx->D;
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_P] = &rsactx->P;
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_Q] = &rsactx->Q;
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_DP] = &rsactx->DP;
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_DQ] = &rsactx->DQ;
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_QI] = &rsactx->QP;
-
-               count = LWS_GENCRYPTO_RSA_KEYEL_COUNT;
-               n = LWS_GENCRYPTO_RSA_KEYEL_E;
-               break;
-
-       case MBEDTLS_PK_ECKEY:
-               lwsl_notice("%s: EC key\n", __func__);
-               jwk->kty = LWS_GENCRYPTO_KTY_EC;
-               ecpctx = mbedtls_pk_ec(x509->cert.pk);
-               mpi[LWS_GENCRYPTO_EC_KEYEL_X] = &ecpctx->Q.X;
-               mpi[LWS_GENCRYPTO_EC_KEYEL_D] = &ecpctx->d;
-               mpi[LWS_GENCRYPTO_EC_KEYEL_Y] = &ecpctx->Q.Y;
-
-               if (lws_genec_confirm_curve_allowed_by_tls_id(curves,
-                               ecpctx->grp.id, jwk))
-                       /* already logged */
-                       goto bail;
-
-               count = LWS_GENCRYPTO_EC_KEYEL_COUNT;
-               n = LWS_GENCRYPTO_EC_KEYEL_X;
-               break;
-       default:
-               lwsl_err("%s: key type %d not supported\n", __func__, kt);
-
-               return -1;
-       }
-
-       for (; n < count; n++) {
-               if (!mbedtls_mpi_size(mpi[n]))
-                       continue;
-
-               jwk->e[n].buf = lws_malloc(mbedtls_mpi_size(mpi[n]), "certjwk");
-               if (!jwk->e[n].buf)
-                       goto bail;
-               jwk->e[n].len = mbedtls_mpi_size(mpi[n]);
-               mbedtls_mpi_write_binary(mpi[n], jwk->e[n].buf, jwk->e[n].len);
-       }
-
-       ret = 0;
-
-bail:
-       /* jwk destroy will clean up partials */
-       if (ret)
-               lws_jwk_destroy(jwk);
-
-       return ret;
-}
-
-int
-lws_x509_jwk_privkey_pem(struct lws_jwk *jwk, void *pem, size_t len,
-                        const char *passphrase)
-{
-       mbedtls_rsa_context *rsactx;
-       mbedtls_ecp_keypair *ecpctx;
-       mbedtls_pk_context pk;
-       mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT];
-       int n, ret = -1, count = 0;
-
-       mbedtls_pk_init(&pk);
-
-       n = 0;
-       if (passphrase)
-               n = strlen(passphrase);
-       n = mbedtls_pk_parse_key(&pk, pem, len, (uint8_t *)passphrase, n);
-       if (n) {
-               lwsl_err("%s: parse PEM key failed: -0x%x\n", __func__, -n);
-
-               return -1;
-       }
-
-       /* the incoming private key type */
-       switch (mbedtls_pk_get_type(&pk)) {
-       case MBEDTLS_PK_RSA:
-               if (jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
-                       lwsl_err("%s: RSA privkey, non-RSA jwk\n", __func__);
-                       goto bail;
-               }
-               rsactx = mbedtls_pk_rsa(pk);
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_D] = &rsactx->D;
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_P] = &rsactx->P;
-               mpi[LWS_GENCRYPTO_RSA_KEYEL_Q] = &rsactx->Q;
-               n = LWS_GENCRYPTO_RSA_KEYEL_D;
-               count = LWS_GENCRYPTO_RSA_KEYEL_Q + 1;
-               break;
-       case MBEDTLS_PK_ECKEY:
-               if (jwk->kty != LWS_GENCRYPTO_KTY_EC) {
-                       lwsl_err("%s: EC privkey, non-EC jwk\n", __func__);
-                       goto bail;
-               }
-               ecpctx = mbedtls_pk_ec(pk);
-               mpi[LWS_GENCRYPTO_EC_KEYEL_D] = &ecpctx->d;
-               n = LWS_GENCRYPTO_EC_KEYEL_D;
-               count = n + 1;
-               break;
-       default:
-               lwsl_err("%s: unusable key type %d\n", __func__,
-                               mbedtls_pk_get_type(&pk));
-               goto bail;
-       }
-
-       for (; n < count; n++) {
-               if (!mbedtls_mpi_size(mpi[n])) {
-                       lwsl_err("%s: empty privkey\n", __func__);
-                       goto bail;
-               }
-
-               jwk->e[n].buf = lws_malloc(mbedtls_mpi_size(mpi[n]), "certjwk");
-               if (!jwk->e[n].buf)
-                       goto bail;
-               jwk->e[n].len = mbedtls_mpi_size(mpi[n]);
-               mbedtls_mpi_write_binary(mpi[n], jwk->e[n].buf, jwk->e[n].len);
-       }
-
-       ret = 0;
-
-bail:
-       mbedtls_pk_free(&pk);
-
-       return ret;
-}
-#endif
-
-void
-lws_x509_destroy(struct lws_x509_cert **x509)
-{
-       if (!*x509)
-               return;
-
-       mbedtls_x509_crt_free(&(*x509)->cert);
-
-       lws_free_set_NULL(*x509);
-}
index cf3ac36..fa0fe80 100644 (file)
@@ -1,35 +1,40 @@
-/*
- * libwebsockets - generic AES api hiding the backend
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws_genaes provides an AES abstraction api in lws that works the
  *  same whether you are using openssl or mbedtls hash functions underneath.
  */
-#include "core/private.h"
-#include "../../jose/private.h"
+#include "private-lib-core.h"
+#if defined(LWS_WITH_JOSE)
+#include "private-lib-jose.h"
+#endif
 
 /*
  * Care: many openssl apis return 1 for success.  These are translated to the
  * lws convention of 0 for success.
  */
 
-LWS_VISIBLE int
+int
 lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
                  enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el,
                  enum enum_aes_padding padding, void *engine)
@@ -74,19 +79,27 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
                        ctx->cipher = EVP_aes_128_cfb8();
                        break;
 #endif
+#if defined(LWS_HAVE_EVP_aes_128_ctr)
                case LWS_GAESM_CTR:
                        ctx->cipher = EVP_aes_128_ctr();
                        break;
+#endif
+#if defined(LWS_HAVE_EVP_aes_128_ecb)
                case LWS_GAESM_ECB:
                        ctx->cipher = EVP_aes_128_ecb();
                        break;
+#endif
+#if defined(LWS_HAVE_EVP_aes_128_ofb)
                case LWS_GAESM_OFB:
                        ctx->cipher = EVP_aes_128_ofb();
                        break;
+#endif
+#if defined(LWS_HAVE_EVP_aes_128_xts)
                case LWS_GAESM_XTS:
                        lwsl_err("%s: AES XTS requires double-length key\n",
                                 __func__);
                        break;
+#endif
                case LWS_GAESM_GCM:
                        ctx->cipher = EVP_aes_128_gcm();
                        break;
@@ -121,18 +134,26 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
                        ctx->cipher = EVP_aes_192_cfb8();
                        break;
 #endif
+#if defined(LWS_HAVE_EVP_aes_128_ctr)
                case LWS_GAESM_CTR:
                        ctx->cipher = EVP_aes_192_ctr();
                        break;
+#endif
+#if defined(LWS_HAVE_EVP_aes_128_ecb)
                case LWS_GAESM_ECB:
                        ctx->cipher = EVP_aes_192_ecb();
                        break;
+#endif
+#if defined(LWS_HAVE_EVP_aes_128_ofb)
                case LWS_GAESM_OFB:
                        ctx->cipher = EVP_aes_192_ofb();
                        break;
+#endif
+#if defined(LWS_HAVE_EVP_aes_128_xts)
                case LWS_GAESM_XTS:
                        lwsl_err("%s: AES XTS 192 invalid\n", __func__);
                        goto bail;
+#endif
                case LWS_GAESM_GCM:
                        ctx->cipher = EVP_aes_192_gcm();
                        break;
@@ -167,15 +188,21 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
                        ctx->cipher = EVP_aes_256_cfb8();
                        break;
 #endif
+#if defined(LWS_HAVE_EVP_aes_128_ctr)
                case LWS_GAESM_CTR:
                        ctx->cipher = EVP_aes_256_ctr();
                        break;
+#endif
+#if defined(LWS_HAVE_EVP_aes_128_ecb)
                case LWS_GAESM_ECB:
                        ctx->cipher = EVP_aes_256_ecb();
                        break;
+#endif
+#if defined(LWS_HAVE_EVP_aes_128_ofb)
                case LWS_GAESM_OFB:
                        ctx->cipher = EVP_aes_256_ofb();
                        break;
+#endif
 #if defined(LWS_HAVE_EVP_aes_128_xts)
                case LWS_GAESM_XTS:
                        ctx->cipher = EVP_aes_128_xts();
@@ -191,8 +218,10 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
 
        case 512 / 8:
                switch (mode) {
+#if defined(LWS_HAVE_EVP_aes_128_xts)
                case LWS_GAESM_XTS:
                        ctx->cipher = EVP_aes_256_xts();
+#endif
                        break;
                default:
                        goto bail;
@@ -209,12 +238,12 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
        case LWS_GAESO_ENC:
                n = EVP_EncryptInit_ex(ctx->ctx, ctx->cipher, ctx->engine,
                                       NULL, NULL);
-               EVP_CIPHER_CTX_set_padding(ctx->ctx, padding);
+               EVP_CIPHER_CTX_set_padding(ctx->ctx, (int)padding);
                break;
        case LWS_GAESO_DEC:
                n = EVP_DecryptInit_ex(ctx->ctx, ctx->cipher, ctx->engine,
                                       NULL, NULL);
-               EVP_CIPHER_CTX_set_padding(ctx->ctx, padding);
+               EVP_CIPHER_CTX_set_padding(ctx->ctx, (int)padding);
                break;
        }
        if (!n) {
@@ -231,11 +260,11 @@ bail:
        return -1;
 }
 
-LWS_VISIBLE int
+int
 lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen)
 {
-       int outl = 0, n = 0;
        uint8_t buf[256];
+       int outl = sizeof(buf), n = 0;
 
        if (!ctx->ctx)
                return 0;
@@ -258,7 +287,11 @@ lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen)
                                        n = 1;
                                }
                        }
+                       if (ctx->mode == LWS_GAESM_CBC)
+                               memcpy(tag, buf, (unsigned int)outl);
+
                        break;
+
                case LWS_GAESO_DEC:
                        if (EVP_DecryptFinal_ex(ctx->ctx, buf, &outl) != 1) {
                                lwsl_err("%s: dec final failed\n", __func__);
@@ -279,7 +312,7 @@ lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen)
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_genaes_crypt(struct lws_genaes_ctx *ctx,
                 const uint8_t *in, size_t len, uint8_t *out,
                 uint8_t *iv_or_nonce_ctr_or_data_unit_16,
@@ -289,16 +322,16 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx,
 
        if (!ctx->init) {
 
-               EVP_CIPHER_CTX_set_key_length(ctx->ctx, ctx->k->len);
+               EVP_CIPHER_CTX_set_key_length(ctx->ctx, (int)ctx->k->len);
 
                if (ctx->mode == LWS_GAESM_GCM) {
                        n = EVP_CIPHER_CTX_ctrl(ctx->ctx, EVP_CTRL_GCM_SET_IVLEN,
-                                           *nc_or_iv_off, NULL);
+                                          (int)*nc_or_iv_off, NULL);
                        if (n != 1) {
                                lwsl_err("%s: SET_IVLEN failed\n", __func__);
                                return -1;
                        }
-                       memcpy(ctx->tag, stream_block_16, taglen);
+                       memcpy(ctx->tag, stream_block_16, (unsigned int)taglen);
                        ctx->taglen = taglen;
                }
 
@@ -337,10 +370,10 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx,
 
                switch (ctx->op) {
                case LWS_GAESO_ENC:
-                       n = EVP_EncryptUpdate(ctx->ctx, NULL, &olen, in, len);
+                       n = EVP_EncryptUpdate(ctx->ctx, NULL, &olen, in, (int)len);
                        break;
                case LWS_GAESO_DEC:
-                       n = EVP_DecryptUpdate(ctx->ctx, NULL, &olen, in, len);
+                       n = EVP_DecryptUpdate(ctx->ctx, NULL, &olen, in, (int)len);
                        break;
                default:
                        return -1;
@@ -357,10 +390,10 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx,
 
        switch (ctx->op) {
        case LWS_GAESO_ENC:
-               n = EVP_EncryptUpdate(ctx->ctx, out, &outl, in, len);
+               n = EVP_EncryptUpdate(ctx->ctx, out, &outl, in, (int)len);
                break;
        case LWS_GAESO_DEC:
-               n = EVP_DecryptUpdate(ctx->ctx, out, &outl, in, len);
+               n = EVP_DecryptUpdate(ctx->ctx, out, &outl, in, (int)len);
                break;
        default:
                return -1;
index dd74149..efd5e20 100644 (file)
@@ -1,28 +1,31 @@
-/*
- * libwebsockets - generic crypto api hiding the backend
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws-gencrypto openssl-specific common code
  */
 
-#include "core/private.h"
-#include "tls/openssl/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls-openssl.h"
 
 /*
  * Care: many openssl apis return 1 for success.  These are translated to the
index cb62a67..1283009 100644 (file)
@@ -1,34 +1,55 @@
-/*
- * libwebsockets - generic EC api hiding the backend - openssl implementation
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws_genec provides an EC abstraction api in lws that works the
  *  same whether you are using openssl or mbedtls crypto functions underneath.
  */
-#include "core/private.h"
-#include "tls/openssl/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls-openssl.h"
+
+#if !defined(OPENSSL_NO_EC) && defined(LWS_HAVE_EC_KEY_new_by_curve_name) && \
+    (OPENSSL_VERSION_NUMBER >= 0x30000000l) && \
+     !defined(LWS_SUPPRESS_DEPRECATED_API_WARNINGS)
+/* msvc doesn't have #warning... */
+#error "You probably need LWS_SUPPRESS_DEPRECATED_API_WARNINGS"
+#endif
+
+#if defined(USE_WOLFSSL)
+#include "openssl/ecdh.h"
+#endif
 
 /*
  * Care: many openssl apis return 1 for success.  These are translated to the
  * lws convention of 0 for success.
  */
 
+#if defined(USE_WOLFSSL)
+EVP_PKEY * EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *p)
+{
+       return p->pkey;
+}
+#endif
+
 #if !defined(LWS_HAVE_ECDSA_SIG_set0)
 static void
 ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
@@ -56,20 +77,28 @@ ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
 int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen)
 {
     int i;
+#if !defined(USE_WOLFSSL)
     BN_ULONG l;
+#endif
 
+#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(USE_WOLFSSL)
     bn_check_top(a);
+#endif
     i = BN_num_bytes(a);
 
     /* Add leading zeroes if necessary */
     if (tolen > i) {
-        memset(to, 0, tolen - i);
+        memset(to, 0, (size_t)(tolen - i));
         to += tolen - i;
     }
+#if defined(USE_WOLFSSL)
+    BN_bn2bin(a, to);
+#else
     while (i--) {
         l = a->d[i / BN_BYTES];
         *(to++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff;
     }
+#endif
     return tolen;
 }
 #endif
@@ -90,7 +119,8 @@ const struct lws_ec_curves lws_ec_curves[4] = {
 };
 
 static int
-lws_genec_eckey_import(int nid, EVP_PKEY *pkey, struct lws_gencrypto_keyelem *el)
+lws_genec_eckey_import(int nid, EVP_PKEY *pkey,
+                      const struct lws_gencrypto_keyelem *el)
 {
        EC_KEY *ec = EC_KEY_new_by_curve_name(nid);
        BIGNUM *bn_d, *bn_x, *bn_y;
@@ -108,19 +138,34 @@ lws_genec_eckey_import(int nid, EVP_PKEY *pkey, struct lws_gencrypto_keyelem *el
         */
 
        bn_x = BN_bin2bn(el[LWS_GENCRYPTO_EC_KEYEL_X].buf,
-                        el[LWS_GENCRYPTO_EC_KEYEL_X].len, NULL);
+                        (int)el[LWS_GENCRYPTO_EC_KEYEL_X].len, NULL);
        if (!bn_x) {
                lwsl_err("%s: BN_bin2bn (x) fail\n", __func__);
                goto bail;
        }
        bn_y = BN_bin2bn(el[LWS_GENCRYPTO_EC_KEYEL_Y].buf,
-                        el[LWS_GENCRYPTO_EC_KEYEL_Y].len, NULL);
+                       (int)el[LWS_GENCRYPTO_EC_KEYEL_Y].len, NULL);
        if (!bn_y) {
                lwsl_err("%s: BN_bin2bn (y) fail\n", __func__);
                goto bail1;
        }
 
+       /*
+        * EC_KEY_set_public_key_affine_coordinates sets the public key for
+        * key based on its affine co-ordinates, i.e. it constructs an
+        * EC_POINT object based on the supplied x and y values and sets
+        * the public key to be this EC_POINT. It will also performs
+        * certain sanity checks on the key to confirm that it is valid.
+        */
+
+#if defined(USE_WOLFSSL)
+       n = wolfSSL_EC_POINT_set_affine_coordinates_GFp(ec->group,
+                                                ec->pub_key,
+                                                bn_x, bn_y,
+                                                NULL);
+#else
        n = EC_KEY_set_public_key_affine_coordinates(ec, bn_x, bn_y);
+#endif
        BN_free(bn_x);
        BN_free(bn_y);
        if (n != 1) {
@@ -132,7 +177,7 @@ lws_genec_eckey_import(int nid, EVP_PKEY *pkey, struct lws_gencrypto_keyelem *el
 
        if (el[LWS_GENCRYPTO_EC_KEYEL_D].len) {
                bn_d = BN_bin2bn(el[LWS_GENCRYPTO_EC_KEYEL_D].buf,
-                                el[LWS_GENCRYPTO_EC_KEYEL_D].len, NULL);
+                               (int)el[LWS_GENCRYPTO_EC_KEYEL_D].len, NULL);
                if (!bn_d) {
                        lwsl_err("%s: BN_bin2bn (d) fail\n", __func__);
                        goto bail;
@@ -148,10 +193,12 @@ lws_genec_eckey_import(int nid, EVP_PKEY *pkey, struct lws_gencrypto_keyelem *el
 
        /* explicitly confirm the key pieces are consistent */
 
+#if !defined(USE_WOLFSSL)
        if (EC_KEY_check_key(ec) != 1) {
                lwsl_err("%s: EC_KEY_set_private_key fail\n", __func__);
                goto bail;
        }
+#endif
 
        n = EVP_PKEY_assign_EC_KEY(pkey, ec);
        if (n != 1) {
@@ -172,7 +219,8 @@ bail:
 static int
 lws_genec_keypair_import(struct lws_genec_ctx *ctx,
                         const struct lws_ec_curves *curve_table,
-                        EVP_PKEY_CTX **pctx, struct lws_gencrypto_keyelem *el)
+                        EVP_PKEY_CTX **pctx,
+                        const struct lws_gencrypto_keyelem *el)
 {
        EVP_PKEY *pkey = NULL;
        const struct lws_ec_curves *curve;
@@ -223,7 +271,7 @@ bail:
        return -9;
 }
 
-LWS_VISIBLE int
+int
 lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context,
                   const struct lws_ec_curves *curve_table)
 {
@@ -236,7 +284,7 @@ lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context,
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context,
                    const struct lws_ec_curves *curve_table)
 {
@@ -249,7 +297,7 @@ lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context,
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el,
                    enum enum_lws_dh_side side)
 {
@@ -259,9 +307,9 @@ lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el,
        return lws_genec_keypair_import(ctx, ctx->curve_table, &ctx->ctx[side], el);
 }
 
-LWS_VISIBLE int
+int
 lws_genecdsa_set_key(struct lws_genec_ctx *ctx,
-                    struct lws_gencrypto_keyelem *el)
+                    const struct lws_gencrypto_keyelem *el)
 {
        if (ctx->genec_alg != LEGENEC_ECDSA)
                return -1;
@@ -283,7 +331,7 @@ lws_genec_keypair_destroy(EVP_PKEY_CTX **pctx)
        *pctx = NULL;
 }
 
-LWS_VISIBLE void
+void
 lws_genec_destroy(struct lws_genec_ctx *ctx)
 {
        if (ctx->ctx[0])
@@ -363,7 +411,7 @@ lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
                goto bail2;
        }
 
-       el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = strlen(curve_name) + 1;
+       el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = (uint32_t)strlen(curve_name) + 1;
        el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf =
                        lws_malloc(el[LWS_GENCRYPTO_EC_KEYEL_CRV].len, "ec");
        if (!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) {
@@ -380,7 +428,7 @@ lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
                if (!el[n].buf)
                        goto bail2;
 
-               m = BN_bn2binpad(bn[n - 1], el[n].buf, el[n].len);
+               m = BN_bn2binpad(bn[n - 1], el[n].buf, (int32_t)el[n].len);
                if ((uint32_t)m != el[n].len)
                        goto bail2;
        }
@@ -400,7 +448,7 @@ bail:
        return ret;
 }
 
-LWS_VISIBLE int
+int
 lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
                        const char *curve_name,
                        struct lws_gencrypto_keyelem *el)
@@ -411,7 +459,7 @@ lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
        return lws_genec_new_keypair(ctx, side, curve_name, el);
 }
 
-LWS_VISIBLE int
+int
 lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name,
                         struct lws_gencrypto_keyelem *el)
 {
@@ -422,7 +470,7 @@ lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name,
 }
 
 #if 0
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_genecdsa_hash_sign(struct lws_genec_ctx *ctx, const uint8_t *in,
                       enum lws_genhash_types hash_type,
                       uint8_t *sig, size_t sig_len)
@@ -468,12 +516,13 @@ bail:
 }
 #endif
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
                           enum lws_genhash_types hash_type, int keybits,
                           uint8_t *sig, size_t sig_len)
 {
        int ret = -1, n, keybytes = lws_gencrypto_bits_to_bytes(keybits);
+       size_t hs = lws_genhash_size(hash_type);
        const BIGNUM *r = NULL, *s = NULL;
        ECDSA_SIG *ecdsasig;
        EC_KEY *eckey;
@@ -486,9 +535,9 @@ lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
        if (!ctx->has_private)
                return -1;
 
-       if ((int)sig_len < keybytes * 2) {
+       if ((int)sig_len != (int)(keybytes * 2)) {
                lwsl_notice("%s: sig buff %d < %d\n", __func__,
-                           (int)sig_len, keybytes * 2);
+                           (int)sig_len, (int)(hs * 2));
                return -1;
        }
 
@@ -513,7 +562,7 @@ lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
         * 4.  The resulting 64-octet sequence is the JWS Signature value.
         */
 
-       ecdsasig = ECDSA_do_sign(in, lws_genhash_size(hash_type), eckey);
+       ecdsasig = ECDSA_do_sign(in, (int)hs, eckey);
        EC_KEY_free(eckey);
        if (!ecdsasig) {
                lwsl_notice("%s: ECDSA_do_sign fail\n", __func__);
@@ -550,13 +599,13 @@ bail:
 
 /* in is the JWS Signing Input hash */
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
                                 enum lws_genhash_types hash_type, int keybits,
                                 const uint8_t *sig, size_t sig_len)
 {
-       int ret = -1, n, keybytes = lws_gencrypto_bits_to_bytes(keybits),
-           hlen = lws_genhash_size(hash_type);
+       int ret = -1, n, hlen = (int)lws_genhash_size(hash_type),
+                       keybytes = lws_gencrypto_bits_to_bytes(keybits);
        ECDSA_SIG *ecsig = ECDSA_SIG_new();
        BIGNUM *r = NULL, *s = NULL;
        EC_KEY *eckey;
@@ -568,7 +617,7 @@ lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
                goto bail;
 
        if ((int)sig_len != keybytes * 2) {
-               lwsl_err("%s: sig buf too small %d vs %d\n", __func__,
+               lwsl_err("%s: sig buf size %d vs %d\n", __func__,
                         (int)sig_len, keybytes * 2);
                goto bail;
        }
@@ -608,7 +657,7 @@ lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
        n = ECDSA_do_verify(in, hlen, ecsig, eckey);
        EC_KEY_free(eckey);
        if (n != 1) {
-               lwsl_err("%s: ECDSA_do_verify fail\n", __func__);
+               lwsl_err("%s: ECDSA_do_verify fail, hlen %d\n", __func__, (int)hlen);
                lws_tls_err_describe_clear();
                goto bail;
        }
@@ -648,7 +697,12 @@ lws_genecdh_compute_shared_secret(struct lws_genec_ctx *ctx, uint8_t *ss,
 
        len = (EC_GROUP_get_degree(EC_KEY_get0_group(eckey[LDHS_OURS])) + 7) / 8;
        if (len <= *ss_len) {
-               *ss_len = ECDH_compute_key(ss, len,
+#if defined(USE_WOLFSSL)
+               *ss_len = wolfSSL_ECDH_compute_key(
+#else
+               *ss_len = ECDH_compute_key(
+#endif
+                               ss, (unsigned int)len,
                                EC_KEY_get0_public_key(eckey[LDHS_THEIRS]),
                                eckey[LDHS_OURS], NULL);
                ret = -(*ss_len < 0);
index afe98ec..5363bcb 100644 (file)
@@ -1,28 +1,32 @@
-/*
- * libwebsockets - generic hash and HMAC api hiding the backend
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws_genhash provides a hash / hmac abstraction api in lws that works the
  *  same whether you are using openssl or mbedtls hash functions underneath.
  */
-#include "libwebsockets.h"
+#include <private-lib-core.h>
 #include <openssl/obj_mac.h>
+#include <openssl/opensslv.h>
 /*
  * Care: many openssl apis return 1 for success.  These are translated to the
  * lws convention of 0 for success.
@@ -31,7 +35,7 @@
 int
 lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type)
 {
-       ctx->type = type;
+       ctx->type = (uint8_t)type;
        ctx->mdctx = EVP_MD_CTX_create();
        if (!ctx->mdctx)
                return 1;
@@ -80,16 +84,92 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result)
        unsigned int len;
        int ret = 0;
 
+       if (!ctx->mdctx)
+               return 0;
+
        if (result)
                ret = EVP_DigestFinal_ex(ctx->mdctx, result, &len) != 1;
 
        (void)len;
 
        EVP_MD_CTX_destroy(ctx->mdctx);
+       ctx->mdctx = NULL;
 
        return ret;
 }
 
+#if defined(LWS_HAVE_EVP_PKEY_new_raw_private_key)
+
+int
+lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
+                const uint8_t *key, size_t key_len)
+{
+       ctx->ctx = EVP_MD_CTX_create();
+       if (!ctx->ctx)
+               return -1;
+
+       ctx->evp_type = 0;
+       ctx->type = (uint8_t)type;
+
+       switch (type) {
+       case LWS_GENHMAC_TYPE_SHA256:
+               ctx->evp_type = EVP_sha256();
+               break;
+       case LWS_GENHMAC_TYPE_SHA384:
+               ctx->evp_type = EVP_sha384();
+               break;
+       case LWS_GENHMAC_TYPE_SHA512:
+               ctx->evp_type = EVP_sha512();
+               break;
+       default:
+               lwsl_err("%s: unknown HMAC type %d\n", __func__, type);
+               goto bail;
+       }
+
+       ctx->key = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, key_len);
+       if (!ctx->key)
+               goto bail;
+
+       if (EVP_DigestSignInit(ctx->ctx, NULL, ctx->evp_type, NULL, ctx->key) != 1)
+               goto bail1;
+
+       return 0;
+
+bail1:
+       EVP_PKEY_free(ctx->key);
+bail:
+       EVP_MD_CTX_free(ctx->ctx);
+
+       return -1;
+}
+
+int
+lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len)
+{
+
+       if (EVP_DigestSignUpdate(ctx->ctx, in, len) != 1)
+               return -1;
+
+       return 0;
+}
+
+int
+lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result)
+{
+       size_t size = (size_t)lws_genhmac_size(ctx->type);
+       int n;
+
+       n = EVP_DigestSignFinal(ctx->ctx, result, &size);
+       EVP_MD_CTX_free(ctx->ctx);
+       EVP_PKEY_free(ctx->key);
+
+       if (n != 1)
+               return -1;
+
+       return 0;
+}
+
+#else
 
 int
 lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
@@ -103,7 +183,8 @@ lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
        HMAC_CTX_init(&ctx->ctx);
 #endif
 
-       ctx->evp_type = 0; /* coverity unable to see we set this or fail */
+       ctx->evp_type = 0;
+       ctx->type = (uint8_t)type;
 
        switch (type) {
        case LWS_GENHMAC_TYPE_SHA256:
@@ -121,9 +202,9 @@ lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
        }
 
 #if defined(LWS_HAVE_HMAC_CTX_new)
-        if (HMAC_Init_ex(ctx->ctx, key, key_len, ctx->evp_type, NULL) != 1)
+        if (HMAC_Init_ex(ctx->ctx, key, (int)key_len, ctx->evp_type, NULL) != 1)
 #else
-        if (HMAC_Init_ex(&ctx->ctx, key, key_len, ctx->evp_type, NULL) != 1)
+        if (HMAC_Init_ex(&ctx->ctx, key, (int)key_len, ctx->evp_type, NULL) != 1)
 #endif
                goto bail;
 
@@ -141,8 +222,12 @@ int
 lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len)
 {
 #if defined(LWS_HAVE_HMAC_CTX_new)
+#if defined(LIBRESSL_VERSION_NUMBER)
        if (HMAC_Update(ctx->ctx, in, len) != 1)
 #else
+       if (HMAC_Update(ctx->ctx, in, (int)len) != 1)
+#endif
+#else /* HMAC_CTX_new */
        if (HMAC_Update(&ctx->ctx, in, len) != 1)
 #endif
                return -1;
@@ -153,7 +238,7 @@ lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len)
 int
 lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result)
 {
-       unsigned int size = lws_genhmac_size(ctx->type);
+       unsigned int size = (unsigned int)lws_genhmac_size(ctx->type);
 #if defined(LWS_HAVE_HMAC_CTX_new)
        int n = HMAC_Final(ctx->ctx, result, &size);
 
@@ -168,3 +253,5 @@ lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result)
        return 0;
 }
 
+
+#endif
index ec7bde8..985246c 100644 (file)
@@ -1,35 +1,38 @@
-/*
- * libwebsockets - generic RSA api hiding the backend
+ /*
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  lws_genrsa provides an RSA abstraction api in lws that works the
  *  same whether you are using openssl or mbedtls crypto functions underneath.
  */
-#include "core/private.h"
-#include "tls/openssl/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls-openssl.h"
 
 /*
  * Care: many openssl apis return 1 for success.  These are translated to the
  * lws convention of 0 for success.
  */
 
-LWS_VISIBLE void
+void
 lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el)
 {
        lws_gencrypto_destroy_elements(el, LWS_GENCRYPTO_RSA_KEYEL_COUNT);
@@ -73,8 +76,9 @@ bail:
        return 1;
 }
 
-LWS_VISIBLE int
-lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
+int
+lws_genrsa_create(struct lws_genrsa_ctx *ctx,
+                 const struct lws_gencrypto_keyelem *el,
                  struct lws_context *context, enum enum_genrsa_mode mode,
                  enum lws_genhash_types oaep_hashid)
 {
@@ -90,7 +94,7 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
         */
 
        for (n = 0; n < 5; n++) {
-               ctx->bn[n] = BN_bin2bn(el[n].buf, el[n].len, NULL);
+               ctx->bn[n] = BN_bin2bn(el[n].buf, (int)el[n].len, NULL);
                if (!ctx->bn[n]) {
                        lwsl_notice("mpi load failed\n");
                        goto bail;
@@ -108,7 +112,7 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
                goto bail;
        }
 
-#if defined(LWS_HAVE_RSA_SET0_KEY)
+#if defined(LWS_HAVE_RSA_SET0_KEY) && !defined(USE_WOLFSSL) 
        if (RSA_set0_key(ctx->rsa, ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_N],
                         ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_E],
                         ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_D]) != 1) {
@@ -143,7 +147,7 @@ bail:
        return 1;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
                       enum enum_genrsa_mode mode, struct lws_gencrypto_keyelem *el,
                       int bits)
@@ -174,7 +178,7 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
        if (n != 1)
                goto cleanup_1;
 
-#if defined(LWS_HAVE_RSA_SET0_KEY)
+#if defined(LWS_HAVE_RSA_SET0_KEY) && !defined(USE_WOLFSSL)
        {
                const BIGNUM *mpi[5];
 
@@ -190,10 +194,10 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
                for (n = 0; n < 5; n++)
                        if (BN_num_bytes(mpi[n])) {
                                el[n].buf = lws_malloc(
-                                       BN_num_bytes(mpi[n]), "genrsakey");
+                                       (unsigned int)BN_num_bytes(mpi[n]), "genrsakey");
                                if (!el[n].buf)
                                        goto cleanup;
-                               el[n].len = BN_num_bytes(mpi[n]);
+                               el[n].len = (unsigned int)BN_num_bytes(mpi[n]);
                                BN_bn2bin(mpi[n], el[n].buf);
                        }
        }
@@ -217,7 +221,7 @@ cleanup_1:
  * based padding modes
  */
 
-LWS_VISIBLE int
+int
 lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                          size_t in_len, uint8_t *out)
 {
@@ -232,7 +236,7 @@ lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                           size_t in_len, uint8_t *out)
 {
@@ -247,7 +251,7 @@ lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                          size_t in_len, uint8_t *out, size_t out_max)
 {
@@ -261,7 +265,7 @@ lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                           size_t in_len, uint8_t *out, size_t out_max)
 {
@@ -276,7 +280,7 @@ lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                         enum lws_genhash_types hash_type, const uint8_t *sig,
                         size_t sig_len)
@@ -290,7 +294,8 @@ lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in,
 
        switch(ctx->mode) {
        case LGRSAM_PKCS1_1_5:
-               n = RSA_verify(n, in, h, (uint8_t *)sig, (int)sig_len, ctx->rsa);
+               n = RSA_verify(n, in, (unsigned int)h, (uint8_t *)sig,
+                              (unsigned int)sig_len, ctx->rsa);
                break;
        case LGRSAM_PKCS1_OAEP_PSS:
                md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type);
@@ -319,7 +324,7 @@ lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in,
        return 0;
 }
 
-LWS_VISIBLE int
+int
 lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                       enum lws_genhash_types hash_type, uint8_t *sig,
                       size_t sig_len)
@@ -335,7 +340,7 @@ lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in,
 
        switch(ctx->mode) {
        case LGRSAM_PKCS1_1_5:
-               if (RSA_sign(n, in, h, sig, &used, ctx->rsa) != 1) {
+               if (RSA_sign(n, in, (unsigned int)h, sig, &used, ctx->rsa) != 1) {
                        lwsl_err("%s: RSA_sign failed\n", __func__);
 
                        goto bail;
@@ -360,12 +365,16 @@ lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                        goto bail;
 
                if (EVP_DigestSignInit(mdctx, NULL, md, NULL,
+#if defined(USE_WOLFSSL)
+                                       ctx->ctx->pkey)) {
+#else
                                       EVP_PKEY_CTX_get0_pkey(ctx->ctx))) {
+#endif
                        lwsl_err("%s: EVP_DigestSignInit failed\n", __func__);
 
                        goto bail;
                }
-               if (EVP_DigestSignUpdate(mdctx, in, EVP_MD_size(md))) {
+               if (EVP_DigestSignUpdate(mdctx, in, (unsigned int)EVP_MD_size(md))) {
                        lwsl_err("%s: EVP_DigestSignUpdate failed\n", __func__);
 
                        goto bail;
@@ -376,14 +385,14 @@ lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in,
                        goto bail;
                }
                EVP_MD_CTX_free(mdctx);
-               used = (int)sig_len;
+               used = (unsigned int)sig_len;
                break;
 
        default:
                return -1;
        }
 
-       return used;
+       return (int)used;
 
 bail:
        if (mdctx)
@@ -392,7 +401,7 @@ bail:
        return -1;
 }
 
-LWS_VISIBLE void
+void
 lws_genrsa_destroy(struct lws_genrsa_ctx *ctx)
 {
        if (!ctx->ctx)
index e7d51c7..d8c56c5 100644 (file)
@@ -1,27 +1,38 @@
 /*
- * libwebsockets - openSSL-specific client tls code
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "lws_config.h"
+#ifdef LWS_HAVE_X509_VERIFY_PARAM_set1_host
+/* Before glibc 2.10, strnlen required _GNU_SOURCE */
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#endif
+#include <string.h>
 
-#include "tls/openssl/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls-openssl.h"
 
 /*
  * Care: many openssl apis return 1 for success.  These are translated to the
@@ -35,16 +46,56 @@ extern int openssl_websocket_private_data_index,
 
 #if !defined(USE_WOLFSSL)
 
+#if 0
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+
+/*
+ * Completion of sync or async JIT trust lookup
+ */
+
+int
+lws_tls_jit_trust_got_cert_cb(void *got_opaque, const uint8_t *der,
+                             size_t der_len)
+{
+       X509 *x = d2i_X509(NULL, &der, (long)der_len);
+       /** !!! this is not safe for async atm */
+       struct lws *wsi = (struct lws *)got_opaque;
+       X509_STORE *xs;
+       int ret = 0;
+
+       if (!x) {
+               lwsl_err("%s: failed\n", __func__);
+               return 1;
+       }
+
+       xs = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(wsi->tls.ssl));
+       if (xs) {
+               if (X509_STORE_add_cert(xs, x) != 1) {
+                       lwsl_warn("%s: unable to set trusted CA\n", __func__);
+                       ret = 1;
+               } else
+                       lwsl_notice("%s: added trusted CA to CTX for next time\n",
+                                       __func__);
+       } else
+               lwsl_warn("%s: couldn't get cert store\n", __func__);
+
+       X509_free(x);
+
+       return ret;
+}
+#endif
+#endif
+
 static int
 OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
 {
        SSL *ssl;
-       int n;
+       int n, err = 0;
        struct lws *wsi;
 
        /* keep old behaviour accepting self-signed server certs */
        if (!preverify_ok) {
-               int err = X509_STORE_CTX_get_error(x509_ctx);
+               err = X509_STORE_CTX_get_error(x509_ctx);
 
                if (err != X509_V_OK) {
                        ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
@@ -97,9 +148,46 @@ OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
                return 0;
        }
 
-       n = lws_get_context_protocol(wsi->context, 0).callback(wsi,
+#if defined(LWS_WITH_TLS_JIT_TRUST)
+       if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) {
+               union lws_tls_cert_info_results ci;
+               STACK_OF(X509) *x509_stack;
+
+               x509_stack = X509_STORE_CTX_get1_chain(x509_ctx);
+               if (x509_stack) {
+
+                       for (n = 0; n < OPENSSL_sk_num((const OPENSSL_STACK *)x509_stack) &&
+                                   wsi->tls.kid_chain.count !=
+                                    LWS_ARRAY_SIZE(wsi->tls.kid_chain.akid); n++) {
+                               X509 *x509 = OPENSSL_sk_value((const OPENSSL_STACK *)x509_stack, n);
+
+                               if (!lws_tls_openssl_cert_info(x509,
+                                           LWS_TLS_CERT_INFO_SUBJECT_KEY_ID,
+                                           &ci, 0))
+                                       lws_tls_kid_copy(&ci,
+                                               &wsi->tls.kid_chain.skid[
+                                                    wsi->tls.kid_chain.count]);
+
+                               if (!lws_tls_openssl_cert_info(x509,
+                                            LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID,
+                                            &ci, 0))
+                                       lws_tls_kid_copy(&ci,
+                                                &wsi->tls.kid_chain.akid[
+                                                    wsi->tls.kid_chain.count]);
+
+                               wsi->tls.kid_chain.count++;
+                       }
+
+                       sk_X509_pop_free(x509_stack, X509_free);
+               }
+
+               lws_tls_jit_trust_sort_kids(wsi, &wsi->tls.kid_chain);
+       }
+#endif
+
+       n = lws_get_context_protocol(wsi->a.context, 0).callback(wsi,
                        LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION,
-                       x509_ctx, ssl, preverify_ok);
+                       x509_ctx, ssl, (unsigned int)preverify_ok);
 
        /* keep old behaviour if something wrong with server certs */
        /* if ssl error is overruled in callback and cert is ok,
@@ -113,9 +201,24 @@ OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
                        int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
                        const char *msg = X509_verify_cert_error_string(err);
 
+                       lws_strncpy(wsi->tls.err_helper, msg,
+                                   sizeof(wsi->tls.err_helper));
+
                        lwsl_err("SSL error: %s (preverify_ok=%d;err=%d;"
                                 "depth=%d)\n", msg, preverify_ok, err, depth);
 
+#if defined(LWS_WITH_SYS_METRICS)
+                       {
+                               char buckname[64];
+
+                               lws_snprintf(buckname, sizeof(buckname),
+                                            "tls=\"%s\"", msg);
+                               lws_metrics_hist_bump_describe_wsi(wsi,
+                                       lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures),
+                                       buckname);
+                       }
+#endif
+
                        return preverify_ok;    // not ok
                }
        }
@@ -127,7 +230,6 @@ OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
 }
 #endif
 
-
 int
 lws_ssl_client_bio_create(struct lws *wsi)
 {
@@ -135,18 +237,26 @@ lws_ssl_client_bio_create(struct lws *wsi)
 #if defined(LWS_HAVE_SSL_set_alpn_protos) && \
     defined(LWS_HAVE_SSL_get0_alpn_selected)
        uint8_t openssl_alpn[40];
-       const char *alpn_comma = wsi->context->tls.alpn_default;
+       const char *alpn_comma = wsi->a.context->tls.alpn_default;
        int n;
 #endif
 
+       if (wsi->stash) {
+               lws_strncpy(hostname, wsi->stash->cis[CIS_HOST], sizeof(hostname));
+#if defined(LWS_HAVE_SSL_set_alpn_protos) && \
+    defined(LWS_HAVE_SSL_get0_alpn_selected)
+               alpn_comma = wsi->stash->cis[CIS_ALPN];
+#endif
+       } else {
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-       if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
-                        _WSI_TOKEN_CLIENT_HOST) <= 0)
+               if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
+                                _WSI_TOKEN_CLIENT_HOST) <= 0)
 #endif
-       {
-               lwsl_err("%s: Unable to get hostname\n", __func__);
+               {
+                       lwsl_err("%s: Unable to get hostname\n", __func__);
 
-               return -1;
+                       return -1;
+               }
        }
 
        /*
@@ -162,29 +272,45 @@ lws_ssl_client_bio_create(struct lws *wsi)
                p++;
        }
 
-       wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_client_ctx);
+       wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_client_ctx);
        if (!wsi->tls.ssl) {
-               lwsl_err("SSL_new failed: %s\n",
-                        ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
+               const char *es = ERR_error_string(
+#if defined(LWS_WITH_BORINGSSL)
+       (uint32_t)
+#else
+       (unsigned long)
+#endif
+       lws_ssl_get_error(wsi, 0), NULL);
+               lwsl_err("SSL_new failed: %s\n", es);
                lws_tls_err_describe_clear();
                return -1;
        }
 
+#if defined(LWS_WITH_TLS_SESSIONS)
+       if (!(wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE))
+               lws_tls_reuse_session(wsi);
+#endif
+
 #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
-       if (wsi->vhost->tls.ssl_info_event_mask)
+       if (wsi->a.vhost->tls.ssl_info_event_mask)
                SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
 #endif
 
-#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
+#if defined(LWS_HAVE_X509_VERIFY_PARAM_set1_host)
        if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
+#if !defined(USE_WOLFSSL)
+
                X509_VERIFY_PARAM *param = SSL_get0_param(wsi->tls.ssl);
 
                /* Enable automatic hostname checks */
                X509_VERIFY_PARAM_set_hostflags(param,
                                        X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
-               // Handle the case where the hostname is an IP address.
+               /* Handle the case where the hostname is an IP address */
                if (!X509_VERIFY_PARAM_set1_ip_asc(param, hostname))
-                       X509_VERIFY_PARAM_set1_host(param, hostname, 0);
+                       X509_VERIFY_PARAM_set1_host(param, hostname,
+                                       strnlen(hostname, sizeof(hostname)));
+#endif
+
        }
 #else
        if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
@@ -217,9 +343,9 @@ lws_ssl_client_bio_create(struct lws *wsi)
                      strlen(hostname));
 #endif
 #else
-#ifdef WOLFSSL_SNI_HOST_NAME
+#if defined(WOLFSSL_SNI_HOST_NAME) || defined(HAVE_SNI)
        wolfSSL_UseSNI(wsi->tls.ssl, WOLFSSL_SNI_HOST_NAME, hostname,
-                      strlen(hostname));
+                      (unsigned short)strlen(hostname));
 #endif
 #endif
 #else
@@ -237,15 +363,15 @@ lws_ssl_client_bio_create(struct lws *wsi)
         * Otherwise the connect will simply fail with error code -155
         */
 #ifdef USE_OLD_CYASSL
-       if (wsi->tls.use_ssl == 2)
+       if (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)
                CyaSSL_set_verify(wsi->tls.ssl, SSL_VERIFY_NONE, NULL);
 #else
-       if (wsi->tls.use_ssl == 2)
+       if (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)
                wolfSSL_set_verify(wsi->tls.ssl, SSL_VERIFY_NONE, NULL);
 #endif
 #endif /* USE_WOLFSSL */
 
-       wsi->tls.client_bio = BIO_new_socket((int)(long long)wsi->desc.sockfd,
+       wsi->tls.client_bio = BIO_new_socket((int)(lws_intptr_t)wsi->desc.sockfd,
                                             BIO_NOCLOSE);
        SSL_set_bio(wsi->tls.ssl, wsi->tls.client_bio, wsi->tls.client_bio);
 
@@ -261,30 +387,126 @@ lws_ssl_client_bio_create(struct lws *wsi)
 
 #if defined(LWS_HAVE_SSL_set_alpn_protos) && \
     defined(LWS_HAVE_SSL_get0_alpn_selected)
-       if (wsi->vhost->tls.alpn)
-               alpn_comma = wsi->vhost->tls.alpn;
+       if (wsi->a.vhost->tls.alpn)
+               alpn_comma = wsi->a.vhost->tls.alpn;
+       if (wsi->stash)
+               alpn_comma = wsi->stash->cis[CIS_ALPN];
 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
        if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
                         _WSI_TOKEN_CLIENT_ALPN) > 0)
                alpn_comma = hostname;
 #endif
 
-       lwsl_info("client conn using alpn list '%s'\n", alpn_comma);
+       lwsl_info("%s client conn using alpn list '%s'\n", wsi->role_ops->name, alpn_comma);
 
        n = lws_alpn_comma_to_openssl(alpn_comma, openssl_alpn,
                                      sizeof(openssl_alpn) - 1);
 
-       SSL_set_alpn_protos(wsi->tls.ssl, openssl_alpn, n);
+       SSL_set_alpn_protos(wsi->tls.ssl, openssl_alpn, (unsigned int)n);
 #endif
 
        SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index,
                        wsi);
 
+       if (wsi->sys_tls_client_cert) {
+               lws_system_blob_t *b = lws_system_get_blob(wsi->a.context,
+                                       LWS_SYSBLOB_TYPE_CLIENT_CERT_DER,
+                                       wsi->sys_tls_client_cert - 1);
+               const uint8_t *data;
+               size_t size;
+
+               if (!b)
+                       goto no_client_cert;
+
+               /*
+                * Set up the per-connection client cert
+                */
+
+               size = lws_system_blob_get_size(b);
+               if (!size)
+                       goto no_client_cert;
+
+               if (lws_system_blob_get_single_ptr(b, &data))
+                       goto no_client_cert;
+
+               if (SSL_use_certificate_ASN1(wsi->tls.ssl,
+#if defined(USE_WOLFSSL)
+                       (unsigned char *)
+#endif
+                                       data,
+#if defined(LWS_WITH_BORINGSSL)
+                                       (size_t)
+#else
+                                       (int)
+#endif
+                                       size) != 1) {
+                       lwsl_err("%s: use_certificate failed\n", __func__);
+                       lws_tls_err_describe_clear();
+                       goto no_client_cert;
+               }
+
+               b = lws_system_get_blob(wsi->a.context,
+                                       LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
+                                       wsi->sys_tls_client_cert - 1);
+               if (!b)
+                       goto no_client_cert;
+
+               size = lws_system_blob_get_size(b);
+               if (!size)
+                       goto no_client_cert;
+
+               if (lws_system_blob_get_single_ptr(b, &data))
+                       goto no_client_cert;
+
+               if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, wsi->tls.ssl,
+#if defined(USE_WOLFSSL)
+                       (unsigned char *)
+#endif
+
+                                           data,
+#if defined(LWS_WITH_BORINGSSL)
+                                       (size_t)
+#else
+                                       (int)
+#endif
+                                           size) != 1 &&
+                   SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, wsi->tls.ssl,
+#if defined(USE_WOLFSSL)
+                       (unsigned char *)
+#endif
+                                           data,
+#if defined(LWS_WITH_BORINGSSL)
+                                       (size_t)
+#else
+                                       (int)
+#endif
+                                           size) != 1) {
+                       lwsl_err("%s: use_privkey failed\n", __func__);
+                       lws_tls_err_describe_clear();
+                       goto no_client_cert;
+               }
+
+               if (SSL_check_private_key(wsi->tls.ssl) != 1) {
+                       lwsl_err("Private SSL key doesn't match cert\n");
+                       lws_tls_err_describe_clear();
+                       return 1;
+               }
+
+               lwsl_notice("%s: set system client cert %u\n", __func__,
+                               wsi->sys_tls_client_cert - 1);
+       }
+
        return 0;
+
+no_client_cert:
+       lwsl_err("%s: unable to set up system client cert %d\n", __func__,
+                       wsi->sys_tls_client_cert - 1);
+
+       return 1;
 }
 
 enum lws_ssl_capable_status
-lws_tls_client_connect(struct lws *wsi)
+lws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen)
 {
 #if defined(LWS_HAVE_SSL_set_alpn_protos) && \
     defined(LWS_HAVE_SSL_get0_alpn_selected)
@@ -292,12 +514,58 @@ lws_tls_client_connect(struct lws *wsi)
        char a[32];
        unsigned int len;
 #endif
-       int m, n;
-
+       int m, n, en;
+#if defined(LWS_WITH_TLS_SESSIONS) && defined(LWS_HAVE_SSL_SESSION_set_time)
+       SSL_SESSION *sess;
+#endif
        errno = 0;
        ERR_clear_error();
+       wsi->tls.err_helper[0] = '\0';
        n = SSL_connect(wsi->tls.ssl);
-       if (n == 1) {
+       en = errno;
+
+       m = lws_ssl_get_error(wsi, n);
+
+       if (m == SSL_ERROR_SYSCALL
+#if defined(WIN32)
+                       && en
+#endif
+       ) {
+#if defined(WIN32) || (_LWS_ENABLED_LOGS & LLL_INFO)
+               lwsl_info("%s: n %d, m %d, errno %d\n", __func__, n, m, en);
+#endif
+               lws_snprintf(errbuf, elen, "connect SYSCALL %d", en);
+               return LWS_SSL_CAPABLE_ERROR;
+       }
+
+       if (m == SSL_ERROR_SSL) {
+               n = lws_snprintf(errbuf, elen, "tls: %s", wsi->tls.err_helper);
+               if (!wsi->tls.err_helper[0])
+                       ERR_error_string_n((unsigned int)m, errbuf + n, (elen - (unsigned int)n));
+               return LWS_SSL_CAPABLE_ERROR;
+       }
+
+#if defined(LWS_WITH_TLS_SESSIONS)
+       if (SSL_session_reused(wsi->tls.ssl)) {
+#if defined(LWS_HAVE_SSL_SESSION_set_time)
+               sess = SSL_get_session(wsi->tls.ssl);
+               if (sess) /* should always be true */
+#if defined(OPENSSL_IS_BORINGSSL)
+                       SSL_SESSION_set_time(sess, (uint64_t)time(NULL)); /* extend session lifetime */
+#else
+                       SSL_SESSION_set_time(sess, (long)time(NULL)); /* extend session lifetime */
+#endif
+#endif
+       }
+#endif
+
+       if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl))
+               return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+
+       if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl))
+               return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
+
+       if (n == 1 || m == SSL_ERROR_SYSCALL) {
 #if defined(LWS_HAVE_SSL_set_alpn_protos) && \
     defined(LWS_HAVE_SSL_get0_alpn_selected)
                SSL_get0_alpn_selected(wsi->tls.ssl, &prot, &len);
@@ -309,70 +577,90 @@ lws_tls_client_connect(struct lws *wsi)
 
                lws_role_call_alpn_negotiated(wsi, (const char *)a);
 #endif
+#if defined(LWS_TLS_SYNTHESIZE_CB)
+               lws_sul_schedule(wsi->a.context, wsi->tsi,
+                                &wsi->tls.sul_cb_synth,
+                                lws_sess_cache_synth_cb, 500 * LWS_US_PER_MS);
+#endif
+
                lwsl_info("client connect OK\n");
                lws_openssl_describe_cipher(wsi);
                return LWS_SSL_CAPABLE_DONE;
        }
 
-       m = lws_ssl_get_error(wsi, n);
-
-       if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL)
-               return LWS_SSL_CAPABLE_ERROR;
-
-       if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl))
-               return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
-
-       if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl))
-               return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
-
        if (!n) /* we don't know what he wants, but he says to retry */
                return LWS_SSL_CAPABLE_MORE_SERVICE;
 
+       lws_snprintf(errbuf, elen, "connect unk %d", m);
+
        return LWS_SSL_CAPABLE_ERROR;
 }
 
 int
-lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len)
+lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, size_t ebuf_len)
 {
 #if !defined(USE_WOLFSSL)
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        char *p = (char *)&pt->serv_buf[0];
+       const char *es, *type = "";
+       unsigned int avoid = 0;
        char *sb = p;
-       int n;
+       long n;
 
-       lws_latency_pre(wsi->context, wsi);
        errno = 0;
        ERR_clear_error();
        n = SSL_get_verify_result(wsi->tls.ssl);
-       lws_latency(wsi->context, wsi,
-               "SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0);
 
-       lwsl_debug("get_verify says %d\n", n);
-
-       if (n == X509_V_OK)
+       switch (n) {
+       case X509_V_OK:
                return 0;
 
-       if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
-            n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
-            (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)) {
-               lwsl_info("accepting self-signed certificate\n");
-
-               return 0;
-       }
-       if ((n == X509_V_ERR_CERT_NOT_YET_VALID ||
-            n == X509_V_ERR_CERT_HAS_EXPIRED) &&
-            (wsi->tls.use_ssl & LCCSCF_ALLOW_EXPIRED)) {
-               lwsl_info("accepting expired certificate\n");
-               return 0;
+       case X509_V_ERR_HOSTNAME_MISMATCH:
+               type = "tls=hostname";
+               avoid = LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
+               break;
+
+       case X509_V_ERR_INVALID_CA:
+       case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+       case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+               type = "tls=invalidca";
+               avoid = LCCSCF_ALLOW_SELFSIGNED;
+               break;
+
+       case X509_V_ERR_CERT_NOT_YET_VALID:
+               type = "tls=notyetvalid";
+               avoid = LCCSCF_ALLOW_EXPIRED;
+               break;
+
+       case X509_V_ERR_CERT_HAS_EXPIRED:
+               type = "tls=expired";
+               avoid = LCCSCF_ALLOW_EXPIRED;
+               break;
        }
-       if (n == X509_V_ERR_CERT_NOT_YET_VALID) {
-               lwsl_info("Cert is from the future... "
-                           "probably our clock... accepting...\n");
+
+       lwsl_info("%s: cert problem: %s\n", __func__, type);
+
+#if defined(LWS_WITH_SYS_METRICS)
+       lws_metrics_hist_bump_describe_wsi(wsi,
+                       lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures), type);
+#endif
+
+       if (wsi->tls.use_ssl & avoid) {
+               lwsl_info("%s: allowing anyway\n", __func__);
+
                return 0;
        }
+
+       es = ERR_error_string(
+       #if defined(LWS_WITH_BORINGSSL)
+                                        (uint32_t)
+       #else
+                                        (unsigned long)
+       #endif
+                                        n, sb);
        lws_snprintf(ebuf, ebuf_len,
-               "server's cert didn't look good, X509_V_ERR = %d: %s\n",
-                n, ERR_error_string(n, sb));
+               "server's cert didn't look good, %s X509_V_ERR = %ld: %s\n",
+                type, n, es);
        lwsl_info("%s\n", ebuf);
        lws_tls_err_describe_clear();
 
@@ -384,6 +672,40 @@ lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len)
 }
 
 int
+lws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh,
+                const uint8_t *der, size_t der_len)
+{
+       X509_STORE *st;
+#if defined(USE_WOLFSSL)
+       X509 *x  = d2i_X509(NULL, &der, (int)der_len);
+#else
+       X509 *x  = d2i_X509(NULL, &der, (long)der_len);
+#endif
+       int n;
+
+       if (!x) {
+               lwsl_err("%s: Failed to load DER\n", __func__);
+               lws_tls_err_describe_clear();
+               return 1;
+       }
+
+       st = SSL_CTX_get_cert_store(vh->tls.ssl_client_ctx);
+       if (!st) {
+               lwsl_err("%s: failed to get cert store\n", __func__);
+               X509_free(x);
+               return 1;
+       }
+
+       n = X509_STORE_add_cert(st, x);
+       if (n != 1)
+               lwsl_err("%s: failed to add cert\n", __func__);
+
+       X509_free(x);
+
+       return n != 1;
+}
+
+int
 lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                                    const struct lws_context_creation_info *info,
                                    const char *cipher_list,
@@ -393,10 +715,12 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                                    const char *cert_filepath,
                                    const void *cert_mem,
                                    unsigned int cert_mem_len,
-                                   const char *private_key_filepath)
+                                   const char *private_key_filepath,
+                                       const void *key_mem,
+                                   unsigned int key_mem_len
+                                       )
 {
        struct lws_tls_client_reuse *tcr;
-       const unsigned char *ca_mem_ptr;
        X509_STORE *x509_store;
        unsigned long error;
        SSL_METHOD *method;
@@ -419,10 +743,18 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
 #endif
 
        if (!method) {
+               const char *es;
+
                error = ERR_get_error();
+               es = ERR_error_string(
+               #if defined(LWS_WITH_BORINGSSL)
+                       (uint32_t)
+               #else
+                       (unsigned long)
+               #endif
+                        error, (char *)vh->context->pt[0].serv_buf);
                lwsl_err("problem creating ssl method %lu: %s\n",
-                       error, ERR_error_string(error,
-                                     (char *)vh->context->pt[0].serv_buf));
+                       error, es);
                return 1;
        }
 
@@ -503,6 +835,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
 
                        tcr->refcount++;
                        vh->tls.ssl_client_ctx = tcr->ssl_client_ctx;
+                       vh->tls.tcr = tcr;
 
                        lwsl_info("%s: vh %s: reusing client ctx %d: use %d\n",
                                   __func__, vh->name, tcr->index,
@@ -518,13 +851,23 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
        ERR_clear_error();
        vh->tls.ssl_client_ctx = SSL_CTX_new(method);
        if (!vh->tls.ssl_client_ctx) {
+               const char *es;
+
                error = ERR_get_error();
+               es = ERR_error_string(
+               #if defined(LWS_WITH_BORINGSSL)
+                       (uint32_t)
+               #else
+                       (unsigned long)
+               #endif
+                        error, (char *)vh->context->pt[0].serv_buf);
                lwsl_err("problem creating ssl context %lu: %s\n",
-                       error, ERR_error_string(error,
-                                     (char *)vh->context->pt[0].serv_buf));
+                       error, es);
                return 1;
        }
 
+       lws_plat_vhost_tls_client_ctx_init(vh);
+
        tcr = lws_zalloc(sizeof(*tcr), "client ctx tcr");
        if (!tcr) {
                SSL_CTX_free(vh->tls.ssl_client_ctx);
@@ -542,9 +885,13 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
 
        /* bind the tcr to the client context */
 
-       SSL_CTX_set_ex_data(vh->tls.ssl_client_ctx,
-                           openssl_SSL_CTX_private_data_index,
-                           (char *)tcr);
+       vh->tls.tcr = tcr;
+
+#if defined(LWS_WITH_TLS_SESSIONS)
+       vh->tls_session_cache_max = info->tls_session_cache_max ?
+                                   info->tls_session_cache_max : 10;
+       lws_tls_session_cache(vh, info->tls_session_timeout);
+#endif
 
 #ifdef SSL_OP_NO_COMPRESSION
        SSL_CTX_set_options(vh->tls.ssl_client_ctx, SSL_OP_NO_COMPRESSION);
@@ -559,12 +906,34 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
 
        if (info->ssl_client_options_set)
                SSL_CTX_set_options(vh->tls.ssl_client_ctx,
+#if !defined(USE_WOLFSSL)
+#if defined(LWS_WITH_BORINGSSL)
+                               (uint32_t)
+#else
+#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \
+       !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */
+                                   (unsigned long)
+#else
+                                   (long)
+#endif
+#endif
+#endif
                                    info->ssl_client_options_set);
 
        /* SSL_clear_options introduced in 0.9.8m */
 #if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
        if (info->ssl_client_options_clear)
                SSL_CTX_clear_options(vh->tls.ssl_client_ctx,
+#if defined(LWS_WITH_BORINGSSL)
+                               (uint32_t)
+#else
+#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \
+       !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */
+                                   (unsigned long)
+#else
+                                   (long)
+#endif
+#endif
                                      info->ssl_client_options_clear);
 #endif
 
@@ -585,15 +954,25 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
 
        /* openssl init for cert verification (for client sockets) */
        if (!ca_filepath && (!ca_mem || !ca_mem_len)) {
+#if defined(LWS_HAVE_SSL_CTX_load_verify_dir)
+               if (!SSL_CTX_load_verify_dir(
+                       vh->tls.ssl_client_ctx, LWS_OPENSSL_CLIENT_CERTS))
+#else
                if (!SSL_CTX_load_verify_locations(
                        vh->tls.ssl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS))
+#endif
                        lwsl_err("Unable to load SSL Client certs from %s "
                            "(set by LWS_OPENSSL_CLIENT_CERTS) -- "
                            "client ssl isn't going to work\n",
                            LWS_OPENSSL_CLIENT_CERTS);
        } else if (ca_filepath) {
+#if defined(LWS_HAVE_SSL_CTX_load_verify_file)
+               if (!SSL_CTX_load_verify_file(
+                       vh->tls.ssl_client_ctx, ca_filepath)) {
+#else
                if (!SSL_CTX_load_verify_locations(
                        vh->tls.ssl_client_ctx, ca_filepath, NULL)) {
+#endif
                        lwsl_err(
                                "Unable to load SSL Client certs "
                                "file from %s -- client ssl isn't "
@@ -603,23 +982,47 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                else
                        lwsl_info("loaded ssl_ca_filepath\n");
        } else {
-               ca_mem_ptr = (const unsigned char*)ca_mem;
-               client_CA = d2i_X509(NULL, &ca_mem_ptr, ca_mem_len);
-               x509_store = X509_STORE_new();
-               if (!client_CA || !X509_STORE_add_cert(x509_store, client_CA)) {
-                       X509_STORE_free(x509_store);
-                       lwsl_err("Unable to load SSL Client certs from "
-                                "ssl_ca_mem -- client ssl isn't going to "
-                                "work\n");
+
+               lws_filepos_t amount = 0;
+               const uint8_t *up;
+               uint8_t *up1;
+
+               if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, ca_mem,
+                                                 ca_mem_len, &up1, &amount)) {
+                       lwsl_err("%s: Unable to decode x.509 mem\n", __func__);
+                       lwsl_hexdump_notice(ca_mem, ca_mem_len);
+                       return 1;
+               }
+
+               up = up1;
+#if defined(USE_WOLFSSL)
+               client_CA = d2i_X509(NULL, &up, (int)amount);
+#else
+               client_CA = d2i_X509(NULL, &up, (long)amount);
+#endif
+               if (!client_CA) {
+                       lwsl_err("%s: d2i_X509 failed\n", __func__);
+                       lwsl_hexdump_notice(up1, (size_t)amount);
                        lws_tls_err_describe_clear();
                } else {
-                       /* it doesn't increment x509_store ref counter */
-                       SSL_CTX_set_cert_store(vh->tls.ssl_client_ctx,
-                                              x509_store);
-                       lwsl_info("loaded ssl_ca_mem\n");
+                       x509_store = X509_STORE_new();
+                       if (!X509_STORE_add_cert(x509_store, client_CA)) {
+                               X509_STORE_free(x509_store);
+                               lwsl_err("Unable to load SSL Client certs from "
+                                        "ssl_ca_mem -- client ssl isn't going to "
+                                        "work\n");
+                               lws_tls_err_describe_clear();
+                       } else {
+                               /* it doesn't increment x509_store ref counter */
+                               SSL_CTX_set_cert_store(vh->tls.ssl_client_ctx,
+                                                      x509_store);
+                               lwsl_info("loaded ssl_ca_mem\n");
+                       }
                }
                if (client_CA)
                        X509_free(client_CA);
+               lws_free(up1);
+       //      lws_tls_client_vhost_extra_cert_mem(vh, ca_mem, ca_mem_len);
        }
 
        /*
@@ -628,6 +1031,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
         */
 
        /* support for client-side certificate authentication */
+
        if (cert_filepath) {
                if (lws_tls_use_any_upgrade_check_extant(cert_filepath) !=
                                LWS_TLS_EXTANT_YES &&
@@ -644,19 +1048,40 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                        lws_tls_err_describe_clear();
                        return 1;
                }
-               lwsl_notice("Loaded client cert %s\n", cert_filepath);
+               lwsl_info("Loaded client cert %s\n", cert_filepath);
+
        } else if (cert_mem && cert_mem_len) {
+               lws_filepos_t flen;
+               uint8_t *p;
+
+               if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, cert_mem,
+                                                 cert_mem_len, &p, &flen)) {
+                       lwsl_err("%s: couldn't read cert file\n", __func__);
+
+                       return 1;
+               }
+
                n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx,
-                                                cert_mem_len, cert_mem);
+#if defined(LWS_WITH_BORINGSSL)
+                               (size_t)
+#else
+                               (int)
+#endif
+                               flen, p);
+
                if (n < 1) {
-                       lwsl_err("%s: problem interpreting client cert\n",
-                                __func__);
+                       lwsl_err("%s: problem interpreting client cert\n",  __func__);
                        lws_tls_err_describe_clear();
-                       return 1;
                }
+
+               lws_free_set_NULL(p);
+
+               if (n != 1)
+                       return 1;
+
        }
        if (private_key_filepath) {
-               lwsl_notice("%s: doing private key filepath\n", __func__);
+               lwsl_info("%s: using private key filepath\n", __func__);
                lws_ssl_bind_passphrase(vh->tls.ssl_client_ctx, 1, info);
                /* set the private key from KeyFile */
                if (SSL_CTX_use_PrivateKey_file(vh->tls.ssl_client_ctx,
@@ -666,7 +1091,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                        lws_tls_err_describe_clear();
                        return 1;
                }
-               lwsl_notice("Loaded client cert private key %s\n",
+               lwsl_info("Loaded client cert private key %s\n",
                            private_key_filepath);
 
                /* verify private key */
@@ -675,6 +1100,45 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                        return 1;
                }
        }
+       else if (key_mem && key_mem_len) {
+
+               lws_filepos_t flen;
+               uint8_t *p;
+
+               if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, key_mem,
+                                                 key_mem_len, &p, &flen)) {
+                       lwsl_err("%s: couldn't use mem cert\n", __func__);
+
+                       return 1;
+               }
+
+               n = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, vh->tls.ssl_client_ctx, p,
+#if defined(LWS_WITH_BORINGSSL)
+                               (size_t)
+#else
+                               (long)(lws_intptr_t)
+#endif
+                                               flen);
+               if (n != 1)
+                       n = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC,
+                                                       vh->tls.ssl_client_ctx, p,
+#if defined(LWS_WITH_BORINGSSL)
+                               (size_t)
+#else
+                               (long)(lws_intptr_t)
+#endif
+                                               flen);
+
+               lws_free_set_NULL(p);
+
+               if (n != 1)  {
+                       lwsl_err("%s: unable to use key_mem\n", __func__);
+
+                       return 1;
+               }
+       }
 
        return 0;
 }
+
+
index 917c0ea..94e8846 100644 (file)
@@ -1,25 +1,28 @@
 /*
- * libwebsockets - OpenSSL-specific server functions
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /*
  * Care: many openssl apis return 1 for success.  These are translated to the
@@ -56,9 +59,9 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
        else
                lwsl_info("%s: couldn't get client cert CN\n", __func__);
 
-       n = wsi->vhost->protocols[0].callback(wsi,
+       n = wsi->a.vhost->protocols[0].callback(wsi,
                        LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
-                                          x509_ctx, ssl, preverify_ok);
+                                          x509_ctx, ssl, (unsigned int)preverify_ok);
 
        /* convert return code from 0 = OK to 1 = OK */
        return !n;
@@ -152,7 +155,9 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                          const char *mem_cert, size_t mem_cert_len,
                          const char *mem_privkey, size_t mem_privkey_len)
 {
-#if !defined(OPENSSL_NO_EC)
+#if !defined(OPENSSL_NO_EC) && defined(LWS_HAVE_EC_KEY_new_by_curve_name) && \
+    ((OPENSSL_VERSION_NUMBER < 0x30000000l) || \
+     defined(LWS_SUPPRESS_DEPRECATED_API_WARNINGS))
        const char *ecdh_curve = "prime256v1";
 #if !defined(LWS_WITH_BORINGSSL) && defined(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS)
        STACK_OF(X509) *extra_certs = NULL;
@@ -166,11 +171,10 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
        unsigned long error;
        lws_filepos_t flen;
        uint8_t *p;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
        int ret;
-
-       int n = lws_tls_generic_cert_checks(vhost, cert, private_key), m;
-
-       (void)ret;
+#endif
+       int n = (int)lws_tls_generic_cert_checks(vhost, cert, private_key), m;
 
        if (!cert && !private_key)
                n = LWS_TLS_EXTANT_ALTERNATIVE;
@@ -208,10 +212,18 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                /* set the local certificate from CertFile */
                m = SSL_CTX_use_certificate_chain_file(vhost->tls.ssl_ctx, cert);
                if (m != 1) {
+                       const char *s;
                        error = ERR_get_error();
+
+                       s = ERR_error_string(
+#if defined(LWS_WITH_BORINGSSL)
+                               (uint32_t)
+#endif
+                                       error,
+                                      (char *)vhost->context->pt[0].serv_buf);
+
                        lwsl_err("problem getting cert '%s' %lu: %s\n",
-                                cert, error, ERR_error_string(error,
-                                      (char *)vhost->context->pt[0].serv_buf));
+                                cert, error, s);
 
                        return 1;
                }
@@ -220,11 +232,16 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                        /* set the private key from KeyFile */
                        if (SSL_CTX_use_PrivateKey_file(vhost->tls.ssl_ctx, private_key,
                                                        SSL_FILETYPE_PEM) != 1) {
+                               const char *s;
                                error = ERR_get_error();
+                               s = ERR_error_string(
+       #if defined(LWS_WITH_BORINGSSL)
+                                       (uint32_t)
+       #endif
+                                               error,
+                                              (char *)vhost->context->pt[0].serv_buf);
                                lwsl_err("ssl problem getting key '%s' %lu: %s\n",
-                                        private_key, error,
-                                        ERR_error_string(error,
-                                             (char *)vhost->context->pt[0].serv_buf));
+                                        private_key, error, s);
                                return 1;
                        }
                } else {
@@ -250,7 +267,13 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
        }
 
 #if !defined(USE_WOLFSSL)
-       ret = SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx, (int)flen, p);
+       ret = SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx,
+#if defined(LWS_WITH_BORINGSSL)
+                               (size_t)
+#else
+                               (int)
+#endif
+                               flen, p);
 #else
        ret = wolfSSL_CTX_use_certificate_buffer(vhost->tls.ssl_ctx,
                                                 (uint8_t *)p, (int)flen,
@@ -273,11 +296,21 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
 
 #if !defined(USE_WOLFSSL)
        ret = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, vhost->tls.ssl_ctx, p,
-                                         (long)(long long)flen);
+#if defined(LWS_WITH_BORINGSSL)
+                       (size_t)
+#else
+                                         (long)(long long)
+#endif
+                                         flen);
        if (ret != 1) {
                ret = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC,
                                                  vhost->tls.ssl_ctx, p,
-                                                 (long)(long long)flen);
+#if defined(LWS_WITH_BORINGSSL)
+                       (size_t)
+#else
+                                         (long)(long long)
+#endif
+                                                 flen);
        }
 #else
        ret = wolfSSL_CTX_use_PrivateKey_buffer(vhost->tls.ssl_ctx, p, flen,
@@ -335,7 +368,7 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                                                (long)(long long)flen) != 1) {
 #else
                if (wolfSSL_CTX_use_PrivateKey_buffer(vhost->tls.ssl_ctx, p,
-                                           flen, WOLFSSL_FILETYPE_ASN1) != 1) {
+                                           (long)flen, WOLFSSL_FILETYPE_ASN1) != 1) {
 #endif
                        lwsl_notice("unable to use memory privkey\n");
 
@@ -388,7 +421,9 @@ check_key:
        }
 
 
-#if !defined(OPENSSL_NO_EC)
+#if !defined(OPENSSL_NO_EC) && defined(LWS_HAVE_EC_KEY_new_by_curve_name) && \
+    ((OPENSSL_VERSION_NUMBER < 0x30000000l) || \
+     defined(LWS_SUPPRESS_DEPRECATED_API_WARNINGS))
        if (vhost->tls.ecdh_curve[0])
                ecdh_curve = vhost->tls.ecdh_curve;
 
@@ -430,7 +465,8 @@ check_key:
        }
 #else
        return 0;
-#endif
+#endif /* !boringssl */
+
        /* Get the public key from certificate */
        pkey = X509_get_pubkey(x);
        if (!pkey) {
@@ -455,13 +491,14 @@ check_key:
        SSL_CTX_set_tmp_ecdh(vhost->tls.ssl_ctx, EC_key);
 
        EC_KEY_free(EC_key);
-#else
-       lwsl_notice(" OpenSSL doesn't support ECDH\n");
-#endif
+
 #if !defined(OPENSSL_NO_EC) && !defined(LWS_WITH_BORINGSSL)
 post_ecdh:
 #endif
        vhost->tls.skipped_certs = 0;
+#else
+       lwsl_notice(" OpenSSL doesn't support ECDH\n");
+#endif
 
        return 0;
 }
@@ -474,18 +511,32 @@ lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info,
        SSL_METHOD *method = (SSL_METHOD *)SSLv23_server_method();
 
        if (!method) {
+               const char *s;
                error = ERR_get_error();
+               s = ERR_error_string(
+#if defined(LWS_WITH_BORINGSSL)
+                       (uint32_t)
+#endif
+                               error,
+                              (char *)vhost->context->pt[0].serv_buf);
+
                lwsl_err("problem creating ssl method %lu: %s\n",
-                               error, ERR_error_string(error,
-                                     (char *)vhost->context->pt[0].serv_buf));
+                               error, s);
                return 1;
        }
        vhost->tls.ssl_ctx = SSL_CTX_new(method);       /* create context */
        if (!vhost->tls.ssl_ctx) {
+               const char *s;
+
                error = ERR_get_error();
+               s = ERR_error_string(
+#if defined(LWS_WITH_BORINGSSL)
+                       (uint32_t)
+#endif
+                               error,
+                              (char *)vhost->context->pt[0].serv_buf);
                lwsl_err("problem creating ssl context %lu: %s\n",
-                               error, ERR_error_string(error,
-                                     (char *)vhost->context->pt[0].serv_buf));
+                               error, s);
                return 1;
        }
 
@@ -517,19 +568,47 @@ lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info,
 #endif
 
        if (info->ssl_ca_filepath &&
+#if defined(LWS_HAVE_SSL_CTX_load_verify_file)
+           !SSL_CTX_load_verify_file(vhost->tls.ssl_ctx,
+                                     info->ssl_ca_filepath)) {
+#else
            !SSL_CTX_load_verify_locations(vhost->tls.ssl_ctx,
                                           info->ssl_ca_filepath, NULL)) {
+#endif
                lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n",
                         __func__);
        }
 
        if (info->ssl_options_set)
-               SSL_CTX_set_options(vhost->tls.ssl_ctx, info->ssl_options_set);
+               SSL_CTX_set_options(vhost->tls.ssl_ctx,
+#if defined(USE_WOLFSSL)
+                               (long)
+#else
+#if defined(LWS_WITH_BORINGSSL)
+                               (uint32_t)
+#else
+#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */
+                                   (unsigned long)
+#else
+                                   (long)
+#endif
+#endif
+#endif
+                               info->ssl_options_set);
 
 /* SSL_clear_options introduced in 0.9.8m */
 #if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
        if (info->ssl_options_clear)
                SSL_CTX_clear_options(vhost->tls.ssl_ctx,
+#if defined(LWS_WITH_BORINGSSL)
+                               (uint32_t)
+#else
+#if (OPENSSL_VERSION_NUMBER >= 0x10003000l)  && !defined(LIBRESSL_VERSION_NUMBER)/* not documented by openssl */
+                                   (unsigned long)
+#else
+                                   (long)
+#endif
+#endif
                                      info->ssl_options_clear);
 #endif
 
@@ -558,7 +637,7 @@ lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
 
        errno = 0;
        ERR_clear_error();
-       wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_ctx);
+       wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_ctx);
        if (wsi->tls.ssl == NULL) {
                lwsl_err("SSL_new failed: %d (errno %d)\n",
                         lws_ssl_get_error(wsi, 0), errno);
@@ -568,7 +647,7 @@ lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
        }
 
        SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index, wsi);
-       SSL_set_fd(wsi->tls.ssl, (int)(long long)accept_fd);
+       SSL_set_fd(wsi->tls.ssl, (int)(lws_intptr_t)accept_fd);
 
 #ifdef USE_WOLFSSL
 #ifdef USE_OLD_CYASSL
@@ -593,7 +672,7 @@ lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
 #endif
 
 #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
-               if (wsi->vhost->tls.ssl_info_event_mask)
+               if (wsi->a.vhost->tls.ssl_info_event_mask)
                        SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
 #endif
 
@@ -603,7 +682,8 @@ lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
 int
 lws_tls_server_abort_connection(struct lws *wsi)
 {
-       SSL_shutdown(wsi->tls.ssl);
+       if (wsi->tls.use_ssl)
+               SSL_shutdown(wsi->tls.ssl);
        SSL_free(wsi->tls.ssl);
 
        return 0;
@@ -612,7 +692,7 @@ lws_tls_server_abort_connection(struct lws *wsi)
 enum lws_ssl_capable_status
 lws_tls_server_accept(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
        union lws_tls_cert_info_results ir;
        int m, n;
 
@@ -620,6 +700,8 @@ lws_tls_server_accept(struct lws *wsi)
        ERR_clear_error();
        n = SSL_accept(wsi->tls.ssl);
 
+       wsi->skip_fallback = 1;
+
        if (n == 1) {
                n = lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME, &ir,
                                           sizeof(ir.ns.name));
@@ -708,7 +790,7 @@ struct lws_tls_ss_pieces {
        RSA *rsa;
 };
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
                             const char *san_b)
 {
@@ -865,10 +947,11 @@ static int nid_list[] = {
        NID_localityName,               /* LWS_TLS_REQ_ELEMENT_LOCALITY */
        NID_organizationName,           /* LWS_TLS_REQ_ELEMENT_ORGANIZATION */
        NID_commonName,                 /* LWS_TLS_REQ_ELEMENT_COMMON_NAME */
-       NID_organizationalUnitName,     /* LWS_TLS_REQ_ELEMENT_EMAIL */
+       NID_subject_alt_name,           /* LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME */
+       NID_pkcs9_emailAddress,         /* LWS_TLS_REQ_ELEMENT_EMAIL */
 };
 
-LWS_VISIBLE LWS_EXTERN int
+int
 lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
                            uint8_t *csr, size_t csr_len, char **privkey_pem,
                            size_t *privkey_len)
@@ -903,15 +986,45 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
                goto bail2;
 
        for (n = 0; n < LWS_TLS_REQ_ELEMENT_COUNT; n++)
-               if (lws_tls_openssl_add_nid(subj, nid_list[n], elements[n])) {
-                       lwsl_notice("%s: failed to add element %d\n", __func__,
-                                   n);
+               if (elements[n] &&
+                       lws_tls_openssl_add_nid(subj, nid_list[n],
+                               elements[n])) {
+                               lwsl_notice("%s: failed to add element %d\n",
+                                               __func__, n);
                        goto bail3;
                }
 
        if (X509_REQ_set_subject_name(req, subj) != 1)
                goto bail3;
 
+       if (elements[LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME]) {
+               STACK_OF(X509_EXTENSION) *exts;
+               X509_EXTENSION *ext;
+               char san[256];
+
+               exts = sk_X509_EXTENSION_new_null();
+               if (!exts)
+                       goto bail3;
+
+               lws_snprintf(san, sizeof(san), "DNS:%s,DNS:%s",
+                               elements[LWS_TLS_REQ_ELEMENT_COMMON_NAME],
+                               elements[LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME]);
+
+               ext = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name,
+                               san);
+               if (!ext) {
+                       sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+                       goto bail3;
+               }
+               sk_X509_EXTENSION_push(exts, ext);
+
+               if (!X509_REQ_add_extensions(req, exts)) {
+                       sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+                       goto bail3;
+               }
+               sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+       }
+
        if (!X509_REQ_sign(req, pkey, EVP_sha256()))
                goto bail3;
 
@@ -951,7 +1064,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
                        if (*p == '/')
                                *csr++ = '_';
                        else
-                               *csr++ = *p;
+                               *csr++ = (uint8_t)*p;
                p++;
                csr_len--;
        }
@@ -974,7 +1087,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
                goto bail3;
        }
        bio_len = BIO_get_mem_data(bio, &p);
-       *privkey_pem = malloc(bio_len); /* malloc so user code can own / free */
+       *privkey_pem = malloc((unsigned long)bio_len); /* malloc so user code can own / free */
        *privkey_len = (size_t)bio_len;
        if (!*privkey_pem) {
                lwsl_notice("%s: need %ld for private key\n", __func__,
@@ -982,7 +1095,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
                BIO_free(bio);
                goto bail3;
        }
-       memcpy(*privkey_pem, p, (int)(long long)bio_len);
+       memcpy(*privkey_pem, p, (unsigned int)(int)(long long)bio_len);
        BIO_free(bio);
 
        ret = lws_ptr_diff(csr, csr_in);
diff --git a/lib/tls/openssl/openssl-session.c b/lib/tls/openssl/openssl-session.c
new file mode 100644 (file)
index 0000000..d7dd04c
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+typedef struct lws_tls_session_cache_openssl {
+       lws_dll2_t                      list;
+
+       SSL_SESSION                     *session;
+       lws_sorted_usec_list_t          sul_ttl;
+
+       /* name is overallocated here */
+} lws_tls_sco_t;
+
+#define lwsl_tlssess lwsl_info
+
+static void
+__lws_tls_session_destroy(lws_tls_sco_t *ts)
+{
+       lwsl_tlssess("%s: %s (%u)\n", __func__, (const char *)&ts[1],
+                                    ts->list.owner->count - 1);
+
+       lws_sul_cancel(&ts->sul_ttl);
+       SSL_SESSION_free(ts->session);
+       lws_dll2_remove(&ts->list);             /* vh lock */
+
+       lws_free(ts);
+}
+
+static lws_tls_sco_t *
+__lws_tls_session_lookup_by_name(struct lws_vhost *vh, const char *name)
+{
+       lws_start_foreach_dll(struct lws_dll2 *, p,
+                             lws_dll2_get_head(&vh->tls_sessions)) {
+               lws_tls_sco_t *ts = lws_container_of(p, lws_tls_sco_t, list);
+               const char *ts_name = (const char *)&ts[1];
+
+               if (!strcmp(name, ts_name))
+                       return ts;
+
+       } lws_end_foreach_dll(p);
+
+       return NULL;
+}
+
+/*
+ * If possible, reuse an existing, cached session
+ */
+
+void
+lws_tls_reuse_session(struct lws *wsi)
+{
+       char tag[LWS_SESSION_TAG_LEN];
+       lws_tls_sco_t *ts;
+
+       if (!wsi->a.vhost ||
+           wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
+               return;
+
+       lws_context_lock(wsi->a.context, __func__); /* -------------- cx { */
+       lws_vhost_lock(wsi->a.vhost); /* -------------- vh { */
+
+       if (lws_tls_session_tag_from_wsi(wsi, tag, sizeof(tag)))
+               goto bail;
+       ts = __lws_tls_session_lookup_by_name(wsi->a.vhost, tag);
+
+       if (!ts) {
+               lwsl_tlssess("%s: no existing session for %s\n", __func__, tag);
+               goto bail;
+       }
+
+       lwsl_tlssess("%s: %s\n", __func__, (const char *)&ts[1]);
+
+       if (!SSL_set_session(wsi->tls.ssl, ts->session)) {
+               lwsl_err("%s: session not set for %s\n", __func__, tag);
+               goto bail;
+       }
+
+#if !defined(USE_WOLFSSL)
+       /* extend session lifetime */
+       SSL_SESSION_set_time(ts->session,
+#if defined(OPENSSL_IS_BORINGSSL)
+                       (unsigned long)
+#else
+                       (long)
+#endif
+                       time(NULL));
+#endif
+
+       /* keep our session list sorted in lru -> mru order */
+
+       lws_dll2_remove(&ts->list);
+       lws_dll2_add_tail(&ts->list, &wsi->a.vhost->tls_sessions);
+
+bail:
+       lws_vhost_unlock(wsi->a.vhost); /* } vh --------------  */
+       lws_context_unlock(wsi->a.context); /* } cx --------------  */
+}
+
+int
+lws_tls_session_is_reused(struct lws *wsi)
+{
+#if defined(LWS_WITH_CLIENT)
+       struct lws *nwsi = lws_get_network_wsi(wsi);
+
+       if (!nwsi || !nwsi->tls.ssl)
+               return 0;
+
+       return (int)SSL_session_reused(nwsi->tls.ssl);
+#else
+       return 0;
+#endif
+}
+
+static int
+lws_tls_session_destroy_dll(struct lws_dll2 *d, void *user)
+{
+       lws_tls_sco_t *ts = lws_container_of(d, lws_tls_sco_t, list);
+
+       __lws_tls_session_destroy(ts);
+
+       return 0;
+}
+
+void
+lws_tls_session_vh_destroy(struct lws_vhost *vh)
+{
+       lws_dll2_foreach_safe(&vh->tls_sessions, NULL,
+                             lws_tls_session_destroy_dll);
+}
+
+static void
+lws_tls_session_expiry_cb(lws_sorted_usec_list_t *sul)
+{
+       lws_tls_sco_t *ts = lws_container_of(sul, lws_tls_sco_t, sul_ttl);
+       struct lws_vhost *vh = lws_container_of(ts->list.owner,
+                                               struct lws_vhost, tls_sessions);
+
+       lws_context_lock(vh->context, __func__); /* -------------- cx { */
+       lws_vhost_lock(vh); /* -------------- vh { */
+       __lws_tls_session_destroy(ts);
+       lws_vhost_unlock(vh); /* } vh --------------  */
+       lws_context_unlock(vh->context); /* } cx --------------  */
+}
+
+static lws_tls_sco_t *
+lws_tls_session_add_entry(struct lws_vhost *vh, const char *tag)
+{
+       lws_tls_sco_t *ts;
+       size_t nl = strlen(tag);
+
+       if (vh->tls_sessions.count == (vh->tls_session_cache_max ?
+                                     vh->tls_session_cache_max : 10)) {
+
+               /*
+                * We have reached the vhost's session cache limit,
+                * prune the LRU / head
+                */
+               ts = lws_container_of(vh->tls_sessions.head,
+                                     lws_tls_sco_t, list);
+
+               if (ts) { /* centos 7 ... */
+                       lwsl_tlssess("%s: pruning oldest session\n", __func__);
+
+                       lws_vhost_lock(vh); /* -------------- vh { */
+                       __lws_tls_session_destroy(ts);
+                       lws_vhost_unlock(vh); /* } vh --------------  */
+               }
+       }
+
+       ts = lws_malloc(sizeof(*ts) + nl + 1, __func__);
+
+       if (!ts)
+               return NULL;
+
+       memset(ts, 0, sizeof(*ts));
+       memcpy(&ts[1], tag, nl + 1);
+
+       lws_dll2_add_tail(&ts->list, &vh->tls_sessions);
+
+       return ts;
+}
+
+static int
+lws_tls_session_new_cb(SSL *ssl, SSL_SESSION *sess)
+{
+       struct lws *wsi = (struct lws *)SSL_get_ex_data(ssl,
+                                       openssl_websocket_private_data_index);
+       char tag[LWS_SESSION_TAG_LEN];
+       struct lws_vhost *vh;
+       lws_tls_sco_t *ts;
+       long ttl;
+#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
+       const char *disposition = "reuse";
+#endif
+
+       if (!wsi) {
+               lwsl_warn("%s: can't get wsi from ssl privdata\n", __func__);
+
+               return 0;
+       }
+
+       vh = wsi->a.vhost;
+       if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
+               return 0;
+
+       if (lws_tls_session_tag_from_wsi(wsi, tag, sizeof(tag)))
+               return 0;
+
+       /* api return is long, although we only support setting
+        * default (300s) or max uint32_t */
+       ttl = SSL_SESSION_get_timeout(sess);
+
+       lws_context_lock(vh->context, __func__); /* -------------- cx { */
+       lws_vhost_lock(vh); /* -------------- vh { */
+
+       ts = __lws_tls_session_lookup_by_name(vh, tag);
+
+       if (!ts) {
+               ts = lws_tls_session_add_entry(vh, tag);
+
+               if (!ts)
+                       goto bail;
+
+               lws_sul_schedule(wsi->a.context, wsi->tsi, &ts->sul_ttl,
+                                lws_tls_session_expiry_cb,
+                                ttl * LWS_US_PER_SEC);
+
+#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
+               disposition = "new";
+#endif
+
+               /*
+                * We don't have to do a SSL_SESSION_up_ref() here, because
+                * we will return from this callback indicating that we kept the
+                * ref
+                */
+       } else {
+               /*
+                * Give up our refcount on the session we are about to replace
+                * with a newer one
+                */
+               SSL_SESSION_free(ts->session);
+
+               /* keep our session list sorted in lru -> mru order */
+
+               lws_dll2_remove(&ts->list);
+               lws_dll2_add_tail(&ts->list, &vh->tls_sessions);
+       }
+
+       ts->session = sess;
+
+       lws_vhost_unlock(vh); /* } vh --------------  */
+       lws_context_unlock(vh->context); /* } cx --------------  */
+
+       lwsl_tlssess("%s: %p: %s: %s %s, ttl %lds (%s:%u)\n", __func__,
+                    sess, wsi->lc.gutag, disposition, tag, ttl, vh->name,
+                    vh->tls_sessions.count);
+
+       /*
+        * indicate we will hold on to the SSL_SESSION reference, and take
+        * responsibility to call SSL_SESSION_free() on it ourselves
+        */
+
+       return 1;
+
+bail:
+       lws_vhost_unlock(vh); /* } vh --------------  */
+       lws_context_unlock(vh->context); /* } cx --------------  */
+
+       return 0;
+}
+
+#if defined(LWS_TLS_SYNTHESIZE_CB)
+
+/*
+ * On openssl, there is an async cb coming when the server issues the session
+ * information on the link, so we can pick it up and update the cache at the
+ * right time.
+ *
+ * On mbedtls and some version at least of borning ssl, this cb is either not
+ * part of the tls library apis or fails to arrive.
+ *
+ * This synthetic cb is called instead for those build cases, scheduled for
+ * +500ms after the tls negotiation completed.
+ */
+
+void
+lws_sess_cache_synth_cb(lws_sorted_usec_list_t *sul)
+{
+       struct lws_lws_tls *tls = lws_container_of(sul, struct lws_lws_tls,
+                                                  sul_cb_synth);
+       struct lws *wsi = lws_container_of(tls, struct lws, tls);
+       SSL_SESSION *sess;
+
+       if (lws_tls_session_is_reused(wsi))
+               return;
+
+       sess = SSL_get1_session(tls->ssl);
+       if (!sess)
+               return;
+
+       if (!SSL_SESSION_is_resumable(sess) || /* not worth caching, or... */
+           !lws_tls_session_new_cb(tls->ssl, sess)) { /* ...cb didn't keep it */
+               /*
+                * For now the policy if no session message after the wait,
+                * is just let it be.  Typically the session info is sent
+                * early.
+                */
+               SSL_SESSION_free(sess);
+       }
+}
+#endif
+
+void
+lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl)
+{
+       long cmode;
+
+       if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
+               return;
+
+       cmode = SSL_CTX_get_session_cache_mode(vh->tls.ssl_client_ctx);
+
+       SSL_CTX_set_session_cache_mode(vh->tls.ssl_client_ctx,
+                                      (int)(cmode | SSL_SESS_CACHE_CLIENT));
+
+       SSL_CTX_sess_set_new_cb(vh->tls.ssl_client_ctx, lws_tls_session_new_cb);
+
+       if (!ttl)
+               return;
+
+#if defined(OPENSSL_IS_BORINGSSL)
+       SSL_CTX_set_timeout(vh->tls.ssl_client_ctx, ttl);
+#else
+       SSL_CTX_set_timeout(vh->tls.ssl_client_ctx, (long)ttl);
+#endif
+}
+
+int
+lws_tls_session_dump_save(struct lws_vhost *vh, const char *host, uint16_t port,
+                         lws_tls_sess_cb_t cb_save, void *opq)
+{
+       struct lws_tls_session_dump d;
+       lws_tls_sco_t *ts;
+       int ret = 1, bl;
+       void *v;
+
+       if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
+               return 1;
+
+       lws_tls_session_tag_discrete(vh->name, host, port, d.tag, sizeof(d.tag));
+
+       lws_context_lock(vh->context, __func__); /* -------------- cx { */
+       lws_vhost_lock(vh); /* -------------- vh { */
+
+       ts = __lws_tls_session_lookup_by_name(vh, d.tag);
+       if (!ts)
+               goto bail;
+
+       /* We have a ref on the session, exit via bail to clean it... */
+
+       bl = i2d_SSL_SESSION(ts->session, NULL);
+       if (!bl)
+               goto bail;
+
+       d.blob_len = (size_t)bl;
+       v = d.blob = lws_malloc(d.blob_len, __func__);
+
+       if (d.blob) {
+
+               /* this advances d.blob by the blob size ;-) */
+               i2d_SSL_SESSION(ts->session, (uint8_t **)&d.blob);
+
+               d.opaque = opq;
+               d.blob = v;
+               if (cb_save(vh->context, &d))
+                       lwsl_notice("%s: save failed\n", __func__);
+               else
+                       ret = 0;
+
+               lws_free(v);
+       }
+
+bail:
+       lws_vhost_unlock(vh); /* } vh --------------  */
+       lws_context_unlock(vh->context); /* } cx --------------  */
+
+       return ret;
+}
+
+int
+lws_tls_session_dump_load(struct lws_vhost *vh, const char *host, uint16_t port,
+                         lws_tls_sess_cb_t cb_load, void *opq)
+{
+       struct lws_tls_session_dump d;
+       lws_tls_sco_t *ts;
+       SSL_SESSION *sess = NULL; /* allow it to "bail" early */
+       void *v;
+
+       if (vh->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)
+               return 1;
+
+       d.opaque = opq;
+       lws_tls_session_tag_discrete(vh->name, host, port, d.tag, sizeof(d.tag));
+
+       lws_context_lock(vh->context, __func__); /* -------------- cx { */
+       lws_vhost_lock(vh); /* -------------- vh { */
+
+       ts = __lws_tls_session_lookup_by_name(vh, d.tag);
+
+       if (ts) {
+               /*
+                * Since we are getting this out of cold storage, we should
+                * not replace any existing session since it is likely newer
+                */
+               lwsl_notice("%s: session already exists for %s\n", __func__,
+                               d.tag);
+               goto bail1;
+       }
+
+       if (cb_load(vh->context, &d)) {
+               lwsl_warn("%s: load failed\n", __func__);
+
+               goto bail1;
+       }
+
+       /* the callback has allocated the blob and set d.blob / d.blob_len */
+
+       v = d.blob;
+       /* this advances d.blob by the blob size ;-) */
+       sess = d2i_SSL_SESSION(NULL, (const uint8_t **)&d.blob,
+                                                       (long)d.blob_len);
+       free(v); /* user code will have used malloc() */
+       if (!sess) {
+               lwsl_warn("%s: d2i_SSL_SESSION failed\n", __func__);
+               goto bail;
+       }
+
+       lws_vhost_lock(vh); /* -------------- vh { */
+       ts = lws_tls_session_add_entry(vh, d.tag);
+       lws_vhost_unlock(vh); /* } vh --------------  */
+
+       if (!ts) {
+               lwsl_warn("%s: unable to add cache entry\n", __func__);
+               goto bail;
+       }
+
+       ts->session = sess;
+       lwsl_tlssess("%s: session loaded OK\n", __func__);
+
+       lws_vhost_unlock(vh); /* } vh --------------  */
+       lws_context_unlock(vh->context); /* } cx --------------  */
+
+       return 0;
+
+bail:
+       SSL_SESSION_free(sess);
+bail1:
+
+       lws_vhost_unlock(vh); /* } vh --------------  */
+       lws_context_unlock(vh->context); /* } cx --------------  */
+
+       return 1;
+}
similarity index 63%
rename from lib/tls/openssl/ssl.c
rename to lib/tls/openssl/openssl-ssl.c
index ad2a76e..cf4d2b8 100644 (file)
@@ -1,27 +1,29 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-#include "tls/openssl/private.h"
-#include <errno.h>
+#include "private-lib-core.h"
+#include "private-lib-tls-openssl.h"
 
 int openssl_websocket_private_data_index,
           openssl_SSL_CTX_private_data_index;
@@ -33,12 +35,12 @@ int openssl_websocket_private_data_index,
 
 int lws_openssl_describe_cipher(struct lws *wsi)
 {
-#if !defined(LWS_WITH_NO_LOGS)
+#if !defined(LWS_WITH_NO_LOGS) && !defined(USE_WOLFSSL)
        int np = -1;
        SSL *s = wsi->tls.ssl;
 
        SSL_get_cipher_bits(s, &np);
-       lwsl_info("%s: wsi %p: %s, %s, %d bits, %s\n", __func__, wsi,
+       lwsl_info("%s: %s: %s, %s, %d bits, %s\n", __func__, lws_wsi_tag(wsi),
                        SSL_get_cipher_name(s), SSL_get_cipher(s), np,
                        SSL_get_cipher_version(s));
 #endif
@@ -54,12 +56,16 @@ int lws_ssl_get_error(struct lws *wsi, int n)
                return 99;
 
        m = SSL_get_error(wsi->tls.ssl, n);
-       lwsl_debug("%s: %p %d -> %d (errno %d)\n", __func__, wsi->tls.ssl, n, m,
-                  errno);
+       lwsl_debug("%s: %p %d -> %d (errno %d)\n", __func__, wsi->tls.ssl, n, m, LWS_ERRNO);
+       if (m == SSL_ERROR_SSL)
+               lws_tls_err_describe_clear();
+
+       // assert (LWS_ERRNO != 9);
 
        return m;
 }
 
+#if defined(LWS_WITH_SERVER)
 static int
 lws_context_init_ssl_pem_passwd_cb(char *buf, int size, int rwflag,
                                   void *userdata)
@@ -67,12 +73,14 @@ lws_context_init_ssl_pem_passwd_cb(char *buf, int size, int rwflag,
        struct lws_context_creation_info * info =
                        (struct lws_context_creation_info *)userdata;
 
-       strncpy(buf, info->ssl_private_key_password, size);
+       strncpy(buf, info->ssl_private_key_password, (unsigned int)size);
        buf[size - 1] = '\0';
 
        return (int)strlen(buf);
 }
+#endif
 
+#if defined(LWS_WITH_CLIENT)
 static int
 lws_context_init_ssl_pem_passwd_client_cb(char *buf, int size, int rwflag,
                                          void *userdata)
@@ -84,18 +92,28 @@ lws_context_init_ssl_pem_passwd_client_cb(char *buf, int size, int rwflag,
        if (info->client_ssl_private_key_password)
                p = info->client_ssl_private_key_password;
 
-       strncpy(buf, p, size);
+       strncpy(buf, p, (unsigned int)size);
        buf[size - 1] = '\0';
 
        return (int)strlen(buf);
 }
+#endif
 
 void
 lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, int is_client,
                        const struct lws_context_creation_info *info)
 {
-       if (!info->ssl_private_key_password &&
-           !info->client_ssl_private_key_password)
+       if (
+#if defined(LWS_WITH_SERVER)
+               !info->ssl_private_key_password
+#endif
+#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_CLIENT)
+                       &&
+#endif
+#if defined(LWS_WITH_CLIENT)
+           !info->client_ssl_private_key_password
+#endif
+           )
                return;
        /*
         * password provided, set ssl callback and user data
@@ -104,22 +122,27 @@ lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, int is_client,
         */
        SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info);
        SSL_CTX_set_default_passwd_cb(ssl_ctx, is_client ?
+#if defined(LWS_WITH_CLIENT)
                                      lws_context_init_ssl_pem_passwd_client_cb:
-                                     lws_context_init_ssl_pem_passwd_cb);
+#else
+                                       NULL:
+#endif
+#if defined(LWS_WITH_SERVER)
+                                     lws_context_init_ssl_pem_passwd_cb
+#else
+                                       NULL
+#endif
+                                 );
 }
 
+#if defined(LWS_WITH_CLIENT)
 static void
 lws_ssl_destroy_client_ctx(struct lws_vhost *vhost)
 {
-       struct lws_tls_client_reuse *tcr;
-
        if (vhost->tls.user_supplied_ssl_ctx || !vhost->tls.ssl_client_ctx)
                return;
 
-       tcr = SSL_CTX_get_ex_data(vhost->tls.ssl_client_ctx,
-                                 openssl_SSL_CTX_private_data_index);
-
-       if (!tcr || --tcr->refcount)
+       if (vhost->tls.tcr && --vhost->tls.tcr->refcount)
                return;
 
        SSL_CTX_free(vhost->tls.ssl_client_ctx);
@@ -127,11 +150,14 @@ lws_ssl_destroy_client_ctx(struct lws_vhost *vhost)
 
        vhost->context->tls.count_client_contexts--;
 
-       lws_dll2_remove(&tcr->cc_list);
-       lws_free(tcr);
+       if (vhost->tls.tcr) {
+               lws_dll2_remove(&vhost->tls.tcr->cc_list);
+               lws_free(vhost->tls.tcr);
+               vhost->tls.tcr = NULL;
+       }
 }
-
-LWS_VISIBLE void
+#endif
+void
 lws_ssl_destroy(struct lws_vhost *vhost)
 {
        if (!lws_check_opt(vhost->context->options,
@@ -140,8 +166,9 @@ lws_ssl_destroy(struct lws_vhost *vhost)
 
        if (vhost->tls.ssl_ctx)
                SSL_CTX_free(vhost->tls.ssl_ctx);
-
+#if defined(LWS_WITH_CLIENT)
        lws_ssl_destroy_client_ctx(vhost);
+#endif
 
 // after 1.1.0 no need
 #if (OPENSSL_VERSION_NUMBER <  0x10100000)
@@ -168,39 +195,31 @@ lws_ssl_destroy(struct lws_vhost *vhost)
 #endif
 }
 
-LWS_VISIBLE int
-lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
+int
+lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, size_t len)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        int n = 0, m;
 
        if (!wsi->tls.ssl)
                return lws_ssl_capable_read_no_ssl(wsi, buf, len);
 
-       lws_stats_bump(pt, LWSSTATS_C_API_READ, 1);
-
+#ifndef WIN32
        errno = 0;
+#else
+  WSASetLastError(0);
+#endif
        ERR_clear_error();
-       n = SSL_read(wsi->tls.ssl, buf, len);
-#if defined(LWS_WITH_ESP32)
+       n = SSL_read(wsi->tls.ssl, buf, (int)(ssize_t)len);
+#if defined(LWS_PLAT_FREERTOS)
        if (!n && errno == LWS_ENOTCONN) {
-               lwsl_debug("%p: SSL_read ENOTCONN\n", wsi);
+               lwsl_debug("%s: SSL_read ENOTCONN\n", lws_wsi_tag(wsi));
                return LWS_SSL_CAPABLE_ERROR;
        }
 #endif
-#if defined(LWS_WITH_STATS)
-       if (!wsi->seen_rx && wsi->accept_start_us) {
-                lws_stats_bump(pt, LWSSTATS_US_SSL_RX_DELAY_AVG,
-                                     lws_now_usecs() -
-                                             wsi->accept_start_us);
-                lws_stats_bump(pt, LWSSTATS_C_SSL_CONNS_HAD_RX, 1);
-               wsi->seen_rx = 1;
-       }
-#endif
-
 
-       lwsl_debug("%p: SSL_read says %d\n", wsi, n);
+       lwsl_debug("%s: SSL_read says %d\n", lws_wsi_tag(wsi), n);
        /* manpage: returning 0 means connection shut down
         *
         * 2018-09-10: https://github.com/openssl/openssl/issues/1903
@@ -227,19 +246,24 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
         */
        if (n <= 0) {
                m = lws_ssl_get_error(wsi, n);
-               lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno);
+               lwsl_debug("%s: ssl err %d errno %d\n", lws_wsi_tag(wsi), m, LWS_ERRNO);
                if (m == SSL_ERROR_ZERO_RETURN) /* cleanly shut down */
-                       return LWS_SSL_CAPABLE_ERROR;
+                       goto do_err;
 
                /* hm not retryable.. could be 0 size pkt or error  */
 
                if (m == SSL_ERROR_SSL || m == SSL_ERROR_SYSCALL ||
-                   errno == LWS_ENOTCONN) {
+        LWS_ERRNO == LWS_ENOTCONN) {
 
                        /* unclean, eg closed conn */
 
                        wsi->socket_is_permanently_unusable = 1;
-
+do_err:
+#if defined(LWS_WITH_SYS_METRICS)
+               if (wsi->a.vhost)
+                       lws_metric_event(wsi->a.vhost->mt_traffic_rx,
+                                        METRES_NOGO, 0);
+#endif
                        return LWS_SSL_CAPABLE_ERROR;
                }
 
@@ -247,24 +271,33 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
 
                if (SSL_want_read(wsi->tls.ssl)) {
                        lwsl_debug("%s: WANT_READ\n", __func__);
-                       lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
+                       lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi));
                        return LWS_SSL_CAPABLE_MORE_SERVICE;
                }
                if (SSL_want_write(wsi->tls.ssl)) {
-                       lwsl_debug("%s: WANT_WRITE\n", __func__);
-                       lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
+                       lwsl_info("%s: WANT_WRITE\n", __func__);
+                       lwsl_debug("%s: LWS_SSL_CAPABLE_MORE_SERVICE\n", lws_wsi_tag(wsi));
+                       wsi->tls_read_wanted_write = 1;
+                       lws_callback_on_writable(wsi);
                        return LWS_SSL_CAPABLE_MORE_SERVICE;
                }
 
                /* keep on trucking it seems */
        }
 
-       lws_stats_bump(pt, LWSSTATS_B_READ, n);
-
-       if (wsi->vhost)
-               wsi->vhost->conn_stats.rx += n;
+#if defined(LWS_TLS_LOG_PLAINTEXT_RX)
+       /*
+        * If using openssl type tls library, this is the earliest point for all
+        * paths to dump what was received as decrypted data from the tls tunnel
+        */
+       lwsl_notice("%s: len %d\n", __func__, n);
+       lwsl_hexdump_notice(buf, (unsigned int)n);
+#endif
 
-       // lwsl_hexdump_err(buf, n);
+#if defined(LWS_WITH_SYS_METRICS)
+       if (wsi->a.vhost)
+               lws_metric_event(wsi->a.vhost->mt_traffic_rx, METRES_GO, (u_mt_t)n);
+#endif
 
        /*
         * if it was our buffer that limited what we read,
@@ -273,15 +306,17 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
         * Because these won't signal at the network layer with POLLIN
         * and if we don't realize, this data will sit there forever
         */
-       if (n != len)
+       if (n != (int)(ssize_t)len)
                goto bail;
        if (!wsi->tls.ssl)
                goto bail;
 
-       if (SSL_pending(wsi->tls.ssl) &&
-           lws_dll2_is_detached(&wsi->tls.dll_pending_tls))
-               lws_dll2_add_head(&wsi->tls.dll_pending_tls,
-                                 &pt->tls.dll_pending_tls_owner);
+       if (SSL_pending(wsi->tls.ssl)) {
+               if (lws_dll2_is_detached(&wsi->tls.dll_pending_tls))
+                       lws_dll2_add_head(&wsi->tls.dll_pending_tls,
+                                         &pt->tls.dll_pending_tls_owner);
+       } else
+               __lws_ssl_remove_wsi_from_buffered_list(wsi);
 
        return n;
 bail:
@@ -290,7 +325,7 @@ bail:
        return n;
 }
 
-LWS_VISIBLE int
+int
 lws_ssl_pending(struct lws *wsi)
 {
        if (!wsi->tls.ssl)
@@ -299,19 +334,36 @@ lws_ssl_pending(struct lws *wsi)
        return SSL_pending(wsi->tls.ssl);
 }
 
-LWS_VISIBLE int
-lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
+int
+lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, size_t len)
 {
        int n, m;
 
+
+#if defined(LWS_TLS_LOG_PLAINTEXT_TX)
+       /*
+        * If using OpenSSL type tls library, this is the last point for all
+        * paths before sending data into the tls tunnel, where you can dump it
+        * and see what is being sent.
+        */
+       lwsl_notice("%s: len %u\n", __func__, (unsigned int)len);
+       lwsl_hexdump_notice(buf, len);
+#endif
+
        if (!wsi->tls.ssl)
                return lws_ssl_capable_write_no_ssl(wsi, buf, len);
 
        errno = 0;
        ERR_clear_error();
-       n = SSL_write(wsi->tls.ssl, buf, len);
-       if (n > 0)
+       n = SSL_write(wsi->tls.ssl, buf, (int)(ssize_t)len);
+       if (n > 0) {
+#if defined(LWS_WITH_SYS_METRICS)
+               if (wsi->a.vhost)
+                       lws_metric_event(wsi->a.vhost->mt_traffic_tx,
+                                        METRES_GO, (u_mt_t)n);
+#endif
                return n;
+       }
 
        m = lws_ssl_get_error(wsi, n);
        if (m != SSL_ERROR_SYSCALL) {
@@ -330,11 +382,17 @@ lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
                }
        }
 
-       lwsl_debug("%s failed: %s\n",__func__, ERR_error_string(m, NULL));
+       lwsl_debug("%s failed: %s\n",__func__, ERR_error_string((unsigned int)m, NULL));
        lws_tls_err_describe_clear();
 
        wsi->socket_is_permanently_unusable = 1;
 
+#if defined(LWS_WITH_SYS_METRICS)
+               if (wsi->a.vhost)
+                       lws_metric_event(wsi->a.vhost->mt_traffic_tx,
+                                        METRES_NOGO, 0);
+#endif
+
        return LWS_SSL_CAPABLE_ERROR;
 }
 
@@ -344,6 +402,7 @@ lws_ssl_info_callback(const SSL *ssl, int where, int ret)
        struct lws *wsi;
        struct lws_context *context;
        struct lws_ssl_info si;
+       int fd;
 
 #ifndef USE_WOLFSSL
        context = (struct lws_context *)SSL_CTX_get_ex_data(
@@ -356,24 +415,29 @@ lws_ssl_info_callback(const SSL *ssl, int where, int ret)
 #endif
        if (!context)
                return;
-       wsi = wsi_from_fd(context, SSL_get_fd(ssl));
+
+       fd = SSL_get_fd(ssl);
+       if (fd < 0 || (fd - lws_plat_socket_offset()) < 0)
+               return;
+
+       wsi = wsi_from_fd(context, fd);
        if (!wsi)
                return;
 
-       if (!(where & wsi->vhost->tls.ssl_info_event_mask))
+       if (!(where & wsi->a.vhost->tls.ssl_info_event_mask))
                return;
 
        si.where = where;
        si.ret = ret;
 
-       if (user_callback_handle_rxflow(wsi->protocol->callback,
+       if (user_callback_handle_rxflow(wsi->a.protocol->callback,
                                        wsi, LWS_CALLBACK_SSL_INFO,
                                        wsi->user_space, &si, 0))
                lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
 }
 
 
-LWS_VISIBLE int
+int
 lws_ssl_close(struct lws *wsi)
 {
        lws_sockfd_type n;
@@ -385,10 +449,19 @@ lws_ssl_close(struct lws *wsi)
        /* kill ssl callbacks, because we will remove the fd from the
         * table linking it to the wsi
         */
-       if (wsi->vhost->tls.ssl_info_event_mask)
+       if (wsi->a.vhost->tls.ssl_info_event_mask)
                SSL_set_info_callback(wsi->tls.ssl, NULL);
 #endif
 
+#if defined(LWS_TLS_SYNTHESIZE_CB)
+       lws_sul_cancel(&wsi->tls.sul_cb_synth);
+       /*
+        * ... check the session in case it did not live long enough to get
+        * the scheduled callback to sample it
+        */
+       lws_sess_cache_synth_cb(&wsi->tls.sul_cb_synth);
+#endif
+
        n = SSL_get_fd(wsi->tls.ssl);
        if (!wsi->socket_is_permanently_unusable)
                SSL_shutdown(wsi->tls.ssl);
@@ -396,19 +469,11 @@ lws_ssl_close(struct lws *wsi)
        SSL_free(wsi->tls.ssl);
        wsi->tls.ssl = NULL;
 
-       if (wsi->context->simultaneous_ssl_restriction &&
-           wsi->context->simultaneous_ssl-- ==
-                           wsi->context->simultaneous_ssl_restriction)
-               /* we made space and can do an accept */
-               lws_gate_accepts(wsi->context, 1);
+       lws_tls_restrict_return(wsi);
 
        // lwsl_notice("%s: ssl restr %d, simul %d\n", __func__,
-       //              wsi->context->simultaneous_ssl_restriction,
-       //              wsi->context->simultaneous_ssl);
-
-#if defined(LWS_WITH_STATS)
-       wsi->context->updated = 1;
-#endif
+       //              wsi->a.context->simultaneous_ssl_restriction,
+       //              wsi->a.context->simultaneous_ssl);
 
        return 1; /* handled */
 }
@@ -419,7 +484,9 @@ lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
        if (vhost->tls.ssl_ctx)
                SSL_CTX_free(vhost->tls.ssl_ctx);
 
+#if defined(LWS_WITH_CLIENT)
        lws_ssl_destroy_client_ctx(vhost);
+#endif
 
 #if defined(LWS_WITH_ACME)
        lws_tls_acme_sni_cert_destroy(vhost);
@@ -467,7 +534,11 @@ __lws_tls_shutdown(struct lws *wsi)
 {
        int n;
 
+#ifndef WIN32
        errno = 0;
+#else
+  WSASetLastError(0);
+#endif
        ERR_clear_error();
        n = SSL_shutdown(wsi->tls.ssl);
        lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd);
diff --git a/lib/tls/openssl/openssl-tls.c b/lib/tls/openssl/openssl-tls.c
new file mode 100644 (file)
index 0000000..577acf3
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+#include "private-lib-tls-openssl.h"
+
+extern int openssl_websocket_private_data_index,
+          openssl_SSL_CTX_private_data_index;
+#if defined(LWS_WITH_NETWORK)
+static char openssl_ex_indexes_acquired;
+#endif
+
+void
+lws_tls_err_describe_clear(void)
+{
+       char buf[160];
+       unsigned long l;
+
+       do {
+               l = ERR_get_error();
+               if (!l)
+                       break;
+
+               ERR_error_string_n(
+#if defined(LWS_WITH_BORINGSSL)
+                               (uint32_t)
+#endif
+                               l, buf, sizeof(buf));
+               lwsl_info("   openssl error: %s\n", buf);
+       } while (l);
+       lwsl_info("\n");
+}
+
+#if LWS_MAX_SMP != 1
+
+static pthread_mutex_t *openssl_mutexes = NULL;
+
+static void
+lws_openssl_lock_callback(int mode, int type, const char *file, int line)
+{
+       (void)file;
+       (void)line;
+
+       if (mode & CRYPTO_LOCK)
+               pthread_mutex_lock(&openssl_mutexes[type]);
+       else
+               pthread_mutex_unlock(&openssl_mutexes[type]);
+}
+
+static unsigned long
+lws_openssl_thread_id(void)
+{
+#ifdef __PTW32_H
+       return (unsigned long)(intptr_t)(pthread_self()).p;
+#else
+       return (unsigned long)pthread_self();
+#endif
+}
+#endif
+
+int
+lws_context_init_ssl_library(struct lws_context *cx,
+                             const struct lws_context_creation_info *info)
+{
+#ifdef USE_WOLFSSL
+#ifdef USE_OLD_CYASSL
+       lwsl_cx_info(cx, " Compiled with CyaSSL support");
+#else
+       lwsl_cx_info(cx, " Compiled with wolfSSL support");
+#endif
+#else
+#if defined(LWS_WITH_BORINGSSL)
+       lwsl_cx_info(cx, " Compiled with BoringSSL support");
+#else
+       lwsl_cx_info(cx, " Compiled with OpenSSL support");
+#endif
+#endif
+       if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
+               lwsl_cx_info(cx, " SSL disabled: no "
+                         "LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT");
+               return 0;
+       }
+
+       /* basic openssl init */
+
+       lwsl_cx_info(cx, "Doing SSL library init");
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+       SSL_library_init();
+       OpenSSL_add_all_algorithms();
+       SSL_load_error_strings();
+#else
+       OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
+#endif
+#if defined(LWS_WITH_NETWORK)
+       if (!openssl_ex_indexes_acquired) {
+               openssl_websocket_private_data_index =
+                       SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL);
+
+               openssl_SSL_CTX_private_data_index =
+                       SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+
+               openssl_ex_indexes_acquired = 1;
+       }
+#endif
+
+#if LWS_MAX_SMP != 1
+       {
+               int n;
+
+               openssl_mutexes = (pthread_mutex_t *)
+                               OPENSSL_malloc((size_t)((unsigned long)CRYPTO_num_locks() *
+                                              (unsigned long)sizeof(openssl_mutexes[0])));
+
+               for (n = 0; n < CRYPTO_num_locks(); n++)
+                       pthread_mutex_init(&openssl_mutexes[n], NULL);
+
+               /*
+                * These "functions" disappeared in later OpenSSL which is
+                * already threadsafe.
+                */
+
+               (void)lws_openssl_thread_id;
+               (void)lws_openssl_lock_callback;
+
+               CRYPTO_set_id_callback(lws_openssl_thread_id);
+               CRYPTO_set_locking_callback(lws_openssl_lock_callback);
+       }
+#endif
+
+       return 0;
+}
+
+void
+lws_context_deinit_ssl_library(struct lws_context *context)
+{
+#if LWS_MAX_SMP != 1
+       int n;
+
+       if (!lws_check_opt(context->options,
+                          LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
+               return;
+
+       CRYPTO_set_locking_callback(NULL);
+
+       if (openssl_mutexes) {
+               for (n = 0; n < CRYPTO_num_locks(); n++)
+                       pthread_mutex_destroy(&openssl_mutexes[n]);
+
+               OPENSSL_free(openssl_mutexes);
+               openssl_mutexes = NULL;
+       }
+#endif
+}
similarity index 68%
rename from lib/tls/openssl/x509.c
rename to lib/tls/openssl/openssl-x509.c
index 64ac64a..dac4aa3 100644 (file)
@@ -1,26 +1,30 @@
 /*
- * libwebsockets - OpenSSL-specific lws apis
+ * libwebsockets - small server side websockets and web server implementation
  *
  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-#include "tls/openssl/private.h"
+#define WIN32_LEAN_AND_MEAN
+#include "private-lib-core.h"
+#include "private-lib-tls-openssl.h"
 
 #if !defined(LWS_PLAT_OPTEE)
 static int
@@ -67,17 +71,33 @@ lws_tls_openssl_asn1time_to_unix(ASN1_TIME *as)
 #endif
 }
 
+#if defined(USE_WOLFSSL)
+#define AUTHORITY_KEYID WOLFSSL_AUTHORITY_KEYID
+#endif
+
 int
 lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type,
                          union lws_tls_cert_info_results *buf, size_t len)
 {
+#ifndef USE_WOLFSSL
+       const unsigned char *dp;
+       ASN1_OCTET_STRING *val;
+       AUTHORITY_KEYID *akid;
+       X509_EXTENSION *ext;
+       int tag, xclass, r = 1;
+       long xlen, loc;
+#endif
        X509_NAME *xn;
 #if !defined(LWS_PLAT_OPTEE)
        char *p;
 #endif
 
+       buf->ns.len = 0;
+
        if (!x509)
                return -1;
+       if (!len)
+               len = sizeof(buf->ns.name);
 
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(X509_get_notBefore)
 #define X509_get_notBefore(x)  X509_getm_notBefore(x)
@@ -132,7 +152,7 @@ lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type,
        case LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY:
        {
 #ifndef USE_WOLFSSL
-               size_t klen = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), NULL);
+               size_t klen = (unsigned int)i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), NULL);
                uint8_t *tmp, *ptmp;
 
                if (!klen || klen > len)
@@ -160,6 +180,167 @@ lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type,
 #endif
                return 0;
        }
+       case LWS_TLS_CERT_INFO_DER_RAW:
+       {
+               int der_len = i2d_X509(x509, NULL);
+               uint8_t *tmp = (uint8_t *)buf->ns.name;
+
+               buf->ns.len = der_len < 0 ? 0 : der_len;
+
+               if (der_len < 0 || (size_t)der_len > len)
+                       return -1;
+
+               der_len = i2d_X509(x509, &tmp);
+               if (der_len < 0)
+                       return -1;
+
+               return 0;
+       }
+
+#ifndef USE_WOLFSSL
+
+       case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID:
+               loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1);
+               if (loc < 0)
+                       return 1;
+
+               ext = X509_get_ext(x509, (int)loc);
+               if (!ext)
+                       return 1;
+#ifndef USE_WOLFSSL
+               akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext);
+#else
+               akid = (AUTHORITY_KEYID *)wolfSSL_X509V3_EXT_d2i(ext);
+#endif
+               if (!akid || !akid->keyid)
+                       return 1;
+               val = akid->keyid;
+               dp = (const unsigned char *)val->data;
+               xlen = val->length;
+
+               buf->ns.len = (int)xlen;
+               if (len < (size_t)buf->ns.len)
+                       return -1;
+
+               memcpy(buf->ns.name, dp, (size_t)buf->ns.len);
+
+               AUTHORITY_KEYID_free(akid);
+               break;
+
+       case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER:
+               loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1);
+               if (loc < 0)
+                       return 1;
+
+               ext = X509_get_ext(x509, (int)loc);
+               if (!ext)
+                       return 1;
+
+#ifndef USE_WOLFSSL
+               akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext);
+#else
+               akid = (AUTHORITY_KEYID *)wolfSSL_X509V3_EXT_d2i(ext);
+#endif
+               if (!akid || !akid->issuer)
+                       return 1;
+
+#if defined(LWS_HAVE_OPENSSL_STACK)
+               {
+                       const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
+                       STACK_OF(CONF_VALUE) *cv;
+                       int j;
+
+                       cv = i2v_GENERAL_NAMES((X509V3_EXT_METHOD*)method, akid->issuer, NULL);
+                       if (!cv)
+                               goto bail_ak;
+
+                       for (j = 0; j < OPENSSL_sk_num((const OPENSSL_STACK *)&cv); j++) {
+                           CONF_VALUE *nval = OPENSSL_sk_value((const OPENSSL_STACK *)&cv, j);
+                           size_t ln = (nval->name ? strlen(nval->name) : 0),
+                                  lv = (nval->value ? strlen(nval->value) : 0),
+                                  l = ln + lv;
+
+                           if (len > l) {
+                                   if (nval->name)
+                                           memcpy(buf->ns.name + buf->ns.len, nval->name, ln);
+                                   if (nval->value)
+                                           memcpy(buf->ns.name + buf->ns.len + ln, nval->value, lv);
+                                   buf->ns.len = (int)((size_t)buf->ns.len + l);
+                                   len -= l;
+                                   buf->ns.name[buf->ns.len] = '\0';
+
+                                   r = 0;
+                           }
+                       }
+               }
+
+bail_ak:
+#endif
+               AUTHORITY_KEYID_free(akid);
+
+               return r;
+
+       case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_SERIAL:
+               loc = X509_get_ext_by_NID(x509, NID_authority_key_identifier, -1);
+               if (loc < 0)
+                       return 1;
+
+               ext = X509_get_ext(x509, (int)loc);
+               if (!ext)
+                       return 1;
+               akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext);
+               if (!akid || !akid->serial)
+                       return 1;
+
+#if 0
+               // need to handle blobs, and ASN1_INTEGER_get_uint64 not
+               // available on older openssl
+               {
+                       uint64_t res;
+                       if (ASN1_INTEGER_get_uint64(&res, akid->serial) != 1)
+                               break;
+                       buf->ns.len = lws_snprintf(buf->ns.name, len, "%llu",
+                                       (unsigned long long)res);
+               }
+#endif
+               break;
+
+       case LWS_TLS_CERT_INFO_SUBJECT_KEY_ID:
+
+               loc = X509_get_ext_by_NID(x509, NID_subject_key_identifier, -1);
+               if (loc < 0)
+                       return 1;
+
+               ext = X509_get_ext(x509, (int)loc);
+               if (!ext)
+                       return 1;
+
+               val = X509_EXTENSION_get_data(ext);
+               if (!val)
+                       return 1;
+
+#if defined(USE_WOLFSSL)
+               return 1;
+#else
+               dp = (const unsigned char *)val->data;
+
+               if (ASN1_get_object(&dp, &xlen,
+                                   &tag, &xclass, val->length) & 0x80)
+                       return -1;
+
+               if (tag != V_ASN1_OCTET_STRING) {
+                       lwsl_notice("not octet string %d\n", (int)tag);
+                       return 1;
+               }
+#endif
+               buf->ns.len = (int)xlen;
+               if (len < (size_t)buf->ns.len)
+                       return -1;
+
+               memcpy(buf->ns.name, dp, (size_t)buf->ns.len);
+               break;
+#endif
+
        default:
                return -1;
        }
@@ -432,7 +613,7 @@ lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509,
        for (; n < count; n++) {
                if (!mpi[n])
                        continue;
-               jwk->e[n].len = BN_num_bytes(mpi[n]);
+               jwk->e[n].len = (unsigned int)BN_num_bytes(mpi[n]);
                jwk->e[n].buf = lws_malloc(jwk->e[n].len, "certkeyimp");
                if (!jwk->e[n].buf) {
                        if (id == NID_X9_62_id_ecPublicKey) {
@@ -471,19 +652,19 @@ static int
 lws_x509_jwk_privkey_pem_pp_cb(char *buf, int size, int rwflag, void *u)
 {
        const char *pp = (const char *)u;
-       int n = strlen(pp);
+       size_t n = strlen(pp);
 
-       if (n > size - 1)
+       if ((int)n > size - 1)
                return -1;
 
        memcpy(buf, pp, n + 1);
 
-       return n;
+       return (int)n;
 }
 
 int
-lws_x509_jwk_privkey_pem(struct lws_jwk *jwk, void *pem, size_t len,
-                        const char *passphrase)
+lws_x509_jwk_privkey_pem(struct lws_context *cx, struct lws_jwk *jwk,
+                        void *pem, size_t len, const char *passphrase)
 {
        BIO* bio = BIO_new(BIO_s_mem());
        BIGNUM *mpi, *dummy[6];
@@ -534,13 +715,13 @@ lws_x509_jwk_privkey_pem(struct lws_jwk *jwk, void *pem, size_t len,
 
                /* TODO.. check public curve / group + point */
 
-               jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len = n;
-               jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf = lws_malloc(n, "ec");
+               jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len = (unsigned int)n;
+               jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf = lws_malloc((unsigned int)n, "ec");
                if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf)
                        goto bail1;
 
                m = BN_bn2binpad(cmpi, jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf,
-                                     jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len);
+                                     (int32_t)jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len);
                if ((unsigned int)m != (unsigned int)BN_num_bytes(cmpi))
                        goto bail1;
 
@@ -559,7 +740,7 @@ lws_x509_jwk_privkey_pem(struct lws_jwk *jwk, void *pem, size_t len,
                        goto bail;
                }
 
-#if defined(LWS_HAVE_RSA_SET0_KEY)
+#if defined(LWS_HAVE_RSA_SET0_KEY) && !defined(USE_WOLFSSL)
                RSA_get0_key(rsapriv, (const BIGNUM **)&dummy[0], /* n */
                                      (const BIGNUM **)&dummy[1], /* e */
                                      (const BIGNUM **)&mpi);     /* d */
@@ -585,10 +766,10 @@ lws_x509_jwk_privkey_pem(struct lws_jwk *jwk, void *pem, size_t len,
                /* then check that n & e match what we got from the cert */
 
                dummy[2] = BN_bin2bn(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].buf,
-                                    jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len,
+                                    (int32_t)jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len,
                                     NULL);
                dummy[3] = BN_bin2bn(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf,
-                                    jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len,
+                                    (int32_t)jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len,
                                     NULL);
 
                m = BN_cmp(dummy[2], dummy[0]) | BN_cmp(dummy[3], dummy[1]);
@@ -603,8 +784,8 @@ lws_x509_jwk_privkey_pem(struct lws_jwk *jwk, void *pem, size_t len,
 
                /* accept d from the PEM privkey into the JWK */
 
-               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].len = n;
-               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf = lws_malloc(n, "privjk");
+               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].len = (unsigned int)n;
+               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf = lws_malloc((unsigned int)n, "privjk");
                if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf)
                        goto bail1;
 
@@ -612,16 +793,16 @@ lws_x509_jwk_privkey_pem(struct lws_jwk *jwk, void *pem, size_t len,
 
                /* accept p and q from the PEM privkey into the JWK */
 
-               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].len = BN_num_bytes(dummy[4]);
-               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf = lws_malloc(n, "privjk");
+               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].len = (unsigned int)BN_num_bytes(dummy[4]);
+               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf = lws_malloc((unsigned int)n, "privjk");
                if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) {
                        lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf);
                        goto bail1;
                }
                BN_bn2bin(dummy[4], jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf);
 
-               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].len = BN_num_bytes(dummy[5]);
-               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf = lws_malloc(n, "privjk");
+               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].len = (unsigned int)BN_num_bytes(dummy[5]);
+               jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf = lws_malloc((unsigned int)n, "privjk");
                if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf) {
                        lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf);
                        lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf);
diff --git a/lib/tls/openssl/private-lib-tls-openssl.h b/lib/tls/openssl/private-lib-tls-openssl.h
new file mode 100644 (file)
index 0000000..004d596
--- /dev/null
@@ -0,0 +1,62 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *  gencrypto openssl-specific helper declarations
+ */
+
+#if !defined(__LWS_PRIVATE_LIB_TLS_OPENSSL_H__)
+#define __LWS_PRIVATE_LIB_TLS_OPENSSL_H__
+
+/*
+ * one of these per different client context
+ * cc_owner is in lws_context.lws_context_tls
+ */
+
+struct lws_tls_client_reuse {
+       lws_tls_ctx *ssl_client_ctx;
+       uint8_t hash[32];
+       struct lws_dll2 cc_list;
+       int refcount;
+       int index;
+};
+
+typedef int (*next_proto_cb)(SSL *, const unsigned char **out,
+                             unsigned char *outlen, const unsigned char *in,
+                             unsigned int inlen, void *arg);
+
+struct lws_x509_cert {
+       X509 *cert; /* X509 is opaque, this has to be a pointer */
+};
+
+int
+lws_gencrypto_openssl_hash_to_NID(enum lws_genhash_types hash_type);
+
+const EVP_MD *
+lws_gencrypto_openssl_hash_to_EVP_MD(enum lws_genhash_types hash_type);
+
+#if !defined(LWS_HAVE_BN_bn2binpad)
+int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen);
+#endif
+
+#endif
+
diff --git a/lib/tls/openssl/private.h b/lib/tls/openssl/private.h
deleted file mode 100644 (file)
index bd0b174..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- *  gencrypto openssl-specific helper declarations
- */
-
-/*
- * one of these per different client context
- * cc_owner is in lws_context.lws_context_tls
- */
-
-struct lws_tls_client_reuse {
-       lws_tls_ctx *ssl_client_ctx;
-       uint8_t hash[32];
-       struct lws_dll2 cc_list;
-       int refcount;
-       int index;
-};
-
-typedef int (*next_proto_cb)(SSL *, const unsigned char **out,
-                             unsigned char *outlen, const unsigned char *in,
-                             unsigned int inlen, void *arg);
-
-struct lws_x509_cert {
-       X509 *cert; /* X509 is opaque, this has to be a pointer */
-};
-
-int
-lws_gencrypto_openssl_hash_to_NID(enum lws_genhash_types hash_type);
-
-const EVP_MD *
-lws_gencrypto_openssl_hash_to_EVP_MD(enum lws_genhash_types hash_type);
-
-#if !defined(LWS_HAVE_BN_bn2binpad)
-int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen);
-#endif
diff --git a/lib/tls/openssl/tls.c b/lib/tls/openssl/tls.c
deleted file mode 100644 (file)
index d14cd83..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "core/private.h"
-#include "tls/openssl/private.h"
-
-extern int openssl_websocket_private_data_index,
-openssl_SSL_CTX_private_data_index;
-
-char* lws_ssl_get_error_string(int status, int ret, char *buf, size_t len) {
-       switch (status) {
-       case SSL_ERROR_NONE:
-               return lws_strncpy(buf, "SSL_ERROR_NONE", len);
-       case SSL_ERROR_ZERO_RETURN:
-               return lws_strncpy(buf, "SSL_ERROR_ZERO_RETURN", len);
-       case SSL_ERROR_WANT_READ:
-               return lws_strncpy(buf, "SSL_ERROR_WANT_READ", len);
-       case SSL_ERROR_WANT_WRITE:
-               return lws_strncpy(buf, "SSL_ERROR_WANT_WRITE", len);
-       case SSL_ERROR_WANT_CONNECT:
-               return lws_strncpy(buf, "SSL_ERROR_WANT_CONNECT", len);
-       case SSL_ERROR_WANT_ACCEPT:
-               return lws_strncpy(buf, "SSL_ERROR_WANT_ACCEPT", len);
-       case SSL_ERROR_WANT_X509_LOOKUP:
-               return lws_strncpy(buf, "SSL_ERROR_WANT_X509_LOOKUP", len);
-       case SSL_ERROR_SYSCALL:
-               switch (ret) {
-                case 0:
-                        lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: EOF");
-                        return buf;
-                case -1:
-#ifndef LWS_PLAT_OPTEE
-                       lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %s",
-                                    strerror(errno));
-#else
-                       lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %d", errno);
-#endif
-                       return buf;
-                default:
-                        return strncpy(buf, "SSL_ERROR_SYSCALL", len);
-       }
-       case SSL_ERROR_SSL:
-               return "SSL_ERROR_SSL";
-       default:
-               return "SSL_ERROR_UNKNOWN";
-       }
-}
-
-void
-lws_tls_err_describe_clear(void)
-{
-       char buf[160];
-       unsigned long l;
-
-       do {
-               l = ERR_get_error();
-               if (!l)
-                       break;
-
-               ERR_error_string_n(l, buf, sizeof(buf));
-               lwsl_info("   openssl error: %s\n", buf);
-       } while (l);
-       lwsl_info("\n");
-}
-
-#if LWS_MAX_SMP != 1
-
-static pthread_mutex_t *openssl_mutexes;
-
-static void
-lws_openssl_lock_callback(int mode, int type, const char *file, int line)
-{
-       (void)file;
-       (void)line;
-
-       if (mode & CRYPTO_LOCK)
-               pthread_mutex_lock(&openssl_mutexes[type]);
-       else
-               pthread_mutex_unlock(&openssl_mutexes[type]);
-}
-
-static unsigned long
-lws_openssl_thread_id(void)
-{
-       return (unsigned long)pthread_self();
-}
-#endif
-
-
-int
-lws_context_init_ssl_library(const struct lws_context_creation_info *info)
-{
-#ifdef USE_WOLFSSL
-#ifdef USE_OLD_CYASSL
-       lwsl_info(" Compiled with CyaSSL support\n");
-#else
-       lwsl_info(" Compiled with wolfSSL support\n");
-#endif
-#else
-#if defined(LWS_WITH_BORINGSSL)
-       lwsl_info(" Compiled with BoringSSL support\n");
-#else
-       lwsl_info(" Compiled with OpenSSL support\n");
-#endif
-#endif
-       if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
-               lwsl_info(" SSL disabled: no "
-                         "LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
-               return 0;
-       }
-
-       /* basic openssl init */
-
-       lwsl_info("Doing SSL library init\n");
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-       SSL_library_init();
-       OpenSSL_add_all_algorithms();
-       SSL_load_error_strings();
-#else
-       OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
-#endif
-#if defined(LWS_WITH_NETWORK)
-       openssl_websocket_private_data_index =
-               SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL);
-
-       openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0,
-                       NULL, NULL, NULL, NULL);
-#endif
-
-#if LWS_MAX_SMP != 1
-       {
-               int n;
-
-               openssl_mutexes = (pthread_mutex_t *)
-                               OPENSSL_malloc(CRYPTO_num_locks() *
-                                              sizeof(openssl_mutexes[0]));
-
-               for (n = 0; n < CRYPTO_num_locks(); n++)
-                       pthread_mutex_init(&openssl_mutexes[n], NULL);
-
-               /*
-                * These "functions" disappeared in later OpenSSL which is
-                * already threadsafe.
-                */
-
-               (void)lws_openssl_thread_id;
-               (void)lws_openssl_lock_callback;
-
-               CRYPTO_set_id_callback(lws_openssl_thread_id);
-               CRYPTO_set_locking_callback(lws_openssl_lock_callback);
-       }
-#endif
-
-       return 0;
-}
-
-void
-lws_context_deinit_ssl_library(struct lws_context *context)
-{
-#if LWS_MAX_SMP != 1
-       int n;
-
-       if (!lws_check_opt(context->options,
-                          LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
-               return;
-
-       CRYPTO_set_locking_callback(NULL);
-
-       for (n = 0; n < CRYPTO_num_locks(); n++)
-               pthread_mutex_destroy(&openssl_mutexes[n]);
-
-       OPENSSL_free(openssl_mutexes);
-#endif
-}
diff --git a/lib/tls/private-jit-trust.h b/lib/tls/private-jit-trust.h
new file mode 100644 (file)
index 0000000..521c3a2
--- /dev/null
@@ -0,0 +1,149 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ *  This is included from private-lib-core.h if LWS_WITH_TLS
+ *
+ * First-party trusted certs are handled outside of JIT Trust, eg, in SS policy.
+ * JIT Trust is used to validate arbitrary connections on demand, without
+ * needing a complete set of CAs in memory.
+ *
+ * Instantiated CA X509s are bound to dedicated SSL_CTX in their own dynamic
+ * vhosts for client connections to use, these are lazily culled when they have
+ * no remaining active connections using them.
+ *
+ *   - check jit trust cache to see if hostname has vhost already
+ *      - if so, use it
+ *      - if not, check jit trust cache to see if we know the trusted kids list,
+ *   - attempt connection
+ *   - remote or local trust blob / store
+ */
+
+#if !defined(__LWS_TLS_PRIVATE_JIT_TRUST_H__)
+#define __LWS_TLS_PRIVATE_JIT_TRUST_H__
+
+/*
+ * Refer to ./READMEs/README.jit-trust.md for blob layout specification
+ */
+
+#define LWS_JIT_TRUST_MAGIC_BE         0x54424c42
+
+enum {
+       LJT_OFS_32_COUNT_CERTS          = 6,
+       LJT_OFS_32_DERLEN               = 0x0c,
+       LJT_OFS_32_SKIDLEN              = 0x10,
+       LJT_OFS_32_SKID                 = 0x14,
+       LJT_OFS_END                     = 0x18,
+
+       LJT_OFS_DER                     = 0x1c,
+};
+
+typedef struct {
+       uint8_t                         kid[20];
+       uint8_t                         kid_len;
+} lws_tls_kid_t;
+
+typedef struct {
+       lws_tls_kid_t                   akid[4];
+       lws_tls_kid_t                   skid[4];
+       uint8_t                         count;
+} lws_tls_kid_chain_t;
+
+/*
+ * This is used to manage ongoing jit trust lookups for a specific host.  It
+ * collects results and any trusted DER certs until all of them have arrived,
+ * then caches the hostname -> trusted SKIDs mapping, and creates a vhost +
+ * SSL_CTX trusting the certs named after the trusted SKIDs.
+ *
+ * The cert copies and this inflight object are then freed.
+ *
+ * JIT Trust lookups may be async, there may be multiple lookups fired at one
+ * time, and these mappings are not actually related to a wsi lifetime, so these
+ * separate inflight tracking objects are needed.
+ *
+ * These objects only live until all the AKID lookups for the host that created
+ * them complete.
+ */
+
+typedef struct {
+       lws_dll2_t                      list;
+
+       lws_tls_kid_t                   kid[2]; /* SKID of the der if any */
+       uint8_t                         *der[2]; /* temp allocated */
+
+       int                             ders;
+
+       uint32_t                        tag; /* xor'd from start of SKIDs that
+                                             * that contributed certs, so we
+                                             * can name the vhost in a way that
+                                             * can be regenerated no matter
+                                             * the order of SKID results
+                                             */
+
+       short                           der_len[2];
+
+       char                            refcount; /* expected results left */
+
+       /* hostname overcommitted */
+} lws_tls_jit_inflight_t;
+
+/*
+ * These are the items in the jit trust cache, the cache tag is the hostname
+ * and it resolves to one of these if present.  It describes 1 - 3 SKIDs
+ * of trusted CAs needed to validate that host, and a 32-bit tag that is
+ * the first 4 bytes of each valid SKID xor'd together, so you can find any
+ * existing vhost that already has the required trust (independent of the
+ * order they are checked in due to commutative xor).
+ */
+
+typedef struct {
+       lws_tls_kid_t                   skids[3];
+       int                             count_skids;
+       uint32_t                        xor_tag;
+} lws_tls_jit_cache_item_t;
+
+union lws_tls_cert_info_results;
+
+void
+lws_tls_kid_copy(union lws_tls_cert_info_results *ci, lws_tls_kid_t *kid);
+
+int
+lws_tls_kid_cmp(const lws_tls_kid_t *a, const lws_tls_kid_t *b);
+
+int
+lws_tls_jit_trust_sort_kids(struct lws *wsi, lws_tls_kid_chain_t *ch);
+
+void
+lws_tls_jit_trust_inflight_destroy(lws_tls_jit_inflight_t *inf);
+
+void
+lws_tls_jit_trust_inflight_destroy_all(struct lws_context *cx);
+
+int
+lws_tls_jit_trust_vhost_bind(struct lws_context *cx, const char *address,
+                            struct lws_vhost **pvh);
+
+void
+lws_tls_jit_trust_vh_start_grace(struct lws_vhost *vh);
+
+#endif
+
similarity index 53%
rename from lib/tls/private.h
rename to lib/tls/private-lib-tls.h
index 16b7d66..28203c5 100644 (file)
@@ -1,24 +1,27 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
- *  This is included from core/private.h if LWS_WITH_TLS
+ *  This is included from private-lib-core.h if LWS_WITH_TLS
  */
 
 #if !defined(__LWS_TLS_PRIVATE_H__)
@@ -27,6 +30,8 @@
 
 #if defined(LWS_WITH_TLS)
 
+#include "private-jit-trust.h"
+
 #if defined(USE_WOLFSSL)
  #if defined(USE_OLD_CYASSL)
   #if defined(_WIN32)
@@ -49,7 +54,7 @@
   #define OPENSSL_NO_TLSEXT
  #endif /* not USE_OLD_CYASSL */
 #else /* WOLFSSL */
- #if defined(LWS_WITH_ESP32)
+ #if defined(LWS_PLAT_FREERTOS)
   #define OPENSSL_NO_TLSEXT
   #if !defined(LWS_AMAZON_RTOS)
    /* AMAZON RTOS has its own setting via MTK_MBEDTLS_CONFIG_FILE */
@@ -60,7 +65,7 @@
   #include <mbedtls/aes.h>
   #include <mbedtls/gcm.h>
   #include <mbedtls/x509_crt.h>
-  #include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */
+  #include "ssl.h" /* wrapper !!!! */
  #else /* not esp32 */
   #if defined(LWS_WITH_MBEDTLS)
    #include <mbedtls/ssl.h>
    #include <mbedtls/x509_csr.h>
    #include <mbedtls/ecp.h>
    #include <mbedtls/ecdsa.h>
-   #include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */
+  #if defined(LWS_AMAZON_LINUX)
+   #include "ssl.h" /* wrapper !!!! */
+  #else
+   #include "openssl/ssl.h" /* wrapper !!!! */
+  #endif
   #else
    #include <openssl/ssl.h>
    #include <openssl/evp.h>
@@ -83,7 +92,7 @@
    #ifdef LWS_HAVE_OPENSSL_ECDH_H
     #include <openssl/ecdh.h>
    #endif
-   #if !defined(LWS_HAVE_EVP_MD_CTX_free)
+   #if !defined(LWS_HAVE_EVP_MD_CTX_free) && !defined(USE_WOLFSSL)
     #define EVP_MD_CTX_free EVP_MD_CTX_destroy
    #endif
    #include <openssl/x509v3.h>
@@ -109,21 +118,35 @@ enum lws_tls_extant {
        LWS_TLS_EXTANT_ALTERNATIVE
 };
 
-
 #if defined(LWS_WITH_TLS)
 
+#if defined(LWS_WITH_TLS_SESSIONS) && defined(LWS_WITH_CLIENT) && \
+       (defined(LWS_WITH_MBEDTLS) || defined(OPENSSL_IS_BORINGSSL))
+#define LWS_TLS_SYNTHESIZE_CB 1
+#endif
+
+int
+lws_tls_restrict_borrow(struct lws *wsi);
+
+void
+lws_tls_restrict_return(struct lws *wsi);
+
+void
+lws_tls_restrict_return_handshake(struct lws *wsi);
+
 typedef SSL lws_tls_conn;
 typedef SSL_CTX lws_tls_ctx;
 typedef BIO lws_tls_bio;
 typedef X509 lws_tls_x509;
 
 #if defined(LWS_WITH_NETWORK)
-#include "tls/private-network.h"
+#include "private-network.h"
 #endif
 
-LWS_EXTERN int
-lws_context_init_ssl_library(const struct lws_context_creation_info *info);
-LWS_EXTERN void
+int
+lws_context_init_ssl_library(struct lws_context *cx,
+                            const struct lws_context_creation_info *info);
+void
 lws_context_deinit_ssl_library(struct lws_context *context);
 #define LWS_SSL_ENABLED(vh) (vh && vh->tls.use_ssl)
 
@@ -134,26 +157,23 @@ struct lws_ec_valid_curves {
        const char *jwa_name; /* list terminates with NULL jwa_name */
 };
 
-LWS_EXTERN enum lws_tls_extant
+enum lws_tls_extant
 lws_tls_use_any_upgrade_check_extant(const char *name);
-LWS_EXTERN int openssl_websocket_private_data_index;
+extern int openssl_websocket_private_data_index;
 
-
-LWS_EXTERN void
+void
 lws_tls_err_describe_clear(void);
 
-LWS_EXTERN int
+int
 lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type,
                          union lws_tls_cert_info_results *buf, size_t len);
-LWS_EXTERN int
+int
 lws_tls_check_all_cert_lifetimes(struct lws_context *context);
 
-LWS_EXTERN int
+int
 lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
                              const char *inbuf, lws_filepos_t inlen,
                              uint8_t **buf, lws_filepos_t *amount);
-LWS_EXTERN char *
-lws_ssl_get_error_string(int status, int ret, char *buf, size_t len);
 
 int
 lws_gencrypto_bits_to_bytes(int bits);
@@ -166,7 +186,7 @@ lws_gencrypto_destroy_elements(struct lws_gencrypto_keyelem *el, int m);
 struct lws_gencrypto_keyelem;
 struct lws_ec_curves;
 
-LWS_EXTERN const struct lws_ec_curves lws_ec_curves[4];
+extern const struct lws_ec_curves lws_ec_curves[4];
 const struct lws_ec_curves *
 lws_genec_curve(const struct lws_ec_curves *table, const char *name);
 LWS_VISIBLE void
@@ -178,5 +198,48 @@ int
 lws_genec_confirm_curve_allowed_by_tls_id(const char *allowed, int id,
                                          struct lws_jwk *jwk);
 
+void
+lws_tls_reuse_session(struct lws *wsi);
+
+void
+lws_tls_session_cache(struct lws_vhost *vh, uint32_t ttl);
+
+int
+lws_tls_session_name_from_wsi(struct lws *wsi, char *buf, size_t len);
+
+/**
+ * lws_tls_session_name_discrete() - form an lws session tag name from pieces
+ *
+ * \param vhname: name of the vhost
+ * \param host: name of the host we are connecting to, like warmcat.com
+ * \param port: the port we connected to
+ * \param buf: the destination buffer for the tag
+ * \param len: the max available size of the destination buffer
+ *
+ * Creates a tag string representing a specific host, for use with serializing
+ * sessions made with the host.
+ */
+void
+lws_tls_session_tag_discrete(const char *vhname, const char *host,
+                            uint16_t port, char *buf, size_t len);
+
+/**
+ * lws_tls_session_name_from_wsi() - form an lws session tag name from a client wsi
+ *
+ * \param wsi: the wsi whose vhost, host and port we should use for the tag
+ * \param buf: the destination buffer for the tag
+ * \param len: the max available size of the destination buffer
+ *
+ * Creates a tag string representing a specific host, for use with serializing
+ * sessions made with the host.
+ */
+int
+lws_tls_session_tag_from_wsi(struct lws *wsi, char *buf, size_t len);
+
+#else /* ! WITH_TLS */
+
+#define lws_tls_restrict_borrow(xxx) (0)
+#define lws_tls_restrict_return(xxx)
+
 #endif
 #endif
index 806b62d..9c26f0b 100644 (file)
@@ -1,24 +1,27 @@
-/*
+ /*
  * libwebsockets - small server side websockets and web server implementation
  *
  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
- *  This is included from core/private.h if LWS_WITH_TLS
+ *  This is included from private-lib-core.h if LWS_WITH_TLS
  */
 
 struct lws_context_per_thread;
@@ -48,6 +51,7 @@ struct alpn_ctx {
 struct lws_vhost_tls {
        lws_tls_ctx *ssl_ctx;
        lws_tls_ctx *ssl_client_ctx;
+       struct lws_tls_client_reuse *tcr;
        const char *alpn;
        struct lws_tls_ss_pieces *ss; /* for acme tls certs */
        char *alloc_cert_path;
@@ -62,64 +66,80 @@ struct lws_vhost_tls {
        int allow_non_ssl_on_ssl_port;
        int ssl_info_event_mask;
 
+#if defined(LWS_WITH_MBEDTLS)
+       uint32_t tls_session_cache_ttl;
+#endif
+
        unsigned int user_supplied_ssl_ctx:1;
        unsigned int skipped_certs:1;
 };
 
 struct lws_lws_tls {
-       lws_tls_conn *ssl;
-       lws_tls_bio *client_bio;
-       struct lws_dll2 dll_pending_tls;
-       unsigned int use_ssl;
-       unsigned int redirect_to_https:1;
+       lws_tls_conn            *ssl;
+       lws_tls_bio             *client_bio;
+#if defined(LWS_TLS_SYNTHESIZE_CB)
+       lws_sorted_usec_list_t  sul_cb_synth;
+#endif
+#if !defined(LWS_WITH_MBEDTLS) && defined(LWS_WITH_TLS_JIT_TRUST)
+       /* mbedtls has this in the wrapper, since no wsi ptr at validation */
+       lws_tls_kid_chain_t     kid_chain;
+#endif
+       struct lws_dll2         dll_pending_tls;
+       char                    err_helper[32];
+       unsigned int            use_ssl;
+       unsigned int            redirect_to_https:1;
 };
 
 
-LWS_EXTERN void
+void
 lws_context_init_alpn(struct lws_vhost *vhost);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
+int LWS_WARN_UNUSED_RESULT
+lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, size_t len);
+int LWS_WARN_UNUSED_RESULT
+lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, size_t len);
+int LWS_WARN_UNUSED_RESULT
 lws_ssl_pending(struct lws *wsi);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_server_socket_service_ssl(struct lws *new_wsi, lws_sockfd_type accept_fd);
-LWS_EXTERN int
+int LWS_WARN_UNUSED_RESULT
+lws_server_socket_service_ssl(struct lws *new_wsi, lws_sockfd_type accept_fd,
+                               char is_pollin);
+
+void
+lws_sess_cache_synth_cb(lws_sorted_usec_list_t *sul);
+
+int
 lws_ssl_close(struct lws *wsi);
-LWS_EXTERN void
+void
 lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost);
-LWS_EXTERN void
+void
 lws_ssl_context_destroy(struct lws_context *context);
 void
 __lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi);
 LWS_VISIBLE void
 lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi);
-LWS_EXTERN int
+int
 lws_ssl_client_bio_create(struct lws *wsi);
-LWS_EXTERN int
-lws_ssl_client_connect1(struct lws *wsi);
-LWS_EXTERN int
-lws_ssl_client_connect2(struct lws *wsi, char *errbuf, int len);
-LWS_EXTERN int
+
+int
+lws_ssl_client_connect2(struct lws *wsi, char *errbuf, size_t len);
+int
 lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt);
-LWS_EXTERN int
+int
 lws_gate_accepts(struct lws_context *context, int on);
-LWS_EXTERN void
+void
 lws_ssl_bind_passphrase(lws_tls_ctx *ssl_ctx, int is_client,
                        const struct lws_context_creation_info *info);
-LWS_EXTERN void
+void
 lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
-LWS_EXTERN int
+int
 lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
                          const char *cert, const char *private_key,
                          const char *mem_cert, size_t len_mem_cert,
                          const char *mem_privkey, size_t mem_privkey_len);
-LWS_EXTERN enum lws_tls_extant
+enum lws_tls_extant
 lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
                            const char *private_key);
-#if !defined(LWS_NO_SERVER)
LWS_EXTERN int
+#if defined(LWS_WITH_SERVER)
+ int
  lws_context_init_server_ssl(const struct lws_context_creation_info *info,
                             struct lws_vhost *vhost);
  void
@@ -129,35 +149,35 @@ lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
  #define lws_tls_acme_sni_cert_destroy(_a)
 #endif
 
-LWS_EXTERN void
+void
 lws_ssl_destroy(struct lws_vhost *vhost);
 
 /*
 * lws_tls_ abstract backend implementations
 */
 
-LWS_EXTERN int
+int
 lws_tls_server_client_cert_verify_config(struct lws_vhost *vh);
-LWS_EXTERN int
+int
 lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info,
                          struct lws_vhost *vhost, struct lws *wsi);
-LWS_EXTERN int
+int
 lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd);
 
-LWS_EXTERN enum lws_ssl_capable_status
+enum lws_ssl_capable_status
 lws_tls_server_accept(struct lws *wsi);
 
-LWS_EXTERN enum lws_ssl_capable_status
+enum lws_ssl_capable_status
 lws_tls_server_abort_connection(struct lws *wsi);
 
-LWS_EXTERN enum lws_ssl_capable_status
+enum lws_ssl_capable_status
 __lws_tls_shutdown(struct lws *wsi);
 
-LWS_EXTERN enum lws_ssl_capable_status
-lws_tls_client_connect(struct lws *wsi);
-LWS_EXTERN int
-lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len);
-LWS_EXTERN int
+enum lws_ssl_capable_status
+lws_tls_client_connect(struct lws *wsi, char *errbuf, size_t len);
+int
+lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, size_t ebuf_len);
+int
 lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                            const struct lws_context_creation_info *info,
                            const char *cipher_list,
@@ -167,24 +187,22 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
                            const char *cert_filepath,
                            const void *cert_mem,
                            unsigned int cert_mem_len,
-                           const char *private_key_filepath);
+                           const char *private_key_filepath,
+                           const void *key_mem,
+                           unsigned int key_mem_len);
 
-LWS_EXTERN lws_tls_ctx *
+
+lws_tls_ctx *
 lws_tls_ctx_from_wsi(struct lws *wsi);
-LWS_EXTERN int
+int
 lws_ssl_get_error(struct lws *wsi, int n);
 
-LWS_EXTERN int
+int
 lws_context_init_client_ssl(const struct lws_context_creation_info *info,
                    struct lws_vhost *vhost);
 
-LWS_EXTERN void
+void
 lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
 
 int
 lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt);
-
-
-
-
-
index a94ef30..9d93a3d 100644 (file)
@@ -1,40 +1,46 @@
 /*
- * libwebsockets - client-related ssl code independent of backend
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
-int
-lws_ssl_client_connect1(struct lws *wsi)
+static int
+lws_ssl_client_connect1(struct lws *wsi, char *errbuf, size_t len)
 {
-       struct lws_context *context = wsi->context;
-       int n = 0;
-
-       lws_latency_pre(context, wsi);
-       n = lws_tls_client_connect(wsi);
-       lws_latency(context, wsi, "SSL_connect hs", n, n > 0);
+       int n;
 
+       n = lws_tls_client_connect(wsi, errbuf, len);
        switch (n) {
        case LWS_SSL_CAPABLE_ERROR:
+               lws_tls_restrict_return_handshake(wsi);
                return -1;
        case LWS_SSL_CAPABLE_DONE:
+               lws_tls_restrict_return_handshake(wsi);
+               lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
+#if defined(LWS_WITH_CONMON)
+       wsi->conmon.ciu_tls = (lws_conmon_interval_us_t)
+                                       (lws_now_usecs() - wsi->conmon_datum);
+#endif
                return 1; /* connected */
        case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
                lws_callback_on_writable(wsi);
@@ -49,21 +55,18 @@ lws_ssl_client_connect1(struct lws *wsi)
 }
 
 int
-lws_ssl_client_connect2(struct lws *wsi, char *errbuf, int len)
+lws_ssl_client_connect2(struct lws *wsi, char *errbuf, size_t len)
 {
-       int n = 0;
+       int n;
 
        if (lwsi_state(wsi) == LRS_WAITING_SSL) {
-               lws_latency_pre(wsi->context, wsi);
-
-               n = lws_tls_client_connect(wsi);
+               n = lws_tls_client_connect(wsi, errbuf, len);
                lwsl_debug("%s: SSL_connect says %d\n", __func__, n);
-               lws_latency(wsi->context, wsi,
-                           "SSL_connect LRS_WAITING_SSL", n, n > 0);
 
                switch (n) {
                case LWS_SSL_CAPABLE_ERROR:
-                       lws_snprintf(errbuf, len, "client connect failed");
+                       lws_tls_restrict_return_handshake(wsi);
+                       // lws_snprintf(errbuf, len, "client connect failed");
                        return -1;
                case LWS_SSL_CAPABLE_DONE:
                        break; /* connected */
@@ -74,14 +77,24 @@ lws_ssl_client_connect2(struct lws *wsi, char *errbuf, int len)
                        lwsi_set_state(wsi, LRS_WAITING_SSL);
                        /* fallthru */
                case LWS_SSL_CAPABLE_MORE_SERVICE:
-                       return 0;
+                       return 0; /* retry */
                }
        }
 
-       if (lws_tls_client_confirm_peer_cert(wsi, errbuf, len))
+       lws_tls_restrict_return_handshake(wsi);
+
+       if (lws_tls_client_confirm_peer_cert(wsi, errbuf, len)) {
+               lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
                return -1;
+       }
 
-       return 1;
+       lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
+#if defined(LWS_WITH_CONMON)
+       wsi->conmon.ciu_tls = (lws_conmon_interval_us_t)
+                                       (lws_now_usecs() - wsi->conmon_datum);
+#endif
+
+       return 1; /* connected */
 }
 
 
@@ -92,7 +105,9 @@ int lws_context_init_client_ssl(const struct lws_context_creation_info *info,
        const char *cert_filepath = info->ssl_cert_filepath;
        const char *ca_filepath = info->ssl_ca_filepath;
        const char *cipher_list = info->ssl_cipher_list;
-       struct lws wsi;
+       lws_fakewsi_def_plwsa(&vhost->context->pt[0]);
+
+       lws_fakewsi_prep_plwsa_ctx(vhost->context);
 
        if (vhost->options & LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG)
                return 0;
@@ -123,6 +138,7 @@ int lws_context_init_client_ssl(const struct lws_context_creation_info *info,
        if (vhost->tls.ssl_client_ctx)
                return 0;
 
+#if !defined(LWS_WITH_MBEDTLS)
        if (info->provided_client_ssl_ctx) {
                /* use the provided OpenSSL context if given one */
                vhost->tls.ssl_client_ctx = info->provided_client_ssl_ctx;
@@ -131,6 +147,7 @@ int lws_context_init_client_ssl(const struct lws_context_creation_info *info,
 
                return 0;
        }
+#endif
 
        if (lws_tls_client_create_vhost_context(vhost, info, cipher_list,
                                                ca_filepath,
@@ -139,7 +156,10 @@ int lws_context_init_client_ssl(const struct lws_context_creation_info *info,
                                                cert_filepath,
                                                info->client_ssl_cert_mem,
                                                info->client_ssl_cert_mem_len,
-                                               private_key_filepath))
+                                               private_key_filepath,
+                                               info->client_ssl_key_mem,
+                                               info->client_ssl_key_mem_len
+                                               ))
                return 1;
 
        lwsl_info("created client ssl context for %s\n", vhost->name);
@@ -148,13 +168,65 @@ int lws_context_init_client_ssl(const struct lws_context_creation_info *info,
         * give him a fake wsi with context set, so he can use
         * lws_get_context() in the callback
         */
-       memset(&wsi, 0, sizeof(wsi));
-       wsi.vhost = vhost; /* not a real bound wsi */
-       wsi.context = vhost->context;
 
-       vhost->protocols[0].callback(&wsi,
+       plwsa->vhost = vhost; /* not a real bound wsi */
+
+       vhost->protocols[0].callback((struct lws *)plwsa,
                        LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
                                     vhost->tls.ssl_client_ctx, NULL, 0);
 
        return 0;
 }
+
+int
+lws_client_create_tls(struct lws *wsi, const char **pcce, int do_c1)
+{
+       /* we can retry this... just cook the SSL BIO the first time */
+
+       if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
+               int n;
+
+               if (!wsi->tls.ssl) {
+
+#if defined(LWS_WITH_TLS)
+                       if (!wsi->transaction_from_pipeline_queue &&
+                           lws_tls_restrict_borrow(wsi)) {
+                               *pcce = "tls restriction limit";
+                               return CCTLS_RETURN_ERROR;
+                       }
+#endif
+                       if (lws_ssl_client_bio_create(wsi) < 0) {
+                               *pcce = "bio_create failed";
+                               return CCTLS_RETURN_ERROR;
+                       }
+               }
+
+               if (!do_c1)
+                       return CCTLS_RETURN_DONE;
+
+               lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
+               lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mt_conn_tls);
+#if defined(LWS_WITH_CONMON)
+               wsi->conmon_datum = lws_now_usecs();
+#endif
+
+               n = lws_ssl_client_connect1(wsi, (char *)wsi->a.context->pt[(int)wsi->tsi].serv_buf,
+                                           wsi->a.context->pt_serv_buf_size);
+               lwsl_debug("%s: lws_ssl_client_connect1: %d\n", __func__, n);
+               if (!n)
+                       return CCTLS_RETURN_RETRY; /* caller should return 0 */
+
+               if (n < 0) {
+                       *pcce = (const char *)wsi->a.context->pt[(int)wsi->tsi].serv_buf;
+                       lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO);
+                       return CCTLS_RETURN_ERROR;
+               }
+               /* ...connect1 already handled caliper if SSL_accept done */
+
+               lws_tls_server_conn_alpn(wsi);
+
+       } else
+               wsi->tls.ssl = NULL;
+
+       return CCTLS_RETURN_DONE; /* OK */
+}
diff --git a/lib/tls/tls-jit-trust.c b/lib/tls/tls-jit-trust.c
new file mode 100644 (file)
index 0000000..f780299
--- /dev/null
@@ -0,0 +1,689 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+void
+lws_tls_kid_copy(union lws_tls_cert_info_results *ci, lws_tls_kid_t *kid)
+{
+
+       /*
+        * KIDs all seem to be 20 bytes / SHA1 or less.  If we get one that
+        * is bigger, treat only the first 20 bytes as significant.
+        */
+
+       if ((size_t)ci->ns.len > sizeof(kid->kid))
+               kid->kid_len = sizeof(kid->kid);
+       else
+               kid->kid_len = (uint8_t)ci->ns.len;
+
+       memcpy(kid->kid, ci->ns.name, kid->kid_len);
+}
+
+void
+lws_tls_kid_copy_kid(lws_tls_kid_t *kid, const lws_tls_kid_t *src)
+{
+       int klen = sizeof(kid->kid);
+
+       if (src->kid_len < klen)
+               klen = src->kid_len;
+
+       kid->kid_len = (uint8_t)klen;
+
+       memcpy(kid->kid, src->kid, (size_t)klen);
+}
+
+int
+lws_tls_kid_cmp(const lws_tls_kid_t *a, const lws_tls_kid_t *b)
+{
+       if (a->kid_len != b->kid_len)
+               return 1;
+
+       return memcmp(a->kid, b->kid, a->kid_len);
+}
+
+/*
+ * We have the SKID and AKID for every peer cert captured, but they may be
+ * in any order, and eg, falsely have sent the root CA, or an attacker may
+ * send unresolveable self-referencing loops of KIDs.
+ *
+ * Let's sort them into the SKID -> AKID hierarchy, so the last entry is the
+ * server cert and the first entry is the highest parent that the server sent.
+ * Normally the top one will be an intermediate, and its AKID is the ID of the
+ * root CA cert we would need to trust to validate the chain.
+ *
+ * It's not unknown the server is misconfigured to also send the root CA, if so
+ * the top slot's AKID is empty and we should look for its SKID in the trust
+ * blob.
+ *
+ * If we return 0, we succeeded and the AKID of ch[0] is the SKID we want to see
+ * try to import from the trust blob.
+ *
+ * If we return nonzero, we can't identify what we want and should abandon the
+ * connection.
+ */
+
+int
+lws_tls_jit_trust_sort_kids(struct lws *wsi, lws_tls_kid_chain_t *ch)
+{
+       size_t hl;
+       lws_tls_jit_inflight_t *inf;
+       int n, m, sanity = 10;
+       const char *host = wsi->cli_hostname_copy;
+       char more = 1;
+
+       lwsl_info("%s\n", __func__);
+
+       if (!host) {
+               if (wsi->stash && wsi->stash->cis[CIS_HOST])
+                       host = wsi->stash->cis[CIS_HOST];
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+               else
+                       host = lws_hdr_simple_ptr(wsi,
+                                             _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+       }
+#endif
+       if (!host)
+               return 1;
+
+       hl = strlen(host);
+
+       /* something to work with? */
+
+       if (!ch->count)
+               return 1;
+
+       /* do we need to sort? */
+
+       if (ch->count > 1) {
+
+               /* okie... */
+
+               while (more) {
+
+                       if (!sanity--)
+                               /* let's not get fooled into spinning */
+                               return 1;
+
+                       more = 0;
+                       for (n = 0; n < ch->count - 1; n++) {
+
+                               if (!lws_tls_kid_cmp(&ch->skid[n],
+                                                    &ch->akid[n + 1]))
+                                       /* next belongs with this one */
+                                       continue;
+
+                               /*
+                                * next doesn't belong with this one, let's
+                                * try to figure out where this one does belong
+                                * then
+                                */
+
+                               for (m = 0; m < ch->count; m++) {
+                                       if (n == m)
+                                               continue;
+                                       if (!lws_tls_kid_cmp(&ch->skid[n],
+                                                            &ch->akid[m])) {
+                                               lws_tls_kid_t t;
+
+                                               /*
+                                                * m references us, so we
+                                                * need to go one step above m,
+                                                * swap m and n
+                                                */
+
+                                               more = 1;
+                                               t = ch->akid[m];
+                                               ch->akid[m] = ch->akid[n];
+                                               ch->akid[n] = t;
+                                               t = ch->skid[m];
+                                               ch->skid[m] = ch->skid[n];
+                                               ch->skid[n] = t;
+
+                                               break;
+                                       }
+                               }
+
+                               if (more)
+                                       break;
+                       }
+               }
+
+               /* then we should be sorted */
+       }
+
+       for (n = 0; n < ch->count; n++) {
+               lwsl_info("%s: AKID[%d]\n", __func__, n);
+               lwsl_hexdump_info(ch->akid[n].kid, ch->akid[n].kid_len);
+               lwsl_info("%s: SKID[%d]\n", __func__, n);
+               lwsl_hexdump_info(ch->skid[n].kid, ch->skid[n].kid_len);
+       }
+
+       /* to go further, user must provide a lookup helper */
+
+       if (!wsi->a.context->system_ops ||
+           !wsi->a.context->system_ops->jit_trust_query)
+               return 1;
+
+       /*
+        * If there's already a pending lookup for this host, let's bail and
+        * just wait for that to complete (since it will be done async if we
+        * can see it)
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, d,
+                             wsi->a.context->jit_inflight.head) {
+               inf = lws_container_of(d, lws_tls_jit_inflight_t, list);
+
+               if (!strcmp((const char *)&inf[1], host))
+                       /* already being handled */
+                       return 1;
+
+       } lws_end_foreach_dll(d);
+
+       /*
+        * No... let's make an inflight entry for this host, then
+        */
+
+       inf = lws_zalloc(sizeof(*inf) + hl + 1, __func__);
+       if (!inf)
+               return 1;
+
+       memcpy(&inf[1], host, hl + 1);
+       inf->refcount = (char)ch->count;
+       lws_dll2_add_tail(&inf->list, &wsi->a.context->jit_inflight);
+
+       /*
+        * ...kid_chain[0] AKID should indicate the right CA SKID that we want.
+        *
+        * Because of cross-signing, we check all of them and accept we may get
+        * multiple (the inflight accepts up to 2) CAs needed.
+        */
+
+       for (n = 0; n < ch->count; n++)
+               wsi->a.context->system_ops->jit_trust_query(wsi->a.context,
+                       ch->akid[n].kid, (size_t)ch->akid[n].kid_len,
+                       (void *)inf);
+
+       return 0;
+}
+
+static void
+tag_to_vh_name(char *result, size_t max, uint32_t tag)
+{
+       lws_snprintf(result, max, "jitt-%08X", tag);
+}
+
+int
+lws_tls_jit_trust_vhost_bind(struct lws_context *cx, const char *address,
+                            struct lws_vhost **pvh)
+{
+       lws_tls_jit_cache_item_t *ci, jci;
+       lws_tls_jit_inflight_t *inf;
+       char vhtag[32];
+       size_t size;
+       int n;
+
+       if (lws_cache_item_get(cx->trust_cache, address, (const void **)&ci,
+                                                                       &size))
+               /*
+                * There's no cached info, we have to start from scratch on
+                * this one
+                */
+               return 1;
+
+       /* gotten cache item may be evicted by jit_trust_query */
+       jci = *ci;
+
+       /*
+        * We have some trust cache information for this host already, it tells
+        * us the trusted CA SKIDs we found before, and the xor tag used to name
+        * the vhost configured for these trust CAs in its SSL_CTX.
+        *
+        * Let's check first if the correct prepared vhost already exists, if
+        * so, we can just bind to that and go.
+        */
+
+       tag_to_vh_name(vhtag, sizeof(vhtag), jci.xor_tag);
+
+       *pvh = lws_get_vhost_by_name(cx, vhtag);
+       if (*pvh) {
+               lwsl_info("%s: %s -> existing %s\n", __func__, address, vhtag);
+               /* hit, let's just use that then */
+               return 0;
+       }
+
+       /*
+        * ... so, we know the SKIDs of the missing CAs, but we don't have the
+        * DERs for them, and so no configured vhost trusting them yet.  We have
+        * had the DERs at some point, but we can't afford to cache them, so
+        * we will have to get them again.
+        *
+        * Let's make an inflight for this, it will create the vhost when it
+        * completes.  If syncrhronous, then it will complete before we leave
+        * here, otherwise it will have a life of its own until all the
+        * queries use the cb to succeed or fail.
+        */
+
+       size = strlen(address);
+       inf = lws_zalloc(sizeof(*inf) + size + 1, __func__);
+       if (!inf)
+               return 1;
+
+       memcpy(&inf[1], address, size + 1);
+       inf->refcount = (char)jci.count_skids;
+       lws_dll2_add_tail(&inf->list, &cx->jit_inflight);
+
+       /*
+        * ...kid_chain[0] AKID should indicate the right CA SKID that we want.
+        *
+        * Because of cross-signing, we check all of them and accept we may get
+        * multiple (we can handle 3) CAs needed.
+        */
+
+       for (n = 0; n < jci.count_skids; n++)
+               cx->system_ops->jit_trust_query(cx, jci.skids[n].kid,
+                                               (size_t)jci.skids[n].kid_len,
+                                               (void *)inf);
+
+       /* ... in case synchronous and it already finished the queries */
+
+       *pvh = lws_get_vhost_by_name(cx, vhtag);
+       if (*pvh) {
+               /* hit, let's just use that then */
+               lwsl_info("%s: bind to created vhost %s\n", __func__, vhtag);
+               return 0;
+       } else
+               lwsl_err("%s: unable to bind to %s\n", __func__, vhtag);
+
+       /* right now, nothing to offer */
+
+       return 1;
+}
+
+void
+lws_tls_jit_trust_inflight_destroy(lws_tls_jit_inflight_t *inf)
+{
+       int n;
+
+       for (n = 0; n < inf->ders; n++)
+               lws_free_set_NULL(inf->der[n]);
+       lws_dll2_remove(&inf->list);
+
+       lws_free(inf);
+}
+
+static int
+inflight_destroy(struct lws_dll2 *d, void *user)
+{
+       lws_tls_jit_inflight_t *inf;
+
+       inf = lws_container_of(d, lws_tls_jit_inflight_t, list);
+
+       lws_tls_jit_trust_inflight_destroy(inf);
+
+       return 0;
+}
+
+void
+lws_tls_jit_trust_inflight_destroy_all(struct lws_context *cx)
+{
+       lws_dll2_foreach_safe(&cx->jit_inflight, cx, inflight_destroy);
+}
+
+static void
+unref_vh_grace_cb(lws_sorted_usec_list_t *sul)
+{
+       struct lws_vhost *vh = lws_container_of(sul, struct lws_vhost,
+                                               sul_unref);
+
+       lwsl_info("%s: %s\n", __func__, vh->lc.gutag);
+
+       lws_vhost_destroy(vh);
+}
+
+void
+lws_tls_jit_trust_vh_start_grace(struct lws_vhost *vh)
+{
+       lwsl_info("%s: %s: unused, grace %dms\n", __func__, vh->lc.gutag,
+                       vh->context->vh_idle_grace_ms);
+       lws_sul_schedule(vh->context, 0, &vh->sul_unref, unref_vh_grace_cb,
+                        (lws_usec_t)vh->context->vh_idle_grace_ms *
+                                                               LWS_US_PER_MS);
+}
+
+#if defined(_DEBUG)
+static void
+lws_tls_jit_trust_cert_info(const uint8_t *der, size_t der_len)
+{
+       struct lws_x509_cert *x;
+       union lws_tls_cert_info_results *u;
+       char p = 0, buf[192 + sizeof(*u)];
+
+       if (lws_x509_create(&x))
+               return;
+
+       if (!lws_x509_parse_from_pem(x, der, der_len)) {
+
+               u = (union lws_tls_cert_info_results *)buf;
+
+               if (!lws_x509_info(x, LWS_TLS_CERT_INFO_ISSUER_NAME, u, 192)) {
+                       lwsl_info("ISS: %s\n", u->ns.name);
+                       p = 1;
+               }
+               if (!lws_x509_info(x, LWS_TLS_CERT_INFO_COMMON_NAME, u, 192)) {
+                       lwsl_info("CN: %s\n", u->ns.name);
+                       p = 1;
+               }
+
+               if (!p) {
+                       lwsl_err("%s: unable to get any info\n", __func__);
+                       lwsl_hexdump_err(der, der_len);
+               }
+       } else
+               lwsl_err("%s: unable to load DER\n", __func__);
+
+       lws_x509_destroy(&x);
+}
+#endif
+
+/*
+ * This processes the JIT Trust lookup results independent of the tls backend.
+ */
+
+int
+lws_tls_jit_trust_got_cert_cb(struct lws_context *cx, void *got_opaque,
+                             const uint8_t *skid, size_t skid_len,
+                             const uint8_t *der, size_t der_len)
+{
+       lws_tls_jit_inflight_t *inf = (lws_tls_jit_inflight_t *)got_opaque;
+       struct lws_context_creation_info info;
+       lws_tls_jit_cache_item_t jci;
+       struct lws_vhost *v;
+       char vhtag[20];
+       char hit = 0;
+       int n;
+
+       /*
+        * Before anything else, check the inf is still valid.  In the low
+        * probability but possible case it was reallocated to be a different
+        * inflight, that may cause different CA certs to apply to a connection,
+        * but since mbedtls will then validate the server cert using the wrong
+        * trusted CA, it will just cause temporary conn fail.
+        */
+
+       lws_start_foreach_dll(struct lws_dll2 *, e, cx->jit_inflight.head) {
+               lws_tls_jit_inflight_t *i = lws_container_of(e,
+                                               lws_tls_jit_inflight_t, list);
+               if (i == inf) {
+                       hit = 1;
+                       break;
+               }
+
+       } lws_end_foreach_dll(e);
+
+       if (!hit)
+               /* inf has already gone */
+               return 1;
+
+       inf->refcount--;
+
+       if (skid_len >= 4)
+               inf->tag ^= *((uint32_t *)skid);
+
+       if (der && inf->ders < (int)LWS_ARRAY_SIZE(inf->der) && inf->refcount) {
+               /*
+                * We have a trusted CA, but more results coming... stash it
+                * in heap.
+                */
+
+               inf->kid[inf->ders].kid_len = (uint8_t)((skid_len >
+                                    (uint8_t)sizeof(inf->kid[inf->ders].kid)) ?
+                                    sizeof(inf->kid[inf->ders].kid) : skid_len);
+               memcpy(inf->kid[inf->ders].kid, skid,
+                      inf->kid[inf->ders].kid_len);
+
+               inf->der[inf->ders] = lws_malloc(der_len, __func__);
+               if (!inf->der[inf->ders])
+                       return 1;
+               memcpy(inf->der[inf->ders], der, der_len);
+               inf->der_len[inf->ders] = (short)der_len;
+               inf->ders++;
+
+               return 0;
+       }
+
+       /*
+        * We accept up to three valid CA, and then end the inflight early.
+        * Any further pending results are dropped, since we got all we could
+        * use.  Up to two valid CA would be held in the inflight and the other
+        * provided in the params.
+        *
+        * If we did not already fill up the inflight, keep waiting for any
+        * others expected
+        */
+
+       if (inf->refcount && inf->ders < (int)LWS_ARRAY_SIZE(inf->der))
+               return 0;
+
+       if (!der && !inf->ders) {
+               lwsl_warn("%s: no trusted CA certs matching\n", __func__);
+
+               goto destroy_inf;
+       }
+
+       tag_to_vh_name(vhtag, sizeof(vhtag), inf->tag);
+
+       /*
+        * We have got at least one CA, it's all the CAs we're going to get,
+        * or that we can handle.  So we have to process and drop the inf.
+        *
+        * First let's make a cache entry with a shortish ttl, mapping the
+        * hostname we were trying to connect to, to the SKIDs that actually
+        * had trust results.  This may come in handy later when we want to
+        * connect to the same host again, but any vhost from before has been
+        * removed... we can just ask for the specific CAs to regenerate the
+        * vhost, without having to first fail the connection attempt to get the
+        * server cert.
+        *
+        * The cache entry can be evicted at any time, so it is selfcontained.
+        * If it's also lost, we start over with the initial failing connection
+        * to figure out what we need to make it work.
+        */
+
+       memset(&jci, 0, sizeof(jci));
+
+       jci.xor_tag = inf->tag;
+
+       /* copy the SKIDs from the inflight and params into the cache item */
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(inf->der); n++)
+               if (inf->kid[n].kid_len)
+                       lws_tls_kid_copy_kid(&jci.skids[jci.count_skids++],
+                                               &inf->kid[n]);
+
+       if (skid_len) {
+               if (skid_len > sizeof(inf->kid[0].kid))
+                       skid_len = sizeof(inf->kid[0].kid);
+               jci.skids[jci.count_skids].kid_len = (uint8_t)skid_len;
+               memcpy(jci.skids[jci.count_skids++].kid, skid, skid_len);
+       }
+
+       lwsl_info("%s: adding cache mapping %s -> %s\n", __func__,
+                       (const char *)&inf[1], vhtag);
+
+       if (lws_cache_write_through(cx->trust_cache, (const char *)&inf[1],
+                                   (const uint8_t *)&jci, sizeof(jci),
+                                   lws_now_usecs() + (3600ll *LWS_US_PER_SEC),
+                                   NULL))
+               lwsl_warn("%s: add to cache failed\n", __func__);
+
+       /* is there already a vhost for this commutative-xor SKID trust? */
+
+       if (lws_get_vhost_by_name(cx, vhtag)) {
+               lwsl_info("%s: tag vhost %s already exists, skipping\n",
+                               __func__, vhtag);
+               goto destroy_inf;
+       }
+
+       /*
+        * We only end up here when we attempted a connection to this hostname.
+        *
+        * We have the identified CA trust DER(s) to hand, let's create the
+        * necessary vhost + prepared SSL_CTX for it to use on the retry, it
+        * will be used straight away if the retry comes before the idle vhost
+        * timeout.
+        *
+        * We also use this path in the case we have the cache entry but no
+        * matching vhost already existing, to create one.
+        */
+
+       memset(&info, 0, sizeof(info));
+       info.vhost_name = vhtag;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.options = cx->options;
+
+       /*
+        * We have to create the vhost with the first valid trusted DER...
+        * if we have a params one, use that so the rest are all from inflight
+        */
+
+       if (der) {
+               info.client_ssl_ca_mem = der;
+               info.client_ssl_ca_mem_len = (unsigned int)der_len;
+               n = 0;
+       } else {
+               info.client_ssl_ca_mem = inf->der[0];
+               info.client_ssl_ca_mem_len = (unsigned int)inf->der_len[0];
+               n = 1;
+       }
+
+#if defined(_DEBUG)
+       lws_tls_jit_trust_cert_info(info.client_ssl_ca_mem,
+                                   info.client_ssl_ca_mem_len);
+#endif
+
+       info.protocols = cx->protocols_copy;
+
+       v = lws_create_vhost(cx, &info);
+       if (!v)
+               lwsl_err("%s: failed to create vh %s\n", __func__, vhtag);
+
+       v->grace_after_unref = 1;
+       lws_tls_jit_trust_vh_start_grace(v);
+
+       /*
+        * Do we need to add more trusted certs from inflight?
+        */
+
+       while (n < inf->ders) {
+
+#if defined(_DEBUG)
+               lws_tls_jit_trust_cert_info(inf->der[n],
+                                           (size_t)inf->der_len[n]);
+#endif
+
+               if (lws_tls_client_vhost_extra_cert_mem(v, inf->der[n],
+                                               (size_t)inf->der_len[n]))
+                       lwsl_err("%s: add extra cert failed\n", __func__);
+               n++;
+       }
+
+       lwsl_info("%s: created jitt %s -> vh %s\n", __func__,
+                               (const char *)&inf[1], vhtag);
+
+destroy_inf:
+       lws_tls_jit_trust_inflight_destroy(inf);
+
+       return 0;
+}
+
+/*
+ * Refer to ./READMEs/README.jit-trust.md for blob layout specification
+ */
+
+int
+lws_tls_jit_trust_blob_queury_skid(const void *_blob, size_t blen,
+                                  const uint8_t *skid, size_t skid_len,
+                                  const uint8_t **prpder, size_t *prder_len)
+{
+       const uint8_t *pskidlen, *pskids, *pder, *blob = (uint8_t *)_blob;
+       const uint16_t *pderlen;
+       int certs;
+
+       /* sanity check blob length and magic */
+
+       if (blen < 32768 ||
+          lws_ser_ru32be(blob) != LWS_JIT_TRUST_MAGIC_BE ||
+          lws_ser_ru32be(blob + LJT_OFS_END) != blen) {
+               lwsl_err("%s: blob not sane\n", __func__);
+
+               return -1;
+       }
+
+       if (!skid_len)
+               return 1;
+
+       /* point into the various sub-tables */
+
+       certs           = (int)lws_ser_ru16be(blob + LJT_OFS_32_COUNT_CERTS);
+
+       pderlen         = (uint16_t *)(blob + lws_ser_ru32be(blob +
+                                                       LJT_OFS_32_DERLEN));
+       pskidlen        = blob + lws_ser_ru32be(blob + LJT_OFS_32_SKIDLEN);
+       pskids          = blob + lws_ser_ru32be(blob + LJT_OFS_32_SKID);
+       pder            = blob + LJT_OFS_DER;
+
+       /* check each cert SKID in turn, return the DER if found */
+
+       while (certs--) {
+
+               /* paranoia / sanity */
+
+               assert(pskids < blob + blen);
+               assert(pder < blob + blen);
+               assert(pskidlen < blob + blen);
+               assert((uint8_t *)pderlen < blob + blen);
+
+               /* we will accept to match on truncated SKIDs */
+
+               if (*pskidlen >= skid_len &&
+                   !memcmp(skid, pskids, skid_len)) {
+                       /*
+                        * We found a trusted CA cert of the right SKID
+                        */
+                       *prpder = pder;
+                       *prder_len = lws_ser_ru16be((uint8_t *)pderlen);
+
+                       return 0;
+               }
+
+               pder += lws_ser_ru16be((uint8_t *)pderlen);
+               pskids += *pskidlen;
+               pderlen++;
+               pskidlen++;
+       }
+
+       return 1;
+}
index 99b5ac8..ef404af 100644 (file)
@@ -3,23 +3,26 @@
  *
  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
 /*
  * fakes POLLIN on all tls guys with buffered rx
@@ -37,9 +40,13 @@ lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt)
                struct lws *wsi = lws_container_of(p, struct lws,
                                                   tls.dll_pending_tls);
 
-               pt->fds[wsi->position_in_fds_table].revents |=
-                       pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
-               ret |= pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN;
+               if (wsi->position_in_fds_table >= 0) {
+
+                       pt->fds[wsi->position_in_fds_table].revents = (short)
+                               (pt->fds[wsi->position_in_fds_table].revents |
+                                (pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN));
+                       ret |= pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN;
+               }
 
        } lws_end_foreach_dll_safe(p, p1);
 
@@ -55,14 +62,14 @@ __lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
 void
 lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
 {
-       struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+       struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
 
        lws_pt_lock(pt, __func__);
        __lws_ssl_remove_wsi_from_buffered_list(wsi);
        lws_pt_unlock(pt);
 }
 
-
+#if defined(LWS_WITH_SERVER)
 int
 lws_tls_check_cert_lifetime(struct lws_vhost *v)
 {
@@ -83,10 +90,10 @@ lws_tls_check_cert_lifetime(struct lws_vhost *v)
                        return 1;
 
                life = (ir.time - now) / (24 * 3600);
-               lwsl_notice("   vhost %s: cert expiry: %dd\n", v->name,
+               lwsl_vhost_notice(v, "   vhost %s: cert expiry: %dd", v->name,
                            (int)life);
        } else
-               lwsl_info("   vhost %s: no cert\n", v->name);
+               lwsl_vhost_info(v, "   vhost %s: no cert", v->name);
 
        memset(&caa, 0, sizeof(caa));
        caa.vh = v;
@@ -110,7 +117,6 @@ lws_tls_check_all_cert_lifetimes(struct lws_context *context)
        return 0;
 }
 
-
 /*
  * LWS_TLS_EXTANT_NO         : skip adding the cert
  * LWS_TLS_EXTANT_YES        : use the cert and private key paths normally
@@ -136,16 +142,16 @@ lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
        if (!cert || !private_key)
                return LWS_TLS_EXTANT_NO;
 
-       n = lws_tls_use_any_upgrade_check_extant(cert);
+       n = (int)lws_tls_use_any_upgrade_check_extant(cert);
        if (n == LWS_TLS_EXTANT_ALTERNATIVE)
                return LWS_TLS_EXTANT_ALTERNATIVE;
-       m = lws_tls_use_any_upgrade_check_extant(private_key);
+       m = (int)lws_tls_use_any_upgrade_check_extant(private_key);
        if (m == LWS_TLS_EXTANT_ALTERNATIVE)
                return LWS_TLS_EXTANT_ALTERNATIVE;
 
        if ((n == LWS_TLS_EXTANT_NO || m == LWS_TLS_EXTANT_NO) &&
            (vhost->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) {
-               lwsl_notice("Ignoring missing %s or %s\n", cert, private_key);
+               lwsl_vhost_notice(vhost, "Ignoring missing %s or %s", cert, private_key);
                vhost->tls.skipped_certs = 1;
 
                return LWS_TLS_EXTANT_NO;
@@ -158,12 +164,11 @@ lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
        return LWS_TLS_EXTANT_YES;
 }
 
-#if !defined(LWS_NO_SERVER)
 /*
  * update the cert for every vhost using the given path
  */
 
-LWS_VISIBLE int
+int
 lws_tls_cert_updated(struct lws_context *context, const char *certpath,
                     const char *keypath,
                     const char *mem_cert, size_t len_mem_cert,
@@ -171,10 +176,10 @@ lws_tls_cert_updated(struct lws_context *context, const char *certpath,
 {
        struct lws wsi;
 
-       wsi.context = context;
+       wsi.a.context = context;
 
        lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) {
-               wsi.vhost = v; /* not a real bound wsi */
+               wsi.a.vhost = v; /* not a real bound wsi */
                if (v->tls.alloc_cert_path && v->tls.key_path &&
                    !strcmp(v->tls.alloc_cert_path, certpath) &&
                    !strcmp(v->tls.key_path, keypath)) {
@@ -183,14 +188,12 @@ lws_tls_cert_updated(struct lws_context *context, const char *certpath,
                                                  mem_privkey, len_mem_privkey);
 
                        if (v->tls.skipped_certs)
-                               lwsl_notice("%s: vhost %s: cert unset\n",
-                                           __func__, v->name);
+                               lwsl_vhost_notice(v, "vhost %s: cert unset", v->name);
                }
        } lws_end_foreach_ll(v, vhost_next);
 
        return 0;
 }
-#endif
 
 int
 lws_gate_accepts(struct lws_context *context, int on)
@@ -199,21 +202,29 @@ lws_gate_accepts(struct lws_context *context, int on)
 
        lwsl_notice("%s: on = %d\n", __func__, on);
 
-#if defined(LWS_WITH_STATS)
-       context->updated = 1;
-#endif
+       if (context->tls_gate_accepts == (char)on)
+               return 0;
+
+       context->tls_gate_accepts = (char)on;
 
        while (v) {
-               if (v->tls.use_ssl && v->lserv_wsi &&
-                   lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
-                                     (LWS_POLLIN) * on))
-                       lwsl_notice("Unable to set accept POLLIN %d\n", on);
+               lws_start_foreach_dll(struct lws_dll2 *, d,
+                                     lws_dll2_get_head(&v->listen_wsi)) {
+                       struct lws *wsi = lws_container_of(d, struct lws,
+                                                          listen_list);
+
+                       if (v->tls.use_ssl &&
+                           lws_change_pollfd(wsi, on ? LWS_POLLIN : 0,
+                                                  on ? 0 : LWS_POLLIN))
+                               lwsl_cx_notice(context, "Unable to set POLLIN %d", on);
+               } lws_end_foreach_dll(d);
 
                v = v->vhost_next;
        }
 
        return 0;
 }
+#endif
 
 /* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */
 
@@ -222,7 +233,10 @@ lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len)
 {
        uint8_t *oos = os, *plen = NULL;
 
-       while (*comma && len > 1) {
+       if (!comma)
+               return 0;
+
+       while (*comma && len > 2) {
                if (!plen && *comma == ' ') {
                        comma++;
                        continue;
@@ -233,17 +247,19 @@ lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len)
                }
 
                if (*comma == ',') {
-                       *plen = lws_ptr_diff(os, plen + 1);
+                       *plen = (uint8_t)lws_ptr_diff(os, plen + 1);
                        plen = NULL;
                        comma++;
                } else {
-                       *os++ = *comma++;
+                       *os++ = (uint8_t)*comma++;
                        len--;
                }
        }
 
        if (plen)
-               *plen = lws_ptr_diff(os, plen + 1);
+               *plen = (uint8_t)lws_ptr_diff(os, plen + 1);
+
+       *os = 0;
 
        return lws_ptr_diff(os, oos);
 }
index db14a6d..dbb5178 100644 (file)
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
+#include "private-lib-core.h"
 
-#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
-                                 OPENSSL_VERSION_NUMBER >= 0x10002000L)
-static int
-alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen,
-       const unsigned char *in, unsigned int inlen, void *arg)
-{
-#if !defined(LWS_WITH_MBEDTLS)
-       struct alpn_ctx *alpn_ctx = (struct alpn_ctx *)arg;
-
-       if (SSL_select_next_proto((unsigned char **)out, outlen, alpn_ctx->data,
-                                 alpn_ctx->len, in, inlen) !=
-           OPENSSL_NPN_NEGOTIATED)
-               return SSL_TLSEXT_ERR_NOACK;
-#endif
-
-       return SSL_TLSEXT_ERR_OK;
-}
-#endif
-
-void
-lws_context_init_alpn(struct lws_vhost *vhost)
-{
-#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
-                                 OPENSSL_VERSION_NUMBER >= 0x10002000L)
-       const char *alpn_comma = vhost->context->tls.alpn_default;
-
-       if (vhost->tls.alpn)
-               alpn_comma = vhost->tls.alpn;
-
-       lwsl_info(" Server '%s' advertising ALPN: %s\n",
-                   vhost->name, alpn_comma);
-       vhost->tls.alpn_ctx.len = lws_alpn_comma_to_openssl(alpn_comma,
-                                       vhost->tls.alpn_ctx.data,
-                                       sizeof(vhost->tls.alpn_ctx.data) - 1);
-
-       SSL_CTX_set_alpn_select_cb(vhost->tls.ssl_ctx, alpn_cb,
-                                  &vhost->tls.alpn_ctx);
-#else
-       lwsl_err(
-               " HTTP2 / ALPN configured but not supported by OpenSSL 0x%lx\n",
-                   OPENSSL_VERSION_NUMBER);
-#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
-}
-
-int
-lws_tls_server_conn_alpn(struct lws *wsi)
-{
-#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
-                                 OPENSSL_VERSION_NUMBER >= 0x10002000L)
-       const unsigned char *name = NULL;
-       char cstr[10];
-       unsigned len;
-
-       if (!wsi->tls.ssl)
-               return 0;
-
-       SSL_get0_alpn_selected(wsi->tls.ssl, &name, &len);
-       if (!len) {
-               lwsl_info("no ALPN upgrade\n");
-               return 0;
-       }
-
-       if (len > sizeof(cstr) - 1)
-               len = sizeof(cstr) - 1;
-
-       memcpy(cstr, name, len);
-       cstr[len] = '\0';
-
-       lwsl_info("negotiated '%s' using ALPN\n", cstr);
-       wsi->tls.use_ssl |= LCCSCF_USE_SSL;
-
-       return lws_role_call_alpn_negotiated(wsi, (const char *)cstr);
-#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
-
-       return 0;
-}
-
-#if !defined(LWS_NO_SERVER)
+#if defined(LWS_WITH_SERVER)
 
 static void
 lws_sul_tls_cb(lws_sorted_usec_list_t *sul)
@@ -108,16 +34,19 @@ lws_sul_tls_cb(lws_sorted_usec_list_t *sul)
 
        lws_tls_check_all_cert_lifetimes(pt->context);
 
-       __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_tls,
-                        (lws_usec_t)24 * 3600 * LWS_US_PER_SEC);
+       __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                           &pt->sul_tls,
+                           (lws_usec_t)24 * 3600 * LWS_US_PER_SEC);
 }
 
-LWS_VISIBLE int
+int
 lws_context_init_server_ssl(const struct lws_context_creation_info *info,
                            struct lws_vhost *vhost)
 {
        struct lws_context *context = vhost->context;
-       struct lws wsi;
+       lws_fakewsi_def_plwsa(&vhost->context->pt[0]);
+
+       lws_fakewsi_prep_plwsa_ctx(vhost->context);
 
        if (!lws_check_opt(info->options,
                           LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
@@ -146,19 +75,15 @@ lws_context_init_server_ssl(const struct lws_context_creation_info *info,
                        lwsl_notice(" SSL ciphers: '%s'\n",
                                                info->ssl_cipher_list);
 
-               if (vhost->tls.use_ssl)
-                       lwsl_notice(" Using SSL mode\n");
-               else
-                       lwsl_notice(" Using non-SSL mode\n");
+               lwsl_notice(" Vhost '%s' using %sTLS mode\n",
+                           vhost->name, vhost->tls.use_ssl ? "" : "non-");
        }
 
        /*
         * give him a fake wsi with context + vhost set, so he can use
         * lws_get_context() in the callback
         */
-       memset(&wsi, 0, sizeof(wsi));
-       wsi.vhost = vhost; /* not a real bound wsi */
-       wsi.context = context;
+       plwsa->vhost = vhost; /* not a real bound wsi */
 
        /*
         * as a server, if we are requiring clients to identify themselves
@@ -174,12 +99,12 @@ lws_context_init_server_ssl(const struct lws_context_creation_info *info,
         * allowing it to verify incoming client certs
         */
        if (vhost->tls.use_ssl) {
-               if (lws_tls_server_vhost_backend_init(info, vhost, &wsi))
+               if (lws_tls_server_vhost_backend_init(info, vhost, (struct lws *)plwsa))
                        return -1;
 
                lws_tls_server_client_cert_verify_config(vhost);
 
-               if (vhost->protocols[0].callback(&wsi,
+               if (vhost->protocols[0].callback((struct lws *)plwsa,
                            LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
                            vhost->tls.ssl_ctx, vhost, 0))
                        return -1;
@@ -191,25 +116,24 @@ lws_context_init_server_ssl(const struct lws_context_creation_info *info,
        /* check certs once a day */
 
        context->pt[0].sul_tls.cb = lws_sul_tls_cb;
-       __lws_sul_insert(&context->pt[0].pt_sul_owner, &context->pt[0].sul_tls,
-                        (lws_usec_t)24 * 3600 * LWS_US_PER_SEC);
+       __lws_sul_insert_us(&context->pt[0].pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED],
+                           &context->pt[0].sul_tls,
+                           (lws_usec_t)24 * 3600 * LWS_US_PER_SEC);
 
        return 0;
 }
 #endif
 
-LWS_VISIBLE int
-lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
+int
+lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd, char from_pollin)
 {
-       struct lws_context *context = wsi->context;
+       struct lws_context *context = wsi->a.context;
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        struct lws_vhost *vh;
-        char buf[256];
+       ssize_t s;
        int n;
 
-        (void)buf;
-
-       if (!LWS_SSL_ENABLED(wsi->vhost))
+       if (!LWS_SSL_ENABLED(wsi->a.vhost))
                return 0;
 
        switch (lwsi_state(wsi)) {
@@ -219,28 +143,20 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                        lwsl_err("%s: leaking ssl\n", __func__);
                if (accept_fd == LWS_SOCK_INVALID)
                        assert(0);
-               if (context->simultaneous_ssl_restriction &&
-                   context->simultaneous_ssl >=
-                           context->simultaneous_ssl_restriction) {
-                       lwsl_notice("unable to deal with SSL connection\n");
+
+               if (lws_tls_restrict_borrow(wsi)) {
+                       lwsl_err("%s: failed on ssl restriction\n", __func__);
                        return 1;
                }
 
                if (lws_tls_server_new_nonblocking(wsi, accept_fd)) {
+                       lwsl_err("%s: failed on lws_tls_server_new_nonblocking\n", __func__);
                        if (accept_fd != LWS_SOCK_INVALID)
                                compatible_close(accept_fd);
+                       lws_tls_restrict_return(wsi);
                        goto fail;
                }
 
-               if (context->simultaneous_ssl_restriction &&
-                   ++context->simultaneous_ssl ==
-                                   context->simultaneous_ssl_restriction)
-                       /* that was the last allowed SSL connection */
-                       lws_gate_accepts(context, 0);
-
-#if defined(LWS_WITH_STATS)
-               context->updated = 1;
-#endif
                /*
                 * we are not accepted yet, but we need to enter ourselves
                 * as a live connection.  That way we can retry when more
@@ -256,7 +172,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                lws_pt_unlock(pt);
 
                lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
-                               context->timeout_secs);
+                               (int)context->timeout_secs);
 
                lwsl_debug("inserted SSL accept into fds, trying SSL_accept\n");
 
@@ -269,13 +185,14 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                        goto fail;
                }
 
-               lws_latency_pre(context, wsi);
-
-               if (wsi->vhost->tls.allow_non_ssl_on_ssl_port) {
+               if (wsi->a.vhost->tls.allow_non_ssl_on_ssl_port && !wsi->skip_fallback) {
+                       /*
+                        * We came here by POLLIN, so there is supposed to be
+                        * something to read...
+                        */
 
-                       n = recv(wsi->desc.sockfd, (char *)pt->serv_buf,
+                       s = recv(wsi->desc.sockfd, (char *)pt->serv_buf,
                                 context->pt_serv_buf_size, MSG_PEEK);
-
                        /*
                         * We have LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT..
                         * this just means don't hang up on him because of no
@@ -301,7 +218,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                         *     continue with that
                         */
 
-                       if (n >= 1 && pt->serv_buf[0] >= ' ') {
+                       if (s >= 1 && pt->serv_buf[0] >= ' ') {
                                /*
                                * TLS content-type for Handshake is 0x16, and
                                * for ChangeCipherSpec Record, it's 0x14
@@ -321,7 +238,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                                 */
                                wsi->tls.ssl = NULL;
 
-                               if (lws_check_opt(wsi->vhost->options,
+                               if (lws_check_opt(wsi->a.vhost->options,
                                    LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS)) {
                                        lwsl_info("%s: redirecting from http "
                                                  "to https\n", __func__);
@@ -329,7 +246,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                                        goto notls_accepted;
                                }
 
-                               if (lws_check_opt(wsi->vhost->options,
+                               if (lws_check_opt(wsi->a.vhost->options,
                                LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER)) {
                                        lwsl_info("%s: allowing unencrypted "
                                                  "http service on tls port\n",
@@ -337,7 +254,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                                        goto notls_accepted;
                                }
 
-                               if (lws_check_opt(wsi->vhost->options,
+                               if (lws_check_opt(wsi->a.vhost->options,
                    LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG)) {
                                        if (lws_http_to_fallback(wsi, NULL, 0))
                                                goto fail;
@@ -348,18 +265,37 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
 
                                lwsl_notice("%s: client did not send a valid "
                                            "tls hello (default vhost %s)\n",
-                                           __func__, wsi->vhost->name);
+                                           __func__, wsi->a.vhost->name);
                                goto fail;
                        }
-                       if (!n) {
+                       if (!s) {
+                               /*
+                                * POLLIN but nothing to read is supposed to
+                                * mean the connection is gone, we should
+                                * fail out...
+                                *
+                                */
+                               lwsl_debug("%s: PEEKed 0 (from_pollin %d)\n",
+                                         __func__, from_pollin);
+                               if (!from_pollin)
+                                       /*
+                                        * If this wasn't actually info from a
+                                        * pollin let it go around again until
+                                        * either data came or we still get told
+                                        * zero length peek AND POLLIN
+                                        */
+                                       goto punt;
+
                                /*
-                                * connection is gone, fail out
+                                * treat as remote closed
                                 */
-                               lwsl_debug("PEEKed 0\n");
+
                                goto fail;
                        }
-                       if (n < 0 && (LWS_ERRNO == LWS_EAGAIN ||
+                       if (s < 0 && (LWS_ERRNO == LWS_EAGAIN ||
                                      LWS_ERRNO == LWS_EWOULDBLOCK)) {
+
+punt:
                                /*
                                 * well, we get no way to know ssl or not
                                 * so go around again waiting for something
@@ -367,7 +303,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                                 * connection.
                                 */
                                if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
-                                       lwsl_info("%s: change_pollfd failed\n",
+                                       lwsl_err("%s: change_pollfd failed\n",
                                                  __func__);
                                        return -1;
                                }
@@ -379,24 +315,17 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
 
                /* normal SSL connection processing path */
 
-#if defined(LWS_WITH_STATS)
-               /* only set this the first time around */
-               if (!wsi->accept_start_us)
-                       wsi->accept_start_us = lws_now_usecs();
-#endif
                errno = 0;
-               lws_stats_bump(pt, LWSSTATS_C_SSL_ACCEPT_SPIN, 1);
                n = lws_tls_server_accept(wsi);
-               lws_latency(context, wsi,
-                       "SSL_accept LRS_SSL_ACK_PENDING\n", n, n == 1);
                lwsl_info("SSL_accept says %d\n", n);
                switch (n) {
                case LWS_SSL_CAPABLE_DONE:
+                       lws_tls_restrict_return_handshake(wsi);
                        break;
                case LWS_SSL_CAPABLE_ERROR:
-                       lws_stats_bump(pt, LWSSTATS_C_SSL_CONNECTIONS_FAILED, 1);
-                       lwsl_info("SSL_accept failed socket %u: %d\n",
-                                       wsi->desc.sockfd, n);
+                       lws_tls_restrict_return_handshake(wsi);
+                       lwsl_info("%s: SSL_accept failed socket %u: %d\n",
+                                       __func__, wsi->desc.sockfd, n);
                        wsi->socket_is_permanently_unusable = 1;
                        goto fail;
 
@@ -404,16 +333,6 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
                        return 0;
                }
 
-               lws_stats_bump(pt, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, 1);
-#if defined(LWS_WITH_STATS)
-               if (wsi->accept_start_us)
-                       lws_stats_bump(pt,
-                                     LWSSTATS_US_SSL_ACCEPT_LATENCY_AVG,
-                                     lws_now_usecs() -
-                                             wsi->accept_start_us);
-               wsi->accept_start_us = lws_now_usecs();
-#endif
-
                /* adapt our vhost to match the SNI SSL_CTX that was chosen */
                vh = context->vhost_list;
                while (vh) {
@@ -428,11 +347,13 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
 
                /* OK, we are accepted... give him some time to negotiate */
                lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
-                               context->timeout_secs);
+                               (int)context->timeout_secs);
 
                lwsi_set_state(wsi, LRS_ESTABLISHED);
-               if (lws_tls_server_conn_alpn(wsi))
+               if (lws_tls_server_conn_alpn(wsi)) {
+                       lwsl_warn("%s: fail on alpn\n", __func__);
                        goto fail;
+               }
                lwsl_debug("accepted new SSL conn\n");
                break;
 
diff --git a/lib/tls/tls-sessions.c b/lib/tls/tls-sessions.c
new file mode 100644 (file)
index 0000000..b1e90aa
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "private-lib-core.h"
+
+void
+lws_tls_session_tag_discrete(const char *vhname, const char *host,
+                             uint16_t port, char *buf, size_t len)
+{
+       /*
+        * We have to include the vhost name in the session tag, since
+        * different vhosts may make connections to the same endpoint using
+        * different client certs.
+        */
+
+       lws_snprintf(buf, len, "%s_%s_%u", vhname, host, port);
+}
+
+int
+lws_tls_session_tag_from_wsi(struct lws *wsi, char *buf, size_t len)
+{
+       const char *host;
+
+       if (!wsi)
+               return 1;
+
+       if (!wsi->stash)
+               return 1;
+
+       host = wsi->stash->cis[CIS_HOST];
+       if (!host)
+               host = wsi->stash->cis[CIS_ADDRESS];
+
+       if (!host)
+               return 1;
+
+       lws_tls_session_tag_discrete(wsi->a.vhost->name, host, wsi->c_port,
+                                    buf, len);
+
+       return 0;
+}
+
+
index b21b26f..29a7a5d 100644 (file)
  *
  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
-#include "core/private.h"
-#include "tls/private.h"
+#include "private-lib-core.h"
+#include "private-lib-tls.h"
+
+#if defined(LWS_WITH_NETWORK)
+#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
+                                 OPENSSL_VERSION_NUMBER >= 0x10002000L)
+static int
+alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen,
+       const unsigned char *in, unsigned int inlen, void *arg)
+{
+#if !defined(LWS_WITH_MBEDTLS)
+       struct alpn_ctx *alpn_ctx = (struct alpn_ctx *)arg;
+
+       if (SSL_select_next_proto((unsigned char **)out, outlen, alpn_ctx->data,
+                                 alpn_ctx->len, in, inlen) !=
+           OPENSSL_NPN_NEGOTIATED)
+               return SSL_TLSEXT_ERR_NOACK;
+#endif
+
+       return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
+int
+lws_tls_restrict_borrow(struct lws *wsi)
+{
+       struct lws_context *cx = wsi->a.context;
+
+       if (cx->simultaneous_ssl_restriction &&
+           cx->simultaneous_ssl >= cx->simultaneous_ssl_restriction) {
+               lwsl_notice("%s: tls connection limit %d\n", __func__,
+                           cx->simultaneous_ssl);
+               return 1;
+       }
+
+       if (cx->simultaneous_ssl_handshake_restriction &&
+           cx->simultaneous_ssl_handshake >=
+                           cx->simultaneous_ssl_handshake_restriction) {
+               lwsl_notice("%s: tls handshake limit %d\n", __func__,
+                           cx->simultaneous_ssl);
+               return 1;
+       }
+
+       cx->simultaneous_ssl++;
+       cx->simultaneous_ssl_handshake++;
+       wsi->tls_borrowed_hs = 1;
+       wsi->tls_borrowed = 1;
+
+       lwsl_info("%s: %d -> %d\n", __func__,
+                 cx->simultaneous_ssl - 1,
+                 cx->simultaneous_ssl);
+
+       assert(!cx->simultaneous_ssl_restriction ||
+                       cx->simultaneous_ssl <=
+                               cx->simultaneous_ssl_restriction);
+       assert(!cx->simultaneous_ssl_handshake_restriction ||
+                       cx->simultaneous_ssl_handshake <=
+                               cx->simultaneous_ssl_handshake_restriction);
+
+#if defined(LWS_WITH_SERVER)
+       lws_gate_accepts(cx,
+                       (cx->simultaneous_ssl_restriction &&
+                        cx->simultaneous_ssl == cx->simultaneous_ssl_restriction) ||
+                       (cx->simultaneous_ssl_handshake_restriction &&
+                        cx->simultaneous_ssl_handshake == cx->simultaneous_ssl_handshake_restriction));
+#endif
+
+       return 0;
+}
+
+static void
+_lws_tls_restrict_return(struct lws *wsi)
+{
+#if defined(LWS_WITH_SERVER)
+       struct lws_context *cx = wsi->a.context;
+
+       assert(cx->simultaneous_ssl_handshake >= 0);
+       assert(cx->simultaneous_ssl >= 0);
+
+       lws_gate_accepts(cx,
+                       (cx->simultaneous_ssl_restriction &&
+                        cx->simultaneous_ssl == cx->simultaneous_ssl_restriction) ||
+                       (cx->simultaneous_ssl_handshake_restriction &&
+                        cx->simultaneous_ssl_handshake == cx->simultaneous_ssl_handshake_restriction));
+#endif
+}
+
+void
+lws_tls_restrict_return_handshake(struct lws *wsi)
+{
+       struct lws_context *cx = wsi->a.context;
+
+       /* we're just returning the hs part */
+
+       if (!wsi->tls_borrowed_hs)
+               return;
+
+       wsi->tls_borrowed_hs = 0; /* return it one time per wsi */
+       cx->simultaneous_ssl_handshake--;
+
+       lwsl_info("%s:  %d -> %d\n", __func__,
+                 cx->simultaneous_ssl_handshake + 1,
+                 cx->simultaneous_ssl_handshake);
+
+       _lws_tls_restrict_return(wsi);
+}
+
+void
+lws_tls_restrict_return(struct lws *wsi)
+{
+       struct lws_context *cx = wsi->a.context;
+
+       if (!wsi->tls_borrowed)
+               return;
+
+       wsi->tls_borrowed = 0;
+       cx->simultaneous_ssl--;
+
+       lwsl_info("%s: %d -> %d\n", __func__,
+                 cx->simultaneous_ssl + 1,
+                 cx->simultaneous_ssl);
+
+       /* We're returning everything, even if hs didn't complete */
+
+       if (wsi->tls_borrowed_hs)
+               lws_tls_restrict_return_handshake(wsi);
+       else
+               _lws_tls_restrict_return(wsi);
+}
+
+void
+lws_context_init_alpn(struct lws_vhost *vhost)
+{
+#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
+                                 OPENSSL_VERSION_NUMBER >= 0x10002000L)
+       const char *alpn_comma = vhost->context->tls.alpn_default;
+
+       if (vhost->tls.alpn)
+               alpn_comma = vhost->tls.alpn;
+
+       lwsl_info(" Server '%s' advertising ALPN: %s\n",
+                   vhost->name, alpn_comma);
+
+       vhost->tls.alpn_ctx.len = (uint8_t)lws_alpn_comma_to_openssl(alpn_comma,
+                                       vhost->tls.alpn_ctx.data,
+                                       sizeof(vhost->tls.alpn_ctx.data) - 1);
+
+       SSL_CTX_set_alpn_select_cb(vhost->tls.ssl_ctx, alpn_cb,
+                                  &vhost->tls.alpn_ctx);
+#else
+       lwsl_err(" HTTP2 / ALPN configured "
+                "but not supported by OpenSSL 0x%lx\n",
+                OPENSSL_VERSION_NUMBER);
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
+}
+
+int
+lws_tls_server_conn_alpn(struct lws *wsi)
+{
+#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
+                                 OPENSSL_VERSION_NUMBER >= 0x10002000L)
+       const unsigned char *name = NULL;
+       char cstr[10];
+       unsigned len;
+
+       lwsl_info("%s\n", __func__);
+
+       if (!wsi->tls.ssl) {
+               lwsl_err("%s: non-ssl\n", __func__);
+               return 0;
+       }
+
+       SSL_get0_alpn_selected(wsi->tls.ssl, &name, &len);
+       if (!len) {
+               lwsl_info("no ALPN upgrade\n");
+               return 0;
+       }
+
+       if (len > sizeof(cstr) - 1)
+               len = sizeof(cstr) - 1;
+
+       memcpy(cstr, name, len);
+       cstr[len] = '\0';
+
+       lwsl_info("%s: negotiated '%s' using ALPN\n", __func__, cstr);
+       wsi->tls.use_ssl |= LCCSCF_USE_SSL;
+
+       return lws_role_call_alpn_negotiated(wsi, (const char *)cstr);
+#else
+       lwsl_err("%s: openssl too old\n", __func__);
+#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
+
+       return 0;
+}
+#endif
 
 #if !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
-#if defined(LWS_WITH_ESP32) && !defined(LWS_AMAZON_RTOS)
+#if defined(LWS_PLAT_FREERTOS) && !defined(LWS_AMAZON_RTOS)
 int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
               lws_filepos_t *amount)
 {
@@ -63,6 +259,7 @@ int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
 {
        FILE *f;
        size_t s;
+       ssize_t m;
        int n = 0;
 
        f = fopen(filename, "rb");
@@ -76,18 +273,19 @@ int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
                goto bail;
        }
 
-       s = ftell(f);
-       if (s == (size_t)-1) {
+       m = (ssize_t)ftell(f);
+       if (m == -1l) {
                n = 1;
                goto bail;
        }
+       s = (size_t)m;
 
        if (fseek(f, 0, SEEK_SET) != 0) {
                n = 1;
                goto bail;
        }
 
-       *buf = lws_malloc(s, "alloc_file");
+       *buf = lws_malloc(s + 1, "alloc_file");
        if (!*buf) {
                n = 2;
                goto bail;
@@ -147,11 +345,11 @@ lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
 
                /* take it as being already DER */
 
-               pem = lws_malloc(inlen, "alloc_der");
+               pem = lws_malloc((size_t)inlen, "alloc_der");
                if (!pem)
                        return 1;
 
-               memcpy(pem, inbuf, inlen);
+               memcpy(pem, inbuf, (size_t)inlen);
 
                *buf = pem;
                *amount = inlen;
@@ -163,7 +361,7 @@ lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
 
        if (!filename) {
                /* we don't know if it's in const memory... alloc the output */
-               pem = lws_malloc((inlen * 3) / 4, "alloc_der");
+               pem = lws_malloc(((size_t)inlen * 3) / 4, "alloc_der");
                if (!pem) {
                        lwsl_err("a\n");
                        return 1;
@@ -179,7 +377,6 @@ lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
                p++;
 
        if (*p != '-') {
-               lwsl_err("b\n");
                goto bail;
        }
 
@@ -187,7 +384,6 @@ lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
                p++;
 
        if (p >= end) {
-               lwsl_err("c\n");
                goto bail;
        }
 
@@ -200,10 +396,8 @@ lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
        while (q > opem && *q != '\n')
                q--;
 
-       if (*q != '\n') {
-               lwsl_err("d\n");
+       if (*q != '\n')
                goto bail;
-       }
 
        /* we can't write into the input buffer for mem, since it may be in RO
         * const segment
@@ -211,7 +405,10 @@ lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
        if (filename)
                *q = '\0';
 
-       *amount = lws_b64_decode_string_len((char *)p, lws_ptr_diff(q, p),
+       n = lws_ptr_diff(q, p);
+       if (n == -1) /* coverity */
+               goto bail;
+       *amount = (unsigned int)lws_b64_decode_string_len((char *)p, n,
                                            (char *)pem, (int)(long long)len);
        *buf = (uint8_t *)pem;
 
@@ -226,15 +423,16 @@ bail:
 
 #endif
 
-#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
+#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE) && !defined(OPTEE_DEV_KIT)
 
 
 static int
 lws_tls_extant(const char *name)
 {
        /* it exists if we can open it... */
-       int fd = open(name, O_RDONLY), n;
+       int fd = open(name, O_RDONLY);
        char buf[1];
+       ssize_t n;
 
        if (fd < 0)
                return 1;
@@ -275,15 +473,15 @@ lws_tls_extant(const char *name)
  * 4) LWS_TLS_EXTANT_YES: The certs are present with the correct name and we
  *    have the rights to read them.
  */
-#if !defined(LWS_AMAZON_RTOS)
+
 enum lws_tls_extant
 lws_tls_use_any_upgrade_check_extant(const char *name)
 {
-#if !defined(LWS_PLAT_OPTEE)
+#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_AMAZON_RTOS)
 
        int n;
 
-#if !defined(LWS_WITH_ESP32)
+#if !defined(LWS_PLAT_FREERTOS)
        char buf[256];
 
        lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", name);
@@ -332,5 +530,3 @@ lws_tls_use_any_upgrade_check_extant(const char *name)
 #endif
        return LWS_TLS_EXTANT_YES;
 }
-#endif
-
index 4ad1012..013bda0 100644 (file)
@@ -28,7 +28,6 @@ INHERIT_DOCS           = YES
 SEPARATE_MEMBER_PAGES  = NO
 TAB_SIZE               = 8
 ALIASES                =
-TCL_SUBST              =
 OPTIMIZE_OUTPUT_FOR_C  = YES
 OPTIMIZE_OUTPUT_JAVA   = NO
 OPTIMIZE_FOR_FORTRAN   = NO
@@ -103,39 +102,61 @@ WARN_LOGFILE           =
 #---------------------------------------------------------------------------
 INPUT                  = include/libwebsockets.h \
                         include/libwebsockets/lws-adopt.h \
+                        include/libwebsockets/lws-async-dns.h \
+                        include/libwebsockets/lws-bb-i2c.h \
+                        include/libwebsockets/lws-bb-spi.h \
+                        include/libwebsockets/lws-button.h \
                         include/libwebsockets/lws-callbacks.h \
                         include/libwebsockets/lws-cgi.h \
                         include/libwebsockets/lws-client.h \
                         include/libwebsockets/lws-context-vhost.h \
                         include/libwebsockets/lws-dbus.h \
+                        include/libwebsockets/lws-detailed-latency.h \
                         include/libwebsockets/lws-diskcache.h \
+                        include/libwebsockets/lws-display.h \
+                        include/libwebsockets/lws-dll2.h \
                         include/libwebsockets/lws-dsh.h \
-                        include/libwebsockets/lws-esp32.h \
+                        include/libwebsockets/lws-eventlib-exports.h \
+                        include/libwebsockets/lws-freertos.h \
                         include/libwebsockets/lws-fts.h \
                         include/libwebsockets/lws-genaes.h \
                         include/libwebsockets/lws-gencrypto.h \
                         include/libwebsockets/lws-genec.h \
                         include/libwebsockets/lws-genhash.h \
                         include/libwebsockets/lws-genrsa.h \
+                        include/libwebsockets/lws-gpio.h \
                         include/libwebsockets/lws-http.h \
+                        include/libwebsockets/lws-i2c.h \
+                        include/libwebsockets/lws-ili9341-spi.h \
                         include/libwebsockets/lws-jose.h \
                         include/libwebsockets/lws-jwe.h \
                         include/libwebsockets/lws-jwk.h \
                         include/libwebsockets/lws-jws.h \
+                        include/libwebsockets/lws-led.h \
                         include/libwebsockets/lws-lejp.h \
                         include/libwebsockets/lws-logs.h \
                         include/libwebsockets/lws-lwsac.h \
                         include/libwebsockets/lws-misc.h \
+                        include/libwebsockets/lws-mqtt.h \
+                        include/libwebsockets/lws-netdev.h \
                         include/libwebsockets/lws-network-helper.h \
-                        include/libwebsockets/lws-plugin-generic-sessions.h \
                         include/libwebsockets/lws-protocols-plugins.h \
                         include/libwebsockets/lws-purify.h \
+                        include/libwebsockets/lws-pwm.h \
                         include/libwebsockets/lws-retry.h \
                         include/libwebsockets/lws-ring.h \
+                        include/libwebsockets/lws-secure-streams-client.h \
+                        include/libwebsockets/lws-secure-streams.h \
+                        include/libwebsockets/lws-secure-streams-policy.h \
                         include/libwebsockets/lws-sequencer.h \
                         include/libwebsockets/lws-service.h \
+                        include/libwebsockets/lws-settings.h \
                         include/libwebsockets/lws-sha1-base64.h \
+                        include/libwebsockets/lws-smd.h \
                         include/libwebsockets/lws-spa.h \
+                        include/libwebsockets/lws-spi.h \
+                        include/libwebsockets/lws-ssd1306-i2c.h \
+                        include/libwebsockets/lws-state.h \
                         include/libwebsockets/lws-stats.h \
                         include/libwebsockets/lws-struct.h \
                         include/libwebsockets/lws-system.h \
@@ -152,22 +173,23 @@ INPUT                  = include/libwebsockets.h \
                         include/libwebsockets/lws-x509.h \
                         plugins/ssh-base/include/lws-plugin-ssh.h \
                         ./READMEs/mainpage.md \
+                        ./READMEs/README.async-dns.md \
                         ./READMEs/README.build.md \
                         ./READMEs/README.ci.md \
                         ./READMEs/README.coding.md \
                         ./READMEs/README.content-security-policy.md \
                         ./READMEs/README.contributing.md \
                         ./READMEs/README.crypto-apis.md \
+                        ./READMEs/README.detailed-latency.md \
                         ./READMEs/README.esp32.md \
-                        ./READMEs/README.generic-sessions.md \
-                        ./READMEs/README.generic-table.md \
+                        ./READMEs/README.h2-long-poll.md \
                         ./READMEs/README.http-fallback.md \
                         ./READMEs/README.lws_dll.md \
                         ./READMEs/README.lws_sequencer.md \
                         ./READMEs/README.lws_struct.md \
                         ./READMEs/README.lws_sul.md \
                         ./READMEs/README.lwsws.md \
-                        ./READMEs/README.plugin-sshd-base.md \
+                        ./READMEs/README-plugin-sshd-base.md \
                         ./READMEs/README.plugin-acme.md \
                         ./READMEs/README.porting.md \
                         ./READMEs/README.problems.md \
@@ -219,7 +241,7 @@ HTML_FILE_EXTENSION    = .html
 HTML_HEADER            =
 HTML_FOOTER            =
 HTML_STYLESHEET        =
-HTML_EXTRA_STYLESHEET  =
+HTML_EXTRA_STYLESHEET  = scripts/dox-extra.css
 HTML_EXTRA_FILES       =
 HTML_COLORSTYLE_HUE    = 220
 HTML_COLORSTYLE_SAT    = 100
@@ -350,12 +372,10 @@ GENERATE_TAGFILE       =
 ALLEXTERNALS           = NO
 EXTERNAL_GROUPS        = YES
 EXTERNAL_PAGES         = YES
-PERL_PATH              = /usr/bin/perl
 #---------------------------------------------------------------------------
 # Configuration options related to the dot tool
 #---------------------------------------------------------------------------
 CLASS_DIAGRAMS         = YES
-MSCGEN_PATH            =
 DIA_PATH               =
 HIDE_UNDOC_RELATIONS   = YES
 HAVE_DOT               = NO
diff --git a/lwsws/CMakeLists.txt b/lwsws/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5446672
--- /dev/null
@@ -0,0 +1,68 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+if (LWS_WITH_LWSWS)
+       list(APPEND LWSWS_SRCS
+               "main.c"
+       )
+
+       if (WIN32)
+               list(APPEND LWSWS_SRCS
+                       ${WIN32_HELPERS_PATH}/getopt.c
+                       ${WIN32_HELPERS_PATH}/getopt_long.c
+                       ${WIN32_HELPERS_PATH}/gettimeofday.c
+               )
+
+               list(APPEND LWSWS_HDR
+                       ${WIN32_HELPERS_PATH}/getopt.h
+                       ${WIN32_HELPERS_PATH}/gettimeofday.h
+               )
+       endif(WIN32)
+
+       source_group("Headers Private"   FILES ${LWSWS_HDR})
+       source_group("Sources"   FILES ${LWSWS_SRCS})
+       add_executable(lwsws ${LWSWS_SRCS} ${LWSWS_HDR})
+
+       if (LWS_WITH_SHARED)
+               target_link_libraries(lwsws websockets_shared ${LIB_LIST_AT_END})
+               add_dependencies(lwsws websockets_shared)
+       else()
+               target_link_libraries(lwsws websockets ${LIB_LIST_AT_END})
+               add_dependencies(lwsws websockets)
+       endif()
+       target_include_directories(lwsws PRIVATE "${LWS_LIB_INCLUDES}" ${LWS_LIB_BUILD_INC_PATHS})
+       # Set test app specific defines.
+       set_property(TARGET lwsws
+                    PROPERTY COMPILE_DEFINITIONS
+                    INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
+       )
+
+       install(TARGETS lwsws
+               RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT lwsws )
+       target_compile_definitions(lwsws PRIVATE LWS_BUILDING_SHARED)
+
+
+endif (LWS_WITH_LWSWS)
+
+
index f74d803..eb19a04 100644 (file)
@@ -57,14 +57,14 @@ int fork(void)
 
 static struct lws_context *context;
 static lws_sorted_usec_list_t sul_lwsws;
-static char config_dir[128];
+static char config_dir[128], default_plugin_path = 1;
 static int opts = 0, do_reload = 1;
 static uv_loop_t loop;
 static uv_signal_t signal_outer[2];
 static int pids[32];
 void lwsl_emit_stderr(int level, const char *line);
 
-#define LWSWS_CONFIG_STRING_SIZE (32 * 1024)
+#define LWSWS_CONFIG_STRING_SIZE (64 * 1024)
 
 static const struct lws_extension exts[] = {
 #if !defined(LWS_WITHOUT_EXTENSIONS)
@@ -77,16 +77,19 @@ static const struct lws_extension exts[] = {
        { NULL, NULL, NULL /* terminator */ }
 };
 
+#if defined(LWS_WITH_PLUGINS)
 static const char * const plugin_dirs[] = {
        INSTALL_DATADIR"/libwebsockets-test-server/plugins/",
        NULL
 };
+#endif
 
 #if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)
 static struct option options[] = {
        { "help",       no_argument,            NULL, 'h' },
        { "debug",      required_argument,      NULL, 'd' },
        { "configdir",  required_argument,      NULL, 'c' },
+       { "no-default-plugins",  no_argument,   NULL, 'n' },
        { NULL, 0, 0, 0 }
 };
 #endif
@@ -146,11 +149,14 @@ context_creation(void)
 
        info.external_baggage_free_on_destroy = config_strings;
        info.pt_serv_buf_size = 8192;
-       info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 |
+       info.options = (uint64_t)((uint64_t)opts | LWS_SERVER_OPTION_VALIDATE_UTF8 |
                              LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
-                             LWS_SERVER_OPTION_LIBUV;
+                             LWS_SERVER_OPTION_LIBUV);
 
-       info.plugin_dirs = plugin_dirs;
+#if defined(LWS_WITH_PLUGINS)
+       if (default_plugin_path)
+               info.plugin_dirs = plugin_dirs;
+#endif
        lwsl_notice("Using config dir: \"%s\"\n", config_dir);
 
        /*
@@ -216,7 +222,7 @@ reload_handler(int signum)
        case SIGINT:
        case SIGTERM:
        case SIGKILL:
-               fprintf(stderr, "master process waiting 2s...\n");
+               fprintf(stderr, "parent process waiting 2s...\n");
                sleep(2); /* give children a chance to deal with the signal */
                fprintf(stderr, "killing service processes\n");
                for (m = 0; m < (int)LWS_ARRAY_SIZE(pids); m++)
@@ -240,9 +246,9 @@ int main(int argc, char **argv)
        strcpy(config_dir, "/etc/lwsws");
        while (n >= 0) {
 #if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)
-               n = getopt_long(argc, argv, "hd:c:", options, NULL);
+               n = getopt_long(argc, argv, "hd:c:n", options, NULL);
 #else
-               n = getopt(argc, argv, "hd:c:");
+               n = getopt(argc, argv, "hd:c:n");
 #endif
                if (n < 0)
                        continue;
@@ -250,12 +256,16 @@ int main(int argc, char **argv)
                case 'd':
                        debug_level = atoi(optarg);
                        break;
+               case 'n':
+                       default_plugin_path = 0;
+                       break;
                case 'c':
                        lws_strncpy(config_dir, optarg, sizeof(config_dir));
                        break;
                case 'h':
                        fprintf(stderr, "Usage: lwsws [-c <config dir>] "
-                                       "[-d <log bitfield>] [--help]\n");
+                                       "[-d <log bitfield>] [--help] "
+                                       "[-n]\n");
                        exit(1);
                }
        }
@@ -271,7 +281,7 @@ int main(int argc, char **argv)
        signal(SIGHUP, reload_handler);
        signal(SIGINT, reload_handler);
 
-       fprintf(stderr, "Root process is %u\n", getpid());
+       fprintf(stderr, "Root process is %u\n", (unsigned int)getpid());
 
        while (1) {
                if (do_reload) {
@@ -335,7 +345,7 @@ int main(int argc, char **argv)
        }
 
        /* cancel the per-minute sul */
-       lws_sul_schedule(context, 0, &sul_lwsws, NULL, LWS_SET_TIMER_USEC_CANCEL);
+       lws_sul_cancel(&sul_lwsws);
 
        lws_context_destroy(context);
        (void)budget;
diff --git a/minimal-examples/CMakeLists.txt b/minimal-examples/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8591c2e
--- /dev/null
@@ -0,0 +1,50 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+MACRO(SUBDIRLIST result curdir)
+  FILE(GLOB children RELATIVE ${curdir} ${curdir}/*)
+  SET(dirlist "")
+
+  FOREACH(child ${children})
+    IF (IS_DIRECTORY ${curdir}/${child})
+       LIST(APPEND dirlist ${child})
+    ENDIF()
+  ENDFOREACH()
+
+  SET(${result} ${dirlist})
+ENDMACRO()
+
+include_directories(${LWS_LIB_BUILD_INC_PATHS})
+link_libraries(${LIB_LIST_AT_END})
+
+SUBDIRLIST(SUBDIRS "${PROJECT_SOURCE_DIR}/minimal-examples")
+FOREACH(subdir ${SUBDIRS})
+
+       SUBDIRLIST(SUBDIRS2 "${PROJECT_SOURCE_DIR}/minimal-examples/${subdir}")
+       FOREACH(subdir2 ${SUBDIRS2})
+               if (EXISTS "${PROJECT_SOURCE_DIR}/minimal-examples/${subdir}/${subdir2}/CMakeLists.txt")
+                       message("Processing ${PROJECT_SOURCE_DIR}/minimal-examples/${subdir}/${subdir2}")
+                       add_subdirectory("${PROJECT_SOURCE_DIR}/minimal-examples/${subdir}/${subdir2}")
+               endif()
+       ENDFOREACH()
+ENDFOREACH()
index 2f271db..956256d 100644 (file)
@@ -6,6 +6,7 @@ dbus-server|Minimal examples showing how to integrate DBUS into lws event loop
 http-client|Minimal examples providing an http client
 http-server|Minimal examples providing an http server
 raw|Minimal examples related to adopting raw file or socket descriptors into the event loop
+secure-streams|Minimal examples related to the Secure Streams client api
 ws-client|Minimal examples providing a ws client
 ws-server|Minimal examples providing a ws server (and an http server)
 
index 43f4246..5264313 100644 (file)
@@ -1,66 +1,13 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-api-test-smtp_client C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-api-test-smtp_client)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_SMTP 1 requirements)
 
@@ -68,9 +15,9 @@ if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 11d6b20..d21c4ea 100644 (file)
@@ -21,12 +21,14 @@ sigint_handler(int sig)
 }
 
 static int
-email_sent_or_failed(struct lws_smtp_email *email, void *buf, size_t len)
+done_cb(struct lws_smtp_email *email, void *buf, size_t len)
 {
        /* you could examine email->data here */
-       if (buf)
-               lwsl_notice("%s: %.*s\n", __func__, (int)len, (const char *)buf);
-       else
+       if (buf) {
+               char dotstar[96];
+               lws_strnncpy(dotstar, (const char *)buf, len, sizeof(dotstar));
+               lwsl_notice("%s: %s\n", __func__, dotstar);
+       } else
                lwsl_notice("%s:\n", __func__);
 
        /* destroy any allocations in email */
@@ -39,39 +41,16 @@ email_sent_or_failed(struct lws_smtp_email *email, void *buf, size_t len)
        return 0;
 }
 
-/*
- * We're going to bind to the raw-skt transport, so tell that what we want it
- * to connect to
- */
-
-static const lws_token_map_t smtp_raw_skt_transport_tokens[] = {
- {
-       .u = { .value = "127.0.0.1" },
-       .name_index = LTMI_PEER_V_DNS_ADDRESS,
- }, {
-       .u = { .lvalue = 25 },
-       .name_index = LTMI_PEER_LV_PORT,
- }, {
- }
-};
-
-static const lws_token_map_t smtp_protocol_tokens[] = {
- {
-       .u = { .value = "lws-test-client" },
-       .name_index = LTMI_PSMTP_V_HELO,
- }, {
- }
-};
-
-
 int main(int argc, const char **argv)
 {
        int n = 1, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
        struct lws_context_creation_info info;
+       lws_smtp_sequencer_args_t ss_args;
        struct lws_context *context;
-       lws_abs_t abs, *instance;
-       lws_smtp_email_t email;
+       lws_smtp_sequencer_t *sseq;
+       lws_smtp_email_t *email;
        struct lws_vhost *vh;
+       char payload[2048];
        const char *p;
 
        /* the normal lws init */
@@ -107,56 +86,30 @@ int main(int argc, const char **argv)
                goto bail1;
        }
 
-       /*
-        * create an smtp client that's hooked up to real sockets
-        */
+       memset(&ss_args, 0, sizeof(ss_args));
+       ss_args.helo = "lws-abs-smtp-test";
+       ss_args.vhost = vh;
 
-       memset(&abs, 0, sizeof(abs));
-       abs.vh = vh;
-
-       /* select the protocol and bind its tokens */
-
-       abs.ap = lws_abs_protocol_get_by_name("smtp");
-       if (!abs.ap)
-               goto bail1;
-       abs.ap_tokens = smtp_protocol_tokens;
-
-       /* select the transport and bind its tokens */
-
-       abs.at = lws_abs_transport_get_by_name("raw_skt");
-       if (!abs.at)
-               goto bail1;
-       abs.at_tokens = smtp_raw_skt_transport_tokens;
-
-       instance = lws_abs_bind_and_create_instance(&abs);
-       if (!instance) {
-               lwsl_err("%s: failed to create SMTP client\n", __func__);
+       sseq = lws_smtp_sequencer_create(&ss_args);
+       if (!sseq) {
+               lwsl_err("%s: smtp sequencer create failed\n", __func__);
                goto bail1;
        }
 
        /* attach an email to it */
 
-       memset(&email, 0, sizeof(email));
-       email.data = NULL /* email specific user data */;
-       email.email_from = "andy@warmcat.com";
-       email.email_to = recip;
-       email.payload = malloc(2048);
-       if (!email.payload) {
-               goto bail1;
-       }
-
-       lws_snprintf((char *)email.payload, 2048,
+       n = lws_snprintf(payload, sizeof(payload),
                        "From: noreply@example.com\n"
                        "To: %s\n"
                        "Subject: Test email for lws smtp-client\n"
                        "\n"
                        "Hello this was an api test for lws smtp-client\n"
                        "\r\n.\r\n", recip);
-       email.done = email_sent_or_failed;
 
-       if (lws_smtp_client_add_email(instance, &email)) {
+       if (lws_smtpc_add_email(sseq, payload, n, "testserver",
+                               "andy@warmcat.com", recip, NULL, done_cb)) {
                lwsl_err("%s: failed to add email\n", __func__);
-               goto bail;
+               goto bail1;
        }
 
        /* the usual lws event loop */
@@ -164,8 +117,6 @@ int main(int argc, const char **argv)
        while (n >= 0 && !interrupted)
                n = lws_service(context, 0);
 
-bail:
-
 bail1:
        lwsl_user("Completed: %s\n", result ? "FAIL" : "PASS");
 
diff --git a/minimal-examples/api-tests/api-test-async-dns/CMakeLists.txt b/minimal-examples/api-tests/api-test-async-dns/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f2954d0
--- /dev/null
@@ -0,0 +1,26 @@
+project(lws-api-test-async-dns C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+
+set(SAMP lws-api-test-async-dns)
+set(SRCS main.c)
+
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SYS_ASYNC_DNS 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+       add_test(NAME api-test-async-dns COMMAND lws-api-test-async-dns)
+       set_tests_properties(api-test-async-dns
+                            PROPERTIES
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/api-tests/api-test-async-dns
+                            TIMEOUT 60)
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/api-tests/api-test-async-dns/main.c b/minimal-examples/api-tests/api-test-async-dns/main.c
new file mode 100644 (file)
index 0000000..4af79d3
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * lws-api-test-async-dns
+ *
+ * Written in 2019 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This api test confirms various kinds of async dns apis
+ */
+
+#include <libwebsockets.h>
+#include <signal.h>
+
+static int interrupted, dtest, ok, fail, _exp = 26;
+struct lws_context *context;
+
+/*
+ * These are used to test the apis to parse and print ipv4 / ipv6 literal
+ * address strings for various cases.
+ *
+ * Expected error cases are not used to test the ip data -> string api.
+ */
+
+static const struct ipparser_tests {
+       const char      *test;
+       int             rlen;
+       const char      *emit_test;
+       int             emit_len;
+       uint8_t         b[16];
+} ipt[] = {
+       { "2001:db8:85a3:0:0:8a2e:370:7334", 16,
+         "2001:db8:85a3::8a2e:370:7334", 28,
+               { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00,
+                 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 } },
+
+       { "2001:db8:85a3::8a2e:370:7334", 16,
+         "2001:db8:85a3::8a2e:370:7334", 28,
+               { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00,
+                 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 } },
+
+       { "::1", 16, "::1", 3,
+                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
+
+       { "::",  16, "::", 2,
+                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+
+       { "::ffff:192.0.2.128", 16,  "::ffff:192.0.2.128", 18,
+               { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x02, 0x80 } },
+
+       { "cats", -1, "", 0,
+                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
+
+       { "onevalid.bogus.warmcat.com", -1, "", 0,
+                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
+
+       { "1.cat.dog.com", -1, "", 0,
+                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
+
+       { ":::1", -8, "", 0,
+                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
+
+       { "0:0::0:1", 16, "::1", 3,
+                       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
+
+       { "1.2.3.4", 4, "1.2.3.4", 7, { 1, 2, 3, 4 } },
+};
+
+static const struct async_dns_tests {
+       const char *dns_name;
+       int recordtype;
+       int addrlen;
+       uint8_t ads[16];
+} adt[] = {
+       { "warmcat.com", LWS_ADNS_RECORD_A, 4,
+               { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
+       { "libwebsockets.org", LWS_ADNS_RECORD_A, 4,
+               { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
+       { "doesntexist", LWS_ADNS_RECORD_A, 0,
+               { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
+       { "localhost", LWS_ADNS_RECORD_A, 4,
+               { 127, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
+       { "ipv4only.warmcat.com", LWS_ADNS_RECORD_A, 4,
+               { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
+       { "onevalid.bogus.warmcat.com", LWS_ADNS_RECORD_A, 4,
+               { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
+#if defined(LWS_WITH_IPV6)
+       { "warmcat.com", LWS_ADNS_RECORD_AAAA, 16, /* check ipv6 */
+               { 0x20, 0x01, 0x41, 0xd0, 0x00, 0x02, 0xee, 0x93,
+                               0, 0, 0, 0, 0, 0, 0, 1, } },
+       { "ipv6only.warmcat.com", LWS_ADNS_RECORD_AAAA, 16, /* check ipv6 */
+               { 0x20, 0x01, 0x41, 0xd0, 0x00, 0x02, 0xee, 0x93,
+                               0, 0, 0, 0, 0, 0, 0, 1, } },
+#endif
+};
+
+static lws_sorted_usec_list_t sul;
+
+struct lws *
+cb1(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n,
+    void *opaque);
+
+static void
+next_test_cb(lws_sorted_usec_list_t *sul)
+{
+       int m;
+
+       lwsl_notice("%s: querying %s\n", __func__, adt[dtest].dns_name);
+
+       m = lws_async_dns_query(context, 0,
+                               adt[dtest].dns_name,
+                               (adns_query_type_t)adt[dtest].recordtype, cb1, NULL,
+                               context);
+       if (m != LADNS_RET_CONTINUING && m != LADNS_RET_FOUND && m != LADNS_RET_FAILED_WSI_CLOSED) {
+               lwsl_err("%s: adns 1: %s failed: %d\n", __func__, adt[dtest].dns_name, m);
+               interrupted = 1;
+       }
+}
+
+struct lws *
+cb1(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n,
+    void *opaque)
+{
+       const struct addrinfo *ac = a;
+       int ctr = 0, alen;
+       uint8_t *addr;
+       char buf[64];
+
+       dtest++;
+
+       if (!ac)
+               lwsl_warn("%s: no results\n", __func__);
+
+       /* dump the results */
+
+       while (ac) {
+               if (ac->ai_family == AF_INET) {
+                       addr = (uint8_t *)&(((struct sockaddr_in *)
+                                       ac->ai_addr)->sin_addr.s_addr);
+                       alen = 4;
+               } else {
+                       addr = (uint8_t *)&(((struct sockaddr_in6 *)
+                                       ac->ai_addr)->sin6_addr.s6_addr);
+                       alen = 16;
+               }
+               strcpy(buf, "unknown");
+               lws_write_numeric_address(addr, alen, buf, sizeof(buf));
+
+               lwsl_warn("%s: %d: %s %d %s\n", __func__, ctr++, ads, alen, buf);
+
+               ac = ac->ai_next;
+       }
+
+       ac = a;
+       while (ac) {
+               if (ac->ai_family == AF_INET) {
+                       addr = (uint8_t *)&(((struct sockaddr_in *)
+                                       ac->ai_addr)->sin_addr.s_addr);
+                       alen = 4;
+               } else {
+#if defined(LWS_WITH_IPV6)
+                       addr = (uint8_t *)&(((struct sockaddr_in6 *)
+                                       ac->ai_addr)->sin6_addr.s6_addr);
+                       alen = 16;
+#else
+                       goto again;
+#endif
+               }
+               if (alen == adt[dtest - 1].addrlen &&
+                   !memcmp(adt[dtest - 1].ads, addr, (unsigned int)alen)) {
+                       ok++;
+                       goto next;
+               }
+#if !defined(LWS_WITH_IPV6)
+again:
+#endif
+               ac = ac->ai_next;
+       }
+
+       /* testing for NXDOMAIN? */
+
+       if (!a && !adt[dtest - 1].addrlen) {
+               ok++;
+               goto next;
+       }
+
+       lwsl_err("%s: dns test %d: no match\n", __func__, dtest);
+       fail++;
+
+next:
+       lws_async_dns_freeaddrinfo(&a);
+       if (dtest == (int)LWS_ARRAY_SIZE(adt))
+               interrupted = 1;
+       else
+               lws_sul_schedule(context, 0, &sul, next_test_cb, 1);
+
+       return NULL;
+}
+
+static lws_sorted_usec_list_t sul_l;
+
+struct lws *
+cb_loop(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n,
+               void *opaque)
+{
+       if (!a) {
+               lwsl_err("%s: no results\n", __func__);
+               return NULL;
+       }
+
+       lwsl_notice("%s: addrinfo %p\n", __func__, a);\
+       lws_async_dns_freeaddrinfo(&a);
+
+       return NULL;
+}
+
+
+static void
+sul_retry_l(struct lws_sorted_usec_list *sul)
+{
+       int m;
+
+       lwsl_user("%s: starting new query\n", __func__);
+
+       m = lws_async_dns_query(context, 0, "warmcat.com",
+                                   (adns_query_type_t)LWS_ADNS_RECORD_A,
+                                   cb_loop, NULL, context);
+       switch (m) {
+       case LADNS_RET_FAILED_WSI_CLOSED:
+               lwsl_warn("%s: LADNS_RET_FAILED_WSI_CLOSED "
+                         "(== from cache / success in this test)\n", __func__);
+               break;
+       case LADNS_RET_NXDOMAIN:
+               lwsl_warn("%s: LADNS_RET_NXDOMAIN\n", __func__);
+               break;
+       case LADNS_RET_TIMEDOUT:
+               lwsl_warn("%s: LADNS_RET_TIMEDOUT\n", __func__);
+               break;
+       case LADNS_RET_FAILED:
+               lwsl_warn("%s: LADNS_RET_FAILED\n", __func__);
+               break;
+       case LADNS_RET_FOUND:
+               lwsl_warn("%s: LADNS_RET_FOUND\n", __func__);
+               break;
+       case LADNS_RET_CONTINUING:
+               lwsl_warn("%s: LADNS_RET_CONTINUING\n", __func__);
+               break;
+       }
+
+       lws_sul_schedule(context, 0, &sul_l, sul_retry_l, 5 * LWS_US_PER_SEC);
+}
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int
+main(int argc, const char **argv)
+{
+       int n = 1, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       struct lws_context_creation_info info;
+       const char *p;
+
+       /* the normal lws init */
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS API selftest: Async DNS\n");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       if (lws_cmdline_option(argc, argv, "-l")) {
+               lws_sul_schedule(context, 0, &sul_l, sul_retry_l, LWS_US_PER_SEC);
+               goto evloop;
+       }
+
+
+       /* ip address parser tests */
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(ipt); n++) {
+               uint8_t u[16];
+               int m = lws_parse_numeric_address(ipt[n].test, u, sizeof(u));
+
+               if (m != ipt[n].rlen) {
+                       lwsl_err("%s: fail %s ret %d\n",
+                                       __func__, ipt[n].test, m);
+                       fail++;
+                       continue;
+               }
+
+               if (m > 0) {
+                       if (memcmp(ipt[n].b, u, (unsigned int)m)) {
+                               lwsl_err("%s: fail %s compare\n", __func__,
+                                               ipt[n].test);
+                               lwsl_hexdump_notice(u, (unsigned int)m);
+                               fail++;
+                               continue;
+                       }
+               }
+               ok++;
+       }
+
+       /* ip address formatter tests */
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(ipt); n++) {
+               char buf[64];
+               int m;
+
+               /* don't attempt to reverse the ones that are meant to fail */
+               if (ipt[n].rlen < 0)
+                       continue;
+
+               m = lws_write_numeric_address(ipt[n].b, ipt[n].rlen, buf,
+                                               sizeof(buf));
+               if (m != ipt[n].emit_len) {
+                       lwsl_err("%s: fail %s ret %d\n",
+                                       __func__, ipt[n].emit_test, m);
+                       fail++;
+                       continue;
+               }
+
+               if (m > 0) {
+                       if (strcmp(ipt[n].emit_test, buf)) {
+                               lwsl_err("%s: fail %s compare\n", __func__,
+                                               ipt[n].test);
+                               lwsl_hexdump_notice(buf, (unsigned int)m);
+                               fail++;
+                               continue;
+                       }
+               }
+               ok++;
+       }
+
+#if !defined(LWS_WITH_IPV6)
+       _exp -= 2;
+#endif
+
+       /* kick off the async dns tests */
+
+       lws_sul_schedule(context, 0, &sul, next_test_cb, 1);
+
+evloop:
+       /* the usual lws event loop */
+
+       n = 1;
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       if (fail || ok != _exp)
+               lwsl_user("Completed: PASS: %d / %d, FAIL: %d\n", ok, _exp,
+                               fail);
+       else
+               lwsl_user("Completed: ALL PASS: %d / %d\n", ok, _exp);
+
+       return !(ok == _exp && !fail);
+}
diff --git a/minimal-examples/api-tests/api-test-cose/CMakeLists.txt b/minimal-examples/api-tests/api-test-cose/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bd6b142
--- /dev/null
@@ -0,0 +1,29 @@
+project(lws-api-test-cose C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-api-test-cose)
+set(SRCS main.c keys.c sign.c)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_COSE 1 requirements)
+require_lws_config(LWS_WITH_CBOR 1 requirements)
+
+if (requirements)
+
+       add_executable(${SAMP} ${SRCS})
+
+       if (NOT (LWS_WITH_MBEDTLS AND NOT LWS_HAVE_mbedtls_internal_aes_encrypt))
+               add_test(NAME api-test-cose COMMAND lws-api-test-cose)
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/api-tests/api-test-cose/README.md b/minimal-examples/api-tests/api-test-cose/README.md
new file mode 100644 (file)
index 0000000..74034c7
--- /dev/null
@@ -0,0 +1,22 @@
+# lws api test lwsac
+
+Demonstrates how to use and performs selftests for lwsac
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+ $ ./lws-api-test-lwsac
+[2018/10/09 09:14:17:4834] USER: LWS API selftest: lwsac
+[2018/10/09 09:14:17:4835] USER: Completed: PASS
+```
+
diff --git a/minimal-examples/api-tests/api-test-cose/keys.c b/minimal-examples/api-tests/api-test-cose/keys.c
new file mode 100644 (file)
index 0000000..134784d
--- /dev/null
@@ -0,0 +1,931 @@
+/*
+ * lws-api-test-jose - RFC8152 cose_key tests
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * Raw key CBOR created from descriptions at
+ *
+ * https://github.com/cose-wg/Examples/blob/master/KeySet.txt
+ */
+
+#include <libwebsockets.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+static int
+key_import_cb(struct lws_cose_key *s, void *user)
+{
+       lwsl_notice("%s: key type %lld\n", __func__, (long long)s->kty);
+
+       return 0;
+}
+
+static const uint8_t
+       cose_key1[] = {
+                       0xa6, 0x01, 0x02, 0x02, 0x62,
+                       0x31, 0x31, 0x20, 0x01, 0x21,
+                       0x58, 0x20, 0xba, 0xc5, 0xb1,
+                       0x1c, 0xad, 0x8f, 0x99, 0xf9,
+                       0xc7, 0x2b, 0x05, 0xcf, 0x4b,
+                       0x9e, 0x26, 0xd2, 0x44, 0xdc,
+                       0x18, 0x9f, 0x74, 0x52, 0x28,
+                       0x25, 0x5a, 0x21, 0x9a, 0x86,
+                       0xd6, 0xa0, 0x9e, 0xff, 0x22,
+                       0x58, 0x20, 0x20, 0x13, 0x8b,
+                       0xf8, 0x2d, 0xc1, 0xb6, 0xd5,
+                       0x62, 0xbe, 0x0f, 0xa5, 0x4a,
+                       0xb7, 0x80, 0x4a, 0x3a, 0x64,
+                       0xb6, 0xd7, 0x2c, 0xcf, 0xed,
+                       0x6b, 0x6f, 0xb6, 0xed, 0x28,
+                       0xbb, 0xfc, 0x11, 0x7e, 0x23,
+                       0x58, 0x20, 0x57, 0xc9, 0x20,
+                       0x77, 0x66, 0x41, 0x46, 0xe8,
+                       0x76, 0x76, 0x0c, 0x95, 0x20,
+                       0xd0, 0x54, 0xaa, 0x93, 0xc3,
+                       0xaf, 0xb0, 0x4e, 0x30, 0x67,
+                       0x05, 0xdb, 0x60, 0x90, 0x30,
+                       0x85, 0x07, 0xb4, 0xd3 },
+       cose_key2[] = {
+                       0xa6, 0x01, 0x02, 0x02, 0x78,
+                       0x24, 0x6d, 0x65, 0x72, 0x69,
+                       0x61, 0x64, 0x6f, 0x63, 0x2e,
+                       0x62, 0x72, 0x61, 0x6e, 0x64,
+                       0x79, 0x62, 0x75, 0x63, 0x6b,
+                       0x40, 0x62, 0x75, 0x63, 0x6b,
+                       0x6c, 0x61, 0x6e, 0x64, 0x2e,
+                       0x65, 0x78, 0x61, 0x6d, 0x70,
+                       0x6c, 0x65, 0x20, 0x01, 0x21,
+                       0x58, 0x20, 0x65, 0xed, 0xa5,
+                       0xa1, 0x25, 0x77, 0xc2, 0xba,
+                       0xe8, 0x29, 0x43, 0x7f, 0xe3,
+                       0x38, 0x70, 0x1a, 0x10, 0xaa,
+                       0xa3, 0x75, 0xe1, 0xbb, 0x5b,
+                       0x5d, 0xe1, 0x08, 0xde, 0x43,
+                       0x9c, 0x08, 0x55, 0x1d, 0x22,
+                       0x58, 0x20, 0x1e, 0x52, 0xed,
+                       0x75, 0x70, 0x11, 0x63, 0xf7,
+                       0xf9, 0xe4, 0x0d, 0xdf, 0x9f,
+                       0x34, 0x1b, 0x3d, 0xc9, 0xba,
+                       0x86, 0x0a, 0xf7, 0xe0, 0xca,
+                       0x7c, 0xa7, 0xe9, 0xee, 0xcd,
+                       0x00, 0x84, 0xd1, 0x9c, 0x23,
+                       0x58, 0x20, 0xaf, 0xf9, 0x07,
+                       0xc9, 0x9f, 0x9a, 0xd3, 0xaa,
+                       0xe6, 0xc4, 0xcd, 0xf2, 0x11,
+                       0x22, 0xbc, 0xe2, 0xbd, 0x68,
+                       0xb5, 0x28, 0x3e, 0x69, 0x07,
+                       0x15, 0x4a, 0xd9, 0x11, 0x84,
+                       0x0f, 0xa2, 0x08, 0xcf },
+
+       cose_key3[] = { 0xa3, 0x01, 0x04, 0x02, 0x6a,
+                       0x6f, 0x75, 0x72, 0x2d, 0x73,
+                       0x65, 0x63, 0x72, 0x65, 0x74,
+                       0x20, 0x58, 0x20, 0x84, 0x9b,
+                       0x57, 0x21, 0x9d, 0xae, 0x48,
+                       0xde, 0x64, 0x6d, 0x07, 0xdb,
+                       0xb5, 0x33, 0x56, 0x6e, 0x97,
+                       0x66, 0x86, 0x45, 0x7c, 0x14,
+                       0x91, 0xbe, 0x3a, 0x76, 0xdc,
+                       0xea, 0x6c, 0x42, 0x71, 0x88 },
+
+       cose_key4[] = { 0xa6, 0x01, 0x02, 0x02, 0x78,
+                       0x1e, 0x62, 0x69, 0x6c, 0x62,
+                       0x6f, 0x2e, 0x62, 0x61, 0x67,
+                       0x67, 0x69, 0x6e, 0x73, 0x40,
+                       0x68, 0x6f, 0x62, 0x62, 0x69,
+                       0x74, 0x6f, 0x6e, 0x2e, 0x65,
+                       0x78, 0x61, 0x6d, 0x70, 0x6c,
+                       0x65, 0x20, 0x03, 0x21, 0x58,
+                       0x42, 0x00, 0x72, 0x99, 0x2c,
+                       0xb3, 0xac, 0x08, 0xec, 0xf3,
+                       0xe5, 0xc6, 0x3d, 0xed, 0xec,
+                       0x0d, 0x51, 0xa8, 0xc1, 0xf7,
+                       0x9e, 0xf2, 0xf8, 0x2f, 0x94,
+                       0xf3, 0xc7, 0x37, 0xbf, 0x5d,
+                       0xe7, 0x98, 0x66, 0x71, 0xea,
+                       0xc6, 0x25, 0xfe, 0x82, 0x57,
+                       0xbb, 0xd0, 0x39, 0x46, 0x44,
+                       0xca, 0xaa, 0x3a, 0xaf, 0x8f,
+                       0x27, 0xa4, 0x58, 0x5f, 0xbb,
+                       0xca, 0xd0, 0xf2, 0x45, 0x76,
+                       0x20, 0x08, 0x5e, 0x5c, 0x8f,
+                       0x42, 0xad, 0x22, 0x58, 0x42,
+                       0x01, 0xdc, 0xa6, 0x94, 0x7b,
+                       0xce, 0x88, 0xbc, 0x57, 0x90,
+                       0x48, 0x5a, 0xc9, 0x74, 0x27,
+                       0x34, 0x2b, 0xc3, 0x5f, 0x88,
+                       0x7d, 0x86, 0xd6, 0x5a, 0x08,
+                       0x93, 0x77, 0xe2, 0x47, 0xe6,
+                       0x0b, 0xaa, 0x55, 0xe4, 0xe8,
+                       0x50, 0x1e, 0x2a, 0xda, 0x57,
+                       0x24, 0xac, 0x51, 0xd6, 0x90,
+                       0x90, 0x08, 0x03, 0x3e, 0xbc,
+                       0x10, 0xac, 0x99, 0x9b, 0x9d,
+                       0x7f, 0x5c, 0xc2, 0x51, 0x9f,
+                       0x3f, 0xe1, 0xea, 0x1d, 0x94,
+                       0x75, 0x23, 0x58, 0x42, 0x00,
+                       0x08, 0x51, 0x38, 0xdd, 0xab,
+                       0xf5, 0xca, 0x97, 0x5f, 0x58,
+                       0x60, 0xf9, 0x1a, 0x08, 0xe9,
+                       0x1d, 0x6d, 0x5f, 0x9a, 0x76,
+                       0xad, 0x40, 0x18, 0x76, 0x6a,
+                       0x47, 0x66, 0x80, 0xb5, 0x5c,
+                       0xd3, 0x39, 0xe8, 0xab, 0x6c,
+                       0x72, 0xb5, 0xfa, 0xcd, 0xb2,
+                       0xa2, 0xa5, 0x0a, 0xc2, 0x5b,
+                       0xd0, 0x86, 0x64, 0x7d, 0xd3,
+                       0xe2, 0xe6, 0xe9, 0x9e, 0x84,
+                       0xca, 0x2c, 0x36, 0x09, 0xfd,
+                       0xf1, 0x77, 0xfe, 0xb2, 0x6d },
+       cose_key5[] = { 0xa3, 0x01, 0x04, 0x02, 0x6b,
+                       0x6f, 0x75, 0x72, 0x2d, 0x73,
+                       0x65, 0x63, 0x72, 0x65, 0x74,
+                       0x32, 0x20, 0x50, 0x84, 0x9b,
+                       0x57, 0x86, 0x45, 0x7c, 0x14,
+                       0x91, 0xbe, 0x3a, 0x76, 0xdc,
+                       0xea, 0x6c, 0x42, 0x71 },
+
+       cose_key6[] = { 0xa6, 0x01, 0x02, 0x02, 0x78,
+                       0x21, 0x70, 0x65, 0x72, 0x65,
+                       0x67, 0x72, 0x69, 0x6e, 0x2e,
+                       0x74, 0x6f, 0x6f, 0x6b, 0x40,
+                       0x74, 0x75, 0x63, 0x6b, 0x62,
+                       0x6f, 0x72, 0x6f, 0x75, 0x67,
+                       0x68, 0x2e, 0x65, 0x78, 0x61,
+                       0x6d, 0x70, 0x6c, 0x65, 0x20,
+                       0x01, 0x21, 0x58, 0x20, 0x98,
+                       0xf5, 0x0a, 0x4f, 0xf6, 0xc0,
+                       0x58, 0x61, 0xc8, 0x86, 0x0d,
+                       0x13, 0xa6, 0x38, 0xea, 0x56,
+                       0xc3, 0xf5, 0xad, 0x75, 0x90,
+                       0xbb, 0xfb, 0xf0, 0x54, 0xe1,
+                       0xc7, 0xb4, 0xd9, 0x1d, 0x62,
+                       0x80, 0x22, 0x58, 0x20, 0xf0,
+                       0x14, 0x00, 0xb0, 0x89, 0x86,
+                       0x78, 0x04, 0xb8, 0xe9, 0xfc,
+                       0x96, 0xc3, 0x93, 0x21, 0x61,
+                       0xf1, 0x93, 0x4f, 0x42, 0x23,
+                       0x06, 0x91, 0x70, 0xd9, 0x24,
+                       0xb7, 0xe0, 0x3b, 0xf8, 0x22,
+                       0xbb, 0x23, 0x58, 0x20, 0x02,
+                       0xd1, 0xf7, 0xe6, 0xf2, 0x6c,
+                       0x43, 0xd4, 0x86, 0x8d, 0x87,
+                       0xce, 0xb2, 0x35, 0x31, 0x61,
+                       0x74, 0x0a, 0xac, 0xf1, 0xf7,
+                       0x16, 0x36, 0x47, 0x98, 0x4b,
+                       0x52, 0x2a, 0x84, 0x8d, 0xf1,
+                       0xc3 },
+       cose_key7[] = { 0xa3, 0x01, 0x04, 0x02, 0x58,
+                       0x24, 0x30, 0x31, 0x38, 0x63,
+                       0x30, 0x61, 0x65, 0x35, 0x2d,
+                       0x34, 0x64, 0x39, 0x62, 0x2d,
+                       0x34, 0x37, 0x31, 0x62, 0x2d,
+                       0x62, 0x66, 0x64, 0x36, 0x2d,
+                       0x65, 0x65, 0x66, 0x33, 0x31,
+                       0x34, 0x62, 0x63, 0x37, 0x30,
+                       0x33, 0x37, 0x20, 0x58, 0x20,
+                       0x84, 0x9b, 0x57, 0x21, 0x9d,
+                       0xae, 0x48, 0xde, 0x64, 0x6d,
+                       0x07, 0xdb, 0xb5, 0x33, 0x56,
+                       0x6e, 0x97, 0x66, 0x86, 0x45,
+                       0x7c, 0x14, 0x91, 0xbe, 0x3a,
+                       0x76, 0xdc, 0xea, 0x6c, 0x42,
+                       0x71, 0x88 },
+
+       cose_key8[] = {
+                       /* kid "sec-48" for hmac 384 */
+
+                       0xa3, 0x01, 0x04, 0x02, 0x66,
+                       0x73, 0x65, 0x63, 0x2d, 0x34,
+                       0x38, 0x20, 0x58, 0x30, 0x84,
+                       0x9b, 0x57, 0x21, 0x9d, 0xae,
+                       0x48, 0xde, 0x64, 0x6d, 0x07,
+                       0xdb, 0xb5, 0x33, 0x56, 0x6e,
+                       0x97, 0x66, 0x86, 0x45, 0x7c,
+                       0x14, 0x91, 0xbe, 0x3a, 0x76,
+                       0xdc, 0xea, 0x6c, 0x42, 0x71,
+                       0x88, 0x00, 0x11, 0x22, 0x33,
+                       0x77, 0x88, 0x99, 0xaa, 0x21,
+                       0x22, 0x23, 0x24, 0x25, 0x26,
+                       0x27, 0x28
+       },
+
+       cose_key9[] = {
+                       /* kid "sec-64" for hmac 512 */
+
+                       0xa3, 0x01, 0x04, 0x02, 0x46,
+                       0x73, 0x65, 0x63, 0x2d, 0x36,
+                       0x34, 0x20, 0x58, 0x40, 0x84,
+                       0x9b, 0x57, 0x21, 0x9d, 0xae,
+                       0x48, 0xde, 0x64, 0x6d, 0x07,
+                       0xdb, 0xb5, 0x33, 0x56, 0x6e,
+                       0x97, 0x66, 0x86, 0x45, 0x7c,
+                       0x14, 0x91, 0xbe, 0x3a, 0x76,
+                       0xdc, 0xea, 0x6c, 0x42, 0x71,
+                       0x88, 0x00, 0x11, 0x22, 0x33,
+                       0x77, 0x88, 0x99, 0xaa, 0x21,
+                       0x22, 0x23, 0x24, 0x25, 0x26,
+                       0x27, 0x28, 0xaa, 0xbb, 0xcc,
+                       0xdd, 0xee, 0xff, 0xa5, 0xa6,
+                       0xa7, 0xa8, 0xa9, 0xa0, 0xb1,
+                       0xb2, 0xb3, 0xb4,
+       },
+
+       cose_key10[] = { /* kid "11" (again) ed22519 OKP key */
+                       0xa5, 0x01, 0x01, 0x02, 0x42,
+                       0x31, 0x31, 0x20, 0x06, 0x21,
+                       0x58, 0x20, 0xd7, 0x5a, 0x98,
+                       0x01, 0x82, 0xb1, 0x0a, 0xb7,
+                       0xd5, 0x4b, 0xfe, 0xd3, 0xc9,
+                       0x64, 0x07, 0x3a, 0x0e, 0xe1,
+                       0x72, 0xf3, 0xda, 0xa6, 0x23,
+                       0x25, 0xaf, 0x02, 0x1a, 0x68,
+                       0xf7, 0x07, 0x51, 0x1a, 0x23,
+                       0x58, 0x20, 0x9d, 0x61, 0xb1,
+                       0x9d, 0xef, 0xfd, 0x5a, 0x60,
+                       0xba, 0x84, 0x4a, 0xf4, 0x92,
+                       0xec, 0x2c, 0xc4, 0x44, 0x49,
+                       0xc5, 0x69, 0x7b, 0x32, 0x69,
+                       0x19, 0x70, 0x3b, 0xac, 0x03,
+                       0x1c, 0xae, 0x7f, 0x60
+       },
+
+       cose_key_set1[] = {
+
+                       0x89,
+
+                       0xa6, 0x01, 0x02, 0x02, 0x42,
+                       0x31, 0x31, 0x20, 0x01, 0x21,
+                       0x58, 0x20, 0xba, 0xc5, 0xb1,
+                       0x1c, 0xad, 0x8f, 0x99, 0xf9,
+                       0xc7, 0x2b, 0x05, 0xcf, 0x4b,
+                       0x9e, 0x26, 0xd2, 0x44, 0xdc,
+                       0x18, 0x9f, 0x74, 0x52, 0x28,
+                       0x25, 0x5a, 0x21, 0x9a, 0x86,
+                       0xd6, 0xa0, 0x9e, 0xff, 0x22,
+                       0x58, 0x20, 0x20, 0x13, 0x8b,
+                       0xf8, 0x2d, 0xc1, 0xb6, 0xd5,
+                       0x62, 0xbe, 0x0f, 0xa5, 0x4a,
+                       0xb7, 0x80, 0x4a, 0x3a, 0x64,
+                       0xb6, 0xd7, 0x2c, 0xcf, 0xed,
+                       0x6b, 0x6f, 0xb6, 0xed, 0x28,
+                       0xbb, 0xfc, 0x11, 0x7e, 0x23,
+                       0x58, 0x20, 0x57, 0xc9, 0x20,
+                       0x77, 0x66, 0x41, 0x46, 0xe8,
+                       0x76, 0x76, 0x0c, 0x95, 0x20,
+                       0xd0, 0x54, 0xaa, 0x93, 0xc3,
+                       0xaf, 0xb0, 0x4e, 0x30, 0x67,
+                       0x05, 0xdb, 0x60, 0x90, 0x30,
+                       0x85, 0x07, 0xb4, 0xd3,
+
+                       0xa6, 0x01, 0x02, 0x02, 0x58,
+                       0x24, 0x6d, 0x65, 0x72, 0x69,
+                       0x61, 0x64, 0x6f, 0x63, 0x2e,
+                       0x62, 0x72, 0x61, 0x6e, 0x64,
+                       0x79, 0x62, 0x75, 0x63, 0x6b,
+                       0x40, 0x62, 0x75, 0x63, 0x6b,
+                       0x6c, 0x61, 0x6e, 0x64, 0x2e,
+                       0x65, 0x78, 0x61, 0x6d, 0x70,
+                       0x6c, 0x65, 0x20, 0x01, 0x21,
+                       0x58, 0x20, 0x65, 0xed, 0xa5,
+                       0xa1, 0x25, 0x77, 0xc2, 0xba,
+                       0xe8, 0x29, 0x43, 0x7f, 0xe3,
+                       0x38, 0x70, 0x1a, 0x10, 0xaa,
+                       0xa3, 0x75, 0xe1, 0xbb, 0x5b,
+                       0x5d, 0xe1, 0x08, 0xde, 0x43,
+                       0x9c, 0x08, 0x55, 0x1d, 0x22,
+                       0x58, 0x20, 0x1e, 0x52, 0xed,
+                       0x75, 0x70, 0x11, 0x63, 0xf7,
+                       0xf9, 0xe4, 0x0d, 0xdf, 0x9f,
+                       0x34, 0x1b, 0x3d, 0xc9, 0xba,
+                       0x86, 0x0a, 0xf7, 0xe0, 0xca,
+                       0x7c, 0xa7, 0xe9, 0xee, 0xcd,
+                       0x00, 0x84, 0xd1, 0x9c, 0x23,
+                       0x58, 0x20, 0xaf, 0xf9, 0x07,
+                       0xc9, 0x9f, 0x9a, 0xd3, 0xaa,
+                       0xe6, 0xc4, 0xcd, 0xf2, 0x11,
+                       0x22, 0xbc, 0xe2, 0xbd, 0x68,
+                       0xb5, 0x28, 0x3e, 0x69, 0x07,
+                       0x15, 0x4a, 0xd9, 0x11, 0x84,
+                       0x0f, 0xa2, 0x08, 0xcf,
+
+                       0xa3, 0x01, 0x04, 0x02, 0x4a,
+                       0x6f, 0x75, 0x72, 0x2d, 0x73,
+                       0x65, 0x63, 0x72, 0x65, 0x74,
+                       0x20, 0x58, 0x20, 0x84, 0x9b,
+                       0x57, 0x21, 0x9d, 0xae, 0x48,
+                       0xde, 0x64, 0x6d, 0x07, 0xdb,
+                       0xb5, 0x33, 0x56, 0x6e, 0x97,
+                       0x66, 0x86, 0x45, 0x7c, 0x14,
+                       0x91, 0xbe, 0x3a, 0x76, 0xdc,
+                       0xea, 0x6c, 0x42, 0x71, 0x88,
+
+                       0xa6, 0x01, 0x02, 0x02, 0x58,
+                       0x1e, 0x62, 0x69, 0x6c, 0x62,
+                       0x6f, 0x2e, 0x62, 0x61, 0x67,
+                       0x67, 0x69, 0x6e, 0x73, 0x40,
+                       0x68, 0x6f, 0x62, 0x62, 0x69,
+                       0x74, 0x6f, 0x6e, 0x2e, 0x65,
+                       0x78, 0x61, 0x6d, 0x70, 0x6c,
+                       0x65, 0x20, 0x03, 0x21, 0x58,
+                       0x42, 0x00, 0x72, 0x99, 0x2c,
+                       0xb3, 0xac, 0x08, 0xec, 0xf3,
+                       0xe5, 0xc6, 0x3d, 0xed, 0xec,
+                       0x0d, 0x51, 0xa8, 0xc1, 0xf7,
+                       0x9e, 0xf2, 0xf8, 0x2f, 0x94,
+                       0xf3, 0xc7, 0x37, 0xbf, 0x5d,
+                       0xe7, 0x98, 0x66, 0x71, 0xea,
+                       0xc6, 0x25, 0xfe, 0x82, 0x57,
+                       0xbb, 0xd0, 0x39, 0x46, 0x44,
+                       0xca, 0xaa, 0x3a, 0xaf, 0x8f,
+                       0x27, 0xa4, 0x58, 0x5f, 0xbb,
+                       0xca, 0xd0, 0xf2, 0x45, 0x76,
+                       0x20, 0x08, 0x5e, 0x5c, 0x8f,
+                       0x42, 0xad, 0x22, 0x58, 0x42,
+                       0x01, 0xdc, 0xa6, 0x94, 0x7b,
+                       0xce, 0x88, 0xbc, 0x57, 0x90,
+                       0x48, 0x5a, 0xc9, 0x74, 0x27,
+                       0x34, 0x2b, 0xc3, 0x5f, 0x88,
+                       0x7d, 0x86, 0xd6, 0x5a, 0x08,
+                       0x93, 0x77, 0xe2, 0x47, 0xe6,
+                       0x0b, 0xaa, 0x55, 0xe4, 0xe8,
+                       0x50, 0x1e, 0x2a, 0xda, 0x57,
+                       0x24, 0xac, 0x51, 0xd6, 0x90,
+                       0x90, 0x08, 0x03, 0x3e, 0xbc,
+                       0x10, 0xac, 0x99, 0x9b, 0x9d,
+                       0x7f, 0x5c, 0xc2, 0x51, 0x9f,
+                       0x3f, 0xe1, 0xea, 0x1d, 0x94,
+                       0x75, 0x23, 0x58, 0x42, 0x00,
+                       0x08, 0x51, 0x38, 0xdd, 0xab,
+                       0xf5, 0xca, 0x97, 0x5f, 0x58,
+                       0x60, 0xf9, 0x1a, 0x08, 0xe9,
+                       0x1d, 0x6d, 0x5f, 0x9a, 0x76,
+                       0xad, 0x40, 0x18, 0x76, 0x6a,
+                       0x47, 0x66, 0x80, 0xb5, 0x5c,
+                       0xd3, 0x39, 0xe8, 0xab, 0x6c,
+                       0x72, 0xb5, 0xfa, 0xcd, 0xb2,
+                       0xa2, 0xa5, 0x0a, 0xc2, 0x5b,
+                       0xd0, 0x86, 0x64, 0x7d, 0xd3,
+                       0xe2, 0xe6, 0xe9, 0x9e, 0x84,
+                       0xca, 0x2c, 0x36, 0x09, 0xfd,
+                       0xf1, 0x77, 0xfe, 0xb2, 0x6d,
+
+                       0xa3, 0x01, 0x04, 0x02, 0x4b,
+                       0x6f, 0x75, 0x72, 0x2d, 0x73,
+                       0x65, 0x63, 0x72, 0x65, 0x74,
+                       0x32, 0x20, 0x50, 0x84, 0x9b,
+                       0x57, 0x86, 0x45, 0x7c, 0x14,
+                       0x91, 0xbe, 0x3a, 0x76, 0xdc,
+                       0xea, 0x6c, 0x42, 0x71,
+
+                       0xa6, 0x01, 0x02, 0x02, 0x58,
+                       0x21, 0x70, 0x65, 0x72, 0x65,
+                       0x67, 0x72, 0x69, 0x6e, 0x2e,
+                       0x74, 0x6f, 0x6f, 0x6b, 0x40,
+                       0x74, 0x75, 0x63, 0x6b, 0x62,
+                       0x6f, 0x72, 0x6f, 0x75, 0x67,
+                       0x68, 0x2e, 0x65, 0x78, 0x61,
+                       0x6d, 0x70, 0x6c, 0x65, 0x20,
+                       0x01, 0x21, 0x58, 0x20, 0x98,
+                       0xf5, 0x0a, 0x4f, 0xf6, 0xc0,
+                       0x58, 0x61, 0xc8, 0x86, 0x0d,
+                       0x13, 0xa6, 0x38, 0xea, 0x56,
+                       0xc3, 0xf5, 0xad, 0x75, 0x90,
+                       0xbb, 0xfb, 0xf0, 0x54, 0xe1,
+                       0xc7, 0xb4, 0xd9, 0x1d, 0x62,
+                       0x80, 0x22, 0x58, 0x20, 0xf0,
+                       0x14, 0x00, 0xb0, 0x89, 0x86,
+                       0x78, 0x04, 0xb8, 0xe9, 0xfc,
+                       0x96, 0xc3, 0x93, 0x21, 0x61,
+                       0xf1, 0x93, 0x4f, 0x42, 0x23,
+                       0x06, 0x91, 0x70, 0xd9, 0x24,
+                       0xb7, 0xe0, 0x3b, 0xf8, 0x22,
+                       0xbb, 0x23, 0x58, 0x20, 0x02,
+                       0xd1, 0xf7, 0xe6, 0xf2, 0x6c,
+                       0x43, 0xd4, 0x86, 0x8d, 0x87,
+                       0xce, 0xb2, 0x35, 0x31, 0x61,
+                       0x74, 0x0a, 0xac, 0xf1, 0xf7,
+                       0x16, 0x36, 0x47, 0x98, 0x4b,
+                       0x52, 0x2a, 0x84, 0x8d, 0xf1,
+                       0xc3,
+
+                       0xa3, 0x01, 0x04, 0x02, 0x58,
+                       0x24, 0x30, 0x31, 0x38, 0x63,
+                       0x30, 0x61, 0x65, 0x35, 0x2d,
+                       0x34, 0x64, 0x39, 0x62, 0x2d,
+                       0x34, 0x37, 0x31, 0x62, 0x2d,
+                       0x62, 0x66, 0x64, 0x36, 0x2d,
+                       0x65, 0x65, 0x66, 0x33, 0x31,
+                       0x34, 0x62, 0x63, 0x37, 0x30,
+                       0x33, 0x37, 0x04, 0x58, 0x20,
+                       0x84, 0x9b, 0x57, 0x21, 0x9d,
+                       0xae, 0x48, 0xde, 0x64, 0x6d,
+                       0x07, 0xdb, 0xb5, 0x33, 0x56,
+                       0x6e, 0x97, 0x66, 0x86, 0x45,
+                       0x7c, 0x14, 0x91, 0xbe, 0x3a,
+                       0x76, 0xdc, 0xea, 0x6c, 0x42,
+                       0x71, 0x88,
+
+                       /* kid "sec-48" for hmac 384 */
+
+                       0xa3, 0x01, 0x04, 0x02, 0x46,
+                       0x73, 0x65, 0x63, 0x2d, 0x34,
+                       0x38, 0x20, 0x58, 0x30, 0x84,
+                       0x9b, 0x57, 0x21, 0x9d, 0xae,
+                       0x48, 0xde, 0x64, 0x6d, 0x07,
+                       0xdb, 0xb5, 0x33, 0x56, 0x6e,
+                       0x97, 0x66, 0x86, 0x45, 0x7c,
+                       0x14, 0x91, 0xbe, 0x3a, 0x76,
+                       0xdc, 0xea, 0x6c, 0x42, 0x71,
+                       0x88, 0x00, 0x11, 0x22, 0x33,
+                       0x77, 0x88, 0x99, 0xaa, 0x21,
+                       0x22, 0x23, 0x24, 0x25, 0x26,
+                       0x27, 0x28,
+
+                       /* kid "sec-64" for hmac 512 */
+
+                       0xa3, 0x01, 0x04, 0x02, 0x46,
+                       0x73, 0x65, 0x63, 0x2d, 0x36,
+                       0x34, 0x20, 0x58, 0x40, 0x84,
+                       0x9b, 0x57, 0x21, 0x9d, 0xae,
+                       0x48, 0xde, 0x64, 0x6d, 0x07,
+                       0xdb, 0xb5, 0x33, 0x56, 0x6e,
+                       0x97, 0x66, 0x86, 0x45, 0x7c,
+                       0x14, 0x91, 0xbe, 0x3a, 0x76,
+                       0xdc, 0xea, 0x6c, 0x42, 0x71,
+                       0x88, 0x00, 0x11, 0x22, 0x33,
+                       0x77, 0x88, 0x99, 0xaa, 0x21,
+                       0x22, 0x23, 0x24, 0x25, 0x26,
+                       0x27, 0x28, 0xaa, 0xbb, 0xcc,
+                       0xdd, 0xee, 0xff, 0xa5, 0xa6,
+                       0xa7, 0xa8, 0xa9, 0xa0, 0xb1,
+                       0xb2, 0xb3, 0xb4,
+}
+;
+
+struct keyinfo {
+       const uint8_t           *set;
+       size_t                  len;
+};
+
+struct keyinfo keyset1 = { cose_key_set1, sizeof(cose_key_set1) },
+               key3 = { cose_key3, sizeof(cose_key3) },
+               key8 = { cose_key8, sizeof(cose_key8) },
+               key9 = { cose_key9, sizeof(cose_key9) },
+               key10 = { cose_key10, sizeof(cose_key10) }
+;
+
+/* key pieces */
+
+static const uint8_t
+       key1_x[] = { 0xba, 0xc5, 0xb1, 0x1c, 0xad,
+                       0x8f, 0x99, 0xf9, 0xc7, 0x2b,
+                       0x05, 0xcf, 0x4b, 0x9e, 0x26,
+                       0xd2, 0x44, 0xdc, 0x18, 0x9f,
+                       0x74, 0x52, 0x28, 0x25, 0x5a,
+                       0x21, 0x9a, 0x86, 0xd6, 0xa0,
+                       0x9e, 0xff },
+       key1_y[] = { 0x20, 0x13, 0x8b, 0xf8, 0x2d,
+                       0xc1, 0xb6, 0xd5, 0x62, 0xbe,
+                       0x0f, 0xa5, 0x4a, 0xb7, 0x80,
+                       0x4a, 0x3a, 0x64, 0xb6, 0xd7,
+                       0x2c, 0xcf, 0xed, 0x6b, 0x6f,
+                       0xb6, 0xed, 0x28, 0xbb, 0xfc,
+                       0x11, 0x7e },
+       key1_d[] = { 0x57, 0xc9, 0x20, 0x77, 0x66,
+                       0x41, 0x46, 0xe8, 0x76, 0x76,
+                       0x0c, 0x95, 0x20, 0xd0, 0x54,
+                       0xaa, 0x93, 0xc3, 0xaf, 0xb0,
+                       0x4e, 0x30, 0x67, 0x05, 0xdb,
+                       0x60, 0x90, 0x30, 0x85, 0x07,
+                       0xb4, 0xd3 },
+
+       key2_x[] = { 0x65, 0xed, 0xa5, 0xa1, 0x25,
+                       0x77, 0xc2, 0xba, 0xe8, 0x29,
+                       0x43, 0x7f, 0xe3, 0x38, 0x70,
+                       0x1a, 0x10, 0xaa, 0xa3, 0x75,
+                       0xe1, 0xbb, 0x5b, 0x5d, 0xe1,
+                       0x08, 0xde, 0x43, 0x9c, 0x08,
+                       0x55, 0x1d },
+       key2_y[] = { 0x1e, 0x52, 0xed, 0x75, 0x70,
+                       0x11, 0x63, 0xf7, 0xf9, 0xe4,
+                       0x0d, 0xdf, 0x9f, 0x34, 0x1b,
+                       0x3d, 0xc9, 0xba, 0x86, 0x0a,
+                       0xf7, 0xe0, 0xca, 0x7c, 0xa7,
+                       0xe9, 0xee, 0xcd, 0x00, 0x84,
+                       0xd1, 0x9c },
+       key2_d[] = { 0xaf, 0xf9, 0x07, 0xc9, 0x9f,
+                       0x9a, 0xd3, 0xaa, 0xe6, 0xc4,
+                       0xcd, 0xf2, 0x11, 0x22, 0xbc,
+                       0xe2, 0xbd, 0x68, 0xb5, 0x28,
+                       0x3e, 0x69, 0x07, 0x15, 0x4a,
+                       0xd9, 0x11, 0x84, 0x0f, 0xa2,
+                       0x08, 0xcf },
+
+       key3_k[] = { 0x84, 0x9b, 0x57, 0x21, 0x9d,
+                       0xae, 0x48, 0xde, 0x64, 0x6d,
+                       0x07, 0xdb, 0xb5, 0x33, 0x56,
+                       0x6e, 0x97, 0x66, 0x86, 0x45,
+                       0x7c, 0x14, 0x91, 0xbe, 0x3a,
+                       0x76, 0xdc, 0xea, 0x6c, 0x42,
+                       0x71, 0x88 },
+
+       key4_x[] = { 0x00, 0x72, 0x99, 0x2c, 0xb3,
+                       0xac, 0x08, 0xec, 0xf3, 0xe5,
+                       0xc6, 0x3d, 0xed, 0xec, 0x0d,
+                       0x51, 0xa8, 0xc1, 0xf7, 0x9e,
+                       0xf2, 0xf8, 0x2f, 0x94, 0xf3,
+                       0xc7, 0x37, 0xbf, 0x5d, 0xe7,
+                       0x98, 0x66, 0x71, 0xea, 0xc6,
+                       0x25, 0xfe, 0x82, 0x57, 0xbb,
+                       0xd0, 0x39, 0x46, 0x44, 0xca,
+                       0xaa, 0x3a, 0xaf, 0x8f, 0x27,
+                       0xa4, 0x58, 0x5f, 0xbb, 0xca,
+                       0xd0, 0xf2, 0x45, 0x76, 0x20,
+                       0x08, 0x5e, 0x5c, 0x8f, 0x42,
+                       0xad },
+       key4_y[] = { 0x01, 0xdc, 0xa6, 0x94, 0x7b,
+                       0xce, 0x88, 0xbc, 0x57, 0x90,
+                       0x48, 0x5a, 0xc9, 0x74, 0x27,
+                       0x34, 0x2b, 0xc3, 0x5f, 0x88,
+                       0x7d, 0x86, 0xd6, 0x5a, 0x08,
+                       0x93, 0x77, 0xe2, 0x47, 0xe6,
+                       0x0b, 0xaa, 0x55, 0xe4, 0xe8,
+                       0x50, 0x1e, 0x2a, 0xda, 0x57,
+                       0x24, 0xac, 0x51, 0xd6, 0x90,
+                       0x90, 0x08, 0x03, 0x3e, 0xbc,
+                       0x10, 0xac, 0x99, 0x9b, 0x9d,
+                       0x7f, 0x5c, 0xc2, 0x51, 0x9f,
+                       0x3f, 0xe1, 0xea, 0x1d, 0x94,
+                       0x75 },
+       key4_d[] = { 0x00, 0x08, 0x51, 0x38, 0xdd,
+                       0xab, 0xf5, 0xca, 0x97, 0x5f,
+                       0x58, 0x60, 0xf9, 0x1a, 0x08,
+                       0xe9, 0x1d, 0x6d, 0x5f, 0x9a,
+                       0x76, 0xad, 0x40, 0x18, 0x76,
+                       0x6a, 0x47, 0x66, 0x80, 0xb5,
+                       0x5c, 0xd3, 0x39, 0xe8, 0xab,
+                       0x6c, 0x72, 0xb5, 0xfa, 0xcd,
+                       0xb2, 0xa2, 0xa5, 0x0a, 0xc2,
+                       0x5b, 0xd0, 0x86, 0x64, 0x7d,
+                       0xd3, 0xe2, 0xe6, 0xe9, 0x9e,
+                       0x84, 0xca, 0x2c, 0x36, 0x09,
+                       0xfd, 0xf1, 0x77, 0xfe, 0xb2,
+                       0x6d },
+       key5_k[] = { 0x84, 0x9b, 0x57, 0x86, 0x45,
+                       0x7c, 0x14, 0x91, 0xbe, 0x3a,
+                       0x76, 0xdc, 0xea, 0x6c, 0x42,
+                       0x71 },
+
+       key6_x[] = { 0x98, 0xf5, 0x0a, 0x4f, 0xf6,
+                       0xc0, 0x58, 0x61, 0xc8, 0x86,
+                       0x0d, 0x13, 0xa6, 0x38, 0xea,
+                       0x56, 0xc3, 0xf5, 0xad, 0x75,
+                       0x90, 0xbb, 0xfb, 0xf0, 0x54,
+                       0xe1, 0xc7, 0xb4, 0xd9, 0x1d,
+                       0x62, 0x80 },
+       key6_y[] = { 0xf0, 0x14, 0x00, 0xb0, 0x89,
+                       0x86, 0x78, 0x04, 0xb8, 0xe9,
+                       0xfc, 0x96, 0xc3, 0x93, 0x21,
+                       0x61, 0xf1, 0x93, 0x4f, 0x42,
+                       0x23, 0x06, 0x91, 0x70, 0xd9,
+                       0x24, 0xb7, 0xe0, 0x3b, 0xf8,
+                       0x22, 0xbb },
+       key6_d[] = { 0x02, 0xd1, 0xf7, 0xe6, 0xf2,
+                       0x6c, 0x43, 0xd4, 0x86, 0x8d,
+                       0x87, 0xce, 0xb2, 0x35, 0x31,
+                       0x61, 0x74, 0x0a, 0xac, 0xf1,
+                       0xf7, 0x16, 0x36, 0x47, 0x98,
+                       0x4b, 0x52, 0x2a, 0x84, 0x8d,
+                       0xf1, 0xc3 },
+
+       key7_k[] = { 0x84, 0x9b, 0x57, 0x21, 0x9d,
+                       0xae, 0x48, 0xde, 0x64, 0x6d,
+                       0x07, 0xdb, 0xb5, 0x33, 0x56,
+                       0x6e, 0x97, 0x66, 0x86, 0x45,
+                       0x7c, 0x14, 0x91, 0xbe, 0x3a,
+                       0x76, 0xdc, 0xea, 0x6c, 0x42,
+                       0x71, 0x88 },
+
+       key8_k[] = { 0x84, 0x9b, 0x57, 0x21, 0x9d,
+                       0xae, 0x48, 0xde, 0x64, 0x6d,
+                       0x07, 0xdb, 0xb5, 0x33, 0x56,
+                       0x6e, 0x97, 0x66, 0x86, 0x45,
+                       0x7c, 0x14, 0x91, 0xbe, 0x3a,
+                       0x76, 0xdc, 0xea, 0x6c, 0x42,
+                       0x71, 0x88, 0x00, 0x11, 0x22,
+                       0x33, 0x77, 0x88, 0x99, 0xaa,
+                       0x21, 0x22, 0x23, 0x24, 0x25,
+                       0x26, 0x27, 0x28 },
+
+       key9_k[] = {    0x84, 0x9b, 0x57, 0x21, 0x9d,
+                       0xae, 0x48, 0xde, 0x64, 0x6d,
+                       0x07, 0xdb, 0xb5, 0x33, 0x56,
+                       0x6e, 0x97, 0x66, 0x86, 0x45,
+                       0x7c, 0x14, 0x91, 0xbe, 0x3a,
+                       0x76, 0xdc, 0xea, 0x6c, 0x42,
+                       0x71, 0x88, 0x00, 0x11, 0x22,
+                       0x33, 0x77, 0x88, 0x99, 0xaa,
+                       0x21, 0x22, 0x23, 0x24, 0x25,
+                       0x26, 0x27, 0x28, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0xa5,
+                       0xa6, 0xa7, 0xa8, 0xa9, 0xa0,
+                       0xb1, 0xb2, 0xb3, 0xb4 }
+#if 0
+                       ,
+       key10_x[] = {
+                       0xd7, 0x5a, 0x98, 0x01, 0x82,
+                       0xb1, 0x0a, 0xb7, 0xd5, 0x4b,
+                       0xfe, 0xd3, 0xc9, 0x64, 0x07,
+                       0x3a, 0x0e, 0xe1, 0x72, 0xf3,
+                       0xda, 0xa6, 0x23, 0x25, 0xaf,
+                       0x02, 0x1a, 0x68, 0xf7, 0x07,
+                       0x51, 0x1a
+       }, key10_d[] = {
+                       0x9d, 0x61, 0xb1, 0x9d, 0xef,
+                       0xfd, 0x5a, 0x60, 0xba, 0x84,
+                       0x4a, 0xf4, 0x92, 0xec, 0x2c,
+                       0xc4, 0x44, 0x49, 0xc5, 0x69,
+                       0x7b, 0x32, 0x69, 0x19, 0x70,
+                       0x3b, 0xac, 0x03, 0x1c, 0xae,
+                       0x7f, 0x60
+       }
+#endif
+;
+
+int
+test_cose_keys(struct lws_context *context)
+{
+       struct lws_cose_key *ck;
+       lws_dll2_owner_t set;
+       lws_lec_pctx_t wc;
+       uint8_t buf[4096];
+       int n;
+
+#if 0
+       {
+               int fd = open("set1.cks",
+                             LWS_O_CREAT | LWS_O_TRUNC | LWS_O_WRONLY, 0600);
+
+               if (fd >= 0) {
+                       write(fd, cose_key_set1, sizeof(cose_key_set1));
+                       close(fd);
+               }
+       }
+#endif
+
+#if 0
+       lws_lec_pctx_t wx;
+       uint8_t dump[8192];
+
+       lws_lec_init(&wx, buf, sizeof(buf));
+
+       if (lws_lec_printf(&wx,
+               "{%d:%d, %d:%.*b, %d:%d, %d:%.*b, %d:%.*b}",
+               LWSCOSE_WKK_KTY, LWSCOSE_WKKTV_OKP,
+               LWSCOSE_WKK_KID, 2, "11",
+               LWSCOSE_WKOKP_CRV, LWSCOSE_WKEC_ED25519,
+               LWSCOSE_WKECKP_X, (int)sizeof(key10_x), key10_x,
+//             LWSCOSE_WKECKP_Y, (int)sizeof(key6_y), key6_y,
+               LWSCOSE_WKECKP_D, (int)sizeof(key10_d), key10_d) !=
+                       LWS_LECPCTX_RET_FINISHED)
+               return 1;
+
+       lws_hex_from_byte_array(buf, wx.used, (char *)dump, sizeof(dump));
+       puts((const char *)dump);
+#endif
+#if 0
+       lws_lec_pctx_t wx;
+       uint8_t dump[8192];
+
+       lws_lec_init(&wx, buf, sizeof(buf));
+
+       if (lws_lec_printf(&wx,
+               "{%d:%d, %d:%.*b, %d:%.*b}",
+               LWSCOSE_WKK_KTY, LWSCOSE_WKKTV_SYMMETRIC,
+               LWSCOSE_WKK_KID, 6, "sec-64",
+               -1, (int)sizeof(key9_k), key9_k) !=
+                       LWS_LECPCTX_RET_FINISHED)
+               return 1;
+
+       lws_hex_from_byte_array(buf, wx.used, (char *)dump, sizeof(dump));
+       puts((const char *)dump);
+#endif
+
+       /* key1 import */
+
+       lwsl_user("%s: key 1 import\n", __func__);
+
+       ck = lws_cose_key_import(NULL, key_import_cb, NULL, cose_key1, sizeof(cose_key1));
+       if (!ck)
+               return 1;
+
+       if (ck->kty != LWSCOSE_WKKTV_EC2 ||
+           ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_X].len != sizeof(key1_x) ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != sizeof(key1_y) ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_D].len != sizeof(key1_d) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_X].buf, key1_x, sizeof(key1_x)) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf, key1_y, sizeof(key1_y)) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, key1_d, sizeof(key1_d)))
+               goto bail;
+
+       // lws_cose_key_dump(ck);
+
+       /* key 1 export */
+
+       lwsl_user("%s: key 1 export\n", __func__);
+
+       lws_lec_init(&wc, buf, sizeof(buf));
+       n = (int)lws_cose_key_export(ck, &wc, LWSJWKF_EXPORT_PRIVATE);
+       lws_cose_key_destroy(&ck);
+       if (n != LWS_LECPCTX_RET_FINISHED)
+               goto bail;
+
+       // lwsl_hexdump_notice(buf, wc.used);
+
+       /* key2 import */
+
+       lwsl_user("%s: key 2 import\n", __func__);
+
+       ck = lws_cose_key_import(NULL, NULL, NULL, cose_key2, sizeof(cose_key2));
+       if (!ck)
+               return 1;
+
+       if (ck->kty != LWSCOSE_WKKTV_EC2 ||
+           ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_X].len != sizeof(key2_x) ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != sizeof(key2_y) ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_D].len != sizeof(key2_d) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_X].buf, key2_x, sizeof(key2_x)) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf, key2_y, sizeof(key2_y)) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, key2_d, sizeof(key2_d)))
+               goto bail;
+
+       lws_cose_key_destroy(&ck);
+
+       /* key3 import */
+
+       lwsl_user("%s: key 3 import\n", __func__);
+
+       ck = lws_cose_key_import(NULL, NULL, NULL, cose_key3, sizeof(cose_key3));
+       if (!ck) {
+               lwsl_err("%s: key 3 import failed\n", __func__);
+               goto bail;
+       }
+
+       if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
+           ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
+           ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key3_k) ||
+           memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key3_k, sizeof(key3_k))) {
+               lwsl_err("%s: key 3 checks failed %d %d %d\n", __func__,
+                               (int)ck->kty, (int)ck->gencrypto_kty,
+                               (int)ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len);
+               goto bail;
+       }
+
+       lws_cose_key_destroy(&ck);
+
+       /* key4 import */
+
+       lwsl_user("%s: key 4 import\n", __func__);
+
+       ck = lws_cose_key_import(NULL, NULL, NULL, cose_key4, sizeof(cose_key4));
+       if (!ck)
+               return 1;
+
+       if (ck->kty != LWSCOSE_WKKTV_EC2 ||
+           ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_X].len != sizeof(key4_x) ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != sizeof(key4_y) ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_D].len != sizeof(key4_d) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_X].buf, key4_x, sizeof(key4_x)) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf, key4_y, sizeof(key4_y)) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, key4_d, sizeof(key4_d)))
+               goto bail;
+
+       lws_cose_key_destroy(&ck);
+
+       /* key5 import */
+
+       lwsl_user("%s: key 5 import\n", __func__);
+
+       ck = lws_cose_key_import(NULL, NULL, NULL, cose_key5, sizeof(cose_key5));
+       if (!ck)
+               return 1;
+
+       if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
+           ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
+           ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key5_k) ||
+           memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key5_k, sizeof(key5_k)))
+               goto bail;
+
+       lws_cose_key_destroy(&ck);
+
+       /* key6 import */
+
+       lwsl_user("%s: key 6 import\n", __func__);
+
+       ck = lws_cose_key_import(NULL, NULL, NULL, cose_key6, sizeof(cose_key6));
+       if (!ck)
+               return 1;
+
+       if (ck->kty != LWSCOSE_WKKTV_EC2 ||
+           ck->gencrypto_kty != LWS_GENCRYPTO_KTY_EC ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_X].len != sizeof(key6_x) ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != sizeof(key6_y) ||
+           ck->e[LWS_GENCRYPTO_EC_KEYEL_D].len != sizeof(key6_d) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_X].buf, key6_x, sizeof(key6_x)) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf, key6_y, sizeof(key6_y)) ||
+           memcmp(ck->e[LWS_GENCRYPTO_EC_KEYEL_D].buf, key6_d, sizeof(key6_d)))
+               goto bail;
+
+       lws_cose_key_destroy(&ck);
+
+       /* key7 import */
+
+       lwsl_user("%s: key 7 import\n", __func__);
+
+       ck = lws_cose_key_import(NULL, NULL, NULL, cose_key7, sizeof(cose_key7));
+       if (!ck)
+               return 1;
+
+       if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
+           ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
+           ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key7_k) ||
+           memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key7_k, sizeof(key7_k)))
+               goto bail;
+
+       lws_cose_key_destroy(&ck);
+
+       /* key8 import */
+
+       lwsl_user("%s: key 8 import\n", __func__);
+
+       ck = lws_cose_key_import(NULL, NULL, NULL, cose_key8, sizeof(cose_key8));
+       if (!ck)
+               return 1;
+
+       if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
+           ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
+           ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key8_k) ||
+           memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key8_k, sizeof(key8_k)))
+               goto bail;
+
+       lws_cose_key_destroy(&ck);
+
+       /* key9 import */
+
+       lwsl_user("%s: key 9 import\n", __func__);
+
+       ck = lws_cose_key_import(NULL, NULL, NULL, cose_key9, sizeof(cose_key9));
+       if (!ck) {
+               lwsl_err("%s: cose9 import fail\n", __func__);
+               goto bail;
+       }
+
+       if (ck->kty != LWSCOSE_WKKTV_SYMMETRIC ||
+           ck->gencrypto_kty != LWS_GENCRYPTO_KTY_OCT ||
+           ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].len != sizeof(key9_k) ||
+           memcmp(ck->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, key9_k, sizeof(key9_k))) {
+               lwsl_notice("%s: key9 check fails\n", __func__);
+               goto bail;
+       }
+
+       lws_cose_key_destroy(&ck);
+
+       /* key set 1 */
+
+       lwsl_user("%s: key_set1\n", __func__);
+       lws_dll2_owner_clear(&set);
+       ck = lws_cose_key_import(&set, NULL, NULL, cose_key_set1, sizeof(cose_key_set1));
+       if (!ck)
+               return 1;
+
+       lws_cose_key_set_destroy(&set);
+
+       /* generate */
+
+       ck = lws_cose_key_generate(context, LWSCOSE_WKKTV_EC2,
+                                  (1 << LWSCOSE_WKKO_SIGN) |
+                                  (1 << LWSCOSE_WKKO_VERIFY) |
+                                  (1 << LWSCOSE_WKKO_ENCRYPT) |
+                                  (1 << LWSCOSE_WKKO_DECRYPT),
+                                  0, "P-256", (const uint8_t *)"the-keyid", 9);
+       if (!ck)
+               return 1;
+
+       // lws_cose_key_dump(ck);
+
+       lws_cose_key_destroy(&ck);
+
+       return 0;
+
+bail:
+       lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__);
+
+       return 1;
+}
diff --git a/minimal-examples/api-tests/api-test-cose/main.c b/minimal-examples/api-tests/api-test-cose/main.c
new file mode 100644 (file)
index 0000000..19de29c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * lws-api-test-cose
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+
+int
+test_cose_keys(struct lws_context *context);
+int
+test_cose_sign(struct lws_context *context);
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+       int result = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS COSE api tests\n");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
+       info.options = 0;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       result |= test_cose_keys(context);
+       result |= test_cose_sign(context);
+
+       lwsl_user("Completed: %s\n", result ? "FAIL" : "PASS");
+
+       lws_context_destroy(context);
+
+       return result;
+}
diff --git a/minimal-examples/api-tests/api-test-cose/sign.c b/minimal-examples/api-tests/api-test-cose/sign.c
new file mode 100644 (file)
index 0000000..6c8c50b
--- /dev/null
@@ -0,0 +1,1862 @@
+/*
+ * lws-api-test-jose - RFC8152 cose_sign tests
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * Raw key CBOR created from descriptions at
+ *
+ * https://github.com/cose-wg/Examples/blob/master/KeySet.txt
+ */
+
+#include <libwebsockets.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+static const uint8_t
+       sign1_pass_01[] = {
+               /*
+                * https://github.com/cose-wg/Examples/blob/master/
+                * sign1-tests/sign-pass-01.json
+                */
+               0xd2, 0x84, 0x41, 0xa0, 0xa2,
+               0x01, 0x26, 0x04, 0x42, 0x31,
+               0x31, 0x54, 0x54, 0x68, 0x69,
+               0x73, 0x20, 0x69, 0x73, 0x20,
+               0x74, 0x68, 0x65, 0x20, 0x63,
+               0x6f, 0x6e, 0x74, 0x65, 0x6e,
+               0x74, 0x2e, 0x58, 0x40, 0x87,
+               0xdb, 0x0d, 0x2e, 0x55, 0x71,
+               0x84, 0x3b, 0x78, 0xac, 0x33,
+               0xec, 0xb2, 0x83, 0x0d, 0xf7,
+               0xb6, 0xe0, 0xa4, 0xd5, 0xb7,
+               0x37, 0x6d, 0xe3, 0x36, 0xb2,
+               0x3c, 0x59, 0x1c, 0x90, 0xc4,
+               0x25, 0x31, 0x7e, 0x56, 0x12,
+               0x7f, 0xbe, 0x04, 0x37, 0x00,
+               0x97, 0xce, 0x34, 0x70, 0x87,
+               0xb2, 0x33, 0xbf, 0x72, 0x2b,
+               0x64, 0x07, 0x2b, 0xeb, 0x44,
+               0x86, 0xbd, 0xa4, 0x03, 0x1d,
+               0x27, 0x24, 0x4f },
+       sign1_pass_02[] = {
+               0xd2, 0x84, 0x43, 0xa1, 0x01,
+               0x26, 0xa1, 0x04, 0x42, 0x31,
+               0x31, 0x54, 0x54, 0x68, 0x69,
+               0x73, 0x20, 0x69, 0x73, 0x20,
+               0x74, 0x68, 0x65, 0x20, 0x63,
+               0x6f, 0x6e, 0x74, 0x65, 0x6e,
+               0x74, 0x2e, 0x58, 0x40, 0x10,
+               0x72, 0x9c, 0xd7, 0x11, 0xcb,
+               0x38, 0x13, 0xd8, 0xd8, 0xe9,
+               0x44, 0xa8, 0xda, 0x71, 0x11,
+               0xe7, 0xb2, 0x58, 0xc9, 0xbd,
+               0xca, 0x61, 0x35, 0xf7, 0xae,
+               0x1a, 0xdb, 0xee, 0x95, 0x09,
+               0x89, 0x12, 0x67, 0x83, 0x7e,
+               0x1e, 0x33, 0xbd, 0x36, 0xc1,
+               0x50, 0x32, 0x6a, 0xe6, 0x27,
+               0x55, 0xc6, 0xbd, 0x8e, 0x54,
+               0x0c, 0x3e, 0x8f, 0x92, 0xd7,
+               0xd2, 0x25, 0xe8, 0xdb, 0x72,
+               0xb8, 0x82, 0x0b },
+
+       sign1_pass_02_ext[] = {
+               0x11, 0xaa, 0x22, 0xbb, 0x33,
+               0xcc, 0x44, 0xdd, 0x55, 0x00,
+               0x66, 0x99 },
+
+       sign1_pass_03[] = {
+               0x84, 0x43, 0xa1, 0x01, 0x26,
+               0xa1, 0x04, 0x42, 0x31, 0x31,
+               0x54, 0x54, 0x68, 0x69, 0x73,
+               0x20, 0x69, 0x73, 0x20, 0x74,
+               0x68, 0x65, 0x20, 0x63, 0x6f,
+               0x6e, 0x74, 0x65, 0x6e, 0x74,
+               0x2e, 0x58, 0x40, 0x8e, 0xb3,
+               0x3e, 0x4c, 0xa3, 0x1d, 0x1c,
+               0x46, 0x5a, 0xb0, 0x5a, 0xac,
+               0x34, 0xcc, 0x6b, 0x23, 0xd5,
+               0x8f, 0xef, 0x5c, 0x08, 0x31,
+               0x06, 0xc4, 0xd2, 0x5a, 0x91,
+               0xae, 0xf0, 0xb0, 0x11, 0x7e,
+               0x2a, 0xf9, 0xa2, 0x91, 0xaa,
+               0x32, 0xe1, 0x4a, 0xb8, 0x34,
+               0xdc, 0x56, 0xed, 0x2a, 0x22,
+               0x34, 0x44, 0x54, 0x7e, 0x01,
+               0xf1, 0x1d, 0x3b, 0x09, 0x16,
+               0xe5, 0xa4, 0xc3, 0x45, 0xca,
+               0xcb, 0x36 },
+       sign1_fail_01[] = {
+               0xd9, 0x03, 0xe6, 0x84, 0x43,
+               0xa1, 0x01, 0x26, 0xa1, 0x04,
+               0x42, 0x31, 0x31, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x58,
+               0x40, 0x8e, 0xb3, 0x3e, 0x4c,
+               0xa3, 0x1d, 0x1c, 0x46, 0x5a,
+               0xb0, 0x5a, 0xac, 0x34, 0xcc,
+               0x6b, 0x23, 0xd5, 0x8f, 0xef,
+               0x5c, 0x08, 0x31, 0x06, 0xc4,
+               0xd2, 0x5a, 0x91, 0xae, 0xf0,
+               0xb0, 0x11, 0x7e, 0x2a, 0xf9,
+               0xa2, 0x91, 0xaa, 0x32, 0xe1,
+               0x4a, 0xb8, 0x34, 0xdc, 0x56,
+               0xed, 0x2a, 0x22, 0x34, 0x44,
+               0x54, 0x7e, 0x01, 0xf1, 0x1d,
+               0x3b, 0x09, 0x16, 0xe5, 0xa4,
+               0xc3, 0x45, 0xca, 0xcb, 0x36 },
+       sign1_fail_02[] = {
+               0xd2, 0x84, 0x43, 0xa1, 0x01,
+               0x26, 0xa1, 0x04, 0x42, 0x31,
+               0x31, 0x54, 0x54, 0x68, 0x69,
+               0x73, 0x20, 0x69, 0x73, 0x20,
+               0x74, 0x68, 0x65, 0x20, 0x63,
+               0x6f, 0x6e, 0x74, 0x65, 0x6e,
+               0x74, 0x2f, 0x58, 0x40, 0x8e,
+               0xb3, 0x3e, 0x4c, 0xa3, 0x1d,
+               0x1c, 0x46, 0x5a, 0xb0, 0x5a,
+               0xac, 0x34, 0xcc, 0x6b, 0x23,
+               0xd5, 0x8f, 0xef, 0x5c, 0x08,
+               0x31, 0x06, 0xc4, 0xd2, 0x5a,
+               0x91, 0xae, 0xf0, 0xb0, 0x11,
+               0x7e, 0x2a, 0xf9, 0xa2, 0x91,
+               0xaa, 0x32, 0xe1, 0x4a, 0xb8,
+               0x34, 0xdc, 0x56, 0xed, 0x2a,
+               0x22, 0x34, 0x44, 0x54, 0x7e,
+               0x01, 0xf1, 0x1d, 0x3b, 0x09,
+               0x16, 0xe5, 0xa4, 0xc3, 0x45,
+               0xca, 0xcb, 0x36 },
+       sign1_fail_03[] = {
+               0xd2, 0x84, 0x45, 0xa1, 0x01,
+               0x39, 0x03, 0xe6, 0xa1, 0x04,
+               0x42, 0x31, 0x31, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x58,
+               0x40, 0x8e, 0xb3, 0x3e, 0x4c,
+               0xa3, 0x1d, 0x1c, 0x46, 0x5a,
+               0xb0, 0x5a, 0xac, 0x34, 0xcc,
+               0x6b, 0x23, 0xd5, 0x8f, 0xef,
+               0x5c, 0x08, 0x31, 0x06, 0xc4,
+               0xd2, 0x5a, 0x91, 0xae, 0xf0,
+               0xb0, 0x11, 0x7e, 0x2a, 0xf9,
+               0xa2, 0x91, 0xaa, 0x32, 0xe1,
+               0x4a, 0xb8, 0x34, 0xdc, 0x56,
+               0xed, 0x2a, 0x22, 0x34, 0x44,
+               0x54, 0x7e, 0x01, 0xf1, 0x1d,
+               0x3b, 0x09, 0x16, 0xe5, 0xa4,
+               0xc3, 0x45, 0xca, 0xcb, 0x36 },
+       sign1_fail_04[] = {
+               0xd2, 0x84, 0x4a, 0xa1, 0x01,
+               0x67, 0x75, 0x6e, 0x6b, 0x6e,
+               0x6f, 0x77, 0x6e, 0xa1, 0x04,
+               0x42, 0x31, 0x31, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x58,
+               0x40, 0x8e, 0xb3, 0x3e, 0x4c,
+               0xa3, 0x1d, 0x1c, 0x46, 0x5a,
+               0xb0, 0x5a, 0xac, 0x34, 0xcc,
+               0x6b, 0x23, 0xd5, 0x8f, 0xef,
+               0x5c, 0x08, 0x31, 0x06, 0xc4,
+               0xd2, 0x5a, 0x91, 0xae, 0xf0,
+               0xb0, 0x11, 0x7e, 0x2a, 0xf9,
+               0xa2, 0x91, 0xaa, 0x32, 0xe1,
+               0x4a, 0xb8, 0x34, 0xdc, 0x56,
+               0xed, 0x2a, 0x22, 0x34, 0x44,
+               0x54, 0x7e, 0x01, 0xf1, 0x1d,
+               0x3b, 0x09, 0x16, 0xe5, 0xa4,
+               0xc3, 0x45, 0xca, 0xcb, 0x36 },
+
+               /* sign1/fail05 is missing upstream */
+
+       sign1_fail_06[] = {
+               0xd2, 0x84, 0x45, 0xa2, 0x01,
+               0x26, 0x03, 0x00, 0xa1, 0x04,
+               0x42, 0x31, 0x31, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x58,
+               0x40, 0x8e, 0xb3, 0x3e, 0x4c,
+               0xa3, 0x1d, 0x1c, 0x46, 0x5a,
+               0xb0, 0x5a, 0xac, 0x34, 0xcc,
+               0x6b, 0x23, 0xd5, 0x8f, 0xef,
+               0x5c, 0x08, 0x31, 0x06, 0xc4,
+               0xd2, 0x5a, 0x91, 0xae, 0xf0,
+               0xb0, 0x11, 0x7e, 0x2a, 0xf9,
+               0xa2, 0x91, 0xaa, 0x32, 0xe1,
+               0x4a, 0xb8, 0x34, 0xdc, 0x56,
+               0xed, 0x2a, 0x22, 0x34, 0x44,
+               0x54, 0x7e, 0x01, 0xf1, 0x1d,
+               0x3b, 0x09, 0x16, 0xe5, 0xa4,
+               0xc3, 0x45, 0xca, 0xcb, 0x36 },
+
+       sign1_fail_07[] = {
+               0xd2, 0x84, 0x43, 0xa1, 0x01,
+               0x26, 0xa1, 0x04, 0x42, 0x31,
+               0x31, 0x54, 0x54, 0x68, 0x69,
+               0x73, 0x20, 0x69, 0x73, 0x20,
+               0x74, 0x68, 0x65, 0x20, 0x63,
+               0x6f, 0x6e, 0x74, 0x65, 0x6e,
+               0x74, 0x2e, 0x58, 0x40, 0x65,
+               0x20, 0xbb, 0xaf, 0x20, 0x81,
+               0xd7, 0xe0, 0xed, 0x0f, 0x95,
+               0xf7, 0x6e, 0xb0, 0x73, 0x3d,
+               0x66, 0x70, 0x05, 0xf7, 0x46,
+               0x7c, 0xec, 0x4b, 0x87, 0xb9,
+               0x38, 0x1a, 0x6b, 0xa1, 0xed,
+               0xe8, 0xe0, 0x0d, 0xf2, 0x9f,
+               0x32, 0xa3, 0x72, 0x30, 0xf3,
+               0x9a, 0x84, 0x2a, 0x54, 0x82,
+               0x1f, 0xdd, 0x22, 0x30, 0x92,
+               0x81, 0x9d, 0x77, 0x28, 0xef,
+               0xb9, 0xd3, 0xa0, 0x08, 0x0b,
+               0x75, 0x38, 0x0b },
+
+       sign_pass_01[] = {
+               0xd8, 0x62, 0x84, 0x41, 0xa0,
+               0xa0, 0x54, 0x54, 0x68, 0x69,
+               0x73, 0x20, 0x69, 0x73, 0x20,
+               0x74, 0x68, 0x65, 0x20, 0x63,
+               0x6f, 0x6e, 0x74, 0x65, 0x6e,
+               0x74, 0x2e, 0x81, 0x83, 0x43,
+               0xa1, 0x01, 0x26, 0xa1, 0x04,
+               0x42, 0x31, 0x31, 0x58, 0x40,
+               0xe2, 0xae, 0xaf, 0xd4, 0x0d,
+               0x69, 0xd1, 0x9d, 0xfe, 0x6e,
+               0x52, 0x07, 0x7c, 0x5d, 0x7f,
+               0xf4, 0xe4, 0x08, 0x28, 0x2c,
+               0xbe, 0xfb, 0x5d, 0x06, 0xcb,
+               0xf4, 0x14, 0xaf, 0x2e, 0x19,
+               0xd9, 0x82, 0xac, 0x45, 0xac,
+               0x98, 0xb8, 0x54, 0x4c, 0x90,
+               0x8b, 0x45, 0x07, 0xde, 0x1e,
+               0x90, 0xb7, 0x17, 0xc3, 0xd3,
+               0x48, 0x16, 0xfe, 0x92, 0x6a,
+               0x2b, 0x98, 0xf5, 0x3a, 0xfd,
+               0x2f, 0xa0, 0xf3, 0x0a },
+
+       sign_pass_02[] = {
+               0xd8, 0x62, 0x84, 0x40, 0xa0,
+               0x54, 0x54, 0x68, 0x69, 0x73,
+               0x20, 0x69, 0x73, 0x20, 0x74,
+               0x68, 0x65, 0x20, 0x63, 0x6f,
+               0x6e, 0x74, 0x65, 0x6e, 0x74,
+               0x2e, 0x81, 0x83, 0x43, 0xa1,
+               0x01, 0x26, 0xa1, 0x04, 0x42,
+               0x31, 0x31, 0x58, 0x40, 0xcb,
+               0xb8, 0xda, 0xd9, 0xbe, 0xaf,
+               0xb8, 0x90, 0xe1, 0xa4, 0x14,
+               0x12, 0x4d, 0x8b, 0xfb, 0xc2,
+               0x6b, 0xed, 0xf2, 0xa9, 0x4f,
+               0xcb, 0x5a, 0x88, 0x24, 0x32,
+               0xbf, 0xf6, 0xd6, 0x3e, 0x15,
+               0xf5, 0x74, 0xee, 0xb2, 0xab,
+               0x51, 0xd8, 0x3f, 0xa2, 0xcb,
+               0xf6, 0x26, 0x72, 0xeb, 0xf4,
+               0xc7, 0xd9, 0x93, 0xb0, 0xf4,
+               0xc2, 0x44, 0x76, 0x47, 0xd8,
+               0x31, 0xba, 0x57, 0xcc, 0xa8,
+               0x6b, 0x93, 0x0a },
+
+       sign_pass_03[] = {
+               0x84, 0x40, 0xa0, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x81,
+               0x83, 0x43, 0xa1, 0x01, 0x26,
+               0xa1, 0x04, 0x42, 0x31, 0x31,
+               0x58, 0x40, 0xe2, 0xae, 0xaf,
+               0xd4, 0x0d, 0x69, 0xd1, 0x9d,
+               0xfe, 0x6e, 0x52, 0x07, 0x7c,
+               0x5d, 0x7f, 0xf4, 0xe4, 0x08,
+               0x28, 0x2c, 0xbe, 0xfb, 0x5d,
+               0x06, 0xcb, 0xf4, 0x14, 0xaf,
+               0x2e, 0x19, 0xd9, 0x82, 0xac,
+               0x45, 0xac, 0x98, 0xb8, 0x54,
+               0x4c, 0x90, 0x8b, 0x45, 0x07,
+               0xde, 0x1e, 0x90, 0xb7, 0x17,
+               0xc3, 0xd3, 0x48, 0x16, 0xfe,
+               0x92, 0x6a, 0x2b, 0x98, 0xf5,
+               0x3a, 0xfd, 0x2f, 0xa0, 0xf3,
+               0x0a },
+
+       sign_fail_01[] = {
+               0xd9, 0x03, 0xe6, 0x84, 0x40,
+               0xa0, 0x54, 0x54, 0x68, 0x69,
+               0x73, 0x20, 0x69, 0x73, 0x20,
+               0x74, 0x68, 0x65, 0x20, 0x63,
+               0x6f, 0x6e, 0x74, 0x65, 0x6e,
+               0x74, 0x2e, 0x81, 0x83, 0x43,
+               0xa1, 0x01, 0x26, 0xa1, 0x04,
+               0x42, 0x31, 0x31, 0x58, 0x40,
+               0xe2, 0xae, 0xaf, 0xd4, 0x0d,
+               0x69, 0xd1, 0x9d, 0xfe, 0x6e,
+               0x52, 0x07, 0x7c, 0x5d, 0x7f,
+               0xf4, 0xe4, 0x08, 0x28, 0x2c,
+               0xbe, 0xfb, 0x5d, 0x06, 0xcb,
+               0xf4, 0x14, 0xaf, 0x2e, 0x19,
+               0xd9, 0x82, 0xac, 0x45, 0xac,
+               0x98, 0xb8, 0x54, 0x4c, 0x90,
+               0x8b, 0x45, 0x07, 0xde, 0x1e,
+               0x90, 0xb7, 0x17, 0xc3, 0xd3,
+               0x48, 0x16, 0xfe, 0x92, 0x6a,
+               0x2b, 0x98, 0xf5, 0x3a, 0xfd,
+               0x2f, 0xa0, 0xf3, 0x0a },
+
+       sign_fail_02[] = {
+               0xd8, 0x62, 0x84, 0x40, 0xa0,
+               0x54, 0x54, 0x68, 0x69, 0x73,
+               0x20, 0x69, 0x73, 0x20, 0x74,
+               0x68, 0x65, 0x20, 0x63, 0x6f,
+               0x6e, 0x74, 0x65, 0x6e, 0x74,
+               0x2e, 0x81, 0x83, 0x43, 0xa1,
+               0x01, 0x26, 0xa1, 0x04, 0x42,
+               0x31, 0x31, 0x58, 0x40, 0xe2,
+               0xae, 0xaf, 0xd4, 0x0d, 0x69,
+               0xd1, 0x9d, 0xfe, 0x6e, 0x52,
+               0x07, 0x7c, 0x5d, 0x7f, 0xf4,
+               0xe4, 0x08, 0x28, 0x2c, 0xbe,
+               0xfb, 0x5d, 0x06, 0xcb, 0xf4,
+               0x14, 0xaf, 0x2e, 0x19, 0xd9,
+               0x82, 0xac, 0x45, 0xac, 0x98,
+               0xb8, 0x54, 0x4c, 0x90, 0x8b,
+               0x45, 0x07, 0xde, 0x1e, 0x90,
+               0xb7, 0x17, 0xc3, 0xd3, 0x48,
+               0x16, 0xfe, 0x92, 0x6a, 0x2b,
+               0x98, 0xf5, 0x3a, 0xfd, 0x2f,
+               0xa0, 0xf3, 0x0b },
+
+       sign_fail_03[] = {
+               0xd8, 0x62, 0x84, 0x40, 0xa0,
+               0x54, 0x54, 0x68, 0x69, 0x73,
+               0x20, 0x69, 0x73, 0x20, 0x74,
+               0x68, 0x65, 0x20, 0x63, 0x6f,
+               0x6e, 0x74, 0x65, 0x6e, 0x74,
+               0x2e, 0x81, 0x83, 0x45, 0xa1,
+               0x01, 0x39, 0x03, 0xe6, 0xa1,
+               0x04, 0x42, 0x31, 0x31, 0x58,
+               0x40, 0xe2, 0xae, 0xaf, 0xd4,
+               0x0d, 0x69, 0xd1, 0x9d, 0xfe,
+               0x6e, 0x52, 0x07, 0x7c, 0x5d,
+               0x7f, 0xf4, 0xe4, 0x08, 0x28,
+               0x2c, 0xbe, 0xfb, 0x5d, 0x06,
+               0xcb, 0xf4, 0x14, 0xaf, 0x2e,
+               0x19, 0xd9, 0x82, 0xac, 0x45,
+               0xac, 0x98, 0xb8, 0x54, 0x4c,
+               0x90, 0x8b, 0x45, 0x07, 0xde,
+               0x1e, 0x90, 0xb7, 0x17, 0xc3,
+               0xd3, 0x48, 0x16, 0xfe, 0x92,
+               0x6a, 0x2b, 0x98, 0xf5, 0x3a,
+               0xfd, 0x2f, 0xa0, 0xf3, 0x0a },
+
+       sign_fail_04[] = {
+               0xd8, 0x62, 0x84, 0x40, 0xa0,
+               0x54, 0x54, 0x68, 0x69, 0x73,
+               0x20, 0x69, 0x73, 0x20, 0x74,
+               0x68, 0x65, 0x20, 0x63, 0x6f,
+               0x6e, 0x74, 0x65, 0x6e, 0x74,
+               0x2e, 0x81, 0x83, 0x4a, 0xa1,
+               0x01, 0x67, 0x75, 0x6e, 0x6b,
+               0x6e, 0x6f, 0x77, 0x6e, 0xa1,
+               0x04, 0x42, 0x31, 0x31, 0x58,
+               0x40, 0xe2, 0xae, 0xaf, 0xd4,
+               0x0d, 0x69, 0xd1, 0x9d, 0xfe,
+               0x6e, 0x52, 0x07, 0x7c, 0x5d,
+               0x7f, 0xf4, 0xe4, 0x08, 0x28,
+               0x2c, 0xbe, 0xfb, 0x5d, 0x06,
+               0xcb, 0xf4, 0x14, 0xaf, 0x2e,
+               0x19, 0xd9, 0x82, 0xac, 0x45,
+               0xac, 0x98, 0xb8, 0x54, 0x4c,
+               0x90, 0x8b, 0x45, 0x07, 0xde,
+               0x1e, 0x90, 0xb7, 0x17, 0xc3,
+               0xd3, 0x48, 0x16, 0xfe, 0x92,
+               0x6a, 0x2b, 0x98, 0xf5, 0x3a,
+               0xfd, 0x2f, 0xa0, 0xf3, 0x0a },
+
+               /* fail 5 missing upstream */
+
+       sign_fail_06[] = {
+               0xd8, 0x62, 0x84, 0x43, 0xa1,
+               0x03, 0x00, 0xa0, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x81,
+               0x83, 0x43, 0xa1, 0x01, 0x26,
+               0xa1, 0x04, 0x42, 0x31, 0x31,
+               0x58, 0x40, 0xe2, 0xae, 0xaf,
+               0xd4, 0x0d, 0x69, 0xd1, 0x9d,
+               0xfe, 0x6e, 0x52, 0x07, 0x7c,
+               0x5d, 0x7f, 0xf4, 0xe4, 0x08,
+               0x28, 0x2c, 0xbe, 0xfb, 0x5d,
+               0x06, 0xcb, 0xf4, 0x14, 0xaf,
+               0x2e, 0x19, 0xd9, 0x82, 0xac,
+               0x45, 0xac, 0x98, 0xb8, 0x54,
+               0x4c, 0x90, 0x8b, 0x45, 0x07,
+               0xde, 0x1e, 0x90, 0xb7, 0x17,
+               0xc3, 0xd3, 0x48, 0x16, 0xfe,
+               0x92, 0x6a, 0x2b, 0x98, 0xf5,
+               0x3a, 0xfd, 0x2f, 0xa0, 0xf3,
+               0x0a },
+
+       sign_fail_07[] = {
+               0xd8, 0x62, 0x84, 0x41, 0xa0,
+               0xa0, 0x54, 0x54, 0x68, 0x69,
+               0x73, 0x20, 0x69, 0x73, 0x20,
+               0x74, 0x68, 0x65, 0x20, 0x63,
+               0x6f, 0x6e, 0x74, 0x65, 0x6e,
+               0x74, 0x2e, 0x81, 0x83, 0x43,
+               0xa1, 0x01, 0x26, 0xa1, 0x04,
+               0x42, 0x31, 0x31, 0x58, 0x40,
+               0xd7, 0x1c, 0x05, 0xdb, 0x52,
+               0xc9, 0xce, 0x7f, 0x1b, 0xf5,
+               0xaa, 0xc0, 0x13, 0x34, 0xbb,
+               0xea, 0xca, 0xc1, 0xd8, 0x6a,
+               0x23, 0x03, 0xe6, 0xee, 0xaa,
+               0x89, 0x26, 0x6f, 0x45, 0xc0,
+               0x1e, 0xd6, 0x02, 0xca, 0x64,
+               0x9e, 0xaf, 0x79, 0x0d, 0x8b,
+               0xc9, 0x9d, 0x24, 0x58, 0x45,
+               0x7c, 0xa6, 0xa8, 0x72, 0x06,
+               0x19, 0x40, 0xe7, 0xaf, 0xbe,
+               0x48, 0xe2, 0x89, 0xdf, 0xac,
+               0x14, 0x6a, 0xe2, 0x58 },
+
+       sign_hmac_01[] = {
+               0xd8, 0x61, 0x85, 0x43, 0xa1,
+               0x01, 0x05, 0xa0, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x58,
+               0x20, 0x2b, 0xdc, 0xc8, 0x9f,
+               0x05, 0x82, 0x16, 0xb8, 0xa2,
+               0x08, 0xdd, 0xc6, 0xd8, 0xb5,
+               0x4a, 0xa9, 0x1f, 0x48, 0xbd,
+               0x63, 0x48, 0x49, 0x86, 0x56,
+               0x51, 0x05, 0xc9, 0xad, 0x5a,
+               0x66, 0x82, 0xf6, 0x81, 0x83,
+               0x40, 0xa2, 0x01, 0x25, 0x04,
+               0x4a, 0x6f, 0x75, 0x72, 0x2d,
+               0x73, 0x65, 0x63, 0x72, 0x65,
+               0x74, 0x40 },
+
+       sign_hmac_02[] = {
+               0xd8, 0x61, 0x85, 0x43, 0xa1,
+               0x01, 0x06, 0xa0, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x58,
+               0x30, 0xb3, 0x09, 0x7f, 0x70,
+               0x00, 0x9a, 0x11, 0x50, 0x74,
+               0x09, 0x59, 0x8a, 0x83, 0xe1,
+               0x5b, 0xbb, 0xbf, 0x19, 0x82,
+               0xdc, 0xe2, 0x8e, 0x5a, 0xb6,
+               0xd5, 0xa6, 0xaf, 0xf6, 0x89,
+               0x7b, 0xd2, 0x4b, 0xb8, 0xb7,
+               0x47, 0x96, 0x22, 0xc9, 0x40,
+               0x1b, 0x24, 0x09, 0x0d, 0x45,
+               0x82, 0x06, 0xd5, 0x87, 0x81,
+               0x83, 0x40, 0xa2, 0x01, 0x25,
+               0x04, 0x46, 0x73, 0x65, 0x63,
+               0x2d, 0x34, 0x38, 0x40 },
+
+       sign_hmac_03[] = {
+               0xd8, 0x61, 0x85, 0x43, 0xa1,
+               0x01, 0x07, 0xa0, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x58,
+               0x40, 0xcd, 0x28, 0xa6, 0xb3,
+               0xcf, 0xbb, 0xbf, 0x21, 0x48,
+               0x51, 0xb9, 0x06, 0xe0, 0x50,
+               0x05, 0x6c, 0xb4, 0x38, 0xa8,
+               0xb8, 0x89, 0x05, 0xb8, 0xb7,
+               0x46, 0x19, 0x77, 0x02, 0x27,
+               0x11, 0xa9, 0xd8, 0xac, 0x5d,
+               0xbc, 0x54, 0xe2, 0x9a, 0x56,
+               0xd9, 0x26, 0x04, 0x6b, 0x40,
+               0xfc, 0x26, 0x07, 0xc2, 0x5b,
+               0x34, 0x44, 0x54, 0xaa, 0x5f,
+               0x68, 0xde, 0x09, 0xa3, 0xe5,
+               0x25, 0xd3, 0x86, 0x5a, 0x05,
+               0x81, 0x83, 0x40, 0xa2, 0x01,
+               0x25, 0x04, 0x46, 0x73, 0x65,
+               0x63, 0x2d, 0x36, 0x34, 0x40 },
+
+       sign_hmac_04[] = {
+               0xd8, 0x61, 0x85, 0x43, 0xa1,
+               0x01, 0x05, 0xa0, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x58,
+               0x20, 0x2b, 0xdc, 0xc8, 0x9f,
+               0x05, 0x82, 0x16, 0xb8, 0xa2,
+               0x08, 0xdd, 0xc6, 0xd8, 0xb5,
+               0x4a, 0xa9, 0x1f, 0x48, 0xbd,
+               0x63, 0x48, 0x49, 0x86, 0x56,
+               0x51, 0x05, 0xc9, 0xad, 0x5a,
+               0x66, 0x82, 0xf7, 0x81, 0x83,
+               0x40, 0xa2, 0x01, 0x25, 0x04,
+               0x4a, 0x6f, 0x75, 0x72, 0x2d,
+               0x73, 0x65, 0x63, 0x72, 0x65,
+               0x74, 0x40 },
+
+       sign_hmac_05[] = {
+               0xd8, 0x61, 0x85, 0x43, 0xa1,
+               0x01, 0x04, 0xa0, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x48,
+               0x6f, 0x35, 0xca, 0xb7, 0x79,
+               0xf7, 0x78, 0x33, 0x81, 0x83,
+               0x40, 0xa2, 0x01, 0x25, 0x04,
+               0x4a, 0x6f, 0x75, 0x72, 0x2d,
+               0x73, 0x65, 0x63, 0x72, 0x65,
+               0x74, 0x40 },
+
+       enc_hmac_01[] = {
+               0xd1, 0x84, 0x43, 0xa1, 0x01,
+               0x05, 0xa0, 0x54, 0x54, 0x68,
+               0x69, 0x73, 0x20, 0x69, 0x73,
+               0x20, 0x74, 0x68, 0x65, 0x20,
+               0x63, 0x6f, 0x6e, 0x74, 0x65,
+               0x6e, 0x74, 0x2e, 0x58, 0x20,
+               0xa1, 0xa8, 0x48, 0xd3, 0x47,
+               0x1f, 0x9d, 0x61, 0xee, 0x49,
+               0x01, 0x8d, 0x24, 0x4c, 0x82,
+               0x47, 0x72, 0xf2, 0x23, 0xad,
+               0x4f, 0x93, 0x52, 0x93, 0xf1,
+               0x78, 0x9f, 0xc3, 0xa0, 0x8d,
+               0x8c, 0x58 },
+
+       enc_hmac_02[] = {
+               0xd1, 0x84, 0x43, 0xa1, 0x01,
+               0x06, 0xa0, 0x54, 0x54, 0x68,
+               0x69, 0x73, 0x20, 0x69, 0x73,
+               0x20, 0x74, 0x68, 0x65, 0x20,
+               0x63, 0x6f, 0x6e, 0x74, 0x65,
+               0x6e, 0x74, 0x2e, 0x58, 0x30,
+               0x99, 0x8d, 0x26, 0xc6, 0x45,
+               0x9a, 0xae, 0xec, 0xf4, 0x4e,
+               0xd2, 0x0c, 0xe0, 0x0c, 0x8c,
+               0xce, 0xdf, 0x0a, 0x1f, 0x3d,
+               0x22, 0xa9, 0x2f, 0xc0, 0x5d,
+               0xb0, 0x8c, 0x5a, 0xeb, 0x1c,
+               0xb5, 0x94, 0xca, 0xaf, 0x5a,
+               0x5c, 0x5e, 0x2e, 0x9d, 0x01,
+               0xcc, 0xe7, 0xe7, 0x7a, 0x93,
+               0xaa, 0x8c, 0x62 },
+
+       enc_hmac_03[] = {
+               0xd1, 0x84, 0x43, 0xa1, 0x01,
+               0x07, 0xa0, 0x54, 0x54, 0x68,
+               0x69, 0x73, 0x20, 0x69, 0x73,
+               0x20, 0x74, 0x68, 0x65, 0x20,
+               0x63, 0x6f, 0x6e, 0x74, 0x65,
+               0x6e, 0x74, 0x2e, 0x58, 0x40,
+               0x4a, 0x55, 0x5b, 0xf9, 0x71,
+               0xf7, 0xc1, 0x89, 0x1d, 0x9d,
+               0xdf, 0x30, 0x4a, 0x1a, 0x13,
+               0x2e, 0x2d, 0x6f, 0x81, 0x74,
+               0x49, 0x47, 0x4d, 0x81, 0x3e,
+               0x6d, 0x04, 0xd6, 0x59, 0x62,
+               0xbe, 0xd8, 0xbb, 0xa7, 0x0c,
+               0x17, 0xe1, 0xf5, 0x30, 0x8f,
+               0xa3, 0x99, 0x62, 0x95, 0x9a,
+               0x4b, 0x9b, 0x8d, 0x7d, 0xa8,
+               0xe6, 0xd8, 0x49, 0xb2, 0x09,
+               0xdc, 0xd3, 0xe9, 0x8c, 0xc0,
+               0xf1, 0x1e, 0xdd, 0xf2 },
+
+       enc_hmac_04[] = {
+               0xd1, 0x84, 0x43, 0xa1, 0x01,
+               0x05, 0xa0, 0x54, 0x54, 0x68,
+               0x69, 0x73, 0x20, 0x69, 0x73,
+               0x20, 0x74, 0x68, 0x65, 0x20,
+               0x63, 0x6f, 0x6e, 0x74, 0x65,
+               0x6e, 0x74, 0x2e, 0x58, 0x20,
+               0xa1, 0xa8, 0x48, 0xd3, 0x47,
+               0x1f, 0x9d, 0x61, 0xee, 0x49,
+               0x01, 0x8d, 0x24, 0x4c, 0x82,
+               0x47, 0x72, 0xf2, 0x23, 0xad,
+               0x4f, 0x93, 0x52, 0x93, 0xf1,
+               0x78, 0x9f, 0xc3, 0xa0, 0x8d,
+               0x8c, 0x59 },
+
+       enc_hmac_05[] = {
+               0xd1, 0x84, 0x43, 0xa1, 0x01,
+               0x04, 0xa0, 0x54, 0x54, 0x68,
+               0x69, 0x73, 0x20, 0x69, 0x73,
+               0x20, 0x74, 0x68, 0x65, 0x20,
+               0x63, 0x6f, 0x6e, 0x74, 0x65,
+               0x6e, 0x74, 0x2e, 0x48, 0x11,
+               0xf9, 0xe3, 0x57, 0x97, 0x5f,
+               0xb8, 0x49 }
+#if 0
+,
+
+       countersign_sign_01[] = {
+               0xd8, 0x62, 0x84, 0x43, 0xa1,
+               0x03, 0x00, 0xa0, 0x54, 0x54,
+               0x68, 0x69, 0x73, 0x20, 0x69,
+               0x73, 0x20, 0x74, 0x68, 0x65,
+               0x20, 0x63, 0x6f, 0x6e, 0x74,
+               0x65, 0x6e, 0x74, 0x2e, 0x81,
+               0x83, 0x43, 0xa1, 0x01, 0x27,
+               0xa2, 0x07, 0x83, 0x43, 0xa1,
+               0x01, 0x27, 0xa1, 0x04, 0x42,
+               0x31, 0x31, 0x58, 0x40, 0x8e,
+               0x1b, 0xe2, 0xf9, 0x45, 0x3d,
+               0x26, 0x48, 0x12, 0xe5, 0x90,
+               0x49, 0x91, 0x32, 0xbe, 0xf3,
+               0xfb, 0xf9, 0xee, 0x9d, 0xb2,
+               0x7c, 0x2c, 0x16, 0x87, 0x88,
+               0xe3, 0xb7, 0xeb, 0xe5, 0x06,
+               0xc0, 0x4f, 0xd3, 0xd1, 0x9f,
+               0xaa, 0x9f, 0x51, 0x23, 0x2a,
+               0xf5, 0xc9, 0x59, 0xe4, 0xef,
+               0x47, 0x92, 0x88, 0x34, 0x64,
+               0x7f, 0x56, 0xdf, 0xbe, 0x93,
+               0x91, 0x12, 0x88, 0x4d, 0x08,
+               0xef, 0x25, 0x05, 0x04, 0x42,
+               0x31, 0x31, 0x58, 0x40, 0x77,
+               0xf3, 0xea, 0xcd, 0x11, 0x85,
+               0x2c, 0x4b, 0xf9, 0xcb, 0x1d,
+               0x72, 0xfa, 0xbe, 0x6b, 0x26,
+               0xfb, 0xa1, 0xd7, 0x60, 0x92,
+               0xb2, 0xb5, 0xb7, 0xec, 0x83,
+               0xb8, 0x35, 0x57, 0x65, 0x22,
+               0x64, 0xe6, 0x96, 0x90, 0xdb,
+               0xc1, 0x17, 0x2d, 0xdc, 0x0b,
+               0xf8, 0x84, 0x11, 0xc0, 0xd2,
+               0x5a, 0x50, 0x7f, 0xdb, 0x24,
+               0x7a, 0x20, 0xc4, 0x0d, 0x5e,
+               0x24, 0x5f, 0xab, 0xd3, 0xfc,
+               0x9e, 0xc1, 0x06 }
+#endif
+;
+
+extern const struct {
+       const uint8_t           *set;
+       size_t                  len;
+} keyset1, key3, key8, key9, key10;
+
+static int
+xcb(lws_cose_sig_ext_pay_t *x)
+{
+       x->ext = sign1_pass_02_ext;
+       x->xl = sizeof(sign1_pass_02_ext);
+
+       return LCOSESIGEXTCB_RET_FINISHED;
+}
+
+
+
+int
+test_cose_sign(struct lws_context *context)
+{
+       struct lws_cose_validate_context *cps;
+       lws_cose_validate_create_info_t info;
+       lws_cose_validate_res_t *res;
+       lws_dll2_owner_t set;
+       lws_dll2_owner_t *o;
+       int n;
+
+       memset(&info, 0, sizeof(info));
+       info.cx = context;
+       info.keyset = &set;
+
+#if 1
+       {
+               int fd = open("sign_hmac01.sig",
+                             LWS_O_CREAT | LWS_O_TRUNC | LWS_O_WRONLY, 0600);
+
+               if (fd >= 0) {
+                       write(fd, sign_hmac_01, sizeof(sign_hmac_01));
+                       close(fd);
+               }
+       }
+#endif
+
+       /*
+        * valid sign1 we have key for
+        */
+
+       lwsl_user("%s: sign1/sign-pass-01\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_SINGLE;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_pass_01, sizeof(sign1_pass_01),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1)
+               goto bail1;
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid sign1 but empty key set, so can't judge it
+        */
+
+       lwsl_user("%s: sign1/sign-pass-01 - no key\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+
+       info.sigtype = SIGTYPE_SINGLE;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_pass_01, sizeof(sign1_pass_01),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1)
+               goto bail1;
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid sign1
+        */
+
+       lwsl_user("%s: sign1/sign-pass-02\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_SINGLE;
+       info.ext_cb = xcb;
+       info.ext_len = sizeof(sign1_pass_02_ext);
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_pass_02, sizeof(sign1_pass_02),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1)
+               goto bail1;
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid sign1 without enclosing tag
+        */
+
+       lwsl_user("%s: sign1/sign-pass-03\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_SINGLE;
+       info.ext_cb = NULL;
+       info.ext_len = 0;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_pass_03, sizeof(sign1_pass_03),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1)
+               goto bail1;
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * sign1 with wrong tag
+        */
+
+       lwsl_user("%s: sign1/sign-fail-01\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_SINGLE;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_fail_01, sizeof(sign1_fail_01),
+                                   NULL);
+       if (!n) {
+               lwsl_notice("%s: sign_val_chunk should have failed\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * invalid sign1, signature tampered
+        */
+
+       lwsl_user("%s: sign1/sign-fail-02\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_SINGLE;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_fail_02, sizeof(sign1_fail_02),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1)
+               goto bail1;
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result)
+               /* validation result must be fail */
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * invalid sign1, alg tampered
+        */
+
+       lwsl_user("%s: sign1/sign-fail-03\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_SINGLE;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_fail_03, sizeof(sign1_fail_03),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1)
+               goto bail1;
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result)
+               /* validation result must be fail */
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * invalid sign1, alg sign tampered
+        */
+
+       lwsl_user("%s: sign1/sign-fail-04\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_SINGLE;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_fail_04, sizeof(sign1_fail_04),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1)
+               goto bail1;
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result)
+               /* validation result must be fail */
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * invalid sign1, protected attributes tampered
+        */
+
+       lwsl_user("%s: sign1/sign-fail-06\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_SINGLE;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_fail_06, sizeof(sign1_fail_06),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1)
+               goto bail1;
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result)
+               /* validation result must be fail */
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * invalid sign1, protected attribute removed
+        */
+
+       lwsl_user("%s: sign1/sign-fail-07\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_SINGLE;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign1_fail_07, sizeof(sign1_fail_07),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1)
+               goto bail1;
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result)
+               /* validation result must be fail */
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid sign we have key for
+        */
+
+       lwsl_user("%s: sign/sign-pass-01\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MULTI;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_pass_01, sizeof(sign_pass_01),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_notice("%s: results: %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid sign we have key for
+        */
+
+       lwsl_user("%s: sign/sign-pass-02\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MULTI;
+       info.ext_cb = xcb;
+       info.ext_len = sizeof(sign1_pass_02_ext);
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_pass_02, sizeof(sign_pass_02),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_notice("%s: results: %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid sign we have key for
+        */
+
+       lwsl_user("%s: sign/sign-pass-03\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MULTI;
+       info.ext_cb = NULL;
+       info.ext_len = 0;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_pass_03, sizeof(sign_pass_03),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_notice("%s: results: %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * wrong cbor tag
+        */
+
+       lwsl_user("%s: sign/sign-fail-01\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MULTI;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_fail_01, sizeof(sign_fail_01),
+                                   NULL);
+       if (!n) {
+               lwsl_notice("%s: sign_val_chunk should fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * tampered signature
+        */
+
+       lwsl_user("%s: sign/sign-fail-02\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MULTI;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_fail_02, sizeof(sign_fail_02),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_notice("%s: results: %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * tampered sign alg -999
+        */
+
+       lwsl_user("%s: sign/sign-fail-03\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MULTI;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_fail_03, sizeof(sign_fail_03),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_notice("%s: results: %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * tampered sign alg 0
+        */
+
+       lwsl_user("%s: sign/sign-fail-04\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MULTI;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_fail_04, sizeof(sign_fail_04),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_notice("%s: results: %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * add protected attribute
+        */
+
+       lwsl_user("%s: sign/sign-fail-06\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MULTI;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_fail_06, sizeof(sign_fail_06),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_notice("%s: results: %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * remove protected attribute
+        */
+
+       lwsl_user("%s: sign/sign-fail-07\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MULTI;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_fail_07, sizeof(sign_fail_07),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_notice("%s: results: %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result)
+               goto bail1;
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+
+       /*
+        * valid HMAC sign we have key for
+        */
+
+       lwsl_user("%s: hmac-examples/hmac-01\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_hmac_01, sizeof(sign_hmac_01),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result) {
+               lwsl_err("%s: result is fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid HMAC sign we have key for
+        */
+
+       lwsl_user("%s: hmac-examples/hmac-02\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_hmac_02, sizeof(sign_hmac_02),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result) {
+               lwsl_err("%s: result is fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+
+       /*
+        * valid HMAC sign we have key for
+        */
+
+       lwsl_user("%s: hmac-examples/hmac-03\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_hmac_03, sizeof(sign_hmac_03),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result) {
+               lwsl_err("%s: result is fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * invalid HMAC sign we have key for
+        */
+
+       lwsl_user("%s: hmac-examples/hmac-04 fail mac tag\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_hmac_04, sizeof(sign_hmac_04),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result) {
+               lwsl_err("%s: result is wrongly succeeding\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid HMAC sign we have key for HS256/64
+        */
+
+       lwsl_user("%s: hmac-examples/hmac-05\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, keyset1.set, keyset1.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, sign_hmac_05, sizeof(sign_hmac_05),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result) {
+               lwsl_err("%s: result is fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid HMAC sign with implicit HS256 key
+        */
+
+       lwsl_user("%s: hmac-examples/enc-01\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, key3.set, key3.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC0;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, enc_hmac_01, sizeof(enc_hmac_01),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result) {
+               lwsl_err("%s: result is fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid HMAC sign with implicit HS384 key
+        */
+
+       lwsl_user("%s: hmac-examples/enc-02\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, key8.set, key8.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC0;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, enc_hmac_02, sizeof(enc_hmac_02),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result) {
+               lwsl_err("%s: result is fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid HMAC sign with implicit HS512 key
+        */
+
+       lwsl_user("%s: hmac-examples/enc-03\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, key9.set, key9.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC0;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, enc_hmac_03, sizeof(enc_hmac_03),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result) {
+               lwsl_err("%s: result is fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * invalid HMAC sign with implicit HS256 key, tampered hmac tag
+        */
+
+       lwsl_user("%s: hmac-examples/enc-04\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, key3.set, key3.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC0;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, enc_hmac_04, sizeof(enc_hmac_04),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (!res->result) {
+               lwsl_err("%s: result wrongly succeeds\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+
+       /*
+        * valid HMAC sign with implicit HS256 key, HS256/64
+        */
+
+       lwsl_user("%s: hmac-examples/enc-05\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, key3.set, key3.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_MAC0;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, enc_hmac_05, sizeof(enc_hmac_05),
+                                   NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result) {
+               lwsl_err("%s: result is fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+#if 0
+       /*
+        * valid Ed25519 signature with countersignature from same key + alg
+        */
+
+       lwsl_user("%s: countersign/sign-01\n", __func__);
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, key10.set, key10.len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               return 1;
+       }
+
+       info.sigtype = SIGTYPE_COUNTERSIGNED;
+       cps = lws_cose_validate_create(&info);
+       if (!cps) {
+               lwsl_notice("%s: sign_val_create fail\n", __func__);
+               goto bail;
+       }
+
+       n = lws_cose_validate_chunk(cps, countersign_sign_01,
+                                        sizeof(countersign_sign_01), NULL);
+       if (n) {
+               lwsl_notice("%s: sign_val_chunk failed\n", __func__);
+               goto bail1;
+       }
+
+       o = lws_cose_validate_results(cps);
+       if (o->count != 1) {
+               lwsl_err("%s: result count %d\n", __func__, o->count);
+               goto bail1;
+       }
+
+       res = lws_container_of(o->head, lws_cose_validate_res_t, list);
+       if (res->result) {
+               lwsl_err("%s: result is fail\n", __func__);
+               goto bail1;
+       }
+
+       lws_cose_validate_destroy(&cps);
+       lws_cose_key_set_destroy(&set);
+#endif
+
+       return 0;
+
+bail1:
+       lws_cose_validate_destroy(&cps);
+bail:
+       lws_cose_key_set_destroy(&set);
+
+       return 1;
+}
diff --git a/minimal-examples/api-tests/api-test-dhcpc/CMakeLists.txt b/minimal-examples/api-tests/api-test-dhcpc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1bb2dcd
--- /dev/null
@@ -0,0 +1,23 @@
+project(lws-api-test-dhcpc C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-api-test-dhcpc)
+set(SRCS main.c)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_SYS_DHCP_CLIENT 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/api-tests/api-test-dhcpc/README.md b/minimal-examples/api-tests/api-test-dhcpc/README.md
new file mode 100644 (file)
index 0000000..74f79a0
--- /dev/null
@@ -0,0 +1,27 @@
+# api test dhcpc
+
+The application confirms it can set DHCP on the given interface
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-i <netif>|Network interface name to set by DHCP, eg, eth0 or wlo1
+
+```
+ $ ./lws-api-test-dhcpc -i wlo1
+[2019/10/06 14:56:41:7683] U: LWS API selftest: Async DNS
+[2019/10/06 14:56:42:4461] U: main: requesting DHCP for wlo1
+[2019/10/06 14:56:42:5207] N: callback_dhcpc: DHCP configured wlo1
+[2019/10/06 14:56:42:5246] U: lws_dhcpc_cb: dhcp set OK
+[2019/10/06 14:56:42:5999] U: Completed: ALL PASS: 1 / 1
+```
+
+
diff --git a/minimal-examples/api-tests/api-test-dhcpc/main.c b/minimal-examples/api-tests/api-test-dhcpc/main.c
new file mode 100644 (file)
index 0000000..b0dccbb
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * lws-api-test-dhcpc
+ *
+ * Written in 2019 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <signal.h>
+
+static int interrupted, ok, fail, exp = 1;
+struct lws_context *context;
+const char *nif;
+
+static const char * const sa46_names[] = {
+       "LWSDH_SA46_IP",
+       "LWSDH_SA46_DNS_SRV_1",
+       "LWSDH_SA46_DNS_SRV_2",
+       "LWSDH_SA46_DNS_SRV_3",
+       "LWSDH_SA46_DNS_SRV_4",
+       "LWSDH_SA46_IPV4_ROUTER",
+       "LWSDH_SA46_NTP_SERVER",
+       "LWSDH_SA46_DHCP_SERVER",
+};
+
+static int
+lws_dhcpc_cb(void *opaque, lws_dhcpc_ifstate_t *is)
+{
+       unsigned int n;
+       char buf[64];
+
+       lwsl_user("%s: dhcp set OK\n", __func__);
+
+       for (n = 0; n < LWS_ARRAY_SIZE(sa46_names); n++) {
+               lws_sa46_write_numeric_address(&is->sa46[n], buf, sizeof(buf));
+               lwsl_notice("%s: %s: %s\n", __func__, sa46_names[n], buf);
+       }
+
+       ok = 1;
+       interrupted = 1;
+       return 0;
+}
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int
+main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+#if !defined(__COVERITY__)
+       const char *p;
+#endif
+       int n = 1;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+       lwsl_user("LWS API selftest: DHCP Client\n");
+
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+
+#if !defined(__COVERITY__)
+       if ((p = lws_cmdline_option(argc, argv, "-i")))
+               nif = p;
+#endif
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       if (nif) {
+               lwsl_user("%s: requesting DHCP for %s\n", __func__, nif);
+               lws_dhcpc_request(context, nif, AF_INET, lws_dhcpc_cb, NULL);
+       } else {
+               lwsl_err("%s: use -i <network-interface> to select if\n", __func__);
+               interrupted = 1;
+       }
+
+       /* the usual lws event loop */
+
+       n = 1;
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       if (fail || ok != exp)
+               lwsl_user("Completed: PASS: %d / %d, FAIL: %d\n", ok, exp,
+                               fail);
+       else
+               lwsl_user("Completed: ALL PASS: %d / %d\n", ok, exp);
+
+       return !(ok == exp && !fail);
+}
index 023e837..5a81ae8 100644 (file)
@@ -1,66 +1,13 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-api-test-fts C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-api-test-fts)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_FTS 1 requirements)
 
@@ -68,9 +15,9 @@ if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 5003f8c..d21a19b 100644 (file)
@@ -106,7 +106,7 @@ int main(int argc, char **argv)
                while (optind < argc) {
 
                        fi = lws_fts_file_index(t, argv[optind],
-                                               strlen(argv[optind]), 1);
+                                               (int)strlen(argv[optind]), 1);
                        if (fi < 0) {
                                lwsl_err("%s: Failed to get file idx for %s\n",
                                         __func__, argv[optind]);
@@ -122,12 +122,12 @@ int main(int argc, char **argv)
                        }
 
                        do {
-                               int n = read(fd, buf, sizeof(buf));
+                               int n = (int)read(fd, buf, sizeof(buf));
 
                                if (n <= 0)
                                        break;
 
-                               if (lws_fts_fill(t, fi, buf, n)) {
+                               if (lws_fts_fill(t, (uint32_t)fi, buf, (size_t)n)) {
                                        lwsl_err("%s: lws_fts_fill failed\n",
                                                 __func__);
                                        close(fd);
diff --git a/minimal-examples/api-tests/api-test-fts/selftest.sh b/minimal-examples/api-tests/api-test-fts/selftest.sh
deleted file mode 100755 (executable)
index 03e7d49..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=4
-
-FAILS=0
-
-#
-# let's make an index with just Dorian first
-#
-dotest $1 $2 apitest -c -i /tmp/lws-fts-dorian.index \
-    "../minimal-examples/api-tests/api-test-fts/the-picture-of-dorian-gray.txt"
-
-# and let's hear about autocompletes for "b"
-
-dotest $1 $2 apitest -i /tmp/lws-fts-dorian.index b
-cat $2/api-test-fts/apitest.log | cut -d' ' -f5- > /tmp/fts1
-diff -urN /tmp/fts1 "../minimal-examples/api-tests/api-test-fts/canned-1.txt"
-if [ $? -ne 0 ] ; then
-       echo "Test 1 failed"
-       FAILS=$(( $FAILS + 1 ))
-fi
-
-#
-# let's make an index with Dorian + Les Mis in French (ie, UTF-8) as well
-#
-dotest $1 $2 apitest -c -i /tmp/lws-fts-both.index \
-   "../minimal-examples/api-tests/api-test-fts/the-picture-of-dorian-gray.txt" \
-   "../minimal-examples/api-tests/api-test-fts/les-mis-utf8.txt"
-
-# and let's hear about "help", which appears in both
-
-dotest $1 $2 apitest -i /tmp/lws-fts-both.index -f -l help
-cat $2/api-test-fts/apitest.log | cut -d' ' -f5- > /tmp/fts2
-diff -urN /tmp/fts2 "../minimal-examples/api-tests/api-test-fts/canned-2.txt"
-if [ $? -ne 0 ] ; then
-       echo "Test 1 failed"
-       FAILS=$(( $FAILS + 1 ))
-fi
-
-exit $FAILS
index 4e97252..a3678d5 100644 (file)
@@ -1,80 +1,28 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-api-test-gencrypto C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-api-test-gencrypto)
 set(SRCS main.c lws-genaes.c lws-genec.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_GENCRYPTO 1 requirements)
 require_lws_config(LWS_WITH_JOSE 1 requirements)
-
+require_lws_config(USE_WOLFSSL 0 requirements)
 
 if (requirements)
 
        add_executable(${SAMP} ${SRCS})
+       add_test(NAME api-test-gencrypto COMMAND lws-api-test-gencrypto)
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
 
index 9063647..e7f2aa2 100644 (file)
@@ -9,6 +9,10 @@
 
 #include <libwebsockets.h>
 
+
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_CBC))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_cbc))
+
 static const uint8_t
        /*
         * produced with (plaintext.txt contains "test plaintext\0\0")
@@ -101,7 +105,10 @@ bail:
 
        return -1;
 }
+#endif
 
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_CFB))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_cfb128))
 static const uint8_t
 /*
  * produced with (plaintext.txt contains "test plaintext\0\0")
@@ -188,6 +195,10 @@ bail:
 
        return -1;
 }
+#endif
+
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_CFB))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_cfb8))
 
 static const uint8_t
 /*
@@ -272,7 +283,10 @@ bail:
 
        return -1;
 }
+#endif
 
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_CTR))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_ctr))
 static const uint8_t
 /*
  * produced with (plaintext.txt contains "test plaintext\0\0")
@@ -365,7 +379,10 @@ bail:
 
        return -1;
 }
+#endif
 
+#if (defined(LWS_WITH_MBEDTLS)) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_ecb))
 static const uint8_t
 /*
  * produced with (plaintext.txt contains "test plaintext\0\0")
@@ -449,10 +466,10 @@ bail:
 
        return -1;
 }
+#endif
 
-#if defined(MBEDTLS_CONFIG_H) && !defined(MBEDTLS_CIPHER_MODE_OFB)
-#else
-
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_OFB))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_ofb))
 static const uint8_t
        /*
         * produced with (plaintext.txt contains "test plaintext\0\0")
@@ -481,7 +498,6 @@ static const uint8_t
                0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
        }
 ;
-
 static int
 test_genaes_ofb(void)
 {
@@ -549,8 +565,8 @@ bail:
 
 #endif
 
-#if defined(MBEDTLS_CONFIG_H) && !defined(MBEDTLS_CIPHER_MODE_XTS)
-#else
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_XTS))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_xts))
 
 static const uint8_t
        /*
@@ -575,10 +591,10 @@ static const uint8_t
                0x5f, 0x31, 0x9e, 0xcd, 0x33, 0x08, 0xa0, 0x44
        }
 ;
-
 static int
 test_genaes_xts(void)
 {
+
        struct lws_genaes_ctx ctx;
        struct lws_gencrypto_keyelem e;
        uint8_t res[32], res1[32], data_unit[16];
@@ -757,30 +773,38 @@ bail:
 int
 test_genaes(struct lws_context *context)
 {
-
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_CBC))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_cbc))
        if (test_genaes_cbc())
                goto bail;
-
+#endif
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_CFB))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_cfb128))
        if (test_genaes_cfb128())
                goto bail;
-
+#endif
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_CFB))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_cfb8))
        if (test_genaes_cfb8())
                goto bail;
-
+#endif
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_CTR))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_ctr))
        if (test_genaes_ctr())
                goto bail;
-
+#endif
+#if (defined(LWS_WITH_MBEDTLS)) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_ecb))
        if (test_genaes_ecb())
                goto bail;
-
-#if defined(MBEDTLS_CONFIG_H) && !defined(MBEDTLS_CIPHER_MODE_OFB)
-#else
+#endif
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_OFB))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_ofb))
        if (test_genaes_ofb())
                goto bail;
 #endif
-
-#if defined(MBEDTLS_CONFIG_H) && !defined(MBEDTLS_CIPHER_MODE_XTS)
-#else
+#if (defined(LWS_WITH_MBEDTLS) && (!defined(MBEDTLS_CONFIG_H) || defined(MBEDTLS_CIPHER_MODE_XTS))) || \
+    (!defined(LWS_WITH_MBEDTLS) && defined(LWS_HAVE_EVP_aes_128_xts))
        if (test_genaes_xts())
                goto bail;
 #endif
index 31137b0..8203190 100644 (file)
@@ -28,7 +28,9 @@ int main(int argc, const char **argv)
        lwsl_user("LWS gencrypto apis tests\n");
 
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
        info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
        info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
 
        context = lws_create_context(&info);
diff --git a/minimal-examples/api-tests/api-test-gencrypto/selftest.sh b/minimal-examples/api-tests/api-test-gencrypto/selftest.sh
deleted file mode 100755 (executable)
index 16d1e2e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=1
-
-dotest $1 $2 apiselftest
-exit $FAILS
index 64e8bde..3a53382 100644 (file)
@@ -1,66 +1,13 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-api-test-jose C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-api-test-jose)
 set(SRCS main.c jwk.c jws.c jwe.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_JOSE 1 requirements)
 
@@ -68,10 +15,14 @@ if (requirements)
 
        add_executable(${SAMP} ${SRCS})
 
+       if (NOT (LWS_WITH_MBEDTLS AND NOT LWS_HAVE_mbedtls_internal_aes_encrypt))
+               add_test(NAME api-test-jose COMMAND lws-api-test-jose)
+       endif()
+
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 2519ef4..e403b2d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-api-test-jose - RFC7516 jwe tests
  *
- * Written in 2010-2018 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
@@ -82,7 +82,7 @@ test_jwe_a1(struct lws_context *context)
        }
 
        /* converts a compact serialization to jws b64 + decoded maps */
-       if (lws_jws_compact_decode(ex_a1_compact, strlen(ex_a1_compact),
+       if (lws_jws_compact_decode(ex_a1_compact, (int)strlen(ex_a1_compact),
                                   &jwe.jws.map, &jwe.jws.map_b64, temp,
                                   &temp_len) != 5) {
                lwsl_err("%s: lws_jws_compact_decode failed\n", __func__);
@@ -100,7 +100,7 @@ test_jwe_a1(struct lws_context *context)
        /* allowing for trailing padding, confirm the plaintext */
        if (jwe.jws.map.len[LJWE_CTXT] < strlen(ex_a1_ptext) ||
            lws_timingsafe_bcmp(jwe.jws.map.buf[LJWE_CTXT], ex_a1_ptext,
-                               strlen(ex_a1_ptext))) {
+                               (uint32_t)strlen(ex_a1_ptext))) {
                lwsl_err("%s: plaintext AES decrypt wrong\n", __func__);
                lwsl_hexdump_notice(ex_a1_ptext, strlen(ex_a1_ptext));
                lwsl_hexdump_notice(jwe.jws.map.buf[LJWE_CTXT],
@@ -134,9 +134,9 @@ test_jwe_a1(struct lws_context *context)
        /* we require a JOSE-formatted header to do the encryption */
 
        jwe.jws.map.buf[LJWS_JOSE] = temp;
-       jwe.jws.map.len[LJWS_JOSE] = lws_snprintf(temp, temp_len,
+       jwe.jws.map.len[LJWS_JOSE] = (uint32_t)lws_snprintf(temp, (unsigned int)temp_len,
                        "{\"alg\":\"%s\",\"enc\":\"%s\"}", "RSA-OAEP", "A256GCM");
-       temp_len -= jwe.jws.map.len[LJWS_JOSE];
+       temp_len -= (int)jwe.jws.map.len[LJWS_JOSE];
 
        /*
         * dup the plaintext into the ciphertext element, it will be
@@ -155,7 +155,7 @@ test_jwe_a1(struct lws_context *context)
        n = lws_gencrypto_bits_to_bytes(jwe.jose.enc_alg->keybits_fixed);
        if (lws_jws_randomize_element(context, &jwe.jws.map, LJWE_EKEY,
                                      lws_concat_temp(temp, temp_len),
-                                     &temp_len, n,
+                                     &temp_len, (unsigned int)n,
                                      LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) {
                lwsl_err("Problem getting random\n");
                goto bail;
@@ -185,7 +185,7 @@ test_jwe_a1(struct lws_context *context)
        temp_len = sizeof(temp);
 
        /* converts a compact serialization to jws b64 + decoded maps */
-       if (lws_jws_compact_decode(compact, strlen(compact), &jwe.jws.map,
+       if (lws_jws_compact_decode(compact, (int)strlen(compact), &jwe.jws.map,
                                   &jwe.jws.map_b64, temp, &temp_len) != 5) {
                lwsl_err("%s: lws_jws_compact_decode failed\n", __func__);
                goto bail;
@@ -299,7 +299,7 @@ test_jwe_a2(struct lws_context *context)
 
        /* converts a compact serialization to jws b64 + decoded maps */
        if (lws_jws_compact_decode((const char *)ex_a2_compact,
-                                  strlen((char *)ex_a2_compact),
+                                  (int)strlen((char *)ex_a2_compact),
                                   &jwe.jws.map, &jwe.jws.map_b64,
                                   (char *)temp, &temp_len) != 5) {
                lwsl_err("%s: lws_jws_compact_decode failed\n", __func__);
@@ -500,7 +500,7 @@ test_jwe_ra_ptext_1024(struct lws_context *context, char *jwk_txt, int jwk_len)
 
        /* reuse the rsa private key from the JWE Appendix 2 test above */
 
-       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, jwk_len) < 0) {
+       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, (unsigned int)jwk_len) < 0) {
                lwsl_notice("%s: Failed to decode JWK test key\n", __func__);
                goto bail;
        }
@@ -509,7 +509,9 @@ test_jwe_ra_ptext_1024(struct lws_context *context, char *jwk_txt, int jwk_len)
 
        if (lws_jws_dup_element(&jwe.jws.map, LJWE_CTXT,
                                lws_concat_temp(temp, temp_len), &temp_len,
-                               ra_ptext_1024, sizeof(ra_ptext_1024), 0)) {
+                               ra_ptext_1024, sizeof(ra_ptext_1024),
+                               lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN,
+                                                     sizeof(ra_ptext_1024)))) {
                lwsl_notice("%s: Not enough temp space for ptext\n", __func__);
                goto bail;
        }
@@ -525,10 +527,10 @@ test_jwe_ra_ptext_1024(struct lws_context *context, char *jwk_txt, int jwk_len)
        }
 
        jwe.jws.map.buf[LJWE_JOSE] = rsa256a128_jose;
-       jwe.jws.map.len[LJWE_JOSE] = strlen(rsa256a128_jose);
+       jwe.jws.map.len[LJWE_JOSE] = (uint32_t)strlen(rsa256a128_jose);
 
        n = lws_jwe_parse_jose(&jwe.jose, jwe.jws.map.buf[LJWE_JOSE],
-                              jwe.jws.map.len[LJWE_JOSE],
+                              (int)jwe.jws.map.len[LJWE_JOSE],
                               lws_concat_temp(temp, temp_len), &temp_len);
        if (n < 0) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
@@ -557,7 +559,7 @@ test_jwe_ra_ptext_1024(struct lws_context *context, char *jwk_txt, int jwk_len)
 
        /* now we created the encrypted version, see if we can decrypt it */
 
-       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, jwk_len) < 0) {
+       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, (unsigned int)jwk_len) < 0) {
                lwsl_notice("%s: Failed to decode JWK test key\n", __func__);
                goto bail;
        }
@@ -625,19 +627,21 @@ test_jwe_r256a192_ptext(struct lws_context *context, char *jwk_txt, int jwk_len)
 
        /* reuse the rsa private key from the JWE Appendix 2 test above */
 
-       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, jwk_len) < 0) {
+       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, (unsigned int)jwk_len) < 0) {
                lwsl_notice("%s: Failed to decode JWK test key\n", __func__);
                goto bail;
        }
 
        /*
         * dup the plaintext into the ciphertext element, it will be
-        * encrypted in-place to a ciphertext of the same length
+        * encrypted in-place to a ciphertext of the same length + padding
         */
 
        if (lws_jws_dup_element(&jwe.jws.map, LJWE_CTXT,
                                lws_concat_temp(temp, temp_len), &temp_len,
-                               ra_ptext_1024, sizeof(ra_ptext_1024), 0)) {
+                               ra_ptext_1024, sizeof(ra_ptext_1024),
+                               lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN,
+                                                     sizeof(ra_ptext_1024)))) {
                lwsl_notice("%s: Not enough temp space for ptext\n", __func__);
                goto bail;
        }
@@ -653,10 +657,10 @@ test_jwe_r256a192_ptext(struct lws_context *context, char *jwk_txt, int jwk_len)
        }
 
        jwe.jws.map.buf[LJWE_JOSE] = rsa256a192_jose;
-       jwe.jws.map.len[LJWE_JOSE] = strlen(rsa256a192_jose);
+       jwe.jws.map.len[LJWE_JOSE] = (uint32_t)strlen(rsa256a192_jose);
 
        n = lws_jwe_parse_jose(&jwe.jose, jwe.jws.map.buf[LJWE_JOSE],
-                              jwe.jws.map.len[LJWE_JOSE],
+                              (int)jwe.jws.map.len[LJWE_JOSE],
                               lws_concat_temp(temp, temp_len), &temp_len);
        if (n < 0) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
@@ -684,7 +688,7 @@ test_jwe_r256a192_ptext(struct lws_context *context, char *jwk_txt, int jwk_len)
        lws_jwe_destroy(&jwe);
        lws_jwe_init(&jwe, context);
 
-       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, jwk_len) < 0) {
+       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, (unsigned int)jwk_len) < 0) {
                lwsl_notice("%s: Failed to decode JWK test key\n", __func__);
                goto bail;
        }
@@ -755,19 +759,21 @@ test_jwe_r256a256_ptext(struct lws_context *context, char *jwk_txt, int jwk_len)
 
        /* reuse the rsa private key from the JWE Appendix 2 test above */
 
-       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, jwk_len) < 0) {
+       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, (unsigned int)jwk_len) < 0) {
                lwsl_notice("%s: Failed to decode JWK test key\n", __func__);
                goto bail;
        }
 
        /*
         * dup the plaintext into the ciphertext element, it will be
-        * encrypted in-place to a ciphertext of the same length
+        * encrypted in-place to a ciphertext of the same length + padding
         */
 
        if (lws_jws_dup_element(&jwe.jws.map, LJWE_CTXT,
                                lws_concat_temp(temp, temp_len), &temp_len,
-                               ra_ptext_1024, sizeof(ra_ptext_1024), 0)) {
+                               ra_ptext_1024, sizeof(ra_ptext_1024),
+                               lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN,
+                                                     sizeof(ra_ptext_1024)))) {
                lwsl_notice("%s: Not enough temp space for ptext\n", __func__);
                goto bail;
        }
@@ -783,9 +789,10 @@ test_jwe_r256a256_ptext(struct lws_context *context, char *jwk_txt, int jwk_len)
        }
 
        jwe.jws.map.buf[LJWE_JOSE] = rsa256a256_jose;
-       jwe.jws.map.len[LJWE_JOSE] = strlen(rsa256a256_jose);
+       jwe.jws.map.len[LJWE_JOSE] = (uint32_t)strlen(rsa256a256_jose);
 
-       n = lws_jwe_parse_jose(&jwe.jose, rsa256a256_jose, strlen(rsa256a256_jose),
+       n = lws_jwe_parse_jose(&jwe.jose, rsa256a256_jose,
+                              (int)strlen(rsa256a256_jose),
                               lws_concat_temp(temp, temp_len), &temp_len);
        if (n < 0) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
@@ -813,7 +820,7 @@ test_jwe_r256a256_ptext(struct lws_context *context, char *jwk_txt, int jwk_len)
        lws_jwe_destroy(&jwe);
        lws_jwe_init(&jwe, context);
 
-       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, jwk_len) < 0) {
+       if (lws_jwk_import(&jwe.jwk, NULL, NULL, jwk_txt, (unsigned int)jwk_len) < 0) {
                lwsl_notice("%s: Failed to decode JWK test key\n", __func__);
                goto bail;
        }
@@ -1005,38 +1012,33 @@ static const char *rsa_key_4096_no_optional =
  */
 
 static char *jwe_compact_rsa_cbc_openssl =
-       "eyAiYWxnIjoiUlNBMV81IiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9"
-       "."
-       "mWXwMv4hxwgKbUAyMFAuHxiKjg62Z5owkFYLgxho5FNT3Hm5ZGiF8plS5W3NwUTmv8t6C"
-       "I0kV5cOOJXE_PXPaOptsie2aoQR-_Bs6gAFixa7aZNsnsMF4lMAiIy7VkrvP2qh0s04y2"
-       "2poOLfmS93tB9AyWdlnQ6Z-U1wzrM9kncqO9GpPol9M4WnAss1ZtTE-9Tbc7dMHURHbZb"
-       "vHn2h625pBD8oD_s0osRav8YEw7jNeQjW_ch4pI6HRox-hf0dyLtk9yFCtBjxbCvysadW"
-       "SlZPJBj0HYv0BVqCK0fETi7URx4MCJ3zgCJnpAuQo2yq1yQzXwOYcFoLIvY0jIm44A"
-       "."
-       "WINMABhU_GQKJarmmTP_-g"
-       "."
-       "V9kHAh9ajE558EPj_zX6p_C903MevMPJLcMU4MWhfhwe1cFW_0io-LvZfcF_Xj7aNoIZd"
-       "vPXJ0On_jHPFsnwe4dus6kuh8RrSKFFV0sGIv-FFXrKB99FFRY_8BTPsYFrcqt_8EV2Af"
-       "p7toaVOO15WXOEH6Ym81a3aOWCVGdj_akMN46Qx_JrQaql-Xs_fL2HdpaEWHHTV2ac9aY"
-       "ah7o0Ojl9UnzkHyXieRgrjXymvCcT0te3D4OQJhrv7TzH_hfKu621O-Frmkr-NvQGSNcl"
-       "fVgRkte2ks34j5HPqEbJQWWKG3IDfkPRvWmDZzEXW_JTrK_1r1FM-aYtY79tLnir8Zw7I"
-       "WCczD-XmtlOJNYA2Ss5dbjoJDtevbqaZWVl-sDSwO1xdf-DUfiemep7S7IFoFAdl0vXLT"
-       "YtuNBxuFw-cP2Kwi8RyF__uENo4vD003cI4htqSYIYXeyAVqWIkmsP1BFpT7MGixfvhAu"
-       "VCj_ToJmowGY3bOHiMuzyT9M7wtCCiCySEBARVU-EdQBXj8X-quSj-0OnBtxXChUS4QXw"
-       "q2pNn3UKSMsxqvHR25HQq_6U2AbvNHxKhup3luzn0T27uy0l3XeWSz_48SwJZKRnbYPtC"
-       "n5Jd5mRdr5GxihpNwupaO4BWnHZo_fHUTI9-Z18lpj_4QB-c3dzDL15xFN4HEZ5lv2iO5"
-       "zMiRI_NlVVDdA9lqGpn4IyO44osHQieBraUjWF8X5cSXDoqktXDVymAdrxe0fYZQca6Bq"
-       "CsBqFTYae4CG01SpG46ysfwAXmsTEKPzj7uiOguFCRB4hClTd-Q8R2axj9JNT1jU_Vb7U"
-       "GKFBGeDJt5PDXJyvW5rHyiQDewykf0Lpvdp39yITT8qARmJl2SwCrDCPADZ4TwwobT42B"
-       "J_Cq5IKgEOeuS3S7NOdOfXxmAcNfN0yujKbmfiOxnXhwnepQ-TnpgTV0nv8snBRITN7mS"
-       "EgflqQlKAZus_0mDbHmBmw1nY-0q4qMWI03IEwMC57-p4JLshnWgIAupnFCGp9nyi4E_s"
-       "GVyQlGCxzC5VSH1Hba3rvbulQGxx_kGk0j56NGhGsQEzqvSuI4xgIsGMPo1Ii7xUh68dd"
-       "BzJRzaov9oDTgnWM5-hoEQQoazW7hDKAFPYccC6zqX0fnI7vBIIBZsjUsol6-5bdujpb4"
-       "l3LRGCjULXlSPbnNGzyk5R-mIwQC8aM9wcIiZZdcdHdr4meMNr3HmpG_B5xtBmENAJAvU"
-       "K3DO6pro2xhypuNKYtOAdH0Xyl8QBPIJ0EFVH6_1V-H_gHs2MLMIqGfUmFCuRev60APcw"
-       "Pbf-GZxLeXLutPq2DOl1HD0XLNtYL1dB1aw2j4L8OJREOC_N-KpIH3g"
-       "."
-       "n4QRlTzW2urRnNiJlwQkZw"
+        "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0."
+        "HgQBfAg2IUpExcs74-gtuSOciw6rxh2cc4x9MVRWDZKSvMqoBYKAxl6ebSxGTReHhbvhv2Rm8stKq"
+        "OIROhWzTNGTQPnSRMzAm9x6ms39hAIGh1KCEZ47MRYkCN7hElfDVtczOCX3ZRsG9_qYEmzcY1aJ-4"
+        "_LS3yeP0HfqKBmcfvjVLw-KqcUuHp5YXsZEvt28nA9uBlCN0ROWy_2Fs-zlQj8pDMWo5pZrffKTUX"
+        "gUh_UJ9eC3qNyXtQSqUH-5vDeHPhxNnIJOsmJ5ZUAjxXPm-RJZRC9THg0DzGRZn9IqfP9qcanbcZ8"
+        "iow7gjFh1EPp3MKlpZqDKbLLei1WZvz2_A."
+        "q4STtyu4yxZfH1HNDYlYcA."
+        "_uRfuwWO22_auSqXHORw_e_Q6PmbpC0sv0tefVKsj3Zqnh2qUBlj10kiWBMWoMMjqsClBO0nUoup4"
+        "c7i1YSqxlCHliXru3athv_EYtg5qvC-z2co9NiFABHCHmBDrhj7CuKN5gqFDt1EbYMLwWtU3gOnQy"
+        "dvnzfFcQs4_jKi6tRpQzbobrkkZ2p7Y_ltjA1Wmwqrp9O8DGSRnvcomqzGHcshuyxTkjLDzD8TSMR"
+        "S1kp-miy5eDGAcp-ymWiUKN7gswy5FPjPQYzgs7Vc0n0R1ljepRHJiHaP61z_DKWXrCE6RqAVqnaw"
+        "TjjVOXXKKF9pz9W7pZL8diLZ0Ueev6xk8wzRRsUChM5toQNzFLXsnzSDQSzfSKpRnLjYvosiEegyx"
+        "RrwtQwEcNCXRj0aGxG6e_W79JdUJoi4blpTtrAVn_pk7SgRiU3aly1vso5tV_0kvMOcS6Hn38mqRQ"
+        "PQxbdIpohi8C7FFabluZqGoiji8ZTM3v-2ib2vrBFj1YvoyPG1HXJsABINzo0xOkrMFNfN_oQrCSM"
+        "Ij49N86GXmYOnu5jtZeSMXZIR2BAXnu0upXMsvtSjU8D-LJJChy0XNYoyuJar5P3YhDStdTfmn0z-"
+        "XLwaIHWc1L9-rmW9CZey3HxCLKEnr7-FjXsXqzAArsFqn1X_sVR5HRHng5ioc7sUaRoC1S_k0XPVC"
+        "qCjZvkbRry2cp2313DNwjl8SK-iZA0fVUZVPM7_eZfpEgB3bBTyamtAaqQeES6lcVEtpg176Mlh64"
+        "3JCAjroJPP4eqAA3JHnDgwlO-XhlLPTNNQ5FMLBC_dp41A-H3HFlbQUR6jX3k_H4Ggqtit50EIye3"
+        "nnKb3emFn9KVyeZCYaBecYbicEIMKW7sWLbcE_cDGqkHZcMGTOQKRiLp-xwyEu89oDGAcGBYpmC_f"
+        "iQ2qyFfe6tQK_5nPZbtW2mudiYZ-d0YIURSTp58S_n6w3wLDUEcuZtv-nhCaFVy8oUbAztkBIK6pu"
+        "VamKhHVLkCtOGIdNJYbLKAedhK1lQVPbrvfcSDPPkhxSx9AjKqhKA3ZPMA_UXQb6p9c33tgi_MdZX"
+        "-jRGXwGKWBCrv4UjttFLV-a5U7NgxQIIjwfAoutXtYardFw2d5nTJRqBrw06PSqaLzQi616_b-U0g"
+        "6bWxrFObIWrKODkGfQcXPXIQxW_4Vh6gR2GaHSi_A_5SGH0zsBtYxisbKXLK2HiZJOXBew4-am6c0"
+        "R1jBh7QtOWpwrYWt0d_xxrWtKezeEp3FkrFkwWCgY9dT1uV8tKUuxeeGqshkrXifT4axttpkbi-qA"
+        "eG_C6J-H29CPqScclD-A5LIg7k-KmA9hsWrXttAvoCSawNj1tv9JHq0jgP1yZytDW1DkWdCBY0au5"
+        "4."
+        "qqYQEaGx-lUHoO43fOXvKQ"
 ;
 
 
@@ -1057,7 +1059,7 @@ test_jwe_r256a128_jwe_openssl(struct lws_context *context)
 
        /* converts a compact serialization to jws b64 + decoded maps */
        if (lws_jws_compact_decode((const char *)jwe_compact_rsa_cbc_openssl,
-                                  strlen((char *)jwe_compact_rsa_cbc_openssl),
+                                  (int)strlen((char *)jwe_compact_rsa_cbc_openssl),
                                   &jwe.jws.map, &jwe.jws.map_b64,
                                   temp, &temp_len) != 5) {
                lwsl_err("%s: lws_jws_compact_decode failed\n", __func__);
@@ -1102,7 +1104,33 @@ bail:
 
 static char
 *jwe_compact_rsa_cbc_mbedtls =
-       "eyAiYWxnIjoiUlNBMV81IiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.oBqKJ06UJs2oryPLWZKyI8743GC0geUt_xaKLMaPtApp__swG2w0IhNtmkIBKA9LeeGyiCWKpGGzOlQUR5YSxrT99PnincHXw_pkCprOvi4j3oxThJ2pFRx-CBc9ZgPJ3Kje1QifOueT3vQt_65iiyXmqyc5PDxzuV0L_KtrA_jEsm2m1JVBMOX--qzXjYyqx_dc87d43TXY_4kuTmAtqVpQe7ixKJlUViPVSzuASyeLEUTIaNlALuEWial1wP-ICF37OQzOcZRH3OVZObrcZi1aWkDOLxF4qO4I_GtpuAgZT732a7gnobR-T2oyBpimcqCVEk88Wa7cYyBXZvAOUA.fNLEFh1mjdlyc3WKw0I2Kg.e8X-11K9yXK0KkK-8ikplEWFViruqduaKPDOA7x6lKpBk8l3RFX1aqC4s0WVc1eN0qd-fB__EoO_AIG1xsfw1ie2IDWV0p18ZaRkQRN9Th5UU-W9C9XyPFQUxcl7ShKRE-yKJU-VdZDk6L2-07FH3s-voVKx0oqLIYqkkXp9a2jvnzrZ0Psujs4PSCHOZEgcS8PNdMmdsjDHLsb0NDMifOSlXk2Mp6V2SizXRIPJtOkVJGKwuBc7FbdO02GnzzVXldiLC7GI0zoRsnSJndF8yc3pMrMQhoVRktkBClAcIujD_OxJwHG-i3OJqUg1uVfci86RoQrnULoygvB7apX_WMxF7eXXJdXbG8sPLLCf0SW4sgvuSclOHL2UXzGi6Tp_l1XjxFQTzVEfUaj7i0gD2wM74Ru79RX8yO0m-5qOOwkySU1lEXqbLTuxjJXD9WLcTQQmF0Nm5myTUyNOl7xKpeDpnNt5A0L8o6SW6iJ3DwZEzhMxk3JWQOYtQP1J2sgwAKEDM6SkGzTy9QXpCEoraKp2UEzunux9S6-roYpzgEFT2RZrq3Hg_JyequTtrcNaoiEKd5szJvE6pUc25WEjDzgg79v_n40gQm688mO62kiVBThVmc88u2JVlNpzVQFUfKt-bu2Xxiqn5lRfEMK93EEPZRd8n12vBq5aJKvvEpPN1AC4HaMepf78Ob0GNTYGR-70zSS0ErecCeIgUJ1CttE2Nn0qEOfbQcO48SjeIltecl9DRzeLT3tPN3Z4BqbzSX8kKU5LStUX5YC-obM_0Ss7swXJM19I1O-QH8VbHZl-9TADR6BLzmrsJQ9_BL_uTB6uPdLhYfqWw6VUf0eMLaqvsY92vV5-JVQqyv7s70FNLT1-8P94k79ZGiLvNdDNZgGsmRQOwA2Vk6snHI0oUYGj7NeEK4O64ZfNRZJgPfWnxtQ-LIhSYCJvxFGL7ZMoA_ijKl9_v_bRqd03_7o8YQisw2luDYqLa87Dh9u9tacOoraGAzcEBIAh-BOcnIrQEt5KoSbly5xNAkfqj7QDvL0vPHArZ5E3Gb_k3VbKjsqCzvisNMEjm887Z-Dc6tW4Y2OceYf-rfUDvJ3EXZ66CWSQ7yKhPVcP1RRtNUFEqLoIAkA4aEAAS2ZPKVHIJQwyMzbbNFAuvY_7piNYprAI5lySFcA1cz_hKl6s9xmqbAkH2XGZZduw5Nv-aY_LMXujjhmblqE2Ocej91xTdgMe74Ftr1b3y9FvPPVSqNjpTSfujCi5L57LOpjT78do8eSrDz6coG0zeRUybjWeTszoiYbif_NlyAcMScO5OMZHNkre6L8u-AVeYSKTGsdpK7em_iLN8cGSEjZABNAr_A9Lfg.6Qb_Qf-ktX0DRHWUHAJxDQ"
+       "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.Ptg-RZjEhY1dWg7T"
+       "v72rqRoHXBeory9ePCC5cfASTz8BH7IdSLQcPeBWHQsmd13TXPjo-dxnmkWkx9AyKdvy"
+       "K0A6oCnsP7KfbGzPwTy5eadpaaDZ3UyXIGmusLgiXGgDZ4d13voirbRQV9nQTPsagG_k"
+       "FGRI5dKzenG2WcbUhKG-uCmypzYqjNM3LqUzdH42jjjHFOBkmK_sWSZL7Uxqq8s08hkO"
+       "aXeUQyeM7Z8wm1bsZAvIfGri5LMcBS8P70AyENchlchZpTeACIOWk19ddLPUt-ruEcm0"
+       "zZV7Gjap7uG06a0m3VyR3vMpKkXnBHQxko-RICU2PDmELVXg0pZWTw.-VaaDaUiynH_t"
+       "sh2HqKISQ.vVE8j1TQinb4anJk0ArV9ccYdlUIO20vnMa7b-JGfQ7CFi_WVt6xNaqytB"
+       "QqiTHLtAxBDIV4m9Kwid-8Kcx7BmRqu-memxHztBSvBNOYWVPTxy5I2ORGLNEbPVrFYp"
+       "c2nm3TnHfr-_2fuw6_HEnyqv_c6ZyzU0-lHZ1pE5Cs-lrjnj4ibNcK6XHhrO3nxUjPMZ"
+       "rO-2B_tZwCxzKsFAqD_XGROvNGWXEgxgIr09MyuwKJnw2oZ0xOF_d3FVYjK5XMONgWPo"
+       "lyDmbP_XLSIUXbHmLxpDB5NPLN8SKRHbMV3_qw5rFRlak2C_XlR58P-Im1PQ8gMg7lgE"
+       "IFz2DrqF4sJA5TYbQG5KCdas0SfONlP1V692dufH5D30RGsiWNSrhiyDmUNC0SeB8VqA"
+       "bmc02pPGgzZHxa5-_xIHKm4h6fmnZFScjliBQ5W6smxQ6m2Kby0MkOdqlRYFn8qLYLmF"
+       "vmVNe_Q5-iLNobx-hyyeeExRXfzNOY0HHEKw67ipBWwqA0JGIggCWAFa0fpA-Wt7sNl_"
+       "gPy96nbwuXIuRoC3wuboUlDp9k2F1vC7VY6R9jdRk1VXT_O3liBIiUIRhZiqZZ75H2RV"
+       "pLYXGrvL5G9THdRcbsg3XUt-kF4vvGQAdNmPdRmuIG1DfGDmOZnXfrG8ckTvxoKBXdQZ"
+       "gfwfAQFgeHjltiWZTCSBV4464sn2qLZ1MP3Ku9bOjb72RCpIF60Cqssb8gTQyXQf48ZR"
+       "OBd242Q7Ae6PePmb_TcnG3jOguNUgmhj8iTU7QUz0uJWpJjMRPJ8vK8SnYEguGHer4qT"
+       "EocdMzRTTZB-Pr4-Ey0Hm0zeiFvjU0Qy6crjna6SKrgms4VAJT9LiicTYFPsmFBFQ0L1"
+       "BVDiZ3NTBIv_ajvzRpBNZ0IxEH5t6W3OY0223xUF3cq8c9HhwIxMf9a2-PmZ3mVWIRnU"
+       "nGegoVkzd2l6el8aw57v5KKYas4-EkovHntCZZ_hkZ1uHtezKq0EvjnT5xGWjPFjOZnh"
+       "veiozAsaMSSyTny6mcI-hjvcgd--7qlqWpt_BEkp9XVkP2k7eHLM9v4rL6hhk_n6yK3w"
+       "qKi0xDboxU5xjuBiGKb-E8um1MUEjuLqZanKSBsgU-Vwvw0gx1r-MG6BSlrgUlT2if5k"
+       "-Wfs6iVdpK7x1zZSsetp3NEjT4DUrfmp_E_CTXhOEP0AgzpQ4Ukx5bFN3gm5gyBZw1E8"
+       "q20Hs01OBcMJ9wenLEQVMvO_IEIkRNBMWEgoZ148As14LNOgdh1UBrF6W4pAUjYvA3WG"
+       "Zp7uG9ooDB1RF2aaeBqoLJflqIegsvsfaNNBDJ-U6i_jLG1FSlttEhJVdXll0gMSYlXD"
+       "O3BBil4eiUPfiksfOmsbwoIxc-3yPTivU3DPM.O_IaktJRbdV66zfhD0LQmw"
 ;
 
 static int
@@ -1122,7 +1150,7 @@ test_jwe_r256a128_jwe_mbedtls(struct lws_context *context)
 
        /* converts a compact serialization to jws b64 + decoded maps */
        if (lws_jws_compact_decode((const char *)jwe_compact_rsa_cbc_mbedtls,
-                                  strlen((char *)jwe_compact_rsa_cbc_mbedtls),
+                                  (int)strlen((char *)jwe_compact_rsa_cbc_mbedtls),
                                   &jwe.jws.map, &jwe.jws.map_b64,
                                   temp, &temp_len) != 5) {
                lwsl_err("%s: lws_jws_compact_decode failed\n", __func__);
@@ -1213,7 +1241,7 @@ test_jwe_a3(struct lws_context *context)
 
        /* converts a compact serialization to jws b64 + decoded maps */
        if (lws_jws_compact_decode((const char *)ex_a3_compact,
-                                  strlen((char *)ex_a3_compact),
+                                  (int)strlen((char *)ex_a3_compact),
                                   &jwe.jws.map, &jwe.jws.map_b64, temp,
                                   &temp_len)  != 5) {
                lwsl_err("%s: lws_jws_compact_decode failed\n", __func__);
@@ -1622,7 +1650,7 @@ test_jwa_c(struct lws_context *context)
         * See test_jwe_a3 above for a more normal usage pattern.
         */
 
-       if (lws_jwe_parse_jose(&jwe.jose, ex_jwa_c_jose, strlen(ex_jwa_c_jose),
+       if (lws_jwe_parse_jose(&jwe.jose, ex_jwa_c_jose, (int)strlen(ex_jwa_c_jose),
                               temp, &temp_len) < 0) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
 
@@ -1770,7 +1798,7 @@ test_ecdhes_t1(struct lws_context *context, const char *jose_hdr,
                                jose_hdr, strlen(jose_hdr), 0))
                goto bail;
 
-       if (lws_jwe_parse_jose(&jwe.jose, jose_hdr, strlen(jose_hdr),
+       if (lws_jwe_parse_jose(&jwe.jose, jose_hdr, (int)strlen(jose_hdr),
                               temp, &temp_len) < 0) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
 
@@ -1787,13 +1815,15 @@ test_ecdhes_t1(struct lws_context *context, const char *jose_hdr,
 
        /*
         * dup the plaintext into the ciphertext element, it will be
-        * encrypted in-place to a ciphertext of the same length
+        * encrypted in-place to a ciphertext of the same length + padding
         */
 
        if (lws_jws_dup_element(&jwe.jws.map, LJWE_CTXT,
                                lws_concat_temp(temp, temp_len), &temp_len,
                                ecdhes_t1_plaintext,
-                               strlen(ecdhes_t1_plaintext), 0)) {
+                               strlen(ecdhes_t1_plaintext),
+                               lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN,
+                                               strlen(ecdhes_t1_plaintext)))) {
                lwsl_notice("%s: Not enough temp space for ptext\n", __func__);
                goto bail;
        }
@@ -1844,7 +1874,7 @@ test_ecdhes_t1(struct lws_context *context, const char *jose_hdr,
        }
 
        /* converts a compact serialization to jws b64 + decoded maps */
-       if (lws_jws_compact_decode(compact, strlen(compact), &jwe.jws.map,
+       if (lws_jws_compact_decode(compact, (int)strlen(compact), &jwe.jws.map,
                                   &jwe.jws.map_b64, temp, &temp_len) != 5) {
                lwsl_err("%s: lws_jws_compact_decode failed\n", __func__);
                goto bail;
@@ -1873,24 +1903,58 @@ bail:
 
 /* AES Key Wrap and AES_XXX_CBC_HMAC_SHA_YYY variations
  *
- * These were created by, eg
- *
- *   echo -n "plaintext0123456" | \
- *   ./lws-crypto-jwe -e "A192KW A256CBC-HS512" -k aes192.key
+ * These were created using the node-jose node.js package
  */
-
-/* "Live long and prosper." */
 static const char
        *akw_ptext = "plaintext0123456",
-       *akw_ct_128_128 = "eyJhbGciOiJBMTI4S1ciLCAiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.zbTfhhWePf1UrCRDxJD_-8eAQr2AoWAL51_nNOv0L4nV3P0e4_9ARA.qWehIhy4j4_gh_h5MF9ZEw.GD40YH6NeNOEkhhxC9ryZA.PEuU6V3rhYXeoxENrAzDgw",
-       *akw_ct_128_192 = "eyJhbGciOiJBMTI4S1ciLCAiZW5jIjoiQTE5MkNCQy1IUzM4NCJ9.zpkr45xH_kSJ5eTBv5dGo5PN_A6YdC4JoJSOw3_VTqcOeAYyCkCAXeGWugqIVLzMzBKgtXdabO8.O28MVhkgfketu5sxQK4Ffw.j25N7luxh251kQwpAoYURQ.Pm_NOj0KZzUq2fV9ARpHxT3Iach9feLK",
-       *akw_ct_128_256 = "eyJhbGciOiJBMTI4S1ciLCAiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.VvFmi121jliyh_UKzsBv7HR3TVY7-yALpcdlasHqdzmfISd8LFU5oc2fEhfn3_TKfCbgRycm5M3103NEMbVSiNULZWvJAPFe.7uLHGFO1g-PgD9YkjPbvoA.AlPwQPWSqGaB_em4qEEyjw.0LgTLld5pSffZnzGG6IRWEwXg7HhClmwP4m_p1yKnHw",
-       *akw_ct_192_128 = "eyJhbGciOiJBMTkyS1ciLCAiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.kxlmi-xn0JN-ZlnSfkVDP-fXvricJ-L63WP2bWddWEiVK4m-os2trw.iarAWaeV873kh5s7HjoZ4Q.nFHEpnnIxvbCiYfFfsLj7Q.karz-h-R93dJgwN_YZyPmw",
-       *akw_ct_192_192 = "eyJhbGciOiJBMTkyS1ciLCAiZW5jIjoiQTE5MkNCQy1IUzM4NCJ9.D869MEk-JERZU_4MgFuL_6Pg24LUEbXlTvGj-t_JUnNFsJ0p8fk5L-iOATqPmx2g7AyVWgcUqU0.RrxzDsy6Bne1pzx99PBGsA.C-ZWmMwd1uswYkvhKX2_jg.bIFY0TmGuohI2APxDZyFUYpa6s1Mx2j1",
-       *akw_ct_192_256 = "eyJhbGciOiJBMTkyS1ciLCAiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.XNOBw0Dy1paAX2_XGkZYm2Zm455i8InAVMqM3aOrVDpXYBAADuZ_Ke_dlo3Fc8J5b9m_KNCUtVUU8f3KV0sY-yESsqyZTSXk.n3wEIV1-tL50JAp4H19Y1w.ODPd-oxmpCai9CzqaO0P3Q.b9z08hJTySSVSOw-4qp5lrTEcUur46L-RRB-SEcqPpk",
-       *akw_ct_256_128 = "eyJhbGciOiJBMjU2S1ciLCAiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.THaIbHUOHkr7McMeiQqIO_gBcm61F0BKx79JXkzQVVSF7m0u7Z6uhA.RAU8Yx_a9rbWeqr_0YyLZA.zzfdv55bM-qblTxaR5pNzQ.cySMIOTOcEoFkcVn0D6RKQ",
-       *akw_ct_256_192 = "eyJhbGciOiJBMjU2S1ciLCAiZW5jIjoiQTE5MkNCQy1IUzM4NCJ9.gFcfX6fVrpmDJWN5jPqSWEvpOOoNuV4Yn2KO47p1wGsdw5qIw3r5AO5U8zOEtoGNVX68IC8vkpo.9w3tBsve4e-77lI-S9cFog.Vj3L009JDipPJlHY0tS4Iw.WYGgCedW4SmxleDF3P6Hx26BUXxnizxl",
-       *akw_ct_256_256 = "eyJhbGciOiJBMjU2S1ciLCAiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.ldhqlMf2LJrZ7EDl-oZvaqi0b_KPGy4cMRx2QDpKtTg92tTSWF7ALVHPPCyT4qccIybP4rygajKfdC_Q_UE16KFyUvXhBgaj.S9OCmKpY0zDkArLF5XsrJw.zvJ1X-zuHsrwLXGJJbglPA.WaRKb7Le2ZQ30pGQAV3sfp-YY1563KXxPURHQ8ntdPc",
+       *akw_ct_128_128 = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Ii"
+       "wia2lkIjoiLTRXTEpQNWNrYUxBUFFFNXkwYXhLT0JUSTlFTngxUXBCa0toNkdOY2loOC"
+       "J9.h6oNSEgz3LwIMndEkPEa8H7_5zy0hh8TaU_1yWoNtu4Dh_WJpEgx9g.j7TYjj8wB0"
+       "RS6rclTWYmqw.zm3tPzuWhXoD7IsAWbA0xz-AJXvE9gydWPRBTaO40sQ.Okf7ttWDLPM"
+       "wIj1kUyUO_A",
+       *akw_ct_128_192 = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTkyQ0JDLUhTMzg0Ii"
+       "wia2lkIjoiLTRXTEpQNWNrYUxBUFFFNXkwYXhLT0JUSTlFTngxUXBCa0toNkdOY2loOC"
+       "J9.XkRTu4nP3b0KZxXjkjdHEnbf6AWZUmFvpsqZLuLxKcrONqDUsnYasnVuo6U0QKRUm"
+       "cyBRtSPGW4.MzNxxoOp8JR2AHoLNve-vw.rdxgo6InRAxk3afG02_75l58u5m6KYHd3h"
+       "LH16ksnZE.v7BLKaRZIwhUPhhBRTd8yPwH0xa1fOft",
+       *akw_ct_128_256 = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIi"
+       "wia2lkIjoiLTRXTEpQNWNrYUxBUFFFNXkwYXhLT0JUSTlFTngxUXBCa0toNkdOY2loOC"
+       "J9.mueR-8XzXs2RyvzzvghpIpGS1mGl7vkSjJDF5zqhH8-ektBpCXSd7R7MS5nh2-Xf_"
+       "8XDym1gn1QEQh5bDI3GPESnSN1TJR-h.g6plL_5L2BD8wcjZS7X79A.UTndfTFhGFaVZ"
+       "vWqPkV7dN00gckesd_7UylosVDqjwU.-rgi0jkYuCZDMwUVLxN6e6x8fXw2U0u4-vL8u"
+       "Kb__S8",
+       *akw_ct_192_128 = "eyJhbGciOiJBMTkyS1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Ii"
+       "wia2lkIjoiai10RWp2Q2JyNVlUZWtKUXlES3kyQXh5cjBWeUlUWXk4S3IycjB0cy1USS"
+       "J9.mEURnj2NvPa3TU0uR8mcm2cMd33Y6iYYZ_LFrYS_Gz49gcdxZpdk1Q.v3csq81X9o"
+       "mI-bcp6i-FTQ.EgroRqmqNfeH7XC9msLap1IGcqvc09SlnI4PO6RQqS0.hDi57mXD3vX"
+       "dx2r4Kwnv9w",
+       *akw_ct_192_192 = "eyJhbGciOiJBMTkyS1ciLCJlbmMiOiJBMTkyQ0JDLUhTMzg0Ii"
+       "wia2lkIjoiai10RWp2Q2JyNVlUZWtKUXlES3kyQXh5cjBWeUlUWXk4S3IycjB0cy1USS"
+       "J9.QHgtusQdP7Zvw9tsCZNkJyEmzg6KUaaIyTb2BXB0ng9mxSUIQ7y_6oqasYKBUJgBn"
+       "Koru-3CXOE.ZZXcGY35mmlAb4-IgA5XlQ.AuG2GRPeYJ80_4XoYAUgXbVY65ZQ689Grn"
+       "x8RCNQdfc.UjfgDr4z3PGQBdftWT2gqx1Egfd9PUR4",
+       *akw_ct_192_256 = "eyJhbGciOiJBMTkyS1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIi"
+       "wia2lkIjoiai10RWp2Q2JyNVlUZWtKUXlES3kyQXh5cjBWeUlUWXk4S3IycjB0cy1USS"
+       "J9.G6DziymYyU3-6unIa-Oz-0lksH05OJFDZKkFuShMuoazEMZ5ZH2S_65qD-pjpf8aN"
+       "2thOVOYT0mdtgFM0ARUfx8ZLhRFCcn1.yEKK4eARZIo9WtGVcQmgDQ.ovan2NXDmt_Ka"
+       "SsVJmhIMQqVz6meqz1oExfVcY8vdzA.R3T4lQIKX5cc2Ktv42e9u5PR--v_w2uK7F4Wp"
+       "Sr5SQ8",
+       *akw_ct_256_128 = "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Ii"
+       "wia2lkIjoiSDVwSzRRUU81U0tHbDA3UXhIdk9YMzVqS2FJbzA2NXVLdWRubVZFZVpJYy"
+       "J9.ZLWrz5CE7Iav2db37VL9ZABeaRVrV9af-7-46Loc9M2D0SPSNtsxpg.ktk-VU8-5b"
+       "XRvW_A6IqDjQ.xZVIglOhadDBHUYuxPx6Wr_YzOo0qCDH24xVe58qP9Q.pO_tME930wO"
+       "u5fNJ8ubGrw",
+       *akw_ct_256_192 = "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMTkyQ0JDLUhTMzg0Ii"
+       "wia2lkIjoiSDVwSzRRUU81U0tHbDA3UXhIdk9YMzVqS2FJbzA2NXVLdWRubVZFZVpJYy"
+       "J9.fcblAVZ7VOXtyhymqxDBr-zgvId18p3AURNbhH5FmAvKNuUVU37xPkz6BrFopLP0J"
+       "jqXaTyyg1s.fprTe2e0esH2w7EnLEgBZQ.g1BI0U1aKSM_JBEp9jC4BxBaFXVG5BW4nl"
+       "bhX1MDeLo.XOLanrIkitLLDRONnfM05avahl_lJ_UY",
+       *akw_ct_256_256 = "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIi"
+       "wia2lkIjoiSDVwSzRRUU81U0tHbDA3UXhIdk9YMzVqS2FJbzA2NXVLdWRubVZFZVpJYy"
+       "J9.SpizfgtzQLJCCnYnUmNfiMMTyL8iIDi8OyUDrO00KJtfwJdNAcs-NuYQkLKx6PlDJ"
+       "IGjucT4-IuA8k_Oc752kq1BzTHMZ-Mo.go-e8xpQoCmLD5RBQw7ruA.WqkEdM6T1_z5F"
+       "C-8eGQfGjos7cHPy1ecZk1Ep-TYgXo.bZVHhIpe2PbjguQlK_afkYDlVmEtRAe3LUJUX"
+       "4STOtU",
        *akw_key_128 = "{\"k\":\"JjVJVh8JsXvKf9qgHHWWBA\",\"kty\":\"oct\"}",
        *akw_key_192 = "{\"k\":\"BYF6urCMDRMKFXXRxXrDSVtW71AUZghj\",\"kty\":\"oct\"}",
        *akw_key_256 = "{\"k\":\"cSHyZXGEfnlgKud21cM6tAxRyXnK6xbWRTsyLUegTMk\",\"kty\":\"oct\"}"
@@ -1912,7 +1976,7 @@ test_akw_decrypt(struct lws_context *context, const char *test_name,
        }
 
        /* converts a compact serialization to jws b64 + decoded maps */
-       if (lws_jws_compact_decode(ciphertext, strlen(ciphertext),
+       if (lws_jws_compact_decode(ciphertext, (int)strlen(ciphertext),
                                   &jwe.jws.map, &jwe.jws.map_b64,
                                   temp, &temp_len) != 5) {
                lwsl_err("%s: lws_jws_compact_decode failed\n", __func__);
@@ -1929,7 +1993,7 @@ test_akw_decrypt(struct lws_context *context, const char *test_name,
        /* allowing for trailing padding, confirm the plaintext */
        if (jwe.jws.map.len[LJWE_CTXT] < strlen(akw_ptext) ||
            lws_timingsafe_bcmp(jwe.jws.map.buf[LJWE_CTXT], akw_ptext,
-                               strlen(akw_ptext))) {
+                               (uint32_t)strlen(akw_ptext))) {
                lwsl_err("%s: plaintext AES decrypt wrong\n", __func__);
                lwsl_hexdump_notice(akw_ptext, strlen(akw_ptext));
                lwsl_hexdump_notice(jwe.jws.map.buf[LJWE_CTXT],
@@ -1978,18 +2042,20 @@ test_akw_encrypt(struct lws_context *context, const char *test_name,
        /* we require a JOSE-formatted header to do the encryption */
 
        jwe.jws.map.buf[LJWS_JOSE] = temp;
-       jwe.jws.map.len[LJWS_JOSE] = lws_snprintf(temp, temp_len,
+       jwe.jws.map.len[LJWS_JOSE] = (uint32_t)lws_snprintf(temp, (unsigned int)temp_len,
                        "{\"alg\":\"%s\", \"enc\":\"%s\"}", alg, enc);
-       temp_len -= jwe.jws.map.len[LJWS_JOSE];
+       temp_len -= (int)jwe.jws.map.len[LJWS_JOSE];
 
        /*
         * dup the plaintext into the ciphertext element, it will be
-        * encrypted in-place to a ciphertext of the same length
+        * encrypted in-place to a ciphertext of the same length + padding
         */
 
        if (lws_jws_dup_element(&jwe.jws.map, LJWE_CTXT,
                                lws_concat_temp(temp, temp_len), &temp_len,
-                               akw_ptext, strlen(akw_ptext), 0)) {
+                               akw_ptext, strlen(akw_ptext),
+                               lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN,
+                                                         strlen(akw_ptext)))) {
                lwsl_notice("%s: Not enough temp space for ptext\n", __func__);
                goto bail;
        }
@@ -1999,7 +2065,7 @@ test_akw_encrypt(struct lws_context *context, const char *test_name,
        n = lws_gencrypto_bits_to_bytes(jwe.jose.enc_alg->keybits_fixed);
        if (lws_jws_randomize_element(context, &jwe.jws.map, LJWE_EKEY,
                                      lws_concat_temp(temp, temp_len),
-                                     &temp_len, n,
+                                     &temp_len, (unsigned int)n,
                                      LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) {
                lwsl_err("Problem getting random\n");
                goto bail;
@@ -2012,7 +2078,7 @@ test_akw_encrypt(struct lws_context *context, const char *test_name,
                goto bail;
        }
 
-       n = lws_jwe_render_compact(&jwe, compact, compact_len);
+       n = lws_jwe_render_compact(&jwe, compact, (unsigned int)compact_len);
        if (n < 0) {
                lwsl_err("%s: lws_jwe_render_compact failed: %d\n",
                         __func__, n);
@@ -2076,7 +2142,7 @@ test_jwe_json_complete(struct lws_context *context)
 
        lws_jwe_init(&jwe, context);
 
-       if (lws_jwe_parse_jose(&jwe.jose, complete, strlen(complete),
+       if (lws_jwe_parse_jose(&jwe.jose, complete, (int)strlen(complete),
                               temp, &temp_len) < 0) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
 
@@ -2134,29 +2200,29 @@ test_jwe(struct lws_context *context)
        n |= test_jwe_a2(context);
 
        n |= test_jwe_ra_ptext_1024(context, (char *)lws_jwe_ex_a2_jwk_json,
-                                   strlen((char *)lws_jwe_ex_a2_jwk_json));
+                                   (int)strlen((char *)lws_jwe_ex_a2_jwk_json));
        n |= test_jwe_r256a192_ptext(context, (char *)lws_jwe_ex_a2_jwk_json,
-                                    strlen((char *)lws_jwe_ex_a2_jwk_json));
+                       (int)strlen((char *)lws_jwe_ex_a2_jwk_json));
        n |= test_jwe_r256a256_ptext(context, (char *)lws_jwe_ex_a2_jwk_json,
-                                    strlen((char *)lws_jwe_ex_a2_jwk_json));
+                       (int)strlen((char *)lws_jwe_ex_a2_jwk_json));
        n |= test_jwe_ra_ptext_1024(context, (char *)rsa_key_2048,
-                                   strlen((char *)rsa_key_2048));
+                       (int)strlen((char *)rsa_key_2048));
        n |= test_jwe_r256a192_ptext(context, (char *)rsa_key_2048,
-                                    strlen((char *)rsa_key_2048));
+                       (int)strlen((char *)rsa_key_2048));
        n |= test_jwe_r256a256_ptext(context, (char *)rsa_key_2048,
-                                    strlen((char *)rsa_key_2048));
+                       (int)strlen((char *)rsa_key_2048));
        n |= test_jwe_ra_ptext_1024(context, (char *)rsa_key_4096,
-                                   strlen((char *)rsa_key_4096));
+                       (int)strlen((char *)rsa_key_4096));
        n |= test_jwe_r256a192_ptext(context, (char *)rsa_key_4096,
-                                    strlen((char *)rsa_key_4096));
+                       (int)strlen((char *)rsa_key_4096));
        n |= test_jwe_r256a256_ptext(context, (char *)rsa_key_4096,
-                                    strlen((char *)rsa_key_4096));
+                       (int)strlen((char *)rsa_key_4096));
        n |= test_jwe_ra_ptext_1024(context, (char *)rsa_key_4096_no_optional,
-                                   strlen((char *)rsa_key_4096_no_optional));
+                       (int)strlen((char *)rsa_key_4096_no_optional));
        n |= test_jwe_r256a192_ptext(context, (char *)rsa_key_4096_no_optional,
-                                    strlen((char *)rsa_key_4096_no_optional));
+                       (int)strlen((char *)rsa_key_4096_no_optional));
        n |= test_jwe_r256a256_ptext(context, (char *)rsa_key_4096_no_optional,
-                                    strlen((char *)rsa_key_4096_no_optional));
+                       (int)strlen((char *)rsa_key_4096_no_optional));
 
        /* AESKW decrypt all variations */
 
index 8fc6ad5..b6f8e69 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-api-test-jose - RFC7515 jws tests
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
@@ -46,7 +46,7 @@ test_jws_none(struct lws_context *context)
        /* A.5 Unsecured JSON "none" RFC7515 worked example */
 
        /* decode the b64.b64[.b64] compact serialization blocks */
-       n = lws_jws_compact_decode(none_cser, strlen(none_cser), &map, NULL,
+       n = lws_jws_compact_decode(none_cser, (int)strlen(none_cser), &map, NULL,
                                   temp, &temp_len);
        if (n != 2) {
                lwsl_err("%s: concat_map failed\n", __func__);
@@ -61,7 +61,7 @@ test_jws_none(struct lws_context *context)
 
        /* parse the JOSE header */
        if (lws_jws_parse_jose(&jose, map.buf[LJWS_JOSE],
-                              map.len[LJWS_JOSE],
+                              (int)map.len[LJWS_JOSE],
                               (char *)lws_concat_temp(temp, temp_len),
                               &temp_len) < 0 || !jose.alg) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
@@ -131,8 +131,8 @@ test_jws_HS256(struct lws_context *context)
 
        /* parse the JOSE header */
 
-       if (lws_jws_parse_jose(&jose, test1, strlen(test1), temp, &temp_len) < 0 ||
-                       !jose.alg) {
+       if (lws_jws_parse_jose(&jose, test1, (int)strlen(test1), temp,
+                              &temp_len) < 0 || !jose.alg) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
                goto bail;
        }
@@ -180,7 +180,7 @@ test_jws_HS256(struct lws_context *context)
                             jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].buf,
                             jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].len))
                goto bail;
-       if (lws_genhmac_update(&ctx, (uint8_t *)buf, p - buf))
+       if (lws_genhmac_update(&ctx, (uint8_t *)buf, lws_ptr_diff_size_t(p, buf)))
                goto bail_destroy_hmac;
        lws_genhmac_destroy(&ctx, digest);
 
@@ -198,7 +198,7 @@ test_jws_HS256(struct lws_context *context)
 
        /* 1.5: Check we can agree the signature matches the payload */
 
-       if (lws_jws_sig_confirm_compact_b64(buf, p - buf, &map, &jwk, context,
+       if (lws_jws_sig_confirm_compact_b64(buf, lws_ptr_diff_size_t(p, buf), &map, &jwk, context,
                        lws_concat_temp(temp, temp_len), &temp_len) < 0) {
                lwsl_notice("%s: confirm sig failed\n", __func__);
                goto bail;
@@ -314,7 +314,7 @@ test_jws_RS256(struct lws_context *context)
                goto bail;
        }
 
-       if (lws_jws_b64_compact_map(rfc7515_rsa_a1, strlen(rfc7515_rsa_a1),
+       if (lws_jws_b64_compact_map(rfc7515_rsa_a1, (int)strlen(rfc7515_rsa_a1),
                                   &jws.map_b64) != 3) {
                lwsl_notice("%s: lws_jws_b64_compact_map failed\n", __func__);
                goto bail;
@@ -323,10 +323,10 @@ test_jws_RS256(struct lws_context *context)
        /* 2.3: generate our own signature for a copy of the test packet */
 
        in = lws_concat_temp(temp, temp_len);
-       l = strlen(rfc7515_rsa_a1);
+       l = (int)strlen(rfc7515_rsa_a1);
        if (temp_len < l + 1)
                goto bail;
-       memcpy(in, rfc7515_rsa_a1, l + 1);
+       memcpy(in, rfc7515_rsa_a1, (unsigned int)l + 1);
        temp_len -= l + 1;
 
        if (lws_jws_b64_compact_map(in, l, &jws.map_b64) != 3) {
@@ -342,12 +342,13 @@ test_jws_RS256(struct lws_context *context)
                lwsl_err("%s: failed signing test packet\n", __func__);
                goto bail;
        }
-       jws.map_b64.len[LJWS_SIG] = n;
+       jws.map_b64.len[LJWS_SIG] = (unsigned int)n;
 
        /* 2.4: confirm our signature can be verified */
 
        in[l] = '\0';
-       if (lws_jws_sig_confirm_compact_b64(in, l, &map, &jwk, context, lws_concat_temp(temp, temp_len), &temp_len) < 0) {
+       if (lws_jws_sig_confirm_compact_b64(in, (unsigned int)l, &map, &jwk,
+                       context, lws_concat_temp(temp, temp_len), &temp_len) < 0) {
                lwsl_notice("%s: 2.2: confirm rsa sig failed\n", __func__);
                goto bail;
        }
@@ -421,7 +422,7 @@ test_jws_ES256(struct lws_context *context)
        lws_jose_init(&jose);
 
        /* decode the b64.b64[.b64] compact serialization blocks */
-       if (lws_jws_compact_decode(es256_cser, strlen(es256_cser),
+       if (lws_jws_compact_decode(es256_cser, (int)strlen(es256_cser),
                                   &jws.map, &jws.map_b64,
                                   temp, &temp_len) != 3) {
                lwsl_err("%s: concat_map failed\n", __func__);
@@ -446,7 +447,7 @@ test_jws_ES256(struct lws_context *context)
 
        /* parse the JOSE header */
        if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE],
-                              jws.map.len[LJWS_JOSE],
+                              (int)jws.map.len[LJWS_JOSE],
                               (char *)lws_concat_temp(temp, temp_len), &temp_len) < 0) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
                goto bail;
@@ -481,11 +482,11 @@ test_jws_ES256(struct lws_context *context)
 
        /* A.3 "ES256" RFC7515 worked example - sign */
 
-       l = strlen(es256_cser);
+       l = (int)strlen(es256_cser);
        if (temp_len < l + 1)
                goto bail1;
        p = lws_concat_temp(temp, temp_len);
-       memcpy(p, es256_cser, l + 1);
+       memcpy(p, es256_cser, (unsigned int)l + 1);
        temp_len -= l + 1;
 
        /* scan the b64 compact serialization string to map the blocks */
@@ -515,7 +516,7 @@ test_jws_ES256(struct lws_context *context)
                lwsl_err("%s: failed signing test packet\n", __func__);
                goto bail1;
        }
-       jws.map_b64.len[LJWS_SIG] = n;
+       jws.map_b64.len[LJWS_SIG] = (unsigned int)n;
 
        lwsl_hexdump(jws.map_b64.buf[LJWS_SIG], jws.map_b64.len[LJWS_SIG]);
 
@@ -523,7 +524,8 @@ test_jws_ES256(struct lws_context *context)
 
 //     lwsl_err("p %p, l %d\n", p, (int)l);
        p[l] = '\0';
-       if (lws_jws_sig_confirm_compact_b64(p, l, &map, &jwk, context, lws_concat_temp(temp, temp_len), &temp_len) < 0) {
+       if (lws_jws_sig_confirm_compact_b64(p, (unsigned int)l, &map, &jwk,
+                       context, lws_concat_temp(temp, temp_len), &temp_len) < 0) {
                lwsl_notice("%s: confirm our EC sig failed\n", __func__);
                goto bail1;
        }
@@ -582,7 +584,7 @@ test_jws_ES512(struct lws_context *context)
        lws_jose_init(&jose);
 
        /* decode the b64.b64[.b64] compact serialization blocks */
-       if (lws_jws_compact_decode(es512_cser, strlen(es512_cser),
+       if (lws_jws_compact_decode(es512_cser, (int)strlen(es512_cser),
                                   &jws.map, &jws.map_b64, temp,
                                   &temp_len) != 3) {
                lwsl_err("%s: concat_map failed\n", __func__);
@@ -607,7 +609,7 @@ test_jws_ES512(struct lws_context *context)
 
        /* parse the JOSE header */
        if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE],
-                             jws.map.len[LJWS_JOSE],
+                             (int)jws.map.len[LJWS_JOSE],
                              lws_concat_temp(temp, temp_len), &temp_len) < 0) {
                lwsl_err("%s: JOSE parse failed\n", __func__);
                goto bail;
@@ -642,11 +644,11 @@ test_jws_ES512(struct lws_context *context)
 
        /* A.3 "es512" RFC7515 worked example - sign */
 
-       l = strlen(es512_cser);
+       l = (int)strlen(es512_cser);
        if (temp_len < l)
                goto bail1;
        p = lws_concat_temp(temp, temp_len);
-       memcpy(p, es512_cser, l + 1);
+       memcpy(p, es512_cser, (unsigned int)l + 1);
        temp_len -= (l + 1);
 
        /* scan the b64 compact serialization string to map the blocks */
@@ -673,18 +675,55 @@ test_jws_ES512(struct lws_context *context)
                lwsl_err("%s: failed signing test packet\n", __func__);
                goto bail1;
        }
-       jws.map_b64.len[LJWS_SIG] = n;
+       jws.map_b64.len[LJWS_SIG] = (unsigned int)n;
 
        /* 2.4: confirm our generated signature can be verified */
 
        p[l] = '\0';
 
-       if (lws_jws_sig_confirm_compact_b64(p, l, &map, &jwk, context,
+       if (lws_jws_sig_confirm_compact_b64(p, (unsigned int)l, &map, &jwk, context,
                        lws_concat_temp(temp, temp_len), &temp_len) < 0) {
                lwsl_notice("%s: confirm our ECDSA sig failed\n", __func__);
                goto bail1;
        }
 
+       /* jwt test */
+
+       {
+               unsigned long long ull = lws_now_secs();
+               char buf[8192];
+               size_t cml = 2048, cml2 = 2048;
+
+               if (lws_jwt_sign_compact(context, &jwk, "ES512",
+                                       (char *)buf, &cml2,
+                                       (char *)buf + 2048, 4096,
+                                       "{\"iss\":\"warmcat.com\",\"aud\":"
+                                       "\"https://libwebsockets.org/sai\","
+                                       "\"iat\":%llu,"
+                                       "\"nbf\":%llu,"
+                                       "\"exp\":%llu,"
+                                       "\"sub\":\"manage\"}", ull,
+                                       ull - 60, ull + (30 * 24 * 3600)
+                                    )) {
+                       lwsl_err("%s: failed to create JWT\n", __func__);
+                       goto bail1;
+               }
+
+               lwsl_notice("%s: jwt test '%s'\n", __func__, buf);
+
+               if (lws_jwt_signed_validate(context, &jwk, "ES512",
+                                            (const char *)buf, cml2,
+                                            (char *)buf + 2048, 2048,
+                                            (char *)buf + 4096, &cml)) {
+                       lwsl_err("%s: failed to parse JWT\n", __func__);
+
+                       goto bail1;
+               }
+
+               lwsl_notice("%s: jwt valid, payload '%s'\n",
+                               __func__, buf + 4096);
+       }
+
        /* end */
        ret =  0;
 
@@ -698,6 +737,215 @@ bail:
        return ret;
 }
 
+static char
+       rsa_cert[] = "-----BEGIN CERTIFICATE-----\n"
+            "MIIF5jCCA86gAwIBAgIJANq50IuwPFKgMA0GCSqGSIb3DQEBCwUAMIGGMQswCQYD\n"
+            "VQQGEwJHQjEQMA4GA1UECAwHRXJld2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEb\n"
+            "MBkGA1UECgwSbGlid2Vic29ja2V0cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3Qx\n"
+            "HzAdBgkqhkiG9w0BCQEWEG5vbmVAaW52YWxpZC5vcmcwIBcNMTgwMzIwMDQxNjA3\n"
+            "WhgPMjExODAyMjQwNDE2MDdaMIGGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRXJl\n"
+            "d2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEbMBkGA1UECgwSbGlid2Vic29ja2V0\n"
+            "cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEG5vbmVA\n"
+            "aW52YWxpZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCjYtuW\n"
+            "aICCY0tJPubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8\n"
+            "Di3DAmHKnSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTek\n"
+            "LWcfI5ZZtoGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnH\n"
+            "KT/m6DSU0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6\n"
+            "jzhNyMBTJ1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQ\n"
+            "Ujy5N8pSNp7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAz\n"
+            "TK4l2pHNuC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBK\n"
+            "Izv9cgi9fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0\n"
+            "nPN1IMSnzXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzo\n"
+            "GMTvP/AuehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9p\n"
+            "sNcjTMaBQLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABo1MwUTAdBgNVHQ4EFgQU\n"
+            "9mYU23tW2zsomkKTAXarjr2vjuswHwYDVR0jBBgwFoAU9mYU23tW2zsomkKTAXar\n"
+            "jr2vjuswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEANjIBMrow\n"
+            "YNCbhAJdP7dhlhT2RUFRdeRUJD0IxrH/hkvb6myHHnK8nOYezFPjUlmRKUgNEDuA\n"
+            "xbnXZzPdCRNV9V2mShbXvCyiDY7WCQE2Bn44z26O0uWVk+7DNNLH9BnkwUtOnM9P\n"
+            "wtmD9phWexm4q2GnTsiL6Ul6cy0QlTJWKVLEUQQ6yda582e23J1AXqtqFcpfoE34\n"
+            "H3afEiGy882b+ZBiwkeV+oq6XVF8sFyr9zYrv9CvWTYlkpTQfLTZSsgPdEHYVcjv\n"
+            "xQ2D+XyDR0aRLRlvxUa9dHGFHLICG34Juq5Ai6lM1EsoD8HSsJpMcmrH7MWw2cKk\n"
+            "ujC3rMdFTtte83wF1uuF4FjUC72+SmcQN7A386BC/nk2TTsJawTDzqwOu/VdZv2g\n"
+            "1WpTHlumlClZeP+G/jkSyDwqNnTu1aodDmUa4xZodfhP1HWPwUKFcq8oQr148QYA\n"
+            "AOlbUOJQU7QwRWd1VbnwhDtQWXC92A2w1n/xkZSR1BM/NUSDhkBSUU1WjMbWg6Gg\n"
+            "mnIZLRerQCu1Oozr87rOQqQakPkyt8BUSNK3K42j2qcfhAONdRl8Hq8Qs5pupy+s\n"
+            "8sdCGDlwR3JNCMv6u48OK87F4mcIxhkSefFJUFII25pCGN5WtE4p5l+9cnO1GrIX\n"
+            "e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE=\n"
+            "-----END CERTIFICATE-----\n",
+       rsa_key[] = "-----BEGIN PRIVATE KEY-----\n"
+           "MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCjYtuWaICCY0tJ\n"
+           "PubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8Di3DAmHK\n"
+           "nSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTekLWcfI5ZZ\n"
+           "toGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnHKT/m6DSU\n"
+           "0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6jzhNyMBT\n"
+           "J1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQUjy5N8pS\n"
+           "Np7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAzTK4l2pHN\n"
+           "uC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBKIzv9cgi9\n"
+           "fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0nPN1IMSn\n"
+           "zXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzoGMTvP/Au\n"
+           "ehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9psNcjTMaB\n"
+           "QLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABAoICAFWe8MQZb37k2gdAV3Y6aq8f\n"
+           "qokKQqbCNLd3giGFwYkezHXoJfg6Di7oZxNcKyw35LFEghkgtQqErQqo35VPIoH+\n"
+           "vXUpWOjnCmM4muFA9/cX6mYMc8TmJsg0ewLdBCOZVw+wPABlaqz+0UOiSMMftpk9\n"
+           "fz9JwGd8ERyBsT+tk3Qi6D0vPZVsC1KqxxL/cwIFd3Hf2ZBtJXe0KBn1pktWht5A\n"
+           "Kqx9mld2Ovl7NjgiC1Fx9r+fZw/iOabFFwQA4dr+R8mEMK/7bd4VXfQ1o/QGGbMT\n"
+           "G+ulFrsiDyP+rBIAaGC0i7gDjLAIBQeDhP409ZhswIEc/GBtODU372a2CQK/u4Q/\n"
+           "HBQvuBtKFNkGUooLgCCbFxzgNUGc83GB/6IwbEM7R5uXqsFiE71LpmroDyjKTlQ8\n"
+           "YZkpIcLNVLw0usoGYHFm2rvCyEVlfsE3Ub8cFyTFk50SeOcF2QL2xzKmmbZEpXgl\n"
+           "xBHR0hjgon0IKJDGfor4bHO7Nt+1Ece8u2oTEKvpz5aIn44OeC5mApRGy83/0bvs\n"
+           "esnWjDE/bGpoT8qFuy+0urDEPNId44XcJm1IRIlG56ErxC3l0s11wrIpTmXXckqw\n"
+           "zFR9s2z7f0zjeyxqZg4NTPI7wkM3M8BXlvp2GTBIeoxrWB4V3YArwu8QF80QBgVz\n"
+           "mgHl24nTg00UH1OjZsABAoIBAQDOxftSDbSqGytcWqPYP3SZHAWDA0O4ACEM+eCw\n"
+           "au9ASutl0IDlNDMJ8nC2ph25BMe5hHDWp2cGQJog7pZ/3qQogQho2gUniKDifN77\n"
+           "40QdykllTzTVROqmP8+efreIvqlzHmuqaGfGs5oTkZaWj5su+B+bT+9rIwZcwfs5\n"
+           "YRINhQRx17qa++xh5mfE25c+M9fiIBTiNSo4lTxWMBShnK8xrGaMEmN7W0qTMbFH\n"
+           "PgQz5FcxRjCCqwHilwNBeLDTp/ZECEB7y34khVh531mBE2mNzSVIQcGZP1I/DvXj\n"
+           "W7UUNdgFwii/GW+6M0uUDy23UVQpbFzcV8o1C2nZc4Fb4zwBAoIBAQDKSJkFwwuR\n"
+           "naVJS6WxOKjX8MCu9/cKPnwBv2mmI2jgGxHTw5sr3ahmF5eTb8Zo19BowytN+tr6\n"
+           "2ZFoIBA9Ubc9esEAU8l3fggdfM82cuR9sGcfQVoCh8tMg6BP8IBLOmbSUhN3PG2m\n"
+           "39I802u0fFNVQCJKhx1m1MFFLOu7lVcDS9JN+oYVPb6MDfBLm5jOiPuYkFZ4gH79\n"
+           "J7gXI0/YKhaJ7yXthYVkdrSF6Eooer4RZgma62Dd1VNzSq3JBo6rYjF7Lvd+RwDC\n"
+           "R1thHrmf/IXplxpNVkoMVxtzbrrbgnC25QmvRYc0rlS/kvM4yQhMH3eA7IycDZMp\n"
+           "Y+0xm7I7jTT7AoIBAGKzKIMDXdCxBWKhNYJ8z7hiItNl1IZZMW2TPUiY0rl6yaCh\n"
+           "BVXjM9W0r07QPnHZsUiByqb743adkbTUjmxdJzjaVtxN7ZXwZvOVrY7I7fPWYnCE\n"
+           "fXCr4+IVpZI/ZHZWpGX6CGSgT6EOjCZ5IUufIvEpqVSmtF8MqfXO9o9uIYLokrWQ\n"
+           "x1dBl5UnuTLDqw8bChq7O5y6yfuWaOWvL7nxI8NvSsfj4y635gIa/0dFeBYZEfHI\n"
+           "UlGdNVomwXwYEzgE/c19ruIowX7HU/NgxMWTMZhpazlxgesXybel+YNcfDQ4e3RM\n"
+           "OMz3ZFiaMaJsGGNf4++d9TmMgk4Ns6oDs6Tb9AECggEBAJYzd+SOYo26iBu3nw3L\n"
+           "65uEeh6xou8pXH0Tu4gQrPQTRZZ/nT3iNgOwqu1gRuxcq7TOjt41UdqIKO8vN7/A\n"
+           "aJavCpaKoIMowy/aGCbvAvjNPpU3unU8jdl/t08EXs79S5IKPcgAx87sTTi7KDN5\n"
+           "SYt4tr2uPEe53NTXuSatilG5QCyExIELOuzWAMKzg7CAiIlNS9foWeLyVkBgCQ6S\n"
+           "me/L8ta+mUDy37K6vC34jh9vK9yrwF6X44ItRoOJafCaVfGI+175q/eWcqTX4q+I\n"
+           "G4tKls4sL4mgOJLq+ra50aYMxbcuommctPMXU6CrrYyQpPTHMNVDQy2ttFdsq9iK\n"
+           "TncCggEBAMmt/8yvPflS+xv3kg/ZBvR9JB1In2n3rUCYYD47ReKFqJ03Vmq5C9nY\n"
+           "56s9w7OUO8perBXlJYmKZQhO4293lvxZD2Iq4NcZbVSCMoHAUzhzY3brdgtSIxa2\n"
+           "gGveGAezZ38qKIU26dkz7deECY4vrsRkwhpTW0LGVCpjcQoaKvymAoCmAs8V2oMr\n"
+           "Ziw1YQ9uOUoWwOqm1wZqmVcOXvPIS2gWAs3fQlWjH9hkcQTMsUaXQDOD0aqkSY3E\n"
+           "NqOvbCV1/oUpRi3076khCoAXI1bKSn/AvR3KDP14B5toHI/F5OTSEiGhhHesgRrs\n"
+           "fBrpEY1IATtPq1taBZZogRqI3rOkkPk=\n"
+           "-----END PRIVATE KEY-----\n";
+
+int
+test_jwt_RS256(struct lws_context *context)
+{
+       struct lws_jwk jwk;
+       struct lws_x509_cert *pub = NULL;
+       int ret = -1;
+       int ret_encode;
+       char sha1_fingerprint[30];
+       uint8_t sha1sum[20];
+       char der_buf[LWS_ARRAY_SIZE(rsa_cert)];
+       union lws_tls_cert_info_results *der_info =
+                       (union lws_tls_cert_info_results *)der_buf;
+
+       if (lws_x509_create(&pub)) {
+               lwsl_err("%s: failed to create x509 public key\n", __func__);
+               goto bail;
+       }
+
+       if (lws_x509_parse_from_pem(pub, rsa_cert, LWS_ARRAY_SIZE(rsa_cert))) {
+               lwsl_err("%s: failed to parse x509 public key\n", __func__);
+               goto bail;
+       }
+
+       if (lws_x509_public_to_jwk(&jwk, pub, NULL, 2048)) {
+               lwsl_err("%s: failed to copy public key to jwk\n", __func__);
+               goto bail;
+       }
+
+       if (lws_x509_jwk_privkey_pem(context, &jwk, (char *)rsa_key,
+                                    LWS_ARRAY_SIZE(rsa_key), NULL)) {
+               lwsl_err("%s: failed to copy private key to jwk\n", __func__);
+               goto bail;
+       }
+
+       if (lws_x509_info(pub, LWS_TLS_CERT_INFO_DER_RAW, der_info,
+                         LWS_ARRAY_SIZE(der_buf) - sizeof(*der_info) +
+                         sizeof(der_info->ns.name)) ||
+           der_info->ns.len <= 0) {
+               lwsl_err("%s: failed to parse x509 public key\n", __func__);
+               goto bail;
+       }
+
+       if (!lws_SHA1((unsigned char *)der_info->ns.name,
+                     (size_t)der_info->ns.len, sha1sum)) {
+               lwsl_err("%s: sha1sum of public key failed\n", __func__);
+               goto bail;
+       }
+
+       ret_encode = lws_b64_encode_string_url((char *)sha1sum,
+                               LWS_ARRAY_SIZE(sha1sum), sha1_fingerprint,
+                               LWS_ARRAY_SIZE(sha1_fingerprint));
+       if (ret_encode < 0) {
+               lwsl_err("%s: failed to encode sha1sum to base64url\n", __func__);
+               goto bail;
+       }
+
+       while (sha1_fingerprint[--ret_encode] == '=')
+               sha1_fingerprint[ret_encode] = '\0';
+
+       lwsl_notice("%s: cert fingerprint '%s'\n", __func__, sha1_fingerprint);
+
+       /* now produce jwt with some additional header fields */
+       {
+               unsigned long long ull = lws_now_secs();
+               char buf[8192];
+               size_t cml = 2048, cml2 = 2048;
+               const char hdr_fmt[] = "{\"alg\":\"RS256\", \"typ\":\"JWT\", \"x5t\":\"%s\"}";
+               char jose_hdr[LWS_ARRAY_SIZE(hdr_fmt) + LWS_ARRAY_SIZE(sha1_fingerprint)];
+
+               struct lws_jwt_sign_info info = {
+                       .alg = NULL,
+                       .jose_hdr = jose_hdr,
+                       .jose_hdr_len = (size_t)lws_snprintf(jose_hdr, LWS_ARRAY_SIZE(jose_hdr), hdr_fmt, sha1_fingerprint),
+                       .out = buf,
+                       .out_len = &cml2,
+                       .temp = buf + cml2,
+                       .tl = 4096
+               };
+
+               lwsl_notice("%s: jose_hdr of len %zu: '%s'\n", __func__, info.jose_hdr_len, info.jose_hdr);
+               if (lws_jwt_sign_via_info(context, &jwk, &info,
+                                       "{\"iss\":\"warmcat.com\",\"aud\":"
+                                       "\"https://libwebsockets.org/sai\","
+                                       "\"iat\":%llu,"
+                                       "\"nbf\":%llu,"
+                                       "\"exp\":%llu,"
+                                       "\"sub\":\"manage\"}", ull,
+                                       ull - 60, ull + (30 * 24 * 3600)
+                                                )) {
+                       lwsl_err("%s: failed to create JWT\n", __func__);
+                       goto bail1;
+               }
+
+               lwsl_notice("%s: jwt test '%s'\n", __func__, buf);
+
+               if (lws_jwt_signed_validate(context, &jwk, "RS256",
+                                                        (const char *)buf, cml2,
+                                                        (char *)buf + 2048, 2048,
+                                                        (char *)buf + 4096, &cml)) {
+                       lwsl_err("%s: failed to parse JWT\n", __func__);
+
+                       goto bail1;
+               }
+
+               lwsl_notice("%s: jwt valid, payload '%s'\n",
+                               __func__, buf + 4096);
+       }
+
+       /* end */
+       ret =   0;
+
+bail1:
+       lws_jwk_destroy(&jwk);
+       lws_x509_destroy(&pub);
+
+bail:
+       lwsl_notice("%s: selftest %s\n", __func__, ret ? "FAIL" : "OK");
+
+       return ret;
+}
+
 int
 test_jws(struct lws_context *context)
 {
@@ -708,6 +956,7 @@ test_jws(struct lws_context *context)
        n |= test_jws_RS256(context);
        n |= test_jws_ES256(context);
        n |= test_jws_ES512(context);
+       n |= test_jwt_RS256(context);
 
        return n;
 }
index c2f2c72..2d636cd 100644 (file)
@@ -30,7 +30,9 @@ int main(int argc, const char **argv)
        lwsl_user("LWS JOSE api tests\n");
 
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
        info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
        info.options = 0;
 
        context = lws_create_context(&info);
diff --git a/minimal-examples/api-tests/api-test-jose/selftest.sh b/minimal-examples/api-tests/api-test-jose/selftest.sh
deleted file mode 100755 (executable)
index 16d1e2e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=1
-
-dotest $1 $2 apiselftest
-exit $FAILS
diff --git a/minimal-examples/api-tests/api-test-lecp/CMakeLists.txt b/minimal-examples/api-tests/api-test-lecp/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b09ee02
--- /dev/null
@@ -0,0 +1,22 @@
+project(lws-api-test-lecp C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_CBOR 1 requirements)
+
+if (requirements)
+
+       add_executable(${PROJECT_NAME} main.c)
+       add_test(NAME api-test-lecp COMMAND lws-api-test-lecp)
+
+       if (websockets_shared)
+               target_link_libraries(${PROJECT_NAME} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${PROJECT_NAME} websockets_shared)
+       else()
+               target_link_libraries(${PROJECT_NAME} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/api-tests/api-test-lecp/README.md b/minimal-examples/api-tests/api-test-lecp/README.md
new file mode 100644 (file)
index 0000000..ebe930d
--- /dev/null
@@ -0,0 +1,56 @@
+# lws api test lws_struct JSON
+
+Demonstrates how to use and performs selftests for lws_struct
+JSON serialization and deserialization
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+ $ ./lws-api-test-lws_struct-json
+[2019/03/30 22:09:09:2529] USER: LWS API selftest: lws_struct JSON
+[2019/03/30 22:09:09:2625] NOTICE: main: ++++++++++++++++ test 1
+[2019/03/30 22:09:09:2812] NOTICE: builder.hostname = 'learn', timeout = 1800, targets (2)
+[2019/03/30 22:09:09:2822] NOTICE:     target.name 'target1' (target 0x543a830)
+[2019/03/30 22:09:09:2824] NOTICE:     target.name 'target2' (target 0x543a860)
+[2019/03/30 22:09:09:2826] NOTICE: main:    .... strarting serialization of test 1
+[2019/03/30 22:09:09:2899] NOTICE: ser says 1
+{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800,"targets":[{"name":"target1"},{"name":"target2"}]}
+[2019/03/30 22:09:09:2929] NOTICE: main: ++++++++++++++++ test 2
+[2019/03/30 22:09:09:2932] NOTICE: builder.hostname = 'learn', timeout = 0, targets (3)
+[2019/03/30 22:09:09:2932] NOTICE:     target.name 'target1' (target 0x543b060)
+[2019/03/30 22:09:09:2933] NOTICE:     target.name 'target2' (target 0x543b090)
+[2019/03/30 22:09:09:2933] NOTICE:     target.name 'target3' (target 0x543b0c0)
+[2019/03/30 22:09:09:2934] NOTICE: main:    .... strarting serialization of test 2
+[2019/03/30 22:09:09:2935] NOTICE: ser says 1
+{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":0,"targets":[{"name":"target1"},{"name":"target2"},{"name":"target3"}]}
+[2019/03/30 22:09:09:2940] NOTICE: main: ++++++++++++++++ test 3
+[2019/03/30 22:09:09:2959] NOTICE: builder.hostname = 'learn', timeout = 1800, targets (2)
+[2019/03/30 22:09:09:2960] NOTICE:     target.name 'target1' (target 0x543b450)
+[2019/03/30 22:09:09:2961] NOTICE:       child 0x543b480, target.child.somename 'abc'
+[2019/03/30 22:09:09:2961] NOTICE:     target.name 'target2' (target 0x543b490)
+[2019/03/30 22:09:09:2962] NOTICE: main:    .... strarting serialization of test 3
+[2019/03/30 22:09:09:2969] NOTICE: ser says 1
+{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800,"targets":[{"name":"target1","child":{"somename":"abc"}},{"name":"target2"}]}
+[2019/03/30 22:09:09:2970] NOTICE: main: ++++++++++++++++ test 4
+[2019/03/30 22:09:09:2971] NOTICE: builder.hostname = 'learn', timeout = 1800, targets (0)
+[2019/03/30 22:09:09:2971] NOTICE: main:    .... strarting serialization of test 4
+[2019/03/30 22:09:09:2973] NOTICE: ser says 1
+{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800}
+[2019/03/30 22:09:09:2974] NOTICE: main: ++++++++++++++++ test 5
+[2019/03/30 22:09:09:2978] NOTICE: builder.hostname = '', timeout = 0, targets (0)
+[2019/03/30 22:09:09:2979] NOTICE: main:    .... strarting serialization of test 5
+[2019/03/30 22:09:09:2980] NOTICE: ser says 1
+{"schema":"com-warmcat-sai-builder","hostname":"","nspawn_timeout":0}
+[2019/03/30 22:09:09:2982] USER: Completed: PASS
+```
+
diff --git a/minimal-examples/api-tests/api-test-lecp/main.c b/minimal-examples/api-tests/api-test-lecp/main.c
new file mode 100644 (file)
index 0000000..89133d7
--- /dev/null
@@ -0,0 +1,5020 @@
+/*
+ * lws-api-test-lecp
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * unit tests for lecp
+ */
+
+#include <libwebsockets.h>
+
+#if defined(LWS_WITH_CBOR_FLOAT)
+#include <math.h>
+#endif
+
+#define VERBOSE
+
+#if defined(VERBOSE)
+static const char * const reason_names[] = {
+       "LECPCB_CONSTRUCTED",
+       "LECPCB_DESTRUCTED",
+       "LECPCB_START",
+       "LECPCB_COMPLETE",
+       "LECPCB_FAILED",
+       "LECPCB_PAIR_NAME",
+       "LECPCB_VAL_TRUE",
+       "LECPCB_VAL_FALSE",
+       "LECPCB_VAL_NULL",
+       "LECPCB_VAL_NUM_INT",
+       "LECPCB_VAL_RESERVED", /* float in lejp */
+       "LECPCB_VAL_STR_START",
+       "LECPCB_VAL_STR_CHUNK",
+       "LECPCB_VAL_STR_END",
+       "LECPCB_ARRAY_START",
+       "LECPCB_ARRAY_END",
+       "LECPCB_OBJECT_START",
+       "LECPCB_OBJECT_END",
+       "LECPCB_TAG_START",
+       "LECPCB_TAG_END",
+       "LECPCB_VAL_NUM_UINT",
+       "LECPCB_VAL_UNDEFINED",
+       "LECPCB_VAL_FLOAT16",
+       "LECPCB_VAL_FLOAT32",
+       "LECPCB_VAL_FLOAT64",
+       "LECPCB_VAL_SIMPLE",
+       "LECPCB_VAL_BLOB_START",
+       "LECPCB_VAL_BLOB_CHUNK",
+       "LECPCB_VAL_BLOB_END",
+       "LECPCB_ARRAY_ITEM_START",
+       "LECPCB_ARRAY_ITEM_END",
+       "LECPCB_LITERAL_CBOR"
+};
+#endif
+
+/*
+ * Based on the official CBOR test vectors from here
+ *
+ * https://github.com/cbor/test-vectors/blob/master/appendix_a.json
+ */
+
+static const uint8_t
+       test1[]         = { 0x00 },
+       test2[]         = { 0x01 },
+       test3[]         = { 0x0a },
+       test4[]         = { 0x17 },
+       test5[]         = { 0x18, 0x18 },
+       test6[]         = { 0x18, 0x19 },
+       test7[]         = { 0x18, 0x64 },
+       test8[]         = { 0x19, 0x03, 0xe8 },
+       test9[]         = { 0x1a, 0x00, 0x0f, 0x42, 0x40 },
+       test10[]        = { 0x1b, 0x00, 0x00, 0x00,
+                           0xe8, 0xd4, 0xa5, 0x10, 0x00 },
+       test11[]        = { 0x1b, 0xff, 0xff, 0xff, 0xff,
+                           0xff, 0xff, 0xff, 0xff },
+       test12[]        = { 0xc2, 0x49, 0x01, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00 },
+       test13[]        = { 0x3b, 0xff, 0xff, 0xff, 0xff,
+                           0xff, 0xff, 0xff, 0xff },
+       test14[]        = { 0xc3, 0x49, 0x01, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00, 0x00,
+                           0x00 },
+       test15[]        = { 0x20 },
+       test16[]        = { 0x29 },
+       test17[]        = { 0x38, 0x63 },
+       test18[]        = { 0x39, 0x03, 0xe7 },
+       test19[]        = { 0xf9, 0x00, 0x00 },
+       test20[]        = { 0xf9, 0x80, 0x00 },
+       test21[]        = { 0xf9, 0x3c, 0x00 },
+       test22[]        = { 0xfb, 0x3f, 0xf1, 0x99, 0x99,
+                           0x99, 0x99, 0x99, 0x9a },
+       test23[]        = { 0xf9, 0x3e, 0x00 },
+       test24[]        = { 0xf9, 0x7b, 0xff },
+       test25[]        = { 0xfa, 0x47, 0xc3, 0x50, 0x00 },
+       test26[]        = { 0xfa, 0x7f, 0x7f, 0xff, 0xff },
+       test27[]        = { 0xfb, 0x7e, 0x37, 0xe4, 0x3c,
+                           0x88, 0x00, 0x75, 0x9c },
+       test28[]        = { 0xf9, 0x00, 0x01 },
+       test29[]        = { 0xf9, 0x04, 0x00 },
+       test30[]        = { 0xf9, 0xc4, 0x00 },
+       test31[]        = { 0xfb, 0xc0, 0x10, 0x66, 0x66,
+                           0x66, 0x66, 0x66, 0x66 },
+       test32[]        = { 0xf9, 0x7c, 0x00 },
+       test33[]        = { 0xf9, 0x7e, 0x00 },
+       test34[]        = { 0xf9, 0xfc, 0x00 },
+       test35[]        = { 0xfa, 0x7f, 0x80, 0x00, 0x00 },
+       test36[]        = { 0xfa, 0x7f, 0xc0, 0x00, 0x00 },
+       test37[]        = { 0xfa, 0xff, 0x80, 0x00, 0x00 },
+       test38[]        = { 0xfb, 0x7f, 0xf0, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00 },
+       test39[]        = { 0xfb, 0x7f, 0xf8, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00 },
+       test40[]        = { 0xfb, 0xff, 0xf0, 0x00, 0x00,
+                           0x00, 0x00, 0x00, 0x00 },
+       test41[]        = { 0xf4 },
+       test42[]        = { 0xf5 },
+       test43[]        = { 0xf6 },
+       test44[]        = { 0xf7 },
+       test45[]        = { 0xf0 },
+       test46[]        = { 0xf8, 0x18 },
+       test47[]        = { 0xf8, 0xff },
+       test48[]        = { 0xc0, 0x74, 0x32, 0x30, 0x31,
+                           0x33, 0x2d, 0x30, 0x33, 0x2d,
+                           0x32, 0x31, 0x54, 0x32, 0x30,
+                           0x3a, 0x30, 0x34, 0x3a, 0x30,
+                           0x30, 0x5a },
+       test49[]        = { 0xc1, 0x1a, 0x51, 0x4b, 0x67,
+                           0xb0 },
+       test50[]        = { 0xc1, 0xfb, 0x41, 0xd4, 0x52,
+                           0xd9, 0xec, 0x20, 0x00, 0x00 },
+       test51[]        = { 0xd7, 0x44, 0x01, 0x02, 0x03,
+                           0x04 },
+       test52[]        = { 0xd8, 0x18, 0x45, 0x64, 0x49,
+                           0x45, 0x54, 0x46 },
+       test53[]        = { 0xd8, 0x20, 0x76, 0x68, 0x74,
+                           0x74, 0x70, 0x3a, 0x2f, 0x2f,
+                           0x77, 0x77, 0x77, 0x2e, 0x65,
+                           0x78, 0x61, 0x6d, 0x70, 0x6c,
+                           0x65, 0x2e, 0x63, 0x6f, 0x6d },
+       test54[]        = { 0x40 },
+       test55[]        = { 0x44, 0x01, 0x02, 0x03, 0x04 },
+       test56[]        = { 0x60 },
+       test57[]        = { 0x61, 0x61 },
+       test58[]        = { 0x64, 0x49, 0x45, 0x54, 0x46 },
+       test59[]        = { 0x62, 0x22, 0x5c },
+       test60[]        = { 0x62, 0xc3, 0xbc },
+       test61[]        = { 0x63, 0xe6, 0xb0, 0xb4 },
+       test62[]        = { 0x64, 0xf0, 0x90, 0x85, 0x91 },
+       test63[]        = { 0x80 },
+       test64[]        = { 0x83, 0x01, 0x02, 0x03 },
+       test65[]        = { 0x83, 0x01, 0x82, 0x02, 0x03,
+                           0x82, 0x04, 0x05 },
+       test66[]        = { 0x98, 0x19, 0x01, 0x02, 0x03,
+                           0x04, 0x05, 0x06, 0x07, 0x08,
+                           0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+                           0x0e, 0x0f, 0x10, 0x11, 0x12,
+                           0x13, 0x14, 0x15, 0x16, 0x17,
+                           0x18, 0x18, 0x18, 0x19 },
+       test67[]        = { 0xa0 },
+       test68[]        = { 0xa2, 0x01, 0x02, 0x03, 0x04 },
+       test69[]        = { 0xa2, 0x61, 0x61, 0x01, 0x61,
+                           0x62, 0x82, 0x02, 0x03 },
+       test70[]        = { 0x82, 0x61, 0x61, 0xa1, 0x61,
+                           0x62, 0x61, 0x63 },
+       test71[]        = { 0xa5, 0x61, 0x61, 0x61, 0x41,
+                           0x61, 0x62, 0x61, 0x42, 0x61,
+                           0x63, 0x61, 0x43, 0x61, 0x64,
+                           0x61, 0x44, 0x61, 0x65, 0x61,
+                           0x45 },
+       test72[]        = { 0x5f, 0x42, 0x01, 0x02, 0x43,
+                           0x03, 0x04, 0x05, 0xff },
+       test73[]        = { 0x7f, 0x65, 0x73, 0x74, 0x72,
+                           0x65, 0x61, 0x64, 0x6d, 0x69,
+                           0x6e, 0x67, 0xff },
+       test74[]        = { 0x9f, 0xff },
+       test75[]        = { 0x9f, 0x01, 0x82, 0x02, 0x03,
+                           0x9f, 0x04, 0x05, 0xff, 0xff },
+       test76[]        = { 0x9f, 0x01, 0x82, 0x02, 0x03,
+                           0x82, 0x04, 0x05, 0xff },
+       test77[]        = { 0x83, 0x01, 0x82, 0x02, 0x03,
+                           0x9f, 0x04, 0x05, 0xff },
+       test78[]        = { 0x83, 0x01, 0x9f, 0x02, 0x03,
+                           0xff, 0x82, 0x04, 0x05 },
+       test79[]        = { 0x9f, 0x01, 0x02, 0x03, 0x04,
+                           0x05, 0x06, 0x07, 0x08, 0x09,
+                           0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+                           0x0f, 0x10, 0x11, 0x12, 0x13,
+                           0x14, 0x15, 0x16, 0x17, 0x18,
+                           0x18, 0x18, 0x19, 0xff },
+       test80[]        = { 0xbf, 0x61, 0x61, 0x01, 0x61,
+                           0x62, 0x9f, 0x02, 0x03, 0xff,
+                           0xff },
+       test81[]        = { 0x82, 0x61, 0x61, 0xbf, 0x61,
+                           0x62, 0x61, 0x63, 0xff },
+       test82[]        = { 0xbf, 0x63, 0x46, 0x75, 0x6e,
+                           0xf5, 0x63, 0x41, 0x6d, 0x74,
+                           0x21, 0xff },
+
+       /* some random COSE examples
+        *
+        * COSE hmac-01 test vector
+        */
+
+       test83[]        = { 0xD8, 0x61, 0x85, 0x43, 0xA1,
+                           0x01, 0x05, 0xA0, 0x54, 0x54,
+                           0x68, 0x69, 0x73, 0x20, 0x69,
+                           0x73, 0x20, 0x74, 0x68, 0x65,
+                           0x20, 0x63, 0x6F, 0x6E, 0x74,
+                           0x65, 0x6E, 0x74, 0x2E, 0x58,
+                           0x20, 0x2B, 0xDC, 0xC8, 0x9F,
+                           0x05, 0x82, 0x16, 0xB8, 0xA2,
+                           0x08, 0xDD, 0xC6, 0xD8, 0xB5,
+                           0x4A, 0xA9, 0x1F, 0x48, 0xBD,
+                           0x63, 0x48, 0x49, 0x86, 0x56,
+                           0x51, 0x05, 0xC9, 0xAD, 0x5A,
+                           0x66, 0x82, 0xF6, 0x81, 0x83,
+                           0x40, 0xA2, 0x01, 0x25, 0x04,
+                           0x4A, 0x6F, 0x75, 0x72, 0x2D,
+                           0x73, 0x65, 0x63, 0x72, 0x65,
+                           0x74, 0x40 },
+        /*
+        * COSE hmac-02 test vector
+        */
+       test84[]        = { 0xD8, 0x61, 0x85, 0x43, 0xA1,
+                           0x01, 0x06, 0xA0, 0x54, 0x54,
+                           0x68, 0x69, 0x73, 0x20, 0x69,
+                           0x73, 0x20, 0x74, 0x68, 0x65,
+                           0x20, 0x63, 0x6F, 0x6E, 0x74,
+                           0x65, 0x6E, 0x74, 0x2E, 0x58,
+                           0x30, 0xB3, 0x09, 0x7F, 0x70,
+                           0x00, 0x9A, 0x11, 0x50, 0x74,
+                           0x09, 0x59, 0x8A, 0x83, 0xE1,
+                           0x5B, 0xBB, 0xBF, 0x19, 0x82,
+                           0xDC, 0xE2, 0x8E, 0x5A, 0xB6,
+                           0xD5, 0xA6, 0xAF, 0xF6, 0x89,
+                           0x7B, 0xD2, 0x4B, 0xB8, 0xB7,
+                           0x47, 0x96, 0x22, 0xC9, 0x40,
+                           0x1B, 0x24, 0x09, 0x0D, 0x45,
+                           0x82, 0x06, 0xD5, 0x87, 0x81,
+                           0x83, 0x40, 0xA2, 0x01, 0x25,
+                           0x04, 0x46, 0x73, 0x65, 0x63,
+                           0x2D, 0x34, 0x38, 0x40 },
+       test85[]        = { 0xD8, 0x61, 0x85, 0x43, 0xA1,
+                           0x01, 0x07, 0xA0, 0x54, 0x54,
+                           0x68, 0x69, 0x73, 0x20, 0x69,
+                           0x73, 0x20, 0x74, 0x68, 0x65,
+                           0x20, 0x63, 0x6F, 0x6E, 0x74,
+                           0x65, 0x6E, 0x74, 0x2E, 0x58,
+                           0x40, 0xCD, 0x28, 0xA6, 0xB3,
+                           0xCF, 0xBB, 0xBF, 0x21, 0x48,
+                           0x51, 0xB9, 0x06, 0xE0, 0x50,
+                           0x05, 0x6C, 0xB4, 0x38, 0xA8,
+                           0xB8, 0x89, 0x05, 0xB8, 0xB7,
+                           0x46, 0x19, 0x77, 0x02, 0x27,
+                           0x11, 0xA9, 0xD8, 0xAC, 0x5D,
+                           0xBC, 0x54, 0xE2, 0x9A, 0x56,
+                           0xD9, 0x26, 0x04, 0x6B, 0x40,
+                           0xFC, 0x26, 0x07, 0xC2, 0x5B,
+                           0x34, 0x44, 0x54, 0xAA, 0x5F,
+                           0x68, 0xDE, 0x09, 0xA3, 0xE5,
+                           0x25, 0xD3, 0x86, 0x5A, 0x05,
+                           0x81, 0x83, 0x40, 0xA2, 0x01,
+                           0x25, 0x04, 0x46, 0x73, 0x65,
+                           0x63, 0x2D, 0x36, 0x34, 0x40 },
+       test86[]        = { 0xD8, 0x61, 0x85, 0x43, 0xA1,
+                           0x01, 0x05, 0xA0, 0x54, 0x54,
+                           0x68, 0x69, 0x73, 0x20, 0x69,
+                           0x73, 0x20, 0x74, 0x68, 0x65,
+                           0x20, 0x63, 0x6F, 0x6E, 0x74,
+                           0x65, 0x6E, 0x74, 0x2E, 0x58,
+                           0x20, 0x2B, 0xDC, 0xC8, 0x9F,
+                           0x05, 0x82, 0x16, 0xB8, 0xA2,
+                           0x08, 0xDD, 0xC6, 0xD8, 0xB5,
+                           0x4A, 0xA9, 0x1F, 0x48, 0xBD,
+                           0x63, 0x48, 0x49, 0x86, 0x56,
+                           0x51, 0x05, 0xC9, 0xAD, 0x5A,
+                           0x66, 0x82, 0xF7, 0x81, 0x83,
+                           0x40, 0xA2, 0x01, 0x25, 0x04,
+                           0x4A, 0x6F, 0x75, 0x72, 0x2D,
+                           0x73, 0x65, 0x63, 0x72, 0x65,
+                           0x74, 0x40 },
+       test87[]        = { 0xD8, 0x61, 0x85, 0x43, 0xA1,
+                           0x01, 0x04, 0xA0, 0x54, 0x54,
+                           0x68, 0x69, 0x73, 0x20, 0x69,
+                           0x73, 0x20, 0x74, 0x68, 0x65,
+                           0x20, 0x63, 0x6F, 0x6E, 0x74,
+                           0x65, 0x6E, 0x74, 0x2E, 0x48,
+                           0x6F, 0x35, 0xCA, 0xB7, 0x79,
+                           0xF7, 0x78, 0x33, 0x81, 0x83,
+                           0x40, 0xA2, 0x01, 0x25, 0x04,
+                           0x4A, 0x6F, 0x75, 0x72, 0x2D,
+                           0x73, 0x65, 0x63, 0x72, 0x65,
+                           0x74, 0x40
+
+                           /* COSE HMAX Enc 01 vector */
+
+       }, test88[]     = { 0xD1, 0x84, 0x43, 0xA1, 0x01,
+                           0x05, 0xA0, 0x54, 0x54, 0x68,
+                           0x69, 0x73, 0x20, 0x69, 0x73,
+                           0x20, 0x74, 0x68, 0x65, 0x20,
+                           0x63, 0x6F, 0x6E, 0x74, 0x65,
+                           0x6E, 0x74, 0x2E, 0x58, 0x20,
+                           0xA1, 0xA8, 0x48, 0xD3, 0x47,
+                           0x1F, 0x9D, 0x61, 0xEE, 0x49,
+                           0x01, 0x8D, 0x24, 0x4C, 0x82,
+                           0x47, 0x72, 0xF2, 0x23, 0xAD,
+                           0x4F, 0x93, 0x52, 0x93, 0xF1,
+                           0x78, 0x9F, 0xC3, 0xA0, 0x8D,
+                           0x8C, 0x58
+       }, test89[]     = { 0xD1, 0x84, 0x43, 0xA1, 0x01,
+                           0x06, 0xA0, 0x54, 0x54, 0x68,
+                           0x69, 0x73, 0x20, 0x69, 0x73,
+                           0x20, 0x74, 0x68, 0x65, 0x20,
+                           0x63, 0x6F, 0x6E, 0x74, 0x65,
+                           0x6E, 0x74, 0x2E, 0x58, 0x30,
+                           0x99, 0x8D, 0x26, 0xC6, 0x45,
+                           0x9A, 0xAE, 0xEC, 0xF4, 0x4E,
+                           0xD2, 0x0C, 0xE0, 0x0C, 0x8C,
+                           0xCE, 0xDF, 0x0A, 0x1F, 0x3D,
+                           0x22, 0xA9, 0x2F, 0xC0, 0x5D,
+                           0xB0, 0x8C, 0x5A, 0xEB, 0x1C,
+                           0xB5, 0x94, 0xCA, 0xAF, 0x5A,
+                           0x5C, 0x5E, 0x2E, 0x9D, 0x01,
+                           0xCC, 0xE7, 0xE7, 0x7A, 0x93,
+                           0xAA, 0x8C, 0x62
+       }, test90[]     = { 0xD1, 0x84, 0x43, 0xA1, 0x01,
+                           0x07, 0xA0, 0x54, 0x54, 0x68,
+                           0x69, 0x73, 0x20, 0x69, 0x73,
+                           0x20, 0x74, 0x68, 0x65, 0x20,
+                           0x63, 0x6F, 0x6E, 0x74, 0x65,
+                           0x6E, 0x74, 0x2E, 0x58, 0x40,
+                           0x4A, 0x55, 0x5B, 0xF9, 0x71,
+                           0xF7, 0xC1, 0x89, 0x1D, 0x9D,
+                           0xDF, 0x30, 0x4A, 0x1A, 0x13,
+                           0x2E, 0x2D, 0x6F, 0x81, 0x74,
+                           0x49, 0x47, 0x4D, 0x81, 0x3E,
+                           0x6D, 0x04, 0xD6, 0x59, 0x62,
+                           0xBE, 0xD8, 0xBB, 0xA7, 0x0C,
+                           0x17, 0xE1, 0xF5, 0x30, 0x8F,
+                           0xA3, 0x99, 0x62, 0x95, 0x9A,
+                           0x4B, 0x9B, 0x8D, 0x7D, 0xA8,
+                           0xE6, 0xD8, 0x49, 0xB2, 0x09,
+                           0xDC, 0xD3, 0xE9, 0x8C, 0xC0,
+                           0xF1, 0x1E, 0xDD, 0xF2
+
+       }, test91[]     = { 0xD1, 0x84, 0x43, 0xA1, 0x01,
+                           0x05, 0xA0, 0x54, 0x54, 0x68,
+                           0x69, 0x73, 0x20, 0x69, 0x73,
+                           0x20, 0x74, 0x68, 0x65, 0x20,
+                           0x63, 0x6F, 0x6E, 0x74, 0x65,
+                           0x6E, 0x74, 0x2E, 0x58, 0x20,
+                           0xA1, 0xA8, 0x48, 0xD3, 0x47,
+                           0x1F, 0x9D, 0x61, 0xEE, 0x49,
+                           0x01, 0x8D, 0x24, 0x4C, 0x82,
+                           0x47, 0x72, 0xF2, 0x23, 0xAD,
+                           0x4F, 0x93, 0x52, 0x93, 0xF1,
+                           0x78, 0x9F, 0xC3, 0xA0, 0x8D,
+                           0x8C, 0x59
+
+       }, test92[]     = { 0xD1, 0x84, 0x43, 0xA1, 0x01,
+                           0x04, 0xA0, 0x54, 0x54, 0x68,
+                           0x69, 0x73, 0x20, 0x69, 0x73,
+                           0x20, 0x74, 0x68, 0x65, 0x20,
+                           0x63, 0x6F, 0x6E, 0x74, 0x65,
+                           0x6E, 0x74, 0x2E, 0x48, 0x11,
+                           0xF9, 0xE3, 0x57, 0x97, 0x5F,
+                           0xB8, 0x49
+
+                        /*
+                        * COSE countersign encrypt-01
+                        */
+
+       }, test93[]     = {
+                           0xd0, 0x83, 0x43, 0xa1, 0x01,
+                           0x01, 0xa2, 0x05, 0x4c, 0x02,
+                           0xd1, 0xf7, 0xe6, 0xf2, 0x6c,
+                           0x43, 0xd4, 0x86, 0x8d, 0x87,
+                           0xce, 0x07, 0x83, 0x43, 0xa1,
+                           0x01, 0x27, 0xa1, 0x04, 0x42,
+                           0x31, 0x31, 0x58, 0x40, 0xe1,
+                           0x04, 0x39, 0x15, 0x4c, 0xc7,
+                           0x5c, 0x7a, 0x3a, 0x53, 0x91,
+                           0x49, 0x1f, 0x88, 0x65, 0x1e,
+                           0x02, 0x92, 0xfd, 0x0f, 0xe0,
+                           0xe0, 0x2c, 0xf7, 0x40, 0x54,
+                           0x7e, 0xaf, 0x66, 0x77, 0xb4,
+                           0xa4, 0x04, 0x0b, 0x8e, 0xca,
+                           0x16, 0xdb, 0x59, 0x28, 0x81,
+                           0x26, 0x2f, 0x77, 0xb1, 0x4c,
+                           0x1a, 0x08, 0x6c, 0x02, 0x26,
+                           0x8b, 0x17, 0x17, 0x1c, 0xa1,
+                           0x6b, 0xe4, 0xb8, 0x59, 0x5f,
+                           0x8c, 0x0a, 0x08, 0x58, 0x24,
+                           0x60, 0x97, 0x3a, 0x94, 0xbb,
+                           0x28, 0x98, 0x00, 0x9e, 0xe5,
+                           0x2e, 0xcf, 0xd9, 0xab, 0x1d,
+                           0xd2, 0x58, 0x67, 0x37, 0x4b,
+                           0x16, 0x2e, 0x2c, 0x03, 0x56,
+                           0x8b, 0x41, 0xf5, 0x7c, 0x3c,
+                           0xc1, 0x6f, 0x91, 0x66, 0x25,
+                           0x0a
+                        /*
+                         * COSE countersign encrypt-02
+                         */
+               }, test94[]     = {
+                       0xd0, 0x83, 0x43, 0xa1, 0x01,
+                       0x01, 0xa2, 0x05, 0x4c, 0x02,
+                       0xd1, 0xf7, 0xe6, 0xf2, 0x6c,
+                       0x43, 0xd4, 0x86, 0x8d, 0x87,
+                       0xce, 0x07, 0x82, 0x83, 0x43,
+                       0xa1, 0x01, 0x27, 0xa1, 0x04,
+                       0x42, 0x31, 0x31, 0x58, 0x40,
+                       0xe1, 0x04, 0x39, 0x15, 0x4c,
+                       0xc7, 0x5c, 0x7a, 0x3a, 0x53,
+                       0x91, 0x49, 0x1f, 0x88, 0x65,
+                       0x1e, 0x02, 0x92, 0xfd, 0x0f,
+                       0xe0, 0xe0, 0x2c, 0xf7, 0x40,
+                       0x54, 0x7e, 0xaf, 0x66, 0x77,
+                       0xb4, 0xa4, 0x04, 0x0b, 0x8e,
+                       0xca, 0x16, 0xdb, 0x59, 0x28,
+                       0x81, 0x26, 0x2f, 0x77, 0xb1,
+                       0x4c, 0x1a, 0x08, 0x6c, 0x02,
+                       0x26, 0x8b, 0x17, 0x17, 0x1c,
+                       0xa1, 0x6b, 0xe4, 0xb8, 0x59,
+                       0x5f, 0x8c, 0x0a, 0x08, 0x83,
+                       0x43, 0xa1, 0x01, 0x26, 0xa1,
+                       0x04, 0x42, 0x31, 0x31, 0x58,
+                       0x40, 0xfc, 0xa9, 0x8e, 0xca,
+                       0xc8, 0x0b, 0x5f, 0xeb, 0x3a,
+                       0xc7, 0xc1, 0x08, 0xb2, 0xb7,
+                       0x91, 0x10, 0xde, 0x88, 0x86,
+                       0x7b, 0xc0, 0x42, 0x6f, 0xc8,
+                       0x3c, 0x53, 0xcc, 0xd6, 0x78,
+                       0x96, 0x94, 0xed, 0xc5, 0xfe,
+                       0xe3, 0xc4, 0x0d, 0xe8, 0xe7,
+                       0xb4, 0x4f, 0xe8, 0xaa, 0xd3,
+                       0x67, 0xe0, 0x95, 0xc8, 0xfc,
+                       0x31, 0xb7, 0x9e, 0xe6, 0x66,
+                       0xdf, 0x9c, 0xf9, 0x09, 0x06,
+                       0xeb, 0x43, 0x75, 0x6c, 0x73,
+                       0x58, 0x24, 0x60, 0x97, 0x3a,
+                       0x94, 0xbb, 0x28, 0x98, 0x00,
+                       0x9e, 0xe5, 0x2e, 0xcf, 0xd9,
+                       0xab, 0x1d, 0xd2, 0x58, 0x67,
+                       0x37, 0x4b, 0x16, 0x2e, 0x2c,
+                       0x03, 0x56, 0x8b, 0x41, 0xf5,
+                       0x7c, 0x3c, 0xc1, 0x6f, 0x91,
+                       0x66, 0x25, 0x0a
+
+                        /*
+                         * COSE countersign enveloped-01
+                         */
+       }, test95[]     = {
+                       0xd8, 0x60, 0x84, 0x43, 0xa1,
+                       0x01, 0x01, 0xa2, 0x05, 0x4c,
+                       0x02, 0xd1, 0xf7, 0xe6, 0xf2,
+                       0x6c, 0x43, 0xd4, 0x86, 0x8d,
+                       0x87, 0xce, 0x07, 0x83, 0x43,
+                       0xa1, 0x01, 0x27, 0xa1, 0x04,
+                       0x42, 0x31, 0x31, 0x58, 0x40,
+                       0x9a, 0x8e, 0xed, 0xe3, 0xb3,
+                       0xcb, 0x83, 0x7b, 0xa0, 0x0d,
+                       0xf0, 0x8f, 0xa2, 0x1b, 0x12,
+                       0x8b, 0x2d, 0x6d, 0x91, 0x62,
+                       0xa4, 0x29, 0x0a, 0x58, 0x2d,
+                       0x9f, 0x19, 0xbd, 0x0f, 0xb5,
+                       0x02, 0xf0, 0xf9, 0x2b, 0x9b,
+                       0xf4, 0x53, 0xa4, 0x05, 0x40,
+                       0x1f, 0x8b, 0x70, 0x55, 0xef,
+                       0x4e, 0x95, 0x8d, 0xf7, 0xf4,
+                       0xfb, 0xd7, 0xcf, 0xb4, 0xa0,
+                       0xc9, 0x71, 0x60, 0xf9, 0x47,
+                       0x2b, 0x0a, 0xa1, 0x04, 0x58,
+                       0x24, 0x60, 0x97, 0x3a, 0x94,
+                       0xbb, 0x28, 0x98, 0x00, 0x9e,
+                       0xe5, 0x2e, 0xcf, 0xd9, 0xab,
+                       0x1d, 0xd2, 0x58, 0x67, 0x37,
+                       0x4b, 0x35, 0x81, 0xf2, 0xc8,
+                       0x00, 0x39, 0x82, 0x63, 0x50,
+                       0xb9, 0x7a, 0xe2, 0x30, 0x0e,
+                       0x42, 0xfc, 0x81, 0x83, 0x40,
+                       0xa2, 0x01, 0x25, 0x04, 0x4a,
+                       0x6f, 0x75, 0x72, 0x2d, 0x73,
+                       0x65, 0x63, 0x72, 0x65, 0x74,
+                       0x40
+       }, test96[]     = {
+                       0xd8, 0x60, 0x84, 0x43, 0xa1,
+                       0x01, 0x01, 0xa2, 0x05, 0x4c,
+                       0x02, 0xd1, 0xf7, 0xe6, 0xf2,
+                       0x6c, 0x43, 0xd4, 0x86, 0x8d,
+                       0x87, 0xce, 0x07, 0x82, 0x83,
+                       0x43, 0xa1, 0x01, 0x27, 0xa1,
+                       0x04, 0x42, 0x31, 0x31, 0x58,
+                       0x40, 0x9a, 0x8e, 0xed, 0xe3,
+                       0xb3, 0xcb, 0x83, 0x7b, 0xa0,
+                       0x0d, 0xf0, 0x8f, 0xa2, 0x1b,
+                       0x12, 0x8b, 0x2d, 0x6d, 0x91,
+                       0x62, 0xa4, 0x29, 0x0a, 0x58,
+                       0x2d, 0x9f, 0x19, 0xbd, 0x0f,
+                       0xb5, 0x02, 0xf0, 0xf9, 0x2b,
+                       0x9b, 0xf4, 0x53, 0xa4, 0x05,
+                       0x40, 0x1f, 0x8b, 0x70, 0x55,
+                       0xef, 0x4e, 0x95, 0x8d, 0xf7,
+                       0xf4, 0xfb, 0xd7, 0xcf, 0xb4,
+                       0xa0, 0xc9, 0x71, 0x60, 0xf9,
+                       0x47, 0x2b, 0x0a, 0xa1, 0x04,
+                       0x83, 0x43, 0xa1, 0x01, 0x26,
+                       0xa1, 0x04, 0x42, 0x31, 0x31,
+                       0x58, 0x40, 0x24, 0x27, 0xcb,
+                       0x37, 0x56, 0x85, 0x0f, 0xbb,
+                       0x79, 0x05, 0x18, 0x07, 0xc8,
+                       0xb2, 0x3d, 0x2e, 0x6d, 0x16,
+                       0xa3, 0x22, 0x4f, 0x99, 0x01,
+                       0xb4, 0x73, 0x99, 0xcf, 0xc7,
+                       0xe3, 0xfa, 0xc4, 0xcc, 0x62,
+                       0x1d, 0xbb, 0xeb, 0x02, 0x02,
+                       0xa6, 0xd8, 0xbb, 0x25, 0x69,
+                       0x5c, 0x9d, 0xcc, 0x9c, 0x47,
+                       0x49, 0x20, 0xff, 0x57, 0x60,
+                       0x6d, 0x76, 0x4d, 0xea, 0x19,
+                       0x2f, 0xc8, 0x67, 0x41, 0x16,
+                       0xf2, 0x58, 0x24, 0x60, 0x97,
+                       0x3a, 0x94, 0xbb, 0x28, 0x98,
+                       0x00, 0x9e, 0xe5, 0x2e, 0xcf,
+                       0xd9, 0xab, 0x1d, 0xd2, 0x58,
+                       0x67, 0x37, 0x4b, 0x35, 0x81,
+                       0xf2, 0xc8, 0x00, 0x39, 0x82,
+                       0x63, 0x50, 0xb9, 0x7a, 0xe2,
+                       0x30, 0x0e, 0x42, 0xfc, 0x81,
+                       0x83, 0x40, 0xa2, 0x01, 0x25,
+                       0x04, 0x4a, 0x6f, 0x75, 0x72,
+                       0x2d, 0x73, 0x65, 0x63, 0x72,
+                       0x65, 0x74, 0x40
+
+       }, test97[]     = {
+                       0xd8, 0x60, 0x84, 0x43, 0xa1,
+                       0x01, 0x01, 0xa1, 0x05, 0x4c,
+                       0x02, 0xd1, 0xf7, 0xe6, 0xf2,
+                       0x6c, 0x43, 0xd4, 0x86, 0x8d,
+                       0x87, 0xce, 0x58, 0x24, 0x60,
+                       0x97, 0x3a, 0x94, 0xbb, 0x28,
+                       0x98, 0x00, 0x9e, 0xe5, 0x2e,
+                       0xcf, 0xd9, 0xab, 0x1d, 0xd2,
+                       0x58, 0x67, 0x37, 0x4b, 0x35,
+                       0x81, 0xf2, 0xc8, 0x00, 0x39,
+                       0x82, 0x63, 0x50, 0xb9, 0x7a,
+                       0xe2, 0x30, 0x0e, 0x42, 0xfc,
+                       0x81, 0x83, 0x40, 0xa3, 0x01,
+                       0x25, 0x04, 0x4a, 0x6f, 0x75,
+                       0x72, 0x2d, 0x73, 0x65, 0x63,
+                       0x72, 0x65, 0x74, 0x07, 0x83,
+                       0x43, 0xa1, 0x01, 0x27, 0xa1,
+                       0x04, 0x42, 0x31, 0x31, 0x58,
+                       0x40, 0xcc, 0xb1, 0xf3, 0xfe,
+                       0xdf, 0xce, 0xa7, 0x2b, 0x9c,
+                       0x86, 0x79, 0x63, 0xe2, 0x52,
+                       0xb6, 0x65, 0x8a, 0xd0, 0x7f,
+                       0x3f, 0x5f, 0x15, 0xa3, 0x26,
+                       0xa3, 0xf5, 0x72, 0x54, 0xcc,
+                       0xb8, 0xd4, 0x8d, 0x60, 0x02,
+                       0x1d, 0x2f, 0x1f, 0x8a, 0x80,
+                       0x3b, 0x84, 0x4b, 0x78, 0x72,
+                       0x16, 0x6c, 0x6d, 0x45, 0x90,
+                       0x25, 0xd2, 0x1c, 0x8c, 0x84,
+                       0x62, 0xa2, 0x44, 0xba, 0x19,
+                       0x60, 0x4e, 0xc4, 0xd5, 0x0b,
+                       0x40
+       }, test98[]     = {
+                       0xd8, 0x61, 0x85, 0x43, 0xa1,
+                       0x01, 0x05, 0xa1, 0x07, 0x83,
+                       0x43, 0xa1, 0x01, 0x27, 0xa1,
+                       0x04, 0x42, 0x31, 0x31, 0x58,
+                       0x40, 0xb4, 0x92, 0x4b, 0x18,
+                       0xeb, 0x4e, 0x04, 0x73, 0x13,
+                       0xc7, 0x07, 0xb0, 0xed, 0xa4,
+                       0xab, 0x84, 0x43, 0x45, 0xf2,
+                       0xc4, 0x49, 0x87, 0xd6, 0xf9,
+                       0xeb, 0xcc, 0x77, 0x7e, 0xfd,
+                       0x40, 0x78, 0xcc, 0x0f, 0x4c,
+                       0x10, 0x8d, 0xef, 0x95, 0x9f,
+                       0x78, 0xf1, 0xed, 0xb2, 0x76,
+                       0x54, 0x25, 0x78, 0x5f, 0xcd,
+                       0x17, 0xd5, 0x12, 0xbe, 0x31,
+                       0xee, 0xb6, 0x6b, 0xef, 0xf1,
+                       0xe8, 0xfc, 0x27, 0x47, 0x07,
+                       0x54, 0x54, 0x68, 0x69, 0x73,
+                       0x20, 0x69, 0x73, 0x20, 0x74,
+                       0x68, 0x65, 0x20, 0x63, 0x6f,
+                       0x6e, 0x74, 0x65, 0x6e, 0x74,
+                       0x2e, 0x58, 0x20, 0x2b, 0xdc,
+                       0xc8, 0x9f, 0x05, 0x82, 0x16,
+                       0xb8, 0xa2, 0x08, 0xdd, 0xc6,
+                       0xd8, 0xb5, 0x4a, 0xa9, 0x1f,
+                       0x48, 0xbd, 0x63, 0x48, 0x49,
+                       0x86, 0x56, 0x51, 0x05, 0xc9,
+                       0xad, 0x5a, 0x66, 0x82, 0xf6,
+                       0x81, 0x83, 0x40, 0xa2, 0x01,
+                       0x25, 0x04, 0x4a, 0x6f, 0x75,
+                       0x72, 0x2d, 0x73, 0x65, 0x63,
+                       0x72, 0x65, 0x74, 0x40
+       }, test99[]     = {
+                       0xd8, 0x61, 0x85, 0x43, 0xa1,
+                       0x01, 0x05, 0xa1, 0x07, 0x82,
+                       0x83, 0x43, 0xa1, 0x01, 0x27,
+                       0xa1, 0x04, 0x42, 0x31, 0x31,
+                       0x58, 0x40, 0xb4, 0x92, 0x4b,
+                       0x18, 0xeb, 0x4e, 0x04, 0x73,
+                       0x13, 0xc7, 0x07, 0xb0, 0xed,
+                       0xa4, 0xab, 0x84, 0x43, 0x45,
+                       0xf2, 0xc4, 0x49, 0x87, 0xd6,
+                       0xf9, 0xeb, 0xcc, 0x77, 0x7e,
+                       0xfd, 0x40, 0x78, 0xcc, 0x0f,
+                       0x4c, 0x10, 0x8d, 0xef, 0x95,
+                       0x9f, 0x78, 0xf1, 0xed, 0xb2,
+                       0x76, 0x54, 0x25, 0x78, 0x5f,
+                       0xcd, 0x17, 0xd5, 0x12, 0xbe,
+                       0x31, 0xee, 0xb6, 0x6b, 0xef,
+                       0xf1, 0xe8, 0xfc, 0x27, 0x47,
+                       0x07, 0x83, 0x43, 0xa1, 0x01,
+                       0x26, 0xa1, 0x04, 0x42, 0x31,
+                       0x31, 0x58, 0x40, 0x6a, 0xcd,
+                       0x94, 0xd3, 0xcc, 0xf7, 0x1d,
+                       0x19, 0x2e, 0x85, 0x28, 0x36,
+                       0x0b, 0xa7, 0xe3, 0x46, 0xda,
+                       0xc4, 0x64, 0xe9, 0xed, 0xca,
+                       0x4c, 0xfe, 0xb6, 0xce, 0xb6,
+                       0xbd, 0xe7, 0xba, 0xec, 0x9f,
+                       0xf2, 0x6c, 0xa6, 0xbd, 0xf7,
+                       0x3d, 0x0b, 0xe4, 0x1e, 0x36,
+                       0x12, 0x9d, 0xcf, 0xf7, 0x51,
+                       0xdd, 0x2b, 0x5a, 0xd5, 0xce,
+                       0x11, 0x6e, 0x8a, 0x96, 0x3a,
+                       0x27, 0x38, 0xa2, 0x99, 0x47,
+                       0x7a, 0x68, 0x54, 0x54, 0x68,
+                       0x69, 0x73, 0x20, 0x69, 0x73,
+                       0x20, 0x74, 0x68, 0x65, 0x20,
+                       0x63, 0x6f, 0x6e, 0x74, 0x65,
+                       0x6e, 0x74, 0x2e, 0x58, 0x20,
+                       0x2b, 0xdc, 0xc8, 0x9f, 0x05,
+                       0x82, 0x16, 0xb8, 0xa2, 0x08,
+                       0xdd, 0xc6, 0xd8, 0xb5, 0x4a,
+                       0xa9, 0x1f, 0x48, 0xbd, 0x63,
+                       0x48, 0x49, 0x86, 0x56, 0x51,
+                       0x05, 0xc9, 0xad, 0x5a, 0x66,
+                       0x82, 0xf6, 0x81, 0x83, 0x40,
+                       0xa2, 0x01, 0x25, 0x04, 0x4a,
+                       0x6f, 0x75, 0x72, 0x2d, 0x73,
+                       0x65, 0x63, 0x72, 0x65, 0x74,
+                       0x40
+       }, test100[]    = {
+                       0xd1, 0x84, 0x43, 0xa1, 0x01,
+                       0x05, 0xa1, 0x07, 0x83, 0x43,
+                       0xa1, 0x01, 0x27, 0xa1, 0x04,
+                       0x42, 0x31, 0x31, 0x58, 0x40,
+                       0xb4, 0x92, 0x4b, 0x18, 0xeb,
+                       0x4e, 0x04, 0x73, 0x13, 0xc7,
+                       0x07, 0xb0, 0xed, 0xa4, 0xab,
+                       0x84, 0x43, 0x45, 0xf2, 0xc4,
+                       0x49, 0x87, 0xd6, 0xf9, 0xeb,
+                       0xcc, 0x77, 0x7e, 0xfd, 0x40,
+                       0x78, 0xcc, 0x0f, 0x4c, 0x10,
+                       0x8d, 0xef, 0x95, 0x9f, 0x78,
+                       0xf1, 0xed, 0xb2, 0x76, 0x54,
+                       0x25, 0x78, 0x5f, 0xcd, 0x17,
+                       0xd5, 0x12, 0xbe, 0x31, 0xee,
+                       0xb6, 0x6b, 0xef, 0xf1, 0xe8,
+                       0xfc, 0x27, 0x47, 0x07, 0x54,
+                       0x54, 0x68, 0x69, 0x73, 0x20,
+                       0x69, 0x73, 0x20, 0x74, 0x68,
+                       0x65, 0x20, 0x63, 0x6f, 0x6e,
+                       0x74, 0x65, 0x6e, 0x74, 0x2e,
+                       0x58, 0x20, 0xa1, 0xa8, 0x48,
+                       0xd3, 0x47, 0x1f, 0x9d, 0x61,
+                       0xee, 0x49, 0x01, 0x8d, 0x24,
+                       0x4c, 0x82, 0x47, 0x72, 0xf2,
+                       0x23, 0xad, 0x4f, 0x93, 0x52,
+                       0x93, 0xf1, 0x78, 0x9f, 0xc3,
+                       0xa0, 0x8d, 0x8c, 0x58
+       }, test101[]    = { /* mac-02 */
+                       0xd8, 0x61, 0x85, 0x43, 0xa1,
+                       0x01, 0x05, 0xa1, 0x07, 0x82,
+                       0x83, 0x43, 0xa1, 0x01, 0x27,
+                       0xa1, 0x04, 0x42, 0x31, 0x31,
+                       0x58, 0x40, 0xb4, 0x92, 0x4b,
+                       0x18, 0xeb, 0x4e, 0x04, 0x73,
+                       0x13, 0xc7, 0x07, 0xb0, 0xed,
+                       0xa4, 0xab, 0x84, 0x43, 0x45,
+                       0xf2, 0xc4, 0x49, 0x87, 0xd6,
+                       0xf9, 0xeb, 0xcc, 0x77, 0x7e,
+                       0xfd, 0x40, 0x78, 0xcc, 0x0f,
+                       0x4c, 0x10, 0x8d, 0xef, 0x95,
+                       0x9f, 0x78, 0xf1, 0xed, 0xb2,
+                       0x76, 0x54, 0x25, 0x78, 0x5f,
+                       0xcd, 0x17, 0xd5, 0x12, 0xbe,
+                       0x31, 0xee, 0xb6, 0x6b, 0xef,
+                       0xf1, 0xe8, 0xfc, 0x27, 0x47,
+                       0x07, 0x83, 0x43, 0xa1, 0x01,
+                       0x26, 0xa1, 0x04, 0x42, 0x31,
+                       0x31, 0x58, 0x40, 0x6a, 0xcd,
+                       0x94, 0xd3, 0xcc, 0xf7, 0x1d,
+                       0x19, 0x2e, 0x85, 0x28, 0x36,
+                       0x0b, 0xa7, 0xe3, 0x46, 0xda,
+                       0xc4, 0x64, 0xe9, 0xed, 0xca,
+                       0x4c, 0xfe, 0xb6, 0xce, 0xb6,
+                       0xbd, 0xe7, 0xba, 0xec, 0x9f,
+                       0xf2, 0x6c, 0xa6, 0xbd, 0xf7,
+                       0x3d, 0x0b, 0xe4, 0x1e, 0x36,
+                       0x12, 0x9d, 0xcf, 0xf7, 0x51,
+                       0xdd, 0x2b, 0x5a, 0xd5, 0xce,
+                       0x11, 0x6e, 0x8a, 0x96, 0x3a,
+                       0x27, 0x38, 0xa2, 0x99, 0x47,
+                       0x7a, 0x68, 0x54, 0x54, 0x68,
+                       0x69, 0x73, 0x20, 0x69, 0x73,
+                       0x20, 0x74, 0x68, 0x65, 0x20,
+                       0x63, 0x6f, 0x6e, 0x74, 0x65,
+                       0x6e, 0x74, 0x2e, 0x58, 0x20,
+                       0x2b, 0xdc, 0xc8, 0x9f, 0x05,
+                       0x82, 0x16, 0xb8, 0xa2, 0x08,
+                       0xdd, 0xc6, 0xd8, 0xb5, 0x4a,
+                       0xa9, 0x1f, 0x48, 0xbd, 0x63,
+                       0x48, 0x49, 0x86, 0x56, 0x51,
+                       0x05, 0xc9, 0xad, 0x5a, 0x66,
+                       0x82, 0xf6, 0x81, 0x83, 0x40,
+                       0xa2, 0x01, 0x25, 0x04, 0x4a,
+                       0x6f, 0x75, 0x72, 0x2d, 0x73,
+                       0x65, 0x63, 0x72, 0x65, 0x74,
+                       0x40
+       }, test102[] = { /* mac0-01 */
+                       0xd1, 0x84, 0x43, 0xa1, 0x01,
+                       0x05, 0xa1, 0x07, 0x83, 0x43,
+                       0xa1, 0x01, 0x27, 0xa1, 0x04,
+                       0x42, 0x31, 0x31, 0x58, 0x40,
+                       0xb4, 0x92, 0x4b, 0x18, 0xeb,
+                       0x4e, 0x04, 0x73, 0x13, 0xc7,
+                       0x07, 0xb0, 0xed, 0xa4, 0xab,
+                       0x84, 0x43, 0x45, 0xf2, 0xc4,
+                       0x49, 0x87, 0xd6, 0xf9, 0xeb,
+                       0xcc, 0x77, 0x7e, 0xfd, 0x40,
+                       0x78, 0xcc, 0x0f, 0x4c, 0x10,
+                       0x8d, 0xef, 0x95, 0x9f, 0x78,
+                       0xf1, 0xed, 0xb2, 0x76, 0x54,
+                       0x25, 0x78, 0x5f, 0xcd, 0x17,
+                       0xd5, 0x12, 0xbe, 0x31, 0xee,
+                       0xb6, 0x6b, 0xef, 0xf1, 0xe8,
+                       0xfc, 0x27, 0x47, 0x07, 0x54,
+                       0x54, 0x68, 0x69, 0x73, 0x20,
+                       0x69, 0x73, 0x20, 0x74, 0x68,
+                       0x65, 0x20, 0x63, 0x6f, 0x6e,
+                       0x74, 0x65, 0x6e, 0x74, 0x2e,
+                       0x58, 0x20, 0xa1, 0xa8, 0x48,
+                       0xd3, 0x47, 0x1f, 0x9d, 0x61,
+                       0xee, 0x49, 0x01, 0x8d, 0x24,
+                       0x4c, 0x82, 0x47, 0x72, 0xf2,
+                       0x23, 0xad, 0x4f, 0x93, 0x52,
+                       0x93, 0xf1, 0x78, 0x9f, 0xc3,
+                       0xa0, 0x8d, 0x8c, 0x58
+       }, test103[] = { /* mac0-02 */
+                       0xd1, 0x84, 0x43, 0xa1, 0x01,
+                       0x05, 0xa1, 0x07, 0x82, 0x83,
+                       0x43, 0xa1, 0x01, 0x27, 0xa1,
+                       0x04, 0x42, 0x31, 0x31, 0x58,
+                       0x40, 0xb4, 0x92, 0x4b, 0x18,
+                       0xeb, 0x4e, 0x04, 0x73, 0x13,
+                       0xc7, 0x07, 0xb0, 0xed, 0xa4,
+                       0xab, 0x84, 0x43, 0x45, 0xf2,
+                       0xc4, 0x49, 0x87, 0xd6, 0xf9,
+                       0xeb, 0xcc, 0x77, 0x7e, 0xfd,
+                       0x40, 0x78, 0xcc, 0x0f, 0x4c,
+                       0x10, 0x8d, 0xef, 0x95, 0x9f,
+                       0x78, 0xf1, 0xed, 0xb2, 0x76,
+                       0x54, 0x25, 0x78, 0x5f, 0xcd,
+                       0x17, 0xd5, 0x12, 0xbe, 0x31,
+                       0xee, 0xb6, 0x6b, 0xef, 0xf1,
+                       0xe8, 0xfc, 0x27, 0x47, 0x07,
+                       0x83, 0x43, 0xa1, 0x01, 0x26,
+                       0xa1, 0x04, 0x42, 0x31, 0x31,
+                       0x58, 0x40, 0x6a, 0xcd, 0x94,
+                       0xd3, 0xcc, 0xf7, 0x1d, 0x19,
+                       0x2e, 0x85, 0x28, 0x36, 0x0b,
+                       0xa7, 0xe3, 0x46, 0xda, 0xc4,
+                       0x64, 0xe9, 0xed, 0xca, 0x4c,
+                       0xfe, 0xb6, 0xce, 0xb6, 0xbd,
+                       0xe7, 0xba, 0xec, 0x9f, 0xf2,
+                       0x6c, 0xa6, 0xbd, 0xf7, 0x3d,
+                       0x0b, 0xe4, 0x1e, 0x36, 0x12,
+                       0x9d, 0xcf, 0xf7, 0x51, 0xdd,
+                       0x2b, 0x5a, 0xd5, 0xce, 0x11,
+                       0x6e, 0x8a, 0x96, 0x3a, 0x27,
+                       0x38, 0xa2, 0x99, 0x47, 0x7a,
+                       0x68, 0x54, 0x54, 0x68, 0x69,
+                       0x73, 0x20, 0x69, 0x73, 0x20,
+                       0x74, 0x68, 0x65, 0x20, 0x63,
+                       0x6f, 0x6e, 0x74, 0x65, 0x6e,
+                       0x74, 0x2e, 0x58, 0x20, 0xa1,
+                       0xa8, 0x48, 0xd3, 0x47, 0x1f,
+                       0x9d, 0x61, 0xee, 0x49, 0x01,
+                       0x8d, 0x24, 0x4c, 0x82, 0x47,
+                       0x72, 0xf2, 0x23, 0xad, 0x4f,
+                       0x93, 0x52, 0x93, 0xf1, 0x78,
+                       0x9f, 0xc3, 0xa0, 0x8d, 0x8c,
+                       0x58
+       }, test104[] = { /* signed-01 */
+                       0xd8, 0x62, 0x84, 0x43, 0xa1,
+                       0x03, 0x00, 0xa0, 0x54, 0x54,
+                       0x68, 0x69, 0x73, 0x20, 0x69,
+                       0x73, 0x20, 0x74, 0x68, 0x65,
+                       0x20, 0x63, 0x6f, 0x6e, 0x74,
+                       0x65, 0x6e, 0x74, 0x2e, 0x81,
+                       0x83, 0x43, 0xa1, 0x01, 0x27,
+                       0xa2, 0x07, 0x83, 0x43, 0xa1,
+                       0x01, 0x27, 0xa1, 0x04, 0x42,
+                       0x31, 0x31, 0x58, 0x40, 0x8e,
+                       0x1b, 0xe2, 0xf9, 0x45, 0x3d,
+                       0x26, 0x48, 0x12, 0xe5, 0x90,
+                       0x49, 0x91, 0x32, 0xbe, 0xf3,
+                       0xfb, 0xf9, 0xee, 0x9d, 0xb2,
+                       0x7c, 0x2c, 0x16, 0x87, 0x88,
+                       0xe3, 0xb7, 0xeb, 0xe5, 0x06,
+                       0xc0, 0x4f, 0xd3, 0xd1, 0x9f,
+                       0xaa, 0x9f, 0x51, 0x23, 0x2a,
+                       0xf5, 0xc9, 0x59, 0xe4, 0xef,
+                       0x47, 0x92, 0x88, 0x34, 0x64,
+                       0x7f, 0x56, 0xdf, 0xbe, 0x93,
+                       0x91, 0x12, 0x88, 0x4d, 0x08,
+                       0xef, 0x25, 0x05, 0x04, 0x42,
+                       0x31, 0x31, 0x58, 0x40, 0x77,
+                       0xf3, 0xea, 0xcd, 0x11, 0x85,
+                       0x2c, 0x4b, 0xf9, 0xcb, 0x1d,
+                       0x72, 0xfa, 0xbe, 0x6b, 0x26,
+                       0xfb, 0xa1, 0xd7, 0x60, 0x92,
+                       0xb2, 0xb5, 0xb7, 0xec, 0x83,
+                       0xb8, 0x35, 0x57, 0x65, 0x22,
+                       0x64, 0xe6, 0x96, 0x90, 0xdb,
+                       0xc1, 0x17, 0x2d, 0xdc, 0x0b,
+                       0xf8, 0x84, 0x11, 0xc0, 0xd2,
+                       0x5a, 0x50, 0x7f, 0xdb, 0x24,
+                       0x7a, 0x20, 0xc4, 0x0d, 0x5e,
+                       0x24, 0x5f, 0xab, 0xd3, 0xfc,
+                       0x9e, 0xc1, 0x06
+       }, test105[] = { /* signed-02 */
+                       0xd8, 0x62, 0x84, 0x43, 0xa1,
+                       0x03, 0x00, 0xa0, 0x54, 0x54,
+                       0x68, 0x69, 0x73, 0x20, 0x69,
+                       0x73, 0x20, 0x74, 0x68, 0x65,
+                       0x20, 0x63, 0x6f, 0x6e, 0x74,
+                       0x65, 0x6e, 0x74, 0x2e, 0x81,
+                       0x83, 0x43, 0xa1, 0x01, 0x27,
+                       0xa2, 0x07, 0x82, 0x83, 0x43,
+                       0xa1, 0x01, 0x27, 0xa1, 0x04,
+                       0x42, 0x31, 0x31, 0x58, 0x40,
+                       0x8e, 0x1b, 0xe2, 0xf9, 0x45,
+                       0x3d, 0x26, 0x48, 0x12, 0xe5,
+                       0x90, 0x49, 0x91, 0x32, 0xbe,
+                       0xf3, 0xfb, 0xf9, 0xee, 0x9d,
+                       0xb2, 0x7c, 0x2c, 0x16, 0x87,
+                       0x88, 0xe3, 0xb7, 0xeb, 0xe5,
+                       0x06, 0xc0, 0x4f, 0xd3, 0xd1,
+                       0x9f, 0xaa, 0x9f, 0x51, 0x23,
+                       0x2a, 0xf5, 0xc9, 0x59, 0xe4,
+                       0xef, 0x47, 0x92, 0x88, 0x34,
+                       0x64, 0x7f, 0x56, 0xdf, 0xbe,
+                       0x93, 0x91, 0x12, 0x88, 0x4d,
+                       0x08, 0xef, 0x25, 0x05, 0x83,
+                       0x43, 0xa1, 0x01, 0x26, 0xa1,
+                       0x04, 0x42, 0x31, 0x31, 0x58,
+                       0x40, 0xaf, 0x04, 0x9b, 0x80,
+                       0xd5, 0x2c, 0x36, 0x69, 0xb2,
+                       0x99, 0x70, 0xc1, 0x33, 0x54,
+                       0x37, 0x54, 0xf9, 0xcc, 0x60,
+                       0x8c, 0xe4, 0x11, 0x23, 0xae,
+                       0x1c, 0x82, 0x7e, 0x36, 0xb3,
+                       0x8c, 0xb8, 0x25, 0x98, 0x7f,
+                       0x01, 0xf2, 0x2b, 0xb8, 0xab,
+                       0x13, 0xe9, 0xc6, 0x62, 0x26,
+                       0xee, 0x23, 0x17, 0x8f, 0xfa,
+                       0x00, 0xa4, 0xfc, 0x22, 0x05,
+                       0x93, 0xb6, 0xe5, 0xac, 0x38,
+                       0x96, 0x00, 0x71, 0xc9, 0xc8,
+                       0x04, 0x42, 0x31, 0x31, 0x58,
+                       0x40, 0x77, 0xf3, 0xea, 0xcd,
+                       0x11, 0x85, 0x2c, 0x4b, 0xf9,
+                       0xcb, 0x1d, 0x72, 0xfa, 0xbe,
+                       0x6b, 0x26, 0xfb, 0xa1, 0xd7,
+                       0x60, 0x92, 0xb2, 0xb5, 0xb7,
+                       0xec, 0x83, 0xb8, 0x35, 0x57,
+                       0x65, 0x22, 0x64, 0xe6, 0x96,
+                       0x90, 0xdb, 0xc1, 0x17, 0x2d,
+                       0xdc, 0x0b, 0xf8, 0x84, 0x11,
+                       0xc0, 0xd2, 0x5a, 0x50, 0x7f,
+                       0xdb, 0x24, 0x7a, 0x20, 0xc4,
+                       0x0d, 0x5e, 0x24, 0x5f, 0xab,
+                       0xd3, 0xfc, 0x9e, 0xc1, 0x06
+       }, test106[] = { /* signed-03 */
+                       0xd8, 0x62, 0x84, 0x43, 0xa1,
+                       0x03, 0x00, 0xa1, 0x07, 0x83,
+                       0x43, 0xa1, 0x01, 0x27, 0xa1,
+                       0x04, 0x42, 0x31, 0x31, 0x58,
+                       0x40, 0xb7, 0xca, 0xcb, 0xa2,
+                       0x85, 0xc4, 0xcd, 0x3e, 0xd2,
+                       0xf0, 0x14, 0x6f, 0x41, 0x98,
+                       0x86, 0x14, 0x4c, 0xa6, 0x38,
+                       0xd0, 0x87, 0xde, 0x12, 0x3d,
+                       0x40, 0x01, 0x67, 0x30, 0x8a,
+                       0xce, 0xab, 0xc4, 0xb5, 0xe5,
+                       0xc6, 0xa4, 0x0c, 0x0d, 0xe0,
+                       0xb7, 0x11, 0x67, 0xa3, 0x91,
+                       0x75, 0xea, 0x56, 0xc1, 0xfe,
+                       0x96, 0xc8, 0x9e, 0x5e, 0x7d,
+                       0x30, 0xda, 0xf2, 0x43, 0x8a,
+                       0x45, 0x61, 0x59, 0xa2, 0x0a,
+                       0x54, 0x54, 0x68, 0x69, 0x73,
+                       0x20, 0x69, 0x73, 0x20, 0x74,
+                       0x68, 0x65, 0x20, 0x63, 0x6f,
+                       0x6e, 0x74, 0x65, 0x6e, 0x74,
+                       0x2e, 0x81, 0x83, 0x43, 0xa1,
+                       0x01, 0x27, 0xa1, 0x04, 0x42,
+                       0x31, 0x31, 0x58, 0x40, 0x77,
+                       0xf3, 0xea, 0xcd, 0x11, 0x85,
+                       0x2c, 0x4b, 0xf9, 0xcb, 0x1d,
+                       0x72, 0xfa, 0xbe, 0x6b, 0x26,
+                       0xfb, 0xa1, 0xd7, 0x60, 0x92,
+                       0xb2, 0xb5, 0xb7, 0xec, 0x83,
+                       0xb8, 0x35, 0x57, 0x65, 0x22,
+                       0x64, 0xe6, 0x96, 0x90, 0xdb,
+                       0xc1, 0x17, 0x2d, 0xdc, 0x0b,
+                       0xf8, 0x84, 0x11, 0xc0, 0xd2,
+                       0x5a, 0x50, 0x7f, 0xdb, 0x24,
+                       0x7a, 0x20, 0xc4, 0x0d, 0x5e,
+                       0x24, 0x5f, 0xab, 0xd3, 0xfc,
+                       0x9e, 0xc1, 0x06
+       }, test107[] = { /* signed1-01 */
+                       0xd2, 0x84, 0x45, 0xa2, 0x01,
+                       0x27, 0x03, 0x00, 0xa2, 0x07,
+                       0x83, 0x43, 0xa1, 0x01, 0x27,
+                       0xa1, 0x04, 0x42, 0x31, 0x31,
+                       0x58, 0x40, 0x6d, 0xae, 0xd1,
+                       0x58, 0xaf, 0xe4, 0x03, 0x2e,
+                       0x8d, 0xd4, 0x77, 0xd3, 0xd2,
+                       0xb7, 0xf6, 0x67, 0xe7, 0x95,
+                       0x7a, 0xa8, 0x30, 0x2b, 0xb5,
+                       0xe5, 0x68, 0xb4, 0xdc, 0xbc,
+                       0xce, 0x3c, 0xf0, 0xed, 0x5a,
+                       0x90, 0xf8, 0x31, 0x35, 0x1c,
+                       0x85, 0xd6, 0x15, 0x5a, 0x42,
+                       0xa1, 0x7c, 0xa1, 0xf2, 0x5f,
+                       0x50, 0x1c, 0xc1, 0x3f, 0x67,
+                       0x10, 0x8a, 0xe5, 0x3b, 0xda,
+                       0x92, 0xdb, 0x88, 0x27, 0x2e,
+                       0x00, 0x04, 0x42, 0x31, 0x31,
+                       0x54, 0x54, 0x68, 0x69, 0x73,
+                       0x20, 0x69, 0x73, 0x20, 0x74,
+                       0x68, 0x65, 0x20, 0x63, 0x6f,
+                       0x6e, 0x74, 0x65, 0x6e, 0x74,
+                       0x2e, 0x58, 0x40, 0x71, 0x42,
+                       0xfd, 0x2f, 0xf9, 0x6d, 0x56,
+                       0xdb, 0x85, 0xbe, 0xe9, 0x05,
+                       0xa7, 0x6b, 0xa1, 0xd0, 0xb7,
+                       0x32, 0x1a, 0x95, 0xc8, 0xc4,
+                       0xd3, 0x60, 0x7c, 0x57, 0x81,
+                       0x93, 0x2b, 0x7a, 0xfb, 0x87,
+                       0x11, 0x49, 0x7d, 0xfa, 0x75,
+                       0x1b, 0xf4, 0x0b, 0x58, 0xb3,
+                       0xbc, 0xc3, 0x23, 0x00, 0xb1,
+                       0x48, 0x7f, 0x3d, 0xb3, 0x40,
+                       0x85, 0xee, 0xf0, 0x13, 0xbf,
+                       0x08, 0xf4, 0xa4, 0x4d, 0x6f,
+                       0xef, 0x0d
+       }, test108[] = { /* signed1-02 */
+                       0xd2, 0x84, 0x45, 0xa2, 0x01,
+                       0x27, 0x03, 0x00, 0xa2, 0x07,
+                       0x82, 0x83, 0x43, 0xa1, 0x01,
+                       0x27, 0xa1, 0x04, 0x42, 0x31,
+                       0x31, 0x58, 0x40, 0x6d, 0xae,
+                       0xd1, 0x58, 0xaf, 0xe4, 0x03,
+                       0x2e, 0x8d, 0xd4, 0x77, 0xd3,
+                       0xd2, 0xb7, 0xf6, 0x67, 0xe7,
+                       0x95, 0x7a, 0xa8, 0x30, 0x2b,
+                       0xb5, 0xe5, 0x68, 0xb4, 0xdc,
+                       0xbc, 0xce, 0x3c, 0xf0, 0xed,
+                       0x5a, 0x90, 0xf8, 0x31, 0x35,
+                       0x1c, 0x85, 0xd6, 0x15, 0x5a,
+                       0x42, 0xa1, 0x7c, 0xa1, 0xf2,
+                       0x5f, 0x50, 0x1c, 0xc1, 0x3f,
+                       0x67, 0x10, 0x8a, 0xe5, 0x3b,
+                       0xda, 0x92, 0xdb, 0x88, 0x27,
+                       0x2e, 0x00, 0x83, 0x43, 0xa1,
+                       0x01, 0x26, 0xa1, 0x04, 0x42,
+                       0x31, 0x31, 0x58, 0x40, 0x93,
+                       0x48, 0x7d, 0x09, 0x25, 0x6a,
+                       0x3e, 0xf4, 0x96, 0x37, 0x19,
+                       0xba, 0x5c, 0xf1, 0x01, 0xac,
+                       0xe2, 0xfc, 0x13, 0xd6, 0x31,
+                       0x4b, 0x49, 0x58, 0x21, 0x71,
+                       0xff, 0xa4, 0xa1, 0x31, 0x4d,
+                       0xc9, 0x3e, 0x4a, 0x4a, 0xdf,
+                       0xa4, 0x2a, 0x79, 0xe3, 0x1b,
+                       0x35, 0xd7, 0x30, 0x43, 0x58,
+                       0x58, 0x5b, 0x41, 0x79, 0x96,
+                       0x78, 0xce, 0x00, 0xca, 0x47,
+                       0xc3, 0xe0, 0x23, 0x86, 0x39,
+                       0x23, 0xf8, 0xc8, 0x04, 0x42,
+                       0x31, 0x31, 0x54, 0x54, 0x68,
+                       0x69, 0x73, 0x20, 0x69, 0x73,
+                       0x20, 0x74, 0x68, 0x65, 0x20,
+                       0x63, 0x6f, 0x6e, 0x74, 0x65,
+                       0x6e, 0x74, 0x2e, 0x58, 0x40,
+                       0x71, 0x42, 0xfd, 0x2f, 0xf9,
+                       0x6d, 0x56, 0xdb, 0x85, 0xbe,
+                       0xe9, 0x05, 0xa7, 0x6b, 0xa1,
+                       0xd0, 0xb7, 0x32, 0x1a, 0x95,
+                       0xc8, 0xc4, 0xd3, 0x60, 0x7c,
+                       0x57, 0x81, 0x93, 0x2b, 0x7a,
+                       0xfb, 0x87, 0x11, 0x49, 0x7d,
+                       0xfa, 0x75, 0x1b, 0xf4, 0x0b,
+                       0x58, 0xb3, 0xbc, 0xc3, 0x23,
+                       0x00, 0xb1, 0x48, 0x7f, 0x3d,
+                       0xb3, 0x40, 0x85, 0xee, 0xf0,
+                       0x13, 0xbf, 0x08, 0xf4, 0xa4,
+                       0x4d, 0x6f, 0xef, 0x0d
+       };
+;
+
+struct seq {
+       char                    reason;
+       struct lecp_item        item;
+       const uint8_t           *buf;
+       size_t                  buf_len;
+};
+
+static const uint8_t bm12[] = {
+       0x01, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00
+}, bm48[] = {
+       0x32, 0x30, 0x31, 0x33,
+       0x2D, 0x30, 0x33, 0x2D,
+       0x32, 0x31, 0x54, 0x32,
+       0x30, 0x3A, 0x30, 0x34,
+       0x3A, 0x30, 0x30, 0x5A
+}, bm51[] = {
+       0x01, 0x02, 0x03, 0x04
+}, bm52[] = {
+       0x64, 0x49, 0x45, 0x54,
+       0x46
+}, bm53[] = {
+       0x68, 0x74, 0x74, 0x70,
+       0x3A, 0x2F, 0x2F, 0x77,
+       0x77, 0x77, 0x2E, 0x65,
+       0x78, 0x61, 0x6D, 0x70,
+       0x6C, 0x65, 0x2E, 0x63,
+       0x6F, 0x6D
+}, bm57[] = {
+       0x61
+}, bm58[] = {
+       0x49, 0x45, 0x54, 0x46
+}, bm59[] = {
+       0x22, 0x5C
+}, bm60[] = {
+       0xc3, 0xbc
+}, bm61[] = {
+       0xe6, 0xb0, 0xb4
+}, bm62[] = {
+       0xF0, 0x90, 0x85, 0x91
+}, bm72a[] = {
+       0x01, 0x02
+}, bm72b[] = {
+       0x03, 0x04, 0x05
+}, bm83a[] = {
+       0xa1, 0x01, 0x05
+}, bm83b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm83c[] = {
+       0x2B, 0xDC, 0xC8, 0x9F,
+       0x05, 0x82, 0x16, 0xB8,
+       0xA2, 0x08, 0xDD, 0xC6,
+       0xD8, 0xB5, 0x4A, 0xA9,
+       0x1F, 0x48, 0xBD, 0x63,
+       0x48, 0x49, 0x86, 0x56,
+       0x51, 0x05, 0xC9, 0xAD,
+       0x5A, 0x66, 0x82, 0xF6
+}, bm83d[] = {
+       0x6F, 0x75, 0x72, 0x2D,
+       0x73, 0x65, 0x63, 0x72,
+       0x65, 0x74
+}, bm84a[] = {
+       0xa1, 0x01, 0x06
+}, bm84b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm84c[] = {
+       0xB3, 0x09, 0x7F, 0x70,
+       0x00, 0x9A, 0x11, 0x50,
+       0x74, 0x09, 0x59, 0x8A,
+       0x83, 0xE1, 0x5B, 0xBB,
+       0xBF, 0x19, 0x82, 0xDC,
+       0xE2, 0x8E, 0x5A, 0xB6,
+       0xD5, 0xA6, 0xAF, 0xF6,
+       0x89, 0x7B, 0xD2, 0x4B,
+       0xB8, 0xB7, 0x47, 0x96,
+       0x22, 0xC9, 0x40, 0x1B,
+       0x24, 0x09, 0x0D, 0x45,
+       0x82, 0x06, 0xD5, 0x87
+}, bm84d[] = {
+       0x73, 0x65, 0x63, 0x2D,
+       0x34, 0x38
+}, bm85a[] = {
+       0xa1, 0x01, 0x07
+}, bm85b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm85c[] = {
+       0xCD, 0x28, 0xA6, 0xB3,
+       0xCF, 0xBB, 0xBF, 0x21,
+       0x48, 0x51, 0xB9, 0x06,
+       0xE0, 0x50, 0x05, 0x6C,
+       0xB4, 0x38, 0xA8, 0xB8,
+       0x89, 0x05, 0xB8, 0xB7,
+       0x46, 0x19, 0x77, 0x02,
+       0x27, 0x11, 0xA9, 0xD8,
+       0xAC, 0x5D, 0xBC, 0x54,
+       0xE2, 0x9A, 0x56, 0xD9,
+       0x26, 0x04, 0x6B, 0x40,
+       0xFC, 0x26, 0x07, 0xC2,
+       0x5B, 0x34, 0x44, 0x54,
+       0xAA, 0x5F, 0x68, 0xDE,
+       0x09, 0xA3, 0xE5, 0x25,
+       0xD3, 0x86, 0x5A, 0x05
+}, bm85d[] = {
+       0x73, 0x65, 0x63, 0x2D,
+       0x36, 0x34
+}, bm86a[] = {
+       0xa1, 0x01, 0x05
+}, bm86b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm86c[] = {
+       0x2B, 0xDC, 0xC8, 0x9F,
+       0x05, 0x82, 0x16, 0xB8,
+       0xA2, 0x08, 0xDD, 0xC6,
+       0xD8, 0xB5, 0x4A, 0xA9,
+       0x1F, 0x48, 0xBD, 0x63,
+       0x48, 0x49, 0x86, 0x56,
+       0x51, 0x05, 0xC9, 0xAD,
+       0x5A, 0x66, 0x82, 0xF7
+}, bm86d[] = {
+       0x6F, 0x75, 0x72, 0x2D,
+       0x73, 0x65, 0x63, 0x72,
+       0x65, 0x74
+}, bm87a[] = {
+       0xa1, 0x01, 0x04
+}, bm87b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm87c[] = {
+       0x6F, 0x35, 0xCA, 0xB7,
+       0x79, 0xF7, 0x78, 0x33
+}, bm87d[] = {
+       0x6F, 0x75, 0x72, 0x2D,
+       0x73, 0x65, 0x63, 0x72,
+       0x65, 0x74
+}, bm88a[] = {
+       0xa1, 0x01, 0x05
+}, bm88b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm88c[] = {
+       0xA1, 0xA8, 0x48, 0xD3,
+       0x47, 0x1F, 0x9D, 0x61,
+       0xEE, 0x49, 0x01, 0x8D,
+       0x24, 0x4C, 0x82, 0x47,
+       0x72, 0xF2, 0x23, 0xAD,
+       0x4F, 0x93, 0x52, 0x93,
+       0xF1, 0x78, 0x9F, 0xC3,
+       0xA0, 0x8D, 0x8C, 0x58
+}, bm89a[] = {
+       0xa1, 0x01, 0x06
+}, bm89b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm89c[] = {
+       0x99, 0x8D, 0x26, 0xC6,
+       0x45, 0x9A, 0xAE, 0xEC,
+       0xF4, 0x4E, 0xD2, 0x0C,
+       0xE0, 0x0C, 0x8C, 0xCE,
+       0xDF, 0x0A, 0x1F, 0x3D,
+       0x22, 0xA9, 0x2F, 0xC0,
+       0x5D, 0xB0, 0x8C, 0x5A,
+       0xEB, 0x1C, 0xB5, 0x94,
+       0xCA, 0xAF, 0x5A, 0x5C,
+       0x5E, 0x2E, 0x9D, 0x01,
+       0xCC, 0xE7, 0xE7, 0x7A,
+       0x93, 0xAA, 0x8C, 0x62
+}, bm90a[] = {
+       0xa1, 0x01, 0x07
+}, bm90b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm90c[] = {
+       0x4A, 0x55, 0x5B, 0xF9,
+       0x71, 0xF7, 0xC1, 0x89,
+       0x1D, 0x9D, 0xDF, 0x30,
+       0x4A, 0x1A, 0x13, 0x2E,
+       0x2D, 0x6F, 0x81, 0x74,
+       0x49, 0x47, 0x4D, 0x81,
+       0x3E, 0x6D, 0x04, 0xD6,
+       0x59, 0x62, 0xBE, 0xD8,
+       0xBB, 0xA7, 0x0C, 0x17,
+       0xE1, 0xF5, 0x30, 0x8F,
+       0xA3, 0x99, 0x62, 0x95,
+       0x9A, 0x4B, 0x9B, 0x8D,
+       0x7D, 0xA8, 0xE6, 0xD8,
+       0x49, 0xB2, 0x09, 0xDC,
+       0xD3, 0xE9, 0x8C, 0xC0,
+       0xF1, 0x1E, 0xDD, 0xF2
+}, bm91a[] = {
+       0xa1, 0x01, 0x05
+}, bm91b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm91c[] = {
+       0xA1, 0xA8, 0x48, 0xD3,
+       0x47, 0x1F, 0x9D, 0x61,
+       0xEE, 0x49, 0x01, 0x8D,
+       0x24, 0x4C, 0x82, 0x47,
+       0x72, 0xF2, 0x23, 0xAD,
+       0x4F, 0x93, 0x52, 0x93,
+       0xF1, 0x78, 0x9F, 0xC3,
+       0xA0, 0x8D, 0x8C, 0x59
+}, bm92a[] = {
+       0xa1, 0x01, 0x04
+}, bm92b[] = {
+       0x54, 0x68, 0x69, 0x73,
+       0x20, 0x69, 0x73, 0x20,
+       0x74, 0x68, 0x65, 0x20,
+       0x63, 0x6F, 0x6E, 0x74,
+       0x65, 0x6E, 0x74, 0x2E
+}, bm92c[] = {
+       0x11, 0xF9, 0xE3, 0x57,
+       0x97, 0x5F, 0xB8, 0x49
+}, bm93a[] = {
+       0xa1, 0x01, 0x01
+}, bm93b[] = {
+       0x02, 0xd1, 0xf7, 0xe6, 0xf2,
+       0x6c, 0x43, 0xd4, 0x86, 0x8d,
+       0x87, 0xce
+}, bm93c[] = {
+       0xa1, 0x01, 0x27
+}, bm93d[] = {
+       0x31, 0x31
+}, bm93e[] = {
+       0xe1, 0x04, 0x39, 0x15, 0x4c,
+       0xc7, 0x5c, 0x7a, 0x3a, 0x53,
+       0x91, 0x49, 0x1f, 0x88, 0x65,
+       0x1e, 0x02, 0x92, 0xfd, 0x0f,
+       0xe0, 0xe0, 0x2c, 0xf7, 0x40,
+       0x54, 0x7e, 0xaf, 0x66, 0x77,
+       0xb4, 0xa4, 0x04, 0x0b, 0x8e,
+       0xca, 0x16, 0xdb, 0x59, 0x28,
+       0x81, 0x26, 0x2f, 0x77, 0xb1,
+       0x4c, 0x1a, 0x08, 0x6c, 0x02,
+       0x26, 0x8b, 0x17, 0x17, 0x1c,
+       0xa1, 0x6b, 0xe4, 0xb8, 0x59,
+       0x5f, 0x8c, 0x0a, 0x08
+}, bm93f[] = {
+       0x60, 0x97, 0x3a, 0x94, 0xbb,
+       0x28, 0x98, 0x00, 0x9e, 0xe5,
+       0x2e, 0xcf, 0xd9, 0xab, 0x1d,
+       0xd2, 0x58, 0x67, 0x37, 0x4b,
+       0x16, 0x2e, 0x2c, 0x03, 0x56,
+       0x8b, 0x41, 0xf5, 0x7c, 0x3c,
+       0xc1, 0x6f, 0x91, 0x66, 0x25,
+       0x0a
+
+}, bm94a[] = {
+       0xa1, 0x01, 0x01
+}, bm94b[] = {
+       0x02, 0xd1, 0xf7, 0xe6, 0xf2,
+       0x6c, 0x43, 0xd4, 0x86, 0x8d,
+       0x87, 0xce
+}, bm94c[] = {
+       0xa1, 0x01, 0x27
+}, bm94d[] = {
+       0x31, 0x31
+}, bm94e[] = {
+       0xe1, 0x04, 0x39, 0x15, 0x4c,
+       0xc7, 0x5c, 0x7a, 0x3a, 0x53,
+       0x91, 0x49, 0x1f, 0x88, 0x65,
+       0x1e, 0x02, 0x92, 0xfd, 0x0f,
+       0xe0, 0xe0, 0x2c, 0xf7, 0x40,
+       0x54, 0x7e, 0xaf, 0x66, 0x77,
+       0xb4, 0xa4, 0x04, 0x0b, 0x8e,
+       0xca, 0x16, 0xdb, 0x59, 0x28,
+       0x81, 0x26, 0x2f, 0x77, 0xb1,
+       0x4c, 0x1a, 0x08, 0x6c, 0x02,
+       0x26, 0x8b, 0x17, 0x17, 0x1c,
+       0xa1, 0x6b, 0xe4, 0xb8, 0x59,
+       0x5f, 0x8c, 0x0a, 0x08
+}, bm94f[] = {
+       0xa1, 0x01, 0x26
+}, bm94g[] = {
+       0x31, 0x31
+}, bm94h[] = {
+       0xfc, 0xa9, 0x8e, 0xca, 0xc8,
+       0x0b, 0x5f, 0xeb, 0x3a, 0xc7,
+       0xc1, 0x08, 0xb2, 0xb7, 0x91,
+       0x10, 0xde, 0x88, 0x86, 0x7b,
+       0xc0, 0x42, 0x6f, 0xc8, 0x3c,
+       0x53, 0xcc, 0xd6, 0x78, 0x96,
+       0x94, 0xed, 0xc5, 0xfe, 0xe3,
+       0xc4, 0x0d, 0xe8, 0xe7, 0xb4,
+       0x4f, 0xe8, 0xaa, 0xd3, 0x67,
+       0xe0, 0x95, 0xc8, 0xfc, 0x31,
+       0xb7, 0x9e, 0xe6, 0x66, 0xdf,
+       0x9c, 0xf9, 0x09, 0x06, 0xeb,
+       0x43, 0x75, 0x6c, 0x73
+}, bm94i[] = {
+       0x60, 0x97, 0x3a, 0x94, 0xbb,
+       0x28, 0x98, 0x00, 0x9e, 0xe5,
+       0x2e, 0xcf, 0xd9, 0xab, 0x1d,
+       0xd2, 0x58, 0x67, 0x37, 0x4b,
+       0x16, 0x2e, 0x2c, 0x03, 0x56,
+       0x8b, 0x41, 0xf5, 0x7c, 0x3c,
+       0xc1, 0x6f, 0x91, 0x66, 0x25,
+       0x0a
+
+}, bm95a[] = {
+       0xa1, 0x01, 0x01
+}, bm95b[] = {
+       0x02, 0xd1, 0xf7, 0xe6, 0xf2,
+       0x6c, 0x43, 0xd4, 0x86, 0x8d,
+       0x87, 0xce
+}, bm95c[] = {
+       0xa1, 0x01, 0x27
+}, bm95d[] = {
+       0x31, 0x31
+}, bm95e[] = {
+       0x9a, 0x8e, 0xed, 0xe3, 0xb3,
+       0xcb, 0x83, 0x7b, 0xa0, 0x0d,
+       0xf0, 0x8f, 0xa2, 0x1b, 0x12,
+       0x8b, 0x2d, 0x6d, 0x91, 0x62,
+       0xa4, 0x29, 0x0a, 0x58, 0x2d,
+       0x9f, 0x19, 0xbd, 0x0f, 0xb5,
+       0x02, 0xf0, 0xf9, 0x2b, 0x9b,
+       0xf4, 0x53, 0xa4, 0x05, 0x40,
+       0x1f, 0x8b, 0x70, 0x55, 0xef,
+       0x4e, 0x95, 0x8d, 0xf7, 0xf4,
+       0xfb, 0xd7, 0xcf, 0xb4, 0xa0,
+       0xc9, 0x71, 0x60, 0xf9, 0x47,
+       0x2b, 0x0a, 0xa1, 0x04
+}, bm95f[] = {
+       0x60, 0x97, 0x3a, 0x94, 0xbb,
+       0x28, 0x98, 0x00, 0x9e, 0xe5,
+       0x2e, 0xcf, 0xd9, 0xab, 0x1d,
+       0xd2, 0x58, 0x67, 0x37, 0x4b,
+       0x35, 0x81, 0xf2, 0xc8, 0x00,
+       0x39, 0x82, 0x63, 0x50, 0xb9,
+       0x7a, 0xe2, 0x30, 0x0E, 0x42,
+       0xFC
+}, bm95g[] = {
+       0x6f, 0x75, 0x72, 0x2d, 0x73,
+       0x65, 0x63, 0x72, 0x65, 0x74
+
+}, bm96a[] = {
+       0xa1, 0x01, 0x01
+}, bm96b[] = {
+       0x02, 0xd1, 0xf7, 0xe6, 0xf2,
+       0x6c, 0x43, 0xd4, 0x86, 0x8d,
+       0x87, 0xce
+}, bm96c[] = {
+       0xa1, 0x01, 0x27
+}, bm96d[] = {
+       0x31, 0x31
+}, bm96e[] = {
+       0x9a, 0x8e, 0xed, 0xe3, 0xb3,
+       0xcb, 0x83, 0x7b, 0xa0, 0x0d,
+       0xf0, 0x8f, 0xa2, 0x1b, 0x12,
+       0x8b, 0x2d, 0x6d, 0x91, 0x62,
+       0xa4, 0x29, 0x0a, 0x58, 0x2d,
+       0x9f, 0x19, 0xbd, 0x0f, 0xb5,
+       0x02, 0xf0, 0xf9, 0x2b, 0x9b,
+       0xf4, 0x53, 0xa4, 0x05, 0x40,
+       0x1f, 0x8b, 0x70, 0x55, 0xef,
+       0x4e, 0x95, 0x8d, 0xf7, 0xf4,
+       0xfb, 0xd7, 0xcf, 0xb4, 0xa0,
+       0xc9, 0x71, 0x60, 0xf9, 0x47,
+       0x2b, 0x0a, 0xa1, 0x04
+}, bm96f[] = {
+       0xa1, 0x01, 0x26
+}, bm96g[] = {
+       0x31, 0x31
+}, bm96h[] = {
+       0x24, 0x27, 0xcb, 0x37, 0x56,
+       0x85, 0x0f, 0xbb, 0x79, 0x05,
+       0x18, 0x07, 0xc8, 0xb2, 0x3d,
+       0x2e, 0x6d, 0x16, 0xa3, 0x22,
+       0x4f, 0x99, 0x01, 0xb4, 0x73,
+       0x99, 0xcf, 0xc7, 0xe3, 0xfa,
+       0xc4, 0xcc, 0x62, 0x1d, 0xbb,
+       0xeb, 0x02, 0x02, 0xa6, 0xd8,
+       0xbb, 0x25, 0x69, 0x5c, 0x9d,
+       0xcc, 0x9c, 0x47, 0x49, 0x20,
+       0xff, 0x57, 0x60, 0x6d, 0x76,
+       0x4d, 0xea, 0x19, 0x2f, 0xc8,
+       0x67, 0x41, 0x16, 0xf2
+}, bm96i[] = {
+       0x60, 0x97, 0x3a, 0x94, 0xbb,
+       0x28, 0x98, 0x00, 0x9e, 0xe5,
+       0x2e, 0xcf, 0xd9, 0xab, 0x1d,
+       0xd2, 0x58, 0x67, 0x37, 0x4b,
+       0x35, 0x81, 0xf2, 0xc8, 0x00,
+       0x39, 0x82, 0x63, 0x50, 0xb9,
+       0x7a, 0xe2, 0x30, 0x0e, 0x42,
+       0xfc
+}, bm96j[] = {
+       0x6f, 0x75, 0x72, 0x2d, 0x73,
+       0x65, 0x63, 0x72, 0x65, 0x74
+
+}, bm97a[] = {
+       0xa1, 0x01, 0x01
+}, bm97b[] = {
+       0x02, 0xd1, 0xf7, 0xe6, 0xf2,
+       0x6c, 0x43, 0xd4, 0x86, 0x8d,
+       0x87, 0xce
+}, bm97c[] = {
+       0x60, 0x97, 0x3a, 0x94, 0xbb,
+       0x28, 0x98, 0x00, 0x9e, 0xe5,
+       0x2e, 0xcf, 0xd9, 0xab, 0x1d,
+       0xd2, 0x58, 0x67, 0x37, 0x4b,
+       0x35, 0x81, 0xf2, 0xc8, 0x00,
+       0x39, 0x82, 0x63, 0x50, 0xb9,
+       0x7a, 0xe2, 0x30, 0x0e, 0x42,
+       0xfc
+}, bm97d[] = {
+       0x6f, 0x75, 0x72, 0x2d, 0x73,
+       0x65, 0x63, 0x72, 0x65, 0x74
+}, bm97e[] = {
+       0xa1, 0x01, 0x27
+}, bm97f[] = {
+       0x31, 0x31
+}, bm97g[] = {
+       0xcc, 0xb1, 0xf3, 0xfe, 0xdf,
+       0xce, 0xa7, 0x2b, 0x9c, 0x86,
+       0x79, 0x63, 0xe2, 0x52, 0xb6,
+       0x65, 0x8a, 0xd0, 0x7f, 0x3f,
+       0x5f, 0x15, 0xa3, 0x26, 0xa3,
+       0xf5, 0x72, 0x54, 0xcc, 0xb8,
+       0xd4, 0x8d, 0x60, 0x02, 0x1d,
+       0x2f, 0x1f, 0x8a, 0x80, 0x3b,
+       0x84, 0x4b, 0x78, 0x72, 0x16,
+       0x6c, 0x6d, 0x45, 0x90, 0x25,
+       0xd2, 0x1c, 0x8c, 0x84, 0x62,
+       0xa2, 0x44, 0xba, 0x19, 0x60,
+       0x4e, 0xc4, 0xd5, 0x0b
+
+}, bm98a[] = {
+       0xa1, 0x01, 0x05
+}, bm98b[] = {
+       0xa1, 0x01, 0x27
+}, bm98c[] = {
+       0x31, 0x31
+}, bm98d[] = {
+       0xb4, 0x92, 0x4b, 0x18, 0xeb,
+       0x4e, 0x04, 0x73, 0x13, 0xc7,
+       0x07, 0xb0, 0xed, 0xa4, 0xab,
+       0x84, 0x43, 0x45, 0xf2, 0xc4,
+       0x49, 0x87, 0xd6, 0xf9, 0xeb,
+       0xcc, 0x77, 0x7e, 0xfd, 0x40,
+       0x78, 0xcc, 0x0f, 0x4c, 0x10,
+       0x8d, 0xef, 0x95, 0x9f, 0x78,
+       0xf1, 0xed, 0xb2, 0x76, 0x54,
+       0x25, 0x78, 0x5f, 0xcd, 0x17,
+       0xd5, 0x12, 0xbe, 0x31, 0xee,
+       0xb6, 0x6b, 0xef, 0xf1, 0xe8,
+       0xfc, 0x27, 0x47, 0x07
+}, bm98e[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm98f[] = {
+       0x2b, 0xdc, 0xc8, 0x9f, 0x05,
+       0x82, 0x16, 0xb8, 0xa2, 0x08,
+       0xdd, 0xc6, 0xd8, 0xb5, 0x4a,
+       0xa9, 0x1f, 0x48, 0xbd, 0x63,
+       0x48, 0x49, 0x86, 0x56, 0x51,
+       0x05, 0xc9, 0xad, 0x5a, 0x66,
+       0x82, 0xf6
+}, bm98g[] = {
+       0x6f, 0x75, 0x72, 0x2d, 0x73,
+       0x65, 0x63, 0x72, 0x65, 0x74
+
+}, bm99a[] = {
+       0xa1, 0x01, 0x05
+}, bm99b[] = {
+       0xa1, 0x01, 0x27
+}, bm99c[] = {
+       0x31, 0x31
+}, bm99d[] = {
+       0xb4, 0x92, 0x4b, 0x18, 0xeb,
+       0x4e, 0x04, 0x73, 0x13, 0xc7,
+       0x07, 0xb0, 0xed, 0xa4, 0xab,
+       0x84, 0x43, 0x45, 0xf2, 0xc4,
+       0x49, 0x87, 0xd6, 0xf9, 0xeb,
+       0xcc, 0x77, 0x7e, 0xfd, 0x40,
+       0x78, 0xcc, 0x0f, 0x4c, 0x10,
+       0x8d, 0xef, 0x95, 0x9f, 0x78,
+       0xf1, 0xed, 0xb2, 0x76, 0x54,
+       0x25, 0x78, 0x5f, 0xcd, 0x17,
+       0xd5, 0x12, 0xbe, 0x31, 0xee,
+       0xb6, 0x6b, 0xef, 0xf1, 0xe8,
+       0xfc, 0x27, 0x47, 0x07
+}, bm99e[] = {
+       0xa1, 0x01, 0x26
+}, bm99f[] = {
+       0x31, 0x31
+}, bm99g[] = {
+       0x6a, 0xcd, 0x94, 0xd3, 0xcc,
+       0xf7, 0x1d, 0x19, 0x2e, 0x85,
+       0x28, 0x36, 0x0b, 0xa7, 0xe3,
+       0x46, 0xda, 0xc4, 0x64, 0xe9,
+       0xed, 0xca, 0x4c, 0xfe, 0xb6,
+       0xce, 0xb6, 0xbd, 0xe7, 0xba,
+       0xec, 0x9f, 0xf2, 0x6c, 0xa6,
+       0xbd, 0xf7, 0x3d, 0x0b, 0xe4,
+       0x1e, 0x36, 0x12, 0x9d, 0xcf,
+       0xf7, 0x51, 0xdd, 0x2b, 0x5a,
+       0xd5, 0xce, 0x11, 0x6e, 0x8a,
+       0x96, 0x3a, 0x27, 0x38, 0xa2,
+       0x99, 0x47, 0x7a, 0x68
+}, bm99h[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm99i[] = {
+       0x2b, 0xdc, 0xc8, 0x9f, 0x05,
+       0x82, 0x16, 0xb8, 0xa2, 0x08,
+       0xdd, 0xc6, 0xd8, 0xb5, 0x4a,
+       0xa9, 0x1f, 0x48, 0xbd, 0x63,
+       0x48, 0x49, 0x86, 0x56, 0x51,
+       0x05, 0xc9, 0xad, 0x5a, 0x66,
+       0x82, 0xf6
+}, bm99j[] = {
+       0x6f, 0x75, 0x72, 0x2d, 0x73,
+       0x65, 0x63, 0x72, 0x65, 0x74
+
+}, bm100a[] = {
+       0xa1, 0x01, 0x05
+}, bm100b[] = {
+       0xa1, 0x01, 0x27
+}, bm100c[] = {
+       0x31, 0x31
+}, bm100d[] = {
+       0xb4, 0x92, 0x4b, 0x18, 0xeb,
+       0x4e, 0x04, 0x73, 0x13, 0xc7,
+       0x07, 0xb0, 0xed, 0xa4, 0xab,
+       0x84, 0x43, 0x45, 0xf2, 0xc4,
+       0x49, 0x87, 0xd6, 0xf9, 0xeb,
+       0xcc, 0x77, 0x7e, 0xfd, 0x40,
+       0x78, 0xcc, 0x0f, 0x4c, 0x10,
+       0x8d, 0xef, 0x95, 0x9f, 0x78,
+       0xf1, 0xed, 0xb2, 0x76, 0x54,
+       0x25, 0x78, 0x5f, 0xcd, 0x17,
+       0xd5, 0x12, 0xbe, 0x31, 0xee,
+       0xb6, 0x6b, 0xef, 0xf1, 0xe8,
+       0xfc, 0x27, 0x47, 0x07
+}, bm100e[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm100f[] = {
+       0xa1, 0xa8, 0x48, 0xd3, 0x47,
+       0x1f, 0x9d, 0x61, 0xee, 0x49,
+       0x01, 0x8d, 0x24, 0x4c, 0x82,
+       0x47, 0x72, 0xf2, 0x23, 0xad,
+       0x4f, 0x93, 0x52, 0x93, 0xf1,
+       0x78, 0x9f, 0xc3, 0xa0, 0x8d,
+       0x8c, 0x58
+
+
+}, bm101a[] = {
+       0xa1, 0x01, 0x05
+}, bm101b[] = {
+       0xa1, 0x01, 0x27
+}, bm101c[] = {
+       0x31, 0x31
+}, bm101d[] = {
+       0xb4, 0x92, 0x4b, 0x18, 0xeb,
+       0x4e, 0x04, 0x73, 0x13, 0xc7,
+       0x07, 0xb0, 0xed, 0xa4, 0xab,
+       0x84, 0x43, 0x45, 0xf2, 0xc4,
+       0x49, 0x87, 0xd6, 0xf9, 0xeb,
+       0xcc, 0x77, 0x7e, 0xfd, 0x40,
+       0x78, 0xcc, 0x0f, 0x4c, 0x10,
+       0x8d, 0xef, 0x95, 0x9f, 0x78,
+       0xf1, 0xed, 0xb2, 0x76, 0x54,
+       0x25, 0x78, 0x5f, 0xcd, 0x17,
+       0xd5, 0x12, 0xbe, 0x31, 0xee,
+       0xb6, 0x6b, 0xef, 0xf1, 0xe8,
+       0xfc, 0x27, 0x47, 0x07
+}, bm101e[] = {
+       0xa1, 0x01, 0x26
+}, bm101f[] = {
+       0x31, 0x31
+}, bm101g[] = {
+       0x6a, 0xcd, 0x94, 0xd3, 0xcc,
+       0xf7, 0x1d, 0x19, 0x2e, 0x85,
+       0x28, 0x36, 0x0b, 0xa7, 0xe3,
+       0x46, 0xda, 0xc4, 0x64, 0xe9,
+       0xed, 0xca, 0x4c, 0xfe, 0xb6,
+       0xce, 0xb6, 0xbd, 0xe7, 0xba,
+       0xec, 0x9f, 0xf2, 0x6c, 0xa6,
+       0xbd, 0xf7, 0x3d, 0x0b, 0xe4,
+       0x1e, 0x36, 0x12, 0x9d, 0xcf,
+       0xf7, 0x51, 0xdd, 0x2b, 0x5a,
+       0xd5, 0xce, 0x11, 0x6e, 0x8a,
+       0x96, 0x3a, 0x27, 0x38, 0xa2,
+       0x99, 0x47, 0x7a, 0x68
+}, bm101h[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm101i[] = {
+       0x2b, 0xdc, 0xc8, 0x9f, 0x05,
+       0x82, 0x16, 0xb8, 0xa2, 0x08,
+       0xdd, 0xc6, 0xd8, 0xb5, 0x4a,
+       0xa9, 0x1f, 0x48, 0xbd, 0x63,
+       0x48, 0x49, 0x86, 0x56, 0x51,
+       0x05, 0xc9, 0xad, 0x5a, 0x66,
+       0x82, 0xf6
+}, bm101j[] = {
+       0x6f, 0x75, 0x72, 0x2d, 0x73,
+       0x65, 0x63, 0x72, 0x65, 0x74
+
+}, bm102a[] = { /* mac0-01 */
+       0xa1, 0x01, 0x05
+}, bm102b[] = {
+       0xa1, 0x01, 0x27
+}, bm102c[] = {
+       0x31, 0x31
+}, bm102d[] = {
+       0xb4, 0x92, 0x4b, 0x18, 0xeb,
+       0x4e, 0x04, 0x73, 0x13, 0xc7,
+       0x07, 0xb0, 0xed, 0xa4, 0xab,
+       0x84, 0x43, 0x45, 0xf2, 0xc4,
+       0x49, 0x87, 0xd6, 0xf9, 0xeb,
+       0xcc, 0x77, 0x7e, 0xfd, 0x40,
+       0x78, 0xcc, 0x0f, 0x4c, 0x10,
+       0x8d, 0xef, 0x95, 0x9f, 0x78,
+       0xf1, 0xed, 0xb2, 0x76, 0x54,
+       0x25, 0x78, 0x5f, 0xcd, 0x17,
+       0xd5, 0x12, 0xbe, 0x31, 0xee,
+       0xb6, 0x6b, 0xef, 0xf1, 0xe8,
+       0xfc, 0x27, 0x47, 0x07
+}, bm102e[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm102f[] = {
+       0xa1, 0xa8, 0x48, 0xd3, 0x47,
+       0x1f, 0x9d, 0x61, 0xee, 0x49,
+       0x01, 0x8d, 0x24, 0x4c, 0x82,
+       0x47, 0x72, 0xf2, 0x23, 0xad,
+       0x4f, 0x93, 0x52, 0x93, 0xf1,
+       0x78, 0x9f, 0xc3, 0xa0, 0x8d,
+       0x8c, 0x58
+
+}, bm103a[] = {
+       0xa1, 0x01, 0x05
+}, bm103b[] = {
+       0xa1, 0x01, 0x27
+}, bm103c[] = {
+       0x31, 0x31
+}, bm103d[] = {
+       0xb4, 0x92, 0x4b, 0x18, 0xeb,
+       0x4e, 0x04, 0x73, 0x13, 0xc7,
+       0x07, 0xb0, 0xed, 0xa4, 0xab,
+       0x84, 0x43, 0x45, 0xf2, 0xc4,
+       0x49, 0x87, 0xd6, 0xf9, 0xeb,
+       0xcc, 0x77, 0x7e, 0xfd, 0x40,
+       0x78, 0xcc, 0x0f, 0x4c, 0x10,
+       0x8d, 0xef, 0x95, 0x9f, 0x78,
+       0xf1, 0xed, 0xb2, 0x76, 0x54,
+       0x25, 0x78, 0x5f, 0xcd, 0x17,
+       0xd5, 0x12, 0xbe, 0x31, 0xee,
+       0xb6, 0x6b, 0xef, 0xf1, 0xe8,
+       0xfc, 0x27, 0x47, 0x07
+}, bm103e[] = {
+       0xa1, 0x01, 0x26
+}, bm103f[] = {
+       0x31, 0x31
+}, bm103g[] = {
+       0x6a, 0xcd, 0x94, 0xd3, 0xcc,
+       0xf7, 0x1d, 0x19, 0x2e, 0x85,
+       0x28, 0x36, 0x0b, 0xa7, 0xe3,
+       0x46, 0xda, 0xc4, 0x64, 0xe9,
+       0xed, 0xca, 0x4c, 0xfe, 0xb6,
+       0xce, 0xb6, 0xbd, 0xe7, 0xba,
+       0xec, 0x9f, 0xf2, 0x6c, 0xa6,
+       0xbd, 0xf7, 0x3d, 0x0b, 0xe4,
+       0x1e, 0x36, 0x12, 0x9d, 0xcf,
+       0xf7, 0x51, 0xdd, 0x2b, 0x5a,
+       0xd5, 0xce, 0x11, 0x6e, 0x8a,
+       0x96, 0x3a, 0x27, 0x38, 0xa2,
+       0x99, 0x47, 0x7a, 0x68
+}, bm103h[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm103i[] = {
+       0xa1, 0xa8, 0x48, 0xd3, 0x47,
+       0x1f, 0x9d, 0x61, 0xee, 0x49,
+       0x01, 0x8d, 0x24, 0x4c, 0x82,
+       0x47, 0x72, 0xf2, 0x23, 0xad,
+       0x4f, 0x93, 0x52, 0x93, 0xf1,
+       0x78, 0x9f, 0xc3, 0xa0, 0x8d,
+       0x8c, 0x58
+
+}, bm104a[] = {
+       0xa1, 0x03, 0x00
+}, bm104b[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm104c[] = {
+       0xa1, 0x01, 0x27
+}, bm104d[] = {
+       0xa1, 0x01, 0x27
+}, bm104e[] = {
+       0x31, 0x31
+}, bm104f[] = {
+       0x8e, 0x1b, 0xe2, 0xf9, 0x45,
+       0x3d, 0x26, 0x48, 0x12, 0xe5,
+       0x90, 0x49, 0x91, 0x32, 0xbe,
+       0xf3, 0xfb, 0xf9, 0xee, 0x9d,
+       0xb2, 0x7c, 0x2c, 0x16, 0x87,
+       0x88, 0xe3, 0xb7, 0xeb, 0xe5,
+       0x06, 0xc0, 0x4f, 0xd3, 0xd1,
+       0x9f, 0xaa, 0x9f, 0x51, 0x23,
+       0x2a, 0xf5, 0xc9, 0x59, 0xe4,
+       0xef, 0x47, 0x92, 0x88, 0x34,
+       0x64, 0x7f, 0x56, 0xdf, 0xbe,
+       0x93, 0x91, 0x12, 0x88, 0x4d,
+       0x08, 0xef, 0x25, 0x05
+}, bm104g[] = {
+       0x31, 0x31
+}, bm104h[] = {
+       0x77, 0xf3, 0xea, 0xcd, 0x11,
+       0x85, 0x2c, 0x4b, 0xf9, 0xcb,
+       0x1d, 0x72, 0xfa, 0xbe, 0x6b,
+       0x26, 0xfb, 0xa1, 0xd7, 0x60,
+       0x92, 0xb2, 0xb5, 0xb7, 0xec,
+       0x83, 0xb8, 0x35, 0x57, 0x65,
+       0x22, 0x64, 0xe6, 0x96, 0x90,
+       0xdb, 0xc1, 0x17, 0x2d, 0xdc,
+       0x0b, 0xf8, 0x84, 0x11, 0xc0,
+       0xd2, 0x5a, 0x50, 0x7f, 0xdb,
+       0x24, 0x7a, 0x20, 0xc4, 0x0d,
+       0x5e, 0x24, 0x5f, 0xab, 0xd3,
+       0xfc, 0x9e, 0xc1, 0x06
+
+}, bm105a[] = {
+       0xa1, 0x03, 0x00
+}, bm105b[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm105c[] = {
+       0xa1, 0x01, 0x27
+}, bm105d[] = {
+       0xa1, 0x01, 0x27
+}, bm105e[] = {
+       0x31, 0x31
+}, bm105f[] = {
+               0x8e, 0x1b, 0xe2, 0xf9, 0x45,
+               0x3d, 0x26, 0x48, 0x12, 0xe5,
+               0x90, 0x49, 0x91, 0x32, 0xbe,
+               0xf3, 0xfb, 0xf9, 0xee, 0x9d,
+               0xb2, 0x7c, 0x2c, 0x16, 0x87,
+               0x88, 0xe3, 0xb7, 0xeb, 0xe5,
+               0x06, 0xc0, 0x4f, 0xd3, 0xd1,
+               0x9f, 0xaa, 0x9f, 0x51, 0x23,
+               0x2a, 0xf5, 0xc9, 0x59, 0xe4,
+               0xef, 0x47, 0x92, 0x88, 0x34,
+               0x64, 0x7f, 0x56, 0xdf, 0xbe,
+               0x93, 0x91, 0x12, 0x88, 0x4d,
+               0x08, 0xef, 0x25, 0x05
+}, bm105g[] = {
+       0xa1, 0x01, 0x26
+}, bm105h[] = {
+       0x31, 0x31
+}, bm105i[] = {
+               0xaf, 0x04, 0x9b, 0x80, 0xd5,
+               0x2c, 0x36, 0x69, 0xb2, 0x99,
+               0x70, 0xc1, 0x33, 0x54, 0x37,
+               0x54, 0xf9, 0xcc, 0x60, 0x8c,
+               0xe4, 0x11, 0x23, 0xae, 0x1c,
+               0x82, 0x7e, 0x36, 0xb3, 0x8c,
+               0xb8, 0x25, 0x98, 0x7f, 0x01,
+               0xf2, 0x2b, 0xb8, 0xab, 0x13,
+               0xe9, 0xc6, 0x62, 0x26, 0xee,
+               0x23, 0x17, 0x8f, 0xfa, 0x00,
+               0xa4, 0xfc, 0x22, 0x05, 0x93,
+               0xb6, 0xe5, 0xac, 0x38, 0x96,
+               0x00, 0x71, 0xc9, 0xc8
+}, bm105j[] = {
+       0x31, 0x31
+}, bm105k[] = {
+               0x77, 0xf3, 0xea, 0xcd, 0x11,
+               0x85, 0x2c, 0x4b, 0xf9, 0xcb,
+               0x1d, 0x72, 0xfa, 0xbe, 0x6b,
+               0x26, 0xfb, 0xa1, 0xd7, 0x60,
+               0x92, 0xb2, 0xb5, 0xb7, 0xec,
+               0x83, 0xb8, 0x35, 0x57, 0x65,
+               0x22, 0x64, 0xe6, 0x96, 0x90,
+               0xdb, 0xc1, 0x17, 0x2d, 0xdc,
+               0x0b, 0xf8, 0x84, 0x11, 0xc0,
+               0xd2, 0x5a, 0x50, 0x7f, 0xdb,
+               0x24, 0x7a, 0x20, 0xc4, 0x0d,
+               0x5e, 0x24, 0x5f, 0xab, 0xd3,
+               0xfc, 0x9e, 0xc1, 0x06
+
+}, bm106a[] = {
+       0xa1, 0x03, 0x00
+}, bm106b[] = {
+       0xa1, 0x01, 0x27
+}, bm106c[] = {
+       0x31, 0x31
+}, bm106d[] = {
+               0xb7, 0xca, 0xcb, 0xa2, 0x85,
+               0xc4, 0xcd, 0x3e, 0xd2, 0xf0,
+               0x14, 0x6f, 0x41, 0x98, 0x86,
+               0x14, 0x4c, 0xa6, 0x38, 0xd0,
+               0x87, 0xde, 0x12, 0x3d, 0x40,
+               0x01, 0x67, 0x30, 0x8a, 0xce,
+               0xab, 0xc4, 0xb5, 0xe5, 0xc6,
+               0xa4, 0x0c, 0x0d, 0xe0, 0xb7,
+               0x11, 0x67, 0xa3, 0x91, 0x75,
+               0xea, 0x56, 0xc1, 0xfe, 0x96,
+               0xc8, 0x9e, 0x5e, 0x7d, 0x30,
+               0xda, 0xf2, 0x43, 0x8a, 0x45,
+               0x61, 0x59, 0xa2, 0x0a
+}, bm106e[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm106f[] = {
+       0xa1, 0x01, 0x27
+}, bm106g[] = {
+       0x31, 0x31
+}, bm106h[] = {
+               0x77, 0xf3, 0xea, 0xcd, 0x11,
+               0x85, 0x2c, 0x4b, 0xf9, 0xcb,
+               0x1d, 0x72, 0xfa, 0xbe, 0x6b,
+               0x26, 0xfb, 0xa1, 0xd7, 0x60,
+               0x92, 0xb2, 0xb5, 0xb7, 0xec,
+               0x83, 0xb8, 0x35, 0x57, 0x65,
+               0x22, 0x64, 0xe6, 0x96, 0x90,
+               0xdb, 0xc1, 0x17, 0x2d, 0xdc,
+               0x0b, 0xf8, 0x84, 0x11, 0xc0,
+               0xd2, 0x5a, 0x50, 0x7f, 0xdb,
+               0x24, 0x7a, 0x20, 0xc4, 0x0d,
+               0x5e, 0x24, 0x5f, 0xab, 0xd3,
+               0xfc, 0x9e, 0xc1, 0x06
+
+}, bm107a[] = {
+       0xa2, 0x01, 0x27, 0x03, 0x00
+}, bm107b[] = {
+       0xa1, 0x01, 0x27,
+}, bm107c[] = {
+       0x31, 0x31
+}, bm107d[] = {
+       0x6d, 0xae, 0xd1, 0x58, 0xaf,
+       0xe4, 0x03, 0x2e, 0x8d, 0xd4,
+       0x77, 0xd3, 0xd2, 0xb7, 0xf6,
+       0x67, 0xe7, 0x95, 0x7a, 0xa8,
+       0x30, 0x2b, 0xb5, 0xe5, 0x68,
+       0xb4, 0xdc, 0xbc, 0xce, 0x3c,
+       0xf0, 0xed, 0x5a, 0x90, 0xf8,
+       0x31, 0x35, 0x1c, 0x85, 0xd6,
+       0x15, 0x5a, 0x42, 0xa1, 0x7c,
+       0xa1, 0xf2, 0x5f, 0x50, 0x1c,
+       0xc1, 0x3f, 0x67, 0x10, 0x8a,
+       0xe5, 0x3b, 0xda, 0x92, 0xdb,
+       0x88, 0x27, 0x2e, 0x00
+}, bm107e[] = {
+       0x31, 0x31
+}, bm107f[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm107g[] = {
+       0x71, 0x42, 0xfd, 0x2f, 0xf9,
+       0x6d, 0x56, 0xdb, 0x85, 0xbe,
+       0xe9, 0x05, 0xa7, 0x6b, 0xa1,
+       0xd0, 0xb7, 0x32, 0x1a, 0x95,
+       0xc8, 0xc4, 0xd3, 0x60, 0x7c,
+       0x57, 0x81, 0x93, 0x2b, 0x7a,
+       0xfb, 0x87, 0x11, 0x49, 0x7d,
+       0xfa, 0x75, 0x1b, 0xf4, 0x0b,
+       0x58, 0xb3, 0xbc, 0xc3, 0x23,
+       0x00, 0xb1, 0x48, 0x7f, 0x3d,
+       0xb3, 0x40, 0x85, 0xee, 0xf0,
+       0x13, 0xbf, 0x08, 0xf4, 0xa4,
+       0x4d, 0x6f, 0xef, 0x0d
+
+}, bm108a[] = {
+       0xa2, 0x01, 0x27, 0x03, 0x00
+}, bm108b[] = {
+       0xa1, 0x01, 0x27
+}, bm108c[] = {
+       0x31, 0x31
+}, bm108d[] = {
+       0x6d, 0xae, 0xd1, 0x58, 0xaf,
+       0xe4, 0x03, 0x2e, 0x8d, 0xd4,
+       0x77, 0xd3, 0xd2, 0xb7, 0xf6,
+       0x67, 0xe7, 0x95, 0x7a, 0xa8,
+       0x30, 0x2b, 0xb5, 0xe5, 0x68,
+       0xb4, 0xdc, 0xbc, 0xce, 0x3c,
+       0xf0, 0xed, 0x5a, 0x90, 0xf8,
+       0x31, 0x35, 0x1c, 0x85, 0xd6,
+       0x15, 0x5a, 0x42, 0xa1, 0x7c,
+       0xa1, 0xf2, 0x5f, 0x50, 0x1c,
+       0xc1, 0x3f, 0x67, 0x10, 0x8a,
+       0xe5, 0x3b, 0xda, 0x92, 0xdb,
+       0x88, 0x27, 0x2e, 0x00
+}, bm108e[] = {
+       0xa1, 0x01, 0x26
+}, bm108f[] = {
+       0x31, 0x31
+}, bm108g[] = {
+       0x93, 0x48, 0x7d, 0x09, 0x25,
+       0x6a, 0x3e, 0xf4, 0x96, 0x37,
+       0x19, 0xba, 0x5c, 0xf1, 0x01,
+       0xac, 0xe2, 0xfc, 0x13, 0xd6,
+       0x31, 0x4b, 0x49, 0x58, 0x21,
+       0x71, 0xff, 0xa4, 0xa1, 0x31,
+       0x4d, 0xc9, 0x3e, 0x4a, 0x4a,
+       0xdf, 0xa4, 0x2a, 0x79, 0xe3,
+       0x1b, 0x35, 0xd7, 0x30, 0x43,
+       0x58, 0x58, 0x5b, 0x41, 0x79,
+       0x96, 0x78, 0xce, 0x00, 0xca,
+       0x47, 0xc3, 0xe0, 0x23, 0x86,
+       0x39, 0x23, 0xf8, 0xc8
+}, bm108h[] = {
+       0x31, 0x31
+}, bm108i[] = {
+       0x54, 0x68, 0x69, 0x73, 0x20,
+       0x69, 0x73, 0x20, 0x74, 0x68,
+       0x65, 0x20, 0x63, 0x6f, 0x6e,
+       0x74, 0x65, 0x6e, 0x74, 0x2e
+}, bm108j[] = {
+       0x71, 0x42, 0xfd, 0x2f, 0xf9,
+       0x6d, 0x56, 0xdb, 0x85, 0xbe,
+       0xe9, 0x05, 0xa7, 0x6b, 0xa1,
+       0xd0, 0xb7, 0x32, 0x1a, 0x95,
+       0xc8, 0xc4, 0xd3, 0x60, 0x7c,
+       0x57, 0x81, 0x93, 0x2b, 0x7a,
+       0xfb, 0x87, 0x11, 0x49, 0x7d,
+       0xfa, 0x75, 0x1b, 0xf4, 0x0b,
+       0x58, 0xb3, 0xbc, 0xc3, 0x23,
+       0x00, 0xb1, 0x48, 0x7f, 0x3d,
+       0xb3, 0x40, 0x85, 0xee, 0xf0,
+       0x13, 0xbf, 0x08, 0xf4, 0xa4,
+       0x4d, 0x6f, 0xef, 0x0d
+};
+
+static const struct seq
+seq1[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 0 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq2[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq3[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 10 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq4[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 23 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq5[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 24 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq6[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 25 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq7[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 100 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq8[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1000 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq9[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1000000 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq10[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1000000000000 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq11[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 18446744073709551615ull } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq12[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 0 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm12, .buf_len = sizeof(bm12)},
+       { .reason = LECPCB_TAG_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq13[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = 0ull } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq14[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm12, .buf_len = sizeof(bm12)},
+       { .reason = LECPCB_TAG_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq15[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -1ll } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq16[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -10ll } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq17[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -100ll } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq18[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -1000ll } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq19[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq20[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0x8000 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq21[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0x3c00 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq22[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+#if defined(LWS_WITH_CBOR_FLOAT)
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.d = 1.1 } },
+#else
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0x3ff199999999999aull } },
+#endif
+       { .reason = LECPCB_DESTRUCTED },
+}, seq23[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0x3e00 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq24[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0x7bff } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq25[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+#if defined(LWS_WITH_CBOR_FLOAT)
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.f =  100000.0  } },
+#else
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.f = 0x47c35000 } },
+#endif
+       { .reason = LECPCB_DESTRUCTED },
+}, seq26[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+#if defined(LWS_WITH_CBOR_FLOAT)
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.f = 3.4028234663852886e+38 } },
+#else
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.f = 0x7f7fffff } },
+#endif
+       { .reason = LECPCB_DESTRUCTED },
+}, seq27[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0x7e37e43c8800759cull } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq28[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0x0001 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq29[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0x0400 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq30[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0xc400 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq31[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0xc010666666666666ull } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq32[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0x7c00 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq33[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0x7e00 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq34[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FLOAT16, .item = { .u.hf = 0xfc00 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq35[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+#if defined(LWS_WITH_CBOR_FLOAT)
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.u32 = 0x7f800000 } },
+#else
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.f = 0x7f800000 } },
+#endif
+       { .reason = LECPCB_DESTRUCTED },
+}, seq36[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+#if defined(LWS_WITH_CBOR_FLOAT)
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.f = NAN } },
+#else
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.f = 0x7fc00000 } },
+#endif
+       { .reason = LECPCB_DESTRUCTED },
+}, seq37[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+#if defined(LWS_WITH_CBOR_FLOAT)
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.u32 = 0xff800000 } },
+#else
+       { .reason = LECPCB_VAL_FLOAT32, .item = { .u.f = 0xff800000 } },
+#endif
+       { .reason = LECPCB_DESTRUCTED },
+}, seq38[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+#if defined(LWS_WITH_CBOR_FLOAT)
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0x7ff0000000000000ull } },
+#else
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0x7ff0000000000000ull } },
+#endif
+       { .reason = LECPCB_DESTRUCTED },
+}, seq39[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+#if defined(LWS_WITH_CBOR_FLOAT)
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0x7ff8000000000000ull } },
+#else
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0x7ff8000000000000ull } },
+#endif
+       { .reason = LECPCB_DESTRUCTED },
+}, seq40[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+#if defined(LWS_WITH_CBOR_FLOAT)
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0xfff0000000000000ull } },
+#else
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0xfff0000000000000ull } },
+#endif
+       { .reason = LECPCB_DESTRUCTED },
+}, seq41[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_FALSE },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq42[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_TRUE },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq43[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_NULL },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq44[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_UNDEFINED },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq45[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_SIMPLE, .item = { .u.u64 = 16 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq46[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_FAILED }, /* example disallowed by RFC! */
+       { .reason = LECPCB_DESTRUCTED },
+}, seq47[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_SIMPLE, .item = { .u.u64 = 255 } },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq48[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 0 } },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = bm48, .buf_len = sizeof(bm48)},
+       { .reason = LECPCB_TAG_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq49[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1363896240 } },
+       { .reason = LECPCB_TAG_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq50[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_FLOAT64, .item = { .u.u64 = 0x41d452d9ec200000ull } },
+       { .reason = LECPCB_TAG_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq51[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 23 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm51, .buf_len = sizeof(bm51)},
+       { .reason = LECPCB_TAG_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq52[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 24 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm52, .buf_len = sizeof(bm52)},
+       { .reason = LECPCB_TAG_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq53[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 32 } },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = bm53, .buf_len = sizeof(bm53)},
+       { .reason = LECPCB_TAG_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq54[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm53, .buf_len = 0},
+       { .reason = LECPCB_DESTRUCTED },
+}, seq55[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm51, .buf_len = sizeof(bm51)},
+       { .reason = LECPCB_DESTRUCTED },
+}, seq56[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = bm53, .buf_len = 0},
+       { .reason = LECPCB_DESTRUCTED },
+}, seq57[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = bm57, .buf_len = sizeof(bm57)},
+       { .reason = LECPCB_DESTRUCTED },
+}, seq58[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = bm58, .buf_len = sizeof(bm58)},
+       { .reason = LECPCB_DESTRUCTED },
+}, seq59[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = bm59, .buf_len = sizeof(bm59)},
+       { .reason = LECPCB_DESTRUCTED },
+}, seq60[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = bm60, .buf_len = sizeof(bm60)},
+       { .reason = LECPCB_DESTRUCTED },
+}, seq61[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = bm61, .buf_len = sizeof(bm61)},
+       { .reason = LECPCB_DESTRUCTED },
+}, seq62[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = bm62, .buf_len = sizeof(bm62)},
+       { .reason = LECPCB_DESTRUCTED },
+}, seq63[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq64[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq65[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+        { .reason = LECPCB_ARRAY_ITEM_END, },
+
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END },
+        { .reason = LECPCB_ARRAY_ITEM_END, },
+
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END },
+        { .reason = LECPCB_ARRAY_ITEM_END, },
+
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq66[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 6 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 8 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 9 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 10 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 11 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 12 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 13 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 14 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 15 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 16 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 17 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 18 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 19 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 20 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 21 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 22 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 23 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 24 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 25 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq67[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq68[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq69[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"a", .buf_len = 1},
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"b", .buf_len = 1},
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq70[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"a", .buf_len = 1},
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"b", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"c", .buf_len = 1},
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq71[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"a", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"A", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"b", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"B", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"c", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"C", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"d", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"D", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"e", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"E", .buf_len = 1},
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq72[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_CHUNK, .buf = bm72a, .buf_len = sizeof(bm72a)},
+       { .reason = LECPCB_VAL_BLOB_CHUNK, .buf = bm72b, .buf_len = sizeof(bm72b)},
+       { .reason = LECPCB_VAL_BLOB_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq73[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_CHUNK, .buf = (const uint8_t *)"stream", .buf_len = 5},
+       { .reason = LECPCB_VAL_STR_CHUNK, .buf = (const uint8_t *)"ming", .buf_len = 4},
+       { .reason = LECPCB_VAL_STR_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq74[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq75[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq76[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq77[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq78[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq79[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 6 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 8 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 9 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 10 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 11 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 12 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 13 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 14 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 15 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 16 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 17 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 18 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 19 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 20 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 21 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 22 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 23 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 24 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 25 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq80[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"a", .buf_len = 1},
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"b", .buf_len = 1},
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 2 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 3 } },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq81[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"a", .buf_len = 1},
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"b", .buf_len = 1},
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"c", .buf_len = 1},
+       { .reason = LECPCB_OBJECT_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq82[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"Fun", .buf_len = 3},
+       { .reason = LECPCB_VAL_TRUE },
+       { .reason = LECPCB_VAL_STR_START, },
+       { .reason = LECPCB_VAL_STR_END, .buf = (const uint8_t *)"Amt", .buf_len = 3},
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = (int64_t)-2ll } },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_DESTRUCTED },
+
+}, seq83[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 97 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm83a, .buf_len = sizeof(bm83a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm83b, .buf_len = sizeof(bm83b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm83c, .buf_len = sizeof(bm83c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm83a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm83d, .buf_len = sizeof(bm83d) },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm83a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+
+}, seq84[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 97 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm84a, .buf_len = sizeof(bm84a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm84b, .buf_len = sizeof(bm84b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm84c, .buf_len = sizeof(bm84c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm84a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm84d, .buf_len = sizeof(bm84d) },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm84a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+
+}, seq85[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 97 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm85a, .buf_len = sizeof(bm85a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm85b, .buf_len = sizeof(bm85b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm85c, .buf_len = sizeof(bm85c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm85a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm85d, .buf_len = sizeof(bm85d) },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm85a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+
+}, seq86[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 97 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm86a, .buf_len = sizeof(bm86a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm86b, .buf_len = sizeof(bm86b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm86c, .buf_len = sizeof(bm86c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm86a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm86d, .buf_len = sizeof(bm86d) },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm86a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq87[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 97 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm87a, .buf_len = sizeof(bm87a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm87b, .buf_len = sizeof(bm87b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm87c, .buf_len = sizeof(bm87c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm87a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+       { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm87d, .buf_len = sizeof(bm87d) },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm87a, .buf_len = 0 },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq88[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm88a, .buf_len = sizeof(bm88a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm88b, .buf_len = sizeof(bm88b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm88c, .buf_len = sizeof(bm88c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq89[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm89a, .buf_len = sizeof(bm89a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm89b, .buf_len = sizeof(bm89b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm89c, .buf_len = sizeof(bm89c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq90[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm90a, .buf_len = sizeof(bm90a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm90b, .buf_len = sizeof(bm90b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm90c, .buf_len = sizeof(bm90c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq91[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm91a, .buf_len = sizeof(bm91a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm91b, .buf_len = sizeof(bm91b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm91c, .buf_len = sizeof(bm91c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq92[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm92a, .buf_len = sizeof(bm92a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm92b, .buf_len = sizeof(bm92b) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm92c, .buf_len = sizeof(bm92c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq93[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 16 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm93a, .buf_len = sizeof(bm93a) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm93b, .buf_len = sizeof(bm93b) },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+       { .reason = LECPCB_ARRAY_START, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm93c, .buf_len = sizeof(bm93c) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_OBJECT_START, },
+       { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm93d, .buf_len = sizeof(bm93d) },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm93e, .buf_len = sizeof(bm93e) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_OBJECT_END },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_ITEM_START, },
+       { .reason = LECPCB_VAL_BLOB_START, },
+       { .reason = LECPCB_VAL_BLOB_END, .buf = bm93f, .buf_len = sizeof(bm93f) },
+       { .reason = LECPCB_ARRAY_ITEM_END, },
+       { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq94[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 16 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm94a, .buf_len = sizeof(bm94a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+          { .reason = LECPCB_VAL_BLOB_START, },
+          { .reason = LECPCB_VAL_BLOB_END, .buf = bm94b, .buf_len = sizeof(bm94b) },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm94c, .buf_len = sizeof(bm94c) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_OBJECT_START, },
+             { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm94d, .buf_len = sizeof(bm94d) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm94e, .buf_len = sizeof(bm94e) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm94f, .buf_len = sizeof(bm94f) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_OBJECT_START, },
+             { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm94g, .buf_len = sizeof(bm94g) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm94h, .buf_len = sizeof(bm94h) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm94i, .buf_len = sizeof(bm94i) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq95[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 96 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm95a, .buf_len = sizeof(bm95a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+          { .reason = LECPCB_VAL_BLOB_START, },
+          { .reason = LECPCB_VAL_BLOB_END, .buf = bm95b, .buf_len = sizeof(bm95b) },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm95c, .buf_len = sizeof(bm95c) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm95d, .buf_len = sizeof(bm95d) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm95e, .buf_len = sizeof(bm95e) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm95f, .buf_len = sizeof(bm95f) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm95f, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+            { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm95g, .buf_len = sizeof(bm95g) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm95f, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq96[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 96 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm96a, .buf_len = sizeof(bm96a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+          { .reason = LECPCB_VAL_BLOB_START, },
+          { .reason = LECPCB_VAL_BLOB_END, .buf = bm96b, .buf_len = sizeof(bm96b) },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm96c, .buf_len = sizeof(bm96c) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_OBJECT_START, },
+             { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm96d, .buf_len = sizeof(bm96d) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm96e, .buf_len = sizeof(bm96e) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_END, },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm96f, .buf_len = sizeof(bm96f) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_OBJECT_START, },
+             { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm96g, .buf_len = sizeof(bm96g) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm96h, .buf_len = sizeof(bm96h) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_OBJECT_END },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm96i, .buf_len = sizeof(bm96i) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm96f, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+            { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm96j, .buf_len = sizeof(bm96j) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm96f, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq97[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 96 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm97a, .buf_len = sizeof(bm97a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 5 } },
+          { .reason = LECPCB_VAL_BLOB_START, },
+          { .reason = LECPCB_VAL_BLOB_END, .buf = bm97b, .buf_len = sizeof(bm97b) },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm97c, .buf_len = sizeof(bm97c) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm97f, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+            { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm97d, .buf_len = sizeof(bm97d) },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+            { .reason = LECPCB_ARRAY_START, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm97e, .buf_len = sizeof(bm97e) },
+             { .reason = LECPCB_ARRAY_ITEM_END, },
+             { .reason = LECPCB_ARRAY_ITEM_START, },
+             { .reason = LECPCB_OBJECT_START, },
+              { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+              { .reason = LECPCB_VAL_BLOB_START, },
+              { .reason = LECPCB_VAL_BLOB_END, .buf = bm97f, .buf_len = sizeof(bm97f) },
+             { .reason = LECPCB_OBJECT_END },
+             { .reason = LECPCB_ARRAY_ITEM_END, },
+             { .reason = LECPCB_ARRAY_ITEM_START, },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm97g, .buf_len = sizeof(bm97g) },
+             { .reason = LECPCB_ARRAY_ITEM_END, },
+             { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm97e, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq98[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 97 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm98a, .buf_len = sizeof(bm98a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm98b, .buf_len = sizeof(bm98b) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm98c, .buf_len = sizeof(bm98c) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm98d, .buf_len = sizeof(bm98d) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm98e, .buf_len = sizeof(bm98e) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm98f, .buf_len = sizeof(bm98f) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm98e, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+            { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm98g, .buf_len = sizeof(bm98g) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm98e, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+
+}, seq99[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 97 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm99a, .buf_len = sizeof(bm99a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm99b, .buf_len = sizeof(bm99b) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_OBJECT_START, },
+             { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm99c, .buf_len = sizeof(bm99c) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm99d, .buf_len = sizeof(bm99d) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm99e, .buf_len = sizeof(bm99e) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_OBJECT_START, },
+             { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm99f, .buf_len = sizeof(bm99f) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm99g, .buf_len = sizeof(bm99g) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm99h, .buf_len = sizeof(bm99h) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm99i, .buf_len = sizeof(bm99i) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm99a, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+            { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm99j, .buf_len = sizeof(bm99j) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm98e, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+
+}, seq100[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm100a, .buf_len = sizeof(bm100a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm100b, .buf_len = sizeof(bm100b) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm100c, .buf_len = sizeof(bm100c) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm100d, .buf_len = sizeof(bm100d) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm100e, .buf_len = sizeof(bm100e) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm100f, .buf_len = sizeof(bm100f) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+
+}, seq101[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm101a, .buf_len = sizeof(bm101a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm101b, .buf_len = sizeof(bm101b) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_OBJECT_START, },
+             { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm101c, .buf_len = sizeof(bm101c) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm101d, .buf_len = sizeof(bm101d) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm101e, .buf_len = sizeof(bm101e) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_OBJECT_START, },
+             { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm101f, .buf_len = sizeof(bm101f) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm101g, .buf_len = sizeof(bm101g) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm101h, .buf_len = sizeof(bm101h) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm101i, .buf_len = sizeof(bm101i) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm101j, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 1 } },
+            { .reason = LECPCB_VAL_NUM_INT, .item = { .u.i64 = -6 } },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm101j, .buf_len = sizeof(bm101j) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm101j, .buf_len = 0 },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq102[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm102a, .buf_len = sizeof(bm102a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm102b, .buf_len = sizeof(bm102b) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm102c, .buf_len = sizeof(bm102c) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm102d, .buf_len = sizeof(bm102d) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm102e, .buf_len = sizeof(bm102e) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm102f, .buf_len = sizeof(bm102f) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq103[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm103a, .buf_len = sizeof(bm103a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm103b, .buf_len = sizeof(bm103b) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm103c, .buf_len = sizeof(bm103c) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm103d, .buf_len = sizeof(bm103d) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+                 { .reason = LECPCB_VAL_BLOB_START, },
+                 { .reason = LECPCB_VAL_BLOB_END, .buf = bm103e, .buf_len = sizeof(bm103e) },
+                 { .reason = LECPCB_ARRAY_ITEM_END, },
+                 { .reason = LECPCB_ARRAY_ITEM_START, },
+                 { .reason = LECPCB_OBJECT_START, },
+                    { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+                         { .reason = LECPCB_VAL_BLOB_START, },
+                         { .reason = LECPCB_VAL_BLOB_END, .buf = bm103f, .buf_len = sizeof(bm103f) },
+
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm103g, .buf_len = sizeof(bm103g) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm103h, .buf_len = sizeof(bm103h) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm103i, .buf_len = sizeof(bm103i) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+
+}, seq104[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 98 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm104a, .buf_len = sizeof(bm104a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm104b, .buf_len = sizeof(bm104b) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm104c, .buf_len = sizeof(bm104c) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+            { .reason = LECPCB_ARRAY_START, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm104d, .buf_len = sizeof(bm104d) },
+             { .reason = LECPCB_ARRAY_ITEM_END, },
+             { .reason = LECPCB_ARRAY_ITEM_START, },
+             { .reason = LECPCB_OBJECT_START },
+              { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+              { .reason = LECPCB_VAL_BLOB_START, },
+              { .reason = LECPCB_VAL_BLOB_END, .buf = bm104e, .buf_len = sizeof(bm104e) },
+             { .reason = LECPCB_OBJECT_END },
+             { .reason = LECPCB_ARRAY_ITEM_END, },
+             { .reason = LECPCB_ARRAY_ITEM_START, },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm104f, .buf_len = sizeof(bm104f) },
+             { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_END, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm104g, .buf_len = sizeof(bm104g) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm104h, .buf_len = sizeof(bm104h) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq105[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 98 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm105a, .buf_len = sizeof(bm105a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+         { .reason = LECPCB_OBJECT_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm105b, .buf_len = sizeof(bm105b) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm105c, .buf_len = sizeof(bm105c) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+            { .reason = LECPCB_ARRAY_START, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+             { .reason = LECPCB_ARRAY_START, },
+             { .reason = LECPCB_ARRAY_ITEM_START, },
+              { .reason = LECPCB_VAL_BLOB_START, },
+              { .reason = LECPCB_VAL_BLOB_END, .buf = bm105d, .buf_len = sizeof(bm105d) },
+              { .reason = LECPCB_ARRAY_ITEM_END, },
+              { .reason = LECPCB_ARRAY_ITEM_START, },
+              { .reason = LECPCB_OBJECT_START, },
+               { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+               { .reason = LECPCB_VAL_BLOB_START, },
+               { .reason = LECPCB_VAL_BLOB_END, .buf = bm105e, .buf_len = sizeof(bm105e) },
+              { .reason = LECPCB_OBJECT_END, },
+              { .reason = LECPCB_ARRAY_ITEM_END, },
+              { .reason = LECPCB_ARRAY_ITEM_START, },
+              { .reason = LECPCB_VAL_BLOB_START, },
+              { .reason = LECPCB_VAL_BLOB_END, .buf = bm105f, .buf_len = sizeof(bm105f) },
+              { .reason = LECPCB_ARRAY_ITEM_END, },
+             { .reason = LECPCB_ARRAY_END, },
+             { .reason = LECPCB_ARRAY_ITEM_END, },
+             { .reason = LECPCB_ARRAY_ITEM_START, },
+             { .reason = LECPCB_ARRAY_START, },
+             { .reason = LECPCB_ARRAY_ITEM_START, },
+              { .reason = LECPCB_VAL_BLOB_START, },
+              { .reason = LECPCB_VAL_BLOB_END, .buf = bm105g, .buf_len = sizeof(bm105g) },
+              { .reason = LECPCB_ARRAY_ITEM_END, },
+              { .reason = LECPCB_ARRAY_ITEM_START, },
+              { .reason = LECPCB_OBJECT_START, },
+               { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+               { .reason = LECPCB_VAL_BLOB_START, },
+               { .reason = LECPCB_VAL_BLOB_END, .buf = bm105h, .buf_len = sizeof(bm105h) },
+              { .reason = LECPCB_OBJECT_END, },
+              { .reason = LECPCB_ARRAY_ITEM_END, },
+              { .reason = LECPCB_ARRAY_ITEM_START, },
+              { .reason = LECPCB_VAL_BLOB_START, },
+              { .reason = LECPCB_VAL_BLOB_END, .buf = bm105i, .buf_len = sizeof(bm105i) },
+              { .reason = LECPCB_ARRAY_ITEM_END, },
+             { .reason = LECPCB_ARRAY_END, },
+             { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_END, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm105j, .buf_len = sizeof(bm105j) },
+           { .reason = LECPCB_OBJECT_END, },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm105k, .buf_len = sizeof(bm105k) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq106[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 98 } },
+        { .reason = LECPCB_ARRAY_START, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm106a, .buf_len = sizeof(bm106a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm106b, .buf_len = sizeof(bm106b) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm106c, .buf_len = sizeof(bm106c) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm106d, .buf_len = sizeof(bm106d) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_OBJECT_END },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm106e, .buf_len = sizeof(bm106e) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_ARRAY_START, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm106f, .buf_len = sizeof(bm106f) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm106g, .buf_len = sizeof(bm106g) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm106h, .buf_len = sizeof(bm106h) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq107[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 17 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm107a, .buf_len = sizeof(bm107a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm107b, .buf_len = sizeof(bm107b) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm107c, .buf_len = sizeof(bm107c) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm107d, .buf_len = sizeof(bm107d) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm107e, .buf_len = sizeof(bm107e) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm107f, .buf_len = sizeof(bm107f) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm107g, .buf_len = sizeof(bm107g) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+}, seq108[] = {
+       { .reason = LECPCB_CONSTRUCTED },
+       { .reason = LECPCB_TAG_START, .item = { .u.u64 = 18 } },
+        { .reason = LECPCB_ARRAY_START, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm108a, .buf_len = sizeof(bm108a) },
+         { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_ITEM_START, },
+         { .reason = LECPCB_OBJECT_START, },
+          { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 7 } },
+          { .reason = LECPCB_ARRAY_START, },
+          { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm108b, .buf_len = sizeof(bm108b) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_OBJECT_START, },
+             { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+             { .reason = LECPCB_VAL_BLOB_START, },
+             { .reason = LECPCB_VAL_BLOB_END, .buf = bm108c, .buf_len = sizeof(bm108c) },
+            { .reason = LECPCB_OBJECT_END },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+            { .reason = LECPCB_ARRAY_ITEM_START, },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm108d, .buf_len = sizeof(bm108d) },
+            { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_END, },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_ARRAY_START, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm108e, .buf_len = sizeof(bm108e) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_OBJECT_START, },
+            { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+            { .reason = LECPCB_VAL_BLOB_START, },
+            { .reason = LECPCB_VAL_BLOB_END, .buf = bm108f, .buf_len = sizeof(bm108f) },
+           { .reason = LECPCB_OBJECT_END },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+           { .reason = LECPCB_ARRAY_ITEM_START, },
+           { .reason = LECPCB_VAL_BLOB_START, },
+           { .reason = LECPCB_VAL_BLOB_END, .buf = bm108g, .buf_len = sizeof(bm108g) },
+           { .reason = LECPCB_ARRAY_ITEM_END, },
+          { .reason = LECPCB_ARRAY_END, },
+          { .reason = LECPCB_ARRAY_ITEM_END, },
+         { .reason = LECPCB_ARRAY_END, },
+         { .reason = LECPCB_VAL_NUM_UINT, .item = { .u.u64 = 4 } },
+         { .reason = LECPCB_VAL_BLOB_START, },
+         { .reason = LECPCB_VAL_BLOB_END, .buf = bm108h, .buf_len = sizeof(bm108h) },
+        { .reason = LECPCB_OBJECT_END },
+        { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_BLOB_START, },
+        { .reason = LECPCB_VAL_BLOB_END, .buf = bm108i, .buf_len = sizeof(bm108i) },
+        { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_ITEM_START, },
+        { .reason = LECPCB_VAL_BLOB_START, },
+        { .reason = LECPCB_VAL_BLOB_END, .buf = bm108j, .buf_len = sizeof(bm108j) },
+        { .reason = LECPCB_ARRAY_ITEM_END, },
+        { .reason = LECPCB_ARRAY_END, },
+       { .reason = LECPCB_TAG_END, },
+       { .reason = LECPCB_DESTRUCTED },
+};
+
+
+struct cbort {
+       const uint8_t           *b;
+       size_t                  blen;
+       const struct seq        *seq;
+       size_t                  seq_size;
+};
+
+static const struct cbort cbor_tests[] = {
+       { .b = test1,  .blen = sizeof(test1),
+                       .seq = seq1,  .seq_size = LWS_ARRAY_SIZE(seq1) },
+       { .b = test2,  .blen = sizeof(test2),
+                       .seq = seq2,  .seq_size = LWS_ARRAY_SIZE(seq2) },
+       { .b = test3,  .blen = sizeof(test3),
+                       .seq = seq3,  .seq_size = LWS_ARRAY_SIZE(seq3) },
+       { .b = test4,  .blen = sizeof(test4),
+                       .seq = seq4,  .seq_size = LWS_ARRAY_SIZE(seq4) },
+       { .b = test5,  .blen = sizeof(test5),
+                       .seq = seq5,  .seq_size = LWS_ARRAY_SIZE(seq5) },
+       { .b = test6,  .blen = sizeof(test6),
+                       .seq = seq6,  .seq_size = LWS_ARRAY_SIZE(seq6) },
+       { .b = test7,  .blen = sizeof(test7),
+                       .seq = seq7,  .seq_size = LWS_ARRAY_SIZE(seq7) },
+       { .b = test8,  .blen = sizeof(test8),
+                       .seq = seq8,  .seq_size = LWS_ARRAY_SIZE(seq8) },
+       { .b = test9,  .blen = sizeof(test9),
+                       .seq = seq9,  .seq_size = LWS_ARRAY_SIZE(seq9) },
+       { .b = test10, .blen = sizeof(test10),
+                       .seq = seq10, .seq_size = LWS_ARRAY_SIZE(seq10) },
+       { .b = test11, .blen = sizeof(test11),
+                       .seq = seq11, .seq_size = LWS_ARRAY_SIZE(seq11) },
+       { .b = test12, .blen = sizeof(test12),
+                       .seq = seq12, .seq_size = LWS_ARRAY_SIZE(seq12) },
+       { .b = test13, .blen = sizeof(test13),
+                       .seq = seq13, .seq_size = LWS_ARRAY_SIZE(seq13) },
+       { .b = test14, .blen = sizeof(test14),
+                       .seq = seq14, .seq_size = LWS_ARRAY_SIZE(seq14) },
+       { .b = test15, .blen = sizeof(test15),
+                       .seq = seq15, .seq_size = LWS_ARRAY_SIZE(seq15) },
+       { .b = test16, .blen = sizeof(test16),
+                       .seq = seq16, .seq_size = LWS_ARRAY_SIZE(seq16) },
+       { .b = test17, .blen = sizeof(test17),
+                       .seq = seq17, .seq_size = LWS_ARRAY_SIZE(seq17) },
+       { .b = test18, .blen = sizeof(test18),
+                       .seq = seq18, .seq_size = LWS_ARRAY_SIZE(seq18) },
+       { .b = test19, .blen = sizeof(test19),
+                       .seq = seq19, .seq_size = LWS_ARRAY_SIZE(seq19) },
+       { .b = test20, .blen = sizeof(test20),
+                       .seq = seq20, .seq_size = LWS_ARRAY_SIZE(seq20) },
+       { .b = test21, .blen = sizeof(test21),
+                       .seq = seq21, .seq_size = LWS_ARRAY_SIZE(seq21) },
+       { .b = test22, .blen = sizeof(test22),
+                       .seq = seq22, .seq_size = LWS_ARRAY_SIZE(seq22) },
+       { .b = test23, .blen = sizeof(test23),
+                       .seq = seq23, .seq_size = LWS_ARRAY_SIZE(seq23) },
+       { .b = test24, .blen = sizeof(test24),
+                       .seq = seq24, .seq_size = LWS_ARRAY_SIZE(seq24) },
+       { .b = test25, .blen = sizeof(test25),
+                       .seq = seq25, .seq_size = LWS_ARRAY_SIZE(seq25) },
+       { .b = test26, .blen = sizeof(test26),
+                       .seq = seq26, .seq_size = LWS_ARRAY_SIZE(seq26) },
+       { .b = test27, .blen = sizeof(test27),
+                       .seq = seq27, .seq_size = LWS_ARRAY_SIZE(seq27) },
+       { .b = test28, .blen = sizeof(test28),
+                       .seq = seq28, .seq_size = LWS_ARRAY_SIZE(seq28) },
+       { .b = test29, .blen = sizeof(test29),
+                       .seq = seq29, .seq_size = LWS_ARRAY_SIZE(seq29) },
+       { .b = test30, .blen = sizeof(test30),
+                       .seq = seq30, .seq_size = LWS_ARRAY_SIZE(seq30) },
+       { .b = test31, .blen = sizeof(test31),
+                       .seq = seq31, .seq_size = LWS_ARRAY_SIZE(seq31) },
+       { .b = test32, .blen = sizeof(test32),
+                       .seq = seq32, .seq_size = LWS_ARRAY_SIZE(seq32) },
+       { .b = test33, .blen = sizeof(test33),
+                       .seq = seq33, .seq_size = LWS_ARRAY_SIZE(seq33) },
+       { .b = test34, .blen = sizeof(test34),
+                       .seq = seq34, .seq_size = LWS_ARRAY_SIZE(seq34) },
+       { .b = test35, .blen = sizeof(test35),
+                       .seq = seq35, .seq_size = LWS_ARRAY_SIZE(seq35) },
+       { .b = test36, .blen = sizeof(test36),
+                       .seq = seq36, .seq_size = LWS_ARRAY_SIZE(seq36) },
+       { .b = test37, .blen = sizeof(test37),
+                       .seq = seq37, .seq_size = LWS_ARRAY_SIZE(seq37) },
+       { .b = test38, .blen = sizeof(test38),
+                       .seq = seq38, .seq_size = LWS_ARRAY_SIZE(seq38) },
+       { .b = test39, .blen = sizeof(test39),
+                       .seq = seq39, .seq_size = LWS_ARRAY_SIZE(seq39) },
+       { .b = test40, .blen = sizeof(test40),
+                       .seq = seq40, .seq_size = LWS_ARRAY_SIZE(seq40) },
+       { .b = test41, .blen = sizeof(test41),
+                       .seq = seq41, .seq_size = LWS_ARRAY_SIZE(seq41) },
+       { .b = test42, .blen = sizeof(test42),
+                       .seq = seq42, .seq_size = LWS_ARRAY_SIZE(seq42) },
+       { .b = test43, .blen = sizeof(test43),
+                       .seq = seq43, .seq_size = LWS_ARRAY_SIZE(seq43) },
+       { .b = test44, .blen = sizeof(test44),
+                       .seq = seq44, .seq_size = LWS_ARRAY_SIZE(seq44) },
+       { .b = test45, .blen = sizeof(test45),
+                       .seq = seq45, .seq_size = LWS_ARRAY_SIZE(seq45) },
+       { .b = test46, .blen = sizeof(test46),
+                       .seq = seq46, .seq_size = LWS_ARRAY_SIZE(seq46) },
+       { .b = test47, .blen = sizeof(test47),
+                       .seq = seq47, .seq_size = LWS_ARRAY_SIZE(seq47) },
+       { .b = test48, .blen = sizeof(test48),
+                       .seq = seq48, .seq_size = LWS_ARRAY_SIZE(seq48) },
+       { .b = test49, .blen = sizeof(test49),
+                       .seq = seq49, .seq_size = LWS_ARRAY_SIZE(seq49) },
+       { .b = test50, .blen = sizeof(test50),
+                       .seq = seq50, .seq_size = LWS_ARRAY_SIZE(seq50) },
+       { .b = test51, .blen = sizeof(test51),
+                       .seq = seq51, .seq_size = LWS_ARRAY_SIZE(seq51) },
+       { .b = test52, .blen = sizeof(test52),
+                       .seq = seq52, .seq_size = LWS_ARRAY_SIZE(seq52) },
+       { .b = test53, .blen = sizeof(test53),
+                       .seq = seq53, .seq_size = LWS_ARRAY_SIZE(seq53) },
+       { .b = test54, .blen = sizeof(test54),
+                       .seq = seq54, .seq_size = LWS_ARRAY_SIZE(seq54) },
+       { .b = test55, .blen = sizeof(test55),
+                       .seq = seq55, .seq_size = LWS_ARRAY_SIZE(seq55) },
+       { .b = test56, .blen = sizeof(test56),
+                       .seq = seq56, .seq_size = LWS_ARRAY_SIZE(seq56) },
+       { .b = test57, .blen = sizeof(test57),
+                       .seq = seq57, .seq_size = LWS_ARRAY_SIZE(seq57) },
+       { .b = test58, .blen = sizeof(test58),
+                       .seq = seq58, .seq_size = LWS_ARRAY_SIZE(seq58) },
+       { .b = test59, .blen = sizeof(test59),
+                       .seq = seq59, .seq_size = LWS_ARRAY_SIZE(seq59) },
+       { .b = test60, .blen = sizeof(test60),
+                       .seq = seq60, .seq_size = LWS_ARRAY_SIZE(seq60) },
+       { .b = test61, .blen = sizeof(test61),
+                       .seq = seq61, .seq_size = LWS_ARRAY_SIZE(seq61) },
+       { .b = test62, .blen = sizeof(test62),
+                       .seq = seq62, .seq_size = LWS_ARRAY_SIZE(seq62) },
+       { .b = test63, .blen = sizeof(test63),
+                       .seq = seq63, .seq_size = LWS_ARRAY_SIZE(seq63) },
+       { .b = test64, .blen = sizeof(test64),
+                       .seq = seq64, .seq_size = LWS_ARRAY_SIZE(seq64) },
+       { .b = test65, .blen = sizeof(test65),
+                       .seq = seq65, .seq_size = LWS_ARRAY_SIZE(seq65) },
+       { .b = test66, .blen = sizeof(test66),
+                       .seq = seq66, .seq_size = LWS_ARRAY_SIZE(seq66) },
+       { .b = test67, .blen = sizeof(test67),
+                       .seq = seq67, .seq_size = LWS_ARRAY_SIZE(seq67) },
+       { .b = test68, .blen = sizeof(test68),
+                       .seq = seq68, .seq_size = LWS_ARRAY_SIZE(seq68) },
+       { .b = test69, .blen = sizeof(test69),
+                       .seq = seq69, .seq_size = LWS_ARRAY_SIZE(seq69) },
+       { .b = test70, .blen = sizeof(test70),
+                       .seq = seq70, .seq_size = LWS_ARRAY_SIZE(seq70) },
+       { .b = test71, .blen = sizeof(test71),
+                       .seq = seq71, .seq_size = LWS_ARRAY_SIZE(seq71) },
+       { .b = test72, .blen = sizeof(test72),
+                       .seq = seq72, .seq_size = LWS_ARRAY_SIZE(seq72) },
+       { .b = test73, .blen = sizeof(test73),
+                       .seq = seq73, .seq_size = LWS_ARRAY_SIZE(seq73) },
+       { .b = test74, .blen = sizeof(test74),
+                       .seq = seq74, .seq_size = LWS_ARRAY_SIZE(seq74) },
+       { .b = test75, .blen = sizeof(test75),
+                       .seq = seq75, .seq_size = LWS_ARRAY_SIZE(seq75) },
+       { .b = test76, .blen = sizeof(test76),
+                       .seq = seq76, .seq_size = LWS_ARRAY_SIZE(seq76) },
+       { .b = test77, .blen = sizeof(test77),
+                       .seq = seq77, .seq_size = LWS_ARRAY_SIZE(seq77) },
+       { .b = test78, .blen = sizeof(test78),
+                       .seq = seq78, .seq_size = LWS_ARRAY_SIZE(seq78) },
+       { .b = test79, .blen = sizeof(test79),
+                       .seq = seq79, .seq_size = LWS_ARRAY_SIZE(seq79) },
+       { .b = test80, .blen = sizeof(test80),
+                       .seq = seq80, .seq_size = LWS_ARRAY_SIZE(seq80) },
+       { .b = test81, .blen = sizeof(test81),
+                       .seq = seq81, .seq_size = LWS_ARRAY_SIZE(seq81) },
+       { .b = test82, .blen = sizeof(test82),
+                       .seq = seq82, .seq_size = LWS_ARRAY_SIZE(seq82) },
+
+       /* COSE-dervied test vectors */
+
+       { .b = test83, .blen = sizeof(test83),
+                       .seq = seq83, .seq_size = LWS_ARRAY_SIZE(seq83) },
+       { .b = test84, .blen = sizeof(test84),
+                       .seq = seq84, .seq_size = LWS_ARRAY_SIZE(seq84) },
+       { .b = test85, .blen = sizeof(test85),
+                       .seq = seq85, .seq_size = LWS_ARRAY_SIZE(seq85) },
+       { .b = test86, .blen = sizeof(test86),
+                       .seq = seq86, .seq_size = LWS_ARRAY_SIZE(seq86) },
+       { .b = test87, .blen = sizeof(test87),
+                       .seq = seq87, .seq_size = LWS_ARRAY_SIZE(seq87) },
+       { .b = test88, .blen = sizeof(test88),
+                       .seq = seq88, .seq_size = LWS_ARRAY_SIZE(seq88) },
+       { .b = test89, .blen = sizeof(test89),
+                       .seq = seq89, .seq_size = LWS_ARRAY_SIZE(seq89) },
+       { .b = test90, .blen = sizeof(test90),
+                       .seq = seq90, .seq_size = LWS_ARRAY_SIZE(seq90) },
+       { .b = test91, .blen = sizeof(test91),
+                       .seq = seq91, .seq_size = LWS_ARRAY_SIZE(seq91) },
+       { .b = test92, .blen = sizeof(test92),
+                       .seq = seq92, .seq_size = LWS_ARRAY_SIZE(seq92) },
+       { .b = test93, .blen = sizeof(test93),
+                       .seq = seq93, .seq_size = LWS_ARRAY_SIZE(seq93) },
+       { .b = test94, .blen = sizeof(test94),
+                       .seq = seq94, .seq_size = LWS_ARRAY_SIZE(seq94) },
+       { .b = test95, .blen = sizeof(test95),
+                       .seq = seq95, .seq_size = LWS_ARRAY_SIZE(seq95) },
+       { .b = test96, .blen = sizeof(test96),
+                       .seq = seq96, .seq_size = LWS_ARRAY_SIZE(seq96) },
+       { .b = test97, .blen = sizeof(test97),
+                       .seq = seq97, .seq_size = LWS_ARRAY_SIZE(seq97) },
+       { .b = test98, .blen = sizeof(test98),
+                       .seq = seq98, .seq_size = LWS_ARRAY_SIZE(seq98) },
+       { .b = test99, .blen = sizeof(test99),
+                       .seq = seq99, .seq_size = LWS_ARRAY_SIZE(seq99) },
+       { .b = test100, .blen = sizeof(test100),
+                       .seq = seq100, .seq_size = LWS_ARRAY_SIZE(seq100) },
+       { .b = test101, .blen = sizeof(test101),
+                       .seq = seq101, .seq_size = LWS_ARRAY_SIZE(seq101) },
+       { .b = test102, .blen = sizeof(test102),
+                       .seq = seq102, .seq_size = LWS_ARRAY_SIZE(seq102) },
+       { .b = test103, .blen = sizeof(test103),
+                       .seq = seq103, .seq_size = LWS_ARRAY_SIZE(seq103) },
+       { .b = test104, .blen = sizeof(test104),
+                       .seq = seq104, .seq_size = LWS_ARRAY_SIZE(seq104) },
+       { .b = test105, .blen = sizeof(test105),
+                       .seq = seq105, .seq_size = LWS_ARRAY_SIZE(seq105) },
+       { .b = test106, .blen = sizeof(test106),
+                       .seq = seq106, .seq_size = LWS_ARRAY_SIZE(seq106) },
+       { .b = test107, .blen = sizeof(test107),
+                       .seq = seq107, .seq_size = LWS_ARRAY_SIZE(seq107) },
+       { .b = test108, .blen = sizeof(test108),
+                       .seq = seq108, .seq_size = LWS_ARRAY_SIZE(seq108) },
+};
+
+static const uint8_t
+       w1[] = { 0x65, 0x68, 0x65, 0x6C,
+                0x6C, 0x6F },
+       w2[] = { 0xc2 },
+       w3[] = { 0x82, 0x63, 0x61, 0x62,
+                0x63, 0x63, 0x64, 0x65,
+                0x66 },
+       w4[] = { 0xA2, 0x63, 0x67, 0x68,
+                0x69, 0x01, 0x63, 0x6A,
+                0x6B, 0x6C, 0x02 },
+       w5[] = { 0xD8, 0x7B, 0xA2, 0x63,
+                0x67, 0x68, 0x69, 0x01,
+                0x63, 0x6A, 0x6B, 0x6C,
+                0x02 },
+       w6[] = { 0xCC, 0xA2, 0x63, 0x67,
+                0x68, 0x69, 0x01, 0x63,
+                0x6A, 0x6B, 0x6C, 0x82,
+                0x61, 0x61, 0x61, 0x62 },
+       w7[] = { 0x20, },
+       w8[] = { 0x0c, },
+       w13[] = { 0x18, 0x34 },
+       w14[] = { 0x19, 0x12, 0x34 },
+       w15[] = { 0x1a, 0x12, 0x34, 0x56, 0x78 },
+       w16[] = { 0x1b, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 },
+       w17[] = { 0x65, 0x68, 0x65, 0x6C, 0x6C, 0x6F },
+       w18[] = { 0x25 },
+       w19[] = {
+                       0xd8, 0x7b, 0x58, 0xb7,
+                       0xd8, 0x62, 0x84, 0x43, 0xa1,
+                       0x03, 0x00, 0xa1, 0x07, 0x83,
+                       0x43, 0xa1, 0x01, 0x27, 0xa1,
+                       0x04, 0x42, 0x31, 0x31, 0x58,
+                       0x40, 0xb7, 0xca, 0xcb, 0xa2,
+                       0x85, 0xc4, 0xcd, 0x3e, 0xd2,
+                       0xf0, 0x14, 0x6f, 0x41, 0x98,
+                       0x86, 0x14, 0x4c, 0xa6, 0x38,
+                       0xd0, 0x87, 0xde, 0x12, 0x3d,
+                       0x40, 0x01, 0x67, 0x30, 0x8a,
+                       0xce, 0xab, 0xc4, 0xb5, 0xe5,
+                       0xc6, 0xa4, 0x0c, 0x0d, 0xe0,
+                       },
+       w19a[] = {
+                       0xb7, 0x11, 0x67, 0xa3, 0x91,
+                       0x75, 0xea, 0x56, 0xc1, 0xfe,
+                       0x96, 0xc8, 0x9e, 0x5e, 0x7d,
+                       0x30, 0xda, 0xf2, 0x43, 0x8a,
+                       0x45, 0x61, 0x59, 0xa2, 0x0a,
+                       0x54, 0x54, 0x68, 0x69, 0x73,
+                       0x20, 0x69, 0x73, 0x20, 0x74,
+                       0x68, 0x65, 0x20, 0x63, 0x6f,
+                       0x6e, 0x74, 0x65, 0x6e, 0x74,
+                       0x2e, 0x81, 0x83, 0x43, 0xa1,
+                       0x01, 0x27, 0xa1, 0x04, 0x42,
+                       0x31, 0x31, 0x58, 0x40, 0x77,
+                       0xf3, 0xea, 0xcd, 0x11,},
+       w19b[] = {
+                       0x85, 0x2c, 0x4b, 0xf9, 0xcb, 0x1d,
+                       0x72, 0xfa, 0xbe, 0x6b, 0x26,
+                       0xfb, 0xa1, 0xd7, 0x60, 0x92,
+                       0xb2, 0xb5, 0xb7, 0xec, 0x83,
+                       0xb8, 0x35, 0x57, 0x65, 0x22,
+                       0x64, 0xe6, 0x96, 0x90, 0xdb,
+                       0xc1, 0x17, 0x2d, 0xdc, 0x0b,
+                       0xf8, 0x84, 0x11, 0xc0, 0xd2,
+                       0x5a, 0x50, 0x7f, 0xdb, 0x24,
+                       0x7a, 0x20, 0xc4, 0x0d, 0x5e,
+                       0x24, 0x5f, 0xab, 0xd3, 0xfc,
+                       0x9e, 0xc1, 0x06 },
+       w22[] = { 0xD8, 0x7B, 0x19, 0x01, 0xC8 },
+       w24[] = { 0xDB, 0x12, 0x34, 0x56, 0x78, 0x9A,
+                       0xBC, 0xED, 0xF0, 0x19, 0x01, 0xC8},
+       w25[] = { 0xF9, 0x3C, 0x00 },
+       w26[] = { 0xF9, 0x3E, 0x00 },
+       w27[] = { 0xFB, 0x3F, 0xF1, 0xF7, 0xCE, 0xD9, 0x16, 0x87, 0x2B },
+       w28[] = { 0xA2, 0x61, 0x61, 0x01, 0x61, 0x62, 0x82, 0x02, 0x03 },
+       w29[] = { 0x7F, 0x65, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0xFF
+}
+;
+
+static const char * const tok[] = {
+       "something",
+};
+
+struct priv {
+       const struct cbort *cbt;
+       size_t idx;
+};
+
+static int pass;
+
+static signed char
+test_cb(struct lecp_ctx *ctx, char reason)
+{
+       struct priv *priv = (struct priv *)ctx->user;
+       size_t i = priv->idx++;
+
+#if defined(VERBOSE)
+        lwsl_notice("%s: %s, ctx->path %s\n", __func__,
+                        reason_names[(int)reason & 0x1f], ctx->path);
+#endif
+
+       // if (ctx->npos)
+       //      lwsl_hexdump_notice(ctx->buf, ctx->npos);
+
+       if (!priv->cbt->seq)
+               return 0;
+
+       if (i >= priv->cbt->seq_size) {
+               lwsl_warn("%s: unexpected parse states\n", __func__);
+               return 1;
+       }
+
+       if (priv->cbt->seq[i].reason != reason) {
+               lwsl_warn("%s: reason mismatch\n", __func__);
+               return 1;
+       }
+
+       if (priv->cbt->seq[i].buf &&
+           (priv->cbt->seq[i].buf_len != ctx->npos ||
+            memcmp(priv->cbt->seq[i].buf, ctx->buf, ctx->npos))) {
+               lwsl_warn("%s: buf mismatch\n", __func__);
+               lwsl_hexdump_notice(ctx->buf, (size_t)ctx->npos);
+               return 1;
+       }
+
+       switch (reason) {
+       case LECPCB_VAL_SIMPLE:
+       case LECPCB_VAL_NUM_UINT:
+       case LECPCB_VAL_NUM_INT:
+               if (ctx->item.u.u64 != priv->cbt->seq[i].item.u.u64) {
+                       lwsl_warn("%s: number mismatch %llu %llu\n", __func__,
+                               (unsigned long long)ctx->item.u.u64,
+                               (unsigned long long)priv->cbt->seq[i].item.u.u64);
+                       return 1;
+               }
+               break;
+
+       case LECPCB_VAL_FLOAT16:
+               if (ctx->item.u.hf != priv->cbt->seq[i].item.u.hf) {
+                       lwsl_warn("%s: number mismatch %llu %llu\n", __func__,
+                               (unsigned long long)ctx->item.u.hf,
+                               (unsigned long long)priv->cbt->seq[i].item.u.hf);
+                       return 1;
+               }
+               break;
+       case LECPCB_VAL_FLOAT32:
+#if defined(LWS_WITH_CBOR_FLOAT)
+               if (!isfinite(ctx->item.u.f) &&
+                   !isfinite(priv->cbt->seq[i].item.u.f))
+                       break;
+               if (isnan(ctx->item.u.f) &&
+                   isnan(priv->cbt->seq[i].item.u.f))
+                       break;
+#endif
+               if (ctx->item.u.f != priv->cbt->seq[i].item.u.f) {
+#if defined(LWS_WITH_CBOR_FLOAT)
+                       lwsl_warn("%s: number mismatch %f %f\n", __func__,
+                               ctx->item.u.f,
+                               priv->cbt->seq[i].item.u.f);
+#else
+                       lwsl_warn("%s: f32 number mismatch %llu %llu\n", __func__,
+                               (unsigned long long)ctx->item.u.f,
+                               (unsigned long long)priv->cbt->seq[i].item.u.f);
+#endif
+                       return 1;
+               }
+               break;
+       case LECPCB_VAL_FLOAT64:
+#if defined(LWS_WITH_CBOR_FLOAT)
+               if (!isfinite(ctx->item.u.d) &&
+                   !isfinite(priv->cbt->seq[i].item.u.d))
+                       break;
+               if (isnan(ctx->item.u.d) &&
+                   isnan(priv->cbt->seq[i].item.u.d))
+                       break;
+#endif
+               if (ctx->item.u.d != priv->cbt->seq[i].item.u.d) {
+#if defined(LWS_WITH_CBOR_FLOAT)
+                       lwsl_warn("%s: f64 number mismatch %f %f\n", __func__,
+                               ctx->item.u.d,
+                               priv->cbt->seq[i].item.u.d);
+#else
+                       lwsl_warn("%s: number mismatch %llu %llu\n", __func__,
+                               (unsigned long long)ctx->item.u.d,
+                               (unsigned long long)priv->cbt->seq[i].item.u.d);
+#endif
+                       return 1;
+               }
+               break;
+
+       case LECPCB_DESTRUCTED:
+               pass++;
+               break;
+       }
+
+       return 0;
+}
+
+int main(int argc, const char **argv)
+{
+       int n, m, e = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE,
+                       expected = (int)LWS_ARRAY_SIZE(cbor_tests) +
+                                       29 /* <-- how many write tests */;
+       struct lecp_ctx ctx;
+       const char *p;
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS API selftest: LECP CBOR parser\n");
+
+       for (m = 0; m < (int)LWS_ARRAY_SIZE(cbor_tests); m++) {
+
+               struct priv priv;
+
+               priv.cbt = &cbor_tests[m];
+               priv.idx = 0;
+
+               lwsl_notice("%s: ++++++++++++++++ test %d\n", __func__, m + 1);
+
+               lecp_construct(&ctx, test_cb, &priv, tok, LWS_ARRAY_SIZE(tok));
+
+               lwsl_hexdump_info(cbor_tests[m].b, cbor_tests[m].blen);
+
+#if 0
+               {
+                       char fn[128];
+                       int fd;
+
+                       lws_snprintf(fn, sizeof(fn), "/tmp/cbor-%d", m + 1);
+                       fd = open(fn, LWS_O_CREAT | LWS_O_TRUNC | LWS_O_WRONLY, 0600);
+                       if (fd != -1) {
+                               write(fd,  cbor_tests[m].b,
+                                          cbor_tests[m].blen);
+                               close(fd);
+                       }
+               }
+#endif
+
+               n = lecp_parse(&ctx, cbor_tests[m].b,
+                                    cbor_tests[m].blen);
+
+               lecp_destruct(&ctx);
+
+               if (n < 0 && m + 1 != 46 /* expected to fail */) {
+                       lwsl_err("%s: test %d: CBOR decode failed %d '%s'\n",
+                                       __func__, m + 1, n,
+                                       lecp_error_to_string(n));
+                       e++;
+               }
+       }
+
+       {
+               lws_lec_pctx_t ctx;
+               uint8_t buf[64];
+
+               lws_lec_init(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "'hello'") !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w1) || memcmp(w1, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "2()") !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w2) || memcmp(w2, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "['abc','def']") !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w3) || memcmp(w3, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test4\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "{'ghi':1,'jkl':2}") !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w4) || memcmp(w4, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test5\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "123({'ghi':1,'jkl':2})") !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w5) || memcmp(w5, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test6\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "12({'ghi':1,'jkl':['a', 'b']})") !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w6) || memcmp(w6, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test7\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%d", -1) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w7) || memcmp(w7, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test8\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%ld", -1l) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w7) || memcmp(w7, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test9\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%lld", -1ll) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w7) || memcmp(w7, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test10\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%u", 12) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w8) || memcmp(w8, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test11\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%ld", 12l) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w8) || memcmp(w8, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test12\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%lld", 12ll) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w8) || memcmp(w8, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test13\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%u", 0x34u) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w13) || memcmp(w13, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test14\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%ld", 0x1234ul) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w14) || memcmp(w14, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test15\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%lld", 0x12345678ull) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w15) || memcmp(w15, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test16\n", __func__);
+
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%lld", 0x123456789abcdef0ull) !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w16) || memcmp(w16, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test17\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%s", "hello") !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w17) || memcmp(w17, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test18\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "-6") !=
+                                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w18) || memcmp(w18, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               /*
+                * A big binary blob is going to get emitted in 3 output
+                * buffers, by calling it two more times while still handling
+                * the same format object, format objects before that which
+                * were completed are skipped on the subsequent calls
+                */
+
+               lwsl_user("%s: test19\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "123(%.*b)", (int)sizeof(test106), test106) !=
+                               LWS_LECPCTX_RET_AGAIN ||
+                   ctx.used != sizeof(w19) || memcmp(w19, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test20\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "123(%.*b)", (int)sizeof(test106), test106) !=
+                               LWS_LECPCTX_RET_AGAIN ||
+                   ctx.used != sizeof(w19a) || memcmp(w19a, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test21\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "123(%.*b)", (int)sizeof(test106), test106) !=
+                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w19b) || memcmp(w19b, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test22\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%t(456)", 123) !=
+                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w22) || memcmp(w22, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test23\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%lt(456)", 123ul) !=
+                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w22) || memcmp(w22, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test24\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%llt(456)", 0x123456789abcedf0ull) !=
+                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w24) || memcmp(w24, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test25\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%f", 1.0) !=
+                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w25) || memcmp(w25, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test26\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%f", 1.5) !=
+                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w26) || memcmp(w26, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               lwsl_user("%s: test27\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "%f", 1.123) !=
+                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w27) || memcmp(w27, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+
+               {
+                       int args[3] = { 1, 2, 3 };
+
+                       lwsl_user("%s: test28\n", __func__);
+                       lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+                       if (lws_lec_printf(&ctx, "{'a':%d,'b':[%d,%d]}",
+                                               args[0], args[1], args[2]) !=
+                                       LWS_LECPCTX_RET_FINISHED ||
+                           ctx.used != sizeof(w28) ||
+                           memcmp(w28, buf, ctx.used)) {
+                               lwsl_hexdump_notice(ctx.start, ctx.used);
+                               e++;
+                       } else
+                               pass++;
+               }
+
+               lwsl_user("%s: test29\n", __func__);
+               lws_lec_setbuf(&ctx, buf, sizeof(buf));
+
+               if (lws_lec_printf(&ctx, "<t'hello'>") !=
+                               LWS_LECPCTX_RET_FINISHED ||
+                   ctx.used != sizeof(w29) || memcmp(w29, buf, ctx.used)) {
+                       lwsl_hexdump_notice(ctx.start, ctx.used);
+                       e++;
+               } else
+                       pass++;
+       }
+
+       if (e)
+               goto bail;
+
+       if (pass != expected)
+               goto bail;
+
+       lwsl_user("Completed: PASS %d / %d\n", pass, expected);
+
+       return 0;
+
+bail:
+       lwsl_user("Completed: FAIL, passed %d / %d (e %d)\n", pass,
+                               expected, e);
+
+       return 1;
+}
diff --git a/minimal-examples/api-tests/api-test-lejp/CMakeLists.txt b/minimal-examples/api-tests/api-test-lejp/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ccdb9b5
--- /dev/null
@@ -0,0 +1,22 @@
+project(lws-api-test-lejp C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_LEJP 1 requirements)
+
+if (requirements)
+
+       add_executable(${PROJECT_NAME} main.c)
+       add_test(NAME api-test-lejp COMMAND lws-api-test-lejp)
+
+       if (websockets_shared)
+               target_link_libraries(${PROJECT_NAME} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${PROJECT_NAME} websockets_shared)
+       else()
+               target_link_libraries(${PROJECT_NAME} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/api-tests/api-test-lejp/main.c b/minimal-examples/api-tests/api-test-lejp/main.c
new file mode 100644 (file)
index 0000000..352181b
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * lws-api-test-lejp
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * sanity tests for lejp
+ */
+
+#include <libwebsockets.h>
+
+/*
+ * in this example, the JSON is for one "builder" object, which may specify
+ * a child list "targets" of zero or more "target" objects.
+ */
+
+static const char * const json_tests[] = {
+       "{" /* test 1 */
+               "\"schema\":\"com-warmcat-sai-builder\","
+
+               "\"hostname\":\"learn\","
+               "\"nspawn_timeout\":1800,"
+               "\"targets\":["
+                       "{"
+                               "\"name\":\"target1\","
+                               "\"someflag\":true"
+                       "},"
+                       "{"
+                               "\"name\":\"target2\","
+                               "\"someflag\":false"
+                       "}"
+               "]"
+       "}",
+       "{" /* test 2 */
+               "\"schema\":\"com-warmcat-sai-builder\","
+
+               "\"hostname\":\"learn\","
+               "\"targets\":["
+                       "{"
+                               "\"name\":\"target1\""
+                       "},"
+                       "{"
+                               "\"name\":\"target2\""
+                       "},"
+                       "{"
+                               "\"name\":\"target3\""
+                       "}"
+               "]"
+       "}", "{" /* test 3 */
+               "\"schema\":\"com-warmcat-sai-builder\","
+
+               "\"hostname\":\"learn\","
+               "\"nspawn_timeout\":1800,"
+               "\"targets\":["
+                       "{"
+                               "\"name\":\"target1\","
+                               "\"unrecognized\":\"xyz\","
+                               "\"child\": {"
+                                       "\"somename\": \"abc\","
+                                       "\"junk\": { \"x\": \"y\" }"
+                               "}"
+                       "},"
+                       "{"
+                               "\"name\":\"target2\""
+                       "}"
+               "]"
+       "}",
+       "{" /* test 4 */
+               "\"schema\":\"com-warmcat-sai-builder\","
+
+               "\"hostname\":\"learn\","
+               "\"nspawn_timeout\":1800"
+       "}",
+       "{" /* test 5 */
+               "\"schema\":\"com-warmcat-sai-builder\""
+       "}",
+       "{" /* test 6 ... check huge strings into smaller fixed char array */
+               "\"schema\":\"com-warmcat-sai-builder\","
+               "\"hostname\":\""
+               "PYvtan6kqppjnS0KpYTCaiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6A"
+               "zefzoWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9D1QKIWqg5RJ/"
+               "CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6bzhA+A/xAsFzSBnb3MHYWzGMprr5"
+               "3FAP1ISo5Ec9i+2ehV40sG6Q470sH3PGQZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV"
+               "8sq3ZgcxKNB7tNfN7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1"
+               "NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEhdZgxky2+g5hhlSIG"
+               "JYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/RrfOV+oV4R26IDq+KqUiJBENeo8/GXkG"
+               "LUH/87iPyzXKEMavr6fkrK0vTGto8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MW"
+               "v+B/t1eZZ+1euLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZvstK9"
+               "eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6O/grHnvJZm2vBkxuXgsY"
+               "VkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0WaCqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/"
+               "uZjjEGGLhJR1jPqA9D1Ej3ChV+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yu"
+               "yJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx"
+               "+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\""
+       "}",
+       "{" /* test 7 ... check huge strings into char * */
+               "\"schema\":\"com-warmcat-sai-builder\","
+               "\"targets\":["
+                       "{"
+                               "\"name\":\""
+               "PYvtan6kqppjnS0KpYTCaiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6A"
+               "zefzoWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9D1QKIWqg5RJ/"
+               "CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6bzhA+A/xAsFzSBnb3MHYWzGMprr5"
+               "3FAP1ISo5Ec9i+2ehV40sG6Q470sH3PGQZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV"
+               "8sq3ZgcxKNB7tNfN7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1"
+               "NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEhdZgxky2+g5hhlSIG"
+               "JYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/RrfOV+oV4R26IDq+KqUiJBENeo8/GXkG"
+               "LUH/87iPyzXKEMavr6fkrK0vTGto8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MW"
+               "v+B/t1eZZ+1euLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZvstK9"
+               "eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6O/grHnvJZm2vBkxuXgsY"
+               "VkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0WaCqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/"
+               "uZjjEGGLhJR1jPqA9D1Ej3ChV+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yu"
+               "yJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx"
+               "+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\"}]}"
+       "}",
+       "{" /* test 8 the "other" schema */
+               "\"schema\":\"com-warmcat-sai-logs\","
+               "\"task_uuid\":\"97fc90052506af8b3eb43b87aaa6fb76feab32bc128ede479a8a6b961e801f06\","
+               "\"timestamp\": 170366786103,\"channel\":3, \"len\":20, "
+               "\"log\": \"PnNhaWI+IE5TU1RBVEVfSU5JVAo=\"}\x0a"
+               "ntu-xenial-amd64\"},{\"name\":\"linux-ubuntu-bionic-amd64\"},{\"name\":\"linux-fedora-32-x86_64\"}]}\",",
+
+       "{" /* test 9, empty object */
+               "\"a\":123,\"b\":{}"
+       "}",
+
+       "{" /* SHOULD_FAIL: test 10, missing open */
+               "\"a\":123,\"b\":}"
+       "}"
+};
+
+static const char * const tok[] = {
+       "something",
+};
+
+static signed char
+test_cb(struct lejp_ctx *ctx, char reason)
+{
+       lwsl_info("%s: ctx->path %s, buf %s\n", __func__, ctx->path, ctx->buf);
+       return 0;
+}
+
+/* authz JSON parsing */
+
+
+int main(int argc, const char **argv)
+{
+       int n, m, e = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       struct lejp_ctx ctx;
+       const char *p;
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS API selftest: lws_struct JSON\n");
+
+       for (m = 0; m < (int)LWS_ARRAY_SIZE(json_tests); m++) {
+
+               lwsl_info("%s: ++++++++++++++++ test %d\n", __func__, m + 1);
+
+               lejp_construct(&ctx, test_cb, NULL, tok, LWS_ARRAY_SIZE(tok));
+
+               lwsl_hexdump_info(json_tests[m], strlen(json_tests[m]));
+
+               if (m == 7)
+                       n = lejp_parse(&ctx, (uint8_t *)json_tests[m],
+                                                        0xc8);
+               else
+                       n = lejp_parse(&ctx, (uint8_t *)json_tests[m],
+                                                (int)strlen(json_tests[m]));
+
+               lwsl_info("n = %d\n", n);
+               if (n < 0 && m != 9) {
+                       lwsl_err("%s: test %d: JSON decode failed '%s'\n",
+                                       __func__, m + 1, lejp_error_to_string(n));
+                       e++;
+               }
+               if (n >= 0 && m == 9) {
+                       lwsl_err("%s: test %d: JSON decode should have failed '%s'\n",
+                                       __func__, m + 1, lejp_error_to_string(n));
+                       e++;
+               }
+       }
+
+       {
+               const char *cs;
+               size_t cslen;
+               cs = lws_json_simple_find("{\"blah\":123,\"ext\":{\"authorized\":1}}", 35,
+                                           "\"ext\":", &cslen);
+               if (!cs) {
+                       lwsl_err("%s: simple_find failed\n", __func__);
+                       e++;
+               } else {
+                       if (lws_json_simple_strcmp(cs, cslen,
+                                       "\"authorized\":", "1"))
+                               e++;
+               }
+               cs = lws_json_simple_find("{\"blah\":123,\"auth_user\":\"andy@warmcat.com\",\"thing\":\"yeah\"}", 57,
+                                           "\"auth_user\":", &cslen);
+               if (cslen != 16) {
+                       lwsl_err("%s: wrong string len %d isolated\n", __func__, (int)cslen);
+                       e++;
+               }
+       }
+
+       if (e)
+               goto bail;
+
+       lwsl_user("Completed: PASS\n");
+
+       return 0;
+
+bail:
+       lwsl_user("Completed: FAIL\n");
+
+       return 1;
+}
diff --git a/minimal-examples/api-tests/api-test-lws_cache/CMakeLists.txt b/minimal-examples/api-tests/api-test-lws_cache/CMakeLists.txt
new file mode 100644 (file)
index 0000000..72ae86a
--- /dev/null
@@ -0,0 +1,19 @@
+project(lws-api-test-lws_cache C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-api-test-lws_cache)
+set(SRCS main.c)
+
+add_executable(${SAMP} ${SRCS})
+add_test(NAME api-test-lws_cache COMMAND lws-api-test-lws_cache)
+
+if (websockets_shared)
+       target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+       add_dependencies(${SAMP} websockets_shared)
+else()
+       target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+endif()
diff --git a/minimal-examples/api-tests/api-test-lws_cache/README.md b/minimal-examples/api-tests/api-test-lws_cache/README.md
new file mode 100644 (file)
index 0000000..74034c7
--- /dev/null
@@ -0,0 +1,22 @@
+# lws api test lwsac
+
+Demonstrates how to use and performs selftests for lwsac
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+ $ ./lws-api-test-lwsac
+[2018/10/09 09:14:17:4834] USER: LWS API selftest: lwsac
+[2018/10/09 09:14:17:4835] USER: Completed: PASS
+```
+
diff --git a/minimal-examples/api-tests/api-test-lws_cache/main.c b/minimal-examples/api-tests/api-test-lws_cache/main.c
new file mode 100644 (file)
index 0000000..64835ff
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * lws-api-test-lws_cache
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+
+static struct lws_context *cx;
+static int tests, fail;
+
+static int
+test_just_l1(void)
+{
+       struct lws_cache_creation_info ci;
+       struct lws_cache_ttl_lru *l1;
+       int ret = 1;
+       size_t size;
+       char *po;
+
+       lwsl_user("%s\n", __func__);
+
+       tests++;
+
+       /* just create a heap cache "L1" */
+
+       memset(&ci, 0, sizeof(ci));
+       ci.cx = cx;
+       ci.ops = &lws_cache_ops_heap;
+       ci.name = "L1";
+
+       l1 = lws_cache_create(&ci);
+       if (!l1)
+               goto cdone;
+
+       /* add two items, a has 1s expiry and b has 2s */
+
+       if (lws_cache_write_through(l1, "a", (const uint8_t *)"is_a", 5,
+                                   lws_now_usecs() + LWS_US_PER_SEC, NULL))
+               goto cdone;
+
+       if (lws_cache_write_through(l1, "b", (const uint8_t *)"is_b", 5,
+                                   lws_now_usecs() + LWS_US_PER_SEC * 2, NULL))
+               goto cdone;
+
+       /* check they exist as intended */
+
+       if (lws_cache_item_get(l1, "a", (const void **)&po, &size) ||
+           size != 5 || strcmp(po, "is_a"))
+               goto cdone;
+
+       if (lws_cache_item_get(l1, "b", (const void **)&po, &size) ||
+           size != 5 || strcmp(po, "is_b"))
+               goto cdone;
+
+       /* wait for 1.2s to pass, working the event loop by hand */
+
+       lws_cancel_service(cx);
+       if (lws_service(cx, 0) < 0)
+               goto cdone;
+#if defined(WIN32)
+       Sleep(1200);
+#else
+       /* netbsd cares about < 1M */
+       usleep(999999);
+       usleep(200001);
+#endif
+       lws_cancel_service(cx);
+       if (lws_service(cx, 0) < 0)
+               goto cdone;
+
+       lws_cancel_service(cx);
+       if (lws_service(cx, 0) < 0)
+               goto cdone;
+
+       /* a only had 1s lifetime, he should be gone */
+
+       if (!lws_cache_item_get(l1, "a", (const void **)&po, &size)) {
+               lwsl_err("%s: cache: a still exists after expiry\n", __func__);
+               fail++;
+               goto cdone;
+       }
+
+       /* that's ok then */
+
+       ret = 0;
+
+cdone:
+       lws_cache_destroy(&l1);
+
+       if (ret)
+               lwsl_warn("%s: fail\n", __func__);
+
+       return ret;
+}
+
+static int
+test_just_l1_limits(void)
+{
+       struct lws_cache_creation_info ci;
+       struct lws_cache_ttl_lru *l1;
+       int ret = 1;
+       size_t size;
+       char *po;
+
+       lwsl_user("%s\n", __func__);
+       tests++;
+
+       /* just create a heap cache "L1" */
+
+       memset(&ci, 0, sizeof(ci));
+       ci.cx = cx;
+       ci.ops = &lws_cache_ops_heap;
+       ci.name = "L1_lim";
+       ci.max_items = 1; /* ie, adding a second item destroys the first */
+
+       l1 = lws_cache_create(&ci);
+       if (!l1)
+               goto cdone;
+
+       /* add two items, a has 1s expiry and b has 2s */
+
+       if (lws_cache_write_through(l1, "a", (const uint8_t *)"is_a", 5,
+                                   lws_now_usecs() + LWS_US_PER_SEC, NULL))
+               goto cdone;
+
+       if (lws_cache_write_through(l1, "b", (const uint8_t *)"is_b", 5,
+                                   lws_now_usecs() + LWS_US_PER_SEC * 2, NULL))
+               goto cdone;
+
+       /* only b should exit, since we limit to cache to just one entry */
+
+       if (!lws_cache_item_get(l1, "a", (const void **)&po, &size))
+               goto cdone;
+
+       if (lws_cache_item_get(l1, "b", (const void **)&po, &size) ||
+           size != 5 || strcmp(po, "is_b"))
+               goto cdone;
+
+       /* that's ok then */
+
+       ret = 0;
+
+cdone:
+       lws_cache_destroy(&l1);
+
+       if (ret)
+               lwsl_warn("%s: fail\n", __func__);
+
+       return ret;
+}
+
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR)
+
+static const char
+       *cookie1 = "host.com\tFALSE\t/\tTRUE\t4000000000\tmycookie\tmycookievalue",
+       *tag_cookie1 = "host.com|/|mycookie",
+       *cookie2 = "host.com\tFALSE\t/xxx\tTRUE\t4000000000\tmycookie\tmyxxxcookievalue",
+       *tag_cookie2 = "host.com|/xxx|mycookie",
+       *cookie3 = "host.com\tFALSE\t/\tTRUE\t4000000000\textra\tcookie3value",
+       *tag_cookie3 = "host.com|/|extra",
+       *cookie4 = "host.com\tFALSE\t/yyy\tTRUE\t4000000000\tnewcookie\tnewcookievalue",
+       *tag_cookie4 = "host.com|/yyy|newcookie"
+;
+
+static int
+test_nsc1(void)
+{
+       struct lws_cache_creation_info ci;
+       struct lws_cache_ttl_lru *l1 = NULL, *nsc;
+       lws_cache_results_t cr;
+       int n, ret = 1;
+       size_t size;
+       char *po;
+
+       lwsl_user("%s\n", __func__);
+       tests++;
+
+       /* First create a netscape cookie cache object */
+
+       memset(&ci, 0, sizeof(ci));
+       ci.cx = cx;
+       ci.ops = &lws_cache_ops_nscookiejar;
+       ci.name = "NSC";
+       ci.u.nscookiejar.filepath = "./cookies.txt";
+
+       nsc = lws_cache_create(&ci);
+       if (!nsc)
+               goto cdone;
+
+       /* Then a heap cache "L1" as a child of nsc */
+
+       ci.ops = &lws_cache_ops_heap;
+       ci.name = "L1";
+       ci.parent = nsc;
+
+       l1 = lws_cache_create(&ci);
+       if (!l1)
+               goto cdone;
+
+       lws_cache_debug_dump(nsc);
+       lws_cache_debug_dump(l1);
+
+       lwsl_user("%s: add cookies to L1\n", __func__);
+
+       /* add three cookies */
+
+       if (lws_cache_write_through(l1, tag_cookie1,
+                                   (const uint8_t *)cookie1, strlen(cookie1),
+                                   lws_now_usecs() + LWS_US_PER_SEC, NULL)) {
+               lwsl_err("%s: write1 failed\n", __func__);
+               goto cdone;
+       }
+
+       lws_cache_debug_dump(nsc);
+       lws_cache_debug_dump(l1);
+
+       if (lws_cache_write_through(l1, tag_cookie2,
+                                   (const uint8_t *)cookie2, strlen(cookie2),
+                                   lws_now_usecs() + LWS_US_PER_SEC * 2, NULL)) {
+               lwsl_err("%s: write2 failed\n", __func__);
+               goto cdone;
+       }
+
+       lws_cache_debug_dump(nsc);
+       lws_cache_debug_dump(l1);
+
+       if (lws_cache_write_through(l1, tag_cookie3,
+                                   (const uint8_t *)cookie3, strlen(cookie3),
+                                   lws_now_usecs() + LWS_US_PER_SEC * 2, NULL)) {
+               lwsl_err("%s: write3 failed\n", __func__);
+               goto cdone;
+       }
+
+       lws_cache_debug_dump(nsc);
+       lws_cache_debug_dump(l1);
+
+       lwsl_user("%s: check cookies in L1\n", __func__);
+
+       /* confirm that the cookies are individually in L1 */
+
+       if (lws_cache_item_get(l1, tag_cookie1, (const void **)&po, &size) ||
+           size != strlen(cookie1) || memcmp(po, cookie1, size)) {
+               lwsl_err("%s: L1 '%s' missing, size %llu, po %s\n", __func__,
+                        tag_cookie1, (unsigned long long)size, po);
+               goto cdone;
+       }
+
+       if (lws_cache_item_get(l1, tag_cookie2, (const void **)&po, &size) ||
+           size != strlen(cookie2) || memcmp(po, cookie2, size)) {
+               lwsl_err("%s: L1 '%s' missing\n", __func__, tag_cookie2);
+               goto cdone;
+       }
+
+       if (lws_cache_item_get(l1, tag_cookie3, (const void **)&po, &size) ||
+           size != strlen(cookie3) || memcmp(po, cookie3, size)) {
+               lwsl_err("%s: L1 '%s' missing\n", __func__, tag_cookie3);
+               goto cdone;
+       }
+
+       /* confirm that the cookies are individually in L2 / NSC... normally
+        * we don't do this but check via L1 so we can get it from there if
+        * present.  But as a unit test, we want to make sure it's in L2 / NSC
+        */
+
+       lwsl_user("%s: check cookies written thru to NSC\n", __func__);
+
+       if (lws_cache_item_get(nsc, tag_cookie1, (const void **)&po, &size) ||
+           size != strlen(cookie1) || memcmp(po, cookie1, size)) {
+               lwsl_err("%s: NSC '%s' missing, size %llu, po %s\n", __func__,
+                        tag_cookie1, (unsigned long long)size, po);
+               goto cdone;
+       }
+
+       if (lws_cache_item_get(nsc, tag_cookie2, (const void **)&po, &size) ||
+           size != strlen(cookie2) || memcmp(po, cookie2, size)) {
+               lwsl_err("%s: NSC '%s' missing\n", __func__, tag_cookie2);
+               goto cdone;
+       }
+
+       if (lws_cache_item_get(nsc, tag_cookie3, (const void **)&po, &size) ||
+           size != strlen(cookie3) || memcmp(po, cookie3, size)) {
+               lwsl_err("%s: NSC '%s' missing\n", __func__, tag_cookie3);
+               goto cdone;
+       }
+
+       /* let's do a lookup with no results */
+
+       lwsl_user("%s: nonexistant get must not pass\n", __func__);
+
+       if (!lws_cache_item_get(l1, "x.com|y|z", (const void **)&po, &size)) {
+               lwsl_err("%s: nonexistant found size %llu, po %s\n", __func__,
+                        (unsigned long long)size, po);
+               goto cdone;
+       }
+
+       /*
+        * let's try some url paths and check we get the right results set...
+        * for / and any cookie, we expect only c1 and c3 to be listed
+        */
+
+       lwsl_user("%s: wildcard lookup 1\n", __func__);
+
+       n = lws_cache_lookup(l1, "host.com|/|*",
+                            (const void **)&cr.ptr, &cr.size);
+       if (n) {
+               lwsl_err("%s: lookup failed %d\n", __func__, n);
+               goto cdone;
+       }
+       lwsl_hexdump_notice(cr.ptr, size);
+
+       if (cr.size != 53)
+               goto cdone;
+
+       while (!lws_cache_results_walk(&cr))
+               lwsl_notice("  %s (%d)\n", (const char *)cr.tag,
+                                          (int)cr.payload_len);
+
+       /*
+        * for /xxx and any cookie, we expect all 3 listed
+        */
+
+       lwsl_user("%s: wildcard lookup 2\n", __func__);
+
+       n = lws_cache_lookup(l1, "host.com|/xxx|*",
+                            (const void **)&cr.ptr, &cr.size);
+       if (n) {
+               lwsl_err("%s: lookup failed %d\n", __func__, n);
+               goto cdone;
+       }
+
+       if (cr.size != 84)
+               goto cdone;
+
+       while (!lws_cache_results_walk(&cr))
+               lwsl_notice("  %s (%d)\n", (const char *)cr.tag,
+                                          (int)cr.payload_len);
+
+       /*
+        * for /yyyy and any cookie, we expect only c1 and c3
+        */
+
+       lwsl_user("%s: wildcard lookup 3\n", __func__);
+
+       n = lws_cache_lookup(l1, "host.com|/yyyy|*",
+                            (const void **)&cr.ptr, &cr.size);
+       if (n) {
+               lwsl_err("%s: lookup failed %d\n", __func__, n);
+               goto cdone;
+       }
+
+       if (cr.size != 53)
+               goto cdone;
+
+       while (!lws_cache_results_walk(&cr))
+               lwsl_notice("  %s (%d)\n", (const char *)cr.tag,
+                                          (int)cr.payload_len);
+
+       /*
+        * repeat the above test, results should come from cache
+        */
+
+       lwsl_user("%s: wildcard lookup 4\n", __func__);
+
+       n = lws_cache_lookup(l1, "host.com|/yyyy|*",
+                            (const void **)&cr.ptr, &cr.size);
+       if (n) {
+               lwsl_err("%s: lookup failed %d\n", __func__, n);
+               goto cdone;
+       }
+
+       if (cr.size != 53)
+               goto cdone;
+
+       while (!lws_cache_results_walk(&cr))
+               lwsl_notice("  %s (%d)\n", (const char *)cr.tag,
+                                          (int)cr.payload_len);
+
+       /* now let's try deleting cookie 1 */
+
+       if (lws_cache_item_remove(l1, tag_cookie1))
+               goto cdone;
+
+       lws_cache_debug_dump(nsc);
+       lws_cache_debug_dump(l1);
+
+       /* with c1 gone, we should only get c3 */
+
+       lwsl_user("%s: wildcard lookup 5\n", __func__);
+
+       n = lws_cache_lookup(l1, "host.com|/|*",
+                            (const void **)&cr.ptr, &cr.size);
+       if (n) {
+               lwsl_err("%s: lookup failed %d\n", __func__, n);
+               goto cdone;
+       }
+
+       if (cr.size != 25)
+               goto cdone;
+
+       while (!lws_cache_results_walk(&cr))
+               lwsl_notice("  %s (%d)\n", (const char *)cr.tag,
+                                          (int)cr.payload_len);
+
+       /*
+        * let's add a fourth cookie (third in cache now we deleted one)
+        */
+
+       if (lws_cache_write_through(l1, tag_cookie4,
+                                   (const uint8_t *)cookie4, strlen(cookie4),
+                                   lws_now_usecs() + LWS_US_PER_SEC * 2, NULL)) {
+               lwsl_err("%s: write4 failed\n", __func__);
+               goto cdone;
+       }
+
+       /*
+        * for /yy and any cookie, we expect only c3
+        */
+
+       lwsl_user("%s: wildcard lookup 6\n", __func__);
+
+       n = lws_cache_lookup(l1, "host.com|/yy|*",
+                            (const void **)&cr.ptr, &cr.size);
+       if (n) {
+               lwsl_err("%s: lookup failed %d\n", __func__, n);
+               goto cdone;
+       }
+
+       if (cr.size != 25)
+               goto cdone;
+
+       while (!lws_cache_results_walk(&cr))
+               lwsl_notice("  %s (%d)\n", (const char *)cr.tag,
+                                          (int)cr.payload_len);
+
+       /*
+        * for /yyy and any cookie, we expect  c3 and c4
+        */
+
+       lwsl_user("%s: wildcard lookup 7\n", __func__);
+
+       n = lws_cache_lookup(l1, "host.com|/yyy|*",
+                            (const void **)&cr.ptr, &cr.size);
+       if (n) {
+               lwsl_err("%s: lookup failed %d\n", __func__, n);
+               goto cdone;
+       }
+
+       if (cr.size != 57)
+               goto cdone;
+
+       while (!lws_cache_results_walk(&cr))
+               lwsl_notice("  %s (%d)\n", (const char *)cr.tag,
+                                          (int)cr.payload_len);
+
+       /* that's ok then */
+
+       lwsl_user("%s: done\n", __func__);
+
+       ret = 0;
+
+cdone:
+       lws_cache_destroy(&nsc);
+       lws_cache_destroy(&l1);
+
+       if (ret)
+               lwsl_warn("%s: fail\n", __func__);
+
+       return ret;
+}
+#endif
+
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+
+       lwsl_user("LWS API selftest: lws_cache\n");
+
+       cx = lws_create_context(&info);
+       if (!cx) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       if (test_just_l1())
+               fail++;
+       if (test_just_l1_limits())
+               fail++;
+
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR)
+       if (test_nsc1())
+               fail++;
+#endif
+
+       lws_context_destroy(cx);
+
+       if (tests && !fail)
+               lwsl_user("Completed: PASS\n");
+       else
+               lwsl_err("Completed: FAIL %d / %d\n", fail, tests);
+
+       return 0;
+}
diff --git a/minimal-examples/api-tests/api-test-lws_cache/text1.txt b/minimal-examples/api-tests/api-test-lws_cache/text1.txt
new file mode 100644 (file)
index 0000000..c4079a2
--- /dev/null
@@ -0,0 +1,3 @@
+# Netscape HTTP Cookie File
+host.com       FALSE   /       FALSE   1234    mycookie        value
+host.com       FALSE   /xxx    FALSE   1234    mycookie        valuexxx
index 936d610..59d08cd 100644 (file)
@@ -1,66 +1,13 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-api-test-lws_dsh C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-api-test-lws_dsh)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_NETWORK 1 requirements)
 require_lws_config(LWS_WITH_LWS_DSH 1 requirements)
@@ -68,11 +15,12 @@ require_lws_config(LWS_WITH_LWS_DSH 1 requirements)
 if (requirements)
 
        add_executable(${SAMP} ${SRCS})
+       add_test(NAME api-test-lws_dsh COMMAND lws-api-test-lws_dsh)
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 8f92fd9..befd490 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-api-test-lws_dsh
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
@@ -12,7 +12,7 @@
 int
 test1(void)
 {
-       lws_dsh_t *dsh;
+       struct lws_dsh *dsh;
        size_t size;
        void *a1;
 
@@ -92,88 +92,9 @@ bail:
 }
 
 int
-test2(void)
-{
-       lws_dsh_t *dsh, *dsh2;
-       lws_dll2_owner_t owner;
-       uint8_t blob[4096];
-
-       memset(blob, 0, sizeof(blob));
-
-       /*
-        * test 2: multiple dsh, overflow allocation and dynamic destroy
-        */
-
-       lws_dll2_owner_clear(&owner);
-
-       dsh = lws_dsh_create(&owner, 4096, 2);
-       if (!dsh) {
-               lwsl_err("%s: Failed to create dsh1\n", __func__);
-
-               return 1;
-       }
-
-       dsh2 = lws_dsh_create(&owner, 4096, 2);
-       if (!dsh) {
-               lwsl_err("%s: Failed to create dsh2\n", __func__);
-
-               goto bail;
-       }
-
-       if (lws_dsh_alloc_tail(dsh, 0, blob, 4000, NULL, 0)) {
-               lwsl_err("%s: Failed to alloc 1\n", __func__);
-
-               goto bail2;
-       }
-
-       if (lws_dsh_alloc_tail(dsh2, 0, "hello", 5, NULL, 0)) {
-               lwsl_err("%s: Failed to alloc 2\n", __func__);
-
-               goto bail2;
-       }
-
-       /*
-        * We create this logically on dsh.  But there's no room for the body.
-        * It should figure out it can use space on dsh2.
-        */
-
-       if (lws_dsh_alloc_tail(dsh, 0, blob, 2000, NULL, 0)) {
-               lwsl_err("%s: Failed to alloc 3\n", __func__);
-
-               goto bail2;
-       }
-
-       if (lws_dsh_alloc_tail(dsh2, 0, "hello again", 11, NULL, 0)) {
-               lwsl_err("%s: Failed to alloc 4\n", __func__);
-
-               goto bail2;
-       }
-
-       /*
-        * When we destroy dsh2 it will try to migrate out the 2000 allocation
-        * from there but find there is no space in dsh1.  It should handle it
-        * by logicalling dropping the object.
-        */
-
-       lws_dsh_destroy(&dsh2);
-       lws_dsh_destroy(&dsh);
-
-       return 0;
-
-bail2:
-       lws_dsh_destroy(&dsh2);
-
-bail:
-       lws_dsh_destroy(&dsh);
-
-       return 1;
-
-}
-
-int
 test3(void)
 {
-       lws_dsh_t *dsh, *dsh2;
+       struct lws_dsh *dsh, *dsh2;
        lws_dll2_owner_t owner;
        uint8_t blob[4096];
 
@@ -193,7 +114,7 @@ test3(void)
        }
 
        dsh2 = lws_dsh_create(&owner, 4096, 2);
-       if (!dsh) {
+       if (!dsh2) {
                lwsl_err("%s: Failed to create dsh2\n", __func__);
 
                goto bail;
@@ -245,14 +166,14 @@ int
 test4(void)
 {
        uint8_t blob[4096];
-       lws_dsh_t *dsh;
+       struct lws_dsh *dsh;
        size_t size;
        void *a1;
 
        memset(blob, 0, sizeof(blob));
 
        /*
-        * test 1: use up whole free list, then recover and alloc something
+        * test 4: use up whole free list, then recover and alloc something
         *         else
         */
 
@@ -327,6 +248,94 @@ bail:
        return 1;
 }
 
+int
+test5(void)
+{
+       struct lws_dsh *dsh;
+       unsigned int budget;
+       uint8_t blob[4096];
+       lws_xos_t xos;
+       size_t size;
+       void *a1;
+
+       memset(blob, 0, sizeof(blob));
+       lws_xos_init(&xos, 0x123456789abcdef0ull);
+
+       budget = (unsigned int)(lws_xos(&xos) % 4000) + 4000;
+
+       lwsl_notice("%s: budget %u\n", __func__, budget);
+
+
+       /*
+        * test 5: PRNG-based spamming and erratic bidi draining
+        */
+
+       dsh = lws_dsh_create(NULL, 409600, 2);
+       if (!dsh) {
+               lwsl_err("%s: Failed to create dsh\n", __func__);
+
+               return 1;
+       }
+
+       do {
+
+               if (lws_xos_percent(&xos, 60)) {
+                       /* kind 0 is going to try to write */
+
+                       size = (size_t)((lws_xos(&xos) & 127) + 1);
+
+                       if (!lws_dsh_alloc_tail(dsh, 0, blob, size, NULL, 0))
+                               lwsl_notice("%s: kind 0 alloc %d\n", __func__, (int)size);
+               }
+
+               if (lws_xos_percent(&xos, 80)) {
+                       /* kind 1 is going to try to write */
+
+                       size = (size_t)((lws_xos(&xos) & 127) + 1);
+
+                       if (!lws_dsh_alloc_tail(dsh, 1, blob, size, NULL, 0))
+                               lwsl_notice("%s: kind 1 alloc %d\n", __func__, (int)size);
+               }
+
+               if (lws_xos_percent(&xos, 40)) {
+                       /* kind 0 is going to try to read */
+
+                       while (!lws_dsh_get_head(dsh, 0, &a1, &size)) {
+                               lwsl_notice("%s: kind 0 read %d\n", __func__, (int)size);
+                               lws_dsh_free(&a1);
+                       }
+               }
+
+               if (lws_xos_percent(&xos, 30)) {
+                       /* kind 1 is going to try to read */
+
+                       while (!lws_dsh_get_head(dsh, 1, &a1, &size)) {
+                               lwsl_notice("%s: kind 1 read %d\n", __func__, (int)size);
+                               lws_dsh_free(&a1);
+                       }
+               }
+
+       } while (budget--);
+
+       while (!lws_dsh_get_head(dsh, 0, &a1, &size)) {
+               lwsl_notice("%s: kind 0 read %d\n", __func__, (int)size);
+               lws_dsh_free(&a1);
+       }
+
+       while (!lws_dsh_get_head(dsh, 1, &a1, &size)) {
+               lwsl_notice("%s: kind 1 read %d\n", __func__, (int)size);
+               lws_dsh_free(&a1);
+       }
+
+#if defined(_DEBUG)
+       lws_dsh_describe(dsh, "test dsh end state");
+#endif
+
+       lws_dsh_destroy(&dsh);
+
+       return 0;
+}
+
 int main(int argc, const char **argv)
 {
        int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
@@ -343,10 +352,6 @@ int main(int argc, const char **argv)
        lwsl_user("%s: test1: %d\n", __func__, n);
        ret |= n;
 
-       n = test2();
-       lwsl_user("%s: test2: %d\n", __func__, n);
-       ret |= n;
-
        n = test3();
        lwsl_user("%s: test3: %d\n", __func__, n);
        ret |= n;
@@ -355,6 +360,10 @@ int main(int argc, const char **argv)
        lwsl_user("%s: test4: %d\n", __func__, n);
        ret |= n;
 
+       n = test5();
+       lwsl_user("%s: test5: %d\n", __func__, n);
+       ret |= n;
+
        lwsl_user("Completed: %s\n", ret ? "FAIL" : "PASS");
 
        return ret;
diff --git a/minimal-examples/api-tests/api-test-lws_dsh/selftest.sh b/minimal-examples/api-tests/api-test-lws_dsh/selftest.sh
deleted file mode 100755 (executable)
index 16d1e2e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=1
-
-dotest $1 $2 apiselftest
-exit $FAILS
diff --git a/minimal-examples/api-tests/api-test-lws_map/CMakeLists.txt b/minimal-examples/api-tests/api-test-lws_map/CMakeLists.txt
new file mode 100644 (file)
index 0000000..897042c
--- /dev/null
@@ -0,0 +1,17 @@
+project(lws-api-test-lws_map C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+
+
+       add_executable(${PROJECT_NAME} main.c)
+       add_test(NAME api-test-lws_map COMMAND lws-api-test-lws_map)
+
+       if (websockets_shared)
+               target_link_libraries(${PROJECT_NAME} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${PROJECT_NAME} websockets_shared)
+       else()
+               target_link_libraries(${PROJECT_NAME} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
diff --git a/minimal-examples/api-tests/api-test-lws_map/main.c b/minimal-examples/api-tests/api-test-lws_map/main.c
new file mode 100644 (file)
index 0000000..022c98a
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * lws-api-test-lws_map
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * unit tests for lws_map
+ */
+
+#include <libwebsockets.h>
+
+/* custom key and comparator for test 3 */
+
+typedef struct mykey {
+       int                     key;
+} mykey_t;
+
+static int
+compare_mykey_t(const lws_map_key_t key1, size_t kl1,
+               const lws_map_value_t key2, size_t kl2)
+{
+       const mykey_t *m1 = (mykey_t *)key1, *m2 = (mykey_t *)key2;
+
+       return m1->key != m2->key;
+}
+
+int main(int argc, const char **argv)
+{
+       int e = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE,
+                       expected = 4, pass = 0;
+       mykey_t k1 = { .key = 123 }, k2 = { .key = 234 }, k3 = { .key = 999 };
+       struct lwsac *ac = NULL;
+       lws_map_item_t *item;
+       lws_map_info_t info;
+       lws_map_t *map;
+       const char *p;
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS API selftest: lws_map\n");
+
+       /* Test 1: string keys */
+
+       lwsl_user("%s: test1\n", __func__);
+       memset(&info, 0, sizeof(info));
+       map = lws_map_create(&info);
+       if (!map) {
+               e++;
+               goto end_t1;
+       }
+       if (!lws_map_item_create_ks(map, "abc", (lws_map_value_t)"def", 3)) {
+               e++;
+               goto end_t1;
+       }
+       if (!lws_map_item_create_ks(map, "123", (lws_map_value_t)"4567", 4)) {
+               e++;
+               goto end_t1;
+       }
+       item = lws_map_item_lookup_ks(map, "abc");
+       if (!item) {
+               e++;
+               goto end_t1;
+       }
+
+       if (lws_map_item_value_len(item) != 3 ||
+           memcmp(lws_map_item_value(item), "def", 3)) {
+               e++;
+               goto end_t1;
+       }
+
+       item = lws_map_item_lookup_ks(map, "123");
+       if (!item) {
+               e++;
+               goto end_t1;
+       }
+
+       if (lws_map_item_value_len(item) != 4 ||
+           memcmp(lws_map_item_value(item), "4567", 4)) {
+               e++;
+               goto end_t1;
+       }
+
+       item = lws_map_item_lookup_ks(map, "nope");
+       if (item) {
+               e++;
+               goto end_t1;
+       }
+
+       pass++;
+
+end_t1:
+       lws_map_destroy(&map);
+
+       /* Test 2: Use lwsac item allocators */
+
+       lwsl_user("%s: test2\n", __func__);
+       memset(&info, 0, sizeof(info));
+       info._alloc = lws_map_alloc_lwsac;
+       info._free = lws_map_free_lwsac;
+       info.opaque = (void *)&ac;
+
+       map = lws_map_create(&info);
+       if (!map) {
+               e++;
+               goto end_t2;
+       }
+       if (!lws_map_item_create_ks(map, "abc", "def", 3)) {
+               e++;
+               goto end_t2;
+       }
+       if (!lws_map_item_create_ks(map, "123", "4567", 4)) {
+               e++;
+               goto end_t2;
+       }
+       item = lws_map_item_lookup_ks(map, "abc");
+       if (!item) {
+               e++;
+               goto end_t2;
+       }
+
+       if (lws_map_item_value_len(item) != 3 ||
+           memcmp(lws_map_item_value(item), "def", 3)) {
+               e++;
+               goto end_t2;
+       }
+
+       item = lws_map_item_lookup_ks(map, "123");
+       if (!item) {
+               e++;
+               goto end_t2;
+       }
+
+       if (lws_map_item_value_len(item) != 4 ||
+           memcmp(lws_map_item_value(item), "4567", 4)) {
+               e++;
+               goto end_t2;
+       }
+
+       item = lws_map_item_lookup_ks(map, "nope");
+       if (item) {
+               e++;
+               goto end_t2;
+       }
+
+       pass++;
+
+end_t2:
+       lws_map_destroy(&map);
+       lwsac_free(&ac);
+
+       /* Test 3: custom key object and comparator */
+
+       lwsl_user("%s: test3\n", __func__);
+       memset(&info, 0, sizeof(info));
+       info._compare = compare_mykey_t;
+
+       map = lws_map_create(&info);
+       if (!map) {
+               e++;
+               goto end_t3;
+       }
+       if (!lws_map_item_create(map, (lws_map_key_t)&k1, sizeof(k1),
+                                     (lws_map_value_t)"def", 3)) {
+               lwsl_err("%s: t3; a\n", __func__);
+               e++;
+               goto end_t3;
+       }
+       if (!lws_map_item_create(map, (lws_map_key_t)&k2, sizeof(k2),
+                                     (lws_map_value_t)"4567", 4)) {
+               lwsl_err("%s: t3; b\n", __func__);
+               e++;
+               goto end_t3;
+       }
+       item = lws_map_item_lookup(map, (lws_map_key_t)&k1, sizeof(k1));
+       if (!item) {
+               lwsl_err("%s: t3; c\n", __func__);
+               e++;
+               goto end_t3;
+       }
+
+       if (lws_map_item_value_len(item) != 3 ||
+           memcmp(lws_map_item_value(item), "def", 3)) {
+               lwsl_err("%s: t3; d\n", __func__);
+               e++;
+               goto end_t3;
+       }
+
+       item = lws_map_item_lookup(map, (lws_map_key_t)&k2, sizeof(k2));
+       if (!item) {
+               lwsl_err("%s: t3; e\n", __func__);
+               e++;
+               goto end_t3;
+       }
+
+       if (lws_map_item_value_len(item) != 4 ||
+           memcmp(lws_map_item_value(item), "4567", 4)) {
+               lwsl_err("%s: t3; f\n", __func__);
+               e++;
+               goto end_t3;
+       }
+
+       item = lws_map_item_lookup(map, (lws_map_key_t)&k3, sizeof(k3));
+       if (item) {
+               lwsl_err("%s: t3; g\n", __func__);
+               e++;
+               goto end_t3;
+       }
+
+       pass++;
+
+end_t3:
+       lws_map_destroy(&map);
+
+       /* Test 4: same key items */
+
+       lwsl_user("%s: test4\n", __func__);
+       memset(&info, 0, sizeof(info));
+       map = lws_map_create(&info);
+       if (!map) {
+               e++;
+               goto end_t4;
+       }
+       if (!lws_map_item_create_ks(map, "abc", (lws_map_value_t)"def", 3)) {
+               e++;
+               goto end_t4;
+       }
+       if (!lws_map_item_create_ks(map, "abc", (lws_map_value_t)"4567", 4)) {
+               e++;
+               goto end_t4;
+       }
+       item = lws_map_item_lookup_ks(map, "abc");
+       if (!item) {
+               e++;
+               goto end_t4;
+       }
+
+       if (lws_map_item_value_len(item) != 4 ||
+           memcmp(lws_map_item_value(item), "4567", 4)) {
+               e++;
+               goto end_t4;
+       }
+
+       pass++;
+
+end_t4:
+       lws_map_destroy(&map);
+
+       if (e)
+               goto bail;
+
+       lwsl_user("Completed: PASS %d / %d\n", pass, expected);
+
+       return 0;
+
+bail:
+       lwsl_user("Completed: FAIL, passed %d / %d (e %d)\n", pass,
+                               expected, e);
+
+       return 1;
+}
index 1d24090..59333d8 100644 (file)
@@ -1,78 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-api-test-lws_sequencer C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-api-test-lws_sequencer)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 require_lws_config(LWS_WITH_SEQUENCER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 4a9fb35..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFWjCCBEKgAwIBAgISA9x0/oj5PLdW46hsmR82/7ytMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5NDBaFw0x
-OTEyMDYwNzA5NDBaMBwxGjAYBgNVBAMTEWxpYndlYnNvY2tldHMub3JnMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPinIkleLmvEcA/YuBss6ASXVi7g
-yr6Sss7cB3vTy7Fp8OB2c1N25prHZxVpORAUo0UreiaY2Ws4NFvDaYp08ZffevuC
-UhThsEJlbkD0uvt7dPapJt9PNJtlxjNFWyvHEy6PijzIaMYDROiStcCJQn7kAew/
-Za2+5kNVgKqT+7OXukJEFdSdVZI6QC/npeQlkIrFSq1WVthCGBNJehxxES0hSWzk
-0gNVKlkD3/SbkupsfUpe73XiawMtrtsSE7cdnul7VZmiP8I/3sJr1+4/3xZ+DEYg
-mVB82B0vd08VJYzU7Nf0pz0PWusAmzRoRn81IXkOfBg9ohlSSEoZhHYS7QIDAQAB
-o4ICZjCCAmIwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
-BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRmKKyGjufWgp7pR2x0tWxG
-D9G+WTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcB
-AQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlw
-dC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlw
-dC5vcmcvMBwGA1UdEQQVMBOCEWxpYndlYnNvY2tldHMub3JnMEwGA1UdIARFMEMw
-CAYGZ4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9j
-cHMubGV0c2VuY3J5cHQub3JnMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcAdH7a
-gzGtMxCRIZzOJU9CcMK//V5CIAjGNzV55hB7zFYAAAFtCsWIfgAABAMASDBGAiEA
-0H55VqSKV3otHK7uHNbcR0QwoUYtCmeObhsqxzCnmDwCIQD3mtuSKrxTD3oA+Yde
-nmTgWfFyS4TNgLNEPCJYo2s75gB1ACk8UZZUyDlluqpQ/FgH1Ldvv1h6KXLcpMMM
-9OVFR/R4AAABbQrFil4AAAQDAEYwRAIgNSpvz/1JA2aP6fh6ujGNuYfrAvWjlxXo
-CJtVGe4XaDYCIGmK1/9tl1uQbVD46P5NswnULq06KQmuOrlI3HO4r86HMA0GCSqG
-SIb3DQEBCwUAA4IBAQBiAlV7wkCsWE99VmZHBmcbZChWyWUHG3LM1hnaQRQjTSYk
-CIlauCpWzlUd6weuvra85KqBbCYo+1hxbwITI796uAdgtHmBE8nj0VltHwKeSq2s
-KKiGXBRT7Z7t0VHYSLOlGOVn1auuQFaWBArc0cQ/m1ZsoHvOiHTlKQvVsA4HnIxA
-CjGY9OOQoh0c36ecbJZ44XKnU9J/OXtDx00aW6QodaZmgMp/OOCghFQUvufkgTUL
-LZid873/8dJVWjAaj1VdadO1nSbdAfBbeWXy93+vg1aAoig80RoscrzYCaNlwmR7
-EO5zWxL3l+xUZogQSJuICgUgNzVB3wjn8HeHGsqt
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
index a84aa7e..0db7f40 100644 (file)
@@ -90,7 +90,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
        case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
                if (!s)
                        return 1;
-               s->http_resp = lws_http_client_http_response(wsi);
+               s->http_resp = (int)lws_http_client_http_response(wsi);
                lwsl_info("Connected with server response: %d\n", s->http_resp);
                break;
 
@@ -169,8 +169,8 @@ notify:
 }
 
 static const struct lws_protocols protocols[] = {
-       { "seq-test-http", callback_http, 0, 0, },
-       { NULL, NULL, 0, 0 }
+       { "seq-test-http", callback_http, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 
@@ -218,7 +218,7 @@ sequencer_start_client(struct myseq *s)
                /* we couldn't even get started with the client connection */
 
                lws_seq_queue_event(lws_seq_from_user(s),
-                                   SEQ_MSG_CLIENT_FAILED, NULL, NULL);
+                                   (lws_seq_events_t)SEQ_MSG_CLIENT_FAILED, NULL, NULL);
 
                return 1;
        }
@@ -324,7 +324,7 @@ main(int argc, const char **argv)
        int n = 1, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
        struct lws_context_creation_info info;
        struct lws_context *context;
-       lws_seq_t *seq;
+       struct lws_sequencer *seq;
        struct lws_vhost *vh;
        lws_seq_info_t i;
        struct myseq *s;
@@ -346,7 +346,7 @@ main(int argc, const char **argv)
                       LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
        info.protocols = protocols;
 
-#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
        /*
         * OpenSSL uses the system trust store.  mbedTLS has to be told which
         * CA to trust explicitly.
diff --git a/minimal-examples/api-tests/api-test-lws_smd/CMakeLists.txt b/minimal-examples/api-tests/api-test-lws_smd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e282706
--- /dev/null
@@ -0,0 +1,28 @@
+project(lws-api-test-lws_smd C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(requirements 1)
+require_pthreads(requirements)
+require_lws_config(LWS_WITH_SYS_SMD 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${PROJECT_NAME} main.c)
+       add_test(NAME api-test-lws_smd COMMAND lws-api-test-lws_smd -d1151)
+       set_tests_properties(api-test-lws_smd
+                            PROPERTIES
+                            RUN_SERIAL TRUE
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/api-tests/api-test-lws_smd
+                            TIMEOUT 60)
+
+       if (websockets_shared)
+               target_link_libraries(${PROJECT_NAME} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${PROJECT_NAME} websockets_shared)
+       else()
+               target_link_libraries(${PROJECT_NAME} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/api-tests/api-test-lws_smd/main.c b/minimal-examples/api-tests/api-test-lws_smd/main.c
new file mode 100644 (file)
index 0000000..b3f8bd5
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * lws-api-test-lws_smd
+ *
+ * Written in 2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This api test confirms lws_smd System Message Distribution
+ */
+
+#include <libwebsockets.h>
+#define HAVE_STRUCT_TIMESPEC
+#include <pthread.h>
+#include <signal.h>
+
+static int interrupted, ok, fail, _exp = 111;
+static unsigned int how_many_msg = 100, usec_interval = 1000;
+static lws_sorted_usec_list_t sul, sul_initial_drain;
+struct lws_context *context;
+static pthread_t thread_spam;
+
+static void
+timeout_cb(lws_sorted_usec_list_t *sul)
+{
+       /* We should have completed the test before this fires */
+       lwsl_notice("%s: test period finished\n", __func__);
+       interrupted = 1;
+       lws_cancel_service(context);
+}
+
+static int
+smd_cb1int(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
+          void *buf, size_t len)
+{
+#if 0
+       lwsl_notice("%s: ts %llu, len %d\n", __func__,
+                   (unsigned long long)timestamp, (int)len);
+       lwsl_hexdump_notice(buf, len);
+#endif
+       ok++;
+
+       return 0;
+}
+
+static int
+smd_cb2int(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
+          void *buf, size_t len)
+{
+#if 0
+       lwsl_notice("%s: ts %llu, len %d\n", __func__,
+                   (unsigned long long)timestamp, (int)len);
+       lwsl_hexdump_notice(buf, len);
+#endif
+       ok++;
+
+       return 0;
+}
+
+/*
+ * This is used in an smd participant that is deregistered before the message
+ * can be delivered, it should never see any message
+ */
+
+static int
+smd_cb3int(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
+          void *buf, size_t len)
+{
+       lwsl_err("%s: Countermanded ts %llu, len %d\n", __func__,
+                   (unsigned long long)timestamp, (int)len);
+       lwsl_hexdump_err(buf, len);
+
+       fail++;
+
+       return 0;
+}
+
+static void *
+_thread_spam(void *d)
+{
+#if defined(WIN32)
+       unsigned int mypid = 0;
+#else
+       unsigned int mypid = (unsigned int)getpid();
+#endif
+       unsigned int n = 0, atm = 0;
+
+       while (n++ < how_many_msg) {
+
+               atm++;
+               if (lws_smd_msg_printf(context, LWSSMDCL_SYSTEM_STATE,
+                                              "{\"s\":\"state\","
+                                               "\"pid\":%u,"
+                                               "\"msg\":%d}",
+                                              mypid, (unsigned int)n)) {
+                       lwsl_err("%s: send attempt %d failed\n", __func__, atm);
+                       n--;
+                       fail++;
+                       if (fail >= 3) {
+                               interrupted = 1;
+                               lws_cancel_service(context);
+                               break;
+                       }
+               }
+#if defined(WIN32)
+               Sleep(3);
+#else
+               usleep(usec_interval);
+#endif
+       }
+#if !defined(WIN32)
+       pthread_exit(NULL);
+#endif
+
+       return NULL;
+}
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static void
+drained_cb(lws_sorted_usec_list_t *sul)
+{
+       /*
+        * spawn the test thread, it's going to spam 100 messages at 3ms
+        * intervals... check we got everything
+        */
+
+       if (pthread_create(&thread_spam, NULL, _thread_spam, NULL))
+               lwsl_err("%s: failed to create the spamming thread\n", __func__);
+}
+
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                  int current, int target)
+{
+       // struct lws_context *context = mgr->parent;
+       int n;
+
+       if (current != LWS_SYSTATE_OPERATIONAL || target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       /*
+        * Overflow the message queue too see if it handles it well, both
+        * as overflowing and in recovery.  These are all still going into the
+        * smd buffer dll2, since we don't break for the event loop to have a
+        * chance to deliver them.
+        */
+
+       n = 0;
+       while (n++ < 100)
+               if (lws_smd_msg_printf(context, LWSSMDCL_SYSTEM_STATE,
+                                      "{\"s\":\"state\",\"test\":\"overflow\"}"))
+                       break;
+
+       lwsl_notice("%s: overflow test added %d messages\n", __func__, n);
+       if (n == 100) {
+               lwsl_err("%s: didn't overflow\n", __func__);
+               interrupted = 1;
+               return 1;
+       }
+
+       /*
+        * So we have some normal messages from earlier and now the rest of the
+        * smd buffer filled with junk overflow messages.  Before we start the
+        * actual spamming test from another thread, we need to return to the
+        * event loop so these can be cleared first.
+        */
+
+       lws_sul_schedule(context, 0, &sul_initial_drain, drained_cb,
+                        5 * LWS_US_PER_MS);
+
+
+       lwsl_info("%s: operational\n", __func__);
+
+       return 0;
+}
+
+int
+main(int argc, const char **argv)
+{
+       lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
+                                               system_notify_cb, "app" };
+       lws_state_notify_link_t *na[] = { &notifier, NULL };
+       int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       struct lws_context_creation_info info;
+       struct lws_smd_peer *userreg;
+       const char *p;
+       void *retval;
+
+       /* the normal lws init */
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       if ((p = lws_cmdline_option(argc, argv, "--count")))
+               how_many_msg = (unsigned int)atol(p);
+
+       if ((p = lws_cmdline_option(argc, argv, "--interval")))
+               usec_interval = (unsigned int)atol(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS API selftest: lws_smd: %u msgs at %uus interval\n",
+                       how_many_msg, usec_interval);
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.register_notifier_list = na;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* game over after this long */
+
+       lws_sul_schedule(context, 0, &sul, timeout_cb,
+                        (how_many_msg * (usec_interval + 1000)) + (4 * LWS_US_PER_SEC));
+
+       /* register a messaging participant to hear INTERACTION class */
+
+       if (!lws_smd_register(context, NULL, 0, LWSSMDCL_INTERACTION,
+                             smd_cb1int)) {
+               lwsl_err("%s: smd register 1 failed\n", __func__);
+               goto bail;
+       }
+
+       /* register a messaging participant to hear SYSTEM_STATE class */
+
+       if (!lws_smd_register(context, NULL, 0, LWSSMDCL_SYSTEM_STATE,
+                             smd_cb2int)) {
+               lwsl_err("%s: smd register 2 failed\n", __func__);
+               goto bail;
+       }
+
+       /* temporarily register a messaging participant to hear a user class */
+
+       userreg = lws_smd_register(context, NULL, 0, 1 << LWSSMDCL_USER_BASE_BITNUM,
+                             smd_cb3int);
+       if (!userreg) {
+               lwsl_err("%s: smd register userclass failed\n", __func__);
+               goto bail;
+       }
+
+       /*
+        * The event loop isn't started yet, so these smd messages are getting
+        * buffered.  Later we will deliberately overrun the buffer and wait
+        * for that to be cleared before the spam thread test.
+        */
+
+       /* generate an INTERACTION class message */
+
+       if (lws_smd_msg_printf(context, LWSSMDCL_INTERACTION,
+                              "{\"s\":\"interaction\"}")) {
+               lwsl_err("%s: problem sending smd\n", __func__);
+               goto bail;
+       }
+
+       /* generate a SYSTEM_STATE class message */
+
+       if (lws_smd_msg_printf(context, LWSSMDCL_SYSTEM_STATE,
+                              "{\"s\":\"state\"}")) {
+               lwsl_err("%s: problem sending smd\n", __func__);
+               goto bail;
+       }
+
+       /* no participant listens for this class, so it should be skipped */
+
+       if (lws_smd_msg_printf(context, LWSSMDCL_NETWORK, "{\"s\":\"network\"}")) {
+               lwsl_err("%s: problem sending smd\n", __func__);
+               goto bail;
+       }
+
+       /* generate a user class message... */
+
+       if (lws_smd_msg_printf(context, 1 << LWSSMDCL_USER_BASE_BITNUM,
+                              "{\"s\":\"userclass\"}")) {
+               lwsl_err("%s: problem sending smd\n", __func__);
+               goto bail;
+       }
+
+       /*
+        * ... and screw that user class message up by deregistering the only
+        * handler before it can deliver it... it should not get delivered
+        * and cleanly discarded
+        */
+
+       lws_smd_unregister(userreg);
+
+       /* the usual lws event loop */
+
+       while (!interrupted && lws_service(context, 0) >= 0)
+               ;
+
+       pthread_join(thread_spam, &retval);
+
+bail:
+       lws_context_destroy(context);
+
+       if (fail || ok >= _exp)
+               lwsl_user("Completed: PASS: %d / %d, FAIL: %d\n", ok, _exp,
+                               fail);
+       else
+               lwsl_user("Completed: ALL PASS: %d / %d\n", ok, _exp);
+
+       return !(ok >= _exp && !fail);
+}
index 07ab387..9068028 100644 (file)
@@ -1,77 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-api-test-lws_struct-json C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-api-test-lws_struct-json)
-set(SRCS main.c)
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
+set(SRCS main.c test2.c)
 
 set(requirements 1)
 require_lws_config(LWS_WITH_STRUCT_JSON 1 requirements)
 
 if (requirements)
+
        add_executable(${SAMP} ${SRCS})
+       add_test(NAME api-test-lws_struct-json COMMAND lws-api-test-lws_struct-json)
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
-
index ebe930d..f21ba78 100644 (file)
@@ -17,40 +17,92 @@ Commandline option|Meaning
 
 ```
  $ ./lws-api-test-lws_struct-json
-[2019/03/30 22:09:09:2529] USER: LWS API selftest: lws_struct JSON
-[2019/03/30 22:09:09:2625] NOTICE: main: ++++++++++++++++ test 1
-[2019/03/30 22:09:09:2812] NOTICE: builder.hostname = 'learn', timeout = 1800, targets (2)
-[2019/03/30 22:09:09:2822] NOTICE:     target.name 'target1' (target 0x543a830)
-[2019/03/30 22:09:09:2824] NOTICE:     target.name 'target2' (target 0x543a860)
-[2019/03/30 22:09:09:2826] NOTICE: main:    .... strarting serialization of test 1
-[2019/03/30 22:09:09:2899] NOTICE: ser says 1
-{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800,"targets":[{"name":"target1"},{"name":"target2"}]}
-[2019/03/30 22:09:09:2929] NOTICE: main: ++++++++++++++++ test 2
-[2019/03/30 22:09:09:2932] NOTICE: builder.hostname = 'learn', timeout = 0, targets (3)
-[2019/03/30 22:09:09:2932] NOTICE:     target.name 'target1' (target 0x543b060)
-[2019/03/30 22:09:09:2933] NOTICE:     target.name 'target2' (target 0x543b090)
-[2019/03/30 22:09:09:2933] NOTICE:     target.name 'target3' (target 0x543b0c0)
-[2019/03/30 22:09:09:2934] NOTICE: main:    .... strarting serialization of test 2
-[2019/03/30 22:09:09:2935] NOTICE: ser says 1
-{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":0,"targets":[{"name":"target1"},{"name":"target2"},{"name":"target3"}]}
-[2019/03/30 22:09:09:2940] NOTICE: main: ++++++++++++++++ test 3
-[2019/03/30 22:09:09:2959] NOTICE: builder.hostname = 'learn', timeout = 1800, targets (2)
-[2019/03/30 22:09:09:2960] NOTICE:     target.name 'target1' (target 0x543b450)
-[2019/03/30 22:09:09:2961] NOTICE:       child 0x543b480, target.child.somename 'abc'
-[2019/03/30 22:09:09:2961] NOTICE:     target.name 'target2' (target 0x543b490)
-[2019/03/30 22:09:09:2962] NOTICE: main:    .... strarting serialization of test 3
-[2019/03/30 22:09:09:2969] NOTICE: ser says 1
-{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800,"targets":[{"name":"target1","child":{"somename":"abc"}},{"name":"target2"}]}
-[2019/03/30 22:09:09:2970] NOTICE: main: ++++++++++++++++ test 4
-[2019/03/30 22:09:09:2971] NOTICE: builder.hostname = 'learn', timeout = 1800, targets (0)
-[2019/03/30 22:09:09:2971] NOTICE: main:    .... strarting serialization of test 4
-[2019/03/30 22:09:09:2973] NOTICE: ser says 1
+[2020/05/21 16:36:57:0808] U: LWS API selftest: lws_struct JSON
+[2020/05/21 16:36:57:1188] N: main: ++++++++++++++++ test 1
+[2020/05/21 16:36:57:1291] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1387] N: lws_struct_default_lejp_cb: created 'targets' object size 48
+[2020/05/21 16:36:57:1429] N: lws_struct_default_lejp_cb: created 'targets' object size 48
+[2020/05/21 16:36:57:1467] N: builder.hostname = 'learn', timeout = 1800, targets (2)
+[2020/05/21 16:36:57:1490] N:     target.name 'target1' (target 0x509fe30)
+[2020/05/21 16:36:57:1495] N:     target.name 'target2' (target 0x509fe68)
+[2020/05/21 16:36:57:1500] N: main:    .... strarting serialization of test 1
+{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800,"targets":[{"name":"target1","someflag":true},{"name":"target2","someflag":false}]}
+[2020/05/21 16:36:57:1648] N: main: ++++++++++++++++ test 2
+[2020/05/21 16:36:57:1649] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1650] N: lws_struct_default_lejp_cb: created 'targets' object size 48
+[2020/05/21 16:36:57:1651] N: lws_struct_default_lejp_cb: created 'targets' object size 48
+[2020/05/21 16:36:57:1652] N: lws_struct_default_lejp_cb: created 'targets' object size 48
+[2020/05/21 16:36:57:1653] N: builder.hostname = 'learn', timeout = 0, targets (3)
+[2020/05/21 16:36:57:1653] N:     target.name 'target1' (target 0x50a0660)
+[2020/05/21 16:36:57:1654] N:     target.name 'target2' (target 0x50a0698)
+[2020/05/21 16:36:57:1655] N:     target.name 'target3' (target 0x50a06d0)
+[2020/05/21 16:36:57:1655] N: main:    .... strarting serialization of test 2
+{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":0,"targets":[{"name":"target1","someflag":false},{"name":"target2","someflag":false},{"name":"target3","someflag":false}]}
+[2020/05/21 16:36:57:1662] N: main: ++++++++++++++++ test 3
+[2020/05/21 16:36:57:1663] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1664] N: lws_struct_default_lejp_cb: created 'targets' object size 48
+[2020/05/21 16:36:57:1671] N: lws_struct_default_lejp_cb: created 'child' object size 8
+[2020/05/21 16:36:57:1685] N: lws_struct_default_lejp_cb: created 'targets' object size 48
+[2020/05/21 16:36:57:1685] N: builder.hostname = 'learn', timeout = 1800, targets (2)
+[2020/05/21 16:36:57:1686] N:     target.name 'target1' (target 0x50a0a50)
+[2020/05/21 16:36:57:1687] N:       child 0x50a0a88, target.child.somename 'abc'
+[2020/05/21 16:36:57:1688] N:     target.name 'target2' (target 0x50a0a98)
+[2020/05/21 16:36:57:1688] N: main:    .... strarting serialization of test 3
+{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800,"targets":[{"name":"target1","someflag":false,"child":{"somename":"abc"}},{"name":"target2","someflag":false}]}
+[2020/05/21 16:36:57:1697] N: main: ++++++++++++++++ test 4
+[2020/05/21 16:36:57:1698] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1699] N: builder.hostname = 'learn', timeout = 1800, targets (0)
+[2020/05/21 16:36:57:1699] N: main:    .... strarting serialization of test 4
 {"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800}
-[2019/03/30 22:09:09:2974] NOTICE: main: ++++++++++++++++ test 5
-[2019/03/30 22:09:09:2978] NOTICE: builder.hostname = '', timeout = 0, targets (0)
-[2019/03/30 22:09:09:2979] NOTICE: main:    .... strarting serialization of test 5
-[2019/03/30 22:09:09:2980] NOTICE: ser says 1
+[2020/05/21 16:36:57:1701] N: main: ++++++++++++++++ test 5
+[2020/05/21 16:36:57:1702] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1707] N: builder.hostname = '', timeout = 0, targets (0)
+[2020/05/21 16:36:57:1708] N: main:    .... strarting serialization of test 5
 {"schema":"com-warmcat-sai-builder","hostname":"","nspawn_timeout":0}
-[2019/03/30 22:09:09:2982] USER: Completed: PASS
+[2020/05/21 16:36:57:1709] N: main: ++++++++++++++++ test 6
+[2020/05/21 16:36:57:1710] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1730] N: builder.hostname = 'PYvtan6kqppjnS0KpYTCaiOLsJkc7Xe', timeout = 0, targets (0)
+[2020/05/21 16:36:57:1731] N: main:    .... strarting serialization of test 6
+{"schema":"com-warmcat-sai-builder","hostname":"PYvtan6kqppjnS0KpYTCaiOLsJkc7Xe","nspawn_timeout":0}
+[2020/05/21 16:36:57:1732] N: main: ++++++++++++++++ test 7
+[2020/05/21 16:36:57:1732] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1733] N: lws_struct_default_lejp_cb: created 'targets' object size 48
+[2020/05/21 16:36:57:1739] N: builder.hostname = '', timeout = 0, targets (1)
+[2020/05/21 16:36:57:1751] N:     target.name 'PYvtan6kqppjnS0KpYTCaiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6AzefzoWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9D1QKIWqg5RJ/CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6bzhA+A/xAsFzSBnb3MHYWzGMprr53FAP1ISo5Ec9i+2ehV40sG6Q470sH3PGQZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV8sq3ZgcxKNB7tNfN7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEhdZgxky2+g5hhlSIGJYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/RrfOV+oV4R26IDq+KqUiJBENeo8/GXkGLUH/87iPyzXKEMavr6fkrK0vTGto8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MWv+B/t1eZZ+1euLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZvstK9eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6O/grHnvJZm2vBkxuXgsYVkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0WaCqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/uZjjEGGLhJR1jPqA9D1Ej3ChV+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yuyJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx+z3f+jTFM/aon5...
+[2020/05/21 16:36:57:1752] N: main:    .... strarting serialization of test 7
+{"schema":"com-warmcat-sai-builder","hostname":"","nspawn_timeout":0,"targets":[{"name":"PYvtan6kqppjnS0KpYTCaiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6AzefzoWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9D1QKIWqg5RJ/CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6bzhA+A/xAsFzSBnb3MHYWzGMprr53FAP1ISo5Ec9i+2ehV40sG6Q470sH3PGQZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV8sq3ZgcxKNB7tNfN7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEhdZgxky2+g5hhlSIGJYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/RrfOV+oV4R26IDq+KqUiJBENeo8/GXkGLUH/87iPyzXKEMavr6fkrK0vTGto8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MWv+B/t1eZZ+1euLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZvstK9eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6O/grHnvJZm2vBkxuXgsYVkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0WaCqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/uZjjEGGLhJR1jPqA9D1Ej3ChV+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yuyJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC","someflag":false}]}
+[2020/05/21 16:36:57:1756] N: main: ++++++++++++++++ test 8
+[2020/05/21 16:36:57:1758] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1761] N: other.name = 'somename'
+[2020/05/21 16:36:57:1763] N: main:    .... strarting serialization of test 8
+{"schema":"com-warmcat-sai-other","name":"somename"}
+{"schema":"meta.schema","t":{"name":"mytargetname","someflag":false},"e":{"hostname":"myhostname","nspawn_timeout":0}}
+[2020/05/21 16:36:57:1785] N: Test set 2
+[2020/05/21 16:36:57:1791] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1795] N: Test set 2: 6: 071ab46ab4296e5de674c628fec17c55088254679f7714ad991f8c4873dca
+[2020/05/21 16:36:57:1801] N: test2: start 
+[2020/05/21 16:36:57:1811] N: lws_struct_schema_only_lejp_cb: child map ofs_clist 0
+[2020/05/21 16:36:57:1815] N: lws_struct_default_lejp_cb: created 'config' object size 80
+[2020/05/21 16:36:57:1819] N: lws_struct_default_lejp_cb: created 'creds' object size 16
+[2020/05/21 16:36:57:1833] N: lws_struct_default_lejp_cb: created 'config' object size 80
+[2020/05/21 16:36:57:1834] N: lws_struct_default_lejp_cb: created 'creds' object size 16
+[2020/05/21 16:36:57:1837] N: test2: lejp_parse 0
+[2020/05/21 16:36:57:1841] N: t2_configs_dump: number of configs: 2
+[2020/05/21 16:36:57:1844] N: t2_config_dump:   id1 '(null)'
+[2020/05/21 16:36:57:1846] N: t2_config_dump:   arg1 'val1'
+[2020/05/21 16:36:57:1848] N: t2_config_dump:   ssid '"nw2"'
+[2020/05/21 16:36:57:1850] N: t2_config_dump:   freq 0
+[2020/05/21 16:36:57:1852] N: t2_config_dump:   arg2 0
+[2020/05/21 16:36:57:1854] N: t2_config_dump:   priority 1
+[2020/05/21 16:36:57:1856] N: t2_config_dump:      key1: "xxxxxxxxx", key2: (null)
+[2020/05/21 16:36:57:1857] N: t2_config_dump:   id1 '(null)'
+[2020/05/21 16:36:57:1858] N: t2_config_dump:   arg1 'val2'
+[2020/05/21 16:36:57:1858] N: t2_config_dump:   ssid '"nw1"'
+[2020/05/21 16:36:57:1859] N: t2_config_dump:   freq 11
+[2020/05/21 16:36:57:1859] N: t2_config_dump:   arg2 1420887242594
+[2020/05/21 16:36:57:1860] N: t2_config_dump:   priority 3
+[2020/05/21 16:36:57:1860] N: t2_config_dump:      key1: "xxxxxxxxxxxxx", key2: (null)
+{"config":[{"creds":{"key1":"\u0022xxxxxxxxx\u0022"},"arg1":"val1","ssid":"\u0022nw2\u0022","frequency":0,"arg2":0,"priority":1},{"creds":{"key1":"\u0022xxxxxxxxxxxxx\u0022"},"arg1":"val2","ssid":"\u0022nw1\u0022","frequency":11,"arg2":1420887242594,"priority":3}]}
+[2020/05/21 16:36:57:1880] U: Completed: PASS
 ```
 
index 5b84718..0aae74c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-api-test-lws_struct-json
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
 
 #include <libwebsockets.h>
 
+typedef struct {
+       lws_dll2_t              list;
+
+       struct gpiod_line       *line;
+
+       const char              *name;
+       const char              *wire;
+
+       int                     chip_idx;
+       int                     offset;
+       int                     safe;
+} sai_jig_gpio_t;
+
+typedef struct {
+       lws_dll2_t              list;
+       sai_jig_gpio_t          *gpio; /* null = wait ms */
+       const char              *gpio_name;
+       int                     value;
+} sai_jig_seq_item_t;
+
+typedef struct {
+       lws_dll2_t              list;
+       lws_dll2_owner_t        seq_owner;
+       const char              *name;
+} sai_jig_sequence_t;
+
+typedef struct {
+       lws_dll2_t              list;
+       lws_dll2_owner_t        gpio_owner;
+       lws_dll2_owner_t        seq_owner;
+
+       lws_sorted_usec_list_t  sul;            /* next step in ongoing seq */
+       sai_jig_seq_item_t      *current;       /* next seq step */
+
+       const char              *name;
+
+       struct lws              *wsi;
+} sai_jig_target_t;
+
+typedef struct {
+       lws_dll2_owner_t        target_owner;
+       struct gpiod_chip       *chip[16];
+       struct lwsac            *ac_conf;
+       int                     port;
+       const char              *iface;
+       struct lws_context      *ctx;
+} sai_jig_t;
+
+/*
+ * We read the JSON config using lws_struct... instrument the related structures
+ */
+
+static const lws_struct_map_t lsm_sai_jig_gpio[] = {
+       LSM_UNSIGNED    (sai_jig_gpio_t, chip_idx,              "chip_idx"),
+       LSM_UNSIGNED    (sai_jig_gpio_t, offset,                "offset"),
+       LSM_UNSIGNED    (sai_jig_gpio_t, safe,                  "safe"),
+       LSM_STRING_PTR  (sai_jig_gpio_t, name,                  "name"),
+       LSM_STRING_PTR  (sai_jig_gpio_t, wire,                  "wire"),
+};
+
+static const lws_struct_map_t lsm_sai_jig_seq_item[] = {
+       LSM_STRING_PTR  (sai_jig_seq_item_t, gpio_name,         "gpio_name"),
+       LSM_UNSIGNED    (sai_jig_seq_item_t, value,             "value"),
+};
+
+static const lws_struct_map_t lsm_sai_jig_sequence[] = {
+       LSM_STRING_PTR  (sai_jig_sequence_t, name,              "name"),
+       LSM_LIST        (sai_jig_sequence_t, seq_owner,
+                        sai_jig_seq_item_t, list,
+                        NULL, lsm_sai_jig_seq_item,            "seq"),
+};
+
+static const lws_struct_map_t lsm_sai_jig_target[] = {
+       LSM_STRING_PTR  (sai_jig_target_t, name,                "name"),
+       LSM_LIST        (sai_jig_target_t, gpio_owner, sai_jig_gpio_t, list,
+                        NULL, lsm_sai_jig_gpio,                "gpios"),
+       LSM_LIST        (sai_jig_target_t, seq_owner, sai_jig_sequence_t, list,
+                        NULL, lsm_sai_jig_sequence,            "sequences"),
+};
+
+static const lws_struct_map_t lsm_sai_jig[] = {
+       LSM_STRING_PTR  (sai_jig_t, iface,                      "iface"),
+       LSM_UNSIGNED    (sai_jig_t, port,                       "port"),
+       LSM_LIST        (sai_jig_t, target_owner, sai_jig_target_t, list,
+                        NULL, lsm_sai_jig_target,              "targets"),
+};
+
+static const lws_struct_map_t lsm_jig_schema[] = {
+        LSM_SCHEMA      (sai_jig_t, NULL, lsm_sai_jig,         "sai-jig"),
+};
+
+static const char * const jig_conf =
+"{"
+       "\"schema\":    \"sai-jig\","
+       "\"port\":              44000,"
+       "\"targets\":   ["
+               "{"
+                       "\"name\": \"linkit-7697-1\","
+                       "\"gpios\": ["
+                               "{"
+                                       "\"chip_index\":        0,"
+                                       "\"name\":              \"nReset\","
+                                       "\"offset\":    17,"
+                                       "\"wire\":              \"RST\","
+                                       "\"safe\":              0"
+                               "}, {"
+                                       "\"name\":              \"usr\","
+                                       "\"chip_index\":        0,"
+                                       "\"offset\":    22,"
+                                       "\"wire\":              \"P6\","
+                                       "\"safe\":              0"
+                               "}"
+                        "], \"sequences\": ["
+                               "{"
+                                       "\"name\":              \"reset\","
+                                       "\"seq\": ["
+                                               "{ \"gpio_name\": \"nReset\",   \"value\": 0 },"
+                                               "{ \"gpio_name\": \"usr\",              \"value\": 0 },"
+                                               "{                              \"value\": 300 },"
+                                               "{ \"gpio_name\": \"nReset\",   \"value\": 1 }"
+                                       "]"
+                               "}, {"
+                                       "\"name\":              \"flash\","
+                                       "\"seq\": ["
+                                               "{ \"gpio_name\": \"nReset\",   \"value\": 0 },"
+                                               "{ \"gpio_name\": \"usr\",              \"value\": 1 },"
+                                               "{                              \"value\": 300 },"
+                                               "{ \"gpio_name\": \"nReset\",   \"value\": 1 },"
+                                               "{                              \"value\": 100 },"
+                                               "{ \"gpio_name\": \"usr\",              \"value\": 0 }"
+                                       "]"
+                               "}"
+                       "]"
+               "}"
+       "]"
+"}";
+
+
+
+extern int test2(void);
+
 /*
  * in this example, the JSON is for one "builder" object, which may specify
  * a child list "targets" of zero or more "target" objects.
@@ -119,6 +260,10 @@ static const char * const json_tests[] = {
                "yJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx"
                "+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\"}]}"
        "}",
+       "{" /* test 8 the "other" schema */
+               "\"schema\":\"com-warmcat-sai-other\","
+               "\"name\":\"somename\""
+       "}",
 };
 
 /*
@@ -170,7 +315,8 @@ static const char * const json_expected[] = {
                "V+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yuyJln+v4R"
                "IWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5v"
                "METteZlx+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\""
-                       ",\"someflag\":false}]}"
+                       ",\"someflag\":false}]}",
+       "{\"schema\":\"com-warmcat-sai-other\",\"name\":\"somename\"}"
 };
 
 /*
@@ -210,6 +356,8 @@ static const lws_struct_map_t lsm_target[] = {
                         NULL, lsm_child,                       "child"),
 };
 
+/* the first kind of struct / schema we can receive */
+
 /* builder object */
 
 typedef struct sai_builder {
@@ -227,22 +375,125 @@ static const lws_struct_map_t lsm_builder[] = {
                         NULL, lsm_target,                      "targets"),
 };
 
-/* Schema table
+/*
+ * the second kind of struct / schema we can receive
+ */
+
+typedef struct sai_other {
+       char                    name[32];
+} sai_other_t;
+
+static const lws_struct_map_t lsm_other[] = {
+       LSM_CARRAY      (sai_other_t, name,             "name"),
+};
+
+/*
+ * meta composed pointers test
+ *
+ * We serialize a struct that consists of members that point to other objects,
+ * we expect this kind of thing
+ *
+ * {
+ *   "schema": "meta",
+ *   "t": { ... },
+ *   "e": { ...}
+ * }
+ */
+
+typedef struct meta {
+       sai_target_t    *t;
+       sai_builder_t   *b;
+} meta_t;
+
+static const lws_struct_map_t lsm_meta[] = {
+       LSM_CHILD_PTR   (meta_t, t, sai_target_t, NULL, lsm_target, "t"),
+       LSM_CHILD_PTR   (meta_t, b, sai_child_t, NULL, lsm_builder, "e"),
+};
+
+static const lws_struct_map_t lsm_schema_meta[] = {
+       LSM_SCHEMA      (meta_t, NULL, lsm_meta, "meta.schema"),
+};
+
+/*
+ * Schema table
  *
  * Before we can understand the serialization top level format, we must read
  * the schema, use the table below to create the right toplevel object for the
  * schema name, and select the correct map tables to interpret the rest of the
  * serialization.
  *
- * Therefore the schema tables below are the starting point for the
- * JSON deserialization.
+ * In this example there are two completely separate structs / schemas possible
+ * to receive, and we disambiguate and create the correct one using the schema
+ * JSON node.
+ *
+ * Therefore the schema table below is the starting point for the JSON
+ * deserialization.
  */
 
 static const lws_struct_map_t lsm_schema_map[] = {
        LSM_SCHEMA      (sai_builder_t, NULL,
                         lsm_builder,           "com-warmcat-sai-builder"),
+       LSM_SCHEMA      (sai_other_t, NULL,
+                        lsm_other,             "com-warmcat-sai-other"),
 };
 
+typedef struct sai_cancel {
+       char task_uuid[65];
+} sai_cancel_t;
+
+const lws_struct_map_t lsm_task_cancel[] = {
+       LSM_CARRAY      (sai_cancel_t, task_uuid,        "uuid"),
+};
+
+static const lws_struct_map_t t2_map[] = {
+       LSM_SCHEMA      (sai_cancel_t, NULL, lsm_task_cancel,
+                                             "com.warmcat.sai.taskinfo"),
+       LSM_SCHEMA      (sai_cancel_t, NULL, lsm_task_cancel,
+                                             "com.warmcat.sai.eventinfo"),
+       LSM_SCHEMA      (sai_cancel_t, NULL, lsm_task_cancel,
+                       /* shares struct */   "com.warmcat.sai.taskreset"),
+       LSM_SCHEMA      (sai_cancel_t, NULL, lsm_task_cancel,
+                       /* shares struct */   "com.warmcat.sai.eventreset"),
+       LSM_SCHEMA      (sai_cancel_t, NULL, lsm_task_cancel,
+                       /* shares struct */   "com.warmcat.sai.eventdelete"),
+       LSM_SCHEMA      (sai_cancel_t,           NULL, lsm_task_cancel,
+                                             "com.warmcat.sai.taskcan"),
+};
+
+static const char *t2 =
+       "{\"schema\":\"com.warmcat.sai.taskcan\","
+        "\"uuid\": \"071ab46ab4296e5de674c628fec17c55088254679f7714ad991f8c4873dca\"}\x01\x02\xff\xff\xff\xff";
+
+typedef struct xlws_wifi_creds {
+       lws_dll2_t      list;
+       char            ssid[33];
+       char            passphrase[64];
+       int             alg;
+       char            bssid[6];
+} xlws_wifi_creds_t;
+
+typedef struct xlws_netdevs {
+       lws_dll2_owner_t        owner_creds;
+} xlws_netdevs_t;
+
+static const lws_struct_map_t lsm_wifi_creds[] = {
+       LSM_CARRAY      (xlws_wifi_creds_t, ssid,               "ssid"),
+       LSM_CARRAY      (xlws_wifi_creds_t, passphrase,         "passphrase"),
+       LSM_UNSIGNED    (xlws_wifi_creds_t, alg,                        "alg"),
+       LSM_STRING_PTR  (xlws_wifi_creds_t, bssid,              "bssid"),
+};
+
+static const lws_struct_map_t lsm_netdev_credentials[] = {
+       LSM_LIST        (xlws_netdevs_t, owner_creds, xlws_wifi_creds_t, list,
+                        NULL, lsm_wifi_creds,                  "credentials"),
+};
+
+static const lws_struct_map_t lsm_netdev_schema[] = {
+       LSM_SCHEMA      (xlws_netdevs_t, NULL, lsm_netdev_credentials,
+                                             "com.warmcat.sai.taskinfo"),
+};
+
+
 static int
 show_target(struct lws_dll2 *d, void *user)
 {
@@ -268,8 +519,11 @@ int main(int argc, const char **argv)
 #endif
        struct lejp_ctx ctx;
        lws_struct_args_t a;
-       sai_builder_t *b;
+       sai_builder_t *b, mb;
+       sai_target_t mt;
+       sai_other_t *o;
        const char *p;
+       meta_t meta;
 
        if ((p = lws_cmdline_option(argc, argv, "-d")))
                logs = atoi(p);
@@ -289,8 +543,8 @@ int main(int argc, const char **argv)
                a.ac_block_size = 512;
 
                lws_struct_json_init_parse(&ctx, NULL, &a);
-               n = (int)(signed char)lejp_parse(&ctx, (uint8_t *)json_tests[m],
-                                                strlen(json_tests[m]));
+               n = lejp_parse(&ctx, (uint8_t *)json_tests[m],
+                                                (int)strlen(json_tests[m]));
                if (n < 0) {
                        lwsl_err("%s: notification JSON decode failed '%s'\n",
                                        __func__, lejp_error_to_string(n));
@@ -299,41 +553,71 @@ int main(int argc, const char **argv)
                }
                lwsac_info(a.ac);
 
-               b = a.dest;
-               if (!b) {
-                       lwsl_err("%s: didn't produce any output\n", __func__);
-                       e++;
-                       goto done;
-               }
+               if (m + 1 != 8) {
+                       b = a.dest;
+                       if (!b) {
+                               lwsl_err("%s: didn't produce any output\n", __func__);
+                               e++;
+                               goto done;
+                       }
+
+                       if (a.top_schema_index) {
+                               lwsl_err("%s: wrong top_schema_index\n", __func__);
+                               e++;
+                               goto done;
+                       }
 
-               lwsl_notice("builder.hostname = '%s', timeout = %d, targets (%d)\n",
-                           b->hostname, b->nspawn_timeout,
-                           b->targets.count);
+                       lwsl_notice("builder.hostname = '%s', timeout = %d, targets (%d)\n",
+                                   b->hostname, b->nspawn_timeout,
+                                   b->targets.count);
+
+                       lws_dll2_foreach_safe(&b->targets, NULL, show_target);
+               } else {
+                       o = a.dest;
+                       if (!o) {
+                               lwsl_err("%s: didn't produce any output\n", __func__);
+                               e++;
+                               goto done;
+                       }
 
-               lws_dll2_foreach_safe(&b->targets, NULL, show_target);
+                       if (a.top_schema_index != 1) {
+                               lwsl_err("%s: wrong top_schema_index\n", __func__);
+                               e++;
+                               goto done;
+                       }
+
+                       lwsl_notice("other.name = '%s'\n", o->name);
+               }
 
                /* 2. serialize the structs into JSON and confirm */
 
                lwsl_notice("%s:    .... strarting serialization of test %d\n",
                                __func__, m + 1);
-               ser = lws_struct_json_serialize_create(lsm_schema_map,
+
+               if (m + 1 != 8) {
+                       ser = lws_struct_json_serialize_create(lsm_schema_map,
                                                LWS_ARRAY_SIZE(lsm_schema_map),
                                                       0//LSSERJ_FLAG_PRETTY
                                                       , b);
+               } else {
+                       ser = lws_struct_json_serialize_create(&lsm_schema_map[1],
+                                               1,
+                                                      0//LSSERJ_FLAG_PRETTY
+                                                      , o);
+               }
                if (!ser) {
                        lwsl_err("%s: unable to init serialization\n", __func__);
                        goto bail;
                }
 
                do {
-                       n = lws_struct_json_serialize(ser, buf, sizeof(buf),
+                       n = (int)lws_struct_json_serialize(ser, buf, sizeof(buf),
                                                      &written);
-                       lwsl_notice("ser says %d\n", n);
                        switch (n) {
-                       case LSJS_RESULT_CONTINUE:
                        case LSJS_RESULT_FINISH:
                                puts((const char *)buf);
                                break;
+                       case LSJS_RESULT_CONTINUE:
                        case LSJS_RESULT_ERROR:
                                goto bail;
                        }
@@ -343,6 +627,7 @@ int main(int argc, const char **argv)
                        lwsl_err("%s: test %d: expected %s\n", __func__, m + 1,
                                        json_expected[m]);
                        e++;
+                       goto done;
                }
 
                lws_struct_json_serialize_destroy(&ser);
@@ -354,11 +639,162 @@ done:
        if (e)
                goto bail;
 
+       /* ad-hoc tests */
+
+       memset(&meta, 0, sizeof(meta));
+       memset(&mb, 0, sizeof(mb));
+       memset(&mt, 0, sizeof(mt));
+
+       meta.t = &mt;
+       meta.b = &mb;
+
+       meta.t->name = "mytargetname";
+       lws_strncpy(meta.b->hostname, "myhostname", sizeof(meta.b->hostname));
+       ser = lws_struct_json_serialize_create(lsm_schema_meta, 1, 0,
+                                              &meta);
+       if (!ser) {
+               lwsl_err("%s: failed to create json\n", __func__);
+
+
+       }
+       do {
+               n = (int)lws_struct_json_serialize(ser, buf, sizeof(buf), &written);
+               switch (n) {
+               case LSJS_RESULT_CONTINUE:
+               case LSJS_RESULT_FINISH:
+                       puts((const char *)buf);
+                       if (strcmp((const char *)buf,
+                               "{\"schema\":\"meta.schema\","
+                               "\"t\":{\"name\":\"mytargetname\","
+                                       "\"someflag\":false},"
+                               "\"e\":{\"hostname\":\"myhostname\","
+                                       "\"nspawn_timeout\":0}}")) {
+                               lwsl_err("%s: meta test fail\n", __func__);
+                               goto bail;
+                       }
+                       break;
+               case LSJS_RESULT_ERROR:
+                       goto bail;
+               }
+       } while(n == LSJS_RESULT_CONTINUE);
+
+       lws_struct_json_serialize_destroy(&ser);
+
+       lwsl_notice("Test set 2\n");
+
+       memset(&a, 0, sizeof(a));
+       a.map_st[0] = t2_map;
+       a.map_entries_st[0] = LWS_ARRAY_SIZE(t2_map);
+       a.ac_block_size = 128;
+
+       lws_struct_json_init_parse(&ctx, NULL, &a);
+       m = lejp_parse(&ctx, (uint8_t *)t2, (int)strlen(t2));
+       if (m < 0 || !a.dest) {
+               lwsl_notice("%s: notification JSON decode failed '%s'\n",
+                               __func__, lejp_error_to_string(m));
+               goto bail;
+       }
+
+       lwsl_notice("Test set 2: %d: %s\n", m,
+                       ((sai_cancel_t *)a.dest)->task_uuid);
+
+       lwsac_free(&a.ac);
+
+       if (test2())
+               goto bail;
+
+       {
+               lws_struct_serialize_t *js;
+               xlws_wifi_creds_t creds;
+               xlws_netdevs_t netdevs;
+               unsigned char *buf;
+               size_t w;
+               int n;
+
+               memset(&creds, 0, sizeof(creds));
+               memset(&netdevs, 0, sizeof(netdevs));
+
+               lws_strncpy(creds.ssid, "xxx", sizeof(creds.ssid));
+               lws_strncpy(creds.passphrase, "yyy", sizeof(creds.passphrase));
+               lws_dll2_add_tail(&creds.list, &netdevs.owner_creds);
+
+               buf = malloc(2048); /* length should be computed */
+
+               js = lws_struct_json_serialize_create(lsm_netdev_schema,
+                       LWS_ARRAY_SIZE(lsm_netdev_schema), 0, &netdevs);
+               if (!js)
+                       goto bail;
+
+               n = (int)lws_struct_json_serialize(js, buf, 2048, &w);
+               lws_struct_json_serialize_destroy(&js);
+               if (n != LSJS_RESULT_FINISH)
+                       goto bail;
+               if (strcmp("{\"schema\":\"com.warmcat.sai.taskinfo\",\"credentials\":[{\"ssid\":\"xxx\",\"passphrase\":\"yyy\",\"alg\":0}]}", (const char *)buf)) {
+                       puts((const char *)buf);
+                       goto bail;
+               }
+               free(buf);
+       }
+
+       {
+               struct x { lws_dll2_t list; const char *sz; };
+               struct x x1, x2, *xp;
+               lws_dll2_owner_t o;
+
+               lws_dll2_owner_clear(&o);
+               memset(&x1, 0, sizeof(x1));
+               memset(&x2, 0, sizeof(x2));
+
+               x1.sz = "nope";
+               x2.sz = "yes";
+
+               lws_dll2_add_tail(&x1.list, &o);
+               lws_dll2_add_tail(&x2.list, &o);
+
+               xp = lws_dll2_search_sz_pl(&o, "yes", 3, struct x, list, sz);
+               if (xp != &x2) {
+                       lwsl_err("%s: 1 xp %p\n", __func__, xp);
+                       goto bail;
+               }
+               xp = lws_dll2_search_sz_pl(&o, "nope", 4, struct x, list, sz);
+               if (xp != &x1) {
+                       lwsl_err("%s: 2 xp %p\n", __func__, xp);
+                       goto bail;
+               }
+               xp = lws_dll2_search_sz_pl(&o, "wrong", 4, struct x, list, sz);
+               if (xp) {
+                       lwsl_err("%s: 3 xp %p\n", __func__, xp);
+                       goto bail;
+               }
+       }
+
+       {
+               lws_struct_args_t a;
+               struct lejp_ctx ctx;
+               int m;
+
+               memset(&a, 0, sizeof(a));
+               a.map_st[0] = lsm_jig_schema;
+               a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_jig_schema);
+               a.ac_block_size = 512;
+
+               lws_struct_json_init_parse(&ctx, NULL, &a);
+
+               m = lejp_parse(&ctx, (uint8_t *)jig_conf, (int)strlen(jig_conf));
+
+               if (m < 0 || !a.dest) {
+                       lwsl_err("%s: line %d: JSON decode failed '%s'\n",
+                                   __func__, ctx.line, lejp_error_to_string(m));
+                       goto bail;
+               }
+       }
+
        lwsl_user("Completed: PASS\n");
 
        return 0;
 
 bail:
+
        lwsl_user("Completed: FAIL\n");
 
        return 1;
diff --git a/minimal-examples/api-tests/api-test-lws_struct-json/selftest.sh b/minimal-examples/api-tests/api-test-lws_struct-json/selftest.sh
deleted file mode 100755 (executable)
index 16d1e2e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=1
-
-dotest $1 $2 apiselftest
-exit $FAILS
diff --git a/minimal-examples/api-tests/api-test-lws_struct-json/test2.c b/minimal-examples/api-tests/api-test-lws_struct-json/test2.c
new file mode 100644 (file)
index 0000000..4afa5a0
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * lws-api-test-lws_struct-json
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * lws_struct apis are used to serialize and deserialize your C structs and
+ * linked-lists in a standardized way that's very modest on memory but
+ * convenient and easy to maintain.
+ *
+ * This second test file shows a worked example for how to express a schema
+ * and both consume JSON -> struct and struct -> JSON for it.
+ */
+
+#include <libwebsockets.h>
+
+static const char * const test2_json =
+"{"
+       "\"config\":["
+               "{"
+                       "\"id1\":"              "null,"
+                       "\"creds\":{"
+                               "\"key1\":"     "\"\\\"xxxxxxxxx\\\"\","
+                               "\"key2\":"     "null"
+                       "},"
+                       "\"frequency\":"        "0,"
+                       "\"arg1\":"             "\"val1\","
+                       "\"arg2\":"             "0,"
+                       "\"priority\":"         "1,"
+                       "\"ssid\":"             "\"\\\"nw2\\\"\""
+               "}, {"
+                       "\"id2\":"              "null,"
+                       "\"creds\": {"
+                               "\"key1\":"     "\"\\\"xxxxxxxxxxxxx\\\"\","
+                               "\"key2\":"     "null"
+                       "},"
+                       "\"frequency\":"        "11,"
+                       "\"arg1\":"             "\"val2\","
+                       "\"arg2\":"             "1420887242594,"
+                       "\"priority\":"         "3,"
+                       "\"ssid\":"             "\"\\\"nw1\\\"\""
+               "}"
+       "]"
+"}";
+
+static const char * const test2_json_expected =
+       "{\"config\":[{\"creds\":{\"key1\":\"\\u0022xxxxxxxxx\\u0022\"},"
+        "\"arg1\":\"val1\",\"ssid\":\"\\u0022nw2\\u0022\","
+        "\"frequency\":0,\"arg2\":0,\"priority\":1},"
+        "{\"creds\":{\"key1\":\"\\u0022xxxxxxxxxxxxx\\u0022\"},"
+        "\"arg1\":\"val2\",\"ssid\":\"\\u0022nw1\\u0022\","
+        "\"frequency\":11,\"arg2\":1420887242594,\"priority\":3}]}"
+;
+
+/*
+ * level 3: Credentials object
+ */
+
+typedef struct t2_cred {
+       const char                              *key1;
+       const char                              *key2;
+} t2_cred_t;
+
+static const lws_struct_map_t lsm_t2_cred[] = {
+       LSM_STRING_PTR  (t2_cred_t, key1, "key1"),
+       LSM_STRING_PTR  (t2_cred_t, key2, "key2"),
+};
+
+/*
+ * level 2: Configuration object, containing a child credentials object
+ */
+
+typedef struct t2_config {
+       lws_dll2_t                              list;
+       t2_cred_t                               *creds;
+       const char                              *id1;
+       const char                              *arg1;
+       const char                              *ssid;
+       unsigned int                            frequency;
+       unsigned long long                      arg2;
+       unsigned int                            priority;
+} t2_config_t;
+
+static const lws_struct_map_t lsm_t2_config[] = {
+       LSM_CHILD_PTR   (t2_config_t,
+                        creds,                 /* the child pointer member */
+                        t2_cred_t,             /* the child type */
+                        NULL, lsm_t2_cred,     /* map object for item type */
+                        "creds"),              /* outer json object name */
+       LSM_STRING_PTR  (t2_config_t, id1,       "id1"),
+       LSM_STRING_PTR  (t2_config_t, arg1,      "arg1"),
+       LSM_STRING_PTR  (t2_config_t, ssid,      "ssid"),
+
+       LSM_UNSIGNED    (t2_config_t, frequency, "frequency"),
+       LSM_UNSIGNED    (t2_config_t, arg2,      "arg2"),
+       LSM_UNSIGNED    (t2_config_t, priority,  "priority"),
+};
+
+/*
+ * level 1: list-of-configurations object
+ */
+
+typedef struct t2_configs {
+       lws_dll2_owner_t                        configs;
+} t2_configs_t;
+
+static const lws_struct_map_t lsm_t2_configs[] = {
+       LSM_LIST        (t2_configs_t, configs, /* the list owner type/member */
+                        t2_config_t,  list,    /* the list item type/member */
+                        NULL, lsm_t2_config,   /* map object for item type */
+                        "config"),             /* outer json object name */
+};
+
+/*
+ * For parsing, this lists the kind of object we expect to parse so the struct
+ * can be allocated polymorphically.
+ *
+ * Lws uses an explicit "schema" member so the type is known unambiguously.  If
+ * in the incoming JSON the first member is not "schema", it will scan the
+ * maps listed here and instantiate the first object that has a member of that
+ * name.
+ */
+
+static const lws_struct_map_t lsm_schema[] = {
+       LSM_SCHEMA      (t2_configs_t, NULL, lsm_t2_configs, "t2"),
+       /* other schemata that might need parsing... */
+};
+
+
+
+static int
+t2_config_dump(struct lws_dll2 *d, void *user)
+{
+#if !defined(LWS_WITH_NO_LOGS)
+       t2_config_t *c = lws_container_of(d, t2_config_t, list);
+
+       lwsl_notice("%s:   id1 '%s'\n", __func__, c->id1);
+       lwsl_notice("%s:   arg1 '%s'\n", __func__, c->arg1);
+       lwsl_notice("%s:   ssid '%s'\n", __func__, c->ssid);
+
+       lwsl_notice("%s:   freq %d\n", __func__, c->frequency);
+       lwsl_notice("%s:   arg2 %llu\n", __func__, c->arg2);
+       lwsl_notice("%s:   priority %d\n", __func__, c->priority);
+
+       lwsl_notice("%s:      key1: %s, key2: %s\n", __func__,
+                            c->creds->key1, c->creds->key2);
+#endif
+
+       return 0;
+}
+
+static int
+t2_configs_dump(t2_configs_t *t2cs)
+{
+       lwsl_notice("%s: number of configs: %d\n", __func__,
+                   t2cs->configs.count);
+
+       lws_dll2_foreach_safe(&t2cs->configs, NULL, t2_config_dump);
+
+       return 0;
+}
+
+
+int
+test2(void)
+{
+       lws_struct_serialize_t *ser;
+       struct lejp_ctx ctx;
+       lws_struct_args_t a;
+       t2_configs_t *top;
+       uint8_t buf[4096];
+       size_t written;
+       int n, bad = 1;
+
+       lwsl_notice("%s: start \n", __func__);
+
+       memset(&a, 0, sizeof(a));
+       a.map_st[0] = lsm_schema;
+       a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema);
+       a.ac_block_size = 512;
+       lws_struct_json_init_parse(&ctx, NULL, &a);
+
+       n = lejp_parse(&ctx, (uint8_t *)test2_json, (int)strlen(test2_json));
+       lwsl_notice("%s: lejp_parse %d\n", __func__, n);
+       if (n < 0) {
+               lwsl_err("%s: test2 JSON decode failed '%s'\n",
+                               __func__, lejp_error_to_string(n));
+               goto bail;
+       }
+       lwsac_info(a.ac);
+
+       top = (t2_configs_t *)a.dest; /* the top level object */
+
+       if (!top) {
+               lwsl_err("%s: no top level object\n", __func__);
+               goto bail;
+       }
+       t2_configs_dump(top);
+
+       /* 2. Let's reserialize the top level object and see what comes out */
+
+       ser = lws_struct_json_serialize_create(&lsm_schema[0], 1,
+                                              LSSERJ_FLAG_OMIT_SCHEMA, top);
+       if (!ser) {
+               lwsl_err("%s: unable to init serialization\n", __func__);
+               goto bail;
+       }
+
+       do {
+               n = (int)lws_struct_json_serialize(ser, buf, sizeof(buf), &written);
+               switch (n) {
+               case LSJS_RESULT_FINISH:
+                       puts((const char *)buf);
+                       break;
+               case LSJS_RESULT_CONTINUE:
+               case LSJS_RESULT_ERROR:
+                       goto bail;
+               }
+       } while (n == LSJS_RESULT_CONTINUE);
+
+       if (strcmp(test2_json_expected, (char *)buf)) {
+               lwsl_err("%s: expected %s\n", __func__, test2_json_expected);
+               goto bail;
+       }
+
+       lws_struct_json_serialize_destroy(&ser);
+
+       bad = 0;
+
+bail:
+       lwsac_free(&a.ac);
+
+       return bad;
+}
diff --git a/minimal-examples/api-tests/api-test-lws_struct_sqlite/CMakeLists.txt b/minimal-examples/api-tests/api-test-lws_struct_sqlite/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ac8b161
--- /dev/null
@@ -0,0 +1,25 @@
+project(lws-api-test-lws_struct-sqlite C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-api-test-lws_struct-sqlite)
+set(SRCS main.c)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_STRUCT_SQLITE3 1 requirements)
+
+if (requirements)
+
+       add_executable(${SAMP} ${SRCS})
+       add_test(NAME api-test-lws_struct_sqlite COMMAND lws-api-test-lws_struct-sqlite)
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared sqlite3 ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets sqlite3 ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/api-tests/api-test-lws_struct_sqlite/README.md b/minimal-examples/api-tests/api-test-lws_struct_sqlite/README.md
new file mode 100644 (file)
index 0000000..aa2b6a8
--- /dev/null
@@ -0,0 +1,25 @@
+# lws api test lws_struct SQLITE
+
+Demonstrates how to use and performs selftests for lws_struct
+SQLITE serialization and deserialization
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+ $ ./lws-api-test-lws_struct-sqlite
+[2020/02/22 09:55:05:4335] U: LWS API selftest: lws_struct SQLite
+[2020/02/22 09:55:05:5579] N: lws_struct_sq3_open: created _lws_apitest.sq3 owned by 0:0 mode 0600
+[2020/02/22 09:55:05:9206] U: Completed: PASS
+
+```
+
diff --git a/minimal-examples/api-tests/api-test-lws_struct_sqlite/main.c b/minimal-examples/api-tests/api-test-lws_struct_sqlite/main.c
new file mode 100644 (file)
index 0000000..f7c1d38
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * lws-api-test-lws_struct-sqlite
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * lws_struct apis are used to serialize and deserialize your C structs and
+ * linked-lists in a standardized way that's very modest on memory but
+ * convenient and easy to maintain.
+ *
+ * The API test shows how to serialize and deserialize a struct with a linked-
+ * list of child structs in JSON using lws_struct APIs.
+ */
+
+#include <libwebsockets.h>
+
+typedef struct teststruct {
+       lws_dll2_t              list; /* not directly serialized */
+
+       char                    str1[32];
+       const char              *str2;
+       uint8_t                 u8;
+       uint16_t                u16;
+       uint32_t                u32;
+       uint64_t                u64;
+       int32_t                 s32;
+} teststruct_t;
+
+/*
+ * These are the members that we will serialize and deserialize, not every
+ * member in the struct (eg, the dll2 list member)
+ */
+
+static const lws_struct_map_t lsm_teststruct[] = {
+       LSM_CARRAY      (teststruct_t, str1,            "str1"),
+       LSM_STRING_PTR  (teststruct_t, str2,            "str2"),
+       LSM_UNSIGNED    (teststruct_t, u8,              "u8"),
+       LSM_UNSIGNED    (teststruct_t, u16,             "u16"),
+       LSM_UNSIGNED    (teststruct_t, u32,             "u32"),
+       LSM_UNSIGNED    (teststruct_t, u64,             "u64"),
+       LSM_SIGNED      (teststruct_t, s32,             "s32"),
+};
+
+static const lws_struct_map_t lsm_schema_apitest[] = {
+       LSM_SCHEMA_DLL2 (teststruct_t, list, NULL, lsm_teststruct, "apitest")
+};
+
+static const char *test_string =
+       "No one would have believed in the last years of the nineteenth "
+       "century that this world was being watched keenly and closely by "
+       "intelligences greater than man's and yet as mortal as his own; that as "
+       "men busied themselves about their various concerns they were "
+       "scrutinised and studied, perhaps almost as narrowly as a man with a "
+       "microscope might scrutinise the transient creatures that swarm and "
+       "multiply in a drop of water.  With infinite complacency men went to "
+       "and fro over this globe about their little affairs, serene in their "
+       "assurance of their empire over matter. It is possible that the "
+       "infusoria under the microscope do the same.  No one gave a thought to "
+       "the older worlds of space as sources of human danger, or thought of "
+       "them only to dismiss the idea of life upon them as impossible or "
+       "improbable.  It is curious to recall some of the mental habits of "
+       "those departed days.  At most terrestrial men fancied there might be "
+       "other men upon Mars, perhaps inferior to themselves and ready to "
+       "welcome a missionary enterprise. Yet across the gulf of space, minds "
+       "that are to our minds as ours are to those of the beasts that perish, "
+       "intellects vast and cool and unsympathetic, regarded this earth with "
+       "envious eyes, and slowly and surely drew their plans against us.  And "
+       "early in the twentieth century came the great disillusionment. ";
+
+int main(int argc, const char **argv)
+{
+       int e = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       struct lwsac *ac = NULL;
+       lws_dll2_owner_t resown;
+       teststruct_t ts, *pts;
+       const char *p;
+       sqlite3 *db;
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS API selftest: lws_struct SQLite\n");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+
+       unlink("_lws_apitest.sq3");
+
+       if (lws_struct_sq3_open(context, "_lws_apitest.sq3", 1, &db)) {
+               lwsl_err("%s: failed to open table\n", __func__);
+               goto bail;
+       }
+
+       /* 1. populate the struct */
+
+       memset(&ts, 0, sizeof(ts));
+
+       lws_strncpy(ts.str1, "hello", sizeof(ts.str1));
+       ts.str2 = test_string;
+       ts.u8 = 1;
+       ts.u16 = 512,
+       ts.u32 = 0x55aa1234; /* 1437209140, */
+       ts.u64 = 0x34abcdef01ull;
+       ts.s32 = -1;
+
+       /* add our struct to the dll2 owner list */
+
+       lws_dll2_owner_clear(&resown);
+       lws_dll2_add_head(&ts.list, &resown);
+
+       /* gratuitously create the table */
+
+       if (lws_struct_sq3_create_table(db, lsm_schema_apitest)) {
+               lwsl_err("%s: Create table failed\n", __func__);
+               e++;
+               goto done;
+       }
+
+       /* serialize the items on the dll2 owner */
+
+       if (lws_struct_sq3_serialize(db, lsm_schema_apitest, &resown, 0)) {
+               lwsl_err("%s: Serialize failed\n", __func__);
+               e++;
+               goto done;
+       }
+
+       /* resown should be cleared by deserialize, ac is already NULL */
+
+       lws_dll2_owner_clear(&resown); /* make sure old resown data is gone */
+
+       if (lws_struct_sq3_deserialize(db, NULL, NULL, lsm_schema_apitest,
+                                      &resown, &ac, 0, 1)) {
+               lwsl_err("%s: Deserialize failed\n", __func__);
+               e++;
+               goto done;
+       }
+
+       /* we should have 1 entry in resown now (created into the ac) */
+
+       if (resown.count != 1) {
+               lwsl_err("%s: Expected 1 result got %d\n", __func__,
+                               resown.count);
+               e++;
+               goto done;
+       }
+
+       /*
+        * Convert the pointer to the embedded lws_dll2 into a pointer
+        * to the actual struct with the correct type
+        */
+
+       pts = lws_container_of(lws_dll2_get_head(&resown),
+                              teststruct_t, list);
+
+       if (strcmp(pts->str1, "hello") ||
+           strcmp(pts->str2, test_string) ||
+           pts->u8 != 1 ||
+           pts->u16 != 512 ||
+           pts->u32 != 0x55aa1234 ||
+           pts->u64 != 0x34abcdef01ull ||
+           pts->s32 != -1) {
+               lwsl_err("%s: unexpected deser values: %s\n", __func__, pts->str1);
+               lwsl_err("%s: %s\n", __func__, pts->str2);
+               lwsl_err("%s: %u %u %u 0x%llx %d\n", __func__, pts->u8, pts->u16,
+                        pts->u32, (unsigned long long)pts->u64, pts->s32);
+
+               e++;
+               goto done;
+       }
+
+done:
+       lwsac_free(&ac);
+       lws_struct_sq3_close(&db);
+
+
+       if (e)
+               goto bail;
+
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: PASS\n");
+
+       return 0;
+
+bail:
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: FAIL\n");
+
+       return 1;
+}
index 7bfc6f6..503f25d 100644 (file)
@@ -1,73 +1,19 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-api-test-lws_tokenize C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-api-test-lws_tokenize)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
-
-
        add_executable(${SAMP} ${SRCS})
+       add_test(NAME api-test-lws_tokenize COMMAND lws-api-test-lws_tokenize)
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
index 3257c4f..b9bbcea 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-api-test-lws_tokenize
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
@@ -20,7 +20,7 @@
 struct expected {
        lws_tokenize_elem e;
        const char *value;
-       int len;
+       size_t len;
 };
 
 struct tests {
@@ -169,8 +169,15 @@ struct expected expected1[] = {
                { LWS_TOKZE_TOKEN_NAME_EQUALS, "a", 1 },
                { LWS_TOKZE_TOKEN, "5", 1 },
                { LWS_TOKZE_ENDED, "", 0 },
+       },
+       expected17[] = {
+               { LWS_TOKZE_TOKEN, "hello", 5 },
+               { LWS_TOKZE_ENDED, "", 0 },
+       },
+       expected18[] = {
+               { LWS_TOKZE_TOKEN, "x=y", 3 },
+               { LWS_TOKZE_ENDED, "", 0 },
        }
-
 ;
 
 struct tests tests[] = {
@@ -201,7 +208,7 @@ struct tests tests[] = {
        }, {
                "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5",
                expected7, LWS_ARRAY_SIZE(expected7),
-               LWS_TOKENIZE_F_RFC7230_DELIMS
+               LWS_TOKENIZE_F_ASTERISK_NONTERM | LWS_TOKENIZE_F_RFC7230_DELIMS
        },
        {
                " Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, greek",
@@ -247,6 +254,14 @@ struct tests tests[] = {
                "a=5", expected16, LWS_ARRAY_SIZE(expected16),
                LWS_TOKENIZE_F_NO_INTEGERS
        },
+       {
+               "# comment1\r\nhello #comment2\r\n#comment3", expected17,
+               LWS_ARRAY_SIZE(expected17), LWS_TOKENIZE_F_HASH_COMMENT
+       },
+       {
+               "x=y", expected18,
+               LWS_ARRAY_SIZE(expected18), LWS_TOKENIZE_F_EQUALS_NONTERM
+       }
 };
 
 /*
@@ -270,8 +285,45 @@ static const char *element_names[] = {
        "LWS_TOKZE_QUOTED_STRING",
 };
 
+
+int
+exp_cb1(void *priv, const char *name, char *out, size_t *pos, size_t olen,
+       size_t *exp_ofs)
+{
+       const char *replace = NULL;
+       size_t total, budget;
+
+       if (!strcmp(name, "test")) {
+               replace = "replacement_string";
+               total = strlen(replace);
+               goto expand;
+       }
+
+       return LSTRX_FATAL_NAME_UNKNOWN;
+
+expand:
+       budget = olen - *pos;
+       total -= *exp_ofs;
+       if (total < budget)
+               budget = total;
+
+       if (out)
+               memcpy(out + *pos, replace + (*exp_ofs), budget);
+       *exp_ofs += budget;
+       *pos += budget;
+
+       if (budget == total)
+               return LSTRX_DONE;
+
+       return LSTRX_FILLED_OUT;
+}
+
+static const char *exp_inp1 = "this-is-a-${test}-for-strexp";
+
 int main(int argc, const char **argv)
 {
+       struct lws_context_creation_info info;
+       struct lws_context *cx;
        struct lws_tokenize ts;
        lws_tokenize_elem e;
        const char *p;
@@ -283,6 +335,7 @@ int main(int argc, const char **argv)
                        /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
                        /* | LLL_DEBUG */;
        int fail = 0, ok = 0, flags = 0;
+       char dotstar[512];
 
        if ((p = lws_cmdline_option(argc, argv, "-d")))
                logs = atoi(p);
@@ -293,22 +346,208 @@ int main(int argc, const char **argv)
        if ((p = lws_cmdline_option(argc, argv, "-f")))
                flags = atoi(p);
 
+
+       memset(&info, 0, sizeof info);
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW;
+
+       /*
+        * since we know this lws context is only ever going to be used with
+        * one client wsis / fds / sockets at a time, let lws know it doesn't
+        * have to use the default allocations for fd tables up to ulimit -n.
+        * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
+        * will use.
+        */
+       info.fd_limit_per_thread = 1 + 1 + 1;
+
+#if 0
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+       /*
+        * OpenSSL uses the system trust store.  mbedTLS has to be told which
+        * CA to trust explicitly.
+        */
+       info.client_ssl_ca_filepath = "./warmcat.com.cer";
+#endif
+#endif
+#if 0
+       n = open("./warmcat.com.cer", O_RDONLY);
+       if (n >= 0) {
+               info.client_ssl_ca_mem_len = read(n, memcert, sizeof(memcert));
+               info.client_ssl_ca_mem = memcert;
+               close(n);
+               n = 0;
+               memcert[info.client_ssl_ca_mem_len++] = '\0';
+       }
+#endif
+       cx = lws_create_context(&info);
+
+       /* lws_strexp */
+
+       {
+               size_t in_len, used_in, used_out;
+               lws_strexp_t exp;
+               char obuf[128];
+               const char *p;
+
+               obuf[0] = '\0';
+               lws_strexp_init(&exp, NULL, exp_cb1, obuf, sizeof(obuf));
+               n = lws_strexp_expand(&exp, exp_inp1, 28, &used_in, &used_out);
+               if (n != LSTRX_DONE || used_in != 28 ||
+                   strcmp(obuf, "this-is-a-replacement_string-for-strexp")) {
+                       lwsl_notice("%s: obuf %s\n", __func__, obuf);
+                       lwsl_err("%s: lws_strexp test 1 failed: %d\n", __func__, n);
+
+                       return 1;
+               }
+
+               /* as above, but don't generate output, just find the length */
+
+               lws_strexp_init(&exp, NULL, exp_cb1, NULL, (size_t)-1);
+               n = lws_strexp_expand(&exp, exp_inp1, 28, &used_in, &used_out);
+               if (n != LSTRX_DONE || used_in != 28 || used_out != 39) {
+                       lwsl_err("%s: lws_strexp test 2 failed: %d, used_out: %d\n",
+                                       __func__, n, (int)used_out);
+
+                       return 1;
+               }
+
+               p = exp_inp1;
+               in_len = strlen(p);
+               memset(obuf, 0, sizeof(obuf));
+               lws_strexp_init(&exp, NULL, exp_cb1, obuf, 16);
+               n = lws_strexp_expand(&exp, p, in_len, &used_in, &used_out);
+               if (n != LSTRX_FILLED_OUT || used_in != 16 || used_out != 16) {
+                       lwsl_err("a\n");
+                       return 1;
+               }
+
+               p += used_in;
+               in_len -= used_in;
+
+               memset(obuf, 0, sizeof(obuf));
+               lws_strexp_reset_out(&exp, obuf, 16);
+
+               n = lws_strexp_expand(&exp, p, in_len, &used_in, &used_out);
+               if (n != LSTRX_FILLED_OUT || used_in != 5 || used_out != 16) {
+                       lwsl_err("b: n %d, used_in %d, used_out %d\n", n,
+                                       (int)used_in, (int)used_out);
+                       return 2;
+               }
+
+               p += used_in;
+               in_len -= used_in;
+
+               memset(obuf, 0, sizeof(obuf));
+               lws_strexp_reset_out(&exp, obuf, 16);
+
+               n = lws_strexp_expand(&exp, p, in_len, &used_in, &used_out);
+               if (n != LSTRX_DONE || used_in != 7 || used_out != 7) {
+                       lwsl_err("c: n %d, used_in %d, used_out %d\n", n, (int)used_in, (int)used_out);
+                       return 2;
+               }
+       }
+
+       /* sanity check lws_strnncpy() */
+
+       lws_strnncpy(dotstar, "12345678", 4, sizeof(dotstar));
+       if (strcmp(dotstar, "1234")) {
+               lwsl_err("%s: lws_strnncpy check failed\n", __func__);
+
+               return 1;
+       }
+       lws_strnncpy(dotstar, "12345678", 8, 6);
+       if (strcmp(dotstar, "12345")) {
+               lwsl_err("%s: lws_strnncpy check failed\n", __func__);
+
+               return 1;
+       }
+
+       /* sanity check lws_nstrstr() */
+
+       {
+               static const char *t1 = "abc123456";
+               const char *mcp;
+
+               mcp = lws_nstrstr(t1, strlen(t1), "abc", 3);
+               if (mcp != t1) {
+                       lwsl_err("%s: lws_nstrstr 1 failed\n", __func__);
+                       return 1;
+               }
+               mcp = lws_nstrstr(t1, strlen(t1), "def", 3);
+               if (mcp != NULL) {
+                       lwsl_err("%s: lws_nstrstr 2 failed\n", __func__);
+                       return 1;
+               }
+               mcp = lws_nstrstr(t1, strlen(t1), "456", 3);
+               if (mcp != t1 + 6) {
+                       lwsl_err("%s: lws_nstrstr 3 failed: %p\n", __func__, mcp);
+                       return 1;
+               }
+               mcp = lws_nstrstr(t1, strlen(t1), "1", 1);
+               if (mcp != t1 + 3) {
+                       lwsl_err("%s: lws_nstrstr 4 failed\n", __func__);
+                       return 1;
+               }
+               mcp = lws_nstrstr(t1, strlen(t1), "abc1234567", 10);
+               if (mcp != NULL) {
+                       lwsl_err("%s: lws_nstrstr 5 failed\n", __func__);
+                       return 1;
+               }
+       }
+
+       /* sanity check lws_json_simple_find() */
+
+       {
+               static const char *t1 = "{\"myname1\":true,"
+                                        "\"myname2\":\"string\", "
+                                        "\"myname3\": 123}";
+               size_t alen;
+               const char *mcp;
+
+               mcp = lws_json_simple_find(t1, strlen(t1), "\"myname1\":", &alen);
+               if (mcp != t1 + 11 || alen != 4) {
+                       lwsl_err("%s: lws_json_simple_find 1 failed: (%d) %s\n",
+                                __func__, (int)alen, mcp);
+                       return 1;
+               }
+
+               mcp = lws_json_simple_find(t1, strlen(t1), "\"myname2\":", &alen);
+               if (mcp != t1 + 27 || alen != 6) {
+                       lwsl_err("%s: lws_json_simple_find 2 failed\n", __func__);
+                       return 1;
+               }
+
+               mcp = lws_json_simple_find(t1, strlen(t1), "\"myname3\":", &alen);
+               if (mcp != t1 + 47 || alen != 3) {
+                       lwsl_err("%s: lws_json_simple_find 3 failed\n", __func__);
+                       return 1;
+               }
+
+               mcp = lws_json_simple_find(t1, strlen(t1), "\"nope\":", &alen);
+               if (mcp != NULL) {
+                       lwsl_err("%s: lws_json_simple_find 4 failed\n", __func__);
+                       return 1;
+               }
+       }
+
        p = lws_cmdline_option(argc, argv, "-s");
 
        for (n = 0; n < (int)LWS_ARRAY_SIZE(tests); n++) {
                int m = 0, in_fail = fail;
                struct expected *exp = tests[n].exp;
 
+               memset(&ts, 0, sizeof(ts));
                ts.start = tests[n].string;
                ts.len = strlen(ts.start);
-               ts.flags = tests[n].flags;
+               ts.flags = (uint16_t)tests[n].flags;
 
                do {
                        e = lws_tokenize(&ts);
 
-                       lwsl_info("{ %s, \"%.*s\", %d }\n",
-                                 element_names[e + LWS_TOKZE_ERRS],
-                                 (int)ts.token_len, ts.token,
+                       lws_strnncpy(dotstar, ts.token, ts.token_len,
+                                    sizeof(dotstar));
+                       lwsl_info("{ %s, \"%s\", %d }\n",
+                                 element_names[e + LWS_TOKZE_ERRS], dotstar,
                                  (int)ts.token_len);
 
                        if (m == (int)tests[n].count) {
@@ -328,8 +567,11 @@ int main(int argc, const char **argv)
                        if (e > 0 &&
                            (ts.token_len != exp->len ||
                             memcmp(exp->value, ts.token, exp->len))) {
-                               lwsl_notice("fail token mismatch %d %d %.*s\n",
-                                               ts.token_len, exp->len, ts.token_len, ts.token);
+                               lws_strnncpy(dotstar, ts.token, ts.token_len,
+                                            sizeof(dotstar));
+                               lwsl_notice("fail token mismatch %d %d %s\n",
+                                           (int)ts.token_len, (int)exp->len,
+                                           dotstar);
                                fail++;
                                break;
                        }
@@ -346,7 +588,7 @@ int main(int argc, const char **argv)
        if (p) {
                ts.start = p;
                ts.len = strlen(p);
-               ts.flags = flags;
+               ts.flags = (uint16_t)flags;
 
                printf("\t{\n\t\t\"%s\",\n"
                       "\t\texpected%d, LWS_ARRAY_SIZE(expected%d),\n\t\t",
@@ -391,18 +633,147 @@ int main(int argc, const char **argv)
                do {
                        e = lws_tokenize(&ts);
 
-                       printf("\t\t{ %s, \"%.*s\", %d },\n",
+                       lws_strnncpy(dotstar, ts.token, ts.token_len,
+                                    sizeof(dotstar));
+
+                       printf("\t\t{ %s, \"%s\", %d },\n",
                                  element_names[e + LWS_TOKZE_ERRS],
-                                 (int)ts.token_len,
-                                 ts.token, (int)ts.token_len);
+                                 dotstar, (int)ts.token_len);
 
                } while (e > 0);
 
                printf("\t}\n");
        }
 
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+       {
+               time_t t;
+
+               if (lws_http_date_parse_unix("Tue, 15 Nov 1994 08:12:31 GMT", 29, &t)) {
+                       lwsl_err("%s: date parse failed\n", __func__);
+                       fail++;
+               } else {
+                       /* lwsl_notice("%s: %llu\n", __func__, (unsigned long long)t); */
+                       if (t != (time_t)784887151) {
+                               lwsl_err("%s: date parse wrong\n", __func__);
+                               fail++;
+                       } else {
+                               char s[30];
+
+                               if (lws_http_date_render_from_unix(s, sizeof(s), &t)) {
+                                       lwsl_err("%s: failed date render\n", __func__);
+                                       fail++;
+                               } else {
+                                       if (!strcmp(s, "Tue, 15 Nov 1994 08:12:31 GMT")) {
+                                               lwsl_err("%s: date render wrong\n", __func__);
+                                               fail++;
+                                       }
+                               }
+                       }
+               }
+       }
+#endif
+
+       {
+               char buf[24];
+               int m;
+
+               m = lws_humanize(buf, sizeof(buf), 0, humanize_schema_si);
+               if (m != 1 || strcmp(buf, "0")) {
+                       lwsl_user("%s: humanize 1 fail '%s' (%d)\n", __func__, buf, m);
+                       fail++;
+               }
+               m = lws_humanize(buf, sizeof(buf), 2, humanize_schema_si);
+               if (m != 1 || strcmp(buf, "2")) {
+                       lwsl_user("%s: humanize 2 fail '%s' (%d)\n", __func__, buf, m);
+                       fail++;
+               }
+               m = lws_humanize(buf, sizeof(buf), 999, humanize_schema_si);
+               if (m != 3 || strcmp(buf, "999")) {
+                       lwsl_user("%s: humanize 3 fail '%s' (%d)\n", __func__, buf, m);
+                       fail++;
+               }
+               m = lws_humanize(buf, sizeof(buf), 1000, humanize_schema_si);
+               if (m != 4 || strcmp(buf, "1000")) {
+                       lwsl_user("%s: humanize 4 fail '%s' (%d)\n", __func__, buf, m);
+                       fail++;
+               }
+               m = lws_humanize(buf, sizeof(buf), 1024, humanize_schema_si);
+               if (m != 7 || strcmp(buf, "1.000Ki")) {
+                       lwsl_user("%s: humanize 5 fail '%s' (%d)\n", __func__, buf, m);
+                       fail++;
+               }
+       }
+
+       if (lws_strcmp_wildcard("allied", 6, "allied", 6)) {
+               lwsl_user("%s: wc 1 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("a*", 2, "allied", 6)) {
+               lwsl_user("%s: wc 2 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("all*", 4, "allied", 6)) {
+               lwsl_user("%s: wc 3 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("all*d", 5, "allied", 6)) {
+               lwsl_user("%s: wc 4 fail\n", __func__);
+               fail++;
+       }
+       if (!lws_strcmp_wildcard("b*", 2, "allied", 6)) {
+               lwsl_user("%s: wc 5 fail\n", __func__);
+               fail++;
+       }
+       if (!lws_strcmp_wildcard("b*ed", 4, "allied", 6)) {
+               lwsl_user("%s: wc 6 fail\n", __func__);
+               fail++;
+       }
+       if (!lws_strcmp_wildcard("allie", 5, "allied", 6)) {
+               lwsl_user("%s: wc 7 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("allie*", 6, "allied", 6)) {
+               lwsl_user("%s: wc 8 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("*llie*", 6, "allied", 6)) {
+               lwsl_user("%s: wc 9 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("*llied", 6, "allied", 6)) {
+               lwsl_user("%s: wc 10 fail\n", __func__);
+               fail++;
+       }
+       if (!lws_strcmp_wildcard("*llie", 5, "allied", 6)) {
+               lwsl_user("%s: wc 11 fail\n", __func__);
+               fail++;
+       }
+       if (!lws_strcmp_wildcard("*nope", 5, "allied", 6)) {
+               lwsl_user("%s: wc 12 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("*li*", 4, "allied", 6)) {
+               lwsl_user("%s: wc 13 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("*", 1, "allied", 6)) {
+               lwsl_user("%s: wc 14 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("*abc*d", 6, "xxabyyabcdd", 11)) {
+               lwsl_user("%s: wc 15 fail\n", __func__);
+               fail++;
+       }
+       if (lws_strcmp_wildcard("ssproxy.n.cn.*", 14,
+                               "ssproxy.n.cn.failures", 21)) {
+               lwsl_user("%s: wc 16 fail\n", __func__);
+               fail++;
+       }
 
        lwsl_user("Completed: PASS: %d, FAIL: %d\n", ok, fail);
 
+       lws_context_destroy(cx);
+
        return !(ok && !fail);
 }
diff --git a/minimal-examples/api-tests/api-test-lws_tokenize/selftest.sh b/minimal-examples/api-tests/api-test-lws_tokenize/selftest.sh
deleted file mode 100755 (executable)
index 16d1e2e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=1
-
-dotest $1 $2 apiselftest
-exit $FAILS
index a73c680..f7d0aaf 100644 (file)
@@ -1,73 +1,19 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-api-test-lwsac C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-api-test-lwsac)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
+add_executable(${SAMP} ${SRCS})
+add_test(NAME api-test-lwsac COMMAND lws-api-test-lwsac)
 
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
-
-
-       add_executable(${SAMP} ${SRCS})
-
-       if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
-               add_dependencies(${SAMP} websockets_shared)
-       else()
-               target_link_libraries(${SAMP} websockets)
-       endif()
+if (websockets_shared)
+       target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+       add_dependencies(${SAMP} websockets_shared)
+else()
+       target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+endif()
diff --git a/minimal-examples/api-tests/api-test-lwsac/selftest.sh b/minimal-examples/api-tests/api-test-lwsac/selftest.sh
deleted file mode 100755 (executable)
index 16d1e2e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=1
-
-dotest $1 $2 apiselftest
-exit $FAILS
diff --git a/minimal-examples/api-tests/api-test-secure-streams/CMakeLists.txt b/minimal-examples/api-tests/api-test-secure-streams/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b4f39ca
--- /dev/null
@@ -0,0 +1,31 @@
+project(lws-api-test-secure-streams C)
+cmake_minimum_required(VERSION 2.8.12)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+
+if (requirements)
+
+       add_executable(${PROJECT_NAME} main.c)
+       
+       if (LWS_CTEST_INTERNET_AVAILABLE)
+               add_test(NAME api-test-secure-streams COMMAND ${PROJECT_NAME})
+               set_tests_properties(api-test-secure-streams
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/api-tests/api-test-secure-streams
+                                    TIMEOUT 20)
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${PROJECT_NAME} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${PROJECT_NAME} websockets_shared)
+       else()
+               target_link_libraries(${PROJECT_NAME} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+endif()
diff --git a/minimal-examples/api-tests/api-test-secure-streams/README.md b/minimal-examples/api-tests/api-test-secure-streams/README.md
new file mode 100644 (file)
index 0000000..a5a220a
--- /dev/null
@@ -0,0 +1,21 @@
+# lws api test Secure Streams
+
+Performs some tests against httpbin.org server
+to check Secure Streams client performance
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+ $ ./lws-api-test-secure-streams
+```
+
diff --git a/minimal-examples/api-tests/api-test-secure-streams/main.c b/minimal-examples/api-tests/api-test-secure-streams/main.c
new file mode 100644 (file)
index 0000000..841cd1a
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * lws-api-test-secure-streams
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * Let's exercise some basic SS / h1 functionality against httpbin.org
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted, bad = 1;
+static lws_state_notify_link_t nl;
+static struct lws_context *context;
+
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+#if defined(VIA_LOCALHOST_SOCKS)
+         "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+#endif
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+
+               "{\"amz_root_ca1\": \""
+       "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"
+               "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"amz\","
+                       "\"stack\": ["
+                               "\"amz_root_ca1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": ["
+               /*
+                * "fetch_policy" decides from where the real policy
+                * will be fetched, if present.  Otherwise the initial
+                * policy is treated as the whole, hardcoded, policy.
+                */
+               "{\"httpbin_get\": {"
+                       "\"endpoint\":"         "\"httpbin.org\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"/get\","
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"amz\""
+               "}},"
+               "{\"httpbin_get404\": {"
+                       "\"endpoint\":"         "\"httpbin.org\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"/status/404\","
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"amz\""
+               "}},"
+               "{\"httpbin_post\": {"
+                       "\"endpoint\":"         "\"httpbin.org\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"POST\","
+                       "\"http_url\":"         "\"/post\","
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"amz\""
+                       "}}"
+                "}"
+       "]}"
+;
+
+typedef struct atss {
+       const lws_ss_info_t             *ssi;
+       size_t                          send;
+       char                            expect_nack;
+} atss_t;
+
+static const atss_t *next_test;
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+       size_t                          payload;
+       size_t                          sent;
+       char                            seen_eom;
+       char                            ended_well;
+} myss_t;
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_hexdump_info(buf, len);
+
+       m->payload += len;
+
+       if (!(flags & LWSSS_FLAG_EOM))
+               m->seen_eom = 1;
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_tx_get(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+           int *flags)
+{
+       return 1; /* nothing to send */
+}
+
+static lws_ss_state_return_t
+myss_tx_post(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+            int *flags)
+{
+       myss_t *m = (myss_t *)userobj;
+       size_t budget = (next_test->send - m->sent);
+
+       if (!budget)
+               return 1;
+
+       if (*len < budget)
+               budget = *len;
+
+       if (!m->sent)
+               *flags |= LWSSS_FLAG_SOM;
+
+       memset(buf, 0x55, budget);
+       *len = budget;
+       m->sent += budget;
+       if (m->sent != next_test->send)
+               return lws_ss_request_tx(m->ss);
+
+       *flags |= LWSSS_FLAG_EOM;
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+       lws_ss_state_return_t r;
+
+       lwsl_notice("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               r = lws_ss_client_connect(m->ss);
+               if (r)
+                       return r;
+               if (next_test->send)
+                       return lws_ss_request_tx_len(m->ss, (unsigned long)next_test->send);
+               break;
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               lwsl_notice("%s: Connection failed\n", __func__);
+               interrupted = 1;
+               break;
+       case LWSSSCS_QOS_NACK_REMOTE:
+               if (next_test->expect_nack)
+                       goto happy;
+               lwsl_notice("%s: remote NACK\n", __func__);
+               interrupted = 1;
+               break;
+       case LWSSSCS_QOS_ACK_REMOTE:
+               /*
+                * To be satisfied, we want to see the ACK_REMOTE indicating
+                * that the transaction went through; that we had the payload
+                * EOM; and that we saw at least 200 + posted bytes response
+                */
+
+               if (!m->seen_eom || m->payload < 200 + next_test->send) {
+                       lwsl_warn("%s: ACK_REMOTE but eom %d, payload %d\n",
+                                 __func__, m->seen_eom, (int)m->payload);
+                       interrupted = 1;
+                       return -1;
+               }
+
+happy:
+               /* when we disconnect, we can go happily */
+               m->ended_well = 1;
+
+               if (!(++next_test)->ssi) {
+                       lwsl_notice("%s: completed all tests\n", __func__);
+                       bad = 0;
+                       interrupted = 1;
+                       break;
+               }
+               if (lws_ss_create(context, 0, next_test->ssi,
+                                 NULL, NULL, NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+                       return -1;
+               }
+               break;
+
+       case LWSSSCS_DISCONNECTED:
+               if (!m->ended_well) {
+                       lwsl_warn("%s: DISCONNECTED without good end\n",
+                                 __func__);
+                       interrupted = 1;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static const lws_ss_info_t ssi_get = {
+       .handle_offset                  = offsetof(myss_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_t, opaque_data),
+       .rx                             = myss_rx,
+       .tx                             = myss_tx_get,
+       .state                          = myss_state,
+       .user_alloc                     = sizeof(myss_t),
+       .streamtype                     = "httpbin_get"
+}, ssi_get404 = {
+       .handle_offset                  = offsetof(myss_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_t, opaque_data),
+       .rx                             = myss_rx,
+       .tx                             = myss_tx_get,
+       .state                          = myss_state,
+       .user_alloc                     = sizeof(myss_t),
+       .streamtype                     = "httpbin_get404"
+}, ssi_post = {
+       .handle_offset                  = offsetof(myss_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_t, opaque_data),
+       .rx                             = myss_rx,
+       .tx                             = myss_tx_post,
+       .state                          = myss_state,
+       .user_alloc                     = sizeof(myss_t),
+       .streamtype                     = "httpbin_post"
+};
+
+static const atss_t test_list[] = {
+               { .ssi = &ssi_get },
+               { .ssi = &ssi_get404, .expect_nack = 1 },
+               { .ssi = &ssi_post, .send = 4096 },
+               { .ssi = NULL }
+};
+
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+
+                       next_test = &test_list[0];
+
+                       if (lws_ss_create(context, 0, next_test->ssi,
+                                         NULL, NULL, NULL, NULL)) {
+                               lwsl_err("%s: failed to create secure stream\n",
+                                        __func__);
+                               return -1;
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams test client [-d<verb>]\n");
+
+       /* these options are mutually exclusive if given */
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.pss_policies_json = default_ss_policy;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW;
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
index 4c8e671..49e67ff 100644 (file)
@@ -1,66 +1,13 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-unit-tests-smtp-client C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-unit-tests-smtp-client)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_SMTP 1 requirements)
 
@@ -68,9 +15,9 @@ if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index df7adac..c32e5ac 100644 (file)
@@ -55,7 +55,7 @@ smtp_test_instance_init(lws_abs_t *instance)
                        "\r\n.\r\n", "andy@warmcat.com");
        email->done = email_sent_or_failed;
 
-       if (lws_smtp_client_add_email(instance, email)) {
+       if (lws_smtpc_add_email(instance, email)) {
                lwsl_err("%s: failed to add email\n", __func__);
                return 1;
        }
@@ -163,7 +163,7 @@ sigint_handler(int sig)
  * set the HELO our SMTP client will use
  */
 
-static const lws_token_map_t smtp_protocol_tokens[] = {
+static const lws_token_map_t smtp_ap_tokens[] = {
  {
        .u = { .value = "lws-test-client" },
        .name_index = LTMI_PSMTP_V_HELO,
@@ -183,8 +183,8 @@ int main(int argc, const char **argv)
        struct lws_context_creation_info info;
        lws_test_sequencer_args_t args;
        struct lws_context *context;
+       lws_abs_t *abs = NULL;
        struct lws_vhost *vh;
-       lws_abs_t abs, *instance;
        const char *p;
 
        /* the normal lws init */
@@ -213,32 +213,16 @@ int main(int argc, const char **argv)
                goto bail1;
        }
 
-       /* create the smtp client */
+       /* create the abs used to create connections */
 
-       memset(&abs, 0, sizeof(abs));
-       abs.vh = vh;
-
-       /* select the protocol and bind its tokens */
-
-       abs.ap = lws_abs_protocol_get_by_name("smtp");
-       if (!abs.ap)
-               goto bail1;
-
-       abs.ap_tokens = smtp_protocol_tokens;
-
-       /* select the transport and bind its tokens */
-
-       abs.at = lws_abs_transport_get_by_name("unit_test");
-       if (!abs.at)
-               goto bail1;
-
-       instance = lws_abs_bind_and_create_instance(&abs);
-       if (!instance)
+       abs = lws_abstract_alloc(vh, NULL, "smtp.unit_test",
+                                &smtp_ap_tokens[0], NULL);
+       if (!abs)
                goto bail1;
 
        /* configure the test sequencer */
 
-       args.abs = &abs;
+       args.abs = abs;
        args.tests = tests;
        args.results = results;
        args.results_max = LWS_ARRAY_SIZE(results);
@@ -271,5 +255,7 @@ bail1:
 
        lws_context_destroy(context);
 
+       lws_abstract_free(&abs);
+
        return !count_tests || count_passes != count_tests;
 }
index a265496..65a01b6 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-proxy C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-proxy)
 set(SRCS minimal-ws-proxy.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
\ No newline at end of file
index 4bb5a3e..e304c61 100644 (file)
 #include "protocol_lws_minimal.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0},
        LWS_PLUGIN_PROTOCOL_MINIMAL,
-       { NULL, NULL, 0, 0 } /* terminator */
+
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
index a25a3cd..e483922 100644 (file)
@@ -28,15 +28,12 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
 document.addEventListener("DOMContentLoaded", function() {
 
-       ws = new_ws(get_appropriate_ws_url(""), "lws-minimal-proxy");
+       var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal-proxy");
        try {
                ws.onopen = function() {
                        document.getElementById("r").disabled = 0;
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index c51c304..428a27d 100644 (file)
@@ -41,6 +41,8 @@ struct per_vhost_data__minimal {
        struct lws_vhost *vhost;
        const struct lws_protocols *protocol;
 
+       lws_sorted_usec_list_t sul;
+
        struct per_session_data__minimal *pss_list; /* linked-list of live pss*/
 
        struct lws_ring *ring; /* ringbuffer holding unsent messages */
@@ -60,9 +62,12 @@ __minimal_destroy_message(void *_msg)
        msg->len = 0;
 }
 
-static int
-connect_client(struct per_vhost_data__minimal *vhd)
+static void
+sul_connect_attempt(struct lws_sorted_usec_list *sul)
 {
+       struct per_vhost_data__minimal *vhd =
+               lws_container_of(sul, struct per_vhost_data__minimal, sul);
+
        vhd->i.context = vhd->context;
        vhd->i.port = 443;
        vhd->i.address = "libwebsockets.org";
@@ -75,7 +80,9 @@ connect_client(struct per_vhost_data__minimal *vhd)
        vhd->i.local_protocol_name = "lws-minimal-proxy";
        vhd->i.pwsi = &vhd->client_wsi;
 
-       return !lws_client_connect_via_info(&vhd->i);
+       if (!lws_client_connect_via_info(&vhd->i))
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, 10 * LWS_US_PER_SEC);
 }
 
 static int
@@ -109,14 +116,12 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                if (!vhd->ring)
                        return 1;
 
-               if (connect_client(vhd))
-                       lws_timed_callback_vh_protocol(vhd->vhost,
-                                               vhd->protocol,
-                                               LWS_CALLBACK_USER, 1);
+               sul_connect_attempt(&vhd->sul);
                break;
 
        case LWS_CALLBACK_PROTOCOL_DESTROY:
                lws_ring_destroy(vhd->ring);
+               lws_sul_cancel(&vhd->sul);
                break;
 
        /* --- serving callbacks --- */
@@ -169,8 +174,8 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
                         in ? (char *)in : "(null)");
                vhd->client_wsi = NULL;
-               lws_timed_callback_vh_protocol(vhd->vhost, vhd->protocol,
-                                              LWS_CALLBACK_USER, 1);
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, LWS_US_PER_SEC);
                break;
 
        case LWS_CALLBACK_CLIENT_ESTABLISHED:
@@ -214,18 +219,8 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
 
        case LWS_CALLBACK_CLIENT_CLOSED:
                vhd->client_wsi = NULL;
-               lws_timed_callback_vh_protocol(vhd->vhost, vhd->protocol,
-                                              LWS_CALLBACK_USER, 1);
-               break;
-
-       /* rate-limited client connect retries */
-
-       case LWS_CALLBACK_USER:
-               lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__);
-               if (connect_client(vhd))
-                       lws_timed_callback_vh_protocol(vhd->vhost,
-                                               vhd->protocol,
-                                               LWS_CALLBACK_USER, 1);
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, LWS_US_PER_SEC);
                break;
 
        default:
@@ -243,37 +238,3 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                128, \
                0, NULL, 0 \
        }
-
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal(struct lws_context *context,
-                     struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal(struct lws_context *context)
-{
-       return 0;
-}
-#endif
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/CMakeLists.txt b/minimal-examples/crypto/minimal-crypto-cose-key/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6ee78ae
--- /dev/null
@@ -0,0 +1,55 @@
+project(lws-crypto-cose-key C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-crypto-cose-key)
+set(SRCS main.c)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_COSE 1 requirements)
+
+if (requirements)
+
+       add_executable(${SAMP} ${SRCS})
+       
+       add_test(NAME crypto-cose-key-1
+                COMMAND lws-crypto-cose-key --stdin set1.cks )
+       add_test(NAME crypto-cose-key-2
+                COMMAND lws-crypto-cose-key --kty EC2 --curve P-256 --kid ctest-256 --stdout ctest-ec-256.key)
+       add_test(NAME crypto-cose-key-3
+                COMMAND lws-crypto-cose-key --kty EC2 --curve P-384 --kid ctest-384 --stdout ctest-ec-384.key)
+       add_test(NAME crypto-cose-key-4
+                COMMAND lws-crypto-cose-key --kty EC2 --curve P-521 --kid ctest-512 --stdout ctest-ec-512.key)
+       add_test(NAME crypto-cose-key-5
+                COMMAND lws-crypto-cose-key --kty SYMMETRIC --bits 256 --stdout ctest-sym-256.key)
+       add_test(NAME crypto-cose-key-6
+                COMMAND lws-crypto-cose-key --kty RSA --bits 2048 --stdout ctest-rsa-2048.key)
+       add_test(NAME crypto-cose-key-7
+                COMMAND lws-crypto-cose-key --stdin ctest-rsa-2048.key)
+
+       set_tests_properties(crypto-cose-key-1
+                            crypto-cose-key-2
+                            crypto-cose-key-3
+                            crypto-cose-key-4
+                            crypto-cose-key-5
+                            crypto-cose-key-6
+                            crypto-cose-key-7
+                            PROPERTIES
+                               WORKING_DIRECTORY
+                                       ${CMAKE_SOURCE_DIR}/minimal-examples/crypto/minimal-crypto-cose-key
+                               TIMEOUT 5)
+                               
+       set_tests_properties(crypto-cose-key-7
+                            PROPERTIES
+                               DEPENDS crypto-cose-key-6)
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/README.md b/minimal-examples/crypto/minimal-crypto-cose-key/README.md
new file mode 100644 (file)
index 0000000..f6be13d
--- /dev/null
@@ -0,0 +1,132 @@
+# lws minimal example for cose_key
+
+Demonstrates how to create and dump cose_keys.
+
+## Dump key or key_set
+
+Pipe a cose_key or cose_key_set into stdin to get a textual dump of all the keys
+inside.  You can optionally use --kid kid or --kid-hex HEXSTRING to dump one key
+from a set.
+
+```
+$ cat set1.cks | ./bin/lws-crypto-cose-key
+$ cat set1.cks | ./bin/lws-crypto-cose-key --kid 11
+```
+
+## Create keys
+
+Stdin is not used, give parameters for the kty and kid etc to create a
+new key on stdout (which can be redirected to a file).
+
+```
+$ ./bin/lws-crypto-cose-key --kty EC2 --curve P-521 --kid sec512 >ec512.key
+```
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+|Option|Meaning|
+|---|---|
+|--kty type|Key type, one of OKP, EC2, RSA or SYMMETRIC|
+|-k \<keyset filepath\>|One or a set of cose_keys|
+|--kid string|Specifies the key ID to use as a string|
+|--kid-hex HEXSTRING|Specifies the key ID to use as a hex blob|
+|--curve curve|For EC type key creation, specify the curve|
+|--stdin filepath|Makes tool fetch from filepath instead of stdin (useful for CI)|
+|--stdout filepath|Makes tool write to filepath instead of stdout (useful for CI)|
+
+
+HEXSTRING above means a string like `1a2b3c`
+
+## Examples
+
+### cose_key dumping
+
+```
+$ cat set1.cks | ./bin/lws-crypto-cose-key
+[2021/07/30 10:14:31:0420] U: LWS cose-key example tool -k keyset [-s alg-name kid ]
+[2021/07/30 10:14:31:0780] N: lws_create_context: LWS: 4.2.99-v4.2.0-134-g8433c8b459, NET CLI SRV H1 H2 WS ConMon IPV6-on
+[2021/07/30 10:14:31:0892] N:  ++ [wsi|0|pipe] (1)
+[2021/07/30 10:14:31:0926] N:  ++ [vh|0|netlink] (1)
+[2021/07/30 10:14:31:0977] N:  ++ [vh|1|default||-1] (2)
+[2021/07/30 10:14:31:1057] N: main: importing
+Cose key #1
+  kty: EC2
+  kid: 11
+  kty: P-256
+  x: bac5b11cad8f99f9c72b05cf4b9e26d244dc189f745228255a219a86d6a09eff
+  d: 57c92077664146e876760c9520d054aa93c3afb04e306705db6090308507b4d3
+  y: 20138bf82dc1b6d562be0fa54ab7804a3a64b6d72ccfed6b6fb6ed28bbfc117e
+Cose key #2
+  kty: EC2
+  kid: meriadoc.brandybuck@buckland.example
+  kty: P-256
+  x: 65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d
+  d: aff907c99f9ad3aae6c4cdf21122bce2bd68b5283e6907154ad911840fa208cf
+  y: 1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c
+Cose key #3
+  kty: SYMMETRIC
+  kid: our-secret
+  k: 849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188
+Cose key #4
+  kty: EC2
+  kid: bilbo.baggins@hobbiton.example
+  kty: P-521
+  x: 0072992cb3ac08ecf3e5c63dedec0d51a8c1f79ef2f82f94f3c737bf5de7986671eac625fe8257bbd0394644caaa3aaf8f27a4585fbbcad0f2457620085e5c8f42ad
+  d: 00085138ddabf5ca975f5860f91a08e91d6d5f9a76ad4018766a476680b55cd339e8ab6c72b5facdb2a2a50ac25bd086647dd3e2e6e99e84ca2c3609fdf177feb26d
+  y: 01dca6947bce88bc5790485ac97427342bc35f887d86d65a089377e247e60baa55e4e8501e2ada5724ac51d6909008033ebc10ac999b9d7f5cc2519f3fe1ea1d9475
+Cose key #5
+  kty: SYMMETRIC
+  kid: our-secret2
+  k: 849b5786457c1491be3a76dcea6c4271
+Cose key #6
+  kty: EC2
+  kid: peregrin.took@tuckborough.example
+  kty: P-256
+  x: 98f50a4ff6c05861c8860d13a638ea56c3f5ad7590bbfbf054e1c7b4d91d6280
+  d: 02d1f7e6f26c43d4868d87ceb2353161740aacf1f7163647984b522a848df1c3
+  y: f01400b089867804b8e9fc96c3932161f1934f4223069170d924b7e03bf822bb
+Cose key #7
+  kty: SYMMETRIC
+  kid: 018c0ae5-4d9b-471b-bfd6-eef314bc7037
+  use: 849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c427188
+Cose key #8
+  kty: SYMMETRIC
+  kid: sec-48
+  k: 849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c42718800112233778899aa2122232425262728
+Cose key #9
+  kty: SYMMETRIC
+  kid: sec-64
+  k: 849b57219dae48de646d07dbb533566e976686457c1491be3a76dcea6c42718800112233778899aa2122232425262728aabbccddeeffa5a6a7a8a9a0b1b2b3b4
+Cose key #10
+  kty: EC2
+  kid: sec384
+  kty: P-384
+  x: ea2866349fe3a2f9ad4d6bfe7c30c527436e901c5fb22210b67b2150574ffcd0b1dd8c43d5d1e3d5cb849ecec202117c
+  d: 4d46a58480d43d5454307edcf501e098ef7c0186cc6b56b41dfd13fe4b9b1ab1425851cf5b23e6636ed18f5bbdde1896
+  y: 4c3d245515a688ef25ff68034089ca4f10a01bef51cc57309f12919c3d484142368795c6f2a5d30af650b4e12d0133e4
+Cose key #11
+  kty: EC2
+  kid: sec512
+  kty: P-521
+  x: 003b81ed66d8a2194b42f29ecb2c9ae48199be695924804a8407194ed0e172f39693f870f32463e2d36950034a21901487c5a0c43a1713a818fb89fa8a5b3b2dc181
+  d: 013e0f06ce394ac14a3df3953fc560679ad0dee14779ef0d475787451fca71e3b4b827b6f7cedcf00e23c716fb829b5419234ba5c92c33e0bc94351fe97be21f2b82
+  y: 004b9b6b0adf41913b5d700cf43bfe0ee8b79eb58fc308509e574fcb910b3fd5a2ad585affc6776f7fc9d4ff48f5923fe900660ecc6e3720f89c1363eecfffb38b5b
+[2021/07/30 10:14:31:1430] N:  -- [wsi|0|pipe] (0) 52.763ms
+[2021/07/30 10:14:31:1441] N:  -- [vh|0|netlink] (1) 51.437ms
+[2021/07/30 10:14:31:1491] N:  -- [vh|1|default||-1] (0) 51.591ms
+[2021/07/30 10:14:31:1536] N: main: PASS
+
+```
+
+### cose_key creation
+
+```
+$ ./bin/lws-crypto-cose-key --kty EC2 --curve P-521 --kid sec512 >ec512.key
+```
+
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/main.c b/minimal-examples/crypto/minimal-crypto-cose-key/main.c
new file mode 100644 (file)
index 0000000..5a19e2c
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * lws-minimal-crypto-cose-key
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+static int fdin = 0, fdout = 1;
+
+static const char *meta_names[] = {
+       "kty", "kid", "use", "key_ops", "base_iv", "alg"
+};
+
+static const char *oct_names[] = {
+       "k"
+};
+
+static const char *rsa_names[] = {
+       "e", "n", "d", "p", "q", "dp", "dq", "qi", "other", "ri", "di", "ti"
+};
+
+static const char *ec_names[] = {
+       "crv", "x", "d", "y",
+};
+
+static void
+cose_key_dump(const struct lws_cose_key *ck)
+{
+       const char **enames;
+       char hex[2048], dump[3072];
+       int elems;
+       size_t l;
+       int n;
+
+       (void)enames;
+       (void)meta_names;
+
+       switch (ck->gencrypto_kty) {
+
+       case LWS_GENCRYPTO_KTY_OCT:
+               elems = LWS_GENCRYPTO_OCT_KEYEL_COUNT;
+               enames = oct_names;
+               break;
+       case LWS_GENCRYPTO_KTY_RSA:
+               elems = LWS_GENCRYPTO_RSA_KEYEL_COUNT;
+               enames = rsa_names;
+               break;
+       case LWS_GENCRYPTO_KTY_EC:
+               elems = LWS_GENCRYPTO_EC_KEYEL_COUNT;
+               enames = ec_names;
+               break;
+
+       default:
+               lwsl_err("%s: jwk %p: unknown type\n", __func__, ck);
+
+               return;
+       }
+
+       for (n = 0; n < LWS_COUNT_COSE_KEY_ELEMENTS; n++) {
+               if (ck->meta[n].buf) {
+                       if (n < 2) {
+                               l = (size_t)lws_snprintf(dump, sizeof(dump),
+                                                "  %s: %.*s\n", meta_names[n],
+                                                (int)ck->meta[n].len,
+                                                ck->meta[n].buf);
+                               write(fdout, dump, l);
+                       } else {
+                               l = (size_t)lws_snprintf(dump, sizeof(dump),
+                                                "  %s: ", meta_names[n]);
+                               write(fdout, dump, l);
+                               lws_hex_from_byte_array(ck->meta[n].buf,
+                                                       ck->meta[n].len,
+                                                       hex, sizeof(hex));
+                               write(fdout, hex, strlen(hex));
+                               write(fdout, "\n", 1);
+                       }
+               }
+       }
+
+       for (n = 0; n < elems; n++) {
+               if (ck->e[n].buf) {
+                       if (!n && ck->gencrypto_kty == LWS_GENCRYPTO_KTY_EC) {
+                               l = (size_t)lws_snprintf(dump, sizeof(dump),
+                                                "  %s: %.*s\n", enames[n],
+                                                (int)ck->e[n].len,
+                                                ck->e[n].buf);
+                               write(fdout, dump, l);
+                       } else {
+                               l = (size_t)lws_snprintf(dump, sizeof(dump),
+                                                "  %s: ", enames[n]);
+                               write(fdout, dump, l);
+                               lws_hex_from_byte_array(ck->e[n].buf,
+                                                       ck->e[n].len,
+                                                       hex, sizeof(hex));
+                               write(fdout, hex, strlen(hex));
+                               write(fdout, "\n", 1);
+                       }
+               }
+       }
+}
+
+int main(int argc, const char **argv)
+{
+       uint8_t *kid = NULL, ktmp[4096], set_temp[32 * 1024], temp[256];
+       int result = 1, bits = 0,
+           logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       struct lws_context_creation_info info;
+       size_t kid_len = 0, stp = 0;
+       struct lws_context *context;
+       lws_cose_key_t *ck = NULL;
+       cose_param_t cose_kty = 0;
+       lws_dll2_owner_t set;
+       const char *p, *crv;
+       lws_lec_pctx_t lec;
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+
+       lwsl_user("LWS cose-key example tool -k keyset [-s alg-name kid ]\n");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "--stdin"))) {
+               fdin = open(p, LWS_O_RDONLY, 0);
+               if (fdin < 0) {
+                       lwsl_err("%s: unable to open stdin file\n", __func__);
+                       return 1;
+               }
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "--stdout"))) {
+               fdout = open(p, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC, 0600);
+               if (fdout < 0) {
+                       lwsl_err("%s: unable to open stdout file\n", __func__);
+                       goto bail_early;
+               }
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "--kid"))) {
+               kid = (uint8_t *)p;
+               kid_len = strlen(p);
+               //lwsl_hexdump_notice(kid, kid_len);
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "--kid-hex"))) {
+               kid_len = (size_t)lws_hex_to_byte_array(p, ktmp, sizeof(ktmp));
+               kid = (uint8_t *)ktmp;
+       }
+
+       /*
+        * If we have some stdin queued up, we understand we are dumping
+        * an existing cose_key or key_set from stdin
+        */
+
+       if (!fdin) {
+               struct timeval  timeout;
+               fd_set  fds;
+
+               FD_ZERO(&fds);
+               FD_SET(0, &fds);
+
+               timeout.tv_sec  = 0;
+               timeout.tv_usec = 1000;
+
+               if (select(fdin + 1, &fds, NULL, NULL, &timeout) < 0)
+                       goto no_stdin;
+
+               if (!FD_ISSET(0, &fds))
+                       goto no_stdin;
+       }
+
+       do {
+               int n = (int)read(fdin, temp, sizeof(temp));
+
+               if (n < 0)
+                       goto bail;
+               if (!n) {
+                       int kc = 0;
+
+                       if (!stp)
+                               /* there was no stdin */
+                               break;
+
+                       lwsl_notice("%s: importing\n", __func__);
+
+                       lws_dll2_owner_clear(&set);
+                       ck = lws_cose_key_import(&set, NULL, NULL, set_temp, stp);
+                       if (!ck) {
+                               lwsl_err("%s: import failed\n", __func__);
+                               goto bail;
+                       }
+
+                       lws_start_foreach_dll(struct lws_dll2 *, p,
+                                               lws_dll2_get_head(&set)) {
+                               lws_cose_key_t *ck = lws_container_of(p,
+                                                       lws_cose_key_t, list);
+                               struct lws_gencrypto_keyelem *ke =
+                                               &ck->meta[COSEKEY_META_KID];
+
+                               kc++;
+
+                               if (!kid_len || (ke->len &&
+                                   ke->len == (uint32_t)kid_len &&
+                                   !memcmp(ke->buf, kid, kid_len))) {
+                                           printf("Cose key #%d\n", kc);
+                                           cose_key_dump(ck);
+                               }
+
+                       } lws_end_foreach_dll(p);
+
+                       lws_cose_key_set_destroy(&set);
+                       result = 0;
+                       goto bail;
+
+               }
+
+               if (stp + (size_t)n > sizeof(set_temp)) {
+                       lwsl_err("%s: stdin bigger than our buffer\n", __func__);
+                       goto bail;
+               }
+               memcpy(set_temp + stp, temp, (size_t)n);
+               stp += (size_t)n;
+       } while (1);
+
+no_stdin:
+
+       /*
+        *
+        */
+
+       p = lws_cmdline_option(argc, argv, "--kty");
+       if (!p) {
+               lwsl_err("%s: use --kty OKP|EC2|RSA|SYMMETRIC\n",
+                                       __func__);
+               goto bail;
+       }
+
+       if (!strcmp(p, "OKP"))
+               cose_kty = LWSCOSE_WKKTV_OKP;
+       if (!strcmp(p, "EC2"))
+               cose_kty = LWSCOSE_WKKTV_EC2;
+       if (!strcmp(p, "RSA"))
+               cose_kty = LWSCOSE_WKKTV_RSA;
+       if (!strcmp(p, "SYMMETRIC") || !strcmp(p, "SYM"))
+               cose_kty = LWSCOSE_WKKTV_SYMMETRIC;
+
+       if (!cose_kty) {
+               lwsl_err("%s: use --kty OKP|EC2|RSA|SYMMETRIC\n",
+                        __func__);
+               goto bail;
+       }
+
+       crv = NULL;
+       if (cose_kty == LWSCOSE_WKKTV_OKP ||
+           cose_kty == LWSCOSE_WKKTV_EC2) {
+               crv = lws_cmdline_option(argc, argv, "--curve");
+               if (!crv) {
+                       lwsl_err("%s: use --curve P-256 etc\n", __func__);
+                       goto bail;
+               }
+       }
+
+       p = lws_cmdline_option(argc, argv, "--bits");
+       if (p)
+               bits = atoi(p);
+
+       ck = lws_cose_key_generate(context, cose_kty, 0, bits, crv,
+                                  kid, kid_len);
+       if (!ck)
+               goto bail;
+
+       lws_lec_init(&lec, ktmp, sizeof(ktmp));
+       lws_cose_key_export(ck, &lec, LWSJWKF_EXPORT_PRIVATE);
+       write(fdout, ktmp, lec.used);
+
+       lws_cose_key_destroy(&ck);
+       result = 0;
+
+bail:
+       lws_context_destroy(context);
+
+       if (result)
+               lwsl_err("%s: FAIL: %d\n", __func__, result);
+       else
+               lwsl_notice("%s: PASS\n", __func__);
+
+bail_early:
+       if (fdin > 0)
+               close(fdin);
+       if (fdout != 1 && fdout >= 0)
+               close(fdout);
+
+       return result;
+}
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/set1.cks b/minimal-examples/crypto/minimal-crypto-cose-key/set1.cks
new file mode 100644 (file)
index 0000000..e5eca18
Binary files /dev/null and b/minimal-examples/crypto/minimal-crypto-cose-key/set1.cks differ
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass01.sig b/minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass01.sig
new file mode 100644 (file)
index 0000000..d78767e
Binary files /dev/null and b/minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass01.sig differ
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass02.sig b/minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass02.sig
new file mode 100644 (file)
index 0000000..2b53930
--- /dev/null
@@ -0,0 +1 @@
\84\ 1\ 4B11TThis is the content.X@\10r\9c×\11Ë8\13ØØéD¨Úq\11ç²XɽÊa5÷®\1aÛî\95       \89\12g\83~\1e3½6ÁP2jæ'Uƽ\8eT\f>\8f\92×Ò%èÛr¸\82\v
\ No newline at end of file
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass03.sig b/minimal-examples/crypto/minimal-crypto-cose-key/sign1_pass03.sig
new file mode 100644 (file)
index 0000000..a10fc96
--- /dev/null
@@ -0,0 +1 @@
+\84\ 1\ 4B11TThis is the content.X@\8e³>L£\1d\1cFZ°Z¬4Ìk#Õ\8fï\\b1\ 6ÄÒZ\91®ð°\11~*ù¢\91ª2áJ¸4ÜVí*"4DT~\ 1ñ\1d;       \16å¤ÃEÊË6
\ No newline at end of file
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/sign_pass01.sig b/minimal-examples/crypto/minimal-crypto-cose-key/sign_pass01.sig
new file mode 100644 (file)
index 0000000..268b086
--- /dev/null
@@ -0,0 +1 @@
+Øb\84A  TThis is the content.\81\83\ 1\ 4B11X@⮯Ô\r\9dþnR\a|]\7fôä\b(,¾û]\ 6Ëô\14¯.\19Ù\82¬E¬\98¸TL\90\8bE\aÞ\1e\90·\17ÃÓH\16þ\92j+\98õ:ý/ ó
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/sign_pass02.sig b/minimal-examples/crypto/minimal-crypto-cose-key/sign_pass02.sig
new file mode 100644 (file)
index 0000000..b80f7a2
--- /dev/null
@@ -0,0 +1 @@
+Øb\84@ TThis is the content.\81\83\ 1\ 4B11X@˸ÚÙ¾¯¸\90á¤\14\12M\8bûÂkíò©OËZ\88$2¿öÖ>\15õtQØ?¢Ëö&rëôÇÙ\93°ôÂDvGØ1ºW̨k\93
diff --git a/minimal-examples/crypto/minimal-crypto-cose-key/sign_pass03.sig b/minimal-examples/crypto/minimal-crypto-cose-key/sign_pass03.sig
new file mode 100644 (file)
index 0000000..60d8f03
--- /dev/null
@@ -0,0 +1 @@
+\84@ TThis is the content.\81\83\ 1\ 4B11X@⮯Ô\r\9dþnR\a|]\7fôä\b(,¾û]\ 6Ëô\14¯.\19Ù\82¬E¬\98¸TL\90\8bE\aÞ\1e\90·\17ÃÓH\16þ\92j+\98õ:ý/ ó
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/CMakeLists.txt b/minimal-examples/crypto/minimal-crypto-cose-sign/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b49b417
--- /dev/null
@@ -0,0 +1,219 @@
+project(lws-crypto-cose-sign C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-crypto-cose-sign)
+set(SRCS main.c)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_COSE 1 requirements)
+
+if (requirements)
+
+       add_executable(${SAMP} ${SRCS})
+
+       # EC signing
+       
+       add_test(NAME crypto-cose-sign-1
+                COMMAND lws-crypto-cose-sign -s -k set1.cks --kid 11
+                       --alg ES256 --cose-sign
+                       --stdin payload.txt
+                       --stdout ctest-sig-es256.sig)
+       add_test(NAME crypto-cose-sign-2
+                COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec384
+                       --alg ES384 --cose-sign
+                       --stdin payload.txt
+                       --stdout ctest-sig-es384.sig)
+       add_test(NAME crypto-cose-sign-3
+                COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec512
+                       --alg ES512 --cose-sign
+                       --stdin payload.txt
+                       --stdout ctest-sig-es512.sig)
+
+       # EC validation
+                               
+       add_test(NAME crypto-cose-sign-4
+                COMMAND lws-crypto-cose-sign -k set1.cks
+                       --stdout r1.txt
+                       --stdin ctest-sig-es256.sig)
+       set_tests_properties(crypto-cose-sign-4 PROPERTIES
+                                               DEPENDS crypto-cose-sign-1)
+                       
+       add_test(NAME crypto-cose-sign-5
+                COMMAND lws-crypto-cose-sign -k set1.cks
+                       --stdout r2.txt
+                       --stdin ctest-sig-es384.sig)
+       set_tests_properties(crypto-cose-sign-5 PROPERTIES
+                                               DEPENDS crypto-cose-sign-2)
+                       
+       add_test(NAME crypto-cose-sign-6
+                COMMAND lws-crypto-cose-sign -k set1.cks --cose-sign
+                       --stdout r3.txt
+                       --stdin ctest-sig-es512.sig)
+       set_tests_properties(crypto-cose-sign-6 PROPERTIES
+                                               DEPENDS crypto-cose-sign-3)
+
+       # RSA 4096 signing
+       
+       add_test(NAME crypto-cose-sign-7
+        COMMAND lws-crypto-cose-sign -s -k rsa-4096.ck
+               --alg RS512 --cose-sign
+               --stdin payload.txt
+               --stdout ctest-sig-rs512.sig)
+               
+        # RSA 4096 validation
+
+       add_test(NAME crypto-cose-sign-8
+                COMMAND lws-crypto-cose-sign -k rsa-4096.ck --cose-sign
+                       --stdout r8.txt
+                       --stdin ctest-sig-rs512.sig)
+       set_tests_properties(crypto-cose-sign-8 PROPERTIES
+                                               DEPENDS crypto-cose-sign-7)
+                                               
+       # HMAC signing, cose-mac
+
+#      add_test(NAME crypto-cose-sign-9
+#               COMMAND lws-crypto-cose-sign -s -k set1.cks --kid our-secret
+#                      --alg HS256 --cose-mac
+#                      --stdin payload.txt
+#                      --stdout ctest-sig-hmac256.sig)
+#      add_test(NAME crypto-cose-sign-10
+#               COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec-48
+#                      --alg HS384 --cose-mac
+#                      --stdin payload.txt
+#                      --stdout ctest-sig-hmac384.sig)
+#      add_test(NAME crypto-cose-sign-11
+#               COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec-64
+#                      --alg HS512 --cose-mac
+#                      --stdin payload.txt
+#                      --stdout ctest-sig-hmac512.sig)
+#      add_test(NAME crypto-cose-sign-12
+#               COMMAND lws-crypto-cose-sign -s -k set1.cks --kid our-secret
+#                      --alg HS256_64 --cose-mac
+#                      --stdin payload.txt
+#                      --stdout ctest-sig-hmac256_64.sig)
+
+       # HMAC validation, cose-mac
+       
+#      add_test(NAME crypto-cose-sign-13
+#               COMMAND lws-crypto-cose-sign -k set1.cks
+#                      --stdout r1.txt
+#                      --stdin ctest-sig-hmac256.sig)
+#      set_tests_properties(crypto-cose-sign-13
+#                           PROPERTIES DEPENDS crypto-cose-sign-9)
+#                      
+#      add_test(NAME crypto-cose-sign-14
+#               COMMAND lws-crypto-cose-sign -k set1.cks
+#                      --stdout r2.txt
+#                      --stdin ctest-sig-hmac384.sig)
+#      set_tests_properties(crypto-cose-sign-14
+#                           PROPERTIES DEPENDS crypto-cose-sign-10)
+#                      
+#      add_test(NAME crypto-cose-sign-15
+#               COMMAND lws-crypto-cose-sign -k set1.cks
+#                      --stdout r3.txt
+#                      --stdin ctest-sig-hmac512.sig)
+#      set_tests_properties(crypto-cose-sign-15
+#                           PROPERTIES DEPENDS crypto-cose-sign-11)
+#                           
+#      add_test(NAME crypto-cose-sign-16
+#               COMMAND lws-crypto-cose-sign -k set1.cks
+#                      --stdout r4.txt
+#                      --stdin ctest-sig-hmac256_64.sig)
+#      set_tests_properties(crypto-cose-sign-16
+#                           PROPERTIES DEPENDS crypto-cose-sign-12)
+                            
+       # HMAC signing, cose-mac0
+
+       add_test(NAME crypto-cose-sign-17
+                COMMAND lws-crypto-cose-sign -s -k set1.cks --kid our-secret
+                       --alg HS256 --cose-mac0
+                       --stdin payload.txt
+                       --stdout ctest-sig-hmac0256.sig)
+       add_test(NAME crypto-cose-sign-18
+                COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec-48
+                       --alg HS384 --cose-mac0
+                       --stdin payload.txt
+                       --stdout ctest-sig-hmac0384.sig)
+       add_test(NAME crypto-cose-sign-19
+                COMMAND lws-crypto-cose-sign -s -k set1.cks --kid sec-64
+                       --alg HS512 --cose-mac0
+                       --stdin payload.txt
+                       --stdout ctest-sig-hmac0512.sig)
+       add_test(NAME crypto-cose-sign-20
+                COMMAND lws-crypto-cose-sign -s -k set1.cks --kid our-secret
+                       --alg HS256_64 --cose-mac0
+                       --stdin payload.txt
+                       --stdout ctest-sig-hmac0256_64.sig)
+
+       # HMAC validation, cose-mac0
+       
+       add_test(NAME crypto-cose-sign-21
+                COMMAND lws-crypto-cose-sign -k set1.cks
+                       --stdout r1.txt
+                       --stdin ctest-sig-hmac0256.sig)
+       set_tests_properties(crypto-cose-sign-21
+                            PROPERTIES DEPENDS crypto-cose-sign-17)
+                       
+       add_test(NAME crypto-cose-sign-22
+                COMMAND lws-crypto-cose-sign -k set1.cks
+                       --stdout r2.txt
+                       --stdin ctest-sig-hmac0384.sig)
+       set_tests_properties(crypto-cose-sign-22
+                            PROPERTIES DEPENDS crypto-cose-sign-18)
+                       
+       add_test(NAME crypto-cose-sign-23
+                COMMAND lws-crypto-cose-sign -k set1.cks
+                       --stdout r3.txt
+                       --stdin ctest-sig-hmac0512.sig)
+       set_tests_properties(crypto-cose-sign-23
+                            PROPERTIES DEPENDS crypto-cose-sign-19)
+                            
+       add_test(NAME crypto-cose-sign-24
+                COMMAND lws-crypto-cose-sign -k set1.cks
+                       --stdout r4.txt
+                       --stdin ctest-sig-hmac0256_64.sig)
+       set_tests_properties(crypto-cose-sign-24
+                            PROPERTIES DEPENDS crypto-cose-sign-20)
+
+
+       set_tests_properties(crypto-cose-sign-1
+                            crypto-cose-sign-2
+                            crypto-cose-sign-3
+                            crypto-cose-sign-4
+                            crypto-cose-sign-5
+                            crypto-cose-sign-6
+                            crypto-cose-sign-7
+                            crypto-cose-sign-8
+#                           crypto-cose-sign-9
+#                           crypto-cose-sign-10
+#                           crypto-cose-sign-11
+#                           crypto-cose-sign-12
+#                           crypto-cose-sign-13
+#                           crypto-cose-sign-14
+#                           crypto-cose-sign-15
+#                           crypto-cose-sign-16
+                            crypto-cose-sign-17
+                            crypto-cose-sign-18
+                            crypto-cose-sign-19
+                            crypto-cose-sign-20
+                            crypto-cose-sign-21
+                            crypto-cose-sign-22
+                            crypto-cose-sign-23
+                            crypto-cose-sign-24
+
+                            PROPERTIES
+                               WORKING_DIRECTORY
+                                       ${CMAKE_SOURCE_DIR}/minimal-examples/crypto/minimal-crypto-cose-sign
+                               TIMEOUT 5)
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/README.md b/minimal-examples/crypto/minimal-crypto-cose-sign/README.md
new file mode 100644 (file)
index 0000000..f241d75
--- /dev/null
@@ -0,0 +1,105 @@
+# lws minimal example for cose_sign
+
+Demonstrates how to sign and verify using cose_sign and cose_key, providing a
+commandline tool for signing and verifying stdin.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+|Option|Sig|Val|Meaning|
+|---|---|---|---|
+|-s|o|||Select signing mode (stdin is payload)|
+|-k <keyset filepath>|o|o|One or a set of cose_keys|
+|--kid string|o|mac0|Specifies the key ID to use as a string|
+|--kid-hex HEXSTRING|o|mac0|Specifies the key ID to use as a hex blob|
+|--cose-sign|o|if no tag|Sets cose-sign mode|
+|--cose-sign1|o|if no tag|Sets cose-sign1 mode|
+|--cose-mac|o|if no tag|Sets cose-sign1 mode|
+|--cose-mac0|o|if no tag|Sets cose-sign1 mode|
+|--extra HEXSTRING|o|o|Optional extra payload data|
+
+HEXSTRING above means a string like `1a2b3c`
+
+Stdin is either the plaintext (if signing) or cose_sign (if verifying).
+
+For convenience, a keyset from the COSE RFC is provided in
+`minimal-examples/crypto/minimal-crypto-cose-sign/set1.cks`.  Six example
+cose_sign1 and cose_sign are also provided in that directory signed with keys
+from the provided keyset.
+
+## Examples
+
+### Validation
+
+The RFC8152 sign1_pass01.sig is a cose_sign1 that contains the ES256 alg
+parameter along with a kid hint that it was signed with the key with kid "11"
+from the RFC8152 key set.  So we just need to provide the signature and the key
+set and lws can sort it out.
+
+```
+$ cat sign1_pass01.sig | ./lws-crypto-cose-sign -k set1.cks
+[2021/07/26 05:41:29:1663] N: lws_create_context: LWS: 4.2.99-v4.2.0-133-g300f3f3250, NET CLI SRV H1 H2 WS ConMon IPV6-on
+[2021/07/26 05:41:29:3892] N: results count 1
+[2021/07/26 05:41:29:3901] N: result: 0 (alg ES256, kid 3131)
+[2021/07/26 05:41:29:4168] N: main: PASS
+```
+
+Notice how the validation just delivers a results list and leaves it to the user
+code to iterate it, and confirm that it's happy with the result, the alg used,
+and the kid that was used.
+
+RFC8152 sign1_pass02.sig is similar but contains extra application data in the
+signature, that must be given at validation too.
+
+```
+$cat sign1_pass02.sig | ./lws-crypto-cose-sign -k set1.cks --extra 11aa22bb33cc44dd55006699
+[2021/07/26 05:55:50:9103] N: lws_create_context: LWS: 4.2.99-v4.2.0-133-g300f3f3250, NET CLI SRV H1 H2 WS ConMon IPV6-on
+[2021/07/26 05:55:50:9381] N: 12
+[2021/07/26 05:55:51:0924] N: 
+[2021/07/26 05:55:51:0939] N: 0000: 11 AA 22 BB 33 CC 44 DD 55 00 66 99                ..".3.D.U.f.    
+[2021/07/26 05:55:51:0943] N: 
+[2021/07/26 05:55:51:1368] N: results count 1
+[2021/07/26 05:55:51:1377] N: result: 0 (alg ES256, kid 3131)
+[2021/07/26 05:55:51:1657] N: main: PASS
+```
+
+### Signing
+
+Generate a cose-sign1 using ES256 and the key set key with id "11" for the
+payload given on stdin
+
+```
+$ echo -n "This is the content." |\
+   ./bin/lws-crypto-cose-sign -s -k set1.cks \
+   --kid 11 --alg ES256 > ./test.sig
+
+00000000  d2 84 43 a1 01 26 a1 04  42 31 31 54 54 68 69 73  |..C..&..B11TThis|
+00000010  20 69 73 20 74 68 65 20  63 6f 6e 74 65 6e 74 2e  | is the content.|
+00000020  58 40 b9 a8 85 09 17 7f  01 f6 78 5d 39 62 d0 44  |X@........x]9b.D|
+00000030  08 0b fa b4 b4 5b 17 80  c2 e3 ba a3 af 33 6f e6  |.....[.......3o.|
+00000040  44 09 13 1f cf 4f 17 5c  62 9f 8d 29 29 1c ab 28  |D....O.\b..))..(|
+00000050  b2 f4 e6 af f9 62 ea 69  52 90 07 0e 2c 40 72 d3  |.....b.iR...,@r.|
+00000060  12 cf                                             |..|
+
+```
+
+Same as above, but force it to use cose-sign layout
+
+```
+$ echo -n "This is the content." |\
+   ./bin/lws-crypto-cose-sign -s -k set1.cks \
+   --kid 11 --alg ES256 --cose-sign > ./test.sig
+
+00000000  d8 62 84 40 40 54 54 68  69 73 20 69 73 20 74 68  |.b.@@TThis is th|
+00000010  65 20 63 6f 6e 74 65 6e  74 2e 81 83 a1 01 26 a1  |e content.....&.|
+00000020  04 42 31 31 58 40 37 5d  93 48 20 b0 d0 75 16 41  |.B11X@7].H ..u.A|
+00000030  db 95 95 5b 39 7d 6d 92  6e 52 c9 78 96 d8 a2 9b  |...[9}m.nR.x....|
+00000040  62 62 89 9e e5 26 31 63  4b 90 d1 37 86 ca 82 a2  |bb...&1cK..7....|
+00000050  28 9a d2 82 a7 6d 24 23  cd de 58 91 47 98 bb 11  |(....m$#..X.G...|
+00000060  e4 b9 08 18 48 65                                 |....He|
+```
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/main.c b/minimal-examples/crypto/minimal-crypto-cose-sign/main.c
new file mode 100644 (file)
index 0000000..c1e8e58
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * lws-minimal-crypto-cose-sign
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+static int fdin = 0, fdout = 1;
+static uint8_t extra[4096];
+static size_t ext_len;
+
+int
+_alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
+               size_t *amount)
+{
+       FILE *f;
+       size_t s;
+       ssize_t m;
+       int n = 0;
+
+       f = fopen(filename, "rb");
+       if (f == NULL) {
+               n = 1;
+               goto bail;
+       }
+
+       if (fseek(f, 0, SEEK_END) != 0) {
+               n = 1;
+               goto bail;
+       }
+
+       m = ftell(f);
+       if (m == -1l) {
+               n = 1;
+               goto bail;
+       }
+       s = (size_t)m;
+
+       if (fseek(f, 0, SEEK_SET) != 0) {
+               n = 1;
+               goto bail;
+       }
+
+       *buf = malloc(s + 1);
+       if (!*buf) {
+               n = 2;
+               goto bail;
+       }
+
+       if (fread(*buf, s, 1, f) != 1) {
+               free(*buf);
+               n = 1;
+               goto bail;
+       }
+
+       *amount = s;
+
+bail:
+       if (f)
+               fclose(f);
+
+       return n;
+
+}
+
+static int
+extra_cb(lws_cose_sig_ext_pay_t *x)
+{
+       x->ext = extra;
+       x->xl = ext_len;
+
+       // lwsl_hexdump_notice(extra, ext_len);
+
+       return 0;
+}
+
+int
+pay_cb(struct lws_cose_validate_context *cps, void *opaque,
+       const uint8_t *paychunk, size_t paychunk_len)
+{
+       write(fdout, paychunk, paychunk_len);
+
+       return 0;
+}
+
+int main(int argc, const char **argv)
+{
+       uint8_t *ks, temp[256], *kid = NULL, ktmp[4096], sbuf[512];
+       int n, m, sign = 0, result = 1,
+           logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       enum lws_cose_sig_types sigtype = SIGTYPE_UNKNOWN;
+       struct lws_cose_validate_context *cps = NULL;
+       struct lws_cose_sign_context *csc = NULL;
+       const struct lws_gencrypto_keyelem *ke;
+       struct lws_context_creation_info info;
+       lws_cose_validate_create_info_t vi;
+       struct lws_buflist *paybuf = NULL;
+       lws_cose_sign_create_info_t i;
+       struct lws_context *context;
+       size_t ks_len, kid_len = 0;
+       lws_cose_key_t *ck = NULL;
+       lws_dll2_owner_t *o, set;
+       lws_lec_pctx_t lec;
+       cose_param_t alg;
+       const char *p;
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+
+       lwsl_user("LWS cose-sign example tool -k keyset [-s alg-name kid ]\n");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "--stdin"))) {
+               fdin = open(p, LWS_O_RDONLY, 0);
+               if (fdin < 0) {
+                       lwsl_err("%s: unable to open stdin file\n", __func__);
+                       return 1;
+               }
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "--stdout"))) {
+               fdout = open(p, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC, 0600);
+               if (fdout < 0) {
+                       lwsl_err("%s: unable to open stdout file\n", __func__);
+                       goto bail_early;
+               }
+       }
+
+       /*
+        * If no tag, you can tell it the signature type, otherwise it will
+        * use the tag to select the right type without these
+        */
+
+       if (lws_cmdline_option(argc, argv, "--cose-sign"))
+               sigtype = SIGTYPE_MULTI;
+
+       if (lws_cmdline_option(argc, argv, "--cose-sign1"))
+               sigtype = SIGTYPE_SINGLE;
+
+       if (lws_cmdline_option(argc, argv, "--cose-mac"))
+               sigtype = SIGTYPE_MAC;
+
+       if (lws_cmdline_option(argc, argv, "--cose-mac0"))
+               sigtype = SIGTYPE_MAC0;
+
+       /* if signing, set the ciphers */
+
+       if (lws_cmdline_option(argc, argv, "-s"))
+               sign = 1;
+
+       if ((p = lws_cmdline_option(argc, argv, "--kid"))) {
+               kid = (uint8_t *)p;
+               kid_len = strlen(p);
+               //lwsl_hexdump_notice(kid, kid_len);
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "--kid-hex"))) {
+               kid_len = (size_t)lws_hex_to_byte_array(p, ktmp, sizeof(ktmp));
+               kid = (uint8_t *)ktmp;
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "--extra"))) {
+               ext_len = (size_t)lws_hex_to_byte_array(p, extra, sizeof(extra));
+               lwsl_notice("%llu\n", (unsigned long long)ext_len);
+               if (ext_len == (size_t)-1ll)
+                       ext_len = 0;
+       }
+
+       /* grab the key */
+
+       if (!(p = lws_cmdline_option(argc, argv, "-k"))) {
+               lwsl_err("-k <key set file> is required\n");
+               goto bail;
+       }
+
+       if (_alloc_file(context, p, &ks, &ks_len)) {
+               lwsl_err("%s: unable to load %s\n", __func__, p);
+               goto bail;
+       }
+
+       lws_dll2_owner_clear(&set);
+       if (!lws_cose_key_import(&set, NULL, NULL, ks, ks_len)) {
+               lwsl_notice("%s: key import fail\n", __func__);
+               free(ks);
+               goto bail2;
+       }
+
+       free(ks);
+
+       if (!fdin) {
+               struct timeval  timeout;
+               fd_set  fds;
+
+               FD_ZERO(&fds);
+               FD_SET(0, &fds);
+
+               timeout.tv_sec  = 0;
+               timeout.tv_usec = 1000;
+
+               if (select(fdin + 1, &fds, NULL, NULL, &timeout) < 0 ||
+                   !FD_ISSET(0, &fds)) {
+                       lwsl_err("%s: pass cose_sign or plaintext "
+                                "on stdin or --stdin\n", __func__);
+                       goto bail2;
+               }
+       }
+
+       if (sign) {
+               uint8_t *ppay;
+               size_t s;
+
+               p = lws_cmdline_option(argc, argv, "--alg");
+               if (!p) {
+                       lwsl_err("%s: need to specify alg (eg, ES256) "
+                                "when signing\n", __func__);
+                       goto bail2;
+               }
+               alg = lws_cose_name_to_alg(p);
+
+               lws_lec_init(&lec, sbuf, sizeof(sbuf));
+               memset(&i, 0, sizeof(i));
+               i.cx            = context;
+               i.keyset        = &set;
+               i.lec           = &lec;
+               i.flags         = LCSC_FL_ADD_CBOR_TAG |
+                                 LCSC_FL_ADD_CBOR_PREFER_MAC0;
+               i.sigtype       = sigtype;
+
+               /*
+                * Unfortunately, with COSE we must know the payload length
+                * before we have seen the payload.  It's illegal to use
+                * indeterminite lengths inside COSE objects.
+                */
+
+               do {
+                       n = (int)read(fdin, temp, sizeof(temp));
+                       if (n < 0)
+                               goto bail3;
+                       if (!n)
+                               break;
+
+                       s = (size_t)n;
+
+                       if (lws_buflist_append_segment(&paybuf, temp, s) < 0)
+                               goto bail3;
+                       i.inline_payload_len += s;
+
+               } while (1);
+
+       //      lwsl_notice("%s: inline_payload_len %llu\n", __func__,
+       //                      (unsigned long long)i.inline_payload_len);
+
+               csc = lws_cose_sign_create(&i);
+               if (!csc)
+                       goto bail2;
+               ck = lws_cose_key_from_set(&set, kid, kid_len);
+               if (!ck)
+                       goto bail2;
+
+               if (lws_cose_sign_add(csc, alg, ck))
+                       goto bail2;
+
+               do {
+                       s = lws_buflist_next_segment_len(&paybuf, &ppay);
+                       if (!s)
+                               break;
+
+                       do {
+                               m = (int)lws_cose_sign_payload_chunk(csc,
+                                                                    ppay, s);
+                               if (lec.used) {
+                                       // lwsl_hexdump_err(sbuf, lec.used);
+                                       write(fdout, sbuf, lec.used);
+                                       lws_lec_setbuf(&lec, sbuf, sizeof(sbuf));
+                               }
+                       } while (m == LCOSESIGEXTCB_RET_AGAIN);
+
+                       if (m == LWS_LECPCTX_RET_FAIL)
+                               goto bail2;
+
+                       if (lec.used) {
+                               write(fdout, sbuf, lec.used);
+                               lws_lec_setbuf(&lec, sbuf, sizeof(sbuf));
+                       }
+
+                       lws_buflist_use_segment(&paybuf, s);
+               } while(1);
+
+       } else {
+               memset(&vi, 0, sizeof(vi));
+
+               vi.cx           = context;
+               vi.keyset       = &set;
+               vi.sigtype      = sigtype;
+               vi.ext_cb       = extra_cb;
+               vi.ext_opaque   = extra;
+               vi.ext_len      = ext_len;
+               vi.pay_cb       = pay_cb;
+
+               cps = lws_cose_validate_create(&vi);
+               if (!cps) {
+                       lwsl_notice("%s: sign_val_create fail\n", __func__);
+                       goto bail;
+               }
+
+               do {
+                       n = (int)read(fdin, temp, sizeof(temp));
+                       if (n < 0)
+                               goto bail3;
+                       if (!n)
+                               break;
+
+                       n = lws_cose_validate_chunk(cps, temp, (size_t)n, NULL);
+                       if (n && n != LECP_CONTINUE) {
+                               lwsl_err("%s: chunk validation failed: %d\n",
+                                               __func__, n);
+                               goto bail2;
+                       }
+               } while (1);
+       }
+
+bail3:
+
+       result = 0;
+
+       if (!sign) {
+               char buf[2048];
+               int os;
+
+               o = lws_cose_validate_results(cps);
+               if (!o)
+                       result = 1;
+               else {
+                       os = lws_snprintf(buf, sizeof(buf),
+                                         "\nresults count %d\n", o->count);
+                       write(fdout, buf, (size_t)os);
+
+                       if (!o->count)
+                               result = 1;
+               }
+
+               lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
+                                          lws_dll2_get_head(o)) {
+                       lws_cose_validate_res_t *res = lws_container_of(p,
+                                               lws_cose_validate_res_t, list);
+                       char khr[256];
+
+                       khr[0] = '\0';
+                       if (res->cose_key) {
+                               ke = &res->cose_key->meta[COSEKEY_META_KID];
+                               if (ke && ke->buf)
+                                       lws_hex_from_byte_array(ke->buf, ke->len,
+                                                       khr, sizeof(khr));
+                       }
+                       os = lws_snprintf(buf, sizeof(buf),
+                                   " result: %d (alg %s, kid %s)\n",
+                                   res->result,
+                                   lws_cose_alg_to_name(res->cose_alg), khr);
+                       write(fdout, buf, (size_t)os);
+                       result |= res->result;
+               } lws_end_foreach_dll_safe(p, tp);
+       }
+
+bail2:
+       if (!sign)
+               lws_cose_validate_destroy(&cps);
+       else {
+               lws_buflist_destroy_all_segments(&paybuf);
+               lws_cose_sign_destroy(&csc);
+       }
+//bail1:
+       lws_cose_key_set_destroy(&set);
+bail:
+       lws_context_destroy(context);
+
+       if (result)
+               lwsl_err("%s: FAIL: %d\n", __func__, result);
+       else
+               lwsl_notice("%s: PASS\n", __func__);
+
+bail_early:
+       if (fdin > 0)
+               close(fdin);
+       if (fdout != 1 && fdout >= 0)
+               close(fdout);
+
+       return result;
+}
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/payload.txt b/minimal-examples/crypto/minimal-crypto-cose-sign/payload.txt
new file mode 100644 (file)
index 0000000..402bd7c
--- /dev/null
@@ -0,0 +1 @@
+The Test Payload
\ No newline at end of file
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/rsa-4096.ck b/minimal-examples/crypto/minimal-crypto-cose-sign/rsa-4096.ck
new file mode 100644 (file)
index 0000000..8b3fddb
Binary files /dev/null and b/minimal-examples/crypto/minimal-crypto-cose-sign/rsa-4096.ck differ
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/set1.cks b/minimal-examples/crypto/minimal-crypto-cose-sign/set1.cks
new file mode 100644 (file)
index 0000000..e5eca18
Binary files /dev/null and b/minimal-examples/crypto/minimal-crypto-cose-sign/set1.cks differ
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/sign-rsa4096.sig b/minimal-examples/crypto/minimal-crypto-cose-sign/sign-rsa4096.sig
new file mode 100644 (file)
index 0000000..a233d68
Binary files /dev/null and b/minimal-examples/crypto/minimal-crypto-cose-sign/sign-rsa4096.sig differ
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass01.sig b/minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass01.sig
new file mode 100644 (file)
index 0000000..d78767e
Binary files /dev/null and b/minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass01.sig differ
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass02.sig b/minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass02.sig
new file mode 100644 (file)
index 0000000..2b53930
--- /dev/null
@@ -0,0 +1 @@
\84\ 1\ 4B11TThis is the content.X@\10r\9c×\11Ë8\13ØØéD¨Úq\11ç²XɽÊa5÷®\1aÛî\95       \89\12g\83~\1e3½6ÁP2jæ'Uƽ\8eT\f>\8f\92×Ò%èÛr¸\82\v
\ No newline at end of file
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass03.sig b/minimal-examples/crypto/minimal-crypto-cose-sign/sign1_pass03.sig
new file mode 100644 (file)
index 0000000..a10fc96
--- /dev/null
@@ -0,0 +1 @@
+\84\ 1\ 4B11TThis is the content.X@\8e³>L£\1d\1cFZ°Z¬4Ìk#Õ\8fï\\b1\ 6ÄÒZ\91®ð°\11~*ù¢\91ª2áJ¸4ÜVí*"4DT~\ 1ñ\1d;       \16å¤ÃEÊË6
\ No newline at end of file
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/sign_pass01.sig b/minimal-examples/crypto/minimal-crypto-cose-sign/sign_pass01.sig
new file mode 100644 (file)
index 0000000..268b086
--- /dev/null
@@ -0,0 +1 @@
+Øb\84A  TThis is the content.\81\83\ 1\ 4B11X@⮯Ô\r\9dþnR\a|]\7fôä\b(,¾û]\ 6Ëô\14¯.\19Ù\82¬E¬\98¸TL\90\8bE\aÞ\1e\90·\17ÃÓH\16þ\92j+\98õ:ý/ ó
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/sign_pass02.sig b/minimal-examples/crypto/minimal-crypto-cose-sign/sign_pass02.sig
new file mode 100644 (file)
index 0000000..b80f7a2
--- /dev/null
@@ -0,0 +1 @@
+Øb\84@ TThis is the content.\81\83\ 1\ 4B11X@˸ÚÙ¾¯¸\90á¤\14\12M\8bûÂkíò©OËZ\88$2¿öÖ>\15õtQØ?¢Ëö&rëôÇÙ\93°ôÂDvGØ1ºW̨k\93
diff --git a/minimal-examples/crypto/minimal-crypto-cose-sign/sign_pass03.sig b/minimal-examples/crypto/minimal-crypto-cose-sign/sign_pass03.sig
new file mode 100644 (file)
index 0000000..60d8f03
--- /dev/null
@@ -0,0 +1 @@
+\84@ TThis is the content.\81\83\ 1\ 4B11X@⮯Ô\r\9dþnR\a|]\7fôä\b(,¾û]\ 6Ëô\14¯.\19Ù\82¬E¬\98¸TL\90\8bE\aÞ\1e\90·\17ÃÓH\16þ\92j+\98õ:ý/ ó
index 05f7376..4896dfc 100644 (file)
@@ -1,77 +1,23 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-crypto-jwe C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-crypto-jwe)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_JOSE 1 requirements)
 
 if (requirements)
-
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 9bd2676..883f0b6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-crypto-jwe
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
@@ -97,7 +97,9 @@ int main(int argc, const char **argv)
        lwsl_user("LWS JWE example tool\n");
 
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
        info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
        info.options = 0;
 
        context = lws_create_context(&info);
@@ -140,20 +142,23 @@ int main(int argc, const char **argv)
                        return 1;
                }
 
-               jwe.jws.map.len[LJWS_JOSE] = lws_snprintf(
-                               (char *)jwe.jws.map.buf[LJWS_JOSE], temp_len,
+               jwe.jws.map.len[LJWS_JOSE] = (uint32_t)lws_snprintf(
+                               (char *)jwe.jws.map.buf[LJWS_JOSE], (unsigned int)temp_len,
                                "{\"alg\":\"%s\",\"enc\":\"%s\"}", p, sp + 1);
 
                enc = 1;
        }
 
        in = lws_concat_temp(temp, temp_len);
-       n = read(0, in, temp_len);
+       n = (int)read(0, in, (unsigned int)temp_len);
        if (n < 0) {
                lwsl_err("Problem reading from stdin\n");
                return 1;
        }
-       temp_len -= n;
+
+       /* account for padding as well */
+
+       temp_len -= (int)lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN, (unsigned int)n);
 
        /* grab the key */
 
@@ -174,7 +179,7 @@ int main(int argc, const char **argv)
                /* point CTXT to the plaintext we read from stdin */
 
                jwe.jws.map.buf[LJWE_CTXT] = in;
-               jwe.jws.map.len[LJWE_CTXT] = n;
+               jwe.jws.map.len[LJWE_CTXT] = (uint32_t)n;
 
                /*
                 * Create a random CEK and set EKEY to it
@@ -184,7 +189,7 @@ int main(int argc, const char **argv)
                n = lws_gencrypto_bits_to_bytes(jwe.jose.enc_alg->keybits_fixed);
                if (lws_jws_randomize_element(context, &jwe.jws.map, LJWE_EKEY,
                                              lws_concat_temp(temp, temp_len),
-                                             &temp_len, n,
+                                             &temp_len, (unsigned int)n,
                                              LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) {
                        lwsl_err("Problem getting random\n");
                        goto bail1;
@@ -216,7 +221,11 @@ int main(int argc, const char **argv)
                if (lws_cmdline_option(argc, argv, "-c"))
                        format_c(compact);
                else
-                       if (write(1, compact, strlen(compact)) < 0) {
+                       if (write(1, compact,
+#if defined(WIN32)
+                                       (unsigned int)
+#endif
+                                       strlen(compact)) < 0) {
                                lwsl_err("Write stdout failed\n");
                                goto bail1;
                        }
index fb8c3e3..a5b2d07 100644 (file)
@@ -1,77 +1,23 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-crypto-jwk C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-crypto-jwk)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_JOSE 1 requirements)
 
 if (requirements)
-
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index f962136..db62457 100644 (file)
@@ -104,7 +104,9 @@ int main(int argc, const char **argv)
        }
 
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
        info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
        info.options = 0;
 
        context = lws_create_context(&info);
@@ -123,16 +125,16 @@ int main(int argc, const char **argv)
        }
 
        if ((p = lws_cmdline_option(argc, argv, "--kid")))
-               lws_jwk_strdup_meta(&jwk, JWK_META_KID, p, strlen(p));
+               lws_jwk_strdup_meta(&jwk, JWK_META_KID, p, (int)strlen(p));
 
        if ((p = lws_cmdline_option(argc, argv, "--use")))
-               lws_jwk_strdup_meta(&jwk, JWK_META_USE, p, strlen(p));
+               lws_jwk_strdup_meta(&jwk, JWK_META_USE, p, (int)strlen(p));
 
        if ((p = lws_cmdline_option(argc, argv, "--alg")))
-               lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, strlen(p));
+               lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
 
        if ((p = lws_cmdline_option(argc, argv, "--key-ops")))
-               lws_jwk_strdup_meta(&jwk, JWK_META_KEY_OPS, p, strlen(p));
+               lws_jwk_strdup_meta(&jwk, JWK_META_KEY_OPS, p, (int)strlen(p));
 
        if ((p = lws_cmdline_option(argc, argv, "--public")) &&
            kty != LWS_GENCRYPTO_KTY_OCT) {
@@ -156,7 +158,11 @@ int main(int argc, const char **argv)
                if (lws_cmdline_option(argc, argv, "-c"))
                        format_c(fd, key);
                else {
-                       if (write(fd, key, strlen(key)) < 0) {
+                       if (write(fd, key,
+#if defined(WIN32)
+                                       (unsigned int)
+#endif
+                                       strlen(key)) < 0) {
                                lwsl_err("Write public failed\n");
                                return 1;
                        }
@@ -167,7 +173,7 @@ int main(int argc, const char **argv)
 
        /* private version */
 
-       if (lws_jwk_export(&jwk, 1, key, &vl) < 0) {
+       if (lws_jwk_export(&jwk, LWSJWKF_EXPORT_PRIVATE, key, &vl) < 0) {
                lwsl_err("lws_jwk_export failed\n");
 
                return 1;
@@ -177,7 +183,11 @@ int main(int argc, const char **argv)
                if (format_c(1, key) < 0)
                        return 1;
        } else
-               if (write(1, key, strlen(key)) < 0) {
+               if (write(1, key,
+#if defined(WIN32)
+                               (unsigned int)
+#endif
+                               strlen(key)) < 0) {
                        lwsl_err("Write stdout failed\n");
                        return 1;
                }
index ddf9579..b566fb2 100644 (file)
@@ -1,66 +1,13 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-crypto-jws C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-crypto-jws)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_JOSE 1 requirements)
 
@@ -69,9 +16,9 @@ if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 5879fa9..d579aab 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-crypto-jws
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
@@ -35,7 +35,9 @@ int main(int argc, const char **argv)
        lwsl_user("LWS JWS example tool\n");
 
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
        info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
        info.options = 0;
 
        context = lws_create_context(&info);
@@ -67,14 +69,14 @@ int main(int argc, const char **argv)
                        return 1;
                }
 
-               jws.map.len[LJWS_JOSE] =
+               jws.map.len[LJWS_JOSE] = (uint32_t)
                                lws_snprintf((char *)jws.map.buf[LJWS_JOSE],
-                                            temp_len, "{\"alg\":\"%s\"}", p);
+                                            (unsigned int)temp_len, "{\"alg\":\"%s\"}", p);
                sign = 1;
        }
 
        in = lws_concat_temp(temp, temp_len);
-       n = read(0, in, temp_len);
+       n = (int)read(0, in, (unsigned int)temp_len);
        if (n < 0) {
                lwsl_err("Problem reading from stdin\n");
                return 1;
@@ -99,7 +101,7 @@ int main(int argc, const char **argv)
                /* add the plaintext from stdin to the map and a b64 version */
 
                jws.map.buf[LJWS_PYLD] = in;
-               jws.map.len[LJWS_PYLD] = n;
+               jws.map.len[LJWS_PYLD] = (unsigned int)n;
 
                if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_PYLD,
                                               lws_concat_temp(temp, temp_len),
@@ -119,7 +121,7 @@ int main(int argc, const char **argv)
 
                if (lws_jws_alloc_element(&jws.map_b64, LJWS_SIG,
                                      lws_concat_temp(temp, temp_len),
-                                     &temp_len, lws_base64_size(
+                                     &temp_len, (unsigned int)lws_base64_size(
                                         LWS_JWE_LIMIT_KEY_ELEMENT_BYTES), 0)) {
                        lwsl_err("%s: temp space too small\n", __func__);
                        goto bail1;
@@ -137,7 +139,7 @@ int main(int argc, const char **argv)
                        goto bail1;
                }
                /* set the actual b64 signature size */
-               jws.map_b64.len[LJWS_SIG] = n;
+               jws.map_b64.len[LJWS_SIG] = (uint32_t)n;
 
                if (lws_cmdline_option(argc, argv, "-f"))
                        /* create the flattened representation */
@@ -152,7 +154,11 @@ int main(int argc, const char **argv)
 
                /* dump the compact JWS representation on stdout */
 
-               if (write(1, compact, strlen(compact))  < 0) {
+               if (write(1, compact,
+#if defined(WIN32)
+                               (unsigned int)
+#endif
+                               strlen(compact))  < 0) {
                        lwsl_err("Write stdout failed\n");
                        goto bail1;
                }
@@ -161,7 +167,7 @@ int main(int argc, const char **argv)
                /* perform the verify directly on the compact representation */
 
                if (lws_cmdline_option(argc, argv, "-f")) {
-                       if (lws_jws_sig_confirm_json(in, n, &jws, &jwk, context,
+                       if (lws_jws_sig_confirm_json(in, (unsigned int)n, &jws, &jwk, context,
                                        lws_concat_temp(temp, temp_len),
                                        &temp_len) < 0) {
                                lwsl_notice("%s: confirm rsa sig failed\n",
@@ -177,7 +183,7 @@ int main(int argc, const char **argv)
                        }
                } else {
                        if (lws_jws_sig_confirm_compact_b64(in,
-                                       lws_concat_used(temp, temp_len),
+                                       lws_concat_used(temp, (unsigned int)temp_len),
                                        &map, &jwk, context,
                                        lws_concat_temp(temp, temp_len),
                                        &temp_len) < 0) {
index 327cdcd..74d7732 100644 (file)
@@ -1,66 +1,13 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-crypto-x509 C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-crypto-x509)
 set(SRCS main.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_WITH_JOSE 1 requirements)
 
@@ -69,9 +16,9 @@ if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 64875fb..7a3bc3b 100644 (file)
@@ -19,7 +19,7 @@ read_pem(const char *filename, char *pembuf, int pembuf_len)
        if (fd == -1)
                return -1;
 
-       n = read(fd, pembuf, pembuf_len - 1);
+       n = (int)read(fd, pembuf, (unsigned int)pembuf_len - 1);
        close(fd);
 
        pembuf[n++] = '\0';
@@ -43,7 +43,7 @@ read_pem_c509_cert(struct lws_x509_cert **x509, const char *filename,
                return -1;
        }
 
-       if (lws_x509_parse_from_pem(*x509, pembuf, n) < 0) {
+       if (lws_x509_parse_from_pem(*x509, pembuf, (unsigned int)n) < 0) {
                lwsl_err("%s: unable to parse PEM %s\n", __func__, filename);
                lws_x509_destroy(x509);
 
@@ -72,7 +72,9 @@ int main(int argc, const char **argv)
        lwsl_user("LWS X509 api example\n");
 
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+#if defined(LWS_WITH_NETWORK)
        info.port = CONTEXT_PORT_NO_LISTEN;
+#endif
        info.options = 0;
 
        context = lws_create_context(&info);
@@ -126,7 +128,7 @@ int main(int argc, const char **argv)
                }
 
                if ((p = lws_cmdline_option(argc, argv, "--alg")))
-                       lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, strlen(p));
+                       lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
 
                lwsl_info("JWK version of trusted cert:\n");
                lws_jwk_dump(&jwk);
@@ -143,7 +145,7 @@ int main(int argc, const char **argv)
        lwsl_info("JWK version of cert:\n");
 
        if ((p = lws_cmdline_option(argc, argv, "--alg")))
-               lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, strlen(p));
+               lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
 
        lws_jwk_dump(&jwk);
        /* only print public if he doesn't provide private */
@@ -164,7 +166,8 @@ int main(int argc, const char **argv)
 
                        goto bail3;
                }
-               if (lws_x509_jwk_privkey_pem(&jwk, pembuf, n, NULL)) {
+               if (lws_x509_jwk_privkey_pem(context, &jwk, pembuf,
+                                               (unsigned int)n, NULL)) {
                        lwsl_err("%s: unable to parse privkey %s\n",
                                        __func__, p);
 
@@ -172,13 +175,13 @@ int main(int argc, const char **argv)
                }
 
                if ((p = lws_cmdline_option(argc, argv, "--alg")))
-                       lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, strlen(p));
+                       lws_jwk_strdup_meta(&jwk, JWK_META_ALG, p, (int)strlen(p));
 
                lwsl_info("JWK version of cert + privkey:\n");
                lws_jwk_dump(&jwk);
                lwsl_notice("Issuing Cert + Private JWK on stdout\n");
                n = sizeof(pembuf);
-               if (lws_jwk_export(&jwk, 1, pembuf, &n))
+               if (lws_jwk_export(&jwk, LWSJWKF_EXPORT_PRIVATE, pembuf, &n))
                        puts(pembuf);
        }
 
index 674bb09..6496e17 100644 (file)
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-dbus-client C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
 include(CheckLibraryExists)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-dbus-client)
 set(SRCS minimal-dbus-client.c)
 
-if (NOT LWS_WITH_MINIMAL_EXAMPLES)
-       CHECK_LIBRARY_EXISTS(dbus-1 dbus_connection_set_watch_functions "" LWS_HAVE_LIBDBUS)
-       if (NOT LWS_HAVE_LIBDBUS)
-               message(FATAL_ERROR "Install dbus-devel, or libdbus-1-dev etc")
-       endif()
-
-       if (NOT LWS_DBUS_LIB)
-               set(LWS_DBUS_LIB "dbus-1")
-       endif()
-
-       if (NOT LWS_DBUS_INCLUDE1)
-               # look in fedora and debian / ubuntu place
-               if (EXISTS "/usr/include/dbus-1.0")
-                       set(LWS_DBUS_INCLUDE1 "/usr/include/dbus-1.0")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE1 to /usr/include/dbus-1.0 or wherever the main dbus includes are")
-               endif()
-       endif()
-
-       if (NOT LWS_DBUS_INCLUDE2)
-               # look in fedora... debian / ubuntu has the ARCH in the path...
-               if (EXISTS "/usr/lib64/dbus-1.0/include")
-                       set(LWS_DBUS_INCLUDE2 "/usr/lib64/dbus-1.0/include")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE2 to /usr/lib/ARCH-linux-gnu/dbus-1.0/include or wherever dbus-arch-deps.h is on your system")
-               endif()
-       endif()
-
-       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_DBUS_INCLUDE1};${LWS_DBUS_INCLUDE2})
-
-       if (NOT LWS_DBUS_INCLUDE1 OR NOT LWS_DBUS_INCLUDE2)
-               message(FATAL_ERROR "To build with libdbus, LWS_DBUS_INCLUDE1/2 must be given. See lib/roles/dbus/README.md")
-       endif()
-
-endif()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
+set(requirements 1)
+require_lws_config(LWS_ROLE_DBUS 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
+if (NOT MSVC AND NOT WIN32 AND requirements)
+       add_executable(${SAMP} ${SRCS})
 
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
+       if (NOT LWS_PLAT_FREERTOS)
+               find_package(PkgConfig QUIET)
+               pkg_check_modules(PC_DBUS1 dbus-1 QUIET)
+               list(APPEND LWS_DBUS_INCLUDE1 ${PC_DBUS1_INCLUDE_DIRS})
+               list(APPEND LWS_DBUS_LIB "${PC_DBUS1_LIBRARIES};dl")
        endif()
 
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-
+       if (LWS_DBUS_INCLUDE1)
+               include_directories("${LWS_DBUS_INCLUDE1}")
        endif()
-ENDMACRO()
-
-
-set(requirements 1)
-require_lws_config(LWS_ROLE_DBUS 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
-
-if (requirements)
-       add_executable(${SAMP} ${SRCS})
-       
-       include_directories("${LWS_DBUS_INCLUDE1}")
-       include_directories("${LWS_DBUS_INCLUDE2}")
-       list(APPEND LIB_LIST dbus-1)
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared ${LWS_DBUS_LIB})
        else()
-               target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB})
+               target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index dda46bf..5c69398 100644 (file)
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-dbus-ws-proxy-testclient C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
 include(CheckLibraryExists)
+include(LwsCheckRequirements)
 
-set(SAMP lws-minimal-dbus-ws-proxy-testclient)
-set(SRCS minimal-dbus-ws-proxy-testclient.c)
-
-if (NOT LWS_WITH_MINIMAL_EXAMPLES)
-       CHECK_LIBRARY_EXISTS(dbus-1 dbus_connection_set_watch_functions "" LWS_HAVE_LIBDBUS)
-       if (NOT LWS_HAVE_LIBDBUS)
-               message(FATAL_ERROR "Install dbus-devel, or libdbus-1-dev etc")
-       endif()
-
-       if (NOT LWS_DBUS_LIB)
-               set(LWS_DBUS_LIB "dbus-1")
-       endif()
-
-       if (NOT LWS_DBUS_INCLUDE1)
-               # look in fedora and debian / ubuntu place
-               if (EXISTS "/usr/include/dbus-1.0")
-                       set(LWS_DBUS_INCLUDE1 "/usr/include/dbus-1.0")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE1 to /usr/include/dbus-1.0 or wherever the main dbus includes are")
-               endif()
-       endif()
-
-       if (NOT LWS_DBUS_INCLUDE2)
-               # look in fedora... debian / ubuntu has the ARCH in the path...
-               if (EXISTS "/usr/lib64/dbus-1.0/include")
-                       set(LWS_DBUS_INCLUDE2 "/usr/lib64/dbus-1.0/include")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE2 to /usr/lib/ARCH-linux-gnu/dbus-1.0/include or wherever dbus-arch-deps.h is on your system")
-               endif()
-       endif()
-
-       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_DBUS_INCLUDE1};${LWS_DBUS_INCLUDE2})
-
-       if (NOT LWS_DBUS_INCLUDE1 OR NOT LWS_DBUS_INCLUDE2)
-               message(FATAL_ERROR "To build with libdbus, LWS_DBUS_INCLUDE1/2 must be given. See lib/roles/dbus/README.md")
-       endif()
-
-endif()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
+set(requirements 1)
+require_lws_config(LWS_ROLE_DBUS 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
+if (NOT MSVC AND NOT WIN32 AND requirements)
+       add_executable(${PROJECT_NAME} minimal-dbus-ws-proxy-testclient.c)
 
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
+       if (NOT LWS_PLAT_FREERTOS)
+               find_package(PkgConfig QUIET)
+               pkg_check_modules(PC_DBUS1 dbus-1 QUIET)
+               list(APPEND LWS_DBUS_INCLUDE1 ${PC_DBUS1_INCLUDE_DIRS})
+               list(APPEND LWS_DBUS_LIB "${PC_DBUS1_LIBRARIES};dl")
        endif()
 
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-
+       if (LWS_DBUS_INCLUDE1)
+               include_directories("${LWS_DBUS_INCLUDE1}")
        endif()
-ENDMACRO()
-
-
-set(requirements 1)
-require_lws_config(LWS_ROLE_DBUS 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
-
-if (requirements)
-       add_executable(${SAMP} ${SRCS})
-       
-       include_directories("${LWS_DBUS_INCLUDE1}")
-       include_directories("${LWS_DBUS_INCLUDE2}")
-       list(APPEND LIB_LIST dbus-1)
-
+       message("project ${PROJECT_NAME}")
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
-               add_dependencies(${SAMP} websockets_shared ${LWS_DBUS_LIB})
+               target_link_libraries(${PROJECT_NAME} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${PROJECT_NAME} websockets_shared ${LWS_DBUS_LIB})
        else()
-               target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB})
+               target_link_libraries(${PROJECT_NAME} websockets ${LWS_DBUS_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index d2818fa..c3d92ee 100644 (file)
@@ -43,6 +43,8 @@ enum lws_dbus_client_state {
 struct lws_dbus_ctx_wsproxy_client {
        struct lws_dbus_ctx ctx;
 
+       lws_sorted_usec_list_t sul;
+
        enum lws_dbus_client_state state;
 };
 
@@ -309,83 +311,56 @@ bail:
        return ret;
 }
 
-/*
- * Stub lws protocol, just so we can get synchronous timers conveniently.
- *
- * Set up a 1Hz timer and if our connection state is suitable, use that
- * to write mirror protocol drawing packets to the proxied ws connection
- */
-
-static int
-callback_just_timer(struct lws *wsi, enum lws_callback_reasons reason,
-                   void *user, void *in, size_t len)
+static void
+sul_timer(struct lws_sorted_usec_list *sul)
 {
        char payload[64];
        const char *ws_pkt = payload;
        DBusMessage *msg;
 
-       switch (reason) {
-       case LWS_CALLBACK_PROTOCOL_INIT:
-       case LWS_CALLBACK_USER:
-               lwsl_info("%s: LWS_CALLBACK_USER\n", __func__);
+       if (!dbus_ctx || dbus_ctx->state != LDCS_CONN_ONWARD)
+               goto again;
 
-               if (!dbus_ctx || dbus_ctx->state != LDCS_CONN_ONWARD)
-                       goto again;
-
-               if (autoexit_budget > 0) {
-                       if (!--autoexit_budget) {
-                               lwsl_notice("reached autoexit budget\n");
-                               interrupted = 1;
-                               break;
-                       }
+       if (autoexit_budget > 0) {
+               if (!--autoexit_budget) {
+                       lwsl_notice("reached autoexit budget\n");
+                       interrupted = 1;
+                       return;
                }
+       }
 
-               msg = dbus_message_new_method_call(THIS_BUSNAME, THIS_OBJECT,
-                                                  THIS_INTERFACE, "Send");
-               if (!msg)
-                       break;
-
-               lws_snprintf(payload, sizeof(payload), "d #%06X %d %d %d %d;",
-                            rand() & 0xffffff, rand() % 480, rand() % 300,
-                            rand() % 480, rand() % 300);
-
-               if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &ws_pkt,
-                                                  DBUS_TYPE_INVALID)) {
-                       dbus_message_unref(msg);
-                       break;
-               }
+       msg = dbus_message_new_method_call(THIS_BUSNAME, THIS_OBJECT,
+                                          THIS_INTERFACE, "Send");
+       if (!msg)
+               goto again;
 
-               if (!dbus_connection_send_with_reply(dbus_ctx->ctx.conn, msg,
-                                                    &dbus_ctx->ctx.pc,
-                                                   DBUS_TIMEOUT_USE_DEFAULT)) {
-                       lwsl_err("%s: unable to send\n", __func__);
-                       dbus_message_unref(msg);
-                       break;
-               }
+       lws_snprintf(payload, sizeof(payload), "d #%06X %d %d %d %d;",
+                    rand() & 0xffffff, rand() % 480, rand() % 300,
+                    rand() % 480, rand() % 300);
 
+       if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &ws_pkt,
+                                          DBUS_TYPE_INVALID)) {
                dbus_message_unref(msg);
-               dbus_pending_call_set_notify(dbus_ctx->ctx.pc,
-                                            pending_call_notify,
-                                            &dbus_ctx->ctx, NULL);
-               count_tx++;
-
-again:
-               lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
-                                              lws_get_protocol(wsi),
-                                              LWS_CALLBACK_USER, 2);
-               break;
-       default:
-               break;
+               goto again;
        }
 
-       return 0;
-}
+       if (!dbus_connection_send_with_reply(dbus_ctx->ctx.conn, msg,
+                                            &dbus_ctx->ctx.pc,
+                                           DBUS_TIMEOUT_USE_DEFAULT)) {
+               lwsl_err("%s: unable to send\n", __func__);
+               dbus_message_unref(msg);
+               goto again;
+       }
 
-static struct lws_protocols protocols[] = {
-               { "_just_timer", callback_just_timer, 0, 10, 0, NULL, 0 },
-               { }
-};
+       dbus_message_unref(msg);
+       dbus_pending_call_set_notify(dbus_ctx->ctx.pc,
+                                    pending_call_notify,
+                                    &dbus_ctx->ctx, NULL);
+       count_tx++;
 
+again:
+       lws_sul_schedule(context, 0, &dbus_ctx->sul, sul_timer, 2 * LWS_US_PER_SEC);
+}
 
 int main(int argc, const char **argv)
 {
@@ -413,7 +388,6 @@ int main(int argc, const char **argv)
 
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
        info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
-       info.protocols = protocols;
        context = lws_create_context(&info);
        if (!context) {
                lwsl_err("lws init failed\n");
@@ -431,6 +405,9 @@ int main(int argc, const char **argv)
        if (!dbus_ctx)
                goto bail1;
 
+       lws_sul_schedule(context, 0, &dbus_ctx->sul, sul_timer, LWS_US_PER_SEC);
+
+
        if (remote_method_call(dbus_ctx))
                goto bail2;
 
index 7260d5a..0c0b7cf 100644 (file)
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-dbus-server C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
 include(CheckLibraryExists)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-dbus-server)
 set(SRCS main.c)
 
-if (NOT LWS_WITH_MINIMAL_EXAMPLES)
-       CHECK_LIBRARY_EXISTS(dbus-1 dbus_connection_set_watch_functions "" LWS_HAVE_LIBDBUS)
-       if (NOT LWS_HAVE_LIBDBUS)
-               message(FATAL_ERROR "Install dbus-devel, or libdbus-1-dev etc")
-       endif()
-
-       if (NOT LWS_DBUS_LIB)
-               set(LWS_DBUS_LIB "dbus-1")
-       endif()
-
-       if (NOT LWS_DBUS_INCLUDE1)
-               # look in fedora and debian / ubuntu place
-               if (EXISTS "/usr/include/dbus-1.0")
-                       set(LWS_DBUS_INCLUDE1 "/usr/include/dbus-1.0")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE1 to /usr/include/dbus-1.0 or wherever the main dbus includes are")
-               endif()
-       endif()
-
-       if (NOT LWS_DBUS_INCLUDE2)
-               # look in fedora... debian / ubuntu has the ARCH in the path...
-               if (EXISTS "/usr/lib64/dbus-1.0/include")
-                       set(LWS_DBUS_INCLUDE2 "/usr/lib64/dbus-1.0/include")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE2 to /usr/lib/ARCH-linux-gnu/dbus-1.0/include or wherever dbus-arch-deps.h is on your system")
-               endif()
-       endif()
-
-       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_DBUS_INCLUDE1};${LWS_DBUS_INCLUDE2})
-
-       if (NOT LWS_DBUS_INCLUDE1 OR NOT LWS_DBUS_INCLUDE2)
-               message(FATAL_ERROR "To build with libdbus, LWS_DBUS_INCLUDE1/2 must be given. See lib/roles/dbus/README.md")
-       endif()
-
-endif()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
+set(requirements 1)
+require_lws_config(LWS_ROLE_DBUS 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
+if (NOT MSVC AND NOT WIN32 AND requirements)
+       add_executable(${SAMP} ${SRCS})
 
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
+       if (NOT LWS_PLAT_FREERTOS)
+               find_package(PkgConfig QUIET)
+               pkg_check_modules(PC_DBUS1 dbus-1 QUIET)
+               list(APPEND LWS_DBUS_INCLUDE1 ${PC_DBUS1_INCLUDE_DIRS})
+               list(APPEND LWS_DBUS_LIB "${PC_DBUS1_LIBRARIES};dl")
        endif()
 
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-
+       if (LWS_DBUS_INCLUDE1)
+               include_directories("${LWS_DBUS_INCLUDE1}")
        endif()
-ENDMACRO()
-
-
-set(requirements 1)
-require_lws_config(LWS_ROLE_DBUS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
-
-if (requirements)
-       add_executable(${SAMP} ${SRCS})
-       
-       include_directories("${LWS_DBUS_INCLUDE1}")
-       include_directories("${LWS_DBUS_INCLUDE2}")
-       list(APPEND LIB_LIST dbus-1)
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared ${LWS_DBUS_LIB})
        else()
-               target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB})
+               target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index bad9ec3..cd699a2 100644 (file)
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-dbus-ws-proxy C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
 include(CheckLibraryExists)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-dbus-ws-proxy)
 set(SRCS main.c)
 
-if (NOT LWS_WITH_MINIMAL_EXAMPLES)
-       CHECK_LIBRARY_EXISTS(dbus-1 dbus_connection_set_watch_functions "" LWS_HAVE_LIBDBUS)
-       if (NOT LWS_HAVE_LIBDBUS)
-               message(FATAL_ERROR "Install dbus-devel, or libdbus-1-dev etc")
-       endif()
-
-       if (NOT LWS_DBUS_LIB)
-               set(LWS_DBUS_LIB "dbus-1")
-       endif()
-
-       if (NOT LWS_DBUS_INCLUDE1)
-               # look in fedora and debian / ubuntu place
-               if (EXISTS "/usr/include/dbus-1.0")
-                       set(LWS_DBUS_INCLUDE1 "/usr/include/dbus-1.0")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE1 to /usr/include/dbus-1.0 or wherever the main dbus includes are")
-               endif()
-       endif()
-
-       if (NOT LWS_DBUS_INCLUDE2)
-               # look in fedora... debian / ubuntu has the ARCH in the path...
-               if (EXISTS "/usr/lib64/dbus-1.0/include")
-                       set(LWS_DBUS_INCLUDE2 "/usr/lib64/dbus-1.0/include")
-               else()
-                       message(FATAL_ERROR "Set LWS_DBUS_INCLUDE2 to /usr/lib/ARCH-linux-gnu/dbus-1.0/include or wherever dbus-arch-deps.h is on your system")
-               endif()
-       endif()
-
-       set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES};${LWS_DBUS_INCLUDE1};${LWS_DBUS_INCLUDE2})
-
-       if (NOT LWS_DBUS_INCLUDE1 OR NOT LWS_DBUS_INCLUDE2)
-               message(FATAL_ERROR "To build with libdbus, LWS_DBUS_INCLUDE1/2 must be given. See lib/roles/dbus/README.md")
-       endif()
-
-endif()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-
-       endif()
-ENDMACRO()
-
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_DBUS 1 requirements)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 
-if (requirements)
+if (NOT MSVC AND NOT WIN32 AND requirements)
        add_executable(${SAMP} ${SRCS})
 
-       include_directories("${LWS_DBUS_INCLUDE1}")
-       include_directories("${LWS_DBUS_INCLUDE2}")
-       list(APPEND LIB_LIST dbus-1)
+       if (NOT LWS_PLAT_FREERTOS)
+               find_package(PkgConfig QUIET)
+               pkg_check_modules(PC_DBUS1 dbus-1 QUIET)
+               list(APPEND LWS_DBUS_INCLUDE1 ${PC_DBUS1_INCLUDE_DIRS})
+               list(APPEND LWS_DBUS_LIB "${PC_DBUS1_LIBRARIES};dl")
+       endif()
+
+       if (LWS_DBUS_INCLUDE1)
+               include_directories("${LWS_DBUS_INCLUDE1}")
+       endif()
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared ${LWS_DBUS_LIB})
        else()
-               target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB})
+               target_link_libraries(${SAMP} websockets ${LWS_DBUS_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index f926c80..353b159 100644 (file)
@@ -26,7 +26,7 @@
 static int interrupted;
 static struct lws_protocols protocols[] = {
        LWS_PLUGIN_PROTOCOL_MINIMAL_DBUS_WSPROXY,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 /*
@@ -79,7 +79,6 @@ int main(int argc, const char **argv)
        info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
        info.port = CONTEXT_PORT_NO_LISTEN;
-       info.ws_ping_pong_interval = 30;
        info.protocols = protocols;
        info.pvo = &pvo;
 
index 693acc7..3db1c4e 100644 (file)
@@ -739,10 +739,10 @@ callback_minimal_dbus_wsproxy(struct lws *wsi, enum lws_callback_reasons reason,
 
                {
                        char strbuf[256];
-                       int l = len;
+                       size_t l = len;
 
-                       if (l > (int)sizeof(strbuf) - 1)
-                               l = sizeof(strbuf) - 1;
+                       if (l > sizeof(strbuf) - 1u)
+                               l = sizeof(strbuf) - 1u;
 
                        memcpy(strbuf, in, l);
                        strbuf[l] = '\0';
@@ -793,36 +793,3 @@ callback_minimal_dbus_wsproxy(struct lws *wsi, enum lws_callback_reasons reason,
                1024, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL_DBUS_WSPROXY
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal_dbus_wsproxy(struct lws_context *context,
-                              struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal_dbus_wsproxy(struct lws_context *context)
-{
-       return 0;
-}
-#endif
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/CMakeLists.txt b/minimal-examples/embedded/esp32/esp-c3dev/CMakeLists.txt
new file mode 100644 (file)
index 0000000..57d7bfc
--- /dev/null
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 3.5)
+
+if (ESP_PLATFORM)
+       include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+       project(lws-minimal-esp32)
+       enable_testing()
+
+       target_link_libraries(lws-minimal-esp32.elf websockets)
+
+       option(LWS_WITH_DRIVERS "With generic drivers for gpio, i2c, display etc" ON)
+       set(LWS_WITH_DRIVERS ON)
+       option(LWS_WITH_SECURE_STREAMS "With secure streams" ON)
+       set(LWS_WITH_SECURE_STREAMS ON)
+       option(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY "static ssp" OFF)
+       set(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY OFF)
+       option(LWS_WITH_LWSAC "With lwsac" ON)
+       set(LWS_WITH_LWSAC ON)
+       option(LWS_WITH_STRUCT_JSON "With lws_struct JSON" ON)
+       set(LWS_WITH_STRUCT_JSON ON)
+       option(LWS_WITH_SYS_NTPCLIENT "With ntpclient" ON)
+        set(LWS_WITH_SYS_NTPCLIENT ON)
+
+
+       add_subdirectory(libwebsockets)
+
+       add_test(NAME flashing COMMAND idf.py flash)
+       set_tests_properties(flashing PROPERTIES
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+                            TIMEOUT 120)
+
+       add_test(NAME boot COMMAND /usr/local/bin/sai-expect)
+       set_tests_properties(boot PROPERTIES
+                            DEPENDS flashing
+                            TIMEOUT 20)
+
+endif()
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/lws-button.c b/minimal-examples/embedded/esp32/esp-c3dev/lws-button.c
new file mode 100644 (file)
index 0000000..7f5ed31
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * Generic GPIO / irq buttons
+ *
+ * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "private-lib-core.h"
+
+typedef enum lws_button_classify_states {
+       LBCS_IDLE,              /* nothing happening */
+       LBCS_MIN_DOWN_QUALIFY,
+
+       LBCS_ASSESS_DOWN_HOLD,
+       LBCS_UP_SETTLE1,
+       LBCS_WAIT_DOUBLECLICK,
+       LBCS_MIN_DOWN_QUALIFY2,
+
+       LBCS_WAIT_UP,
+       LBCS_UP_SETTLE2,
+} lws_button_classify_states_t;
+
+/*
+ * This is the opaque, allocated, non-const, dynamic footprint of the
+ * button controller
+ */
+
+typedef struct lws_button_state {
+#if defined(LWS_PLAT_TIMER_TYPE)
+       LWS_PLAT_TIMER_TYPE                     timer;     /* bh timer */
+       LWS_PLAT_TIMER_TYPE                     timer_mon; /* monitor timer */
+#endif
+       const lws_button_controller_t           *controller;
+       struct lws_context                      *ctx;
+       short                                   mon_refcount;
+       lws_button_idx_t                        enable_bitmap;
+       lws_button_idx_t                        state_bitmap;
+
+       uint16_t                                mon_timer_count;
+       /* incremented each time the mon timer cb happens */
+
+       /* lws_button_each_t per button overallocated after this */
+} lws_button_state_t;
+
+typedef struct lws_button_each {
+       lws_button_state_t                      *bcs;
+       uint16_t                                mon_timer_comp;
+       uint8_t                                 state;
+       /**^ lws_button_classify_states_t */
+       uint8_t                                 isr_pending;
+} lws_button_each_t;
+
+#if defined(LWS_PLAT_TIMER_START)
+static const lws_button_regime_t default_regime = {
+       .ms_min_down                    = 20,
+       .ms_min_down_longpress          = 300,
+       .ms_up_settle                   = 20,
+       .ms_doubleclick_grace           = 120,
+       .flags                          = LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK
+};
+#endif
+
+
+/*
+ * This is happening in interrupt context, we have to schedule a bottom half to
+ * do the foreground lws_smd queueing, using, eg, a platform timer.
+ *
+ * All the buttons point here and use one timer per button controller.  An
+ * interrupt here means, "something happened to one or more buttons"
+ */
+#if defined(LWS_PLAT_TIMER_START)
+void
+lws_button_irq_cb_t(void *arg)
+{
+       lws_button_each_t *each = (lws_button_each_t *)arg;
+
+       each->isr_pending = 1;
+       LWS_PLAT_TIMER_START(each->bcs->timer);
+}
+#endif
+
+/*
+ * This is the bottom-half scheduled via a timer set in the ISR.  From here
+ * we are allowed to hold mutexes etc.  We are coming here because any button
+ * interrupt arrived, we have to try to figure out which events have happened.
+ */
+
+#if defined(LWS_PLAT_TIMER_CB)
+static LWS_PLAT_TIMER_CB(lws_button_bh, th)
+{
+       lws_button_state_t *bcs = LWS_PLAT_TIMER_CB_GET_OPAQUE(th);
+       const lws_button_controller_t *bc = bcs->controller;
+       lws_button_each_t *each = (lws_button_each_t *)&bcs[1];
+       size_t n;
+
+       /*
+        * The ISR and bottom-half is shared by all the buttons.  Each gpio
+        * IRQ has an individual opaque ptr pointing to the corresponding
+        * button's dynamic lws_button_each_t, the ISR marks the button's
+        * each->isr_pending and schedules this bottom half.
+        *
+        * So now the bh timer has fired and something to do, we need to go
+        * through all the buttons that have isr_pending set and service their
+        * state.  Intermediate states should start / bump the refcount on the
+        * mon timer.  That's refcounted so it only runs when a button down.
+        */
+
+       for (n = 0; n < bc->count_buttons; n++) {
+
+               if (!each[n].isr_pending)
+                       continue;
+
+               /*
+                * Hide what we're about to do from the delicate eyes of the
+                * IRQ controller...
+                */
+
+               bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
+                                      LWSGGPIO_IRQ_NONE, NULL, NULL);
+
+               each[n].isr_pending = 0;
+
+               /*
+                * Force the network around the switch to the
+                * active level briefly
+                */
+
+               bc->gpio_ops->set(bc->button_map[n].gpio,
+                                 !!(bc->active_state_bitmap & (1 << n)));
+               bc->gpio_ops->mode(bc->button_map[n].gpio, LWSGGPIO_FL_WRITE);
+
+               if (each[n].state == LBCS_IDLE) {
+                       /*
+                        * If this is the first sign something happening on this
+                        * button, make sure the monitor timer is running to
+                        * classify it over time
+                        */
+
+                       each[n].state = LBCS_MIN_DOWN_QUALIFY;
+                       each[n].mon_timer_comp = bcs->mon_timer_count;
+
+                       if (!bcs->mon_refcount++) {
+#if defined(LWS_PLAT_TIMER_START)
+                               // lwsl_notice("%s: starting mon timer\n", __func__);
+                               LWS_PLAT_TIMER_START(bcs->timer_mon);
+#endif
+                       }
+               }
+
+               /*
+                * Just for a us or two inbetween here, we're driving it to the
+                * level we were informed by the interrupt it had enetered, to
+                * force to charge on the actual and parasitic network around
+                * the switch to a deterministic-ish state.
+                *
+                * If the switch remains in that state, well, it makes no
+                * difference; if it was a pre-contact and the charge on the
+                * network was left indeterminate, this will dispose it to act
+                * consistently in the short term until the pullup / pulldown
+                * has time to act on it or the switch comes and forces the
+                * network charge state itself.
+                */
+               bc->gpio_ops->mode(bc->button_map[n].gpio, LWSGGPIO_FL_READ);
+
+               /*
+                * We could do a better job manipulating the irq mode according
+                * to the switch state.  But if an interrupt comes and we have
+                * done that, we can't tell if it's from before or after the
+                * mode change... ie, we don't know what the interrupt was
+                * telling us.  We can't trust the gpio state if we read it now
+                * to be related to what the irq from some time before was
+                * trying to tell us.  So always set it back to the same mode
+                * and accept the limitation.
+                */
+
+               bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
+                                      bc->active_state_bitmap & (1 << n) ?
+                                          LWSGGPIO_IRQ_RISING :
+                                          LWSGGPIO_IRQ_FALLING,
+                                             lws_button_irq_cb_t, &each[n]);
+       }
+}
+#endif
+
+#if defined(LWS_PLAT_TIMER_CB)
+static LWS_PLAT_TIMER_CB(lws_button_mon, th)
+{
+       lws_button_state_t *bcs = LWS_PLAT_TIMER_CB_GET_OPAQUE(th);
+       lws_button_each_t *each = (lws_button_each_t *)&bcs[1];
+       const lws_button_controller_t *bc = bcs->controller;
+       const lws_button_regime_t *regime;
+       const char *event_name;
+       int comp_age_ms;
+       char active;
+       size_t n;
+
+       bcs->mon_timer_count++;
+
+       for (n = 0; n < bc->count_buttons; n++) {
+
+               if (each[n].state == LBCS_IDLE)
+                       continue;
+
+               if (bc->button_map[n].regime)
+                       regime = bc->button_map[n].regime;
+               else
+                       regime = &default_regime;
+
+               comp_age_ms = (bcs->mon_timer_count - each[n].mon_timer_comp) *
+                               LWS_BUTTON_MON_TIMER_MS;
+
+               active = bc->gpio_ops->read(bc->button_map[n].gpio) ^
+                              (!(bc->active_state_bitmap & (1 << n)));
+
+               // lwsl_notice("%d\n", each[n].state);
+
+               switch (each[n].state) {
+               case LBCS_MIN_DOWN_QUALIFY:
+                       /*
+                        * We're trying to figure out if the initial down event
+                        * is a glitch, or if it meets the criteria for being
+                        * treated as the definitive start of some kind of click
+                        * action.  To get past this, he has to be solidly down
+                        * for the time mentioned in the applied regime (at
+                        * least when we sample it).
+                        *
+                        * Significant bounce at the start will abort this try,
+                        * but if it's really down there will be a subsequent
+                        * solid down period... it will simply restart this flow
+                        * from a new interrupt and pass the filter then.
+                        *
+                        * The "brief drive on edge" strategy considerably
+                        * reduces inconsistencies here.  But physical bounce
+                        * will continue to be observed.
+                        */
+
+                       if (!active) {
+                               /* We ignore stuff for a bit after discard */
+                               each[n].mon_timer_comp = bcs->mon_timer_count;
+                               each[n].state = LBCS_UP_SETTLE2;
+                               continue;
+                       }
+
+                       if (comp_age_ms >= regime->ms_min_down) {
+
+                               /* We made it through the initial regime filter,
+                                * the next step is wait and see if this down
+                                * event evolves into a single/double click or
+                                * we can call it as a long-click
+                                */
+
+                               each[n].state = LBCS_ASSESS_DOWN_HOLD;
+                               break;
+                       }
+                       break;
+
+               case LBCS_ASSESS_DOWN_HOLD:
+                       /*
+                        * How long is he going to hold it?  If he holds it
+                        * past the long-click threshold, we can call it as a
+                        * long-click and do the up processing afterwards.
+                        */
+                       if (comp_age_ms >= regime->ms_min_down_longpress) {
+                               /* call it as a longclick */
+                               event_name = "longclick";
+                               each[n].state = LBCS_WAIT_UP;
+                               goto classify;
+                       }
+
+                       if (!active) {
+                               /*
+                                * He didn't hold it past the long-click
+                                * threshold... we could end up classifying it
+                                * as either a click or a double-click then.
+                                *
+                                * If double-clicks are not allowed to be
+                                * classified, then we can already classify it
+                                * as a single-click.
+                                */
+                               if (!(regime->flags & LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK))
+                                       goto classify_single;
+
+                               /*
+                                * Just wait for the up settle time then start
+                                * looking for a second down.
+                                */
+                               each[n].mon_timer_comp = bcs->mon_timer_count;
+                               each[n].state = LBCS_UP_SETTLE1;
+                       }
+                       break;
+
+               case LBCS_UP_SETTLE1:
+                       if (comp_age_ms > regime->ms_up_settle)
+                               /*
+                                * Just block anything for the up settle time
+                                */
+                               each[n].state = LBCS_WAIT_DOUBLECLICK;
+                       break;
+
+               case LBCS_WAIT_DOUBLECLICK:
+                       if (active) {
+                               /*
+                                * He has gone down again inside the regime's
+                                * doubleclick grace period... he's going down
+                                * the double-click path
+                                */
+                               each[n].mon_timer_comp = bcs->mon_timer_count;
+                               each[n].state = LBCS_MIN_DOWN_QUALIFY2;
+                               break;
+                       }
+
+                       if (comp_age_ms >= regime->ms_doubleclick_grace) {
+                               /*
+                                * The grace period expired, the second click
+                                * was either not forthcoming at all, or coming
+                                * quick enough to count: we classify it as a
+                                * single-click
+                                */
+
+                               goto classify_single;
+                       }
+                       break;
+
+               case LBCS_MIN_DOWN_QUALIFY2:
+                       if (!active) {
+classify_single:
+                               /*
+                                * He went up again too quickly, classify it
+                                * as a single-click.  It could be bounce in
+                                * which case you might want to increase
+                                * the ms_up_settle in the regime
+                                */
+                               event_name = "click";
+                               each[n].mon_timer_comp = bcs->mon_timer_count;
+                               each[n].state = LBCS_UP_SETTLE2;
+                               goto classify;
+                       }
+
+                       if (comp_age_ms >= regime->ms_min_down) {
+                               /*
+                                * It's a double-click
+                                */
+                               event_name = "doubleclick";
+                               each[n].state = LBCS_WAIT_UP;
+                               goto classify;
+                       }
+                       break;
+
+               case LBCS_WAIT_UP:
+                       if (!active) {
+                               each[n].mon_timer_comp = bcs->mon_timer_count;
+                               each[n].state = LBCS_UP_SETTLE2;
+                       }
+                       break;
+
+               case LBCS_UP_SETTLE2:
+                       if (comp_age_ms < regime->ms_up_settle)
+                               break;
+
+                       each[n].state = LBCS_IDLE;
+                       if (!(--bcs->mon_refcount)) {
+#if defined(LWS_PLAT_TIMER_STOP)
+                               LWS_PLAT_TIMER_STOP(bcs->timer_mon);
+#endif
+                       }
+                       break;
+               }
+
+               continue;
+
+classify:
+               lws_smd_msg_printf(bcs->ctx, LWSSMDCL_INTERACTION,
+                  "{\"btn\":\"%s/%s\", \"s\":\"%s\"}",
+                  bc->smd_bc_name,
+                  bc->button_map[n].smd_interaction_name,
+                  event_name);
+       }
+}
+#endif
+
+struct lws_button_state *
+lws_button_controller_create(struct lws_context *ctx,
+                            const lws_button_controller_t *controller)
+{
+       lws_button_state_t *bcs = lws_zalloc(sizeof(lws_button_state_t) +
+                       (controller->count_buttons * sizeof(lws_button_each_t)),
+                       __func__);
+       lws_button_each_t *each = (lws_button_each_t *)&bcs[1];
+       size_t n;
+
+       if (!bcs)
+               return NULL;
+
+       bcs->controller = controller;
+       bcs->ctx = ctx;
+
+       for (n = 0; n < controller->count_buttons; n++)
+               each[n].bcs = bcs;
+
+#if defined(LWS_PLAT_TIMER_CREATE)
+       /* this only runs inbetween a gpio ISR and the bottom half */
+       bcs->timer = LWS_PLAT_TIMER_CREATE("bcst",
+                       1, 0, bcs, (TimerCallbackFunction_t)lws_button_bh);
+       if (!bcs->timer)
+               return NULL;
+       /* this only runs when a button activity is being classified */
+       bcs->timer_mon = LWS_PLAT_TIMER_CREATE("bcmon", LWS_BUTTON_MON_TIMER_MS, 1, bcs,
+                       (TimerCallbackFunction_t)lws_button_mon);
+       if (!bcs->timer_mon)
+               return NULL;
+#endif
+
+       return bcs;
+}
+
+void
+lws_button_controller_destroy(struct lws_button_state *bcs)
+{
+       /* disable them all */
+       lws_button_enable(bcs, 0, 0);
+
+#if defined(LWS_PLAT_TIMER_DELETE)
+       LWS_PLAT_TIMER_DELETE(&bcs->timer);
+       LWS_PLAT_TIMER_DELETE(&bcs->timer_mon);
+#endif
+
+       lws_free(bcs);
+}
+
+lws_button_idx_t
+lws_button_get_bit(struct lws_button_state *bcs, const char *name)
+{
+       const lws_button_controller_t *bc = bcs->controller;
+       int n;
+
+       for (n = 0; n < bc->count_buttons; n++)
+               if (!strcmp(name, bc->button_map[n].smd_interaction_name))
+                       return 1 << n;
+
+       return 0; /* not found */
+}
+
+void
+lws_button_enable(lws_button_state_t *bcs,
+                 lws_button_idx_t _reset, lws_button_idx_t _set)
+{
+       lws_button_idx_t u = (bcs->enable_bitmap & (~_reset)) | _set;
+       const lws_button_controller_t *bc = bcs->controller;
+#if defined(LWS_PLAT_TIMER_START)
+       lws_button_each_t *each = (lws_button_each_t *)&bcs[1];
+#endif
+       int n;
+
+       for (n = 0; n < bcs->controller->count_buttons; n++) {
+               if (!(bcs->enable_bitmap & (1 << n)) && (u & (1 << n))) {
+                       /* set as input with pullup or pulldown appropriately */
+                       bc->gpio_ops->mode(bc->button_map[n].gpio,
+                               LWSGGPIO_FL_READ |
+                               ((bc->active_state_bitmap & (1 << n)) ?
+                               LWSGGPIO_FL_PULLDOWN : LWSGGPIO_FL_PULLUP));
+#if defined(LWS_PLAT_TIMER_START)
+                       /*
+                        * This one is becoming enabled... the opaque for the
+                        * ISR is the indvidual lws_button_each_t, they all
+                        * point to the same ISR
+                        */
+                       bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
+                                       bc->active_state_bitmap & (1 << n) ?
+                                               LWSGGPIO_IRQ_RISING :
+                                                       LWSGGPIO_IRQ_FALLING,
+                                               lws_button_irq_cb_t, &each[n]);
+#endif
+               }
+               if ((bcs->enable_bitmap & (1 << n)) && !(u & (1 << n)))
+                       /* this one is becoming disabled */
+                       bc->gpio_ops->irq_mode(bc->button_map[n].gpio,
+                                               LWSGGPIO_IRQ_NONE, NULL, NULL);
+       }
+
+       bcs->enable_bitmap = u;
+}
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/CMakeLists.txt b/minimal-examples/embedded/esp32/esp-c3dev/main/CMakeLists.txt
new file mode 100644 (file)
index 0000000..77040de
--- /dev/null
@@ -0,0 +1,6 @@
+idf_component_register(SRCS
+               lws-minimal-esp32.c devices.c
+               INCLUDE_DIRS "../libwebsockets/include;${IDF_PATH}/components/spi_flash/include;${IDF_PATH}/components/nvs_flash/include;${IDF_PATH}/components/mdns/include")
+
+target_link_libraries(${COMPONENT_LIB} websockets)
+include_directories(../build/libwebsockets)
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/bb-i2c.c b/minimal-examples/embedded/esp32/esp-c3dev/main/bb-i2c.c
new file mode 100644 (file)
index 0000000..0c89e90
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * lws generic bitbang i2c
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include "bb-i2c.h"
+
+int
+lws_bb_i2c_start(lws_i2c_ops_t *octx)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+
+       ctx->gpio->set(ctx->sda, 1);
+       ctx->gpio->set(ctx->scl, 1);
+       ctx->delay();
+
+       if (!ctx->gpio->read(ctx->sda))
+               return 1;
+
+       ctx->gpio->set(ctx->sda, 0);
+       ctx->delay();
+       ctx->gpio->set(ctx->scl, 0);
+
+       return 0;
+}
+
+void
+lws_bb_i2c_stop(lws_i2c_ops_t *octx)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+
+       ctx->gpio->set(ctx->sda, 0);
+       ctx->gpio->set(ctx->scl, 1);
+       ctx->delay();
+
+       while (!ctx->gpio->read(ctx->scl))
+               ;
+
+       ctx->gpio->set(ctx->sda, 1);
+       ctx->delay();
+}
+
+int
+lws_bb_i2c_write(lws_i2c_ops_t *octx, uint8_t data)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+       int n;
+
+       for (n = 0; n < 8; n++) {
+               ctx->gpio->set(ctx->sda, !!(data & (1 << 7)));
+               ctx->delay();
+               ctx->gpio->set(ctx->scl, 1);
+               ctx->delay();
+               data <<= 1;
+               ctx->gpio->set(ctx->scl, 0);
+       }
+
+       ctx->gpio->set(ctx->sda, 1);
+       ctx->delay();
+       ctx->gpio->set(ctx->scl, 1);
+       ctx->delay();
+       n = ctx->gpio->read(ctx->sda);
+       ctx->gpio->set(ctx->scl, 0);
+       ctx->delay();
+
+       return !!n; /* 0 = ACKED = OK */
+}
+
+int
+lws_bb_i2c_read(lws_i2c_ops_t *octx)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+       int n, r = 0;
+
+       ctx->gpio->set(ctx->sda, 1);
+
+       for (n = 7; n <= 0; n--) {
+               ctx->gpio->set(ctx->scl, 0);
+               ctx->delay();
+               ctx->gpio->set(ctx->scl, 1);
+               ctx->delay();
+               if (ctx->gpio->read(ctx->sda))
+                       r |= 1 << n;
+       }
+       ctx->gpio->set(ctx->scl, 0);
+
+       return r;
+}
+
+void
+lws_bb_i2c_set_ack(lws_i2c_ops_t *octx, int ack)
+{
+       lws_bb_i2c_t *ctx = (lws_bb_i2c_t *)octx;
+
+       ctx->gpio->set(ctx->scl, 0);
+       ctx->gpio->set(ctx->sda, !!ack);
+       ctx->delay();
+       ctx->gpio->set(ctx->scl, 1);
+       ctx->delay();
+       ctx->gpio->set(ctx->scl, 0);
+       ctx->delay();
+       ctx->gpio->set(ctx->sda, 1);
+}
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/bb-i2c.h b/minimal-examples/embedded/esp32/esp-c3dev/main/bb-i2c.h
new file mode 100644 (file)
index 0000000..31cc3b5
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * lws-minimal-esp32
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include "i2c.h"
+#include "gpio-esp32.h"
+
+typedef struct lws_bb_i2c {
+       lws_i2c_ops_t           bb_ops; /* init to lws_bb_i2c_ops */
+
+       /* implementation-specific members */
+
+       _lws_plat_gpio_t        scl;
+       _lws_plat_gpio_t        sda;
+
+       const lws_gpio_ops_t    *gpio;
+       void (*delay)(void);
+} lws_bb_i2c_t;
+
+#define lws_bb_i2c_ops \
+       { \
+               .start = lws_bb_i2c_start, \
+               .stop = lws_bb_i2c_stop, \
+               .write = lws_bb_i2c_write, \
+               .read = lws_bb_i2c_read, \
+               .set_ack = lws_bb_i2c_set_ack, \
+       }
+
+int
+lws_bb_i2c_start(lws_i2c_ops_t *octx);
+
+void
+lws_bb_i2c_stop(lws_i2c_ops_t *octx);
+
+int
+lws_bb_i2c_write(lws_i2c_ops_t *octx, uint8_t data);
+
+int
+lws_bb_i2c_read(lws_i2c_ops_t *octx);
+
+void
+lws_bb_i2c_set_ack(lws_i2c_ops_t *octx, int ack);
+
+
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/component.mk b/minimal-examples/embedded/esp32/esp-c3dev/main/component.mk
new file mode 100644 (file)
index 0000000..0b9d758
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/devices.c b/minimal-examples/embedded/esp32/esp-c3dev/main/devices.c
new file mode 100644 (file)
index 0000000..2d079d5
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * devices for ESP32 C3 dev board
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#define LWIP_PROVIDE_ERRNO 1
+#define _ESP_PLATFORM_ERRNO_H_
+
+#include <stdio.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include <driver/gpio.h>
+
+#include <libwebsockets.h>
+
+struct lws_led_state *lls;
+lws_display_state_t lds;
+struct lws_button_state *bcs;
+lws_netdev_instance_wifi_t *wnd;
+
+/*
+ * Button controller
+ */
+
+static const lws_button_map_t bcm[] = {
+       {
+               .gpio                   = GPIO_NUM_0,
+               .smd_interaction_name   = "user"
+       },
+};
+
+static const lws_button_controller_t bc = {
+       .smd_bc_name                    = "bc",
+       .gpio_ops                       = &lws_gpio_plat,
+       .button_map                     = &bcm[0],
+       .active_state_bitmap            = 0,
+       .count_buttons                  = LWS_ARRAY_SIZE(bcm),
+};
+
+/*
+ * pwm controller
+ */
+
+static const lws_pwm_map_t pwm_map[] = {
+       { .gpio = GPIO_NUM_8, .index = 0, .active_level = 1 }
+};
+
+static const lws_pwm_ops_t pwm_ops = {
+       lws_pwm_plat_ops,
+       .pwm_map                        = &pwm_map[0],
+       .count_pwm_map                  = LWS_ARRAY_SIZE(pwm_map)
+};
+
+#if 0
+static const lws_display_ssd1306_t disp = {
+       .disp = {
+               lws_display_ssd1306_ops,
+               .w                      = 128,
+               .h                      = 64
+       },
+       .i2c                            = (lws_i2c_ops_t *)&li2c,
+       .gpio                           = &lws_gpio_plat,
+       .reset_gpio                     = GPIO_NUM_16,
+       .i2c7_address                   = SSD1306_I2C7_ADS1
+};
+#endif
+
+/*
+ * led controller
+ */
+
+static const lws_led_gpio_map_t lgm[] = {
+       {
+               .name                   = "alert",
+               .gpio                   = GPIO_NUM_8,
+               .pwm_ops                = &pwm_ops, /* managed by pwm */
+               .active_level           = 1,
+       },
+};
+
+static const lws_led_gpio_controller_t lgc = {
+       .led_ops                        = lws_led_gpio_ops,
+       .gpio_ops                       = &lws_gpio_plat,
+       .led_map                        = &lgm[0],
+       .count_leds                     = LWS_ARRAY_SIZE(lgm)
+};
+
+/*
+ * Settings stored in platform nv
+ */
+
+static const lws_settings_ops_t sett = {
+       lws_settings_ops_plat
+};
+
+/*
+ * Wifi
+ */
+
+static const lws_netdev_ops_t wifi_ops = {
+       lws_netdev_wifi_plat_ops
+};
+
+int
+init_plat_devices(struct lws_context *ctx)
+{
+       lws_settings_instance_t *si;
+       lws_netdevs_t *netdevs = lws_netdevs_from_ctx(ctx);
+
+       si = lws_settings_init(&sett, (void *)"nvs");
+       if (!si) {
+               lwsl_err("%s: failed to create settings instance\n", __func__);
+               return 1;
+       }
+       netdevs->si = si;
+
+#if 0
+       /*
+        * This is a temp hack to bootstrap the settings to contain the test
+        * AP ssid and passphrase for one time, so the settings can be stored
+        * while there's no UI atm
+        */
+       {
+               lws_wifi_creds_t creds;
+
+               memset(&creds, 0, sizeof(creds));
+
+               lws_strncpy(creds.ssid, "xxx", sizeof(creds.ssid));
+               lws_strncpy(creds.passphrase, "xxx", sizeof(creds.passphrase));
+               lws_dll2_add_tail(&creds.list, &netdevs->owner_creds);
+
+               if (lws_netdev_credentials_settings_set(netdevs)) {
+                       lwsl_err("%s: failed to write bootstrap creds\n",
+                                       __func__);
+                       return 1;
+               }
+       }
+#endif
+
+       /* create the wifi network device and configure it */
+
+       wnd = (lws_netdev_instance_wifi_t *)
+                       wifi_ops.create(ctx, &wifi_ops, "wl0", NULL);
+       if (!wnd) {
+               lwsl_err("%s: failed to create wifi object\n", __func__);
+               return 1;
+       }
+
+       wnd->flags |= LNDIW_MODE_STA;
+
+       if (wifi_ops.configure(&wnd->inst, NULL)) {
+               lwsl_err("%s: failed to configure wifi object\n", __func__);
+               return 1;
+       }
+
+       wifi_ops.up(&wnd->inst);
+       esp_wifi_set_mode(WIFI_MODE_STA);
+lws_netdev_wifi_scan_plat(&wnd->inst);
+       lls = lgc.led_ops.create(&lgc.led_ops);
+       if (!lls) {
+               lwsl_err("%s: could not create led\n", __func__);
+               return 1;
+       }
+
+       /* pwm init must go after the led controller init */
+
+//     pwm_ops.init(&pwm_ops);
+
+       bcs = lws_button_controller_create(ctx, &bc);
+       if (!bcs) {
+               lwsl_err("%s: could not create buttons\n", __func__);
+               return 1;
+       }
+
+       lws_button_enable(bcs, 0, lws_button_get_bit(bcs, "user"));
+//     lws_led_transition(lls, "alert", &lws_pwmseq_static_off,
+//                                      &lws_pwmseq_static_on);
+
+       lwsl_notice("%s: exiting device init\n", __func__);
+       return 0;
+}
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/gpio-esp32.c b/minimal-examples/embedded/esp32/esp-c3dev/main/gpio-esp32.c
new file mode 100644 (file)
index 0000000..92fe863
--- /dev/null
@@ -0,0 +1,36 @@
+#include <driver/gpio.h>
+#include "gpio-esp32.h"
+       
+static void
+lws_gpio_esp32_mode_write(_lws_plat_gpio_t gpio)
+{
+       gpio_reset_pin(gpio);
+       gpio_set_pull_mode(gpio, GPIO_PULLUP_ONLY);
+       gpio_set_direction(gpio, GPIO_MODE_INPUT_OUTPUT);
+       gpio_set_level(gpio, 1);
+}
+static void
+lws_gpio_esp32_mode_read(_lws_plat_gpio_t gpio)
+{
+       gpio_set_pull_mode(gpio, GPIO_PULLUP_ONLY);
+       gpio_set_direction(gpio, GPIO_MODE_INPUT);
+       gpio_set_level(gpio, 1);
+}
+static int
+lws_gpio_esp32_read(_lws_plat_gpio_t gpio)
+{
+       return gpio_get_level(gpio);
+}
+static void
+lws_gpio_esp32_set(_lws_plat_gpio_t gpio, int val)
+{
+       gpio_set_level(gpio, val);
+}
+
+const lws_gpio_ops_t lws_gpio_esp32 = {
+       .mode_write             = lws_gpio_esp32_mode_write,
+       .mode_read              = lws_gpio_esp32_mode_read,
+       .read                   = lws_gpio_esp32_read,
+       .set                    = lws_gpio_esp32_set,
+};
+
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/gpio-esp32.h b/minimal-examples/embedded/esp32/esp-c3dev/main/gpio-esp32.h
new file mode 100644 (file)
index 0000000..d220168
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * lws generic gpio - esp32 platform wrapper
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+typedef int _lws_plat_gpio_t;
+#include "gpio.h"
+
+extern const lws_gpio_ops_t lws_gpio_esp32;
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/gpio.h b/minimal-examples/embedded/esp32/esp-c3dev/main/gpio.h
new file mode 100644 (file)
index 0000000..5020518
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * lws genric gpio
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * You should typedef _lws_plat_gpio_t to int or whatever before
+ * including this.  It's better to wrap this in a platform-specific
+ * include that does that and then include the platform-specific
+ * include in your code.
+ */
+
+#if !defined(__LWS_GPIO_H__)
+#define __LWS_GPIO_H__
+
+typedef struct lws_gpio_ops {
+       void (*mode_write)(_lws_plat_gpio_t gpio);
+       void (*mode_read)(_lws_plat_gpio_t gpio);
+       int (*read)(_lws_plat_gpio_t gpio);
+       void (*set)(_lws_plat_gpio_t gpio, int val);
+} lws_gpio_ops_t;
+
+#endif
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/i2c.c b/minimal-examples/embedded/esp32/esp-c3dev/main/i2c.c
new file mode 100644 (file)
index 0000000..5e0b4cd
--- /dev/null
@@ -0,0 +1,32 @@
+#include "i2c.h"
+       
+int
+lws_i2c_command(lws_i2c_ops_t *ctx, uint8_t ads, uint8_t c)
+{
+       if (ctx->start(ctx))
+               return 1;
+
+       if (ctx->write(ctx, ads << 1)) {
+               ctx->stop(ctx);
+
+               return 1;
+       }
+
+       ctx->write(ctx, 0);
+       ctx->write(ctx, c);
+       ctx->stop(ctx);
+
+       return 0;
+}
+
+int
+lws_i2c_command_list(lws_i2c_ops_t *ctx, uint8_t ads, const uint8_t *buf, size_t len)
+{
+       while (len--)
+               if (lws_i2c_command(ctx, ads, *buf++))
+                       return 1;
+
+       return 0;
+}
+
+
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/i2c.h b/minimal-examples/embedded/esp32/esp-c3dev/main/i2c.h
new file mode 100644 (file)
index 0000000..fe33980
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Generic i2c ops
+ *
+ * These ops always appear first in an implementation-specific
+ * object, so the generic ops can be cast to the implementation-
+ * specific object in the handlers.
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#if !defined(__LWS_I2C_H__)
+#define __LWS_I2C_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef struct lws_i2c_ops {
+       int  (*start)(struct lws_i2c_ops *ctx);
+       void (*stop)(struct lws_i2c_ops *ctx);
+       int  (*write)(struct lws_i2c_ops *ctx, uint8_t data);
+       int  (*read)(struct lws_i2c_ops *ctx);
+       void (*set_ack)(struct lws_i2c_ops *octx, int ack);
+} lws_i2c_ops_t;
+
+int
+lws_i2c_command(lws_i2c_ops_t *ctx, uint8_t ads, uint8_t c);
+
+int
+lws_i2c_command_list(lws_i2c_ops_t *ctx, uint8_t ads, const uint8_t *buf, size_t len);
+
+#endif
+
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/lws-minimal-esp32.c b/minimal-examples/embedded/esp32/esp-c3dev/main/lws-minimal-esp32.c
new file mode 100644 (file)
index 0000000..436521c
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * lws-minimal-esp32
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * Based on espressif Public Domain sample
+ */
+
+#define LWIP_PROVIDE_ERRNO 1
+#define _ESP_PLATFORM_ERRNO_H_
+
+#include <stdio.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include <driver/gpio.h>
+
+#include <libwebsockets.h>
+
+struct lws_context *context;
+extern struct lws_led_state *lls;
+extern lws_display_state_t lds;
+extern lws_netdev_instance_wifi_t *wnd;
+
+extern int init_plat_devices(struct lws_context *);
+
+#include "policy.h"
+
+static uint8_t flip;
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+
+       size_t                          amount;
+
+} myss_t;
+
+static int
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+//     lwsl_hexdump_info(buf, len);
+       m->amount += len;
+
+       if (flags & LWSSS_FLAG_EOM) {
+
+               /*
+                * If we received the whole message, for our example it means
+                * we are done.
+                */
+
+               lwsl_notice("%s: received %u bytes\n", __func__,
+                           (unsigned int)m->amount);
+
+               /*
+                * In CI, we use sai-expect to look for this
+                * string for success
+                */
+
+               lwsl_notice("Completed: PASS\n");
+       }
+
+       return 0;
+}
+
+static int
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               if (lws_ss_client_connect(m->ss))
+                       lwsl_err("%s: connection failed\n", __func__);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const lws_ss_info_t ssi = {
+       .handle_offset                  = offsetof(myss_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_t, opaque_data),
+       .rx                             = myss_rx,
+       .state                          = myss_state,
+       .user_alloc                     = sizeof(myss_t),
+       .streamtype                     = "test_stream",
+};
+
+static const lws_led_sequence_def_t *seqs[] = {
+       &lws_pwmseq_static_on,
+       &lws_pwmseq_static_off,
+       &lws_pwmseq_sine_endless_slow,
+       &lws_pwmseq_sine_endless_fast,
+};
+
+static int
+smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp, void *buf,
+       size_t len)
+{
+
+       if (!lws_json_simple_strcmp(buf, len, "\"src\":", "bc/user") &&
+           !lws_json_simple_strcmp(buf, len, "\"event\":", "click")) {
+               lws_led_transition(lls, "alert", seqs[flip & 3],
+                                  &lws_pwmseq_linear_wipe);
+               flip++;
+       }
+
+       lwsl_hexdump_notice(buf, len);
+
+       if ((_class & LWSSMDCL_SYSTEM_STATE) &&
+           !lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
+
+               /* create the secure stream */
+
+               lwsl_notice("%s: creating test secure stream\n", __func__);
+
+               if (lws_ss_create(context, 0, &ssi, NULL, NULL, NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+                       return -1;
+               }
+       }
+
+       if (_class & LWSSMDCL_INTERACTION)
+               /*
+                * Any kind of user interaction brings the display back up and
+                * resets the dimming / blanking timers
+                */
+               lws_display_state_active(&lds);
+
+       return 0;
+}
+
+void 
+app_main(void)
+{
+       struct lws_context_creation_info *info;
+
+       lws_set_log_level(1024 | 7, NULL);
+
+        lws_netdev_plat_init();
+        lws_netdev_plat_wifi_init();
+
+        info = malloc(sizeof(*info));
+        if (!info)
+               goto spin;
+
+       memset(info, 0, sizeof(*info));
+
+       lwsl_notice("LWS test for ESP32-C3 Dev Board\n");
+
+       info->pss_policies_json         = ss_policy;
+       info->options                   = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                                         LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info->port                      = CONTEXT_PORT_NO_LISTEN;
+       info->early_smd_cb              = smd_cb;
+       info->early_smd_class_filter    = LWSSMDCL_INTERACTION |
+                                         LWSSMDCL_SYSTEM_STATE |
+                                         LWSSMDCL_NETWORK;
+
+       context = lws_create_context(info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return;
+       }
+
+       /*
+        * We don't need this after context creation... things it pointed to
+        * still need to exist though since the context copied the pointers.
+        */
+
+       free(info);
+
+       /* devices and init are in devices.c */
+
+       if (init_plat_devices(context))
+               goto spin;
+
+
+       /* the lws event loop */
+
+       do {
+               taskYIELD();
+       } while (lws_service(context, 0) >= 0);
+
+
+spin:
+       vTaskDelay(10);
+       taskYIELD();
+       goto spin;
+}
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/main/policy.h b/minimal-examples/embedded/esp32/esp-c3dev/main/policy.h
new file mode 100644 (file)
index 0000000..03c44b6
--- /dev/null
@@ -0,0 +1,134 @@
+
+static const char * const ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "25,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+               "{\"isrg_root_x1\": \"" /* ISRG ROOT X1 */
+       "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="
+               "\"},"
+               "{\"LEX3_isrg_root_x1\": \"" /* LE X3 signed by ISRG X1 root */
+       "MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAw"
+       "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh"
+       "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1"
+       "WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg"
+       "RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEi"
+       "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrX"
+       "NSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf"
+       "89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHl"
+       "Npi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7Dc"
+       "Gu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgz"
+       "uEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMB"
+       "AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU"
+       "BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB"
+       "FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSo"
+       "SmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js"
+       "LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF"
+       "BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG"
+       "AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD"
+       "VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB"
+       "ABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGx"
+       "A/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRM"
+       "UM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2"
+       "DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1"
+       "eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOu"
+       "OsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vw"
+       "p7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY"
+       "2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0"
+       "ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKR"
+       "PB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5b"
+       "rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt"
+               "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\","
+                               "\"LEX3_isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": ["
+
+               "{\"test_stream\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h2\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"index.html\","
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}},{"
+                       /*
+                        * "captive_portal_detect" describes
+                        * what to do in order to check if the path to
+                        * the Internet is being interrupted by a
+                        * captive portal.
+                        */
+                   "\"captive_portal_detect\": {"
+                        "\"endpoint\":"                "\"connectivitycheck.android.com\","
+                       "\"http_url\":"         "\"generate_204\","
+                       "\"port\":"             "80,"
+                        "\"protocol\":"                "\"h1\","
+                        "\"http_method\":"     "\"GET\","
+                        "\"opportunistic\":"   "true,"
+                        "\"http_expect\":"     "204,"
+                       "\"http_fail_redirect\": true"
+                "}}"
+       "]}"
+;
+
+
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/partitions.csv b/minimal-examples/embedded/esp32/esp-c3dev/partitions.csv
new file mode 100644 (file)
index 0000000..e261b7c
--- /dev/null
@@ -0,0 +1,5 @@
+# ESP-IDF Partition Table
+# Name,   Type, SubType, Offset,  Size, Flags
+nvs,      data, nvs,     0x9000,  0x6000,
+phy_init, data, phy,     0xf000,  0x1000,
+factory,  app,  factory, 0x10000, 2M,
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/private-lib-plat-freertos.h b/minimal-examples/embedded/esp32/esp-c3dev/private-lib-plat-freertos.h
new file mode 100644 (file)
index 0000000..a81bbc0
--- /dev/null
@@ -0,0 +1,131 @@
+ /*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Included from lib/private-lib-core.h if LWS_PLAT_FREERTOS
+ */
+
+#if !defined(LWS_ESP_PLATFORM)
+#define SOMAXCONN 3
+#endif
+
+#if defined(LWS_AMAZON_RTOS)
+ int
+ open(const char *path, int oflag, ...);
+#else
+ #include <fcntl.h>
+#endif
+
+ #include <strings.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <sys/time.h>
+ #include <netdb.h>
+
+ #ifndef __cplusplus
+  #include <errno.h>
+ #endif
+ #include <signal.h>
+#if defined(LWS_AMAZON_RTOS)
+const char *
+gai_strerror(int);
+#else
+ #include <sys/socket.h>
+#endif
+
+#if defined(LWS_AMAZON_RTOS)
+ #include "FreeRTOS.h"
+#if defined(LWS_WITH_SYS_ASYNC_DNS)
+ #include "FreeRTOS_IP.h"
+#endif
+ #include "timers.h"
+ #include <esp_attr.h>
+#else
+ #include "freertos/timers.h"
+ #include <esp_attr.h>
+ #include <esp_system.h>
+ #include <esp_task_wdt.h>
+#endif
+
+#if defined(LWS_WITH_ESP32)
+#include "lwip/apps/sntp.h"
+#include <errno.h>
+#endif
+
+typedef SemaphoreHandle_t lws_mutex_t;
+#define lws_mutex_init(x)      x = xSemaphoreCreateMutex()
+#define lws_mutex_destroy(x)   vSemaphoreDelete(x)
+#define lws_mutex_lock(x)      xSemaphoreTake(x, portMAX_DELAY)
+#define lws_mutex_unlock(x)    xSemaphoreGive(x)
+
+#include <lwip/sockets.h>
+
+ #if defined(LWS_BUILTIN_GETIFADDRS)
+  #include "./misc/getifaddrs.h"
+ #endif
+
+ #define LWS_ERRNO errno
+ #define LWS_EAGAIN EAGAIN
+ #define LWS_EALREADY EALREADY
+ #define LWS_EINPROGRESS EINPROGRESS
+ #define LWS_EINTR EINTR
+ #define LWS_EISCONN EISCONN
+ #define LWS_ENOTCONN ENOTCONN
+ #define LWS_EWOULDBLOCK EWOULDBLOCK
+ #define LWS_EADDRINUSE EADDRINUSE
+
+ #define lws_set_blocking_send(wsi)
+
+ #ifndef LWS_NO_FORK
+  #ifdef LWS_HAVE_SYS_PRCTL_H
+   #include <sys/prctl.h>
+  #endif
+ #endif
+
+#if !defined(MSG_NOSIGNAL)
+#define MSG_NOSIGNAL 0
+#endif
+
+#define compatible_close(x) close(x)
+#define lws_plat_socket_offset() LWIP_SOCKET_OFFSET
+#define wsi_from_fd(A,B)  A->lws_lookup[B - lws_plat_socket_offset()]
+
+struct lws_context;
+struct lws;
+
+int
+insert_wsi(const struct lws_context *context, struct lws *wsi);
+
+#define delete_from_fd(A,B) A->lws_lookup[B - lws_plat_socket_offset()] = 0
+
+#define LWS_PLAT_TIMER_TYPE            TimerHandle_t
+#define LWS_PLAT_TIMER_CB(name, var)   void name(TimerHandle_t var)
+#define LWS_PLAT_TIMER_CB_GET_OPAQUE(x) pvTimerGetTimerID(x)
+#define LWS_PLAT_TIMER_CREATE(name, interval, repeat, opaque, cb) \
+       xTimerCreate(name, pdMS_TO_TICKS(interval) ? pdMS_TO_TICKS(interval) : 1, \
+                       repeat ? pdTRUE : 0, opaque, cb)
+#define LWS_PLAT_TIMER_DELETE(ptr)     xTimerDelete(ptr, 0)
+#define LWS_PLAT_TIMER_START(ptr)      xTimerStart(ptr, 0)
+#define LWS_PLAT_TIMER_STOP(ptr)       xTimerStop(ptr, 0)
+
+
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/sdkconfig b/minimal-examples/embedded/esp32/esp-c3dev/sdkconfig
new file mode 100644 (file)
index 0000000..a406123
--- /dev/null
@@ -0,0 +1,1301 @@
+#
+# Automatically generated file. DO NOT EDIT.
+# Espressif IoT Development Framework (ESP-IDF) Project Configuration
+#
+CONFIG_IDF_CMAKE=y
+CONFIG_IDF_TARGET_ARCH_RISCV=y
+CONFIG_IDF_TARGET="esp32c3"
+CONFIG_IDF_TARGET_ESP32C3=y
+CONFIG_IDF_FIRMWARE_CHIP_ID=0x0005
+
+#
+# SDK tool configuration
+#
+CONFIG_SDK_TOOLPREFIX="riscv32-esp-elf-"
+# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set
+# end of SDK tool configuration
+
+#
+# Build type
+#
+CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y
+# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set
+CONFIG_APP_BUILD_GENERATE_BINARIES=y
+CONFIG_APP_BUILD_BOOTLOADER=y
+CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y
+# end of Build type
+
+#
+# Application manager
+#
+CONFIG_APP_COMPILE_TIME_DATE=y
+# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
+# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
+# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set
+CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16
+# end of Application manager
+
+#
+# Bootloader config
+#
+CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0
+CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
+CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
+# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
+CONFIG_BOOTLOADER_LOG_LEVEL=3
+CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
+# CONFIG_BOOTLOADER_FACTORY_RESET is not set
+# CONFIG_BOOTLOADER_APP_TEST is not set
+CONFIG_BOOTLOADER_WDT_ENABLE=y
+# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
+CONFIG_BOOTLOADER_WDT_TIME_MS=9000
+# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set
+CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0
+# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set
+CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y
+# end of Bootloader config
+
+#
+# Security features
+#
+CONFIG_SECURE_BOOT_SUPPORTS_RSA=y
+CONFIG_SECURE_TARGET_HAS_SECURE_ROM_DL_MODE=y
+# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set
+# CONFIG_SECURE_BOOT is not set
+# CONFIG_SECURE_FLASH_ENC_ENABLED is not set
+# end of Security features
+
+#
+# Boot ROM Behavior
+#
+CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y
+# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set
+# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set
+# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set
+# end of Boot ROM Behavior
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
+# CONFIG_ESPTOOLPY_NO_STUB is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
+# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE="dio"
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ="80m"
+# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
+# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_BEFORE_RESET=y
+# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
+CONFIG_ESPTOOLPY_BEFORE="default_reset"
+CONFIG_ESPTOOLPY_AFTER_RESET=y
+# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
+CONFIG_ESPTOOLPY_AFTER="hard_reset"
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
+# end of Serial flasher config
+
+#
+# Partition Table
+#
+# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
+CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
+# CONFIG_PARTITION_TABLE_TWO_OTA is not set
+# CONFIG_PARTITION_TABLE_CUSTOM is not set
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp_large.csv"
+CONFIG_PARTITION_TABLE_OFFSET=0x8000
+CONFIG_PARTITION_TABLE_MD5=y
+# end of Partition Table
+
+#
+# Compiler options
+#
+CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
+# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
+# CONFIG_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
+CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
+CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2
+# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set
+CONFIG_COMPILER_HIDE_PATHS_MACROS=y
+# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
+# CONFIG_COMPILER_CXX_RTTI is not set
+CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
+# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
+# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
+# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_COMPILER_DUMP_RTL_FILES is not set
+# end of Compiler options
+
+#
+# Component config
+#
+
+#
+# Application Level Tracing
+#
+# CONFIG_APPTRACE_DEST_JTAG is not set
+CONFIG_APPTRACE_DEST_NONE=y
+CONFIG_APPTRACE_LOCK_ENABLE=y
+# end of Application Level Tracing
+
+#
+# ESP-ASIO
+#
+# CONFIG_ASIO_SSL_SUPPORT is not set
+# end of ESP-ASIO
+
+#
+# Bluetooth
+#
+# CONFIG_BT_ENABLED is not set
+CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=0
+CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0
+CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0
+CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0
+CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=0
+CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0
+CONFIG_BTDM_CTRL_PINNED_TO_CORE=0
+CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1
+CONFIG_BT_CTRL_MODE_EFF=1
+CONFIG_BT_CTRL_BLE_MAX_ACT=10
+CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=10
+CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0
+CONFIG_BT_CTRL_PINNED_TO_CORE=0
+CONFIG_BT_CTRL_HCI_TL=1
+CONFIG_BT_CTRL_ADV_DUP_FILT_MAX=30
+CONFIG_BT_CTRL_HW_CCA_EFF=0
+CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_EFF=0
+CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
+CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM=100
+CONFIG_BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD=20
+CONFIG_BT_CTRL_BLE_SCAN_DUPL=y
+CONFIG_BT_CTRL_SCAN_DUPL_TYPE=0
+CONFIG_BT_CTRL_SCAN_DUPL_CACHE_SIZE=100
+CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EFF=0
+CONFIG_BT_CTRL_SLEEP_MODE_EFF=0
+CONFIG_BT_CTRL_SLEEP_CLOCK_EFF=0
+CONFIG_BT_CTRL_HCI_TL_EFF=1
+CONFIG_BT_RESERVE_DRAM=0
+CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=y
+CONFIG_BT_NIMBLE_USE_ESP_TIMER=y
+# end of Bluetooth
+
+#
+# CoAP Configuration
+#
+CONFIG_COAP_MBEDTLS_PSK=y
+# CONFIG_COAP_MBEDTLS_PKI is not set
+# CONFIG_COAP_MBEDTLS_DEBUG is not set
+CONFIG_COAP_LOG_DEFAULT_LEVEL=0
+# end of CoAP Configuration
+
+#
+# Driver configurations
+#
+
+#
+# ADC configuration
+#
+# CONFIG_ADC_FORCE_XPD_FSM is not set
+CONFIG_ADC_DISABLE_DAC=y
+# end of ADC configuration
+
+#
+# SPI configuration
+#
+# CONFIG_SPI_MASTER_IN_IRAM is not set
+CONFIG_SPI_MASTER_ISR_IN_IRAM=y
+# CONFIG_SPI_SLAVE_IN_IRAM is not set
+CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
+# end of SPI configuration
+
+#
+# TWAI configuration
+#
+# CONFIG_TWAI_ISR_IN_IRAM is not set
+# end of TWAI configuration
+
+#
+# UART configuration
+#
+# CONFIG_UART_ISR_IN_IRAM is not set
+# end of UART configuration
+# end of Driver configurations
+
+#
+# eFuse Bit Manager
+#
+# CONFIG_EFUSE_CUSTOM_TABLE is not set
+# CONFIG_EFUSE_VIRTUAL is not set
+CONFIG_EFUSE_MAX_BLK_LEN=256
+# end of eFuse Bit Manager
+
+#
+# ESP-TLS
+#
+CONFIG_ESP_TLS_USING_MBEDTLS=y
+CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y
+# CONFIG_ESP_TLS_SERVER is not set
+# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
+# CONFIG_ESP_TLS_INSECURE is not set
+# end of ESP-TLS
+
+#
+# ESP32C3-Specific
+#
+# CONFIG_ESP32C3_DEFAULT_CPU_FREQ_80 is not set
+CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y
+CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ=160
+# CONFIG_ESP32C3_REV_MIN_0 is not set
+# CONFIG_ESP32C3_REV_MIN_1 is not set
+# CONFIG_ESP32C3_REV_MIN_2 is not set
+CONFIG_ESP32C3_REV_MIN_3=y
+CONFIG_ESP32C3_REV_MIN=3
+CONFIG_ESP32C3_DEBUG_OCDAWARE=y
+# CONFIG_ESP32C3_DEBUG_STUBS_ENABLE is not set
+CONFIG_ESP32C3_BROWNOUT_DET=y
+CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_7=y
+# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_6 is not set
+# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_5 is not set
+# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_4 is not set
+# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_3 is not set
+# CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_2 is not set
+CONFIG_ESP32C3_BROWNOUT_DET_LVL=7
+CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC_SYSTIMER=y
+# CONFIG_ESP32C3_TIME_SYSCALL_USE_RTC is not set
+# CONFIG_ESP32C3_TIME_SYSCALL_USE_SYSTIMER is not set
+# CONFIG_ESP32C3_TIME_SYSCALL_USE_NONE is not set
+CONFIG_ESP32C3_RTC_CLK_SRC_INT_RC=y
+# CONFIG_ESP32C3_RTC_CLK_SRC_EXT_CRYS is not set
+# CONFIG_ESP32C3_RTC_CLK_SRC_EXT_OSC is not set
+# CONFIG_ESP32C3_RTC_CLK_SRC_INT_8MD256 is not set
+CONFIG_ESP32C3_RTC_CLK_CAL_CYCLES=1024
+# CONFIG_ESP32C3_NO_BLOBS is not set
+CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND=y
+# end of ESP32C3-Specific
+
+#
+# ADC-Calibration
+#
+# end of ADC-Calibration
+
+#
+# Common ESP-related
+#
+CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
+# end of Common ESP-related
+
+#
+# Ethernet
+#
+CONFIG_ETH_ENABLED=y
+CONFIG_ETH_USE_SPI_ETHERNET=y
+# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set
+# CONFIG_ETH_SPI_ETHERNET_W5500 is not set
+# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set
+# CONFIG_ETH_USE_OPENETH is not set
+# end of Ethernet
+
+#
+# Event Loop Library
+#
+# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
+CONFIG_ESP_EVENT_POST_FROM_ISR=y
+CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
+# end of Event Loop Library
+
+#
+# GDB Stub
+#
+# end of GDB Stub
+
+#
+# ESP HTTP client
+#
+CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
+# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
+CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y
+# end of ESP HTTP client
+
+#
+# HTTP Server
+#
+CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
+CONFIG_HTTPD_MAX_URI_LEN=512
+CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
+CONFIG_HTTPD_PURGE_BUF_LEN=32
+# CONFIG_HTTPD_LOG_PURGE_DATA is not set
+# CONFIG_HTTPD_WS_SUPPORT is not set
+# end of HTTP Server
+
+#
+# ESP HTTPS OTA
+#
+# CONFIG_OTA_ALLOW_HTTP is not set
+# end of ESP HTTPS OTA
+
+#
+# ESP HTTPS server
+#
+# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
+# end of ESP HTTPS server
+
+#
+# Hardware Settings
+#
+
+#
+# MAC Config
+#
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
+# CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_TWO is not set
+CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES_FOUR=y
+CONFIG_ESP32C3_UNIVERSAL_MAC_ADDRESSES=4
+# end of MAC Config
+
+#
+# Sleep Config
+#
+CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y
+# end of Sleep Config
+# end of Hardware Settings
+
+#
+# IPC (Inter-Processor Call)
+#
+CONFIG_ESP_IPC_TASK_STACK_SIZE=1024
+# end of IPC (Inter-Processor Call)
+
+#
+# LCD and Touch Panel
+#
+
+#
+# LCD Peripheral Configuration
+#
+CONFIG_LCD_PERIPH_CLK_SRC_PLL160M=y
+# CONFIG_LCD_PERIPH_CLK_SRC_XTAL is not set
+CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32
+# end of LCD Peripheral Configuration
+# end of LCD and Touch Panel
+
+#
+# ESP NETIF Adapter
+#
+CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
+CONFIG_ESP_NETIF_TCPIP_LWIP=y
+# CONFIG_ESP_NETIF_LOOPBACK is not set
+CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y
+# end of ESP NETIF Adapter
+
+#
+# PHY
+#
+CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
+# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
+CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
+CONFIG_ESP32_PHY_MAX_TX_POWER=20
+# end of PHY
+
+#
+# Power Management
+#
+# CONFIG_PM_ENABLE is not set
+CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
+# end of Power Management
+
+#
+# ESP System Settings
+#
+# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
+CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
+# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set
+CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y
+CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y
+CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y
+# CONFIG_ESP_SYSTEM_USE_EH_FRAME is not set
+
+#
+# Memory protection
+#
+CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=y
+CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK=y
+# end of Memory protection
+
+CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3304
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=7584
+CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y
+# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_ESP_MAIN_TASK_AFFINITY=0x0
+CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=3048
+CONFIG_ESP_CONSOLE_UART_DEFAULT=y
+# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set
+# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_NONE is not set
+CONFIG_ESP_CONSOLE_UART=y
+CONFIG_ESP_CONSOLE_UART_NUM=0
+CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
+CONFIG_ESP_INT_WDT=y
+CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
+CONFIG_ESP_TASK_WDT=y
+# CONFIG_ESP_TASK_WDT_PANIC is not set
+CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
+CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+# CONFIG_ESP_PANIC_HANDLER_IRAM is not set
+# end of ESP System Settings
+
+#
+# High resolution timer (esp_timer)
+#
+# CONFIG_ESP_TIMER_PROFILING is not set
+CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
+CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y
+CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584
+CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1
+# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set
+CONFIG_ESP_TIMER_IMPL_SYSTIMER=y
+# end of High resolution timer (esp_timer)
+
+#
+# Wi-Fi
+#
+CONFIG_ESP32_WIFI_ENABLED=y
+CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y
+CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
+CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP32_WIFI_TX_BA_WIN=6
+CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP32_WIFI_RX_BA_WIN=6
+CONFIG_ESP32_WIFI_NVS_ENABLED=y
+CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752
+CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
+CONFIG_ESP32_WIFI_IRAM_OPT=y
+CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
+# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
+# CONFIG_ESP_WIFI_FTM_ENABLE is not set
+# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set
+# end of Wi-Fi
+
+#
+# Core dump
+#
+# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set
+# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set
+CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y
+# end of Core dump
+
+#
+# FAT Filesystem support
+#
+# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set
+CONFIG_FATFS_CODEPAGE_437=y
+# CONFIG_FATFS_CODEPAGE_720 is not set
+# CONFIG_FATFS_CODEPAGE_737 is not set
+# CONFIG_FATFS_CODEPAGE_771 is not set
+# CONFIG_FATFS_CODEPAGE_775 is not set
+# CONFIG_FATFS_CODEPAGE_850 is not set
+# CONFIG_FATFS_CODEPAGE_852 is not set
+# CONFIG_FATFS_CODEPAGE_855 is not set
+# CONFIG_FATFS_CODEPAGE_857 is not set
+# CONFIG_FATFS_CODEPAGE_860 is not set
+# CONFIG_FATFS_CODEPAGE_861 is not set
+# CONFIG_FATFS_CODEPAGE_862 is not set
+# CONFIG_FATFS_CODEPAGE_863 is not set
+# CONFIG_FATFS_CODEPAGE_864 is not set
+# CONFIG_FATFS_CODEPAGE_865 is not set
+# CONFIG_FATFS_CODEPAGE_866 is not set
+# CONFIG_FATFS_CODEPAGE_869 is not set
+# CONFIG_FATFS_CODEPAGE_932 is not set
+# CONFIG_FATFS_CODEPAGE_936 is not set
+# CONFIG_FATFS_CODEPAGE_949 is not set
+# CONFIG_FATFS_CODEPAGE_950 is not set
+CONFIG_FATFS_CODEPAGE=437
+CONFIG_FATFS_LFN_NONE=y
+# CONFIG_FATFS_LFN_HEAP is not set
+# CONFIG_FATFS_LFN_STACK is not set
+CONFIG_FATFS_FS_LOCK=0
+CONFIG_FATFS_TIMEOUT_MS=10000
+CONFIG_FATFS_PER_FILE_CACHE=y
+# CONFIG_FATFS_USE_FASTSEEK is not set
+# end of FAT Filesystem support
+
+#
+# Modbus configuration
+#
+CONFIG_FMB_COMM_MODE_TCP_EN=y
+CONFIG_FMB_TCP_PORT_DEFAULT=502
+CONFIG_FMB_TCP_PORT_MAX_CONN=5
+CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
+CONFIG_FMB_COMM_MODE_RTU_EN=y
+CONFIG_FMB_COMM_MODE_ASCII_EN=y
+CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_FMB_QUEUE_LENGTH=20
+CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
+CONFIG_FMB_SERIAL_BUF_SIZE=256
+CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8
+CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000
+CONFIG_FMB_PORT_TASK_PRIO=10
+CONFIG_FMB_PORT_TASK_AFFINITY=0x7FFFFFFF
+CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y
+CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233
+CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_FMB_CONTROLLER_STACK_SIZE=4096
+CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20
+# CONFIG_FMB_TIMER_PORT_ENABLED is not set
+CONFIG_FMB_TIMER_GROUP=0
+CONFIG_FMB_TIMER_INDEX=0
+CONFIG_FMB_MASTER_TIMER_GROUP=0
+CONFIG_FMB_MASTER_TIMER_INDEX=0
+# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set
+# end of Modbus configuration
+
+#
+# FreeRTOS
+#
+CONFIG_FREERTOS_UNICORE=y
+CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
+CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y
+CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y
+# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set
+CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y
+CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=y
+CONFIG_FREERTOS_HZ=100
+CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
+# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
+CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
+CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
+CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
+# CONFIG_FREERTOS_ASSERT_DISABLE is not set
+CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
+CONFIG_FREERTOS_ISR_STACKSIZE=1536
+# CONFIG_FREERTOS_LEGACY_HOOKS is not set
+CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
+CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
+# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
+CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
+CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
+# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
+# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
+CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y
+CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
+# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
+# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set
+CONFIG_FREERTOS_DEBUG_OCDAWARE=y
+# end of FreeRTOS
+
+#
+# Hardware Abstraction Layer (HAL) and Low Level (LL)
+#
+CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y
+# CONFIG_HAL_ASSERTION_DISABLE is not set
+# CONFIG_HAL_ASSERTION_SILIENT is not set
+# CONFIG_HAL_ASSERTION_ENABLE is not set
+CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2
+# end of Hardware Abstraction Layer (HAL) and Low Level (LL)
+
+#
+# Heap memory debugging
+#
+CONFIG_HEAP_POISONING_DISABLED=y
+# CONFIG_HEAP_POISONING_LIGHT is not set
+# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set
+CONFIG_HEAP_TRACING_OFF=y
+# CONFIG_HEAP_TRACING_STANDALONE is not set
+# CONFIG_HEAP_TRACING_TOHOST is not set
+# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set
+# end of Heap memory debugging
+
+#
+# jsmn
+#
+# CONFIG_JSMN_PARENT_LINKS is not set
+# CONFIG_JSMN_STRICT is not set
+# end of jsmn
+
+#
+# libsodium
+#
+# end of libsodium
+
+#
+# Log output
+#
+# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
+# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
+# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
+CONFIG_LOG_DEFAULT_LEVEL_INFO=y
+# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
+# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y
+# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set
+# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set
+CONFIG_LOG_MAXIMUM_LEVEL=3
+CONFIG_LOG_COLORS=y
+CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
+# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set
+# end of Log output
+
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
+# CONFIG_LWIP_NETIF_API is not set
+CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
+# CONFIG_LWIP_L2_TO_L3_COPY is not set
+# CONFIG_LWIP_IRAM_OPTIMIZATION is not set
+CONFIG_LWIP_TIMERS_ONDEMAND=y
+CONFIG_LWIP_MAX_SOCKETS=10
+# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
+# CONFIG_LWIP_SO_LINGER is not set
+CONFIG_LWIP_SO_REUSE=y
+CONFIG_LWIP_SO_REUSE_RXTOALL=y
+# CONFIG_LWIP_SO_RCVBUF is not set
+# CONFIG_LWIP_NETBUF_RECVINFO is not set
+CONFIG_LWIP_IP4_FRAG=y
+CONFIG_LWIP_IP6_FRAG=y
+# CONFIG_LWIP_IP4_REASSEMBLY is not set
+# CONFIG_LWIP_IP6_REASSEMBLY is not set
+# CONFIG_LWIP_IP_FORWARD is not set
+# CONFIG_LWIP_STATS is not set
+# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
+CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
+CONFIG_LWIP_GARP_TMR_INTERVAL=60
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
+# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set
+# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
+
+#
+# DHCP server
+#
+CONFIG_LWIP_DHCPS=y
+CONFIG_LWIP_DHCPS_LEASE_UNIT=60
+CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
+# end of DHCP server
+
+# CONFIG_LWIP_AUTOIP is not set
+CONFIG_LWIP_IPV6=y
+# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
+CONFIG_LWIP_IPV6_NUM_ADDRESSES=3
+# CONFIG_LWIP_IPV6_FORWARD is not set
+CONFIG_LWIP_IPV6_RDNSS_MAX_DNS_SERVERS=0
+# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set
+CONFIG_LWIP_NETIF_LOOPBACK=y
+CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
+
+#
+# TCP
+#
+CONFIG_LWIP_MAX_ACTIVE_TCP=16
+CONFIG_LWIP_MAX_LISTENING_TCP=16
+CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y
+CONFIG_LWIP_TCP_MAXRTX=12
+CONFIG_LWIP_TCP_SYNMAXRTX=12
+CONFIG_LWIP_TCP_MSS=1440
+CONFIG_LWIP_TCP_TMR_INTERVAL=250
+CONFIG_LWIP_TCP_MSL=60000
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744
+CONFIG_LWIP_TCP_WND_DEFAULT=5744
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
+CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
+# CONFIG_LWIP_TCP_SACK_OUT is not set
+# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_LWIP_TCP_OVERSIZE_MSS=y
+# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
+CONFIG_LWIP_TCP_RTO_TIME=1500
+# end of TCP
+
+#
+# UDP
+#
+CONFIG_LWIP_MAX_UDP_PCBS=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=6
+# end of UDP
+
+#
+# Checksums
+#
+# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set
+# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set
+CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y
+# end of Checksums
+
+CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
+CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_LWIP_PPP_SUPPORT is not set
+CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3
+CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5
+# CONFIG_LWIP_SLIP_SUPPORT is not set
+
+#
+# ICMP
+#
+CONFIG_LWIP_ICMP=y
+# CONFIG_LWIP_MULTICAST_PING is not set
+# CONFIG_LWIP_BROADCAST_PING is not set
+# end of ICMP
+
+#
+# LWIP RAW API
+#
+CONFIG_LWIP_MAX_RAW_PCBS=16
+# end of LWIP RAW API
+
+#
+# SNTP
+#
+CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
+CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
+# end of SNTP
+
+CONFIG_LWIP_ESP_LWIP_ASSERT=y
+
+#
+# Hooks
+#
+# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set
+CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y
+# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set
+CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y
+# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set
+# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set
+CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y
+# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set
+# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set
+CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y
+# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set
+# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set
+# end of Hooks
+
+# CONFIG_LWIP_DEBUG is not set
+# end of LWIP
+
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
+# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
+# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
+CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
+CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
+CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
+# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set
+# CONFIG_MBEDTLS_DEBUG is not set
+
+#
+# Certificate Bundle
+#
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
+# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
+# end of Certificate Bundle
+
+# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
+# CONFIG_MBEDTLS_CMAC_C is not set
+CONFIG_MBEDTLS_HARDWARE_AES=y
+CONFIG_MBEDTLS_AES_USE_INTERRUPT=y
+CONFIG_MBEDTLS_HARDWARE_MPI=y
+CONFIG_MBEDTLS_HARDWARE_SHA=y
+CONFIG_MBEDTLS_ROM_MD5=y
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set
+CONFIG_MBEDTLS_HAVE_TIME=y
+# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
+CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y
+CONFIG_MBEDTLS_SHA512_C=y
+CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
+# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
+# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
+# CONFIG_MBEDTLS_TLS_DISABLED is not set
+CONFIG_MBEDTLS_TLS_SERVER=y
+CONFIG_MBEDTLS_TLS_CLIENT=y
+CONFIG_MBEDTLS_TLS_ENABLED=y
+
+#
+# TLS Key Exchange Methods
+#
+# CONFIG_MBEDTLS_PSK_MODES is not set
+CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
+# end of TLS Key Exchange Methods
+
+CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
+# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set
+CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
+# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set
+# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
+CONFIG_MBEDTLS_SSL_ALPN=y
+CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y
+CONFIG_MBEDTLS_X509_CHECK_KEY_USAGE=y
+CONFIG_MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE=y
+CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y
+
+#
+# Symmetric Ciphers
+#
+CONFIG_MBEDTLS_AES_C=y
+# CONFIG_MBEDTLS_CAMELLIA_C is not set
+# CONFIG_MBEDTLS_DES_C is not set
+CONFIG_MBEDTLS_RC4_DISABLED=y
+# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set
+# CONFIG_MBEDTLS_RC4_ENABLED is not set
+# CONFIG_MBEDTLS_BLOWFISH_C is not set
+# CONFIG_MBEDTLS_XTEA_C is not set
+CONFIG_MBEDTLS_CCM_C=y
+CONFIG_MBEDTLS_GCM_C=y
+# CONFIG_MBEDTLS_NIST_KW_C is not set
+# end of Symmetric Ciphers
+
+# CONFIG_MBEDTLS_RIPEMD160_C is not set
+
+#
+# Certificates
+#
+CONFIG_MBEDTLS_PEM_PARSE_C=y
+CONFIG_MBEDTLS_PEM_WRITE_C=y
+CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
+CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
+# end of Certificates
+
+CONFIG_MBEDTLS_ECP_C=y
+CONFIG_MBEDTLS_ECDH_C=y
+CONFIG_MBEDTLS_ECDSA_C=y
+# CONFIG_MBEDTLS_ECJPAKE_C is not set
+CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
+CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
+# CONFIG_MBEDTLS_POLY1305_C is not set
+# CONFIG_MBEDTLS_CHACHA20_C is not set
+# CONFIG_MBEDTLS_HKDF_C is not set
+# CONFIG_MBEDTLS_THREADING_C is not set
+CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI=y
+# CONFIG_MBEDTLS_SECURITY_RISKS is not set
+# end of mbedTLS
+
+#
+# mDNS
+#
+CONFIG_MDNS_MAX_SERVICES=10
+CONFIG_MDNS_TASK_PRIORITY=1
+CONFIG_MDNS_TASK_STACK_SIZE=4096
+# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_MDNS_TASK_AFFINITY_CPU0=y
+CONFIG_MDNS_TASK_AFFINITY=0x0
+CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000
+# CONFIG_MDNS_STRICT_MODE is not set
+CONFIG_MDNS_TIMER_PERIOD_MS=100
+# CONFIG_MDNS_NETWORKING_SOCKET is not set
+# end of mDNS
+
+#
+# ESP-MQTT Configurations
+#
+CONFIG_MQTT_PROTOCOL_311=y
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set
+# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set
+# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set
+# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set
+# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set
+# CONFIG_MQTT_CUSTOM_OUTBOX is not set
+# end of ESP-MQTT Configurations
+
+#
+# Newlib
+#
+CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set
+CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
+# CONFIG_NEWLIB_NANO_FORMAT is not set
+# end of Newlib
+
+#
+# NVS
+#
+# end of NVS
+
+#
+# OpenSSL
+#
+# CONFIG_OPENSSL_DEBUG is not set
+CONFIG_OPENSSL_ERROR_STACK=y
+# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set
+CONFIG_OPENSSL_ASSERT_EXIT=y
+# end of OpenSSL
+
+#
+# OpenThread
+#
+# CONFIG_OPENTHREAD_ENABLED is not set
+# end of OpenThread
+
+#
+# PThreads
+#
+CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_PTHREAD_STACK_MIN=768
+CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
+# end of PThreads
+
+#
+# SPI Flash driver
+#
+# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
+# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
+CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
+# CONFIG_SPI_FLASH_ROM_IMPL is not set
+CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set
+# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set
+# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set
+# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set
+CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y
+CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20
+CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1
+# CONFIG_SPI_FLASH_AUTO_SUSPEND is not set
+CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192
+# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set
+# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set
+# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set
+
+#
+# Auto-detect flash chips
+#
+CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y
+# end of Auto-detect flash chips
+
+CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y
+# end of SPI Flash driver
+
+#
+# SPIFFS Configuration
+#
+CONFIG_SPIFFS_MAX_PARTITIONS=3
+
+#
+# SPIFFS Cache Configuration
+#
+CONFIG_SPIFFS_CACHE=y
+CONFIG_SPIFFS_CACHE_WR=y
+# CONFIG_SPIFFS_CACHE_STATS is not set
+# end of SPIFFS Cache Configuration
+
+CONFIG_SPIFFS_PAGE_CHECK=y
+CONFIG_SPIFFS_GC_MAX_RUNS=10
+# CONFIG_SPIFFS_GC_STATS is not set
+CONFIG_SPIFFS_PAGE_SIZE=256
+CONFIG_SPIFFS_OBJ_NAME_LEN=32
+# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set
+CONFIG_SPIFFS_USE_MAGIC=y
+CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
+CONFIG_SPIFFS_META_LENGTH=4
+CONFIG_SPIFFS_USE_MTIME=y
+
+#
+# Debug Configuration
+#
+# CONFIG_SPIFFS_DBG is not set
+# CONFIG_SPIFFS_API_DBG is not set
+# CONFIG_SPIFFS_GC_DBG is not set
+# CONFIG_SPIFFS_CACHE_DBG is not set
+# CONFIG_SPIFFS_CHECK_DBG is not set
+# CONFIG_SPIFFS_TEST_VISUALISATION is not set
+# end of Debug Configuration
+# end of SPIFFS Configuration
+
+#
+# TCP Transport
+#
+
+#
+# Websocket
+#
+CONFIG_WS_TRANSPORT=y
+CONFIG_WS_BUFFER_SIZE=1024
+# end of Websocket
+# end of TCP Transport
+
+#
+# Unity unit testing library
+#
+CONFIG_UNITY_ENABLE_FLOAT=y
+CONFIG_UNITY_ENABLE_DOUBLE=y
+# CONFIG_UNITY_ENABLE_64BIT is not set
+# CONFIG_UNITY_ENABLE_COLOR is not set
+CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
+# CONFIG_UNITY_ENABLE_FIXTURE is not set
+# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set
+# end of Unity unit testing library
+
+#
+# Virtual file system
+#
+CONFIG_VFS_SUPPORT_IO=y
+CONFIG_VFS_SUPPORT_DIR=y
+CONFIG_VFS_SUPPORT_SELECT=y
+CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_VFS_SUPPORT_TERMIOS=y
+
+#
+# Host File System I/O (Semihosting)
+#
+CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
+# end of Host File System I/O (Semihosting)
+# end of Virtual file system
+
+#
+# Wear Levelling
+#
+# CONFIG_WL_SECTOR_SIZE_512 is not set
+CONFIG_WL_SECTOR_SIZE_4096=y
+CONFIG_WL_SECTOR_SIZE=4096
+# end of Wear Levelling
+
+#
+# Wi-Fi Provisioning Manager
+#
+CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
+CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
+# end of Wi-Fi Provisioning Manager
+
+#
+# Supplicant
+#
+CONFIG_WPA_MBEDTLS_CRYPTO=y
+# CONFIG_WPA_WAPI_PSK is not set
+# CONFIG_WPA_DEBUG_PRINT is not set
+# CONFIG_WPA_TESTING_OPTIONS is not set
+# CONFIG_WPA_WPS_STRICT is not set
+# CONFIG_WPA_11KV_SUPPORT is not set
+# end of Supplicant
+# end of Component config
+
+#
+# Compatibility options
+#
+# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
+# end of Compatibility options
+
+# Deprecated options for backward compatibility
+CONFIG_TOOLPREFIX="riscv32-esp-elf-"
+# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
+CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
+# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
+CONFIG_LOG_BOOTLOADER_LEVEL=3
+# CONFIG_APP_ROLLBACK_ENABLE is not set
+# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
+# CONFIG_FLASHMODE_QIO is not set
+# CONFIG_FLASHMODE_QOUT is not set
+CONFIG_FLASHMODE_DIO=y
+# CONFIG_FLASHMODE_DOUT is not set
+# CONFIG_MONITOR_BAUD_9600B is not set
+# CONFIG_MONITOR_BAUD_57600B is not set
+CONFIG_MONITOR_BAUD_115200B=y
+# CONFIG_MONITOR_BAUD_230400B is not set
+# CONFIG_MONITOR_BAUD_921600B is not set
+# CONFIG_MONITOR_BAUD_2MB is not set
+# CONFIG_MONITOR_BAUD_OTHER is not set
+CONFIG_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_MONITOR_BAUD=115200
+CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
+# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
+CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
+# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
+CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2
+# CONFIG_CXX_EXCEPTIONS is not set
+CONFIG_STACK_CHECK_NONE=y
+# CONFIG_STACK_CHECK_NORM is not set
+# CONFIG_STACK_CHECK_STRONG is not set
+# CONFIG_STACK_CHECK_ALL is not set
+# CONFIG_WARN_WRITE_STRINGS is not set
+# CONFIG_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
+CONFIG_ESP32_APPTRACE_DEST_NONE=y
+CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
+CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
+CONFIG_ADC2_DISABLE_DAC=y
+# CONFIG_EVENT_LOOP_PROFILING is not set
+CONFIG_POST_EVENTS_FROM_ISR=y
+CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
+CONFIG_ESP_SYSTEM_PD_FLASH=y
+CONFIG_IPC_TASK_STACK_SIZE=1024
+CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y
+# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set
+CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP32S2_PANIC_GDBSTUB is not set
+CONFIG_ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP=y
+CONFIG_ESP32H2_MEMPROT_FEATURE=y
+CONFIG_ESP32H2_MEMPROT_FEATURE_LOCK=y
+CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=3304
+CONFIG_MAIN_TASK_STACK_SIZE=7584
+CONFIG_CONSOLE_UART_DEFAULT=y
+# CONFIG_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_UART_NONE is not set
+CONFIG_CONSOLE_UART=y
+CONFIG_CONSOLE_UART_NUM=0
+CONFIG_CONSOLE_UART_BAUDRATE=115200
+CONFIG_INT_WDT=y
+CONFIG_INT_WDT_TIMEOUT_MS=300
+CONFIG_TASK_WDT=y
+# CONFIG_TASK_WDT_PANIC is not set
+CONFIG_TASK_WDT_TIMEOUT_S=5
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+CONFIG_TIMER_TASK_STACK_SIZE=3584
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
+CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
+CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_MB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_MB_QUEUE_LENGTH=20
+CONFIG_MB_SERIAL_TASK_STACK_SIZE=4096
+CONFIG_MB_SERIAL_BUF_SIZE=256
+CONFIG_MB_SERIAL_TASK_PRIO=10
+CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT=y
+CONFIG_MB_CONTROLLER_SLAVE_ID=0x00112233
+CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_MB_CONTROLLER_STACK_SIZE=4096
+CONFIG_MB_EVENT_QUEUE_TIMEOUT=20
+# CONFIG_MB_TIMER_PORT_ENABLED is not set
+CONFIG_MB_TIMER_GROUP=0
+CONFIG_MB_TIMER_INDEX=0
+# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
+CONFIG_TIMER_TASK_PRIORITY=1
+CONFIG_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_TIMER_QUEUE_LENGTH=10
+# CONFIG_L2_TO_L3_COPY is not set
+# CONFIG_USE_ONLY_LWIP_SELECT is not set
+CONFIG_ESP_GRATUITOUS_ARP=y
+CONFIG_GARP_TMR_INTERVAL=60
+CONFIG_TCPIP_RECVMBOX_SIZE=32
+CONFIG_TCP_MAXRTX=12
+CONFIG_TCP_SYNMAXRTX=12
+CONFIG_TCP_MSS=1440
+CONFIG_TCP_MSL=60000
+CONFIG_TCP_SND_BUF_DEFAULT=5744
+CONFIG_TCP_WND_DEFAULT=5744
+CONFIG_TCP_RECVMBOX_SIZE=6
+CONFIG_TCP_QUEUE_OOSEQ=y
+# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_TCP_OVERSIZE_MSS=y
+# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_TCP_OVERSIZE_DISABLE is not set
+CONFIG_UDP_RECVMBOX_SIZE=6
+CONFIG_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set
+CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_PPP_SUPPORT is not set
+CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_ESP32_PTHREAD_STACK_MIN=768
+CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
+CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
+CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_SUPPORT_TERMIOS=y
+CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
+# End of deprecated options
diff --git a/minimal-examples/embedded/esp32/esp-c3dev/sdkconfig.h b/minimal-examples/embedded/esp32/esp-c3dev/sdkconfig.h
new file mode 100644 (file)
index 0000000..43d3c99
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * Automatically generated file. DO NOT EDIT.
+ * Espressif IoT Development Framework (ESP-IDF) Configuration Header
+ */
+#pragma once
+#define CONFIG_IDF_CMAKE 1
+#define CONFIG_IDF_TARGET "esp32"
+#define CONFIG_IDF_TARGET_ESP32 1
+#define CONFIG_IDF_FIRMWARE_CHIP_ID 0x0000
+#define CONFIG_SDK_TOOLPREFIX "xtensa-esp32-elf-"
+#define CONFIG_APP_BUILD_TYPE_APP_2NDBOOT 1
+#define CONFIG_APP_BUILD_GENERATE_BINARIES 1
+#define CONFIG_APP_BUILD_BOOTLOADER 1
+#define CONFIG_APP_BUILD_USE_FLASH_SECTIONS 1
+#define CONFIG_APP_COMPILE_TIME_DATE 1
+#define CONFIG_APP_RETRIEVE_LEN_ELF_SHA 16
+#define CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE 1
+#define CONFIG_BOOTLOADER_LOG_LEVEL_INFO 1
+#define CONFIG_BOOTLOADER_LOG_LEVEL 3
+#define CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V 1
+#define CONFIG_BOOTLOADER_WDT_ENABLE 1
+#define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
+#define CONFIG_BOOTLOADER_RESERVE_RTC_SIZE 0x0
+#define CONFIG_ESPTOOLPY_BAUD_OTHER_VAL 115200
+#define CONFIG_ESPTOOLPY_FLASHMODE_DIO 1
+#define CONFIG_ESPTOOLPY_FLASHMODE "dio"
+#define CONFIG_ESPTOOLPY_FLASHFREQ_26M 1
+#define CONFIG_ESPTOOLPY_FLASHFREQ "26m"
+#define CONFIG_ESPTOOLPY_FLASHSIZE_2MB 1
+#define CONFIG_ESPTOOLPY_FLASHSIZE "2MB"
+#define CONFIG_ESPTOOLPY_FLASHSIZE_DETECT 1
+#define CONFIG_ESPTOOLPY_BEFORE_RESET 1
+#define CONFIG_ESPTOOLPY_BEFORE "default_reset"
+#define CONFIG_ESPTOOLPY_AFTER_RESET 1
+#define CONFIG_ESPTOOLPY_AFTER "hard_reset"
+#define CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B 1
+#define CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL 115200
+#define CONFIG_ESPTOOLPY_MONITOR_BAUD 115200
+#define CONFIG_PARTITION_TABLE_CUSTOM 1
+#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv"
+#define CONFIG_PARTITION_TABLE_FILENAME "partitions_singleapp.csv"
+#define CONFIG_PARTITION_TABLE_OFFSET 0x8000
+#define CONFIG_PARTITION_TABLE_MD5 1
+#define CONFIG_COMPILER_OPTIMIZATION_DEFAULT 1
+#define CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE 1
+#define CONFIG_COMPILER_STACK_CHECK_MODE_NONE 1
+#define CONFIG_APPTRACE_DEST_NONE 1
+#define CONFIG_APPTRACE_LOCK_ENABLE 1
+#define CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF 0
+#define CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF 0
+#define CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF 0
+#define CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF 0
+#define CONFIG_BTDM_CTRL_PINNED_TO_CORE 0
+#define CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF 1
+#define CONFIG_BT_RESERVE_DRAM 0x0
+#define CONFIG_COAP_MBEDTLS_PSK 1
+#define CONFIG_COAP_LOG_DEFAULT_LEVEL 0
+#define CONFIG_ADC_DISABLE_DAC 1
+#define CONFIG_SPI_MASTER_ISR_IN_IRAM 1
+#define CONFIG_SPI_SLAVE_ISR_IN_IRAM 1
+#define CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4 1
+#define CONFIG_EFUSE_MAX_BLK_LEN 192
+#define CONFIG_ESP_TLS_USING_MBEDTLS 1
+#define CONFIG_ESP32_REV_MIN_0 1
+#define CONFIG_ESP32_REV_MIN 0
+#define CONFIG_ESP32_DPORT_WORKAROUND 1
+#define CONFIG_ESP32_DEFAULT_CPU_FREQ_160 1
+#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 160
+#define CONFIG_ESP32_TRACEMEM_RESERVE_DRAM 0x0
+#define CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR 1
+#define CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES 4
+#define CONFIG_ESP32_ULP_COPROC_RESERVE_MEM 0
+#define CONFIG_ESP32_DEBUG_OCDAWARE 1
+#define CONFIG_ESP32_BROWNOUT_DET 1
+#define CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0 1
+#define CONFIG_ESP32_BROWNOUT_DET_LVL 0
+#define CONFIG_ESP32_REDUCE_PHY_TX_POWER 1
+#define CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 1
+#define CONFIG_ESP32_RTC_CLK_SRC_INT_RC 1
+#define CONFIG_ESP32_RTC_CLK_CAL_CYCLES 1024
+#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000
+#define CONFIG_ESP32_XTAL_FREQ_26 1
+#define CONFIG_ESP32_XTAL_FREQ 26
+#define CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL 5
+#define CONFIG_ADC_CAL_EFUSE_TP_ENABLE 1
+#define CONFIG_ADC_CAL_EFUSE_VREF_ENABLE 1
+#define CONFIG_ADC_CAL_LUT_ENABLE 1
+#define CONFIG_ESP_ERR_TO_NAME_LOOKUP 1
+#define CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE 32
+#define CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE 2304
+#define CONFIG_ESP_MAIN_TASK_STACK_SIZE 6584
+#define CONFIG_ESP_IPC_TASK_STACK_SIZE 1024
+#define CONFIG_ESP_IPC_USES_CALLERS_PRIORITY 1
+#define CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE 2048
+#define CONFIG_ESP_CONSOLE_UART_DEFAULT 1
+#define CONFIG_ESP_CONSOLE_UART_NUM 0
+#define CONFIG_ESP_CONSOLE_UART_TX_GPIO 1
+#define CONFIG_ESP_CONSOLE_UART_RX_GPIO 3
+#define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200
+#define CONFIG_ESP_INT_WDT 1
+#define CONFIG_ESP_INT_WDT_TIMEOUT_MS 300
+#define CONFIG_ESP_INT_WDT_CHECK_CPU1 1
+#define CONFIG_ESP_TASK_WDT 1
+#define CONFIG_ESP_TASK_WDT_TIMEOUT_S 5
+#define CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 1
+#define CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_BT 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH 1
+#define CONFIG_ETH_ENABLED 1
+#define CONFIG_ETH_USE_ESP32_EMAC 1
+#define CONFIG_ETH_PHY_INTERFACE_RMII 1
+#define CONFIG_ETH_RMII_CLK_INPUT 1
+#define CONFIG_ETH_RMII_CLK_IN_GPIO 0
+#define CONFIG_ETH_DMA_BUFFER_SIZE 512
+#define CONFIG_ETH_DMA_RX_BUFFER_NUM 10
+#define CONFIG_ETH_DMA_TX_BUFFER_NUM 10
+#define CONFIG_ETH_USE_SPI_ETHERNET 1
+#define CONFIG_ESP_EVENT_POST_FROM_ISR 1
+#define CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR 1
+#define CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS 1
+#define CONFIG_HTTPD_MAX_REQ_HDR_LEN 512
+#define CONFIG_HTTPD_MAX_URI_LEN 512
+#define CONFIG_HTTPD_ERR_RESP_NO_DELAY 1
+#define CONFIG_HTTPD_PURGE_BUF_LEN 32
+#define CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL 120
+#define CONFIG_ESP_NETIF_TCPIP_LWIP 1
+#define CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER 1
+#define CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT 1
+#define CONFIG_ESP_TIMER_TASK_STACK_SIZE 3584
+#define CONFIG_ESP_TIMER_IMPL_TG0_LAC 1
+#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 10
+#define CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 32
+#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER 1
+#define CONFIG_ESP32_WIFI_TX_BUFFER_TYPE 1
+#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32
+#define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 1
+#define CONFIG_ESP32_WIFI_TX_BA_WIN 6
+#define CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED 1
+#define CONFIG_ESP32_WIFI_RX_BA_WIN 6
+#define CONFIG_ESP32_WIFI_NVS_ENABLED 1
+#define CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 1
+#define CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN 752
+#define CONFIG_ESP32_WIFI_MGMT_SBUF_NUM 32
+#define CONFIG_ESP32_WIFI_IRAM_OPT 1
+#define CONFIG_ESP32_WIFI_RX_IRAM_OPT 1
+#define CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE 1
+#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1
+#define CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER 20
+#define CONFIG_ESP32_PHY_MAX_TX_POWER 20
+#define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1
+#define CONFIG_FATFS_CODEPAGE_437 1
+#define CONFIG_FATFS_CODEPAGE 437
+#define CONFIG_FATFS_LFN_NONE 1
+#define CONFIG_FATFS_FS_LOCK 0
+#define CONFIG_FATFS_TIMEOUT_MS 10000
+#define CONFIG_FATFS_PER_FILE_CACHE 1
+#define CONFIG_FMB_COMM_MODE_RTU_EN 1
+#define CONFIG_FMB_COMM_MODE_ASCII_EN 1
+#define CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND 150
+#define CONFIG_FMB_MASTER_DELAY_MS_CONVERT 200
+#define CONFIG_FMB_QUEUE_LENGTH 20
+#define CONFIG_FMB_SERIAL_TASK_STACK_SIZE 2048
+#define CONFIG_FMB_SERIAL_BUF_SIZE 256
+#define CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB 8
+#define CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS 1000
+#define CONFIG_FMB_SERIAL_TASK_PRIO 10
+#define CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT 20
+#define CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE 20
+#define CONFIG_FMB_CONTROLLER_STACK_SIZE 4096
+#define CONFIG_FMB_EVENT_QUEUE_TIMEOUT 20
+#define CONFIG_FMB_TIMER_PORT_ENABLED 1
+#define CONFIG_FMB_TIMER_GROUP 0
+#define CONFIG_FMB_TIMER_INDEX 0
+#define CONFIG_FREERTOS_NO_AFFINITY 0x7FFFFFFF
+#define CONFIG_FREERTOS_CORETIMER_0 1
+#define CONFIG_FREERTOS_HZ 100
+#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1
+#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY 1
+#define CONFIG_FREERTOS_INTERRUPT_BACKTRACE 1
+#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 1
+#define CONFIG_FREERTOS_ASSERT_FAIL_ABORT 1
+#define CONFIG_FREERTOS_IDLE_TASK_STACKSIZE 1536
+#define CONFIG_FREERTOS_ISR_STACKSIZE 1536
+#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16
+#define CONFIG_FREERTOS_TIMER_TASK_PRIORITY 1
+#define CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH 2048
+#define CONFIG_FREERTOS_TIMER_QUEUE_LENGTH 10
+#define CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE 0
+#define CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER 1
+#define CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER 1
+#define CONFIG_FREERTOS_DEBUG_OCDAWARE 1
+#define CONFIG_HEAP_POISONING_DISABLED 1
+#define CONFIG_HEAP_TRACING_OFF 1
+#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1
+#define CONFIG_LOG_DEFAULT_LEVEL 3
+#define CONFIG_LOG_COLORS 1
+#define CONFIG_LOG_TIMESTAMP_SOURCE_RTOS 1
+#define CONFIG_LWIP_LOCAL_HOSTNAME "espressif"
+#define CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES 1
+#define CONFIG_LWIP_TIMERS_ONDEMAND 1
+#define CONFIG_LWIP_MAX_SOCKETS 10
+#define CONFIG_LWIP_SO_REUSE 1
+#define CONFIG_LWIP_SO_REUSE_RXTOALL 1
+#define CONFIG_LWIP_IP_FRAG 1
+#define CONFIG_LWIP_ESP_GRATUITOUS_ARP 1
+#define CONFIG_LWIP_GARP_TMR_INTERVAL 60
+#define CONFIG_LWIP_TCPIP_RECVMBOX_SIZE 32
+#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1
+#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60
+#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8
+#define CONFIG_LWIP_NETIF_LOOPBACK 1
+#define CONFIG_LWIP_LOOPBACK_MAX_PBUFS 8
+#define CONFIG_LWIP_MAX_ACTIVE_TCP 16
+#define CONFIG_LWIP_MAX_LISTENING_TCP 16
+#define CONFIG_LWIP_TCP_MAXRTX 12
+#define CONFIG_LWIP_TCP_SYNMAXRTX 6
+#define CONFIG_LWIP_TCP_MSS 1440
+#define CONFIG_LWIP_TCP_TMR_INTERVAL 250
+#define CONFIG_LWIP_TCP_MSL 60000
+#define CONFIG_LWIP_TCP_SND_BUF_DEFAULT 5744
+#define CONFIG_LWIP_TCP_WND_DEFAULT 5744
+#define CONFIG_LWIP_TCP_RECVMBOX_SIZE 6
+#define CONFIG_LWIP_TCP_QUEUE_OOSEQ 1
+#define CONFIG_LWIP_TCP_OVERSIZE_MSS 1
+#define CONFIG_LWIP_MAX_UDP_PCBS 16
+#define CONFIG_LWIP_UDP_RECVMBOX_SIZE 6
+#define CONFIG_LWIP_TCPIP_TASK_STACK_SIZE 3072
+#define CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY 1
+#define CONFIG_LWIP_TCPIP_TASK_AFFINITY 0x7FFFFFFF
+#define CONFIG_LWIP_MAX_RAW_PCBS 16
+#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1
+#define CONFIG_LWIP_SNTP_UPDATE_DELAY 3600000
+#define CONFIG_LWIP_ESP_LWIP_ASSERT 1
+#define CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC 1
+#define CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN 1
+#define CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN 16384
+#define CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN 4096
+#define CONFIG_MBEDTLS_CERTIFICATE_BUNDLE 1
+#define CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL 1
+#define CONFIG_MBEDTLS_HARDWARE_AES 1
+#define CONFIG_MBEDTLS_HARDWARE_MPI 1
+#define CONFIG_MBEDTLS_HARDWARE_SHA 1
+#define CONFIG_MBEDTLS_HAVE_TIME 1
+#define CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT 1
+#define CONFIG_MBEDTLS_TLS_SERVER 1
+#define CONFIG_MBEDTLS_TLS_CLIENT 1
+#define CONFIG_MBEDTLS_TLS_ENABLED 1
+#define CONFIG_MBEDTLS_PSK_MODES 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA 1
+#define CONFIG_MBEDTLS_SSL_RENEGOTIATION 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_1 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 1
+#define CONFIG_MBEDTLS_SSL_PROTO_DTLS 1
+#define CONFIG_MBEDTLS_SSL_ALPN 1
+#define CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS 1
+#define CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS 1
+#define CONFIG_MBEDTLS_AES_C 1
+#define CONFIG_MBEDTLS_RC4_DISABLED 1
+#define CONFIG_MBEDTLS_CCM_C 1
+#define CONFIG_MBEDTLS_GCM_C 1
+#define CONFIG_MBEDTLS_PEM_PARSE_C 1
+#define CONFIG_MBEDTLS_PEM_WRITE_C 1
+#define CONFIG_MBEDTLS_X509_CRL_PARSE_C 1
+#define CONFIG_MBEDTLS_X509_CSR_PARSE_C 1
+#define CONFIG_MBEDTLS_ECP_C 1
+#define CONFIG_MBEDTLS_ECDH_C 1
+#define CONFIG_MBEDTLS_ECDSA_C 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_NIST_OPTIM 1
+#define CONFIG_MDNS_MAX_SERVICES 10
+#define CONFIG_MDNS_TASK_PRIORITY 1
+#define CONFIG_MDNS_TASK_AFFINITY_CPU0 1
+#define CONFIG_MDNS_TASK_AFFINITY 0x0
+#define CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS 2000
+#define CONFIG_MDNS_TIMER_PERIOD_MS 100
+#define CONFIG_MQTT_PROTOCOL_311 1
+#define CONFIG_MQTT_TRANSPORT_SSL 1
+#define CONFIG_MQTT_TRANSPORT_WEBSOCKET 1
+#define CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE 1
+#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF 1
+#define CONFIG_NEWLIB_STDIN_LINE_ENDING_CR 1
+#define CONFIG_OPENSSL_ASSERT_EXIT 1
+#define CONFIG_PTHREAD_TASK_PRIO_DEFAULT 5
+#define CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT 3072
+#define CONFIG_PTHREAD_STACK_MIN 768
+#define CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY 1
+#define CONFIG_PTHREAD_TASK_CORE_DEFAULT -1
+#define CONFIG_PTHREAD_TASK_NAME_DEFAULT "pthread"
+#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1
+#define CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS 1
+#define CONFIG_SPI_FLASH_YIELD_DURING_ERASE 1
+#define CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS 20
+#define CONFIG_SPI_FLASH_ERASE_YIELD_TICKS 1
+#define CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP 1
+#define CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP 1
+#define CONFIG_SPI_FLASH_SUPPORT_GD_CHIP 1
+#define CONFIG_SPIFFS_MAX_PARTITIONS 3
+#define CONFIG_SPIFFS_CACHE 1
+#define CONFIG_SPIFFS_CACHE_WR 1
+#define CONFIG_SPIFFS_PAGE_CHECK 1
+#define CONFIG_SPIFFS_GC_MAX_RUNS 10
+#define CONFIG_SPIFFS_PAGE_SIZE 256
+#define CONFIG_SPIFFS_OBJ_NAME_LEN 32
+#define CONFIG_SPIFFS_USE_MAGIC 1
+#define CONFIG_SPIFFS_USE_MAGIC_LENGTH 1
+#define CONFIG_SPIFFS_META_LENGTH 4
+#define CONFIG_SPIFFS_USE_MTIME 1
+#define CONFIG_USB_DESC_CUSTOM_VID 0x1234
+#define CONFIG_USB_DESC_CUSTOM_PID 0x5678
+#define CONFIG_UNITY_ENABLE_FLOAT 1
+#define CONFIG_UNITY_ENABLE_DOUBLE 1
+#define CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER 1
+#define CONFIG_VFS_SUPPORT_IO 1
+#define CONFIG_VFS_SUPPORT_DIR 1
+#define CONFIG_VFS_SUPPORT_SELECT 1
+#define CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT 1
+#define CONFIG_VFS_SUPPORT_TERMIOS 1
+#define CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS 1
+#define CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN 128
+#define CONFIG_WL_SECTOR_SIZE_4096 1
+#define CONFIG_WL_SECTOR_SIZE 4096
+#define CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES 16
+#define CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT 30
+#define CONFIG_WPA_MBEDTLS_CRYPTO 1
+
+/* List of deprecated options */
+#define CONFIG_ADC2_DISABLE_DAC CONFIG_ADC_DISABLE_DAC
+#define CONFIG_BROWNOUT_DET CONFIG_ESP32_BROWNOUT_DET
+#define CONFIG_BROWNOUT_DET_LVL_SEL_0 CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0
+#define CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG CONFIG_COMPILER_OPTIMIZATION_DEFAULT
+#define CONFIG_CONSOLE_UART_BAUDRATE CONFIG_ESP_CONSOLE_UART_BAUDRATE
+#define CONFIG_CONSOLE_UART_DEFAULT CONFIG_ESP_CONSOLE_UART_DEFAULT
+#define CONFIG_CONSOLE_UART_RX_GPIO CONFIG_ESP_CONSOLE_UART_RX_GPIO
+#define CONFIG_CONSOLE_UART_TX_GPIO CONFIG_ESP_CONSOLE_UART_TX_GPIO
+#define CONFIG_ESP32S2_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT
+#define CONFIG_ESP32_APPTRACE_DEST_NONE CONFIG_APPTRACE_DEST_NONE
+#define CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY
+#define CONFIG_ESP32_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT
+#define CONFIG_ESP32_PTHREAD_STACK_MIN CONFIG_PTHREAD_STACK_MIN
+#define CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT CONFIG_PTHREAD_TASK_NAME_DEFAULT
+#define CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT CONFIG_PTHREAD_TASK_PRIO_DEFAULT
+#define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT
+#define CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC CONFIG_ESP32_RTC_CLK_SRC_INT_RC
+#define CONFIG_ESP_GRATUITOUS_ARP CONFIG_LWIP_ESP_GRATUITOUS_ARP
+#define CONFIG_FLASHMODE_DIO CONFIG_ESPTOOLPY_FLASHMODE_DIO
+#define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR
+#define CONFIG_GARP_TMR_INTERVAL CONFIG_LWIP_GARP_TMR_INTERVAL
+#define CONFIG_INT_WDT CONFIG_ESP_INT_WDT
+#define CONFIG_INT_WDT_CHECK_CPU1 CONFIG_ESP_INT_WDT_CHECK_CPU1
+#define CONFIG_INT_WDT_TIMEOUT_MS CONFIG_ESP_INT_WDT_TIMEOUT_MS
+#define CONFIG_IPC_TASK_STACK_SIZE CONFIG_ESP_IPC_TASK_STACK_SIZE
+#define CONFIG_LOG_BOOTLOADER_LEVEL_INFO CONFIG_BOOTLOADER_LOG_LEVEL_INFO
+#define CONFIG_MAIN_TASK_STACK_SIZE CONFIG_ESP_MAIN_TASK_STACK_SIZE
+#define CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE
+#define CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT
+#define CONFIG_MB_CONTROLLER_STACK_SIZE CONFIG_FMB_CONTROLLER_STACK_SIZE
+#define CONFIG_MB_EVENT_QUEUE_TIMEOUT CONFIG_FMB_EVENT_QUEUE_TIMEOUT
+#define CONFIG_MB_MASTER_DELAY_MS_CONVERT CONFIG_FMB_MASTER_DELAY_MS_CONVERT
+#define CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND
+#define CONFIG_MB_QUEUE_LENGTH CONFIG_FMB_QUEUE_LENGTH
+#define CONFIG_MB_SERIAL_BUF_SIZE CONFIG_FMB_SERIAL_BUF_SIZE
+#define CONFIG_MB_SERIAL_TASK_PRIO CONFIG_FMB_SERIAL_TASK_PRIO
+#define CONFIG_MB_SERIAL_TASK_STACK_SIZE CONFIG_FMB_SERIAL_TASK_STACK_SIZE
+#define CONFIG_MB_TIMER_GROUP CONFIG_FMB_TIMER_GROUP
+#define CONFIG_MB_TIMER_INDEX CONFIG_FMB_TIMER_INDEX
+#define CONFIG_MB_TIMER_PORT_ENABLED CONFIG_FMB_TIMER_PORT_ENABLED
+#define CONFIG_MONITOR_BAUD_115200B CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B
+#define CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE
+#define CONFIG_OPTIMIZATION_LEVEL_DEBUG CONFIG_COMPILER_OPTIMIZATION_DEFAULT
+#define CONFIG_POST_EVENTS_FROM_IRAM_ISR CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR
+#define CONFIG_POST_EVENTS_FROM_ISR CONFIG_ESP_EVENT_POST_FROM_ISR
+#define CONFIG_REDUCE_PHY_TX_POWER CONFIG_ESP32_REDUCE_PHY_TX_POWER
+#define CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN
+#define CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS
+#define CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS
+#define CONFIG_STACK_CHECK_NONE CONFIG_COMPILER_STACK_CHECK_MODE_NONE
+#define CONFIG_SUPPORT_TERMIOS CONFIG_VFS_SUPPORT_TERMIOS
+#define CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT
+#define CONFIG_SYSTEM_EVENT_QUEUE_SIZE CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE
+#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE
+#define CONFIG_TASK_WDT CONFIG_ESP_TASK_WDT
+#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
+#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
+#define CONFIG_TASK_WDT_TIMEOUT_S CONFIG_ESP_TASK_WDT_TIMEOUT_S
+#define CONFIG_TCPIP_RECVMBOX_SIZE CONFIG_LWIP_TCPIP_RECVMBOX_SIZE
+#define CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY
+#define CONFIG_TCPIP_TASK_STACK_SIZE CONFIG_LWIP_TCPIP_TASK_STACK_SIZE
+#define CONFIG_TCP_MAXRTX CONFIG_LWIP_TCP_MAXRTX
+#define CONFIG_TCP_MSL CONFIG_LWIP_TCP_MSL
+#define CONFIG_TCP_MSS CONFIG_LWIP_TCP_MSS
+#define CONFIG_TCP_OVERSIZE_MSS CONFIG_LWIP_TCP_OVERSIZE_MSS
+#define CONFIG_TCP_QUEUE_OOSEQ CONFIG_LWIP_TCP_QUEUE_OOSEQ
+#define CONFIG_TCP_RECVMBOX_SIZE CONFIG_LWIP_TCP_RECVMBOX_SIZE
+#define CONFIG_TCP_SND_BUF_DEFAULT CONFIG_LWIP_TCP_SND_BUF_DEFAULT
+#define CONFIG_TCP_SYNMAXRTX CONFIG_LWIP_TCP_SYNMAXRTX
+#define CONFIG_TCP_WND_DEFAULT CONFIG_LWIP_TCP_WND_DEFAULT
+#define CONFIG_TIMER_QUEUE_LENGTH CONFIG_FREERTOS_TIMER_QUEUE_LENGTH
+#define CONFIG_TIMER_TASK_PRIORITY CONFIG_FREERTOS_TIMER_TASK_PRIORITY
+#define CONFIG_TIMER_TASK_STACK_DEPTH CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH
+#define CONFIG_TIMER_TASK_STACK_SIZE CONFIG_ESP_TIMER_TASK_STACK_SIZE
+#define CONFIG_TOOLPREFIX CONFIG_SDK_TOOLPREFIX
+#define CONFIG_UDP_RECVMBOX_SIZE CONFIG_LWIP_UDP_RECVMBOX_SIZE
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/CMakeLists.txt b/minimal-examples/embedded/esp32/esp-heltec-wb32/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4c05324
--- /dev/null
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.5)
+
+if (ESP_PLATFORM)
+       include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+       project(lws-minimal-esp32 C)
+       enable_testing()
+
+       target_link_libraries(lws-minimal-esp32.elf websockets)
+
+       option(LWS_WITH_DRIVERS "With generic drivers for gpio, i2c, display etc" ON)
+       set(LWS_WITH_DRIVERS ON)
+       option(LWS_WITH_SECURE_STREAMS "With secure streams" ON)
+       set(LWS_WITH_SECURE_STREAMS ON)
+       option(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY "static ssp" OFF)
+       set(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY OFF)
+       option(LWS_WITH_LWSAC "With lwsac" ON)
+       set(LWS_WITH_LWSAC ON)
+       option(LWS_WITH_STRUCT_JSON "With lws_struct JSON" ON)
+       set(LWS_WITH_STRUCT_JSON ON)
+       option(LWS_WITH_SYS_NTPCLIENT "With ntpclient" ON)
+        set(LWS_WITH_SYS_NTPCLIENT ON)
+
+       add_subdirectory(libwebsockets)
+
+       add_test(NAME flashing COMMAND idf.py flash)
+       set_tests_properties(flashing PROPERTIES
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+                            TIMEOUT 120)
+
+       add_test(NAME boot COMMAND /usr/local/bin/sai-expect)
+       set_tests_properties(boot PROPERTIES
+                            DEPENDS flashing
+                            TIMEOUT 60)
+
+endif()
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/banded-img.h b/minimal-examples/embedded/esp32/esp-heltec-wb32/banded-img.h
new file mode 100644 (file)
index 0000000..7fbe218
--- /dev/null
@@ -0,0 +1,64 @@
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xE0, 0x40, 0x20, 0x20, 0x20, 0x20, 0x00, 0x40, 0xE0, 0x00, 0x80, 0xE0, 0x20, 0x20, 
+0x20, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x00, 0x80, 0x40, 0x20, 
+0x20, 0x20, 0x60, 0x80, 0x00, 0xE0, 0x40, 0x20, 0x20, 0x60, 0xC0, 0x00, 0x80, 0x40, 0x20, 0x20, 
+0x20, 0x60, 0x80, 0x00, 0xC0, 0x60, 0x20, 0x20, 0x20, 0xC0, 0x00, 0x80, 0xC0, 0x20, 0x20, 0x20, 
+0x40, 0xC0, 0x00, 0xE0, 0x00, 0x80, 0x80, 0x60, 0x00, 0x80, 0xC0, 0x20, 0x20, 0x20, 0x60, 0x80, 
+0x00, 0x00, 0x40, 0x60, 0x20, 0x00, 0xC0, 0x40, 0x20, 0x20, 0x20, 0xC0, 0x40, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6F, 0x00, 0x34, 0x2F, 0x08, 0x08, 
+0x08, 0x0D, 0x07, 0x00, 0x0F, 0x00, 0x01, 0x0E, 0x0E, 0x01, 0x00, 0x0F, 0x08, 0x02, 0x0F, 0x09, 
+0x09, 0x19, 0x0F, 0x02, 0x00, 0x7F, 0x19, 0x08, 0x18, 0x08, 0x07, 0x01, 0x00, 0x0E, 0x09, 0x0B, 
+0x09, 0x0D, 0x04, 0x00, 0x07, 0x08, 0x08, 0x08, 0x08, 0x0F, 0x00, 0x03, 0x0E, 0x08, 0x18, 0x08, 
+0x0C, 0x04, 0x00, 0x7F, 0x02, 0x07, 0x08, 0x08, 0x00, 0x05, 0x0F, 0x0A, 0x11, 0x09, 0x0D, 0x06, 
+0x00, 0x08, 0x3F, 0x19, 0x08, 0x00, 0x06, 0x0A, 0x09, 0x09, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0xC0, 
+0xE0, 0xE0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xE0, 
+0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0xC1, 0x87, 0x8F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x00, 0x00, 
+0x00, 0x80, 0x80, 0xC0, 0x83, 0x87, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x83, 0x80, 0x80, 0x80, 0x83, 
+0x07, 0x0F, 0x1F, 0x0F, 0x0F, 0x0F, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x03, 0x07, 0x0F, 
+0x0F, 0x0F, 0x0F, 0x8F, 0x87, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x10, 0x00, 0xBC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xF8, 0x00, 0x28, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 
+0x3F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3F, 0x3F, 0x00, 0x00, 0x1F, 0x3F, 0x7F, 0x7F, 0xFF, 0x7F, 0x7F, 
+0x3F, 0x0E, 0x00, 0x05, 0x3F, 0x7F, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0x1F, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x0E, 0x3F, 0x7F, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xF8, 0xF8, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0x20, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/main/CMakeLists.txt b/minimal-examples/embedded/esp32/esp-heltec-wb32/main/CMakeLists.txt
new file mode 100644 (file)
index 0000000..77040de
--- /dev/null
@@ -0,0 +1,6 @@
+idf_component_register(SRCS
+               lws-minimal-esp32.c devices.c
+               INCLUDE_DIRS "../libwebsockets/include;${IDF_PATH}/components/spi_flash/include;${IDF_PATH}/components/nvs_flash/include;${IDF_PATH}/components/mdns/include")
+
+target_link_libraries(${COMPONENT_LIB} websockets)
+include_directories(../build/libwebsockets)
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/main/devices.c b/minimal-examples/embedded/esp32/esp-heltec-wb32/main/devices.c
new file mode 100644 (file)
index 0000000..a4dab2a
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * devices for ESP32 Heltec WB32
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#define LWIP_PROVIDE_ERRNO 1
+#define _ESP_PLATFORM_ERRNO_H_
+
+#include <stdio.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include <driver/gpio.h>
+
+#include <libwebsockets.h>
+
+struct lws_led_state *lls;
+lws_display_state_t lds;
+struct lws_button_state *bcs;
+lws_netdev_instance_wifi_t *wnd;
+
+/*
+ * Hook up bitbang i2c, display driver and display
+ */
+
+static void
+esp32_i2c_delay(void)
+{
+       ets_delay_us(1);
+}
+
+static const lws_bb_i2c_t li2c = {
+       .bb_ops                         = lws_bb_i2c_ops,
+       .scl                            = GPIO_NUM_15,
+       .sda                            = GPIO_NUM_4,
+       .gpio                           = &lws_gpio_plat,
+       .delay                          = esp32_i2c_delay
+};
+
+/*
+ * Button controller
+ */
+
+static const lws_button_map_t bcm[] = {
+       {
+               .gpio                   = GPIO_NUM_0,
+               .smd_interaction_name   = "user"
+       },
+};
+
+static const lws_button_controller_t bc = {
+       .smd_bc_name                    = "bc",
+       .gpio_ops                       = &lws_gpio_plat,
+       .button_map                     = &bcm[0],
+       .active_state_bitmap            = 0,
+       .count_buttons                  = LWS_ARRAY_SIZE(bcm),
+};
+
+/*
+ * pwm controller
+ */
+
+static const lws_pwm_map_t pwm_map[] = {
+       { .gpio = GPIO_NUM_25, .index = 0, .active_level = 1 }
+};
+
+static const lws_pwm_ops_t pwm_ops = {
+       lws_pwm_plat_ops,
+       .pwm_map                        = &pwm_map[0],
+       .count_pwm_map                  = LWS_ARRAY_SIZE(pwm_map)
+};
+
+static const lws_display_ssd1306_t disp = {
+       .disp = {
+               lws_display_ssd1306_ops,
+               .w                      = 128,
+               .h                      = 64
+       },
+       .i2c                            = (lws_i2c_ops_t *)&li2c,
+       .gpio                           = &lws_gpio_plat,
+       .reset_gpio                     = GPIO_NUM_16,
+       .i2c7_address                   = SSD1306_I2C7_ADS1
+};
+
+/*
+ * led controller
+ */
+
+static const lws_led_gpio_map_t lgm[] = {
+       {
+               .name                   = "alert",
+               .gpio                   = GPIO_NUM_25,
+               .pwm_ops                = &pwm_ops, /* managed by pwm */
+               .active_level           = 1,
+       },
+};
+
+static const lws_led_gpio_controller_t lgc = {
+       .led_ops                        = lws_led_gpio_ops,
+       .gpio_ops                       = &lws_gpio_plat,
+       .led_map                        = &lgm[0],
+       .count_leds                     = LWS_ARRAY_SIZE(lgm)
+};
+
+/*
+ * Settings stored in platform nv
+ */
+
+static const lws_settings_ops_t sett = {
+       lws_settings_ops_plat
+};
+
+/*
+ * Wifi
+ */
+
+static const lws_netdev_ops_t wifi_ops = {
+       lws_netdev_wifi_plat_ops
+};
+
+int
+init_plat_devices(struct lws_context *ctx)
+{
+       lws_settings_instance_t *si;
+       lws_netdevs_t *netdevs = lws_netdevs_from_ctx(ctx);
+
+       si = lws_settings_init(&sett, (void *)"nvs");
+       if (!si) {
+               lwsl_err("%s: failed to create settings instance\n", __func__);
+               return 1;
+       }
+       netdevs->si = si;
+
+#if 0
+       /*
+        * This is a temp hack to bootstrap the settings to contain the test
+        * AP ssid and passphrase for one time, so the settings can be stored
+        * while there's no UI atm
+        */
+       {
+               lws_wifi_creds_t creds;
+
+               memset(&creds, 0, sizeof(creds));
+
+               lws_strncpy(creds.ssid, "xxx", sizeof(creds.ssid));
+               lws_strncpy(creds.passphrase, "yyy", sizeof(creds.passphrase));
+               lws_dll2_add_tail(&creds.list, &netdevs->owner_creds);
+
+               if (lws_netdev_credentials_settings_set(netdevs)) {
+                       lwsl_err("%s: failed to write bootstrap creds\n",
+                                       __func__);
+                       return 1;
+               }
+       }
+#endif
+
+       /* create the wifi network device and configure it */
+
+       wnd = (lws_netdev_instance_wifi_t *)
+                       wifi_ops.create(ctx, &wifi_ops, "wl0", NULL);
+       if (!wnd) {
+               lwsl_err("%s: failed to create wifi object\n", __func__);
+               return 1;
+       }
+
+       wnd->flags |= LNDIW_MODE_STA;
+
+       if (wifi_ops.configure(&wnd->inst, NULL)) {
+               lwsl_err("%s: failed to configure wifi object\n", __func__);
+               return 1;
+       }
+
+       wifi_ops.up(&wnd->inst);
+
+       lls = lgc.led_ops.create(&lgc.led_ops);
+       if (!lls) {
+               lwsl_err("%s: could not create led\n", __func__);
+               return 1;
+       }
+
+       /* pwm init must go after the led controller init */
+
+       pwm_ops.init(&pwm_ops);
+
+       bcs = lws_button_controller_create(ctx, &bc);
+       if (!bcs) {
+               lwsl_err("%s: could not create buttons\n", __func__);
+               return 1;
+       }
+
+       /*
+        * Show the lws logo on the display
+        */
+
+       lws_display_state_init(&lds, ctx, 10000, 20000, lls, &disp.disp);
+
+       lws_button_enable(bcs, 0, lws_button_get_bit(bcs, "user"));
+       lws_led_transition(lls, "alert", &lws_pwmseq_static_off,
+                                        &lws_pwmseq_static_on);
+
+       return 0;
+}
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/main/lws-minimal-esp32.c b/minimal-examples/embedded/esp32/esp-heltec-wb32/main/lws-minimal-esp32.c
new file mode 100644 (file)
index 0000000..a249906
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * lws-minimal-esp32
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * Based on espressif Public Domain sample
+ */
+
+#define LWIP_PROVIDE_ERRNO 1
+#define _ESP_PLATFORM_ERRNO_H_
+
+#include <stdio.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include <driver/gpio.h>
+
+#include <libwebsockets.h>
+
+struct lws_context *context;
+extern struct lws_led_state *lls;
+extern lws_display_state_t lds;
+extern lws_netdev_instance_wifi_t *wnd;
+
+extern int init_plat_devices(struct lws_context *);
+
+static const uint8_t img[] = {
+#include "../banded-img.h"
+};
+
+#include "policy.h"
+
+static uint8_t flip;
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+
+       size_t                          amount;
+
+} myss_t;
+
+static int
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+//     lwsl_hexdump_info(buf, len);
+       m->amount += len;
+
+       if (flags & LWSSS_FLAG_EOM) {
+
+               /*
+                * If we received the whole message, for our example it means
+                * we are done.
+                */
+
+               lwsl_notice("%s: received %u bytes\n", __func__,
+                           (unsigned int)m->amount);
+
+               /*
+                * In CI, we use sai-expect to look for this
+                * string for success
+                */
+
+               lwsl_notice("Completed: PASS\n");
+       }
+
+       return 0;
+}
+
+static int
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_client_connect(m->ss);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const lws_ss_info_t ssi = {
+       .handle_offset                  = offsetof(myss_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_t, opaque_data),
+       .rx                             = myss_rx,
+       .state                          = myss_state,
+       .user_alloc                     = sizeof(myss_t),
+       .streamtype                     = "test_stream",
+};
+
+static const lws_led_sequence_def_t *seqs[] = {
+       &lws_pwmseq_static_on,
+       &lws_pwmseq_static_off,
+       &lws_pwmseq_sine_endless_slow,
+       &lws_pwmseq_sine_endless_fast,
+};
+
+static int
+smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp, void *buf,
+       size_t len)
+{
+
+       if (!lws_json_simple_strcmp(buf, len, "\"src\":", "bc/user") &&
+           !lws_json_simple_strcmp(buf, len, "\"event\":", "click")) {
+               lws_led_transition(lls, "alert", seqs[flip & 3],
+                                  &lws_pwmseq_linear_wipe);
+               flip++;
+       }
+
+       lwsl_hexdump_notice(buf, len);
+
+       if ((_class & LWSSMDCL_SYSTEM_STATE) &&
+           !lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
+
+               /* create the secure stream */
+
+               lwsl_notice("%s: creating test secure stream\n", __func__);
+
+               if (lws_ss_create(context, 0, &ssi, NULL, NULL, NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+                       return -1;
+               }
+       }
+
+       if (_class & LWSSMDCL_INTERACTION)
+               /*
+                * Any kind of user interaction brings the display back up and
+                * resets the dimming / blanking timers
+                */
+               lws_display_state_active(&lds);
+
+       return 0;
+}
+
+void 
+app_main(void)
+{
+       struct lws_context_creation_info *info;
+
+       lws_set_log_level(1024 | 15, NULL);
+
+        lws_netdev_plat_init();
+        lws_netdev_plat_wifi_init();
+
+        info = malloc(sizeof(*info));
+        if (!info)
+               goto spin;
+
+       memset(info, 0, sizeof(*info));
+
+       lwsl_notice("LWS test for Heltec WB32 ESP32 board\n");
+
+       info->pss_policies_json         = ss_policy;
+       info->options                   = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                                         LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info->port                      = CONTEXT_PORT_NO_LISTEN;
+       info->early_smd_cb              = smd_cb;
+       info->early_smd_class_filter    = LWSSMDCL_INTERACTION |
+                                         LWSSMDCL_SYSTEM_STATE |
+                                         LWSSMDCL_NETWORK;
+
+       context = lws_create_context(info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return;
+       }
+
+       /*
+        * We don't need this after context creation... things it pointed to
+        * still need to exist though since the context copied the pointers.
+        */
+
+       free(info);
+
+       /* devices and init are in devices.c */
+
+       if (init_plat_devices(context))
+               goto spin;
+
+       /* put the logo on the OLED display */
+
+       lds.disp->blit(lds.disp, img, 0, 0, 128, 64);
+       lws_display_state_active(&lds);
+
+       /* the lws event loop */
+
+       do {
+               taskYIELD();
+       } while (lws_service(context, 0) >= 0);
+
+
+spin:
+       vTaskDelay(10);
+       taskYIELD();
+       goto spin;
+}
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/main/policy.h b/minimal-examples/embedded/esp32/esp-heltec-wb32/main/policy.h
new file mode 100644 (file)
index 0000000..79e21fd
--- /dev/null
@@ -0,0 +1,101 @@
+
+static const char * const ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "25,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+               "{\"isrg_root_x1\": \""
+       "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="
+         "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": ["
+
+               "{\"test_stream\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h2\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"index.html\","
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}},{"
+                       /*
+                        * "captive_portal_detect" describes
+                        * what to do in order to check if the path to
+                        * the Internet is being interrupted by a
+                        * captive portal.
+                        */
+                   "\"captive_portal_detect\": {"
+                        "\"endpoint\":"                "\"connectivitycheck.android.com\","
+                       "\"http_url\":"         "\"generate_204\","
+                       "\"port\":"             "80,"
+                        "\"protocol\":"                "\"h1\","
+                        "\"http_method\":"     "\"GET\","
+                        "\"opportunistic\":"   "true,"
+                        "\"http_expect\":"     "204,"
+                       "\"http_fail_redirect\": true"
+                "}}"
+       "]}"
+;
+
+
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/partitions.csv b/minimal-examples/embedded/esp32/esp-heltec-wb32/partitions.csv
new file mode 100644 (file)
index 0000000..e261b7c
--- /dev/null
@@ -0,0 +1,5 @@
+# ESP-IDF Partition Table
+# Name,   Type, SubType, Offset,  Size, Flags
+nvs,      data, nvs,     0x9000,  0x6000,
+phy_init, data, phy,     0xf000,  0x1000,
+factory,  app,  factory, 0x10000, 2M,
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/output.bmp b/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/output.bmp
new file mode 100644 (file)
index 0000000..bab071c
Binary files /dev/null and b/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/output.bmp differ
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/pic.h b/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/pic.h
new file mode 100644 (file)
index 0000000..e27f56a
--- /dev/null
@@ -0,0 +1,64 @@
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x2f, 0x27, 0xc6, 0x61, 0xe5, 0xc3, 0xc7, 0x87, 0x11, 0x1e, 0x18, 0xe0, 0x00, 0x00,
+0x00, 0x00, 0x30, 0x64, 0x46, 0x62, 0x26, 0x64, 0x4c, 0x48, 0xd1, 0x22, 0x33, 0x18, 0x00, 0x00,
+0x00, 0x00, 0x20, 0x2c, 0x46, 0x64, 0x14, 0x28, 0x28, 0x58, 0x56, 0x61, 0x02, 0x10, 0x00, 0x00,
+0x00, 0x00, 0x20, 0x24, 0x6a, 0x53, 0xe6, 0x33, 0xc8, 0x50, 0x14, 0x6e, 0x30, 0xf0, 0x00, 0x00,
+0x00, 0x00, 0x20, 0x24, 0x29, 0x96, 0x34, 0x25, 0x08, 0x58, 0x1c, 0x31, 0x23, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x30, 0x6c, 0x69, 0x92, 0x24, 0x24, 0x68, 0x48, 0xd4, 0x63, 0x22, 0x10, 0x00, 0x00,
+0x00, 0x00, 0x20, 0x27, 0xc9, 0x9b, 0xe7, 0xc7, 0xc7, 0xcf, 0x93, 0x36, 0x79, 0xf0, 0x00, 0x00,
+0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x46, 0x80, 0x00, 0x02, 0x10, 0x08, 0x30, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x20, 0x2c, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0xc0, 0x30, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x07, 0xe0, 0xfc, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x0f, 0xf1, 0xfe, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x0f, 0xf1, 0xfe, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x03, 0xfc, 0x0f, 0xf1, 0xfe, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x0f, 0xf1, 0xfe, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x07, 0xe0, 0xfc, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0xc0, 0x7c, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x7c, 0x1f, 0x03, 0xc0, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0xfe, 0x3f, 0x8f, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x3f, 0x8f, 0xe0, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0x8f, 0xf0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xdf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xff, 0x7f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xdf, 0xf0, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x3f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0x9f, 0xf0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xdf, 0xf0, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0x8f, 0xf0, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0xfe, 0x3f, 0x8f, 0xe0, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x78, 0x1f, 0x07, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x04, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/pic.h.1 b/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/pic.h.1
new file mode 100644 (file)
index 0000000..631e2e1
--- /dev/null
@@ -0,0 +1,64 @@
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x2f, 0x27, 0xc6, 0x61, 0xe5, 0xc3, 0xc7, 0x87, 0x11, 0x1e, 0x18, 0xe0, 0x00, 0x00
+0x00, 0x00, 0x30, 0x64, 0x46, 0x62, 0x26, 0x64, 0x4c, 0x48, 0xd1, 0x22, 0x33, 0x18, 0x00, 0x00
+0x00, 0x00, 0x20, 0x2c, 0x46, 0x64, 0x14, 0x28, 0x28, 0x58, 0x56, 0x61, 0x02, 0x10, 0x00, 0x00
+0x00, 0x00, 0x20, 0x24, 0x6a, 0x53, 0xe6, 0x33, 0xc8, 0x50, 0x14, 0x6e, 0x30, 0xf0, 0x00, 0x00
+0x00, 0x00, 0x20, 0x24, 0x29, 0x96, 0x34, 0x25, 0x08, 0x58, 0x1c, 0x31, 0x23, 0x00, 0x00, 0x00
+0x00, 0x00, 0x30, 0x6c, 0x69, 0x92, 0x24, 0x24, 0x68, 0x48, 0xd4, 0x63, 0x22, 0x10, 0x00, 0x00
+0x00, 0x00, 0x20, 0x27, 0xc9, 0x9b, 0xe7, 0xc7, 0xc7, 0xcf, 0x93, 0x36, 0x79, 0xf0, 0x00, 0x00
+0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x46, 0x80, 0x00, 0x02, 0x10, 0x08, 0x30, 0x00, 0x00, 0x00
+0x00, 0x00, 0x20, 0x2c, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00
+0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0xc0, 0x30, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x07, 0xe0, 0xfc, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x0f, 0xf1, 0xfe, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x0f, 0xf1, 0xfe, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x03, 0xfc, 0x0f, 0xf1, 0xfe, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x0f, 0xf1, 0xfe, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x07, 0xe0, 0xfc, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0xc0, 0x7c, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x7c, 0x1f, 0x03, 0xc0, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0xfe, 0x3f, 0x8f, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x3f, 0x8f, 0xe0, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0x8f, 0xf0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xdf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xff, 0x7f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xdf, 0xf0, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x3f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0x9f, 0xf0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xdf, 0xf0, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0xcf, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc1, 0xfe, 0x7f, 0x8f, 0xf0, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0xfe, 0x3f, 0x8f, 0xe0, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x78, 0x1f, 0x07, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x04, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan b/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan
new file mode 100755 (executable)
index 0000000..923975e
Binary files /dev/null and b/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan differ
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan.c b/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan.c
new file mode 100644 (file)
index 0000000..35c6f46
--- /dev/null
@@ -0,0 +1,70 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+/*
+ * The bitmap mapping for the framebuffer is from top left to right, a strip of 8 vertical
+ * bits from each byte, so there is a block of 128 x 8 px on a stride of 128 bytes.
+ *
+ * The 8 bits from the first byte in the fb are the leftmost vertical strip of 8, then the
+ * next byte is the 8 pixels one to the right, until the 127th byte if the vertical strip
+ * of 8 on the rhs.
+ *
+ * +----------------------------------+
+ * |0                                 |
+ * |1                                 |
+ * |2                                 |
+ * |3                                 |
+ * |4                                 |
+ * |5                                 |
+ * |6                                 |
+ * |7                                 |
+ *
+ * In this way the fb is more like (8 x vertical (128 x 8))
+ *
+ */
+
+
+static const uint8_t scan[] = {
+
+#include "pic.h"
+};
+
+/*
+ * input byte 0 is like ABCDEFGH, one bit per horizontal pixel for one line
+ * on an hstride of 16 bytes
+ *
+ * output byte 0 =  b0 = byte 0 b0, b1 = byte16 b0, b2 = byte24 b0 etc
+ *
+ * px(0,0) --> byte0 b0
+ * px(0,1) --> byte0 b1
+ */
+
+int
+main(void)
+{
+       const uint8_t *p = scan;
+       uint8_t r[1024];
+       int x, y, t = 0;
+
+       memset(&r, 0, sizeof(r));
+
+       while (t < 1024) {
+
+               for (x = 0; x < 128; x++) {
+                       for (y = 0; y < 8; y++) {
+                               if (p[t + (16 * y) + (x / 8)] & (1 << (7 - (x & 7))))
+                                       r[t + x] |= 1 << y;
+                       }
+               }
+
+               t += 128;
+       }
+
+       for (x = 0; x < 1024; x++) {
+               printf("0x%02X, ", r[x]);
+               if ((x & 0xf) == 0xf)
+                       printf("\n");
+       }
+}
+
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan.sh b/minimal-examples/embedded/esp32/esp-heltec-wb32/scan/scan.sh
new file mode 100755 (executable)
index 0000000..be090a8
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+convert -size 128x64 /tmp/128x64.png -monochrome output.bmp
+dd if=output.bmp bs=1 skip=130 | hexdump -Cv | tr -s ' ' | cut -d' ' -f2-17 | grep ' ' | sed "s/^/0x/g" | sed "s/\ /,\ 0x/g" > pic.h.1
+cat pic.h.1 | sed "s/\$/,/g" > pic.h
+
+gcc -o scan scan.c && ./scan > ../banded-img.h
+
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/sdkconfig b/minimal-examples/embedded/esp32/esp-heltec-wb32/sdkconfig
new file mode 100644 (file)
index 0000000..56008bf
--- /dev/null
@@ -0,0 +1,1152 @@
+#
+# Automatically generated file. DO NOT EDIT.
+# Espressif IoT Development Framework (ESP-IDF) Project Configuration
+#
+CONFIG_IDF_CMAKE=y
+CONFIG_IDF_TARGET="esp32"
+CONFIG_IDF_TARGET_ESP32=y
+CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
+
+#
+# SDK tool configuration
+#
+CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-"
+# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set
+# end of SDK tool configuration
+
+#
+# Build type
+#
+CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y
+# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set
+CONFIG_APP_BUILD_GENERATE_BINARIES=y
+CONFIG_APP_BUILD_BOOTLOADER=y
+CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y
+# end of Build type
+
+#
+# Application manager
+#
+CONFIG_APP_COMPILE_TIME_DATE=y
+# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
+# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
+# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set
+CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16
+# end of Application manager
+
+#
+# Bootloader config
+#
+CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
+CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
+# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
+CONFIG_BOOTLOADER_LOG_LEVEL=3
+# CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V is not set
+CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
+# CONFIG_BOOTLOADER_FACTORY_RESET is not set
+# CONFIG_BOOTLOADER_APP_TEST is not set
+CONFIG_BOOTLOADER_WDT_ENABLE=y
+# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
+CONFIG_BOOTLOADER_WDT_TIME_MS=9000
+# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set
+CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0
+# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set
+# end of Bootloader config
+
+#
+# Security features
+#
+# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set
+# CONFIG_SECURE_BOOT is not set
+# CONFIG_SECURE_FLASH_ENC_ENABLED is not set
+# end of Security features
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
+# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
+# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE="dio"
+# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ_26M=y
+# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ="26m"
+# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
+# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_BEFORE_RESET=y
+# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
+CONFIG_ESPTOOLPY_BEFORE="default_reset"
+CONFIG_ESPTOOLPY_AFTER_RESET=y
+# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
+CONFIG_ESPTOOLPY_AFTER="hard_reset"
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
+# end of Serial flasher config
+
+#
+# Partition Table
+#
+# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
+# CONFIG_PARTITION_TABLE_TWO_OTA is not set
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
+CONFIG_PARTITION_TABLE_OFFSET=0x8000
+CONFIG_PARTITION_TABLE_MD5=y
+# end of Partition Table
+
+#
+# Compiler options
+#
+CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
+# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
+# CONFIG_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
+CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
+# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
+# CONFIG_COMPILER_CXX_RTTI is not set
+CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
+# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
+# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
+# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set
+# end of Compiler options
+
+#
+# Component config
+#
+
+#
+# Application Level Tracing
+#
+# CONFIG_APPTRACE_DEST_TRAX is not set
+CONFIG_APPTRACE_DEST_NONE=y
+CONFIG_APPTRACE_LOCK_ENABLE=y
+# end of Application Level Tracing
+
+#
+# Bluetooth
+#
+# CONFIG_BT_ENABLED is not set
+CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=0
+CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0
+CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=0
+CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0
+CONFIG_BTDM_CTRL_PINNED_TO_CORE=0
+CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1
+CONFIG_BT_RESERVE_DRAM=0
+# end of Bluetooth
+
+#
+# CoAP Configuration
+#
+CONFIG_COAP_MBEDTLS_PSK=y
+# CONFIG_COAP_MBEDTLS_PKI is not set
+# CONFIG_COAP_MBEDTLS_DEBUG is not set
+CONFIG_COAP_LOG_DEFAULT_LEVEL=0
+# end of CoAP Configuration
+
+#
+# Driver configurations
+#
+
+#
+# ADC configuration
+#
+# CONFIG_ADC_FORCE_XPD_FSM is not set
+CONFIG_ADC_DISABLE_DAC=y
+# end of ADC configuration
+
+#
+# SPI configuration
+#
+# CONFIG_SPI_MASTER_IN_IRAM is not set
+CONFIG_SPI_MASTER_ISR_IN_IRAM=y
+# CONFIG_SPI_SLAVE_IN_IRAM is not set
+CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
+# end of SPI configuration
+
+#
+# UART configuration
+#
+# CONFIG_UART_ISR_IN_IRAM is not set
+# end of UART configuration
+
+#
+# RTCIO configuration
+#
+# CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC is not set
+# end of RTCIO configuration
+# end of Driver configurations
+
+#
+# eFuse Bit Manager
+#
+# CONFIG_EFUSE_CUSTOM_TABLE is not set
+# CONFIG_EFUSE_VIRTUAL is not set
+# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set
+CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y
+# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set
+CONFIG_EFUSE_MAX_BLK_LEN=192
+# end of eFuse Bit Manager
+
+#
+# ESP-TLS
+#
+CONFIG_ESP_TLS_USING_MBEDTLS=y
+# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set
+# CONFIG_ESP_TLS_SERVER is not set
+# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
+# end of ESP-TLS
+
+#
+# ESP32-specific
+#
+CONFIG_ESP32_REV_MIN_0=y
+# CONFIG_ESP32_REV_MIN_1 is not set
+# CONFIG_ESP32_REV_MIN_2 is not set
+# CONFIG_ESP32_REV_MIN_3 is not set
+CONFIG_ESP32_REV_MIN=0
+CONFIG_ESP32_DPORT_WORKAROUND=y
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
+CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_240 is not set
+CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160
+# CONFIG_ESP32_SPIRAM_SUPPORT is not set
+# CONFIG_ESP32_TRAX is not set
+CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0
+# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
+CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y
+CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4
+# CONFIG_ESP32_ULP_COPROC_ENABLED is not set
+CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0
+CONFIG_ESP32_DEBUG_OCDAWARE=y
+CONFIG_ESP32_BROWNOUT_DET=y
+CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set
+CONFIG_ESP32_BROWNOUT_DET_LVL=0
+CONFIG_ESP32_REDUCE_PHY_TX_POWER=y
+CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y
+# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set
+# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set
+# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set
+CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y
+# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set
+# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set
+# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set
+CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024
+CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000
+# CONFIG_ESP32_XTAL_FREQ_40 is not set
+CONFIG_ESP32_XTAL_FREQ_26=y
+# CONFIG_ESP32_XTAL_FREQ_AUTO is not set
+CONFIG_ESP32_XTAL_FREQ=26
+# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set
+# CONFIG_ESP32_NO_BLOBS is not set
+# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
+# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set
+CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5
+# end of ESP32-specific
+
+#
+# Power Management
+#
+# CONFIG_PM_ENABLE is not set
+# end of Power Management
+
+#
+# ADC-Calibration
+#
+CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
+CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
+CONFIG_ADC_CAL_LUT_ENABLE=y
+# end of ADC-Calibration
+
+#
+# Common ESP-related
+#
+CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
+CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4304
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=6584
+CONFIG_ESP_IPC_TASK_STACK_SIZE=3024
+CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y
+CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
+CONFIG_ESP_CONSOLE_UART_DEFAULT=y
+# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_UART_NONE is not set
+CONFIG_ESP_CONSOLE_UART_NUM=0
+CONFIG_ESP_CONSOLE_UART_TX_GPIO=1
+CONFIG_ESP_CONSOLE_UART_RX_GPIO=3
+CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
+CONFIG_ESP_INT_WDT=y
+CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
+CONFIG_ESP_INT_WDT_CHECK_CPU1=y
+CONFIG_ESP_TASK_WDT=y
+# CONFIG_ESP_TASK_WDT_PANIC is not set
+CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
+CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
+# CONFIG_ESP_PANIC_HANDLER_IRAM is not set
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
+# end of Common ESP-related
+
+#
+# Ethernet
+#
+CONFIG_ETH_ENABLED=y
+CONFIG_ETH_USE_ESP32_EMAC=y
+CONFIG_ETH_PHY_INTERFACE_RMII=y
+# CONFIG_ETH_PHY_INTERFACE_MII is not set
+CONFIG_ETH_RMII_CLK_INPUT=y
+# CONFIG_ETH_RMII_CLK_OUTPUT is not set
+CONFIG_ETH_RMII_CLK_IN_GPIO=0
+CONFIG_ETH_DMA_BUFFER_SIZE=512
+CONFIG_ETH_DMA_RX_BUFFER_NUM=10
+CONFIG_ETH_DMA_TX_BUFFER_NUM=10
+CONFIG_ETH_USE_SPI_ETHERNET=y
+# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set
+# CONFIG_ETH_USE_OPENETH is not set
+# end of Ethernet
+
+#
+# Event Loop Library
+#
+# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
+CONFIG_ESP_EVENT_POST_FROM_ISR=y
+CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
+# end of Event Loop Library
+
+#
+# GDB Stub
+#
+# end of GDB Stub
+
+#
+# ESP HTTP client
+#
+CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
+# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
+# end of ESP HTTP client
+
+#
+# HTTP Server
+#
+CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
+CONFIG_HTTPD_MAX_URI_LEN=512
+CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
+CONFIG_HTTPD_PURGE_BUF_LEN=32
+# CONFIG_HTTPD_LOG_PURGE_DATA is not set
+# CONFIG_HTTPD_WS_SUPPORT is not set
+# end of HTTP Server
+
+#
+# ESP HTTPS OTA
+#
+# CONFIG_OTA_ALLOW_HTTP is not set
+# end of ESP HTTPS OTA
+
+#
+# ESP HTTPS server
+#
+# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
+# end of ESP HTTPS server
+
+#
+# ESP NETIF Adapter
+#
+CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
+CONFIG_ESP_NETIF_TCPIP_LWIP=y
+# CONFIG_ESP_NETIF_LOOPBACK is not set
+CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y
+# end of ESP NETIF Adapter
+
+#
+# ESP System Settings
+#
+# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
+CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
+# end of ESP System Settings
+
+#
+# High resolution timer (esp_timer)
+#
+# CONFIG_ESP_TIMER_PROFILING is not set
+CONFIG_ESP_TIMER_TASK_STACK_SIZE=6584
+# CONFIG_ESP_TIMER_IMPL_FRC2 is not set
+CONFIG_ESP_TIMER_IMPL_TG0_LAC=y
+# end of High resolution timer (esp_timer)
+
+#
+# Wi-Fi
+#
+CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y
+CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
+CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP32_WIFI_TX_BA_WIN=6
+CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP32_WIFI_RX_BA_WIN=6
+CONFIG_ESP32_WIFI_NVS_ENABLED=y
+CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
+# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set
+CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752
+CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
+# CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE is not set
+CONFIG_ESP32_WIFI_IRAM_OPT=y
+CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
+# end of Wi-Fi
+
+#
+# PHY
+#
+CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
+# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
+CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
+CONFIG_ESP32_PHY_MAX_TX_POWER=20
+# end of PHY
+
+#
+# Core dump
+#
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
+CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
+# end of Core dump
+
+#
+# FAT Filesystem support
+#
+# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set
+CONFIG_FATFS_CODEPAGE_437=y
+# CONFIG_FATFS_CODEPAGE_720 is not set
+# CONFIG_FATFS_CODEPAGE_737 is not set
+# CONFIG_FATFS_CODEPAGE_771 is not set
+# CONFIG_FATFS_CODEPAGE_775 is not set
+# CONFIG_FATFS_CODEPAGE_850 is not set
+# CONFIG_FATFS_CODEPAGE_852 is not set
+# CONFIG_FATFS_CODEPAGE_855 is not set
+# CONFIG_FATFS_CODEPAGE_857 is not set
+# CONFIG_FATFS_CODEPAGE_860 is not set
+# CONFIG_FATFS_CODEPAGE_861 is not set
+# CONFIG_FATFS_CODEPAGE_862 is not set
+# CONFIG_FATFS_CODEPAGE_863 is not set
+# CONFIG_FATFS_CODEPAGE_864 is not set
+# CONFIG_FATFS_CODEPAGE_865 is not set
+# CONFIG_FATFS_CODEPAGE_866 is not set
+# CONFIG_FATFS_CODEPAGE_869 is not set
+# CONFIG_FATFS_CODEPAGE_932 is not set
+# CONFIG_FATFS_CODEPAGE_936 is not set
+# CONFIG_FATFS_CODEPAGE_949 is not set
+# CONFIG_FATFS_CODEPAGE_950 is not set
+CONFIG_FATFS_CODEPAGE=437
+CONFIG_FATFS_LFN_NONE=y
+# CONFIG_FATFS_LFN_HEAP is not set
+# CONFIG_FATFS_LFN_STACK is not set
+CONFIG_FATFS_FS_LOCK=0
+CONFIG_FATFS_TIMEOUT_MS=10000
+CONFIG_FATFS_PER_FILE_CACHE=y
+# end of FAT Filesystem support
+
+#
+# Modbus configuration
+#
+CONFIG_FMB_COMM_MODE_RTU_EN=y
+CONFIG_FMB_COMM_MODE_ASCII_EN=y
+CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_FMB_QUEUE_LENGTH=20
+CONFIG_FMB_SERIAL_TASK_STACK_SIZE=2048
+CONFIG_FMB_SERIAL_BUF_SIZE=256
+CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8
+CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000
+CONFIG_FMB_SERIAL_TASK_PRIO=10
+# CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT is not set
+CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_FMB_CONTROLLER_STACK_SIZE=4096
+CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20
+CONFIG_FMB_TIMER_PORT_ENABLED=y
+CONFIG_FMB_TIMER_GROUP=0
+CONFIG_FMB_TIMER_INDEX=0
+# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set
+# end of Modbus configuration
+
+#
+# FreeRTOS
+#
+# CONFIG_FREERTOS_UNICORE is not set
+CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
+CONFIG_FREERTOS_CORETIMER_0=y
+# CONFIG_FREERTOS_CORETIMER_1 is not set
+CONFIG_FREERTOS_HZ=100
+CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
+# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
+CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
+CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
+CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
+# CONFIG_FREERTOS_ASSERT_DISABLE is not set
+CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
+CONFIG_FREERTOS_ISR_STACKSIZE=1536
+# CONFIG_FREERTOS_LEGACY_HOOKS is not set
+CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
+# CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION is not set
+CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=5048
+CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
+CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
+# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
+# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
+CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y
+CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
+# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
+CONFIG_FREERTOS_DEBUG_OCDAWARE=y
+# CONFIG_FREERTOS_FPU_IN_ISR is not set
+# end of FreeRTOS
+
+#
+# Heap memory debugging
+#
+CONFIG_HEAP_POISONING_DISABLED=y
+# CONFIG_HEAP_POISONING_LIGHT is not set
+# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set
+CONFIG_HEAP_TRACING_OFF=y
+# CONFIG_HEAP_TRACING_STANDALONE is not set
+# CONFIG_HEAP_TRACING_TOHOST is not set
+# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set
+# end of Heap memory debugging
+
+#
+# jsmn
+#
+# CONFIG_JSMN_PARENT_LINKS is not set
+# CONFIG_JSMN_STRICT is not set
+# end of jsmn
+
+#
+# libsodium
+#
+# end of libsodium
+
+#
+# Log output
+#
+# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
+# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
+# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
+CONFIG_LOG_DEFAULT_LEVEL_INFO=y
+# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
+# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_LOG_COLORS=y
+CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
+# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set
+# end of Log output
+
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
+CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
+# CONFIG_LWIP_L2_TO_L3_COPY is not set
+# CONFIG_LWIP_IRAM_OPTIMIZATION is not set
+CONFIG_LWIP_TIMERS_ONDEMAND=y
+CONFIG_LWIP_MAX_SOCKETS=10
+# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
+CONFIG_LWIP_SO_REUSE=y
+CONFIG_LWIP_SO_REUSE_RXTOALL=y
+# CONFIG_LWIP_SO_RCVBUF is not set
+# CONFIG_LWIP_NETBUF_RECVINFO is not set
+CONFIG_LWIP_IP_FRAG=y
+# CONFIG_LWIP_IP_REASSEMBLY is not set
+# CONFIG_LWIP_IP_FORWARD is not set
+# CONFIG_LWIP_STATS is not set
+# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
+CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
+CONFIG_LWIP_GARP_TMR_INTERVAL=60
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
+# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
+
+#
+# DHCP server
+#
+CONFIG_LWIP_DHCPS_LEASE_UNIT=60
+CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
+# end of DHCP server
+
+# CONFIG_LWIP_AUTOIP is not set
+# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
+CONFIG_LWIP_NETIF_LOOPBACK=y
+CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
+
+#
+# TCP
+#
+CONFIG_LWIP_MAX_ACTIVE_TCP=16
+CONFIG_LWIP_MAX_LISTENING_TCP=16
+CONFIG_LWIP_TCP_MAXRTX=12
+CONFIG_LWIP_TCP_SYNMAXRTX=6
+CONFIG_LWIP_TCP_MSS=1440
+CONFIG_LWIP_TCP_TMR_INTERVAL=250
+CONFIG_LWIP_TCP_MSL=60000
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744
+CONFIG_LWIP_TCP_WND_DEFAULT=5744
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
+CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
+# CONFIG_LWIP_TCP_SACK_OUT is not set
+# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_LWIP_TCP_OVERSIZE_MSS=y
+# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
+# end of TCP
+
+#
+# UDP
+#
+CONFIG_LWIP_MAX_UDP_PCBS=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=6
+# end of UDP
+
+CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
+# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set
+CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_LWIP_PPP_SUPPORT is not set
+
+#
+# ICMP
+#
+# CONFIG_LWIP_MULTICAST_PING is not set
+# CONFIG_LWIP_BROADCAST_PING is not set
+# end of ICMP
+
+#
+# LWIP RAW API
+#
+CONFIG_LWIP_MAX_RAW_PCBS=16
+# end of LWIP RAW API
+
+#
+# SNTP
+#
+CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
+CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
+# end of SNTP
+
+CONFIG_LWIP_ESP_LWIP_ASSERT=y
+# end of LWIP
+
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
+# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
+# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
+CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
+CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
+CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
+# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set
+# CONFIG_MBEDTLS_DEBUG is not set
+
+#
+# Certificate Bundle
+#
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
+# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
+# end of Certificate Bundle
+
+# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
+# CONFIG_MBEDTLS_CMAC_C is not set
+CONFIG_MBEDTLS_HARDWARE_AES=y
+CONFIG_MBEDTLS_HARDWARE_MPI=y
+CONFIG_MBEDTLS_HARDWARE_SHA=y
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set
+CONFIG_MBEDTLS_HAVE_TIME=y
+# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
+CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y
+CONFIG_MBEDTLS_SHA512_C=y
+CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
+# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
+# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
+# CONFIG_MBEDTLS_TLS_DISABLED is not set
+CONFIG_MBEDTLS_TLS_SERVER=y
+CONFIG_MBEDTLS_TLS_CLIENT=y
+CONFIG_MBEDTLS_TLS_ENABLED=y
+
+#
+# TLS Key Exchange Methods
+#
+# CONFIG_MBEDTLS_PSK_MODES is not set
+CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
+# end of TLS Key Exchange Methods
+
+CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
+# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set
+CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
+# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
+CONFIG_MBEDTLS_SSL_ALPN=y
+CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y
+CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y
+
+#
+# Symmetric Ciphers
+#
+CONFIG_MBEDTLS_AES_C=y
+# CONFIG_MBEDTLS_CAMELLIA_C is not set
+# CONFIG_MBEDTLS_DES_C is not set
+CONFIG_MBEDTLS_RC4_DISABLED=y
+# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set
+# CONFIG_MBEDTLS_RC4_ENABLED is not set
+# CONFIG_MBEDTLS_BLOWFISH_C is not set
+# CONFIG_MBEDTLS_XTEA_C is not set
+CONFIG_MBEDTLS_CCM_C=y
+CONFIG_MBEDTLS_GCM_C=y
+# end of Symmetric Ciphers
+
+# CONFIG_MBEDTLS_RIPEMD160_C is not set
+
+#
+# Certificates
+#
+CONFIG_MBEDTLS_PEM_PARSE_C=y
+CONFIG_MBEDTLS_PEM_WRITE_C=y
+CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
+CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
+# end of Certificates
+
+CONFIG_MBEDTLS_ECP_C=y
+CONFIG_MBEDTLS_ECDH_C=y
+CONFIG_MBEDTLS_ECDSA_C=y
+# CONFIG_MBEDTLS_ECJPAKE_C is not set
+CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
+CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
+# CONFIG_MBEDTLS_POLY1305_C is not set
+# CONFIG_MBEDTLS_CHACHA20_C is not set
+# CONFIG_MBEDTLS_HKDF_C is not set
+# CONFIG_MBEDTLS_THREADING_C is not set
+# CONFIG_MBEDTLS_SECURITY_RISKS is not set
+# end of mbedTLS
+
+#
+# mDNS
+#
+CONFIG_MDNS_MAX_SERVICES=10
+CONFIG_MDNS_TASK_PRIORITY=1
+CONFIG_MDNS_TASK_STACK_SIZE=4096
+# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_MDNS_TASK_AFFINITY_CPU0=y
+# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set
+CONFIG_MDNS_TASK_AFFINITY=0x0
+CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000
+CONFIG_MDNS_TIMER_PERIOD_MS=100
+# end of mDNS
+
+#
+# ESP-MQTT Configurations
+#
+CONFIG_MQTT_PROTOCOL_311=y
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set
+# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set
+# CONFIG_MQTT_CUSTOM_OUTBOX is not set
+# end of ESP-MQTT Configurations
+
+#
+# Newlib
+#
+CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set
+CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
+# CONFIG_NEWLIB_NANO_FORMAT is not set
+# end of Newlib
+
+#
+# NVS
+#
+# end of NVS
+
+#
+# OpenSSL
+#
+# CONFIG_OPENSSL_DEBUG is not set
+# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set
+CONFIG_OPENSSL_ASSERT_EXIT=y
+# end of OpenSSL
+
+#
+# PThreads
+#
+CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_PTHREAD_STACK_MIN=768
+CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y
+# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set
+# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set
+CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
+# end of PThreads
+
+#
+# SPI Flash driver
+#
+# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
+# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
+CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
+CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set
+# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set
+# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set
+# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set
+CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y
+CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20
+CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1
+
+#
+# Auto-detect flash chips
+#
+CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
+# end of Auto-detect flash chips
+# end of SPI Flash driver
+
+#
+# SPIFFS Configuration
+#
+CONFIG_SPIFFS_MAX_PARTITIONS=3
+
+#
+# SPIFFS Cache Configuration
+#
+CONFIG_SPIFFS_CACHE=y
+CONFIG_SPIFFS_CACHE_WR=y
+# CONFIG_SPIFFS_CACHE_STATS is not set
+# end of SPIFFS Cache Configuration
+
+CONFIG_SPIFFS_PAGE_CHECK=y
+CONFIG_SPIFFS_GC_MAX_RUNS=10
+# CONFIG_SPIFFS_GC_STATS is not set
+CONFIG_SPIFFS_PAGE_SIZE=256
+CONFIG_SPIFFS_OBJ_NAME_LEN=32
+# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set
+CONFIG_SPIFFS_USE_MAGIC=y
+CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
+CONFIG_SPIFFS_META_LENGTH=4
+CONFIG_SPIFFS_USE_MTIME=y
+
+#
+# Debug Configuration
+#
+# CONFIG_SPIFFS_DBG is not set
+# CONFIG_SPIFFS_API_DBG is not set
+# CONFIG_SPIFFS_GC_DBG is not set
+# CONFIG_SPIFFS_CACHE_DBG is not set
+# CONFIG_SPIFFS_CHECK_DBG is not set
+# CONFIG_SPIFFS_TEST_VISUALISATION is not set
+# end of Debug Configuration
+# end of SPIFFS Configuration
+
+#
+# TinyUSB
+#
+
+#
+# Descriptor configuration
+#
+CONFIG_USB_DESC_CUSTOM_VID=0x1234
+CONFIG_USB_DESC_CUSTOM_PID=0x5678
+# end of Descriptor configuration
+# end of TinyUSB
+
+#
+# Unity unit testing library
+#
+CONFIG_UNITY_ENABLE_FLOAT=y
+CONFIG_UNITY_ENABLE_DOUBLE=y
+# CONFIG_UNITY_ENABLE_COLOR is not set
+CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
+# CONFIG_UNITY_ENABLE_FIXTURE is not set
+# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set
+# end of Unity unit testing library
+
+#
+# Virtual file system
+#
+CONFIG_VFS_SUPPORT_IO=y
+CONFIG_VFS_SUPPORT_DIR=y
+CONFIG_VFS_SUPPORT_SELECT=y
+CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_VFS_SUPPORT_TERMIOS=y
+
+#
+# Host File System I/O (Semihosting)
+#
+CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
+# end of Host File System I/O (Semihosting)
+# end of Virtual file system
+
+#
+# Wear Levelling
+#
+# CONFIG_WL_SECTOR_SIZE_512 is not set
+CONFIG_WL_SECTOR_SIZE_4096=y
+CONFIG_WL_SECTOR_SIZE=4096
+# end of Wear Levelling
+
+#
+# Wi-Fi Provisioning Manager
+#
+CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
+CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
+# end of Wi-Fi Provisioning Manager
+
+#
+# Supplicant
+#
+CONFIG_WPA_MBEDTLS_CRYPTO=y
+# CONFIG_WPA_DEBUG_PRINT is not set
+# CONFIG_WPA_TESTING_OPTIONS is not set
+# CONFIG_WPA_TLS_V12 is not set
+# CONFIG_WPA_WPS_WARS is not set
+# end of Supplicant
+# end of Component config
+
+#
+# Compatibility options
+#
+# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
+# end of Compatibility options
+
+# Deprecated options for backward compatibility
+CONFIG_TOOLPREFIX="xtensa-esp32-elf-"
+# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
+CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
+# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
+CONFIG_LOG_BOOTLOADER_LEVEL=3
+# CONFIG_APP_ROLLBACK_ENABLE is not set
+# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
+# CONFIG_FLASHMODE_QIO is not set
+# CONFIG_FLASHMODE_QOUT is not set
+CONFIG_FLASHMODE_DIO=y
+# CONFIG_FLASHMODE_DOUT is not set
+# CONFIG_MONITOR_BAUD_9600B is not set
+# CONFIG_MONITOR_BAUD_57600B is not set
+CONFIG_MONITOR_BAUD_115200B=y
+# CONFIG_MONITOR_BAUD_230400B is not set
+# CONFIG_MONITOR_BAUD_921600B is not set
+# CONFIG_MONITOR_BAUD_2MB is not set
+# CONFIG_MONITOR_BAUD_OTHER is not set
+CONFIG_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_MONITOR_BAUD=115200
+CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
+# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
+CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
+# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
+# CONFIG_CXX_EXCEPTIONS is not set
+CONFIG_STACK_CHECK_NONE=y
+# CONFIG_STACK_CHECK_NORM is not set
+# CONFIG_STACK_CHECK_STRONG is not set
+# CONFIG_STACK_CHECK_ALL is not set
+# CONFIG_WARN_WRITE_STRINGS is not set
+# CONFIG_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
+CONFIG_ESP32_APPTRACE_DEST_NONE=y
+CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
+CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
+CONFIG_ADC2_DISABLE_DAC=y
+# CONFIG_SPIRAM_SUPPORT is not set
+CONFIG_TRACEMEM_RESERVE_DRAM=0x0
+# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set
+CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y
+CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4
+# CONFIG_ULP_COPROC_ENABLED is not set
+CONFIG_ULP_COPROC_RESERVE_MEM=0
+CONFIG_BROWNOUT_DET=y
+CONFIG_BROWNOUT_DET_LVL_SEL_0=y
+# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set
+CONFIG_BROWNOUT_DET_LVL=0
+CONFIG_REDUCE_PHY_TX_POWER=y
+CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y
+# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set
+# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set
+# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set
+# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set
+# CONFIG_NO_BLOBS is not set
+# CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
+CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=4304
+CONFIG_MAIN_TASK_STACK_SIZE=6584
+CONFIG_IPC_TASK_STACK_SIZE=3024
+CONFIG_CONSOLE_UART_DEFAULT=y
+# CONFIG_CONSOLE_UART_CUSTOM is not set
+# CONFIG_CONSOLE_UART_NONE is not set
+CONFIG_CONSOLE_UART_NUM=0
+CONFIG_CONSOLE_UART_TX_GPIO=1
+CONFIG_CONSOLE_UART_RX_GPIO=3
+CONFIG_CONSOLE_UART_BAUDRATE=115200
+CONFIG_INT_WDT=y
+CONFIG_INT_WDT_TIMEOUT_MS=300
+CONFIG_INT_WDT_CHECK_CPU1=y
+CONFIG_TASK_WDT=y
+# CONFIG_TASK_WDT_PANIC is not set
+CONFIG_TASK_WDT_TIMEOUT_S=5
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
+# CONFIG_EVENT_LOOP_PROFILING is not set
+CONFIG_POST_EVENTS_FROM_ISR=y
+CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
+# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set
+CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP32S2_PANIC_GDBSTUB is not set
+CONFIG_TIMER_TASK_STACK_SIZE=6584
+CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_MB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_MB_QUEUE_LENGTH=20
+CONFIG_MB_SERIAL_TASK_STACK_SIZE=2048
+CONFIG_MB_SERIAL_BUF_SIZE=256
+CONFIG_MB_SERIAL_TASK_PRIO=10
+# CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT is not set
+CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_MB_CONTROLLER_STACK_SIZE=4096
+CONFIG_MB_EVENT_QUEUE_TIMEOUT=20
+CONFIG_MB_TIMER_PORT_ENABLED=y
+CONFIG_MB_TIMER_GROUP=0
+CONFIG_MB_TIMER_INDEX=0
+# CONFIG_SUPPORT_STATIC_ALLOCATION is not set
+CONFIG_TIMER_TASK_PRIORITY=1
+CONFIG_TIMER_TASK_STACK_DEPTH=5048
+CONFIG_TIMER_QUEUE_LENGTH=10
+# CONFIG_L2_TO_L3_COPY is not set
+# CONFIG_USE_ONLY_LWIP_SELECT is not set
+CONFIG_ESP_GRATUITOUS_ARP=y
+CONFIG_GARP_TMR_INTERVAL=60
+CONFIG_TCPIP_RECVMBOX_SIZE=32
+CONFIG_TCP_MAXRTX=12
+CONFIG_TCP_SYNMAXRTX=6
+CONFIG_TCP_MSS=1440
+CONFIG_TCP_MSL=60000
+CONFIG_TCP_SND_BUF_DEFAULT=5744
+CONFIG_TCP_WND_DEFAULT=5744
+CONFIG_TCP_RECVMBOX_SIZE=6
+CONFIG_TCP_QUEUE_OOSEQ=y
+# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_TCP_OVERSIZE_MSS=y
+# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_TCP_OVERSIZE_DISABLE is not set
+CONFIG_UDP_RECVMBOX_SIZE=6
+CONFIG_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set
+# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set
+CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_PPP_SUPPORT is not set
+CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_ESP32_PTHREAD_STACK_MIN=768
+CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y
+# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set
+# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set
+CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
+CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
+CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_SUPPORT_TERMIOS=y
+CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
+# End of deprecated options
+
diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/sdkconfig.h b/minimal-examples/embedded/esp32/esp-heltec-wb32/sdkconfig.h
new file mode 100644 (file)
index 0000000..43d3c99
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * Automatically generated file. DO NOT EDIT.
+ * Espressif IoT Development Framework (ESP-IDF) Configuration Header
+ */
+#pragma once
+#define CONFIG_IDF_CMAKE 1
+#define CONFIG_IDF_TARGET "esp32"
+#define CONFIG_IDF_TARGET_ESP32 1
+#define CONFIG_IDF_FIRMWARE_CHIP_ID 0x0000
+#define CONFIG_SDK_TOOLPREFIX "xtensa-esp32-elf-"
+#define CONFIG_APP_BUILD_TYPE_APP_2NDBOOT 1
+#define CONFIG_APP_BUILD_GENERATE_BINARIES 1
+#define CONFIG_APP_BUILD_BOOTLOADER 1
+#define CONFIG_APP_BUILD_USE_FLASH_SECTIONS 1
+#define CONFIG_APP_COMPILE_TIME_DATE 1
+#define CONFIG_APP_RETRIEVE_LEN_ELF_SHA 16
+#define CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE 1
+#define CONFIG_BOOTLOADER_LOG_LEVEL_INFO 1
+#define CONFIG_BOOTLOADER_LOG_LEVEL 3
+#define CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V 1
+#define CONFIG_BOOTLOADER_WDT_ENABLE 1
+#define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
+#define CONFIG_BOOTLOADER_RESERVE_RTC_SIZE 0x0
+#define CONFIG_ESPTOOLPY_BAUD_OTHER_VAL 115200
+#define CONFIG_ESPTOOLPY_FLASHMODE_DIO 1
+#define CONFIG_ESPTOOLPY_FLASHMODE "dio"
+#define CONFIG_ESPTOOLPY_FLASHFREQ_26M 1
+#define CONFIG_ESPTOOLPY_FLASHFREQ "26m"
+#define CONFIG_ESPTOOLPY_FLASHSIZE_2MB 1
+#define CONFIG_ESPTOOLPY_FLASHSIZE "2MB"
+#define CONFIG_ESPTOOLPY_FLASHSIZE_DETECT 1
+#define CONFIG_ESPTOOLPY_BEFORE_RESET 1
+#define CONFIG_ESPTOOLPY_BEFORE "default_reset"
+#define CONFIG_ESPTOOLPY_AFTER_RESET 1
+#define CONFIG_ESPTOOLPY_AFTER "hard_reset"
+#define CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B 1
+#define CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL 115200
+#define CONFIG_ESPTOOLPY_MONITOR_BAUD 115200
+#define CONFIG_PARTITION_TABLE_CUSTOM 1
+#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv"
+#define CONFIG_PARTITION_TABLE_FILENAME "partitions_singleapp.csv"
+#define CONFIG_PARTITION_TABLE_OFFSET 0x8000
+#define CONFIG_PARTITION_TABLE_MD5 1
+#define CONFIG_COMPILER_OPTIMIZATION_DEFAULT 1
+#define CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE 1
+#define CONFIG_COMPILER_STACK_CHECK_MODE_NONE 1
+#define CONFIG_APPTRACE_DEST_NONE 1
+#define CONFIG_APPTRACE_LOCK_ENABLE 1
+#define CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF 0
+#define CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF 0
+#define CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF 0
+#define CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF 0
+#define CONFIG_BTDM_CTRL_PINNED_TO_CORE 0
+#define CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF 1
+#define CONFIG_BT_RESERVE_DRAM 0x0
+#define CONFIG_COAP_MBEDTLS_PSK 1
+#define CONFIG_COAP_LOG_DEFAULT_LEVEL 0
+#define CONFIG_ADC_DISABLE_DAC 1
+#define CONFIG_SPI_MASTER_ISR_IN_IRAM 1
+#define CONFIG_SPI_SLAVE_ISR_IN_IRAM 1
+#define CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4 1
+#define CONFIG_EFUSE_MAX_BLK_LEN 192
+#define CONFIG_ESP_TLS_USING_MBEDTLS 1
+#define CONFIG_ESP32_REV_MIN_0 1
+#define CONFIG_ESP32_REV_MIN 0
+#define CONFIG_ESP32_DPORT_WORKAROUND 1
+#define CONFIG_ESP32_DEFAULT_CPU_FREQ_160 1
+#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 160
+#define CONFIG_ESP32_TRACEMEM_RESERVE_DRAM 0x0
+#define CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR 1
+#define CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES 4
+#define CONFIG_ESP32_ULP_COPROC_RESERVE_MEM 0
+#define CONFIG_ESP32_DEBUG_OCDAWARE 1
+#define CONFIG_ESP32_BROWNOUT_DET 1
+#define CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0 1
+#define CONFIG_ESP32_BROWNOUT_DET_LVL 0
+#define CONFIG_ESP32_REDUCE_PHY_TX_POWER 1
+#define CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 1
+#define CONFIG_ESP32_RTC_CLK_SRC_INT_RC 1
+#define CONFIG_ESP32_RTC_CLK_CAL_CYCLES 1024
+#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000
+#define CONFIG_ESP32_XTAL_FREQ_26 1
+#define CONFIG_ESP32_XTAL_FREQ 26
+#define CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL 5
+#define CONFIG_ADC_CAL_EFUSE_TP_ENABLE 1
+#define CONFIG_ADC_CAL_EFUSE_VREF_ENABLE 1
+#define CONFIG_ADC_CAL_LUT_ENABLE 1
+#define CONFIG_ESP_ERR_TO_NAME_LOOKUP 1
+#define CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE 32
+#define CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE 2304
+#define CONFIG_ESP_MAIN_TASK_STACK_SIZE 6584
+#define CONFIG_ESP_IPC_TASK_STACK_SIZE 1024
+#define CONFIG_ESP_IPC_USES_CALLERS_PRIORITY 1
+#define CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE 2048
+#define CONFIG_ESP_CONSOLE_UART_DEFAULT 1
+#define CONFIG_ESP_CONSOLE_UART_NUM 0
+#define CONFIG_ESP_CONSOLE_UART_TX_GPIO 1
+#define CONFIG_ESP_CONSOLE_UART_RX_GPIO 3
+#define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200
+#define CONFIG_ESP_INT_WDT 1
+#define CONFIG_ESP_INT_WDT_TIMEOUT_MS 300
+#define CONFIG_ESP_INT_WDT_CHECK_CPU1 1
+#define CONFIG_ESP_TASK_WDT 1
+#define CONFIG_ESP_TASK_WDT_TIMEOUT_S 5
+#define CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 1
+#define CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_BT 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH 1
+#define CONFIG_ETH_ENABLED 1
+#define CONFIG_ETH_USE_ESP32_EMAC 1
+#define CONFIG_ETH_PHY_INTERFACE_RMII 1
+#define CONFIG_ETH_RMII_CLK_INPUT 1
+#define CONFIG_ETH_RMII_CLK_IN_GPIO 0
+#define CONFIG_ETH_DMA_BUFFER_SIZE 512
+#define CONFIG_ETH_DMA_RX_BUFFER_NUM 10
+#define CONFIG_ETH_DMA_TX_BUFFER_NUM 10
+#define CONFIG_ETH_USE_SPI_ETHERNET 1
+#define CONFIG_ESP_EVENT_POST_FROM_ISR 1
+#define CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR 1
+#define CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS 1
+#define CONFIG_HTTPD_MAX_REQ_HDR_LEN 512
+#define CONFIG_HTTPD_MAX_URI_LEN 512
+#define CONFIG_HTTPD_ERR_RESP_NO_DELAY 1
+#define CONFIG_HTTPD_PURGE_BUF_LEN 32
+#define CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL 120
+#define CONFIG_ESP_NETIF_TCPIP_LWIP 1
+#define CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER 1
+#define CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT 1
+#define CONFIG_ESP_TIMER_TASK_STACK_SIZE 3584
+#define CONFIG_ESP_TIMER_IMPL_TG0_LAC 1
+#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 10
+#define CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 32
+#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER 1
+#define CONFIG_ESP32_WIFI_TX_BUFFER_TYPE 1
+#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32
+#define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 1
+#define CONFIG_ESP32_WIFI_TX_BA_WIN 6
+#define CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED 1
+#define CONFIG_ESP32_WIFI_RX_BA_WIN 6
+#define CONFIG_ESP32_WIFI_NVS_ENABLED 1
+#define CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 1
+#define CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN 752
+#define CONFIG_ESP32_WIFI_MGMT_SBUF_NUM 32
+#define CONFIG_ESP32_WIFI_IRAM_OPT 1
+#define CONFIG_ESP32_WIFI_RX_IRAM_OPT 1
+#define CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE 1
+#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1
+#define CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER 20
+#define CONFIG_ESP32_PHY_MAX_TX_POWER 20
+#define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1
+#define CONFIG_FATFS_CODEPAGE_437 1
+#define CONFIG_FATFS_CODEPAGE 437
+#define CONFIG_FATFS_LFN_NONE 1
+#define CONFIG_FATFS_FS_LOCK 0
+#define CONFIG_FATFS_TIMEOUT_MS 10000
+#define CONFIG_FATFS_PER_FILE_CACHE 1
+#define CONFIG_FMB_COMM_MODE_RTU_EN 1
+#define CONFIG_FMB_COMM_MODE_ASCII_EN 1
+#define CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND 150
+#define CONFIG_FMB_MASTER_DELAY_MS_CONVERT 200
+#define CONFIG_FMB_QUEUE_LENGTH 20
+#define CONFIG_FMB_SERIAL_TASK_STACK_SIZE 2048
+#define CONFIG_FMB_SERIAL_BUF_SIZE 256
+#define CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB 8
+#define CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS 1000
+#define CONFIG_FMB_SERIAL_TASK_PRIO 10
+#define CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT 20
+#define CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE 20
+#define CONFIG_FMB_CONTROLLER_STACK_SIZE 4096
+#define CONFIG_FMB_EVENT_QUEUE_TIMEOUT 20
+#define CONFIG_FMB_TIMER_PORT_ENABLED 1
+#define CONFIG_FMB_TIMER_GROUP 0
+#define CONFIG_FMB_TIMER_INDEX 0
+#define CONFIG_FREERTOS_NO_AFFINITY 0x7FFFFFFF
+#define CONFIG_FREERTOS_CORETIMER_0 1
+#define CONFIG_FREERTOS_HZ 100
+#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1
+#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY 1
+#define CONFIG_FREERTOS_INTERRUPT_BACKTRACE 1
+#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 1
+#define CONFIG_FREERTOS_ASSERT_FAIL_ABORT 1
+#define CONFIG_FREERTOS_IDLE_TASK_STACKSIZE 1536
+#define CONFIG_FREERTOS_ISR_STACKSIZE 1536
+#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16
+#define CONFIG_FREERTOS_TIMER_TASK_PRIORITY 1
+#define CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH 2048
+#define CONFIG_FREERTOS_TIMER_QUEUE_LENGTH 10
+#define CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE 0
+#define CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER 1
+#define CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER 1
+#define CONFIG_FREERTOS_DEBUG_OCDAWARE 1
+#define CONFIG_HEAP_POISONING_DISABLED 1
+#define CONFIG_HEAP_TRACING_OFF 1
+#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1
+#define CONFIG_LOG_DEFAULT_LEVEL 3
+#define CONFIG_LOG_COLORS 1
+#define CONFIG_LOG_TIMESTAMP_SOURCE_RTOS 1
+#define CONFIG_LWIP_LOCAL_HOSTNAME "espressif"
+#define CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES 1
+#define CONFIG_LWIP_TIMERS_ONDEMAND 1
+#define CONFIG_LWIP_MAX_SOCKETS 10
+#define CONFIG_LWIP_SO_REUSE 1
+#define CONFIG_LWIP_SO_REUSE_RXTOALL 1
+#define CONFIG_LWIP_IP_FRAG 1
+#define CONFIG_LWIP_ESP_GRATUITOUS_ARP 1
+#define CONFIG_LWIP_GARP_TMR_INTERVAL 60
+#define CONFIG_LWIP_TCPIP_RECVMBOX_SIZE 32
+#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1
+#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60
+#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8
+#define CONFIG_LWIP_NETIF_LOOPBACK 1
+#define CONFIG_LWIP_LOOPBACK_MAX_PBUFS 8
+#define CONFIG_LWIP_MAX_ACTIVE_TCP 16
+#define CONFIG_LWIP_MAX_LISTENING_TCP 16
+#define CONFIG_LWIP_TCP_MAXRTX 12
+#define CONFIG_LWIP_TCP_SYNMAXRTX 6
+#define CONFIG_LWIP_TCP_MSS 1440
+#define CONFIG_LWIP_TCP_TMR_INTERVAL 250
+#define CONFIG_LWIP_TCP_MSL 60000
+#define CONFIG_LWIP_TCP_SND_BUF_DEFAULT 5744
+#define CONFIG_LWIP_TCP_WND_DEFAULT 5744
+#define CONFIG_LWIP_TCP_RECVMBOX_SIZE 6
+#define CONFIG_LWIP_TCP_QUEUE_OOSEQ 1
+#define CONFIG_LWIP_TCP_OVERSIZE_MSS 1
+#define CONFIG_LWIP_MAX_UDP_PCBS 16
+#define CONFIG_LWIP_UDP_RECVMBOX_SIZE 6
+#define CONFIG_LWIP_TCPIP_TASK_STACK_SIZE 3072
+#define CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY 1
+#define CONFIG_LWIP_TCPIP_TASK_AFFINITY 0x7FFFFFFF
+#define CONFIG_LWIP_MAX_RAW_PCBS 16
+#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1
+#define CONFIG_LWIP_SNTP_UPDATE_DELAY 3600000
+#define CONFIG_LWIP_ESP_LWIP_ASSERT 1
+#define CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC 1
+#define CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN 1
+#define CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN 16384
+#define CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN 4096
+#define CONFIG_MBEDTLS_CERTIFICATE_BUNDLE 1
+#define CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL 1
+#define CONFIG_MBEDTLS_HARDWARE_AES 1
+#define CONFIG_MBEDTLS_HARDWARE_MPI 1
+#define CONFIG_MBEDTLS_HARDWARE_SHA 1
+#define CONFIG_MBEDTLS_HAVE_TIME 1
+#define CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT 1
+#define CONFIG_MBEDTLS_TLS_SERVER 1
+#define CONFIG_MBEDTLS_TLS_CLIENT 1
+#define CONFIG_MBEDTLS_TLS_ENABLED 1
+#define CONFIG_MBEDTLS_PSK_MODES 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA 1
+#define CONFIG_MBEDTLS_SSL_RENEGOTIATION 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_1 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 1
+#define CONFIG_MBEDTLS_SSL_PROTO_DTLS 1
+#define CONFIG_MBEDTLS_SSL_ALPN 1
+#define CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS 1
+#define CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS 1
+#define CONFIG_MBEDTLS_AES_C 1
+#define CONFIG_MBEDTLS_RC4_DISABLED 1
+#define CONFIG_MBEDTLS_CCM_C 1
+#define CONFIG_MBEDTLS_GCM_C 1
+#define CONFIG_MBEDTLS_PEM_PARSE_C 1
+#define CONFIG_MBEDTLS_PEM_WRITE_C 1
+#define CONFIG_MBEDTLS_X509_CRL_PARSE_C 1
+#define CONFIG_MBEDTLS_X509_CSR_PARSE_C 1
+#define CONFIG_MBEDTLS_ECP_C 1
+#define CONFIG_MBEDTLS_ECDH_C 1
+#define CONFIG_MBEDTLS_ECDSA_C 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_NIST_OPTIM 1
+#define CONFIG_MDNS_MAX_SERVICES 10
+#define CONFIG_MDNS_TASK_PRIORITY 1
+#define CONFIG_MDNS_TASK_AFFINITY_CPU0 1
+#define CONFIG_MDNS_TASK_AFFINITY 0x0
+#define CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS 2000
+#define CONFIG_MDNS_TIMER_PERIOD_MS 100
+#define CONFIG_MQTT_PROTOCOL_311 1
+#define CONFIG_MQTT_TRANSPORT_SSL 1
+#define CONFIG_MQTT_TRANSPORT_WEBSOCKET 1
+#define CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE 1
+#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF 1
+#define CONFIG_NEWLIB_STDIN_LINE_ENDING_CR 1
+#define CONFIG_OPENSSL_ASSERT_EXIT 1
+#define CONFIG_PTHREAD_TASK_PRIO_DEFAULT 5
+#define CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT 3072
+#define CONFIG_PTHREAD_STACK_MIN 768
+#define CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY 1
+#define CONFIG_PTHREAD_TASK_CORE_DEFAULT -1
+#define CONFIG_PTHREAD_TASK_NAME_DEFAULT "pthread"
+#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1
+#define CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS 1
+#define CONFIG_SPI_FLASH_YIELD_DURING_ERASE 1
+#define CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS 20
+#define CONFIG_SPI_FLASH_ERASE_YIELD_TICKS 1
+#define CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP 1
+#define CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP 1
+#define CONFIG_SPI_FLASH_SUPPORT_GD_CHIP 1
+#define CONFIG_SPIFFS_MAX_PARTITIONS 3
+#define CONFIG_SPIFFS_CACHE 1
+#define CONFIG_SPIFFS_CACHE_WR 1
+#define CONFIG_SPIFFS_PAGE_CHECK 1
+#define CONFIG_SPIFFS_GC_MAX_RUNS 10
+#define CONFIG_SPIFFS_PAGE_SIZE 256
+#define CONFIG_SPIFFS_OBJ_NAME_LEN 32
+#define CONFIG_SPIFFS_USE_MAGIC 1
+#define CONFIG_SPIFFS_USE_MAGIC_LENGTH 1
+#define CONFIG_SPIFFS_META_LENGTH 4
+#define CONFIG_SPIFFS_USE_MTIME 1
+#define CONFIG_USB_DESC_CUSTOM_VID 0x1234
+#define CONFIG_USB_DESC_CUSTOM_PID 0x5678
+#define CONFIG_UNITY_ENABLE_FLOAT 1
+#define CONFIG_UNITY_ENABLE_DOUBLE 1
+#define CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER 1
+#define CONFIG_VFS_SUPPORT_IO 1
+#define CONFIG_VFS_SUPPORT_DIR 1
+#define CONFIG_VFS_SUPPORT_SELECT 1
+#define CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT 1
+#define CONFIG_VFS_SUPPORT_TERMIOS 1
+#define CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS 1
+#define CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN 128
+#define CONFIG_WL_SECTOR_SIZE_4096 1
+#define CONFIG_WL_SECTOR_SIZE 4096
+#define CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES 16
+#define CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT 30
+#define CONFIG_WPA_MBEDTLS_CRYPTO 1
+
+/* List of deprecated options */
+#define CONFIG_ADC2_DISABLE_DAC CONFIG_ADC_DISABLE_DAC
+#define CONFIG_BROWNOUT_DET CONFIG_ESP32_BROWNOUT_DET
+#define CONFIG_BROWNOUT_DET_LVL_SEL_0 CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0
+#define CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG CONFIG_COMPILER_OPTIMIZATION_DEFAULT
+#define CONFIG_CONSOLE_UART_BAUDRATE CONFIG_ESP_CONSOLE_UART_BAUDRATE
+#define CONFIG_CONSOLE_UART_DEFAULT CONFIG_ESP_CONSOLE_UART_DEFAULT
+#define CONFIG_CONSOLE_UART_RX_GPIO CONFIG_ESP_CONSOLE_UART_RX_GPIO
+#define CONFIG_CONSOLE_UART_TX_GPIO CONFIG_ESP_CONSOLE_UART_TX_GPIO
+#define CONFIG_ESP32S2_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT
+#define CONFIG_ESP32_APPTRACE_DEST_NONE CONFIG_APPTRACE_DEST_NONE
+#define CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY
+#define CONFIG_ESP32_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT
+#define CONFIG_ESP32_PTHREAD_STACK_MIN CONFIG_PTHREAD_STACK_MIN
+#define CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT CONFIG_PTHREAD_TASK_NAME_DEFAULT
+#define CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT CONFIG_PTHREAD_TASK_PRIO_DEFAULT
+#define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT
+#define CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC CONFIG_ESP32_RTC_CLK_SRC_INT_RC
+#define CONFIG_ESP_GRATUITOUS_ARP CONFIG_LWIP_ESP_GRATUITOUS_ARP
+#define CONFIG_FLASHMODE_DIO CONFIG_ESPTOOLPY_FLASHMODE_DIO
+#define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR
+#define CONFIG_GARP_TMR_INTERVAL CONFIG_LWIP_GARP_TMR_INTERVAL
+#define CONFIG_INT_WDT CONFIG_ESP_INT_WDT
+#define CONFIG_INT_WDT_CHECK_CPU1 CONFIG_ESP_INT_WDT_CHECK_CPU1
+#define CONFIG_INT_WDT_TIMEOUT_MS CONFIG_ESP_INT_WDT_TIMEOUT_MS
+#define CONFIG_IPC_TASK_STACK_SIZE CONFIG_ESP_IPC_TASK_STACK_SIZE
+#define CONFIG_LOG_BOOTLOADER_LEVEL_INFO CONFIG_BOOTLOADER_LOG_LEVEL_INFO
+#define CONFIG_MAIN_TASK_STACK_SIZE CONFIG_ESP_MAIN_TASK_STACK_SIZE
+#define CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE
+#define CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT
+#define CONFIG_MB_CONTROLLER_STACK_SIZE CONFIG_FMB_CONTROLLER_STACK_SIZE
+#define CONFIG_MB_EVENT_QUEUE_TIMEOUT CONFIG_FMB_EVENT_QUEUE_TIMEOUT
+#define CONFIG_MB_MASTER_DELAY_MS_CONVERT CONFIG_FMB_MASTER_DELAY_MS_CONVERT
+#define CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND
+#define CONFIG_MB_QUEUE_LENGTH CONFIG_FMB_QUEUE_LENGTH
+#define CONFIG_MB_SERIAL_BUF_SIZE CONFIG_FMB_SERIAL_BUF_SIZE
+#define CONFIG_MB_SERIAL_TASK_PRIO CONFIG_FMB_SERIAL_TASK_PRIO
+#define CONFIG_MB_SERIAL_TASK_STACK_SIZE CONFIG_FMB_SERIAL_TASK_STACK_SIZE
+#define CONFIG_MB_TIMER_GROUP CONFIG_FMB_TIMER_GROUP
+#define CONFIG_MB_TIMER_INDEX CONFIG_FMB_TIMER_INDEX
+#define CONFIG_MB_TIMER_PORT_ENABLED CONFIG_FMB_TIMER_PORT_ENABLED
+#define CONFIG_MONITOR_BAUD_115200B CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B
+#define CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE
+#define CONFIG_OPTIMIZATION_LEVEL_DEBUG CONFIG_COMPILER_OPTIMIZATION_DEFAULT
+#define CONFIG_POST_EVENTS_FROM_IRAM_ISR CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR
+#define CONFIG_POST_EVENTS_FROM_ISR CONFIG_ESP_EVENT_POST_FROM_ISR
+#define CONFIG_REDUCE_PHY_TX_POWER CONFIG_ESP32_REDUCE_PHY_TX_POWER
+#define CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN
+#define CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS
+#define CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS
+#define CONFIG_STACK_CHECK_NONE CONFIG_COMPILER_STACK_CHECK_MODE_NONE
+#define CONFIG_SUPPORT_TERMIOS CONFIG_VFS_SUPPORT_TERMIOS
+#define CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT
+#define CONFIG_SYSTEM_EVENT_QUEUE_SIZE CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE
+#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE
+#define CONFIG_TASK_WDT CONFIG_ESP_TASK_WDT
+#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
+#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
+#define CONFIG_TASK_WDT_TIMEOUT_S CONFIG_ESP_TASK_WDT_TIMEOUT_S
+#define CONFIG_TCPIP_RECVMBOX_SIZE CONFIG_LWIP_TCPIP_RECVMBOX_SIZE
+#define CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY
+#define CONFIG_TCPIP_TASK_STACK_SIZE CONFIG_LWIP_TCPIP_TASK_STACK_SIZE
+#define CONFIG_TCP_MAXRTX CONFIG_LWIP_TCP_MAXRTX
+#define CONFIG_TCP_MSL CONFIG_LWIP_TCP_MSL
+#define CONFIG_TCP_MSS CONFIG_LWIP_TCP_MSS
+#define CONFIG_TCP_OVERSIZE_MSS CONFIG_LWIP_TCP_OVERSIZE_MSS
+#define CONFIG_TCP_QUEUE_OOSEQ CONFIG_LWIP_TCP_QUEUE_OOSEQ
+#define CONFIG_TCP_RECVMBOX_SIZE CONFIG_LWIP_TCP_RECVMBOX_SIZE
+#define CONFIG_TCP_SND_BUF_DEFAULT CONFIG_LWIP_TCP_SND_BUF_DEFAULT
+#define CONFIG_TCP_SYNMAXRTX CONFIG_LWIP_TCP_SYNMAXRTX
+#define CONFIG_TCP_WND_DEFAULT CONFIG_LWIP_TCP_WND_DEFAULT
+#define CONFIG_TIMER_QUEUE_LENGTH CONFIG_FREERTOS_TIMER_QUEUE_LENGTH
+#define CONFIG_TIMER_TASK_PRIORITY CONFIG_FREERTOS_TIMER_TASK_PRIORITY
+#define CONFIG_TIMER_TASK_STACK_DEPTH CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH
+#define CONFIG_TIMER_TASK_STACK_SIZE CONFIG_ESP_TIMER_TASK_STACK_SIZE
+#define CONFIG_TOOLPREFIX CONFIG_SDK_TOOLPREFIX
+#define CONFIG_UDP_RECVMBOX_SIZE CONFIG_LWIP_UDP_RECVMBOX_SIZE
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/CMakeLists.txt b/minimal-examples/embedded/esp32/esp-wrover-kit/CMakeLists.txt
new file mode 100644 (file)
index 0000000..68542b2
--- /dev/null
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.5)
+
+if (ESP_PLATFORM)
+       include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+       project(lws-minimal-esp32 C)
+       enable_testing()
+
+       target_link_libraries(lws-minimal-esp32.elf websockets)
+
+       option(LWS_WITH_DRIVERS "With generic drivers for gpio, i2c, display etc" ON)
+       set(LWS_WITH_DRIVERS ON)
+       option(LWS_WITH_SECURE_STREAMS "With secure streams" ON)
+       set(LWS_WITH_SECURE_STREAMS ON)
+       option(LWS_WITH_LWSAC "With lwsac" ON)
+       set(LWS_WITH_LWSAC ON)
+       option(LWS_WITH_STRUCT_JSON "With lws_struct JSON" ON)
+       set(LWS_WITH_STRUCT_JSON ON)
+       option(LWS_WITH_SYS_NTPCLIENT "With ntpclient" ON)
+        set(LWS_WITH_SYS_NTPCLIENT ON)
+
+       add_subdirectory(libwebsockets)
+
+       add_test(NAME flashing COMMAND idf.py flash)
+       set_tests_properties(flashing PROPERTIES
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+                            TIMEOUT 120)
+
+       add_test(NAME boot COMMAND /usr/local/bin/sai-expect)
+       set_tests_properties(boot PROPERTIES
+                            DEPENDS flashing
+                            TIMEOUT 60)
+
+endif()
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/main/CMakeLists.txt b/minimal-examples/embedded/esp32/esp-wrover-kit/main/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b7e1960
--- /dev/null
@@ -0,0 +1,7 @@
+idf_component_register(SRCS
+               lws-minimal-esp32.c
+               devices.c
+               INCLUDE_DIRS "../libwebsockets/include;${IDF_PATH}/components/spi_flash/include;${IDF_PATH}/components/nvs_flash/include;${IDF_PATH}/components/mdns/include")
+
+target_link_libraries(${COMPONENT_LIB} websockets)
+include_directories(../build/libwebsockets)
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/main/cat-565.h b/minimal-examples/embedded/esp32/esp-wrover-kit/main/cat-565.h
new file mode 100644 (file)
index 0000000..46eaefb
--- /dev/null
@@ -0,0 +1,19200 @@
+0x62, 0xEB, 0x5A, 0xAA, 0x52, 0x8A, 0x52, 0x69, 
+0x5A, 0xAA, 0x62, 0xEB, 0x73, 0x0C, 0x72, 0xEB, 
+0x52, 0x08, 0x31, 0x24, 0x4A, 0x08, 0x4A, 0x07, 
+0x41, 0xE7, 0x39, 0xC6, 0x39, 0xC6, 0x31, 0x85, 
+0x29, 0x44, 0x21, 0x24, 0x31, 0x85, 0x41, 0xE7, 
+0x41, 0xE7, 0x39, 0x85, 0x41, 0xA6, 0x39, 0x45, 
+0x31, 0x24, 0x29, 0x04, 0x20, 0xC3, 0x28, 0xC3, 
+0x28, 0xC2, 0x28, 0xC2, 0x31, 0x04, 0x49, 0xA6, 
+0x5A, 0x27, 0x62, 0x48, 0x62, 0x48, 0x52, 0x27, 
+0x39, 0x86, 0x20, 0xE3, 0x29, 0x24, 0x41, 0xE8, 
+0x39, 0xA6, 0x4A, 0x48, 0x4A, 0x49, 0x39, 0xC7, 
+0x31, 0x65, 0x29, 0x24, 0x6B, 0x2C, 0x4A, 0x29, 
+0x52, 0x69, 0x84, 0x10, 0x63, 0x0B, 0x52, 0x6A, 
+0x62, 0xEB, 0x4A, 0x08, 0x6B, 0x0C, 0x6B, 0x2C, 
+0x5A, 0xAB, 0x39, 0xC7, 0x31, 0x86, 0x73, 0xAF, 
+0xDE, 0xFD, 0xDE, 0xDC, 0xBD, 0xF8, 0x94, 0x92, 
+0x4A, 0x28, 0x29, 0x44, 0x39, 0xE6, 0x4A, 0x48, 
+0x6B, 0x2C, 0x52, 0x8A, 0x73, 0x6D, 0x6B, 0x4D, 
+0x52, 0x69, 0x52, 0x69, 0x84, 0x10, 0xAD, 0x14, 
+0xBD, 0xB6, 0xC5, 0xF6, 0xC5, 0xB4, 0xA4, 0xAF, 
+0xA4, 0xAE, 0xA4, 0x8E, 0xA4, 0xAF, 0xB5, 0x10, 
+0xB5, 0x30, 0xB5, 0x30, 0xBD, 0x51, 0xBD, 0x51, 
+0xBD, 0x51, 0xBD, 0x52, 0xBD, 0x72, 0xBD, 0x72, 
+0xB5, 0x31, 0xAC, 0xF0, 0xB5, 0x31, 0xB5, 0x31, 
+0xB5, 0x31, 0xB5, 0x31, 0xB5, 0x31, 0xB5, 0x31, 
+0xAD, 0x11, 0xAD, 0x10, 0xB5, 0x10, 0xC5, 0x92, 
+0xC5, 0x51, 0xAC, 0xD0, 0x9C, 0x8E, 0x9C, 0x6E, 
+0x94, 0x2E, 0x8B, 0xED, 0x7B, 0xAC, 0x7B, 0x8C, 
+0x7B, 0x8C, 0x83, 0xAC, 0x8C, 0x0D, 0x94, 0x4D, 
+0xB5, 0x10, 0x94, 0x0D, 0x83, 0xCC, 0x7B, 0x8B, 
+0x73, 0x6B, 0x84, 0x0E, 0x94, 0x6F, 0x83, 0xCD, 
+0x7B, 0xAD, 0x7B, 0xCD, 0x8C, 0x2F, 0x8C, 0x2F, 
+0xDE, 0xB8, 0xDE, 0xD9, 0xC6, 0x16, 0x9C, 0xB0, 
+0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x52, 
+0xAD, 0x52, 0xB5, 0x93, 0xCE, 0x35, 0xA4, 0xAF, 
+0xAC, 0xCF, 0xBD, 0x93, 0x8C, 0x4F, 0x8C, 0x4F, 
+0x73, 0xAD, 0x7B, 0xAF, 0x4A, 0x29, 0x52, 0x8A, 
+0x6B, 0x4D, 0x73, 0xAE, 0x7B, 0xCE, 0x9C, 0xB1, 
+0xA5, 0x33, 0x94, 0xB1, 0x8C, 0x70, 0x94, 0x90, 
+0x84, 0x2F, 0x8C, 0x4F, 0x84, 0x2F, 0x6B, 0x6D, 
+0x84, 0x2F, 0x8C, 0x4F, 0x84, 0x0E, 0x8C, 0x70, 
+0x9C, 0xF2, 0xBD, 0x94, 0xAD, 0x53, 0xAD, 0x12, 
+0xBD, 0x94, 0xB5, 0x73, 0xAD, 0x53, 0xC5, 0xF6, 
+0xB5, 0xB4, 0xAD, 0x33, 0xAD, 0x33, 0xA5, 0x32, 
+0xB5, 0x73, 0x9C, 0xF1, 0xAD, 0x33, 0xBD, 0xD5, 
+0xAD, 0x53, 0xB5, 0x94, 0xB5, 0x74, 0xB5, 0x94, 
+0xB5, 0x53, 0xBD, 0xB5, 0xA5, 0x12, 0x7B, 0xAD, 
+0xAD, 0x32, 0x9C, 0xB0, 0xAD, 0x53, 0xA5, 0x11, 
+0x9C, 0xB0, 0xAD, 0x32, 0xA4, 0xF1, 0xA5, 0x12, 
+0x94, 0x4F, 0x83, 0xEE, 0x83, 0xED, 0x8C, 0x2E, 
+0x94, 0x4F, 0x94, 0x8F, 0x94, 0x6F, 0x94, 0x6F, 
+0x94, 0x4F, 0xA5, 0x11, 0xAD, 0x31, 0xAD, 0x32, 
+0xB5, 0x52, 0xA4, 0xF0, 0xAD, 0x31, 0xB5, 0x51, 
+0xAD, 0x31, 0xAD, 0x31, 0xAD, 0x11, 0xAC, 0xF1, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xAD, 0x52, 0xBD, 0xB3, 
+0xAD, 0x32, 0xAC, 0xF1, 0xD5, 0xB3, 0xD5, 0x72, 
+0xCD, 0x71, 0xBD, 0x10, 0xB5, 0x10, 0xB5, 0x11, 
+0xB5, 0x10, 0xAC, 0xF0, 0xAC, 0xF0, 0xAC, 0xD0, 
+0xAC, 0xD0, 0xBD, 0x52, 0xC5, 0xB3, 0xC5, 0x92, 
+0xCD, 0xF3, 0xCD, 0xF3, 0xC5, 0x92, 0xC5, 0xB3, 
+0xBD, 0x72, 0xC5, 0xB3, 0xC5, 0xB3, 0xAC, 0xF0, 
+0xB5, 0x52, 0xB5, 0x53, 0xB5, 0x52, 0xD6, 0x35, 
+0xCD, 0xD3, 0xBD, 0x72, 0xCD, 0xB3, 0xCD, 0xD4, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xBD, 0x73, 0xB5, 0x73, 
+0xA4, 0xF1, 0xA4, 0xF2, 0x94, 0x70, 0xA4, 0xF1, 
+0xA4, 0xF2, 0x94, 0x90, 0x94, 0x71, 0x8C, 0x70, 
+0x9C, 0xD2, 0xA5, 0x13, 0xA4, 0xF3, 0x8C, 0x50, 
+0x8C, 0x50, 0x8C, 0x30, 0x7B, 0xCF, 0x6B, 0x4D, 
+0x4A, 0x6A, 0x29, 0x66, 0x21, 0x25, 0x21, 0x04, 
+0x18, 0xE4, 0x18, 0xE4, 0x29, 0x66, 0x4A, 0x6A, 
+0x6B, 0x6E, 0x8C, 0x51, 0xA4, 0xF4, 0xA5, 0x14, 
+0xA5, 0x35, 0xA5, 0x14, 0x9C, 0xD3, 0x8C, 0x51, 
+0x7B, 0xEF, 0x7B, 0xAE, 0x84, 0x10, 0x84, 0x10, 
+0x6B, 0x2C, 0x7B, 0xAE, 0x84, 0x10, 0x84, 0x32, 
+0x7C, 0x12, 0x73, 0xD1, 0x7C, 0x12, 0x8C, 0x94, 
+0x94, 0xD5, 0x8C, 0xB5, 0x94, 0xD5, 0x94, 0xD5, 
+0x94, 0xD5, 0x94, 0xF5, 0x8C, 0xD5, 0x94, 0xD5, 
+0x95, 0x16, 0x94, 0xD5, 0x84, 0x73, 0x84, 0x32, 
+0x84, 0x32, 0x73, 0xD0, 0x7B, 0xD0, 0x84, 0x31, 
+0x7B, 0xF0, 0x73, 0xAF, 0x73, 0x8F, 0x6B, 0x4E, 
+0x4A, 0x28, 0x42, 0x07, 0x4A, 0x07, 0x41, 0xE7, 
+0x4A, 0x08, 0x41, 0xE7, 0x73, 0x4C, 0x7B, 0x4C, 
+0x31, 0x45, 0x29, 0x03, 0x41, 0xE6, 0x39, 0xA6, 
+0x39, 0xA6, 0x31, 0x85, 0x39, 0xC6, 0x42, 0x07, 
+0x39, 0xE7, 0x29, 0x64, 0x31, 0x85, 0x21, 0x03, 
+0x29, 0x04, 0x31, 0x65, 0x42, 0x07, 0x29, 0x24, 
+0x31, 0x45, 0x20, 0xC3, 0x28, 0xE3, 0x39, 0x85, 
+0x5A, 0x28, 0x72, 0xCA, 0x8B, 0x4C, 0x8B, 0x4B, 
+0xB4, 0x4F, 0xC4, 0xF1, 0xC4, 0xD1, 0xCD, 0x12, 
+0xB4, 0xB1, 0xA4, 0x71, 0xA4, 0xB2, 0x52, 0x69, 
+0x18, 0xE3, 0x18, 0xE3, 0x10, 0xA2, 0x18, 0xC3, 
+0x29, 0x24, 0x41, 0xE7, 0x63, 0x0C, 0x21, 0x24, 
+0x39, 0xA7, 0x6B, 0x4D, 0x5A, 0xCB, 0x52, 0x69, 
+0x5A, 0xAA, 0x4A, 0x28, 0x4A, 0x49, 0x42, 0x07, 
+0x41, 0xE7, 0x39, 0xA6, 0x6B, 0x6D, 0xDE, 0xFD, 
+0xDE, 0xFD, 0xC6, 0x3A, 0xA4, 0xF4, 0x52, 0x6A, 
+0x29, 0x45, 0x31, 0x85, 0x52, 0x89, 0x63, 0x2C, 
+0x6B, 0x2C, 0x31, 0x66, 0x42, 0x28, 0x63, 0x0B, 
+0x4A, 0x69, 0x39, 0xC7, 0x8C, 0x31, 0xA4, 0xF4, 
+0xCE, 0x18, 0xD6, 0x38, 0xE6, 0xDA, 0xC5, 0x94, 
+0x9C, 0x6F, 0x94, 0x4F, 0x9C, 0x6F, 0xA4, 0xD0, 
+0xBD, 0x92, 0xBD, 0x72, 0xB5, 0x31, 0xB5, 0x31, 
+0xB5, 0x31, 0xB5, 0x31, 0x94, 0x0D, 0x94, 0x2D, 
+0xA4, 0xAF, 0xB5, 0x10, 0xAC, 0xF0, 0x83, 0xAB, 
+0x94, 0x0C, 0x94, 0x2D, 0x94, 0x2D, 0x9C, 0x4E, 
+0x9C, 0x6E, 0x9C, 0x6E, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xAC, 0xCF, 0xB5, 0x10, 0xB5, 0x30, 
+0xB5, 0x10, 0xB5, 0x11, 0xAC, 0xF0, 0xB5, 0x11, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xB5, 0x11, 0xB4, 0xEF, 
+0xB5, 0x0F, 0xAC, 0xCF, 0xB4, 0xF0, 0xB5, 0x10, 
+0xBD, 0x11, 0xB5, 0x31, 0xBD, 0x51, 0xB5, 0x30, 
+0xB5, 0x10, 0xB5, 0x10, 0xAD, 0x11, 0xA4, 0xD0, 
+0xA4, 0x8F, 0xA4, 0xAF, 0xA4, 0xCF, 0x9C, 0x8E, 
+0x9C, 0x6E, 0xA4, 0xAF, 0x9C, 0x8E, 0x94, 0x2D, 
+0x9C, 0xAF, 0xB5, 0x72, 0x9C, 0x6E, 0xAC, 0xEF, 
+0xA4, 0xCF, 0xB5, 0x31, 0x9C, 0xAF, 0x8C, 0x2E, 
+0x6B, 0x0B, 0x41, 0xE7, 0x20, 0xE4, 0x4A, 0x49, 
+0x73, 0x8E, 0x6B, 0x2C, 0x63, 0x2B, 0x9C, 0xF1, 
+0xCE, 0x56, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0xB4, 
+0xB5, 0xB4, 0xAD, 0x32, 0xA5, 0x12, 0x94, 0x70, 
+0xBD, 0xB4, 0xB5, 0x73, 0x94, 0x90, 0x84, 0x2F, 
+0xA4, 0xF2, 0xC5, 0xF5, 0xB5, 0x94, 0xB5, 0x94, 
+0xDE, 0xB8, 0xD6, 0x98, 0xC6, 0x16, 0xAD, 0x32, 
+0xCE, 0x37, 0xB5, 0xB4, 0xC6, 0x16, 0xC6, 0x37, 
+0xAD, 0x53, 0xA5, 0x33, 0xA5, 0x33, 0xB5, 0x94, 
+0xB5, 0x94, 0xC5, 0xF6, 0xC6, 0x16, 0xC6, 0x37, 
+0xC6, 0x16, 0xBD, 0xD5, 0xA4, 0xF2, 0x7B, 0xAC, 
+0xAD, 0x12, 0xAD, 0x33, 0x9C, 0x90, 0x9C, 0x90, 
+0x94, 0x4F, 0x94, 0x6F, 0xA4, 0xD0, 0xA5, 0x11, 
+0x94, 0x4F, 0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x52, 
+0xAD, 0x32, 0xA4, 0xF1, 0xA4, 0xD1, 0x9C, 0x90, 
+0x8C, 0x4E, 0x9C, 0xB0, 0xA4, 0xD0, 0xA4, 0xF0, 
+0xA4, 0xCF, 0x9C, 0xAF, 0xA4, 0xF0, 0xAD, 0x31, 
+0xB5, 0x51, 0xAD, 0x31, 0xA5, 0x11, 0xA4, 0xF0, 
+0xA5, 0x11, 0xAD, 0x11, 0xBD, 0x93, 0xAD, 0x31, 
+0xAD, 0x32, 0xAD, 0x11, 0xDD, 0xF4, 0xDD, 0xB3, 
+0xCD, 0x71, 0xC5, 0x30, 0xBD, 0x51, 0xC5, 0x72, 
+0xB5, 0x31, 0xB5, 0x31, 0xB5, 0x11, 0xAD, 0x10, 
+0x9C, 0x8F, 0xAC, 0xF0, 0xB5, 0x11, 0xB5, 0x31, 
+0xBD, 0x72, 0xC5, 0x92, 0xBD, 0x72, 0xC5, 0xB2, 
+0xC5, 0x92, 0xC5, 0xB3, 0xB5, 0x31, 0xB5, 0x72, 
+0xB5, 0x52, 0xBD, 0x73, 0xCD, 0xD4, 0xDE, 0x55, 
+0xCD, 0xD3, 0xBD, 0x71, 0xC5, 0x92, 0xCD, 0xB3, 
+0xCD, 0xD3, 0xDE, 0x35, 0xDE, 0x55, 0xDE, 0x55, 
+0xCD, 0xF4, 0xB5, 0x32, 0xA4, 0xD0, 0xAD, 0x12, 
+0xBD, 0x73, 0xC5, 0xD4, 0xCE, 0x16, 0xC5, 0xD6, 
+0x94, 0x70, 0x8C, 0x50, 0x94, 0xB2, 0x8C, 0x50, 
+0xAD, 0x33, 0xA5, 0x33, 0xA5, 0x13, 0x9C, 0xD2, 
+0x9C, 0xB2, 0x8C, 0x50, 0x6B, 0x4D, 0x4A, 0x6A, 
+0x39, 0xE7, 0x29, 0x86, 0x29, 0x45, 0x19, 0x04, 
+0x18, 0xE4, 0x29, 0x45, 0x42, 0x08, 0x4A, 0x49, 
+0x5A, 0xEC, 0x73, 0xAF, 0x8C, 0x52, 0x94, 0xB3, 
+0x9C, 0xD4, 0xB5, 0xB7, 0x9C, 0xD3, 0x9D, 0x14, 
+0x9C, 0xB3, 0x94, 0x72, 0x94, 0x92, 0x9C, 0xD4, 
+0xA5, 0x36, 0xAD, 0x76, 0xA5, 0x56, 0x9C, 0xF5, 
+0x8C, 0x93, 0x84, 0x32, 0x7C, 0x12, 0x7B, 0xF1, 
+0x73, 0xB0, 0x73, 0xD1, 0x7C, 0x12, 0x84, 0x53, 
+0x8C, 0x94, 0x84, 0x73, 0x7C, 0x12, 0x73, 0xB0, 
+0x6B, 0x8F, 0x5A, 0xED, 0x52, 0xCC, 0x52, 0xAC, 
+0x4A, 0x6B, 0x39, 0xE8, 0x31, 0xA7, 0x29, 0x87, 
+0x31, 0x65, 0x39, 0xA5, 0x39, 0xA5, 0x39, 0x85, 
+0x31, 0x85, 0x31, 0x65, 0x94, 0x51, 0xD6, 0x38, 
+0x83, 0xAE, 0x29, 0x44, 0x31, 0x65, 0x31, 0x65, 
+0x31, 0x85, 0x31, 0x85, 0x31, 0xA6, 0x39, 0xA6, 
+0x39, 0xA6, 0x21, 0x03, 0x21, 0x24, 0x21, 0x24, 
+0x73, 0xAE, 0xAD, 0x55, 0xAD, 0x75, 0xA5, 0x14, 
+0x8C, 0x51, 0x42, 0x07, 0x41, 0xC7, 0x62, 0x8A, 
+0x8B, 0x4C, 0x93, 0x6C, 0x9B, 0xAD, 0x72, 0x68, 
+0x82, 0xEA, 0xC4, 0xD0, 0xBC, 0x70, 0x93, 0x6C, 
+0x9C, 0x0F, 0xA4, 0x51, 0x6A, 0xCA, 0x20, 0xC2, 
+0x18, 0xC3, 0x18, 0xC3, 0x18, 0xE3, 0x18, 0xE3, 
+0x18, 0xC3, 0x29, 0x65, 0x42, 0x07, 0x29, 0x24, 
+0x29, 0x24, 0x4A, 0x69, 0x5A, 0xCA, 0x42, 0x07, 
+0x42, 0x08, 0x41, 0xE7, 0x39, 0xC6, 0x31, 0xA6, 
+0x31, 0xA6, 0x39, 0xA6, 0x8C, 0x72, 0xE7, 0x1D, 
+0xD6, 0x9B, 0xC6, 0x19, 0x7B, 0xD0, 0x31, 0x86, 
+0x42, 0x07, 0x4A, 0x48, 0x4A, 0x69, 0x4A, 0x28, 
+0x63, 0x0B, 0x31, 0x65, 0x31, 0xA6, 0x52, 0x8A, 
+0x42, 0x28, 0x42, 0x08, 0x5A, 0xCB, 0x8C, 0x10, 
+0xB5, 0x55, 0xBD, 0x96, 0xE6, 0xBA, 0xCD, 0xF7, 
+0x7B, 0x8D, 0x83, 0xEE, 0x63, 0x0A, 0x8C, 0x4F, 
+0xAD, 0x11, 0xAD, 0x51, 0x9C, 0x8F, 0xB5, 0x72, 
+0xBD, 0xB3, 0x94, 0x4F, 0x73, 0x8D, 0x84, 0x0F, 
+0x8C, 0x6F, 0x94, 0x6F, 0xA4, 0xF0, 0x7B, 0xAB, 
+0x9C, 0x8F, 0x94, 0x8F, 0x94, 0x6E, 0x94, 0x4E, 
+0x83, 0xEC, 0x83, 0xCC, 0x83, 0xCB, 0x83, 0xCC, 
+0x7B, 0x8B, 0x7B, 0x8A, 0x83, 0xCB, 0x83, 0x8B, 
+0x83, 0xAB, 0x83, 0xCB, 0x9C, 0x6E, 0xA4, 0x8E, 
+0x94, 0x2D, 0x7B, 0x8B, 0x73, 0x2A, 0x94, 0x2D, 
+0xAD, 0x10, 0xD6, 0x55, 0xD6, 0x55, 0xD6, 0x14, 
+0xD6, 0x14, 0xD5, 0xF4, 0xC5, 0x92, 0xB5, 0x30, 
+0xB5, 0x10, 0xAC, 0xF0, 0xA4, 0xAF, 0xAC, 0xAF, 
+0xAC, 0xCF, 0xB5, 0x10, 0xB5, 0x10, 0xBD, 0x51, 
+0xB5, 0x30, 0xB5, 0x10, 0xC5, 0x71, 0xBD, 0x31, 
+0xBD, 0x30, 0xB5, 0x10, 0xBD, 0x30, 0xBD, 0x50, 
+0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x10, 0xAC, 0xF0, 
+0xAC, 0xD0, 0xA4, 0xF0, 0x73, 0x4B, 0x63, 0x2D, 
+0x84, 0x10, 0x73, 0x8E, 0x7B, 0xAD, 0x9C, 0xB0, 
+0xA4, 0xAF, 0x9C, 0x6E, 0x9C, 0x6F, 0x94, 0x4E, 
+0x94, 0x6E, 0x83, 0xCC, 0x83, 0xED, 0x83, 0xED, 
+0x8C, 0x4E, 0x8C, 0x2E, 0x73, 0x6C, 0x6B, 0x4B, 
+0x9C, 0xB1, 0xA4, 0xF1, 0x9C, 0xD1, 0x9C, 0xB1, 
+0xBD, 0xB4, 0xB5, 0x73, 0xA5, 0x12, 0x83, 0xEE, 
+0xBD, 0xD5, 0xC5, 0xF5, 0xB5, 0x94, 0xA4, 0xF1, 
+0xA5, 0x12, 0xA4, 0xF2, 0xAD, 0x53, 0xC6, 0x16, 
+0xC6, 0x16, 0xCE, 0x36, 0xCE, 0x57, 0xC5, 0xF6, 
+0xC5, 0xF5, 0xCE, 0x57, 0x9C, 0xD1, 0x8C, 0x0E, 
+0xA5, 0x12, 0xAD, 0x32, 0xAD, 0x12, 0x94, 0x6F, 
+0x94, 0x6F, 0x9C, 0xB0, 0xA4, 0xF1, 0x9C, 0xB0, 
+0x83, 0xED, 0xAD, 0x32, 0xAD, 0x52, 0xA5, 0x12, 
+0x9C, 0xD1, 0x9C, 0xB0, 0x94, 0x8F, 0xA4, 0xF1, 
+0x94, 0x8F, 0xAD, 0x32, 0xB5, 0x72, 0xA4, 0xF0, 
+0xAD, 0x31, 0xAD, 0x11, 0xAD, 0x31, 0xB5, 0x51, 
+0xA4, 0xF0, 0xA5, 0x10, 0x9C, 0xAF, 0x94, 0x6E, 
+0x8C, 0x2D, 0x8C, 0x0D, 0x94, 0x4E, 0x83, 0xAB, 
+0xB5, 0x53, 0xB5, 0x52, 0xDD, 0xD3, 0xDD, 0xF3, 
+0xD5, 0xB3, 0xCD, 0x92, 0xC5, 0x72, 0xC5, 0x93, 
+0xBD, 0x52, 0xBD, 0x52, 0xB5, 0x31, 0xAD, 0x10, 
+0xAD, 0x11, 0xAD, 0x11, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xB5, 0x31, 0xC5, 0x92, 0xB5, 0x31, 0xBD, 0x72, 
+0xBD, 0x51, 0xC5, 0xB3, 0xC5, 0x93, 0xC5, 0xD4, 
+0xC5, 0xB3, 0xBD, 0x72, 0xDE, 0x55, 0xD5, 0xF3, 
+0xD5, 0xF4, 0xC5, 0x92, 0xC5, 0x92, 0xCD, 0x92, 
+0xC5, 0x92, 0xD6, 0x14, 0xD6, 0x14, 0xDE, 0x34, 
+0xD6, 0x14, 0xC5, 0x93, 0xB5, 0x10, 0xAC, 0xF1, 
+0xB5, 0x32, 0xCD, 0xF5, 0xBD, 0xB4, 0xD6, 0x57, 
+0xD6, 0x78, 0xBD, 0xB5, 0xAD, 0x53, 0x7B, 0xCE, 
+0x84, 0x2F, 0xA4, 0xF3, 0xAD, 0x54, 0x94, 0x91, 
+0x83, 0xEF, 0x8C, 0x50, 0x94, 0x91, 0x9C, 0xB2, 
+0x8C, 0x50, 0x7B, 0xEF, 0x73, 0x6D, 0x5A, 0xEB, 
+0x31, 0x86, 0x21, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x21, 0x05, 0x29, 0x46, 0x29, 0x87, 0x3A, 0x08, 
+0x63, 0x0D, 0x84, 0x31, 0x73, 0x8F, 0x63, 0x4D, 
+0x6B, 0x6E, 0x73, 0xAF, 0x73, 0x8F, 0x73, 0x8F, 
+0x73, 0x6E, 0x73, 0x8E, 0x6B, 0x4D, 0x73, 0xAF, 
+0x9C, 0xD4, 0x9D, 0x15, 0x9D, 0x15, 0x9C, 0xF5, 
+0x9C, 0xF4, 0x9C, 0xF4, 0x9D, 0x15, 0x9D, 0x15, 
+0x9C, 0xD5, 0x9D, 0x15, 0xA5, 0x56, 0xAD, 0x97, 
+0xB5, 0xB8, 0xB5, 0xD9, 0xB5, 0xB8, 0xA5, 0x56, 
+0x94, 0xD4, 0x84, 0x53, 0x84, 0x32, 0x7B, 0xF1, 
+0x52, 0xAA, 0x52, 0xCB, 0x52, 0xCA, 0x4A, 0x49, 
+0x29, 0x24, 0x31, 0x86, 0x7B, 0xCE, 0xCD, 0xF7, 
+0xA4, 0x71, 0x39, 0x85, 0x21, 0x04, 0x39, 0xC6, 
+0x29, 0x65, 0x21, 0x24, 0x29, 0x44, 0x39, 0xC6, 
+0x4A, 0x48, 0x31, 0xA6, 0x31, 0x86, 0x4A, 0x48, 
+0x7B, 0xAE, 0x9C, 0xB2, 0x94, 0x71, 0x9C, 0xB2, 
+0x6B, 0x0B, 0x29, 0x03, 0x29, 0x44, 0x62, 0x89, 
+0x93, 0x6C, 0x83, 0x0A, 0x93, 0x4B, 0x83, 0x0A, 
+0x41, 0x64, 0x62, 0x89, 0x6A, 0x89, 0x52, 0x48, 
+0x62, 0xCA, 0x41, 0xE7, 0x5A, 0xCA, 0x4A, 0x28, 
+0x21, 0x24, 0x29, 0x65, 0x21, 0x24, 0x21, 0x24, 
+0x21, 0x24, 0x18, 0xC3, 0x18, 0xE3, 0x29, 0x45, 
+0x21, 0x04, 0x29, 0x44, 0x39, 0xE7, 0x39, 0xC6, 
+0x39, 0xC6, 0x31, 0xA6, 0x31, 0x85, 0x29, 0x85, 
+0x31, 0x85, 0x31, 0xC6, 0xB5, 0xD7, 0xE7, 0x5E, 
+0xD6, 0xBC, 0xB5, 0x77, 0x5A, 0xCB, 0x52, 0x8A, 
+0x42, 0x28, 0x31, 0x85, 0x42, 0x07, 0x39, 0xE7, 
+0x5A, 0xEB, 0x39, 0xC7, 0x31, 0x86, 0x39, 0xE7, 
+0x42, 0x28, 0x63, 0x0C, 0x62, 0xCB, 0x7B, 0xAE, 
+0xA4, 0xB2, 0xA4, 0xB2, 0xBD, 0x75, 0xDE, 0x79, 
+0xC5, 0xF7, 0x7B, 0x8D, 0x8C, 0x50, 0xBD, 0xB6, 
+0x4A, 0x28, 0x84, 0x0E, 0xCE, 0x36, 0xD6, 0x97, 
+0xD6, 0x56, 0x94, 0x70, 0x73, 0x8D, 0x8C, 0x70, 
+0x94, 0xB1, 0x94, 0x90, 0xAD, 0x11, 0x7B, 0x6B, 
+0xA4, 0xD0, 0xA4, 0xF0, 0x94, 0x6F, 0x94, 0x4E, 
+0x8C, 0x0D, 0x8C, 0x0D, 0x83, 0xCC, 0x8C, 0x2D, 
+0x94, 0x8F, 0x9C, 0x8F, 0x8C, 0x0C, 0x8C, 0x0D, 
+0x94, 0x6E, 0x94, 0x2D, 0xAC, 0xF0, 0x94, 0x0D, 
+0x94, 0x4E, 0xAD, 0x11, 0x9C, 0xD0, 0x94, 0x6F, 
+0x8C, 0x0D, 0xA5, 0x10, 0xD6, 0x55, 0xD6, 0x35, 
+0xC5, 0xB2, 0xD6, 0x35, 0xCD, 0xF4, 0x9C, 0x8E, 
+0x9C, 0x6F, 0x94, 0x2E, 0x94, 0x4E, 0xA4, 0xAF, 
+0xB5, 0x11, 0xAC, 0xF0, 0xB5, 0x52, 0xB5, 0x31, 
+0xCE, 0x14, 0xCD, 0xD3, 0xBD, 0x51, 0x94, 0x0C, 
+0x9C, 0x8E, 0xAD, 0x10, 0xAC, 0xCF, 0xAC, 0xEF, 
+0xB5, 0x51, 0xAC, 0xCF, 0x94, 0x4D, 0x8C, 0x0C, 
+0x94, 0x2D, 0xAC, 0xD0, 0xA4, 0xF2, 0x9C, 0xB3, 
+0x9C, 0xF3, 0x84, 0x0F, 0x8C, 0x0E, 0xA4, 0xD0, 
+0xA4, 0xAF, 0xA4, 0x8F, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xAC, 0xF0, 0xBD, 0x73, 0xB5, 0x32, 
+0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x53, 0xB5, 0x94, 
+0xBD, 0xD5, 0xB5, 0xB4, 0xBD, 0x94, 0xB5, 0x94, 
+0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x33, 0xAD, 0x33, 
+0xA4, 0xD1, 0x94, 0x90, 0x94, 0x4F, 0x9C, 0x90, 
+0xA4, 0xD1, 0xA4, 0xD1, 0x9C, 0xB1, 0xA4, 0xD1, 
+0x9C, 0xB0, 0x9C, 0xB1, 0xA4, 0xF1, 0x9C, 0xB0, 
+0x94, 0x6F, 0x94, 0x70, 0x83, 0xED, 0x73, 0x6C, 
+0xA4, 0xD1, 0x8C, 0x0E, 0x8C, 0x0E, 0x7B, 0xAC, 
+0x7B, 0xAC, 0x7B, 0xAC, 0x83, 0xED, 0x84, 0x0E, 
+0x6B, 0x4B, 0x73, 0x6B, 0x9C, 0xB0, 0x8C, 0x2E, 
+0x62, 0xEA, 0x84, 0x0E, 0x8C, 0x4E, 0xAD, 0x32, 
+0xB5, 0x53, 0xB5, 0x93, 0xBD, 0x93, 0xAD, 0x11, 
+0xBD, 0x93, 0xBD, 0x93, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xBD, 0x92, 0xB5, 0x51, 0xA4, 0xF0, 0x94, 0x8E, 
+0x84, 0x0C, 0x7B, 0x8B, 0x7B, 0xAB, 0x83, 0xCC, 
+0xB5, 0x73, 0xAD, 0x11, 0xDE, 0x56, 0xCD, 0xB3, 
+0xBD, 0x51, 0xB5, 0x31, 0xB5, 0x31, 0xBD, 0x52, 
+0xB5, 0x31, 0xB5, 0x52, 0xB5, 0x72, 0xBD, 0x93, 
+0xB5, 0x72, 0xBD, 0x93, 0xB5, 0x52, 0xBD, 0x72, 
+0xC5, 0xB3, 0xCD, 0xD3, 0xC5, 0x93, 0xCD, 0xF4, 
+0xBD, 0x72, 0xB5, 0x51, 0xB5, 0x51, 0xAD, 0x10, 
+0xA4, 0xAF, 0xB5, 0x11, 0xCD, 0xF4, 0xD6, 0x14, 
+0xDE, 0x55, 0xD6, 0x14, 0xCD, 0xB2, 0xD5, 0xD3, 
+0xC5, 0x71, 0xCD, 0xB3, 0xDE, 0x55, 0xD5, 0xF3, 
+0xD5, 0xF3, 0xD5, 0xF3, 0xBD, 0x51, 0xA4, 0xAF, 
+0xB5, 0x31, 0xC5, 0xF4, 0xD6, 0x56, 0xDE, 0xB7, 
+0xC5, 0xF5, 0xA4, 0xF1, 0xDE, 0xB8, 0xCE, 0x37, 
+0x94, 0x91, 0x7B, 0xCE, 0x83, 0xEF, 0x84, 0x2F, 
+0x7B, 0xCF, 0x7B, 0xCE, 0x84, 0x0F, 0x9C, 0xB2, 
+0xA5, 0x33, 0x9C, 0xD2, 0x94, 0x71, 0x84, 0x30, 
+0x63, 0x2C, 0x39, 0xE8, 0x29, 0x66, 0x21, 0x25, 
+0x18, 0xE4, 0x10, 0xC4, 0x18, 0xE4, 0x21, 0x25, 
+0x29, 0x87, 0x42, 0x29, 0x6B, 0x6E, 0x9C, 0xF4, 
+0xA5, 0x35, 0xA5, 0x15, 0x9C, 0xF5, 0x94, 0x93, 
+0x84, 0x32, 0x7C, 0x11, 0x73, 0xAF, 0x6B, 0x4E, 
+0x63, 0x0C, 0x6B, 0x6E, 0x84, 0x31, 0x7B, 0xCF, 
+0x6B, 0x2C, 0x83, 0xCF, 0x9C, 0xD3, 0x94, 0x93, 
+0x94, 0x93, 0x9C, 0xD4, 0xA5, 0x15, 0x9C, 0xF5, 
+0x94, 0xD4, 0x9C, 0xF4, 0xA5, 0x36, 0xAD, 0x77, 
+0xB5, 0xB8, 0xB5, 0xB8, 0xAD, 0x77, 0x9D, 0x15, 
+0xAD, 0x96, 0xAD, 0x96, 0xAD, 0x76, 0xA5, 0x55, 
+0x8C, 0x72, 0x7C, 0x10, 0x73, 0x4D, 0xCD, 0xD6, 
+0x8B, 0xAE, 0x62, 0xEB, 0x5A, 0xEB, 0x73, 0xAE, 
+0x73, 0x8D, 0x73, 0x6D, 0x7B, 0xAE, 0x84, 0x2F, 
+0x8C, 0x30, 0x84, 0x0F, 0x6B, 0x4C, 0x73, 0x8D, 
+0x39, 0xA6, 0x31, 0x65, 0x62, 0xCA, 0x5A, 0x69, 
+0x52, 0x69, 0x39, 0xC7, 0x5A, 0xAA, 0x72, 0xEB, 
+0x8B, 0x4C, 0x82, 0xEA, 0x82, 0xEA, 0x8B, 0x0B, 
+0x62, 0x68, 0x83, 0xAD, 0x8B, 0xCD, 0x94, 0x0E, 
+0x8B, 0xED, 0x7B, 0x8D, 0x8C, 0x2F, 0x83, 0xEE, 
+0x62, 0xEB, 0x4A, 0x69, 0x31, 0xA6, 0x21, 0x03, 
+0x29, 0x44, 0x29, 0x45, 0x21, 0x24, 0x29, 0x65, 
+0x21, 0x24, 0x21, 0x03, 0x29, 0x44, 0x29, 0x64, 
+0x29, 0x44, 0x29, 0x65, 0x29, 0x44, 0x29, 0x24, 
+0x29, 0x44, 0x63, 0x0C, 0xE7, 0x3D, 0xDE, 0xDC, 
+0xAD, 0x35, 0x9C, 0xB3, 0xA5, 0x14, 0x7B, 0xEF, 
+0x39, 0xA6, 0x21, 0x24, 0x4A, 0x48, 0x41, 0xE7, 
+0x4A, 0x28, 0x31, 0xA6, 0x42, 0x08, 0x5A, 0xEB, 
+0x5A, 0xEB, 0x6B, 0x2D, 0x83, 0xEF, 0x94, 0x71, 
+0xAD, 0x13, 0xA4, 0xB2, 0xBD, 0x55, 0xC5, 0x96, 
+0xDE, 0x9A, 0xC5, 0xD7, 0xAD, 0x55, 0xEF, 0x7D, 
+0xC6, 0x18, 0x39, 0xC7, 0x52, 0x68, 0x7B, 0xCD, 
+0x7B, 0xAD, 0x8C, 0x2F, 0x73, 0x8D, 0x9C, 0xD2, 
+0xA5, 0x53, 0xB5, 0x73, 0xAC, 0xF1, 0x8C, 0x2E, 
+0xAD, 0x11, 0xA4, 0xF1, 0x94, 0x8F, 0x94, 0x4E, 
+0x8C, 0x0D, 0x8C, 0x2D, 0x83, 0xED, 0x8C, 0x0D, 
+0x9C, 0xB0, 0x9C, 0xB0, 0x8C, 0x0D, 0x83, 0xEC, 
+0x94, 0x6E, 0x9C, 0x8F, 0xB5, 0x31, 0x8C, 0x0C, 
+0xB5, 0x93, 0xC6, 0x15, 0xB5, 0x93, 0xBD, 0xB4, 
+0xAD, 0x32, 0x7B, 0xCC, 0xB5, 0x93, 0xCE, 0x35, 
+0xB5, 0x72, 0xAD, 0x11, 0xA4, 0xD0, 0xBD, 0x94, 
+0xBD, 0xD4, 0xBD, 0xD4, 0xB5, 0x93, 0xA5, 0x11, 
+0xC5, 0xD4, 0x8C, 0x0E, 0x7B, 0xAC, 0x8C, 0x4F, 
+0xAD, 0x32, 0xAC, 0xEF, 0xC5, 0x51, 0x83, 0x6A, 
+0x8C, 0x6F, 0xB5, 0x93, 0x8C, 0x4E, 0x94, 0x6F, 
+0x9C, 0xB0, 0x94, 0x4E, 0x9C, 0x90, 0x94, 0x4E, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xB5, 0x54, 0xA5, 0x35, 
+0xA5, 0x14, 0x84, 0x10, 0x6B, 0x4B, 0x94, 0x4E, 
+0xAD, 0x11, 0xAD, 0x11, 0xBD, 0xB3, 0xBD, 0x93, 
+0xBD, 0x72, 0xA4, 0xAF, 0x9C, 0x6F, 0x73, 0x6C, 
+0x63, 0x0B, 0x62, 0xEA, 0x6B, 0x2B, 0x83, 0xEE, 
+0x9C, 0x90, 0xA4, 0xF1, 0x94, 0x6F, 0x83, 0xEE, 
+0x8C, 0x2E, 0x94, 0x70, 0x94, 0x70, 0x94, 0x4F, 
+0xAD, 0x12, 0x9C, 0x90, 0x9C, 0xB1, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xA4, 0xD1, 0xA4, 0xF2, 
+0xA4, 0xF2, 0xAD, 0x12, 0xAD, 0x32, 0xA4, 0xF1, 
+0xAD, 0x33, 0xB5, 0x53, 0xBD, 0x94, 0xAD, 0x53, 
+0xBD, 0x94, 0xB5, 0x74, 0xBD, 0x94, 0xB5, 0x74, 
+0xB5, 0x94, 0xB5, 0x74, 0xBD, 0x95, 0xBD, 0xB5, 
+0xB5, 0x94, 0xA5, 0x12, 0xA4, 0xD2, 0xAD, 0x13, 
+0xB5, 0x74, 0xAD, 0x33, 0xA4, 0xF1, 0xA4, 0xD1, 
+0xA4, 0xF1, 0xA4, 0xF1, 0x9C, 0x90, 0x94, 0x6F, 
+0x94, 0x4E, 0x94, 0x4E, 0x94, 0x8F, 0x9C, 0x8F, 
+0xA4, 0xD0, 0xA4, 0xF0, 0xB5, 0x52, 0xAD, 0x31, 
+0xA4, 0xD0, 0x9C, 0x8F, 0x73, 0x6A, 0x73, 0x4B, 
+0xB5, 0x53, 0xAD, 0x12, 0xAD, 0x12, 0xAD, 0x32, 
+0xAD, 0x32, 0xAC, 0xF1, 0xA4, 0xB0, 0x9C, 0xB0, 
+0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0x8F, 0x9C, 0xB0, 
+0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x90, 0x9C, 0x6F, 
+0x9C, 0xB0, 0x9C, 0x8F, 0x94, 0x4E, 0xA4, 0xB0, 
+0x9C, 0x8F, 0x9C, 0x6E, 0xA4, 0xD0, 0xB5, 0x52, 
+0x8C, 0x0D, 0xB5, 0x32, 0x9C, 0x6E, 0xAD, 0x11, 
+0xB5, 0x11, 0xB5, 0x11, 0xB4, 0xF0, 0xB5, 0x11, 
+0xAC, 0xCF, 0xA4, 0xAF, 0xB5, 0x11, 0xBD, 0x51, 
+0xBD, 0x31, 0xC5, 0x71, 0xCD, 0xD3, 0xA4, 0xAF, 
+0xAC, 0xD0, 0xB5, 0x31, 0xBD, 0x93, 0xD6, 0x56, 
+0xE6, 0xD8, 0xDE, 0xB8, 0xD6, 0x77, 0xC5, 0xD5, 
+0xAD, 0x13, 0x8C, 0x50, 0x8C, 0x70, 0xBD, 0xF6, 
+0xC5, 0xF6, 0xA5, 0x33, 0x7B, 0xCE, 0x9C, 0xD2, 
+0xB5, 0x74, 0xB5, 0x74, 0xAD, 0x54, 0x9C, 0xD2, 
+0x8C, 0x50, 0x73, 0xAE, 0x63, 0x0B, 0x4A, 0x8A, 
+0x42, 0x08, 0x31, 0x86, 0x21, 0x25, 0x21, 0x04, 
+0x18, 0xE4, 0x21, 0x04, 0x31, 0xA7, 0x52, 0x8A, 
+0x73, 0xCF, 0x84, 0x11, 0x8C, 0x93, 0x94, 0xB4, 
+0x9C, 0xF5, 0x9C, 0xF5, 0x9D, 0x15, 0xA5, 0x15, 
+0x9D, 0x15, 0x94, 0x93, 0x84, 0x10, 0x6B, 0x4D, 
+0x6B, 0x2C, 0x73, 0x4C, 0x8C, 0x2F, 0xA4, 0xF3, 
+0x9C, 0x91, 0x8C, 0x0F, 0x83, 0xCF, 0x83, 0xCE, 
+0x7B, 0xCE, 0x7B, 0xCE, 0x7B, 0xCF, 0x7B, 0xCF, 
+0x7C, 0x10, 0x84, 0x32, 0x8C, 0x93, 0x9C, 0xF5, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x35, 
+0x9D, 0x14, 0x8C, 0x92, 0x52, 0x8A, 0x8B, 0xCE, 
+0x6B, 0x0B, 0x6B, 0x2C, 0x73, 0x8D, 0x73, 0xAD, 
+0x73, 0x8D, 0x83, 0xEE, 0x84, 0x0E, 0x8C, 0x4F, 
+0x94, 0x70, 0x94, 0x90, 0x94, 0x70, 0x83, 0xCD, 
+0x31, 0x65, 0x39, 0xC6, 0x31, 0x85, 0x6B, 0x2B, 
+0x73, 0x4B, 0x6B, 0x2B, 0x73, 0x4C, 0x5A, 0x68, 
+0x7A, 0xEB, 0x7A, 0xCA, 0x82, 0xEB, 0x7A, 0xEA, 
+0x5A, 0x07, 0x62, 0xA9, 0x83, 0x8C, 0x83, 0xAD, 
+0x8B, 0xEE, 0x8B, 0xEE, 0x94, 0x4F, 0x8B, 0xED, 
+0x83, 0xED, 0x8C, 0x0E, 0x8C, 0x2E, 0x7B, 0x8C, 
+0x4A, 0x07, 0x31, 0x85, 0x29, 0x65, 0x29, 0x44, 
+0x29, 0x65, 0x21, 0x24, 0x19, 0x03, 0x21, 0x24, 
+0x21, 0x03, 0x21, 0x03, 0x21, 0x03, 0x19, 0x03, 
+0x21, 0x45, 0xAD, 0x76, 0xE7, 0x1D, 0xBD, 0xD8, 
+0x5A, 0xAB, 0x6B, 0x4D, 0xA5, 0x35, 0x8C, 0x51, 
+0x42, 0x08, 0x42, 0x28, 0x84, 0x30, 0x39, 0xC7, 
+0x42, 0x07, 0x4A, 0x69, 0x4A, 0x49, 0x4A, 0x69, 
+0x52, 0x8A, 0x4A, 0x6A, 0x4A, 0x29, 0x5A, 0xCB, 
+0x7B, 0xAE, 0x83, 0xCF, 0x6B, 0x0C, 0xA4, 0x92, 
+0xC5, 0x95, 0xA4, 0xB2, 0x84, 0x10, 0xD6, 0xBA, 
+0xE7, 0x3C, 0x9C, 0xD3, 0x39, 0x66, 0x62, 0xCA, 
+0xBD, 0xB6, 0x8C, 0x50, 0x6B, 0x6D, 0x94, 0xD2, 
+0xA5, 0x54, 0xBD, 0xB4, 0xA4, 0xD0, 0x9C, 0x8F, 
+0xA5, 0x11, 0x9C, 0xB0, 0x9C, 0x8F, 0x9C, 0x8F, 
+0x8C, 0x2E, 0x8C, 0x2E, 0x8C, 0x0D, 0x83, 0xCC, 
+0x8C, 0x0D, 0x94, 0x6F, 0x8C, 0x2E, 0x83, 0xEC, 
+0x94, 0x6E, 0x9C, 0x6E, 0xB5, 0x31, 0x83, 0xAB, 
+0xAD, 0x52, 0xC5, 0xD5, 0xBD, 0xB4, 0xC6, 0x16, 
+0xBD, 0xB4, 0x83, 0xCD, 0x7B, 0xAD, 0x84, 0x0E, 
+0x83, 0xED, 0x84, 0x0E, 0xB5, 0x93, 0xC6, 0x15, 
+0xC6, 0x16, 0xC5, 0xF5, 0xCE, 0x36, 0xC6, 0x15, 
+0xBD, 0xD4, 0x73, 0xAC, 0x6B, 0x4B, 0x73, 0x8C, 
+0x94, 0x6F, 0xA4, 0xAF, 0xC5, 0x71, 0x83, 0x6B, 
+0x9C, 0xD1, 0xB5, 0x93, 0x94, 0x6F, 0x9C, 0xD0, 
+0x8C, 0x4E, 0x94, 0x8F, 0xA5, 0x12, 0x9C, 0xB0, 
+0x9C, 0xD1, 0x9C, 0xD1, 0xB5, 0x95, 0xAD, 0x96, 
+0xA5, 0x35, 0x94, 0x92, 0x73, 0x8D, 0x94, 0x70, 
+0xB5, 0x52, 0xAD, 0x11, 0xB5, 0x52, 0xAD, 0x31, 
+0xAD, 0x52, 0xA4, 0xB0, 0xA4, 0xB0, 0x73, 0x6C, 
+0x8C, 0x2F, 0x94, 0x70, 0x84, 0x0E, 0x83, 0xEE, 
+0x8C, 0x4F, 0x94, 0x4F, 0x7B, 0xCD, 0x73, 0x4C, 
+0x94, 0x70, 0xAD, 0x32, 0x9C, 0xD1, 0x9C, 0x90, 
+0xA4, 0xD1, 0x9C, 0x90, 0xA4, 0xF2, 0xA4, 0xD1, 
+0xA4, 0xD1, 0x8C, 0x2F, 0x8C, 0x2F, 0x8C, 0x4F, 
+0x8C, 0x2E, 0x94, 0x70, 0xA4, 0xF2, 0x9C, 0x90, 
+0xAD, 0x12, 0x8C, 0x0E, 0x8C, 0x0E, 0xA4, 0xF2, 
+0xAD, 0x12, 0xAD, 0x33, 0xB5, 0x74, 0xB5, 0x94, 
+0xAD, 0x33, 0xAD, 0x33, 0xAD, 0x33, 0xA4, 0xF2, 
+0x9C, 0xB1, 0xAD, 0x12, 0xAD, 0x33, 0xB5, 0x74, 
+0xA5, 0x12, 0xAD, 0x53, 0x9C, 0xD1, 0x9C, 0x90, 
+0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x33, 0xAD, 0x32, 
+0xAD, 0x32, 0xB5, 0x73, 0xBD, 0xB5, 0xBD, 0x94, 
+0xBD, 0xB4, 0xAD, 0x12, 0xA4, 0xD0, 0xB5, 0x73, 
+0xAC, 0xF1, 0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x32, 
+0xAD, 0x33, 0xAD, 0x33, 0xBD, 0x94, 0xC5, 0xD5, 
+0xBD, 0xB5, 0xC5, 0xF5, 0xC5, 0xF5, 0xC5, 0xF6, 
+0xC5, 0xF5, 0xC5, 0xF5, 0xC5, 0xF5, 0xC5, 0xD5, 
+0xC5, 0xD5, 0xC5, 0xF5, 0xC5, 0xD5, 0xC5, 0xF6, 
+0xCD, 0xF5, 0xC5, 0xD5, 0xC5, 0xD5, 0xCD, 0xF6, 
+0xC5, 0xF5, 0xBD, 0xB4, 0xB5, 0x53, 0xB5, 0x53, 
+0xBD, 0x74, 0xC5, 0xF5, 0xBD, 0x94, 0xB5, 0x53, 
+0xBD, 0x73, 0xBD, 0x73, 0xBD, 0x74, 0xBD, 0x73, 
+0xBD, 0x73, 0xB5, 0x73, 0xAD, 0x12, 0xA4, 0xF1, 
+0xAD, 0x11, 0xAC, 0xF1, 0xA4, 0xAF, 0xA4, 0x8F, 
+0x9C, 0x6F, 0x94, 0x4E, 0x94, 0x4E, 0x94, 0x4F, 
+0x9C, 0x90, 0xAD, 0x12, 0xB5, 0x32, 0xA4, 0xB0, 
+0xA4, 0xF1, 0xA4, 0xF2, 0x7B, 0xCE, 0x83, 0xEE, 
+0xA4, 0xF1, 0xBD, 0xD5, 0x83, 0xEE, 0x9C, 0xD2, 
+0x9C, 0xD1, 0x9C, 0xD2, 0xAD, 0x33, 0xB5, 0x74, 
+0xAD, 0x13, 0x9C, 0xD2, 0x94, 0x91, 0x8C, 0x50, 
+0x84, 0x30, 0x7B, 0xEF, 0x6B, 0x6E, 0x5A, 0xCB, 
+0x39, 0xE8, 0x29, 0x45, 0x21, 0x05, 0x19, 0x04, 
+0x18, 0xE4, 0x21, 0x45, 0x42, 0x08, 0x5A, 0xCB, 
+0x6B, 0x4E, 0x7B, 0xD0, 0x7C, 0x10, 0x7C, 0x11, 
+0x84, 0x31, 0x8C, 0x72, 0x94, 0x92, 0x9C, 0xB3, 
+0x9C, 0xD2, 0x9C, 0xB2, 0x8C, 0x0F, 0x7B, 0xAD, 
+0x7B, 0x8C, 0x8B, 0xCE, 0x6B, 0x0B, 0x7B, 0x6C, 
+0x7B, 0xAD, 0x7B, 0x6C, 0x73, 0x4B, 0x63, 0x2B, 
+0x6B, 0x2D, 0x7B, 0xF0, 0x7B, 0xF0, 0x84, 0x32, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x35, 0xA5, 0x34, 
+0x9C, 0xF4, 0x8C, 0x51, 0x41, 0xE7, 0x42, 0x07, 
+0x52, 0x68, 0x63, 0x0B, 0x6B, 0x4B, 0x7B, 0xAD, 
+0x84, 0x0E, 0x8C, 0x4F, 0x94, 0x4F, 0x8C, 0x0E, 
+0x8C, 0x2D, 0x9C, 0x8E, 0x9C, 0x8E, 0x94, 0x2D, 
+0x73, 0x2B, 0x73, 0x4B, 0x5A, 0x88, 0x9C, 0x8F, 
+0xA4, 0xB0, 0xA4, 0x8F, 0xA4, 0x8F, 0x62, 0xAA, 
+0x5A, 0x28, 0x6A, 0x69, 0x72, 0x8A, 0x7A, 0xCA, 
+0x6A, 0x8A, 0x62, 0x89, 0x72, 0xEB, 0x83, 0x8D, 
+0x83, 0x8D, 0xA4, 0x90, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xB5, 0x11, 0xB5, 0x31, 0xB5, 0x11, 0xB5, 0x31, 
+0xA4, 0xD0, 0x4A, 0x27, 0x29, 0x65, 0x29, 0x65, 
+0x31, 0x65, 0x29, 0x44, 0x29, 0x65, 0x21, 0x24, 
+0x21, 0x24, 0x19, 0x03, 0x18, 0xE3, 0x29, 0x87, 
+0x94, 0xB4, 0xE7, 0x3E, 0xCE, 0x5A, 0x9C, 0xD4, 
+0x39, 0xC8, 0x9C, 0xD3, 0xBD, 0xF7, 0x84, 0x31, 
+0x84, 0x10, 0x9C, 0xF4, 0xA4, 0xF4, 0x42, 0x29, 
+0x7B, 0xCF, 0xBD, 0xD7, 0xBD, 0xF8, 0xB5, 0x96, 
+0x84, 0x10, 0x52, 0x8A, 0x52, 0xAA, 0x5A, 0xEB, 
+0x39, 0xC7, 0x52, 0x8A, 0x62, 0xCB, 0x5A, 0xAA, 
+0xA4, 0x91, 0x62, 0xAA, 0x73, 0x6E, 0xBD, 0xF8, 
+0xD6, 0x9A, 0xC6, 0x39, 0x6B, 0x0C, 0xC5, 0xF6, 
+0xC5, 0xF6, 0x8C, 0x30, 0x6B, 0x6D, 0x8C, 0x71, 
+0xB5, 0x94, 0xB5, 0x93, 0xA4, 0xD0, 0x9C, 0xAF, 
+0xB5, 0x93, 0xB5, 0x52, 0xA4, 0xF0, 0xA4, 0xD0, 
+0xA4, 0xF0, 0xA4, 0xF0, 0x83, 0xCC, 0x83, 0xEC, 
+0x8C, 0x4E, 0xA4, 0xF0, 0x8C, 0x2E, 0x8C, 0x0D, 
+0x84, 0x0C, 0x94, 0x6E, 0xB5, 0x10, 0x7B, 0x8B, 
+0xB5, 0x93, 0xBD, 0xD4, 0xBD, 0xD5, 0xC6, 0x16, 
+0xBD, 0xD4, 0x8C, 0x2E, 0x7B, 0xCD, 0x84, 0x0E, 
+0x83, 0xED, 0x94, 0x6F, 0xAD, 0x53, 0xC6, 0x15, 
+0xCE, 0x36, 0xC6, 0x15, 0xC6, 0x35, 0xCE, 0x36, 
+0xBD, 0xD4, 0x8C, 0x4F, 0x73, 0x8C, 0x73, 0xAC, 
+0x7B, 0x8C, 0xA4, 0xB0, 0xBD, 0x51, 0x7B, 0x4A, 
+0x9C, 0xD1, 0xB5, 0x73, 0x94, 0xB0, 0xAD, 0x32, 
+0xA5, 0x11, 0x9C, 0xD1, 0xA5, 0x32, 0x9C, 0xD0, 
+0x9C, 0xD1, 0x9C, 0xD1, 0xB5, 0xB6, 0xAD, 0x55, 
+0xA5, 0x15, 0x94, 0x92, 0x6B, 0x6C, 0x9D, 0x12, 
+0xAD, 0x73, 0xAD, 0x73, 0xB5, 0x73, 0xAD, 0x52, 
+0xB5, 0x94, 0x8C, 0x2E, 0xA4, 0xF1, 0x83, 0xCD, 
+0x83, 0xEE, 0x8C, 0x4F, 0x84, 0x0E, 0x83, 0xEE, 
+0x8C, 0x2F, 0x83, 0xEE, 0x7B, 0xAD, 0x7B, 0xAD, 
+0xA4, 0xF2, 0xAD, 0x53, 0xA5, 0x12, 0xAD, 0x73, 
+0xA5, 0x12, 0xA4, 0xF2, 0xA4, 0xF2, 0xA5, 0x12, 
+0xAD, 0x73, 0xA5, 0x32, 0xA5, 0x12, 0xA5, 0x32, 
+0x94, 0x70, 0x84, 0x0E, 0xA4, 0xD1, 0xA4, 0xD1, 
+0x9C, 0xB1, 0x9C, 0xB1, 0xB5, 0x94, 0xBD, 0x94, 
+0xAD, 0x53, 0xB5, 0x53, 0xB5, 0x73, 0xBD, 0xB4, 
+0xB5, 0x94, 0xB5, 0x73, 0xAD, 0x53, 0xA4, 0xF1, 
+0xAD, 0x12, 0xB5, 0x74, 0xAD, 0x12, 0xAD, 0x53, 
+0x9C, 0x90, 0xAC, 0xF2, 0x83, 0xCD, 0x8C, 0x0E, 
+0x84, 0x0E, 0x6B, 0x2B, 0x8C, 0x4F, 0x8C, 0x2E, 
+0x84, 0x0E, 0x9C, 0x90, 0x9C, 0xB0, 0x8C, 0x2E, 
+0x9C, 0xD1, 0x94, 0x6F, 0x84, 0x0E, 0x84, 0x0D, 
+0x83, 0xCD, 0x83, 0xCC, 0x94, 0x6E, 0xA4, 0xAF, 
+0x94, 0x4E, 0x94, 0x6E, 0x94, 0x2E, 0x7B, 0x8B, 
+0x8C, 0x0D, 0x8C, 0x2D, 0x8C, 0x2D, 0x94, 0x2E, 
+0x8C, 0x2D, 0x83, 0xCC, 0x8C, 0x2E, 0xB5, 0x52, 
+0x94, 0x6F, 0x8C, 0x2E, 0x8C, 0x0D, 0x94, 0x4E, 
+0x9C, 0x8F, 0x9C, 0xB0, 0x9C, 0x90, 0x94, 0x4F, 
+0xA4, 0xD0, 0xAD, 0x11, 0xAD, 0x12, 0xAC, 0xF1, 
+0xAC, 0xF2, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x12, 
+0xAC, 0xF2, 0xB5, 0x32, 0xB5, 0x53, 0xB5, 0x53, 
+0xB5, 0x32, 0xBD, 0x73, 0xC5, 0xD5, 0xCE, 0x16, 
+0xCE, 0x36, 0xBD, 0x73, 0xAC, 0xF1, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x12, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x11, 0xAD, 0x11, 
+0xB5, 0x32, 0xB5, 0x53, 0xB5, 0x74, 0xB5, 0x53, 
+0xA4, 0xF2, 0x94, 0x4F, 0x94, 0x90, 0xA5, 0x12, 
+0xAD, 0x13, 0xA5, 0x13, 0x94, 0x70, 0x8C, 0x0F, 
+0x94, 0x70, 0xA4, 0xF2, 0xB5, 0x54, 0xB5, 0x74, 
+0xAD, 0x33, 0xA4, 0xF3, 0x9C, 0xD2, 0x94, 0x92, 
+0x8C, 0x71, 0x73, 0xAE, 0x5A, 0xEB, 0x42, 0x08, 
+0x29, 0x66, 0x21, 0x45, 0x21, 0x45, 0x29, 0x45, 
+0x29, 0x45, 0x31, 0xA7, 0x42, 0x49, 0x5A, 0xEC, 
+0x63, 0x2D, 0x7C, 0x11, 0x84, 0x31, 0x7C, 0x11, 
+0x73, 0xAE, 0x73, 0x8E, 0x7B, 0xCF, 0x83, 0xEF, 
+0x83, 0xEF, 0x8C, 0x10, 0x73, 0x6D, 0x52, 0x89, 
+0x6B, 0x2B, 0x7B, 0x6C, 0x7B, 0x8C, 0x52, 0x89, 
+0x52, 0x6A, 0x5A, 0xCB, 0x73, 0x6D, 0x7B, 0xD0, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x55, 0x9D, 0x14, 
+0x9C, 0xF4, 0x84, 0x51, 0x4A, 0x28, 0x7B, 0xCD, 
+0x8C, 0x2E, 0x9C, 0xB0, 0x94, 0x8F, 0x9C, 0x8F, 
+0xB5, 0x72, 0xBD, 0xB3, 0xC5, 0xD3, 0xBD, 0xB2, 
+0xBD, 0x51, 0xC5, 0xB2, 0xC5, 0xB2, 0xBD, 0x71, 
+0xBD, 0x71, 0xBD, 0x51, 0xBD, 0x71, 0xBD, 0x92, 
+0xBD, 0x72, 0xBD, 0x72, 0xBD, 0x51, 0x94, 0x2E, 
+0x6B, 0x0B, 0x5A, 0x28, 0x62, 0x69, 0x72, 0xAA, 
+0x7A, 0xEB, 0x72, 0xCB, 0x83, 0x6D, 0x8B, 0xCE, 
+0x83, 0x8C, 0x9C, 0x6F, 0xA4, 0x8F, 0xA4, 0xAF, 
+0x9C, 0x6E, 0xA4, 0x8F, 0xA4, 0x8F, 0xA4, 0xAF, 
+0xAC, 0xF0, 0x8C, 0x0E, 0x39, 0xA5, 0x31, 0x85, 
+0x29, 0x24, 0x29, 0x65, 0x29, 0x64, 0x29, 0x64, 
+0x29, 0x64, 0x52, 0xAB, 0xA5, 0x15, 0xD6, 0xBC, 
+0xE7, 0x3E, 0xCE, 0x7A, 0xAD, 0x15, 0x6B, 0x2D, 
+0x7B, 0xCF, 0xA5, 0x14, 0xB5, 0x96, 0xA5, 0x34, 
+0xAD, 0x76, 0xA5, 0x35, 0x94, 0x92, 0x5A, 0xEB, 
+0x7B, 0xEF, 0x6B, 0x6D, 0x63, 0x0C, 0x6B, 0x4D, 
+0x6B, 0x2C, 0x4A, 0x49, 0x63, 0x2C, 0x83, 0xF0, 
+0x4A, 0x49, 0x42, 0x08, 0x39, 0xA7, 0x52, 0x69, 
+0x73, 0x6D, 0x62, 0xEC, 0x84, 0x31, 0xA5, 0x35, 
+0xBD, 0xF8, 0xD6, 0x7A, 0xA5, 0x34, 0xAD, 0x34, 
+0xC6, 0x17, 0xC5, 0xF8, 0x84, 0x10, 0xAD, 0x54, 
+0xBD, 0xD5, 0xB5, 0x73, 0xAC, 0xF0, 0xA4, 0xF0, 
+0xBD, 0x93, 0xBD, 0xB3, 0xAD, 0x32, 0x9C, 0xAF, 
+0x94, 0x6E, 0xA4, 0xD0, 0x9C, 0x8F, 0x8C, 0x2D, 
+0x94, 0x6F, 0xA4, 0xD0, 0x94, 0x6F, 0x9C, 0x8F, 
+0x94, 0x6E, 0x94, 0x8F, 0xAC, 0xF0, 0x83, 0xAC, 
+0xA5, 0x32, 0xC6, 0x15, 0xC5, 0xF5, 0xCE, 0x36, 
+0xC5, 0xF5, 0x7B, 0xCD, 0x83, 0xED, 0x7B, 0xAC, 
+0x8C, 0x6F, 0xA4, 0xF1, 0xBD, 0xB4, 0xCE, 0x36, 
+0xC6, 0x35, 0xCE, 0x56, 0xCE, 0x56, 0xC5, 0xF5, 
+0xAD, 0x53, 0x8C, 0x4F, 0x7B, 0xCD, 0x6B, 0x2B, 
+0x6B, 0x6C, 0x83, 0xEC, 0xBD, 0x51, 0x73, 0x2A, 
+0xA4, 0xF2, 0xAD, 0x32, 0x9C, 0xB0, 0xAD, 0x32, 
+0x94, 0x6F, 0x8C, 0x4E, 0xBD, 0xB4, 0xA4, 0xF1, 
+0x9C, 0xD1, 0x9C, 0xF2, 0xBD, 0xD6, 0xAD, 0x55, 
+0xA5, 0x14, 0x9C, 0xD3, 0x7B, 0xCE, 0x9D, 0x12, 
+0xAD, 0x94, 0xB5, 0x94, 0xB5, 0x94, 0xB5, 0x93, 
+0xBD, 0xD5, 0x94, 0x6F, 0xAD, 0x32, 0x8C, 0x2E, 
+0x8C, 0x4F, 0x94, 0x90, 0x94, 0x70, 0x84, 0x0E, 
+0x9C, 0x90, 0x83, 0xED, 0x83, 0xEE, 0x7B, 0xCE, 
+0x9C, 0xB1, 0xA5, 0x12, 0x9C, 0xD1, 0xAD, 0x53, 
+0x9C, 0xD1, 0x94, 0x90, 0x9C, 0xD1, 0xA4, 0xF2, 
+0xB5, 0x74, 0xA4, 0xF2, 0x9C, 0xF1, 0xAD, 0x53, 
+0x94, 0x90, 0x8C, 0x2F, 0xA4, 0xF2, 0xA4, 0xF1, 
+0x9C, 0x90, 0xAD, 0x53, 0xA4, 0xF1, 0x9C, 0xB0, 
+0xA5, 0x12, 0xAD, 0x32, 0xCE, 0x36, 0xCE, 0x16, 
+0xC6, 0x16, 0xC6, 0x15, 0xC5, 0xD4, 0xBD, 0xB4, 
+0xC5, 0xF5, 0xCE, 0x36, 0xC6, 0x15, 0xC5, 0xD5, 
+0x9C, 0xD1, 0xB5, 0x53, 0xA5, 0x12, 0x84, 0x0E, 
+0x6B, 0x4B, 0x84, 0x2E, 0xA4, 0xF1, 0x9C, 0xD0, 
+0x9C, 0xD0, 0x9C, 0xD0, 0x94, 0x6F, 0x83, 0xED, 
+0x9C, 0xD1, 0xA5, 0x11, 0xAD, 0x52, 0xAD, 0x52, 
+0x9C, 0x8F, 0x9C, 0xB0, 0xBD, 0xB2, 0xCE, 0x13, 
+0xCE, 0x13, 0xBD, 0x71, 0xAD, 0x10, 0x7B, 0x8B, 
+0x94, 0x6E, 0xA4, 0xF0, 0xAD, 0x10, 0xB5, 0x50, 
+0xBD, 0x91, 0xA4, 0xCF, 0x83, 0xEC, 0xB5, 0x52, 
+0x94, 0x6E, 0x9C, 0x8F, 0x94, 0x6E, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xAD, 0x10, 0xAD, 0x10, 0xA4, 0xCF, 
+0xA4, 0xD0, 0xAC, 0xF0, 0x9C, 0x8F, 0x7B, 0x8B, 
+0x9C, 0x6F, 0xA4, 0xD0, 0xA4, 0xD0, 0x9C, 0xB0, 
+0xA4, 0xB0, 0xAD, 0x11, 0x9C, 0x6F, 0xA4, 0xF1, 
+0xAD, 0x32, 0xAD, 0x32, 0x9C, 0xB0, 0xAC, 0xF2, 
+0xAD, 0x12, 0x9C, 0x6F, 0x9C, 0xB0, 0xB5, 0x32, 
+0xB5, 0x73, 0xB5, 0x73, 0xBD, 0x93, 0xBD, 0x94, 
+0xBD, 0x93, 0xBD, 0x93, 0xC5, 0xD4, 0xBD, 0x93, 
+0xBD, 0x93, 0xB5, 0x52, 0xB5, 0x32, 0xBD, 0x94, 
+0xBD, 0x93, 0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x12, 
+0x8C, 0x2F, 0x8C, 0x2F, 0x9C, 0xD2, 0xA4, 0xF2, 
+0x9C, 0xB1, 0x8C, 0x2F, 0x83, 0xEE, 0x94, 0x91, 
+0xAD, 0x33, 0xAD, 0x54, 0xAD, 0x34, 0xA5, 0x13, 
+0xA5, 0x13, 0x9D, 0x13, 0x9D, 0x13, 0x9C, 0xD2, 
+0x7C, 0x0F, 0x5A, 0xEB, 0x3A, 0x08, 0x29, 0x87, 
+0x31, 0xC8, 0x3A, 0x08, 0x39, 0xE8, 0x31, 0xC7, 
+0x39, 0xE8, 0x52, 0xAB, 0x6B, 0x4E, 0x84, 0x32, 
+0xA4, 0xF4, 0xA5, 0x15, 0xA5, 0x15, 0x9C, 0xF4, 
+0x8C, 0x52, 0x73, 0xAF, 0x6B, 0x4E, 0x63, 0x0D, 
+0x5A, 0xEB, 0x62, 0xEB, 0x62, 0xEB, 0x5A, 0xEB, 
+0x5A, 0xCB, 0x52, 0x49, 0x4A, 0x28, 0x52, 0x6A, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x15, 
+0x9C, 0xF4, 0x84, 0x31, 0x62, 0xEA, 0x9C, 0xB0, 
+0x94, 0x6E, 0x9C, 0x6E, 0x94, 0x4D, 0xA4, 0xCF, 
+0xB5, 0x92, 0xBD, 0x92, 0xC5, 0xD2, 0xC5, 0xB2, 
+0xC5, 0xB2, 0xC5, 0xB1, 0xC5, 0xB1, 0xB5, 0x2F, 
+0xBD, 0x71, 0xBD, 0x71, 0xCD, 0xF3, 0xC5, 0xB2, 
+0xC5, 0x92, 0xCD, 0xD3, 0xC5, 0xB2, 0xAC, 0xF0, 
+0xB5, 0x32, 0x8B, 0xEE, 0x72, 0xEA, 0x7A, 0xEB, 
+0x72, 0xCA, 0x7B, 0x0B, 0x83, 0x8D, 0x83, 0xAD, 
+0x94, 0x4F, 0x83, 0xED, 0x7B, 0xAC, 0x8B, 0xED, 
+0x94, 0x4E, 0x9C, 0x8F, 0x83, 0xCC, 0x83, 0xEC, 
+0x94, 0x6F, 0x9C, 0xB0, 0x6B, 0x4B, 0x31, 0xA6, 
+0x29, 0x44, 0x29, 0x65, 0x31, 0x65, 0x31, 0x85, 
+0x5A, 0xEB, 0xD6, 0xBB, 0xE7, 0x3D, 0xDE, 0xFC, 
+0xBD, 0xD7, 0x8C, 0x11, 0x73, 0x6E, 0x73, 0x6D, 
+0x84, 0x30, 0x8C, 0x30, 0xAD, 0x34, 0x94, 0xB2, 
+0xBD, 0xD7, 0xB5, 0x96, 0xC6, 0x18, 0xA5, 0x34, 
+0x4A, 0x49, 0x4A, 0x49, 0x42, 0x28, 0x31, 0x66, 
+0x31, 0x86, 0x39, 0xC7, 0x39, 0xA7, 0x52, 0x6A, 
+0x52, 0x69, 0x52, 0x8A, 0x52, 0x8A, 0x4A, 0x69, 
+0x7B, 0x8E, 0x94, 0x92, 0xAD, 0x75, 0xB5, 0xB7, 
+0xB5, 0x97, 0xDE, 0xDB, 0xC6, 0x18, 0xC6, 0x39, 
+0xE7, 0x3D, 0xE7, 0x1C, 0xAD, 0x55, 0x8C, 0x2F, 
+0xA4, 0xD0, 0xAC, 0xF0, 0xA4, 0xCF, 0x9C, 0x6E, 
+0xA4, 0xD0, 0x9C, 0xAF, 0x9C, 0xAF, 0xA4, 0xD0, 
+0x9C, 0xAF, 0x94, 0x6E, 0x94, 0x4E, 0xA4, 0xAF, 
+0xAD, 0x11, 0xB5, 0x72, 0xC5, 0xB3, 0xB5, 0x31, 
+0x94, 0x4E, 0x94, 0x6E, 0xA4, 0xAF, 0x73, 0x4A, 
+0x8C, 0x4E, 0xA4, 0xD0, 0xB5, 0x73, 0xB5, 0x93, 
+0xA4, 0xF1, 0x94, 0x6F, 0x9C, 0xF1, 0x9C, 0xB1, 
+0x7B, 0xED, 0x9C, 0xB0, 0xC5, 0xF5, 0xD6, 0x77, 
+0xCE, 0x36, 0xCE, 0x76, 0xCE, 0x55, 0xBD, 0xD4, 
+0xB5, 0x73, 0x8C, 0x6F, 0x8C, 0x4F, 0x7B, 0xCD, 
+0x73, 0x8C, 0x73, 0x6A, 0xB5, 0x31, 0x6B, 0x0A, 
+0x9C, 0xF1, 0xBD, 0xD5, 0x9C, 0xD1, 0x9C, 0xD0, 
+0x8C, 0x2E, 0x94, 0x8F, 0xB5, 0x73, 0xA5, 0x12, 
+0x9C, 0xD1, 0xA5, 0x12, 0xBD, 0xF7, 0xAD, 0x76, 
+0x9C, 0xD3, 0x8C, 0x71, 0x8C, 0x50, 0xA5, 0x32, 
+0xB5, 0x93, 0xB5, 0x93, 0xB5, 0xB4, 0xB5, 0x94, 
+0xBD, 0xB4, 0xAD, 0x32, 0xAD, 0x32, 0x8C, 0x2E, 
+0x94, 0x70, 0x94, 0x70, 0x8C, 0x2F, 0x8C, 0x2F, 
+0x94, 0x4F, 0x7B, 0xCD, 0x84, 0x0E, 0x84, 0x0E, 
+0x94, 0xB1, 0xAD, 0x53, 0xA5, 0x12, 0xAD, 0x53, 
+0xAD, 0x33, 0x9C, 0xD1, 0xA5, 0x33, 0xA4, 0xF2, 
+0x9C, 0xD1, 0x94, 0x70, 0x94, 0x70, 0x9C, 0xD1, 
+0x8C, 0x4F, 0x8C, 0x2F, 0xA4, 0xF2, 0xAD, 0x32, 
+0xA5, 0x32, 0x9C, 0xF1, 0x7B, 0xAD, 0x8C, 0x70, 
+0xA5, 0x12, 0x94, 0x6F, 0xC6, 0x15, 0xDE, 0xD8, 
+0xD6, 0x77, 0xCE, 0x56, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xCE, 0x16, 0xCE, 0x15, 0xC6, 0x15, 
+0xA4, 0xD1, 0xB5, 0x73, 0xB5, 0x73, 0x94, 0x90, 
+0x73, 0x8C, 0x7B, 0xAD, 0xAD, 0x32, 0xA5, 0x11, 
+0xA5, 0x12, 0xA5, 0x11, 0x9C, 0xD0, 0x83, 0xED, 
+0xA4, 0xF1, 0x9C, 0x8F, 0xB5, 0x93, 0xB5, 0x52, 
+0xAD, 0x31, 0xB5, 0x72, 0xCE, 0x34, 0xA4, 0xEF, 
+0x9C, 0x8D, 0xAC, 0xEF, 0xB5, 0x71, 0x83, 0xCB, 
+0x8C, 0x4E, 0xA4, 0xCF, 0xAC, 0xF0, 0xB5, 0x50, 
+0xB5, 0x51, 0xAD, 0x10, 0x8C, 0x2E, 0xB5, 0x73, 
+0x7B, 0xAC, 0x73, 0x4A, 0x6B, 0x29, 0x83, 0xEC, 
+0x83, 0xCC, 0x9C, 0x8F, 0x9C, 0xAF, 0xA4, 0xF0, 
+0xB5, 0x72, 0xA4, 0xD0, 0xA4, 0xD0, 0xB5, 0x73, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xAD, 0x32, 0xA4, 0xD0, 
+0xA4, 0xF1, 0xBD, 0x94, 0xAD, 0x12, 0xAD, 0x11, 
+0xBD, 0x93, 0xBD, 0xB3, 0xAD, 0x11, 0xB5, 0x33, 
+0xAC, 0xF1, 0x9C, 0xD1, 0x9C, 0xD1, 0xB5, 0x53, 
+0xC5, 0xD4, 0xBD, 0xB3, 0xBD, 0x93, 0xBD, 0x93, 
+0xBD, 0x94, 0xBD, 0x94, 0xBD, 0x94, 0xBD, 0xB4, 
+0xC5, 0xD4, 0xBD, 0xB4, 0xC5, 0xF5, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xCE, 0x15, 0xD6, 0x36, 0xC5, 0xD4, 
+0xCE, 0x15, 0xCE, 0x36, 0x9C, 0x90, 0x73, 0x8C, 
+0x9C, 0xB1, 0xAD, 0x33, 0xAD, 0x54, 0x94, 0x91, 
+0x83, 0xEF, 0x8C, 0x30, 0x8C, 0x50, 0x94, 0x91, 
+0x9C, 0xD2, 0x94, 0xB2, 0x9C, 0xD2, 0xA5, 0x13, 
+0x94, 0xB2, 0x8C, 0x71, 0x84, 0x0F, 0x6B, 0x4D, 
+0x42, 0x49, 0x29, 0x86, 0x21, 0x45, 0x29, 0x46, 
+0x31, 0xA7, 0x4A, 0x6A, 0x5A, 0xEC, 0x6B, 0x6E, 
+0x7B, 0xD0, 0x7B, 0xF0, 0x7B, 0xF1, 0x84, 0x11, 
+0x8C, 0x72, 0x94, 0xB4, 0x9C, 0xF5, 0x9D, 0x15, 
+0xA5, 0x35, 0xA5, 0x35, 0x9C, 0xF4, 0x94, 0xD4, 
+0x94, 0xB4, 0x94, 0xD4, 0x8C, 0x72, 0x84, 0x51, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x55, 0x9D, 0x34, 
+0x9C, 0xF4, 0x84, 0x50, 0x63, 0x0A, 0x9C, 0xAF, 
+0x94, 0x6D, 0x94, 0x4D, 0x9C, 0x8E, 0xA4, 0xF0, 
+0xAD, 0x51, 0xBD, 0x71, 0xC5, 0xB2, 0xC5, 0xD2, 
+0xC5, 0xB1, 0xB5, 0x0F, 0xA4, 0xAE, 0xA4, 0xAE, 
+0xC5, 0xB2, 0x8B, 0xEB, 0xB5, 0x30, 0xB5, 0x10, 
+0xAD, 0x0F, 0xAD, 0x0F, 0xAD, 0x0F, 0x94, 0x2D, 
+0xB5, 0x51, 0xA4, 0xAF, 0xA4, 0x6F, 0x83, 0x6C, 
+0x83, 0xAD, 0x83, 0xCD, 0x8B, 0xEE, 0x62, 0xEA, 
+0x83, 0xED, 0x83, 0xCD, 0x73, 0x6B, 0x84, 0x0D, 
+0x5A, 0xC9, 0x63, 0x0A, 0x5A, 0xA8, 0x52, 0x67, 
+0x6B, 0x4B, 0x84, 0x0E, 0x6B, 0x2B, 0x63, 0x2B, 
+0x39, 0xC6, 0x29, 0x64, 0x29, 0x64, 0x31, 0xA6, 
+0xA5, 0x35, 0xE7, 0x1D, 0xB5, 0xB7, 0x94, 0x92, 
+0x84, 0x10, 0x42, 0x28, 0x4A, 0x28, 0x5A, 0xEB, 
+0x52, 0x69, 0x7B, 0xAE, 0x8C, 0x50, 0x94, 0x71, 
+0xB5, 0x96, 0xBD, 0xB6, 0xBD, 0xD7, 0xB5, 0x76, 
+0x52, 0x69, 0x52, 0x8A, 0x73, 0x6D, 0x42, 0x28, 
+0x52, 0x89, 0x42, 0x28, 0x31, 0x65, 0x31, 0x86, 
+0x52, 0x8A, 0x6B, 0x2C, 0x5A, 0xEB, 0x4A, 0x49, 
+0x73, 0x8E, 0x94, 0x92, 0xA5, 0x35, 0xB5, 0x76, 
+0x8C, 0x52, 0xD6, 0x9B, 0xAD, 0x56, 0xCE, 0x5A, 
+0xB5, 0xB7, 0xB5, 0xB7, 0xB5, 0x96, 0x94, 0x90, 
+0x9C, 0x8F, 0xAC, 0xF0, 0xB5, 0x31, 0x8C, 0x0C, 
+0x8C, 0x0D, 0x94, 0x2D, 0x94, 0x6E, 0x94, 0x4E, 
+0xAC, 0xCF, 0xAC, 0xD0, 0xB5, 0x11, 0xC5, 0x92, 
+0x94, 0x0C, 0x94, 0x2D, 0x94, 0x0C, 0x8B, 0xEC, 
+0x8C, 0x0C, 0x8B, 0xEC, 0x9C, 0x6E, 0xA4, 0xCF, 
+0x9C, 0x8F, 0x94, 0x4E, 0x94, 0x2D, 0xA4, 0xAF, 
+0x9C, 0x6E, 0x94, 0x4E, 0x94, 0x4E, 0x94, 0x6F, 
+0x8C, 0x0D, 0x94, 0x6E, 0xA4, 0xD0, 0xB5, 0x52, 
+0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x52, 0xA4, 0xF0, 
+0xA5, 0x11, 0x94, 0xB0, 0x94, 0x6F, 0x84, 0x2E, 
+0x7B, 0xCD, 0x73, 0x4A, 0xB5, 0x10, 0x62, 0xC8, 
+0x9C, 0xF1, 0xBD, 0xD4, 0xAD, 0x32, 0xAD, 0x52, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x73, 0xB5, 0x73, 
+0xA5, 0x12, 0xB5, 0x74, 0xC6, 0x58, 0xB5, 0xB7, 
+0xA5, 0x35, 0x84, 0x30, 0x94, 0xB1, 0xBD, 0xD5, 
+0xBD, 0xD4, 0xB5, 0x93, 0xB5, 0x94, 0xB5, 0x93, 
+0xB5, 0x93, 0xB5, 0x73, 0xAD, 0x32, 0x8C, 0x2F, 
+0x8C, 0x4F, 0x94, 0x70, 0x8C, 0x2E, 0x84, 0x0E, 
+0x94, 0x6F, 0x83, 0xED, 0x84, 0x0E, 0x94, 0x90, 
+0xAD, 0x53, 0xB5, 0xD5, 0xB5, 0x74, 0xB5, 0x94, 
+0xAD, 0x74, 0xAD, 0x74, 0xBD, 0xD6, 0xA5, 0x33, 
+0x9C, 0xF2, 0x84, 0x0E, 0x8C, 0x2F, 0x8C, 0x4F, 
+0x8C, 0x4F, 0x8C, 0x2F, 0xB5, 0x53, 0xB5, 0x74, 
+0xA4, 0xF2, 0x9C, 0xB1, 0x8C, 0x2F, 0x94, 0x90, 
+0xAD, 0x33, 0x94, 0x6F, 0xCE, 0x57, 0xCE, 0x56, 
+0xD6, 0x97, 0xCE, 0x36, 0xCE, 0x35, 0xCE, 0x15, 
+0xCE, 0x36, 0xCE, 0x56, 0xC6, 0x15, 0xC5, 0xF5, 
+0x9C, 0x90, 0xB5, 0x74, 0xC5, 0xF5, 0x9C, 0xD1, 
+0x94, 0x90, 0x94, 0x90, 0xAD, 0x52, 0xA4, 0xF1, 
+0xAD, 0x53, 0xA4, 0xF1, 0x9C, 0xB0, 0x7B, 0x8C, 
+0x8C, 0x4F, 0x9C, 0xB0, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xBD, 0xB3, 0xC5, 0xB3, 0xC5, 0xD3, 0x73, 0x8A, 
+0x9C, 0xAE, 0x9C, 0x6D, 0x94, 0x2D, 0x94, 0x6E, 
+0xAD, 0x52, 0xC5, 0xF4, 0xB5, 0x71, 0xBD, 0x92, 
+0xBD, 0x71, 0xAD, 0x30, 0x9C, 0xAF, 0xAD, 0x12, 
+0x7B, 0x8B, 0x7B, 0x8B, 0x73, 0xAC, 0x94, 0x6F, 
+0x94, 0x4E, 0x94, 0x6E, 0x9C, 0x8E, 0xAD, 0x10, 
+0xA4, 0xCF, 0x94, 0x6E, 0xA4, 0xD0, 0xC5, 0xF5, 
+0xAD, 0x32, 0xA4, 0xF1, 0xB5, 0x93, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xAD, 0x32, 0xAD, 0x32, 0x94, 0x8F, 
+0xA4, 0xF0, 0xA5, 0x10, 0xA4, 0xF1, 0xBD, 0x73, 
+0x9C, 0x90, 0x7B, 0xCE, 0x8C, 0x4F, 0xA5, 0x32, 
+0xBD, 0xD4, 0xBD, 0x93, 0xB5, 0x72, 0xB5, 0x52, 
+0xB5, 0x52, 0xB5, 0x73, 0xB5, 0x94, 0xB5, 0x53, 
+0xBD, 0xB4, 0xC5, 0xF5, 0xBD, 0x93, 0xBD, 0x93, 
+0xBD, 0xB3, 0xC5, 0xB4, 0xCD, 0xF5, 0xBD, 0x94, 
+0xBD, 0xB3, 0xD6, 0x56, 0xD6, 0x57, 0x94, 0x4F, 
+0xA4, 0xF2, 0xAD, 0x33, 0x9C, 0xD2, 0x9C, 0xD1, 
+0xA4, 0xF2, 0xA5, 0x13, 0x9C, 0xB1, 0xA5, 0x12, 
+0x8C, 0x70, 0x7B, 0xEE, 0x94, 0x70, 0x94, 0x91, 
+0x9C, 0xD2, 0x9C, 0xB1, 0x94, 0x91, 0x8C, 0x50, 
+0x7B, 0xCE, 0x6B, 0x4D, 0x5A, 0xCB, 0x52, 0x8A, 
+0x39, 0xE8, 0x31, 0x86, 0x29, 0x46, 0x39, 0xE8, 
+0x52, 0xCB, 0x73, 0x8F, 0x84, 0x31, 0x84, 0x52, 
+0x6B, 0x6F, 0x63, 0x0D, 0x5A, 0xEC, 0x5A, 0xEC, 
+0x73, 0x8F, 0x84, 0x31, 0x94, 0xB3, 0x94, 0xD4, 
+0x94, 0xB3, 0x8C, 0x93, 0x9C, 0xD4, 0x9C, 0xF5, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x55, 0x9D, 0x34, 
+0x9C, 0xF4, 0x84, 0x30, 0x62, 0xE9, 0x94, 0x2D, 
+0x94, 0x2C, 0x8C, 0x0C, 0x94, 0x4D, 0x94, 0x2C, 
+0x9C, 0xAE, 0xAD, 0x0F, 0xAC, 0xEF, 0xBD, 0x91, 
+0xA4, 0xCE, 0xAD, 0x10, 0xB5, 0x50, 0xAD, 0x10, 
+0xBD, 0x92, 0x73, 0x29, 0x94, 0x4D, 0x9C, 0x8E, 
+0x9C, 0x6D, 0xA4, 0xCF, 0xAC, 0xCF, 0x8B, 0xEC, 
+0xA4, 0xEF, 0xAD, 0x10, 0x94, 0x0D, 0x83, 0xCD, 
+0x7B, 0xAD, 0x9C, 0xB0, 0xA4, 0xF1, 0x6B, 0x6B, 
+0x94, 0x6F, 0x8C, 0x4F, 0x8C, 0x6F, 0xAD, 0x53, 
+0x73, 0x6C, 0x73, 0x8D, 0x6B, 0x4C, 0x7B, 0xAD, 
+0x73, 0x8C, 0x94, 0x4F, 0x8C, 0x0E, 0x9C, 0xB0, 
+0x7B, 0xCD, 0x39, 0xC6, 0x29, 0x65, 0x39, 0xE7, 
+0x94, 0xB3, 0xD6, 0xBA, 0xAD, 0x55, 0x4A, 0x29, 
+0x4A, 0x48, 0x42, 0x28, 0x4A, 0x28, 0x42, 0x28, 
+0x73, 0x6D, 0x8C, 0x30, 0x94, 0x71, 0x9C, 0xB3, 
+0xA5, 0x14, 0xAD, 0x34, 0xAD, 0x75, 0xAD, 0x34, 
+0x6B, 0x6D, 0x5A, 0xCB, 0x63, 0x0B, 0x29, 0x45, 
+0x39, 0xC7, 0x39, 0xE7, 0x42, 0x28, 0x4A, 0x28, 
+0x52, 0x89, 0x5A, 0xEB, 0x42, 0x28, 0x4A, 0x69, 
+0x5A, 0xEB, 0x7C, 0x10, 0x94, 0xD3, 0xAD, 0x96, 
+0xBD, 0xB7, 0xBD, 0xF8, 0xBD, 0xD8, 0xC6, 0x39, 
+0xD6, 0xBB, 0xCE, 0x5A, 0xC6, 0x18, 0x9C, 0xD2, 
+0xAD, 0x52, 0xB5, 0x93, 0xC6, 0x15, 0x9C, 0xD0, 
+0x8C, 0x2E, 0x8C, 0x2E, 0x94, 0x4E, 0x94, 0x4E, 
+0x94, 0x4E, 0x8C, 0x2D, 0x94, 0x2D, 0xAC, 0xCF, 
+0x7B, 0x8B, 0x73, 0x6B, 0x8C, 0x0D, 0x83, 0xEC, 
+0x73, 0x8B, 0x73, 0x4A, 0x62, 0xC9, 0x83, 0xED, 
+0x8B, 0xEC, 0x8B, 0xEC, 0x8B, 0xEC, 0xBD, 0x31, 
+0xA4, 0x6D, 0xAC, 0xCF, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xAC, 0xCF, 0xAC, 0xD0, 0xAC, 0xCF, 0x9C, 0x4D, 
+0x8C, 0x0D, 0x9C, 0x6E, 0x94, 0x2D, 0x8B, 0xEC, 
+0x8B, 0xEC, 0xAC, 0xF0, 0xBD, 0x51, 0xAC, 0xAF, 
+0xA4, 0xCF, 0xA4, 0x8F, 0x9C, 0x4E, 0x9C, 0x6E, 
+0x94, 0x2D, 0x94, 0x4E, 0x9C, 0x8F, 0xA4, 0xD0, 
+0x94, 0x4E, 0x94, 0x90, 0xC6, 0x38, 0xB5, 0xD7, 
+0xB5, 0x76, 0x8C, 0x51, 0x9C, 0xD1, 0xB5, 0xB3, 
+0xC5, 0xF5, 0xC6, 0x36, 0xC5, 0xF5, 0xBD, 0xB4, 
+0xA4, 0xF1, 0x83, 0xED, 0xAD, 0x53, 0x94, 0x4F, 
+0x94, 0x70, 0x9C, 0xD1, 0x94, 0x90, 0x9C, 0xB1, 
+0xA5, 0x12, 0x94, 0x90, 0x9C, 0xB1, 0xB5, 0x74, 
+0xB5, 0x74, 0xCE, 0x57, 0xBD, 0xD5, 0xC5, 0xF6, 
+0xBD, 0xF5, 0xA5, 0x33, 0xBD, 0xD5, 0x9C, 0xD1, 
+0xA5, 0x12, 0x94, 0x90, 0x9C, 0xB1, 0x8C, 0x2F, 
+0x9C, 0xD1, 0x94, 0x90, 0xAD, 0x33, 0xA4, 0xF2, 
+0xBD, 0xD5, 0xB5, 0x94, 0x8C, 0x4F, 0x94, 0x70, 
+0xA5, 0x12, 0x9C, 0xB0, 0xD6, 0x98, 0xD6, 0x97, 
+0xD6, 0x97, 0xD6, 0x97, 0xDE, 0xB7, 0xC5, 0xD4, 
+0xC5, 0xF5, 0xCE, 0x36, 0xD6, 0x76, 0xC5, 0xF5, 
+0x8C, 0x4F, 0xAD, 0x32, 0xAD, 0x12, 0x9C, 0xD1, 
+0x94, 0xB0, 0x9C, 0xD1, 0xA5, 0x12, 0xA4, 0xF1, 
+0x9C, 0x90, 0xA4, 0xD1, 0x94, 0x6F, 0x73, 0x8C, 
+0x84, 0x0E, 0x9C, 0x8F, 0xBD, 0x92, 0xC5, 0xD3, 
+0x94, 0x8E, 0xA4, 0xD0, 0xC5, 0xD3, 0xBD, 0xB3, 
+0xCE, 0x14, 0xC5, 0xD3, 0x94, 0x6E, 0x9C, 0xD0, 
+0xBD, 0xD4, 0xCE, 0x35, 0xBD, 0xB2, 0xBD, 0xD3, 
+0xBD, 0xB3, 0xAD, 0x10, 0xA4, 0xF0, 0xA4, 0xF1, 
+0x7B, 0xAC, 0x94, 0x6F, 0x9C, 0xB0, 0x7B, 0xAC, 
+0x8C, 0x4E, 0x94, 0x8F, 0xA4, 0xF0, 0xAD, 0x31, 
+0xA4, 0xF1, 0x94, 0x6E, 0x94, 0x6F, 0xAD, 0x52, 
+0xB5, 0x94, 0xB5, 0xB4, 0xB5, 0x94, 0x9C, 0xD1, 
+0xA4, 0xF1, 0xAD, 0x53, 0xAD, 0x33, 0x94, 0x8F, 
+0xA5, 0x11, 0xA5, 0x11, 0xAD, 0x11, 0xB5, 0x73, 
+0x9C, 0x90, 0x83, 0xEE, 0x84, 0x2F, 0x9C, 0xD1, 
+0xB5, 0x72, 0xB5, 0x31, 0xA4, 0xF0, 0xA4, 0xF0, 
+0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x74, 
+0xBD, 0x94, 0xBD, 0xB4, 0xC5, 0xF5, 0xBD, 0xB3, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xCE, 0x15, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xF4, 0xDE, 0x76, 0xB5, 0x32, 
+0xBD, 0x94, 0xB5, 0x53, 0xAD, 0x53, 0xB5, 0x53, 
+0xBD, 0xB5, 0xAD, 0x53, 0xA4, 0xF2, 0xC5, 0xD5, 
+0xD6, 0x57, 0x94, 0x50, 0x7B, 0xAD, 0x8C, 0x2F, 
+0x8C, 0x50, 0x94, 0x91, 0x9C, 0xD2, 0x9C, 0xD2, 
+0x8C, 0x50, 0x83, 0xEF, 0x83, 0xEF, 0x84, 0x0F, 
+0x7B, 0xEF, 0x6B, 0x8D, 0x52, 0x8A, 0x39, 0xC7, 
+0x29, 0x45, 0x21, 0x04, 0x21, 0x45, 0x39, 0xC8, 
+0x4A, 0x6A, 0x63, 0x2D, 0x73, 0x8F, 0x73, 0xAF, 
+0x7B, 0xD0, 0x7B, 0xD0, 0x7B, 0xD0, 0x7C, 0x11, 
+0x7B, 0xF0, 0x73, 0xAF, 0x7B, 0xF0, 0x73, 0xB0, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x55, 0x9D, 0x34, 
+0x9C, 0xF4, 0x7C, 0x0F, 0x5A, 0xC9, 0x83, 0xAB, 
+0x83, 0xAB, 0x7B, 0x8B, 0x83, 0xCC, 0x83, 0xCC, 
+0x8C, 0x0D, 0x9C, 0x8E, 0x9C, 0xAE, 0x94, 0x4D, 
+0x73, 0x49, 0x94, 0x4D, 0xAD, 0x31, 0xBD, 0x92, 
+0xC5, 0xD4, 0x8C, 0x0D, 0x94, 0x6E, 0xA4, 0xCF, 
+0xAC, 0xF0, 0x94, 0x6E, 0x9C, 0x6E, 0x8C, 0x0C, 
+0x9C, 0x8E, 0xAC, 0xEF, 0x94, 0x2D, 0x7B, 0x8C, 
+0x7B, 0x8C, 0xA4, 0xD1, 0xA4, 0xF1, 0x7B, 0xCD, 
+0x9C, 0x91, 0x9C, 0xB1, 0x9C, 0xB0, 0xAD, 0x53, 
+0x9C, 0xB0, 0xAD, 0x32, 0xAD, 0x33, 0xAD, 0x53, 
+0xA5, 0x32, 0xA5, 0x12, 0x94, 0x90, 0x9C, 0xD0, 
+0x8C, 0x4F, 0x73, 0x8C, 0x31, 0xA5, 0x31, 0xA6, 
+0x41, 0xE7, 0x62, 0xEB, 0x7B, 0xAE, 0x31, 0x86, 
+0x29, 0x65, 0x39, 0xE7, 0x52, 0x8A, 0x6B, 0x4C, 
+0x73, 0xAE, 0x7B, 0xCF, 0x8C, 0x51, 0x8C, 0x30, 
+0x84, 0x10, 0xAD, 0x35, 0xB5, 0x96, 0x94, 0xB2, 
+0x84, 0x10, 0x8C, 0x71, 0x94, 0xB1, 0x6B, 0x6D, 
+0x29, 0x24, 0x39, 0xA6, 0x42, 0x28, 0x31, 0x85, 
+0x31, 0x85, 0x39, 0xE7, 0x31, 0xA6, 0x5A, 0xCA, 
+0x63, 0x0C, 0x6B, 0x4D, 0x7B, 0xCF, 0xAD, 0x76, 
+0xA5, 0x35, 0xAD, 0x76, 0xBD, 0xF8, 0xCE, 0x7B, 
+0xE7, 0x1D, 0xD6, 0xBB, 0xCE, 0x59, 0xB5, 0xB6, 
+0xB5, 0x74, 0xB5, 0x93, 0xBD, 0xD4, 0xAD, 0x53, 
+0xA4, 0xF1, 0x9C, 0xD0, 0xA5, 0x11, 0xA5, 0x11, 
+0xA4, 0xF1, 0xA4, 0xF0, 0xA4, 0xCF, 0xA4, 0xCF, 
+0x7B, 0x8B, 0x7B, 0xAC, 0x7B, 0x8C, 0x83, 0xED, 
+0x84, 0x2E, 0x83, 0xED, 0x7B, 0xAD, 0x8C, 0x4F, 
+0x94, 0x6F, 0x8C, 0x4E, 0x8B, 0xEC, 0xA4, 0x8E, 
+0x8C, 0x0C, 0x9C, 0x8E, 0x8C, 0x0D, 0x73, 0x6B, 
+0x73, 0x4A, 0x62, 0xE9, 0x62, 0xA9, 0x62, 0xE9, 
+0x6B, 0x09, 0x73, 0x4A, 0x94, 0x2D, 0x8B, 0xCB, 
+0x7B, 0x8A, 0x8B, 0xCB, 0x94, 0x2D, 0x94, 0x0D, 
+0x83, 0xAB, 0x83, 0x8A, 0x8B, 0xEC, 0xA4, 0x6E, 
+0xAC, 0xCF, 0xAC, 0x8E, 0xBD, 0x31, 0xB5, 0x10, 
+0xBD, 0x30, 0xBD, 0x31, 0xB5, 0x30, 0xB5, 0x10, 
+0xAC, 0xF0, 0xA4, 0xF1, 0xCE, 0x79, 0xBD, 0xD8, 
+0xBD, 0xB7, 0x9C, 0xD1, 0xA4, 0xF0, 0xAD, 0x10, 
+0xAC, 0xD0, 0xA4, 0xAF, 0xA4, 0xAF, 0x9C, 0x6E, 
+0x94, 0x6E, 0xA4, 0xD1, 0xBD, 0x94, 0xAD, 0x53, 
+0xA4, 0xF2, 0x94, 0x90, 0x94, 0x70, 0x8C, 0x4F, 
+0x8C, 0x4F, 0x8C, 0x4F, 0x8C, 0x4F, 0x94, 0x70, 
+0x8C, 0x2F, 0x8C, 0x2F, 0x84, 0x0E, 0x8C, 0x4F, 
+0x94, 0x70, 0x7B, 0xAD, 0x83, 0xEE, 0x94, 0x6F, 
+0xA5, 0x32, 0xAD, 0x33, 0xA5, 0x12, 0xAD, 0x53, 
+0xA5, 0x33, 0x83, 0xEE, 0xA5, 0x12, 0x9C, 0xD1, 
+0xB5, 0xB4, 0xB5, 0x94, 0x9C, 0xB1, 0x94, 0x90, 
+0xAD, 0x32, 0xAD, 0x32, 0xCE, 0x36, 0xCE, 0x77, 
+0xD6, 0x77, 0xD6, 0x56, 0xB5, 0x53, 0x94, 0x90, 
+0x94, 0x6F, 0x8C, 0x0E, 0xBD, 0xB4, 0xB5, 0x94, 
+0x83, 0xEE, 0xB5, 0x53, 0x9C, 0xD1, 0xC6, 0x36, 
+0x9C, 0xB1, 0xAD, 0x32, 0xAD, 0x52, 0xA4, 0xF1, 
+0xA4, 0xD1, 0xA4, 0xF1, 0x9C, 0xB0, 0x7B, 0xED, 
+0x7B, 0xCD, 0x94, 0x8F, 0xAD, 0x51, 0xBD, 0xD3, 
+0xB5, 0x72, 0x73, 0x6B, 0x9C, 0x8F, 0xC6, 0x14, 
+0xCE, 0x35, 0xD6, 0x96, 0x9C, 0xAF, 0xAD, 0x31, 
+0xCE, 0x15, 0xCE, 0x35, 0xBD, 0xD3, 0xCE, 0x35, 
+0xCE, 0x35, 0xB5, 0x72, 0xA4, 0xCF, 0xA4, 0xF1, 
+0x62, 0xE9, 0x5A, 0xE9, 0x6B, 0x2A, 0x83, 0xED, 
+0x94, 0x8F, 0xB5, 0x73, 0xC5, 0xD5, 0xAD, 0x53, 
+0xAD, 0x32, 0x9C, 0xB0, 0x9C, 0xB0, 0xA5, 0x12, 
+0xB5, 0x94, 0xBD, 0xF5, 0xA5, 0x32, 0x9C, 0xD1, 
+0xB5, 0x74, 0xC6, 0x16, 0xBD, 0xD5, 0xAD, 0x53, 
+0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x11, 0xB5, 0x73, 
+0x8C, 0x4F, 0x7B, 0xCE, 0x8C, 0x50, 0x9C, 0xD1, 
+0xAD, 0x11, 0xAD, 0x11, 0xA4, 0xAF, 0x9C, 0x8F, 
+0xA5, 0x11, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x73, 0xAD, 0x32, 0xB5, 0x93, 0xB5, 0x73, 
+0xB5, 0x73, 0xB5, 0x73, 0xBD, 0xB3, 0xC5, 0xB3, 
+0xCD, 0xF4, 0xC5, 0xF4, 0xC5, 0xD4, 0xB5, 0x32, 
+0xB5, 0x53, 0x9C, 0xB1, 0x9C, 0xD1, 0x9C, 0xD0, 
+0xAD, 0x32, 0xC5, 0xD5, 0xBD, 0xD5, 0xBD, 0xD5, 
+0xC5, 0xF5, 0x8C, 0x4F, 0x94, 0x70, 0xB5, 0x54, 
+0xA4, 0xD2, 0x8C, 0x2F, 0x94, 0x91, 0x9C, 0xB1, 
+0x94, 0x91, 0x94, 0x71, 0x94, 0x70, 0x8C, 0x70, 
+0x8C, 0x50, 0x8C, 0x50, 0x84, 0x0F, 0x73, 0x8E, 
+0x5B, 0x0C, 0x4A, 0x69, 0x39, 0xE7, 0x31, 0x86, 
+0x21, 0x25, 0x21, 0x25, 0x21, 0x45, 0x31, 0xA7, 
+0x42, 0x29, 0x5A, 0xCC, 0x63, 0x2D, 0x6B, 0x8F, 
+0x7B, 0xF1, 0x8C, 0x93, 0x8C, 0x72, 0x84, 0x52, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x55, 0x9D, 0x34, 
+0x9C, 0xF4, 0x7B, 0xCF, 0x52, 0x68, 0x6A, 0xE9, 
+0x5A, 0x88, 0x62, 0xC9, 0x62, 0xE9, 0x52, 0x68, 
+0x62, 0xE9, 0x73, 0x6B, 0x73, 0x6B, 0x83, 0xEC, 
+0x6B, 0x2A, 0x83, 0xED, 0x9C, 0xAF, 0x8C, 0x2D, 
+0xC5, 0xF4, 0x9C, 0xAF, 0xA4, 0xF0, 0xB5, 0x51, 
+0xA4, 0xF0, 0x94, 0x6E, 0x9C, 0xAF, 0x9C, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xCF, 0x83, 0xAB, 0x5A, 0xA9, 
+0x5A, 0xCA, 0x94, 0x90, 0x94, 0x6F, 0x63, 0x0A, 
+0x8C, 0x2F, 0x7B, 0xCD, 0x94, 0x90, 0x94, 0x90, 
+0x7B, 0xAC, 0x9C, 0xD0, 0x8C, 0x4F, 0xA4, 0xF1, 
+0x9C, 0xB0, 0x9C, 0xD0, 0x9C, 0xD1, 0x8C, 0x4E, 
+0x8C, 0x2E, 0x94, 0x6F, 0x5A, 0xEA, 0x31, 0x85, 
+0x39, 0xE7, 0x42, 0x28, 0x42, 0x07, 0x31, 0x86, 
+0x31, 0xA6, 0x42, 0x28, 0x52, 0xAA, 0x52, 0xAA, 
+0x5A, 0xCA, 0x63, 0x0C, 0x73, 0x8D, 0x7B, 0xAE, 
+0x73, 0x6D, 0x94, 0xB2, 0xB5, 0x96, 0x84, 0x30, 
+0x52, 0x8A, 0x52, 0x69, 0x9C, 0xD2, 0xAD, 0x74, 
+0x8C, 0x70, 0x29, 0x65, 0x21, 0x04, 0x29, 0x65, 
+0x31, 0x85, 0x31, 0x85, 0x4A, 0x48, 0x5A, 0xAA, 
+0x5A, 0xEB, 0x5A, 0xEB, 0x63, 0x4D, 0x8C, 0x51, 
+0xAD, 0x76, 0xBD, 0xD8, 0xBD, 0xD8, 0xCE, 0x5A, 
+0xC6, 0x39, 0x94, 0x92, 0x8C, 0x51, 0xDE, 0xBB, 
+0x94, 0x91, 0xB5, 0x94, 0xC6, 0x16, 0xB5, 0x94, 
+0xA5, 0x12, 0x94, 0x8F, 0x94, 0x8F, 0x9C, 0xD0, 
+0x8C, 0x2E, 0x9C, 0xAF, 0x9C, 0x6E, 0xA4, 0x8E, 
+0x8C, 0x0D, 0x7B, 0xED, 0x7B, 0xCD, 0x7B, 0xED, 
+0x94, 0xB1, 0x8C, 0x4F, 0x7B, 0xCE, 0x8C, 0x70, 
+0x9C, 0xD1, 0x94, 0x70, 0x8B, 0xED, 0xA4, 0x8F, 
+0x7B, 0xAC, 0x84, 0x0D, 0x8C, 0x2E, 0x84, 0x0E, 
+0x84, 0x0E, 0x8C, 0x4F, 0x7B, 0xAD, 0x4A, 0x27, 
+0x6B, 0x4B, 0x83, 0xCD, 0x94, 0x6F, 0x8C, 0x0D, 
+0x8B, 0xEC, 0x8C, 0x2D, 0x94, 0x4E, 0xA4, 0xF0, 
+0xB5, 0x73, 0x8C, 0x6F, 0x9C, 0xB0, 0xC5, 0xF4, 
+0xD6, 0x55, 0xB5, 0x30, 0xAC, 0xCF, 0x9C, 0x4D, 
+0x9C, 0x4D, 0xB5, 0x10, 0xB5, 0x51, 0xA4, 0xD0, 
+0x9C, 0x8F, 0xA4, 0xF2, 0xDE, 0xFB, 0xBD, 0xF8, 
+0xAD, 0x34, 0x9C, 0x90, 0x94, 0x2E, 0x94, 0x0D, 
+0x94, 0x2D, 0xA4, 0xCF, 0x94, 0x4D, 0x94, 0x2D, 
+0x94, 0x2D, 0x8C, 0x0D, 0x94, 0x4E, 0x9C, 0xD1, 
+0xB5, 0x53, 0xAD, 0x33, 0xAD, 0x12, 0xBD, 0xB5, 
+0xAD, 0x33, 0xB5, 0x53, 0xAD, 0x33, 0xAD, 0x53, 
+0xBD, 0x94, 0xB5, 0x54, 0xB5, 0x53, 0xB5, 0x53, 
+0xAD, 0x53, 0xB5, 0x74, 0xB5, 0x74, 0xB5, 0x74, 
+0xAD, 0x32, 0xA4, 0xF1, 0xA5, 0x12, 0xA5, 0x12, 
+0xA5, 0x12, 0x9C, 0xB1, 0xB5, 0x74, 0xBD, 0xB5, 
+0xAD, 0x53, 0x94, 0x90, 0x9C, 0x90, 0x94, 0x70, 
+0x94, 0x6F, 0x8C, 0x0E, 0x84, 0x0F, 0x84, 0x0E, 
+0x84, 0x0E, 0x94, 0x2F, 0x9C, 0xB0, 0xA5, 0x12, 
+0xA4, 0xF1, 0x8C, 0x0F, 0x7B, 0xAD, 0x73, 0x8C, 
+0x8C, 0x2F, 0xAD, 0x12, 0x7B, 0xAC, 0xB5, 0x94, 
+0xA4, 0xD1, 0x94, 0x8F, 0x94, 0x6F, 0x83, 0xCD, 
+0x83, 0xED, 0xA4, 0xF1, 0xA5, 0x12, 0x94, 0x4F, 
+0x7B, 0xAD, 0x9C, 0xB0, 0xB5, 0x92, 0xC5, 0xF3, 
+0xCE, 0x14, 0xBD, 0xB3, 0xBD, 0xB3, 0xB5, 0x92, 
+0xD6, 0x55, 0xDE, 0xB7, 0x94, 0x4E, 0xCE, 0x35, 
+0xCE, 0x35, 0xD6, 0x55, 0xCE, 0x35, 0xD6, 0x96, 
+0xD6, 0x75, 0xBD, 0xB2, 0xA4, 0xF0, 0xA4, 0xF1, 
+0x6B, 0x4B, 0x5A, 0xCA, 0x5A, 0xC9, 0x7B, 0x8C, 
+0x94, 0x6F, 0xA5, 0x31, 0xA5, 0x11, 0x9C, 0x90, 
+0x7B, 0xCC, 0x9C, 0xB0, 0xA4, 0xF1, 0xB5, 0x73, 
+0xB5, 0x73, 0xB5, 0xB4, 0xAD, 0x53, 0xB5, 0xB4, 
+0xB5, 0xB4, 0xAD, 0x93, 0x9C, 0xB1, 0x7B, 0xAD, 
+0x94, 0x6F, 0xAD, 0x11, 0xA4, 0xF1, 0xB5, 0x73, 
+0x7B, 0xAD, 0x7B, 0xCE, 0x84, 0x2F, 0x9C, 0xD1, 
+0xA4, 0xF1, 0x9C, 0xAF, 0xA4, 0xD0, 0x9C, 0x8F, 
+0x9C, 0xB0, 0xA5, 0x12, 0xA5, 0x12, 0xAD, 0x33, 
+0xBD, 0xB5, 0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x12, 
+0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x73, 0x9C, 0xB0, 
+0xB5, 0x52, 0xB5, 0x51, 0xB5, 0x72, 0xAD, 0x12, 
+0xB5, 0x53, 0x9C, 0xB0, 0x9C, 0xB1, 0xA4, 0xF1, 
+0x9C, 0xB0, 0x9C, 0xD0, 0x94, 0x6F, 0xA4, 0xF1, 
+0xCE, 0x15, 0xC6, 0x15, 0xBD, 0xB4, 0xAD, 0x33, 
+0xAD, 0x12, 0xA4, 0xD2, 0x84, 0x0F, 0x7B, 0x8D, 
+0x73, 0x8C, 0x84, 0x0F, 0x8C, 0x50, 0x9C, 0xB1, 
+0x9C, 0xB1, 0x94, 0x91, 0x94, 0x91, 0x8C, 0x50, 
+0x84, 0x2F, 0x83, 0xEF, 0x73, 0x8E, 0x6B, 0x4C, 
+0x5A, 0xEB, 0x42, 0x29, 0x31, 0xA6, 0x29, 0x45, 
+0x21, 0x25, 0x21, 0x24, 0x21, 0x25, 0x29, 0x66, 
+0x39, 0xC8, 0x63, 0x2D, 0x84, 0x11, 0x84, 0x31, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x55, 0x9D, 0x14, 
+0x9C, 0xF3, 0x84, 0x0F, 0x62, 0xC9, 0x6B, 0x09, 
+0x73, 0x4A, 0x73, 0x6B, 0x7B, 0x8B, 0x7B, 0x8B, 
+0x73, 0x4A, 0x73, 0x2A, 0x73, 0x4B, 0x7B, 0xAB, 
+0x83, 0xCC, 0x6B, 0x2A, 0x73, 0x4A, 0x5A, 0xA8, 
+0x8C, 0x4E, 0x7B, 0x8B, 0x9C, 0x8F, 0x83, 0xED, 
+0x73, 0x6A, 0x8C, 0x0D, 0x9C, 0x8E, 0x94, 0x6E, 
+0xAD, 0x10, 0xAC, 0xCF, 0x8B, 0xEC, 0x8C, 0x4F, 
+0x8C, 0x2F, 0x94, 0x6F, 0xAD, 0x12, 0x8C, 0x4F, 
+0x84, 0x0E, 0x84, 0x0E, 0x8C, 0x6F, 0x94, 0x4F, 
+0x94, 0x4F, 0x94, 0x6F, 0x9C, 0xD1, 0x9C, 0xD0, 
+0x7B, 0xAC, 0x63, 0x2A, 0x73, 0x6B, 0x73, 0x4B, 
+0x7B, 0xCD, 0x73, 0x8C, 0x8C, 0x4F, 0x4A, 0x48, 
+0x31, 0x85, 0x39, 0xC6, 0x31, 0x85, 0x39, 0xC6, 
+0x39, 0xC6, 0x42, 0x07, 0x4A, 0x28, 0x39, 0xC6, 
+0x5A, 0xCA, 0x6B, 0x2C, 0x73, 0x6D, 0x7B, 0xEF, 
+0x5A, 0xEB, 0x84, 0x30, 0x84, 0x30, 0x94, 0x92, 
+0x8C, 0x30, 0x42, 0x29, 0x7B, 0xEF, 0xAD, 0x73, 
+0xBD, 0xB4, 0x9C, 0xD1, 0x63, 0x0B, 0x4A, 0x28, 
+0x21, 0x04, 0x31, 0x86, 0x39, 0xE7, 0x4A, 0x48, 
+0x5A, 0xEB, 0x63, 0x2C, 0x6B, 0x6D, 0x73, 0x8E, 
+0x8C, 0x72, 0x9C, 0xF4, 0xB5, 0x76, 0x9C, 0xF4, 
+0xA5, 0x15, 0xC5, 0xF8, 0xCE, 0x5A, 0xDE, 0xDC, 
+0xCE, 0x59, 0xAD, 0x54, 0xBD, 0xD5, 0xB5, 0xB4, 
+0xAD, 0x53, 0x94, 0x6F, 0x7B, 0xAC, 0xA5, 0x11, 
+0xA4, 0xD1, 0x8C, 0x2E, 0x9C, 0x8F, 0x94, 0x2D, 
+0x94, 0x6F, 0x73, 0xAC, 0x6B, 0x6C, 0x7C, 0x0E, 
+0xA5, 0x33, 0x94, 0x90, 0x8C, 0x70, 0x9C, 0xD2, 
+0x9C, 0xF2, 0x9C, 0xD1, 0x94, 0x2E, 0x9C, 0x8F, 
+0x8C, 0x0E, 0x94, 0x90, 0x94, 0x6F, 0x8C, 0x4F, 
+0x8C, 0x4F, 0xA5, 0x12, 0x7B, 0xAD, 0x6B, 0x2C, 
+0x73, 0x8C, 0x94, 0x90, 0xA5, 0x11, 0x94, 0x8F, 
+0x8C, 0x4E, 0x94, 0x6F, 0x94, 0x6F, 0xAD, 0x52, 
+0xCE, 0x76, 0xBD, 0xD4, 0xC6, 0x15, 0xDE, 0xB6, 
+0xD6, 0x55, 0xBD, 0x92, 0xA4, 0xAF, 0x9C, 0x6D, 
+0xAC, 0xF0, 0xB5, 0x71, 0xC6, 0x14, 0xCE, 0x35, 
+0xBD, 0xD5, 0xCE, 0x58, 0xC6, 0x18, 0x5A, 0xAC, 
+0x94, 0xB2, 0xD6, 0x98, 0xC5, 0xF4, 0xC5, 0xF4, 
+0xBD, 0xB3, 0xCE, 0x36, 0xB5, 0x73, 0xAD, 0x52, 
+0xAD, 0x11, 0xA5, 0x11, 0xBD, 0xD4, 0xCE, 0x36, 
+0xD6, 0x76, 0xCE, 0x56, 0x94, 0x70, 0xB5, 0x74, 
+0x9C, 0xB1, 0xCE, 0x16, 0xB5, 0x53, 0x94, 0x70, 
+0x8C, 0x0E, 0x94, 0x6F, 0x9C, 0x90, 0xA4, 0xF1, 
+0xAD, 0x12, 0x94, 0x4F, 0x9C, 0xB1, 0x94, 0x90, 
+0x94, 0x4F, 0x9C, 0xB0, 0x9C, 0xB0, 0x83, 0xED, 
+0x8C, 0x2E, 0x9C, 0xB0, 0xB5, 0x74, 0x94, 0x6F, 
+0x94, 0x6F, 0xA4, 0xF1, 0xA5, 0x12, 0xBD, 0x94, 
+0xA4, 0xF1, 0xA5, 0x12, 0xA5, 0x12, 0xAD, 0x53, 
+0xB5, 0x53, 0xAD, 0x32, 0xA4, 0xF1, 0x9C, 0x90, 
+0xA4, 0xF2, 0xA4, 0xF2, 0xAD, 0x33, 0xB5, 0x95, 
+0xAD, 0x33, 0xAD, 0x33, 0xAD, 0x53, 0xBD, 0xD4, 
+0xB5, 0x94, 0xBD, 0x94, 0xBD, 0xB5, 0xB5, 0x74, 
+0xBD, 0x94, 0xB5, 0x53, 0xAD, 0x12, 0xAD, 0x33, 
+0xBD, 0xB5, 0xBD, 0xB4, 0xAD, 0x51, 0x9C, 0xAF, 
+0x9C, 0xAF, 0x9C, 0xB0, 0x94, 0x4E, 0x94, 0x4E, 
+0x9C, 0x90, 0x94, 0x8F, 0x83, 0xCC, 0x94, 0x6F, 
+0xA4, 0xF1, 0xA4, 0xD0, 0xA4, 0xF0, 0xAD, 0x51, 
+0xAD, 0x10, 0xA4, 0xAF, 0xA4, 0xAF, 0xAD, 0x11, 
+0xA4, 0xD1, 0x94, 0x6F, 0x8C, 0x2E, 0x8C, 0x2E, 
+0x9C, 0xB0, 0x9C, 0xAF, 0x9C, 0xB0, 0x9C, 0xB0, 
+0x9C, 0xB0, 0xA4, 0xD1, 0xB5, 0x73, 0xB5, 0xB4, 
+0xAD, 0x32, 0xB5, 0x94, 0xAD, 0x53, 0xB5, 0xB4, 
+0xBD, 0xD5, 0xC5, 0xF5, 0xB5, 0x94, 0xAD, 0x53, 
+0xB5, 0x74, 0x9C, 0xD0, 0x94, 0x6F, 0xA4, 0xD1, 
+0x8C, 0x4F, 0x94, 0x90, 0x73, 0xAE, 0x94, 0x70, 
+0x9C, 0xB0, 0x94, 0x2E, 0x94, 0x4E, 0x8C, 0x2E, 
+0x9C, 0xB0, 0x9C, 0xD1, 0x9C, 0xD1, 0x9C, 0xD1, 
+0xA4, 0xF2, 0xB5, 0x94, 0xAD, 0x12, 0x94, 0x70, 
+0x94, 0x6F, 0xA4, 0xF1, 0xA5, 0x12, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xAD, 0x31, 0xB5, 0x72, 0xAD, 0x12, 
+0xB5, 0x53, 0x9C, 0x90, 0x9C, 0xB1, 0x9C, 0xB0, 
+0x9C, 0xB1, 0x9C, 0xB0, 0x94, 0x6F, 0x94, 0x6F, 
+0x94, 0x6F, 0x9C, 0x8F, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xB5, 0x73, 0xA4, 0xF2, 0x9C, 0xD1, 0xAD, 0x53, 
+0xAD, 0x33, 0xB5, 0x94, 0x83, 0xCE, 0x73, 0x6C, 
+0x83, 0xCE, 0x8C, 0x2F, 0x9C, 0xB2, 0xA4, 0xD2, 
+0x9C, 0xB1, 0x9C, 0xB1, 0x94, 0x70, 0x8C, 0x4F, 
+0x84, 0x0F, 0x73, 0xAD, 0x63, 0x0B, 0x4A, 0x8A, 
+0x42, 0x08, 0x31, 0xA7, 0x29, 0x86, 0x29, 0x86, 
+0x31, 0xA7, 0x52, 0x8B, 0x6B, 0x4E, 0x84, 0x11, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x55, 0x9D, 0x14, 
+0x9C, 0xF4, 0x7B, 0xCF, 0x62, 0xC9, 0x73, 0x4A, 
+0x7B, 0x6A, 0x83, 0xAB, 0x8B, 0xEC, 0x94, 0x4D, 
+0x9C, 0x4D, 0x9C, 0x6E, 0xA4, 0x8F, 0x9C, 0x6E, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xCF, 0xA4, 0x8F, 
+0x9C, 0x8F, 0x94, 0x4E, 0x94, 0x2D, 0x9C, 0x6E, 
+0x94, 0x4E, 0x94, 0x2D, 0x94, 0x2D, 0x8B, 0xEC, 
+0x9C, 0x4D, 0xB4, 0xEF, 0x94, 0x0C, 0x73, 0x6B, 
+0x7B, 0x8C, 0x73, 0x6B, 0x83, 0xED, 0x8C, 0x4E, 
+0x8C, 0x0E, 0x94, 0x4F, 0x9C, 0xB0, 0x8C, 0x4F, 
+0x94, 0x6F, 0x73, 0x6B, 0x9C, 0x90, 0xAD, 0x52, 
+0x9C, 0xD1, 0x83, 0xEE, 0x7B, 0xAC, 0x8C, 0x2F, 
+0x94, 0x70, 0x9C, 0xD1, 0x94, 0x70, 0x63, 0x2B, 
+0x4A, 0x48, 0x39, 0xE7, 0x39, 0xC6, 0x41, 0xE7, 
+0x42, 0x07, 0x42, 0x28, 0x4A, 0x48, 0x4A, 0x48, 
+0x5A, 0xCA, 0x63, 0x2C, 0x7B, 0xCE, 0x8C, 0x71, 
+0x94, 0xB2, 0x7B, 0xEF, 0x84, 0x31, 0xA4, 0xF4, 
+0x94, 0x71, 0x4A, 0x69, 0x84, 0x30, 0xBD, 0xB4, 
+0xB5, 0x73, 0xB5, 0x94, 0x9C, 0xB0, 0x94, 0xB0, 
+0x63, 0x0A, 0x42, 0x27, 0x31, 0x85, 0x41, 0xE7, 
+0x52, 0xAA, 0x63, 0x2C, 0x6B, 0x4D, 0x5A, 0xEB, 
+0x6B, 0x6D, 0x7B, 0xAF, 0x94, 0xB3, 0xA5, 0x14, 
+0xBD, 0xD8, 0xCE, 0x59, 0x94, 0x93, 0xA5, 0x15, 
+0xCE, 0x7A, 0xC6, 0x18, 0xBD, 0xF6, 0xB5, 0x94, 
+0xAD, 0x53, 0x8C, 0x4E, 0x73, 0x8B, 0x94, 0x8F, 
+0xA5, 0x11, 0xA5, 0x11, 0x9C, 0x8F, 0x9C, 0x8E, 
+0x94, 0x6F, 0x73, 0x8C, 0x73, 0x8C, 0x84, 0x2F, 
+0x8C, 0x4F, 0x4A, 0x48, 0x8C, 0x70, 0xA5, 0x33, 
+0xA5, 0x32, 0xA5, 0x12, 0x94, 0x6F, 0x9C, 0x8F, 
+0x94, 0x6F, 0xA5, 0x12, 0x94, 0x90, 0x9C, 0xD1, 
+0xA5, 0x32, 0xB5, 0x94, 0x7B, 0xAD, 0x7B, 0xEE, 
+0x84, 0x2F, 0x94, 0xB1, 0xAD, 0x32, 0xA4, 0xF1, 
+0x8C, 0x4E, 0x94, 0x8F, 0xA4, 0xF1, 0xB5, 0x93, 
+0xD6, 0x77, 0xCE, 0x56, 0xD6, 0x76, 0xDE, 0x96, 
+0xD6, 0x55, 0xBD, 0x72, 0xA4, 0xCF, 0xA4, 0xAE, 
+0xAD, 0x31, 0xBD, 0xD3, 0xC5, 0xF4, 0xCE, 0x55, 
+0xCE, 0x36, 0xCE, 0x78, 0x9C, 0xD3, 0x52, 0xAB, 
+0x94, 0xB2, 0xD6, 0xB8, 0xC6, 0x15, 0xCE, 0x35, 
+0xBD, 0xF4, 0xD6, 0x77, 0xC6, 0x15, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xC6, 0x15, 0xB5, 0x93, 0xCE, 0x36, 
+0xD6, 0x76, 0xE6, 0xD8, 0x94, 0x90, 0xBD, 0x94, 
+0xA4, 0xD1, 0xCE, 0x57, 0xBD, 0xD5, 0x9C, 0xD1, 
+0x8C, 0x4F, 0xAD, 0x12, 0xA5, 0x11, 0xA4, 0xF1, 
+0xB5, 0x53, 0xAD, 0x12, 0xB5, 0x53, 0xB5, 0x73, 
+0xA5, 0x12, 0xAD, 0x52, 0xA5, 0x11, 0xAD, 0x32, 
+0xA4, 0xF1, 0x94, 0x6F, 0xBD, 0x94, 0xBD, 0xB4, 
+0xBD, 0x94, 0xAD, 0x52, 0x8C, 0x2E, 0xB5, 0x73, 
+0xA4, 0xF1, 0xAD, 0x12, 0xA5, 0x12, 0xB5, 0x73, 
+0xC5, 0xD4, 0xBD, 0x93, 0xB5, 0x32, 0x94, 0x6F, 
+0x8C, 0x2E, 0x94, 0x4F, 0xAD, 0x12, 0xBD, 0xB4, 
+0xBD, 0x94, 0xBD, 0xB4, 0x9C, 0x90, 0xB5, 0x53, 
+0xA4, 0xF1, 0xAD, 0x12, 0xA5, 0x11, 0x9C, 0xB0, 
+0xA4, 0xD1, 0xAC, 0xF1, 0xAD, 0x12, 0xB5, 0x53, 
+0xA4, 0xF1, 0xB5, 0x53, 0xAD, 0x52, 0xAD, 0x32, 
+0xAD, 0x12, 0xAD, 0x12, 0xB5, 0x52, 0xB5, 0x53, 
+0xBD, 0x94, 0xCD, 0xF6, 0xA4, 0xD1, 0x94, 0x6F, 
+0xB5, 0x52, 0xB5, 0x52, 0xAD, 0x32, 0xAD, 0x11, 
+0xAD, 0x11, 0xAD, 0x11, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xCD, 0xF5, 0xBD, 0xB4, 0xBD, 0x94, 0xBD, 0x94, 
+0xC5, 0xB4, 0xBD, 0xB4, 0xC5, 0xD5, 0xC5, 0xD5, 
+0xCE, 0x16, 0xCE, 0x15, 0xC5, 0xF5, 0xCE, 0x15, 
+0xC5, 0xD5, 0xBD, 0x94, 0xB5, 0x32, 0xB5, 0x52, 
+0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x53, 0xAD, 0x32, 
+0xAD, 0x32, 0xA4, 0xF2, 0xB5, 0x32, 0xC5, 0xB4, 
+0xB5, 0x53, 0xB5, 0x73, 0xA4, 0xF2, 0x9C, 0xD1, 
+0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x52, 0xAD, 0x32, 
+0xAC, 0xF2, 0xA4, 0xF1, 0x9C, 0xD1, 0x8C, 0x2F, 
+0x94, 0x50, 0xA4, 0xF2, 0xA4, 0xD1, 0x9C, 0x90, 
+0x94, 0x90, 0x94, 0x6F, 0x94, 0x90, 0x94, 0x6F, 
+0x9C, 0xB0, 0x8C, 0x2E, 0xBD, 0x93, 0xC5, 0xD4, 
+0xA4, 0xF1, 0xAD, 0x32, 0xB5, 0x73, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xA5, 0x12, 0xA4, 0xF2, 0xA4, 0xF1, 
+0xA4, 0xF2, 0x9C, 0xB0, 0x94, 0x6F, 0x83, 0xCD, 
+0x8C, 0x2E, 0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x94, 
+0xB5, 0x74, 0xBD, 0xB5, 0xBD, 0xD5, 0xAD, 0x74, 
+0xA5, 0x13, 0x83, 0xEE, 0x6B, 0x2C, 0x83, 0xEE, 
+0x9C, 0xB1, 0xAD, 0x13, 0xAD, 0x33, 0xA4, 0xF2, 
+0x94, 0x91, 0x8C, 0x2F, 0x7B, 0xEE, 0x6B, 0x6D, 
+0x63, 0x0C, 0x52, 0x8A, 0x3A, 0x08, 0x31, 0xA7, 
+0x29, 0x66, 0x29, 0x86, 0x31, 0xA6, 0x39, 0xE8, 
+0xA5, 0x55, 0xA5, 0x35, 0xA5, 0x35, 0x9D, 0x14, 
+0x94, 0xD3, 0x83, 0xEF, 0x6B, 0x2B, 0x6B, 0x2A, 
+0x62, 0xE9, 0x62, 0xE9, 0x73, 0x4A, 0x7B, 0x6B, 
+0x83, 0xCB, 0x83, 0xCB, 0x8B, 0xEC, 0x8B, 0xCC, 
+0x9C, 0x6E, 0x9C, 0x8E, 0x9C, 0x6E, 0x94, 0x0D, 
+0xAC, 0xD0, 0xBD, 0x51, 0xB5, 0x30, 0xA4, 0xAF, 
+0xAC, 0xD0, 0xAC, 0xF0, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xEF, 0xA4, 0xAF, 
+0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x8F, 0x9C, 0x6E, 
+0x9C, 0x6E, 0x94, 0x4E, 0x8C, 0x0D, 0x83, 0xCC, 
+0x83, 0xCC, 0x83, 0xCC, 0x7B, 0x8C, 0x7B, 0x8B, 
+0x83, 0xCC, 0x7B, 0x8B, 0x6B, 0x2A, 0x62, 0xE9, 
+0x62, 0xE9, 0x63, 0x0A, 0x62, 0xE9, 0x6B, 0x2A, 
+0x52, 0x68, 0x39, 0xC6, 0x39, 0xC6, 0x39, 0xC6, 
+0x39, 0xC6, 0x31, 0xA6, 0x42, 0x07, 0x4A, 0x48, 
+0x5A, 0xCA, 0x63, 0x2C, 0x83, 0xEF, 0x8C, 0x50, 
+0x9C, 0xB2, 0x94, 0x71, 0xB5, 0x96, 0xBD, 0xD7, 
+0x8C, 0x51, 0x31, 0x86, 0x7B, 0xEE, 0xB5, 0x73, 
+0xB5, 0x73, 0xBD, 0xB4, 0xB5, 0x93, 0xA5, 0x11, 
+0x7B, 0xAC, 0x9C, 0x90, 0x4A, 0x27, 0x42, 0x07, 
+0x42, 0x27, 0x52, 0x89, 0x5A, 0xEB, 0x63, 0x0B, 
+0x5A, 0xEB, 0x63, 0x0C, 0x94, 0x72, 0xA5, 0x35, 
+0xAD, 0x55, 0x8C, 0x51, 0x83, 0xF0, 0x8C, 0x31, 
+0xC6, 0x18, 0xE7, 0x1C, 0x94, 0xB2, 0xB5, 0x94, 
+0xBD, 0xF5, 0xA5, 0x12, 0xA5, 0x11, 0x9C, 0xD0, 
+0x8C, 0x6E, 0x9C, 0xD0, 0x83, 0xCB, 0x9C, 0x8E, 
+0x8C, 0x4E, 0x8C, 0x2E, 0x84, 0x2E, 0x8C, 0x6F, 
+0x84, 0x0E, 0x4A, 0x48, 0x8C, 0x70, 0xB5, 0x94, 
+0xB5, 0x94, 0xB5, 0x94, 0x9C, 0x8F, 0xA4, 0xAF, 
+0x94, 0x6F, 0x9C, 0xF2, 0xA5, 0x12, 0xAD, 0x73, 
+0xAD, 0x73, 0xB5, 0x73, 0x8C, 0x2F, 0x8C, 0x70, 
+0x8C, 0x90, 0x9C, 0xF1, 0xB5, 0x93, 0xBD, 0x93, 
+0x9C, 0x8F, 0x8C, 0x4E, 0xAD, 0x32, 0xBD, 0xF4, 
+0xD6, 0x77, 0xC6, 0x15, 0xD6, 0x96, 0xDE, 0xB6, 
+0xD6, 0x76, 0xBD, 0x92, 0xAC, 0xEF, 0x9C, 0x8E, 
+0xA4, 0xAF, 0xAD, 0x31, 0xB5, 0x72, 0xC6, 0x15, 
+0xC6, 0x15, 0xCE, 0x78, 0x9C, 0xF3, 0x8C, 0x72, 
+0xA5, 0x54, 0xD6, 0x98, 0xD6, 0x76, 0xD6, 0x76, 
+0xC6, 0x15, 0xCE, 0x36, 0xCE, 0x35, 0xCE, 0x35, 
+0xD6, 0x97, 0xD6, 0x56, 0xAD, 0x52, 0xCE, 0x36, 
+0xDE, 0x97, 0xDE, 0xD8, 0x94, 0x6F, 0xB5, 0x74, 
+0xA4, 0xF2, 0xCE, 0x36, 0xBD, 0xB4, 0x9C, 0xB0, 
+0x94, 0x70, 0xA4, 0xF1, 0xAD, 0x32, 0xA4, 0xF1, 
+0xB5, 0x73, 0xB5, 0x73, 0xBD, 0xD5, 0xC5, 0xF5, 
+0xA4, 0xF1, 0xAD, 0x12, 0x83, 0xED, 0x9C, 0xB0, 
+0xB5, 0x94, 0x9C, 0xB0, 0xBD, 0xB4, 0xB5, 0xB4, 
+0xB5, 0x94, 0xAD, 0x32, 0x8C, 0x2E, 0xA5, 0x12, 
+0x9C, 0xB0, 0x94, 0x8F, 0x9C, 0xB0, 0xA5, 0x11, 
+0x9C, 0xAF, 0xAD, 0x10, 0xB5, 0x31, 0xA4, 0xF1, 
+0x94, 0x6F, 0x9C, 0x90, 0xBD, 0xB5, 0xC5, 0xD5, 
+0xBD, 0xB4, 0xB5, 0x73, 0x94, 0x6F, 0xA4, 0xF1, 
+0xA4, 0xD0, 0x9C, 0xAF, 0x94, 0x4E, 0x8C, 0x2D, 
+0xA4, 0xD0, 0xAD, 0x32, 0xBD, 0x93, 0xBD, 0xB4, 
+0xAD, 0x11, 0xA4, 0xF1, 0x9C, 0x8F, 0x9C, 0x8F, 
+0x9C, 0x8F, 0x9C, 0xB0, 0xAD, 0x32, 0xA4, 0xF1, 
+0x94, 0x4F, 0xB5, 0x53, 0x9C, 0x90, 0xC5, 0xD4, 
+0xBD, 0x93, 0xBD, 0x94, 0xC5, 0xF5, 0xC5, 0xB4, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0xB4, 0xA4, 0xF1, 
+0xAD, 0x32, 0xBD, 0x94, 0xAC, 0xF1, 0x9C, 0xB0, 
+0x9C, 0x8F, 0x94, 0x4F, 0xA4, 0xD1, 0x9C, 0x6F, 
+0x8C, 0x0E, 0x8C, 0x0D, 0x94, 0x4F, 0x9C, 0x90, 
+0xA4, 0xD1, 0xAC, 0xF1, 0xAC, 0xF1, 0xA4, 0xD1, 
+0xB5, 0x73, 0xB5, 0x32, 0xA4, 0xF1, 0xAD, 0x12, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xB5, 0x53, 0xB5, 0x53, 
+0xBD, 0x73, 0xB5, 0x32, 0xAD, 0x12, 0xBD, 0x94, 
+0xCE, 0x36, 0xCD, 0xF6, 0xCD, 0xF5, 0xCE, 0x16, 
+0xCE, 0x36, 0xCE, 0x16, 0xCE, 0x16, 0xCE, 0x36, 
+0xCE, 0x36, 0xCE, 0x16, 0xD6, 0x36, 0xCD, 0xF5, 
+0xC5, 0xD5, 0xC5, 0xB4, 0xBD, 0x94, 0xB5, 0x53, 
+0xB5, 0x53, 0xAD, 0x12, 0xAD, 0x32, 0xAC, 0xF1, 
+0x94, 0x4F, 0x83, 0xED, 0x8C, 0x0E, 0x83, 0xED, 
+0x83, 0xCD, 0x7B, 0x8C, 0x7B, 0xAD, 0x7B, 0xAD, 
+0x7B, 0xAD, 0x83, 0xCD, 0x8C, 0x2F, 0x94, 0x4F, 
+0x94, 0x4F, 0x94, 0x90, 0xAD, 0x12, 0xBD, 0xB4, 
+0xBD, 0xD5, 0xC5, 0xD5, 0xCE, 0x36, 0xC6, 0x16, 
+0xCE, 0x37, 0xCE, 0x17, 0x9C, 0xB1, 0x8C, 0x2F, 
+0x7B, 0xAD, 0x73, 0x8C, 0x83, 0xEE, 0x9C, 0xD1, 
+0xAD, 0x33, 0xA5, 0x13, 0x9C, 0xB1, 0x8C, 0x50, 
+0x84, 0x0F, 0x7B, 0xEF, 0x73, 0xAE, 0x6B, 0x8D, 
+0x63, 0x0C, 0x4A, 0x69, 0x31, 0xC7, 0x31, 0x86, 
+0x94, 0xD3, 0x9D, 0x14, 0x9C, 0xF4, 0x94, 0xB3, 
+0x94, 0xB3, 0x83, 0xEF, 0x73, 0x8C, 0x7B, 0x8C, 
+0x7B, 0xAC, 0x6B, 0x2A, 0x7B, 0x8B, 0x8C, 0x0D, 
+0x94, 0x2E, 0x94, 0x2D, 0x94, 0x2E, 0x8C, 0x0D, 
+0x94, 0x2D, 0x9C, 0x6E, 0x9C, 0x8F, 0x73, 0x2A, 
+0x6A, 0xE8, 0x94, 0x2D, 0xA4, 0x8E, 0x9C, 0x6E, 
+0x83, 0xAB, 0x83, 0x8B, 0x7B, 0x6B, 0x7B, 0x6B, 
+0x73, 0x29, 0x73, 0x29, 0x8C, 0x0D, 0x7B, 0x6A, 
+0x8B, 0xEC, 0x8B, 0xEC, 0x8B, 0xED, 0x8B, 0xCC, 
+0x8B, 0xEC, 0x8B, 0xED, 0x94, 0x0D, 0x83, 0xCC, 
+0x83, 0xAC, 0x8B, 0xED, 0x8C, 0x0D, 0x9C, 0x4E, 
+0x9C, 0x4E, 0xAC, 0xD0, 0x94, 0x0D, 0x8C, 0x2E, 
+0x94, 0x0E, 0x94, 0x2E, 0x94, 0x4E, 0x94, 0x2E, 
+0x8C, 0x0E, 0x52, 0x68, 0x31, 0xA6, 0x39, 0xC6, 
+0x31, 0x85, 0x31, 0x85, 0x42, 0x07, 0x4A, 0x28, 
+0x52, 0x89, 0x52, 0xAA, 0x63, 0x0B, 0x73, 0x8D, 
+0x8C, 0x30, 0x94, 0x71, 0xB5, 0x96, 0xBD, 0xD7, 
+0xB5, 0x76, 0x39, 0xC7, 0x39, 0xE7, 0x8C, 0x2E, 
+0x8C, 0x0D, 0x83, 0xCC, 0x83, 0xCC, 0x83, 0xAC, 
+0x83, 0xCD, 0xAD, 0x10, 0x9C, 0x6E, 0x6B, 0x0A, 
+0x42, 0x07, 0x4A, 0x69, 0x52, 0x89, 0x63, 0x0C, 
+0x52, 0xAA, 0x5A, 0xEC, 0x63, 0x2D, 0x84, 0x10, 
+0xA5, 0x14, 0x73, 0x8E, 0x63, 0x0D, 0x8C, 0x51, 
+0x94, 0xB3, 0xAD, 0x55, 0x7B, 0xEF, 0xB5, 0x74, 
+0xB5, 0x74, 0x9C, 0xB0, 0x9C, 0xB0, 0xA4, 0xD0, 
+0x8C, 0x4E, 0x9C, 0x8F, 0x8B, 0xEC, 0x94, 0x0D, 
+0x62, 0xC8, 0x6B, 0x4A, 0x73, 0x6B, 0x83, 0xED, 
+0x83, 0xED, 0x4A, 0x68, 0x7C, 0x0E, 0xAD, 0x73, 
+0xBD, 0xB4, 0xB5, 0x73, 0x9C, 0x8E, 0xA4, 0xAF, 
+0x8C, 0x2D, 0xA5, 0x12, 0xA4, 0xF1, 0xAD, 0x32, 
+0xAD, 0x53, 0xAD, 0x32, 0x9C, 0xD1, 0x94, 0x90, 
+0x8C, 0x4F, 0xA5, 0x12, 0xBD, 0xD4, 0xBD, 0xD4, 
+0x94, 0x8F, 0x7B, 0xAC, 0xB5, 0x93, 0xCE, 0x35, 
+0xCE, 0x56, 0xAD, 0x51, 0xCE, 0x14, 0xD6, 0x96, 
+0xDE, 0xB6, 0xBD, 0x92, 0xB5, 0x10, 0x94, 0x2C, 
+0x9C, 0x8E, 0xB5, 0x51, 0xAD, 0x51, 0xC5, 0xF4, 
+0xBD, 0xD4, 0xCE, 0x78, 0xAD, 0x55, 0xA4, 0xF4, 
+0xC6, 0x17, 0xCE, 0x36, 0xCE, 0x35, 0xB5, 0x93, 
+0xCE, 0x55, 0xCE, 0x56, 0xBD, 0xD4, 0xCE, 0x36, 
+0xD6, 0x97, 0xCE, 0x55, 0xCE, 0x56, 0xD6, 0x77, 
+0xDE, 0xB7, 0xDE, 0xD8, 0x8C, 0x4F, 0xB5, 0x74, 
+0xA4, 0xF2, 0xCE, 0x37, 0xBD, 0x94, 0x9C, 0x90, 
+0x94, 0x90, 0xA4, 0xF1, 0xA5, 0x11, 0xAD, 0x32, 
+0xBD, 0xD5, 0xB5, 0x73, 0xB5, 0x73, 0xCE, 0x36, 
+0xB5, 0x73, 0xB5, 0x74, 0xAD, 0x12, 0x94, 0x90, 
+0xCE, 0x36, 0xC6, 0x16, 0xC5, 0xF5, 0xC6, 0x16, 
+0xC5, 0xF5, 0xB5, 0x94, 0x8C, 0x2E, 0xA4, 0xF2, 
+0x94, 0x6F, 0x8C, 0x2E, 0x94, 0x8F, 0x9C, 0xAF, 
+0xA4, 0xAF, 0xC5, 0xB3, 0xC5, 0xB3, 0xA4, 0xF1, 
+0x83, 0xED, 0xA4, 0xD1, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x73, 0xAD, 0x32, 0x94, 0x6F, 0xB5, 0x32, 
+0xB5, 0x72, 0xA4, 0xD0, 0xA4, 0xF1, 0xA4, 0xD0, 
+0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x52, 0xAD, 0x11, 
+0x94, 0x4E, 0x94, 0x6E, 0x8C, 0x2E, 0x94, 0x4E, 
+0x94, 0x4E, 0x8C, 0x2D, 0x9C, 0x8F, 0xAD, 0x12, 
+0x94, 0x4F, 0xBD, 0xB4, 0xBD, 0x93, 0xCE, 0x15, 
+0xC5, 0xF5, 0xC5, 0xB4, 0xCE, 0x15, 0xC5, 0xF4, 
+0xC5, 0xF5, 0xC5, 0xD4, 0xBD, 0xB3, 0xC5, 0xF5, 
+0xBD, 0xB4, 0xAD, 0x32, 0x8C, 0x2E, 0x8C, 0x2E, 
+0xA4, 0xF1, 0x9C, 0xB0, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xA4, 0xD1, 0x94, 0x90, 0x9C, 0x90, 0x94, 0x90, 
+0x8C, 0x2F, 0xAD, 0x12, 0xBD, 0xB4, 0xCE, 0x36, 
+0xCE, 0x36, 0xCE, 0x16, 0xD6, 0x57, 0xD6, 0x57, 
+0xA4, 0xF1, 0x83, 0xED, 0x83, 0xED, 0xAC, 0xF2, 
+0xB5, 0x32, 0x94, 0x4F, 0x94, 0x4F, 0x9C, 0x90, 
+0x9C, 0x6F, 0x9C, 0xB0, 0x94, 0x6F, 0x8C, 0x4E, 
+0x94, 0x6F, 0xA4, 0xF1, 0x9C, 0x90, 0x9C, 0x6F, 
+0xA4, 0xD0, 0xAC, 0xF1, 0xB5, 0x53, 0xAD, 0x11, 
+0xB5, 0x32, 0xB5, 0x32, 0xAD, 0x11, 0xAC, 0xF1, 
+0xB5, 0x32, 0xB5, 0x53, 0xAD, 0x32, 0xB5, 0x53, 
+0xB5, 0x33, 0xB5, 0x53, 0xBD, 0x73, 0xBD, 0x94, 
+0xB5, 0x53, 0xB5, 0x73, 0xB5, 0x53, 0x94, 0x70, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xA4, 0xF1, 0xB5, 0x53, 
+0xAD, 0x32, 0xAD, 0x32, 0xB5, 0x53, 0xB5, 0x52, 
+0xB5, 0x52, 0xBD, 0x93, 0xBD, 0x93, 0xBD, 0xB4, 
+0xBD, 0x94, 0xBD, 0xB4, 0x9C, 0x90, 0xA5, 0x12, 
+0xAD, 0x33, 0x9C, 0xD2, 0x94, 0x70, 0x7B, 0xAD, 
+0x7B, 0x8D, 0x7B, 0xCE, 0x8C, 0x50, 0x9C, 0xB1, 
+0x9C, 0xD2, 0x9C, 0xB1, 0x94, 0x70, 0x8C, 0x50, 
+0x8C, 0x50, 0x84, 0x30, 0x7B, 0xCE, 0x5A, 0xEB, 
+0xAD, 0x75, 0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x35, 
+0x9C, 0xF4, 0x84, 0x10, 0x6B, 0x2B, 0x7B, 0x8C, 
+0x83, 0xED, 0x84, 0x0D, 0x84, 0x0D, 0x8C, 0x0D, 
+0x8C, 0x0D, 0x8C, 0x2E, 0xA4, 0xB0, 0x94, 0x6F, 
+0x94, 0x4E, 0x7B, 0x8B, 0x8B, 0xED, 0x83, 0xCC, 
+0x94, 0x6E, 0xA4, 0xCF, 0xAC, 0xAF, 0xB5, 0x11, 
+0xA4, 0x8F, 0x9C, 0x4E, 0x9C, 0x4F, 0xA4, 0x90, 
+0x8B, 0xED, 0x8C, 0x2E, 0xA4, 0xB0, 0x8C, 0x0D, 
+0xA4, 0xB0, 0xA4, 0xD0, 0xB5, 0x52, 0x9C, 0x8F, 
+0x94, 0x4F, 0x9C, 0x8F, 0xA4, 0xF0, 0x94, 0x6E, 
+0x83, 0xCC, 0x9C, 0x6F, 0xB5, 0x32, 0xB5, 0x72, 
+0x83, 0xCC, 0x9C, 0x4E, 0x7B, 0x4A, 0x8B, 0xCD, 
+0x83, 0xCD, 0x83, 0xAC, 0x83, 0xAC, 0x7B, 0x8B, 
+0x8B, 0xEE, 0x73, 0x8D, 0x4A, 0x28, 0x39, 0xE7, 
+0x31, 0xA6, 0x31, 0x85, 0x39, 0xC6, 0x41, 0xE7, 
+0x4A, 0x28, 0x4A, 0x28, 0x5A, 0xCB, 0x73, 0x8D, 
+0x8C, 0x30, 0x94, 0x92, 0xA4, 0xF3, 0xC6, 0x18, 
+0xBD, 0xD7, 0x83, 0xF0, 0x20, 0xE4, 0x8C, 0x4F, 
+0xA4, 0xB0, 0x94, 0x2D, 0x9C, 0x8F, 0x9C, 0x6F, 
+0x9C, 0x6F, 0xA4, 0xAF, 0xA4, 0xAF, 0x9C, 0x6F, 
+0x62, 0xEA, 0x52, 0x89, 0x5B, 0x0B, 0x73, 0xAE, 
+0x52, 0x8A, 0x5A, 0xAA, 0x4A, 0x49, 0x63, 0x0C, 
+0x8C, 0x51, 0x94, 0x92, 0xA4, 0xF4, 0xB5, 0x97, 
+0xB5, 0x96, 0xCE, 0x59, 0xB5, 0xB6, 0xCE, 0x38, 
+0xBD, 0x95, 0x9C, 0x70, 0x9C, 0x4E, 0x9C, 0x4D, 
+0x94, 0x4D, 0x9C, 0x6E, 0xA4, 0x8E, 0xBD, 0x51, 
+0xBD, 0x71, 0xB5, 0x30, 0xAC, 0xEF, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xA4, 0xAF, 0xAC, 0xD0, 0xA4, 0xAF, 
+0xA4, 0xCF, 0xAC, 0xCF, 0xB5, 0x30, 0xA4, 0x8E, 
+0x83, 0xCC, 0x8B, 0xEC, 0x83, 0xAB, 0x83, 0xEC, 
+0x94, 0x4D, 0x83, 0xEC, 0x83, 0xED, 0x7B, 0xAC, 
+0x83, 0xED, 0x9C, 0xAF, 0xAD, 0x52, 0xAD, 0x31, 
+0x8C, 0x4E, 0x5A, 0xC8, 0xAD, 0x32, 0xCE, 0x56, 
+0xBD, 0xB3, 0x94, 0x6E, 0xBD, 0xB3, 0xD6, 0x55, 
+0xDE, 0x76, 0xA4, 0xAF, 0xB5, 0x30, 0x94, 0x0C, 
+0xA4, 0xEF, 0xBD, 0xD3, 0xB5, 0x72, 0xC5, 0xD4, 
+0xB5, 0x72, 0xC6, 0x17, 0xB5, 0x96, 0xA5, 0x35, 
+0xD6, 0x78, 0xD6, 0x76, 0xCE, 0x35, 0xBD, 0xD4, 
+0xCE, 0x15, 0xD6, 0x76, 0xBD, 0xD4, 0xD6, 0x76, 
+0xDE, 0xB7, 0xD6, 0x76, 0xD6, 0x97, 0xDE, 0x97, 
+0xDE, 0xB8, 0xDE, 0xD8, 0x94, 0x70, 0xB5, 0x53, 
+0xB5, 0x73, 0xCE, 0x36, 0xAD, 0x53, 0x9C, 0xB0, 
+0x9C, 0xD0, 0xC5, 0xF5, 0xBD, 0xB4, 0xB5, 0xB4, 
+0xC5, 0xF5, 0xBD, 0xD5, 0xCE, 0x36, 0xC5, 0xF5, 
+0xBD, 0xB4, 0xC5, 0xF5, 0xBD, 0xD5, 0xAD, 0x33, 
+0xD6, 0x77, 0xCE, 0x57, 0xC5, 0xF5, 0xC6, 0x16, 
+0xBD, 0xD5, 0xBD, 0xB4, 0x8C, 0x4E, 0x9C, 0xD0, 
+0x8C, 0x2E, 0x7B, 0xAC, 0x8C, 0x2E, 0x7B, 0xCC, 
+0x8C, 0x0D, 0x9C, 0xAF, 0xA4, 0xD0, 0xA4, 0xF1, 
+0x7B, 0xAC, 0xA5, 0x12, 0xBD, 0xB4, 0xAD, 0x32, 
+0xB5, 0x73, 0xA4, 0xF1, 0x8C, 0x2E, 0xAD, 0x32, 
+0xAD, 0x11, 0xA4, 0xCF, 0x9C, 0x8F, 0x9C, 0x6E, 
+0xB5, 0x73, 0x9C, 0xB0, 0xAD, 0x11, 0xA4, 0xF0, 
+0x9C, 0xAF, 0xA4, 0xF1, 0x9C, 0xAF, 0x9C, 0x8F, 
+0x8C, 0x2E, 0x94, 0x6E, 0xAD, 0x11, 0xB5, 0x73, 
+0x94, 0x6F, 0xBD, 0x94, 0xA4, 0xF1, 0xAD, 0x31, 
+0xBD, 0xB3, 0xC5, 0xF4, 0xCE, 0x35, 0xC5, 0xD4, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xC5, 0xD4, 0xBD, 0xD4, 
+0xBD, 0x93, 0xB5, 0x52, 0x9C, 0xB0, 0xAD, 0x32, 
+0xB5, 0x73, 0xAD, 0x32, 0xA4, 0xF1, 0xAD, 0x32, 
+0xAD, 0x32, 0xA4, 0xF1, 0xA4, 0xF1, 0x9C, 0xD1, 
+0x84, 0x0E, 0xAD, 0x32, 0xA5, 0x12, 0xA4, 0xF1, 
+0xA4, 0xD1, 0x9C, 0x90, 0xA4, 0xD1, 0xA4, 0xF1, 
+0x9C, 0x90, 0x9C, 0xB0, 0x9C, 0xD1, 0x9C, 0x90, 
+0xAD, 0x32, 0xA4, 0xF1, 0xAD, 0x11, 0xA4, 0xD1, 
+0xAD, 0x12, 0xB5, 0x73, 0xBD, 0x94, 0xB5, 0x93, 
+0xB5, 0x73, 0xBD, 0xD5, 0xC5, 0xF5, 0xB5, 0x73, 
+0xA5, 0x11, 0x94, 0x6F, 0xA4, 0xD0, 0x9C, 0x6F, 
+0x9C, 0x6F, 0x9C, 0x6F, 0xA4, 0xB0, 0xA4, 0xD0, 
+0xAD, 0x11, 0xAD, 0x11, 0xA4, 0xF1, 0xAD, 0x11, 
+0xAC, 0xF1, 0xA4, 0xF1, 0x9C, 0x8F, 0x94, 0x4F, 
+0x9C, 0x6F, 0xAC, 0xF1, 0xAD, 0x11, 0x94, 0x6F, 
+0xAC, 0xF1, 0x9C, 0x8F, 0x9C, 0x6F, 0xAD, 0x31, 
+0xAD, 0x31, 0xAD, 0x11, 0x9C, 0x8F, 0x9C, 0x6F, 
+0x94, 0x4E, 0x9C, 0x6F, 0x8C, 0x2D, 0x8C, 0x0D, 
+0x94, 0x4E, 0x9C, 0xB0, 0xAD, 0x32, 0xBD, 0x94, 
+0xAD, 0x12, 0xA5, 0x12, 0xAD, 0x32, 0xA5, 0x12, 
+0x9C, 0xB1, 0x8C, 0x0F, 0x6B, 0x2B, 0x8C, 0x30, 
+0x8C, 0x50, 0x94, 0x91, 0x94, 0x91, 0x8C, 0x70, 
+0x8C, 0x70, 0x8C, 0x50, 0x8C, 0x30, 0x7B, 0xCE, 
+0xAD, 0x76, 0xAD, 0x75, 0xAD, 0x55, 0xA5, 0x55, 
+0xA5, 0x35, 0x8C, 0x51, 0x5A, 0xC9, 0x73, 0x8B, 
+0x83, 0xCC, 0x84, 0x0D, 0x84, 0x0D, 0x8C, 0x4E, 
+0x8C, 0x2D, 0x8C, 0x0D, 0x94, 0x8F, 0x94, 0x6F, 
+0x9C, 0x90, 0x8C, 0x2E, 0x94, 0x4E, 0x52, 0x88, 
+0xA4, 0xD0, 0x9C, 0x8E, 0xA4, 0xAF, 0xAC, 0xD0, 
+0x9C, 0x8F, 0x9C, 0x8F, 0x94, 0x4E, 0xA4, 0xB0, 
+0x9C, 0x8F, 0xAD, 0x11, 0xA4, 0xF1, 0xA4, 0xF0, 
+0xA4, 0xF1, 0xAD, 0x31, 0xB5, 0x52, 0x9C, 0xAF, 
+0x94, 0x6F, 0xA4, 0xD0, 0xAD, 0x31, 0xB5, 0x52, 
+0x9C, 0xB0, 0xAD, 0x32, 0xB5, 0x52, 0xAD, 0x32, 
+0x94, 0x4E, 0x94, 0x4E, 0x73, 0x4A, 0x8C, 0x0D, 
+0x94, 0x2E, 0x8B, 0xCD, 0x7B, 0x8C, 0x73, 0x4B, 
+0x7B, 0xAD, 0x73, 0x8D, 0x62, 0xEB, 0x4A, 0x69, 
+0x41, 0xE7, 0x31, 0x85, 0x31, 0x65, 0x41, 0xE7, 
+0x41, 0xE7, 0x4A, 0x49, 0x52, 0x8A, 0x6B, 0x4C, 
+0x7B, 0xAE, 0x83, 0xEF, 0x94, 0x71, 0xB5, 0x76, 
+0xB5, 0x76, 0xD6, 0x7A, 0x4A, 0x6A, 0x73, 0x6C, 
+0x94, 0x2E, 0x7B, 0x8B, 0x73, 0x6B, 0x62, 0xC9, 
+0x62, 0xC9, 0x73, 0x4A, 0x73, 0x4A, 0x73, 0x4B, 
+0x73, 0x6B, 0x52, 0x89, 0x4A, 0x69, 0x5A, 0xEB, 
+0x52, 0xAA, 0x5A, 0xCB, 0x5A, 0xAA, 0x5A, 0xEB, 
+0x73, 0x8E, 0x84, 0x10, 0x9C, 0xD4, 0xC6, 0x39, 
+0xE6, 0xFC, 0xE7, 0x1C, 0xC5, 0xD7, 0xB5, 0x55, 
+0xD6, 0x59, 0xBD, 0x75, 0x8B, 0xED, 0x8B, 0xCB, 
+0x9C, 0x4D, 0x94, 0x2D, 0x9C, 0x4D, 0x93, 0xEB, 
+0xA4, 0x6D, 0xAC, 0xCF, 0xB4, 0xEF, 0xAC, 0xEF, 
+0xAC, 0xCF, 0xA4, 0x6E, 0xC5, 0x91, 0xBD, 0x30, 
+0xAC, 0xAE, 0xAC, 0xCF, 0xB5, 0x10, 0xB4, 0xEF, 
+0xA4, 0xAE, 0xB4, 0xEF, 0xBD, 0x51, 0xB4, 0xEF, 
+0xAC, 0xCF, 0xAC, 0xEF, 0xB5, 0x10, 0xB5, 0x10, 
+0xB5, 0x10, 0xB5, 0x10, 0xAC, 0xF0, 0xAC, 0xCF, 
+0xA4, 0x8E, 0x94, 0x2D, 0x94, 0x2D, 0x9C, 0x6D, 
+0x94, 0x2C, 0x83, 0xEB, 0x94, 0x4D, 0x9C, 0x8E, 
+0x9C, 0x8E, 0x7B, 0x6A, 0xBD, 0x51, 0xA4, 0xAE, 
+0x94, 0x4C, 0x9C, 0x6E, 0xC5, 0xD3, 0xBD, 0xB3, 
+0xB5, 0x53, 0xCE, 0x38, 0xB5, 0xB7, 0xAD, 0x35, 
+0xDE, 0x98, 0xCE, 0x35, 0xD6, 0x76, 0xC6, 0x15, 
+0xCE, 0x15, 0xDE, 0x97, 0xD6, 0x97, 0xD6, 0x56, 
+0xCE, 0x15, 0xD6, 0x97, 0xDE, 0xB7, 0xD6, 0x97, 
+0xDE, 0xB7, 0xDE, 0xB8, 0x94, 0x90, 0xAD, 0x53, 
+0xB5, 0x53, 0xD6, 0x77, 0xC5, 0xF5, 0xAD, 0x52, 
+0x94, 0x90, 0xB5, 0x93, 0xB5, 0x73, 0xB5, 0x93, 
+0xC6, 0x15, 0xB5, 0xB4, 0xBD, 0xD4, 0xBD, 0xD4, 
+0xB5, 0x93, 0xBD, 0xD4, 0xBD, 0xD4, 0xAD, 0x73, 
+0xD6, 0x77, 0xD6, 0x77, 0xAD, 0x73, 0xBD, 0xB4, 
+0xAD, 0x53, 0xB5, 0xB4, 0x84, 0x0D, 0x9C, 0xD1, 
+0x94, 0x8F, 0x8C, 0x0E, 0x8C, 0x2E, 0x83, 0xED, 
+0x9C, 0x8F, 0x9C, 0xCF, 0xAD, 0x31, 0xAD, 0x52, 
+0x94, 0x6F, 0xA5, 0x12, 0xBD, 0xB4, 0xB5, 0x53, 
+0xBD, 0x94, 0x94, 0x90, 0x7B, 0xCD, 0xA5, 0x11, 
+0x94, 0x6E, 0x9C, 0xAF, 0x94, 0x6E, 0x94, 0x4E, 
+0xAD, 0x31, 0x94, 0x6E, 0xA4, 0xF0, 0xAD, 0x11, 
+0x9C, 0x8F, 0xA4, 0xF0, 0xA4, 0xF0, 0xB5, 0x72, 
+0xA4, 0xF0, 0xB5, 0x52, 0xA4, 0xD0, 0xBD, 0x94, 
+0x94, 0x6F, 0xBD, 0x73, 0x9C, 0x8F, 0xAD, 0x32, 
+0xBD, 0xB3, 0xCE, 0x35, 0xC5, 0xD4, 0xBD, 0x93, 
+0xC5, 0xD4, 0xC5, 0xF4, 0xCE, 0x15, 0xCE, 0x35, 
+0xC5, 0xF4, 0xB5, 0x93, 0xBD, 0x94, 0xC5, 0xF5, 
+0xB5, 0x73, 0xB5, 0x53, 0xA4, 0xD1, 0xB5, 0x53, 
+0xAD, 0x33, 0xA4, 0xD1, 0xAD, 0x12, 0x9C, 0xB0, 
+0x8C, 0x2F, 0xB5, 0x53, 0xAD, 0x32, 0xAD, 0x52, 
+0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x52, 
+0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x53, 0xB5, 0x94, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x94, 0xA5, 0x12, 
+0xAD, 0x12, 0xB5, 0x73, 0xBD, 0xD5, 0xB5, 0x93, 
+0xB5, 0x93, 0xC5, 0xF5, 0xBD, 0xD4, 0xC5, 0xF5, 
+0xB5, 0x73, 0x9C, 0x90, 0x9C, 0xB0, 0xA5, 0x11, 
+0xA5, 0x11, 0xAD, 0x32, 0xB5, 0x52, 0xB5, 0x52, 
+0xB5, 0x52, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x11, 
+0xAD, 0x11, 0xA4, 0xF1, 0xA4, 0xD1, 0x94, 0x6F, 
+0x94, 0x6F, 0x94, 0x2E, 0xB5, 0x32, 0x9C, 0x6E, 
+0xB5, 0x71, 0xBD, 0x72, 0xBD, 0x71, 0xB5, 0x71, 
+0xBD, 0x92, 0xBD, 0x72, 0xBD, 0xB3, 0xB5, 0x52, 
+0xB5, 0x72, 0xB5, 0x52, 0xAD, 0x31, 0xAD, 0x32, 
+0xB5, 0x52, 0xBD, 0x93, 0xC5, 0xD4, 0xD6, 0x34, 
+0xCE, 0x14, 0xC5, 0xD3, 0xBD, 0x93, 0x8C, 0x0E, 
+0x9C, 0xD1, 0xAD, 0x33, 0x8C, 0x2F, 0xCE, 0x36, 
+0xC5, 0xD5, 0xB5, 0x53, 0x9C, 0xB1, 0x84, 0x2F, 
+0x84, 0x2F, 0x8C, 0x70, 0x8C, 0x50, 0x84, 0x2F, 
+0x8C, 0x92, 0x8C, 0x92, 0x8C, 0x92, 0x8C, 0x72, 
+0x94, 0x92, 0x7B, 0xCF, 0x42, 0x27, 0x63, 0x0A, 
+0x73, 0x4B, 0x73, 0x8C, 0x8C, 0x0D, 0x94, 0x4E, 
+0x8C, 0x0D, 0x8C, 0x4E, 0x94, 0x8F, 0x9C, 0xB0, 
+0x9C, 0xB0, 0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0xB0, 
+0x9C, 0xD0, 0xA4, 0x8E, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xA4, 0x8F, 0xA4, 0x8F, 0x94, 0x6F, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xAD, 0x11, 0xB5, 0x73, 0xAD, 0x32, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0x73, 0xA4, 0xF1, 
+0x94, 0x4E, 0xA4, 0xD0, 0xAD, 0x11, 0x94, 0x6E, 
+0x94, 0x6F, 0xAD, 0x32, 0xB5, 0x52, 0xB5, 0x52, 
+0x94, 0x2E, 0xA4, 0x8F, 0x7B, 0x8B, 0x9C, 0x4F, 
+0xA4, 0x6F, 0x8B, 0xCC, 0x83, 0xAC, 0x83, 0xAC, 
+0x83, 0xCD, 0x84, 0x2F, 0x84, 0x0F, 0x6B, 0x4C, 
+0x39, 0xC6, 0x39, 0xC7, 0x39, 0xC6, 0x39, 0xC7, 
+0x41, 0xE7, 0x42, 0x08, 0x4A, 0x49, 0x5A, 0xAA, 
+0x5A, 0xCB, 0x7B, 0xAE, 0x9C, 0xD3, 0xA4, 0xF4, 
+0xB5, 0x96, 0xD6, 0x9A, 0xBD, 0xB7, 0x94, 0x91, 
+0x9C, 0xB1, 0x8C, 0x2E, 0x9C, 0x90, 0x8C, 0x0D, 
+0x7B, 0xAC, 0x83, 0xED, 0x7B, 0xAC, 0x8C, 0x0D, 
+0x9C, 0xB0, 0x8C, 0x0E, 0x52, 0x89, 0x42, 0x27, 
+0x42, 0x28, 0x52, 0x8A, 0x52, 0x89, 0x5A, 0xAA, 
+0x52, 0x8A, 0x5A, 0xEB, 0x6B, 0x4E, 0xB5, 0x76, 
+0xD6, 0x7A, 0xDE, 0xBB, 0xCE, 0x19, 0xCE, 0x18, 
+0xD6, 0x59, 0xBD, 0x96, 0xA4, 0xD2, 0x94, 0x4F, 
+0xA4, 0xAF, 0x9C, 0x6E, 0x9C, 0x6E, 0xA4, 0x8E, 
+0x9C, 0x6D, 0xB5, 0x52, 0xD6, 0x55, 0xD6, 0x34, 
+0xCE, 0x14, 0xBD, 0x72, 0xAC, 0xEF, 0xAC, 0xCF, 
+0x94, 0x4D, 0x8C, 0x0C, 0x9C, 0xAE, 0x8B, 0xCC, 
+0x94, 0x2D, 0x9C, 0x4D, 0x94, 0x0C, 0x94, 0x4D, 
+0xAD, 0x11, 0xB5, 0x51, 0x94, 0x0C, 0x8B, 0xEC, 
+0x8B, 0xCC, 0x8B, 0xEC, 0x9C, 0x4D, 0xA4, 0x8E, 
+0xB4, 0xF0, 0xB4, 0xF0, 0xB5, 0x10, 0xBD, 0x10, 
+0xB4, 0xF0, 0xB5, 0x10, 0xBD, 0x51, 0xB5, 0x10, 
+0xAC, 0xF0, 0xB5, 0x30, 0xBD, 0x51, 0xBD, 0x51, 
+0xC5, 0x72, 0xBD, 0x51, 0xAD, 0x10, 0xA4, 0xCF, 
+0x9C, 0xB1, 0xC6, 0x38, 0xB5, 0x97, 0x9C, 0xD3, 
+0x94, 0x6F, 0x94, 0x4D, 0x9C, 0x8E, 0x94, 0x6E, 
+0x94, 0x4D, 0x94, 0x6E, 0x9C, 0x8F, 0x94, 0x6E, 
+0x94, 0x4E, 0x9C, 0xB0, 0xAD, 0x11, 0xAD, 0x11, 
+0xAD, 0x32, 0x94, 0x90, 0x9C, 0xB1, 0xAD, 0x33, 
+0x9C, 0xB0, 0xB5, 0x73, 0xB5, 0x73, 0x9C, 0xB0, 
+0x83, 0xED, 0x94, 0x6F, 0x8C, 0x4E, 0x8C, 0x2E, 
+0x94, 0x8F, 0x94, 0x6F, 0x8C, 0x2E, 0xAD, 0x32, 
+0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x73, 0xA5, 0x11, 
+0xB5, 0xB4, 0xBD, 0xB4, 0xB5, 0x73, 0xBD, 0x94, 
+0xB5, 0x73, 0xB5, 0x73, 0x7B, 0xAC, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xB5, 0x53, 0xA5, 0x11, 0x9C, 0xB0, 
+0xC5, 0xF5, 0xCE, 0x15, 0xCE, 0x35, 0xB5, 0x52, 
+0x8C, 0x4E, 0xAD, 0x32, 0xC5, 0xD5, 0xB5, 0x53, 
+0xB5, 0x93, 0x94, 0x4F, 0xAD, 0x32, 0xBD, 0x93, 
+0xA5, 0x11, 0xA4, 0xF0, 0x9C, 0xD0, 0x94, 0x8F, 
+0xAD, 0x32, 0xAD, 0x11, 0x9C, 0x8F, 0x9C, 0xAF, 
+0x8C, 0x2D, 0x9C, 0xAF, 0x9C, 0xB0, 0xB5, 0x52, 
+0xA4, 0xD0, 0xB5, 0x73, 0xB5, 0x52, 0xBD, 0xB4, 
+0x94, 0x6F, 0xB5, 0x53, 0xA4, 0xF1, 0xB5, 0x53, 
+0xB5, 0x73, 0xBD, 0x93, 0xB5, 0x72, 0xA4, 0xD0, 
+0xB5, 0x52, 0xBD, 0x93, 0xBD, 0xB3, 0xB5, 0x52, 
+0xAD, 0x31, 0xBD, 0xB3, 0xAD, 0x32, 0x9C, 0xB0, 
+0x9C, 0x90, 0xB5, 0x53, 0xB5, 0x73, 0xAD, 0x53, 
+0xB5, 0x53, 0xB5, 0x53, 0xAD, 0x12, 0x9C, 0x90, 
+0x9C, 0x90, 0xAD, 0x33, 0xA4, 0xF1, 0xBD, 0x94, 
+0xA4, 0xF1, 0xAD, 0x32, 0xAD, 0x12, 0xAD, 0x32, 
+0xAD, 0x12, 0xB5, 0x53, 0xB5, 0x73, 0xBD, 0x94, 
+0xC5, 0xF5, 0xBD, 0xD5, 0xBD, 0xB5, 0xBD, 0x94, 
+0xB5, 0x93, 0xB5, 0x93, 0xAD, 0x52, 0xAD, 0x52, 
+0xB5, 0x73, 0xBD, 0xB4, 0xC6, 0x15, 0xC6, 0x15, 
+0xAD, 0x32, 0x9C, 0xB0, 0xB5, 0x52, 0xBD, 0x93, 
+0xB5, 0x32, 0xC5, 0xB4, 0xBD, 0x93, 0xBD, 0x93, 
+0xC5, 0xB4, 0xAD, 0x32, 0xB5, 0x52, 0xBD, 0x73, 
+0xA4, 0xF1, 0xA4, 0xF0, 0xA4, 0xD0, 0x9C, 0xB0, 
+0x94, 0x6F, 0x9C, 0x90, 0xBD, 0x73, 0x8C, 0x2D, 
+0xAD, 0x10, 0xAC, 0xEF, 0xAD, 0x30, 0xAD, 0x10, 
+0xAC, 0xEF, 0x8C, 0x0C, 0x9C, 0xAF, 0xA4, 0xCF, 
+0xA4, 0xD0, 0xA4, 0xF1, 0xAC, 0xF1, 0xA4, 0xD0, 
+0xA4, 0xF0, 0xB5, 0x52, 0xB5, 0x72, 0xCD, 0xF3, 
+0xD6, 0x34, 0xD6, 0x13, 0xC5, 0xD3, 0xB5, 0x52, 
+0xCE, 0x36, 0xCE, 0x16, 0x9C, 0xB0, 0xDE, 0xD7, 
+0xDE, 0xB7, 0xDE, 0xB7, 0xDE, 0x97, 0xCE, 0x57, 
+0xB5, 0x94, 0x94, 0x70, 0x8C, 0x50, 0x94, 0x91, 
+0x8C, 0x92, 0x94, 0xD3, 0xA5, 0x55, 0x9D, 0x35, 
+0x9D, 0x14, 0x5A, 0xCB, 0x42, 0x07, 0x5A, 0xC9, 
+0x6B, 0x2A, 0x62, 0xE9, 0x73, 0x8B, 0x8C, 0x0D, 
+0x83, 0xEC, 0x8C, 0x2E, 0x94, 0x6F, 0x9C, 0xB0, 
+0xAD, 0x11, 0xA4, 0xF1, 0xAD, 0x32, 0xB5, 0x52, 
+0xA4, 0xD0, 0x9C, 0x4D, 0xAC, 0xCF, 0xA4, 0x8F, 
+0xA4, 0x8F, 0xA4, 0x8F, 0x9C, 0xB0, 0xB5, 0x72, 
+0xBD, 0x93, 0xB5, 0x73, 0xB5, 0x93, 0x73, 0x4B, 
+0xBD, 0x94, 0xBD, 0x94, 0xC5, 0xD4, 0xAD, 0x11, 
+0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x32, 0xA4, 0xD0, 
+0xA4, 0xD1, 0xB5, 0x73, 0xAD, 0x11, 0xB5, 0x52, 
+0x8B, 0xED, 0xAC, 0xD0, 0x83, 0x8C, 0xA4, 0x90, 
+0xA4, 0x6F, 0x83, 0x8B, 0x83, 0xAC, 0x83, 0x8C, 
+0x8C, 0x2F, 0x8C, 0x70, 0x94, 0x70, 0xA5, 0x12, 
+0x5A, 0xCA, 0x41, 0xE7, 0x41, 0xE7, 0x39, 0xC6, 
+0x39, 0xC6, 0x39, 0xC6, 0x39, 0xE7, 0x4A, 0x48, 
+0x5A, 0xCA, 0x6B, 0x4D, 0x8C, 0x51, 0x9C, 0xD3, 
+0xA5, 0x14, 0xC5, 0xF8, 0xC6, 0x18, 0xD6, 0xBA, 
+0x9C, 0xB1, 0xA4, 0xD1, 0xBD, 0x93, 0xA4, 0xF1, 
+0x94, 0x6F, 0xA4, 0xF1, 0x94, 0x4F, 0x9C, 0xB0, 
+0xB5, 0x73, 0xBD, 0x94, 0xA4, 0xB0, 0x63, 0x0A, 
+0x31, 0xA5, 0x4A, 0x48, 0x62, 0xEB, 0x52, 0x69, 
+0x52, 0x69, 0x5A, 0xEC, 0x94, 0x72, 0xAD, 0x35, 
+0xC5, 0xF8, 0xCE, 0x59, 0xD6, 0x7A, 0xBD, 0x96, 
+0xB5, 0x55, 0xCE, 0x38, 0xA4, 0xD3, 0x94, 0x30, 
+0xBD, 0x73, 0xAC, 0xD0, 0xAC, 0xD0, 0xAC, 0xCF, 
+0x9C, 0x6D, 0x94, 0x4E, 0xCE, 0x34, 0xDE, 0x95, 
+0xE6, 0xB6, 0xD6, 0x34, 0xAC, 0xEF, 0xB4, 0xEF, 
+0xAC, 0xF0, 0x83, 0xCC, 0x84, 0x0D, 0x8C, 0x0D, 
+0x94, 0x4E, 0x8C, 0x0D, 0x8C, 0x2D, 0xAD, 0x52, 
+0xC5, 0xF5, 0xB5, 0x73, 0x94, 0x6F, 0x73, 0x8B, 
+0x83, 0xED, 0x8C, 0x0E, 0x8C, 0x4E, 0x94, 0x6E, 
+0xAD, 0x31, 0xB5, 0x72, 0xB5, 0x31, 0x8C, 0x0C, 
+0x8B, 0xEC, 0x94, 0x2C, 0xAC, 0xCF, 0x8B, 0xCB, 
+0x83, 0xAB, 0x83, 0xCC, 0x94, 0x2D, 0x94, 0x0C, 
+0x7B, 0x8B, 0x8B, 0xEC, 0x94, 0x0C, 0x94, 0x2D, 
+0xA4, 0xF2, 0xC6, 0x38, 0xAD, 0x76, 0x9C, 0xF3, 
+0x94, 0x4F, 0x9C, 0x6E, 0x9C, 0x8F, 0x9C, 0x8F, 
+0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x8E, 0x9C, 0x6E, 
+0x9C, 0xAF, 0xA4, 0xAF, 0xAC, 0xF1, 0xA4, 0xD1, 
+0x7B, 0xAD, 0x8C, 0x2E, 0x8C, 0x2F, 0xA5, 0x12, 
+0xAD, 0x12, 0xA4, 0xD1, 0xA4, 0xF1, 0xA5, 0x12, 
+0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x12, 
+0xAD, 0x33, 0xAD, 0x12, 0x9C, 0xB1, 0x9C, 0xD1, 
+0xA4, 0xD1, 0x9C, 0xB0, 0x94, 0x6F, 0x94, 0x6F, 
+0x94, 0x4F, 0x94, 0x6F, 0x94, 0x4F, 0x94, 0x4F, 
+0x84, 0x0D, 0x83, 0xED, 0x7B, 0xCD, 0x94, 0x70, 
+0x9C, 0xB0, 0xBD, 0xB4, 0xAD, 0x52, 0x8C, 0x4E, 
+0x9C, 0xB0, 0x94, 0x4E, 0x8C, 0x2E, 0x9C, 0x8F, 
+0x7B, 0xCC, 0x9C, 0xB0, 0xB5, 0x53, 0xA4, 0xF1, 
+0xAD, 0x52, 0x9C, 0xB0, 0x8C, 0x2E, 0xAD, 0x52, 
+0xC5, 0xF5, 0xC6, 0x15, 0xD6, 0x77, 0xBD, 0xB3, 
+0xCE, 0x35, 0xBD, 0x93, 0xA4, 0xD0, 0xB5, 0x52, 
+0xA4, 0xF0, 0xB5, 0x72, 0xA4, 0xF0, 0x8C, 0x4E, 
+0x8C, 0x2D, 0xAD, 0x11, 0xB5, 0x52, 0x9C, 0xB0, 
+0x83, 0xCD, 0xB5, 0x53, 0x8C, 0x2E, 0xAD, 0x11, 
+0xBD, 0x93, 0xBD, 0xB3, 0xCE, 0x15, 0xB5, 0x72, 
+0xB5, 0x52, 0xC5, 0xD4, 0xB5, 0x72, 0xA4, 0xF1, 
+0x9C, 0xB0, 0xBD, 0x73, 0xAD, 0x52, 0xAD, 0x11, 
+0x94, 0x4F, 0x9C, 0xB0, 0xA4, 0xF1, 0xB5, 0x52, 
+0xB5, 0x53, 0xAD, 0x32, 0xA4, 0xF1, 0x9C, 0xB0, 
+0x94, 0x4F, 0xA5, 0x11, 0x9C, 0xD0, 0xC5, 0xF5, 
+0xB5, 0x73, 0xB5, 0x53, 0xBD, 0x94, 0xBD, 0xB4, 
+0xAD, 0x12, 0xB5, 0x93, 0xCE, 0x16, 0xCE, 0x16, 
+0xC5, 0xF5, 0xC5, 0xD5, 0xB5, 0x94, 0xC5, 0xD5, 
+0xC6, 0x15, 0xC5, 0xF5, 0xBD, 0x94, 0xBD, 0xD5, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xCE, 0x36, 0xC5, 0xF5, 
+0xAD, 0x32, 0xA4, 0xD0, 0xB5, 0x52, 0xC5, 0xD4, 
+0xBD, 0x72, 0xBD, 0x93, 0xB5, 0x52, 0xC5, 0xB3, 
+0xBD, 0x93, 0xA4, 0xD0, 0xB5, 0x73, 0xC5, 0xD4, 
+0x9C, 0xB0, 0x9C, 0x8F, 0xA4, 0xF1, 0x94, 0x6F, 
+0x83, 0xED, 0xA4, 0xB0, 0xB5, 0x32, 0x83, 0xEC, 
+0xAD, 0x11, 0xA4, 0xF0, 0xBD, 0x92, 0xB5, 0x72, 
+0xAD, 0x31, 0x94, 0x6F, 0x83, 0xCC, 0x94, 0x8F, 
+0xAD, 0x11, 0xA4, 0xD0, 0x9C, 0x8F, 0x8C, 0x2E, 
+0x83, 0xED, 0x94, 0x6F, 0x9C, 0x8F, 0xA4, 0xF0, 
+0xB5, 0x51, 0xB5, 0x30, 0xA4, 0xEF, 0xA4, 0xF0, 
+0xCE, 0x14, 0xBD, 0x73, 0xAC, 0xF1, 0xE6, 0xD7, 
+0xCE, 0x34, 0xCD, 0xF4, 0xCE, 0x14, 0xD6, 0x76, 
+0xD6, 0x97, 0xD6, 0x98, 0x9C, 0xD2, 0x84, 0x0F, 
+0x9D, 0x14, 0x9D, 0x14, 0x9C, 0xF4, 0x94, 0xD3, 
+0x9D, 0x14, 0x4A, 0x8A, 0x31, 0x85, 0x4A, 0x07, 
+0x5A, 0xA9, 0x5A, 0xA8, 0x63, 0x0A, 0x73, 0x4A, 
+0x73, 0x6B, 0x7B, 0x8C, 0x8C, 0x0D, 0x83, 0xEC, 
+0xA4, 0xF1, 0xAD, 0x12, 0xB5, 0x52, 0xA4, 0xD0, 
+0x9C, 0xAF, 0x9C, 0x4D, 0xA4, 0xAF, 0x9C, 0x6E, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xB5, 0x52, 0xAD, 0x32, 
+0xAD, 0x31, 0xAD, 0x11, 0xA4, 0xD0, 0x94, 0x6F, 
+0xA4, 0xF1, 0xB5, 0x52, 0xC5, 0xD4, 0xA4, 0xF1, 
+0xAD, 0x52, 0xBD, 0x94, 0xBD, 0x94, 0xB5, 0x93, 
+0xAD, 0x11, 0xC5, 0xF5, 0xAD, 0x11, 0xB5, 0x73, 
+0x83, 0xAC, 0xAC, 0xF1, 0x83, 0x8B, 0xA4, 0x8F, 
+0xA4, 0x4F, 0x93, 0xED, 0x8C, 0x0E, 0x8C, 0x0E, 
+0x94, 0x90, 0x8C, 0x4F, 0x9C, 0xD1, 0xAD, 0x53, 
+0x7B, 0xAD, 0x5A, 0xCA, 0x31, 0x85, 0x29, 0x44, 
+0x31, 0x85, 0x31, 0xA6, 0x39, 0xC6, 0x4A, 0x69, 
+0x52, 0x89, 0x63, 0x2C, 0x7B, 0xCE, 0x94, 0x92, 
+0xA5, 0x35, 0xB5, 0xB7, 0xC6, 0x39, 0xE7, 0x1C, 
+0x9C, 0xD2, 0xB5, 0x73, 0xBD, 0xD4, 0xA4, 0xF1, 
+0xA4, 0xD0, 0xAD, 0x32, 0x94, 0x6F, 0xA4, 0xF1, 
+0xB5, 0x73, 0xA4, 0xD0, 0xBD, 0x72, 0xB5, 0x93, 
+0x73, 0x8C, 0x41, 0xE7, 0x4A, 0x28, 0x4A, 0x48, 
+0x52, 0xAA, 0x62, 0xEC, 0x4A, 0x69, 0x73, 0xAE, 
+0x8C, 0x51, 0x94, 0x72, 0xCE, 0x39, 0xBD, 0xB6, 
+0xA4, 0xD3, 0xBD, 0x76, 0x8C, 0x10, 0x62, 0xEB, 
+0xAD, 0x13, 0xBD, 0x74, 0xAC, 0xD0, 0xAC, 0xF0, 
+0x9C, 0x6E, 0x9C, 0x6E, 0xDE, 0x96, 0xDE, 0xB6, 
+0xE6, 0xB6, 0xD6, 0x34, 0xB5, 0x30, 0x9C, 0x6E, 
+0xB5, 0x31, 0x62, 0xE9, 0x63, 0x0A, 0x7B, 0xCD, 
+0x94, 0x6F, 0x8C, 0x2E, 0x8C, 0x4F, 0xC6, 0x36, 
+0xD6, 0x97, 0xCE, 0x36, 0x94, 0xB0, 0x7B, 0xAD, 
+0x84, 0x0E, 0x8C, 0x6F, 0x94, 0x6F, 0x94, 0xB0, 
+0xB5, 0x73, 0xC5, 0xF4, 0xB5, 0x72, 0x9C, 0xB0, 
+0x9C, 0x8F, 0x9C, 0x8E, 0xA4, 0xCF, 0x8B, 0xCC, 
+0x94, 0x4E, 0x9C, 0x8F, 0x94, 0x6F, 0x94, 0x6E, 
+0x83, 0xED, 0x8C, 0x2E, 0x94, 0x6F, 0x73, 0x8C, 
+0xB5, 0x95, 0xC6, 0x18, 0xAD, 0x76, 0x9C, 0xD3, 
+0xA5, 0x12, 0x7B, 0xAC, 0x7B, 0xAC, 0x8C, 0x0E, 
+0x84, 0x0D, 0x94, 0x6F, 0x94, 0x6F, 0x94, 0x8F, 
+0x8C, 0x0D, 0x83, 0xEC, 0xAD, 0x32, 0x94, 0x70, 
+0x62, 0xEA, 0x73, 0x8D, 0x73, 0xAD, 0x84, 0x0E, 
+0x8C, 0x0E, 0x84, 0x0E, 0x7B, 0xAD, 0x7B, 0xAC, 
+0x8C, 0x4F, 0x8C, 0x0E, 0x94, 0x4F, 0x8C, 0x0E, 
+0x8C, 0x0E, 0x9C, 0x90, 0x9C, 0x90, 0x8C, 0x4F, 
+0x8C, 0x4F, 0x8C, 0x2F, 0x83, 0xEE, 0x9C, 0x90, 
+0x8C, 0x0E, 0x8C, 0x4F, 0x9C, 0xD1, 0x8C, 0x2E, 
+0xAD, 0x12, 0xAD, 0x32, 0xAD, 0x32, 0xB5, 0x53, 
+0xAD, 0x32, 0x9C, 0xB1, 0xA4, 0xF1, 0xA4, 0xD1, 
+0xAC, 0xF2, 0xA4, 0xD1, 0xA4, 0xF2, 0x9C, 0xB1, 
+0xA4, 0xF1, 0xA5, 0x12, 0xB5, 0x53, 0xB5, 0x73, 
+0xB5, 0x53, 0xA4, 0xF2, 0xAD, 0x33, 0xAD, 0x52, 
+0x9C, 0xB0, 0x94, 0x4F, 0xA4, 0xD1, 0x9C, 0xB0, 
+0x9C, 0x8F, 0x9C, 0x8F, 0xA4, 0xD1, 0xA4, 0xF1, 
+0xA4, 0xD0, 0x9C, 0xB0, 0x9C, 0xB0, 0xAD, 0x32, 
+0x9C, 0x90, 0x94, 0x6F, 0x94, 0x6F, 0x73, 0x6B, 
+0x7B, 0xAD, 0xBD, 0xB4, 0x8C, 0x2E, 0xA4, 0xD1, 
+0xB5, 0x53, 0xAD, 0x52, 0xB5, 0x73, 0xAD, 0x32, 
+0x9C, 0x8F, 0xB5, 0x73, 0x9C, 0xB0, 0x9C, 0x90, 
+0xA4, 0xF1, 0xAD, 0x12, 0x9C, 0x8F, 0x83, 0xED, 
+0x8C, 0x0E, 0xAD, 0x52, 0xAD, 0x32, 0xA4, 0xF1, 
+0xAD, 0x12, 0xB5, 0x73, 0xB5, 0x73, 0x94, 0x6F, 
+0x83, 0xED, 0x9C, 0xD1, 0xA4, 0xD0, 0xBD, 0x93, 
+0xA4, 0xF1, 0xB5, 0x32, 0xC5, 0xB4, 0xCD, 0xF5, 
+0xC5, 0xF5, 0xBD, 0xB4, 0xC5, 0xD4, 0xCE, 0x36, 
+0xD6, 0x77, 0xCE, 0x36, 0xB5, 0x94, 0xC5, 0xF5, 
+0xCE, 0x36, 0xCE, 0x35, 0xC5, 0xF5, 0xB5, 0x52, 
+0xBD, 0x93, 0xBD, 0xD4, 0xCE, 0x35, 0xBD, 0xD4, 
+0x9C, 0xD0, 0xA4, 0xF1, 0xB5, 0x72, 0xBD, 0xB3, 
+0xC5, 0xD4, 0xC5, 0xF4, 0xBD, 0x93, 0xC5, 0xD4, 
+0xC5, 0xB4, 0xAD, 0x11, 0xBD, 0x73, 0xBD, 0x93, 
+0x8C, 0x4E, 0x9C, 0x90, 0xAC, 0xF1, 0x9C, 0x90, 
+0x73, 0x6C, 0x9C, 0xB0, 0xAD, 0x11, 0x94, 0x4E, 
+0xB5, 0x73, 0xA4, 0xF1, 0xAD, 0x32, 0xB5, 0x73, 
+0xAD, 0x52, 0xBD, 0x94, 0xAD, 0x32, 0xAD, 0x12, 
+0xAD, 0x12, 0xAD, 0x32, 0x9C, 0x90, 0x8C, 0x2E, 
+0x52, 0x89, 0x7B, 0xAD, 0x9C, 0xB0, 0x9C, 0xB0, 
+0x94, 0x6F, 0x94, 0x4E, 0x9C, 0xAF, 0xAD, 0x11, 
+0xC5, 0xB3, 0xB5, 0x52, 0xB5, 0x32, 0xE6, 0xD7, 
+0xD6, 0x34, 0xD6, 0x55, 0xDE, 0x96, 0xD6, 0x75, 
+0xD6, 0x56, 0xD6, 0x97, 0xDE, 0x97, 0xC5, 0xF5, 
+0x9D, 0x14, 0x9D, 0x14, 0x9D, 0x14, 0x94, 0xF4, 
+0x94, 0xB3, 0x5A, 0xCB, 0x52, 0x68, 0x5A, 0xA9, 
+0x5A, 0xC9, 0x62, 0xC9, 0x62, 0xEA, 0x6A, 0xEA, 
+0x73, 0x2A, 0x73, 0x2A, 0x7B, 0x4A, 0x7B, 0x8B, 
+0x83, 0xCC, 0x8C, 0x0D, 0x94, 0x2D, 0x94, 0x2E, 
+0x7B, 0x8B, 0x9C, 0x4E, 0x93, 0xEC, 0x7B, 0x6A, 
+0x83, 0xCC, 0x7B, 0x8B, 0xA4, 0xD1, 0x9C, 0xB0, 
+0xA4, 0xD0, 0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x32, 
+0xA4, 0xF1, 0xB5, 0x52, 0xBD, 0xD4, 0xB5, 0x73, 
+0xC5, 0xD5, 0xBD, 0x94, 0xB5, 0x94, 0xC5, 0xF5, 
+0x9C, 0x90, 0xC5, 0xD5, 0x94, 0x6F, 0x6B, 0x0A, 
+0x73, 0x4A, 0xA4, 0xB0, 0x9C, 0x4E, 0xB5, 0x11, 
+0xAC, 0xD0, 0xA4, 0x8F, 0xA4, 0xB0, 0xA4, 0xB1, 
+0xA4, 0xD1, 0x94, 0x70, 0xA5, 0x12, 0xB5, 0x73, 
+0x94, 0x70, 0x7B, 0xAD, 0x41, 0xE6, 0x29, 0x64, 
+0x29, 0x44, 0x39, 0xC6, 0x39, 0xE7, 0x39, 0xE7, 
+0x42, 0x07, 0x52, 0xAA, 0x63, 0x2C, 0x83, 0xEF, 
+0x9C, 0xF3, 0xA5, 0x14, 0xBD, 0xD8, 0xCE, 0x59, 
+0x9C, 0xB2, 0xB5, 0x94, 0xBD, 0xB4, 0xB5, 0x73, 
+0x9C, 0xB0, 0xA4, 0xD1, 0x9C, 0x90, 0xAD, 0x32, 
+0xBD, 0x73, 0xA4, 0xD0, 0xB5, 0x32, 0xBD, 0x93, 
+0xB5, 0x52, 0x62, 0xEA, 0x39, 0xC6, 0x42, 0x07, 
+0x4A, 0x69, 0x5A, 0xAA, 0x52, 0x8A, 0x6B, 0x2C, 
+0x84, 0x10, 0x52, 0x6A, 0x4A, 0x69, 0x9C, 0xB2, 
+0xBD, 0xB6, 0xBD, 0x96, 0xB5, 0x34, 0xD6, 0x59, 
+0x73, 0x6D, 0x9C, 0x70, 0xBD, 0x53, 0xAC, 0xCF, 
+0x9C, 0x6D, 0xA4, 0xAF, 0xE6, 0xD7, 0xE6, 0xB6, 
+0xE6, 0xB6, 0xCE, 0x14, 0xB5, 0x30, 0x9C, 0x4D, 
+0xA4, 0xD0, 0x73, 0x6B, 0x73, 0xAC, 0x83, 0xEE, 
+0x8C, 0x4F, 0x83, 0xCD, 0x83, 0xED, 0xBD, 0xD4, 
+0xDE, 0xD8, 0xCE, 0x76, 0x9C, 0xD1, 0x8C, 0x2F, 
+0x84, 0x0E, 0x9C, 0xB1, 0x8C, 0x2F, 0x94, 0x90, 
+0xBD, 0xD5, 0xC5, 0xF5, 0xCE, 0x15, 0xAD, 0x32, 
+0x83, 0xED, 0x9C, 0x8F, 0xAC, 0xF0, 0x83, 0x8B, 
+0x94, 0x4E, 0x94, 0x6F, 0x94, 0x4F, 0x94, 0x4F, 
+0x94, 0x90, 0x94, 0x70, 0xAD, 0x53, 0x9C, 0xD2, 
+0xCE, 0x59, 0xB5, 0xB7, 0xAD, 0x55, 0x9C, 0xF3, 
+0xC5, 0xF6, 0xB5, 0xB4, 0xAD, 0x53, 0xAD, 0x53, 
+0x94, 0x6F, 0x9C, 0xD1, 0xA5, 0x12, 0xCE, 0x57, 
+0xC5, 0xF5, 0x8C, 0x2E, 0xAD, 0x12, 0x94, 0x4F, 
+0x8C, 0x70, 0x94, 0xB1, 0x9C, 0xD1, 0xAD, 0x33, 
+0xA5, 0x12, 0x94, 0x90, 0x94, 0x6F, 0x94, 0x90, 
+0x94, 0x90, 0x7B, 0xCD, 0x83, 0xEE, 0x8C, 0x2F, 
+0x83, 0xEE, 0xA4, 0xD1, 0xB5, 0x52, 0xAD, 0x32, 
+0xB5, 0x73, 0xAD, 0x53, 0xAD, 0x12, 0xAD, 0x32, 
+0x9C, 0xD1, 0x94, 0x90, 0x94, 0x4F, 0x62, 0xEA, 
+0x73, 0x8C, 0x7B, 0xED, 0x84, 0x0E, 0x8C, 0x2F, 
+0x94, 0x90, 0x94, 0x70, 0x8C, 0x0E, 0x83, 0xED, 
+0x83, 0xED, 0x9C, 0xB0, 0x94, 0x70, 0x83, 0xEE, 
+0x8C, 0x4F, 0x94, 0x70, 0x7B, 0xCD, 0x7B, 0xAD, 
+0x7B, 0xAD, 0x83, 0xCE, 0x8C, 0x0F, 0x94, 0x4F, 
+0x9C, 0xB0, 0xA4, 0xB1, 0xB5, 0x74, 0xCE, 0x16, 
+0xB5, 0x53, 0xBD, 0x73, 0xB5, 0x73, 0xB5, 0x53, 
+0xB5, 0x53, 0xBD, 0x73, 0xB5, 0x73, 0xBD, 0x93, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xBD, 0xB4, 0xB5, 0x73, 
+0xB5, 0x74, 0xC5, 0xD5, 0xCE, 0x37, 0xCE, 0x37, 
+0xCE, 0x16, 0xCE, 0x16, 0xCE, 0x16, 0xCD, 0xF6, 
+0xCD, 0xF5, 0xC5, 0xD5, 0xBD, 0xB5, 0xBD, 0x94, 
+0xAD, 0x32, 0xAD, 0x12, 0xAD, 0x12, 0xAC, 0xF2, 
+0xA4, 0xB1, 0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0xB0, 
+0x9C, 0xB0, 0xA4, 0xD1, 0x9C, 0x90, 0x8C, 0x2E, 
+0xAD, 0x12, 0xB5, 0x73, 0x9C, 0x90, 0xA4, 0xD0, 
+0x94, 0x2E, 0x8C, 0x0E, 0x9C, 0x6F, 0x94, 0x6F, 
+0x94, 0x4E, 0x83, 0xCD, 0x94, 0x4F, 0x9C, 0xB0, 
+0xB5, 0x73, 0xB5, 0x53, 0xAD, 0x33, 0xBD, 0xB4, 
+0xCD, 0xF5, 0xCE, 0x36, 0xBD, 0xB4, 0xAD, 0x52, 
+0xB5, 0x52, 0xC6, 0x16, 0xCE, 0x56, 0xB5, 0x73, 
+0x94, 0x8F, 0xAD, 0x32, 0xBD, 0xB3, 0xB5, 0x52, 
+0xBD, 0x93, 0xBD, 0x93, 0xAD, 0x31, 0xB5, 0x72, 
+0xBD, 0x93, 0xB5, 0x51, 0xC5, 0xD4, 0xBD, 0x73, 
+0xAD, 0x32, 0xBD, 0x93, 0xB5, 0x73, 0x83, 0xED, 
+0x6B, 0x2B, 0x9C, 0xB0, 0xB5, 0x52, 0x8C, 0x4F, 
+0xB5, 0x94, 0xAD, 0x32, 0xB5, 0x73, 0xBD, 0xD5, 
+0xAD, 0x32, 0x8C, 0x4F, 0xBD, 0xD5, 0xB5, 0x94, 
+0xA4, 0xF2, 0xAD, 0x73, 0xA5, 0x12, 0x9C, 0xF2, 
+0x73, 0xAD, 0x6B, 0x2B, 0x9C, 0xD1, 0xA4, 0xF1, 
+0x94, 0x90, 0x8C, 0x2F, 0x9C, 0xB0, 0x9C, 0xAF, 
+0xAD, 0x10, 0xA4, 0xF0, 0xAD, 0x11, 0xDE, 0x96, 
+0xD6, 0x34, 0xD6, 0x34, 0xDE, 0x95, 0xDE, 0xB6, 
+0xDE, 0xB6, 0xDE, 0xB7, 0xD6, 0x76, 0xD6, 0x76, 
+0xA5, 0x35, 0xA5, 0x34, 0x9D, 0x14, 0x9C, 0xF4, 
+0x94, 0xB3, 0x5A, 0xCA, 0x5A, 0xA9, 0x62, 0xE9, 
+0x6B, 0x0A, 0x73, 0x2A, 0x7B, 0x6B, 0x7B, 0x6B, 
+0x83, 0xAC, 0x83, 0xAB, 0x83, 0x8B, 0x83, 0x8B, 
+0x83, 0xAB, 0x8B, 0xCC, 0x8B, 0xEC, 0x94, 0x2D, 
+0x9C, 0x6E, 0xAC, 0xCF, 0xB4, 0xF0, 0xAC, 0xD0, 
+0x9C, 0x4E, 0x8B, 0xEC, 0x94, 0x2E, 0x94, 0x4E, 
+0x94, 0x4E, 0x94, 0x2E, 0x94, 0x2D, 0x94, 0x2D, 
+0x94, 0x4E, 0x94, 0x4E, 0x94, 0x4E, 0x94, 0x4E, 
+0xA4, 0xB0, 0xAD, 0x11, 0xA4, 0xD0, 0xA4, 0xD0, 
+0x94, 0x4E, 0x9C, 0xAF, 0x83, 0xCC, 0x62, 0xC8, 
+0x94, 0x4E, 0x9C, 0x6E, 0x94, 0x0D, 0xB5, 0x11, 
+0xB5, 0x11, 0xAC, 0xB0, 0xAC, 0xF1, 0xAD, 0x12, 
+0xA4, 0xF1, 0x8C, 0x4F, 0xA4, 0xF2, 0xBD, 0xB4, 
+0x73, 0x8C, 0x5A, 0xCA, 0x4A, 0x28, 0x39, 0xC6, 
+0x3A, 0x07, 0x42, 0x07, 0x39, 0xE7, 0x39, 0xA6, 
+0x39, 0xE7, 0x4A, 0x49, 0x5A, 0xCA, 0x6B, 0x6D, 
+0x84, 0x0F, 0x9C, 0xF3, 0xB5, 0xB6, 0x73, 0x8E, 
+0x9C, 0xB3, 0xD6, 0x79, 0xB5, 0x53, 0xBD, 0x93, 
+0xB5, 0x52, 0xBD, 0x94, 0xB5, 0x73, 0xBD, 0x73, 
+0xC5, 0xB4, 0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x31, 
+0xB5, 0x32, 0x9C, 0x8F, 0x6B, 0x2A, 0x31, 0x85, 
+0x42, 0x07, 0x5A, 0xEB, 0x4A, 0x49, 0x73, 0x8D, 
+0x7B, 0x8E, 0x31, 0x86, 0x4A, 0x29, 0x62, 0xEB, 
+0x83, 0xF0, 0xB5, 0x55, 0xCD, 0xF7, 0xCE, 0x17, 
+0xCD, 0xF7, 0x6B, 0x0B, 0xAC, 0xD2, 0xBD, 0x73, 
+0x7B, 0x8A, 0xAC, 0xF0, 0xE6, 0xD7, 0xDE, 0xB6, 
+0xE6, 0xD6, 0xD6, 0x14, 0xB5, 0x30, 0x8B, 0xAB, 
+0x9C, 0x8F, 0x73, 0x6B, 0x5A, 0xCA, 0x6B, 0x4B, 
+0x8C, 0x2E, 0x73, 0x8C, 0x83, 0xED, 0xB5, 0x73, 
+0xD6, 0x76, 0xCE, 0x56, 0xA5, 0x12, 0x94, 0xB1, 
+0x8C, 0x4F, 0xA5, 0x12, 0x9C, 0xB0, 0xA5, 0x12, 
+0xC5, 0xF5, 0xC6, 0x15, 0xCE, 0x35, 0xB5, 0x52, 
+0x83, 0xEC, 0x94, 0x6E, 0xAD, 0x11, 0x83, 0x8B, 
+0x83, 0xED, 0x8C, 0x4E, 0x94, 0x4F, 0x8C, 0x4E, 
+0x8C, 0x4E, 0x8C, 0x2E, 0x94, 0x6F, 0xA4, 0xF2, 
+0xCE, 0x38, 0xB5, 0x96, 0xAD, 0x55, 0x94, 0x71, 
+0xB5, 0x74, 0xAD, 0x53, 0xB5, 0x94, 0xA5, 0x12, 
+0x8C, 0x4F, 0x9C, 0xD1, 0x9C, 0xD0, 0xA4, 0xF1, 
+0xB5, 0x94, 0x9C, 0xD1, 0xAD, 0x33, 0x8C, 0x4F, 
+0x94, 0x90, 0x94, 0x90, 0xA5, 0x12, 0xAD, 0x32, 
+0x9C, 0xD1, 0x9C, 0xD1, 0x9C, 0xB0, 0x94, 0x90, 
+0x8C, 0x4F, 0x63, 0x2B, 0x5B, 0x0B, 0x6B, 0x6C, 
+0x73, 0x6C, 0x94, 0x90, 0xAD, 0x52, 0xBD, 0xB4, 
+0xA5, 0x11, 0xAD, 0x32, 0xB5, 0x93, 0xB5, 0x93, 
+0xB5, 0x73, 0x9C, 0xD1, 0x94, 0x90, 0x73, 0x6C, 
+0x73, 0x8D, 0x7B, 0xAD, 0x6B, 0x4C, 0x73, 0x6C, 
+0x6B, 0x4C, 0x6B, 0x4C, 0x6B, 0x2B, 0x6B, 0x2B, 
+0x73, 0x6C, 0x83, 0xCD, 0x94, 0x6F, 0x83, 0xCD, 
+0x83, 0xCD, 0x8C, 0x2F, 0x7B, 0xAD, 0x6B, 0x4C, 
+0x63, 0x0B, 0x6B, 0x2B, 0x6B, 0x2B, 0x6B, 0x4B, 
+0x83, 0xCD, 0x83, 0xCD, 0x83, 0xED, 0xAD, 0x12, 
+0x94, 0x6F, 0xA4, 0xF1, 0xA4, 0xF1, 0xA4, 0xD0, 
+0x9C, 0xAF, 0xA4, 0xD0, 0x94, 0x6F, 0x7B, 0xCD, 
+0x7B, 0x8C, 0x7B, 0xAD, 0x7B, 0xAD, 0x7B, 0x8C, 
+0x83, 0xED, 0x83, 0xCD, 0x8B, 0xEE, 0x9C, 0xB0, 
+0xAD, 0x12, 0x9C, 0x70, 0x8C, 0x2F, 0x94, 0x4F, 
+0x9C, 0x70, 0x9C, 0x90, 0xB5, 0x74, 0xC5, 0xD5, 
+0xA4, 0xF1, 0xAD, 0x12, 0xA4, 0xF1, 0xAD, 0x32, 
+0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x32, 
+0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x53, 0xBD, 0x73, 
+0xC5, 0xB4, 0xBD, 0x94, 0xBD, 0x73, 0xBD, 0x73, 
+0xB5, 0x52, 0xB5, 0x32, 0xB5, 0x53, 0xB5, 0x32, 
+0xB5, 0x73, 0xBD, 0x94, 0xC5, 0xB4, 0xC5, 0xB4, 
+0xBD, 0x73, 0xB5, 0x53, 0xAD, 0x12, 0xAD, 0x12, 
+0xAD, 0x12, 0xA4, 0xF1, 0x9C, 0xB0, 0x94, 0x6F, 
+0x9C, 0x90, 0xAD, 0x12, 0xAD, 0x11, 0x94, 0x6F, 
+0x9C, 0xB0, 0xA4, 0xF1, 0x9C, 0xB0, 0x8C, 0x2E, 
+0x8C, 0x0E, 0x83, 0xCD, 0x8B, 0xED, 0x94, 0x4E, 
+0x9C, 0x6F, 0xAD, 0x11, 0xAD, 0x11, 0xAC, 0xF1, 
+0xBD, 0x73, 0xBD, 0x73, 0xB5, 0x52, 0x73, 0x6B, 
+0x6B, 0x2A, 0x9C, 0xB0, 0xA4, 0xF1, 0xA4, 0xD1, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xBD, 0xD4, 0xBD, 0xD5, 
+0xBD, 0xB4, 0xBD, 0xD5, 0xC5, 0xF5, 0xC6, 0x16, 
+0xBD, 0xD5, 0xAD, 0x74, 0xAD, 0x53, 0xAD, 0x73, 
+0x94, 0xB1, 0x84, 0x0F, 0xAD, 0x32, 0xB5, 0x94, 
+0xA5, 0x32, 0xA4, 0xF2, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xA4, 0xF0, 0x9C, 0xAF, 0xA4, 0xB0, 0xD6, 0x55, 
+0xDE, 0x95, 0xD6, 0x54, 0xD6, 0x75, 0xDE, 0x75, 
+0xDE, 0x75, 0xD6, 0x96, 0xE6, 0xB7, 0xDE, 0x96, 
+0xA5, 0x35, 0xA5, 0x34, 0x9D, 0x14, 0x9C, 0xF4, 
+0x94, 0xD3, 0x52, 0xAA, 0x52, 0x68, 0x63, 0x0A, 
+0x6B, 0x2A, 0x6B, 0x09, 0x73, 0x2A, 0x73, 0x2A, 
+0x83, 0xCC, 0x8C, 0x0D, 0x94, 0x2D, 0x9C, 0x6F, 
+0x7B, 0xAB, 0x73, 0x6A, 0x7B, 0xAB, 0x8B, 0xEC, 
+0x94, 0x2D, 0x94, 0x0C, 0x93, 0xEC, 0x8B, 0xAB, 
+0x6A, 0xA8, 0x9C, 0x4D, 0xA4, 0xAF, 0xA4, 0x6E, 
+0x9C, 0x6E, 0x94, 0x2D, 0x9C, 0x8E, 0xA4, 0xCF, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xA4, 0x8F, 0x9C, 0x4E, 0xA4, 0x8E, 0x9C, 0x4D, 
+0x9C, 0x4D, 0x9C, 0x6E, 0x94, 0x4D, 0xA4, 0xCF, 
+0xAC, 0xF0, 0xA4, 0xAF, 0x83, 0xAB, 0x8B, 0xEC, 
+0x83, 0x8B, 0x62, 0xC9, 0x62, 0xC9, 0x62, 0xC9, 
+0x62, 0xE9, 0x62, 0xC9, 0x5A, 0x88, 0x5A, 0xA9, 
+0x62, 0xC9, 0x4A, 0x27, 0x4A, 0x28, 0x52, 0x89, 
+0x4A, 0x48, 0x4A, 0x28, 0x39, 0xA6, 0x31, 0xA6, 
+0x39, 0xE6, 0x4A, 0x48, 0x52, 0xAA, 0x73, 0xAE, 
+0x8C, 0x51, 0x9C, 0xD3, 0x9C, 0xD3, 0x6B, 0x6E, 
+0x8C, 0x72, 0xDE, 0xBA, 0xC6, 0x16, 0xA4, 0xD0, 
+0xB5, 0x32, 0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x32, 
+0xB5, 0x52, 0xAC, 0xF1, 0x9C, 0xAF, 0xA4, 0xD0, 
+0x9C, 0x6F, 0x94, 0x2E, 0xB5, 0x31, 0x62, 0xEA, 
+0x39, 0xA6, 0x39, 0xA6, 0x52, 0x8A, 0x73, 0x8E, 
+0x52, 0x8A, 0x62, 0xEB, 0x63, 0x0C, 0x6B, 0x4D, 
+0x8C, 0x31, 0x5A, 0x8A, 0x9C, 0x92, 0x94, 0x31, 
+0xE6, 0x99, 0xDE, 0x79, 0x8B, 0xCF, 0xBD, 0x74, 
+0xAC, 0xF1, 0x9C, 0xB0, 0xDE, 0x97, 0xCE, 0x14, 
+0xE6, 0xF7, 0xCE, 0x14, 0xB4, 0xF0, 0x7B, 0x6A, 
+0x94, 0x6F, 0x7B, 0xAC, 0x5A, 0xCA, 0x6B, 0x4C, 
+0x8C, 0x4F, 0x8C, 0x2F, 0x9C, 0xB0, 0xBD, 0xB4, 
+0xDE, 0xB7, 0xD6, 0x77, 0xB5, 0x94, 0xA5, 0x33, 
+0xA5, 0x12, 0xA5, 0x12, 0xAD, 0x32, 0xAD, 0x53, 
+0xCE, 0x36, 0xD6, 0x56, 0xCE, 0x36, 0xAD, 0x11, 
+0x94, 0x6F, 0x9C, 0xD0, 0xB5, 0x31, 0x83, 0x8B, 
+0x94, 0x4E, 0x9C, 0x90, 0x94, 0x4F, 0xA5, 0x12, 
+0xA5, 0x11, 0xA4, 0xD1, 0xAD, 0x53, 0xB5, 0x54, 
+0xC5, 0xF7, 0xAD, 0x55, 0xA5, 0x14, 0x9C, 0xB2, 
+0xAD, 0x33, 0xAD, 0x12, 0xB5, 0x73, 0xAD, 0x33, 
+0x94, 0x70, 0x9C, 0xB1, 0x94, 0x8F, 0x94, 0x90, 
+0xB5, 0x94, 0xBD, 0xB4, 0xAD, 0x33, 0x8C, 0x2F, 
+0x94, 0x70, 0x8C, 0x6F, 0xA5, 0x12, 0xA5, 0x12, 
+0xA4, 0xF2, 0xA5, 0x32, 0xA4, 0xF1, 0x9C, 0xB1, 
+0x84, 0x0E, 0x6B, 0x6C, 0x63, 0x4C, 0x6B, 0x8D, 
+0x6B, 0x6C, 0x84, 0x2F, 0xAD, 0x53, 0xBD, 0xB4, 
+0xAD, 0x52, 0xBD, 0xB4, 0xB5, 0x93, 0xAD, 0x53, 
+0xAD, 0x53, 0xA4, 0xD1, 0x94, 0x90, 0x83, 0xEE, 
+0x73, 0x6D, 0x7B, 0x8D, 0x7B, 0x8D, 0x7B, 0xCD, 
+0x8C, 0x2F, 0x94, 0x90, 0x8C, 0x2F, 0x83, 0xEE, 
+0x8C, 0x2F, 0x8C, 0x4F, 0x9C, 0xB1, 0x84, 0x0E, 
+0x94, 0x4F, 0x94, 0x4F, 0x84, 0x0E, 0x7B, 0x8D, 
+0x73, 0x8D, 0x73, 0x6C, 0x5A, 0xCA, 0x6B, 0x0B, 
+0x73, 0x6C, 0x73, 0x6C, 0x8C, 0x4F, 0xAD, 0x12, 
+0x9C, 0xB0, 0xA4, 0xF0, 0x9C, 0xB0, 0x9C, 0xD0, 
+0x94, 0x6E, 0x94, 0x4E, 0x8C, 0x2E, 0x84, 0x0E, 
+0x6B, 0x4B, 0x6B, 0x4B, 0x6B, 0x2B, 0x6B, 0x2B, 
+0x6B, 0x6B, 0x6B, 0x4B, 0x73, 0xAD, 0x8C, 0x2F, 
+0x94, 0x4F, 0x84, 0x0E, 0x94, 0x91, 0x84, 0x2F, 
+0x83, 0xCD, 0x6B, 0x0B, 0x73, 0x6D, 0xB5, 0x53, 
+0xD6, 0x77, 0xBD, 0xB4, 0xAD, 0x32, 0xB5, 0x53, 
+0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x94, 0xBD, 0x94, 
+0xBD, 0xB4, 0xBD, 0x94, 0xB5, 0x53, 0xA5, 0x12, 
+0xAD, 0x33, 0xAD, 0x12, 0xA4, 0xB0, 0xA4, 0xD0, 
+0xA4, 0xF1, 0x94, 0x4F, 0x8C, 0x0E, 0x94, 0x2E, 
+0x8C, 0x0E, 0x8C, 0x0E, 0x8C, 0x0E, 0xAD, 0x12, 
+0x9C, 0x90, 0x8C, 0x0E, 0x8C, 0x0D, 0x8C, 0x0E, 
+0xA4, 0xB0, 0x9C, 0x90, 0x9C, 0x8F, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xA4, 0xD1, 0xAD, 0x31, 0xAD, 0x11, 
+0xAD, 0x12, 0xAD, 0x11, 0xAD, 0x11, 0xB5, 0x32, 
+0xB5, 0x53, 0xB5, 0x32, 0xAD, 0x11, 0xB5, 0x52, 
+0xB5, 0x32, 0xB5, 0x73, 0xB5, 0x52, 0xA4, 0xF1, 
+0x9C, 0x6F, 0x94, 0x4E, 0x83, 0xED, 0x7B, 0xAC, 
+0x7B, 0xAD, 0xA4, 0xD1, 0xAD, 0x11, 0xAD, 0x12, 
+0xB5, 0x53, 0xAD, 0x32, 0xAD, 0x12, 0xAD, 0x32, 
+0xAD, 0x12, 0x9C, 0xD1, 0x9C, 0xD1, 0xAD, 0x32, 
+0xAD, 0x52, 0xAD, 0x32, 0xA5, 0x12, 0xA5, 0x12, 
+0xA4, 0xF1, 0x9C, 0xB1, 0xA4, 0xF2, 0xA5, 0x12, 
+0x94, 0x6F, 0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0xB0, 
+0x94, 0x6F, 0x94, 0x4F, 0x83, 0xAC, 0xC5, 0xB3, 
+0xE6, 0xB6, 0xDE, 0x95, 0xE6, 0xB6, 0xE6, 0xD6, 
+0xE6, 0xB6, 0xE6, 0xB6, 0xE6, 0xD7, 0xDE, 0x96, 
+0xA5, 0x35, 0xA5, 0x35, 0xA5, 0x34, 0x9C, 0xF4, 
+0x94, 0xB3, 0x5A, 0xCB, 0x5A, 0xA9, 0x73, 0x8B, 
+0x83, 0xCC, 0x83, 0xAC, 0x8C, 0x0D, 0x8C, 0x0D, 
+0x94, 0x4E, 0xA4, 0xF1, 0xA4, 0xD0, 0xAC, 0xF1, 
+0x9C, 0x6F, 0x94, 0x6F, 0x9C, 0x6F, 0xA4, 0xB0, 
+0xB5, 0x31, 0xAC, 0xF0, 0xAC, 0xD0, 0x7B, 0x4A, 
+0x52, 0x26, 0xA4, 0xAF, 0xAC, 0xF0, 0xAD, 0x11, 
+0xBD, 0xB3, 0xC5, 0xD4, 0x94, 0x6F, 0xA5, 0x11, 
+0xA4, 0xF1, 0xAD, 0x32, 0xAD, 0x31, 0xAD, 0x31, 
+0xB5, 0x72, 0xA4, 0xF0, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xA5, 0x11, 0xAD, 0x11, 0x8C, 0x2E, 0x73, 0x6A, 
+0x7B, 0xAB, 0x73, 0x4A, 0x6B, 0x09, 0x9C, 0x6F, 
+0xA4, 0xB0, 0x7B, 0xAB, 0x94, 0x4E, 0x94, 0x2D, 
+0x83, 0xAC, 0x83, 0xCC, 0x8B, 0xED, 0x8B, 0xEC, 
+0x83, 0xCB, 0x83, 0xAC, 0x41, 0xE6, 0x52, 0x89, 
+0x42, 0x07, 0x39, 0xE7, 0x39, 0xE6, 0x29, 0x65, 
+0x31, 0xA6, 0x42, 0x08, 0x4A, 0x48, 0x63, 0x2C, 
+0x63, 0x2C, 0x73, 0xAE, 0x6B, 0x2C, 0x8C, 0x72, 
+0xBD, 0xB7, 0xB5, 0x96, 0xDE, 0xBA, 0xA4, 0xF3, 
+0x83, 0xAD, 0x8C, 0x0D, 0x8B, 0xCC, 0x8B, 0xCC, 
+0x8B, 0xCC, 0x93, 0xED, 0x8B, 0xEC, 0x8B, 0xEC, 
+0x7B, 0x8B, 0x73, 0x29, 0x7B, 0x4A, 0x4A, 0x07, 
+0x42, 0x07, 0x42, 0x28, 0x52, 0x69, 0x31, 0x65, 
+0x42, 0x08, 0x4A, 0x69, 0x4A, 0x69, 0x62, 0xEB, 
+0x94, 0x72, 0x41, 0xE8, 0x6B, 0x2D, 0xAD, 0x14, 
+0xB5, 0x34, 0xCE, 0x17, 0xC5, 0x75, 0x8B, 0xAE, 
+0xD6, 0x58, 0xA4, 0xD1, 0xA4, 0xB0, 0x9C, 0x8F, 
+0xBD, 0xB3, 0xAC, 0xF0, 0xAC, 0xAE, 0x73, 0x4A, 
+0x62, 0xEA, 0x63, 0x0A, 0x6B, 0x4B, 0x73, 0x6C, 
+0x83, 0xEE, 0x84, 0x0E, 0x9C, 0xB0, 0xBD, 0xD4, 
+0xDE, 0xD8, 0xD6, 0x97, 0xBD, 0xD4, 0xA5, 0x12, 
+0xBD, 0xD5, 0xAD, 0x53, 0xA5, 0x12, 0xAD, 0x53, 
+0xCE, 0x56, 0xCE, 0x15, 0xD6, 0x56, 0x9C, 0xB0, 
+0x94, 0x4F, 0x9C, 0x6E, 0xB5, 0x31, 0x7B, 0x8B, 
+0x9C, 0x90, 0xAD, 0x52, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xB5, 0x93, 0xBD, 0xB5, 
+0xC6, 0x18, 0xAD, 0x35, 0x9C, 0xF4, 0xBD, 0xB5, 
+0xB5, 0x74, 0xB5, 0x73, 0xBD, 0x94, 0xC5, 0xD5, 
+0xA5, 0x12, 0xA4, 0xF2, 0xA5, 0x32, 0xAD, 0x33, 
+0xBD, 0xD5, 0xBD, 0xD5, 0xAD, 0x32, 0x8C, 0x2E, 
+0x8C, 0x4F, 0x8C, 0x6F, 0x9C, 0xD1, 0xA5, 0x12, 
+0xAD, 0x33, 0xA5, 0x32, 0x9C, 0xD1, 0x9C, 0xB0, 
+0x84, 0x2E, 0x7B, 0xEE, 0x7B, 0xCE, 0x7B, 0xEF, 
+0x84, 0x2F, 0xA5, 0x33, 0xBD, 0xD4, 0xBD, 0xD4, 
+0xAD, 0x53, 0xC5, 0xF5, 0xBD, 0xB4, 0xA5, 0x32, 
+0xAD, 0x32, 0x9C, 0xB1, 0x9C, 0x90, 0x7B, 0x8C, 
+0x6B, 0x4C, 0x6B, 0x6C, 0x7B, 0xAD, 0x7B, 0xCD, 
+0x8C, 0x4F, 0x9C, 0xD1, 0x9C, 0x90, 0x94, 0x90, 
+0x94, 0x90, 0x94, 0x90, 0x9C, 0xB1, 0x94, 0x70, 
+0x9C, 0xB1, 0x8C, 0x2F, 0x94, 0x70, 0x8C, 0x0F, 
+0x83, 0xEE, 0x7B, 0xAD, 0x62, 0xEA, 0x63, 0x2B, 
+0x73, 0x6C, 0x63, 0x0B, 0x94, 0x90, 0xAD, 0x32, 
+0xB5, 0x93, 0x9C, 0x8F, 0x9C, 0xB0, 0x94, 0x8F, 
+0x9C, 0xB0, 0xAD, 0x12, 0x9C, 0xB0, 0x8C, 0x6F, 
+0x73, 0xAD, 0x7B, 0xCD, 0x73, 0x8C, 0x6B, 0x4C, 
+0x6B, 0x4C, 0x7B, 0xEE, 0x94, 0xB1, 0xAD, 0x53, 
+0xA5, 0x12, 0xA5, 0x33, 0xAD, 0xB5, 0x94, 0xB2, 
+0x7B, 0xAE, 0x7B, 0xCE, 0x83, 0xEE, 0xB5, 0x73, 
+0xCE, 0x36, 0xB5, 0x94, 0xA4, 0xD1, 0x8C, 0x0E, 
+0x8C, 0x2E, 0x94, 0x6F, 0x94, 0x4F, 0x9C, 0xB1, 
+0xA5, 0x12, 0xA4, 0xD1, 0x9C, 0xB1, 0x94, 0x4F, 
+0x8C, 0x4F, 0x94, 0x4F, 0x94, 0x6F, 0x94, 0x6F, 
+0x9C, 0x90, 0x9C, 0x90, 0xA4, 0xD0, 0xA4, 0xF0, 
+0xA4, 0xF1, 0xA4, 0xF1, 0x94, 0x4F, 0xB5, 0x12, 
+0x7B, 0x8C, 0x73, 0x4B, 0x8C, 0x2E, 0x83, 0xCD, 
+0x94, 0x4E, 0x94, 0x6F, 0x8C, 0x2E, 0x94, 0x4E, 
+0x8C, 0x2E, 0x7B, 0xAC, 0x8C, 0x0D, 0x7B, 0xAC, 
+0x94, 0x6F, 0x94, 0x4E, 0x73, 0x6B, 0x73, 0x6B, 
+0x73, 0x4B, 0x73, 0x4B, 0x7B, 0x8C, 0x83, 0xED, 
+0x8B, 0xED, 0x8B, 0xED, 0x9C, 0x8F, 0xB5, 0x72, 
+0x8C, 0x0D, 0x9C, 0x6F, 0x94, 0x4F, 0x94, 0x90, 
+0x8C, 0x4F, 0x94, 0x4F, 0x9C, 0x90, 0xA4, 0xD1, 
+0xAD, 0x12, 0xAD, 0x33, 0xAD, 0x32, 0xB5, 0x32, 
+0xBD, 0x94, 0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x32, 
+0xB5, 0x73, 0xB5, 0x53, 0xB5, 0x73, 0xC5, 0xB4, 
+0xC5, 0xB4, 0xC5, 0xD5, 0xC5, 0xB4, 0xBD, 0xB4, 
+0xBD, 0x74, 0xBD, 0x94, 0xBD, 0x73, 0xBD, 0x94, 
+0xC5, 0xD5, 0xCD, 0xF5, 0xA4, 0xD1, 0xAC, 0xF0, 
+0xB5, 0x31, 0xB5, 0x31, 0xAC, 0xF0, 0xA4, 0xAF, 
+0xA4, 0xB0, 0xAD, 0x11, 0xAD, 0x31, 0xC5, 0xB3, 
+0xA5, 0x55, 0xA5, 0x35, 0xA5, 0x34, 0x9C, 0xF4, 
+0x94, 0xB2, 0x6B, 0x4C, 0x6B, 0x4B, 0x7B, 0xAC, 
+0x8C, 0x0D, 0x8B, 0xED, 0x8C, 0x0D, 0x8C, 0x2D, 
+0x8C, 0x2E, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x31, 
+0xA4, 0xD0, 0xA4, 0xB0, 0xA4, 0xD0, 0xAC, 0xF1, 
+0xBD, 0x93, 0xAC, 0xF0, 0xA4, 0x6E, 0x73, 0x09, 
+0x73, 0x4A, 0x94, 0x0C, 0xB5, 0x31, 0xBD, 0x72, 
+0xBD, 0xD4, 0xCE, 0x36, 0xA5, 0x32, 0xAD, 0x53, 
+0xAD, 0x53, 0xB5, 0x94, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xA5, 0x12, 0xB5, 0x73, 0xBD, 0xD4, 0xBD, 0xB4, 
+0xB5, 0x73, 0xB5, 0xB4, 0xAD, 0x52, 0x9C, 0xF1, 
+0xAD, 0x53, 0x94, 0x90, 0x73, 0x8C, 0x84, 0x0E, 
+0x83, 0xEE, 0x7B, 0xAC, 0x9C, 0x8E, 0xAD, 0x10, 
+0xCE, 0x14, 0xCE, 0x14, 0xDE, 0x96, 0xCE, 0x14, 
+0xC5, 0xD2, 0xCD, 0xF3, 0xB5, 0x51, 0x94, 0x4E, 
+0x39, 0xC5, 0x41, 0xE7, 0x42, 0x27, 0x29, 0x64, 
+0x29, 0x65, 0x42, 0x07, 0x4A, 0x69, 0x52, 0xAA, 
+0x5A, 0xCB, 0x5A, 0xEB, 0x62, 0xEB, 0xA4, 0xF4, 
+0xC5, 0xF8, 0x7B, 0xF0, 0xAD, 0x76, 0xDE, 0xBB, 
+0xA4, 0xF3, 0x94, 0x50, 0x83, 0xAC, 0x9C, 0x6E, 
+0x94, 0x2D, 0x94, 0x2E, 0x94, 0x0D, 0x7B, 0x6A, 
+0x83, 0xCC, 0x7B, 0x4A, 0x73, 0x2A, 0x29, 0x44, 
+0x52, 0xA9, 0x5A, 0xCA, 0x42, 0x07, 0x31, 0x65, 
+0x39, 0xC7, 0x4A, 0x49, 0x52, 0x6A, 0x62, 0xEC, 
+0x84, 0x10, 0x6B, 0x0D, 0x41, 0xC7, 0xAD, 0x34, 
+0xB5, 0x34, 0xC5, 0xB6, 0xE6, 0x99, 0xAC, 0xD2, 
+0x6B, 0x0B, 0xBD, 0xB6, 0x9C, 0x91, 0x7B, 0x8C, 
+0x8B, 0xEC, 0x9C, 0x4D, 0xA4, 0xAE, 0xAC, 0xAF, 
+0xA4, 0x8F, 0x94, 0x4E, 0x8B, 0xEC, 0x7B, 0xAC, 
+0x83, 0xCC, 0x8C, 0x0D, 0x8B, 0xEC, 0x8C, 0x2D, 
+0xA4, 0xD0, 0xAC, 0xF0, 0x9C, 0x8F, 0x83, 0xEC, 
+0x94, 0x6F, 0x8C, 0x2E, 0x83, 0xED, 0x8C, 0x4E, 
+0xB5, 0x52, 0xB5, 0x93, 0xB5, 0x93, 0x7B, 0xAC, 
+0x6B, 0x4B, 0x7B, 0xAB, 0xA4, 0xAF, 0x73, 0x2A, 
+0x9C, 0xB0, 0xBD, 0xD4, 0xC5, 0xF5, 0xC6, 0x15, 
+0xC6, 0x15, 0xC5, 0xF5, 0xAD, 0x73, 0xB5, 0x74, 
+0xC6, 0x38, 0xAD, 0x76, 0xA5, 0x34, 0xCE, 0x57, 
+0xC6, 0x16, 0xB5, 0x73, 0xBD, 0xF5, 0xCE, 0x56, 
+0xC5, 0xF5, 0xBD, 0xF5, 0xBD, 0xD5, 0xC5, 0xF6, 
+0xC6, 0x36, 0xBD, 0xD5, 0xA5, 0x12, 0x7B, 0xCD, 
+0x8C, 0x2E, 0x94, 0x90, 0xBD, 0xD5, 0xC5, 0xF6, 
+0xBD, 0xD5, 0xB5, 0x73, 0xAD, 0x53, 0x94, 0x90, 
+0x8C, 0x2E, 0x8C, 0x4F, 0x84, 0x4F, 0x8C, 0x90, 
+0x8C, 0x70, 0xA5, 0x12, 0xBD, 0xF5, 0xBD, 0xD5, 
+0xB5, 0x94, 0xC5, 0xF5, 0xBD, 0xD4, 0xB5, 0x73, 
+0xA4, 0xD1, 0xA4, 0xF2, 0x9C, 0xB0, 0x83, 0xEE, 
+0x73, 0x4C, 0x73, 0x6C, 0x7B, 0x8D, 0x7B, 0xAD, 
+0x7B, 0xAD, 0x83, 0xCD, 0x7B, 0xAD, 0x7B, 0xCD, 
+0x83, 0xEE, 0x8C, 0x0E, 0x83, 0xEE, 0x83, 0xCD, 
+0x7B, 0xAD, 0x7B, 0xCD, 0x7B, 0xAD, 0x7B, 0xAD, 
+0x73, 0x8D, 0x6B, 0x4C, 0x5A, 0xEA, 0x6B, 0x4C, 
+0x73, 0x8D, 0x6B, 0x6C, 0xA4, 0xF2, 0xB5, 0x73, 
+0xCE, 0x16, 0x8C, 0x0D, 0x94, 0x6F, 0x94, 0x8F, 
+0x9C, 0xD1, 0xA5, 0x32, 0x9C, 0xB0, 0xA4, 0xF1, 
+0x9C, 0xF2, 0x94, 0x90, 0x7C, 0x0E, 0x73, 0x8D, 
+0x84, 0x0F, 0x8C, 0x70, 0xA5, 0x33, 0xB5, 0x94, 
+0xBD, 0xF6, 0xB5, 0xD5, 0xBD, 0xF6, 0xA5, 0x54, 
+0x94, 0x91, 0xA5, 0x12, 0x8C, 0x4F, 0xB5, 0x94, 
+0xBD, 0x94, 0xBD, 0xB4, 0xA4, 0xD1, 0x94, 0x4F, 
+0x9C, 0x90, 0x9C, 0x90, 0x9C, 0xB1, 0x9C, 0xD1, 
+0x9C, 0xB1, 0x9C, 0x90, 0x9C, 0xD1, 0xA5, 0x12, 
+0x9C, 0xB1, 0x9C, 0xD1, 0xA4, 0xD1, 0x9C, 0xD1, 
+0xA4, 0xF1, 0xAD, 0x52, 0xC5, 0xD4, 0xB5, 0x52, 
+0xAD, 0x11, 0xBD, 0xB3, 0x9C, 0xB0, 0xAD, 0x32, 
+0x9C, 0xB0, 0x83, 0xEE, 0x8C, 0x2E, 0xA4, 0xD0, 
+0xAD, 0x11, 0x9C, 0xB0, 0xB5, 0x53, 0xB5, 0x93, 
+0xB5, 0x73, 0x9C, 0xD1, 0x94, 0x8F, 0x9C, 0x90, 
+0xA4, 0xD1, 0x9C, 0xD0, 0x9C, 0xB0, 0xA4, 0xF1, 
+0x9C, 0xD0, 0x9C, 0xD1, 0x9C, 0xB0, 0x94, 0x6E, 
+0x83, 0xED, 0x9C, 0x8F, 0x83, 0xCC, 0xB5, 0x73, 
+0x9C, 0xB0, 0xBD, 0x93, 0xAD, 0x52, 0xB5, 0x93, 
+0xAD, 0x32, 0xB5, 0x73, 0xBD, 0xB4, 0xB5, 0x93, 
+0xB5, 0x93, 0xB5, 0x73, 0xAD, 0x53, 0xA4, 0xF1, 
+0x9C, 0xD1, 0x9C, 0x90, 0x94, 0x6F, 0x94, 0x90, 
+0xAD, 0x12, 0xAD, 0x33, 0x9C, 0x90, 0xA4, 0xD1, 
+0xA4, 0xD1, 0x94, 0x2E, 0xA4, 0xD1, 0xBD, 0x94, 
+0x8C, 0x2E, 0x8C, 0x0E, 0x7B, 0x8C, 0x83, 0xED, 
+0x94, 0x2E, 0x9C, 0x6F, 0x8C, 0x0E, 0x94, 0x4E, 
+0xA4, 0xB0, 0xAD, 0x11, 0xB5, 0x52, 0xAC, 0xF1, 
+0xB5, 0x52, 0xAD, 0x11, 0xB5, 0x32, 0xAD, 0x11, 
+0xA5, 0x55, 0xA5, 0x55, 0xA5, 0x35, 0x9C, 0xF4, 
+0x8C, 0x92, 0x63, 0x0B, 0x6B, 0x4B, 0x7B, 0xAC, 
+0x8C, 0x0D, 0x8C, 0x2E, 0x8C, 0x2E, 0x94, 0x4E, 
+0x94, 0x4E, 0xAD, 0x11, 0xB5, 0x52, 0xB5, 0x72, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xAD, 0x11, 0xB5, 0x31, 
+0xBD, 0x72, 0x94, 0x2D, 0x8B, 0xCC, 0x8B, 0xCC, 
+0x9C, 0x2E, 0x8B, 0xCC, 0xB5, 0x10, 0xBD, 0x73, 
+0xCE, 0x56, 0xC6, 0x15, 0xAD, 0x73, 0xB5, 0x73, 
+0xB5, 0x94, 0xBD, 0xB5, 0xBD, 0xF5, 0xBD, 0xF5, 
+0x84, 0x0E, 0xC6, 0x16, 0xCE, 0x36, 0xC6, 0x16, 
+0xC6, 0x16, 0xBD, 0xD5, 0xAD, 0x32, 0xAD, 0x53, 
+0xB5, 0xD5, 0xAD, 0x33, 0x94, 0x90, 0x94, 0x70, 
+0x8C, 0x0E, 0x94, 0x6E, 0xB5, 0x51, 0xCE, 0x13, 
+0xCE, 0x55, 0xCE, 0x34, 0xDE, 0xB6, 0xDE, 0x74, 
+0xD6, 0x12, 0xD6, 0x33, 0xC5, 0xB1, 0xD6, 0x54, 
+0xAD, 0x31, 0x52, 0x88, 0x42, 0x27, 0x39, 0xE7, 
+0x29, 0x65, 0x29, 0x65, 0x4A, 0x69, 0x4A, 0x48, 
+0x52, 0x8A, 0x62, 0xEC, 0x7B, 0xCF, 0xA5, 0x35, 
+0xA4, 0xF4, 0xAD, 0x55, 0xB5, 0xB7, 0xC6, 0x39, 
+0xDE, 0xDB, 0x9C, 0xD2, 0x94, 0x4F, 0xA4, 0xAF, 
+0x9C, 0x8F, 0xA4, 0xD0, 0xAC, 0xF0, 0xA4, 0x6F, 
+0x9C, 0x4E, 0xA4, 0xAF, 0x83, 0xAC, 0x31, 0x65, 
+0x52, 0xAA, 0x4A, 0x48, 0x39, 0xA6, 0x42, 0x07, 
+0x42, 0x28, 0x4A, 0x49, 0x52, 0x6A, 0xA5, 0x34, 
+0xA5, 0x14, 0x94, 0x31, 0x5A, 0x6A, 0x62, 0xAA, 
+0xB5, 0x54, 0xBD, 0x95, 0xC5, 0x95, 0xDE, 0x78, 
+0xA4, 0xB2, 0x73, 0x4C, 0xB5, 0x33, 0xAC, 0xF1, 
+0xAC, 0xF1, 0x8C, 0x0C, 0x94, 0x0C, 0x8B, 0xEC, 
+0x9C, 0x4E, 0xA4, 0x8E, 0xAC, 0xCF, 0xB4, 0xF0, 
+0xAC, 0xD0, 0xAC, 0xCF, 0xAC, 0xCF, 0xB5, 0x10, 
+0xB5, 0x30, 0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x30, 
+0xAC, 0xF0, 0xAC, 0xEF, 0xAC, 0xCF, 0xAC, 0xD0, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAE, 0x94, 0x2D, 
+0x94, 0x2D, 0x9C, 0x6E, 0xB5, 0x10, 0xAC, 0xCF, 
+0x9C, 0x8E, 0x94, 0x4E, 0x94, 0x0D, 0x8C, 0x0D, 
+0x94, 0x4E, 0x94, 0x2D, 0x8C, 0x0D, 0x94, 0x6F, 
+0xCE, 0x59, 0xAD, 0x96, 0x9C, 0xD3, 0x83, 0xCD, 
+0x9C, 0x8F, 0x8C, 0x2E, 0x84, 0x0D, 0xAD, 0x11, 
+0xAD, 0x11, 0xB5, 0x72, 0xBD, 0xB4, 0xBD, 0xD5, 
+0xA5, 0x11, 0x7B, 0xAC, 0x9C, 0xF1, 0x7B, 0xCD, 
+0x83, 0xED, 0x8C, 0x2F, 0xA5, 0x12, 0xAD, 0x53, 
+0xAD, 0x32, 0x94, 0x6F, 0x7B, 0xCD, 0x94, 0x6F, 
+0x9C, 0xB0, 0x94, 0x70, 0x94, 0x90, 0x94, 0x90, 
+0x94, 0x90, 0x7B, 0xAD, 0xA5, 0x12, 0xBD, 0xD5, 
+0xAD, 0x52, 0xC5, 0xF5, 0xB5, 0x93, 0xBD, 0xD5, 
+0xAD, 0x53, 0xAD, 0x53, 0x9C, 0xD1, 0x7B, 0xAD, 
+0x6B, 0x0B, 0x63, 0x0B, 0x6B, 0x4C, 0x73, 0x6C, 
+0x73, 0x8C, 0x7B, 0xAC, 0x83, 0xCD, 0x6B, 0x2B, 
+0x84, 0x0E, 0x83, 0xEE, 0x84, 0x0E, 0x73, 0x8C, 
+0x7B, 0x8C, 0x7B, 0xAC, 0x7B, 0x8C, 0x73, 0x6C, 
+0x63, 0x2B, 0x5A, 0xCA, 0x52, 0xAA, 0x63, 0x2B, 
+0x6B, 0x4C, 0x6B, 0x4C, 0xAD, 0x33, 0xAD, 0x53, 
+0xCE, 0x56, 0x8C, 0x2E, 0x94, 0x6F, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xA5, 0x11, 0xA4, 0xF1, 0xA4, 0xF1, 
+0x94, 0x90, 0x9C, 0xD1, 0x94, 0xB0, 0x7B, 0xEE, 
+0x8C, 0x70, 0x9C, 0xD1, 0xA5, 0x53, 0xB5, 0x94, 
+0xBE, 0x16, 0xB5, 0xB5, 0xBD, 0xD5, 0x9D, 0x13, 
+0x9C, 0xD2, 0xAD, 0x74, 0x94, 0x70, 0xBD, 0x94, 
+0xBD, 0xB4, 0xB5, 0x53, 0x9C, 0x90, 0x9C, 0x90, 
+0xA4, 0xD1, 0x9C, 0xB0, 0xA4, 0xF1, 0xAD, 0x53, 
+0xAD, 0x12, 0xAD, 0x12, 0xAD, 0x73, 0xBD, 0xB5, 
+0xAD, 0x53, 0x9C, 0xB0, 0xA4, 0xD1, 0xAD, 0x53, 
+0xB5, 0x74, 0xBD, 0x94, 0xBD, 0x73, 0xAD, 0x11, 
+0xB5, 0x72, 0xCE, 0x15, 0x9C, 0xB0, 0xAD, 0x32, 
+0xB5, 0x72, 0x8C, 0x2E, 0x8C, 0x0D, 0xA4, 0xB0, 
+0x8C, 0x2E, 0x84, 0x0D, 0x9C, 0x90, 0xBD, 0xD4, 
+0xBD, 0xD4, 0xAD, 0x53, 0xA5, 0x11, 0xAD, 0x32, 
+0xAD, 0x52, 0xAD, 0x32, 0xAD, 0x32, 0xBD, 0xD4, 
+0xB5, 0x94, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x73, 
+0xAD, 0x11, 0xAD, 0x31, 0x94, 0x6F, 0xBD, 0x93, 
+0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x93, 0xB5, 0x93, 
+0xBD, 0x94, 0xCE, 0x36, 0xC6, 0x15, 0xC6, 0x36, 
+0xC6, 0x36, 0xC6, 0x36, 0xCE, 0x36, 0xC6, 0x36, 
+0xBD, 0xD5, 0xB5, 0xB4, 0xBD, 0xD5, 0xBD, 0xD5, 
+0xD6, 0x98, 0xD6, 0x77, 0xC6, 0x16, 0xCE, 0x57, 
+0xD6, 0x77, 0xAD, 0x52, 0x83, 0xED, 0xB5, 0x53, 
+0x83, 0xCD, 0x8C, 0x4E, 0x8C, 0x0E, 0x94, 0x70, 
+0xA4, 0xD0, 0xAD, 0x11, 0xC5, 0xB3, 0xCD, 0xF4, 
+0xCD, 0xF4, 0xD6, 0x35, 0xC5, 0xD4, 0x9C, 0x8F, 
+0xBD, 0x72, 0xD6, 0x54, 0xDE, 0x55, 0xDE, 0x75, 
+0xA5, 0x55, 0xA5, 0x35, 0xA5, 0x35, 0x9C, 0xF4, 
+0x8C, 0x92, 0x62, 0xEB, 0x5A, 0xA9, 0x7B, 0xAC, 
+0x83, 0xEC, 0x94, 0x4E, 0x8C, 0x2D, 0x94, 0x4E, 
+0x94, 0x6F, 0xAD, 0x32, 0xAC, 0xF1, 0xAD, 0x11, 
+0xAC, 0xF1, 0xA4, 0xD0, 0xB5, 0x32, 0xB5, 0x52, 
+0xC5, 0xB3, 0x94, 0x2E, 0x8B, 0xCC, 0x9C, 0x4E, 
+0x9C, 0x2E, 0x83, 0x8B, 0xB5, 0x11, 0xB5, 0x52, 
+0xC5, 0xF5, 0xBD, 0xB5, 0xAD, 0x74, 0xAD, 0x73, 
+0xAD, 0x53, 0xB5, 0xB4, 0xC5, 0xF5, 0xC6, 0x36, 
+0xBD, 0xD5, 0xCE, 0x77, 0xC6, 0x16, 0xC6, 0x16, 
+0xB5, 0x94, 0xB5, 0x94, 0xAD, 0x53, 0xAD, 0x53, 
+0xAD, 0x73, 0xA4, 0xF1, 0x9C, 0xB1, 0x9C, 0xB1, 
+0x94, 0x6F, 0xA4, 0xAF, 0xBD, 0x71, 0xC5, 0xD2, 
+0xBD, 0xB2, 0xC5, 0xF3, 0xCE, 0x34, 0xCD, 0xF2, 
+0xD6, 0x33, 0xCE, 0x13, 0xCD, 0xF2, 0xCD, 0xF3, 
+0xDE, 0x96, 0xB5, 0x72, 0x4A, 0x07, 0x4A, 0x48, 
+0x31, 0xA6, 0x31, 0xC6, 0x4A, 0x69, 0x4A, 0x69, 
+0x4A, 0x49, 0x63, 0x2C, 0x7B, 0xAE, 0x94, 0x92, 
+0x8C, 0x51, 0xBD, 0xD7, 0x9C, 0xB3, 0xA5, 0x35, 
+0xD6, 0xBB, 0xB5, 0x75, 0x83, 0xEE, 0x5A, 0xA9, 
+0x83, 0xCE, 0xAD, 0x32, 0xAC, 0xF1, 0x8B, 0xED, 
+0x9C, 0x6E, 0xCD, 0xD4, 0xBD, 0x73, 0x83, 0xEE, 
+0x31, 0x86, 0x29, 0x44, 0x52, 0xA9, 0x6B, 0x2C, 
+0x42, 0x08, 0x8C, 0x71, 0x7B, 0xCF, 0x9C, 0xD3, 
+0xB5, 0x96, 0xAD, 0x14, 0x7B, 0x8E, 0x4A, 0x08, 
+0x7B, 0x8D, 0xBD, 0x75, 0xB5, 0x13, 0xC5, 0x95, 
+0xCD, 0xF7, 0x94, 0x50, 0x6B, 0x0B, 0x7B, 0x6D, 
+0x8B, 0xEE, 0x83, 0xCD, 0x7B, 0xAD, 0x7B, 0x8C, 
+0x6B, 0x2A, 0x83, 0xAB, 0xAC, 0xF0, 0x7B, 0x6B, 
+0x73, 0x2A, 0x7B, 0x8B, 0x7B, 0x6B, 0x7B, 0x6B, 
+0x6A, 0xE9, 0x6B, 0x09, 0x7B, 0x8B, 0x83, 0xAB, 
+0x83, 0xAC, 0x83, 0xAB, 0x94, 0x0D, 0x94, 0x0D, 
+0x93, 0xEC, 0x9C, 0x2D, 0xAC, 0xEF, 0xA4, 0xAF, 
+0xA4, 0x8E, 0xA4, 0x8E, 0xB4, 0xEF, 0xAC, 0xCF, 
+0xB5, 0x30, 0xB5, 0x30, 0xBD, 0x71, 0xAC, 0xCF, 
+0xA4, 0x6E, 0xA4, 0x6E, 0xA4, 0x8E, 0xAC, 0xF2, 
+0xCE, 0x59, 0xB5, 0xB7, 0xAD, 0x75, 0xA4, 0xD1, 
+0xAC, 0xCF, 0xAC, 0xCF, 0xAC, 0xCF, 0xA4, 0xAE, 
+0x9C, 0x8E, 0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x6F, 
+0x9C, 0x6E, 0x9C, 0x4E, 0xAD, 0x32, 0xB5, 0x32, 
+0xAD, 0x32, 0xA4, 0xF2, 0xA4, 0xF1, 0xA4, 0xD1, 
+0xA4, 0xF1, 0x9C, 0xD1, 0x9C, 0xB1, 0x9C, 0xD1, 
+0x9C, 0xB1, 0x94, 0x70, 0x94, 0x6F, 0x8C, 0x0E, 
+0x8C, 0x2E, 0x84, 0x0E, 0x8C, 0x2E, 0x8C, 0x2F, 
+0x83, 0xEE, 0x94, 0x6F, 0x9C, 0xB0, 0x94, 0x90, 
+0x83, 0xED, 0x73, 0x6C, 0x9C, 0xD1, 0x7B, 0xCD, 
+0x7B, 0x8D, 0x5A, 0xCA, 0x5A, 0xAA, 0x83, 0xEE, 
+0x94, 0x70, 0x8C, 0x2F, 0x83, 0xEE, 0x84, 0x0E, 
+0x8C, 0x4F, 0x94, 0xB0, 0x94, 0x90, 0x8C, 0x2F, 
+0x7B, 0xCD, 0x7B, 0xAD, 0x73, 0x6C, 0x6B, 0x4C, 
+0x6B, 0x4C, 0x6B, 0x4C, 0x63, 0x2C, 0x63, 0x2C, 
+0x63, 0x0B, 0x73, 0x6C, 0xAD, 0x53, 0xB5, 0x73, 
+0xD6, 0x77, 0x94, 0x8F, 0x94, 0x6F, 0x9C, 0x90, 
+0x9C, 0xD0, 0xA5, 0x11, 0xB5, 0x73, 0xAD, 0x52, 
+0x9C, 0xD1, 0xA5, 0x32, 0xAD, 0x53, 0x94, 0xB0, 
+0x9C, 0xF1, 0xA5, 0x32, 0xAD, 0x53, 0xC6, 0x36, 
+0xC6, 0x16, 0xBD, 0xD5, 0xC6, 0x16, 0xA5, 0x33, 
+0x9D, 0x13, 0xAD, 0x53, 0xA4, 0xD1, 0xB5, 0x94, 
+0xB5, 0x53, 0xA4, 0xD1, 0x9C, 0x90, 0xAD, 0x32, 
+0xBD, 0x93, 0xAD, 0x12, 0xB5, 0x53, 0xC5, 0xD5, 
+0xB5, 0x53, 0xA5, 0x12, 0xB5, 0x94, 0xC5, 0xD5, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xA4, 0xD1, 0xAD, 0x32, 
+0xB5, 0x94, 0xC5, 0xF5, 0xBD, 0xB4, 0xB5, 0x72, 
+0xAD, 0x11, 0xD6, 0x36, 0xA4, 0xB0, 0xAD, 0x11, 
+0xAD, 0x32, 0x83, 0xED, 0x83, 0xCC, 0xA4, 0xB0, 
+0x9C, 0x8F, 0x8C, 0x0D, 0x84, 0x0D, 0xAD, 0x11, 
+0xC5, 0xF5, 0x94, 0x8F, 0xAD, 0x32, 0xA5, 0x11, 
+0xB5, 0x73, 0xB5, 0x94, 0xBD, 0xB4, 0xC5, 0xD5, 
+0xB5, 0x73, 0xB5, 0x94, 0xBD, 0xB4, 0xB5, 0x93, 
+0x9C, 0xB0, 0xA4, 0xF0, 0x94, 0x4E, 0xBD, 0x93, 
+0xB5, 0x73, 0xB5, 0x93, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xD6, 0x77, 0xCE, 0x56, 0xCE, 0x56, 
+0xD6, 0x76, 0xC6, 0x15, 0xBD, 0xD5, 0xBD, 0xD5, 
+0xBD, 0xF5, 0xBD, 0xD5, 0xBD, 0xF5, 0xCE, 0x56, 
+0xCE, 0x36, 0xBD, 0xB4, 0xAD, 0x52, 0xAD, 0x32, 
+0xAD, 0x73, 0xAD, 0x32, 0x94, 0x6F, 0xB5, 0x53, 
+0xA4, 0xB1, 0xB5, 0x53, 0xAD, 0x53, 0xAD, 0x32, 
+0xAD, 0x32, 0xC5, 0xB4, 0xB5, 0x72, 0xC5, 0xD3, 
+0xC5, 0xD3, 0xC5, 0xD3, 0xC5, 0x93, 0xA4, 0xB0, 
+0xD6, 0x14, 0xE6, 0x95, 0xDE, 0x53, 0xDE, 0x53, 
+0xA5, 0x55, 0xA5, 0x35, 0xA5, 0x35, 0x9C, 0xF4, 
+0x8C, 0x92, 0x52, 0x89, 0x4A, 0x27, 0x7B, 0x8C, 
+0x8C, 0x0D, 0x8C, 0x0D, 0x8C, 0x0D, 0x94, 0x4E, 
+0x9C, 0x6F, 0xA4, 0xB0, 0x94, 0x2E, 0x83, 0xEC, 
+0xAD, 0x11, 0xAD, 0x31, 0xB5, 0x52, 0xBD, 0x73, 
+0xCD, 0xD4, 0x9C, 0x6E, 0x83, 0xAC, 0x73, 0x2A, 
+0x52, 0x27, 0x52, 0x47, 0xAC, 0xF0, 0xA4, 0xD0, 
+0xB5, 0x94, 0xBD, 0xD5, 0xB5, 0x94, 0xAD, 0x73, 
+0xAD, 0x53, 0xBD, 0xD5, 0xBD, 0xF5, 0xBD, 0xF5, 
+0xB5, 0x73, 0xC6, 0x36, 0xB5, 0xB4, 0xBD, 0xF5, 
+0xB5, 0x94, 0xBD, 0xD5, 0xAD, 0x53, 0xAD, 0x53, 
+0xAD, 0x53, 0xA5, 0x12, 0x94, 0xB1, 0x9C, 0xF2, 
+0x94, 0x90, 0xA4, 0xF0, 0xBD, 0x71, 0xB5, 0x71, 
+0x8C, 0x0C, 0x94, 0x6E, 0x8C, 0x2D, 0xBD, 0x91, 
+0xCE, 0x13, 0xCE, 0x13, 0xD6, 0x33, 0xCD, 0xD2, 
+0xCE, 0x13, 0xDE, 0x76, 0x94, 0x4E, 0x41, 0xE6, 
+0x39, 0xC6, 0x3A, 0x07, 0x42, 0x28, 0x4A, 0x48, 
+0x4A, 0x69, 0x52, 0x8A, 0x63, 0x0C, 0x63, 0x0C, 
+0x9C, 0xB3, 0xBD, 0xD7, 0xAD, 0x56, 0xA5, 0x15, 
+0xBD, 0xD7, 0xBD, 0xB6, 0x94, 0x92, 0x4A, 0x69, 
+0x6B, 0x2C, 0xCE, 0x16, 0xA4, 0xB0, 0x8B, 0xED, 
+0x9C, 0x6E, 0xB5, 0x32, 0xAC, 0xF0, 0xAD, 0x12, 
+0xA4, 0xF2, 0xA5, 0x12, 0xB5, 0x74, 0x6B, 0x4C, 
+0x42, 0x07, 0x94, 0xB2, 0x94, 0xB2, 0xA4, 0xF4, 
+0xB5, 0x96, 0xBD, 0xD7, 0xA4, 0xF3, 0x9C, 0x92, 
+0x41, 0xE8, 0x83, 0xCE, 0xB5, 0x33, 0xB5, 0x13, 
+0xA4, 0xB1, 0xC5, 0xB6, 0x8B, 0xCF, 0x7B, 0x4C, 
+0x94, 0x4F, 0x94, 0x70, 0x94, 0xB1, 0x9C, 0xB1, 
+0x84, 0x0E, 0x9C, 0x6F, 0xB5, 0x31, 0x83, 0xAC, 
+0x62, 0xE9, 0x84, 0x0E, 0x7B, 0xED, 0x7B, 0xCD, 
+0x63, 0x2B, 0x6B, 0x4B, 0x84, 0x4F, 0x9C, 0xD1, 
+0x94, 0xB1, 0x94, 0x90, 0x84, 0x2E, 0x6B, 0x2B, 
+0x5A, 0x89, 0x52, 0x68, 0x62, 0xEA, 0x5A, 0xA9, 
+0x63, 0x2A, 0x7B, 0xCC, 0x8C, 0x0E, 0x8C, 0x0D, 
+0x94, 0x4D, 0x9C, 0x6D, 0xBD, 0x51, 0x9C, 0x2D, 
+0x62, 0xA8, 0x62, 0xE9, 0x6B, 0x0A, 0x94, 0x91, 
+0xC6, 0x38, 0xBD, 0xF8, 0xCE, 0x59, 0x8B, 0xEE, 
+0x73, 0x4A, 0x83, 0x8C, 0x8B, 0xEC, 0x94, 0x0D, 
+0x94, 0x0D, 0x7B, 0x6B, 0x8B, 0xCC, 0x83, 0x8B, 
+0x7B, 0x6A, 0x83, 0xAC, 0x93, 0xED, 0x94, 0x0D, 
+0x8B, 0xEE, 0x94, 0x0E, 0xB5, 0x53, 0xAD, 0x12, 
+0xA4, 0xD1, 0x94, 0x70, 0xA4, 0xD1, 0x9C, 0xB1, 
+0x94, 0x4F, 0xA4, 0xF2, 0xAD, 0x12, 0x9C, 0xB1, 
+0xA5, 0x12, 0xAD, 0x32, 0xAD, 0x33, 0xB5, 0x53, 
+0xB5, 0x74, 0xAD, 0x33, 0xAD, 0x53, 0xB5, 0x53, 
+0xAD, 0x33, 0xAD, 0x33, 0xB5, 0x94, 0xAD, 0x12, 
+0x9C, 0xD1, 0x9C, 0xB1, 0xA4, 0xD2, 0x94, 0x90, 
+0x94, 0x6F, 0x94, 0x4F, 0x94, 0x90, 0x9C, 0x90, 
+0x84, 0x0E, 0x94, 0x6F, 0x94, 0x6F, 0x9C, 0x90, 
+0x94, 0x90, 0x94, 0x70, 0x7B, 0xCE, 0x7B, 0xAD, 
+0x73, 0x8C, 0x73, 0x6C, 0x6B, 0x4C, 0x6B, 0x2C, 
+0x63, 0x0B, 0x73, 0x6C, 0xAD, 0x53, 0x9C, 0xD1, 
+0xAD, 0x12, 0x8C, 0x4E, 0x83, 0xCD, 0x7B, 0xAC, 
+0x83, 0xED, 0x84, 0x0D, 0x84, 0x0E, 0xAD, 0x53, 
+0xBD, 0xD4, 0xB5, 0xB4, 0xB5, 0x94, 0xAD, 0x73, 
+0x94, 0x90, 0xA5, 0x12, 0xA5, 0x32, 0xBD, 0xD5, 
+0xA5, 0x33, 0x8C, 0x4F, 0xB5, 0x94, 0xAD, 0x53, 
+0xAD, 0x74, 0xA5, 0x33, 0xAD, 0x12, 0xB5, 0x73, 
+0xD6, 0x57, 0xAD, 0x53, 0xA4, 0xF1, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xF5, 0xC6, 0x15, 0xB5, 0x52, 
+0x9C, 0xB0, 0xA4, 0xF1, 0xBD, 0xB5, 0xBD, 0xD5, 
+0xB5, 0x94, 0xBD, 0xB5, 0xBD, 0xB5, 0xB5, 0x94, 
+0xB5, 0x73, 0xC5, 0xF4, 0xCE, 0x35, 0xD6, 0x35, 
+0xBD, 0x72, 0xC5, 0xB4, 0xA4, 0xD0, 0x94, 0x6F, 
+0xB5, 0x52, 0x94, 0x6F, 0x8C, 0x2E, 0xA4, 0xF1, 
+0x9C, 0xAF, 0x9C, 0xAF, 0x83, 0xCD, 0x9C, 0xD0, 
+0xC5, 0xF5, 0x9C, 0xD0, 0xAD, 0x52, 0xA4, 0xF1, 
+0xBD, 0xB4, 0xB5, 0xB4, 0xB5, 0x93, 0xC5, 0xD5, 
+0xBD, 0x94, 0xB5, 0x73, 0xAD, 0x52, 0xAD, 0x53, 
+0x94, 0x4E, 0x9C, 0xB0, 0x8C, 0x2D, 0xAD, 0x32, 
+0xBD, 0xB4, 0xB5, 0x73, 0xB5, 0x73, 0xBD, 0xD4, 
+0xBD, 0xB4, 0xD6, 0x97, 0xD6, 0x76, 0xCE, 0x56, 
+0xCE, 0x56, 0xC6, 0x15, 0xC6, 0x15, 0xC6, 0x15, 
+0xAD, 0x53, 0x8C, 0x4F, 0xB5, 0x73, 0xD6, 0x77, 
+0xC5, 0xF5, 0xBD, 0xB4, 0xAD, 0x53, 0xA5, 0x12, 
+0x9C, 0xF1, 0x9C, 0xB0, 0x8C, 0x0D, 0xB5, 0x53, 
+0xA4, 0xF1, 0xBD, 0xB4, 0xC5, 0xD5, 0xB5, 0x94, 
+0xB5, 0x73, 0xC5, 0xD4, 0xAD, 0x10, 0xCD, 0xF4, 
+0xCE, 0x14, 0xC5, 0xD4, 0xBD, 0x72, 0xA4, 0x8F, 
+0xDE, 0x55, 0xDE, 0x33, 0xD5, 0xF2, 0xCD, 0x91, 
+0xA5, 0x35, 0xB5, 0xB7, 0xA5, 0x34, 0x9C, 0xF4, 
+0x8C, 0x92, 0x63, 0x0B, 0x62, 0xC9, 0x62, 0xC9, 
+0x6B, 0x09, 0x6B, 0x09, 0x73, 0x4A, 0x73, 0x4A, 
+0x73, 0x4A, 0x6B, 0x2A, 0x7B, 0x8B, 0x73, 0x29, 
+0x8C, 0x0D, 0x9C, 0x6F, 0x9C, 0x6E, 0xAD, 0x11, 
+0xBD, 0x73, 0x8B, 0xCC, 0xB4, 0xF1, 0x93, 0xED, 
+0x5A, 0x68, 0x62, 0x88, 0xAC, 0xF1, 0xB5, 0x52, 
+0xB5, 0x73, 0xB5, 0x93, 0xB5, 0xB4, 0xBD, 0xF5, 
+0xB5, 0xD5, 0xBD, 0xF5, 0xC6, 0x16, 0xBD, 0xF5, 
+0xBD, 0xD5, 0xC6, 0x57, 0xC6, 0x36, 0xBD, 0xF5, 
+0xB5, 0x94, 0xB5, 0xB5, 0xB5, 0xB4, 0xAD, 0x74, 
+0xB5, 0x94, 0xAD, 0x94, 0xA5, 0x13, 0xA5, 0x12, 
+0x9C, 0xD1, 0xAD, 0x10, 0xB5, 0x30, 0xCE, 0x14, 
+0xC5, 0xD4, 0x73, 0x8B, 0x7B, 0x8B, 0x84, 0x0C, 
+0xCE, 0x34, 0xCD, 0xF2, 0xCD, 0xF2, 0xBD, 0x91, 
+0xC5, 0xB2, 0xD6, 0x54, 0xD6, 0x35, 0x73, 0x4B, 
+0x39, 0xC6, 0x42, 0x07, 0x42, 0x07, 0x42, 0x28, 
+0x4A, 0x69, 0x52, 0xAA, 0x5A, 0xEB, 0x6B, 0x6D, 
+0x9C, 0xD3, 0xAD, 0x55, 0xB5, 0x96, 0x94, 0xB3, 
+0xBD, 0xD7, 0xA5, 0x14, 0xAD, 0x35, 0x73, 0x8E, 
+0x73, 0x8E, 0xC5, 0xF6, 0xBD, 0x74, 0xAC, 0xD0, 
+0xA4, 0xB0, 0xAC, 0xD0, 0xAC, 0xF1, 0xB5, 0x53, 
+0xCE, 0x15, 0xD6, 0x56, 0x94, 0x70, 0x31, 0x45, 
+0x29, 0x65, 0x42, 0x08, 0x4A, 0x49, 0x7B, 0xAF, 
+0x84, 0x10, 0xA4, 0xF3, 0x94, 0x92, 0xAD, 0x34, 
+0x94, 0x51, 0x4A, 0x28, 0x8B, 0xEE, 0xAC, 0xF2, 
+0xB5, 0x12, 0xBD, 0x54, 0xB5, 0x33, 0x94, 0x0F, 
+0x7B, 0x4C, 0x8C, 0x2F, 0xAD, 0x33, 0x94, 0x91, 
+0x94, 0x70, 0xA4, 0xD1, 0xB5, 0x31, 0x83, 0xAB, 
+0x62, 0xEA, 0x73, 0xAD, 0x73, 0xAD, 0x73, 0xAD, 
+0x6B, 0x6D, 0x73, 0x8D, 0x8C, 0x4F, 0xA5, 0x33, 
+0xB5, 0x95, 0xBD, 0xF6, 0xA5, 0x53, 0x7B, 0xCE, 
+0x6B, 0x6C, 0x52, 0xAA, 0x5A, 0xCA, 0x6B, 0x4C, 
+0x8C, 0x70, 0xB5, 0xB4, 0xB5, 0x74, 0xAD, 0x53, 
+0x94, 0x8F, 0x9C, 0x6D, 0xBD, 0x51, 0xAC, 0xCF, 
+0x83, 0xAC, 0x83, 0xCD, 0x83, 0xCD, 0xA5, 0x34, 
+0xBD, 0xF7, 0xB5, 0xB7, 0x84, 0x10, 0x83, 0xEF, 
+0x73, 0x4B, 0x8C, 0x0E, 0x8C, 0x0E, 0x8C, 0x0D, 
+0xA4, 0xD0, 0x94, 0x4E, 0x8B, 0xCC, 0x7B, 0x4B, 
+0x6B, 0x0A, 0x6A, 0xCA, 0x73, 0x0A, 0x7B, 0x0A, 
+0x73, 0x0A, 0x7B, 0x4B, 0xB5, 0x53, 0x8C, 0x2E, 
+0xA5, 0x12, 0xA4, 0xD1, 0x94, 0x70, 0x9C, 0xB1, 
+0xA5, 0x12, 0xAD, 0x53, 0xA5, 0x12, 0x7B, 0xCD, 
+0x83, 0xEE, 0xA5, 0x12, 0xA4, 0xF1, 0xA4, 0xD1, 
+0x94, 0x70, 0x73, 0x6C, 0x7B, 0xAD, 0xA4, 0xD1, 
+0xB5, 0x74, 0xAD, 0x13, 0xAD, 0x12, 0xAD, 0x33, 
+0xAD, 0x12, 0x8C, 0x4F, 0x9C, 0xD1, 0xAD, 0x33, 
+0xA4, 0xF2, 0xA4, 0xD1, 0xA4, 0xF1, 0x9C, 0xB1, 
+0x9C, 0xB1, 0xA4, 0xF1, 0x9C, 0xD1, 0x94, 0x90, 
+0xAD, 0x13, 0x9C, 0xB1, 0x9C, 0xD1, 0xA5, 0x12, 
+0xAD, 0x33, 0xAD, 0x33, 0xAD, 0x12, 0xAD, 0x33, 
+0xAD, 0x33, 0xAD, 0x12, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x53, 0xA4, 0xF1, 0xAD, 0x32, 0xAD, 0x12, 
+0xAD, 0x12, 0xAD, 0x12, 0xA4, 0xD1, 0x9C, 0xD1, 
+0x94, 0x90, 0x94, 0x90, 0x8C, 0x4F, 0x8C, 0x4F, 
+0x83, 0xEE, 0x94, 0x4F, 0x83, 0xEE, 0x8C, 0x4F, 
+0x8C, 0x6F, 0x8C, 0x2E, 0x9C, 0xB0, 0x84, 0x0E, 
+0xA4, 0xF2, 0x8C, 0x2F, 0xA5, 0x12, 0xA4, 0xF1, 
+0xB5, 0x94, 0xB5, 0x73, 0xAD, 0x32, 0xB5, 0x32, 
+0xB5, 0x32, 0xB5, 0x52, 0xB5, 0x52, 0x8C, 0x2E, 
+0x94, 0x4F, 0x9C, 0xB0, 0x94, 0x6F, 0x9C, 0xD0, 
+0xB5, 0x73, 0xA5, 0x12, 0xB5, 0x53, 0xBD, 0xD5, 
+0xBD, 0xB4, 0xA4, 0xF1, 0xBD, 0x73, 0xCE, 0x15, 
+0xD6, 0x35, 0xC5, 0xD4, 0x94, 0x4E, 0xA4, 0xD0, 
+0xAD, 0x52, 0x7B, 0x8C, 0xB5, 0x52, 0x6B, 0x4B, 
+0x73, 0x6B, 0xA4, 0xF1, 0xA5, 0x11, 0xA5, 0x11, 
+0x9C, 0xB0, 0xAD, 0x52, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xBD, 0xF5, 0x8C, 0x4F, 0xAD, 0x32, 0xC5, 0xF5, 
+0xC5, 0xF5, 0x94, 0x70, 0x6B, 0x4B, 0xBD, 0xD5, 
+0xBD, 0xB4, 0xAD, 0x32, 0x94, 0x6F, 0xAD, 0x11, 
+0xC5, 0xD5, 0xBD, 0xD4, 0xB5, 0x93, 0xBD, 0xD4, 
+0xC5, 0xF5, 0xCE, 0x15, 0xCE, 0x15, 0xBD, 0xD4, 
+0xC6, 0x15, 0xC6, 0x15, 0xD6, 0x56, 0xC6, 0x15, 
+0xB5, 0x94, 0x9C, 0xB1, 0x94, 0x70, 0xCE, 0x36, 
+0xCE, 0x57, 0xC6, 0x15, 0xBD, 0xD5, 0xBD, 0xF5, 
+0xB5, 0x94, 0xB5, 0x94, 0x94, 0x6F, 0xB5, 0x73, 
+0xAD, 0x12, 0xB5, 0x94, 0xB5, 0x94, 0xBD, 0x94, 
+0xBD, 0x93, 0xC5, 0xB3, 0xB5, 0x72, 0xC5, 0xD3, 
+0xCE, 0x14, 0xCE, 0x14, 0xC5, 0xB3, 0x9C, 0x8F, 
+0xDE, 0x55, 0xD6, 0x12, 0xBD, 0x50, 0xBD, 0x50, 
+0xA5, 0x35, 0xBD, 0xF8, 0xA5, 0x35, 0x9C, 0xF4, 
+0x8C, 0x72, 0x73, 0x6C, 0x7B, 0x8B, 0x83, 0xAC, 
+0x83, 0xCC, 0x8B, 0xCC, 0x8B, 0xEC, 0x94, 0x0C, 
+0x94, 0x4D, 0x94, 0x4D, 0x94, 0x2D, 0x94, 0x2D, 
+0xA4, 0x8E, 0xA4, 0x8F, 0xA4, 0x6E, 0x9C, 0x4D, 
+0x94, 0x2D, 0x8B, 0xEC, 0x94, 0x0C, 0x94, 0x0C, 
+0x94, 0x2D, 0xA4, 0x8F, 0xB5, 0x10, 0xAC, 0xEF, 
+0xAD, 0x10, 0xAD, 0x31, 0x9C, 0xAF, 0xA4, 0xF1, 
+0xAD, 0x52, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x93, 
+0xAD, 0x52, 0xB5, 0x73, 0xC5, 0xF5, 0xBD, 0xB4, 
+0xAD, 0x32, 0xBD, 0xB4, 0xC6, 0x16, 0xC5, 0xF5, 
+0xCE, 0x57, 0xCE, 0x77, 0xC6, 0x16, 0xC5, 0xF5, 
+0xB5, 0x93, 0xA4, 0xCF, 0xAC, 0xEF, 0xCE, 0x13, 
+0xCE, 0x34, 0xAC, 0xF1, 0x5A, 0xA8, 0x73, 0x6A, 
+0xCE, 0x14, 0xD6, 0x13, 0xCD, 0xF3, 0xCD, 0xF2, 
+0xD6, 0x13, 0xD6, 0x14, 0xD6, 0x34, 0xC5, 0x93, 
+0x4A, 0x07, 0x31, 0xA6, 0x42, 0x07, 0x42, 0x27, 
+0x42, 0x28, 0x52, 0x89, 0x5A, 0xCB, 0x63, 0x2C, 
+0x83, 0xF0, 0xA5, 0x14, 0xAD, 0x55, 0x9C, 0xB3, 
+0xAD, 0x76, 0xAD, 0x55, 0xA5, 0x35, 0x94, 0x92, 
+0x42, 0x08, 0x73, 0x6D, 0xC5, 0xD6, 0x94, 0x2F, 
+0x94, 0x2E, 0xA4, 0x8F, 0x94, 0x2E, 0xA4, 0xF0, 
+0xBD, 0xB4, 0xB5, 0x52, 0x8C, 0x0E, 0x29, 0x24, 
+0x29, 0x45, 0x29, 0x65, 0x41, 0xE7, 0x4A, 0x49, 
+0x7B, 0xCF, 0xAD, 0x34, 0xB5, 0x96, 0xBD, 0xB6, 
+0x83, 0xEF, 0x73, 0x4D, 0x39, 0x86, 0x62, 0xCB, 
+0xA4, 0x91, 0xAC, 0xD2, 0x9C, 0x50, 0x7B, 0x6C, 
+0x7B, 0x6D, 0x94, 0x50, 0xC5, 0xD6, 0xCD, 0xF7, 
+0x9C, 0xB2, 0xAC, 0xF1, 0xB5, 0x31, 0x7B, 0x6B, 
+0x84, 0x0F, 0x84, 0x50, 0x84, 0x2F, 0x7B, 0xEF, 
+0x73, 0xAE, 0x7B, 0xCE, 0x94, 0x90, 0xAD, 0x33, 
+0xC6, 0x16, 0xB5, 0xB4, 0x9C, 0xF2, 0x94, 0x91, 
+0x73, 0xAE, 0x6B, 0x6D, 0x6B, 0x6C, 0x84, 0x0F, 
+0xA5, 0x13, 0xC6, 0x16, 0xC5, 0xF6, 0xBD, 0xD5, 
+0xA5, 0x32, 0x9C, 0x6E, 0xBD, 0x51, 0xA4, 0x6E, 
+0x94, 0x2E, 0x83, 0xED, 0x7B, 0xAD, 0xB5, 0xB6, 
+0xB5, 0xB7, 0x94, 0x92, 0x63, 0x2C, 0x94, 0x71, 
+0x7B, 0x8C, 0x7B, 0x8C, 0x7B, 0xCC, 0x7B, 0xAC, 
+0x83, 0xED, 0x9C, 0x6F, 0x8B, 0xED, 0x7B, 0x8B, 
+0x7B, 0x8C, 0x7B, 0x6B, 0x73, 0x0A, 0x83, 0x4B, 
+0x83, 0x4B, 0x8B, 0xAD, 0xBD, 0x94, 0xA5, 0x12, 
+0xC6, 0x16, 0xB5, 0xB5, 0xAD, 0x74, 0xA5, 0x33, 
+0xAD, 0x74, 0xB5, 0xB5, 0xB5, 0x94, 0xAD, 0x74, 
+0xAD, 0x73, 0xB5, 0xB4, 0xB5, 0x94, 0xB5, 0x94, 
+0xB5, 0x74, 0x84, 0x0E, 0x73, 0x8C, 0x83, 0xED, 
+0xC6, 0x16, 0xCE, 0x36, 0xC5, 0xD5, 0xC5, 0xF5, 
+0xBD, 0xD5, 0x8C, 0x2F, 0x8C, 0x2F, 0x94, 0xB0, 
+0x94, 0x90, 0x7B, 0xED, 0x9C, 0xD1, 0x94, 0x90, 
+0x94, 0x4F, 0x9C, 0xD1, 0xA4, 0xF2, 0xA5, 0x12, 
+0xB5, 0x94, 0xAD, 0x53, 0x8C, 0x4F, 0x94, 0x90, 
+0xA4, 0xD1, 0xB5, 0x74, 0xB5, 0x53, 0xB5, 0x53, 
+0xA4, 0xD1, 0x9C, 0x90, 0x8C, 0x4F, 0x84, 0x0E, 
+0x94, 0x4F, 0x9C, 0x90, 0x7B, 0xCD, 0x8C, 0x2F, 
+0xAD, 0x32, 0xB5, 0x32, 0xBD, 0x94, 0xBD, 0xB4, 
+0x9C, 0xB0, 0x9C, 0x70, 0x9C, 0xB0, 0x9C, 0xB0, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xB5, 0x32, 0xAD, 0x12, 
+0xA4, 0xD1, 0xAD, 0x12, 0xA4, 0xD0, 0x9C, 0xB0, 
+0x9C, 0xB0, 0x9C, 0x90, 0xAD, 0x32, 0xB5, 0x73, 
+0xB5, 0x32, 0xAD, 0x12, 0xAD, 0x12, 0xB5, 0x53, 
+0xC5, 0xD5, 0xC5, 0xB4, 0xBD, 0x94, 0x94, 0x6F, 
+0xA5, 0x12, 0xAD, 0x32, 0xAD, 0x12, 0xA4, 0xF1, 
+0x9C, 0x90, 0xA4, 0xB1, 0xA4, 0xD1, 0xA4, 0xF1, 
+0xAC, 0xF2, 0xA4, 0xD1, 0xAC, 0xF1, 0xA4, 0xD0, 
+0xA4, 0xB0, 0xAC, 0xD0, 0xAD, 0x12, 0xB5, 0x73, 
+0xAD, 0x12, 0x94, 0x8F, 0xA4, 0xF1, 0x73, 0x4C, 
+0x73, 0x6C, 0x8C, 0x4E, 0xA5, 0x11, 0xAD, 0x31, 
+0xAD, 0x11, 0xB5, 0x53, 0xB5, 0x93, 0xBD, 0xB4, 
+0xC5, 0xF5, 0xA5, 0x11, 0xAD, 0x32, 0xC6, 0x15, 
+0xC5, 0xF5, 0xAD, 0x32, 0xA5, 0x12, 0xC5, 0xD5, 
+0xC6, 0x15, 0xAD, 0x52, 0xA4, 0xD0, 0xB5, 0x73, 
+0xC5, 0xF5, 0xD6, 0x97, 0xCE, 0x36, 0xCE, 0x35, 
+0xCE, 0x56, 0xCE, 0x56, 0xD6, 0x76, 0xCE, 0x35, 
+0xCE, 0x36, 0xC5, 0xF4, 0xCE, 0x15, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xC5, 0xF5, 0x9C, 0xB1, 0xA4, 0xF1, 
+0xDE, 0xD8, 0xD6, 0x77, 0xCE, 0x36, 0xCE, 0x56, 
+0xCE, 0x36, 0xBD, 0xD4, 0x9C, 0x8F, 0xB5, 0x73, 
+0x9C, 0x90, 0xB5, 0x53, 0xB5, 0x94, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD3, 0xBD, 0x72, 0xC5, 0xB3, 
+0xCE, 0x14, 0xD6, 0x35, 0xCE, 0x14, 0x9C, 0x8F, 
+0xDE, 0x35, 0xD5, 0xF2, 0xBD, 0x50, 0xBD, 0x30, 
+0xA5, 0x35, 0xB5, 0xB7, 0x9D, 0x14, 0x94, 0xF3, 
+0x8C, 0x71, 0x62, 0xEA, 0x73, 0x4B, 0x6B, 0x2A, 
+0x6B, 0x2A, 0x83, 0xCC, 0x94, 0x2D, 0x83, 0xCB, 
+0x8C, 0x0D, 0x9C, 0xAF, 0xA4, 0xF0, 0x9C, 0x6E, 
+0x9C, 0x6E, 0x9C, 0x6E, 0xA4, 0xAF, 0xB5, 0x30, 
+0xB5, 0x10, 0xAC, 0xEF, 0xAC, 0xF0, 0xA4, 0x8E, 
+0xB5, 0x10, 0xB5, 0x10, 0x9C, 0x2D, 0xAC, 0xCF, 
+0xB5, 0x10, 0xB5, 0x31, 0xA4, 0xCF, 0xA4, 0xAF, 
+0xA4, 0x8F, 0xA4, 0xAF, 0xA4, 0x8E, 0x9C, 0x8E, 
+0x9C, 0x8E, 0x9C, 0x6E, 0xA4, 0x8E, 0xA4, 0xAF, 
+0xAC, 0xCF, 0xA4, 0xCF, 0xA4, 0xCF, 0xA4, 0xCF, 
+0x9C, 0x8E, 0x9C, 0x8E, 0x9C, 0x8E, 0xA4, 0xAF, 
+0xA4, 0xCF, 0xAC, 0xCF, 0xAD, 0x0F, 0xAC, 0xEF, 
+0xB5, 0x51, 0xAC, 0xEF, 0x83, 0xCB, 0x8B, 0xEC, 
+0xBD, 0x71, 0xBD, 0x71, 0xC5, 0x91, 0xC5, 0xB1, 
+0xC5, 0x91, 0xB5, 0x0F, 0xAD, 0x0F, 0xCD, 0xF3, 
+0x83, 0xCC, 0x39, 0xC6, 0x42, 0x27, 0x42, 0x07, 
+0x42, 0x28, 0x39, 0xC6, 0x4A, 0x28, 0x52, 0x8A, 
+0x63, 0x0C, 0x84, 0x31, 0x94, 0x92, 0x9C, 0xF4, 
+0xA5, 0x14, 0xB5, 0x96, 0xA5, 0x15, 0x94, 0x92, 
+0x63, 0x0C, 0x29, 0x45, 0x8C, 0x30, 0xC5, 0xD5, 
+0xB5, 0x11, 0xBD, 0x52, 0xB5, 0x32, 0xAD, 0x11, 
+0xBD, 0x73, 0xBD, 0x72, 0xBD, 0x73, 0x83, 0xCD, 
+0x52, 0x68, 0x29, 0x44, 0x29, 0x65, 0x41, 0xE7, 
+0x4A, 0x28, 0x62, 0xEB, 0x73, 0x4C, 0x52, 0x69, 
+0x39, 0xC7, 0x29, 0x45, 0x18, 0xC3, 0x4A, 0x07, 
+0x62, 0xCB, 0x7B, 0x4C, 0xA4, 0x71, 0x8B, 0xCF, 
+0xB5, 0x55, 0xC5, 0xD6, 0xAD, 0x13, 0xDE, 0x9A, 
+0xBD, 0x75, 0xA4, 0xB1, 0xB5, 0x10, 0x94, 0x2E, 
+0x84, 0x0F, 0x94, 0x91, 0x8C, 0x71, 0x84, 0x30, 
+0x7B, 0xEF, 0x84, 0x0F, 0x94, 0x90, 0x9C, 0xF2, 
+0xA5, 0x33, 0x9C, 0xD1, 0x8C, 0x6F, 0x73, 0xCD, 
+0x73, 0xAD, 0x73, 0xCE, 0x7B, 0xCE, 0x84, 0x0F, 
+0x9C, 0xF2, 0xC6, 0x16, 0xB5, 0xD5, 0xA5, 0x32, 
+0xAD, 0x53, 0x94, 0x4D, 0xB5, 0x10, 0x8B, 0xCB, 
+0xA4, 0xD0, 0xA4, 0xF0, 0x8C, 0x0E, 0xBD, 0xF7, 
+0xB5, 0x76, 0x9C, 0xD3, 0x73, 0xAE, 0x83, 0xEE, 
+0x8C, 0x2E, 0x83, 0xCD, 0x73, 0x6B, 0x84, 0x0D, 
+0x8C, 0x0D, 0xA4, 0xD0, 0x7B, 0x6B, 0x8B, 0xED, 
+0x8C, 0x0D, 0x94, 0x0E, 0x83, 0x6B, 0x8B, 0x6C, 
+0x8B, 0x8C, 0x94, 0x0E, 0xBD, 0x94, 0xAD, 0x53, 
+0xC6, 0x36, 0xBD, 0xB5, 0xAD, 0x74, 0xAD, 0x53, 
+0xB5, 0x74, 0xBD, 0xD5, 0xB5, 0x74, 0x8C, 0x4F, 
+0x9C, 0xF1, 0xA5, 0x12, 0xB5, 0x94, 0xBD, 0xF5, 
+0xBD, 0xB5, 0x94, 0x90, 0x8C, 0x4F, 0x62, 0xE9, 
+0xB5, 0x73, 0xCE, 0x77, 0xCE, 0x77, 0xCE, 0x36, 
+0xC6, 0x16, 0x8C, 0x2F, 0x94, 0x70, 0x9C, 0xD1, 
+0xA5, 0x32, 0x94, 0x90, 0xA5, 0x12, 0xA4, 0xF1, 
+0xA5, 0x12, 0xAD, 0x73, 0xAD, 0x74, 0xAD, 0x53, 
+0xB5, 0x74, 0xAD, 0x53, 0x8C, 0x2F, 0x9C, 0xB1, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xAD, 0x32, 0x94, 0x6F, 
+0x94, 0x4F, 0xA4, 0xF1, 0x94, 0x6F, 0x84, 0x0E, 
+0x8C, 0x4F, 0x83, 0xED, 0x7B, 0xAC, 0x8C, 0x2E, 
+0xBD, 0x93, 0xC5, 0xF5, 0xDE, 0xD8, 0xDE, 0xB7, 
+0xB5, 0x53, 0x8C, 0x0E, 0x8C, 0x0D, 0x83, 0xED, 
+0x7B, 0xAC, 0x83, 0xAC, 0x83, 0xCC, 0x94, 0x4F, 
+0xAC, 0xF2, 0xCE, 0x16, 0xD6, 0x98, 0xBD, 0xB4, 
+0x8C, 0x0E, 0x8C, 0x0E, 0xA4, 0xB0, 0xBD, 0x52, 
+0xBD, 0x73, 0xBD, 0x73, 0xAC, 0xD0, 0x9C, 0x6F, 
+0xA4, 0xD0, 0x9C, 0x8F, 0x94, 0x4F, 0x9C, 0x6F, 
+0xA4, 0xB0, 0x9C, 0x6F, 0x9C, 0xB0, 0xA4, 0xB1, 
+0x94, 0x4F, 0x8C, 0x0E, 0x94, 0x4F, 0x94, 0x2F, 
+0x94, 0x4F, 0x9C, 0x90, 0xA4, 0xD1, 0xAC, 0xF1, 
+0xAC, 0xF1, 0xB5, 0x32, 0xBD, 0x73, 0xBD, 0x93, 
+0xC5, 0xB4, 0xC5, 0xD4, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xCE, 0x16, 0xBD, 0x73, 0xAD, 0x12, 0xB5, 0x32, 
+0xBD, 0x73, 0xB5, 0x52, 0xB5, 0x52, 0xA4, 0xD1, 
+0xA4, 0xD0, 0xA4, 0xB0, 0x9C, 0xB0, 0x9C, 0xB0, 
+0x9C, 0x8F, 0x9C, 0x8F, 0xA4, 0xF1, 0xAC, 0xF1, 
+0xAD, 0x11, 0x9C, 0xB0, 0xB5, 0x53, 0xAD, 0x11, 
+0xA4, 0xF1, 0xB5, 0x52, 0xAD, 0x32, 0xAD, 0x11, 
+0xAD, 0x11, 0xAD, 0x32, 0xB5, 0x52, 0xB5, 0x73, 
+0xAD, 0x32, 0x9C, 0x8F, 0x94, 0x6F, 0xAD, 0x32, 
+0xBD, 0xD5, 0xC5, 0xD5, 0xB5, 0x73, 0x9C, 0xB0, 
+0xCE, 0x56, 0xCE, 0x56, 0xCE, 0x56, 0xD6, 0x56, 
+0xC5, 0xF5, 0xBD, 0x93, 0x9C, 0x90, 0xB5, 0x73, 
+0xC5, 0xD5, 0xCE, 0x15, 0xC5, 0xF5, 0xCE, 0x15, 
+0xCE, 0x35, 0xCE, 0x14, 0xC5, 0xF4, 0xD6, 0x55, 
+0xD6, 0x55, 0xD6, 0x55, 0xC5, 0xB3, 0x94, 0x4E, 
+0xDE, 0x35, 0xBD, 0x50, 0xA4, 0xAE, 0x94, 0x2D, 
+0xA5, 0x35, 0xB5, 0xB7, 0x9D, 0x14, 0x9C, 0xF3, 
+0x8C, 0x92, 0x7B, 0xEE, 0x84, 0x2F, 0x84, 0x0E, 
+0x7B, 0xED, 0x9C, 0xD0, 0xAD, 0x52, 0xA5, 0x11, 
+0x9C, 0xF0, 0xA5, 0x31, 0xB5, 0x93, 0xA4, 0xF1, 
+0xAD, 0x11, 0xAD, 0x31, 0xBD, 0xB3, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xA4, 0xCF, 0x8C, 0x2D, 0x9C, 0x8F, 
+0xBD, 0x93, 0xAD, 0x31, 0x63, 0x0A, 0xAD, 0x32, 
+0x94, 0x6E, 0xAD, 0x32, 0xCE, 0x36, 0xB5, 0x73, 
+0xBD, 0x93, 0xC5, 0xF4, 0xA4, 0xF0, 0xAD, 0x31, 
+0x94, 0x6E, 0x94, 0x6F, 0x9C, 0x8F, 0x94, 0x6F, 
+0xA4, 0xAF, 0xB5, 0x51, 0xAC, 0xF0, 0xB5, 0x10, 
+0x94, 0x0C, 0x83, 0xCB, 0x94, 0x2D, 0x94, 0x2D, 
+0x94, 0x0C, 0x9C, 0x6E, 0xA4, 0xCE, 0xAC, 0xEF, 
+0xAC, 0xCF, 0xA4, 0xCF, 0xB5, 0x10, 0xAC, 0xEF, 
+0xAC, 0xEF, 0xB4, 0xEF, 0xAC, 0xCE, 0xAC, 0xCE, 
+0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xAC, 0xF0, 0x7B, 0x8B, 0x39, 0xA5, 0x39, 0xC6, 
+0x41, 0xE6, 0x42, 0x07, 0x4A, 0x48, 0x4A, 0x48, 
+0x63, 0x2C, 0x73, 0x8E, 0x94, 0x92, 0xA5, 0x14, 
+0x9C, 0xD3, 0xB5, 0x76, 0xAD, 0x55, 0x94, 0xB3, 
+0x73, 0x6E, 0x29, 0x25, 0x39, 0xE7, 0xA4, 0xF2, 
+0xBD, 0x73, 0xAC, 0xF0, 0xAC, 0xD0, 0xAC, 0xF1, 
+0xAD, 0x11, 0xAC, 0xF1, 0xB5, 0x32, 0xBD, 0x93, 
+0xB5, 0x32, 0x73, 0x4B, 0x29, 0x44, 0x39, 0xA6, 
+0x4A, 0x48, 0x29, 0x45, 0x31, 0x85, 0x31, 0x65, 
+0x39, 0xA6, 0x4A, 0x49, 0x39, 0xC7, 0x31, 0x45, 
+0x52, 0x28, 0x6A, 0xAA, 0x94, 0x0F, 0x9C, 0x51, 
+0xA4, 0xD3, 0x94, 0x51, 0xB5, 0x34, 0xA4, 0xD3, 
+0xCE, 0x18, 0xBD, 0x74, 0xB5, 0x31, 0xB5, 0x32, 
+0x84, 0x0F, 0xB5, 0x95, 0xAD, 0x94, 0xAD, 0x74, 
+0x94, 0x91, 0xA5, 0x13, 0xAD, 0x74, 0xB5, 0x94, 
+0xAD, 0x54, 0x73, 0xAD, 0x6B, 0x4C, 0x5A, 0xEA, 
+0x73, 0xAD, 0x7B, 0xEF, 0x8C, 0x50, 0x8C, 0x70, 
+0xB5, 0xB5, 0xC6, 0x37, 0xC6, 0x16, 0x83, 0xEE, 
+0x83, 0xEE, 0x9C, 0x6E, 0xB5, 0x10, 0x7B, 0x8A, 
+0xA4, 0xD0, 0xAC, 0xF1, 0xA5, 0x12, 0xC6, 0x18, 
+0xB5, 0x76, 0x9C, 0xF4, 0x73, 0x8D, 0x83, 0xAD, 
+0x9C, 0x90, 0x83, 0xED, 0x73, 0x4B, 0x8C, 0x2E, 
+0xA4, 0xB0, 0xAD, 0x11, 0xA4, 0xB0, 0xA4, 0xB0, 
+0x9C, 0x6F, 0xA4, 0x8F, 0x83, 0x6B, 0x93, 0xAC, 
+0x93, 0xAC, 0x94, 0x0E, 0xBD, 0x94, 0xB5, 0x94, 
+0xC6, 0x36, 0xB5, 0xB4, 0xB5, 0x74, 0xAD, 0x53, 
+0xB5, 0x94, 0xAD, 0x73, 0xAD, 0x32, 0x9C, 0xB1, 
+0xA5, 0x32, 0xB5, 0x94, 0xB5, 0x94, 0xBD, 0xD5, 
+0xBD, 0xD5, 0xBD, 0xD5, 0xBD, 0xF5, 0x9C, 0xD1, 
+0x94, 0x6F, 0xB5, 0x94, 0xCE, 0x36, 0xC6, 0x16, 
+0xC5, 0xF5, 0x84, 0x2E, 0x9C, 0xD1, 0xA5, 0x12, 
+0xA4, 0xF2, 0x9C, 0xB1, 0xA5, 0x12, 0xA5, 0x32, 
+0xA5, 0x33, 0xBD, 0xF5, 0xAD, 0x74, 0xA5, 0x33, 
+0xB5, 0x94, 0xAD, 0x73, 0x83, 0xEE, 0x9C, 0xD1, 
+0xA4, 0xF1, 0x9C, 0xD1, 0xA4, 0xF2, 0x84, 0x0E, 
+0x84, 0x0E, 0xA5, 0x12, 0x9C, 0xB0, 0x94, 0x4F, 
+0x94, 0x90, 0x8C, 0x2E, 0x94, 0x4F, 0x9C, 0x90, 
+0xBD, 0x93, 0xCE, 0x36, 0xDE, 0xB7, 0xD6, 0x76, 
+0xCE, 0x15, 0xA4, 0xD1, 0x94, 0x6F, 0x94, 0x4E, 
+0x7B, 0xAC, 0x7B, 0x8C, 0x7B, 0xAD, 0x94, 0x6F, 
+0xAD, 0x12, 0xB5, 0x53, 0xC5, 0xD5, 0xAD, 0x32, 
+0x83, 0xEE, 0x94, 0x4F, 0xB5, 0x12, 0xBD, 0x52, 
+0xC5, 0x93, 0xBD, 0x73, 0x9C, 0x2E, 0xA4, 0x6F, 
+0xA4, 0xB0, 0x94, 0x4F, 0x9C, 0x90, 0xAD, 0x32, 
+0xAD, 0x32, 0xAD, 0x12, 0x9C, 0xB0, 0x9C, 0x90, 
+0x94, 0x6F, 0xA4, 0xF1, 0x9C, 0xD1, 0x94, 0x6F, 
+0x8C, 0x2F, 0x94, 0x6F, 0x8C, 0x2E, 0xA4, 0xD1, 
+0x8C, 0x2E, 0x94, 0x70, 0x9C, 0xB0, 0x8C, 0x2E, 
+0x7B, 0xAC, 0x83, 0xCD, 0x83, 0xCD, 0x83, 0xCD, 
+0xB5, 0x53, 0x8C, 0x2E, 0x8C, 0x2E, 0x94, 0x6F, 
+0x9C, 0x70, 0x9C, 0x90, 0x9C, 0x90, 0x94, 0x2E, 
+0x94, 0x4F, 0x9C, 0x8F, 0x94, 0x6F, 0x9C, 0x6F, 
+0x9C, 0xB0, 0xA4, 0xD1, 0xAD, 0x32, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xB5, 0x32, 0xB5, 0x32, 
+0xB5, 0x53, 0xBD, 0x73, 0xB5, 0x53, 0xB5, 0x32, 
+0xBD, 0x73, 0xB5, 0x32, 0xAC, 0xF2, 0xAC, 0xD1, 
+0xA4, 0xD1, 0xAC, 0xF1, 0xAC, 0xF1, 0xA4, 0xF1, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF2, 0xAD, 0x12, 
+0xAC, 0xF1, 0xA4, 0xF1, 0xA4, 0xB0, 0x9C, 0xB0, 
+0x9C, 0x90, 0x9C, 0xB0, 0xAD, 0x12, 0xB5, 0x53, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xAC, 0xF0, 0xA4, 0xD0, 0xA4, 0xD0, 0xAC, 0xF0, 
+0xA4, 0xD0, 0xA4, 0xD0, 0x94, 0x2D, 0xA4, 0xB0, 
+0xCD, 0xB3, 0xC5, 0x91, 0xBD, 0x72, 0x9C, 0x6E, 
+0xA5, 0x35, 0xAD, 0x96, 0x9D, 0x14, 0x9C, 0xF4, 
+0x8C, 0x92, 0x84, 0x0F, 0x8C, 0x90, 0x8C, 0x70, 
+0x8C, 0x4F, 0xA5, 0x11, 0xB5, 0x73, 0xAD, 0x52, 
+0xA5, 0x11, 0xAD, 0x52, 0xBD, 0xB4, 0xB5, 0x73, 
+0xAD, 0x52, 0xA4, 0xF1, 0xC5, 0xF4, 0xA4, 0xAF, 
+0xAC, 0xEF, 0xBD, 0xD3, 0xA5, 0x11, 0xA5, 0x12, 
+0xB5, 0x93, 0xAD, 0x52, 0xAD, 0x53, 0xAD, 0x53, 
+0x9C, 0xD1, 0xBD, 0xD5, 0xBD, 0xB4, 0xC6, 0x15, 
+0xB5, 0x93, 0xB5, 0x94, 0xB5, 0x73, 0xB5, 0x93, 
+0xB5, 0x93, 0xAD, 0x73, 0xBD, 0xD5, 0xBD, 0xB4, 
+0xA4, 0xF1, 0xB5, 0x93, 0xAD, 0x11, 0xB5, 0x10, 
+0x9C, 0x4E, 0x9C, 0xB0, 0xAD, 0x32, 0xAD, 0x32, 
+0xA4, 0xF1, 0xAD, 0x52, 0xB5, 0x72, 0xBD, 0xB4, 
+0xBD, 0x93, 0xB5, 0x52, 0xB5, 0x72, 0xB5, 0x52, 
+0x94, 0x6F, 0xB5, 0x52, 0xB5, 0x32, 0xA4, 0xF0, 
+0xBD, 0x73, 0xAC, 0xF0, 0x9C, 0x8F, 0x9C, 0x8F, 
+0xA4, 0xCF, 0x94, 0x2E, 0x52, 0x88, 0x31, 0xA5, 
+0x39, 0xE6, 0x41, 0xE6, 0x42, 0x07, 0x39, 0xC7, 
+0x4A, 0x69, 0x6B, 0x4D, 0x84, 0x10, 0x9C, 0xD3, 
+0x9C, 0xF3, 0xAD, 0x76, 0xB5, 0x97, 0xB5, 0x96, 
+0xA5, 0x35, 0x7B, 0xAF, 0x7B, 0xEE, 0xA4, 0xF1, 
+0xAC, 0xF1, 0xB4, 0xF0, 0xB4, 0xF0, 0xB4, 0xF0, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xB5, 0x11, 0xAC, 0xF0, 
+0xAC, 0xCF, 0xAC, 0xD0, 0x8B, 0xED, 0x7B, 0xAC, 
+0x52, 0x48, 0x31, 0x85, 0x39, 0xC6, 0x39, 0xE7, 
+0x39, 0xC6, 0x6B, 0x0C, 0x6B, 0x2C, 0x5A, 0xAA, 
+0x41, 0xA6, 0x62, 0x8A, 0x83, 0x4C, 0x6A, 0xAA, 
+0x9C, 0x92, 0x8B, 0xF0, 0xC5, 0xD7, 0xA4, 0xD3, 
+0xAD, 0x34, 0xC5, 0xD6, 0xD5, 0xF5, 0xCD, 0x93, 
+0xAC, 0xD0, 0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0xD1, 
+0x94, 0x70, 0x9C, 0xD1, 0xB5, 0x94, 0xBD, 0xD5, 
+0xB5, 0xB4, 0x94, 0xB0, 0x84, 0x0E, 0x73, 0xAE, 
+0x7B, 0xCE, 0x7C, 0x0F, 0x9C, 0xF2, 0xAD, 0x95, 
+0xDE, 0xDA, 0xCE, 0x79, 0xC6, 0x17, 0xB5, 0x95, 
+0xBD, 0x95, 0xB5, 0x32, 0xB5, 0x10, 0xA4, 0xAF, 
+0xBD, 0x93, 0xBD, 0x93, 0xBD, 0xB4, 0xC6, 0x18, 
+0xAD, 0x56, 0xA4, 0xF3, 0xA4, 0xF2, 0x9C, 0x90, 
+0x94, 0x2E, 0x7B, 0xAC, 0x7B, 0xAC, 0x94, 0x4F, 
+0xAD, 0x11, 0xB5, 0x72, 0xBD, 0x72, 0xAC, 0xD0, 
+0xAC, 0xD0, 0xA4, 0x8F, 0x7B, 0x0A, 0x83, 0x6B, 
+0x8B, 0x6B, 0x9C, 0x4F, 0xB5, 0x73, 0xBD, 0xF5, 
+0xC6, 0x36, 0xBD, 0xD5, 0xBD, 0xB5, 0xB5, 0x94, 
+0xBD, 0xD5, 0xB5, 0x94, 0xA4, 0xF2, 0xA5, 0x12, 
+0xA5, 0x32, 0xA5, 0x32, 0xAD, 0x53, 0xBD, 0xB5, 
+0xBD, 0xF5, 0xB5, 0xB4, 0xB5, 0xB4, 0xBD, 0xF5, 
+0xBD, 0xD5, 0xC6, 0x16, 0xC6, 0x36, 0xC6, 0x16, 
+0xBD, 0xD5, 0x84, 0x2E, 0xA5, 0x12, 0xAD, 0x33, 
+0xA4, 0xF2, 0x9C, 0xD1, 0x9C, 0xF1, 0x94, 0x90, 
+0x9C, 0xB1, 0xAD, 0x73, 0xAD, 0x53, 0xB5, 0xB5, 
+0xBD, 0xF6, 0xB5, 0xB5, 0x8C, 0x6F, 0xA5, 0x12, 
+0x9C, 0xD1, 0xAD, 0x12, 0xBD, 0xB5, 0xB5, 0x74, 
+0xA5, 0x12, 0xA4, 0xF1, 0x9C, 0xD1, 0x9C, 0xD1, 
+0x9C, 0xB0, 0x9C, 0x90, 0x9C, 0xB1, 0x9C, 0xB1, 
+0xBD, 0x73, 0xCE, 0x35, 0xC5, 0xF4, 0xCE, 0x15, 
+0xC5, 0xF4, 0xA4, 0xF0, 0xA4, 0xD0, 0xAD, 0x11, 
+0x8B, 0xED, 0xA4, 0xD1, 0x94, 0x6F, 0x9C, 0xB0, 
+0x9C, 0xB1, 0x94, 0x70, 0xB5, 0x74, 0x94, 0x90, 
+0x8C, 0x2F, 0xA4, 0xD1, 0xAC, 0xF2, 0xBD, 0x53, 
+0xCD, 0xB4, 0xC5, 0x73, 0x83, 0x8C, 0xA4, 0x6F, 
+0xA4, 0xF1, 0x9C, 0xB0, 0x94, 0x6F, 0xB5, 0x53, 
+0xB5, 0x73, 0xAD, 0x53, 0xA4, 0xF2, 0xA4, 0xD1, 
+0x9C, 0xB1, 0xB5, 0x73, 0xAD, 0x53, 0xA5, 0x12, 
+0xA4, 0xF1, 0x94, 0x90, 0x9C, 0x90, 0xA4, 0xF2, 
+0xA4, 0xF2, 0xAD, 0x53, 0xAD, 0x53, 0xA5, 0x12, 
+0x9C, 0xB1, 0x7B, 0xCD, 0x94, 0x70, 0x8C, 0x4F, 
+0xAD, 0x33, 0x83, 0xED, 0x9C, 0x90, 0xA4, 0xF1, 
+0x8C, 0x2E, 0x8B, 0xED, 0x9C, 0x6F, 0x94, 0x2E, 
+0x94, 0x4E, 0x83, 0xCD, 0x83, 0xED, 0x8B, 0xEE, 
+0xA4, 0xD1, 0x94, 0x4F, 0x94, 0x8F, 0x9C, 0x90, 
+0x94, 0x2E, 0x8B, 0xED, 0x8C, 0x0E, 0x9C, 0x90, 
+0xA4, 0xD1, 0x9C, 0xB0, 0xAD, 0x11, 0x9C, 0xB0, 
+0xA4, 0xD1, 0x9C, 0xB0, 0x8B, 0xED, 0x7B, 0x8C, 
+0x8C, 0x0E, 0xB5, 0x53, 0xB5, 0x53, 0x9C, 0x90, 
+0xA4, 0xD1, 0xA4, 0xB0, 0xAC, 0xF1, 0xA4, 0xF1, 
+0x9C, 0x90, 0xA4, 0xD1, 0xB5, 0x32, 0xB5, 0x32, 
+0xBD, 0x53, 0xB5, 0x32, 0xB5, 0x53, 0xB5, 0x53, 
+0xBD, 0x94, 0xBD, 0x94, 0xBD, 0x73, 0xC5, 0xB5, 
+0xC5, 0xB4, 0xCD, 0xD5, 0xBD, 0x94, 0xBD, 0x73, 
+0xBD, 0x93, 0xC5, 0x94, 0xC5, 0x94, 0xC5, 0xB4, 
+0xC5, 0x93, 0xBD, 0x72, 0xB5, 0x52, 0xB5, 0x32, 
+0xA5, 0x35, 0xB5, 0xB7, 0x9D, 0x14, 0x9C, 0xF3, 
+0x8C, 0x92, 0x84, 0x0F, 0x8C, 0x91, 0x94, 0xB1, 
+0x8C, 0x4F, 0xA5, 0x12, 0xB5, 0x93, 0xAD, 0x31, 
+0xAD, 0x31, 0x9C, 0xF0, 0xBD, 0xD4, 0xB5, 0x94, 
+0xBD, 0xD4, 0xAD, 0x32, 0xC6, 0x14, 0xA4, 0xAF, 
+0xA4, 0xAE, 0xBD, 0xB3, 0xAD, 0x52, 0xA5, 0x32, 
+0xB5, 0x73, 0xAD, 0x32, 0xA5, 0x32, 0xA5, 0x32, 
+0xA5, 0x12, 0xBD, 0xD4, 0xC5, 0xF5, 0xBD, 0xF4, 
+0xB5, 0x73, 0xB5, 0xB4, 0xB5, 0x93, 0xBD, 0xB4, 
+0xC5, 0xD5, 0xB5, 0xB4, 0xB5, 0x93, 0xB5, 0x73, 
+0xB5, 0x52, 0xBD, 0x93, 0xB5, 0x72, 0xAD, 0x10, 
+0x83, 0xAB, 0xAD, 0x53, 0xAD, 0x53, 0xB5, 0xB4, 
+0x94, 0xB1, 0xB5, 0xB4, 0xB5, 0xB4, 0xC6, 0x16, 
+0xBD, 0xD5, 0xC6, 0x16, 0xC6, 0x36, 0xBD, 0xF6, 
+0xA5, 0x12, 0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x74, 
+0xBD, 0xF5, 0xBD, 0xF5, 0xBD, 0xF5, 0xC6, 0x16, 
+0xC6, 0x16, 0xA5, 0x32, 0x8C, 0x2E, 0x4A, 0x27, 
+0x39, 0xC6, 0x41, 0xE7, 0x42, 0x07, 0x4A, 0x28, 
+0x42, 0x28, 0x63, 0x2C, 0x7B, 0xCF, 0x7B, 0xCF, 
+0xA5, 0x35, 0x94, 0x92, 0x9C, 0xD3, 0xAD, 0x55, 
+0xAD, 0x75, 0xB5, 0xB6, 0xC5, 0xF7, 0xBD, 0xD5, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xBD, 0x92, 0xB5, 0x51, 
+0xB5, 0x52, 0xCD, 0xF4, 0xB5, 0x10, 0x9C, 0x6E, 
+0x83, 0x8A, 0x83, 0xAB, 0x8B, 0xCC, 0x83, 0xED, 
+0x52, 0x68, 0x29, 0x44, 0x31, 0x85, 0x39, 0xA6, 
+0x41, 0xE7, 0x63, 0x0C, 0x5A, 0xAA, 0x5A, 0x8A, 
+0x83, 0xEF, 0x52, 0x6A, 0x62, 0x69, 0x93, 0xEF, 
+0xA4, 0x92, 0x9C, 0x71, 0xC5, 0xD7, 0xD6, 0x38, 
+0xBD, 0x75, 0xBD, 0x55, 0xB5, 0x33, 0xBD, 0x52, 
+0xBD, 0x31, 0xB5, 0x10, 0xA4, 0xAF, 0x9C, 0x6E, 
+0xA4, 0x8F, 0xAC, 0xD0, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xA4, 0xD0, 0x9C, 0x8F, 0x9C, 0x8F, 0x94, 0x4F, 
+0x94, 0x6F, 0x9C, 0x8F, 0xA4, 0xAF, 0xA4, 0xF1, 
+0x7B, 0xAD, 0x6B, 0x2B, 0x5A, 0x89, 0x52, 0x69, 
+0x8C, 0x30, 0xA4, 0xF2, 0xC5, 0xD5, 0xB5, 0x52, 
+0xBD, 0x93, 0xAD, 0x11, 0xC5, 0xB5, 0xC6, 0x38, 
+0xA5, 0x55, 0x94, 0x71, 0xBD, 0x73, 0xAD, 0x11, 
+0xA4, 0xB0, 0xA4, 0xB0, 0x8C, 0x2E, 0x94, 0x2E, 
+0x94, 0x4E, 0x8C, 0x0D, 0x9C, 0x6E, 0xAC, 0xF0, 
+0xB5, 0x11, 0x8B, 0xEC, 0x73, 0x0A, 0x72, 0xE9, 
+0x73, 0x0A, 0x9C, 0x6F, 0xAD, 0x12, 0xB5, 0x73, 
+0xBD, 0xD5, 0xBD, 0xD5, 0xBD, 0xD5, 0xB5, 0x74, 
+0xB5, 0x94, 0xAD, 0x33, 0xA4, 0xF2, 0xAD, 0x73, 
+0x94, 0x6F, 0xA4, 0xF1, 0xAD, 0x53, 0xC5, 0xF6, 
+0xBD, 0xD5, 0xBD, 0xD5, 0xB5, 0x94, 0xC5, 0xF5, 
+0xCE, 0x36, 0xCE, 0x36, 0xC6, 0x16, 0xC6, 0x16, 
+0xBD, 0xB4, 0x7B, 0xCD, 0x94, 0x90, 0xB5, 0x94, 
+0xB5, 0xB4, 0xAD, 0x53, 0xB5, 0xB4, 0x84, 0x0E, 
+0x94, 0x70, 0xA5, 0x12, 0xA5, 0x12, 0xB5, 0xB5, 
+0xBD, 0xD5, 0xBD, 0xD5, 0x9C, 0xB1, 0xAD, 0x33, 
+0x9C, 0xD1, 0xAD, 0x32, 0xDE, 0xB8, 0xC6, 0x16, 
+0xC5, 0xF5, 0xBD, 0xB4, 0xB5, 0x73, 0xBD, 0x94, 
+0xBD, 0xD5, 0xBD, 0xD4, 0xC5, 0xF5, 0xA4, 0xF2, 
+0xBD, 0x94, 0xC5, 0xD4, 0xC6, 0x15, 0xC5, 0xF4, 
+0xC5, 0xD4, 0xAD, 0x11, 0xAC, 0xF0, 0xAD, 0x11, 
+0x9C, 0x8F, 0x9C, 0x90, 0x9C, 0x90, 0xA5, 0x12, 
+0xAD, 0x33, 0xAD, 0x54, 0xBD, 0xD5, 0xA4, 0xF2, 
+0x94, 0x70, 0xAC, 0xF1, 0xB5, 0x12, 0xC5, 0x94, 
+0xCD, 0xB3, 0xCD, 0x93, 0x8B, 0x8C, 0xA4, 0x90, 
+0x9C, 0x90, 0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xB5, 0x73, 0xA4, 0xF2, 
+0xA5, 0x12, 0xAD, 0x32, 0xBD, 0xB4, 0xAD, 0x53, 
+0xBD, 0xD5, 0xAD, 0x53, 0xAD, 0x74, 0xB5, 0x74, 
+0xB5, 0x74, 0xBD, 0xD5, 0xBD, 0xD4, 0xBD, 0xF5, 
+0xBD, 0xB5, 0xAD, 0x32, 0x8C, 0x2E, 0x8C, 0x2E, 
+0xA4, 0xF1, 0x8C, 0x0E, 0xAD, 0x12, 0xA4, 0xD1, 
+0x8C, 0x0E, 0x7B, 0xCC, 0x9C, 0x8F, 0xAD, 0x11, 
+0x8C, 0x2E, 0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0x90, 
+0xBD, 0xB4, 0x9C, 0xB0, 0x8C, 0x2E, 0xA4, 0xD1, 
+0x8C, 0x2E, 0x8B, 0xED, 0x9C, 0x8F, 0xAD, 0x32, 
+0x94, 0x4E, 0xB5, 0x52, 0x9C, 0x8F, 0x9C, 0x8F, 
+0xAD, 0x12, 0x94, 0x8F, 0x83, 0xED, 0x6B, 0x0A, 
+0xAD, 0x12, 0xB5, 0x53, 0xBD, 0x93, 0xA4, 0xD0, 
+0xA4, 0xF1, 0xB5, 0x73, 0xAD, 0x32, 0x9C, 0xB0, 
+0x8C, 0x2F, 0x94, 0x90, 0xAD, 0x33, 0xA5, 0x32, 
+0xBD, 0xB4, 0x8C, 0x2F, 0x9C, 0xB0, 0xAD, 0x52, 
+0x9C, 0xD0, 0x9C, 0x90, 0x94, 0x6F, 0x8C, 0x0E, 
+0x8C, 0x2E, 0xB5, 0x52, 0xA4, 0xD1, 0xAD, 0x11, 
+0xAC, 0xF1, 0xA4, 0xD0, 0x9C, 0x6F, 0x9C, 0x90, 
+0x8C, 0x0E, 0xA4, 0xB0, 0xA4, 0xF1, 0xAD, 0x11, 
+0xA5, 0x35, 0xB5, 0xB7, 0x9D, 0x14, 0x9C, 0xF4, 
+0x8C, 0x71, 0x84, 0x50, 0x8C, 0x90, 0x94, 0xD1, 
+0x84, 0x2F, 0xA5, 0x11, 0xB5, 0x93, 0xB5, 0x73, 
+0xA5, 0x11, 0xAD, 0x72, 0xB5, 0xB4, 0xB5, 0x94, 
+0xBD, 0xB4, 0xAD, 0x52, 0xC5, 0xF4, 0xA4, 0x8E, 
+0x9C, 0x6E, 0xB5, 0x72, 0xB5, 0xB4, 0xAD, 0x73, 
+0xAD, 0x52, 0xAD, 0x53, 0xA5, 0x32, 0xB5, 0x74, 
+0xA5, 0x12, 0xBD, 0xF5, 0xC5, 0xF5, 0xC6, 0x15, 
+0xB5, 0xB4, 0xBD, 0xB4, 0xC6, 0x15, 0xBD, 0xD5, 
+0xB5, 0x94, 0xB5, 0x73, 0xB5, 0x73, 0xA5, 0x11, 
+0xB5, 0x72, 0xBD, 0xD4, 0xB5, 0x72, 0xAC, 0xEF, 
+0x8C, 0x0D, 0xB5, 0xB4, 0xB5, 0x94, 0xBD, 0xF6, 
+0xAD, 0x94, 0xC6, 0x16, 0xBD, 0xF6, 0xBD, 0xF6, 
+0xBD, 0xD5, 0xBE, 0x16, 0xC6, 0x37, 0xC6, 0x16, 
+0xC6, 0x16, 0xBD, 0xF6, 0xBD, 0xD5, 0xB5, 0xB5, 
+0xBD, 0xF6, 0xBD, 0xD5, 0xCE, 0x77, 0xCE, 0x57, 
+0xC6, 0x16, 0xB5, 0xB4, 0x9C, 0xB0, 0x94, 0x4F, 
+0x39, 0xA5, 0x31, 0x85, 0x39, 0xE7, 0x39, 0xA6, 
+0x31, 0x85, 0x41, 0xE7, 0x4A, 0x28, 0x73, 0x6D, 
+0x8C, 0x51, 0x8C, 0x51, 0xB5, 0x75, 0x9C, 0xB3, 
+0x8C, 0x51, 0x94, 0xB2, 0xC6, 0x38, 0xD6, 0x98, 
+0xC6, 0x15, 0xD6, 0x76, 0xCE, 0x55, 0xB5, 0x72, 
+0xAD, 0x31, 0xBD, 0x92, 0x9C, 0x8E, 0xAC, 0xF0, 
+0x83, 0xAB, 0x8C, 0x2D, 0x94, 0x4E, 0x9C, 0xD0, 
+0x9C, 0xD0, 0x7B, 0xCD, 0x39, 0xA5, 0x39, 0xA6, 
+0x4A, 0x48, 0x42, 0x07, 0x41, 0xE7, 0x83, 0xCF, 
+0x8C, 0x51, 0xC5, 0xF7, 0x52, 0x29, 0x6A, 0xCB, 
+0x72, 0xEB, 0x94, 0x31, 0xA4, 0xB3, 0xCD, 0xF7, 
+0xD6, 0x58, 0xAC, 0xD3, 0x6B, 0x0B, 0x83, 0x8D, 
+0xAC, 0xD1, 0x73, 0x2A, 0x83, 0x8A, 0x83, 0xAB, 
+0x7B, 0x6A, 0x94, 0x0D, 0x94, 0x2D, 0x94, 0x2D, 
+0x9C, 0x4E, 0x94, 0x2D, 0x94, 0x2E, 0x9C, 0x6E, 
+0xA4, 0xAF, 0xAC, 0xCF, 0xB5, 0x31, 0xB5, 0x10, 
+0xBD, 0x52, 0xBD, 0x52, 0xAC, 0xF0, 0x9C, 0x4F, 
+0x6B, 0x2B, 0x42, 0x07, 0x73, 0x6D, 0x94, 0x71, 
+0xB5, 0x74, 0xAC, 0xF2, 0xC5, 0xD6, 0xCE, 0x59, 
+0xAD, 0x76, 0x94, 0x71, 0xAC, 0xF1, 0xB5, 0x31, 
+0xB5, 0x31, 0xB5, 0x31, 0xB5, 0x31, 0xB5, 0x31, 
+0xB5, 0x52, 0xB5, 0x11, 0xAC, 0xD0, 0xAC, 0xF0, 
+0xAC, 0xD0, 0xAC, 0xF1, 0xA4, 0xB1, 0xA4, 0xB1, 
+0x9C, 0xB1, 0xAD, 0x12, 0xB5, 0x74, 0xA4, 0xF2, 
+0xA4, 0xD1, 0x94, 0x70, 0x8C, 0x4F, 0x94, 0x6F, 
+0x9C, 0xB0, 0x9C, 0xB1, 0x94, 0x70, 0x8C, 0x2E, 
+0x8C, 0x2E, 0x83, 0xED, 0x83, 0xED, 0x94, 0x90, 
+0x9C, 0xF1, 0xB5, 0x94, 0xAD, 0x52, 0xBD, 0xB4, 
+0xBD, 0xD5, 0xBD, 0xB4, 0xB5, 0x94, 0xBD, 0xB4, 
+0xAD, 0x52, 0x7B, 0xAC, 0x94, 0x90, 0xA4, 0xF1, 
+0xB5, 0x94, 0xAD, 0x33, 0xAD, 0x53, 0x8C, 0x2F, 
+0x84, 0x0E, 0x9C, 0xD0, 0xA5, 0x11, 0xB5, 0x94, 
+0xBD, 0xD5, 0xB5, 0xB4, 0x94, 0x6F, 0xB5, 0x73, 
+0xAD, 0x12, 0xAD, 0x32, 0xC5, 0xD5, 0xC5, 0xF5, 
+0xD6, 0x76, 0xD6, 0x76, 0xD6, 0x76, 0xD6, 0x56, 
+0xBD, 0xD4, 0xBD, 0xD5, 0xD6, 0x77, 0xAD, 0x11, 
+0xB5, 0x73, 0xCE, 0x15, 0xC5, 0xF5, 0xCE, 0x15, 
+0xC5, 0xF4, 0xB5, 0x32, 0xA4, 0xD0, 0xA4, 0xF0, 
+0x9C, 0x8F, 0xBD, 0x73, 0xA4, 0xF1, 0x9C, 0xF1, 
+0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x53, 0xA5, 0x12, 
+0xA4, 0xF1, 0xB5, 0x32, 0xBD, 0x53, 0xCD, 0xD4, 
+0xD5, 0xF4, 0xCD, 0xB3, 0x8B, 0x8C, 0xA4, 0x90, 
+0x94, 0x4F, 0x9C, 0xB0, 0xA4, 0xD1, 0xA4, 0xD1, 
+0xC6, 0x15, 0xC5, 0xF5, 0xB5, 0xB4, 0x9C, 0xB0, 
+0xA5, 0x32, 0xAD, 0x33, 0xB5, 0x94, 0xAD, 0x53, 
+0xBD, 0xB4, 0xB5, 0x73, 0xA5, 0x12, 0xAD, 0x53, 
+0xB5, 0x74, 0xAD, 0x53, 0xB5, 0x74, 0xBD, 0xD5, 
+0xBD, 0xD5, 0xBD, 0xB4, 0xA4, 0xF1, 0x94, 0x4F, 
+0xA4, 0xF1, 0x9C, 0x90, 0xA4, 0xF1, 0x9C, 0xB0, 
+0x8C, 0x2E, 0x84, 0x0D, 0x94, 0x4F, 0x94, 0x8F, 
+0x8C, 0x2E, 0x8C, 0x2E, 0xAD, 0x32, 0x9C, 0x90, 
+0xB5, 0x53, 0x9C, 0x8F, 0x94, 0x6F, 0xA5, 0x11, 
+0x94, 0x6F, 0x94, 0x2E, 0xAD, 0x12, 0xBD, 0x72, 
+0xBD, 0x93, 0xC5, 0x93, 0x94, 0x4E, 0x9C, 0xB0, 
+0xB5, 0x53, 0x9C, 0x90, 0x8C, 0x4F, 0x73, 0x4B, 
+0xA4, 0xD1, 0xAD, 0x11, 0xA4, 0xF1, 0x9C, 0x90, 
+0xA4, 0xD1, 0xB5, 0x53, 0xAD, 0x32, 0xA5, 0x32, 
+0xAD, 0x53, 0xAD, 0x53, 0xBD, 0xD5, 0xB5, 0x94, 
+0xC6, 0x16, 0x9C, 0xB0, 0xAD, 0x53, 0xC5, 0xF5, 
+0xB5, 0x93, 0xA4, 0xD1, 0xA4, 0xD1, 0xAC, 0xF2, 
+0x8C, 0x4F, 0xB5, 0x53, 0xB5, 0x52, 0xD6, 0x55, 
+0xBD, 0x93, 0xBD, 0x72, 0xBD, 0xD4, 0xC5, 0xF4, 
+0xB5, 0x52, 0x94, 0x6F, 0xB5, 0x73, 0xB5, 0x73, 
+0xA5, 0x35, 0xB5, 0xB7, 0x9D, 0x14, 0x9C, 0xF3, 
+0x8C, 0x91, 0x84, 0x70, 0x8C, 0x91, 0x94, 0xB1, 
+0x94, 0xB0, 0xA5, 0x52, 0xAD, 0x72, 0xAD, 0x52, 
+0xA5, 0x11, 0xBD, 0xB4, 0xBD, 0xD4, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xAD, 0x52, 0xCE, 0x15, 0x9C, 0x6E, 
+0x94, 0x4D, 0xAD, 0x31, 0xAD, 0x53, 0xB5, 0x94, 
+0xBD, 0xB4, 0x9C, 0xF1, 0xB5, 0xB5, 0xAD, 0x74, 
+0xA5, 0x12, 0xBD, 0xD4, 0xB5, 0x73, 0xBD, 0xF5, 
+0xBD, 0xF5, 0xBD, 0xD5, 0xC5, 0xF5, 0xB5, 0xB4, 
+0xB5, 0x73, 0xB5, 0x73, 0xA5, 0x11, 0x94, 0xAF, 
+0xA5, 0x31, 0xB5, 0x93, 0xAD, 0x11, 0xAC, 0xF0, 
+0x8C, 0x2D, 0xB5, 0xB4, 0xBD, 0xF6, 0xBD, 0xF6, 
+0xB5, 0xD5, 0xC6, 0x36, 0xC6, 0x16, 0xB5, 0xD5, 
+0xB5, 0xB4, 0xBD, 0xF6, 0xBD, 0xF6, 0xC6, 0x16, 
+0xC6, 0x37, 0xCE, 0x57, 0x9C, 0xD1, 0xAD, 0x94, 
+0xCE, 0x98, 0xCE, 0x57, 0xD6, 0x78, 0xCE, 0x57, 
+0xCE, 0x37, 0xB5, 0x94, 0xAD, 0x32, 0xB5, 0x52, 
+0x73, 0x6C, 0x31, 0xA6, 0x39, 0xC6, 0x42, 0x07, 
+0x42, 0x07, 0x42, 0x07, 0x52, 0x8A, 0x63, 0x2C, 
+0x7B, 0xCF, 0x9C, 0xD3, 0xBD, 0xF7, 0xA5, 0x14, 
+0x6B, 0x4D, 0x73, 0xAF, 0xBD, 0xD7, 0xDE, 0xBA, 
+0xB5, 0x54, 0x63, 0x0B, 0xA4, 0xF1, 0xBD, 0xD4, 
+0xAD, 0x31, 0xB5, 0x72, 0x94, 0x4D, 0xB5, 0x51, 
+0x94, 0x4E, 0xAD, 0x32, 0xAD, 0x53, 0xB5, 0x94, 
+0xB5, 0x73, 0xAD, 0x52, 0x7B, 0xAD, 0x29, 0x24, 
+0x29, 0x45, 0x39, 0xC6, 0x42, 0x07, 0x5A, 0xAA, 
+0x8C, 0x51, 0xC5, 0xF7, 0x94, 0x51, 0x83, 0xAF, 
+0x6A, 0xCB, 0x9C, 0x51, 0xAC, 0xD3, 0x8B, 0xEF, 
+0x7B, 0x8E, 0x83, 0x8E, 0x8B, 0xEF, 0x83, 0xAD, 
+0xAD, 0x13, 0xCE, 0x37, 0x94, 0x4F, 0x83, 0x8C, 
+0x83, 0xAC, 0x73, 0x4A, 0x6B, 0x0A, 0x7B, 0x6B, 
+0x7B, 0x4A, 0x6A, 0xE9, 0x62, 0xC9, 0x52, 0x27, 
+0x4A, 0x27, 0x5A, 0x67, 0x6A, 0xE9, 0x8B, 0xCC, 
+0xC5, 0x92, 0xA4, 0x6D, 0x94, 0x2D, 0xA4, 0x8E, 
+0xAC, 0xF0, 0x9C, 0x8F, 0x84, 0x0E, 0x5A, 0xCA, 
+0x4A, 0x48, 0x5A, 0xEB, 0x9C, 0xB2, 0xCE, 0x59, 
+0x9C, 0xD3, 0x7B, 0xAD, 0x8B, 0xEC, 0xB5, 0x11, 
+0x7B, 0x6B, 0x83, 0x8B, 0x83, 0xAB, 0x83, 0xAC, 
+0x83, 0x8B, 0x83, 0xAC, 0x8B, 0xCC, 0x94, 0x0D, 
+0xA4, 0xB0, 0xAD, 0x12, 0xAD, 0x12, 0xB5, 0x32, 
+0xB5, 0x74, 0xBD, 0x94, 0xB5, 0x53, 0xB5, 0x73, 
+0xB5, 0x74, 0xBD, 0x94, 0xC5, 0xB5, 0xBD, 0x94, 
+0xBD, 0x94, 0xBD, 0x94, 0xBD, 0xB5, 0xBD, 0x94, 
+0xB5, 0x74, 0xBD, 0xB4, 0xB5, 0x74, 0xB5, 0x74, 
+0xB5, 0x74, 0xA5, 0x12, 0x9C, 0x90, 0x9C, 0xB0, 
+0x9C, 0x90, 0x9C, 0x90, 0x8C, 0x2F, 0x8C, 0x0E, 
+0x8C, 0x0E, 0x8C, 0x4F, 0x9C, 0xB1, 0x8C, 0x4F, 
+0x8C, 0x2E, 0x84, 0x0E, 0x7B, 0xCD, 0x83, 0xED, 
+0x84, 0x0E, 0x94, 0x6F, 0x94, 0x4F, 0x9C, 0xB0, 
+0xA5, 0x12, 0x9C, 0x90, 0x7B, 0x8C, 0xA5, 0x12, 
+0x9C, 0xD0, 0x9C, 0xB0, 0xAD, 0x32, 0xA5, 0x11, 
+0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x73, 0xBD, 0x93, 
+0xC5, 0xD4, 0xCE, 0x35, 0xBD, 0x93, 0x94, 0x6F, 
+0xB5, 0x73, 0xCE, 0x15, 0xBD, 0xB4, 0xC5, 0xB4, 
+0xBD, 0xB4, 0xAD, 0x11, 0x94, 0x6F, 0x9C, 0x8F, 
+0x8C, 0x2E, 0xAD, 0x11, 0xA4, 0xF1, 0xA5, 0x12, 
+0xB5, 0x94, 0xAD, 0x74, 0xBD, 0xD5, 0xB5, 0x94, 
+0xBD, 0x94, 0xC5, 0x93, 0xBD, 0x52, 0xBD, 0x52, 
+0xDE, 0x15, 0xCD, 0x93, 0x83, 0x6B, 0xAC, 0xD1, 
+0x8C, 0x0E, 0xA4, 0xD0, 0xBD, 0x94, 0xBD, 0xB4, 
+0xCE, 0x36, 0xCE, 0x15, 0xBD, 0xD4, 0xAD, 0x32, 
+0x9C, 0xD1, 0xA4, 0xF1, 0xB5, 0x74, 0xB5, 0x94, 
+0xBD, 0xB5, 0xAD, 0x53, 0xA5, 0x12, 0xAD, 0x33, 
+0xBD, 0xB4, 0xB5, 0xB4, 0xB5, 0x94, 0xBD, 0xF5, 
+0xB5, 0x73, 0xA4, 0xF1, 0xA5, 0x11, 0x94, 0x4F, 
+0xB5, 0x53, 0xA4, 0xD1, 0xB5, 0x53, 0xAD, 0x32, 
+0x9C, 0x90, 0x9C, 0xB0, 0xA4, 0xF1, 0xAD, 0x12, 
+0xAD, 0x12, 0x9C, 0xB0, 0xC5, 0xD5, 0xB5, 0x73, 
+0xC6, 0x15, 0xB5, 0x93, 0xA4, 0xF1, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xAD, 0x11, 0x9C, 0x6F, 0xBD, 0x72, 
+0xC5, 0xB3, 0xC5, 0xB3, 0x9C, 0x8F, 0xAD, 0x12, 
+0xAD, 0x11, 0x9C, 0xB0, 0x94, 0x4F, 0x73, 0x8C, 
+0x94, 0x6F, 0xC5, 0xD4, 0xBD, 0x73, 0xAD, 0x12, 
+0xAD, 0x33, 0xA4, 0xD1, 0x94, 0x6F, 0xAD, 0x32, 
+0xA5, 0x32, 0xAD, 0x94, 0xCE, 0x57, 0xBD, 0xD5, 
+0xBD, 0xB4, 0xAD, 0x33, 0xC6, 0x16, 0xC6, 0x35, 
+0xC6, 0x15, 0xAD, 0x32, 0x9C, 0x90, 0xB5, 0x73, 
+0xA5, 0x12, 0xBD, 0x93, 0xC5, 0xB3, 0xD6, 0x55, 
+0xCE, 0x14, 0xA4, 0xAF, 0xC5, 0xD4, 0xCE, 0x55, 
+0xC5, 0xF4, 0xAD, 0x31, 0xBD, 0xD4, 0xC6, 0x35, 
+0xA5, 0x35, 0xB5, 0x97, 0xA5, 0x34, 0x9C, 0xF4, 
+0x8C, 0x92, 0x8C, 0x90, 0x94, 0xB1, 0x9C, 0xF2, 
+0x9D, 0x12, 0xB5, 0x94, 0xB5, 0x93, 0xB5, 0x93, 
+0xB5, 0xB4, 0xC6, 0x36, 0xBD, 0xB4, 0xC6, 0x15, 
+0xC6, 0x15, 0xBD, 0xD4, 0xCE, 0x36, 0x9C, 0x4D, 
+0xB5, 0x31, 0xC5, 0xF4, 0xBD, 0xD4, 0xB5, 0xB4, 
+0xBD, 0xF5, 0xAD, 0x73, 0xC6, 0x37, 0xB5, 0xB5, 
+0x9D, 0x12, 0xC6, 0x36, 0xBD, 0xD5, 0xC6, 0x15, 
+0xC6, 0x16, 0xC6, 0x16, 0xC6, 0x36, 0xC6, 0x16, 
+0xC5, 0xF5, 0xC5, 0xF5, 0xAD, 0x32, 0xB5, 0x93, 
+0xBD, 0xF5, 0xCE, 0x35, 0x9C, 0x8F, 0xAC, 0xF0, 
+0x8C, 0x2D, 0xAD, 0x74, 0xB5, 0xB5, 0xBD, 0xF6, 
+0xC6, 0x16, 0xCE, 0x57, 0xBD, 0xF6, 0xBD, 0xF6, 
+0xB5, 0xD5, 0xB5, 0x94, 0xB5, 0xB5, 0xBD, 0xD5, 
+0xC6, 0x36, 0xBD, 0xF6, 0x9C, 0xF2, 0xBE, 0x16, 
+0xAD, 0x74, 0xCE, 0x57, 0xCE, 0x57, 0xCE, 0x57, 
+0xC6, 0x16, 0xBD, 0xB5, 0xAD, 0x32, 0xB5, 0x52, 
+0xAD, 0x32, 0x63, 0x2B, 0x42, 0x07, 0x42, 0x07, 
+0x4A, 0x48, 0x52, 0xAA, 0x63, 0x2C, 0x63, 0x0C, 
+0x6B, 0x2C, 0x84, 0x30, 0x9C, 0xD3, 0xA5, 0x14, 
+0x94, 0xB3, 0xAD, 0x56, 0xAD, 0x76, 0xCE, 0x59, 
+0xBD, 0xB7, 0x21, 0x05, 0x63, 0x2C, 0xC6, 0x36, 
+0xC5, 0xF4, 0xD6, 0x56, 0xA4, 0xAF, 0xB5, 0x51, 
+0xA4, 0xD0, 0xBD, 0xF5, 0xBD, 0xD5, 0xC5, 0xF5, 
+0xB5, 0x94, 0xAD, 0x52, 0xAD, 0x32, 0x73, 0x8C, 
+0x18, 0xC3, 0x39, 0xC6, 0x31, 0xA6, 0x6B, 0x4D, 
+0x9C, 0xD3, 0x7B, 0xAE, 0x94, 0x92, 0xD6, 0x59, 
+0xB5, 0x34, 0x72, 0xEC, 0x94, 0x30, 0x49, 0xE7, 
+0x52, 0x28, 0x83, 0x8D, 0xA4, 0xD2, 0xCD, 0xF6, 
+0x83, 0xCE, 0xAD, 0x13, 0xCE, 0x16, 0x9C, 0x90, 
+0x8C, 0x0E, 0x94, 0x2E, 0x8C, 0x2E, 0x8C, 0x2E, 
+0x94, 0x2E, 0x8C, 0x0E, 0x8C, 0x0E, 0x83, 0xEE, 
+0x83, 0xCD, 0x83, 0xAD, 0x6B, 0x0A, 0x6B, 0x0A, 
+0xBD, 0x72, 0x8B, 0xEB, 0x7B, 0xAB, 0x94, 0x4E, 
+0x9C, 0x4E, 0x8B, 0xEC, 0x94, 0x8F, 0x94, 0x6F, 
+0x6B, 0x4B, 0x39, 0xE7, 0x73, 0x8E, 0xA5, 0x35, 
+0x94, 0x92, 0x8C, 0x2E, 0x83, 0x8B, 0xB5, 0x31, 
+0x9C, 0x4E, 0x94, 0x4E, 0x94, 0x4E, 0x8B, 0xED, 
+0x7B, 0x8B, 0x8C, 0x0D, 0x94, 0x4E, 0x94, 0x4E, 
+0xA4, 0xD1, 0xB5, 0x53, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xAD, 0x11, 0xBD, 0x93, 0xA4, 0xD1, 0xBD, 0xB4, 
+0xBD, 0xB4, 0x94, 0x70, 0x94, 0x4F, 0x9C, 0x90, 
+0xAD, 0x12, 0x9C, 0x90, 0x7B, 0x8D, 0x73, 0x6C, 
+0x83, 0xCD, 0x83, 0xEE, 0x9C, 0x90, 0xAD, 0x12, 
+0x94, 0x4F, 0xA4, 0xF1, 0x9C, 0xB0, 0x94, 0x6F, 
+0x9C, 0xD1, 0xAD, 0x12, 0xB5, 0x73, 0xBD, 0x94, 
+0xBD, 0x94, 0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x53, 
+0xAD, 0x12, 0xB5, 0x53, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xAD, 0x32, 0xA4, 0xF1, 0xAD, 0x32, 0xB5, 0x53, 
+0xAD, 0x12, 0xAD, 0x12, 0xB5, 0x53, 0xBD, 0x94, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xB5, 0x53, 0xAD, 0x12, 
+0xAD, 0x12, 0xB5, 0x53, 0xAD, 0x32, 0xB5, 0x33, 
+0xAD, 0x32, 0xB5, 0x52, 0xAD, 0x32, 0xBD, 0xB4, 
+0xB5, 0x52, 0xAD, 0x12, 0xB5, 0x53, 0xBD, 0x73, 
+0xB5, 0x32, 0xAD, 0x12, 0xAD, 0x32, 0xA4, 0xD1, 
+0x9C, 0x8F, 0xA4, 0xD0, 0x9C, 0x8F, 0xA4, 0xD1, 
+0x8C, 0x2F, 0x94, 0x91, 0x94, 0x70, 0x9C, 0xD1, 
+0x9C, 0x90, 0xAC, 0xD1, 0xAC, 0xF1, 0xAC, 0xD0, 
+0xAC, 0xF0, 0x9C, 0x2E, 0x7B, 0x2A, 0xAC, 0xF1, 
+0x83, 0xAC, 0x9C, 0xB0, 0xAD, 0x32, 0xC6, 0x15, 
+0xBD, 0xD4, 0xC5, 0xF4, 0xBD, 0xD4, 0xBD, 0xD5, 
+0xBD, 0xD4, 0xB5, 0x94, 0xB5, 0x94, 0xB5, 0x94, 
+0xB5, 0xB4, 0xBD, 0xB5, 0xBD, 0xD5, 0xC5, 0xF5, 
+0xC6, 0x15, 0xC6, 0x15, 0xC6, 0x15, 0xC5, 0xF5, 
+0xAD, 0x32, 0xB5, 0x53, 0x9C, 0xD0, 0x8C, 0x2E, 
+0xAD, 0x52, 0x8C, 0x0E, 0xCE, 0x36, 0x9C, 0xB0, 
+0x94, 0x6F, 0x83, 0xED, 0xA4, 0xF1, 0xA4, 0xF1, 
+0x94, 0x6F, 0x9C, 0x90, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xC5, 0xF4, 0xA5, 0x11, 0x8C, 0x2E, 0xA4, 0xF1, 
+0xAC, 0xF1, 0xB5, 0x52, 0xAC, 0xF0, 0xB5, 0x11, 
+0xBD, 0x72, 0xAC, 0xF0, 0xA4, 0xD0, 0xB5, 0x73, 
+0xB5, 0x53, 0x9C, 0xB0, 0x9C, 0xB1, 0x8C, 0x0E, 
+0x9C, 0xB0, 0xCE, 0x36, 0xC5, 0xF5, 0xB5, 0x73, 
+0xB5, 0x53, 0xB5, 0x73, 0xBD, 0xD5, 0xB5, 0x94, 
+0xA4, 0xF2, 0xA5, 0x33, 0xC6, 0x16, 0xC6, 0x16, 
+0xCE, 0x36, 0xA5, 0x32, 0xBD, 0xD5, 0xC6, 0x15, 
+0xCE, 0x15, 0xC5, 0xD5, 0xA4, 0xD1, 0xB5, 0xB4, 
+0xAD, 0x33, 0xB5, 0x73, 0xCD, 0xF4, 0xCE, 0x14, 
+0xBD, 0xB2, 0x9C, 0xAF, 0xCE, 0x14, 0xCE, 0x35, 
+0xB5, 0x52, 0xBD, 0xB3, 0xBD, 0xD4, 0xCE, 0x56, 
+0xA5, 0x35, 0xB5, 0xB7, 0x9D, 0x14, 0x9C, 0xF4, 
+0x7B, 0xEF, 0x5A, 0xC9, 0x63, 0x09, 0x6B, 0x2A, 
+0x6B, 0x4A, 0x73, 0x8B, 0x73, 0x8B, 0x83, 0xCC, 
+0x83, 0xEC, 0x83, 0xED, 0x7B, 0x6B, 0x83, 0xED, 
+0x83, 0xED, 0x7B, 0x8C, 0x7B, 0x8C, 0x83, 0xAB, 
+0x7B, 0x8A, 0x7B, 0x8B, 0x8C, 0x0D, 0x7B, 0xAC, 
+0x7B, 0xAC, 0x94, 0x6F, 0xA4, 0xF1, 0x94, 0xB0, 
+0x94, 0xB0, 0xB5, 0x73, 0xAD, 0x73, 0xB5, 0xB4, 
+0xBD, 0xD4, 0xC5, 0xF5, 0xCE, 0x36, 0xD6, 0x77, 
+0xCE, 0x57, 0xCE, 0x57, 0xAD, 0x32, 0x9C, 0xB0, 
+0xBD, 0xB4, 0xC5, 0xD4, 0x83, 0xAC, 0xAC, 0xD0, 
+0x94, 0x8F, 0xBD, 0xF5, 0xC6, 0x16, 0xC6, 0x37, 
+0xC6, 0x16, 0xCE, 0x57, 0xCE, 0x57, 0xC6, 0x16, 
+0xC6, 0x16, 0xBD, 0xD5, 0xB5, 0xB4, 0xBD, 0xF6, 
+0xCE, 0x57, 0xCE, 0x98, 0xA5, 0x12, 0xCE, 0x57, 
+0xBD, 0xF6, 0xC6, 0x37, 0xD6, 0x78, 0xD6, 0x98, 
+0xCE, 0x77, 0xC5, 0xF5, 0xAD, 0x11, 0xBD, 0x92, 
+0x9C, 0xAF, 0x94, 0x70, 0x52, 0x89, 0x4A, 0x69, 
+0x52, 0x89, 0x84, 0x10, 0x7B, 0xAE, 0x52, 0x8A, 
+0x5A, 0xEB, 0x73, 0x8E, 0x94, 0x92, 0xB5, 0xB6, 
+0x9C, 0xD3, 0xB5, 0xB7, 0xB5, 0xB7, 0xB5, 0xB7, 
+0xC6, 0x18, 0x84, 0x10, 0x6B, 0x4D, 0xC6, 0x37, 
+0x9C, 0xD1, 0xC5, 0xF5, 0xA4, 0xF0, 0xB5, 0x31, 
+0xAD, 0x52, 0xC6, 0x16, 0xBD, 0xB5, 0xC5, 0xF5, 
+0xB5, 0x73, 0x8C, 0x4E, 0x8C, 0x2E, 0x94, 0x90, 
+0x31, 0x65, 0x21, 0x04, 0x31, 0x86, 0x42, 0x08, 
+0x4A, 0x28, 0x31, 0x86, 0x39, 0xA7, 0x84, 0x10, 
+0xDE, 0x9A, 0x8C, 0x10, 0x4A, 0x08, 0x41, 0xE7, 
+0x94, 0x2F, 0xAC, 0xF2, 0x94, 0x0F, 0xC5, 0xD6, 
+0xBD, 0x94, 0xBD, 0x74, 0x9C, 0x91, 0xCE, 0x16, 
+0xBD, 0x94, 0x9C, 0x90, 0xA4, 0xB0, 0xA4, 0xF1, 
+0xAD, 0x32, 0x9C, 0x90, 0x8B, 0xED, 0x8C, 0x0E, 
+0x94, 0x2E, 0x8C, 0x2F, 0x83, 0xCD, 0x8C, 0x0E, 
+0xBD, 0x31, 0xAC, 0xF0, 0xAD, 0x11, 0xBD, 0xB3, 
+0xB5, 0x72, 0xAD, 0x52, 0xAD, 0x52, 0xB5, 0x73, 
+0xAD, 0x32, 0x6B, 0x4C, 0x63, 0x0C, 0x8C, 0x51, 
+0x94, 0x71, 0x9C, 0x90, 0x83, 0xAB, 0xBD, 0x51, 
+0xAC, 0xCF, 0x8C, 0x0D, 0x7B, 0xAB, 0x7B, 0xAB, 
+0x6B, 0x09, 0x83, 0xEC, 0x7B, 0x8B, 0x8C, 0x0E, 
+0xA4, 0xF1, 0xA4, 0xF1, 0x7B, 0x8C, 0x9C, 0x90, 
+0xA4, 0xD0, 0x9C, 0xAF, 0xAD, 0x32, 0xC5, 0xF5, 
+0xCE, 0x36, 0xA5, 0x12, 0x83, 0xCD, 0x9C, 0xB0, 
+0x9C, 0xB0, 0x8C, 0x4F, 0x7B, 0xAD, 0x83, 0xEE, 
+0x83, 0xCD, 0x83, 0xEE, 0xB5, 0x73, 0xCE, 0x36, 
+0xAD, 0x32, 0xB5, 0x73, 0xBD, 0x94, 0xB5, 0x53, 
+0x94, 0x4F, 0x94, 0x6F, 0x94, 0x6F, 0xA4, 0xD1, 
+0xA4, 0xF1, 0xA4, 0xD0, 0xAD, 0x32, 0xB5, 0x53, 
+0xAD, 0x32, 0xB5, 0x32, 0xAD, 0x32, 0xB5, 0x52, 
+0xAD, 0x32, 0xB5, 0x94, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xB5, 0x74, 0xB5, 0x93, 0xB5, 0x53, 0xB5, 0x73, 
+0x9C, 0xB0, 0x94, 0x6F, 0x9C, 0xB1, 0xAD, 0x32, 
+0xAD, 0x12, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x32, 
+0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x53, 0xBD, 0x94, 
+0xC5, 0xB4, 0xBD, 0xB4, 0xBD, 0x94, 0xC5, 0xB4, 
+0xC5, 0xD5, 0xC5, 0xD5, 0xC5, 0xD5, 0xC5, 0xF5, 
+0xC5, 0xD5, 0xCE, 0x15, 0xC5, 0xD4, 0xBD, 0x94, 
+0xBD, 0x94, 0xBD, 0x94, 0xBD, 0x74, 0xBD, 0x74, 
+0xBD, 0x74, 0xC5, 0x94, 0xBD, 0x73, 0xBD, 0x72, 
+0xBD, 0x73, 0xB5, 0x32, 0xB5, 0x12, 0xBD, 0x94, 
+0x9C, 0x6F, 0x8C, 0x0E, 0x94, 0x6F, 0xA4, 0xD0, 
+0x94, 0x2E, 0x9C, 0x90, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xAD, 0x12, 0xAD, 0x32, 0xAD, 0x53, 0xA5, 0x12, 
+0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x73, 0xBD, 0x94, 
+0xB5, 0x73, 0xB5, 0x73, 0xC5, 0xD5, 0xBD, 0xB4, 
+0xBD, 0x93, 0xB5, 0x73, 0x94, 0x6F, 0x84, 0x0E, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xAD, 0x32, 0x94, 0x4F, 
+0x9C, 0xB1, 0x9C, 0x90, 0x83, 0xED, 0x9C, 0xB1, 
+0x8C, 0x2E, 0x8C, 0x2E, 0xB5, 0x53, 0xAC, 0xF1, 
+0xBD, 0x93, 0x83, 0xED, 0x5A, 0xA9, 0x94, 0x4F, 
+0x94, 0x4E, 0x9C, 0x6F, 0xA4, 0x8F, 0xA4, 0xAF, 
+0x9C, 0x6E, 0x9C, 0x4E, 0xA4, 0xD0, 0xB5, 0x32, 
+0xB5, 0x53, 0x9C, 0x90, 0xB5, 0x53, 0x9C, 0xB0, 
+0x94, 0x6F, 0xCE, 0x36, 0xD6, 0x56, 0xBD, 0xB4, 
+0xB5, 0x53, 0xAD, 0x33, 0xBD, 0xB4, 0xB5, 0x94, 
+0xAD, 0x33, 0xAD, 0x73, 0xCE, 0x57, 0xD6, 0x77, 
+0xCE, 0x56, 0xAD, 0x53, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xAD, 0x12, 0xBD, 0xD5, 
+0xAD, 0x32, 0xB5, 0x73, 0xC5, 0xB3, 0xD6, 0x14, 
+0xBD, 0x72, 0x9C, 0xAF, 0xCE, 0x55, 0xD6, 0x75, 
+0xAD, 0x31, 0xA4, 0xF0, 0xBD, 0xB3, 0xC5, 0xF4, 
+0xA5, 0x35, 0xB5, 0xB7, 0x9D, 0x14, 0x94, 0xF3, 
+0x7C, 0x10, 0x62, 0xCA, 0x62, 0xE9, 0x6B, 0x0A, 
+0x73, 0x6B, 0x83, 0xAC, 0x8B, 0xEC, 0x8B, 0xCC, 
+0x94, 0x2E, 0x9C, 0x6E, 0xA4, 0x8F, 0x9C, 0x6E, 
+0xA4, 0x8F, 0xA4, 0xAF, 0xAC, 0xF0, 0xB5, 0x10, 
+0xAD, 0x10, 0xAC, 0xD0, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xAC, 0xD0, 0xA4, 0x8F, 0x9C, 0x6D, 
+0x9C, 0x6E, 0x9C, 0x8E, 0x9C, 0x4E, 0x94, 0x0D, 
+0x94, 0x0C, 0x93, 0xEC, 0x8C, 0x0C, 0x94, 0x0D, 
+0x8B, 0xEC, 0x83, 0xCC, 0x83, 0xAB, 0x83, 0xAB, 
+0x7B, 0x8B, 0x7B, 0x6A, 0x94, 0x2D, 0xAC, 0xCF, 
+0x94, 0x4D, 0xAD, 0x32, 0xAD, 0x53, 0xAD, 0x32, 
+0xA4, 0xF1, 0xB5, 0x73, 0xB5, 0x93, 0xAD, 0x53, 
+0xA5, 0x11, 0xA4, 0xF1, 0x94, 0x4F, 0x94, 0x6F, 
+0xAD, 0x53, 0xCE, 0x77, 0xBD, 0xB4, 0xD6, 0x98, 
+0xD6, 0xB8, 0xD6, 0x98, 0xD6, 0x77, 0xCE, 0x77, 
+0xC6, 0x36, 0xCE, 0x16, 0x9C, 0x8F, 0xB5, 0x31, 
+0xBD, 0x93, 0xC5, 0xD5, 0x94, 0x70, 0x4A, 0x69, 
+0x39, 0xE7, 0x52, 0x89, 0x52, 0x69, 0x42, 0x07, 
+0x5A, 0xAA, 0x6B, 0x4C, 0x84, 0x10, 0x8C, 0x30, 
+0x9C, 0xF4, 0xAD, 0x56, 0xB5, 0x96, 0xA5, 0x35, 
+0xC6, 0x18, 0xD6, 0x7A, 0x9C, 0xD3, 0xC6, 0x17, 
+0x94, 0x70, 0x73, 0x8D, 0xA4, 0xD0, 0xB5, 0x52, 
+0xB5, 0x93, 0xBD, 0xD5, 0xBD, 0xD5, 0xC5, 0xF5, 
+0xBD, 0xB4, 0xA5, 0x12, 0xB5, 0x73, 0xB5, 0x73, 
+0x94, 0x90, 0x39, 0x85, 0x42, 0x07, 0x39, 0xC6, 
+0x4A, 0x28, 0x4A, 0x49, 0x42, 0x08, 0x4A, 0x29, 
+0xA4, 0xF4, 0xAD, 0x55, 0x83, 0xAE, 0x7B, 0x8D, 
+0xBD, 0x53, 0xCD, 0xB5, 0xD6, 0x37, 0xDE, 0x78, 
+0xDE, 0x58, 0xC5, 0x74, 0xB5, 0x33, 0x8C, 0x0F, 
+0xBD, 0x94, 0xAC, 0xF1, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xB5, 0x52, 0xA4, 0xD1, 0x8C, 0x0E, 0x8B, 0xCE, 
+0x94, 0x4F, 0x8C, 0x0E, 0x83, 0xCD, 0xA4, 0xAF, 
+0xB5, 0x30, 0xB5, 0x11, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xBD, 0xB3, 0xC5, 0xD4, 0xBD, 0xB4, 0xBD, 0x93, 
+0xBD, 0xB4, 0xA4, 0xF2, 0x8C, 0x72, 0x8C, 0x51, 
+0x94, 0x71, 0x94, 0x2E, 0x73, 0x29, 0xBD, 0x51, 
+0x94, 0x0D, 0x83, 0xCC, 0x83, 0xCC, 0x8C, 0x0E, 
+0x7B, 0xAC, 0x8C, 0x4E, 0x84, 0x0D, 0x94, 0x6F, 
+0xA5, 0x11, 0x9C, 0xB0, 0x7B, 0xCD, 0x9C, 0x90, 
+0xAD, 0x11, 0x8C, 0x2E, 0xA4, 0xD1, 0xBD, 0xD5, 
+0xC5, 0xF5, 0x9C, 0xB1, 0x63, 0x0A, 0x9C, 0xD1, 
+0x8C, 0x2E, 0x6B, 0x4B, 0x83, 0xED, 0x83, 0xED, 
+0x83, 0xCD, 0x83, 0xED, 0x9C, 0x90, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xAD, 0x11, 0xB5, 0x52, 0xB5, 0x52, 
+0x94, 0x70, 0x9C, 0x90, 0x8C, 0x0E, 0x83, 0xED, 
+0x9C, 0x8F, 0x94, 0x6E, 0xA4, 0xD0, 0xAD, 0x11, 
+0xA4, 0xD0, 0xAD, 0x11, 0xAD, 0x31, 0xAD, 0x11, 
+0x9C, 0xAF, 0xA4, 0xF1, 0xBD, 0x93, 0xBD, 0x93, 
+0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x31, 0xB5, 0x52, 
+0xB5, 0x52, 0xA5, 0x11, 0xAD, 0x32, 0x9C, 0x6F, 
+0x94, 0x6F, 0xB5, 0x53, 0xD6, 0x56, 0xCE, 0x15, 
+0xC5, 0xD4, 0xAD, 0x32, 0x94, 0x4F, 0x73, 0x6B, 
+0x73, 0x4B, 0x6B, 0x2B, 0x7B, 0x8C, 0x84, 0x0D, 
+0x9C, 0x90, 0x94, 0x6F, 0x84, 0x0D, 0x83, 0xCD, 
+0x8C, 0x0E, 0x8C, 0x0D, 0x8C, 0x0E, 0x94, 0x2E, 
+0x94, 0x4F, 0x8C, 0x0E, 0x94, 0x2F, 0x8C, 0x0E, 
+0xA4, 0xB0, 0xBD, 0x73, 0xAC, 0xF1, 0xAD, 0x11, 
+0xBD, 0x53, 0xBD, 0x73, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xCD, 0xD5, 0xCD, 0xF5, 0xCD, 0xF5, 0xCD, 0xF6, 
+0xCE, 0x16, 0xCD, 0xF5, 0xC5, 0xD5, 0xCD, 0xF5, 
+0xC5, 0xD5, 0xC5, 0xB4, 0xC5, 0xD5, 0xB5, 0x53, 
+0xAC, 0xF1, 0xBD, 0x73, 0xB5, 0x53, 0xAD, 0x12, 
+0xB5, 0x53, 0xB5, 0x73, 0xBD, 0x73, 0xC5, 0xB4, 
+0xAC, 0xF1, 0xA4, 0xD1, 0x9C, 0x90, 0xAD, 0x12, 
+0xB5, 0x33, 0xAC, 0xF2, 0xAD, 0x12, 0xA4, 0xD1, 
+0x9C, 0xB0, 0xAD, 0x12, 0x9C, 0x90, 0xA4, 0xD1, 
+0x9C, 0x90, 0x94, 0x4F, 0xAD, 0x32, 0xB5, 0x52, 
+0xBD, 0x93, 0x73, 0x6C, 0x6B, 0x2B, 0x9C, 0xB0, 
+0xAD, 0x32, 0x94, 0x4E, 0x83, 0xAC, 0x94, 0x0E, 
+0x8C, 0x0D, 0x83, 0xAC, 0x9C, 0x6F, 0x94, 0x4E, 
+0xAD, 0x12, 0x9C, 0xD0, 0xAD, 0x32, 0x73, 0x8C, 
+0x6B, 0x0A, 0xA5, 0x11, 0xCE, 0x15, 0xCE, 0x15, 
+0xB5, 0x94, 0xB5, 0x94, 0xBD, 0xB4, 0xBD, 0xD5, 
+0xB5, 0xB5, 0xB5, 0xB5, 0xCE, 0x57, 0xCE, 0x56, 
+0xCE, 0x36, 0xC5, 0xD4, 0xAD, 0x32, 0xBD, 0xD4, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xAD, 0x32, 0xC5, 0xD5, 
+0xA5, 0x12, 0xB5, 0x53, 0xBD, 0x52, 0xCE, 0x14, 
+0xD6, 0x35, 0x9C, 0x8F, 0xC6, 0x14, 0xC5, 0xF4, 
+0xA4, 0xD0, 0x94, 0x8F, 0xC5, 0xF5, 0xC6, 0x15, 
+0xA5, 0x35, 0xB5, 0xB7, 0x9D, 0x14, 0x94, 0xD3, 
+0x73, 0xAE, 0x63, 0x0B, 0x63, 0x2B, 0x63, 0x0A, 
+0x52, 0x68, 0x5A, 0x88, 0x5A, 0xA8, 0x52, 0x68, 
+0x5A, 0xC9, 0x63, 0x0A, 0x5A, 0xA9, 0x52, 0x47, 
+0x73, 0x4B, 0x8B, 0xED, 0x94, 0x6E, 0x8B, 0xED, 
+0x83, 0xAB, 0x83, 0xAB, 0x8B, 0xCC, 0x94, 0x0D, 
+0x9C, 0x2D, 0x9C, 0x4D, 0xAC, 0xEF, 0xAC, 0xCF, 
+0xA4, 0x8E, 0x9C, 0x4D, 0x8B, 0xCB, 0x8B, 0xAB, 
+0x94, 0x0D, 0xA4, 0x6E, 0x9C, 0x6D, 0xA4, 0x8E, 
+0xAC, 0xAF, 0xAC, 0xCF, 0xBD, 0x10, 0xBD, 0x30, 
+0xBD, 0x30, 0xBD, 0x51, 0xC5, 0x51, 0xBD, 0x50, 
+0xB5, 0x30, 0xB5, 0x10, 0xB4, 0xF0, 0xAC, 0xCF, 
+0xA4, 0x8E, 0x9C, 0x6E, 0x9C, 0x6E, 0xA4, 0xAE, 
+0xA4, 0xAE, 0x9C, 0x6E, 0xA4, 0x8E, 0xA4, 0xAF, 
+0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x8F, 
+0x9C, 0x6E, 0xA4, 0xAF, 0xA4, 0xD0, 0xA4, 0xAF, 
+0x9C, 0x8F, 0x94, 0x4D, 0x9C, 0x4D, 0xBD, 0x31, 
+0xA4, 0xAF, 0x9C, 0x8F, 0x7B, 0x8C, 0x52, 0x68, 
+0x29, 0x45, 0x29, 0x45, 0x39, 0xA6, 0x42, 0x08, 
+0x52, 0x69, 0x5A, 0xCB, 0x4A, 0x49, 0x5A, 0xCB, 
+0x8C, 0x71, 0xAD, 0x35, 0xA5, 0x35, 0x9C, 0xF4, 
+0xBD, 0xB7, 0xD6, 0x9A, 0xB5, 0xB6, 0xBD, 0xF7, 
+0xAD, 0x54, 0x5A, 0x8A, 0x94, 0x6F, 0xB5, 0x73, 
+0xC6, 0x16, 0xC6, 0x16, 0xC6, 0x16, 0xC5, 0xF5, 
+0xBD, 0xD4, 0xCE, 0x76, 0xD6, 0x97, 0xD6, 0x76, 
+0xC5, 0xD4, 0xA4, 0xD1, 0x39, 0xC6, 0x21, 0x03, 
+0x39, 0xA6, 0x52, 0xAA, 0x31, 0x86, 0x21, 0x24, 
+0x4A, 0x49, 0x4A, 0x49, 0x73, 0x6D, 0x9C, 0x50, 
+0x83, 0xAD, 0xAC, 0xD2, 0xBD, 0x54, 0xD6, 0x17, 
+0xDE, 0x58, 0xD6, 0x37, 0xBD, 0x74, 0x7B, 0x8D, 
+0x94, 0x50, 0xC5, 0xB5, 0xC5, 0xD5, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xAD, 0x11, 0x9C, 0x6F, 0x9C, 0x6F, 
+0x9C, 0x6F, 0x9C, 0x6F, 0x8B, 0xED, 0xA4, 0x8F, 
+0xBD, 0x51, 0xB5, 0x51, 0xC5, 0xD3, 0xC5, 0xF4, 
+0xCE, 0x14, 0xCE, 0x55, 0xC6, 0x15, 0xBD, 0xF4, 
+0xBD, 0xD4, 0xB5, 0x95, 0xA5, 0x35, 0x9C, 0xD3, 
+0x8C, 0x50, 0x6B, 0x2B, 0x73, 0x0A, 0xBD, 0x51, 
+0x8B, 0xCC, 0x7B, 0x8B, 0x7B, 0xAC, 0x8C, 0x0D, 
+0x8C, 0x0D, 0x94, 0x4F, 0x94, 0x6F, 0x9C, 0x8F, 
+0xA5, 0x12, 0x9C, 0xB0, 0x83, 0xEE, 0x94, 0x8F, 
+0xAD, 0x32, 0x8C, 0x2E, 0xA4, 0xF1, 0xB5, 0x94, 
+0xBD, 0xD4, 0xA4, 0xF2, 0x63, 0x0A, 0xAD, 0x53, 
+0x94, 0x90, 0x83, 0xEE, 0x94, 0x70, 0x94, 0x70, 
+0x83, 0xED, 0x84, 0x0E, 0x94, 0x6F, 0xA4, 0xD0, 
+0xAD, 0x11, 0xAD, 0x32, 0xB5, 0x72, 0xB5, 0x52, 
+0x94, 0x70, 0x9C, 0x90, 0x7B, 0xAC, 0x73, 0x6C, 
+0x9C, 0x8F, 0x94, 0x2D, 0xA4, 0xB0, 0xB5, 0x52, 
+0x9C, 0x6E, 0x94, 0x6E, 0x9C, 0x6E, 0x9C, 0x6E, 
+0x8C, 0x2E, 0xA4, 0xD0, 0xA4, 0xD0, 0xB5, 0x52, 
+0xAD, 0x11, 0x9C, 0x6F, 0xA4, 0xD0, 0x94, 0x2D, 
+0x8C, 0x0D, 0x8C, 0x2D, 0x83, 0xEC, 0x8C, 0x0D, 
+0x94, 0x4F, 0xAD, 0x32, 0xAD, 0x32, 0x83, 0xED, 
+0xA4, 0xD1, 0xBD, 0x94, 0xAD, 0x32, 0x8C, 0x4F, 
+0x63, 0x2B, 0x6B, 0x4C, 0x8C, 0x2E, 0x9C, 0xD1, 
+0xAD, 0x32, 0x9C, 0xB0, 0xAD, 0x53, 0xA5, 0x12, 
+0x9C, 0xB0, 0x7B, 0xCD, 0x7B, 0xAC, 0x94, 0x4F, 
+0x9C, 0xB0, 0x94, 0x4F, 0x6B, 0x0A, 0x7B, 0x8C, 
+0x94, 0x2E, 0xBD, 0x73, 0xB5, 0x32, 0xBD, 0x73, 
+0x8C, 0x0E, 0x7B, 0x6B, 0x83, 0xCD, 0xA4, 0xD1, 
+0x8C, 0x0E, 0x8B, 0xED, 0x8C, 0x2E, 0x94, 0x4E, 
+0x94, 0x4E, 0x94, 0x2E, 0x94, 0x4F, 0x9C, 0x90, 
+0x9C, 0x90, 0x9C, 0xB0, 0xA4, 0xD1, 0xA4, 0xB0, 
+0x9C, 0x6F, 0xA4, 0xD0, 0xA4, 0xD1, 0x9C, 0x90, 
+0xA4, 0xB0, 0xBD, 0x53, 0xB5, 0x32, 0xB5, 0x52, 
+0xBD, 0x93, 0xBD, 0x93, 0xB5, 0x32, 0xB5, 0x32, 
+0xBD, 0x94, 0xC5, 0xB4, 0xC5, 0xB4, 0xC5, 0xD4, 
+0xC5, 0xB4, 0xCD, 0xF5, 0xC5, 0xF5, 0xC5, 0xD5, 
+0xCE, 0x15, 0xC5, 0xD4, 0xB5, 0x53, 0xB5, 0x53, 
+0xBD, 0xB4, 0xB5, 0x53, 0xBD, 0xB4, 0xB5, 0x73, 
+0xA4, 0xF1, 0xA4, 0xB0, 0x9C, 0xB0, 0x94, 0x6F, 
+0x94, 0x4F, 0x8C, 0x0E, 0x8C, 0x2E, 0x94, 0x2E, 
+0xA4, 0xD1, 0x9C, 0x90, 0x9C, 0x90, 0x94, 0x70, 
+0x9C, 0x90, 0x9C, 0xB0, 0xA4, 0xF0, 0xAD, 0x32, 
+0xB5, 0x53, 0xBD, 0xB4, 0xC5, 0xF5, 0xBD, 0xD5, 
+0xB5, 0x94, 0xBD, 0xD5, 0xBD, 0xD5, 0xCE, 0x77, 
+0xD6, 0x76, 0xC5, 0xF5, 0xC5, 0xF5, 0xCE, 0x35, 
+0xCE, 0x35, 0xC5, 0xD5, 0xC5, 0xD5, 0xC6, 0x15, 
+0x9C, 0x90, 0xB5, 0x73, 0xC5, 0xB3, 0xDE, 0x55, 
+0xDE, 0x76, 0x9C, 0x8F, 0xC5, 0xD4, 0xB5, 0x92, 
+0x9C, 0xAF, 0x9C, 0x8F, 0xCE, 0x35, 0xCE, 0x35, 
+0xA5, 0x55, 0xAD, 0x96, 0x9D, 0x14, 0x94, 0xD3, 
+0x7B, 0xEF, 0x84, 0x0F, 0x94, 0x90, 0x8C, 0x4F, 
+0x52, 0x88, 0x6B, 0x4B, 0x73, 0x8C, 0x6B, 0x2B, 
+0x73, 0x8C, 0x6B, 0x4B, 0x52, 0x88, 0x6B, 0x4B, 
+0x73, 0x6C, 0x8C, 0x4F, 0x9C, 0xD0, 0x73, 0x8C, 
+0x6B, 0x0A, 0x62, 0xC9, 0x73, 0x8C, 0xAD, 0x32, 
+0xB5, 0x32, 0xA4, 0x8F, 0xAC, 0xAF, 0xA4, 0x6E, 
+0xB4, 0xF0, 0xC5, 0x72, 0xBD, 0x92, 0xB5, 0x51, 
+0xAC, 0xF0, 0x94, 0x4E, 0x83, 0xCC, 0x8B, 0xCC, 
+0x8B, 0xEC, 0x8B, 0xCB, 0x8B, 0xCB, 0x8B, 0xEB, 
+0x8B, 0xCB, 0x83, 0xAA, 0x83, 0x6A, 0x7B, 0x6A, 
+0x83, 0x8A, 0x9C, 0x4E, 0xB5, 0x10, 0xAC, 0xEF, 
+0xB5, 0x10, 0xB4, 0xF0, 0xAC, 0xCF, 0xB5, 0x10, 
+0xAC, 0xCF, 0xA4, 0x8E, 0xAC, 0xCF, 0xAC, 0xAF, 
+0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0xAF, 
+0xB4, 0xEF, 0xB4, 0xF0, 0xB4, 0xEF, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xB4, 0xEF, 0xBD, 0x30, 0xBD, 0x51, 
+0xB5, 0x10, 0xB4, 0xEF, 0xAC, 0xEF, 0x94, 0x2E, 
+0x52, 0x68, 0x31, 0xA6, 0x39, 0xE7, 0x42, 0x07, 
+0x4A, 0x48, 0x4A, 0x69, 0x42, 0x08, 0x63, 0x0C, 
+0x7B, 0xCF, 0xAD, 0x35, 0xAD, 0x55, 0xAD, 0x56, 
+0xAD, 0x76, 0xBD, 0xD7, 0xBD, 0xD7, 0xC6, 0x38, 
+0xD6, 0x79, 0xA4, 0xD3, 0x6B, 0x2B, 0x7B, 0x8D, 
+0xA4, 0xF1, 0xAD, 0x31, 0xAC, 0xF1, 0xA4, 0xF0, 
+0x9C, 0xAF, 0xA4, 0xCF, 0xA4, 0xF0, 0x9C, 0x6E, 
+0x7B, 0x8B, 0xA4, 0xB0, 0x7B, 0x8C, 0x31, 0x64, 
+0x18, 0xE3, 0x31, 0xA5, 0x39, 0xA6, 0x31, 0xA6, 
+0x39, 0xC7, 0x6B, 0x4D, 0xAD, 0x55, 0xAD, 0x14, 
+0x9C, 0x71, 0x9C, 0x70, 0xBD, 0x74, 0xAC, 0xF2, 
+0xBD, 0x53, 0xD6, 0x17, 0x9C, 0x50, 0x7B, 0x8D, 
+0xA4, 0xD3, 0xBD, 0x75, 0xAD, 0x13, 0xAC, 0xF2, 
+0xAC, 0xF1, 0xAD, 0x12, 0xA4, 0xD1, 0xC5, 0xF5, 
+0xC5, 0xB4, 0xC5, 0xB4, 0x8C, 0x0D, 0x9C, 0x6E, 
+0xBD, 0x51, 0xBD, 0xB2, 0xC6, 0x14, 0xC5, 0xD3, 
+0xC5, 0xD3, 0xC6, 0x34, 0xC6, 0x15, 0xC6, 0x15, 
+0xC6, 0x15, 0xB5, 0xB6, 0xAD, 0x56, 0x9C, 0xD3, 
+0x83, 0xEF, 0x6B, 0x2B, 0x7B, 0x6B, 0xB5, 0x31, 
+0x83, 0xCB, 0x7B, 0xAC, 0x7B, 0xAC, 0x83, 0xCC, 
+0x7B, 0xAC, 0x83, 0xED, 0x94, 0x6F, 0x8C, 0x2E, 
+0xAD, 0x32, 0xA4, 0xD1, 0x83, 0xCD, 0x9C, 0xB0, 
+0x9C, 0xB0, 0x83, 0xEC, 0xA4, 0xF1, 0xBD, 0xB4, 
+0xBD, 0xD5, 0xB5, 0x53, 0x7B, 0x8C, 0xAD, 0x53, 
+0x9C, 0xB0, 0x9C, 0x90, 0xAD, 0x32, 0x9C, 0xB1, 
+0xA5, 0x12, 0x9C, 0x90, 0x94, 0x90, 0xB5, 0x53, 
+0xC5, 0xF5, 0xC5, 0xD4, 0xCE, 0x15, 0xB5, 0x73, 
+0x94, 0x6F, 0x8C, 0x0E, 0x73, 0x6C, 0x7B, 0x8C, 
+0x94, 0x4F, 0x8B, 0xED, 0xA4, 0xD0, 0xAD, 0x31, 
+0x94, 0x2D, 0x8C, 0x0C, 0x8B, 0xEC, 0x94, 0x4E, 
+0x83, 0xED, 0x9C, 0x8F, 0x94, 0x4E, 0xAD, 0x11, 
+0xA4, 0xD0, 0x8C, 0x2D, 0x8C, 0x2E, 0x83, 0xCC, 
+0x94, 0x4E, 0x8C, 0x2D, 0x9C, 0x8F, 0xA4, 0xF1, 
+0x94, 0x4F, 0xAD, 0x32, 0xAD, 0x11, 0x7B, 0xAD, 
+0x83, 0xEE, 0xB5, 0x94, 0xB5, 0x73, 0xA5, 0x12, 
+0x8C, 0x2F, 0x7B, 0xAD, 0x9C, 0xD0, 0xBD, 0xD4, 
+0xA5, 0x11, 0x9C, 0xD0, 0xAD, 0x52, 0xB5, 0x74, 
+0xB5, 0x73, 0x8C, 0x2E, 0x83, 0xEE, 0x7B, 0xCD, 
+0x83, 0xED, 0x83, 0xEE, 0x63, 0x0A, 0x7B, 0xAD, 
+0x94, 0x6F, 0xB5, 0x53, 0x9C, 0x90, 0xAD, 0x32, 
+0xA4, 0xD1, 0x83, 0xEE, 0x83, 0xEE, 0x94, 0x6F, 
+0x94, 0x6F, 0x9C, 0x90, 0x9C, 0xB0, 0x9C, 0xB0, 
+0xA4, 0xF1, 0x9C, 0xD1, 0x9C, 0xB0, 0x94, 0x4F, 
+0x9C, 0xB0, 0xA4, 0xD1, 0x9C, 0x90, 0x94, 0x6F, 
+0x8C, 0x2E, 0x8C, 0x0E, 0x83, 0xEE, 0x7B, 0x8C, 
+0x94, 0x4F, 0xB5, 0x52, 0xC5, 0xB4, 0xBD, 0x92, 
+0xBD, 0x72, 0xB5, 0x52, 0xB5, 0x31, 0xB5, 0x52, 
+0xC5, 0xB4, 0xAC, 0xF1, 0x9C, 0x6E, 0x8B, 0xED, 
+0x94, 0x2E, 0x9C, 0x8F, 0x94, 0x2E, 0x9C, 0x8F, 
+0xAD, 0x11, 0xAC, 0xF1, 0xA4, 0xF0, 0xAD, 0x11, 
+0x94, 0x4E, 0xAD, 0x32, 0xAD, 0x12, 0xB5, 0x32, 
+0xBD, 0x93, 0xCE, 0x15, 0xAD, 0x12, 0x94, 0x50, 
+0x9C, 0xB0, 0xA4, 0xB1, 0xAC, 0xF1, 0xB5, 0x32, 
+0xC5, 0xB5, 0xC5, 0xB5, 0xC5, 0xB4, 0xCD, 0xF5, 
+0xCD, 0xF5, 0xC5, 0xF5, 0xC5, 0xD5, 0xBD, 0xB4, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xBD, 0x94, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x52, 0xA4, 0xD1, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0x8F, 
+0xA4, 0xF1, 0xAD, 0x32, 0xB5, 0x31, 0xBD, 0x92, 
+0xB5, 0x52, 0x9C, 0x8F, 0xA4, 0xD1, 0xA4, 0xD0, 
+0x94, 0x6F, 0x9C, 0x8F, 0xAD, 0x11, 0xA4, 0xF0, 
+0xA5, 0x75, 0xAD, 0x76, 0x9D, 0x14, 0x94, 0xD3, 
+0x7B, 0xCF, 0x8C, 0x50, 0x94, 0xB0, 0x8C, 0x2F, 
+0x73, 0x6C, 0x9C, 0xB1, 0x7B, 0xCD, 0x7B, 0xCD, 
+0x6B, 0x4B, 0x4A, 0x68, 0x6B, 0x4C, 0x7B, 0xEE, 
+0x84, 0x0F, 0x94, 0x90, 0x7B, 0xCD, 0x83, 0xED, 
+0x8C, 0x4F, 0xA4, 0xF2, 0xB5, 0x73, 0xAD, 0x53, 
+0xAD, 0x32, 0x9C, 0x8F, 0xB4, 0xF0, 0xA4, 0x8E, 
+0xD6, 0x14, 0xD5, 0xF3, 0xD6, 0x13, 0xD6, 0x54, 
+0xD6, 0x34, 0xD6, 0x35, 0xC5, 0xF4, 0xBD, 0x93, 
+0xB5, 0x52, 0xA4, 0xAF, 0xBD, 0x93, 0xBD, 0x93, 
+0xAD, 0x11, 0xA4, 0xD0, 0x8C, 0x2E, 0x83, 0xCD, 
+0x94, 0x6F, 0x9C, 0x90, 0xAD, 0x10, 0xB5, 0x10, 
+0xBD, 0x71, 0xDE, 0x55, 0xB5, 0x10, 0xB4, 0xCF, 
+0x7B, 0x6A, 0x7B, 0x6B, 0x5A, 0x88, 0x4A, 0x06, 
+0x49, 0xE6, 0x4A, 0x27, 0x4A, 0x27, 0x62, 0xA9, 
+0x62, 0xA8, 0x6B, 0x0A, 0x73, 0x2A, 0x73, 0x4A, 
+0x7B, 0x4A, 0x73, 0x2A, 0x7B, 0x6A, 0x7B, 0x8A, 
+0x73, 0x09, 0x7B, 0x4A, 0x83, 0xAB, 0x9C, 0x4E, 
+0x8C, 0x0E, 0x4A, 0x48, 0x39, 0xE7, 0x42, 0x07, 
+0x31, 0xA6, 0x42, 0x07, 0x42, 0x08, 0x5A, 0xCB, 
+0x6B, 0x4D, 0x94, 0x92, 0xA5, 0x35, 0xB5, 0x96, 
+0xAD, 0x56, 0xA5, 0x35, 0xAD, 0x55, 0xC6, 0x38, 
+0xDE, 0xBA, 0x94, 0x50, 0x41, 0xE7, 0x7B, 0xAE, 
+0x94, 0x2E, 0xBD, 0x72, 0xBD, 0x51, 0xBD, 0x30, 
+0xBD, 0x51, 0xC5, 0x71, 0xC5, 0x91, 0xBD, 0x71, 
+0xC5, 0x72, 0xB5, 0x10, 0xB5, 0x10, 0x8B, 0xED, 
+0x21, 0x03, 0x21, 0x03, 0x63, 0x0B, 0x42, 0x07, 
+0x31, 0xA6, 0x4A, 0x48, 0x9C, 0xB2, 0x9C, 0x92, 
+0x9C, 0x71, 0x8B, 0xEF, 0xAC, 0xF2, 0xAC, 0xD2, 
+0x9C, 0x2F, 0x9C, 0x2F, 0x73, 0x0B, 0x94, 0x10, 
+0x83, 0xCF, 0x7B, 0x8E, 0xB5, 0x34, 0xBD, 0x75, 
+0xB5, 0x55, 0xCE, 0x38, 0xA4, 0xD2, 0xA5, 0x12, 
+0xBD, 0xB4, 0xBD, 0x93, 0x8C, 0x0D, 0xAC, 0xCF, 
+0xAC, 0xEF, 0xA4, 0xCF, 0xA4, 0xF0, 0x94, 0x4E, 
+0x83, 0xCC, 0x8C, 0x2D, 0x9C, 0xD0, 0xB5, 0x73, 
+0xAD, 0x52, 0xB5, 0xB5, 0xAD, 0x76, 0x9C, 0xF4, 
+0x83, 0xEF, 0x7B, 0x8C, 0x8B, 0xED, 0xB4, 0xF0, 
+0x94, 0x0D, 0x7B, 0xAC, 0x7B, 0xAC, 0x8C, 0x0D, 
+0x73, 0x6B, 0x73, 0x6B, 0x7B, 0xAC, 0x73, 0x4B, 
+0xA4, 0xF1, 0x8C, 0x0E, 0x94, 0x6F, 0xAD, 0x52, 
+0xA4, 0xD1, 0x83, 0xED, 0xAD, 0x53, 0xCE, 0x16, 
+0xC5, 0xD5, 0xC5, 0xF5, 0xB5, 0x74, 0xCE, 0x36, 
+0xBD, 0xD4, 0xA4, 0xF1, 0x9C, 0x90, 0x94, 0x6F, 
+0x9C, 0x90, 0xA4, 0xF1, 0xAD, 0x32, 0xCE, 0x36, 
+0xD6, 0x76, 0xCE, 0x36, 0xCE, 0x15, 0xA4, 0xD1, 
+0x8C, 0x2E, 0x7B, 0xAD, 0x73, 0x4B, 0x7B, 0x8C, 
+0x8B, 0xCD, 0x94, 0x0D, 0xA4, 0xF0, 0xAD, 0x10, 
+0x94, 0x2D, 0x8B, 0xEC, 0x94, 0x2D, 0x9C, 0x8F, 
+0x8C, 0x0D, 0x9C, 0x8F, 0x94, 0x8F, 0xA5, 0x11, 
+0x94, 0x4E, 0x7B, 0xCB, 0x8C, 0x0D, 0x8B, 0xED, 
+0x83, 0xEC, 0x7B, 0x8B, 0x94, 0x6E, 0xA4, 0xF0, 
+0x9C, 0xD0, 0xB5, 0x53, 0xA4, 0xF1, 0x7B, 0xAD, 
+0xA4, 0xF1, 0xBD, 0xD4, 0xBD, 0xD5, 0xAD, 0x53, 
+0x9C, 0xD1, 0x8C, 0x4F, 0x8C, 0x4F, 0xA4, 0xD1, 
+0x8C, 0x0E, 0x94, 0x6F, 0xA4, 0xF1, 0xB5, 0x73, 
+0xBD, 0xB4, 0x94, 0x90, 0x94, 0x90, 0x9C, 0xF1, 
+0x94, 0xB0, 0x9C, 0xB1, 0x7B, 0xCD, 0x83, 0xEE, 
+0x9C, 0xB0, 0xAD, 0x32, 0x73, 0x8C, 0x7B, 0xCD, 
+0x84, 0x0E, 0x9C, 0xF2, 0xA5, 0x12, 0xAD, 0x53, 
+0xAD, 0x53, 0xAD, 0x73, 0xB5, 0x74, 0xAD, 0x53, 
+0xAD, 0x33, 0xA4, 0xF1, 0xA4, 0xF2, 0x94, 0x70, 
+0x8C, 0x4F, 0x94, 0x6F, 0x9C, 0xB0, 0xA4, 0xF1, 
+0x94, 0x6F, 0x8C, 0x4F, 0x9C, 0xB1, 0x83, 0xEE, 
+0x8C, 0x2E, 0xAD, 0x12, 0x9C, 0xAF, 0xAD, 0x10, 
+0xAD, 0x10, 0x9C, 0x8F, 0xAC, 0xF1, 0xBD, 0x93, 
+0xBD, 0xB3, 0xBD, 0x93, 0xAD, 0x31, 0x94, 0x4E, 
+0x8C, 0x4E, 0x8C, 0x2E, 0x7B, 0xAC, 0x8C, 0x2E, 
+0x9C, 0xD0, 0x9C, 0xB0, 0xB5, 0x73, 0xC5, 0xF5, 
+0xB5, 0x73, 0xAD, 0x52, 0xAD, 0x11, 0xAD, 0x32, 
+0x9C, 0xB0, 0xB5, 0x52, 0x73, 0x4B, 0x5A, 0xA9, 
+0x73, 0x4B, 0x83, 0x8C, 0x7B, 0x8C, 0x83, 0xCD, 
+0x9C, 0x6F, 0xA4, 0xB0, 0xA4, 0xD1, 0xB5, 0x53, 
+0xB5, 0x53, 0xA4, 0xD1, 0x9C, 0xB0, 0x9C, 0xB0, 
+0xA4, 0xD0, 0xA4, 0xB0, 0x9C, 0x70, 0x9C, 0x90, 
+0xA4, 0xB1, 0xA4, 0xD1, 0xAC, 0xF1, 0xAD, 0x12, 
+0xA4, 0xF1, 0xB5, 0x32, 0xB5, 0x32, 0x94, 0x4F, 
+0x83, 0xED, 0x9C, 0x8F, 0xA4, 0xF1, 0xAD, 0x12, 
+0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x32, 0xB5, 0x32, 
+0xAD, 0x11, 0xAD, 0x32, 0xB5, 0x52, 0xB5, 0x73, 
+0xA4, 0xF1, 0xB5, 0x73, 0xBD, 0x73, 0xBD, 0x94, 
+0xAD, 0x76, 0xB5, 0xD7, 0x9D, 0x14, 0x94, 0xD3, 
+0x7B, 0xCF, 0x84, 0x50, 0x84, 0x4F, 0x84, 0x2E, 
+0x9C, 0xD1, 0x84, 0x2F, 0x6B, 0x8C, 0x94, 0x90, 
+0x7B, 0xEE, 0x73, 0xAE, 0x8C, 0x70, 0x94, 0x91, 
+0x94, 0xB2, 0xA4, 0xF2, 0x94, 0x70, 0x9C, 0xD1, 
+0x7B, 0xEE, 0x9C, 0xB1, 0xBD, 0xD5, 0xAD, 0x53, 
+0xBD, 0x94, 0xA4, 0xAF, 0xB4, 0xF0, 0xAC, 0xCF, 
+0xDE, 0x55, 0xB4, 0xEF, 0xBD, 0x50, 0xC5, 0x91, 
+0xC5, 0xB2, 0xCD, 0xD3, 0xCD, 0xD3, 0xC5, 0xD3, 
+0xBD, 0x92, 0xC5, 0xD4, 0xCE, 0x35, 0xD6, 0x35, 
+0xC5, 0xD4, 0xCE, 0x15, 0xBD, 0x93, 0xAD, 0x32, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xCD, 0xF4, 0xD6, 0x35, 
+0xCD, 0xF3, 0xDE, 0x75, 0xBD, 0x30, 0xB5, 0x10, 
+0xA4, 0xB0, 0x94, 0x6F, 0x7B, 0xCD, 0x7B, 0xAD, 
+0x84, 0x0F, 0x8C, 0x4F, 0x83, 0xEE, 0x8C, 0x2F, 
+0x7B, 0xCD, 0x83, 0xCD, 0x7B, 0x8C, 0x7B, 0xAD, 
+0x8C, 0x2E, 0x7B, 0x8C, 0x6B, 0x0A, 0x73, 0x6B, 
+0x7B, 0x8C, 0x8C, 0x0D, 0x9C, 0xB0, 0xA4, 0xD1, 
+0xAD, 0x12, 0x73, 0x4B, 0x4A, 0x27, 0x4A, 0x28, 
+0x4A, 0x48, 0x4A, 0x48, 0x39, 0xC6, 0x42, 0x28, 
+0x5A, 0xCB, 0x7B, 0xCF, 0x9C, 0xF4, 0xAD, 0x76, 
+0xAD, 0x55, 0x9C, 0xD3, 0x9C, 0xD4, 0xB5, 0xB7, 
+0xCE, 0x79, 0x7B, 0xAE, 0x42, 0x08, 0x39, 0xA6, 
+0x62, 0xCA, 0x83, 0xAC, 0x83, 0xAB, 0x94, 0x0D, 
+0xAC, 0xD0, 0xAC, 0xCF, 0xAC, 0xCF, 0x83, 0xAA, 
+0x94, 0x2C, 0x9C, 0x4D, 0x9C, 0x6E, 0xA4, 0x8F, 
+0x41, 0xE6, 0x5A, 0xCA, 0x7B, 0x8C, 0x31, 0x65, 
+0x39, 0xA6, 0x31, 0xA5, 0x42, 0x08, 0xA4, 0xF3, 
+0x7B, 0x6D, 0xAC, 0xF4, 0xA4, 0xF3, 0xA4, 0xB2, 
+0x7B, 0x6D, 0x39, 0x86, 0x4A, 0x28, 0x7B, 0xAE, 
+0x4A, 0x29, 0x5A, 0x8B, 0xBD, 0x96, 0xB5, 0x96, 
+0xCE, 0x59, 0xBD, 0xF8, 0xF7, 0x7D, 0xBD, 0xF7, 
+0x73, 0x6D, 0xBD, 0x94, 0xAD, 0x11, 0xBD, 0x30, 
+0xB5, 0x10, 0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xEF, 
+0xB4, 0xCF, 0xB4, 0xEF, 0xAC, 0xCF, 0xA4, 0xAF, 
+0x9C, 0x6F, 0xBD, 0xB6, 0xBD, 0xD7, 0xA5, 0x14, 
+0xAC, 0xF2, 0xA4, 0xAF, 0xB5, 0x10, 0xB4, 0xEF, 
+0x94, 0x0D, 0x8B, 0xEC, 0x83, 0xEC, 0x8C, 0x0D, 
+0x7B, 0x8B, 0x7B, 0xAC, 0x7B, 0x8B, 0x94, 0x2E, 
+0xB5, 0x53, 0x73, 0x6C, 0x83, 0xCD, 0x9C, 0x90, 
+0x9C, 0xB0, 0x8C, 0x0E, 0xA4, 0xF1, 0xBD, 0xB4, 
+0xAD, 0x32, 0x94, 0x90, 0xA4, 0xD1, 0xCE, 0x16, 
+0xA5, 0x12, 0x83, 0xED, 0x8C, 0x0E, 0x8C, 0x2E, 
+0xA4, 0xD1, 0xB5, 0x53, 0xCE, 0x16, 0xC6, 0x15, 
+0xDE, 0x97, 0xD6, 0x76, 0xC5, 0xF5, 0x73, 0x6B, 
+0x83, 0xCD, 0x7B, 0x8D, 0x4A, 0x07, 0x6B, 0x2B, 
+0x83, 0x8C, 0x94, 0x4E, 0xAD, 0x11, 0xAC, 0xF0, 
+0xAC, 0xD0, 0xAD, 0x10, 0xB5, 0x72, 0xB5, 0x72, 
+0xAD, 0x31, 0xAD, 0x31, 0xAD, 0x32, 0xAD, 0x11, 
+0x94, 0x6E, 0x94, 0x4E, 0x94, 0x4E, 0x9C, 0x8F, 
+0x94, 0x2E, 0x83, 0xED, 0x7B, 0xAC, 0xA4, 0xF0, 
+0xA4, 0xD1, 0xAD, 0x12, 0x9C, 0x90, 0x63, 0x2B, 
+0xA5, 0x33, 0xBD, 0xD4, 0xBD, 0xB5, 0xAD, 0x53, 
+0xA5, 0x33, 0x94, 0x70, 0x94, 0x6F, 0x8C, 0x2F, 
+0x84, 0x0E, 0xA5, 0x12, 0xB5, 0xB4, 0xC5, 0xF5, 
+0xBD, 0xD4, 0xA5, 0x32, 0xAD, 0x53, 0xAD, 0x53, 
+0xA5, 0x32, 0xA5, 0x12, 0x94, 0x90, 0x8C, 0x70, 
+0x9C, 0x6F, 0xA4, 0xF1, 0x7B, 0xEE, 0x94, 0x90, 
+0x9C, 0xF2, 0xAD, 0x53, 0xAD, 0x53, 0xB5, 0xB4, 
+0xB5, 0xB4, 0xB5, 0xB4, 0xBD, 0xB5, 0xB5, 0xB4, 
+0xAD, 0x73, 0xB5, 0x73, 0xB5, 0x94, 0xA5, 0x12, 
+0x94, 0xB0, 0xAD, 0x33, 0xB5, 0x74, 0xBD, 0xD5, 
+0xAD, 0x33, 0x94, 0x90, 0x9C, 0xB1, 0x8C, 0x4F, 
+0x94, 0x6F, 0xAD, 0x32, 0xAD, 0x31, 0xAD, 0x31, 
+0xA4, 0xCF, 0x94, 0x6E, 0xB5, 0x72, 0xB5, 0x93, 
+0xBD, 0xD4, 0xBD, 0xD4, 0xBD, 0xB4, 0xA4, 0xF1, 
+0xAD, 0x53, 0xA5, 0x12, 0x8C, 0x6F, 0x94, 0x70, 
+0x9C, 0xD1, 0xA4, 0xF1, 0xC5, 0xD5, 0xCE, 0x36, 
+0xBD, 0xB4, 0xC5, 0xF4, 0xBD, 0x93, 0xB5, 0x73, 
+0x9C, 0xB0, 0xA4, 0xB0, 0x6A, 0xEA, 0x83, 0xCE, 
+0x7B, 0x8C, 0x8B, 0xED, 0x83, 0xED, 0x7B, 0xAC, 
+0x83, 0xAC, 0x9C, 0x6F, 0xA4, 0xF1, 0xB5, 0x73, 
+0xB5, 0x73, 0xBD, 0x94, 0xB5, 0x73, 0xB5, 0x53, 
+0xB5, 0x73, 0xBD, 0x93, 0xAD, 0x12, 0xA4, 0xF1, 
+0x94, 0x2F, 0x83, 0xCD, 0x94, 0x4F, 0x73, 0x6C, 
+0x62, 0xCA, 0x7B, 0xAD, 0x7B, 0x8C, 0x6B, 0x0B, 
+0x62, 0xA9, 0x9C, 0x90, 0x9C, 0xB0, 0xA4, 0xD1, 
+0xAD, 0x12, 0x9C, 0x90, 0x9C, 0xB0, 0x9C, 0x8F, 
+0x83, 0xED, 0x94, 0x4F, 0x94, 0x6F, 0x94, 0x4F, 
+0x8C, 0x0E, 0xB5, 0x53, 0xAC, 0xF1, 0xA4, 0xF1, 
+0xA5, 0x55, 0xAD, 0x76, 0x9D, 0x14, 0x94, 0xD3, 
+0x73, 0xCF, 0x84, 0x2F, 0x94, 0xB1, 0x9C, 0xD1, 
+0x9C, 0xF2, 0x84, 0x0E, 0x8C, 0x50, 0x63, 0x2B, 
+0x6B, 0x4C, 0x9C, 0xD2, 0x9C, 0xD2, 0x8C, 0x50, 
+0x7C, 0x0F, 0xAD, 0x33, 0x94, 0x91, 0xA4, 0xF2, 
+0x83, 0xEE, 0xB5, 0x94, 0xB5, 0x94, 0xA4, 0xF1, 
+0xBD, 0x93, 0x9C, 0x8F, 0xB5, 0x10, 0xAC, 0xCF, 
+0xD6, 0x13, 0xAC, 0xEF, 0x9C, 0x4D, 0xAC, 0xEF, 
+0xBD, 0x71, 0xC5, 0x92, 0xBD, 0x71, 0xC5, 0xB2, 
+0xB5, 0x51, 0xCE, 0x35, 0xCE, 0x35, 0xD6, 0x35, 
+0xCE, 0x15, 0xCE, 0x15, 0xC5, 0xF5, 0xAD, 0x12, 
+0xBD, 0x93, 0xCE, 0x14, 0xB5, 0x31, 0xAC, 0xCF, 
+0xB5, 0x10, 0xD6, 0x34, 0xAC, 0xCF, 0xB5, 0x10, 
+0xB5, 0x52, 0x84, 0x0E, 0x8C, 0x4F, 0xA4, 0xF2, 
+0xA4, 0xD1, 0xAD, 0x32, 0x7B, 0xCD, 0x94, 0x90, 
+0x94, 0x90, 0xA4, 0xF2, 0x8C, 0x50, 0x8C, 0x70, 
+0x8C, 0x4F, 0x8C, 0x2F, 0x8C, 0x4F, 0x9C, 0xB0, 
+0x8C, 0x2E, 0x9C, 0xB0, 0xB5, 0x93, 0xB5, 0x73, 
+0xB5, 0x73, 0xA4, 0xD1, 0x52, 0x68, 0x42, 0x07, 
+0x41, 0xE7, 0x41, 0xE7, 0x39, 0xC6, 0x31, 0xA6, 
+0x42, 0x49, 0x63, 0x2C, 0x8C, 0x51, 0xAD, 0x76, 
+0xAD, 0x76, 0x9C, 0xB3, 0x8C, 0x72, 0xB5, 0x96, 
+0xD6, 0x9A, 0xB5, 0x96, 0x6B, 0x4E, 0x4A, 0x29, 
+0x5A, 0x8A, 0x7B, 0x8D, 0x83, 0xCD, 0x7B, 0xCD, 
+0x7B, 0xAC, 0x8B, 0xED, 0xAC, 0xF0, 0x9C, 0x8F, 
+0x9C, 0xAF, 0xAD, 0x10, 0xAC, 0xCF, 0x9C, 0x4E, 
+0x7B, 0xAC, 0x73, 0x8C, 0x21, 0x03, 0x21, 0x03, 
+0x31, 0x85, 0x31, 0xA6, 0x29, 0x45, 0x5A, 0xCA, 
+0xA4, 0xD3, 0xAC, 0xF4, 0xCE, 0x38, 0x7B, 0x8D, 
+0x41, 0xE7, 0x29, 0x04, 0x29, 0x45, 0x6B, 0x2C, 
+0x7B, 0xCF, 0x7B, 0x8F, 0xB5, 0x76, 0xC5, 0xF8, 
+0xCE, 0x39, 0xB5, 0xB7, 0xCE, 0x9A, 0xEF, 0x7D, 
+0xA4, 0xF4, 0xBD, 0xB5, 0xE6, 0xF9, 0xD5, 0xF3, 
+0xDE, 0x54, 0xE6, 0x75, 0xDE, 0x54, 0xC5, 0x71, 
+0xCD, 0xB2, 0xDE, 0x34, 0xC5, 0x71, 0xBD, 0x30, 
+0xA4, 0xD0, 0xCE, 0x38, 0xA5, 0x14, 0xA5, 0x13, 
+0xA4, 0xB0, 0xAC, 0xCF, 0xB4, 0xEF, 0xB5, 0x10, 
+0xB5, 0x30, 0xBD, 0x51, 0xC5, 0x71, 0xCD, 0x92, 
+0xC5, 0x71, 0xC5, 0x71, 0xBD, 0x51, 0xC5, 0x93, 
+0xC5, 0xF5, 0xC5, 0xF6, 0xBD, 0xB5, 0xB5, 0x74, 
+0xAD, 0x33, 0xAD, 0x12, 0xA4, 0xF2, 0x9C, 0x90, 
+0xA4, 0xD1, 0xAD, 0x32, 0xAD, 0x12, 0xA4, 0xD1, 
+0x9C, 0x90, 0x94, 0x90, 0x94, 0x70, 0x8C, 0x2F, 
+0x8C, 0x2F, 0x83, 0xEE, 0x8C, 0x2E, 0x8C, 0x0E, 
+0x9C, 0x90, 0x94, 0x4F, 0x83, 0xED, 0x7B, 0x8C, 
+0x8C, 0x2F, 0x9C, 0x91, 0x94, 0x50, 0x83, 0xCE, 
+0x7B, 0x8D, 0x73, 0x6B, 0x7B, 0x8B, 0x7B, 0xAB, 
+0x8C, 0x0D, 0x9C, 0x8F, 0xA4, 0xCF, 0xA4, 0xD0, 
+0xB5, 0x52, 0xBD, 0xB3, 0xBD, 0xB3, 0xBD, 0x93, 
+0xB5, 0x72, 0xAD, 0x10, 0xAD, 0x10, 0xBD, 0x52, 
+0xAD, 0x10, 0xAD, 0x11, 0x94, 0x6E, 0x9C, 0xB0, 
+0xAD, 0x32, 0xAD, 0x12, 0x84, 0x0E, 0x63, 0x2B, 
+0xBD, 0xF5, 0xBD, 0xD4, 0xCE, 0x56, 0xBD, 0xD4, 
+0xAD, 0x73, 0x8C, 0x2F, 0x73, 0x8C, 0x7B, 0xAC, 
+0x8C, 0x2E, 0xA5, 0x12, 0xC5, 0xF5, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xA5, 0x12, 0x9C, 0xF2, 0xB5, 0xB5, 
+0xAD, 0x73, 0xAD, 0x74, 0xAD, 0x53, 0xA4, 0xF1, 
+0x9C, 0x90, 0xA4, 0xD1, 0x8C, 0x4F, 0x9C, 0xD1, 
+0xA5, 0x12, 0xA5, 0x12, 0xA5, 0x32, 0xB5, 0x94, 
+0xC5, 0xF6, 0xBD, 0xD5, 0xBD, 0xB4, 0xBD, 0xD5, 
+0xBD, 0xD5, 0xBD, 0xF5, 0xC6, 0x16, 0xB5, 0x94, 
+0xB5, 0x94, 0xBD, 0xD5, 0xBD, 0xD5, 0xC6, 0x36, 
+0xBD, 0xF5, 0x9C, 0xF2, 0xA4, 0xF1, 0x94, 0x6F, 
+0x9C, 0xB0, 0xB5, 0x73, 0xB5, 0x52, 0xAD, 0x11, 
+0xAD, 0x32, 0xAD, 0x52, 0xC5, 0xF5, 0xC5, 0xD4, 
+0xBD, 0x93, 0xAD, 0x52, 0xBD, 0xB4, 0xAD, 0x12, 
+0xA4, 0xF1, 0x9C, 0xF1, 0x94, 0xB1, 0x9C, 0xD1, 
+0xAD, 0x74, 0xAD, 0x53, 0xC6, 0x36, 0xCE, 0x35, 
+0xBD, 0xD4, 0xC6, 0x15, 0xC5, 0xF5, 0xBD, 0xD4, 
+0x94, 0x90, 0xA4, 0xD1, 0x73, 0x4B, 0x8C, 0x2F, 
+0x83, 0xCD, 0x94, 0x4E, 0x83, 0xCD, 0x83, 0xCD, 
+0x94, 0x4F, 0x9C, 0xB0, 0xA4, 0xD0, 0xA4, 0xF1, 
+0x94, 0x6F, 0x83, 0xED, 0x83, 0xCD, 0x7B, 0xCC, 
+0x83, 0xED, 0x94, 0x4F, 0x94, 0x6F, 0x8C, 0x2E, 
+0x8C, 0x2E, 0x94, 0x4F, 0xA4, 0xD1, 0x8C, 0x2F, 
+0x73, 0x6C, 0x73, 0x4C, 0x4A, 0x28, 0x52, 0x48, 
+0x73, 0x4C, 0xAD, 0x12, 0x94, 0x6F, 0xAD, 0x12, 
+0xB5, 0x53, 0x9C, 0x90, 0xA4, 0xF1, 0xA4, 0xF1, 
+0x94, 0x6F, 0xAD, 0x11, 0xA4, 0xF1, 0xAD, 0x32, 
+0x94, 0x6F, 0xB5, 0x53, 0xB5, 0x73, 0x9C, 0xB0, 
+0xA5, 0x55, 0xA5, 0x35, 0x9D, 0x14, 0x94, 0xD3, 
+0x73, 0xCE, 0x84, 0x50, 0x94, 0x90, 0x94, 0x90, 
+0x9C, 0xD1, 0x9C, 0xB1, 0x94, 0x90, 0x84, 0x0E, 
+0x6B, 0x6C, 0x9C, 0xD2, 0x94, 0x71, 0x94, 0x90, 
+0x8C, 0x70, 0xAD, 0x54, 0x9C, 0xD1, 0xAD, 0x33, 
+0xBD, 0xB4, 0xBD, 0xD4, 0xB5, 0x73, 0xB5, 0x93, 
+0xC5, 0xD5, 0x9C, 0x6F, 0xB4, 0xF0, 0xA4, 0x8E, 
+0xD5, 0xF3, 0xBD, 0x51, 0xB4, 0xEF, 0x8B, 0xAA, 
+0x9C, 0x6E, 0xAC, 0xCF, 0xB5, 0x51, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xD6, 0x35, 0xCE, 0x35, 0xCE, 0x15, 
+0xCD, 0xF4, 0xD6, 0x36, 0xCD, 0xF5, 0xBD, 0x72, 
+0xC5, 0xD4, 0xD6, 0x35, 0xC5, 0x92, 0xA4, 0xAE, 
+0x9C, 0x2D, 0xD5, 0xF3, 0xAC, 0xCE, 0xBD, 0x92, 
+0xBD, 0x93, 0xAD, 0x12, 0xAD, 0x32, 0xBD, 0xB5, 
+0xB5, 0x73, 0xBD, 0xB5, 0xB5, 0x53, 0xAD, 0x33, 
+0xB5, 0x73, 0xB5, 0x73, 0x9C, 0xD1, 0xA4, 0xF2, 
+0xB5, 0x53, 0xB5, 0x73, 0x7B, 0xCD, 0x9C, 0xD1, 
+0xAD, 0x32, 0xAD, 0x12, 0xBD, 0x93, 0xB5, 0x52, 
+0xC5, 0xD4, 0xA4, 0xD1, 0x7B, 0xCD, 0x42, 0x06, 
+0x39, 0xA6, 0x42, 0x07, 0x4A, 0x68, 0x42, 0x08, 
+0x4A, 0x49, 0x5A, 0xCB, 0x73, 0x8E, 0x8C, 0x71, 
+0x94, 0xB3, 0x84, 0x10, 0xA5, 0x34, 0xB5, 0x96, 
+0xA5, 0x14, 0xBD, 0xF7, 0xA5, 0x14, 0x94, 0x71, 
+0x9C, 0xB1, 0xA4, 0xD2, 0xAD, 0x33, 0xA5, 0x12, 
+0x7B, 0xCD, 0x6B, 0x4B, 0xAD, 0x11, 0xB5, 0x51, 
+0xA4, 0xCF, 0xBD, 0x92, 0xB5, 0x31, 0x9C, 0x6E, 
+0x94, 0x2E, 0x9C, 0x90, 0x6B, 0x4B, 0x5A, 0xAA, 
+0x6B, 0x2B, 0x41, 0xE7, 0x39, 0xE7, 0x29, 0x24, 
+0x4A, 0x28, 0x8C, 0x30, 0xAD, 0x13, 0x41, 0xE6, 
+0x18, 0xC2, 0x29, 0x45, 0x39, 0xA6, 0x4A, 0x49, 
+0x7B, 0xAE, 0x52, 0x8A, 0x6B, 0x2D, 0x84, 0x11, 
+0xAD, 0x56, 0xD6, 0x9B, 0xCE, 0x7A, 0xBD, 0xB7, 
+0x94, 0x71, 0x8C, 0x50, 0xCE, 0x17, 0xA4, 0xB0, 
+0xB5, 0x51, 0xC5, 0xB2, 0xBD, 0x51, 0xB4, 0xEF, 
+0x9C, 0x4C, 0xA4, 0xAE, 0xB5, 0x0F, 0xAC, 0xAF, 
+0x83, 0xEE, 0xB5, 0x95, 0x5A, 0xCB, 0x84, 0x10, 
+0x5A, 0xA9, 0x5A, 0x88, 0x62, 0xE9, 0x6B, 0x0A, 
+0x7B, 0x6B, 0x83, 0xAB, 0x94, 0x0D, 0xA4, 0x8F, 
+0xB5, 0x10, 0xAD, 0x0F, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xA4, 0xD0, 0xA4, 0xD1, 0xAD, 0x32, 0xAD, 0x12, 
+0xB5, 0x33, 0xB5, 0x74, 0xBD, 0x94, 0xB5, 0x33, 
+0xB5, 0x73, 0xAD, 0x12, 0xB5, 0x33, 0xBD, 0xB4, 
+0xC5, 0xD5, 0xC5, 0xD5, 0xB5, 0x73, 0xB5, 0x94, 
+0xBD, 0xB5, 0xBD, 0x94, 0xBD, 0x93, 0xBD, 0x94, 
+0xBD, 0xB5, 0xBD, 0xB4, 0xBD, 0xB4, 0xC5, 0xD5, 
+0xC5, 0xB5, 0xC5, 0xD5, 0xC5, 0xF6, 0xC5, 0xF6, 
+0xBD, 0xD5, 0xB5, 0x53, 0xAD, 0x12, 0x9C, 0xB0, 
+0x94, 0x6F, 0x8C, 0x0E, 0x83, 0xEE, 0x8B, 0xEE, 
+0x83, 0xED, 0x83, 0xED, 0x8C, 0x0D, 0x8B, 0xED, 
+0x83, 0xCD, 0x7B, 0xAC, 0x83, 0xCC, 0x83, 0xCC, 
+0x7B, 0xAB, 0x8B, 0xED, 0x83, 0xCC, 0x83, 0xAC, 
+0xAD, 0x32, 0x9C, 0xB0, 0x8C, 0x4F, 0x84, 0x2E, 
+0x9C, 0xF1, 0xA4, 0xF1, 0xBD, 0xD4, 0xA4, 0xF1, 
+0xB5, 0x73, 0x7B, 0xAD, 0x6B, 0x6C, 0x73, 0x6C, 
+0x8C, 0x4F, 0xAD, 0x53, 0xCE, 0x36, 0xCE, 0x36, 
+0xC6, 0x16, 0xB5, 0x94, 0xB5, 0xB4, 0xBD, 0xF5, 
+0xC5, 0xF5, 0xBD, 0xD5, 0xA5, 0x32, 0x9C, 0xB0, 
+0x94, 0x6F, 0xA4, 0xD1, 0x9C, 0xB1, 0xA5, 0x12, 
+0xAD, 0x53, 0xAD, 0x53, 0x9C, 0xF2, 0xB5, 0x73, 
+0xB5, 0x94, 0xBD, 0xD5, 0xB5, 0x73, 0xB5, 0x74, 
+0xB5, 0x94, 0xBD, 0xB4, 0xBD, 0xD5, 0xB5, 0x94, 
+0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0xD5, 0xC5, 0xF5, 
+0xBD, 0xB5, 0xA4, 0xF2, 0xA5, 0x32, 0x9C, 0xD1, 
+0x8C, 0x2F, 0xB5, 0x73, 0xAD, 0x31, 0xAD, 0x11, 
+0xAD, 0x52, 0xB5, 0x93, 0xBD, 0xB4, 0xBD, 0x93, 
+0xB5, 0x73, 0xAD, 0x52, 0xBD, 0xB4, 0xAD, 0x32, 
+0x9C, 0xB0, 0x8C, 0x4E, 0x7B, 0xCD, 0x94, 0x90, 
+0xB5, 0x94, 0xAD, 0x53, 0xC6, 0x36, 0xC6, 0x35, 
+0xBD, 0xB4, 0xC6, 0x15, 0xC5, 0xF4, 0xAD, 0x32, 
+0x94, 0x8F, 0xA5, 0x11, 0x8C, 0x0E, 0x94, 0x4F, 
+0x8C, 0x0E, 0x94, 0x4F, 0x8C, 0x2F, 0x94, 0x2F, 
+0x9C, 0x90, 0xA4, 0xF1, 0xA5, 0x11, 0xBD, 0xB4, 
+0xA4, 0xF1, 0x7B, 0xCC, 0x84, 0x0D, 0x83, 0xCD, 
+0x94, 0x6F, 0xA4, 0xD1, 0xB5, 0x93, 0x9C, 0xB0, 
+0x9C, 0xB0, 0xA4, 0xD1, 0xB5, 0x53, 0xA4, 0xF1, 
+0x7B, 0x8C, 0x7B, 0xAE, 0x6B, 0x0C, 0x7B, 0x8D, 
+0x94, 0x71, 0xB5, 0x94, 0x9C, 0xB1, 0xB5, 0x73, 
+0xB5, 0x52, 0xAC, 0xF1, 0xB5, 0x73, 0xBD, 0xB3, 
+0xA4, 0xD0, 0xC5, 0xB4, 0xBD, 0x93, 0xBD, 0x93, 
+0xA4, 0xD0, 0xBD, 0x94, 0xAD, 0x12, 0xA4, 0xD0, 
+0xA5, 0x55, 0xA5, 0x35, 0x9D, 0x14, 0x9C, 0xD3, 
+0x5A, 0xEB, 0x5A, 0xC9, 0x6B, 0x2B, 0x6B, 0x4B, 
+0x73, 0x8C, 0x7B, 0xCD, 0x84, 0x0E, 0x84, 0x0E, 
+0x84, 0x0E, 0x94, 0x90, 0x8C, 0x50, 0x94, 0x70, 
+0x94, 0x90, 0x9C, 0xD1, 0x9C, 0xF2, 0xA5, 0x12, 
+0xAD, 0x73, 0xB5, 0x93, 0xB5, 0x73, 0xBD, 0xB4, 
+0xA4, 0xD0, 0x94, 0x4D, 0xAC, 0xEF, 0x93, 0xEC, 
+0xCD, 0xB3, 0x9C, 0x4D, 0x94, 0x0C, 0x7B, 0x6A, 
+0x9C, 0x6F, 0x83, 0x8B, 0x73, 0x2A, 0x7B, 0x8B, 
+0xAC, 0xF0, 0xD6, 0x35, 0xD6, 0x56, 0xD6, 0x35, 
+0xD6, 0x55, 0xD6, 0x56, 0xC5, 0xB3, 0xC5, 0xB3, 
+0xC5, 0x92, 0xC5, 0xB3, 0xC5, 0xB3, 0xB5, 0x10, 
+0x83, 0x8A, 0xAC, 0xEF, 0xA4, 0x8E, 0xCD, 0xF4, 
+0xC5, 0xF4, 0xAD, 0x52, 0xA5, 0x12, 0xBD, 0x94, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xA4, 0xF1, 0xBD, 0x94, 
+0xBD, 0xB4, 0xB5, 0x73, 0xA4, 0xD1, 0xA4, 0xF1, 
+0xB5, 0x74, 0x8C, 0x4F, 0x7B, 0xCD, 0xB5, 0x73, 
+0xBD, 0xB4, 0xB5, 0x73, 0xBD, 0x94, 0xBD, 0x93, 
+0xBD, 0xB4, 0x9C, 0x6F, 0xB5, 0x52, 0x62, 0xC9, 
+0x41, 0xE7, 0x39, 0xA6, 0x39, 0xE7, 0x42, 0x07, 
+0x42, 0x28, 0x4A, 0x48, 0x52, 0x89, 0x6B, 0x4D, 
+0x73, 0x6D, 0x94, 0x92, 0xA5, 0x34, 0xAD, 0x75, 
+0x9C, 0xD3, 0xCE, 0x59, 0xDE, 0xBB, 0xAD, 0x14, 
+0xB5, 0x54, 0xB5, 0x53, 0xB5, 0x74, 0xAD, 0x33, 
+0x83, 0xCE, 0x6B, 0x0B, 0xAD, 0x11, 0xB5, 0x31, 
+0xA4, 0xCF, 0xB5, 0x71, 0xBD, 0x72, 0xA4, 0x6E, 
+0xA4, 0xD0, 0xAC, 0xF1, 0xA4, 0xB0, 0x8C, 0x0E, 
+0x8B, 0xEE, 0x73, 0x2B, 0x39, 0xA6, 0x31, 0x85, 
+0x31, 0x85, 0x39, 0xA6, 0x62, 0xEA, 0x39, 0xA5, 
+0x29, 0x65, 0x39, 0xA6, 0x39, 0xE7, 0x4A, 0x69, 
+0x41, 0xE8, 0x52, 0x8A, 0x5A, 0xAB, 0x6B, 0x6E, 
+0xAD, 0x55, 0xCE, 0x59, 0x8C, 0x51, 0x6B, 0x2D, 
+0x7B, 0xAE, 0x8C, 0x30, 0x94, 0x71, 0xC5, 0xF7, 
+0xBD, 0x73, 0xCD, 0xF4, 0xC5, 0xB2, 0xC5, 0xB2, 
+0xA4, 0xAE, 0x9C, 0x4C, 0xAC, 0xEF, 0xA4, 0x8E, 
+0x8C, 0x2F, 0xB5, 0x96, 0x8C, 0x51, 0x8C, 0x51, 
+0x42, 0x07, 0x42, 0x07, 0x4A, 0x48, 0x4A, 0x48, 
+0x4A, 0x48, 0x52, 0x68, 0x52, 0x68, 0x5A, 0x89, 
+0x62, 0xEA, 0x73, 0x4B, 0x5A, 0xA8, 0x63, 0x0A, 
+0x62, 0xEA, 0x52, 0x88, 0x5A, 0xC9, 0x62, 0xEA, 
+0x83, 0xCD, 0x84, 0x0E, 0x94, 0x6F, 0x9C, 0x8F, 
+0x8C, 0x2E, 0x83, 0xAC, 0x83, 0xCD, 0x94, 0x70, 
+0xA4, 0xD1, 0xA4, 0xD1, 0xA4, 0xF2, 0xB5, 0x53, 
+0x9C, 0xD1, 0x94, 0x6F, 0x8C, 0x2E, 0x9C, 0x90, 
+0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x12, 0xAD, 0x12, 
+0xB5, 0x33, 0x94, 0x2F, 0x8C, 0x2E, 0x8C, 0x0E, 
+0x94, 0x8F, 0xA4, 0xF1, 0xA4, 0xF2, 0xB5, 0x73, 
+0xAD, 0x12, 0xAD, 0x33, 0xBD, 0x94, 0xBD, 0x94, 
+0xBD, 0x94, 0xB5, 0x94, 0xBD, 0x94, 0xBD, 0xB5, 
+0xC5, 0xD5, 0xBD, 0xB5, 0xBD, 0x94, 0xBD, 0x94, 
+0xAD, 0x32, 0x73, 0x8C, 0xB5, 0x74, 0xBD, 0xB5, 
+0xBD, 0xD5, 0xC5, 0xD5, 0xBD, 0xB4, 0xB5, 0x73, 
+0xAD, 0x32, 0xA4, 0xF1, 0xA4, 0xF1, 0x9C, 0xD1, 
+0xA5, 0x12, 0xA4, 0xF2, 0xA5, 0x12, 0xAD, 0x12, 
+0xA5, 0x12, 0xAD, 0x33, 0xAD, 0x32, 0xA4, 0xF1, 
+0xA5, 0x11, 0xA5, 0x12, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xAD, 0x53, 0x8C, 0x2E, 0x7B, 0xAD, 
+0x8C, 0x4F, 0x8C, 0x2E, 0x9C, 0xD1, 0xB5, 0x94, 
+0xC5, 0xF6, 0xCE, 0x37, 0xC5, 0xF6, 0xBD, 0xB4, 
+0xB5, 0x93, 0xCE, 0x57, 0xCE, 0x36, 0xC6, 0x36, 
+0xC6, 0x16, 0xBD, 0xD5, 0xBD, 0xD5, 0xBD, 0xB4, 
+0xB5, 0x94, 0xAD, 0x53, 0xB5, 0x74, 0xBD, 0xB4, 
+0xA5, 0x12, 0xB5, 0x94, 0xBD, 0xB5, 0xA4, 0xF1, 
+0x7B, 0xAD, 0xA4, 0xF1, 0x9C, 0x8F, 0xA5, 0x11, 
+0xAD, 0x12, 0xCE, 0x36, 0xC6, 0x15, 0xBD, 0xB4, 
+0xB5, 0x93, 0xB5, 0x93, 0xBD, 0xD5, 0xAD, 0x53, 
+0xB5, 0x94, 0xAD, 0x32, 0x94, 0x6F, 0xAD, 0x53, 
+0xB5, 0x94, 0xAD, 0x53, 0xC6, 0x35, 0xC6, 0x35, 
+0xBD, 0xD4, 0xBD, 0xD4, 0xB5, 0x73, 0x9C, 0xB0, 
+0x94, 0x8F, 0xAD, 0x32, 0x94, 0x6F, 0x84, 0x0E, 
+0x9C, 0xD0, 0x9C, 0xB1, 0x94, 0x6F, 0xA4, 0xD1, 
+0x9C, 0xB0, 0xA4, 0xF1, 0x9C, 0xB0, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xAD, 0x12, 0xA4, 0xD1, 0x9C, 0xD1, 
+0xAD, 0x12, 0xBD, 0xB4, 0xBD, 0xB4, 0xAD, 0x32, 
+0x9C, 0xD1, 0xA4, 0xD1, 0xB5, 0x52, 0xBD, 0x93, 
+0x7B, 0x8D, 0x62, 0xEB, 0x62, 0xEB, 0x73, 0x8D, 
+0x94, 0x71, 0xBD, 0xD6, 0xA4, 0xF2, 0xB5, 0x52, 
+0xB5, 0x32, 0xAC, 0xF1, 0xBD, 0x93, 0xC5, 0xB4, 
+0xAC, 0xF1, 0xC5, 0xB3, 0xCD, 0xF4, 0xC5, 0xF4, 
+0xAD, 0x11, 0xB5, 0x52, 0xAD, 0x32, 0xB5, 0x53, 
+0xA5, 0x55, 0xA5, 0x35, 0x9D, 0x14, 0x94, 0xD3, 
+0x73, 0xAD, 0x7B, 0x8B, 0x83, 0xCC, 0x8C, 0x0D, 
+0x94, 0x2D, 0x9C, 0x6E, 0x9C, 0x8E, 0x9C, 0x6E, 
+0x9C, 0x8F, 0xA4, 0x8F, 0xA4, 0x8F, 0xA4, 0x8F, 
+0x9C, 0x6E, 0x94, 0x2D, 0x94, 0x4E, 0x9C, 0x6F, 
+0xA4, 0xAF, 0xA4, 0xD0, 0xA4, 0xB0, 0x9C, 0xAF, 
+0x9C, 0x8E, 0xA4, 0x8E, 0xAC, 0xAE, 0x83, 0x8A, 
+0xA4, 0x6E, 0xA4, 0x6E, 0x8B, 0xCB, 0x8B, 0xCC, 
+0xA4, 0xAF, 0x73, 0x4A, 0x7B, 0x8C, 0x8C, 0x0D, 
+0xAC, 0xF0, 0xC5, 0xB3, 0xCD, 0xF4, 0xBD, 0x72, 
+0xBD, 0x72, 0xA4, 0xF0, 0xA4, 0xAF, 0xBD, 0x72, 
+0xC5, 0x92, 0xBD, 0x72, 0xB5, 0x31, 0xA4, 0x8E, 
+0x83, 0x8B, 0xAC, 0xEF, 0xAC, 0xAE, 0xBD, 0x72, 
+0xC5, 0xD4, 0xA4, 0xF1, 0x9C, 0xB0, 0x94, 0x6F, 
+0xA4, 0xD1, 0xAD, 0x32, 0x9C, 0xB0, 0xBD, 0xD4, 
+0xBD, 0x93, 0x9C, 0xB0, 0xBD, 0xB5, 0x9C, 0x90, 
+0xB5, 0x74, 0x9C, 0x90, 0x9C, 0xB0, 0xC5, 0xF5, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xCE, 0x35, 0xAC, 0xD0, 0xC5, 0x72, 0x94, 0x4E, 
+0x52, 0x88, 0x39, 0xA6, 0x31, 0x85, 0x39, 0xC6, 
+0x39, 0xC6, 0x39, 0xC6, 0x4A, 0x69, 0x63, 0x2C, 
+0x84, 0x10, 0x9C, 0xD3, 0x9C, 0xD3, 0x94, 0x72, 
+0x84, 0x10, 0xBD, 0xD7, 0xD6, 0xBA, 0xCE, 0x58, 
+0xA4, 0xD2, 0xC5, 0xB5, 0xC5, 0xD6, 0xAD, 0x33, 
+0x83, 0xCE, 0x63, 0x0B, 0xA4, 0xD0, 0xB5, 0x31, 
+0xAD, 0x10, 0xB5, 0x51, 0xB5, 0x30, 0x9C, 0x6D, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xA4, 0xD0, 0x9C, 0x6F, 
+0x73, 0x0A, 0x94, 0x0E, 0x9C, 0x90, 0x62, 0xCA, 
+0x31, 0x85, 0x31, 0x65, 0x31, 0x85, 0x29, 0x44, 
+0x31, 0xA6, 0x31, 0xA6, 0x39, 0xE7, 0x39, 0xE7, 
+0x42, 0x28, 0x6B, 0x2D, 0x63, 0x2D, 0x7B, 0xCF, 
+0x8C, 0x72, 0xA5, 0x35, 0x63, 0x2C, 0x52, 0x8A, 
+0x62, 0xCB, 0x7B, 0x6D, 0x7B, 0xAE, 0xD6, 0x9A, 
+0xCE, 0x37, 0xAD, 0x12, 0xA4, 0xD0, 0x94, 0x2D, 
+0x83, 0xEC, 0x94, 0x4D, 0xB5, 0x10, 0xA4, 0x8E, 
+0x94, 0x92, 0xB5, 0x96, 0x9C, 0xF4, 0x8C, 0x71, 
+0x42, 0x28, 0x4A, 0x49, 0x52, 0x89, 0x5A, 0xAA, 
+0x5A, 0xAA, 0x5A, 0xAA, 0x52, 0x69, 0x52, 0x69, 
+0x52, 0x89, 0x5A, 0xCA, 0x52, 0x89, 0x5A, 0xCA, 
+0x5A, 0xCA, 0x5A, 0xCA, 0x63, 0x0B, 0x62, 0xEB, 
+0x52, 0xA9, 0x5A, 0xEA, 0x94, 0x70, 0xA4, 0xF1, 
+0x94, 0x4F, 0x83, 0xED, 0x7B, 0xAD, 0x73, 0x8C, 
+0x83, 0xEE, 0x7B, 0xCD, 0x73, 0x8C, 0x7B, 0xAD, 
+0x83, 0xCD, 0x7B, 0xAD, 0x7B, 0x8C, 0x7B, 0x8C, 
+0x7B, 0xAC, 0x73, 0x4B, 0xA4, 0xD1, 0x9C, 0xB1, 
+0x7B, 0xAD, 0x6B, 0x0A, 0x7B, 0x8C, 0x8C, 0x2E, 
+0x83, 0xAD, 0x83, 0xEE, 0x8C, 0x0E, 0x94, 0x90, 
+0x94, 0x6F, 0x9C, 0x90, 0x8C, 0x4E, 0x94, 0x6F, 
+0x9C, 0xD0, 0x9C, 0xD1, 0x9C, 0xB1, 0xA4, 0xF1, 
+0x94, 0x70, 0xAD, 0x32, 0xAD, 0x12, 0x9C, 0xB1, 
+0x62, 0xEB, 0x4A, 0x49, 0x8C, 0x70, 0x94, 0x6F, 
+0x9C, 0x90, 0x9C, 0x90, 0xAD, 0x12, 0xA4, 0xF1, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xB5, 0x53, 0xB5, 0x73, 
+0xC5, 0xF5, 0xBD, 0x94, 0xBD, 0x94, 0xB5, 0x73, 
+0xBD, 0x73, 0xBD, 0xB4, 0xBD, 0x94, 0xB5, 0x52, 
+0xB5, 0x73, 0xBD, 0x73, 0xC5, 0xB4, 0xC5, 0xB4, 
+0xBD, 0x94, 0xBD, 0x94, 0xC5, 0xD5, 0xC5, 0xF5, 
+0xCE, 0x16, 0xC5, 0xB4, 0xB5, 0x53, 0xAD, 0x12, 
+0xA4, 0xB1, 0xA4, 0xB1, 0xA4, 0xD0, 0x9C, 0xB0, 
+0x9C, 0xB0, 0x9C, 0xB0, 0xA4, 0xF1, 0xA4, 0xD1, 
+0x9C, 0xB0, 0x9C, 0xB0, 0xA4, 0xF1, 0xAD, 0x32, 
+0xA4, 0xF1, 0x8C, 0x2E, 0x94, 0x6F, 0x9C, 0x90, 
+0x9C, 0xB1, 0xAD, 0x33, 0xB5, 0x53, 0x84, 0x0E, 
+0x83, 0xEE, 0xBD, 0xB5, 0xAD, 0x32, 0x9C, 0xB0, 
+0x8C, 0x2E, 0xAD, 0x32, 0x83, 0xED, 0x9C, 0xD0, 
+0xBD, 0xD4, 0xCE, 0x36, 0xC6, 0x15, 0xAD, 0x52, 
+0xCE, 0x36, 0xCE, 0x36, 0xB5, 0x94, 0xC6, 0x16, 
+0xC5, 0xF6, 0xC5, 0xF5, 0xD6, 0x97, 0xC6, 0x15, 
+0xC6, 0x15, 0xCE, 0x36, 0xBD, 0xB4, 0x94, 0x8F, 
+0x9C, 0xB0, 0xA4, 0xF1, 0x94, 0x6F, 0xA4, 0xF1, 
+0x9C, 0xD1, 0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x94, 0xC5, 0xF5, 0xBD, 0xD5, 0xC5, 0xF5, 
+0xCE, 0x36, 0xC5, 0xF5, 0xBD, 0xB4, 0xB5, 0x73, 
+0xBD, 0xB4, 0xC5, 0xF5, 0xC5, 0xF5, 0xBD, 0xB4, 
+0xBD, 0x94, 0xBD, 0x94, 0xC5, 0xD4, 0xC5, 0xD4, 
+0x83, 0xCD, 0x8C, 0x0F, 0x62, 0xEB, 0x6B, 0x6D, 
+0x94, 0x91, 0xC6, 0x17, 0xB5, 0x54, 0xAD, 0x32, 
+0xB5, 0x32, 0xB5, 0x32, 0xBD, 0x93, 0xC5, 0x93, 
+0xBD, 0x73, 0xD6, 0x35, 0xCE, 0x14, 0xC5, 0xF4, 
+0xA4, 0xF1, 0xAC, 0xF1, 0xAD, 0x32, 0xB5, 0x52, 
+0xA5, 0x55, 0xA5, 0x35, 0x9D, 0x14, 0x94, 0xB3, 
+0x6B, 0x4C, 0x5A, 0x67, 0x5A, 0x67, 0x6A, 0xC8, 
+0x72, 0xE9, 0x7B, 0x29, 0x7B, 0x4A, 0x7B, 0x4A, 
+0x83, 0xAB, 0x8B, 0xCC, 0x94, 0x0C, 0x9C, 0x2D, 
+0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x8F, 0xA4, 0x6E, 
+0x9C, 0x4E, 0x9C, 0x6E, 0x9C, 0x6E, 0xA4, 0xAF, 
+0xAC, 0xAF, 0xA4, 0x8E, 0xAC, 0xCF, 0xB5, 0x10, 
+0xB4, 0xEF, 0xB4, 0xCF, 0xB4, 0xF0, 0xAC, 0xEF, 
+0xAC, 0xCF, 0xB4, 0xF0, 0xB4, 0xEF, 0xAC, 0xAE, 
+0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x6D, 0x9C, 0x2C, 
+0x94, 0x2C, 0x93, 0xEC, 0x8B, 0xEC, 0x94, 0x2D, 
+0x8B, 0xCC, 0x83, 0x8B, 0x83, 0x6A, 0x8B, 0xAA, 
+0x72, 0xE8, 0x94, 0x0D, 0xAC, 0xCF, 0x9C, 0x2D, 
+0x8B, 0xEC, 0x73, 0x2A, 0x8B, 0xED, 0x73, 0x2A, 
+0x62, 0xA9, 0x62, 0xC9, 0x73, 0x4B, 0x7B, 0x6B, 
+0x73, 0x2A, 0x62, 0xC9, 0x83, 0xEE, 0x73, 0x4A, 
+0x83, 0xCC, 0x83, 0xCC, 0x9C, 0x6F, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAD, 0x31, 0xB5, 0x52, 
+0xAD, 0x11, 0xAC, 0xCF, 0xC5, 0x71, 0x9C, 0x4D, 
+0x8C, 0x0E, 0x42, 0x07, 0x39, 0xA6, 0x42, 0x07, 
+0x42, 0x28, 0x42, 0x28, 0x4A, 0x69, 0x52, 0x89, 
+0x63, 0x0C, 0x7B, 0xAE, 0x9C, 0xB2, 0x83, 0xEF, 
+0x9C, 0xD3, 0xB5, 0x96, 0xBD, 0xB7, 0xCE, 0x59, 
+0x94, 0x51, 0xA4, 0xF3, 0xEF, 0x3C, 0xDE, 0xDB, 
+0xBD, 0xB6, 0x7B, 0xCE, 0xA4, 0xD1, 0xBD, 0x93, 
+0xC5, 0xD3, 0xBD, 0xB3, 0xB5, 0x10, 0x9C, 0x2C, 
+0xB5, 0x10, 0xB5, 0x11, 0xAC, 0xF0, 0xB4, 0xF1, 
+0x94, 0x0E, 0x8B, 0xED, 0x94, 0x2E, 0x73, 0x4B, 
+0x31, 0xA5, 0x39, 0xC6, 0x31, 0x85, 0x29, 0x64, 
+0x31, 0x85, 0x39, 0xC6, 0x39, 0xE7, 0x42, 0x28, 
+0x62, 0xEB, 0x6B, 0x6D, 0x7B, 0xCF, 0x63, 0x0C, 
+0x63, 0x2D, 0x8C, 0x72, 0x6B, 0x2D, 0x39, 0x86, 
+0x41, 0xE7, 0x52, 0x49, 0x73, 0x6D, 0xAD, 0x35, 
+0xDE, 0xBA, 0xE6, 0xDB, 0xCE, 0x38, 0x83, 0xEE, 
+0x83, 0xED, 0x9C, 0x8F, 0xBD, 0x30, 0xA4, 0x8F, 
+0xB5, 0x75, 0xAD, 0x76, 0x9C, 0xF4, 0x8C, 0x51, 
+0x6B, 0x4D, 0x6B, 0x2C, 0x62, 0xEB, 0x63, 0x0B, 
+0x63, 0x2B, 0x63, 0x0B, 0x62, 0xEA, 0x6B, 0x4B, 
+0x6B, 0x6C, 0x73, 0x8D, 0x63, 0x2B, 0x6B, 0x4C, 
+0x6B, 0x6C, 0x73, 0x8D, 0x73, 0xAE, 0x7B, 0xCE, 
+0x83, 0xEE, 0x83, 0xEE, 0x9C, 0xD1, 0xAD, 0x12, 
+0xB5, 0x32, 0xA4, 0xF1, 0xA4, 0xF1, 0xA5, 0x12, 
+0xB5, 0x93, 0xB5, 0x94, 0x9C, 0xD1, 0xAD, 0x12, 
+0xA4, 0xF1, 0x94, 0x2E, 0x9C, 0x8F, 0xA4, 0xD1, 
+0xA4, 0xB1, 0x83, 0xEE, 0xCE, 0x57, 0xDE, 0xB8, 
+0xCD, 0xF5, 0xBD, 0x94, 0xA4, 0xD0, 0xB5, 0x52, 
+0xA4, 0xB0, 0xAC, 0xF1, 0x9C, 0xB0, 0xB5, 0x53, 
+0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x12, 
+0xB5, 0x73, 0xAD, 0x32, 0xA4, 0xF2, 0xA4, 0xF1, 
+0xA4, 0xD1, 0xA4, 0xF1, 0x8C, 0x2E, 0x5A, 0xCB, 
+0x4A, 0x6A, 0x52, 0xAB, 0x94, 0x91, 0xA5, 0x12, 
+0x9C, 0x90, 0xAD, 0x12, 0xC5, 0xD5, 0xBD, 0x94, 
+0xB5, 0x52, 0xB5, 0x53, 0xAD, 0x32, 0xA4, 0xD1, 
+0x9C, 0x90, 0x8C, 0x0D, 0x94, 0x4E, 0x9C, 0x8F, 
+0xA4, 0xD0, 0x94, 0x4E, 0x94, 0x6F, 0x83, 0xEC, 
+0x94, 0x6E, 0xA4, 0xD0, 0xAC, 0xF0, 0xB5, 0x10, 
+0xAD, 0x10, 0xA4, 0xCF, 0x8C, 0x2D, 0x94, 0x2E, 
+0x8C, 0x2E, 0x8C, 0x0E, 0x8C, 0x0E, 0x94, 0x4F, 
+0x9C, 0x90, 0x9C, 0x90, 0x9C, 0xB0, 0xB5, 0x53, 
+0xBD, 0x73, 0xB5, 0x53, 0xAD, 0x32, 0xB5, 0x52, 
+0xB5, 0x53, 0xB5, 0x73, 0xB5, 0x53, 0xB5, 0x53, 
+0xAD, 0x12, 0xB5, 0x53, 0xA5, 0x12, 0xB5, 0x53, 
+0xC5, 0xB4, 0xBD, 0x94, 0xB5, 0x53, 0xBD, 0xB4, 
+0xAD, 0x32, 0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x12, 
+0xA4, 0xD1, 0xA4, 0xF2, 0x94, 0x70, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xA4, 0xD0, 0x9C, 0xD0, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x32, 
+0xA5, 0x11, 0xA5, 0x11, 0xA4, 0xD0, 0x94, 0x4F, 
+0x94, 0x6F, 0x9C, 0x90, 0x83, 0xED, 0x6B, 0x2A, 
+0x94, 0x6F, 0xA5, 0x12, 0xB5, 0x73, 0xA4, 0xF1, 
+0x94, 0x90, 0xB5, 0x94, 0xBD, 0xB4, 0xBD, 0x94, 
+0xC6, 0x16, 0xCE, 0x57, 0xCE, 0x36, 0xCE, 0x36, 
+0xCE, 0x36, 0xCE, 0x36, 0xCE, 0x36, 0xCE, 0x36, 
+0xCE, 0x36, 0xD6, 0x56, 0xD6, 0x57, 0xCE, 0x36, 
+0xCE, 0x56, 0xD6, 0x76, 0xD6, 0x77, 0xCE, 0x15, 
+0x83, 0xCD, 0xA4, 0xF2, 0x7B, 0xAE, 0x8C, 0x51, 
+0xAD, 0x55, 0xCE, 0x79, 0xC5, 0xD5, 0xBD, 0x94, 
+0xB5, 0x32, 0xBD, 0x73, 0xD6, 0x15, 0xD6, 0x35, 
+0xCD, 0xD3, 0xD6, 0x55, 0xD6, 0x35, 0xCD, 0xF4, 
+0xA4, 0xF0, 0xAD, 0x11, 0xC5, 0xF4, 0xBD, 0x93, 
+0xA5, 0x55, 0xA5, 0x35, 0x9D, 0x14, 0x94, 0xB2, 
+0x8C, 0x0F, 0x7B, 0x6B, 0x7B, 0x6B, 0x83, 0xAC, 
+0x94, 0x2D, 0x8B, 0xCC, 0x7B, 0x4B, 0x83, 0x6B, 
+0x8B, 0xCC, 0x83, 0x6B, 0x83, 0xAC, 0x83, 0xAC, 
+0x8B, 0xEC, 0x9C, 0x2D, 0x9C, 0x4D, 0x9C, 0x4D, 
+0x7B, 0x6A, 0x83, 0xCC, 0x7B, 0x8B, 0x6B, 0x09, 
+0x6A, 0xE9, 0x6A, 0xE9, 0x7B, 0x6A, 0x73, 0x09, 
+0x7B, 0x4A, 0x83, 0x6A, 0x8B, 0xCB, 0x94, 0x0C, 
+0x9C, 0x2C, 0xA4, 0x6D, 0x9C, 0x2C, 0x9C, 0x2C, 
+0xA4, 0x6D, 0xA4, 0x8E, 0x9C, 0x2D, 0xA4, 0x8E, 
+0xB4, 0xCF, 0xB4, 0xEF, 0xB4, 0xEF, 0xA4, 0x8E, 
+0x9C, 0x4D, 0xA4, 0x8E, 0xA4, 0x8E, 0x9C, 0x6D, 
+0x9C, 0x4D, 0x9C, 0x2D, 0xA4, 0x8E, 0xAC, 0xCF, 
+0xA4, 0x8E, 0x9C, 0x6F, 0x9C, 0x6E, 0x9C, 0x4E, 
+0x9C, 0x6F, 0x9C, 0x4F, 0x9C, 0x6E, 0x9C, 0x6E, 
+0xA4, 0xCF, 0xA4, 0xB0, 0x9C, 0x6E, 0xA4, 0x6F, 
+0x94, 0x0D, 0x94, 0x0D, 0x9C, 0x6E, 0x9C, 0x6E, 
+0x94, 0x0D, 0x8B, 0xEC, 0x83, 0xAB, 0x73, 0x4A, 
+0x73, 0x29, 0x7B, 0x6A, 0xAC, 0xCF, 0x94, 0x0D, 
+0x83, 0xAC, 0x62, 0xEA, 0x42, 0x07, 0x4A, 0x48, 
+0x4A, 0x48, 0x42, 0x07, 0x4A, 0x69, 0x52, 0xAA, 
+0x5A, 0xAA, 0x7B, 0xCF, 0x73, 0x6D, 0x84, 0x30, 
+0x9C, 0xF3, 0xAD, 0x55, 0xB5, 0x96, 0xBD, 0xB7, 
+0x8C, 0x51, 0x62, 0xEC, 0xA5, 0x14, 0xBD, 0xB7, 
+0xBD, 0x96, 0x94, 0x50, 0xBD, 0xB4, 0xCE, 0x34, 
+0xC5, 0xF4, 0xBD, 0xB3, 0xB5, 0x10, 0xA4, 0x6D, 
+0xCD, 0xD3, 0xD5, 0xD3, 0xCD, 0xB3, 0xCD, 0xB3, 
+0x9C, 0x2E, 0x83, 0xAC, 0x7B, 0x6B, 0x6B, 0x0A, 
+0x5A, 0xA9, 0x39, 0xC6, 0x41, 0xE7, 0x31, 0x85, 
+0x31, 0xA6, 0x39, 0xC6, 0x42, 0x07, 0x52, 0x89, 
+0x73, 0x8D, 0x52, 0xAA, 0x5A, 0xEB, 0x39, 0xE7, 
+0x6B, 0x4D, 0x84, 0x31, 0x6B, 0x4D, 0x31, 0x85, 
+0x41, 0xE7, 0x42, 0x08, 0x4A, 0x28, 0x39, 0xA7, 
+0x52, 0x8A, 0x6B, 0x2D, 0xDE, 0xBB, 0xD6, 0x79, 
+0x94, 0x70, 0x9C, 0x6F, 0xBD, 0x51, 0xA4, 0xAF, 
+0xBD, 0xF6, 0xA5, 0x35, 0x8C, 0x72, 0x9C, 0xB1, 
+0xAD, 0x32, 0xAD, 0x11, 0xA4, 0xF1, 0x9C, 0xB0, 
+0x94, 0x6F, 0x8C, 0x2E, 0x8C, 0x4F, 0x8C, 0x2E, 
+0x8C, 0x2E, 0x9C, 0xB0, 0x8C, 0x4F, 0x83, 0xED, 
+0x83, 0xEE, 0x83, 0xEE, 0x8C, 0x0E, 0x8C, 0x4F, 
+0x9C, 0xB0, 0xA4, 0xF1, 0xAD, 0x32, 0xAD, 0x11, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xB5, 0x72, 0xA5, 0x11, 
+0xA4, 0xF1, 0xB5, 0x73, 0xA4, 0xD1, 0xBD, 0x93, 
+0xCD, 0xD4, 0xCD, 0xD3, 0xBD, 0x72, 0xBD, 0x52, 
+0xAC, 0xF1, 0x41, 0xE7, 0x6B, 0x6C, 0x9C, 0xB1, 
+0xBD, 0xB4, 0xCE, 0x36, 0xB5, 0x51, 0xA4, 0xD0, 
+0xB5, 0x11, 0xC5, 0x93, 0x9C, 0x90, 0xB5, 0x73, 
+0xB5, 0x53, 0xA4, 0xF1, 0xAD, 0x52, 0xB5, 0x94, 
+0xB5, 0x74, 0xB5, 0x74, 0xBD, 0x94, 0xBD, 0x94, 
+0xB5, 0x73, 0x9C, 0xB1, 0x5A, 0xCA, 0x4A, 0x4A, 
+0x4A, 0x6A, 0x4A, 0x6A, 0x8C, 0x50, 0x9C, 0xB1, 
+0x8C, 0x4F, 0x9C, 0xB0, 0xA4, 0xF1, 0xAD, 0x32, 
+0xB5, 0x52, 0xAD, 0x32, 0xBD, 0xB4, 0xB5, 0x52, 
+0xA4, 0xD1, 0xAD, 0x11, 0xBD, 0xB3, 0xB5, 0x72, 
+0xBD, 0x93, 0xA4, 0xD0, 0x9C, 0x8F, 0x9C, 0xB0, 
+0xB5, 0x52, 0xAC, 0xF0, 0xB5, 0x30, 0xBD, 0x71, 
+0xAD, 0x30, 0xB5, 0x51, 0xB5, 0x72, 0xB5, 0x72, 
+0xA4, 0xF0, 0x94, 0x6E, 0x94, 0x6E, 0x8C, 0x2D, 
+0x94, 0x6F, 0x83, 0xCC, 0x73, 0x4B, 0xA4, 0xD1, 
+0xB5, 0x53, 0xBD, 0x94, 0x83, 0xCD, 0x9C, 0x90, 
+0xAD, 0x12, 0x94, 0x70, 0x94, 0x2F, 0x94, 0x6F, 
+0x8C, 0x2F, 0x94, 0x4F, 0x83, 0xED, 0x8C, 0x0E, 
+0x94, 0x2F, 0x9C, 0x90, 0x9C, 0x70, 0x8C, 0x2F, 
+0x8C, 0x2E, 0x94, 0x6F, 0x9C, 0xB0, 0xA4, 0xD1, 
+0xAC, 0xF1, 0xB5, 0x53, 0xBD, 0x73, 0xB5, 0x32, 
+0xA4, 0xB0, 0x94, 0x4F, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0x9C, 0x90, 0x9C, 0x90, 0x9C, 0x8F, 
+0x94, 0x6F, 0x94, 0x4E, 0x9C, 0x90, 0xA4, 0xF1, 
+0xA4, 0xD0, 0xAD, 0x12, 0xAD, 0x11, 0xAD, 0x11, 
+0xAD, 0x12, 0xAD, 0x32, 0xAD, 0x12, 0xAD, 0x32, 
+0x9C, 0xB0, 0xA4, 0xF1, 0xA4, 0xD1, 0xAD, 0x32, 
+0xAD, 0x32, 0xAD, 0x32, 0xAC, 0xF1, 0xA4, 0xD1, 
+0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xA4, 0xF2, 0xCE, 0x16, 0xDE, 0x99, 0xDE, 0x99, 
+0xAD, 0x33, 0xAD, 0x32, 0xB5, 0x73, 0xAD, 0x53, 
+0x83, 0xCE, 0xAD, 0x54, 0x94, 0x71, 0x73, 0x8E, 
+0x63, 0x2D, 0x8C, 0x51, 0xCE, 0x17, 0xC5, 0xD4, 
+0xC5, 0x94, 0xBD, 0x73, 0xCD, 0xF5, 0xC5, 0xB4, 
+0xBD, 0x72, 0xC5, 0xB3, 0xC5, 0x72, 0xAC, 0xD0, 
+0xA4, 0x8F, 0xB5, 0x52, 0xCD, 0xF5, 0xB5, 0x73, 
+0xA5, 0x55, 0xA5, 0x34, 0x9D, 0x14, 0x94, 0xB2, 
+0x94, 0x70, 0x8B, 0xED, 0x94, 0x2E, 0xAC, 0xF1, 
+0x83, 0x8B, 0x94, 0x4E, 0xAC, 0xF0, 0xAD, 0x11, 
+0xB5, 0x11, 0xAD, 0x11, 0xB5, 0x32, 0xA4, 0xAF, 
+0xB5, 0x31, 0xB5, 0x10, 0xAC, 0xAE, 0xA4, 0x6E, 
+0x94, 0x4E, 0x9C, 0xB0, 0x94, 0x90, 0xA4, 0xF1, 
+0x9C, 0xB1, 0x8C, 0x2E, 0x8C, 0x0D, 0x8C, 0x2E, 
+0x8C, 0x2E, 0x8C, 0x2E, 0x9C, 0x8F, 0x94, 0x4E, 
+0x9C, 0x4E, 0xA4, 0xAF, 0x9C, 0x4D, 0xA4, 0xAE, 
+0xA4, 0x8E, 0xAC, 0xCF, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xAC, 0xD0, 0x9C, 0x6E, 0xA4, 0x8E, 0xAC, 0xCF, 
+0xC5, 0x92, 0xBD, 0x31, 0xB5, 0x10, 0xBD, 0x51, 
+0xA4, 0x8E, 0x94, 0x0D, 0x94, 0x0C, 0xA4, 0x6D, 
+0x9C, 0x2D, 0xA4, 0x6E, 0xA4, 0x8E, 0x94, 0x0D, 
+0x8B, 0xAB, 0x83, 0xAC, 0x8B, 0xCC, 0x94, 0x0D, 
+0x9C, 0x4D, 0xA4, 0x8F, 0x9C, 0x4D, 0x8B, 0xAB, 
+0x93, 0xEC, 0x9C, 0x4D, 0xB5, 0x10, 0xB5, 0x10, 
+0xA4, 0xAF, 0xA4, 0x6E, 0x9C, 0x6E, 0x9C, 0x2D, 
+0x94, 0x2D, 0x9C, 0x6E, 0xAC, 0xAE, 0xAC, 0xCF, 
+0xA4, 0x8E, 0x8C, 0x0D, 0x4A, 0x48, 0x39, 0xC6, 
+0x39, 0xA6, 0x39, 0xC6, 0x4A, 0x28, 0x52, 0x89, 
+0x52, 0x8A, 0x5A, 0xCA, 0x5A, 0xCB, 0x9C, 0xB2, 
+0x9C, 0xB2, 0xA5, 0x14, 0xAD, 0x76, 0xB5, 0x76, 
+0x84, 0x30, 0x41, 0xE8, 0x5A, 0x8A, 0x5A, 0xAB, 
+0x4A, 0x49, 0x63, 0x0B, 0xB5, 0x73, 0x8C, 0x2D, 
+0x7B, 0xAB, 0x7B, 0x8A, 0x9C, 0x4D, 0x8B, 0xEB, 
+0x9C, 0x4D, 0xA4, 0x8E, 0x9C, 0x6E, 0x83, 0x8B, 
+0x62, 0xA8, 0x83, 0xAC, 0x73, 0x4B, 0x6A, 0xEA, 
+0x8C, 0x0E, 0x9C, 0x6F, 0xA4, 0x8F, 0x73, 0x6B, 
+0x39, 0xC6, 0x29, 0x65, 0x39, 0xC7, 0x42, 0x07, 
+0x52, 0x69, 0x31, 0xA6, 0x39, 0xC7, 0x52, 0xAA, 
+0x73, 0x8E, 0x7B, 0xEF, 0x7B, 0xAE, 0x39, 0xA6, 
+0x52, 0x8A, 0x52, 0xAA, 0x7B, 0xCF, 0x73, 0xAE, 
+0x5A, 0xCB, 0x39, 0xC8, 0x63, 0x0D, 0xBD, 0xF7, 
+0xDE, 0xDA, 0xAD, 0x11, 0xB5, 0x30, 0xB5, 0x11, 
+0xCE, 0x58, 0xAD, 0x55, 0x8C, 0x72, 0xBD, 0x94, 
+0xD6, 0x75, 0xDE, 0x75, 0xD6, 0x55, 0xDE, 0x96, 
+0xD6, 0x55, 0xCD, 0xF4, 0xD6, 0x55, 0xDE, 0x75, 
+0xD6, 0x34, 0xCD, 0xF4, 0xB5, 0x52, 0xA4, 0xF1, 
+0x7B, 0x8C, 0x94, 0x6F, 0xB5, 0x53, 0xBD, 0x93, 
+0xA4, 0xF1, 0xAD, 0x32, 0xB5, 0x53, 0xAD, 0x11, 
+0xC5, 0xB3, 0xBD, 0x93, 0xBD, 0x73, 0xB5, 0x73, 
+0xAD, 0x52, 0xC5, 0xF5, 0xB5, 0x53, 0xB5, 0x31, 
+0xAC, 0xCF, 0xCD, 0xB3, 0xCD, 0x92, 0xCD, 0xB3, 
+0xCD, 0xD4, 0x52, 0x69, 0x39, 0xE8, 0x4A, 0x49, 
+0x73, 0x6D, 0xA4, 0xF1, 0x94, 0x4E, 0xAC, 0xF0, 
+0xC5, 0x73, 0xC5, 0x73, 0xA4, 0xB0, 0xAD, 0x32, 
+0xBD, 0xD5, 0xC5, 0xD5, 0xC5, 0xF5, 0xCE, 0x36, 
+0xC6, 0x16, 0xBD, 0xD5, 0xAD, 0x32, 0x94, 0x4F, 
+0x73, 0x8D, 0x52, 0x8A, 0x39, 0xE8, 0x41, 0xE9, 
+0x42, 0x09, 0x3A, 0x08, 0x83, 0xEF, 0x9C, 0xD1, 
+0x8C, 0x2F, 0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0x90, 
+0x94, 0x6F, 0x9C, 0xB0, 0xA4, 0xF1, 0xB5, 0x73, 
+0x9C, 0xD0, 0xAD, 0x11, 0xB5, 0x93, 0xBD, 0xB3, 
+0xC5, 0xF5, 0xB5, 0x52, 0xAD, 0x11, 0xB5, 0x52, 
+0xB5, 0x51, 0xAD, 0x10, 0xB5, 0x30, 0xAD, 0x0F, 
+0xA4, 0xCF, 0xAD, 0x30, 0xB5, 0x72, 0xB5, 0x92, 
+0xBD, 0xB3, 0x9C, 0xAF, 0xB5, 0x51, 0xB5, 0x51, 
+0xBD, 0x93, 0xAD, 0x11, 0x8C, 0x0D, 0xB5, 0x53, 
+0xBD, 0x74, 0x9C, 0xB0, 0x94, 0x4F, 0x94, 0x4F, 
+0x83, 0xCD, 0x7B, 0x8C, 0x83, 0xAD, 0x94, 0x4F, 
+0x8C, 0x2E, 0x8C, 0x0E, 0x7B, 0x8C, 0x7B, 0x6C, 
+0x6B, 0x2B, 0x83, 0xEE, 0x9C, 0xB0, 0x9C, 0x90, 
+0x94, 0x70, 0x94, 0x4F, 0x8C, 0x0E, 0x7B, 0xAC, 
+0x7B, 0x8C, 0x8C, 0x2E, 0x83, 0xCD, 0x83, 0xCD, 
+0xA4, 0xD1, 0x9C, 0xB1, 0x8C, 0x0E, 0x94, 0x4F, 
+0x5A, 0xA8, 0x83, 0xCD, 0x8C, 0x2E, 0xA4, 0xD0, 
+0xBD, 0x93, 0xB5, 0x52, 0xAD, 0x32, 0xAD, 0x11, 
+0xA4, 0xF0, 0xB5, 0x32, 0xAC, 0xF1, 0xAD, 0x32, 
+0x9C, 0x6F, 0x9C, 0x6F, 0xA4, 0xD0, 0xB5, 0x32, 
+0xBD, 0x93, 0xAD, 0x31, 0xAC, 0xF1, 0xBD, 0x93, 
+0xBD, 0x93, 0xB5, 0x32, 0xB5, 0x73, 0xBD, 0x73, 
+0xBD, 0x73, 0xBD, 0x94, 0xBD, 0x94, 0xAD, 0x33, 
+0xCE, 0x58, 0xCE, 0x18, 0xC6, 0x38, 0xDE, 0xDB, 
+0xBD, 0xB6, 0xA4, 0xF2, 0xA4, 0xD1, 0x9C, 0xD1, 
+0xAD, 0x33, 0xC5, 0xD6, 0x8C, 0x50, 0x41, 0xE8, 
+0x39, 0xE8, 0x63, 0x2D, 0xB5, 0x75, 0xAD, 0x12, 
+0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x90, 0x9C, 0x90, 
+0x9C, 0x8F, 0x9C, 0x8F, 0x9C, 0x6E, 0x94, 0x4E, 
+0xA4, 0xD1, 0xAC, 0xF1, 0x9C, 0x90, 0x94, 0x6F, 
+0xA5, 0x75, 0xA5, 0x35, 0x9D, 0x14, 0x94, 0xB2, 
+0x9C, 0x90, 0x8C, 0x0D, 0x9C, 0x8F, 0xA4, 0xD0, 
+0x94, 0x2D, 0xB5, 0x31, 0xB5, 0x31, 0xB5, 0x51, 
+0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x52, 0xBD, 0x92, 
+0xC5, 0xB3, 0xBD, 0x72, 0xAC, 0xCF, 0xA4, 0x8E, 
+0xA4, 0xD0, 0x9C, 0xB0, 0x8C, 0x4F, 0x94, 0x6F, 
+0x9C, 0xB1, 0x9C, 0xD0, 0x94, 0x4E, 0xA4, 0xD1, 
+0xB5, 0x73, 0xAD, 0x11, 0xA4, 0xF0, 0x94, 0x6F, 
+0x9C, 0x8F, 0xAC, 0xF1, 0xAD, 0x31, 0xBD, 0x93, 
+0xB5, 0x72, 0xBD, 0x73, 0xAD, 0x11, 0xB5, 0x73, 
+0xBD, 0x73, 0xA4, 0xD0, 0x9C, 0x6D, 0xAC, 0xAE, 
+0xC5, 0xB2, 0xAC, 0xEF, 0xC5, 0x92, 0xBD, 0x31, 
+0xB5, 0x10, 0xAC, 0xF0, 0xA4, 0x8E, 0xA4, 0x8E, 
+0x94, 0x0C, 0x94, 0x0D, 0x94, 0x2D, 0x94, 0x2D, 
+0x8B, 0xCC, 0x83, 0xAC, 0x94, 0x2E, 0x9C, 0x6E, 
+0x9C, 0x8E, 0xAC, 0xF0, 0xAC, 0xF0, 0x9C, 0x8E, 
+0x8B, 0xEC, 0x93, 0xEC, 0x94, 0x0C, 0xA4, 0x6D, 
+0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x10, 0xA4, 0xAF, 
+0x83, 0x8B, 0x7B, 0x6A, 0x94, 0x0C, 0x94, 0x0C, 
+0x94, 0x2D, 0x9C, 0x8F, 0x7B, 0xAD, 0x4A, 0x28, 
+0x39, 0xE7, 0x31, 0x85, 0x41, 0xE7, 0x41, 0xE7, 
+0x41, 0xE7, 0x4A, 0x48, 0x6B, 0x2C, 0x83, 0xEF, 
+0x7B, 0xEF, 0x9C, 0xD3, 0x8C, 0x71, 0x9C, 0xD3, 
+0xA4, 0xF3, 0x5A, 0xAB, 0x6B, 0x2D, 0x6B, 0x4D, 
+0x31, 0x66, 0x42, 0x28, 0xAD, 0x13, 0xAD, 0x12, 
+0xAC, 0xF0, 0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xAE, 
+0x9C, 0x4D, 0x9C, 0x2D, 0x93, 0xEC, 0x8B, 0xED, 
+0x9C, 0x4E, 0xA4, 0x8F, 0x9C, 0x6E, 0xB5, 0x11, 
+0xC5, 0x92, 0xC5, 0x71, 0xC5, 0x71, 0xB4, 0xF0, 
+0xA4, 0x8F, 0x6B, 0x0B, 0x5A, 0xEB, 0x39, 0xE7, 
+0x31, 0x86, 0x31, 0xA6, 0x42, 0x07, 0x4A, 0x49, 
+0x63, 0x0C, 0x39, 0xE7, 0x31, 0x86, 0x5A, 0xAB, 
+0x6B, 0x4D, 0x6B, 0x6D, 0x94, 0xD2, 0xA5, 0x34, 
+0x73, 0x6E, 0x52, 0x8A, 0x42, 0x29, 0x94, 0x92, 
+0x8C, 0x30, 0xBD, 0x94, 0xB5, 0x31, 0xA4, 0xD0, 
+0xCE, 0x38, 0xAD, 0x35, 0x94, 0x92, 0xB5, 0x73, 
+0xCD, 0xF4, 0xC5, 0xD3, 0xBD, 0x92, 0xCD, 0xF3, 
+0xD6, 0x34, 0xD6, 0x55, 0xE6, 0xB6, 0xDE, 0x96, 
+0xDE, 0x75, 0xDE, 0x96, 0xD6, 0x15, 0xB5, 0x31, 
+0xAD, 0x31, 0xB5, 0x32, 0xCD, 0xF4, 0xD6, 0x35, 
+0xCE, 0x36, 0xBD, 0x93, 0xBD, 0x94, 0xB5, 0x52, 
+0xC5, 0xB3, 0xBD, 0x92, 0xBD, 0xB3, 0xBD, 0xB4, 
+0xC5, 0xD4, 0xBD, 0xD4, 0xB5, 0x72, 0xC5, 0xB3, 
+0xCD, 0xD3, 0xCD, 0x92, 0xCD, 0xB3, 0xCD, 0xB3, 
+0xC5, 0x93, 0x83, 0xCE, 0x42, 0x08, 0x42, 0x09, 
+0x42, 0x08, 0x4A, 0x49, 0x73, 0x6C, 0xA4, 0xB0, 
+0xBD, 0x52, 0xBD, 0x51, 0xA4, 0xF0, 0x9C, 0x8F, 
+0xAD, 0x32, 0xA4, 0xF2, 0x9C, 0xD1, 0x94, 0x90, 
+0x7B, 0xCE, 0x52, 0x69, 0x39, 0xE7, 0x39, 0xC7, 
+0x31, 0x87, 0x29, 0x46, 0x29, 0x46, 0x31, 0x87, 
+0x39, 0xA7, 0x39, 0xC7, 0x7B, 0xCE, 0x8C, 0x6F, 
+0x8C, 0x2E, 0x8C, 0x2E, 0x8C, 0x2E, 0x8C, 0x2E, 
+0x8C, 0x4E, 0x9C, 0xB0, 0xA5, 0x11, 0xB5, 0x73, 
+0xA4, 0xF1, 0xB5, 0x52, 0xC5, 0xF4, 0xC5, 0xD4, 
+0xBD, 0xD4, 0xB5, 0x52, 0xB5, 0x52, 0xAD, 0x32, 
+0xBD, 0xB3, 0xB5, 0x71, 0xBD, 0x71, 0xAD, 0x10, 
+0xB5, 0x71, 0xB5, 0x72, 0xB5, 0x52, 0xC5, 0xD4, 
+0xCE, 0x15, 0xAD, 0x31, 0xB5, 0x71, 0xB5, 0x51, 
+0xC5, 0xD3, 0xBD, 0xB3, 0xA4, 0xF0, 0xBD, 0x94, 
+0xBD, 0x73, 0x9C, 0xB0, 0xBD, 0x94, 0xBD, 0xB4, 
+0xB5, 0x53, 0xAD, 0x33, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xAD, 0x53, 0xAD, 0x52, 0xA4, 0xF1, 0x8C, 0x2F, 
+0x83, 0xCE, 0xA4, 0xF1, 0xAD, 0x32, 0xBD, 0x93, 
+0xAD, 0x32, 0x9C, 0x90, 0x9C, 0xB0, 0x94, 0x6F, 
+0x6B, 0x2A, 0x8C, 0x2E, 0x73, 0x6B, 0x9C, 0xB1, 
+0xAD, 0x53, 0x94, 0x70, 0xA4, 0xD1, 0xA4, 0xD1, 
+0x6B, 0x2B, 0x83, 0xCD, 0x7B, 0x8B, 0x7B, 0xAC, 
+0x8C, 0x0D, 0x83, 0xED, 0x83, 0xEC, 0x83, 0xCC, 
+0x83, 0xCC, 0x83, 0xED, 0x8C, 0x2E, 0xA4, 0xF0, 
+0x8C, 0x0D, 0x83, 0xCD, 0x8B, 0xED, 0x8C, 0x0D, 
+0x83, 0xCC, 0x83, 0xCC, 0xAC, 0xF0, 0xBD, 0x72, 
+0xA4, 0xB0, 0xA4, 0xB0, 0xA4, 0xB0, 0x94, 0x4E, 
+0xA4, 0xF1, 0xAD, 0x32, 0xBD, 0x73, 0xB5, 0x54, 
+0xC6, 0x18, 0xC5, 0xF8, 0xE7, 0x1C, 0xE7, 0x3C, 
+0xC6, 0x38, 0xBD, 0xD6, 0xB5, 0x54, 0xB5, 0x73, 
+0xB5, 0x74, 0xB5, 0x74, 0x94, 0x91, 0x52, 0x8A, 
+0x5A, 0xCB, 0x73, 0xAF, 0xAD, 0x54, 0xB5, 0x74, 
+0xBD, 0x73, 0xB5, 0x52, 0xB5, 0x53, 0xB5, 0x53, 
+0xB5, 0x53, 0xB5, 0x32, 0xB5, 0x52, 0xB5, 0x52, 
+0xB5, 0x73, 0xBD, 0x73, 0xB5, 0x53, 0xB5, 0x52, 
+0xB5, 0xD5, 0xA5, 0x55, 0x9D, 0x14, 0x94, 0xD2, 
+0x94, 0x70, 0x7B, 0x6B, 0x9C, 0x8F, 0xA4, 0xAF, 
+0xA4, 0xF0, 0xB5, 0x31, 0x8C, 0x0D, 0xA4, 0xCF, 
+0xBD, 0x93, 0xB5, 0x52, 0xAD, 0x31, 0xBD, 0x72, 
+0xBD, 0x93, 0xC5, 0x93, 0xAC, 0xCF, 0xA4, 0x8E, 
+0xB5, 0x31, 0xA5, 0x11, 0x9C, 0xB0, 0x94, 0x70, 
+0xA4, 0xD1, 0x9C, 0xB0, 0x94, 0x8F, 0xBD, 0x93, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x52, 0xA4, 0xD0, 
+0x9C, 0x8F, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x31, 
+0x9C, 0xAF, 0xAD, 0x31, 0xC5, 0xD4, 0xBD, 0x93, 
+0xC5, 0xD4, 0xAD, 0x11, 0xA4, 0x8E, 0xAC, 0xCF, 
+0xCD, 0xD3, 0xCD, 0xD3, 0xCD, 0xD3, 0xCD, 0xB2, 
+0xCD, 0xD3, 0xBD, 0x72, 0xBD, 0x51, 0xB5, 0x30, 
+0xA4, 0xCF, 0xA4, 0xAF, 0xAC, 0xF0, 0xBD, 0x51, 
+0xBD, 0x72, 0xBD, 0x52, 0xB5, 0x11, 0xA4, 0xAF, 
+0xB5, 0x10, 0xB5, 0x31, 0xBD, 0x51, 0xB5, 0x30, 
+0xBD, 0x51, 0xA4, 0x6E, 0x83, 0x8A, 0x9C, 0x4D, 
+0xAC, 0xD0, 0xAC, 0xCF, 0xAC, 0xCF, 0xAC, 0xF0, 
+0x94, 0x0D, 0x9C, 0x4D, 0x9C, 0x4E, 0xA4, 0x6E, 
+0x94, 0x0D, 0xA4, 0x8F, 0x94, 0x2F, 0x52, 0x68, 
+0x39, 0xA6, 0x29, 0x44, 0x41, 0xE7, 0x52, 0x69, 
+0x5A, 0xAA, 0x52, 0x8A, 0x62, 0xEB, 0x73, 0x8D, 
+0x94, 0x92, 0x94, 0xB2, 0x83, 0xF0, 0xA5, 0x14, 
+0xA4, 0xF4, 0x8C, 0x51, 0x8C, 0x52, 0x84, 0x10, 
+0x4A, 0x49, 0x29, 0x25, 0x52, 0x8A, 0x5A, 0xAA, 
+0x73, 0x2B, 0x6B, 0x0A, 0x73, 0x2A, 0x73, 0x4B, 
+0x7B, 0x6B, 0x73, 0x4B, 0x6B, 0x0A, 0x7B, 0x6B, 
+0x94, 0x0D, 0xA4, 0x6E, 0xA4, 0x8E, 0xA4, 0xAF, 
+0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x8E, 0x9C, 0x4D, 
+0x94, 0x0D, 0x6B, 0x2B, 0x42, 0x07, 0x21, 0x24, 
+0x19, 0x04, 0x21, 0x24, 0x39, 0xE7, 0x4A, 0x48, 
+0x3A, 0x07, 0x29, 0x65, 0x39, 0xE7, 0x5A, 0xCB, 
+0x73, 0x8E, 0x8C, 0x71, 0xC6, 0x38, 0x9C, 0xD2, 
+0x63, 0x2D, 0x8C, 0x72, 0x73, 0x8F, 0x63, 0x0C, 
+0x84, 0x10, 0x8C, 0x30, 0xCD, 0xF6, 0xBD, 0x95, 
+0xC6, 0x18, 0xA5, 0x35, 0x94, 0x71, 0x94, 0x4F, 
+0x9C, 0x4E, 0xA4, 0x6E, 0xA4, 0x8E, 0xA4, 0x6D, 
+0x9C, 0x6D, 0x9C, 0x2C, 0x93, 0xEC, 0x94, 0x0D, 
+0xA4, 0x8E, 0xAC, 0xCF, 0xBD, 0x31, 0xAC, 0xD0, 
+0xA4, 0xD0, 0xB5, 0x52, 0xAD, 0x11, 0xAC, 0xF0, 
+0xCD, 0xF5, 0xBD, 0x73, 0xB5, 0x73, 0x9C, 0x8F, 
+0x9C, 0xB0, 0xB5, 0x52, 0xAD, 0x11, 0xBD, 0xB4, 
+0xB5, 0x73, 0xC5, 0xF5, 0xBD, 0x72, 0xDE, 0x55, 
+0xD5, 0xF4, 0xCD, 0xB3, 0xE6, 0x55, 0xDE, 0x55, 
+0xD6, 0x14, 0xB5, 0x53, 0x52, 0x69, 0x39, 0xC8, 
+0x39, 0xC7, 0x41, 0xE8, 0x39, 0xC8, 0x41, 0xC7, 
+0x5A, 0x89, 0x5A, 0x88, 0x4A, 0x07, 0x39, 0xC6, 
+0x39, 0x86, 0x31, 0x65, 0x29, 0x45, 0x29, 0x45, 
+0x29, 0x66, 0x31, 0x87, 0x29, 0x66, 0x29, 0x25, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x29, 0x26, 
+0x29, 0x46, 0x31, 0x86, 0x52, 0x89, 0x7B, 0xAD, 
+0x8C, 0x0E, 0x94, 0x4F, 0x7B, 0xCC, 0x84, 0x0D, 
+0xA4, 0xF1, 0xAD, 0x32, 0x8C, 0x2E, 0xBD, 0x94, 
+0xA4, 0xF1, 0xAD, 0x52, 0xC5, 0xF4, 0xBD, 0xD4, 
+0xC6, 0x15, 0xC5, 0xD4, 0xBD, 0x93, 0xB5, 0x52, 
+0xBD, 0xB3, 0xB5, 0x92, 0xBD, 0x92, 0xBD, 0x92, 
+0xC5, 0xD3, 0xC5, 0xF4, 0xCE, 0x15, 0xBD, 0x93, 
+0xC5, 0xF4, 0xBD, 0x93, 0xBD, 0x92, 0xBD, 0xB3, 
+0xB5, 0x72, 0xC5, 0xF4, 0xA4, 0xF0, 0xC5, 0xB4, 
+0xB5, 0x53, 0xAD, 0x11, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xCE, 0x15, 0xC6, 0x15, 0xAD, 0x32, 0xAD, 0x52, 
+0xC5, 0xF5, 0xAD, 0x32, 0xBD, 0xB4, 0x94, 0x4F, 
+0xAD, 0x12, 0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x93, 
+0xBD, 0xB4, 0xA4, 0xD1, 0xAD, 0x32, 0xAD, 0x32, 
+0x7B, 0x8C, 0x8C, 0x2E, 0x94, 0x70, 0x94, 0x6F, 
+0xAD, 0x33, 0x9C, 0x90, 0x83, 0xEE, 0xB5, 0x53, 
+0x7B, 0xCD, 0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0x90, 
+0xA4, 0xF1, 0x8C, 0x2E, 0x8C, 0x2E, 0x94, 0x8F, 
+0x94, 0x8F, 0x7B, 0xCD, 0x8C, 0x0E, 0x94, 0x6F, 
+0x9C, 0x8F, 0xA4, 0xF1, 0x94, 0x4E, 0x83, 0xED, 
+0x9C, 0x8F, 0x9C, 0xB0, 0xAC, 0xF0, 0xC5, 0x93, 
+0xA4, 0xD0, 0xBD, 0x94, 0xB5, 0x53, 0x94, 0x6F, 
+0xAD, 0x53, 0xB5, 0x94, 0xCE, 0x36, 0xBD, 0xD6, 
+0xBD, 0xD7, 0xD6, 0xBB, 0xCE, 0x7A, 0xB5, 0x56, 
+0xB5, 0x76, 0xEF, 0x3C, 0xCE, 0x37, 0xCE, 0x36, 
+0xCD, 0xF6, 0xC5, 0xD5, 0xAD, 0x53, 0x73, 0x6D, 
+0x63, 0x2D, 0x7B, 0xAF, 0x8C, 0x30, 0xB5, 0x94, 
+0x94, 0x4F, 0xAC, 0xF1, 0xA4, 0xB0, 0xA4, 0xB0, 
+0xBD, 0x93, 0xAD, 0x12, 0xAD, 0x11, 0x9C, 0x6F, 
+0x8C, 0x0D, 0xB5, 0x32, 0xBD, 0x73, 0xAD, 0x11, 
+0x95, 0x2F, 0xA5, 0x94, 0x9D, 0x34, 0x94, 0xB2, 
+0x94, 0x4F, 0x83, 0xAB, 0xA4, 0x8F, 0xA4, 0xAF, 
+0xB5, 0x52, 0xB5, 0x32, 0x8C, 0x0D, 0x94, 0x2D, 
+0xB5, 0x52, 0xB5, 0x31, 0xAD, 0x11, 0xBD, 0x72, 
+0xC5, 0x93, 0xC5, 0x92, 0xA4, 0x6E, 0xA4, 0x8E, 
+0xAD, 0x31, 0xB5, 0x73, 0xAD, 0x12, 0x94, 0x70, 
+0x94, 0x70, 0x9C, 0x90, 0xAD, 0x32, 0xB5, 0x73, 
+0xB5, 0x72, 0xCD, 0xF5, 0xB5, 0x52, 0xB5, 0x32, 
+0xAD, 0x12, 0xA4, 0xF1, 0x9C, 0xB0, 0x9C, 0xD0, 
+0x9C, 0x8F, 0xB5, 0x52, 0xAD, 0x11, 0xBD, 0xB4, 
+0xB5, 0x72, 0xA4, 0x8F, 0xAC, 0xAE, 0xAC, 0xAE, 
+0xDE, 0x35, 0xCD, 0xD3, 0xCD, 0xD3, 0xCD, 0xD2, 
+0xCD, 0xF3, 0xD5, 0xF3, 0xC5, 0xB2, 0xC5, 0x71, 
+0xC5, 0xB2, 0xD5, 0xF3, 0xCD, 0xB2, 0xD6, 0x34, 
+0xCD, 0xD3, 0xCD, 0xB3, 0xCD, 0xB3, 0xC5, 0x92, 
+0xCD, 0xD2, 0xCD, 0xB2, 0xCD, 0x92, 0xCD, 0xB2, 
+0xC5, 0x71, 0xBD, 0x31, 0x9C, 0x2C, 0xA4, 0x6D, 
+0xC5, 0x72, 0xAC, 0xCF, 0x93, 0xEB, 0xB5, 0x30, 
+0xBD, 0x51, 0xA4, 0x8E, 0x9C, 0x2D, 0x94, 0x0C, 
+0xA4, 0xCF, 0x8B, 0xED, 0x7B, 0x8C, 0x52, 0x89, 
+0x31, 0xA6, 0x29, 0x44, 0x42, 0x07, 0x52, 0x89, 
+0x4A, 0x28, 0x42, 0x07, 0x5A, 0xAA, 0x6B, 0x4C, 
+0x84, 0x10, 0x8C, 0x71, 0x8C, 0x31, 0x94, 0x72, 
+0xAD, 0x35, 0xB5, 0x97, 0xA4, 0xF4, 0x94, 0x71, 
+0x6B, 0x4D, 0x42, 0x08, 0x52, 0x69, 0x4A, 0x28, 
+0x7B, 0xAD, 0x73, 0x8D, 0x5A, 0xCA, 0x5A, 0xCA, 
+0x52, 0xA9, 0x52, 0x89, 0x52, 0x89, 0x7B, 0xAC, 
+0x8C, 0x0D, 0x8C, 0x0D, 0x6B, 0x2A, 0x5A, 0x88, 
+0x52, 0x68, 0x52, 0x48, 0x52, 0x89, 0x52, 0x88, 
+0x52, 0x48, 0x52, 0x69, 0x62, 0xEB, 0x5A, 0xCA, 
+0x39, 0xE7, 0x29, 0x44, 0x39, 0xC7, 0x39, 0xE7, 
+0x29, 0x65, 0x42, 0x28, 0x4A, 0x48, 0x52, 0x69, 
+0x63, 0x2C, 0x8C, 0x50, 0x8C, 0x50, 0x8C, 0x71, 
+0x8C, 0x51, 0x9D, 0x15, 0xA5, 0x35, 0xAD, 0x56, 
+0xAD, 0x35, 0xBD, 0xB6, 0xCE, 0x17, 0xC5, 0xD7, 
+0xC6, 0x38, 0xAD, 0x35, 0x8C, 0x71, 0x9C, 0x6F, 
+0xA4, 0xAF, 0x94, 0x0C, 0xA4, 0x8E, 0xA4, 0x8E, 
+0x9C, 0x6D, 0x9C, 0x4D, 0x9C, 0x6D, 0xA4, 0x8E, 
+0xB4, 0xF0, 0xBD, 0x51, 0xBD, 0x50, 0xC5, 0x92, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xD4, 0xB5, 0x52, 
+0xBD, 0x72, 0xC5, 0xD4, 0xC5, 0xD5, 0xBD, 0x94, 
+0xBD, 0xB4, 0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x12, 
+0xAC, 0xF1, 0xAD, 0x11, 0xA4, 0xD1, 0xA4, 0xF1, 
+0xA4, 0xD0, 0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x90, 
+0x9C, 0x6F, 0x8C, 0x2F, 0x62, 0xEB, 0x29, 0x46, 
+0x31, 0x87, 0x31, 0x87, 0x39, 0xA7, 0x29, 0x45, 
+0x21, 0x04, 0x21, 0x04, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x25, 0x29, 0x25, 0x21, 0x25, 0x20, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x29, 0x26, 0x31, 0x66, 0x42, 0x08, 
+0x6B, 0x2B, 0x8C, 0x2E, 0x84, 0x0D, 0x9C, 0xB0, 
+0xB5, 0x73, 0xAD, 0x52, 0x8C, 0x4E, 0xBD, 0xD4, 
+0xA4, 0xD0, 0xBD, 0xB3, 0xC5, 0xF4, 0xBD, 0xD4, 
+0xCE, 0x35, 0xC5, 0xF4, 0xC6, 0x15, 0xBD, 0x93, 
+0xC5, 0xF4, 0xBD, 0xB2, 0xC5, 0xB3, 0xC5, 0xD3, 
+0xCE, 0x14, 0x9C, 0xD0, 0xAD, 0x32, 0xB5, 0x53, 
+0xC5, 0xF4, 0xB5, 0x93, 0xB5, 0x72, 0xCE, 0x34, 
+0xB5, 0x72, 0xC5, 0xF4, 0xA4, 0xD0, 0xC5, 0xB5, 
+0xB5, 0x53, 0xA4, 0xF1, 0xC5, 0xD4, 0xCE, 0x36, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xB5, 0x73, 0xC5, 0xF5, 
+0xCE, 0x16, 0xC5, 0xF5, 0xC5, 0xF5, 0xAD, 0x12, 
+0xBD, 0xB4, 0xC5, 0xF5, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x93, 0xAD, 0x52, 0xBD, 0x93, 0xBD, 0x94, 
+0x7B, 0xAD, 0x9C, 0x90, 0x9C, 0xB1, 0x9C, 0x90, 
+0xAD, 0x32, 0x94, 0x90, 0x52, 0x68, 0x8C, 0x2E, 
+0x5A, 0xC9, 0x5A, 0xC9, 0x62, 0xEA, 0x62, 0xEA, 
+0x94, 0x6F, 0xA4, 0xD1, 0x94, 0x8F, 0xA4, 0xD1, 
+0x9C, 0x90, 0x83, 0xED, 0x9C, 0xB0, 0xAD, 0x32, 
+0xAD, 0x32, 0xB5, 0x52, 0xA4, 0xD0, 0x8C, 0x0E, 
+0xAD, 0x32, 0xA4, 0xD1, 0x9C, 0x6F, 0xB5, 0x52, 
+0xAD, 0x11, 0xB5, 0x53, 0xB5, 0x32, 0xA4, 0xF1, 
+0xB5, 0x94, 0xB5, 0x94, 0xC5, 0xF6, 0xCE, 0x38, 
+0xD6, 0x9A, 0xC6, 0x39, 0x8C, 0x72, 0xBD, 0xF8, 
+0xE6, 0xFC, 0xD6, 0xBA, 0xBD, 0xF7, 0x9C, 0xD2, 
+0x9C, 0xB1, 0xCE, 0x36, 0xC6, 0x16, 0x7B, 0xCE, 
+0x62, 0xEB, 0x73, 0x8E, 0x8C, 0x30, 0xBD, 0xD6, 
+0xAD, 0x12, 0xB5, 0x52, 0x9C, 0x8F, 0xAD, 0x11, 
+0xBD, 0xB4, 0xA4, 0xF1, 0xA4, 0xF0, 0xAD, 0x10, 
+0xA4, 0xD0, 0xD6, 0x56, 0xD6, 0x35, 0xBD, 0xB3, 
+0xA5, 0xB2, 0x9D, 0x54, 0x9D, 0x14, 0x94, 0xB2, 
+0x7B, 0xAC, 0x7B, 0x6A, 0x83, 0xAC, 0x94, 0x4E, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAD, 0x11, 0xA4, 0xD0, 
+0xAD, 0x11, 0xBD, 0x72, 0xBD, 0x73, 0xC5, 0xD4, 
+0xBD, 0x72, 0xCD, 0xD3, 0xAC, 0xCF, 0xAC, 0xCF, 
+0x83, 0xAB, 0xB5, 0x52, 0xA5, 0x11, 0x8C, 0x0E, 
+0x94, 0x90, 0xAD, 0x12, 0xA4, 0xD1, 0x9C, 0xAF, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xA4, 0xD0, 0xC5, 0xF5, 
+0xBD, 0x93, 0xAD, 0x32, 0xA4, 0xF1, 0xA4, 0xF1, 
+0x9C, 0xD0, 0xBD, 0x94, 0xB5, 0x73, 0xBD, 0x93, 
+0xC5, 0xB4, 0x94, 0x2D, 0xBD, 0x30, 0xAC, 0xCE, 
+0xC5, 0x92, 0xBD, 0x10, 0xCD, 0xD2, 0xCD, 0xB2, 
+0xCD, 0xD2, 0xD5, 0xF3, 0xD6, 0x13, 0xCD, 0xD2, 
+0xCD, 0xD2, 0xD5, 0xD3, 0xCD, 0xB2, 0xD6, 0x13, 
+0xCD, 0xB2, 0xD5, 0xF3, 0xD5, 0xF3, 0xD5, 0xF3, 
+0xCD, 0xB2, 0xCD, 0x92, 0xCD, 0x91, 0xCD, 0x92, 
+0xC5, 0x51, 0xC5, 0x30, 0xAC, 0x8E, 0xAC, 0x8D, 
+0xBD, 0x51, 0xB5, 0x10, 0xBD, 0x31, 0xBD, 0x51, 
+0x94, 0x2D, 0xBD, 0x31, 0xAC, 0xAF, 0xA4, 0x8F, 
+0xAC, 0xF0, 0x94, 0x4E, 0x94, 0x6F, 0x8C, 0x0E, 
+0x52, 0x48, 0x31, 0xA6, 0x39, 0xC6, 0x31, 0x65, 
+0x39, 0xC6, 0x4A, 0x48, 0x52, 0x89, 0x52, 0x89, 
+0x6B, 0x4D, 0x73, 0xAE, 0x94, 0x71, 0x94, 0x92, 
+0xA5, 0x35, 0xA4, 0xF4, 0x7B, 0x8E, 0x83, 0xCF, 
+0x73, 0x8E, 0x62, 0xEB, 0x4A, 0x69, 0x4A, 0x49, 
+0x7B, 0xAE, 0xAD, 0x13, 0x84, 0x0F, 0x73, 0x8D, 
+0x6B, 0x4C, 0x6B, 0x6D, 0x73, 0x6D, 0x8C, 0x4F, 
+0x94, 0x4E, 0x8C, 0x0D, 0x83, 0xCD, 0x7B, 0xAD, 
+0x73, 0xAD, 0x73, 0xAD, 0x83, 0xEE, 0x73, 0x6C, 
+0x6B, 0x4C, 0x73, 0x6C, 0x8C, 0x2F, 0x94, 0x90, 
+0x8C, 0x4F, 0x4A, 0x68, 0x31, 0xA6, 0x39, 0xE7, 
+0x31, 0x85, 0x39, 0xE7, 0x42, 0x07, 0x4A, 0x49, 
+0x5A, 0xCA, 0x5A, 0xCA, 0x6B, 0x6D, 0x7B, 0xEF, 
+0x94, 0xB3, 0x9C, 0xD4, 0xAD, 0x55, 0x8C, 0x52, 
+0x7B, 0xAF, 0x73, 0x6E, 0xA5, 0x14, 0xBD, 0xD7, 
+0xCE, 0x39, 0xB5, 0x96, 0x94, 0x72, 0x8C, 0x0E, 
+0x9C, 0x8F, 0x8B, 0xEC, 0xAD, 0x10, 0x7B, 0x8B, 
+0x6B, 0x29, 0x83, 0xEC, 0x8C, 0x0C, 0x8B, 0xED, 
+0x8B, 0xEC, 0xAC, 0xCF, 0xB5, 0x30, 0xBD, 0x52, 
+0xC5, 0xB4, 0x94, 0x4F, 0x94, 0x4E, 0x9C, 0xB0, 
+0xA4, 0xF0, 0xA4, 0xD0, 0xA4, 0xF1, 0xA4, 0xD1, 
+0xA4, 0xD1, 0xA4, 0xB0, 0xA4, 0xD1, 0xAC, 0xF1, 
+0xAC, 0xF1, 0xA4, 0xF1, 0xAD, 0x32, 0xAD, 0x12, 
+0xAD, 0x32, 0xAD, 0x12, 0xAD, 0x32, 0xB5, 0x33, 
+0xB5, 0x53, 0xAC, 0xF2, 0x83, 0xCE, 0x31, 0x66, 
+0x29, 0x46, 0x29, 0x66, 0x29, 0x66, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x20, 0xE5, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x25, 0x29, 0x45, 
+0x4A, 0x49, 0x83, 0xEE, 0x84, 0x0D, 0x8C, 0x2E, 
+0x94, 0x6F, 0x94, 0x6F, 0x8C, 0x0E, 0xAD, 0x32, 
+0x8C, 0x2E, 0xA4, 0xD1, 0xB5, 0x73, 0xA4, 0xF1, 
+0x94, 0x6F, 0x94, 0x6F, 0xC5, 0xF5, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD3, 0xBD, 0xB3, 0xBD, 0xB2, 
+0xBD, 0xB3, 0x8C, 0x2F, 0xAD, 0x74, 0xB5, 0x94, 
+0xCE, 0x35, 0xC5, 0xD4, 0xBD, 0xB3, 0xBD, 0x93, 
+0xBD, 0x93, 0xB5, 0x72, 0xA4, 0xF1, 0xC5, 0xD4, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xB5, 0x73, 0xD6, 0x56, 
+0xC5, 0xD5, 0xBD, 0xB4, 0xCE, 0x36, 0xCE, 0x36, 
+0xC5, 0xF5, 0xCE, 0x36, 0xB5, 0x73, 0xAD, 0x11, 
+0xBD, 0xB4, 0xCE, 0x15, 0xBD, 0xB3, 0xCE, 0x15, 
+0xDE, 0x97, 0xBD, 0xB4, 0xBD, 0xB4, 0xC5, 0xD5, 
+0x83, 0xEE, 0x9C, 0xB0, 0x9C, 0x90, 0xA4, 0xD1, 
+0xAD, 0x32, 0x8C, 0x2E, 0x5A, 0xC9, 0xAD, 0x33, 
+0xA4, 0xF1, 0x52, 0x89, 0x4A, 0x48, 0x73, 0x8D, 
+0x9C, 0xB0, 0x9C, 0xD1, 0xA4, 0xF1, 0x94, 0x8F, 
+0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x32, 0xCE, 0x15, 
+0xB5, 0x53, 0xCE, 0x36, 0xBD, 0x94, 0xA4, 0xD1, 
+0xBD, 0xB4, 0x6B, 0x2B, 0x4A, 0x27, 0x6B, 0x2B, 
+0x9C, 0xB0, 0xB5, 0x32, 0xAD, 0x12, 0xA4, 0xF1, 
+0xBD, 0xD4, 0x9C, 0xB1, 0x73, 0x8E, 0xA5, 0x14, 
+0xCE, 0x3A, 0xCE, 0x7A, 0xCE, 0x7A, 0xDE, 0xDB, 
+0xCE, 0x7A, 0x8C, 0x31, 0xAD, 0x35, 0xB5, 0x96, 
+0xBD, 0xD6, 0xCE, 0x37, 0xB5, 0x74, 0x73, 0x8D, 
+0x4A, 0x49, 0x52, 0x8A, 0x7B, 0xCF, 0x94, 0x91, 
+0xAD, 0x12, 0xAD, 0x32, 0x9C, 0xB0, 0xB5, 0x53, 
+0xC5, 0xD4, 0xCE, 0x35, 0xCE, 0x15, 0xC5, 0xD4, 
+0xC5, 0xF4, 0xD6, 0x76, 0xCE, 0x55, 0xBD, 0xB3, 
+0xA5, 0x93, 0xA5, 0x54, 0x9C, 0xF3, 0x94, 0x71, 
+0x62, 0xC9, 0x6A, 0xE9, 0x73, 0x2A, 0x7B, 0x6B, 
+0x8B, 0xCB, 0x94, 0x2C, 0x94, 0x2D, 0x9C, 0x4E, 
+0xA4, 0x8E, 0xA4, 0xCF, 0x9C, 0x4D, 0xAC, 0xCF, 
+0x9C, 0x6E, 0xAC, 0xCF, 0xB4, 0xEF, 0xB5, 0x10, 
+0x94, 0x2D, 0x94, 0x4E, 0x9C, 0xB0, 0x84, 0x0E, 
+0x8C, 0x2E, 0x9C, 0xB0, 0x9C, 0xB0, 0xBD, 0xD4, 
+0xD6, 0x56, 0xCE, 0x35, 0xC5, 0xD4, 0xBD, 0xB3, 
+0xBD, 0xD4, 0xBD, 0xB3, 0xAD, 0x32, 0xAD, 0x11, 
+0xAD, 0x32, 0xBD, 0xD4, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xC5, 0xB4, 0x73, 0x2A, 0xAC, 0xCF, 0xA4, 0x6D, 
+0xC5, 0x70, 0xB5, 0x0F, 0xCD, 0x92, 0xAC, 0x8E, 
+0xAC, 0x8E, 0xB5, 0x0F, 0xBD, 0x30, 0xCD, 0xB2, 
+0xCD, 0xB2, 0xCD, 0x92, 0xC5, 0x71, 0xCD, 0x92, 
+0xC5, 0x71, 0xC5, 0x51, 0xBD, 0x30, 0xBD, 0x30, 
+0xC5, 0x71, 0xC5, 0x30, 0xC5, 0x30, 0xBD, 0x10, 
+0xC5, 0x30, 0xBD, 0x10, 0xBC, 0xEF, 0xAC, 0xAE, 
+0x94, 0x0C, 0xC5, 0x91, 0xCD, 0xD3, 0xBD, 0x71, 
+0xBD, 0x31, 0xCD, 0xB2, 0xBD, 0x51, 0xBD, 0x51, 
+0xB5, 0x11, 0xB5, 0x11, 0xAD, 0x10, 0xC5, 0xB3, 
+0x8B, 0xEE, 0x52, 0x48, 0x41, 0xE7, 0x31, 0xA5, 
+0x39, 0xC6, 0x39, 0xC6, 0x41, 0xE7, 0x52, 0x69, 
+0x62, 0xEB, 0x7B, 0xEF, 0x84, 0x30, 0x8C, 0x71, 
+0x8C, 0x31, 0xAD, 0x14, 0x94, 0x51, 0x73, 0x6D, 
+0x73, 0x6D, 0x63, 0x0C, 0x4A, 0x49, 0x39, 0xE7, 
+0x7B, 0x8D, 0xAD, 0x33, 0xAD, 0x34, 0x7B, 0xCE, 
+0x73, 0xAE, 0x7B, 0xCE, 0x6B, 0x6D, 0x94, 0x6F, 
+0x94, 0x6F, 0x9C, 0xB0, 0x94, 0x90, 0x94, 0x70, 
+0x8C, 0x70, 0x8C, 0x4F, 0x83, 0xCE, 0x7B, 0xCE, 
+0x7B, 0xCE, 0x73, 0x8C, 0x73, 0x8C, 0x7B, 0xCD, 
+0x7B, 0xEE, 0x63, 0x2B, 0x63, 0x0B, 0x42, 0x07, 
+0x42, 0x07, 0x4A, 0x28, 0x42, 0x07, 0x42, 0x28, 
+0x52, 0xAA, 0x5A, 0xEB, 0x63, 0x0C, 0x8C, 0x71, 
+0x94, 0xB3, 0x94, 0x92, 0x73, 0xAF, 0x63, 0x0C, 
+0x84, 0x10, 0x52, 0x6A, 0x63, 0x0D, 0xB5, 0xB7, 
+0xD6, 0xBB, 0xCE, 0x59, 0xC6, 0x18, 0xBD, 0x95, 
+0x83, 0xED, 0x9C, 0xB0, 0xAD, 0x52, 0xA4, 0xD1, 
+0x8C, 0x4E, 0x94, 0x4E, 0x94, 0x6E, 0x8C, 0x2E, 
+0x8C, 0x0E, 0x83, 0xED, 0xAD, 0x31, 0xB5, 0x52, 
+0xB5, 0x32, 0x94, 0x2E, 0x8C, 0x0D, 0xA4, 0xF1, 
+0x8C, 0x2E, 0x83, 0xED, 0x83, 0xED, 0x94, 0x4E, 
+0x9C, 0x8F, 0x8C, 0x2E, 0x9C, 0x6F, 0x94, 0x4E, 
+0x8C, 0x2E, 0x7B, 0x8C, 0x83, 0xAD, 0x83, 0xCC, 
+0x7B, 0xAC, 0x7B, 0xAC, 0x83, 0xAC, 0x83, 0xED, 
+0x94, 0x6F, 0x8C, 0x0E, 0x83, 0xEE, 0x52, 0x69, 
+0x21, 0x25, 0x29, 0x46, 0x29, 0x46, 0x29, 0x25, 
+0x21, 0x05, 0x18, 0xE4, 0x18, 0xE4, 0x21, 0x05, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xC4, 0x18, 0xE4, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xE4, 0x4A, 0x49, 0x6B, 0x4D, 
+0x41, 0xE8, 0x5A, 0xAA, 0x84, 0x0E, 0x7B, 0x8C, 
+0x5A, 0x89, 0x52, 0x68, 0x62, 0xEA, 0x83, 0xED, 
+0xA4, 0xD1, 0xAD, 0x53, 0xAD, 0x54, 0xB5, 0x74, 
+0xB5, 0x74, 0xAD, 0x33, 0xA4, 0xF1, 0xA4, 0xB0, 
+0x9C, 0x8F, 0x9C, 0x8F, 0x9C, 0xAF, 0xA4, 0xB0, 
+0xA4, 0xF0, 0x9C, 0x90, 0x9C, 0xD1, 0xA5, 0x11, 
+0x9C, 0x90, 0xA4, 0xF1, 0xAD, 0x11, 0xAD, 0x11, 
+0x9C, 0xB0, 0x9C, 0x8F, 0x9C, 0x8F, 0x9C, 0x8F, 
+0x8C, 0x2E, 0x7B, 0x8C, 0x6B, 0x4B, 0x84, 0x0E, 
+0xAD, 0x12, 0xBD, 0x73, 0xD6, 0x36, 0xCD, 0xF5, 
+0xC5, 0xD4, 0xCE, 0x15, 0xC5, 0xB4, 0xB5, 0x73, 
+0xC5, 0xD4, 0xCE, 0x15, 0xB5, 0x72, 0xBD, 0xB3, 
+0xCE, 0x35, 0xCE, 0x15, 0xCE, 0x35, 0xAD, 0x11, 
+0x7B, 0x8C, 0x94, 0x6F, 0x94, 0x6F, 0x9C, 0xB0, 
+0xAD, 0x12, 0x83, 0xCD, 0x9C, 0xD1, 0xC5, 0xF5, 
+0xC5, 0xD4, 0xBD, 0xB4, 0xAD, 0x32, 0xAD, 0x12, 
+0xA4, 0xD1, 0x94, 0x4F, 0xA4, 0xD1, 0x8C, 0x2E, 
+0x94, 0x4F, 0x9C, 0x8F, 0xAD, 0x11, 0xBD, 0x73, 
+0xBD, 0x73, 0xC5, 0xB4, 0xB5, 0x73, 0xAD, 0x32, 
+0xB5, 0x53, 0x52, 0x69, 0x4A, 0x69, 0x6B, 0x2B, 
+0x9C, 0xB1, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x53, 
+0xB5, 0x73, 0x9C, 0xB1, 0x4A, 0x49, 0x73, 0x8E, 
+0xA5, 0x35, 0xB5, 0x76, 0xBD, 0xB8, 0xD6, 0x7B, 
+0xDE, 0xDC, 0xDE, 0xDC, 0xD6, 0x9A, 0xBD, 0xD7, 
+0xBD, 0xD6, 0xCE, 0x57, 0xCE, 0x56, 0x8C, 0x4F, 
+0x52, 0x8A, 0x63, 0x2C, 0x7B, 0xCF, 0x7B, 0xCF, 
+0x8C, 0x2F, 0xB5, 0x52, 0xA4, 0xB0, 0xB5, 0x53, 
+0xBD, 0xB4, 0xCE, 0x35, 0xCE, 0x15, 0xAD, 0x31, 
+0xAD, 0x31, 0xC5, 0xF4, 0xCE, 0x55, 0xBD, 0xD4, 
+0xAD, 0xD5, 0xAE, 0x16, 0xB6, 0x16, 0xB5, 0xF6, 
+0x9D, 0x12, 0x7B, 0x8C, 0x7B, 0x4B, 0x83, 0xCC, 
+0x8B, 0xCB, 0x83, 0xAB, 0x94, 0x0C, 0x93, 0xEC, 
+0x9C, 0x2D, 0x9C, 0x4D, 0xA4, 0x8E, 0xA4, 0x8E, 
+0xAC, 0xCF, 0xB4, 0xF0, 0xBD, 0x30, 0xBD, 0x51, 
+0xBD, 0x30, 0xB5, 0x10, 0xAC, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0x9C, 0x8F, 0x9C, 0x8F, 0xA4, 0xCF, 
+0xA4, 0xCF, 0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xCF, 
+0xAC, 0xF0, 0xA4, 0xD0, 0x9C, 0xAF, 0x9C, 0x8F, 
+0xA4, 0xF0, 0xB5, 0x52, 0xBD, 0x93, 0xB5, 0x52, 
+0x94, 0x4E, 0x9C, 0x4D, 0xB5, 0x10, 0xAC, 0x8D, 
+0x94, 0x0C, 0x9C, 0x4C, 0xB4, 0xCF, 0xAC, 0xAE, 
+0xB4, 0xCE, 0xB4, 0xCE, 0xAC, 0x8E, 0xB4, 0xEF, 
+0xC5, 0x71, 0xAC, 0xAE, 0x9C, 0x0C, 0xAC, 0x8E, 
+0x9C, 0x4D, 0xB4, 0xEF, 0xC5, 0x71, 0xAC, 0x8E, 
+0xC5, 0x31, 0xAC, 0x8E, 0xAC, 0x6D, 0xAC, 0x6D, 
+0xB4, 0xCF, 0x93, 0xAB, 0xAC, 0x8E, 0xB4, 0xCF, 
+0x83, 0x8A, 0x83, 0xCB, 0xBD, 0x72, 0xD5, 0xF3, 
+0xD5, 0xF4, 0xC5, 0x71, 0xBD, 0x51, 0xC5, 0x92, 
+0xB5, 0x11, 0xB5, 0x31, 0xC5, 0x92, 0xC5, 0xB4, 
+0xCD, 0xD5, 0x83, 0xCD, 0x31, 0x85, 0x31, 0x65, 
+0x39, 0xC6, 0x39, 0xC6, 0x42, 0x07, 0x4A, 0x48, 
+0x52, 0x8A, 0x5A, 0xCB, 0x7B, 0xEF, 0x83, 0xEF, 
+0x83, 0xEF, 0x9C, 0x71, 0x8B, 0xEF, 0x83, 0xEF, 
+0x6B, 0x2D, 0x6B, 0x4D, 0x4A, 0x69, 0x31, 0xA6, 
+0x5A, 0xAA, 0x8C, 0x30, 0xB5, 0x74, 0x84, 0x2F, 
+0x7B, 0xEE, 0x7B, 0xCF, 0x63, 0x0B, 0x9C, 0x90, 
+0x94, 0x6F, 0xB5, 0x52, 0xAD, 0x12, 0x9C, 0xB1, 
+0x9C, 0xB0, 0x9C, 0xD1, 0x94, 0x70, 0x9C, 0xB1, 
+0x94, 0x90, 0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0xB0, 
+0x84, 0x0E, 0x83, 0xEE, 0x84, 0x0F, 0x73, 0xAE, 
+0x5A, 0xAA, 0x42, 0x07, 0x42, 0x28, 0x42, 0x07, 
+0x52, 0x89, 0x5A, 0xCA, 0x4A, 0x69, 0x6B, 0x6D, 
+0x7B, 0xCF, 0x7B, 0xAF, 0x52, 0x8A, 0x4A, 0x29, 
+0x5A, 0xCB, 0x6B, 0x4D, 0x94, 0xB3, 0xC6, 0x19, 
+0xC6, 0x39, 0x7B, 0xF0, 0x9C, 0xB2, 0xB5, 0x33, 
+0x83, 0xCD, 0x9C, 0xB0, 0xA5, 0x11, 0xAD, 0x32, 
+0x8C, 0x2E, 0x8C, 0x2E, 0xA4, 0xD0, 0x94, 0x4E, 
+0x94, 0x4F, 0x83, 0xCD, 0xB5, 0x73, 0xBD, 0x73, 
+0xB5, 0x52, 0x7B, 0x6B, 0x8C, 0x2E, 0xB5, 0x52, 
+0xAD, 0x31, 0x9C, 0x8F, 0x8C, 0x4D, 0xAD, 0x10, 
+0xAD, 0x11, 0xAD, 0x31, 0xB5, 0x52, 0xBD, 0xB3, 
+0xB5, 0x52, 0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0x90, 
+0xB5, 0x53, 0x9C, 0x6F, 0xB5, 0x32, 0x9C, 0xB0, 
+0xA4, 0xD0, 0x9C, 0x90, 0x73, 0x6C, 0x7B, 0xAE, 
+0x21, 0x05, 0x21, 0x25, 0x21, 0x05, 0x18, 0xE4, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x10, 0xA3, 0x18, 0xA3, 0x21, 0x05, 0x18, 0xC4, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC3, 
+0x18, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 0x21, 0x05, 
+0x20, 0xE5, 0x18, 0xC4, 0x62, 0xEC, 0xB5, 0x55, 
+0x94, 0x71, 0x4A, 0x29, 0x31, 0x86, 0x31, 0x66, 
+0x29, 0x46, 0x29, 0x25, 0x29, 0x25, 0x31, 0x66, 
+0x5A, 0xA9, 0x7B, 0xAE, 0x94, 0x71, 0xA4, 0xF2, 
+0xAD, 0x33, 0xAD, 0x33, 0xAD, 0x32, 0xB5, 0x53, 
+0xBD, 0x94, 0xC5, 0xD4, 0xC5, 0x94, 0xC5, 0xB4, 
+0xCD, 0xF5, 0xCE, 0x16, 0xCD, 0xF5, 0xBD, 0xB4, 
+0xBD, 0x94, 0x9C, 0xD1, 0xA4, 0xD1, 0x9C, 0xB0, 
+0x8C, 0x0E, 0x7B, 0xAD, 0x83, 0xED, 0x83, 0xCD, 
+0xA4, 0xD0, 0xA4, 0xD1, 0x9C, 0x90, 0x9C, 0x90, 
+0x9C, 0x90, 0x94, 0x4F, 0x8C, 0x2E, 0x8C, 0x0E, 
+0x83, 0xED, 0x83, 0xED, 0x8B, 0xEE, 0x7B, 0xAD, 
+0x83, 0xED, 0x8C, 0x2E, 0x8C, 0x0E, 0x94, 0x4E, 
+0xA4, 0xD0, 0xA4, 0xF1, 0x9C, 0x90, 0x8C, 0x2E, 
+0x8C, 0x2E, 0x94, 0x4F, 0x8C, 0x2E, 0x94, 0x6F, 
+0x94, 0x90, 0x73, 0x4B, 0xAD, 0x12, 0xAD, 0x11, 
+0xB5, 0x52, 0xB5, 0x72, 0xAD, 0x32, 0x9C, 0xB0, 
+0x94, 0x6F, 0x8C, 0x2E, 0x7B, 0xAC, 0x83, 0xED, 
+0x94, 0x4E, 0x9C, 0xB0, 0xB5, 0x52, 0xC5, 0xB3, 
+0xC5, 0xB4, 0xC5, 0xB4, 0xB5, 0x52, 0xA4, 0xD0, 
+0xA4, 0xD0, 0x6B, 0x2B, 0x73, 0x6C, 0x83, 0xCE, 
+0xA4, 0xD1, 0xB5, 0x52, 0xB5, 0x73, 0xB5, 0x93, 
+0xC6, 0x15, 0xCE, 0x77, 0xA5, 0x33, 0x63, 0x2C, 
+0x84, 0x10, 0xAD, 0x56, 0xA4, 0xF5, 0xC6, 0x19, 
+0xDE, 0xDC, 0xA4, 0xF4, 0x9C, 0xB3, 0x9C, 0xB3, 
+0x9C, 0x92, 0xC5, 0xD6, 0xCE, 0x36, 0x7B, 0xAD, 
+0x4A, 0x69, 0x5A, 0xCB, 0x73, 0x8D, 0x6B, 0x4C, 
+0x8C, 0x2F, 0xB5, 0x32, 0xA4, 0xF1, 0xB5, 0x73, 
+0xB5, 0x73, 0xC5, 0xF4, 0xCE, 0x15, 0xBD, 0xB3, 
+0xBD, 0xB3, 0xCE, 0x35, 0xD6, 0x55, 0xBD, 0xD4, 
+0xB6, 0x55, 0xBE, 0xD8, 0xC6, 0xF8, 0xCE, 0xF8, 
+0xC6, 0xB8, 0xB5, 0xD5, 0x83, 0xED, 0x6B, 0x29, 
+0x6B, 0x2A, 0x73, 0x4A, 0x7B, 0x8B, 0x6B, 0x09, 
+0x73, 0x2A, 0x83, 0xCC, 0x7B, 0x6A, 0x73, 0x4A, 
+0x62, 0xC8, 0x5A, 0x87, 0x6A, 0xE9, 0x73, 0x4A, 
+0x8B, 0xEC, 0x93, 0xEC, 0x8B, 0xEC, 0x9C, 0x4E, 
+0x9C, 0x4E, 0xA4, 0x8F, 0xAC, 0xAF, 0xAC, 0xAF, 
+0xB5, 0x10, 0xB5, 0x10, 0xB4, 0xEF, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xAC, 0xCF, 0xA4, 0xAF, 0xAC, 0xCF, 
+0xAC, 0xAF, 0xA4, 0x8F, 0xA4, 0x8E, 0xA4, 0x8E, 
+0xAC, 0xCF, 0xB5, 0x10, 0xB5, 0x0F, 0xAC, 0xCE, 
+0xAC, 0xCF, 0xAC, 0xAE, 0xA4, 0x6D, 0xA4, 0x4D, 
+0x9C, 0x0C, 0x93, 0xEB, 0x93, 0xCB, 0x94, 0x0C, 
+0x9C, 0x2C, 0xA4, 0x4D, 0xA4, 0x8E, 0xA4, 0x8E, 
+0x9C, 0x2C, 0xA4, 0x4D, 0xA4, 0x6D, 0xA4, 0x4C, 
+0xA4, 0x6D, 0x9B, 0xEB, 0xAC, 0x8D, 0xAC, 0xAE, 
+0xB4, 0xAE, 0xA4, 0x4D, 0xA4, 0x2C, 0xBD, 0x0F, 
+0xB4, 0xCF, 0x7B, 0x4A, 0x73, 0x09, 0x83, 0x8A, 
+0x94, 0x0C, 0x8B, 0xCB, 0x9C, 0x2D, 0xAC, 0xAF, 
+0xA4, 0xAF, 0xC5, 0x93, 0xB5, 0x31, 0xC5, 0xD3, 
+0xCE, 0x14, 0xA4, 0xD0, 0x63, 0x0A, 0x31, 0xA5, 
+0x39, 0xA6, 0x39, 0xC6, 0x42, 0x07, 0x41, 0xE7, 
+0x39, 0xC7, 0x52, 0x8A, 0x6B, 0x4D, 0x5A, 0xCB, 
+0x4A, 0x28, 0x4A, 0x08, 0x41, 0xC7, 0x5A, 0xCB, 
+0x4A, 0x49, 0x63, 0x0C, 0x52, 0x6A, 0x29, 0x65, 
+0x31, 0x66, 0x7B, 0xAE, 0x8C, 0x0F, 0x84, 0x0F, 
+0x7B, 0xEF, 0x73, 0xAE, 0x63, 0x0B, 0xA4, 0xF2, 
+0x94, 0x4E, 0xB5, 0x52, 0xBD, 0x73, 0xBD, 0x93, 
+0xB5, 0x32, 0xAD, 0x11, 0xAD, 0x12, 0xB5, 0x73, 
+0xAD, 0x32, 0xAD, 0x11, 0xB5, 0x73, 0xB5, 0x32, 
+0xA4, 0xD1, 0xA5, 0x11, 0x9C, 0x90, 0x9C, 0xB0, 
+0x7B, 0x8D, 0x73, 0x8D, 0x39, 0xA6, 0x39, 0xE6, 
+0x42, 0x27, 0x42, 0x28, 0x4A, 0x68, 0x63, 0x0B, 
+0x5A, 0xCA, 0x63, 0x0B, 0x52, 0x69, 0x41, 0xE8, 
+0x42, 0x08, 0x8C, 0x51, 0xA4, 0xF4, 0xC6, 0x19, 
+0x9C, 0xB4, 0x5A, 0xAC, 0xA5, 0x14, 0xB5, 0x75, 
+0xC5, 0xB5, 0xA4, 0xB1, 0x94, 0x4F, 0xAD, 0x12, 
+0x94, 0x2E, 0x8C, 0x2E, 0x9C, 0x90, 0x94, 0x4E, 
+0x94, 0x6F, 0x7B, 0xAC, 0x94, 0x6F, 0xB5, 0x72, 
+0xB5, 0x52, 0x6B, 0x0A, 0x8C, 0x2E, 0xA4, 0xD0, 
+0x94, 0x6F, 0x94, 0x2E, 0x94, 0x6F, 0x94, 0x6E, 
+0xA4, 0xAF, 0xAC, 0xF1, 0x9C, 0xAF, 0x9C, 0x8F, 
+0x9C, 0x8F, 0x94, 0x6F, 0x9C, 0xB0, 0xA4, 0xD0, 
+0xB5, 0x73, 0x94, 0x4F, 0x9C, 0x90, 0xAC, 0xF1, 
+0xB5, 0x72, 0xA4, 0xF1, 0x7B, 0xAD, 0x8C, 0x30, 
+0x21, 0x04, 0x18, 0xE4, 0x20, 0xE4, 0x18, 0xC4, 
+0x10, 0xA3, 0x10, 0xC4, 0x18, 0xE4, 0x10, 0xC4, 
+0x10, 0x83, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xA4, 
+0x18, 0xC4, 0x18, 0xC3, 0x18, 0xC4, 0x18, 0xC3, 
+0x10, 0xA4, 0x10, 0xA3, 0x18, 0xA3, 0x18, 0xC4, 
+0x18, 0xC4, 0x10, 0xA4, 0x10, 0xA3, 0x29, 0x45, 
+0x42, 0x08, 0x21, 0x05, 0x21, 0x05, 0x21, 0x04, 
+0x20, 0xE4, 0x18, 0xC4, 0x18, 0xC3, 0x20, 0xE4, 
+0x29, 0x45, 0x31, 0x87, 0x42, 0x08, 0x52, 0x8A, 
+0x7B, 0xAE, 0x94, 0x50, 0x9C, 0xB1, 0x83, 0xEE, 
+0x8B, 0xEE, 0x83, 0xEE, 0x7B, 0xAD, 0x7B, 0xAD, 
+0x73, 0x8D, 0x83, 0xEE, 0x94, 0x50, 0x94, 0x90, 
+0x94, 0x50, 0x7B, 0xCE, 0x73, 0x6D, 0x6B, 0x4D, 
+0x63, 0x0C, 0x5A, 0xCB, 0x5A, 0xAA, 0x62, 0xEB, 
+0x7B, 0x8D, 0x73, 0x4C, 0x7B, 0x6C, 0x94, 0x2F, 
+0x9C, 0xB0, 0xAD, 0x12, 0xB5, 0x33, 0xB5, 0x33, 
+0xB5, 0x33, 0xB5, 0x33, 0xAD, 0x32, 0xB5, 0x53, 
+0xB5, 0x53, 0xAD, 0x12, 0xAD, 0x32, 0xA4, 0xF1, 
+0xA4, 0xD1, 0xB5, 0x73, 0xBD, 0x73, 0xBD, 0x94, 
+0xBD, 0x94, 0xC5, 0xB4, 0xB5, 0x32, 0xBD, 0x94, 
+0xA4, 0xD1, 0x83, 0xEE, 0x8C, 0x0E, 0x83, 0xED, 
+0x83, 0xED, 0x8C, 0x0E, 0x8C, 0x0E, 0x83, 0xEE, 
+0x8B, 0xEE, 0x94, 0x6F, 0xA4, 0xB1, 0x94, 0x6F, 
+0x8C, 0x0E, 0x7B, 0xCC, 0x83, 0xAC, 0x83, 0xCD, 
+0x94, 0x0F, 0x9C, 0x6F, 0x94, 0x4F, 0x94, 0x4F, 
+0x83, 0xED, 0x94, 0x4F, 0x7B, 0x8C, 0x7B, 0x8C, 
+0xAD, 0x32, 0xA4, 0xF1, 0xB5, 0x52, 0xBD, 0xD4, 
+0xBD, 0xB4, 0xBD, 0xD4, 0xC6, 0x15, 0x8C, 0x4F, 
+0x6B, 0x4D, 0x84, 0x31, 0x83, 0xF0, 0xBD, 0xF8, 
+0xA4, 0xF4, 0x7B, 0xAF, 0xA4, 0xD3, 0xBD, 0x76, 
+0x7B, 0x8E, 0xC6, 0x17, 0xCE, 0x78, 0x63, 0x2C, 
+0x5A, 0xCA, 0x63, 0x0C, 0x63, 0x0B, 0x52, 0xAA, 
+0x5A, 0xAA, 0x8C, 0x2F, 0x94, 0x4E, 0xAD, 0x32, 
+0xAD, 0x11, 0xC5, 0xF4, 0xC5, 0xF4, 0xA4, 0xD0, 
+0xA4, 0xF0, 0xCE, 0x14, 0xD6, 0x55, 0xC5, 0xF4, 
+0xA5, 0xF1, 0xA5, 0xB4, 0x95, 0x32, 0x84, 0x50, 
+0x3A, 0x07, 0x5A, 0xC9, 0x6B, 0x29, 0x73, 0x6A, 
+0x83, 0xCC, 0x94, 0x4E, 0x94, 0x6E, 0x8C, 0x2D, 
+0x8C, 0x0D, 0x9C, 0x8F, 0xA4, 0xD0, 0x9C, 0x8F, 
+0x94, 0x6F, 0x7B, 0x8C, 0x7B, 0xAC, 0x73, 0x4B, 
+0x7B, 0xAB, 0x83, 0xAB, 0x83, 0xCC, 0x94, 0x0D, 
+0x8B, 0xCC, 0x83, 0xAB, 0xA4, 0x8F, 0x9C, 0x2D, 
+0x9C, 0x4D, 0xA4, 0x6D, 0x9C, 0x4D, 0x83, 0xAB, 
+0x7B, 0x6A, 0x94, 0x0C, 0x83, 0xCB, 0x73, 0x2A, 
+0x73, 0x29, 0x83, 0xCB, 0x94, 0x0D, 0x9C, 0x2D, 
+0x8B, 0xCC, 0x9C, 0x4D, 0xB4, 0xEF, 0xB5, 0x10, 
+0xAC, 0xAE, 0xA4, 0x8E, 0xAC, 0xAE, 0xA4, 0x4D, 
+0xAC, 0x8E, 0xAC, 0xCF, 0xB4, 0xF0, 0x8B, 0xEC, 
+0x93, 0xEC, 0x9C, 0x2D, 0x9C, 0x2C, 0xAC, 0xAF, 
+0xAC, 0xCF, 0xAC, 0xAE, 0xAC, 0xCF, 0xAC, 0x8E, 
+0xAC, 0x8E, 0xAC, 0x8E, 0xA4, 0x8E, 0xAC, 0x8E, 
+0xAC, 0x8E, 0xAC, 0xAE, 0xB4, 0xCF, 0xBD, 0x30, 
+0xBD, 0x10, 0xB4, 0xF0, 0xB4, 0xF0, 0x9C, 0x4E, 
+0x94, 0x2D, 0x94, 0x2D, 0x8B, 0xEC, 0x8B, 0xEC, 
+0x94, 0x0D, 0xA4, 0x6E, 0xAC, 0xAE, 0x94, 0x0C, 
+0x9C, 0x4D, 0xA4, 0x8F, 0x94, 0x2E, 0x4A, 0x28, 
+0x39, 0xA6, 0x39, 0xC6, 0x39, 0xA6, 0x39, 0xC6, 
+0x4A, 0x28, 0x52, 0x69, 0x52, 0x8A, 0x42, 0x08, 
+0x39, 0xC7, 0x39, 0xC7, 0x31, 0x86, 0x39, 0xA6, 
+0x31, 0x86, 0x6B, 0x2D, 0x5A, 0xCB, 0x42, 0x08, 
+0x4A, 0x28, 0xAD, 0x34, 0xA4, 0xD2, 0x9C, 0xB1, 
+0x9C, 0xB1, 0x94, 0x71, 0x8C, 0x4F, 0xB5, 0x53, 
+0x94, 0x2D, 0xAD, 0x11, 0xBD, 0x52, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xC5, 0x92, 0xBD, 0x51, 0xBD, 0x52, 
+0xBD, 0x52, 0xBD, 0x51, 0xB5, 0x11, 0xAC, 0xF1, 
+0xA4, 0xAF, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x11, 
+0xA4, 0xD0, 0xAD, 0x11, 0x6B, 0x2A, 0x39, 0xA5, 
+0x39, 0xC6, 0x39, 0xE6, 0x4A, 0x48, 0x42, 0x07, 
+0x41, 0xE7, 0x52, 0x69, 0x4A, 0x48, 0x31, 0xA6, 
+0x4A, 0x69, 0x84, 0x10, 0x9C, 0xD4, 0xC6, 0x39, 
+0xA5, 0x35, 0x7B, 0xD0, 0xBD, 0xD7, 0xAD, 0x55, 
+0xC5, 0xB6, 0xCD, 0xB5, 0xB5, 0x33, 0x8C, 0x0E, 
+0xA4, 0xF1, 0xBD, 0xF6, 0xB5, 0x53, 0x94, 0x70, 
+0xA4, 0xF1, 0x7B, 0xAC, 0x8C, 0x0D, 0xB5, 0x52, 
+0xAD, 0x12, 0x5A, 0xA9, 0x9C, 0x6F, 0xAC, 0xF0, 
+0x9C, 0xAF, 0x9C, 0x8F, 0x94, 0x6E, 0x9C, 0x6F, 
+0xA4, 0xF0, 0xAD, 0x10, 0xA4, 0xD0, 0x9C, 0xAF, 
+0x94, 0x6E, 0x94, 0x4E, 0x8C, 0x2E, 0x8C, 0x4E, 
+0x94, 0x4E, 0x8C, 0x2E, 0x8C, 0x0D, 0xA4, 0xF0, 
+0x94, 0x4E, 0x8C, 0x2E, 0x7B, 0xCD, 0x94, 0x91, 
+0x29, 0x66, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xA4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x18, 0xE4, 
+0x20, 0xE4, 0x20, 0xE5, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x21, 0x04, 0x29, 0x25, 0x29, 0x66, 0x29, 0x66, 
+0x39, 0xC7, 0x52, 0x6A, 0x6B, 0x4D, 0x7B, 0xAE, 
+0x9C, 0xB2, 0xA4, 0xF2, 0x8C, 0x2F, 0x8C, 0x50, 
+0x7B, 0xCE, 0x7B, 0xAE, 0x73, 0x8D, 0x6B, 0x2C, 
+0x63, 0x0C, 0x5A, 0xAB, 0x52, 0x6A, 0x52, 0x6A, 
+0x52, 0x6A, 0x5A, 0x8B, 0x5A, 0xAB, 0x5A, 0x8B, 
+0x5A, 0xAB, 0x5A, 0xAA, 0x5A, 0xCB, 0x73, 0x6D, 
+0x8C, 0x2F, 0x8C, 0x0E, 0x94, 0x2F, 0x9C, 0xB0, 
+0x94, 0x70, 0x94, 0x2F, 0x83, 0xED, 0x8C, 0x2E, 
+0xA4, 0xD1, 0x9C, 0x70, 0x94, 0x4F, 0x9C, 0x90, 
+0x9C, 0x70, 0xAD, 0x11, 0xBD, 0x72, 0xBD, 0x73, 
+0xB5, 0x11, 0xAC, 0xF1, 0xB5, 0x32, 0xBD, 0x94, 
+0xB5, 0x53, 0xA4, 0xD1, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xBD, 0x94, 0xBD, 0x73, 0xC5, 0xD5, 0xCD, 0xF6, 
+0xCE, 0x16, 0xCE, 0x16, 0xD6, 0x57, 0xC5, 0xD5, 
+0xC5, 0xD5, 0xBD, 0x94, 0xC5, 0xD5, 0xC5, 0xD5, 
+0xC5, 0xD4, 0xC5, 0xB4, 0xC5, 0xD5, 0xC5, 0xD5, 
+0xC5, 0xD4, 0xBD, 0x94, 0xB5, 0x53, 0xB5, 0x53, 
+0xB5, 0x53, 0xAD, 0x32, 0xAC, 0xF1, 0xA4, 0xB0, 
+0x94, 0x6F, 0xA4, 0xB0, 0x9C, 0xB0, 0x94, 0x70, 
+0x7B, 0xAD, 0x6B, 0x4D, 0x8C, 0x51, 0xBD, 0xF7, 
+0x84, 0x10, 0xAD, 0x35, 0x8C, 0x51, 0xBD, 0x96, 
+0x94, 0x51, 0xCE, 0x59, 0xD6, 0xBA, 0x73, 0xAF, 
+0x4A, 0x49, 0x5A, 0xCA, 0x52, 0xAA, 0x5A, 0xEB, 
+0x6B, 0x2C, 0xAD, 0x13, 0x8C, 0x2E, 0x9C, 0xB0, 
+0xB5, 0x73, 0xB5, 0x93, 0xB5, 0x72, 0x9C, 0x8F, 
+0x94, 0x4E, 0xC5, 0xD4, 0xC5, 0xF4, 0xC5, 0xD4, 
+0x9D, 0xD0, 0x9D, 0x72, 0x9D, 0x73, 0x84, 0x50, 
+0x7C, 0x2F, 0x94, 0xD0, 0x6B, 0x4A, 0x83, 0xCC, 
+0x94, 0x6F, 0x94, 0x6F, 0x9C, 0x8F, 0x83, 0xED, 
+0xA4, 0xF0, 0xA4, 0xD0, 0xA4, 0xF0, 0xA4, 0xD0, 
+0x9C, 0xAF, 0x9C, 0x8F, 0x9C, 0xAF, 0x94, 0x2E, 
+0x94, 0x6E, 0x94, 0x4E, 0xA4, 0xD0, 0x9C, 0x6F, 
+0x94, 0x6F, 0x83, 0xCC, 0xA4, 0xCF, 0xA4, 0xAF, 
+0x9C, 0x8E, 0xAD, 0x10, 0xAC, 0xF0, 0xAD, 0x11, 
+0x9C, 0x8F, 0x94, 0x4E, 0x9C, 0xB0, 0x94, 0x6F, 
+0x73, 0x6B, 0x94, 0x4E, 0x8C, 0x2E, 0x8C, 0x0D, 
+0x7B, 0x6B, 0x73, 0x29, 0x83, 0x6A, 0x83, 0x6A, 
+0x83, 0x8A, 0x83, 0x8A, 0x83, 0xAB, 0x9C, 0x6E, 
+0x83, 0x8B, 0x8B, 0xEC, 0xB5, 0x10, 0x9C, 0x8E, 
+0x9C, 0xD0, 0xA4, 0xD0, 0xA4, 0xD0, 0xAD, 0x11, 
+0xA4, 0xF0, 0xAD, 0x11, 0xAD, 0x11, 0xA4, 0xCF, 
+0x9C, 0x8E, 0x9C, 0x4D, 0xA4, 0x8E, 0x9C, 0x6E, 
+0x9C, 0x6E, 0x9C, 0x4E, 0x8B, 0xEC, 0x94, 0x0C, 
+0x8B, 0xCB, 0x8B, 0xCB, 0x8B, 0xCC, 0x8B, 0xCB, 
+0x9C, 0x4D, 0xAC, 0xEF, 0xC5, 0x92, 0xCD, 0xB3, 
+0xC5, 0x71, 0xB4, 0xF0, 0xBD, 0x10, 0xAC, 0xCF, 
+0xB4, 0xEF, 0xB5, 0x10, 0xAC, 0xD0, 0x73, 0x4B, 
+0x31, 0x85, 0x41, 0xE7, 0x41, 0xE7, 0x42, 0x08, 
+0x4A, 0x48, 0x42, 0x08, 0x4A, 0x48, 0x39, 0xA6, 
+0x29, 0x44, 0x29, 0x24, 0x31, 0x65, 0x4A, 0x28, 
+0x6B, 0x4D, 0x94, 0x72, 0x73, 0x8E, 0x52, 0x8A, 
+0x7B, 0x8D, 0x73, 0x4C, 0x62, 0xCA, 0x6B, 0x2B, 
+0x84, 0x0F, 0x9C, 0x90, 0xB5, 0x52, 0xC5, 0x93, 
+0xA4, 0x8E, 0x9C, 0x6E, 0x9C, 0x4E, 0x9C, 0x6E, 
+0xAC, 0xCF, 0xBD, 0x30, 0xC5, 0x71, 0xCD, 0xD2, 
+0xCD, 0x92, 0xC5, 0x51, 0xBD, 0x50, 0xBD, 0x51, 
+0xCD, 0xB2, 0xCD, 0xB3, 0xC5, 0x72, 0xAC, 0xF0, 
+0xAD, 0x11, 0xB5, 0x51, 0xAC, 0xF0, 0x6A, 0xE9, 
+0x29, 0x64, 0x31, 0xA5, 0x42, 0x07, 0x39, 0xA5, 
+0x39, 0xA6, 0x42, 0x07, 0x42, 0x07, 0x39, 0xC7, 
+0x5A, 0xAA, 0x73, 0xAE, 0x94, 0xB3, 0xC6, 0x19, 
+0x94, 0x93, 0x84, 0x10, 0xBD, 0xF8, 0xAD, 0x56, 
+0xAD, 0x35, 0xA4, 0xD3, 0xD6, 0x38, 0x9C, 0x50, 
+0x52, 0x8A, 0x8C, 0x51, 0xB5, 0x95, 0x8C, 0x4F, 
+0xB5, 0x53, 0x8C, 0x4E, 0x94, 0x4F, 0xB5, 0x73, 
+0xB5, 0x53, 0x52, 0x68, 0xA4, 0xD1, 0xA4, 0xF0, 
+0xAD, 0x31, 0xAC, 0xF0, 0x9C, 0xAF, 0x9C, 0x8F, 
+0xAD, 0x31, 0xB5, 0x51, 0xB5, 0x52, 0xA4, 0xD0, 
+0xA4, 0xB0, 0xA4, 0xD0, 0xA4, 0xD1, 0x8C, 0x4E, 
+0x94, 0x6F, 0x84, 0x0E, 0x8C, 0x4E, 0xAD, 0x11, 
+0x9C, 0x6F, 0x94, 0x2F, 0x94, 0x2F, 0x94, 0x50, 
+0x39, 0xA7, 0x21, 0x05, 0x18, 0xC4, 0x18, 0xE4, 
+0x19, 0x05, 0x18, 0xE4, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC3, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xC4, 0x20, 0xE5, 0x49, 0x46, 0x71, 0xA8, 
+0x59, 0x86, 0x21, 0x04, 0x21, 0x05, 0x21, 0x05, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC3, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x21, 0x25, 0x29, 0x46, 0x29, 0x66, 
+0x39, 0xA7, 0x31, 0xA7, 0x39, 0xE8, 0x4A, 0x29, 
+0x62, 0xEC, 0x7B, 0xAE, 0x6B, 0x4D, 0x62, 0xEC, 
+0x5A, 0xAB, 0x52, 0x6A, 0x52, 0x4A, 0x4A, 0x29, 
+0x4A, 0x09, 0x41, 0xE8, 0x41, 0xC8, 0x41, 0xC8, 
+0x41, 0xC8, 0x4A, 0x09, 0x52, 0x8B, 0x5A, 0xAB, 
+0x52, 0x8B, 0x52, 0x8B, 0x5A, 0xAB, 0x73, 0x6D, 
+0x9C, 0xD2, 0xB5, 0x74, 0xB5, 0x74, 0xBD, 0xB4, 
+0xA4, 0xF2, 0x94, 0x70, 0xA4, 0xF2, 0x9C, 0xD1, 
+0x9C, 0xD1, 0xA4, 0xF2, 0x8C, 0x2F, 0x83, 0xEE, 
+0xAD, 0x32, 0xBD, 0xB3, 0xC5, 0xD3, 0xC5, 0xB3, 
+0xAD, 0x11, 0xA4, 0xF0, 0x9C, 0xAF, 0x9C, 0x8F, 
+0xAD, 0x11, 0xB5, 0x52, 0x9C, 0xB0, 0xA4, 0xD0, 
+0xAD, 0x11, 0xAC, 0xF1, 0xA4, 0xB0, 0x9C, 0x8F, 
+0xAD, 0x32, 0xA4, 0xD0, 0x94, 0x6F, 0x94, 0x4E, 
+0x8C, 0x0E, 0xAC, 0xF1, 0xB5, 0x32, 0xB5, 0x32, 
+0xB5, 0x11, 0xAC, 0xF1, 0xA4, 0xD0, 0xAD, 0x11, 
+0xA4, 0xB0, 0xAC, 0xD0, 0xAC, 0xD0, 0xB5, 0x32, 
+0xAC, 0xD0, 0xAC, 0xF1, 0xA4, 0xB0, 0xB5, 0x11, 
+0xBD, 0x73, 0xBD, 0x73, 0xB5, 0x52, 0xBD, 0x93, 
+0xB5, 0x33, 0x6B, 0x2C, 0x73, 0xAF, 0x8C, 0x72, 
+0xB5, 0x96, 0xB5, 0x56, 0x83, 0xEF, 0xB5, 0x55, 
+0xCE, 0x7A, 0xD6, 0xDB, 0xEF, 0x5D, 0xD6, 0xBA, 
+0x73, 0x8E, 0x52, 0xAA, 0x52, 0xAA, 0x63, 0x2C, 
+0x7B, 0xEF, 0xB5, 0x54, 0xAD, 0x33, 0xA4, 0xD1, 
+0x94, 0x6F, 0x9C, 0x6F, 0x94, 0x6F, 0x8C, 0x2E, 
+0x8C, 0x2E, 0x94, 0x4F, 0x94, 0x4F, 0x8C, 0x0E, 
+0x95, 0xAE, 0x9D, 0x70, 0x9D, 0x52, 0x9D, 0x52, 
+0x9D, 0x32, 0x6B, 0x6B, 0x94, 0x8F, 0xBD, 0xF4, 
+0xCE, 0x95, 0xBD, 0xF4, 0x9C, 0x8F, 0x6B, 0x2A, 
+0xAD, 0x52, 0xA4, 0xD0, 0xAD, 0x11, 0xAD, 0x31, 
+0xAD, 0x31, 0xAD, 0x31, 0xB5, 0x52, 0xAD, 0x11, 
+0xAD, 0x11, 0xA4, 0xD0, 0xBD, 0x93, 0xAD, 0x31, 
+0xAC, 0xF0, 0x94, 0x2D, 0xA4, 0xAF, 0xAD, 0x10, 
+0xB5, 0x31, 0xBD, 0x72, 0xB5, 0x72, 0xAD, 0x32, 
+0xAD, 0x12, 0xB5, 0x53, 0xB5, 0x73, 0xAD, 0x12, 
+0x94, 0x4F, 0x9C, 0x90, 0x9C, 0xD0, 0x9C, 0x90, 
+0xAD, 0x11, 0x7B, 0x8C, 0x7B, 0x6B, 0x62, 0xC8, 
+0x83, 0xAC, 0xA4, 0xB0, 0x8B, 0xED, 0x94, 0x4E, 
+0x94, 0x2E, 0x83, 0xAB, 0xB5, 0x10, 0xAD, 0x11, 
+0xB5, 0x93, 0xB5, 0x53, 0xAD, 0x32, 0xB5, 0x73, 
+0xBD, 0xB4, 0xB5, 0x53, 0xA5, 0x11, 0xAD, 0x32, 
+0x9C, 0xD0, 0x9C, 0xD0, 0xA4, 0xF1, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xAD, 0x52, 0x9C, 0xB0, 0x8C, 0x0D, 
+0x9C, 0x8F, 0xA4, 0xD0, 0xA4, 0xF1, 0x9C, 0x8F, 
+0xA4, 0xD0, 0xA4, 0x8E, 0xB4, 0xF0, 0xAC, 0xCF, 
+0xBD, 0x51, 0xBD, 0x51, 0xB5, 0x30, 0xAC, 0xEF, 
+0xA4, 0xAF, 0xBD, 0x52, 0x8C, 0x0D, 0x8C, 0x2E, 
+0x4A, 0x48, 0x41, 0xE7, 0x39, 0xC6, 0x39, 0xA6, 
+0x41, 0xE7, 0x52, 0x69, 0x4A, 0x48, 0x41, 0xE7, 
+0x29, 0x45, 0x31, 0x65, 0x39, 0xA6, 0x52, 0x69, 
+0x84, 0x10, 0xAD, 0x55, 0x83, 0xEF, 0x4A, 0x48, 
+0x5A, 0xAA, 0x31, 0x45, 0x29, 0x45, 0x41, 0xE7, 
+0x5A, 0x89, 0xA4, 0xB0, 0xBD, 0x31, 0xBD, 0x50, 
+0xCD, 0x92, 0xCD, 0xB2, 0xCD, 0xB2, 0xCD, 0xB2, 
+0xCD, 0xB2, 0xC5, 0x92, 0xC5, 0x51, 0xBD, 0x30, 
+0xC5, 0x71, 0xC5, 0x71, 0xBD, 0x10, 0xBD, 0x30, 
+0xBD, 0x31, 0xBD, 0x10, 0xB4, 0xEF, 0xB4, 0xEF, 
+0xAC, 0xEF, 0xAC, 0xCF, 0xB5, 0x10, 0xAC, 0xF0, 
+0x62, 0xC9, 0x29, 0x64, 0x39, 0xA5, 0x39, 0xA5, 
+0x39, 0xC6, 0x41, 0xE7, 0x42, 0x28, 0x42, 0x08, 
+0x52, 0x8A, 0x6B, 0x4D, 0xA5, 0x35, 0xBD, 0xD7, 
+0x84, 0x11, 0x7B, 0xD0, 0xA5, 0x35, 0xBD, 0xF8, 
+0x94, 0x93, 0x73, 0x6D, 0xBD, 0x95, 0x9C, 0x71, 
+0xB5, 0x35, 0x9C, 0xB2, 0x9C, 0xF3, 0x5A, 0xCB, 
+0x94, 0x70, 0x8C, 0x4E, 0x9C, 0xB0, 0xBD, 0x94, 
+0xB5, 0x32, 0x8B, 0xEE, 0xA4, 0xF1, 0xAC, 0xF0, 
+0xB5, 0x52, 0xBD, 0x72, 0xBD, 0x93, 0xB5, 0x31, 
+0xBD, 0x72, 0xB5, 0x51, 0xB5, 0x52, 0xBD, 0x72, 
+0xBD, 0x93, 0xB5, 0x32, 0xB5, 0x52, 0xB5, 0x73, 
+0xAD, 0x11, 0x9C, 0xB0, 0xA5, 0x12, 0xAD, 0x32, 
+0xA4, 0xB0, 0x94, 0x4F, 0x83, 0xCD, 0x6B, 0x2B, 
+0x21, 0x04, 0x18, 0xC4, 0x10, 0xA3, 0x18, 0xC4, 
+0x18, 0xE4, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xC3, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 
+0x10, 0xC4, 0x30, 0xE5, 0x71, 0x87, 0xA1, 0xE9, 
+0xA2, 0x8A, 0x31, 0x04, 0x20, 0xE5, 0x21, 0x05, 
+0x20, 0xE4, 0x18, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC3, 
+0x18, 0xC4, 0x21, 0x04, 0x29, 0x45, 0x29, 0x66, 
+0x29, 0x66, 0x31, 0x67, 0x31, 0x87, 0x39, 0xA7, 
+0x41, 0xE8, 0x4A, 0x29, 0x52, 0x6A, 0x52, 0x8B, 
+0x4A, 0x4A, 0x4A, 0x09, 0x41, 0xE8, 0x39, 0xC8, 
+0x39, 0x87, 0x39, 0x87, 0x31, 0x66, 0x31, 0x66, 
+0x31, 0x86, 0x31, 0x87, 0x39, 0xC8, 0x41, 0xE8, 
+0x4A, 0x4A, 0x52, 0x8B, 0x52, 0xAB, 0x5A, 0xCC, 
+0x62, 0xEC, 0x73, 0x8E, 0x94, 0x91, 0xB5, 0x74, 
+0xBD, 0x94, 0xB5, 0x74, 0xB5, 0x74, 0xAD, 0x33, 
+0xAD, 0x53, 0xAD, 0x53, 0x9C, 0x90, 0x84, 0x2E, 
+0xB5, 0x93, 0xBD, 0xB3, 0xBD, 0x72, 0xCD, 0xF4, 
+0xBD, 0xB4, 0xBD, 0xD4, 0xAD, 0x12, 0xAD, 0x12, 
+0xB5, 0x53, 0xB5, 0x93, 0xBD, 0x92, 0xBD, 0x72, 
+0xAD, 0x11, 0xAD, 0x31, 0xB5, 0x73, 0xA4, 0xF1, 
+0xAD, 0x52, 0xAD, 0x52, 0xA5, 0x11, 0x94, 0x6F, 
+0x7B, 0x6C, 0xCD, 0xF5, 0xCE, 0x15, 0xCD, 0xF4, 
+0xAC, 0xD0, 0xBD, 0x52, 0x8C, 0x0D, 0xA4, 0x8F, 
+0xA4, 0xAF, 0xAC, 0xF0, 0xBD, 0x52, 0xBD, 0x72, 
+0xB5, 0x52, 0xC5, 0xB3, 0xBD, 0x72, 0xAC, 0xF1, 
+0x7B, 0x6B, 0x8C, 0x2E, 0xA4, 0xD0, 0xA4, 0xB0, 
+0xC5, 0xB4, 0xA4, 0xF2, 0x52, 0xAA, 0x7B, 0xF0, 
+0xB5, 0x76, 0x73, 0x8E, 0x94, 0x92, 0xCE, 0x39, 
+0xDE, 0xDB, 0xC6, 0x18, 0x94, 0xB3, 0xB5, 0x96, 
+0xBD, 0xD7, 0x73, 0xAE, 0x5A, 0xEB, 0x6B, 0x4D, 
+0x7B, 0xEF, 0xA5, 0x13, 0xAD, 0x33, 0xAD, 0x12, 
+0xB5, 0x73, 0xBD, 0x73, 0xBD, 0x73, 0xB5, 0x53, 
+0xC5, 0xB4, 0xBD, 0x73, 0xBD, 0x73, 0xBD, 0x94, 
+0x85, 0x0A, 0x9D, 0xAF, 0x95, 0x30, 0x8C, 0xCF, 
+0x4A, 0x87, 0x6B, 0x4A, 0x84, 0x2D, 0x9D, 0x2E, 
+0x9D, 0xAD, 0xC6, 0x93, 0xB5, 0x92, 0xA4, 0xCF, 
+0xAD, 0x30, 0x84, 0x0C, 0xB5, 0x52, 0xB5, 0x52, 
+0xAD, 0x11, 0xAD, 0x31, 0xB5, 0x52, 0xB5, 0x32, 
+0xB5, 0x32, 0xAD, 0x31, 0xC5, 0xD4, 0xB5, 0x51, 
+0xB5, 0x31, 0xAD, 0x11, 0xAC, 0xF0, 0xB5, 0x31, 
+0xC5, 0x92, 0xCD, 0xF4, 0xBD, 0x93, 0xB5, 0x53, 
+0xBD, 0x73, 0xBD, 0xB4, 0xAD, 0x12, 0xAD, 0x32, 
+0xB5, 0x32, 0x8C, 0x2E, 0x94, 0x6F, 0xAD, 0x52, 
+0xB5, 0x52, 0x9C, 0xB0, 0x94, 0x4E, 0x6A, 0xE9, 
+0x83, 0xED, 0x73, 0x6A, 0x9C, 0x8F, 0x9C, 0x6F, 
+0x9C, 0xB0, 0x9C, 0x8F, 0xB5, 0x31, 0xB5, 0x73, 
+0xC5, 0xF5, 0xBD, 0xB4, 0xAD, 0x53, 0xB5, 0x94, 
+0xBD, 0xB4, 0xAD, 0x53, 0xB5, 0x94, 0xAD, 0x52, 
+0xA5, 0x11, 0xAD, 0x32, 0xAD, 0x53, 0xA5, 0x11, 
+0xAD, 0x53, 0xB5, 0x94, 0xB5, 0x73, 0xA4, 0xF1, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x93, 0xAD, 0x52, 
+0xC5, 0xF5, 0xA4, 0xAF, 0xA4, 0x8E, 0xAC, 0xD0, 
+0xBD, 0x72, 0xD6, 0x14, 0xCD, 0xF4, 0xCD, 0xF4, 
+0xCD, 0xD3, 0xCD, 0xF4, 0x9C, 0x90, 0x9C, 0xB0, 
+0x7B, 0xCE, 0x4A, 0x48, 0x41, 0xE7, 0x39, 0xC7, 
+0x39, 0xC7, 0x4A, 0x28, 0x42, 0x08, 0x41, 0xE7, 
+0x4A, 0x28, 0x5A, 0xAA, 0x52, 0x8A, 0x62, 0xEB, 
+0x94, 0x71, 0xB5, 0x75, 0x7B, 0xCF, 0x5A, 0xCB, 
+0x4A, 0x48, 0x39, 0x86, 0x4A, 0x49, 0x5A, 0xCA, 
+0x41, 0xC6, 0x83, 0xCD, 0x94, 0x2D, 0x8B, 0xCB, 
+0x9C, 0x6D, 0x9C, 0x4D, 0xA4, 0x6E, 0xBD, 0x10, 
+0xC5, 0x71, 0x94, 0x0C, 0xA4, 0x8E, 0x94, 0x0C, 
+0x94, 0x2D, 0x94, 0x2C, 0x94, 0x0C, 0x94, 0x2D, 
+0x9C, 0x6E, 0xA4, 0x8E, 0xA4, 0x8E, 0x94, 0x2D, 
+0x9C, 0x4D, 0xA4, 0x8E, 0xB5, 0x10, 0xAC, 0xF0, 
+0x5A, 0xA8, 0x21, 0x03, 0x21, 0x23, 0x39, 0xA5, 
+0x42, 0x07, 0x39, 0xC6, 0x42, 0x07, 0x41, 0xE7, 
+0x42, 0x08, 0x5A, 0xEB, 0xC6, 0x18, 0xB5, 0x76, 
+0x8C, 0x72, 0x73, 0x8F, 0x9C, 0xF4, 0xB5, 0x96, 
+0x84, 0x10, 0x7B, 0xCF, 0x6B, 0x0C, 0x39, 0xA6, 
+0xC5, 0xF7, 0xD6, 0x79, 0xAD, 0x34, 0x7B, 0xEF, 
+0x73, 0x6C, 0x8B, 0xED, 0x94, 0x2E, 0xAD, 0x11, 
+0xAC, 0xF1, 0x9C, 0xB0, 0x9C, 0x90, 0x9C, 0xB0, 
+0xAC, 0xF0, 0xAC, 0xF0, 0xB5, 0x11, 0x9C, 0x8E, 
+0x9C, 0x8F, 0x9C, 0x6F, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xA4, 0xAF, 0x9C, 0x8F, 0xAC, 0xF1, 
+0xBD, 0x94, 0xBD, 0x94, 0xBD, 0x94, 0xB5, 0x73, 
+0xA4, 0xF1, 0x94, 0x6F, 0x7B, 0x8D, 0x52, 0x49, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 0x10, 0xC4, 
+0x10, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xA3, 0x49, 0x26, 0x79, 0x47, 0xAA, 0x4A, 
+0x79, 0xA8, 0x28, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC3, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x20, 0xE5, 0x21, 0x05, 0x21, 0x25, 
+0x29, 0x46, 0x29, 0x66, 0x31, 0x87, 0x39, 0xA7, 
+0x39, 0xC8, 0x39, 0xC8, 0x39, 0xE8, 0x4A, 0x09, 
+0x42, 0x09, 0x41, 0xC8, 0x39, 0xC8, 0x31, 0x87, 
+0x31, 0x87, 0x31, 0x87, 0x29, 0x66, 0x29, 0x46, 
+0x29, 0x46, 0x29, 0x46, 0x29, 0x66, 0x31, 0x87, 
+0x39, 0xA7, 0x39, 0xC8, 0x42, 0x29, 0x4A, 0x4A, 
+0x4A, 0x2A, 0x4A, 0x4A, 0x52, 0x8B, 0x63, 0x2D, 
+0x83, 0xEF, 0x9C, 0xD2, 0xB5, 0x74, 0xB5, 0x94, 
+0xB5, 0xB5, 0xAD, 0x53, 0x94, 0x70, 0x94, 0x6F, 
+0xBD, 0xB4, 0xCD, 0xF4, 0xBD, 0x92, 0xC5, 0xF4, 
+0xB5, 0x52, 0xB5, 0x73, 0xAD, 0x53, 0xBD, 0xB4, 
+0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x51, 0xBD, 0x92, 
+0xBD, 0x72, 0xB5, 0x51, 0xB5, 0x93, 0xAD, 0x32, 
+0xC6, 0x16, 0xBD, 0xD5, 0xBD, 0xF5, 0xB5, 0x73, 
+0x9C, 0xD0, 0xCD, 0xF4, 0xCE, 0x35, 0xCE, 0x15, 
+0xA4, 0xB0, 0xBD, 0x73, 0x94, 0x6F, 0x94, 0x0D, 
+0x9C, 0x4E, 0xAD, 0x11, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xBD, 0xB3, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x11, 
+0x8C, 0x0D, 0xA4, 0xF0, 0xAD, 0x11, 0xAD, 0x11, 
+0xBD, 0x93, 0xC5, 0xB4, 0x94, 0x70, 0x5A, 0xCB, 
+0x8C, 0x51, 0x73, 0xAF, 0x7B, 0xCF, 0xB5, 0x96, 
+0x83, 0xF0, 0x5A, 0xCC, 0x73, 0x6E, 0x84, 0x30, 
+0x94, 0xB2, 0x8C, 0x51, 0x62, 0xEC, 0x6B, 0x4D, 
+0x7B, 0xEF, 0x9C, 0xF3, 0xC5, 0xF6, 0xC5, 0xF4, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xB5, 0x73, 0xBD, 0xB3, 
+0xC5, 0xB4, 0xBD, 0x72, 0xBD, 0x93, 0xAD, 0x11, 
+0x74, 0xE9, 0x7C, 0xEC, 0x85, 0x0F, 0x84, 0x8F, 
+0x39, 0xE6, 0x52, 0x88, 0x73, 0xAB, 0x7C, 0x2A, 
+0x74, 0x47, 0x9D, 0x8B, 0xBE, 0x30, 0xB5, 0xB0, 
+0x94, 0x8C, 0x94, 0x6D, 0xA4, 0xAF, 0xB5, 0x52, 
+0xAD, 0x31, 0xAD, 0x11, 0xB5, 0x31, 0xB5, 0x52, 
+0xB5, 0x32, 0xBD, 0x73, 0xC5, 0xB3, 0xB5, 0x51, 
+0xAD, 0x31, 0x9C, 0x6E, 0xAC, 0xF0, 0xB5, 0x10, 
+0xBD, 0x92, 0xC5, 0xB3, 0xC5, 0xB4, 0xC5, 0xB4, 
+0xC5, 0xD4, 0xC5, 0xD5, 0xBD, 0xB4, 0xBD, 0xD5, 
+0xA4, 0xD1, 0x94, 0x4F, 0xAD, 0x32, 0xBD, 0xB4, 
+0xAD, 0x11, 0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x32, 
+0xA4, 0xD0, 0x8C, 0x2E, 0xA4, 0xF1, 0x9C, 0x6F, 
+0x9C, 0xB0, 0x9C, 0xAF, 0xB5, 0x10, 0xBD, 0xB3, 
+0xBD, 0xD5, 0xB5, 0x94, 0xBD, 0xD4, 0xBD, 0xB4, 
+0xBD, 0xD5, 0xB5, 0x74, 0xC5, 0xF5, 0xBD, 0xB4, 
+0xB5, 0x73, 0xBD, 0xD5, 0xBD, 0xD5, 0xB5, 0x94, 
+0xB5, 0xB4, 0xBD, 0xD5, 0xBD, 0xB4, 0xA5, 0x11, 
+0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x32, 0xB5, 0x73, 
+0xC5, 0xF5, 0xA4, 0xCF, 0xA4, 0x8E, 0xB5, 0x52, 
+0xBD, 0x93, 0xCD, 0xF4, 0xCD, 0xF4, 0xCD, 0xD3, 
+0xCD, 0xD3, 0xCD, 0xF4, 0x9C, 0xB0, 0x8C, 0x4F, 
+0x84, 0x0E, 0x73, 0x6D, 0x41, 0xE7, 0x39, 0xA6, 
+0x29, 0x44, 0x39, 0xC6, 0x39, 0xC6, 0x52, 0x69, 
+0x52, 0x89, 0x5A, 0xAA, 0x63, 0x0C, 0x73, 0x8D, 
+0x94, 0x91, 0x8C, 0x30, 0x7B, 0xAE, 0x6B, 0x2C, 
+0x42, 0x07, 0x39, 0xA6, 0x39, 0xC7, 0x42, 0x08, 
+0x4A, 0x28, 0xA4, 0xF1, 0xB5, 0x31, 0x9C, 0x6E, 
+0xAC, 0xF0, 0xB5, 0x31, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xC5, 0x72, 0x94, 0x0C, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xAD, 0x31, 0xA4, 0xAF, 0xAD, 0x11, 0xAD, 0x11, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xAC, 0xF0, 0x9C, 0xB0, 
+0x84, 0x0D, 0x94, 0x6F, 0xA4, 0xF0, 0xAD, 0x11, 
+0xB5, 0x73, 0x73, 0x6C, 0x4A, 0x48, 0x63, 0x2B, 
+0x29, 0x64, 0x42, 0x27, 0x42, 0x07, 0x39, 0xC6, 
+0x84, 0x10, 0x94, 0xB3, 0xD6, 0x7A, 0xA5, 0x35, 
+0x8C, 0x51, 0x8C, 0x52, 0x9C, 0xF4, 0x8C, 0x52, 
+0x7B, 0xAF, 0x84, 0x10, 0xC5, 0xD7, 0x62, 0xCB, 
+0x62, 0xEC, 0x84, 0x10, 0x9C, 0xD3, 0xAD, 0x34, 
+0xA4, 0xD2, 0xAC, 0xD0, 0xA4, 0xB0, 0xB5, 0x53, 
+0xB5, 0x73, 0xC5, 0xB4, 0xC5, 0xD5, 0xC5, 0xD5, 
+0xC5, 0xB4, 0xBD, 0x94, 0xB5, 0x52, 0xB5, 0x53, 
+0xC5, 0xD5, 0xC5, 0xB4, 0xC5, 0xB4, 0xBD, 0x93, 
+0xBD, 0x94, 0xC5, 0xB4, 0xBD, 0x94, 0xBD, 0x94, 
+0xB5, 0x53, 0xB5, 0x32, 0xAD, 0x12, 0xAD, 0x32, 
+0xAD, 0x12, 0xAD, 0x53, 0x9C, 0x90, 0x41, 0xE7, 
+0x20, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC3, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xC4, 0x18, 0xC4, 0x10, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xE4, 0x21, 0x05, 0x18, 0xE4, 
+0x20, 0xA3, 0x61, 0x87, 0x71, 0x26, 0x89, 0xE9, 
+0x30, 0x83, 0x20, 0xC4, 0x18, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x21, 0x05, 0x21, 0x05, 0x29, 0x25, 
+0x29, 0x46, 0x29, 0x66, 0x31, 0x87, 0x31, 0xA7, 
+0x39, 0xC8, 0x39, 0xC8, 0x31, 0xA7, 0x39, 0xA8, 
+0x39, 0xC8, 0x39, 0xC8, 0x31, 0x87, 0x31, 0x87, 
+0x31, 0x66, 0x29, 0x66, 0x29, 0x66, 0x29, 0x66, 
+0x29, 0x66, 0x29, 0x46, 0x29, 0x46, 0x21, 0x25, 
+0x29, 0x46, 0x29, 0x46, 0x31, 0x87, 0x31, 0xA7, 
+0x39, 0xC8, 0x4A, 0x4A, 0x4A, 0x6A, 0x52, 0x6B, 
+0x5A, 0xAB, 0x63, 0x0C, 0x7B, 0xCF, 0xA4, 0xF3, 
+0xBD, 0xB5, 0xBD, 0xD5, 0xA5, 0x12, 0x94, 0x90, 
+0xBD, 0x94, 0xCE, 0x14, 0xBD, 0x72, 0xC5, 0xD4, 
+0xAD, 0x52, 0xAD, 0x32, 0xB5, 0x94, 0xBD, 0xD5, 
+0xBD, 0xD5, 0xBD, 0xB4, 0xB5, 0x52, 0xBD, 0xB3, 
+0xB5, 0x51, 0xB5, 0x31, 0xAD, 0x31, 0xAD, 0x52, 
+0xC6, 0x15, 0xBD, 0xB5, 0xB5, 0xB4, 0xB5, 0x93, 
+0xA4, 0xF1, 0xC5, 0xF4, 0xCE, 0x14, 0xC5, 0xD4, 
+0xA4, 0xB0, 0xBD, 0x93, 0x94, 0x4F, 0xAC, 0xD0, 
+0xAC, 0xF0, 0xBD, 0x93, 0xAD, 0x31, 0xBD, 0x73, 
+0xCE, 0x15, 0xA4, 0xF0, 0xAD, 0x11, 0xB5, 0x52, 
+0xA4, 0xD0, 0xA4, 0xF1, 0xA4, 0xD0, 0xAD, 0x32, 
+0xC5, 0xF5, 0xC5, 0xD4, 0xC5, 0xF5, 0x6B, 0x4C, 
+0x62, 0xEC, 0x4A, 0x29, 0x52, 0x69, 0x63, 0x0C, 
+0x6B, 0x4D, 0x5A, 0xCB, 0x6B, 0x2D, 0x73, 0x8E, 
+0x84, 0x10, 0xAD, 0x76, 0x6B, 0x6E, 0x73, 0xAF, 
+0x84, 0x10, 0x9C, 0xF3, 0xBD, 0xB5, 0xC5, 0xD4, 
+0xC6, 0x14, 0xBD, 0xB3, 0xAD, 0x11, 0xC5, 0xD3, 
+0xCE, 0x35, 0xCE, 0x15, 0xCE, 0x35, 0xC5, 0xF4, 
+0x74, 0xAA, 0x8D, 0x4F, 0x9D, 0x71, 0x7C, 0x4D, 
+0x63, 0x49, 0x52, 0xE8, 0x5A, 0xC8, 0x63, 0x29, 
+0x5B, 0x26, 0x7C, 0x68, 0x84, 0x87, 0x95, 0x2B, 
+0xAD, 0xB0, 0xAD, 0x90, 0x8C, 0x6C, 0x9C, 0x8F, 
+0x9C, 0x8F, 0x9C, 0x8E, 0x9C, 0xAF, 0xAD, 0x11, 
+0xB5, 0x32, 0xBD, 0x93, 0xB5, 0x52, 0xBD, 0x93, 
+0xB5, 0x52, 0x83, 0xCB, 0xB5, 0x10, 0xB5, 0x30, 
+0xC5, 0xD3, 0xCE, 0x15, 0xD6, 0x35, 0xCE, 0x15, 
+0xCE, 0x35, 0xCE, 0x35, 0xC5, 0xF5, 0xCE, 0x16, 
+0x8C, 0x0E, 0xC5, 0xD5, 0xC5, 0xD5, 0xBD, 0xB4, 
+0xB5, 0x94, 0xB5, 0x94, 0xB5, 0x73, 0xBD, 0x94, 
+0xBD, 0x94, 0xB5, 0x73, 0xAD, 0x32, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xA4, 0xF0, 0xB5, 0x31, 0xC5, 0xF4, 
+0xC5, 0xF6, 0xB5, 0x94, 0xC6, 0x16, 0xBD, 0xD5, 
+0xBD, 0xD5, 0xC5, 0xF6, 0xC6, 0x16, 0xC6, 0x36, 
+0xC6, 0x15, 0xC5, 0xF5, 0xBD, 0xD5, 0xB5, 0xB4, 
+0xC6, 0x16, 0xBD, 0xD5, 0xBD, 0xD5, 0xBD, 0xD5, 
+0xC6, 0x16, 0xC6, 0x15, 0xB5, 0x73, 0xBD, 0xB4, 
+0xBD, 0x93, 0xB5, 0x10, 0xA4, 0x8E, 0xAD, 0x11, 
+0xC5, 0xD4, 0xCD, 0xF4, 0xD5, 0xF4, 0xCD, 0xD3, 
+0xCD, 0xF3, 0xD6, 0x15, 0xA4, 0xD1, 0x9C, 0xD1, 
+0x8C, 0x2F, 0x94, 0x71, 0x52, 0x89, 0x41, 0xE7, 
+0x39, 0xC6, 0x39, 0xA6, 0x41, 0xE7, 0x4A, 0x28, 
+0x4A, 0x49, 0x63, 0x0B, 0x6B, 0x4C, 0x6B, 0x4C, 
+0x73, 0x8E, 0x7B, 0xCE, 0x8C, 0x51, 0x73, 0x8E, 
+0x5A, 0xAA, 0x52, 0x69, 0x8C, 0x71, 0x7B, 0xAE, 
+0x52, 0x69, 0xA4, 0xF1, 0xC5, 0xD4, 0xAC, 0xF0, 
+0x9C, 0xAF, 0xAD, 0x31, 0xCD, 0xF5, 0xA4, 0xAF, 
+0xBD, 0x51, 0x94, 0x4D, 0xAC, 0xF0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xA4, 0xF1, 0xAD, 0x32, 0xB5, 0x52, 
+0xB5, 0x52, 0xAD, 0x31, 0xAD, 0x11, 0xB5, 0x73, 
+0xAD, 0x52, 0xB5, 0x73, 0xAD, 0x52, 0xB5, 0x73, 
+0xBD, 0xB4, 0xB5, 0x73, 0xA5, 0x12, 0x63, 0x0B, 
+0x18, 0xE3, 0x29, 0x64, 0x31, 0xA5, 0x4A, 0x69, 
+0x94, 0xB2, 0xC6, 0x39, 0xC5, 0xF8, 0xA4, 0xF4, 
+0x84, 0x11, 0x84, 0x31, 0x7B, 0xCF, 0x7B, 0xD0, 
+0x73, 0x6E, 0x94, 0x72, 0xCE, 0x38, 0xB5, 0x55, 
+0x52, 0x49, 0x4A, 0x28, 0x5A, 0xAA, 0x5A, 0x8A, 
+0xA4, 0xF2, 0xBD, 0x52, 0x9C, 0x6E, 0xAD, 0x11, 
+0xB5, 0x52, 0xB5, 0x52, 0xA4, 0xD0, 0xA4, 0xB0, 
+0xBD, 0x73, 0x9C, 0x8F, 0xA4, 0xD0, 0xB5, 0x31, 
+0xAD, 0x11, 0xAD, 0x11, 0xA4, 0xD0, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xA4, 0xB0, 0xA4, 0xB0, 0xAD, 0x12, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xD0, 0xAD, 0x12, 
+0xB5, 0x53, 0xB5, 0x73, 0x94, 0x4F, 0x31, 0x86, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 
+0x10, 0xC4, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xA3, 
+0x38, 0xE4, 0x71, 0x46, 0x89, 0xA8, 0x61, 0x46, 
+0x20, 0xA3, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x21, 0x05, 0x21, 0x05, 0x21, 0x25, 
+0x21, 0x05, 0x21, 0x25, 0x21, 0x25, 0x29, 0x46, 
+0x31, 0xA7, 0x39, 0xC8, 0x39, 0xC8, 0x31, 0x87, 
+0x31, 0x87, 0x31, 0x87, 0x31, 0x66, 0x29, 0x46, 
+0x31, 0x66, 0x31, 0x87, 0x31, 0x66, 0x29, 0x66, 
+0x29, 0x46, 0x29, 0x46, 0x29, 0x46, 0x29, 0x46, 
+0x21, 0x25, 0x21, 0x05, 0x29, 0x46, 0x31, 0x87, 
+0x39, 0xC8, 0x39, 0xC8, 0x41, 0xE9, 0x4A, 0x29, 
+0x52, 0x8B, 0x52, 0x8B, 0x52, 0x8B, 0x5A, 0xCC, 
+0x73, 0x8E, 0x94, 0x91, 0x94, 0x91, 0x94, 0x90, 
+0xBD, 0x73, 0xC5, 0xF4, 0xBD, 0x92, 0xC5, 0xD4, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0xD4, 
+0xC6, 0x16, 0xBD, 0xB4, 0xB5, 0x93, 0xC5, 0xB3, 
+0xC5, 0xD3, 0xC5, 0xF4, 0xB5, 0x93, 0xB5, 0x73, 
+0xC5, 0xF5, 0xC5, 0xF5, 0xB5, 0x94, 0xBD, 0xB4, 
+0xB5, 0x52, 0xC5, 0xD4, 0xCE, 0x35, 0xBD, 0xD3, 
+0xAD, 0x11, 0xC5, 0xB4, 0x94, 0x2E, 0xA4, 0xAF, 
+0xB5, 0x51, 0xC5, 0xD4, 0xCE, 0x15, 0xD6, 0x35, 
+0xCE, 0x15, 0xB5, 0x72, 0xBD, 0xB3, 0xCE, 0x15, 
+0xC5, 0xF4, 0xBD, 0xB4, 0xB5, 0x53, 0xAD, 0x52, 
+0xC5, 0xF4, 0xC5, 0xD4, 0xC5, 0xB4, 0xAD, 0x32, 
+0x6B, 0x0B, 0x52, 0x8A, 0x5A, 0xAA, 0x84, 0x10, 
+0x8C, 0x51, 0x39, 0xC7, 0x4A, 0x4A, 0x8C, 0x31, 
+0x84, 0x10, 0xC5, 0xF8, 0x9C, 0xB3, 0x84, 0x31, 
+0x8C, 0x51, 0x6B, 0x4D, 0xAD, 0x13, 0xCE, 0x15, 
+0xCE, 0x35, 0xBD, 0xD3, 0xB5, 0x72, 0xC5, 0xD4, 
+0xCE, 0x34, 0xD6, 0x55, 0xC5, 0xF3, 0xC5, 0xF4, 
+0x7D, 0x0C, 0x7C, 0xEC, 0x6C, 0x4B, 0x7C, 0x8B, 
+0x84, 0x8C, 0x8C, 0x8C, 0x84, 0x0B, 0x8C, 0x0C, 
+0x94, 0x6D, 0x94, 0xCC, 0x7C, 0x68, 0x5B, 0x84, 
+0x63, 0xE5, 0x7C, 0x68, 0x9C, 0xEC, 0x9C, 0x6D, 
+0x94, 0x2D, 0x94, 0x2D, 0x94, 0x2D, 0x94, 0x2D, 
+0x94, 0x2D, 0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x6E, 
+0x8B, 0xEC, 0x7B, 0x6A, 0xB5, 0x10, 0x8B, 0xCB, 
+0x94, 0x4D, 0xA4, 0xAF, 0xA4, 0xD0, 0xA4, 0x8F, 
+0xA4, 0xB0, 0xAD, 0x11, 0xB5, 0x32, 0xB5, 0x73, 
+0xB5, 0x53, 0xB5, 0x93, 0xB5, 0x73, 0xBD, 0x94, 
+0xC5, 0xF5, 0xCE, 0x15, 0xCE, 0x16, 0xCE, 0x36, 
+0xC5, 0xD5, 0xC5, 0xD5, 0xB5, 0x73, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xB5, 0x31, 0xBD, 0x51, 0xBD, 0xB4, 
+0xCE, 0x57, 0xBD, 0xF5, 0xC6, 0x16, 0xCE, 0x57, 
+0xCE, 0x36, 0xC6, 0x36, 0xCE, 0x36, 0xC6, 0x16, 
+0xC6, 0x16, 0xC6, 0x16, 0xC5, 0xF5, 0xBD, 0xF5, 
+0xC6, 0x16, 0xBD, 0xD5, 0xC5, 0xF5, 0xBD, 0xD5, 
+0xBD, 0xB4, 0xC5, 0xF5, 0xB5, 0x73, 0xB5, 0x73, 
+0xBD, 0xB4, 0xAD, 0x10, 0x9C, 0x6E, 0x94, 0x4E, 
+0xC5, 0xD4, 0xCD, 0xD3, 0xDE, 0x35, 0xCD, 0xF4, 
+0xCD, 0xB3, 0xD6, 0x15, 0xAD, 0x12, 0xAD, 0x33, 
+0x9C, 0xF2, 0x9C, 0xF2, 0x8C, 0x50, 0x4A, 0x28, 
+0x42, 0x07, 0x4A, 0x28, 0x41, 0xE7, 0x4A, 0x48, 
+0x5A, 0xCA, 0x5A, 0xEB, 0x5A, 0xCA, 0x5A, 0xCB, 
+0x62, 0xEB, 0x83, 0xEF, 0x94, 0x92, 0x8C, 0x30, 
+0x7B, 0xCF, 0x6B, 0x2D, 0x9C, 0xB3, 0x83, 0xF0, 
+0x62, 0xEB, 0x83, 0xEE, 0xCE, 0x35, 0xC5, 0xD4, 
+0xA5, 0x11, 0xBD, 0xB3, 0xCE, 0x15, 0x9C, 0x8F, 
+0xB5, 0x51, 0x7B, 0x6A, 0x94, 0x6F, 0xAD, 0x11, 
+0xAD, 0x11, 0xC5, 0xD4, 0xC6, 0x15, 0xC5, 0xF5, 
+0xCE, 0x36, 0xBD, 0xD4, 0xBD, 0xD4, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xCE, 0x56, 0xC5, 0xD5, 
+0xBD, 0xD4, 0xBD, 0xD4, 0xB5, 0x94, 0x8C, 0x50, 
+0x4A, 0x49, 0x42, 0x28, 0x29, 0x44, 0x39, 0xE7, 
+0x7B, 0xCF, 0xB5, 0x96, 0xAD, 0x55, 0x9C, 0xD4, 
+0x73, 0x8F, 0x52, 0xAB, 0x63, 0x2D, 0x73, 0x6E, 
+0x73, 0x6E, 0x73, 0x6E, 0xB5, 0x96, 0xBD, 0x96, 
+0x7B, 0xAE, 0x62, 0xEB, 0x39, 0xA6, 0x62, 0xEB, 
+0x9C, 0x91, 0xB5, 0x52, 0xA4, 0xB0, 0xC5, 0xB3, 
+0xC5, 0xD3, 0xC5, 0xB3, 0xB5, 0x52, 0x9C, 0x90, 
+0xB5, 0x52, 0xC5, 0xB3, 0xC5, 0xD3, 0xCD, 0xD3, 
+0xDE, 0x75, 0xC5, 0xB3, 0xBD, 0x72, 0xBD, 0x92, 
+0xD6, 0x14, 0xC5, 0x93, 0xA4, 0xB0, 0xA4, 0xF0, 
+0xAC, 0xF0, 0x9C, 0x8F, 0x9C, 0x6F, 0xBD, 0x73, 
+0xB5, 0x53, 0xAD, 0x12, 0x7B, 0xAD, 0x29, 0x45, 
+0x21, 0x04, 0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x08, 0x83, 0x10, 0xA3, 0x18, 0xC4, 
+0x10, 0xC3, 0x10, 0xC3, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x20, 0x83, 
+0x61, 0x26, 0x81, 0x67, 0x91, 0xE9, 0x38, 0xA3, 
+0x18, 0xA3, 0x18, 0xA3, 0x18, 0xA3, 0x18, 0xA3, 
+0x18, 0xA3, 0x10, 0xA3, 0x18, 0xA3, 0x18, 0xA3, 
+0x18, 0xA3, 0x18, 0xC3, 0x18, 0xC3, 0x18, 0xE4, 
+0x20, 0xE4, 0x21, 0x05, 0x21, 0x05, 0x21, 0x25, 
+0x29, 0x25, 0x29, 0x46, 0x29, 0x46, 0x31, 0x66, 
+0x31, 0x87, 0x39, 0xA7, 0x31, 0xA7, 0x31, 0x87, 
+0x31, 0x66, 0x29, 0x25, 0x21, 0x25, 0x21, 0x05, 
+0x21, 0x25, 0x29, 0x46, 0x29, 0x46, 0x21, 0x25, 
+0x29, 0x46, 0x29, 0x25, 0x29, 0x25, 0x29, 0x25, 
+0x29, 0x25, 0x29, 0x46, 0x29, 0x46, 0x29, 0x46, 
+0x31, 0x87, 0x31, 0xA7, 0x31, 0x87, 0x31, 0xA7, 
+0x41, 0xE8, 0x4A, 0x29, 0x4A, 0x4A, 0x4A, 0x4A, 
+0x4A, 0x6A, 0x52, 0xAB, 0x63, 0x2C, 0x84, 0x0F, 
+0xB5, 0x53, 0xC5, 0xF4, 0xCE, 0x14, 0xCE, 0x15, 
+0xCE, 0x36, 0xC5, 0xF5, 0xB5, 0x73, 0xB5, 0xB4, 
+0xC6, 0x36, 0xBD, 0xB4, 0xC6, 0x15, 0xCE, 0x55, 
+0xCE, 0x35, 0xD6, 0x76, 0xBD, 0xB4, 0xB5, 0x94, 
+0xBD, 0xD5, 0xBD, 0xD4, 0xB5, 0x94, 0xB5, 0x94, 
+0xBD, 0x93, 0xBD, 0x93, 0xD6, 0x76, 0xC5, 0xD4, 
+0xB5, 0x52, 0xC5, 0xB3, 0x94, 0x0E, 0x7B, 0x6B, 
+0x94, 0x4E, 0xBD, 0xB3, 0xB5, 0x92, 0xC5, 0xD3, 
+0xAD, 0x11, 0xAC, 0xF0, 0xB5, 0x52, 0xC5, 0xD3, 
+0xC5, 0xF4, 0xBD, 0xD4, 0xB5, 0x73, 0xB5, 0x53, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xCE, 0x15, 0xB5, 0x73, 
+0x9C, 0xB0, 0x5A, 0xEB, 0x62, 0xEB, 0x7B, 0xCF, 
+0x73, 0xAE, 0x52, 0x6A, 0x52, 0x6A, 0x6B, 0x4D, 
+0x63, 0x0D, 0x84, 0x10, 0x8C, 0x31, 0x63, 0x0C, 
+0x42, 0x08, 0x31, 0x87, 0xAD, 0x34, 0xCE, 0x36, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xC6, 0x14, 0xC5, 0xD4, 
+0xCE, 0x55, 0xC6, 0x14, 0xC5, 0xF4, 0xBD, 0xD3, 
+0x5B, 0xE7, 0x6C, 0x4A, 0x8D, 0x0E, 0x7C, 0x4C, 
+0x63, 0x89, 0x8C, 0x6C, 0x7B, 0xCB, 0x84, 0x0C, 
+0xAD, 0x31, 0x9C, 0xEF, 0x73, 0xE7, 0x6C, 0x06, 
+0x64, 0x26, 0x84, 0xA9, 0xAD, 0x2E, 0xAD, 0x10, 
+0xA4, 0x8E, 0x9C, 0x6D, 0x9C, 0x6D, 0xAC, 0xEF, 
+0xB5, 0x10, 0xAC, 0xEF, 0xB5, 0x10, 0xB5, 0x30, 
+0xBD, 0x31, 0xB5, 0x30, 0xB5, 0x30, 0xAC, 0xAF, 
+0xAC, 0xAF, 0xA4, 0x8E, 0xA4, 0x8E, 0xB4, 0xF0, 
+0xB4, 0xF0, 0xAC, 0xAF, 0xA4, 0x8F, 0xA4, 0x8E, 
+0x9C, 0x6E, 0x9C, 0x4D, 0x94, 0x0D, 0x94, 0x2D, 
+0x93, 0xEC, 0x8B, 0xEC, 0x9C, 0x4E, 0x9C, 0x8E, 
+0x9C, 0x8F, 0xA4, 0xD0, 0xAC, 0xF0, 0xA4, 0xF0, 
+0xAD, 0x11, 0xBD, 0x51, 0xC5, 0x71, 0xBD, 0x51, 
+0xBD, 0x72, 0xB5, 0x72, 0xAD, 0x31, 0xB5, 0x72, 
+0xB5, 0x52, 0xB5, 0x52, 0xC5, 0xD4, 0xC6, 0x15, 
+0xCE, 0x36, 0xCE, 0x56, 0xCE, 0x57, 0xD6, 0x77, 
+0xD6, 0x77, 0xCE, 0x56, 0xD6, 0x77, 0xCE, 0x36, 
+0xCE, 0x16, 0xCE, 0x36, 0xC5, 0xF5, 0xC5, 0xD4, 
+0xB5, 0x73, 0xB5, 0x10, 0xAC, 0xEF, 0x8C, 0x0D, 
+0xCD, 0xF4, 0xD6, 0x55, 0xCE, 0x14, 0xCD, 0xF4, 
+0xD6, 0x35, 0xDE, 0x56, 0xBD, 0x73, 0xA4, 0xF2, 
+0x9C, 0xF2, 0x9C, 0xF2, 0xAD, 0x33, 0x73, 0x8D, 
+0x41, 0xE7, 0x41, 0xE7, 0x41, 0xE7, 0x52, 0x69, 
+0x41, 0xE7, 0x4A, 0x28, 0x52, 0x69, 0x4A, 0x49, 
+0x52, 0x8A, 0x73, 0x6D, 0x94, 0x72, 0x9C, 0xB2, 
+0x94, 0x92, 0x84, 0x10, 0xAD, 0x55, 0xA4, 0xF3, 
+0x6B, 0x2C, 0x62, 0xEA, 0xCE, 0x36, 0xCE, 0x35, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xCE, 0x15, 0xB5, 0x31, 
+0xB5, 0x30, 0x7B, 0x8B, 0x94, 0x6F, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xBD, 0x93, 0xB5, 0x52, 0xBD, 0x93, 
+0xB5, 0x72, 0xA4, 0xF1, 0xBD, 0xB4, 0xB5, 0x73, 
+0x9C, 0xD1, 0xBD, 0xD5, 0xC5, 0xF5, 0xBD, 0x94, 
+0xC5, 0xF5, 0xC5, 0xF5, 0xC6, 0x15, 0xCE, 0x57, 
+0xA5, 0x33, 0x52, 0xA9, 0x39, 0xC7, 0x21, 0x03, 
+0x52, 0xAB, 0xBD, 0xF8, 0xA5, 0x14, 0x8C, 0x72, 
+0x63, 0x2D, 0x42, 0x08, 0x62, 0xEC, 0x6B, 0x4D, 
+0x6B, 0x2D, 0x5A, 0xCB, 0x63, 0x2D, 0x7B, 0xAF, 
+0x73, 0x6D, 0x83, 0xF0, 0x7B, 0x6E, 0x62, 0xEC, 
+0x94, 0x70, 0xBD, 0x94, 0xAD, 0x12, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xC5, 0xB3, 0xA4, 0xB0, 
+0xB5, 0x52, 0xCD, 0xD4, 0xBD, 0x71, 0xCD, 0xD3, 
+0xCD, 0xD3, 0xC5, 0x72, 0xC5, 0x92, 0xC5, 0xB2, 
+0xDE, 0x35, 0xCD, 0xD3, 0xB5, 0x11, 0xB5, 0x31, 
+0xBD, 0x72, 0xBD, 0x72, 0xAC, 0xF1, 0xAD, 0x11, 
+0x94, 0x6F, 0x94, 0x6F, 0x73, 0x6C, 0x29, 0x25, 
+0x18, 0xE4, 0x21, 0x05, 0x18, 0xE4, 0x10, 0xA3, 
+0x10, 0xC3, 0x18, 0xE4, 0x19, 0x04, 0x18, 0xE4, 
+0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x40, 0xE4, 
+0x79, 0x46, 0x91, 0x87, 0x69, 0x46, 0x20, 0xA3, 
+0x18, 0xC4, 0x18, 0xA3, 0x18, 0xA3, 0x18, 0xC3, 
+0x18, 0xA3, 0x18, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xA3, 0x18, 0xC3, 0x18, 0xC4, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x25, 0x21, 0x05, 0x21, 0x05, 0x21, 0x25, 
+0x29, 0x46, 0x29, 0x25, 0x21, 0x25, 0x29, 0x25, 
+0x29, 0x66, 0x29, 0x46, 0x21, 0x25, 0x21, 0x05, 
+0x20, 0xE4, 0x21, 0x05, 0x29, 0x46, 0x29, 0x46, 
+0x21, 0x25, 0x21, 0x25, 0x21, 0x05, 0x18, 0xE4, 
+0x21, 0x25, 0x29, 0x25, 0x29, 0x46, 0x29, 0x46, 
+0x29, 0x46, 0x29, 0x46, 0x31, 0x67, 0x31, 0xA7, 
+0x39, 0xA7, 0x39, 0xC8, 0x41, 0xE9, 0x42, 0x09, 
+0x4A, 0x2A, 0x4A, 0x4A, 0x4A, 0x4A, 0x52, 0x8A, 
+0x6B, 0x0C, 0x8C, 0x2F, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xA4, 0xF1, 0x9C, 0xD0, 0xAD, 0x12, 
+0xBD, 0xD4, 0xBD, 0xD4, 0xCE, 0x35, 0xD6, 0x96, 
+0xD6, 0x96, 0xD6, 0x76, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xC6, 0x16, 0xC6, 0x16, 0xBD, 0xD4, 0xBD, 0xB4, 
+0xB5, 0x52, 0xCE, 0x35, 0xDE, 0x96, 0xBD, 0xB3, 
+0xB5, 0x52, 0xBD, 0x73, 0xAD, 0x12, 0x94, 0x4F, 
+0x8C, 0x0D, 0xA4, 0xAF, 0xA4, 0xD0, 0xAD, 0x11, 
+0xA4, 0xD0, 0xAD, 0x11, 0xAD, 0x11, 0xB5, 0x31, 
+0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x73, 
+0xBD, 0xB4, 0xC5, 0xF4, 0xBD, 0xB3, 0xAD, 0x11, 
+0xAD, 0x52, 0x7B, 0xCD, 0x5A, 0xCA, 0x63, 0x0C, 
+0x63, 0x0C, 0x84, 0x10, 0x9C, 0xD3, 0x9C, 0xD3, 
+0x6B, 0x2D, 0x42, 0x29, 0x5A, 0xCB, 0x39, 0xE7, 
+0x39, 0xA6, 0x39, 0x87, 0xB5, 0x75, 0xDE, 0xDA, 
+0xAD, 0x32, 0xC5, 0xF4, 0xC6, 0x15, 0xBD, 0xD3, 
+0xC6, 0x14, 0xB5, 0x92, 0xC6, 0x14, 0xBD, 0xD4, 
+0x8D, 0x6E, 0x9D, 0xD0, 0x8D, 0x2E, 0x74, 0x4C, 
+0x7C, 0x2C, 0x94, 0xCF, 0x8C, 0x4E, 0x94, 0x4E, 
+0xAD, 0x31, 0xBD, 0xD3, 0xA5, 0x4E, 0x74, 0x47, 
+0x84, 0xCA, 0x9D, 0x4E, 0xBD, 0xD2, 0xC5, 0xF4, 
+0xC5, 0xD4, 0xD6, 0x76, 0xBD, 0x72, 0xAC, 0xCF, 
+0xA4, 0x8E, 0x93, 0xCC, 0x93, 0xEC, 0x83, 0x6A, 
+0x83, 0x8B, 0x83, 0x8A, 0x83, 0x8A, 0x83, 0xAB, 
+0x83, 0xAB, 0x83, 0x8A, 0x94, 0x0C, 0x94, 0x0C, 
+0x93, 0xEC, 0x9C, 0x2D, 0x9C, 0x4D, 0xA4, 0x8E, 
+0xAC, 0xAF, 0xAC, 0xAF, 0xBD, 0x30, 0xBD, 0x31, 
+0xB5, 0x10, 0xBD, 0x51, 0xBD, 0x30, 0xBD, 0x30, 
+0xB5, 0x10, 0xB4, 0xF0, 0xAC, 0xCF, 0xAC, 0xF0, 
+0xB5, 0x10, 0xBD, 0x30, 0xBD, 0x50, 0xB5, 0x10, 
+0xBD, 0x30, 0xBD, 0x51, 0xBD, 0x51, 0xBD, 0x51, 
+0xB5, 0x30, 0xB5, 0x30, 0xB5, 0x10, 0xB5, 0x10, 
+0xAD, 0x0F, 0xAC, 0xEF, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xD0, 0xAC, 0xD0, 0xAD, 0x11, 
+0xBD, 0x72, 0xBD, 0x93, 0xBD, 0x72, 0xB5, 0x52, 
+0xB5, 0x10, 0xC5, 0x71, 0xBD, 0x31, 0x7B, 0x6A, 
+0xAD, 0x10, 0xC5, 0xB3, 0xBD, 0x72, 0xC5, 0x92, 
+0xCD, 0xF4, 0xD6, 0x35, 0xB5, 0x32, 0x9C, 0xB0, 
+0x9C, 0xD1, 0x9C, 0xD1, 0x9C, 0xF1, 0xB5, 0x73, 
+0x5A, 0xC9, 0x41, 0xE7, 0x39, 0xC6, 0x39, 0xC7, 
+0x41, 0xE7, 0x52, 0x8A, 0x5A, 0xCB, 0x62, 0xEB, 
+0x63, 0x0C, 0x6B, 0x6D, 0x94, 0x71, 0xA4, 0xF4, 
+0x9C, 0xF4, 0x9C, 0xD3, 0xC6, 0x18, 0xAD, 0x34, 
+0x7B, 0xAF, 0x8C, 0x50, 0xBD, 0xD5, 0xD6, 0x56, 
+0xCE, 0x35, 0xCE, 0x35, 0xD6, 0x56, 0xA4, 0xD0, 
+0xB5, 0x30, 0x83, 0xCC, 0x9C, 0xB0, 0xAD, 0x32, 
+0xB5, 0x52, 0xA5, 0x11, 0xA4, 0xF1, 0xA5, 0x11, 
+0xB5, 0x73, 0xB5, 0x93, 0xB5, 0x93, 0xB5, 0x53, 
+0x9C, 0xD0, 0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x53, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xC5, 0xF5, 0xCE, 0x36, 
+0xCE, 0x76, 0xBD, 0xD5, 0x5A, 0xCA, 0x29, 0x65, 
+0x5A, 0xEC, 0xCE, 0x59, 0xAD, 0x76, 0x8C, 0x52, 
+0x52, 0x8A, 0x42, 0x08, 0x52, 0xAA, 0x5A, 0xEB, 
+0x63, 0x2C, 0x5A, 0xEC, 0x52, 0x8A, 0x4A, 0x49, 
+0x52, 0x69, 0x6B, 0x2D, 0xA4, 0xF3, 0x7B, 0x8E, 
+0x73, 0x4D, 0x9C, 0x71, 0xCE, 0x16, 0xC5, 0xD4, 
+0xBD, 0x92, 0xC5, 0xB2, 0xC5, 0xD3, 0xA4, 0xD0, 
+0xB5, 0x31, 0xC5, 0x92, 0xB5, 0x0F, 0xC5, 0x92, 
+0xD6, 0x34, 0xC5, 0xB2, 0xC5, 0x92, 0xBD, 0x51, 
+0xC5, 0x92, 0xB5, 0x10, 0xAC, 0xD0, 0xBD, 0x72, 
+0xCD, 0xB3, 0xBD, 0x71, 0x9C, 0xAF, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xA4, 0xD1, 0x6B, 0x4C, 0x29, 0x25, 
+0x20, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x05, 0x19, 0x04, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC3, 0x18, 0xA3, 0x59, 0x46, 
+0x89, 0x67, 0x89, 0x67, 0x38, 0xC3, 0x18, 0xA3, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xA3, 0x18, 0xA3, 0x18, 0xA3, 0x18, 0xC4, 
+0x18, 0xA3, 0x18, 0xC3, 0x18, 0xC4, 0x18, 0xE4, 
+0x20, 0xE4, 0x21, 0x05, 0x20, 0xE4, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x25, 0x21, 0x25, 0x21, 0x05, 0x21, 0x25, 
+0x29, 0x25, 0x29, 0x46, 0x21, 0x25, 0x21, 0x05, 
+0x18, 0xE4, 0x21, 0x05, 0x21, 0x25, 0x29, 0x26, 
+0x29, 0x25, 0x21, 0x05, 0x21, 0x05, 0x18, 0xE4, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x25, 0x21, 0x25, 
+0x21, 0x05, 0x21, 0x25, 0x29, 0x46, 0x31, 0xA7, 
+0x39, 0xC8, 0x31, 0xA7, 0x39, 0xA8, 0x39, 0xC8, 
+0x41, 0xE9, 0x42, 0x09, 0x42, 0x2A, 0x4A, 0x2A, 
+0x42, 0x29, 0x4A, 0x29, 0x63, 0x0C, 0x94, 0x50, 
+0xAD, 0x12, 0xB5, 0x53, 0xB5, 0x53, 0xAC, 0xF1, 
+0xA4, 0xB0, 0x9C, 0x6F, 0x94, 0x2E, 0x8B, 0xED, 
+0x83, 0xED, 0x83, 0xCD, 0x83, 0xCD, 0x84, 0x0E, 
+0x9C, 0x70, 0x94, 0x6F, 0x83, 0xEE, 0x9C, 0xB0, 
+0xA4, 0xD0, 0xB5, 0x32, 0xAD, 0x11, 0x94, 0x6E, 
+0xA4, 0xD0, 0x9C, 0x8F, 0x9C, 0x90, 0xA4, 0xF1, 
+0xA4, 0xD1, 0xAD, 0x31, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xAD, 0x11, 0xB5, 0x52, 0xB5, 0x52, 
+0xB5, 0x52, 0xB5, 0x52, 0xAD, 0x12, 0x9C, 0x8F, 
+0xBD, 0x93, 0xC5, 0xD3, 0xA4, 0xD0, 0xB5, 0x73, 
+0x9C, 0x8F, 0x73, 0x8C, 0x73, 0x8D, 0x62, 0xEB, 
+0x5A, 0xEB, 0x84, 0x10, 0xBD, 0xB6, 0x9C, 0xF3, 
+0x73, 0x6E, 0x4A, 0x49, 0x63, 0x2D, 0x4A, 0x49, 
+0x39, 0xC7, 0x39, 0xA7, 0xAD, 0x55, 0xAD, 0x34, 
+0x83, 0xCF, 0xAD, 0x33, 0xCE, 0x15, 0xCE, 0x35, 
+0xC6, 0x14, 0xBD, 0xD3, 0xC6, 0x14, 0xC6, 0x14, 
+0x74, 0xA9, 0x6C, 0x68, 0x6C, 0x49, 0x74, 0x4B, 
+0x94, 0xCF, 0xC6, 0x55, 0xBD, 0xF5, 0xB5, 0x72, 
+0xBD, 0xB3, 0xB5, 0x71, 0x8C, 0xAB, 0x84, 0xAA, 
+0xB6, 0x11, 0xAD, 0x91, 0xC5, 0xF3, 0xBD, 0x93, 
+0xC5, 0xD4, 0xDE, 0x96, 0xBD, 0x72, 0xB4, 0xCF, 
+0x93, 0xEB, 0xB4, 0x6E, 0xBC, 0xCF, 0x8B, 0x8B, 
+0x7B, 0x4A, 0x9C, 0x6E, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xA4, 0xAF, 0xA4, 0xAF, 0xAC, 0xCF, 
+0xA4, 0x8E, 0x94, 0x2D, 0x94, 0x0C, 0x94, 0x2D, 
+0x94, 0x2D, 0x9C, 0x4E, 0xAC, 0xF0, 0xAC, 0xCF, 
+0xA4, 0x8E, 0x9C, 0x6D, 0xB4, 0xEF, 0x9C, 0x2C, 
+0x8B, 0xEC, 0xA4, 0x8E, 0x8B, 0xCB, 0x8B, 0xEC, 
+0x9C, 0x4D, 0x94, 0x2D, 0x9C, 0x4D, 0xA4, 0x8E, 
+0x8B, 0xCB, 0x9C, 0x4D, 0xA4, 0x8E, 0xA4, 0x6D, 
+0xAC, 0xCE, 0xAC, 0xAE, 0xA4, 0x8E, 0x9C, 0x4D, 
+0x94, 0x0C, 0x9C, 0x2D, 0x94, 0x0C, 0x9C, 0x2D, 
+0xA4, 0x8E, 0xBD, 0x51, 0xC5, 0x71, 0xCD, 0xB2, 
+0xC5, 0x51, 0xC5, 0x71, 0xC5, 0x91, 0xC5, 0x71, 
+0xC5, 0x71, 0xC5, 0x71, 0xC5, 0x71, 0xBD, 0x30, 
+0xAC, 0xCE, 0xAC, 0xAE, 0xA4, 0xAE, 0xA4, 0x8D, 
+0xA4, 0x8E, 0xAC, 0xAE, 0xA4, 0x8E, 0x9C, 0x6E, 
+0x9C, 0x8F, 0x9C, 0x6F, 0x9C, 0x6E, 0xB5, 0x10, 
+0x8C, 0x2E, 0x4A, 0x07, 0x39, 0xC6, 0x39, 0xA6, 
+0x42, 0x08, 0x52, 0x8A, 0x5A, 0xAA, 0x6B, 0x4C, 
+0x63, 0x2C, 0x63, 0x2C, 0x8C, 0x31, 0x9C, 0xB3, 
+0x9C, 0xB3, 0xAD, 0x55, 0xC6, 0x18, 0xAD, 0x35, 
+0x7B, 0xCF, 0x5A, 0xCB, 0x7B, 0xAE, 0xD6, 0x77, 
+0xD6, 0x76, 0xD6, 0x76, 0xD6, 0x56, 0xA4, 0xCF, 
+0xA4, 0xCF, 0x83, 0xCC, 0x9C, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xF1, 0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xC5, 0xD5, 0xC6, 0x15, 0xC6, 0x15, 0xBD, 0xD4, 
+0xB5, 0x73, 0xB5, 0x94, 0xBD, 0xD4, 0xB5, 0x73, 
+0xB5, 0x93, 0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0xD4, 
+0xB5, 0x93, 0xBD, 0xB4, 0x83, 0xED, 0x7B, 0xCE, 
+0x9C, 0xB2, 0xC6, 0x18, 0xAD, 0x56, 0x8C, 0x52, 
+0x31, 0xA7, 0x31, 0xA6, 0x42, 0x08, 0x4A, 0x69, 
+0x63, 0x0B, 0x6B, 0x4D, 0x6B, 0x4D, 0x63, 0x0C, 
+0x63, 0x0C, 0x7B, 0xCF, 0xD6, 0x79, 0xA4, 0xF3, 
+0x6B, 0x0C, 0x94, 0x71, 0x9C, 0xB2, 0xCE, 0x17, 
+0xBD, 0x73, 0xBD, 0x92, 0xB5, 0x52, 0xA4, 0xD0, 
+0xB5, 0x31, 0xC5, 0x92, 0xBD, 0x51, 0xCD, 0xF3, 
+0xD6, 0x34, 0xD5, 0xF4, 0xC5, 0xB3, 0xC5, 0xB2, 
+0xC5, 0xB2, 0xC5, 0xB2, 0xB5, 0x10, 0xB5, 0x31, 
+0xC5, 0xB3, 0xB5, 0x31, 0x9C, 0x8F, 0xAD, 0x32, 
+0xBD, 0x73, 0xAD, 0x32, 0x7B, 0xCD, 0x39, 0xA7, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xE4, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0xC4, 0x28, 0xC4, 0x71, 0x46, 
+0x89, 0x67, 0x69, 0x25, 0x20, 0x62, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xA3, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x20, 0xE4, 
+0x20, 0xE4, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x18, 0xE4, 
+0x21, 0x05, 0x29, 0x46, 0x29, 0x46, 0x21, 0x25, 
+0x18, 0xC4, 0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 
+0x20, 0xE4, 0x20, 0xE4, 0x21, 0x05, 0x18, 0xE4, 
+0x18, 0xE4, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x20, 0xE4, 0x18, 0xE4, 0x21, 0x25, 0x31, 0x67, 
+0x31, 0xA7, 0x31, 0x87, 0x31, 0x87, 0x31, 0xA8, 
+0x39, 0xC8, 0x39, 0xE9, 0x42, 0x09, 0x42, 0x09, 
+0x4A, 0x2A, 0x42, 0x2A, 0x4A, 0x2A, 0x52, 0x8B, 
+0x7B, 0x8E, 0xA4, 0xD2, 0xAC, 0xF2, 0xB5, 0x53, 
+0xAD, 0x12, 0xA4, 0xD1, 0xAC, 0xF1, 0xAC, 0xF1, 
+0xA4, 0xB0, 0xAC, 0xF2, 0xAC, 0xF1, 0xAD, 0x12, 
+0xAC, 0xF1, 0xAD, 0x12, 0xB5, 0x12, 0xB5, 0x12, 
+0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x53, 
+0xBD, 0x73, 0xB5, 0x52, 0xAD, 0x12, 0xAD, 0x12, 
+0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x32, 0xBD, 0x73, 
+0xBD, 0x73, 0xB5, 0x32, 0xAC, 0xD0, 0xA4, 0xB0, 
+0xA4, 0xB0, 0xA4, 0xD0, 0xAC, 0xF1, 0x94, 0x4F, 
+0x9C, 0xB0, 0xA4, 0xD1, 0x94, 0x6F, 0xA4, 0xF1, 
+0x9C, 0x90, 0x8C, 0x2E, 0x94, 0x4F, 0x73, 0x6C, 
+0x5A, 0xCB, 0x7B, 0xAF, 0x94, 0x71, 0x73, 0x6E, 
+0x4A, 0x49, 0x63, 0x0C, 0x84, 0x10, 0x5A, 0xCB, 
+0x4A, 0x29, 0x31, 0x66, 0x7B, 0xAF, 0x83, 0xCF, 
+0x94, 0x31, 0x73, 0x4D, 0x83, 0xCE, 0xC5, 0xF5, 
+0xC6, 0x14, 0xCE, 0x55, 0xDE, 0x97, 0xBD, 0xB4, 
+0x5C, 0x04, 0x4B, 0xA4, 0x7C, 0xAC, 0x84, 0x8E, 
+0xA5, 0x91, 0xA5, 0x91, 0xD6, 0xD8, 0xBD, 0xD4, 
+0xBD, 0xB3, 0x84, 0x2B, 0x6B, 0xE6, 0x9D, 0x6D, 
+0xBE, 0x12, 0x9C, 0xEE, 0xBD, 0xB2, 0xBD, 0x92, 
+0xC5, 0xD3, 0xDE, 0x76, 0xB5, 0x31, 0xA4, 0x8E, 
+0x8B, 0x69, 0x93, 0x8A, 0x8B, 0x6A, 0x93, 0xCC, 
+0xA4, 0x6E, 0xB5, 0x10, 0xB5, 0x11, 0xA4, 0xAF, 
+0xAC, 0xF0, 0xA4, 0xAF, 0xA4, 0x8F, 0xAC, 0xCF, 
+0xAC, 0xF0, 0xA4, 0xD0, 0x94, 0x2D, 0xAC, 0xF0, 
+0xB5, 0x31, 0xB5, 0x52, 0xBD, 0x72, 0xB5, 0x31, 
+0xB5, 0x31, 0xA4, 0xAF, 0xB5, 0x30, 0x94, 0x0D, 
+0x83, 0xCC, 0x9C, 0x8F, 0x83, 0xCC, 0x83, 0xCC, 
+0x83, 0xED, 0x94, 0x6F, 0x8C, 0x0D, 0x8C, 0x2D, 
+0x7B, 0x8B, 0x94, 0x4E, 0x9C, 0x6E, 0xA4, 0xAF, 
+0xA4, 0x8E, 0xA4, 0xCF, 0xA4, 0xAE, 0xA4, 0xCF, 
+0xA4, 0xAF, 0xB5, 0x11, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xBD, 0x31, 0xB4, 0xEF, 0xC5, 0x72, 
+0xBD, 0x71, 0xCD, 0xB3, 0xC5, 0x92, 0xD5, 0xF4, 
+0xCD, 0xD3, 0xD6, 0x14, 0xD6, 0x34, 0xD6, 0x14, 
+0xC5, 0x92, 0xB5, 0x30, 0xBD, 0x72, 0xBD, 0x72, 
+0xBD, 0x51, 0xBD, 0x51, 0xBD, 0x51, 0xAC, 0xEF, 
+0xA4, 0xAF, 0xBD, 0x52, 0xBD, 0x31, 0xBD, 0x31, 
+0xAC, 0xF0, 0x6B, 0x0A, 0x39, 0xA6, 0x39, 0xA6, 
+0x39, 0xC7, 0x4A, 0x28, 0x5A, 0xAA, 0x5A, 0xAA, 
+0x5A, 0xAA, 0x52, 0x8A, 0x6B, 0x4D, 0x7B, 0xAF, 
+0x7B, 0xAF, 0xAD, 0x76, 0x9C, 0xD3, 0xC5, 0xF8, 
+0x8C, 0x31, 0x5A, 0xCB, 0x52, 0x89, 0xA4, 0xF1, 
+0xA4, 0x8F, 0x8B, 0xEC, 0x8B, 0xCB, 0x83, 0x6A, 
+0x9C, 0x4D, 0x8C, 0x0D, 0x8B, 0xED, 0x83, 0xAC, 
+0x73, 0x4A, 0x7B, 0x8B, 0x83, 0xAC, 0x83, 0xCC, 
+0x7B, 0xAC, 0x7B, 0x8C, 0x73, 0x8B, 0x7B, 0xAC, 
+0x7B, 0xAC, 0x83, 0xED, 0x8C, 0x2E, 0x8C, 0x0E, 
+0x8C, 0x4F, 0x84, 0x0D, 0x83, 0xED, 0x7B, 0xAC, 
+0x83, 0xCC, 0x8C, 0x4E, 0x63, 0x0A, 0x8C, 0x2F, 
+0xB5, 0x75, 0xBD, 0xF7, 0xB5, 0x76, 0x8C, 0x72, 
+0x39, 0xC7, 0x39, 0xE7, 0x31, 0xA6, 0x39, 0xC6, 
+0x4A, 0x69, 0x52, 0x8A, 0x63, 0x0C, 0x63, 0x0C, 
+0x63, 0x0C, 0x52, 0xAB, 0x6B, 0x4D, 0x83, 0xF0, 
+0x42, 0x08, 0x73, 0x8E, 0x94, 0x51, 0x94, 0x51, 
+0xC5, 0xB6, 0xB5, 0x32, 0x9C, 0x8F, 0xA4, 0xB0, 
+0xAD, 0x11, 0xC5, 0x92, 0xC5, 0x71, 0xC5, 0xB2, 
+0xCD, 0xD3, 0xCD, 0xB2, 0xCD, 0xF3, 0xD6, 0x35, 
+0xD6, 0x14, 0xD5, 0xF3, 0xCD, 0xB3, 0xBD, 0x51, 
+0xC5, 0x92, 0xBD, 0x52, 0xAD, 0x11, 0xB5, 0x52, 
+0xBD, 0x92, 0xB5, 0x31, 0x8C, 0x2F, 0x52, 0x8A, 
+0x21, 0x05, 0x18, 0xE4, 0x18, 0xC4, 0x19, 0x04, 
+0x18, 0xE4, 0x19, 0x04, 0x19, 0x05, 0x18, 0xC4, 
+0x10, 0x83, 0x10, 0xA3, 0x18, 0xE4, 0x10, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x38, 0xE4, 0x69, 0x25, 
+0x71, 0x25, 0x40, 0xE4, 0x18, 0xA3, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xA3, 0x18, 0xC3, 0x18, 0xC4, 0x21, 0x04, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x25, 0x21, 0x05, 0x18, 0xE4, 
+0x18, 0xC4, 0x20, 0xE4, 0x21, 0x25, 0x21, 0x25, 
+0x21, 0x05, 0x18, 0xC4, 0x18, 0xC3, 0x18, 0xC3, 
+0x18, 0xC4, 0x18, 0xA4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x21, 0x05, 0x29, 0x46, 0x29, 0x25, 
+0x20, 0xE4, 0x18, 0xE4, 0x21, 0x05, 0x29, 0x66, 
+0x31, 0x87, 0x29, 0x67, 0x31, 0x67, 0x31, 0x87, 
+0x31, 0x67, 0x31, 0x87, 0x39, 0xC8, 0x39, 0xC8, 
+0x41, 0xE9, 0x4A, 0x2A, 0x4A, 0x29, 0x42, 0x2A, 
+0x4A, 0x4A, 0x5A, 0xAB, 0x73, 0x6D, 0x8C, 0x2F, 
+0x7B, 0x6C, 0x7B, 0xAD, 0x83, 0xCD, 0x9C, 0x70, 
+0x94, 0x0E, 0x73, 0x4B, 0x7B, 0x6C, 0x83, 0xAC, 
+0x83, 0xAD, 0x73, 0x4B, 0x73, 0x2B, 0x62, 0xC9, 
+0x6A, 0xEA, 0x83, 0xAD, 0x6B, 0x0A, 0x73, 0x2B, 
+0x83, 0x8C, 0x83, 0xCD, 0xA4, 0xB0, 0x9C, 0x6F, 
+0x94, 0x2E, 0xA4, 0xB0, 0xAC, 0xD0, 0xB5, 0x32, 
+0xC5, 0xD4, 0xCD, 0xB4, 0xCD, 0xD4, 0xB5, 0x32, 
+0xCD, 0xB4, 0xCD, 0xF5, 0xCE, 0x15, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xCD, 0xF5, 0xC5, 0xD5, 0xC5, 0xD4, 
+0xB5, 0x53, 0xBD, 0x94, 0xBD, 0x52, 0xBD, 0x73, 
+0x7B, 0xAD, 0x6B, 0x4D, 0x5A, 0xEB, 0x4A, 0x49, 
+0x39, 0xA7, 0x5A, 0xCB, 0x63, 0x0C, 0x73, 0x8E, 
+0x63, 0x0C, 0x21, 0x05, 0x62, 0xEC, 0x83, 0xCF, 
+0xCE, 0x17, 0xCE, 0x18, 0xAD, 0x14, 0xCE, 0x17, 
+0xC5, 0xD5, 0xCE, 0x36, 0xC5, 0xB5, 0x94, 0x4F, 
+0x53, 0xA6, 0x8D, 0x0F, 0x9D, 0x72, 0x84, 0x4E, 
+0x9D, 0x4F, 0x95, 0x2E, 0xAD, 0xD3, 0xCE, 0xB7, 
+0xC6, 0x34, 0x84, 0xA9, 0x8D, 0x08, 0x8D, 0x0B, 
+0x9D, 0x4F, 0x8C, 0x8D, 0xBD, 0xF3, 0xBD, 0xD3, 
+0xC5, 0xF4, 0xDE, 0x76, 0xCD, 0xB3, 0xA4, 0x4D, 
+0x9B, 0xCB, 0x8B, 0x6B, 0x72, 0xC9, 0x62, 0xA9, 
+0x73, 0x0A, 0x9C, 0x4E, 0xA4, 0x8F, 0x83, 0xCC, 
+0x7B, 0x8B, 0x8B, 0xED, 0x94, 0x2E, 0x83, 0xCC, 
+0x9C, 0x6E, 0xA4, 0xF0, 0x94, 0x4E, 0xAD, 0x31, 
+0xB5, 0x52, 0xBD, 0x72, 0xBD, 0x52, 0xBD, 0x72, 
+0xBD, 0x72, 0xAC, 0xAF, 0xBD, 0x30, 0xA4, 0xAF, 
+0x8C, 0x2E, 0x94, 0x4E, 0xA4, 0xD1, 0xA4, 0xD1, 
+0x94, 0x6F, 0x8C, 0x0D, 0x83, 0xED, 0x94, 0x6F, 
+0x8C, 0x2E, 0x94, 0x6F, 0x94, 0x6E, 0xA4, 0xD0, 
+0x94, 0x4E, 0x8C, 0x2D, 0x9C, 0xAF, 0x9C, 0xAF, 
+0xB5, 0x52, 0xB5, 0x52, 0xBD, 0x93, 0xBD, 0x92, 
+0xB5, 0x10, 0xBD, 0x30, 0xA4, 0xAE, 0x94, 0x2D, 
+0x8C, 0x2E, 0x8C, 0x0E, 0x7B, 0x8C, 0x7B, 0x8B, 
+0x7B, 0xAB, 0x7B, 0xAC, 0x83, 0xEC, 0x83, 0xCC, 
+0x62, 0xE9, 0x6B, 0x0A, 0x83, 0xCD, 0x8C, 0x0E, 
+0x83, 0xED, 0x73, 0x6B, 0x8C, 0x0D, 0x62, 0xE9, 
+0x6B, 0x2B, 0x7B, 0x8C, 0x7B, 0x8C, 0x73, 0x2A, 
+0x7B, 0xAC, 0x94, 0x90, 0x52, 0x69, 0x39, 0xC6, 
+0x31, 0xA6, 0x42, 0x08, 0x5A, 0x8A, 0x5A, 0xAA, 
+0x6B, 0x2C, 0x5A, 0xAA, 0x52, 0x8A, 0x5A, 0xCB, 
+0x8C, 0x51, 0x94, 0x92, 0xB5, 0x96, 0xD6, 0xBB, 
+0xAD, 0x35, 0x63, 0x2D, 0x42, 0x08, 0x62, 0xEA, 
+0x9C, 0x6F, 0xA4, 0x6E, 0x94, 0x0C, 0x9C, 0x4D, 
+0xA4, 0xAF, 0xA4, 0x8E, 0xA4, 0x8F, 0xA4, 0x8E, 
+0x9C, 0x6E, 0xA4, 0x8F, 0xAC, 0xD0, 0xAC, 0xF0, 
+0xB5, 0x11, 0xB5, 0x11, 0xAC, 0xF0, 0xAD, 0x10, 
+0xB5, 0x51, 0xB5, 0x51, 0xB5, 0x31, 0xB5, 0x31, 
+0xB5, 0x31, 0xB5, 0x10, 0xAC, 0xF0, 0xA4, 0xAF, 
+0x9C, 0x8F, 0x8C, 0x2E, 0x83, 0xED, 0x9C, 0x90, 
+0xC5, 0xF6, 0xB5, 0x96, 0xAD, 0x35, 0x7B, 0xF0, 
+0x31, 0x86, 0x31, 0xA6, 0x39, 0xE7, 0x31, 0x85, 
+0x31, 0xC6, 0x42, 0x08, 0x5A, 0xEB, 0x5A, 0xCB, 
+0x5A, 0xCB, 0x5A, 0xCB, 0x5A, 0xEB, 0x63, 0x0C, 
+0x52, 0x8A, 0x7B, 0xAF, 0x62, 0xCB, 0x73, 0x4E, 
+0x83, 0xEF, 0xAD, 0x13, 0x9C, 0x90, 0xA4, 0xB0, 
+0xA4, 0x8F, 0xC5, 0x92, 0xBD, 0x71, 0xC5, 0x92, 
+0xCD, 0xD3, 0xBD, 0x72, 0xAC, 0xF0, 0xB5, 0x10, 
+0xBD, 0x51, 0xD6, 0x34, 0xDE, 0x34, 0xCD, 0xB3, 
+0xCD, 0xB3, 0xBD, 0x51, 0xB5, 0x52, 0xAD, 0x31, 
+0xB5, 0x51, 0xB5, 0x52, 0x94, 0x6F, 0x83, 0xEE, 
+0x39, 0xC7, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x10, 0xC3, 
+0x10, 0xA3, 0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x41, 0x05, 0x61, 0x25, 
+0x59, 0x04, 0x30, 0xC3, 0x20, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC3, 0x18, 0xC4, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x18, 0xE4, 
+0x18, 0xA3, 0x18, 0xE4, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x18, 0xE4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x21, 0x25, 0x21, 0x05, 
+0x20, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x21, 0x25, 
+0x31, 0x87, 0x31, 0x87, 0x29, 0x46, 0x29, 0x46, 
+0x29, 0x67, 0x31, 0x67, 0x31, 0x87, 0x39, 0xA8, 
+0x39, 0xC8, 0x41, 0xE9, 0x42, 0x09, 0x4A, 0x2A, 
+0x42, 0x09, 0x42, 0x09, 0x4A, 0x6A, 0x63, 0x0C, 
+0x7B, 0xAE, 0x94, 0x4F, 0x94, 0x2F, 0x9C, 0x90, 
+0x94, 0x70, 0x83, 0xCE, 0x94, 0x4F, 0x8C, 0x0E, 
+0x83, 0xCD, 0x83, 0xEE, 0x73, 0x4B, 0x6B, 0x2B, 
+0x6B, 0x2B, 0x6A, 0xEA, 0x5A, 0x88, 0x62, 0xCA, 
+0x83, 0xAD, 0x7B, 0xAD, 0x7B, 0xAC, 0x7B, 0xAC, 
+0x83, 0xED, 0x9C, 0x90, 0xA4, 0xB0, 0xAC, 0xD1, 
+0xBD, 0x93, 0xB5, 0x11, 0xBD, 0x52, 0xC5, 0x93, 
+0xC5, 0x72, 0xB5, 0x31, 0x9C, 0x4E, 0x94, 0x0E, 
+0xA4, 0xB0, 0xAC, 0xF1, 0xAD, 0x11, 0xBD, 0xB3, 
+0xAD, 0x11, 0xAC, 0xD0, 0x9C, 0x6E, 0xA4, 0xD1, 
+0x9C, 0x91, 0x73, 0x8D, 0x4A, 0x49, 0x4A, 0x29, 
+0x31, 0x86, 0x4A, 0x29, 0x73, 0x8E, 0x83, 0xCF, 
+0x6B, 0x4D, 0x29, 0x46, 0x4A, 0x29, 0x73, 0x6D, 
+0xB5, 0x34, 0xC5, 0x95, 0xCD, 0xD6, 0xBD, 0x74, 
+0x8B, 0xEF, 0xA4, 0xB2, 0x9C, 0x71, 0xA4, 0xB1, 
+0x9D, 0x91, 0xA5, 0xB3, 0xB6, 0x35, 0x7C, 0x4E, 
+0x8C, 0xCC, 0x84, 0xCA, 0x9D, 0x90, 0xA5, 0xD1, 
+0x9D, 0x6C, 0x95, 0x47, 0x7C, 0x85, 0x7C, 0x88, 
+0xB5, 0xD1, 0xB5, 0xB2, 0xC6, 0x14, 0xC6, 0x14, 
+0xBD, 0xB2, 0xCE, 0x34, 0xC5, 0x92, 0xA4, 0x6D, 
+0x93, 0xAB, 0x83, 0x4B, 0x5A, 0x68, 0x52, 0x68, 
+0x52, 0x48, 0x62, 0xC9, 0x62, 0xC9, 0x6B, 0x2B, 
+0x5A, 0xA9, 0x6B, 0x4B, 0x94, 0x4F, 0x94, 0x4F, 
+0x83, 0xCD, 0x9C, 0xB0, 0x73, 0x6B, 0xAD, 0x31, 
+0xBD, 0x72, 0xB5, 0x31, 0xB5, 0x31, 0xAC, 0xF0, 
+0xC5, 0x93, 0x9C, 0x6E, 0xB5, 0x10, 0x9C, 0x6E, 
+0x7B, 0xAC, 0x94, 0x6F, 0x9C, 0xD1, 0x9C, 0xD1, 
+0xBD, 0xB4, 0x9C, 0xB0, 0x8C, 0x4F, 0x94, 0x6F, 
+0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0xB0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xA4, 0xD0, 0x94, 0x4E, 0x9C, 0x8F, 
+0xAC, 0xF1, 0xB5, 0x52, 0xB5, 0x52, 0x7B, 0x6B, 
+0x73, 0x49, 0xBD, 0x30, 0xAC, 0xCF, 0xAD, 0x11, 
+0xBD, 0x94, 0xB5, 0x73, 0xAD, 0x53, 0xA4, 0xF1, 
+0xA4, 0xD1, 0x9C, 0xB0, 0x8C, 0x2E, 0x94, 0x8F, 
+0x94, 0x90, 0x94, 0xB0, 0x8C, 0x4F, 0x8C, 0x2E, 
+0x8C, 0x0E, 0x84, 0x0E, 0x83, 0xEE, 0x84, 0x0E, 
+0x7B, 0xEE, 0x7B, 0xEE, 0x73, 0x8D, 0x63, 0x0B, 
+0x7B, 0xAD, 0x8C, 0x2F, 0x83, 0xCE, 0x4A, 0x48, 
+0x39, 0xC7, 0x41, 0xE7, 0x5A, 0x8A, 0x5A, 0xCB, 
+0x52, 0x8A, 0x41, 0xE7, 0x52, 0x8A, 0x73, 0xAE, 
+0x94, 0xB2, 0xA5, 0x35, 0xBD, 0xD7, 0xCE, 0x59, 
+0xB5, 0xB7, 0x8C, 0x31, 0x73, 0x8F, 0x5A, 0xCB, 
+0x62, 0xEA, 0xBD, 0x93, 0xB5, 0x31, 0xBD, 0x72, 
+0xB5, 0x31, 0x8B, 0xCC, 0x83, 0x8A, 0x83, 0xAB, 
+0x7B, 0x8A, 0x7B, 0x6A, 0x8B, 0xCC, 0x7B, 0x6A, 
+0x83, 0xCC, 0x7B, 0x8A, 0x8B, 0xCB, 0xA4, 0xAF, 
+0xBD, 0x72, 0xB5, 0x10, 0xB5, 0x10, 0xB4, 0xEF, 
+0xA4, 0x8E, 0xAC, 0xAE, 0x9C, 0x6D, 0x83, 0xCB, 
+0xA4, 0xD0, 0xB5, 0x52, 0x9C, 0x6F, 0x8B, 0xED, 
+0xBD, 0xD6, 0xAD, 0x76, 0xA5, 0x14, 0x7B, 0xAF, 
+0x39, 0xC7, 0x29, 0x44, 0x31, 0xA6, 0x42, 0x08, 
+0x39, 0xC7, 0x39, 0xE7, 0x5A, 0xCB, 0x4A, 0x69, 
+0x52, 0x89, 0x52, 0xAA, 0x5A, 0xEC, 0x6B, 0x4E, 
+0x73, 0x6E, 0xCE, 0x39, 0xCE, 0x59, 0x6B, 0x2D, 
+0x62, 0xEC, 0x7B, 0x8D, 0xAD, 0x33, 0x9C, 0x6F, 
+0xAD, 0x12, 0x9C, 0x6F, 0x8C, 0x0D, 0x94, 0x2D, 
+0x94, 0x2D, 0x8B, 0xED, 0x8B, 0xED, 0x94, 0x2D, 
+0x94, 0x2D, 0x9C, 0x6E, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xAC, 0xF0, 0xA4, 0xD0, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xBD, 0x72, 0xBD, 0x72, 0xAD, 0x11, 0x9C, 0xB1, 
+0x52, 0x8A, 0x29, 0x25, 0x19, 0x04, 0x21, 0x04, 
+0x21, 0x05, 0x18, 0xE4, 0x18, 0xC3, 0x18, 0xC3, 
+0x18, 0xE5, 0x18, 0xE4, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x41, 0x05, 0x58, 0xE4, 
+0x48, 0xE4, 0x30, 0xE4, 0x20, 0xE4, 0x21, 0x04, 
+0x21, 0x05, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 
+0x20, 0xE4, 0x20, 0xE5, 0x20, 0xE4, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x20, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x21, 0x25, 0x21, 0x05, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x20, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x21, 0x25, 0x29, 0x66, 0x29, 0x46, 0x29, 0x46, 
+0x29, 0x46, 0x29, 0x46, 0x29, 0x67, 0x31, 0x87, 
+0x31, 0x87, 0x31, 0xA8, 0x41, 0xE9, 0x42, 0x0A, 
+0x42, 0x2A, 0x42, 0x09, 0x42, 0x09, 0x4A, 0x4A, 
+0x5A, 0xAB, 0x7B, 0x8E, 0x94, 0x2F, 0x94, 0x4F, 
+0x94, 0x4F, 0xA4, 0x90, 0x9C, 0x70, 0x9C, 0x70, 
+0x94, 0x0E, 0xA4, 0xB0, 0x94, 0x2E, 0x7B, 0x8C, 
+0x94, 0x0E, 0x94, 0x0F, 0x73, 0x2B, 0x73, 0x4C, 
+0x8B, 0xEE, 0x8C, 0x2F, 0x83, 0xCD, 0x83, 0xAD, 
+0x83, 0xCD, 0x8C, 0x2E, 0xAC, 0xF1, 0xB5, 0x12, 
+0xB5, 0x31, 0xA4, 0x8F, 0xA4, 0x8F, 0xAC, 0xF0, 
+0xBD, 0x51, 0xC5, 0x72, 0x9C, 0x6E, 0x94, 0x2E, 
+0xA4, 0xD0, 0xAC, 0xF1, 0xB5, 0x32, 0xAC, 0xF0, 
+0x9C, 0x4E, 0x94, 0x0D, 0x94, 0x2E, 0x94, 0x4E, 
+0x94, 0x2F, 0x8C, 0x0F, 0x5A, 0xCB, 0x62, 0xEC, 
+0x39, 0xA7, 0x39, 0xE8, 0x7B, 0xCF, 0x7B, 0xCF, 
+0x84, 0x10, 0x5A, 0xCB, 0x6B, 0x2D, 0x83, 0xCF, 
+0x73, 0x4D, 0x8B, 0xCF, 0x9C, 0x71, 0x83, 0xCE, 
+0xA4, 0xD2, 0xAD, 0x13, 0xA4, 0xD2, 0xBD, 0x52, 
+0xA5, 0xB4, 0x9D, 0x71, 0x9D, 0x70, 0xA5, 0xD2, 
+0x84, 0xCB, 0x74, 0x88, 0x8D, 0x6D, 0x9D, 0xAD, 
+0x85, 0x06, 0x8D, 0x47, 0x84, 0xC7, 0x74, 0x47, 
+0x84, 0x2B, 0x94, 0xCE, 0xA5, 0x2F, 0x8C, 0xAD, 
+0x9D, 0x2F, 0xCE, 0x34, 0xAC, 0xEF, 0xA4, 0x6D, 
+0xBD, 0x30, 0x9C, 0x4E, 0x62, 0xA9, 0x6B, 0x4C, 
+0x73, 0x8D, 0x62, 0xEB, 0x52, 0x89, 0x6B, 0x6C, 
+0x62, 0xCA, 0x52, 0x69, 0x6B, 0x4B, 0x6B, 0x4C, 
+0x5A, 0xA9, 0x5A, 0xCA, 0x5A, 0xA9, 0x94, 0x6F, 
+0xA4, 0xF0, 0xAD, 0x11, 0xB5, 0x31, 0xA4, 0xD0, 
+0xBD, 0x73, 0x8C, 0x0C, 0xB5, 0x10, 0xB5, 0x31, 
+0x9C, 0xB0, 0x94, 0x8F, 0x8C, 0x2F, 0x5A, 0xEA, 
+0x9C, 0xB0, 0xC6, 0x16, 0xB5, 0x53, 0x94, 0x6F, 
+0x94, 0x90, 0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x32, 
+0xB5, 0x73, 0xB5, 0x73, 0xA4, 0xF1, 0x9C, 0xB0, 
+0xAD, 0x11, 0xAD, 0x31, 0xB5, 0x31, 0x94, 0x6F, 
+0x83, 0xEC, 0xBD, 0x51, 0xAC, 0xCE, 0xB5, 0x52, 
+0xBD, 0xB4, 0xB5, 0x73, 0xBD, 0xD5, 0xBD, 0xB4, 
+0xBD, 0xD4, 0xC5, 0xF5, 0xB5, 0x73, 0xAD, 0x52, 
+0xB5, 0x94, 0xB5, 0x93, 0xAD, 0x32, 0xA5, 0x12, 
+0xAD, 0x33, 0xA5, 0x12, 0xAD, 0x53, 0xB5, 0x74, 
+0xAD, 0x53, 0xAD, 0x53, 0xB5, 0x74, 0xAD, 0x33, 
+0xA4, 0xD1, 0xA4, 0xB0, 0xAC, 0xF1, 0x5A, 0xA9, 
+0x4A, 0x48, 0x4A, 0x28, 0x4A, 0x28, 0x39, 0xA6, 
+0x52, 0x69, 0x6B, 0x4D, 0x62, 0xEC, 0x6B, 0x6E, 
+0x8C, 0x51, 0x9C, 0xF4, 0xB5, 0x97, 0xBD, 0xD7, 
+0xA5, 0x35, 0xC5, 0xF8, 0x94, 0xB3, 0x6B, 0x6D, 
+0x6B, 0x2B, 0xB5, 0x93, 0xA4, 0xCF, 0x83, 0xCD, 
+0xBD, 0xB4, 0x94, 0x4E, 0x73, 0x4A, 0x6B, 0x2A, 
+0x83, 0xCC, 0x8C, 0x0D, 0x83, 0xEC, 0x8C, 0x0D, 
+0xA4, 0xF1, 0x94, 0x6F, 0x8C, 0x0D, 0xAC, 0xF0, 
+0x94, 0x4D, 0x9C, 0x6E, 0x94, 0x2D, 0x8B, 0xCB, 
+0x83, 0x89, 0x94, 0x0B, 0x94, 0x0C, 0x7B, 0x8B, 
+0x7B, 0xAC, 0x9C, 0x8F, 0x8C, 0x2E, 0x8C, 0x2F, 
+0xC6, 0x17, 0xAD, 0x55, 0xA5, 0x14, 0x7B, 0xAF, 
+0x4A, 0x49, 0x29, 0x45, 0x18, 0xC3, 0x29, 0x65, 
+0x39, 0xE7, 0x42, 0x08, 0x42, 0x08, 0x39, 0xE7, 
+0x42, 0x28, 0x52, 0x8A, 0x5A, 0xCB, 0x5A, 0xEC, 
+0x63, 0x0C, 0x7B, 0xAE, 0xBD, 0xB7, 0xB5, 0x35, 
+0x94, 0x51, 0x6A, 0xEC, 0x6B, 0x0B, 0x7B, 0x6C, 
+0xBD, 0x53, 0xB5, 0x52, 0xB5, 0x53, 0xB5, 0x32, 
+0xB5, 0x32, 0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x33, 
+0xB5, 0x32, 0xB5, 0x32, 0xAD, 0x12, 0xAC, 0xF1, 
+0xAC, 0xF1, 0xAD, 0x32, 0xB5, 0x32, 0xB5, 0x32, 
+0xAC, 0xF1, 0xA4, 0xB0, 0xA4, 0xD0, 0x94, 0x2F, 
+0x62, 0xEB, 0x39, 0xC7, 0x29, 0x45, 0x21, 0x05, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xC3, 0x18, 0xC4, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x41, 0x05, 0x50, 0xE4, 
+0x40, 0xC4, 0x28, 0xE4, 0x20, 0xE4, 0x21, 0x25, 
+0x18, 0xE4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 0x20, 0xE4, 
+0x21, 0x04, 0x20, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xC4, 0x18, 0xC4, 0x21, 0x05, 0x21, 0x25, 
+0x21, 0x05, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x20, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x18, 0xE4, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x25, 0x29, 0x46, 
+0x29, 0x46, 0x21, 0x26, 0x29, 0x26, 0x29, 0x47, 
+0x29, 0x67, 0x31, 0x67, 0x39, 0xA8, 0x39, 0xE9, 
+0x42, 0x09, 0x42, 0x09, 0x42, 0x09, 0x3A, 0x09, 
+0x42, 0x4A, 0x52, 0x8B, 0x6B, 0x2C, 0x9C, 0x90, 
+0x9C, 0xB0, 0x9C, 0x4F, 0x9C, 0x4F, 0x6B, 0x0A, 
+0x62, 0xC9, 0x9C, 0x6F, 0xA4, 0x90, 0x8B, 0xED, 
+0x94, 0x2F, 0x9C, 0x70, 0x9C, 0x70, 0x7B, 0x6C, 
+0x8C, 0x0E, 0xA4, 0xD1, 0x9C, 0x90, 0x9C, 0x90, 
+0x94, 0x4F, 0x94, 0x4F, 0xA4, 0xB0, 0xAC, 0xF1, 
+0xB5, 0x32, 0xAC, 0xF0, 0x9C, 0x6E, 0xA4, 0x8F, 
+0xAC, 0xAF, 0xB4, 0xF0, 0xA4, 0x6F, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xAD, 0x11, 0xB5, 0x32, 0xAD, 0x11, 
+0xAD, 0x11, 0xA4, 0xD0, 0x94, 0x2E, 0x94, 0x2E, 
+0x94, 0x4F, 0x94, 0x6F, 0x63, 0x0B, 0x52, 0x6A, 
+0x39, 0xC7, 0x31, 0xA7, 0x63, 0x2C, 0x5A, 0xCB, 
+0x73, 0xAE, 0x52, 0x8A, 0x52, 0x6A, 0x83, 0xCF, 
+0x83, 0xAF, 0x73, 0x4D, 0xAC, 0xD2, 0xB5, 0x34, 
+0xC5, 0xB6, 0xBD, 0x95, 0xAC, 0xF2, 0xEE, 0xD7, 
+0xAD, 0xB4, 0x9D, 0x70, 0x85, 0x0B, 0x8D, 0x4C, 
+0x8D, 0x0B, 0x74, 0x67, 0x7C, 0xA8, 0x8D, 0x28, 
+0x9D, 0xC9, 0x8D, 0x08, 0x9D, 0x4A, 0x6B, 0xC7, 
+0x6B, 0x88, 0x63, 0xA8, 0x6B, 0xE8, 0x95, 0x0D, 
+0xA5, 0x70, 0x6B, 0x68, 0x9C, 0x6C, 0xB5, 0x0F, 
+0xAD, 0x2F, 0x7B, 0x6A, 0x7B, 0x8C, 0xB5, 0x94, 
+0xAD, 0x33, 0x7B, 0xAD, 0x4A, 0x07, 0x42, 0x07, 
+0x52, 0x68, 0x52, 0x89, 0x42, 0x07, 0x41, 0xE7, 
+0x42, 0x07, 0x42, 0x07, 0x42, 0x07, 0x7B, 0xAC, 
+0x73, 0x6B, 0x73, 0x4B, 0x83, 0xED, 0x8C, 0x0D, 
+0xA4, 0xD0, 0x8B, 0xEC, 0xAC, 0xEF, 0xB5, 0x51, 
+0xB5, 0x52, 0x94, 0x6F, 0x94, 0x90, 0x8C, 0x4F, 
+0x94, 0x70, 0xA5, 0x12, 0xA4, 0xD1, 0xAD, 0x32, 
+0xAD, 0x33, 0xA5, 0x11, 0xAD, 0x11, 0xBD, 0xB4, 
+0xA4, 0xD0, 0xB5, 0x52, 0xB5, 0x52, 0x9C, 0xB0, 
+0x9C, 0xB0, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x31, 
+0x9C, 0x6E, 0xBD, 0x51, 0xAC, 0xEF, 0xC5, 0xB3, 
+0xCE, 0x15, 0xB5, 0x73, 0xAD, 0x52, 0xB5, 0x93, 
+0xC5, 0xF5, 0xC5, 0xF5, 0xCE, 0x15, 0xC5, 0xF5, 
+0xCE, 0x36, 0xC5, 0xF5, 0xAD, 0x32, 0xB5, 0x73, 
+0xAD, 0x53, 0xAD, 0x53, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xBD, 0xD4, 0xAD, 0x53, 0xB5, 0x94, 0xBD, 0xD4, 
+0xB5, 0x73, 0xBD, 0x72, 0xB5, 0x31, 0x7B, 0x6B, 
+0x39, 0xC6, 0x31, 0x86, 0x31, 0x65, 0x4A, 0x49, 
+0x52, 0x8A, 0x5A, 0xCB, 0x73, 0x6E, 0x6B, 0x4D, 
+0x7B, 0xCF, 0x8C, 0x72, 0x9C, 0xD3, 0xA4, 0xF4, 
+0xB5, 0x97, 0xCE, 0x7A, 0xAD, 0x56, 0x8C, 0x51, 
+0xAD, 0x13, 0x8C, 0x4F, 0x52, 0x68, 0x39, 0xC6, 
+0xAD, 0x33, 0xAD, 0x32, 0x8C, 0x0D, 0x94, 0x4E, 
+0x8C, 0x2E, 0x9C, 0x8F, 0x94, 0x6F, 0x94, 0x8F, 
+0xA4, 0xD1, 0x9C, 0x8F, 0x8C, 0x2E, 0x94, 0x6F, 
+0x94, 0x8F, 0xAD, 0x10, 0xAD, 0x10, 0x8C, 0x2D, 
+0x94, 0x2D, 0x9C, 0x8E, 0x9C, 0x6E, 0x94, 0x8F, 
+0x83, 0xED, 0x84, 0x0E, 0x9C, 0xD1, 0xAD, 0x54, 
+0xC6, 0x38, 0xA5, 0x35, 0xA5, 0x14, 0x6B, 0x6D, 
+0x31, 0x86, 0x31, 0x86, 0x21, 0x24, 0x18, 0xE3, 
+0x31, 0x86, 0x4A, 0x48, 0x4A, 0x49, 0x31, 0x86, 
+0x39, 0xE7, 0x4A, 0x48, 0x4A, 0x69, 0x52, 0x8A, 
+0x5A, 0xEB, 0x62, 0xEC, 0x73, 0x4D, 0x94, 0x51, 
+0xCE, 0x18, 0x8C, 0x10, 0x6B, 0x0C, 0x8C, 0x0F, 
+0x9C, 0x50, 0xAC, 0xF2, 0xAD, 0x12, 0xAC, 0xF1, 
+0xA4, 0xF1, 0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF1, 
+0x9C, 0x90, 0xA4, 0xD0, 0xB5, 0x32, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xA4, 0xD1, 0xA4, 0xD1, 
+0xAD, 0x12, 0xB5, 0x53, 0xBD, 0xB4, 0xAD, 0x12, 
+0x94, 0x4F, 0x52, 0x89, 0x4A, 0x69, 0x39, 0xE7, 
+0x21, 0x25, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA4, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x20, 0xE4, 0x41, 0x05, 0x49, 0x05, 
+0x38, 0xC4, 0x28, 0xE4, 0x21, 0x05, 0x21, 0x05, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC3, 0x18, 0xA3, 0x18, 0xA3, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xE4, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xE4, 0x18, 0xE4, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xE4, 0x18, 0xC4, 0x20, 0xE4, 
+0x21, 0x25, 0x21, 0x05, 0x18, 0xC4, 0x20, 0xE4, 
+0x29, 0x25, 0x29, 0x46, 0x21, 0x05, 0x21, 0x05, 
+0x29, 0x46, 0x21, 0x26, 0x21, 0x05, 0x29, 0x46, 
+0x29, 0x67, 0x31, 0x67, 0x31, 0x87, 0x31, 0xA8, 
+0x39, 0xE9, 0x42, 0x09, 0x42, 0x09, 0x42, 0x09, 
+0x39, 0xE8, 0x42, 0x09, 0x52, 0xAB, 0x5A, 0xEB, 
+0x94, 0x70, 0x9C, 0x90, 0x9C, 0x8F, 0x73, 0x6C, 
+0x7B, 0xAD, 0x94, 0x2F, 0xA4, 0xD1, 0xA4, 0xF1, 
+0xAD, 0x12, 0xA4, 0xD1, 0xAD, 0x12, 0x9C, 0x90, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xAC, 0xF1, 0x9C, 0x90, 
+0x9C, 0xB0, 0x94, 0x6F, 0xA4, 0xB0, 0xAC, 0xF1, 
+0xB5, 0x31, 0xAC, 0xF0, 0xB5, 0x32, 0xBD, 0x52, 
+0xBD, 0x72, 0xBD, 0x72, 0xB5, 0x11, 0x94, 0x4E, 
+0x9C, 0x8F, 0xB5, 0x32, 0xBD, 0x73, 0xBD, 0x73, 
+0xBD, 0x73, 0xB5, 0x32, 0x83, 0xCC, 0x8C, 0x0D, 
+0x94, 0x2E, 0x94, 0x4F, 0x83, 0xCE, 0x42, 0x28, 
+0x63, 0x0C, 0x39, 0xC7, 0x73, 0x6E, 0x52, 0x8A, 
+0x5A, 0xCB, 0x4A, 0x6A, 0x73, 0x8E, 0x73, 0x8E, 
+0x73, 0x4D, 0x7B, 0x6D, 0x8B, 0xCF, 0xA4, 0x91, 
+0xCE, 0x17, 0xCE, 0x17, 0xA4, 0xD1, 0xC5, 0xB3, 
+0x5B, 0x8A, 0x8D, 0x0E, 0x6C, 0x68, 0x85, 0x08, 
+0x74, 0xA7, 0x64, 0x05, 0x85, 0x08, 0x8D, 0x48, 
+0x84, 0xE7, 0x7C, 0xC7, 0x84, 0xC9, 0x9D, 0x0C, 
+0x8C, 0x8A, 0x74, 0x48, 0x95, 0x2C, 0xA5, 0x6E, 
+0x9D, 0x4E, 0xC6, 0x71, 0xA5, 0x2C, 0xB5, 0x4F, 
+0xAD, 0x4F, 0xBD, 0x92, 0xCE, 0x35, 0xBD, 0xB3, 
+0x9C, 0xAF, 0xAC, 0xD0, 0xB5, 0x31, 0xB5, 0x11, 
+0xAC, 0xF1, 0xA4, 0xAF, 0x9C, 0x4E, 0x94, 0x4E, 
+0x9C, 0x8F, 0x94, 0x6E, 0x94, 0x2E, 0x94, 0x2E, 
+0x83, 0xCC, 0x6B, 0x2B, 0x7B, 0x6B, 0x7B, 0x8B, 
+0x8B, 0xED, 0x9C, 0x6E, 0xAC, 0xCF, 0x8C, 0x0C, 
+0x9C, 0x8F, 0x94, 0x4E, 0xA4, 0xF1, 0x9C, 0xB0, 
+0x73, 0x4B, 0xA5, 0x12, 0x9C, 0xB0, 0x8C, 0x2E, 
+0xA4, 0xD0, 0xA4, 0xD1, 0xA4, 0xF1, 0xAD, 0x12, 
+0x9C, 0xB0, 0xB5, 0x52, 0xAD, 0x31, 0xAD, 0x11, 
+0x94, 0x4E, 0xA4, 0xF0, 0xAD, 0x11, 0x8B, 0xEC, 
+0x83, 0xCB, 0xBD, 0x51, 0xBD, 0x30, 0xD6, 0x56, 
+0xD6, 0x76, 0xCE, 0x35, 0xCE, 0x15, 0xCE, 0x36, 
+0xC6, 0x15, 0xC5, 0xF4, 0xCE, 0x35, 0xCD, 0xF4, 
+0xC5, 0xF4, 0xCE, 0x35, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xC5, 0xD4, 0xC5, 0xF5, 0xCE, 0x35, 0xCE, 0x15, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xC6, 0x15, 0xC5, 0xF4, 
+0xAD, 0x11, 0xBD, 0x72, 0xB5, 0x10, 0x8B, 0xCD, 
+0x63, 0x0B, 0x52, 0x8A, 0x5A, 0xAA, 0x62, 0xEB, 
+0x6B, 0x0C, 0x73, 0x8E, 0x73, 0x8E, 0x6B, 0x4D, 
+0x73, 0x8E, 0x73, 0x8E, 0x84, 0x10, 0xAD, 0x55, 
+0xBD, 0xF8, 0xC6, 0x18, 0xBD, 0xF8, 0x9C, 0xB2, 
+0x8C, 0x2F, 0x52, 0x8A, 0x41, 0xE8, 0x39, 0xC7, 
+0x7B, 0xCE, 0xCE, 0x36, 0x8C, 0x0E, 0xA5, 0x11, 
+0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x53, 0xB5, 0x73, 
+0xBD, 0xD5, 0xA4, 0xF1, 0xAD, 0x32, 0xB5, 0x93, 
+0xBD, 0xB4, 0xC5, 0xF4, 0xBD, 0xB3, 0xAC, 0xF0, 
+0xAD, 0x10, 0xAC, 0xEF, 0xAC, 0xCF, 0x8C, 0x0E, 
+0x84, 0x0E, 0x94, 0x4F, 0x9C, 0xB0, 0xB5, 0x74, 
+0xC6, 0x18, 0xA5, 0x35, 0xA5, 0x15, 0x8C, 0x50, 
+0x63, 0x0B, 0x29, 0x45, 0x29, 0x65, 0x21, 0x04, 
+0x18, 0xE3, 0x31, 0xA6, 0x4A, 0x49, 0x42, 0x08, 
+0x31, 0xA6, 0x39, 0xE7, 0x4A, 0x49, 0x4A, 0x69, 
+0x52, 0x8A, 0x4A, 0x48, 0x52, 0x69, 0x6B, 0x0C, 
+0x73, 0x8D, 0x52, 0x49, 0x83, 0xCF, 0xA4, 0xB2, 
+0x94, 0x30, 0x94, 0x2F, 0xC5, 0xD5, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xCD, 0xF4, 0xCE, 0x15, 
+0xBD, 0x93, 0xC5, 0xD3, 0xD6, 0x35, 0xCE, 0x15, 
+0xD6, 0x15, 0xC5, 0xD4, 0xB5, 0x52, 0xAD, 0x32, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xBD, 0xB4, 0xB5, 0x32, 
+0xA4, 0xD1, 0x8C, 0x2F, 0x83, 0xEE, 0x6B, 0x2C, 
+0x31, 0xA6, 0x21, 0x04, 0x19, 0x04, 0x18, 0xA3, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x29, 0x45, 
+0x18, 0xC3, 0x20, 0xE4, 0x39, 0x04, 0x49, 0x25, 
+0x30, 0xE4, 0x20, 0xE4, 0x20, 0xE4, 0x18, 0xE4, 
+0x18, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xE4, 0x18, 0xC4, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x18, 0xE4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xA3, 
+0x18, 0xC4, 0x18, 0xC4, 0x20, 0xE4, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x21, 0x25, 0x21, 0x05, 0x18, 0xE4, 0x18, 0xE5, 
+0x21, 0x25, 0x29, 0x66, 0x29, 0x46, 0x21, 0x05, 
+0x21, 0x25, 0x21, 0x26, 0x21, 0x05, 0x21, 0x26, 
+0x29, 0x46, 0x21, 0x26, 0x21, 0x05, 0x29, 0x67, 
+0x31, 0x87, 0x39, 0xC8, 0x39, 0xE9, 0x41, 0xE9, 
+0x39, 0xC8, 0x31, 0xA8, 0x39, 0xE9, 0x4A, 0x6A, 
+0x5A, 0xCB, 0x83, 0xEF, 0x9C, 0x6F, 0x83, 0xCD, 
+0x9C, 0x4F, 0x94, 0x2F, 0x94, 0x2E, 0x8B, 0xED, 
+0xAC, 0xF1, 0xB5, 0x32, 0xAC, 0xF1, 0xA4, 0xD1, 
+0xA4, 0xF1, 0xA4, 0xB0, 0x83, 0xAC, 0x62, 0xC9, 
+0x9C, 0xB1, 0x9C, 0x90, 0xA4, 0xD1, 0xAD, 0x11, 
+0xB5, 0x11, 0xA4, 0xD0, 0xBD, 0x72, 0xC5, 0xD4, 
+0xB5, 0x52, 0xBD, 0x73, 0xAD, 0x11, 0x9C, 0xB0, 
+0xAD, 0x12, 0xB5, 0x52, 0xB5, 0x32, 0xB5, 0x32, 
+0xBD, 0x93, 0xAC, 0xF1, 0x7B, 0xAC, 0x94, 0x4E, 
+0xA4, 0xB0, 0x9C, 0x4F, 0x8C, 0x2F, 0x63, 0x0B, 
+0x73, 0x8E, 0x31, 0x66, 0x42, 0x08, 0x31, 0x66, 
+0x31, 0x66, 0x31, 0x66, 0x31, 0x86, 0x39, 0xA7, 
+0x5A, 0xCB, 0x94, 0x51, 0x7B, 0x4C, 0x9C, 0x71, 
+0xC5, 0xD6, 0xDE, 0x99, 0x94, 0x51, 0x62, 0xCA, 
+0x8D, 0x10, 0xA5, 0xB2, 0x64, 0x06, 0x8D, 0x68, 
+0x74, 0x86, 0x53, 0x64, 0x7C, 0xA7, 0x85, 0x08, 
+0x95, 0x8B, 0x7C, 0x88, 0x5B, 0x45, 0x6B, 0xC8, 
+0x63, 0xC6, 0x6C, 0x26, 0x84, 0xE9, 0x8C, 0xEB, 
+0x7C, 0x89, 0xA5, 0xCB, 0xA5, 0x6A, 0x94, 0xAB, 
+0xA5, 0x2F, 0xA5, 0x30, 0xAD, 0x30, 0xB5, 0x30, 
+0xB5, 0x10, 0xAC, 0xD0, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xAC, 0xD0, 0xB5, 0x10, 0xB5, 0x10, 0xAD, 0x10, 
+0xAD, 0x10, 0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x10, 
+0xBD, 0x71, 0xC5, 0x92, 0xC5, 0x72, 0xC5, 0x92, 
+0xC5, 0x72, 0xC5, 0x51, 0xC5, 0x71, 0xC5, 0x71, 
+0xB5, 0x31, 0xB5, 0x10, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xAC, 0xCF, 0xA4, 0x8E, 0x9C, 0x4D, 
+0x94, 0x2D, 0x94, 0x2D, 0x94, 0x2D, 0x8B, 0xEC, 
+0x8B, 0xEC, 0x8B, 0xEC, 0x8B, 0xEC, 0x8B, 0xEC, 
+0x94, 0x0C, 0x94, 0x0D, 0x8B, 0xEC, 0x83, 0xAB, 
+0x94, 0x2D, 0xC5, 0x71, 0xA4, 0x8E, 0xAC, 0xF0, 
+0xC5, 0xB3, 0xBD, 0x93, 0xB5, 0x52, 0xB5, 0x31, 
+0xBD, 0x72, 0xB5, 0x52, 0xC5, 0xD4, 0xBD, 0x93, 
+0xAC, 0xF0, 0xBD, 0xB3, 0xBD, 0x93, 0xC5, 0xD4, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xD6, 0x56, 0xCE, 0x15, 
+0xCD, 0xF5, 0xC5, 0xF4, 0xC5, 0xB4, 0xC5, 0xB4, 
+0x9C, 0x6E, 0xC5, 0x72, 0xBD, 0x31, 0xAD, 0x12, 
+0x62, 0xEB, 0x63, 0x0B, 0x5A, 0xAA, 0x52, 0x69, 
+0x6B, 0x4D, 0x6B, 0x4D, 0x6B, 0x2D, 0x7B, 0xAF, 
+0x73, 0x8E, 0x73, 0xAF, 0x9C, 0xB3, 0xA5, 0x14, 
+0xAD, 0x56, 0xBD, 0xD8, 0xAD, 0x15, 0x8C, 0x30, 
+0x8C, 0x10, 0x52, 0x8A, 0x42, 0x08, 0x31, 0xA6, 
+0x42, 0x28, 0xBD, 0xB5, 0xC6, 0x15, 0xBD, 0xD4, 
+0xC5, 0xF5, 0xCE, 0x16, 0xCE, 0x56, 0xCE, 0x56, 
+0xCE, 0x36, 0xBD, 0xD4, 0xC6, 0x15, 0xCE, 0x36, 
+0xD6, 0x76, 0xC6, 0x15, 0xC5, 0xD4, 0xAD, 0x10, 
+0xAD, 0x10, 0xAD, 0x0F, 0xAC, 0xF0, 0x7B, 0xAC, 
+0x83, 0xEE, 0x9C, 0xB0, 0x9C, 0xD1, 0xB5, 0xB5, 
+0xC6, 0x18, 0xA5, 0x35, 0x9C, 0xF4, 0x9C, 0xD2, 
+0x8C, 0x71, 0x73, 0xAE, 0x29, 0x24, 0x31, 0x86, 
+0x21, 0x24, 0x18, 0xE3, 0x39, 0xC7, 0x4A, 0x48, 
+0x31, 0xA6, 0x31, 0x86, 0x41, 0xE7, 0x52, 0x8A, 
+0x52, 0xAA, 0x63, 0x0C, 0x73, 0x6D, 0x4A, 0x49, 
+0x29, 0x45, 0x41, 0xE8, 0x5A, 0xAA, 0x8C, 0x10, 
+0xA4, 0xB2, 0x94, 0x0F, 0xB5, 0x53, 0xEE, 0xF8, 
+0xDE, 0x96, 0xD6, 0x76, 0xDE, 0x96, 0xDE, 0x96, 
+0xB5, 0x32, 0xBD, 0x73, 0xD6, 0x56, 0xD6, 0x35, 
+0xD6, 0x55, 0xCE, 0x35, 0xC5, 0xF5, 0xBD, 0xD4, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xBD, 0x73, 0x94, 0x4F, 
+0x94, 0x2E, 0x94, 0x2E, 0x9C, 0x4F, 0x94, 0x2E, 
+0x6B, 0x0B, 0x52, 0x69, 0x4A, 0x28, 0x41, 0xE7, 
+0x41, 0xE7, 0x52, 0x89, 0x7B, 0xAD, 0x83, 0xCE, 
+0x39, 0xA6, 0x31, 0x66, 0x39, 0x25, 0x41, 0x25, 
+0x28, 0xE4, 0x20, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x21, 0x05, 0x21, 0x25, 
+0x18, 0xC4, 0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 
+0x21, 0x05, 0x21, 0x05, 0x18, 0xE4, 0x18, 0xC4, 
+0x21, 0x05, 0x21, 0x25, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x29, 0x46, 0x29, 0x46, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x25, 0x21, 0x25, 0x21, 0x26, 
+0x29, 0x46, 0x29, 0x46, 0x21, 0x05, 0x21, 0x26, 
+0x29, 0x67, 0x31, 0xA8, 0x31, 0xA8, 0x31, 0xA8, 
+0x39, 0xC8, 0x31, 0xA8, 0x39, 0xC9, 0x3A, 0x09, 
+0x42, 0x4A, 0x52, 0x6A, 0x6A, 0xEB, 0x73, 0x4C, 
+0x7B, 0x6C, 0x6B, 0x0A, 0x6A, 0xEA, 0x6B, 0x0A, 
+0x73, 0x4B, 0x83, 0xAD, 0x8B, 0xED, 0x7B, 0x8C, 
+0x8C, 0x0E, 0x9C, 0x6F, 0x6B, 0x0A, 0x6B, 0x0A, 
+0x9C, 0xB1, 0x8C, 0x0E, 0xA4, 0xD1, 0xB5, 0x32, 
+0xB5, 0x31, 0xB5, 0x31, 0xBD, 0x93, 0xBD, 0x72, 
+0xBD, 0x72, 0xC5, 0xB3, 0xAD, 0x11, 0xAC, 0xF1, 
+0x9C, 0x8F, 0xA4, 0xD0, 0xAD, 0x32, 0xAC, 0xF1, 
+0xBD, 0xB4, 0xAD, 0x32, 0x8C, 0x2E, 0x9C, 0x90, 
+0xAC, 0xD1, 0xA4, 0xD1, 0x9C, 0xB0, 0x7B, 0xAD, 
+0x4A, 0x49, 0x29, 0x45, 0x41, 0xE8, 0x62, 0xEC, 
+0x39, 0xC7, 0x29, 0x45, 0x21, 0x04, 0x31, 0x66, 
+0x39, 0xC7, 0x6B, 0x0C, 0x73, 0x0C, 0x83, 0xAE, 
+0x8B, 0xEF, 0x94, 0x30, 0x83, 0x8E, 0x52, 0x49, 
+0xAD, 0xF4, 0x95, 0x31, 0x4B, 0x45, 0x74, 0xC7, 
+0x74, 0xA7, 0x74, 0x48, 0x6C, 0x25, 0x6C, 0x66, 
+0x8D, 0x4A, 0x84, 0xCA, 0x4A, 0xC5, 0x5B, 0x66, 
+0x5B, 0x86, 0x7C, 0xA8, 0x7C, 0xC7, 0x85, 0x0A, 
+0x7C, 0xA9, 0x7C, 0xE6, 0xAE, 0x0A, 0x94, 0xCA, 
+0x8C, 0x4B, 0x8C, 0x4C, 0xA4, 0xAE, 0xB5, 0x10, 
+0x94, 0x0C, 0x83, 0xCC, 0x83, 0xCC, 0x7B, 0x8B, 
+0x83, 0xED, 0x84, 0x0D, 0x8C, 0x2E, 0x94, 0x4E, 
+0xA4, 0xD0, 0x9C, 0x6E, 0x9C, 0x6E, 0xA4, 0xAF, 
+0xAC, 0xCF, 0xA4, 0x8F, 0xA4, 0x6E, 0x94, 0x0D, 
+0x94, 0x2D, 0x9C, 0x4D, 0xA4, 0x8E, 0x9C, 0x6E, 
+0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xCF, 0xBD, 0x31, 
+0xAC, 0xCF, 0xAC, 0xCF, 0xA4, 0x6D, 0x9C, 0x4D, 
+0x9C, 0x6D, 0xA4, 0x8E, 0xA4, 0x8E, 0xB4, 0xEF, 
+0xB5, 0x10, 0xC5, 0x71, 0xC5, 0x71, 0xC5, 0x71, 
+0xCD, 0x92, 0xCD, 0xD3, 0xCD, 0xD3, 0xCD, 0xB2, 
+0xC5, 0x92, 0xC5, 0x51, 0xC5, 0x91, 0xBD, 0x51, 
+0xB4, 0xEF, 0xAC, 0xAF, 0x94, 0x2D, 0x8B, 0xCC, 
+0x83, 0xAB, 0x8B, 0xEC, 0x8B, 0xEC, 0x8B, 0xEC, 
+0x93, 0xEC, 0x94, 0x0C, 0x93, 0xEC, 0x93, 0xEC, 
+0x83, 0x8B, 0x83, 0xAB, 0x8B, 0xED, 0x8B, 0xEC, 
+0xA4, 0xAF, 0xB5, 0x52, 0xC5, 0xB3, 0xB5, 0x51, 
+0xC5, 0xB2, 0xCD, 0xB2, 0xBD, 0x51, 0xC5, 0xB4, 
+0x41, 0xE7, 0x7B, 0xCF, 0x7B, 0x8D, 0x4A, 0x28, 
+0x52, 0x69, 0x6B, 0x2C, 0x5A, 0xAA, 0x62, 0xEB, 
+0x52, 0x6A, 0x6B, 0x2D, 0x7B, 0xCF, 0x84, 0x10, 
+0xA5, 0x35, 0x94, 0xB2, 0x94, 0x72, 0xA4, 0xF4, 
+0x94, 0x51, 0x62, 0xEB, 0x41, 0xE7, 0x31, 0x86, 
+0x42, 0x28, 0x7B, 0xEE, 0xD6, 0x77, 0xBD, 0xD4, 
+0xC5, 0xF5, 0xC6, 0x15, 0xC6, 0x15, 0xC6, 0x15, 
+0xBD, 0xF4, 0xA5, 0x11, 0xC6, 0x15, 0xCE, 0x36, 
+0xCE, 0x35, 0xD6, 0x56, 0xC5, 0xF4, 0x9C, 0x6E, 
+0xBD, 0x50, 0xB5, 0x10, 0xB5, 0x11, 0x73, 0x6B, 
+0x84, 0x0E, 0x9C, 0xD1, 0xA4, 0xF1, 0xBD, 0xD6, 
+0xBD, 0xF8, 0xA5, 0x35, 0x84, 0x31, 0x8C, 0x50, 
+0x9C, 0xD1, 0x9C, 0xF2, 0x84, 0x0F, 0x63, 0x2C, 
+0x21, 0x24, 0x18, 0xE3, 0x29, 0x86, 0x31, 0xA6, 
+0x42, 0x07, 0x42, 0x08, 0x39, 0xC6, 0x42, 0x07, 
+0x5A, 0xEB, 0x52, 0x8A, 0x8C, 0x10, 0x83, 0xCF, 
+0x5A, 0x8A, 0x52, 0x49, 0x6B, 0x0C, 0x8B, 0xEF, 
+0x83, 0xAE, 0x8C, 0x0F, 0xA4, 0xB1, 0xBD, 0x73, 
+0xD6, 0x76, 0xDE, 0x96, 0xE6, 0xB7, 0xDE, 0x97, 
+0xB5, 0x52, 0xCE, 0x36, 0xD6, 0x56, 0xD6, 0x35, 
+0xCE, 0x35, 0xCE, 0x15, 0xBD, 0xD4, 0xBD, 0xB4, 
+0xAD, 0x32, 0xAD, 0x12, 0xB5, 0x53, 0x94, 0x4F, 
+0x7B, 0x8C, 0x9C, 0x6F, 0xBD, 0x52, 0xBD, 0x52, 
+0xAC, 0xF1, 0x9C, 0x90, 0x94, 0x2E, 0x94, 0x4F, 
+0xA4, 0xD1, 0xB5, 0x53, 0xC5, 0x93, 0xBD, 0x53, 
+0x94, 0x2F, 0x7B, 0x8D, 0x73, 0x2C, 0x49, 0xE7, 
+0x29, 0x05, 0x21, 0x04, 0x21, 0x04, 0x18, 0xC4, 
+0x18, 0xA3, 0x18, 0xC4, 0x18, 0xC3, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0xA3, 0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC4, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xC4, 0x10, 0xA3, 0x18, 0xA3, 
+0x18, 0xE4, 0x21, 0x05, 0x21, 0x05, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xE4, 0x21, 0x25, 0x21, 0x25, 
+0x18, 0xE5, 0x21, 0x26, 0x29, 0x46, 0x21, 0x05, 
+0x18, 0xE4, 0x21, 0x05, 0x21, 0x25, 0x29, 0x46, 
+0x21, 0x25, 0x21, 0x25, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x26, 0x29, 0x67, 0x31, 0x87, 0x31, 0xA8, 
+0x39, 0xC8, 0x39, 0xC8, 0x31, 0xA8, 0x31, 0xA8, 
+0x39, 0xE9, 0x42, 0x2A, 0x4A, 0x4A, 0x63, 0x0C, 
+0x83, 0xCE, 0x83, 0xCE, 0x83, 0xAD, 0x83, 0xAD, 
+0x7B, 0x8D, 0x7B, 0x8C, 0x7B, 0x8C, 0x73, 0x2B, 
+0x6B, 0x2B, 0x6B, 0x0A, 0x6B, 0x2B, 0x73, 0x2B, 
+0x62, 0xEA, 0x73, 0x2B, 0x8C, 0x0E, 0x94, 0x4E, 
+0x94, 0x4E, 0x94, 0x4E, 0x94, 0x2E, 0x9C, 0x6F, 
+0xAC, 0xF1, 0xA4, 0xD0, 0xA4, 0x8F, 0xA4, 0xD0, 
+0xB5, 0x31, 0x9C, 0x6F, 0xBD, 0x73, 0xAC, 0xF1, 
+0xBD, 0x73, 0x94, 0x4E, 0x94, 0x4F, 0x94, 0x4F, 
+0x94, 0x4F, 0x8C, 0x2E, 0x8C, 0x0E, 0x7B, 0xAD, 
+0x4A, 0x49, 0x21, 0x25, 0x5A, 0xCB, 0x6B, 0x4D, 
+0x39, 0xC7, 0x39, 0xA7, 0x4A, 0x49, 0x62, 0xCB, 
+0x52, 0x8A, 0x52, 0x69, 0x6A, 0xEB, 0x41, 0xA6, 
+0x62, 0xAA, 0x8B, 0xAE, 0x8B, 0xCE, 0x5A, 0xAA, 
+0x8D, 0x10, 0x84, 0xCE, 0x7C, 0xAB, 0x7C, 0xC9, 
+0x8D, 0x4C, 0x8D, 0x0B, 0x63, 0xC4, 0x5B, 0xE3, 
+0x74, 0x66, 0x95, 0x2B, 0x63, 0x87, 0x53, 0x25, 
+0x53, 0x44, 0x74, 0x87, 0x6C, 0x65, 0x6C, 0x87, 
+0x6C, 0x87, 0x74, 0xC5, 0x9D, 0xA7, 0x9D, 0x2B, 
+0x84, 0x4D, 0xA5, 0x52, 0xBE, 0x15, 0xC6, 0x15, 
+0xA4, 0xD0, 0x94, 0x90, 0xA5, 0x12, 0x84, 0x2F, 
+0x84, 0x2E, 0x7B, 0xCD, 0x84, 0x2F, 0x9C, 0xB0, 
+0xA4, 0xD0, 0x7B, 0xAC, 0x7B, 0xAC, 0xAD, 0x32, 
+0xA4, 0xD0, 0x9C, 0xAF, 0x9C, 0x8F, 0x84, 0x0E, 
+0x7B, 0xAC, 0x8C, 0x2E, 0xA4, 0xF1, 0x9C, 0x90, 
+0x9C, 0xB0, 0x8C, 0x2E, 0x94, 0x0D, 0xB5, 0x10, 
+0x94, 0x0C, 0xA4, 0x8E, 0xA4, 0x8E, 0x9C, 0x6E, 
+0x94, 0x0C, 0x8B, 0xEC, 0x94, 0x0C, 0x94, 0x2D, 
+0x8B, 0xCB, 0xAC, 0x8E, 0x83, 0x6A, 0x7B, 0x49, 
+0x7B, 0x49, 0x7B, 0x6A, 0x83, 0x8B, 0x83, 0x8B, 
+0x8B, 0xAB, 0x93, 0xEB, 0x9C, 0x2C, 0xA4, 0x6E, 
+0xAC, 0xAF, 0xAC, 0xCF, 0xAC, 0xEF, 0xB5, 0x10, 
+0xBD, 0x71, 0xC5, 0x92, 0xBD, 0x51, 0xB5, 0x30, 
+0xB4, 0xF0, 0xAC, 0xCF, 0xB5, 0x10, 0xB5, 0x10, 
+0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x10, 0xAC, 0xCF, 
+0xAC, 0xAE, 0xA4, 0x8E, 0x9C, 0x6D, 0xA4, 0x8E, 
+0xB5, 0x0F, 0xBD, 0x10, 0xBD, 0x30, 0xBD, 0x72, 
+0xA4, 0xD2, 0x9C, 0x92, 0x6B, 0x2C, 0x39, 0xA7, 
+0x42, 0x28, 0x52, 0x69, 0x42, 0x08, 0x42, 0x07, 
+0x4A, 0x28, 0x62, 0xEC, 0x4A, 0x49, 0x8C, 0x51, 
+0x8C, 0x71, 0xA5, 0x14, 0xBD, 0xB7, 0xBD, 0xD7, 
+0x9C, 0xD3, 0x73, 0x8E, 0x4A, 0x28, 0x52, 0x69, 
+0x4A, 0x48, 0x42, 0x28, 0xB5, 0x73, 0xBD, 0x93, 
+0xBD, 0x93, 0xBD, 0xD3, 0xBD, 0xB3, 0xC5, 0xD4, 
+0xC5, 0xF4, 0xB5, 0x72, 0xBD, 0xD4, 0xC5, 0xD3, 
+0xBD, 0xB3, 0xBD, 0xD3, 0xAD, 0x31, 0x8C, 0x0C, 
+0xB5, 0x30, 0xBD, 0x50, 0xBD, 0x31, 0x7B, 0xAC, 
+0x83, 0xEE, 0x84, 0x0E, 0x9C, 0xB0, 0xC6, 0x17, 
+0xBD, 0xB7, 0xA5, 0x15, 0x84, 0x30, 0xA5, 0x13, 
+0xA5, 0x33, 0xAD, 0x53, 0xA5, 0x33, 0xA4, 0xF2, 
+0x7B, 0xCE, 0x52, 0x89, 0x4A, 0x69, 0x4A, 0x69, 
+0x39, 0xC7, 0x42, 0x08, 0x31, 0xA6, 0x39, 0xC6, 
+0x4A, 0x48, 0x8C, 0x30, 0x94, 0x71, 0x94, 0x51, 
+0xAC, 0xF3, 0xC5, 0xB5, 0x73, 0x2C, 0x73, 0x4D, 
+0x8B, 0xEF, 0x6A, 0xEB, 0xA4, 0xB1, 0x7B, 0x8D, 
+0x9C, 0x50, 0xCD, 0xF5, 0xE6, 0xB7, 0xDE, 0xB7, 
+0xD6, 0x76, 0xDE, 0x77, 0xCE, 0x35, 0xBD, 0xB3, 
+0xC5, 0xD4, 0xC5, 0xF5, 0xBD, 0xD4, 0xC5, 0xF5, 
+0xAD, 0x53, 0xA4, 0xF1, 0xB5, 0x32, 0xAC, 0xF1, 
+0x83, 0xAC, 0xA4, 0xD0, 0xBD, 0x52, 0xBD, 0x52, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xBD, 0x93, 0xC5, 0x93, 
+0xC5, 0x93, 0xCD, 0xB4, 0xCD, 0xB3, 0xC5, 0x93, 
+0xCD, 0xB4, 0xBD, 0x73, 0xB5, 0x12, 0x73, 0x6D, 
+0x29, 0x04, 0x21, 0x05, 0x21, 0x04, 0x18, 0xC4, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x20, 0xE4, 0x21, 0x05, 0x18, 0xE4, 
+0x10, 0xA3, 0x18, 0xE4, 0x21, 0x05, 0x21, 0x26, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x26, 0x29, 0x46, 
+0x18, 0xE5, 0x18, 0xC4, 0x18, 0xE5, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x18, 0xE5, 0x21, 0x05, 
+0x18, 0xE5, 0x21, 0x05, 0x29, 0x46, 0x31, 0x87, 
+0x31, 0x87, 0x31, 0x87, 0x31, 0xA8, 0x31, 0xA7, 
+0x31, 0xA8, 0x42, 0x09, 0x42, 0x2A, 0x4A, 0x49, 
+0x6B, 0x2C, 0xA4, 0xD2, 0xA4, 0xD1, 0xAD, 0x12, 
+0xAC, 0xF1, 0xAC, 0xF2, 0xA4, 0xD1, 0xA4, 0xB0, 
+0xA4, 0xB0, 0x9C, 0x70, 0x94, 0x4F, 0x94, 0x4F, 
+0x9C, 0x70, 0x9C, 0x90, 0xA4, 0xB0, 0xA4, 0xD0, 
+0xA4, 0xD1, 0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF1, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xD0, 0xA4, 0xB0, 
+0x9C, 0x90, 0x94, 0x6F, 0x9C, 0x90, 0x9C, 0x6F, 
+0x9C, 0x8F, 0x8C, 0x0E, 0x8B, 0xED, 0x83, 0xCD, 
+0x8C, 0x0E, 0x8B, 0xEE, 0x83, 0xAC, 0xA4, 0xD1, 
+0x73, 0xAD, 0x31, 0xA6, 0x5A, 0xCB, 0x5A, 0xCB, 
+0x42, 0x08, 0x5A, 0xCB, 0x6B, 0x0C, 0x52, 0x49, 
+0x39, 0xA6, 0x41, 0xC7, 0x4A, 0x07, 0x62, 0xAA, 
+0x4A, 0x08, 0x7B, 0x6C, 0x94, 0x30, 0x5A, 0xAA, 
+0xA5, 0xF3, 0x7C, 0x8C, 0x6C, 0x28, 0x6C, 0x48, 
+0x8D, 0x4D, 0x9D, 0x6D, 0x5B, 0xA4, 0x85, 0x09, 
+0x9D, 0xAD, 0x84, 0xAA, 0x7C, 0x68, 0x7C, 0xA8, 
+0x74, 0x87, 0x64, 0x04, 0x5C, 0x03, 0x74, 0xA7, 
+0x6C, 0x86, 0x7D, 0x05, 0x9D, 0xC9, 0xBE, 0x73, 
+0xDF, 0x3A, 0xD7, 0x3A, 0xC6, 0x97, 0xBE, 0x14, 
+0x94, 0xAF, 0xAD, 0x53, 0xB5, 0xD5, 0x8C, 0x70, 
+0x8C, 0x4F, 0x73, 0xAD, 0x7B, 0xEE, 0x8C, 0x4F, 
+0x83, 0xED, 0x73, 0x8C, 0x8C, 0x70, 0xC6, 0x16, 
+0xBD, 0xB5, 0xA4, 0xF1, 0x94, 0x6F, 0x8C, 0x4F, 
+0x7B, 0xCD, 0x84, 0x0E, 0x8C, 0x70, 0x94, 0xB1, 
+0x9C, 0xD2, 0x9C, 0xB1, 0xA4, 0xB0, 0xBD, 0x51, 
+0x9C, 0x4D, 0xB5, 0x11, 0xB5, 0x32, 0xBD, 0x93, 
+0xB5, 0x31, 0xB5, 0x31, 0xBD, 0x72, 0xB5, 0x31, 
+0xAC, 0xF0, 0xA4, 0xD0, 0x94, 0x0D, 0x94, 0x0D, 
+0x94, 0x2E, 0x8C, 0x0D, 0x83, 0xAC, 0x83, 0xAC, 
+0x83, 0xAC, 0x83, 0x8B, 0x8B, 0xEC, 0x8C, 0x0D, 
+0x8B, 0xEC, 0x8B, 0xEC, 0xB4, 0xEF, 0xB5, 0x10, 
+0xBD, 0x72, 0xB5, 0x11, 0xA4, 0xCF, 0x9C, 0x8F, 
+0x94, 0x2D, 0x7B, 0x8B, 0x8C, 0x0C, 0x8B, 0xCB, 
+0x8B, 0xEC, 0x94, 0x2D, 0x94, 0x2C, 0x94, 0x0C, 
+0x9C, 0x4D, 0xAC, 0xF0, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xA4, 0xAE, 0xA4, 0x6D, 0xA4, 0xAE, 0xBD, 0x73, 
+0xBD, 0x95, 0x7B, 0x8E, 0x4A, 0x08, 0x29, 0x24, 
+0x4A, 0x49, 0x42, 0x07, 0x21, 0x03, 0x31, 0x85, 
+0x52, 0x69, 0x5A, 0xAA, 0x73, 0x8E, 0x8C, 0x51, 
+0x94, 0xB3, 0xAD, 0x76, 0xB5, 0xB7, 0xBD, 0xF8, 
+0xB5, 0x76, 0x94, 0x72, 0x63, 0x0C, 0x52, 0x8A, 
+0x7B, 0x8D, 0x83, 0xCD, 0x7B, 0x8B, 0x83, 0xAB, 
+0x8B, 0xEC, 0x9C, 0x4D, 0xA4, 0xAE, 0xAC, 0xCF, 
+0xA4, 0xCF, 0xA4, 0xCF, 0xB5, 0x10, 0xAC, 0xCF, 
+0xA4, 0xAF, 0xA4, 0xCE, 0xA4, 0xAE, 0xAC, 0xCF, 
+0xAC, 0xEF, 0xBD, 0x10, 0xB5, 0x10, 0x94, 0x2D, 
+0x83, 0xED, 0x83, 0xED, 0x94, 0x90, 0xCE, 0x38, 
+0xAD, 0x55, 0x9C, 0xD3, 0x84, 0x0F, 0x8C, 0x4F, 
+0xA4, 0xF2, 0xAD, 0x73, 0xA5, 0x12, 0xA4, 0xF2, 
+0xA4, 0xF2, 0x8C, 0x2F, 0x8C, 0x2F, 0x83, 0xCE, 
+0x63, 0x0B, 0x52, 0xAA, 0x39, 0xE7, 0x42, 0x07, 
+0x52, 0x69, 0x62, 0xCA, 0x73, 0x2C, 0x6B, 0x0B, 
+0x9C, 0x70, 0xBD, 0x54, 0x9C, 0x91, 0x41, 0xC7, 
+0x5A, 0x8A, 0x7B, 0x6D, 0x83, 0xAE, 0xAC, 0xF2, 
+0x94, 0x4F, 0x94, 0x4F, 0xDE, 0x77, 0xDE, 0xB7, 
+0xDE, 0xB7, 0xE6, 0xF8, 0xDE, 0xB8, 0xD6, 0x56, 
+0xCE, 0x36, 0xCE, 0x15, 0xBD, 0x94, 0xBD, 0xD5, 
+0xAD, 0x52, 0xAD, 0x32, 0xB5, 0x53, 0xB5, 0x53, 
+0x83, 0xCC, 0xA4, 0x8F, 0xB5, 0x11, 0xBD, 0x72, 
+0xBD, 0x93, 0xC5, 0xB3, 0xCD, 0xD4, 0xD5, 0xF5, 
+0xD5, 0xF5, 0xD5, 0xF4, 0xD5, 0xF4, 0xC5, 0x93, 
+0xC5, 0x73, 0xC5, 0x73, 0xAC, 0xF1, 0x73, 0x4C, 
+0x29, 0x45, 0x21, 0x25, 0x18, 0xE4, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x10, 0xA4, 0x18, 0xE5, 0x29, 0x46, 0x21, 0x26, 
+0x21, 0x25, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x18, 0xE5, 0x18, 0xE4, 0x18, 0xE5, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x18, 0xE5, 0x18, 0xE4, 
+0x18, 0xE5, 0x18, 0xE5, 0x21, 0x26, 0x29, 0x67, 
+0x31, 0x87, 0x31, 0xA8, 0x29, 0x87, 0x29, 0x87, 
+0x29, 0x67, 0x31, 0xA8, 0x42, 0x2A, 0x4A, 0x6B, 
+0x4A, 0x8B, 0x6B, 0x4C, 0x8C, 0x2F, 0x83, 0xED, 
+0x83, 0xED, 0x6B, 0x2B, 0x7B, 0x8C, 0x94, 0x4F, 
+0xA4, 0xB0, 0xC5, 0xB3, 0xCD, 0xD4, 0xB5, 0x11, 
+0xA4, 0xD0, 0xA4, 0xB0, 0xAC, 0xF1, 0xB5, 0x32, 
+0xBD, 0x73, 0xC5, 0x93, 0xC5, 0xB4, 0xC5, 0xB4, 
+0xBD, 0x52, 0xBD, 0x93, 0xB5, 0x32, 0xC5, 0xB4, 
+0xC5, 0xB4, 0xC5, 0xB4, 0xBD, 0x93, 0xBD, 0x73, 
+0xBD, 0x52, 0xBD, 0x73, 0xB5, 0x12, 0xAD, 0x12, 
+0xAD, 0x32, 0xA4, 0xB0, 0xA4, 0xD1, 0xAD, 0x53, 
+0x7B, 0x8D, 0x39, 0xC7, 0x39, 0xA6, 0x4A, 0x28, 
+0x42, 0x08, 0x39, 0xC7, 0x31, 0x65, 0x39, 0x86, 
+0x39, 0xC7, 0x41, 0xC7, 0x52, 0x28, 0x5A, 0x89, 
+0x49, 0xE7, 0x7B, 0x6D, 0x9C, 0x50, 0x62, 0xCB, 
+0x84, 0xEE, 0xB6, 0x73, 0x6C, 0x4A, 0x53, 0x85, 
+0x6C, 0x48, 0x85, 0x0B, 0x6C, 0x47, 0x95, 0x6C, 
+0x95, 0x4D, 0x8C, 0xEB, 0x74, 0x67, 0x6C, 0x65, 
+0x74, 0xC6, 0x64, 0x24, 0x7C, 0xE8, 0x6C, 0x67, 
+0x7C, 0xE8, 0x74, 0xC5, 0xB6, 0x4F, 0xBE, 0x54, 
+0xA5, 0x92, 0xA5, 0x92, 0x94, 0xCF, 0xA5, 0x10, 
+0x94, 0x6E, 0xBD, 0xD5, 0xBD, 0xF6, 0x8C, 0x70, 
+0x84, 0x2F, 0x7B, 0xCE, 0x84, 0x0F, 0x8C, 0x2F, 
+0x84, 0x0E, 0x7B, 0xEE, 0xA5, 0x33, 0xC6, 0x37, 
+0xCE, 0x37, 0xC6, 0x37, 0xA5, 0x33, 0x94, 0xB1, 
+0x8C, 0x70, 0x9C, 0xD2, 0x94, 0x90, 0x94, 0x91, 
+0xA5, 0x13, 0xB5, 0x95, 0xA4, 0xF1, 0xBD, 0x51, 
+0xA4, 0x8E, 0xC5, 0xB3, 0xBD, 0x93, 0xC5, 0xD4, 
+0xBD, 0x93, 0xBD, 0x93, 0xC5, 0xD4, 0xB5, 0x72, 
+0xBD, 0x93, 0xBD, 0xB3, 0xAD, 0x11, 0xB5, 0x32, 
+0xAD, 0x52, 0xAD, 0x31, 0xAD, 0x32, 0xAD, 0x32, 
+0xAD, 0x11, 0xA4, 0xD0, 0x9C, 0xCF, 0xAD, 0x11, 
+0xB5, 0x52, 0xBD, 0x72, 0xB5, 0x10, 0xAC, 0xCF, 
+0xCE, 0x14, 0xBD, 0x93, 0xB5, 0x52, 0xAD, 0x32, 
+0xAD, 0x32, 0x9C, 0xD1, 0xAD, 0x11, 0xA4, 0xB0, 
+0x9C, 0x8F, 0x9C, 0x8F, 0xA4, 0xD0, 0xAD, 0x11, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xAD, 0x11, 0xAD, 0x11, 
+0xA4, 0xD0, 0x8B, 0xEC, 0x8B, 0xED, 0xC5, 0xD6, 
+0xB5, 0x34, 0x73, 0x4C, 0x4A, 0x28, 0x21, 0x04, 
+0x21, 0x04, 0x21, 0x24, 0x29, 0x44, 0x39, 0xC6, 
+0x4A, 0x69, 0x5A, 0xAB, 0x6B, 0x6D, 0x7B, 0xF0, 
+0x84, 0x31, 0x9C, 0xD3, 0xAD, 0x55, 0xAD, 0x76, 
+0xBD, 0xD8, 0xB5, 0x96, 0x83, 0xF0, 0x83, 0xEE, 
+0x9C, 0x90, 0xA4, 0x8F, 0x94, 0x2E, 0x9C, 0x6E, 
+0xA4, 0xAF, 0xAC, 0xCF, 0xB5, 0x0F, 0xB5, 0x10, 
+0xB5, 0x30, 0xBD, 0x50, 0xBD, 0x71, 0xB5, 0x30, 
+0xC5, 0x71, 0xC5, 0x71, 0xBD, 0x50, 0xBD, 0x50, 
+0xBD, 0x50, 0xBD, 0x50, 0xC5, 0x50, 0xC5, 0x71, 
+0xC5, 0x71, 0xC5, 0x71, 0xC5, 0x93, 0xCE, 0x58, 
+0xA5, 0x35, 0x94, 0xB2, 0x9C, 0xB1, 0x9C, 0x6F, 
+0xAC, 0xD0, 0xAC, 0xCF, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xAC, 0xAF, 0xA4, 0x8E, 0xAC, 0xAF, 0xAC, 0xAF, 
+0xA4, 0xAF, 0x94, 0x4E, 0x39, 0xA6, 0x42, 0x28, 
+0x5A, 0xCA, 0x52, 0x69, 0x7B, 0x4D, 0x62, 0xCB, 
+0x83, 0xCE, 0x94, 0x30, 0x94, 0x50, 0x8C, 0x10, 
+0x39, 0x86, 0x7B, 0x6D, 0x5A, 0x69, 0x52, 0x28, 
+0x7B, 0x4C, 0x8B, 0xEF, 0xAC, 0xF2, 0xD6, 0x56, 
+0xD6, 0x56, 0xD6, 0x56, 0xD6, 0x56, 0xCE, 0x15, 
+0xCE, 0x15, 0xC5, 0xF5, 0xBD, 0xB4, 0xBD, 0xD4, 
+0xA5, 0x12, 0xBD, 0x94, 0xB5, 0x53, 0xBD, 0x73, 
+0x7B, 0x8B, 0x94, 0x4E, 0xA4, 0xB0, 0xCD, 0xD4, 
+0xCD, 0xF4, 0xCD, 0xD4, 0xCD, 0xF4, 0xD5, 0xF4, 
+0xD6, 0x15, 0xD6, 0x15, 0xDE, 0x35, 0xDE, 0x35, 
+0xCD, 0xB4, 0xD5, 0xF5, 0xBD, 0x93, 0x83, 0xAD, 
+0x39, 0xA6, 0x29, 0x25, 0x18, 0xE4, 0x10, 0xC3, 
+0x10, 0xC3, 0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x21, 0x05, 0x18, 0xE4, 0x21, 0x05, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x10, 0xA3, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC3, 0x18, 0xE4, 0x29, 0x46, 0x21, 0x25, 
+0x21, 0x25, 0x21, 0x25, 0x21, 0x05, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xE4, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE5, 0x18, 0xE5, 0x18, 0xE5, 0x21, 0x46, 
+0x29, 0x67, 0x31, 0x87, 0x31, 0xA8, 0x31, 0xC8, 
+0x31, 0x87, 0x29, 0x67, 0x31, 0xC8, 0x42, 0x4A, 
+0x4A, 0x8B, 0x52, 0x8B, 0x6B, 0x6D, 0x94, 0x70, 
+0x94, 0x4F, 0x62, 0xEA, 0x8C, 0x4F, 0xBD, 0x53, 
+0xC5, 0x92, 0xD5, 0xF3, 0xE6, 0x96, 0xE6, 0x96, 
+0xE6, 0x96, 0xE6, 0x96, 0xE6, 0x96, 0xDE, 0x76, 
+0xDE, 0x55, 0xDE, 0x55, 0xDE, 0x55, 0xCD, 0xF4, 
+0xA4, 0xB0, 0x94, 0x4E, 0xB5, 0x52, 0xBD, 0x72, 
+0xCD, 0xD4, 0xDE, 0x56, 0xE6, 0x96, 0xDE, 0x56, 
+0xD6, 0x15, 0xDE, 0x76, 0xD6, 0x36, 0xAC, 0xF1, 
+0x94, 0x6F, 0xB5, 0x32, 0xA4, 0xB0, 0x9C, 0xB0, 
+0x83, 0xCE, 0x52, 0x69, 0x18, 0xE3, 0x31, 0x86, 
+0x39, 0xA7, 0x31, 0x86, 0x5A, 0xEB, 0x84, 0x10, 
+0x42, 0x08, 0x4A, 0x08, 0x62, 0xAA, 0x62, 0x8A, 
+0x49, 0xE7, 0x83, 0x8D, 0x83, 0xAD, 0x83, 0xAE, 
+0x8D, 0x4F, 0xBE, 0x95, 0xBE, 0x54, 0x6C, 0x09, 
+0x64, 0x07, 0x64, 0x07, 0x6C, 0x07, 0x64, 0x07, 
+0x84, 0xCB, 0x8D, 0x0B, 0x85, 0x08, 0x74, 0x85, 
+0x7C, 0xE6, 0x85, 0x47, 0x95, 0x89, 0x64, 0x25, 
+0x74, 0xA7, 0x74, 0x87, 0x95, 0x4C, 0x8C, 0xCD, 
+0x8C, 0xEE, 0x94, 0xEF, 0x8C, 0x6D, 0xAD, 0x30, 
+0x9C, 0xAF, 0xBD, 0xD5, 0xB5, 0x94, 0x8C, 0x71, 
+0x8C, 0x50, 0x84, 0x0F, 0x84, 0x30, 0x63, 0x2B, 
+0x73, 0xCD, 0x94, 0xB1, 0xA5, 0x54, 0xD6, 0x98, 
+0xCE, 0x37, 0xCE, 0x77, 0xAD, 0x53, 0xAD, 0x74, 
+0xB5, 0xB5, 0xBD, 0xD6, 0x9C, 0xF2, 0x94, 0xD2, 
+0xA5, 0x33, 0xAD, 0x53, 0xA4, 0xD0, 0xB5, 0x31, 
+0xA4, 0xAF, 0xC5, 0xD3, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xC5, 0xB4, 0xBD, 0x93, 0xC5, 0xF4, 0xBD, 0x93, 
+0xBD, 0x72, 0xBD, 0xB3, 0xB5, 0x72, 0xC6, 0x15, 
+0xBD, 0xB3, 0xB5, 0x52, 0xB5, 0x32, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xAD, 0x11, 0xAD, 0x52, 0xB5, 0x52, 
+0xAD, 0x31, 0xBD, 0x92, 0xB5, 0x10, 0xAC, 0xAF, 
+0xCD, 0xF4, 0xBD, 0xB4, 0xB5, 0x73, 0xBD, 0xD4, 
+0xB5, 0x73, 0xAD, 0x53, 0xBD, 0x94, 0xC5, 0xD4, 
+0xC5, 0xF5, 0xBD, 0x93, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x52, 0xBD, 0x93, 
+0xBD, 0xB4, 0xB5, 0x72, 0xB5, 0x53, 0xCE, 0x17, 
+0xAD, 0x13, 0xAC, 0xF2, 0x9C, 0x4F, 0x41, 0xE7, 
+0x31, 0x85, 0x31, 0xA5, 0x42, 0x28, 0x39, 0xE7, 
+0x42, 0x08, 0x52, 0x8A, 0x6B, 0x2D, 0x73, 0xAF, 
+0x7C, 0x10, 0x9C, 0xF4, 0x9C, 0xF4, 0x84, 0x31, 
+0xC6, 0x19, 0xB5, 0x76, 0x83, 0xEF, 0x83, 0xEF, 
+0x7B, 0x8C, 0xBD, 0x94, 0x9C, 0x90, 0x94, 0x2F, 
+0x73, 0x6B, 0x62, 0xE9, 0x5A, 0xA8, 0x62, 0xC8, 
+0x62, 0xA8, 0x6B, 0x09, 0x83, 0xAB, 0x83, 0xCB, 
+0xB5, 0x30, 0x9C, 0x6E, 0x9C, 0x6D, 0xAC, 0xCE, 
+0xA4, 0x8D, 0xAC, 0xCE, 0xBD, 0x50, 0xBD, 0x50, 
+0xBD, 0x50, 0xBD, 0x50, 0xC5, 0xB4, 0xC6, 0x17, 
+0xAD, 0x55, 0x94, 0x92, 0xA4, 0xD1, 0xD6, 0x35, 
+0xEE, 0xD7, 0xDE, 0x35, 0xD6, 0x14, 0xD5, 0xF3, 
+0xCD, 0xB2, 0xBD, 0x51, 0xC5, 0x51, 0xBD, 0x30, 
+0xB5, 0x10, 0xAC, 0xAF, 0x83, 0xCC, 0x4A, 0x27, 
+0x52, 0x69, 0x4A, 0x08, 0x62, 0xAA, 0x6B, 0x0B, 
+0x4A, 0x08, 0x5A, 0xAA, 0x9C, 0x51, 0xCE, 0x17, 
+0x73, 0x6E, 0x39, 0x86, 0x52, 0x49, 0x52, 0x28, 
+0x94, 0x10, 0x94, 0x0F, 0xA4, 0xD2, 0x8B, 0xEE, 
+0xB5, 0x53, 0xAD, 0x11, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xAD, 0x11, 0xAD, 0x11, 0x9C, 0xB0, 0x83, 0xED, 
+0x83, 0xCD, 0xAD, 0x12, 0xA4, 0xB0, 0x8C, 0x0D, 
+0x7B, 0x8C, 0x83, 0xAC, 0x83, 0xED, 0x9C, 0x6F, 
+0xAD, 0x11, 0xB5, 0x32, 0xBD, 0x93, 0xBD, 0x93, 
+0xBD, 0x73, 0xB5, 0x32, 0xBD, 0x72, 0xC5, 0x93, 
+0xC5, 0xB4, 0xCD, 0xF5, 0xBD, 0x93, 0x8C, 0x0E, 
+0x4A, 0x07, 0x29, 0x45, 0x21, 0x04, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC3, 
+0x10, 0xA3, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 0x21, 0x25, 
+0x21, 0x05, 0x21, 0x05, 0x18, 0xC4, 0x10, 0xA3, 
+0x18, 0xC4, 0x18, 0xE4, 0x10, 0xA3, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x21, 0x25, 0x21, 0x25, 
+0x21, 0x05, 0x21, 0x25, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x21, 0x05, 0x21, 0x25, 0x21, 0x26, 0x21, 0x46, 
+0x29, 0x67, 0x21, 0x26, 0x29, 0x67, 0x31, 0xC8, 
+0x31, 0xC8, 0x31, 0x87, 0x29, 0x67, 0x31, 0xA8, 
+0x42, 0x0A, 0x4A, 0x4A, 0x4A, 0x6A, 0x73, 0xAE, 
+0x94, 0x90, 0x6B, 0x4C, 0xA4, 0xF1, 0xC5, 0x93, 
+0xDE, 0x55, 0xDE, 0x14, 0xE6, 0x96, 0xEE, 0xB6, 
+0xEE, 0x96, 0xEE, 0xB6, 0xEE, 0xB7, 0xEE, 0x96, 
+0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x96, 
+0xEE, 0xD7, 0xEE, 0xD8, 0xC5, 0xD4, 0xCD, 0xD4, 
+0x9C, 0xB0, 0xDE, 0x76, 0xD6, 0x14, 0xD6, 0x14, 
+0xCD, 0xF4, 0xCD, 0xD3, 0xDE, 0x76, 0xA4, 0xB0, 
+0xB5, 0x53, 0xD6, 0x77, 0xC5, 0xD5, 0xBD, 0x94, 
+0xA4, 0xF1, 0x7B, 0xAD, 0x39, 0xC7, 0x18, 0xC3, 
+0x18, 0xC3, 0x21, 0x04, 0x8C, 0x51, 0xCE, 0x39, 
+0x84, 0x11, 0x52, 0x49, 0x6A, 0xEB, 0x7B, 0x4C, 
+0x52, 0x08, 0x52, 0x28, 0x62, 0xAA, 0x94, 0x50, 
+0x53, 0x86, 0x84, 0xED, 0xA5, 0xD2, 0xAE, 0x12, 
+0x6C, 0x28, 0x64, 0x06, 0x63, 0xE6, 0x53, 0x65, 
+0x6C, 0x47, 0x7C, 0xA8, 0x85, 0x08, 0x7C, 0xE6, 
+0x95, 0x66, 0xA5, 0xE8, 0x74, 0x84, 0x6C, 0x85, 
+0x6C, 0x85, 0x85, 0x08, 0x84, 0xC9, 0x84, 0xAA, 
+0x84, 0xCB, 0x8C, 0x8D, 0x9C, 0xAE, 0xAC, 0xEF, 
+0x8C, 0x2D, 0xB5, 0xB4, 0xB5, 0xD5, 0xA5, 0x54, 
+0x9D, 0x13, 0xA5, 0x13, 0x94, 0xB1, 0x84, 0x2F, 
+0x94, 0x90, 0xA5, 0x13, 0xA5, 0x53, 0xBD, 0xD5, 
+0xB5, 0x94, 0xBD, 0xD5, 0xA5, 0x12, 0xAD, 0x54, 
+0xBD, 0xD5, 0xBD, 0xF6, 0xA5, 0x33, 0xAD, 0x54, 
+0xAD, 0x74, 0xB5, 0x74, 0xA4, 0xD0, 0xB5, 0x10, 
+0xA4, 0xAF, 0xC5, 0xB3, 0xC5, 0xB4, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xF4, 0xBD, 0x93, 
+0xBD, 0x93, 0xBD, 0x93, 0xB5, 0x72, 0xC5, 0xF4, 
+0xC5, 0xD4, 0xC5, 0xB4, 0xBD, 0x93, 0xB5, 0x52, 
+0xB5, 0x72, 0xB5, 0x93, 0xBD, 0x93, 0xBD, 0x73, 
+0xAD, 0x11, 0xBD, 0x71, 0xBD, 0x30, 0xB5, 0x10, 
+0xCE, 0x14, 0xC5, 0xD4, 0xBD, 0x93, 0xBD, 0x94, 
+0xAD, 0x32, 0xBD, 0xD5, 0xC6, 0x15, 0xCE, 0x15, 
+0xD6, 0x56, 0xCE, 0x15, 0xCE, 0x15, 0xCE, 0x35, 
+0xC5, 0xF5, 0xCE, 0x15, 0xBD, 0xD4, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xCE, 0x36, 0xBD, 0x95, 
+0xAD, 0x13, 0xAC, 0xF1, 0xAD, 0x11, 0x6A, 0xEA, 
+0x4A, 0x48, 0x42, 0x07, 0x39, 0xE7, 0x39, 0xA6, 
+0x4A, 0x48, 0x5A, 0xAA, 0x62, 0xEC, 0x63, 0x0C, 
+0x7B, 0xD0, 0x8C, 0x31, 0x84, 0x31, 0xAD, 0x55, 
+0xC6, 0x18, 0xA4, 0xF3, 0x8C, 0x51, 0xA4, 0xF3, 
+0x4A, 0x28, 0x8C, 0x50, 0xC5, 0xF7, 0xA4, 0xF2, 
+0xB5, 0x53, 0xB5, 0x73, 0xAD, 0x32, 0x9C, 0xB0, 
+0x84, 0x0E, 0x7B, 0xAD, 0x5A, 0xC9, 0x6B, 0x2A, 
+0x8C, 0x2E, 0x6B, 0x2A, 0x52, 0x48, 0x52, 0x68, 
+0x52, 0x68, 0x62, 0xC8, 0x8B, 0xEC, 0xB5, 0x31, 
+0xB5, 0x52, 0xA4, 0xB0, 0xBD, 0xB5, 0xBD, 0xD7, 
+0xAD, 0x35, 0x94, 0x71, 0xBD, 0x73, 0xD6, 0x35, 
+0xDE, 0x96, 0xD6, 0x55, 0xD6, 0x14, 0xCD, 0xF4, 
+0xC5, 0x92, 0xD6, 0x14, 0xC5, 0x92, 0xBD, 0x51, 
+0xBD, 0x72, 0xBD, 0x72, 0xC5, 0xB3, 0xAD, 0x12, 
+0x4A, 0x07, 0x41, 0xE7, 0x6A, 0xEB, 0x73, 0x0B, 
+0x5A, 0x69, 0x62, 0xCB, 0x9C, 0x71, 0xC5, 0xD6, 
+0xC5, 0xB6, 0x5A, 0x8A, 0x73, 0x2C, 0x7B, 0x8D, 
+0x73, 0x2C, 0x9C, 0x70, 0x94, 0x0F, 0x9C, 0x50, 
+0xBD, 0x94, 0xBD, 0x94, 0xB5, 0x53, 0xBD, 0x94, 
+0xBD, 0x94, 0xAD, 0x32, 0xBD, 0xB4, 0xC5, 0xB5, 
+0xBD, 0x94, 0xC5, 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 
+0xC5, 0xD5, 0xC5, 0xB5, 0xBD, 0x94, 0xB5, 0x73, 
+0xB5, 0x32, 0xAD, 0x11, 0xA4, 0xD1, 0xA4, 0xD1, 
+0xAC, 0xF2, 0xA4, 0xF2, 0xA4, 0xD1, 0x9C, 0x90, 
+0x94, 0x6F, 0x8C, 0x0E, 0x83, 0xCD, 0x83, 0xAD, 
+0x52, 0x48, 0x29, 0x45, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xE4, 0x18, 0xC3, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xE4, 0x21, 0x25, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x21, 0x05, 0x21, 0x25, 
+0x18, 0xE5, 0x21, 0x05, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE5, 
+0x21, 0x05, 0x21, 0x26, 0x21, 0x46, 0x29, 0x46, 
+0x29, 0x46, 0x21, 0x26, 0x21, 0x26, 0x29, 0x67, 
+0x31, 0xA8, 0x31, 0xA8, 0x29, 0x87, 0x29, 0x67, 
+0x39, 0xC8, 0x42, 0x29, 0x42, 0x2A, 0x4A, 0x8B, 
+0x84, 0x0F, 0x7B, 0xCE, 0xA4, 0xF1, 0xC5, 0xD4, 
+0xD6, 0x14, 0xDE, 0x14, 0xE6, 0x75, 0xEE, 0xB6, 
+0xEE, 0xB6, 0xEE, 0x96, 0xEE, 0xB6, 0xE6, 0x96, 
+0xDE, 0x54, 0xD6, 0x13, 0xD5, 0xF3, 0xCD, 0xD3, 
+0xDE, 0x35, 0xDE, 0x76, 0xBD, 0x93, 0xE6, 0xB8, 
+0xDE, 0x97, 0xDE, 0x76, 0xD6, 0x35, 0xD6, 0x14, 
+0xD6, 0x34, 0xD5, 0xF4, 0xDE, 0x76, 0xA4, 0xD0, 
+0xBD, 0x94, 0xBD, 0x93, 0xBD, 0x93, 0xC5, 0xB4, 
+0xB5, 0x73, 0x9C, 0xD1, 0x7B, 0xCE, 0x29, 0x66, 
+0x10, 0xA3, 0x18, 0xE4, 0x39, 0xC7, 0xB5, 0x97, 
+0xBD, 0xB7, 0x73, 0x4D, 0x6A, 0xCB, 0x83, 0xAE, 
+0x52, 0x08, 0x7B, 0x6D, 0x6A, 0xEA, 0x8C, 0x0F, 
+0x4B, 0x44, 0x53, 0xA6, 0x7C, 0xCC, 0x95, 0x6F, 
+0x6C, 0x48, 0x64, 0x06, 0x64, 0x07, 0x53, 0x45, 
+0x64, 0x27, 0x74, 0xA7, 0x6C, 0x65, 0x74, 0x84, 
+0x8D, 0x44, 0x9D, 0xC7, 0x5B, 0xE2, 0x4B, 0x61, 
+0x53, 0xC2, 0x7C, 0xE7, 0x74, 0x86, 0x74, 0x66, 
+0x7C, 0x88, 0x7C, 0x69, 0x9C, 0xCD, 0xB5, 0x50, 
+0x9C, 0x8E, 0x9C, 0xB0, 0xA4, 0xF1, 0xA5, 0x12, 
+0xAD, 0x73, 0xBD, 0xB5, 0xBD, 0x94, 0xA4, 0xD1, 
+0x9C, 0xB0, 0xA5, 0x12, 0xAD, 0x53, 0xAD, 0x53, 
+0xAD, 0x33, 0xB5, 0xB4, 0x8C, 0x4F, 0xBD, 0xB5, 
+0xC6, 0x37, 0xBD, 0xF6, 0xB5, 0x94, 0xBD, 0xD5, 
+0xB5, 0x94, 0xAD, 0x53, 0xAC, 0xF0, 0xB5, 0x10, 
+0xA4, 0xAF, 0xC5, 0xD3, 0xC5, 0xD4, 0xC5, 0xF5, 
+0xC5, 0xD4, 0xC5, 0xF4, 0xCE, 0x15, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xB5, 0x52, 0xCE, 0x15, 
+0xCE, 0x15, 0xC5, 0xF5, 0xC5, 0xD4, 0xBD, 0xB4, 
+0xBD, 0x93, 0xBD, 0x93, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xBD, 0xB3, 0xB5, 0x51, 0xBD, 0x31, 0xAD, 0x10, 
+0xCD, 0xF4, 0xCE, 0x15, 0xCE, 0x15, 0xC5, 0xF5, 
+0xB5, 0x73, 0xCE, 0x36, 0xC5, 0xF5, 0xB5, 0x53, 
+0xC5, 0xF5, 0xCE, 0x15, 0xCE, 0x36, 0xCE, 0x35, 
+0xAD, 0x12, 0xB5, 0x73, 0xCE, 0x16, 0xC6, 0x15, 
+0xBD, 0xD4, 0xC5, 0xF5, 0xC5, 0xF5, 0xAD, 0x12, 
+0xAD, 0x12, 0xAC, 0xF0, 0xAD, 0x10, 0xA4, 0xB1, 
+0x52, 0x89, 0x52, 0x69, 0x41, 0xE7, 0x42, 0x07, 
+0x42, 0x28, 0x4A, 0x69, 0x52, 0x8A, 0x5A, 0xEB, 
+0x5A, 0xEB, 0x6B, 0x6D, 0x9C, 0xB3, 0xAD, 0x76, 
+0x9C, 0xF4, 0x73, 0x8E, 0xA4, 0xF3, 0xBD, 0x96, 
+0x5A, 0xAB, 0x39, 0xA7, 0x83, 0xEF, 0xB5, 0x54, 
+0xCD, 0xF5, 0xD6, 0x76, 0xCE, 0x36, 0xC5, 0xF5, 
+0xCE, 0x15, 0xD6, 0x56, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xAD, 0x32, 0xA5, 0x11, 0x9C, 0xB1, 0x94, 0x6F, 
+0x84, 0x0E, 0x7B, 0xAD, 0x8C, 0x0E, 0x8C, 0x4F, 
+0x94, 0x4F, 0x8C, 0x2F, 0xC6, 0x38, 0xB5, 0x96, 
+0xA5, 0x35, 0x9C, 0xB2, 0xBD, 0x53, 0xBD, 0x93, 
+0xBD, 0x93, 0xB5, 0x52, 0xBD, 0x72, 0xCD, 0xF4, 
+0xB5, 0x72, 0xBD, 0x72, 0xB5, 0x31, 0xB5, 0x31, 
+0xB5, 0x51, 0xC5, 0xB3, 0xC5, 0xD4, 0xBD, 0x73, 
+0x5A, 0x89, 0x39, 0x86, 0x6B, 0x2C, 0x52, 0x48, 
+0x39, 0xC6, 0x4A, 0x28, 0x6A, 0xEA, 0x9C, 0x50, 
+0xCD, 0xF7, 0x94, 0x30, 0x62, 0x8A, 0x9C, 0x50, 
+0x73, 0x2C, 0x73, 0x2C, 0x94, 0x2F, 0xAD, 0x12, 
+0xBD, 0x74, 0x94, 0x50, 0x73, 0x4B, 0xB5, 0x53, 
+0xA4, 0xF1, 0xB5, 0x53, 0x9C, 0x90, 0x83, 0xCD, 
+0x83, 0xCD, 0x94, 0x4F, 0x94, 0x4F, 0x8C, 0x0E, 
+0x94, 0x4F, 0x9C, 0x6F, 0x9C, 0x4F, 0xA4, 0xD1, 
+0xAD, 0x12, 0xAD, 0x11, 0xBD, 0x73, 0xA4, 0xD1, 
+0xAD, 0x12, 0xBD, 0x73, 0xBD, 0x73, 0xB5, 0x53, 
+0xBD, 0x94, 0xBD, 0x74, 0xBD, 0x94, 0xA4, 0x90, 
+0x4A, 0x08, 0x29, 0x45, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC4, 
+0x10, 0xA3, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC4, 0x18, 0xE4, 0x21, 0x25, 
+0x18, 0xE4, 0x10, 0xA4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA4, 0x10, 0xA3, 
+0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x21, 0x05, 
+0x18, 0xE4, 0x18, 0xE5, 0x18, 0xE4, 0x10, 0xC4, 
+0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA4, 0x10, 0xC4, 0x18, 0xE4, 
+0x19, 0x05, 0x21, 0x25, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x46, 0x29, 0x46, 0x21, 0x26, 0x21, 0x26, 
+0x29, 0x46, 0x29, 0x87, 0x31, 0x88, 0x29, 0x67, 
+0x31, 0x87, 0x39, 0xE9, 0x42, 0x2A, 0x4A, 0x4A, 
+0x5A, 0xEC, 0x7B, 0xAE, 0xA4, 0xF2, 0xC5, 0xD4, 
+0xDE, 0x35, 0xD5, 0xD3, 0xE6, 0x75, 0xE6, 0x96, 
+0xEE, 0x96, 0xEE, 0x96, 0xEE, 0xB6, 0xE6, 0x75, 
+0xE6, 0x75, 0xD6, 0x14, 0xD5, 0xF4, 0xD5, 0xF4, 
+0xDE, 0x35, 0xCD, 0xF4, 0xC5, 0xD4, 0xDE, 0x97, 
+0xDE, 0x56, 0xCD, 0xD4, 0xD6, 0x35, 0xCE, 0x14, 
+0xCD, 0xF4, 0xDE, 0x76, 0xD6, 0x35, 0xA4, 0xF1, 
+0xA4, 0xD0, 0x9C, 0x8F, 0xC5, 0xF4, 0xC5, 0xF4, 
+0xB5, 0x73, 0xAD, 0x12, 0xC5, 0xF5, 0x73, 0x8D, 
+0x18, 0xE4, 0x18, 0xA3, 0x41, 0xE8, 0xAD, 0x35, 
+0xCE, 0x59, 0xAD, 0x35, 0x41, 0xC7, 0x52, 0x48, 
+0x39, 0x85, 0x6A, 0xCB, 0x8B, 0xAE, 0x94, 0x0F, 
+0x7C, 0xEA, 0x53, 0xE6, 0x64, 0x48, 0x74, 0xAA, 
+0x64, 0x26, 0x5B, 0xC5, 0x74, 0x69, 0x5B, 0x87, 
+0x42, 0xE4, 0x6C, 0x27, 0x6C, 0x26, 0x6C, 0x45, 
+0x6C, 0x63, 0x6C, 0x24, 0x7C, 0x6A, 0x74, 0x28, 
+0x6C, 0x26, 0x7C, 0xA8, 0x6C, 0x06, 0x5B, 0xA4, 
+0x63, 0xE6, 0x8C, 0xAA, 0x9C, 0xED, 0xAC, 0xCE, 
+0xB5, 0x10, 0xAD, 0x10, 0xB5, 0x51, 0xBD, 0x51, 
+0xAC, 0xF0, 0xBD, 0x51, 0xBD, 0x52, 0xC5, 0x92, 
+0xBD, 0x51, 0xB5, 0x31, 0xAD, 0x10, 0xAC, 0xF0, 
+0xAD, 0x10, 0xAC, 0xF0, 0xA4, 0xAF, 0xA4, 0xD0, 
+0xAD, 0x11, 0xAD, 0x31, 0xAD, 0x32, 0xAD, 0x11, 
+0xA4, 0xD0, 0x9C, 0x6E, 0xB5, 0x31, 0xC5, 0x71, 
+0xB4, 0xF0, 0xB5, 0x30, 0xB5, 0x10, 0xB5, 0x31, 
+0xBD, 0x72, 0xBD, 0x72, 0xB5, 0x52, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xAC, 0xF0, 0xAC, 0xF0, 0xB5, 0x52, 
+0xBD, 0x72, 0xB5, 0x52, 0xB5, 0x32, 0xBD, 0x72, 
+0xC5, 0xB4, 0xC5, 0xD4, 0xCE, 0x15, 0xCE, 0x15, 
+0xC5, 0xD4, 0xB5, 0x31, 0xC5, 0x71, 0xA4, 0xAF, 
+0xD6, 0x76, 0xCE, 0x15, 0xCE, 0x15, 0xCE, 0x36, 
+0xC6, 0x15, 0xCE, 0x56, 0xCE, 0x36, 0xC6, 0x15, 
+0xC6, 0x15, 0xCE, 0x35, 0xCE, 0x15, 0xCE, 0x15, 
+0xC5, 0xD5, 0xCE, 0x56, 0xCE, 0x16, 0xCE, 0x35, 
+0xC6, 0x15, 0xCE, 0x15, 0xC5, 0xF5, 0xAD, 0x33, 
+0xB5, 0x74, 0xA4, 0xB0, 0xBD, 0x52, 0xD6, 0x57, 
+0x63, 0x0B, 0x62, 0xEB, 0x39, 0xC6, 0x39, 0xE7, 
+0x42, 0x07, 0x42, 0x28, 0x4A, 0x48, 0x52, 0x8A, 
+0x6B, 0x4D, 0x8C, 0x51, 0x8C, 0x72, 0x94, 0x92, 
+0x84, 0x10, 0x84, 0x31, 0x8C, 0x51, 0x94, 0x71, 
+0x73, 0x6E, 0x5A, 0xAB, 0x4A, 0x48, 0xA4, 0xF3, 
+0xCD, 0xF6, 0xD6, 0x56, 0xCE, 0x14, 0xCE, 0x15, 
+0xCE, 0x15, 0xD6, 0x56, 0xBD, 0x92, 0xCE, 0x35, 
+0xCE, 0x35, 0xCE, 0x15, 0xCE, 0x15, 0xCE, 0x36, 
+0xC5, 0xD4, 0xBD, 0x94, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xB5, 0x94, 0xAD, 0x53, 0xCE, 0x59, 0xAD, 0x55, 
+0x9C, 0xF4, 0xA4, 0xF2, 0xB5, 0x52, 0xD6, 0x36, 
+0xC5, 0xB4, 0xB5, 0x52, 0xB5, 0x72, 0xBD, 0xB3, 
+0xBD, 0xB3, 0xB5, 0x72, 0xBD, 0x72, 0xB5, 0x72, 
+0xB5, 0x31, 0xAD, 0x11, 0xBD, 0x92, 0x83, 0xCD, 
+0x73, 0x4C, 0x6B, 0x0B, 0x42, 0x07, 0x41, 0xE7, 
+0x42, 0x07, 0x41, 0xE7, 0x5A, 0xAA, 0x7B, 0x6C, 
+0x83, 0xCE, 0x73, 0x4C, 0x52, 0x49, 0x49, 0xE7, 
+0x6B, 0x0C, 0x6A, 0xEB, 0x83, 0xAE, 0x94, 0x50, 
+0xB5, 0x33, 0x94, 0x2F, 0x83, 0xCE, 0x5A, 0x89, 
+0x6B, 0x2B, 0x83, 0xAD, 0x62, 0xEA, 0x4A, 0x48, 
+0x52, 0x49, 0x52, 0x68, 0x5A, 0xA9, 0x6B, 0x2B, 
+0x7B, 0x8C, 0x9C, 0x90, 0x9C, 0x4F, 0xAD, 0x12, 
+0xAD, 0x12, 0xAC, 0xF1, 0xB5, 0x53, 0xAD, 0x11, 
+0xBD, 0x73, 0xBD, 0x73, 0xBD, 0x93, 0xB5, 0x52, 
+0xBD, 0x52, 0xBD, 0x73, 0xCD, 0xD4, 0xA4, 0x90, 
+0x41, 0xC7, 0x29, 0x45, 0x21, 0x25, 0x21, 0x25, 
+0x21, 0x04, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 0x21, 0x25, 
+0x18, 0xE4, 0x10, 0xC3, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xA3, 0x10, 0xA4, 0x10, 0xC4, 0x10, 0xC4, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x29, 0x87, 0x31, 0x88, 
+0x29, 0x67, 0x31, 0xA8, 0x39, 0xE9, 0x42, 0x4A, 
+0x42, 0x4A, 0x63, 0x0C, 0xA4, 0xD1, 0xC5, 0xB3, 
+0xE6, 0x96, 0xDE, 0x14, 0xDE, 0x55, 0xE6, 0x96, 
+0xEE, 0x96, 0xEE, 0x96, 0xEE, 0x96, 0xE6, 0x75, 
+0xE6, 0x75, 0xCD, 0xF3, 0xCD, 0xB3, 0xCD, 0xD3, 
+0xDE, 0x55, 0xCD, 0xF4, 0xD6, 0x36, 0xE6, 0xB7, 
+0xDE, 0x77, 0xDE, 0x56, 0xD6, 0x35, 0xCD, 0xF4, 
+0xCD, 0xD4, 0xE6, 0x96, 0xC5, 0x93, 0xB5, 0x12, 
+0xBD, 0x73, 0xCD, 0xF5, 0xC5, 0xD4, 0xC5, 0xF4, 
+0xBD, 0x93, 0xAD, 0x53, 0xCE, 0x36, 0xBD, 0xD5, 
+0x31, 0x86, 0x18, 0xA3, 0x5A, 0xAB, 0xA4, 0xF3, 
+0xAD, 0x55, 0xBD, 0xD7, 0x4A, 0x69, 0x4A, 0x28, 
+0x31, 0x65, 0x52, 0x28, 0x8B, 0xAD, 0xB5, 0x12, 
+0x5B, 0xE6, 0x64, 0x47, 0x7C, 0xEA, 0x74, 0xA9, 
+0x5B, 0xE5, 0x6C, 0x28, 0x84, 0xCB, 0x6B, 0xEA, 
+0x3A, 0x64, 0x4A, 0xE5, 0x63, 0xC7, 0x7C, 0x89, 
+0x6C, 0x06, 0x8C, 0xED, 0xBE, 0x55, 0x95, 0x0E, 
+0x84, 0xAA, 0x95, 0x4C, 0x8C, 0xEB, 0x6C, 0x49, 
+0x64, 0x08, 0x6C, 0x08, 0x9C, 0xED, 0x9C, 0x6D, 
+0x7B, 0x49, 0x9C, 0x6E, 0x8C, 0x0C, 0x7B, 0x8B, 
+0x83, 0xCC, 0x7B, 0x8B, 0x83, 0xCB, 0x8B, 0xEC, 
+0x83, 0xCC, 0x8B, 0xEC, 0xAC, 0xCF, 0xAC, 0xF0, 
+0xA4, 0x8F, 0xA4, 0xAF, 0xAC, 0xCF, 0xB5, 0x10, 
+0xB5, 0x30, 0xC5, 0x92, 0xC5, 0x92, 0xCD, 0x92, 
+0xD5, 0xF3, 0xCD, 0xB2, 0xBD, 0x71, 0xBD, 0x50, 
+0xAC, 0xCF, 0xB4, 0xEF, 0xC5, 0x71, 0xC5, 0x92, 
+0xCD, 0x92, 0xC5, 0x72, 0xC5, 0x71, 0xC5, 0x92, 
+0xC5, 0x92, 0xC5, 0x92, 0xC5, 0x92, 0xC5, 0x71, 
+0xBD, 0x51, 0xBD, 0x31, 0xB4, 0xF0, 0xB5, 0x10, 
+0xB4, 0xF0, 0xA4, 0xCF, 0xAC, 0xCF, 0xB5, 0x31, 
+0xBD, 0x51, 0xBD, 0x50, 0xC5, 0x71, 0xB4, 0xEF, 
+0xB5, 0x10, 0xCE, 0x35, 0xC5, 0xB3, 0xB5, 0x52, 
+0xB5, 0x72, 0xC5, 0xF4, 0xCE, 0x35, 0xD6, 0x56, 
+0xCE, 0x36, 0xCE, 0x36, 0xD6, 0x56, 0xD6, 0x56, 
+0xC5, 0xD4, 0xBD, 0x93, 0xCE, 0x15, 0xCE, 0x15, 
+0xCE, 0x56, 0xD6, 0x97, 0xDE, 0x97, 0xC5, 0xD5, 
+0xB5, 0x54, 0x9C, 0x4F, 0xC5, 0x93, 0xDE, 0x98, 
+0x83, 0xEF, 0x73, 0x8D, 0x4A, 0x28, 0x39, 0xC6, 
+0x52, 0x89, 0x4A, 0x48, 0x4A, 0x48, 0x52, 0x69, 
+0x52, 0xAA, 0x5A, 0xEB, 0x7B, 0xCF, 0x8C, 0x72, 
+0xA4, 0xF4, 0xAD, 0x55, 0xBD, 0xB7, 0xB5, 0x97, 
+0xA4, 0xF3, 0x8C, 0x30, 0x9C, 0xD2, 0xBD, 0xB5, 
+0xCE, 0x15, 0xD6, 0x76, 0xD6, 0x35, 0xD6, 0x35, 
+0xDE, 0x56, 0xCD, 0xF4, 0xD6, 0x56, 0xD6, 0x36, 
+0xD6, 0x35, 0xDE, 0x76, 0xD6, 0x76, 0xD6, 0x76, 
+0xC5, 0xD4, 0xD6, 0x56, 0xCE, 0x16, 0xC5, 0xF5, 
+0xCE, 0x15, 0xC6, 0x16, 0xCE, 0x59, 0xB5, 0xB7, 
+0x9C, 0xB3, 0xAD, 0x12, 0xB5, 0x31, 0xB5, 0x72, 
+0xB5, 0x32, 0xBD, 0x73, 0xBD, 0x93, 0xCE, 0x15, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xC5, 0xD3, 0xC5, 0xD4, 0xC5, 0xD3, 0xCD, 0xF4, 
+0xD6, 0x15, 0xD6, 0x15, 0x94, 0x2E, 0x39, 0x85, 
+0x39, 0xC7, 0x42, 0x07, 0x73, 0x4C, 0x8C, 0x0F, 
+0x94, 0x30, 0x9C, 0x71, 0x9C, 0x92, 0x62, 0xAA, 
+0x39, 0xA6, 0x7B, 0x8D, 0x73, 0x2C, 0x8B, 0xEE, 
+0x8B, 0xEF, 0xB5, 0x34, 0x94, 0x71, 0x62, 0xCA, 
+0x5A, 0xCA, 0x52, 0x89, 0x52, 0xAA, 0x73, 0x6C, 
+0x94, 0x70, 0xA4, 0xD1, 0xAD, 0x32, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xB5, 0x72, 0xC5, 0xB4, 0xD6, 0x15, 
+0xBD, 0x93, 0xAD, 0x12, 0xB5, 0x53, 0xAD, 0x12, 
+0xC5, 0xB4, 0xC5, 0xD4, 0xCD, 0xF4, 0xC5, 0xD3, 
+0xCD, 0xD4, 0xC5, 0xB3, 0xCD, 0xD4, 0x9C, 0x4F, 
+0x41, 0xC7, 0x29, 0x25, 0x18, 0xE4, 0x21, 0x25, 
+0x18, 0xE4, 0x10, 0xA3, 0x18, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xE4, 0x21, 0x25, 
+0x18, 0xC3, 0x18, 0xE4, 0x21, 0x05, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x05, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC3, 
+0x10, 0xC3, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA4, 0x18, 0xC4, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x05, 0x21, 0x26, 0x29, 0x46, 0x21, 0x26, 
+0x29, 0x46, 0x29, 0x67, 0x29, 0x67, 0x31, 0xA8, 
+0x31, 0x87, 0x29, 0x87, 0x31, 0xC8, 0x39, 0xE9, 
+0x42, 0x2A, 0x4A, 0x4A, 0x8C, 0x0F, 0xAC, 0xF1, 
+0xBD, 0x52, 0xDE, 0x56, 0xEE, 0xD7, 0xF6, 0xF7, 
+0xF6, 0xF7, 0xF6, 0xF7, 0xEE, 0xD7, 0xEE, 0xD6, 
+0xEE, 0xD6, 0xE6, 0x96, 0xDE, 0x35, 0xDE, 0x75, 
+0xE6, 0x96, 0xCD, 0xD4, 0xDE, 0x76, 0xE6, 0xB7, 
+0xE6, 0x97, 0xDE, 0x56, 0xD6, 0x15, 0xCD, 0xD4, 
+0xC5, 0xB3, 0xDE, 0x76, 0xC5, 0x93, 0x9C, 0x8F, 
+0xCE, 0x36, 0xD6, 0x56, 0xCE, 0x15, 0xCE, 0x15, 
+0xBD, 0xB4, 0xAD, 0x32, 0xCE, 0x36, 0xD6, 0x77, 
+0x5A, 0xAA, 0x18, 0xE4, 0x29, 0x24, 0x6B, 0x2B, 
+0x94, 0x91, 0x62, 0xEA, 0x42, 0x07, 0x5A, 0xA9, 
+0x4A, 0x07, 0x52, 0x28, 0x6A, 0xCA, 0x8B, 0xCD, 
+0x63, 0xEA, 0x43, 0x44, 0x6C, 0x86, 0x64, 0x45, 
+0x6C, 0x47, 0x74, 0x69, 0x8D, 0x0D, 0x74, 0x2A, 
+0x6B, 0xEA, 0x42, 0x86, 0x42, 0x84, 0x53, 0x46, 
+0x64, 0x08, 0x6B, 0xEA, 0x84, 0x6D, 0x8C, 0xCD, 
+0x84, 0xAB, 0x9D, 0x2D, 0x94, 0xCD, 0xB5, 0xD1, 
+0xAD, 0xD1, 0xA5, 0x70, 0xBE, 0x13, 0xA4, 0xEF, 
+0x9C, 0xAF, 0x9C, 0xB0, 0x7B, 0xCC, 0xA4, 0xD1, 
+0xAD, 0x32, 0x8C, 0x2E, 0x9C, 0x8F, 0x9C, 0x90, 
+0x9C, 0x90, 0x83, 0xED, 0x94, 0x8F, 0x8C, 0x4E, 
+0x83, 0xED, 0x8C, 0x2E, 0x8C, 0x0E, 0xBD, 0x93, 
+0xBD, 0x51, 0x9C, 0x4D, 0xA4, 0x6D, 0xAC, 0xCE, 
+0xBD, 0x51, 0xB5, 0x31, 0xAC, 0xF0, 0x9C, 0x4D, 
+0x83, 0xAB, 0x73, 0x29, 0x94, 0x2D, 0x9C, 0x8E, 
+0xA4, 0x8F, 0xAC, 0xD0, 0xB5, 0x31, 0xA4, 0xAE, 
+0xB5, 0x31, 0xBD, 0x51, 0xBD, 0x51, 0xA4, 0x8E, 
+0x9C, 0x4D, 0xA4, 0xAF, 0xAC, 0xAF, 0xC5, 0x92, 
+0xC5, 0x92, 0xB4, 0xEF, 0xBD, 0x50, 0xB5, 0x10, 
+0xAC, 0xCF, 0xAC, 0xAF, 0xAC, 0xAE, 0xB4, 0xEF, 
+0xA4, 0x8E, 0xAC, 0xAF, 0xA4, 0x8E, 0x9C, 0x4E, 
+0xA4, 0xAF, 0xAC, 0xCF, 0xAC, 0xCF, 0xA4, 0x8E, 
+0xA4, 0x8E, 0xA4, 0xAF, 0xA4, 0xCF, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xAC, 0xD0, 0xAC, 0xF0, 
+0xAC, 0xF1, 0xAD, 0x11, 0xA4, 0xD0, 0x9C, 0x6F, 
+0x73, 0x4B, 0x9C, 0x6F, 0xC5, 0xD4, 0xCE, 0x15, 
+0x9C, 0x90, 0x83, 0xEE, 0x52, 0x89, 0x39, 0xE7, 
+0x42, 0x28, 0x52, 0x69, 0x42, 0x28, 0x42, 0x28, 
+0x52, 0x8A, 0x63, 0x0C, 0x7B, 0xCF, 0x94, 0x92, 
+0x9C, 0xF4, 0xA5, 0x35, 0xAD, 0x76, 0xAD, 0x55, 
+0xAD, 0x34, 0x7B, 0xAE, 0x9C, 0xB1, 0xDE, 0xB8, 
+0xD6, 0x77, 0xD6, 0x77, 0xCE, 0x15, 0xD6, 0x56, 
+0xD6, 0x55, 0xCE, 0x14, 0xCE, 0x15, 0xCE, 0x15, 
+0xBD, 0x93, 0xCE, 0x35, 0xCE, 0x15, 0xCE, 0x35, 
+0xB5, 0x72, 0xD6, 0x56, 0xCE, 0x36, 0xC5, 0xD4, 
+0xCE, 0x36, 0xCE, 0x37, 0xD6, 0xBB, 0xCE, 0x59, 
+0x9C, 0xD3, 0xB5, 0x52, 0xCD, 0xF4, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xCD, 0xF4, 0xB5, 0x31, 0xCE, 0x15, 
+0xD6, 0x35, 0xCE, 0x14, 0xCD, 0xF4, 0xCD, 0xF4, 
+0xD6, 0x14, 0xD6, 0x14, 0xD6, 0x34, 0xDE, 0x55, 
+0xD5, 0xF3, 0xCD, 0xF3, 0xDE, 0x55, 0xB5, 0x12, 
+0x4A, 0x27, 0x42, 0x07, 0x4A, 0x28, 0x83, 0xCE, 
+0x83, 0xEF, 0x8B, 0xEF, 0xC5, 0x95, 0x94, 0x2F, 
+0x49, 0xE8, 0x41, 0xA7, 0x73, 0x4D, 0x73, 0x2C, 
+0x83, 0xCE, 0x9C, 0x91, 0xAC, 0xF3, 0x83, 0xCE, 
+0x7B, 0xAD, 0x6B, 0x2C, 0x73, 0x6D, 0x94, 0x70, 
+0xA4, 0xD1, 0xBD, 0x93, 0xBD, 0x93, 0xAD, 0x32, 
+0xB5, 0x32, 0xAD, 0x31, 0xB5, 0x52, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xAC, 0xF1, 0xBD, 0x73, 0xAD, 0x12, 
+0xBD, 0x93, 0xC5, 0xB3, 0xCE, 0x14, 0xC5, 0x93, 
+0xC5, 0x93, 0xCD, 0xD4, 0xC5, 0xD4, 0x9C, 0x6F, 
+0x41, 0xC7, 0x21, 0x04, 0x18, 0xE4, 0x29, 0x25, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x08, 0x83, 
+0x10, 0x83, 0x08, 0x83, 0x19, 0x04, 0x21, 0x05, 
+0x18, 0xC4, 0x21, 0x05, 0x21, 0x05, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x21, 0x05, 0x18, 0xE4, 
+0x21, 0x25, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x18, 0xC4, 0x10, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 
+0x10, 0xA4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA4, 0x18, 0xE4, 
+0x21, 0x25, 0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x29, 0x46, 0x29, 0x47, 
+0x21, 0x46, 0x29, 0x67, 0x29, 0x67, 0x29, 0x87, 
+0x29, 0x87, 0x29, 0x87, 0x29, 0x87, 0x39, 0xC8, 
+0x42, 0x2A, 0x4A, 0x4A, 0x52, 0xAA, 0xAD, 0x32, 
+0xBD, 0x93, 0xAC, 0xD0, 0xAC, 0xD0, 0xAC, 0xD0, 
+0xAC, 0xF0, 0xB4, 0xF0, 0xB5, 0x10, 0xB5, 0x10, 
+0xB5, 0x10, 0xB4, 0xF0, 0xB5, 0x31, 0xB5, 0x31, 
+0xAD, 0x31, 0xBD, 0x73, 0xDE, 0x56, 0xDE, 0x76, 
+0xDE, 0x76, 0xDE, 0x76, 0xD6, 0x35, 0xD6, 0x15, 
+0xCD, 0xF4, 0xDE, 0x76, 0xC5, 0x93, 0x9C, 0x6F, 
+0xBD, 0x93, 0xBD, 0xB4, 0xBD, 0x93, 0xC5, 0xD4, 
+0xB5, 0x73, 0xA4, 0xD1, 0xCE, 0x16, 0xCE, 0x16, 
+0x63, 0x2B, 0x29, 0x65, 0x10, 0xA3, 0x31, 0x65, 
+0x39, 0xE6, 0x29, 0x24, 0x39, 0x86, 0x52, 0x48, 
+0x49, 0xE7, 0x41, 0xE7, 0x52, 0x07, 0x83, 0x6D, 
+0xAD, 0xF4, 0x63, 0xEB, 0x43, 0x42, 0x4B, 0xA2, 
+0x3A, 0xC2, 0x4B, 0x06, 0x84, 0xAC, 0x7C, 0x6C, 
+0xAD, 0x91, 0x6B, 0x89, 0x3A, 0x44, 0x5B, 0x87, 
+0x4B, 0x05, 0x8C, 0xAE, 0xAD, 0xB2, 0x94, 0xEE, 
+0x9D, 0x0F, 0x9C, 0xCE, 0x9C, 0xCE, 0xCE, 0x54, 
+0xBD, 0xF3, 0xAD, 0x50, 0x94, 0x6D, 0x84, 0x0D, 
+0xB5, 0x73, 0xBD, 0xD5, 0xB5, 0xB4, 0xB5, 0x94, 
+0xCE, 0x56, 0xB5, 0x72, 0x94, 0x8F, 0xAD, 0x53, 
+0xCE, 0x57, 0xBD, 0xD5, 0xCE, 0x57, 0xCE, 0x57, 
+0xBD, 0xF5, 0xCE, 0x36, 0xD6, 0x98, 0xD6, 0x56, 
+0xDE, 0x96, 0xBD, 0x72, 0xAC, 0xEF, 0xC5, 0xB3, 
+0xCD, 0xF5, 0xCE, 0x15, 0xC5, 0xF4, 0xBD, 0x92, 
+0xAD, 0x11, 0x9C, 0xAF, 0x9C, 0xAF, 0x8C, 0x2E, 
+0xA4, 0xF0, 0xA4, 0xF1, 0xAD, 0x11, 0xA4, 0xF0, 
+0xA5, 0x11, 0xA4, 0xF0, 0x9C, 0x8F, 0xA4, 0xF0, 
+0xAD, 0x31, 0xC5, 0xD4, 0xC5, 0xF4, 0xB5, 0x51, 
+0xCD, 0xF3, 0xA4, 0x8E, 0xB5, 0x10, 0x8B, 0xEC, 
+0x9C, 0x4E, 0x94, 0x4D, 0x9C, 0x6E, 0xB5, 0x10, 
+0xA4, 0x8E, 0x9C, 0x4E, 0xA4, 0x8E, 0xA4, 0x8E, 
+0x8B, 0xCC, 0x8B, 0xEC, 0x8B, 0xEC, 0x8B, 0xEC, 
+0x8B, 0xEC, 0x94, 0x0C, 0x9C, 0x6E, 0xA4, 0x8E, 
+0xAC, 0xCF, 0xAC, 0xAF, 0xAC, 0xCF, 0xB5, 0x10, 
+0xB5, 0x30, 0xAC, 0xD0, 0xB5, 0x10, 0xBD, 0x51, 
+0xB5, 0x10, 0xA4, 0x8E, 0xA4, 0xAE, 0xA4, 0x8F, 
+0x94, 0x6E, 0x94, 0x4F, 0x5A, 0x89, 0x52, 0x89, 
+0x42, 0x07, 0x42, 0x07, 0x39, 0xA6, 0x4A, 0x28, 
+0x52, 0x8A, 0x5A, 0xEC, 0x73, 0x8E, 0x84, 0x10, 
+0x73, 0x8E, 0x8C, 0x51, 0x84, 0x30, 0x8C, 0x51, 
+0x94, 0x72, 0x5A, 0xAB, 0x73, 0x4C, 0xC5, 0xB5, 
+0xCD, 0xF6, 0x8C, 0x2F, 0x8C, 0x2E, 0xBD, 0xB4, 
+0xAD, 0x31, 0xB5, 0x72, 0xAD, 0x31, 0xC5, 0xF4, 
+0xB5, 0x52, 0xD6, 0x56, 0xCE, 0x35, 0xBD, 0x72, 
+0x9C, 0x8F, 0xAD, 0x31, 0xCE, 0x35, 0xCE, 0x15, 
+0xDE, 0x77, 0x9C, 0x91, 0x94, 0x72, 0x94, 0xB3, 
+0x9C, 0xD2, 0xB5, 0x52, 0xBD, 0x52, 0xAC, 0xF0, 
+0xC5, 0xB3, 0xCE, 0x14, 0xC5, 0xB3, 0xCD, 0xF4, 
+0xD6, 0x14, 0xD6, 0x14, 0xCD, 0xF4, 0xCD, 0xD3, 
+0xDE, 0x35, 0xDE, 0x55, 0xDE, 0x75, 0xDE, 0x75, 
+0xCD, 0xB2, 0xD6, 0x13, 0xDE, 0x34, 0xDE, 0x35, 
+0xC5, 0xD4, 0x94, 0x6F, 0x62, 0xEA, 0x4A, 0x28, 
+0x7B, 0x6D, 0x7B, 0x8E, 0xB5, 0x54, 0xA4, 0xB1, 
+0x6A, 0xCB, 0x39, 0x65, 0x62, 0xCB, 0x5A, 0x69, 
+0x83, 0xAE, 0x83, 0xAE, 0xCD, 0xF7, 0x9C, 0x91, 
+0x94, 0x50, 0x8C, 0x0F, 0x94, 0x70, 0xAC, 0xF1, 
+0xBD, 0x94, 0xBD, 0x73, 0xAC, 0xD0, 0xBD, 0x52, 
+0xBD, 0x52, 0xB5, 0x31, 0xA4, 0xAF, 0xBD, 0x72, 
+0xC5, 0xD4, 0xAD, 0x11, 0xC5, 0x94, 0xB5, 0x32, 
+0xBD, 0x73, 0xC5, 0x93, 0xCD, 0xD3, 0xC5, 0x92, 
+0xCD, 0xD4, 0xC5, 0x72, 0xCD, 0xD3, 0xA4, 0x6F, 
+0x49, 0xC7, 0x20, 0xE4, 0x21, 0x04, 0x21, 0x25, 
+0x21, 0x04, 0x18, 0xC4, 0x10, 0xA3, 0x18, 0xC4, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0x83, 0x08, 0x83, 0x10, 0x83, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x10, 0xC3, 0x21, 0x05, 0x21, 0x05, 
+0x18, 0xC3, 0x21, 0x05, 0x21, 0x25, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x21, 0x05, 0x18, 0xE4, 
+0x21, 0x05, 0x10, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 
+0x18, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xE4, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x29, 0x46, 0x29, 0x46, 
+0x29, 0x67, 0x29, 0x46, 0x29, 0x67, 0x29, 0x67, 
+0x29, 0x67, 0x29, 0x46, 0x29, 0x67, 0x29, 0x87, 
+0x3A, 0x09, 0x42, 0x29, 0x42, 0x09, 0x63, 0x2C, 
+0xB5, 0x53, 0xAC, 0xF1, 0xBD, 0x94, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xAC, 0xD1, 0xAC, 0xF1, 
+0xAD, 0x11, 0xAD, 0x11, 0xB5, 0x12, 0xB5, 0x53, 
+0xB5, 0x32, 0xAD, 0x12, 0xAC, 0xF1, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF1, 0xAD, 0x32, 
+0xAD, 0x31, 0xB5, 0x52, 0xAD, 0x11, 0xAC, 0xF1, 
+0xA4, 0xB0, 0x9C, 0x90, 0x9C, 0x90, 0x9C, 0x90, 
+0xA4, 0xD0, 0x9C, 0x90, 0x94, 0x90, 0x9C, 0x70, 
+0x94, 0x6F, 0x52, 0x89, 0x20, 0xC3, 0x21, 0x04, 
+0x31, 0x85, 0x31, 0x45, 0x39, 0x85, 0x42, 0x07, 
+0x41, 0xC6, 0x39, 0xA6, 0x52, 0x48, 0x7B, 0x4C, 
+0x9D, 0x52, 0xAD, 0xF4, 0x6C, 0x2C, 0x43, 0x03, 
+0x3A, 0xA2, 0x3A, 0xA4, 0x74, 0x4A, 0x53, 0x27, 
+0x8C, 0xAD, 0x84, 0x4C, 0x52, 0xE6, 0x53, 0x06, 
+0x7C, 0x2B, 0x9D, 0x30, 0x84, 0x2C, 0x84, 0x6C, 
+0xAD, 0x51, 0x9C, 0xAE, 0xA4, 0xEF, 0xD6, 0x76, 
+0xC6, 0x14, 0xA4, 0xF0, 0x9C, 0xCF, 0xA5, 0x11, 
+0xCE, 0x16, 0xC5, 0xF5, 0xBD, 0xB5, 0xBD, 0xD4, 
+0xCE, 0x36, 0xBD, 0xD4, 0x9C, 0xD0, 0xA4, 0xF1, 
+0xB5, 0x94, 0xC5, 0xF6, 0x9C, 0xD1, 0xD6, 0x98, 
+0xC6, 0x36, 0xD6, 0x77, 0xD6, 0x56, 0xBD, 0x93, 
+0xBD, 0xB3, 0xC5, 0xB3, 0xB5, 0x10, 0xD6, 0x76, 
+0xDE, 0x97, 0xDE, 0x97, 0xDE, 0xB7, 0xDE, 0x96, 
+0xD6, 0x76, 0xCE, 0x15, 0xAD, 0x32, 0x94, 0x6F, 
+0x9C, 0x90, 0x84, 0x0E, 0xA4, 0xF1, 0xB5, 0x73, 
+0x9C, 0xD0, 0xAD, 0x11, 0xBD, 0xB4, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xCE, 0x15, 0xCE, 0x56, 0xBD, 0xB3, 
+0xC5, 0xD3, 0xA4, 0x8E, 0xB5, 0x10, 0x83, 0xAB, 
+0x8C, 0x4E, 0x9C, 0xB0, 0x94, 0x4E, 0xA4, 0xD0, 
+0xB5, 0x31, 0xB5, 0x52, 0xAD, 0x31, 0xA4, 0xD0, 
+0x7B, 0x8C, 0x7B, 0x8C, 0x6B, 0x4B, 0x73, 0x6C, 
+0x73, 0x4B, 0x9C, 0xB0, 0xBD, 0x94, 0xBD, 0x73, 
+0x9C, 0x6E, 0x94, 0x2E, 0xAD, 0x11, 0x9C, 0x8E, 
+0x8B, 0xEC, 0xB4, 0xEF, 0xB4, 0xEF, 0xAD, 0x10, 
+0xC5, 0x92, 0xB5, 0x10, 0xB5, 0x30, 0xCD, 0xF4, 
+0xC5, 0xD3, 0xB5, 0x52, 0x62, 0xA9, 0x52, 0x69, 
+0x42, 0x07, 0x42, 0x07, 0x42, 0x07, 0x4A, 0x48, 
+0x4A, 0x49, 0x52, 0xAA, 0x63, 0x0C, 0x6B, 0x4D, 
+0x7B, 0xF0, 0x94, 0x92, 0xA5, 0x14, 0xA5, 0x35, 
+0x8C, 0x51, 0x6B, 0x4D, 0x83, 0xEF, 0xA4, 0xD2, 
+0xB5, 0x34, 0x7B, 0x8E, 0x41, 0xC7, 0x94, 0x6F, 
+0xAC, 0xCF, 0xA4, 0xAE, 0xA4, 0x6E, 0xA4, 0x8E, 
+0x9C, 0x6E, 0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x8E, 
+0x9C, 0x6E, 0xA4, 0x8F, 0xA4, 0xAF, 0xB5, 0x10, 
+0xBD, 0x52, 0xB5, 0x54, 0x9C, 0xB3, 0x83, 0xF0, 
+0xAD, 0x12, 0xBD, 0x72, 0xB4, 0xF0, 0xA4, 0xAF, 
+0xAC, 0xF0, 0xA4, 0x8E, 0xB5, 0x10, 0xB4, 0xD0, 
+0xAC, 0xCF, 0xA4, 0x8E, 0x94, 0x2D, 0xA4, 0x6E, 
+0xBD, 0x51, 0xCD, 0xB2, 0xCD, 0xF3, 0xCD, 0xD2, 
+0xB5, 0x0F, 0xBD, 0x50, 0xDE, 0x34, 0xCD, 0xB2, 
+0xBD, 0x71, 0xB5, 0x10, 0x8C, 0x0E, 0x5A, 0xAA, 
+0x83, 0xAE, 0x94, 0x30, 0x6A, 0xEB, 0x5A, 0x8A, 
+0x4A, 0x08, 0x52, 0x49, 0x39, 0x86, 0x6B, 0x0B, 
+0x5A, 0x69, 0x73, 0x6D, 0xCE, 0x17, 0x83, 0x8D, 
+0x8B, 0xEF, 0xBD, 0x95, 0xA4, 0xF1, 0xBD, 0x73, 
+0xD5, 0xF4, 0xC5, 0x92, 0xBD, 0x51, 0xCD, 0xD3, 
+0xC5, 0x72, 0xAD, 0x11, 0x7B, 0x8B, 0x7B, 0x8C, 
+0xC5, 0xB4, 0xAD, 0x11, 0xC5, 0xB4, 0xAD, 0x12, 
+0xB5, 0x52, 0xBD, 0x72, 0xC5, 0xB3, 0xBD, 0x92, 
+0xBD, 0x72, 0xBD, 0x31, 0xC5, 0x72, 0x9C, 0x6F, 
+0x62, 0xA9, 0x39, 0xA7, 0x29, 0x46, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x08, 0x83, 
+0x10, 0xA3, 0x10, 0xC3, 0x19, 0x05, 0x18, 0xE4, 
+0x18, 0xC4, 0x21, 0x25, 0x19, 0x05, 0x18, 0xE4, 
+0x19, 0x04, 0x18, 0xE4, 0x21, 0x05, 0x18, 0xE4, 
+0x19, 0x05, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC3, 0x18, 0xC4, 0x10, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x21, 0x05, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x21, 0x46, 0x29, 0x46, 
+0x29, 0x67, 0x29, 0x46, 0x29, 0x67, 0x29, 0x67, 
+0x29, 0x67, 0x21, 0x26, 0x29, 0x46, 0x29, 0x87, 
+0x39, 0xC8, 0x42, 0x09, 0x3A, 0x09, 0x39, 0xE8, 
+0x8C, 0x30, 0xBD, 0xB4, 0xC5, 0xF5, 0x94, 0x70, 
+0x8C, 0x0E, 0x9C, 0xB0, 0x8C, 0x2E, 0xAD, 0x12, 
+0xA4, 0xD1, 0xC5, 0xF5, 0xBD, 0xD5, 0xBD, 0xB5, 
+0xB5, 0x54, 0xAD, 0x33, 0xA4, 0xF2, 0xAD, 0x12, 
+0xB5, 0x73, 0xAD, 0x12, 0x9C, 0xB0, 0x94, 0x70, 
+0x94, 0x70, 0x94, 0x4F, 0x8C, 0x0E, 0x83, 0xEE, 
+0x94, 0x2F, 0x94, 0x6F, 0x9C, 0x90, 0x9C, 0x90, 
+0x9C, 0x90, 0xA4, 0xF1, 0xA4, 0xD1, 0x9C, 0x6F, 
+0xA4, 0xF1, 0x73, 0x8C, 0x20, 0xE4, 0x18, 0xA3, 
+0x31, 0x65, 0x31, 0x65, 0x39, 0x85, 0x39, 0xA6, 
+0x4A, 0x07, 0x39, 0xA6, 0x4A, 0x07, 0x8B, 0xCE, 
+0x7C, 0x8D, 0x63, 0xCA, 0x84, 0xAE, 0x5B, 0x88, 
+0x43, 0x04, 0x53, 0x66, 0x8D, 0x0D, 0x6B, 0xE9, 
+0x52, 0xC6, 0x4A, 0x65, 0x4A, 0x85, 0x94, 0xEE, 
+0xAD, 0xB1, 0x8C, 0xAE, 0x73, 0xEB, 0xAD, 0x71, 
+0xB5, 0x92, 0x9C, 0xCE, 0xA4, 0xEF, 0xCE, 0x55, 
+0xCE, 0x14, 0xAD, 0x31, 0xA4, 0xF0, 0xBD, 0xB4, 
+0xC5, 0xF5, 0xB5, 0x94, 0xB5, 0x73, 0xC6, 0x15, 
+0xD6, 0xB7, 0xD6, 0x77, 0xC6, 0x15, 0xBD, 0xD4, 
+0xB5, 0x94, 0xAD, 0x53, 0x6B, 0x4C, 0x9C, 0xD1, 
+0xBD, 0xB4, 0xC5, 0xF5, 0xCE, 0x15, 0xD6, 0x76, 
+0xD6, 0x76, 0xBD, 0x72, 0xB5, 0x51, 0xD6, 0x56, 
+0xCE, 0x14, 0xCE, 0x14, 0xD6, 0x55, 0xCE, 0x14, 
+0xCE, 0x35, 0xD6, 0x76, 0xCE, 0x35, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xAD, 0x53, 0xB5, 0x94, 0xCE, 0x36, 
+0xAD, 0x52, 0xAD, 0x11, 0x94, 0x6F, 0xA4, 0xD0, 
+0xB5, 0x72, 0xCE, 0x35, 0xCE, 0x35, 0xCE, 0x14, 
+0xCD, 0xF4, 0xAC, 0xEF, 0xB4, 0xEF, 0x8C, 0x0D, 
+0x9C, 0xB0, 0xAD, 0x12, 0x8C, 0x0D, 0x9C, 0x6F, 
+0xB5, 0x52, 0xC5, 0xD4, 0xC5, 0xD4, 0xB5, 0x93, 
+0x9C, 0xB1, 0x84, 0x0F, 0x6B, 0x6C, 0x5A, 0xEA, 
+0x6B, 0x6C, 0xB5, 0x94, 0x8C, 0x0E, 0xAC, 0xF1, 
+0x9C, 0x8F, 0xBD, 0xB3, 0xCE, 0x15, 0x9C, 0x8F, 
+0x83, 0xAB, 0xB5, 0x10, 0xB5, 0x0F, 0xC5, 0xB2, 
+0xCE, 0x15, 0xD6, 0x35, 0xB5, 0x51, 0xCE, 0x14, 
+0xC5, 0xD4, 0xBD, 0xB3, 0xBD, 0x73, 0x83, 0xCD, 
+0x4A, 0x68, 0x4A, 0x48, 0x42, 0x07, 0x4A, 0x48, 
+0x4A, 0x48, 0x4A, 0x69, 0x5A, 0xCA, 0x63, 0x2D, 
+0x7B, 0xCF, 0x84, 0x10, 0x94, 0x92, 0x8C, 0x71, 
+0x8C, 0x51, 0xAD, 0x55, 0x9C, 0xB2, 0x83, 0xCE, 
+0x9C, 0x91, 0x9C, 0x91, 0x42, 0x08, 0x7B, 0x8D, 
+0xB5, 0x52, 0x94, 0x2D, 0x8B, 0xEC, 0x83, 0xAB, 
+0x8B, 0xCC, 0x94, 0x2C, 0x93, 0xEC, 0x94, 0x0C, 
+0x9C, 0x4E, 0xA4, 0x8E, 0xAC, 0xAE, 0xBD, 0x30, 
+0xC5, 0x73, 0xC5, 0xF7, 0xA5, 0x14, 0x8C, 0x51, 
+0xAC, 0xF2, 0xB5, 0x10, 0xBD, 0x31, 0xBD, 0x31, 
+0xB5, 0x31, 0xBD, 0x31, 0xBD, 0x50, 0xBD, 0x51, 
+0xBD, 0x31, 0xBD, 0x50, 0xC5, 0x51, 0xBD, 0x30, 
+0xB5, 0x10, 0xB4, 0xEF, 0xB4, 0xCE, 0xAC, 0x8E, 
+0x9C, 0x2C, 0x9C, 0x4D, 0xB5, 0x0F, 0xBD, 0x10, 
+0xAC, 0xAE, 0xB5, 0x10, 0x9C, 0x6F, 0x5A, 0xA9, 
+0x7B, 0xAE, 0x8B, 0xEF, 0x41, 0xE7, 0x29, 0x45, 
+0x4A, 0x08, 0x5A, 0x69, 0x4A, 0x08, 0x83, 0xCF, 
+0x7B, 0x8D, 0x4A, 0x08, 0x9C, 0x91, 0x7B, 0x8D, 
+0x73, 0x2C, 0x9C, 0x90, 0xA4, 0xD0, 0xCD, 0xD4, 
+0xDE, 0x15, 0xD6, 0x14, 0xCD, 0x92, 0xC5, 0x92, 
+0xBD, 0x72, 0xBD, 0x72, 0x9C, 0x6F, 0xA4, 0xB1, 
+0xC5, 0xD4, 0x9C, 0x8F, 0xC5, 0xB4, 0xAC, 0xF1, 
+0xAD, 0x11, 0xAC, 0xF0, 0xAC, 0xF0, 0xB5, 0x11, 
+0xB5, 0x31, 0xB5, 0x10, 0xB5, 0x31, 0xAC, 0xAF, 
+0x9C, 0x4E, 0x6B, 0x0B, 0x31, 0x66, 0x21, 0x25, 
+0x21, 0x25, 0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0xA3, 0x19, 0x05, 0x18, 0xE4, 
+0x18, 0xC4, 0x21, 0x25, 0x18, 0xE4, 0x18, 0xE4, 
+0x10, 0xC3, 0x18, 0xE4, 0x18, 0xE4, 0x10, 0xC4, 
+0x18, 0xE4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 0x10, 0xC4, 
+0x18, 0xE4, 0x19, 0x05, 0x19, 0x05, 0x18, 0xE4, 
+0x19, 0x05, 0x18, 0xE5, 0x21, 0x05, 0x21, 0x46, 
+0x21, 0x46, 0x29, 0x46, 0x21, 0x46, 0x21, 0x46, 
+0x29, 0x46, 0x29, 0x67, 0x29, 0x67, 0x29, 0x67, 
+0x29, 0x67, 0x29, 0x46, 0x29, 0x46, 0x29, 0x67, 
+0x31, 0xC8, 0x3A, 0x09, 0x39, 0xE9, 0x31, 0xC8, 
+0x39, 0xC8, 0x94, 0x71, 0xCE, 0x16, 0x94, 0x90, 
+0x94, 0x4F, 0xA4, 0xD1, 0xA4, 0xD0, 0xB5, 0x53, 
+0xAD, 0x53, 0xCE, 0x77, 0xC6, 0x37, 0xC5, 0xF6, 
+0xC6, 0x17, 0xBD, 0xF6, 0xAD, 0x53, 0x9C, 0xB1, 
+0xAD, 0x33, 0xA5, 0x12, 0x8C, 0x50, 0x8C, 0x50, 
+0x9C, 0x91, 0xA4, 0xD1, 0x9C, 0xB1, 0x94, 0x70, 
+0x9C, 0xD2, 0xA4, 0xD2, 0xA5, 0x12, 0xB5, 0x74, 
+0xAD, 0x53, 0xA4, 0xF1, 0xA4, 0xD1, 0x8C, 0x2E, 
+0xA4, 0xF1, 0xAD, 0x12, 0x29, 0x44, 0x21, 0x04, 
+0x18, 0xC3, 0x29, 0x44, 0x39, 0x85, 0x41, 0xE7, 
+0x52, 0x48, 0x5A, 0x69, 0x4A, 0x07, 0x8B, 0xCE, 
+0x63, 0xCA, 0x6C, 0x0A, 0x5B, 0x89, 0x4B, 0x26, 
+0x5B, 0xC7, 0x5B, 0xC8, 0x6B, 0xE8, 0x5B, 0x67, 
+0x73, 0xEA, 0x4A, 0xA6, 0x6B, 0x68, 0x84, 0x4B, 
+0x7C, 0x0A, 0x7C, 0x0B, 0x84, 0x6D, 0x8C, 0xAE, 
+0x8C, 0x6D, 0xAD, 0x72, 0xB5, 0xB3, 0xC6, 0x34, 
+0xCE, 0x55, 0xCE, 0x35, 0xB5, 0x72, 0xBD, 0xB3, 
+0xBD, 0xD4, 0xA5, 0x12, 0xB5, 0x73, 0xC6, 0x35, 
+0xDE, 0xB7, 0xD6, 0x97, 0xCE, 0x56, 0xCE, 0x36, 
+0xC5, 0xF5, 0xB5, 0x74, 0x9C, 0xB1, 0xAD, 0x74, 
+0xB5, 0x94, 0xC5, 0xF5, 0xC5, 0xF4, 0xCE, 0x55, 
+0xD6, 0x55, 0xB5, 0x10, 0xB5, 0x51, 0xC5, 0xD3, 
+0xCD, 0xF4, 0xA4, 0xAF, 0xB5, 0x72, 0xCE, 0x35, 
+0xD6, 0x76, 0xB5, 0x52, 0x83, 0xEE, 0x9C, 0xD1, 
+0xBD, 0xD5, 0xD6, 0x57, 0xAD, 0x53, 0xB5, 0x53, 
+0xCE, 0x36, 0xBD, 0xD4, 0xAD, 0x53, 0xB5, 0x93, 
+0xCE, 0x36, 0xD6, 0x76, 0xCE, 0x56, 0xCD, 0xF4, 
+0xC5, 0xB3, 0xB4, 0xEF, 0xB4, 0xEF, 0x8C, 0x0D, 
+0x94, 0x6F, 0xA4, 0xF1, 0x8C, 0x0D, 0x9C, 0x8F, 
+0xB5, 0x52, 0xC5, 0xD4, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xA4, 0xF2, 0x8C, 0x2F, 0x83, 0xEF, 0x73, 0xCD, 
+0x84, 0x2F, 0xBD, 0xB5, 0x9C, 0x90, 0x73, 0x4B, 
+0x7B, 0x8C, 0xB5, 0x73, 0xBD, 0x94, 0x9C, 0x90, 
+0x94, 0x2D, 0xBD, 0x31, 0xB5, 0x10, 0xCD, 0xF4, 
+0xB5, 0x72, 0xCE, 0x14, 0xBD, 0x92, 0xBD, 0x93, 
+0xBD, 0x93, 0xB5, 0x73, 0xB5, 0x73, 0x94, 0x6F, 
+0x4A, 0x68, 0x4A, 0x69, 0x39, 0xC6, 0x31, 0xA5, 
+0x39, 0xE7, 0x4A, 0x48, 0x5A, 0xCB, 0x63, 0x2C, 
+0x6B, 0x4D, 0x73, 0x8E, 0x83, 0xF0, 0x8C, 0x51, 
+0xAD, 0x75, 0xAD, 0x75, 0x94, 0x71, 0xA4, 0xB2, 
+0x9C, 0x91, 0x9C, 0x91, 0x5A, 0x8A, 0x62, 0xEB, 
+0xB5, 0x73, 0xAD, 0x11, 0x9C, 0xAF, 0x94, 0x6F, 
+0x7B, 0xAC, 0x83, 0xCC, 0x9C, 0x8F, 0x94, 0x0D, 
+0x94, 0x2D, 0xA4, 0xCF, 0x9C, 0x6D, 0xB4, 0xF0, 
+0xBD, 0x93, 0xBD, 0xD6, 0xAD, 0x35, 0x94, 0x71, 
+0x8B, 0xEE, 0x8B, 0xEC, 0x83, 0xAB, 0x7B, 0x6B, 
+0x83, 0xAC, 0x94, 0x2D, 0xA4, 0x6E, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xAC, 0xAE, 0xAC, 0xAE, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xB4, 0xEF, 0xB5, 0x10, 0xB4, 0xEF, 
+0xB5, 0x0F, 0xC5, 0x71, 0xBD, 0x51, 0xB4, 0xEF, 
+0xBD, 0x31, 0xBD, 0x52, 0x6B, 0x0A, 0x62, 0xEA, 
+0x4A, 0x28, 0x41, 0xE7, 0x29, 0x44, 0x31, 0x86, 
+0x41, 0xC7, 0x4A, 0x08, 0x52, 0x49, 0x5A, 0x89, 
+0x94, 0x30, 0x62, 0xCB, 0x5A, 0x69, 0x7B, 0x8E, 
+0x7B, 0x8E, 0x83, 0x8E, 0xB5, 0x13, 0xCE, 0x16, 
+0xAD, 0x12, 0x9C, 0x90, 0x9C, 0x6F, 0x94, 0x2E, 
+0xA4, 0xAF, 0xAD, 0x11, 0xBD, 0x53, 0xB5, 0x32, 
+0xAC, 0xF0, 0x94, 0x2E, 0xBD, 0x74, 0xA4, 0xB0, 
+0x9C, 0x6F, 0x9C, 0x4E, 0x9C, 0x4E, 0x9C, 0x6E, 
+0xA4, 0xAF, 0xAC, 0xD0, 0xAC, 0xD0, 0xA4, 0xB0, 
+0xAC, 0xF1, 0x94, 0x0E, 0x5A, 0x69, 0x31, 0x66, 
+0x21, 0x25, 0x21, 0x25, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x82, 0x08, 0x83, 0x08, 0x83, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x19, 0x04, 0x18, 0xC4, 
+0x18, 0xE4, 0x21, 0x25, 0x18, 0xE4, 0x18, 0xC4, 
+0x10, 0xC3, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xE4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x05, 0x19, 0x05, 
+0x18, 0xE5, 0x18, 0xE5, 0x21, 0x26, 0x21, 0x46, 
+0x21, 0x46, 0x29, 0x46, 0x21, 0x46, 0x21, 0x46, 
+0x29, 0x46, 0x29, 0x46, 0x21, 0x46, 0x29, 0x46, 
+0x21, 0x46, 0x21, 0x46, 0x29, 0x46, 0x29, 0x46, 
+0x29, 0x87, 0x39, 0xE9, 0x39, 0xE9, 0x39, 0xE9, 
+0x31, 0x87, 0x39, 0xE8, 0x8C, 0x50, 0x9C, 0xF1, 
+0x94, 0x6F, 0x9C, 0x90, 0x9C, 0xB0, 0xB5, 0x53, 
+0xB5, 0x53, 0xCE, 0x57, 0xC6, 0x37, 0xBD, 0xB5, 
+0xB5, 0xB5, 0xBD, 0xB5, 0xA5, 0x12, 0x84, 0x2F, 
+0x8C, 0x91, 0x8C, 0x50, 0x7B, 0xEE, 0x8C, 0x50, 
+0x94, 0x91, 0x9C, 0xF2, 0xA5, 0x13, 0xA5, 0x33, 
+0xBD, 0xB5, 0xA5, 0x12, 0x9C, 0x91, 0xA4, 0xF2, 
+0x9C, 0xB0, 0x94, 0x90, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xC5, 0xB4, 0xD6, 0x56, 0x52, 0x89, 0x18, 0xE4, 
+0x10, 0x82, 0x29, 0x44, 0x39, 0x85, 0x39, 0xA6, 
+0x52, 0x48, 0x6A, 0xEA, 0x5A, 0x89, 0x7B, 0x8D, 
+0x95, 0x70, 0x9D, 0x91, 0x74, 0x6D, 0x5B, 0xC9, 
+0x6C, 0x49, 0x53, 0x66, 0x53, 0x46, 0x6C, 0x08, 
+0x6B, 0xE9, 0x5B, 0x27, 0x8C, 0x6C, 0x8C, 0x4C, 
+0x84, 0x0B, 0x73, 0xCB, 0x74, 0x0B, 0x6B, 0xEB, 
+0x7C, 0x4D, 0xBE, 0x34, 0xA5, 0x10, 0xA5, 0x10, 
+0xB5, 0x71, 0xBD, 0xB3, 0xB5, 0x52, 0xB5, 0x52, 
+0xBD, 0xD4, 0x9C, 0xD0, 0xAD, 0x32, 0xBD, 0xD4, 
+0xCE, 0x35, 0xBD, 0xB3, 0xAD, 0x31, 0xCE, 0x36, 
+0xC5, 0xD5, 0xAD, 0x33, 0x8C, 0x2F, 0xB5, 0xB5, 
+0xB5, 0x94, 0xCE, 0x36, 0xCE, 0x56, 0xCE, 0x55, 
+0xD6, 0x55, 0xAD, 0x10, 0xBD, 0x92, 0xBD, 0x92, 
+0xD6, 0x35, 0x94, 0x6F, 0x39, 0xA5, 0x73, 0x4B, 
+0xB5, 0x73, 0xD6, 0x57, 0xBD, 0xB5, 0x5A, 0xCA, 
+0x4A, 0x68, 0x73, 0xAD, 0x83, 0xEE, 0x9C, 0xB1, 
+0xB5, 0x95, 0xCE, 0x57, 0xD6, 0x78, 0xCE, 0x57, 
+0xCE, 0x36, 0xD6, 0x97, 0xDE, 0x97, 0xD6, 0x76, 
+0xCE, 0x14, 0xB4, 0xEF, 0xB5, 0x10, 0xA4, 0xB0, 
+0xAD, 0x32, 0xAD, 0x52, 0xA4, 0xF0, 0xA4, 0xF1, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0x94, 0xB5, 0x93, 
+0xAD, 0x32, 0x94, 0xD1, 0xA4, 0xF2, 0xA5, 0x13, 
+0x7B, 0xEE, 0xB5, 0x95, 0xB5, 0x53, 0x6B, 0x2A, 
+0x83, 0xCD, 0xBD, 0xB4, 0xCD, 0xF5, 0x9C, 0x8F, 
+0x94, 0x4E, 0xBD, 0x31, 0xBD, 0x30, 0xCE, 0x35, 
+0xBD, 0xB3, 0xC5, 0xF4, 0xC5, 0xF4, 0xBD, 0xB3, 
+0xC5, 0xD3, 0xBD, 0xB4, 0xB5, 0x52, 0xA4, 0xF1, 
+0x41, 0xE7, 0x62, 0xEB, 0x4A, 0x48, 0x29, 0x44, 
+0x39, 0xA6, 0x42, 0x28, 0x4A, 0x49, 0x52, 0x8A, 
+0x6B, 0x4D, 0x73, 0x6E, 0x84, 0x10, 0x94, 0x92, 
+0xA5, 0x14, 0xA5, 0x14, 0xAD, 0x55, 0xC5, 0xD7, 
+0x9C, 0x92, 0x6B, 0x2C, 0x62, 0xEB, 0x73, 0x8D, 
+0x94, 0x6F, 0x9C, 0xD0, 0xAD, 0x52, 0xB5, 0x73, 
+0xA5, 0x11, 0xA4, 0xF1, 0x8C, 0x0D, 0x73, 0x4A, 
+0x84, 0x0D, 0xB5, 0x31, 0xAC, 0xF0, 0xAC, 0xCF, 
+0xC5, 0xB4, 0xBD, 0xD6, 0xA5, 0x35, 0x84, 0x10, 
+0x6A, 0xEA, 0x8C, 0x0D, 0x83, 0x8B, 0x7B, 0x6C, 
+0x5A, 0x89, 0x5A, 0x89, 0x4A, 0x07, 0x41, 0xE6, 
+0x52, 0x47, 0x62, 0xC9, 0x5A, 0xA8, 0x62, 0xC9, 
+0x62, 0xC9, 0x62, 0xA8, 0x6A, 0xE9, 0x94, 0x2D, 
+0xB5, 0x10, 0x8B, 0xEC, 0x73, 0x29, 0x8B, 0xEC, 
+0xB5, 0x32, 0x9C, 0x4F, 0x62, 0xCA, 0x62, 0xCA, 
+0x31, 0x85, 0x21, 0x04, 0x29, 0x45, 0x31, 0x85, 
+0x31, 0x65, 0x39, 0xA6, 0x6B, 0x2C, 0x4A, 0x08, 
+0x41, 0xA7, 0x73, 0x4D, 0x83, 0xCE, 0x62, 0xEB, 
+0xC6, 0x18, 0xDE, 0x9A, 0xBD, 0x95, 0xC5, 0xD6, 
+0xD6, 0x37, 0xB5, 0x33, 0xBD, 0x94, 0xBD, 0x94, 
+0xC5, 0xD4, 0xB5, 0x32, 0xB5, 0x52, 0xBD, 0x53, 
+0xB5, 0x32, 0xB5, 0x53, 0xC5, 0xD5, 0xC5, 0xD5, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xD5, 0xC5, 0xB4, 
+0xC5, 0xB4, 0xCD, 0xD4, 0xCD, 0xB4, 0xC5, 0x94, 
+0xCD, 0xD4, 0xAC, 0xF1, 0x8B, 0xCE, 0x52, 0x28, 
+0x29, 0x25, 0x21, 0x25, 0x18, 0xE4, 0x19, 0x04, 
+0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0xC4, 0x18, 0xE4, 0x10, 0xA3, 
+0x18, 0xE4, 0x19, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xC4, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x21, 0x05, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x21, 0x46, 0x21, 0x26, 
+0x21, 0x46, 0x21, 0x46, 0x21, 0x46, 0x21, 0x46, 
+0x29, 0x46, 0x21, 0x46, 0x21, 0x26, 0x21, 0x46, 
+0x21, 0x46, 0x21, 0x46, 0x21, 0x46, 0x29, 0x46, 
+0x29, 0x67, 0x31, 0xA8, 0x39, 0xE9, 0x39, 0xE9, 
+0x39, 0xC8, 0x29, 0x87, 0x42, 0x28, 0x83, 0xEF, 
+0x94, 0x4F, 0x9C, 0xB0, 0x8C, 0x2F, 0xB5, 0x53, 
+0xB5, 0x53, 0xD6, 0x98, 0xCE, 0x57, 0xBD, 0xB5, 
+0xAD, 0x74, 0xB5, 0x74, 0x9C, 0xF2, 0x84, 0x30, 
+0x8C, 0x91, 0x84, 0x2F, 0x7B, 0xEE, 0x7B, 0xEF, 
+0x94, 0x71, 0xA5, 0x13, 0xA4, 0xF2, 0x94, 0x90, 
+0xB5, 0x94, 0xA5, 0x13, 0x8C, 0x50, 0xA5, 0x33, 
+0x94, 0xB0, 0x94, 0x90, 0xA4, 0xD1, 0xAD, 0x12, 
+0xC5, 0xB4, 0xD6, 0x55, 0x9C, 0x90, 0x18, 0xE4, 
+0x10, 0xA3, 0x18, 0xE3, 0x39, 0xC6, 0x39, 0xA5, 
+0x4A, 0x27, 0x62, 0xEA, 0x6B, 0x0B, 0x7B, 0x6C, 
+0x63, 0xEB, 0x8D, 0x10, 0x74, 0x4D, 0x74, 0x4C, 
+0x64, 0x29, 0x5B, 0xC8, 0x43, 0x04, 0x64, 0x07, 
+0x53, 0x26, 0x52, 0xE6, 0x6B, 0x89, 0x94, 0xAE, 
+0x84, 0x2C, 0x74, 0x0B, 0x74, 0x4A, 0x6C, 0x09, 
+0x84, 0x6D, 0x94, 0x6D, 0xA4, 0xAF, 0xA4, 0xAE, 
+0x9C, 0x6D, 0xA4, 0xAF, 0xAC, 0xF0, 0xB5, 0x31, 
+0xAC, 0xF0, 0xAC, 0xF0, 0xB5, 0x11, 0xAC, 0xF0, 
+0xAC, 0xCF, 0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x31, 
+0xB5, 0x11, 0xAC, 0xF1, 0xA4, 0xB0, 0x94, 0x6F, 
+0x9C, 0x8F, 0xA4, 0xD0, 0xB5, 0x31, 0xC5, 0xB3, 
+0xBD, 0x92, 0xBD, 0x51, 0xBD, 0x31, 0x9C, 0x6D, 
+0xAC, 0xF0, 0xA4, 0x8F, 0x73, 0x2A, 0x39, 0xC6, 
+0x52, 0xA9, 0x5A, 0xC9, 0x6B, 0x6C, 0x73, 0x6D, 
+0x31, 0x65, 0x42, 0x49, 0x52, 0x8A, 0x42, 0x29, 
+0x42, 0x4A, 0x5A, 0xEC, 0x7B, 0xF0, 0xA5, 0x34, 
+0xC6, 0x37, 0xD6, 0x97, 0xDE, 0x97, 0xD6, 0x76, 
+0xC5, 0xB3, 0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x52, 
+0xB5, 0x93, 0xBD, 0xB4, 0xBD, 0x94, 0xAD, 0x11, 
+0xC5, 0xD5, 0xC5, 0xF5, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xB5, 0x73, 0xA5, 0x33, 0xA5, 0x33, 0xAD, 0x54, 
+0x7B, 0xAE, 0x84, 0x0E, 0x8C, 0x2E, 0x5A, 0xC9, 
+0x8C, 0x0E, 0xA4, 0xD0, 0xAD, 0x32, 0x8C, 0x2E, 
+0x9C, 0x6E, 0xBD, 0x51, 0xB5, 0x10, 0xC5, 0xF4, 
+0xC5, 0xD3, 0xC5, 0xF4, 0xC5, 0xF4, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xBD, 0x93, 0xBD, 0x93, 
+0x73, 0x6C, 0x42, 0x07, 0x5A, 0xEA, 0x31, 0xA6, 
+0x39, 0xA6, 0x42, 0x07, 0x42, 0x28, 0x52, 0x8A, 
+0x63, 0x0C, 0x6B, 0x4D, 0x73, 0x8E, 0x84, 0x10, 
+0x9C, 0xD3, 0xA5, 0x15, 0xB5, 0x96, 0xCE, 0x38, 
+0xBD, 0x96, 0x94, 0x51, 0x73, 0x6D, 0xA5, 0x13, 
+0xAD, 0x53, 0x9C, 0xD1, 0xB5, 0x73, 0xC5, 0xF5, 
+0xCE, 0x36, 0xB5, 0x93, 0x8C, 0x2E, 0x9C, 0xD1, 
+0xAD, 0x32, 0xAD, 0x11, 0xB5, 0x31, 0xAC, 0xD0, 
+0xD6, 0x57, 0x9C, 0xD3, 0x7B, 0xCF, 0x94, 0x71, 
+0x83, 0xED, 0x8B, 0xED, 0x8B, 0xED, 0xB5, 0x52, 
+0x83, 0xCD, 0x94, 0x4F, 0x6B, 0x4C, 0x52, 0x8A, 
+0x52, 0x89, 0x52, 0x89, 0x84, 0x0F, 0xA4, 0xD1, 
+0xA4, 0xD1, 0x94, 0x4F, 0x5A, 0x89, 0x94, 0x4F, 
+0xA4, 0x8F, 0x94, 0x4E, 0x83, 0xCD, 0x94, 0x4F, 
+0xBD, 0x73, 0x94, 0x2F, 0x41, 0xE7, 0x62, 0xCA, 
+0x4A, 0x07, 0x20, 0xE3, 0x21, 0x24, 0x29, 0x44, 
+0x29, 0x44, 0x29, 0x45, 0x5A, 0x89, 0x52, 0x69, 
+0x41, 0xC7, 0x5A, 0xAA, 0x39, 0xA6, 0x39, 0xA7, 
+0x6B, 0x2D, 0xAD, 0x14, 0xCD, 0xF7, 0xAD, 0x13, 
+0xC5, 0xD6, 0x83, 0xCD, 0x94, 0x4F, 0x94, 0x6F, 
+0xBD, 0x73, 0xB5, 0x52, 0xB5, 0x53, 0xBD, 0xB4, 
+0xBD, 0x94, 0xA4, 0xD0, 0xA4, 0xF1, 0xA4, 0xB0, 
+0x8C, 0x0D, 0xAD, 0x32, 0xA4, 0xD1, 0xA4, 0xD0, 
+0xAC, 0xF1, 0xA4, 0xB0, 0xA4, 0xD1, 0xA4, 0xB0, 
+0xC5, 0xD4, 0xC5, 0xB4, 0x9C, 0x6F, 0x73, 0x2B, 
+0x41, 0xE7, 0x29, 0x45, 0x21, 0x04, 0x21, 0x25, 
+0x18, 0xC4, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x10, 0xA3, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x10, 0xC3, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xA3, 0x08, 0x83, 0x08, 0x83, 0x10, 0xA3, 
+0x10, 0xC3, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x05, 0x18, 0xE5, 0x21, 0x05, 0x21, 0x05, 
+0x19, 0x05, 0x21, 0x26, 0x29, 0x46, 0x21, 0x26, 
+0x21, 0x46, 0x21, 0x46, 0x21, 0x26, 0x21, 0x46, 
+0x21, 0x46, 0x21, 0x46, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x29, 0x46, 0x29, 0x46, 
+0x29, 0x46, 0x29, 0x87, 0x39, 0xE9, 0x39, 0xC8, 
+0x39, 0xC8, 0x29, 0x87, 0x29, 0x67, 0x52, 0x6A, 
+0xA4, 0xF2, 0xBD, 0xB4, 0x8C, 0x0E, 0xB5, 0x53, 
+0xAD, 0x53, 0xCE, 0x57, 0xC6, 0x37, 0xC6, 0x37, 
+0xC6, 0x16, 0xC5, 0xF6, 0xAD, 0x54, 0x94, 0xB2, 
+0x94, 0xD2, 0x94, 0x91, 0x84, 0x30, 0x8C, 0x50, 
+0xA5, 0x13, 0xB5, 0x94, 0x8C, 0x4F, 0x7B, 0xCE, 
+0xAD, 0x54, 0x94, 0x91, 0x8C, 0x70, 0xB5, 0x94, 
+0x9C, 0xD1, 0x94, 0xB1, 0x9C, 0xB1, 0xA4, 0xF2, 
+0xCE, 0x15, 0xD6, 0x54, 0xD6, 0x56, 0x39, 0xA6, 
+0x18, 0xE3, 0x10, 0x82, 0x31, 0x65, 0x41, 0xE7, 
+0x4A, 0x28, 0x5A, 0xA9, 0x6A, 0xEB, 0x5A, 0x89, 
+0x7C, 0x6D, 0x74, 0x4D, 0x74, 0x4D, 0x63, 0xEA, 
+0x64, 0x0A, 0x5B, 0xA7, 0x4B, 0x44, 0x64, 0x07, 
+0x4B, 0x24, 0x84, 0xCC, 0x74, 0x4B, 0x53, 0x08, 
+0x84, 0xAD, 0x6C, 0x28, 0x74, 0x67, 0x95, 0x4D, 
+0x8C, 0x8D, 0x7B, 0xCC, 0x7B, 0x8B, 0x73, 0x2A, 
+0x83, 0xCC, 0x8C, 0x0D, 0xAD, 0x31, 0xCD, 0xD4, 
+0xA4, 0xAF, 0xA4, 0xAF, 0x9C, 0x4E, 0xB5, 0x31, 
+0xAC, 0xF0, 0xAC, 0xCF, 0x9C, 0x6E, 0x9C, 0x8E, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xB5, 0x10, 0xAD, 0x10, 0xA4, 0xAF, 0xAC, 0xCF, 
+0xB5, 0x31, 0xBD, 0x31, 0xD5, 0xF4, 0xCD, 0xD2, 
+0xD5, 0xF3, 0xC5, 0x92, 0xCD, 0xB3, 0x7B, 0x8B, 
+0x5A, 0xCA, 0x63, 0x0B, 0x29, 0x65, 0x18, 0xC3, 
+0x19, 0x04, 0x18, 0xC3, 0x29, 0x45, 0x31, 0x86, 
+0x29, 0x66, 0x29, 0x87, 0x31, 0xA8, 0x31, 0xC9, 
+0x4A, 0x8B, 0x7B, 0xCF, 0x9C, 0xB1, 0x9C, 0xB0, 
+0xA4, 0x8E, 0xBD, 0x51, 0xB5, 0x30, 0xBD, 0x72, 
+0xBD, 0x93, 0xBD, 0x93, 0xB5, 0x73, 0xC5, 0xD4, 
+0xCE, 0x15, 0xBD, 0x93, 0xCE, 0x35, 0xCE, 0x15, 
+0xB5, 0x93, 0xAD, 0x74, 0x9C, 0xD2, 0x9C, 0xD2, 
+0x7B, 0xAE, 0x7B, 0xCD, 0x9C, 0xB0, 0x83, 0xED, 
+0xAD, 0x12, 0xB5, 0x73, 0xA4, 0xD0, 0x83, 0xED, 
+0x8B, 0xED, 0xBD, 0x71, 0xAC, 0xEF, 0xB5, 0x31, 
+0xB5, 0x72, 0xB5, 0x72, 0xC5, 0xF4, 0xC5, 0xF4, 
+0xD6, 0x55, 0xC5, 0xF5, 0xC5, 0xD4, 0xCE, 0x15, 
+0xAD, 0x12, 0x31, 0x65, 0x63, 0x0B, 0x42, 0x07, 
+0x29, 0x65, 0x4A, 0x48, 0x4A, 0x69, 0x4A, 0x69, 
+0x5A, 0xAA, 0x63, 0x0B, 0x73, 0x6E, 0x8C, 0x31, 
+0x94, 0xB3, 0x9C, 0xD4, 0xB5, 0x96, 0xBD, 0xD7, 
+0xAD, 0x34, 0xAD, 0x14, 0xAD, 0x34, 0xAD, 0x33, 
+0xB5, 0x94, 0xB5, 0x53, 0xAD, 0x52, 0xCE, 0x15, 
+0xCE, 0x56, 0xCE, 0x36, 0xB5, 0x73, 0xAD, 0x32, 
+0xAD, 0x11, 0xA4, 0xF1, 0xC5, 0xD4, 0xB5, 0x53, 
+0xD6, 0x58, 0x83, 0xEF, 0x63, 0x2D, 0x8C, 0x51, 
+0xAD, 0x11, 0xAC, 0xF1, 0x94, 0x0D, 0xC5, 0xD4, 
+0x9C, 0x6F, 0x9C, 0x90, 0x7B, 0x8D, 0x73, 0x6D, 
+0x6B, 0x4C, 0x5A, 0xAA, 0x84, 0x0E, 0xA4, 0xF1, 
+0xAD, 0x12, 0xB5, 0x52, 0x7B, 0x8C, 0xA4, 0xB0, 
+0xC5, 0x93, 0xD6, 0x15, 0xA4, 0xD0, 0xAC, 0xF1, 
+0xBD, 0x73, 0x9C, 0xB0, 0x83, 0xEE, 0x5A, 0x69, 
+0x62, 0xAA, 0x4A, 0x69, 0x6B, 0x4C, 0x5A, 0xCB, 
+0x31, 0x85, 0x31, 0x85, 0x31, 0x85, 0x39, 0xC6, 
+0x4A, 0x49, 0x39, 0xA6, 0x29, 0x44, 0x29, 0x44, 
+0x42, 0x08, 0x52, 0x49, 0x6B, 0x0C, 0x6B, 0x0C, 
+0x94, 0x50, 0xB5, 0x53, 0x9C, 0x70, 0x94, 0x6F, 
+0xBD, 0x94, 0xB5, 0x32, 0xBD, 0x73, 0xC5, 0xF5, 
+0xCE, 0x36, 0xA4, 0xF1, 0x9C, 0xB0, 0x8C, 0x0D, 
+0x8C, 0x2E, 0xA4, 0xD0, 0xAD, 0x11, 0xC5, 0xD5, 
+0xCD, 0xF5, 0xAC, 0xF1, 0x9C, 0x90, 0x8C, 0x0D, 
+0xAD, 0x11, 0xC5, 0xB3, 0xC5, 0x93, 0xAC, 0xF1, 
+0x9C, 0x91, 0x73, 0x4C, 0x52, 0x49, 0x6B, 0x2C, 
+0x31, 0xA6, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x10, 0xA3, 0x18, 0xE4, 0x19, 0x04, 0x18, 0xE4, 
+0x19, 0x04, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xC3, 0x10, 0xA3, 0x18, 0xE4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC3, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x26, 0x21, 0x46, 0x21, 0x26, 
+0x21, 0x26, 0x29, 0x46, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x29, 0x46, 0x29, 0x67, 
+0x21, 0x46, 0x29, 0x67, 0x31, 0xC8, 0x31, 0xC8, 
+0x31, 0xA8, 0x31, 0xA8, 0x31, 0x87, 0x31, 0x87, 
+0x6B, 0x4C, 0xBD, 0xB4, 0x94, 0x4E, 0xB5, 0x53, 
+0xB5, 0x94, 0xD6, 0x98, 0xD6, 0x98, 0xCE, 0x78, 
+0xCE, 0x57, 0xC6, 0x36, 0xBD, 0xB5, 0xA5, 0x33, 
+0xAD, 0x74, 0xA5, 0x34, 0xA5, 0x34, 0xB5, 0x95, 
+0xC6, 0x16, 0xAD, 0x74, 0x73, 0xAD, 0x9C, 0xF2, 
+0xAD, 0x74, 0xA5, 0x13, 0x9C, 0xD2, 0xBD, 0xB5, 
+0xAD, 0x53, 0x9C, 0xB1, 0x9C, 0xB1, 0xA4, 0xF2, 
+0xD6, 0x56, 0xDE, 0x75, 0xDE, 0x96, 0x52, 0x89, 
+0x18, 0xE4, 0x10, 0xA3, 0x18, 0xA3, 0x41, 0xE7, 
+0x4A, 0x07, 0x4A, 0x27, 0x62, 0xEA, 0x52, 0x48, 
+0xBE, 0x75, 0x6C, 0x0B, 0x5B, 0xAA, 0x7C, 0xCE, 
+0x6C, 0x0A, 0x53, 0x86, 0x4B, 0x64, 0x53, 0x85, 
+0x63, 0xE7, 0x85, 0x0C, 0x6C, 0x49, 0x5B, 0xA7, 
+0x5B, 0xA6, 0x64, 0x05, 0x7C, 0xC8, 0x9D, 0x8E, 
+0x8C, 0xAF, 0x63, 0x09, 0x9C, 0xD1, 0x9C, 0xD1, 
+0x8C, 0x4F, 0x8C, 0x2E, 0x9C, 0xD1, 0xA4, 0xF1, 
+0xA4, 0xD1, 0xA4, 0xF1, 0x9C, 0xAF, 0xB5, 0x10, 
+0xAC, 0xF0, 0xB5, 0x52, 0xA4, 0xB0, 0xA4, 0xD1, 
+0xAD, 0x33, 0xA4, 0xF2, 0xA4, 0xD1, 0xA4, 0xF0, 
+0x94, 0x6E, 0x8C, 0x4E, 0x8C, 0x2E, 0x8C, 0x0D, 
+0x83, 0x8B, 0x7B, 0x8B, 0xA4, 0xAF, 0x9C, 0x4D, 
+0xAC, 0xF0, 0xAC, 0xF0, 0xA4, 0x8F, 0x94, 0x2D, 
+0x6B, 0x0A, 0x5A, 0xCA, 0x5A, 0xCA, 0x31, 0x86, 
+0x21, 0x04, 0x21, 0x25, 0x19, 0x04, 0x10, 0xA3, 
+0x10, 0xC3, 0x21, 0x25, 0x21, 0x25, 0x21, 0x47, 
+0x29, 0xA8, 0x31, 0xC9, 0x42, 0x2A, 0x6B, 0x6E, 
+0x94, 0x70, 0xAC, 0xF1, 0xBD, 0x72, 0xC5, 0x92, 
+0xBD, 0x51, 0xBD, 0x31, 0xB5, 0x30, 0xB5, 0x10, 
+0xB5, 0x10, 0xAC, 0xCF, 0x9C, 0x6E, 0x94, 0x2D, 
+0x83, 0xCB, 0x8C, 0x2E, 0x94, 0x4E, 0x94, 0x2E, 
+0x8B, 0xEC, 0x9C, 0x6F, 0xA4, 0xD0, 0x8B, 0xED, 
+0xA4, 0xB0, 0xB5, 0x31, 0xB5, 0x32, 0xB5, 0x31, 
+0xAC, 0xF0, 0xAC, 0xCE, 0x83, 0xAA, 0x7B, 0x6A, 
+0x94, 0x4D, 0xA4, 0xCF, 0xB5, 0x72, 0xCE, 0x14, 
+0xD6, 0x35, 0xCE, 0x35, 0xCD, 0xF4, 0xBD, 0x72, 
+0xC5, 0xD4, 0x52, 0x68, 0x42, 0x28, 0x5A, 0xEB, 
+0x39, 0xC6, 0x31, 0xA6, 0x42, 0x28, 0x39, 0xC6, 
+0x4A, 0x69, 0x62, 0xEB, 0x6B, 0x6D, 0x7B, 0xAF, 
+0x8C, 0x72, 0x94, 0x93, 0xA5, 0x35, 0xB5, 0x96, 
+0xB5, 0x75, 0xAD, 0x14, 0xCE, 0x38, 0xAD, 0x13, 
+0xBD, 0xB5, 0xBD, 0xB4, 0xC5, 0xF5, 0xD6, 0x97, 
+0xD6, 0x56, 0xCE, 0x56, 0xBD, 0xB4, 0xB5, 0x73, 
+0xB5, 0x72, 0xAD, 0x52, 0xBD, 0xB3, 0xB5, 0x32, 
+0xBD, 0x95, 0x94, 0x92, 0x7B, 0xEF, 0x9C, 0xB1, 
+0xBD, 0x73, 0xAC, 0xD0, 0x8B, 0xCC, 0xC5, 0xB4, 
+0xA4, 0xD0, 0xB5, 0x53, 0x8C, 0x2F, 0x8C, 0x2F, 
+0x73, 0x8D, 0x6B, 0x4C, 0x94, 0x90, 0xBD, 0xB4, 
+0xCD, 0xF5, 0xC5, 0xD4, 0x83, 0xCD, 0xA5, 0x11, 
+0xB5, 0x31, 0xCD, 0xF4, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xC5, 0xB4, 0xA4, 0xB0, 0xA4, 0xD1, 0x6B, 0x2B, 
+0x39, 0xA6, 0x39, 0xC6, 0x41, 0xE7, 0xA5, 0x13, 
+0x7B, 0xCD, 0x39, 0xA6, 0x29, 0x65, 0x39, 0xC7, 
+0x39, 0xC6, 0x31, 0xA6, 0x31, 0x85, 0x29, 0x44, 
+0x29, 0x64, 0x42, 0x07, 0x83, 0xEF, 0x9C, 0x92, 
+0x7B, 0x6D, 0xA4, 0xD2, 0xCE, 0x16, 0xA4, 0xD1, 
+0xBD, 0x73, 0xC5, 0xD4, 0xCE, 0x15, 0xCE, 0x36, 
+0xC5, 0xD4, 0xB5, 0x53, 0x94, 0x6F, 0x8C, 0x2E, 
+0x9C, 0x90, 0xC5, 0xB4, 0xB5, 0x73, 0xC5, 0xF5, 
+0xBD, 0x93, 0xA4, 0xB0, 0xAD, 0x32, 0x8C, 0x2E, 
+0xA4, 0xD1, 0xB5, 0x52, 0xC5, 0xD4, 0xBD, 0x73, 
+0xC5, 0xD4, 0xB5, 0x32, 0xAC, 0xD1, 0xBD, 0x73, 
+0x7B, 0x8C, 0x52, 0x69, 0x29, 0x25, 0x18, 0xE4, 
+0x10, 0xC3, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xC4, 
+0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x10, 0x83, 0x18, 0xE4, 0x19, 0x05, 0x18, 0xE4, 
+0x19, 0x04, 0x18, 0xC4, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xC3, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 0x21, 0x25, 
+0x21, 0x05, 0x21, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x26, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x46, 0x29, 0x46, 
+0x29, 0x46, 0x21, 0x46, 0x31, 0x87, 0x39, 0xE9, 
+0x31, 0xA8, 0x31, 0xA7, 0x39, 0xC8, 0x31, 0x87, 
+0x39, 0xA7, 0x7B, 0xAE, 0x9C, 0x90, 0xB5, 0x53, 
+0xB5, 0x73, 0xC6, 0x16, 0xAD, 0x53, 0xBD, 0xB5, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x94, 0xB5, 0x94, 
+0xB5, 0x74, 0xA5, 0x13, 0xAD, 0x33, 0xA5, 0x13, 
+0xAD, 0x33, 0x9C, 0xD1, 0x84, 0x0E, 0xA4, 0xF2, 
+0xB5, 0x74, 0xAD, 0x53, 0xA5, 0x13, 0xBD, 0xB5, 
+0xCE, 0x37, 0xB5, 0x74, 0xA4, 0xF1, 0xAD, 0x12, 
+0xCE, 0x15, 0xE6, 0xB6, 0xD6, 0x35, 0x7B, 0xAD, 
+0x39, 0xC7, 0x18, 0xC3, 0x10, 0x82, 0x31, 0x66, 
+0x42, 0x07, 0x4A, 0x07, 0x6B, 0x2B, 0x4A, 0x27, 
+0x64, 0x29, 0x5B, 0xE8, 0x2A, 0x43, 0x42, 0xE8, 
+0x74, 0x6C, 0x63, 0xE8, 0x4B, 0x44, 0x4B, 0x64, 
+0x6C, 0x28, 0x6C, 0x29, 0x4B, 0x65, 0x64, 0x27, 
+0x6C, 0x68, 0x7C, 0xCB, 0x9D, 0xAF, 0xA5, 0x70, 
+0xA5, 0x11, 0x9C, 0xF1, 0xA5, 0x33, 0xB5, 0x94, 
+0x9C, 0xD1, 0x94, 0x90, 0x8C, 0x4F, 0x8C, 0x6F, 
+0x94, 0x90, 0x9C, 0xD1, 0x9C, 0xAF, 0xB5, 0x10, 
+0xB5, 0x10, 0xC5, 0xD4, 0xAD, 0x53, 0xB5, 0x94, 
+0xAD, 0x53, 0xA5, 0x12, 0xA5, 0x12, 0xA4, 0xF1, 
+0x9C, 0xD0, 0x9C, 0xB0, 0xA4, 0xF1, 0x9C, 0xB0, 
+0x9C, 0x90, 0x9C, 0xB0, 0xA4, 0xD1, 0xAD, 0x11, 
+0xC5, 0xD4, 0xCD, 0xF4, 0x94, 0x6F, 0x94, 0x6F, 
+0xA4, 0xF2, 0x62, 0xEB, 0x52, 0xAA, 0x52, 0xAA, 
+0x31, 0x86, 0x19, 0x04, 0x18, 0xE4, 0x10, 0xC3, 
+0x08, 0x82, 0x08, 0x82, 0x10, 0xE3, 0x19, 0x25, 
+0x21, 0x46, 0x21, 0x67, 0x31, 0xA9, 0x31, 0xC9, 
+0x39, 0xEA, 0x4A, 0x69, 0x5A, 0xA9, 0x73, 0x4B, 
+0x8B, 0xEC, 0x9C, 0x4E, 0xA4, 0xAF, 0x9C, 0x6D, 
+0xA4, 0x8E, 0xB4, 0xEF, 0xC5, 0x71, 0xBD, 0x51, 
+0xB5, 0x10, 0xB5, 0x31, 0xBD, 0x51, 0xB5, 0x10, 
+0xBD, 0x30, 0xBD, 0x51, 0xC5, 0x72, 0xBD, 0x30, 
+0xBD, 0x51, 0xC5, 0x72, 0xC5, 0x92, 0xC5, 0xB2, 
+0xCD, 0xB2, 0xC5, 0x92, 0xBD, 0x30, 0xB5, 0x31, 
+0xBD, 0x71, 0xBD, 0x51, 0xAC, 0xCF, 0xA4, 0xAF, 
+0x9C, 0x6E, 0x9C, 0x4D, 0x9C, 0x4D, 0x94, 0x2D, 
+0x94, 0x2E, 0x52, 0x68, 0x18, 0xE3, 0x52, 0x89, 
+0x5A, 0xCA, 0x39, 0xC6, 0x42, 0x07, 0x31, 0x86, 
+0x42, 0x08, 0x52, 0x8A, 0x63, 0x0C, 0x63, 0x0C, 
+0x73, 0x8E, 0x73, 0xAF, 0x94, 0xB3, 0xAD, 0x55, 
+0x8C, 0x71, 0xAD, 0x55, 0xD6, 0x58, 0xD6, 0x58, 
+0xBD, 0x94, 0xC5, 0xF5, 0xD6, 0x77, 0xD6, 0x56, 
+0xCE, 0x56, 0xBD, 0xD4, 0xBD, 0xB4, 0xB5, 0x73, 
+0xAD, 0x32, 0xBD, 0xB4, 0xAD, 0x11, 0xC5, 0xB5, 
+0xB5, 0x95, 0x9C, 0xF3, 0x84, 0x30, 0xBD, 0x94, 
+0xC5, 0x94, 0x8B, 0xCD, 0xAC, 0xF1, 0xC5, 0xB3, 
+0xB5, 0x52, 0xC5, 0xB4, 0x9C, 0x6F, 0xB5, 0x73, 
+0x94, 0x4F, 0x94, 0x2F, 0xBD, 0x94, 0xCE, 0x36, 
+0xCE, 0x15, 0xC5, 0xD4, 0x7B, 0x8C, 0xAD, 0x11, 
+0x83, 0xCC, 0xB5, 0x32, 0x9C, 0x8F, 0x9C, 0x8F, 
+0xC5, 0xB4, 0x94, 0x6F, 0xAD, 0x32, 0x9C, 0xB1, 
+0x31, 0x64, 0x21, 0x24, 0x52, 0x89, 0xB5, 0x53, 
+0xB5, 0x73, 0x7B, 0xCD, 0x31, 0x85, 0x31, 0x85, 
+0x31, 0x85, 0x39, 0xC6, 0x39, 0xC6, 0x31, 0x85, 
+0x39, 0xC6, 0x42, 0x07, 0x4A, 0x08, 0x7B, 0x8E, 
+0x62, 0xCA, 0x73, 0x6C, 0xBD, 0xB5, 0xBD, 0xB5, 
+0xC5, 0xB5, 0xCE, 0x16, 0xD6, 0x77, 0xCE, 0x35, 
+0xBD, 0xB4, 0xA4, 0xF1, 0xA4, 0xF1, 0x9C, 0x8F, 
+0x94, 0x4E, 0xA4, 0xD0, 0xBD, 0x93, 0xC5, 0xD4, 
+0xB5, 0x52, 0xAD, 0x52, 0xB5, 0x73, 0xAD, 0x12, 
+0xB5, 0x53, 0xC5, 0xF4, 0xC5, 0xF4, 0xD6, 0x15, 
+0xD6, 0x15, 0xCD, 0xD4, 0xCD, 0xD4, 0xC5, 0xF4, 
+0xB5, 0x32, 0x9C, 0x6F, 0x62, 0xEB, 0x39, 0xA6, 
+0x29, 0x25, 0x18, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x08, 0x83, 0x08, 0x82, 0x08, 0x83, 0x08, 0x83, 
+0x10, 0x83, 0x08, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 0x10, 0xC3, 
+0x08, 0x83, 0x10, 0xC3, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x10, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC4, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 0x21, 0x26, 
+0x21, 0x05, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x26, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x21, 0x46, 
+0x21, 0x46, 0x21, 0x46, 0x29, 0x46, 0x39, 0xC8, 
+0x31, 0xA8, 0x29, 0x67, 0x39, 0xC8, 0x39, 0xE9, 
+0x31, 0x87, 0x4A, 0x4A, 0x73, 0x6D, 0x94, 0x70, 
+0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0xB0, 0x94, 0x6F, 
+0x8C, 0x2E, 0x8C, 0x0E, 0x84, 0x0E, 0x84, 0x0E, 
+0x8C, 0x2F, 0x8C, 0x0E, 0x83, 0xEE, 0x83, 0xCD, 
+0x73, 0x6C, 0x73, 0x6C, 0x7B, 0x8C, 0x7B, 0xAD, 
+0x94, 0x4F, 0x83, 0xEE, 0x84, 0x0E, 0x84, 0x0E, 
+0x94, 0x70, 0x84, 0x0E, 0x8C, 0x2F, 0x9C, 0xB0, 
+0xA4, 0x90, 0xCD, 0xD4, 0xD6, 0x55, 0x9C, 0xB0, 
+0x4A, 0x48, 0x21, 0x04, 0x18, 0xA3, 0x18, 0xC3, 
+0x41, 0xC7, 0x4A, 0x28, 0x73, 0x4C, 0x62, 0xCA, 
+0x64, 0x07, 0x64, 0x48, 0x53, 0x87, 0x3A, 0xA5, 
+0x5B, 0xA9, 0x53, 0x87, 0x6C, 0x28, 0x53, 0x85, 
+0x6C, 0x28, 0x42, 0xE4, 0x43, 0x44, 0x74, 0xAA, 
+0xA5, 0xF1, 0xC6, 0xF7, 0xA5, 0x71, 0x8C, 0xCF, 
+0x8C, 0xAF, 0x9C, 0xF0, 0xA5, 0x53, 0xB5, 0xD4, 
+0xB5, 0xB4, 0xA5, 0x53, 0x94, 0x90, 0x9C, 0xF2, 
+0xA5, 0x12, 0xB5, 0x94, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xBD, 0x72, 0xD6, 0x56, 0xCE, 0x15, 0xE6, 0xF9, 
+0xD6, 0x97, 0xCE, 0x36, 0xB5, 0x74, 0xAD, 0x73, 
+0xAD, 0x53, 0xAD, 0x32, 0xAD, 0x32, 0xB5, 0x53, 
+0xAD, 0x53, 0xB5, 0x94, 0xB5, 0x94, 0xC5, 0xF5, 
+0xDE, 0xB7, 0xE6, 0xD8, 0xD6, 0x77, 0xCE, 0x58, 
+0xF7, 0x9D, 0xCE, 0x38, 0x4A, 0x48, 0x42, 0x07, 
+0x18, 0xC3, 0x08, 0x82, 0x08, 0x62, 0x08, 0x82, 
+0x08, 0x82, 0x08, 0x82, 0x08, 0x82, 0x10, 0xA3, 
+0x21, 0x25, 0x21, 0x66, 0x21, 0x47, 0x21, 0x67, 
+0x29, 0x88, 0x29, 0x88, 0x29, 0x87, 0x63, 0x2D, 
+0x52, 0x8A, 0x63, 0x0A, 0x8C, 0x4E, 0xA4, 0xB0, 
+0x94, 0x2D, 0x8C, 0x0C, 0xB5, 0x10, 0xC5, 0x71, 
+0xAC, 0xAE, 0x7B, 0x6A, 0x94, 0x4D, 0x94, 0x0C, 
+0x9C, 0x6E, 0x9C, 0x4E, 0x8B, 0xEC, 0x94, 0x2D, 
+0xAC, 0xCF, 0xB5, 0x10, 0xAC, 0xCF, 0xAC, 0xEF, 
+0xAC, 0xCF, 0xA4, 0x8E, 0xB4, 0xEF, 0xAC, 0xAF, 
+0xB4, 0xEF, 0xAC, 0xEF, 0xAC, 0xCF, 0xA4, 0x8F, 
+0xB4, 0xF0, 0xB5, 0x10, 0xB4, 0xEF, 0xB5, 0x10, 
+0xB4, 0xF0, 0x83, 0xAC, 0x29, 0x45, 0x39, 0xE7, 
+0x5A, 0xEB, 0x4A, 0x48, 0x42, 0x28, 0x39, 0xC6, 
+0x39, 0xE7, 0x4A, 0x69, 0x52, 0xAA, 0x52, 0x8A, 
+0x6B, 0x6D, 0x7B, 0xF0, 0x8C, 0x71, 0x84, 0x30, 
+0x9C, 0xB3, 0xBD, 0x96, 0xCE, 0x17, 0xB5, 0x74, 
+0xBD, 0xB5, 0xB5, 0x31, 0xAD, 0x10, 0xB5, 0x10, 
+0xB5, 0x31, 0xAC, 0xF0, 0x9C, 0xAF, 0x9C, 0x8F, 
+0x9C, 0x8F, 0xAD, 0x11, 0xAC, 0xF0, 0xD6, 0x37, 
+0xAD, 0x34, 0x9C, 0xD3, 0xA4, 0xD2, 0xDE, 0x97, 
+0xDE, 0x55, 0xBD, 0x52, 0xC5, 0x73, 0xC5, 0x93, 
+0xC5, 0x93, 0xBD, 0x72, 0xB5, 0x11, 0xE6, 0xB7, 
+0xDE, 0x35, 0xDE, 0x56, 0xDE, 0x56, 0xB5, 0x72, 
+0xB5, 0x72, 0xAD, 0x11, 0x8C, 0x0E, 0xC5, 0xB4, 
+0x94, 0x2E, 0xAD, 0x11, 0xA4, 0xF1, 0x9C, 0x6F, 
+0xC5, 0xD5, 0x94, 0x4F, 0xAD, 0x52, 0xA4, 0xD1, 
+0x6B, 0x4B, 0x63, 0x0B, 0xAD, 0x53, 0xB5, 0x93, 
+0xB5, 0x73, 0xB5, 0x74, 0x73, 0x8D, 0x39, 0xC6, 
+0x41, 0xE7, 0x39, 0xE7, 0x39, 0xC6, 0x39, 0xE7, 
+0x42, 0x07, 0x29, 0x44, 0x21, 0x24, 0x4A, 0x28, 
+0x6B, 0x2C, 0x4A, 0x28, 0x39, 0xA6, 0x4A, 0x48, 
+0x73, 0x6C, 0xA4, 0xD1, 0xCE, 0x15, 0xCE, 0x16, 
+0xAD, 0x32, 0x9C, 0xB0, 0x94, 0x2E, 0x9C, 0x8F, 
+0x83, 0xEC, 0x73, 0x6A, 0xA4, 0xD0, 0xCE, 0x15, 
+0xC5, 0xF5, 0xBD, 0x93, 0xB5, 0x93, 0x9C, 0xB0, 
+0xB5, 0x52, 0xC5, 0xF4, 0xD6, 0x36, 0xCD, 0xF4, 
+0xD6, 0x15, 0xCD, 0xF4, 0xCD, 0xD3, 0xC5, 0x93, 
+0xB5, 0x52, 0xB5, 0x32, 0xAC, 0xF1, 0x8C, 0x0E, 
+0x73, 0x2C, 0x62, 0xEB, 0x52, 0x69, 0x31, 0x66, 
+0x20, 0xE4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC4, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x10, 0xC4, 0x10, 0xC3, 0x10, 0xC3, 
+0x10, 0xC4, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xC4, 0x19, 0x04, 0x19, 0x05, 0x19, 0x05, 
+0x18, 0xE4, 0x18, 0xE5, 0x21, 0x05, 0x21, 0x05, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x21, 0x05, 0x21, 0x05, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x29, 0x87, 
+0x31, 0xA8, 0x21, 0x46, 0x31, 0xC8, 0x39, 0xE9, 
+0x31, 0x87, 0x39, 0xC8, 0x52, 0x8B, 0x63, 0x0C, 
+0x9C, 0xD1, 0xBD, 0x94, 0xB5, 0x73, 0xAD, 0x53, 
+0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x12, 
+0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x12, 
+0xB5, 0x74, 0xAD, 0x32, 0xAD, 0x32, 0xBD, 0xB4, 
+0xAD, 0x33, 0xA4, 0xF2, 0xAD, 0x12, 0xAD, 0x32, 
+0xA4, 0xF2, 0xA4, 0xD1, 0xA4, 0xF2, 0xAD, 0x12, 
+0xAC, 0xF2, 0x9C, 0x90, 0x8C, 0x2F, 0x94, 0x70, 
+0x52, 0x89, 0x21, 0x04, 0x18, 0xC3, 0x10, 0x82, 
+0x31, 0x65, 0x42, 0x07, 0x73, 0x4C, 0x73, 0x6C, 
+0x74, 0xAA, 0x5C, 0x07, 0x53, 0xC7, 0x42, 0xE5, 
+0x4B, 0x47, 0x43, 0x05, 0x8D, 0x2D, 0x6C, 0x49, 
+0x4B, 0x25, 0x4B, 0x65, 0x5C, 0x07, 0x5B, 0xE7, 
+0x7C, 0xAC, 0xB6, 0x54, 0x8C, 0xEF, 0x7C, 0x4C, 
+0x84, 0x8D, 0x9D, 0x11, 0x9D, 0x11, 0x9C, 0xD1, 
+0xB5, 0x73, 0xAD, 0x53, 0x9C, 0xD1, 0xAD, 0x94, 
+0xAD, 0x74, 0xB5, 0x94, 0xA4, 0xD0, 0xAC, 0xEF, 
+0xC5, 0xF4, 0xCE, 0x55, 0xD6, 0x56, 0xE7, 0x19, 
+0xEF, 0x3A, 0xE7, 0x1A, 0xD6, 0x57, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xC6, 0x16, 0xBD, 0xD5, 0xBD, 0xB5, 
+0xB5, 0x95, 0xAD, 0x54, 0xA5, 0x34, 0xAD, 0x54, 
+0xAD, 0x33, 0x9C, 0xD1, 0x7B, 0xCE, 0x6B, 0x2D, 
+0x7B, 0xCF, 0x73, 0x8E, 0x29, 0x45, 0x10, 0xA3, 
+0x10, 0x82, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x08, 0xA3, 0x08, 0x83, 0x08, 0x82, 
+0x08, 0xA3, 0x21, 0x46, 0x31, 0x87, 0x29, 0x87, 
+0x21, 0x67, 0x21, 0x46, 0x21, 0x46, 0x42, 0x29, 
+0x94, 0xB3, 0x8C, 0x91, 0x6B, 0x4C, 0xA4, 0xF2, 
+0x9C, 0x90, 0xAD, 0x11, 0xBD, 0x51, 0xC5, 0x92, 
+0xB4, 0xF0, 0x94, 0x6F, 0xA4, 0xD0, 0xA4, 0xD1, 
+0x94, 0x6F, 0xA4, 0xD1, 0xAD, 0x32, 0xB5, 0x93, 
+0xA4, 0xF1, 0xA4, 0xF1, 0x9C, 0x8F, 0xA4, 0xF0, 
+0xAD, 0x31, 0xB5, 0x52, 0xAC, 0xF0, 0xA4, 0xD0, 
+0xA4, 0xAF, 0x94, 0x4E, 0xA4, 0xF0, 0x8C, 0x2D, 
+0x9C, 0x6E, 0x9C, 0x8F, 0xB5, 0x10, 0xBD, 0x31, 
+0xA4, 0x6E, 0x94, 0x4E, 0x6B, 0x0B, 0x31, 0x85, 
+0x39, 0xE7, 0x5A, 0xAA, 0x4A, 0x28, 0x39, 0xC6, 
+0x4A, 0x48, 0x52, 0x89, 0x42, 0x08, 0x4A, 0x69, 
+0x73, 0x8E, 0x73, 0xAE, 0x73, 0x8E, 0x83, 0xEF, 
+0x9C, 0xB3, 0xB5, 0x96, 0xC5, 0xF7, 0xCE, 0x17, 
+0xDE, 0x98, 0xAD, 0x12, 0xA4, 0xAF, 0xAD, 0x10, 
+0xAC, 0xF0, 0xB5, 0x11, 0xBD, 0x51, 0xBD, 0x31, 
+0xB5, 0x30, 0xB5, 0x31, 0xB5, 0x52, 0xB5, 0x74, 
+0x9C, 0xD3, 0x8C, 0x51, 0x9C, 0x90, 0xAC, 0xAF, 
+0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x8E, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xC5, 0x71, 0xBD, 0x31, 0xC5, 0x71, 
+0xCD, 0x92, 0xC5, 0x71, 0xBD, 0x51, 0xB5, 0x31, 
+0xAC, 0xD0, 0xA4, 0xAF, 0xB5, 0x11, 0xD6, 0x15, 
+0xBD, 0x72, 0xAC, 0xB0, 0x83, 0x8B, 0x8B, 0xED, 
+0xC5, 0xB4, 0x8C, 0x2E, 0x9C, 0xB0, 0x8C, 0x2E, 
+0x8C, 0x2F, 0x8C, 0x4F, 0xAD, 0x52, 0xA5, 0x12, 
+0xA5, 0x12, 0xAD, 0x32, 0xAD, 0x53, 0x6B, 0x4C, 
+0x41, 0xE7, 0x42, 0x07, 0x42, 0x07, 0x42, 0x07, 
+0x42, 0x28, 0x29, 0x65, 0x31, 0x85, 0x31, 0x85, 
+0x39, 0xC6, 0x41, 0xE7, 0x42, 0x28, 0x29, 0x45, 
+0x31, 0x65, 0x62, 0xCA, 0x8B, 0xEE, 0xB5, 0x74, 
+0xC5, 0xD5, 0xBD, 0xB4, 0x9C, 0xB0, 0x94, 0x4E, 
+0x9C, 0x8F, 0x9C, 0xB0, 0xB5, 0x53, 0xD6, 0x57, 
+0xCE, 0x56, 0xC5, 0xD4, 0xC5, 0xF5, 0xAD, 0x32, 
+0xAD, 0x52, 0xC5, 0xB4, 0xD6, 0x36, 0xD6, 0x35, 
+0xD6, 0x15, 0xD6, 0x15, 0xCD, 0xD4, 0xB5, 0x11, 
+0xB5, 0x52, 0xB5, 0x52, 0xBD, 0xB4, 0xBD, 0x93, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF1, 0x7B, 0xAD, 
+0x52, 0x69, 0x21, 0x04, 0x18, 0xC4, 0x10, 0xC3, 
+0x18, 0xC4, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC3, 0x10, 0xC4, 
+0x10, 0xC3, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE5, 0x19, 0x05, 
+0x18, 0xE5, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x18, 0xE5, 0x19, 0x05, 0x18, 0xE5, 0x18, 0xE5, 
+0x18, 0xE5, 0x18, 0xE5, 0x18, 0xE5, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x29, 0x46, 0x29, 0x46, 
+0x21, 0x46, 0x21, 0x46, 0x21, 0x46, 0x29, 0x67, 
+0x29, 0x67, 0x21, 0x26, 0x29, 0x67, 0x31, 0x87, 
+0x29, 0x66, 0x21, 0x46, 0x39, 0xC9, 0x52, 0x8B, 
+0x63, 0x0C, 0xAD, 0x53, 0xD6, 0x77, 0xB5, 0x94, 
+0xB5, 0x73, 0xCE, 0x36, 0xCE, 0x36, 0xCE, 0x36, 
+0xC5, 0xF5, 0xBD, 0xD4, 0xBD, 0x94, 0xBD, 0xB4, 
+0xD6, 0x56, 0xB5, 0x53, 0xB5, 0x73, 0xBD, 0x94, 
+0xBD, 0xB4, 0xA4, 0xD1, 0xB5, 0x73, 0xB5, 0x32, 
+0xB5, 0x73, 0xAD, 0x12, 0xAD, 0x12, 0xAD, 0x11, 
+0xAD, 0x12, 0xB5, 0x53, 0xAD, 0x12, 0xB5, 0x73, 
+0x6B, 0x2C, 0x29, 0x46, 0x18, 0xC3, 0x10, 0xA2, 
+0x21, 0x04, 0x4A, 0x08, 0x5A, 0xA9, 0x62, 0xEA, 
+0x74, 0x8A, 0x53, 0xA6, 0x5B, 0xE7, 0x53, 0xA8, 
+0x3A, 0xC5, 0x43, 0x05, 0x43, 0x04, 0x53, 0x65, 
+0x43, 0x24, 0x7C, 0xEB, 0x53, 0xC6, 0x4B, 0x44, 
+0x6C, 0x29, 0x8D, 0x0E, 0x6B, 0xEA, 0x5B, 0x67, 
+0xAD, 0xF2, 0xBE, 0x76, 0xA5, 0x53, 0x84, 0x0F, 
+0x94, 0xB1, 0x94, 0xB1, 0x8C, 0x71, 0x9C, 0xD2, 
+0x9C, 0xF2, 0xA5, 0x13, 0x94, 0x90, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xA4, 0xF2, 0x94, 0xB1, 0x94, 0x91, 
+0x8C, 0x50, 0x84, 0x0F, 0x7B, 0xEF, 0x7B, 0xCF, 
+0x73, 0x8E, 0x6B, 0x4D, 0x63, 0x2E, 0x63, 0x2E, 
+0x63, 0x2E, 0x63, 0x2E, 0x6B, 0x4E, 0x63, 0x0E, 
+0x52, 0xAC, 0x4A, 0x6B, 0x42, 0x2A, 0x41, 0xE9, 
+0x39, 0xC8, 0x29, 0x67, 0x29, 0x46, 0x21, 0x04, 
+0x18, 0xE4, 0x18, 0xE4, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x08, 0x83, 
+0x08, 0x83, 0x21, 0x25, 0x29, 0x46, 0x31, 0xC8, 
+0x31, 0xA8, 0x29, 0x67, 0x21, 0x46, 0x21, 0x46, 
+0x4A, 0x6B, 0xBE, 0x18, 0xDE, 0xFC, 0x94, 0xB2, 
+0x94, 0x50, 0xBD, 0xB4, 0xBD, 0x71, 0xC5, 0x92, 
+0xB5, 0x31, 0xC5, 0xD4, 0xC6, 0x16, 0xC5, 0xF5, 
+0xB5, 0x73, 0xBD, 0xB4, 0xC6, 0x16, 0xCE, 0x36, 
+0xC5, 0xF5, 0xB5, 0x94, 0xBD, 0x94, 0xC6, 0x16, 
+0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0xD4, 
+0xB5, 0x73, 0xAD, 0x52, 0xB5, 0x94, 0xAD, 0x32, 
+0xAD, 0x32, 0xB5, 0x93, 0xBD, 0x92, 0xB5, 0x10, 
+0xA4, 0xAF, 0xBD, 0x93, 0xBD, 0xD4, 0x9C, 0xD1, 
+0x6B, 0x2B, 0x52, 0x89, 0x4A, 0x48, 0x31, 0x85, 
+0x39, 0xC6, 0x39, 0xE7, 0x4A, 0x48, 0x5A, 0xCB, 
+0x5A, 0xAA, 0x6B, 0x2D, 0x8C, 0x30, 0x94, 0x92, 
+0xA4, 0xF3, 0x94, 0x71, 0xB5, 0x75, 0xCE, 0x17, 
+0xCE, 0x17, 0xE6, 0xDA, 0x94, 0x50, 0xCE, 0x15, 
+0xCD, 0xF4, 0xA4, 0xB0, 0x94, 0x2D, 0x9C, 0x8E, 
+0x94, 0x2C, 0x8B, 0xEC, 0xA4, 0xB0, 0xB5, 0x75, 
+0x9C, 0xD3, 0x83, 0xF0, 0x9C, 0xB1, 0xBD, 0x51, 
+0xCD, 0x92, 0xCD, 0xB2, 0xC5, 0x51, 0x9C, 0x4D, 
+0x9C, 0x6D, 0xA4, 0x8E, 0xAC, 0xEF, 0xAC, 0xAE, 
+0xB4, 0xEF, 0xBD, 0x31, 0xC5, 0x72, 0xCD, 0x92, 
+0xC5, 0x92, 0xC5, 0xB2, 0xC5, 0x51, 0xBD, 0x30, 
+0xC5, 0x51, 0xC5, 0x71, 0xC5, 0x72, 0xC5, 0x93, 
+0xC5, 0x94, 0xC5, 0xD5, 0xBD, 0x94, 0xB5, 0x73, 
+0xBD, 0x94, 0xB5, 0x53, 0xB5, 0x73, 0xB5, 0x53, 
+0xAD, 0x32, 0xAD, 0x12, 0xAD, 0x12, 0x7B, 0xAD, 
+0x41, 0xE7, 0x4A, 0x28, 0x42, 0x28, 0x42, 0x28, 
+0x42, 0x07, 0x4A, 0x48, 0x42, 0x28, 0x39, 0xA6, 
+0x39, 0xE7, 0x42, 0x07, 0x29, 0x65, 0x29, 0x44, 
+0x42, 0x07, 0x83, 0xEF, 0x73, 0x6D, 0x8C, 0x0F, 
+0xAD, 0x32, 0xAD, 0x32, 0x9C, 0xB0, 0xA4, 0xF0, 
+0xB5, 0x73, 0xD6, 0x56, 0xD6, 0x56, 0xCE, 0x56, 
+0xCE, 0x35, 0xCE, 0x15, 0xBD, 0xB4, 0xAD, 0x32, 
+0xC5, 0xD4, 0xCE, 0x15, 0xD6, 0x56, 0xD6, 0x76, 
+0xD6, 0x35, 0xD6, 0x15, 0xC5, 0xB3, 0x94, 0x0D, 
+0xBD, 0x73, 0xBD, 0x72, 0xA4, 0xD0, 0xC5, 0xD4, 
+0xC5, 0xB4, 0xC5, 0xB4, 0xC5, 0xB3, 0xCD, 0xD4, 
+0x94, 0x2F, 0x6B, 0x0B, 0x52, 0x89, 0x18, 0xE4, 
+0x18, 0xC4, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC4, 
+0x10, 0xC4, 0x18, 0xC4, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC3, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x19, 0x05, 
+0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE5, 0x18, 0xE5, 
+0x18, 0xE5, 0x18, 0xE5, 0x18, 0xE5, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE5, 0x21, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x21, 0x25, 0x21, 0x26, 0x21, 0x46, 0x29, 0x66, 
+0x21, 0x46, 0x29, 0x67, 0x29, 0x46, 0x29, 0x46, 
+0x21, 0x46, 0x19, 0x05, 0x21, 0x05, 0x21, 0x26, 
+0x21, 0x46, 0x19, 0x05, 0x29, 0x66, 0x39, 0xE8, 
+0x4A, 0x6A, 0x6B, 0x4D, 0x94, 0x90, 0x94, 0x70, 
+0xD6, 0x77, 0xDE, 0xB8, 0xCE, 0x56, 0xD6, 0x97, 
+0xD6, 0x77, 0xD6, 0x57, 0xCE, 0x36, 0xD6, 0x56, 
+0xD6, 0x77, 0xD6, 0x56, 0xD6, 0x76, 0xD6, 0x97, 
+0xD6, 0x77, 0x9C, 0x90, 0x8C, 0x0E, 0xAD, 0x32, 
+0xC5, 0xF5, 0xBD, 0x93, 0xB5, 0x73, 0xBD, 0xB4, 
+0xB5, 0x73, 0xAD, 0x32, 0xB5, 0x73, 0xBD, 0x93, 
+0x9C, 0xB1, 0x31, 0xA6, 0x18, 0xC4, 0x10, 0xA3, 
+0x18, 0xC3, 0x4A, 0x49, 0x4A, 0x28, 0x4A, 0x28, 
+0x64, 0x28, 0x5B, 0xE8, 0x4B, 0x45, 0x4B, 0x46, 
+0x3A, 0xE5, 0x43, 0x25, 0x3A, 0xE3, 0x3A, 0xE3, 
+0x3A, 0xE4, 0x5B, 0xC7, 0x3A, 0xC3, 0x43, 0x24, 
+0x53, 0x85, 0x5B, 0x86, 0x5B, 0x87, 0x84, 0x8C, 
+0xA5, 0x71, 0xA5, 0x52, 0x94, 0xB0, 0x31, 0x86, 
+0x39, 0xC8, 0x39, 0xE8, 0x3A, 0x09, 0x42, 0x09, 
+0x42, 0x29, 0x42, 0x4A, 0x4A, 0x4A, 0x4A, 0x6B, 
+0x52, 0x8B, 0x4A, 0x8B, 0x4A, 0x8B, 0x52, 0xAB, 
+0x52, 0xAC, 0x5B, 0x0D, 0x63, 0x2E, 0x63, 0x2D, 
+0x63, 0x4E, 0x73, 0xB0, 0x73, 0x90, 0x73, 0x90, 
+0x73, 0x8F, 0x6B, 0x4E, 0x6B, 0x4E, 0x6B, 0x4E, 
+0x73, 0x8E, 0x6B, 0x4D, 0x4A, 0x6B, 0x52, 0xAB, 
+0x42, 0x09, 0x21, 0x26, 0x18, 0xE4, 0x19, 0x04, 
+0x18, 0xC4, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x08, 0xA3, 0x08, 0xA3, 
+0x21, 0x46, 0x73, 0xAF, 0x94, 0xD4, 0x8C, 0x94, 
+0x73, 0xB0, 0x4A, 0x4B, 0x29, 0x67, 0x31, 0xA8, 
+0x29, 0x87, 0x42, 0x4A, 0xAD, 0xB7, 0xEF, 0x9E, 
+0xC6, 0x38, 0xA4, 0xD1, 0xBD, 0x51, 0xC5, 0x71, 
+0xB5, 0x31, 0xC5, 0xF4, 0xC6, 0x16, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xCE, 0x56, 0xC5, 0xF5, 0xBD, 0xD4, 
+0xC5, 0xF5, 0xBD, 0xD5, 0xC5, 0xF5, 0x84, 0x0E, 
+0x9C, 0xD1, 0xC5, 0xF5, 0xC6, 0x15, 0xC6, 0x36, 
+0xC5, 0xF5, 0xBD, 0xD5, 0xBD, 0xB4, 0xBD, 0xD4, 
+0xBD, 0xF5, 0xD6, 0x97, 0xC5, 0xB3, 0xB4, 0xF0, 
+0xAC, 0xF0, 0xC6, 0x15, 0xBD, 0xD5, 0x84, 0x0E, 
+0x5A, 0xCA, 0x39, 0xC6, 0x52, 0x69, 0x52, 0x69, 
+0x42, 0x07, 0x42, 0x08, 0x52, 0x69, 0x5A, 0xAA, 
+0x63, 0x0C, 0x73, 0x8E, 0x8C, 0x30, 0x94, 0x72, 
+0xAD, 0x14, 0xA4, 0xF3, 0xB5, 0x96, 0xBD, 0xD7, 
+0xB5, 0x55, 0xBD, 0xB6, 0x9C, 0x91, 0xB5, 0x53, 
+0xAD, 0x11, 0x7B, 0x8C, 0x7B, 0x8B, 0xA4, 0xF0, 
+0xAD, 0x10, 0x94, 0x4E, 0x9C, 0xD1, 0xB5, 0x75, 
+0x9C, 0xB3, 0x7B, 0xCF, 0x7B, 0xAD, 0xA4, 0xAF, 
+0xC5, 0x51, 0xBD, 0x30, 0x93, 0xEC, 0x8C, 0x0D, 
+0xAC, 0xF0, 0x9C, 0x8E, 0x94, 0x2D, 0x8B, 0xED, 
+0x7B, 0x8B, 0x7B, 0x6B, 0x8B, 0xCC, 0x83, 0xAC, 
+0x8B, 0xCC, 0x8B, 0xCC, 0x8B, 0xED, 0x7B, 0x6A, 
+0x73, 0x2A, 0x7B, 0x6A, 0x8C, 0x0C, 0x9C, 0x6E, 
+0xA4, 0xF0, 0x9C, 0x6F, 0x94, 0x4F, 0xAD, 0x12, 
+0xB5, 0x53, 0xA4, 0xD1, 0xB5, 0x53, 0xAD, 0x12, 
+0xA4, 0xD1, 0xA4, 0xD1, 0x9C, 0xF1, 0x7B, 0xAD, 
+0x29, 0x45, 0x4A, 0x48, 0x4A, 0x48, 0x42, 0x07, 
+0x39, 0xC6, 0x4A, 0x69, 0x39, 0xC6, 0x4A, 0x28, 
+0x52, 0xAA, 0x5A, 0xCB, 0x5A, 0xCA, 0x39, 0xE7, 
+0x7B, 0xAE, 0x5A, 0xAA, 0x83, 0xAE, 0x94, 0x30, 
+0x8B, 0xEE, 0xAD, 0x12, 0xBD, 0x73, 0xB5, 0x53, 
+0xAD, 0x32, 0xAD, 0x12, 0xAC, 0xF1, 0xA4, 0xD1, 
+0xA4, 0xB0, 0xAD, 0x11, 0xA4, 0xD0, 0x94, 0x70, 
+0x9C, 0xB0, 0xB5, 0x32, 0xBD, 0x93, 0xBD, 0xB4, 
+0xC5, 0xB4, 0xBD, 0x52, 0xB5, 0x11, 0xA4, 0xD0, 
+0xC5, 0xB4, 0xCD, 0xF4, 0xC5, 0x93, 0xD6, 0x56, 
+0xDE, 0x76, 0xDE, 0x76, 0xE6, 0x97, 0xDE, 0x97, 
+0xC5, 0xB4, 0xCD, 0xD5, 0x62, 0xCA, 0x18, 0xC3, 
+0x10, 0xC4, 0x18, 0xE4, 0x18, 0xC3, 0x10, 0xC3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xC4, 0x10, 0xA3, 0x18, 0xE4, 0x10, 0xA3, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xC3, 0x10, 0xC3, 0x10, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x10, 0xC3, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x19, 0x05, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x26, 0x29, 0x67, 
+0x21, 0x46, 0x29, 0x67, 0x29, 0x67, 0x21, 0x46, 
+0x21, 0x05, 0x19, 0x05, 0x18, 0xE5, 0x18, 0xE5, 
+0x21, 0x26, 0x19, 0x05, 0x21, 0x26, 0x31, 0x87, 
+0x39, 0xC8, 0x52, 0x8A, 0x7B, 0xAE, 0x94, 0x91, 
+0xD6, 0x78, 0xDE, 0xD8, 0xD6, 0x97, 0xD6, 0x77, 
+0xD6, 0x97, 0xD6, 0x97, 0xDE, 0xB8, 0xDE, 0xB7, 
+0xD6, 0x56, 0xCE, 0x56, 0xD6, 0x76, 0xDE, 0xB7, 
+0xCE, 0x35, 0x9C, 0xB0, 0xAD, 0x32, 0xBD, 0xD4, 
+0xCE, 0x15, 0xBD, 0x93, 0xBD, 0x93, 0xBD, 0x93, 
+0xBD, 0x93, 0xB5, 0x73, 0xB5, 0x52, 0xBD, 0x93, 
+0xBD, 0xD4, 0x5A, 0xA9, 0x21, 0x04, 0x18, 0xA3, 
+0x10, 0x82, 0x41, 0xE7, 0x4A, 0x28, 0x41, 0xE7, 
+0x53, 0x86, 0x53, 0x86, 0x43, 0x05, 0x42, 0xE5, 
+0x4B, 0x67, 0x43, 0x05, 0x5B, 0xC7, 0x53, 0x86, 
+0x4B, 0x86, 0x4B, 0x86, 0x53, 0x85, 0x5B, 0xC7, 
+0x63, 0xC7, 0x7C, 0x4A, 0x94, 0xCD, 0xA5, 0x0F, 
+0xA5, 0x0F, 0xA4, 0xF0, 0x62, 0xEA, 0x18, 0xC3, 
+0x21, 0x25, 0x29, 0x46, 0x29, 0x66, 0x29, 0x66, 
+0x31, 0xA7, 0x4A, 0x49, 0x63, 0x0B, 0x6B, 0x2C, 
+0x73, 0x6D, 0x73, 0x8D, 0x73, 0x6D, 0x73, 0x6D, 
+0x7B, 0xAE, 0x83, 0xAE, 0x73, 0x6D, 0x6B, 0x4C, 
+0x6B, 0x2C, 0x6B, 0x6D, 0x6B, 0x4D, 0x7B, 0x8E, 
+0x8C, 0x0F, 0xAD, 0x33, 0xD6, 0x57, 0xDE, 0x77, 
+0xE6, 0x97, 0xD6, 0x36, 0x62, 0xA9, 0x41, 0xE8, 
+0x4A, 0x49, 0x21, 0x25, 0x10, 0xA3, 0x10, 0xA3, 
+0x08, 0x82, 0x08, 0x82, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 
+0x5B, 0x2D, 0xD6, 0xDC, 0xE7, 0x7E, 0xEF, 0x7E, 
+0xEF, 0x5E, 0xD6, 0x7B, 0x7B, 0xD1, 0x29, 0x67, 
+0x29, 0xA8, 0x29, 0xA8, 0x3A, 0x4B, 0x94, 0xF4, 
+0xEF, 0x7E, 0xE6, 0xFB, 0xBD, 0x32, 0xB5, 0x10, 
+0xBD, 0x72, 0xCE, 0x36, 0xCE, 0x77, 0xCE, 0x56, 
+0xC5, 0xF5, 0xC6, 0x15, 0xA4, 0xF1, 0x94, 0x90, 
+0xC6, 0x15, 0xC6, 0x16, 0xC5, 0xF6, 0xA5, 0x33, 
+0xB5, 0xB5, 0xCE, 0x36, 0xC6, 0x15, 0xC6, 0x15, 
+0xC5, 0xF5, 0xBD, 0xD5, 0xC6, 0x15, 0xC6, 0x36, 
+0xC6, 0x15, 0xD6, 0x97, 0xC5, 0xB3, 0xAC, 0xEF, 
+0xB5, 0x31, 0xC6, 0x15, 0xB5, 0x73, 0xB5, 0x74, 
+0x94, 0x70, 0x29, 0x45, 0x39, 0xC6, 0x52, 0x89, 
+0x31, 0x86, 0x39, 0xC6, 0x4A, 0x48, 0x52, 0x8A, 
+0x63, 0x0B, 0x7B, 0xAE, 0x7B, 0xAE, 0x7B, 0xCF, 
+0x8C, 0x31, 0xA4, 0xF4, 0xAD, 0x55, 0xA5, 0x14, 
+0x8C, 0x51, 0x73, 0x8E, 0x8C, 0x50, 0x94, 0x70, 
+0x94, 0x70, 0x83, 0xEE, 0x8C, 0x2E, 0xAD, 0x11, 
+0xA4, 0xF0, 0x94, 0x8F, 0xBD, 0x95, 0xAD, 0x35, 
+0x8C, 0x72, 0x7B, 0xCF, 0x6B, 0x4C, 0xA4, 0xAF, 
+0xBD, 0x51, 0xAC, 0xAF, 0x83, 0x8B, 0xA4, 0xF0, 
+0xB5, 0x73, 0xA4, 0xD0, 0x94, 0x8F, 0x83, 0xCD, 
+0x73, 0x4B, 0x62, 0xEA, 0x5A, 0xA9, 0x62, 0xEA, 
+0x6B, 0x2B, 0x62, 0xEA, 0x83, 0xED, 0x62, 0xCA, 
+0x5A, 0xCA, 0x62, 0xCA, 0x73, 0x4B, 0x94, 0x4E, 
+0x94, 0x8F, 0x83, 0xCD, 0x83, 0xCC, 0xA4, 0xF1, 
+0xAD, 0x32, 0xB5, 0x33, 0xBD, 0x93, 0xC5, 0xB4, 
+0xC5, 0xB5, 0xAD, 0x33, 0xAD, 0x12, 0xAD, 0x33, 
+0x83, 0xEE, 0x39, 0xC6, 0x39, 0xE7, 0x42, 0x07, 
+0x41, 0xE7, 0x39, 0xE7, 0x42, 0x07, 0x5A, 0xCA, 
+0x5A, 0xCA, 0x5A, 0xAA, 0x4A, 0x69, 0x5A, 0xCB, 
+0xB5, 0x96, 0xAD, 0x34, 0x6A, 0xEB, 0x94, 0x0F, 
+0x8B, 0xCE, 0xAC, 0xF2, 0xB5, 0x53, 0xB5, 0x53, 
+0xAD, 0x12, 0xB5, 0x53, 0xBD, 0x73, 0xB5, 0x73, 
+0xBD, 0x94, 0xBD, 0xB4, 0xC5, 0xD5, 0xCD, 0xF5, 
+0xCD, 0xF5, 0xC5, 0xB4, 0xBD, 0xB4, 0xBD, 0xB3, 
+0xC5, 0xB4, 0xC5, 0xB4, 0xCD, 0xD4, 0xCD, 0xD5, 
+0xCD, 0xF5, 0xCD, 0xD4, 0xC5, 0xB4, 0xC5, 0xB3, 
+0xB5, 0x32, 0xB5, 0x32, 0xBD, 0x32, 0xB5, 0x11, 
+0xAC, 0xF0, 0xAC, 0xF1, 0x41, 0xC6, 0x10, 0xC3, 
+0x10, 0xA3, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x10, 0xA3, 0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x82, 
+0x08, 0x82, 0x08, 0x82, 0x08, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x05, 0x21, 0x26, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x46, 0x29, 0x67, 
+0x21, 0x26, 0x29, 0x46, 0x29, 0x67, 0x21, 0x26, 
+0x18, 0xE5, 0x18, 0xE4, 0x10, 0xC3, 0x18, 0xC4, 
+0x21, 0x25, 0x21, 0x26, 0x21, 0x26, 0x29, 0x67, 
+0x31, 0xA8, 0x52, 0x8B, 0x94, 0xB2, 0xBD, 0xB5, 
+0x8C, 0x2F, 0xC5, 0xF6, 0xD6, 0x97, 0xD6, 0x77, 
+0xD6, 0x97, 0xDE, 0xB8, 0xCE, 0x35, 0xD6, 0x97, 
+0xD6, 0x97, 0xD6, 0x77, 0xD6, 0x97, 0xDE, 0xB7, 
+0xDE, 0xD7, 0xBD, 0xB3, 0xAD, 0x32, 0xB5, 0x73, 
+0xC6, 0x15, 0xB5, 0x73, 0xBD, 0x93, 0xBD, 0x93, 
+0xBD, 0xD4, 0xAD, 0x11, 0xCE, 0x35, 0xC5, 0xF4, 
+0xCE, 0x56, 0x8C, 0x2F, 0x29, 0x45, 0x18, 0xC3, 
+0x10, 0xA2, 0x29, 0x65, 0x42, 0x07, 0x41, 0xC6, 
+0x5B, 0xC8, 0x5B, 0xC7, 0x5B, 0xC7, 0x42, 0xE5, 
+0x43, 0x45, 0x32, 0x82, 0x4B, 0x45, 0x5B, 0xE7, 
+0x43, 0x25, 0x53, 0x86, 0x74, 0x8A, 0x7C, 0x6B, 
+0x74, 0x0A, 0x63, 0x89, 0x73, 0xA9, 0x84, 0x0B, 
+0x8C, 0x4D, 0xA4, 0xCF, 0xA4, 0xD0, 0x8C, 0x4E, 
+0x8C, 0x4F, 0x94, 0x4F, 0x9C, 0xB1, 0x94, 0x70, 
+0x8C, 0x2F, 0x9C, 0x90, 0xA4, 0xF0, 0xB5, 0x11, 
+0xB5, 0x10, 0xB5, 0x11, 0xB5, 0x11, 0xB4, 0xF0, 
+0xAC, 0xF0, 0xB5, 0x31, 0xBD, 0x51, 0xB5, 0x11, 
+0xB5, 0x10, 0xAC, 0xF0, 0xAC, 0xF0, 0xAC, 0xCF, 
+0xAC, 0xAF, 0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x6D, 
+0x9C, 0x6D, 0xB5, 0x10, 0xAC, 0xF0, 0x9C, 0x6F, 
+0x73, 0x2B, 0x41, 0xE6, 0x4A, 0x6A, 0x8C, 0x72, 
+0x29, 0x66, 0x08, 0x82, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x21, 0x25, 
+0x94, 0xF4, 0xD7, 0x1C, 0xDF, 0x5D, 0xE7, 0x5D, 
+0xE7, 0x5E, 0xEF, 0x7F, 0xE7, 0x3E, 0x94, 0xB4, 
+0x19, 0x05, 0x21, 0x46, 0x21, 0x88, 0x31, 0xC9, 
+0x73, 0xB0, 0xDE, 0xFC, 0xF7, 0x5C, 0xB5, 0x31, 
+0xCD, 0xD4, 0xD6, 0x76, 0xCE, 0x36, 0xC6, 0x15, 
+0xCE, 0x36, 0xCE, 0x77, 0xC6, 0x15, 0xBD, 0xD5, 
+0xB5, 0x94, 0xC5, 0xF5, 0xAD, 0x53, 0xBD, 0xD5, 
+0xC6, 0x16, 0xCE, 0x56, 0xC5, 0xF5, 0xC6, 0x15, 
+0xBD, 0xF5, 0xBD, 0xF5, 0xC6, 0x16, 0xAD, 0x53, 
+0xBD, 0xB4, 0xC5, 0xF5, 0xBD, 0x92, 0xB5, 0x10, 
+0xB5, 0x31, 0xB5, 0x73, 0xBD, 0x94, 0xBD, 0xD5, 
+0xCE, 0x36, 0x6B, 0x4C, 0x29, 0x45, 0x42, 0x08, 
+0x42, 0x07, 0x39, 0xA6, 0x39, 0xA6, 0x4A, 0x49, 
+0x52, 0x8A, 0x5A, 0xAA, 0x5A, 0xCB, 0x6B, 0x2D, 
+0x73, 0x6E, 0x94, 0x92, 0x9C, 0xB2, 0x7B, 0xAE, 
+0x73, 0x6D, 0x84, 0x10, 0xB5, 0x95, 0xB5, 0x95, 
+0x84, 0x0F, 0x94, 0x90, 0x94, 0x6F, 0x94, 0x8F, 
+0xA4, 0xD0, 0xA4, 0xD1, 0xBD, 0xB5, 0x94, 0xB3, 
+0x84, 0x31, 0x83, 0xEF, 0x7B, 0xAD, 0xA4, 0xCF, 
+0xC5, 0x51, 0x9C, 0x4E, 0x73, 0x6B, 0x83, 0xED, 
+0x9C, 0xD0, 0x94, 0x6F, 0xB5, 0x73, 0xAD, 0x52, 
+0x73, 0x4B, 0x62, 0xEA, 0x63, 0x0B, 0x62, 0xEB, 
+0x62, 0xEB, 0x5A, 0xCA, 0x8C, 0x4F, 0x7B, 0xAD, 
+0x7B, 0xCD, 0x6B, 0x4B, 0x7B, 0xAD, 0x8C, 0x2E, 
+0x8C, 0x2E, 0x73, 0x4B, 0x73, 0x8C, 0xAD, 0x32, 
+0xAD, 0x32, 0xBD, 0x94, 0xCE, 0x15, 0xCD, 0xF5, 
+0xC5, 0xF5, 0xB5, 0x74, 0xAD, 0x12, 0xAD, 0x32, 
+0xC5, 0xD5, 0x94, 0x4F, 0x31, 0x65, 0x4A, 0x68, 
+0x39, 0xC6, 0x39, 0xC6, 0x52, 0x89, 0x5A, 0xEB, 
+0x42, 0x28, 0x52, 0x89, 0x39, 0xE7, 0x52, 0xAA, 
+0x84, 0x30, 0xCE, 0x79, 0x9C, 0xB3, 0x73, 0x0C, 
+0x8B, 0xCE, 0x94, 0x2F, 0x9C, 0x50, 0x9C, 0x90, 
+0x8C, 0x2E, 0x9C, 0x8F, 0x9C, 0x90, 0x9C, 0x90, 
+0xAD, 0x12, 0xA4, 0xF1, 0xA4, 0xD0, 0x8B, 0xED, 
+0xAD, 0x32, 0xB5, 0x33, 0xB5, 0x32, 0x9C, 0xAF, 
+0x94, 0x4E, 0x8C, 0x2E, 0x94, 0x6F, 0x94, 0x6F, 
+0x9C, 0x4F, 0x9C, 0x6F, 0xAC, 0xF0, 0xB5, 0x31, 
+0xAC, 0xF1, 0xBD, 0x73, 0xBD, 0x73, 0xD6, 0x15, 
+0xCD, 0xD4, 0x9C, 0x90, 0x39, 0x85, 0x18, 0xC3, 
+0x10, 0xC3, 0x10, 0xC3, 0x18, 0xC4, 0x19, 0x05, 
+0x18, 0xE4, 0x10, 0x83, 0x10, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x08, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x18, 0xE4, 
+0x19, 0x04, 0x18, 0xE4, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 0x10, 0xC4, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x19, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 0x19, 0x05, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x05, 0x21, 0x26, 0x21, 0x25, 0x21, 0x26, 
+0x19, 0x05, 0x21, 0x25, 0x21, 0x26, 0x21, 0x46, 
+0x21, 0x26, 0x21, 0x46, 0x21, 0x26, 0x21, 0x05, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA4, 0x18, 0xE4, 
+0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 0x21, 0x46, 
+0x31, 0x87, 0x4A, 0x4A, 0xA5, 0x34, 0xB5, 0x95, 
+0x8C, 0x2F, 0xDE, 0xB9, 0xDE, 0xB8, 0xDE, 0x97, 
+0xE6, 0xF9, 0xBD, 0xB4, 0xC6, 0x15, 0xD6, 0x97, 
+0xD6, 0x77, 0xD6, 0x77, 0xD6, 0x76, 0xD6, 0x76, 
+0xD6, 0x96, 0xBD, 0xB4, 0xAD, 0x32, 0xB5, 0x52, 
+0xCE, 0x36, 0xC5, 0xF4, 0xC5, 0xF4, 0xCE, 0x15, 
+0xCE, 0x15, 0xBD, 0x93, 0xCE, 0x35, 0xCE, 0x14, 
+0xC5, 0xF4, 0xA4, 0xF1, 0x5A, 0xCB, 0x20, 0xE4, 
+0x18, 0xC3, 0x21, 0x04, 0x4A, 0x28, 0x41, 0xC6, 
+0x74, 0x8B, 0x74, 0x69, 0x74, 0x6A, 0x64, 0x08, 
+0x53, 0xA6, 0x64, 0x28, 0x4B, 0x45, 0x4B, 0x45, 
+0x32, 0x62, 0x63, 0xC9, 0x74, 0x2B, 0x53, 0x28, 
+0x52, 0xE8, 0x6B, 0xAB, 0x53, 0x07, 0x4A, 0xE6, 
+0x6B, 0xAA, 0x73, 0x89, 0x9C, 0xAE, 0xB5, 0x70, 
+0xBD, 0xB2, 0xA5, 0x11, 0xA5, 0x11, 0x9C, 0xD0, 
+0x9C, 0x90, 0x94, 0x4E, 0xA4, 0xF0, 0xCD, 0xF3, 
+0xA4, 0xAE, 0xC5, 0xB3, 0xC5, 0xD3, 0xBD, 0x52, 
+0xBD, 0x92, 0xCD, 0xD3, 0xC5, 0x93, 0x9C, 0x6E, 
+0xAD, 0x10, 0xD6, 0x14, 0xCD, 0xF4, 0xB5, 0x31, 
+0x9C, 0x4D, 0xB4, 0xEF, 0xC5, 0xB2, 0xC5, 0xB2, 
+0xBD, 0x51, 0xA4, 0x6E, 0xBD, 0x31, 0xB5, 0x30, 
+0xAC, 0xF0, 0xB5, 0x53, 0xE7, 0x3B, 0xF7, 0x7D, 
+0x5A, 0xEB, 0x08, 0x82, 0x08, 0x82, 0x10, 0x83, 
+0x08, 0x82, 0x08, 0x83, 0x10, 0xC3, 0x3A, 0x09, 
+0xB5, 0xD8, 0xD6, 0xDB, 0xD7, 0x1C, 0xDF, 0x3D, 
+0xE7, 0x3E, 0xE7, 0x5E, 0xEF, 0x7E, 0xEF, 0x7F, 
+0xAD, 0x76, 0x31, 0xA8, 0x19, 0x05, 0x19, 0x26, 
+0x21, 0x66, 0x63, 0x4D, 0xE7, 0x3B, 0xE6, 0xB9, 
+0xB5, 0x31, 0xC5, 0xD3, 0xBD, 0xB3, 0xB5, 0x51, 
+0xB5, 0x52, 0xBD, 0xB4, 0xBD, 0xD4, 0xBD, 0xD5, 
+0xBD, 0x93, 0xC5, 0xD5, 0xC5, 0xF5, 0xC6, 0x16, 
+0xCE, 0x36, 0xCE, 0x56, 0xC6, 0x15, 0xC6, 0x16, 
+0xC5, 0xF5, 0xC6, 0x16, 0xD6, 0x77, 0xC6, 0x36, 
+0xBD, 0xD4, 0xC5, 0xF5, 0x9C, 0x8F, 0xBD, 0x30, 
+0xB5, 0x31, 0xC6, 0x15, 0xCE, 0x36, 0xC6, 0x36, 
+0xD6, 0x77, 0xBD, 0xB4, 0x41, 0xE7, 0x52, 0xAA, 
+0x63, 0x0B, 0x42, 0x07, 0x39, 0xC6, 0x39, 0xA6, 
+0x4A, 0x49, 0x52, 0x89, 0x5A, 0xAA, 0x6B, 0x2C, 
+0x73, 0x6E, 0x94, 0x92, 0x94, 0x71, 0x8C, 0x30, 
+0x83, 0xEF, 0x9C, 0xD2, 0x94, 0x71, 0xC5, 0xD7, 
+0xA5, 0x13, 0x9C, 0xB1, 0x94, 0x90, 0x94, 0x6F, 
+0xA5, 0x11, 0xAD, 0x33, 0xB5, 0x95, 0xA5, 0x14, 
+0x94, 0x72, 0x7B, 0xAE, 0x83, 0xCE, 0xAC, 0xD0, 
+0xBD, 0x50, 0x83, 0xAC, 0x7B, 0xCD, 0xA5, 0x12, 
+0xB5, 0x53, 0x9C, 0x90, 0x94, 0x6F, 0x94, 0x6F, 
+0x6B, 0x2B, 0x5A, 0xEA, 0x62, 0xEB, 0x5A, 0xCB, 
+0x62, 0xEB, 0x5A, 0xEA, 0xA5, 0x12, 0xA4, 0xF1, 
+0xA4, 0xD1, 0x84, 0x0E, 0x94, 0x6F, 0x9C, 0x90, 
+0xA4, 0xD0, 0x73, 0x4B, 0x7B, 0x8C, 0xBD, 0x94, 
+0xA4, 0xF1, 0xBD, 0x94, 0xC5, 0xF5, 0xC5, 0xD5, 
+0xC5, 0xF5, 0xB5, 0x94, 0xB5, 0x53, 0xA4, 0xF1, 
+0xAD, 0x32, 0xA4, 0xF2, 0x73, 0x8C, 0x8C, 0x50, 
+0x63, 0x0B, 0x39, 0xE7, 0x4A, 0x28, 0x5A, 0xCA, 
+0x42, 0x07, 0x4A, 0x49, 0x52, 0xAA, 0x52, 0xAA, 
+0x62, 0xEC, 0x9C, 0xF3, 0xAD, 0x34, 0x6B, 0x0B, 
+0x94, 0x0F, 0x8B, 0xCE, 0x94, 0x50, 0x83, 0xCE, 
+0x7B, 0xAD, 0x7B, 0xAD, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xB5, 0x52, 0xAD, 0x32, 0xBD, 0xB4, 0xAD, 0x32, 
+0xAD, 0x32, 0xB5, 0x53, 0x9C, 0xB0, 0x94, 0x6F, 
+0x9C, 0x8F, 0x9C, 0x8F, 0xAD, 0x32, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xA4, 0xD0, 0xA4, 0xD0, 0xA5, 0x10, 
+0x9C, 0xAF, 0xC5, 0xB4, 0xB5, 0x32, 0xC5, 0x93, 
+0xBD, 0x93, 0x9C, 0x6F, 0x39, 0x86, 0x18, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC3, 0x21, 0x25, 
+0x18, 0xE4, 0x10, 0xA3, 0x10, 0xA3, 0x08, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x08, 0x83, 
+0x10, 0x83, 0x08, 0x83, 0x10, 0xA3, 0x10, 0xC4, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 0x10, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x10, 0xA3, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x21, 0x05, 0x21, 0x25, 0x19, 0x05, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x21, 0x26, 0x18, 0xE5, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE5, 0x19, 0x05, 
+0x21, 0x25, 0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 
+0x29, 0x87, 0x31, 0xA8, 0x94, 0xB2, 0xA5, 0x12, 
+0x8C, 0x2F, 0xE6, 0xFA, 0xD6, 0x97, 0xDE, 0xD8, 
+0xDE, 0xB8, 0x83, 0xCE, 0xDE, 0xB8, 0xDE, 0xB7, 
+0xD6, 0x97, 0xDE, 0x97, 0xDE, 0xB7, 0xD6, 0x96, 
+0xDE, 0xB7, 0xB5, 0x52, 0xAD, 0x12, 0xCE, 0x35, 
+0xD6, 0x35, 0xCE, 0x35, 0xCE, 0x14, 0xCE, 0x14, 
+0xCE, 0x35, 0xBD, 0xB3, 0xCE, 0x14, 0xC6, 0x14, 
+0xC5, 0xF4, 0xCE, 0x35, 0xC5, 0xF6, 0x39, 0xA7, 
+0x18, 0xE4, 0x18, 0xA3, 0x4A, 0x08, 0x39, 0xC6, 
+0x4B, 0x27, 0x3A, 0xC4, 0x5B, 0xC8, 0x42, 0xE4, 
+0x53, 0x86, 0x53, 0x86, 0x32, 0x42, 0x43, 0x05, 
+0x53, 0x48, 0x74, 0x0B, 0x74, 0x2C, 0x63, 0x8A, 
+0x95, 0x10, 0x9D, 0x31, 0x5B, 0xA9, 0x63, 0xE8, 
+0xA5, 0xAF, 0x9D, 0x4D, 0x7C, 0x69, 0xA5, 0x8E, 
+0xAD, 0x70, 0xAD, 0x11, 0xA4, 0xF1, 0x94, 0x4F, 
+0x94, 0x6F, 0x83, 0xED, 0xAD, 0x11, 0xCE, 0x34, 
+0xCE, 0x14, 0xD6, 0x55, 0xC5, 0xD3, 0xC5, 0xD3, 
+0xC5, 0xD4, 0xCE, 0x15, 0xC5, 0xD3, 0xCD, 0xD3, 
+0xB5, 0x31, 0xCD, 0xF4, 0xD6, 0x55, 0xBD, 0x51, 
+0x8B, 0xAB, 0xB5, 0x10, 0xAC, 0xCF, 0xAC, 0xAE, 
+0xDE, 0x34, 0x9C, 0x4D, 0xCD, 0xF4, 0xD6, 0x35, 
+0xBD, 0x92, 0xCE, 0x56, 0xEF, 0x7C, 0xEF, 0x7D, 
+0x8C, 0x31, 0x08, 0x63, 0x08, 0x82, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 0x63, 0x6E, 
+0xC6, 0x79, 0xD6, 0xFC, 0xD6, 0xFC, 0xDE, 0xFC, 
+0xDF, 0x1C, 0xDF, 0x1C, 0xE7, 0x1D, 0xEF, 0x5E, 
+0xF7, 0xBE, 0xCE, 0x39, 0x41, 0xE8, 0x21, 0x46, 
+0x29, 0x87, 0x21, 0x45, 0x6B, 0x8E, 0xE7, 0x1A, 
+0xB5, 0x11, 0xB5, 0x10, 0xBD, 0x50, 0xBD, 0x51, 
+0xC5, 0x72, 0xBD, 0x31, 0xB5, 0x10, 0xAC, 0xEF, 
+0xA4, 0xAF, 0x9C, 0x8E, 0x9C, 0x6E, 0x9C, 0x4D, 
+0x94, 0x4D, 0x94, 0x4D, 0x94, 0x4E, 0x94, 0x2D, 
+0x9C, 0x8F, 0xAD, 0x11, 0xAD, 0x31, 0xAC, 0xF1, 
+0xA4, 0xAF, 0xAC, 0xF0, 0x9C, 0x8E, 0xB5, 0x10, 
+0xBD, 0x51, 0xD6, 0x56, 0xD6, 0x56, 0xCE, 0x15, 
+0xCE, 0x36, 0xD6, 0x77, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xB5, 0x73, 0x5A, 0x88, 0x42, 0x07, 0x39, 0xC6, 
+0x41, 0xE7, 0x4A, 0x28, 0x52, 0x8A, 0x63, 0x0C, 
+0x73, 0x8E, 0x7B, 0xCF, 0x73, 0x6D, 0x7B, 0xCF, 
+0x8C, 0x51, 0x9C, 0xB2, 0xAD, 0x55, 0xBD, 0xD6, 
+0xBD, 0xD6, 0xA5, 0x13, 0xAD, 0x53, 0xA4, 0xF1, 
+0xA5, 0x11, 0xB5, 0x74, 0xAD, 0x54, 0x9C, 0xD3, 
+0xAD, 0x15, 0x73, 0x6D, 0x83, 0xEE, 0xA4, 0xCF, 
+0xB4, 0xEF, 0x7B, 0x8B, 0x94, 0x4F, 0xAD, 0x32, 
+0xB5, 0x52, 0xAD, 0x32, 0x9C, 0x90, 0x8C, 0x2F, 
+0x8C, 0x2F, 0x6B, 0x4C, 0x84, 0x0F, 0x73, 0x8D, 
+0x73, 0x6D, 0x63, 0x2B, 0xB5, 0x74, 0xAD, 0x11, 
+0xA4, 0xD1, 0x9C, 0xB0, 0xA4, 0xF1, 0x9C, 0xB0, 
+0x94, 0x8F, 0x73, 0x6B, 0x7B, 0xCD, 0xBD, 0xD5, 
+0xA4, 0xF2, 0xA5, 0x12, 0xB5, 0x94, 0xAD, 0x53, 
+0x9C, 0xB1, 0x9C, 0xB0, 0xA4, 0xD1, 0x94, 0x4F, 
+0x94, 0x4F, 0x8C, 0x4F, 0x73, 0x6C, 0x8C, 0x30, 
+0x83, 0xEE, 0x52, 0x89, 0x39, 0xC6, 0x5A, 0xAA, 
+0x52, 0x89, 0x5A, 0xCA, 0x5A, 0xCA, 0x5A, 0xCB, 
+0x6B, 0x2D, 0x62, 0xEC, 0x52, 0x8A, 0x41, 0xE7, 
+0x73, 0x4C, 0x7B, 0x4C, 0x7B, 0x8D, 0x6B, 0x0C, 
+0x62, 0xCB, 0x4A, 0x28, 0xA4, 0xD1, 0xBD, 0xD4, 
+0xB5, 0x53, 0xAD, 0x52, 0xB5, 0x73, 0xAD, 0x12, 
+0x9C, 0xD0, 0xB5, 0x73, 0x9C, 0xB0, 0xA4, 0xD1, 
+0x94, 0x6F, 0x8C, 0x2E, 0x9C, 0xD0, 0x94, 0x6F, 
+0x94, 0x4E, 0x8C, 0x2E, 0x8C, 0x4E, 0x94, 0x6F, 
+0x9C, 0x8F, 0xBD, 0x94, 0xBD, 0x73, 0xC5, 0xD4, 
+0xBD, 0x93, 0xA4, 0xB0, 0x39, 0x86, 0x18, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC3, 0x21, 0x25, 
+0x19, 0x04, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x10, 0x82, 
+0x10, 0x83, 0x21, 0x05, 0x42, 0x08, 0x5A, 0xCA, 
+0x4A, 0x69, 0x29, 0x65, 0x18, 0xE4, 0x21, 0x05, 
+0x10, 0xC3, 0x10, 0xA3, 0x10, 0xC3, 0x18, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 
+0x18, 0xE4, 0x19, 0x04, 0x10, 0xC4, 0x10, 0xC4, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 0x21, 0x05, 
+0x19, 0x05, 0x18, 0xE4, 0x19, 0x05, 0x19, 0x05, 
+0x19, 0x05, 0x18, 0xE4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x19, 0x05, 0x21, 0x05, 0x18, 0xE5, 
+0x18, 0xC4, 0x19, 0x05, 0x21, 0x05, 0x18, 0xE5, 
+0x19, 0x05, 0x21, 0x26, 0x21, 0x25, 0x18, 0xE4, 
+0x18, 0xE5, 0x18, 0xE5, 0x19, 0x05, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 0x21, 0x46, 
+0x31, 0x87, 0x31, 0x87, 0x5A, 0xCB, 0x9C, 0xD2, 
+0xBD, 0x94, 0xD6, 0x77, 0xD6, 0x77, 0xD6, 0x98, 
+0xD6, 0x78, 0x8C, 0x30, 0xE7, 0x1A, 0xDE, 0xD8, 
+0xD6, 0x77, 0xCE, 0x15, 0xC5, 0xF4, 0xDE, 0x96, 
+0xE6, 0xF8, 0xAD, 0x11, 0xA4, 0xB0, 0xDE, 0x96, 
+0xE6, 0xB6, 0xDE, 0x96, 0xD6, 0x55, 0xDE, 0x76, 
+0xD6, 0x75, 0xC5, 0xD3, 0xD6, 0x35, 0xD6, 0x55, 
+0xCE, 0x14, 0xD6, 0x35, 0xDE, 0xB7, 0x83, 0xEE, 
+0x20, 0xE4, 0x10, 0xA3, 0x29, 0x24, 0x41, 0xE7, 
+0x53, 0x69, 0x5B, 0x89, 0x74, 0x2B, 0x63, 0xA9, 
+0x42, 0xC4, 0x42, 0xA3, 0x3A, 0x64, 0x3A, 0x85, 
+0x5B, 0x69, 0x5B, 0x29, 0x3A, 0x66, 0x42, 0xA7, 
+0x9D, 0x52, 0x74, 0x0C, 0x3A, 0xA3, 0x4B, 0x64, 
+0x53, 0xA4, 0x6C, 0x26, 0x9D, 0x8C, 0xBE, 0x30, 
+0xBD, 0xD2, 0xC6, 0x15, 0xB5, 0x73, 0x94, 0x8F, 
+0x94, 0x70, 0xA4, 0xD1, 0xC6, 0x15, 0xDE, 0x96, 
+0xD6, 0x75, 0xD6, 0x76, 0xC5, 0xF4, 0xAD, 0x11, 
+0xB5, 0x73, 0xB5, 0x73, 0xA4, 0xF0, 0xC5, 0xB3, 
+0xBD, 0x92, 0xB5, 0x31, 0xCE, 0x34, 0xC5, 0xB2, 
+0x8B, 0xCC, 0xA4, 0x8E, 0xB5, 0x30, 0xDE, 0x55, 
+0xD5, 0xF4, 0xCD, 0xD3, 0xD6, 0x55, 0xCE, 0x14, 
+0xC5, 0xD4, 0xC6, 0x15, 0xDE, 0xFA, 0xE7, 0x1B, 
+0xAD, 0x55, 0x18, 0xA3, 0x08, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xE4, 0x7C, 0x31, 
+0xC6, 0x59, 0xD6, 0xFB, 0xD6, 0xDB, 0xD6, 0xDB, 
+0xD6, 0xDB, 0xDE, 0xDB, 0xDE, 0xDB, 0xDE, 0xFC, 
+0xE7, 0x1C, 0xEF, 0x5D, 0xB5, 0x75, 0x29, 0x66, 
+0x31, 0xA7, 0x29, 0x86, 0x21, 0x45, 0x7B, 0xEF, 
+0xAD, 0x32, 0x8B, 0xEC, 0x9C, 0x4D, 0xA4, 0xAF, 
+0x8B, 0xEC, 0xA4, 0xAE, 0x9C, 0x4D, 0x94, 0x0C, 
+0x9C, 0x4D, 0x9C, 0x6E, 0xA4, 0x8E, 0x9C, 0x6D, 
+0xAC, 0xEF, 0xB5, 0x0F, 0xAC, 0xEF, 0xA4, 0xAE, 
+0x9C, 0x6E, 0x9C, 0x4D, 0xA4, 0x8E, 0xA4, 0x8E, 
+0xAC, 0xCF, 0xB5, 0x0F, 0xB5, 0x10, 0xB5, 0x10, 
+0xA4, 0x8E, 0x9C, 0x6E, 0x9C, 0x8E, 0x9C, 0x6E, 
+0x9C, 0x6E, 0xA4, 0x8E, 0x9C, 0x6E, 0x9C, 0x6D, 
+0x94, 0x2D, 0x7B, 0x6B, 0x52, 0x48, 0x39, 0xA6, 
+0x39, 0xC6, 0x39, 0xA6, 0x52, 0x69, 0x63, 0x0C, 
+0x73, 0x6D, 0x52, 0x8A, 0x63, 0x0C, 0x7B, 0xAF, 
+0xA4, 0xF3, 0xA4, 0xF3, 0xBD, 0xB6, 0xAD, 0x54, 
+0xB5, 0x75, 0xCE, 0x17, 0xA5, 0x12, 0x9C, 0xB0, 
+0x94, 0x8F, 0xAD, 0x54, 0xA5, 0x14, 0x9C, 0xD3, 
+0xB5, 0xB7, 0x7B, 0xCE, 0x73, 0x6B, 0xA4, 0xD0, 
+0xB5, 0x10, 0x7B, 0x8B, 0x73, 0x4B, 0x94, 0x6F, 
+0xA4, 0xF1, 0xAD, 0x12, 0x9C, 0x90, 0x94, 0x70, 
+0x6B, 0x2B, 0x63, 0x0B, 0x94, 0x91, 0x8C, 0x2F, 
+0x73, 0x8D, 0x6B, 0x8D, 0xB5, 0x94, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xAD, 0x32, 0xAD, 0x52, 0x9C, 0xD0, 
+0x8C, 0x4E, 0x73, 0x4B, 0x84, 0x0E, 0xC5, 0xF6, 
+0xA4, 0xF2, 0x83, 0xEE, 0x7B, 0xAD, 0x73, 0x8C, 
+0x6B, 0x4C, 0x62, 0xEA, 0x6B, 0x4C, 0x6B, 0x2B, 
+0x6B, 0x2B, 0x6B, 0x4B, 0x62, 0xEB, 0x63, 0x0B, 
+0x63, 0x0B, 0x63, 0x0B, 0x4A, 0x28, 0x4A, 0x48, 
+0x42, 0x07, 0x4A, 0x48, 0x52, 0x89, 0x4A, 0x69, 
+0x63, 0x0C, 0x6B, 0x2C, 0x6B, 0x4D, 0x41, 0xC7, 
+0x5A, 0x69, 0x62, 0xAA, 0x62, 0x8A, 0x73, 0x0C, 
+0x83, 0xCF, 0x7B, 0x6D, 0x83, 0xCD, 0xAD, 0x32, 
+0xCE, 0x57, 0xB5, 0x93, 0xAD, 0x31, 0xA4, 0xF0, 
+0x9C, 0xB0, 0xBD, 0x74, 0xBD, 0x93, 0xA5, 0x11, 
+0x9C, 0xB0, 0x8C, 0x2E, 0x94, 0x90, 0x8C, 0x4E, 
+0x94, 0x6F, 0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0xB0, 
+0x9C, 0xB0, 0xBD, 0x73, 0xB5, 0x52, 0xCD, 0xF5, 
+0xC5, 0xD4, 0xB5, 0x33, 0x4A, 0x08, 0x18, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x18, 0xC4, 0x21, 0x45, 
+0x19, 0x04, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x08, 0x83, 0x08, 0x83, 
+0x21, 0x05, 0x73, 0xAE, 0x94, 0x91, 0x9C, 0xB1, 
+0x9C, 0xD1, 0x8C, 0x2F, 0x63, 0x0B, 0x6B, 0x4C, 
+0x4A, 0x48, 0x19, 0x04, 0x10, 0xC3, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE5, 0x19, 0x05, 
+0x19, 0x05, 0x18, 0xE5, 0x18, 0xE5, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x18, 0xE5, 0x18, 0xE5, 0x21, 0x05, 0x18, 0xE5, 
+0x18, 0xC4, 0x18, 0xE5, 0x18, 0xE5, 0x18, 0xC4, 
+0x10, 0xC4, 0x19, 0x05, 0x19, 0x05, 0x18, 0xE4, 
+0x19, 0x05, 0x19, 0x05, 0x18, 0xE5, 0x21, 0x05, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x05, 0x29, 0x46, 
+0x31, 0xA8, 0x29, 0x87, 0x39, 0xE8, 0x73, 0x6D, 
+0x94, 0x70, 0x9C, 0x90, 0x9C, 0x90, 0x9C, 0xB1, 
+0x9C, 0x90, 0x8C, 0x2F, 0x9C, 0x90, 0x9C, 0x6F, 
+0x94, 0x2F, 0x8C, 0x0E, 0x94, 0x2E, 0xA4, 0xB0, 
+0xB5, 0x31, 0xAC, 0xF0, 0x9C, 0x8F, 0xA4, 0x8F, 
+0xB5, 0x11, 0xC5, 0xB3, 0xC5, 0xD3, 0xC5, 0xD3, 
+0xB5, 0x52, 0xBD, 0x92, 0xD6, 0x35, 0xD6, 0x35, 
+0xCE, 0x15, 0xD6, 0x76, 0xD6, 0x76, 0xCE, 0x36, 
+0x73, 0x8D, 0x6B, 0x4C, 0x31, 0x86, 0x41, 0xE7, 
+0x74, 0x4D, 0x53, 0x28, 0x42, 0xA6, 0x5B, 0x48, 
+0x6B, 0xE9, 0x74, 0x4A, 0x6C, 0x0A, 0x4B, 0x06, 
+0x42, 0xE6, 0x4A, 0xE7, 0x5B, 0x8A, 0x95, 0x31, 
+0xBE, 0x15, 0x6B, 0xCB, 0x43, 0x24, 0x5B, 0xC5, 
+0x5B, 0xE4, 0x8D, 0x0A, 0xA5, 0x6D, 0xAD, 0x90, 
+0xAD, 0x51, 0x9C, 0xF0, 0x8C, 0x4E, 0x8C, 0x2E, 
+0x8C, 0x2E, 0x9C, 0xD1, 0xCE, 0x14, 0xDE, 0xB6, 
+0xD6, 0x54, 0xCE, 0x35, 0xC5, 0xF4, 0xAD, 0x31, 
+0xBD, 0xB4, 0xAD, 0x32, 0xA4, 0xF1, 0xBD, 0x92, 
+0xCD, 0xF4, 0xAD, 0x31, 0xCE, 0x14, 0xB5, 0x31, 
+0xB5, 0x31, 0xA4, 0x8E, 0xB5, 0x10, 0xD5, 0xF3, 
+0xCD, 0xD3, 0xCD, 0xD3, 0xCE, 0x14, 0xCD, 0xF4, 
+0xCE, 0x15, 0xC6, 0x35, 0xD6, 0xB9, 0xCE, 0x78, 
+0xC5, 0xF7, 0x62, 0xEB, 0x08, 0x82, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC3, 0x19, 0x25, 0x84, 0x72, 
+0xBE, 0x38, 0xCE, 0xBA, 0xCE, 0x9A, 0xCE, 0x9A, 
+0xD6, 0xBA, 0xD6, 0x99, 0xCE, 0x99, 0xCE, 0x9A, 
+0xD6, 0x9A, 0xD6, 0x99, 0xC6, 0x37, 0x7B, 0xAE, 
+0x29, 0x45, 0x21, 0x25, 0x21, 0x45, 0x39, 0xC7, 
+0x94, 0x90, 0x94, 0x6F, 0x8C, 0x2E, 0x8C, 0x2E, 
+0x94, 0x6F, 0x94, 0x6F, 0x7B, 0xCC, 0x83, 0xED, 
+0x94, 0x4E, 0x94, 0x6E, 0x83, 0xCB, 0x83, 0xCB, 
+0xA4, 0x8E, 0xAC, 0xEF, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xB5, 0x51, 0xAC, 0xEF, 0x94, 0x2C, 0x8B, 0xEB, 
+0x9C, 0x4D, 0xB5, 0x30, 0xAC, 0xCF, 0x9C, 0x4D, 
+0xA4, 0x6D, 0xA4, 0xAE, 0xAC, 0xEF, 0xB5, 0x10, 
+0xBD, 0x31, 0xC5, 0x71, 0xB5, 0x30, 0xAC, 0xCF, 
+0x9C, 0x6E, 0x94, 0x4E, 0x8B, 0xED, 0x52, 0x68, 
+0x42, 0x08, 0x4A, 0x28, 0x52, 0x89, 0x5A, 0xCB, 
+0x73, 0x6D, 0x62, 0xEB, 0x73, 0x8E, 0x94, 0x71, 
+0x9C, 0xD3, 0x9C, 0xD3, 0xBD, 0xD7, 0xBD, 0xB6, 
+0xA5, 0x13, 0xCE, 0x38, 0xD6, 0x58, 0xAC, 0xF2, 
+0xA4, 0xD1, 0xAD, 0x33, 0x94, 0x91, 0x84, 0x10, 
+0x6B, 0x4D, 0x83, 0xCD, 0x94, 0x2D, 0xBD, 0x52, 
+0xC5, 0x72, 0xAC, 0xF0, 0x8B, 0xED, 0x8B, 0xCD, 
+0x9C, 0x6E, 0x94, 0x4E, 0x8C, 0x0D, 0x83, 0xAC, 
+0x83, 0xAC, 0x73, 0x6C, 0x84, 0x0E, 0x83, 0xED, 
+0x7B, 0xCD, 0x83, 0xEE, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xB5, 0x73, 0x94, 0x6F, 0xAD, 0x11, 0xA4, 0xD0, 
+0x8C, 0x2E, 0x62, 0xEA, 0x7B, 0xAD, 0xC5, 0xF5, 
+0xA4, 0xF1, 0x8C, 0x2F, 0x8C, 0x2F, 0x8C, 0x2F, 
+0x84, 0x2F, 0x73, 0x8D, 0x84, 0x0F, 0x7B, 0xCE, 
+0x73, 0x8D, 0x6B, 0x6D, 0x6B, 0x4C, 0x5A, 0xCA, 
+0x6B, 0x4C, 0x62, 0xEB, 0x5A, 0xEB, 0x5A, 0xCA, 
+0x39, 0xA6, 0x42, 0x08, 0x4A, 0x48, 0x4A, 0x49, 
+0x52, 0x8A, 0x6B, 0x4C, 0x63, 0x0C, 0x41, 0xE7, 
+0x5A, 0x69, 0x62, 0xAA, 0x73, 0x2C, 0x7B, 0x6D, 
+0x73, 0x4C, 0x7B, 0x6D, 0x83, 0xAD, 0x83, 0xCE, 
+0xAD, 0x13, 0xB5, 0x93, 0xB5, 0x73, 0xAD, 0x31, 
+0x9C, 0xB0, 0xB5, 0x73, 0xAD, 0x12, 0xAD, 0x12, 
+0xA4, 0xF1, 0x94, 0x90, 0xAD, 0x32, 0x9C, 0xD0, 
+0xA4, 0xF1, 0x9C, 0xD1, 0xAD, 0x12, 0xAD, 0x52, 
+0x9C, 0xB0, 0xBD, 0x94, 0xB5, 0x52, 0xD6, 0x56, 
+0xCE, 0x15, 0xC5, 0xB4, 0x62, 0xCA, 0x18, 0xC3, 
+0x10, 0x83, 0x10, 0x83, 0x18, 0xC3, 0x21, 0x46, 
+0x21, 0x05, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x08, 0x82, 0x10, 0xA3, 
+0x63, 0x0C, 0x9C, 0xF1, 0xB5, 0x94, 0xB5, 0x73, 
+0xC5, 0xD5, 0xAD, 0x12, 0xA4, 0xD1, 0xA5, 0x12, 
+0xA4, 0xD1, 0x52, 0x89, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE5, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 
+0x19, 0x05, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE5, 
+0x18, 0xE5, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x21, 0x25, 0x21, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x18, 0xE5, 0x18, 0xE5, 0x18, 0xE5, 0x18, 0xE4, 
+0x10, 0xA4, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xE5, 0x19, 0x05, 0x19, 0x05, 0x21, 0x25, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x29, 0x46, 
+0x31, 0xA8, 0x29, 0x66, 0x31, 0x87, 0x5A, 0xCC, 
+0x94, 0x50, 0xCE, 0x16, 0xCD, 0xF5, 0xD6, 0x15, 
+0xCD, 0xF5, 0xC5, 0xB4, 0xBD, 0x73, 0xB5, 0x53, 
+0xC5, 0xB4, 0x94, 0x4F, 0xA4, 0xB0, 0xA4, 0xB0, 
+0x94, 0x4E, 0x9C, 0x8F, 0xB5, 0x32, 0x9C, 0x8F, 
+0xAC, 0xF1, 0xC5, 0x92, 0xC5, 0x93, 0xA4, 0xB0, 
+0xA4, 0xB0, 0xA4, 0xD0, 0x9C, 0x8F, 0x9C, 0x8F, 
+0x94, 0x2E, 0x9C, 0x8F, 0xA4, 0xD0, 0xA5, 0x11, 
+0x9C, 0xB0, 0x63, 0x2B, 0x18, 0xA2, 0x39, 0xA6, 
+0x8D, 0x10, 0x8C, 0xEF, 0x63, 0xCA, 0x53, 0x48, 
+0x53, 0x27, 0x5B, 0x67, 0x53, 0x06, 0x42, 0xC6, 
+0x63, 0xC9, 0x7C, 0x8D, 0xAD, 0xD3, 0x8C, 0xD0, 
+0xB5, 0xB4, 0x84, 0x6C, 0x43, 0x03, 0x4B, 0x63, 
+0x6C, 0x27, 0x84, 0x89, 0x94, 0xAC, 0xA5, 0x0F, 
+0x94, 0x8E, 0xA5, 0x10, 0x94, 0x8F, 0x94, 0x6F, 
+0x8C, 0x2E, 0x7B, 0xAC, 0xAD, 0x31, 0xD6, 0x55, 
+0xC5, 0xF3, 0xCE, 0x34, 0xBD, 0x93, 0xA5, 0x11, 
+0xBD, 0xB4, 0x9C, 0x90, 0x8C, 0x2F, 0xB5, 0x52, 
+0xC5, 0xF4, 0xC5, 0xD3, 0xCE, 0x34, 0xB5, 0x30, 
+0xD6, 0x35, 0xAC, 0xCF, 0xAC, 0xEF, 0xC5, 0x91, 
+0xCD, 0xD3, 0xD6, 0x35, 0xD6, 0x55, 0xCE, 0x15, 
+0xCE, 0x35, 0xCE, 0x56, 0xD6, 0x97, 0xC6, 0x37, 
+0xBD, 0xB6, 0x94, 0x71, 0x31, 0x86, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x19, 0x04, 0x7C, 0x30, 
+0xB5, 0xF7, 0xBE, 0x38, 0xC6, 0x38, 0xC6, 0x38, 
+0xC6, 0x58, 0xCE, 0x58, 0xC6, 0x58, 0xC6, 0x38, 
+0xC6, 0x58, 0xC6, 0x37, 0xC5, 0xF6, 0xB5, 0x94, 
+0x7B, 0xAE, 0x31, 0xA6, 0x19, 0x04, 0x21, 0x24, 
+0x73, 0xAD, 0x84, 0x2F, 0x7B, 0xCD, 0x6B, 0x6B, 
+0x63, 0x4B, 0x73, 0x8C, 0x7B, 0xAC, 0x73, 0x8C, 
+0x73, 0x8C, 0x7B, 0xAC, 0x7B, 0xAB, 0x8C, 0x0D, 
+0x8B, 0xEC, 0xB4, 0xF0, 0xAC, 0xEF, 0xC5, 0xB2, 
+0xB5, 0x51, 0x9C, 0x6D, 0x94, 0x4D, 0xA4, 0xF0, 
+0xAD, 0x10, 0xA4, 0xCF, 0x9C, 0x8E, 0x9C, 0x8E, 
+0xAC, 0xF0, 0xA4, 0xCF, 0xB5, 0x30, 0xBD, 0x71, 
+0xBD, 0x30, 0xC5, 0x91, 0xC5, 0x91, 0xAC, 0xEF, 
+0xBD, 0xB2, 0xC5, 0xF4, 0xCE, 0x35, 0x9C, 0xB0, 
+0x52, 0x68, 0x52, 0x8A, 0x52, 0x8A, 0x52, 0x69, 
+0x6B, 0x4D, 0x7B, 0xAE, 0x83, 0xEF, 0x73, 0x8E, 
+0x8C, 0x71, 0xA4, 0xF3, 0xB5, 0x76, 0xBD, 0xB6, 
+0x9C, 0x92, 0xC5, 0xF7, 0xE6, 0xBA, 0xC5, 0xB5, 
+0x9C, 0xB1, 0x94, 0x50, 0x83, 0xEF, 0x8C, 0x51, 
+0x94, 0x51, 0xB5, 0x53, 0xAC, 0xF0, 0xA4, 0x8E, 
+0x9C, 0x4D, 0x9C, 0x6E, 0xA4, 0x8F, 0xB4, 0xF0, 
+0xB5, 0x30, 0xB5, 0x30, 0xBD, 0x51, 0xB4, 0xF0, 
+0xAC, 0xF0, 0xA4, 0xD0, 0xA4, 0x8F, 0xA4, 0x8F, 
+0x9C, 0x4E, 0x94, 0x0D, 0xA4, 0xCF, 0xA4, 0xCF, 
+0x9C, 0x6E, 0x8C, 0x0D, 0x8C, 0x0D, 0x8C, 0x0D, 
+0x7B, 0xAD, 0x7B, 0x8D, 0x94, 0x90, 0xBD, 0xB4, 
+0xA4, 0xF1, 0x8C, 0x2F, 0x83, 0xEE, 0x83, 0xEE, 
+0x83, 0xEE, 0x7B, 0xCE, 0x83, 0xEE, 0x83, 0xEE, 
+0x83, 0xEE, 0x83, 0xEE, 0x83, 0xEE, 0x83, 0xEE, 
+0x8C, 0x2F, 0x73, 0x8D, 0x6B, 0x4C, 0x6B, 0x6C, 
+0x5A, 0xAA, 0x39, 0xC7, 0x42, 0x28, 0x42, 0x07, 
+0x52, 0x89, 0x63, 0x0B, 0x52, 0x8A, 0x52, 0x8A, 
+0x5A, 0xAA, 0x5A, 0x89, 0x62, 0xAA, 0x7B, 0x6D, 
+0x6B, 0x0C, 0x7B, 0x8E, 0x94, 0x50, 0x8B, 0xEF, 
+0x7B, 0x8D, 0xA4, 0xF2, 0x94, 0x70, 0x84, 0x0E, 
+0x9C, 0xB0, 0xBD, 0x93, 0xBD, 0xB4, 0xB5, 0x94, 
+0xAD, 0x52, 0xAD, 0x73, 0xBD, 0xD5, 0xB5, 0x94, 
+0xB5, 0x73, 0xAD, 0x32, 0xB5, 0x73, 0xBD, 0xB4, 
+0xA4, 0xF1, 0xBD, 0x94, 0xB5, 0x53, 0xDE, 0x97, 
+0xCE, 0x36, 0xC5, 0xF5, 0x62, 0xEA, 0x18, 0xC3, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xC3, 0x29, 0x66, 
+0x21, 0x25, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x5A, 0xAA, 
+0xBD, 0xB4, 0xC5, 0xF5, 0xC5, 0xD5, 0xC5, 0xD4, 
+0xBD, 0xB4, 0xA4, 0xF1, 0xAD, 0x32, 0xC6, 0x15, 
+0xC5, 0xF5, 0xA4, 0xF2, 0x29, 0x65, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC3, 0x10, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 0x19, 0x05, 
+0x19, 0x05, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xE4, 0x19, 0x05, 0x19, 0x05, 0x18, 0xE5, 
+0x18, 0xE5, 0x19, 0x05, 0x19, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x05, 0x19, 0x05, 0x18, 0xE4, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 0x18, 0xC4, 
+0x18, 0xE5, 0x21, 0x05, 0x19, 0x05, 0x21, 0x26, 
+0x19, 0x05, 0x19, 0x05, 0x21, 0x26, 0x29, 0x46, 
+0x31, 0xA8, 0x29, 0x46, 0x21, 0x25, 0x42, 0x29, 
+0x7B, 0xAE, 0xCD, 0xF5, 0xD6, 0x35, 0xD5, 0xF5, 
+0xD5, 0xF4, 0xD6, 0x14, 0xC5, 0xB3, 0xC5, 0xB3, 
+0xD5, 0xF5, 0xA4, 0x90, 0x8B, 0xED, 0x8B, 0xED, 
+0xA4, 0xAF, 0xBD, 0x51, 0xBD, 0x52, 0x9C, 0x6F, 
+0xBD, 0x52, 0xD5, 0xF4, 0xDE, 0x55, 0xA4, 0x8F, 
+0xAD, 0x11, 0xB5, 0x53, 0xB5, 0x73, 0xB5, 0x73, 
+0xA5, 0x11, 0xA4, 0xD1, 0xA5, 0x11, 0xA4, 0xF1, 
+0x9C, 0xD0, 0x5A, 0xCA, 0x18, 0xC3, 0x20, 0xE3, 
+0x3A, 0xC5, 0x42, 0xE6, 0x5B, 0xA9, 0x4B, 0x07, 
+0x5B, 0x69, 0x4A, 0xA6, 0x42, 0x86, 0x5B, 0x89, 
+0x6C, 0x0B, 0x8D, 0x0F, 0xA5, 0x93, 0xA5, 0x72, 
+0x6B, 0x8A, 0x8C, 0xED, 0x4B, 0x24, 0x63, 0xE9, 
+0xA5, 0xB2, 0x9D, 0x10, 0x94, 0xAD, 0x9C, 0xEE, 
+0xA5, 0x30, 0xAD, 0x52, 0x9C, 0xF1, 0xA4, 0xF1, 
+0x9C, 0xD1, 0x8C, 0x4E, 0xB5, 0x73, 0xDE, 0xB7, 
+0xCE, 0x14, 0xCE, 0x14, 0xB5, 0x72, 0x9C, 0xB0, 
+0xA5, 0x12, 0x94, 0x90, 0x8C, 0x0F, 0xAD, 0x11, 
+0xA5, 0x11, 0x94, 0x6E, 0xBD, 0xB2, 0xB5, 0x30, 
+0xCE, 0x14, 0xAC, 0xCF, 0xA4, 0x6D, 0x8B, 0xEB, 
+0x94, 0x4D, 0xA4, 0xAE, 0xA4, 0xCF, 0xB5, 0x51, 
+0xBD, 0x93, 0xBD, 0xD4, 0xCE, 0x36, 0xCE, 0x36, 
+0xB5, 0x95, 0x9C, 0xB1, 0x6B, 0x0C, 0x18, 0xE3, 
+0x10, 0xC3, 0x10, 0xA3, 0x18, 0xE4, 0x6B, 0xAE, 
+0xAD, 0x95, 0xB5, 0xF6, 0xBD, 0xF6, 0xBD, 0xF6, 
+0xBD, 0xF6, 0xBD, 0xF6, 0xBD, 0xF6, 0xBD, 0xD6, 
+0xBD, 0xD6, 0xBD, 0xF6, 0xBD, 0xD5, 0xBD, 0xF6, 
+0xBD, 0xD6, 0xAD, 0x33, 0x5A, 0xCA, 0x10, 0xA2, 
+0x52, 0xAA, 0x84, 0x2F, 0x7B, 0xEE, 0x73, 0xAC, 
+0x73, 0xAD, 0x84, 0x0E, 0x83, 0xEE, 0x8C, 0x2F, 
+0x8C, 0x4F, 0x7B, 0xCD, 0x8C, 0x2E, 0x94, 0x6E, 
+0xA4, 0xAF, 0xB4, 0xEF, 0xAC, 0xCF, 0xB5, 0x51, 
+0xBD, 0x92, 0x9C, 0xAF, 0x9C, 0xAF, 0xB5, 0x72, 
+0xC5, 0xF4, 0xCE, 0x14, 0xBD, 0x92, 0xBD, 0xB3, 
+0xBD, 0x93, 0xAD, 0x10, 0xAD, 0x31, 0xB5, 0x51, 
+0xB5, 0x31, 0xD6, 0x35, 0xB5, 0x30, 0xB5, 0x30, 
+0xCE, 0x14, 0xCE, 0x55, 0xD6, 0x76, 0xBD, 0xB3, 
+0x83, 0xEE, 0x4A, 0x48, 0x42, 0x07, 0x39, 0xC7, 
+0x4A, 0x49, 0x52, 0x69, 0x52, 0x69, 0x63, 0x0C, 
+0x7C, 0x10, 0x9C, 0xF3, 0xB5, 0x96, 0xA4, 0xF4, 
+0xBD, 0x96, 0xBD, 0xD7, 0xB5, 0x95, 0xCE, 0x17, 
+0xBD, 0xB6, 0xBD, 0xD7, 0x84, 0x10, 0x84, 0x30, 
+0x94, 0x91, 0x94, 0x70, 0x83, 0xAC, 0x7B, 0xAC, 
+0x6B, 0x0A, 0x6B, 0x2A, 0x5A, 0x88, 0x73, 0x6B, 
+0x7B, 0x8B, 0x8C, 0x2D, 0x94, 0x2D, 0x9C, 0x8E, 
+0xAC, 0xCF, 0x94, 0x2D, 0x8C, 0x0C, 0x94, 0x2D, 
+0x9C, 0x6E, 0xAC, 0xF0, 0x9C, 0x8E, 0xA4, 0xCF, 
+0xAC, 0xCF, 0xAC, 0xF0, 0xAC, 0xF0, 0xB5, 0x52, 
+0xBD, 0x93, 0xBD, 0x74, 0xBD, 0x94, 0xBD, 0xB4, 
+0xBD, 0x94, 0xBD, 0x94, 0xBD, 0xB4, 0xBD, 0x94, 
+0xBD, 0x74, 0xC5, 0xD5, 0xC5, 0xF5, 0xC5, 0xD5, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0x74, 0xC5, 0xD5, 
+0xC5, 0xB4, 0xB5, 0x33, 0xB5, 0x74, 0xB5, 0x74, 
+0xAD, 0x12, 0x83, 0xCE, 0x42, 0x27, 0x42, 0x28, 
+0x4A, 0x48, 0x52, 0x89, 0x5A, 0x89, 0x83, 0xCE, 
+0x7B, 0x6D, 0x52, 0x28, 0x7B, 0x8D, 0x9C, 0x71, 
+0x8B, 0xEF, 0xA4, 0xB2, 0x7B, 0x6D, 0x73, 0x0C, 
+0x7B, 0x8E, 0x7B, 0x8E, 0xA4, 0xF2, 0xA4, 0xF2, 
+0xA4, 0xF2, 0xBD, 0x93, 0xC5, 0xD4, 0xD6, 0x97, 
+0xCE, 0x16, 0xC6, 0x15, 0xD6, 0x77, 0xAD, 0x32, 
+0xC5, 0xF5, 0xC5, 0xF5, 0xC5, 0xF5, 0xC5, 0xF4, 
+0x94, 0x6F, 0xBD, 0xB4, 0xB5, 0x32, 0xDE, 0xB7, 
+0xDE, 0xB7, 0xCE, 0x15, 0x73, 0x6C, 0x18, 0xC3, 
+0x10, 0x83, 0x10, 0x82, 0x10, 0xC3, 0x29, 0x86, 
+0x21, 0x05, 0x19, 0x04, 0x19, 0x04, 0x18, 0xE4, 
+0x18, 0xC3, 0x10, 0xA3, 0x10, 0xC3, 0x84, 0x0F, 
+0xCE, 0x56, 0xCE, 0x35, 0xCE, 0x15, 0xCE, 0x35, 
+0xCE, 0x15, 0xAD, 0x11, 0xB5, 0x52, 0xD6, 0x76, 
+0xDE, 0x97, 0xD6, 0x77, 0x83, 0xCE, 0x20, 0xE4, 
+0x10, 0xC3, 0x10, 0xC3, 0x18, 0xC4, 0x10, 0xC4, 
+0x18, 0xC4, 0x18, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE5, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x18, 0xE5, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xC4, 0x18, 0xE4, 0x19, 0x05, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 
+0x19, 0x05, 0x18, 0xE5, 0x19, 0x05, 0x18, 0xE4, 
+0x18, 0xC4, 0x10, 0xA4, 0x10, 0xA3, 0x18, 0xE4, 
+0x19, 0x05, 0x21, 0x26, 0x18, 0xE5, 0x21, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x29, 0x46, 0x29, 0x46, 
+0x31, 0x87, 0x29, 0x67, 0x21, 0x46, 0x31, 0x87, 
+0x5A, 0xCC, 0xB5, 0x32, 0xE6, 0x76, 0xDE, 0x35, 
+0xDE, 0x35, 0xDE, 0x35, 0xD6, 0x14, 0xDE, 0x35, 
+0xDE, 0x35, 0xBD, 0x52, 0xC5, 0xB3, 0xCD, 0xD4, 
+0xCD, 0xB3, 0xD5, 0xF3, 0xCD, 0xB3, 0xD5, 0xD3, 
+0xDE, 0x14, 0xDE, 0x34, 0xDE, 0x34, 0xA4, 0x8F, 
+0xAC, 0xF1, 0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0xD5, 
+0xBD, 0xB4, 0xB5, 0x73, 0xB5, 0x53, 0xAD, 0x32, 
+0xAD, 0x32, 0x8C, 0x4F, 0x21, 0x04, 0x10, 0xA2, 
+0x3A, 0x85, 0x53, 0x88, 0x4B, 0x07, 0x4A, 0xE7, 
+0x4A, 0xE7, 0x4A, 0x86, 0x5B, 0x08, 0x5B, 0x28, 
+0x74, 0x0B, 0x7C, 0x6D, 0x8C, 0xAE, 0xA5, 0x30, 
+0x5B, 0x28, 0x8C, 0xCD, 0x8C, 0xED, 0xC6, 0xD6, 
+0xD7, 0x39, 0xAD, 0x93, 0x94, 0x8D, 0xAD, 0x2F, 
+0xAD, 0x0F, 0x9C, 0xAE, 0x94, 0x4E, 0x94, 0x4E, 
+0x9C, 0x8F, 0x9C, 0xAF, 0x9C, 0xAF, 0xB5, 0x31, 
+0x9C, 0x8E, 0xAD, 0x10, 0x9C, 0x8E, 0x94, 0x4E, 
+0x9C, 0xAF, 0x94, 0x4E, 0x8C, 0x2E, 0x9C, 0x8F, 
+0xBD, 0x73, 0xAD, 0x10, 0xAC, 0xCF, 0x94, 0x4D, 
+0xA4, 0xAF, 0x9C, 0x6D, 0xBD, 0x51, 0xB5, 0x30, 
+0x94, 0x4D, 0xA4, 0xF0, 0xB5, 0x72, 0xB5, 0x72, 
+0xBD, 0xB3, 0xB5, 0x52, 0xCE, 0x35, 0xD6, 0x77, 
+0xCE, 0x57, 0xA5, 0x12, 0x73, 0x6C, 0x10, 0xA2, 
+0x19, 0x04, 0x21, 0x25, 0x18, 0xE4, 0x3A, 0x28, 
+0x8C, 0x91, 0xA5, 0x54, 0xA5, 0x54, 0xAD, 0x74, 
+0xAD, 0x74, 0xAD, 0x74, 0xB5, 0x94, 0xB5, 0xB5, 
+0xAD, 0x74, 0xB5, 0x94, 0xAD, 0x94, 0xB5, 0xB4, 
+0xBD, 0xD5, 0xA4, 0xF2, 0x31, 0x85, 0x10, 0x82, 
+0x31, 0xA6, 0x8C, 0x50, 0x8C, 0x4F, 0x73, 0xCD, 
+0x73, 0xAD, 0x84, 0x2F, 0x94, 0x6F, 0x8C, 0x90, 
+0xAD, 0x53, 0x94, 0x90, 0x9C, 0xB0, 0x9C, 0xAF, 
+0xA4, 0xEF, 0xAC, 0xCF, 0xAC, 0xCF, 0x9C, 0x8E, 
+0xAD, 0x10, 0x94, 0x6E, 0xAD, 0x11, 0xC5, 0xD4, 
+0xBD, 0x93, 0xBD, 0xB3, 0xBD, 0x93, 0xB5, 0x52, 
+0xAD, 0x31, 0x94, 0x6E, 0xAD, 0x51, 0xB5, 0x52, 
+0xB5, 0x72, 0xCE, 0x35, 0xA4, 0xCE, 0xB5, 0x30, 
+0xCE, 0x14, 0xCE, 0x34, 0xC5, 0xF4, 0xAD, 0x32, 
+0xB5, 0x53, 0x5A, 0xA9, 0x4A, 0x08, 0x42, 0x08, 
+0x4A, 0x49, 0x52, 0x69, 0x52, 0x8A, 0x52, 0xAA, 
+0x6B, 0x6D, 0x73, 0x8E, 0x7B, 0xCF, 0xAD, 0x55, 
+0xCE, 0x18, 0x84, 0x10, 0xAD, 0x34, 0xCE, 0x39, 
+0xCE, 0x38, 0xCE, 0x59, 0xA4, 0xF3, 0x94, 0x71, 
+0x9C, 0xD2, 0x8C, 0x2F, 0x8C, 0x2F, 0x9C, 0xB1, 
+0x8C, 0x0E, 0x84, 0x0E, 0x7B, 0xAD, 0x94, 0x90, 
+0x7B, 0xAC, 0x52, 0x68, 0x73, 0x6B, 0x94, 0x4F, 
+0x8C, 0x4E, 0x83, 0xED, 0x84, 0x0D, 0x83, 0xED, 
+0x7B, 0xAC, 0x83, 0xED, 0x83, 0xEC, 0x94, 0x4E, 
+0x94, 0x4E, 0xA4, 0xD0, 0xAD, 0x11, 0xC5, 0xF5, 
+0xCE, 0x15, 0xC5, 0xF4, 0xC5, 0xF5, 0xCE, 0x36, 
+0xCE, 0x15, 0xBD, 0x93, 0xB5, 0x53, 0xAD, 0x32, 
+0xB5, 0x52, 0xB5, 0x53, 0xAD, 0x12, 0xAD, 0x32, 
+0xAD, 0x32, 0xB5, 0x52, 0xBD, 0x73, 0xB5, 0x53, 
+0xC5, 0xB4, 0xC5, 0xD5, 0xC5, 0xB4, 0xC5, 0xB4, 
+0xC5, 0xD5, 0xAD, 0x12, 0x8B, 0xEE, 0x4A, 0x48, 
+0x42, 0x27, 0x4A, 0x28, 0x7B, 0x8D, 0x8C, 0x2F, 
+0x94, 0x0F, 0x5A, 0x69, 0x83, 0xCE, 0xAD, 0x13, 
+0x94, 0x50, 0xA4, 0xD2, 0x8C, 0x0F, 0x6B, 0x0B, 
+0x8B, 0xEF, 0x8C, 0x10, 0x8C, 0x0F, 0xA4, 0xB2, 
+0xB5, 0x33, 0xBD, 0x94, 0xA4, 0xD1, 0xA4, 0xD0, 
+0x9C, 0xB0, 0xA4, 0xB0, 0xA4, 0xD0, 0x94, 0x6F, 
+0xA4, 0xB0, 0x9C, 0xB0, 0x9C, 0x90, 0x9C, 0xD0, 
+0xAD, 0x32, 0xB5, 0x73, 0xAD, 0x11, 0xC5, 0xF5, 
+0xCE, 0x36, 0xCE, 0x15, 0x6B, 0x2B, 0x18, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x18, 0xC3, 0x29, 0x86, 
+0x19, 0x04, 0x19, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x10, 0xC3, 0x18, 0xC3, 0x41, 0xE7, 0xAD, 0x53, 
+0xCE, 0x35, 0xD6, 0x76, 0xD6, 0x56, 0xCE, 0x36, 
+0xBD, 0xB3, 0xB5, 0x52, 0xAD, 0x11, 0xCE, 0x35, 
+0xB5, 0x73, 0xD6, 0x56, 0xBD, 0x94, 0x5A, 0xCA, 
+0x18, 0xE4, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x05, 0x18, 0xE4, 0x18, 0xE5, 0x18, 0xE4, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x18, 0xE4, 
+0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE5, 0x18, 0xE5, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x18, 0xE4, 
+0x19, 0x05, 0x21, 0x05, 0x18, 0xE5, 0x19, 0x05, 
+0x19, 0x05, 0x21, 0x05, 0x29, 0x46, 0x29, 0x46, 
+0x31, 0x87, 0x29, 0x87, 0x29, 0x87, 0x21, 0x46, 
+0x4A, 0x4A, 0x7B, 0xAE, 0xE6, 0x97, 0xEE, 0xD7, 
+0xE6, 0x96, 0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x75, 
+0xDE, 0x55, 0xDE, 0x35, 0xD5, 0xF4, 0xDE, 0x55, 
+0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x55, 0xEE, 0x96, 
+0xE6, 0x75, 0xE6, 0x55, 0xDE, 0x14, 0xAC, 0xD0, 
+0xAD, 0x11, 0xB5, 0x93, 0xBD, 0xD5, 0xBD, 0xB4, 
+0xC6, 0x16, 0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x53, 
+0xAD, 0x53, 0xAD, 0x12, 0x6B, 0x2B, 0x18, 0xA2, 
+0x7C, 0x8E, 0x63, 0xAA, 0x3A, 0x65, 0x32, 0x05, 
+0x4A, 0xA7, 0x63, 0x4A, 0x6B, 0xAB, 0x63, 0x8A, 
+0x52, 0xC8, 0x5B, 0x09, 0x63, 0x4A, 0x84, 0x0C, 
+0x63, 0x68, 0x5B, 0x88, 0x63, 0xC9, 0x84, 0xAF, 
+0x73, 0xEC, 0x8C, 0x4D, 0x94, 0x6D, 0x9C, 0x6E, 
+0xA4, 0xAE, 0xA4, 0xAF, 0xB5, 0x10, 0xAC, 0xEF, 
+0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x31, 0xB5, 0x10, 
+0xA4, 0xAE, 0xB5, 0x10, 0xAC, 0xF0, 0xB5, 0x10, 
+0xB5, 0x30, 0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xF0, 
+0xB5, 0x31, 0xB5, 0x30, 0xB5, 0x10, 0xAC, 0xEF, 
+0xAC, 0xEF, 0xB4, 0xEF, 0xB5, 0x0F, 0xB4, 0xEF, 
+0xAC, 0xCF, 0xA4, 0xAF, 0x94, 0x4D, 0x8C, 0x0C, 
+0x9C, 0x6E, 0xA4, 0xCF, 0xAD, 0x10, 0xB5, 0x51, 
+0xBD, 0x72, 0xB5, 0x31, 0x9C, 0x6F, 0x29, 0x45, 
+0x10, 0xA3, 0x42, 0x49, 0x42, 0x28, 0x18, 0xE3, 
+0x52, 0xCB, 0x8C, 0x91, 0x94, 0xD1, 0x9C, 0xD1, 
+0x9C, 0xD1, 0xA4, 0xF2, 0xA5, 0x12, 0xAD, 0x33, 
+0xA5, 0x33, 0xA5, 0x32, 0xA5, 0x12, 0x94, 0xB1, 
+0x63, 0x2B, 0x18, 0xE3, 0x10, 0x82, 0x10, 0xA3, 
+0x21, 0x04, 0xAD, 0x54, 0xA5, 0x33, 0x8C, 0x4F, 
+0x8C, 0x4F, 0xA5, 0x33, 0xAD, 0x53, 0x9D, 0x12, 
+0xB5, 0x94, 0xAD, 0x53, 0xA4, 0xF1, 0xA4, 0xD0, 
+0xAC, 0xF0, 0xAC, 0xCE, 0xAC, 0xCE, 0x9C, 0x8E, 
+0x9C, 0xCF, 0x83, 0xED, 0xB5, 0x72, 0xB5, 0x93, 
+0xBD, 0x92, 0xBD, 0xB3, 0xBD, 0xD3, 0xA5, 0x10, 
+0xB5, 0x52, 0x7B, 0xAC, 0x94, 0x8F, 0x94, 0x8F, 
+0x8C, 0x4E, 0xC5, 0xB3, 0xA4, 0x8E, 0xBD, 0x50, 
+0xCD, 0xF3, 0xCE, 0x14, 0xAD, 0x31, 0xC5, 0xD4, 
+0xC5, 0xB4, 0x8C, 0x2F, 0x52, 0x69, 0x52, 0x69, 
+0x4A, 0x49, 0x52, 0x69, 0x52, 0x8A, 0x63, 0x0C, 
+0x6B, 0x4D, 0x6B, 0x6D, 0x73, 0x8E, 0x8C, 0x72, 
+0x9C, 0xF3, 0xA4, 0xF3, 0xC5, 0xF8, 0xD6, 0x7A, 
+0xD6, 0x79, 0xAD, 0x14, 0xA4, 0xD3, 0xC5, 0xF7, 
+0x8C, 0x30, 0x9C, 0xB1, 0xA4, 0xF2, 0xA4, 0xF2, 
+0xAD, 0x12, 0xAD, 0x53, 0xA5, 0x12, 0x9C, 0xB1, 
+0x6B, 0x2B, 0x63, 0x0B, 0x73, 0xAD, 0x73, 0x8C, 
+0x6B, 0x4B, 0x7B, 0xAC, 0x84, 0x0D, 0x8C, 0x4F, 
+0x94, 0x6F, 0x8C, 0x2E, 0x8C, 0x4F, 0x84, 0x0E, 
+0x83, 0xED, 0x94, 0x6F, 0xB5, 0x32, 0xB5, 0x72, 
+0xBD, 0x93, 0xBD, 0x93, 0xB5, 0x52, 0xB5, 0x73, 
+0xBD, 0xB4, 0xA4, 0xF1, 0x94, 0x4F, 0x8C, 0x2F, 
+0x83, 0xED, 0x8C, 0x2E, 0x83, 0xEE, 0x7B, 0xAD, 
+0x7B, 0x8D, 0x7B, 0xAD, 0x7B, 0x8C, 0x83, 0xEE, 
+0x84, 0x0E, 0x9C, 0x90, 0xB5, 0x73, 0xC5, 0xD5, 
+0xCE, 0x15, 0xAC, 0xF2, 0xB5, 0x33, 0x7B, 0xAD, 
+0x42, 0x07, 0x41, 0xE7, 0x6B, 0x2B, 0x83, 0xCD, 
+0xAC, 0xF2, 0x8B, 0xEE, 0x7B, 0x8D, 0x6B, 0x0B, 
+0x7B, 0x8D, 0x83, 0xCF, 0x62, 0xAA, 0x6B, 0x2C, 
+0x8B, 0xEF, 0x94, 0x30, 0x94, 0x30, 0x6A, 0xEB, 
+0x7B, 0x6D, 0x83, 0xAE, 0xA4, 0xB1, 0xAD, 0x12, 
+0xB5, 0x53, 0xBD, 0x73, 0xBD, 0x73, 0xBD, 0x73, 
+0xAD, 0x12, 0xB5, 0x52, 0xAD, 0x32, 0xB5, 0x32, 
+0xBD, 0x73, 0xBD, 0x94, 0xB5, 0x52, 0xAC, 0xF1, 
+0xA4, 0xD0, 0xAC, 0xF1, 0x52, 0x48, 0x18, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x18, 0xE4, 0x31, 0x87, 
+0x19, 0x04, 0x19, 0x04, 0x18, 0xE4, 0x18, 0xC4, 
+0x18, 0xC3, 0x18, 0xE4, 0x6B, 0x6D, 0xC5, 0xF5, 
+0xC5, 0xB3, 0xB5, 0x52, 0xAC, 0xF1, 0xCE, 0x15, 
+0xC5, 0xF4, 0xB5, 0x72, 0xAC, 0xF1, 0xC5, 0xD4, 
+0xCD, 0xF5, 0xD6, 0x76, 0xD6, 0x56, 0xB5, 0x33, 
+0x39, 0xA6, 0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x18, 0xE5, 
+0x18, 0xE4, 0x18, 0xE5, 0x19, 0x05, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x18, 0xE4, 
+0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x05, 0x18, 0xE5, 0x18, 0xE5, 0x19, 0x05, 
+0x18, 0xE5, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xA4, 
+0x10, 0x83, 0x08, 0x83, 0x10, 0xA4, 0x18, 0xE4, 
+0x18, 0xE5, 0x19, 0x05, 0x19, 0x05, 0x21, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x21, 0x26, 0x29, 0x46, 
+0x31, 0x87, 0x31, 0x87, 0x31, 0xA8, 0x31, 0xC8, 
+0x39, 0xE8, 0x4A, 0x4A, 0x8C, 0x30, 0xD6, 0x56, 
+0xEE, 0xD7, 0xEE, 0xD6, 0xE6, 0x95, 0xEE, 0x96, 
+0xE6, 0x55, 0xDE, 0x55, 0xCD, 0xF3, 0xDE, 0x54, 
+0xEE, 0x95, 0xEE, 0x95, 0xEE, 0xB6, 0xEE, 0x96, 
+0xE6, 0x75, 0xE6, 0x55, 0xDE, 0x14, 0xAC, 0xD0, 
+0xA4, 0xF1, 0xB5, 0x73, 0xC5, 0xD4, 0xBD, 0xB4, 
+0xCE, 0x16, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x74, 0xC5, 0xD4, 0xCE, 0x57, 0x5A, 0xAA, 
+0x95, 0x31, 0x5B, 0x2A, 0x29, 0x83, 0x52, 0xE9, 
+0x5B, 0x2A, 0x5B, 0x2A, 0x63, 0x4A, 0x6B, 0xCC, 
+0x6B, 0xAC, 0x6B, 0xAB, 0x42, 0x67, 0x7B, 0xED, 
+0x63, 0x49, 0x4B, 0x07, 0x53, 0x08, 0x4A, 0xA8, 
+0x52, 0xE9, 0x7B, 0xED, 0x84, 0x0D, 0x8C, 0x2E, 
+0x9C, 0x8F, 0x9C, 0xB0, 0x7B, 0xAB, 0x94, 0x6E, 
+0xAC, 0xCF, 0xA4, 0xAF, 0xAC, 0xF0, 0xA4, 0xAF, 
+0x9C, 0x8E, 0xAC, 0xEF, 0x9C, 0x4D, 0x8B, 0xEB, 
+0x9C, 0x4D, 0x94, 0x0C, 0xA4, 0xCE, 0x94, 0x2D, 
+0x9C, 0x4D, 0xA4, 0x8E, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xA4, 0xAE, 0xAC, 0xCE, 0xBD, 0x50, 0xB5, 0x30, 
+0xB5, 0x30, 0xB5, 0x30, 0xBD, 0x30, 0xBD, 0x30, 
+0xBD, 0x30, 0xB5, 0x30, 0xBD, 0x50, 0xBD, 0x30, 
+0xB5, 0x30, 0xBD, 0x50, 0xC5, 0x72, 0x8B, 0xEE, 
+0x42, 0x07, 0x18, 0xC3, 0x39, 0xE7, 0x21, 0x04, 
+0x18, 0xE3, 0x4A, 0x89, 0x6B, 0xAD, 0x73, 0xCD, 
+0x7B, 0xED, 0x84, 0x0E, 0x8C, 0x4F, 0x8C, 0x4F, 
+0x8C, 0x6F, 0x8C, 0x4F, 0x7B, 0xAD, 0x39, 0xC6, 
+0x10, 0x82, 0x10, 0xA2, 0x10, 0xA2, 0x10, 0xA3, 
+0x18, 0xC3, 0xA5, 0x33, 0xD6, 0xB8, 0xB5, 0xB4, 
+0xAD, 0x73, 0xC6, 0x36, 0xCE, 0x56, 0xBD, 0xF5, 
+0xBD, 0xF5, 0xB5, 0x94, 0xA4, 0xF1, 0xAD, 0x11, 
+0xA4, 0xCF, 0xAC, 0xEF, 0xAC, 0xEF, 0x9C, 0x6E, 
+0x83, 0xEC, 0x6B, 0x6A, 0x9C, 0xD0, 0xC5, 0xD4, 
+0xC5, 0xF4, 0xBD, 0xB3, 0xBD, 0xB3, 0xA4, 0xF0, 
+0xAD, 0x52, 0x83, 0xCD, 0x8C, 0x2E, 0x84, 0x0D, 
+0x7B, 0xAC, 0xAC, 0xF0, 0xA4, 0x6D, 0xBD, 0x30, 
+0xC5, 0xF3, 0xCD, 0xF4, 0xB5, 0x92, 0xC5, 0xD4, 
+0xCE, 0x36, 0x9C, 0x70, 0x41, 0xE7, 0x52, 0x69, 
+0x52, 0x69, 0x52, 0x89, 0x63, 0x0C, 0x73, 0xAE, 
+0x73, 0x8E, 0x4A, 0x49, 0x6B, 0x4D, 0x8C, 0x72, 
+0x9C, 0xF3, 0xBD, 0xB7, 0xC6, 0x18, 0xCE, 0x59, 
+0xAD, 0x14, 0x83, 0xF0, 0xC5, 0xB6, 0xCD, 0xF7, 
+0x73, 0x4D, 0x9C, 0xB1, 0x6B, 0x0B, 0x62, 0xCA, 
+0x8C, 0x2F, 0xB5, 0x94, 0xB5, 0x74, 0x6B, 0x6C, 
+0x5A, 0xEA, 0x7B, 0xEE, 0x8C, 0x50, 0x84, 0x0E, 
+0x7B, 0xCD, 0x83, 0xEE, 0x94, 0x70, 0xA4, 0xF1, 
+0xAD, 0x33, 0xA4, 0xF2, 0x9C, 0xD1, 0x94, 0x6F, 
+0x83, 0xCD, 0x94, 0x4E, 0xB5, 0x52, 0xB5, 0x72, 
+0xBD, 0x93, 0xB5, 0x72, 0xAD, 0x12, 0x8C, 0x2F, 
+0x84, 0x0E, 0x84, 0x0E, 0x8C, 0x4F, 0x9C, 0xB0, 
+0xA4, 0xD1, 0x9C, 0xB1, 0xB5, 0x74, 0xAD, 0x33, 
+0xAD, 0x33, 0xAD, 0x53, 0xB5, 0x94, 0xA4, 0xF1, 
+0xA4, 0xD1, 0xB5, 0x53, 0xBD, 0xB4, 0xAD, 0x32, 
+0xAD, 0x11, 0xAC, 0xF2, 0xB5, 0x33, 0x94, 0x4F, 
+0x7B, 0xCD, 0x4A, 0x47, 0x41, 0xE6, 0x52, 0x68, 
+0x83, 0xCD, 0xB5, 0x33, 0xAC, 0xF2, 0x7B, 0x8D, 
+0x7B, 0x6D, 0x8C, 0x10, 0x73, 0x2C, 0x83, 0xCE, 
+0x9C, 0x71, 0xA4, 0xB2, 0x8B, 0xEF, 0x83, 0xAE, 
+0x94, 0x30, 0x94, 0x30, 0x8C, 0x0F, 0x9C, 0x90, 
+0xC5, 0xF5, 0xBD, 0x94, 0xB5, 0x32, 0xC5, 0xB4, 
+0xCD, 0xF5, 0xDE, 0x97, 0xCD, 0xF5, 0xCE, 0x15, 
+0xC5, 0xD4, 0xBD, 0x53, 0xB5, 0x32, 0xAD, 0x32, 
+0xAD, 0x11, 0xAC, 0xF1, 0x41, 0xA6, 0x18, 0xA3, 
+0x10, 0x83, 0x10, 0x82, 0x19, 0x04, 0x31, 0xA7, 
+0x21, 0x04, 0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC3, 
+0x18, 0xE4, 0x39, 0xA7, 0xA4, 0xF2, 0xAD, 0x32, 
+0xB5, 0x11, 0xAD, 0x11, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xAD, 0x10, 0xAD, 0x11, 0xAC, 0xF1, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xAC, 0xF0, 0xB5, 0x11, 
+0x62, 0xCA, 0x21, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x19, 0x04, 0x19, 0x05, 0x19, 0x05, 
+0x19, 0x04, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x04, 0x19, 0x05, 0x19, 0x05, 
+0x19, 0x04, 0x18, 0xE4, 0x19, 0x04, 0x18, 0xE4, 
+0x18, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x05, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xA4, 
+0x10, 0x83, 0x08, 0x83, 0x10, 0xC4, 0x18, 0xE4, 
+0x19, 0x05, 0x21, 0x25, 0x21, 0x05, 0x21, 0x26, 
+0x18, 0xE5, 0x19, 0x05, 0x21, 0x46, 0x29, 0x66, 
+0x31, 0xA7, 0x31, 0xA8, 0x31, 0xC8, 0x39, 0xE9, 
+0x31, 0xA8, 0x31, 0xC8, 0x4A, 0x2A, 0x7B, 0x8D, 
+0xB5, 0x32, 0xDE, 0x35, 0xE6, 0x75, 0xE6, 0x75, 
+0xE6, 0x75, 0xE6, 0x95, 0xD6, 0x14, 0xE6, 0x55, 
+0xEE, 0xB6, 0xEE, 0xB6, 0xEE, 0xD6, 0xEE, 0xB6, 
+0xE6, 0x95, 0xE6, 0x75, 0xD5, 0xF3, 0xAC, 0xF0, 
+0xAD, 0x32, 0xAD, 0x52, 0xBD, 0x94, 0xB5, 0x53, 
+0xC5, 0xF5, 0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x94, 
+0xBD, 0x94, 0xC5, 0xF5, 0xCE, 0x36, 0x9C, 0xB1, 
+0x31, 0xE5, 0x42, 0x87, 0x52, 0xE8, 0x6B, 0xCC, 
+0x6B, 0xAC, 0x63, 0x8C, 0x6B, 0xAC, 0x6B, 0x8C, 
+0x73, 0xED, 0x6B, 0x8B, 0x3A, 0x46, 0x7C, 0x4E, 
+0x5B, 0x08, 0x4A, 0xE7, 0x5B, 0x4B, 0x4A, 0xA9, 
+0x52, 0xC9, 0x84, 0x2E, 0x8C, 0x4F, 0x94, 0x90, 
+0xA5, 0x12, 0xA5, 0x32, 0x9C, 0xD1, 0xAD, 0x31, 
+0xA4, 0xCF, 0xAD, 0x31, 0xC5, 0xD4, 0xAD, 0x31, 
+0xAD, 0x31, 0xBD, 0x93, 0xBD, 0x93, 0xA4, 0xD0, 
+0xA4, 0xF0, 0xA4, 0xF0, 0xAC, 0xF0, 0xA4, 0xAF, 
+0xA4, 0xCF, 0xB5, 0x51, 0xBD, 0x72, 0xBD, 0x92, 
+0xAC, 0xCF, 0xB5, 0x10, 0x7B, 0x6A, 0x8B, 0xEC, 
+0x94, 0x2D, 0x9C, 0x8E, 0xC5, 0x92, 0xAC, 0xCF, 
+0xBD, 0x30, 0xCD, 0xD3, 0xB5, 0x10, 0xBD, 0x30, 
+0x94, 0x2C, 0x94, 0x2C, 0x9C, 0x2D, 0xA4, 0x6E, 
+0x9C, 0x6F, 0x7B, 0x8C, 0x42, 0x07, 0x18, 0xE3, 
+0x18, 0xE4, 0x19, 0x04, 0x29, 0x65, 0x42, 0x27, 
+0x52, 0xA9, 0x62, 0xEA, 0x63, 0x2A, 0x6B, 0x6B, 
+0x6B, 0x4B, 0x4A, 0x27, 0x18, 0xC2, 0x10, 0x82, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA2, 0x10, 0xA3, 
+0x10, 0xA3, 0x73, 0x8D, 0xAD, 0x32, 0xAC, 0xF0, 
+0xA4, 0xCF, 0xAD, 0x10, 0xAC, 0xF0, 0xA4, 0xAF, 
+0x94, 0x4E, 0x9C, 0x6E, 0x9C, 0x8E, 0xAD, 0x31, 
+0x9C, 0x8E, 0xB4, 0xEF, 0xC5, 0x91, 0xBD, 0x51, 
+0x94, 0x2D, 0x83, 0xCC, 0x73, 0x6B, 0xAD, 0x11, 
+0xBD, 0x93, 0xBD, 0x92, 0xB5, 0x72, 0x8C, 0x2D, 
+0x94, 0x6E, 0x83, 0xED, 0x8C, 0x2E, 0x9C, 0xD0, 
+0xAD, 0x52, 0xA4, 0xAF, 0xA4, 0x8E, 0xAC, 0xEF, 
+0xC5, 0xB2, 0xC5, 0xF3, 0xBD, 0xD3, 0xC5, 0xF4, 
+0xD6, 0x56, 0xC5, 0xD5, 0x4A, 0x27, 0x52, 0x89, 
+0x5A, 0xCA, 0x73, 0x8E, 0x8C, 0x10, 0x62, 0xCB, 
+0x52, 0x8A, 0x6B, 0x4D, 0x7B, 0xCF, 0x8C, 0x31, 
+0xA4, 0xF4, 0xBD, 0xD7, 0xB5, 0x55, 0x7B, 0xAF, 
+0x7B, 0x8E, 0xB5, 0x34, 0xBD, 0x95, 0x8C, 0x0F, 
+0x62, 0xAA, 0x62, 0xAA, 0x29, 0x24, 0x20, 0xE4, 
+0x5A, 0xEB, 0xB5, 0x95, 0xB5, 0x74, 0x94, 0xB1, 
+0x94, 0x91, 0x8C, 0x2F, 0x7B, 0xCE, 0x84, 0x0E, 
+0x84, 0x0F, 0x8C, 0x4F, 0xAD, 0x33, 0xB5, 0x73, 
+0xAD, 0x53, 0xA5, 0x32, 0xA5, 0x12, 0x94, 0x90, 
+0x84, 0x0E, 0x94, 0x4F, 0xB5, 0x53, 0xB5, 0x73, 
+0xA4, 0xD1, 0x94, 0x4F, 0x8C, 0x2E, 0x6B, 0x6C, 
+0x84, 0x2E, 0xAD, 0x33, 0x9C, 0xD1, 0x9C, 0x90, 
+0xAD, 0x12, 0x9C, 0xB1, 0xAD, 0x53, 0xAD, 0x32, 
+0xAD, 0x12, 0xA5, 0x12, 0xBD, 0xB4, 0xA4, 0xF1, 
+0x94, 0x90, 0xA4, 0xF1, 0xA4, 0xD1, 0x9C, 0xB0, 
+0x94, 0x6F, 0xAD, 0x12, 0xAD, 0x32, 0x8C, 0x2E, 
+0x9C, 0x90, 0x94, 0x6F, 0x5A, 0x88, 0x31, 0x65, 
+0x41, 0xC6, 0x73, 0x2B, 0xA4, 0xD1, 0x83, 0xCE, 
+0x62, 0xA9, 0x83, 0xCE, 0x8B, 0xEF, 0x7B, 0x4C, 
+0x8C, 0x0F, 0x8C, 0x0F, 0x73, 0x2C, 0x8C, 0x0F, 
+0x9C, 0x71, 0x8B, 0xEF, 0x73, 0x2C, 0x7B, 0x8D, 
+0x94, 0x2F, 0x9C, 0x91, 0xB5, 0x33, 0xBD, 0x74, 
+0xB5, 0x53, 0xC5, 0xF5, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xBD, 0x73, 0xBD, 0x73, 0xBD, 0x93, 0xC5, 0x93, 
+0xC5, 0xD4, 0x8B, 0xEE, 0x29, 0x25, 0x10, 0x82, 
+0x10, 0x82, 0x18, 0xC4, 0x21, 0x25, 0x31, 0x86, 
+0x19, 0x04, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC3, 
+0x18, 0xC3, 0x4A, 0x49, 0xB5, 0x74, 0xAC, 0xD0, 
+0xC5, 0xB3, 0xBD, 0x72, 0xB5, 0x31, 0xB5, 0x31, 
+0xB5, 0x31, 0xAD, 0x11, 0xA4, 0xD0, 0xBD, 0x52, 
+0xBD, 0x72, 0xCD, 0xF4, 0xD6, 0x15, 0xD6, 0x35, 
+0x9C, 0x6F, 0x41, 0xE7, 0x18, 0xC4, 0x18, 0xE5, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 
+0x18, 0xE4, 0x19, 0x04, 0x18, 0xE4, 0x19, 0x05, 
+0x19, 0x04, 0x18, 0xE4, 0x19, 0x04, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x04, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xA3, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x08, 0x83, 0x08, 0x83, 0x10, 0xC4, 0x18, 0xE4, 
+0x19, 0x05, 0x21, 0x05, 0x18, 0xE5, 0x21, 0x26, 
+0x18, 0xE5, 0x21, 0x06, 0x29, 0x46, 0x31, 0x87, 
+0x31, 0xA8, 0x31, 0xA8, 0x31, 0xC8, 0x39, 0xC8, 
+0x29, 0x67, 0x31, 0xC8, 0x42, 0x0A, 0x4A, 0x6A, 
+0x63, 0x0C, 0xAC, 0xF1, 0xDE, 0x54, 0xEE, 0x95, 
+0xE6, 0x95, 0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x75, 
+0xE6, 0x75, 0xE6, 0x54, 0xEE, 0x95, 0xEE, 0xB6, 
+0xEE, 0x95, 0xEE, 0x95, 0xCD, 0x93, 0xB5, 0x11, 
+0xA4, 0xF1, 0xAD, 0x12, 0xBD, 0x94, 0xAD, 0x32, 
+0xBD, 0xB4, 0xAD, 0x53, 0xB5, 0x53, 0xB5, 0x73, 
+0xBD, 0xB4, 0xB5, 0x93, 0xC5, 0xF5, 0xBD, 0xB4, 
+0x32, 0x06, 0x21, 0x62, 0x29, 0xC4, 0x42, 0x67, 
+0x4A, 0xC9, 0x73, 0xED, 0x7C, 0x0E, 0x7C, 0x0E, 
+0x7C, 0x2E, 0x73, 0xAC, 0x3A, 0x25, 0x6B, 0xCC, 
+0x7C, 0x4E, 0x95, 0x11, 0x94, 0xF2, 0x73, 0xCE, 
+0x5B, 0x0B, 0x84, 0x2F, 0x8C, 0x90, 0xA5, 0x33, 
+0xC6, 0x16, 0xAD, 0x53, 0xAD, 0x54, 0xB5, 0x53, 
+0xAC, 0xD0, 0xBD, 0x93, 0xDE, 0x97, 0xC5, 0xF4, 
+0xB5, 0x52, 0xAD, 0x11, 0xA4, 0xD0, 0xAD, 0x31, 
+0xC5, 0xD4, 0xC5, 0xB3, 0xCD, 0xD4, 0xCD, 0xD4, 
+0xC5, 0xB3, 0xCD, 0xF4, 0xC5, 0xD3, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xC5, 0xB3, 0x9C, 0x8E, 0xA4, 0xF1, 
+0xA4, 0xAF, 0x9C, 0xAF, 0xC5, 0xD3, 0x9C, 0x4D, 
+0xBD, 0x30, 0xD6, 0x15, 0xDE, 0x76, 0xDE, 0x55, 
+0xA4, 0xD0, 0xB5, 0x31, 0xB5, 0x52, 0xB5, 0x52, 
+0xB5, 0x11, 0x9C, 0x8F, 0x94, 0x4F, 0x7B, 0x8D, 
+0x18, 0xE3, 0x10, 0xC3, 0x19, 0x04, 0x29, 0x65, 
+0x39, 0xC7, 0x39, 0xE6, 0x31, 0xC6, 0x31, 0x85, 
+0x18, 0xC2, 0x10, 0x82, 0x10, 0x82, 0x10, 0xA2, 
+0x10, 0x82, 0x08, 0x82, 0x10, 0xA2, 0x10, 0xA3, 
+0x10, 0xA3, 0x52, 0x69, 0xA4, 0xB0, 0xA4, 0x8E, 
+0xA4, 0x8E, 0xA4, 0xAE, 0xA4, 0xAE, 0xAC, 0xCF, 
+0xAC, 0xEF, 0xAC, 0xEF, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xBD, 0x30, 0xBD, 0x51, 0xBD, 0x51, 0xBD, 0x51, 
+0xBD, 0x51, 0xBD, 0x51, 0xBD, 0x31, 0xB5, 0x10, 
+0xB5, 0x10, 0xB5, 0x10, 0xAC, 0xCF, 0xA4, 0xAF, 
+0xB5, 0x10, 0xB5, 0x10, 0xBD, 0x31, 0xB5, 0x30, 
+0xBD, 0x71, 0xBD, 0x30, 0xB5, 0x10, 0xA4, 0x8D, 
+0xAC, 0xCE, 0xBD, 0x72, 0xAD, 0x31, 0xC5, 0xD4, 
+0xB5, 0x52, 0xA4, 0xD1, 0x94, 0x4F, 0x7B, 0x8D, 
+0x6B, 0x2C, 0x73, 0x4D, 0x63, 0x0C, 0x52, 0x6A, 
+0x7B, 0x8E, 0x83, 0xF0, 0x94, 0x72, 0xAD, 0x76, 
+0xCE, 0x39, 0x9C, 0xD3, 0x5A, 0x8B, 0x62, 0xCB, 
+0x94, 0x51, 0xAD, 0x14, 0x9C, 0xB2, 0x6A, 0xEB, 
+0x5A, 0x69, 0x49, 0xE7, 0x29, 0x24, 0x41, 0xE7, 
+0x9C, 0xD2, 0xAD, 0x33, 0xB5, 0x74, 0x94, 0xB1, 
+0x94, 0xB1, 0x9C, 0xD2, 0x84, 0x0E, 0x83, 0xEE, 
+0x94, 0x70, 0x94, 0x90, 0xB5, 0x53, 0xA5, 0x12, 
+0xAD, 0x32, 0xB5, 0x94, 0xAD, 0x53, 0x9C, 0xD1, 
+0x8C, 0x2E, 0x94, 0x6F, 0xBD, 0x94, 0xA4, 0xB0, 
+0x63, 0x0A, 0x6B, 0x4B, 0x73, 0x6C, 0x7B, 0xCD, 
+0x83, 0xED, 0x9C, 0xF1, 0xC5, 0xF5, 0xA4, 0xF1, 
+0x94, 0x6F, 0x9C, 0x90, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xA4, 0xF2, 0x9C, 0xD1, 0x9C, 0x90, 0x94, 0x90, 
+0x9C, 0xD1, 0xA4, 0xD1, 0x8C, 0x2F, 0x73, 0x6C, 
+0x8C, 0x0E, 0xAD, 0x12, 0xB5, 0x53, 0xA4, 0xD0, 
+0x9C, 0x8F, 0x9C, 0xD0, 0x94, 0x6F, 0x5A, 0xC9, 
+0x39, 0xA6, 0x39, 0xA5, 0x62, 0xC9, 0x8B, 0xEE, 
+0x73, 0x2C, 0x52, 0x48, 0x52, 0x48, 0x73, 0x4C, 
+0x6A, 0xEB, 0x7B, 0x4D, 0x73, 0x0C, 0x94, 0x10, 
+0x7B, 0x4C, 0x7B, 0x6D, 0x8B, 0xEF, 0x73, 0x0C, 
+0x6A, 0xEB, 0x6A, 0xEB, 0x8C, 0x0F, 0xB5, 0x54, 
+0xAD, 0x13, 0xAD, 0x13, 0xB5, 0x53, 0xAD, 0x32, 
+0xAD, 0x32, 0xA4, 0xB0, 0x8C, 0x0D, 0x94, 0x4E, 
+0x8C, 0x0E, 0x4A, 0x07, 0x31, 0x65, 0x21, 0x04, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 0x21, 0x25, 
+0x18, 0xE4, 0x18, 0xC3, 0x18, 0xE4, 0x18, 0xC3, 
+0x31, 0xA6, 0x8C, 0x2F, 0xB5, 0x32, 0xB5, 0x31, 
+0xCD, 0xF4, 0xC5, 0xB3, 0xB5, 0x32, 0xB5, 0x52, 
+0xAC, 0xF1, 0xA4, 0x8F, 0x83, 0xAC, 0x9C, 0x6E, 
+0xA4, 0xAF, 0xB5, 0x31, 0xBD, 0x52, 0xBD, 0x51, 
+0xAD, 0x11, 0x7B, 0x8D, 0x29, 0x45, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 0x19, 0x05, 
+0x21, 0x25, 0x21, 0x25, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x04, 0x18, 0xE4, 0x18, 0xC4, 0x18, 0xE4, 
+0x19, 0x05, 0x19, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x10, 0xA3, 0x10, 0xA3, 0x18, 0xE4, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xC4, 0x10, 0xC4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x08, 0x83, 0x10, 0x83, 0x10, 0xC4, 0x18, 0xE4, 
+0x18, 0xE5, 0x19, 0x05, 0x18, 0xE5, 0x21, 0x26, 
+0x18, 0xE5, 0x21, 0x46, 0x29, 0x47, 0x31, 0xA8, 
+0x31, 0x88, 0x31, 0x87, 0x31, 0xA8, 0x31, 0xA8, 
+0x31, 0xA8, 0x42, 0x2A, 0x42, 0x09, 0x42, 0x09, 
+0x4A, 0x4A, 0x73, 0x6D, 0xA4, 0x90, 0xA4, 0x8F, 
+0xB5, 0x10, 0xBD, 0x51, 0xC5, 0x92, 0xCD, 0xD3, 
+0xD5, 0xD3, 0xD5, 0xD3, 0xD5, 0xD3, 0xD5, 0xD3, 
+0xDE, 0x34, 0xB4, 0xF0, 0x83, 0x8B, 0xA4, 0xF1, 
+0x8C, 0x2E, 0x94, 0x4E, 0x9C, 0xB0, 0x9C, 0xD0, 
+0x9C, 0xD0, 0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x32, 
+0xAD, 0x32, 0xA4, 0xF1, 0x9C, 0xAF, 0xAD, 0x11, 
+0x4A, 0x88, 0x73, 0xCD, 0x5B, 0x2A, 0x84, 0x4F, 
+0x84, 0x4F, 0x7C, 0x0E, 0x8C, 0x90, 0x8C, 0x91, 
+0x8C, 0x90, 0x8C, 0x6E, 0x3A, 0x25, 0x53, 0x09, 
+0x63, 0x8B, 0x84, 0x6F, 0x84, 0x4F, 0x73, 0xAD, 
+0x6B, 0x8D, 0x8C, 0x91, 0xA5, 0x33, 0xB5, 0x94, 
+0xC6, 0x37, 0xAD, 0x74, 0xAD, 0x94, 0xAD, 0x52, 
+0xA4, 0xD0, 0xAD, 0x31, 0xCE, 0x36, 0xBD, 0xB3, 
+0xB5, 0x73, 0x8C, 0x2E, 0x6B, 0x2B, 0xCE, 0x15, 
+0xD6, 0x56, 0xCD, 0xF4, 0xCD, 0xF3, 0xCD, 0xD4, 
+0xD6, 0x14, 0xD6, 0x14, 0xCD, 0xF4, 0xCD, 0xF4, 
+0xCD, 0xF4, 0xCD, 0xF4, 0xBD, 0x92, 0xBD, 0x93, 
+0xBD, 0x93, 0xAD, 0x31, 0xB5, 0x51, 0x9C, 0x6E, 
+0xBD, 0x51, 0xCD, 0xD3, 0xDE, 0x55, 0xD6, 0x15, 
+0xC5, 0xB3, 0xC5, 0xF5, 0xCE, 0x15, 0xC5, 0xF4, 
+0xA4, 0xD1, 0x8B, 0xED, 0x62, 0xCA, 0x5A, 0xCA, 
+0x21, 0x24, 0x10, 0xA3, 0x08, 0x82, 0x10, 0xA3, 
+0x31, 0x86, 0x3A, 0x08, 0x39, 0xC7, 0x18, 0xC3, 
+0x08, 0x62, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 
+0x10, 0x82, 0x08, 0x82, 0x10, 0xA2, 0x10, 0xA2, 
+0x10, 0xA3, 0x31, 0x86, 0x84, 0x0E, 0x7B, 0xAC, 
+0x7B, 0x6B, 0x73, 0x6A, 0x73, 0x4A, 0x7B, 0x8A, 
+0x7B, 0x6A, 0x73, 0x29, 0x73, 0x29, 0x7B, 0x8A, 
+0x83, 0xCB, 0x9C, 0x4D, 0x8B, 0xEB, 0xA4, 0x8E, 
+0xA4, 0xAE, 0xAC, 0xCF, 0xAC, 0xCF, 0xC5, 0x91, 
+0xB5, 0x0F, 0xAC, 0xCE, 0xB5, 0x0F, 0xB4, 0xEF, 
+0xB5, 0x30, 0xB5, 0x10, 0xB5, 0x0F, 0xB4, 0xEF, 
+0xB5, 0x0F, 0xBD, 0x10, 0xAC, 0xCE, 0xB4, 0xEF, 
+0xA4, 0xAE, 0xBD, 0x93, 0xAD, 0x32, 0x8C, 0x0E, 
+0x83, 0x8B, 0x83, 0xCC, 0xA4, 0x90, 0x8C, 0x0F, 
+0x7B, 0x8D, 0x5A, 0xAA, 0x62, 0xCB, 0x62, 0xCB, 
+0x8C, 0x51, 0xA5, 0x14, 0xB5, 0x96, 0xAD, 0x76, 
+0x7B, 0xCF, 0x42, 0x29, 0x6B, 0x2D, 0x6B, 0x2D, 
+0x73, 0x8E, 0xAD, 0x14, 0x8C, 0x30, 0x52, 0x28, 
+0x52, 0x28, 0x4A, 0x28, 0x52, 0x28, 0x6A, 0xEA, 
+0x62, 0xEB, 0x8C, 0x4F, 0x9C, 0xB1, 0x94, 0x70, 
+0x73, 0x8C, 0x9C, 0xD1, 0x9C, 0xB1, 0x9C, 0xD1, 
+0xAD, 0x12, 0xA4, 0xD2, 0xAD, 0x53, 0xB5, 0x73, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x73, 0xAD, 0x32, 
+0x9C, 0xD0, 0x8C, 0x4F, 0xBD, 0xB4, 0xBD, 0x73, 
+0x94, 0x4F, 0x8C, 0x2F, 0x84, 0x0E, 0x8C, 0x2F, 
+0x73, 0xAC, 0x84, 0x0E, 0x9C, 0xD1, 0x84, 0x0E, 
+0x73, 0x6B, 0x94, 0x6F, 0x7B, 0xCD, 0x94, 0x90, 
+0x9C, 0xD1, 0xA5, 0x12, 0x8C, 0x2F, 0x94, 0x4F, 
+0x8C, 0x2F, 0x8C, 0x4F, 0x8C, 0x4F, 0x73, 0x8D, 
+0x8C, 0x2F, 0xB5, 0x52, 0xB5, 0x53, 0xAD, 0x32, 
+0xAD, 0x31, 0x94, 0x6F, 0x9C, 0x90, 0x94, 0x6F, 
+0x63, 0x0A, 0x4A, 0x28, 0x42, 0x07, 0x6B, 0x2B, 
+0x5A, 0xAA, 0x4A, 0x28, 0x41, 0xE7, 0x62, 0xCA, 
+0x83, 0xAE, 0x8B, 0xCF, 0x73, 0x0C, 0x6A, 0xEB, 
+0x83, 0xCF, 0x83, 0xCE, 0x9C, 0x92, 0x7B, 0x6D, 
+0x94, 0x50, 0x83, 0xCE, 0x94, 0x30, 0x9C, 0x71, 
+0x94, 0x30, 0x8B, 0xEE, 0x94, 0x30, 0x83, 0xCE, 
+0x94, 0x2F, 0x39, 0xA6, 0x18, 0xC3, 0x18, 0xA2, 
+0x18, 0xE3, 0x41, 0xE7, 0x31, 0x66, 0x20, 0xE4, 
+0x10, 0xC3, 0x10, 0x83, 0x10, 0xA3, 0x18, 0xE4, 
+0x18, 0xC4, 0x18, 0xC3, 0x18, 0xE4, 0x21, 0x04, 
+0x94, 0x70, 0xB5, 0x73, 0xAD, 0x11, 0xB5, 0x32, 
+0xBD, 0x93, 0xBD, 0x93, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xC5, 0xB3, 0xC5, 0xD4, 0xAC, 0xD0, 0xBD, 0x73, 
+0xC5, 0xD4, 0xC5, 0x93, 0xBD, 0x52, 0xBD, 0x93, 
+0xB5, 0x72, 0x94, 0x4F, 0x5A, 0x8A, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x25, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x04, 0x19, 0x04, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x21, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x18, 0xE4, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xC3, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x10, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x19, 0x05, 0x19, 0x05, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x46, 0x29, 0x46, 0x29, 0x87, 
+0x21, 0x46, 0x29, 0x67, 0x29, 0x87, 0x31, 0x87, 
+0x39, 0xE9, 0x3A, 0x09, 0x39, 0xC8, 0x31, 0xC8, 
+0x42, 0x09, 0x52, 0xCC, 0x84, 0x0F, 0xB5, 0x32, 
+0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x32, 0xB5, 0x32, 
+0xB5, 0x12, 0xAC, 0xF1, 0xAC, 0xF1, 0xB5, 0x11, 
+0xAD, 0x11, 0xA4, 0xB0, 0xAD, 0x32, 0xBD, 0x93, 
+0xB5, 0x32, 0xA4, 0xF1, 0xA4, 0xD1, 0x9C, 0x90, 
+0x9C, 0x90, 0x94, 0x6F, 0x8C, 0x2E, 0x94, 0x4F, 
+0x8C, 0x2E, 0x8C, 0x0E, 0x83, 0xED, 0x83, 0xED, 
+0x8C, 0xB0, 0x94, 0xB1, 0x6B, 0x6C, 0x8C, 0xB0, 
+0x7C, 0x2F, 0x94, 0xB1, 0xB5, 0xF6, 0xAD, 0x94, 
+0x9C, 0xD1, 0x52, 0x87, 0x42, 0x26, 0x63, 0x8B, 
+0x74, 0x2E, 0x84, 0x90, 0x8C, 0xB0, 0x84, 0x50, 
+0x84, 0x2F, 0x9C, 0xF2, 0xAD, 0x74, 0xAD, 0x74, 
+0xC6, 0x57, 0xB5, 0xB5, 0xAD, 0x74, 0x9C, 0xD0, 
+0xAC, 0xF0, 0xB5, 0x52, 0xC5, 0xD4, 0xBD, 0x93, 
+0xB5, 0x52, 0xB5, 0x73, 0xB5, 0x52, 0xCE, 0x15, 
+0xDE, 0x76, 0xD6, 0x15, 0xCE, 0x14, 0xCE, 0x14, 
+0xDE, 0x76, 0xD6, 0x35, 0xCE, 0x14, 0xCD, 0xF4, 
+0xCD, 0xF4, 0xD6, 0x55, 0xD6, 0x15, 0xCD, 0xF4, 
+0xCE, 0x14, 0xBD, 0xB3, 0xAD, 0x11, 0x9C, 0x8E, 
+0xBD, 0x51, 0xA4, 0xAE, 0xBD, 0x92, 0xC5, 0xB3, 
+0xC5, 0xD4, 0xD6, 0x56, 0xD6, 0x76, 0xD6, 0x36, 
+0xA4, 0xB1, 0x8C, 0x2F, 0x73, 0x6C, 0x4A, 0x08, 
+0x18, 0xE4, 0x10, 0xC3, 0x19, 0x04, 0x29, 0x86, 
+0x31, 0xC8, 0x31, 0xC8, 0x39, 0xE8, 0x4A, 0x6A, 
+0x29, 0x46, 0x08, 0x62, 0x08, 0x62, 0x08, 0x82, 
+0x08, 0x82, 0x08, 0x82, 0x08, 0x82, 0x08, 0x82, 
+0x10, 0xA3, 0x21, 0x25, 0xAD, 0x53, 0xB5, 0x53, 
+0xB5, 0x53, 0xAD, 0x32, 0x9C, 0xB0, 0x9C, 0xB0, 
+0xA4, 0xF1, 0xA4, 0xD1, 0x94, 0x6F, 0x8C, 0x2E, 
+0x94, 0x6E, 0x94, 0x4E, 0x8B, 0xED, 0x9C, 0xAF, 
+0xAD, 0x11, 0xA4, 0xAF, 0x8C, 0x0D, 0xAC, 0xEF, 
+0x9C, 0x4D, 0xA4, 0x6D, 0xA4, 0x6D, 0xA4, 0x8E, 
+0xBD, 0x51, 0xAD, 0x11, 0xAC, 0xD0, 0x7B, 0x8B, 
+0x73, 0x2A, 0x7B, 0x8B, 0x8C, 0x0C, 0x9C, 0x6E, 
+0x83, 0xCD, 0xAD, 0x13, 0xA4, 0xF2, 0x73, 0x4C, 
+0x73, 0x4B, 0xA4, 0x90, 0x9C, 0x4F, 0x6A, 0xCA, 
+0x6B, 0x2C, 0x7B, 0xAE, 0xA4, 0xF3, 0x94, 0x72, 
+0x7B, 0xAE, 0x52, 0x8A, 0x39, 0xA7, 0x4A, 0x6A, 
+0x62, 0xEC, 0x73, 0x6E, 0x63, 0x0C, 0x6B, 0x0C, 
+0x7B, 0x8E, 0x83, 0xEF, 0x73, 0x2C, 0x6B, 0x2C, 
+0x5A, 0x89, 0x31, 0x44, 0x29, 0x44, 0x39, 0x85, 
+0x62, 0xEB, 0x9C, 0x91, 0x94, 0x50, 0x94, 0x50, 
+0x8C, 0x2E, 0x94, 0x0D, 0x94, 0x0D, 0x94, 0x4E, 
+0x9C, 0x8E, 0x9C, 0x8F, 0xA4, 0x8F, 0xA4, 0xD0, 
+0xB5, 0x11, 0xAD, 0x11, 0xAD, 0x11, 0xAC, 0xF1, 
+0xAD, 0x11, 0x94, 0x4E, 0xA4, 0xD0, 0xAD, 0x12, 
+0xAD, 0x32, 0x9C, 0x90, 0x7B, 0xAD, 0x7B, 0x8C, 
+0x7B, 0xCD, 0x83, 0xEE, 0x83, 0xEE, 0x8C, 0x4F, 
+0x94, 0x6F, 0xA4, 0xF1, 0x9C, 0xB0, 0x8C, 0x2E, 
+0x83, 0xED, 0x83, 0xEE, 0x73, 0x8C, 0x83, 0xEE, 
+0x8C, 0x0E, 0x94, 0x70, 0x94, 0x70, 0x9C, 0xB1, 
+0x9C, 0x90, 0xAC, 0xF1, 0xB5, 0x52, 0xB5, 0x32, 
+0xC5, 0xD4, 0xB5, 0x52, 0xBD, 0x93, 0xC5, 0xF4, 
+0xBD, 0x93, 0x8C, 0x2E, 0x41, 0xE6, 0x41, 0xE6, 
+0x41, 0xE7, 0x41, 0xE7, 0x42, 0x07, 0x41, 0xE7, 
+0xA5, 0x14, 0xBD, 0x96, 0x94, 0x71, 0x62, 0xCB, 
+0x62, 0xEB, 0x6A, 0xEB, 0x83, 0xCF, 0x73, 0x2C, 
+0x94, 0x30, 0x6A, 0xEB, 0x8B, 0xEF, 0xAC, 0xD2, 
+0x94, 0x30, 0x83, 0x8D, 0x52, 0x49, 0x4A, 0x07, 
+0x6B, 0x0B, 0x73, 0x4D, 0x83, 0xEF, 0x62, 0xEB, 
+0x29, 0x24, 0x31, 0x86, 0x21, 0x04, 0x18, 0xC3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x18, 0xE4, 0x18, 0xC3, 0x18, 0xE4, 0x29, 0x65, 
+0xAD, 0x53, 0xC5, 0xD4, 0xAC, 0xF1, 0xBD, 0x73, 
+0xC5, 0xD4, 0xC5, 0xB3, 0xC5, 0xD4, 0xCD, 0xF4, 
+0xCD, 0xF4, 0xCD, 0xD4, 0xBD, 0x73, 0xCD, 0xF4, 
+0xD6, 0x36, 0xCE, 0x15, 0xCD, 0xF5, 0xCD, 0xF5, 
+0xCE, 0x15, 0xB5, 0x32, 0x83, 0xEE, 0x29, 0x65, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 0x18, 0xE4, 
+0x18, 0xE4, 0x21, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x04, 0x19, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x04, 0x18, 0xE5, 
+0x18, 0xE4, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA3, 0x10, 0xA3, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC4, 
+0x18, 0xE4, 0x19, 0x05, 0x19, 0x05, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x46, 0x21, 0x26, 
+0x18, 0xE5, 0x29, 0x46, 0x29, 0x67, 0x29, 0x87, 
+0x31, 0xC8, 0x39, 0xC9, 0x39, 0xC8, 0x39, 0xE9, 
+0x42, 0x2A, 0x3A, 0x09, 0x42, 0x49, 0xA4, 0xF2, 
+0xCE, 0x16, 0xBD, 0x73, 0xBD, 0x93, 0xA4, 0xB0, 
+0xAC, 0xF1, 0xCD, 0xD4, 0xBD, 0x52, 0x9C, 0x8F, 
+0x83, 0xCD, 0x7B, 0xAC, 0x94, 0x2E, 0xAD, 0x11, 
+0xB5, 0x52, 0x9C, 0x6F, 0xA4, 0xF1, 0xAD, 0x12, 
+0xA4, 0xD1, 0x9C, 0x6F, 0x9C, 0xAF, 0xAD, 0x11, 
+0xAD, 0x11, 0xAD, 0x32, 0xB5, 0x52, 0xB5, 0x52, 
+0x9D, 0x53, 0x8C, 0xB0, 0x5A, 0xC9, 0x73, 0xAD, 
+0x7C, 0x2E, 0xC6, 0x37, 0xB5, 0xD6, 0x7C, 0x2F, 
+0x5A, 0xEA, 0x63, 0x0A, 0x52, 0x87, 0x31, 0xE4, 
+0x3A, 0x46, 0x63, 0x8C, 0x94, 0xF1, 0x9C, 0xF2, 
+0x9D, 0x13, 0xA5, 0x54, 0xBD, 0xF6, 0xBD, 0xD5, 
+0xC6, 0x16, 0xBD, 0xD5, 0xA5, 0x33, 0xA4, 0xF1, 
+0xAD, 0x10, 0xB5, 0x52, 0xAD, 0x11, 0xBD, 0x93, 
+0xBD, 0xB3, 0xBD, 0xD4, 0xC5, 0xD4, 0xCE, 0x35, 
+0xD6, 0x56, 0xC5, 0xF4, 0xD6, 0x35, 0xD6, 0x15, 
+0xD6, 0x56, 0xCD, 0xD4, 0xC5, 0xD4, 0xD6, 0x35, 
+0xDE, 0x56, 0xDE, 0x56, 0xBD, 0x52, 0xCE, 0x15, 
+0xBD, 0xB3, 0xBD, 0xB3, 0xAD, 0x32, 0x9C, 0x4E, 
+0xBD, 0x30, 0xAC, 0xCF, 0xC5, 0x93, 0xCD, 0xF4, 
+0xCE, 0x35, 0xD6, 0x77, 0xD6, 0x77, 0x8C, 0x0E, 
+0x8B, 0xEF, 0x8C, 0x10, 0x62, 0xCB, 0x39, 0xA7, 
+0x42, 0x08, 0x39, 0xE8, 0x29, 0x86, 0x31, 0xA7, 
+0x29, 0x66, 0x29, 0x86, 0x21, 0x45, 0x42, 0x29, 
+0x63, 0x0D, 0x29, 0x45, 0x10, 0xA3, 0x08, 0x62, 
+0x08, 0x82, 0x08, 0x82, 0x08, 0x82, 0x10, 0xA2, 
+0x18, 0xC3, 0x21, 0x24, 0xBD, 0xF6, 0xCE, 0x36, 
+0xCE, 0x16, 0xAD, 0x53, 0xAD, 0x32, 0xCE, 0x36, 
+0xCE, 0x57, 0xCE, 0x36, 0xC5, 0xF5, 0xBD, 0x94, 
+0xAD, 0x52, 0xAD, 0x11, 0xAD, 0x32, 0xB5, 0x93, 
+0xB5, 0x73, 0xA4, 0xF1, 0x8C, 0x0D, 0xA4, 0xCF, 
+0xAC, 0xAE, 0xAC, 0xCF, 0xC5, 0xB2, 0xC5, 0xB2, 
+0xBD, 0xB3, 0xBD, 0xD4, 0xB5, 0x93, 0x9C, 0xF1, 
+0x94, 0x6F, 0x8C, 0x4F, 0x94, 0x90, 0x83, 0xEE, 
+0x41, 0xE7, 0x5A, 0x8A, 0x5A, 0xAA, 0x5A, 0xCB, 
+0x5A, 0xAA, 0x8B, 0xEE, 0x83, 0xAD, 0x5A, 0x89, 
+0x62, 0xAA, 0x5A, 0x69, 0x62, 0xEB, 0xA4, 0xF4, 
+0x7B, 0xCF, 0x5A, 0xAB, 0x42, 0x08, 0x39, 0xC7, 
+0x62, 0xEC, 0x8C, 0x10, 0x5A, 0xAA, 0x83, 0xAF, 
+0x73, 0x6D, 0x7B, 0xAE, 0x63, 0x0B, 0x52, 0x69, 
+0x4A, 0x48, 0x39, 0x85, 0x29, 0x24, 0x39, 0x85, 
+0x62, 0xEB, 0x83, 0xEF, 0x8C, 0x30, 0x7B, 0x8D, 
+0xAC, 0xF1, 0xBD, 0x31, 0xBD, 0x31, 0xBD, 0x51, 
+0xBD, 0x51, 0xB5, 0x31, 0xB5, 0x10, 0xBD, 0x10, 
+0xBD, 0x31, 0xBD, 0x31, 0xBD, 0x31, 0xBD, 0x10, 
+0xBD, 0x31, 0xB5, 0x10, 0xB5, 0x11, 0xB5, 0x32, 
+0xAD, 0x12, 0xAD, 0x11, 0xB5, 0x53, 0xB5, 0x73, 
+0xB5, 0x33, 0xAC, 0xF1, 0xA4, 0xD1, 0xA4, 0xD1, 
+0x9C, 0x8F, 0x9C, 0x90, 0x9C, 0x90, 0x9C, 0x70, 
+0x94, 0x4F, 0x94, 0x4F, 0x8C, 0x2E, 0x8C, 0x2F, 
+0x8C, 0x2F, 0x8C, 0x2E, 0x8C, 0x2F, 0x94, 0x4F, 
+0x94, 0x4F, 0xAD, 0x11, 0xB5, 0x32, 0xB5, 0x31, 
+0xB5, 0x52, 0xCD, 0xF4, 0xC5, 0xF4, 0xBD, 0xB3, 
+0xC5, 0xD4, 0xBD, 0x93, 0x83, 0xAC, 0x31, 0x85, 
+0x31, 0x65, 0x39, 0xA6, 0x31, 0x85, 0x42, 0x08, 
+0x94, 0x92, 0x7B, 0xCF, 0x7B, 0xCF, 0x7B, 0xCF, 
+0xB5, 0x96, 0x83, 0xF0, 0x62, 0xEB, 0x5A, 0x8A, 
+0x7B, 0x6D, 0x5A, 0x69, 0x7B, 0x4D, 0x93, 0xEF, 
+0x7B, 0x2C, 0x8B, 0xCE, 0x62, 0xCB, 0x62, 0xCB, 
+0x73, 0x2C, 0x6B, 0x0C, 0x83, 0xCF, 0x9C, 0x71, 
+0x8C, 0x30, 0x4A, 0x08, 0x20, 0xE4, 0x18, 0xC4, 
+0x10, 0xC4, 0x18, 0xC4, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xC3, 0x42, 0x08, 
+0xC5, 0xD5, 0xCD, 0xF5, 0xAC, 0xD0, 0xC5, 0x93, 
+0xDE, 0x35, 0xD6, 0x14, 0xD5, 0xF4, 0xD5, 0xF4, 
+0xD6, 0x14, 0xD6, 0x35, 0xCD, 0xB3, 0xD5, 0xF5, 
+0xCD, 0xF4, 0xCD, 0xD4, 0xC5, 0x93, 0xBD, 0x92, 
+0xAC, 0xF0, 0xC5, 0xB4, 0xAD, 0x12, 0x5A, 0xCA, 
+0x29, 0x45, 0x18, 0xE4, 0x19, 0x05, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x19, 0x05, 0x18, 0xE4, 0x18, 0xE4, 
+0x19, 0x04, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x10, 0xA3, 0x10, 0xC4, 0x10, 0xC4, 
+0x18, 0xE4, 0x19, 0x05, 0x21, 0x05, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x19, 0x05, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x46, 0x29, 0x67, 
+0x31, 0x87, 0x39, 0xC8, 0x39, 0xE9, 0x39, 0xE9, 
+0x31, 0xA8, 0x31, 0x88, 0x31, 0x87, 0x6B, 0x4C, 
+0xC5, 0xD5, 0xC5, 0xB4, 0xBD, 0x94, 0xA4, 0xF1, 
+0xA4, 0xB0, 0xB5, 0x32, 0xBD, 0x72, 0xBD, 0x93, 
+0xD6, 0x36, 0xD6, 0x56, 0xAD, 0x32, 0x9C, 0x8F, 
+0xA4, 0xB0, 0xBD, 0x93, 0xCD, 0xF4, 0xBD, 0x93, 
+0x94, 0x6F, 0x8C, 0x0E, 0x8B, 0xED, 0xBD, 0x93, 
+0xBD, 0x92, 0xB5, 0x11, 0xB5, 0x31, 0xAD, 0x11, 
+0xBD, 0xF5, 0xBD, 0xD5, 0x73, 0x8C, 0x6B, 0x4B, 
+0x52, 0xC8, 0x7C, 0x4E, 0x5B, 0x29, 0x7B, 0xEC, 
+0x9C, 0xD1, 0xAD, 0x73, 0xA5, 0x52, 0x84, 0x2D, 
+0x84, 0x2C, 0x7B, 0xEB, 0x84, 0x0D, 0x94, 0xB0, 
+0x8C, 0x6F, 0x94, 0x90, 0x9C, 0xB0, 0xAD, 0x32, 
+0xB5, 0x93, 0xB5, 0x94, 0xA4, 0xF2, 0x9C, 0x8F, 
+0xAC, 0xCF, 0x9C, 0x8F, 0x94, 0x6F, 0xA4, 0xF0, 
+0xAD, 0x11, 0x94, 0x6F, 0x83, 0xED, 0xBD, 0x93, 
+0xC5, 0xD4, 0xBD, 0xB4, 0xBD, 0x93, 0x9C, 0xB0, 
+0xB5, 0x52, 0xBD, 0x93, 0xBD, 0x93, 0xCD, 0xF4, 
+0xCE, 0x15, 0xDE, 0x76, 0xCE, 0x15, 0xCE, 0x15, 
+0xD6, 0x56, 0xCE, 0x36, 0xCE, 0x36, 0xAC, 0xCF, 
+0xB4, 0xEF, 0xC5, 0x71, 0xB5, 0x31, 0xB5, 0x52, 
+0xD6, 0x56, 0xDE, 0x97, 0xC5, 0xF5, 0x8C, 0x0F, 
+0xAC, 0xF3, 0x83, 0xAF, 0x73, 0x4D, 0x83, 0xEF, 
+0x6B, 0x2D, 0x5A, 0xEC, 0x3A, 0x08, 0x31, 0xA7, 
+0x31, 0xC7, 0x42, 0x29, 0x29, 0x86, 0x18, 0xE4, 
+0x52, 0x8B, 0x5A, 0xCC, 0x4A, 0x6A, 0x21, 0x25, 
+0x18, 0xE4, 0x08, 0x82, 0x08, 0x82, 0x10, 0xA2, 
+0x18, 0xC3, 0x21, 0x25, 0xBD, 0xF6, 0xCE, 0x36, 
+0xCE, 0x15, 0xD6, 0x57, 0xD6, 0x77, 0xD6, 0x56, 
+0xD6, 0x76, 0xCE, 0x35, 0xBD, 0xD4, 0xBD, 0xB4, 
+0xBD, 0x94, 0xAD, 0x52, 0xB5, 0x94, 0xBD, 0xB4, 
+0xC5, 0xF5, 0xAD, 0x52, 0x9C, 0xB0, 0x9C, 0x8E, 
+0xAC, 0xCF, 0x8C, 0x0C, 0xC5, 0x92, 0xAC, 0xAE, 
+0x9C, 0x6F, 0x9C, 0xB0, 0x7B, 0xAC, 0x8C, 0x2E, 
+0x94, 0x70, 0x8C, 0x4F, 0x9C, 0xD2, 0xBD, 0xD6, 
+0x9C, 0xD3, 0x94, 0x92, 0x9C, 0x92, 0xAD, 0x14, 
+0x94, 0x30, 0x8C, 0x2F, 0x4A, 0x28, 0x5A, 0x8A, 
+0x62, 0xEB, 0x5A, 0xAA, 0x5A, 0xAA, 0x6B, 0x2C, 
+0x7B, 0xCF, 0x8C, 0x10, 0x83, 0xAF, 0x52, 0x69, 
+0x4A, 0x28, 0x5A, 0x8A, 0x63, 0x0B, 0x73, 0x8D, 
+0x7B, 0xAE, 0x8C, 0x30, 0x52, 0x69, 0x52, 0x69, 
+0x41, 0xE7, 0x29, 0x03, 0x31, 0x85, 0x4A, 0x28, 
+0x39, 0xA6, 0x5A, 0xAA, 0x7B, 0x8E, 0x52, 0x69, 
+0x52, 0x89, 0x62, 0xC9, 0x73, 0x4B, 0x8C, 0x0D, 
+0xAD, 0x11, 0xB5, 0x32, 0xBD, 0x52, 0xBD, 0x72, 
+0xCD, 0xD4, 0xC5, 0xD3, 0xC5, 0x92, 0xDE, 0x55, 
+0xD6, 0x35, 0xD6, 0x35, 0xD6, 0x35, 0x9C, 0x8F, 
+0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x33, 0xB5, 0x33, 
+0xAD, 0x12, 0xB5, 0x52, 0xBD, 0x73, 0xC5, 0x93, 
+0xBD, 0x53, 0xB5, 0x32, 0xB5, 0x53, 0xB5, 0x53, 
+0xBD, 0x53, 0xBD, 0x73, 0xBD, 0x73, 0xBD, 0x73, 
+0xBD, 0x93, 0xBD, 0x53, 0xB5, 0x32, 0xBD, 0x73, 
+0xBD, 0x94, 0xC5, 0xB4, 0xCD, 0xD5, 0xBD, 0x73, 
+0xB5, 0x31, 0xAC, 0xF1, 0xAC, 0xF0, 0xB5, 0x31, 
+0xB5, 0x52, 0xA4, 0x90, 0x7B, 0x6C, 0x31, 0x65, 
+0x42, 0x07, 0x31, 0x85, 0x29, 0x44, 0x29, 0x45, 
+0x4A, 0x49, 0x4A, 0x8A, 0x3A, 0x08, 0x52, 0xAA, 
+0x94, 0x72, 0x9C, 0x92, 0x94, 0x92, 0x8C, 0x51, 
+0x52, 0x49, 0x52, 0x49, 0x5A, 0x8A, 0x52, 0x28, 
+0x52, 0x28, 0x8B, 0xEF, 0x62, 0xCB, 0x83, 0xCE, 
+0x7B, 0x8E, 0x62, 0xAB, 0x7B, 0x6D, 0x94, 0x30, 
+0x8C, 0x30, 0x83, 0xAE, 0x39, 0x87, 0x18, 0xC4, 
+0x18, 0xE4, 0x19, 0x04, 0x18, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC3, 0x21, 0x24, 0x94, 0x70, 
+0xD6, 0x56, 0xCD, 0xF4, 0xAC, 0xD0, 0xC5, 0x93, 
+0xD6, 0x14, 0xD6, 0x14, 0xE6, 0x76, 0xDE, 0x76, 
+0xDE, 0x75, 0xDE, 0x35, 0xCD, 0xD3, 0xCD, 0xB4, 
+0xC5, 0x93, 0xBD, 0x72, 0xC5, 0x93, 0xC5, 0xD3, 
+0xA4, 0xAF, 0xD6, 0x35, 0xCD, 0xF5, 0xAD, 0x12, 
+0x7B, 0xAD, 0x31, 0x86, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x10, 0xC4, 0x18, 0xC4, 
+0x18, 0xE4, 0x19, 0x04, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x10, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x10, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x08, 0x83, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 
+0x08, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA4, 
+0x18, 0xE4, 0x19, 0x05, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x05, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 
+0x29, 0x67, 0x39, 0xC8, 0x31, 0xC8, 0x39, 0xE9, 
+0x31, 0xA8, 0x4A, 0x6B, 0x4A, 0x4A, 0x4A, 0x29, 
+0x7B, 0xAD, 0xB5, 0x32, 0xBD, 0x73, 0xAD, 0x32, 
+0xA4, 0xF1, 0xAD, 0x11, 0xB5, 0x12, 0xD6, 0x35, 
+0xDE, 0x76, 0xE6, 0x96, 0xDE, 0x96, 0xBD, 0x72, 
+0xBD, 0x72, 0xE6, 0xB7, 0xDE, 0x76, 0xD6, 0x56, 
+0xBD, 0x93, 0xB5, 0x52, 0xBD, 0x52, 0xD6, 0x35, 
+0xD6, 0x34, 0xDE, 0x54, 0xDE, 0x55, 0xDE, 0x76, 
+0x7B, 0xAD, 0xAD, 0x32, 0x9C, 0xB1, 0x8C, 0x2E, 
+0x7B, 0xCC, 0x7C, 0x0D, 0x7B, 0xEC, 0x73, 0xAB, 
+0x6B, 0x6B, 0x7B, 0xCD, 0x8C, 0x4E, 0x8C, 0x2D, 
+0x9C, 0xAF, 0xA4, 0xEF, 0xA4, 0xEF, 0x9C, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xCF, 0xA4, 0xCF, 0xAC, 0xF0, 
+0xA4, 0xCF, 0xA4, 0xAF, 0xAC, 0xF0, 0xB5, 0x31, 
+0xBD, 0x31, 0xB5, 0x10, 0xB5, 0x10, 0xAC, 0xCF, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xAD, 0x10, 0xB5, 0x31, 0xAC, 0xF0, 
+0xAC, 0xCF, 0xA4, 0xCF, 0x9C, 0x8E, 0xAC, 0xF0, 
+0xAD, 0x11, 0xA4, 0xAF, 0x9C, 0xAF, 0x9C, 0xAF, 
+0xBD, 0x93, 0xBD, 0x72, 0xCE, 0x15, 0xB5, 0x10, 
+0xB5, 0x10, 0xB4, 0xEF, 0x73, 0x29, 0x7B, 0x6B, 
+0xC5, 0xD4, 0xCE, 0x16, 0x94, 0x4F, 0x8B, 0xEF, 
+0x8B, 0xEF, 0x73, 0x6D, 0x8C, 0x10, 0xAD, 0x14, 
+0x94, 0x72, 0x73, 0x8E, 0x39, 0xE7, 0x31, 0xA6, 
+0x4A, 0x49, 0x5A, 0xEC, 0x63, 0x0C, 0x52, 0x8A, 
+0x39, 0xE8, 0x52, 0x8A, 0x5A, 0xCB, 0x5A, 0xCB, 
+0x29, 0x66, 0x08, 0x62, 0x08, 0x82, 0x10, 0xA3, 
+0x10, 0xA3, 0x39, 0xE7, 0xC6, 0x37, 0xBD, 0xB4, 
+0xB5, 0x73, 0xCE, 0x56, 0xD6, 0x56, 0xD6, 0x56, 
+0xD6, 0x56, 0xCE, 0x36, 0xAD, 0x32, 0xBD, 0xB5, 
+0xBD, 0x94, 0xAD, 0x52, 0xA5, 0x11, 0xBD, 0xB4, 
+0xCE, 0x36, 0xB5, 0xB4, 0xAD, 0x52, 0x9C, 0x8E, 
+0xBD, 0x71, 0x7B, 0x8A, 0xCD, 0xF3, 0x9C, 0x6E, 
+0x84, 0x0D, 0x8C, 0x4F, 0x83, 0xEE, 0x9C, 0xD1, 
+0x9C, 0xB0, 0xA5, 0x12, 0xB5, 0x95, 0xAD, 0x34, 
+0xA5, 0x14, 0xBD, 0x96, 0xB5, 0x76, 0x9C, 0x92, 
+0xA4, 0xF3, 0x73, 0x6D, 0x31, 0x65, 0x4A, 0x28, 
+0x5A, 0x8A, 0x62, 0xCB, 0x5A, 0x8A, 0x42, 0x08, 
+0x5A, 0xCB, 0x73, 0x6E, 0x5A, 0x8A, 0x4A, 0x49, 
+0x5A, 0xAA, 0x73, 0x6D, 0x94, 0x71, 0x73, 0x6D, 
+0x73, 0x6D, 0x7B, 0xAE, 0x42, 0x07, 0x5A, 0xAA, 
+0x41, 0xE7, 0x21, 0x03, 0x29, 0x44, 0x41, 0xE7, 
+0x21, 0x24, 0x73, 0x6D, 0x73, 0x4D, 0x4A, 0x49, 
+0x63, 0x0C, 0x5A, 0xCB, 0x63, 0x0B, 0x7B, 0xAD, 
+0x83, 0xEE, 0x7B, 0xCD, 0x73, 0x6B, 0x63, 0x0A, 
+0x6B, 0x4B, 0x7B, 0xCD, 0x8C, 0x2E, 0xBD, 0xD4, 
+0xC5, 0xF5, 0xAD, 0x12, 0xCE, 0x36, 0xB5, 0x73, 
+0xD6, 0x36, 0xB5, 0x53, 0x9C, 0x6F, 0xAD, 0x12, 
+0xD6, 0x36, 0xE6, 0xB6, 0xE6, 0xB7, 0xDE, 0x76, 
+0xDE, 0x56, 0xD6, 0x55, 0xD6, 0x56, 0xDE, 0x76, 
+0xD6, 0x35, 0xCD, 0xF4, 0xBD, 0x73, 0xB5, 0x32, 
+0xB5, 0x32, 0xB5, 0x32, 0xAC, 0xF0, 0x9C, 0x6F, 
+0x8C, 0x0D, 0xAD, 0x11, 0xB5, 0x11, 0xAD, 0x11, 
+0xBD, 0x73, 0xBD, 0x73, 0xAD, 0x11, 0xB5, 0x32, 
+0xB5, 0x32, 0x52, 0x48, 0x39, 0x86, 0x52, 0x68, 
+0xAD, 0x32, 0x73, 0x6C, 0x31, 0x85, 0x29, 0x44, 
+0x29, 0x45, 0x31, 0xA6, 0x31, 0x85, 0x31, 0xA6, 
+0x42, 0x07, 0x4A, 0x29, 0x7B, 0xAF, 0xB5, 0x96, 
+0x9C, 0xB2, 0x7B, 0xAE, 0x6B, 0x0C, 0x62, 0xAB, 
+0x49, 0xE7, 0x7B, 0x6E, 0x7B, 0xAE, 0x8C, 0x30, 
+0x6B, 0x0C, 0x7B, 0xAE, 0x9C, 0x71, 0x9C, 0x70, 
+0x8B, 0xEF, 0x94, 0x10, 0x73, 0x4D, 0x31, 0x66, 
+0x18, 0xA3, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x4A, 0x49, 0x8C, 0x0F, 
+0xBD, 0x93, 0xB5, 0x11, 0xB5, 0x11, 0xCD, 0xF4, 
+0xE6, 0x96, 0xE6, 0x76, 0xDE, 0x76, 0xE6, 0x96, 
+0xE6, 0x96, 0xB5, 0x11, 0xA4, 0x6F, 0x8B, 0xED, 
+0x8B, 0xCD, 0x94, 0x2E, 0x9C, 0x90, 0x94, 0x2E, 
+0x73, 0x6B, 0xBD, 0xB4, 0xE6, 0xB8, 0xDE, 0x76, 
+0xBD, 0x93, 0x73, 0x4C, 0x31, 0xA7, 0x18, 0xC4, 
+0x18, 0xE4, 0x10, 0xE4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xC4, 0x10, 0xA3, 0x18, 0xE4, 
+0x18, 0xC4, 0x10, 0xC4, 0x10, 0xA4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x08, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 
+0x18, 0xE4, 0x21, 0x25, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x21, 0x05, 0x21, 0x46, 0x21, 0x26, 0x19, 0x05, 
+0x29, 0x46, 0x31, 0xA8, 0x31, 0xA8, 0x31, 0xA8, 
+0x39, 0xE9, 0x3A, 0x09, 0x39, 0xE9, 0x39, 0xA8, 
+0x41, 0xE8, 0x73, 0x6C, 0x9C, 0x90, 0xAD, 0x32, 
+0x9C, 0x90, 0xA4, 0xD1, 0xAC, 0xF1, 0xC5, 0xD4, 
+0xCD, 0xD4, 0xD6, 0x14, 0xD6, 0x35, 0xCD, 0xD4, 
+0xCD, 0xD4, 0xD6, 0x35, 0xCE, 0x14, 0xCD, 0xF4, 
+0xCD, 0xF5, 0xD6, 0x36, 0xC5, 0x93, 0xE6, 0xB7, 
+0xE6, 0x95, 0xE6, 0x95, 0xE6, 0x95, 0xE6, 0xB6, 
+0x73, 0x8D, 0x8C, 0x0F, 0x84, 0x0E, 0x94, 0x4E, 
+0x94, 0x6E, 0x83, 0xED, 0x8C, 0x6E, 0x94, 0x8F, 
+0x8C, 0x4F, 0x84, 0x0D, 0x8C, 0x2E, 0x9C, 0xD0, 
+0xA4, 0xF0, 0xA4, 0xCF, 0xA4, 0xEF, 0xA4, 0xCF, 
+0xAC, 0xCF, 0xAC, 0xCF, 0xAC, 0xCF, 0x94, 0x4D, 
+0xA4, 0x8E, 0x94, 0x0C, 0x8B, 0xCB, 0x94, 0x2C, 
+0xA4, 0x6E, 0xA4, 0x8E, 0xAC, 0xAE, 0xA4, 0x8E, 
+0xB4, 0xF0, 0xBD, 0x71, 0xB5, 0x30, 0xAC, 0xEF, 
+0xB4, 0xEF, 0xB4, 0xEF, 0xB5, 0x10, 0xB5, 0x10, 
+0xB5, 0x10, 0xB5, 0x10, 0xBD, 0x30, 0xBD, 0x51, 
+0xB5, 0x30, 0xAC, 0xF0, 0xB5, 0x10, 0xB5, 0x10, 
+0xB4, 0xF0, 0xA4, 0xAF, 0xA4, 0x8E, 0xAC, 0xEF, 
+0xB5, 0x10, 0xBD, 0x10, 0xB5, 0x10, 0xB4, 0xF0, 
+0xA4, 0x8E, 0x5A, 0xA8, 0x39, 0xC6, 0x42, 0x07, 
+0x4A, 0x28, 0x62, 0xCB, 0x94, 0x72, 0xB5, 0x96, 
+0xBD, 0xF8, 0x6B, 0x4D, 0x4A, 0x69, 0x73, 0x8E, 
+0x73, 0x8E, 0x7B, 0xCF, 0x8C, 0x51, 0x8C, 0x71, 
+0x84, 0x31, 0x84, 0x10, 0x6B, 0x2D, 0x31, 0xA7, 
+0x08, 0x62, 0x08, 0x62, 0x08, 0x62, 0x10, 0xC3, 
+0x39, 0xE8, 0x6B, 0x6D, 0xD6, 0x57, 0xAD, 0x32, 
+0x8C, 0x0E, 0xB5, 0x73, 0xD6, 0x76, 0xCE, 0x56, 
+0xCE, 0x56, 0xCE, 0x36, 0xBD, 0xD4, 0xC5, 0xF5, 
+0xC5, 0xD5, 0xBD, 0xB4, 0xBD, 0x94, 0xBD, 0xB4, 
+0xC6, 0x15, 0xC5, 0xD5, 0xB5, 0x52, 0x9C, 0x6E, 
+0xCD, 0xD3, 0x8C, 0x0C, 0xD6, 0x35, 0xAC, 0xF0, 
+0x94, 0x8F, 0xA5, 0x12, 0x94, 0xB0, 0xB5, 0xB4, 
+0xAD, 0x52, 0xBD, 0xB4, 0xBD, 0x95, 0x8C, 0x30, 
+0x8C, 0x30, 0x9C, 0xB2, 0xA4, 0xF3, 0x73, 0x6D, 
+0x5A, 0xCB, 0x29, 0x24, 0x41, 0xE7, 0x42, 0x07, 
+0x4A, 0x48, 0x5A, 0xAA, 0x6B, 0x2C, 0x6B, 0x0C, 
+0x6B, 0x2C, 0x6B, 0x2C, 0x52, 0x69, 0x4A, 0x08, 
+0x5A, 0xAA, 0x52, 0x69, 0x63, 0x0B, 0x52, 0x89, 
+0x5A, 0xAA, 0x5A, 0xCA, 0x52, 0x89, 0x5A, 0xAA, 
+0x4A, 0x28, 0x39, 0xA6, 0x39, 0xC6, 0x21, 0x24, 
+0x21, 0x04, 0x6B, 0x4D, 0x63, 0x0B, 0x6B, 0x4C, 
+0x83, 0xEF, 0x84, 0x0F, 0x94, 0x70, 0x9C, 0xD1, 
+0xA5, 0x13, 0xAD, 0x53, 0xA5, 0x32, 0x94, 0x90, 
+0x94, 0x70, 0x94, 0x90, 0x8C, 0x4F, 0x94, 0x70, 
+0xA4, 0xF2, 0x94, 0x90, 0xA4, 0xF2, 0xB5, 0x53, 
+0xC5, 0xF5, 0xCE, 0x16, 0xA4, 0xD1, 0xB5, 0x32, 
+0xDE, 0x76, 0xDE, 0x96, 0xE6, 0x96, 0xE6, 0x96, 
+0xD6, 0x35, 0xDE, 0x75, 0xE6, 0xB7, 0xC5, 0xB3, 
+0xBD, 0x72, 0xD6, 0x35, 0xDE, 0x55, 0xD6, 0x35, 
+0xD6, 0x35, 0xCD, 0xF5, 0xC5, 0xD4, 0xBD, 0x93, 
+0xAC, 0xF1, 0xB5, 0x52, 0xAC, 0xF0, 0xA4, 0x6F, 
+0xCD, 0xF4, 0xDE, 0x55, 0xCD, 0xF4, 0xAC, 0xD0, 
+0xC5, 0xD5, 0xA4, 0xD1, 0x9C, 0xB1, 0x8C, 0x4F, 
+0xA5, 0x11, 0xA4, 0xD1, 0x8C, 0x2E, 0x52, 0xA9, 
+0x31, 0xA6, 0x31, 0x85, 0x29, 0x44, 0x29, 0x44, 
+0x29, 0x65, 0x39, 0xC7, 0x52, 0x8A, 0x63, 0x2C, 
+0x9D, 0x14, 0xCE, 0x59, 0xB5, 0x96, 0x7B, 0x8E, 
+0x52, 0x49, 0x83, 0xCE, 0x62, 0xCA, 0x52, 0x29, 
+0x41, 0xE7, 0x73, 0x6D, 0xA4, 0x91, 0x94, 0x0F, 
+0x83, 0x8D, 0x8C, 0x0F, 0x83, 0xCE, 0x6B, 0x0C, 
+0x39, 0x86, 0x21, 0x25, 0x18, 0xE4, 0x18, 0xE4, 
+0x21, 0x04, 0x5A, 0xAA, 0x9C, 0x91, 0x9C, 0x90, 
+0xA4, 0xB0, 0xAC, 0xF1, 0xB5, 0x11, 0xAC, 0xF0, 
+0xAC, 0xD0, 0xA4, 0xAF, 0x9C, 0x4E, 0x9C, 0x4E, 
+0xA4, 0x8F, 0x94, 0x0D, 0x83, 0xAD, 0x83, 0x8C, 
+0x7B, 0x4C, 0x6A, 0xEA, 0x5A, 0xA9, 0x5A, 0x89, 
+0x73, 0x2C, 0xB5, 0x32, 0xA4, 0xD0, 0x94, 0x2E, 
+0x83, 0xED, 0x83, 0xCD, 0x73, 0x4C, 0x39, 0xC7, 
+0x18, 0xE4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC3, 0x10, 0xC3, 0x10, 0xC3, 0x10, 0xC4, 
+0x18, 0xC4, 0x18, 0xE4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 
+0x08, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xC4, 
+0x21, 0x05, 0x29, 0x46, 0x29, 0x66, 0x21, 0x26, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x18, 0xE5, 
+0x21, 0x26, 0x29, 0x46, 0x21, 0x26, 0x21, 0x26, 
+0x29, 0x67, 0x29, 0x87, 0x29, 0x87, 0x29, 0x67, 
+0x29, 0x67, 0x29, 0x67, 0x29, 0x67, 0x31, 0xA7, 
+0x42, 0x09, 0x5A, 0xCB, 0x73, 0x6D, 0xA4, 0xD1, 
+0x94, 0x6F, 0xA4, 0xB0, 0x9C, 0xB0, 0xB5, 0x73, 
+0xBD, 0x93, 0xC5, 0xB3, 0xC5, 0xB3, 0xCD, 0xD3, 
+0xD6, 0x14, 0xD6, 0x55, 0xD6, 0x14, 0xCD, 0xB4, 
+0xBD, 0x93, 0xC5, 0xD4, 0xD6, 0x15, 0xE6, 0xB7, 
+0xE6, 0x96, 0xE6, 0x75, 0xDE, 0x75, 0xDE, 0x75, 
+0x83, 0xEE, 0x83, 0xCE, 0x73, 0x6D, 0xC6, 0x17, 
+0xC6, 0x16, 0x84, 0x0D, 0x6B, 0x6A, 0x94, 0x8F, 
+0x9C, 0xD1, 0xA4, 0xF2, 0x8C, 0x4E, 0x94, 0x6F, 
+0x8C, 0x4E, 0x94, 0x6F, 0xA4, 0xF0, 0x94, 0x4D, 
+0x9C, 0x4D, 0xA4, 0xAE, 0xAC, 0xEF, 0x9C, 0x8F, 
+0x9C, 0x8F, 0x9C, 0x8F, 0x94, 0x4E, 0x94, 0x4E, 
+0x9C, 0x4E, 0x9C, 0x4E, 0x94, 0x4E, 0x94, 0x0D, 
+0x8B, 0xEC, 0x94, 0x0D, 0x83, 0xAB, 0x8B, 0xEC, 
+0x83, 0xCB, 0x83, 0xCB, 0x83, 0xAB, 0x7B, 0x4A, 
+0x73, 0x4A, 0x83, 0x8B, 0xA4, 0x6E, 0xA4, 0xAE, 
+0xB4, 0xEF, 0xAC, 0xAE, 0xA4, 0x8E, 0xC5, 0xB3, 
+0xB5, 0x31, 0x9C, 0x6E, 0xB5, 0x10, 0xB5, 0x10, 
+0xAC, 0xCF, 0xAC, 0xAE, 0xA4, 0x6E, 0x9C, 0x2C, 
+0xA4, 0xAE, 0x83, 0xCC, 0x39, 0xA5, 0x52, 0x89, 
+0x39, 0xC6, 0x6B, 0x4D, 0x8C, 0x71, 0x9C, 0xF4, 
+0xB5, 0x76, 0x5A, 0xCB, 0x73, 0x8E, 0x84, 0x30, 
+0x84, 0x10, 0x8C, 0x51, 0x94, 0xB2, 0x94, 0xB2, 
+0x94, 0xB3, 0xB5, 0x76, 0xA5, 0x14, 0x6B, 0x6E, 
+0x52, 0x8A, 0x42, 0x08, 0x3A, 0x08, 0x4A, 0x8A, 
+0x41, 0xE8, 0x8C, 0x70, 0xB5, 0x73, 0xB5, 0x52, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xAD, 0x32, 0xA5, 0x11, 
+0xAD, 0x32, 0xB5, 0x52, 0xB5, 0x52, 0xBD, 0xB4, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xBD, 0xD4, 0xBD, 0xB4, 
+0xBD, 0xD4, 0xBD, 0xD5, 0xB5, 0x52, 0xA4, 0xAF, 
+0xCD, 0xF3, 0xB5, 0x10, 0xCD, 0xF3, 0xB5, 0x11, 
+0xB5, 0x32, 0xB5, 0x93, 0xB5, 0x94, 0xBD, 0xB4, 
+0x9C, 0xB0, 0x9C, 0xD1, 0xA4, 0xF2, 0x6B, 0x4C, 
+0x73, 0x8E, 0x8C, 0x30, 0x8C, 0x10, 0x6B, 0x0C, 
+0x52, 0x49, 0x52, 0x69, 0x31, 0x65, 0x41, 0xE7, 
+0x4A, 0x28, 0x52, 0x69, 0x5A, 0xAA, 0x6B, 0x0C, 
+0x6B, 0x0C, 0x6B, 0x0C, 0x52, 0x69, 0x41, 0xC7, 
+0x62, 0xCB, 0x39, 0xA6, 0x39, 0xC6, 0x4A, 0x28, 
+0x42, 0x28, 0x4A, 0x28, 0x4A, 0x48, 0x52, 0x89, 
+0x41, 0xE7, 0x29, 0x24, 0x39, 0xA6, 0x4A, 0x28, 
+0x5A, 0xAA, 0x7B, 0xCE, 0x84, 0x0F, 0x7B, 0xCE, 
+0x83, 0xEF, 0x7B, 0xEE, 0x84, 0x0F, 0x8C, 0x4F, 
+0x8C, 0x4F, 0x94, 0x90, 0x9C, 0xD1, 0xB5, 0x73, 
+0xA5, 0x12, 0x8C, 0x4F, 0x9C, 0xD1, 0x8C, 0x4F, 
+0xA5, 0x12, 0xBD, 0xD5, 0xBD, 0xB5, 0xB5, 0x53, 
+0xC5, 0xF5, 0xCE, 0x15, 0xAD, 0x11, 0xB5, 0x32, 
+0xDE, 0x96, 0xD6, 0x34, 0xD6, 0x34, 0xDE, 0x75, 
+0xDE, 0x75, 0xE6, 0x96, 0xDE, 0x55, 0xC5, 0x92, 
+0xD6, 0x14, 0xCD, 0xF4, 0xE6, 0x96, 0xE6, 0x96, 
+0xE6, 0xB6, 0xE6, 0x96, 0xE6, 0xB6, 0xE6, 0x96, 
+0xE6, 0x96, 0xCD, 0xD3, 0xBD, 0x51, 0xCD, 0xF4, 
+0xE6, 0xD7, 0xE6, 0x96, 0xB5, 0x31, 0xAD, 0x11, 
+0xAD, 0x32, 0xAD, 0x52, 0xBD, 0xB4, 0xB5, 0x52, 
+0x94, 0x8F, 0xBD, 0x94, 0xBD, 0xB4, 0xAD, 0x12, 
+0x8C, 0x4F, 0x42, 0x07, 0x31, 0x85, 0x29, 0x65, 
+0x29, 0x44, 0x29, 0x44, 0x31, 0x65, 0x39, 0xC6, 
+0x52, 0xCA, 0x7B, 0xCE, 0x9C, 0xD3, 0x6B, 0x4C, 
+0x5A, 0xAA, 0x73, 0x6D, 0x42, 0x28, 0x4A, 0x28, 
+0x62, 0xCA, 0x62, 0xAA, 0x73, 0x0B, 0x7B, 0x2C, 
+0x8B, 0xEF, 0x83, 0xAE, 0x6A, 0xAA, 0x7B, 0x6C, 
+0x73, 0x0C, 0x6B, 0x0C, 0x6B, 0x0B, 0x7B, 0x6D, 
+0x7B, 0xAE, 0x7B, 0x8D, 0x8C, 0x0E, 0xAD, 0x32, 
+0xBD, 0x73, 0xBD, 0x52, 0xBD, 0x72, 0xB5, 0x31, 
+0xAC, 0xD0, 0xA4, 0x8F, 0xA4, 0xB0, 0xAC, 0xF1, 
+0xB5, 0x11, 0xB5, 0x11, 0xAC, 0xF1, 0xA4, 0x90, 
+0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x6F, 0x94, 0x4F, 
+0x94, 0x4F, 0x9C, 0x70, 0x9C, 0x6F, 0x94, 0x2E, 
+0x94, 0x4F, 0x94, 0x4F, 0x8C, 0x0E, 0x6B, 0x4C, 
+0x31, 0x86, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x18, 0xE4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x08, 0x83, 
+0x08, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xC4, 
+0x21, 0x05, 0x29, 0x66, 0x31, 0xA7, 0x29, 0x67, 
+0x21, 0x26, 0x18, 0xE5, 0x18, 0xE5, 0x18, 0xE5, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x21, 0x46, 
+0x29, 0x46, 0x29, 0x67, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x29, 0x67, 0x31, 0xA8, 
+0x42, 0x4A, 0x5A, 0xEC, 0x5A, 0xCB, 0x73, 0xAD, 
+0x9C, 0x90, 0x9C, 0xB0, 0x94, 0x6F, 0xB5, 0x53, 
+0xB5, 0x72, 0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x52, 
+0xBD, 0x92, 0xD6, 0x55, 0xCD, 0xF4, 0xBD, 0x52, 
+0xB5, 0x32, 0xB5, 0x73, 0xCE, 0x15, 0xE6, 0xD7, 
+0xD6, 0x14, 0xD6, 0x14, 0xD6, 0x14, 0xD6, 0x34, 
+0x6B, 0x6C, 0x7B, 0xCE, 0x7B, 0xEF, 0xDE, 0xFB, 
+0xDE, 0x99, 0xAD, 0x2F, 0x94, 0x6C, 0xAD, 0x31, 
+0xC5, 0xF5, 0xCE, 0x37, 0xAD, 0x12, 0xAD, 0x32, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xD0, 0xB5, 0x30, 
+0xAC, 0xEF, 0xAC, 0xCE, 0xBD, 0x92, 0xE6, 0x97, 
+0xC5, 0xD4, 0xBD, 0x93, 0xBD, 0x93, 0xBD, 0x93, 
+0xBD, 0x93, 0xBD, 0x93, 0xB5, 0x52, 0xB5, 0x32, 
+0xB5, 0x52, 0xB5, 0x32, 0xAD, 0x11, 0xAD, 0x11, 
+0x9C, 0xB0, 0x9C, 0x8F, 0xAD, 0x11, 0xB5, 0x52, 
+0xAD, 0x11, 0xAD, 0x32, 0xC5, 0xB3, 0xBD, 0x93, 
+0xBD, 0x72, 0xAC, 0xCF, 0xB5, 0x51, 0xC5, 0xF4, 
+0xBD, 0xB3, 0xAD, 0x32, 0xA4, 0xD0, 0x8C, 0x0D, 
+0x9C, 0x8E, 0x94, 0x4D, 0x94, 0x4D, 0x8C, 0x2C, 
+0x9C, 0xAF, 0x8C, 0x2D, 0x52, 0x68, 0x6B, 0x4C, 
+0x52, 0x69, 0x52, 0x8A, 0x6B, 0x4D, 0x7C, 0x10, 
+0x9C, 0xD3, 0x5A, 0xEB, 0x94, 0x92, 0x73, 0x8E, 
+0x94, 0x92, 0x9C, 0xD3, 0x94, 0xB3, 0xA5, 0x14, 
+0xA5, 0x35, 0x9C, 0xD3, 0x39, 0xC7, 0xA5, 0x14, 
+0x9C, 0xB3, 0x4A, 0x49, 0x63, 0x2C, 0x5A, 0xCB, 
+0x8C, 0x2F, 0xB5, 0x72, 0xB5, 0x51, 0xBD, 0x71, 
+0xB5, 0x30, 0xB5, 0x10, 0xB5, 0x31, 0xB5, 0x30, 
+0xB5, 0x30, 0xAC, 0xEF, 0xAC, 0xCF, 0x9C, 0x8E, 
+0x9C, 0x6E, 0x9C, 0x8E, 0xAD, 0x11, 0xAD, 0x31, 
+0xB5, 0x52, 0xAC, 0xF0, 0x94, 0x4D, 0xB5, 0x10, 
+0xBD, 0x71, 0xBD, 0x51, 0xC5, 0x71, 0xC5, 0x92, 
+0xBD, 0x72, 0x94, 0x6F, 0xA5, 0x11, 0xAD, 0x11, 
+0x8C, 0x2D, 0x8C, 0x2E, 0x9C, 0xB1, 0x6B, 0x0B, 
+0x4A, 0x28, 0x5A, 0x8A, 0x52, 0x49, 0x52, 0x49, 
+0x4A, 0x48, 0x4A, 0x28, 0x29, 0x44, 0x41, 0xE7, 
+0x4A, 0x28, 0x42, 0x07, 0x4A, 0x08, 0x52, 0x8A, 
+0x5A, 0xAA, 0x52, 0x69, 0x4A, 0x08, 0x39, 0xC6, 
+0x39, 0xC6, 0x31, 0x86, 0x41, 0xE7, 0x41, 0xE7, 
+0x5A, 0xAA, 0x62, 0xEB, 0x5A, 0xCA, 0x63, 0x0B, 
+0x52, 0x8A, 0x4A, 0x48, 0x62, 0xEB, 0x84, 0x0F, 
+0x83, 0xEF, 0x9C, 0xB2, 0xBD, 0xD6, 0x9C, 0xB2, 
+0x8C, 0x50, 0x7B, 0xEE, 0x8C, 0x2F, 0x9C, 0xB1, 
+0x94, 0x4F, 0x9C, 0xB1, 0xA5, 0x12, 0x9C, 0xD1, 
+0x94, 0x70, 0x7B, 0xAD, 0x8C, 0x4F, 0x6B, 0x6C, 
+0x8C, 0x50, 0x8C, 0x4F, 0x94, 0x90, 0x9C, 0xB1, 
+0x94, 0x6F, 0xB5, 0x32, 0xAD, 0x11, 0xAD, 0x11, 
+0xC5, 0xD4, 0xE6, 0xB6, 0xE6, 0xB6, 0xE6, 0xB6, 
+0xDE, 0x95, 0xDE, 0x95, 0xD6, 0x14, 0xB5, 0x30, 
+0xB5, 0x31, 0xC5, 0x92, 0xDE, 0x76, 0xE6, 0x96, 
+0xE6, 0xB6, 0xE6, 0x95, 0xE6, 0xB6, 0xE6, 0xB6, 
+0xE6, 0x75, 0xCD, 0xB2, 0xE6, 0x75, 0xE6, 0x96, 
+0xE6, 0xB6, 0xDE, 0x55, 0xCD, 0xF4, 0xB5, 0x32, 
+0xAD, 0x11, 0xB5, 0x93, 0xC5, 0xD4, 0xBD, 0x93, 
+0xBD, 0xD5, 0x9C, 0xB1, 0xBD, 0xD5, 0xBD, 0xD5, 
+0xC5, 0xF5, 0xAD, 0x32, 0x63, 0x2B, 0x31, 0x85, 
+0x21, 0x24, 0x29, 0x44, 0x31, 0xA5, 0x29, 0x44, 
+0x21, 0x24, 0x29, 0x65, 0x31, 0xA6, 0x31, 0x85, 
+0x29, 0x44, 0x31, 0x85, 0x29, 0x65, 0x4A, 0x48, 
+0x5A, 0xAA, 0x73, 0x2B, 0x83, 0x8D, 0x73, 0x0C, 
+0x8B, 0xEF, 0x8B, 0xAE, 0x83, 0x8D, 0x93, 0xEF, 
+0x72, 0xEB, 0x73, 0x2C, 0x9C, 0x30, 0x83, 0x8E, 
+0x83, 0xCE, 0xA4, 0xD2, 0x6B, 0x0B, 0x73, 0x6C, 
+0x9C, 0x90, 0xB5, 0x52, 0xB5, 0x72, 0xAD, 0x11, 
+0x8B, 0xEC, 0x94, 0x2E, 0x9C, 0x6E, 0x9C, 0x8F, 
+0xA4, 0xD0, 0xAC, 0xD0, 0xBD, 0x73, 0xD6, 0x15, 
+0xB5, 0x11, 0xC5, 0xB3, 0xC5, 0xB3, 0xBD, 0x72, 
+0xAC, 0xF0, 0xAD, 0x11, 0xB5, 0x11, 0xAC, 0xF1, 
+0xC5, 0xB4, 0xB5, 0x32, 0xAD, 0x11, 0x7B, 0xAC, 
+0x29, 0x86, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 
+0x10, 0xC4, 0x18, 0xC4, 0x18, 0xE4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x10, 0x83, 
+0x08, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xC4, 
+0x21, 0x05, 0x29, 0x66, 0x39, 0xE8, 0x39, 0xC7, 
+0x29, 0x67, 0x21, 0x05, 0x18, 0xE5, 0x19, 0x05, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x46, 0x21, 0x26, 
+0x21, 0x46, 0x21, 0x46, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x29, 0x46, 0x29, 0x87, 0x31, 0xC8, 
+0x42, 0x2A, 0x42, 0x29, 0x39, 0xA8, 0x4A, 0x29, 
+0x94, 0x70, 0xA4, 0xD1, 0x9C, 0xB0, 0xAD, 0x32, 
+0xB5, 0x32, 0xB5, 0x52, 0xAD, 0x12, 0xAD, 0x12, 
+0xAC, 0xF1, 0xC5, 0x93, 0xBD, 0x93, 0xAD, 0x32, 
+0xAD, 0x32, 0xA4, 0xF1, 0xBD, 0x93, 0xCE, 0x15, 
+0xC5, 0x93, 0xC5, 0xB3, 0xC5, 0xB3, 0xC5, 0xD3, 
+0x63, 0x2B, 0x7B, 0xCE, 0x9C, 0xB2, 0xD6, 0x9A, 
+0xB5, 0x74, 0xB5, 0x31, 0xBD, 0xB2, 0xBD, 0xD3, 
+0xCE, 0x36, 0xB5, 0x74, 0xB5, 0x74, 0xC5, 0xF5, 
+0xAD, 0x52, 0xA5, 0x11, 0xA4, 0xF1, 0xAC, 0xF0, 
+0xC5, 0x71, 0xAC, 0xAE, 0xB5, 0x31, 0xDE, 0x76, 
+0xCE, 0x15, 0xCE, 0x15, 0xCE, 0x15, 0xCE, 0x15, 
+0xCD, 0xF5, 0xCD, 0xF5, 0xCD, 0xF5, 0xCE, 0x15, 
+0xCE, 0x15, 0xBD, 0xB3, 0xBD, 0x93, 0xBD, 0x93, 
+0xB5, 0x52, 0xB5, 0x52, 0xBD, 0xB4, 0xC5, 0xF4, 
+0xCE, 0x35, 0xC5, 0xF4, 0xC5, 0xD4, 0xDE, 0x97, 
+0xDE, 0x55, 0xAC, 0xAE, 0xAC, 0xF0, 0xBD, 0xD3, 
+0xC6, 0x14, 0xB5, 0x52, 0x9C, 0xAF, 0x8C, 0x2E, 
+0xA4, 0xD0, 0xAD, 0x31, 0xAD, 0x31, 0xAD, 0x31, 
+0xAD, 0x31, 0xA5, 0x11, 0x73, 0x6C, 0x5A, 0xAA, 
+0x52, 0x69, 0x4A, 0x69, 0x5A, 0xCB, 0x6B, 0x4D, 
+0x7B, 0xCF, 0x7B, 0xF0, 0x84, 0x10, 0x6B, 0x6E, 
+0xA5, 0x35, 0xA5, 0x35, 0x8C, 0x51, 0x9C, 0xD4, 
+0xA4, 0xF4, 0x5A, 0xAB, 0x73, 0xAF, 0xAD, 0x75, 
+0x83, 0xEF, 0x29, 0x45, 0x4A, 0x6A, 0x6B, 0x4C, 
+0x83, 0xCE, 0x94, 0x2E, 0x83, 0xCB, 0xB5, 0x51, 
+0xAD, 0x10, 0x83, 0xAB, 0x83, 0xAB, 0x8B, 0xEB, 
+0x8B, 0xEC, 0x94, 0x0C, 0xAC, 0xF0, 0xD6, 0x14, 
+0xBD, 0x51, 0xB5, 0x30, 0xAC, 0xAE, 0xA4, 0x8E, 
+0xA4, 0x8E, 0x9C, 0x6E, 0xB4, 0xF0, 0xCD, 0xD2, 
+0xCD, 0xB2, 0xC5, 0x91, 0xC5, 0x91, 0xC5, 0x71, 
+0xBD, 0x71, 0xBD, 0x30, 0xBD, 0x51, 0xBD, 0x51, 
+0xBD, 0x51, 0xBD, 0x51, 0xBD, 0x52, 0x6A, 0xEB, 
+0x29, 0x04, 0x31, 0x65, 0x31, 0x85, 0x31, 0x85, 
+0x39, 0xA6, 0x29, 0x44, 0x29, 0x24, 0x41, 0xE7, 
+0x4A, 0x28, 0x52, 0x69, 0x31, 0x65, 0x4A, 0x48, 
+0x5A, 0xAA, 0x41, 0xE7, 0x52, 0x69, 0x4A, 0x28, 
+0x41, 0xE7, 0x39, 0xC7, 0x31, 0x65, 0x31, 0x65, 
+0x4A, 0x48, 0x62, 0xCA, 0x39, 0xA6, 0x63, 0x0B, 
+0x6B, 0x4C, 0x73, 0x8D, 0x83, 0xCE, 0x7B, 0xCE, 
+0x8C, 0x10, 0xA5, 0x34, 0xC6, 0x38, 0xBD, 0xB6, 
+0xAD, 0x33, 0x84, 0x2F, 0x8C, 0x2F, 0x9C, 0xB1, 
+0xB5, 0x33, 0xB5, 0x53, 0xB5, 0x73, 0xB5, 0x52, 
+0xA4, 0xD1, 0x8C, 0x2F, 0x73, 0xAD, 0x6B, 0x4C, 
+0x84, 0x0F, 0x7B, 0xEE, 0x84, 0x2F, 0x94, 0x90, 
+0x94, 0x90, 0x9C, 0xB0, 0xAD, 0x12, 0xB5, 0x12, 
+0xD6, 0x15, 0xDE, 0x55, 0xDE, 0x54, 0xDE, 0x75, 
+0xCD, 0xD3, 0xCD, 0xB2, 0xC5, 0x92, 0xAC, 0xF0, 
+0xA4, 0xCF, 0xC5, 0xB3, 0xDE, 0x95, 0xE6, 0x96, 
+0xE6, 0x96, 0xDE, 0x95, 0xDE, 0x34, 0xD6, 0x14, 
+0xE6, 0x96, 0xC5, 0x71, 0xC5, 0x91, 0xDE, 0x34, 
+0xDE, 0x54, 0xD6, 0x34, 0xBD, 0x72, 0xB5, 0x53, 
+0xB5, 0x73, 0xC6, 0x15, 0xBD, 0xD4, 0xBD, 0xD4, 
+0xC5, 0xF5, 0xB5, 0x53, 0xBD, 0xD5, 0xAD, 0x53, 
+0xBD, 0xB4, 0xBD, 0xD4, 0xAD, 0x32, 0x94, 0x90, 
+0x6B, 0x2C, 0x31, 0x85, 0x29, 0x44, 0x21, 0x44, 
+0x21, 0x03, 0x21, 0x03, 0x21, 0x24, 0x29, 0x44, 
+0x21, 0x44, 0x29, 0x65, 0x31, 0x65, 0x52, 0x49, 
+0x62, 0xAA, 0x7B, 0x8D, 0x7B, 0x8D, 0x73, 0x2C, 
+0x73, 0x2C, 0x7B, 0x6D, 0x83, 0x8D, 0x94, 0x0F, 
+0x83, 0x8D, 0x83, 0x8D, 0x94, 0x0F, 0x83, 0xAE, 
+0x94, 0x50, 0xA4, 0xB2, 0x9C, 0x71, 0x94, 0x0F, 
+0x6B, 0x2B, 0x73, 0x4B, 0x9C, 0x90, 0xBD, 0x93, 
+0xB5, 0x52, 0xAD, 0x31, 0xAD, 0x31, 0xB5, 0x31, 
+0xB5, 0x31, 0xB5, 0x52, 0xCD, 0xD4, 0xD6, 0x56, 
+0xB5, 0x11, 0xAC, 0xF0, 0xA4, 0xD0, 0x8C, 0x0D, 
+0xAC, 0xF1, 0xC5, 0x93, 0xB5, 0x12, 0x83, 0xED, 
+0x9C, 0x70, 0x8C, 0x0E, 0x7B, 0xAC, 0x42, 0x07, 
+0x18, 0xE3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 0x10, 0xC4, 
+0x10, 0xC4, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x18, 0xE4, 
+0x19, 0x05, 0x29, 0x66, 0x42, 0x29, 0x52, 0x8A, 
+0x41, 0xE8, 0x29, 0x46, 0x21, 0x25, 0x19, 0x05, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x46, 0x21, 0x26, 
+0x21, 0x46, 0x21, 0x46, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x46, 0x29, 0x67, 0x29, 0x87, 0x31, 0xA8, 
+0x31, 0xA7, 0x29, 0x66, 0x29, 0x46, 0x39, 0xC8, 
+0x73, 0x4D, 0x94, 0x4F, 0x83, 0xEE, 0x7B, 0xAD, 
+0x83, 0xCD, 0x83, 0xED, 0x7B, 0xAD, 0x7B, 0xAD, 
+0x8B, 0xEE, 0x94, 0x4F, 0x94, 0x2F, 0x94, 0x4F, 
+0x94, 0x6F, 0x9C, 0x90, 0xB5, 0x32, 0xAD, 0x12, 
+0xAC, 0xF1, 0xAD, 0x11, 0xB5, 0x52, 0xB5, 0x73, 
+0x52, 0xAA, 0x6B, 0x4C, 0x8C, 0x50, 0xAD, 0x35, 
+0x73, 0x8E, 0x9C, 0x91, 0xC5, 0xF6, 0xBD, 0x94, 
+0xC5, 0xD5, 0xB5, 0x54, 0x62, 0xEB, 0x73, 0x8C, 
+0xA5, 0x32, 0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xAF, 
+0xBD, 0x51, 0xAC, 0xAE, 0xA4, 0x8E, 0xD6, 0x36, 
+0xD6, 0x15, 0xD6, 0x35, 0xCE, 0x15, 0xCE, 0x15, 
+0xD6, 0x35, 0xD6, 0x35, 0xCE, 0x15, 0xCE, 0x15, 
+0xD6, 0x56, 0xD6, 0x56, 0xCE, 0x36, 0xD6, 0x77, 
+0xCE, 0x15, 0xC5, 0xF4, 0xC5, 0xD4, 0xC5, 0xF4, 
+0xCE, 0x15, 0xCE, 0x15, 0xC5, 0xB3, 0xD6, 0x35, 
+0xD6, 0x35, 0xAC, 0xAE, 0x94, 0x2D, 0xA4, 0xF0, 
+0xA4, 0xF0, 0xAD, 0x11, 0x9C, 0xB0, 0xA5, 0x11, 
+0xBD, 0xB3, 0xBD, 0xB3, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xC5, 0xD4, 0xBD, 0xB3, 0xAD, 0x11, 0x52, 0x89, 
+0x52, 0x69, 0x4A, 0x28, 0x52, 0xCA, 0x5B, 0x0B, 
+0x4A, 0x49, 0x7B, 0xEF, 0x63, 0x0C, 0x73, 0xAF, 
+0xAD, 0x75, 0xA5, 0x14, 0x94, 0xB3, 0x8C, 0x72, 
+0x84, 0x10, 0x8C, 0x72, 0xA5, 0x35, 0x84, 0x10, 
+0x52, 0x8A, 0x31, 0xA7, 0x6B, 0x4D, 0xAD, 0x33, 
+0xAD, 0x33, 0x94, 0x6F, 0x7B, 0xAD, 0x62, 0xEA, 
+0x83, 0xCD, 0x8C, 0x2E, 0x6B, 0x4A, 0x83, 0xED, 
+0x8C, 0x0E, 0x84, 0x0D, 0x83, 0xCD, 0xB5, 0x31, 
+0xBD, 0x50, 0xAC, 0xEF, 0xCD, 0xD2, 0xD5, 0xF3, 
+0xD6, 0x13, 0xCD, 0xB2, 0xC5, 0x92, 0xCD, 0xB2, 
+0xCD, 0xB2, 0xD5, 0xB2, 0xCD, 0xB2, 0xC5, 0x70, 
+0xC5, 0x70, 0xC5, 0x71, 0xCD, 0xB2, 0xD5, 0xD2, 
+0xCD, 0xB2, 0xC5, 0x71, 0xCD, 0xF4, 0x83, 0xCD, 
+0x31, 0x65, 0x31, 0x44, 0x29, 0x44, 0x29, 0x24, 
+0x29, 0x24, 0x29, 0x23, 0x21, 0x03, 0x29, 0x44, 
+0x39, 0xA6, 0x42, 0x07, 0x29, 0x44, 0x31, 0x85, 
+0x4A, 0x48, 0x4A, 0x48, 0x52, 0x69, 0x41, 0xE7, 
+0x39, 0xE6, 0x31, 0x65, 0x29, 0x44, 0x39, 0xC6, 
+0x42, 0x27, 0x62, 0xEA, 0x5A, 0xAA, 0x63, 0x0B, 
+0x62, 0xEB, 0x6B, 0x2C, 0x6B, 0x4C, 0x73, 0x4C, 
+0x84, 0x30, 0xC6, 0x18, 0xCE, 0x79, 0xCE, 0x79, 
+0x9C, 0xB1, 0x8C, 0x0E, 0x94, 0x4F, 0x83, 0xED, 
+0x8C, 0x2E, 0x83, 0xED, 0x94, 0x2E, 0x9C, 0x8F, 
+0x8C, 0x2E, 0x94, 0x6F, 0x7B, 0x8D, 0x73, 0xAD, 
+0x7B, 0xCE, 0x8C, 0x4F, 0x7B, 0xCE, 0x7B, 0xCD, 
+0x8C, 0x0E, 0x94, 0x6F, 0xB5, 0x52, 0xBD, 0x72, 
+0xEE, 0xD7, 0xE6, 0x75, 0xDE, 0x55, 0xE6, 0xB6, 
+0xE6, 0x96, 0xD6, 0x14, 0xC5, 0x92, 0xB5, 0x10, 
+0xC5, 0xB3, 0xDE, 0x55, 0xE6, 0xB6, 0xEE, 0xB6, 
+0xEE, 0xD6, 0xE6, 0x95, 0xD6, 0x13, 0xD5, 0xF3, 
+0xBD, 0x50, 0xCD, 0xD2, 0xCD, 0xB2, 0xD6, 0x13, 
+0xD6, 0x13, 0xD5, 0xD3, 0xAC, 0xF0, 0xB5, 0x72, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xCE, 0x36, 0xBD, 0xB4, 
+0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x53, 0xAD, 0x32, 
+0xB5, 0x73, 0xC5, 0xD4, 0xC5, 0xF5, 0xAD, 0x12, 
+0xB5, 0x32, 0x9C, 0x70, 0x52, 0x68, 0x29, 0x44, 
+0x21, 0x03, 0x21, 0x24, 0x29, 0x65, 0x31, 0x85, 
+0x29, 0x64, 0x29, 0x65, 0x62, 0xEB, 0x62, 0xEA, 
+0x5A, 0x89, 0x73, 0x2C, 0x73, 0x2C, 0x62, 0xCA, 
+0x62, 0xCA, 0x5A, 0x8A, 0x6A, 0xCA, 0x83, 0x8D, 
+0x8B, 0xCE, 0x8B, 0xCE, 0x9C, 0x50, 0x8B, 0xEF, 
+0x7B, 0x6D, 0x83, 0xAE, 0xB4, 0xF3, 0xB5, 0x13, 
+0xAC, 0xF2, 0x62, 0xAA, 0x62, 0xCA, 0x7B, 0x6D, 
+0xAC, 0xF1, 0xB5, 0x32, 0xBD, 0x93, 0xB5, 0x52, 
+0xB5, 0x31, 0xCE, 0x15, 0xDE, 0x56, 0xD6, 0x56, 
+0xCD, 0xF5, 0xCE, 0x15, 0xCD, 0xF5, 0xBD, 0x93, 
+0xC5, 0xD4, 0xC5, 0xB4, 0xC5, 0x94, 0xBD, 0xB4, 
+0x9C, 0x90, 0x62, 0xA9, 0x31, 0x65, 0x18, 0xC3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC3, 
+0x10, 0xC3, 0x10, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x18, 0xE4, 
+0x21, 0x05, 0x31, 0x87, 0x73, 0x4D, 0x8C, 0x30, 
+0x62, 0xEB, 0x42, 0x08, 0x31, 0xA7, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 
+0x29, 0x67, 0x29, 0x46, 0x29, 0x67, 0x29, 0x67, 
+0x21, 0x26, 0x21, 0x26, 0x29, 0x67, 0x39, 0xC8, 
+0x52, 0x49, 0x83, 0xEF, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xBD, 0x74, 0xB5, 0x33, 0xAD, 0x33, 0xB5, 0x53, 
+0xB5, 0x53, 0xAD, 0x33, 0xAD, 0x32, 0xAD, 0x12, 
+0xA4, 0xF2, 0xA4, 0xF2, 0xA4, 0xD1, 0xA4, 0xD1, 
+0x9C, 0xB1, 0x94, 0x70, 0x94, 0x4F, 0x94, 0x6F, 
+0x3A, 0x07, 0x42, 0x27, 0x52, 0xAA, 0x5A, 0xCA, 
+0x6B, 0x2D, 0x6B, 0x4D, 0xA5, 0x14, 0xAD, 0x13, 
+0xC5, 0xB6, 0xC5, 0xB7, 0xA4, 0xB2, 0x6B, 0x2B, 
+0xBD, 0xB5, 0xB5, 0x93, 0xAD, 0x31, 0x9C, 0x8E, 
+0xAC, 0xCF, 0xA4, 0x8E, 0x9C, 0x6E, 0xD6, 0x35, 
+0xD6, 0x35, 0xD6, 0x56, 0xD6, 0x56, 0xD6, 0x76, 
+0xD6, 0x56, 0xDE, 0x97, 0xDE, 0x76, 0xDE, 0x76, 
+0xDE, 0x77, 0xD6, 0x56, 0xD6, 0x36, 0xD6, 0x76, 
+0xCE, 0x15, 0xCE, 0x15, 0xCE, 0x15, 0xD6, 0x36, 
+0xD6, 0x56, 0xD6, 0x56, 0xCE, 0x15, 0xD6, 0x56, 
+0xCD, 0xF3, 0xA4, 0xAE, 0x73, 0x29, 0x94, 0x4E, 
+0x9C, 0xAF, 0xAD, 0x31, 0xBD, 0x93, 0xBD, 0x93, 
+0xC5, 0xB3, 0xBD, 0xB3, 0xC5, 0xD3, 0xB5, 0x72, 
+0xC5, 0xD4, 0xC5, 0xF4, 0xC5, 0xB4, 0x9C, 0xB0, 
+0x39, 0x85, 0x29, 0x44, 0x42, 0x28, 0x52, 0xAA, 
+0x52, 0xAA, 0x6B, 0x4D, 0x5A, 0xEC, 0x84, 0x10, 
+0x94, 0x92, 0x8C, 0x51, 0xB5, 0xB7, 0x8C, 0x52, 
+0x7B, 0xCF, 0x94, 0xB2, 0xA5, 0x14, 0x8C, 0x51, 
+0x63, 0x0D, 0x5A, 0xEB, 0x5A, 0xCA, 0x6B, 0x2C, 
+0x6B, 0x2B, 0x7B, 0x8D, 0xAC, 0xF2, 0x94, 0x90, 
+0x9C, 0xB0, 0xA4, 0xF1, 0xA5, 0x12, 0xBD, 0xB4, 
+0xB5, 0x94, 0xBD, 0xF5, 0xBD, 0xD5, 0xC5, 0xB4, 
+0xAC, 0xEF, 0xB4, 0xEF, 0xD5, 0xF3, 0xDD, 0xF3, 
+0xD5, 0xD2, 0xC5, 0x50, 0xC5, 0x91, 0xDE, 0x54, 
+0xDE, 0x33, 0xDE, 0x33, 0xCD, 0xB1, 0xBD, 0x50, 
+0xB5, 0x10, 0xAC, 0xEF, 0xBD, 0x30, 0xCD, 0xB2, 
+0xC5, 0x71, 0x9C, 0x6D, 0x94, 0x4E, 0x8B, 0xED, 
+0x6B, 0x2A, 0x6B, 0x0A, 0x62, 0xC9, 0x62, 0xC9, 
+0x62, 0xC9, 0x4A, 0x27, 0x42, 0x07, 0x41, 0xE7, 
+0x41, 0xE7, 0x39, 0xA5, 0x29, 0x44, 0x29, 0x24, 
+0x29, 0x23, 0x31, 0x65, 0x42, 0x28, 0x4A, 0x28, 
+0x39, 0xC6, 0x31, 0x65, 0x31, 0x85, 0x29, 0x44, 
+0x42, 0x07, 0x4A, 0x48, 0x39, 0xA6, 0x41, 0xE7, 
+0x5A, 0xAA, 0x6B, 0x4C, 0x52, 0x8A, 0x84, 0x10, 
+0x9C, 0xF4, 0x9C, 0xF4, 0xBD, 0xD7, 0xB5, 0x75, 
+0xC5, 0xD6, 0xBD, 0x32, 0xBD, 0x51, 0xA4, 0xAF, 
+0x9C, 0x8E, 0xA4, 0x8F, 0x9C, 0x8F, 0xAC, 0xD0, 
+0x9C, 0x8F, 0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x6E, 
+0xAC, 0xF1, 0xAD, 0x12, 0x9C, 0xB1, 0x9C, 0xB0, 
+0x9C, 0xB0, 0xAD, 0x12, 0xB5, 0x32, 0xA4, 0xD0, 
+0xBD, 0x72, 0xC5, 0xB3, 0xD5, 0xF4, 0xD6, 0x34, 
+0xD6, 0x14, 0xDE, 0x55, 0xD6, 0x35, 0xD6, 0x14, 
+0xD6, 0x14, 0xEE, 0xD7, 0xF6, 0xF7, 0xF6, 0xF7, 
+0xEE, 0xD7, 0xEE, 0xD7, 0xEE, 0x96, 0xE6, 0x75, 
+0xCD, 0xB2, 0xDE, 0x34, 0xDE, 0x14, 0xE6, 0x54, 
+0xDE, 0x54, 0xCD, 0xB2, 0xA4, 0x8E, 0xBD, 0x93, 
+0xC5, 0xD4, 0xAD, 0x32, 0xBD, 0xD4, 0xB5, 0xB4, 
+0xC6, 0x15, 0xC6, 0x15, 0xBD, 0xD5, 0xBD, 0xB4, 
+0xB5, 0x93, 0xBD, 0xB4, 0xB5, 0x73, 0xAD, 0x11, 
+0xBD, 0x52, 0xDE, 0x35, 0xE6, 0x76, 0xBD, 0x93, 
+0x94, 0x2F, 0x41, 0xE7, 0x29, 0x44, 0x29, 0x44, 
+0x21, 0x24, 0x39, 0xC6, 0x7B, 0xEE, 0x8C, 0x0F, 
+0x8C, 0x10, 0x4A, 0x28, 0x52, 0x49, 0x41, 0xE7, 
+0x73, 0x4C, 0x83, 0xCF, 0x73, 0x4C, 0x72, 0xEA, 
+0x83, 0x8D, 0x93, 0xCE, 0x94, 0x0F, 0x94, 0x0F, 
+0x6A, 0xCB, 0x62, 0xAA, 0x8B, 0xEF, 0xB5, 0x33, 
+0xC5, 0x95, 0x7B, 0x6D, 0x6A, 0xCB, 0x5A, 0x89, 
+0x83, 0xAD, 0xA4, 0xB0, 0xC5, 0xD4, 0xBD, 0xB3, 
+0xBD, 0x72, 0xDE, 0x76, 0xDE, 0x77, 0x94, 0x2F, 
+0x41, 0xE7, 0x41, 0xE7, 0x4A, 0x07, 0x52, 0x69, 
+0x94, 0x70, 0xA4, 0xD1, 0x7B, 0x8C, 0x52, 0x89, 
+0x31, 0x45, 0x18, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC4, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 
+0x19, 0x04, 0x31, 0x66, 0x5A, 0xAA, 0x9C, 0xB1, 
+0xA4, 0xD1, 0x73, 0x4C, 0x5A, 0xAB, 0x31, 0x87, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x29, 0x67, 
+0x29, 0x87, 0x21, 0x46, 0x21, 0x46, 0x21, 0x05, 
+0x18, 0xE5, 0x21, 0x05, 0x29, 0x67, 0x31, 0x87, 
+0x39, 0xC7, 0x5A, 0xAA, 0x94, 0x4F, 0xCD, 0xF5, 
+0xDE, 0x56, 0xCD, 0xD4, 0x9C, 0x90, 0x94, 0x6F, 
+0x94, 0x4F, 0x8C, 0x2F, 0x94, 0x70, 0x94, 0x6F, 
+0x8C, 0x2E, 0x94, 0x4F, 0x9C, 0xD1, 0xAD, 0x33, 
+0xAD, 0x33, 0xA4, 0xF2, 0xA4, 0xF1, 0x9C, 0xD1, 
+0x3A, 0x07, 0x42, 0x06, 0x42, 0x27, 0x62, 0xEB, 
+0x84, 0x10, 0x52, 0xAA, 0x73, 0xAF, 0xC5, 0xD7, 
+0x9C, 0x71, 0x9C, 0x71, 0x9C, 0x71, 0x8C, 0x0D, 
+0xAD, 0x32, 0xB5, 0x93, 0x83, 0xED, 0x8B, 0xEC, 
+0xAC, 0xCF, 0xA4, 0x6D, 0x94, 0x2D, 0x9C, 0x8F, 
+0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x6F, 0xA4, 0xF1, 
+0x94, 0x4E, 0x9C, 0x90, 0xA4, 0xF1, 0xAD, 0x12, 
+0x9C, 0x90, 0x9C, 0x90, 0xA4, 0xF1, 0xAD, 0x11, 
+0x7B, 0x8C, 0x83, 0xAC, 0x8C, 0x0E, 0xAD, 0x11, 
+0xBD, 0x93, 0xCD, 0xF5, 0xCE, 0x15, 0xBD, 0x72, 
+0xC5, 0xB2, 0xAC, 0xCF, 0x8B, 0xEC, 0xA5, 0x11, 
+0xAD, 0x11, 0xB5, 0x93, 0xBD, 0x93, 0xCE, 0x15, 
+0xCE, 0x35, 0xC5, 0xF4, 0xD6, 0x55, 0xC5, 0xF4, 
+0xBD, 0xB3, 0xB5, 0x73, 0xBD, 0x73, 0xBD, 0x93, 
+0x7B, 0x8C, 0x63, 0x0B, 0x6B, 0x2B, 0x4A, 0x28, 
+0x52, 0x89, 0x73, 0x8E, 0x5A, 0xEC, 0x73, 0xAE, 
+0x7B, 0xEF, 0x8C, 0x72, 0xAD, 0x55, 0x83, 0xF0, 
+0x73, 0x8E, 0xB5, 0x96, 0xAD, 0x76, 0x84, 0x10, 
+0x84, 0x10, 0x62, 0xEC, 0x39, 0xE7, 0x6B, 0x6D, 
+0xAD, 0x34, 0xB5, 0x75, 0xC5, 0xF6, 0xAD, 0x33, 
+0xA5, 0x33, 0xC6, 0x16, 0xCE, 0x36, 0xC6, 0x16, 
+0xC6, 0x15, 0xCE, 0x36, 0xC5, 0xF5, 0xCE, 0x15, 
+0xC5, 0x72, 0xB5, 0x0F, 0xEE, 0xB6, 0xD5, 0xD2, 
+0xE6, 0x54, 0xE6, 0x54, 0xEE, 0x75, 0xEE, 0xD6, 
+0xEE, 0xD6, 0xEE, 0xB5, 0xCD, 0x91, 0xD6, 0x14, 
+0xCD, 0xD3, 0xBD, 0x72, 0xC5, 0x71, 0xDE, 0x14, 
+0xC5, 0x91, 0xAC, 0xEF, 0xC5, 0xB3, 0xA4, 0xF0, 
+0x83, 0xED, 0x94, 0x2E, 0xA4, 0xF0, 0xA4, 0xF0, 
+0x9C, 0x90, 0x73, 0x6C, 0x73, 0x6C, 0x63, 0x0B, 
+0x62, 0xEB, 0x42, 0x07, 0x29, 0x44, 0x29, 0x24, 
+0x21, 0x03, 0x21, 0x03, 0x20, 0xE3, 0x29, 0x44, 
+0x39, 0xA6, 0x29, 0x64, 0x29, 0x24, 0x29, 0x64, 
+0x39, 0xA6, 0x42, 0x07, 0x39, 0xA6, 0x29, 0x24, 
+0x4A, 0x08, 0x63, 0x0C, 0x8C, 0x51, 0xA5, 0x35, 
+0x94, 0xB3, 0x9C, 0xB3, 0xA4, 0xF4, 0xB5, 0xB6, 
+0xD6, 0x78, 0xA4, 0xD0, 0xA4, 0x8F, 0x94, 0x2D, 
+0x9C, 0x6E, 0x9C, 0x6E, 0xA4, 0x8E, 0xAC, 0xF0, 
+0xAC, 0xCF, 0xB5, 0x10, 0xAC, 0xF0, 0xAC, 0xCF, 
+0xBD, 0x51, 0xBD, 0x72, 0xD6, 0x36, 0xD6, 0x36, 
+0xD6, 0x36, 0xC5, 0xB4, 0xBD, 0x73, 0xB5, 0x52, 
+0xB5, 0x32, 0xB5, 0x11, 0xAC, 0xF0, 0xAC, 0xD0, 
+0xB5, 0x11, 0xB5, 0x31, 0xB4, 0xF1, 0xBD, 0x31, 
+0xB5, 0x10, 0xAC, 0xD0, 0xAC, 0xD0, 0xAC, 0xD0, 
+0xB4, 0xF0, 0xB4, 0xF0, 0xBD, 0x31, 0xBD, 0x31, 
+0xBD, 0x31, 0xBD, 0x10, 0xBD, 0x51, 0xB5, 0x31, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xB5, 0x31, 0xB5, 0x52, 
+0xB5, 0x52, 0xB5, 0x72, 0xC5, 0xF4, 0xC5, 0xF5, 
+0xC6, 0x15, 0xC5, 0xF5, 0xC6, 0x15, 0xCE, 0x56, 
+0xCE, 0x36, 0xBD, 0xB4, 0x7B, 0xAC, 0xAC, 0xF1, 
+0xAC, 0xF0, 0xCD, 0xD4, 0xDE, 0x55, 0xDE, 0x55, 
+0xE6, 0x97, 0xC5, 0xB4, 0x6B, 0x2A, 0x39, 0xA5, 
+0x21, 0x03, 0x39, 0xE7, 0x6B, 0x2C, 0x6B, 0x2C, 
+0x73, 0x8E, 0x39, 0xC7, 0x73, 0x8E, 0x73, 0x6D, 
+0x5A, 0xAA, 0x62, 0xCA, 0x62, 0xCA, 0x6A, 0xCA, 
+0x6A, 0xEB, 0x6A, 0xAA, 0x73, 0x0B, 0x8B, 0xEE, 
+0x5A, 0x69, 0x7B, 0xAE, 0x62, 0x8A, 0x73, 0x2C, 
+0x8B, 0xCF, 0x83, 0xAE, 0x83, 0xAE, 0x8C, 0x0F, 
+0x73, 0x2B, 0x6A, 0xEA, 0x83, 0x8D, 0x94, 0x2E, 
+0xB5, 0x52, 0xEE, 0xD8, 0xBD, 0x94, 0x42, 0x08, 
+0x18, 0xC4, 0x10, 0xA3, 0x10, 0x82, 0x10, 0x83, 
+0x18, 0xE4, 0x29, 0x25, 0x20, 0xE4, 0x20, 0xE4, 
+0x18, 0xC3, 0x18, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x08, 0x83, 0x10, 0x83, 
+0x08, 0x83, 0x08, 0x83, 0x10, 0x83, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xC4, 0x10, 0xC4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC4, 
+0x19, 0x04, 0x29, 0x46, 0x39, 0xC7, 0x84, 0x0E, 
+0xBD, 0xD4, 0x8B, 0xEE, 0x6B, 0x2C, 0x39, 0xC7, 
+0x29, 0x46, 0x21, 0x26, 0x21, 0x05, 0x21, 0x05, 
+0x21, 0x05, 0x21, 0x26, 0x21, 0x26, 0x29, 0x87, 
+0x21, 0x26, 0x21, 0x26, 0x21, 0x26, 0x21, 0x05, 
+0x21, 0x05, 0x18, 0xE5, 0x19, 0x05, 0x31, 0x67, 
+0x39, 0xE8, 0x4A, 0x49, 0x5A, 0xAA, 0xAC, 0xF1, 
+0xF7, 0x19, 0xCD, 0xF4, 0xAD, 0x12, 0x8C, 0x0E, 
+0x9C, 0xB0, 0x94, 0x90, 0xA4, 0xF1, 0xA4, 0xD1, 
+0x94, 0x70, 0x94, 0x70, 0xAD, 0x12, 0xBD, 0xB4, 
+0xBD, 0x93, 0xA4, 0xF1, 0x83, 0xEE, 0x83, 0xEE, 
+0x73, 0x8D, 0x52, 0xA9, 0x39, 0xE6, 0x42, 0x07, 
+0x4A, 0x48, 0x4A, 0x48, 0x6B, 0x4D, 0x94, 0x71, 
+0x8C, 0x31, 0x39, 0xC7, 0x41, 0xE7, 0x9C, 0xB1, 
+0xD6, 0x77, 0xCE, 0x16, 0xBD, 0xB5, 0xA4, 0xB0, 
+0xA4, 0x8E, 0xA4, 0x6E, 0x8B, 0xCB, 0x83, 0xAC, 
+0x83, 0xAC, 0x94, 0x0D, 0x8C, 0x0D, 0x7B, 0x8B, 
+0x83, 0x8C, 0x83, 0xAC, 0x73, 0x4B, 0x73, 0x2A, 
+0x6A, 0xEA, 0x6B, 0x0A, 0x62, 0xC9, 0x62, 0xA9, 
+0x5A, 0xA9, 0x73, 0x2B, 0x7B, 0x4B, 0x7B, 0x8C, 
+0x7B, 0x8C, 0x83, 0xAC, 0x9C, 0x8F, 0xBD, 0x72, 
+0xCD, 0xF3, 0xAC, 0xEF, 0x9C, 0x6E, 0xBD, 0xB3, 
+0xC5, 0xF4, 0xAD, 0x31, 0x94, 0x4D, 0x94, 0x2D, 
+0x94, 0x4D, 0x9C, 0xAF, 0xC5, 0xD3, 0xC5, 0xD3, 
+0xD6, 0x55, 0xD6, 0x76, 0xDE, 0x97, 0xDE, 0x97, 
+0xBD, 0x94, 0x8C, 0x2F, 0xCE, 0x16, 0xC5, 0xF6, 
+0xA4, 0xF2, 0x8C, 0x30, 0x39, 0xE8, 0x5A, 0xEC, 
+0x63, 0x0C, 0x7B, 0xF0, 0x94, 0xB3, 0x5A, 0xEC, 
+0x84, 0x10, 0xB5, 0x96, 0xB5, 0x76, 0x73, 0x8E, 
+0x9C, 0xF4, 0x31, 0xA7, 0x73, 0x8D, 0x94, 0xB2, 
+0xD6, 0x79, 0xDE, 0xDA, 0xE6, 0xFB, 0x8C, 0x30, 
+0x4A, 0x69, 0xBD, 0xB5, 0xCE, 0x77, 0xCE, 0x56, 
+0xC6, 0x15, 0xCE, 0x56, 0xBD, 0xD4, 0xC5, 0xB3, 
+0xBD, 0x30, 0xBD, 0x50, 0xF6, 0xD6, 0xE6, 0x33, 
+0xDE, 0x13, 0xDE, 0x33, 0xE6, 0x33, 0xDE, 0x33, 
+0xE6, 0x54, 0xD5, 0xF2, 0xC5, 0x51, 0xD6, 0x14, 
+0xCD, 0xB2, 0xCD, 0xD3, 0xCD, 0xD3, 0xDE, 0x54, 
+0xC5, 0x50, 0xBD, 0x30, 0xCE, 0x14, 0xBD, 0x72, 
+0x7B, 0xAC, 0x73, 0x6B, 0xAD, 0x32, 0xC5, 0xD4, 
+0xBD, 0x73, 0x9C, 0x8F, 0x94, 0x4F, 0x8C, 0x2F, 
+0x8C, 0x2F, 0x73, 0x8C, 0x5A, 0xA9, 0x31, 0x65, 
+0x29, 0x23, 0x29, 0x64, 0x29, 0x44, 0x21, 0x03, 
+0x29, 0x24, 0x29, 0x44, 0x31, 0x85, 0x31, 0xA5, 
+0x41, 0xE6, 0x31, 0x85, 0x41, 0xE7, 0x52, 0x49, 
+0x62, 0xCB, 0x6B, 0x2C, 0xA5, 0x14, 0xAD, 0x55, 
+0xA5, 0x14, 0xA5, 0x14, 0xA4, 0xF4, 0xB5, 0xB7, 
+0xCE, 0x59, 0xBD, 0xB5, 0x9C, 0x90, 0xA5, 0x11, 
+0xB5, 0x73, 0xB5, 0x92, 0xBD, 0xB3, 0xC5, 0xB3, 
+0xC5, 0xD4, 0xBD, 0x72, 0xAC, 0xF0, 0x7B, 0x8A, 
+0xA4, 0xAF, 0xC5, 0xB4, 0xE6, 0x97, 0xCD, 0xD4, 
+0xD6, 0x15, 0xCD, 0xF5, 0xB5, 0x32, 0xCD, 0xF4, 
+0xCD, 0xD4, 0xC5, 0x72, 0xC5, 0x93, 0xD6, 0x15, 
+0xD6, 0x55, 0xDE, 0x97, 0xCD, 0xF4, 0xDE, 0x56, 
+0xDE, 0x56, 0xDE, 0x56, 0xCD, 0xB4, 0xBD, 0x52, 
+0xBD, 0x73, 0xBD, 0x52, 0xBD, 0x52, 0xC5, 0x72, 
+0xC5, 0x72, 0xC5, 0x73, 0xBD, 0x52, 0xA4, 0xB0, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xB5, 0x12, 0xB5, 0x32, 
+0xAD, 0x31, 0xA4, 0xD0, 0xA4, 0xF0, 0xAD, 0x11, 
+0xAD, 0x11, 0xB5, 0x73, 0xB5, 0x52, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAD, 0x11, 0xAD, 0x32, 
+0xAD, 0x11, 0xA4, 0xD0, 0x9C, 0x6F, 0x94, 0x4F, 
+0x94, 0x4F, 0x9C, 0x6F, 0x94, 0x2E, 0x7B, 0xAC, 
+0x41, 0xE7, 0x4A, 0x69, 0x7B, 0xEF, 0x8C, 0x30, 
+0x84, 0x10, 0x39, 0xC7, 0x8C, 0x71, 0x8C, 0x51, 
+0x9C, 0xB2, 0x9C, 0xD3, 0x83, 0xCF, 0x8C, 0x10, 
+0x83, 0xCE, 0x73, 0x6C, 0x6B, 0x0C, 0x5A, 0x8A, 
+0x62, 0xCB, 0x83, 0xCE, 0x7B, 0xAE, 0x73, 0x2C, 
+0x62, 0xCA, 0x9C, 0x50, 0x9C, 0x71, 0x8B, 0xEF, 
+0x94, 0x30, 0x73, 0x2C, 0x6A, 0xCB, 0x7B, 0x4C, 
+0x6B, 0x0B, 0xB5, 0x32, 0x7B, 0x8D, 0x20, 0xE4, 
+0x10, 0x83, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0x83, 0x08, 0x83, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0xA3, 0x18, 0xC4, 0x10, 0xA3, 
+0x10, 0x83, 0x08, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xC4, 0x20, 0xE4, 0x31, 0x66, 0x6B, 0x2B, 
+0xB5, 0x93, 0x9C, 0x70, 0x73, 0x6D, 0x42, 0x08, 
+0x29, 0x87, 0x21, 0x26, 0x19, 0x05, 0x21, 0x05, 
+0x19, 0x05, 0x21, 0x05, 0x21, 0x25, 0x29, 0x87, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x21, 0x05, 
+0x18, 0xE5, 0x19, 0x05, 0x29, 0x87, 0x31, 0xA8, 
+0x39, 0xC8, 0x39, 0xC8, 0x41, 0xC8, 0x73, 0x2C, 
+0xE6, 0x97, 0xC5, 0xD4, 0xAD, 0x32, 0x9C, 0x90, 
+0xAD, 0x53, 0xAD, 0x53, 0xB5, 0x73, 0xAD, 0x33, 
+0xA4, 0xD1, 0x9C, 0xB0, 0xBD, 0xB4, 0xBD, 0xB3, 
+0xC5, 0xD4, 0xB5, 0x73, 0x94, 0x90, 0xA4, 0xF2, 
+0x9C, 0xF3, 0x84, 0x2F, 0x7B, 0xCD, 0x6B, 0x2B, 
+0x41, 0xE6, 0x21, 0x23, 0x31, 0x85, 0x4A, 0x48, 
+0x6B, 0x2C, 0x7B, 0xAE, 0x39, 0xC6, 0x63, 0x0B, 
+0xBD, 0x95, 0xD6, 0x78, 0xDE, 0xB9, 0xD6, 0x37, 
+0xAC, 0xF2, 0x8B, 0xED, 0x94, 0x2D, 0x9C, 0x6E, 
+0xA4, 0x8E, 0xA4, 0xAF, 0xAC, 0xD0, 0xA4, 0x8E, 
+0xB5, 0x11, 0xB5, 0x31, 0xA4, 0xAF, 0xA4, 0x8F, 
+0xAC, 0xD0, 0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0x8F, 
+0x9C, 0x6E, 0x9C, 0x4E, 0x9C, 0x6E, 0xA4, 0x8E, 
+0xAC, 0xCE, 0xB4, 0xEF, 0xAC, 0xCF, 0xA4, 0xAE, 
+0xAC, 0xCF, 0xAC, 0xF0, 0x94, 0x2D, 0x94, 0x4D, 
+0x94, 0x2D, 0xB5, 0x11, 0xB5, 0x51, 0x94, 0x4D, 
+0xA4, 0xAE, 0xAD, 0x10, 0xAD, 0x10, 0xB5, 0x32, 
+0x9C, 0x4F, 0xAD, 0x11, 0xD6, 0x76, 0xE6, 0xD8, 
+0xBD, 0x94, 0x8C, 0x30, 0x42, 0x28, 0x4A, 0x48, 
+0x4A, 0x69, 0x5A, 0xCB, 0x7B, 0xEF, 0x52, 0x8A, 
+0x7B, 0xF0, 0xB5, 0x96, 0x8C, 0x51, 0x9C, 0xF3, 
+0x8C, 0x31, 0x9C, 0xB2, 0xAD, 0x55, 0x8C, 0x51, 
+0x9C, 0xB3, 0x94, 0x92, 0x94, 0x92, 0x63, 0x0C, 
+0x52, 0x6A, 0x84, 0x0F, 0xE7, 0x1A, 0xD6, 0x97, 
+0xD6, 0x77, 0xCE, 0x56, 0xCE, 0x36, 0xC5, 0xD4, 
+0xB5, 0x10, 0xC5, 0x91, 0xF6, 0xF6, 0xE6, 0x33, 
+0xDD, 0xF2, 0xD5, 0xD2, 0xDE, 0x33, 0xE6, 0x33, 
+0xD5, 0xD2, 0xCD, 0x91, 0xCD, 0xF3, 0xD6, 0x34, 
+0xD6, 0x34, 0xD5, 0xF4, 0xC5, 0x71, 0xE6, 0x54, 
+0xC5, 0x50, 0xBD, 0x50, 0xD6, 0x35, 0xC5, 0xD3, 
+0x9C, 0x6F, 0xAD, 0x32, 0xCE, 0x15, 0xCE, 0x15, 
+0xBD, 0x93, 0xC5, 0xB4, 0xA4, 0xD1, 0x94, 0x70, 
+0x94, 0x90, 0x8C, 0x4F, 0x94, 0x4F, 0x6B, 0x2B, 
+0x31, 0x85, 0x29, 0x64, 0x31, 0x85, 0x31, 0x65, 
+0x29, 0x44, 0x20, 0xE3, 0x29, 0x24, 0x31, 0x85, 
+0x31, 0x85, 0x31, 0xA5, 0x52, 0x69, 0x5A, 0xCB, 
+0x63, 0x0C, 0x6B, 0x2C, 0x73, 0x8E, 0x7B, 0xAF, 
+0x7B, 0xF0, 0x83, 0xF0, 0x94, 0xB3, 0x94, 0x92, 
+0xBD, 0xB6, 0xCE, 0x38, 0xAD, 0x54, 0xB5, 0x73, 
+0xC6, 0x15, 0xC5, 0xF4, 0xC5, 0xD3, 0xC5, 0xF4, 
+0xC5, 0xF4, 0xA4, 0xCF, 0xB5, 0x51, 0x94, 0x2E, 
+0xA4, 0xB0, 0xBD, 0xB3, 0xDE, 0x97, 0xCD, 0xF4, 
+0xD6, 0x35, 0xD6, 0x35, 0xB5, 0x31, 0xBD, 0x72, 
+0xCD, 0xF4, 0xC5, 0xB3, 0xB5, 0x31, 0xD5, 0xF4, 
+0xD6, 0x15, 0xDE, 0x76, 0xDE, 0x56, 0xD6, 0x15, 
+0xC5, 0xB3, 0xDE, 0x76, 0xE6, 0xB7, 0xDE, 0x55, 
+0xDE, 0x55, 0xDE, 0x35, 0xCD, 0xB3, 0xDE, 0x35, 
+0xB5, 0x31, 0xAC, 0xF1, 0x9C, 0x70, 0x8C, 0x0E, 
+0x9C, 0x8F, 0x9C, 0x8F, 0x9C, 0x8F, 0xA4, 0xD0, 
+0x9C, 0x8F, 0x94, 0x4E, 0xA4, 0xD0, 0xA4, 0xAF, 
+0x94, 0x2E, 0xA4, 0xD0, 0xA4, 0xF1, 0xA4, 0xF0, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xAD, 0x12, 0xB5, 0x52, 
+0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x53, 0xBD, 0x73, 
+0xC5, 0xB4, 0xBD, 0x93, 0xAD, 0x32, 0xAD, 0x12, 
+0x8C, 0x2F, 0x6B, 0x4C, 0x73, 0x8D, 0x7B, 0xCF, 
+0x7B, 0xAF, 0x39, 0xC7, 0x5A, 0xCA, 0x42, 0x08, 
+0x4A, 0x69, 0x6B, 0x4D, 0x7B, 0xCF, 0x9C, 0xD3, 
+0xAD, 0x34, 0x9C, 0x91, 0x83, 0xEE, 0x73, 0x6D, 
+0x6B, 0x0B, 0x52, 0x69, 0x6B, 0x0C, 0x7B, 0x8E, 
+0x8B, 0xEF, 0x83, 0xAD, 0x7B, 0x4C, 0x93, 0xEF, 
+0x8B, 0xEF, 0xB5, 0x13, 0xA4, 0xB2, 0x7B, 0x6D, 
+0x6A, 0xEB, 0x83, 0xAF, 0x41, 0xE7, 0x18, 0xC4, 
+0x18, 0xE4, 0x18, 0xC3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x82, 0x10, 0x83, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 
+0x18, 0xC4, 0x10, 0xA3, 0x18, 0xC3, 0x18, 0xE4, 
+0x31, 0x86, 0x4A, 0x69, 0x29, 0x65, 0x10, 0x83, 
+0x08, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0xA3, 0x18, 0xE4, 0x21, 0x04, 0x41, 0xC7, 
+0x83, 0xCE, 0xA4, 0xB1, 0x8C, 0x2F, 0x7B, 0xAE, 
+0x52, 0xAA, 0x31, 0x86, 0x21, 0x25, 0x21, 0x05, 
+0x19, 0x05, 0x18, 0xE5, 0x21, 0x25, 0x21, 0x46, 
+0x18, 0xE5, 0x18, 0xE5, 0x18, 0xE5, 0x18, 0xE4, 
+0x21, 0x25, 0x29, 0x46, 0x29, 0x66, 0x29, 0x66, 
+0x21, 0x46, 0x21, 0x25, 0x29, 0x66, 0x4A, 0x28, 
+0xBD, 0x94, 0xC5, 0xD4, 0xB5, 0x53, 0x9C, 0xB1, 
+0xAD, 0x32, 0xAD, 0x32, 0xBD, 0xB4, 0xA4, 0xD1, 
+0xA4, 0xF2, 0xA4, 0xF1, 0xBD, 0xB4, 0xAD, 0x32, 
+0xC5, 0xF5, 0xAD, 0x53, 0x9C, 0xB0, 0xAD, 0x33, 
+0x94, 0xD3, 0x84, 0x2F, 0x94, 0x6F, 0xAD, 0x32, 
+0x9C, 0xD0, 0x5A, 0xA8, 0x29, 0x64, 0x31, 0xA6, 
+0x39, 0xE7, 0x5A, 0xEB, 0x52, 0x69, 0x4A, 0x48, 
+0x6B, 0x4C, 0x94, 0x91, 0xA4, 0xF3, 0xC5, 0xF7, 
+0xE6, 0xDB, 0xBD, 0xB6, 0x52, 0x68, 0x6B, 0x09, 
+0xB5, 0x31, 0xAC, 0xCF, 0xAC, 0xCF, 0xAC, 0xF0, 
+0xBD, 0x92, 0xAC, 0xF0, 0x94, 0x4E, 0x8C, 0x2D, 
+0xB5, 0x52, 0xB5, 0x31, 0xB5, 0x30, 0xA4, 0x8E, 
+0x9C, 0x8E, 0x9C, 0x6E, 0xA4, 0xAE, 0x9C, 0x6E, 
+0x9C, 0x6E, 0x9C, 0x8E, 0xA4, 0x8E, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xB5, 0x10, 0xBD, 0x30, 0xB4, 0xEF, 
+0xB5, 0x10, 0xBD, 0x30, 0xB5, 0x30, 0xB5, 0x10, 
+0xB4, 0xEF, 0xAC, 0xCF, 0xAC, 0xCE, 0xAC, 0xCF, 
+0xAC, 0xEF, 0xB5, 0x10, 0xAC, 0xCF, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xCF, 0xA4, 0xCF, 
+0x8B, 0xCD, 0x6B, 0x0B, 0x5A, 0xCA, 0x42, 0x48, 
+0x3A, 0x07, 0x42, 0x07, 0x52, 0xAA, 0x4A, 0x69, 
+0x6B, 0x6D, 0x8C, 0x72, 0x73, 0x8E, 0x94, 0xB3, 
+0x83, 0xF0, 0x94, 0x72, 0x94, 0x71, 0x7B, 0xAF, 
+0x5A, 0xCC, 0xB5, 0x76, 0xBD, 0xB6, 0x94, 0x92, 
+0x83, 0xF0, 0x8C, 0x71, 0x7B, 0xEF, 0xB5, 0x74, 
+0xCE, 0x57, 0xD6, 0x97, 0xD6, 0x76, 0xD6, 0x75, 
+0xB5, 0x10, 0xAC, 0xCE, 0xE6, 0x54, 0xEE, 0x95, 
+0xE6, 0x13, 0xDE, 0x13, 0xE6, 0x54, 0xEE, 0x75, 
+0xC5, 0x71, 0xCD, 0xB2, 0xD5, 0xF3, 0xDE, 0x55, 
+0xCD, 0xD3, 0xC5, 0x92, 0xC5, 0x91, 0xE6, 0x75, 
+0xCD, 0x91, 0xBD, 0x51, 0xDE, 0x96, 0xDE, 0x55, 
+0xBD, 0x92, 0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xBD, 0x73, 0xAD, 0x11, 0xAD, 0x32, 
+0xAD, 0x32, 0xA4, 0xD1, 0xA4, 0xF1, 0x9C, 0x90, 
+0x29, 0x44, 0x29, 0x44, 0x31, 0x85, 0x41, 0xE7, 
+0x29, 0x24, 0x21, 0x03, 0x31, 0x65, 0x42, 0x07, 
+0x42, 0x07, 0x52, 0x69, 0x7B, 0xCF, 0xA5, 0x34, 
+0x7B, 0xAE, 0x5A, 0xAA, 0x63, 0x0C, 0x73, 0x8E, 
+0x6B, 0x4D, 0x7B, 0xCF, 0x84, 0x10, 0x94, 0x92, 
+0xA5, 0x35, 0xC6, 0x18, 0xCE, 0x38, 0xB5, 0x95, 
+0xCE, 0x15, 0xCE, 0x35, 0xB5, 0x72, 0xBD, 0xB3, 
+0xBD, 0xB3, 0xC5, 0xF4, 0xC5, 0xB3, 0xB5, 0x52, 
+0xAC, 0xD0, 0xC5, 0xB3, 0xE6, 0xB7, 0xC5, 0xB3, 
+0xB5, 0x51, 0xCD, 0xD4, 0xCD, 0xD3, 0xCD, 0xF4, 
+0xD6, 0x14, 0xD5, 0xF4, 0xC5, 0x92, 0xD5, 0xF4, 
+0xDE, 0x55, 0xDE, 0x76, 0xDE, 0x96, 0xDE, 0x75, 
+0xE6, 0xD7, 0xE6, 0xB7, 0xDE, 0x96, 0xD6, 0x34, 
+0xDE, 0x54, 0xE6, 0x75, 0xDE, 0x55, 0xDE, 0x34, 
+0xAC, 0xD0, 0xBD, 0x94, 0x94, 0x4F, 0x84, 0x0E, 
+0x8C, 0x2F, 0x94, 0x8F, 0xA4, 0xD0, 0xAD, 0x11, 
+0x94, 0x2E, 0x9C, 0xB0, 0xBD, 0x93, 0xA4, 0xF0, 
+0x9C, 0xAF, 0x94, 0x4E, 0x9C, 0xB0, 0xB5, 0x52, 
+0xA4, 0xF1, 0xA4, 0xD0, 0xBD, 0xB4, 0xB5, 0x72, 
+0xA4, 0xB0, 0xA4, 0xD0, 0xA4, 0xD0, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xAD, 0x11, 0xB5, 0x53, 0xCE, 0x15, 
+0xBD, 0x94, 0xA4, 0xF2, 0x94, 0x70, 0x84, 0x0F, 
+0x6B, 0x2C, 0x4A, 0x48, 0x4A, 0x48, 0x4A, 0x28, 
+0x31, 0x85, 0x29, 0x45, 0x29, 0x44, 0x39, 0xE7, 
+0x52, 0xAA, 0x6B, 0x4D, 0x73, 0x8E, 0x7B, 0xAE, 
+0x9C, 0xD2, 0x8C, 0x30, 0x63, 0x0C, 0x62, 0xAA, 
+0x7B, 0x6D, 0x62, 0xCA, 0x6A, 0xEB, 0x83, 0x8D, 
+0x94, 0x0F, 0xB5, 0x13, 0xB5, 0x13, 0x6B, 0x0B, 
+0x5A, 0x8A, 0x5A, 0x69, 0x49, 0xE8, 0x18, 0xC4, 
+0x21, 0x25, 0x21, 0x45, 0x10, 0xA3, 0x10, 0x82, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0x82, 0x10, 0x82, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xC3, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x4A, 0x28, 0x8C, 0x50, 
+0x94, 0x70, 0x9C, 0x90, 0x73, 0x6C, 0x31, 0xA6, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xC3, 0x18, 0xE4, 0x21, 0x05, 
+0x4A, 0x28, 0x83, 0xCE, 0xAD, 0x12, 0x9C, 0xB1, 
+0x63, 0x0B, 0x39, 0xE8, 0x29, 0x66, 0x21, 0x05, 
+0x18, 0xE4, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x18, 0xE4, 0x18, 0xE4, 0x18, 0xC4, 0x21, 0x46, 
+0x29, 0x66, 0x21, 0x25, 0x21, 0x25, 0x21, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x31, 0x87, 0x42, 0x08, 
+0x83, 0xEE, 0xBD, 0x93, 0xAD, 0x32, 0x9C, 0xB1, 
+0x9C, 0xD1, 0xAD, 0x32, 0xB5, 0x73, 0xA4, 0xF1, 
+0xA5, 0x12, 0xA4, 0xF2, 0xB5, 0x73, 0xA4, 0xD1, 
+0xC6, 0x15, 0xBD, 0x94, 0xA4, 0xF1, 0xA5, 0x12, 
+0x9C, 0xF3, 0x8C, 0x50, 0x9C, 0xD0, 0xAD, 0x52, 
+0xB5, 0x92, 0xB5, 0x93, 0x94, 0x6F, 0x4A, 0x47, 
+0x39, 0xC6, 0x41, 0xE7, 0x62, 0xEB, 0xAD, 0x34, 
+0x8C, 0x50, 0x6B, 0x0B, 0x7B, 0x8D, 0x7B, 0x8E, 
+0xC6, 0x18, 0xC5, 0xF7, 0x9C, 0xD2, 0xA4, 0xF2, 
+0xBD, 0xB3, 0xA4, 0xAF, 0xA4, 0xAF, 0xBD, 0xD4, 
+0xBD, 0xB3, 0xB5, 0x73, 0xAD, 0x32, 0x9C, 0xD1, 
+0x7B, 0x8C, 0x6B, 0x0A, 0x6B, 0x2A, 0x8C, 0x0D, 
+0xA4, 0xF0, 0xA4, 0xD0, 0x94, 0x6E, 0x94, 0x4E, 
+0x9C, 0xAF, 0x9C, 0x6F, 0x94, 0x4E, 0x8C, 0x0D, 
+0x8B, 0xEC, 0x8C, 0x0D, 0x94, 0x2D, 0x9C, 0x6E, 
+0xA4, 0xCF, 0xAC, 0xCF, 0x9C, 0x6D, 0xA4, 0xCF, 
+0xAC, 0xF0, 0xA4, 0x8E, 0x9C, 0x6D, 0x9C, 0x4D, 
+0x94, 0x0C, 0x9C, 0x6E, 0x9C, 0x8E, 0x9C, 0x6E, 
+0xA4, 0x8E, 0xA4, 0xCF, 0xAC, 0xCF, 0xA4, 0xCF, 
+0xA4, 0xB0, 0x73, 0x6C, 0x73, 0x8D, 0x4A, 0x48, 
+0x29, 0x65, 0x31, 0x85, 0x4A, 0x68, 0x42, 0x28, 
+0x5A, 0xCB, 0x6B, 0x6E, 0x5A, 0xEC, 0x6B, 0x2D, 
+0x73, 0x8E, 0x21, 0x05, 0x63, 0x0C, 0x94, 0x72, 
+0x7B, 0xAF, 0x8C, 0x31, 0x39, 0xC8, 0x63, 0x0C, 
+0xD6, 0x99, 0xE6, 0xFB, 0xAD, 0x35, 0x5A, 0xAA, 
+0x7B, 0xAD, 0xC5, 0xD5, 0xBD, 0xB4, 0xB5, 0x51, 
+0xAC, 0xAE, 0xB4, 0xEF, 0xBD, 0x30, 0xDE, 0x54, 
+0xE6, 0x75, 0xE6, 0x54, 0xE6, 0x75, 0xEE, 0x95, 
+0xE6, 0x75, 0xDE, 0x13, 0xDE, 0x13, 0xCD, 0xB2, 
+0xCD, 0x91, 0xDE, 0x34, 0xEE, 0x95, 0xE6, 0x54, 
+0xC5, 0x30, 0xBD, 0x71, 0xEE, 0xF7, 0xEE, 0xD7, 
+0xE6, 0xB6, 0xEE, 0xD7, 0xEE, 0xB6, 0xE6, 0xB6, 
+0xE6, 0x76, 0xD6, 0x15, 0xCD, 0xD4, 0xD6, 0x56, 
+0xCE, 0x15, 0xC5, 0xB3, 0xC5, 0xD4, 0xCE, 0x16, 
+0x62, 0xCA, 0x94, 0x70, 0x9C, 0x6F, 0xB5, 0x53, 
+0x94, 0x2E, 0x41, 0xE6, 0x29, 0x44, 0x42, 0x07, 
+0x4A, 0x48, 0x41, 0xE7, 0x6B, 0x2C, 0x73, 0x6D, 
+0x5A, 0xCA, 0x41, 0xE7, 0x5A, 0xAA, 0x52, 0xAA, 
+0x4A, 0x28, 0x6B, 0x2C, 0x7B, 0xAE, 0x7B, 0xCF, 
+0x9C, 0xD3, 0xBD, 0xB7, 0xCE, 0x59, 0xCE, 0x37, 
+0xBD, 0xB4, 0xC5, 0xD3, 0xCE, 0x14, 0xCE, 0x15, 
+0xCE, 0x35, 0xC5, 0xD4, 0xC5, 0xB3, 0xCD, 0xF5, 
+0xA4, 0xB0, 0xBD, 0x93, 0xE6, 0xB7, 0xCD, 0xF4, 
+0xD6, 0x15, 0xCE, 0x14, 0xCD, 0xD3, 0xC5, 0x92, 
+0xD6, 0x14, 0xCD, 0xB3, 0xCD, 0xB3, 0xD5, 0xF3, 
+0xDE, 0x55, 0xDE, 0x55, 0xDE, 0x75, 0xDE, 0x75, 
+0xE6, 0xB6, 0xD6, 0x35, 0xDE, 0x76, 0xDE, 0x55, 
+0xDE, 0x55, 0xDE, 0x75, 0xD6, 0x14, 0xD6, 0x14, 
+0xAC, 0xD0, 0xBD, 0x94, 0x83, 0xEE, 0x8C, 0x2E, 
+0x9C, 0xD1, 0x94, 0x90, 0x94, 0x6F, 0x9C, 0x8F, 
+0x9C, 0xB0, 0xAD, 0x11, 0xBD, 0x93, 0xAD, 0x11, 
+0x8C, 0x0E, 0x84, 0x2E, 0x73, 0x8C, 0x83, 0xED, 
+0xA4, 0xF1, 0xB5, 0x53, 0xC5, 0xF5, 0xCE, 0x35, 
+0xB5, 0x52, 0xAD, 0x11, 0xB5, 0x52, 0xB5, 0x73, 
+0xB5, 0x73, 0xB5, 0x52, 0xBD, 0x94, 0xC5, 0xF5, 
+0xBD, 0xB5, 0xBD, 0xB4, 0xC5, 0xF5, 0xBD, 0x94, 
+0xBD, 0xB5, 0xAD, 0x53, 0xAD, 0x73, 0xB5, 0x94, 
+0x9C, 0xD1, 0x4A, 0x48, 0x20, 0xE3, 0x21, 0x24, 
+0x21, 0x24, 0x29, 0x44, 0x29, 0x45, 0x39, 0xA6, 
+0x63, 0x0C, 0x7B, 0xEF, 0xA5, 0x13, 0x94, 0x71, 
+0x73, 0x4D, 0x73, 0x2C, 0x73, 0x2C, 0x7B, 0x4C, 
+0x83, 0x6D, 0x8B, 0xEF, 0xA4, 0x91, 0x52, 0x28, 
+0x31, 0x65, 0x52, 0x28, 0x4A, 0x28, 0x39, 0x87, 
+0x18, 0xC3, 0x19, 0x04, 0x21, 0x05, 0x18, 0xC3, 
+0x18, 0xC4, 0x10, 0xC3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC3, 
+0x10, 0xA3, 0x18, 0xC3, 0x18, 0xE4, 0x21, 0x04, 
+0x52, 0x69, 0x7B, 0xAD, 0x9C, 0x70, 0xA4, 0xB0, 
+0x9C, 0x90, 0xAC, 0xF2, 0xAC, 0xF2, 0x83, 0xEE, 
+0x41, 0xE7, 0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC3, 
+0x29, 0x46, 0x5A, 0xAA, 0x94, 0x6F, 0xAD, 0x12, 
+0x73, 0x6C, 0x5A, 0xCB, 0x42, 0x29, 0x29, 0x66, 
+0x21, 0x25, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x18, 0xE4, 0x18, 0xE4, 0x21, 0x26, 0x29, 0x67, 
+0x21, 0x25, 0x19, 0x05, 0x21, 0x05, 0x19, 0x05, 
+0x21, 0x05, 0x29, 0x46, 0x31, 0x87, 0x39, 0xC7, 
+0x52, 0x8A, 0x9C, 0xB1, 0xAD, 0x12, 0x9C, 0xB0, 
+0x9C, 0xB0, 0xA5, 0x12, 0xAD, 0x12, 0xA4, 0xF1, 
+0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x32, 0xB5, 0x73, 
+0xCE, 0x15, 0xBD, 0xB4, 0xA4, 0xF2, 0xAD, 0x53, 
+0x9C, 0xF2, 0x8C, 0x70, 0xA5, 0x11, 0xAD, 0x31, 
+0xAD, 0x32, 0xBD, 0xB3, 0xBD, 0xB3, 0xAD, 0x52, 
+0x63, 0x0A, 0x3A, 0x06, 0x39, 0xE6, 0x63, 0x0B, 
+0xA5, 0x13, 0x63, 0x0B, 0x5A, 0xCA, 0x84, 0x10, 
+0x84, 0x10, 0x8C, 0x10, 0x9C, 0xB2, 0xDE, 0x99, 
+0xC5, 0xF5, 0xA4, 0x8E, 0xAC, 0xCF, 0xC5, 0xF4, 
+0xBD, 0x93, 0xAD, 0x32, 0xAD, 0x73, 0xB5, 0x74, 
+0xA4, 0xF2, 0x8C, 0x0E, 0x7B, 0xCD, 0x8C, 0x4F, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xA5, 0x11, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x32, 
+0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x12, 0xB5, 0x73, 
+0xBD, 0x72, 0xA4, 0xAE, 0x9C, 0x6E, 0xA5, 0x11, 
+0xAD, 0x32, 0xB5, 0x52, 0xB5, 0x52, 0xA5, 0x11, 
+0x9C, 0x8F, 0xA4, 0xD0, 0xA4, 0xF0, 0xA4, 0xF0, 
+0xA4, 0xD0, 0xA4, 0xF0, 0xA4, 0xCF, 0x9C, 0x8F, 
+0xA4, 0xD0, 0x94, 0x6F, 0x8C, 0x0E, 0xA4, 0xF1, 
+0x6B, 0x2B, 0x31, 0x65, 0x31, 0x85, 0x39, 0xC7, 
+0x39, 0xC7, 0x62, 0xEC, 0x5A, 0xCB, 0x62, 0xEB, 
+0x7B, 0x8E, 0x52, 0x6A, 0x29, 0x66, 0x31, 0x86, 
+0x63, 0x0C, 0x62, 0xEC, 0x52, 0x8B, 0x94, 0x92, 
+0xD6, 0x59, 0xDE, 0x9A, 0x8C, 0x31, 0x7B, 0x8E, 
+0x41, 0xA7, 0x41, 0xC7, 0x7B, 0xAD, 0xCD, 0xD5, 
+0xBD, 0x31, 0xAC, 0xCF, 0xAC, 0xCF, 0xAC, 0xCE, 
+0xAC, 0xAE, 0xAC, 0xAE, 0xAC, 0x8D, 0xA4, 0x6D, 
+0xAC, 0x8E, 0xAC, 0x8D, 0xAC, 0xAD, 0xB4, 0xCE, 
+0xB4, 0xEE, 0xBD, 0x0F, 0xBD, 0x0F, 0xB4, 0xEE, 
+0xB4, 0xCE, 0xBD, 0x50, 0xCD, 0xB3, 0xCD, 0xD3, 
+0xD6, 0x14, 0xDE, 0x55, 0xE6, 0x75, 0xE6, 0x75, 
+0xDE, 0x75, 0xDE, 0x75, 0xE6, 0x76, 0xEE, 0xB6, 
+0xE6, 0x96, 0xE6, 0x76, 0xE6, 0x96, 0xEE, 0xB7, 
+0xE6, 0x76, 0xEE, 0xD8, 0xE6, 0xD7, 0xE6, 0x97, 
+0xD6, 0x35, 0xAC, 0xF1, 0x39, 0x85, 0x31, 0xA5, 
+0x4A, 0x27, 0x31, 0x85, 0x62, 0xCA, 0x39, 0xA6, 
+0x31, 0x65, 0x4A, 0x28, 0x4A, 0x49, 0x52, 0x69, 
+0x52, 0x89, 0x6B, 0x4C, 0x73, 0x8E, 0x7B, 0xCF, 
+0x94, 0x92, 0xB5, 0x76, 0xC6, 0x18, 0xC6, 0x17, 
+0xB5, 0x94, 0xA5, 0x11, 0xBD, 0x93, 0xB5, 0x52, 
+0xBD, 0x93, 0xAD, 0x31, 0xA4, 0xD0, 0xAC, 0xF1, 
+0xA4, 0xD0, 0xBD, 0xB4, 0xE6, 0xD8, 0xCD, 0xF4, 
+0xDE, 0x56, 0xE6, 0x97, 0xD6, 0x14, 0xC5, 0x72, 
+0xBD, 0x51, 0xAC, 0xCF, 0xBD, 0x31, 0xCD, 0xD3, 
+0xE6, 0x76, 0xE6, 0x96, 0xE6, 0xB6, 0xE6, 0xD7, 
+0xE6, 0xB7, 0xE6, 0xB7, 0xE6, 0x96, 0xE6, 0x96, 
+0xDE, 0x75, 0xDE, 0x34, 0xCD, 0xD3, 0xCD, 0xD3, 
+0xAC, 0xF0, 0xBD, 0x94, 0x83, 0xEE, 0x94, 0x90, 
+0xB5, 0x73, 0xB5, 0xB4, 0xB5, 0x73, 0xAD, 0x53, 
+0xB5, 0x94, 0xC5, 0xF4, 0xCE, 0x35, 0xBD, 0xB4, 
+0x9C, 0xB1, 0x9C, 0xF1, 0x7B, 0xAD, 0x8C, 0x4F, 
+0xAD, 0x52, 0xB5, 0x73, 0xC5, 0xD4, 0xBD, 0xD3, 
+0xBD, 0x93, 0xAD, 0x11, 0xB5, 0x73, 0xBD, 0x93, 
+0xB5, 0x73, 0xB5, 0x32, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xBD, 0xB4, 0xBD, 0xB5, 0xC6, 0x16, 0xBD, 0xD5, 
+0xBD, 0xD5, 0xC5, 0xF6, 0xC6, 0x16, 0xCE, 0x16, 
+0xC5, 0xF6, 0xA4, 0xF2, 0x9C, 0xD2, 0x8C, 0x70, 
+0x5A, 0xCA, 0x31, 0x85, 0x29, 0x44, 0x21, 0x24, 
+0x21, 0x24, 0x31, 0x85, 0x52, 0xAA, 0x7B, 0xEF, 
+0x9C, 0xB2, 0xB5, 0x35, 0x7B, 0x6D, 0x73, 0x4C, 
+0x73, 0x2C, 0x6A, 0xEB, 0x7B, 0x6D, 0x7B, 0x8E, 
+0x5A, 0x8A, 0x41, 0xC7, 0x39, 0x86, 0x5A, 0x8A, 
+0x4A, 0x08, 0x20, 0xE4, 0x18, 0xC4, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE4, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x18, 0xC4, 0x29, 0x25, 
+0x4A, 0x28, 0x52, 0x89, 0x73, 0x4C, 0x9C, 0x90, 
+0xD6, 0x36, 0xDE, 0x97, 0xD6, 0x35, 0xC5, 0xB3, 
+0xC5, 0xD4, 0xBD, 0x93, 0xBD, 0xB4, 0xBD, 0x73, 
+0x8C, 0x0E, 0x39, 0xC6, 0x10, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xC4, 0x29, 0x45, 0x83, 0xEE, 0xAC, 0xF1, 
+0xA4, 0xB0, 0x94, 0x2F, 0x6B, 0x2C, 0x42, 0x08, 
+0x29, 0x46, 0x21, 0x25, 0x19, 0x04, 0x18, 0xE4, 
+0x18, 0xE4, 0x18, 0xE5, 0x21, 0x46, 0x21, 0x25, 
+0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 0x19, 0x05, 
+0x21, 0x25, 0x29, 0x46, 0x29, 0x46, 0x29, 0x66, 
+0x41, 0xE8, 0x83, 0xEF, 0xA4, 0xB1, 0x9C, 0xB1, 
+0xA4, 0xF2, 0x9C, 0xB1, 0xA4, 0xF1, 0x9C, 0xB1, 
+0x9C, 0xD1, 0xB5, 0x94, 0x9C, 0xB0, 0xBD, 0x93, 
+0xB5, 0x93, 0xAD, 0x53, 0x9C, 0xB1, 0x9C, 0xD1, 
+0x94, 0xD1, 0x8C, 0x6F, 0xA5, 0x11, 0xA5, 0x11, 
+0xA5, 0x31, 0xAD, 0x52, 0xB5, 0x92, 0xB5, 0x92, 
+0xB5, 0x93, 0x52, 0xC8, 0x31, 0xA5, 0x31, 0xA6, 
+0x39, 0xE7, 0x42, 0x07, 0x4A, 0x48, 0x83, 0xEF, 
+0x73, 0x6D, 0x73, 0x6D, 0x6B, 0x2D, 0xC6, 0x18, 
+0xE6, 0xFB, 0x94, 0x2F, 0xA4, 0xB0, 0xC5, 0xD4, 
+0xB5, 0x52, 0xBD, 0xB4, 0xBD, 0xB5, 0xB5, 0x74, 
+0xAD, 0x53, 0xAD, 0x53, 0x9C, 0xD2, 0xA5, 0x33, 
+0xB5, 0x74, 0xAD, 0x73, 0xAD, 0x33, 0xAD, 0x33, 
+0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x53, 
+0xAD, 0x33, 0xB5, 0x73, 0xBD, 0xD4, 0xC5, 0xD4, 
+0xBD, 0xB2, 0xA4, 0xCE, 0xA4, 0xF0, 0xAD, 0x32, 
+0xC5, 0xF5, 0xCE, 0x57, 0xD6, 0x77, 0xBD, 0xB4, 
+0xAD, 0x32, 0xB5, 0x94, 0xAD, 0x52, 0xAD, 0x52, 
+0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x12, 
+0xAD, 0x32, 0xBD, 0xB4, 0xBD, 0x93, 0xCE, 0x56, 
+0xBD, 0xB3, 0x9C, 0xAF, 0x7B, 0xCD, 0x29, 0x44, 
+0x8C, 0x71, 0xCE, 0x59, 0xC6, 0x18, 0x9C, 0xB2, 
+0xBD, 0xD6, 0xCE, 0x38, 0xBD, 0xB6, 0x94, 0x92, 
+0xA5, 0x34, 0xAD, 0x35, 0xBD, 0x97, 0xCD, 0xF8, 
+0xDE, 0x7A, 0xD6, 0x59, 0xDE, 0xBA, 0xCD, 0xF8, 
+0x6A, 0xEC, 0x28, 0xE4, 0x39, 0xA7, 0x8B, 0xEF, 
+0x83, 0xAE, 0x41, 0xC7, 0xAC, 0xF1, 0xB4, 0xEF, 
+0xAC, 0xCF, 0xC5, 0x71, 0xD6, 0x14, 0xD6, 0x14, 
+0xD5, 0xF4, 0xD5, 0xF3, 0xCD, 0xB2, 0xAC, 0xCF, 
+0xAC, 0xEF, 0xAC, 0xCF, 0xA4, 0xAE, 0xAC, 0xCF, 
+0xA4, 0xAE, 0xA4, 0x8E, 0xA4, 0x6E, 0x9C, 0x4D, 
+0x9C, 0x4D, 0x9C, 0x2C, 0x94, 0x2C, 0x9C, 0x4D, 
+0xAC, 0xAE, 0xAC, 0xAE, 0xAC, 0xAE, 0xAC, 0xAE, 
+0xAC, 0xAE, 0xAC, 0xCF, 0xAC, 0xAE, 0xA4, 0x6E, 
+0xA4, 0x6D, 0x9C, 0x4D, 0x9C, 0x4D, 0xA4, 0x8F, 
+0xAC, 0xCF, 0xA4, 0xAE, 0x7B, 0x6B, 0x4A, 0x06, 
+0x39, 0xC6, 0x29, 0x44, 0x31, 0x85, 0x39, 0xC6, 
+0x41, 0xE7, 0x39, 0xC6, 0x39, 0xA6, 0x52, 0x69, 
+0x5A, 0xAA, 0x6B, 0x4C, 0x7B, 0xAE, 0x84, 0x0F, 
+0x8C, 0x51, 0xA5, 0x34, 0xB5, 0xB6, 0xBD, 0xD6, 
+0xD6, 0x98, 0xCE, 0x36, 0xCE, 0x35, 0xCE, 0x15, 
+0xC5, 0xF4, 0xBD, 0xD4, 0xB5, 0x72, 0xAD, 0x31, 
+0xA4, 0xF0, 0xB5, 0x52, 0xE6, 0xD7, 0xCD, 0xD3, 
+0xD6, 0x35, 0xEE, 0xD7, 0xD6, 0x14, 0xB5, 0x30, 
+0xB4, 0xF0, 0xBD, 0x31, 0xC5, 0x71, 0xCD, 0xD3, 
+0xE6, 0x75, 0xDE, 0x55, 0xD6, 0x14, 0xD6, 0x14, 
+0xDE, 0x55, 0xDE, 0x75, 0xD6, 0x34, 0xCD, 0xF3, 
+0xD5, 0xF3, 0xD6, 0x34, 0xCD, 0xD2, 0xCD, 0xB3, 
+0xAC, 0xF1, 0xBD, 0x74, 0x8C, 0x2E, 0x9C, 0xD1, 
+0xAD, 0x53, 0xB5, 0x94, 0xBD, 0xD5, 0xBD, 0xB4, 
+0xC5, 0xF5, 0xBD, 0xD4, 0xCE, 0x15, 0xC6, 0x15, 
+0xAD, 0x53, 0xAD, 0x32, 0x8C, 0x2F, 0x9C, 0xB0, 
+0xB5, 0x94, 0xC5, 0xF5, 0xCE, 0x35, 0xC5, 0xF4, 
+0xAD, 0x52, 0xA4, 0xD0, 0xAD, 0x32, 0xBD, 0xD4, 
+0xB5, 0x73, 0xA4, 0xF1, 0xCE, 0x15, 0xCE, 0x15, 
+0xBD, 0x94, 0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xAD, 0x33, 0xBD, 0xB5, 0xC5, 0xF5, 0xC6, 0x16, 
+0xCE, 0x36, 0xCE, 0x16, 0xCE, 0x36, 0xD6, 0x97, 
+0xCE, 0x36, 0xB5, 0x73, 0x83, 0xCE, 0x42, 0x07, 
+0x31, 0x85, 0x29, 0x65, 0x29, 0x45, 0x29, 0x65, 
+0x52, 0x8A, 0x8C, 0x51, 0x94, 0x71, 0x8C, 0x0F, 
+0x5A, 0x89, 0x5A, 0x8A, 0x62, 0xAA, 0x94, 0x30, 
+0xAC, 0xF3, 0x73, 0x2C, 0x4A, 0x08, 0x49, 0xE7, 
+0x6A, 0xCA, 0x5A, 0x69, 0x31, 0x86, 0x10, 0xA3, 
+0x18, 0xC3, 0x10, 0xA3, 0x21, 0x04, 0x52, 0xAA, 
+0x4A, 0x29, 0x42, 0x29, 0x52, 0xAA, 0x94, 0x91, 
+0x9C, 0xB1, 0x94, 0x70, 0xA4, 0xD1, 0xBD, 0x94, 
+0xAC, 0xF1, 0x94, 0x6F, 0xAC, 0xF0, 0xB5, 0x52, 
+0xB5, 0x52, 0x9C, 0xB0, 0x9C, 0x8F, 0x94, 0x4E, 
+0x9C, 0x90, 0x83, 0xCE, 0x31, 0x86, 0x18, 0xE4, 
+0x10, 0xC3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x08, 0x82, 
+0x10, 0xA3, 0x29, 0x24, 0x8C, 0x0F, 0xB5, 0x52, 
+0xBD, 0x73, 0xB5, 0x32, 0x94, 0x6F, 0x63, 0x0A, 
+0x39, 0xC7, 0x29, 0x66, 0x21, 0x05, 0x18, 0xE4, 
+0x19, 0x04, 0x19, 0x05, 0x21, 0x25, 0x19, 0x05, 
+0x18, 0xE4, 0x18, 0xE4, 0x19, 0x05, 0x21, 0x25, 
+0x21, 0x25, 0x21, 0x45, 0x21, 0x45, 0x29, 0x66, 
+0x31, 0x87, 0x73, 0x4C, 0xB5, 0x33, 0xBD, 0x94, 
+0xB5, 0x53, 0xAD, 0x32, 0xAD, 0x12, 0xA4, 0xD1, 
+0x9C, 0xB0, 0xA4, 0xD1, 0x9C, 0xB0, 0xA4, 0xD1, 
+0xA4, 0xD0, 0x94, 0x70, 0x8C, 0x0F, 0x8C, 0x2F, 
+0xB5, 0xF6, 0x7C, 0x2D, 0x94, 0xCF, 0xAD, 0x72, 
+0xAD, 0x72, 0xB5, 0x93, 0xC6, 0x15, 0xB5, 0xB2, 
+0xAD, 0x4F, 0xA5, 0x4F, 0x8C, 0x4D, 0x31, 0xA5, 
+0x29, 0x65, 0x39, 0xE6, 0x42, 0x28, 0x6B, 0x4C, 
+0x52, 0xAA, 0x52, 0xAA, 0x6B, 0x4D, 0xCE, 0x59, 
+0xCE, 0x59, 0xAD, 0x34, 0xCE, 0x58, 0xB5, 0x53, 
+0xB5, 0x93, 0xC5, 0xF5, 0xB5, 0xB5, 0xAD, 0x74, 
+0xAD, 0x53, 0xB5, 0x74, 0xA5, 0x13, 0xAD, 0x74, 
+0xAD, 0x74, 0xB5, 0x74, 0xA5, 0x32, 0xA4, 0xF2, 
+0x9C, 0xF2, 0xB5, 0x73, 0xAD, 0x53, 0xB5, 0x53, 
+0xAD, 0x33, 0xB5, 0x73, 0xB5, 0x93, 0xC6, 0x15, 
+0xC5, 0xD3, 0xA4, 0xAE, 0xAD, 0x11, 0xAD, 0x32, 
+0xB5, 0x94, 0xBD, 0xB4, 0xC5, 0xF6, 0xAD, 0x53, 
+0xB5, 0x73, 0xC5, 0xF5, 0xB5, 0x73, 0xB5, 0x73, 
+0xAD, 0x53, 0xBD, 0xB4, 0xB5, 0x53, 0xAD, 0x32, 
+0xA4, 0xF1, 0xB5, 0x73, 0xBD, 0xB4, 0xB5, 0x93, 
+0xA5, 0x11, 0x9C, 0xAF, 0xAD, 0x11, 0x52, 0x68, 
+0x84, 0x30, 0xB5, 0xB6, 0xCE, 0x18, 0x8C, 0x30, 
+0xC6, 0x18, 0xE6, 0xDB, 0xBD, 0xD7, 0xCE, 0x59, 
+0xBD, 0xD7, 0xCE, 0x59, 0xDE, 0xBB, 0xDE, 0xBA, 
+0xC5, 0xD7, 0xB5, 0x55, 0xD6, 0x38, 0xA4, 0xB2, 
+0xB5, 0x35, 0x8B, 0xEF, 0x9C, 0x71, 0xAD, 0x13, 
+0xBD, 0x95, 0xBD, 0x96, 0xD6, 0x17, 0xCD, 0xB4, 
+0xB4, 0xF0, 0xC5, 0x92, 0xCD, 0xD3, 0xC5, 0x92, 
+0xD5, 0xF3, 0xCD, 0xD3, 0xCD, 0xB3, 0xA4, 0x8E, 
+0x9C, 0x8F, 0x9C, 0x8F, 0x94, 0x6E, 0xAD, 0x10, 
+0x94, 0x6E, 0xAD, 0x31, 0xA4, 0xD0, 0x9C, 0x8F, 
+0xA4, 0xD0, 0x9C, 0xAF, 0x8C, 0x0C, 0xAC, 0xCF, 
+0x9C, 0x2C, 0x9C, 0x2C, 0x83, 0xAA, 0x8B, 0xCB, 
+0x8B, 0xEC, 0x7B, 0x6A, 0x83, 0xAB, 0x94, 0x0D, 
+0x8B, 0xCB, 0x83, 0xAB, 0x8B, 0xEC, 0x94, 0x2D, 
+0x9C, 0x4D, 0x9C, 0x6E, 0xA4, 0xAF, 0x94, 0x4E, 
+0x41, 0xE6, 0x31, 0x86, 0x39, 0xC6, 0x42, 0x07, 
+0x42, 0x07, 0x39, 0xA6, 0x4A, 0x28, 0x52, 0x89, 
+0x5A, 0xCA, 0x63, 0x0B, 0x6B, 0x2C, 0x6B, 0x6D, 
+0x84, 0x0F, 0x84, 0x30, 0xAD, 0x55, 0xAD, 0x55, 
+0xD6, 0x99, 0xB5, 0x74, 0xAD, 0x11, 0xB5, 0x52, 
+0xB5, 0x51, 0xB5, 0x51, 0xA4, 0xF0, 0xA4, 0xF0, 
+0xA4, 0xAF, 0x9C, 0x8F, 0xB5, 0x31, 0xB5, 0x31, 
+0xB5, 0x10, 0xC5, 0xB3, 0xCD, 0xB3, 0xD6, 0x14, 
+0xD6, 0x35, 0xDE, 0x56, 0xE6, 0x76, 0xDE, 0x34, 
+0xE6, 0x96, 0xDE, 0x75, 0xDE, 0x55, 0xDE, 0x34, 
+0xDE, 0x75, 0xDE, 0x55, 0xE6, 0x75, 0xDE, 0x55, 
+0xDE, 0x54, 0xEE, 0xB6, 0xE6, 0x55, 0xDE, 0x35, 
+0xB5, 0x32, 0xB5, 0x73, 0x8C, 0x4F, 0xA5, 0x32, 
+0xB5, 0x94, 0xB5, 0xB4, 0xB5, 0x94, 0xA5, 0x12, 
+0xBD, 0xD4, 0xC5, 0xF4, 0xC6, 0x15, 0xB5, 0x93, 
+0xAD, 0x53, 0xAD, 0x73, 0x9C, 0xB1, 0xA5, 0x12, 
+0xB5, 0xB4, 0xCE, 0x35, 0xD6, 0x76, 0xCE, 0x15, 
+0xAD, 0x11, 0xA4, 0xD1, 0xB5, 0x52, 0xBD, 0x93, 
+0xB5, 0x52, 0xA4, 0xF1, 0xC5, 0xD4, 0xC5, 0xF5, 
+0xAD, 0x32, 0xA5, 0x12, 0xB5, 0x53, 0xBD, 0x94, 
+0xAD, 0x32, 0xBD, 0xD5, 0xD6, 0x36, 0xC5, 0xD5, 
+0xCE, 0x36, 0xC5, 0xF5, 0xCE, 0x36, 0xCE, 0x56, 
+0xCE, 0x35, 0xD6, 0x76, 0xD6, 0x56, 0xBD, 0xD5, 
+0x8C, 0x2F, 0x4A, 0x27, 0x29, 0x65, 0x29, 0x65, 
+0x21, 0x45, 0x31, 0xA6, 0x42, 0x08, 0x94, 0x51, 
+0x9C, 0x92, 0x4A, 0x08, 0x5A, 0x8A, 0x62, 0xAA, 
+0x83, 0xAE, 0xA4, 0x91, 0x7B, 0x6D, 0x52, 0x28, 
+0x52, 0x27, 0x6A, 0xA9, 0x5A, 0x69, 0x52, 0x28, 
+0x31, 0x86, 0x31, 0x66, 0x39, 0xC7, 0x6B, 0x2C, 
+0x8C, 0x30, 0x9C, 0xD2, 0xAD, 0x34, 0xCE, 0x36, 
+0xDE, 0x97, 0xCE, 0x36, 0x9C, 0xB0, 0xAD, 0x32, 
+0xD6, 0x56, 0xCE, 0x15, 0xCE, 0x35, 0xCE, 0x15, 
+0xCE, 0x14, 0xDE, 0x96, 0xDE, 0x76, 0xCE, 0x15, 
+0xCD, 0xF5, 0xC5, 0xB4, 0x8B, 0xEE, 0x5A, 0xAA, 
+0x29, 0x65, 0x10, 0xA3, 0x10, 0x83, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 
+0x10, 0xA3, 0x21, 0x04, 0x83, 0xCE, 0xD6, 0x15, 
+0xD5, 0xF4, 0xC5, 0x72, 0xBD, 0x72, 0x9C, 0x8F, 
+0x73, 0x4C, 0x41, 0xE7, 0x29, 0x45, 0x21, 0x05, 
+0x19, 0x04, 0x19, 0x04, 0x19, 0x05, 0x19, 0x04, 
+0x18, 0xE4, 0x18, 0xE4, 0x21, 0x25, 0x21, 0x25, 
+0x21, 0x25, 0x21, 0x25, 0x21, 0x25, 0x29, 0x46, 
+0x39, 0xC7, 0x6B, 0x2C, 0x9C, 0x90, 0xA4, 0xD1, 
+0x9C, 0xB0, 0x94, 0x4F, 0x9C, 0x90, 0x9C, 0x90, 
+0x9C, 0xB0, 0xA4, 0xD0, 0xA4, 0xD0, 0xA4, 0xF1, 
+0xB5, 0x52, 0xAD, 0x12, 0xAD, 0x32, 0xB5, 0x52, 
+0x95, 0x32, 0x63, 0xCA, 0x8C, 0xEF, 0xAD, 0x72, 
+0xAD, 0x52, 0xA5, 0x31, 0xA5, 0x6F, 0x8C, 0xCA, 
+0x7C, 0x68, 0xAD, 0xAD, 0xB5, 0xB1, 0xAD, 0x31, 
+0x52, 0xA8, 0x31, 0x85, 0x42, 0x28, 0x5A, 0xCA, 
+0x4A, 0x28, 0x5A, 0xEB, 0x84, 0x10, 0xAD, 0x75, 
+0xA5, 0x34, 0xBE, 0x18, 0xEF, 0x7D, 0xDE, 0xB9, 
+0xB5, 0x94, 0xC5, 0xF5, 0xBD, 0xF6, 0xC5, 0xF6, 
+0xBD, 0xD5, 0x9C, 0xB1, 0x94, 0x70, 0xBD, 0xB5, 
+0xB5, 0xB5, 0xB5, 0xB4, 0xB5, 0x94, 0xB5, 0x73, 
+0xB5, 0x74, 0xB5, 0x94, 0xAD, 0x32, 0xBD, 0x94, 
+0xBD, 0xB4, 0xBD, 0x94, 0xBD, 0x94, 0xBD, 0xB3, 
+0xC5, 0xB3, 0xAC, 0xCE, 0xAC, 0xF0, 0xB5, 0x53, 
+0xAD, 0x12, 0xAD, 0x32, 0xB5, 0x94, 0xAD, 0x53, 
+0xB5, 0x94, 0xBD, 0xD5, 0xB5, 0x94, 0xC5, 0xD5, 
+0xB5, 0x94, 0xB5, 0x94, 0xB5, 0x73, 0xAD, 0x32, 
+0x9C, 0xD0, 0xAD, 0x52, 0xBD, 0xB4, 0xB5, 0x73, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xD0, 0x83, 0xED, 
+0x62, 0xEB, 0x9C, 0xD3, 0xB5, 0x96, 0x83, 0xEF, 
+0x9C, 0xD3, 0xBD, 0xB7, 0xAD, 0x34, 0x94, 0x92, 
+0x73, 0x8E, 0x7B, 0xCF, 0xA5, 0x14, 0xC5, 0xF7, 
+0x94, 0x72, 0x5A, 0xAA, 0x7B, 0xAE, 0xB5, 0x55, 
+0xD6, 0x38, 0xDE, 0x79, 0xAC, 0xF3, 0x94, 0x50, 
+0x6B, 0x0B, 0x6B, 0x0C, 0x73, 0x4D, 0xA4, 0x91, 
+0xD5, 0xF5, 0xD6, 0x15, 0xE6, 0x97, 0xD5, 0xF4, 
+0xD6, 0x14, 0xDE, 0x34, 0xCD, 0xB2, 0xAC, 0xCF, 
+0x9C, 0xB0, 0xA5, 0x12, 0x9C, 0xF1, 0xAD, 0x52, 
+0x9C, 0xD0, 0xAD, 0x53, 0xA5, 0x32, 0xAD, 0x53, 
+0xB5, 0x73, 0xB5, 0x73, 0xA4, 0xAF, 0xAC, 0xCF, 
+0xBD, 0x31, 0x9C, 0x8E, 0x9C, 0x8F, 0xB5, 0x72, 
+0xB5, 0x72, 0xB5, 0x52, 0x9C, 0x8F, 0xA4, 0xF1, 
+0x8C, 0x2E, 0x94, 0x4F, 0x94, 0x6F, 0x8C, 0x0E, 
+0x7B, 0xAC, 0x7B, 0x8C, 0x73, 0x4B, 0x83, 0xED, 
+0x83, 0xEE, 0x4A, 0x27, 0x31, 0x85, 0x31, 0x65, 
+0x39, 0xA6, 0x41, 0xE7, 0x4A, 0x48, 0x4A, 0x68, 
+0x5A, 0xAA, 0x63, 0x0C, 0x73, 0x6D, 0x73, 0xAE, 
+0x7B, 0xEF, 0x7B, 0xCF, 0x84, 0x10, 0xA5, 0x14, 
+0xCE, 0x59, 0xC5, 0xF7, 0xA4, 0xB0, 0xA4, 0xCF, 
+0xA4, 0xCF, 0xAC, 0xCF, 0xA4, 0xCF, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xAC, 0xF1, 0xA4, 0xB0, 0xAC, 0xF0, 
+0xAD, 0x11, 0xAC, 0xF1, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xAC, 0xD0, 0xAC, 0xF0, 0xB5, 0x11, 0xBD, 0x31, 
+0xC5, 0x92, 0xC5, 0xB3, 0xC5, 0x92, 0xC5, 0x92, 
+0xC5, 0x93, 0xCD, 0xD4, 0xCD, 0xF4, 0xD6, 0x14, 
+0xDE, 0x55, 0xD6, 0x14, 0xC5, 0x92, 0xC5, 0x93, 
+0xAC, 0xF1, 0xA4, 0xD1, 0x83, 0xED, 0x94, 0x90, 
+0xB5, 0x73, 0xB5, 0x94, 0xB5, 0x94, 0xB5, 0x94, 
+0xCE, 0x36, 0xD6, 0x77, 0xD6, 0x77, 0xBD, 0xD4, 
+0xB5, 0x73, 0xB5, 0x73, 0x9C, 0xF1, 0xA5, 0x12, 
+0xAD, 0x32, 0xCE, 0x56, 0xD6, 0x76, 0xCE, 0x56, 
+0xAD, 0x52, 0xAD, 0x11, 0xBD, 0x93, 0xAD, 0x52, 
+0xAD, 0x32, 0xA4, 0xF1, 0xC5, 0xD4, 0xBD, 0xB4, 
+0xAD, 0x32, 0xBD, 0x73, 0xBD, 0x73, 0xC5, 0xB4, 
+0x94, 0x6F, 0x83, 0xED, 0xBD, 0x93, 0xB5, 0x53, 
+0xBD, 0xB3, 0xBD, 0xB4, 0xC5, 0xF4, 0xCE, 0x15, 
+0xCE, 0x15, 0xCE, 0x35, 0xCE, 0x35, 0xD6, 0x76, 
+0xDE, 0x97, 0xCE, 0x15, 0x94, 0x6F, 0x4A, 0x27, 
+0x31, 0x85, 0x29, 0x65, 0x31, 0x85, 0x4A, 0x49, 
+0x83, 0xCF, 0x62, 0xEB, 0x52, 0x69, 0x4A, 0x28, 
+0x4A, 0x28, 0x5A, 0x69, 0x62, 0x8A, 0x4A, 0x07, 
+0x52, 0x28, 0x52, 0x07, 0x62, 0x89, 0x83, 0x8D, 
+0x62, 0x8A, 0x4A, 0x08, 0x4A, 0x29, 0x52, 0x69, 
+0x83, 0xCF, 0xCE, 0x57, 0xDE, 0xD8, 0xDE, 0x97, 
+0xE6, 0xD8, 0xBD, 0x73, 0xA4, 0xD1, 0xB5, 0x32, 
+0xE6, 0xF8, 0xE6, 0xD7, 0xDE, 0x97, 0xE6, 0xB7, 
+0xDE, 0x75, 0xDE, 0x75, 0xDE, 0x75, 0xDE, 0x96, 
+0xDE, 0x76, 0xDE, 0x55, 0xD6, 0x15, 0xBD, 0x73, 
+0x83, 0xCD, 0x39, 0xA6, 0x31, 0x65, 0x18, 0xE4, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x83, 0x08, 0x83, 
+0x08, 0x83, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x83, 0x10, 0x83, 0x10, 0x83, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC3, 0xA4, 0xD2, 0xE6, 0x76, 
+0xDE, 0x34, 0xD5, 0xF4, 0xD6, 0x14, 0xBD, 0x72, 
+0x8C, 0x2E, 0x62, 0xEA, 0x31, 0x86, 0x29, 0x45, 
+0x21, 0x25, 0x21, 0x25, 0x21, 0x25, 0x19, 0x05, 
+0x18, 0xE4, 0x19, 0x04, 0x21, 0x25, 0x19, 0x05, 
+0x19, 0x05, 0x19, 0x05, 0x21, 0x05, 0x21, 0x46, 
+0x39, 0xE8, 0x7B, 0x8D, 0x8C, 0x0E, 0x8C, 0x0E, 
+0x9C, 0x6F, 0x94, 0x4F, 0x94, 0x6F, 0x9C, 0x8F, 
+0x9C, 0xB0, 0x94, 0x4E, 0x83, 0xED, 0x9C, 0x90, 
+0xAD, 0x12, 0xAD, 0x11, 0xAC, 0xF1, 0xA4, 0xD1, 
+0x64, 0x0A, 0x64, 0x09, 0x95, 0x50, 0xBE, 0x55, 
+0x8C, 0x8E, 0x84, 0x4B, 0x74, 0x46, 0x6C, 0x65, 
+0x74, 0x65, 0xA5, 0x8B, 0xA5, 0x0D, 0xA4, 0xEE, 
+0xA5, 0x10, 0x73, 0x6B, 0x41, 0xE6, 0x42, 0x28, 
+0x4A, 0x28, 0x5A, 0xCA, 0x63, 0x2C, 0x7C, 0x10, 
+0x8C, 0x51, 0xAD, 0x55, 0xD6, 0xBA, 0xEF, 0x5C, 
+0xCE, 0x58, 0x9C, 0xD1, 0xA4, 0xD1, 0xA4, 0xF1, 
+0xAD, 0x33, 0xA5, 0x12, 0xA4, 0xF1, 0xA5, 0x12, 
+0xA5, 0x12, 0xAD, 0x33, 0xAD, 0x53, 0xAD, 0x53, 
+0xAD, 0x33, 0xAD, 0x53, 0xAD, 0x73, 0xB5, 0x74, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x73, 0xB5, 0x92, 
+0xC5, 0xD3, 0xAC, 0xCF, 0x94, 0x2D, 0x9C, 0xD0, 
+0xAD, 0x52, 0xAD, 0x53, 0xAD, 0x53, 0xA5, 0x12, 
+0xA5, 0x12, 0xB5, 0x53, 0xAD, 0x53, 0xBD, 0xB5, 
+0xAD, 0x53, 0xB5, 0x53, 0xAD, 0x52, 0xAD, 0x32, 
+0xA4, 0xF1, 0xAD, 0x52, 0xBD, 0xB4, 0xB5, 0x73, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xD0, 0x94, 0x6F, 
+0x39, 0xA6, 0x5A, 0xCB, 0x83, 0xEF, 0x73, 0x8E, 
+0x62, 0xEC, 0x7B, 0xEF, 0x6B, 0x6D, 0x52, 0x8A, 
+0x21, 0x04, 0x42, 0x08, 0xA5, 0x34, 0xCE, 0x59, 
+0xD6, 0x9A, 0xA5, 0x14, 0x62, 0xCB, 0x9C, 0x71, 
+0xAD, 0x14, 0xB5, 0x14, 0x7B, 0x4D, 0x94, 0x0F, 
+0xAC, 0xB2, 0x6B, 0x0C, 0x62, 0xCB, 0xA4, 0xB2, 
+0xEE, 0xFB, 0xF7, 0x3B, 0xDE, 0x57, 0xBD, 0x74, 
+0xB5, 0x32, 0xB5, 0x12, 0xB4, 0xF1, 0xA4, 0xAF, 
+0xAD, 0x53, 0xBE, 0x16, 0xB5, 0x94, 0xB5, 0xB4, 
+0xAD, 0x94, 0xBD, 0xF6, 0xB5, 0xB5, 0xB5, 0xD5, 
+0xB5, 0xB4, 0xB5, 0x93, 0xAC, 0xF0, 0xAC, 0xCF, 
+0xAD, 0x10, 0x9C, 0x8E, 0xB5, 0x52, 0xBD, 0x93, 
+0xBD, 0xB3, 0xBD, 0xB3, 0xBD, 0xB3, 0xB5, 0x73, 
+0xA4, 0xD1, 0xA5, 0x12, 0xAD, 0x12, 0xB5, 0x74, 
+0xB5, 0x74, 0xAD, 0x12, 0xA4, 0xD1, 0xAD, 0x32, 
+0xC5, 0xD4, 0xA4, 0xD0, 0x52, 0x47, 0x31, 0xA5, 
+0x29, 0x64, 0x31, 0x85, 0x42, 0x07, 0x4A, 0x28, 
+0x5A, 0xCA, 0x6B, 0x4C, 0x6B, 0x2C, 0x6B, 0x4C, 
+0x6B, 0x4C, 0x73, 0xAE, 0x7B, 0xEF, 0xAD, 0x55, 
+0xBD, 0xD7, 0xD6, 0x79, 0xBD, 0xB6, 0xB5, 0x73, 
+0xAD, 0x32, 0xAD, 0x32, 0xA4, 0xF0, 0xA4, 0xB0, 
+0xA4, 0xB0, 0x9C, 0xAF, 0x7B, 0xAC, 0x9C, 0x8F, 
+0x9C, 0xB0, 0xA4, 0xD1, 0xAD, 0x11, 0xAC, 0xD1, 
+0xA4, 0xD0, 0x9C, 0x90, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xAC, 0xD1, 0xAC, 0xF1, 0xAD, 0x11, 0xB5, 0x11, 
+0xB5, 0x11, 0xAD, 0x11, 0xAC, 0xF0, 0xAC, 0xF1, 
+0xAC, 0xF0, 0xAC, 0xF1, 0xBD, 0x72, 0xBD, 0x72, 
+0xBD, 0x73, 0xBD, 0x94, 0xBD, 0x94, 0xB5, 0x73, 
+0xAD, 0x32, 0xAD, 0x12, 0xA4, 0xF1, 0x94, 0x6F, 
+0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0x90, 
+0x94, 0x4F, 0x8C, 0x2E, 0x94, 0x4F, 0x9C, 0xB0, 
+0xAD, 0x32, 0xB5, 0x73, 0xC5, 0xF5, 0xCE, 0x35, 
+0xB5, 0x52, 0xAD, 0x32, 0xBD, 0x93, 0xAD, 0x52, 
+0xAD, 0x32, 0xA4, 0xD0, 0xCE, 0x15, 0xD6, 0x56, 
+0xCD, 0xD4, 0xCD, 0xD4, 0xD5, 0xF5, 0xDE, 0x76, 
+0xBD, 0x93, 0xB5, 0x53, 0xCE, 0x36, 0xCE, 0x36, 
+0xCE, 0x15, 0xCE, 0x15, 0xD6, 0x56, 0xD6, 0x55, 
+0xDE, 0x76, 0xD6, 0x56, 0xD6, 0x55, 0xD6, 0x35, 
+0xDE, 0x55, 0xDE, 0x55, 0xD6, 0x15, 0xBD, 0x73, 
+0x8C, 0x0E, 0x4A, 0x27, 0x31, 0x85, 0x29, 0x45, 
+0x31, 0xA6, 0x7B, 0xAE, 0x94, 0x91, 0x62, 0xEB, 
+0x41, 0xC7, 0x5A, 0x69, 0x5A, 0x8A, 0x4A, 0x08, 
+0x6A, 0xEB, 0x6A, 0xCB, 0x5A, 0x69, 0x7B, 0x4C, 
+0x83, 0x6D, 0x83, 0xAE, 0x5A, 0xAA, 0x5A, 0x8A, 
+0x73, 0x4C, 0xA4, 0xD2, 0xC6, 0x15, 0xE6, 0xB7, 
+0xEE, 0xF8, 0xAC, 0xD1, 0xAD, 0x12, 0xB5, 0x32, 
+0xD6, 0x76, 0xD6, 0x55, 0xDE, 0x76, 0xE6, 0xB6, 
+0xDE, 0x55, 0xE6, 0x95, 0xE6, 0x95, 0xDE, 0x75, 
+0xE6, 0x75, 0xE6, 0x96, 0xE6, 0xD7, 0xDE, 0x35, 
+0xC5, 0x94, 0xA4, 0xB1, 0xAD, 0x12, 0x4A, 0x28, 
+0x10, 0xC3, 0x10, 0x83, 0x08, 0x83, 0x10, 0x82, 
+0x10, 0x83, 0x08, 0x83, 0x08, 0x83, 0x08, 0x82, 
+0x08, 0x82, 0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 
+0x18, 0xE4, 0x21, 0x04, 0xBD, 0x94, 0xE6, 0xB7, 
+0xDE, 0x34, 0xD5, 0xF3, 0xC5, 0xB2, 0xBD, 0x52, 
+0xA4, 0xD0, 0x83, 0xAC, 0x41, 0xE7, 0x39, 0xC6, 
+0x29, 0x66, 0x21, 0x46, 0x21, 0x25, 0x19, 0x04, 
+0x18, 0xE4, 0x21, 0x05, 0x21, 0x05, 0x19, 0x05, 
+0x19, 0x04, 0x19, 0x04, 0x21, 0x05, 0x29, 0x66, 
+0x4A, 0x49, 0x8C, 0x50, 0x94, 0x6F, 0x8B, 0xED, 
+0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x32, 0xA4, 0xD0, 
+0x94, 0x6F, 0x8C, 0x0E, 0x8C, 0x2E, 0xA4, 0xF1, 
+0xB5, 0x53, 0xAD, 0x12, 0xB5, 0x52, 0xBD, 0x73, 
+0x64, 0x29, 0x64, 0x49, 0x8D, 0x4E, 0xBE, 0x75, 
+0x94, 0xCF, 0x74, 0x09, 0x74, 0x86, 0x6C, 0x64, 
+0x6C, 0x64, 0x8D, 0x09, 0x8C, 0x8B, 0x9C, 0xAD, 
+0xAD, 0x50, 0xB5, 0x50, 0x8C, 0x0C, 0x4A, 0x67, 
+0x39, 0xC6, 0x4A, 0x48, 0x52, 0xCA, 0x63, 0x0C, 
+0x8C, 0x92, 0xA5, 0x35, 0xBD, 0xF8, 0xBD, 0xD7, 
+0xDE, 0xFB, 0x9C, 0xD2, 0xA4, 0xF2, 0x94, 0x2E, 
+0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x6E, 0x94, 0x4E, 
+0x8C, 0x0C, 0x94, 0x2D, 0x9C, 0x6E, 0x94, 0x2D, 
+0x83, 0xEC, 0x83, 0xCC, 0x7B, 0xAC, 0x84, 0x0D, 
+0x94, 0x8F, 0x9C, 0x8F, 0xA4, 0xD0, 0xAD, 0x10, 
+0xB5, 0x10, 0xA4, 0x8E, 0xAC, 0xAF, 0x94, 0x2D, 
+0x83, 0xCC, 0x8C, 0x2E, 0xA4, 0xD1, 0xA5, 0x12, 
+0xBD, 0xD5, 0xAD, 0x73, 0xAD, 0x32, 0xB5, 0x73, 
+0xA4, 0xF1, 0xA4, 0xF1, 0x9C, 0xD1, 0xA4, 0xF1, 
+0xA5, 0x12, 0xB5, 0x74, 0xBD, 0x94, 0xB5, 0x53, 
+0xA4, 0xF1, 0xA4, 0xF1, 0x9C, 0xD0, 0xA5, 0x11, 
+0x5A, 0xC9, 0x6B, 0x2B, 0x73, 0x8D, 0x6B, 0x0B, 
+0x6B, 0x4B, 0x6B, 0x4C, 0x52, 0x48, 0x31, 0x65, 
+0x6B, 0x6D, 0x63, 0x0B, 0x8C, 0x30, 0xBD, 0xB6, 
+0xD6, 0x79, 0xBD, 0x96, 0xB5, 0x54, 0xC5, 0xB6, 
+0x9C, 0x91, 0x7B, 0x4D, 0x9C, 0x51, 0xCD, 0xD6, 
+0x9C, 0x51, 0x8B, 0xCF, 0xA4, 0xB2, 0x9C, 0x51, 
+0x94, 0x51, 0x94, 0x71, 0x8C, 0x31, 0xAD, 0x34, 
+0xCE, 0x38, 0xDE, 0xBA, 0xDE, 0xB9, 0xC5, 0xF6, 
+0xBD, 0xB5, 0xA5, 0x33, 0xB5, 0x94, 0xBD, 0xF5, 
+0xBD, 0xF6, 0xBD, 0xD5, 0xAD, 0x94, 0xBD, 0xF6, 
+0xBD, 0xF5, 0xB5, 0x73, 0xB5, 0x52, 0xAC, 0xEF, 
+0xB5, 0x51, 0x9C, 0x8F, 0xBD, 0xB3, 0xCE, 0x35, 
+0xB5, 0x93, 0xA4, 0xF0, 0xBD, 0xD4, 0xBD, 0x93, 
+0xAD, 0x32, 0xB5, 0x53, 0xAD, 0x12, 0xB5, 0x94, 
+0xAD, 0x12, 0xA4, 0xF2, 0xAD, 0x32, 0xB5, 0x52, 
+0xC5, 0xB3, 0xCD, 0xF4, 0x8C, 0x0E, 0x42, 0x06, 
+0x29, 0x64, 0x29, 0x43, 0x31, 0x85, 0x42, 0x07, 
+0x4A, 0x48, 0x52, 0x89, 0x6B, 0x4C, 0x73, 0x8D, 
+0x6B, 0x4D, 0x73, 0xAE, 0x7B, 0xEF, 0x94, 0xB3, 
+0xA5, 0x14, 0xAD, 0x75, 0xCE, 0x58, 0xD6, 0x78, 
+0xCE, 0x57, 0xBD, 0xB4, 0xAD, 0x11, 0xA5, 0x11, 
+0x94, 0x8F, 0x7B, 0xCC, 0x73, 0x6B, 0x8C, 0x4F, 
+0x94, 0x6F, 0xA4, 0xD1, 0xB5, 0x53, 0x94, 0x4F, 
+0xA5, 0x11, 0xB5, 0x32, 0xB5, 0x52, 0xA4, 0xD0, 
+0xA4, 0xF1, 0xAD, 0x11, 0x9C, 0xAF, 0xA4, 0xB0, 
+0xB5, 0x52, 0xBD, 0xB3, 0xB5, 0x32, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xA4, 0xF0, 0x94, 0x6E, 0x9C, 0x6F, 
+0xB5, 0x52, 0xA4, 0xD0, 0x9C, 0x6F, 0x9C, 0x8F, 
+0xA4, 0xD0, 0xA4, 0xB0, 0xAD, 0x11, 0x94, 0x6F, 
+0xAC, 0xF1, 0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x52, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xA4, 0xF1, 0xA4, 0xD0, 
+0xA4, 0xF1, 0xAD, 0x31, 0xAD, 0x32, 0xAD, 0x11, 
+0xA4, 0xD0, 0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x31, 
+0xBD, 0x73, 0xB5, 0x32, 0xAD, 0x32, 0xB5, 0x32, 
+0xAC, 0xF0, 0xAC, 0xD0, 0xA4, 0xB0, 0xB5, 0x32, 
+0xBD, 0x72, 0xAD, 0x11, 0xAD, 0x11, 0xB5, 0x52, 
+0xBD, 0x93, 0xC5, 0xB4, 0xCE, 0x15, 0xC5, 0xB3, 
+0xCD, 0xF4, 0xDE, 0x56, 0xDE, 0x55, 0xD6, 0x35, 
+0xDE, 0x55, 0xD6, 0x15, 0xD5, 0xF4, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xB5, 0x52, 0x6B, 0x0A, 0x31, 0x65, 
+0x29, 0x45, 0x31, 0x85, 0x52, 0x8A, 0x94, 0x71, 
+0x94, 0x71, 0x73, 0x2D, 0x52, 0x69, 0x52, 0x29, 
+0x52, 0x28, 0x73, 0x2C, 0x73, 0x0C, 0x5A, 0x48, 
+0x73, 0x0B, 0x73, 0x0C, 0x94, 0x10, 0x73, 0x4C, 
+0x6B, 0x0B, 0xA4, 0xB2, 0xBD, 0x95, 0xA4, 0xD1, 
+0xDE, 0x98, 0xBD, 0x73, 0xB5, 0x32, 0xBD, 0x73, 
+0xD6, 0x56, 0xDE, 0x75, 0xDE, 0x96, 0xE6, 0x96, 
+0xDE, 0x54, 0xE6, 0x75, 0xEE, 0xB6, 0xE6, 0x95, 
+0xE6, 0x75, 0xE6, 0x95, 0xE6, 0x95, 0xD6, 0x14, 
+0xDE, 0x35, 0xDE, 0x76, 0xE6, 0x97, 0x8B, 0xED, 
+0x4A, 0x28, 0x20, 0xE4, 0x10, 0x83, 0x08, 0x63, 
+0x10, 0x83, 0x10, 0x83, 0x08, 0x82, 0x08, 0x82, 
+0x08, 0x82, 0x10, 0x83, 0x10, 0xA3, 0x18, 0xC3, 
+0x18, 0xE4, 0x39, 0xA6, 0xD6, 0x56, 0xD6, 0x14, 
+0xD6, 0x13, 0xD6, 0x14, 0xDE, 0x75, 0xD6, 0x34, 
+0xC5, 0x93, 0x9C, 0x4E, 0x73, 0x4B, 0x62, 0xEA, 
+0x42, 0x07, 0x31, 0x86, 0x29, 0x46, 0x29, 0x25, 
+0x21, 0x05, 0x21, 0x05, 0x21, 0x04, 0x19, 0x04, 
+0x18, 0xE4, 0x18, 0xE4, 0x21, 0x25, 0x31, 0xA7, 
+0x73, 0x8D, 0xA4, 0xF1, 0x83, 0xCC, 0x6B, 0x0A, 
+0xAD, 0x12, 0xAD, 0x32, 0xAD, 0x32, 0xBD, 0x93, 
+0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x32, 0xA4, 0xD1, 
+0xAD, 0x12, 0xBD, 0x73, 0xCE, 0x15, 0xDE, 0x76, 
+0x64, 0x08, 0x64, 0x48, 0x74, 0xCB, 0x7C, 0x8C, 
+0x84, 0xCE, 0x8C, 0xCC, 0x74, 0x88, 0x6C, 0x65, 
+0x95, 0xCD, 0x74, 0x49, 0x7C, 0x4B, 0x8C, 0x6D, 
+0x83, 0xEB, 0x73, 0x6A, 0x8C, 0x0C, 0x9C, 0xAE, 
+0x52, 0x67, 0x39, 0xC6, 0x4A, 0x48, 0x5A, 0xCA, 
+0x6B, 0x8D, 0x8C, 0x51, 0xA5, 0x15, 0xC6, 0x19, 
+0xB5, 0x76, 0x8C, 0x51, 0xEF, 0x5C, 0xB5, 0x53, 
+0xAC, 0xF0, 0xAC, 0xF0, 0xAC, 0xF0, 0xAC, 0xEF, 
+0xB4, 0xEF, 0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x10, 
+0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x30, 0xAC, 0xCF, 
+0xAC, 0xAF, 0xAC, 0xAF, 0x9C, 0x4D, 0x9C, 0x6D, 
+0xA4, 0x6E, 0xAC, 0xEF, 0xB4, 0xEF, 0xB4, 0xCF, 
+0xB4, 0xEF, 0xB4, 0xF0, 0xA4, 0x8E, 0x94, 0x4E, 
+0x94, 0x4E, 0x8C, 0x2D, 0x8C, 0x0D, 0x8C, 0x0D, 
+0x83, 0xCD, 0x8C, 0x0D, 0x8C, 0x0D, 0x8C, 0x2E, 
+0x94, 0x4E, 0xAD, 0x11, 0xA4, 0xF1, 0x9C, 0x8F, 
+0x8C, 0x2E, 0x94, 0x4E, 0x9C, 0xB0, 0xAD, 0x11, 
+0x8C, 0x2E, 0x73, 0x8C, 0xCD, 0xF5, 0xBD, 0x92, 
+0xC5, 0xD4, 0xD6, 0x35, 0xAC, 0xF0, 0x94, 0x2E, 
+0x5A, 0xAA, 0x8C, 0x51, 0xA5, 0x14, 0xB5, 0x96, 
+0xCE, 0x59, 0xDE, 0x9A, 0xAD, 0x14, 0xBD, 0x96, 
+0xB5, 0x54, 0xA4, 0xB2, 0xBD, 0x96, 0xC5, 0xB6, 
+0xCD, 0xF8, 0xC5, 0x96, 0x8B, 0xCF, 0x83, 0xAE, 
+0x9C, 0x92, 0x7B, 0xAE, 0xB5, 0x76, 0xBD, 0xB6, 
+0xC5, 0xF7, 0xAD, 0x75, 0xB5, 0xB6, 0xE6, 0xFC, 
+0xE7, 0x3C, 0x9C, 0xF3, 0x94, 0x91, 0x9C, 0xD1, 
+0x9D, 0x12, 0xAD, 0x74, 0xB5, 0xB5, 0xC6, 0x57, 
+0xCE, 0x77, 0xCE, 0x56, 0xB5, 0x52, 0xAC, 0xF0, 
+0xB5, 0x52, 0x9C, 0xAF, 0xAD, 0x11, 0xB5, 0x52, 
+0xBD, 0x93, 0x94, 0x6F, 0xC5, 0xD4, 0xCE, 0x15, 
+0xBD, 0xB4, 0xBD, 0xD5, 0xAD, 0x53, 0xAD, 0x32, 
+0xA4, 0xD1, 0xAD, 0x32, 0xAD, 0x52, 0xAD, 0x11, 
+0xB5, 0x52, 0xCE, 0x14, 0xAC, 0xF0, 0x7B, 0xAC, 
+0x39, 0xC5, 0x31, 0x84, 0x39, 0xA6, 0x4A, 0x27, 
+0x5A, 0xCA, 0x62, 0xEB, 0x6B, 0x4C, 0x6B, 0x4D, 
+0x63, 0x0C, 0x63, 0x0C, 0x6B, 0x4D, 0x73, 0x6E, 
+0x94, 0xB3, 0xAD, 0x76, 0xC6, 0x38, 0xBD, 0xD6, 
+0xA5, 0x13, 0xA5, 0x33, 0x94, 0x90, 0xB5, 0x73, 
+0xB5, 0x93, 0x84, 0x2E, 0x84, 0x2F, 0x9C, 0xD1, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xB5, 0x73, 0x94, 0x6F, 
+0x9C, 0xB0, 0xAD, 0x11, 0xAD, 0x12, 0xA4, 0xD0, 
+0xBD, 0xB4, 0xAD, 0x52, 0x9C, 0xD0, 0x9C, 0xB0, 
+0xB5, 0x93, 0xCE, 0x35, 0xC6, 0x14, 0xC5, 0xF5, 
+0xB5, 0x73, 0xAD, 0x11, 0xAD, 0x11, 0xB5, 0x73, 
+0xBD, 0x93, 0xAD, 0x31, 0xAD, 0x31, 0xAC, 0xF1, 
+0xAD, 0x31, 0x9C, 0x8F, 0xA4, 0xF1, 0xBD, 0x94, 
+0xB5, 0x52, 0xB5, 0x52, 0x9C, 0xB0, 0xB5, 0x52, 
+0xDE, 0x76, 0xCD, 0xF4, 0xD6, 0x35, 0xD6, 0x55, 
+0xD6, 0x35, 0xB5, 0x52, 0x9C, 0x90, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xBD, 0x93, 0xAD, 0x11, 0xB5, 0x73, 
+0xB5, 0x52, 0xAC, 0xF1, 0x94, 0x2E, 0x94, 0x2E, 
+0xA4, 0x8F, 0xB5, 0x11, 0xB5, 0x52, 0x9C, 0x6F, 
+0x9C, 0x6F, 0x94, 0x2E, 0x9C, 0x4F, 0x9C, 0x6F, 
+0xA4, 0xB0, 0xA4, 0xB0, 0xA4, 0x90, 0x9C, 0x6F, 
+0xA4, 0x8F, 0x9C, 0x6F, 0x9C, 0x6E, 0x9C, 0x4E, 
+0x9C, 0x2E, 0x9C, 0x6E, 0xA4, 0x8F, 0x9C, 0x4F, 
+0x94, 0x2E, 0x9C, 0x6F, 0xA4, 0xB0, 0x8C, 0x0E, 
+0x4A, 0x27, 0x29, 0x65, 0x29, 0x45, 0x52, 0x69, 
+0x8C, 0x50, 0x8C, 0x30, 0xA4, 0xF3, 0x94, 0x51, 
+0x73, 0x6D, 0x62, 0x8A, 0x5A, 0x69, 0x5A, 0x89, 
+0x5A, 0x69, 0x62, 0xAA, 0x73, 0x0B, 0x7B, 0x6D, 
+0x5A, 0x8A, 0x62, 0xCB, 0x9C, 0x71, 0xAC, 0xD2, 
+0x83, 0xAD, 0x94, 0x2F, 0x9C, 0x70, 0xBD, 0x93, 
+0xEF, 0x18, 0xEE, 0xF7, 0xEE, 0xF7, 0xEE, 0xD6, 
+0xE6, 0xB6, 0xE6, 0x95, 0xE6, 0x95, 0xEE, 0xB5, 
+0xE6, 0x95, 0xE6, 0x74, 0xDE, 0x54, 0xDE, 0x34, 
+0xEE, 0xB6, 0xF6, 0xF7, 0xEE, 0xD7, 0xBD, 0x72, 
+0x9C, 0x6F, 0x6B, 0x0B, 0x31, 0x65, 0x10, 0x83, 
+0x10, 0xA3, 0x10, 0x83, 0x08, 0x82, 0x08, 0x82, 
+0x08, 0x82, 0x10, 0x83, 0x10, 0x83, 0x18, 0xC4, 
+0x18, 0xE4, 0x73, 0x8C, 0xE6, 0xF8, 0xD6, 0x13, 
+0xDE, 0x54, 0xDE, 0x54, 0xDE, 0x54, 0xDE, 0x54, 
+0xCE, 0x14, 0xB5, 0x52, 0xA4, 0xD0, 0x83, 0xED, 
+0x62, 0xEA, 0x39, 0xE7, 0x39, 0xE7, 0x39, 0xC7, 
+0x29, 0x46, 0x21, 0x25, 0x21, 0x04, 0x21, 0x04, 
+0x18, 0xE4, 0x21, 0x05, 0x29, 0x66, 0x52, 0x6A, 
+0xBD, 0xB5, 0xCE, 0x35, 0x94, 0x6F, 0x62, 0xC9, 
+0xAD, 0x12, 0xCE, 0x15, 0xC5, 0xF5, 0xCE, 0x15, 
+0xCE, 0x15, 0xC5, 0xD4, 0xBD, 0x94, 0xBD, 0x94, 
+0xC5, 0xD5, 0xCE, 0x15, 0xD6, 0x35, 0xD6, 0x35, 
+0x53, 0xC6, 0x64, 0x67, 0x5B, 0xC7, 0x53, 0x66, 
+0x74, 0x8C, 0x7C, 0xAC, 0x74, 0x69, 0x5B, 0xE5, 
+0xA6, 0x30, 0x95, 0x6F, 0x94, 0xEE, 0xA5, 0x0F, 
+0xB5, 0x92, 0xAD, 0x51, 0xA4, 0xF0, 0xB5, 0x50, 
+0xAD, 0x10, 0x62, 0xE9, 0x42, 0x07, 0x3A, 0x07, 
+0x4A, 0x89, 0x6B, 0x6D, 0x8C, 0x71, 0xAD, 0x76, 
+0x84, 0x11, 0x94, 0x72, 0xBD, 0xD7, 0x84, 0x30, 
+0x52, 0x68, 0x83, 0xED, 0x9C, 0x8F, 0x8C, 0x0C, 
+0x94, 0x4D, 0x9C, 0x6E, 0xA4, 0xAE, 0xB5, 0x31, 
+0xAC, 0xF0, 0xB5, 0x10, 0xB5, 0x30, 0xAC, 0xCF, 
+0xB5, 0x10, 0xAC, 0xCF, 0x9C, 0x6E, 0xA4, 0x8E, 
+0xA4, 0xAE, 0xA4, 0xAF, 0xAC, 0xAE, 0xB4, 0xEF, 
+0xAC, 0xCF, 0xB5, 0x10, 0xB4, 0xEF, 0xAC, 0xAF, 
+0xA4, 0x8E, 0xAC, 0xD0, 0xAC, 0xD0, 0xA4, 0xAF, 
+0xAC, 0xCF, 0xAC, 0xCF, 0xAC, 0xCF, 0xAC, 0xF0, 
+0xAC, 0xCF, 0xA4, 0xCF, 0xA4, 0xAF, 0xA4, 0xAE, 
+0xA4, 0xAF, 0xAC, 0xEF, 0xAC, 0xCF, 0xAC, 0xF0, 
+0xB5, 0x51, 0x7B, 0xAC, 0xA4, 0xD0, 0xA4, 0x8E, 
+0xB5, 0x10, 0xBD, 0x31, 0xB4, 0xEF, 0xC5, 0x52, 
+0x73, 0x2B, 0x4A, 0x07, 0x62, 0xCB, 0x8C, 0x30, 
+0x94, 0x51, 0xAD, 0x55, 0xE7, 0x1C, 0xA4, 0xF4, 
+0x52, 0x4A, 0x73, 0x6E, 0x73, 0x6E, 0x73, 0x4E, 
+0x73, 0x4E, 0x94, 0x72, 0x83, 0xCF, 0x9C, 0x72, 
+0x8C, 0x10, 0xA4, 0xF4, 0xC5, 0xD7, 0xA5, 0x14, 
+0x73, 0x6D, 0x52, 0x6A, 0x73, 0xAF, 0xB5, 0xB7, 
+0xCE, 0x59, 0xCE, 0x59, 0xBD, 0xD7, 0x9C, 0xD2, 
+0xB5, 0x94, 0xC6, 0x37, 0xC6, 0x37, 0xC6, 0x16, 
+0xBE, 0x15, 0xC6, 0x15, 0xAD, 0x11, 0xB5, 0x31, 
+0xB5, 0x51, 0x94, 0x4D, 0xBD, 0x92, 0x9C, 0xAF, 
+0xAD, 0x31, 0xAD, 0x11, 0xBD, 0xB3, 0xD6, 0x56, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xB5, 0x52, 0xA4, 0xF1, 
+0x94, 0x8F, 0xA5, 0x11, 0xAD, 0x32, 0xA4, 0xF1, 
+0xAD, 0x10, 0xD5, 0xF4, 0xB5, 0x31, 0xA4, 0x8F, 
+0x62, 0xC9, 0x39, 0xA5, 0x39, 0xC6, 0x4A, 0x48, 
+0x4A, 0x48, 0x4A, 0x48, 0x62, 0xEB, 0x5A, 0xEB, 
+0x52, 0x8A, 0x52, 0x8A, 0x5A, 0xEB, 0x7B, 0xCF, 
+0x94, 0x93, 0xA5, 0x14, 0xB5, 0xB6, 0xCE, 0x59, 
+0xA5, 0x34, 0xAD, 0x54, 0x94, 0x90, 0xB5, 0x93, 
+0xB5, 0x73, 0x94, 0xB0, 0xA5, 0x12, 0xB5, 0xB4, 
+0xAD, 0x33, 0xA4, 0xD1, 0xBD, 0x94, 0x9C, 0x90, 
+0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0xD4, 0xAD, 0x11, 
+0xBD, 0xB4, 0xB5, 0x93, 0xAD, 0x52, 0xA5, 0x32, 
+0xA4, 0xF1, 0xC5, 0xF4, 0xC6, 0x15, 0xBD, 0xB3, 
+0xAD, 0x52, 0xAD, 0x32, 0xAD, 0x52, 0xB5, 0x93, 
+0xBD, 0xB4, 0xC6, 0x15, 0xBD, 0xD4, 0xBD, 0xD4, 
+0xC5, 0xF4, 0xA4, 0xD0, 0xB5, 0x52, 0xBD, 0x73, 
+0xB5, 0x31, 0xC5, 0xB3, 0xBD, 0x93, 0xC5, 0xB3, 
+0xCD, 0xD3, 0xC5, 0xB2, 0xCD, 0xB3, 0xCD, 0xF3, 
+0xD6, 0x35, 0xB5, 0x32, 0x9C, 0x6F, 0xA4, 0xF1, 
+0xAD, 0x52, 0xC5, 0xD5, 0xC5, 0xD5, 0xC5, 0xD4, 
+0xB5, 0x52, 0xB5, 0x32, 0x8C, 0x2E, 0xA4, 0xD1, 
+0xB5, 0x73, 0xC5, 0xD4, 0xBD, 0xB4, 0x94, 0x6F, 
+0xA4, 0xB0, 0xAD, 0x12, 0xAC, 0xF1, 0x9C, 0x8F, 
+0x9C, 0x4E, 0x9C, 0x8F, 0xA4, 0xB0, 0xA4, 0xB0, 
+0x9C, 0x6F, 0xA4, 0x8F, 0x9C, 0x8F, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xAC, 0xF1, 0xAC, 0xD1, 
+0xA4, 0xD0, 0xAC, 0xF1, 0xB5, 0x53, 0xBD, 0x73, 
+0xAC, 0xF1, 0x73, 0x6C, 0x39, 0xA6, 0x29, 0x24, 
+0x39, 0x86, 0x5A, 0xAA, 0x8C, 0x30, 0xAD, 0x14, 
+0xBD, 0x96, 0xAD, 0x14, 0x8C, 0x10, 0x62, 0xEB, 
+0x4A, 0x08, 0x49, 0xE7, 0x62, 0xAA, 0x94, 0x0F, 
+0x8B, 0xEF, 0x62, 0xCA, 0x7B, 0x6D, 0x94, 0x0F, 
+0x8C, 0x0F, 0x5A, 0x8A, 0x5A, 0x8A, 0x83, 0xAD, 
+0xAD, 0x11, 0xAC, 0xF0, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xB5, 0x30, 0xC5, 0x51, 0xC5, 0x71, 
+0xC5, 0x71, 0xC5, 0x92, 0xCD, 0xB2, 0xCD, 0xB3, 
+0xD5, 0xF3, 0xD6, 0x14, 0xD6, 0x14, 0xC5, 0xB3, 
+0xBD, 0x52, 0xAC, 0xF1, 0x7B, 0x6C, 0x20, 0xE4, 
+0x10, 0x82, 0x10, 0x83, 0x08, 0x82, 0x08, 0x82, 
+0x08, 0x82, 0x10, 0x83, 0x10, 0xA3, 0x18, 0xC4, 
+0x18, 0xE4, 0x9C, 0xD1, 0xDE, 0x96, 0xCD, 0xD3, 
+0xDE, 0x55, 0xDE, 0x54, 0xDE, 0x54, 0xDE, 0x75, 
+0xDE, 0x55, 0xC5, 0xD3, 0xC5, 0xD4, 0xA4, 0xF1, 
+0x94, 0x6F, 0x73, 0x6C, 0x6B, 0x4B, 0x4A, 0x69, 
+0x39, 0xC7, 0x29, 0x66, 0x29, 0x46, 0x21, 0x05, 
+0x21, 0x25, 0x29, 0x66, 0x52, 0x8A, 0xA4, 0xF2, 
+0xDE, 0xB8, 0xDE, 0xB7, 0xD6, 0x56, 0xB5, 0x73, 
+0xBD, 0x93, 0xD6, 0x76, 0xCE, 0x15, 0xD6, 0x56, 
+0xCE, 0x35, 0xC5, 0xD4, 0xC5, 0xF4, 0xD6, 0x56, 
+0xD6, 0x36, 0xD6, 0x56, 0xCE, 0x14, 0xCD, 0xF4, 
+0x4B, 0x65, 0x43, 0x23, 0x53, 0xA5, 0x64, 0x28, 
+0x7C, 0xCC, 0x84, 0xCD, 0x74, 0x6A, 0x5B, 0xC6, 
+0x85, 0x2C, 0x9D, 0xD0, 0x74, 0x0A, 0x94, 0xED, 
+0xAD, 0x70, 0xA5, 0x10, 0x8C, 0x4C, 0xA4, 0xCF, 
+0xB5, 0x92, 0xBD, 0xD3, 0x63, 0x2A, 0x39, 0xE7, 
+0x3A, 0x07, 0x4A, 0x69, 0x5B, 0x0B, 0x6B, 0x4D, 
+0x9C, 0xD3, 0xBD, 0xB7, 0xAD, 0x55, 0x63, 0x2C, 
+0x73, 0x6D, 0x7B, 0xCE, 0xBD, 0xB5, 0xB5, 0x73, 
+0xAD, 0x32, 0xA4, 0xF1, 0xB5, 0x53, 0xC5, 0xD4, 
+0xBD, 0x93, 0xDE, 0x76, 0xC5, 0xB3, 0xAC, 0xEF, 
+0xBD, 0xB3, 0xB5, 0x72, 0xB5, 0x52, 0xAD, 0x31, 
+0xAD, 0x31, 0xAC, 0xF0, 0xA4, 0xCF, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xB5, 0x10, 0xAC, 0xCF, 0xA4, 0xCF, 
+0xAD, 0x10, 0xB5, 0x31, 0xAC, 0xF0, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xB5, 0x10, 0xAD, 0x10, 0xAC, 0xF0, 
+0xAD, 0x10, 0xA4, 0xAF, 0xAC, 0xAF, 0xB5, 0x30, 
+0xB5, 0x30, 0xAC, 0xEF, 0xAC, 0xCF, 0xA4, 0x8E, 
+0xB5, 0x30, 0x73, 0x8B, 0xA4, 0xF0, 0xBD, 0x71, 
+0xBD, 0x30, 0xBD, 0x30, 0xC5, 0x71, 0xCD, 0xB2, 
+0xBD, 0x31, 0x73, 0x2B, 0x5A, 0x89, 0x52, 0x49, 
+0x7B, 0xAF, 0xCE, 0x59, 0xCE, 0x39, 0xDE, 0xBB, 
+0xCE, 0x39, 0x5A, 0xAB, 0x10, 0xA4, 0x18, 0xC4, 
+0x10, 0x83, 0x4A, 0x4A, 0x94, 0x51, 0x7B, 0x8E, 
+0x94, 0x51, 0xBD, 0xD7, 0x94, 0x72, 0x83, 0xCF, 
+0x8C, 0x51, 0xA4, 0xF3, 0xBD, 0xF8, 0xBD, 0xD7, 
+0xC5, 0xF8, 0xD6, 0x9A, 0xE7, 0x3D, 0xEF, 0x3C, 
+0xB5, 0x96, 0x94, 0x91, 0x94, 0xB0, 0x94, 0x8F, 
+0xA4, 0xF0, 0xB5, 0x52, 0xB5, 0x10, 0xAC, 0xEF, 
+0xB5, 0x31, 0xA4, 0xAF, 0xA4, 0xCF, 0x83, 0xAB, 
+0x9C, 0xAF, 0xA4, 0xCF, 0xB5, 0x51, 0xCE, 0x14, 
+0xC5, 0xF4, 0xCE, 0x15, 0xBD, 0xB3, 0xB5, 0x73, 
+0xAD, 0x11, 0xAD, 0x32, 0xB5, 0x52, 0xAD, 0x32, 
+0xBD, 0x72, 0xCE, 0x14, 0xB4, 0xF0, 0xA4, 0xB0, 
+0x8C, 0x0E, 0x4A, 0x27, 0x31, 0x64, 0x39, 0xC6, 
+0x52, 0x89, 0x5A, 0xCA, 0x63, 0x2C, 0x5A, 0xEB, 
+0x4A, 0x69, 0x5A, 0xEB, 0x6B, 0x4D, 0x7B, 0xF0, 
+0x8C, 0x31, 0x94, 0x93, 0xB5, 0x96, 0xD6, 0xBA, 
+0xC6, 0x38, 0xAD, 0x75, 0xAD, 0x53, 0xB5, 0xB4, 
+0xB5, 0xD4, 0xB5, 0xB4, 0xB5, 0xB4, 0xA5, 0x53, 
+0xAD, 0x32, 0x9C, 0xB0, 0xBD, 0xB4, 0xA4, 0xD1, 
+0xBD, 0x94, 0xBD, 0xD5, 0xC5, 0xF5, 0xA5, 0x12, 
+0xB5, 0x93, 0xBD, 0xD5, 0xBD, 0xB4, 0xBD, 0xD5, 
+0xA5, 0x12, 0xBD, 0xB4, 0xC5, 0xF5, 0xBD, 0xD4, 
+0xAD, 0x32, 0xB5, 0x73, 0xA5, 0x11, 0xA5, 0x11, 
+0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x32, 
+0xBD, 0xB3, 0x9C, 0x8F, 0xB5, 0x52, 0xC5, 0x93, 
+0xC5, 0xB3, 0xD6, 0x34, 0xC5, 0xD3, 0xD6, 0x14, 
+0xD6, 0x34, 0xDE, 0x34, 0xDE, 0x34, 0xE6, 0x95, 
+0xE6, 0x75, 0xC5, 0xB3, 0xA4, 0xB0, 0xAD, 0x12, 
+0xBD, 0x94, 0xB5, 0x93, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x53, 0xBD, 0xB4, 0x9C, 0xB0, 0xB5, 0x53, 
+0xB5, 0x53, 0xBD, 0xB4, 0xCE, 0x15, 0x94, 0x4E, 
+0xAD, 0x11, 0xB5, 0x73, 0xAD, 0x11, 0xA4, 0xD0, 
+0xA4, 0xB0, 0x9C, 0x8F, 0xA4, 0xAF, 0xA4, 0xD0, 
+0x9C, 0x8F, 0xA4, 0xD0, 0xAD, 0x11, 0xB5, 0x32, 
+0xAC, 0xF1, 0xAC, 0xD1, 0xAD, 0x11, 0x9C, 0x8F, 
+0x9C, 0x8F, 0xA4, 0x8F, 0x8B, 0xED, 0x83, 0x8B, 
+0x94, 0x2E, 0x8C, 0x0D, 0x94, 0x4E, 0x52, 0x68, 
+0x29, 0x44, 0x39, 0x86, 0x41, 0xE7, 0x52, 0x49, 
+0x6A, 0xEC, 0x8C, 0x30, 0xB5, 0x55, 0xBD, 0xD7, 
+0x94, 0x92, 0x6B, 0x0C, 0x41, 0xC7, 0x73, 0x2C, 
+0x9C, 0x50, 0x9C, 0x91, 0x73, 0x2C, 0x73, 0x4D, 
+0x7B, 0x8D, 0x52, 0x69, 0x6B, 0x0C, 0x83, 0xEF, 
+0x94, 0x2F, 0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x32, 
+0xB5, 0x32, 0xB5, 0x12, 0xB5, 0x12, 0xB5, 0x12, 
+0xAC, 0xF2, 0xAD, 0x12, 0xB5, 0x53, 0xB5, 0x12, 
+0xAC, 0xF1, 0xA4, 0xD1, 0xAC, 0xF1, 0xAD, 0x11, 
+0xAD, 0x11, 0xAD, 0x11, 0x94, 0x4F, 0x39, 0xA6, 
+0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 
+0x10, 0x82, 0x10, 0x82, 0x10, 0xC3, 0x18, 0xC3, 
+0x31, 0xA7, 0x94, 0x70, 0xA4, 0xD0, 0xAD, 0x11, 
+0xB5, 0x31, 0xBD, 0x92, 0xBD, 0x92, 0xBD, 0x72, 
+0xBD, 0x72, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x11, 
+0xA4, 0xF1, 0x8C, 0x2E, 0x83, 0xED, 0x6B, 0x0B, 
+0x52, 0x89, 0x42, 0x08, 0x31, 0xA7, 0x31, 0x86, 
+0x39, 0xA7, 0x4A, 0x69, 0x7B, 0xCE, 0x9C, 0xD1, 
+0xBD, 0xD4, 0xB5, 0x52, 0xBD, 0xB4, 0x94, 0x4F, 
+0x83, 0xED, 0xDE, 0x97, 0xD6, 0x77, 0xD6, 0x56, 
+0xD6, 0x56, 0xD6, 0x57, 0xD6, 0x77, 0xD6, 0x77, 
+0xBD, 0xB4, 0xB5, 0x73, 0xBD, 0x93, 0xBD, 0x73, 
+0x32, 0xA3, 0x6C, 0x4A, 0x9D, 0xD2, 0x9D, 0xB2, 
+0x74, 0x4C, 0x7C, 0x8C, 0x7C, 0xAB, 0x7C, 0x8A, 
+0x6C, 0x49, 0x74, 0x6A, 0x8D, 0x0C, 0x84, 0xA9, 
+0x84, 0xCA, 0x8C, 0xAC, 0x8C, 0x6C, 0xA4, 0xCE, 
+0xC5, 0xD3, 0xC6, 0x15, 0xC5, 0xF5, 0x7B, 0xCE, 
+0x39, 0xE6, 0x39, 0xE6, 0x42, 0x48, 0x5A, 0xEB, 
+0x84, 0x31, 0x84, 0x10, 0x94, 0x92, 0x73, 0x6D, 
+0x7B, 0xAF, 0xBD, 0xD7, 0xD6, 0x79, 0xC6, 0x16, 
+0xBD, 0xD5, 0xBD, 0xD5, 0xCE, 0x57, 0xCE, 0x56, 
+0xAD, 0x31, 0xC5, 0xD3, 0xBD, 0x72, 0xB5, 0x30, 
+0xC5, 0xD4, 0xB5, 0xB4, 0xB5, 0xB4, 0xBD, 0xD4, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xBD, 0xD4, 0xC5, 0xF4, 
+0xC5, 0xF4, 0xC5, 0xD3, 0xBD, 0xB3, 0xC5, 0xD4, 
+0xCE, 0x35, 0xD6, 0x55, 0xD6, 0x76, 0xD6, 0x76, 
+0xCE, 0x35, 0xCE, 0x14, 0xC5, 0xD4, 0xBD, 0x93, 
+0xC5, 0xD3, 0xBD, 0x92, 0xAC, 0xCF, 0xAC, 0xEF, 
+0xAC, 0xCF, 0x9C, 0x4D, 0x94, 0x4D, 0x94, 0x0C, 
+0x94, 0x2D, 0x5A, 0xC9, 0x73, 0xAC, 0x8C, 0x2D, 
+0x94, 0x4D, 0x8B, 0xEC, 0xA4, 0xAE, 0x9C, 0x6D, 
+0x9C, 0x4D, 0x94, 0x2F, 0x5A, 0xA9, 0x52, 0x69, 
+0x8C, 0x31, 0xAD, 0x55, 0x62, 0xEC, 0xB5, 0x97, 
+0xE6, 0xFC, 0xE7, 0x1C, 0x9C, 0xB3, 0x52, 0x8A, 
+0x31, 0x87, 0x52, 0xAB, 0x39, 0xC7, 0x4A, 0x29, 
+0x8C, 0x51, 0x94, 0x92, 0x62, 0xEC, 0x83, 0xEF, 
+0xA4, 0xF3, 0xAD, 0x75, 0xB5, 0xB7, 0xBD, 0xB7, 
+0xBD, 0xF8, 0xD6, 0x9B, 0xD6, 0x9A, 0xCE, 0x59, 
+0xCE, 0x59, 0xC5, 0xF7, 0xAD, 0x54, 0xA4, 0xD1, 
+0xA4, 0xAF, 0xA4, 0x8E, 0xAC, 0xEF, 0xB5, 0x0F, 
+0xAD, 0x10, 0xAC, 0xEF, 0xB4, 0xEF, 0xAC, 0xEF, 
+0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xCF, 0xAC, 0xEF, 
+0xAD, 0x10, 0xB5, 0x31, 0xB5, 0x30, 0xB5, 0x51, 
+0xB5, 0x52, 0xCD, 0xD4, 0xAC, 0xF1, 0xC5, 0x93, 
+0xA4, 0xD0, 0xAC, 0xF0, 0x9C, 0x4E, 0xB5, 0x11, 
+0xAC, 0xD1, 0x6B, 0x0A, 0x42, 0x07, 0x42, 0x27, 
+0x4A, 0x68, 0x4A, 0x48, 0x52, 0x8A, 0x5A, 0xCB, 
+0x52, 0xAA, 0x5A, 0xEB, 0x73, 0x8E, 0x84, 0x11, 
+0x84, 0x11, 0x94, 0xB3, 0xB5, 0x96, 0xB5, 0x97, 
+0xC6, 0x39, 0xCE, 0x79, 0xB5, 0x94, 0xBD, 0xF5, 
+0xBD, 0xF5, 0xA5, 0x12, 0xA5, 0x32, 0xAD, 0x53, 
+0xB5, 0xB4, 0x9C, 0xB1, 0xBD, 0xB4, 0xA4, 0xF2, 
+0xB5, 0x73, 0xBD, 0xB4, 0xC6, 0x16, 0xB5, 0x94, 
+0xBD, 0xB4, 0xBD, 0xF5, 0xBD, 0xF5, 0xC6, 0x36, 
+0xB5, 0x73, 0xB5, 0x94, 0xBD, 0xD4, 0xC6, 0x16, 
+0xBD, 0xD5, 0xB5, 0xB4, 0xB5, 0xB4, 0xAD, 0x32, 
+0x9C, 0xD1, 0x9C, 0xD1, 0x9C, 0xD0, 0xBD, 0xB4, 
+0xAD, 0x31, 0x9C, 0x8F, 0xB5, 0x52, 0xC5, 0xB3, 
+0xCD, 0xD2, 0xD6, 0x13, 0xC5, 0x92, 0xCD, 0xF3, 
+0xDE, 0x34, 0xDE, 0x54, 0xDE, 0x54, 0xE6, 0xB5, 
+0xDE, 0x55, 0xD6, 0x14, 0xA4, 0xB0, 0xAD, 0x32, 
+0xBD, 0x94, 0xB5, 0x94, 0xB5, 0x94, 0xBD, 0x94, 
+0xBD, 0xB4, 0xBD, 0xB5, 0xAD, 0x53, 0xB5, 0x73, 
+0xBD, 0x94, 0xC5, 0xD4, 0xD6, 0x56, 0x94, 0x4E, 
+0xAD, 0x32, 0xBD, 0x93, 0xA4, 0xF1, 0xA4, 0x90, 
+0xA4, 0xD0, 0x9C, 0x8F, 0xA4, 0xAF, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xAD, 0x11, 0xB5, 0x52, 0xBD, 0x73, 
+0xBD, 0x72, 0xBD, 0x72, 0xB5, 0x52, 0xB5, 0x31, 
+0xB5, 0x31, 0xB5, 0x31, 0x9C, 0x8F, 0x8B, 0xED, 
+0x8B, 0xCC, 0x94, 0x2D, 0xAC, 0xF0, 0xA4, 0xD0, 
+0x83, 0xED, 0x52, 0x67, 0x29, 0x65, 0x29, 0x45, 
+0x39, 0x85, 0x41, 0xC7, 0x4A, 0x69, 0x7B, 0xCF, 
+0x9C, 0xF3, 0x94, 0x71, 0x41, 0xE8, 0x5A, 0x8A, 
+0x73, 0x0B, 0x94, 0x30, 0x8B, 0xEF, 0x5A, 0xAA, 
+0x4A, 0x49, 0x52, 0x49, 0x4A, 0x28, 0x73, 0x6D, 
+0x94, 0x50, 0x8C, 0x0E, 0xB5, 0x32, 0xAC, 0xF1, 
+0xCD, 0xF5, 0xBD, 0x93, 0xB5, 0x12, 0xB5, 0x52, 
+0xBD, 0x73, 0xBD, 0x52, 0xBD, 0x94, 0xBD, 0x73, 
+0xB5, 0x52, 0xAD, 0x32, 0xBD, 0x73, 0xB5, 0x73, 
+0xB5, 0x73, 0xB5, 0x53, 0xAD, 0x33, 0x4A, 0x48, 
+0x18, 0xA3, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 
+0x10, 0x82, 0x10, 0xA3, 0x18, 0xE4, 0x18, 0xE4, 
+0x63, 0x2C, 0xB5, 0x53, 0xAC, 0xF1, 0xB5, 0x32, 
+0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x32, 0xB5, 0x52, 
+0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x52, 
+0xAD, 0x32, 0xA4, 0xD1, 0x94, 0x4F, 0x8B, 0xEE, 
+0x73, 0x6C, 0x63, 0x0B, 0x52, 0x89, 0x52, 0x89, 
+0x63, 0x0B, 0x84, 0x0E, 0x83, 0xEE, 0x83, 0xCE, 
+0xA4, 0xD1, 0xAD, 0x32, 0xA4, 0xD1, 0x73, 0x8C, 
+0x62, 0xEB, 0x73, 0x4C, 0x7B, 0x8D, 0x83, 0xCD, 
+0x83, 0xEE, 0x83, 0xEE, 0x83, 0xEE, 0x73, 0x6C, 
+0x62, 0xEA, 0x73, 0x4C, 0x7B, 0x6C, 0x94, 0x2E, 
+0x85, 0x0E, 0xA5, 0xF3, 0xA5, 0xD4, 0xA5, 0xB4, 
+0xA5, 0xB3, 0x7C, 0x8D, 0x84, 0xCC, 0x8C, 0xCC, 
+0x85, 0x0C, 0x4B, 0x45, 0x64, 0x06, 0x6C, 0x25, 
+0x7C, 0x68, 0xA5, 0x2E, 0xA4, 0xEE, 0x9C, 0xCE, 
+0x8C, 0x4D, 0xAD, 0x72, 0xC5, 0xF5, 0xBD, 0xD5, 
+0x8C, 0x4F, 0x39, 0xE6, 0x42, 0x48, 0x63, 0x4D, 
+0x8C, 0x51, 0x84, 0x31, 0x7B, 0xEF, 0x73, 0x6E, 
+0x7B, 0xAF, 0xC6, 0x18, 0xCE, 0x79, 0xEF, 0x7D, 
+0xC6, 0x37, 0xB5, 0xB5, 0xCE, 0x57, 0xC5, 0xD5, 
+0xA4, 0xF1, 0xD6, 0x36, 0xBD, 0x51, 0xAC, 0xCF, 
+0xBD, 0x93, 0xBD, 0xD4, 0xBD, 0xD5, 0xC5, 0xF5, 
+0xBD, 0xF4, 0xBD, 0xF4, 0xBD, 0xD4, 0xC5, 0xD4, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xBD, 0xD4, 0xC5, 0xF4, 
+0xC5, 0xD4, 0xC5, 0xF4, 0xCE, 0x35, 0xCE, 0x14, 
+0xCE, 0x15, 0xCE, 0x15, 0xD6, 0x56, 0xC5, 0xD4, 
+0xC5, 0xF4, 0xC5, 0xD3, 0xAC, 0xCF, 0xAC, 0xEF, 
+0xBD, 0x93, 0xB5, 0x72, 0xAD, 0x31, 0xA4, 0xD0, 
+0x8C, 0x0D, 0x7B, 0xAC, 0x8C, 0x6F, 0x94, 0x8F, 
+0x8C, 0x4D, 0x84, 0x0D, 0xA4, 0xF0, 0x9C, 0xAF, 
+0x94, 0x4E, 0x84, 0x0E, 0x7B, 0xAD, 0x62, 0xEA, 
+0x52, 0xAA, 0x73, 0xAF, 0x8C, 0x72, 0xC6, 0x18, 
+0xCE, 0x7A, 0xD6, 0xBB, 0xC5, 0xF8, 0xB5, 0x76, 
+0x94, 0x72, 0x8C, 0x31, 0x63, 0x0C, 0x7B, 0xEF, 
+0x6B, 0x2C, 0x7B, 0xAE, 0x7B, 0xAF, 0x8C, 0x31, 
+0x9C, 0xD3, 0xB5, 0x76, 0xB5, 0x96, 0x9C, 0xD4, 
+0xC6, 0x18, 0xBD, 0xB7, 0x9C, 0xD4, 0xA5, 0x15, 
+0xBD, 0xF8, 0xD6, 0x9A, 0xE7, 0x1B, 0xDE, 0x78, 
+0xCD, 0xD3, 0xC5, 0x71, 0xCD, 0xF3, 0xCD, 0xD2, 
+0xBD, 0x50, 0xC5, 0x91, 0xC5, 0x91, 0xBD, 0x30, 
+0xBD, 0x50, 0xBD, 0x50, 0xB5, 0x10, 0xAC, 0xEF, 
+0xB4, 0xEF, 0xAC, 0xCE, 0xA4, 0xAE, 0xAC, 0xEF, 
+0xB4, 0xEF, 0xAC, 0xCF, 0xAC, 0xCF, 0xAC, 0xF0, 
+0xAC, 0xAF, 0x9C, 0x6E, 0xA4, 0xAF, 0xAC, 0xAF, 
+0x9C, 0x6F, 0x73, 0x4B, 0x52, 0x48, 0x39, 0xA5, 
+0x3A, 0x06, 0x4A, 0x48, 0x4A, 0x48, 0x4A, 0x69, 
+0x52, 0x89, 0x52, 0x8A, 0x6B, 0x6D, 0x7B, 0xEF, 
+0x84, 0x10, 0x8C, 0x31, 0xAD, 0x35, 0xAD, 0x76, 
+0xB5, 0xD7, 0xC6, 0x58, 0xB5, 0xB5, 0xA5, 0x12, 
+0xBD, 0xB4, 0xA5, 0x32, 0xAD, 0x53, 0xBD, 0xF6, 
+0xAD, 0x32, 0x94, 0x90, 0xBD, 0x94, 0xA4, 0xF1, 
+0xCE, 0x36, 0xBD, 0xF5, 0xC6, 0x36, 0xCE, 0x37, 
+0xC6, 0x16, 0xBD, 0xF5, 0xBD, 0xD5, 0xBD, 0xD5, 
+0xBD, 0xD5, 0xB5, 0xB4, 0xBD, 0xF5, 0xBD, 0xF5, 
+0xC6, 0x36, 0xC5, 0xF5, 0xC6, 0x16, 0xC6, 0x16, 
+0xBD, 0xD5, 0xAD, 0x52, 0xAD, 0x52, 0xC5, 0xF5, 
+0x94, 0x6E, 0xA4, 0xF0, 0xB5, 0x32, 0xC5, 0xB3, 
+0xD6, 0x13, 0xDE, 0x55, 0xDE, 0x34, 0xD6, 0x14, 
+0xDE, 0x54, 0xDE, 0x54, 0xDE, 0x54, 0xDE, 0x54, 
+0xDE, 0x54, 0xD6, 0x34, 0xA4, 0xF0, 0xAD, 0x32, 
+0xB5, 0x93, 0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0xD5, 
+0xC5, 0xD5, 0xC5, 0xF5, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xC5, 0xD5, 0xCE, 0x15, 0xCE, 0x15, 0x9C, 0x8F, 
+0xB5, 0x32, 0xC5, 0xD4, 0xBD, 0x73, 0xAD, 0x11, 
+0xB5, 0x11, 0xAC, 0xD0, 0xA4, 0xD0, 0xAC, 0xF1, 
+0xAC, 0xF1, 0xAC, 0xF0, 0xAD, 0x11, 0xAD, 0x11, 
+0xAC, 0xF0, 0xAD, 0x31, 0xB5, 0x31, 0xAD, 0x10, 
+0xB5, 0x31, 0xB5, 0x31, 0xB5, 0x31, 0xAD, 0x10, 
+0xA4, 0xAF, 0x9C, 0x6E, 0x9C, 0x6E, 0xAD, 0x11, 
+0xBD, 0xB3, 0xB5, 0x92, 0x73, 0x6B, 0x29, 0x65, 
+0x21, 0x24, 0x21, 0x03, 0x29, 0x45, 0x31, 0xA6, 
+0x3A, 0x07, 0x39, 0xC7, 0x39, 0xA6, 0x52, 0x49, 
+0x4A, 0x28, 0x5A, 0x69, 0x83, 0xCE, 0x83, 0xCE, 
+0x4A, 0x28, 0x62, 0xCB, 0x52, 0x69, 0x52, 0x8A, 
+0x73, 0x4D, 0x94, 0x71, 0x94, 0x2F, 0x94, 0x4F, 
+0xBD, 0x73, 0xEE, 0xD7, 0xD6, 0x15, 0xDE, 0x55, 
+0xDE, 0x35, 0xCD, 0xD3, 0xC5, 0xB3, 0xCD, 0xD4, 
+0xCD, 0xB3, 0xD6, 0x55, 0xC5, 0xD4, 0xAD, 0x11, 
+0xB5, 0x73, 0xB5, 0x73, 0xBD, 0x94, 0x42, 0x07, 
+0x10, 0xA3, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 
+0x10, 0xA3, 0x10, 0xC3, 0x18, 0xE4, 0x18, 0xE4, 
+0x73, 0x8D, 0x9C, 0xD1, 0xAD, 0x11, 0xB5, 0x73, 
+0xAC, 0xF1, 0xB5, 0x73, 0xA4, 0xD0, 0x94, 0x4F, 
+0xA4, 0xD0, 0xA4, 0xD1, 0x94, 0x4F, 0x9C, 0x6F, 
+0x9C, 0x8F, 0xA4, 0xD1, 0x94, 0x4F, 0xA4, 0xD0, 
+0x8C, 0x2E, 0x8C, 0x0E, 0x7B, 0xAD, 0x8C, 0x0F, 
+0xA5, 0x12, 0xB5, 0x73, 0xBD, 0xB5, 0xBD, 0x94, 
+0xBD, 0x94, 0xBD, 0x94, 0xBD, 0x94, 0xB5, 0x53, 
+0xAD, 0x33, 0xAD, 0x33, 0xAD, 0x13, 0xA4, 0xF2, 
+0xA4, 0xF2, 0xA4, 0xD2, 0x9C, 0xD2, 0x9C, 0x91, 
+0x94, 0x70, 0x8C, 0x2F, 0x94, 0x4F, 0x8C, 0x0E, 
+0x8C, 0xEF, 0x7C, 0x8E, 0xAD, 0xF5, 0x9D, 0x93, 
+0x8D, 0x31, 0x7C, 0xAD, 0x64, 0x09, 0x74, 0x49, 
+0x85, 0x0C, 0x63, 0xC7, 0x4B, 0x43, 0x63, 0xE5, 
+0x6B, 0xE7, 0x6B, 0xC8, 0x8C, 0x8B, 0x6B, 0x87, 
+0x8C, 0x8D, 0xAD, 0x72, 0xB5, 0x73, 0xB5, 0x73, 
+0xBD, 0xD4, 0x7B, 0xCD, 0x4A, 0x68, 0x63, 0x0B, 
+0x6B, 0x2C, 0x6B, 0x4C, 0x6B, 0x2C, 0x5A, 0xAB, 
+0x8C, 0x71, 0x9C, 0xF3, 0xC6, 0x39, 0xE6, 0xFC, 
+0xDE, 0xFB, 0xD6, 0xBA, 0x9C, 0xD2, 0x73, 0x6D, 
+0x9C, 0xB2, 0xAD, 0x53, 0x83, 0xCC, 0xA4, 0x8F, 
+0xB5, 0x73, 0xC5, 0xF5, 0xC6, 0x16, 0xC6, 0x16, 
+0xC6, 0x15, 0xBD, 0xF5, 0xBD, 0xD4, 0xBD, 0xD4, 
+0xBD, 0xD4, 0xC5, 0xF5, 0xC6, 0x15, 0xD6, 0x56, 
+0xC5, 0xD4, 0xB5, 0x93, 0xBD, 0x93, 0xB5, 0x93, 
+0xBD, 0xB3, 0xB5, 0x73, 0xBD, 0xD4, 0xB5, 0x73, 
+0xC5, 0xF4, 0xC5, 0xB2, 0xAC, 0xAE, 0xA4, 0xF0, 
+0xBD, 0xB3, 0xB5, 0x72, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xA4, 0xD0, 0xA4, 0xF1, 0xB5, 0x73, 0xA4, 0xF1, 
+0x9C, 0x8F, 0x9C, 0x8F, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xAD, 0x32, 0x94, 0x90, 0x83, 0xEE, 0x84, 0x0E, 
+0x7B, 0x8D, 0x5A, 0xAA, 0x84, 0x10, 0xAD, 0x55, 
+0xD6, 0x9A, 0xB5, 0xB7, 0xC5, 0xF8, 0xDE, 0xDB, 
+0xAD, 0x35, 0xAD, 0x14, 0x52, 0x8A, 0x42, 0x08, 
+0x52, 0xAA, 0x4A, 0x69, 0x62, 0xEC, 0x7B, 0xAE, 
+0xAD, 0x55, 0x94, 0x71, 0x94, 0x92, 0xC5, 0xF8, 
+0xAD, 0x76, 0xA5, 0x35, 0xC5, 0xF8, 0xBD, 0xD7, 
+0xCE, 0x39, 0xBD, 0xD7, 0x9C, 0xF3, 0xB5, 0x95, 
+0x94, 0x4F, 0xD6, 0x13, 0xDE, 0x34, 0xD5, 0xF3, 
+0xB5, 0x2F, 0xC5, 0x91, 0xDE, 0x33, 0xDE, 0x74, 
+0xE6, 0xB5, 0xDE, 0x74, 0xE6, 0x95, 0xE6, 0x95, 
+0xD6, 0x33, 0xB5, 0x30, 0xBD, 0x30, 0xB5, 0x10, 
+0xAC, 0xAE, 0xB5, 0x10, 0xB5, 0x30, 0xAC, 0xEF, 
+0xBD, 0x50, 0xBD, 0x50, 0xC5, 0x51, 0xBD, 0x51, 
+0xB5, 0x10, 0x9C, 0x6F, 0x62, 0xEA, 0x42, 0x07, 
+0x42, 0x07, 0x42, 0x27, 0x39, 0xE6, 0x4A, 0x68, 
+0x52, 0xA9, 0x5A, 0xAA, 0x5A, 0xCB, 0x63, 0x2C, 
+0x6B, 0x4D, 0x7B, 0xCF, 0x9C, 0xF3, 0x94, 0x92, 
+0x73, 0xAE, 0xA5, 0x55, 0xBD, 0xF6, 0xBD, 0x73, 
+0xBD, 0x52, 0xB5, 0x11, 0x9C, 0xB0, 0x9C, 0xB1, 
+0x94, 0x4F, 0xAD, 0x12, 0xBD, 0x94, 0x9C, 0xB0, 
+0xB5, 0x94, 0xBD, 0xD4, 0xAD, 0x53, 0xAD, 0x12, 
+0xB5, 0x74, 0xBD, 0xB4, 0xB5, 0x73, 0xAD, 0x53, 
+0xAD, 0x32, 0xBD, 0xB4, 0xBD, 0xB4, 0xC6, 0x15, 
+0xD6, 0x77, 0xCE, 0x56, 0xCE, 0x56, 0xD6, 0x97, 
+0xCE, 0x77, 0xC6, 0x36, 0xC6, 0x15, 0xA4, 0xF0, 
+0x9C, 0x6F, 0xB5, 0x52, 0xB5, 0x32, 0xBD, 0x72, 
+0xD6, 0x14, 0xD6, 0x14, 0xD6, 0x34, 0xE6, 0x75, 
+0xDE, 0x75, 0xDE, 0x54, 0xDE, 0x54, 0xDE, 0x75, 
+0xDE, 0x54, 0xCD, 0xF3, 0xAC, 0xF0, 0xA4, 0xF1, 
+0xA5, 0x11, 0xA4, 0xF1, 0xB5, 0x74, 0xC6, 0x15, 
+0xCE, 0x36, 0xD6, 0x56, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xCE, 0x15, 0xD6, 0x76, 0xBD, 0xB4, 0x9C, 0x8F, 
+0xB5, 0x11, 0xCD, 0xD4, 0xC5, 0xB3, 0xBD, 0x52, 
+0xAC, 0xF0, 0xAC, 0xF1, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xA4, 0xB0, 0xA4, 0xB0, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xA4, 0xCF, 0xAC, 0xF0, 0xAC, 0xF0, 0xA4, 0xAF, 
+0xAC, 0xF0, 0xBD, 0x31, 0xBD, 0x51, 0xB5, 0x31, 
+0xAC, 0xF0, 0xA4, 0xAF, 0x94, 0x4E, 0xAD, 0x11, 
+0xAD, 0x31, 0xB5, 0x72, 0xAD, 0x32, 0x5A, 0xCA, 
+0x31, 0x85, 0x29, 0x44, 0x29, 0x44, 0x29, 0x65, 
+0x31, 0xA6, 0x31, 0xA6, 0x39, 0xC7, 0x42, 0x07, 
+0x31, 0x85, 0x39, 0x86, 0x4A, 0x28, 0x73, 0x4D, 
+0x83, 0xAE, 0x62, 0xEB, 0x62, 0xCB, 0x83, 0xAE, 
+0x73, 0x4C, 0x6B, 0x0C, 0x9C, 0x91, 0xAC, 0xF3, 
+0xB5, 0x32, 0xF6, 0xF8, 0xE6, 0xB6, 0xDE, 0x75, 
+0xDE, 0x55, 0xDE, 0x75, 0xDE, 0x55, 0xD6, 0x14, 
+0xDE, 0x55, 0xDE, 0x76, 0xB5, 0x31, 0xDE, 0xB7, 
+0xDE, 0xB8, 0xDE, 0xB8, 0xBD, 0x95, 0x29, 0x45, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0x82, 0x10, 0x82, 
+0x10, 0xA3, 0x10, 0xC3, 0x10, 0xC3, 0x21, 0x04, 
+0x8C, 0x0F, 0xBD, 0x94, 0xD6, 0x97, 0xCE, 0x35, 
+0xC5, 0xD4, 0xCE, 0x56, 0xCE, 0x15, 0xC5, 0xD4, 
+0xBD, 0xB4, 0xBD, 0x93, 0xAD, 0x12, 0xAD, 0x32, 
+0xAD, 0x12, 0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xF1, 
+0x9C, 0xD0, 0x94, 0x8F, 0x9C, 0xD0, 0xA4, 0xF1, 
+0xA4, 0xD1, 0xA4, 0xF1, 0xA5, 0x12, 0x9C, 0xD1, 
+0x9C, 0x90, 0xA4, 0xD1, 0xA4, 0xD1, 0xA4, 0xF1, 
+0xB5, 0x53, 0xAD, 0x33, 0xAD, 0x12, 0xA4, 0xD1, 
+0xA4, 0xD1, 0x9C, 0xB0, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xAD, 0x12, 0xAD, 0x12, 
+0x74, 0x4D, 0x5B, 0x8A, 0x74, 0x4E, 0x7C, 0xAF, 
+0x8D, 0x50, 0x84, 0xED, 0x6C, 0x49, 0x64, 0x06, 
+0x74, 0x68, 0x74, 0x69, 0x43, 0x02, 0x74, 0x48, 
+0x63, 0xC7, 0x53, 0x66, 0x5B, 0x86, 0x7C, 0x49, 
+0xB5, 0xD1, 0xB5, 0x72, 0xC6, 0x35, 0xC6, 0x15, 
+0xC6, 0x15, 0xBD, 0xB4, 0xAD, 0x33, 0x5A, 0xAA, 
+0x41, 0xE7, 0x4A, 0x28, 0x42, 0x08, 0x4A, 0x29, 
+0x7B, 0xEF, 0x9C, 0xF4, 0xC6, 0x39, 0xA5, 0x35, 
+0xAD, 0x55, 0xEF, 0x5D, 0xE7, 0x1C, 0xC6, 0x18, 
+0xAD, 0x55, 0x73, 0x8D, 0x94, 0x4F, 0xA4, 0xAF, 
+0xB5, 0x52, 0xBD, 0xD4, 0xC6, 0x15, 0xCE, 0x36, 
+0xCE, 0x36, 0xBD, 0xD4, 0xBD, 0xF5, 0xCE, 0x36, 
+0xC6, 0x15, 0xC5, 0xF4, 0xC6, 0x15, 0xCE, 0x56, 
+0xCE, 0x35, 0xC5, 0xF4, 0xC5, 0xF5, 0xC6, 0x15, 
+0xCE, 0x56, 0xBD, 0xF4, 0xC5, 0xF5, 0xB5, 0x73, 
+0xBD, 0xB3, 0xB5, 0x50, 0xAC, 0xEF, 0xA4, 0xAF, 
+0xB5, 0x93, 0xBD, 0xB3, 0xAD, 0x32, 0xA4, 0xF1, 
+0xA5, 0x11, 0xB5, 0x93, 0xAD, 0x32, 0xA5, 0x11, 
+0x9C, 0x8F, 0x94, 0x6F, 0x9C, 0x8F, 0x9C, 0xAF, 
+0xB5, 0x73, 0xAD, 0x53, 0x8C, 0x0E, 0x83, 0xEE, 
+0x8C, 0x2E, 0x8C, 0x4F, 0x6B, 0x2B, 0x73, 0xAE, 
+0x94, 0x72, 0x8C, 0x72, 0x94, 0x92, 0xA5, 0x14, 
+0x9C, 0xD3, 0xDE, 0xDB, 0xB5, 0x96, 0x52, 0x8A, 
+0x21, 0x24, 0x29, 0x45, 0x42, 0x28, 0x62, 0xEB, 
+0x7B, 0xCF, 0x62, 0xEC, 0xAD, 0x55, 0xB5, 0x96, 
+0x94, 0xB3, 0xB5, 0x96, 0xCE, 0x39, 0xAD, 0x35, 
+0x83, 0xF0, 0x73, 0xAF, 0x84, 0x31, 0xB5, 0x75, 
+0xA4, 0xF3, 0xB5, 0x54, 0xCD, 0xD3, 0xDE, 0x54, 
+0xC5, 0xB1, 0xCD, 0xB1, 0xD6, 0x34, 0xDE, 0x54, 
+0xD6, 0x13, 0xD6, 0x33, 0xDE, 0x74, 0xDE, 0x33, 
+0xCD, 0xB1, 0xAC, 0xCE, 0xC5, 0xB2, 0xAC, 0xEF, 
+0x8B, 0xEB, 0xAD, 0x0F, 0xBD, 0x51, 0xB5, 0x30, 
+0xD5, 0xF3, 0xCD, 0x92, 0xD5, 0xF3, 0xC5, 0x92, 
+0xC5, 0x92, 0xA4, 0xD0, 0x9C, 0x8F, 0x52, 0x68, 
+0x39, 0xC6, 0x31, 0x85, 0x42, 0x07, 0x4A, 0x48, 
+0x52, 0x89, 0x5A, 0xEB, 0x63, 0x0B, 0x63, 0x2C, 
+0x6B, 0x6D, 0x8C, 0x51, 0x8C, 0x51, 0x8C, 0x30, 
+0x6B, 0x6D, 0xA5, 0x34, 0xCE, 0x58, 0xC5, 0xB3, 
+0xC5, 0x93, 0xA4, 0xAF, 0xA4, 0xD0, 0xA4, 0xD1, 
+0xAD, 0x32, 0xA4, 0xF1, 0xBD, 0x94, 0xBD, 0x94, 
+0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x53, 
+0xAD, 0x32, 0xAC, 0xF2, 0xAD, 0x12, 0xAD, 0x12, 
+0xAD, 0x12, 0xA4, 0xB1, 0x9C, 0xB0, 0xA4, 0xD1, 
+0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x11, 
+0xAD, 0x73, 0xAD, 0x52, 0xBD, 0xB4, 0x9C, 0xB0, 
+0x9C, 0x8F, 0xAD, 0x11, 0xA4, 0xB0, 0xB5, 0x11, 
+0xB4, 0xF0, 0xAC, 0xF0, 0xB5, 0x30, 0xC5, 0x71, 
+0xBD, 0x51, 0xB4, 0xF0, 0xC5, 0x72, 0xCD, 0xD3, 
+0xC5, 0xB2, 0xC5, 0x92, 0xAC, 0xF0, 0xA4, 0xD0, 
+0x8C, 0x2E, 0x8C, 0x2E, 0xA4, 0xD1, 0xC5, 0xD4, 
+0xCE, 0x35, 0xC5, 0xF5, 0xBD, 0x93, 0xCE, 0x36, 
+0xD6, 0x77, 0xCE, 0x36, 0xB5, 0x32, 0x9C, 0x8F, 
+0xBD, 0x52, 0xD6, 0x35, 0xD6, 0x35, 0xCD, 0xD3, 
+0xBD, 0x93, 0xA4, 0xD0, 0x8B, 0xED, 0xA4, 0xD0, 
+0x94, 0x0D, 0x9C, 0x8F, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xCF, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xAC, 0xF0, 0xB5, 0x10, 0xAC, 0xCF, 
+0x9C, 0x8E, 0x9C, 0x8F, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xAD, 0x11, 0xA4, 0xF0, 0xAD, 0x32, 
+0x9C, 0xB0, 0x6B, 0x2B, 0x42, 0x07, 0x29, 0x44, 
+0x29, 0x65, 0x39, 0xE6, 0x42, 0x07, 0x41, 0xE7, 
+0x4A, 0x48, 0x39, 0xC6, 0x29, 0x45, 0x39, 0x86, 
+0x5A, 0x8A, 0x83, 0xAE, 0x4A, 0x08, 0x5A, 0x69, 
+0x83, 0xAE, 0x73, 0x4D, 0x5A, 0x69, 0x83, 0xEF, 
+0xA4, 0xB2, 0xAC, 0xD1, 0xCD, 0xB4, 0xD6, 0x14, 
+0xDE, 0x76, 0xE6, 0x76, 0xDE, 0x55, 0xDE, 0x35, 
+0xE6, 0x76, 0xD6, 0x14, 0xC5, 0x93, 0xE6, 0xB7, 
+0xE6, 0xD8, 0xDE, 0xB7, 0x9C, 0x90, 0x29, 0x04, 
+0x10, 0xA3, 0x10, 0x82, 0x10, 0xA3, 0x10, 0x82, 
+0x10, 0xA3, 0x18, 0xC3, 0x18, 0xE4, 0x29, 0x65, 
+0x9C, 0x91, 0xBD, 0xB4, 0xD6, 0x56, 0xD6, 0x56, 
+0xC5, 0xD4, 0xCE, 0x15, 0xBD, 0x93, 0xC6, 0x15, 
+0xCE, 0x35, 0xCE, 0x15, 0xC5, 0xD5, 0xBD, 0xD4, 
+0xB5, 0x93, 0xBD, 0x94, 0xAD, 0x53, 0xBD, 0x93, 
+0xB5, 0x73, 0xB5, 0x93, 0xAD, 0x32, 0xB5, 0x53, 
+0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0xD5, 0xC5, 0xD5, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xA4, 0xD0, 0xAD, 0x11, 
+0xCD, 0xD4, 0xC5, 0xB3, 0xC5, 0xB3, 0xC5, 0xB3, 
+0xC5, 0xD4, 0xC5, 0xB3, 0xC5, 0x93, 0xCD, 0xD4, 
+0xCD, 0xD4, 0xC5, 0x93, 0xC5, 0xB3, 0xC5, 0xB3, 
+0x53, 0x48, 0x4B, 0x48, 0x5B, 0xCA, 0x64, 0x0B, 
+0x85, 0x0E, 0xA5, 0xD0, 0x74, 0x8A, 0x5B, 0xE5, 
+0x5B, 0xE5, 0x53, 0x64, 0x63, 0xE6, 0x74, 0x48, 
+0x63, 0xC7, 0x53, 0x86, 0x8C, 0xCB, 0xA5, 0x2D, 
+0x9C, 0xCD, 0x8C, 0x2C, 0x9C, 0x8F, 0x9C, 0x8F, 
+0xA4, 0xCF, 0xAD, 0x10, 0xAD, 0x11, 0x73, 0x6B, 
+0x39, 0xC5, 0x39, 0xC6, 0x42, 0x07, 0x4A, 0x28, 
+0x5A, 0xCB, 0x84, 0x30, 0xA5, 0x35, 0x7B, 0xF0, 
+0xBD, 0xD7, 0xDE, 0xBB, 0xDE, 0xBB, 0xCE, 0x7A, 
+0x9C, 0xF4, 0x8C, 0x30, 0xA4, 0xD1, 0xB5, 0x51, 
+0xCE, 0x35, 0xCE, 0x35, 0xCE, 0x56, 0xCE, 0x35, 
+0xCE, 0x36, 0xC6, 0x35, 0xCE, 0x36, 0xCE, 0x77, 
+0xCE, 0x77, 0xCE, 0x36, 0xC6, 0x36, 0xCE, 0x56, 
+0xCE, 0x36, 0xCE, 0x56, 0xCE, 0x56, 0xCE, 0x56, 
+0xD6, 0x77, 0xCE, 0x56, 0xD6, 0x77, 0xCE, 0x36, 
+0xCE, 0x15, 0xB5, 0x51, 0xAC, 0xEF, 0x9C, 0xAF, 
+0xB5, 0x72, 0xAD, 0x52, 0x9C, 0xD0, 0xA4, 0xF1, 
+0xAD, 0x32, 0xB5, 0x53, 0x9C, 0xD0, 0xA4, 0xF1, 
+0x8C, 0x2E, 0x9C, 0xB0, 0x9C, 0xD0, 0x94, 0x8F, 
+0xAD, 0x53, 0xAD, 0x52, 0x8C, 0x2E, 0x8C, 0x2E, 
+0xA4, 0xF1, 0xB5, 0x73, 0xA4, 0xF2, 0x7B, 0xAD, 
+0x52, 0x8A, 0x7B, 0xAF, 0x84, 0x10, 0x9C, 0xD3, 
+0x5A, 0xCB, 0x9C, 0xD3, 0xDE, 0xBB, 0xBD, 0xB7, 
+0xA4, 0xF4, 0x63, 0x0C, 0x31, 0x86, 0x4A, 0x49, 
+0x6B, 0x4D, 0x73, 0x6E, 0xAD, 0x76, 0x9C, 0xD3, 
+0x9C, 0xD3, 0xBD, 0xD7, 0xA5, 0x14, 0x9C, 0xB3, 
+0x9C, 0xF4, 0xB5, 0x96, 0xC6, 0x18, 0xCE, 0x59, 
+0xD6, 0x9A, 0xE7, 0x1C, 0xDE, 0xB9, 0xA4, 0xD1, 
+0x7B, 0x8B, 0xC5, 0xD3, 0xD5, 0xF3, 0xCD, 0xF2, 
+0xD5, 0xF2, 0xD6, 0x33, 0xD6, 0x12, 0xD6, 0x13, 
+0xC5, 0x71, 0xB5, 0x10, 0xAD, 0x10, 0xB5, 0x30, 
+0xAD, 0x10, 0xAC, 0xEF, 0xB5, 0x30, 0xC5, 0xB2, 
+0xCD, 0x91, 0xB5, 0x10, 0x7B, 0x6A, 0x94, 0x6E, 
+0x9C, 0x6F, 0x6B, 0x0A, 0x94, 0x4E, 0x62, 0xE9, 
+0x39, 0xC6, 0x29, 0x44, 0x31, 0x64, 0x41, 0xE6, 
+0x52, 0x89, 0x62, 0xEB, 0x5A, 0xEB, 0x5A, 0xEB, 
+0x73, 0x8E, 0x84, 0x10, 0x73, 0x8E, 0x6B, 0x2C, 
+0x94, 0x92, 0xBD, 0xD7, 0xB5, 0xB6, 0xC5, 0xD5, 
+0x9C, 0x6F, 0x94, 0x2E, 0xAD, 0x11, 0xB5, 0x11, 
+0xAD, 0x11, 0x94, 0x2E, 0xA4, 0xB0, 0xB5, 0x53, 
+0x9C, 0xB0, 0x94, 0x4F, 0x94, 0x2E, 0xA4, 0xB0, 
+0xB5, 0x53, 0xBD, 0x53, 0xAD, 0x12, 0xA4, 0xF1, 
+0xB5, 0x32, 0xB5, 0x52, 0xBD, 0x93, 0xBD, 0x93, 
+0xB5, 0x32, 0xB5, 0x52, 0xBD, 0x93, 0xBD, 0x73, 
+0xB5, 0x73, 0xBD, 0x73, 0xB5, 0x53, 0xB5, 0x32, 
+0xBD, 0x94, 0xBD, 0x94, 0xBD, 0x94, 0xBD, 0x94, 
+0xBD, 0x93, 0xBD, 0x93, 0xBD, 0x73, 0xBD, 0x52, 
+0xB5, 0x32, 0xB5, 0x32, 0xAC, 0xF1, 0xAD, 0x11, 
+0xB5, 0x31, 0xBD, 0x72, 0xBD, 0x73, 0xC5, 0xD5, 
+0xC5, 0xD5, 0xC5, 0xB4, 0xAD, 0x12, 0xA4, 0xB0, 
+0x9C, 0x8F, 0x94, 0x2E, 0x83, 0xED, 0x8C, 0x0E, 
+0x94, 0x2F, 0x8C, 0x0E, 0x8C, 0x0E, 0x8C, 0x0D, 
+0x9C, 0x6F, 0xBD, 0x93, 0xD6, 0x35, 0xBD, 0x72, 
+0xAC, 0xF0, 0x9C, 0x6E, 0x94, 0x2D, 0x9C, 0x6F, 
+0x83, 0xCC, 0x8B, 0xED, 0x9C, 0x6E, 0xA4, 0x8F, 
+0xA4, 0xCF, 0xA4, 0xAF, 0xAD, 0x10, 0xAD, 0x10, 
+0xA4, 0xCF, 0xA4, 0x8F, 0xA4, 0x8F, 0xA4, 0x8F, 
+0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x8F, 0xA4, 0xCF, 
+0x9C, 0xAF, 0xB5, 0x51, 0xAD, 0x31, 0xB5, 0x72, 
+0xA5, 0x11, 0xA5, 0x11, 0x9C, 0xD1, 0x5A, 0xCA, 
+0x31, 0x65, 0x31, 0x85, 0x31, 0xA6, 0x39, 0xE6, 
+0x52, 0x69, 0x4A, 0x28, 0x29, 0x45, 0x29, 0x04, 
+0x31, 0x65, 0x4A, 0x28, 0x52, 0x89, 0x41, 0xE7, 
+0x62, 0xAA, 0x7B, 0x4D, 0x62, 0xAA, 0x52, 0x49, 
+0x8B, 0xEF, 0xA4, 0x92, 0x94, 0x30, 0x9C, 0x2F, 
+0xD6, 0x36, 0xD6, 0x35, 0xCD, 0xD3, 0xCD, 0xD4, 
+0xCD, 0xD3, 0xD6, 0x14, 0xD6, 0x35, 0xE6, 0xD7, 
+0xE6, 0xD7, 0xD6, 0x35, 0x7B, 0x8D, 0x21, 0x04, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC3, 0x18, 0xE4, 0x73, 0x6D, 
+0xAD, 0x33, 0xC5, 0xD4, 0xD6, 0x56, 0xCE, 0x35, 
+0xC5, 0xD4, 0xCE, 0x15, 0xB5, 0x73, 0xAD, 0x32, 
+0xC5, 0xD4, 0xCE, 0x15, 0xC5, 0xF5, 0xCE, 0x15, 
+0xC5, 0xD5, 0xBD, 0xD4, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xBD, 0xD4, 0xC5, 0xF5, 0xB5, 0x93, 0xC5, 0xF5, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xA4, 0xF1, 0xB5, 0x52, 0xD6, 0x35, 0xE6, 0x76, 
+0xD6, 0x15, 0xD6, 0x34, 0xD6, 0x35, 0xD6, 0x15, 
+0xDE, 0x35, 0xD6, 0x35, 0xD6, 0x35, 0xD6, 0x15, 
+0xDE, 0x76, 0xDE, 0x55, 0xD6, 0x14, 0xDE, 0x55, 
+0x84, 0xAD, 0x6C, 0x4C, 0x7C, 0xAE, 0x63, 0xEB, 
+0x5B, 0xA8, 0x74, 0xAB, 0x74, 0x8A, 0x63, 0xE6, 
+0x53, 0x84, 0x4B, 0x24, 0x6C, 0x27, 0x6B, 0xE7, 
+0x6B, 0xE7, 0x7C, 0x6A, 0x9C, 0xED, 0xA4, 0xCD, 
+0xA4, 0x8E, 0x9C, 0x8D, 0xA4, 0x8E, 0xAC, 0xEF, 
+0xB5, 0x10, 0xAC, 0xEF, 0xA4, 0xAE, 0xA4, 0xAF, 
+0xA4, 0x8F, 0x6B, 0x09, 0x39, 0xC5, 0x39, 0xE7, 
+0x42, 0x28, 0x5A, 0xCB, 0x6B, 0x4D, 0x8C, 0x51, 
+0x9C, 0xB3, 0x94, 0x92, 0xC6, 0x18, 0xDE, 0xBB, 
+0xC6, 0x39, 0x9C, 0xD2, 0xBD, 0x94, 0xAD, 0x10, 
+0xB5, 0x51, 0xBD, 0x71, 0xBD, 0x72, 0xB5, 0x71, 
+0xAD, 0x30, 0xAC, 0xF0, 0xAD, 0x31, 0xB5, 0x72, 
+0xBD, 0xB3, 0xBD, 0xB3, 0xBD, 0x93, 0xB5, 0x73, 
+0xBD, 0xB4, 0xC6, 0x15, 0xC6, 0x35, 0xCE, 0x56, 
+0xCE, 0x76, 0xD6, 0x77, 0xD6, 0x97, 0xCE, 0x56, 
+0xCE, 0x15, 0xAC, 0xF0, 0xAC, 0xAE, 0xA4, 0xCF, 
+0xB5, 0x72, 0xB5, 0x73, 0xA5, 0x11, 0xA5, 0x11, 
+0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x32, 0xA5, 0x11, 
+0x9C, 0xD0, 0xA4, 0xF1, 0xA5, 0x12, 0xA4, 0xF1, 
+0xAD, 0x32, 0xAD, 0x73, 0x94, 0x8F, 0x94, 0x6F, 
+0x9C, 0xF1, 0xAD, 0x12, 0x9C, 0x90, 0x9C, 0x90, 
+0x6B, 0x4C, 0x42, 0x28, 0x6B, 0x4D, 0x9C, 0xB2, 
+0x83, 0xF0, 0x9C, 0xD3, 0xBD, 0xB7, 0xC5, 0xF8, 
+0xE7, 0x1C, 0xB5, 0x76, 0x9C, 0xB3, 0x8C, 0x51, 
+0xA5, 0x34, 0x9C, 0xD3, 0xA5, 0x34, 0x8C, 0x51, 
+0x7B, 0xAF, 0xC5, 0xF8, 0x7B, 0xAF, 0x8C, 0x51, 
+0xC6, 0x39, 0xBD, 0xD8, 0xAD, 0x35, 0x94, 0x72, 
+0x83, 0xF0, 0xC6, 0x39, 0xC5, 0xF7, 0x94, 0x92, 
+0x5A, 0xAA, 0x8C, 0x2E, 0xD6, 0x34, 0xD6, 0x13, 
+0xD6, 0x34, 0xD6, 0x13, 0xCE, 0x13, 0xD6, 0x33, 
+0xBD, 0x71, 0xB5, 0x30, 0xB5, 0x30, 0xC5, 0xB2, 
+0xBD, 0x71, 0xAD, 0x10, 0xBD, 0x51, 0xC5, 0x71, 
+0xB4, 0xEF, 0xAC, 0xCF, 0x73, 0x2A, 0x8C, 0x0D, 
+0x94, 0x4E, 0x94, 0x4E, 0x8C, 0x0D, 0x83, 0xCC, 
+0x52, 0x88, 0x39, 0xA5, 0x29, 0x64, 0x31, 0xA5, 
+0x42, 0x27, 0x52, 0x89, 0x5A, 0xCA, 0x63, 0x2C, 
+0x73, 0x8E, 0x63, 0x2C, 0x4A, 0x49, 0x73, 0x8E, 
+0x94, 0xB2, 0x9C, 0xF4, 0xA4, 0xF4, 0xCE, 0x38, 
+0x9C, 0x91, 0x94, 0x6F, 0xBD, 0x72, 0xBD, 0x92, 
+0xC5, 0x92, 0xBD, 0x73, 0xCD, 0xF4, 0xB5, 0x32, 
+0x94, 0x6F, 0xB5, 0x33, 0xAD, 0x12, 0x94, 0x4F, 
+0xB5, 0x73, 0xC5, 0xD5, 0xBD, 0x94, 0x9C, 0xB0, 
+0x7B, 0x8C, 0x83, 0xED, 0x8B, 0xED, 0x94, 0x6E, 
+0xBD, 0x93, 0xC5, 0xB4, 0xD6, 0x56, 0xC5, 0xB4, 
+0xA4, 0xD0, 0xA4, 0xD1, 0xBD, 0x73, 0xBD, 0x52, 
+0xBD, 0x73, 0xBD, 0x73, 0xB5, 0x32, 0xAD, 0x11, 
+0xBD, 0x72, 0xB5, 0x31, 0xBD, 0x52, 0xBD, 0x73, 
+0xC5, 0x93, 0xC5, 0x93, 0xBD, 0x52, 0xBD, 0x52, 
+0xBD, 0x52, 0xB5, 0x31, 0xC5, 0x93, 0xC5, 0x94, 
+0xBD, 0x73, 0xC5, 0x93, 0xC5, 0x94, 0xC5, 0xB4, 
+0xB5, 0x53, 0xAD, 0x12, 0x9C, 0xB0, 0xA4, 0xB0, 
+0xBD, 0x53, 0xB5, 0x53, 0xBD, 0x74, 0xB5, 0x33, 
+0xA4, 0xB0, 0x94, 0x2E, 0x8B, 0xED, 0x8B, 0xCC, 
+0x83, 0xCC, 0x7B, 0x8B, 0x83, 0xAC, 0x8B, 0xCC, 
+0x7B, 0x6B, 0x73, 0x4A, 0x83, 0xAB, 0x83, 0xEC, 
+0x8C, 0x0D, 0x94, 0x4E, 0x9C, 0x8F, 0x94, 0x4E, 
+0x8B, 0xCC, 0x83, 0xAC, 0x83, 0x8B, 0x83, 0xCC, 
+0x94, 0x4E, 0x9C, 0xAF, 0xA4, 0xD0, 0x9C, 0xAF, 
+0x94, 0x4E, 0xAD, 0x10, 0xBD, 0x93, 0xBD, 0xB3, 
+0xB5, 0x72, 0xBD, 0xB3, 0xC6, 0x15, 0xBD, 0xD4, 
+0x8C, 0x4F, 0x4A, 0x27, 0x31, 0xA6, 0x39, 0xC6, 
+0x39, 0xA6, 0x31, 0x85, 0x31, 0x85, 0x29, 0x45, 
+0x29, 0x24, 0x29, 0x04, 0x41, 0xE7, 0x5A, 0xAA, 
+0x4A, 0x28, 0x6A, 0xEB, 0x62, 0xCA, 0x73, 0x4C, 
+0x94, 0x30, 0x9C, 0x71, 0xA4, 0xD2, 0x83, 0xAE, 
+0x8B, 0xCE, 0xA4, 0xB0, 0x9C, 0x8F, 0x9C, 0x6F, 
+0xAD, 0x11, 0xBD, 0x73, 0xB5, 0x52, 0xD6, 0x56, 
+0xDE, 0x56, 0xB5, 0x32, 0x4A, 0x08, 0x18, 0xC4, 
+0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0xA3, 0x18, 0xC3, 0x29, 0x45, 0x9C, 0xD2, 
+0xB5, 0x53, 0xBD, 0xB4, 0xD6, 0x56, 0xCE, 0x15, 
+0xC5, 0xF5, 0xCE, 0x15, 0xB5, 0x52, 0xAD, 0x32, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xF4, 
+0xCE, 0x36, 0xC5, 0xF5, 0xAD, 0x52, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xC5, 0xF5, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xB5, 0x93, 0xBD, 0xF5, 0xCE, 0x15, 0xCE, 0x15, 
+0xA4, 0xD1, 0xB5, 0x52, 0xD6, 0x35, 0xDE, 0x55, 
+0xD6, 0x14, 0xD6, 0x35, 0xD6, 0x35, 0xD6, 0x15, 
+0xD6, 0x15, 0xCD, 0xF4, 0xBD, 0x72, 0xDE, 0x35, 
+0xD6, 0x15, 0xD6, 0x35, 0xD6, 0x35, 0xD6, 0x35, 
+0x84, 0xAD, 0x64, 0x0B, 0x74, 0x8D, 0x74, 0x8C, 
+0x53, 0x66, 0x4B, 0x66, 0x6C, 0x2A, 0x64, 0x08, 
+0x63, 0xE7, 0x6B, 0xE7, 0x63, 0xA6, 0x6B, 0xE7, 
+0x95, 0x2D, 0xA5, 0x4F, 0xBD, 0xB2, 0xC5, 0xD3, 
+0xCD, 0xF3, 0xC5, 0xB2, 0xC5, 0xB2, 0xD6, 0x55, 
+0xDE, 0x55, 0xCD, 0xD3, 0xA4, 0x8E, 0xA4, 0xAF, 
+0xAC, 0xCF, 0xA4, 0xCF, 0x83, 0xCC, 0x4A, 0x27, 
+0x39, 0xC6, 0x42, 0x28, 0x52, 0x8A, 0x52, 0xAA, 
+0x84, 0x10, 0x6B, 0x6D, 0x52, 0x8A, 0x8C, 0x51, 
+0x84, 0x30, 0x4A, 0x69, 0x7B, 0xAD, 0xCE, 0x16, 
+0xA4, 0xAF, 0xAC, 0xAF, 0xB5, 0x10, 0xB5, 0x30, 
+0xB5, 0x10, 0xB5, 0x30, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xA4, 0xAE, 0xA4, 0xAE, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xA4, 0xCF, 0xA4, 0x8F, 0xA4, 0x8E, 0x9C, 0x4E, 
+0x9C, 0x4D, 0x9C, 0x2D, 0x9C, 0x2D, 0x9C, 0x4D, 
+0x9C, 0x4C, 0xA4, 0x6D, 0xAC, 0xAE, 0x9C, 0x8E, 
+0xAD, 0x10, 0xB5, 0x52, 0xAD, 0x31, 0xAD, 0x32, 
+0xAD, 0x31, 0x9C, 0xAF, 0xAD, 0x31, 0xA4, 0xF0, 
+0xA4, 0xD0, 0xAD, 0x31, 0xB5, 0x52, 0xB5, 0x93, 
+0xB5, 0x93, 0xBD, 0xB4, 0xA5, 0x11, 0xA4, 0xF1, 
+0xA4, 0xD0, 0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0xB0, 
+0x94, 0x8F, 0x7B, 0x8C, 0x73, 0x4C, 0x73, 0x6D, 
+0x5A, 0xCB, 0xA5, 0x14, 0xBD, 0x96, 0xDE, 0xBB, 
+0xA5, 0x14, 0x94, 0x92, 0x7B, 0xAF, 0x9C, 0xB3, 
+0x9C, 0xF4, 0xA5, 0x14, 0x84, 0x10, 0x6B, 0x2D, 
+0x31, 0xA6, 0x94, 0xB3, 0xCE, 0x39, 0xB5, 0x96, 
+0xC5, 0xF8, 0xA4, 0xF4, 0xAD, 0x35, 0xB5, 0x76, 
+0xA5, 0x14, 0xCE, 0x39, 0xDE, 0xDB, 0xC6, 0x39, 
+0x7B, 0xEF, 0x73, 0x8E, 0xBD, 0x93, 0xCD, 0xF3, 
+0xCD, 0xF3, 0xD6, 0x14, 0xC5, 0x92, 0xCD, 0xB2, 
+0xAC, 0xEF, 0xAD, 0x30, 0xAD, 0x10, 0xA4, 0xCF, 
+0xB5, 0x31, 0xB5, 0x30, 0xB5, 0x10, 0xB4, 0xEF, 
+0x9C, 0x4D, 0xA4, 0x8E, 0x8B, 0xEC, 0xAC, 0xF0, 
+0xA4, 0xCF, 0x9C, 0x6E, 0x9C, 0x8F, 0xAC, 0xF0, 
+0x8C, 0x0D, 0x42, 0x07, 0x31, 0x85, 0x31, 0x85, 
+0x41, 0xE6, 0x42, 0x07, 0x42, 0x28, 0x52, 0x8A, 
+0x4A, 0x48, 0x4A, 0x68, 0x63, 0x0B, 0x83, 0xEF, 
+0x84, 0x10, 0x94, 0x92, 0xA5, 0x14, 0xBD, 0xD7, 
+0xCE, 0x59, 0xA4, 0xF2, 0xBD, 0x73, 0xBD, 0x72, 
+0xBD, 0x92, 0xBD, 0x93, 0xC5, 0xD4, 0xBD, 0xB4, 
+0xAD, 0x32, 0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x53, 
+0xB5, 0x73, 0xC5, 0xD4, 0xCD, 0xF4, 0xA4, 0xF1, 
+0x94, 0x6F, 0x94, 0x4F, 0x8C, 0x0E, 0xAD, 0x12, 
+0xC5, 0xF4, 0xCD, 0xF4, 0xCE, 0x15, 0xB5, 0x52, 
+0xAC, 0xF1, 0xBD, 0x73, 0xD6, 0x35, 0xD6, 0x14, 
+0xCD, 0xD3, 0xC5, 0x93, 0xC5, 0xB3, 0xBD, 0x72, 
+0xA4, 0xD0, 0x94, 0x4E, 0xA4, 0xCF, 0xAC, 0xF0, 
+0xAD, 0x11, 0xAD, 0x10, 0x9C, 0x6F, 0x9C, 0x6E, 
+0x9C, 0x6E, 0xAC, 0xD0, 0xAC, 0xF0, 0xA4, 0xAF, 
+0x9C, 0x6E, 0x9C, 0x8F, 0xAC, 0xF1, 0xA4, 0xD0, 
+0xA4, 0xB0, 0x9C, 0x6F, 0x9C, 0x8F, 0x9C, 0x6F, 
+0xA4, 0xD0, 0xA4, 0xB0, 0xAD, 0x12, 0xB5, 0x53, 
+0xAD, 0x12, 0xAC, 0xF1, 0xB5, 0x32, 0xAD, 0x12, 
+0xAD, 0x12, 0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x32, 
+0xB5, 0x11, 0xAC, 0xF1, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xB5, 0x31, 0xB5, 0x11, 0xAC, 0xD0, 0x9C, 0x8F, 
+0x9C, 0x90, 0x9C, 0x90, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xAD, 0x11, 0xB5, 0x52, 
+0xB5, 0x32, 0xA4, 0xF0, 0xAC, 0xF0, 0xA4, 0xD0, 
+0x94, 0x6E, 0x9C, 0x6F, 0xA4, 0xF1, 0xAD, 0x12, 
+0xAD, 0x11, 0x83, 0xED, 0x41, 0xC6, 0x39, 0xA6, 
+0x31, 0x85, 0x31, 0xA6, 0x6B, 0x2C, 0x63, 0x0B, 
+0x39, 0x86, 0x29, 0x25, 0x31, 0x45, 0x4A, 0x08, 
+0x4A, 0x48, 0x4A, 0x28, 0x5A, 0x89, 0x6B, 0x0C, 
+0x8B, 0xEF, 0x8B, 0xEF, 0x9C, 0x70, 0x83, 0xCE, 
+0x73, 0x2C, 0x8B, 0xCE, 0x83, 0xCD, 0x8B, 0xEE, 
+0xA4, 0xB1, 0x9C, 0x91, 0x52, 0x69, 0x52, 0x48, 
+0x52, 0x68, 0x42, 0x07, 0x21, 0x04, 0x18, 0xC3, 
+0x10, 0xA3, 0x10, 0x83, 0x10, 0xA3, 0x10, 0xA3, 
+0x10, 0x82, 0x18, 0xC3, 0x73, 0x6C, 0xAD, 0x32, 
+0xB5, 0x53, 0xC5, 0xD5, 0xD6, 0x56, 0xCE, 0x15, 
+0xCE, 0x15, 0xC5, 0xF5, 0xB5, 0x73, 0xB5, 0x93, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xC5, 0xF4, 0xCE, 0x15, 
+0xCE, 0x15, 0xC5, 0xD4, 0xC5, 0xD4, 0xC6, 0x15, 
+0xC6, 0x15, 0xC5, 0xD5, 0xC5, 0xD5, 0xBD, 0xD4, 
+0xC5, 0xF5, 0xC6, 0x15, 0xCE, 0x35, 0xAD, 0x32, 
+0xA4, 0xF0, 0xC5, 0xD4, 0xD6, 0x14, 0xDE, 0x55, 
+0xD6, 0x14, 0xD6, 0x14, 0xDE, 0x76, 0xD6, 0x14, 
+0xCD, 0xF4, 0xCD, 0xD4, 0xC5, 0xB3, 0xD6, 0x35, 
+0xD6, 0x14, 0xD6, 0x35, 0xD6, 0x15, 0xDE, 0x35, 
+0x6C, 0x2A, 0x5B, 0xEA, 0x6C, 0x6B, 0x64, 0x29, 
+0x5B, 0xE6, 0x64, 0x08, 0x53, 0x67, 0x53, 0x88, 
+0x8D, 0x0E, 0x95, 0x0D, 0x74, 0x28, 0x84, 0xAB, 
+0xA5, 0x8F, 0xAD, 0xB1, 0xA5, 0x50, 0x94, 0xAE, 
+0xC6, 0x14, 0xD6, 0x75, 0xD6, 0x75, 0xDE, 0x75, 
+0xD6, 0x54, 0xD6, 0x14, 0xA4, 0x8E, 0x83, 0xCB, 
+0x9C, 0x8E, 0xA4, 0xF0, 0xAD, 0x11, 0xAD, 0x32, 
+0x63, 0x0B, 0x39, 0xA6, 0x42, 0x07, 0x42, 0x28, 
+0x63, 0x0C, 0x6B, 0x2D, 0x5A, 0xAB, 0x4A, 0x49, 
+0x41, 0xE7, 0x62, 0xEB, 0x9C, 0xD3, 0xEF, 0x7D, 
+0xDE, 0xDA, 0x8C, 0x0F, 0x8C, 0x0D, 0xA4, 0x8E, 
+0x94, 0x2C, 0x94, 0x2C, 0xAC, 0xAE, 0xAC, 0xAE, 
+0xA4, 0xAE, 0xA4, 0x8E, 0xA4, 0x8E, 0x9C, 0x6D, 
+0x9C, 0x6D, 0xA4, 0x8E, 0xAC, 0xCF, 0xB4, 0xEF, 
+0xAC, 0xEF, 0xB4, 0xF0, 0xB5, 0x10, 0xB5, 0x10, 
+0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x10, 
+0xAD, 0x0F, 0xAC, 0xEF, 0xB5, 0x10, 0xAC, 0xF0, 
+0xAC, 0xCF, 0xA4, 0xAE, 0xAC, 0xCF, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xAE, 0xA4, 0xAE, 0x9C, 0x8E, 
+0x9C, 0x8F, 0x9C, 0x8F, 0x94, 0x6E, 0x9C, 0x6E, 
+0x9C, 0x6E, 0x9C, 0x6E, 0x94, 0x4E, 0x8C, 0x0D, 
+0x8C, 0x0D, 0xAC, 0xF1, 0x94, 0x4F, 0x5A, 0xCA, 
+0x39, 0xE7, 0x73, 0x8E, 0x94, 0x92, 0xA5, 0x14, 
+0x94, 0x71, 0xAD, 0x35, 0x94, 0x71, 0x63, 0x0C, 
+0x84, 0x10, 0xC5, 0xF7, 0x94, 0x51, 0x62, 0xEB, 
+0x62, 0xEC, 0x4A, 0x69, 0xB5, 0xB6, 0xC6, 0x39, 
+0x8C, 0x51, 0xB5, 0xB7, 0xBD, 0xF8, 0xA4, 0xF4, 
+0xBD, 0xB7, 0xC5, 0xF8, 0xD6, 0x9B, 0xE6, 0xFD, 
+0xBD, 0xD7, 0xC6, 0x17, 0xC5, 0xF5, 0xD6, 0x35, 
+0xD6, 0x55, 0xD6, 0x34, 0xC5, 0xB2, 0xCD, 0xD3, 
+0xB5, 0x30, 0xB5, 0x71, 0x9C, 0xAF, 0x8C, 0x2D, 
+0xB5, 0x72, 0xA4, 0xEF, 0xB5, 0x30, 0xB5, 0x10, 
+0x93, 0xEC, 0xA4, 0xAF, 0x9C, 0x6E, 0xBD, 0x92, 
+0xA4, 0xCF, 0xAC, 0xF0, 0xAD, 0x31, 0xB5, 0x51, 
+0xB5, 0x31, 0x73, 0x4B, 0x39, 0xA5, 0x39, 0xC6, 
+0x39, 0xA5, 0x39, 0xC6, 0x39, 0xA6, 0x42, 0x07, 
+0x4A, 0x48, 0x42, 0x28, 0x4A, 0x48, 0x63, 0x2C, 
+0x7B, 0xCF, 0x9C, 0xD3, 0x9C, 0xF4, 0xB5, 0xB7, 
+0xCE, 0x7A, 0xBD, 0xD6, 0xAD, 0x52, 0xB5, 0x51, 
+0xB5, 0x72, 0xC5, 0xB3, 0xC5, 0xB3, 0xC5, 0xD4, 
+0xBD, 0x94, 0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x94, 
+0xC5, 0xD4, 0xCD, 0xF5, 0xC5, 0xD4, 0x9C, 0x90, 
+0x94, 0x4F, 0x8C, 0x2E, 0x94, 0x4F, 0xBD, 0x93, 
+0xCE, 0x35, 0xD6, 0x35, 0xD6, 0x55, 0xB5, 0x52, 
+0xAC, 0xF1, 0xBD, 0x73, 0xCD, 0xF4, 0xDE, 0x55, 
+0xDE, 0x35, 0xD6, 0x34, 0xD6, 0x35, 0xDE, 0x76, 
+0xD6, 0x15, 0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xAD, 0x31, 0xB5, 0x32, 0xC5, 0xD4, 0xC5, 0xB4, 
+0xBD, 0x93, 0xC5, 0xB4, 0xB5, 0x52, 0x9C, 0x8F, 
+0x83, 0xEC, 0x8C, 0x2E, 0xB5, 0x52, 0xA4, 0xF1, 
+0xA4, 0xD1, 0x9C, 0x8F, 0xA4, 0xF1, 0xA4, 0xD1, 
+0xA4, 0xF1, 0xA4, 0xD0, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xF1, 0xAD, 0x12, 0xA4, 0xD1, 0x94, 0x4F, 
+0x94, 0x4F, 0x8C, 0x2E, 0x9C, 0x90, 0xA4, 0xB0, 
+0xB5, 0x31, 0xBD, 0x52, 0xC5, 0x92, 0xD6, 0x14, 
+0xDE, 0x34, 0xD5, 0xF3, 0xBD, 0x72, 0xAC, 0xF1, 
+0xBD, 0x73, 0xA4, 0xD1, 0xAC, 0xD0, 0xB5, 0x11, 
+0xB5, 0x31, 0xBD, 0x52, 0xBD, 0x52, 0xBD, 0x52, 
+0xB5, 0x32, 0xBD, 0x32, 0xB5, 0x31, 0xBD, 0x52, 
+0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x31, 0xB5, 0x32, 
+0xB5, 0x52, 0xBD, 0x52, 0xA4, 0xD1, 0x83, 0xCD, 
+0x41, 0xE6, 0x31, 0x85, 0x52, 0xAA, 0x94, 0x50, 
+0x94, 0x71, 0x7B, 0x8E, 0x41, 0xE8, 0x29, 0x25, 
+0x39, 0xC6, 0x4A, 0x08, 0x41, 0xE7, 0x4A, 0x08, 
+0x62, 0xCB, 0x73, 0x4C, 0x8B, 0xEF, 0x94, 0x50, 
+0x8B, 0xCF, 0x8B, 0xCE, 0x7B, 0x6D, 0x62, 0xCA, 
+0x8C, 0x2F, 0x7B, 0x8D, 0x18, 0xC3, 0x10, 0xA3, 
+0x10, 0xA3, 0x10, 0xA3, 0x10, 0xA3, 0x10, 0x82, 
+0x10, 0xA3, 0x18, 0xC3, 0x18, 0xE4, 0x18, 0xE3, 
+0x10, 0xA3, 0x52, 0x89, 0xA5, 0x12, 0x94, 0x4F, 
+0xA4, 0xB0, 0xA4, 0xF1, 0xAD, 0x52, 0xAD, 0x32, 
+0xB5, 0x52, 0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x52, 
+0xB5, 0x93, 0xC5, 0xD4, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xCE, 0x36, 0xB5, 0x73, 0xCE, 0x16, 0xCE, 0x56, 
+0xCE, 0x15, 0xC5, 0xD5, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xC6, 0x15, 0xCE, 0x15, 0xD6, 0x56, 0xBD, 0xD4, 
+0xA4, 0xD0, 0xBD, 0xB3, 0xC5, 0xB3, 0xD6, 0x14, 
+0xCD, 0xB3, 0xBD, 0x72, 0xCD, 0xF4, 0xD6, 0x14, 
+0xD5, 0xF4, 0xCD, 0xD3, 0xD6, 0x14, 0xD6, 0x15, 
+0xD6, 0x35, 0xCD, 0xD4, 0xD6, 0x14, 0xD6, 0x35, 
+0x4B, 0x46, 0x53, 0x87, 0x5C, 0x08, 0x64, 0x27, 
+0x64, 0x26, 0x74, 0x8A, 0x9D, 0x90, 0x8C, 0xEE, 
+0x84, 0xAE, 0x95, 0x2E, 0x6B, 0xA8, 0xA5, 0x8F, 
+0x7C, 0x4A, 0x4B, 0x25, 0x74, 0x2A, 0xB5, 0xF3, 
+0xD6, 0x96, 0xD6, 0x75, 0xD6, 0x54, 0xCE, 0x34, 
+0xCE, 0x13, 0xD6, 0x14, 0xA4, 0xAE, 0xB5, 0x72, 
+0xC6, 0x15, 0xCE, 0x35, 0xCE, 0x35, 0xCE, 0x35, 
+0xCE, 0x16, 0x8C, 0x2F, 0x39, 0xC6, 0x39, 0xC6, 
+0x42, 0x28, 0x52, 0x8A, 0x5A, 0xAA, 0x5A, 0xEB, 
+0x52, 0x8A, 0x52, 0x69, 0x9C, 0xD3, 0xE7, 0x3C, 
+0xEF, 0x7D, 0xD6, 0xBA, 0xC5, 0xF7, 0xAD, 0x11, 
+0xA4, 0xEF, 0xA4, 0xAE, 0xA4, 0x8E, 0xB5, 0x10, 
+0xA4, 0xAF, 0x94, 0x2D, 0xA4, 0xCF, 0xAC, 0xF0, 
+0xA4, 0xCF, 0xB5, 0x31, 0xBD, 0x72, 0xA4, 0xAF, 
+0x94, 0x0D, 0xA4, 0x8F, 0xA4, 0xAE, 0xAC, 0xEF, 
+0xB5, 0x30, 0xAC, 0xCF, 0xAC, 0xAE, 0xAC, 0xCF, 
+0xB5, 0x10, 0xAC, 0xCF, 0x94, 0x2C, 0x8B, 0xEB, 
+0xA4, 0x8E, 0xB5, 0x10, 0xB5, 0x0F, 0xBD, 0x30, 
+0xBD, 0x50, 0xBD, 0x50, 0xB5, 0x30, 0xB4, 0xEF, 
+0xAC, 0xCF, 0xA4, 0xAE, 0xAC, 0xCE, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xB4, 0xEF, 0xB4, 0xEF, 0xAC, 0xAE, 
+0xA4, 0xAE, 0xB4, 0xF0, 0xB5, 0x10, 0x83, 0xAC, 
+0x8C, 0x0D, 0x83, 0xCD, 0x52, 0x89, 0x73, 0xAE, 
+0x94, 0x92, 0x7B, 0xAE, 0x7B, 0xAF, 0x6B, 0x4D, 
+0xBD, 0xB7, 0xBD, 0xD7, 0xD6, 0xBB, 0x94, 0x92, 
+0x7B, 0xCF, 0x31, 0x66, 0x42, 0x08, 0x6B, 0x8E, 
+0xAD, 0x76, 0xCE, 0x39, 0x9C, 0xF4, 0xA5, 0x15, 
+0xC6, 0x19, 0xC6, 0x39, 0xC6, 0x39, 0xD6, 0xBB, 
+0xD6, 0xBB, 0xDE, 0xDB, 0xBD, 0xB6, 0x94, 0x2F, 
+0xAD, 0x31, 0xAD, 0x31, 0xBD, 0x72, 0xC5, 0x92, 
+0xAD, 0x10, 0xAD, 0x31, 0xB5, 0x72, 0xBD, 0x92, 
+0xC5, 0xF4, 0xAD, 0x30, 0xCD, 0xF3, 0xB5, 0x30, 
+0x93, 0xEC, 0xA4, 0x6E, 0x94, 0x4D, 0xC5, 0xD3, 
+0xB5, 0x52, 0xB5, 0x51, 0xA4, 0xF0, 0xBD, 0x72, 
+0xBD, 0x93, 0xA4, 0xD0, 0x4A, 0x48, 0x39, 0xA5, 
+0x31, 0x85, 0x31, 0x85, 0x39, 0xA6, 0x4A, 0x28, 
+0x52, 0x8A, 0x4A, 0x28, 0x4A, 0x69, 0x6B, 0x2C, 
+0x73, 0x8E, 0x84, 0x31, 0x9C, 0xD3, 0xAD, 0x76, 
+0xC6, 0x19, 0xCE, 0x38, 0xAD, 0x32, 0xA4, 0xF0, 
+0xBD, 0x72, 0xC5, 0xB4, 0xBD, 0x72, 0xBD, 0x73, 
+0xB5, 0x73, 0xBD, 0x94, 0xBD, 0x94, 0xBD, 0xB4, 
+0xCE, 0x15, 0xCE, 0x15, 0xCD, 0xF5, 0xBD, 0x73, 
+0xA4, 0xD1, 0x94, 0x6F, 0x9C, 0xB0, 0xC5, 0xD4, 
+0xD6, 0x35, 0xDE, 0x75, 0xD6, 0x14, 0xB5, 0x11, 
+0xAD, 0x12, 0xC5, 0xB4, 0xCD, 0xF4, 0xD6, 0x34, 
+0xD6, 0x34, 0xD5, 0xF3, 0xC5, 0xB2, 0xD6, 0x14, 
+0xC5, 0xB3, 0xB5, 0x52, 0xA4, 0xAF, 0xA4, 0xAF, 
+0xA4, 0xF1, 0x9C, 0xB0, 0x9C, 0xAF, 0xAD, 0x11, 
+0xB5, 0x31, 0xAD, 0x11, 0xAD, 0x11, 0x9C, 0xB0, 
+0x94, 0x4E, 0xAD, 0x11, 0xBD, 0xB4, 0xAD, 0x11, 
+0xAD, 0x12, 0xB5, 0x53, 0xA4, 0xF1, 0x9C, 0xB0, 
+0xAD, 0x12, 0x9C, 0xB0, 0xA5, 0x11, 0xA4, 0xD1, 
+0xAD, 0x32, 0xCD, 0xF5, 0xC5, 0xD4, 0xB5, 0x73, 
+0xAD, 0x32, 0xAD, 0x32, 0xB5, 0x73, 0xAD, 0x32, 
+0xAD, 0x11, 0xCD, 0xD3, 0xDE, 0x34, 0xD6, 0x13, 
+0xDE, 0x33, 0xCD, 0xD2, 0xBD, 0x51, 0x9C, 0x8F, 
+0xB5, 0x53, 0xA4, 0x8F, 0xAC, 0xD0, 0xB5, 0x11, 
+0xAC, 0xAF, 0xA4, 0x6F, 0x9C, 0x4E, 0x94, 0x2E, 
+0x7B, 0x8B, 0x83, 0xCC, 0x94, 0x2E, 0xA4, 0x8F, 
+0xA4, 0x8F, 0xA4, 0xD0, 0xA4, 0xD0, 0xAC, 0xF1, 
+0xAC, 0xD0, 0xA4, 0xB0, 0x9C, 0x6F, 0x94, 0x4F, 
+0x83, 0xCD, 0x4A, 0x27, 0x29, 0x45, 0x31, 0xA6, 
+0x5A, 0xCB, 0x94, 0x51, 0x83, 0xAE, 0x5A, 0x6A, 
+0x4A, 0x08, 0x39, 0xC7, 0x41, 0xE7, 0x4A, 0x08, 
+0x41, 0xE7, 0x4A, 0x29, 0x5A, 0x8A, 0x62, 0xCB, 
+0x52, 0x49, 0x73, 0x4D, 0x83, 0xCE, 0x8C, 0x10, 
+0x6B, 0x0B, 0x52, 0x8A, 0x31, 0x87, 0x31, 0x87, 
+0x10, 0xA3, 0x10, 0x82, 0x10, 0xA3, 0x10, 0xA3, 
+0x18, 0xE4, 0x29, 0x45, 0x19, 0x04, 0x10, 0xC3, 
+0x18, 0xE4, 0x73, 0x8D, 0x94, 0x70, 0x94, 0x50, 
+0x94, 0x70, 0x94, 0x4F, 0x8C, 0x0F, 0x8C, 0x2F, 
+0x8C, 0x2F, 0x94, 0x70, 0x94, 0x70, 0x8C, 0x2F, 
+0x8C, 0x0F, 0x8C, 0x0E, 0x8C, 0x2F, 0x8C, 0x2F, 
+0x8C, 0x2F, 0x7B, 0xCD, 0x8C, 0x4F, 0x94, 0x70, 
+0x84, 0x0E, 0x84, 0x0E, 0x9C, 0xD1, 0xA4, 0xF1, 
+0xAD, 0x11, 0xB5, 0x73, 0xA4, 0xD1, 0x94, 0x6F, 
+0xA4, 0xD0, 0x94, 0x6F, 0x83, 0xAC, 0x94, 0x2E, 
+0x9C, 0x6F, 0xB5, 0x31, 0xCD, 0xD4, 0xCD, 0xF4, 
+0xCD, 0xF4, 0xCD, 0xD4, 0xDE, 0x56, 0xE6, 0xB7, 
+0xEE, 0xD7, 0xEE, 0xD7, 0xE6, 0x96, 0xDE, 0x75, 
+0x53, 0xA7, 0x63, 0xE9, 0x64, 0x29, 0x4B, 0x64, 
+0x64, 0x05, 0x53, 0x86, 0x74, 0x8C, 0x74, 0x4C, 
+0x74, 0x4A, 0x7C, 0xAA, 0x84, 0xAC, 0x9D, 0x4E, 
+0x53, 0x66, 0x74, 0x6A, 0xBE, 0x33, 0xC6, 0x14, 
+0xC5, 0xF4, 0xCE, 0x54, 0xC6, 0x13, 0xCE, 0x13, 
+0xC5, 0xD3, 0xCD, 0xF3, 0xA4, 0x8E, 0xC5, 0xF3, 
+0xCE, 0x35, 0xC5, 0xF4, 0xC5, 0xF4, 0xC5, 0xF4, 
+0xC5, 0xD4, 0xCE, 0x15, 0xAD, 0x53, 0x4A, 0x48, 
+0x29, 0x45, 0x31, 0xA6, 0x39, 0xC6, 0x4A, 0x49, 
+0x42, 0x07, 0x4A, 0x69, 0x52, 0x8A, 0x5A, 0xEB, 
+0x7B, 0xEF, 0xD6, 0xBB, 0xF7, 0x9E, 0xCE, 0x37, 
+0xAD, 0x52, 0xBD, 0x92, 0xAC, 0xF0, 0xBD, 0x92, 
+0xB5, 0x72, 0xB5, 0x72, 0xAD, 0x31, 0xB5, 0x73, 
+0xC5, 0xD4, 0xCE, 0x35, 0xC5, 0xF4, 0xBD, 0xB3, 
+0xBD, 0xB3, 0xC5, 0xD4, 0xBD, 0xB3, 0xCE, 0x35, 
+0xB5, 0x51, 0xBD, 0x72, 0xBD, 0x72, 0xB5, 0x31, 
+0xBD, 0x72, 0xAC, 0xEF, 0x94, 0x2C, 0x9C, 0x8E, 
+0x9C, 0x6D, 0x9C, 0x4D, 0x9C, 0x8E, 0xC5, 0x92, 
+0xD5, 0xF3, 0xD6, 0x13, 0xCD, 0xF3, 0xC5, 0xB2, 
+0xB5, 0x31, 0xAD, 0x10, 0xAD, 0x31, 0xB5, 0x10, 
+0xBD, 0x71, 0xBD, 0x92, 0xB5, 0x30, 0xAC, 0xEF, 
+0xAC, 0xCF, 0xBD, 0x71, 0xBD, 0x30, 0xA4, 0xAE, 
+0xA4, 0xCF, 0x9C, 0xB0, 0x83, 0xCD, 0x5A, 0xA9, 
+0x5A, 0xCA, 0x4A, 0x48, 0x6B, 0x0C, 0x73, 0x8E, 
+0xC6, 0x39, 0xBD, 0xD7, 0x7B, 0xEF, 0x94, 0x92, 
+0xBD, 0xF7, 0x84, 0x30, 0x31, 0x86, 0x42, 0x49, 
+0x9C, 0xF3, 0xAD, 0x55, 0xAD, 0x55, 0xBD, 0xF8, 
+0xBD, 0xB7, 0xC6, 0x19, 0xCE, 0x39, 0xCE, 0x7A, 
+0xAD, 0x76, 0xC6, 0x19, 0xBD, 0xF7, 0x8C, 0x30, 
+0x8C, 0x0F, 0x94, 0x2E, 0x94, 0x0D, 0x8B, 0xEC, 
+0x83, 0x8B, 0x7B, 0x6A, 0x83, 0xCC, 0x83, 0xCC, 
+0x83, 0xAC, 0x8B, 0xEC, 0x94, 0x2D, 0x73, 0x29, 
+0x83, 0xAB, 0x94, 0x0C, 0x73, 0x29, 0xA4, 0xD0, 
+0x9C, 0x8F, 0xA4, 0xD0, 0xB5, 0x72, 0xB5, 0x72, 
+0xB5, 0x31, 0xAD, 0x31, 0x7B, 0xCD, 0x42, 0x07, 
+0x39, 0xC6, 0x42, 0x07, 0x4A, 0x28, 0x4A, 0x28, 
+0x5A, 0xAA, 0x5A, 0xCA, 0x5A, 0xAA, 0x73, 0x8D, 
+0x73, 0x8E, 0x7C, 0x10, 0x84, 0x51, 0x9C, 0xD4, 
+0xB5, 0xD7, 0xC6, 0x38, 0xBD, 0xB5, 0xAD, 0x32, 
+0xC5, 0xB3, 0xC5, 0xD4, 0xBD, 0x93, 0xB5, 0x73, 
+0xB5, 0x73, 0xBD, 0x94, 0xBD, 0xB4, 0xBD, 0xD4, 
+0xC5, 0xF4, 0xC5, 0xB4, 0xBD, 0x93, 0xBD, 0x73, 
+0xC5, 0xB4, 0xBD, 0x93, 0xB5, 0x93, 0xC5, 0xF4, 
+0xD6, 0x14, 0xD6, 0x35, 0xC5, 0xD3, 0xB5, 0x31, 
+0xAD, 0x11, 0xC5, 0xB3, 0xCD, 0xF4, 0xD6, 0x34, 
+0xD6, 0x14, 0xC5, 0x92, 0xBD, 0x92, 0xD6, 0x14, 
+0xC5, 0x93, 0xAD, 0x11, 0xA4, 0xF0, 0x9C, 0x8F, 
+0x94, 0x6E, 0x8C, 0x2D, 0x94, 0x8F, 0x9C, 0xAF, 
+0xA5, 0x11, 0xBD, 0x92, 0xBD, 0x93, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xBD, 0x93, 0xBD, 0xB4, 0xAD, 0x32, 
+0xAD, 0x53, 0xBD, 0xB4, 0xAD, 0x52, 0xB5, 0x53, 
+0xBD, 0xB4, 0xAD, 0x32, 0x9C, 0xB0, 0xA4, 0xD1, 
+0xB5, 0x52, 0xC5, 0xD4, 0xBD, 0x93, 0xC5, 0xD4, 
+0xB5, 0x73, 0xA5, 0x12, 0xAD, 0x32, 0xAD, 0x32, 
+0xAD, 0x12, 0xB5, 0x52, 0xC5, 0x92, 0xC5, 0x91, 
+0xC5, 0xB1, 0xBD, 0x51, 0xB5, 0x31, 0xB5, 0x32, 
+0xBD, 0x73, 0xB5, 0x11, 0xAC, 0xCF, 0x9C, 0x6E, 
+0x9C, 0x6E, 0xA4, 0xB0, 0xA4, 0xB0, 0xAD, 0x11, 
+0xA4, 0xD0, 0x9C, 0xB0, 0xA4, 0xD0, 0xB5, 0x31, 
+0xAC, 0xF1, 0xA4, 0xD0, 0xA4, 0xAF, 0xBD, 0x73, 
+0xBD, 0x93, 0xC5, 0xF5, 0xBD, 0x73, 0x9C, 0x90, 
+0x9C, 0xB0, 0x9C, 0x6F, 0x6B, 0x2B, 0x31, 0x65, 
+0x29, 0x25, 0x31, 0x65, 0x4A, 0x28, 0x62, 0xEB, 
+0x7B, 0x8E, 0x7B, 0xAE, 0x62, 0xCB, 0x4A, 0x08, 
+0x4A, 0x08, 0x41, 0xC7, 0x4A, 0x08, 0x62, 0xAA, 
+0x52, 0x69, 0x49, 0xE8, 0x73, 0x0C, 0xAC, 0xD2, 
+0xAC, 0xD2, 0x62, 0xCB, 0x20, 0xE4, 0x21, 0x05, 
+0x21, 0x04, 0x21, 0x04, 0x21, 0x25, 0x29, 0x45, 
+0x21, 0x25, 0x18, 0xE4, 0x19, 0x04, 0x18, 0xE4, 
+0x4A, 0x69, 0xA4, 0xF2, 0xAD, 0x33, 0xAD, 0x33, 
+0xB5, 0x53, 0xAD, 0x12, 0xAD, 0x32, 0xB5, 0x73, 
+0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x53, 
+0xB5, 0x53, 0xB5, 0x73, 0xAD, 0x53, 0xB5, 0x53, 
+0xAD, 0x33, 0xAD, 0x33, 0xA5, 0x12, 0xA5, 0x12, 
+0xA5, 0x12, 0xA5, 0x13, 0xA4, 0xF2, 0xA4, 0xF2, 
+0x9C, 0xD1, 0x9C, 0xD1, 0x9C, 0xD1, 0xA4, 0xF2, 
+0xA4, 0xF2, 0xA4, 0xF2, 0xA4, 0xF2, 0x9C, 0xB1, 
+0x94, 0x50, 0x8C, 0x2E, 0x8C, 0x0E, 0x8C, 0x2E, 
+0x8C, 0x0E, 0x8C, 0x0D, 0x94, 0x4E, 0x9C, 0x8F, 
+0xA4, 0xAF, 0xA4, 0xCF, 0x9C, 0x6E, 0x9C, 0x6E, 
+0x4B, 0x27, 0x7C, 0xAC, 0x74, 0x4A, 0x43, 0x03, 
+0x84, 0xEC, 0x8D, 0x0F, 0x63, 0xEB, 0x74, 0x4C, 
+0x64, 0x28, 0x6C, 0x47, 0x95, 0x2E, 0x6B, 0xE9, 
+0x64, 0x07, 0x7C, 0xAB, 0xB6, 0x13, 0xBD, 0xF4, 
+0xBD, 0xB3, 0xBD, 0xD3, 0xC5, 0xD3, 0xC5, 0xD3, 
+0xC5, 0xD3, 0xCE, 0x14, 0x9C, 0x4D, 0xAD, 0x10, 
+0x9C, 0xAF, 0xAD, 0x52, 0xC5, 0xF5, 0xC6, 0x15, 
+0xC5, 0xF4, 0xBD, 0xB4, 0xD6, 0x56, 0xC5, 0xF6, 
+0x5A, 0xEA, 0x29, 0x44, 0x31, 0x85, 0x31, 0xA6, 
+0x42, 0x07, 0x63, 0x2C, 0x6B, 0x4D, 0x4A, 0x49, 
+0x41, 0xE8, 0x73, 0x8E, 0xA5, 0x34, 0x4A, 0x49, 
+0x6B, 0x4C, 0xAD, 0x11, 0xAC, 0xF0, 0xBD, 0x93, 
+0xB5, 0x73, 0xBD, 0x92, 0xB5, 0x52, 0xB5, 0x52, 
+0xBD, 0xD4, 0xC5, 0xF4, 0x9C, 0x8F, 0xB5, 0x52, 
+0xC5, 0xF4, 0xBD, 0xB3, 0xB5, 0x52, 0xC5, 0xD4, 
+0xBD, 0xB3, 0xBD, 0x92, 0xB5, 0x31, 0xBD, 0x92, 
+0xB5, 0x30, 0xA4, 0xAE, 0xAD, 0x30, 0xB5, 0x51, 
+0xBD, 0x92, 0xAC, 0xCF, 0x9C, 0x8E, 0xBD, 0x92, 
+0xC5, 0xD2, 0xA4, 0xCF, 0xCD, 0xF4, 0xCD, 0xF3, 
+0xCE, 0x14, 0xBD, 0xD3, 0xC5, 0xF4, 0xCD, 0xD4, 
+0xC5, 0xD3, 0xCE, 0x14, 0xC5, 0xB3, 0xBD, 0xB3, 
+0xBD, 0x72, 0xC5, 0xB2, 0xC5, 0xB2, 0xBD, 0x92, 
+0xBD, 0x92, 0xB5, 0x73, 0x9C, 0xD0, 0x8C, 0x4F, 
+0x73, 0x6C, 0x39, 0xA6, 0x52, 0xAA, 0x5A, 0xCB, 
+0x8C, 0x51, 0xBD, 0xB6, 0x73, 0x8E, 0xB5, 0x76, 
+0xDE, 0xDB, 0xE7, 0x3C, 0x9C, 0xD3, 0x39, 0xE7, 
+0x5A, 0xCB, 0xAD, 0x76, 0xC6, 0x19, 0xB5, 0x97, 
+0xAD, 0x76, 0xB5, 0x76, 0xB5, 0x76, 0x8C, 0x52, 
+0x73, 0x8F, 0xD6, 0x7A, 0xDE, 0xFB, 0xC5, 0xF7, 
+0xC5, 0x95, 0xBD, 0x32, 0xBD, 0x52, 0xC5, 0x72, 
+0xBD, 0x31, 0xB5, 0x31, 0xB5, 0x31, 0xB5, 0x11, 
+0xB4, 0xF0, 0xAC, 0xCF, 0xAC, 0xAF, 0xAC, 0xD0, 
+0xB4, 0xF0, 0xB5, 0x10, 0xA4, 0xCF, 0x9C, 0x6E, 
+0x9C, 0x6E, 0x9C, 0x4D, 0x94, 0x0C, 0x83, 0xCB, 
+0x8C, 0x0C, 0x94, 0x4D, 0x94, 0x4E, 0x6B, 0x2A, 
+0x31, 0xA5, 0x42, 0x07, 0x42, 0x07, 0x42, 0x07, 
+0x4A, 0x48, 0x52, 0x89, 0x52, 0xAA, 0x52, 0xAA, 
+0x6B, 0x4D, 0x7B, 0xF0, 0x94, 0x92, 0x9C, 0xF4, 
+0xAD, 0x55, 0xAD, 0x55, 0xCE, 0x58, 0xB5, 0x74, 
+0xB5, 0x52, 0xB5, 0x32, 0xA4, 0xF1, 0xA4, 0xD0, 
+0xAD, 0x32, 0xB5, 0x73, 0xBD, 0x93, 0xBD, 0xD4, 
+0xC5, 0xF4, 0xC5, 0xD4, 0xB5, 0x72, 0xC5, 0xB3, 
+0xCD, 0xF4, 0xCE, 0x35, 0xCE, 0x15, 0xCD, 0xF4, 
+0xD6, 0x35, 0xD6, 0x55, 0xCE, 0x14, 0xB5, 0x31, 
+0xAC, 0xF1, 0xBD, 0xB3, 0xBD, 0x52, 0xCD, 0xD3, 
+0xD6, 0x14, 0xCD, 0xD3, 0xCD, 0xF4, 0xD6, 0x35, 
+0xD6, 0x14, 0xC5, 0xB3, 0xC5, 0x93, 0xC5, 0xB3, 
+0xAD, 0x31, 0x9C, 0x8F, 0xAD, 0x11, 0xB5, 0x72, 
+0xBD, 0x93, 0xCD, 0xF4, 0xCE, 0x14, 0xBD, 0x92, 
+0xBD, 0xB2, 0xC5, 0xD3, 0xC5, 0xF4, 0xAD, 0x32, 
+0xAD, 0x32, 0xC5, 0xD4, 0xBD, 0x94, 0xBD, 0x94, 
+0xC5, 0xD5, 0xBD, 0xB4, 0xAD, 0x12, 0x9C, 0xB0, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xB5, 0x52, 0xBD, 0xB4, 
+0xB5, 0x73, 0xA5, 0x12, 0xB5, 0x53, 0xB5, 0x93, 
+0xBD, 0x94, 0xB5, 0x53, 0xBD, 0x72, 0xCD, 0xF3, 
+0xC5, 0x92, 0xA4, 0xD0, 0xB5, 0x52, 0xB5, 0x52, 
+0xB5, 0x32, 0x9C, 0x4E, 0x94, 0x0D, 0x9C, 0x4E, 
+0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xAC, 0xF1, 0xA4, 0xB0, 0x9C, 0x6F, 0xA4, 0xD0, 
+0x9C, 0x6F, 0xA4, 0xB0, 0xBD, 0x93, 0xB5, 0x53, 
+0x9C, 0x8F, 0x9C, 0xB0, 0xA4, 0xB0, 0x9C, 0xB0, 
+0xBD, 0x93, 0xC5, 0xD4, 0xCD, 0xF4, 0x83, 0xCC, 
+0x41, 0xE6, 0x29, 0x44, 0x29, 0x44, 0x39, 0xC6, 
+0x52, 0x69, 0x7B, 0x8E, 0xA4, 0xD3, 0x83, 0xEF, 
+0x4A, 0x28, 0x52, 0x29, 0x52, 0x29, 0x52, 0x49, 
+0x62, 0xEB, 0x5A, 0x8A, 0x4A, 0x08, 0x7B, 0x8D, 
+0x94, 0x50, 0xA4, 0xD3, 0x73, 0x4D, 0x20, 0xE4, 
+0x18, 0xE4, 0x19, 0x04, 0x21, 0x25, 0x21, 0x25, 
+0x21, 0x04, 0x18, 0xE4, 0x18, 0xC4, 0x5A, 0xCB, 
+0x84, 0x0E, 0x8C, 0x2F, 0x94, 0x6F, 0xA4, 0xF2, 
+0xB5, 0x74, 0xCD, 0xF6, 0xB5, 0x73, 0x8C, 0x2F, 
+0x94, 0x4F, 0xB5, 0x74, 0x9C, 0x70, 0x9C, 0x90, 
+0x9C, 0xB0, 0x9C, 0x90, 0x94, 0x70, 0x83, 0xEE, 
+0x8C, 0x0E, 0x94, 0x50, 0xA4, 0xF2, 0xCE, 0x57, 
+0xBD, 0xB4, 0x9C, 0x90, 0xAD, 0x12, 0xAD, 0x33, 
+0xAD, 0x12, 0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x32, 
+0xAD, 0x12, 0xB5, 0x32, 0xB5, 0x73, 0xB5, 0x32, 
+0xBD, 0x74, 0xB5, 0x53, 0xAD, 0x12, 0xB5, 0x32, 
+0xB5, 0x53, 0xB5, 0x53, 0xAD, 0x32, 0xB5, 0x32, 
+0xB5, 0x32, 0xAD, 0x11, 0xAC, 0xF1, 0xAC, 0xF1, 
+0x32, 0x24, 0x5B, 0x88, 0x6B, 0xC9, 0x42, 0xA4, 
+0x7C, 0xAD, 0xA5, 0x93, 0xB6, 0x36, 0x74, 0x4C, 
+0x64, 0x27, 0x63, 0xE5, 0x74, 0x68, 0x74, 0x6A, 
+0x6C, 0x69, 0x7C, 0xAC, 0xBE, 0x54, 0xBD, 0xD3, 
+0xB5, 0xB2, 0xBD, 0xD3, 0xC5, 0xF4, 0xBD, 0xD4, 
+0xC6, 0x14, 0xD6, 0x55, 0xA4, 0x8E, 0x8C, 0x0C, 
+0x6B, 0x2A, 0xBD, 0xB4, 0xC6, 0x15, 0xC5, 0xF4, 
+0xC6, 0x15, 0xC5, 0xF5, 0xC5, 0xF5, 0xD6, 0x77, 
+0xCE, 0x36, 0x7B, 0x8C, 0x31, 0x85, 0x31, 0x85, 
+0x42, 0x07, 0x4A, 0x48, 0x42, 0x07, 0x42, 0x08, 
+0x52, 0x8A, 0x42, 0x28, 0x52, 0x6A, 0x73, 0x8E, 
+0x41, 0xC7, 0x39, 0xC7, 0xB5, 0x95, 0xB5, 0x93, 
+0xAD, 0x11, 0xBD, 0xD4, 0xB5, 0x72, 0xB5, 0x72, 
+0xC5, 0xF4, 0xBD, 0x93, 0xB5, 0x93, 0xCE, 0x15, 
+0xC5, 0xF4, 0xB5, 0x93, 0xB5, 0x52, 0xBD, 0xD4, 
+0xBD, 0xB3, 0xB5, 0x51, 0xAD, 0x31, 0xA4, 0xEF, 
+0xAD, 0x10, 0xA4, 0xCF, 0xAC, 0xEF, 0xB5, 0x30, 
+0xC5, 0x71, 0x9C, 0x6D, 0xA4, 0xCF, 0xBD, 0xB3, 
+0xCD, 0xF4, 0x83, 0xED, 0xC5, 0xD4, 0xC5, 0xD3, 
+0xC5, 0xF4, 0xBD, 0xD3, 0xCE, 0x15, 0xCE, 0x35, 
+0xC5, 0xD3, 0xC5, 0xF4, 0xBD, 0xB3, 0xC5, 0xD4, 
+0xAD, 0x11, 0xBD, 0x93, 0xBD, 0x92, 0xB5, 0x71, 
+0xB5, 0x51, 0xC5, 0xD4, 0xA5, 0x11, 0xAD, 0x11, 
+0x9C, 0x8F, 0x8C, 0x0D, 0x73, 0x6B, 0x52, 0x68, 
+0x5A, 0xCA, 0x7B, 0xAE, 0x83, 0xEF, 0xB5, 0x76, 
+0xC6, 0x18, 0xB5, 0x96, 0xB5, 0x96, 0x7B, 0xCE, 
+0x42, 0x08, 0x6B, 0x2D, 0xC6, 0x39, 0x9C, 0xB3, 
+0x52, 0x8B, 0x39, 0xE8, 0xA5, 0x15, 0xCE, 0x7A, 
+0x9C, 0xD3, 0x52, 0x8A, 0x8C, 0x51, 0xDE, 0xBA, 
+0xEE, 0xFB, 0xD6, 0x17, 0x8B, 0xCE, 0x8B, 0xED, 
+0x7B, 0x6B, 0x7B, 0x8B, 0x83, 0xAB, 0x7B, 0x8B, 
+0x83, 0xAC, 0x83, 0x8C, 0x7B, 0x6B, 0x8B, 0xED, 
+0xAD, 0x10, 0xAC, 0xF0, 0xA4, 0xAF, 0xBD, 0x51, 
+0xC5, 0xB3, 0xC5, 0x92, 0xB5, 0x31, 0xAC, 0xEF, 
+0xA4, 0xCF, 0xA4, 0xCF, 0xA4, 0xCF, 0x9C, 0x6F, 
+0x4A, 0x27, 0x39, 0xA5, 0x39, 0xA6, 0x31, 0x85, 
+0x42, 0x27, 0x52, 0xA9, 0x4A, 0x89, 0x52, 0xAA, 
+0x63, 0x2C, 0x73, 0x8E, 0x94, 0xB3, 0x8C, 0x72, 
+0x8C, 0x52, 0x9C, 0xF4, 0xCE, 0x59, 0xB5, 0x75, 
+0x94, 0x70, 0x94, 0x4F, 0x8C, 0x0E, 0x8C, 0x0E, 
+0x8C, 0x2F, 0x94, 0x4F, 0x9C, 0x6F, 0x9C, 0xAF, 
+0x9C, 0xB0, 0x9C, 0x8F, 0x94, 0x6E, 0x9C, 0x8F, 
+0xA4, 0xB0, 0xA4, 0xB0, 0xAD, 0x11, 0xBD, 0x72, 
+0xBD, 0x72, 0xBD, 0x93, 0xB5, 0x52, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAD, 0x31, 0xCE, 0x15, 0xD6, 0x35, 
+0xD6, 0x34, 0xD6, 0x14, 0xDE, 0x76, 0xD6, 0x35, 
+0xDE, 0x55, 0xD6, 0x14, 0xCD, 0xF4, 0xDE, 0xB7, 
+0xCD, 0xF4, 0xBD, 0xB3, 0xCD, 0xF4, 0xCE, 0x14, 
+0xD6, 0x35, 0xD6, 0x14, 0xD6, 0x34, 0xD6, 0x34, 
+0xDE, 0x55, 0xD6, 0x14, 0xCE, 0x15, 0xB5, 0x53, 
+0xB5, 0x52, 0xC5, 0xD4, 0xB5, 0x93, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xBD, 0x94, 0xAD, 0x12, 0x83, 0xED, 
+0x9C, 0xD1, 0xCE, 0x36, 0xB5, 0x73, 0xBD, 0xB4, 
+0xB5, 0x73, 0xAD, 0x12, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xBD, 0x94, 0xB5, 0x53, 0xBD, 0x93, 0xC5, 0xF3, 
+0xBD, 0x92, 0xA4, 0xD0, 0x9C, 0xAF, 0xAC, 0xF1, 
+0xAC, 0xF1, 0x94, 0x4E, 0x94, 0x2D, 0x94, 0x4E, 
+0x9C, 0x4E, 0x94, 0x4E, 0x9C, 0x6E, 0xAC, 0xF1, 
+0xB5, 0x32, 0xA4, 0xB0, 0x9C, 0x4E, 0x9C, 0x8F, 
+0x9C, 0x6F, 0xA4, 0xD0, 0xC5, 0xD4, 0xB5, 0x52, 
+0x9C, 0x6E, 0xA4, 0xAF, 0x9C, 0x8F, 0x9C, 0x4F, 
+0x9C, 0x8F, 0xAC, 0xF0, 0xBD, 0x92, 0xA4, 0xAF, 
+0x94, 0x4F, 0x63, 0x0A, 0x39, 0xA6, 0x29, 0x44, 
+0x31, 0x65, 0x39, 0xC7, 0x4A, 0x49, 0x63, 0x0C, 
+0x4A, 0x49, 0x62, 0xEB, 0x94, 0x51, 0x7B, 0xCF, 
+0x39, 0xA6, 0x62, 0xCB, 0x5A, 0x8A, 0x4A, 0x29, 
+0x5A, 0xAA, 0x9C, 0x71, 0xBD, 0x75, 0x83, 0xAE, 
+0x31, 0x66, 0x18, 0xC4, 0x18, 0xE4, 0x18, 0xE4, 
+0x18, 0xE3, 0x18, 0xE4, 0x5A, 0xCA, 0xD6, 0x76, 
+0xEF, 0x18, 0xDE, 0xB7, 0xCD, 0xF5, 0xBD, 0x94, 
+0xAD, 0x53, 0xBD, 0xB4, 0xC5, 0xF5, 0x94, 0x90, 
+0xBD, 0xD5, 0xDE, 0xB8, 0xAD, 0x32, 0x94, 0x70, 
+0x8C, 0x4F, 0xA4, 0xF2, 0xA5, 0x12, 0xAD, 0x33, 
+0xB5, 0x94, 0xB5, 0x74, 0xBD, 0x94, 0xD6, 0x56, 
+0xDE, 0xB8, 0x94, 0x70, 0xB5, 0x53, 0xB5, 0x32, 
+0xAD, 0x11, 0xC5, 0xD3, 0xCD, 0xD4, 0xCD, 0xD4, 
+0xC5, 0xB3, 0xCD, 0xF4, 0xCE, 0x14, 0xBD, 0x93, 
+0xBD, 0x72, 0xBD, 0x73, 0xD6, 0x35, 0xD6, 0x14, 
+0xBD, 0x92, 0xC5, 0xB3, 0xCD, 0xF4, 0xD6, 0x14, 
+0xDE, 0x55, 0xD6, 0x35, 0xD6, 0x14, 0xCD, 0xF4, 
+0x63, 0xCB, 0x4A, 0xE6, 0x74, 0x0A, 0x4A, 0xC5, 
+0x63, 0xCA, 0x9D, 0x52, 0xA5, 0x73, 0x5B, 0x48, 
+0x64, 0x08, 0x4B, 0x23, 0x63, 0xE7, 0x6C, 0x69, 
+0x7C, 0xCB, 0x7C, 0x8B, 0x8C, 0xAD, 0x9D, 0x0D, 
+0xA5, 0x4D, 0xAD, 0x6F, 0xA4, 0xCF, 0xA4, 0xCF, 
+0xAD, 0x30, 0xBD, 0x91, 0xA4, 0xAE, 0x94, 0x0C, 
+0xAD, 0x52, 0xD6, 0x96, 0xDE, 0xB7, 0xD6, 0x76, 
+0xD6, 0x76, 0xD6, 0x97, 0xD6, 0x76, 0xD6, 0x97, 
+0xD6, 0x97, 0xC5, 0xF4, 0x94, 0x6F, 0x4A, 0x67, 
+0x39, 0xC6, 0x41, 0xE7, 0x39, 0xE7, 0x52, 0xAA, 
+0x73, 0x8E, 0x4A, 0x69, 0x5A, 0xCA, 0x73, 0x6D, 
+0x83, 0xAE, 0x73, 0xAE, 0xEF, 0x7C, 0xEF, 0x5B, 
+0xBD, 0xB5, 0xAD, 0x32, 0xAD, 0x31, 0xAD, 0x11, 
+0xC5, 0xD4, 0xB5, 0x93, 0xBD, 0xB3, 0xBD, 0xB4, 
+0xB5, 0x72, 0xB5, 0x72, 0xAD, 0x31, 0xAD, 0x31, 
+0xA4, 0xF0, 0xA4, 0xEF, 0xA4, 0xCF, 0x94, 0x6D, 
+0xA4, 0xEF, 0xA4, 0xEF, 0xC5, 0x91, 0xCD, 0xD2, 
+0xD6, 0x34, 0x9C, 0x6D, 0xAD, 0x11, 0xC5, 0xF4, 
+0xCE, 0x55, 0xB5, 0x93, 0xAD, 0x52, 0xB5, 0x93, 
+0xBD, 0xB3, 0xB5, 0x52, 0xB5, 0x92, 0xBD, 0xD3, 
+0xBD, 0xB3, 0xC5, 0xD4, 0xBD, 0xD4, 0xC6, 0x15, 
+0xB5, 0x93, 0xC5, 0xD4, 0xBD, 0x92, 0xAD, 0x51, 
+0x94, 0x4E, 0xA4, 0xF0, 0xA4, 0xF1, 0xAD, 0x31, 
+0xBD, 0x71, 0xDE, 0x54, 0xCD, 0xD3, 0xB5, 0x52, 
+0x6A, 0xEA, 0x4A, 0x28, 0x7B, 0xCF, 0xA5, 0x14, 
+0x7B, 0xAF, 0x83, 0xF0, 0xAD, 0x75, 0xC5, 0xF7, 
+0x52, 0x8A, 0x42, 0x49, 0x73, 0xAF, 0xB5, 0x96, 
+0xA5, 0x14, 0x73, 0x8E, 0xAD, 0x76, 0xAD, 0x35, 
+0x52, 0x6A, 0x5A, 0xAB, 0xA5, 0x14, 0xDE, 0x9A, 
+0xF7, 0x3C, 0xEF, 0x1C, 0xB5, 0x75, 0x7B, 0xAD, 
+0x7B, 0xAC, 0x8C, 0x0E, 0x8C, 0x2E, 0x83, 0xED, 
+0x7B, 0xCD, 0x83, 0xCD, 0x8C, 0x2E, 0x8C, 0x2E, 
+0x94, 0x6F, 0x7B, 0xAC, 0x7B, 0xAB, 0xA4, 0xAF, 
+0x9C, 0x6E, 0x9C, 0x8E, 0xAC, 0xCF, 0xB5, 0x31, 
+0xA4, 0xD0, 0xA4, 0xB0, 0x9C, 0x8F, 0xA4, 0xB0, 
+0x7B, 0x8C, 0x41, 0xE6, 0x39, 0xC6, 0x39, 0xC6, 
+0x41, 0xE7, 0x52, 0xA9, 0x42, 0x28, 0x52, 0x8A, 
+0x5A, 0xEB, 0x63, 0x2C, 0x6B, 0x4D, 0x73, 0x6E, 
+0x7B, 0xAF, 0x9C, 0xF4, 0xBD, 0xF8, 0xCE, 0x59, 
+0xB5, 0x54, 0xAD, 0x12, 0xB5, 0x53, 0xAD, 0x12, 
+0xA4, 0xB1, 0x9C, 0x6F, 0x9C, 0x90, 0xA4, 0xD0, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF1, 0xA4, 0xD0, 
+0x9C, 0x6F, 0x9C, 0x6F, 0x9C, 0x6F, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xAC, 0xF1, 0xB5, 0x52, 
+0xBD, 0x73, 0xB5, 0x52, 0xA4, 0xB0, 0xA4, 0x8F, 
+0x9C, 0x8F, 0x9C, 0x6E, 0xA4, 0xD0, 0xB5, 0x52, 
+0xC5, 0xD3, 0xC5, 0xB3, 0xBD, 0x92, 0xCD, 0xF4, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xCE, 0x14, 0xD6, 0x55, 
+0xD6, 0x34, 0xD6, 0x35, 0xD6, 0x34, 0xDE, 0x75, 
+0xDE, 0x76, 0xDE, 0x55, 0xCD, 0xF4, 0xA4, 0xF1, 
+0xAC, 0xF1, 0xBD, 0x93, 0xB5, 0x53, 0xBD, 0x94, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xBD, 0xB4, 0xAD, 0x53, 
+0xA4, 0xF1, 0xC5, 0xF5, 0xB5, 0x93, 0xC5, 0xF5, 
+0xB5, 0x73, 0xAD, 0x53, 0xBD, 0xB5, 0xBD, 0xB4, 
+0xBD, 0xB4, 0xAD, 0x12, 0xBD, 0x93, 0xBD, 0xB3, 
+0xC5, 0xB3, 0xAD, 0x31, 0xA4, 0xF0, 0xAD, 0x11, 
+0xAD, 0x32, 0xA4, 0xF0, 0x9C, 0x8E, 0xA4, 0xD0, 
+0x9C, 0x6E, 0xA4, 0xD0, 0xAC, 0xF0, 0xB5, 0x31, 
+0xB5, 0x31, 0xA4, 0xD0, 0xA4, 0x8F, 0x9C, 0x8F, 
+0xA4, 0xD0, 0x9C, 0x6E, 0x94, 0x2D, 0x9C, 0x8F, 
+0x94, 0x6E, 0x94, 0x4E, 0xAC, 0xF1, 0xAC, 0xF1, 
+0xAC, 0xF0, 0xA4, 0xD0, 0xBD, 0x72, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xB5, 0x52, 0x83, 0xEE, 0x39, 0xC6, 
+0x29, 0x44, 0x29, 0x44, 0x29, 0x45, 0x29, 0x45, 
+0x29, 0x65, 0x41, 0xE7, 0x6B, 0x2D, 0x7B, 0xCF, 
+0x4A, 0x49, 0x62, 0xEB, 0x5A, 0x8A, 0x52, 0x6A, 
+0x41, 0xE8, 0x5A, 0xAB, 0x83, 0xAE, 0xA4, 0xD3, 
+0x94, 0x51, 0x41, 0xE8, 0x10, 0x82, 0x10, 0xA3, 
+0x21, 0x04, 0x52, 0x68, 0xD6, 0x55, 0xEF, 0x18, 
+0xEE, 0xD7, 0xE6, 0xD7, 0xE6, 0xB7, 0xDE, 0xB8, 
+0xCE, 0x57, 0xC6, 0x16, 0xC6, 0x16, 0xC6, 0x16, 
+0xCE, 0x77, 0xD6, 0x97, 0xCE, 0x57, 0xBD, 0xF6, 
+0xCE, 0x37, 0xD6, 0x98, 0xDE, 0xB8, 0xDE, 0xB8, 
+0xDE, 0xB8, 0xDE, 0xB8, 0xE6, 0xD9, 0xE6, 0xB8, 
+0xDE, 0xB8, 0xA4, 0xF2, 0xBD, 0xB4, 0xD6, 0x34, 
+0xD6, 0x34, 0xDE, 0x74, 0xDE, 0x75, 0xDE, 0x75, 
+0xDE, 0x55, 0xDE, 0x75, 0xE6, 0x96, 0xD6, 0x34, 
+0xDE, 0x55, 0xDE, 0x55, 0xE6, 0x95, 0xE6, 0x95, 
+0xE6, 0x75, 0xE6, 0x95, 0xE6, 0x95, 0xEE, 0xB6, 
+0xE6, 0x95, 0xE6, 0xB5, 0xE6, 0xB6, 0xEE, 0xD6, 
+0x74, 0x2C, 0x53, 0x47, 0x63, 0xC8, 0x6C, 0x09, 
+0x5B, 0x89, 0x74, 0x2C, 0x74, 0x0B, 0x53, 0x27, 
+0x6C, 0x29, 0x43, 0x03, 0x53, 0x65, 0x53, 0xA7, 
+0x6C, 0x69, 0x74, 0x89, 0x8C, 0xEA, 0x95, 0x49, 
+0x9D, 0x6A, 0x9C, 0xCA, 0x94, 0x8B, 0x84, 0x2A, 
+0x9C, 0xEE, 0xAD, 0x0F, 0xA4, 0x8D, 0x94, 0x2C, 
+0x8B, 0xCB, 0x8C, 0x0C, 0x94, 0x2D, 0x94, 0x4D, 
+0x9C, 0x6D, 0x9C, 0x6E, 0xA4, 0xF0, 0xAC, 0xF0, 
+0x94, 0x2D, 0x83, 0xCC, 0x9C, 0x6E, 0x9C, 0x6F, 
+0x52, 0x47, 0x39, 0xC6, 0x42, 0x07, 0x4A, 0x48, 
+0x52, 0xAA, 0x52, 0x89, 0x4A, 0x49, 0x41, 0xE7, 
+0x63, 0x0C, 0x63, 0x0C, 0xBD, 0xD7, 0xEF, 0x5D, 
+0xEF, 0x7D, 0xDE, 0xBA, 0x94, 0x91, 0x6B, 0x2B, 
+0x9C, 0xD0, 0xBD, 0xB4, 0xC5, 0xF4, 0xBD, 0xD4, 
+0xBD, 0xB3, 0xB5, 0x93, 0xAD, 0x52, 0xB5, 0x72, 
+0xAD, 0x31, 0xA5, 0x10, 0x8C, 0x0C, 0x94, 0x4D, 
+0xA4, 0xAE, 0xC5, 0xB1, 0xD6, 0x12, 0xD6, 0x12, 
+0xDE, 0x54, 0x8B, 0xCB, 0x8C, 0x2D, 0xAD, 0x31, 
+0xB5, 0x92, 0xA5, 0x11, 0xA5, 0x11, 0x9C, 0xD1, 
+0xAD, 0x52, 0xA5, 0x11, 0xB5, 0xB3, 0xAD, 0x52, 
+0xB5, 0x72, 0xBD, 0xB3, 0xBD, 0xD3, 0xBD, 0xD4, 
+0xC5, 0xF4, 0xC5, 0xF4, 0xBD, 0x92, 0xA4, 0xF0, 
+0x9C, 0xB0, 0x8C, 0x2E, 0x83, 0xED, 0x94, 0x6E, 
+0xB5, 0x30, 0xDE, 0x34, 0xC5, 0x91, 0xC5, 0xB2, 
+0xA4, 0xAF, 0x8C, 0x0D, 0x6B, 0x2B, 0x84, 0x10, 
+0x73, 0xAF, 0xA5, 0x14, 0x9C, 0xF3, 0xB5, 0x75, 
+0xA5, 0x14, 0x52, 0x8A, 0x39, 0xE8, 0x73, 0xAF, 
+0xC6, 0x18, 0xA5, 0x14, 0xBD, 0xF7, 0xBD, 0xD7, 
+0x9C, 0xB2, 0xC5, 0xD7, 0xDE, 0xDA, 0xE6, 0xBA, 
+0xF7, 0x5D, 0xEE, 0xFB, 0xDE, 0x79, 0x94, 0x70, 
+0x9C, 0x90, 0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x12, 
+0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xBD, 0xB4, 0xAD, 0x12, 0x8C, 0x2E, 0x9C, 0xB0, 
+0x9C, 0xAF, 0x9C, 0x8F, 0xAC, 0xF0, 0xBD, 0x72, 
+0xB5, 0x52, 0x94, 0x6F, 0xB5, 0x93, 0xC5, 0xF5, 
+0xB5, 0x53, 0x52, 0x48, 0x39, 0xA5, 0x39, 0xC6, 
+0x31, 0x85, 0x42, 0x28, 0x42, 0x28, 0x5A, 0xEB, 
+0x6B, 0x4C, 0x63, 0x0C, 0x63, 0x2C, 0x7B, 0xAF, 
+0x8C, 0x72, 0xA5, 0x35, 0xB5, 0xB7, 0xC6, 0x18, 
+0xCE, 0x17, 0x9C, 0x91, 0xAC, 0xF1, 0xC5, 0xD5, 
+0xBD, 0xB4, 0xAD, 0x32, 0xBD, 0x93, 0xAC, 0xF1, 
+0xA4, 0xD0, 0xAC, 0xF1, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xAD, 0x12, 0xAC, 0xF1, 0xA4, 0xD0, 0xAC, 0xF1, 
+0xA4, 0x90, 0xA4, 0xD0, 0xA4, 0xF0, 0xAC, 0xF0, 
+0xAC, 0xF1, 0xAD, 0x12, 0xB5, 0x52, 0xB5, 0x32, 
+0xB5, 0x52, 0xB5, 0x12, 0xB5, 0x32, 0xA4, 0x8F, 
+0x8B, 0xED, 0xA4, 0xD0, 0xB5, 0x31, 0xB5, 0x31, 
+0xAD, 0x10, 0xAD, 0x11, 0xA4, 0xD0, 0xAC, 0xF0, 
+0xA4, 0xD0, 0xAC, 0xF0, 0xAD, 0x10, 0xB5, 0x11, 
+0xB5, 0x10, 0xAD, 0x10, 0xB5, 0x11, 0xB5, 0x31, 
+0xB5, 0x72, 0xB5, 0x52, 0xA4, 0xF1, 0xA4, 0xD0, 
+0x9C, 0xB0, 0xAD, 0x11, 0xAD, 0x32, 0xAD, 0x11, 
+0x9C, 0xD0, 0xA4, 0xF1, 0xA4, 0xD1, 0x9C, 0xB0, 
+0x94, 0x90, 0xA4, 0xF1, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xAD, 0x32, 0x9C, 0xB1, 0xA4, 0xF1, 0xAD, 0x32, 
+0xBD, 0x93, 0xAC, 0xF0, 0xB5, 0x52, 0xAD, 0x11, 
+0xB5, 0x52, 0xAD, 0x31, 0xAD, 0x10, 0xBD, 0x93, 
+0xAC, 0xF0, 0xB5, 0x32, 0xBD, 0x73, 0xB5, 0x31, 
+0xC5, 0xB3, 0xAD, 0x11, 0xAD, 0x11, 0xA4, 0xD0, 
+0xA4, 0xD0, 0x9C, 0x6F, 0xA4, 0xB0, 0xAC, 0xF1, 
+0xA4, 0xD0, 0x9C, 0xAF, 0xB5, 0x52, 0xB5, 0x11, 
+0xAC, 0xF1, 0xAD, 0x11, 0xAD, 0x11, 0xAC, 0xF0, 
+0xB5, 0x52, 0xBD, 0x73, 0xBD, 0xD4, 0xA4, 0xD1, 
+0x5A, 0xCA, 0x31, 0x85, 0x29, 0x24, 0x21, 0x03, 
+0x29, 0x24, 0x29, 0x65, 0x29, 0x65, 0x39, 0xC7, 
+0x41, 0xE7, 0x4A, 0x28, 0x5A, 0xAB, 0x52, 0x49, 
+0x4A, 0x29, 0x4A, 0x08, 0x83, 0xAF, 0x83, 0xAE, 
+0xB5, 0x34, 0xA4, 0xD3, 0x41, 0xE8, 0x18, 0xC4, 
+0x63, 0x0B, 0xAC, 0xF1, 0xF7, 0x18, 0xE6, 0xD7, 
+0xE6, 0xD6, 0xE6, 0xB6, 0xDE, 0x96, 0xE6, 0xD8, 
+0xE6, 0xD8, 0xDE, 0xB8, 0xDE, 0xB8, 0xDE, 0xB8, 
+0xDE, 0xB8, 0xDE, 0x97, 0xDE, 0x97, 0xDE, 0x98, 
+0xDE, 0xD8, 0xDE, 0xD8, 0xDE, 0xB7, 0xDE, 0xB8, 
+0xE6, 0xD8, 0xE6, 0xF8, 0xE6, 0xF8, 0xE6, 0xD8, 
+0xDE, 0xB8, 0xAD, 0x12, 0xA4, 0xD0, 0xE6, 0xB6, 
+0xE6, 0x95, 0xE6, 0x74, 0xE6, 0x75, 0xDE, 0x75, 
+0xE6, 0x96, 0xDE, 0x75, 0xDE, 0x55, 0xDE, 0x75, 
+0xDE, 0x75, 0xDE, 0x75, 0xE6, 0x95, 0xE6, 0x95, 
+0xEE, 0xB5, 0xEE, 0xB5, 0xE6, 0x95, 0xE6, 0x95, 
+0xE6, 0x54, 0xDE, 0x54, 0xDE, 0x34, 0xDE, 0x34, 
+0x6C, 0x0A, 0x6C, 0x2A, 0x6C, 0x4A, 0x63, 0xE9, 
+0x6B, 0xEA, 0x8C, 0xCE, 0x42, 0x85, 0x3A, 0x84, 
+0x53, 0x86, 0x74, 0x68, 0x53, 0xA6, 0x43, 0x45, 
+0x64, 0x68, 0x5C, 0x25, 0x95, 0x6A, 0xA5, 0xAA, 
+0x9D, 0x69, 0x84, 0x88, 0x7C, 0x48, 0x8C, 0xEC, 
+0xAD, 0x6F, 0xCD, 0xF3, 0xCD, 0xD3, 0xCD, 0xD2, 
+0xC5, 0x92, 0xAC, 0xEF, 0xB5, 0x30, 0xC5, 0x92, 
+0xCD, 0xF3, 0xD5, 0xF4, 0xD5, 0xF3, 0xCD, 0xB2, 
+0xCD, 0xD3, 0xCD, 0xD2, 0xA4, 0x8E, 0x9C, 0x6D, 
+0xB5, 0x52, 0x6B, 0x2A, 0x41, 0xE7, 0x4A, 0x48, 
+0x52, 0x89, 0x52, 0x69, 0x42, 0x28, 0x39, 0xC6, 
+0x41, 0xE7, 0x41, 0xE7, 0x39, 0xC7, 0x7B, 0xF0, 
+0xC6, 0x18, 0xEF, 0x7D, 0xEF, 0x3D, 0xAD, 0x34, 
+0x8C, 0x0E, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x31, 
+0xBD, 0x93, 0xA4, 0xF0, 0xA4, 0xF0, 0xAD, 0x31, 
+0xAD, 0x10, 0xA4, 0xF0, 0x94, 0x6E, 0x94, 0x4D, 
+0xA4, 0xAE, 0xDE, 0x74, 0xE6, 0x74, 0xDE, 0x33, 
+0xD6, 0x13, 0x8C, 0x0C, 0x94, 0x4E, 0x9C, 0xAF, 
+0x9C, 0xB0, 0x8C, 0x4E, 0x8C, 0x4E, 0x94, 0x90, 
+0x9C, 0xB0, 0x8C, 0x4E, 0xA5, 0x32, 0xB5, 0x73, 
+0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x72, 0xBD, 0xB3, 
+0xBD, 0xD4, 0xBD, 0x93, 0xB5, 0x72, 0x9C, 0xAF, 
+0xAD, 0x10, 0xA5, 0x11, 0xA4, 0xF0, 0xAD, 0x10, 
+0xAD, 0x0F, 0xDE, 0x34, 0xCD, 0xD2, 0xD5, 0xF3, 
+0xAC, 0xAE, 0x8B, 0xEC, 0x9C, 0x8F, 0x73, 0x6C, 
+0x8C, 0x30, 0x7B, 0xCF, 0x7B, 0xAF, 0x94, 0x72, 
+0xB5, 0x75, 0xB5, 0x75, 0x42, 0x07, 0x4A, 0x49, 
+0x7B, 0xAE, 0x6B, 0x4D, 0x9C, 0xD3, 0xAD, 0x14, 
+0xCD, 0xF7, 0xBD, 0x75, 0xC5, 0xF7, 0xD6, 0x38, 
+0xCE, 0x18, 0xE6, 0xBA, 0xCE, 0x17, 0xB5, 0x34, 
+0xBD, 0xB4, 0xB5, 0x73, 0xAD, 0x12, 0xB5, 0x53, 
+0xB5, 0x93, 0xB5, 0x73, 0xAD, 0x32, 0x9C, 0x8F, 
+0xAD, 0x32, 0xA4, 0xD1, 0x94, 0x90, 0xA4, 0xF1, 
+0xB5, 0x73, 0xAC, 0xF0, 0xAD, 0x10, 0xCD, 0xF4, 
+0xC6, 0x14, 0xA4, 0xD0, 0x6B, 0x6B, 0xA5, 0x11, 
+0xC5, 0xD4, 0x7B, 0xCD, 0x41, 0xE6, 0x39, 0xC6, 
+0x31, 0x85, 0x39, 0xC6, 0x4A, 0x28, 0x4A, 0x69, 
+0x4A, 0x69, 0x5A, 0xCA, 0x63, 0x2D, 0x73, 0x8F, 
+0x84, 0x31, 0x94, 0x93, 0x9C, 0xD3, 0xB5, 0x76, 
+0xA5, 0x14, 0xAD, 0x13, 0xA4, 0xF1, 0xC5, 0xF5, 
+0xB5, 0x73, 0xAD, 0x11, 0xB5, 0x73, 0xCE, 0x36, 
+0xC5, 0xF5, 0xC5, 0xF5, 0xC5, 0xD4, 0xC5, 0xF5, 
+0xCD, 0xF5, 0xC5, 0xB4, 0xBD, 0x93, 0xBD, 0x93, 
+0xBD, 0xB4, 0xB5, 0x32, 0xB5, 0x32, 0xA4, 0xD0, 
+0xB5, 0x32, 0xBD, 0x94, 0xCE, 0x15, 0xBD, 0xB3, 
+0xCE, 0x15, 0xA4, 0xB0, 0xC5, 0x93, 0xDE, 0x76, 
+0xCE, 0x14, 0xBD, 0x72, 0xB5, 0x31, 0xA4, 0xD0, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF1, 0xB5, 0x32, 
+0xBD, 0x72, 0xB5, 0x52, 0xB5, 0x31, 0xB5, 0x32, 
+0xBD, 0x72, 0xB5, 0x52, 0xAC, 0xD0, 0xB5, 0x31, 
+0xBD, 0x72, 0xAD, 0x11, 0xA4, 0xB0, 0xA4, 0xD1, 
+0xA4, 0xF1, 0xA4, 0xF1, 0x9C, 0x90, 0xA4, 0xD0, 
+0xAD, 0x12, 0xA4, 0xF1, 0xA4, 0xD1, 0xAD, 0x11, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xD1, 0xA4, 0xF1, 
+0xA4, 0xF2, 0x9C, 0xB1, 0x9C, 0xB0, 0x94, 0x4F, 
+0x94, 0x4E, 0x94, 0x4E, 0x8C, 0x0D, 0x94, 0x4E, 
+0xA4, 0xB0, 0xA4, 0xB0, 0xB5, 0x11, 0xAC, 0xD0, 
+0xB5, 0x11, 0xAC, 0xD0, 0xAC, 0xF0, 0xB5, 0x32, 
+0xBD, 0x52, 0xA4, 0xD0, 0xA4, 0x8F, 0xA4, 0xD0, 
+0xA4, 0xAF, 0xA4, 0xD0, 0xAD, 0x11, 0xAC, 0xF0, 
+0xB5, 0x31, 0xB5, 0x52, 0xBD, 0x72, 0xC5, 0x93, 
+0xCD, 0xF4, 0xC5, 0xB3, 0xBD, 0x93, 0xBD, 0x72, 
+0xC5, 0x93, 0xAC, 0xF1, 0xC5, 0xB4, 0xC5, 0xF5, 
+0xC5, 0xD5, 0x73, 0x6C, 0x39, 0xC6, 0x29, 0x44, 
+0x29, 0x45, 0x29, 0x65, 0x29, 0x44, 0x29, 0x65, 
+0x31, 0xA6, 0x29, 0x45, 0x42, 0x28, 0x62, 0xEB, 
+0x5A, 0xAA, 0x4A, 0x49, 0x4A, 0x08, 0x7B, 0x8E, 
+0x83, 0xAE, 0xB5, 0x33, 0x7B, 0x8E, 0x5A, 0x8A, 
+0x94, 0x50, 0xBD, 0x53, 0xF7, 0x18, 0xEE, 0xD7, 
+0xE6, 0xB6, 0xDE, 0x75, 0xD6, 0x35, 0xDE, 0x56, 
+0xDE, 0x97, 0xE6, 0xD8, 0xE6, 0xD8, 0xDE, 0xB7, 
+0xE6, 0xF8, 0xE6, 0xF8, 0xE6, 0xD8, 0xE6, 0xF8, 
+0xE6, 0xD8, 0xE6, 0xD8, 0xDE, 0xD7, 0xDE, 0xD7, 
+0xE6, 0xD8, 0xDE, 0x97, 0xD6, 0x56, 0xE6, 0xF8, 
+0xDE, 0xB8, 0xA4, 0xF1, 0xE6, 0x96, 0xEE, 0xD6, 
+0xE6, 0x74, 0xDE, 0x33, 0xD6, 0x13, 0xD5, 0xF3, 
+0xD6, 0x34, 0xD6, 0x54, 0xD6, 0x34, 0xD6, 0x13, 
+0xD6, 0x13, 0xDE, 0x34, 0xE6, 0x74, 0xE6, 0x75, 
+0xDE, 0x53, 0xE6, 0x53, 0xE6, 0x74, 0xE6, 0x53, 
+0xDE, 0x53, 0xDE, 0x33, 0xDE, 0x34, 0xDE, 0x54, 
+0x5B, 0x88, 0x5B, 0xE9, 0x53, 0x87, 0x4B, 0x46, 
+0x6C, 0x29, 0x74, 0x6A, 0x64, 0x08, 0x53, 0x86, 
+0x53, 0xC6, 0x6C, 0x68, 0x5C, 0x07, 0x3A, 0xE3, 
+0x53, 0xE6, 0x74, 0xA8, 0xA5, 0xEB, 0x7C, 0xA6, 
+0x63, 0xE3, 0x74, 0x46, 0x7C, 0x87, 0x8C, 0xEA, 
+0xAD, 0x4E, 0xC5, 0xB1, 0xCD, 0xD2, 0xC5, 0x91, 
+0xD6, 0x13, 0xCD, 0xD2, 0xB5, 0x30, 0xB5, 0x30, 
+0xC5, 0x92, 0xC5, 0x71, 0xD5, 0xF3, 0xD5, 0xF3, 
+0xD5, 0xD3, 0xD6, 0x13, 0xCD, 0xB2, 0xD6, 0x14, 
+0xBD, 0xB3, 0x62, 0xEA, 0x4A, 0x27, 0x31, 0xA6, 
+0x42, 0x07, 0x39, 0xE6, 0x39, 0xA6, 0x4A, 0x28, 
+0x5A, 0xAA, 0x4A, 0x48, 0x39, 0xC7, 0x42, 0x08, 
+0x42, 0x08, 0x73, 0x8E, 0xB5, 0x96, 0x7B, 0xAE, 
+0xAD, 0x13, 0x94, 0x70, 0x8C, 0x0E, 0x8B, 0xEC, 
+0x94, 0x0D, 0x8B, 0xEC, 0x94, 0x2C, 0x9C, 0x8E, 
+0x9C, 0x6D, 0x94, 0x2C, 0x8B, 0xEB, 0x8B, 0xEB, 
+0x9C, 0x6D, 0xAC, 0xEE, 0xBD, 0x2F, 0xBD, 0x2F, 
+0xBD, 0x30, 0xA4, 0xAE, 0x8B, 0xEC, 0x7B, 0x6A, 
+0x6B, 0x09, 0x62, 0xE9, 0x63, 0x09, 0x7B, 0xAC, 
+0x7B, 0xAC, 0x6B, 0x4B, 0xA4, 0xD1, 0xBD, 0xD4, 
+0xBD, 0xB3, 0xBD, 0x92, 0xB5, 0x72, 0xBD, 0xB3, 
+0xB5, 0x92, 0xA4, 0xF0, 0xAD, 0x10, 0x9C, 0x8E, 
+0x9C, 0x8E, 0x9C, 0x8E, 0x94, 0x6D, 0xB5, 0x51, 
+0xAC, 0xEF, 0xDE, 0x54, 0xDE, 0x34, 0xDE, 0x34, 
+0xAC, 0xAE, 0x9C, 0x2D, 0xAC, 0xCF, 0xB5, 0x31, 
+0xA4, 0xF1, 0x8C, 0x30, 0x31, 0x66, 0x62, 0xEB, 
+0x94, 0x71, 0xAD, 0x34, 0x6B, 0x4C, 0x42, 0x28, 
+0x52, 0x8A, 0x73, 0x8E, 0x7B, 0xCF, 0x9C, 0x92, 
+0x83, 0xCF, 0x73, 0x6D, 0xB5, 0x96, 0xBD, 0xD6, 
+0xEF, 0x1B, 0xDE, 0x9A, 0xAD, 0x35, 0xAD, 0x55, 
+0xB5, 0x95, 0xBD, 0xD6, 0x94, 0x90, 0x94, 0x70, 
+0xAD, 0x53, 0xA4, 0xF2, 0x9C, 0xD1, 0x94, 0x4F, 
+0x8C, 0x2F, 0xCE, 0x38, 0xE6, 0xFB, 0xBD, 0xB5, 
+0xAD, 0x31, 0x9C, 0x8F, 0xAC, 0xF0, 0xCE, 0x14, 
+0xCE, 0x35, 0xBD, 0xD4, 0xA4, 0xF1, 0x8C, 0x2E, 
+0xAD, 0x31, 0x94, 0x70, 0x4A, 0x28, 0x31, 0xA5, 
+0x39, 0xC6, 0x42, 0x07, 0x42, 0x28, 0x4A, 0x49, 
+0x42, 0x28, 0x52, 0xAA, 0x63, 0x0C, 0x6B, 0x4D, 
+0x6B, 0x6E, 0x73, 0xAF, 0x84, 0x11, 0xA5, 0x35, 
+0xAD, 0x75, 0xDE, 0x9A, 0xB5, 0x54, 0xCE, 0x16, 
+0xBD, 0x93, 0xAC, 0xF1, 0x94, 0x6F, 0xCE, 0x36, 
+0xD6, 0x76, 0xD6, 0x56, 0xCE, 0x15, 0xC5, 0xF4, 
+0xBD, 0x73, 0xAC, 0xF1, 0xA4, 0xB0, 0xAD, 0x32, 
+0xB5, 0x73, 0xBD, 0x93, 0xD6, 0x36, 0xCD, 0xF4, 
+0xBD, 0x73, 0xCD, 0xF4, 0xC5, 0x93, 0xB5, 0x72, 
+0xC5, 0xB3, 0xAD, 0x11, 0xC5, 0xB3, 0xDE, 0x55, 
+0xCD, 0xD4, 0xBD, 0x72, 0xC5, 0xD4, 0xC5, 0xB3, 
+0xC5, 0x93, 0xC5, 0x93, 0xC5, 0xB3, 0xCD, 0xD4, 
+0xCD, 0xD4, 0xD6, 0x15, 0xAD, 0x11, 0xAD, 0x11, 
+0xBD, 0x93, 0xB5, 0x72, 0xB5, 0x73, 0xB5, 0x73, 
+0x9C, 0x8F, 0xA4, 0xF1, 0xAD, 0x32, 0xBD, 0x94, 
+0xAD, 0x32, 0xA4, 0xD1, 0xAD, 0x11, 0x9C, 0xB0, 
+0x73, 0x6B, 0x7B, 0xAC, 0x83, 0xCD, 0x94, 0x6F, 
+0x9C, 0x6F, 0x9C, 0x90, 0xA4, 0xF1, 0xB5, 0x53, 
+0xB5, 0x53, 0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x52, 
+0xB5, 0x31, 0xAD, 0x31, 0xAD, 0x11, 0xAC, 0xD0, 
+0xA4, 0xD0, 0xA4, 0x8F, 0x9C, 0x4E, 0x9C, 0x4E, 
+0x9C, 0x4E, 0x9C, 0x4E, 0xA4, 0xB0, 0xAC, 0xD0, 
+0xA4, 0xAF, 0xAC, 0xD0, 0xA4, 0xD0, 0xAC, 0xD0, 
+0xAC, 0xF0, 0xAC, 0xD0, 0xAC, 0xD0, 0xA4, 0xAF, 
+0x9C, 0x8F, 0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0x8F, 
+0xA4, 0x8F, 0x9C, 0x6E, 0xAC, 0xD0, 0xA4, 0x8F, 
+0x94, 0x2E, 0x94, 0x2E, 0x9C, 0x8F, 0xAD, 0x11, 
+0xAD, 0x32, 0xA4, 0xD0, 0x73, 0x6B, 0x42, 0x07, 
+0x31, 0x85, 0x29, 0x65, 0x29, 0x44, 0x31, 0x85, 
+0x42, 0x07, 0x42, 0x07, 0x4A, 0x28, 0x39, 0xC6, 
+0x62, 0xEB, 0x6B, 0x0C, 0x49, 0xE7, 0x5A, 0x8A, 
+0x83, 0xAE, 0x83, 0x8D, 0x73, 0x6D, 0x73, 0x2C, 
+0x73, 0x2C, 0x6A, 0xEA, 0xBD, 0x73, 0xCD, 0xF4, 
+0xC5, 0xB3, 0xC5, 0x93, 0xAC, 0xF1, 0xC5, 0xB4, 
+0xBD, 0x93, 0xCE, 0x15, 0xD6, 0x56, 0xD6, 0x35, 
+0xE6, 0xB7, 0xDE, 0x97, 0xDE, 0xB7, 0xE6, 0xB8, 
+0xE6, 0xB7, 0xE6, 0xB7, 0xE6, 0xD8, 0xE6, 0xB7, 
+0xE6, 0xF8, 0xDE, 0x97, 0xDE, 0x77, 0xE6, 0xF8, 
+0xDE, 0xB7, 0xA4, 0xD0, 0xF7, 0x18, 0xEE, 0xD6, 
+0xE6, 0x75, 0xDE, 0x33, 0xD5, 0xF3, 0xD6, 0x14, 
+0xDE, 0x55, 0xDE, 0x54, 0xDE, 0x55, 0xE6, 0x75, 
+0xDE, 0x54, 0xDE, 0x54, 0xDE, 0x54, 0xDE, 0x54, 
+0xDE, 0x33, 0xDE, 0x33, 0xDE, 0x13, 0xE6, 0x54, 
+0xDE, 0x33, 0xDE, 0x33, 0xE6, 0x74, 0xE6, 0x95, 
+0x21, 0xE3, 0x4B, 0x27, 0x32, 0xC4, 0x3A, 0xC4, 
+0x53, 0xA6, 0x43, 0x24, 0x43, 0x44, 0x3B, 0x04, 
+0x64, 0x08, 0x3B, 0x03, 0x53, 0xC6, 0x43, 0x45, 
+0x5B, 0xC7, 0x9D, 0xCE, 0x63, 0xC6, 0x6C, 0x08, 
+0x8C, 0xEC, 0xB5, 0xF0, 0xCE, 0x51, 0xC5, 0xF0, 
+0xBD, 0x8F, 0xBD, 0x70, 0xBD, 0x30, 0xB5, 0x0F, 
+0xCD, 0xB2, 0xCD, 0xB2, 0xBD, 0x71, 0xC5, 0x92, 
+0xCD, 0xB2, 0xCD, 0xD3, 0xD6, 0x14, 0xD5, 0xF3, 
+0xD5, 0xF3, 0xD5, 0xD3, 0xD6, 0x13, 0xD6, 0x14, 
+0x6A, 0xEA, 0x7B, 0xCD, 0x73, 0x6B, 0x4A, 0x27, 
+0x39, 0x85, 0x31, 0xA6, 0x31, 0xA6, 0x41, 0xE7, 
+0x52, 0x89, 0x62, 0xEB, 0x52, 0x89, 0x63, 0x0B, 
+0x73, 0x4D, 0x7B, 0x8E, 0x8C, 0x51, 0x73, 0x6E, 
+0xC6, 0x38, 0xEF, 0x3C, 0xB5, 0x75, 0x8C, 0x0E, 
+0x9C, 0x8F, 0xA4, 0xAF, 0x8B, 0xEC, 0x83, 0xCB, 
+0x8C, 0x0C, 0xA4, 0xAE, 0xB4, 0xEF, 0xB5, 0x10, 
+0xBD, 0x51, 0xC5, 0x91, 0xC5, 0x71, 0xAC, 0xCE, 
+0xB4, 0xEF, 0xBD, 0x50, 0xBD, 0x31, 0xAC, 0xAF, 
+0x9C, 0x6E, 0xA4, 0xAE, 0xAC, 0xCF, 0xA4, 0xAE, 
+0x9C, 0x4D, 0x94, 0x2D, 0x94, 0x2D, 0x94, 0x2D, 
+0x9C, 0x4D, 0xA4, 0xAE, 0xA4, 0x8E, 0xA4, 0x8E, 
+0x9C, 0x8E, 0x9C, 0x8E, 0xA4, 0xAE, 0xA4, 0xAE, 
+0xAC, 0xCF, 0xA4, 0xAE, 0x94, 0x0C, 0x9C, 0x6D, 
+0xA4, 0x8D, 0xCD, 0xF2, 0xCD, 0xF3, 0xBD, 0x51, 
+0x8B, 0xCB, 0x8B, 0xEC, 0xAC, 0xCE, 0xAC, 0xEF, 
+0xAD, 0x10, 0x6B, 0x0A, 0x39, 0xA6, 0x31, 0xA6, 
+0x6B, 0x2C, 0x8C, 0x30, 0x73, 0x6C, 0x5A, 0xCB, 
+0x6B, 0x6D, 0x6B, 0x2C, 0x7B, 0xAE, 0x8C, 0x30, 
+0x94, 0x30, 0x94, 0x30, 0x73, 0x4D, 0x94, 0x71, 
+0xE6, 0xFB, 0x94, 0x92, 0x6B, 0x2D, 0xA5, 0x14, 
+0x5A, 0xAB, 0x94, 0x91, 0x84, 0x0F, 0x8C, 0x50, 
+0x94, 0x91, 0x9C, 0xB2, 0x94, 0x51, 0x9C, 0x91, 
+0xC6, 0x18, 0xEF, 0x5D, 0xCE, 0x59, 0x9C, 0xD2, 
+0xA4, 0xF1, 0xA4, 0xCF, 0xB5, 0x10, 0xCE, 0x14, 
+0xC5, 0xD3, 0x9C, 0xD0, 0xB5, 0x52, 0xAD, 0x72, 
+0xB5, 0x73, 0xB5, 0x74, 0x6B, 0x2B, 0x39, 0xC6, 
+0x42, 0x07, 0x5A, 0xAA, 0x52, 0xAA, 0x52, 0x8A, 
+0x63, 0x0B, 0x6B, 0x6D, 0x73, 0x8D, 0x5A, 0xCB, 
+0x52, 0x8A, 0x6B, 0x4D, 0x7B, 0xF0, 0x8C, 0x92, 
+0xA5, 0x35, 0xC6, 0x38, 0xBD, 0xF6, 0xCE, 0x16, 
+0xCE, 0x15, 0xAD, 0x32, 0xA4, 0xD1, 0xD6, 0x56, 
+0xDE, 0x97, 0xDE, 0x76, 0xD6, 0x76, 0xCE, 0x35, 
+0xBD, 0x93, 0xAD, 0x11, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xA4, 0xF1, 0xB5, 0x73, 0xCE, 0x15, 0xCD, 0xF4, 
+0xB5, 0x52, 0xAD, 0x31, 0xAC, 0xF0, 0xBD, 0x93, 
+0xBD, 0x93, 0xB5, 0x11, 0xBD, 0x93, 0xCD, 0xD3, 
+0xC5, 0x92, 0xB5, 0x31, 0xC5, 0xB3, 0xC5, 0xB3, 
+0xBD, 0x52, 0xBD, 0x72, 0xB5, 0x51, 0xBD, 0x72, 
+0xC5, 0xB3, 0xCD, 0xF4, 0xB5, 0x32, 0x9C, 0x6F, 
+0xA4, 0xF1, 0xB5, 0x52, 0xC5, 0xD4, 0xD6, 0x57, 
+0xBD, 0xD5, 0xBD, 0xD4, 0xBD, 0xB4, 0xBD, 0x94, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xB5, 0x52, 0xA4, 0xD1, 
+0x7B, 0xAC, 0x7B, 0xCD, 0x7B, 0xCC, 0x8C, 0x0E, 
+0x9C, 0x6F, 0x8C, 0x2E, 0x83, 0xED, 0x83, 0xAC, 
+0x83, 0x8C, 0x83, 0xAC, 0x7B, 0x8B, 0x83, 0xAC, 
+0x8B, 0xED, 0x9C, 0x6E, 0xA4, 0xB0, 0x9C, 0x6E, 
+0xA4, 0x8F, 0xA4, 0x8F, 0x94, 0x0D, 0x94, 0x2E, 
+0x83, 0xAB, 0x83, 0xAB, 0xA4, 0xB0, 0x9C, 0x6F, 
+0x8B, 0xED, 0x83, 0xAC, 0x8B, 0xED, 0x9C, 0x4E, 
+0x94, 0x2E, 0x9C, 0x4E, 0xA4, 0x8F, 0xA4, 0x8F, 
+0x9C, 0x4E, 0xAC, 0xD0, 0xAD, 0x11, 0xAC, 0xF0, 
+0xB5, 0x32, 0xAC, 0xF0, 0xAC, 0xF0, 0xAD, 0x11, 
+0xB5, 0x52, 0xBD, 0x73, 0xBD, 0x94, 0xBD, 0xB4, 
+0xBD, 0x93, 0xBD, 0x93, 0xBD, 0x94, 0xA4, 0xF2, 
+0x5A, 0xCA, 0x31, 0xA6, 0x29, 0x65, 0x31, 0x85, 
+0x39, 0xC6, 0x41, 0xE7, 0x4A, 0x68, 0x42, 0x07, 
+0x31, 0xA6, 0x52, 0x69, 0x5A, 0xAA, 0x6B, 0x0C, 
+0x5A, 0xAA, 0x4A, 0x28, 0x52, 0x49, 0x62, 0x8A, 
+0x8B, 0xCE, 0x62, 0xAA, 0x62, 0x89, 0x94, 0x4F, 
+0xA4, 0xB0, 0xAD, 0x11, 0x94, 0x4F, 0x9C, 0x90, 
+0x94, 0x6F, 0xA4, 0xD0, 0xB5, 0x52, 0xB5, 0x32, 
+0xBD, 0x73, 0xA4, 0xD0, 0x9C, 0xB0, 0xC5, 0xD5, 
+0xBD, 0x52, 0xBD, 0x73, 0xBD, 0x93, 0xBD, 0x93, 
+0xCE, 0x15, 0xDE, 0x97, 0xE6, 0xD8, 0xE6, 0xD8, 
+0xDE, 0x77, 0xAC, 0xF1, 0xF7, 0x18, 0xEE, 0xD6, 
+0xDE, 0x54, 0xDE, 0x54, 0xE6, 0x55, 0xD6, 0x13, 
+0xE6, 0x96, 0xDE, 0x34, 0xE6, 0x96, 0xEE, 0xB6, 
+0xDE, 0x75, 0xEE, 0xD6, 0xE6, 0x95, 0xE6, 0x95, 
+0xE6, 0x95, 0xE6, 0x74, 0xDE, 0x54, 0xEE, 0xB5, 
+0xE6, 0x75, 0xDE, 0x54, 0xDE, 0x34, 0xE6, 0x95, 
+0x21, 0xC4, 0x43, 0x27, 0x6C, 0x4B, 0x43, 0x05, 
+0x4B, 0x05, 0x53, 0x66, 0x5B, 0xC8, 0x43, 0x05, 
+0x64, 0x09, 0x22, 0x21, 0x3B, 0x03, 0x4B, 0x45, 
+0x7C, 0xAB, 0x7C, 0x6A, 0xA5, 0xD1, 0xC6, 0xD5, 
+0xCE, 0xD6, 0xE7, 0x17, 0xD6, 0x54, 0xC5, 0x70, 
+0xB5, 0x0F, 0xC5, 0x91, 0xB5, 0x30, 0xB4, 0xEF, 
+0xBD, 0x71, 0xC5, 0x92, 0xC5, 0x92, 0xCD, 0xD3, 
+0xCD, 0xF3, 0xD6, 0x14, 0xCD, 0xD3, 0xCD, 0xD2, 
+0xD5, 0xF3, 0xDE, 0x34, 0xD6, 0x14, 0xDE, 0x35, 
+0xDE, 0x56, 0xDE, 0x96, 0xAC, 0xEF, 0xAC, 0xCF, 
+0x94, 0x2E, 0x73, 0x6C, 0x39, 0xA6, 0x29, 0x44, 
+0x39, 0xC6, 0x4A, 0x68, 0x52, 0x89, 0x52, 0x69, 
+0x73, 0x8D, 0x83, 0xEF, 0x94, 0x71, 0x73, 0x6D, 
+0x9C, 0xD3, 0xEF, 0x5D, 0xF7, 0x9E, 0xD6, 0x79, 
+0x84, 0x0E, 0x8C, 0x2E, 0x8B, 0xEE, 0x8C, 0x2E, 
+0x8C, 0x2E, 0x8C, 0x0D, 0xAC, 0xCF, 0xAC, 0xAF, 
+0xC5, 0x72, 0xCD, 0xF3, 0xC5, 0xB2, 0xAC, 0xCF, 
+0xA4, 0xAE, 0xA4, 0xAF, 0xAC, 0xF0, 0xAC, 0xAF, 
+0xA4, 0x8E, 0xAC, 0xAF, 0xB5, 0x10, 0xCD, 0xD3, 
+0xBD, 0x51, 0xB5, 0x10, 0xBD, 0x30, 0xB5, 0x30, 
+0xB5, 0x30, 0xB5, 0x30, 0xB5, 0x10, 0xBD, 0x51, 
+0xB5, 0x30, 0xB5, 0x10, 0xA4, 0x6D, 0xAC, 0xAE, 
+0xC5, 0x71, 0xBD, 0x50, 0xA4, 0x8E, 0xA4, 0x6D, 
+0xAC, 0xCE, 0xB4, 0xCE, 0xA4, 0x8E, 0xA4, 0x8E, 
+0x8B, 0xCB, 0x94, 0x2D, 0xAC, 0xEF, 0xB5, 0x0F, 
+0xAC, 0xCF, 0xB5, 0x10, 0x6B, 0x0A, 0x41, 0xE7, 
+0x52, 0x89, 0x4A, 0x49, 0x42, 0x28, 0x31, 0x86, 
+0x52, 0x8A, 0x62, 0xEB, 0x73, 0x4D, 0x83, 0xEF, 
+0xCE, 0x17, 0xCD, 0xD6, 0xA4, 0xB2, 0x73, 0x4D, 
+0xC5, 0xF7, 0xAD, 0x75, 0xAD, 0x55, 0xB5, 0x75, 
+0x94, 0x72, 0xAD, 0x75, 0x94, 0x71, 0xAD, 0x55, 
+0xAD, 0x55, 0xC6, 0x18, 0xB5, 0x76, 0x94, 0x92, 
+0xBD, 0xB6, 0xCE, 0x59, 0xAD, 0x55, 0x8C, 0x30, 
+0xBD, 0xB4, 0xB5, 0x31, 0xAC, 0xF0, 0xBD, 0xB3, 
+0xC5, 0xF4, 0xB5, 0x52, 0xB5, 0x72, 0xBD, 0xD4, 
+0xBD, 0xD4, 0xAD, 0x52, 0x9C, 0xD1, 0x4A, 0x48, 
+0x5A, 0xCA, 0x73, 0x6D, 0x73, 0xAE, 0x7B, 0xAE, 
+0x83, 0xEF, 0x5A, 0xCB, 0x4A, 0x49, 0x52, 0x8A, 
+0x52, 0x8A, 0x6B, 0x4D, 0x7B, 0xAF, 0x84, 0x31, 
+0xA5, 0x14, 0xAD, 0x76, 0xCE, 0x58, 0xCE, 0x37, 
+0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x32, 0xD6, 0x76, 
+0xDE, 0x96, 0xD6, 0x76, 0xD6, 0x76, 0xD6, 0x56, 
+0xBD, 0x73, 0xAD, 0x11, 0xAD, 0x11, 0x9C, 0xD0, 
+0x94, 0x8F, 0xC5, 0xB4, 0xCE, 0x15, 0xC5, 0xB3, 
+0xAD, 0x31, 0x9C, 0x8F, 0xA4, 0xF0, 0xBD, 0xB3, 
+0xBD, 0x93, 0xAD, 0x11, 0xC5, 0xB3, 0xC5, 0xB3, 
+0xBD, 0x51, 0xB5, 0x11, 0xBD, 0x73, 0xBD, 0x31, 
+0xB4, 0xF0, 0xBD, 0x52, 0xB5, 0x11, 0xBD, 0x52, 
+0xCD, 0xD3, 0xCD, 0xF4, 0xB5, 0x32, 0xAD, 0x11, 
+0xBD, 0x94, 0xB5, 0x73, 0xBD, 0x93, 0xBD, 0xB4, 
+0xAD, 0x32, 0xB5, 0x73, 0xBD, 0x93, 0xBD, 0x94, 
+0xB5, 0x52, 0xC5, 0xF5, 0xB5, 0x53, 0xAD, 0x32, 
+0x94, 0x6F, 0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0xB0, 
+0xB5, 0x73, 0xA4, 0xF1, 0x94, 0x6F, 0x83, 0xCC, 
+0x7B, 0x8B, 0x7B, 0x8C, 0x7B, 0xAC, 0x83, 0xCD, 
+0x83, 0xCD, 0x83, 0xAC, 0xA4, 0xAF, 0xB5, 0x31, 
+0xBD, 0x52, 0xBD, 0x72, 0xAC, 0xF1, 0xAC, 0xF1, 
+0xA4, 0x8F, 0x9C, 0x4E, 0xB5, 0x32, 0x94, 0x2E, 
+0x7B, 0x8C, 0x7B, 0xAC, 0x83, 0xCD, 0x9C, 0x6E, 
+0x8C, 0x0D, 0x8B, 0xCC, 0x8B, 0xED, 0x94, 0x0D, 
+0x94, 0x0D, 0xAC, 0xD0, 0xB5, 0x31, 0xB5, 0x31, 
+0xAC, 0xF0, 0x8B, 0xCD, 0x83, 0xAC, 0x9C, 0x6F, 
+0xAD, 0x11, 0xB5, 0x52, 0xA4, 0xD1, 0xC5, 0xB4, 
+0xB5, 0x52, 0xAD, 0x32, 0xAD, 0x12, 0xAD, 0x12, 
+0x9C, 0x90, 0x7B, 0xCD, 0x39, 0xC6, 0x31, 0x85, 
+0x29, 0x65, 0x39, 0xA6, 0x42, 0x28, 0x42, 0x28, 
+0x4A, 0x28, 0x4A, 0x28, 0x4A, 0x49, 0x7B, 0xAE, 
+0x83, 0xCE, 0x73, 0x2C, 0x5A, 0x69, 0x7B, 0x6D, 
+0xB5, 0x13, 0x94, 0x2F, 0x62, 0xCA, 0x62, 0xCA, 
+0x8C, 0x0E, 0xB5, 0x52, 0xBD, 0xB3, 0xAD, 0x12, 
+0xBD, 0x94, 0xBD, 0x73, 0xB5, 0x32, 0xB5, 0x32, 
+0xBD, 0x73, 0xB5, 0x73, 0xB5, 0x53, 0xB5, 0x53, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xA4, 0xD1, 0xA4, 0xD1, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF2, 0xAD, 0x12, 
+0xAC, 0xF2, 0xA4, 0xD1, 0xB5, 0x32, 0xB5, 0x11, 
+0xAC, 0xD0, 0xC5, 0x72, 0xCD, 0xD3, 0xCD, 0xD3, 
+0xCD, 0xD3, 0xC5, 0x92, 0xCD, 0xD3, 0xCD, 0xF4, 
+0xD6, 0x14, 0xD5, 0xF4, 0xCD, 0xB3, 0xCD, 0xB3, 
+0xD6, 0x14, 0xDE, 0x34, 0xDE, 0x54, 0xE6, 0x75, 
+0xE6, 0x95, 0xEE, 0xD6, 0xE6, 0x95, 0xD5, 0xF3, 
+0x5B, 0x0B, 0x2A, 0x04, 0x32, 0x85, 0x42, 0xE5, 
+0x32, 0x63, 0x3A, 0x64, 0x3A, 0x65, 0x3A, 0x44, 
+0x53, 0x28, 0x53, 0x67, 0x4B, 0x45, 0x43, 0x04, 
+0x74, 0x2A, 0xA5, 0x8F, 0xA5, 0x6F, 0xA5, 0x70, 
+0xBE, 0x34, 0xE7, 0x18, 0xDE, 0xD7, 0xD6, 0x34, 
+0xB5, 0x0F, 0xCD, 0xD3, 0xBD, 0x50, 0xBD, 0x51, 
+0xBD, 0x72, 0xBD, 0x92, 0xBD, 0x92, 0xBD, 0x72, 
+0xC5, 0x92, 0xCD, 0xB2, 0xCD, 0xB2, 0xCD, 0xB2, 
+0xCD, 0xD2, 0xDE, 0x34, 0xC5, 0x71, 0xCD, 0xB2, 
+0xCD, 0xF4, 0xDE, 0x35, 0xB5, 0x0F, 0xAC, 0xEE, 
+0xAC, 0xF0, 0xBD, 0xD4, 0x9C, 0xD1, 0x52, 0x89, 
+0x29, 0x64, 0x31, 0x85, 0x39, 0xC6, 0x4A, 0x69, 
+0x39, 0xA6, 0x42, 0x07, 0x52, 0x89, 0x4A, 0x28, 
+0x5A, 0xCB, 0xCE, 0x38, 0xE7, 0x1C, 0x8C, 0x30, 
+0x29, 0x25, 0x29, 0x24, 0x39, 0xE7, 0x94, 0x91, 
+0x9C, 0xD1, 0x8C, 0x2E, 0xAC, 0xCF, 0xC5, 0x92, 
+0xD6, 0x35, 0xBD, 0x51, 0xB5, 0x31, 0xBD, 0x72, 
+0xBD, 0x52, 0xB5, 0x31, 0xBD, 0x52, 0xBD, 0x72, 
+0xBD, 0x72, 0xC5, 0x93, 0xC5, 0xB3, 0xCD, 0xD3, 
+0xC5, 0x92, 0xBD, 0x71, 0xD5, 0xF3, 0xBD, 0x51, 
+0xB5, 0x51, 0xBD, 0x51, 0xB5, 0x31, 0xBD, 0x52, 
+0xC5, 0x92, 0xDE, 0x35, 0xAC, 0xAF, 0xB4, 0xEF, 
+0xD5, 0xF3, 0xDD, 0xF3, 0xCD, 0xB2, 0xC5, 0x51, 
+0xC5, 0x51, 0xCD, 0x92, 0xCD, 0xB2, 0xBD, 0x31, 
+0xBD, 0x31, 0xAC, 0xCF, 0xA4, 0x6D, 0xA4, 0x8E, 
+0xAC, 0xCF, 0xC5, 0x71, 0xB4, 0xF0, 0x73, 0x4B, 
+0x83, 0xCE, 0x73, 0x6D, 0x42, 0x08, 0x39, 0xA7, 
+0x62, 0xEC, 0x73, 0x8E, 0x94, 0x92, 0xA4, 0xF3, 
+0xC5, 0xF7, 0xDE, 0x59, 0xA4, 0x92, 0xB5, 0x34, 
+0x6B, 0x0B, 0x52, 0x69, 0x4A, 0x69, 0x6B, 0x4D, 
+0x73, 0x8E, 0xBD, 0xB6, 0xB5, 0x96, 0xAD, 0x34, 
+0xC5, 0xF7, 0xB5, 0x75, 0xA5, 0x14, 0x62, 0xCB, 
+0x7B, 0xAF, 0xBD, 0xB6, 0x94, 0x92, 0x8C, 0x0E, 
+0x9C, 0x8E, 0xA4, 0xAE, 0xAD, 0x10, 0xAC, 0xF0, 
+0xAD, 0x10, 0xA5, 0x10, 0xAC, 0xF0, 0xAD, 0x11, 
+0xAD, 0x31, 0xA4, 0xF1, 0xB5, 0x73, 0x83, 0xEE, 
+0x63, 0x0B, 0x5A, 0xCA, 0x5A, 0xCA, 0x52, 0x89, 
+0x4A, 0x28, 0x4A, 0x69, 0x4A, 0x69, 0x4A, 0x69, 
+0x41, 0xE7, 0x5A, 0xCB, 0x63, 0x0C, 0x73, 0xAE, 
+0x8C, 0x31, 0x9C, 0xF4, 0xBD, 0xF8, 0xD6, 0xBA, 
+0xB5, 0x74, 0xAD, 0x32, 0x9C, 0x8F, 0xC5, 0xF4, 
+0xCE, 0x55, 0xD6, 0x55, 0xD6, 0x56, 0xCE, 0x15, 
+0xB5, 0x73, 0xB5, 0x72, 0xB5, 0x52, 0xA4, 0xD1, 
+0x9C, 0xD0, 0xBD, 0xD4, 0xD6, 0x35, 0xBD, 0x93, 
+0xA4, 0xB0, 0x94, 0x6F, 0x9C, 0xB0, 0xAD, 0x31, 
+0xBD, 0xB3, 0xB5, 0x32, 0xC5, 0xB4, 0xCD, 0xD3, 
+0xBD, 0x51, 0xB5, 0x32, 0xC5, 0x73, 0xC5, 0x52, 
+0xC5, 0x52, 0xBD, 0x52, 0xB5, 0x11, 0xBD, 0x72, 
+0xC5, 0xD3, 0xCD, 0xF4, 0xB5, 0x11, 0xB5, 0x53, 
+0xC5, 0xF5, 0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xB5, 0x73, 0xAD, 0x52, 0xA5, 0x11, 0xBD, 0xB4, 
+0xBD, 0xD4, 0xCE, 0x36, 0xB5, 0x52, 0xB5, 0x73, 
+0xA4, 0xD0, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x52, 
+0xBD, 0x94, 0xBD, 0x93, 0xA4, 0xD1, 0x8C, 0x2E, 
+0x7B, 0xAC, 0x73, 0x2A, 0x73, 0x2A, 0x8C, 0x2E, 
+0x94, 0x4F, 0x94, 0x2E, 0x9C, 0x6F, 0xAC, 0xF0, 
+0xC5, 0x92, 0xBD, 0x72, 0xB5, 0x11, 0xB5, 0x10, 
+0x9C, 0x4E, 0x8B, 0xCC, 0xBD, 0x52, 0x94, 0x4E, 
+0x83, 0xED, 0x94, 0x4F, 0x9C, 0x90, 0xB5, 0x52, 
+0xBD, 0x93, 0xB5, 0x52, 0xAD, 0x11, 0xB5, 0x52, 
+0xA4, 0xD0, 0xB5, 0x11, 0xBD, 0x72, 0xC5, 0xB2, 
+0xB5, 0x31, 0xA4, 0xD0, 0x94, 0x2E, 0xA4, 0xD0, 
+0xBD, 0x73, 0xAD, 0x11, 0xBD, 0x93, 0xBD, 0xB3, 
+0xAD, 0x11, 0xB5, 0x73, 0xAD, 0x11, 0xAD, 0x32, 
+0xAD, 0x11, 0xCE, 0x36, 0x9C, 0xB1, 0x52, 0x89, 
+0x39, 0xA6, 0x39, 0xC6, 0x39, 0xA6, 0x42, 0x07, 
+0x4A, 0x48, 0x4A, 0x68, 0x52, 0x89, 0x4A, 0x28, 
+0x73, 0x8D, 0x94, 0x51, 0x73, 0x2C, 0x52, 0x48, 
+0x9C, 0x50, 0x94, 0x2F, 0x83, 0xAE, 0x73, 0x4C, 
+0x8C, 0x0E, 0xAD, 0x10, 0xBD, 0x93, 0xBD, 0x73, 
+0xE6, 0x97, 0xC5, 0xB4, 0xBD, 0x93, 0xC5, 0xB4, 
+0xBD, 0x93, 0xBD, 0x93, 0xC5, 0xD4, 0xB5, 0x52, 
+0xCD, 0xF5, 0xCE, 0x15, 0xCD, 0xF5, 0xCD, 0xD5, 
+0xC5, 0xD5, 0xCD, 0xF5, 0xCD, 0xD5, 0xC5, 0xD5, 
+0xC5, 0xB5, 0xC5, 0xB4, 0xBD, 0x94, 0xB5, 0x53, 
+0xB5, 0x53, 0xB5, 0x52, 0xB5, 0x32, 0xB5, 0x12, 
+0xB5, 0x12, 0xAC, 0xF1, 0xA4, 0xB0, 0xA4, 0xB0, 
+0xA4, 0xB0, 0x9C, 0x70, 0x9C, 0x70, 0x94, 0x4F, 
+0x94, 0x4E, 0x94, 0x4E, 0x9C, 0x4F, 0x9C, 0x8F, 
+0xAC, 0xF0, 0xB5, 0x31, 0xBD, 0x32, 0xAD, 0x11, 
+0x6B, 0xCD, 0x19, 0x42, 0x32, 0x65, 0x6C, 0x0A, 
+0x3A, 0x44, 0x53, 0x08, 0x42, 0x86, 0x6B, 0xCB, 
+0x6B, 0xEB, 0x5B, 0x47, 0x7C, 0x4B, 0x9D, 0x4F, 
+0xB5, 0xF2, 0xC6, 0x54, 0xCE, 0x54, 0x9C, 0xCD, 
+0xC5, 0xF3, 0xDE, 0x75, 0xBD, 0x72, 0xA4, 0x8E, 
+0xBD, 0x91, 0xCD, 0xD3, 0xBD, 0x51, 0xA4, 0xAE, 
+0xBD, 0x72, 0xB5, 0x30, 0xB5, 0x30, 0xB5, 0x51, 
+0xBD, 0x51, 0xCD, 0xD3, 0xD5, 0xF3, 0xBD, 0x51, 
+0xC5, 0x92, 0xD6, 0x14, 0xAC, 0xEF, 0xC5, 0xB2, 
+0xD6, 0x34, 0xDE, 0x34, 0xBD, 0x30, 0xB4, 0xCE, 
+0xA4, 0xCF, 0xBD, 0xB4, 0xB5, 0x53, 0xB5, 0x53, 
+0x7B, 0x8D, 0x39, 0xC6, 0x29, 0x44, 0x39, 0xC6, 
+0x41, 0xE6, 0x39, 0xA6, 0x31, 0x85, 0x5A, 0xEB, 
+0x62, 0xEC, 0x4A, 0x49, 0x5A, 0xEB, 0x83, 0xEF, 
+0x73, 0x8E, 0x4A, 0x48, 0x31, 0xA6, 0x6B, 0x4C, 
+0xAD, 0x53, 0x94, 0x70, 0xA4, 0x8F, 0xB5, 0x31, 
+0xAC, 0xF0, 0xB5, 0x31, 0xBD, 0x72, 0xA4, 0xF0, 
+0xA4, 0xD0, 0xA4, 0xD0, 0xB5, 0x31, 0xB5, 0x31, 
+0xBD, 0x72, 0xBD, 0x73, 0xBD, 0xB3, 0xBD, 0x92, 
+0xC5, 0xB3, 0xBD, 0x51, 0xB5, 0x31, 0xAC, 0xD0, 
+0xAC, 0xF1, 0xAD, 0x11, 0xA4, 0xD0, 0xB5, 0x31, 
+0xBD, 0x72, 0xD5, 0xF4, 0xAC, 0x8E, 0xAC, 0x8E, 
+0xC5, 0x51, 0xCD, 0x92, 0xD5, 0xD3, 0xDE, 0x14, 
+0xDD, 0xF3, 0xD5, 0xF3, 0xCD, 0xB2, 0xBD, 0x51, 
+0xBD, 0x71, 0xD5, 0xD3, 0xCD, 0xB2, 0xCD, 0x91, 
+0xCD, 0x92, 0xCD, 0xD2, 0xC5, 0x92, 0x8C, 0x0D, 
+0x6B, 0x2B, 0x6B, 0x4C, 0x39, 0xC6, 0x31, 0x66, 
+0x4A, 0x49, 0x4A, 0x69, 0x5A, 0xEB, 0x83, 0xEF, 
+0x9C, 0x92, 0x94, 0x51, 0x8C, 0x10, 0xBD, 0x54, 
+0xAC, 0xB2, 0x6A, 0xCB, 0x39, 0xA7, 0x73, 0x8E, 
+0x8C, 0x51, 0xBD, 0xB7, 0xAD, 0x55, 0x7B, 0xCF, 
+0xA4, 0xF3, 0x7B, 0xCF, 0x4A, 0x49, 0x5A, 0xCB, 
+0x7B, 0xAF, 0xCE, 0x18, 0xC5, 0xF7, 0xA4, 0xD1, 
+0x94, 0x2D, 0x9C, 0x4D, 0x9C, 0x6E, 0x8C, 0x0C, 
+0x8C, 0x0D, 0x94, 0x2D, 0xA4, 0xD0, 0x9C, 0x8F, 
+0xA4, 0xAF, 0xAD, 0x11, 0xB5, 0x31, 0x9C, 0xB0, 
+0x4A, 0x07, 0x42, 0x27, 0x42, 0x07, 0x41, 0xE7, 
+0x52, 0x69, 0x52, 0x89, 0x4A, 0x48, 0x4A, 0x49, 
+0x39, 0xC6, 0x42, 0x28, 0x63, 0x0C, 0x6B, 0x6E, 
+0x73, 0xAF, 0x8C, 0x72, 0xAD, 0x76, 0xC6, 0x18, 
+0xBD, 0xB6, 0xAD, 0x12, 0xA5, 0x11, 0xBD, 0xB4, 
+0xC5, 0xF5, 0xC6, 0x15, 0xC6, 0x15, 0xC6, 0x15, 
+0xBD, 0xD4, 0xBD, 0xD4, 0xBD, 0xB4, 0xB5, 0x73, 
+0xAD, 0x32, 0xC5, 0xD5, 0xCE, 0x15, 0xCE, 0x15, 
+0xC5, 0xD4, 0xBD, 0xB4, 0x9C, 0xB0, 0xAD, 0x31, 
+0xBD, 0x92, 0xAD, 0x11, 0xCD, 0xD4, 0xCD, 0xF3, 
+0xC5, 0x71, 0xBD, 0x72, 0xC5, 0x72, 0xBD, 0x31, 
+0xC5, 0x52, 0xC5, 0x93, 0xAC, 0xAF, 0xB5, 0x51, 
+0xC5, 0x93, 0xD6, 0x35, 0xAD, 0x11, 0xB5, 0x52, 
+0xC5, 0xF5, 0xBD, 0xD4, 0xBD, 0xB4, 0xB5, 0x94, 
+0xB5, 0x93, 0xBD, 0x94, 0xB5, 0xB4, 0xBD, 0xD4, 
+0xC5, 0xF5, 0xCE, 0x15, 0xB5, 0x32, 0xBD, 0x73, 
+0xAD, 0x32, 0xB5, 0x32, 0xA4, 0xF1, 0xAD, 0x12, 
+0xB5, 0x53, 0xB5, 0x73, 0x9C, 0xB0, 0x94, 0x70, 
+0x8C, 0x2F, 0x94, 0x70, 0x8C, 0x2E, 0xA4, 0xD1, 
+0x8C, 0x0E, 0x9C, 0x90, 0x94, 0x6E, 0xA4, 0xB0, 
+0xAC, 0xD0, 0xAC, 0xF0, 0x94, 0x4E, 0x83, 0xAC, 
+0x7B, 0x6B, 0x8B, 0xCD, 0xBD, 0x53, 0x94, 0x2E, 
+0x8C, 0x2E, 0x94, 0x6F, 0xA4, 0xF1, 0xB5, 0x72, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xB3, 0xC5, 0xD4, 
+0xB5, 0x32, 0xB5, 0x51, 0xCD, 0xF4, 0xCE, 0x14, 
+0xBD, 0x72, 0xAD, 0x11, 0x83, 0xCD, 0xBD, 0x93, 
+0xBD, 0xB4, 0xB5, 0x52, 0xB5, 0x73, 0xB5, 0x52, 
+0xAC, 0xF1, 0xBD, 0xB3, 0xAD, 0x31, 0xAD, 0x32, 
+0xAD, 0x11, 0xCE, 0x35, 0xC5, 0xF5, 0xB5, 0x94, 
+0x63, 0x2B, 0x31, 0xA6, 0x31, 0xA5, 0x31, 0x85, 
+0x42, 0x07, 0x4A, 0x68, 0x52, 0x8A, 0x42, 0x28, 
+0x4A, 0x48, 0x63, 0x0B, 0x7B, 0x6D, 0x6A, 0xEB, 
+0x52, 0x28, 0x93, 0xEF, 0x9C, 0x70, 0x8B, 0xEE, 
+0x94, 0x6E, 0x9C, 0x8D, 0xA4, 0xEF, 0x9C, 0x6F, 
+0xDE, 0x56, 0xDE, 0x55, 0xDE, 0x35, 0xCD, 0xD4, 
+0xCD, 0xD4, 0xC5, 0xB3, 0xC5, 0x93, 0xCD, 0xD4, 
+0xD6, 0x35, 0xDE, 0x56, 0xDE, 0x76, 0xDE, 0x56, 
+0xCD, 0xD4, 0xC5, 0xD5, 0xCE, 0x15, 0xD6, 0x16, 
+0xDE, 0x77, 0xD6, 0x56, 0xD6, 0x36, 0xD6, 0x16, 
+0xCD, 0xD5, 0xD6, 0x16, 0xB5, 0x52, 0x9C, 0x90, 
+0xA4, 0xF1, 0xB5, 0x74, 0xB5, 0x32, 0xB5, 0x53, 
+0xBD, 0x94, 0xBD, 0x53, 0xB5, 0x33, 0xBD, 0x74, 
+0xCD, 0xF5, 0xD6, 0x36, 0xC5, 0xD5, 0xCE, 0x15, 
+0xD6, 0x76, 0xC5, 0xB4, 0xC5, 0xB4, 0xC5, 0xD5, 
+0x53, 0x0A, 0x29, 0xA4, 0x42, 0xA6, 0x6B, 0xC9, 
+0x31, 0xC3, 0x42, 0x46, 0x31, 0xE4, 0x52, 0xE9, 
+0x6B, 0xAC, 0x84, 0x8F, 0x7C, 0x4D, 0x84, 0x8E, 
+0x9D, 0x30, 0xA5, 0x31, 0xAD, 0x71, 0xA4, 0xCE, 
+0xC5, 0x91, 0xD6, 0x13, 0xBD, 0x50, 0x9C, 0x2D, 
+0xB5, 0x30, 0xBD, 0x72, 0x9C, 0x4D, 0xAC, 0xCF, 
+0xC5, 0xB2, 0xBD, 0x92, 0x9C, 0x8E, 0xCD, 0xD3, 
+0xB5, 0x31, 0xC5, 0xD3, 0xCD, 0xB3, 0xB5, 0x30, 
+0xD5, 0xF4, 0xD6, 0x14, 0xBD, 0x51, 0xCD, 0xF4, 
+0xDE, 0x76, 0xE6, 0x96, 0xBD, 0x10, 0xAC, 0xAE, 
+0xAC, 0xF0, 0xBD, 0x93, 0xAD, 0x52, 0xB5, 0x74, 
+0xAD, 0x32, 0x9C, 0x90, 0x52, 0x89, 0x31, 0x65, 
+0x31, 0xA5, 0x31, 0x65, 0x31, 0x86, 0x4A, 0x69, 
+0x63, 0x0C, 0x52, 0x8A, 0x42, 0x28, 0x7B, 0xCF, 
+0xA4, 0xD2, 0x94, 0x50, 0x73, 0x6D, 0x42, 0x28, 
+0x73, 0xAE, 0xC5, 0xF6, 0xB5, 0x32, 0xA4, 0xAF, 
+0x9C, 0x6F, 0xA4, 0xD0, 0xAD, 0x11, 0xA4, 0xF1, 
+0x9C, 0xAF, 0xA4, 0xB0, 0xA4, 0xB0, 0xA4, 0xB0, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x32, 0xB5, 0x52, 
+0xB5, 0x52, 0xAD, 0x11, 0xAD, 0x10, 0xA4, 0xF0, 
+0xA4, 0xD0, 0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xD0, 
+0xAC, 0xF0, 0xC5, 0x92, 0xAC, 0xCF, 0xB5, 0x10, 
+0xCD, 0x92, 0xCD, 0x92, 0xCD, 0x91, 0xCD, 0x92, 
+0xC5, 0x71, 0xC5, 0x71, 0xD5, 0xD3, 0xCD, 0x92, 
+0xC5, 0x71, 0xD5, 0xF3, 0xD5, 0xF3, 0xD5, 0xF3, 
+0xDE, 0x13, 0xD5, 0xF3, 0xCD, 0xB2, 0x9C, 0x4E, 
+0x6B, 0x0A, 0x6B, 0x0B, 0x39, 0xA6, 0x41, 0xE8, 
+0x73, 0xAF, 0x5A, 0xCB, 0x52, 0x8A, 0x73, 0x4D, 
+0x6B, 0x4D, 0x73, 0x8E, 0x9C, 0xB2, 0xA4, 0xB2, 
+0x93, 0xCE, 0x8B, 0xAE, 0x73, 0x2C, 0x6B, 0x0B, 
+0x52, 0x49, 0x8C, 0x51, 0x84, 0x30, 0x52, 0x6A, 
+0x62, 0xEB, 0x6B, 0x4D, 0x9C, 0xF3, 0xCE, 0x59, 
+0xDE, 0xBB, 0xCE, 0x18, 0xCD, 0xF7, 0xAD, 0x13, 
+0x83, 0xCD, 0x7B, 0xAC, 0x7B, 0xAC, 0x94, 0x4F, 
+0xAD, 0x11, 0x9C, 0x8F, 0x9C, 0x8F, 0x7B, 0xAC, 
+0x62, 0xE9, 0x62, 0xC9, 0x73, 0x4B, 0x73, 0x6B, 
+0x62, 0xCA, 0x31, 0x64, 0x39, 0xA6, 0x39, 0xC6, 
+0x4A, 0x68, 0x52, 0x69, 0x4A, 0x68, 0x52, 0x89, 
+0x42, 0x28, 0x4A, 0x49, 0x63, 0x0C, 0x6B, 0x4E, 
+0x73, 0x8F, 0x84, 0x31, 0x9C, 0xF4, 0xB5, 0x96, 
+0xAD, 0x34, 0x9C, 0xB1, 0xAD, 0x12, 0xA4, 0xD1, 
+0x9C, 0xB0, 0x9C, 0x90, 0x9C, 0x90, 0xA4, 0xF1, 
+0xB5, 0x52, 0xBD, 0x93, 0xBD, 0x94, 0xBD, 0x73, 
+0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0x93, 0xB5, 0x52, 
+0xB5, 0x52, 0xB5, 0x73, 0xB5, 0x52, 0xC5, 0xF4, 
+0xD6, 0x56, 0xB5, 0x31, 0xC5, 0x73, 0xC5, 0xB3, 
+0xC5, 0x92, 0xD5, 0xF4, 0xD6, 0x14, 0xD5, 0xF4, 
+0xD5, 0xF4, 0xD6, 0x15, 0xB4, 0xF0, 0xAC, 0xCF, 
+0xBD, 0x72, 0xDE, 0x76, 0xAD, 0x11, 0xB5, 0x73, 
+0xD6, 0x77, 0xBD, 0xF5, 0xC5, 0xF5, 0xBD, 0xD4, 
+0xCE, 0x15, 0xBD, 0x93, 0xBD, 0xD4, 0xCE, 0x56, 
+0xBD, 0xD4, 0xC5, 0xD4, 0xAD, 0x32, 0xB5, 0x72, 
+0xB5, 0x73, 0xAD, 0x32, 0xA4, 0xD0, 0xA4, 0xF1, 
+0xB5, 0x73, 0xAD, 0x32, 0x9C, 0xB0, 0x9C, 0x90, 
+0x9C, 0x90, 0x9C, 0x90, 0x94, 0x6F, 0xA4, 0xD1, 
+0x94, 0x6F, 0xA4, 0xD1, 0xA4, 0xD0, 0xAD, 0x11, 
+0xA4, 0xD0, 0xA4, 0xD0, 0x62, 0xE9, 0x6B, 0x0A, 
+0x7B, 0x8C, 0xA4, 0x90, 0xBD, 0x53, 0x8C, 0x0E, 
+0x94, 0x6F, 0x9C, 0x90, 0xAD, 0x32, 0xBD, 0x93, 
+0xC5, 0xD4, 0xC5, 0xF4, 0xCD, 0xF4, 0xCD, 0xF4, 
+0xBD, 0x93, 0xB5, 0x51, 0xB5, 0x72, 0xBD, 0x92, 
+0xC5, 0xB3, 0xAC, 0xF1, 0x8C, 0x2E, 0xBD, 0xB4, 
+0xBD, 0x93, 0xAD, 0x11, 0xA4, 0xF0, 0xB5, 0x52, 
+0xA4, 0xF0, 0xC5, 0xD4, 0xAD, 0x11, 0xA4, 0xD0, 
+0xB5, 0x72, 0xCE, 0x15, 0xBD, 0xB3, 0xB5, 0x94, 
+0xB5, 0x74, 0x73, 0xAD, 0x42, 0x07, 0x31, 0xA6, 
+0x39, 0xC6, 0x42, 0x28, 0x52, 0x89, 0x52, 0x69, 
+0x4A, 0x69, 0x62, 0xEB, 0x8B, 0xEF, 0x73, 0x2C, 
+0x73, 0x2C, 0x73, 0x0B, 0x94, 0x0F, 0x83, 0x8C, 
+0x62, 0xC8, 0x83, 0xEB, 0xB5, 0x91, 0x7B, 0x6B, 
+0xAC, 0xD0, 0xE6, 0x96, 0xE6, 0x96, 0xE6, 0xB7, 
+0xE6, 0x76, 0xE6, 0x76, 0xDE, 0x56, 0xDE, 0x76, 
+0xE6, 0x76, 0xE6, 0x97, 0xE6, 0xB7, 0xE6, 0xB8, 
+0xDE, 0x77, 0xDE, 0x77, 0xD6, 0x56, 0xDE, 0x77, 
+0xDE, 0x97, 0xDE, 0x77, 0xDE, 0x57, 0xD6, 0x56, 
+0xDE, 0x56, 0xDE, 0x97, 0xDE, 0x77, 0xA4, 0xD1, 
+0x9C, 0x90, 0x9C, 0x90, 0x94, 0x50, 0x7B, 0xAD, 
+0x9C, 0x90, 0xC5, 0xB4, 0xD6, 0x15, 0xD6, 0x36, 
+0x9C, 0x70, 0xB5, 0x53, 0xDE, 0x76, 0xDE, 0x77, 
+0x9C, 0x90, 0x7B, 0x8C, 0x83, 0xCD, 0x94, 0x2F, 
+0x6B, 0x8B, 0x4A, 0x87, 0x53, 0x08, 0x52, 0xC7, 
+0x39, 0xE5, 0x52, 0xC8, 0x63, 0x6A, 0x73, 0xED, 
+0x73, 0xED, 0x84, 0x90, 0x9D, 0x53, 0x84, 0xAF, 
+0x9D, 0x51, 0x8C, 0xAE, 0x9C, 0xEF, 0xAC, 0xEF, 
+0xAC, 0xEE, 0xB5, 0x0F, 0xB4, 0xEF, 0xA4, 0x8E, 
+0x9C, 0x6D, 0xAC, 0xCF, 0xA4, 0xAE, 0xA4, 0x8E, 
+0xAC, 0xCF, 0xA4, 0x8E, 0x94, 0x0C, 0x9C, 0x4D, 
+0x9C, 0x6D, 0xA4, 0xAE, 0xA4, 0x6D, 0xA4, 0x8E, 
+0xB5, 0x10, 0xBD, 0x51, 0xB4, 0xEF, 0xBD, 0x31, 
+0xCD, 0xF4, 0xD6, 0x34, 0xC5, 0x71, 0xAC, 0xAE, 
+0xA4, 0xAE, 0xAD, 0x10, 0xA5, 0x11, 0xB5, 0x93, 
+0xBD, 0x94, 0xB5, 0x93, 0xAD, 0x32, 0x73, 0x6B, 
+0x31, 0x85, 0x31, 0x65, 0x31, 0x65, 0x42, 0x07, 
+0x4A, 0x48, 0x4A, 0x69, 0x63, 0x0C, 0x42, 0x28, 
+0x9C, 0xD2, 0xA4, 0xD2, 0x94, 0x70, 0x94, 0xB2, 
+0x84, 0x10, 0x94, 0x92, 0xE7, 0x1B, 0xAD, 0x12, 
+0x7B, 0x6B, 0xA4, 0xD0, 0xBD, 0x93, 0xA4, 0xD0, 
+0x9C, 0x8F, 0x94, 0x6F, 0x8C, 0x2E, 0x94, 0x4F, 
+0x94, 0x4F, 0x9C, 0x6F, 0xA4, 0xF1, 0xAD, 0x32, 
+0xB5, 0x72, 0xAD, 0x11, 0xAD, 0x11, 0xA4, 0xAF, 
+0xA4, 0xD0, 0xA4, 0xD1, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xB5, 0x31, 0xB4, 0xEF, 0xC5, 0x72, 
+0xC5, 0x71, 0xC5, 0x71, 0xC5, 0x30, 0xBD, 0x10, 
+0xC5, 0x51, 0xBD, 0x30, 0xCD, 0x92, 0xB4, 0xF0, 
+0xB5, 0x10, 0xCD, 0xB2, 0xD5, 0xF3, 0xD5, 0xF3, 
+0xDE, 0x34, 0xDE, 0x54, 0xBD, 0x51, 0x8B, 0xED, 
+0x73, 0x6D, 0x94, 0x71, 0x94, 0x92, 0xBD, 0xB7, 
+0xBD, 0xD7, 0x63, 0x2C, 0x4A, 0x49, 0x5A, 0xAA, 
+0x5A, 0xCB, 0x62, 0xEB, 0x8C, 0x30, 0x94, 0x50, 
+0x9C, 0x91, 0x94, 0x0F, 0x94, 0x0F, 0xAC, 0xB2, 
+0x9C, 0x91, 0x9C, 0xB2, 0x83, 0xEF, 0x73, 0x6E, 
+0x8C, 0x51, 0xBD, 0xF7, 0xD6, 0x9A, 0xDE, 0xDB, 
+0xBD, 0xF7, 0xE6, 0xFB, 0xEF, 0x3C, 0xD6, 0x59, 
+0xAC, 0xF2, 0x9C, 0x90, 0x9C, 0x90, 0x94, 0x6F, 
+0x9C, 0x90, 0x9C, 0x6F, 0x8C, 0x2E, 0x7B, 0xAC, 
+0x7B, 0xAD, 0x7B, 0xAD, 0x94, 0x4F, 0x9C, 0xB0, 
+0x9C, 0xD1, 0x62, 0xEA, 0x39, 0xC6, 0x39, 0xA5, 
+0x41, 0xE6, 0x39, 0xC6, 0x39, 0xE7, 0x42, 0x28, 
+0x4A, 0x29, 0x52, 0xAA, 0x63, 0x2C, 0x63, 0x0C, 
+0x5A, 0xCC, 0x73, 0xAF, 0x7C, 0x10, 0x8C, 0x51, 
+0xAD, 0x34, 0xB5, 0x74, 0xBD, 0xB4, 0xAD, 0x12, 
+0xB5, 0x53, 0xBD, 0x94, 0xB5, 0x52, 0xB5, 0x52, 
+0xAD, 0x32, 0xA4, 0xF1, 0xAD, 0x11, 0xB5, 0x52, 
+0xAC, 0xF1, 0xA4, 0xD0, 0x9C, 0x90, 0x9C, 0xB0, 
+0xA4, 0xB0, 0x9C, 0x8F, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xA4, 0xF0, 0xAC, 0xF1, 0xAC, 0xD0, 0xA4, 0xAF, 
+0x9C, 0x6E, 0xA4, 0x8F, 0xAC, 0xCF, 0xAC, 0xD0, 
+0xAC, 0xF0, 0xAC, 0xD0, 0x9C, 0x6E, 0x9C, 0x6E, 
+0x9C, 0x6E, 0xAD, 0x11, 0x94, 0x4E, 0x94, 0x2E, 
+0x9C, 0xB0, 0xAD, 0x32, 0xA4, 0xF1, 0x94, 0x4E, 
+0x9C, 0x90, 0x8C, 0x2E, 0x94, 0x6F, 0xB5, 0x93, 
+0xC6, 0x15, 0xC5, 0xF5, 0xA4, 0xD0, 0x83, 0xED, 
+0x7B, 0xAC, 0x83, 0xED, 0xAD, 0x11, 0xA4, 0xF1, 
+0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x32, 0xAD, 0x11, 
+0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x73, 0xA5, 0x11, 
+0xAD, 0x32, 0xB5, 0x32, 0xAC, 0xF1, 0xB5, 0x52, 
+0xA4, 0xAF, 0xA4, 0xD0, 0x6B, 0x0A, 0x94, 0x4F, 
+0x9C, 0x8F, 0xA4, 0x90, 0xBD, 0x73, 0x8C, 0x0D, 
+0x9C, 0x90, 0xA4, 0xD0, 0xB5, 0x73, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xF4, 0xC5, 0xD3, 
+0xBD, 0x93, 0xB5, 0x51, 0xBD, 0x92, 0xB5, 0x72, 
+0xBD, 0x93, 0xC5, 0xB4, 0xAD, 0x11, 0xC5, 0xD4, 
+0xB5, 0x73, 0xAD, 0x11, 0xB5, 0x52, 0xBD, 0xB4, 
+0xAD, 0x11, 0xC5, 0xD4, 0xAC, 0xF1, 0xA4, 0xD1, 
+0xBD, 0x93, 0xCE, 0x15, 0xB5, 0x93, 0xAD, 0x73, 
+0xAD, 0x32, 0xB5, 0x73, 0x83, 0xEE, 0x42, 0x27, 
+0x39, 0xC6, 0x42, 0x07, 0x42, 0x28, 0x4A, 0x69, 
+0x4A, 0x49, 0x4A, 0x28, 0x5A, 0xAA, 0x83, 0xCE, 
+0x73, 0x0C, 0x73, 0x0B, 0x8B, 0xAD, 0x73, 0x2B, 
+0x5A, 0xC8, 0x5B, 0x27, 0x9D, 0x0E, 0xB5, 0xB2, 
+0xB5, 0x70, 0xBD, 0xD0, 0xBD, 0xF1, 0xEF, 0x17, 
+0xEE, 0xD7, 0xDE, 0x76, 0xEE, 0xD7, 0xEE, 0xD7, 
+0xE6, 0x97, 0xE6, 0xB7, 0xDE, 0x97, 0xE6, 0xB8, 
+0xDE, 0xB8, 0xE6, 0xB8, 0xE6, 0xB8, 0xE6, 0xB8, 
+0xDE, 0x98, 0xDE, 0x98, 0xDE, 0x77, 0xDE, 0x97, 
+0xDE, 0x97, 0xEE, 0xF8, 0xEE, 0xF8, 0xAD, 0x12, 
+0xAD, 0x33, 0xC5, 0xD5, 0xC5, 0xF5, 0xBD, 0xB5, 
+0x9C, 0xB1, 0xB5, 0x12, 0xD6, 0x15, 0xC5, 0xB4, 
+0x7B, 0xAC, 0x94, 0x70, 0x8C, 0x2F, 0xAD, 0x32, 
+0x8C, 0x2F, 0x8C, 0x2F, 0x9C, 0x91, 0x9C, 0xB1, 
+0x8C, 0x6F, 0x5A, 0xC8, 0x52, 0xC8, 0x5B, 0x2A, 
+0x84, 0x4F, 0x7C, 0x2E, 0x8C, 0x6E, 0x73, 0xCC, 
+0x73, 0xCD, 0x6B, 0xAC, 0x52, 0xE9, 0x4A, 0xA8, 
+0x94, 0xF0, 0x84, 0x2C, 0x94, 0x4D, 0xA4, 0xAE, 
+0xA4, 0x8E, 0xB4, 0xEF, 0xAC, 0xCE, 0xAC, 0xCF, 
+0xBD, 0x71, 0xB5, 0x0F, 0xAC, 0xAE, 0xAC, 0xAE, 
+0xAC, 0xCF, 0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x8E, 
+0xA4, 0x8E, 0xAC, 0xAE, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xB4, 0xEF, 0xB4, 0xEF, 0xAC, 0xCF, 
+0xAC, 0xAE, 0xAC, 0x8D, 0xAC, 0xAE, 0xAC, 0xAE, 
+0xA4, 0x8E, 0x9C, 0x4D, 0x94, 0x2D, 0x94, 0x2D, 
+0x94, 0x4E, 0x8C, 0x0D, 0x8C, 0x2D, 0x94, 0x4E, 
+0x8B, 0xEC, 0x62, 0xA8, 0x31, 0x84, 0x31, 0xA5, 
+0x39, 0xC6, 0x4A, 0x48, 0x63, 0x0C, 0x52, 0xAA, 
+0x52, 0xAA, 0x83, 0xCF, 0x84, 0x0F, 0x7B, 0xAE, 
+0x73, 0x6D, 0x73, 0x8E, 0xD6, 0xBA, 0xEF, 0x1B, 
+0xB5, 0x33, 0x8B, 0xAD, 0xB4, 0xF1, 0x94, 0x4F, 
+0x8C, 0x0E, 0x8C, 0x2E, 0x8C, 0x0E, 0x8C, 0x2F, 
+0x9C, 0x90, 0xA4, 0xD1, 0x94, 0x6F, 0x94, 0x6F, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xA4, 0xB0, 0x94, 0x4E, 
+0x9C, 0xB0, 0xA4, 0xF1, 0x9C, 0xB0, 0xAD, 0x11, 
+0xB5, 0x52, 0xBD, 0x31, 0xC5, 0x72, 0xCD, 0xB3, 
+0xC5, 0x51, 0xC5, 0x51, 0xBD, 0x31, 0xAC, 0xAF, 
+0xB4, 0xF0, 0xC5, 0x51, 0xCD, 0x72, 0xBD, 0x31, 
+0xBD, 0x51, 0xCD, 0x92, 0xD5, 0xD3, 0xCD, 0x92, 
+0xD5, 0xF3, 0xDE, 0x55, 0xA4, 0xB0, 0xB5, 0x95, 
+0xBD, 0xD6, 0xC5, 0xF7, 0xB5, 0xB6, 0x6B, 0x4D, 
+0x6B, 0x4D, 0x42, 0x08, 0x29, 0x45, 0x31, 0xA6, 
+0x42, 0x07, 0x42, 0x08, 0x7B, 0xAE, 0x8C, 0x30, 
+0xAD, 0x14, 0x8B, 0xEF, 0x9C, 0x50, 0xA4, 0xD2, 
+0xB5, 0x34, 0xCE, 0x18, 0xCE, 0x38, 0xCE, 0x38, 
+0xAD, 0x34, 0xD6, 0x79, 0x9C, 0xD3, 0xAD, 0x14, 
+0x94, 0x72, 0xAD, 0x55, 0xCE, 0x59, 0xF7, 0x5C, 
+0xBD, 0xB5, 0xAC, 0xF2, 0xAC, 0xF1, 0x9C, 0x8F, 
+0xA4, 0xD0, 0x94, 0x6F, 0x7B, 0xAC, 0x8C, 0x0E, 
+0x83, 0xCD, 0x8C, 0x2E, 0x9C, 0xB1, 0xAD, 0x12, 
+0x9C, 0xB0, 0x8C, 0x2E, 0x42, 0x06, 0x31, 0x85, 
+0x39, 0xC6, 0x39, 0xC6, 0x39, 0xE6, 0x39, 0xE7, 
+0x42, 0x08, 0x52, 0xAA, 0x5A, 0xCB, 0x63, 0x2D, 
+0x63, 0x0D, 0x6B, 0x6E, 0x73, 0x8E, 0x84, 0x30, 
+0xA5, 0x34, 0xB5, 0x75, 0xC5, 0xD6, 0xC5, 0xB4, 
+0xCE, 0x36, 0xBD, 0xB4, 0xBD, 0x94, 0xBD, 0x93, 
+0xBD, 0x73, 0xB5, 0x52, 0xC5, 0xD4, 0xDE, 0x97, 
+0xDE, 0x97, 0xBD, 0x93, 0xAC, 0xF1, 0xCD, 0xF5, 
+0xC5, 0xB4, 0xAC, 0xF1, 0x9C, 0x4F, 0x8C, 0x0E, 
+0x8C, 0x0D, 0x8C, 0x0E, 0x9C, 0x8F, 0xAD, 0x32, 
+0xBD, 0x73, 0xAC, 0xF1, 0xA4, 0x90, 0xA4, 0xB0, 
+0xA4, 0xB0, 0xA4, 0xB0, 0xA4, 0xB0, 0xAD, 0x11, 
+0xA4, 0xB0, 0x9C, 0x6F, 0xA4, 0xB0, 0xAC, 0xD1, 
+0xA4, 0xD1, 0x9C, 0xB0, 0x94, 0x4E, 0x9C, 0x8F, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xA4, 0xB0, 0x9C, 0x90, 
+0x9C, 0x8F, 0xA4, 0xB0, 0xA4, 0xB0, 0xA4, 0xD1, 
+0xA4, 0xD1, 0x94, 0x4F, 0x83, 0xED, 0x83, 0xCD, 
+0x8B, 0xCD, 0x83, 0xCD, 0x8B, 0xED, 0x83, 0xCD, 
+0x83, 0xCD, 0x8C, 0x0E, 0x8C, 0x2E, 0x8C, 0x0E, 
+0x94, 0x2E, 0x9C, 0xB0, 0xAD, 0x11, 0xB5, 0x52, 
+0xA4, 0xF1, 0x83, 0xED, 0x6B, 0x2A, 0x94, 0x2E, 
+0x9C, 0x8F, 0x94, 0x2E, 0xBD, 0x53, 0x8B, 0xED, 
+0x9C, 0x6F, 0x9C, 0xB0, 0xAD, 0x32, 0xB5, 0x73, 
+0xB5, 0x52, 0xB5, 0x72, 0xBD, 0x93, 0xBD, 0x93, 
+0xBD, 0x93, 0xB5, 0x72, 0xBD, 0xB3, 0xBD, 0x93, 
+0xBD, 0x93, 0xC5, 0xB4, 0xAD, 0x11, 0xBD, 0xB4, 
+0xBD, 0x94, 0xBD, 0x93, 0xC5, 0xF5, 0xBD, 0x93, 
+0xB5, 0x53, 0xBD, 0xB3, 0xA4, 0xF0, 0xAD, 0x32, 
+0xBD, 0x93, 0xC5, 0xD4, 0xA5, 0x11, 0xAD, 0x73, 
+0xA4, 0xF2, 0xB5, 0x73, 0xBD, 0xD4, 0xB5, 0x52, 
+0x52, 0x67, 0x31, 0x85, 0x31, 0x85, 0x39, 0xE6, 
+0x42, 0x27, 0x4A, 0x68, 0x4A, 0x48, 0x8C, 0x30, 
+0x83, 0xAE, 0x73, 0x2C, 0x8B, 0xCE, 0x8B, 0xCD, 
+0x5A, 0xC7, 0x53, 0x26, 0x5B, 0x66, 0x94, 0xEE, 
+0x94, 0x8C, 0xA5, 0x6D, 0xAD, 0xAE, 0xD6, 0x93, 
+0xB5, 0xB1, 0x84, 0x2C, 0xDE, 0xB5, 0xEE, 0xF7, 
+0xEE, 0xD8, 0xEE, 0xF8, 0xE6, 0xB8, 0xDE, 0x97, 
+0xDE, 0xD8, 0xDE, 0x98, 0xDE, 0xB8, 0xDE, 0xB8, 
+0xE6, 0xD8, 0xE6, 0xD8, 0xDE, 0xB7, 0xDE, 0x97, 
+0xDE, 0xB8, 0xE6, 0xF8, 0xE6, 0xD8, 0xAD, 0x12, 
+0xAD, 0x12, 0xCE, 0x36, 0xD6, 0x77, 0xCE, 0x36, 
+0xC5, 0xD5, 0xD6, 0x36, 0xD6, 0x15, 0xCD, 0xF5, 
+0xB5, 0x53, 0xC6, 0x15, 0xA4, 0xD1, 0xBD, 0xD5, 
+0xCE, 0x37, 0xC6, 0x16, 0xCE, 0x16, 0xC5, 0xF6, 
+0x7C, 0x0E, 0x3A, 0x06, 0x6B, 0xAD, 0x73, 0xEE, 
+0x8C, 0xD1, 0x9D, 0x12, 0x8C, 0x6F, 0x94, 0x8F, 
+0xA5, 0x11, 0xB5, 0x52, 0xAD, 0x31, 0x94, 0x6E, 
+0x6B, 0x29, 0x62, 0xC8, 0x5A, 0xA8, 0x73, 0x4A, 
+0x62, 0xE9, 0x73, 0x6A, 0xA4, 0xD0, 0xAC, 0xD0, 
+0x9C, 0x6D, 0xAC, 0xCF, 0xC5, 0x92, 0xC5, 0x92, 
+0xC5, 0x92, 0xBD, 0x30, 0xBD, 0x51, 0xCD, 0xB2, 
+0xB5, 0x10, 0xB4, 0xEF, 0xAC, 0xCF, 0xB5, 0x10, 
+0xA4, 0x8E, 0xAC, 0xCE, 0xAC, 0x8E, 0xAC, 0xAE, 
+0xB4, 0xCF, 0xBD, 0x30, 0xD5, 0xD3, 0xC5, 0x51, 
+0xB5, 0x0F, 0xAC, 0xEF, 0xBD, 0x50, 0xBD, 0x30, 
+0xB5, 0x10, 0xB5, 0x30, 0xB5, 0x10, 0xB5, 0x30, 
+0xBD, 0x30, 0xBD, 0x30, 0x94, 0x2D, 0x52, 0x47, 
+0x29, 0x64, 0x39, 0xE7, 0x62, 0xEB, 0x5A, 0xCA, 
+0x5A, 0xCA, 0x63, 0x0C, 0x41, 0xE7, 0x41, 0xE7, 
+0x5A, 0xEB, 0x7B, 0xF0, 0xD6, 0x9A, 0xE7, 0x1C, 
+0xF7, 0x7D, 0xD6, 0x38, 0x94, 0x2F, 0xA4, 0xD1, 
+0x9C, 0x6F, 0x94, 0x4E, 0x8C, 0x0E, 0x8C, 0x0E, 
+0x94, 0x4F, 0xB5, 0x73, 0x9C, 0xB0, 0x83, 0xCD, 
+0x8C, 0x0E, 0x83, 0xCC, 0x73, 0x6B, 0x83, 0xCC, 
+0x8C, 0x0E, 0x94, 0x4F, 0x9C, 0x6F, 0xA4, 0xD0, 
+0xAD, 0x11, 0xBD, 0x72, 0xCD, 0xB2, 0xD5, 0xD3, 
+0xCD, 0xB2, 0xD5, 0xD3, 0xE6, 0x35, 0xD5, 0xB3, 
+0xC5, 0x51, 0xCD, 0x92, 0xC5, 0x92, 0xCD, 0xD3, 
+0xCD, 0x92, 0xCD, 0xB3, 0xDE, 0x34, 0xC5, 0x71, 
+0xBD, 0x31, 0xBD, 0x72, 0xA4, 0xD1, 0x94, 0x71, 
+0x73, 0x6D, 0x7B, 0xCF, 0x6B, 0x2C, 0x42, 0x28, 
+0x5A, 0xCB, 0x52, 0xAA, 0x4A, 0x49, 0x21, 0x04, 
+0x29, 0x45, 0x31, 0x65, 0x5A, 0xAA, 0x73, 0x8D, 
+0x8B, 0xEF, 0xA4, 0xB2, 0x94, 0x30, 0xA4, 0xD2, 
+0xA4, 0xD2, 0xBD, 0x95, 0xA4, 0xD3, 0xD6, 0x59, 
+0xD6, 0x38, 0xDE, 0x79, 0x8C, 0x10, 0xAD, 0x34, 
+0x73, 0xAE, 0x52, 0x8A, 0x7B, 0xAF, 0xDE, 0xDB, 
+0xCE, 0x38, 0x94, 0x91, 0x9C, 0xB1, 0xAC, 0xF1, 
+0xB5, 0x32, 0xAC, 0xF1, 0x9C, 0x8F, 0xA4, 0xD0, 
+0x9C, 0x90, 0x9C, 0x90, 0xD6, 0x57, 0xBD, 0xD5, 
+0x94, 0x50, 0x83, 0xEE, 0x63, 0x0B, 0x41, 0xE7, 
+0x42, 0x07, 0x39, 0xC6, 0x39, 0xE7, 0x41, 0xE7, 
+0x42, 0x07, 0x52, 0x8A, 0x52, 0x8A, 0x63, 0x0C, 
+0x6B, 0x4D, 0x63, 0x0C, 0x63, 0x2D, 0x83, 0xF0, 
+0x94, 0x92, 0xB5, 0x75, 0xC5, 0xD6, 0xC5, 0xD6, 
+0x8C, 0x50, 0x62, 0xCA, 0xB5, 0x74, 0x9C, 0x70, 
+0xA4, 0xD1, 0xAD, 0x11, 0xB5, 0x73, 0xD6, 0x56, 
+0xE6, 0xD8, 0xBD, 0x93, 0xBD, 0x73, 0xD6, 0x36, 
+0xC5, 0xB4, 0xB5, 0x72, 0xBD, 0x93, 0xB5, 0x52, 
+0xB5, 0x32, 0xAD, 0x12, 0xAD, 0x11, 0xC5, 0xD4, 
+0xC5, 0xF5, 0xC5, 0xD4, 0xAD, 0x11, 0xA4, 0xB0, 
+0x94, 0x4E, 0x8C, 0x0D, 0x94, 0x4F, 0xA4, 0xB0, 
+0x94, 0x4F, 0xB5, 0x32, 0xC5, 0xD4, 0xBD, 0x93, 
+0x9C, 0x6F, 0x9C, 0x6F, 0x9C, 0xB0, 0xC5, 0xB4, 
+0xCD, 0xF5, 0xD6, 0x56, 0xC5, 0xD4, 0xBD, 0x73, 
+0xAD, 0x11, 0x9C, 0x6F, 0xB5, 0x52, 0xAD, 0x11, 
+0xA4, 0xF1, 0xA4, 0xB0, 0xAD, 0x11, 0xAD, 0x11, 
+0xAC, 0xD1, 0xAC, 0xD0, 0xA4, 0xD0, 0xA4, 0xD1, 
+0xA4, 0xB0, 0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x90, 
+0x9C, 0x90, 0x9C, 0x6F, 0x94, 0x2E, 0x94, 0x2E, 
+0x94, 0x0E, 0x9C, 0x4F, 0xA4, 0xB0, 0x9C, 0x6F, 
+0x94, 0x4E, 0x9C, 0x6F, 0xB5, 0x32, 0x9C, 0x6F, 
+0x8C, 0x2E, 0x83, 0xED, 0x94, 0x4E, 0x94, 0x6F, 
+0x83, 0xED, 0x94, 0x4E, 0xA4, 0xD0, 0xA4, 0xF0, 
+0xB5, 0x52, 0xBD, 0xB3, 0xC5, 0xD4, 0xCE, 0x15, 
+0xCE, 0x15, 0xCE, 0x14, 0xB5, 0x52, 0xBD, 0xB4, 
+0xC5, 0xD4, 0xC5, 0xB3, 0xCE, 0x36, 0xC5, 0xD4, 
+0xBD, 0xB4, 0xC5, 0xF4, 0x9C, 0xB0, 0x94, 0x6F, 
+0xA4, 0xF0, 0xA4, 0xF1, 0x94, 0x4E, 0xAD, 0x32, 
+0xAD, 0x32, 0xB5, 0x73, 0xBD, 0xD4, 0xDE, 0xB6, 
+0xBD, 0xD4, 0x52, 0x88, 0x31, 0xA5, 0x29, 0x64, 
+0x39, 0xC6, 0x4A, 0x48, 0x4A, 0x48, 0x62, 0xCA, 
+0x5A, 0xAA, 0x73, 0x2C, 0x83, 0x6D, 0x83, 0x8D, 
+0x5A, 0xC8, 0x42, 0xA5, 0x5B, 0x87, 0x42, 0x64, 
+0x84, 0x2B, 0x84, 0x8A, 0xBE, 0x50, 0x94, 0xEC, 
+0x74, 0x49, 0x6C, 0x09, 0xC6, 0x12, 0xD6, 0x34, 
+0xD6, 0x35, 0xD6, 0x36, 0xBD, 0xB4, 0xA5, 0x12, 
+0xAD, 0x53, 0xBD, 0xB5, 0xDE, 0xB8, 0xCE, 0x36, 
+0xDE, 0xB8, 0xDE, 0xD8, 0xD6, 0x77, 0xD6, 0x77, 
+0xDE, 0xB8, 0xE6, 0xF8, 0xDE, 0xB8, 0xAD, 0x12, 
+0xAD, 0x12, 0xCE, 0x36, 0xD6, 0x57, 0xC5, 0xD5, 
+0xBD, 0xB3, 0xD6, 0x15, 0xCD, 0xB3, 0xDE, 0x55, 
+0xCD, 0xD4, 0xC5, 0xD4, 0xC5, 0xD5, 0xCE, 0x36, 
+0xD6, 0x77, 0xD6, 0x57, 0xCE, 0x16, 0xD6, 0x77, 
+0x3A, 0x47, 0x74, 0x0E, 0x7C, 0x90, 0x84, 0xB1, 
+0x9D, 0x54, 0xA5, 0x74, 0x94, 0xB0, 0x9C, 0xD0, 
+0xC5, 0xF4, 0xDE, 0x76, 0xCE, 0x14, 0xB5, 0x11, 
+0x94, 0x4F, 0x6B, 0x0A, 0x6B, 0x0A, 0x8C, 0x2E, 
+0x7B, 0xCC, 0x94, 0x6F, 0xC5, 0xD5, 0xC5, 0xB3, 
+0xA4, 0x8E, 0xC5, 0x71, 0xD5, 0xF4, 0xDE, 0x55, 
+0xDE, 0x55, 0xD6, 0x14, 0xCD, 0xB2, 0xDE, 0x75, 
+0xDE, 0x55, 0xDE, 0x34, 0xD5, 0xF3, 0xD6, 0x14, 
+0xCD, 0xD3, 0xC5, 0x92, 0xCD, 0xB2, 0xD6, 0x14, 
+0xDE, 0x35, 0xCD, 0xB2, 0xDE, 0x34, 0xC5, 0x71, 
+0xB5, 0x0F, 0xC5, 0x92, 0xBD, 0x30, 0xB4, 0xEF, 
+0xAC, 0xAE, 0x9C, 0x2C, 0x94, 0x2C, 0x7B, 0x8A, 
+0x83, 0xAB, 0x94, 0x0D, 0x9C, 0x6E, 0x83, 0xAC, 
+0x52, 0x68, 0x42, 0x27, 0x42, 0x28, 0x39, 0xE6, 
+0x42, 0x07, 0x39, 0xE7, 0x42, 0x07, 0x39, 0xE7, 
+0x42, 0x28, 0x84, 0x10, 0xBD, 0xD7, 0xAD, 0x55, 
+0xD6, 0xBB, 0xEF, 0x3D, 0xE6, 0xFB, 0xBD, 0x74, 
+0xB5, 0x11, 0xBD, 0x52, 0xBD, 0x31, 0xB5, 0x31, 
+0xAC, 0xF0, 0xAC, 0xF0, 0xAC, 0xD0, 0xA4, 0xAF, 
+0xA4, 0xAF, 0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x4E, 
+0x9C, 0x6E, 0x9C, 0x6E, 0x94, 0x2D, 0x94, 0x4E, 
+0x9C, 0x6E, 0xB5, 0x10, 0xA4, 0x4D, 0x9C, 0x2C, 
+0x9C, 0x2C, 0xA4, 0x6D, 0xB4, 0xCF, 0xBD, 0x10, 
+0xBC, 0xF0, 0xB4, 0xF0, 0xB5, 0x31, 0xBD, 0x72, 
+0xC5, 0x72, 0xCD, 0xB3, 0xDE, 0x35, 0xE6, 0x75, 
+0xEE, 0x95, 0xEE, 0xB7, 0xC5, 0xB3, 0x83, 0xCD, 
+0x52, 0x68, 0x7B, 0xCD, 0x8C, 0x2F, 0x94, 0x71, 
+0x8C, 0x50, 0x8C, 0x51, 0x9C, 0xF3, 0x83, 0xEF, 
+0x73, 0xAE, 0x63, 0x2C, 0x42, 0x28, 0x4A, 0x48, 
+0x6B, 0x0B, 0x83, 0xCE, 0x9C, 0x71, 0xA4, 0xD2, 
+0x9C, 0x71, 0x9C, 0x91, 0xB5, 0x35, 0x8C, 0x10, 
+0xB5, 0x75, 0xCE, 0x38, 0x8C, 0x10, 0x5A, 0xEB, 
+0x39, 0xC7, 0x31, 0xA7, 0x6B, 0x2D, 0xE7, 0x3C, 
+0xF7, 0xBE, 0xEF, 0x3D, 0xE6, 0xDA, 0xB5, 0x53, 
+0xB5, 0x11, 0xC5, 0x92, 0xC5, 0x72, 0xBD, 0x72, 
+0xAC, 0xD0, 0x94, 0x2F, 0xB5, 0x95, 0xDE, 0xDB, 
+0xC6, 0x17, 0x8C, 0x30, 0x7B, 0xAD, 0x52, 0x69, 
+0x39, 0xE6, 0x39, 0xC6, 0x4A, 0x68, 0x4A, 0x48, 
+0x39, 0xE7, 0x39, 0xE7, 0x42, 0x08, 0x4A, 0x49, 
+0x52, 0x69, 0x4A, 0x6A, 0x6B, 0x2D, 0x6B, 0x6D, 
+0x7B, 0xCF, 0x83, 0xF0, 0x73, 0x8E, 0x7B, 0xEF, 
+0x63, 0x0C, 0x94, 0x92, 0xD6, 0x99, 0xAD, 0x13, 
+0x94, 0x6F, 0xA4, 0xD0, 0xA4, 0xF1, 0xC5, 0xD4, 
+0xDE, 0xB8, 0xB5, 0x53, 0xC5, 0xD4, 0xCD, 0xF5, 
+0xBD, 0x94, 0xAD, 0x11, 0xB5, 0x52, 0xAC, 0xF1, 
+0xAD, 0x11, 0xAD, 0x11, 0xBD, 0x73, 0xBD, 0xB4, 
+0xC5, 0xD4, 0xC5, 0xF4, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xB5, 0x52, 0x9C, 0x8F, 0xAD, 0x32, 0xBD, 0x73, 
+0xBD, 0x93, 0xCD, 0xF5, 0xC5, 0xF5, 0xD6, 0x77, 
+0xC5, 0xB4, 0xAC, 0xF1, 0xC5, 0xD4, 0xBD, 0xB3, 
+0xC5, 0xB3, 0xCD, 0xF4, 0xD6, 0x15, 0xCD, 0xF4, 
+0xC5, 0xB4, 0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x52, 
+0xAD, 0x12, 0xB5, 0x52, 0xC5, 0xD4, 0xCD, 0xF5, 
+0xC5, 0xB3, 0xD6, 0x56, 0xC5, 0xD4, 0xA4, 0xD1, 
+0x9C, 0x90, 0x94, 0x6F, 0x9C, 0x6F, 0xBD, 0x73, 
+0xAC, 0xF1, 0xA4, 0xB0, 0xC5, 0xB4, 0xCD, 0xD4, 
+0xCD, 0xD4, 0xCD, 0xD4, 0xBD, 0x73, 0xBD, 0x73, 
+0xBD, 0x52, 0xA4, 0xD0, 0xAC, 0xF1, 0xB5, 0x11, 
+0xAC, 0xF0, 0xAC, 0xF1, 0xAC, 0xF1, 0x9C, 0xB0, 
+0xA4, 0xD1, 0xAC, 0xF1, 0xA4, 0xB0, 0x9C, 0x8F, 
+0xA4, 0xB0, 0x9C, 0x8F, 0x94, 0x4E, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xA4, 0xD0, 0x9C, 0xB0, 0x94, 0x6F, 
+0xA4, 0xD0, 0xAD, 0x11, 0xB5, 0x52, 0xB5, 0x73, 
+0xB5, 0x73, 0xAD, 0x32, 0x8C, 0x2E, 0x83, 0xCD, 
+0x73, 0x6B, 0x6B, 0x2B, 0x73, 0x4B, 0x73, 0x6C, 
+0x83, 0xCD, 0x8C, 0x0E, 0x94, 0x6F, 0x9C, 0x8F, 
+0xA4, 0xD0, 0x83, 0xED, 0x52, 0x68, 0x42, 0x07, 
+0x42, 0x07, 0x39, 0xC6, 0x39, 0xE7, 0x39, 0xE7, 
+0x41, 0xE7, 0x5A, 0xAA, 0x7B, 0x6D, 0x83, 0xCE, 
+0x6A, 0xEA, 0x5A, 0xE9, 0x5B, 0x28, 0x42, 0x66, 
+0x52, 0xC7, 0x94, 0xEC, 0xA5, 0x8D, 0x6C, 0x08, 
+0x6C, 0x48, 0x6C, 0x49, 0xC6, 0x33, 0xE6, 0xB7, 
+0xC5, 0xB4, 0xB5, 0x73, 0xBD, 0xB5, 0xBD, 0xB5, 
+0xAD, 0x33, 0x9C, 0xB1, 0xB5, 0x94, 0x94, 0x70, 
+0x8C, 0x2F, 0x8C, 0x50, 0x94, 0x70, 0xA4, 0xF2, 
+0xC5, 0xF6, 0xEF, 0x3A, 0xDE, 0x97, 0xA4, 0xF1, 
+0xAD, 0x32, 0xCE, 0x36, 0xA4, 0xD1, 0x73, 0x4C, 
+0xAD, 0x11, 0xBD, 0x51, 0xBD, 0x72, 0xBD, 0x51, 
+0xC5, 0x93, 0xDE, 0x57, 0xD6, 0x56, 0xC5, 0xD5, 
+0xCE, 0x15, 0xD6, 0x36, 0xCD, 0xF5, 0xDE, 0x77, 
+0x53, 0x09, 0x5B, 0x2A, 0x5B, 0x4B, 0x63, 0x8C, 
+0x8C, 0xB0, 0x84, 0x2F, 0x8C, 0x6F, 0x9C, 0xD0, 
+0xA4, 0xF1, 0xC5, 0xD4, 0xBD, 0x72, 0xAC, 0xF0, 
+0xB5, 0x52, 0xA4, 0xB0, 0x9C, 0x8F, 0xB5, 0x52, 
+0xCD, 0xF5, 0xDE, 0x77, 0xE6, 0xD8, 0xE6, 0xB7, 
+0xAC, 0xAE, 0xDE, 0x34, 0xDE, 0x34, 0xD6, 0x14, 
+0xCD, 0xD3, 0xCD, 0xB2, 0xC5, 0x92, 0xC5, 0xB2, 
+0xDE, 0x34, 0xE6, 0x75, 0xD5, 0xF4, 0xDE, 0x75, 
+0xE6, 0xB6, 0xEE, 0xB7, 0xE6, 0x96, 0xDE, 0x55, 
+0xD5, 0xF3, 0xBD, 0x30, 0xB4, 0xEF, 0xAC, 0x8E, 
+0xAC, 0xAE, 0xB5, 0x10, 0xD5, 0xF3, 0xB4, 0xEF, 
+0x9C, 0x4D, 0x9C, 0x6E, 0xA4, 0xF0, 0x8C, 0x0E, 
+0x73, 0x6C, 0x73, 0x6B, 0x6B, 0x0A, 0x5A, 0xA9, 
+0x62, 0xC9, 0x52, 0x88, 0x39, 0xC6, 0x39, 0xE7, 
+0x31, 0xA6, 0x31, 0x65, 0x39, 0xE7, 0x39, 0xC6, 
+0x4A, 0x48, 0x7B, 0xEF, 0x94, 0xD3, 0x9C, 0xD4, 
+0xCE, 0x9B, 0xDE, 0xFC, 0xDE, 0xFB, 0xE7, 0x1B, 
+0xBD, 0x94, 0x8B, 0xEE, 0x94, 0x4E, 0x9C, 0x4D, 
+0xA4, 0xAF, 0xAC, 0xCF, 0xA4, 0x8E, 0xAC, 0xCF, 
+0xB4, 0xEF, 0xBD, 0x30, 0xBD, 0x31, 0xB5, 0x10, 
+0xB5, 0x10, 0xBD, 0x51, 0xBD, 0x30, 0xBD, 0x30, 
+0xB5, 0x10, 0xC5, 0x71, 0xC5, 0x71, 0xC5, 0x71, 
+0xCD, 0x91, 0xC5, 0x71, 0xC5, 0x71, 0xC5, 0x30, 
+0xBC, 0xEF, 0xAC, 0x8E, 0x9C, 0x2D, 0xB5, 0x74, 
+0xE6, 0xDA, 0xD6, 0x58, 0xA4, 0x90, 0x8B, 0xAC, 
+0x93, 0xEC, 0x9C, 0x0C, 0x94, 0x0C, 0x94, 0x0D, 
+0x8B, 0xCC, 0x7B, 0x6B, 0x8B, 0xEC, 0x94, 0x2E, 
+0x7B, 0xAC, 0x62, 0xE9, 0x5A, 0xA9, 0x62, 0xEB, 
+0x6B, 0x4D, 0x73, 0xAE, 0x5A, 0xAA, 0x73, 0x6D, 
+0x5A, 0xCA, 0x62, 0xCA, 0x62, 0xCA, 0x73, 0x2C, 
+0xAC, 0xD2, 0x9C, 0x71, 0xBD, 0x96, 0xAC, 0xF4, 
+0xA4, 0xF3, 0xCE, 0x18, 0xD6, 0x59, 0x9C, 0xB3, 
+0x4A, 0x49, 0x31, 0x66, 0x73, 0x8E, 0xDE, 0xBA, 
+0xD6, 0x9A, 0xEF, 0x3C, 0xEF, 0x1C, 0xD6, 0x58, 
+0x9C, 0x91, 0xCD, 0xD5, 0xC5, 0x72, 0xC5, 0x72, 
+0xA4, 0xB0, 0x94, 0x50, 0x6B, 0x2C, 0x94, 0x92, 
+0xCE, 0x59, 0xCE, 0x59, 0xA4, 0xF3, 0x73, 0x8D, 
+0x41, 0xE7, 0x39, 0xC6, 0x4A, 0x68, 0x42, 0x07, 
+0x39, 0xE7, 0x39, 0xC7, 0x39, 0xC7, 0x42, 0x08, 
+0x42, 0x28, 0x4A, 0x49, 0x5A, 0xCB, 0x63, 0x2D, 
+0x6B, 0x4D, 0x62, 0xEC, 0x5A, 0xAB, 0x52, 0xAA, 
+0x62, 0xEC, 0x9C, 0xF3, 0xBD, 0xD6, 0xDE, 0x99, 
+0xA4, 0xD1, 0xA4, 0xD1, 0xA4, 0xF1, 0xC5, 0xD4, 
+0xE6, 0xB8, 0xAD, 0x11, 0xC5, 0xD4, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xA4, 0xD0, 0xB5, 0x52, 0xBD, 0x73, 
+0xB5, 0x52, 0xB5, 0x32, 0xBD, 0x73, 0xB5, 0x52, 
+0xC5, 0xD4, 0xBD, 0x93, 0xBD, 0x93, 0xB5, 0x73, 
+0xB5, 0x52, 0x9C, 0x6F, 0xB5, 0x52, 0xB5, 0x73, 
+0xBD, 0x73, 0xBD, 0x94, 0xBD, 0x94, 0xBD, 0xB4, 
+0xBD, 0x94, 0xA4, 0xB0, 0x9C, 0xB0, 0xBD, 0x93, 
+0xCD, 0xD4, 0xCD, 0xD3, 0xCD, 0xD3, 0xCD, 0xF4, 
+0xCE, 0x14, 0xC5, 0xB4, 0xBD, 0xB4, 0xCE, 0x36, 
+0xC5, 0xD5, 0xC5, 0xF5, 0xBD, 0x72, 0xAC, 0xF1, 
+0xAD, 0x10, 0xB5, 0x51, 0xA4, 0xF0, 0x83, 0xCD, 
+0x94, 0x4F, 0x94, 0x6F, 0x83, 0xAD, 0x94, 0x4F, 
+0x8B, 0xED, 0xAD, 0x11, 0x9C, 0x6E, 0xA4, 0xB0, 
+0xAC, 0xF0, 0xB5, 0x31, 0xAC, 0xF0, 0xAD, 0x11, 
+0xA4, 0xAF, 0x8B, 0xEC, 0x94, 0x2D, 0x94, 0x2D, 
+0x94, 0x2D, 0xBD, 0x72, 0xAC, 0xF0, 0x83, 0xCC, 
+0x8C, 0x2D, 0x9C, 0x6F, 0xAD, 0x11, 0xD6, 0x35, 
+0xBD, 0x93, 0xAD, 0x11, 0xAD, 0x11, 0xB5, 0x32, 
+0xA4, 0xD1, 0x9C, 0x90, 0x9C, 0x8F, 0x94, 0x4F, 
+0x8C, 0x2E, 0x8C, 0x0E, 0x7B, 0xAD, 0x7B, 0xAC, 
+0x83, 0xCD, 0x83, 0xEE, 0x8B, 0xEE, 0x9C, 0x90, 
+0x94, 0x70, 0x9C, 0x90, 0x9C, 0xD1, 0x9C, 0xB1, 
+0x9C, 0x90, 0x9C, 0x90, 0x94, 0x70, 0x94, 0x70, 
+0x9C, 0xB1, 0xA4, 0xF2, 0xA4, 0xD1, 0x7B, 0xAD, 
+0x4A, 0x48, 0x39, 0xA6, 0x31, 0xA5, 0x39, 0xC6, 
+0x42, 0x28, 0x4A, 0x28, 0x5A, 0xCA, 0x6B, 0x2C, 
+0x73, 0x4C, 0x6B, 0x2B, 0x63, 0x0A, 0x5A, 0xE8, 
+0x7C, 0x4B, 0x74, 0x49, 0x84, 0xAA, 0x5B, 0x47, 
+0x63, 0xA8, 0x74, 0x09, 0x9C, 0x8F, 0x9C, 0x4F, 
+0x94, 0x4F, 0x94, 0x70, 0x94, 0x6F, 0x9C, 0xB0, 
+0x9C, 0xB1, 0xA4, 0xF2, 0x94, 0x70, 0x94, 0x70, 
+0xA4, 0xF2, 0xA4, 0xF2, 0xAD, 0x54, 0x9C, 0xD2, 
+0xA4, 0xF2, 0xE6, 0xD8, 0xC5, 0xD4, 0x9C, 0xB0, 
+0xBD, 0x94, 0xE6, 0xB8, 0xCD, 0xF5, 0xCD, 0xF5, 
+0xD6, 0x16, 0xDE, 0x35, 0xBD, 0x73, 0x8B, 0xED, 
+0xAC, 0xD1, 0xDE, 0x77, 0xC5, 0xD4, 0xC5, 0xB3, 
+0xBD, 0x73, 0xBD, 0x73, 0xBD, 0x73, 0xCD, 0xD4, 
+0x5B, 0x2A, 0x84, 0x2E, 0x9C, 0xD0, 0x8C, 0x6E, 
+0xA5, 0x11, 0x84, 0x0D, 0x84, 0x0D, 0x8C, 0x4E, 
+0x9C, 0xAF, 0xCD, 0xF4, 0xA4, 0xCF, 0x94, 0x4D, 
+0x94, 0x4E, 0xB5, 0x32, 0xB5, 0x52, 0xBD, 0x52, 
+0xDE, 0x77, 0xE6, 0xB7, 0xE6, 0x97, 0xDE, 0x56, 
+0xAC, 0xAF, 0xDE, 0x75, 0xDE, 0x55, 0xD5, 0xF3, 
+0xD5, 0xF4, 0xC5, 0x71, 0xC5, 0x71, 0xC5, 0xB2, 
+0xCD, 0xD3, 0xD6, 0x34, 0xBD, 0x51, 0xD6, 0x14, 
+0xDE, 0x34, 0xDE, 0x75, 0xDE, 0x54, 0xCD, 0x92, 
+0xC5, 0x71, 0xCD, 0xB2, 0xDE, 0x35, 0xE6, 0x76, 
+0xE6, 0x96, 0xDE, 0x55, 0xEE, 0x96, 0xC5, 0x51, 
+0x9C, 0x4D, 0xA4, 0x8F, 0xAD, 0x11, 0xA4, 0xF1, 
+0x9C, 0x8F, 0x94, 0x4E, 0x8C, 0x0E, 0x83, 0xED, 
+0x83, 0xED, 0x83, 0xCD, 0x7B, 0x8C, 0x41, 0xE6, 
+0x39, 0xC6, 0x31, 0x85, 0x31, 0x85, 0x31, 0x85, 
+0x4A, 0x48, 0x5A, 0xCA, 0x73, 0xAE, 0x94, 0xB3, 
+0xBE, 0x18, 0xC6, 0x3A, 0xB5, 0x97, 0xCE, 0x7A, 
+0x7B, 0xCF, 0x4A, 0x49, 0xA4, 0xF2, 0x9C, 0xB0, 
+0x9C, 0x8F, 0x9C, 0x6E, 0x8B, 0xEC, 0x7B, 0x4A, 
+0x7B, 0x8B, 0x8B, 0xEC, 0x83, 0xAB, 0x83, 0xCC, 
+0x7B, 0x6B, 0x7B, 0x6A, 0x73, 0x09, 0x83, 0x6A, 
+0x8B, 0xAB, 0x8B, 0xCB, 0x94, 0x0C, 0xA4, 0x8E, 
+0xBD, 0x30, 0xD5, 0xD3, 0xC5, 0x51, 0xBD, 0x30, 
+0xC5, 0x50, 0xD5, 0xD2, 0xD5, 0xD4, 0xEF, 0x1B, 
+0xEF, 0x3C, 0xEF, 0x5D, 0xEF, 0x1B, 0x94, 0x4F, 
+0xB5, 0x12, 0xBD, 0x31, 0xBD, 0x31, 0xBD, 0x31, 
+0xB5, 0x10, 0xBD, 0x31, 0xBD, 0x72, 0xBD, 0x52, 
+0xC5, 0x93, 0xC5, 0x92, 0xAD, 0x10, 0xAC, 0xF0, 
+0x62, 0xC9, 0x31, 0xA6, 0x42, 0x07, 0x73, 0x8D, 
+0x83, 0xEF, 0x52, 0x49, 0x29, 0x24, 0x5A, 0x69, 
+0x83, 0xAE, 0x83, 0x8E, 0x94, 0x51, 0x83, 0xEF, 
+0x73, 0x6E, 0x6B, 0x4D, 0xA4, 0xF4, 0xD6, 0x79, 
+0x8C, 0x31, 0x41, 0xE8, 0x5A, 0xCB, 0x8C, 0x31, 
+0xB5, 0x76, 0xDE, 0xBA, 0xE6, 0xFB, 0xE6, 0xFC, 
+0xD6, 0x59, 0xF7, 0x5C, 0xDE, 0x37, 0xA4, 0x6F, 
+0x94, 0x0D, 0xA4, 0xB0, 0x8C, 0x0F, 0x6B, 0x4C, 
+0x84, 0x10, 0x94, 0x92, 0xC6, 0x18, 0xC5, 0xF7, 
+0x5A, 0xCA, 0x39, 0xC6, 0x39, 0xE6, 0x39, 0xC6, 
+0x42, 0x07, 0x39, 0xC6, 0x39, 0xC6, 0x42, 0x07, 
+0x42, 0x08, 0x42, 0x29, 0x4A, 0x49, 0x5A, 0xCB, 
+0x63, 0x2D, 0x52, 0x8A, 0x39, 0xE8, 0x31, 0x86, 
+0x39, 0xE7, 0x5A, 0xCB, 0x84, 0x10, 0xAD, 0x34, 
+0xB5, 0x53, 0xA4, 0xD1, 0xA5, 0x12, 0xCE, 0x15, 
+0xDE, 0x97, 0xA4, 0xF0, 0xBD, 0x93, 0xC5, 0xB4, 
+0xBD, 0x73, 0x9C, 0xB0, 0xB5, 0x52, 0xB5, 0x52, 
+0xBD, 0x73, 0xB5, 0x52, 0xB5, 0x52, 0xAC, 0xF1, 
+0xBD, 0x94, 0xBD, 0xB4, 0xBD, 0x73, 0xB5, 0x52, 
+0xAD, 0x32, 0xA4, 0xD0, 0xB5, 0x32, 0xB5, 0x52, 
+0xB5, 0x52, 0xBD, 0x93, 0xBD, 0xB4, 0xBD, 0x94, 
+0xA4, 0xD0, 0x9C, 0xB0, 0xA4, 0xF1, 0xCD, 0xF4, 
+0xD6, 0x34, 0xD6, 0x34, 0xD6, 0x14, 0xD6, 0x35, 
+0xD6, 0x35, 0xC5, 0xD4, 0xB5, 0x73, 0xC5, 0xD5, 
+0xD6, 0x77, 0xD6, 0x56, 0xCD, 0xD4, 0xBD, 0x93, 
+0xBD, 0x52, 0xBD, 0x51, 0xC5, 0xB3, 0xB5, 0x53, 
+0xBD, 0xB5, 0xB5, 0x73, 0x9C, 0xD1, 0x9C, 0x90, 
+0x83, 0xED, 0xB5, 0x32, 0x83, 0xCC, 0xA4, 0xB0, 
+0xB5, 0x31, 0xAD, 0x11, 0xAC, 0xF0, 0xAC, 0xF0, 
+0xA4, 0xB0, 0xA4, 0x8F, 0x8B, 0xEC, 0x8B, 0xEC, 
+0xA4, 0xAF, 0xB5, 0x31, 0x9C, 0x8F, 0x94, 0x6E, 
+0x94, 0x4F, 0x9C, 0x6F, 0xA4, 0xB0, 0xBD, 0x72, 
+0xC5, 0xB3, 0xCE, 0x14, 0xCE, 0x14, 0xC5, 0x93, 
+0xAD, 0x32, 0x8B, 0xED, 0x94, 0x2E, 0xB5, 0x73, 
+0xB5, 0x73, 0xAD, 0x11, 0xA4, 0xF1, 0xB5, 0x33, 
+0xC5, 0xD5, 0xBD, 0x94, 0xAD, 0x12, 0xB5, 0x53, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xC5, 0xB4, 0xC5, 0xD4, 
+0xBD, 0xD4, 0xC5, 0xF5, 0xC5, 0xD5, 0xCD, 0xF5, 
+0xBD, 0xB4, 0x62, 0xC9, 0x41, 0xE7, 0x39, 0xE7, 
+0x39, 0xE6, 0x39, 0xE6, 0x4A, 0x48, 0x5A, 0xAA, 
+0x73, 0x6C, 0x6B, 0x2C, 0x4A, 0x47, 0x73, 0xEC, 
+0x7C, 0xAB, 0x74, 0x48, 0x53, 0x05, 0x6B, 0xC9, 
+0x53, 0x07, 0x7C, 0x0B, 0xBD, 0x73, 0xAC, 0xF2, 
+0xA4, 0xD2, 0xA4, 0xF2, 0xA4, 0xB1, 0xA4, 0xD1, 
+0x9C, 0xB1, 0x9C, 0xD1, 0x9C, 0xD1, 0x9C, 0x91, 
+0x9C, 0xD1, 0x9C, 0xB1, 0x9C, 0xB1, 0x8C, 0x2F, 
+0x94, 0x4F, 0xA5, 0x12, 0x94, 0x50, 0x9C, 0x90, 
+0xAD, 0x32, 0xCD, 0xD4, 0xCD, 0xB4, 0xCD, 0xB4, 
+0xC5, 0x73, 0xBD, 0x32, 0xC5, 0x94, 0xC5, 0x94, 
+0xC5, 0xB4, 0xBD, 0x73, 0xA4, 0x8F, 0x9C, 0x8F, 
+0x9C, 0x6F, 0x9C, 0x8F, 0xC5, 0x93, 0xD6, 0x36, 
+0xA5, 0x11, 0xB5, 0x72, 0xA4, 0xCF, 0x9C, 0x8E, 
+0x8C, 0x4D, 0x84, 0x0D, 0x83, 0xED, 0x94, 0x6E, 
+0x9C, 0x8F, 0xCE, 0x14, 0xAC, 0xF0, 0xAD, 0x10, 
+0xB5, 0x51, 0xAD, 0x11, 0xAD, 0x11, 0xAC, 0xD0, 
+0xD6, 0x35, 0xD6, 0x15, 0xDE, 0x55, 0xE6, 0x75, 
+0xAC, 0xAE, 0xD6, 0x13, 0xD6, 0x34, 0xCD, 0xD3, 
+0xC5, 0x71, 0xCD, 0xD2, 0xD6, 0x13, 0xDE, 0x76, 
+0xD5, 0xF4, 0xCD, 0xB3, 0xC5, 0xB3, 0xD6, 0x35, 
+0xDE, 0x34, 0xE6, 0x75, 0xD5, 0xF3, 0xC5, 0x51, 
+0xBD, 0x10, 0xC5, 0x51, 0xCD, 0xD3, 0xD6, 0x14, 
+0xDE, 0x35, 0xE6, 0x55, 0xE6, 0x55, 0xC5, 0x31, 
+0x9C, 0x4D, 0x9C, 0x6E, 0xB5, 0x52, 0xAD, 0x32, 
+0xAD, 0x11, 0xB5, 0x31, 0xB5, 0x52, 0xBD, 0x92, 
+0xCD, 0xF3, 0xCD, 0xF3, 0xD6, 0x14, 0x8C, 0x0D, 
+0x42, 0x06, 0x31, 0xA5, 0x31, 0x85, 0x31, 0x85, 
+0x39, 0xE7, 0x42, 0x28, 0x5A, 0xCA, 0x63, 0x0C, 
+0x9C, 0xF3, 0xAD, 0x96, 0xAD, 0x76, 0xB5, 0x97, 
+0x7B, 0xCF, 0x7B, 0xCF, 0xCE, 0x59, 0xBD, 0xD6, 
+0x94, 0x70, 0x94, 0x4F, 0x94, 0x4F, 0x83, 0xAC, 
+0x8C, 0x0D, 0xB5, 0x73, 0xAD, 0x11, 0xA4, 0xD0, 
+0x94, 0x2E, 0xA4, 0x8F, 0x8C, 0x0D, 0x9C, 0x2E, 
+0x94, 0x2D, 0x8C, 0x0C, 0x94, 0x4D, 0x8C, 0x0C, 
+0x8B, 0xEC, 0x9C, 0x4D, 0xA4, 0x8E, 0xB4, 0xCE, 
+0xC5, 0x50, 0xEE, 0x95, 0xE6, 0x35, 0xBD, 0x95, 
+0xC5, 0xF8, 0xDE, 0xFB, 0xDE, 0xBB, 0xD6, 0x79, 
+0xD6, 0x99, 0xB5, 0x74, 0x9C, 0xD1, 0x7B, 0xAC, 
+0x94, 0x6E, 0xB5, 0x52, 0xBD, 0x72, 0xAD, 0x11, 
+0xBD, 0x93, 0xC5, 0x93, 0xAC, 0xEF, 0xBD, 0x51, 
+0x83, 0xAC, 0x31, 0x65, 0x62, 0xEB, 0x6B, 0x2C, 
+0x63, 0x0B, 0x52, 0x69, 0x29, 0x45, 0x31, 0x45, 
+0x52, 0x48, 0x6B, 0x0B, 0x83, 0xAE, 0x7B, 0x8E, 
+0x63, 0x0B, 0x39, 0xC7, 0x83, 0xCF, 0xBD, 0x96, 
+0xBD, 0xB7, 0xAD, 0x55, 0x73, 0x8E, 0x6B, 0x4D, 
+0xAD, 0x35, 0xE7, 0x1C, 0xE7, 0x1C, 0xE6, 0xFC, 
+0xEF, 0x1C, 0xDE, 0x7A, 0xC5, 0xD6, 0xA4, 0x91, 
+0xB5, 0x12, 0x94, 0x2E, 0x94, 0x0E, 0x8B, 0xED, 
+0x7B, 0x6C, 0x62, 0xCA, 0x73, 0x6E, 0x8C, 0x30, 
+0x5A, 0xAA, 0x4A, 0x48, 0x42, 0x28, 0x42, 0x07, 
+0x39, 0xE7, 0x39, 0xE7, 0x42, 0x07, 0x4A, 0x49, 
+0x4A, 0x69, 0x52, 0x8A, 0x4A, 0x6A, 0x52, 0x8A, 
+0x52, 0x8A, 0x4A, 0x69, 0x39, 0xE8, 0x29, 0x45, 
+0x39, 0xC7, 0x52, 0x89, 0x5A, 0xAA, 0x52, 0x69, 
+0x8C, 0x30, 0xAD, 0x32, 0xC5, 0xD5, 0xDE, 0x77, 
+0xDE, 0x97, 0xAC, 0xF0, 0xC5, 0xD4, 0xD6, 0x35, 
+0xBD, 0x72, 0xB5, 0x52, 0xB5, 0x52, 0xB5, 0x32, 
+0xAD, 0x11, 0xA4, 0xD0, 0xB5, 0x52, 0xAC, 0xF1, 
+0xBD, 0x73, 0xC5, 0xB4, 0xBD, 0x93, 0xB5, 0x52, 
+0xB5, 0x32, 0xAD, 0x11, 0xB5, 0x31, 0xB5, 0x52, 
+0xB5, 0x73, 0xBD, 0x93, 0xCE, 0x36, 0xBD, 0xB4, 
+0xA4, 0xB0, 0xA4, 0xD1, 0xBD, 0x73, 0xD6, 0x35, 
+0xDE, 0x54, 0xD6, 0x14, 0xD5, 0xF3, 0xD6, 0x14, 
+0xCD, 0xF4, 0xCE, 0x14, 0xAD, 0x32, 0xAD, 0x33, 
+0xCE, 0x15, 0xD6, 0x35, 0xBD, 0x72, 0xAC, 0xF0, 
+0xBD, 0x72, 0xB5, 0x10, 0xB5, 0x72, 0x94, 0x2E, 
+0xAD, 0x12, 0xA4, 0xF2, 0x9C, 0xD1, 0x94, 0x70, 
+0x8C, 0x0E, 0xB5, 0x32, 0x8C, 0x0D, 0xB5, 0x32, 
+0xB5, 0x31, 0xC5, 0x93, 0xBD, 0x93, 0xC5, 0xD4, 
+0xC5, 0xB3, 0xA4, 0xD0, 0x94, 0x2D, 0x94, 0x2D, 
+0x94, 0x4E, 0x9C, 0x8F, 0xA4, 0xB0, 0x8C, 0x0D, 
+0x8C, 0x0D, 0x8B, 0xED, 0x9C, 0x6F, 0xA4, 0xF0, 
+0xAD, 0x10, 0xBD, 0xB3, 0xC5, 0xD3, 0xC5, 0xB3, 
+0xAD, 0x11, 0xAC, 0xF2, 0xA4, 0xF1, 0xCE, 0x15, 
+0xDE, 0x97, 0xDE, 0x77, 0xD6, 0x56, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xC5, 0xD5, 0xCE, 0x16, 0xD6, 0x56, 
+0xDE, 0x97, 0xD6, 0x56, 0xCE, 0x35, 0xD6, 0x36, 
+0xCE, 0x15, 0xBD, 0x94, 0xCE, 0x15, 0xDE, 0x76, 
+0xDE, 0x97, 0xE6, 0xD7, 0xEE, 0xF7, 0xF6, 0xF7, 
+0xF7, 0x38, 0xBD, 0xB3, 0x6B, 0x4B, 0x41, 0xE6, 
+0x31, 0x85, 0x31, 0xA5, 0x39, 0xC6, 0x42, 0x27, 
+0x4A, 0x28, 0x31, 0xA6, 0x4A, 0x48, 0x6B, 0xAA, 
+0x7C, 0xAB, 0x7C, 0xCB, 0x5B, 0x67, 0x3A, 0x04, 
+0x84, 0x4C, 0xA5, 0x0F, 0x8C, 0x0E, 0xA4, 0xB1, 
+0xA4, 0xB1, 0xAD, 0x12, 0xBD, 0x74, 0xAD, 0x12, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xB5, 0x33, 0xBD, 0xB4, 
+0xBD, 0x93, 0xBD, 0xB4, 0xB5, 0x52, 0xB5, 0x53, 
+0xC5, 0xB4, 0xBD, 0x53, 0xBD, 0x74, 0xB5, 0x53, 
+0xB5, 0x32, 0xC5, 0x94, 0xBD, 0x53, 0xBD, 0x32, 
+0xBD, 0x73, 0xBD, 0x53, 0xB5, 0x53, 0xB5, 0x32, 
+0xAD, 0x32, 0xAC, 0xF1, 0xAD, 0x12, 0xAC, 0xF2, 
+0xA4, 0xF2, 0xA4, 0xF2, 0xA4, 0xB1, 0x9C, 0x90, 
+0x7B, 0xCC, 0x9C, 0xD0, 0xA4, 0xAF, 0x9C, 0x6E, 
+0x7B, 0xAB, 0x7B, 0x8B, 0x83, 0xEC, 0x8C, 0x2E, 
+0x94, 0x4E, 0xAC, 0xF0, 0xA4, 0xAE, 0x8C, 0x0C, 
+0x83, 0xAB, 0x83, 0xCB, 0x8C, 0x0C, 0xB5, 0x31, 
+0xDE, 0x76, 0xDE, 0x56, 0xE6, 0xB7, 0xEE, 0xB7, 
+0xB4, 0xCF, 0xDE, 0x34, 0xD6, 0x14, 0xCD, 0xB2, 
+0xCD, 0xD3, 0xD5, 0xF3, 0xD6, 0x14, 0xDE, 0x76, 
+0xD5, 0xF4, 0xDE, 0x56, 0xDE, 0x76, 0xDE, 0x75, 
+0xDE, 0x55, 0xDE, 0x34, 0xC5, 0x71, 0xCD, 0x92, 
+0xCD, 0x72, 0xC5, 0x51, 0xCD, 0xB2, 0xCD, 0xD3, 
+0xD5, 0xD3, 0xC5, 0x51, 0xBC, 0xEF, 0xB4, 0x8E, 
+0x9C, 0x4D, 0xAD, 0x11, 0xC5, 0xB3, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xCD, 0xD3, 0xCD, 0xD3, 0xCD, 0xB3, 
+0xD5, 0xF3, 0xCD, 0xD3, 0xCD, 0xD2, 0xD6, 0x14, 
+0xCD, 0xF4, 0x9C, 0x6E, 0x6B, 0x2A, 0x41, 0xE6, 
+0x39, 0xE6, 0x52, 0xA9, 0x52, 0x8A, 0x52, 0x8A, 
+0x63, 0x4C, 0x7B, 0xCF, 0x7B, 0xEF, 0x8C, 0x51, 
+0x8C, 0x51, 0xAD, 0x76, 0xC6, 0x18, 0xE7, 0x3C, 
+0xC6, 0x18, 0xA4, 0xF3, 0x9C, 0x70, 0x7B, 0x8C, 
+0x83, 0xEC, 0xBD, 0xB3, 0xBD, 0xB4, 0xAD, 0x32, 
+0x94, 0x4E, 0x94, 0x4E, 0x8B, 0xED, 0x9C, 0x8F, 
+0x9C, 0x8F, 0xA4, 0xAF, 0xA4, 0xD0, 0x9C, 0x6E, 
+0x8B, 0xED, 0x94, 0x0D, 0xA4, 0x6E, 0xB4, 0xEF, 
+0xB4, 0xCE, 0xCD, 0x91, 0xDE, 0x14, 0xAC, 0xB0, 
+0x84, 0x10, 0xC6, 0x38, 0xB5, 0x76, 0xAD, 0x55, 
+0xF7, 0x7D, 0xDE, 0xBA, 0xB5, 0x54, 0x8C, 0x50, 
+0x7B, 0xCD, 0x8C, 0x4F, 0x84, 0x0E, 0x84, 0x0E, 
+0xB5, 0x93, 0x9C, 0x8F, 0xA4, 0xAE, 0xA4, 0xAF, 
+0x94, 0x2E, 0x5A, 0x89, 0x5A, 0xEB, 0x5A, 0xAA, 
+0x5A, 0xCA, 0x4A, 0x28, 0x52, 0x8A, 0x52, 0x48, 
+0x52, 0x28, 0x41, 0xE7, 0x62, 0xEA, 0x52, 0x89, 
+0x52, 0x69, 0x7B, 0x6D, 0x73, 0x6D, 0x9C, 0x72, 
+0xBD, 0x96, 0xA4, 0xF3, 0xAD, 0x35, 0xA5, 0x14, 
+0xC6, 0x38, 0xE6, 0xFC, 0xC5, 0xD7, 0xC5, 0xF8, 
+0xD6, 0x79, 0xDE, 0xBA, 0x9C, 0xB2, 0x7B, 0x4D, 
+0xB5, 0x13, 0xAC, 0xD1, 0xAC, 0xF0, 0xB5, 0x31, 
+0xB5, 0x31, 0xAD, 0x11, 0x8B, 0xEE, 0x62, 0xCA, 
+0x4A, 0x48, 0x63, 0x0B, 0x4A, 0x68, 0x42, 0x48, 
+0x42, 0x07, 0x42, 0x48, 0x42, 0x28, 0x52, 0x89, 
+0x52, 0x8A, 0x52, 0xAA, 0x52, 0x8A, 0x63, 0x0C, 
+0x5A, 0xCB, 0x52, 0x8A, 0x42, 0x08, 0x31, 0x86, 
+0x29, 0x65, 0x39, 0xC6, 0x39, 0xE7, 0x83, 0xEF, 
+0x9C, 0x90, 0xAC, 0xF1, 0xCE, 0x16, 0xD6, 0x56, 
+0xCE, 0x15, 0xAC, 0xF0, 0xC5, 0xB4, 0xD6, 0x35, 
+0xCD, 0xF4, 0xC5, 0xF4, 0xC5, 0xB4, 0xCD, 0xF5, 
+0xBD, 0xB3, 0xBD, 0x72, 0xC5, 0xD4, 0xC5, 0xB3, 
+0xCE, 0x15, 0xD6, 0x56, 0xCE, 0x35, 0xC5, 0xD4, 
+0xBD, 0xB3, 0xBD, 0x93, 0xC5, 0xB3, 0xBD, 0x93, 
+0xC5, 0xB4, 0xC5, 0xD4, 0xC5, 0xF4, 0xBD, 0xB4, 
+0xA4, 0xD0, 0xAD, 0x32, 0xC5, 0xF4, 0xDE, 0x55, 
+0xDE, 0x75, 0xDE, 0x14, 0xDE, 0x14, 0xD6, 0x14, 
+0xCD, 0xD3, 0xCD, 0xF4, 0xB5, 0x52, 0xB5, 0x73, 
+0xD6, 0x36, 0xD6, 0x35, 0xAC, 0xD0, 0xAC, 0xCF, 
+0xAC, 0xF0, 0xA4, 0xCF, 0xB5, 0x51, 0x8C, 0x0E, 
+0x94, 0x4F, 0x94, 0x6F, 0x8C, 0x4F, 0x8C, 0x2E, 
+0x94, 0x70, 0xB5, 0x53, 0x8B, 0xED, 0xBD, 0x93, 
+0xBD, 0x93, 0xBD, 0xB3, 0xBD, 0x93, 0xBD, 0x93, 
+0xC5, 0xB3, 0x9C, 0x8F, 0xBD, 0x72, 0xA4, 0xF0, 
+0xA4, 0xAF, 0x8C, 0x0D, 0x94, 0x4E, 0xA4, 0xB0, 
+0xAD, 0x11, 0x8C, 0x0D, 0x9C, 0x8F, 0x9C, 0xAF, 
+0x94, 0x4E, 0x94, 0x4E, 0x94, 0x6E, 0xA4, 0xCF, 
+0xA4, 0xD0, 0xAD, 0x33, 0xB5, 0x73, 0xD6, 0x56, 
+0xDE, 0x96, 0xDE, 0xB7, 0xDE, 0x97, 0xD6, 0x77, 
+0xD6, 0x77, 0xD6, 0x77, 0xDE, 0x77, 0xE6, 0xB7, 
+0xDE, 0xB7, 0xDE, 0x97, 0xDE, 0x96, 0xDE, 0x96, 
+0xDE, 0x96, 0xD6, 0x56, 0xD6, 0x56, 0xE6, 0xB7, 
+0xE6, 0xD7, 0xE6, 0xD6, 0xE6, 0xB6, 0xEE, 0xD6, 
+0xEE, 0xF7, 0xCE, 0x14, 0xAD, 0x52, 0x84, 0x0E, 
+0x31, 0xA5, 0x31, 0xA6, 0x39, 0xE6, 0x31, 0xA5, 
+0x39, 0xC6, 0x42, 0x28, 0x4A, 0x48, 0x63, 0x4A, 
+0x53, 0x27, 0x74, 0x8A, 0x6C, 0x49, 0x5B, 0x48, 
+0x4A, 0x86, 0x8C, 0x6C, 0x73, 0x4A, 0x6B, 0x0B, 
+0xA4, 0xD2, 0xA4, 0xB1, 0xB5, 0x53, 0xA4, 0xD1, 
+0xBD, 0x93, 0xDE, 0xB7, 0xA5, 0x31, 0xA5, 0x50, 
+0x8C, 0xCD, 0x94, 0xED, 0xA5, 0x4F, 0xB5, 0x70, 
+0xCE, 0x14, 0xC5, 0xB3, 0xBD, 0x73, 0xBD, 0x52, 
+0xB5, 0x32, 0xB5, 0x32, 0xAD, 0x11, 0xB5, 0x12, 
+0xB5, 0x12, 0xA4, 0xB0, 0x94, 0x2E, 0xAC, 0xF1, 
+0xB5, 0x12, 0xAC, 0xB0, 0xAC, 0xF1, 0xB5, 0x12, 
+0xAC, 0xF2, 0xAC, 0xF2, 0xAC, 0xF2, 0xB5, 0x33, 
+0x8C, 0xB1, 0x94, 0xD1, 0x8C, 0x4E, 0x8C, 0x0C, 
+0x8B, 0xEC, 0x8B, 0xEC, 0x8B, 0xEC, 0x83, 0xCB, 
+0x83, 0xAB, 0x83, 0xAB, 0x83, 0xAB, 0x83, 0x8B, 
+0x7B, 0x6A, 0x7B, 0x6A, 0x83, 0xAB, 0x8B, 0xEB, 
+0x9C, 0x4D, 0x9C, 0x6E, 0xA4, 0xAF, 0xA4, 0x8E, 
+0x9C, 0x4D, 0xC5, 0x71, 0xBD, 0x30, 0xB5, 0x10, 
+0xAC, 0xEF, 0xAC, 0xEF, 0xAC, 0xAE, 0xBD, 0x31, 
+0xC5, 0x92, 0xBD, 0x51, 0xBD, 0x30, 0xC5, 0x72, 
+0xD5, 0xD3, 0xDE, 0x35, 0xDE, 0x14, 0xD5, 0xD3, 
+0xE6, 0x55, 0xE6, 0x75, 0xEE, 0x76, 0xE6, 0x75, 
+0xE6, 0x55, 0xD5, 0xB3, 0xE6, 0x14, 0xC5, 0x51, 
+0xA4, 0x8E, 0xC5, 0xD3, 0xC5, 0xD3, 0xC5, 0x93, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xB5, 0x10, 0xBD, 0x30, 
+0xCD, 0xB2, 0xCD, 0xB2, 0xD5, 0xF3, 0xDE, 0x14, 
+0xE6, 0x55, 0xD6, 0x14, 0xD5, 0xF4, 0xAC, 0xF0, 
+0x6B, 0x09, 0x52, 0x89, 0x39, 0xE7, 0x39, 0xE7, 
+0x42, 0x27, 0x52, 0xAA, 0x63, 0x2C, 0x6B, 0x6D, 
+0x7B, 0xAF, 0xAD, 0x55, 0xBD, 0xF8, 0xCE, 0x7A, 
+0xD6, 0xBA, 0xDE, 0xDB, 0xB5, 0x75, 0x7B, 0xAD, 
+0x7B, 0x8C, 0xAD, 0x32, 0xBD, 0xB4, 0xAC, 0xF1, 
+0x8B, 0xED, 0x83, 0xCC, 0x8C, 0x0D, 0x9C, 0x8F, 
+0xA4, 0xAF, 0x9C, 0x8F, 0xA4, 0xD0, 0xB5, 0x12, 
+0xB5, 0x32, 0xB5, 0x11, 0xA4, 0x8E, 0xB4, 0xEF, 
+0xBD, 0x0F, 0xD5, 0xF3, 0xD5, 0xF3, 0xCD, 0xB3, 
+0x73, 0x4C, 0x8C, 0x51, 0x83, 0xF0, 0x9C, 0xB3, 
+0xDE, 0xBB, 0xD6, 0xBA, 0xA5, 0x13, 0xA5, 0x13, 
+0x8C, 0x70, 0x84, 0x2E, 0x94, 0x90, 0xAD, 0x53, 
+0xBD, 0xD4, 0xAD, 0x10, 0xAC, 0xCF, 0xB5, 0x52, 
+0xB5, 0x52, 0x9C, 0x90, 0x42, 0x07, 0x5A, 0xAA, 
+0x5A, 0xAA, 0x39, 0xC6, 0x52, 0x69, 0x7B, 0x8D, 
+0x83, 0xAE, 0x39, 0xA6, 0x29, 0x65, 0x31, 0x85, 
+0x62, 0xEB, 0x83, 0xEF, 0x94, 0x30, 0x94, 0x51, 
+0x8C, 0x0F, 0x73, 0x6E, 0x9C, 0xB3, 0xC6, 0x17, 
+0xC5, 0xF8, 0xB5, 0x96, 0xC5, 0xD7, 0xE6, 0xFC, 
+0xEF, 0x3C, 0xFF, 0xBE, 0xF7, 0x5C, 0xAC, 0xD3, 
+0x94, 0x0F, 0x83, 0xAD, 0x94, 0x2E, 0x94, 0x4E, 
+0x9C, 0x6F, 0x94, 0x4E, 0xA4, 0xAF, 0xB5, 0x52, 
+0x5A, 0xAA, 0x7B, 0xEE, 0x52, 0xAA, 0x4A, 0x68, 
+0x42, 0x27, 0x4A, 0x89, 0x4A, 0x89, 0x42, 0x48, 
+0x42, 0x28, 0x4A, 0x48, 0x42, 0x28, 0x4A, 0x49, 
+0x4A, 0x69, 0x52, 0x8A, 0x42, 0x29, 0x42, 0x08, 
+0x42, 0x08, 0x31, 0x86, 0x63, 0x0C, 0x9C, 0x91, 
+0x9C, 0x6F, 0x9C, 0x6F, 0x94, 0x2E, 0x8C, 0x0E, 
+0x9C, 0x4F, 0xA4, 0xD0, 0xA4, 0xB0, 0x9C, 0x8F, 
+0x9C, 0x4E, 0x94, 0x4E, 0x8B, 0xED, 0x8C, 0x0E, 
+0x94, 0x2E, 0x8C, 0x0E, 0x94, 0x4E, 0xA4, 0xD1, 
+0xB5, 0x32, 0xB5, 0x52, 0xBD, 0x93, 0xBD, 0x93, 
+0xBD, 0x73, 0xC5, 0xD4, 0xCE, 0x15, 0xCE, 0x15, 
+0xD6, 0x15, 0xCD, 0xF5, 0xC5, 0xD4, 0xC5, 0xD4, 
+0x9C, 0xB0, 0xA4, 0xD0, 0xB5, 0x52, 0xC5, 0xD3, 
+0xD6, 0x34, 0xDE, 0x54, 0xDE, 0x55, 0xDE, 0x54, 
+0xDE, 0x14, 0xCD, 0xD3, 0xAD, 0x11, 0xAD, 0x32, 
+0xD6, 0x35, 0xD6, 0x14, 0xB5, 0x10, 0xB5, 0x31, 
+0xB5, 0x31, 0xB5, 0x10, 0xAD, 0x11, 0x8C, 0x0D, 
+0x83, 0xEE, 0x83, 0xEE, 0x83, 0xEE, 0x7B, 0xAD, 
+0xA4, 0xF1, 0xB5, 0x32, 0x8C, 0x0D, 0xB5, 0x52, 
+0xB5, 0x72, 0xBD, 0xB3, 0xBD, 0x93, 0xBD, 0x93, 
+0xCD, 0xF4, 0xBD, 0x93, 0xAD, 0x11, 0xC5, 0xD4, 
+0xBD, 0x93, 0xA4, 0xD0, 0xA4, 0xF1, 0xBD, 0xB3, 
+0xBD, 0x93, 0xB5, 0x52, 0xAD, 0x32, 0x9C, 0x8F, 
+0x94, 0x4E, 0x8C, 0x2E, 0x8C, 0x2D, 0x94, 0x2E, 
+0x9C, 0xB0, 0xB5, 0x53, 0xB5, 0x33, 0xCE, 0x15, 
+0xDE, 0x76, 0xDE, 0x96, 0xDE, 0x97, 0xDE, 0x97, 
+0xDE, 0x97, 0xDE, 0x97, 0xE6, 0xB7, 0xDE, 0x76, 
+0xE6, 0xD7, 0xDE, 0xB6, 0xDE, 0x96, 0xDE, 0x96, 
+0xDE, 0x76, 0xDE, 0xB6, 0xDE, 0xB7, 0xDE, 0xB6, 
+0xDE, 0x96, 0xE6, 0xB6, 0xE6, 0x96, 0xE6, 0x95, 
+0xE6, 0xB6, 0xC5, 0xD4, 0xAD, 0x12, 0xC5, 0xD4, 
+0xA4, 0xF1, 0x39, 0xA5, 0x39, 0xA6, 0x39, 0xC6, 
+0x39, 0xC6, 0x31, 0x85, 0x31, 0xA5, 0x52, 0x88, 
+0x4A, 0x86, 0x8D, 0x0E, 0x7C, 0xCB, 0x74, 0x8B, 
+0x7C, 0x8C, 0x7C, 0x6C, 0x84, 0x4C, 0x5A, 0xE9, 
+0x52, 0x89, 0x8C, 0x0E, 0xAC, 0xF2, 0xB5, 0x53, 
+0xE6, 0xF8, 0xE6, 0xD7, 0xA5, 0x90, 0x8D, 0x4D, 
+0x7C, 0xAA, 0x6C, 0x48, 0x74, 0x68, 0x95, 0x0B, 
+0xAD, 0xAE, 0xAD, 0x30, 0xB5, 0x72, 0xC5, 0xB3, 
+0xBD, 0x52, 0xA4, 0xB0, 0xBD, 0x52, 0xC5, 0x93, 
+0xBD, 0x52, 0xA4, 0xB0, 0x9C, 0x6F, 0xA4, 0x8F, 
+0x94, 0x0D, 0x8B, 0xAC, 0x83, 0x8B, 0xB4, 0xF1, 
+0xC5, 0x73, 0xC5, 0x73, 0xC5, 0xB4, 0xAC, 0xF2, 
+0x8C, 0xB1, 0x73, 0xCE, 0x5B, 0x09, 0x83, 0xEC, 
+0x94, 0x4E, 0x94, 0x2D, 0x94, 0x2D, 0x9C, 0x6E, 
+0x9C, 0x6E, 0x9C, 0x4E, 0x9C, 0x8F, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0x8E, 0xA4, 0x8E, 
+0xA4, 0xAE, 0xAC, 0xCF, 0xA4, 0x8E, 0xAC, 0xAF, 
+0xAC, 0xAE, 0xAC, 0xAE, 0xA4, 0x8E, 0xA4, 0x8E, 
+0xA4, 0x8E, 0xA4, 0x6E, 0x9C, 0x6D, 0x9C, 0x4D, 
+0x9C, 0x6D, 0xA4, 0x6E, 0xA4, 0x8E, 0xA4, 0x8E, 
+0x9C, 0x2D, 0x9C, 0x4D, 0xAC, 0x8E, 0xAC, 0x8E, 
+0xA4, 0x4D, 0xA4, 0x6E, 0xBD, 0x10, 0xC5, 0x51, 
+0xCD, 0x92, 0xD5, 0xB3, 0xDD, 0xF4, 0xBD, 0x10, 
+0xA4, 0x8D, 0xC5, 0x92, 0xC5, 0x92, 0xCD, 0xD3, 
+0xCD, 0xF4, 0xCD, 0xB3, 0xAC, 0xAE, 0xBD, 0x50, 
+0xD5, 0xF3, 0xD5, 0xD3, 0xDE, 0x14, 0xDE, 0x14, 
+0xDE, 0x13, 0xD5, 0xF3, 0xD6, 0x13, 0xDE, 0x34, 
+0xD5, 0xF3, 0x9C, 0x6E, 0x4A, 0x27, 0x31, 0xA5, 
+0x39, 0xC6, 0x42, 0x28, 0x4A, 0x48, 0x52, 0x8A, 
+0x63, 0x0C, 0x84, 0x30, 0x9C, 0xF4, 0xAD, 0x76, 
+0xC6, 0x19, 0xD6, 0x9B, 0xE7, 0x1C, 0xDE, 0xDB, 
+0xC6, 0x18, 0xAD, 0x13, 0xB5, 0x73, 0x9C, 0xB0, 
+0x7B, 0x8C, 0x7B, 0x8C, 0x8C, 0x0E, 0x9C, 0x4E, 
+0xA4, 0xAF, 0x9C, 0x6E, 0x9C, 0x8F, 0xBD, 0x73, 
+0xC5, 0x93, 0xC5, 0xB3, 0xB4, 0xF0, 0xAC, 0xCE, 
+0xAC, 0xCE, 0xD5, 0xF3, 0xDD, 0xF3, 0xE6, 0x55, 
+0xA4, 0x90, 0x5A, 0x8A, 0x9C, 0xD3, 0xCE, 0x59, 
+0xEF, 0x3D, 0xE7, 0x3D, 0xCE, 0x59, 0xB5, 0x95, 
+0xB5, 0x74, 0x9C, 0xF2, 0x94, 0xB1, 0xAD, 0x33, 
+0xAD, 0x52, 0xA4, 0x8E, 0xAC, 0xCF, 0xBD, 0x72, 
+0xB5, 0x31, 0xBD, 0x72, 0x8C, 0x0E, 0x4A, 0x28, 
+0x4A, 0x28, 0x29, 0x44, 0x31, 0x65, 0x52, 0x69, 
+0x83, 0xAD, 0x52, 0x69, 0x52, 0x69, 0x31, 0x65, 
+0x39, 0xC6, 0x4A, 0x28, 0x73, 0x6C, 0x73, 0x6D, 
+0x52, 0x69, 0x73, 0x6E, 0x84, 0x30, 0x9C, 0xB2, 
+0xB5, 0x76, 0xCE, 0x59, 0xE6, 0xDB, 0xE6, 0xDB, 
+0xE6, 0xFB, 0xEF, 0x3C, 0xE6, 0xFB, 0xD6, 0x18, 
+0xA4, 0xB3, 0xCE, 0x17, 0xB5, 0x54, 0x94, 0x50, 
+0xAD, 0x12, 0xA4, 0xF1, 0xA4, 0xD0, 0xB5, 0x53, 
+0x5A, 0xAA, 0x8C, 0x50, 0x63, 0x0B, 0x4A, 0x69, 
+0x42, 0x07, 0x42, 0x07, 0x42, 0x27, 0x39, 0xE6, 
+0x42, 0x07, 0x4A, 0x48, 0x39, 0xE7, 0x39, 0xC7, 
+0x42, 0x28, 0x42, 0x28, 0x42, 0x08, 0x39, 0xC7, 
+0x39, 0xC7, 0x73, 0x6E, 0xBD, 0xB6, 0xAD, 0x33, 
+0xB5, 0x54, 0xBD, 0x94, 0xB5, 0x73, 0xAD, 0x12, 
+0xAD, 0x12, 0xB5, 0x52, 0xA4, 0xD0, 0x9C, 0x8F, 
+0x94, 0x2E, 0x9C, 0x90, 0xA4, 0xB0, 0xA4, 0xB0, 
+0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x8F, 0x9C, 0x6F, 
+0x9C, 0x6F, 0x9C, 0x6F, 0x9C, 0x8F, 0x9C, 0x8F, 
+0xA4, 0xAF, 0xA4, 0xAF, 0x9C, 0x8F, 0x9C, 0x8F, 
+0xA4, 0x90, 0x9C, 0x4F, 0x8C, 0x0E, 0x9C, 0x8F, 
+0xA4, 0xAF, 0xA4, 0xD0, 0x9C, 0x6F, 0x8C, 0x0D, 
+0x8C, 0x0D, 0x9C, 0x4E, 0x9C, 0x4D, 0x9C, 0x4D, 
+0xAC, 0xAF, 0xAC, 0xCF, 0xA4, 0xD0, 0xAC, 0xF1, 
+0xB5, 0x11, 0xB5, 0x31, 0xA4, 0x8E, 0x9C, 0x6E, 
+0xAC, 0xCF, 0xA4, 0x8E, 0x8B, 0xEC, 0x7B, 0x6B, 
+0x83, 0xCD, 0x7B, 0x8C, 0x6B, 0x4B, 0x6B, 0x2B, 
+0xAC, 0xF1, 0xB5, 0x32, 0x83, 0xED, 0x8C, 0x0E, 
+0x94, 0x4E, 0xAD, 0x11, 0x9C, 0xB0, 0x9C, 0xAF, 
+0xAD, 0x11, 0x83, 0xCC, 0x9C, 0x6F, 0xAC, 0xF1, 
+0xAD, 0x31, 0xA4, 0xB0, 0xB5, 0x52, 0xC5, 0xD4, 
+0xB5, 0x73, 0xB5, 0x73, 0xC5, 0xB4, 0x9C, 0xB0, 
+0x8C, 0x2E, 0x94, 0x6F, 0x83, 0xED, 0x83, 0xED, 
+0xA4, 0xD1, 0xAD, 0x32, 0xAD, 0x12, 0xBD, 0x72, 
+0xDE, 0x55, 0xD6, 0x55, 0xDE, 0x76, 0xDE, 0x96, 
+0xDE, 0x96, 0xDE, 0x97, 0xE6, 0x97, 0xE6, 0xB6, 
+0xE6, 0xD7, 0xE6, 0xB6, 0xE6, 0xB6, 0xDE, 0x75, 
+0xD6, 0x34, 0xDE, 0x76, 0xDE, 0xB6, 0xD6, 0x75, 
+0xD6, 0x35, 0xDE, 0x96, 0xE6, 0x96, 0xE6, 0x95, 
+0xE6, 0x96, 0xC5, 0xD4, 0xAC, 0xF1, 0xD6, 0x36, 
+0xDE, 0xB7, 0xAD, 0x32, 0x4A, 0x27, 0x39, 0xA6, 
+0x31, 0x85, 0x31, 0x65, 0x29, 0x44, 0x31, 0xA5, 
+0x73, 0xEC, 0xA5, 0xB1, 0x85, 0x2D, 0x84, 0xED, 
+0x85, 0x0D, 0x84, 0xED, 0x6C, 0x29, 0x94, 0xEE, 
+0x6B, 0x6B, 0x6A, 0xEA, 0x8B, 0xEE, 0xAC, 0xF1, 
+0xCE, 0x34, 0xD6, 0x95, 0x84, 0xAC, 0x8D, 0x2D, 
+0x95, 0x6D, 0x6C, 0x27, 0x6C, 0x47, 0x7C, 0xC9, 
+0x8D, 0x2B, 0x84, 0xAC, 0x9D, 0x0F, 0xC5, 0xD3, 
+0xCD, 0xB3, 0xC5, 0x73, 0xC5, 0x93, 0xB5, 0x11, 
+0x94, 0x0E, 0xA4, 0x6F, 0xA4, 0x6F, 0x9C, 0x2E, 
+0x8B, 0xAC, 0x83, 0x8C, 0x94, 0x0E, 0xBD, 0x32, 
+0xD5, 0xF5, 0xD5, 0xD4, 0x9C, 0x4F, 0x94, 0x50, 
+0x7B, 0xEF, 0x39, 0xE7, 0x42, 0x28, 0x4A, 0x68, 
+0x62, 0xEA, 0x6B, 0x2A, 0x83, 0xED, 0x94, 0x4E, 
+0x9C, 0x8F, 0x94, 0x4E, 0xA4, 0xD0, 0x94, 0x4E, 
+0x8C, 0x0D, 0x94, 0x2D, 0x9C, 0x6E, 0xA4, 0xAE, 
+0xD6, 0x14, 0xC5, 0xB2, 0x94, 0x2D, 0x9C, 0x6E, 
+0x8B, 0xEC, 0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xCF, 
+0xAC, 0xAF, 0xAC, 0xCF, 0xB4, 0xF0, 0xB5, 0x10, 
+0xA4, 0xAE, 0xAC, 0xCF, 0xAC, 0xCF, 0xB4, 0xEF, 
+0xB4, 0xEF, 0xB4, 0xEF, 0xA4, 0x8E, 0xA4, 0x8E, 
+0xA4, 0x8E, 0xAC, 0xCF, 0xAC, 0xCF, 0xAC, 0xAE, 
+0xAC, 0xAE, 0xAC, 0xAE, 0xB4, 0xCE, 0xB4, 0xEF, 
+0xB4, 0xEF, 0xAC, 0xCE, 0xAC, 0x8D, 0xA4, 0x8D, 
+0xA4, 0x6D, 0xA4, 0x6D, 0xA4, 0x4C, 0xA4, 0x6D, 
+0xAC, 0x8E, 0xAC, 0x8E, 0xAC, 0xCE, 0xB4, 0xEF, 
+0xB4, 0xEF, 0xBD, 0x30, 0xC5, 0x50, 0xCD, 0x71, 
+0xCD, 0x92, 0xCD, 0x92, 0xB4, 0xF0, 0x7B, 0x8B, 
+0x41, 0xE6, 0x39, 0xC6, 0x42, 0x28, 0x42, 0x07, 
+0x4A, 0x48, 0x63, 0x2C, 0x7B, 0xF0, 0x94, 0xB3, 
+0xAD, 0x56, 0xBD, 0xD8, 0xC6, 0x39, 0xDE, 0xDC, 
+0xF7, 0x7E, 0xEF, 0x3C, 0xBD, 0xB6, 0xA4, 0xB1, 
+0x73, 0x2B, 0x73, 0x4B, 0x8B, 0xED, 0x94, 0x2E, 
+0xA4, 0xD0, 0x9C, 0x8F, 0xA4, 0xB0, 0xC5, 0xD4, 
+0xD6, 0x14, 0xD6, 0x14, 0xC5, 0x71, 0xB4, 0xCF, 
+0xAC, 0xAE, 0xD5, 0xD2, 0xE6, 0x34, 0xDD, 0xF3, 
+0xCD, 0xB3, 0x5A, 0xCA, 0xA5, 0x14, 0xDE, 0xBB, 
+0xE6, 0xFC, 0xBD, 0xD8, 0xDE, 0xBB, 0xCE, 0x59, 
+0xB5, 0x75, 0xAD, 0x53, 0xA5, 0x33, 0xB5, 0x73, 
+0xB5, 0x73, 0xA4, 0x8E, 0xAC, 0xCF, 0xC5, 0xB3, 
+0xB5, 0x31, 0xBD, 0x52, 0xBD, 0x93, 0x7B, 0xAD, 
+0x31, 0x64, 0x21, 0x03, 0x18, 0xC3, 0x39, 0xA6, 
+0x62, 0xEA, 0x52, 0x69, 0x62, 0xEB, 0x6B, 0x2B, 
+0x73, 0x2B, 0x5A, 0x89, 0x4A, 0x68, 0x73, 0x6C, 
+0x83, 0xEF, 0x83, 0xEF, 0x73, 0x6D, 0x7B, 0xCF, 
+0x94, 0x72, 0x94, 0xB3, 0xBD, 0xD7, 0xD6, 0x7A, 
+0xDE, 0xBB, 0xCE, 0x39, 0xDE, 0x9A, 0xEE, 0xFC, 
+0xDE, 0x9A, 0xD6, 0x59, 0xEE, 0xFB, 0xE6, 0xDA, 
+0xAD, 0x13, 0xA4, 0xB1, 0x9C, 0x70, 0x9C, 0xB0, 
+0x5A, 0x89, 0x6B, 0x2C, 0x73, 0xAD, 0x52, 0x89, 
+0x4A, 0x48, 0x39, 0xE7, 0x39, 0xE6, 0x42, 0x28, 
+0x39, 0xE7, 0x42, 0x28, 0x42, 0x08, 0x42, 0x08, 
+0x39, 0xE7, 0x39, 0xE7, 0x39, 0xE8, 0x42, 0x07, 
+0x63, 0x2C, 0xA5, 0x34, 0xBD, 0xD7, 0xA4, 0xF2, 
+0xB5, 0x33, 0xBD, 0xB4, 0xC5, 0xF5, 0xC5, 0xB4, 
+0x9C, 0x6F, 0x73, 0x4B, 0x83, 0xAC, 0x8C, 0x0E, 
+0x8B, 0xED, 0x8B, 0xED, 0x94, 0x4F, 0x8C, 0x2E, 
+0xA4, 0xB0, 0xA4, 0xD1, 0x94, 0x6F, 0x8C, 0x2E, 
+0x8C, 0x0E, 0x94, 0x4F, 0xA4, 0xD0, 0xA4, 0xF1, 
+0xAD, 0x32, 0xBD, 0x93, 0xB5, 0x52, 0xA4, 0xF1, 
+0xAC, 0xF1, 0xA4, 0xD0, 0xAC, 0xF1, 0xA4, 0xD0, 
+0xA4, 0xB0, 0xAD, 0x11, 0xA4, 0xB0, 0xA4, 0xB0, 
+0xA4, 0xB0, 0xB5, 0x11, 0xB5, 0x32, 0xBD, 0x52, 
+0xB5, 0x11, 0xB5, 0x11, 0xA4, 0x90, 0xB4, 0xF1, 
+0xAC, 0xD0, 0xAC, 0xB0, 0xAC, 0xD0, 0xA4, 0x8F, 
+0xA4, 0x6E, 0xA4, 0x8E, 0xA4, 0x8F, 0x9C, 0x8F, 
+0xA4, 0x90, 0x94, 0x0E, 0x8C, 0x0E, 0x7B, 0xAC, 
+0x9C, 0x6F, 0xA4, 0xD0, 0x94, 0x4F, 0x8C, 0x0E, 
+0x8B, 0xED, 0x8B, 0xED, 0x8C, 0x0D, 0x83, 0xCD, 
+0x83, 0xCD, 0x7B, 0x6B, 0x83, 0xAC, 0x83, 0xCC, 
+0x83, 0xCC, 0x83, 0xCC, 0x8C, 0x0E, 0x94, 0x4E, 
+0x8C, 0x2E, 0x8C, 0x2E, 0x9C, 0x8F, 0x8C, 0x0E, 
+0x83, 0xCC, 0x83, 0xED, 0x83, 0xCD, 0x8C, 0x2E, 
+0xB5, 0x32, 0xB5, 0x73, 0xBD, 0x93, 0xD6, 0x56, 
+0xDE, 0x96, 0xE6, 0xD7, 0xE6, 0xD7, 0xE6, 0xD7, 
+0xE6, 0xB7, 0xE6, 0xB7, 0xE6, 0xB7, 0xE6, 0xB6, 
+0xE6, 0xD7, 0xE6, 0xD6, 0xE6, 0xD6, 0xE6, 0xD7, 
+0xE6, 0xB6, 0xE6, 0xD7, 0xDE, 0x96, 0xDE, 0x76, 
+0xDE, 0x75, 0xDE, 0x75, 0xE6, 0xB6, 0xE6, 0xB6, 
+0xE6, 0xB6, 0xC5, 0xF4, 0xB5, 0x32, 0xDE, 0x76, 
+0xDE, 0x75, 0xE6, 0xB7, 0xC5, 0xB4, 0x73, 0x4B, 
+0x39, 0xC6, 0x31, 0x85, 0x31, 0x85, 0x29, 0x64, 
+0x3A, 0x25, 0x5B, 0xA9, 0x7C, 0xCC, 0x8D, 0x2E, 
+0x8D, 0x6F, 0x7C, 0xCC, 0x6C, 0x6A, 0x74, 0x2A, 
+0x94, 0xAE, 0x7B, 0x8B, 0x62, 0xA8, 0x9C, 0xB0, 
+0x9C, 0xAF, 0xB5, 0x71, 0x9D, 0x0E, 0x84, 0xAA, 
+0x95, 0x8C, 0x74, 0x89, 0x64, 0x06, 0x6C, 0x68, 
+0x7C, 0xEA, 0x8D, 0x6E, 0x95, 0x4F, 0xC6, 0x13, 
+0xDE, 0x35, 0xD5, 0xD4, 0xCD, 0x93, 0xC5, 0x93, 
+0xC5, 0xB4, 0xCD, 0xB4, 0xD5, 0xD3, 0xDE, 0x15, 
+0xDE, 0x35, 0xDE, 0x16, 0xE6, 0x56, 0xDE, 0x15, 
+0xCD, 0x93, 0xDE, 0x57, 0xCD, 0xF7, 0xBD, 0x96, 
+0x5A, 0xCA, 0x42, 0x07, 0x4A, 0x69, 0x52, 0xA9, 
+0x6B, 0x2B, 0x73, 0x8C, 0xA4, 0xF0, 0xBD, 0x93, 
+0xBD, 0x93, 0xBD, 0xB3, 0xBD, 0x93, 0x8C, 0x2D, 
+0x8C, 0x2D, 0xA4, 0xF1, 0xAC, 0xF0, 0xA4, 0x8E, 
+0xDE, 0x55, 0xB5, 0x31, 0x8C, 0x0C, 0x94, 0x4E, 
+0x8C, 0x0E, 0xC5, 0xB4, 0xC5, 0xB3, 0xBD, 0x52, 
+0xB5, 0x10, 0x94, 0x0C, 0x9C, 0x4D, 0xC5, 0x92, 
+0xC5, 0xB3, 0xBD, 0x72, 0xBD, 0x72, 0xAC, 0xD0, 
+0x8C, 0x0C, 0x9C, 0x8E, 0xAC, 0xF0, 0xAD, 0x10, 
+0xAC, 0xEF, 0xA4, 0xAE, 0xAC, 0xCE, 0xA4, 0x8D, 
+0xB5, 0x10, 0xAC, 0xCE, 0xAC, 0xAE, 0xA4, 0x8D, 
+0xA4, 0x6D, 0xAC, 0xAE, 0xBD, 0x30, 0xB5, 0x0F, 
+0xAC, 0xCE, 0xAC, 0xCE, 0xAC, 0xCE, 0xAC, 0xAE, 
+0xB4, 0xEF, 0xB4, 0xEF, 0xB4, 0xEE, 0xB4, 0xCE, 
+0xB4, 0xEF, 0xBD, 0x0F, 0xBD, 0x0F, 0xBC, 0xEF, 
+0xB4, 0xEE, 0xAC, 0xAE, 0xA4, 0x8D, 0xAC, 0xAE, 
+0x9C, 0x4D, 0x6A, 0xE9, 0x39, 0xC6, 0x39, 0xA6, 
+0x39, 0xE7, 0x42, 0x28, 0x52, 0xCB, 0x73, 0xAF, 
+0x84, 0x11, 0x9C, 0xD4, 0xB5, 0xD8, 0xCE, 0x7A, 
+0xD6, 0xBB, 0xDE, 0xDB, 0xE6, 0xDC, 0xD6, 0x59, 
+0xA4, 0xD2, 0x83, 0xAD, 0x83, 0xAC, 0x8B, 0xED, 
+0x8B, 0xED, 0x94, 0x2E, 0xA4, 0x8F, 0xCD, 0xF4, 
+0xC5, 0x93, 0xC5, 0x92, 0xBD, 0x31, 0xB4, 0xEF, 
+0xAC, 0xCE, 0xE6, 0x54, 0xEE, 0x55, 0xE6, 0x14, 
+0xBD, 0x11, 0x73, 0x4B, 0x8C, 0x71, 0xC6, 0x18, 
+0xAD, 0x76, 0xC6, 0x39, 0xEF, 0x5E, 0xDE, 0xFC, 
+0xBD, 0xF7, 0xBD, 0xB5, 0xC5, 0xD5, 0xCE, 0x56, 
+0xD6, 0x56, 0xBD, 0x51, 0xAC, 0xF0, 0xCD, 0xD3, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xCD, 0xB3, 0xBD, 0x72, 
+0x8C, 0x2E, 0x5A, 0xA9, 0x63, 0x0A, 0x6B, 0x2B, 
+0x31, 0x65, 0x39, 0xA6, 0x52, 0x69, 0x5A, 0xCA, 
+0x6B, 0x2B, 0x62, 0xCA, 0x31, 0x65, 0x4A, 0x07, 
+0x7B, 0xAD, 0xA4, 0xD2, 0x8C, 0x30, 0x73, 0x8E, 
+0x84, 0x10, 0x9C, 0xB3, 0xB5, 0x96, 0xAD, 0x55, 
+0xDE, 0xBB, 0xE6, 0xDB, 0xD6, 0x59, 0xCE, 0x18, 
+0xF7, 0x5D, 0xEE, 0xFB, 0xD6, 0x58, 0xDE, 0x79, 
+0xF7, 0x3B, 0xC5, 0xB6, 0x73, 0x4D, 0x8C, 0x2F, 
+0x6B, 0x0B, 0x42, 0x08, 0x73, 0x8C, 0x52, 0xA9, 
+0x4A, 0x48, 0x42, 0x07, 0x3A, 0x07, 0x4A, 0x69, 
+0x42, 0x48, 0x31, 0xA6, 0x31, 0xA6, 0x4A, 0x49, 
+0x5A, 0xCB, 0x52, 0x69, 0x52, 0x6A, 0x63, 0x2C, 
+0x7B, 0xCF, 0x9C, 0xD3, 0xA5, 0x14, 0xA5, 0x34, 
+0x8C, 0x50, 0x9C, 0xB1, 0xBD, 0xD4, 0xCE, 0x16, 
+0xB5, 0x73, 0xA4, 0xD1, 0xAD, 0x32, 0xAD, 0x32, 
+0xAD, 0x32, 0xA4, 0xF1, 0xC5, 0xF5, 0xBD, 0xB4, 
+0xA4, 0xD1, 0x94, 0x4F, 0x94, 0x4F, 0x94, 0x90, 
+0x9C, 0x90, 0x9C, 0xB0, 0x9C, 0xB0, 0xAD, 0x33, 
+0xBD, 0x94, 0xCE, 0x36, 0xCE, 0x15, 0xC5, 0xF4, 
+0xC5, 0xF4, 0xB5, 0x73, 0xB5, 0x53, 0xAD, 0x32, 
+0xAC, 0xF1, 0xAD, 0x11, 0x9C, 0xB0, 0x94, 0x4E, 
+0x8C, 0x2E, 0x9C, 0x8F, 0x9C, 0x2E, 0x8B, 0xCD, 
+0x83, 0x8C, 0x94, 0x2E, 0xAC, 0xD0, 0xCD, 0xD4, 
+0xCD, 0xD4, 0xC5, 0x93, 0xCD, 0xF4, 0xCD, 0xD4, 
+0xCD, 0xB3, 0xBD, 0x72, 0xB5, 0x10, 0xBD, 0x52, 
+0xC5, 0x72, 0xBD, 0x52, 0xBD, 0x52, 0xB5, 0x11, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xA4, 0xD0, 0xB5, 0x11, 
+0xB5, 0x11, 0xB5, 0x12, 0xB5, 0x32, 0xB5, 0x12, 
+0xB5, 0x11, 0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xA4, 0xB0, 0x9C, 0x90, 
+0xA4, 0xB0, 0xAC, 0xF1, 0xA4, 0xD1, 0x9C, 0x6F, 
+0x8C, 0x0E, 0x83, 0xCD, 0x83, 0xED, 0x94, 0x2E, 
+0x94, 0x4F, 0xA4, 0xD1, 0x9C, 0x90, 0xBD, 0x93, 
+0xCE, 0x14, 0xDE, 0x76, 0xDE, 0x76, 0xD6, 0x56, 
+0xD6, 0x56, 0xDE, 0x76, 0xDE, 0x96, 0xDE, 0x96, 
+0xDE, 0x96, 0xE6, 0xB6, 0xE6, 0xB6, 0xEE, 0xD6, 
+0xEE, 0xD7, 0xEE, 0xF8, 0xE6, 0xD7, 0xE6, 0xD7, 
+0xE6, 0xF7, 0xEE, 0xF7, 0xEE, 0xF7, 0xEE, 0xF7, 
+0xF7, 0x18, 0xCE, 0x14, 0xC5, 0xB4, 0xEF, 0x18, 
+0xE6, 0x96, 0xE6, 0xB6, 0xEE, 0xD7, 0xEE, 0xF8, 
+0xAD, 0x11, 0x39, 0xC6, 0x31, 0x85, 0x31, 0x85, 
+0x29, 0x64, 0x32, 0x25, 0x4B, 0x27, 0x74, 0x8B, 
+0x85, 0x0C, 0x74, 0x8A, 0x6C, 0x6A, 0x21, 0xA2, 
+0x5A, 0xE9, 0x9C, 0xEF, 0xA5, 0x0F, 0x73, 0x8A, 
+0x62, 0xE9, 0x73, 0x6B, 0x8C, 0x6E, 0x7C, 0x4B, 
+0x84, 0xCA, 0x74, 0xA9, 0x63, 0xE8, 0x53, 0x67, 
+0x7C, 0xAB, 0x7C, 0xCC, 0x8D, 0x0E, 0xCE, 0x33, 
+0xD6, 0x14, 0xCD, 0xB3, 0xCD, 0xB4, 0xCD, 0xD4, 
+0xD5, 0xF5, 0xCD, 0x93, 0xCD, 0xB3, 0xE6, 0x56, 
+0xE6, 0x56, 0xD5, 0xF5, 0xAC, 0xF2, 0x9C, 0x50, 
+0xB5, 0x13, 0xBD, 0x54, 0xB5, 0x34, 0xA4, 0xB2, 
+0x39, 0xE7, 0x4A, 0x49, 0x52, 0x89, 0x5A, 0xAA, 
+0x5A, 0xCA, 0x6B, 0x4B, 0x9C, 0xB0, 0xAD, 0x32, 
+0xAD, 0x11, 0xAD, 0x11, 0xAD, 0x31, 0x94, 0x2E, 
+0x83, 0xCD, 0xAD, 0x32, 0xB5, 0x11, 0xA4, 0x8D, 
+0xD6, 0x34, 0xB5, 0x11, 0x8B, 0xEC, 0x8C, 0x2E, 
+0x94, 0x4F, 0xD6, 0x56, 0xBD, 0x52, 0xB5, 0x10, 
+0xA4, 0xAE, 0x83, 0xAA, 0x8C, 0x0C, 0xA4, 0xAF, 
+0xAD, 0x10, 0xBD, 0x92, 0xD6, 0x56, 0xC5, 0xB3, 
+0x7B, 0xAB, 0xAD, 0x11, 0xC5, 0xD4, 0xBD, 0xD3, 
+0xC5, 0xF4, 0xB5, 0x31, 0xA4, 0x8D, 0x9C, 0x4D, 
+0xC5, 0x92, 0xBD, 0x71, 0xAC, 0xEF, 0x9C, 0x4D, 
+0x94, 0x2C, 0x83, 0xCC, 0x7B, 0x6A, 0x83, 0xEB, 
+0x83, 0xCB, 0x83, 0xAB, 0x94, 0x0C, 0x73, 0x49, 
+0x83, 0xCB, 0x83, 0xCA, 0x94, 0x2C, 0x9C, 0x6D, 
+0x9C, 0x6D, 0x94, 0x2C, 0x94, 0x0C, 0xA4, 0x8E, 
+0xB4, 0xEF, 0xBD, 0x30, 0xB5, 0x10, 0xBD, 0x30, 
+0xC5, 0x92, 0xAC, 0xCF, 0x8B, 0xEC, 0x4A, 0x27, 
+0x31, 0xA6, 0x31, 0xA6, 0x3A, 0x07, 0x52, 0x8A, 
+0x5A, 0xCC, 0x84, 0x31, 0xA5, 0x15, 0xA5, 0x35, 
+0xA5, 0x35, 0xB5, 0x97, 0xE7, 0x1D, 0xEF, 0x5D, 
+0xE6, 0xFC, 0xAC, 0xF3, 0x94, 0x4F, 0x9C, 0x4E, 
+0x94, 0x0D, 0x8B, 0xCC, 0x8B, 0xAB, 0x8B, 0xAB, 
+0x83, 0x8B, 0x83, 0x8B, 0x8B, 0xCB, 0x9C, 0x2C, 
+0x8B, 0xAA, 0x8B, 0xAB, 0x9C, 0x2C, 0xAC, 0x8E, 
+0x9C, 0x2D, 0x9C, 0x8F, 0x8C, 0x2E, 0x8C, 0x70, 
+0xA5, 0x14, 0xDE, 0xBB, 0xE7, 0x3D, 0xDE, 0xDC, 
+0xE7, 0x3D, 0xB5, 0x95, 0xC5, 0xD5, 0xCE, 0x36, 
+0xC5, 0xF4, 0xA4, 0x8F, 0x9C, 0x4D, 0xAD, 0x10, 
+0xD6, 0x15, 0xD6, 0x15, 0xD5, 0xF4, 0xC5, 0xB3, 
+0xC5, 0x72, 0xC5, 0xB4, 0xD6, 0x35, 0xAD, 0x31, 
+0x41, 0xC6, 0x39, 0xA6, 0x29, 0x44, 0x39, 0xE7, 
+0x4A, 0x28, 0x5A, 0x89, 0x62, 0xEB, 0x52, 0x89, 
+0x42, 0x07, 0x62, 0xCA, 0x9C, 0x71, 0x94, 0x71, 
+0x6B, 0x4D, 0x8C, 0x51, 0xB5, 0x75, 0xB5, 0x76, 
+0xAD, 0x35, 0xC5, 0xF8, 0xBD, 0x96, 0xDE, 0xDB, 
+0xF7, 0x7D, 0xF7, 0x5D, 0xCD, 0xF7, 0xC5, 0xB6, 
+0xE6, 0xBA, 0xEE, 0x9A, 0xDE, 0x59, 0xBD, 0x75, 
+0xB5, 0x55, 0x39, 0xE7, 0x42, 0x07, 0x5A, 0xEA, 
+0x52, 0xA9, 0x4A, 0x48, 0x4A, 0x68, 0x42, 0x07, 
+0x39, 0xC6, 0x31, 0x85, 0x39, 0xE7, 0x42, 0x28, 
+0x4A, 0x89, 0x4A, 0x69, 0x52, 0xAA, 0x63, 0x2C, 
+0x6B, 0x8E, 0x73, 0xAF, 0x9C, 0xD3, 0xBD, 0xF7, 
+0xB5, 0x96, 0x8C, 0x50, 0xAD, 0x32, 0xBD, 0xB4, 
+0xB5, 0x52, 0xAD, 0x12, 0xB5, 0x33, 0xB5, 0x32, 
+0xAD, 0x12, 0xB5, 0x32, 0xBD, 0x94, 0xC5, 0xF5, 
+0x94, 0x6F, 0x9C, 0xB1, 0xBD, 0xD5, 0xB5, 0x94, 
+0xBD, 0xD5, 0xBD, 0x94, 0x9C, 0x90, 0xAD, 0x12, 
+0xBD, 0xD4, 0xD6, 0x55, 0xCE, 0x34, 0xD6, 0x75, 
+0xD6, 0x55, 0xB5, 0x73, 0x8C, 0x4F, 0x9C, 0xD0, 
+0xAD, 0x32, 0xAD, 0x12, 0xAD, 0x52, 0xA4, 0xF1, 
+0x9C, 0xB0, 0xAC, 0xF1, 0x83, 0x8C, 0x73, 0x2A, 
+0x83, 0xAC, 0x9C, 0x6F, 0xB5, 0x11, 0xA4, 0x6E, 
+0xBD, 0x52, 0xAC, 0xF0, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xB5, 0x30, 0xBD, 0x51, 0xC5, 0x51, 0xC5, 0x92, 
+0xCD, 0xD3, 0xCD, 0xD3, 0xCD, 0xB2, 0xCD, 0xD3, 
+0xBD, 0x72, 0xAC, 0xD0, 0x94, 0x2D, 0x8B, 0xED, 
+0x8B, 0xAC, 0x9C, 0x6F, 0x8C, 0x0E, 0x8C, 0x0D, 
+0x94, 0x2E, 0x94, 0x4E, 0x94, 0x4E, 0x94, 0x4E, 
+0x9C, 0x6F, 0xAC, 0xF1, 0xA4, 0x8F, 0x9C, 0x8F, 
+0xA4, 0xB0, 0xA4, 0xB0, 0xA4, 0xB0, 0xAD, 0x11, 
+0xAD, 0x12, 0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF1, 
+0x9C, 0x6F, 0x94, 0x2E, 0x94, 0x4F, 0x9C, 0x6F, 
+0xAD, 0x12, 0xA4, 0xD1, 0x9C, 0xB1, 0xAC, 0xF2, 
+0xAD, 0x32, 0xB5, 0x32, 0xAD, 0x32, 0xAD, 0x11, 
+0xAD, 0x32, 0xB5, 0x32, 0xB5, 0x52, 0xBD, 0x72, 
+0xBD, 0x93, 0xC5, 0xB3, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xB3, 0xBD, 0x93, 
+0xBD, 0x73, 0xAC, 0xF1, 0xB5, 0x52, 0xDE, 0x96, 
+0xDE, 0x55, 0xD6, 0x35, 0xD6, 0x35, 0xDE, 0x96, 
+0xDE, 0x76, 0x7B, 0xCD, 0x31, 0xA5, 0x31, 0x85, 
+0x4A, 0x67, 0x6C, 0x0B, 0x7C, 0xAC, 0x85, 0x0D, 
+0x6C, 0x6A, 0x6C, 0x49, 0x5B, 0x88, 0x19, 0x22, 
+0x31, 0xC5, 0x63, 0x49, 0xB5, 0xB0, 0x62, 0xE8, 
+0x29, 0x24, 0x41, 0xE6, 0x5A, 0x88, 0x5A, 0xE8, 
+0x74, 0x09, 0x7C, 0x8A, 0x6C, 0x0A, 0x42, 0x67, 
+0xAD, 0x91, 0xCE, 0x53, 0x9D, 0x2F, 0xD6, 0x75, 
+0xD5, 0xF4, 0xCD, 0xB3, 0xD5, 0xF5, 0xDE, 0x36, 
+0xDE, 0x36, 0xC5, 0x73, 0xD5, 0xD5, 0xCD, 0xB4, 
+0xCD, 0x94, 0xC5, 0x95, 0xCD, 0xF7, 0xCE, 0x18, 
+0xB5, 0x55, 0xAC, 0xF3, 0xB5, 0x34, 0xAD, 0x14, 
+0x31, 0xA7, 0x42, 0x28, 0x4A, 0x48, 0x52, 0xAA, 
+0x5A, 0xAA, 0x63, 0x0A, 0x8C, 0x6F, 0xA4, 0xF1, 
+0xA4, 0xD0, 0x9C, 0xB0, 0xA4, 0xF0, 0x8C, 0x2E, 
+0x7B, 0xAC, 0xAD, 0x32, 0xA4, 0xCF, 0x9C, 0x8E, 
+0xD6, 0x35, 0xBD, 0x71, 0x94, 0x4E, 0x8C, 0x2E, 
+0x94, 0x6F, 0xCD, 0xF5, 0xA4, 0xAF, 0x83, 0xAB, 
+0xA4, 0xAF, 0x9C, 0x6E, 0x94, 0x4E, 0x8C, 0x2E, 
+0xA4, 0xD0, 0xCE, 0x15, 0xD6, 0x76, 0xBD, 0xB4, 
+0x94, 0x4E, 0xB5, 0x93, 0xCE, 0x15, 0xBD, 0xB4, 
+0xCE, 0x15, 0xB5, 0x51, 0x9C, 0x6D, 0x9C, 0x8E, 
+0xB5, 0x71, 0xBD, 0x92, 0xC5, 0xD3, 0xC5, 0xD4, 
+0xC5, 0xD3, 0xBD, 0xB3, 0xB5, 0x93, 0x9C, 0xAF, 
+0x7B, 0xAB, 0x9C, 0xAF, 0xA4, 0xAF, 0xA4, 0xF0, 
+0xB5, 0x52, 0xAD, 0x31, 0xAD, 0x10, 0xB5, 0x31, 
+0x9C, 0x8F, 0x7B, 0x8B, 0x7B, 0xAB, 0x9C, 0x6E, 
+0xC5, 0x72, 0xB4, 0xEF, 0x9C, 0x6C, 0xBD, 0x51, 
+0xC5, 0x71, 0xAC, 0xAF, 0x9C, 0x4D, 0xA4, 0x8F, 
+0x52, 0x47, 0x31, 0xA5, 0x31, 0xA5, 0x42, 0x28, 
+0x4A, 0x69, 0x63, 0x0C, 0x7B, 0xCF, 0x6B, 0x4D, 
+0x73, 0x8E, 0xB5, 0xB7, 0xCE, 0x7A, 0xCE, 0x5A, 
+0xE6, 0xFC, 0xD6, 0x7A, 0xCE, 0x18, 0xBD, 0x74, 
+0xC5, 0x93, 0xB5, 0x31, 0xA4, 0x8E, 0xA4, 0x8E, 
+0xAC, 0xCF, 0xB4, 0xF0, 0xAC, 0xAE, 0xAC, 0xAE, 
+0xAC, 0xCF, 0x9C, 0x4D, 0x9C, 0x2D, 0xA4, 0x4D, 
+0x9C, 0x4D, 0x9C, 0x4E, 0x9C, 0x8F, 0x6B, 0x4C, 
+0x9C, 0xD3, 0xA5, 0x14, 0xD6, 0x9A, 0xC6, 0x19, 
+0xE7, 0x1C, 0xCE, 0x59, 0x83, 0xCE, 0x8B, 0xED, 
+0x94, 0x0D, 0x9C, 0x4D, 0xA4, 0x6E, 0x94, 0x0D, 
+0x83, 0xAB, 0x83, 0x8B, 0x83, 0xAB, 0x8B, 0xEC, 
+0x9C, 0x2D, 0xA4, 0x6E, 0xA4, 0xAF, 0x94, 0x2D, 
+0x8B, 0xED, 0x6A, 0xE9, 0x31, 0xA5, 0x39, 0xC5, 
+0x42, 0x06, 0x52, 0x68, 0x6B, 0x2B, 0x6B, 0x2C, 
+0x9C, 0xB2, 0x94, 0x50, 0x62, 0xCA, 0x83, 0xEF, 
+0x9C, 0xD2, 0x63, 0x0C, 0x73, 0xAF, 0x94, 0xB2, 
+0x9C, 0xB2, 0x94, 0x92, 0xAD, 0x55, 0xCE, 0x39, 
+0xEF, 0x5D, 0xD6, 0x79, 0xC5, 0xF7, 0xCE, 0x18, 
+0xBD, 0xB6, 0xD6, 0x39, 0xE6, 0x9A, 0xFF, 0x5D, 
+0xC5, 0xD7, 0x6A, 0xEC, 0x4A, 0x08, 0x5A, 0xCA, 
+0x52, 0x89, 0x42, 0x28, 0x42, 0x27, 0x39, 0xE7, 
+0x39, 0xC6, 0x31, 0x85, 0x31, 0xA6, 0x39, 0xC6, 
+0x4A, 0x69, 0x5A, 0xEB, 0x5A, 0xCA, 0x5A, 0xCA, 
+0x6B, 0x6D, 0x84, 0x30, 0xAD, 0x55, 0xB5, 0x96, 
+0xBD, 0xD7, 0xB5, 0x74, 0xB5, 0x74, 0xBD, 0xB4, 
+0xB5, 0x52, 0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x32, 
+0xB5, 0x53, 0xB5, 0x73, 0xBD, 0x93, 0xC5, 0xF5, 
+0xAD, 0x32, 0xA5, 0x12, 0xBD, 0xB4, 0xC5, 0xF5, 
+0xC5, 0xF5, 0xBD, 0xB4, 0xA4, 0xD1, 0xAD, 0x53, 
+0xBD, 0x93, 0xCE, 0x14, 0xCE, 0x34, 0xD6, 0x55, 
+0xCE, 0x35, 0xA4, 0xF1, 0xB5, 0x74, 0xB5, 0x94, 
+0xAD, 0x32, 0xB5, 0x94, 0xBD, 0x94, 0xA5, 0x11, 
+0x9C, 0x8F, 0xAC, 0xF1, 0x94, 0x0D, 0x83, 0x8C, 
+0x94, 0x2D, 0xBD, 0x32, 0xB4, 0xF0, 0xAC, 0xAF, 
+0xBD, 0x32, 0x9C, 0x8F, 0xA4, 0xB0, 0xB5, 0x31, 
+0xCD, 0xB3, 0xD5, 0xD3, 0xCD, 0xB2, 0xCD, 0xB3, 
+0xCD, 0xD3, 0xCD, 0xB2, 0xC5, 0x51, 0xA4, 0x8F, 
+0x8B, 0xCC, 0x8B, 0xED, 0x94, 0x2D, 0x94, 0x2D, 
+0x8B, 0xCC, 0xA4, 0x90, 0x9C, 0x8F, 0xAC, 0xF0, 
+0xBD, 0x72, 0xBD, 0x93, 0xB5, 0x52, 0xA4, 0xD0, 
+0xA4, 0xB0, 0xA4, 0xF0, 0xA4, 0xAF, 0xA4, 0xB0, 
+0xAC, 0xF1, 0xA4, 0xD0, 0x9C, 0x6F, 0x9C, 0x6F, 
+0xB5, 0x12, 0xAD, 0x11, 0xA4, 0xB0, 0x9C, 0x6F, 
+0x83, 0xCD, 0x7B, 0x8B, 0xB5, 0x32, 0xCD, 0xF4, 
+0xBD, 0x93, 0x94, 0x6F, 0xA4, 0xD0, 0xC5, 0xD5, 
+0xBD, 0x73, 0xB5, 0x32, 0xCD, 0xD4, 0xD6, 0x35, 
+0xD6, 0x36, 0xB5, 0x52, 0xB5, 0x32, 0xB5, 0x32, 
+0xB5, 0x32, 0xC5, 0xB4, 0xBD, 0x94, 0xBD, 0x73, 
+0xB5, 0x52, 0xB5, 0x52, 0xBD, 0x73, 0xBD, 0x73, 
+0xBD, 0x73, 0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x32, 
+0xB5, 0x32, 0xAC, 0xF1, 0xA4, 0xD1, 0x9C, 0xB0, 
+0x9C, 0x90, 0x9C, 0xD0, 0x8C, 0x2E, 0x4A, 0x68, 
+0x5B, 0x08, 0x6C, 0x2A, 0x6C, 0x4A, 0x53, 0xA8, 
+0x3A, 0xA5, 0x32, 0x44, 0x29, 0xC3, 0x21, 0x83, 
+0x4A, 0xE7, 0x4A, 0xE7, 0x7B, 0xEB, 0x8C, 0x6E, 
+0x42, 0x07, 0x29, 0x44, 0x39, 0xA6, 0x52, 0x67, 
+0x5B, 0x28, 0x53, 0x08, 0x42, 0xA7, 0x3A, 0x07, 
+0x73, 0x8B, 0xCE, 0x14, 0xBD, 0x92, 0xCD, 0xF3, 
+0xCD, 0xF4, 0xBD, 0xB3, 0xE6, 0xD8, 0xEE, 0xD9, 
+0xDE, 0x57, 0xE6, 0xB9, 0xE6, 0xD9, 0xD6, 0x77, 
+0xD6, 0x78, 0xD6, 0x17, 0xAD, 0x13, 0xBD, 0x75, 
+0xC5, 0xB6, 0xBD, 0x96, 0xC5, 0xB6, 0xBD, 0x96, 
+0x31, 0x86, 0x39, 0xE7, 0x42, 0x28, 0x4A, 0x28, 
+0x52, 0x69, 0x5A, 0xEA, 0x7B, 0xCD, 0x94, 0x90, 
+0x94, 0x90, 0x94, 0x70, 0x94, 0x70, 0x83, 0xEE, 
+0x83, 0xEE, 0xBD, 0xB4, 0xAC, 0xD0, 0xA4, 0x8E, 
+0xD6, 0x14, 0xCD, 0xD3, 0xA4, 0xB0, 0x94, 0x6F, 
+0x94, 0x6F, 0xBD, 0x93, 0xBD, 0x72, 0xB5, 0x52, 
+0xCE, 0x15, 0xBD, 0x93, 0xC5, 0xD4, 0x9C, 0x90, 
+0xB5, 0x53, 0xCE, 0x15, 0xC5, 0xF4, 0xB5, 0x52, 
+0xA4, 0xD0, 0xC5, 0xF5, 0xCE, 0x35, 0xCE, 0x56, 
+0xC5, 0xD4, 0xB5, 0x31, 0xAC, 0xCF, 0xA4, 0xAE, 
+0xBD, 0x72, 0xBD, 0x93, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xC5, 0xB3, 0xCE, 0x35, 0xCE, 0x35, 0xAD, 0x11, 
+0x63, 0x09, 0xBD, 0xD4, 0xD6, 0x76, 0xCE, 0x55, 
+0xD6, 0x55, 0xD6, 0x76, 0xD6, 0x76, 0xCE, 0x35, 
+0xBD, 0x93, 0xC5, 0xD4, 0xD6, 0x56, 0xCE, 0x14, 
+0xDE, 0x55, 0xB5, 0x10, 0xAC, 0xAE, 0xEE, 0xB6, 
+0xEE, 0xD7, 0xEE, 0xB6, 0xE6, 0x76, 0xE6, 0x55, 
+0xCD, 0x93, 0x72, 0xE9, 0x31, 0x84, 0x39, 0xC6, 
+0x42, 0x07, 0x4A, 0x48, 0x5A, 0xAB, 0x5A, 0xCB, 
+0x73, 0xAF, 0xAD, 0x76, 0xB5, 0xD8, 0xC6, 0x19, 
+0xD6, 0x9B, 0xE7, 0x1D, 0xEF, 0x5D, 0xCE, 0x59, 
+0x9C, 0x91, 0x94, 0x0D, 0xA4, 0xAE, 0xAC, 0xCF, 
+0xC5, 0xB2, 0xC5, 0x71, 0xBD, 0x71, 0xC5, 0x92, 
+0x9C, 0x2D, 0x83, 0x49, 0x9C, 0x2D, 0xB5, 0x11, 
+0xAC, 0xAF, 0x94, 0x0D, 0x9C, 0x6E, 0x6B, 0x2B, 
+0x8C, 0x71, 0x9C, 0xD3, 0xD6, 0xBA, 0xCE, 0x59, 
+0xBD, 0xD7, 0xEF, 0x3D, 0xC6, 0x17, 0x94, 0x2F, 
+0x9C, 0x4E, 0xAC, 0xCF, 0xB5, 0x10, 0xAC, 0xCF, 
+0xAC, 0xF0, 0xB4, 0xF0, 0xB4, 0xF0, 0xB4, 0xF0, 
+0xB5, 0x10, 0xB5, 0x10, 0xBD, 0x31, 0xBD, 0x31, 
+0xBD, 0x51, 0x83, 0xAC, 0x29, 0x23, 0x6B, 0x2A, 
+0x8C, 0x4E, 0x63, 0x09, 0x52, 0x89, 0x42, 0x07, 
+0x5A, 0xCA, 0x8B, 0xEE, 0x6B, 0x0B, 0x31, 0x85, 
+0x6B, 0x2C, 0x6B, 0x2C, 0x62, 0xEC, 0x5A, 0xAB, 
+0x7B, 0xEF, 0x94, 0xB2, 0x9C, 0xB3, 0xA5, 0x35, 
+0xA5, 0x14, 0xC5, 0xF8, 0xEF, 0x5D, 0xE6, 0xFB, 
+0xDE, 0x9A, 0xCE, 0x18, 0xDE, 0x9A, 0xF7, 0x3C, 
+0xF7, 0x3D, 0xD6, 0x18, 0xA4, 0xD3, 0xA4, 0xB2, 
+0x62, 0xCA, 0x42, 0x07, 0x42, 0x07, 0x42, 0x07, 
+0x42, 0x27, 0x39, 0xE7, 0x39, 0xE7, 0x42, 0x07, 
+0x4A, 0x28, 0x52, 0x89, 0x52, 0xAA, 0x5A, 0xEB, 
+0x6B, 0x6D, 0x84, 0x10, 0xA5, 0x14, 0xB5, 0x96, 
+0xA5, 0x14, 0xB5, 0xB5, 0xAD, 0x53, 0xC5, 0xD4, 
+0xC5, 0xB4, 0xB5, 0x52, 0xBD, 0x73, 0xBD, 0x73, 
+0xBD, 0x73, 0xB5, 0x73, 0xB5, 0x73, 0xC5, 0xB4, 
+0xAD, 0x32, 0xAD, 0x33, 0xA4, 0xF2, 0xAD, 0x32, 
+0xAD, 0x12, 0xAD, 0x53, 0xA4, 0xD1, 0xAD, 0x53, 
+0xBD, 0x93, 0xBD, 0x93, 0xC5, 0xF3, 0xD6, 0x55, 
+0xCE, 0x14, 0x9C, 0xB0, 0xAD, 0x33, 0xC5, 0xF5, 
+0xB5, 0x73, 0xAD, 0x32, 0xAD, 0x12, 0xA4, 0xD1, 
+0x9C, 0x8F, 0xA4, 0xB0, 0x9C, 0x4E, 0xA4, 0x6F, 
+0xB4, 0xF0, 0xC5, 0x52, 0xAC, 0x8F, 0xB4, 0xF1, 
+0xC5, 0x93, 0xA4, 0x8F, 0xA4, 0xD0, 0xAC, 0xF0, 
+0xCD, 0xB2, 0xD5, 0xD3, 0xCD, 0xB3, 0xCD, 0xB2, 
+0xD5, 0xD3, 0xCD, 0x92, 0xBD, 0x31, 0x8B, 0xEC, 
+0x7B, 0x8C, 0x7B, 0xAC, 0x83, 0xCD, 0x83, 0xAB, 
+0x8B, 0xCC, 0xA4, 0xD0, 0xAD, 0x31, 0xB5, 0x72, 
+0xB5, 0x72, 0xB5, 0x72, 0xB5, 0x52, 0xB5, 0x52, 
+0xAD, 0x11, 0xA4, 0xF0, 0xA4, 0xD0, 0xB5, 0x32, 
+0xBD, 0x73, 0xB5, 0x72, 0xB5, 0x52, 0xA4, 0xF0, 
+0xBD, 0x72, 0xBD, 0x92, 0xC5, 0xB3, 0xA4, 0xF0, 
+0x83, 0xCD, 0xBD, 0xB3, 0xB5, 0x31, 0xDE, 0x75, 
+0xCE, 0x14, 0x8C, 0x2E, 0xB5, 0x31, 0xC5, 0x93, 
+0x94, 0x4F, 0x73, 0x4B, 0xBD, 0x73, 0xD6, 0x14, 
+0xAD, 0x11, 0x94, 0x4F, 0x94, 0x4E, 0x94, 0x2E, 
+0x9C, 0x6F, 0xBD, 0x72, 0x83, 0xCC, 0x94, 0x4E, 
+0x94, 0x6F, 0xBD, 0x73, 0xBD, 0x73, 0xA4, 0xB0, 
+0xAD, 0x11, 0xB5, 0x11, 0xBD, 0x73, 0xC5, 0xB4, 
+0xDE, 0x77, 0xC5, 0xD4, 0x94, 0x2F, 0xD6, 0x77, 
+0xE6, 0xD7, 0xEE, 0xF8, 0xDE, 0xB7, 0xBD, 0xF4, 
+0x84, 0x6E, 0x74, 0x6C, 0x6C, 0x4A, 0x4B, 0x47, 
+0x32, 0x85, 0x3A, 0x65, 0x53, 0x28, 0x7C, 0xAD, 
+0x53, 0x66, 0x5B, 0xE9, 0x42, 0xA6, 0x9D, 0x10, 
+0x73, 0xAC, 0x52, 0x68, 0x39, 0xA6, 0x52, 0x68, 
+0x52, 0x87, 0x29, 0x84, 0x3A, 0x06, 0x4A, 0x48, 
+0x42, 0x07, 0x8C, 0x0E, 0xA4, 0xD0, 0xD6, 0x56, 
+0xA5, 0x11, 0xA5, 0x72, 0x95, 0x0F, 0xAD, 0x72, 
+0xEF, 0x3A, 0xC5, 0xF5, 0x94, 0xF0, 0x8C, 0xEF, 
+0x9D, 0x31, 0xAD, 0x93, 0x8C, 0x0F, 0xBD, 0x96, 
+0xBD, 0xB6, 0xB5, 0x34, 0xAD, 0x34, 0xA4, 0xD2, 
+0x29, 0x45, 0x29, 0x86, 0x39, 0xC7, 0x39, 0xE7, 
+0x39, 0xE7, 0x42, 0x28, 0x52, 0xA9, 0x63, 0x0B, 
+0x6B, 0x2B, 0x6B, 0x2B, 0x6B, 0x2B, 0x6B, 0x4B, 
+0x83, 0xCD, 0xB5, 0x73, 0xB5, 0x10, 0x9C, 0x6D, 
+0xD6, 0x14, 0xC5, 0x92, 0xA4, 0xAF, 0x94, 0x6F, 
+0x9C, 0x90, 0xCE, 0x35, 0xCD, 0xF4, 0xCE, 0x15, 
+0xD6, 0x56, 0xBD, 0xD3, 0xCE, 0x15, 0xA4, 0xD1, 
+0xCE, 0x16, 0xB5, 0x73, 0xA4, 0xF1, 0xAD, 0x32, 
+0x94, 0x6F, 0xB5, 0x73, 0xCE, 0x15, 0xCE, 0x35, 
+0xBD, 0x93, 0xB5, 0x31, 0xAC, 0xCF, 0x9C, 0x4D, 
+0xBD, 0x93, 0xBD, 0x92, 0xBD, 0x92, 0xBD, 0x72, 
+0xB5, 0x51, 0xB5, 0x72, 0xBD, 0xB3, 0x94, 0x8F, 
+0x73, 0x8C, 0xB5, 0xB4, 0xCE, 0x35, 0xCE, 0x35, 
+0xCE, 0x14, 0xCE, 0x34, 0xCE, 0x35, 0xCE, 0x35, 
+0xCE, 0x35, 0xD6, 0x76, 0xDE, 0x96, 0xD6, 0x76, 
+0xCD, 0xF3, 0xBD, 0x72, 0xB4, 0xCF, 0xE6, 0xB6, 
+0xE6, 0xB6, 0xEE, 0xB6, 0xEE, 0x96, 0xD5, 0xD3, 
+0xD5, 0x72, 0xE6, 0x35, 0xB5, 0x11, 0x52, 0x47, 
+0x39, 0xC6, 0x39, 0xE6, 0x4A, 0x69, 0x4A, 0x28, 
+0x5A, 0xCB, 0x8C, 0x51, 0x9C, 0xF4, 0xB5, 0xD8, 
+0xB5, 0x97, 0xDE, 0xDC, 0xE6, 0xFC, 0xE7, 0x1D, 
+0xC5, 0xF8, 0xA4, 0xF2, 0xA4, 0x8F, 0xBD, 0x51, 
+0xE6, 0x75, 0xE6, 0x55, 0xDE, 0x55, 0xCD, 0xD3, 
+0xA4, 0x6E, 0xAC, 0x8F, 0xCD, 0x93, 0xD5, 0xF4, 
+0xBD, 0x72, 0xCD, 0xD3, 0xCD, 0xD4, 0xA4, 0xD0, 
+0x8C, 0x2F, 0x7B, 0xEF, 0xC6, 0x39, 0xCE, 0x59, 
+0xCE, 0x59, 0xE6, 0xFC, 0xEF, 0x5D, 0xA4, 0xD3, 
+0x7B, 0x8C, 0x73, 0x6B, 0x73, 0x6B, 0x6B, 0x2A, 
+0x73, 0x2A, 0x73, 0x4B, 0x7B, 0x8B, 0x83, 0xCC, 
+0x8C, 0x0D, 0x94, 0x4E, 0x94, 0x4E, 0x94, 0x2D, 
+0x9C, 0x6E, 0x5A, 0x88, 0x29, 0x24, 0x8C, 0x0E, 
+0xA4, 0xF0, 0xAD, 0x31, 0x94, 0x4F, 0x41, 0xE6, 
+0x39, 0xC6, 0x31, 0xA5, 0x21, 0x24, 0x39, 0xE7, 
+0x31, 0x65, 0x4A, 0x48, 0x63, 0x0B, 0x62, 0xEB, 
+0x7B, 0xCF, 0x7B, 0xAE, 0x8C, 0x31, 0x84, 0x10, 
+0x94, 0xB3, 0x94, 0x72, 0xB5, 0x76, 0xDE, 0xBB, 
+0xF7, 0x7E, 0xEF, 0x3C, 0xC5, 0xD8, 0xBD, 0xB6, 
+0xDE, 0x79, 0xEF, 0x1B, 0xF7, 0x5C, 0xCD, 0xF6, 
+0x9C, 0x91, 0x52, 0x48, 0x39, 0xE7, 0x39, 0xE6, 
+0x39, 0xE7, 0x42, 0x07, 0x42, 0x07, 0x4A, 0x48, 
+0x4A, 0x69, 0x4A, 0x69, 0x52, 0xAA, 0x63, 0x0C, 
+0x6B, 0x4D, 0x84, 0x10, 0x83, 0xF0, 0x8C, 0x51, 
+0x9C, 0xD3, 0xBD, 0xF7, 0xAD, 0x12, 0xC5, 0xB4, 
+0xC5, 0xB4, 0xC5, 0x93, 0xCD, 0xF4, 0xCD, 0xF5, 
+0xC5, 0xB4, 0xAD, 0x32, 0xBD, 0x93, 0xB5, 0x53, 
+0xB5, 0x73, 0xAD, 0x12, 0xA4, 0xF1, 0xA5, 0x11, 
+0x9C, 0xD1, 0x9C, 0xD1, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xB5, 0x73, 0xC5, 0xB3, 0xCD, 0xF4, 0xCE, 0x35, 
+0xC5, 0xF4, 0x94, 0x6F, 0x94, 0x90, 0xB5, 0x74, 
+0xB5, 0x94, 0xAD, 0x12, 0xAD, 0x53, 0x9C, 0xD0, 
+0x94, 0x4E, 0xA4, 0xD0, 0x9C, 0x4E, 0xA4, 0x8F, 
+0xBD, 0x11, 0xBD, 0x31, 0xA4, 0x8F, 0xB5, 0x11, 
+0xB5, 0x32, 0x9C, 0x90, 0xA4, 0xD0, 0xAC, 0xF0, 
+0xCD, 0x92, 0xCD, 0x92, 0xCD, 0x92, 0xCD, 0xB2, 
+0xD5, 0xD3, 0xCD, 0xB2, 0xB5, 0x10, 0x7B, 0xAC, 
+0x73, 0x6C, 0x7B, 0x8C, 0x7B, 0xAC, 0x7B, 0x8C, 
+0x83, 0xAC, 0xAC, 0xF1, 0xA4, 0xF0, 0xBD, 0x92, 
+0xBD, 0x72, 0xAD, 0x31, 0xAD, 0x11, 0xA4, 0xF0, 
+0x9C, 0x8F, 0xA4, 0xD0, 0xAC, 0xF1, 0xB5, 0x52, 
+0xB5, 0x52, 0xBD, 0xB3, 0xC5, 0xD3, 0xB5, 0x51, 
+0xC5, 0xB3, 0xC5, 0x92, 0xC5, 0x93, 0xB5, 0x31, 
+0xC5, 0x93, 0xDE, 0x55, 0x93, 0xEC, 0xCD, 0xD4, 
+0xCD, 0xF4, 0x9C, 0x8F, 0xCE, 0x15, 0xD6, 0x36, 
+0xC5, 0xB4, 0xCD, 0xF6, 0xCE, 0x15, 0xDE, 0x56, 
+0xCE, 0x15, 0xBD, 0x53, 0x9C, 0x90, 0x8C, 0x0E, 
+0x9C, 0x90, 0xAD, 0x12, 0xB5, 0x32, 0xBD, 0x73, 
+0xC5, 0x94, 0xD6, 0x36, 0xD6, 0x35, 0xD6, 0x35, 
+0xDE, 0x76, 0xE6, 0x76, 0xE6, 0x76, 0xDE, 0x56, 
+0xDE, 0x76, 0xD6, 0x36, 0xB5, 0x12, 0xCE, 0x16, 
+0xB5, 0x32, 0x9C, 0x90, 0xA4, 0xF1, 0xA5, 0x11, 
+0x95, 0x30, 0x8D, 0x2E, 0x8D, 0x2E, 0x74, 0x6B, 
+0x53, 0x88, 0x5B, 0xE9, 0x85, 0x0E, 0x85, 0x0D, 
+0x5B, 0xE8, 0x74, 0x8B, 0x6B, 0xCA, 0x84, 0x6C, 
+0xBD, 0xF2, 0x73, 0xAB, 0x42, 0x27, 0x52, 0xA7, 
+0x52, 0xC8, 0x31, 0xC5, 0x29, 0x44, 0x42, 0x68, 
+0x5A, 0xEA, 0x73, 0x8C, 0xBD, 0xF4, 0xEF, 0x7A, 
+0xD6, 0xF8, 0x84, 0xCF, 0x42, 0xE5, 0x53, 0x87, 
+0x84, 0xED, 0x74, 0x6B, 0x8D, 0x4F, 0xAE, 0x12, 
+0xAE, 0x33, 0xBE, 0x75, 0xBD, 0xF5, 0x94, 0x50, 
+0x8C, 0x10, 0x83, 0xCE, 0x7B, 0xAD, 0x73, 0x4C, 
+0x31, 0xA6, 0x39, 0xE7, 0x4A, 0x48, 0x52, 0x69, 
+0x5A, 0xA9, 0x5A, 0xAA, 0x5A, 0xA9, 0x5A, 0xA9, 
+0x62, 0xEA, 0x63, 0x0A, 0x63, 0x0A, 0x62, 0xEA, 
+0x73, 0x4B, 0xA4, 0xD0, 0xA4, 0xAF, 0x9C, 0x4D, 
+0xBD, 0x71, 0xB5, 0x10, 0xB5, 0x11, 0xAC, 0xD1, 
+0xAC, 0xF1, 0xD6, 0x36, 0xCE, 0x15, 0xC5, 0xD4, 
+0xC5, 0xD4, 0x94, 0x6E, 0xAD, 0x11, 0x9C, 0xB0, 
+0xBD, 0xD4, 0xDE, 0xD8, 0xBD, 0x93, 0xC5, 0xD4, 
+0xC6, 0x15, 0xCE, 0x35, 0xAD, 0x52, 0xCE, 0x15, 
+0xBD, 0xB3, 0xAD, 0x10, 0xA4, 0x8E, 0x9C, 0x4D, 
+0xBD, 0x92, 0xBD, 0x93, 0xBD, 0x93, 0xBD, 0x93, 
+0xC5, 0xD4, 0xBD, 0x93, 0xC5, 0xD4, 0xB5, 0x73, 
+0xA4, 0xF1, 0xB5, 0x73, 0xBD, 0xB3, 0xBD, 0x92, 
+0xBD, 0x92, 0xC5, 0xF4, 0xC5, 0xD3, 0xBD, 0x93, 
+0xBD, 0x93, 0xC5, 0xB3, 0xCE, 0x34, 0xCE, 0x14, 
+0xD6, 0x14, 0xBD, 0x51, 0xB4, 0xEF, 0xEE, 0xB6, 
+0xE6, 0x75, 0xE6, 0x75, 0xEE, 0x95, 0xDD, 0xD3, 
+0xDD, 0xB3, 0xE6, 0x14, 0xF6, 0xD7, 0xDE, 0x55, 
+0x7B, 0x8C, 0x39, 0xA6, 0x39, 0xC6, 0x39, 0xC6, 
+0x4A, 0x48, 0x5A, 0xCB, 0x73, 0xAF, 0x94, 0xB3, 
+0xA5, 0x56, 0xB5, 0xD8, 0xBD, 0xF9, 0xCE, 0x7A, 
+0xDE, 0xBB, 0xEF, 0x5C, 0xB5, 0x54, 0xCD, 0xD4, 
+0xD5, 0xF4, 0xE6, 0x55, 0xDE, 0x34, 0xBD, 0x72, 
+0xBD, 0x52, 0xDE, 0x55, 0xE6, 0x96, 0xE6, 0x96, 
+0xDE, 0x35, 0xD6, 0x14, 0xDE, 0x14, 0xE6, 0x96, 
+0xDE, 0x55, 0x9C, 0x6F, 0x94, 0x50, 0xB5, 0x96, 
+0xB5, 0x76, 0xCE, 0x39, 0xDE, 0xDB, 0xDE, 0x9A, 
+0xAD, 0x33, 0xAD, 0x53, 0xAD, 0x12, 0x9C, 0xB1, 
+0x8C, 0x0E, 0x7B, 0xAD, 0x73, 0x4B, 0x6B, 0x4B, 
+0x6B, 0x4B, 0x6B, 0x2B, 0x5A, 0xA9, 0x52, 0x89, 
+0x7B, 0xAD, 0x31, 0x64, 0x41, 0xE7, 0x52, 0x68, 
+0x52, 0x88, 0x73, 0x6B, 0x9C, 0x90, 0x73, 0x4C, 
+0x41, 0xE6, 0x31, 0x85, 0x4A, 0x28, 0x5A, 0xCA, 
+0x5A, 0xCA, 0x42, 0x27, 0x42, 0x07, 0x5A, 0xCA, 
+0x6B, 0x4C, 0x5A, 0xCA, 0x6B, 0x4C, 0x73, 0x8E, 
+0x8C, 0x31, 0x9C, 0xD3, 0x73, 0x8F, 0x9C, 0xF4, 
+0xC6, 0x18, 0xDE, 0xBA, 0xD6, 0x7A, 0xBD, 0x96, 
+0xD6, 0x59, 0xDE, 0x79, 0xFF, 0xDE, 0xEF, 0x3C, 
+0xCD, 0xF7, 0xA4, 0xD3, 0x4A, 0x28, 0x42, 0x28, 
+0x39, 0xC6, 0x39, 0xC6, 0x31, 0xA6, 0x42, 0x48, 
+0x52, 0x89, 0x52, 0xAA, 0x5A, 0xEB, 0x52, 0xCA, 
+0x63, 0x0C, 0x6B, 0x4D, 0x73, 0x6E, 0x94, 0xB3, 
+0xB5, 0x96, 0xC6, 0x18, 0xB5, 0x75, 0x9C, 0x91, 
+0x9C, 0x8F, 0x9C, 0x8F, 0x9C, 0x8F, 0xA4, 0xB0, 
+0x9C, 0x6F, 0x9C, 0x8F, 0xA4, 0xD0, 0x9C, 0x90, 
+0xAD, 0x12, 0xBD, 0x73, 0xBD, 0xB4, 0xAD, 0x32, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xF1, 0xB5, 0x73, 
+0xD6, 0x56, 0xD6, 0x76, 0xD6, 0x55, 0xD6, 0x55, 
+0xC5, 0xF4, 0x9C, 0x90, 0x94, 0x70, 0x9C, 0xD1, 
+0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x12, 0x9C, 0xB0, 
+0x8C, 0x0D, 0xAC, 0xF1, 0x9C, 0x4E, 0xAC, 0xD0, 
+0xBD, 0x32, 0xC5, 0x73, 0xAC, 0xB0, 0xA4, 0x6F, 
+0x94, 0x4F, 0x8C, 0x2E, 0x9C, 0x6F, 0xAC, 0xF1, 
+0xC5, 0x92, 0xCD, 0x92, 0xCD, 0x92, 0xCD, 0x92, 
+0xC5, 0x71, 0xBD, 0x30, 0xAC, 0xCF, 0x73, 0x8B, 
+0x73, 0x4B, 0x73, 0x4B, 0x73, 0x4B, 0x7B, 0x6C, 
+0x8B, 0xED, 0xAC, 0xF1, 0x9C, 0xB0, 0xB5, 0x31, 
+0xA4, 0xF0, 0xA4, 0xD0, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xAD, 0x32, 0xB5, 0x72, 0xBD, 0x93, 
+0xBD, 0x73, 0xB5, 0x52, 0xBD, 0x92, 0xA4, 0xF0, 
+0xAC, 0xF0, 0xB5, 0x51, 0xBD, 0x72, 0xB5, 0x51, 
+0xC5, 0x71, 0xD5, 0xF3, 0xBD, 0x31, 0xB5, 0x31, 
+0xC5, 0x93, 0x9C, 0x90, 0xD6, 0x36, 0xDE, 0x77, 
+0xD6, 0x56, 0xDE, 0x77, 0xDE, 0x97, 0xE6, 0xB8, 
+0xDE, 0x77, 0xE6, 0x98, 0xC5, 0xB4, 0xB5, 0x53, 
+0xDE, 0x98, 0xE6, 0xB8, 0xD6, 0x56, 0xE6, 0x97, 
+0xEE, 0xD9, 0xE6, 0xB7, 0xEE, 0xF7, 0xE6, 0xB7, 
+0xE6, 0x76, 0xE6, 0x75, 0xDE, 0x75, 0xDE, 0x55, 
+0xDE, 0x55, 0xD6, 0x15, 0x9C, 0xB0, 0xAD, 0x33, 
+0xC5, 0xF6, 0xC5, 0xF6, 0xCE, 0x37, 0xBD, 0xD3, 
+0x8C, 0xEF, 0x8D, 0x2F, 0x7C, 0xCC, 0x6C, 0x4A, 
+0x74, 0x6B, 0x7C, 0xED, 0x95, 0x6F, 0x64, 0x29, 
+0x64, 0x49, 0x5B, 0xC8, 0x32, 0x04, 0x52, 0xE7, 
+0x84, 0x4B, 0x9D, 0x50, 0x53, 0x07, 0x3A, 0x85, 
+0x42, 0xC5, 0x53, 0x07, 0x4A, 0xC8, 0x63, 0x6A, 
+0x7C, 0x8E, 0x74, 0x0C, 0xB5, 0xF4, 0xD7, 0x18, 
+0x9D, 0x71, 0x4B, 0x27, 0x43, 0x05, 0x3A, 0xE4, 
+0x42, 0xE5, 0x4B, 0x46, 0x6C, 0x2A, 0x9D, 0xD1, 
+0xB6, 0x75, 0xB6, 0x95, 0xA5, 0x92, 0x63, 0x0A, 
+0x62, 0xCA, 0x83, 0xCE, 0x8C, 0x0F, 0x8C, 0x0F, 
+0x5A, 0xCA, 0x6B, 0x0B, 0x6B, 0x4B, 0x7B, 0x8C, 
+0x83, 0xCD, 0x83, 0xED, 0x8C, 0x0D, 0x8C, 0x0D, 
+0x8B, 0xED, 0x8B, 0xEC, 0x8C, 0x0D, 0x94, 0x2D, 
+0x94, 0x4E, 0x94, 0x4D, 0x94, 0x2C, 0x94, 0x2C, 
+0x94, 0x0C, 0x94, 0x2C, 0x94, 0x2D, 0x9C, 0x4E, 
+0x8C, 0x0C, 0x94, 0x2D, 0x94, 0x0C, 0x94, 0x0C, 
+0x94, 0x2D, 0x94, 0x4D, 0x9C, 0x6E, 0x94, 0x2D, 
+0x94, 0x4E, 0xAD, 0x31, 0xB5, 0x73, 0xB5, 0x52, 
+0xAD, 0x11, 0xA5, 0x11, 0xAC, 0xF0, 0xB5, 0x51, 
+0x9C, 0x6E, 0x94, 0x0C, 0xA4, 0x8E, 0xAC, 0xCF, 
+0xB5, 0x72, 0xC5, 0xD3, 0xBD, 0xD3, 0xBD, 0xB3, 
+0xCE, 0x35, 0xC5, 0xD4, 0xBD, 0x93, 0xBD, 0x93, 
+0xAD, 0x31, 0xB5, 0x72, 0xB5, 0x72, 0xBD, 0x92, 
+0xBD, 0x92, 0xB5, 0x92, 0xAD, 0x11, 0xA4, 0xF0, 
+0xA4, 0xD0, 0xB5, 0x72, 0xC5, 0xD3, 0xC5, 0xD3, 
+0xC5, 0xB2, 0xBD, 0x30, 0xBD, 0x30, 0xEE, 0xD7, 
+0xE6, 0x95, 0xE6, 0x75, 0xE6, 0x55, 0xE6, 0x14, 
+0xE5, 0xF3, 0xEE, 0x55, 0xEE, 0x95, 0xEE, 0xB6, 
+0xE6, 0x96, 0xAC, 0xD0, 0x4A, 0x27, 0x31, 0xA6, 
+0x39, 0xE7, 0x39, 0xE7, 0x4A, 0x69, 0x6B, 0x4D, 
+0x84, 0x51, 0x8C, 0x93, 0xB5, 0x97, 0xC6, 0x19, 
+0xDE, 0xFC, 0xEF, 0x3D, 0xB5, 0x96, 0xD6, 0x79, 
+0xC5, 0xD6, 0xCD, 0xF4, 0xD6, 0x14, 0xC5, 0x93, 
+0xD6, 0x15, 0xD6, 0x35, 0xDE, 0x35, 0xDE, 0x34, 
+0xDE, 0x34, 0xDE, 0x34, 0xD5, 0xF3, 0xD5, 0xB2, 
+0xD5, 0xF3, 0xD5, 0xF3, 0xB5, 0x31, 0x73, 0x6C, 
+0xAD, 0x55, 0xDE, 0xDB, 0xE6, 0xFC, 0xEF, 0x5D, 
+0xD6, 0x79, 0xB5, 0x33, 0xB5, 0x93, 0xB5, 0x73, 
+0xAD, 0x32, 0xAD, 0x12, 0x9C, 0xB1, 0x9C, 0x90, 
+0x9C, 0xB0, 0x94, 0x8F, 0x8C, 0x2E, 0x8C, 0x2F, 
+0x4A, 0x27, 0x4A, 0x48, 0x8C, 0x2F, 0x8C, 0x4F, 
+0x9C, 0xD1, 0xAD, 0x12, 0xAD, 0x32, 0x9C, 0xAF, 
+0xA4, 0xD0, 0x73, 0x6B, 0x63, 0x0A, 0x52, 0x68, 
+0x5A, 0xAA, 0x5A, 0xA9, 0x31, 0xA5, 0x39, 0xA6, 
+0x42, 0x07, 0x4A, 0x48, 0x6B, 0x4C, 0x73, 0x6D, 
+0x6B, 0x2C, 0x83, 0xF0, 0x83, 0xF0, 0x7B, 0xF0, 
+0x7B, 0xCF, 0x8C, 0x51, 0x94, 0xB3, 0xAD, 0x35, 
+0xE6, 0xDB, 0xDE, 0x9A, 0xEF, 0x1B, 0xEF, 0x5C, 
+0xC5, 0xD7, 0xDE, 0xBA, 0xAD, 0x34, 0x42, 0x08, 
+0x31, 0xA6, 0x39, 0xC6, 0x39, 0xE6, 0x39, 0xC6, 
+0x3A, 0x07, 0x4A, 0x48, 0x42, 0x48, 0x52, 0x8A, 
+0x5B, 0x0B, 0x6B, 0x6E, 0x7B, 0xD0, 0x9C, 0xB3, 
+0xAD, 0x76, 0xBD, 0xD7, 0xAD, 0x55, 0xC5, 0xD6, 
+0xCE, 0x17, 0xC5, 0x94, 0xBD, 0x94, 0xC5, 0xB4, 
+0xC5, 0x94, 0xBD, 0x93, 0xBD, 0x73, 0xB5, 0x32, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xD1, 0xA4, 0xD0, 
+0xA4, 0xD0, 0xA4, 0xD1, 0xA4, 0xD1, 0xAD, 0x11, 
+0xB5, 0x52, 0xBD, 0x52, 0xB5, 0x52, 0xB5, 0x11, 
+0xBD, 0x72, 0xA4, 0xF1, 0xAD, 0x12, 0xAC, 0xF2, 
+0xA4, 0xD1, 0x9C, 0xD1, 0x94, 0x4F, 0x8C, 0x0D, 
+0x94, 0x4F, 0xA4, 0xD0, 0x94, 0x0E, 0x93, 0xED, 
+0x94, 0x0D, 0xB5, 0x11, 0xBD, 0x52, 0xBD, 0x52, 
+0xB5, 0x32, 0xAD, 0x31, 0xB5, 0x52, 0xBD, 0x52, 
+0xC5, 0x72, 0xD5, 0xD3, 0xD5, 0xD2, 0xCD, 0xB2, 
+0xCD, 0x92, 0xC5, 0x72, 0x94, 0x4E, 0x6B, 0x2B, 
+0x62, 0xEA, 0x63, 0x0A, 0x63, 0x0A, 0x73, 0x4B, 
+0x94, 0x0D, 0xAD, 0x11, 0xA4, 0xD0, 0xBD, 0x72, 
+0xAD, 0x10, 0xAD, 0x11, 0xAD, 0x31, 0xB5, 0x72, 
+0xB5, 0x52, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x52, 
+0xB5, 0x52, 0xB5, 0x52, 0xBD, 0x92, 0xB5, 0x51, 
+0x9C, 0x8E, 0xB5, 0x31, 0xC5, 0xB3, 0xBD, 0x92, 
+0xBD, 0x71, 0xBD, 0x51, 0xCD, 0xB3, 0xB5, 0x31, 
+0xB5, 0x52, 0x9C, 0x90, 0xD6, 0x56, 0xDE, 0x76, 
+0xE6, 0x97, 0xE6, 0xD8, 0xBD, 0xB4, 0x94, 0x50, 
+0x9C, 0x91, 0xB5, 0x54, 0xBD, 0x95, 0xC5, 0xD6, 
+0xC5, 0xF5, 0xD6, 0x16, 0xDE, 0x56, 0xCE, 0x15, 
+0xBD, 0x94, 0xC5, 0xD5, 0xE6, 0x96, 0xDE, 0x35, 
+0xE6, 0x96, 0xE6, 0x96, 0xDE, 0x75, 0xDE, 0x34, 
+0xD6, 0x14, 0xB5, 0x32, 0xB5, 0x74, 0xCE, 0x58, 
+0xC5, 0xF7, 0x9C, 0xB2, 0xE6, 0xD8, 0xE6, 0xD7, 
+0xB5, 0xD2, 0x8D, 0x2E, 0x7C, 0xCD, 0x85, 0x0D, 
+0x8D, 0x2E, 0x8D, 0x4F, 0x95, 0x70, 0x64, 0x09, 
+0x4B, 0x67, 0x21, 0xA3, 0x19, 0x03, 0x29, 0x64, 
+0x21, 0x63, 0x63, 0x8A, 0x7C, 0xAC, 0x5B, 0xC9, 
+0x32, 0x84, 0x42, 0xA6, 0x7C, 0x6C, 0x74, 0x4C, 
+0x9D, 0xB1, 0xA5, 0xD2, 0x8C, 0xEE, 0x6C, 0x2B, 
+0x2A, 0x24, 0x53, 0x88, 0x53, 0xA7, 0x4B, 0x66, 
+0x53, 0x87, 0x63, 0xA8, 0x8C, 0xEE, 0x74, 0x4C, 
+0x7C, 0x8D, 0x85, 0x2F, 0x84, 0xEE, 0x9C, 0xF0, 
+0xC5, 0xB5, 0xAC, 0xF2, 0x83, 0x8D, 0x7B, 0x4C, 
+0x63, 0x0A, 0x7B, 0x8C, 0x83, 0xCD, 0x83, 0xCD, 
+0x94, 0x6F, 0xB5, 0x52, 0xBD, 0xD3, 0xC5, 0xF4, 
+0xBD, 0x92, 0xA4, 0x8E, 0x94, 0x0C, 0xA4, 0xCF, 
+0xB5, 0x31, 0xC5, 0x93, 0xB5, 0x10, 0xAC, 0xCF, 
+0xB4, 0xEF, 0xAC, 0xAF, 0xB4, 0xEF, 0xAC, 0xCF, 
+0x9C, 0x6E, 0x9C, 0x4D, 0xA4, 0xAE, 0xB5, 0x0F, 
+0xAC, 0xEF, 0xB5, 0x10, 0xAC, 0xEF, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xA4, 0x8E, 0x9C, 0x6D, 0x9C, 0x4D, 
+0x94, 0x2D, 0x94, 0x2C, 0x8B, 0xEC, 0x8B, 0xCB, 
+0x94, 0x0C, 0x94, 0x2D, 0x9C, 0x2D, 0x8B, 0xEB, 
+0x8B, 0xCB, 0x83, 0xAB, 0x83, 0xAB, 0x83, 0xAB, 
+0x83, 0xCC, 0x83, 0xCB, 0x83, 0xCC, 0x94, 0x0D, 
+0x9C, 0x8E, 0x94, 0x2D, 0x8C, 0x0C, 0x9C, 0x6E, 
+0x94, 0x2D, 0x83, 0xCB, 0x7B, 0x8B, 0x83, 0xED, 
+0x94, 0x6E, 0xBD, 0x93, 0xCE, 0x14, 0xD6, 0x35, 
+0xD6, 0x55, 0xBD, 0x51, 0xC5, 0x70, 0xF6, 0xF7, 
+0xEE, 0xB6, 0xE6, 0x75, 0xDD, 0xF4, 0xDD, 0x93, 
+0xDD, 0xB3, 0xEE, 0x55, 0xE6, 0x75, 0xE6, 0x75, 
+0xE6, 0x75, 0xEE, 0x96, 0xD5, 0xF4, 0x73, 0x2A, 
+0x41, 0xE6, 0x39, 0xC6, 0x39, 0xE7, 0x4A, 0x28, 
+0x5A, 0xCB, 0x73, 0xAF, 0x9C, 0xF4, 0xAD, 0x97, 
+0xC6, 0x5A, 0xD6, 0x7B, 0xB5, 0x97, 0xC6, 0x39, 
+0xE7, 0x3C, 0xEF, 0x3B, 0xDE, 0xB8, 0xCD, 0xD4, 
+0xCD, 0xD3, 0xCD, 0xD3, 0xD5, 0xF4, 0xDE, 0x55, 
+0xE6, 0x75, 0xE6, 0x54, 0xE6, 0x34, 0xE6, 0x14, 
+0xE6, 0x34, 0xE6, 0x34, 0xE6, 0x35, 0x8B, 0xED, 
+0x9C, 0xF3, 0xC6, 0x18, 0xD6, 0x9A, 0xE6, 0xFC, 
+0xEF, 0x5D, 0xBD, 0xD6, 0xB5, 0x73, 0xB5, 0x52, 
+0xAD, 0x12, 0xA4, 0xF1, 0xA4, 0xF1, 0xA4, 0xF1, 
+0xAD, 0x12, 0xAD, 0x32, 0xAD, 0x53, 0x84, 0x0F, 
+0x31, 0x85, 0x9C, 0xD1, 0xB5, 0x53, 0xAD, 0x32, 
+0xA4, 0xF2, 0x9C, 0xD1, 0xB5, 0x73, 0xBD, 0x72, 
+0xB5, 0x10, 0x83, 0xAC, 0x73, 0x8C, 0x84, 0x0E, 
+0x52, 0x68, 0x5A, 0xA9, 0x42, 0x27, 0x39, 0xC6, 
+0x39, 0xA6, 0x42, 0x07, 0x4A, 0x48, 0x6B, 0x2C, 
+0x6B, 0x4D, 0x5A, 0xCB, 0x5A, 0xEB, 0x73, 0x6E, 
+0x7B, 0xAF, 0x6B, 0x4E, 0x9C, 0x92, 0xAD, 0x34, 
+0x9C, 0xB3, 0x9C, 0xB2, 0x9C, 0xB2, 0xBD, 0x75, 
+0x8C, 0x10, 0xAD, 0x34, 0xD6, 0xBA, 0x5A, 0xCB, 
+0x42, 0x07, 0x31, 0xC6, 0x39, 0xC6, 0x39, 0xE7, 
+0x42, 0x28, 0x42, 0x27, 0x4A, 0x48, 0x5A, 0xEB, 
+0x63, 0x4D, 0x7B, 0xCF, 0x8C, 0x51, 0x94, 0x72, 
+0x9C, 0xD3, 0xA5, 0x35, 0xBD, 0xF8, 0xCE, 0x39, 
+0xC5, 0xF7, 0xAD, 0x12, 0xB5, 0x12, 0xAC, 0xF1, 
+0xB5, 0x32, 0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x53, 
+0xBD, 0x73, 0xC5, 0xD4, 0xCD, 0xF5, 0xC5, 0xD4, 
+0xC5, 0xB4, 0xC5, 0xD4, 0xC5, 0xB4, 0xBD, 0x73, 
+0xB5, 0x52, 0xB5, 0x11, 0xC5, 0x93, 0xBD, 0x53, 
+0xB5, 0x52, 0xBD, 0x93, 0xBD, 0x93, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD5, 0xC5, 0xB4, 0xB5, 0x53, 
+0xB5, 0x53, 0xAC, 0xF1, 0x9C, 0x6F, 0x9C, 0x70, 
+0x9C, 0x6F, 0xA4, 0xB0, 0xA4, 0xAF, 0xB5, 0x11, 
+0xB5, 0x11, 0xAC, 0xCF, 0xB5, 0x10, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xBD, 0x31, 0xBD, 0x30, 0xBD, 0x10, 
+0xBD, 0x30, 0xB5, 0x10, 0x8B, 0xED, 0x73, 0x4B, 
+0x73, 0x6C, 0x73, 0x4B, 0x73, 0x2B, 0x7B, 0x6B, 
+0x94, 0x2D, 0xAD, 0x11, 0x9C, 0x8F, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xBD, 0x93, 0xBD, 0x73, 0xBD, 0x93, 
+0xBD, 0x93, 0xBD, 0x92, 0xBD, 0x93, 0xB5, 0x52, 
+0xB5, 0x72, 0xBD, 0x93, 0xBD, 0x93, 0xBD, 0x92, 
+0x94, 0x6D, 0xBD, 0x92, 0xD6, 0x14, 0xCD, 0xF4, 
+0xCD, 0xD3, 0xCD, 0xD4, 0xDE, 0x55, 0xB5, 0x51, 
+0xA4, 0xD0, 0x9C, 0x90, 0xD6, 0x36, 0xEE, 0xD7, 
+0xE6, 0xB7, 0xEE, 0xF8, 0x8C, 0x2F, 0x5A, 0xCB, 
+0x6B, 0x4C, 0x94, 0xB2, 0x9C, 0xB2, 0xC5, 0xD6, 
+0xE6, 0xB9, 0xDE, 0x99, 0xE6, 0xB9, 0xC5, 0xF6, 
+0x8C, 0x10, 0x9C, 0xD2, 0xBD, 0x73, 0xB5, 0x31, 
+0xAC, 0xF1, 0xB5, 0x11, 0xD6, 0x15, 0xDE, 0x55, 
+0xCD, 0xB3, 0xCE, 0x16, 0xC5, 0xF7, 0x9C, 0xF3, 
+0xAD, 0x13, 0xE6, 0xD9, 0xE6, 0xB7, 0xE6, 0xB6, 
+0xE7, 0x17, 0xCE, 0x95, 0x8D, 0x0E, 0x85, 0x0E, 
+0x85, 0x2E, 0x8D, 0x6F, 0x85, 0x0E, 0x74, 0x8B, 
+0x32, 0x65, 0x29, 0x84, 0x21, 0x44, 0x29, 0x85, 
+0x29, 0xA5, 0x29, 0xA4, 0x5B, 0xA9, 0x6C, 0x8B, 
+0x5B, 0xE9, 0x32, 0x84, 0x63, 0xCA, 0x42, 0xC6, 
+0x32, 0x65, 0x5B, 0xAA, 0x74, 0x6C, 0x6C, 0x4B, 
+0x43, 0x07, 0x5B, 0xE9, 0x5C, 0x09, 0x5B, 0xE8, 
+0x63, 0xE9, 0x5B, 0x89, 0x5B, 0x29, 0x5B, 0x29, 
+0x52, 0xC8, 0x7C, 0x4E, 0xA5, 0x91, 0xAD, 0x92, 
+0xA5, 0x11, 0x8C, 0x0E, 0x7B, 0x4C, 0x73, 0x0A, 
+0x6B, 0x0B, 0x6B, 0x2B, 0x6B, 0x6B, 0x83, 0xED, 
+0x8C, 0x2E, 0x94, 0x8E, 0xA5, 0x10, 0xB5, 0x51, 
+0xB5, 0x51, 0xB5, 0x31, 0xC5, 0xB3, 0xDE, 0x96, 
+0xC5, 0xF4, 0xBD, 0xB3, 0xC5, 0xB3, 0xBD, 0x91, 
+0xDE, 0x75, 0xD6, 0x34, 0xD6, 0x14, 0xCD, 0xF3, 
+0xD6, 0x14, 0xAC, 0xAF, 0xBD, 0x71, 0xEE, 0xB6, 
+0xD5, 0xF3, 0xCD, 0xD2, 0xC5, 0x91, 0xCD, 0xD2, 
+0xDE, 0x54, 0xDE, 0x34, 0xD5, 0xF3, 0xD6, 0x34, 
+0xCD, 0xB2, 0xB5, 0x10, 0xC5, 0x71, 0xC5, 0x71, 
+0xB5, 0x10, 0xD5, 0xF3, 0xCD, 0xD2, 0xC5, 0x92, 
+0xBD, 0x30, 0xBD, 0x51, 0xC5, 0x71, 0xBD, 0x30, 
+0xB5, 0x10, 0xB5, 0x10, 0xAC, 0xCF, 0xAC, 0xAF, 
+0xAC, 0xAE, 0xAC, 0xAE, 0xAC, 0xCF, 0xAC, 0xAE, 
+0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x6E, 0x9C, 0x6E, 
+0x94, 0x4D, 0x94, 0x0C, 0x94, 0x2D, 0x9C, 0x6E, 
+0xA4, 0xAE, 0xA4, 0x6D, 0xA4, 0x4C, 0xBD, 0x30, 
+0xBD, 0x51, 0xBD, 0x31, 0xB4, 0xAF, 0xA4, 0x2D, 
+0xAC, 0x8E, 0xBD, 0x10, 0xBD, 0x10, 0xBD, 0x10, 
+0xD5, 0xF4, 0xDE, 0x14, 0xDE, 0x34, 0xB5, 0x10, 
+0x83, 0xAB, 0x4A, 0x06, 0x42, 0x07, 0x42, 0x07, 
+0x42, 0x28, 0x5A, 0xCB, 0x73, 0xAE, 0x94, 0xB3, 
+0xAD, 0x96, 0x9C, 0xF4, 0xB5, 0xB7, 0xE7, 0x1C, 
+0xD6, 0x9A, 0xBD, 0xF7, 0xC6, 0x38, 0xCE, 0x17, 
+0xCD, 0xF5, 0xDE, 0x35, 0xE6, 0x96, 0xEE, 0x96, 
+0xEE, 0x75, 0xEE, 0x75, 0xE6, 0x54, 0xE6, 0x34, 
+0xDE, 0x13, 0xDD, 0xF3, 0xE6, 0x55, 0xB4, 0xF0, 
+0x7B, 0xAD, 0xA5, 0x14, 0xCE, 0x5A, 0xD6, 0x9A, 
+0xDE, 0xBB, 0xCE, 0x58, 0x9C, 0xD1, 0xAD, 0x12, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xA4, 0xF1, 0x9C, 0xD1, 
+0x9C, 0xD1, 0xA4, 0xD1, 0xA4, 0xF1, 0x52, 0x68, 
+0x6B, 0x2C, 0xB5, 0x74, 0xAD, 0x32, 0xA5, 0x12, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xAD, 0x52, 0xBD, 0x72, 
+0xB5, 0x10, 0x8C, 0x0D, 0x83, 0xCC, 0xAD, 0x31, 
+0x9C, 0x8F, 0x73, 0x6B, 0x4A, 0x27, 0x31, 0x85, 
+0x39, 0xE6, 0x42, 0x07, 0x52, 0x69, 0x4A, 0x48, 
+0x5A, 0xAA, 0x5A, 0xAA, 0x5A, 0xAB, 0x5A, 0xCB, 
+0x7B, 0xCF, 0x84, 0x10, 0xBD, 0x96, 0xC5, 0xD7, 
+0xB5, 0x34, 0xAD, 0x14, 0x94, 0x71, 0xAD, 0x13, 
+0x94, 0x51, 0x52, 0x8A, 0xAD, 0x35, 0xAD, 0x55, 
+0x42, 0x07, 0x31, 0xA6, 0x31, 0xC6, 0x39, 0xE7, 
+0x42, 0x27, 0x4A, 0x48, 0x52, 0x89, 0x63, 0x0C, 
+0x73, 0x8E, 0x73, 0x8E, 0x7B, 0xEF, 0x73, 0x8E, 
+0x7B, 0xF0, 0x94, 0x92, 0xB5, 0x76, 0xAD, 0x55, 
+0xAD, 0x55, 0x94, 0x2F, 0xAC, 0xF1, 0x83, 0xEE, 
+0x83, 0xEE, 0x6B, 0x4C, 0x63, 0x0A, 0x63, 0x0A, 
+0x6B, 0x4B, 0x6B, 0x2B, 0x6B, 0x2B, 0x6B, 0x2B, 
+0x73, 0x6C, 0x7B, 0xAD, 0x8C, 0x0E, 0x94, 0x4F, 
+0x9C, 0x6F, 0xA4, 0xD0, 0xC5, 0xD4, 0xDE, 0x97, 
+0xD6, 0x56, 0xAC, 0xF1, 0xA4, 0xD0, 0xA4, 0xAF, 
+0x9C, 0x8F, 0xAC, 0xF0, 0xB5, 0x32, 0xB5, 0x52, 
+0xAD, 0x11, 0xA4, 0xB0, 0xB4, 0xF0, 0xB5, 0x10, 
+0xAC, 0xF0, 0xAC, 0xF1, 0xAC, 0xD0, 0xB5, 0x11, 
+0xB5, 0x32, 0xB5, 0x11, 0xAC, 0xF0, 0xA4, 0xAF, 
+0xAC, 0xCF, 0xA4, 0xAF, 0xAC, 0xD0, 0xAC, 0xD0, 
+0xAC, 0xF0, 0xAC, 0xF1, 0xB4, 0xF1, 0xAC, 0xF1, 
+0xA4, 0xB0, 0x9C, 0x6F, 0x8B, 0xEE, 0x8C, 0x0D, 
+0xA4, 0xB0, 0xAD, 0x12, 0xA4, 0xB0, 0x94, 0x4E, 
+0x8B, 0xED, 0x8B, 0xED, 0x8C, 0x0D, 0x8B, 0xED, 
+0x8C, 0x0D, 0x8C, 0x0D, 0x94, 0x2E, 0x94, 0x2E, 
+0x8C, 0x0D, 0x83, 0xED, 0x83, 0xEC, 0x94, 0x2D, 
+0x9C, 0xAF, 0xA4, 0xD0, 0xB5, 0x11, 0xBD, 0x72, 
+0xB5, 0x11, 0xA4, 0xAF, 0xBD, 0x92, 0xC5, 0xD3, 
+0x9C, 0x8F, 0x9C, 0x90, 0xC5, 0xD4, 0xF7, 0x18, 
+0xE6, 0xB7, 0xE6, 0x96, 0x9C, 0x70, 0x62, 0xCA, 
+0x5A, 0x89, 0x6B, 0x4C, 0x7B, 0xAE, 0xBD, 0x75, 
+0xCE, 0x17, 0xAD, 0x14, 0x8C, 0x51, 0x83, 0xEF, 
+0xBD, 0x96, 0xDE, 0xBA, 0xE6, 0xBA, 0xCD, 0xD6, 
+0xB5, 0x54, 0xA4, 0xB1, 0x8C, 0x0F, 0xAD, 0x13, 
+0xCE, 0x17, 0xA5, 0x14, 0x73, 0xAF, 0xD6, 0x78, 
+0xEF, 0x19, 0xEE, 0xD7, 0xE6, 0xB6, 0xE6, 0xB6, 
+0xE6, 0xD6, 0xE6, 0xF7, 0xCE, 0x95, 0x95, 0x2F, 
+0x85, 0x0E, 0x8D, 0x6F, 0x74, 0xCC, 0x74, 0x8B, 
+0x32, 0x04, 0x3A, 0x27, 0x3A, 0x07, 0x31, 0xC6, 
+0x31, 0xA5, 0x31, 0xE6, 0x32, 0x24, 0x5B, 0xE8, 
+0x64, 0x2A, 0x4B, 0x47, 0x32, 0x24, 0x42, 0x85, 
+0x29, 0xE3, 0x19, 0xA2, 0x3A, 0x85, 0x74, 0xAC, 
+0x53, 0x88, 0x53, 0xA8, 0x5B, 0xC8, 0x43, 0x05, 
+0x3A, 0xA4, 0x3A, 0x85, 0x5B, 0x28, 0x7C, 0x4D, 
+0x7C, 0x4D, 0xA5, 0x72, 0x9C, 0xF0, 0x94, 0x6F, 
+0x8C, 0x0E, 0x6B, 0x0A, 0x5A, 0x48, 0x6A, 0xA9, 
+0x62, 0xEA, 0x73, 0x8C, 0x7B, 0xAC, 0x94, 0x8F, 
+0x9C, 0xD0, 0x9C, 0xCF, 0x9C, 0xCF, 0xAD, 0x10, 
+0xA4, 0xF0, 0xA4, 0xF0, 0x94, 0x6E, 0xC5, 0xD4, 
+0xAD, 0x32, 0xB5, 0x52, 0xAD, 0x10, 0xAD, 0x10, 
+0xD6, 0x14, 0xCD, 0xF3, 0xCD, 0xF3, 0xBD, 0x91, 
+0xDE, 0x96, 0xAC, 0xAE, 0xC5, 0x71, 0xE6, 0x95, 
+0xE6, 0x74, 0xE6, 0x74, 0xE6, 0x95, 0xE6, 0x95, 
+0xE6, 0x95, 0xE6, 0x75, 0xDE, 0x34, 0xE6, 0x95, 
+0xDE, 0x75, 0xD6, 0x13, 0xE6, 0x54, 0xE6, 0x74, 
+0xD6, 0x13, 0xEE, 0xB5, 0xE6, 0x74, 0xE6, 0x95, 
+0xE6, 0x54, 0xD5, 0xF2, 0xE6, 0x95, 0xC5, 0x70, 
+0xCD, 0xB1, 0xB5, 0x0F, 0xB4, 0xEF, 0xDE, 0x34, 
+0xCD, 0x92, 0xBD, 0x30, 0xB5, 0x30, 0xB5, 0x0F, 
+0xBD, 0x50, 0xBD, 0x30, 0xB5, 0x0F, 0xBD, 0x30, 
+0xBD, 0x10, 0xBD, 0x30, 0xBD, 0x30, 0xB5, 0x10, 
+0xB4, 0xEF, 0xBD, 0x30, 0xBD, 0x30, 0xB4, 0xCF, 
+0xAC, 0xAE, 0xAC, 0x8E, 0x9C, 0x4D, 0x9C, 0x4D, 
+0x9C, 0x4D, 0x9C, 0x4D, 0x9C, 0x4D, 0x9C, 0x2D, 
+0x93, 0xEB, 0x8B, 0xCB, 0x8B, 0xCB, 0x8B, 0xAA, 
+0x8B, 0xAA, 0x7B, 0x4A, 0x52, 0x47, 0x39, 0xC6, 
+0x39, 0xE7, 0x42, 0x28, 0x52, 0xAA, 0x6B, 0x8E, 
+0x84, 0x31, 0x94, 0xB3, 0xBD, 0xD7, 0xC6, 0x18, 
+0x84, 0x10, 0x8C, 0x51, 0x8C, 0x51, 0x73, 0x8E, 
+0xAC, 0xF2, 0xC5, 0x93, 0xCD, 0xB3, 0xDE, 0x34, 
+0xE6, 0x34, 0xE6, 0x54, 0xEE, 0x95, 0xEE, 0xB5, 
+0xEE, 0x95, 0xEE, 0x75, 0xE6, 0x34, 0xB4, 0xCF, 
+0xA4, 0xB0, 0x84, 0x10, 0xBD, 0xF7, 0xC6, 0x38, 
+0x94, 0x92, 0xB5, 0x96, 0xC5, 0xF8, 0xB5, 0x55, 
+0xAD, 0x33, 0xB5, 0x73, 0xAD, 0x32, 0xA4, 0xD1, 
+0xA4, 0xD1, 0x9C, 0xB0, 0x7B, 0xCD, 0x29, 0x44, 
+0x9C, 0xB1, 0xAD, 0x12, 0xAD, 0x12, 0xAD, 0x32, 
+0x9C, 0xD1, 0x9C, 0xD0, 0x9C, 0xB0, 0xAC, 0xF0, 
+0xAC, 0xCF, 0xAC, 0xF0, 0xAC, 0xF0, 0xB5, 0x52, 
+0xBD, 0x72, 0xB5, 0x31, 0x83, 0xCD, 0x4A, 0x27, 
+0x42, 0x07, 0x4A, 0x28, 0x52, 0x69, 0x5A, 0xAA, 
+0x73, 0x8D, 0x5A, 0xCA, 0x5A, 0xCA, 0x52, 0x89, 
+0x6B, 0x4D, 0xA4, 0xD3, 0xAD, 0x14, 0xB5, 0x34, 
+0xD6, 0x18, 0xD6, 0x18, 0xC5, 0x96, 0x94, 0x71, 
+0x9C, 0xB3, 0x73, 0x8E, 0xB5, 0xB6, 0xBD, 0xD6, 
+0x52, 0xAA, 0x39, 0xC6, 0x31, 0xA6, 0x39, 0xC6, 
+0x42, 0x07, 0x42, 0x28, 0x5A, 0xCA, 0x73, 0xAE, 
+0x6B, 0x2C, 0x52, 0xAA, 0x52, 0xAA, 0x63, 0x0C, 
+0x6B, 0x6D, 0x8C, 0x51, 0x84, 0x31, 0xA5, 0x14, 
+0xB5, 0x96, 0xA4, 0xF3, 0xAD, 0x33, 0x9C, 0x90, 
+0xBD, 0x94, 0xB5, 0x73, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x73, 0xAD, 0x32, 0x9C, 0xB1, 0x8C, 0x4F, 
+0x8C, 0x2E, 0x8C, 0x2E, 0x8C, 0x2F, 0x9C, 0x90, 
+0x8C, 0x2F, 0xA4, 0xF1, 0xBD, 0x94, 0xBD, 0xD4, 
+0xD6, 0x77, 0xA4, 0xF1, 0x9C, 0xAF, 0xA4, 0xD0, 
+0xA4, 0xD0, 0x8C, 0x0D, 0x8C, 0x0D, 0x94, 0x6E, 
+0xB5, 0x31, 0x94, 0x2D, 0xBD, 0x30, 0xCD, 0xD2, 
+0xCD, 0xB2, 0xAC, 0xB0, 0xB5, 0x32, 0x9C, 0x8F, 
+0x94, 0x0D, 0xA4, 0xCF, 0xAD, 0x11, 0xAC, 0xF0, 
+0xAC, 0xF1, 0x9C, 0x4E, 0x9C, 0x6F, 0xB5, 0x32, 
+0xC5, 0xD4, 0xBD, 0x72, 0xC5, 0xB4, 0xC5, 0xD4, 
+0xCD, 0xF5, 0xCE, 0x15, 0xCD, 0xD4, 0xBD, 0x93, 
+0x9C, 0x8F, 0xAD, 0x11, 0xBD, 0x52, 0xBD, 0x52, 
+0xB5, 0x32, 0xB5, 0x32, 0xB5, 0x53, 0xAD, 0x32, 
+0xAD, 0x11, 0xA4, 0xF1, 0xA4, 0xF1, 0xAD, 0x12, 
+0xAD, 0x12, 0xA4, 0xD1, 0xA4, 0xB0, 0xA4, 0x90, 
+0x9C, 0x8F, 0x9C, 0x6F, 0x94, 0x4F, 0x8C, 0x0E, 
+0x94, 0x0E, 0x94, 0x0E, 0x94, 0x2E, 0x94, 0x0D, 
+0x83, 0xCD, 0x8C, 0x0E, 0x94, 0x2F, 0xAD, 0x11, 
+0xB5, 0x12, 0xB5, 0x31, 0xB5, 0x32, 0xAC, 0xF2, 
+0x8C, 0x2F, 0x5A, 0xCA, 0x5A, 0xAA, 0x9C, 0x92, 
+0x94, 0x51, 0x9C, 0xB2, 0x7B, 0xCE, 0x5A, 0xCB, 
+0xC5, 0xF7, 0xCE, 0x38, 0xD6, 0x59, 0xD6, 0x79, 
+0xEF, 0x3C, 0xDE, 0xBA, 0xD6, 0xBA, 0xE6, 0xFC, 
+0xC6, 0x18, 0x9C, 0xD3, 0xAD, 0x54, 0xDE, 0x97, 
+0xEE, 0xD7, 0xEE, 0xF7, 0xEE, 0xF7, 0xEE, 0xF7, 
+0xEE, 0xF7, 0xEE, 0xF7, 0xF7, 0x17, 0xCE, 0x75, 
+0x84, 0xEE, 0x95, 0x6F, 0x7C, 0xCD, 0x5B, 0xA9, 
+0x31, 0xC5, 0x42, 0x07, 0x42, 0x28, 0x52, 0x89, 
+0x52, 0xAA, 0x42, 0x47, 0x29, 0xE5, 0x4B, 0x47, 
+0x6C, 0x8B, 0x63, 0xEA, 0x52, 0xC6, 0x7C, 0x09, 
+0x53, 0x46, 0x2A, 0x44, 0x19, 0xA2, 0x4B, 0x27, 
+0x64, 0x09, 0x32, 0xA3, 0x32, 0xC4, 0x3A, 0xC3, 
+0x3A, 0xC4, 0x4B, 0x46, 0x74, 0x8B, 0x8D, 0x2D, 
+0x84, 0xCC, 0x6C, 0x09, 0x6B, 0xA9, 0x6B, 0x49, 
+0x62, 0xA9, 0x49, 0xC6, 0x52, 0x27, 0x7B, 0x4B, 
+0x6B, 0x4B, 0x7B, 0xAC, 0x83, 0xED, 0x9C, 0xD0, 
+0xAD, 0x32, 0xAD, 0x31, 0xA5, 0x10, 0xAD, 0x31, 
+0x9C, 0xAF, 0x94, 0x6E, 0x84, 0x0D, 0xAD, 0x32, 
+0xB5, 0x53, 0xA5, 0x11, 0xA5, 0x10, 0xB5, 0x71, 
+0xCD, 0xF3, 0xCD, 0xF3, 0xC5, 0x92, 0xAC, 0xEF, 
+0xCE, 0x14, 0xA4, 0x8E, 0xBD, 0x50, 0xE6, 0x75, 
+0xE6, 0x74, 0xEE, 0xB5, 0xE6, 0x74, 0xE6, 0x74, 
+0xE6, 0x74, 0xE6, 0xB6, 0xE6, 0x95, 0xE6, 0x95, 
+0xE6, 0x95, 0xDE, 0x54, 0xE6, 0x74, 0xDE, 0x54, 
+0xDE, 0x13, 0xDE, 0x33, 0xD5, 0xF2, 0xDE, 0x33, 
+0xDE, 0x13, 0xD5, 0xD2, 0xE6, 0x74, 0xE6, 0x53, 
+0xE6, 0x95, 0xAC, 0xCE, 0xCD, 0x92, 0xCD, 0x72, 
+0xB4, 0xEF, 0xAC, 0xCF, 0xB5, 0x30, 0xC5, 0x72, 
+0xD5, 0xD3, 0xC5, 0x71, 0xB4, 0xEF, 0xC5, 0x71, 
+0xC5, 0x71, 0xC5, 0x71, 0xC5, 0x71, 0xC5, 0x71, 
+0xC5, 0x91, 0xCD, 0x92, 0xCD, 0x91, 0xC5, 0x51, 
+0xCD, 0xB2, 0xD6, 0x14, 0xBD, 0x51, 0xBD, 0x31, 
+0xDE, 0x14, 0xAC, 0xAE, 0xCD, 0xB2, 0xEE, 0x95, 
+0xDE, 0x34, 0xDE, 0x34, 0xCD, 0xD3, 0xBD, 0x51, 
+0xCD, 0xB3, 0xD5, 0xF4, 0xCD, 0xD4, 0x94, 0x2D, 
+0x41, 0xE6, 0x42, 0x28, 0x52, 0x89, 0x63, 0x0C, 
+0x63, 0x2C, 0x73, 0xAF, 0x94, 0xB3, 0x73, 0x6E, 
+0x7B, 0xCF, 0x6B, 0x4D, 0x7B, 0xAE, 0x73, 0xAE, 
+0x9C, 0xB2, 0xEF, 0x1B, 0xBD, 0x54, 0x94, 0x0D, 
+0x9C, 0x0C, 0xA4, 0x4D, 0xA4, 0x4D, 0xA4, 0x6D, 
+0xAC, 0x8E, 0xAC, 0xAE, 0xB4, 0xCF, 0xB4, 0xEF, 
+0xB5, 0x31, 0x8C, 0x0E, 0x8C, 0x51, 0xA5, 0x14, 
+0xBD, 0xD7, 0xDE, 0xFC, 0xE7, 0x1C, 0xC6, 0x18, 
+0xBD, 0xB5, 0xBD, 0x74, 0xBD, 0x72, 0xB5, 0x72, 
+0xC5, 0xD4, 0xB5, 0x53, 0x6B, 0x4B, 0x4A, 0x48, 
+0xBD, 0xD4, 0xD6, 0x56, 0xCD, 0xF4, 0xB5, 0x32, 
+0x94, 0x4E, 0x8C, 0x2E, 0x8C, 0x2E, 0xB5, 0x31, 
+0xAC, 0xEF, 0xC5, 0xB3, 0xB5, 0x51, 0xB5, 0x51, 
+0xBD, 0x72, 0xC5, 0xD4, 0xBD, 0x93, 0xAD, 0x32, 
+0x63, 0x0A, 0x52, 0x88, 0x4A, 0x68, 0x52, 0x69, 
+0x63, 0x0B, 0x6B, 0x2B, 0x63, 0x0B, 0x42, 0x07, 
+0x52, 0x68, 0x83, 0xAE, 0xAD, 0x14, 0x9C, 0x72, 
+0xDE, 0x59, 0xEE, 0xDB, 0xA4, 0x92, 0x8B, 0xEF, 
+0x9C, 0xB2, 0xAD, 0x55, 0xAD, 0x54, 0xC5, 0xF7, 
+0xC5, 0xF7, 0x5A, 0xCB, 0x39, 0xE7, 0x39, 0xE7, 
+0x41, 0xE7, 0x4A, 0x48, 0x63, 0x2C, 0x5A, 0xCA, 
+0x4A, 0x69, 0x52, 0x89, 0x52, 0xCA, 0x63, 0x2C, 
+0x73, 0x6E, 0x73, 0xAF, 0x8C, 0x72, 0xAD, 0x55, 
+0xBD, 0xD7, 0xCE, 0x38, 0x94, 0x70, 0x9C, 0xB1, 
+0xCE, 0x36, 0xCE, 0x15, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xCE, 0x15, 0xCE, 0x15, 0xCD, 0xF5, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xD4, 0xBD, 0x93, 
+0xAD, 0x32, 0xC5, 0xD4, 0xC5, 0xF5, 0xC5, 0xD4, 
+0xCE, 0x15, 0xA4, 0xD0, 0xAD, 0x11, 0xBD, 0xB3, 
+0xB5, 0x72, 0x9C, 0xAF, 0x9C, 0x8F, 0x94, 0x6E, 
+0xA4, 0xCF, 0xAC, 0xCF, 0xAC, 0xEF, 0xC5, 0x70, 
+0xC5, 0x91, 0xAC, 0xF0, 0xB5, 0x52, 0x9C, 0xAF, 
+0x9C, 0xAF, 0xAD, 0x11, 0xAC, 0xF0, 0xAD, 0x11, 
+0xAD, 0x11, 0xAC, 0xF1, 0x9C, 0xAF, 0x9C, 0xAF, 
+0xA4, 0xF0, 0x9C, 0xAF, 0xA4, 0xB0, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xB5, 0x52, 0xBD, 0x73, 0xB5, 0x31, 
+0xAD, 0x10, 0xB5, 0x31, 0xAC, 0xF0, 0xC5, 0x92, 
+0xD6, 0x14, 0x9C, 0x8F, 0xA4, 0xB0, 0xAD, 0x11, 
+0xB5, 0x52, 0xB5, 0x32, 0xA4, 0xB0, 0xAD, 0x11, 
+0xBD, 0x93, 0xAD, 0x12, 0xBD, 0x93, 0xC5, 0xB4, 
+0xB5, 0x52, 0xAC, 0xF1, 0xA4, 0xF1, 0x8C, 0x0E, 
+0x9C, 0x90, 0xAC, 0xF1, 0xAC, 0xD1, 0xAC, 0xF1, 
+0xAD, 0x11, 0xAD, 0x32, 0xAD, 0x12, 0xAD, 0x12, 
+0xAD, 0x12, 0xAD, 0x12, 0xB5, 0x33, 0xB5, 0x33, 
+0xAD, 0x32, 0xA4, 0xD2, 0x9C, 0xD2, 0xB5, 0x54, 
+0x41, 0xC7, 0x52, 0x69, 0x52, 0x89, 0x52, 0x69, 
+0x73, 0x8D, 0x73, 0x8E, 0x84, 0x10, 0xAD, 0x34, 
+0xA5, 0x14, 0xB5, 0x76, 0xDE, 0xDB, 0xE7, 0x3C, 
+0xE7, 0x1C, 0xE6, 0xFC, 0xC5, 0xD6, 0xB5, 0x53, 
+0xCD, 0xF5, 0xBD, 0x93, 0xBD, 0x73, 0xBD, 0x52, 
+0xBD, 0x52, 0xC5, 0x93, 0xCD, 0xF4, 0xCE, 0x35, 
+0x9D, 0x0F, 0x8D, 0x50, 0x9D, 0x91, 0x73, 0xEC, 
+0x39, 0xE6, 0x42, 0x48, 0x52, 0xCA, 0x42, 0x07, 
+0x52, 0xCA, 0x4A, 0xA9, 0x42, 0x88, 0x53, 0x88, 
+0x85, 0x0D, 0x4B, 0x27, 0x29, 0x82, 0x4A, 0xC5, 
+0x6C, 0x49, 0x4B, 0x67, 0x4B, 0x47, 0x32, 0xA4, 
+0x32, 0xA4, 0x2A, 0x42, 0x2A, 0x62, 0x3A, 0xE4, 
+0x43, 0x45, 0x6C, 0x6A, 0x74, 0xCB, 0x6C, 0x49, 
+0x4B, 0x65, 0x3A, 0xE3, 0x4B, 0x05, 0x63, 0x88, 
+0x6B, 0x09, 0x7B, 0x2B, 0x7B, 0x4C, 0x73, 0x0C, 
+0x6B, 0x4B, 0x7B, 0xCD, 0x7B, 0xED, 0xA4, 0xF1, 
+0xAD, 0x52, 0xAD, 0x32, 0xAD, 0x51, 0xB5, 0x72, 
+0xAD, 0x11, 0xAD, 0x52, 0xAD, 0x73, 0xAD, 0x52, 
+0xAD, 0x32, 0xBD, 0xD4, 0xAD, 0x31, 0xAD, 0x31, 
+0xCD, 0xF3, 0xCD, 0xD3, 0xBD, 0x72, 0xAD, 0x11, 
+0xCE, 0x14, 0xA4, 0x8E, 0xBD, 0x50, 0xE6, 0x74, 
+0xDE, 0x13, 0xE6, 0x74, 0xDE, 0x54, 0xE6, 0x54, 
+0xDE, 0x54, 0xE6, 0x75, 0xD6, 0x13, 0xE6, 0x75, 
+0xE6, 0xB6, 0xE6, 0x75, 0xDE, 0x33, 0xDE, 0x33, 
+0xDE, 0x33, 0xCD, 0xB1, 0xD5, 0xD1, 0xE6, 0x74, 
+0xEE, 0x95, 0xE6, 0x74, 0xDE, 0x13, 0xD5, 0xF2, 
+0xDE, 0x13, 0xB4, 0xCE, 0xBD, 0x30, 0xE6, 0x55, 
+0xCD, 0xB3, 0xC5, 0x52, 0xC5, 0x71, 0xBD, 0x51, 
+0xBD, 0x31, 0xB4, 0xEF, 0xBD, 0x10, 0xBD, 0x10, 
+0xBD, 0x30, 0xC5, 0x71, 0xC5, 0x71, 0xBD, 0x30, 
+0xBD, 0x10, 0xC5, 0x71, 0xBD, 0x30, 0xAC, 0xCF, 
+0xB4, 0xEF, 0xC5, 0x71, 0xE6, 0x95, 0xE6, 0x55, 
+0xE6, 0x75, 0xB4, 0xCF, 0xB4, 0xEF, 0xCD, 0xB2, 
+0xEE, 0x95, 0xCD, 0xB2, 0xBD, 0x51, 0xCD, 0xB3, 
+0xD5, 0xF4, 0xD5, 0xF4, 0xD6, 0x14, 0xDE, 0x34, 
+0xB5, 0x10, 0x5A, 0xA8, 0x4A, 0x48, 0x4A, 0x48, 
+0x42, 0x28, 0x4A, 0x69, 0x52, 0x8A, 0x42, 0x07, 
+0x4A, 0x69, 0x39, 0xC7, 0x52, 0x8A, 0x73, 0x8E, 
+0xAD, 0x55, 0xDE, 0xBA, 0xE6, 0xFB, 0xD6, 0x78, 
+0xBD, 0x74, 0xA4, 0x8F, 0xA4, 0x6E, 0x93, 0xEC, 
+0x9C, 0x4D, 0xA4, 0x6E, 0xA4, 0x8E, 0xA4, 0xAF, 
+0xB4, 0xF0, 0xAC, 0xF1, 0x83, 0xCE, 0x94, 0xB3, 
+0xCE, 0x59, 0xC6, 0x38, 0xE7, 0x1D, 0xE7, 0x3D, 
+0xC5, 0xD7, 0x8C, 0x0E, 0x94, 0x2D, 0x9C, 0x4D, 
+0x9C, 0x6E, 0xA5, 0x11, 0x52, 0x68, 0x73, 0x4B, 
+0xAC, 0xF0, 0xA4, 0x8E, 0xA4, 0xAF, 0xA4, 0xAF, 
+0x9C, 0x6F, 0x94, 0x4E, 0x83, 0xCB, 0xA4, 0x8E, 
+0xA4, 0x6D, 0x94, 0x2D, 0x9C, 0x4E, 0x9C, 0x6E, 
+0xAC, 0xF0, 0xBD, 0x93, 0xAD, 0x11, 0xA4, 0xCF, 
+0x8C, 0x2D, 0x8C, 0x2E, 0x52, 0x88, 0x4A, 0x27, 
+0x52, 0x69, 0x63, 0x0A, 0x73, 0x6C, 0x62, 0xCA, 
+0x4A, 0x07, 0x5A, 0x69, 0x83, 0x8E, 0x8C, 0x10, 
+0xA4, 0xF3, 0xA4, 0xD2, 0x83, 0xAF, 0x9C, 0x92, 
+0xAC, 0xF3, 0x83, 0xCF, 0x9C, 0xD3, 0xF7, 0x7D, 
+0xEF, 0x1B, 0x9C, 0xB3, 0x41, 0xE7, 0x42, 0x07, 
+0x39, 0xE7, 0x52, 0x89, 0x42, 0x27, 0x39, 0xA6, 
+0x39, 0xC6, 0x4A, 0x69, 0x5A, 0xCA, 0x62, 0xEB, 
+0x6B, 0x4D, 0x6B, 0x6D, 0x8C, 0x72, 0xA5, 0x35, 
+0xB5, 0x96, 0xCE, 0x79, 0xC5, 0xF6, 0xA4, 0xD1, 
+0xD6, 0x36, 0xCD, 0xF5, 0xC5, 0xD4, 0xCE, 0x14, 
+0xCE, 0x35, 0xCE, 0x15, 0xCE, 0x15, 0xCD, 0xF4, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xBD, 0xB3, 0xBD, 0x73, 
+0xC5, 0xF5, 0xC5, 0xD4, 0xCD, 0xF4, 0xC5, 0xF4, 
+0xCE, 0x36, 0xA4, 0xF1, 0xB5, 0x73, 0xC5, 0xD3, 
+0xB5, 0x72, 0xBD, 0xB3, 0xAD, 0x11, 0xAD, 0x51, 
+0xAD, 0x31, 0xB5, 0x30, 0xB5, 0x50, 0xBD, 0x50, 
+0xCD, 0xB2, 0xA4, 0xAF, 0xAD, 0x11, 0x9C, 0xAF, 
+0x9C, 0xAF, 0xA4, 0xCF, 0xA4, 0xD0, 0xAD, 0x11, 
+0xB5, 0x72, 0xB5, 0x52, 0xAD, 0x11, 0xAD, 0x11, 
+0xB5, 0x73, 0xB5, 0x32, 0xB5, 0x32, 0xAD, 0x11, 
+0xA4, 0xD0, 0x9C, 0x8F, 0x8B, 0xED, 0xA4, 0xAF, 
+0xB5, 0x52, 0xB5, 0x31, 0xB5, 0x30, 0xCD, 0xB2, 
+0xCD, 0xD3, 0xB5, 0x12, 0xAD, 0x12, 0xC5, 0xD4, 
+0xCE, 0x15, 0xBD, 0xB4, 0xAD, 0x52, 0xBD, 0x93, 
+0xE6, 0xB7, 0xE6, 0xD7, 0xCE, 0x14, 0xE6, 0xB7, 
+0xE6, 0xB7, 0xD6, 0x56, 0xB5, 0x72, 0x8B, 0xED, 
+0xA4, 0x90, 0xBD, 0x93, 0xBD, 0x93, 0xC5, 0xF5, 
+0xBD, 0xB3, 0xBD, 0x93, 0xB5, 0x72, 0xBD, 0x93, 
+0xB5, 0x52, 0x8C, 0x0E, 0x9C, 0x70, 0xCE, 0x36, 
+0xC5, 0xF5, 0xC5, 0xD5, 0xB5, 0x94, 0x8C, 0x30, 
+0x84, 0x10, 0x9C, 0xD2, 0xA4, 0xD2, 0x9C, 0xB1, 
+0xB5, 0x53, 0x52, 0xA9, 0x4A, 0x28, 0x73, 0x8E, 
+0x5A, 0xCB, 0x73, 0xAF, 0x8C, 0x72, 0x8C, 0x52, 
+0x94, 0x93, 0xD6, 0xBB, 0xE6, 0xFB, 0xB5, 0x75, 
+0xB5, 0x75, 0xA4, 0xD2, 0xB5, 0x53, 0xAC, 0xF2, 
+0xA4, 0xB1, 0x9C, 0x70, 0x9C, 0x70, 0x9C, 0x90, 
+0xA5, 0x31, 0x9D, 0x92, 0x8C, 0xD0, 0x7B, 0xEE, 
+0x63, 0x2C, 0x5B, 0x0B, 0x52, 0xA9, 0x39, 0xE6, 
+0x31, 0x85, 0x31, 0xA5, 0x31, 0xC5, 0x53, 0x48, 
+0x85, 0x0D, 0x32, 0x44, 0x3A, 0x65, 0x63, 0xC9, 
+0x6C, 0x6A, 0x6C, 0x69, 0x64, 0x29, 0x5B, 0xE8, 
+0x43, 0x05, 0x4B, 0x67, 0x2A, 0x83, 0x43, 0x25, 
+0x53, 0xE7, 0x5C, 0x08, 0x4B, 0x65, 0x32, 0xC3, 
+0x32, 0xA2, 0x3A, 0xA3, 0x3A, 0xC4, 0x53, 0x66, 
+0x8C, 0x8D, 0x94, 0x6F, 0xAD, 0x34, 0xCE, 0x18, 
+0x83, 0xEE, 0x84, 0x0E, 0x84, 0x0E, 0x9C, 0xB0, 
+0xAD, 0x52, 0xAD, 0x52, 0xAD, 0x51, 0xAD, 0x52, 
+0xAD, 0x31, 0xAD, 0x52, 0xB5, 0x93, 0xAD, 0x52, 
+0xAD, 0x52, 0xC5, 0xF5, 0xA5, 0x11, 0xB5, 0x72, 
+0xC5, 0xD4, 0xCE, 0x14, 0xC5, 0xD3, 0xB5, 0x51, 
+0xBD, 0x92, 0xA4, 0x8D, 0xBD, 0x50, 0xE6, 0x95, 
+0xBD, 0x2F, 0xC5, 0x71, 0xDE, 0x34, 0xDE, 0x33, 
+0xD6, 0x33, 0xE6, 0x75, 0xE6, 0x95, 0xE6, 0x95, 
+0xE6, 0x95, 0xDE, 0x54, 0xDE, 0x13, 0xDE, 0x33, 
+0xDE, 0x53, 0xE6, 0x74, 0xC5, 0x91, 0xE6, 0x54, 
+0xE6, 0x95, 0xDE, 0x53, 0xD6, 0x12, 0xDE, 0x33, 
+0xE6, 0x74, 0xB4, 0xEE, 0xD6, 0x14, 0xD5, 0xF4, 
+0xCD, 0x92, 0xC5, 0x92, 0xC5, 0x51, 0xBD, 0x31, 
+0xB5, 0x10, 0x9C, 0x4D, 0xBD, 0x51, 0xBD, 0x31, 
+0xBD, 0x31, 0xBD, 0x10, 0xB5, 0x10, 0xAC, 0xCF, 
+0xAC, 0xCF, 0xB4, 0xF0, 0xB4, 0xEF, 0xB4, 0xCF, 
+0xBD, 0x30, 0xCD, 0xD3, 0xDE, 0x55, 0xE6, 0x75, 
+0xE6, 0x75, 0xAC, 0xCE, 0xBD, 0x30, 0xD5, 0xF3, 
+0xEE, 0xF7, 0xDE, 0x34, 0xCD, 0xB2, 0xCD, 0xD3, 
+0xD5, 0xF3, 0xD6, 0x14, 0xDE, 0x34, 0xDE, 0x34, 
+0xEE, 0xB6, 0xCD, 0xF4, 0x62, 0xE9, 0x31, 0x85, 
+0x31, 0x86, 0x39, 0xC7, 0x42, 0x07, 0x42, 0x28, 
+0x52, 0x69, 0x63, 0x2C, 0x73, 0xAE, 0x94, 0x71, 
+0x9C, 0xB3, 0xCE, 0x39, 0xCE, 0x59, 0xDE, 0xFB, 
+0xEF, 0x3C, 0xD6, 0x58, 0x94, 0x70, 0x8C, 0x30, 
+0x8C, 0x2F, 0x7B, 0x8C, 0x5A, 0xC9, 0x5A, 0xA8, 
+0x6B, 0x0A, 0x73, 0x4B, 0x5A, 0xA9, 0x84, 0x30, 
+0xCE, 0x7A, 0xD6, 0x7A, 0xD6, 0x9B, 0xDE, 0xFC, 
+0xE6, 0xFC, 0x7B, 0xAE, 0x7B, 0x8C, 0x94, 0x0D, 
+0x94, 0x2E, 0x8C, 0x4F, 0x39, 0xA5, 0x73, 0x8C, 
+0x94, 0x4D, 0x9C, 0x4D, 0xA4, 0x8E, 0xAC, 0xCF, 
+0xB4, 0xF0, 0xB4, 0xF0, 0xB4, 0xF0, 0xAC, 0xEF, 
+0xAC, 0xCF, 0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAF, 
+0x9C, 0x8E, 0x94, 0x4D, 0x9C, 0x4E, 0xA4, 0xAF, 
+0xA4, 0xCF, 0xA4, 0x8F, 0x94, 0x2D, 0x6B, 0x0A, 
+0x4A, 0x06, 0x62, 0xEA, 0x5A, 0xCA, 0x63, 0x0B, 
+0x4A, 0x28, 0x39, 0x85, 0x5A, 0xAA, 0x83, 0xEF, 
+0x94, 0x71, 0x73, 0x4D, 0x6B, 0x0C, 0x8C, 0x10, 
+0x8C, 0x10, 0x8B, 0xF0, 0x7B, 0xAE, 0x94, 0x92, 
+0xE6, 0xFB, 0xE7, 0x1B, 0x7B, 0xCF, 0x31, 0xA6, 
+0x39, 0xE7, 0x42, 0x28, 0x39, 0xE7, 0x42, 0x07, 
+0x41, 0xE7, 0x42, 0x28, 0x52, 0xAA, 0x5A, 0xCA, 
+0x6B, 0x4D, 0x84, 0x10, 0x84, 0x31, 0x9C, 0xD3, 
+0xAD, 0x56, 0xBD, 0xF8, 0xC5, 0xF7, 0xA4, 0xF2, 
+0xB5, 0x73, 0xC5, 0xB4, 0xB5, 0x72, 0xBD, 0x93, 
+0xBD, 0xB3, 0xBD, 0x93, 0xB5, 0x73, 0xBD, 0x93, 
+0xB5, 0x52, 0xB5, 0x73, 0xBD, 0x93, 0xB5, 0x73, 
+0xBD, 0xB3, 0xC5, 0xD4, 0xCE, 0x35, 0xC6, 0x14, 
+0xC5, 0xF5, 0xA4, 0xD1, 0xBD, 0x93, 0xCE, 0x15, 
+0xB5, 0x51, 0x9C, 0xAF, 0x7B, 0xAB, 0xAD, 0x31, 
+0xBD, 0x92, 0xC5, 0xD3, 0xCD, 0xF3, 0xD6, 0x12, 
+0xDE, 0x54, 0x9C, 0x8F, 0xA4, 0xD0, 0x9C, 0xB0, 
+0xAD, 0x11, 0xAD, 0x31, 0xA4, 0xF0, 0xAD, 0x11, 
+0xB5, 0x52, 0xB5, 0x73, 0xB5, 0x73, 0xBD, 0x73, 
+0xB5, 0x52, 0xBD, 0x73, 0xBD, 0x93, 0xB5, 0x52, 
+0xAD, 0x52, 0xB5, 0x52, 0x94, 0x6F, 0xA4, 0xB0, 
+0xB5, 0x32, 0xBD, 0x72, 0xBD, 0x71, 0xBD, 0x71, 
+0xCD, 0xB2, 0xB5, 0x32, 0xB5, 0x53, 0xD6, 0x76, 
+0xD6, 0x55, 0xC5, 0xF4, 0xBD, 0x93, 0xC5, 0xF5, 
+0xDE, 0x96, 0xCE, 0x14, 0xB5, 0x31, 0xC5, 0x92, 
+0xD5, 0xF3, 0xD6, 0x35, 0xA4, 0xD0, 0x9C, 0xB0, 
+0x9C, 0x90, 0xCE, 0x36, 0xD6, 0x76, 0xCE, 0x35, 
+0xCE, 0x14, 0xCD, 0xF3, 0xCE, 0x14, 0xCE, 0x14, 
+0xD6, 0x35, 0x94, 0x6F, 0xB5, 0x73, 0xB5, 0x74, 
+0xAD, 0x53, 0xBD, 0xB4, 0xCE, 0x57, 0xC6, 0x15, 
+0xB5, 0x94, 0x94, 0x90, 0x8C, 0x2F, 0x9C, 0x90, 
+0xBD, 0xB4, 0xB5, 0x94, 0xBD, 0xB4, 0xBD, 0xB5, 
+0xAD, 0x54, 0x8C, 0x50, 0x52, 0xAA, 0x42, 0x09, 
+0x4A, 0x4B, 0xAD, 0x56, 0xDE, 0xBB, 0xCE, 0x18, 
+0xBD, 0x96, 0xC5, 0xD6, 0xB5, 0x54, 0xA4, 0xD1, 
+0xAD, 0x12, 0xA5, 0x12, 0xAD, 0x12, 0xAD, 0x12, 
+0x9C, 0xD1, 0x84, 0x2E, 0x6B, 0x6C, 0x4A, 0x89, 
+0x41, 0xE7, 0x31, 0x85, 0x29, 0x85, 0x21, 0x24, 
+0x21, 0x44, 0x21, 0x44, 0x32, 0x06, 0x5B, 0x89, 
+0x64, 0x2A, 0x64, 0x2A, 0x95, 0x6F, 0x7C, 0xCC, 
+0x4B, 0x67, 0x6C, 0x6A, 0x7C, 0xCB, 0x6C, 0x6A, 
+0x4B, 0x87, 0x64, 0x2A, 0x3A, 0xC5, 0x32, 0x84, 
+0x3A, 0xE5, 0x43, 0x25, 0x4B, 0x86, 0x3A, 0xE4, 
+0x43, 0x25, 0x63, 0xA8, 0x53, 0x27, 0x42, 0xA4, 
+0x5B, 0x88, 0x6B, 0x4A, 0x9C, 0xD2, 0x8C, 0x71, 
+0x7B, 0xAD, 0x7B, 0xAD, 0x6B, 0x2B, 0x63, 0x2A, 
+0x94, 0x6E, 0x9C, 0xD0, 0x8C, 0x4E, 0x94, 0x8F, 
+0xA4, 0xD0, 0xAD, 0x32, 0xB5, 0x73, 0xB5, 0x73, 
+0xB5, 0x73, 0xBD, 0xB4, 0xAD, 0x32, 0xBD, 0xD4, 
+0xC5, 0xD3, 0xC5, 0xD3, 0xAD, 0x30, 0x9C, 0x8E, 
+0x9C, 0x6E, 0xA4, 0xAE, 0xBD, 0x50, 0xEE, 0xB5, 
+0xE6, 0x95, 0xE6, 0x95, 0xE6, 0x75, 0xD5, 0xF2, 
+0xDE, 0x54, 0xDE, 0x74, 0xE6, 0x75, 0xE6, 0xB6, 
+0xE6, 0x95, 0xDE, 0x54, 0xDE, 0x33, 0xD5, 0xD2, 
+0xCD, 0x91, 0xCD, 0xB1, 0xC5, 0x70, 0xD5, 0xD2, 
+0xDE, 0x33, 0xDE, 0x13, 0xCD, 0xB1, 0xD5, 0xD2, 
+0xB4, 0xCE, 0xA4, 0x4C, 0xDE, 0x14, 0xD5, 0xD3, 
+0xCD, 0x92, 0xD5, 0xF4, 0xD5, 0xF4, 0xCD, 0xB3, 
+0xD5, 0xF4, 0xC5, 0x93, 0xCD, 0xB3, 0xD5, 0xF4, 
+0xCD, 0xD3, 0xC5, 0x92, 0xC5, 0x52, 0xC5, 0x72, 
+0xC5, 0x52, 0xBD, 0x51, 0xC5, 0x72, 0xCD, 0x93, 
+0xC5, 0x72, 0xC5, 0x72, 0xCD, 0xD3, 0xE6, 0x96, 
+0xDE, 0x14, 0xA4, 0x8D, 0xDE, 0x13, 0xE6, 0x54, 
+0xEE, 0xB6, 0xEE, 0xB6, 0xEE, 0xB6, 0xEE, 0x96, 
+0xE6, 0x95, 0xEE, 0x95, 0xEE, 0x95, 0xDE, 0x54, 
+0xE6, 0x75, 0xF6, 0xD7, 0xEE, 0xB7, 0xB5, 0x31, 
+0x5A, 0x88, 0x39, 0xC6, 0x39, 0xC6, 0x31, 0xA6, 
+0x39, 0xE7, 0x52, 0xAA, 0x5A, 0xEB, 0x7B, 0xCF, 
+0x8C, 0x72, 0x9C, 0xD3, 0xA5, 0x14, 0xC6, 0x39, 
+0xAD, 0x55, 0xD6, 0x9A, 0xE7, 0x3C, 0xD6, 0x9A, 
+0xC6, 0x17, 0xB5, 0x74, 0x94, 0xB1, 0x84, 0x0F, 
+0x84, 0x0E, 0x84, 0x2F, 0x73, 0x8D, 0x73, 0xAE, 
+0xA5, 0x35, 0xCE, 0x7A, 0xD6, 0xBB, 0xE7, 0x1D, 
+0xDE, 0xFC, 0xB5, 0x76, 0x83, 0xEF, 0x73, 0x8D, 
+0x94, 0x70, 0x73, 0x6C, 0x39, 0xC6, 0x8C, 0x2F, 
+0x8C, 0x2E, 0x83, 0xEE, 0x8C, 0x0E, 0x83, 0xCC, 
+0x83, 0xAC, 0x83, 0xAB, 0x7B, 0x8B, 0x7B, 0x8B, 
+0x7B, 0x8B, 0x83, 0xCC, 0x94, 0x2E, 0xA4, 0xCF, 
+0x8C, 0x0C, 0xA4, 0x6E, 0xA4, 0x8E, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xAC, 0xAF, 0xAC, 0xEF, 0xB5, 0x10, 
+0x94, 0x2E, 0x5A, 0xA8, 0x52, 0x68, 0x52, 0x69, 
+0x42, 0x07, 0x4A, 0x48, 0x6B, 0x2C, 0x5A, 0xAA, 
+0x52, 0x49, 0x52, 0x69, 0x62, 0xCB, 0x83, 0xAE, 
+0xA4, 0xD2, 0x9C, 0x92, 0x9C, 0xB2, 0x83, 0xCF, 
+0x94, 0x92, 0xCE, 0x57, 0x83, 0xEF, 0x5A, 0xCA, 
+0x39, 0xE7, 0x31, 0xA6, 0x31, 0xA6, 0x39, 0xE6, 
+0x39, 0xE7, 0x42, 0x27, 0x52, 0x89, 0x63, 0x0B, 
+0x63, 0x0C, 0x6B, 0x6D, 0x73, 0xAF, 0x8C, 0x92, 
+0xA5, 0x35, 0xAD, 0x56, 0xA5, 0x14, 0xB5, 0x75, 
+0xB5, 0x94, 0xA4, 0xD1, 0xAD, 0x32, 0xB5, 0x53, 
+0x9C, 0x90, 0xB5, 0x73, 0xAD, 0x11, 0xA4, 0xF1, 
+0x9C, 0x90, 0x9C, 0xB0, 0xA4, 0xF1, 0xAD, 0x11, 
+0xB5, 0x52, 0xBD, 0x93, 0xC5, 0xF4, 0xCE, 0x35, 
+0xC5, 0xB4, 0xAC, 0xF1, 0xBD, 0xB3, 0xC5, 0xF3, 
+0xB5, 0x92, 0x94, 0x4E, 0x94, 0x6E, 0xAD, 0x31, 
+0xB5, 0x92, 0xBD, 0xB2, 0xBD, 0x71, 0xBD, 0x70, 
+0xD6, 0x13, 0xA4, 0xD0, 0xAD, 0x11, 0xA4, 0xF0, 
+0xAD, 0x32, 0xA4, 0xF1, 0xB5, 0x72, 0xBD, 0xB4, 
+0xBD, 0xB3, 0xC5, 0xD4, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xBD, 0xB3, 0xBD, 0x93, 0xBD, 0x93, 0xBD, 0xB3, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xBD, 0x93, 0xC5, 0xF5, 
+0xBD, 0x93, 0xB5, 0x52, 0xB5, 0x51, 0xBD, 0x51, 
+0xC5, 0x92, 0xB5, 0x31, 0xBD, 0x93, 0xC5, 0xF4, 
+0xCE, 0x14, 0xC5, 0xD4, 0xB5, 0x93, 0xCE, 0x15, 
+0xC5, 0xD4, 0xB5, 0x31, 0xDE, 0x35, 0xC5, 0x71, 
+0xCD, 0x92, 0xCD, 0xD3, 0xB5, 0x52, 0xB5, 0x53, 
+0xBD, 0xB4, 0xC5, 0xF4, 0xC5, 0xD3, 0xBD, 0xB3, 
+0xCD, 0xF4, 0xCD, 0xF3, 0xD6, 0x14, 0xD6, 0x14, 
+0xCD, 0xF4, 0x9C, 0xB0, 0xA5, 0x12, 0xA4, 0xF1, 
+0xB5, 0x53, 0xBD, 0xB4, 0xC6, 0x15, 0xC5, 0xD4, 
+0xC5, 0xF5, 0xAD, 0x53, 0xA4, 0xD1, 0xB5, 0x74, 
+0xBD, 0xD5, 0xBD, 0xF5, 0xCE, 0x56, 0xCE, 0x36, 
+0xBD, 0xD5, 0x94, 0x70, 0x6B, 0x4C, 0x39, 0xC7, 
+0x4A, 0x4A, 0xB5, 0x76, 0xAD, 0x55, 0xBD, 0x96, 
+0xC6, 0x18, 0xAD, 0x54, 0xB5, 0x54, 0xBD, 0xB5, 
+0xC5, 0xF6, 0xAD, 0x53, 0x8C, 0x50, 0x6B, 0x4C, 
+0x63, 0x0B, 0x7B, 0xAD, 0x73, 0x6D, 0x42, 0x08, 
+0x42, 0x28, 0x39, 0xC6, 0x39, 0xE7, 0x29, 0x64, 
+0x21, 0x44, 0x21, 0x44, 0x53, 0x49, 0x6C, 0x6B, 
+0x74, 0xCB, 0x85, 0x2E, 0x95, 0xB0, 0x6C, 0x6B, 
+0x21, 0xE3, 0x21, 0xC3, 0x4B, 0x47, 0x53, 0x87, 
+0x43, 0x26, 0x43, 0x26, 0x3A, 0xE6, 0x19, 0xC3, 
+0x21, 0xE3, 0x3A, 0xE5, 0x64, 0x2A, 0x53, 0xE8, 
+0x5C, 0x09, 0x6C, 0x2A, 0x5B, 0x68, 0x42, 0x85, 
+0x53, 0x06, 0x5B, 0xA8, 0x5B, 0x88, 0x4B, 0x08, 
+0x7B, 0xCD, 0x8C, 0x0E, 0x8C, 0x2F, 0x8C, 0x0E, 
+0x8C, 0x0D, 0x8C, 0x0E, 0x94, 0x2E, 0x94, 0x4E, 
+0x94, 0x4E, 0x94, 0x4E, 0x8C, 0x2D, 0x84, 0x0D, 
+0x83, 0xED, 0x84, 0x0D, 0x8C, 0x2E, 0x9C, 0x8F, 
+0x94, 0x6E, 0x94, 0x2D, 0x8C, 0x0C, 0x8B, 0xEC, 
+0x9C, 0x6E, 0xA4, 0x8E, 0xA4, 0x8D, 0xDE, 0x33, 
+0xE6, 0x95, 0xE6, 0x95, 0xE6, 0x75, 0xE6, 0x75, 
+0xEE, 0xB6, 0xE6, 0xB5, 0xE6, 0xB6, 0xE6, 0xB6, 
+0xEE, 0xD6, 0xEE, 0xB6, 0xE6, 0x95, 0xE6, 0x74, 
+0xD6, 0x13, 0xC5, 0x91, 0xCD, 0xD2, 0xD6, 0x13, 
+0xEE, 0xB6, 0xD5, 0xF3, 0xC5, 0x71, 0xC5, 0x71, 
+0xBD, 0x0F, 0xA4, 0x6D, 0xCD, 0xB2, 0xCD, 0xB2, 
+0xCD, 0xB2, 0xDE, 0x14, 0xD5, 0xF4, 0xD6, 0x14, 
+0xC5, 0x92, 0xC5, 0x93, 0xAC, 0xD0, 0xD5, 0xF4, 
+0xCD, 0xD4, 0xCD, 0xD3, 0xCD, 0xB3, 0xCD, 0xB3, 
+0xCD, 0xB3, 0xCD, 0x93, 0xC5, 0x92, 0xCD, 0xB3, 
+0xCD, 0xB3, 0xD5, 0xD3, 0xCD, 0xB2, 0xDE, 0x14, 
+0xD5, 0xF3, 0xA4, 0x8D, 0xDE, 0x34, 0xE6, 0x75, 
+0xEE, 0xB6, 0xEE, 0x96, 0xEE, 0x95, 0xE6, 0x75, 
+0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x95, 
+0xE6, 0x75, 0xE6, 0x95, 0xEE, 0xD6, 0xEE, 0xD6, 
+0xE6, 0x75, 0x9C, 0x6E, 0x4A, 0x07, 0x39, 0xA6, 
+0x39, 0xE7, 0x42, 0x07, 0x42, 0x07, 0x5A, 0xCB, 
+0x63, 0x2D, 0x7B, 0xF0, 0x8C, 0x72, 0xAD, 0x55, 
+0xC6, 0x19, 0xAD, 0x56, 0xCE, 0x7A, 0xE7, 0x1C, 
+0xEF, 0x3C, 0xCE, 0x38, 0x9C, 0xD2, 0x8C, 0x50, 
+0x9C, 0xD1, 0xA5, 0x12, 0xA5, 0x12, 0x9C, 0xD1, 
+0x73, 0xAE, 0xAD, 0x76, 0xC6, 0x3A, 0xEF, 0x5E, 
+0xF7, 0x9E, 0xE7, 0x3D, 0xB5, 0x75, 0xAD, 0x33, 
+0xA4, 0xF2, 0x4A, 0x48, 0x73, 0x8D, 0xBD, 0xD5, 
+0xBD, 0xB4, 0xB5, 0x74, 0xAD, 0x53, 0xA4, 0xF1, 
+0xAD, 0x32, 0xB5, 0x53, 0xAD, 0x32, 0xA4, 0xF1, 
+0xB5, 0x53, 0xBD, 0xB4, 0xB5, 0x53, 0xAD, 0x31, 
+0x9C, 0x8F, 0x9C, 0x6E, 0x8C, 0x0C, 0x94, 0x4E, 
+0x94, 0x2E, 0x9C, 0x8F, 0xA4, 0xD0, 0xA4, 0xCF, 
+0xC5, 0xD4, 0xBD, 0x92, 0x63, 0x0A, 0x4A, 0x27, 
+0x4A, 0x27, 0x5A, 0xAA, 0x63, 0x0B, 0x5A, 0xCA, 
+0x52, 0x89, 0x52, 0x49, 0x6B, 0x2C, 0x7B, 0x8E, 
+0x83, 0xCF, 0x73, 0x4D, 0x94, 0x51, 0xBD, 0x95, 
+0x94, 0x71, 0x62, 0xEB, 0xB5, 0x96, 0x9C, 0xB2, 
+0x4A, 0x28, 0x42, 0x28, 0x3A, 0x07, 0x31, 0xA5, 
+0x39, 0xC6, 0x39, 0xE7, 0x42, 0x28, 0x4A, 0x49, 
+0x4A, 0x49, 0x63, 0x0C, 0x73, 0xAF, 0x84, 0x51, 
+0x9D, 0x15, 0xB5, 0x96, 0xAD, 0x76, 0xC5, 0xF7, 
+0xCE, 0x78, 0xAD, 0x55, 0x73, 0x8D, 0x9C, 0x91, 
+0x52, 0x68, 0x94, 0x70, 0x9C, 0x90, 0x9C, 0xB0, 
+0x9C, 0x90, 0x9C, 0x6F, 0xA4, 0xB1, 0xA4, 0xD1, 
+0xA4, 0xB0, 0xBD, 0xB4, 0xC5, 0xF4, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xA4, 0xB0, 0xAD, 0x11, 0xC6, 0x14, 
+0xCE, 0x55, 0xC5, 0xF4, 0xCE, 0x35, 0xD6, 0x55, 
+0xD6, 0x55, 0xD6, 0x54, 0xD6, 0x13, 0xD6, 0x13, 
+0xDE, 0x74, 0xA4, 0xAF, 0xA4, 0xF1, 0xA4, 0xF0, 
+0xAD, 0x31, 0xB5, 0x52, 0xBD, 0x93, 0xB5, 0x72, 
+0xBD, 0xB3, 0xBD, 0xD4, 0xC5, 0xD4, 0xBD, 0xB4, 
+0xC5, 0xF5, 0xC5, 0xF4, 0xC5, 0xD4, 0xC5, 0xF5, 
+0xBD, 0x93, 0xB5, 0x32, 0xAD, 0x11, 0xC5, 0xF4, 
+0xB5, 0x52, 0xBD, 0x73, 0xBD, 0x72, 0xC5, 0x92, 
+0xC5, 0x92, 0xB5, 0x11, 0xB5, 0x52, 0xC5, 0xF4, 
+0xC5, 0xF4, 0xBD, 0x93, 0xB5, 0x73, 0xBD, 0x93, 
+0xB5, 0x72, 0xA4, 0xAF, 0xD6, 0x14, 0xD5, 0xB2, 
+0xCD, 0x72, 0xCD, 0xF3, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xCE, 0x15, 0xC5, 0xD4, 0xC5, 0xB3, 0xCE, 0x14, 
+0xCE, 0x14, 0xCD, 0xF3, 0xD6, 0x34, 0xD6, 0x55, 
+0xC5, 0xB3, 0x9C, 0xB1, 0x9C, 0xD1, 0x94, 0x90, 
+0xA4, 0xF2, 0xB5, 0x53, 0xB5, 0x93, 0xB5, 0x93, 
+0xB5, 0x73, 0xB5, 0x73, 0xA5, 0x12, 0xC6, 0x15, 
+0xC5, 0xF5, 0xCE, 0x36, 0xDE, 0x97, 0xC5, 0xF5, 
+0x9C, 0xD1, 0x83, 0xEE, 0xC5, 0xD5, 0x7B, 0xCE, 
+0x42, 0x08, 0x9C, 0xB3, 0x9C, 0xD3, 0xBD, 0xD7, 
+0xB5, 0x75, 0xBD, 0x96, 0xA4, 0xF3, 0x7B, 0xEF, 
+0x63, 0x0C, 0x5A, 0xCB, 0x9C, 0xD1, 0xC5, 0xF5, 
+0xE6, 0xB8, 0xD6, 0x16, 0xAC, 0xF2, 0x94, 0x92, 
+0x73, 0xAE, 0x39, 0xE7, 0x42, 0x48, 0x42, 0x07, 
+0x31, 0xC6, 0x31, 0xA5, 0x74, 0x4C, 0x85, 0x0D, 
+0x95, 0xB0, 0xA6, 0x11, 0x9D, 0xD0, 0x5B, 0xC8, 
+0x32, 0x65, 0x2A, 0x04, 0x3A, 0xC5, 0x5B, 0xC8, 
+0x5B, 0xC8, 0x4B, 0x47, 0x4B, 0x67, 0x32, 0x85, 
+0x2A, 0x44, 0x32, 0x84, 0x5B, 0xE9, 0x5C, 0x09, 
+0x5C, 0x29, 0x64, 0x08, 0x64, 0x08, 0x7C, 0x6B, 
+0xC6, 0x33, 0x95, 0x0E, 0x5B, 0xA7, 0x5B, 0xC7, 
+0x73, 0x6B, 0x8C, 0x2E, 0x9C, 0x6F, 0x9C, 0x6F, 
+0xAD, 0x12, 0x9C, 0x6F, 0x94, 0x4E, 0x9C, 0x8F, 
+0x9C, 0x8F, 0xA4, 0xF1, 0xB5, 0x52, 0xBD, 0x73, 
+0xAC, 0xF1, 0xA4, 0xB0, 0xA4, 0xD0, 0xA4, 0xAF, 
+0xA4, 0xAF, 0xA4, 0xAE, 0xAC, 0xCF, 0xA4, 0xAE, 
+0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0x6D, 0x9C, 0x4C, 
+0x9C, 0x6D, 0xA4, 0xAE, 0xAC, 0xCE, 0xAC, 0xCF, 
+0xB4, 0xEF, 0xB5, 0x30, 0xBD, 0x50, 0xBD, 0x71, 
+0xC5, 0xB2, 0xCD, 0xD2, 0xD5, 0xF3, 0xD5, 0xF3, 
+0xD6, 0x14, 0xD6, 0x34, 0xD6, 0x34, 0xDE, 0x55, 
+0xE6, 0x96, 0xEE, 0xB6, 0xE6, 0x95, 0xC5, 0x51, 
+0xCD, 0xD2, 0xAC, 0xAE, 0xE6, 0x96, 0xCD, 0xD3, 
+0xDE, 0x35, 0xD5, 0xF4, 0xDE, 0x35, 0xD6, 0x14, 
+0x9C, 0x4D, 0xC5, 0x93, 0xCD, 0xD4, 0xD5, 0xF4, 
+0xCD, 0xD4, 0xD5, 0xF4, 0xD5, 0xD4, 0xD5, 0xD4, 
+0xD5, 0xD4, 0xD5, 0xD4, 0xD5, 0xF4, 0xD5, 0xF4, 
+0xD5, 0xF4, 0xDE, 0x14, 0xD5, 0xF4, 0xD5, 0xF3, 
+0xDE, 0x34, 0xA4, 0x6D, 0xDE, 0x54, 0xE6, 0x95, 
+0xEE, 0x95, 0xEE, 0x95, 0xEE, 0x95, 0xE6, 0x95, 
+0xDE, 0x13, 0xEE, 0x95, 0xE6, 0x95, 0xE6, 0x75, 
+0xE6, 0x75, 0xE6, 0x75, 0xEE, 0xB6, 0xDE, 0x33, 
+0xE6, 0x95, 0xF6, 0xD7, 0xCD, 0xD3, 0x7B, 0x6B, 
+0x41, 0xE6, 0x31, 0x85, 0x31, 0xA6, 0x42, 0x08, 
+0x5A, 0xCB, 0x5B, 0x0C, 0x73, 0x8E, 0x7B, 0xF0, 
+0x94, 0xB3, 0xB5, 0xB7, 0xCE, 0x5A, 0xCE, 0x7A, 
+0xDE, 0xDC, 0xEF, 0x5D, 0xE7, 0x1C, 0xAD, 0x75, 
+0x94, 0x91, 0x9C, 0xF2, 0xB5, 0x53, 0xB5, 0x74, 
+0x7B, 0xEE, 0x84, 0x51, 0xC6, 0x39, 0xDE, 0xDC, 
+0xBE, 0x18, 0xC6, 0x19, 0xCE, 0x59, 0xAD, 0x54, 
+0x94, 0x70, 0x39, 0xC6, 0x94, 0x90, 0xA5, 0x12, 
+0xAD, 0x52, 0xB5, 0x73, 0xB5, 0x73, 0xAD, 0x52, 
+0xA5, 0x11, 0xB5, 0x73, 0xBD, 0xB4, 0xBD, 0x93, 
+0xB5, 0x94, 0xAD, 0x73, 0xAD, 0x32, 0xA4, 0xF1, 
+0xAD, 0x32, 0xA4, 0xAF, 0x7B, 0x6B, 0x6B, 0x6C, 
+0x73, 0x6C, 0x73, 0x8D, 0x83, 0xEE, 0x7B, 0xEE, 
+0x9C, 0xB0, 0xAD, 0x32, 0x9C, 0xB0, 0x6B, 0x4B, 
+0x52, 0x68, 0x4A, 0x68, 0x4A, 0x48, 0x52, 0x89, 
+0x7B, 0x8D, 0x6B, 0x2C, 0x5A, 0x8A, 0x83, 0xEF, 
+0x83, 0xCE, 0x83, 0xAE, 0x9C, 0x71, 0xBD, 0x75, 
+0xCD, 0xD7, 0xA4, 0xB2, 0xA4, 0xB2, 0x73, 0x6D, 
+0x5A, 0xEA, 0x42, 0x07, 0x3A, 0x07, 0x31, 0xA6, 
+0x39, 0xE7, 0x42, 0x28, 0x52, 0xAA, 0x4A, 0x69, 
+0x52, 0xAA, 0x63, 0x2C, 0x73, 0xAF, 0x84, 0x11, 
+0x94, 0xB3, 0xA5, 0x15, 0x8C, 0x72, 0xB5, 0x96, 
+0xC6, 0x17, 0xC5, 0xF7, 0x84, 0x10, 0x73, 0x6D, 
+0x4A, 0x48, 0xAD, 0x33, 0xCD, 0xF6, 0xAD, 0x32, 
+0xAC, 0xF1, 0xA4, 0xD1, 0xA4, 0xB0, 0xA4, 0xB0, 
+0x9C, 0x90, 0x9C, 0x90, 0x9C, 0x90, 0x94, 0x6F, 
+0x9C, 0x8F, 0xA4, 0xB0, 0x9C, 0x6F, 0x94, 0x2E, 
+0x8C, 0x2E, 0x94, 0x4E, 0x94, 0x4E, 0x94, 0x4E, 
+0x9C, 0x6E, 0x9C, 0x8E, 0x9C, 0x8F, 0xA4, 0xCF, 
+0x9C, 0xAF, 0x94, 0x2E, 0x8C, 0x2E, 0x8C, 0x0D, 
+0x8C, 0x0D, 0x8C, 0x2E, 0x8C, 0x0D, 0x83, 0xCC, 
+0x8C, 0x2E, 0x94, 0x6F, 0x9C, 0xB0, 0xA4, 0xF1, 
+0xA4, 0xF1, 0x9C, 0xB0, 0xA4, 0xD0, 0xAD, 0x32, 
+0xB5, 0x72, 0xBD, 0x93, 0xAD, 0x31, 0xA4, 0xD0, 
+0xC5, 0xB4, 0xC5, 0xB4, 0xCD, 0xF3, 0xC5, 0x92, 
+0xCD, 0xB3, 0xAD, 0x11, 0x9C, 0xAF, 0xCE, 0x35, 
+0xCE, 0x15, 0xC5, 0xD4, 0xC5, 0xF5, 0xC5, 0xF5, 
+0xBD, 0xB4, 0xBD, 0x92, 0xCD, 0xB3, 0xD5, 0xD3, 
+0xBD, 0x51, 0xCE, 0x15, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xCE, 0x14, 0xCD, 0xF4, 0xC5, 0xF4, 0xCE, 0x14, 
+0xC5, 0xB3, 0xD6, 0x55, 0xD6, 0x55, 0xDE, 0x75, 
+0xC5, 0xD3, 0xA4, 0xF2, 0xA4, 0xF2, 0x94, 0x70, 
+0x9C, 0xD1, 0xAD, 0x53, 0xB5, 0x53, 0xB5, 0x73, 
+0xB5, 0x74, 0xAD, 0x33, 0xA4, 0xF2, 0xAD, 0x32, 
+0xB5, 0x93, 0xC5, 0xF5, 0xD6, 0x76, 0xCE, 0x56, 
+0xD6, 0x57, 0xD6, 0x77, 0xEF, 0x1A, 0xC5, 0xF6, 
+0xAD, 0x75, 0xD6, 0x79, 0xB5, 0x96, 0xA5, 0x14, 
+0x83, 0xF0, 0x63, 0x0C, 0x5A, 0xCB, 0x5A, 0xEC, 
+0x8C, 0x72, 0xC6, 0x17, 0xDE, 0xB8, 0xDE, 0x97, 
+0xE6, 0xB8, 0xB5, 0x12, 0xD6, 0x38, 0xDE, 0xDB, 
+0xA5, 0x34, 0x42, 0x07, 0x42, 0x07, 0x3A, 0x07, 
+0x21, 0x64, 0x21, 0x64, 0x7C, 0x8D, 0x74, 0xAC, 
+0x6C, 0x6B, 0x7C, 0xED, 0x8D, 0x4E, 0x4B, 0x67, 
+0x3A, 0x85, 0x21, 0xC3, 0x43, 0x06, 0x63, 0xE9, 
+0x2A, 0x44, 0x2A, 0x44, 0x5B, 0xC9, 0x5B, 0xA9, 
+0x32, 0x65, 0x2A, 0x04, 0x3A, 0xC5, 0x4B, 0x67, 
+0x53, 0xA8, 0x53, 0xA7, 0x53, 0xA6, 0x84, 0x8C, 
+0xEF, 0x38, 0xE7, 0x17, 0x7C, 0x4B, 0x53, 0x86, 
+0x62, 0xEA, 0x5A, 0x89, 0x83, 0xCD, 0x94, 0x2E, 
+0x94, 0x4F, 0x52, 0x68, 0x5A, 0x88, 0x7B, 0x8C, 
+0x83, 0xAC, 0x73, 0x4B, 0x94, 0x6F, 0xDE, 0x77, 
+0xCE, 0x15, 0x9C, 0x4E, 0xAC, 0xD0, 0xA4, 0x6E, 
+0xA4, 0x6E, 0xA4, 0xAF, 0xC5, 0xB2, 0xC5, 0xB2, 
+0xC5, 0x92, 0xCD, 0xF3, 0xCD, 0xB3, 0xCD, 0xD3, 
+0xCD, 0xD3, 0xC5, 0xB2, 0xC5, 0xB2, 0xC5, 0xB2, 
+0xC5, 0x91, 0xB5, 0x30, 0xB5, 0x10, 0xBD, 0x71, 
+0xB4, 0xF0, 0xAC, 0xCF, 0xB4, 0xEF, 0xAC, 0xCF, 
+0xA4, 0x8E, 0xA4, 0x6D, 0xA4, 0x6E, 0xA4, 0x6E, 
+0xA4, 0x6D, 0xA4, 0x6D, 0xA4, 0x6D, 0xAC, 0x8E, 
+0xA4, 0x8D, 0xA4, 0x8E, 0xB5, 0x0F, 0xAC, 0xAE, 
+0xA4, 0x8E, 0x9C, 0x2C, 0x94, 0x2C, 0x9C, 0x2D, 
+0x9C, 0x4D, 0x8B, 0xCB, 0x94, 0x0C, 0x9C, 0x2D, 
+0x9C, 0x2D, 0xA4, 0x6E, 0xAC, 0xAF, 0xB4, 0xCF, 
+0xBD, 0x31, 0xC5, 0x72, 0xBD, 0x51, 0xCD, 0xD4, 
+0xCD, 0xB3, 0xCD, 0xD3, 0xCD, 0xF3, 0xD5, 0xF4, 
+0xE6, 0x95, 0xAC, 0x8E, 0xE6, 0x95, 0xF6, 0xF6, 
+0xEE, 0xD6, 0xEE, 0xD6, 0xEE, 0xD6, 0xEE, 0xB6, 
+0xEE, 0xB6, 0xEE, 0xD6, 0xDE, 0x34, 0xE6, 0x75, 
+0xEE, 0x95, 0xEE, 0x95, 0xE6, 0x75, 0xE6, 0x54, 
+0xE6, 0x74, 0xE6, 0x74, 0xEE, 0x95, 0xEE, 0x96, 
+0xB5, 0x10, 0x62, 0xA9, 0x39, 0xA5, 0x31, 0xA6, 
+0x31, 0xC6, 0x3A, 0x07, 0x4A, 0x69, 0x52, 0xAB, 
+0x6B, 0x4D, 0x84, 0x51, 0xAD, 0x96, 0xC6, 0x3A, 
+0xCE, 0x7A, 0xDE, 0xDB, 0xAD, 0x55, 0xBD, 0xB7, 
+0xE7, 0x3C, 0xCE, 0x59, 0xBD, 0x95, 0xB5, 0x75, 
+0x8C, 0x50, 0x8C, 0x30, 0x9C, 0xB3, 0xA5, 0x35, 
+0xD6, 0x9A, 0xD6, 0xBB, 0xEF, 0x3D, 0xD6, 0x79, 
+0x73, 0x6D, 0x5A, 0xA9, 0xBD, 0xB4, 0xC5, 0xF4, 
+0xC5, 0xD4, 0xCD, 0xF4, 0xC5, 0xB4, 0xBD, 0xB3, 
+0xBD, 0x93, 0x94, 0x6F, 0x94, 0x8F, 0x9C, 0xB0, 
+0xAD, 0x32, 0xBD, 0x73, 0xC5, 0xD4, 0xC5, 0xB3, 
+0xB5, 0x52, 0xA4, 0x8F, 0x73, 0x2A, 0x6B, 0x4C, 
+0x5A, 0xEB, 0x63, 0x0B, 0x63, 0x2C, 0x6B, 0x6C, 
+0x7B, 0xEE, 0x8C, 0x4F, 0x8C, 0x4F, 0x8C, 0x2F, 
+0x83, 0xEE, 0x52, 0x48, 0x4A, 0x68, 0x62, 0xEA, 
+0x63, 0x0B, 0x62, 0xEB, 0x4A, 0x28, 0x52, 0x89, 
+0x7B, 0x8E, 0x6A, 0xEB, 0x8C, 0x10, 0xAC, 0xF3, 
+0xCE, 0x17, 0xB5, 0x54, 0xBD, 0x95, 0x9C, 0x72, 
+0x94, 0x71, 0x4A, 0x89, 0x39, 0xE6, 0x39, 0xE7, 
+0x31, 0xA5, 0x31, 0xA5, 0x42, 0x28, 0x42, 0x28, 
+0x5A, 0xEB, 0x6B, 0x6D, 0x6B, 0x6E, 0x7B, 0xF0, 
+0x7C, 0x10, 0x7B, 0xF0, 0xA5, 0x14, 0xAD, 0x76, 
+0xC6, 0x18, 0xC6, 0x18, 0xA5, 0x14, 0x63, 0x0C, 
+0x4A, 0x48, 0x8C, 0x0F, 0xCE, 0x16, 0xC5, 0xF6, 
+0xB5, 0x53, 0xBD, 0xB4, 0xBD, 0x73, 0xBD, 0xB4, 
+0xAD, 0x12, 0x8C, 0x0E, 0x94, 0x4F, 0xA4, 0xAF, 
+0xAC, 0xF1, 0xC5, 0x93, 0xBD, 0x53, 0xBD, 0x53, 
+0xB5, 0x52, 0xA4, 0xD0, 0xA4, 0xB0, 0x9C, 0x8F, 
+0x9C, 0x70, 0x9C, 0x90, 0x9C, 0x90, 0x9C, 0x90, 
+0x9C, 0xB0, 0xAD, 0x11, 0xB5, 0x32, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAD, 0x12, 0xAD, 0x11, 
+0xAC, 0xF1, 0xAC, 0xD1, 0xA4, 0xB0, 0xA4, 0x90, 
+0x9C, 0x6F, 0x9C, 0x4F, 0x9C, 0x4F, 0x9C, 0x4F, 
+0x8B, 0xED, 0x8C, 0x0E, 0x8C, 0x0E, 0x8C, 0x0D, 
+0x94, 0x4E, 0x94, 0x2E, 0x94, 0x2E, 0x94, 0x2D, 
+0x94, 0x0D, 0x94, 0x4F, 0x8C, 0x0E, 0x94, 0x6F, 
+0xAC, 0xF1, 0xB5, 0x52, 0xAD, 0x12, 0xBD, 0x93, 
+0xC5, 0xB4, 0xC5, 0xD4, 0xDE, 0x55, 0xE6, 0x96, 
+0xD6, 0x35, 0xD6, 0x56, 0xC5, 0xD3, 0xCE, 0x15, 
+0xD6, 0x56, 0xC5, 0xD4, 0xCE, 0x15, 0xCE, 0x35, 
+0xCD, 0xF4, 0xCE, 0x14, 0xDE, 0x55, 0xD6, 0x55, 
+0xCD, 0xD4, 0xAD, 0x12, 0x9C, 0xF1, 0x8C, 0x4F, 
+0xA5, 0x12, 0xB5, 0x73, 0xB5, 0x74, 0xBD, 0x94, 
+0xB5, 0x73, 0xAD, 0x33, 0xAD, 0x53, 0xAD, 0x53, 
+0xB5, 0x73, 0xBD, 0xB4, 0xCE, 0x36, 0xCE, 0x56, 
+0xD6, 0x77, 0xD6, 0x98, 0xCE, 0x37, 0xB5, 0x74, 
+0x9C, 0xD2, 0x7B, 0xCF, 0x7B, 0xCE, 0x83, 0xEE, 
+0x73, 0x6D, 0x7B, 0xAE, 0x73, 0x4D, 0x6B, 0x2C, 
+0x73, 0x8E, 0xB5, 0x75, 0xAD, 0x53, 0xDE, 0xB9, 
+0xD6, 0x78, 0x84, 0x10, 0x94, 0x92, 0x94, 0x92, 
+0x84, 0x10, 0x42, 0x28, 0x31, 0xA5, 0x39, 0xC6, 
+0x31, 0xC6, 0x21, 0x64, 0x53, 0x29, 0x6C, 0x8B, 
+0x53, 0xC8, 0x53, 0xC8, 0x4B, 0x67, 0x2A, 0x03, 
+0x19, 0x41, 0x19, 0x62, 0x4B, 0x06, 0x4B, 0x66, 
+0x5B, 0xC9, 0x19, 0x82, 0x53, 0x49, 0x7C, 0xCD, 
+0x5B, 0xA9, 0x63, 0xEA, 0x63, 0xE9, 0x5B, 0xE9, 
+0x6C, 0x6A, 0x4B, 0x86, 0x43, 0x04, 0x8C, 0xCC, 
+0xDE, 0xF5, 0xAD, 0xD0, 0x7C, 0xAA, 0x4B, 0x24, 
+0x52, 0x89, 0x39, 0xC6, 0x52, 0xA9, 0x5A, 0xA9, 
+0x5A, 0xA9, 0x52, 0x48, 0x7B, 0xCD, 0xC5, 0xF4, 
+0xD6, 0x56, 0xB5, 0x32, 0x83, 0xED, 0xA4, 0xD0, 
+0xC5, 0xB4, 0x9C, 0x2E, 0xA4, 0x6E, 0xB4, 0xD0, 
+0x8B, 0xCC, 0x73, 0x2A, 0x7B, 0x6B, 0x83, 0xAC, 
+0x9C, 0x6E, 0xD6, 0x14, 0xCD, 0xB3, 0xCD, 0xB2, 
+0xBD, 0x72, 0xAC, 0xF0, 0xE6, 0x96, 0xDE, 0x54, 
+0xE6, 0x75, 0xC5, 0x92, 0x94, 0x0C, 0xBD, 0x51, 
+0xBD, 0x51, 0xA4, 0x6E, 0xAC, 0xAF, 0xBD, 0x51, 
+0xB4, 0xEF, 0xAC, 0xAE, 0xC5, 0x71, 0xE6, 0x96, 
+0xCD, 0xD3, 0xC5, 0x72, 0xC5, 0x92, 0xD6, 0x14, 
+0xD5, 0xF3, 0xC5, 0x71, 0xC5, 0x71, 0xC5, 0x91, 
+0xC5, 0x91, 0xBD, 0x51, 0xBD, 0x51, 0xAC, 0xEF, 
+0xAC, 0xEF, 0xB5, 0x10, 0xB5, 0x10, 0xB5, 0x30, 
+0xBD, 0x30, 0xB4, 0xEF, 0xAC, 0xAE, 0xAC, 0xCF, 
+0xA4, 0x8E, 0xA4, 0x6E, 0xA4, 0x6E, 0xAC, 0xCF, 
+0x9C, 0x2D, 0x8B, 0xEB, 0x8B, 0xCB, 0xB5, 0x10, 
+0xCD, 0xB2, 0xAC, 0x8D, 0xBD, 0x30, 0xC5, 0x71, 
+0xCD, 0x91, 0xCD, 0xB2, 0xCD, 0x71, 0xCD, 0xB2, 
+0xD5, 0xF3, 0xD5, 0xD2, 0xC5, 0x30, 0xCD, 0x92, 
+0xD5, 0xD2, 0xDE, 0x34, 0xDE, 0x34, 0xDE, 0x33, 
+0xDE, 0x33, 0xE6, 0x54, 0xE6, 0x53, 0xEE, 0x95, 
+0xF6, 0xB6, 0xE6, 0x55, 0x8B, 0xED, 0x39, 0xC6, 
+0x31, 0xA5, 0x31, 0xC6, 0x39, 0xE7, 0x42, 0x08, 
+0x52, 0xAA, 0x6B, 0x6D, 0x84, 0x30, 0x9D, 0x14, 
+0xAD, 0x55, 0xAD, 0x55, 0x6B, 0x4D, 0xB5, 0xB7, 
+0xDE, 0xDB, 0xEF, 0x5D, 0xEF, 0x7D, 0xDE, 0xBA, 
+0xBD, 0x95, 0xA4, 0xD3, 0x84, 0x10, 0x94, 0xB3, 
+0xEF, 0x5D, 0xDE, 0xDB, 0xD6, 0x7A, 0xEF, 0x3D, 
+0x73, 0x8E, 0x94, 0x6F, 0xCE, 0x35, 0xDE, 0x75, 
+0xD6, 0x34, 0xCD, 0xF4, 0xD6, 0x14, 0xCD, 0xF4, 
+0xCD, 0xF4, 0xC5, 0xD4, 0xC5, 0xD4, 0xCE, 0x15, 
+0xCE, 0x15, 0xCE, 0x14, 0xCD, 0xF4, 0xD6, 0x14, 
+0xB5, 0x30, 0xA4, 0x8E, 0x8B, 0xCD, 0x63, 0x2C, 
+0x5A, 0xEB, 0x63, 0x0B, 0x63, 0x4C, 0x73, 0x8D, 
+0x73, 0xAE, 0x7B, 0xEF, 0x84, 0x0F, 0x84, 0x2F, 
+0x84, 0x2F, 0x7B, 0xCE, 0x62, 0xEA, 0x52, 0x69, 
+0x52, 0x69, 0x52, 0x68, 0x62, 0xEB, 0x62, 0xCA, 
+0x7B, 0x8D, 0x7B, 0x8E, 0x73, 0x4C, 0x8C, 0x0F, 
+0xA4, 0xD2, 0x8C, 0x10, 0xA4, 0xD3, 0xB5, 0x76, 
+0xCE, 0x38, 0x8C, 0x51, 0x39, 0xE7, 0x3A, 0x07, 
+0x29, 0x65, 0x39, 0xC6, 0x42, 0x07, 0x39, 0xE7, 
+0x52, 0xCA, 0x63, 0x2C, 0x63, 0x0C, 0x73, 0xAF, 
+0x7B, 0xF0, 0x94, 0x93, 0xA5, 0x35, 0xA5, 0x15, 
+0xBD, 0xF8, 0xB5, 0xB6, 0xB5, 0x96, 0x5A, 0xCB, 
+0x39, 0xA6, 0x5A, 0xCA, 0x5A, 0xAA, 0x84, 0x0F, 
+0xB5, 0x74, 0xC6, 0x16, 0xA5, 0x12, 0xA4, 0xD2, 
+0xDE, 0x98, 0xC5, 0xB5, 0xB4, 0xF1, 0xAC, 0xD0, 
+0xB4, 0xD0, 0xCD, 0x92, 0xCD, 0x72, 0xCD, 0xB3, 
+0xC5, 0x93, 0x9C, 0x6F, 0xA4, 0xD1, 0xA4, 0xF2, 
+0x9C, 0x90, 0x94, 0x2F, 0x83, 0xED, 0x83, 0xED, 
+0x83, 0xCD, 0xA4, 0xB0, 0xAD, 0x11, 0xB5, 0x11, 
+0xB5, 0x31, 0xB5, 0x11, 0xB5, 0x31, 0xBD, 0x72, 
+0xCD, 0xD4, 0xC5, 0xB3, 0xCD, 0xB3, 0xCD, 0xB4, 
+0xCD, 0xD4, 0xC5, 0x73, 0xC5, 0x93, 0xC5, 0xB4, 
+0xC5, 0x93, 0xBD, 0x73, 0xBD, 0x73, 0xBD, 0x73, 
+0xBD, 0x73, 0xB5, 0x33, 0xAC, 0xF1, 0xAD, 0x11, 
+0xB5, 0x32, 0xB5, 0x53, 0xAD, 0x33, 0xAD, 0x12, 
+0xAC, 0xF1, 0xA4, 0xD0, 0x9C, 0x90, 0x9C, 0x90, 
+0x9C, 0x6F, 0x9C, 0x6F, 0x9C, 0x8F, 0x9C, 0x6F, 
+0x9C, 0x6F, 0x94, 0x2E, 0x8C, 0x2E, 0x94, 0x6F, 
+0xA4, 0xF1, 0xA4, 0xB0, 0xB5, 0x52, 0xBD, 0xB3, 
+0xBD, 0x73, 0xC5, 0xB3, 0xCD, 0xF4, 0xC5, 0xD3, 
+0xAC, 0xF0, 0xA4, 0xF1, 0x94, 0x90, 0x8C, 0x4F, 
+0xA4, 0xF2, 0xAD, 0x33, 0xA5, 0x32, 0xA4, 0xF2, 
+0xA4, 0xF2, 0xA4, 0xF2, 0xB5, 0x94, 0xC5, 0xD5, 
+0xCE, 0x57, 0xD6, 0x98, 0xD6, 0x57, 0xC5, 0xF6, 
+0xAD, 0x54, 0x94, 0x91, 0x7B, 0xEF, 0x8C, 0x50, 
+0xA4, 0xF2, 0x9C, 0xD2, 0x8C, 0x4F, 0x9C, 0xB1, 
+0x8B, 0xEE, 0x5A, 0x68, 0x5A, 0x68, 0x6B, 0x0B, 
+0x62, 0xCA, 0x7B, 0xAE, 0x73, 0x8D, 0xA5, 0x12, 
+0x94, 0x91, 0x52, 0x69, 0x39, 0xE7, 0x31, 0x86, 
+0x42, 0x28, 0x31, 0xC6, 0x31, 0xA5, 0x21, 0x44, 
+0x19, 0x23, 0x21, 0x44, 0x21, 0xA4, 0x5B, 0xC9, 
+0x5B, 0xE9, 0x3A, 0xE5, 0x4B, 0x27, 0x6B, 0xEB, 
+0x63, 0xCA, 0x74, 0x6C, 0x5C, 0x08, 0x5C, 0x28, 
+0x7C, 0xEC, 0x32, 0x65, 0x19, 0x83, 0x53, 0x49, 
+0x63, 0xEB, 0x84, 0xCD, 0x95, 0x4F, 0x7C, 0xAC, 
+0x6C, 0x2A, 0x43, 0x26, 0x4B, 0x65, 0x6C, 0x28, 
+0x85, 0x0A, 0x6C, 0x86, 0x4B, 0xA3, 0x43, 0x23, 
+0x52, 0x89, 0x42, 0x08, 0x42, 0x48, 0x52, 0x89, 
+0x5A, 0xCA, 0x62, 0xEB, 0xAD, 0x11, 0xD6, 0x35, 
+0xDE, 0x35, 0xDE, 0x55, 0xD6, 0x15, 0xCD, 0xF4, 
+0xCD, 0xF5, 0x9C, 0x4E, 0x9C, 0x2D, 0xCD, 0x72, 
+0xCD, 0xD4, 0xC5, 0xB3, 0xCD, 0xF4, 0xD6, 0x35, 
+0xD6, 0x14, 0xE6, 0x96, 0xDE, 0x76, 0xDE, 0x55, 
+0xDE, 0x76, 0xD6, 0x35, 0xDE, 0x55, 0xDE, 0x34, 
+0xD6, 0x13, 0xCD, 0xF4, 0xC5, 0xD4, 0xAD, 0x11, 
+0xBD, 0x72, 0xC5, 0xD4, 0xD6, 0x35, 0xEE, 0x97, 
+0xBD, 0x51, 0xA4, 0x6D, 0x94, 0x0C, 0xAC, 0xD0, 
+0x9C, 0x4D, 0x83, 0x8A, 0x8B, 0xCB, 0xAC, 0x8F, 
+0xA4, 0x4E, 0x93, 0xCB, 0x93, 0xEC, 0x93, 0xEC, 
+0x8B, 0xCB, 0x7B, 0x6A, 0x83, 0xAB, 0x94, 0x0C, 
+0x94, 0x2D, 0x8B, 0xEC, 0x7B, 0x4A, 0x83, 0xAB, 
+0x94, 0x0D, 0x94, 0x0C, 0xA4, 0x8E, 0xB5, 0x10, 
+0xB4, 0xEF, 0xBD, 0x30, 0xA4, 0x6D, 0xA4, 0x6D, 
+0xAC, 0xAE, 0xB4, 0xEF, 0xB5, 0x10, 0xB4, 0xEF, 
+0xB4, 0xEF, 0xB4, 0xCE, 0xAC, 0xCE, 0xAC, 0xEF, 
+0xAC, 0xCE, 0xAC, 0xCE, 0xB4, 0xEF, 0xB4, 0xEF, 
+0xB4, 0xEF, 0xB4, 0xCE, 0xB4, 0xEF, 0xB4, 0xEF, 
+0xAC, 0xAE, 0xAC, 0xCE, 0xAC, 0xAE, 0xA4, 0x8D, 
+0xAC, 0xAE, 0xBD, 0x0F, 0xBD, 0x0F, 0xB4, 0xEE, 
+0xB4, 0xCE, 0xB4, 0xEF, 0xBD, 0x10, 0x9C, 0x2E, 
+0x5A, 0x88, 0x39, 0xE6, 0x31, 0xA6, 0x31, 0xA6, 
+0x31, 0xC6, 0x4A, 0x48, 0x5B, 0x0B, 0x73, 0xAF, 
+0x73, 0x8E, 0x63, 0x0C, 0x9C, 0xF3, 0xA5, 0x35, 
+0xC6, 0x39, 0xCE, 0x7A, 0xD6, 0xBB, 0xEF, 0x5D, 
+0xD6, 0x9A, 0xCE, 0x38, 0xC6, 0x18, 0x94, 0x92, 
+0xBD, 0xD7, 0x84, 0x10, 0x9C, 0xD4, 0xD6, 0x9A, 
+0xAD, 0x75, 0xB5, 0x52, 0xD6, 0x14, 0xE6, 0x96, 
+0xEE, 0xD6, 0xEE, 0xD7, 0xE6, 0x96, 0xE6, 0x96, 
+0xDE, 0x35, 0xDE, 0x55, 0xDE, 0x75, 0xDE, 0x55, 
+0xD6, 0x14, 0xD6, 0x14, 0xDE, 0x76, 0xCD, 0xD3, 
+0x9C, 0x6E, 0xA4, 0xAF, 0x8B, 0xED, 0x6B, 0x2C, 
+0x6B, 0x6D, 0x6B, 0x4C, 0x6B, 0x4C, 0x73, 0xAE, 
+0x73, 0xAD, 0x84, 0x0F, 0x8C, 0x30, 0x8C, 0x30, 
+0x84, 0x0F, 0x83, 0xEF, 0x8C, 0x30, 0x73, 0x8D, 
+0x4A, 0x48, 0x39, 0xC6, 0x5A, 0xCA, 0x6B, 0x4C, 
+0x83, 0xCE, 0x41, 0xE7, 0x5A, 0xAA, 0x6B, 0x0B, 
+0x83, 0xCF, 0xBD, 0xB6, 0xBD, 0xD7, 0x94, 0x72, 
+0xBD, 0xF7, 0xAD, 0x34, 0x5A, 0xCA, 0x42, 0x07, 
+0x31, 0xA6, 0x31, 0xA6, 0x39, 0xE7, 0x31, 0xC6, 
+0x31, 0xA6, 0x42, 0x28, 0x52, 0xAA, 0x63, 0x2C, 
+0x6B, 0x4D, 0x73, 0xAF, 0x84, 0x31, 0x8C, 0x52, 
+0xB5, 0xB7, 0xC6, 0x19, 0xCE, 0x7A, 0x9C, 0xD3, 
+0x42, 0x29, 0x4A, 0x49, 0x5A, 0xAB, 0x5A, 0xCB, 
+0x5A, 0xCB, 0x73, 0x8D, 0x83, 0xEF, 0x8C, 0x50, 
+0xD6, 0x58, 0xBD, 0x54, 0xBD, 0x32, 0xAC, 0x8E, 
+0xC5, 0x10, 0xDD, 0xB2, 0xDD, 0xB2, 0xD5, 0xD3, 
+0xC5, 0x93, 0xA4, 0xD1, 0xBD, 0x94, 0xC5, 0xD5, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0x94, 
+0xBD, 0x94, 0xC5, 0x93, 0xC5, 0xB3, 0xC5, 0xB3, 
+0xCD, 0xD4, 0xCD, 0xD3, 0xCD, 0xB3, 0xBD, 0x51, 
+0xBD, 0x31, 0xA4, 0x8E, 0xA4, 0x8E, 0xC5, 0x51, 
+0xCD, 0xB3, 0xD5, 0xD4, 0xCD, 0xD3, 0xD5, 0xD4, 
+0xEE, 0x97, 0xB5, 0x32, 0xB5, 0x32, 0xC5, 0x94, 
+0xB5, 0x53, 0xA4, 0xB1, 0xA4, 0xD1, 0xB5, 0x52, 
+0xBD, 0x73, 0xBD, 0x73, 0xBD, 0x94, 0xC5, 0xD4, 
+0xBD, 0x93, 0xC5, 0x94, 0xBD, 0x93, 0xC5, 0x94, 
+0xC5, 0xB4, 0xC5, 0x94, 0xBD, 0x93, 0xBD, 0x73, 
+0xB5, 0x53, 0xBD, 0x53, 0xB5, 0x32, 0xA4, 0xB0, 
+0x9C, 0x90, 0x9C, 0x90, 0x9C, 0x70, 0x94, 0x4F, 
+0x8C, 0x0F, 0x73, 0x6C, 0x83, 0xED, 0x8C, 0x2E, 
+0x94, 0x70, 0x9C, 0xB0, 0xA4, 0xF2, 0xA5, 0x12, 
+0x9C, 0xD1, 0x9C, 0x91, 0x9C, 0xB2, 0xA5, 0x13, 
+0xB5, 0x54, 0xBD, 0xB5, 0xCE, 0x37, 0xC5, 0xD6, 
+0xAD, 0x54, 0x94, 0x51, 0x73, 0x8D, 0x6B, 0x4D, 
+0x6B, 0x4D, 0x83, 0xEF, 0xAD, 0x13, 0xB5, 0x73, 
+0xA5, 0x11, 0x83, 0xEE, 0x7B, 0x8C, 0x7B, 0xAD, 
+0x83, 0xCD, 0x83, 0xEE, 0x83, 0xAD, 0x6B, 0x0B, 
+0x4A, 0x08, 0x41, 0xE7, 0x31, 0x65, 0x42, 0x27, 
+0x42, 0x07, 0x41, 0xE7, 0x31, 0x86, 0x31, 0xA6, 
+0x4A, 0x69, 0x52, 0x89, 0x5B, 0x0A, 0x42, 0xA7, 
+0x42, 0xC7, 0x53, 0x28, 0x42, 0xC6, 0x53, 0x88, 
+0x6C, 0x4B, 0x4B, 0x07, 0x95, 0x6F, 0x9D, 0xD0, 
+0x95, 0x90, 0x95, 0xB0, 0x7C, 0xEC, 0x74, 0xCA, 
+0x74, 0xAA, 0x21, 0xC3, 0x19, 0x43, 0x32, 0x05, 
+0x11, 0x02, 0x63, 0xAB, 0x95, 0x70, 0x8D, 0x2F, 
+0x43, 0x06, 0x19, 0xA1, 0x32, 0x83, 0x4B, 0x85, 
+0x5C, 0x46, 0x54, 0x04, 0x4B, 0xA4, 0x4B, 0x85, 
+0x7B, 0xEF, 0x73, 0x8D, 0x73, 0x8D, 0x7B, 0xEE, 
+0x84, 0x0F, 0x8C, 0x4F, 0xC5, 0xF5, 0xD6, 0x35, 
+0xD6, 0x14, 0xD6, 0x34, 0xDE, 0x55, 0xDE, 0x76, 
+0xCE, 0x15, 0x9C, 0x4E, 0x93, 0xCC, 0x93, 0xCC, 
+0xA4, 0x6E, 0xDE, 0x55, 0xE6, 0x76, 0xDE, 0x76, 
+0xD6, 0x14, 0xDE, 0x55, 0xDE, 0x55, 0xDE, 0x55, 
+0xDE, 0x75, 0xDE, 0x75, 0xE6, 0xB6, 0xDE, 0x55, 
+0xDE, 0x55, 0xD6, 0x14, 0xDE, 0x76, 0xDE, 0x76, 
+0xE6, 0x96, 0xE6, 0xB7, 0xE6, 0xB7, 0xE6, 0x76, 
+0xBD, 0x31, 0xC5, 0x71, 0xD5, 0xB3, 0xD5, 0xD3, 
+0xD5, 0xD4, 0xC5, 0x72, 0xC5, 0x51, 0xD5, 0x72, 
+0xDD, 0xB2, 0xD5, 0x92, 0xD5, 0x92, 0xC5, 0x51, 
+0xB4, 0xF0, 0x9C, 0x8F, 0xB5, 0x52, 0xC5, 0xB3, 
+0xB5, 0x31, 0xA4, 0xAF, 0x94, 0x6F, 0x94, 0x4E, 
+0x8B, 0xEC, 0x83, 0xAB, 0x83, 0xAB, 0xA4, 0x8E, 
+0xB5, 0x10, 0xDE, 0x75, 0xAC, 0xEF, 0xAD, 0x0F, 
+0xCD, 0xF3, 0xC5, 0xD2, 0xBD, 0x91, 0xB5, 0x0F, 
+0xCD, 0xD2, 0xBD, 0x51, 0xAD, 0x0F, 0xC5, 0xB2, 
+0xBD, 0x30, 0xAC, 0xEF, 0xAC, 0xAE, 0xA4, 0x6D, 
+0xA4, 0x6D, 0xA4, 0x8E, 0xAC, 0xCF, 0xA4, 0xAE, 
+0xA4, 0x8D, 0xB4, 0xCF, 0xB4, 0xEF, 0xB4, 0xCE, 
+0xEE, 0x95, 0xE6, 0x54, 0xC5, 0x70, 0xBD, 0x2F, 
+0xCD, 0x91, 0xCD, 0x91, 0xC5, 0x51, 0xD5, 0xF4, 
+0xD5, 0xF4, 0xB4, 0xEF, 0x73, 0x29, 0x39, 0xC5, 
+0x31, 0xA5, 0x31, 0xA6, 0x42, 0x28, 0x63, 0x2C, 
+0x4A, 0x49, 0x5A, 0xAA, 0x8C, 0x51, 0x84, 0x31, 
+0xB5, 0xD7, 0xCE, 0x9B, 0xCE, 0x7B, 0xCE, 0x7A, 
+0xBD, 0xD8, 0xDE, 0xFC, 0xF7, 0x9E, 0xB5, 0x96, 
+0x7B, 0xD0, 0x5A, 0xCB, 0xA4, 0xF4, 0xBD, 0xB7, 
+0xA4, 0xF4, 0x9C, 0x91, 0xAD, 0x11, 0xB5, 0x10, 
+0xAC, 0xAE, 0xAC, 0xCF, 0xB5, 0x10, 0xBD, 0x72, 
+0xC5, 0xB3, 0xD5, 0xF4, 0xDE, 0x75, 0xE6, 0x96, 
+0xEE, 0xD6, 0xEE, 0xD7, 0xE6, 0x96, 0xC5, 0xB3, 
+0x9C, 0x6E, 0xAC, 0xCF, 0x7B, 0x8C, 0x52, 0x89, 
+0x6B, 0x8D, 0x73, 0x8D, 0x63, 0x4C, 0x7C, 0x0F, 
+0x7B, 0xEE, 0x84, 0x0F, 0x7B, 0xCE, 0x83, 0xEF, 
+0x8C, 0x30, 0x84, 0x0F, 0x84, 0x0F, 0x94, 0x91, 
+0x83, 0xEE, 0x5A, 0xA9, 0x42, 0x27, 0x52, 0x89, 
+0x83, 0xEF, 0x6B, 0x2C, 0x39, 0xA6, 0x52, 0x48, 
+0x8C, 0x30, 0xCE, 0x59, 0xCE, 0x59, 0x9C, 0xF4, 
+0x9C, 0xF3, 0xAD, 0x54, 0x8C, 0x30, 0x52, 0x89, 
+0x39, 0xC6, 0x31, 0xA6, 0x39, 0xE6, 0x42, 0x07, 
+0x39, 0xE6, 0x42, 0x27, 0x4A, 0x89, 0x4A, 0x69, 
+0x52, 0xAB, 0x6B, 0x8E, 0x84, 0x31, 0x94, 0xD4, 
+0xB5, 0x97, 0xB5, 0xB7, 0xC6, 0x39, 0xC6, 0x39, 
+0x63, 0x0D, 0x5A, 0xAB, 0x73, 0x8E, 0x63, 0x2C, 
+0x94, 0x72, 0x94, 0x92, 0x94, 0x92, 0x7B, 0xEF, 
+0xA4, 0xF3, 0xBD, 0xD6, 0xD6, 0x36, 0xCD, 0x52, 
+0xDD, 0x92, 0xD5, 0x71, 0xDD, 0xB2, 0xD5, 0xD3, 
+0xBD, 0x72, 0xAC, 0xF1, 0xBD, 0x74, 0xB5, 0x73, 
+0xBD, 0x93, 0xBD, 0x93, 0xBD, 0x73, 0xC5, 0xD4, 
+0xCE, 0x15, 0xCD, 0xF4, 0xCD, 0xF4, 0xD6, 0x14, 
+0xD5, 0xF4, 0xD5, 0xF4, 0xD5, 0xD3, 0xD6, 0x14, 
+0xCD, 0xD3, 0xB4, 0xF0, 0xC5, 0x72, 0xCD, 0xB3, 
+0xCD, 0xB3, 0xAC, 0xCF, 0xB5, 0x10, 0xC5, 0x31, 
+0xC5, 0x52, 0x9C, 0x6F, 0xCE, 0x15, 0xCE, 0x56, 
+0xBD, 0xD4, 0xB5, 0x94, 0xAD, 0x32, 0xAD, 0x32, 
+0xBD, 0xB4, 0xCE, 0x15, 0xD6, 0x35, 0xCD, 0xF4, 
+0xBD, 0x72, 0xB5, 0x11, 0xB5, 0x52, 0xAC, 0xF1, 
+0xB5, 0x32, 0xBD, 0x53, 0xBD, 0x53, 0xBD, 0x73, 
+0xB5, 0x32, 0xBD, 0x73, 0xC5, 0xB4, 0xC5, 0xD5, 
+0xAD, 0x32, 0xA4, 0xD1, 0xA4, 0xF1, 0xCD, 0xB4, 
+0xC5, 0x93, 0xDE, 0x56, 0xD6, 0x57, 0xD6, 0x57, 
+0xD6, 0x37, 0xCE, 0x16, 0xCE, 0x37, 0xCE, 0x58, 
+0xCE, 0x58, 0xCE, 0x59, 0xC6, 0x38, 0xBD, 0xD7, 
+0xAD, 0x55, 0xA5, 0x14, 0x8C, 0x30, 0x7B, 0xAE, 
+0x8C, 0x10, 0x9C, 0xB2, 0xAD, 0x33, 0xB5, 0x74, 
+0xB5, 0x53, 0xB5, 0x53, 0xAD, 0x53, 0xAD, 0x32, 
+0xA5, 0x12, 0xB5, 0x53, 0xAD, 0x53, 0xAD, 0x53, 
+0xB5, 0x74, 0xB5, 0x53, 0xAD, 0x33, 0xAD, 0x12, 
+0xA4, 0xD2, 0x94, 0x70, 0x83, 0xEF, 0x4A, 0x08, 
+0x94, 0x30, 0x9C, 0xB1, 0x83, 0xEF, 0x84, 0x10, 
+0x94, 0x71, 0x7C, 0x0E, 0x73, 0xEC, 0x5B, 0xEA, 
+0x6C, 0x6B, 0x53, 0xA8, 0x32, 0x44, 0x43, 0x06, 
+0x42, 0xC6, 0x42, 0xE6, 0x6C, 0x6A, 0x85, 0x2D, 
+0x8D, 0x8F, 0x95, 0xAF, 0x85, 0x2D, 0x85, 0x2C, 
+0x85, 0x4D, 0x3A, 0xA5, 0x42, 0x66, 0x31, 0xE5, 
+0x10, 0xC2, 0x19, 0x43, 0x5B, 0x8A, 0x9D, 0x70, 
+0x5B, 0x89, 0x32, 0x44, 0x22, 0x02, 0x32, 0xC3, 
+0x53, 0xC5, 0x95, 0xCC, 0x74, 0xC9, 0x3B, 0x04, 
+0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x53, 0xAD, 0x53, 
+0xB5, 0x73, 0xBD, 0xB3, 0xCE, 0x15, 0xD6, 0x35, 
+0xD6, 0x14, 0xD6, 0x14, 0xD6, 0x55, 0xE6, 0xB7, 
+0xCD, 0xF5, 0x9C, 0x2E, 0xA4, 0x0D, 0xB4, 0xAF, 
+0xD5, 0xF4, 0xDE, 0x76, 0xDE, 0x34, 0xDE, 0x55, 
+0xDE, 0x55, 0xDE, 0x55, 0xE6, 0x75, 0xE6, 0x76, 
+0xD6, 0x14, 0xD6, 0x14, 0xE6, 0x96, 0xDE, 0x75, 
+0xD6, 0x34, 0xCD, 0xF3, 0xDE, 0x55, 0xE6, 0x75, 
+0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x55, 
+0xBD, 0x10, 0xAC, 0xAE, 0xC5, 0x10, 0xDD, 0xF4, 
+0xD5, 0xD3, 0xD5, 0xB3, 0xCD, 0x92, 0xD5, 0x71, 
+0xD5, 0x71, 0xCD, 0x51, 0xCD, 0x51, 0xCD, 0x51, 
+0xCD, 0x92, 0xC5, 0x92, 0xDE, 0x56, 0xCD, 0xD4, 
+0xB5, 0x31, 0xA4, 0xAF, 0x8B, 0xED, 0x8C, 0x0D, 
+0x83, 0xCC, 0x83, 0xCC, 0x8B, 0xEC, 0xA4, 0x8E, 
+0xB5, 0x10, 0xD6, 0x55, 0xB5, 0x71, 0xBD, 0x91, 
+0xC6, 0x12, 0xC6, 0x32, 0xCE, 0x74, 0xAD, 0x50, 
+0xD6, 0x95, 0xD6, 0x94, 0xD6, 0xD5, 0xDE, 0xB5, 
+0xB5, 0x30, 0xB5, 0x30, 0xB5, 0x31, 0xA4, 0xEF, 
+0x9C, 0xAE, 0xB5, 0x51, 0xC5, 0xB2, 0xA4, 0xCF, 
+0xB5, 0x10, 0xBD, 0x50, 0xAC, 0xCE, 0xAC, 0xAD, 
+0xE6, 0x75, 0xDE, 0x33, 0xCD, 0xD2, 0xB5, 0x0F, 
+0xA4, 0x8E, 0xAC, 0xCE, 0x9C, 0x6D, 0xA4, 0x6E, 
+0xD5, 0xF3, 0xDE, 0x13, 0xDE, 0x13, 0xAC, 0xCF, 
+0x5A, 0x88, 0x31, 0x85, 0x39, 0xE7, 0x52, 0x8A, 
+0x42, 0x07, 0x42, 0x28, 0x63, 0x0C, 0x7B, 0xEF, 
+0x8C, 0x92, 0xA5, 0x35, 0xBD, 0xF8, 0xCE, 0x9B, 
+0xCE, 0x5A, 0xBD, 0xF8, 0xBD, 0xF8, 0x94, 0x93, 
+0xC5, 0xF8, 0x8C, 0x72, 0xA5, 0x35, 0xEF, 0x3D, 
+0xD6, 0x9A, 0x9C, 0xB3, 0x8C, 0x0F, 0xB5, 0x32, 
+0xC5, 0x72, 0xBD, 0x51, 0xAC, 0xAF, 0xA4, 0x8F, 
+0x94, 0x2D, 0x8B, 0xEC, 0x8B, 0xEB, 0x8B, 0xCB, 
+0x8B, 0xCC, 0x94, 0x0C, 0x9C, 0x4D, 0x94, 0x2D, 
+0x9C, 0x4D, 0xAC, 0xAF, 0xAC, 0xAF, 0x7B, 0xAC, 
+0x7B, 0x8D, 0x6B, 0x0B, 0x63, 0x0B, 0x73, 0xAE, 
+0x6B, 0x6D, 0x6B, 0x4C, 0x6B, 0x2C, 0x73, 0xAD, 
+0x7B, 0xEE, 0x7B, 0xCE, 0x84, 0x0F, 0x94, 0xB1, 
+0xA4, 0xF2, 0x94, 0xB1, 0x6B, 0x4C, 0x4A, 0x28, 
+0x4A, 0x48, 0x5A, 0xAA, 0x4A, 0x28, 0x62, 0xEB, 
+0x73, 0x8E, 0xAD, 0x75, 0xC5, 0xF8, 0xBD, 0xB7, 
+0x9C, 0xD3, 0x7B, 0xCF, 0x73, 0x6D, 0x6B, 0x6C, 
+0x4A, 0x48, 0x31, 0xC6, 0x39, 0xE7, 0x42, 0x07, 
+0x42, 0x27, 0x39, 0xE7, 0x4A, 0x69, 0x52, 0xCB, 
+0x63, 0x2C, 0x6B, 0x6E, 0x7B, 0xD0, 0x9C, 0xD4, 
+0x9D, 0x15, 0xA5, 0x36, 0xB5, 0xB8, 0xC6, 0x19, 
+0x9C, 0xD4, 0x73, 0x8F, 0x7B, 0xAE, 0x9C, 0xD2, 
+0xA4, 0xF3, 0xAD, 0x55, 0x9C, 0xD3, 0x9C, 0xB3, 
+0xA5, 0x14, 0x7B, 0xAE, 0x73, 0x6D, 0x8B, 0xEE, 
+0xBD, 0x11, 0xAC, 0x8E, 0xCD, 0x51, 0xCD, 0x92, 
+0xBD, 0x51, 0xAC, 0xF1, 0xB5, 0x32, 0xBD, 0xB4, 
+0xC5, 0xD5, 0xC5, 0xB4, 0xC5, 0xB4, 0xB5, 0x72, 
+0xBD, 0x93, 0xC5, 0xB3, 0xC5, 0xB3, 0xD6, 0x14, 
+0xBD, 0x72, 0x83, 0x8B, 0xBD, 0x51, 0xCD, 0xB2, 
+0xDE, 0x35, 0xC5, 0x93, 0xDE, 0x35, 0xD6, 0x14, 
+0xDE, 0x35, 0xC5, 0x51, 0xBD, 0x30, 0xC5, 0x72, 
+0xD6, 0x14, 0xA4, 0xB0, 0xD6, 0x56, 0xCE, 0x16, 
+0xBD, 0xD4, 0xC6, 0x36, 0xCE, 0x57, 0xC5, 0xD4, 
+0xBD, 0xB4, 0xBD, 0xB4, 0xD6, 0x56, 0xDE, 0xB7, 
+0xD6, 0x56, 0xCE, 0x15, 0xBD, 0x93, 0xB5, 0x52, 
+0xB5, 0x72, 0xB5, 0x73, 0xD6, 0x56, 0xCE, 0x15, 
+0xBD, 0x93, 0xBD, 0xB3, 0xBD, 0x93, 0xC5, 0xF4, 
+0xD6, 0x56, 0x9C, 0x90, 0xAD, 0x12, 0xDE, 0x15, 
+0xD5, 0x52, 0xE6, 0x35, 0xD6, 0x16, 0xBD, 0x94, 
+0xB5, 0x54, 0xB5, 0x95, 0xAD, 0x54, 0x94, 0x71, 
+0x73, 0xAE, 0x7B, 0x8E, 0x94, 0x51, 0x9C, 0xB2, 
+0x9C, 0xD2, 0x9C, 0x91, 0xBD, 0x74, 0xD6, 0x36, 
+0xE6, 0x57, 0xE6, 0x77, 0xE6, 0x97, 0xE6, 0xB7, 
+0xE6, 0xD8, 0xEE, 0xF8, 0xAD, 0x32, 0xAD, 0x32, 
+0xBD, 0x94, 0xBD, 0xB3, 0xC5, 0xB4, 0xC5, 0xD4, 
+0xC5, 0xD4, 0xBD, 0x94, 0xB5, 0x53, 0xB5, 0x73, 
+0xB5, 0x54, 0xDE, 0x99, 0xC5, 0xD6, 0x7B, 0x6D, 
+0xC5, 0x95, 0x9C, 0x91, 0x62, 0xEB, 0x84, 0x10, 
+0x9C, 0xB2, 0x7B, 0xCD, 0x7C, 0x8E, 0x74, 0xAC, 
+0x6C, 0x6B, 0x32, 0x85, 0x21, 0x82, 0x3A, 0x86, 
+0x11, 0x21, 0x4B, 0x27, 0x6C, 0x8A, 0x85, 0x4D, 
+0x95, 0xB0, 0x8D, 0x6F, 0x85, 0x2D, 0x85, 0x2D, 
+0x7C, 0xEC, 0x21, 0xE3, 0x53, 0x29, 0x29, 0xA3, 
+0x10, 0xE2, 0x19, 0x23, 0x3A, 0x26, 0x63, 0xAB, 
+0x4A, 0xE8, 0x32, 0x25, 0x42, 0xC6, 0x43, 0x06, 
+0x53, 0xC7, 0x74, 0xCA, 0x53, 0xC6, 0x3B, 0x25, 
+0xB5, 0x73, 0xC5, 0xF5, 0xCE, 0x16, 0xCE, 0x36, 
+0xD6, 0x56, 0xD6, 0x56, 0xDE, 0x55, 0xDE, 0x55, 
+0xDE, 0x55, 0xDE, 0x55, 0xDE, 0x76, 0xD6, 0x35, 
+0xB5, 0x31, 0xAC, 0x8F, 0xCD, 0x11, 0xDD, 0x93, 
+0xDD, 0xF4, 0xE6, 0x76, 0xDE, 0x34, 0xDE, 0x35, 
+0xDE, 0x55, 0xDE, 0x35, 0xDE, 0x55, 0xDE, 0x55, 
+0xDE, 0x35, 0xDE, 0x34, 0xE6, 0x96, 0xE6, 0x75, 
+0xDE, 0x55, 0xDE, 0x34, 0xDE, 0x55, 0xDE, 0x55, 
+0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x55, 
+0xAC, 0x8E, 0xA4, 0x2C, 0xA4, 0x4D, 0xCD, 0x92, 
+0xDD, 0xF4, 0xD5, 0xD3, 0xCD, 0x51, 0xCD, 0x51, 
+0xC5, 0x0F, 0xBC, 0xCF, 0xBC, 0xCF, 0xB4, 0xAF, 
+0xBD, 0x30, 0xC5, 0x92, 0xCD, 0xF4, 0xCD, 0xD3, 
+0xAC, 0xF0, 0xA4, 0xCF, 0x8C, 0x2E, 0x8C, 0x0D, 
+0x8C, 0x0D, 0x83, 0xCC, 0x94, 0x4E, 0xAC, 0xF0, 
+0xB5, 0x30, 0xCE, 0x14, 0xB5, 0x30, 0xBD, 0xB2, 
+0xBE, 0x32, 0xBE, 0x32, 0xC6, 0x53, 0xBE, 0x33, 
+0xCE, 0xB4, 0xD6, 0xF5, 0xDF, 0x36, 0xC6, 0x33, 
+0xC5, 0xD3, 0xBD, 0xB3, 0xC5, 0xD3, 0xBD, 0xB3, 
+0xBD, 0xB3, 0xC5, 0xF4, 0xCD, 0xF4, 0xAC, 0xEF, 
+0xBD, 0x51, 0xAC, 0xCF, 0xAC, 0xAE, 0xAC, 0xCE, 
+0xEE, 0xB5, 0xE6, 0x75, 0xE6, 0x95, 0xEE, 0xD6, 
+0xD6, 0x14, 0xB5, 0x30, 0xA4, 0xAF, 0xAC, 0xD0, 
+0xD5, 0xF3, 0xDE, 0x12, 0xD5, 0xF3, 0xD5, 0xF2, 
+0xCD, 0xD2, 0x9C, 0x8E, 0x52, 0x67, 0x31, 0x85, 
+0x21, 0x24, 0x31, 0x85, 0x3A, 0x07, 0x4A, 0x69, 
+0x5A, 0xEB, 0x73, 0xAE, 0x84, 0x31, 0x84, 0x31, 
+0xAD, 0x76, 0xC6, 0x39, 0xC6, 0x39, 0x94, 0x93, 
+0xAD, 0x56, 0x83, 0xF0, 0xBD, 0xF8, 0xEF, 0x5D, 
+0xD6, 0x9A, 0xE7, 0x1C, 0xBD, 0xD7, 0x73, 0x6D, 
+0x94, 0x4F, 0xAC, 0xF1, 0x9C, 0x4E, 0x94, 0x2D, 
+0xA4, 0x8F, 0xAC, 0xCF, 0xB5, 0x30, 0xBD, 0x31, 
+0xB5, 0x10, 0xB4, 0xEF, 0xAC, 0xAF, 0xAC, 0xCF, 
+0xB4, 0xF0, 0xAC, 0xCF, 0xB4, 0xF0, 0xB5, 0x10, 
+0xAC, 0xAF, 0xA4, 0x6F, 0x9C, 0x6F, 0x9C, 0x6F, 
+0x94, 0x2E, 0x94, 0x2E, 0x8B, 0xED, 0x8B, 0xED, 
+0x83, 0xED, 0x83, 0xEE, 0x83, 0xCD, 0x7B, 0xAD, 
+0x83, 0xCD, 0x7B, 0xCD, 0x83, 0xEE, 0x63, 0x0A, 
+0x41, 0xE7, 0x52, 0x69, 0x4A, 0x28, 0x52, 0x89, 
+0x62, 0xEB, 0x84, 0x30, 0xAD, 0x76, 0xB5, 0x76, 
+0x8C, 0x31, 0x73, 0x8E, 0x73, 0x6D, 0x6B, 0x4D, 
+0x63, 0x0B, 0x39, 0xC6, 0x42, 0x07, 0x39, 0xC6, 
+0x31, 0xA6, 0x3A, 0x07, 0x4A, 0x48, 0x4A, 0x48, 
+0x5A, 0xCB, 0x52, 0x8A, 0x5A, 0xEC, 0x84, 0x52, 
+0x94, 0xD4, 0x9C, 0xF5, 0xAD, 0x97, 0xCE, 0x5A, 
+0xD6, 0x7A, 0x9C, 0xB3, 0x73, 0x8E, 0x73, 0x8E, 
+0xB5, 0x96, 0xBD, 0xB7, 0xC5, 0xF8, 0xBD, 0xD7, 
+0xC5, 0xF8, 0xAD, 0x55, 0xA5, 0x14, 0xBD, 0xB6, 
+0xC5, 0xD6, 0xA4, 0x90, 0xC5, 0x32, 0xC5, 0x51, 
+0xBD, 0x52, 0xAD, 0x12, 0xB5, 0x53, 0xC5, 0xD4, 
+0xC5, 0x93, 0xB5, 0x11, 0xC5, 0x93, 0xC5, 0xB3, 
+0xBD, 0x52, 0xC5, 0x93, 0xC5, 0xB3, 0xD6, 0x35, 
+0xB5, 0x11, 0xAC, 0xD0, 0xC5, 0x72, 0xC5, 0x92, 
+0xCD, 0xB2, 0xDE, 0x35, 0xD6, 0x14, 0xD5, 0xF4, 
+0xD6, 0x14, 0xC5, 0x52, 0xC5, 0x71, 0xC5, 0x51, 
+0xAC, 0xAF, 0xAC, 0xD0, 0xD6, 0x56, 0xC5, 0xF4, 
+0xBD, 0xD4, 0xC5, 0xF5, 0xC6, 0x15, 0xBD, 0xD4, 
+0xC6, 0x15, 0xC5, 0xF4, 0xC5, 0xD4, 0xD6, 0x76, 
+0xDE, 0x96, 0xDE, 0xB7, 0xDE, 0xB7, 0xCE, 0x56, 
+0xDE, 0x97, 0xDE, 0x97, 0xCE, 0x36, 0xC5, 0xF5, 
+0xCE, 0x15, 0xCE, 0x15, 0xCE, 0x35, 0xD6, 0x56, 
+0xD6, 0x76, 0xA4, 0xD1, 0xB5, 0x32, 0xDD, 0xD4, 
+0xDD, 0x72, 0xDD, 0xD4, 0x8B, 0xAE, 0x73, 0x4D, 
+0x62, 0xCA, 0x73, 0x4B, 0x83, 0x8C, 0x9C, 0x2F, 
+0xD6, 0x57, 0xE6, 0xF9, 0xE6, 0xD9, 0xDE, 0x97, 
+0xE6, 0xB8, 0xE6, 0x97, 0xDE, 0x36, 0xE6, 0x35, 
+0xDD, 0xF4, 0xDD, 0xD4, 0xDD, 0xD4, 0xDE, 0x15, 
+0xDE, 0x56, 0xEF, 0x19, 0x9C, 0x90, 0xAD, 0x33, 
+0xCE, 0x15, 0xC5, 0xD4, 0xC5, 0xD4, 0xCD, 0xF4, 
+0xD6, 0x15, 0xD6, 0x15, 0xD6, 0x36, 0xD6, 0x37, 
+0xBD, 0x95, 0xEF, 0x3B, 0xB5, 0x75, 0x9C, 0x91, 
+0xCD, 0xD5, 0xA4, 0x91, 0x52, 0x49, 0x73, 0x4D, 
+0x8C, 0x2F, 0x84, 0x2E, 0x74, 0x4C, 0x64, 0x2A, 
+0x4B, 0x47, 0x19, 0x42, 0x19, 0x63, 0x32, 0x25, 
+0x19, 0x42, 0x53, 0x69, 0x85, 0x4E, 0x9D, 0xD0, 
+0x95, 0xD0, 0x8D, 0x4E, 0x85, 0x2C, 0x74, 0xCB, 
+0x43, 0x05, 0x2A, 0x04, 0x5B, 0x69, 0x29, 0xE4, 
+0x31, 0xE5, 0x42, 0x67, 0x4A, 0xE8, 0x6B, 0xEB, 
+0x5B, 0x69, 0x3A, 0x66, 0x4A, 0xE7, 0x5B, 0xA9, 
+0x85, 0x0E, 0x7D, 0x0C, 0x6C, 0x69, 0x4B, 0xA6, 
+0x73, 0x6B, 0x83, 0xED, 0x9C, 0x6F, 0xA4, 0xD1, 
+0xAC, 0xF1, 0xB5, 0x32, 0xBD, 0x72, 0xC5, 0xB3, 
+0xC5, 0xB3, 0xBD, 0x72, 0xC5, 0xB3, 0x9C, 0x6E, 
+0x9C, 0x4E, 0xA4, 0x4E, 0xD5, 0x31, 0xE5, 0xD4, 
+0xDD, 0xF4, 0xDE, 0x14, 0xDE, 0x34, 0xE6, 0x55, 
+0xE6, 0x96, 0xE6, 0x75, 0xE6, 0x96, 0xDE, 0x34, 
+0xDE, 0x14, 0xDE, 0x14, 0xDE, 0x55, 0xDE, 0x55, 
+0xE6, 0x55, 0xC5, 0x71, 0xDE, 0x14, 0xE6, 0x55, 
+0xE6, 0x55, 0xE6, 0x75, 0xE6, 0x75, 0xE6, 0x55, 
+0xAC, 0xAE, 0x9C, 0x2C, 0x8B, 0xAB, 0xAC, 0xAE, 
+0xA4, 0x6E, 0xB4, 0xAF, 0xB4, 0xCF, 0xBC, 0xCF, 
+0xC5, 0x0F, 0xC5, 0x0F, 0xBC, 0xCF, 0xB4, 0xCF, 
+0xB5, 0x10, 0xCD, 0xD3, 0xD6, 0x35, 0xBD, 0x72, 
+0xAC, 0xF0, 0xA4, 0xD0, 0xA4, 0xB0, 0x9C, 0x8F, 
+0x94, 0x4E, 0x83, 0xCD, 0xA4, 0xD0, 0xBD, 0x72, 
+0xBD, 0x71, 0xCE, 0x14, 0xAC, 0xEF, 0xBD, 0x92, 
+0xC6, 0x54, 0xC6, 0x73, 0xC6, 0x93, 0xC6, 0x73, 
+0xBE, 0x53, 0xDF, 0x36, 0xD6, 0xD5, 0xAD, 0x71, 
+0xC5, 0xD3, 0xCE, 0x35, 0xCE, 0x35, 0xBD, 0xB3, 
+0xCE, 0x14, 0xCE, 0x35, 0xD6, 0x76, 0xB5, 0x51, 
+0xC5, 0xB2, 0xAC, 0xEF, 0xA4, 0xAE, 0xB4, 0xEF, 
+0xEE, 0xD6, 0xDE, 0x74, 0xDE, 0x74, 0xDE, 0x74, 
+0xDE, 0x55, 0xBD, 0x51, 0xC5, 0xB2, 0xCE, 0x14, 
+0xD6, 0x33, 0xDE, 0x74, 0xDE, 0x74, 0xDE, 0x74, 
+0xD6, 0x54, 0xDE, 0x74, 0xC5, 0xF3, 0x8C, 0x0C, 
+0x41, 0xE6, 0x29, 0x64, 0x29, 0x44, 0x31, 0x85, 
+0x39, 0xC6, 0x42, 0x28, 0x4A, 0x69, 0x5A, 0xEB, 
+0x7B, 0xF0, 0x94, 0xB3, 0xAD, 0x55, 0x94, 0xB3, 
+0x5A, 0xCB, 0x8C, 0x31, 0xC6, 0x18, 0xC6, 0x39, 
+0x84, 0x10, 0xDE, 0xDB, 0xE7, 0x1C, 0xD6, 0x7A, 
+0xB5, 0xB6, 0xCE, 0x79, 0x8C, 0x0F, 0x5A, 0xA9, 
+0x62, 0xE9, 0x8B, 0xEC, 0xB4, 0xEF, 0xC5, 0x92, 
+0xC5, 0x72, 0xB5, 0x31, 0xA4, 0xAF, 0xBD, 0x71, 
+0xCD, 0xD3, 0xBD, 0x51, 0xB5, 0x10, 0xBD, 0x51, 
+0xBD, 0x51, 0xBD, 0x51, 0xBD, 0x30, 0xBD, 0x30, 
+0xB5, 0x10, 0xB5, 0x10, 0xB4, 0xF0, 0xB4, 0xF0, 
+0xAC, 0xD0, 0xB4, 0xF0, 0xB5, 0x10, 0xB5, 0x10, 
+0xAC, 0xAF, 0xA4, 0x8F, 0xAC, 0xF0, 0xA4, 0xD0, 
+0x8B, 0xED, 0x42, 0x06, 0x39, 0xC6, 0x42, 0x07, 
+0x52, 0x68, 0x5A, 0xEB, 0x7B, 0xCF, 0x94, 0x92, 
+0x6B, 0x6D, 0x7B, 0xCF, 0x8C, 0x71, 0x84, 0x0F, 
+0x9C, 0x91, 0x52, 0x89, 0x39, 0xE7, 0x39, 0xE6, 
+0x31, 0xA5, 0x3A, 0x07, 0x42, 0x07, 0x42, 0x28, 
+0x52, 0xAA, 0x52, 0x8A, 0x63, 0x0C, 0x73, 0xD0, 
+0x84, 0x32, 0x94, 0xB4, 0x9C, 0xD4, 0xBD, 0xF8, 
+0xAD, 0x76, 0xB5, 0xB7, 0x94, 0x92, 0xAD, 0x55, 
+0xC5, 0xF8, 0xC6, 0x18, 0xBD, 0xB7, 0xB5, 0x56, 
+0xB5, 0x97, 0xBD, 0xB7, 0xA4, 0xF4, 0xCE, 0x39, 
+0xEE, 0xFB, 0xDE, 0x79, 0xCD, 0xD5, 0xC5, 0x73, 
+0xB5, 0x31, 0xAC, 0xD1, 0x94, 0x4F, 0xBD, 0x93, 
+0xC5, 0x93, 0xCD, 0xD3, 0xD5, 0xF4, 0xD6, 0x14, 
+0xCD, 0xB3, 0xCD, 0xB3, 0xD5, 0xF4, 0xDE, 0x55, 
+0xC5, 0xB3, 0xBD, 0x51, 0xBD, 0x31, 0xC5, 0x51, 
+0xCD, 0xB3, 0xDE, 0x55, 0xDE, 0x35, 0xDE, 0x34, 
+0xDE, 0x55, 0xCD, 0x92, 0xCD, 0x92, 0xBD, 0x30, 
+0xB4, 0xF0, 0xAC, 0xD0, 0xD6, 0x56, 0xC6, 0x15, 
+0xC5, 0xF5, 0xC6, 0x36, 0xC6, 0x15, 0xBD, 0xD4, 
+0xCE, 0x36, 0xCE, 0x35, 0xC5, 0xD4, 0xCE, 0x35, 
+0xD6, 0x96, 0xDE, 0x96, 0xDE, 0x96, 0xD6, 0x76, 
+0xCE, 0x35, 0xCE, 0x14, 0xC6, 0x14, 0xCE, 0x56, 
+0xCE, 0x56, 0xCE, 0x15, 0xCE, 0x35, 0xCE, 0x56, 
+0xCE, 0x35, 0xA4, 0xB0, 0xAC, 0xD1, 0xE5, 0xF4, 
+0xED, 0xD3, 0xE5, 0xF4, 0xCD, 0x52, 0xC5, 0x32, 
+0xDD, 0x93, 0xDD, 0xB2, 0xDD, 0x51, 0xE6, 0x14, 
+0xF6, 0xF9, 0xE6, 0xD8, 0xE6, 0xF9, 0xE6, 0xB8, 
+0xE6, 0xB7, 0xE6, 0xB7, 0xE6, 0x76, 0xE6, 0x14, 
+0xE5, 0xB3, 0xE5, 0xB2, 0xE5, 0xB3, 0xDD, 0xB3, 
+0xE6, 0x55, 0xEF, 0x19, 0x94, 0x90, 0xBD, 0x94, 
+0xCE, 0x15, 0xBD, 0x93, 0xB5, 0x73, 0xC5, 0xD4, 
+0xD6, 0x35, 0xDE, 0x97, 0xE6, 0xD9, 0xBD, 0x75, 
+0x94, 0x51, 0x9C, 0x91, 0xAD, 0x34, 0xD5, 0xF7, 
+0xB5, 0x13, 0x7B, 0x4C, 0x52, 0x49, 0x5A, 0xAA, 
+0x73, 0x8C, 0x84, 0x6E, 0x6C, 0x2B, 0x42, 0xE6, 
+0x19, 0x62, 0x10, 0xE2, 0x19, 0x23, 0x21, 0x84, 
+0x19, 0x42, 0x4B, 0x48, 0x7C, 0xED, 0x9D, 0xF1, 
+0x8D, 0x90, 0x95, 0x8F, 0x85, 0x4D, 0x53, 0xC8, 
+0x22, 0x03, 0x4B, 0x07, 0x63, 0xEA, 0x19, 0x62, 
+0x19, 0x42, 0x3A, 0x65, 0x42, 0xC6, 0x63, 0xC9, 
+0x95, 0x70, 0x53, 0x68, 0x63, 0xEA, 0x84, 0xED, 
+0x95, 0x90, 0x7C, 0xEC, 0x7D, 0x0C, 0x95, 0xAF, 
+0x7B, 0x6C, 0x73, 0x4B, 0x73, 0x6B, 0x7B, 0x8C, 
+0x83, 0xAC, 0x83, 0xCD, 0x83, 0xCD, 0x8B, 0xED, 
+0x8B, 0xED, 0x94, 0x0D, 0x94, 0x2E, 0x9C, 0x6E, 
+0xA4, 0x6F, 0xA4, 0x8F, 0xA4, 0x2D, 0xA4, 0x2E, 
+0xA4, 0x6E, 0xA4, 0x6E, 0xA4, 0x6E, 0xA4, 0x6E, 
+0xA4, 0x6E, 0xA4, 0x8E, 0xAC, 0xAF, 0xA4, 0x8E, 
+0xAC, 0xCF, 0xAC, 0xAE, 0xBD, 0x30, 0xCD, 0x92, 
+0xCD, 0xB2, 0xBD, 0x30, 0xD5, 0xF3, 0xDE, 0x34, 
+0xDE, 0x54, 0xE6, 0x55, 0xEE, 0x76, 0xEE, 0x75, 
+0xB4, 0xEF, 0xA4, 0x4D, 0x9C, 0x2C, 0xBD, 0x31, 
+0xA4, 0x4E, 0xB5, 0x10, 0xCD, 0xB3, 0xC5, 0x30, 
+0xCD, 0x51, 0xB4, 0xCF, 0xAC, 0x8F, 0xA4, 0x6E, 
+0x94, 0x0D, 0xAC, 0xF0, 0xB5, 0x31, 0xA4, 0xCF, 
+0x94, 0x6E, 0x83, 0xED, 0x8C, 0x2E, 0x8C, 0x0D, 
+0x8B, 0xED, 0x73, 0x6B, 0xA4, 0xD0, 0x9C, 0x8E, 
+0xB5, 0x51, 0xD6, 0x75, 0xB5, 0x71, 0xBD, 0xB3, 
+0xCE, 0x75, 0xC6, 0x74, 0xC6, 0x74, 0xC6, 0x54, 
+0xC6, 0x54, 0xD6, 0xD6, 0xC6, 0x34, 0xBD, 0xD3, 
+0xBD, 0xB3, 0xC5, 0xF4, 0xC5, 0xD4, 0xC5, 0xF4, 
+0xC5, 0xF4, 0xC6, 0x14, 0xCE, 0x35, 0xB5, 0x51, 
+0xBD, 0xB2, 0xAC, 0xEF, 0xB4, 0xEF, 0xAC, 0xCE, 
+0xE6, 0x95, 0xDE, 0x54, 0xDE, 0x54, 0xDE, 0x54, 
+0xDE, 0x54, 0xCD, 0xB3, 0xCD, 0xD3, 0xD6, 0x34, 
+0xDE, 0x34, 0xDE, 0x54, 0xDE, 0x74, 0xE6, 0xB5, 
+0xDE, 0x94, 0xD6, 0x94, 0xCE, 0x33, 0xCD, 0xF3, 
+0xC5, 0xD3, 0x94, 0xCF, 0x52, 0xA8, 0x29, 0x64, 
+0x29, 0x65, 0x31, 0xA6, 0x31, 0xA6, 0x39, 0xE7, 
+0x52, 0xAA, 0x63, 0x4D, 0x73, 0x8E, 0x73, 0xAE, 
+0x6B, 0x4D, 0x8C, 0x52, 0x73, 0xAF, 0xAD, 0x76, 
+0x9C, 0xF4, 0xC6, 0x39, 0xEF, 0x3D, 0xCE, 0x59, 
+0xC6, 0x18, 0xD6, 0xBA, 0x94, 0x51, 0x94, 0x90, 
+0x7B, 0xAC, 0x8C, 0x0D, 0xB5, 0x0F, 0xA4, 0xAE, 
+0x94, 0x2D, 0x94, 0x2E, 0x94, 0x6E, 0xB5, 0x31, 
+0xBD, 0x92, 0xBD, 0x72, 0xBD, 0x72, 0xC5, 0x93, 
+0xC5, 0x93, 0xCD, 0xD3, 0xC5, 0xB3, 0xC5, 0xD3, 
+0xC5, 0xB3, 0xCD, 0xD3, 0xC5, 0xD3, 0xC5, 0xB3, 
+0xC5, 0x72, 0xB5, 0x11, 0x94, 0x4E, 0x7B, 0x6B, 
+0x8B, 0xED, 0x83, 0xAC, 0xA4, 0xB0, 0xBD, 0x52, 
+0xA4, 0xB0, 0x73, 0x6B, 0x7B, 0xAD, 0x6B, 0x4B, 
+0x41, 0xE6, 0x4A, 0x48, 0x42, 0x28, 0x5A, 0xEB, 
+0x62, 0xEB, 0x52, 0xAA, 0x63, 0x2C, 0x6B, 0x4D, 
+0x8C, 0x30, 0x94, 0x91, 0x4A, 0x48, 0x39, 0xC6, 
+0x31, 0xA6, 0x39, 0xE7, 0x4A, 0x48, 0x4A, 0x68, 
+0x42, 0x07, 0x5A, 0xCB, 0x5A, 0xCB, 0x6B, 0x6E, 
+0x7B, 0xF0, 0x84, 0x32, 0x94, 0x93, 0xA4, 0xF5, 
+0x9C, 0xD4, 0xB5, 0x96, 0xC5, 0xF8, 0xA4, 0xF4, 
+0xB5, 0x76, 0xC5, 0xF8, 0xBD, 0xD7, 0xE6, 0xFB, 
+0xD6, 0x7A, 0xE6, 0xFC, 0xB5, 0x97, 0xAD, 0x35, 
+0xC5, 0xD7, 0xD6, 0x79, 0xDE, 0xBA, 0xD6, 0x38, 
+0xA4, 0xD2, 0xC5, 0xD5, 0xB5, 0x32, 0xCD, 0xF5, 
+0xE6, 0xB7, 0xE6, 0x76, 0xDE, 0x55, 0xE6, 0x96, 
+0xDE, 0x55, 0xDE, 0x55, 0xE6, 0x76, 0xE6, 0x96, 
+0xDE, 0x55, 0xD5, 0xD3, 0xDE, 0x14, 0xDE, 0x14, 
+0xDE, 0x55, 0xEE, 0xB6, 0xDE, 0x75, 0xDE, 0x55, 
+0xEE, 0x96, 0xD5, 0xF3, 0xD5, 0xB2, 0xAC, 0x8E, 
+0xAC, 0x8E, 0xAC, 0xF0, 0xD6, 0x56, 0xCE, 0x35, 
+0xC6, 0x15, 0xCE, 0x36, 0xCE, 0x36, 0xCE, 0x36, 
+0xCE, 0x56, 0xD6, 0x76, 0xBD, 0xD4, 0xCE, 0x15, 
+0xD6, 0x55, 0xD6, 0x55, 0xD6, 0x56, 0xD6, 0x55, 
+0xCE, 0x14, 0xCE, 0x15, 0xCE, 0x15, 0xD6, 0x56, 
+0xD6, 0x76, 0xD6, 0x56, 0xCE, 0x56, 0xCE, 0x35, 
+0xCE, 0x35, 0xA4, 0xD1, 0xA4, 0xB0, 0xEE, 0x35, 
+0xED, 0xD3, 0xF6, 0x35, 0xEE, 0x35, 0xEE, 0x15, 
+0xEE, 0x14, 0xED, 0xF4, 0xED, 0xD3, 0xEE, 0x76, 
+0xEE, 0xD8, 0xE6, 0xD8, 0xDE, 0xB7, 0xE6, 0xB8, 
+0xE6, 0xB7, 0xE6, 0x97, 0xE6, 0x56, 0xE5, 0xD3, 
+0xDD, 0x51, 0xDD, 0x71, 0xE5, 0x92, 0xE5, 0x92, 
+0xE6, 0x35, 0xEE, 0xF9, 0x9C, 0xB1, 0xC5, 0xD5, 
+0xC5, 0xF5, 0xC5, 0xB4, 0xCE, 0x36, 0xE6, 0xD8, 
+0xC5, 0xD5, 0xB5, 0x74, 0xBD, 0x96, 0xB5, 0x55, 
+0x8B, 0xF0, 0xBD, 0x75, 0xCD, 0xF7, 0xDE, 0x58, 
+0x9C, 0x0F, 0x83, 0x2C, 0x5A, 0x49, 0x52, 0x48, 
+0x52, 0x88, 0x6C, 0x0B, 0x4B, 0x27, 0x5B, 0x4A, 
+0x32, 0x06, 0x10, 0xE2, 0x11, 0x02, 0x19, 0x02, 
+0x19, 0x43, 0x5B, 0xCA, 0x74, 0x8C, 0x6C, 0x8B, 
+0x6C, 0xAC, 0x8D, 0x6E, 0x8D, 0x8F, 0x53, 0x87, 
+0x53, 0x89, 0x8D, 0x2F, 0x53, 0x88, 0x32, 0x65, 
+0x3A, 0xA5, 0x5B, 0xC8, 0x64, 0x09, 0x7D, 0x0D, 
+0xB6, 0x93, 0x74, 0x8B, 0x64, 0x09, 0x74, 0x8C, 
+0x9D, 0xB0, 0x95, 0x4F, 0x64, 0x2A, 0xAE, 0x93, 
+0x73, 0x2B, 0x7B, 0x8C, 0x7B, 0x6C, 0x83, 0xAC, 
+0x8C, 0x2E, 0x94, 0x4F, 0x8C, 0x0E, 0x9C, 0x8F, 
+0x9C, 0x6F, 0x9C, 0x6F, 0x8C, 0x2D, 0x94, 0x2E, 
+0xA4, 0xD0, 0xB5, 0x11, 0xA4, 0x8F, 0xAC, 0xF0, 
+0xA4, 0xAF, 0xA4, 0x6E, 0xA4, 0x6E, 0xA4, 0x8E, 
+0x94, 0x0C, 0x8B, 0xCB, 0x8B, 0xAB, 0x83, 0x8A, 
+0x8B, 0xAB, 0x8B, 0xCB, 0x9C, 0x0C, 0x9C, 0x2C, 
+0x94, 0x0C, 0x94, 0x0C, 0x94, 0x0C, 0x9C, 0x2C, 
+0xA4, 0x6D, 0xA4, 0x8E, 0xAC, 0xAE, 0xB4, 0xCF, 
+0xAC, 0xCE, 0xAC, 0x8E, 0xA4, 0x6D, 0xB4, 0xCF, 
+0xAC, 0xD0, 0xB4, 0xF0, 0xB5, 0x10, 0xAC, 0xCF, 
+0xAC, 0xAE, 0x9C, 0x2D, 0x94, 0x0D, 0x83, 0xAB, 
+0x83, 0xAB, 0xA4, 0xD0, 0xA4, 0xCF, 0x94, 0x2D, 
+0x7B, 0x8B, 0x6B, 0x2A, 0x6B, 0x2B, 0x6B, 0x4A, 
+0x73, 0x4B, 0x73, 0x4A, 0xA4, 0xB0, 0xAC, 0xF0, 
+0xB5, 0x30, 0xD6, 0x55, 0xBD, 0x92, 0xC6, 0x35, 
+0xD6, 0x96, 0xCE, 0x75, 0xCE, 0x95, 0xC6, 0x75, 
+0xC6, 0x54, 0xCE, 0x75, 0xC6, 0x14, 0xB5, 0x72, 
+0xC5, 0xF4, 0xC6, 0x14, 0xC5, 0xD4, 0xCE, 0x14, 
+0xCE, 0x14, 0xCE, 0x14, 0xCE, 0x55, 0xB5, 0x72, 
+0x9C, 0x6E, 0x9C, 0x4D, 0xB4, 0xEF, 0xB5, 0x30, 
+0xE6, 0x95, 0xDE, 0x53, 0xE6, 0x74, 0xE6, 0xB5, 
+0xE6, 0x95, 0xCD, 0xF3, 0xCD, 0xF4, 0xD6, 0x34, 
+0xDE, 0x54, 0xDE, 0x54, 0xC5, 0xF1, 0xBD, 0xD1, 
+0xC6, 0x12, 0xD6, 0xB4, 0xD6, 0xB4, 0xC6, 0x33, 
+0xBD, 0xF2, 0xD6, 0xB5, 0xBD, 0xD2, 0x8C, 0x4D, 
+0x4A, 0x67, 0x31, 0x85, 0x31, 0xA5, 0x42, 0x28, 
+0x39, 0xE7, 0x42, 0x28, 0x52, 0x89, 0x52, 0xAA, 
+0x63, 0x2C, 0x6B, 0x4D, 0x6B, 0x4D, 0x8C, 0x52, 
+0xA5, 0x35, 0xB5, 0xB7, 0xD6, 0x9B, 0xB5, 0x96, 
+0xB5, 0xB6, 0x83, 0xF0, 0x8C, 0x51, 0xBD, 0xD7, 
+0x8C, 0x50, 0x94, 0x4F, 0xA4, 0x8F, 0x8C, 0x0D, 
+0x8C, 0x2E, 0x94, 0x90, 0xAD, 0x32, 0xB5, 0x72, 
+0xAD, 0x52, 0xBD, 0x93, 0xAD, 0x32, 0xB5, 0x73, 
+0xBD, 0xB3, 0xC5, 0xD4, 0xCE, 0x15, 0xCE, 0x15, 
+0xCE, 0x15, 0xCE, 0x15, 0xCE, 0x15, 0xC5, 0xD4, 
+0xCD, 0xF5, 0xC5, 0xD4, 0xBD, 0xB5, 0x9C, 0xF2, 
+0xA4, 0xF2, 0xAD, 0x53, 0x94, 0x4F, 0xB5, 0x32, 
+0xAD, 0x32, 0xB5, 0x73, 0xBD, 0x93, 0xB5, 0x73, 
+0x8C, 0x2E, 0x52, 0x68, 0x4A, 0x48, 0x8C, 0x51, 
+0x94, 0x91, 0x5A, 0xEB, 0x5A, 0xAA, 0x8C, 0x51, 
+0x73, 0x6D, 0x62, 0xEA, 0x52, 0x89, 0x4A, 0x28, 
+0x42, 0x07, 0x39, 0xE7, 0x3A, 0x07, 0x4A, 0x48, 
+0x42, 0x07, 0x4A, 0x49, 0x4A, 0x49, 0x52, 0xAB, 
+0x63, 0x0C, 0x7B, 0xF0, 0x9C, 0xF4, 0x7B, 0xD0, 
+0x9C, 0xD3, 0xB5, 0x96, 0xB5, 0xB7, 0xA4, 0xF4, 
+0xAD, 0x56, 0xB5, 0x76, 0xC6, 0x18, 0xA5, 0x15, 
+0x84, 0x11, 0xB5, 0x76, 0xAD, 0x76, 0x9C, 0xD4, 
+0x5A, 0xCB, 0x63, 0x0C, 0x94, 0x92, 0x83, 0xEF, 
+0x42, 0x08, 0x9C, 0xD3, 0x94, 0x50, 0xB5, 0x12, 
+0xC5, 0x93, 0xC5, 0x72, 0xC5, 0x72, 0xBD, 0x31, 
+0xA4, 0xAF, 0x9C, 0x8F, 0xA4, 0xB0, 0xAC, 0xB0, 
+0xAC, 0xD0, 0xA4, 0xB0, 0xAC, 0xD0, 0xC5, 0x72, 
+0xD5, 0xF3, 0xDE, 0x14, 0xDE, 0x55, 0xDE, 0x34, 
+0xDE, 0x14, 0xE6, 0x75, 0xC5, 0x71, 0xAC, 0xAE, 
+0xB5, 0x10, 0xA4, 0xD0, 0xD6, 0x36, 0xD6, 0x76, 
+0xCE, 0x56, 0xCE, 0x56, 0xCE, 0x56, 0xCE, 0x56, 
+0xCE, 0x56, 0xCE, 0x56, 0xC5, 0xF5, 0xD6, 0x56, 
+0xD6, 0x55, 0xD6, 0x55, 0xD6, 0x55, 0xD6, 0x56, 
+0xCE, 0x14, 0xC5, 0xF4, 0xD6, 0x56, 0xD6, 0x97, 
+0xD6, 0x97, 0xD6, 0x76, 0xD6, 0x97, 0xD6, 0x76, 
+0xCE, 0x15, 0xA4, 0xB0, 0xA4, 0x90, 0xE5, 0xF4, 
+0xED, 0xF4, 0xEE, 0x15, 0xED, 0xF4, 0xED, 0xF4, 
+0xE5, 0xF4, 0xEE, 0x14, 0xEE, 0x35, 0xEE, 0x97, 
+0xE6, 0xD8, 0xE6, 0xB8, 0xDE, 0x98, 0xE6, 0xB8, 
+0xE6, 0xB8, 0xE6, 0x97, 0xE6, 0x35, 0xE5, 0xB3, 
+0xE5, 0x71, 0xE5, 0x71, 0xE5, 0x92, 0xE5, 0xB2, 
+0xE6, 0x55, 0xEF, 0x19, 0xA4, 0xD1, 0xC5, 0xF5, 
+0xD6, 0x77, 0xE6, 0xD9, 0xD6, 0x78, 0xB5, 0x95, 
+0x94, 0x71, 0xBD, 0xB6, 0xBD, 0x96, 0xCD, 0xF7, 
+0x9C, 0x71, 0xB5, 0x13, 0xBD, 0x54, 0xAC, 0xB1, 
+0x82, 0xEB, 0x62, 0x48, 0x49, 0xC6, 0x4A, 0x48, 
+0x3A, 0x07, 0x6B, 0xEB, 0x52, 0xE8, 0x9C, 0xF2, 
+0x31, 0xE6, 0x10, 0xE2, 0x19, 0x02, 0x42, 0x25, 
+0x7C, 0x4A, 0x85, 0x0C, 0x74, 0xAC, 0x74, 0xED, 
+0x5C, 0x0A, 0x43, 0x47, 0x74, 0xAC, 0x6C, 0x8C, 
+0x74, 0xAD, 0x85, 0x0F, 0x3A, 0xE6, 0x2A, 0x43, 
+0x53, 0x88, 0x7D, 0x0D, 0x85, 0x2D, 0x95, 0x90, 
+0xB6, 0x73, 0x85, 0x2E, 0x7C, 0xCC, 0x7D, 0x0C, 
+0x95, 0x8F, 0xA5, 0xF2, 0x6C, 0x4B, 0x4B, 0x67, 
+0x8C, 0x50, 0x73, 0x6C, 0x7B, 0xAD, 0x83, 0xAD, 
+0x8C, 0x2E, 0x8C, 0x2E, 0x8C, 0x4E, 0x9C, 0xD0, 
+0xA4, 0xD0, 0x9C, 0xB0, 0x94, 0x6F, 0xA4, 0xD0, 
+0x94, 0x0D, 0xAC, 0xF0, 0xA4, 0xCF, 0xB5, 0x72, 
+0xBD, 0x92, 0xBD, 0x92, 0xC5, 0xB2, 0xB5, 0x31, 
+0xAC, 0xAF, 0xB4, 0xF0, 0xAC, 0xF0, 0xAC, 0xEF, 
+0xAC, 0xCF, 0xA4, 0xAF, 0xAC, 0xCF, 0xC5, 0xB2, 
+0xB5, 0x10, 0xA4, 0x8E, 0xA4, 0x8E, 0x9C, 0x6D, 
+0xAC, 0xEF, 0xA4, 0x6D, 0x9C, 0x4D, 0x9C, 0x6D, 
+0xA4, 0x8D, 0xA4, 0x6D, 0xA4, 0x6D, 0xA4, 0x8E, 
+0xAC, 0x8E, 0xAC, 0x8E, 0xAC, 0xAE, 0xAC, 0xAE, 
+0xAC, 0xAF, 0xAC, 0xAE, 0xAC, 0xAF, 0xAC, 0xAF, 
+0xAC, 0xCF, 0xA4, 0xAF, 0xA4, 0xAF, 0x9C, 0x6E, 
+0x94, 0x2D, 0x8B, 0xEC, 0x83, 0xCC, 0x83, 0xAB, 
+0x7B, 0x6B, 0x73, 0x4A, 0x94, 0x0D, 0x94, 0x0C, 
+0x8B, 0xEC, 0x9C, 0xAE, 0xA4, 0xCF, 0xBD, 0xB3, 
+0xC6, 0x14, 0xC6, 0x14, 0xC6, 0x35, 0xCE, 0x76, 
+0xC6, 0x35, 0xCE, 0x75, 0xC6, 0x34, 0xA4, 0xF0, 
+0xC5, 0xF4, 0xDE, 0xB7, 0xD6, 0x96, 0xD6, 0x76, 
+0xD6, 0x76, 0xD6, 0x76, 0xCE, 0x35, 0xCE, 0x55, 
+0xCE, 0x15, 0xC5, 0x92, 0xB4, 0xEF, 0xB5, 0x0F, 
+0xDE, 0x54, 0xEE, 0xB5, 0xE6, 0x95, 0xE6, 0x95, 
+0xDE, 0x75, 0xD6, 0x14, 0xC5, 0xB3, 0xCD, 0xD3, 
+0xDE, 0x55, 0xE6, 0xD6, 0xE6, 0xF6, 0xDE, 0xD5, 
+0xC6, 0x32, 0xAD, 0xAF, 0xB5, 0xD0, 0xCE, 0x94, 
+0xC6, 0x33, 0xC6, 0x33, 0xA5, 0x2F, 0xB5, 0x70, 
+0xA4, 0xEF, 0x6B, 0x6A, 0x42, 0x27, 0x31, 0xA6, 
+0x21, 0x24, 0x31, 0x85, 0x39, 0xE7, 0x42, 0x28, 
+0x52, 0x8A, 0x52, 0x8A, 0x4A, 0x69, 0x73, 0xAF, 
+0x9C, 0xF4, 0x7B, 0xD0, 0xBD, 0xB8, 0xA4, 0xF4, 
+0xB5, 0xB7, 0xAD, 0x56, 0xBD, 0xD8, 0xAD, 0x35, 
+0xE7, 0x1C, 0xD6, 0x79, 0xAC, 0xF2, 0x83, 0xEE, 
+0x73, 0x8D, 0x7B, 0xEE, 0x84, 0x0F, 0x8C, 0x50, 
+0x9C, 0xD1, 0xA4, 0xF1, 0x9C, 0xB0, 0x9C, 0xB1, 
+0xAD, 0x33, 0xB5, 0x94, 0xC5, 0xD5, 0xC5, 0xF5, 
+0xB5, 0x73, 0xBD, 0x94, 0xC5, 0xD5, 0xBD, 0xB4, 
+0xBD, 0xD4, 0xBD, 0xB4, 0xAD, 0x33, 0x94, 0xB1, 
+0x9C, 0xD1, 0x9C, 0xD1, 0x9C, 0x90, 0xB5, 0x52, 
+0xBD, 0x94, 0xBD, 0x73, 0xA4, 0xF1, 0x94, 0x8F, 
+0xBD, 0xD4, 0xCE, 0x16, 0x9C, 0xB1, 0x8C, 0x71, 
+0x94, 0x92, 0x7B, 0xEF, 0x63, 0x0B, 0x62, 0xEB, 
+0x5A, 0xAA, 0x31, 0xA5, 0x42, 0x28, 0x52, 0x89, 
+0x4A, 0x68, 0x39, 0xE7, 0x39, 0xC6, 0x42, 0x27, 
+0x39, 0xC6, 0x4A, 0x48, 0x52, 0xAA, 0x5A, 0xCB, 
+0x63, 0x2D, 0x84, 0x10, 0x7B, 0xF0, 0x73, 0x6E, 
+0xAD, 0x35, 0xC6, 0x39, 0xB5, 0x97, 0xC6, 0x18, 
+0xBD, 0xB7, 0x8C, 0x51, 0x6B, 0x4D, 0x5A, 0xAB, 
+0x9C, 0xB4, 0xB5, 0xB6, 0xBD, 0xD7, 0x9C, 0xB3, 
+0xAD, 0x55, 0x94, 0x92, 0x73, 0x6E, 0x6B, 0x4D, 
+0x73, 0x6E, 0xBD, 0xB6, 0xC5, 0xF6, 0xC5, 0xB5, 
+0xD5, 0xF4, 0xCD, 0xB3, 0xD5, 0xF4, 0xD6, 0x15, 
+0xCD, 0xD4, 0xBD, 0x73, 0xA4, 0xB0, 0x94, 0x4F, 
+0x9C, 0x6F, 0x9C, 0x90, 0xA4, 0xB0, 0xA4, 0xB0, 
+0xAC, 0xD0, 0xAC, 0xD0, 0xAC, 0xD0, 0xAC, 0xD0, 
+0xAC, 0xD0, 0xA4, 0xAF, 0xA4, 0xAF, 0xBD, 0x11, 
+0xBD, 0x52, 0xBD, 0x93, 0xBD, 0x93, 0xB5, 0x52, 
+0xB5, 0x32, 0xAD, 0x12, 0xA4, 0xF1, 0xA4, 0xF1, 
+0x9C, 0xD1, 0x9C, 0xB0, 0x9C, 0x90, 0xA4, 0xF1, 
+0xB5, 0x72, 0xB5, 0x72, 0xAD, 0x32, 0xB5, 0x73, 
+0xAD, 0x32, 0xAD, 0x32, 0xD6, 0x76, 0xC6, 0x15, 
+0xC5, 0xF4, 0xD6, 0x56, 0xC5, 0xD4, 0xC5, 0xF5, 
+0xB5, 0x73, 0xAC, 0xF2, 0xAC, 0xF1, 0xDD, 0xF4, 
+0xF6, 0x35, 0xEE, 0x14, 0xEE, 0x15, 0xEE, 0x35, 
+0xEE, 0x35, 0xEE, 0x56, 0xEE, 0x97, 0xEE, 0xF9, 
+0xEE, 0xF9, 0xEE, 0xF9, 0xEE, 0xF9, 0xEE, 0xF9, 
+0xEE, 0xF9, 0xEE, 0xD7, 0xEE, 0x97, 0xEE, 0x14, 
+0xE5, 0xB2, 0xED, 0xB3, 0xED, 0xB2, 0xED, 0xD3, 
+0xEE, 0x56, 0xEE, 0xF9, 0xC5, 0xF6, 0xE6, 0xB9, 
+0xB5, 0x74, 0x83, 0xEF, 0x9C, 0xB3, 0xC5, 0xD6, 
+0xB5, 0x55, 0xB5, 0x75, 0xB5, 0x35, 0xBD, 0x75, 
+0x9C, 0x71, 0x93, 0xEF, 0x83, 0x4C, 0x72, 0xA9, 
+0x62, 0x27, 0x49, 0xC6, 0x29, 0x24, 0x31, 0xA6, 
+0x4A, 0x68, 0x63, 0x6B, 0x9C, 0xF2, 0x94, 0xB1, 
+0x3A, 0x07, 0x42, 0x27, 0x7B, 0xCE, 0xA5, 0x11, 
+0xDE, 0xD4, 0xCE, 0x92, 0x74, 0x8C, 0x85, 0x0E, 
+0x53, 0xC9, 0x4B, 0x89, 0x5C, 0x0B, 0x64, 0x4B, 
+0x74, 0xCE, 0x74, 0x8D, 0x32, 0xA5, 0x32, 0x84, 
+0x53, 0xA8, 0x8D, 0x8F, 0x8D, 0x8F, 0x95, 0xB0, 
+0xAE, 0x33, 0x8D, 0x4E, 0x7D, 0x0D, 0x7D, 0x0C, 
+0x64, 0x6A, 0x6C, 0x6B, 0x9D, 0xD0, 0x7C, 0xEC, 
+0xC5, 0xF8, 0x7B, 0x8D, 0x7B, 0x8C, 0x7B, 0xAD, 
+0x94, 0x6F, 0x94, 0x6F, 0x8C, 0x4E, 0x8C, 0x4E, 
+0x94, 0x6E, 0x94, 0x6F, 0xA4, 0xF1, 0xAD, 0x32, 
+0x83, 0xCC, 0x9C, 0x8E, 0xA4, 0xF0, 0xAD, 0x31, 
+0xAD, 0x31, 0xA4, 0xF0, 0xA4, 0xCF, 0x9C, 0xAF, 
+0x8B, 0xEC, 0xA4, 0xAE, 0xAC, 0xCF, 0xAC, 0xEF, 
+0xAD, 0x10, 0xAC, 0xCF, 0xA4, 0xAE, 0xCE, 0x14, 
+0xD6, 0x35, 0xCD, 0xF4, 0xCE, 0x14, 0xC5, 0xD3, 
+0xD6, 0x14, 0xAC, 0xF0, 0x9C, 0x8E, 0x94, 0x2C, 
+0x8B, 0xEC, 0x83, 0xCB, 0x94, 0x2C, 0x8B, 0xEC, 
+0x94, 0x2D, 0x9C, 0x6D, 0xA4, 0xAF, 0xB5, 0x10, 
+0xBD, 0x72, 0xBD, 0x31, 0xB5, 0x10, 0xB5, 0x31, 
+0xA4, 0xAE, 0xA4, 0xAE, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xB4, 0xF0, 0xB4, 0xF0, 0xB4, 0xF0, 0xAC, 0xF0, 
+0xAC, 0xF0, 0xA4, 0xCF, 0xA4, 0x8E, 0xAC, 0xCF, 
+0xA4, 0x8E, 0x9C, 0x8D, 0x94, 0x2D, 0x94, 0x0C, 
+0x8C, 0x0C, 0x94, 0x0D, 0x8C, 0x2D, 0xB5, 0x72, 
+0xAD, 0x51, 0xBD, 0xD3, 0xCE, 0x53, 0xDE, 0xF6, 
+0xD6, 0x95, 0xAD, 0x71, 0x94, 0x6E, 0x94, 0x4E, 
+0x9C, 0x8E, 0x9C, 0x6E, 0x9C, 0x6E, 0xA4, 0xAF, 
+0xB5, 0x31, 0xB5, 0x10, 0xA4, 0xAE, 0xAC, 0xCE, 
+0xA4, 0x8D, 0x9C, 0x6D, 0x9C, 0x2C, 0x94, 0x2C, 
+0x94, 0x2C, 0x9C, 0x6D, 0x9C, 0x8E, 0xA4, 0xAE, 
+0xAC, 0xEF, 0xB5, 0x30, 0xB5, 0x30, 0xC5, 0xB2, 
+0xD6, 0x33, 0xCE, 0x53, 0xB5, 0x70, 0xBD, 0xD2, 
+0xCE, 0x75, 0xBD, 0xD2, 0xAD, 0x30, 0xA4, 0xCE, 
+0xA4, 0xCE, 0x83, 0xEC, 0x7B, 0xCC, 0x5A, 0xA8, 
+0x42, 0x06, 0x31, 0xA6, 0x31, 0xA5, 0x31, 0xA5, 
+0x42, 0x27, 0x31, 0xA6, 0x31, 0xA6, 0x52, 0xAA, 
+0x6B, 0x8D, 0x7B, 0xF0, 0xA4, 0xF4, 0xB5, 0xB7, 
+0xBD, 0xD7, 0xAD, 0x35, 0xBD, 0xF8, 0xD6, 0x9A, 
+0xE7, 0x1C, 0xD6, 0xBA, 0xB5, 0x96, 0xA4, 0xF3, 
+0x8C, 0x30, 0x7B, 0xEF, 0x73, 0x8D, 0x73, 0xAE, 
+0x8C, 0x50, 0x7B, 0xAE, 0x73, 0x6D, 0x6B, 0x6D, 
+0x7B, 0xCE, 0x94, 0x71, 0x9C, 0xD2, 0x94, 0xB1, 
+0x94, 0x91, 0x9C, 0xD2, 0x94, 0xB1, 0x9C, 0xD2, 
+0x94, 0x91, 0x9C, 0xD2, 0x94, 0x71, 0x84, 0x2F, 
+0x94, 0x91, 0x8C, 0x4F, 0xA4, 0xD1, 0xBD, 0x93, 
+0xC5, 0xD4, 0xB5, 0x73, 0xA5, 0x12, 0xBD, 0x94, 
+0xD6, 0x56, 0xC5, 0xD4, 0xC5, 0xF5, 0x94, 0x91, 
+0x84, 0x30, 0x83, 0xEF, 0x73, 0x4D, 0x4A, 0x28, 
+0x39, 0xC6, 0x29, 0x44, 0x29, 0x24, 0x4A, 0x48, 
+0x52, 0x89, 0x39, 0xE7, 0x31, 0xA6, 0x39, 0xC6, 
+0x42, 0x07, 0x52, 0x89, 0x52, 0xAA, 0x63, 0x2C, 
+0x84, 0x10, 0x6B, 0x6D, 0x5A, 0xEB, 0x7B, 0xCF, 
+0x8C, 0x51, 0x9C, 0xD4, 0xBD, 0xD8, 0xC6, 0x18, 
+0x84, 0x10, 0x41, 0xE8, 0x41, 0xE8, 0x94, 0x92, 
+0x8C, 0x51, 0x7B, 0xAF, 0xB5, 0x96, 0xD6, 0x9A, 
+0xE6, 0xFB, 0xB5, 0x96, 0x9C, 0xB3, 0x8C, 0x31, 
+0x94, 0x71, 0xCE, 0x37, 0xDE, 0xB8, 0xC5, 0xF6, 
+0xCE, 0x16, 0xBD, 0x73, 0x9C, 0x6F, 0x8C, 0x0E, 
+0xA4, 0xD1, 0x9C, 0x90, 0x94, 0x6F, 0x7B, 0x8C, 
+0x7B, 0xAD, 0x8C, 0x0E, 0x83, 0xCD, 0x83, 0xAD, 
+0x94, 0x2F, 0x83, 0xCD, 0x83, 0xAD, 0x94, 0x2E, 
+0xA4, 0xB0, 0xB5, 0x53, 0xBD, 0x93, 0xBD, 0x73, 
+0xB5, 0x12, 0xB5, 0x52, 0xBD, 0x93, 0xB5, 0x52, 
+0xB5, 0x52, 0xBD, 0x94, 0xC5, 0xD4, 0xC5, 0xD4, 
+0xC5, 0xB4, 0xBD, 0x94, 0xBD, 0x94, 0xBD, 0x73, 
+0xAD, 0x32, 0xB5, 0x53, 0xB5, 0x32, 0xAD, 0x12, 
+0xAD, 0x12, 0xAC, 0xF1, 0xA4, 0xD1, 0xA4, 0xD1, 
+0xAD, 0x11, 0xA4, 0xF1, 0xA4, 0xD1, 0xAD, 0x11, 
+0xAC, 0xF1, 0xA4, 0xB0, 0x94, 0x2E, 0xBD, 0x52, 
+0xD5, 0x93, 0xCD, 0x72, 0xCD, 0x93, 0xDD, 0xF5, 
+0xDE, 0x15, 0xEE, 0x97, 0xEE, 0xD8, 0xEF, 0x19, 
+0xEF, 0x1A, 0xE7, 0x19, 0xEF, 0x1A, 0xEF, 0x1A, 
+0xEE, 0xF9, 0xEE, 0xB8, 0xEE, 0xD8, 0xF6, 0xB7, 
+0xF6, 0x76, 0xF6, 0x55, 0xEE, 0x55, 0xEE, 0x56, 
+0xEE, 0x98, 0xD6, 0x37, 0x9C, 0xB2, 0x8C, 0x10, 
+0xBD, 0x96, 0xB5, 0x55, 0xC5, 0xD7, 0xBD, 0x95, 
+0xAD, 0x34, 0x8C, 0x30, 0x9C, 0xB2, 0x8C, 0x10, 
+0x7B, 0xAE, 0x6B, 0x0B, 0x52, 0x07, 0x39, 0x44, 
+0x62, 0x69, 0x41, 0xE7, 0x21, 0x03, 0x21, 0x03, 
+0x21, 0x44, 0x31, 0xA6, 0x63, 0x2C, 0x6B, 0x4D, 
+0x63, 0x0C, 0xBD, 0xD5, 0xAD, 0x32, 0xB5, 0x52, 
+0xEF, 0x17, 0xEF, 0x16, 0x84, 0xCE, 0x74, 0x8C, 
+0x4B, 0xA9, 0x6C, 0x8D, 0x74, 0xAE, 0x74, 0xAE, 
+0x74, 0xCE, 0x5B, 0xEA, 0x3A, 0xE5, 0x3B, 0x06, 
+0x53, 0xC8, 0x8D, 0x6E, 0x95, 0x90, 0x9D, 0xD1, 
+0xA6, 0x32, 0x8D, 0x6F, 0x7D, 0x0D, 0x85, 0x2D, 
+0x74, 0xCC, 0x32, 0x84, 0x53, 0x88, 0x95, 0x6E, 
+0xBD, 0xF8, 0x94, 0x72, 0x7B, 0x6C, 0x84, 0x0D, 
+0x9C, 0xD0, 0xA4, 0xF1, 0x9C, 0xD1, 0x9C, 0x90, 
+0x94, 0x8F, 0x94, 0x90, 0x8C, 0x6F, 0x7B, 0xAC, 
+0x73, 0x8B, 0x8C, 0x2D, 0xA5, 0x10, 0xAD, 0x11, 
+0xAD, 0x31, 0xA4, 0xF0, 0xA4, 0xD0, 0xA4, 0xF0, 
+0x9C, 0xD0, 0xAC, 0xF0, 0xA4, 0xAF, 0xA4, 0x8E, 
+0xA4, 0x8E, 0xA4, 0x8E, 0xA4, 0xAE, 0xBD, 0xB2, 
+0xBD, 0xB2, 0xC5, 0xD3, 0xCD, 0xF4, 0xD6, 0x34, 
+0xD6, 0x75, 0xCD, 0xF4, 0xCE, 0x35, 0xCE, 0x15, 
+0xCE, 0x15, 0xCD, 0xF4, 0xCD, 0xF4, 0xC5, 0xD4, 
+0xBD, 0xB3, 0xBD, 0xB3, 0xCD, 0xF4, 0xD6, 0x56, 
+0xD6, 0x35, 0xCD, 0xF3, 0xCE, 0x14, 0xDE, 0x55, 
+0xAC, 0xCF, 0xA4, 0xAF, 0xB5, 0x30, 0xAC, 0xCF, 
+0xA4, 0xCF, 0x9C, 0x6E, 0x94, 0x2D, 0x94, 0x0C, 
+0x94, 0x0C, 0x94, 0x2D, 0x94, 0x2D, 0x9C, 0x6D, 
+0xA4, 0x8E, 0xAC, 0xCF, 0xA4, 0xAE, 0xAC, 0xCF, 
+0xA4, 0xAF, 0xA4, 0x8E, 0xA4, 0xCF, 0xBD, 0x92, 
+0x9C, 0xAE, 0x9C, 0xAD, 0xA4, 0xEE, 0xB5, 0xB0, 
+0xD6, 0xF5, 0xE7, 0x77, 0xD6, 0xB5, 0xBD, 0x92, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xBD, 0x52, 0x94, 0x4D, 
+0x93, 0xEC, 0x94, 0x2C, 0xA4, 0x8D, 0xAC, 0xAE, 
+0x9C, 0x6D, 0x9C, 0x6E, 0xAC, 0xEF, 0xB5, 0x10, 
+0xA4, 0xAE, 0xA4, 0xAE, 0xA4, 0xAE, 0xA4, 0xAE, 
+0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xCF, 0x9C, 0x6D, 
+0xA4, 0x8E, 0xA4, 0x8E, 0x9C, 0x4D, 0x8C, 0x2C, 
+0xBD, 0xD3, 0xB5, 0xB2, 0x9C, 0xAE, 0x9C, 0x8D, 
+0xA5, 0x2F, 0xB5, 0xD1, 0xB5, 0xF1, 0xB5, 0xF1, 
+0xA5, 0x70, 0x7C, 0x0C, 0x42, 0x26, 0x29, 0x64, 
+0x31, 0x86, 0x29, 0x44, 0x31, 0xA6, 0x39, 0xE7, 
+0x4A, 0x69, 0x73, 0x8E, 0x94, 0xB3, 0x94, 0x72, 
+0x8C, 0x51, 0xAD, 0x35, 0xA5, 0x15, 0x84, 0x10, 
+0x9C, 0xB3, 0x8C, 0x31, 0x6B, 0x4D, 0x8C, 0x51, 
+0x94, 0x71, 0xAD, 0x55, 0x6B, 0x6D, 0x63, 0x2C, 
+0x63, 0x4C, 0x63, 0x2C, 0x5A, 0xCA, 0x52, 0xAA, 
+0x6B, 0x4D, 0x7B, 0xCE, 0x84, 0x30, 0x8C, 0x50, 
+0x73, 0xAE, 0x84, 0x30, 0x84, 0x30, 0x8C, 0x50, 
+0x7B, 0xEF, 0x73, 0xAE, 0x84, 0x0F, 0x84, 0x0F, 
+0x84, 0x0E, 0x7B, 0xAD, 0x9C, 0xB1, 0xB5, 0x52, 
+0xBD, 0xB4, 0xAD, 0x53, 0xA5, 0x32, 0xD6, 0x77, 
+0xCE, 0x15, 0xBD, 0x94, 0xB5, 0x74, 0xB5, 0x74, 
+0x84, 0x0F, 0x94, 0x71, 0x73, 0x8D, 0x39, 0xE7, 
+0x31, 0x65, 0x29, 0x44, 0x29, 0x44, 0x31, 0xA5, 
+0x52, 0x88, 0x39, 0xE6, 0x31, 0x85, 0x31, 0xA6, 
+0x3A, 0x07, 0x52, 0xCA, 0x63, 0x2C, 0x5A, 0xEB, 
+0x52, 0xAA, 0x4A, 0x69, 0x63, 0x0C, 0x6B, 0x6E, 
+0x84, 0x11, 0x9C, 0xD4, 0xBD, 0xF8, 0x9C, 0xD3, 
+0x9C, 0xB3, 0x6B, 0x4D, 0x63, 0x0C, 0xA4, 0xD3, 
+0x6B, 0x4D, 0x6B, 0x2D, 0x83, 0xF0, 0xAD, 0x35, 
+0xC5, 0xF8, 0x8C, 0x31, 0x73, 0x6E, 0x7B, 0xAE, 
+0x73, 0x6D, 0x9C, 0xB2, 0x6B, 0x0C, 0x4A, 0x4A, 
+0xC5, 0xD6, 0xFF, 0x7B, 0xCD, 0xF6, 0x83, 0xEF, 
+0x73, 0x6C, 0x9C, 0x70, 0xBD, 0x94, 0xCE, 0x16, 
+0xC5, 0xD5, 0xC5, 0xD5, 0xAD, 0x12, 0xAC, 0xF2, 
+0xAD, 0x12, 0x9C, 0xB0, 0x94, 0x4F, 0xA4, 0xD0, 
+0xAD, 0x31, 0xBD, 0x93, 0xC5, 0xB4, 0xBD, 0x73, 
+0x9C, 0x90, 0x94, 0x6F, 0x83, 0xCD, 0x94, 0x2E, 
+0xA4, 0xF1, 0xA4, 0xB0, 0x9C, 0x8F, 0xB5, 0x32, 
+0xC5, 0xD5, 0x9C, 0x90, 0xAD, 0x12, 0x94, 0x6F, 
+0xA4, 0xF1, 0xB5, 0x53, 0xC5, 0xD5, 0xBD, 0x73, 
+0xBD, 0x73, 0xBD, 0x73, 0xB5, 0x53, 0xAD, 0x32, 
+0xAD, 0x12, 0xAD, 0x11, 0xA4, 0xD1, 0xA4, 0xD1, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xA4, 0xB1, 0xA4, 0xD1, 
+0xAC, 0xF2, 0xAD, 0x12, 0xAD, 0x12, 0xAD, 0x12, 
+0xAC, 0xF2, 0xA4, 0xD1, 0xA4, 0xD2, 0xA4, 0xF2, 
+0xA4, 0xD2, 0x9C, 0xD2, 0x9C, 0xD2, 0x9C, 0xD2, 
+0xA4, 0xD2, 0xA4, 0xD2, 0xA4, 0xD1, 0xB5, 0x33, 
+0xCD, 0xB5, 0xC5, 0x74, 0xAC, 0xD2, 0xA4, 0xD2, 
+0xB5, 0x34, 0xBD, 0xB6, 0x94, 0x92, 0xAD, 0x34, 
+0xCE, 0x18, 0xBD, 0x75, 0xB5, 0x75, 0xA4, 0xF3, 
+0x94, 0x30, 0x6A, 0xEC, 0x73, 0x4D, 0x52, 0x69, 
+0x5A, 0xAA, 0x52, 0x48, 0x41, 0xA6, 0x39, 0x85, 
+0x7B, 0x6D, 0x31, 0x85, 0x21, 0x24, 0x21, 0x24, 
+0x21, 0x24, 0x31, 0x65, 0x73, 0x6C, 0xA5, 0x13, 
+0xA4, 0xF2, 0xBD, 0x94, 0xB5, 0x52, 0xB5, 0x32, 
+0xEF, 0x17, 0xEE, 0xF7, 0x84, 0xAD, 0x64, 0x2B, 
+0x64, 0x4C, 0x7C, 0xEF, 0x85, 0x10, 0x84, 0xEF, 
+0x74, 0xCE, 0x53, 0xC9, 0x43, 0x46, 0x43, 0x66, 
+0x4B, 0xA7, 0x85, 0x2D, 0x95, 0x8F, 0x9D, 0xD1, 
+0xA5, 0xF2, 0x95, 0xB0, 0x8D, 0x6F, 0x95, 0xB0, 
+0x85, 0x2E, 0x21, 0xE3, 0x21, 0xE3, 0x3A, 0xC5, 
+0x5A, 0xCB, 0xA4, 0xF3, 0x7B, 0x8C, 0x8C, 0x2E, 
+0x9C, 0xD0, 0xA4, 0xD1, 0xA4, 0xF1, 0xA5, 0x12, 
+0xA5, 0x11, 0xA4, 0xF1, 0xA4, 0xD1, 0xAD, 0x32, 
+0x94, 0x6F, 0xA5, 0x12, 0xB5, 0x93, 0xB5, 0x72, 
+0xB5, 0x73, 0xAD, 0x52, 0xAD, 0x52, 0xC6, 0x16, 
+0xE7, 0x1B, 0xF7, 0xBE, 0xFF, 0xFF, 0xFF, 0xDE, 
+0xEF, 0x3C, 0xC5, 0xF6, 0xAD, 0x11, 0xBD, 0xB2, 
+0xBD, 0x92, 0xBD, 0xB3, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xC5, 0xF3, 0xBD, 0xB3, 0xC5, 0xB3, 0xBD, 0x93, 
+0xCE, 0x14, 0xD6, 0x35, 0xC5, 0xF4, 0xBD, 0x92, 
+0xBD, 0xB3, 0xBD, 0xB3, 0xBD, 0xB3, 0xC5, 0xD4, 
+0xC5, 0xD3, 0xBD, 0x93, 0xC5, 0xD3, 0xCD, 0xF4, 
+0xA4, 0xAE, 0xB5, 0x10, 0xC5, 0xD3, 0xBD, 0x93, 
+0xBD, 0x72, 0xB5, 0x51, 0xAD, 0x31, 0xB5, 0x31, 
+0xB5, 0x31, 0xB5, 0x31, 0xBD, 0x92, 0xD6, 0x78, 
+0xEF, 0x5C, 0xFF, 0xDF, 0xFF, 0xFF, 0xF7, 0x9E, 
+0xDE, 0xDA, 0xBD, 0xD4, 0xB5, 0x71, 0xB5, 0x71, 
+0xBD, 0xB2, 0xB5, 0x71, 0xAD, 0x4F, 0x9C, 0xCD, 
+0xA5, 0x0F, 0xC6, 0x53, 0xCE, 0x94, 0xAD, 0x51, 
+0xB5, 0x52, 0xAC, 0xF0, 0x94, 0x6E, 0x7B, 0xAC, 
+0x7B, 0x8B, 0xA4, 0xAF, 0xAC, 0xAF, 0x7B, 0x8A, 
+0x52, 0x67, 0x52, 0x68, 0x62, 0xE9, 0x94, 0x4E, 
+0x73, 0x2A, 0x5A, 0xA8, 0x62, 0xE9, 0x6A, 0xE9, 
+0x6B, 0x0A, 0x7B, 0x8B, 0x94, 0x4D, 0x9C, 0x6D, 
+0xA4, 0x8E, 0xA4, 0xAE, 0x8C, 0x0C, 0x73, 0x69, 
+0x8C, 0x4D, 0xAD, 0x71, 0xAD, 0x30, 0xBD, 0x92, 
+0xB5, 0xF0, 0xAD, 0xEF, 0xA5, 0xAD, 0xA5, 0xCE, 
+0xAE, 0x0F, 0xBE, 0x73, 0xB5, 0xD2, 0x4A, 0x67, 
+0x31, 0x85, 0x31, 0x85, 0x31, 0xA6, 0x31, 0xA6, 
+0x39, 0xC6, 0x52, 0xAA, 0x6B, 0x6D, 0x6B, 0x6D, 
+0x84, 0x10, 0xA5, 0x14, 0xA5, 0x14, 0x8C, 0x51, 
+0x7B, 0xAE, 0x7B, 0xCF, 0x8C, 0x51, 0x8C, 0x71, 
+0x9C, 0xD3, 0xE7, 0x1C, 0x8C, 0x51, 0x84, 0x10, 
+0x63, 0x2C, 0x5A, 0xCB, 0x52, 0xAA, 0x52, 0xAA, 
+0x63, 0x2C, 0x6B, 0x6D, 0x7B, 0xCE, 0x84, 0x0F, 
+0x73, 0x8D, 0x7B, 0xEF, 0x7B, 0xEF, 0x73, 0xAE, 
+0x84, 0x30, 0x73, 0x8D, 0x9C, 0xD1, 0x5A, 0xA9, 
+0x39, 0xE7, 0x4A, 0x28, 0xA4, 0xD1, 0xAD, 0x32, 
+0xAD, 0x32, 0xA4, 0xF2, 0x9C, 0xF1, 0xAD, 0x53, 
+0xBD, 0xB4, 0xA5, 0x12, 0xAD, 0x53, 0xB5, 0xB4, 
+0xB5, 0x94, 0xBD, 0xD5, 0x9C, 0xB2, 0x4A, 0x69, 
+0x42, 0x07, 0x39, 0xA6, 0x31, 0x65, 0x31, 0x85, 
+0x4A, 0x48, 0x4A, 0x69, 0x4A, 0x69, 0x4A, 0x68, 
+0x4A, 0x69, 0x52, 0xAA, 0x4A, 0x89, 0x42, 0x28, 
+0x39, 0xE7, 0x4A, 0x49, 0x5A, 0xCB, 0x73, 0xAF, 
+0x84, 0x10, 0xA5, 0x14, 0x94, 0x92, 0x9C, 0xD3, 
+0xE6, 0xDB, 0xAD, 0x35, 0x8C, 0x10, 0xA4, 0xF4, 
+0x83, 0xCF, 0x5A, 0xAA, 0x52, 0x8A, 0x6B, 0x2C, 
+0x7B, 0x8E, 0x52, 0x69, 0x63, 0x0C, 0x7B, 0xCF, 
+0xB5, 0x75, 0xB5, 0x96, 0x52, 0x8B, 0x7B, 0xCF, 
+0xBD, 0xB6, 0xCE, 0x17, 0xEE, 0xFB, 0xEE, 0xFB, 
+0xC5, 0xB6, 0xCD, 0xF7, 0xDE, 0x98, 0xCE, 0x16, 
+0xDE, 0x98, 0xC5, 0xD5, 0x94, 0x50, 0x9C, 0x91, 
+0xBD, 0x94, 0xBD, 0x94, 0xA5, 0x11, 0xAC, 0xF1, 
+0xB5, 0x52, 0xBD, 0x94, 0xAD, 0x53, 0xAD, 0x12, 
+0xBD, 0xB4, 0xAD, 0x32, 0xAC, 0xF1, 0xB5, 0x53, 
+0xAD, 0x32, 0xBD, 0x94, 0xA4, 0xF1, 0xB5, 0x73, 
+0xC5, 0xD5, 0xA4, 0xF1, 0xAD, 0x12, 0x73, 0x4B, 
+0x9C, 0x8F, 0xAD, 0x11, 0xBD, 0x52, 0xBD, 0x93, 
+0xC5, 0xB3, 0xBD, 0x73, 0xC5, 0x93, 0xC5, 0xB4, 
+0xB5, 0x53, 0xB5, 0x11, 0xAC, 0xF1, 0xAC, 0xF1, 
+0xA4, 0xB0, 0xA4, 0xD0, 0x94, 0x2E, 0x8C, 0x2E, 
+0x94, 0x2E, 0x9C, 0x6F, 0xA4, 0xD1, 0xAC, 0xF2, 
+0xAC, 0xF2, 0xAD, 0x12, 0xA4, 0xD2, 0xA4, 0xB1, 
+0xA4, 0xB0, 0xAD, 0x32, 0xB5, 0x53, 0xAD, 0x12, 
+0xBD, 0x74, 0xB5, 0x34, 0xBD, 0x95, 0xC5, 0xB6, 
+0x9C, 0x71, 0xA4, 0xD2, 0xB5, 0x75, 0xC5, 0xB6, 
+0xCD, 0xD7, 0xBD, 0x75, 0xAD, 0x34, 0xA4, 0xF4, 
+0xB5, 0x34, 0xAC, 0xF3, 0x94, 0x51, 0x7B, 0x8E, 
+0x73, 0x6D, 0x5A, 0xAA, 0x4A, 0x48, 0x4A, 0x28, 
+0x41, 0xE7, 0x31, 0x44, 0x39, 0x65, 0x6A, 0xEB, 
+0x5A, 0xAA, 0x21, 0x03, 0x18, 0xE3, 0x31, 0xA6, 
+0x63, 0x2B, 0x8C, 0x2F, 0x94, 0x70, 0x94, 0x6F, 
+0xA4, 0xD1, 0xA4, 0xD1, 0xA4, 0xD1, 0xA4, 0xB1, 
+0xBD, 0x94, 0xBD, 0xB3, 0x5B, 0x69, 0x53, 0xA9, 
+0x64, 0x0C, 0x53, 0x8A, 0x6C, 0x4C, 0x85, 0x10, 
+0x85, 0x0F, 0x53, 0xC9, 0x4B, 0x87, 0x4B, 0x66, 
+0x53, 0xE9, 0x85, 0x2E, 0x8D, 0x6F, 0x8D, 0x8F, 
+0x9D, 0xF2, 0x9D, 0xD1, 0x8D, 0x8F, 0x85, 0x4E, 
+0x3A, 0x65, 0x11, 0x02, 0x19, 0x62, 0x3A, 0x85, 
+0x39, 0xE8, 0x9C, 0xF3, 0x73, 0x6B, 0x94, 0x6F, 
+0xA4, 0xF1, 0x9C, 0xD0, 0xA5, 0x12, 0xAD, 0x53, 
+0xAD, 0x53, 0xAD, 0x52, 0xAD, 0x53, 0xA5, 0x12, 
+0xB5, 0x93, 0xB5, 0x93, 0xB5, 0x93, 0xBD, 0xB3, 
+0xBD, 0xD4, 0xBD, 0xD4, 0xCE, 0x56, 0xE7, 0x1B, 
+0xF7, 0xBE, 0xE7, 0x3C, 0xB5, 0x96, 0xCE, 0x59, 
+0xFF, 0xDE, 0xEF, 0x3C, 0xCE, 0x36, 0xBD, 0xB3, 
+0xB5, 0x72, 0xB5, 0x72, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xBD, 0xD3, 0xBD, 0xD3, 0xC5, 0xD4, 0xBD, 0x73, 
+0xB5, 0x72, 0xB5, 0x72, 0xB5, 0x72, 0xB5, 0x52, 
+0xBD, 0x93, 0xBD, 0x93, 0xB5, 0x93, 0xBD, 0x93, 
+0xBD, 0xB3, 0xBD, 0x93, 0xBD, 0xB3, 0xBD, 0x72, 
+0xA4, 0x8E, 0xAD, 0x10, 0xBD, 0x92, 0xBD, 0x93, 
+0xBD, 0xD4, 0xBD, 0xB3, 0xB5, 0x92, 0xB5, 0x72, 
+0xBD, 0x92, 0xBD, 0x93, 0xD6, 0x78, 0xF7, 0x7D, 
+0xFF, 0xDE, 0xC6, 0x18, 0xAD, 0x55, 0xE7, 0x1C, 
+0xF7, 0xBE, 0xEF, 0x5B, 0xD6, 0xB7, 0xC6, 0x53, 
+0xD6, 0xB5, 0xBD, 0xD1, 0xB5, 0x70, 0xA5, 0x2E, 
+0xAD, 0x4F, 0xB5, 0x90, 0xB5, 0xD1, 0xC5, 0xF3, 
+0xCD, 0xD4, 0xC5, 0xB3, 0xB5, 0x52, 0x9C, 0xB0, 
+0x8C, 0x0D, 0x9C, 0xB0, 0x73, 0x4A, 0x6B, 0x0A, 
+0x52, 0x68, 0x52, 0x68, 0x4A, 0x47, 0x4A, 0x27, 
+0x41, 0xE7, 0x42, 0x07, 0x52, 0x68, 0x4A, 0x68, 
+0x52, 0x88, 0x7B, 0xCC, 0x94, 0xAE, 0xA5, 0x2F, 
+0xA5, 0x4F, 0xAD, 0x4F, 0xAD, 0x70, 0xAD, 0x51, 
+0x9C, 0xD0, 0xB5, 0xB2, 0x94, 0xAF, 0x5A, 0xE9, 
+0x52, 0xE9, 0x7C, 0x0C, 0xA5, 0x0E, 0x84, 0x8A, 
+0x94, 0xEA, 0x9D, 0x4D, 0xAD, 0xB1, 0x63, 0x4A, 
+0x42, 0x27, 0x31, 0x85, 0x29, 0x85, 0x29, 0x85, 
+0x31, 0xA6, 0x42, 0x07, 0x4A, 0x49, 0x63, 0x0B, 
+0x6B, 0x4D, 0x94, 0x92, 0x7B, 0xF0, 0x84, 0x30, 
+0x6B, 0x4D, 0x6B, 0x4D, 0x52, 0x8A, 0x62, 0xEC, 
+0xB5, 0x96, 0xE7, 0x1C, 0xD6, 0xBA, 0xCE, 0x59, 
+0x84, 0x31, 0x73, 0x6D, 0x83, 0xCD, 0x7B, 0xCD, 
+0x7B, 0xCD, 0x7B, 0xAD, 0x7B, 0x8C, 0x73, 0x8C, 
+0x6B, 0x4C, 0x6B, 0x4C, 0x73, 0x6C, 0x63, 0x2B, 
+0xB5, 0x94, 0x6B, 0x6B, 0x94, 0x4F, 0x8B, 0xED, 
+0x8B, 0xEE, 0x7B, 0xAD, 0xAD, 0x32, 0xA5, 0x11, 
+0xAD, 0x32, 0xC6, 0x16, 0xB5, 0x94, 0x9C, 0xD1, 
+0xAD, 0x53, 0xA5, 0x13, 0xAD, 0x54, 0xBD, 0x94, 
+0xC5, 0xD5, 0xC6, 0x16, 0xCE, 0x36, 0x9C, 0xB1, 
+0x9C, 0xB1, 0xBD, 0xB5, 0xAD, 0x33, 0x73, 0x8D, 
+0x31, 0xA5, 0x4A, 0x68, 0x5A, 0xCA, 0x52, 0x89, 
+0x39, 0xE7, 0x41, 0xE7, 0x4A, 0x28, 0x42, 0x28, 
+0x4A, 0x48, 0x52, 0x8A, 0x6B, 0x6D, 0x73, 0x8E, 
+0x6B, 0x4D, 0x94, 0x93, 0x9C, 0xB3, 0xA4, 0xD3, 
+0xDE, 0x9A, 0xCD, 0xF7, 0x9C, 0xB3, 0x8C, 0x10, 
+0x8C, 0x50, 0x7B, 0xAE, 0x8C, 0x0F, 0x94, 0x2F, 
+0x5A, 0xAA, 0x5A, 0xAA, 0x73, 0x6D, 0xB5, 0x95, 
+0xBD, 0xD7, 0xAD, 0x55, 0xAD, 0x35, 0xA5, 0x14, 
+0xC5, 0xF7, 0xBD, 0xB6, 0x6B, 0x4D, 0xDE, 0xBA, 
+0xE6, 0xDB, 0x9C, 0xB2, 0xB5, 0x54, 0xA4, 0xB2, 
+0xA4, 0xF2, 0x94, 0x30, 0x6B, 0x0B, 0xC5, 0xD5, 
+0xCD, 0xF5, 0xD6, 0x56, 0xCD, 0xF5, 0xBD, 0x93, 
+0xC5, 0xD5, 0xDE, 0x97, 0xDE, 0x98, 0xD6, 0x77, 
+0x9C, 0xB1, 0xB5, 0x74, 0xC5, 0xF6, 0xAD, 0x32, 
+0xA4, 0xF1, 0xBD, 0xB4, 0xC5, 0xD5, 0xC5, 0xD5, 
+0xBD, 0xB4, 0xA4, 0xF1, 0xA4, 0xB1, 0x8C, 0x0E, 
+0x94, 0x4E, 0x94, 0x2E, 0x9C, 0x6F, 0xA4, 0x8F, 
+0xAC, 0xF0, 0xA4, 0xD0, 0x9C, 0x6E, 0xA4, 0xD0, 
+0xB5, 0x31, 0xAC, 0xF1, 0xAD, 0x11, 0xB5, 0x52, 
+0xBD, 0x73, 0xCD, 0xD4, 0xC5, 0x93, 0xB5, 0x11, 
+0xA4, 0xB0, 0x94, 0x0E, 0x94, 0x2E, 0xA4, 0x90, 
+0xB5, 0x12, 0xAD, 0x12, 0xAD, 0x12, 0xC5, 0xB4, 
+0xC5, 0xB3, 0xDE, 0x76, 0xDE, 0x77, 0xDE, 0x57, 
+0xB5, 0x54, 0x94, 0x30, 0x9C, 0x92, 0xAD, 0x14, 
+0x94, 0x71, 0xBD, 0x75, 0xA4, 0xD2, 0xAD, 0x34, 
+0xAD, 0x13, 0xAD, 0x13, 0xA4, 0xD2, 0x8C, 0x10, 
+0x8C, 0x30, 0x83, 0xAE, 0x6B, 0x0C, 0x62, 0xAA, 
+0x62, 0xCA, 0x52, 0x69, 0x39, 0xA6, 0x29, 0x44, 
+0x29, 0x04, 0x39, 0xA6, 0x73, 0x6D, 0x5A, 0xAA, 
+0x29, 0x44, 0x29, 0x64, 0x5A, 0xCA, 0x9C, 0xB0, 
+0xAD, 0x53, 0xB5, 0x53, 0xBD, 0x74, 0xBD, 0x94, 
+0xBD, 0x94, 0xB5, 0x53, 0xB5, 0x33, 0xB5, 0x53, 
+0xB5, 0x53, 0x94, 0xAF, 0x4B, 0x08, 0x53, 0x89, 
+0x32, 0x85, 0x22, 0x24, 0x2A, 0x65, 0x53, 0xAA, 
+0x8D, 0x70, 0x53, 0xC9, 0x43, 0x26, 0x2A, 0x64, 
+0x53, 0xC9, 0x74, 0xED, 0x7C, 0xED, 0x8D, 0x6F, 
+0xA5, 0xF2, 0x9D, 0xD2, 0x85, 0x2E, 0x3A, 0x85, 
+0x19, 0x22, 0x10, 0xE2, 0x21, 0x63, 0x63, 0xE9, 
+0x63, 0x6E, 0x8C, 0x71, 0x73, 0x6C, 0x8C, 0x4E, 
+0x94, 0x6F, 0xA5, 0x11, 0xAD, 0x32, 0x9C, 0xD0, 
+0xB5, 0x93, 0xB5, 0x93, 0xBD, 0xB4, 0xB5, 0x73, 
+0xBD, 0xB4, 0xBD, 0xD4, 0xC5, 0xF4, 0xC5, 0xF4, 
+0xC5, 0xF4, 0xBD, 0xF4, 0xE7, 0x1B, 0xF7, 0xBE, 
+0xA5, 0x34, 0x08, 0x41, 0x00, 0x00, 0x00, 0x00, 
+0x4A, 0x49, 0xF7, 0x9E, 0xEF, 0x3C, 0xD6, 0x57, 
+0xB5, 0x93, 0xB5, 0x72, 0xBD, 0x93, 0xB5, 0x72, 
+0xC5, 0xD4, 0xBD, 0xD4, 0xC5, 0xF4, 0xBD, 0xB4, 
+0xB5, 0x93, 0xA4, 0xF0, 0xAD, 0x52, 0xB5, 0x72, 
+0xBD, 0xB4, 0xB5, 0x93, 0xB5, 0x93, 0xB5, 0x93, 
+0xB5, 0x93, 0xBD, 0x93, 0xB5, 0x72, 0xB5, 0x10, 
+0xA4, 0x8E, 0xAD, 0x10, 0xCE, 0x14, 0xBD, 0x93, 
+0xBD, 0xB3, 0xB5, 0x73, 0xB5, 0x72, 0xAD, 0x10, 
+0xAD, 0x30, 0xC6, 0x15, 0xEF, 0x5C, 0xF7, 0x9D, 
+0x39, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x08, 0x41, 
+0xA5, 0x14, 0xFF, 0xDE, 0xDF, 0x1A, 0xC6, 0x52, 
+0xC6, 0x93, 0xBE, 0x10, 0xA5, 0x2B, 0xA5, 0x6B, 
+0xAD, 0x8C, 0xAD, 0x8D, 0xC6, 0x31, 0xE6, 0xD6, 
+0xDE, 0x96, 0xD6, 0x55, 0xD6, 0x35, 0xC5, 0xB4, 
+0xA4, 0xF1, 0xAD, 0x12, 0x73, 0x4B, 0x7B, 0xAD, 
+0x7B, 0xAD, 0x63, 0x0A, 0x4A, 0x48, 0x42, 0x07, 
+0x42, 0x07, 0x4A, 0x48, 0x4A, 0x48, 0x4A, 0x48, 
+0x4A, 0x47, 0xA5, 0x70, 0xAE, 0x10, 0xAE, 0x30, 
+0xAE, 0x50, 0xAE, 0x10, 0x95, 0x2E, 0x9D, 0x30, 
+0x9C, 0xCF, 0x9C, 0xF1, 0x6B, 0x6C, 0x4A, 0x68, 
+0x5A, 0xEA, 0x7B, 0xAD, 0x6B, 0x4A, 0x6B, 0x4A, 
+0xA4, 0xEE, 0xBD, 0xB1, 0x8C, 0x4D, 0x52, 0x88, 
+0x6B, 0x4B, 0x52, 0x88, 0x42, 0x27, 0x29, 0x65, 
+0x31, 0x85, 0x39, 0xE7, 0x42, 0x28, 0x42, 0x07, 
+0x63, 0x0B, 0x84, 0x0F, 0x73, 0x8E, 0x4A, 0x69, 
+0x5A, 0xCB, 0x4A, 0x48, 0x39, 0xC7, 0x6B, 0x2D, 
+0xBD, 0xF8, 0xE7, 0x1C, 0xC6, 0x38, 0xCE, 0x59, 
+0xDE, 0xBB, 0x83, 0xEF, 0x83, 0xCE, 0x9C, 0xB1, 
+0x9C, 0x8F, 0x9C, 0x6F, 0x9C, 0x8E, 0xAD, 0x0F, 
+0x94, 0x6D, 0x94, 0x2D, 0x9C, 0x6E, 0x94, 0x2D, 
+0xD6, 0x56, 0x83, 0xEC, 0x9C, 0x4E, 0xA4, 0x8F, 
+0xAC, 0xF0, 0xAC, 0xD0, 0xA4, 0xF0, 0x94, 0x2E, 
+0x8C, 0x2E, 0x94, 0x90, 0x83, 0xEE, 0x8C, 0x4F, 
+0x9C, 0xB1, 0x8C, 0x91, 0x94, 0xB1, 0xA4, 0xF2, 
+0xAD, 0x53, 0xB5, 0x94, 0xC5, 0xF6, 0xBD, 0xD5, 
+0xC5, 0xF6, 0xBD, 0xD5, 0xC5, 0xF5, 0xC6, 0x15, 
+0x94, 0x70, 0x39, 0xE6, 0x42, 0x07, 0x39, 0xC6, 
+0x31, 0x85, 0x39, 0xA6, 0x42, 0x07, 0x4A, 0x28, 
+0x52, 0x89, 0x52, 0xAA, 0x6B, 0x4D, 0x6B, 0x4D, 
+0x42, 0x08, 0x83, 0xEF, 0xAD, 0x34, 0xB5, 0x34, 
+0xBD, 0x75, 0xB5, 0x55, 0x7B, 0xAE, 0x7B, 0x8D, 
+0x8C, 0x0F, 0x83, 0xCE, 0xA4, 0xB1, 0xBD, 0x53, 
+0x62, 0xA9, 0x52, 0x69, 0x62, 0xEB, 0x73, 0x4C, 
+0x5A, 0xCB, 0xB5, 0x76, 0xC6, 0x18, 0xA4, 0xF4, 
+0xCE, 0x39, 0xB5, 0x55, 0x63, 0x2D, 0xBD, 0xD8, 
+0xEF, 0x1C, 0xCD, 0xF7, 0xAD, 0x13, 0xA4, 0xD2, 
+0x83, 0xCE, 0x73, 0x2C, 0x73, 0x6D, 0xAD, 0x32, 
+0xAC, 0xF1, 0xCD, 0xF5, 0xDE, 0x56, 0xB5, 0x32, 
+0xC5, 0xB4, 0xDE, 0x56, 0xDE, 0x56, 0xDE, 0xB7, 
+0xC5, 0xF6, 0xC6, 0x17, 0xD6, 0x99, 0xCE, 0x58, 
+0xC5, 0xF6, 0xCE, 0x15, 0xCE, 0x15, 0xC5, 0xD4, 
+0xC5, 0xF5, 0xAD, 0x12, 0x9C, 0x90, 0xA4, 0xB0, 
+0x9C, 0xB0, 0x94, 0x4F, 0x94, 0x4E, 0x94, 0x2E, 
+0xA4, 0xB0, 0x9C, 0x8F, 0x8B, 0xED, 0x9C, 0x4E, 
+0xA4, 0xAF, 0xA4, 0x8F, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xAC, 0xF0, 0xB5, 0x11, 0xB5, 0x11, 0xB5, 0x11, 
+0xB5, 0x11, 0xAC, 0xF0, 0xAC, 0xD0, 0xB5, 0x11, 
+0xC5, 0x73, 0xAD, 0x12, 0xB5, 0x53, 0xBD, 0x94, 
+0x9C, 0x4F, 0xDE, 0x57, 0xD6, 0x16, 0xCD, 0xD5, 
+0xBD, 0x74, 0xC5, 0xB5, 0xD6, 0x38, 0xC5, 0xB6, 
+0xA4, 0xD3, 0x94, 0x50, 0x83, 0xEF, 0xA4, 0xD3, 
+0x9C, 0x71, 0x8B, 0xEF, 0x83, 0x8E, 0x73, 0x2C, 
+0x62, 0xEA, 0x62, 0xAA, 0x4A, 0x28, 0x52, 0x28, 
+0x4A, 0x08, 0x39, 0xA6, 0x29, 0x24, 0x21, 0x04, 
+0x5A, 0xAB, 0xC5, 0xF8, 0x94, 0x92, 0x31, 0x65, 
+0x6B, 0x0B, 0x8C, 0x0E, 0x8C, 0x0E, 0x94, 0x2E, 
+0xA4, 0xB1, 0xB5, 0x32, 0xBD, 0x94, 0xC5, 0xF5, 
+0xBD, 0x93, 0xB5, 0x73, 0xC5, 0xD4, 0xAD, 0x11, 
+0x9C, 0xD0, 0x73, 0xCC, 0x4B, 0x49, 0x5B, 0xCA, 
+0x19, 0xC3, 0x21, 0xE4, 0x3A, 0xA6, 0x32, 0xA5, 
+0x74, 0xAD, 0x43, 0x27, 0x2A, 0x23, 0x19, 0xC2, 
+0x2A, 0x24, 0x5B, 0xEA, 0x5C, 0x0A, 0x6C, 0xAC, 
+0x9D, 0xF2, 0xA6, 0x12, 0x5B, 0xEA, 0x32, 0x65, 
+0x31, 0xE5, 0x19, 0x23, 0x4B, 0x08, 0x8D, 0x4E, 
+0x7B, 0xF0, 0x7B, 0xF0, 0x7B, 0x8D, 0x83, 0xED, 
+0x83, 0xCC, 0x7B, 0xAC, 0x83, 0xCC, 0x83, 0xCC, 
+0x8C, 0x0D, 0x8C, 0x2E, 0x94, 0x6E, 0x9C, 0x8F, 
+0x9C, 0x8F, 0x9C, 0xB0, 0x9C, 0xB0, 0x9C, 0xAF, 
+0xA4, 0xD0, 0xA5, 0x11, 0xEF, 0x7D, 0xEF, 0x5D, 
+0x08, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x84, 0x10, 0xFF, 0xBE, 0xE6, 0xFA, 
+0xBD, 0xD4, 0xB5, 0x73, 0xB5, 0x72, 0xB5, 0x73, 
+0xBD, 0xB4, 0xBD, 0x93, 0xB5, 0x93, 0xAD, 0x52, 
+0xAD, 0x52, 0xB5, 0x93, 0xBD, 0xD4, 0xBD, 0xD4, 
+0xCE, 0x36, 0xC5, 0xF5, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xBD, 0x93, 0xBD, 0xB3, 0xB5, 0x72, 0xAD, 0x10, 
+0xA4, 0x8E, 0xBD, 0x72, 0xC6, 0x14, 0xBD, 0xB3, 
+0xB5, 0x73, 0xAD, 0x52, 0xBD, 0x93, 0xAD, 0x31, 
+0xAD, 0x31, 0xCE, 0x37, 0xF7, 0x9E, 0x7B, 0xCF, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x08, 0x41, 0xEF, 0x5D, 0xF7, 0x9D, 0xC6, 0x72, 
+0xC6, 0x72, 0x9D, 0x4B, 0x95, 0x49, 0x8D, 0x07, 
+0x84, 0xC6, 0x84, 0xE6, 0x8C, 0xE9, 0xAD, 0x8F, 
+0xCE, 0x34, 0xE6, 0xB7, 0xE6, 0x96, 0xD6, 0x55, 
+0xD6, 0x15, 0xCD, 0xF5, 0x83, 0xCD, 0xBD, 0xB4, 
+0xB5, 0x74, 0xA4, 0xD1, 0x73, 0x4C, 0x52, 0x89, 
+0x52, 0x89, 0x52, 0x89, 0x73, 0x8D, 0x52, 0xA9, 
+0x42, 0x07, 0x5A, 0xE8, 0x6B, 0xC9, 0x84, 0x8B, 
+0x95, 0x6D, 0xAE, 0x31, 0xBE, 0xB4, 0xB6, 0x74, 
+0xB6, 0x13, 0xA5, 0x52, 0x5A, 0xEA, 0x4A, 0x48, 
+0x4A, 0x68, 0x63, 0x2B, 0x63, 0x0B, 0x63, 0x0A, 
+0xBD, 0x93, 0xA5, 0x11, 0x62, 0xE9, 0x84, 0x0E, 
+0xA4, 0xF1, 0x94, 0x4E, 0x8B, 0xED, 0x4A, 0x27, 
+0x29, 0x65, 0x39, 0xC6, 0x52, 0x89, 0x52, 0x89, 
+0x4A, 0x69, 0x52, 0xAA, 0x63, 0x0B, 0x42, 0x28, 
+0x31, 0xA6, 0x42, 0x08, 0x5A, 0xCA, 0x73, 0xAF, 
+0x7B, 0xAF, 0x9C, 0xF4, 0xA5, 0x35, 0xDF, 0x1B, 
+0xCE, 0x9A, 0xAD, 0x76, 0xBD, 0xD8, 0xC6, 0x19, 
+0x84, 0x10, 0x7B, 0x8C, 0x94, 0x6D, 0xAD, 0x8F, 
+0xA5, 0x2F, 0x9C, 0x6D, 0x94, 0x2D, 0x8C, 0x0C, 
+0xCE, 0x55, 0x9C, 0x8E, 0xB5, 0x11, 0x9C, 0x8E, 
+0xA4, 0xCF, 0x9C, 0x8F, 0xA4, 0xF1, 0xB5, 0x52, 
+0xAD, 0x12, 0xA4, 0xB0, 0x9C, 0xB1, 0x9C, 0x90, 
+0x94, 0x70, 0x8C, 0x4F, 0x94, 0x4F, 0x94, 0x4F, 
+0x8C, 0x2F, 0x94, 0x4F, 0x94, 0x4F, 0x94, 0x4F, 
+0x9C, 0x90, 0x94, 0x90, 0x9C, 0x90, 0x9C, 0xB0, 
+0x6B, 0x4B, 0x5A, 0xAA, 0x73, 0x6C, 0x4A, 0x48, 
+0x39, 0xE6, 0x29, 0x65, 0x31, 0x85, 0x52, 0xAA, 
+0x5A, 0xEB, 0x52, 0xAA, 0x73, 0x6E, 0x8C, 0x51, 
+0x73, 0x6E, 0xAD, 0x14, 0xD6, 0x38, 0xCD, 0xF7, 
+0xB5, 0x34, 0x94, 0x71, 0x52, 0x6A, 0x6B, 0x4D, 
+0x6B, 0x4D, 0x39, 0xA6, 0x41, 0xC7, 0x6A, 0xEA, 
+0x62, 0xAA, 0x39, 0x86, 0x39, 0x86, 0x41, 0xE7, 
+0x6B, 0x2D, 0xCE, 0x39, 0xCE, 0x38, 0x9C, 0xB3, 
+0x8C, 0x51, 0x94, 0x92, 0xAD, 0x35, 0xCE, 0x59, 
+0xE6, 0xFB, 0xCE, 0x17, 0x8C, 0x30, 0xB5, 0x55, 
+0xAD, 0x14, 0x83, 0xEF, 0x73, 0x6D, 0x6B, 0x4C, 
+0x7B, 0xAD, 0xBD, 0x93, 0xD6, 0x35, 0xC5, 0x93, 
+0xDE, 0x56, 0xE6, 0x97, 0xDE, 0x76, 0xDE, 0x97, 
+0xA4, 0xD2, 0xA5, 0x14, 0xBD, 0xF7, 0xDE, 0xDB, 
+0xE6, 0xDA, 0xE6, 0xB8, 0xE6, 0xB8, 0xDE, 0x77, 
+0xD6, 0x56, 0xAD, 0x12, 0x9C, 0x6F, 0x9C, 0x90, 
+0xA4, 0xB0, 0x94, 0x4E, 0x9C, 0x8F, 0x9C, 0x6F, 
+0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x6F, 0xA4, 0xB0, 
+0xA4, 0xB0, 0xA4, 0xD0, 0xA4, 0xD0, 0xA4, 0xAF, 
+0x9C, 0x8F, 0xA4, 0x8F, 0xA4, 0xB0, 0xA4, 0xAF, 
+0xB5, 0x11, 0xB5, 0x11, 0xB5, 0x11, 0xBD, 0x52, 
+0xC5, 0x93, 0x9C, 0x70, 0x9C, 0x91, 0xAD, 0x13, 
+0xCD, 0xF7, 0xCD, 0xF6, 0xA4, 0x91, 0xBD, 0x54, 
+0xB5, 0x13, 0xAC, 0xF3, 0xB5, 0x54, 0xA4, 0xB2, 
+0xA4, 0xD2, 0x7B, 0x6E, 0x62, 0xAB, 0x62, 0xEB, 
+0x7B, 0x6D, 0x73, 0x4C, 0x6A, 0xEB, 0x5A, 0x89, 
+0x4A, 0x07, 0x39, 0xA6, 0x31, 0x85, 0x29, 0x24, 
+0x29, 0x24, 0x21, 0x04, 0x39, 0xC7, 0xA4, 0xF3, 
+0xC6, 0x18, 0x9C, 0xF3, 0x7B, 0x8D, 0xB5, 0x33, 
+0xCD, 0xD5, 0xCD, 0xD4, 0xC5, 0xB3, 0xCD, 0xD4, 
+0xD6, 0x36, 0xC5, 0xB4, 0xBD, 0x93, 0xB5, 0x72, 
+0xBD, 0x73, 0xBD, 0x73, 0xB5, 0x73, 0xBD, 0x73, 
+0xA5, 0x11, 0x53, 0x28, 0x5B, 0xAA, 0x53, 0x89, 
+0x21, 0xE4, 0x19, 0xA3, 0x21, 0xC3, 0x32, 0x44, 
+0x4B, 0x27, 0x32, 0x64, 0x32, 0x64, 0x21, 0xE3, 
+0x11, 0x41, 0x2A, 0x44, 0x22, 0x24, 0x2A, 0x65, 
+0x53, 0x69, 0x7C, 0xCD, 0x2A, 0x23, 0x22, 0x03, 
+0x3A, 0x66, 0x19, 0x43, 0x4A, 0xC8, 0xA5, 0xF1, 
+0x9D, 0x14, 0x73, 0xAE, 0x73, 0x6C, 0x7B, 0xAC, 
+0x83, 0xCC, 0x8C, 0x0D, 0x94, 0x2E, 0x94, 0x4E, 
+0x9C, 0x6F, 0x94, 0x6F, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xA4, 0xF0, 0x9C, 0xAF, 0x94, 0x6F, 0x9C, 0x6E, 
+0x9C, 0x8F, 0x94, 0x4E, 0xF7, 0x7D, 0xA5, 0x34, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x31, 0xA6, 0xFF, 0xDF, 0xE7, 0x1B, 
+0xB5, 0x52, 0x9C, 0x6E, 0x9C, 0x6E, 0x94, 0x4E, 
+0x94, 0x4E, 0x8C, 0x0C, 0x8C, 0x2D, 0x8B, 0xEC, 
+0x94, 0x4E, 0xA4, 0xF1, 0xAD, 0x11, 0xAD, 0x32, 
+0xBD, 0x93, 0xBD, 0xB3, 0xB5, 0x72, 0xBD, 0x92, 
+0xC5, 0xB3, 0xC5, 0xD3, 0xBD, 0xB2, 0xB5, 0x10, 
+0xA4, 0xAE, 0xBD, 0x72, 0xC5, 0xD2, 0xC5, 0xF3, 
+0xC5, 0xD3, 0xB5, 0x72, 0xB5, 0x51, 0xAD, 0x31, 
+0xBD, 0xB3, 0xCE, 0x78, 0xF7, 0xBE, 0x42, 0x08, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xBD, 0xD7, 0xFF, 0xDF, 0xBE, 0x72, 
+0xB6, 0x10, 0x95, 0x0A, 0xA5, 0xAB, 0x95, 0x29, 
+0x95, 0x4A, 0x9D, 0x4C, 0xAD, 0xCF, 0xC6, 0x11, 
+0xDE, 0x95, 0xE6, 0xB6, 0xE6, 0x96, 0xE6, 0x96, 
+0xDE, 0x56, 0xCD, 0xD4, 0x83, 0xAC, 0xD6, 0x77, 
+0xC5, 0xD4, 0xB5, 0x73, 0x94, 0x4F, 0x83, 0xEE, 
+0x73, 0x6C, 0x73, 0x8D, 0xA4, 0xF2, 0x7B, 0xCE, 
+0x73, 0x6C, 0x6B, 0x2B, 0x42, 0x46, 0x84, 0x6C, 
+0xAE, 0x31, 0xCF, 0x36, 0xC7, 0x16, 0xC7, 0x16, 
+0xD7, 0x57, 0xAD, 0xB2, 0x52, 0xA9, 0x4A, 0x69, 
+0x42, 0x28, 0x63, 0x0B, 0x5A, 0xAA, 0x84, 0x0F, 
+0xA4, 0xD2, 0x62, 0xEA, 0x6B, 0x6B, 0x94, 0x6F, 
+0xAD, 0x11, 0xA4, 0xD0, 0xA4, 0xF0, 0x83, 0xCC, 
+0x52, 0x68, 0x5A, 0xA9, 0x52, 0x89, 0x42, 0x07, 
+0x31, 0x85, 0x39, 0xC6, 0x39, 0xC6, 0x39, 0xC6, 
+0x29, 0x65, 0x21, 0x03, 0x39, 0xC7, 0x63, 0x2C, 
+0x63, 0x0C, 0x6B, 0x4D, 0xBD, 0xD7, 0xE7, 0x1C, 
+0xDE, 0xFC, 0xC6, 0x39, 0xEF, 0x7E, 0xEF, 0x7E, 
+0xE7, 0x3D, 0xC5, 0xF7, 0xA5, 0x11, 0xA5, 0x8F, 
+0xAD, 0xD0, 0xAD, 0x2F, 0x9C, 0xAE, 0xA4, 0xF0, 
+0xBD, 0xB3, 0x83, 0xCC, 0xA4, 0xAF, 0xAC, 0xF0, 
+0xAC, 0xD0, 0xA4, 0xB0, 0x9C, 0x8F, 0xA4, 0xD0, 
+0x9C, 0x4F, 0x94, 0x0E, 0x8B, 0xCD, 0x7B, 0x8C, 
+0x9C, 0x70, 0xA4, 0xD1, 0xA4, 0xF1, 0xBD, 0x94, 
+0xB5, 0x53, 0xAD, 0x12, 0xAD, 0x12, 0xB5, 0x33, 
+0xB5, 0x53, 0xB5, 0x53, 0xB5, 0x33, 0xB5, 0x53, 
+0x83, 0xEE, 0x62, 0xEB, 0x6B, 0x2B, 0x52, 0x48, 
+0x4A, 0x48, 0x39, 0xE7, 0x39, 0xC6, 0x42, 0x07, 
+0x42, 0x07, 0x52, 0x69, 0x5A, 0xAB, 0x7B, 0x8E, 
+0x8C, 0x31, 0xB5, 0x75, 0xCD, 0xF7, 0xCD, 0xF8, 
+0xBD, 0x55, 0x73, 0x6E, 0x84, 0x31, 0x6B, 0x4D, 
+0x39, 0xC7, 0x4A, 0x49, 0x5A, 0xAA, 0x39, 0xC6, 
+0x39, 0xC6, 0x29, 0x24, 0x18, 0xE3, 0x21, 0x03, 
+0x8C, 0x51, 0xD6, 0x9A, 0xAD, 0x55, 0xA4, 0xF4, 
+0xBD, 0xD7, 0xBD, 0x96, 0xBD, 0xB6, 0xE6, 0xDB, 
+0xC5, 0xD7, 0x7B, 0xAF, 0x94, 0x92, 0x94, 0x71, 
+0xBD, 0x75, 0xD6, 0x58, 0xD6, 0x38, 0xC5, 0xD7, 
+0xAC, 0xF2, 0xBD, 0x73, 0xD6, 0x36, 0xDE, 0x96, 
+0xE6, 0xB7, 0xCD, 0xF4, 0xE6, 0x97, 0xAC, 0xF1, 
+0x52, 0xAB, 0x73, 0x8F, 0x94, 0x93, 0xB5, 0xB7, 
+0xD6, 0xBA, 0xD6, 0x99, 0xC5, 0xF5, 0xE6, 0xD9, 
+0xD6, 0x56, 0xA4, 0xD1, 0x94, 0x4F, 0x9C, 0x6F, 
+0x9C, 0x8F, 0x94, 0x2E, 0x94, 0x4F, 0x94, 0x4E, 
+0xA4, 0xB0, 0x9C, 0xB0, 0xA4, 0xB0, 0xA4, 0xD0, 
+0xA4, 0xB0, 0xAC, 0xD1, 0xAD, 0x11, 0xAC, 0xD0, 
+0xA4, 0xB0, 0xA4, 0x6F, 0xA4, 0xB0, 0xAC, 0xD0, 
+0xB5, 0x11, 0xB5, 0x12, 0xBD, 0x33, 0xCD, 0xB4, 
+0xC5, 0xB5, 0xB5, 0x54, 0xD6, 0x59, 0xE6, 0xDB, 
+0xE6, 0xBA, 0xC5, 0xD6, 0x83, 0xAE, 0x83, 0xAE, 
+0x8C, 0x0F, 0x94, 0x51, 0x94, 0x30, 0x8C, 0x10, 
+0x8B, 0xEF, 0x41, 0xE7, 0x39, 0xA6, 0x41, 0xC7, 
+0x52, 0x69, 0x5A, 0x69, 0x4A, 0x07, 0x31, 0x65, 
+0x29, 0x24, 0x29, 0x04, 0x29, 0x24, 0x20, 0xE3, 
+0x21, 0x24, 0x4A, 0x29, 0x7B, 0xAF, 0x8C, 0x51, 
+0x63, 0x0B, 0xAD, 0x33, 0xCE, 0x15, 0xCD, 0xF4, 
+0xCD, 0xF4, 0xCD, 0xF4, 0xCD, 0xF4, 0xD6, 0x14, 
+0xCD, 0xF4, 0xD6, 0x35, 0xD6, 0x15, 0xC5, 0xD4, 
+0xC5, 0xB3, 0xCD, 0xF4, 0xD6, 0x35, 0xCE, 0x15, 
+0x8C, 0x6E, 0x5B, 0xAA, 0x5B, 0xCA, 0x3A, 0xE7, 
+0x3A, 0xA7, 0x32, 0x65, 0x2A, 0x25, 0x2A, 0x04, 
+0x21, 0xA3, 0x21, 0xC3, 0x2A, 0x44, 0x2A, 0x24, 
+0x3A, 0x86, 0x42, 0xE7, 0x2A, 0x44, 0x32, 0x45, 
+0x32, 0x65, 0x2A, 0x44, 0x2A, 0x44, 0x32, 0x65, 
+0x3A, 0xA6, 0x29, 0xC4, 0x11, 0x02, 0x74, 0x4C, 
+0x9C, 0xD3, 0x62, 0xEB, 0x6B, 0x4B, 0x73, 0x4B, 
+0x73, 0x4A, 0x83, 0xCC, 0x7B, 0x8B, 0x73, 0x4A, 
+0x83, 0xCC, 0x94, 0x2D, 0x83, 0xCC, 0x8C, 0x0D, 
+0x9C, 0xB0, 0xA4, 0xB0, 0x9C, 0xAF, 0xA4, 0xF0, 
+0xAD, 0x11, 0xB5, 0x51, 0xF7, 0xBE, 0x84, 0x10, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x08, 0x41, 0xFF, 0xDF, 0xE6, 0xFA, 
+0xB5, 0x52, 0xA4, 0x8E, 0xAC, 0xCF, 0xA4, 0xAE, 
+0xA4, 0xAF, 0xA4, 0xAF, 0xA4, 0xAE, 0xA4, 0x8E, 
+0x9C, 0x8E, 0x9C, 0x6E, 0x9C, 0x6E, 0x9C, 0x4D, 
+0x9C, 0x6E, 0xA4, 0x8E, 0xA4, 0xAE, 0xA4, 0xCE, 
+0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xEF, 0xAC, 0xEF, 
+0xA4, 0xAE, 0x94, 0x0C, 0x94, 0x2C, 0x94, 0x4D, 
+0x9C, 0x6D, 0x9C, 0x6E, 0x9C, 0xAE, 0x9C, 0xAE, 
+0xAD, 0x11, 0xC6, 0x37, 0xF7, 0x9E, 0x63, 0x0C, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xDE, 0xDB, 0xF7, 0x9E, 0xB6, 0x11, 
+0x95, 0x0D, 0x84, 0x8B, 0xAD, 0xEF, 0xA5, 0x8D, 
+0xE7, 0x14, 0xEF, 0x15, 0xEE, 0xF5, 0xE6, 0xB5, 
+0xEF, 0x3A, 0xEF, 0x1A, 0xF7, 0x3A, 0xF7, 0x3A, 
+0xEF, 0x19, 0xD6, 0x15, 0xBD, 0xB5, 0xDE, 0xFA, 
+0xD6, 0x78, 0xC6, 0x37, 0xC5, 0xF6, 0xB5, 0x95, 
+0xC5, 0xF7, 0xCE, 0x58, 0xCE, 0x58, 0xC6, 0x17, 
+0xBD, 0xD6, 0x9C, 0xB1, 0x52, 0xA8, 0x9D, 0x30, 
+0xB6, 0x73, 0xA6, 0x11, 0xA6, 0x11, 0xAE, 0x53, 
+0xAD, 0xB2, 0x7C, 0x0D, 0x5A, 0xCA, 0x4A, 0x89, 
+0x42, 0x28, 0x4A, 0x69, 0x7B, 0xCE, 0xA5, 0x34, 
+0x5A, 0xCA, 0x73, 0x8C, 0x84, 0x0D, 0x8C, 0x0D, 
+0x9C, 0xB0, 0x9C, 0x8F, 0x9C, 0x6F, 0x8C, 0x0E, 
+0x8C, 0x0E, 0x9C, 0xB0, 0x6B, 0x2B, 0x41, 0xE7, 
+0x31, 0x85, 0x31, 0xA6, 0x39, 0xC6, 0x31, 0x85, 
+0x18, 0xE2, 0x29, 0x24, 0x39, 0xC6, 0x5A, 0xCB, 
+0x6B, 0x6D, 0x6B, 0x6E, 0xA5, 0x14, 0xA5, 0x15, 
+0xBD, 0xF8, 0xAD, 0x55, 0xD6, 0xBB, 0xDE, 0xDB, 
+0xEF, 0x5D, 0xC6, 0x38, 0xD6, 0xB9, 0xD6, 0xF8, 
+0xD6, 0xF8, 0xDF, 0x18, 0xC6, 0x14, 0xC5, 0xF4, 
+0xAD, 0x51, 0x94, 0x4E, 0xA4, 0xF0, 0xA4, 0xD0, 
+0xAC, 0xD0, 0xA4, 0xB0, 0xB5, 0x11, 0xBD, 0x52, 
+0xC5, 0x72, 0xB5, 0x11, 0xA4, 0x6F, 0x7B, 0x8C, 
+0xAD, 0x12, 0xB5, 0x53, 0xC5, 0xF5, 0xBD, 0xB4, 
+0xAD, 0x32, 0x7B, 0x8C, 0x62, 0xEA, 0x63, 0x2A, 
+0x6B, 0x4B, 0x6B, 0x4B, 0x73, 0x6B, 0x7B, 0x8D, 
+0x94, 0x50, 0xA4, 0xD1, 0x7B, 0x8C, 0x62, 0xEA, 
+0x4A, 0x48, 0x4A, 0x48, 0x42, 0x28, 0x4A, 0x28, 
+0x52, 0x89, 0x5A, 0xAA, 0x5A, 0xAB, 0x5A, 0xAA, 
+0x62, 0xEC, 0x7B, 0xCF, 0x94, 0x30, 0x94, 0x72, 
+0x83, 0xCF, 0x52, 0x49, 0x4A, 0x69, 0x31, 0x65, 
+0x31, 0xA6, 0x5A, 0xEB, 0x5A, 0xCA, 0x42, 0x28, 
+0x39, 0xA6, 0x21, 0x24, 0x29, 0x65, 0x31, 0xA6, 
+0x73, 0xAE, 0xCE, 0x38, 0xC6, 0x38, 0xDE, 0xDB, 
+0xCE, 0x59, 0xBD, 0xB6, 0x84, 0x10, 0xB5, 0x96, 
+0xD6, 0x39, 0xC5, 0xB7, 0x83, 0xCF, 0x52, 0x6A, 
+0x52, 0x8A, 0x73, 0x6E, 0xAD, 0x14, 0xD6, 0x59, 
+0xB5, 0x54, 0x83, 0xEF, 0x8B, 0xEE, 0x94, 0x4F, 
+0x9C, 0x6F, 0x94, 0x0E, 0x9C, 0x6F, 0x5A, 0x68, 
+0x39, 0xC7, 0x52, 0x8B, 0x6B, 0x6E, 0x8C, 0x93, 
+0xAD, 0x55, 0x83, 0xF0, 0xA5, 0x34, 0xE6, 0xFA, 
+0xCE, 0x16, 0x9C, 0xB1, 0x8C, 0x0E, 0x94, 0x2E, 
+0x9C, 0x6F, 0x83, 0xCD, 0x83, 0xCD, 0x83, 0xED, 
+0xA4, 0xB0, 0x9C, 0xB0, 0xAC, 0xF1, 0xAC, 0xF1, 
+0xAC, 0xF1, 0xB5, 0x11, 0xA4, 0xD0, 0xA4, 0xD1, 
+0xAC, 0xF1, 0xAC, 0xF1, 0xAC, 0xF1, 0x9C, 0x6F, 
+0x9C, 0x91, 0xCD, 0xD6, 0xD6, 0x17, 0xDE, 0x99, 
+0xDE, 0x78, 0xBD, 0x95, 0xCE, 0x18, 0xD6, 0x38, 
+0xBD, 0x96, 0x9C, 0x71, 0x73, 0x6D, 0x62, 0xEB, 
+0x83, 0xAE, 0x8B, 0xEF, 0x73, 0x6D, 0x73, 0x2C, 
+0x73, 0x4C, 0x52, 0x48, 0x5A, 0xAA, 0x52, 0x69, 
+0x31, 0x65, 0x41, 0xE7, 0x62, 0xEB, 0x41, 0xE7, 
+0x52, 0x69, 0x31, 0x45, 0x5A, 0xCB, 0x7B, 0xCF, 
+0xAD, 0x55, 0xC5, 0xF7, 0x9C, 0xF3, 0x84, 0x0F, 
+0xA4, 0xD1, 0xD6, 0x76, 0xD6, 0x15, 0xD6, 0x35, 
+0xCD, 0xF4, 0xCD, 0xF4, 0xC5, 0x93, 0xCD, 0xF4, 
+0xCD, 0xF4, 0xD6, 0x55, 0xDE, 0x96, 0xD6, 0x14, 
+0xCD, 0xF4, 0xCD, 0xF4, 0xD6, 0x14, 0xBD, 0xD3, 
+0x63, 0x8A, 0x6C, 0x2B, 0x64, 0x0A, 0x53, 0x89, 
+0x63, 0xEB, 0x53, 0x49, 0x2A, 0x24, 0x19, 0x82, 
+0x21, 0x83, 0x2A, 0x05, 0x21, 0xE3, 0x22, 0x03, 
+0x5B, 0xC9, 0x53, 0xA8, 0x43, 0x07, 0x4B, 0x48, 
+0x53, 0x68, 0x43, 0x27, 0x43, 0x07, 0x4B, 0x48, 
+0x53, 0x88, 0x3A, 0x86, 0x10, 0xE1, 0x21, 0xA3, 
+0x52, 0x89, 0x62, 0xEA, 0x73, 0x6B, 0x83, 0xCC, 
+0x83, 0xAB, 0x83, 0xCC, 0x94, 0x4D, 0x9C, 0x6E, 
+0xA4, 0xAF, 0x9C, 0x8E, 0x83, 0xEC, 0x83, 0xCC, 
+0x83, 0xED, 0xA4, 0xD0, 0xAC, 0xF1, 0xB5, 0x51, 
+0xBD, 0x72, 0xC5, 0xB3, 0xF7, 0xBE, 0x9C, 0xD3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0xC3, 0xFF, 0xDF, 0xE6, 0xFA, 
+0xBD, 0x72, 0x8B, 0xEB, 0xA4, 0xAE, 0xA4, 0xAF, 
+0xA4, 0x8E, 0x94, 0x2C, 0xA4, 0x8E, 0xBD, 0x31, 
+0xB5, 0x10, 0xA4, 0xAE, 0x9C, 0x6D, 0xA4, 0xAF, 
+0xA4, 0xAE, 0xA4, 0xAE, 0xB5, 0x0F, 0xB5, 0x0F, 
+0xB5, 0x0F, 0xBD, 0x51, 0xB5, 0x10, 0xAC, 0xCF, 
+0xAC, 0xEF, 0xB5, 0x30, 0xAC, 0xEF, 0xAC, 0xEF, 
+0xAC, 0xEF, 0xA4, 0xAE, 0xA4, 0x8E, 0x9C, 0x4D, 
+0xA4, 0x8E, 0xBD, 0xB4, 0xEF, 0x5C, 0xDE, 0xBA, 
+0x08, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x63, 0x0C, 0xFF, 0xDE, 0xDE, 0xDA, 0xA5, 0x90, 
+0x6B, 0xE9, 0x95, 0x2E, 0xBE, 0x51, 0xBE, 0x6F, 
+0xBE, 0x4E, 0xC6, 0x4E, 0xCE, 0x50, 0xC5, 0xD1, 
+0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xEF, 0x3B, 0xCE, 0x37, 0xE7, 0x1C, 0xF7, 0x9E, 
+0xF7, 0x9E, 0xF7, 0x9D, 0xE7, 0x3C, 0xCE, 0x79, 
+0xE7, 0x3C, 0xF7, 0x9E, 0xF7, 0x9E, 0xEF, 0x7D, 
+0xDE, 0xDB, 0xA4, 0xF2, 0x6B, 0x6B, 0x94, 0xCF, 
+0xB6, 0x53, 0xA6, 0x11, 0xAE, 0x11, 0xA5, 0xB1, 
+0x94, 0x8E, 0x62, 0xEA, 0x5A, 0xCA, 0x52, 0x89, 
+0x39, 0xC7, 0x7B, 0xEF, 0xA5, 0x34, 0x5A, 0xEA, 
+0x73, 0x6B, 0x9C, 0xB0, 0x83, 0xCC, 0x83, 0xED, 
+0x9C, 0x8F, 0x9C, 0x6F, 0x9C, 0x8F, 0x9C, 0xAF, 
+0x94, 0x6F, 0xA4, 0xF1, 0x6B, 0x0A, 0x62, 0xEA, 
+0x52, 0xA9, 0x4A, 0x48, 0x39, 0xC6, 0x31, 0xC6, 
+0x31, 0xA6, 0x31, 0x86, 0x39, 0xE7, 0x4A, 0x69, 
+0x63, 0x2D, 0x6B, 0x4D, 0x94, 0x72, 0x6B, 0x6E, 
+0xAD, 0x76, 0xDE, 0xDC, 0xA5, 0x35, 0xAD, 0x35, 
+0xEF, 0x5D, 0xE7, 0x3C, 0xF7, 0x9D, 0xF7, 0xDE, 
+0xF7, 0xBE, 0xF7, 0xBD, 0xD6, 0xB7, 0xD6, 0x95, 
+0xAD, 0x10, 0xAC, 0xF0, 0xAD, 0x10, 0xB5, 0x31, 
+0xB5, 0x31, 0xBD, 0x31, 0xC5, 0x92, 0xC5, 0x72, 
+0xC5, 0x72, 0xCD, 0x72, 0xAC, 0xCF, 0x8C, 0x0E, 
+0xB5, 0x53, 0xBD, 0xB4, 0xCE, 0x36, 0xBD, 0x93, 
+0xCE, 0x15, 0xBD, 0xB4, 0xB5, 0x53, 0xA5, 0x12, 
+0xA4, 0xF1, 0x9C, 0x90, 0xA4, 0xD1, 0x94, 0x50, 
+0x7B, 0x6D, 0x94, 0x2F, 0xBD, 0x93, 0xBD, 0xB4, 
+0x83, 0xEE, 0x63, 0x0B, 0x62, 0xEB, 0x63, 0x0B, 
+0x73, 0x6D, 0x83, 0xF0, 0x9C, 0xB2, 0x7B, 0xAE, 
+0x52, 0x6A, 0x4A, 0x29, 0x5A, 0xCB, 0x6B, 0x4D, 
+0x52, 0x8A, 0x39, 0xE7, 0x29, 0x45, 0x29, 0x24, 
+0x31, 0xA6, 0x42, 0x28, 0x31, 0xC6, 0x39, 0xC6, 
+0x29, 0x65, 0x21, 0x24, 0x31, 0x85, 0x39, 0xC6, 
+0x6B, 0x6D, 0xCE, 0x39, 0xEF, 0x7D, 0xF7, 0x9E, 
+0xF7, 0xBE, 0xEF, 0x5D, 0xB5, 0x96, 0xC5, 0xB7, 
+0xD6, 0x39, 0xCE, 0x18, 0xCE, 0x38, 0x94, 0x92, 
+0x63, 0x0D, 0xA5, 0x14, 0xBD, 0xD7, 0xD6, 0x58, 
+0xB5, 0x55, 0xC5, 0xB6, 0xC5, 0xD6, 0xB5, 0x33, 
+0xB5, 0x33, 0xB5, 0x33, 0xB5, 0x33, 0x94, 0x50, 
+0x42, 0x08, 0x42, 0x08, 0x4A, 0x8A, 0x63, 0x4D, 
+0x7B, 0xF0, 0x7C, 0x11, 0xA5, 0x55, 0xC6, 0x18, 
+0xDE, 0xDB, 0xC6, 0x17, 0xB5, 0x75, 0xAD, 0x13, 
+0x9C, 0xB1, 0x8B, 0xEE, 0x83, 0xCD, 0x83, 0xCD, 
+0x8B, 0xEE, 0x8C, 0x0E, 0xA4, 0xD0, 0xAC, 0xF1, 
+0x9C, 0x6F, 0xAC, 0xF1, 0x8C, 0x0E, 0x8C, 0x0E, 
+0x9C, 0x90, 0x9C, 0x91, 0xCD, 0xF6, 0x7B, 0xAE, 
+0xA4, 0xD3, 0xBD, 0x96, 0xC5, 0xB6, 0xDE, 0x58, 
+0xC5, 0xB6, 0xA4, 0xF3, 0xBD, 0x96, 0xBD, 0x96, 
+0xBD, 0x75, 0x8C, 0x10, 0x7B, 0x6D, 0x5A, 0x89, 
+0x6B, 0x2C, 0x6B, 0x0C, 0x6B, 0x0C, 0x62, 0xCB, 
+0x5A, 0x8A, 0x52, 0x49, 0x4A, 0x28, 0x31, 0x65, 
+0x52, 0x69, 0x8C, 0x10, 0xA4, 0xF3, 0xB5, 0x96, 
+0xBD, 0xD7, 0x83, 0xEF, 0xBD, 0xB7, 0x9C, 0xF3, 
+0x8C, 0x71, 0x73, 0x6E, 0x52, 0x6A, 0x83, 0xCE, 
+0xBD, 0xB4, 0xD6, 0x15, 0xBD, 0x72, 0xC5, 0xB3, 
+0xC5, 0x92, 0xBD, 0x72, 0xBD, 0x93, 0xCD, 0xF4, 
+0xD6, 0x35, 0xE6, 0x96, 0xEE, 0xD7, 0xE6, 0x96, 
+0xD6, 0x55, 0xDE, 0x55, 0xDE, 0x76, 0xAD, 0x51, 
+0x74, 0x6D, 0x64, 0x0B, 0x64, 0x0A, 0x3A, 0xE7, 
+0x3A, 0xC6, 0x4B, 0x28, 0x3A, 0x86, 0x2A, 0x05, 
+0x42, 0xE8, 0x32, 0x25, 0x3A, 0x87, 0x2A, 0x24, 
+0x53, 0xA8, 0x64, 0x4A, 0x4B, 0x88, 0x53, 0xA9, 
+0x64, 0x2A, 0x5B, 0xE9, 0x53, 0xC9, 0x5C, 0x0A, 
+0x53, 0x88, 0x22, 0x04, 0x11, 0x22, 0x10, 0xE2, 
+0x4A, 0x48, 0x62, 0xEA, 0x8C, 0x0D, 0x8C, 0x2D, 
+0x9C, 0x8E, 0xAD, 0x31, 0xB5, 0x71, 0xB5, 0x51, 
+0xB5, 0x30, 0xB5, 0x71, 0xB5, 0x51, 0xB5, 0x51, 
+0xBD, 0x93, 0xA4, 0xD0, 0xA4, 0xB0, 0xBD, 0x72, 
+0xAD, 0x10, 0xB5, 0x31, 0xF7, 0x9D, 0x9C, 0xD3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0xE3, 0xFF, 0xDF, 0xEF, 0x3B, 
+0xD6, 0x55, 0xAD, 0x30, 0xD6, 0x76, 0xD6, 0x56, 
+0xCE, 0x15, 0xC5, 0xD4, 0xC5, 0xB4, 0xD6, 0x15, 
+0xC5, 0x92, 0x9C, 0x6D, 0xAC, 0xF0, 0xBD, 0x93, 
+0xC5, 0xD4, 0xBD, 0x73, 0xC5, 0xD4, 0xD6, 0x34, 
+0xA4, 0xAE, 0xBD, 0x51, 0xB5, 0x31, 0xC5, 0xD4, 
+0xDE, 0x77, 0xDE, 0x97, 0xCE, 0x15, 0xDE, 0x55, 
+0xD6, 0x34, 0xB5, 0x30, 0xC5, 0xB2, 0xBD, 0x31, 
+0xC5, 0x92, 0xCE, 0x16, 0xEF, 0x1B, 0xFF, 0xDF, 
+0xE7, 0x1C, 0x73, 0xAE, 0x5A, 0xEB, 0x9C, 0xF3, 
+0xFF, 0xDE, 0xF7, 0x7C, 0xCE, 0x56, 0x63, 0x88, 
+0x5B, 0xC7, 0x95, 0x4E, 0xBE, 0x71, 0xAE, 0x4D, 
+0xB6, 0x4C, 0xB6, 0x4C, 0xBE, 0x6D, 0xBD, 0xEF, 
+0xFF, 0xFF, 0xD6, 0x9A, 0x73, 0xAE, 0xE7, 0x1C, 
+0xEF, 0x5D, 0xD6, 0x78, 0xF7, 0x9D, 0xC6, 0x18, 
+0x73, 0xAE, 0xAD, 0x75, 0xF7, 0x9E, 0xDE, 0xBA, 
+0xF7, 0x9E, 0xCE, 0x59, 0x73, 0xAE, 0xEF, 0x3C, 
+0xDE, 0xFB, 0x94, 0x70, 0x83, 0xCC, 0x94, 0x8E, 
+0x9D, 0x2F, 0xA5, 0xF1, 0x9D, 0x6F, 0x94, 0xAD, 
+0x9C, 0xCF, 0x9C, 0xB0, 0x94, 0x6F, 0x8C, 0x2E, 
+0x94, 0x91, 0x9C, 0xD3, 0x52, 0x89, 0x6B, 0x4B, 
+0x9C, 0xAF, 0x9C, 0x8F, 0x7B, 0xAC, 0xAD, 0x72, 
+0xC6, 0x56, 0xBE, 0x14, 0xC6, 0x74, 0xC6, 0x74, 
+0xAD, 0x92, 0x9C, 0x8F, 0x83, 0xED, 0x52, 0x68, 
+0x5A, 0xCA, 0x62, 0xEA, 0x62, 0xEA, 0x4A, 0x48, 
+0x39, 0xC6, 0x31, 0x85, 0x39, 0xE6, 0x42, 0x07, 
+0x5A, 0xCB, 0x5A, 0xEB, 0x7B, 0xF0, 0x9C, 0xD3, 
+0xBD, 0xF8, 0xC6, 0x39, 0xCE, 0x7A, 0x7B, 0xCF, 
+0xAD, 0x56, 0xF7, 0x9E, 0xFF, 0xFF, 0x7B, 0xEF, 
+0xB5, 0x96, 0xF7, 0xBE, 0xD6, 0xB8, 0xD6, 0x75, 
+0xC5, 0x92, 0xBD, 0x51, 0xC5, 0x31, 0xCD, 0xB2, 
+0xCD, 0x92, 0xC5, 0x72, 0xCD, 0x92, 0xC5, 0x72, 
+0xCD, 0x92, 0xD5, 0xD3, 0xC5, 0x72, 0xA4, 0xD0, 
+0xB5, 0x53, 0xBD, 0x93, 0xBD, 0xB3, 0xB5, 0x52, 
+0xCE, 0x35, 0xC5, 0xF5, 0xC5, 0xD5, 0xBD, 0xB5, 
+0xBD, 0x94, 0xBD, 0x94, 0xC5, 0xD5, 0x83, 0xEE, 
+0x20, 0xE3, 0x94, 0x51, 0xBD, 0x94, 0xBD, 0xB4, 
+0xB5, 0x74, 0xAD, 0x54, 0xBD, 0xF7, 0xC6, 0x18, 
+0xC5, 0xF8, 0xC5, 0xF7, 0xBD, 0xB6, 0xAD, 0x55, 
+0x5A, 0xAB, 0x42, 0x08, 0x41, 0xE7, 0x42, 0x28, 
+0x42, 0x28, 0x41, 0xE7, 0x29, 0x65, 0x29, 0x45, 
+0x31, 0x85, 0x29, 0x65, 0x18, 0xE3, 0x29, 0x65, 
+0x29, 0x44, 0x21, 0x24, 0x29, 0x65, 0x39, 0xC6, 
+0x7B, 0xCE, 0xD6, 0xBA, 0xF7, 0x9E, 0x73, 0xAE, 
+0xC6, 0x18, 0xF7, 0x9E, 0xDE, 0xBA, 0xDE, 0x9A, 
+0xCE, 0x18, 0xC5, 0xD7, 0xBD, 0x76, 0xC5, 0xF7, 
+0x94, 0x92, 0x7B, 0x8E, 0x8C, 0x31, 0xAD, 0x34, 
+0xBD, 0xB6, 0xE7, 0x1B, 0xDE, 0xBA, 0xDE, 0x99, 
+0xC5, 0xB5, 0xAC, 0xF2, 0xC5, 0xD5, 0xBD, 0x94, 
+0x94, 0x70, 0x52, 0xA9, 0x42, 0x08, 0x4A, 0x6A, 
+0x52, 0xAB, 0x6B, 0x6F, 0x8C, 0x52, 0xC6, 0x18, 
+0xEF, 0x5D, 0xF7, 0xBE, 0xF7, 0xBE, 0xEF, 0x5C, 
+0xD6, 0x99, 0xB5, 0x53, 0xAC, 0xF2, 0xA4, 0xF1, 
+0x9C, 0x70, 0xA4, 0xF2, 0xBD, 0x94, 0xA4, 0xB1, 
+0xAD, 0x33, 0xB5, 0x33, 0xB5, 0x54, 0xB5, 0x54, 
+0xD6, 0x18, 0xE6, 0xBA, 0xF7, 0x5C, 0x94, 0x71, 
+0xBD, 0xB7, 0xBD, 0x96, 0xCE, 0x18, 0xC5, 0xB7, 
+0xB5, 0x55, 0x9C, 0x72, 0xB5, 0x34, 0xA4, 0xD3, 
+0x83, 0xAE, 0x62, 0xCA, 0x62, 0xCA, 0x5A, 0x69, 
+0x5A, 0x8A, 0x5A, 0xAA, 0x5A, 0x89, 0x52, 0x28, 
+0x52, 0x49, 0x5A, 0x8A, 0x39, 0xC7, 0x20, 0xE4, 
+0x73, 0x8E, 0xA4, 0xF3, 0xA4, 0xD3, 0x9C, 0xD3, 
+0x84, 0x10, 0xA4, 0xF2, 0xB5, 0x33, 0xBD, 0x94, 
+0xBD, 0xB4, 0x94, 0x91, 0x9C, 0xB2, 0x94, 0x70, 
+0xCE, 0x15, 0xD6, 0x15, 0xC5, 0x93, 0xD6, 0x35, 
+0xBD, 0x72, 0xC5, 0xB3, 0xDE, 0x75, 0xDE, 0x96, 
+0xE6, 0x96, 0xE6, 0x96, 0xDE, 0x75, 0xDE, 0x75, 
+0xD6, 0x55, 0xE6, 0x96, 0xE6, 0xD7, 0xAD, 0x92, 
+0x63, 0xCA, 0x63, 0xEA, 0x8D, 0x50, 0x5B, 0xAA, 
+0x43, 0x07, 0x5B, 0x8A, 0x42, 0xC6, 0x43, 0x07, 
+0x22, 0x04, 0x21, 0xC3, 0x53, 0x69, 0x43, 0x07, 
+0x4B, 0x47, 0x53, 0xC9, 0x5C, 0x09, 0x6C, 0x8B, 
+0x74, 0xCC, 0x6C, 0xAB, 0x53, 0xE9, 0x3A, 0xC5, 
+0x19, 0xE2, 0x19, 0xA2, 0x21, 0xC4, 0x21, 0x64, 
+0x4A, 0x48, 0x5A, 0xCA, 0x8C, 0x0D, 0x8C, 0x2D, 
+0x9C, 0x8E, 0xB5, 0x31, 0xB5, 0x51, 0xAD, 0x30, 
+0xBD, 0x71, 0xB5, 0x30, 0xB5, 0x30, 0xBD, 0x71, 
+0xCE, 0x14, 0xA4, 0xB0, 0x9C, 0x6F, 0xCE, 0x15, 
+0xAD, 0x10, 0xAD, 0x10, 0xF7, 0x9E, 0x9C, 0xD3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0xE3, 0xFF, 0xDF, 0xEF, 0x3B, 
+0xDE, 0x97, 0x9C, 0xB0, 0xDE, 0xD9, 0xEF, 0x5B, 
+0xEF, 0x5C, 0xEF, 0x5C, 0xE7, 0x1B, 0xDE, 0x98, 
+0xD6, 0x35, 0xAD, 0x11, 0xD6, 0x78, 0xE7, 0x1B, 
+0xEF, 0x7C, 0xEF, 0x5C, 0xEF, 0x3B, 0xEE, 0xF9, 
+0xB5, 0x52, 0xE6, 0xB7, 0xEF, 0x1A, 0xF7, 0x7D, 
+0xFF, 0xBE, 0xF7, 0x9D, 0xEF, 0x3B, 0xEF, 0x19, 
+0xD6, 0x55, 0xAC, 0xCF, 0xCD, 0xD3, 0xA4, 0xD0, 
+0xC5, 0xF6, 0xE7, 0x1B, 0xFF, 0xBE, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xF7, 0x9D, 
+0xEF, 0x3B, 0xD6, 0x97, 0xCE, 0x35, 0x63, 0x88, 
+0x6C, 0x29, 0x95, 0x2E, 0xAD, 0xAF, 0xBE, 0x4F, 
+0xB6, 0x2F, 0xBE, 0x6E, 0xB6, 0x2D, 0xBE, 0x50, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xEF, 0x7D, 0xD6, 0x98, 0xF7, 0x9D, 0x8C, 0x71, 
+0x00, 0x00, 0x6B, 0x4D, 0xF7, 0xBE, 0xE6, 0xFB, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0xDE, 0xDB, 
+0xEF, 0x3C, 0xBD, 0x73, 0xB5, 0x10, 0xB5, 0x10, 
+0xA5, 0x0F, 0x9D, 0x2F, 0xA5, 0x2E, 0xA5, 0x0F, 
+0x94, 0x6E, 0xAD, 0x52, 0xA5, 0x10, 0xC5, 0xD4, 
+0xAD, 0x33, 0x4A, 0x68, 0x7B, 0xCD, 0x94, 0xAF, 
+0x8C, 0x0C, 0x73, 0x6A, 0xA5, 0x72, 0xC6, 0x76, 
+0xDF, 0x3A, 0xCE, 0xF6, 0xC6, 0xB4, 0xB6, 0x52, 
+0xBE, 0x33, 0xA4, 0xF0, 0x8C, 0x2E, 0x52, 0x48, 
+0x5A, 0xA9, 0x63, 0x0A, 0x6B, 0x2B, 0x7B, 0xCD, 
+0x73, 0x8D, 0x42, 0x07, 0x31, 0xC6, 0x39, 0xE6, 
+0x42, 0x07, 0x4A, 0x69, 0x63, 0x0C, 0x8C, 0x72, 
+0xB5, 0xB7, 0xAD, 0x76, 0x9C, 0xD3, 0x6B, 0x6E, 
+0xCE, 0x7A, 0xEF, 0x7E, 0xFF, 0xFF, 0x08, 0x41, 
+0x6B, 0x6D, 0xF7, 0x9E, 0xBD, 0xD6, 0xA4, 0xF2, 
+0xAD, 0x11, 0xCD, 0xB3, 0xD5, 0xB2, 0xDE, 0x14, 
+0xD5, 0xF3, 0xC5, 0x51, 0xC5, 0x71, 0xC5, 0x51, 
+0xCD, 0x92, 0xDD, 0xF3, 0xDD, 0xF4, 0x9C, 0x6F, 
+0xB5, 0x53, 0xB5, 0x73, 0xBD, 0xB4, 0xC5, 0xD4, 
+0xC5, 0xF5, 0xBD, 0xB4, 0xBD, 0xB4, 0xBD, 0x94, 
+0xBD, 0x94, 0xBD, 0xB5, 0xC5, 0xD5, 0x83, 0xAE, 
+0x52, 0x69, 0xB5, 0x34, 0xBD, 0x95, 0xCE, 0x37, 
+0xD6, 0x79, 0xD6, 0x79, 0xC6, 0x18, 0xCE, 0x59, 
+0xBD, 0xB6, 0xA5, 0x14, 0x9C, 0x92, 0x94, 0x71, 
+0x5A, 0xAA, 0x41, 0xE7, 0x42, 0x08, 0x42, 0x08, 
+0x39, 0xC7, 0x31, 0x86, 0x31, 0x86, 0x21, 0x24, 
+0x31, 0x85, 0x31, 0xA6, 0x31, 0x86, 0x39, 0xA6, 
+0x29, 0x44, 0x21, 0x03, 0x29, 0x44, 0x4A, 0x48, 
+0x84, 0x0F, 0xDE, 0xDB, 0xEF, 0x7D, 0x00, 0x00, 
+0x8C, 0x51, 0xF7, 0x9E, 0xE6, 0xDB, 0xD6, 0x59, 
+0xC5, 0xF7, 0xD6, 0x59, 0xAD, 0x34, 0xB5, 0x76, 
+0xCE, 0x59, 0xBD, 0xD7, 0x73, 0x4E, 0x7B, 0xAF, 
+0x94, 0x92, 0xD6, 0x79, 0xEF, 0x1C, 0xBD, 0xB6, 
+0xA5, 0x13, 0x94, 0x51, 0xC5, 0xB6, 0xDE, 0xB9, 
+0xC5, 0xB5, 0xB5, 0x74, 0x5A, 0xAA, 0x39, 0xC7, 
+0x42, 0x28, 0x5A, 0xCC, 0x84, 0x31, 0xC6, 0x18, 
+0xF7, 0x9E, 0xEF, 0x5D, 0xDE, 0xFB, 0xF7, 0xBE, 
+0xD6, 0x79, 0xA4, 0xD3, 0xAC, 0xF3, 0xAD, 0x34, 
+0x9C, 0xB2, 0x9C, 0x91, 0xB5, 0x55, 0xB5, 0x55, 
+0xCE, 0x38, 0xD6, 0x58, 0xEE, 0xFA, 0xEF, 0x3C, 
+0xEE, 0xFB, 0xF7, 0x1C, 0xD6, 0x79, 0x7B, 0xAF, 
+0x7B, 0xCF, 0xAD, 0x14, 0xCE, 0x18, 0xBD, 0x96, 
+0x8C, 0x10, 0x7B, 0x4D, 0x6B, 0x0C, 0x5A, 0x69, 
+0x49, 0xE7, 0x41, 0xC7, 0x49, 0xE7, 0x41, 0xC7, 
+0x52, 0x49, 0x5A, 0xAA, 0x63, 0x0B, 0x83, 0xEF, 
+0x9C, 0xD2, 0x7B, 0xAE, 0x5A, 0xAA, 0x31, 0x86, 
+0x62, 0xCA, 0x7B, 0x8E, 0x73, 0x4D, 0x73, 0x6D, 
+0x9C, 0x91, 0xC5, 0xF5, 0xD6, 0x35, 0xD6, 0x56, 
+0xD6, 0x56, 0xAD, 0x32, 0xB5, 0x54, 0xA4, 0xF2, 
+0xB5, 0x32, 0xB5, 0x11, 0xB5, 0x12, 0xBD, 0x94, 
+0xBD, 0x94, 0xBD, 0x93, 0xBD, 0x72, 0xC5, 0xD4, 
+0xCE, 0x14, 0xD6, 0x35, 0xD6, 0x35, 0xD6, 0x35, 
+0xDE, 0x55, 0xD6, 0x35, 0xD6, 0x35, 0x8C, 0xAF, 
+0x42, 0xC7, 0x64, 0x0B, 0xA6, 0x13, 0x5B, 0xCA, 
+0x6C, 0x2C, 0x74, 0x8D, 0x4B, 0x68, 0x32, 0xA4, 
+0x2A, 0x23, 0x2A, 0x65, 0x53, 0x89, 0x53, 0xA9, 
+0x64, 0x0A, 0x4B, 0x48, 0x32, 0xA5, 0x5B, 0xE9, 
+0x6C, 0x8B, 0x85, 0x2D, 0x64, 0x0A, 0x21, 0xE3, 
+0x19, 0xC3, 0x21, 0xE3, 0x32, 0x66, 0x21, 0x84, 
+0x52, 0x89, 0x63, 0x0A, 0x83, 0xCC, 0x8C, 0x0C, 
+0x94, 0x6D, 0xAC, 0xF0, 0xA4, 0xEF, 0xAD, 0x30, 
+0xB5, 0x30, 0xAD, 0x0F, 0xAC, 0xF0, 0xBD, 0x71, 
+0xCE, 0x34, 0xA4, 0xAF, 0xA4, 0x8F, 0xB5, 0x72, 
+0xB5, 0x31, 0xB5, 0x31, 0xF7, 0x9E, 0x9C, 0xD3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0xE3, 0xFF, 0xDF, 0xE7, 0x1B, 
+0xDE, 0xB7, 0xD6, 0x78, 0xF7, 0x7D, 0xFF, 0xDE, 
+0xEF, 0x7D, 0xE7, 0x3C, 0xFF, 0xDE, 0xF7, 0x9D, 
+0xE7, 0x1A, 0xDE, 0xDA, 0xFF, 0xBE, 0xF7, 0x9E, 
+0xC6, 0x18, 0xCE, 0x59, 0xFF, 0xBE, 0xF7, 0x9D, 
+0xDE, 0xBA, 0xF7, 0x9D, 0xFF, 0xDE, 0xE7, 0x1C, 
+0xAD, 0x55, 0xC6, 0x38, 0xFF, 0xDF, 0xF7, 0x9D, 
+0xE6, 0xD8, 0xB5, 0x52, 0xD6, 0x55, 0xCE, 0x37, 
+0xF7, 0x7D, 0xF7, 0x9E, 0xB5, 0x96, 0xA5, 0x34, 
+0xE7, 0x1C, 0xFF, 0xFF, 0xEF, 0x7D, 0xDF, 0x19, 
+0xEF, 0x59, 0xD6, 0x95, 0xD6, 0x97, 0x63, 0x69, 
+0x7C, 0x6B, 0xB6, 0x12, 0xC6, 0x33, 0xD6, 0xB4, 
+0xCE, 0x74, 0xC6, 0x52, 0xBE, 0x11, 0xB5, 0xB0, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xEF, 0x7D, 0xE6, 0xFA, 0xF7, 0xBE, 0xBD, 0xD7, 
+0x63, 0x0C, 0xA5, 0x14, 0xF7, 0xBE, 0xE6, 0xFB, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0xDE, 0xDB, 
+0xEF, 0x5C, 0xCE, 0x36, 0xCD, 0xF4, 0xD6, 0x55, 
+0xCE, 0x14, 0xDE, 0x95, 0xBD, 0x71, 0xAC, 0xEF, 
+0x8C, 0x0D, 0xB5, 0x53, 0xCE, 0x16, 0xAD, 0x53, 
+0x73, 0xAD, 0x94, 0xB0, 0xA5, 0x50, 0xA5, 0x4F, 
+0xA5, 0x0F, 0x9C, 0xCF, 0xC6, 0x55, 0xDF, 0x19, 
+0xEF, 0x7C, 0xCE, 0xB7, 0xAD, 0xF2, 0x94, 0xEF, 
+0x94, 0x8E, 0xBD, 0xB4, 0xB5, 0x53, 0x84, 0x0F, 
+0xA4, 0xD2, 0x9C, 0x91, 0x9C, 0x91, 0xC6, 0x16, 
+0x8C, 0x6F, 0x8C, 0x70, 0x7B, 0xCD, 0x63, 0x2C, 
+0x6B, 0x6D, 0x73, 0xAE, 0x84, 0x0F, 0x84, 0x30, 
+0x94, 0x72, 0x73, 0x8E, 0x63, 0x2D, 0x84, 0x10, 
+0xC6, 0x18, 0xE7, 0x3D, 0xFF, 0xFF, 0x08, 0x41, 
+0x6B, 0x6D, 0xF7, 0x9E, 0xC6, 0x18, 0xAD, 0x74, 
+0xAD, 0x13, 0xD6, 0x36, 0xDE, 0x35, 0xDE, 0x34, 
+0xDE, 0x34, 0xBD, 0x10, 0xC5, 0x51, 0xCD, 0x92, 
+0xD5, 0xD2, 0xD5, 0xF3, 0xCD, 0xB3, 0xA4, 0xB0, 
+0xBD, 0xB4, 0xB5, 0x74, 0xC6, 0x16, 0xCE, 0x36, 
+0xCE, 0x16, 0xC5, 0xF5, 0xBD, 0xB4, 0xBD, 0xB4, 
+0xB5, 0x93, 0xB5, 0x53, 0xAD, 0x32, 0x73, 0x4C, 
+0xA4, 0xD3, 0xCE, 0x17, 0x9C, 0x91, 0x94, 0x71, 
+0xC6, 0x18, 0xBD, 0xD7, 0x9C, 0xD3, 0x94, 0x71, 
+0x8C, 0x51, 0x73, 0x8E, 0x63, 0x0C, 0x7B, 0x8E, 
+0x41, 0xE7, 0x39, 0xA6, 0x31, 0x85, 0x39, 0xC6, 
+0x31, 0xA6, 0x42, 0x07, 0x5A, 0xCB, 0x6B, 0x2C, 
+0x6B, 0x4D, 0x6B, 0x6D, 0x73, 0x8E, 0x6B, 0x4D, 
+0x5A, 0xCA, 0x39, 0xE7, 0x42, 0x07, 0x63, 0x0B, 
+0x8C, 0x30, 0xDE, 0xDB, 0xF7, 0x7D, 0x00, 0x00, 
+0x8C, 0x51, 0xF7, 0x9E, 0xCE, 0x59, 0xC5, 0xD7, 
+0xCE, 0x18, 0xCE, 0x18, 0xAD, 0x35, 0xCE, 0x59, 
+0xD6, 0x9A, 0xD6, 0x79, 0xA4, 0xF4, 0xC6, 0x18, 
+0xB5, 0x96, 0x9C, 0xB3, 0xE6, 0xDB, 0xE7, 0x1C, 
+0xC5, 0xF8, 0xDE, 0xBB, 0xCE, 0x18, 0xBD, 0x96, 
+0xC5, 0xD6, 0xC5, 0xD6, 0x94, 0x71, 0x6B, 0x4C, 
+0x5A, 0xCB, 0x7B, 0xF0, 0x9C, 0xF4, 0xCE, 0x59, 
+0xF7, 0xBE, 0x6B, 0x6D, 0x10, 0x82, 0xFF, 0xDF, 
+0xE7, 0x3C, 0xCE, 0x58, 0xE6, 0xDA, 0xCE, 0x38, 
+0xC5, 0xF7, 0xC5, 0xD7, 0xD6, 0x59, 0xDE, 0x79, 
+0xC5, 0xD6, 0xAD, 0x55, 0xCE, 0x38, 0xCE, 0x59, 
+0xCE, 0x38, 0xBD, 0xB6, 0x9C, 0x93, 0x6B, 0x0D, 
+0x5A, 0xAB, 0x41, 0xE8, 0x4A, 0x49, 0x4A, 0x6A, 
+0x4A, 0x08, 0x41, 0xC7, 0x41, 0xC6, 0x39, 0xA6, 
+0x31, 0x45, 0x31, 0x45, 0x39, 0xA6, 0x62, 0xEC, 
+0xAD, 0x55, 0xAD, 0x54, 0xAD, 0x34, 0xA4, 0xF3, 
+0x94, 0x92, 0x8C, 0x51, 0x84, 0x10, 0x63, 0x0C, 
+0x62, 0xEB, 0x73, 0x6C, 0xAD, 0x32, 0xBD, 0xB5, 
+0xBD, 0xD6, 0xBD, 0xD5, 0xBD, 0xB5, 0xBD, 0xB5, 
+0xC5, 0xD6, 0xCE, 0x17, 0xCE, 0x17, 0xCE, 0x17, 
+0xCE, 0x37, 0xC5, 0xF6, 0xBD, 0x95, 0xB5, 0x53, 
+0xB5, 0x53, 0xBD, 0x74, 0xBD, 0x95, 0xBD, 0x94, 
+0xB5, 0x74, 0xB5, 0x54, 0xAD, 0x33, 0xA4, 0xF2, 
+0xA4, 0xD1, 0xA4, 0xF2, 0xA5, 0x12, 0x8C, 0x90, 
+0x8C, 0x90, 0x8C, 0x90, 0x42, 0xE6, 0x2A, 0x43, 
+0x53, 0x68, 0x32, 0x44, 0x3A, 0xC5, 0x3A, 0xE5, 
+0x3A, 0xC5, 0x43, 0x07, 0x5B, 0xEA, 0x53, 0xA9, 
+0x64, 0x4B, 0x3A, 0xC6, 0x22, 0x03, 0x19, 0xC2, 
+0x43, 0x27, 0x85, 0x2E, 0x74, 0xAC, 0x22, 0x03, 
+0x19, 0xA3, 0x2A, 0x24, 0x2A, 0x25, 0x21, 0x84, 
+0x52, 0xA9, 0x63, 0x0A, 0x7B, 0xAC, 0x83, 0xCB, 
+0x94, 0x2D, 0x9C, 0x8E, 0x9C, 0x8E, 0xA4, 0xCF, 
+0x94, 0x4D, 0xAD, 0x30, 0xA4, 0xEF, 0xB5, 0x71, 
+0xCE, 0x34, 0xA4, 0xAF, 0xA4, 0xAF, 0xB5, 0x71, 
+0xB5, 0x51, 0xB5, 0x72, 0xF7, 0x9E, 0x9C, 0xD3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0xE3, 0xFF, 0xDF, 0xE7, 0x1B, 
+0xDE, 0xB8, 0xEF, 0x7C, 0xEF, 0x7D, 0x52, 0xAA, 
+0x00, 0x00, 0x00, 0x00, 0x39, 0xE7, 0xE7, 0x1B, 
+0xFF, 0xDE, 0xFF, 0xBE, 0xD6, 0x9A, 0x21, 0x04, 
+0x00, 0x00, 0x00, 0x00, 0x31, 0x86, 0xE7, 0x1C, 
+0xFF, 0xBE, 0xFF, 0xFF, 0x9C, 0xF3, 0x00, 0x20, 
+0x00, 0x00, 0x00, 0x00, 0x42, 0x28, 0xF7, 0xBE, 
+0xF7, 0x7C, 0xC5, 0xD5, 0xDE, 0xB8, 0xEF, 0x5C, 
+0xEF, 0x3C, 0x29, 0x65, 0x00, 0x00, 0x00, 0x00, 
+0x08, 0x41, 0xAD, 0x55, 0xF7, 0xBE, 0xD6, 0xD8, 
+0xC6, 0x95, 0xE7, 0x58, 0xD6, 0xB6, 0x6B, 0x8A, 
+0x9D, 0x50, 0xDF, 0x17, 0xE6, 0xD7, 0xE6, 0xD6, 
+0xDE, 0xB6, 0xDE, 0xB6, 0xDE, 0xB5, 0xDE, 0x75, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x9D, 0xE7, 0x1A, 0xFF, 0xBE, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xE6, 0xFA, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0xDE, 0xDB, 
+0xF7, 0x9E, 0xE7, 0x1B, 0xEF, 0x3B, 0xEF, 0x5B, 
+0xE6, 0xFA, 0xDE, 0xB9, 0xC5, 0xF6, 0xAD, 0x32, 
+0xA5, 0x12, 0xDE, 0xDA, 0xD6, 0x99, 0xC6, 0x38, 
+0xCE, 0x58, 0xCE, 0x77, 0xAD, 0xB2, 0xA5, 0x6E, 
+0xB6, 0x31, 0xAD, 0xB2, 0xCE, 0xB8, 0xEF, 0x7C, 
+0xF7, 0xBE, 0xDF, 0x1B, 0xBE, 0x16, 0x9C, 0xD1, 
+0x73, 0x6C, 0x7B, 0xAD, 0xAD, 0x74, 0xCE, 0x38, 
+0xEF, 0x3C, 0xEF, 0x3C, 0xEF, 0x5D, 0xCE, 0x79, 
+0x7B, 0xEF, 0x94, 0xB1, 0xD6, 0x98, 0xCE, 0x79, 
+0xCE, 0x59, 0xCE, 0x79, 0xCE, 0x79, 0xC6, 0x38, 
+0xB5, 0x96, 0x94, 0xB2, 0x8C, 0x51, 0xAD, 0x56, 
+0xBD, 0xF8, 0xE7, 0x1C, 0xFF, 0xDF, 0x08, 0x41, 
+0x6B, 0x6D, 0xFF, 0xDF, 0xDE, 0xFB, 0xDE, 0xDB, 
+0xEF, 0x3C, 0xEF, 0x7D, 0xE7, 0x1A, 0xE7, 0x18, 
+0xDE, 0xB6, 0xC5, 0xF3, 0x9C, 0x6D, 0x94, 0x0D, 
+0xA4, 0x6E, 0xAC, 0xAF, 0xAC, 0xD0, 0xBD, 0xB5, 
+0xCE, 0x58, 0xD6, 0xBA, 0xE7, 0x1B, 0xE7, 0x3B, 
+0xE7, 0x3B, 0xDE, 0xFA, 0xD6, 0x98, 0xCE, 0x57, 
+0xAD, 0xB2, 0xA5, 0x4F, 0x9C, 0xCF, 0xAD, 0x13, 
+0xAC, 0xF3, 0xB5, 0x54, 0x9C, 0xD3, 0xAD, 0x75, 
+0xCE, 0x59, 0xD6, 0x9A, 0xD6, 0x9A, 0xCE, 0x79, 
+0xC6, 0x38, 0xAD, 0x75, 0x94, 0x91, 0x6B, 0x4D, 
+0x39, 0xE7, 0x31, 0x85, 0x31, 0x85, 0x4A, 0x69, 
+0x52, 0xAA, 0x84, 0x10, 0xAD, 0x55, 0xC6, 0x18, 
+0xCE, 0x59, 0xCE, 0x79, 0xCE, 0x79, 0xC6, 0x38, 
+0xB5, 0x96, 0x94, 0x92, 0x7B, 0xCE, 0x52, 0x89, 
+0x84, 0x0F, 0xDE, 0xDB, 0xF7, 0x7D, 0x00, 0x00, 
+0x8C, 0x51, 0xF7, 0x7D, 0xBD, 0xB6, 0xA4, 0xD3, 
+0xC5, 0xB7, 0xB5, 0x76, 0xCE, 0x59, 0xE7, 0x3C, 
+0xD6, 0xBA, 0xEF, 0x3D, 0xDE, 0xFB, 0xD6, 0x9A, 
+0xBD, 0xF7, 0xC5, 0xF8, 0xDE, 0xDB, 0xDE, 0xDB, 
+0xE7, 0x1C, 0xE7, 0x1C, 0xEF, 0x5D, 0xE7, 0x1C, 
+0xC6, 0x18, 0xBD, 0xD7, 0x9C, 0x91, 0xD6, 0x78, 
+0xA5, 0x14, 0xBD, 0xD7, 0xCE, 0x79, 0xDE, 0xFB, 
+0xF7, 0xBE, 0x6B, 0x6D, 0x10, 0x82, 0xFF, 0xFF, 
+0xEF, 0x7D, 0xDE, 0xDB, 0xE7, 0x1C, 0xD6, 0x9A, 
+0xBD, 0xB7, 0xCE, 0x38, 0xC5, 0xD7, 0xEF, 0x1C, 
+0xD6, 0x9A, 0xCE, 0x59, 0xD6, 0xBA, 0xD6, 0xBA, 
+0xDE, 0xBA, 0xCE, 0x79, 0xC5, 0xF7, 0x9C, 0xD3, 
+0x7B, 0xAE, 0x52, 0x6A, 0x41, 0xE8, 0x39, 0xC7, 
+0x29, 0x65, 0x31, 0x65, 0x42, 0x08, 0x73, 0x6D, 
+0x9C, 0xD3, 0xBD, 0xB6, 0xBD, 0xF7, 0xAD, 0x55, 
+0x94, 0xB2, 0xAD, 0x55, 0xBD, 0xF7, 0xCE, 0x59, 
+0xD6, 0xBA, 0xDE, 0xDA, 0xD6, 0x99, 0xC6, 0x37, 
+0xC5, 0xF5, 0xCE, 0x15, 0xBD, 0xB3, 0xB5, 0x74, 
+0xCE, 0x37, 0xDE, 0xDA, 0xEF, 0x1B, 0xE7, 0x1B, 
+0xDE, 0xDA, 0xDE, 0xDA, 0xE6, 0xFB, 0xE7, 0x1B, 
+0xE7, 0x1B, 0xDE, 0xDB, 0xC6, 0x17, 0xB5, 0x74, 
+0xC5, 0xD6, 0xCE, 0x58, 0xDE, 0xDA, 0xE6, 0xFB, 
+0xE7, 0x1B, 0xE7, 0x1B, 0xE6, 0xFB, 0xDE, 0xDA, 
+0xDE, 0xBA, 0xDE, 0xDA, 0xE7, 0x3C, 0xE7, 0x3C, 
+0xEF, 0x5C, 0xD6, 0xDA, 0x22, 0x03, 0x22, 0x23, 
+0x22, 0x03, 0x2A, 0x24, 0x43, 0x27, 0x53, 0xC8, 
+0x53, 0xA8, 0x53, 0xA8, 0x64, 0x4B, 0x5B, 0xEA, 
+0x43, 0x28, 0x19, 0xC3, 0x21, 0xE4, 0x19, 0xC3, 
+0x19, 0xC3, 0x32, 0x84, 0x3A, 0xA5, 0x32, 0x85, 
+0x11, 0x82, 0x22, 0x04, 0x11, 0x42, 0x10, 0xC1, 
+0x52, 0x89, 0x52, 0x88, 0x62, 0xE9, 0x6B, 0x09, 
+0x73, 0x4A, 0x7B, 0xCC, 0x8C, 0x0C, 0x9C, 0x6E, 
+0xA4, 0xF0, 0xAD, 0x31, 0xAD, 0x30, 0xB5, 0x30, 
+0xB5, 0x51, 0x9C, 0x4E, 0x9C, 0x4E, 0xA4, 0xCF, 
+0xA4, 0xAF, 0x9C, 0xAF, 0xF7, 0x9D, 0x9C, 0xD3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0xA2, 0xFF, 0xDF, 0xF7, 0x7D, 
+0xEF, 0x5C, 0xFF, 0xDE, 0x6B, 0x4D, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x08, 
+0xFF, 0xFF, 0xFF, 0xFF, 0x31, 0x86, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xAA, 
+0xFF, 0xFF, 0xE7, 0x3C, 0x08, 0x41, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x50, 
+0xFF, 0xDE, 0xE6, 0xFB, 0xFF, 0x9D, 0xFF, 0xDF, 
+0x63, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x08, 0x61, 0xF7, 0x9E, 0xE7, 0x3C, 
+0xAD, 0xD4, 0xDF, 0x38, 0xAD, 0x71, 0x8C, 0x8D, 
+0xBE, 0x34, 0xCE, 0x34, 0xCE, 0x34, 0xCE, 0x14, 
+0xC6, 0x13, 0xC5, 0xF3, 0xCE, 0x34, 0xCE, 0x34, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x9D, 0xE7, 0x1A, 0xF7, 0x9D, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xDE, 0xDA, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0xDE, 0xFB, 
+0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF, 
+0xFF, 0xDF, 0xFF, 0xDE, 0xF7, 0x9D, 0xEF, 0x3B, 
+0xDE, 0xDA, 0xDE, 0xFB, 0xF7, 0x9D, 0xFF, 0xDE, 
+0xF7, 0xBE, 0xEF, 0x5D, 0xC6, 0x36, 0x9D, 0x6F, 
+0xBE, 0x73, 0xC6, 0x96, 0xEF, 0x9D, 0xFF, 0xDF, 
+0xFF, 0xFF, 0xF7, 0xBE, 0xE7, 0x1B, 0x9C, 0xD2, 
+0x52, 0x89, 0x6B, 0x6D, 0xC6, 0x38, 0xEF, 0x7D, 
+0xF7, 0xBE, 0xFF, 0xDF, 0xF7, 0xBE, 0xD6, 0xBA, 
+0xB5, 0x96, 0xD6, 0xBA, 0xF7, 0xBE, 0xFF, 0xDE, 
+0xFF, 0xBE, 0xFF, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xEF, 0x7D, 0xDE, 0xFB, 0xBD, 0xF7, 0xA5, 0x14, 
+0xB5, 0x96, 0xE7, 0x1C, 0xFF, 0xDF, 0x08, 0x41, 
+0x6B, 0x6D, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xDF, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xF7, 0xBE, 
+0xEF, 0x7C, 0xD6, 0xF8, 0xCE, 0x55, 0xBD, 0x92, 
+0xB5, 0x72, 0xBD, 0xB4, 0xD6, 0x99, 0xEF, 0x5C, 
+0xF7, 0x9E, 0xFF, 0xDE, 0xFF, 0xDF, 0xFF, 0xDF, 
+0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDE, 0xEF, 0x7C, 
+0xCE, 0xB8, 0xA5, 0x91, 0x9D, 0x6F, 0xBD, 0xF4, 
+0xAD, 0x33, 0xBD, 0xF7, 0xDE, 0xFB, 0xEF, 0x7D, 
+0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xF7, 0xBE, 0xEF, 0x7D, 0xE7, 0x1C, 0xBD, 0xF7, 
+0x84, 0x10, 0x42, 0x28, 0x39, 0xC6, 0x63, 0x2C, 
+0xA5, 0x34, 0xD6, 0xBA, 0xEF, 0x7D, 0xF7, 0x9E, 
+0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xF7, 0x9E, 0xE7, 0x1C, 0xC6, 0x18, 0x8C, 0x71, 
+0x84, 0x30, 0xDE, 0xDB, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xEF, 0x7D, 0xB5, 0x55, 0xB5, 0x55, 
+0xC5, 0xD7, 0xDE, 0xDB, 0xF7, 0xBE, 0xFF, 0xDF, 
+0xF7, 0xBE, 0xFF, 0xDF, 0xF7, 0xBE, 0xF7, 0x9E, 
+0xDE, 0xDB, 0xE7, 0x3C, 0xF7, 0x9E, 0xFF, 0xDF, 
+0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF, 
+0xF7, 0xBE, 0xEF, 0x5D, 0xCE, 0x59, 0xB5, 0x96, 
+0xBD, 0xF7, 0xEF, 0x5D, 0xF7, 0xBE, 0xFF, 0xDF, 
+0xFF, 0xFF, 0x6B, 0x6D, 0x10, 0x82, 0xFF, 0xFF, 
+0xFF, 0xDF, 0xF7, 0xBE, 0xF7, 0xBE, 0xEF, 0x5D, 
+0xD6, 0x59, 0xC5, 0xF8, 0xE7, 0x1C, 0xEF, 0x5D, 
+0xF7, 0x9E, 0xF7, 0xBE, 0xFF, 0xBF, 0xFF, 0xDF, 
+0xF7, 0xBE, 0xF7, 0xBE, 0xEF, 0x7D, 0xE6, 0xFB, 
+0xBD, 0xF7, 0x73, 0xAE, 0x4A, 0x29, 0x29, 0x65, 
+0x21, 0x24, 0x31, 0x86, 0xB5, 0x75, 0xC6, 0x17, 
+0xBD, 0xD7, 0xB5, 0x95, 0x8C, 0x71, 0xB5, 0x96, 
+0xDE, 0xFB, 0xEF, 0x7D, 0xF7, 0xBE, 0xFF, 0xDF, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 
+0xFF, 0xDD, 0xEF, 0x5B, 0xCE, 0x56, 0xAD, 0x33, 
+0xE7, 0x1B, 0xFF, 0xBE, 0xFF, 0xDF, 0xFF, 0xDF, 
+0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF, 0xEF, 0x7D, 
+0xEF, 0x7D, 0xF7, 0xBE, 0xE6, 0xDA, 0xDE, 0x99, 
+0xEF, 0x3C, 0xF7, 0x9E, 0xFF, 0xDE, 0xFF, 0xDE, 
+0xFF, 0xDF, 0xFF, 0xDF, 0xFF, 0xDF, 0xF7, 0xBE, 
+0xFF, 0xBE, 0xFF, 0xBE, 0xEF, 0x7D, 0xB5, 0x96, 
+0xD6, 0xBA, 0xEF, 0x5D, 0x32, 0xA4, 0x32, 0x84, 
+0x32, 0xA5, 0x63, 0xEB, 0x3A, 0xE6, 0x4B, 0x67, 
+0x5B, 0xE9, 0x53, 0xA8, 0x6C, 0x8C, 0x53, 0xA9, 
+0x19, 0xA2, 0x11, 0x82, 0x19, 0xC3, 0x19, 0xC3, 
+0x19, 0xA2, 0x2A, 0x24, 0x32, 0x85, 0x3A, 0xA5, 
+0x11, 0x41, 0x11, 0x42, 0x11, 0x22, 0x29, 0xC5, 
+0x5A, 0xCA, 0x5A, 0xCA, 0x5A, 0x89, 0x5A, 0xA9, 
+0x6B, 0x0A, 0x6B, 0x0A, 0x6B, 0x2A, 0x73, 0x2A, 
+0x7B, 0x6B, 0x83, 0xAB, 0x73, 0x6A, 0x73, 0x2A, 
+0x83, 0xCC, 0x94, 0x4E, 0x9C, 0x8F, 0x8C, 0x0D, 
+0x94, 0x2D, 0x94, 0x2E, 0xF7, 0x7D, 0x84, 0x30, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x08, 0x41, 0xFF, 0xFF, 0xFF, 0xBE, 
+0xF7, 0xBE, 0xFF, 0xFF, 0x18, 0xC3, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xEF, 0x7D, 0xEF, 0x5D, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x61, 
+0xFF, 0xFF, 0xA5, 0x14, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xE7, 
+0xFF, 0xFF, 0xF7, 0x7D, 0xFF, 0xBE, 0xFF, 0xFF, 
+0x21, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xBD, 0xD7, 0xEF, 0x7D, 
+0xAD, 0xD3, 0xD7, 0x17, 0x9D, 0x0F, 0xB5, 0xD3, 
+0xC6, 0x54, 0xC6, 0x34, 0xC6, 0x14, 0xC5, 0xF4, 
+0xCE, 0x14, 0xCE, 0x55, 0xCE, 0x34, 0xCE, 0x34, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x9D, 0xDE, 0xD9, 0xF7, 0x9D, 0xDE, 0xDB, 
+0x29, 0x65, 0xB5, 0xB6, 0xF7, 0xBE, 0xDE, 0xB9, 
+0xF7, 0x9E, 0x9C, 0xF3, 0x00, 0x00, 0xDE, 0xFB, 
+0xAD, 0x55, 0x42, 0x28, 0x18, 0xC3, 0x00, 0x00, 
+0x10, 0xA2, 0x39, 0xE7, 0x9C, 0xD3, 0xFF, 0xDF, 
+0xEF, 0x7D, 0xE7, 0x1C, 0xFF, 0xDF, 0x6B, 0x6D, 
+0x4A, 0x49, 0xFF, 0xDE, 0xDF, 0x1A, 0xB6, 0x32, 
+0xA5, 0x90, 0xCE, 0xB8, 0xF7, 0xBE, 0x63, 0x0C, 
+0x31, 0x86, 0x94, 0xB2, 0xF7, 0xBE, 0xCE, 0xB8, 
+0xA5, 0x92, 0xAD, 0x73, 0xE7, 0x1C, 0xE7, 0x1C, 
+0x31, 0x86, 0xA5, 0x34, 0xF7, 0xBE, 0xE7, 0x1C, 
+0xE7, 0x3C, 0xF7, 0xBE, 0x9C, 0xD3, 0x42, 0x08, 
+0x18, 0xC3, 0x00, 0x00, 0x10, 0x82, 0x29, 0x65, 
+0x73, 0xAE, 0xE7, 0x3C, 0xF7, 0x9E, 0xD6, 0xBA, 
+0xCE, 0x59, 0xE7, 0x3D, 0xFF, 0xDF, 0x08, 0x41, 
+0x6B, 0x6D, 0xDE, 0xFB, 0x6B, 0x4D, 0x29, 0x45, 
+0x08, 0x41, 0x08, 0x41, 0x21, 0x24, 0x6B, 0x6D, 
+0xE7, 0x1C, 0xF7, 0xBE, 0xE7, 0x1A, 0xBD, 0xB3, 
+0xC5, 0xF4, 0xE7, 0x1A, 0xF7, 0xBE, 0xE7, 0x1C, 
+0x73, 0x8E, 0x29, 0x65, 0x10, 0xA2, 0x00, 0x00, 
+0x08, 0x61, 0x21, 0x24, 0x63, 0x2C, 0xD6, 0x9A, 
+0xF7, 0x9D, 0xD6, 0xD8, 0xA5, 0xD1, 0xAD, 0xF1, 
+0xD6, 0xB8, 0xF7, 0xBD, 0xE7, 0x3C, 0x73, 0xAE, 
+0x31, 0x86, 0x10, 0x82, 0x00, 0x00, 0x08, 0x61, 
+0x21, 0x24, 0x63, 0x0C, 0xCE, 0x79, 0xF7, 0x9D, 
+0xCE, 0x59, 0x84, 0x10, 0x6B, 0x4C, 0xAD, 0x55, 
+0xE7, 0x1C, 0xEF, 0x5D, 0x84, 0x30, 0x39, 0xC7, 
+0x10, 0x82, 0x00, 0x00, 0x08, 0x41, 0x21, 0x04, 
+0x63, 0x0C, 0xD6, 0x9A, 0xEF, 0x7D, 0xCE, 0x79, 
+0xA5, 0x14, 0xDE, 0xFB, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xF7, 0x9E, 0xBD, 0x96, 0xBD, 0x96, 
+0xDE, 0xDB, 0xF7, 0xBE, 0xB5, 0xB6, 0x31, 0x86, 
+0x63, 0x0C, 0xF7, 0xBE, 0xEF, 0x7D, 0xE7, 0x3C, 
+0xEF, 0x7D, 0xFF, 0xDF, 0xBD, 0xF7, 0x5A, 0xCB, 
+0x18, 0xE3, 0x08, 0x41, 0x08, 0x41, 0x21, 0x04, 
+0x63, 0x0C, 0xCE, 0x59, 0xFF, 0xDF, 0xE7, 0x3C, 
+0xD6, 0xBA, 0xF7, 0x9E, 0x73, 0x8E, 0x31, 0x86, 
+0x31, 0x86, 0x10, 0xA2, 0x00, 0x00, 0x21, 0x04, 
+0x21, 0x04, 0x21, 0x04, 0x73, 0xAE, 0xF7, 0xBE, 
+0xDE, 0xBA, 0xEF, 0x3C, 0xF7, 0xBE, 0xD6, 0x9A, 
+0x63, 0x0C, 0x29, 0x45, 0x10, 0x82, 0x00, 0x00, 
+0x08, 0x61, 0x29, 0x65, 0x73, 0xAE, 0xDE, 0xFB, 
+0xEF, 0x5D, 0xBD, 0xD7, 0x6B, 0x4D, 0x31, 0x86, 
+0x29, 0x45, 0x29, 0x24, 0x5A, 0xCA, 0x62, 0xEB, 
+0x52, 0xAB, 0x73, 0xAE, 0xBD, 0xF7, 0xEF, 0x7D, 
+0xE7, 0x3C, 0x7B, 0xCF, 0x31, 0x86, 0x10, 0xA2, 
+0x00, 0x00, 0x08, 0x61, 0x21, 0x24, 0x63, 0x0C, 
+0xCE, 0x79, 0xFF, 0xDE, 0xE7, 0x3B, 0xCE, 0x37, 
+0xEF, 0x5C, 0xEF, 0x5C, 0x21, 0x24, 0xB5, 0x96, 
+0xB5, 0x96, 0x39, 0xC7, 0x08, 0x41, 0x00, 0x00, 
+0x52, 0x8A, 0xFF, 0xDF, 0xF7, 0x7C, 0xF7, 0x9D, 
+0xF7, 0xBE, 0x94, 0xB2, 0x42, 0x08, 0x18, 0xE3, 
+0x08, 0x41, 0x00, 0x20, 0x18, 0xC3, 0x31, 0xA6, 
+0x84, 0x10, 0xC6, 0x18, 0x10, 0x82, 0x00, 0x00, 
+0x9C, 0xF3, 0xEF, 0x5D, 0x3A, 0xE5, 0x3B, 0x06, 
+0x64, 0x0B, 0x85, 0x0F, 0x5B, 0xCA, 0x43, 0x07, 
+0xA5, 0xD2, 0x53, 0x88, 0x74, 0xAD, 0x43, 0x07, 
+0x19, 0xA3, 0x19, 0xA3, 0x21, 0xC3, 0x19, 0xA3, 
+0x19, 0xA3, 0x19, 0xA2, 0x32, 0x64, 0x32, 0x85, 
+0x19, 0xA3, 0x21, 0xC3, 0x2A, 0x25, 0x32, 0x66, 
+0x73, 0x4C, 0x83, 0xCD, 0x6B, 0x0A, 0x83, 0xED, 
+0xAC, 0xF1, 0xAC, 0xD0, 0xAC, 0xD0, 0x9C, 0x8F, 
+0x9C, 0x6F, 0x94, 0x4E, 0x8B, 0xED, 0x8C, 0x0D, 
+0xA4, 0xD0, 0xBD, 0x73, 0xB5, 0x32, 0xA4, 0xB0, 
+0xA4, 0xD0, 0xAC, 0xD0, 0xF7, 0x9D, 0x5A, 0xEB, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xDE, 
+0xF7, 0xBE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xC6, 0x38, 0xDE, 0xDB, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xF7, 0x9E, 0x84, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
+0xFF, 0xDF, 0xEF, 0x7C, 0xFF, 0xBE, 0xFF, 0xFF, 
+0x08, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xA5, 0x14, 0xEF, 0x7D, 
+0xB6, 0x14, 0xB6, 0x94, 0xBE, 0x74, 0x9D, 0x0F, 
+0x94, 0xAD, 0xAD, 0x70, 0xA5, 0x2E, 0x9D, 0x4D, 
+0xA5, 0x6E, 0xC6, 0x53, 0xD6, 0x96, 0xB5, 0x72, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x9D, 0xCE, 0x58, 0xF7, 0x9D, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0xBE, 0xDE, 0xB9, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0x52, 0xAA, 
+0x00, 0x00, 0x52, 0x8A, 0x8C, 0x71, 0x9C, 0xD3, 
+0x84, 0x30, 0x39, 0xE7, 0x00, 0x00, 0x52, 0xAA, 
+0xFF, 0xDF, 0xF7, 0x9E, 0xFF, 0xFF, 0x84, 0x30, 
+0x00, 0x00, 0xE7, 0x1C, 0xE7, 0x5C, 0xAD, 0xF2, 
+0xAD, 0xF2, 0xDF, 0x3B, 0xF7, 0xBE, 0x08, 0x41, 
+0x08, 0x61, 0x39, 0xE7, 0xF7, 0xDE, 0xDF, 0x1A, 
+0xB6, 0x54, 0xCE, 0x97, 0xEF, 0x7D, 0xA5, 0x34, 
+0x00, 0x00, 0xCE, 0x59, 0xFF, 0xDF, 0xF7, 0xBE, 
+0xF7, 0x9E, 0x42, 0x08, 0x00, 0x00, 0x4A, 0x69, 
+0x8C, 0x71, 0xA5, 0x34, 0x9C, 0xD3, 0x6B, 0x6D, 
+0x10, 0xA2, 0x10, 0x82, 0xCE, 0x79, 0xF7, 0xBE, 
+0xE7, 0x3C, 0xEF, 0x7D, 0xFF, 0xFF, 0x08, 0x41, 
+0x42, 0x28, 0x10, 0x82, 0x21, 0x24, 0x7B, 0xCF, 
+0x9C, 0xD3, 0x94, 0x92, 0x63, 0x2C, 0x08, 0x61, 
+0x10, 0x82, 0xD6, 0xBA, 0xEF, 0x7D, 0xBD, 0xD6, 
+0xC6, 0x16, 0xEF, 0x7D, 0xD6, 0xBA, 0x10, 0x82, 
+0x08, 0x41, 0x5A, 0xCB, 0x84, 0x30, 0x9C, 0xD3, 
+0x8C, 0x71, 0x6B, 0x4D, 0x18, 0xC3, 0x08, 0x41, 
+0xBD, 0xF7, 0xEF, 0x9D, 0xC6, 0x76, 0xBE, 0x56, 
+0xEF, 0x7D, 0xCE, 0x59, 0x10, 0x82, 0x10, 0x82, 
+0x63, 0x0C, 0x94, 0x92, 0x9C, 0xD3, 0x94, 0xB2, 
+0x73, 0x8E, 0x18, 0xE3, 0x00, 0x00, 0xA5, 0x14, 
+0xEF, 0x7D, 0xBD, 0xF7, 0xA5, 0x13, 0xDE, 0xDB, 
+0xEF, 0x5D, 0x29, 0x65, 0x00, 0x20, 0x52, 0xAA, 
+0x84, 0x10, 0x9C, 0xD3, 0x94, 0x92, 0x6B, 0x4D, 
+0x10, 0x82, 0x00, 0x20, 0xAD, 0x75, 0xEF, 0x7D, 
+0xCE, 0x59, 0xEF, 0x5D, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xFF, 0xDF, 0xDE, 0xBA, 0xD6, 0xBA, 
+0xF7, 0x9E, 0xB5, 0x96, 0x00, 0x20, 0x39, 0xE7, 
+0xEF, 0x5D, 0xEF, 0x5D, 0xCE, 0x59, 0xE7, 0x1C, 
+0xFF, 0xDF, 0x7B, 0xEF, 0x00, 0x00, 0x31, 0x86, 
+0x84, 0x10, 0x9C, 0xF3, 0x9C, 0xF3, 0x7B, 0xEF, 
+0x29, 0x65, 0x00, 0x00, 0x94, 0xB2, 0xF7, 0xBE, 
+0xEF, 0x7D, 0xFF, 0xDF, 0x94, 0xB2, 0x63, 0x2C, 
+0x63, 0x2C, 0x29, 0x45, 0x08, 0x41, 0x73, 0xAE, 
+0x73, 0xAE, 0x73, 0xAE, 0xAD, 0x55, 0xF7, 0xBE, 
+0xE7, 0x1C, 0xF7, 0x9E, 0xBD, 0xF7, 0x08, 0x41, 
+0x10, 0xA2, 0x63, 0x2C, 0x8C, 0x71, 0x9C, 0xD3, 
+0x8C, 0x51, 0x5A, 0xEB, 0x08, 0x61, 0x10, 0xA2, 
+0xD6, 0xBA, 0xE7, 0x1C, 0x94, 0x92, 0x42, 0x07, 
+0x21, 0x04, 0x21, 0x04, 0x21, 0x24, 0x29, 0x65, 
+0x62, 0xEB, 0xBD, 0xD6, 0xF7, 0x9D, 0xCE, 0x79, 
+0x10, 0x82, 0x08, 0x61, 0x63, 0x0C, 0x8C, 0x71, 
+0x9C, 0xD3, 0x94, 0xB2, 0x73, 0x8E, 0x21, 0x04, 
+0x00, 0x00, 0x9C, 0xF3, 0xF7, 0xBE, 0xEF, 0x5B, 
+0xFF, 0xDD, 0xE7, 0x3C, 0x00, 0x00, 0x42, 0x08, 
+0x00, 0x20, 0x52, 0x8A, 0x94, 0x92, 0x9C, 0xD3, 
+0xBD, 0xD7, 0xFF, 0xFF, 0xFF, 0xDE, 0xFF, 0xDF, 
+0x4A, 0x49, 0x00, 0x00, 0x4A, 0x49, 0x8C, 0x71, 
+0x9C, 0xF3, 0x9C, 0xF3, 0x84, 0x30, 0x5A, 0xEB, 
+0x08, 0x41, 0x00, 0x00, 0x5A, 0xCB, 0xDE, 0xFB, 
+0xFF, 0xDF, 0xE7, 0x3C, 0x43, 0x26, 0x64, 0x6C, 
+0x85, 0x30, 0x9D, 0xB3, 0x85, 0x10, 0x7C, 0x8D, 
+0xA5, 0xB2, 0x2A, 0x04, 0x53, 0x69, 0x2A, 0x24, 
+0x11, 0x62, 0x19, 0xC4, 0x2A, 0x05, 0x21, 0xC3, 
+0x21, 0xC3, 0x43, 0x07, 0x19, 0xA2, 0x3A, 0x85, 
+0x22, 0x03, 0x3A, 0xC6, 0x42, 0xE6, 0x32, 0x24, 
+0x9C, 0x4F, 0x94, 0x2E, 0x6A, 0xEA, 0xA4, 0xF1, 
+0xC5, 0xB3, 0xC5, 0xB4, 0xBD, 0x93, 0xBD, 0x52, 
+0xB5, 0x32, 0x94, 0x4F, 0x8C, 0x2E, 0x8C, 0x0D, 
+0x83, 0xED, 0x83, 0xCD, 0x7B, 0xAC, 0x73, 0x4B, 
+0x73, 0x4B, 0x73, 0x6B, 0xEF, 0x7D, 0x63, 0x2C, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xBE, 
+0xF7, 0x9E, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xCE, 0x59, 0xDE, 0xFB, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xF7, 0x9E, 0xA5, 0x14, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x24, 
+0xFF, 0xDE, 0xE7, 0x1B, 0xEF, 0x5C, 0xFF, 0xDE, 
+0x18, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xAD, 0x75, 0xEF, 0x7D, 
+0xB6, 0x55, 0xBE, 0xB5, 0xBE, 0x94, 0xA5, 0x91, 
+0x8C, 0x8D, 0xAD, 0x90, 0x7C, 0x88, 0x8D, 0x09, 
+0x8D, 0x08, 0x8C, 0xEA, 0x94, 0xEC, 0xAD, 0x4F, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x9D, 0xDE, 0xD9, 0xF7, 0x9D, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0xBE, 0xDE, 0xB9, 
+0xFF, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0x00, 0x00, 
+0xB5, 0x96, 0xFF, 0xDF, 0xF7, 0xBE, 0xF7, 0x9D, 
+0xF7, 0xBE, 0xFF, 0xDF, 0x84, 0x10, 0x00, 0x00, 
+0xAD, 0x55, 0xFF, 0xFF, 0xFF, 0xFF, 0xCE, 0x79, 
+0x00, 0x00, 0xA5, 0x14, 0xEF, 0x9D, 0xC6, 0x55, 
+0xCE, 0x76, 0xEF, 0x9D, 0xBD, 0xF7, 0x00, 0x00, 
+0x7B, 0xEF, 0x00, 0x20, 0xF7, 0x9E, 0xDF, 0x3B, 
+0xAE, 0x13, 0xCE, 0xD8, 0xFF, 0xDE, 0x63, 0x2C, 
+0x10, 0x82, 0xFF, 0xDF, 0xF7, 0xBE, 0xFF, 0xFF, 
+0x73, 0xAE, 0x00, 0x20, 0xBD, 0xD7, 0xF7, 0xBE, 
+0xEF, 0x7D, 0xEF, 0x5D, 0xEF, 0x7D, 0xF7, 0xBE, 
+0xE7, 0x3C, 0x21, 0x24, 0x29, 0x45, 0xF7, 0xBE, 
+0xE7, 0x1C, 0xE7, 0x1C, 0xFF, 0xDF, 0x08, 0x41, 
+0x00, 0x00, 0x4A, 0x69, 0xF7, 0xBE, 0xF7, 0x9E, 
+0xF7, 0x9E, 0xF7, 0xBE, 0xFF, 0xDF, 0xDE, 0xDB, 
+0x10, 0xA2, 0x39, 0xE7, 0xFF, 0xDF, 0xEF, 0x5D, 
+0xE7, 0x3C, 0xFF, 0xDE, 0x52, 0xAA, 0x08, 0x61, 
+0xDE, 0xDB, 0xFF, 0xDF, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xFF, 0xDE, 0xFF, 0xDF, 0xEF, 0x7D, 0x29, 0x45, 
+0x31, 0x86, 0xF7, 0xDE, 0xDF, 0x1A, 0xE7, 0x3B, 
+0xF7, 0xDE, 0x29, 0x45, 0x29, 0x45, 0xE7, 0x3C, 
+0xF7, 0xBE, 0xEF, 0x9D, 0xEF, 0x7D, 0xEF, 0x7D, 
+0xF7, 0x9E, 0xF7, 0xBE, 0x4A, 0x49, 0x08, 0x41, 
+0xE7, 0x1C, 0xE7, 0x3C, 0xD6, 0x9A, 0xF7, 0x9E, 
+0x6B, 0x4D, 0x00, 0x00, 0xB5, 0xB6, 0xF7, 0xBE, 
+0xEF, 0x7D, 0xEF, 0x5D, 0xEF, 0x7D, 0xF7, 0x9E, 
+0xEF, 0x7D, 0x31, 0x86, 0x10, 0x82, 0xEF, 0x7D, 
+0xEF, 0x5D, 0xEF, 0x7D, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xFF, 0xFF, 0xF7, 0x9E, 0xF7, 0xBE, 
+0xA5, 0x14, 0x00, 0x20, 0x4A, 0x69, 0xF7, 0x9E, 
+0xEF, 0x3C, 0xBD, 0xF7, 0xC6, 0x18, 0xEF, 0x7D, 
+0xBD, 0xF7, 0x00, 0x00, 0x73, 0xAE, 0xFF, 0xDF, 
+0xF7, 0xBE, 0xF7, 0x9E, 0xF7, 0x9E, 0xF7, 0xBE, 
+0xFF, 0xDF, 0x5A, 0xCB, 0x00, 0x20, 0xD6, 0xBA, 
+0xFF, 0xDF, 0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xFF, 0xFF, 0x6B, 0x6D, 0x10, 0x82, 0xFF, 0xFF, 
+0xFF, 0xDF, 0xF7, 0x9E, 0xF7, 0xBE, 0xF7, 0x9E, 
+0xEF, 0x5D, 0xF7, 0xBE, 0x29, 0x65, 0x18, 0xE3, 
+0xEF, 0x5D, 0xF7, 0xBE, 0xEF, 0x7D, 0xEF, 0x7D, 
+0xEF, 0x7D, 0xF7, 0xBE, 0xE7, 0x1C, 0x10, 0x82, 
+0x52, 0xAA, 0xEF, 0x7D, 0xAD, 0x75, 0x52, 0xCA, 
+0x41, 0xE7, 0x7B, 0xAD, 0xAD, 0x32, 0xCE, 0x15, 
+0xD6, 0x77, 0xEF, 0x5C, 0xFF, 0xDF, 0x29, 0x65, 
+0x21, 0x24, 0xE7, 0x3C, 0xFF, 0xDE, 0xF7, 0xDE, 
+0xF7, 0xBD, 0xF7, 0xBD, 0xFF, 0xDE, 0xF7, 0xBE, 
+0x4A, 0x69, 0x08, 0x41, 0xE7, 0x1C, 0xFF, 0xDE, 
+0xFF, 0xDE, 0xE7, 0x3C, 0x00, 0x00, 0x00, 0x20, 
+0xC6, 0x18, 0xFF, 0xDF, 0xFF, 0xBE, 0xFF, 0xBE, 
+0xFF, 0xBE, 0xFF, 0xBE, 0xFF, 0xFF, 0xB5, 0xB6, 
+0x00, 0x00, 0x9C, 0xD3, 0xFF, 0xFF, 0xF7, 0xBE, 
+0xF7, 0x9D, 0xF7, 0xBE, 0xF7, 0xBE, 0xFF, 0xDF, 
+0xDE, 0xDB, 0x08, 0x61, 0x73, 0x8E, 0xFF, 0xDF, 
+0xEF, 0x5C, 0xC6, 0x78, 0x6C, 0x6B, 0x8D, 0x50, 
+0x95, 0x72, 0xA6, 0x15, 0x95, 0x72, 0x53, 0x29, 
+0x53, 0x49, 0x29, 0xE4, 0x21, 0xC3, 0x19, 0xA2, 
+0x11, 0x42, 0x21, 0xC4, 0x32, 0x66, 0x21, 0xC4, 
+0x09, 0x01, 0x19, 0xA3, 0x11, 0x42, 0x21, 0xE4, 
+0x32, 0x85, 0x5B, 0xE9, 0x43, 0x46, 0x3A, 0xA5, 
+0x9C, 0x70, 0x8B, 0xED, 0x6B, 0x0A, 0xAD, 0x11, 
+0xBD, 0xB3, 0xCD, 0xF4, 0xCD, 0xF5, 0xCE, 0x15, 
+0xDE, 0x77, 0xD6, 0x36, 0xCD, 0xF5, 0xD6, 0x56, 
+0xD6, 0x77, 0xBD, 0xB4, 0xAD, 0x32, 0xAD, 0x11, 
+0xA4, 0xD0, 0x9C, 0x90, 0xF7, 0x9D, 0x6B, 0x4D, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0x9E, 
+0xEF, 0x7D, 0xFF, 0xDF, 0x00, 0x20, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xCE, 0x59, 0xDE, 0xFB, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xF7, 0x9E, 0xA5, 0x14, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x65, 
+0xFF, 0xDE, 0xEF, 0x3B, 0xEF, 0x3B, 0xFF, 0xDE, 
+0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xAD, 0x75, 0xEF, 0x7D, 
+0x9D, 0x72, 0xA5, 0xD1, 0xBE, 0x95, 0x6B, 0xCB, 
+0xA5, 0x30, 0xAD, 0x90, 0x63, 0xC6, 0xA5, 0xCC, 
+0x84, 0xE8, 0x7C, 0xA8, 0x84, 0x89, 0x84, 0x2A, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xEF, 0x3C, 0xC5, 0xF6, 0xEF, 0x5C, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0x9D, 0xDE, 0xB9, 
+0xF7, 0x9D, 0x9C, 0xF3, 0x00, 0x00, 0x52, 0xAA, 
+0xFF, 0xDF, 0xE7, 0x3B, 0xC6, 0x76, 0xBE, 0x14, 
+0xDE, 0xF9, 0xF7, 0x9D, 0xFF, 0xDF, 0x21, 0x04, 
+0x4A, 0x49, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xDF, 
+0x10, 0xA2, 0x63, 0x0C, 0xFF, 0xDE, 0xEF, 0x5B, 
+0xE7, 0x19, 0xF7, 0xBE, 0x7B, 0xCF, 0x21, 0x24, 
+0xE7, 0x1C, 0x00, 0x00, 0xBD, 0xD7, 0xEF, 0x9D, 
+0xD6, 0xB7, 0xDF, 0x1A, 0xFF, 0xDF, 0x21, 0x04, 
+0x52, 0xAA, 0xFF, 0xFF, 0xFF, 0xDE, 0xF7, 0xBE, 
+0x08, 0x61, 0x6B, 0x4D, 0xFF, 0xDF, 0xE7, 0x3C, 
+0xBE, 0x17, 0xBE, 0x16, 0xBE, 0x36, 0xD6, 0x99, 
+0xF7, 0x9E, 0xAD, 0x55, 0x00, 0x00, 0xBD, 0xF7, 
+0xF7, 0x9E, 0xE7, 0x3C, 0xFF, 0xDF, 0x08, 0x41, 
+0x00, 0x20, 0xE7, 0x1C, 0xEF, 0x5D, 0xC6, 0x18, 
+0xA5, 0x14, 0xAD, 0x35, 0xCE, 0x79, 0xF7, 0xBE, 
+0x8C, 0x71, 0x00, 0x00, 0xDE, 0xDB, 0xF7, 0xBE, 
+0xF7, 0x9E, 0xFF, 0xDF, 0x18, 0xE3, 0x63, 0x0C, 
+0xFF, 0xFF, 0xF7, 0x7D, 0xDE, 0xDB, 0xB5, 0xB6, 
+0xC6, 0x18, 0xD6, 0xBA, 0xF7, 0xBE, 0x7B, 0xEF, 
+0x00, 0x20, 0xF7, 0xDE, 0xEF, 0x7C, 0xF7, 0xBE, 
+0xC6, 0x18, 0x00, 0x00, 0xAD, 0x55, 0xF7, 0xDE, 
+0xE7, 0x7B, 0xD6, 0xF8, 0xBE, 0x55, 0xBD, 0xF5, 
+0xC6, 0x17, 0xEF, 0x5D, 0xD6, 0xBA, 0x00, 0x00, 
+0x94, 0x92, 0xFF, 0xDF, 0xEF, 0x7D, 0xF7, 0x9E, 
+0x08, 0x61, 0x5A, 0xCB, 0xF7, 0xBE, 0xD6, 0x9A, 
+0xA5, 0x34, 0x94, 0xB2, 0x9C, 0xF3, 0xC6, 0x17, 
+0xEF, 0x7D, 0xBD, 0xD7, 0x00, 0x00, 0xB5, 0x96, 
+0xF7, 0xBE, 0xF7, 0x9E, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xFF, 0xFF, 0xFF, 0xFF, 0x9C, 0xD3, 
+0x00, 0x00, 0x5A, 0xEB, 0xF7, 0xBE, 0xE7, 0x3C, 
+0xAD, 0x75, 0xA4, 0xF3, 0xCE, 0x79, 0xF7, 0x9E, 
+0x52, 0x8A, 0x21, 0x04, 0xFF, 0xDF, 0xF7, 0x9E, 
+0xDE, 0xDB, 0xDE, 0xFB, 0xD6, 0x9A, 0xEF, 0x5D, 
+0xF7, 0xBE, 0xEF, 0x5D, 0x00, 0x20, 0x7B, 0xCF, 
+0xFF, 0xBF, 0xDE, 0xDB, 0xCE, 0x79, 0xCE, 0x79, 
+0xF7, 0xBE, 0x6B, 0x6D, 0x10, 0x82, 0xFF, 0xDF, 
+0xE7, 0x1C, 0xB5, 0xB6, 0xAD, 0x75, 0xBD, 0xD7, 
+0xDE, 0xFB, 0xEF, 0x7D, 0x00, 0x00, 0x84, 0x30, 
+0xF7, 0xBE, 0xD6, 0x9A, 0xB5, 0x96, 0xA5, 0x34, 
+0xAD, 0x75, 0xD6, 0x9A, 0xF7, 0xBE, 0x52, 0xAA, 
+0x29, 0x45, 0xF7, 0x9E, 0xC6, 0x17, 0x9C, 0xD1, 
+0xCE, 0x35, 0xEF, 0x18, 0xEF, 0x18, 0xEF, 0x18, 
+0xDE, 0xB8, 0xF7, 0x9D, 0xCE, 0x58, 0x00, 0x00, 
+0xA5, 0x34, 0xFF, 0xDE, 0xDE, 0xF9, 0xDF, 0x17, 
+0xDF, 0x16, 0xDF, 0x36, 0xEF, 0x99, 0xF7, 0xDD, 
+0xDE, 0xFB, 0x00, 0x00, 0x8C, 0x71, 0xFF, 0xFF, 
+0xFF, 0xFE, 0xE7, 0x3C, 0x00, 0x00, 0x5A, 0xCB, 
+0xFF, 0xFF, 0xF7, 0x9C, 0xE6, 0xF9, 0xE6, 0xB8, 
+0xDE, 0x98, 0xE6, 0xFA, 0xFF, 0xDE, 0x7B, 0xEF, 
+0x00, 0x00, 0xEF, 0x5D, 0xF7, 0x9D, 0xD6, 0x78, 
+0xD6, 0x37, 0xE6, 0xB8, 0xDE, 0x98, 0xEF, 0x5C, 
+0xFF, 0xDF, 0x4A, 0x49, 0x39, 0xC7, 0xF7, 0xBE, 
+0xCE, 0xB8, 0x8D, 0x10, 0x85, 0x4F, 0x95, 0x92, 
+0xA5, 0xD4, 0x9D, 0xB3, 0x4B, 0x29, 0x19, 0xA3, 
+0x2A, 0x04, 0x21, 0xE3, 0x21, 0xE3, 0x11, 0x82, 
+0x11, 0x62, 0x19, 0x83, 0x32, 0x66, 0x19, 0x83, 
+0x19, 0x62, 0x11, 0x21, 0x19, 0xC3, 0x2A, 0x65, 
+0x43, 0x27, 0x4B, 0x87, 0x4B, 0xA7, 0x5B, 0xE9, 
+0x9C, 0x6F, 0x83, 0xAC, 0x73, 0x4B, 0xB5, 0x32, 
+0xB5, 0x52, 0xAD, 0x10, 0xAD, 0x31, 0xBD, 0x93, 
+0xCD, 0xF4, 0xD6, 0x36, 0xCD, 0xF4, 0xDE, 0x76, 
+0xD6, 0x56, 0xBD, 0x93, 0xB5, 0x31, 0xB5, 0x32, 
+0xE6, 0xD8, 0xDE, 0x77, 0xF7, 0xBE, 0x6B, 0x4D, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0x9E, 
+0xEF, 0x7D, 0xFF, 0xDF, 0x00, 0x20, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xCE, 0x59, 0xDE, 0xFB, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xF7, 0x9E, 0xA5, 0x14, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x65, 
+0xFF, 0xDF, 0xF7, 0x9C, 0xF7, 0x9C, 0xFF, 0xDF, 
+0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xAD, 0x75, 0xEF, 0x7D, 
+0xA5, 0xB3, 0x8C, 0xEE, 0x9D, 0x51, 0x84, 0x6E, 
+0x94, 0xAE, 0x9D, 0x0E, 0x74, 0x27, 0x74, 0x67, 
+0x6C, 0x26, 0x8C, 0xCA, 0xAD, 0x4E, 0xAD, 0x0F, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xEF, 0x5C, 0xCE, 0x16, 0xEF, 0x3C, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0x9D, 0xDE, 0xB9, 
+0xF7, 0x9D, 0x9C, 0xF3, 0x00, 0x00, 0xA5, 0x14, 
+0xF7, 0x9D, 0xC6, 0x36, 0xA5, 0x0F, 0x9C, 0x8E, 
+0xBD, 0xB4, 0xD6, 0x79, 0xF7, 0x9E, 0x63, 0x2C, 
+0x10, 0xA2, 0xFF, 0xFF, 0xFF, 0xDE, 0xFF, 0xDF, 
+0x52, 0xAA, 0x18, 0xE3, 0xFF, 0xDE, 0xE7, 0x1B, 
+0xDE, 0xFB, 0xF7, 0xBE, 0x39, 0xC7, 0x63, 0x2C, 
+0xFF, 0xFF, 0x21, 0x04, 0x7B, 0xCF, 0xF7, 0xBE, 
+0xDE, 0xFA, 0xEF, 0x7D, 0xDE, 0xFB, 0x00, 0x00, 
+0x9C, 0xD3, 0xFF, 0xFF, 0xFF, 0xFF, 0xCE, 0x59, 
+0x00, 0x00, 0xB5, 0xB6, 0xFF, 0xDF, 0xE7, 0x3B, 
+0xD6, 0xF9, 0xD6, 0xF9, 0xD6, 0xD9, 0xDF, 0x1A, 
+0xF7, 0xBE, 0xE7, 0x3C, 0x00, 0x00, 0x8C, 0x71, 
+0xFF, 0xDF, 0xEF, 0x5D, 0xFF, 0xDF, 0x08, 0x41, 
+0x31, 0xA6, 0xF7, 0xBE, 0xD6, 0xBA, 0xB5, 0x96, 
+0xAD, 0x55, 0x9C, 0xF3, 0xB5, 0x96, 0xEF, 0x5D, 
+0xD6, 0x9A, 0x00, 0x00, 0xA5, 0x34, 0xF7, 0xBE, 
+0xE7, 0x3C, 0xF7, 0xBE, 0x10, 0xA2, 0x6B, 0x4D, 
+0xFF, 0xDF, 0xE7, 0x1C, 0xCE, 0x59, 0xBD, 0xD6, 
+0xB5, 0xB6, 0xCE, 0x79, 0xF7, 0xBE, 0xEF, 0x7D, 
+0xE7, 0x1C, 0xF7, 0xDE, 0xEF, 0x9D, 0xFF, 0xDF, 
+0x94, 0x92, 0x00, 0x00, 0xEF, 0x5C, 0xEF, 0x9C, 
+0xCE, 0xF6, 0x95, 0x6F, 0xAD, 0xF1, 0xBE, 0x74, 
+0xBD, 0xD5, 0xDE, 0xFB, 0xFF, 0xDF, 0x18, 0xC3, 
+0x63, 0x0C, 0xFF, 0xFF, 0xFF, 0xDF, 0xCE, 0x79, 
+0x00, 0x00, 0xA5, 0x14, 0xEF, 0x5D, 0xA5, 0x14, 
+0x63, 0x0B, 0x52, 0x89, 0x52, 0x89, 0x8C, 0x51, 
+0xDE, 0xFB, 0xEF, 0x5D, 0x00, 0x00, 0x94, 0x92, 
+0xFF, 0xDF, 0xF7, 0x9E, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xFF, 0xFF, 0x94, 0x92, 0x00, 0x00, 
+0x6B, 0x6D, 0xF7, 0xBE, 0xDE, 0xFB, 0xAD, 0x55, 
+0x73, 0x6D, 0x83, 0xEF, 0xCE, 0x79, 0xF7, 0xBE, 
+0x10, 0xA2, 0x6B, 0x4D, 0xFF, 0xDF, 0xEF, 0x7D, 
+0xE7, 0x3C, 0xEF, 0x5D, 0xE7, 0x1C, 0xEF, 0x5D, 
+0xEF, 0x7E, 0xFF, 0xFF, 0x29, 0x65, 0x42, 0x28, 
+0xF7, 0xBE, 0xBD, 0xF8, 0x8C, 0x51, 0xBD, 0xD7, 
+0xF7, 0x9E, 0x6B, 0x6D, 0x10, 0x82, 0xF7, 0xBE, 
+0xCE, 0x79, 0x7B, 0xCF, 0x52, 0x8A, 0x7B, 0xEF, 
+0xD6, 0xBA, 0xEF, 0x5D, 0x00, 0x00, 0x8C, 0x71, 
+0xF7, 0xBE, 0xDE, 0xDB, 0xC6, 0x18, 0xB5, 0x96, 
+0xAD, 0x75, 0xCE, 0x79, 0xF7, 0xBE, 0xEF, 0x5D, 
+0xE7, 0x3C, 0xF7, 0x9E, 0xD6, 0xBA, 0xBD, 0xF4, 
+0xAD, 0x72, 0xAD, 0x51, 0xB5, 0x91, 0xBD, 0xB2, 
+0xCE, 0x36, 0xF7, 0x9D, 0x9C, 0xD3, 0x00, 0x00, 
+0xE7, 0x1C, 0xEF, 0x5C, 0xC6, 0x54, 0xA5, 0x6E, 
+0xB6, 0x0F, 0xBE, 0x4E, 0xC6, 0x91, 0xE7, 0x3A, 
+0xFF, 0xDF, 0x21, 0x04, 0x5A, 0xEB, 0xFF, 0xFF, 
+0xFF, 0xDF, 0xE7, 0x3C, 0x00, 0x00, 0x8C, 0x51, 
+0xFF, 0xDE, 0xEF, 0x5A, 0xCE, 0x34, 0xE6, 0xB6, 
+0xD6, 0x35, 0xE6, 0xB9, 0xFF, 0xBE, 0x84, 0x10, 
+0x00, 0x20, 0xFF, 0xFF, 0xF7, 0x7D, 0xD6, 0x58, 
+0xDE, 0x77, 0xE6, 0xB8, 0xE6, 0xB8, 0xF7, 0x5C, 
+0xFF, 0xDF, 0x42, 0x28, 0x31, 0xA6, 0xF7, 0xBE, 
+0xC6, 0x77, 0x74, 0x8C, 0x53, 0xE8, 0x85, 0x4F, 
+0x95, 0x71, 0x53, 0x8A, 0x21, 0xE3, 0x19, 0xA3, 
+0x22, 0x04, 0x21, 0xE3, 0x21, 0xE3, 0x19, 0xA2, 
+0x11, 0x62, 0x11, 0x62, 0x21, 0xC3, 0x19, 0xA3, 
+0x21, 0xC3, 0x11, 0x41, 0x4B, 0x28, 0x5C, 0x0A, 
+0x5C, 0x0A, 0x4B, 0xA8, 0x5C, 0x09, 0x6C, 0x8C, 
+0xA4, 0xB0, 0x83, 0xAC, 0x73, 0x6B, 0xBD, 0x93, 
+0xAC, 0xF0, 0xA4, 0xF0, 0xA5, 0x10, 0xAD, 0x31, 
+0xB5, 0x52, 0xBD, 0xB3, 0xB5, 0x72, 0xCE, 0x15, 
+0xC5, 0xD4, 0xC5, 0xD4, 0xB5, 0x52, 0xB5, 0x52, 
+0xD6, 0x76, 0xDE, 0x96, 0xFF, 0xBE, 0x6B, 0x4D, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xBE, 
+0xF7, 0x9D, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xCE, 0x59, 0xDE, 0xFB, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xF7, 0x9E, 0x9C, 0xF3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x04, 
+0xFF, 0xFF, 0xF7, 0x9D, 0xF7, 0x9D, 0xFF, 0xFF, 
+0x10, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xAD, 0x75, 0xEF, 0x9D, 
+0xBE, 0x15, 0xA5, 0x51, 0x9D, 0x10, 0x94, 0xCF, 
+0x73, 0xEB, 0x73, 0xE9, 0x8C, 0x8B, 0x94, 0xCC, 
+0x94, 0xAC, 0xA5, 0x0E, 0xC5, 0xD2, 0xCD, 0xF3, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x9D, 0xDE, 0x98, 0xEF, 0x7C, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xFF, 0xBE, 0xE6, 0xFA, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0xBD, 0xF7, 
+0xF7, 0x9D, 0xCE, 0x15, 0xC5, 0xB3, 0xD6, 0x36, 
+0xAD, 0x13, 0xAD, 0x54, 0xF7, 0x9D, 0x84, 0x10, 
+0x00, 0x00, 0xFF, 0xDF, 0xF7, 0xBE, 0xFF, 0xDF, 
+0x9C, 0xF3, 0x00, 0x00, 0xDE, 0xFB, 0xF7, 0xBE, 
+0xF7, 0x9E, 0xEF, 0x7D, 0x00, 0x20, 0xAD, 0x55, 
+0xFF, 0xFF, 0x63, 0x2C, 0x39, 0xC7, 0xFF, 0xDF, 
+0xF7, 0x7D, 0xFF, 0xDF, 0x9C, 0xF3, 0x00, 0x00, 
+0xDE, 0xFB, 0xFF, 0xDF, 0xFF, 0xFF, 0xB5, 0x96, 
+0x00, 0x00, 0xD6, 0xBA, 0xFF, 0xFF, 0xFF, 0xDF, 
+0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 0xFF, 0xDE, 
+0xFF, 0xFF, 0xFF, 0xDF, 0x00, 0x00, 0x7B, 0xCF, 
+0xFF, 0xDF, 0xF7, 0x9D, 0xFF, 0xDF, 0x08, 0x41, 
+0x52, 0x8A, 0xF7, 0x9E, 0xBD, 0xD7, 0x84, 0x30, 
+0x8C, 0x51, 0x6B, 0x6D, 0x94, 0xB2, 0xE7, 0x3C, 
+0xEF, 0x5D, 0x00, 0x00, 0x94, 0xB2, 0xF7, 0xBE, 
+0xDE, 0xFB, 0xF7, 0xBE, 0x4A, 0x69, 0x18, 0xC3, 
+0xD6, 0x9A, 0xFF, 0xDF, 0xFF, 0xDF, 0xF7, 0xBE, 
+0xF7, 0xBE, 0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xEF, 0x9D, 0xE7, 0x7C, 0xFF, 0xDE, 
+0x84, 0x10, 0x00, 0x00, 0xFF, 0xDF, 0xE7, 0x7B, 
+0xA5, 0xD1, 0x74, 0x4A, 0x7C, 0x2B, 0x84, 0x6E, 
+0x94, 0xB1, 0xCE, 0x79, 0xFF, 0xDE, 0x29, 0x65, 
+0x52, 0x8A, 0xFF, 0xFF, 0xFF, 0xFF, 0xAD, 0x55, 
+0x00, 0x00, 0xCE, 0x59, 0xE7, 0x1C, 0x84, 0x10, 
+0x42, 0x27, 0x3A, 0x06, 0x42, 0x27, 0x7B, 0xCE, 
+0xD6, 0x99, 0xF7, 0x9E, 0xFF, 0xDF, 0xFF, 0xDF, 
+0xF7, 0xBE, 0xF7, 0x9E, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0x8C, 0x51, 0x00, 0x00, 0x8C, 0x51, 
+0xFF, 0xFF, 0xE7, 0x5D, 0xC6, 0x18, 0x6B, 0x4D, 
+0x5A, 0x8A, 0x7B, 0xCF, 0xD6, 0xBA, 0xF7, 0x9E, 
+0x00, 0x00, 0x8C, 0x51, 0xFF, 0xFF, 0xFF, 0xDF, 
+0xFF, 0xDF, 0xFF, 0xDF, 0xF7, 0xBF, 0xF7, 0xBF, 
+0xFF, 0xDF, 0xFF, 0xFF, 0x42, 0x28, 0x31, 0x86, 
+0xF7, 0xBE, 0xCE, 0x59, 0xA5, 0x14, 0xB5, 0x96, 
+0xEF, 0x7D, 0x6B, 0x6D, 0x10, 0x82, 0xF7, 0xBE, 
+0xCE, 0x59, 0x6B, 0x6D, 0x31, 0x86, 0x6B, 0x4D, 
+0xC6, 0x38, 0xF7, 0xBE, 0x21, 0x24, 0x29, 0x65, 
+0xDE, 0xFB, 0xF7, 0xBE, 0xF7, 0x9E, 0xEF, 0x7D, 
+0xEF, 0x7D, 0xF7, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xDF, 0xF7, 0x9D, 0xDE, 0xD9, 0xAD, 0x73, 
+0xA5, 0x31, 0xAD, 0x92, 0xB5, 0x91, 0xB5, 0x92, 
+0xC6, 0x36, 0xF7, 0x9E, 0x84, 0x30, 0x00, 0x00, 
+0xF7, 0xBE, 0xEF, 0x5B, 0xBE, 0x32, 0x9D, 0x6A, 
+0xA5, 0xAA, 0xAE, 0x0A, 0xB6, 0x2D, 0xD6, 0xF8, 
+0xFF, 0xDE, 0x31, 0xA6, 0x4A, 0x49, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xE7, 0x3C, 0x00, 0x00, 0x9C, 0xD3, 
+0xF7, 0xBE, 0xDE, 0xF8, 0xA4, 0xF0, 0xD6, 0x76, 
+0xDE, 0xB7, 0xD6, 0x78, 0xF7, 0x9E, 0xAD, 0x55, 
+0x00, 0x00, 0xC6, 0x38, 0xFF, 0xDF, 0xF7, 0x9D, 
+0xF7, 0x9D, 0xF7, 0x7D, 0xF7, 0x9D, 0xFF, 0xDF, 
+0xF7, 0x9E, 0x10, 0xA2, 0x63, 0x0C, 0xF7, 0x9D, 
+0xB5, 0xF5, 0x6C, 0x6B, 0x3B, 0x44, 0x64, 0x2A, 
+0x5B, 0xEA, 0x32, 0x85, 0x21, 0xE3, 0x11, 0x82, 
+0x22, 0x03, 0x21, 0xE3, 0x21, 0xE3, 0x19, 0xA3, 
+0x19, 0x83, 0x19, 0xC3, 0x2A, 0x04, 0x2A, 0x04, 
+0x19, 0xA3, 0x21, 0xC3, 0x64, 0x0A, 0x6C, 0x8B, 
+0x53, 0xC8, 0x53, 0xC8, 0x74, 0xCD, 0x7D, 0x0E, 
+0xAC, 0xF1, 0x83, 0xAC, 0x73, 0x4B, 0xC5, 0xD4, 
+0xB5, 0x52, 0xAD, 0x10, 0xA4, 0xD0, 0xAD, 0x11, 
+0xB5, 0x72, 0xAD, 0x31, 0xAD, 0x31, 0xC5, 0xF4, 
+0xBD, 0xD4, 0xBD, 0x93, 0xC6, 0x15, 0xC5, 0xF4, 
+0xD6, 0x76, 0xD6, 0x75, 0xFF, 0xBE, 0x63, 0x2C, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xDE, 
+0xFF, 0xBE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xC6, 0x38, 0xDE, 0xDB, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xF7, 0x9E, 0x7B, 0xEF, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
+0xFF, 0xFF, 0xFF, 0xBD, 0xFF, 0xBD, 0xFF, 0xFF, 
+0x08, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x94, 0xB2, 0xFF, 0xDE, 
+0xCE, 0x76, 0xC6, 0x14, 0xC5, 0xF4, 0xAD, 0x72, 
+0x8C, 0x8E, 0xBD, 0xF3, 0xE7, 0x17, 0xD6, 0x75, 
+0xA4, 0xCE, 0xAC, 0xEF, 0xBD, 0xB2, 0xCD, 0xF3, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x9D, 0xDE, 0x98, 0xEF, 0x7D, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0x9E, 0xDE, 0xB9, 
+0xF7, 0x9D, 0x9C, 0xF3, 0x00, 0x00, 0xD6, 0x9A, 
+0xEF, 0x5C, 0xCE, 0x35, 0xDE, 0x77, 0xAD, 0x12, 
+0x5A, 0xCA, 0xC5, 0xF6, 0xF7, 0x9D, 0x8C, 0x71, 
+0x00, 0x00, 0xEF, 0x7D, 0xF7, 0x9D, 0xF7, 0x9E, 
+0xE7, 0x1C, 0x00, 0x00, 0x9C, 0xF3, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xB5, 0x96, 0x00, 0x00, 0xEF, 0x5D, 
+0xFF, 0xFF, 0xAD, 0x55, 0x00, 0x20, 0xF7, 0x9E, 
+0xFF, 0xFF, 0xFF, 0xFF, 0x5A, 0xEB, 0x21, 0x24, 
+0xFF, 0xDF, 0xF7, 0x7D, 0xFF, 0xDF, 0xA5, 0x14, 
+0x00, 0x00, 0x39, 0xE7, 0x42, 0x28, 0x42, 0x28, 
+0x42, 0x28, 0x42, 0x28, 0x42, 0x28, 0x42, 0x28, 
+0x42, 0x28, 0x42, 0x28, 0x00, 0x20, 0x6B, 0x4D, 
+0xFF, 0xFF, 0xF7, 0xBE, 0xFF, 0xDF, 0x08, 0x41, 
+0x63, 0x2C, 0xEF, 0x7D, 0xAD, 0x75, 0x63, 0x0C, 
+0x52, 0xAA, 0x63, 0x0C, 0x94, 0xB2, 0xE7, 0x1C, 
+0xF7, 0xBE, 0x00, 0x00, 0x84, 0x10, 0xF7, 0x9E, 
+0xD6, 0xDA, 0xF7, 0xBE, 0xD6, 0xBA, 0x21, 0x04, 
+0x00, 0x00, 0x18, 0xC3, 0x42, 0x08, 0x63, 0x2C, 
+0x84, 0x30, 0xA5, 0x34, 0xD6, 0x9A, 0xFF, 0xDF, 
+0xFF, 0xDF, 0xE7, 0x5C, 0xDF, 0x19, 0xF7, 0xBE, 
+0x73, 0xAE, 0x08, 0x41, 0xFF, 0xFF, 0xDF, 0x3A, 
+0x95, 0x0F, 0x95, 0x2E, 0xA5, 0x6F, 0x9D, 0x0F, 
+0x9D, 0x31, 0xCE, 0x99, 0xFF, 0xDE, 0x42, 0x08, 
+0x39, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0x9C, 0xF3, 
+0x00, 0x00, 0xDE, 0xDB, 0xDE, 0xDB, 0x7B, 0xEF, 
+0x39, 0xE6, 0x31, 0x85, 0x31, 0xA5, 0x6B, 0x4C, 
+0xBD, 0xD6, 0xDE, 0xDB, 0xE7, 0x1B, 0xE7, 0x1C, 
+0xE7, 0x1C, 0xEF, 0x7D, 0xF7, 0x9E, 0x00, 0x00, 
+0x21, 0x04, 0x00, 0x00, 0x8C, 0x51, 0xFF, 0xFF, 
+0xF7, 0xBE, 0xCE, 0x59, 0xCE, 0x7A, 0x7B, 0xAF, 
+0x73, 0xAF, 0xB5, 0xB6, 0xEF, 0x5D, 0xEF, 0x5D, 
+0x00, 0x00, 0x29, 0x45, 0x42, 0x28, 0x42, 0x28, 
+0x42, 0x28, 0x42, 0x28, 0x42, 0x28, 0x42, 0x28, 
+0x42, 0x28, 0x42, 0x28, 0x10, 0xA2, 0x21, 0x04, 
+0xF7, 0xBE, 0xC6, 0x38, 0x7B, 0xEF, 0xA5, 0x35, 
+0xEF, 0x7D, 0x6B, 0x6D, 0x10, 0x82, 0xF7, 0xBE, 
+0xCE, 0x59, 0x6B, 0x6D, 0x29, 0x65, 0x52, 0x8A, 
+0xA5, 0x34, 0xEF, 0x5D, 0xBD, 0xF7, 0x10, 0xA2, 
+0x00, 0x00, 0x21, 0x04, 0x42, 0x28, 0x6B, 0x4D, 
+0x8C, 0x51, 0xAD, 0x75, 0xD6, 0xBA, 0xFF, 0xFF, 
+0xFF, 0xDF, 0xE7, 0x1B, 0xB5, 0x94, 0x9C, 0xD0, 
+0xB5, 0x92, 0xBD, 0xB2, 0xAD, 0x2F, 0xC6, 0x33, 
+0xC6, 0x36, 0xF7, 0x9D, 0x7B, 0xCF, 0x00, 0x20, 
+0xFF, 0xDF, 0xEF, 0x7B, 0xC6, 0x93, 0xA5, 0xAC, 
+0xA5, 0xAB, 0xB6, 0x4B, 0xAE, 0x2B, 0xD6, 0xF7, 
+0xFF, 0xFE, 0x42, 0x28, 0x39, 0xC7, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xE7, 0x3C, 0x00, 0x00, 0x9C, 0xD3, 
+0xF7, 0xBE, 0xD6, 0x98, 0xB5, 0x73, 0xA5, 0x11, 
+0xEF, 0x79, 0xE7, 0x3A, 0xF7, 0xBE, 0xF7, 0x9E, 
+0x10, 0xA2, 0x18, 0xC3, 0x84, 0x30, 0xC6, 0x18, 
+0xD6, 0x9A, 0xD6, 0xBA, 0xC6, 0x38, 0x9C, 0xD3, 
+0x29, 0x65, 0x08, 0x41, 0xCE, 0x79, 0xE7, 0x3C, 
+0x95, 0x11, 0x53, 0xA7, 0x3B, 0x44, 0x3B, 0x05, 
+0x3A, 0xC6, 0x22, 0x24, 0x19, 0xC2, 0x11, 0x61, 
+0x19, 0xC3, 0x22, 0x03, 0x21, 0xE3, 0x21, 0xE3, 
+0x21, 0xE3, 0x22, 0x04, 0x2A, 0x25, 0x21, 0xE4, 
+0x11, 0x42, 0x21, 0xA3, 0x53, 0x68, 0x3A, 0xC5, 
+0x3B, 0x06, 0x74, 0xCD, 0x85, 0x4F, 0x85, 0x0F, 
+0x8B, 0xEE, 0x73, 0x2A, 0x73, 0x4B, 0xA4, 0xF0, 
+0xAD, 0x10, 0xB5, 0x31, 0xB5, 0x31, 0xAC, 0xF0, 
+0xB5, 0x32, 0xAD, 0x11, 0xB5, 0x73, 0xB5, 0x72, 
+0xA4, 0xF0, 0x83, 0xCC, 0xBD, 0xB4, 0xE6, 0xD8, 
+0xDE, 0xB7, 0xDE, 0x96, 0xF7, 0xBE, 0x94, 0xB2, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0x82, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xDF, 0xFF, 0xFF, 0x10, 0x82, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xD6, 0xBA, 0xEF, 0x7D, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x61, 
+0xFF, 0xFF, 0xB5, 0xB6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x28, 
+0xFF, 0xFF, 0xF7, 0x9D, 0xFF, 0xBE, 0xFF, 0xFF, 
+0x39, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xCE, 0x79, 0xF7, 0xBD, 
+0xD6, 0xD7, 0xD6, 0xB6, 0xBD, 0xF3, 0xA5, 0x31, 
+0x84, 0x4E, 0xCE, 0x55, 0xE6, 0xD7, 0xDE, 0xB6, 
+0xA4, 0xEF, 0xAD, 0x0F, 0xCE, 0x34, 0xD6, 0x55, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x9D, 0xE6, 0xF9, 0xF7, 0x9D, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0xBE, 0xE6, 0xDA, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0xDE, 0xDB, 
+0xEF, 0x5C, 0xC6, 0x14, 0xA5, 0x11, 0x5A, 0xC9, 
+0x94, 0x6F, 0xD6, 0x77, 0xEF, 0x7D, 0x94, 0xB2, 
+0x00, 0x00, 0xEF, 0x5D, 0xEF, 0x5D, 0xE7, 0x3C, 
+0xFF, 0xDE, 0x21, 0x24, 0x5A, 0xEB, 0xFF, 0xFF, 
+0xFF, 0xFF, 0x73, 0x8E, 0x29, 0x65, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xEF, 0x5D, 0x00, 0x00, 0xB5, 0xB6, 
+0xFF, 0xFF, 0xFF, 0xFF, 0x18, 0xC3, 0x6B, 0x4D, 
+0xFF, 0xDE, 0xEF, 0x3C, 0xF7, 0xBE, 0x9C, 0xD3, 
+0x00, 0x00, 0x5A, 0xEB, 0x63, 0x2C, 0x63, 0x2C, 
+0x63, 0x2C, 0x63, 0x2C, 0x63, 0x2C, 0x63, 0x2C, 
+0x63, 0x2C, 0x63, 0x2C, 0x63, 0x2C, 0xA5, 0x34, 
+0xFF, 0xFF, 0xF7, 0xBE, 0xFF, 0xFF, 0x08, 0x41, 
+0x73, 0x8E, 0xF7, 0x9D, 0xAD, 0x55, 0x5A, 0xCA, 
+0x39, 0xE7, 0x52, 0xAA, 0x8C, 0x71, 0xDE, 0xDB, 
+0xFF, 0xDF, 0x00, 0x00, 0x84, 0x10, 0xF7, 0x9E, 
+0xD6, 0xBA, 0xEF, 0x7C, 0xFF, 0xDF, 0xFF, 0xDF, 
+0xB5, 0x96, 0x7B, 0xEF, 0x5A, 0xCB, 0x31, 0xA6, 
+0x10, 0x82, 0x00, 0x00, 0x00, 0x00, 0x21, 0x04, 
+0xB5, 0xB6, 0xF7, 0x9E, 0xE7, 0x3C, 0xF7, 0xDE, 
+0x73, 0x8E, 0x10, 0x82, 0xFF, 0xDF, 0xD6, 0xD9, 
+0xA5, 0xB1, 0x95, 0x6B, 0xAD, 0xED, 0xA5, 0xAE, 
+0x95, 0x2E, 0xCE, 0x98, 0xFF, 0xDE, 0x42, 0x08, 
+0x39, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0x9C, 0xD3, 
+0x00, 0x00, 0xDE, 0xFB, 0xDE, 0xDB, 0x7B, 0xEF, 
+0x31, 0xA5, 0x29, 0x64, 0x29, 0x64, 0x63, 0x0B, 
+0xAD, 0x75, 0xD6, 0x9A, 0xDE, 0xDB, 0xDE, 0xFB, 
+0xE7, 0x1C, 0xEF, 0x7D, 0xF7, 0x9E, 0x00, 0x00, 
+0x73, 0xAE, 0x29, 0x65, 0x18, 0xE3, 0xDE, 0xDB, 
+0xFF, 0xDF, 0xDE, 0xDB, 0xC5, 0xF8, 0xCE, 0x59, 
+0xD6, 0x9A, 0xCE, 0x59, 0xEF, 0x5D, 0xDE, 0xFB, 
+0x00, 0x00, 0x39, 0xE7, 0x63, 0x2C, 0x63, 0x2C, 
+0x63, 0x2C, 0x63, 0x2C, 0x63, 0x2C, 0x63, 0x2C, 
+0x63, 0x2C, 0x63, 0x2C, 0x63, 0x2C, 0x7B, 0xCF, 
+0xF7, 0xBE, 0xC6, 0x38, 0x84, 0x30, 0xB5, 0x76, 
+0xEF, 0x7D, 0x6B, 0x6D, 0x10, 0x82, 0xF7, 0xBE, 
+0xCE, 0x59, 0x6B, 0x4D, 0x29, 0x45, 0x4A, 0x69, 
+0x9C, 0xD3, 0xDE, 0xDB, 0xFF, 0xDF, 0xF7, 0x9E, 
+0xAD, 0x55, 0x7B, 0xCF, 0x52, 0xAA, 0x31, 0x86, 
+0x08, 0x61, 0x00, 0x00, 0x00, 0x00, 0x31, 0x86, 
+0xCE, 0x79, 0xF7, 0xBE, 0xD6, 0x98, 0xB5, 0x94, 
+0xAD, 0x12, 0x8C, 0x2E, 0x9C, 0xAF, 0xC6, 0x13, 
+0xC6, 0x16, 0xF7, 0x7D, 0x73, 0xAE, 0x08, 0x41, 
+0xFF, 0xDF, 0xDE, 0xFA, 0xC6, 0x95, 0x95, 0x0E, 
+0x8C, 0xEC, 0xAE, 0x2B, 0xAE, 0x0B, 0xD7, 0x17, 
+0xFF, 0xFE, 0x42, 0x28, 0x39, 0xC7, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xE7, 0x3C, 0x00, 0x00, 0x9C, 0xD3, 
+0xF7, 0x9E, 0xC6, 0x36, 0xBD, 0xB3, 0xDE, 0xD7, 
+0xEF, 0x59, 0xEF, 0x5C, 0xE7, 0x3C, 0x21, 0x04, 
+0x4A, 0x49, 0x5A, 0xCB, 0x08, 0x41, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x39, 0xC7, 0xC6, 0x18, 0xEF, 0x9D, 0xBE, 0x37, 
+0x6C, 0x0C, 0x64, 0x0A, 0x64, 0x09, 0x74, 0x8C, 
+0x74, 0x6D, 0x19, 0xE3, 0x11, 0x82, 0x09, 0x01, 
+0x19, 0xA2, 0x22, 0x03, 0x21, 0xE3, 0x19, 0xC2, 
+0x11, 0x82, 0x21, 0xC3, 0x19, 0xC3, 0x19, 0x83, 
+0x09, 0x02, 0x11, 0x42, 0x42, 0xE7, 0x21, 0xE3, 
+0x3A, 0xC6, 0x74, 0xAC, 0x85, 0x2F, 0x8D, 0x70, 
+0x5A, 0x89, 0x6B, 0x0A, 0x73, 0x4B, 0x7B, 0x8B, 
+0x7B, 0x8A, 0x83, 0xAB, 0x83, 0xAB, 0x83, 0xAB, 
+0x83, 0xCC, 0x94, 0x4E, 0x83, 0xCC, 0x83, 0xCC, 
+0x8B, 0xEC, 0x9C, 0x8F, 0xBD, 0x93, 0xCE, 0x15, 
+0xCD, 0xF4, 0xC5, 0xD3, 0xF7, 0x9D, 0xDE, 0xFB, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x52, 0x8A, 0xFF, 0xFF, 0xFF, 0xBE, 
+0xFF, 0xBE, 0xFF, 0xFF, 0x52, 0xAA, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x04, 
+0xFF, 0xFF, 0xFF, 0xFF, 0x39, 0xE7, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xCB, 
+0xFF, 0xFF, 0xF7, 0x9E, 0x18, 0xC3, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xF3, 
+0xFF, 0xDE, 0xF7, 0x7C, 0xEF, 0x5B, 0xF7, 0xBE, 
+0x94, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x29, 0x45, 0xFF, 0xDE, 0xEF, 0x7C, 
+0xD6, 0xF7, 0xC6, 0x34, 0x5B, 0x08, 0x84, 0x2D, 
+0x63, 0x49, 0xD6, 0xB6, 0xDE, 0xB6, 0xD6, 0x75, 
+0x94, 0x8C, 0x7C, 0x4A, 0x84, 0xAC, 0x9D, 0x2F, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xEF, 0x7D, 0xDE, 0xD9, 0xF7, 0x9D, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0xBE, 0xE7, 0x3B, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0xD6, 0x9A, 
+0xE7, 0x3C, 0xBE, 0x15, 0x5A, 0xE9, 0x7C, 0x0C, 
+0xB5, 0x91, 0xD6, 0x57, 0xF7, 0x9D, 0x84, 0x30, 
+0x00, 0x00, 0xF7, 0x9E, 0xE7, 0x3C, 0xDE, 0xFA, 
+0xF7, 0xBE, 0x6B, 0x6D, 0x18, 0xC3, 0xFF, 0xFF, 
+0xFF, 0xFF, 0x29, 0x65, 0x73, 0x8E, 0xFF, 0xFF, 
+0xF7, 0xBE, 0xFF, 0xFF, 0x29, 0x65, 0x73, 0x8E, 
+0xFF, 0xFF, 0xD6, 0xBA, 0x00, 0x00, 0xAD, 0x75, 
+0xF7, 0x9D, 0xDE, 0xD9, 0xF7, 0x9D, 0xA5, 0x14, 
+0x00, 0x00, 0xDE, 0xFB, 0xFF, 0xFF, 0xF7, 0xBE, 
+0xF7, 0x9E, 0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xF7, 0xDE, 0xFF, 0xFF, 0x08, 0x41, 
+0x63, 0x2C, 0xF7, 0xBE, 0xC6, 0x17, 0x63, 0x2C, 
+0x39, 0xE6, 0x42, 0x07, 0x84, 0x0F, 0xDE, 0xDB, 
+0xEF, 0x7D, 0x00, 0x00, 0x8C, 0x51, 0xFF, 0xDF, 
+0xEF, 0x7D, 0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xDE, 
+0xFF, 0xDF, 0xEF, 0x5D, 0xB5, 0x96, 0x31, 0x86, 
+0x08, 0x61, 0xE7, 0x3C, 0xF7, 0xBE, 0xFF, 0xFF, 
+0x7B, 0xEF, 0x00, 0x00, 0xF7, 0xDE, 0xDF, 0x1A, 
+0xAD, 0xF0, 0x7C, 0xE7, 0x8D, 0x48, 0x85, 0x08, 
+0x8D, 0x4D, 0xCE, 0xB8, 0xF7, 0xDE, 0x31, 0xA6, 
+0x4A, 0x49, 0xFF, 0xFF, 0xFF, 0xFF, 0xA5, 0x34, 
+0x00, 0x00, 0xCE, 0x59, 0xE7, 0x1B, 0x7C, 0x0F, 
+0x39, 0xE6, 0x31, 0xA5, 0x31, 0xC5, 0x6B, 0x6D, 
+0xC6, 0x18, 0xEF, 0x7D, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xF7, 0xBE, 0xF7, 0x9E, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xEF, 0x5D, 0x29, 0x65, 0x18, 0xC3, 
+0xD6, 0x9A, 0xF7, 0xBE, 0xDE, 0xFB, 0xCE, 0x59, 
+0xC6, 0x38, 0xB5, 0x96, 0xE7, 0x1C, 0xE7, 0x3C, 
+0x00, 0x00, 0x94, 0x92, 0xFF, 0xFF, 0xF7, 0xBE, 
+0xF7, 0x9E, 0xF7, 0x9E, 0xF7, 0x9E, 0xF7, 0x9E, 
+0xF7, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xF7, 0xBE, 0xCE, 0x59, 0xA5, 0x14, 0xCE, 0x59, 
+0xF7, 0x9E, 0x6B, 0x6D, 0x10, 0x82, 0xF7, 0xBE, 
+0xCE, 0x59, 0x6B, 0x4D, 0x31, 0xA6, 0x7B, 0xEF, 
+0xD6, 0xBA, 0xF7, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xF7, 0xBE, 0xF7, 0xBE, 0xFF, 0xDE, 
+0xFF, 0xFF, 0xE7, 0x1C, 0xA5, 0x34, 0x18, 0xE3, 
+0x21, 0x04, 0xFF, 0xDE, 0xE7, 0x1B, 0xB5, 0x94, 
+0xAD, 0x12, 0x6B, 0x4B, 0xA4, 0xF1, 0xCE, 0x14, 
+0xBD, 0xB5, 0xEF, 0x7D, 0x84, 0x10, 0x00, 0x00, 
+0xF7, 0xBE, 0xDE, 0xDA, 0xAD, 0x93, 0x9D, 0x90, 
+0xA5, 0xAF, 0xAE, 0x2C, 0xA5, 0xEC, 0xD7, 0x17, 
+0xF7, 0xDE, 0x39, 0xC7, 0x42, 0x28, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xE7, 0x3C, 0x00, 0x00, 0x9C, 0xD3, 
+0xF7, 0x9D, 0xC6, 0x36, 0xC6, 0x53, 0xCE, 0x53, 
+0xE7, 0x39, 0xF7, 0xBE, 0x94, 0x92, 0x08, 0x41, 
+0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDF, 0xE7, 0x3C, 
+0xD6, 0xBA, 0xCE, 0x79, 0xDE, 0xDB, 0xF7, 0x9E, 
+0xFF, 0xFF, 0xFF, 0xDF, 0xD6, 0xDA, 0x8C, 0xB1, 
+0x6B, 0xCB, 0xAD, 0xB2, 0x74, 0x2B, 0x8D, 0x30, 
+0x95, 0x51, 0x19, 0xA3, 0x19, 0x82, 0x21, 0xC4, 
+0x2A, 0x44, 0x22, 0x23, 0x21, 0xE3, 0x19, 0xC2, 
+0x11, 0x62, 0x11, 0x42, 0x11, 0x42, 0x19, 0xA4, 
+0x09, 0x02, 0x11, 0x43, 0x19, 0xA3, 0x2A, 0x24, 
+0x4B, 0x68, 0x64, 0x4B, 0x43, 0x47, 0x7C, 0xEE, 
+0x62, 0xCA, 0x7B, 0xAC, 0x8C, 0x2E, 0x73, 0x6B, 
+0x7B, 0x6A, 0x83, 0x8B, 0x9C, 0x4E, 0xA4, 0xAF, 
+0xA4, 0xB0, 0xA4, 0xCF, 0x9C, 0x6E, 0x94, 0x2D, 
+0x94, 0x2D, 0x8C, 0x0C, 0x94, 0x0C, 0x8B, 0xEC, 
+0x8B, 0xEC, 0x8B, 0xEC, 0xDE, 0xDA, 0xFF, 0xDE, 
+0x52, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x20, 0xC6, 0x38, 0xF7, 0x9E, 0xD6, 0x99, 
+0xD6, 0x58, 0xEF, 0x7D, 0xE7, 0x1B, 0x29, 0x45, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0xA2, 0xC6, 0x38, 
+0xFF, 0xFF, 0xFF, 0xDF, 0xDE, 0xFB, 0x31, 0x86, 
+0x00, 0x00, 0x00, 0x00, 0x42, 0x08, 0xEF, 0x5D, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xC6, 0x38, 0x21, 0x04, 
+0x00, 0x00, 0x00, 0x20, 0x7B, 0xCF, 0xFF, 0xDE, 
+0xF7, 0x9C, 0xDE, 0xD7, 0xCE, 0x96, 0xF7, 0xBD, 
+0xFF, 0xFF, 0x73, 0xAE, 0x08, 0x41, 0x00, 0x00, 
+0x39, 0xC7, 0xD6, 0xBA, 0xEF, 0x5C, 0xAD, 0x95, 
+0xB6, 0x13, 0x95, 0x0E, 0x63, 0x68, 0x9D, 0x0F, 
+0x73, 0xAB, 0xBE, 0x13, 0x9C, 0xEE, 0x7C, 0x6B, 
+0x74, 0x49, 0x7C, 0xCB, 0x95, 0x4D, 0x95, 0x0C, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x7D, 0xD6, 0x98, 0xEF, 0x7D, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0xBE, 0xE7, 0x1B, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0xB5, 0x96, 
+0xF7, 0xBE, 0xAD, 0x74, 0x5B, 0x2A, 0x7C, 0x4A, 
+0x8C, 0xCD, 0xCE, 0x77, 0xF7, 0xBE, 0x73, 0xAE, 
+0x10, 0xA2, 0xFF, 0xDF, 0xE7, 0x1B, 0xCE, 0x77, 
+0xF7, 0x9D, 0xB5, 0x95, 0x00, 0x00, 0xDE, 0xDB, 
+0xEF, 0x7D, 0x00, 0x00, 0xB5, 0x96, 0xFF, 0xBE, 
+0xEF, 0x5C, 0xFF, 0xDE, 0x73, 0x8E, 0x31, 0x86, 
+0xFF, 0xFF, 0x94, 0xB2, 0x00, 0x00, 0xEF, 0x5D, 
+0xE7, 0x1B, 0xC6, 0x36, 0xEF, 0x7D, 0xBD, 0xD7, 
+0x00, 0x00, 0xCE, 0x79, 0xF7, 0xBE, 0xD6, 0x9A, 
+0xE7, 0x3B, 0xE7, 0x3B, 0xC6, 0x38, 0xCE, 0x79, 
+0xEF, 0x7D, 0xFF, 0xFF, 0xDE, 0xFB, 0xEF, 0x7D, 
+0xFF, 0xFF, 0xF7, 0xBE, 0xFF, 0xFF, 0x08, 0x41, 
+0x42, 0x28, 0xFF, 0xFF, 0xDF, 0x1B, 0xB5, 0xF5, 
+0x5A, 0xEA, 0x4A, 0x48, 0x94, 0x91, 0xE7, 0x1C, 
+0xDE, 0xFB, 0x00, 0x00, 0xA5, 0x34, 0xFF, 0xDF, 
+0xF7, 0xBE, 0xEF, 0x7D, 0xBD, 0xD7, 0xEF, 0x5D, 
+0xFF, 0xDE, 0xD6, 0xF9, 0xBE, 0x36, 0xCE, 0x98, 
+0xDF, 0x5A, 0xE7, 0x3B, 0xF7, 0xBE, 0xC6, 0x38, 
+0x00, 0x00, 0xAD, 0x55, 0xFF, 0xFF, 0xFF, 0xFF, 
+0x8C, 0x71, 0x00, 0x00, 0xEF, 0x7D, 0xDF, 0x3B, 
+0xA5, 0xB0, 0xB6, 0x6E, 0xB6, 0x4D, 0xA5, 0xEC, 
+0x95, 0x8F, 0xD6, 0xF9, 0xFF, 0xDE, 0x21, 0x24, 
+0x52, 0xAA, 0xFF, 0xFF, 0xFF, 0xFF, 0xBD, 0xF7, 
+0x00, 0x00, 0xB5, 0xB6, 0xEF, 0x5D, 0x8C, 0x71, 
+0x3A, 0x07, 0x31, 0xA5, 0x39, 0xE6, 0x73, 0x8D, 
+0xCE, 0x79, 0xF7, 0xBE, 0x31, 0xA6, 0x7B, 0xCF, 
+0xFF, 0xDF, 0xF7, 0x9E, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xFF, 0xFF, 0xEF, 0x7D, 0x31, 0x86, 
+0x10, 0x82, 0xCE, 0x59, 0xF7, 0xBE, 0xE7, 0x1C, 
+0xD6, 0x7A, 0xCE, 0x39, 0xDE, 0xDB, 0xF7, 0xBE, 
+0x00, 0x20, 0x84, 0x10, 0xF7, 0xBE, 0xD6, 0xBA, 
+0xB5, 0xB6, 0xAD, 0x75, 0xAD, 0x75, 0xB5, 0xB6, 
+0xDE, 0xDB, 0xF7, 0xBE, 0xEF, 0x5D, 0xE7, 0x1C, 
+0xF7, 0xBE, 0xC6, 0x38, 0xB5, 0xB6, 0xC6, 0x38, 
+0xF7, 0x9E, 0x6B, 0x6D, 0x10, 0x82, 0xF7, 0xBE, 
+0xCE, 0x59, 0x6B, 0x4D, 0x31, 0x86, 0x84, 0x30, 
+0xE7, 0x3C, 0xE7, 0x3C, 0xBD, 0xD7, 0xF7, 0x9E, 
+0xF7, 0x9E, 0xDF, 0x1B, 0xCE, 0xB8, 0xD6, 0xD9, 
+0xE7, 0x5B, 0xF7, 0x9D, 0xFF, 0xDF, 0xA5, 0x14, 
+0x00, 0x00, 0xCE, 0x79, 0xEF, 0x7D, 0xC6, 0x17, 
+0xBD, 0xB5, 0x94, 0x91, 0x94, 0x70, 0xB5, 0x73, 
+0xC5, 0xF7, 0xF7, 0x9E, 0x94, 0x92, 0x00, 0x00, 
+0xE7, 0x3C, 0xE7, 0x1B, 0xA5, 0x53, 0x9D, 0x50, 
+0x63, 0xE9, 0x95, 0x8B, 0xA5, 0xCD, 0xDF, 0x18, 
+0xFF, 0xDE, 0x29, 0x65, 0x52, 0x8A, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xE7, 0x3C, 0x00, 0x00, 0x9C, 0xD3, 
+0xF7, 0x9D, 0xD6, 0x96, 0xBE, 0x4F, 0xAD, 0x8E, 
+0xE6, 0xF8, 0xF7, 0xBE, 0x94, 0xB2, 0x00, 0x00, 
+0xA5, 0x14, 0xEF, 0x7D, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x1C, 0xAD, 0x55, 
+0x8C, 0x70, 0xA5, 0x31, 0x8C, 0x8E, 0x95, 0x10, 
+0x74, 0x4E, 0x53, 0x4B, 0x32, 0x26, 0x32, 0x46, 
+0x21, 0xE3, 0x22, 0x03, 0x21, 0xE3, 0x19, 0xC3, 
+0x19, 0xC3, 0x21, 0xC3, 0x11, 0x62, 0x19, 0xA3, 
+0x21, 0xE4, 0x2A, 0x25, 0x32, 0x86, 0x3A, 0xA6, 
+0x4B, 0x69, 0x6C, 0x6C, 0x3A, 0xC5, 0x64, 0x4B, 
+0x5A, 0x89, 0x39, 0xC6, 0x5A, 0xA9, 0x52, 0x68, 
+0x42, 0x06, 0x5A, 0xA8, 0x9C, 0x8F, 0xBD, 0xB4, 
+0xC5, 0x94, 0xA4, 0xD0, 0x7B, 0x8B, 0x8C, 0x0C, 
+0x9C, 0x4D, 0x83, 0xAB, 0x83, 0x8B, 0x94, 0x0D, 
+0xAC, 0xD0, 0xA4, 0x8F, 0xC5, 0xD5, 0xEF, 0x3C, 
+0xF7, 0xBE, 0x8C, 0x51, 0x42, 0x08, 0x5A, 0xCB, 
+0xCE, 0x59, 0xFF, 0xFF, 0xEF, 0x7D, 0xD6, 0x98, 
+0xCE, 0x16, 0xDE, 0xB9, 0xEF, 0x7D, 0xF7, 0x9E, 
+0xBD, 0xD7, 0xB5, 0x96, 0xEF, 0x7D, 0xFF, 0xFF, 
+0xF7, 0x9E, 0xF7, 0x9D, 0xFF, 0xDF, 0xFF, 0xDF, 
+0xD6, 0xBA, 0xDE, 0xFB, 0xFF, 0xFF, 0xFF, 0xDF, 
+0xF7, 0x9D, 0xFF, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xE7, 0x1B, 0xF7, 0x9D, 0xFF, 0xDE, 0xEF, 0x7C, 
+0xE6, 0xF8, 0xD6, 0x96, 0xE7, 0x39, 0xF7, 0xBD, 
+0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xDF, 0xEF, 0x5D, 
+0xF7, 0xBE, 0xE7, 0x5C, 0xCE, 0x78, 0xA5, 0x52, 
+0x84, 0x6C, 0x6B, 0xC8, 0x95, 0x0D, 0xAD, 0xB1, 
+0x7C, 0x0C, 0xAD, 0xD1, 0x84, 0x6A, 0x8C, 0xED, 
+0x8D, 0x2D, 0x7C, 0xAB, 0x84, 0xAB, 0x8C, 0xEC, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0x7D, 0xD6, 0x99, 0xF7, 0x7D, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0xBE, 0xE7, 0x1B, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0x73, 0xAE, 
+0xF7, 0xBE, 0xC6, 0x38, 0xA5, 0x73, 0x95, 0x30, 
+0xA5, 0x92, 0xD6, 0xD9, 0xFF, 0xDE, 0x39, 0xE7, 
+0x42, 0x08, 0xFF, 0xDE, 0xDE, 0xD9, 0xC6, 0x15, 
+0xE7, 0x5C, 0xEF, 0x7D, 0x00, 0x20, 0x9C, 0xD3, 
+0xAD, 0x55, 0x00, 0x00, 0xEF, 0x5D, 0xEF, 0x5C, 
+0xD6, 0x98, 0xF7, 0x9D, 0xB5, 0x96, 0x00, 0x00, 
+0xEF, 0x5D, 0x52, 0xAA, 0x31, 0xA6, 0xF7, 0xBE, 
+0xCE, 0x98, 0xA5, 0x73, 0xDF, 0x1B, 0xE7, 0x3C, 
+0x00, 0x00, 0x9C, 0xD3, 0xFF, 0xDE, 0xDE, 0xFA, 
+0xF7, 0xDC, 0xD6, 0xB9, 0x9C, 0xF3, 0xB5, 0xB7, 
+0xE7, 0x3D, 0xF7, 0x9E, 0x00, 0x00, 0x8C, 0x51, 
+0xFF, 0xDF, 0xEF, 0x7D, 0xFF, 0xDF, 0x08, 0x41, 
+0x08, 0x61, 0xF7, 0xBE, 0xEF, 0x5D, 0xCE, 0x98, 
+0xC6, 0x77, 0xA5, 0x53, 0xDF, 0x1A, 0xEF, 0x7D, 
+0xAD, 0x55, 0x00, 0x00, 0xCE, 0x79, 0xF7, 0xBE, 
+0xF7, 0xBE, 0xD6, 0x9A, 0x00, 0x00, 0xAD, 0x55, 
+0xF7, 0xDE, 0xBE, 0x56, 0x9D, 0x71, 0x9D, 0x92, 
+0xBE, 0x75, 0xBE, 0x36, 0xEF, 0x5D, 0xDF, 0x1B, 
+0x00, 0x00, 0x9C, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xB5, 0x96, 0x00, 0x00, 0xC6, 0x18, 0xF7, 0xBD, 
+0xDF, 0x37, 0xC6, 0x73, 0xC6, 0xD3, 0xC6, 0xD3, 
+0xC6, 0xB5, 0xE7, 0x5C, 0xEF, 0x7D, 0x00, 0x00, 
+0x7B, 0xEF, 0xFF, 0xFF, 0xF7, 0xBE, 0xEF, 0x5C, 
+0x00, 0x00, 0x8C, 0x51, 0xF7, 0xBE, 0xC6, 0x38, 
+0x84, 0x30, 0x73, 0xCE, 0x7B, 0xEF, 0xA5, 0x13, 
+0xE7, 0x1C, 0xF7, 0x9E, 0x00, 0x20, 0x84, 0x30, 
+0xFF, 0xDF, 0xF7, 0x9E, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xFF, 0xFF, 0xFF, 0xDF, 0xEF, 0x7D, 
+0x31, 0xA6, 0x10, 0x82, 0xC6, 0x38, 0xF7, 0xBF, 
+0xE7, 0x1C, 0xD6, 0x7A, 0xDE, 0xFC, 0xF7, 0xBE, 
+0x31, 0x86, 0x52, 0x8A, 0xF7, 0xBE, 0xD6, 0x9A, 
+0x9C, 0xF3, 0x84, 0x30, 0x8C, 0x51, 0x9C, 0xF3, 
+0xD6, 0x9A, 0xF7, 0xBE, 0x39, 0xE7, 0x42, 0x08, 
+0xF7, 0x9E, 0xCE, 0x59, 0xAD, 0x75, 0xAD, 0x75, 
+0xEF, 0x7D, 0x6B, 0x6D, 0x10, 0x82, 0xFF, 0xDF, 
+0xD6, 0xBA, 0x94, 0x92, 0x73, 0xAE, 0x9C, 0xF3, 
+0xEF, 0x5D, 0xAD, 0x75, 0x00, 0x00, 0xCE, 0x79, 
+0xEF, 0x7D, 0xB5, 0xB6, 0x9C, 0xD3, 0xA5, 0x33, 
+0xB5, 0xD6, 0xCE, 0x58, 0xFF, 0xDE, 0xBD, 0xF7, 
+0x00, 0x00, 0xC6, 0x18, 0xF7, 0x9E, 0xDE, 0xFB, 
+0xE7, 0x1B, 0xDE, 0xFB, 0xDE, 0xDB, 0xDE, 0xFB, 
+0xE6, 0xFB, 0xF7, 0xBE, 0xB5, 0xB6, 0x00, 0x00, 
+0xBD, 0xF7, 0xF7, 0x9D, 0xD6, 0x98, 0xBD, 0xF4, 
+0xA5, 0x92, 0xB6, 0x52, 0xC6, 0x94, 0xE7, 0x7B, 
+0xF7, 0x9E, 0x00, 0x20, 0x7B, 0xCF, 0xFF, 0xFF, 
+0xFF, 0xDE, 0xE7, 0x3C, 0x00, 0x00, 0x9C, 0xD3, 
+0xF7, 0xBD, 0xD6, 0xD5, 0xAD, 0xEB, 0xAD, 0x8D, 
+0xD6, 0x97, 0xF7, 0xBE, 0xEF, 0x7D, 0x31, 0x86, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82, 
+0x21, 0x04, 0x31, 0x86, 0x42, 0x08, 0x52, 0xAA, 
+0x73, 0xAE, 0xA5, 0x34, 0xF7, 0xBE, 0xE7, 0x3C, 
+0xCE, 0x78, 0xBD, 0xF4, 0x8C, 0xAE, 0x7C, 0x2C, 
+0x8D, 0x11, 0x95, 0x32, 0x32, 0x67, 0x2A, 0x26, 
+0x22, 0x04, 0x22, 0x23, 0x19, 0xC2, 0x19, 0xA2, 
+0x11, 0x62, 0x21, 0xE4, 0x19, 0xA3, 0x19, 0xA3, 
+0x32, 0x45, 0x42, 0xE8, 0x4B, 0x29, 0x4B, 0x49, 
+0x4B, 0x69, 0x53, 0x88, 0x2A, 0x44, 0x64, 0x2B, 
+0x73, 0x6C, 0x62, 0xEB, 0x83, 0xEE, 0x73, 0x6C, 
+0x6B, 0x0A, 0x7B, 0xCD, 0x9C, 0xD1, 0xAD, 0x32, 
+0x9C, 0x90, 0x6B, 0x4B, 0x6B, 0x0A, 0x83, 0xEC, 
+0x9C, 0x4D, 0x94, 0x4F, 0xAD, 0x33, 0x94, 0x2F, 
+0x83, 0xCD, 0x83, 0xED, 0x94, 0x4F, 0xBD, 0xB5, 
+0xDE, 0xFB, 0xF7, 0x7D, 0xFF, 0xDE, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xF7, 0x9D, 
+0xE7, 0x3C, 0xD6, 0x99, 0xD6, 0x78, 0xE6, 0xFB, 
+0xF7, 0x7D, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 
+0xFF, 0xBE, 0xFF, 0xBE, 0xFF, 0xDE, 0xFF, 0xFF, 
+0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+0xFF, 0xBE, 0xEF, 0x5C, 0xDE, 0xD9, 0xD6, 0x77, 
+0xD6, 0x98, 0xE7, 0x3B, 0xF7, 0x9E, 0xFF, 0xDE, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xEF, 0x5D, 
+0xD6, 0xB9, 0xBE, 0x15, 0xAD, 0x32, 0x7B, 0xAB, 
+0x8C, 0x6C, 0xA5, 0x6F, 0x9D, 0x4F, 0x84, 0x6C, 
+0x84, 0x6E, 0x8C, 0xCD, 0x53, 0x05, 0x95, 0x2F, 
+0xAE, 0x32, 0x95, 0x2E, 0xAD, 0x90, 0xCE, 0x74, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0xBD, 0xEF, 0x1A, 0xF7, 0x7D, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0xBE, 0xE7, 0x1B, 
+0xF7, 0xBE, 0x9C, 0xF3, 0x00, 0x00, 0x10, 0x82, 
+0xE7, 0x3C, 0xF7, 0xBE, 0xEF, 0x7C, 0xE7, 0x3B, 
+0xE7, 0x5C, 0xF7, 0xBE, 0xC6, 0x38, 0x00, 0x00, 
+0x8C, 0x71, 0xF7, 0x9E, 0xCE, 0x57, 0xBD, 0xF4, 
+0xDE, 0xD9, 0xFF, 0xDE, 0x39, 0xE7, 0x52, 0xAA, 
+0x6B, 0x4D, 0x31, 0xA6, 0xFF, 0xDE, 0xE6, 0xFA, 
+0xD6, 0x56, 0xE7, 0x3B, 0xEF, 0x7D, 0x00, 0x20, 
+0xAD, 0x55, 0x10, 0xA2, 0x7B, 0xEF, 0xF7, 0xBE, 
+0xBE, 0x76, 0xA5, 0xB2, 0xCE, 0xB9, 0xF7, 0xDE, 
+0x42, 0x08, 0x29, 0x45, 0xF7, 0x9E, 0xFF, 0xDE, 
+0xF7, 0xDE, 0xEF, 0x5C, 0xDE, 0xFB, 0xEF, 0x5D, 
+0xFF, 0xDF, 0x9C, 0xD3, 0x00, 0x00, 0xCE, 0x59, 
+0xF7, 0x9E, 0xEF, 0x5D, 0xFF, 0xDF, 0x08, 0x41, 
+0x00, 0x00, 0x8C, 0x71, 0xFF, 0xDF, 0xF7, 0xBD, 
+0xEF, 0x9D, 0xEF, 0x9D, 0xF7, 0xBE, 0xF7, 0xBE, 
+0x39, 0xC7, 0x21, 0x04, 0xF7, 0xBE, 0xDF, 0x1B, 
+0xEF, 0x7C, 0xEF, 0x7D, 0x00, 0x20, 0x73, 0x8E, 
+0xFF, 0xFF, 0xEF, 0x7D, 0xDF, 0x3B, 0xDF, 0x3B, 
+0xE7, 0x5B, 0xEF, 0x5C, 0xF7, 0xDE, 0xAD, 0x55, 
+0x00, 0x00, 0xC6, 0x18, 0xF7, 0xDE, 0xF7, 0xBD, 
+0xEF, 0x7D, 0x08, 0x61, 0x52, 0x8A, 0xFF, 0xDF, 
+0xF7, 0xBD, 0xE7, 0x1B, 0xDF, 0x1A, 0xE7, 0x3B, 
+0xEF, 0x9D, 0xFF, 0xDF, 0x84, 0x30, 0x00, 0x00, 
+0xCE, 0x59, 0xF7, 0xBE, 0xE7, 0x5B, 0xFF, 0xDE, 
+0x42, 0x08, 0x18, 0xE3, 0xF7, 0x9E, 0xFF, 0xBE, 
+0xE7, 0x5C, 0xDE, 0xDA, 0xDE, 0xDB, 0xE7, 0x3C, 
+0xF7, 0xBE, 0x9C, 0xD3, 0x00, 0x00, 0xCE, 0x59, 
+0xF7, 0x9E, 0xEF, 0x7D, 0xF7, 0x9E, 0x00, 0x00, 
+0x8C, 0x51, 0xF7, 0xBE, 0xE7, 0x1C, 0xF7, 0x9E, 
+0xEF, 0x7D, 0x31, 0xA6, 0x08, 0x41, 0xBD, 0xD7, 
+0xF7, 0xBE, 0xE7, 0x1C, 0xE7, 0x1C, 0xFF, 0xDF, 
+0x8C, 0x51, 0x00, 0x20, 0xCE, 0x79, 0xF7, 0x9E, 
+0xE7, 0x1C, 0xD6, 0xBA, 0xD6, 0xBA, 0xE7, 0x1C, 
+0xF7, 0x9E, 0xDE, 0xFB, 0x00, 0x20, 0x84, 0x30, 
+0xEF, 0x7D, 0xCE, 0x59, 0xB5, 0xB7, 0xB5, 0x96, 
+0xEF, 0x7D, 0x7B, 0xEF, 0x00, 0x20, 0xF7, 0xBE, 
+0xF7, 0x9E, 0xDE, 0xFB, 0xDE, 0xDB, 0xE7, 0x1B, 
+0xF7, 0xBE, 0xD6, 0xBA, 0x00, 0x00, 0x94, 0xB2, 
+0xFF, 0xDF, 0xE7, 0x3C, 0xDE, 0xDB, 0xDE, 0xFB, 
+0xE7, 0x3C, 0xEF, 0x5D, 0xFF, 0xDF, 0x84, 0x30, 
+0x00, 0x00, 0xE7, 0x3C, 0xF7, 0x9D, 0xEF, 0x5D, 
+0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xEF, 0x5D, 0xEF, 0x7D, 0xEF, 0x7D, 0x10, 0x82, 
+0x4A, 0x69, 0xFF, 0xDF, 0xF7, 0x9D, 0xE7, 0x3B, 
+0xE7, 0x3B, 0xE7, 0x3B, 0xEF, 0x9D, 0xFF, 0xDF, 
+0x8C, 0x51, 0x00, 0x00, 0xC6, 0x18, 0xFF, 0xDE, 
+0xF7, 0xBE, 0xE7, 0x3C, 0x00, 0x00, 0x9C, 0xD3, 
+0xF7, 0xBD, 0xBE, 0x32, 0xAD, 0xCB, 0xAD, 0x6D, 
+0xCE, 0x35, 0xF7, 0x9D, 0xFF, 0xDF, 0x6B, 0x4D, 
+0x18, 0xC3, 0x8C, 0x71, 0xA5, 0x14, 0x94, 0x92, 
+0x84, 0x10, 0x73, 0x8E, 0x63, 0x0C, 0x4A, 0x69, 
+0x21, 0x24, 0x00, 0x00, 0x21, 0x24, 0xDE, 0xDB, 
+0xF7, 0x9D, 0xB5, 0xD4, 0x42, 0xC6, 0x3A, 0xC6, 
+0x2A, 0x25, 0x32, 0x66, 0x3A, 0xA7, 0x32, 0x45, 
+0x22, 0x03, 0x19, 0xE2, 0x21, 0xE3, 0x19, 0x82, 
+0x11, 0x42, 0x2A, 0x24, 0x2A, 0x24, 0x21, 0xE4, 
+0x3A, 0x86, 0x53, 0x6A, 0x53, 0xAA, 0x64, 0x2C, 
+0x5B, 0xEA, 0x43, 0x27, 0x3A, 0xC5, 0x3A, 0xE6, 
+0xB5, 0xB6, 0xAD, 0x34, 0xB5, 0x53, 0xAD, 0x12, 
+0xA4, 0xF1, 0xA4, 0xD1, 0xAD, 0x52, 0xC5, 0xD5, 
+0xB5, 0x73, 0x94, 0x6F, 0x9C, 0x90, 0xA4, 0xD0, 
+0x94, 0x2D, 0xBD, 0xB4, 0xD6, 0x77, 0xD6, 0x57, 
+0xCE, 0x16, 0xC5, 0xD5, 0xC5, 0xB5, 0xBD, 0x94, 
+0xC5, 0xD6, 0xD6, 0x78, 0xEF, 0x3C, 0xFF, 0xDF, 
+0xF7, 0x9E, 0x84, 0x30, 0x5A, 0xEB, 0x8C, 0x51, 
+0xF7, 0x9E, 0xEF, 0x5D, 0xCE, 0x37, 0xC5, 0xB5, 
+0xDE, 0x99, 0xF7, 0xBE, 0xFF, 0xFF, 0x9C, 0xD3, 
+0x52, 0x8A, 0x63, 0x0C, 0xCE, 0x59, 0xFF, 0xDF, 
+0xF7, 0x9D, 0xF7, 0x9D, 0xFF, 0xDF, 0xBD, 0xF7, 
+0x4A, 0x69, 0x39, 0xC7, 0x84, 0x10, 0xF7, 0xBE, 
+0xFF, 0xBE, 0xEF, 0x1A, 0xD6, 0x56, 0xD6, 0x97, 
+0xEF, 0x7C, 0xF7, 0xBE, 0x7B, 0xEF, 0x29, 0x65, 
+0x31, 0xA6, 0x9C, 0xD3, 0xFF, 0xDF, 0xEF, 0x5C, 
+0xBD, 0xF5, 0x7C, 0x0C, 0x4A, 0x46, 0x39, 0xC4, 
+0x52, 0xC6, 0x95, 0x0E, 0xAD, 0xB0, 0x63, 0x48, 
+0x84, 0x4D, 0x8C, 0xCD, 0x3A, 0x83, 0x53, 0x47, 
+0x8C, 0xCD, 0xB5, 0xD2, 0xB5, 0x91, 0xB5, 0x50, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xEF, 0x5C, 0xC6, 0x17, 0xEF, 0x3C, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0x9E, 0xDE, 0xB9, 
+0xF7, 0x9E, 0x9C, 0xF3, 0x00, 0x00, 0x21, 0x04, 
+0x21, 0x24, 0xAD, 0x55, 0xE7, 0x3C, 0xEF, 0x7D, 
+0xDE, 0xDB, 0x94, 0x92, 0x10, 0x82, 0x21, 0x04, 
+0xEF, 0x7D, 0xE7, 0x3C, 0xC6, 0x15, 0xBD, 0xD3, 
+0xD6, 0xB8, 0xF7, 0xBE, 0x84, 0x10, 0x10, 0xA2, 
+0x21, 0x24, 0x7B, 0xCF, 0xF7, 0x9E, 0xC6, 0x36, 
+0xB5, 0xB3, 0xE7, 0x1A, 0xFF, 0xDE, 0x39, 0xC7, 
+0x39, 0xE7, 0x00, 0x00, 0xBD, 0xF7, 0xEF, 0x7C, 
+0xA5, 0x92, 0x84, 0xAD, 0xAD, 0xD4, 0xEF, 0x5C, 
+0xCE, 0x79, 0x08, 0x61, 0x29, 0x65, 0xAD, 0x55, 
+0xE7, 0x3C, 0xFF, 0xDE, 0xEF, 0x7D, 0xCE, 0x79, 
+0x7B, 0xCF, 0x08, 0x41, 0x52, 0xAA, 0xFF, 0xDF, 
+0xE7, 0x3C, 0xE7, 0x5C, 0xFF, 0xDF, 0x08, 0x41, 
+0x21, 0x04, 0x00, 0x00, 0x7B, 0xCF, 0xD6, 0x9A, 
+0xEF, 0x7D, 0xE7, 0x3C, 0xBD, 0xD7, 0x42, 0x08, 
+0x00, 0x00, 0xA5, 0x34, 0xEF, 0x7D, 0xBD, 0xD7, 
+0xD6, 0xFA, 0xF7, 0xBE, 0x73, 0x8E, 0x00, 0x00, 
+0x73, 0x8E, 0xC6, 0x38, 0xEF, 0x5C, 0xFF, 0xDE, 
+0xEF, 0x7D, 0xD6, 0xBA, 0x8C, 0x71, 0x10, 0x82, 
+0x31, 0xA6, 0xF7, 0xDE, 0xE7, 0x5B, 0xD6, 0xF9, 
+0xF7, 0x9D, 0x8C, 0x71, 0x00, 0x00, 0x4A, 0x69, 
+0xB5, 0xB6, 0xE7, 0x3C, 0xEF, 0x7D, 0xE7, 0x3C, 
+0xC6, 0x18, 0x6B, 0x6D, 0x00, 0x00, 0x5A, 0xEB, 
+0xFF, 0xDE, 0xE7, 0x5B, 0xD6, 0xF8, 0xF7, 0xBD, 
+0xCE, 0x59, 0x00, 0x20, 0x29, 0x65, 0xAD, 0x55, 
+0xE7, 0x3C, 0xEF, 0x7D, 0xE7, 0x3C, 0xCE, 0x79, 
+0x84, 0x10, 0x08, 0x41, 0x52, 0x8A, 0xF7, 0xBE, 
+0xDE, 0xFB, 0xE7, 0x3C, 0xEF, 0x7D, 0x00, 0x00, 
+0x8C, 0x51, 0xF7, 0x9E, 0xBD, 0xF8, 0xC6, 0x59, 
+0xEF, 0x7D, 0xEF, 0x7D, 0x31, 0xA6, 0x00, 0x20, 
+0xAD, 0x75, 0xF7, 0xBE, 0xEF, 0x7D, 0xFF, 0xDF, 
+0xF7, 0xBE, 0x29, 0x65, 0x10, 0x82, 0x8C, 0x71, 
+0xD6, 0xBA, 0xF7, 0x9E, 0xF7, 0x9E, 0xDE, 0xDB, 
+0x9C, 0xD3, 0x21, 0x04, 0x18, 0xE3, 0xEF, 0x5D, 
+0xE6, 0xFC, 0xCE, 0x59, 0xB5, 0x96, 0xAD, 0x76, 
+0xE7, 0x3D, 0xA5, 0x34, 0x00, 0x00, 0x73, 0x8E, 
+0xD6, 0x9A, 0xE7, 0x3C, 0xDE, 0xFB, 0xF7, 0x9E, 
+0xFF, 0xDF, 0xFF, 0xFF, 0x4A, 0x69, 0x08, 0x41, 
+0x84, 0x10, 0xCE, 0x79, 0xEF, 0x5D, 0xFF, 0xDF, 
+0xEF, 0x5D, 0xCE, 0x59, 0x7B, 0xEF, 0x00, 0x20, 
+0x5A, 0xEB, 0xFF, 0xDE, 0xEF, 0x3C, 0xEF, 0x5D, 
+0xFF, 0xDF, 0x08, 0x61, 0x00, 0x00, 0xEF, 0x7D, 
+0xEF, 0x7D, 0xE6, 0xFB, 0xF7, 0xBE, 0x94, 0xB2, 
+0x00, 0x00, 0x4A, 0x49, 0xB5, 0xB6, 0xE7, 0x3C, 
+0xEF, 0x7D, 0xEF, 0x5D, 0xC6, 0x38, 0x73, 0x8E, 
+0x00, 0x00, 0x52, 0xAA, 0xFF, 0xDE, 0xEF, 0x5C, 
+0xF7, 0x7D, 0xE7, 0x1C, 0x00, 0x00, 0x9C, 0xD3, 
+0xF7, 0x9D, 0xAD, 0xB2, 0xBE, 0x0E, 0xA5, 0x2E, 
+0xCE, 0x76, 0xF7, 0xBD, 0xA5, 0x14, 0x08, 0x61, 
+0xE7, 0x1C, 0xFF, 0xDF, 0xF7, 0xBE, 0xF7, 0xBE, 
+0xFF, 0xDE, 0xF7, 0xBE, 0xF7, 0xBE, 0xFF, 0xDF, 
+0xFF, 0xFF, 0xC6, 0x18, 0x08, 0x41, 0x63, 0x2C, 
+0xFF, 0xDE, 0xBE, 0x16, 0x21, 0xC2, 0x32, 0x64, 
+0x32, 0x44, 0x42, 0xC6, 0x42, 0xC7, 0x2A, 0x24, 
+0x21, 0xE3, 0x21, 0xE2, 0x19, 0xC2, 0x11, 0x41, 
+0x21, 0xE4, 0x2A, 0x24, 0x22, 0x03, 0x21, 0xE3, 
+0x4B, 0x49, 0x64, 0x0B, 0x5B, 0xEB, 0x74, 0x8E, 
+0x53, 0x89, 0x32, 0xA5, 0x2A, 0x23, 0x21, 0xE3, 
+0x9C, 0xF3, 0xB5, 0x95, 0xB5, 0x53, 0xB5, 0x32, 
+0xB5, 0x32, 0xB5, 0x52, 0xB5, 0x53, 0xBD, 0xD4, 
+0xC5, 0xD5, 0xAD, 0x52, 0xB5, 0x93, 0xBD, 0xB3, 
+0x94, 0x0D, 0xC5, 0xD4, 0xD6, 0x36, 0xD6, 0x56, 
+0xD6, 0x36, 0xCE, 0x16, 0xD6, 0x36, 0xD6, 0x36, 
+0xD6, 0x56, 0xDE, 0x98, 0xF7, 0x9D, 0xF7, 0x9E, 
+0x29, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x31, 0xA6, 0xFF, 0xBE, 0xF7, 0x7C, 0xE6, 0xD9, 
+0xF7, 0x5B, 0xFF, 0xDF, 0x6B, 0x6D, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xBD, 0xF7, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xBD, 0xF7, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x8A, 
+0xFF, 0xDF, 0xE7, 0x1A, 0xD6, 0x76, 0xE6, 0xFA, 
+0xF7, 0xBE, 0x63, 0x2C, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x94, 0xB2, 0xF7, 0x9D, 
+0xCE, 0x57, 0x7C, 0x0C, 0x6B, 0xAA, 0x63, 0x69, 
+0x5B, 0x68, 0x5B, 0x88, 0x8C, 0xEC, 0x8C, 0xCD, 
+0x63, 0x49, 0x9D, 0x2F, 0x6B, 0xA8, 0x84, 0xAD, 
+0x9D, 0x2F, 0xA4, 0xF0, 0x94, 0x6E, 0x94, 0x4D, 
+0xFF, 0xFF, 0xA5, 0x34, 0x00, 0x00, 0xCE, 0x79, 
+0xEF, 0x5C, 0xCE, 0x57, 0xEF, 0x7C, 0xD6, 0x9A, 
+0x00, 0x00, 0xA5, 0x34, 0xF7, 0x9D, 0xDE, 0xB9, 
+0xF7, 0x9E, 0x9C, 0xF3, 0x00, 0x00, 0xDE, 0xDB, 
+0x4A, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x42, 0x08, 0xDE, 0xDB, 
+0xEF, 0x7D, 0xC6, 0x16, 0x9C, 0xAF, 0x8C, 0x2C, 
+0xB5, 0x73, 0xEF, 0x7D, 0xC6, 0x38, 0x00, 0x00, 
+0x00, 0x00, 0xBD, 0xD7, 0xEF, 0x7D, 0xBE, 0x75, 
+0xA5, 0xD1, 0xC6, 0x56, 0xF7, 0xBE, 0x7B, 0xCF, 
+0x00, 0x00, 0x08, 0x41, 0xF7, 0xBE, 0xDF, 0x1B, 
+0xA5, 0x71, 0x6B, 0xC9, 0x84, 0x8E, 0xC6, 0x78, 
+0xF7, 0x9D, 0xCE, 0x79, 0x42, 0x08, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x08, 0x41, 0x73, 0x8E, 0xF7, 0xBE, 0xEF, 0x5C, 
+0xC6, 0x57, 0xEF, 0x9D, 0xFF, 0xFF, 0x08, 0x41, 
+0x84, 0x30, 0x94, 0x92, 0x08, 0x61, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA2, 
+0x9C, 0xF3, 0xF7, 0xBE, 0xD6, 0xBA, 0x94, 0xD1, 
+0xBE, 0x55, 0xDF, 0x1B, 0xF7, 0xDE, 0x84, 0x30, 
+0x10, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x52, 0xAA, 
+0xE7, 0x3C, 0xEF, 0xBD, 0xCE, 0xD7, 0xA5, 0xB2, 
+0xD6, 0xFA, 0xF7, 0xDE, 0x9D, 0x13, 0x21, 0x04, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0xA2, 0x84, 0x10, 0xF7, 0xBE, 
+0xEF, 0x9C, 0xCF, 0x17, 0xC6, 0xF5, 0xDF, 0x5A, 
+0xF7, 0xDE, 0xC6, 0x18, 0x31, 0xA6, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x08, 0x41, 0x6B, 0x4D, 0xEF, 0x9D, 0xDE, 0xFB, 
+0xB5, 0xB6, 0xDE, 0xDB, 0xEF, 0x7D, 0x00, 0x00, 
+0x8C, 0x51, 0xEF, 0x7D, 0xAD, 0x55, 0x94, 0xB3, 
+0xC6, 0x38, 0xEF, 0x7D, 0xEF, 0x5D, 0x31, 0xA6, 
+0x00, 0x20, 0xAD, 0x55, 0xFF, 0xDF, 0xFF, 0xDF, 
+0xFF, 0xFF, 0xEF, 0x7D, 0x63, 0x0C, 0x00, 0x20, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x4A, 0x49, 0xDE, 0xDB, 0xE7, 0x3D, 
+0xD6, 0x9A, 0xC6, 0x18, 0xA5, 0x35, 0x94, 0x92, 
+0xD6, 0x9A, 0xF7, 0x9E, 0x63, 0x0C, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x79, 
+0xF7, 0xBE, 0xF7, 0x9E, 0xEF, 0x7D, 0x73, 0x8E, 
+0x08, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x08, 0x41, 0x6B, 0x6D, 
+0xF7, 0x9E, 0xEF, 0x5C, 0xD6, 0x79, 0xEF, 0x3C, 
+0xFF, 0xDF, 0x08, 0x61, 0x00, 0x00, 0xEF, 0x7D, 
+0xEF, 0x3C, 0xCE, 0x58, 0xE7, 0x1B, 0xFF, 0xBE, 
+0xA5, 0x34, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA2, 
+0x7B, 0xEF, 0xF7, 0xBE, 0xF7, 0x9D, 0xDE, 0xB9, 
+0xEF, 0x5C, 0xE7, 0x3C, 0x00, 0x00, 0x9C, 0xD3, 
+0xEF, 0x7D, 0xBE, 0x33, 0xCE, 0xB2, 0x9C, 0xEE, 
+0xD6, 0xB7, 0xFF, 0xBE, 0x63, 0x2C, 0x39, 0xC7, 
+0xFF, 0xFF, 0xF7, 0x9D, 0xEF, 0x3B, 0xE7, 0x1A, 
+0xDF, 0x19, 0xDF, 0x1A, 0xE7, 0x3C, 0xEF, 0x5D, 
+0xF7, 0x9E, 0xFF, 0xFF, 0x42, 0x28, 0x39, 0xC7, 
+0xFF, 0xDE, 0xC6, 0x37, 0x32, 0x64, 0x42, 0xE6, 
+0x32, 0x64, 0x32, 0x85, 0x3A, 0xA5, 0x2A, 0x24, 
+0x21, 0xE3, 0x21, 0xE3, 0x19, 0xA2, 0x22, 0x03, 
+0x32, 0xA5, 0x32, 0x64, 0x2A, 0x24, 0x21, 0xE3, 
+0x53, 0x69, 0x6C, 0x6C, 0x64, 0x2B, 0x84, 0xEF, 
+0x32, 0xA6, 0x19, 0xE2, 0x19, 0xE2, 0x19, 0xC2, 
+0x94, 0x91, 0xAD, 0x12, 0xB5, 0x52, 0xB5, 0x52, 
+0xBD, 0x93, 0xBD, 0x93, 0xBD, 0x94, 0xCE, 0x36, 
+0xCD, 0xF5, 0xC5, 0xD4, 0xC5, 0xD4, 0xD6, 0x35, 
+0x94, 0x2D, 0xCE, 0x15, 0xD6, 0x56, 0xD6, 0x56, 
+0xD6, 0x56, 0xD6, 0x56, 0xD6, 0x36, 0xD6, 0x36, 
+0xD6, 0x56, 0xDE, 0xB9, 0xF7, 0xBE, 0x94, 0xB2, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xA5, 0x34, 0xFF, 0xBE, 0xEF, 0x1A, 
+0xF7, 0x7D, 0xEF, 0x5D, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x28, 
+0xFF, 0xFF, 0xFF, 0xFF, 0x4A, 0x49, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xDE, 0xDB, 0xEF, 0x7C, 0xD6, 0xB8, 0xEF, 0x3B, 
+0xF7, 0x9E, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x29, 0x45, 0xFF, 0xBE, 
+0xDE, 0xD9, 0x8C, 0x6E, 0x84, 0xED, 0x95, 0x6E, 
+0x7C, 0xAC, 0x53, 0x88, 0x6C, 0x09, 0x9D, 0x6E, 
+0x5B, 0x28, 0x94, 0xCE, 0xA5, 0x2F, 0x94, 0xAE, 
+0x7B, 0xEC, 0x73, 0x6B, 0x73, 0x6B, 0x7B, 0xAC, 
+0xFF, 0xFF, 0xEF, 0x7D, 0xD6, 0x9A, 0xF7, 0x9E, 
+0xE7, 0x1C, 0xCE, 0x37, 0xE7, 0x3C, 0xF7, 0xBE, 
+0xD6, 0xBA, 0xEF, 0x7D, 0xF7, 0x9D, 0xE6, 0xFA, 
+0xF7, 0xBE, 0xEF, 0x7D, 0xDE, 0xDB, 0xFF, 0xFF, 
+0xFF, 0xFF, 0xE7, 0x1C, 0xBD, 0xF7, 0xAD, 0x55, 
+0xB5, 0xB6, 0xDE, 0xFB, 0xF7, 0xBE, 0xE7, 0x3C, 
+0xBD, 0xF6, 0xC5, 0xF4, 0xB5, 0x30, 0xAD, 0x10, 
+0xB5, 0x92, 0xDE, 0xFA, 0xF7, 0xBE, 0xDE, 0xDB, 
+0xDE, 0xDB, 0xF7, 0xBE, 0xDF, 0x1A, 0xA5, 0x91, 
+0x8D, 0x0C, 0xB5, 0xF3, 0xEF, 0x7C, 0xEF, 0x7D, 
+0xDE, 0xDB, 0xE7, 0x1B, 0xF7, 0xBE, 0xD6, 0x98, 
+0xBD, 0xD3, 0xA4, 0xEF, 0x83, 0xED, 0xA5, 0x32, 
+0xD6, 0xB9, 0xF7, 0xBE, 0xFF, 0xDF, 0xE7, 0x3C, 
+0xBD, 0xF7, 0xAD, 0x75, 0xB5, 0xB6, 0xD6, 0x9A, 
+0xF7, 0x9E, 0xF7, 0xBE, 0xE7, 0x3B, 0xBE, 0x36, 
+0xCE, 0xB8, 0xEF, 0x9C, 0xFF, 0xDF, 0xDE, 0xFB, 
+0xEF, 0x7D, 0xFF, 0xFF, 0xF7, 0xBE, 0xC6, 0x38, 
+0xAD, 0x75, 0xAD, 0x75, 0xCE, 0x59, 0xF7, 0xBE, 
+0xF7, 0xBE, 0xD6, 0xDA, 0xA5, 0x92, 0x7C, 0xAC, 
+0x7C, 0xAB, 0xAE, 0x14, 0xEF, 0x9C, 0xF7, 0xBE, 
+0xF7, 0xBE, 0xCE, 0x79, 0xB5, 0x96, 0xAD, 0x55, 
+0xAD, 0x75, 0xBE, 0x17, 0xEF, 0x5D, 0xF7, 0xBE, 
+0xE7, 0x3B, 0xCE, 0xD7, 0xAE, 0x31, 0x74, 0x8B, 
+0xA5, 0x92, 0xD6, 0xD9, 0xEF, 0x5D, 0xF7, 0xBE, 
+0xDE, 0xDB, 0xBD, 0xD7, 0xAD, 0x55, 0xB5, 0xB6, 
+0xCE, 0x79, 0xF7, 0xBE, 0xEF, 0x9D, 0xDE, 0xFA, 
+0xA5, 0x73, 0x7C, 0x6D, 0x9D, 0xD0, 0xCF, 0x36, 
+0xE7, 0x7A, 0xEF, 0x9D, 0xFF, 0xFF, 0xE7, 0x1C, 
+0xBD, 0xD7, 0xAD, 0x55, 0xB5, 0xB6, 0xCE, 0x59, 
+0xF7, 0x9E, 0xFF, 0xFE, 0xEF, 0x7C, 0xCE, 0xB6, 
+0xAD, 0x92, 0xD6, 0xBA, 0xF7, 0xBE, 0xDE, 0xDB, 
+0xEF, 0x5D, 0xEF, 0x5D, 0x9C, 0xF3, 0x6B, 0x8E, 
+0x8C, 0x72, 0xBD, 0xF7, 0xEF, 0x5D, 0xF7, 0x9E, 
+0xDE, 0xDB, 0xDE, 0xFB, 0xFF, 0xFF, 0xFF, 0xDF, 
+0xF7, 0xBE, 0xFF, 0xDF, 0xFF, 0xDF, 0xF7, 0xBE, 
+0xC6, 0x38, 0xB5, 0x96, 0xAD, 0x75, 0xC6, 0x38, 
+0xE7, 0x3C, 0xF7, 0x9E, 0xE7, 0x1C, 0xC6, 0x18, 
+0xD6, 0x9A, 0xB5, 0xB6, 0x8C, 0x72, 0x6B, 0x4D, 
+0x9C, 0xD3, 0xDE, 0xDB, 0xF7, 0x9E, 0xE7, 0x3C, 
+0xBD, 0xF7, 0xAD, 0x55, 0xAD, 0x55, 0xEF, 0x5D, 
+0xE7, 0x1C, 0xBD, 0xF7, 0xDE, 0xDB, 0xF7, 0x9E, 
+0xF7, 0x9E, 0xC6, 0x38, 0xB5, 0x96, 0xAD, 0x55, 
+0xB5, 0x96, 0xC6, 0x38, 0xEF, 0x7D, 0xFF, 0xDF, 
+0xEF, 0x5D, 0xCE, 0x58, 0xD6, 0x79, 0xE7, 0x3C, 
+0xFF, 0xDF, 0xD6, 0xBA, 0xD6, 0xBA, 0xFF, 0xBE, 
+0xE7, 0x3C, 0xC5, 0xF6, 0xCE, 0x38, 0xE7, 0x3C, 
+0xF7, 0x9E, 0xFF, 0xDF, 0xDE, 0xDB, 0xBD, 0xD7, 
+0xAD, 0x55, 0xB5, 0xB6, 0xCE, 0x79, 0xF7, 0xDE, 
+0xF7, 0xDE, 0xE7, 0x5B, 0xDE, 0xB7, 0xDE, 0xD7, 
+0xEF, 0x5C, 0xFF, 0xDE, 0xDE, 0xFB, 0xEF, 0x7D, 
+0xEF, 0x9C, 0xD6, 0xD5, 0xD6, 0xD4, 0xAD, 0x90, 
+0xD6, 0x97, 0xF7, 0xBE, 0x6B, 0x4D, 0x10, 0xA2, 
+0xFF, 0xDF, 0xFF, 0xDE, 0xF7, 0x9D, 0xEF, 0x7D, 
+0xEF, 0x5C, 0xEF, 0x7D, 0xF7, 0x9E, 0xF7, 0xBE, 
+0xFF, 0xDF, 0xFF, 0xDF, 0x21, 0x04, 0x4A, 0x49, 
+0xF7, 0xBE, 0xB5, 0xD6, 0x32, 0x44, 0x2A, 0x44, 
+0x2A, 0x24, 0x2A, 0x24, 0x11, 0x81, 0x19, 0xA2, 
+0x21, 0xE3, 0x19, 0xA2, 0x19, 0x82, 0x32, 0x85, 
+0x43, 0x06, 0x3A, 0xC5, 0x2A, 0x64, 0x21, 0xE3, 
+0x3A, 0xE6, 0x53, 0xC9, 0x74, 0x8D, 0x8D, 0x30, 
+0x3A, 0xA6, 0x22, 0x03, 0x22, 0x02, 0x19, 0xE2, 
+0x94, 0x90, 0xB5, 0x52, 0xBD, 0xB3, 0xC5, 0xB2, 
+0xC5, 0xB3, 0xCE, 0x14, 0xD6, 0x35, 0xD6, 0x56, 
+0xD6, 0x56, 0xD6, 0x55, 0xCE, 0x15, 0xCE, 0x15, 
+0x94, 0x2D, 0xD6, 0x15, 0xDE, 0x56, 0xD6, 0x56, 
+0xD6, 0x56, 0xD6, 0x56, 0xD6, 0x36, 0xD6, 0x56, 
+0xD6, 0x56, 0xDE, 0xB9, 0xFF, 0xBE, 0x73, 0xAE, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x8C, 0x51, 0xFF, 0xDE, 0xEF, 0x1A, 
+0xF7, 0x9D, 0xD6, 0xBA, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x45, 
+0xFF, 0xFF, 0xFF, 0xFF, 0x39, 0xC7, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xCE, 0x59, 0xF7, 0xBD, 0xE7, 0x3A, 0xEF, 0x7C, 
+0xEF, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0xE3, 0xFF, 0xDE, 
+0xDE, 0xB9, 0xA5, 0x30, 0x95, 0x4F, 0x8D, 0x2F, 
+0x4B, 0x27, 0x53, 0x68, 0x8C, 0xED, 0xA5, 0xAF, 
+0x7C, 0x2B, 0x94, 0xCE, 0xC6, 0x74, 0xB5, 0x92, 
+0x9C, 0xD0, 0xA4, 0xD1, 0xA4, 0xD0, 0x9C, 0xAF, 
+0xEF, 0x3C, 0xEF, 0x5C, 0xEF, 0x5C, 0xEF, 0x3C, 
+0xDE, 0xB9, 0xC5, 0xD5, 0xD6, 0x99, 0xEF, 0x3C, 
+0xEF, 0x5C, 0xEF, 0x3C, 0xE7, 0x1B, 0xDE, 0xD9, 
+0xDE, 0xFA, 0xE7, 0x1C, 0xF7, 0x7D, 0xEF, 0x5C, 
+0xF7, 0x7C, 0xF7, 0x9D, 0xF7, 0x9D, 0xF7, 0x9D, 
+0xF7, 0x9D, 0xDE, 0xFB, 0xC6, 0x58, 0x9D, 0x32, 
+0x74, 0x0D, 0xCE, 0x75, 0xCE, 0x14, 0xBD, 0xD3, 
+0x9C, 0xEF, 0xBD, 0xD5, 0xDF, 0x1A, 0xEF, 0x5C, 
+0xEF, 0x5C, 0xE7, 0x3B, 0xCE, 0x98, 0xAD, 0x71, 
+0x8C, 0xAD, 0x8C, 0x6F, 0xCE, 0x58, 0xE7, 0x3C, 
+0xEF, 0x3C, 0xE7, 0x1C, 0xDE, 0xDA, 0xBD, 0xB4, 
+0x9C, 0x8F, 0xAD, 0x11, 0xD6, 0x77, 0xA5, 0x32, 
+0xC6, 0x57, 0xF7, 0xBD, 0xE7, 0x3C, 0xE7, 0x1C, 
+0xE7, 0x3C, 0xEF, 0x5C, 0xE7, 0x5C, 0xEF, 0x9C, 
+0xE7, 0x3B, 0xC6, 0x98, 0xBE, 0x56, 0xD7, 0x38, 
+0xD6, 0xF9, 0xE7, 0x5B, 0xEF, 0x9D, 0xEF, 0x9D, 
+0xEF, 0x7C, 0xEF, 0x5C, 0xEF, 0x9D, 0xEF, 0x5C, 
+0xEF, 0x9D, 0xEF, 0x7D, 0xF7, 0xBD, 0xE7, 0x3A, 
+0xBE, 0x56, 0x8D, 0x0F, 0x5B, 0xC8, 0x4B, 0x85, 
+0x5B, 0xE7, 0x7C, 0xCB, 0x8C, 0xD0, 0xB5, 0xB5, 
+0xD6, 0xFA, 0xE7, 0x5C, 0xE7, 0x5C, 0xEF, 0x7D, 
+0xEF, 0x9D, 0xE7, 0x5C, 0xDE, 0xFA, 0xC6, 0x77, 
+0xA5, 0xB3, 0x6C, 0x0B, 0x5B, 0xA7, 0x53, 0xA6, 
+0x74, 0x4A, 0x84, 0xAF, 0xA5, 0x54, 0xCE, 0x79, 
+0xE7, 0x7C, 0xE7, 0x5C, 0xE7, 0x5C, 0xE7, 0x5C, 
+0xDF, 0x1B, 0xD6, 0xB9, 0xBE, 0x35, 0x84, 0x8F, 
+0x52, 0xE9, 0x3A, 0x86, 0x42, 0xE5, 0x95, 0xCE, 
+0xA6, 0x11, 0xAD, 0xF4, 0xCE, 0xD8, 0xE7, 0x3B, 
+0xEF, 0x7C, 0xEF, 0x7D, 0xEF, 0x7C, 0xEF, 0x7C, 
+0xEF, 0x9C, 0xD6, 0xF8, 0xBE, 0x93, 0xAE, 0x0E, 
+0xAD, 0xEF, 0xCE, 0x97, 0xDE, 0xDB, 0xEF, 0x5C, 
+0xEF, 0x7C, 0xDE, 0xFA, 0x8C, 0x71, 0x63, 0x0C, 
+0x5B, 0x0C, 0x84, 0x10, 0xBD, 0xD7, 0xE7, 0x1C, 
+0xEF, 0x5D, 0xEF, 0x5D, 0xE7, 0x1C, 0xE7, 0x3C, 
+0xE7, 0x3C, 0xE7, 0x1C, 0xE7, 0x1C, 0xF7, 0xBE, 
+0xFF, 0xDF, 0xF7, 0x9E, 0xEF, 0x7D, 0xE7, 0x3C, 
+0xDE, 0xDB, 0xBD, 0xF7, 0x9C, 0xD3, 0xC6, 0x39, 
+0xBD, 0xF8, 0xAD, 0x55, 0x6B, 0x6E, 0x4A, 0x6A, 
+0x5A, 0xCB, 0x8C, 0x71, 0xBD, 0xF7, 0xDE, 0xDB, 
+0xE7, 0x3C, 0xE7, 0x3C, 0xE7, 0x3C, 0xDE, 0xDB, 
+0xBD, 0xD7, 0x7B, 0xEF, 0x8C, 0x51, 0xB5, 0xB6, 
+0xD6, 0x9A, 0xE7, 0x1C, 0xEF, 0x5D, 0xEF, 0x7D, 
+0xEF, 0x5D, 0xE7, 0x3C, 0xDE, 0xFB, 0xD6, 0x9A, 
+0xC6, 0x18, 0xAD, 0x55, 0xCE, 0x59, 0xE7, 0x3D, 
+0xF7, 0x9E, 0xF7, 0x9E, 0xF7, 0xBE, 0xF7, 0x9E, 
+0xE7, 0x5D, 0xD6, 0xBB, 0xD6, 0xDB, 0xDE, 0xFC, 
+0xE7, 0x1C, 0xEF, 0x5D, 0xEF, 0x7D, 0xF7, 0x9E, 
+0xF7, 0x9D, 0xEF, 0x7C, 0xE7, 0x5C, 0xDF, 0x3A, 
+0xD6, 0xD8, 0xC6, 0x35, 0xA5, 0x10, 0xBD, 0xD2, 
+0xF7, 0x9A, 0xEF, 0x7B, 0xE7, 0x5B, 0xEF, 0x7B, 
+0xDF, 0x19, 0xE7, 0x55, 0xA5, 0x6E, 0xAD, 0xB1, 
+0xCE, 0x37, 0xF7, 0x7D, 0xC6, 0x38, 0x00, 0x20, 
+0x39, 0xE7, 0x9C, 0xD3, 0xCE, 0x79, 0xDE, 0xDB, 
+0xEF, 0x5D, 0xEF, 0x5D, 0xDE, 0xFB, 0xCE, 0x79, 
+0x9C, 0xD3, 0x39, 0xE7, 0x00, 0x00, 0xAD, 0x75, 
+0xEF, 0x5C, 0x9D, 0x13, 0x32, 0x85, 0x32, 0x65, 
+0x32, 0x85, 0x19, 0xA3, 0x11, 0x41, 0x19, 0xC3, 
+0x2A, 0x24, 0x21, 0xC3, 0x19, 0xA2, 0x32, 0x85, 
+0x4B, 0x07, 0x3A, 0xC5, 0x2A, 0x64, 0x21, 0xE2, 
+0x32, 0x84, 0x4B, 0xA8, 0x7C, 0xEE, 0x8D, 0x50, 
+0x32, 0x85, 0x2A, 0x23, 0x22, 0x23, 0x21, 0xE2, 
+0x6B, 0x2A, 0x83, 0xAC, 0x94, 0x4D, 0x9C, 0x8E, 
+0xAD, 0x10, 0xBD, 0x72, 0xC5, 0xD4, 0xCD, 0xF4, 
+0xD6, 0x55, 0xDE, 0x76, 0xDE, 0x97, 0xCD, 0xF4, 
+0x9C, 0x4D, 0xCD, 0xD3, 0xDE, 0x76, 0xE6, 0x97, 
+0xE6, 0xB7, 0xE6, 0xB7, 0xDE, 0x76, 0xDE, 0x76, 
+0xDE, 0x56, 0xEE, 0xF9, 0xF7, 0xBE, 0xAD, 0x75, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xC6, 0x18, 0xFF, 0xBE, 0xDE, 0xB9, 
+0xF7, 0x7C, 0xFF, 0xDE, 0x18, 0xC3, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x6D, 
+0xFF, 0xFF, 0xFF, 0xFF, 0x84, 0x10, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xE3, 
+0xF7, 0xBE, 0xF7, 0x9D, 0xEF, 0x3A, 0xF7, 0x7C, 
+0xFF, 0xDE, 0x39, 0xE7, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x6B, 0x6D, 0xF7, 0xBE, 
+0xDE, 0xD8, 0xAD, 0xB1, 0x8C, 0xED, 0x53, 0x68, 
+0x53, 0x69, 0x6C, 0x2B, 0x84, 0xAC, 0xA5, 0xB0, 
+0xB5, 0xF2, 0x84, 0x6D, 0xC6, 0x54, 0xAD, 0x51, 
+0xA4, 0xF0, 0x9C, 0x90, 0xAD, 0x11, 0xAD, 0x11, 
+0xBD, 0xD5, 0xC5, 0xD5, 0xBD, 0xB4, 0xC5, 0xB4, 
+0xC5, 0xB4, 0xB5, 0x73, 0xAD, 0x12, 0xBD, 0x73, 
+0xB5, 0x53, 0x9C, 0x90, 0xBD, 0xB4, 0xA4, 0xF2, 
+0x84, 0x0F, 0xC6, 0x16, 0xD6, 0x77, 0xD6, 0x36, 
+0xD6, 0x36, 0xD6, 0x56, 0xCE, 0x15, 0xD6, 0x56, 
+0xCE, 0x56, 0x7C, 0x2E, 0x74, 0x0C, 0x5B, 0x88, 
+0x53, 0x26, 0xB5, 0xB2, 0xC6, 0x14, 0xC5, 0xD3, 
+0xBD, 0xB3, 0xB5, 0x52, 0xBD, 0xB3, 0xBD, 0xB3, 
+0xB5, 0x72, 0x9C, 0xB1, 0x73, 0x8D, 0x5A, 0xEA, 
+0x52, 0xA9, 0x73, 0x8C, 0xB5, 0x74, 0xBD, 0xD5, 
+0xB5, 0x74, 0xAD, 0x54, 0xA4, 0xF2, 0x9C, 0xD1, 
+0x7B, 0xCD, 0xC6, 0x57, 0xD6, 0xB7, 0xDE, 0xF9, 
+0xA5, 0x33, 0xE7, 0x3A, 0xDE, 0xF9, 0xA5, 0x32, 
+0x9D, 0x32, 0x94, 0xF1, 0x8C, 0xD0, 0xAE, 0x13, 
+0x9D, 0x91, 0x8C, 0xEE, 0xC6, 0xF4, 0xBE, 0x91, 
+0xAD, 0xF2, 0xC6, 0x97, 0xC6, 0x77, 0xAD, 0xB4, 
+0xA5, 0x73, 0xBE, 0x16, 0xD6, 0xF8, 0xB6, 0x34, 
+0xB6, 0x33, 0xBE, 0x75, 0xAD, 0xD2, 0x8C, 0xEE, 
+0x6C, 0x4A, 0x53, 0x86, 0x6C, 0x49, 0x85, 0x0B, 
+0x74, 0xA8, 0x5C, 0x06, 0x3A, 0xA6, 0x63, 0x8B, 
+0x9D, 0x90, 0x95, 0x50, 0x84, 0x2F, 0x95, 0x31, 
+0xA5, 0xD1, 0x95, 0x50, 0x84, 0xEE, 0x84, 0xED, 
+0x95, 0xAE, 0x85, 0x0C, 0x7C, 0xAA, 0x7C, 0xC9, 
+0x95, 0x8C, 0x6C, 0x28, 0x63, 0x8A, 0xA5, 0xB0, 
+0xA5, 0x90, 0x8C, 0xB0, 0x84, 0x2F, 0x7C, 0x2F, 
+0x84, 0x8F, 0x8D, 0x0E, 0x6C, 0x2B, 0x32, 0x45, 
+0x19, 0x42, 0x2A, 0x03, 0x4B, 0x66, 0x4B, 0xA5, 
+0x53, 0xC6, 0x5B, 0xE9, 0x7C, 0xCD, 0x9D, 0xB0, 
+0xBE, 0x93, 0xB6, 0x12, 0xA5, 0xB0, 0x9D, 0x90, 
+0x9D, 0x8F, 0x8D, 0x0C, 0x8D, 0x4A, 0x8D, 0x49, 
+0x85, 0x29, 0x95, 0x4D, 0xBE, 0x52, 0xCE, 0xD4, 
+0xB5, 0xF3, 0xA5, 0x52, 0x84, 0x6D, 0x63, 0x69, 
+0x63, 0x8A, 0x73, 0xEC, 0x8C, 0xB0, 0xB5, 0xB5, 
+0xBD, 0xD7, 0xAD, 0x55, 0x94, 0x92, 0xA5, 0x14, 
+0xBD, 0xF7, 0xCE, 0x59, 0xCE, 0x59, 0xCE, 0x59, 
+0xCE, 0x7A, 0xDE, 0xDA, 0xCE, 0x99, 0xAD, 0xD5, 
+0xB6, 0x15, 0xA5, 0x73, 0xA5, 0x34, 0xC6, 0x38, 
+0x9C, 0xD3, 0x8C, 0x52, 0x52, 0xAB, 0x42, 0x08, 
+0x31, 0x86, 0x42, 0x28, 0x63, 0x2C, 0x7B, 0xEF, 
+0x84, 0x30, 0x84, 0x10, 0x84, 0x30, 0x84, 0x0F, 
+0x63, 0x0C, 0x4A, 0x49, 0x4A, 0x29, 0x63, 0x0C, 
+0x73, 0x8E, 0x83, 0xEF, 0x8C, 0x50, 0x9C, 0xD2, 
+0x9C, 0xD3, 0xBD, 0xB6, 0xA5, 0x14, 0x8C, 0x31, 
+0x9C, 0xF4, 0xA5, 0x14, 0x8C, 0x72, 0xA5, 0x56, 
+0xB5, 0xD8, 0xAD, 0xB8, 0xB5, 0xD8, 0xB5, 0xF9, 
+0xB5, 0xF9, 0xA5, 0x98, 0xA5, 0xB8, 0xAD, 0xB8, 
+0xAD, 0x98, 0xBE, 0x19, 0xC6, 0x9B, 0xCE, 0x9B, 
+0xCE, 0xBA, 0xB6, 0x35, 0xA5, 0xD1, 0xAD, 0xD1, 
+0x9D, 0x6F, 0xB5, 0xD0, 0xCE, 0x72, 0xD6, 0xD2, 
+0xEF, 0x94, 0xCE, 0xB1, 0xA5, 0xAF, 0xA5, 0xCF, 
+0xAD, 0xEF, 0xEF, 0x93, 0xBE, 0x11, 0xDF, 0x39, 
+0xD6, 0xDA, 0xEF, 0x7D, 0xFF, 0xDF, 0xBD, 0xF7, 
+0x39, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x29, 0x45, 0xAD, 0x55, 0xF7, 0xDE, 
+0xCE, 0x79, 0x7C, 0x2E, 0x2A, 0x44, 0x32, 0x85, 
+0x32, 0x65, 0x11, 0x62, 0x19, 0xA3, 0x19, 0xA3, 
+0x21, 0xC3, 0x19, 0xA3, 0x11, 0x42, 0x09, 0x21, 
+0x32, 0x44, 0x3A, 0xE5, 0x2A, 0x64, 0x21, 0xE2, 
+0x2A, 0x43, 0x53, 0xA8, 0x85, 0x2F, 0x74, 0xAD, 
+0x42, 0xE6, 0x22, 0x23, 0x2A, 0x64, 0x21, 0xE2, 
+0x7B, 0xAC, 0x7B, 0x6B, 0x73, 0x49, 0x8B, 0xEC, 
+0x9C, 0x4D, 0x9C, 0x4D, 0x94, 0x2C, 0x9C, 0x6D, 
+0x9C, 0x6E, 0xA4, 0xAE, 0xA4, 0xCF, 0xA4, 0xAE, 
+0xA4, 0x8E, 0xAC, 0xCF, 0xA4, 0xAF, 0x9C, 0x6E, 
+0xA4, 0x8E, 0xAC, 0xD0, 0xBD, 0x31, 0xC5, 0x92, 
+0xBD, 0x71, 0xBD, 0x72, 0xDE, 0xDA, 0xFF, 0xBE, 
+0x63, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x73, 0xAE, 0xFF, 0xDE, 0xF7, 0x5C, 0xE6, 0xD8, 
+0xF7, 0x3B, 0xFF, 0xDE, 0xBD, 0xF7, 0x10, 0xA2, 
+0x00, 0x00, 0x00, 0x00, 0x39, 0xE7, 0xEF, 0x7D, 
+0xFF, 0xBE, 0xFF, 0xDE, 0xF7, 0xBE, 0x5A, 0xCB, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0xE3, 0xC6, 0x38, 
+0xFF, 0xBE, 0xEF, 0x3A, 0xE7, 0x19, 0xEF, 0x3A, 
+0xFF, 0xBE, 0xDE, 0xFB, 0x39, 0xC7, 0x00, 0x00, 
+0x00, 0x00, 0x52, 0xAA, 0xEF, 0x7D, 0xE7, 0x3B, 
+0xB5, 0x93, 0x5B, 0x08, 0x63, 0x89, 0x63, 0xCA, 
+0x5B, 0xAA, 0x95, 0x2F, 0x9D, 0x4F, 0xBE, 0x53, 
+0xC6, 0x74, 0x7C, 0x2B, 0xBE, 0x33, 0xB5, 0xB2, 
+0x9C, 0xB0, 0x94, 0x6F, 0xA4, 0xF1, 0xAD, 0x11, 
+0xAD, 0x31, 0xB5, 0x50, 0xB5, 0x90, 0xB5, 0x90, 
+0xB5, 0x50, 0xAD, 0x31, 0x73, 0x6B, 0xA4, 0xCF, 
+0xA4, 0xD0, 0xAD, 0x12, 0x7B, 0x8C, 0x6B, 0x4B, 
+0xB5, 0x52, 0xAD, 0x31, 0xBD, 0x92, 0xBD, 0x72, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xA4, 0xD0, 0xBD, 0xB3, 
+0xBD, 0xD3, 0x42, 0xC4, 0x3A, 0xE4, 0x43, 0x03, 
+0x3A, 0xE4, 0x73, 0xEB, 0xC6, 0x14, 0xC5, 0xD3, 
+0xB5, 0x71, 0x94, 0x4D, 0xB5, 0x71, 0xA4, 0xCF, 
+0xA4, 0xAF, 0xA4, 0xF1, 0x84, 0x0E, 0x84, 0x0E, 
+0x94, 0x90, 0xA4, 0xF2, 0xB5, 0x74, 0xA5, 0x12, 
+0x94, 0x90, 0x9C, 0xD1, 0x94, 0xB0, 0x94, 0xB0, 
+0xBD, 0xF5, 0xDE, 0xD9, 0xBE, 0x15, 0xAD, 0xB3, 
+0x9D, 0x51, 0xA5, 0xB2, 0xA5, 0xB2, 0x94, 0xEF, 
+0x63, 0x8A, 0x74, 0x4C, 0x9D, 0x8F, 0x9D, 0xAE, 
+0x7C, 0x8A, 0x85, 0x0B, 0xB6, 0x8F, 0xBE, 0x8E, 
+0x63, 0xC9, 0xC6, 0x97, 0xD7, 0x1A, 0x84, 0x6F, 
+0x9D, 0x32, 0xAD, 0xD3, 0xA5, 0x90, 0xA5, 0xF0, 
+0x8D, 0x4D, 0x74, 0x69, 0x5B, 0xC5, 0x53, 0xC3, 
+0x53, 0x85, 0x95, 0x2E, 0xA5, 0x8F, 0x84, 0xCB, 
+0x5B, 0xE5, 0x53, 0xE5, 0x64, 0x47, 0x7C, 0xC9, 
+0x74, 0xA9, 0x5B, 0xC7, 0x4B, 0x26, 0x74, 0xAA, 
+0x9E, 0x0D, 0x8D, 0x6A, 0x7D, 0x09, 0x64, 0x47, 
+0x7C, 0xEA, 0x9D, 0xAE, 0xA6, 0x0F, 0x6C, 0x88, 
+0x4B, 0x45, 0x42, 0xE4, 0x3A, 0x84, 0x53, 0x46, 
+0x53, 0x66, 0x53, 0x47, 0x29, 0xC4, 0x19, 0x23, 
+0x29, 0xC4, 0x4B, 0x47, 0x4B, 0x26, 0x42, 0xE5, 
+0x2A, 0x24, 0x2A, 0x03, 0x43, 0x05, 0x4B, 0x65, 
+0x5B, 0xE7, 0x7C, 0xCB, 0x8D, 0x6D, 0x5B, 0xE7, 
+0x7C, 0xC9, 0x95, 0x8B, 0x74, 0xA7, 0x6C, 0x86, 
+0x6C, 0x66, 0xA5, 0xEE, 0xBE, 0xD2, 0x8D, 0x6A, 
+0x6C, 0x86, 0x7C, 0xA7, 0xC6, 0xD1, 0xC6, 0xF2, 
+0xBE, 0xD3, 0xBE, 0x93, 0xAE, 0x30, 0x6C, 0x26, 
+0x7C, 0xC8, 0x7C, 0xE8, 0x7C, 0xA9, 0x8C, 0xEE, 
+0x8C, 0x70, 0x73, 0xAE, 0x8C, 0x71, 0x9C, 0xD3, 
+0xCE, 0x7A, 0xAD, 0x76, 0x9C, 0xB3, 0xA4, 0xD3, 
+0x9C, 0xD4, 0x94, 0xB3, 0xAD, 0x75, 0x9D, 0x12, 
+0xAD, 0xF4, 0xB6, 0x35, 0xC6, 0x58, 0xBD, 0xF7, 
+0x9C, 0xD3, 0x6B, 0x4D, 0x42, 0x29, 0x31, 0x86, 
+0x29, 0x65, 0x29, 0x45, 0x31, 0x86, 0x39, 0xC7, 
+0x42, 0x28, 0x42, 0x08, 0x21, 0x04, 0x31, 0x86, 
+0x29, 0x45, 0x4A, 0x28, 0x5A, 0xCB, 0x39, 0xA6, 
+0x39, 0xC7, 0x5A, 0xCB, 0x41, 0xE7, 0x4A, 0x29, 
+0x42, 0x08, 0x62, 0xEB, 0x6B, 0x4D, 0x7B, 0xD0, 
+0x8C, 0x72, 0x9C, 0xD4, 0xA5, 0x14, 0xAD, 0x76, 
+0xA5, 0x35, 0x73, 0xF1, 0x8C, 0xD4, 0xB5, 0xD8, 
+0x7C, 0x32, 0x74, 0x32, 0x7C, 0x73, 0x84, 0xB5, 
+0x8C, 0xD5, 0x84, 0xB5, 0x84, 0xB5, 0x84, 0xB5, 
+0x84, 0x93, 0x8D, 0x11, 0x8D, 0x4C, 0x8D, 0x4B, 
+0x8C, 0xEB, 0xC6, 0xB1, 0xCE, 0xAF, 0xD7, 0x0F, 
+0xB5, 0xE9, 0xB6, 0x29, 0x95, 0x65, 0x85, 0x04, 
+0x95, 0x66, 0xA5, 0x8B, 0x95, 0x2F, 0x8C, 0xF2, 
+0x9D, 0x35, 0xB5, 0xF9, 0xDE, 0xFC, 0xF7, 0xBF, 
+0xFF, 0xDF, 0xEF, 0x7D, 0xCE, 0x79, 0xBD, 0xF7, 
+0xB5, 0x96, 0xAD, 0x55, 0xBD, 0xD7, 0xC6, 0x38, 
+0xE7, 0x3C, 0xF7, 0xBE, 0xF7, 0xBD, 0xDF, 0x3A, 
+0x94, 0xF1, 0x4B, 0x08, 0x32, 0x85, 0x4B, 0x07, 
+0x32, 0x45, 0x21, 0xE4, 0x2A, 0x25, 0x11, 0x42, 
+0x19, 0x62, 0x19, 0xA3, 0x21, 0xA4, 0x11, 0x01, 
+0x32, 0x45, 0x4B, 0x47, 0x2A, 0x43, 0x22, 0x03, 
+0x22, 0x43, 0x53, 0xA9, 0x74, 0xCD, 0x7C, 0xED, 
+0x3A, 0xC6, 0x09, 0x20, 0x2A, 0x44, 0x21, 0xE3, 
+0x83, 0xED, 0x8B, 0xED, 0x7B, 0x4A, 0x8B, 0xEB, 
+0xA4, 0xAE, 0xA4, 0xAE, 0xA4, 0xAE, 0xA4, 0xAF, 
+0xA4, 0x8E, 0xB5, 0x10, 0xB5, 0x10, 0xAD, 0x10, 
+0xB5, 0x10, 0xB5, 0x10, 0xBD, 0x51, 0xBD, 0x51, 
+0xBD, 0x72, 0xC5, 0xB2, 0xBD, 0x51, 0xB5, 0x10, 
+0xB5, 0x10, 0xBD, 0x72, 0xCE, 0x36, 0xEF, 0x5C, 
+0xFF, 0xBE, 0xCE, 0x79, 0xA5, 0x34, 0xD6, 0x9A, 
+0xF7, 0xBE, 0xE7, 0x1B, 0xC5, 0xB4, 0xA4, 0xAF, 
+0xB5, 0x32, 0xD6, 0x99, 0xF7, 0x7D, 0xEF, 0x7D, 
+0xBD, 0xD7, 0xCE, 0x59, 0xFF, 0xBE, 0xF7, 0x7D, 
+0xE6, 0xD9, 0xE6, 0xD9, 0xF7, 0x7C, 0xFF, 0xDE, 
+0xE7, 0x1C, 0xD6, 0x99, 0xFF, 0xBE, 0xFF, 0xBE, 
+0xF7, 0x5B, 0xEF, 0x19, 0xEF, 0x19, 0xEE, 0xF9, 
+0xF7, 0x7C, 0xF7, 0x9D, 0xFF, 0xDF, 0xE7, 0x3C, 
+0xEF, 0x7D, 0xFF, 0xDE, 0xEF, 0x7C, 0xD6, 0x57, 
+0xA4, 0xCF, 0x73, 0x89, 0x74, 0x0B, 0x63, 0xCA, 
+0x63, 0xCA, 0x9D, 0x91, 0x74, 0x0B, 0x8C, 0xED, 
+0xAE, 0x11, 0x73, 0xEB, 0x8C, 0x8E, 0xC6, 0x35, 
+0x7B, 0xCC, 0x8C, 0x2E, 0x9C, 0xD0, 0xB5, 0x92, 
+0xBE, 0x11, 0xBE, 0x50, 0xBE, 0x6F, 0xBE, 0x6F, 
+0xC6, 0x70, 0xC6, 0x53, 0x7B, 0x8A, 0xAD, 0x10, 
+0xAD, 0x11, 0x6B, 0x4B, 0x63, 0x2A, 0x9C, 0xB0, 
+0xB5, 0x72, 0xB5, 0x52, 0xAD, 0x31, 0xBD, 0x72, 
+0xBD, 0x72, 0xBD, 0x72, 0x83, 0xEC, 0xC5, 0xF4, 
+0xAD, 0x50, 0x4B, 0x05, 0x32, 0x82, 0x3A, 0xA2, 
+0x3A, 0xA3, 0x53, 0x68, 0x7C, 0x6C, 0x84, 0x6D, 
+0xA5, 0x51, 0x8C, 0x4D, 0xAD, 0x10, 0x9C, 0x8E, 
+0x9C, 0x6D, 0xB5, 0x52, 0x94, 0x8F, 0x9C, 0xF1, 
+0xAD, 0x73, 0xAD, 0x73, 0xA5, 0x12, 0x94, 0x90, 
+0x6B, 0x4B, 0x6B, 0x6C, 0x83, 0xEE, 0xC5, 0xF6, 
+0xCE, 0x77, 0xA5, 0x32, 0x5B, 0x4A, 0x42, 0xE8, 
+0x42, 0xC7, 0x6B, 0xEB, 0x9D, 0x71, 0xA5, 0x91, 
+0xA5, 0x92, 0x7C, 0x6C, 0xBE, 0x72, 0xBE, 0xB2, 
+0x7C, 0xAA, 0x74, 0x88, 0x9D, 0xCC, 0xA5, 0xED, 
+0x5B, 0x89, 0xD6, 0xF9, 0x94, 0xF1, 0x9D, 0x51, 
+0xA5, 0xB1, 0xAE, 0x32, 0x84, 0xEB, 0x8D, 0x2C, 
+0x95, 0x6D, 0x53, 0xC5, 0x4B, 0xA3, 0x43, 0x43, 
+0x63, 0x87, 0x8C, 0x8D, 0x7C, 0x2A, 0x7C, 0xA9, 
+0x53, 0xC4, 0x64, 0x46, 0x64, 0x26, 0x85, 0x29, 
+0x6C, 0x88, 0x32, 0x63, 0x21, 0xE2, 0x4B, 0x66, 
+0x74, 0xCA, 0x74, 0xC9, 0x74, 0xC9, 0x95, 0xAD, 
+0x95, 0x8C, 0x95, 0xAC, 0x7D, 0x09, 0x4B, 0x84, 
+0x32, 0x63, 0x43, 0x05, 0x3A, 0x84, 0x3A, 0xC5, 
+0x43, 0x05, 0x4B, 0x27, 0x11, 0x21, 0x11, 0x02, 
+0x11, 0x01, 0x2A, 0x24, 0x42, 0xC6, 0xAE, 0x11, 
+0x84, 0xCC, 0x4A, 0xE7, 0x74, 0x4C, 0x8D, 0x2E, 
+0x8D, 0x4D, 0x7C, 0xCB, 0x5B, 0xE7, 0x64, 0x49, 
+0x64, 0x48, 0x4B, 0xC4, 0x74, 0xE9, 0x9E, 0x0E, 
+0xAE, 0x71, 0xAE, 0x50, 0x9D, 0xCE, 0x7D, 0x0A, 
+0x6C, 0x88, 0x95, 0x4A, 0xBE, 0x8F, 0xA5, 0xEF, 
+0xC7, 0x14, 0xBE, 0xF4, 0xB6, 0x71, 0x53, 0xC5, 
+0x54, 0x03, 0x64, 0x63, 0x7C, 0xC7, 0xB6, 0x30, 
+0x84, 0x6D, 0x63, 0x0C, 0x9C, 0xD3, 0x9C, 0xF4, 
+0xBD, 0xF8, 0x8C, 0x31, 0x7B, 0x8E, 0x8B, 0xCF, 
+0xA4, 0xB3, 0xB5, 0x55, 0x8C, 0x51, 0x8C, 0x30, 
+0xAD, 0x94, 0xA5, 0x54, 0xA5, 0x34, 0x9C, 0xF4, 
+0x8C, 0x92, 0x52, 0xCB, 0x39, 0xC7, 0x31, 0x65, 
+0x21, 0x44, 0x29, 0x44, 0x31, 0x85, 0x31, 0x86, 
+0x52, 0x89, 0x5A, 0xCA, 0x29, 0x45, 0x21, 0x04, 
+0x31, 0x65, 0x52, 0x8A, 0x62, 0xEB, 0x5A, 0xAB, 
+0x39, 0xA6, 0x52, 0x8A, 0x6B, 0x2D, 0x41, 0xE8, 
+0x42, 0x08, 0x4A, 0x49, 0x5A, 0xCC, 0x7B, 0xAF, 
+0x94, 0x72, 0x94, 0x92, 0x94, 0x92, 0x8C, 0x71, 
+0x8C, 0x51, 0x94, 0xB3, 0xA5, 0x35, 0x94, 0xD4, 
+0x74, 0x12, 0x6B, 0xD1, 0x63, 0xB1, 0x63, 0xB1, 
+0x63, 0xB1, 0x63, 0xB0, 0x6B, 0xD1, 0x63, 0xB0, 
+0x63, 0x8F, 0x6B, 0xEE, 0x8D, 0x2D, 0x8D, 0x2B, 
+0x8D, 0x2A, 0xC6, 0xAF, 0xD6, 0xEE, 0xD7, 0x0E, 
+0xAD, 0xA7, 0xC6, 0xAA, 0xA5, 0xE7, 0x8D, 0x23, 
+0x8D, 0x25, 0x9D, 0x8B, 0x8C, 0xEF, 0x84, 0xB2, 
+0x8C, 0xD4, 0x8C, 0xF5, 0xAD, 0x97, 0xEF, 0x5C, 
+0xEF, 0x7C, 0xEF, 0x7D, 0xF7, 0xBE, 0xFF, 0xDF, 
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 
+0xEF, 0x7D, 0xDF, 0x1B, 0xD6, 0xF7, 0xB6, 0x31, 
+0x6C, 0x4A, 0x3A, 0xA6, 0x5B, 0xAA, 0x5B, 0xAA, 
+0x2A, 0x04, 0x2A, 0x04, 0x32, 0x66, 0x19, 0xA3, 
+0x21, 0xA3, 0x21, 0xE4, 0x19, 0x63, 0x2A, 0x05, 
+0x6C, 0x4C, 0x5C, 0x09, 0x22, 0x23, 0x22, 0x23, 
+0x22, 0x23, 0x3A, 0xE6, 0x4B, 0x27, 0x7C, 0xEE, 
+0x21, 0xC3, 0x19, 0xA3, 0x32, 0x85, 0x21, 0xE3, 
+0xB5, 0x73, 0x8C, 0x0D, 0x7B, 0x6A, 0x9C, 0x6E, 
+0xBD, 0x51, 0xB5, 0x30, 0xB5, 0x10, 0xA4, 0xAF, 
+0xAD, 0x10, 0xBD, 0x92, 0xC5, 0x93, 0xC5, 0x92, 
+0xCD, 0xF4, 0xBD, 0x72, 0xBD, 0x72, 0xBD, 0x92, 
+0xBD, 0x51, 0xC5, 0x92, 0xA4, 0x8E, 0x8C, 0x0C, 
+0x94, 0x2D, 0x9C, 0x4D, 0x9C, 0x8F, 0xC5, 0xD5, 
+0xE7, 0x1B, 0xF7, 0xBE, 0xFF, 0xFF, 0xFF, 0xDE, 
+0xF7, 0x7C, 0xE6, 0xB8, 0xD6, 0x14, 0xCD, 0xF3, 
+0xC5, 0x92, 0xD6, 0x56, 0xE6, 0xF9, 0xF7, 0x9D, 
+0xFF, 0xDF, 0xFF, 0xBE, 0xEF, 0x3C, 0xDE, 0x78, 
+0xB5, 0x31, 0xB5, 0x31, 0xC5, 0xF5, 0xE6, 0xFA, 
+0xF7, 0x9D, 0xF7, 0x9E, 0xE7, 0x3C, 0xCE, 0x37, 
+0xAD, 0x11, 0xA4, 0x8E, 0x9C, 0x8E, 0xA4, 0xAF, 
+0xBD, 0x72, 0xCE, 0x37, 0xE7, 0x1B, 0xF7, 0x9D, 
+0xF7, 0x7D, 0xE7, 0x1A, 0xCE, 0x36, 0xBD, 0x72, 
+0xA4, 0xAE, 0x8C, 0x2B, 0x63, 0x48, 0x4B, 0x07, 
+0x74, 0x6C, 0x84, 0xEE, 0x5B, 0x69, 0x84, 0xCC, 
+0x85, 0x0C, 0xB6, 0x32, 0x84, 0x4C, 0x7C, 0x0D, 
+0x6B, 0x2A, 0x8C, 0x2E, 0xA5, 0x10, 0xC6, 0x52, 
+0xBE, 0x0F, 0xB6, 0x0D, 0xB5, 0xCC, 0xB5, 0xCD, 
+0xB5, 0xEE, 0xAD, 0x6F, 0x7B, 0xCC, 0xB5, 0x52, 
+0x63, 0x0A, 0x52, 0x88, 0x63, 0x2A, 0x94, 0x8F, 
+0xB5, 0x92, 0xB5, 0x72, 0xAD, 0x10, 0xB5, 0x52, 
+0xBD, 0x72, 0xB5, 0x72, 0x7B, 0xCC, 0xCE, 0x15, 
+0x9C, 0xEF, 0x6C, 0x0A, 0x53, 0xA8, 0x43, 0x05, 
+0x32, 0x63, 0x3A, 0xC5, 0x74, 0x6C, 0x8D, 0x0F, 
+0xA5, 0x51, 0x94, 0xCF, 0xAD, 0x31, 0xA4, 0xAE, 
+0x94, 0x2D, 0xA4, 0xF1, 0xAD, 0x52, 0xB5, 0x53, 
+0xBD, 0x94, 0xB5, 0x74, 0xAD, 0x33, 0x7B, 0xED, 
+0x8C, 0x8F, 0x63, 0x6B, 0xA5, 0x53, 0xBD, 0xF5, 
+0xA5, 0x72, 0x7C, 0x8E, 0x63, 0xEC, 0x53, 0x48, 
+0x6B, 0xEA, 0x8C, 0xCE, 0xA5, 0x71, 0xAD, 0xD2, 
+0xA5, 0x90, 0x95, 0x0D, 0x84, 0xAB, 0xAD, 0xEF, 
+0x9D, 0x8D, 0x64, 0x07, 0x8D, 0x2B, 0x95, 0x2B, 
+0x7C, 0x8F, 0xCE, 0xD9, 0x84, 0x2F, 0x9D, 0x31, 
+0xB6, 0x53, 0xA5, 0xF1, 0x5B, 0xE7, 0x5B, 0xC6, 
+0x85, 0x0B, 0x4B, 0x63, 0x43, 0x03, 0x4A, 0xE6, 
+0x84, 0x2D, 0x94, 0x6D, 0x9D, 0x0E, 0x74, 0x48, 
+0x5B, 0xE5, 0x4B, 0x83, 0x7D, 0x09, 0x8D, 0x6A, 
+0x6C, 0x88, 0x11, 0x60, 0x21, 0xA3, 0x2A, 0x44, 
+0x3A, 0xC5, 0x2A, 0x23, 0x19, 0xA1, 0x6C, 0x49, 
+0xAE, 0x4F, 0x85, 0x29, 0x5C, 0x03, 0x74, 0x88, 
+0x95, 0x4C, 0x63, 0xC8, 0x74, 0x4A, 0x53, 0x67, 
+0x74, 0x6B, 0x53, 0x47, 0x21, 0x62, 0x19, 0x22, 
+0x11, 0x01, 0x53, 0x08, 0xA5, 0xAF, 0xBE, 0x91, 
+0x84, 0x8C, 0x7C, 0x2D, 0x95, 0x10, 0x74, 0x6C, 
+0x3A, 0x84, 0x22, 0x02, 0x74, 0x8B, 0x85, 0x4D, 
+0x6C, 0x89, 0x64, 0x66, 0x85, 0x4B, 0xA6, 0x30, 
+0xAE, 0x51, 0x7D, 0x0B, 0x6C, 0xA9, 0x85, 0x4B, 
+0x9D, 0xAD, 0x9D, 0xAC, 0x95, 0x6A, 0x7C, 0x68, 
+0x9D, 0xAF, 0xC7, 0x15, 0xAE, 0x51, 0x7C, 0xCA, 
+0x6C, 0xC8, 0x75, 0x08, 0x8D, 0x8A, 0xB6, 0x4E, 
+0x9D, 0x4D, 0x63, 0x4B, 0x8C, 0x71, 0xA5, 0x35, 
+0xA5, 0x14, 0x62, 0xCB, 0x62, 0xAB, 0x8B, 0xEF, 
+0xBD, 0x54, 0xAD, 0x33, 0x5A, 0xA9, 0x9C, 0xD2, 
+0x9C, 0xB2, 0xCE, 0x79, 0xDE, 0xDB, 0xB5, 0x96, 
+0x73, 0xD0, 0x52, 0xAA, 0x5A, 0xA9, 0x84, 0x0C, 
+0x4A, 0x46, 0x29, 0x64, 0x39, 0xA6, 0x39, 0xC6, 
+0x63, 0x0B, 0x7B, 0xAE, 0x5A, 0x8A, 0x18, 0xC3, 
+0x31, 0x65, 0x42, 0x08, 0x5A, 0xAA, 0x73, 0x6D, 
+0x52, 0x49, 0x39, 0xA7, 0x5A, 0xCB, 0x5A, 0xCB, 
+0x41, 0xC7, 0x52, 0x6A, 0x62, 0xCC, 0x7B, 0xD0, 
+0x84, 0x10, 0x83, 0xEF, 0x83, 0xEF, 0x7B, 0xCF, 
+0x73, 0x6E, 0x9C, 0xD3, 0xBD, 0xD7, 0xBE, 0x19, 
+0xB6, 0x3A, 0xB6, 0x1A, 0xAD, 0xFA, 0xAD, 0xB9, 
+0xA5, 0x98, 0xA5, 0x98, 0xA5, 0x98, 0xA5, 0x98, 
+0xA5, 0x97, 0xBE, 0x36, 0xC6, 0x73, 0x8C, 0xEB, 
+0xAD, 0xCC, 0xEF, 0xD2, 0xD6, 0xCE, 0xAD, 0xA8, 
+0xC6, 0x49, 0xD7, 0x0B, 0xC6, 0xA9, 0x95, 0x44, 
+0x95, 0x86, 0xBE, 0x8E, 0xA5, 0xB1, 0x95, 0x13, 
+0x95, 0x35, 0x95, 0x16, 0xB5, 0xB6, 0xEF, 0x79, 
+0xDE, 0xD6, 0x5A, 0xA9, 0x4A, 0x29, 0x4A, 0x09, 
+0x5A, 0xCB, 0x8C, 0x51, 0x7B, 0xEF, 0x52, 0xAA, 
+0x3A, 0x05, 0x9D, 0x6D, 0xB6, 0x4E, 0x8D, 0x6A, 
+0x64, 0x07, 0x42, 0xE7, 0x7C, 0xAE, 0x5B, 0xAB, 
+0x11, 0x62, 0x19, 0xA3, 0x32, 0x45, 0x19, 0xA3, 
+0x11, 0x62, 0x11, 0x22, 0x09, 0x01, 0x42, 0xE7, 
+0x64, 0x4A, 0x53, 0xC8, 0x2A, 0x43, 0x2A, 0x23, 
+0x19, 0xA2, 0x09, 0x21, 0x21, 0xA3, 0x42, 0xC8, 
+0x09, 0x21, 0x21, 0xC3, 0x2A, 0x24, 0x3A, 0x86, 
+0xBD, 0xB4, 0x8B, 0xCC, 0x83, 0x8A, 0x9C, 0x6E, 
+0x9C, 0x8E, 0x9C, 0x6E, 0x9C, 0x4E, 0x9C, 0x8E, 
+0xBD, 0xB3, 0xC5, 0xB3, 0xBD, 0x72, 0xAD, 0x31, 
+0xB5, 0x52, 0xAD, 0x11, 0xA4, 0xD0, 0xAD, 0x11, 
+0xAD, 0x11, 0xD6, 0x14, 0xCD, 0xB3, 0xC5, 0x72, 
+0xCD, 0xD3, 0xCD, 0xF4, 0xC5, 0xB3, 0xD5, 0xF4, 
+0xD5, 0xF4, 0xA4, 0x6D, 0xB4, 0xEF, 0xDE, 0x54, 
+0xDE, 0x54, 0xC5, 0x92, 0xC5, 0xB2, 0xD6, 0x34, 
+0xD6, 0x34, 0xD6, 0x34, 0xD6, 0x14, 0xE6, 0x96, 
+0xCD, 0xF3, 0xC5, 0x91, 0xC5, 0xB2, 0xD6, 0x34, 
+0x9C, 0x6E, 0xB5, 0x0F, 0xC5, 0xB2, 0xDE, 0x35, 
+0xE6, 0x75, 0xDE, 0x34, 0xCD, 0xF3, 0xCD, 0xD3, 
+0xAC, 0xEF, 0xA4, 0xAD, 0xAD, 0x2F, 0xB5, 0x50, 
+0xB5, 0x2F, 0xC5, 0xF3, 0xE7, 0x38, 0xD6, 0xD7, 
+0xB6, 0x33, 0xB5, 0xB1, 0xAD, 0x2F, 0xB5, 0x30, 
+0xB5, 0x2F, 0x94, 0xAC, 0x6B, 0xE8, 0x42, 0xA6, 
+0x7C, 0x8D, 0x95, 0x2F, 0x9D, 0x2F, 0x95, 0x4E, 
+0x74, 0x89, 0x95, 0x4C, 0xB6, 0x31, 0xB5, 0xD2, 
+0xB5, 0xB3, 0xD6, 0xB6, 0xCE, 0x92, 0xCE, 0x92, 
+0x94, 0xCB, 0x94, 0xAB, 0x94, 0x6B, 0x94, 0x2A, 
+0x94, 0x4B, 0x83, 0xEC, 0xA4, 0xD1, 0x6B, 0x4B, 
+0x6B, 0x0A, 0x83, 0xCC, 0x83, 0xED, 0x9C, 0xAF, 
+0xAD, 0x10, 0xA4, 0xD0, 0x8C, 0x2D, 0xA4, 0xD0, 
+0x9C, 0xD0, 0x94, 0x8F, 0x8C, 0x2E, 0xC6, 0x15, 
+0xBD, 0xD3, 0x8C, 0xED, 0x74, 0x6B, 0x74, 0x6B, 
+0x6C, 0x2A, 0x74, 0x4B, 0xA5, 0xD1, 0xAD, 0xF2, 
+0xA5, 0xB2, 0x95, 0x0F, 0xAD, 0x31, 0xAC, 0xF0, 
+0x8C, 0x2D, 0x9C, 0xAF, 0xAD, 0x32, 0xA4, 0xF1, 
+0xBD, 0xB4, 0xB5, 0x94, 0xAD, 0x73, 0x84, 0x4E, 
+0xCE, 0xB6, 0xB6, 0x13, 0x73, 0xCC, 0x42, 0x87, 
+0x42, 0xC6, 0x43, 0x07, 0x53, 0x48, 0x74, 0x2C, 
+0xDF, 0x16, 0xE7, 0x36, 0xC6, 0x74, 0x9D, 0x0F, 
+0x95, 0x0E, 0xA5, 0x6F, 0x63, 0x48, 0x7B, 0xEA, 
+0x7C, 0x6B, 0x95, 0x30, 0x95, 0x2E, 0x95, 0x4E, 
+0x84, 0x8F, 0xB5, 0xD6, 0x84, 0x50, 0x94, 0xD0, 
+0xC6, 0xB6, 0x7C, 0x8D, 0x6C, 0x08, 0x95, 0x6D, 
+0x53, 0xA6, 0x5B, 0xA7, 0x4A, 0xE6, 0xAD, 0x92, 
+0xB5, 0xB3, 0x84, 0x2D, 0x84, 0xAB, 0x53, 0x85, 
+0x3A, 0xE2, 0x5B, 0xE6, 0xA6, 0x0E, 0x95, 0xAB, 
+0x64, 0x27, 0x11, 0x41, 0x2A, 0x25, 0x19, 0x82, 
+0x42, 0xE6, 0x3A, 0xA5, 0x4B, 0x06, 0x19, 0x81, 
+0x64, 0x48, 0x6C, 0x86, 0x6C, 0x86, 0x9D, 0xCD, 
+0xA5, 0xEF, 0x4A, 0xE5, 0x5B, 0x68, 0x63, 0x88, 
+0x53, 0x27, 0x42, 0x44, 0x4A, 0x46, 0x5B, 0x08, 
+0x84, 0x8C, 0xAE, 0x10, 0xB6, 0x2F, 0xA5, 0xAE, 
+0x3A, 0x65, 0x73, 0xED, 0xA5, 0x73, 0x7C, 0x4E, 
+0x11, 0x62, 0x2A, 0x23, 0x74, 0xCC, 0x85, 0x4D, 
+0x85, 0x4C, 0x6C, 0xA9, 0x8D, 0x8D, 0x95, 0xEE, 
+0x6C, 0x69, 0x43, 0x43, 0x85, 0x6B, 0x95, 0xAD, 
+0x8D, 0x6C, 0x95, 0x8C, 0x8D, 0x2A, 0x95, 0x4B, 
+0x8D, 0x2C, 0xAE, 0x71, 0xAE, 0x71, 0x8D, 0x6D, 
+0x7D, 0x0A, 0x74, 0xE8, 0x8D, 0xAA, 0x8D, 0x69, 
+0x7C, 0xA7, 0x7C, 0xAC, 0x94, 0xF0, 0x94, 0xB1, 
+0x73, 0x6D, 0x52, 0x68, 0x94, 0x2E, 0x9C, 0x6E, 
+0xBD, 0x92, 0xC6, 0x12, 0xAD, 0x8F, 0xB5, 0xB1, 
+0xAD, 0x72, 0xBD, 0xD6, 0xB5, 0x96, 0xD6, 0xBB, 
+0xB5, 0x96, 0x63, 0x2C, 0x9C, 0xCF, 0xCE, 0x50, 
+0xAD, 0x2C, 0x42, 0x05, 0x42, 0x07, 0x42, 0x07, 
+0x73, 0x6C, 0x83, 0xAE, 0x73, 0x4C, 0x18, 0xA2, 
+0x29, 0x24, 0x4A, 0x28, 0x5A, 0xAB, 0x73, 0x4D, 
+0x73, 0x6E, 0x4A, 0x29, 0x52, 0x49, 0x6B, 0x0C, 
+0x5A, 0x8A, 0x7B, 0x8D, 0x73, 0x4D, 0x7B, 0xAE, 
+0x73, 0x6D, 0x94, 0x51, 0x83, 0xCF, 0x83, 0xEF, 
+0x9C, 0xD3, 0xB5, 0x76, 0xC6, 0x18, 0xC6, 0x5A, 
+0xCE, 0xDC, 0xCE, 0xFD, 0xCE, 0xFE, 0xCE, 0xDE, 
+0xCE, 0xDD, 0xCE, 0xFD, 0xCE, 0xDD, 0xC6, 0x9C, 
+0xCE, 0xB9, 0xDF, 0x36, 0xE7, 0x56, 0xBE, 0x10, 
+0xCE, 0x90, 0xCE, 0xAF, 0x8C, 0xC6, 0xA5, 0x89, 
+0xD6, 0xED, 0xE7, 0x6D, 0xD7, 0x2B, 0xAE, 0x28, 
+0xAE, 0x07, 0xB6, 0x6C, 0xC6, 0xD5, 0x9D, 0x74, 
+0xB6, 0x38, 0xBE, 0x5A, 0xC6, 0x59, 0xC5, 0xF6, 
+0x83, 0xED, 0x42, 0x07, 0x41, 0xE8, 0x41, 0xE7, 
+0x83, 0xEF, 0xAD, 0x34, 0x7B, 0xAE, 0x39, 0xE7, 
+0x63, 0xA9, 0x9D, 0x8C, 0xBE, 0x90, 0x8D, 0x6B, 
+0x4B, 0x65, 0x4B, 0x48, 0x6C, 0x2C, 0x3A, 0xA7, 
+0x19, 0xA3, 0x19, 0xA3, 0x2A, 0x04, 0x19, 0x63, 
+0x08, 0xE1, 0x08, 0xC1, 0x21, 0xC4, 0x32, 0x85, 
+0x3A, 0xC5, 0x53, 0xA8, 0x2A, 0x63, 0x22, 0x03, 
+0x11, 0x82, 0x11, 0x42, 0x11, 0x02, 0x11, 0x42, 
+0x21, 0xC4, 0x21, 0xC4, 0x19, 0xA3, 0x4B, 0x09, 
+0xBD, 0x93, 0x83, 0xCC, 0x83, 0xCB, 0xA4, 0xAF, 
+0x9C, 0x4E, 0x8B, 0xED, 0x8C, 0x0D, 0x94, 0x4E, 
+0x9C, 0xAF, 0x8C, 0x0D, 0xA4, 0xD0, 0xA4, 0xD0, 
+0xA4, 0xD0, 0x9C, 0x8F, 0x9C, 0xB0, 0x94, 0x6F, 
+0xAD, 0x11, 0xCD, 0xD4, 0xD5, 0xF4, 0xD5, 0xF4, 
+0xDE, 0x76, 0xE6, 0x96, 0xDE, 0x75, 0xDE, 0x55, 
+0xEE, 0x96, 0xBD, 0x10, 0xAC, 0xEF, 0xDE, 0x54, 
+0xD6, 0x34, 0xCE, 0x13, 0xD6, 0x14, 0xD6, 0x75, 
+0xD6, 0x55, 0xD6, 0x35, 0xD6, 0x34, 0xDE, 0x75, 
+0xD6, 0x34, 0xC5, 0xD3, 0xDE, 0x76, 0xE6, 0xB7, 
+0xB5, 0x31, 0xC5, 0xD3, 0xCE, 0x14, 0xCD, 0xF3, 
+0xD6, 0x14, 0xD6, 0x34, 0xD6, 0x14, 0xDE, 0x34, 
+0x9C, 0xAD, 0x84, 0x07, 0x7C, 0x47, 0x84, 0x68, 
+0x8C, 0x89, 0xA5, 0x6F, 0xCE, 0xF7, 0xAE, 0x14, 
+0x9D, 0xB1, 0xA5, 0x90, 0x9C, 0x8E, 0x9C, 0x8E, 
+0x9C, 0x8D, 0x7C, 0x29, 0x74, 0x49, 0x63, 0xC8, 
+0x74, 0x4B, 0x8C, 0xCD, 0xAD, 0xD0, 0x8C, 0xEB, 
+0x6C, 0x68, 0x7C, 0xA9, 0xBE, 0x71, 0xC6, 0x53, 
+0xC6, 0x34, 0xA5, 0x0F, 0x9C, 0xED, 0xB5, 0xCE, 
+0xC6, 0x70, 0xCE, 0x72, 0xB5, 0x90, 0xA4, 0xCE, 
+0xAD, 0x11, 0xA4, 0xF1, 0x63, 0x0A, 0x7B, 0xCD, 
+0x9C, 0xAF, 0x9C, 0x6E, 0x9C, 0x6E, 0x94, 0x4E, 
+0x9C, 0x4E, 0x9C, 0x6E, 0xA4, 0xAF, 0x94, 0x4E, 
+0x83, 0xEC, 0x83, 0xCC, 0x83, 0xCC, 0x83, 0xAC, 
+0x7B, 0x8A, 0x73, 0xAA, 0x63, 0xC9, 0x84, 0xED, 
+0x8D, 0x2E, 0x8D, 0x0E, 0x9D, 0x70, 0x8D, 0x0F, 
+0x7C, 0xAD, 0x8C, 0xCE, 0x9C, 0xCF, 0xA4, 0xEF, 
+0x9C, 0x8E, 0x83, 0xEC, 0x94, 0x6F, 0xA4, 0xF1, 
+0xAD, 0x73, 0x9C, 0xB0, 0x8C, 0x4F, 0x7C, 0x0D, 
+0xC6, 0x95, 0xCE, 0xF6, 0x95, 0x70, 0x4B, 0x28, 
+0x5B, 0xA9, 0x6C, 0x4C, 0x74, 0x6C, 0x7C, 0x6C, 
+0x84, 0x8D, 0x5B, 0x88, 0x42, 0xE5, 0x84, 0x6E, 
+0x94, 0xF0, 0xA5, 0x31, 0x7B, 0xEC, 0x6B, 0x6A, 
+0xA5, 0x53, 0xCE, 0xDB, 0xAD, 0xD6, 0xAD, 0xD4, 
+0x63, 0xAC, 0x6B, 0xCD, 0x6B, 0xAC, 0x6B, 0xAB, 
+0x6B, 0x8A, 0x6B, 0x8A, 0x6B, 0xEA, 0x84, 0xEB, 
+0x84, 0xCB, 0x32, 0x24, 0x5B, 0x09, 0xA5, 0x72, 
+0x84, 0x6D, 0x6B, 0xEA, 0x63, 0xE8, 0x53, 0xA5, 
+0x6C, 0x88, 0x6C, 0x87, 0x9D, 0xCD, 0x9D, 0xCD, 
+0x4B, 0x05, 0x11, 0x21, 0x19, 0xA2, 0x3A, 0x85, 
+0x4B, 0x66, 0x5B, 0xE8, 0x63, 0xE8, 0x19, 0x41, 
+0x74, 0xAA, 0x7D, 0x29, 0x95, 0xCD, 0xA6, 0x0F, 
+0x9D, 0xAE, 0x74, 0x29, 0x29, 0xA2, 0x52, 0xC7, 
+0x31, 0xE3, 0x4A, 0x45, 0x62, 0xE7, 0x63, 0x48, 
+0x63, 0xA8, 0xA5, 0xAE, 0xBE, 0x91, 0x6B, 0xC9, 
+0x21, 0x83, 0x63, 0x6C, 0xA5, 0x53, 0x84, 0x6F, 
+0x19, 0x82, 0x32, 0x84, 0x53, 0xA7, 0x6C, 0xAA, 
+0x7D, 0x0C, 0x9D, 0xF0, 0xA6, 0x30, 0x53, 0xC6, 
+0x32, 0xE3, 0x33, 0x02, 0x4B, 0xA6, 0x64, 0x28, 
+0x74, 0xAA, 0x85, 0x2B, 0x85, 0x0A, 0x7C, 0xC9, 
+0x64, 0x27, 0x85, 0x2C, 0xBE, 0xD3, 0xA6, 0x30, 
+0x95, 0xAE, 0x8D, 0x8C, 0x8D, 0x6A, 0x74, 0xA6, 
+0x64, 0x45, 0x64, 0x06, 0x7C, 0x4A, 0x9C, 0xCE, 
+0x6B, 0x09, 0x94, 0x8D, 0x94, 0x8B, 0x94, 0x8B, 
+0x8C, 0x6A, 0x7C, 0x28, 0xA5, 0x6E, 0x84, 0x4B, 
+0x8C, 0x8E, 0x9D, 0x11, 0xBD, 0xD6, 0xCE, 0x79, 
+0xC6, 0x18, 0xC5, 0xF7, 0xC6, 0x14, 0xCE, 0x31, 
+0xBD, 0xAD, 0x7B, 0xC9, 0x8C, 0x2D, 0x52, 0x48, 
+0x62, 0xEB, 0x94, 0x70, 0x6B, 0x0B, 0x18, 0xA2, 
+0x29, 0x24, 0x5A, 0x8A, 0x7B, 0x8E, 0x73, 0x6E, 
+0x73, 0x6E, 0x6B, 0x2D, 0x52, 0x49, 0x5A, 0xCB, 
+0x73, 0x4D, 0xAC, 0xF3, 0x94, 0x50, 0x62, 0xEB, 
+0x5A, 0x8A, 0x73, 0x6D, 0x83, 0xF0, 0x84, 0x10, 
+0x94, 0x92, 0xAD, 0x55, 0xBD, 0xD6, 0xAD, 0x55, 
+0xAD, 0x96, 0xB5, 0xF7, 0xBE, 0x7A, 0xBE, 0x5B, 
+0xBE, 0x5C, 0xBE, 0x5C, 0xBE, 0x7B, 0xCE, 0xDA, 
+0xBE, 0x55, 0xE7, 0x56, 0xE7, 0x54, 0xD6, 0xF2, 
+0xCE, 0xB0, 0xB5, 0xEC, 0x8C, 0xE7, 0xB6, 0x2E, 
+0xCF, 0x10, 0xD6, 0xED, 0xDF, 0x2C, 0xBE, 0x68, 
+0xB6, 0x47, 0xB6, 0x6C, 0xBE, 0xD5, 0xC6, 0xB9, 
+0xB6, 0x18, 0xCE, 0xDB, 0xCE, 0xDB, 0xCE, 0x99, 
+0xA5, 0x34, 0x63, 0x4C, 0x31, 0xA6, 0x5A, 0xCB, 
+0x9C, 0x91, 0xB5, 0x54, 0x7B, 0xCF, 0x31, 0xA5, 
+0x74, 0x6A, 0x8D, 0x6B, 0xBE, 0xB2, 0xA6, 0x10, 
+0x4B, 0x45, 0x32, 0x64, 0x2A, 0x04, 0x42, 0xC7, 
+0x3A, 0x86, 0x21, 0xE3, 0x2A, 0x05, 0x11, 0x62, 
+0x11, 0x42, 0x11, 0x22, 0x32, 0x45, 0x2A, 0x44, 
+0x2A, 0x84, 0x53, 0xE8, 0x2A, 0xA4, 0x11, 0x81, 
+0x11, 0x42, 0x11, 0x43, 0x19, 0x83, 0x19, 0x83, 
+0x21, 0xE4, 0x19, 0x83, 0x19, 0xA4, 0x4B, 0x09, 
+0xC5, 0xB4, 0x8B, 0xEC, 0x83, 0xCB, 0x9C, 0x4D, 
+0x9C, 0x6E, 0xA4, 0xD0, 0x9C, 0x8F, 0x9C, 0x8F, 
+0x9C, 0x8F, 0x5A, 0x88, 0x94, 0x6F, 0x9C, 0xB0, 
+0xA4, 0xB0, 0xA4, 0xB0, 0x9C, 0x8F, 0xA4, 0xD0, 
+0xAD, 0x11, 0xBD, 0x72, 0xB5, 0x31, 0xA4, 0xAF, 
+0xC5, 0x92, 0xCD, 0xD3, 0xCD, 0xB3, 0xCD, 0x92, 
+0xE6, 0x55, 0xC5, 0x72, 0xB5, 0x10, 0xDE, 0x55, 
+0xD6, 0x34, 0xD6, 0x55, 0xD6, 0x35, 0xD6, 0x75, 
+0xCE, 0x35, 0xB5, 0x52, 0xC5, 0xF4, 0xDE, 0x76, 
+0xD6, 0x55, 0xD6, 0x75, 0xDE, 0xB7, 0xE6, 0xD7, 
+0xC5, 0xD4, 0xB5, 0x52, 0xC5, 0xD3, 0xDE, 0x55, 
+0xDE, 0x54, 0xDE, 0x74, 0xD6, 0x54, 0xDE, 0x55, 
+0x9C, 0x8C, 0x94, 0xAA, 0x8C, 0xCA, 0x7C, 0xA8, 
+0x7C, 0x87, 0x74, 0x88, 0x7C, 0xCC, 0x95, 0x90, 
+0xA5, 0xD1, 0x8C, 0x8D, 0x83, 0xEB, 0x83, 0xEB, 
+0x73, 0xC9, 0x9D, 0x2E, 0x7C, 0x8B, 0x74, 0x2A, 
+0x95, 0x2E, 0x7C, 0x6A, 0x74, 0x68, 0x74, 0xA8, 
+0x7C, 0xC8, 0x7C, 0xA8, 0xA5, 0xEE, 0xC6, 0x73, 
+0x8C, 0x4D, 0x94, 0x4C, 0x94, 0x6C, 0xA4, 0xEC, 
+0xAD, 0x4C, 0xA5, 0x2D, 0x94, 0x6D, 0x94, 0x4E, 
+0xBD, 0x94, 0x6B, 0x2B, 0x73, 0x8C, 0x84, 0x0E, 
+0x62, 0xEA, 0x6B, 0x2A, 0x8B, 0xED, 0x62, 0xC9, 
+0x5A, 0x88, 0x7B, 0x6B, 0x9C, 0x8F, 0x8B, 0xEC, 
+0xA4, 0xCF, 0x9C, 0x6E, 0x9C, 0x8E, 0xB5, 0x71, 
+0xA4, 0xCF, 0xAD, 0x30, 0x63, 0xA9, 0x7C, 0xAC, 
+0x84, 0xCD, 0x95, 0x6F, 0x84, 0xED, 0x84, 0xCD, 
+0x8D, 0x2E, 0x94, 0xEE, 0x9C, 0xED, 0x9D, 0x0C, 
+0xA5, 0x2D, 0xA5, 0x2E, 0x9C, 0xEE, 0x94, 0x8E, 
+0x8C, 0x4D, 0x83, 0xEC, 0x83, 0xEC, 0x94, 0xAF, 
+0xA5, 0xB2, 0x9D, 0x90, 0xA5, 0xD0, 0x9D, 0xB0, 
+0x84, 0xEE, 0x8D, 0x2F, 0x7C, 0xAD, 0x4B, 0x47, 
+0x43, 0x06, 0x3B, 0x06, 0x43, 0x06, 0x84, 0xAE, 
+0x95, 0x10, 0x8C, 0x6E, 0x73, 0xCC, 0x6B, 0x6A, 
+0xAD, 0xD5, 0xC6, 0x79, 0xB6, 0x18, 0xAD, 0xF5, 
+0x7C, 0xAD, 0x84, 0xEC, 0x7C, 0xAB, 0x84, 0xCC, 
+0x9D, 0x2D, 0xB6, 0x31, 0xAD, 0xF0, 0x6C, 0x48, 
+0x64, 0x07, 0x4B, 0x26, 0x74, 0x6B, 0x8C, 0xED, 
+0x85, 0x0D, 0x6C, 0x4A, 0x5B, 0xE7, 0x8D, 0x8C, 
+0x7D, 0x09, 0x5C, 0x45, 0x4B, 0xA3, 0x53, 0xE5, 
+0x5B, 0xE8, 0x3A, 0xA4, 0x32, 0x23, 0x4B, 0x26, 
+0x32, 0xA3, 0x6C, 0x69, 0x2A, 0x23, 0x21, 0xA2, 
+0x85, 0x0C, 0xAE, 0x70, 0xAE, 0x70, 0xAE, 0x50, 
+0xA6, 0x0F, 0x7C, 0xCA, 0x4A, 0xC5, 0x63, 0x28, 
+0x5B, 0x27, 0x52, 0x86, 0x39, 0xA3, 0x42, 0x25, 
+0x42, 0x45, 0x32, 0x44, 0x4A, 0xE6, 0x32, 0x44, 
+0x29, 0xE4, 0x32, 0x06, 0x4A, 0xA8, 0x42, 0xA8, 
+0x32, 0x85, 0x3A, 0xE5, 0x4B, 0xA7, 0x7D, 0x0C, 
+0x9E, 0x30, 0x9E, 0x10, 0x6C, 0x6A, 0x2A, 0x82, 
+0x22, 0x41, 0x22, 0x41, 0x22, 0x42, 0x32, 0xC3, 
+0x43, 0x66, 0x53, 0xC7, 0x64, 0x47, 0x43, 0x64, 
+0x53, 0xE6, 0x85, 0x4C, 0x9D, 0xEF, 0x7C, 0xEC, 
+0xA6, 0x51, 0x8D, 0x6E, 0x74, 0xEB, 0x5C, 0x06, 
+0x5C, 0x27, 0x63, 0xE8, 0x4A, 0xA4, 0x83, 0xEA, 
+0x9C, 0xCC, 0xA5, 0x4D, 0x8C, 0x49, 0x5B, 0x06, 
+0x52, 0xA6, 0x5A, 0xC7, 0xA4, 0xAF, 0x94, 0x6F, 
+0x62, 0xEA, 0x83, 0xEE, 0x83, 0xEF, 0x8C, 0x51, 
+0xA5, 0x14, 0xDE, 0xFB, 0xC5, 0xF6, 0xA4, 0xF0, 
+0xB5, 0x6F, 0x94, 0xAD, 0xAD, 0x30, 0x6B, 0x0A, 
+0x4A, 0x27, 0x73, 0x6C, 0x29, 0x44, 0x18, 0xA2, 
+0x29, 0x24, 0x5A, 0xAA, 0x8C, 0x30, 0x73, 0x6E, 
+0x84, 0x10, 0x84, 0x10, 0x6B, 0x0C, 0x52, 0x6A, 
+0x62, 0xCB, 0x7B, 0xAE, 0xB5, 0x75, 0x7B, 0x8E, 
+0x73, 0x6D, 0x9C, 0xB3, 0x9C, 0xD3, 0x94, 0x72, 
+0x8C, 0x31, 0x7B, 0xEF, 0xA5, 0x34, 0x8C, 0x72, 
+0x84, 0x10, 0x8C, 0x71, 0xB5, 0xD7, 0xBE, 0x19, 
+0xB5, 0xFA, 0xAD, 0xD8, 0xD6, 0xD9, 0xE7, 0x37, 
+0xE7, 0x54, 0xCE, 0x8F, 0xD6, 0xCF, 0xD6, 0xF0, 
+0xCE, 0x8F, 0xC6, 0x4D, 0xB6, 0x2D, 0xC6, 0xD1, 
+0xB6, 0x6E, 0xAE, 0x09, 0xCE, 0xEA, 0xB6, 0x25, 
+0xAE, 0x26, 0xAE, 0x4C, 0xAE, 0x32, 0xBE, 0x56, 
+0xBE, 0x57, 0xD7, 0x19, 0xE7, 0x79, 0xD6, 0xD7, 
+0xC6, 0x76, 0xB6, 0x34, 0x8C, 0xB0, 0x9C, 0xD3, 
+0xC5, 0xD6, 0xB5, 0x75, 0x7B, 0xAE, 0x31, 0xE5, 
+0x7C, 0xCA, 0x7D, 0x07, 0x95, 0x8B, 0x9D, 0xEE, 
+0x6C, 0x69, 0x19, 0xC2, 0x11, 0x62, 0x21, 0xC4, 
+0x3A, 0xA7, 0x3A, 0x86, 0x2A, 0x25, 0x19, 0xA3, 
+0x21, 0xE4, 0x21, 0xC3, 0x32, 0x45, 0x2A, 0x23, 
+0x32, 0xA4, 0x43, 0x66, 0x32, 0xC4, 0x11, 0x41, 
+0x11, 0x42, 0x11, 0x62, 0x19, 0xA3, 0x19, 0x83, 
+0x11, 0x42, 0x11, 0x42, 0x2A, 0x46, 0x4B, 0x29, 
+0xC5, 0xB3, 0x8B, 0xEC, 0x83, 0xCC, 0x9C, 0x6E, 
+0x8C, 0x0D, 0x8C, 0x0D, 0x84, 0x0D, 0x94, 0x2E, 
+0x94, 0x4E, 0x62, 0xE9, 0x83, 0xAC, 0x94, 0x6F, 
+0x94, 0x6F, 0x94, 0x4E, 0x94, 0x2E, 0x9C, 0x8F, 
+0xAC, 0xF1, 0xAD, 0x11, 0xBD, 0x52, 0xBD, 0x72, 
+0xBD, 0x72, 0xC5, 0xB3, 0xC5, 0xB3, 0xCD, 0xB3, 
+0xDE, 0x55, 0xC5, 0x92, 0xA4, 0xCF, 0xD6, 0x34, 
+0xCD, 0xF3, 0xC5, 0xF3, 0xCE, 0x34, 0xD6, 0x55, 
+0xBD, 0xD4, 0x94, 0x90, 0xAD, 0x52, 0xD6, 0x76, 
+0xDE, 0x96, 0xDE, 0xB7, 0xBD, 0xB3, 0xD6, 0x76, 
+0xD6, 0x55, 0xC5, 0xD3, 0xCE, 0x14, 0xDE, 0x55, 
+0xD6, 0x34, 0xD6, 0x54, 0xD6, 0x34, 0xD6, 0x34, 
+0x9C, 0x8D, 0xA5, 0x0D, 0xA5, 0x4E, 0x84, 0x8A, 
+0x84, 0xAA, 0x7C, 0x69, 0x53, 0x66, 0x6C, 0x2A, 
+0xA5, 0xB0, 0x9C, 0xEF, 0x94, 0x6E, 0x94, 0x6D, 
+0x7C, 0x2A, 0xA5, 0x4F, 0x9D, 0x2F, 0xA5, 0x90, 
+0x84, 0xAC, 0x4B, 0x44, 0x5C, 0x04, 0x53, 0xE3, 
+0x6C, 0x87, 0x85, 0x09, 0x8D, 0x2C, 0xCE, 0xB5, 
+0x7B, 0xCA, 0x9C, 0x6D, 0xA4, 0xEF, 0x9C, 0xAE, 
+0x94, 0x4D, 0x94, 0x6E, 0x8C, 0x0E, 0xB5, 0x94, 
+0x7B, 0xAD, 0x73, 0x6C, 0x9C, 0xB1, 0x7B, 0xCD, 
+0x52, 0x88, 0x7B, 0xAD, 0xA4, 0xD0, 0x9C, 0xB0, 
+0x83, 0xCC, 0x73, 0x8B, 0x73, 0x4A, 0x6A, 0xE9, 
+0x5A, 0x88, 0x73, 0xAA, 0x8C, 0xAD, 0xB5, 0xD2, 
+0xAD, 0x92, 0xA5, 0x30, 0x63, 0x89, 0x74, 0x2B, 
+0x8D, 0x0E, 0x8D, 0x2E, 0x85, 0x0D, 0x85, 0x0D, 
+0x6B, 0xEA, 0x63, 0x68, 0x84, 0x8A, 0x84, 0xA9, 
+0x84, 0xA9, 0x95, 0x2C, 0x9D, 0x6E, 0xAD, 0x90, 
+0xAD, 0x91, 0x8C, 0x2D, 0x83, 0xEC, 0xC6, 0x35, 
+0xAD, 0xF3, 0x7C, 0xCC, 0x85, 0x0C, 0x8D, 0x2E, 
+0x95, 0x6F, 0x7C, 0xAC, 0x5B, 0xE9, 0x42, 0xE6, 
+0x4B, 0x26, 0x4B, 0x67, 0x53, 0xA8, 0x4B, 0x69, 
+0x84, 0xCF, 0xA5, 0xB2, 0x9D, 0x30, 0x9D, 0x10, 
+0x7C, 0x0E, 0x94, 0xF3, 0x9D, 0x54, 0x95, 0x70, 
+0x84, 0xEA, 0x64, 0x26, 0x5C, 0x06, 0x7D, 0x0A, 
+0x6C, 0x88, 0x64, 0x47, 0x4B, 0x84, 0x32, 0xE2, 
+0x3A, 0xE2, 0x6C, 0x48, 0x7C, 0xAB, 0x9D, 0xD0, 
+0xA6, 0x31, 0x9D, 0xD0, 0x9D, 0xCF, 0x9D, 0xEE, 
+0x85, 0x6B, 0x74, 0xE8, 0x64, 0x87, 0x74, 0xC9, 
+0xA6, 0x2F, 0x5C, 0x07, 0x43, 0x24, 0x43, 0x04, 
+0x5B, 0xE7, 0x6C, 0x49, 0x19, 0x61, 0x19, 0xA2, 
+0x95, 0x8F, 0xAE, 0x50, 0xAE, 0x51, 0xAE, 0x50, 
+0xAE, 0x71, 0x8D, 0x4C, 0x53, 0x05, 0x42, 0x85, 
+0x6B, 0xA9, 0x29, 0x62, 0x4A, 0x46, 0x6B, 0x69, 
+0x5B, 0x27, 0x3A, 0x85, 0x2A, 0x04, 0x2A, 0x04, 
+0x32, 0x45, 0x21, 0xC4, 0x19, 0x83, 0x3A, 0x86, 
+0x4B, 0x87, 0x53, 0xC7, 0x6C, 0xAA, 0x9D, 0xF0, 
+0x74, 0xAC, 0x3A, 0xC5, 0x2A, 0x83, 0x2A, 0x63, 
+0x22, 0x42, 0x22, 0x42, 0x32, 0xA3, 0x3A, 0xE4, 
+0x43, 0x46, 0x53, 0xE7, 0x7C, 0xEA, 0x53, 0xC5, 
+0x3B, 0x03, 0x3B, 0x24, 0x4B, 0x86, 0x3A, 0xC5, 
+0x9D, 0xF1, 0x9D, 0xF0, 0x8D, 0x6E, 0x8D, 0x4D, 
+0x6C, 0x49, 0x9D, 0x6E, 0x6B, 0xA8, 0x9D, 0x2D, 
+0x95, 0x0C, 0xB6, 0x10, 0xC6, 0x72, 0xAD, 0xB1, 
+0x5A, 0xC9, 0x62, 0x89, 0x6A, 0xC9, 0xA4, 0x91, 
+0x9C, 0x50, 0x5A, 0xCA, 0x83, 0xEF, 0x63, 0x2C, 
+0x94, 0x72, 0xC6, 0x38, 0xD6, 0x79, 0xB5, 0x75, 
+0xBD, 0xB6, 0xBD, 0xD6, 0xAD, 0x73, 0x6B, 0x2B, 
+0x6B, 0x2B, 0x62, 0xEB, 0x20, 0xE3, 0x39, 0xC7, 
+0x18, 0xC2, 0x4A, 0x48, 0x7B, 0xAE, 0x7B, 0xAE, 
+0x8C, 0x30, 0x94, 0x51, 0x83, 0xF0, 0x73, 0x4D, 
+0x6B, 0x4D, 0x42, 0x08, 0xA4, 0xF3, 0x8C, 0x30, 
+0x8C, 0x30, 0xAD, 0x55, 0xA4, 0xD4, 0x9C, 0xD3, 
+0x9C, 0x93, 0x6B, 0x4D, 0x7B, 0xF0, 0x9C, 0xB3, 
+0x94, 0x72, 0x94, 0x92, 0xA5, 0x14, 0xC6, 0x38, 
+0xB5, 0xD6, 0xDF, 0x18, 0xF7, 0x96, 0xEF, 0x32, 
+0xEF, 0x72, 0xDF, 0x0E, 0xD6, 0xAD, 0xEF, 0x71, 
+0xAD, 0x6B, 0xD6, 0xEE, 0xB6, 0x4D, 0xBE, 0xB1, 
+0xC6, 0xD0, 0xA5, 0xE8, 0xAE, 0x05, 0xA6, 0x04, 
+0x8D, 0x23, 0x95, 0x88, 0x95, 0x6D, 0xB6, 0x54, 
+0xBE, 0x96, 0xC6, 0x75, 0xD6, 0xD5, 0xE7, 0x97, 
+0xE7, 0x77, 0xB6, 0x32, 0xAD, 0xD4, 0xB5, 0xB6, 
+0xBD, 0xB6, 0xA5, 0x13, 0x63, 0x0C, 0x5B, 0x29, 
+0x95, 0x6D, 0x8D, 0x8A, 0x85, 0x27, 0x85, 0x49, 
+0x6C, 0x68, 0x19, 0xE2, 0x11, 0x82, 0x11, 0x62, 
+0x3A, 0xA7, 0x4B, 0x08, 0x32, 0x45, 0x19, 0xC3, 
+0x22, 0x04, 0x2A, 0x24, 0x21, 0xE3, 0x32, 0x64, 
+0x32, 0x84, 0x3B, 0x25, 0x22, 0x23, 0x11, 0x41, 
+0x11, 0x42, 0x11, 0x42, 0x21, 0xC4, 0x19, 0xA3, 
+0x11, 0x62, 0x21, 0xC4, 0x32, 0x66, 0x42, 0xE8, 
+0x9C, 0x6E, 0x83, 0x8A, 0x83, 0xAB, 0x7B, 0x8A, 
+0x6B, 0x29, 0x73, 0x4A, 0x8C, 0x2D, 0xAC, 0xF0, 
+0xBD, 0x52, 0xAC, 0xF0, 0xAC, 0xD0, 0xAC, 0xF1, 
+0xB5, 0x11, 0xAC, 0xF1, 0xA4, 0xAF, 0x94, 0x2E, 
+0xA4, 0xAF, 0xAC, 0xF0, 0xA4, 0xAF, 0x9C, 0x6E, 
+0xA4, 0xB0, 0xAC, 0xD0, 0xBD, 0x51, 0xC5, 0xB2, 
+0xE6, 0x76, 0xC5, 0x92, 0xAD, 0x10, 0xCD, 0xF3, 
+0xCD, 0xF3, 0xC5, 0xD3, 0xC5, 0xF3, 0xC5, 0xF4, 
+0xAD, 0x52, 0xA5, 0x12, 0xAD, 0x52, 0xC6, 0x15, 
+0xD6, 0x55, 0xDE, 0xB7, 0xDE, 0x96, 0xD6, 0x55, 
+0xDE, 0x96, 0xDE, 0x76, 0xCE, 0x34, 0xD6, 0x34, 
+0xCD, 0xF4, 0xC5, 0xD3, 0xBD, 0xB2, 0xC5, 0xD3, 
+0xA4, 0xAE, 0xA4, 0xEE, 0xA4, 0xEE, 0x9C, 0xEE, 
+0xA5, 0x0E, 0x9C, 0xEE, 0x6B, 0xA9, 0x4B, 0x06, 
+0x74, 0x2B, 0xB5, 0xB2, 0xB5, 0x31, 0xBD, 0x92, 
+0x9C, 0xEF, 0xBD, 0xF2, 0x9D, 0x0F, 0x6C, 0x2A, 
+0x43, 0x04, 0x43, 0x23, 0x4B, 0xA3, 0x53, 0xA4, 
+0x5B, 0xE6, 0x95, 0x4D, 0x84, 0x4C, 0xC6, 0x35, 
+0x6B, 0x29, 0xAD, 0x10, 0xAD, 0x10, 0x7B, 0xAB, 
+0x8C, 0x0D, 0x9C, 0xB0, 0xAD, 0x33, 0x84, 0x0E, 
+0x63, 0x0A, 0x94, 0x90, 0x94, 0x90, 0x62, 0xEA, 
+0x4A, 0x68, 0x5A, 0xC9, 0x94, 0x6F, 0xA5, 0x11, 
+0xAD, 0x51, 0x94, 0xAE, 0x94, 0x6E, 0x6B, 0x2A, 
+0x31, 0xA5, 0x5B, 0x49, 0x9D, 0x70, 0x84, 0xEF, 
+0x9D, 0x92, 0x94, 0xF0, 0x63, 0x69, 0x6B, 0x8A, 
+0x74, 0x2C, 0x63, 0xC9, 0x84, 0xED, 0x7C, 0xCC, 
+0x7C, 0x4B, 0x84, 0x8B, 0x7C, 0xA9, 0x84, 0xC8, 
+0x7C, 0xC8, 0x84, 0xEA, 0x95, 0x6D, 0xA5, 0xAF, 
+0xBE, 0x12, 0x5A, 0xE8, 0x84, 0x0E, 0xCE, 0xB7, 
+0xC6, 0xB5, 0x74, 0x49, 0x7C, 0xAA, 0x95, 0x2D, 
+0xBE, 0x73, 0x9D, 0x8E, 0x6C, 0x4A, 0x64, 0x2B, 
+0x64, 0x2B, 0x64, 0x2B, 0x85, 0x0D, 0x7C, 0xCE, 
+0x84, 0xEE, 0x8D, 0x2F, 0xA5, 0xB2, 0xAD, 0xD3, 
+0x84, 0x6F, 0x95, 0x12, 0xB6, 0x34, 0x85, 0x0B, 
+0x5B, 0xE4, 0x5B, 0xE5, 0x74, 0xE8, 0x64, 0x46, 
+0x4B, 0xA3, 0x43, 0x63, 0x32, 0xE2, 0x5C, 0x27, 
+0x53, 0xE5, 0x85, 0x2B, 0x8D, 0x4D, 0x9D, 0xF0, 
+0xA6, 0x11, 0xA6, 0x11, 0xA6, 0x31, 0x7C, 0xEA, 
+0x7D, 0x2A, 0x74, 0xE9, 0x74, 0xC9, 0x9D, 0xCE, 
+0x95, 0xAE, 0x74, 0xAA, 0x7D, 0x0B, 0x64, 0x28, 
+0x85, 0x4C, 0x64, 0x09, 0x19, 0x61, 0x21, 0xA3, 
+0x42, 0xE6, 0x3A, 0xA4, 0x42, 0xE5, 0x6C, 0x2A, 
+0xA6, 0x0F, 0x9D, 0xCE, 0x63, 0xE7, 0x4B, 0x25, 
+0x84, 0xCB, 0x42, 0xC5, 0x31, 0xE3, 0x4A, 0xC6, 
+0x29, 0xC2, 0x42, 0xA6, 0x32, 0x44, 0x2A, 0x04, 
+0x3A, 0xA7, 0x32, 0x66, 0x32, 0x45, 0x43, 0x07, 
+0x53, 0xA8, 0x2A, 0x63, 0x43, 0x05, 0x32, 0x85, 
+0x2A, 0x24, 0x3A, 0xA5, 0x22, 0x42, 0x22, 0x22, 
+0x22, 0x22, 0x2A, 0x83, 0x43, 0x25, 0x4B, 0xA6, 
+0x64, 0x69, 0x74, 0xCA, 0xAE, 0x50, 0x64, 0x47, 
+0x43, 0x44, 0x2A, 0xA2, 0x2A, 0x62, 0x2A, 0x43, 
+0x7C, 0xED, 0xAE, 0x93, 0x9D, 0xF1, 0xAE, 0x52, 
+0x84, 0xED, 0x7C, 0xAB, 0x95, 0x4D, 0x95, 0x6D, 
+0x95, 0x8E, 0xC7, 0x15, 0xA5, 0xD0, 0x8C, 0xCD, 
+0x73, 0x6B, 0x5A, 0x48, 0x49, 0xE7, 0x8B, 0xAE, 
+0xAC, 0xB1, 0x83, 0xAE, 0x5A, 0x8A, 0x52, 0x8A, 
+0x7B, 0xCE, 0x73, 0x8E, 0x9C, 0xD3, 0xD6, 0x99, 
+0xD6, 0xBA, 0xBD, 0xD7, 0x84, 0x0F, 0x4A, 0x68, 
+0x73, 0x6D, 0x6B, 0x0B, 0x29, 0x24, 0x29, 0x45, 
+0x10, 0x82, 0x31, 0x65, 0x62, 0xCA, 0x7B, 0xAE, 
+0x94, 0x72, 0xA4, 0xD3, 0xA4, 0xD3, 0x7B, 0xAE, 
+0x73, 0x4D, 0x73, 0x6D, 0x52, 0x6A, 0x9C, 0x92, 
+0x7B, 0xAE, 0x8C, 0x51, 0xA5, 0x14, 0x94, 0x72, 
+0x8C, 0x31, 0x84, 0x10, 0x94, 0x72, 0xAD, 0x55, 
+0xBD, 0x97, 0xC5, 0xF8, 0xAD, 0x55, 0xAD, 0x55, 
+0xAD, 0x74, 0xDE, 0xF5, 0xE7, 0x33, 0xEF, 0x72, 
+0xDF, 0x0F, 0xCE, 0x8C, 0xDF, 0x0E, 0xEF, 0x71, 
+0x8C, 0xA7, 0xC6, 0xAD, 0xAE, 0x2B, 0xBE, 0xB0, 
+0xAE, 0x4D, 0x9D, 0xC6, 0x9D, 0xA3, 0xAE, 0x46, 
+0xA5, 0xE8, 0xA6, 0x0B, 0xB6, 0x8F, 0xB6, 0x93, 
+0xAD, 0xF2, 0xCE, 0xF7, 0xC6, 0xB5, 0xB6, 0x51, 
+0xD6, 0xF2, 0xBE, 0x71, 0xA5, 0x92, 0xC6, 0x38, 
+0xBD, 0xB6, 0x8C, 0x71, 0x4A, 0x49, 0x74, 0x2D, 
+0xAE, 0x51, 0x9D, 0xED, 0x85, 0x27, 0x8D, 0xAA, 
+0x7D, 0x2A, 0x43, 0x24, 0x19, 0xC1, 0x11, 0x62, 
+0x42, 0xC7, 0x5B, 0xCA, 0x32, 0x66, 0x11, 0x21, 
+0x19, 0xC3, 0x19, 0xA3, 0x11, 0x41, 0x32, 0xA5, 
+0x22, 0x43, 0x32, 0xC4, 0x11, 0x61, 0x11, 0x22, 
+0x09, 0x22, 0x11, 0x22, 0x22, 0x04, 0x21, 0xE3, 
+0x19, 0xA3, 0x2A, 0x25, 0x3A, 0xA7, 0x53, 0x6A, 
+0x8B, 0xAB, 0x8B, 0xEC, 0x8B, 0xEC, 0x8B, 0xEC, 
+0x8C, 0x0C, 0x8B, 0xEC, 0x8B, 0xCC, 0x8B, 0xCB, 
+0x8B, 0xCC, 0x8B, 0xCC, 0x83, 0x8A, 0x7B, 0x6A, 
+0x7B, 0x6A, 0x7B, 0x6A, 0x83, 0xAB, 0x7B, 0x6A, 
+0x83, 0x8B, 0x8B, 0xCB, 0x8B, 0xEC, 0x8B, 0xCC, 
+0x83, 0xAB, 0x9C, 0x4D, 0xB5, 0x10, 0xCD, 0xD3, 
+0xD5, 0xF3, 0xBD, 0x30, 0xAC, 0xAE, 0xB5, 0x50, 
+0xC5, 0xB2, 0xC5, 0xD3, 0xC5, 0xF4, 0xBD, 0xB3, 
+0xAD, 0x32, 0xAD, 0x53, 0xAD, 0x52, 0xB5, 0x93, 
+0xBD, 0xD3, 0xD6, 0x55, 0xDE, 0xD7, 0xDE, 0xB7, 
+0xDE, 0x96, 0xD6, 0x55, 0xC5, 0xF3, 0xBD, 0xB3, 
+0xBD, 0x93, 0xB5, 0x72, 0xAD, 0x31, 0xAD, 0x31, 
+0xA4, 0xCF, 0xA4, 0xCE, 0xA4, 0xEF, 0xAD, 0x10, 
+0xA4, 0xCF, 0xAD, 0x30, 0x84, 0x0B, 0x3A, 0xA4, 
+0x3A, 0x84, 0x94, 0xCF, 0xBD, 0xB3, 0xBD, 0x72, 
+0xBD, 0xB3, 0xC5, 0xF3, 0xAD, 0x71, 0x42, 0xA4, 
+0x3A, 0xC3, 0x43, 0x23, 0x4B, 0x85, 0x5B, 0xA7, 
+0x9D, 0x2F, 0xBD, 0xF3, 0x83, 0xEC, 0xAD, 0x52, 
+0x5A, 0xA8, 0xAD, 0x10, 0xA4, 0xAE, 0x8C, 0x0D, 
+0x9C, 0xB0, 0x9C, 0xB0, 0xA4, 0xD1, 0x5A, 0xA9, 
+0x8C, 0x4F, 0x9C, 0xD1, 0x8C, 0x2F, 0x5A, 0xEA, 
+0xA5, 0x32, 0xA5, 0x71, 0x94, 0xAE, 0x94, 0xAE, 
+0xAD, 0xB1, 0xAD, 0x90, 0x94, 0x8E, 0x6B, 0x0A, 
+0x31, 0xA6, 0x3A, 0x26, 0x9D, 0x91, 0x7C, 0x8D, 
+0x6C, 0x6C, 0x5B, 0x89, 0x74, 0x0C, 0x5B, 0x29, 
+0x7C, 0x4D, 0x6B, 0xEB, 0x7C, 0x8B, 0x74, 0x69, 
+0x7C, 0x89, 0x7C, 0xA9, 0x7C, 0x69, 0x7C, 0x88, 
+0x7C, 0xA8, 0x84, 0xEA, 0x9D, 0x8E, 0xCE, 0xF5, 
+0xD7, 0x16, 0xBD, 0xF4, 0xAD, 0x73, 0x8C, 0xCF, 
+0x63, 0xA9, 0x74, 0x49, 0x95, 0x0C, 0xA5, 0x4E, 
+0xB5, 0xB1, 0x8D, 0x0D, 0x7C, 0xCC, 0x74, 0x8D, 
+0x7C, 0xCE, 0x74, 0x6C, 0x64, 0x2A, 0x6C, 0x6B, 
+0x74, 0x8C, 0x7C, 0xAD, 0x8D, 0x2F, 0x7C, 0xAD, 
+0x74, 0x0C, 0x95, 0x4F, 0x8D, 0x4C, 0x5C, 0x05, 
+0x5C, 0x25, 0x7D, 0x09, 0x53, 0xE4, 0x53, 0xC4, 
+0x64, 0x27, 0x74, 0x8B, 0x63, 0xC8, 0x6C, 0xA8, 
+0x4B, 0xA4, 0x64, 0x27, 0x74, 0xCA, 0x85, 0x2C, 
+0x95, 0x8F, 0x9D, 0xF0, 0x95, 0x8E, 0x7D, 0x0A, 
+0x7D, 0x2A, 0x7D, 0x0A, 0x8D, 0x8D, 0xAE, 0x31, 
+0x95, 0xAF, 0x8D, 0x6D, 0xAE, 0x71, 0x7C, 0xCA, 
+0x8D, 0x8D, 0x5B, 0xA8, 0x19, 0x62, 0x19, 0xA3, 
+0x21, 0xC3, 0x32, 0x44, 0x32, 0x24, 0x2A, 0x03, 
+0x53, 0x67, 0x7C, 0xCA, 0x5B, 0xE6, 0x4B, 0x64, 
+0x5C, 0x07, 0x42, 0xE4, 0x53, 0x66, 0x64, 0x08, 
+0x4B, 0x25, 0x4B, 0x26, 0x32, 0x64, 0x2A, 0x24, 
+0x3A, 0xC7, 0x42, 0xC7, 0x42, 0xE7, 0x43, 0x06, 
+0x32, 0x64, 0x2A, 0x23, 0x3A, 0xC5, 0x43, 0x06, 
+0x5B, 0xCA, 0x5B, 0xCA, 0x2A, 0x43, 0x22, 0x22, 
+0x2A, 0x42, 0x22, 0x22, 0x32, 0xA3, 0x53, 0xE7, 
+0x5C, 0x27, 0x85, 0x4D, 0xB6, 0x72, 0x6C, 0x89, 
+0x64, 0x68, 0x53, 0xC6, 0x4B, 0x85, 0x4B, 0x66, 
+0x4B, 0x87, 0x8D, 0xB0, 0xA6, 0x52, 0x9D, 0xF1, 
+0x8D, 0x4E, 0x85, 0x0D, 0xB6, 0x71, 0x85, 0x2D, 
+0xA6, 0x32, 0xB6, 0x93, 0x7C, 0xAB, 0x3A, 0x04, 
+0x5A, 0x68, 0x41, 0xA6, 0x52, 0x48, 0x7B, 0x4B, 
+0xAC, 0x70, 0xAC, 0xB1, 0x7B, 0x8D, 0x52, 0xAA, 
+0x73, 0x8E, 0x5A, 0xAA, 0x6B, 0x4D, 0xBD, 0xB6, 
+0x8C, 0x71, 0x5A, 0xCB, 0x4A, 0x49, 0x42, 0x28, 
+0x5A, 0xCA, 0x5A, 0xAA, 0x84, 0x0E, 0x73, 0x8C, 
+0x18, 0xA3, 0x18, 0xC3, 0x39, 0x86, 0x62, 0xCB, 
+0x84, 0x10, 0x9C, 0xD2, 0x9C, 0xD2, 0x7B, 0xCE, 
+0x6A, 0xEB, 0x6A, 0xEB, 0x5A, 0x8A, 0x83, 0xEF, 
+0xAD, 0x34, 0x6B, 0x4D, 0xA4, 0xF4, 0x9C, 0xB3, 
+0xA4, 0xF4, 0xB5, 0x56, 0xB5, 0x56, 0x83, 0xF0, 
+0x83, 0xF0, 0x94, 0x92, 0x94, 0x72, 0x84, 0x10, 
+0x6B, 0x4D, 0x6B, 0x6B, 0x84, 0x2B, 0xAD, 0xAE, 
+0xBE, 0x4D, 0xAD, 0xEA, 0xCE, 0xED, 0xC6, 0xAC, 
+0x7C, 0xA4, 0x85, 0x26, 0x8D, 0x47, 0x9D, 0xCA, 
+0xA6, 0x0A, 0x85, 0x03, 0x8D, 0x81, 0xAE, 0x25, 
+0xB6, 0x69, 0xB6, 0x6A, 0xAE, 0x4B, 0x9D, 0xED, 
+0x9D, 0xF0, 0xCE, 0xF6, 0xC6, 0xB4, 0xB6, 0x70, 
+0xBE, 0x8F, 0xDF, 0x54, 0xB5, 0xF4, 0xCE, 0x58, 
+0xAD, 0x55, 0x73, 0x8E, 0x31, 0xC6, 0x7C, 0x8C, 
+0x95, 0xCE, 0x95, 0xAB, 0x85, 0x48, 0x6C, 0x66, 
+0x5C, 0x06, 0x74, 0xC9, 0x43, 0x25, 0x19, 0x82, 
+0x3A, 0x87, 0x95, 0x51, 0x42, 0xC8, 0x19, 0x83, 
+0x2A, 0x44, 0x42, 0xE6, 0x19, 0x82, 0x3A, 0xC6, 
+0x19, 0xA2, 0x21, 0xE3, 0x11, 0x61, 0x11, 0x22, 
+0x09, 0x02, 0x09, 0x22, 0x21, 0xE4, 0x22, 0x04, 
+0x2A, 0x25, 0x4B, 0x28, 0x4B, 0x49, 0x5B, 0xEB, 
+0x7B, 0x8B, 0x7B, 0x8B, 0x7B, 0x8B, 0x7B, 0x6A, 
+0x83, 0xAB, 0x8B, 0xEC, 0x94, 0x0D, 0x9C, 0x4E, 
+0x9C, 0x4E, 0x9C, 0x4E, 0x9C, 0x8F, 0xA4, 0x8F, 
+0xA4, 0x8F, 0x94, 0x0C, 0x94, 0x0C, 0xA4, 0x8E, 
+0xAC, 0xD0, 0xAC, 0xD0, 0xA4, 0x8E, 0xA4, 0x6E, 
+0xA4, 0x8F, 0x9C, 0x6E, 0x9C, 0x2D, 0x9C, 0x4D, 
+0xA4, 0x8D, 0xA4, 0x6D, 0x9C, 0x4D, 0x94, 0x2C, 
+0x94, 0x0C, 0x8C, 0x0C, 0x94, 0x2C, 0x94, 0x4D, 
+0x9C, 0x8E, 0x9C, 0x6E, 0x9C, 0x6E, 0x94, 0x8F, 
+0xA4, 0xD0, 0xAD, 0x31, 0xBD, 0xB3, 0xCE, 0x14, 
+0xCD, 0xF4, 0xCE, 0x13, 0xCD, 0xF3, 0xC5, 0xB3, 
+0xC5, 0xD3, 0xBD, 0xB2, 0xAD, 0x10, 0xBD, 0x72, 
+0xAC, 0xF0, 0xB5, 0x30, 0xB5, 0x51, 0xB5, 0x51, 
+0xA4, 0xEF, 0xA5, 0x0F, 0x9C, 0xCE, 0x3A, 0x84, 
+0x42, 0xE5, 0x5B, 0x28, 0xAD, 0x51, 0xD6, 0x76, 
+0xBD, 0xD3, 0xBD, 0xF3, 0x9D, 0x0F, 0x42, 0xC3, 
+0x3B, 0x03, 0x53, 0x85, 0x63, 0xC9, 0xAD, 0x71, 
+0xCE, 0x55, 0xCE, 0x35, 0x8C, 0x0E, 0xAD, 0x32, 
+0x62, 0xEA, 0x9C, 0x8F, 0x8C, 0x0D, 0x8C, 0x2E, 
+0x94, 0x6F, 0x94, 0x4E, 0x7B, 0xAC, 0x83, 0xED, 
+0x9C, 0xB0, 0x9C, 0x90, 0x73, 0x4B, 0x4A, 0x68, 
+0x7C, 0x2D, 0xA5, 0xD0, 0x8D, 0x0C, 0xA5, 0xAF, 
+0xC6, 0x92, 0xC6, 0x72, 0x73, 0xAA, 0x52, 0x68, 
+0x39, 0xA6, 0x3A, 0x27, 0xBE, 0x75, 0x9D, 0x70, 
+0x4B, 0x27, 0x5B, 0xA9, 0x63, 0xAA, 0x4A, 0xA7, 
+0x84, 0x8E, 0x84, 0x8D, 0x95, 0x0E, 0x9D, 0x6E, 
+0x64, 0x06, 0x6C, 0x27, 0x6B, 0xE9, 0x6B, 0xCA, 
+0x74, 0x0A, 0x84, 0xAC, 0xB6, 0x13, 0xD7, 0x17, 
+0xCE, 0xB6, 0xB5, 0xF2, 0x6B, 0xEA, 0x63, 0xE9, 
+0x53, 0x47, 0x53, 0x27, 0x6B, 0x89, 0x9C, 0xEF, 
+0x73, 0xAA, 0xAD, 0xD2, 0x84, 0xCE, 0x85, 0x0F, 
+0x7C, 0xCD, 0x6C, 0x4B, 0x6C, 0x2A, 0x74, 0x6B, 
+0x8D, 0x2E, 0x8D, 0x4F, 0x85, 0x2F, 0x85, 0x0E, 
+0x5B, 0xC9, 0x74, 0xCA, 0x5C, 0x25, 0x53, 0xC5, 
+0x85, 0x4B, 0x6C, 0x47, 0x95, 0x8E, 0x7C, 0xAC, 
+0xA5, 0xF0, 0xB6, 0x32, 0x8D, 0x0D, 0x6C, 0x47, 
+0x64, 0x46, 0x5C, 0x05, 0x64, 0x48, 0x8D, 0x8D, 
+0x9E, 0x10, 0x8D, 0x8E, 0x6C, 0x89, 0x74, 0xE9, 
+0x85, 0x4B, 0x85, 0x4C, 0x9D, 0xEF, 0xA6, 0x31, 
+0x95, 0xAE, 0x9D, 0xCF, 0x9D, 0xCF, 0x5B, 0xC7, 
+0x3A, 0xE5, 0x19, 0xA2, 0x21, 0xA3, 0x21, 0xC3, 
+0x19, 0xA3, 0x32, 0x65, 0x3A, 0xC6, 0x2A, 0x24, 
+0x21, 0xE2, 0x53, 0xA6, 0x43, 0x44, 0x43, 0x24, 
+0x5B, 0xE7, 0x43, 0x04, 0x3A, 0xC3, 0x5C, 0x07, 
+0x6C, 0x68, 0x4B, 0x46, 0x2A, 0x03, 0x32, 0x65, 
+0x43, 0x08, 0x53, 0x49, 0x4B, 0x48, 0x4B, 0x47, 
+0x4B, 0x67, 0x43, 0x46, 0x3B, 0x25, 0x3B, 0x05, 
+0x4B, 0x67, 0x4B, 0x67, 0x3A, 0xC5, 0x2A, 0x43, 
+0x3A, 0xC5, 0x22, 0x02, 0x22, 0x22, 0x6C, 0xAA, 
+0x6C, 0xA9, 0x85, 0x4D, 0x9D, 0xF0, 0x74, 0xCA, 
+0x7D, 0x0A, 0x5C, 0x07, 0x4B, 0x85, 0x43, 0x65, 
+0x32, 0xE4, 0x3A, 0xE5, 0x64, 0x2A, 0x85, 0x4E, 
+0x64, 0x49, 0x53, 0x67, 0x8D, 0x6E, 0x8D, 0x8F, 
+0xBE, 0xD4, 0x95, 0x6F, 0x8D, 0x0D, 0x7C, 0x0A, 
+0x73, 0x6A, 0x52, 0x46, 0x49, 0xE7, 0x72, 0xEA, 
+0xA4, 0x0D, 0x72, 0xEA, 0x83, 0xAD, 0x4A, 0x48, 
+0x62, 0xEB, 0x52, 0x6A, 0x62, 0xEC, 0x83, 0xEF, 
+0x73, 0x8E, 0x6B, 0x4D, 0x6B, 0x2C, 0x94, 0x71, 
+0xA5, 0x13, 0x94, 0x71, 0x94, 0xB0, 0x7B, 0xCD, 
+0x20, 0xE4, 0x18, 0xC3, 0x18, 0xC3, 0x39, 0x86, 
+0x5A, 0xAA, 0x7B, 0xCE, 0x83, 0xEF, 0x63, 0x0C, 
+0x7B, 0x8E, 0x62, 0xEB, 0x5A, 0x8A, 0x39, 0xC7, 
+0x9C, 0xB3, 0xBD, 0x75, 0xBD, 0x96, 0xA4, 0xF4, 
+0x9C, 0xB3, 0x9C, 0xD3, 0x94, 0x72, 0x94, 0x72, 
+0xAD, 0x55, 0xAD, 0x55, 0xBD, 0xF7, 0xCE, 0x59, 
+0x7B, 0xCF, 0x62, 0xEB, 0x6B, 0x2B, 0x7C, 0x0C, 
+0x8D, 0x0C, 0x9D, 0xAB, 0xB6, 0x6C, 0xA5, 0xE8, 
+0x64, 0x41, 0x64, 0x41, 0x6C, 0x82, 0x85, 0x26, 
+0xBE, 0xCF, 0x8D, 0x68, 0x8D, 0x63, 0x9D, 0xC3, 
+0xA5, 0xE5, 0xA6, 0x06, 0x9D, 0xE6, 0x95, 0xC9, 
+0xA6, 0x0F, 0xBE, 0x93, 0xC6, 0xD2, 0xA6, 0x0D, 
+0xAE, 0x4E, 0xBE, 0x93, 0xBE, 0x36, 0xC6, 0x18, 
+0xB5, 0x96, 0x73, 0xAF, 0x3A, 0x05, 0x84, 0xE9, 
+0x7D, 0x07, 0x85, 0x68, 0x6C, 0x87, 0x32, 0xC2, 
+0x2A, 0x82, 0x4B, 0x85, 0x3A, 0xE4, 0x19, 0xC2, 
+0x4B, 0x08, 0x8D, 0x31, 0x32, 0x45, 0x21, 0xC3, 
+0x53, 0x88, 0x53, 0x87, 0x2A, 0x23, 0x3A, 0x85, 
+0x19, 0x82, 0x2A, 0x04, 0x2A, 0x44, 0x3A, 0x86, 
+0x42, 0xC7, 0x5B, 0xAA, 0x43, 0x28, 0x3A, 0xE7, 
+0x53, 0x89, 0x5B, 0xEA, 0x4B, 0x48, 0x5B, 0xEB, 
+0x5A, 0xCA, 0x5A, 0xC9, 0x62, 0xEA, 0x6B, 0x0A, 
+0x73, 0x4B, 0x83, 0xCC, 0x83, 0xED, 0x94, 0x4E, 
+0x9C, 0x8F, 0xA4, 0xF0, 0xBD, 0x93, 0xB5, 0x72, 
+0xAC, 0xF0, 0x94, 0x4D, 0x9C, 0x4E, 0xAC, 0xF0, 
+0xA4, 0xAF, 0xA4, 0xD0, 0xA4, 0xD0, 0xAC, 0xF0, 
+0xB5, 0x11, 0xBD, 0x72, 0xB5, 0x31, 0xBD, 0x51, 
+0xDE, 0x55, 0xDE, 0x35, 0xCD, 0xF3, 0xCD, 0xD3, 
+0xC5, 0x71, 0xBD, 0x51, 0xB5, 0x31, 0xB5, 0x10, 
+0xAC, 0xF0, 0xB5, 0x10, 0xB5, 0x31, 0xAC, 0xF0, 
+0x9C, 0x8E, 0x94, 0x4E, 0x9C, 0xAF, 0xAC, 0xEF, 
+0xAC, 0xCF, 0xAC, 0xEF, 0xAC, 0xCF, 0xAC, 0xCF, 
+0xB5, 0x10, 0xB5, 0x51, 0xB5, 0x51, 0xB5, 0x30, 
+0xB5, 0x10, 0xB5, 0x30, 0xAC, 0xF0, 0x94, 0x4D, 
+0x94, 0x4D, 0x9C, 0x8E, 0xAD, 0x30, 0x63, 0x48, 
+0x42, 0xA5, 0x53, 0x06, 0x73, 0xEB, 0xB5, 0xB3, 
+0x5B, 0x48, 0x4B, 0x47, 0x53, 0x86, 0x4B, 0x44, 
+0x43, 0x24, 0x6C, 0x09, 0xB5, 0xB2, 0xCE, 0x35, 
+0xCE, 0x15, 0xCE, 0x14, 0x9C, 0x8F, 0xA4, 0xF1, 
+0x7B, 0xAC, 0x83, 0xCD, 0x94, 0x4D, 0x8C, 0x4E, 
+0x8C, 0x4E, 0x9C, 0x8F, 0x9C, 0xB0, 0xAD, 0x11, 
+0xAD, 0x32, 0x9C, 0x90, 0x73, 0x6C, 0x42, 0x27, 
+0x42, 0x88, 0x8D, 0x2E, 0x95, 0x6D, 0xA5, 0xEF, 
+0xC6, 0xD3, 0xAD, 0xAF, 0x52, 0xA7, 0x52, 0xA8, 
+0x7C, 0x0D, 0xAD, 0xB3, 0xC6, 0xF6, 0xB6, 0x53, 
+0x74, 0x4C, 0xA5, 0xD2, 0x84, 0x8D, 0x73, 0xEB, 
+0x84, 0x6D, 0x8C, 0xCE, 0x9D, 0x2F, 0x9D, 0x2D, 
+0x6C, 0x47, 0x6B, 0xE8, 0x7C, 0x0B, 0x73, 0xAB, 
+0x6B, 0x8B, 0x8C, 0xAE, 0xDF, 0x59, 0xB6, 0x13, 
+0x7C, 0x8D, 0x7C, 0x6B, 0x5B, 0xA8, 0x4B, 0x46, 
+0x74, 0x4B, 0x6B, 0xCA, 0x9D, 0x30, 0xE7, 0x37, 
+0xAD, 0x70, 0xC6, 0x74, 0x9D, 0x70, 0xAD, 0xF2, 
+0x9D, 0x6F, 0xAD, 0xF1, 0x9D, 0x90, 0x74, 0x6B, 
+0x8D, 0x0E, 0x63, 0xEA, 0x74, 0x8C, 0x74, 0xAB, 
+0x6C, 0x89, 0x5C, 0x26, 0x6C, 0x87, 0x95, 0x8C, 
+0x9D, 0x8D, 0x63, 0xE7, 0xAD, 0xF0, 0x7C, 0x4B, 
+0x95, 0x0E, 0xAD, 0xF1, 0x95, 0x4D, 0x6C, 0x68, 
+0x4B, 0xC4, 0x4B, 0x84, 0x7D, 0x2B, 0x85, 0x4D, 
+0x53, 0xA7, 0x3A, 0xE4, 0x3B, 0x24, 0x64, 0x68, 
+0x85, 0x6B, 0x95, 0xCE, 0xA6, 0x10, 0xAE, 0x51, 
+0x95, 0xAE, 0x85, 0x0C, 0x53, 0xA7, 0x32, 0xA4, 
+0x21, 0xE3, 0x11, 0x61, 0x21, 0xE3, 0x21, 0xE3, 
+0x21, 0xE3, 0x3A, 0x85, 0x3A, 0xC5, 0x2A, 0x23, 
+0x21, 0xE2, 0x5C, 0x27, 0x53, 0xC5, 0x43, 0x24, 
+0x5C, 0x07, 0x64, 0x28, 0x53, 0xC6, 0x53, 0xC6, 
+0x64, 0x48, 0x3A, 0xA4, 0x21, 0xC3, 0x32, 0x65, 
+0x4B, 0x27, 0x53, 0x89, 0x4B, 0x68, 0x6C, 0x6B, 
+0x64, 0x4A, 0x5C, 0x08, 0x5B, 0xE8, 0x5C, 0x08, 
+0x74, 0xAB, 0x7C, 0xEC, 0x6C, 0x6A, 0x63, 0xE8, 
+0x53, 0x87, 0x42, 0xC5, 0x2A, 0x43, 0x7D, 0x0D, 
+0x95, 0xCF, 0x8D, 0x8E, 0x9D, 0xF0, 0x85, 0x2C, 
+0x9D, 0xEF, 0x64, 0x28, 0x5C, 0x07, 0x64, 0x68, 
+0x53, 0xA6, 0x4B, 0x87, 0x64, 0x6A, 0x85, 0x6D, 
+0x6C, 0x69, 0x3B, 0x05, 0x6C, 0x8B, 0xB6, 0xB4, 
+0xB6, 0xB4, 0x74, 0x6B, 0x53, 0x86, 0x7C, 0x6A, 
+0x7B, 0xCA, 0x73, 0xCA, 0x52, 0x66, 0x72, 0xC9, 
+0x9B, 0xAC, 0x7A, 0xEA, 0x7B, 0x2B, 0x5A, 0xAA, 
+0x6B, 0x2C, 0x7B, 0xAE, 0x94, 0x51, 0x9C, 0xB2, 
+0x7B, 0xAE, 0x83, 0xEF, 0xAD, 0x34, 0xC6, 0x18, 
+0xCE, 0x18, 0xC6, 0x17, 0xC6, 0x18, 0xC5, 0xD7, 
+0x7B, 0xAF, 0x39, 0x87, 0x29, 0x25, 0x20, 0xE4, 
+0x39, 0x86, 0x62, 0xCA, 0x6B, 0x0C, 0x73, 0x4C, 
+0x83, 0xAE, 0x6B, 0x2C, 0x73, 0x6D, 0x62, 0xCB, 
+0x8C, 0x10, 0xDE, 0x79, 0xD6, 0x38, 0x9C, 0x92, 
+0x8C, 0x31, 0xA4, 0xF4, 0xB5, 0x76, 0xBD, 0xB7, 
+0xBD, 0xD8, 0xCE, 0x59, 0xC6, 0x38, 0xCE, 0x38, 
+0x8C, 0x51, 0x84, 0x10, 0x6B, 0x2B, 0x63, 0x4B, 
+0x4A, 0xE8, 0x84, 0xED, 0xA6, 0x2E, 0xA5, 0xEB, 
+0x64, 0x41, 0x6C, 0x82, 0x74, 0xE3, 0x8D, 0x67, 
+0xCF, 0x32, 0x95, 0xAD, 0x85, 0x26, 0x9D, 0xC5, 
+0x9D, 0xC4, 0x8D, 0x62, 0x95, 0x83, 0xA6, 0x08, 
+0xAE, 0x6E, 0xB6, 0x50, 0xBE, 0x8F, 0xA5, 0xE9, 
+0x9D, 0xEB, 0xA5, 0xF1, 0xBE, 0x37, 0xC6, 0x38, 
+0xA5, 0x55, 0x63, 0x2C, 0x4A, 0xE6, 0x85, 0x28, 
+0x75, 0x05, 0x64, 0x85, 0x32, 0xE1, 0x2A, 0x61, 
+0x3A, 0xE4, 0x53, 0x86, 0x19, 0xC1, 0x32, 0x64, 
+0x53, 0x89, 0x5B, 0x8A, 0x32, 0x45, 0x19, 0x82, 
+0x42, 0xE5, 0x21, 0xE2, 0x2A, 0x23, 0x2A, 0x23, 
+0x21, 0xE3, 0x42, 0xE6, 0x5B, 0xE9, 0x5C, 0x09, 
+0x4B, 0x87, 0x4B, 0x87, 0x4B, 0x87, 0x43, 0x47, 
+0x43, 0x47, 0x43, 0x26, 0x32, 0xA5, 0x43, 0x08, 
+0x7B, 0xAD, 0x73, 0x6C, 0x63, 0x0B, 0x73, 0x6C, 
+0x7B, 0xCD, 0x94, 0x4F, 0x9C, 0x90, 0x94, 0x4F, 
+0x83, 0xCD, 0x83, 0xCD, 0x84, 0x0D, 0x7B, 0xCD, 
+0x73, 0x8B, 0x94, 0x2D, 0x94, 0x0D, 0x94, 0x2D, 
+0x94, 0x4E, 0x8C, 0x4E, 0x83, 0xED, 0x9C, 0x90, 
+0xA4, 0xF1, 0xB5, 0x73, 0xBD, 0xB3, 0xCD, 0xF4, 
+0xCD, 0xF4, 0xC5, 0xB2, 0xD6, 0x14, 0xCD, 0xD3, 
+0xBD, 0x92, 0xBD, 0x93, 0xC5, 0xF4, 0xCD, 0xF4, 
+0xD6, 0x35, 0xD6, 0x35, 0xDE, 0x55, 0xDE, 0x55, 
+0xDE, 0x55, 0xA4, 0xAF, 0xBD, 0x72, 0xCD, 0xF4, 
+0xA4, 0x8E, 0xAC, 0xF0, 0xB5, 0x10, 0xB5, 0x31, 
+0xB5, 0x30, 0xAC, 0xCF, 0xB5, 0x10, 0xBD, 0x92, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xBD, 0x92, 0xCD, 0xD3, 
+0xC5, 0xB3, 0xC5, 0xB3, 0xBD, 0x71, 0xAC, 0xEF, 
+0x63, 0x48, 0x42, 0xA5, 0x5B, 0x89, 0x7C, 0x4D, 
+0x6C, 0x0B, 0x53, 0xA7, 0x43, 0x45, 0x4B, 0x45, 
+0x53, 0x66, 0x9D, 0x4E, 0xAD, 0x0F, 0x9C, 0xAE, 
+0x9C, 0x6E, 0x94, 0x6E, 0x8C, 0x4E, 0x8C, 0x2E, 
+0x94, 0x6F, 0x6B, 0x6A, 0xCE, 0xB5, 0xC6, 0x74, 
+0x9C, 0xEF, 0xBD, 0xD2, 0x9C, 0xAE, 0x94, 0x4E, 
+0x94, 0x4E, 0x94, 0x4D, 0x7B, 0xAC, 0x6B, 0x2A, 
+0x62, 0xE9, 0x5B, 0x09, 0x95, 0x0D, 0x9D, 0x6D, 
+0xBE, 0xB3, 0xAE, 0x32, 0x8C, 0xCF, 0xBE, 0x74, 
+0xC6, 0xF4, 0xC6, 0xD4, 0xB6, 0x52, 0xB6, 0x73, 
+0x74, 0x6C, 0x7C, 0xAD, 0x6B, 0xCA, 0x63, 0xAA, 
+0x7C, 0x4C, 0x84, 0x8C, 0x94, 0xED, 0x8C, 0xEC, 
+0x74, 0x68, 0x84, 0xCB, 0xA5, 0x30, 0x84, 0x2D, 
+0x6B, 0x8B, 0xD6, 0xD7, 0xDF, 0x59, 0x7C, 0x8D, 
+0x6C, 0x2A, 0x74, 0x6A, 0x7C, 0xAB, 0x74, 0x8B, 
+0x7C, 0x6C, 0x6B, 0xA9, 0xB6, 0x13, 0xCE, 0xB5, 
+0xBE, 0x74, 0xBE, 0x54, 0xAD, 0x70, 0xC6, 0x32, 
+0xD6, 0xD5, 0x8C, 0xED, 0x6C, 0x09, 0x53, 0xA7, 
+0x74, 0x8B, 0x74, 0x8B, 0x32, 0x83, 0x3A, 0xE4, 
+0x6C, 0x88, 0x53, 0xE4, 0x64, 0x27, 0x74, 0x29, 
+0x9D, 0x4E, 0x74, 0x69, 0x84, 0xCB, 0x6B, 0xEA, 
+0x84, 0xAF, 0xAD, 0xB2, 0x9D, 0x71, 0x74, 0x4B, 
+0x3B, 0x23, 0x4B, 0xA5, 0x64, 0x47, 0x2A, 0x81, 
+0x19, 0xE1, 0x22, 0x02, 0x3A, 0xE4, 0x64, 0x68, 
+0x95, 0xAD, 0xA6, 0x10, 0xAE, 0x51, 0x9D, 0xF0, 
+0x53, 0x88, 0x19, 0xC2, 0x22, 0x03, 0x2A, 0x44, 
+0x53, 0xA8, 0x43, 0x06, 0x3A, 0xE5, 0x32, 0xA4, 
+0x53, 0x87, 0x63, 0xE9, 0x43, 0x05, 0x43, 0x26, 
+0x2A, 0x42, 0x53, 0xC7, 0x5C, 0x26, 0x4B, 0x64, 
+0x64, 0x27, 0x7C, 0xEA, 0x6C, 0x69, 0x43, 0x45, 
+0x6C, 0xA9, 0x42, 0xE5, 0x19, 0xA2, 0x32, 0x65, 
+0x3A, 0xC5, 0x43, 0x06, 0x53, 0xA9, 0x9D, 0xF1, 
+0x8D, 0x6F, 0x85, 0x2D, 0x85, 0x4E, 0x8D, 0x8F, 
+0x9E, 0x11, 0x53, 0x88, 0x4B, 0x66, 0x5B, 0xE8, 
+0x3A, 0xE4, 0x2A, 0x23, 0x3A, 0xA4, 0x64, 0x69, 
+0x95, 0xCF, 0x95, 0xAF, 0xA6, 0x31, 0x7D, 0x0C, 
+0x7C, 0xEB, 0x4B, 0xA6, 0x95, 0xAE, 0x6C, 0x68, 
+0x5C, 0x47, 0x6C, 0xA9, 0x7D, 0x0B, 0x85, 0x6C, 
+0x8D, 0x8D, 0x95, 0x8D, 0x6C, 0x8A, 0x8D, 0x4E, 
+0xAE, 0x52, 0x6C, 0x4A, 0x6C, 0x49, 0x95, 0x6D, 
+0x63, 0x68, 0x5B, 0x47, 0x63, 0x68, 0x83, 0x69, 
+0x83, 0x09, 0x6A, 0xA8, 0x62, 0x89, 0x83, 0xCF, 
+0x94, 0x91, 0x9C, 0xB2, 0x94, 0x92, 0x8C, 0x30, 
+0x83, 0xEF, 0x9C, 0xB2, 0xA4, 0xD3, 0xBD, 0xB6, 
+0xBD, 0xB6, 0xAD, 0x34, 0xAD, 0x14, 0xCE, 0x38, 
+0xD6, 0x99, 0x9C, 0x92, 0x83, 0xAF, 0x5A, 0xAB, 
+0x20, 0xE4, 0x31, 0x65, 0x5A, 0x8A, 0x73, 0x6D, 
+0x73, 0x6D, 0x83, 0xAE, 0x73, 0x2C, 0x6B, 0x0C, 
+0x94, 0x72, 0xD6, 0x58, 0xDE, 0x79, 0xA4, 0xD3, 
+0xAD, 0x14, 0xAD, 0x55, 0xB5, 0x76, 0xB5, 0x96, 
+0xD6, 0x9A, 0xDE, 0xBB, 0x9C, 0xD3, 0x73, 0x8E, 
+0x73, 0x8E, 0x94, 0x71, 0x8C, 0x30, 0x73, 0x8D, 
+0x63, 0x4B, 0x84, 0xAD, 0x8D, 0x4D, 0x9D, 0xCC, 
+0x74, 0xC5, 0x74, 0xC2, 0x85, 0x44, 0x9D, 0xE9, 
+0xB6, 0x71, 0xCF, 0x35, 0x95, 0xAE, 0x95, 0xA8, 
+0x8D, 0x64, 0x7D, 0x00, 0x85, 0x42, 0x9D, 0xC7, 
+0xA6, 0x0B, 0xAE, 0x4D, 0xB6, 0x6D, 0xAE, 0x49, 
+0x95, 0x88, 0xAD, 0xD1, 0xC6, 0x58, 0xC6, 0x38, 
+0x9D, 0x14, 0x42, 0x49, 0x5B, 0x68, 0x85, 0x48, 
+0x74, 0xE5, 0x53, 0xE3, 0x32, 0xC1, 0x2A, 0x61, 
+0x74, 0x8A, 0x85, 0x4B, 0x2A, 0x41, 0x3A, 0xA4, 
+0x7C, 0xCD, 0xAE, 0x12, 0x5B, 0xAA, 0x21, 0xC3, 
+0x74, 0x8A, 0x53, 0x66, 0x4B, 0x46, 0x53, 0x68, 
+0x64, 0x0A, 0x5B, 0xE9, 0x43, 0x46, 0x32, 0xC4, 
+0x2A, 0x83, 0x2A, 0x63, 0x4B, 0x67, 0x4B, 0x87, 
+0x53, 0xE8, 0x4B, 0x87, 0x2A, 0x63, 0x32, 0x86, 
+0xB5, 0x53, 0xA4, 0xF2, 0x83, 0xEE, 0x94, 0x6F, 
+0xAD, 0x32, 0xC5, 0xD4, 0xCD, 0xF5, 0xC5, 0xB4, 
+0xAD, 0x32, 0x94, 0x90, 0x94, 0x6F, 0x94, 0x6F, 
+0x9C, 0xD1, 0x94, 0x6E, 0x94, 0x0C, 0xB5, 0x31, 
+0xCE, 0x15, 0xD6, 0x76, 0xD6, 0x57, 0xD6, 0x57, 
+0xD6, 0x77, 0xD6, 0x57, 0xDE, 0x97, 0xC5, 0xD4, 
+0xD6, 0x15, 0xDE, 0x96, 0xDE, 0x96, 0xD6, 0x75, 
+0xD6, 0x55, 0xD6, 0x76, 0xD6, 0x77, 0xD6, 0x56, 
+0xD6, 0x56, 0xD6, 0x76, 0xDE, 0x96, 0xD6, 0x55, 
+0xDE, 0x76, 0x9C, 0x4D, 0xAC, 0xF0, 0xB5, 0x52, 
+0x94, 0x4E, 0x9C, 0xB0, 0xAC, 0xF0, 0xB5, 0x31, 
+0xC5, 0xD4, 0xC5, 0xD4, 0x9C, 0xAF, 0xA4, 0xD0, 
+0x94, 0x6E, 0x83, 0xCC, 0x7B, 0xAC, 0x8C, 0x0D, 
+0x8C, 0x2E, 0x9C, 0x8F, 0xBD, 0x92, 0xC5, 0x92, 
+0x9C, 0xCD, 0x63, 0x88, 0x4B, 0x06, 0x53, 0x27, 
+0x6C, 0x2B, 0x5B, 0xE8, 0x4B, 0x65, 0x43, 0x45, 
+0x53, 0x66, 0x9D, 0x2E, 0xB5, 0xAF, 0xB5, 0xAE, 
+0x94, 0xAC, 0x63, 0x48, 0x8C, 0x6E, 0x9C, 0xAF, 
+0xAD, 0x11, 0x63, 0x29, 0xC6, 0xB3, 0xC6, 0x71, 
+0xCE, 0xB3, 0xC6, 0x52, 0xB5, 0x90, 0xA4, 0xEE, 
+0xA4, 0xEE, 0xAD, 0x2E, 0xC5, 0xF2, 0xB5, 0x51, 
+0xB5, 0x51, 0xAD, 0x10, 0xA5, 0x0F, 0xAD, 0xD0, 
+0xBE, 0xB4, 0xC7, 0x16, 0xAE, 0x32, 0x9D, 0xCE, 
+0x7C, 0xEA, 0x8D, 0x2D, 0xB6, 0x72, 0xB6, 0x32, 
+0x8D, 0x0E, 0x74, 0x6C, 0x74, 0x2B, 0x63, 0xC9, 
+0x6B, 0xE9, 0x5B, 0x66, 0x63, 0xA7, 0x8D, 0x0C, 
+0x7C, 0x89, 0x8C, 0xEB, 0x9D, 0x6F, 0x7C, 0x4C, 
+0x95, 0x10, 0xE7, 0x79, 0x9D, 0x30, 0x74, 0x6B, 
+0x74, 0xAB, 0x6C, 0x28, 0x7C, 0xAB, 0x8D, 0x0E, 
+0x6B, 0xCA, 0x6B, 0xAA, 0xC6, 0x53, 0xAD, 0xD0, 
+0xBE, 0x94, 0xBE, 0x95, 0xBE, 0x54, 0xB5, 0xB0, 
+0xD6, 0x93, 0xCE, 0xB3, 0x9D, 0x4E, 0x74, 0x8A, 
+0x7C, 0xCB, 0xA5, 0xCF, 0x43, 0x26, 0x3A, 0xE4, 
+0x5B, 0xE5, 0x4B, 0xA4, 0x7C, 0xCA, 0x5B, 0x67, 
+0x6B, 0xE9, 0x7C, 0xAA, 0x53, 0x86, 0x3A, 0x84, 
+0x9D, 0x73, 0xAD, 0xB4, 0xA5, 0xB4, 0x6C, 0x0C, 
+0x43, 0x45, 0x5C, 0x27, 0x32, 0xC2, 0x19, 0xE1, 
+0x19, 0xA1, 0x11, 0x80, 0x19, 0xE2, 0x3A, 0xC4, 
+0x8D, 0x6D, 0xA6, 0x51, 0x9D, 0xF0, 0x4A, 0xE7, 
+0x09, 0x00, 0x19, 0x62, 0x2A, 0x24, 0x4B, 0x27, 
+0x7D, 0x0C, 0x64, 0x48, 0x5C, 0x07, 0x53, 0xC6, 
+0x6C, 0x8A, 0x6C, 0x8A, 0x4B, 0x65, 0x53, 0xC7, 
+0x4B, 0x45, 0x32, 0xA2, 0x4B, 0x84, 0x53, 0xE5, 
+0x64, 0x47, 0x53, 0xC6, 0x2A, 0x02, 0x09, 0x00, 
+0x42, 0xE6, 0x42, 0xC6, 0x21, 0xA2, 0x22, 0x03, 
+0x22, 0x22, 0x2A, 0x43, 0x64, 0x2A, 0x95, 0x90, 
+0x95, 0xB0, 0x9D, 0xF1, 0xA6, 0x12, 0xA6, 0x52, 
+0x74, 0x8C, 0x32, 0x85, 0x4B, 0x47, 0x5C, 0x09, 
+0x4B, 0x46, 0x3A, 0x84, 0x3A, 0xA5, 0x5B, 0xE7, 
+0x74, 0xCB, 0x95, 0xAF, 0xA6, 0x31, 0x7D, 0x0C, 
+0x8D, 0x6E, 0x64, 0x49, 0xBE, 0xF3, 0x8D, 0x6C, 
+0x5C, 0x47, 0x53, 0xE6, 0x43, 0x64, 0x3B, 0x44, 
+0x8D, 0x4C, 0x9D, 0xCE, 0x9D, 0xCD, 0x85, 0x2B, 
+0x85, 0x2C, 0x6C, 0x89, 0x95, 0x8C, 0x95, 0x8D, 
+0x8C, 0xCC, 0x6B, 0xE8, 0x5B, 0x86, 0x73, 0xA7, 
+0x7B, 0x28, 0x52, 0x07, 0x73, 0x2C, 0x83, 0xEF, 
+0x94, 0x71, 0x94, 0x50, 0x94, 0x71, 0x8C, 0x0F, 
+0x8C, 0x30, 0xA4, 0xF3, 0x8C, 0x10, 0x9C, 0xB3, 
+0x9C, 0x92, 0x94, 0x51, 0xA4, 0xD3, 0xB5, 0x75, 
+0xC5, 0xF7, 0xAD, 0x55, 0xD6, 0x58, 0xBD, 0xB6, 
+0x73, 0x8E, 0x4A, 0x08, 0x41, 0xC7, 0x62, 0xEB, 
+0x62, 0xCA, 0x83, 0xCF, 0x73, 0x2C, 0x52, 0x69, 
+0xA4, 0xD3, 0xD6, 0x58, 0xCD, 0xF7, 0xAD, 0x14, 
+0x7B, 0xCF, 0xAD, 0x55, 0xB5, 0x96, 0xDE, 0xBB, 
+0xDE, 0xBB, 0xB5, 0x96, 0x6B, 0x4D, 0x94, 0x93, 
+0xAD, 0x35, 0x7B, 0xCF, 0x6B, 0x2C, 0xAD, 0x34, 
+0x84, 0x2F, 0x63, 0x8A, 0x84, 0xED, 0x85, 0x2B, 
+0x85, 0x27, 0x7C, 0xE4, 0x95, 0xA7, 0xA6, 0x2B, 
+0x95, 0xAD, 0xBE, 0xF4, 0xBE, 0xF4, 0x9D, 0xCC, 
+0x7D, 0x03, 0x74, 0xC0, 0x85, 0x43, 0x8D, 0x86, 
+0x9D, 0xE9, 0x9E, 0x09, 0x9D, 0xE8, 0xA6, 0x26, 
+0x95, 0x68, 0xA5, 0xB1, 0xCE, 0x99, 0xC6, 0x38, 
+0x94, 0xB3, 0x3A, 0x08, 0x74, 0x4B, 0x8D, 0x49, 
+0x7D, 0x05, 0x4B, 0xA2, 0x32, 0xC2, 0x32, 0xA2, 
+0x95, 0xAC, 0x95, 0xCA, 0x53, 0xC4, 0x22, 0x01, 
+0x8D, 0x4F, 0xBE, 0xD5, 0x63, 0xCB, 0x53, 0x47, 
+0x9D, 0x8B, 0x63, 0xE5, 0x5B, 0xE8, 0x74, 0xAC, 
+0x6C, 0x6B, 0x3A, 0xE6, 0x11, 0x81, 0x32, 0x44, 
+0x3A, 0xE5, 0x4B, 0x87, 0x5C, 0x29, 0x53, 0xC7, 
+0x64, 0x49, 0x4B, 0x86, 0x22, 0x22, 0x4B, 0x07, 
+0xBD, 0xB4, 0xC5, 0xD4, 0xBD, 0x93, 0xC5, 0xD4, 
+0xCE, 0x35, 0xC5, 0xD4, 0xBD, 0x73, 0xCE, 0x15, 
+0xD6, 0x55, 0xCE, 0x35, 0xCE, 0x15, 0xC5, 0xF5, 
+0xCE, 0x15, 0x94, 0x4E, 0x8B, 0xEC, 0xCD, 0xF3, 
+0xD6, 0x76, 0xD6, 0x76, 0xDE, 0x97, 0xDE, 0xB7, 
+0xDE, 0xB8, 0xCE, 0x36, 0xD6, 0x56, 0xCD, 0xF4, 
+0xBD, 0xB3, 0xC5, 0xF4, 0xD6, 0x76, 0xDE, 0x96, 
+0xD6, 0x56, 0xD6, 0x76, 0xDE, 0x97, 0xD6, 0x76, 
+0xD6, 0x76, 0xD6, 0x76, 0xD6, 0x76, 0xD6, 0x56, 
+0xDE, 0x76, 0x9C, 0x6E, 0xA4, 0xD0, 0xBD, 0x93, 
+0x94, 0x6F, 0xA4, 0xF1, 0xAC, 0xF1, 0xA4, 0xD0, 
+0xA4, 0xF1, 0xAD, 0x12, 0xAD, 0x11, 0xBD, 0xB4, 
+0xBD, 0x93, 0x9C, 0x70, 0x6B, 0x0A, 0x73, 0x6C, 
+0x73, 0x6C, 0x84, 0x0E, 0x94, 0x4E, 0x8C, 0x0C, 
+0x8C, 0x4B, 0x5B, 0x47, 0x32, 0x84, 0x32, 0x84, 
+0x42, 0xE5, 0x53, 0xA7, 0x4B, 0x65, 0x64, 0x28, 
+0x74, 0x6A, 0x9D, 0x4D, 0xA5, 0xAC, 0x9D, 0xAA, 
+0x9D, 0x8B, 0x8D, 0x0B, 0x74, 0x4A, 0x84, 0x6D, 
+0xAD, 0x92, 0x63, 0x4A, 0xAD, 0xD0, 0xAD, 0xEF, 
+0x9D, 0x0D, 0xA5, 0x2E, 0xA5, 0x0E, 0xAD, 0x4E, 
+0xA5, 0x6D, 0xAD, 0xAF, 0xC6, 0x12, 0xB5, 0x71, 
+0xB5, 0x51, 0x94, 0x6E, 0x7B, 0xEC, 0x94, 0xEE, 
+0xA5, 0xF2, 0xB6, 0x94, 0xAE, 0x12, 0x7C, 0xAB, 
+0x4B, 0x85, 0x8D, 0x6E, 0x9D, 0x8F, 0x95, 0x4E, 
+0x95, 0x6F, 0xA5, 0xD2, 0x74, 0x4B, 0x63, 0xA9, 
+0x8C, 0xCD, 0x84, 0x6A, 0x63, 0xA7, 0x95, 0x4D, 
+0x84, 0xCB, 0x7C, 0xCA, 0x8C, 0xEB, 0x94, 0xEC, 
+0xB6, 0x33, 0x9D, 0x50, 0x7C, 0x8C, 0x74, 0x8A, 
+0x5B, 0xE8, 0x5B, 0xA7, 0x74, 0x8B, 0x84, 0xCD, 
+0x9D, 0x71, 0xAD, 0xD3, 0xB6, 0x12, 0xB5, 0xF0, 
+0xBE, 0x53, 0x9D, 0x50, 0xB6, 0x54, 0xC6, 0x95, 
+0xB5, 0xD0, 0xCE, 0xB2, 0xBE, 0x30, 0x84, 0xAA, 
+0x63, 0xE8, 0x5B, 0xC7, 0x4B, 0x86, 0x4B, 0x65, 
+0x5B, 0xE6, 0x3A, 0xE2, 0x53, 0x87, 0x5B, 0xC8, 
+0x6C, 0x6A, 0x63, 0xE7, 0x43, 0x25, 0x53, 0x28, 
+0x9D, 0x53, 0xBE, 0x77, 0xBE, 0x77, 0x7C, 0xAE, 
+0x64, 0x49, 0x43, 0x64, 0x2A, 0x81, 0x19, 0xE1, 
+0x53, 0x67, 0x42, 0xC5, 0x2A, 0x23, 0x2A, 0x23, 
+0x32, 0x63, 0x4B, 0x67, 0x32, 0x44, 0x11, 0x21, 
+0x11, 0x41, 0x19, 0x82, 0x2A, 0x44, 0x43, 0x06, 
+0x74, 0xAA, 0x74, 0xCA, 0x6C, 0x89, 0x64, 0x28, 
+0x7C, 0xCB, 0x74, 0xAA, 0x53, 0xC6, 0x53, 0xE6, 
+0x5B, 0xE7, 0x4B, 0x85, 0x53, 0xA6, 0x5C, 0x26, 
+0x53, 0xE6, 0x32, 0x82, 0x2A, 0x03, 0x19, 0x82, 
+0x21, 0xE3, 0x21, 0xA2, 0x3A, 0xA5, 0x3A, 0xA5, 
+0x19, 0xE1, 0x32, 0xA4, 0x6C, 0x8A, 0x8D, 0x6F, 
+0xA6, 0x32, 0xAE, 0x53, 0x95, 0xD0, 0x7C, 0xCD, 
+0x2A, 0x64, 0x32, 0x85, 0x43, 0x26, 0x5B, 0xC8, 
+0x5C, 0x09, 0x53, 0xA7, 0x74, 0xCB, 0x74, 0xEA, 
+0x7D, 0x0C, 0x95, 0xD0, 0xA6, 0x31, 0x74, 0xCB, 
+0x53, 0xC8, 0x7C, 0xCB, 0xAE, 0x70, 0xA6, 0x2F, 
+0x95, 0xCE, 0x85, 0x4B, 0x7D, 0x0B, 0x53, 0xE6, 
+0x95, 0x8D, 0xA6, 0x0F, 0x95, 0x8C, 0x95, 0xAC, 
+0x8D, 0x4C, 0x7D, 0x0A, 0x7C, 0xE9, 0x4B, 0x24, 
+0x31, 0xA2, 0x42, 0x24, 0x5B, 0x66, 0x74, 0x68, 
+0x84, 0x2A, 0x8C, 0x0F, 0x9C, 0x92, 0x8C, 0x10, 
+0x9C, 0xB2, 0xA4, 0xD3, 0xA4, 0xF3, 0x8C, 0x30, 
+0x83, 0xEF, 0xCE, 0x38, 0xA5, 0x13, 0x62, 0xCB, 
+0x73, 0x8E, 0x9C, 0x92, 0x8C, 0x51, 0x84, 0x10, 
+0x94, 0x92, 0xB5, 0x75, 0xD6, 0x79, 0xAD, 0x55, 
+0xC6, 0x18, 0xBD, 0x96, 0x8C, 0x31, 0x7B, 0xAE, 
+0x52, 0x49, 0x73, 0x2C, 0x7B, 0xAE, 0x7B, 0xAE, 
+0xAD, 0x34, 0xD6, 0x38, 0xD6, 0x58, 0xBD, 0x96, 
+0x94, 0x51, 0x9C, 0xB3, 0xDE, 0xBB, 0xD6, 0x7A, 
+0xAD, 0x76, 0x73, 0xAF, 0x6B, 0x4D, 0x84, 0x10, 
+0x94, 0x71, 0x8C, 0x51, 0x7B, 0xCF, 0xA4, 0xF3, 
+0x7B, 0xEF, 0x5B, 0x0B, 0xA5, 0x92, 0x84, 0xED, 
+0x85, 0x09, 0x8D, 0x48, 0x95, 0xCA, 0x9D, 0xEB, 
+0x95, 0x8A, 0x9D, 0xCD, 0xA6, 0x10, 0x9E, 0x0D, 
+0x7D, 0x26, 0x64, 0x60, 0x6C, 0xC2, 0x8D, 0x46, 
+0x9E, 0x09, 0x95, 0xA6, 0x95, 0xA4, 0xA6, 0x26, 
+0x8D, 0x48, 0xA5, 0x92, 0xCE, 0x79, 0xBE, 0x38, 
+0x84, 0x31, 0x3A, 0x06, 0x84, 0xED, 0x85, 0x29, 
+0x74, 0xC6, 0x5C, 0x25, 0x32, 0xC1, 0x53, 0xA6, 
+0x95, 0xCC, 0x85, 0x47, 0x74, 0xE6, 0x32, 0x82, 
+0x84, 0xED, 0xB6, 0x94, 0x53, 0x69, 0x63, 0xA8, 
+0x9D, 0xAC, 0x53, 0x65, 0x42, 0xE5, 0x2A, 0x63, 
+0x22, 0x23, 0x3A, 0xA5, 0x3A, 0xC5, 0x43, 0x27, 
+0x43, 0x46, 0x3A, 0xC4, 0x3B, 0x05, 0x53, 0xC7, 
+0x64, 0x29, 0x3A, 0xC4, 0x09, 0x00, 0x21, 0xE4, 
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/main/devices.c b/minimal-examples/embedded/esp32/esp-wrover-kit/main/devices.c
new file mode 100644 (file)
index 0000000..f27650f
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * devices for ESP WROVER KIT
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#define LWIP_PROVIDE_ERRNO 1
+#define _ESP_PLATFORM_ERRNO_H_
+
+#include <stdio.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include <driver/gpio.h>
+
+#include <libwebsockets.h>
+
+struct lws_led_state *lls;
+lws_display_state_t lds;
+struct lws_button_state *bcs;
+lws_netdev_instance_wifi_t *wnd;
+
+/*
+ * Button controller
+ *
+ * On the WROVER KIT, it's a bit overloaded... the two buttons are reset and
+ * gpio0, gpio is also used for one of the RGB LEDs channels control so it's not
+ * really usable as a general user button.
+ *
+ * Instead we use GPIO 14 (available on J1) for a button with the other side
+ * of the switch connected to 0V.
+ */
+
+static const lws_button_map_t bcm[] = {
+       {
+               .gpio                   = GPIO_NUM_14,
+               .smd_interaction_name   = "user"
+       },
+};
+
+static const lws_button_controller_t bc = {
+       .smd_bc_name                    = "bc",
+       .gpio_ops                       = &lws_gpio_plat,
+       .button_map                     = &bcm[0],
+       .active_state_bitmap            = 0,
+       .count_buttons                  = LWS_ARRAY_SIZE(bcm),
+};
+
+/*
+ * pwm controller
+ */
+
+static const lws_pwm_map_t pwm_map[] = {
+       { .gpio = GPIO_NUM_2, .index = 0, .active_level = 1 },
+       { .gpio = GPIO_NUM_0, .index = 1, .active_level = 1 },
+       { .gpio = GPIO_NUM_4, .index = 2, .active_level = 1 },
+       { .gpio = GPIO_NUM_5, .index = 3, .active_level = 0 }
+};
+
+static const lws_pwm_ops_t pwm_ops = {
+       lws_pwm_plat_ops,
+       .pwm_map                        = &pwm_map[0],
+       .count_pwm_map                  = LWS_ARRAY_SIZE(pwm_map)
+};
+
+/*
+ * led controller
+ */
+
+static const lws_led_gpio_map_t lgm[] = {
+       {
+               .name                   = "red",
+               .gpio                   = GPIO_NUM_2,
+               .pwm_ops                = &pwm_ops, /* managed by pwm */
+               .active_level           = 1,
+       },
+       {
+               .name                   = "green",
+               .gpio                   = GPIO_NUM_0,
+               .pwm_ops                = &pwm_ops, /* managed by pwm */
+               .active_level           = 1,
+       },
+       {
+               .name                   = "blue",
+               .gpio                   = GPIO_NUM_4,
+               .pwm_ops                = &pwm_ops, /* managed by pwm */
+               .active_level           = 1,
+       },
+       {
+               .name                   = "backlight",
+               .gpio                   = GPIO_NUM_5,
+               .pwm_ops                = &pwm_ops, /* managed by pwm */
+               .active_level           = 0,
+               /*
+                * The wrover kit uses a 2 NPN in series to drive the backlight
+                * which means if the GPIO provides no current, the backlight is
+                * full-on.  This causes a white flash during boot... they mark
+                * the first stage with "Modify In ESP-WROVER-KIT!" on the
+                * schematics but on Kit v4.1, it's still like that.
+                */
+       },
+};
+
+static const lws_led_gpio_controller_t lgc = {
+       .led_ops                        = lws_led_gpio_ops,
+       .gpio_ops                       = &lws_gpio_plat,
+       .led_map                        = &lgm[0],
+       .count_leds                     = LWS_ARRAY_SIZE(lgm)
+};
+
+/*
+ * Bitbang SPI configuration for display
+ */
+
+static const lws_bb_spi_t lbspi = {
+               .bb_ops = {
+                       lws_bb_spi_ops,
+                       .bus_mode = LWS_SPI_BUSMODE_CLK_IDLE_LOW_SAMP_RISING
+               },
+               .gpio           = &lws_gpio_plat,
+               .clk            = GPIO_NUM_19,
+               .ncs            = { GPIO_NUM_22 },
+               .ncmd           = { GPIO_NUM_21 },
+               .mosi           = GPIO_NUM_23,
+               .miso           = GPIO_NUM_25,
+               .flags          = LWSBBSPI_FLAG_USE_NCS0 |
+                                 LWSBBSPI_FLAG_USE_NCMD0
+};
+
+/*
+ * SPI display
+ */
+
+static const lws_display_ili9341_t disp = {
+       .disp = {
+               lws_display_ili9341_ops,
+               .bl_pwm_ops             = &pwm_ops,
+               .bl_active              = &lws_pwmseq_static_on,
+               .bl_dim                 = &lws_pwmseq_static_half,
+               .bl_transition          = &lws_pwmseq_linear_wipe,
+               .bl_index               = 3,
+               .w                      = 320,
+               .h                      = 240,
+               .latency_wake_ms        = 150,
+       },
+       .spi                            = (lws_spi_ops_t *)&lbspi,
+       .gpio                           = &lws_gpio_plat,
+       .reset_gpio                     = GPIO_NUM_18,
+       .spi_index                      = 0
+};
+
+/*
+ * Settings stored in platform nv
+ */
+
+static const lws_settings_ops_t sett = {
+       lws_settings_ops_plat
+};
+
+/*
+ * Wifi
+ */
+
+static const lws_netdev_ops_t wifi_ops = {
+       lws_netdev_wifi_plat_ops
+};
+
+int
+init_plat_devices(struct lws_context *ctx)
+{
+       lws_settings_instance_t *si;
+       lws_netdevs_t *netdevs = lws_netdevs_from_ctx(ctx);
+
+       si = lws_settings_init(&sett, (void *)"nvs");
+       if (!si) {
+               lwsl_err("%s: failed to create settings instance\n", __func__);
+               return 1;
+       }
+       netdevs->si = si;
+
+#if 0
+       /*
+        * This is a temp hack to bootstrap the settings to contain the test
+        * AP ssid and passphrase for one time, so the settings can be stored
+        * while there's no UI atm
+        */
+       {
+               lws_wifi_creds_t creds;
+
+               memset(&creds, 0, sizeof(creds));
+
+               lws_strncpy(creds.ssid, "xxx", sizeof(creds.ssid));
+               lws_strncpy(creds.passphrase, "yyy", sizeof(creds.passphrase));
+               lws_dll2_add_tail(&creds.list, &netdevs->owner_creds);
+
+               if (lws_netdev_credentials_settings_set(netdevs)) {
+                       lwsl_err("%s: failed to write bootstrap creds\n",
+                                       __func__);
+                       return 1;
+               }
+       }
+#endif
+
+//     if (lws_netdev_instance_wifi_settings_get(si, "netdev.wl0", &niw, &ac)) {
+//             lwsl_err("%s: unable to fetch wl0 settings\n", __func__);
+//             return 1;
+//     }
+
+       /* create the wifi network device and configure it */
+
+       wnd = (lws_netdev_instance_wifi_t *)
+                               wifi_ops.create(ctx, &wifi_ops, "wl0", NULL);
+       if (!wnd) {
+               lwsl_err("%s: failed to create wifi object\n", __func__);
+               return 1;
+       }
+
+       wnd->flags |= LNDIW_MODE_STA;
+
+       if (wifi_ops.configure(&wnd->inst, NULL)) {
+               lwsl_err("%s: failed to configure wifi object\n", __func__);
+               return 1;
+       }
+
+       wifi_ops.up(&wnd->inst);
+
+       /* bring up the led controller */
+
+       lls = lgc.led_ops.create(&lgc.led_ops);
+       if (!lls) {
+               lwsl_err("%s: could not create led\n", __func__);
+               return 1;
+       }
+
+       /* pwm init must go after the led controller init */
+
+       pwm_ops.init(&pwm_ops);
+
+       /* ... and the button controller */
+
+       bcs = lws_button_controller_create(ctx, &bc);
+       if (!bcs) {
+               lwsl_err("%s: could not create buttons\n", __func__);
+               return 1;
+       }
+
+       lws_button_enable(bcs, 0, lws_button_get_bit(bcs, "user"));
+
+       /* ... bring up spi bb and the display */
+
+       lbspi.bb_ops.init(&lbspi.bb_ops);
+       lws_display_state_init(&lds, ctx, 30000, 10000, lls, &disp.disp);
+
+       /*
+        * Make the RGB LED do something using sequenced PWM... pressing the
+        * GPIO14 button with single-presses advances the blue channel between
+        * different sequences
+        */
+
+       lws_led_transition(lls, "blue", &lws_pwmseq_sine_endless_fast,
+                                       &lws_pwmseq_linear_wipe);
+       lws_led_transition(lls, "green", &lws_pwmseq_sine_endless_slow,
+                                        &lws_pwmseq_linear_wipe);
+       lws_led_transition(lls, "red", &lws_pwmseq_sine_endless_slow,
+                                      &lws_pwmseq_linear_wipe);
+
+       return 0;
+}
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/main/lws-minimal-esp32.c b/minimal-examples/embedded/esp32/esp-wrover-kit/main/lws-minimal-esp32.c
new file mode 100644 (file)
index 0000000..5843317
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * lws-minimal-esp32
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * Configured for ESP32 WROVER KIT
+ *
+ * What should be notable about this is there are no esp-idf apis used here or
+ * any related files, despite we are running on top of stock esp-idf.
+ */
+
+#define LWIP_PROVIDE_ERRNO 1
+#define _ESP_PLATFORM_ERRNO_H_
+
+#include <stdio.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include <driver/gpio.h>
+
+#include <libwebsockets.h>
+
+struct lws_context *context;
+extern struct lws_led_state *lls;
+extern lws_display_state_t lds;
+extern struct lws_button_state *bcs;
+extern lws_netdev_instance_wifi_t *wnd;
+
+lws_sorted_usec_list_t         sul_pass;
+
+extern int init_plat_devices(struct lws_context *);
+
+static const uint8_t logo[] = {
+#include "cat-565.h"
+};
+
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+#include "static-policy.h"
+#else
+#include "policy.h"
+#endif
+
+static uint8_t flip;
+
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+
+       size_t                          amount;
+
+} myss_t;
+
+/*
+ * When we're actually happy we passed, we schedule the actual pass
+ * string to happen a few seconds later, so we can observe what the
+ * code did after the pass.
+ */
+
+static void
+completion_sul_cb(lws_sorted_usec_list_t *sul)
+{
+       /*
+        * In CI, we use sai-expect to look for this
+        * string for success
+        */
+
+       lwsl_notice("Completed: PASS\n");
+}
+
+static int
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+//     lwsl_hexdump_info(buf, len);
+       m->amount += len;
+
+       if (flags & LWSSS_FLAG_EOM) {
+
+               /*
+                * If we received the whole message, for our example it means
+                * we are done.
+                *
+                * Howevere we want to record what happened after we received
+                * the last bit so we can see anything unexpected coming.  So
+                * wait 5s before sending the PASS magic.
+                */
+
+               lwsl_notice("%s: received %u bytes, passing in 10s\n",
+                           __func__, (unsigned int)m->amount);
+
+               lws_sul_schedule(context, 0, &sul_pass, completion_sul_cb,
+                                5 * LWS_US_PER_SEC);
+
+               return LWSSSSRET_DESTROY_ME;
+       }
+
+       return 0;
+}
+
+static int
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               lws_ss_client_connect(m->ss);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const lws_ss_info_t ssi = {
+       .handle_offset                  = offsetof(myss_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_t, opaque_data),
+       .rx                             = myss_rx,
+       .state                          = myss_state,
+       .user_alloc                     = sizeof(myss_t),
+       .streamtype                     = "test_stream",
+};
+
+static const lws_led_sequence_def_t *seqs[] = {
+       &lws_pwmseq_static_on,
+       &lws_pwmseq_static_off,
+       &lws_pwmseq_sine_endless_slow,
+       &lws_pwmseq_sine_endless_fast,
+};
+
+static int
+smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp, void *buf,
+       size_t len)
+{
+
+       if (!lws_json_simple_strcmp(buf, len, "\"src\":", "bc/user") &&
+           !lws_json_simple_strcmp(buf, len, "\"event\":", "click")) {
+               lws_led_transition(lls, "blue", seqs[flip & 3],
+                                  &lws_pwmseq_linear_wipe);
+               flip++;
+       }
+
+       lwsl_hexdump_notice(buf, len);
+
+       if ((_class & LWSSMDCL_SYSTEM_STATE) &&
+           !lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
+
+               /* create the secure stream */
+
+               lwsl_notice("%s: creating test secure stream\n", __func__);
+
+               if (lws_ss_create(context, 0, &ssi, NULL, NULL, NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+                       return -1;
+               }
+       }
+
+       if (_class & LWSSMDCL_INTERACTION)
+               /*
+                * Any kind of user interaction brings the display back up and
+                * resets the dimming / blanking timers
+                */
+               lws_display_state_active(&lds);
+
+       return 0;
+}
+
+void 
+app_main(void)
+{
+       struct lws_context_creation_info *info;
+
+       lws_set_log_level(1024 | 15, NULL);
+
+        lws_netdev_plat_init();
+        lws_netdev_plat_wifi_init();
+
+        info = malloc(sizeof(*info));
+        if (!info)
+               goto spin;
+
+       memset(info, 0, sizeof(*info));
+
+       lwsl_notice("LWS test for Espressif ESP32 WROVER KIT\n");
+
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       info->pss_policies_json         = ss_policy;
+#else
+       info->pss_policies              = &_ss_static_policy_entry;
+#endif
+       info->options                   = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                                         LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info->port                      = CONTEXT_PORT_NO_LISTEN;
+       info->early_smd_cb              = smd_cb;
+       info->early_smd_class_filter    = LWSSMDCL_INTERACTION |
+                                         LWSSMDCL_SYSTEM_STATE |
+                                         LWSSMDCL_NETWORK;
+       info->smd_ttl_us                = 20 * LWS_USEC_PER_SEC; /* we can spend a long time in display */
+
+       context = lws_create_context(info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               goto spin;
+       }
+
+       /*
+        * We don't need this after context creation... things it pointed to
+        * still need to exist though since the context copied the pointers.
+        */
+
+       free(info);
+
+       /* devices and init are in devices.c */
+
+       if (init_plat_devices(context))
+               goto spin;
+
+       /* put the cat picture up there and enable the backlight */
+
+       lds.disp->blit(lds.disp, logo, 0, 0, 320, 240);
+       lws_display_state_active(&lds);
+
+       /* the lws event loop */
+
+       do {
+               taskYIELD();
+               lws_service(context, 0);
+       } while (1);
+
+       lwsl_notice("%s: exited event loop\n", __func__);
+
+
+spin:
+       vTaskDelay(10);
+       taskYIELD();
+       goto spin;
+}
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/main/policy.h b/minimal-examples/embedded/esp32/esp-wrover-kit/main/policy.h
new file mode 100644 (file)
index 0000000..5524332
--- /dev/null
@@ -0,0 +1,98 @@
+
+static const char * const ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "25,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                */
+                               "{\"isrg_root_x1\": \""
+"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="
+         "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": ["
+
+               "{\"test_stream\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h2\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"index.html\","
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}},{"
+                       /*
+                        * "captive_portal_detect" describes
+                        * what to do in order to check if the path to
+                        * the Internet is being interrupted by a
+                        * captive portal.
+                        */
+                   "\"captive_portal_detect\": {"
+                        "\"endpoint\":"                "\"connectivitycheck.android.com\","
+                       "\"http_url\":"         "\"generate_204\","
+                       "\"port\":"             "80,"
+                        "\"protocol\":"                "\"h1\","
+                        "\"http_method\":"     "\"GET\","
+                        "\"opportunistic\":"   "true,"
+                        "\"http_expect\":"     "204,"
+                       "\"http_fail_redirect\": true"
+                "}}"
+       "]}"
+;
+
+
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/main/static-policy.h b/minimal-examples/embedded/esp32/esp-wrover-kit/main/static-policy.h
new file mode 100644 (file)
index 0000000..cb89fb6
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Autogenerated from the following JSON policy
+ */
+
+#if 0
+
+
+ Original JSON size: 13
+#endif
+
+static const uint32_t _rbo_bo_0[] = {
+ 1000,  2000,  3000,  5000,  10000, 
+};
+static const lws_retry_bo_t _rbo_0 = {
+       .retry_ms_table = _rbo_bo_0,
+       .retry_ms_table_count = 5,
+       .conceal_count = 25,
+       .secs_since_valid_ping = 30,
+       .secs_since_valid_hangup = 35,
+       .jitter_percent = 20,
+};
+static const uint8_t _ss_der_isrg_root_x1[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x05, 0x6B, 0x30, 0x82, 0x03, 0x53, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 
+       /* 0x 10 */ 0x82, 0x10, 0xCF, 0xB0, 0xD2, 0x40, 0xE3, 0x59, 
+       /* 0x 18 */ 0x44, 0x63, 0xE0, 0xBB, 0x63, 0x82, 0x8B, 0x00, 
+       /* 0x 20 */ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+       /* 0x 28 */ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 
+       /* 0x 30 */ 0x4F, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 
+       /* 0x 38 */ 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x29, 
+       /* 0x 40 */ 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 
+       /* 0x 48 */ 0x20, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 
+       /* 0x 50 */ 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 
+       /* 0x 58 */ 0x74, 0x79, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 
+       /* 0x 60 */ 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6F, 0x75, 
+       /* 0x 68 */ 0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 
+       /* 0x 70 */ 0x04, 0x03, 0x13, 0x0C, 0x49, 0x53, 0x52, 0x47, 
+       /* 0x 78 */ 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x58, 0x31, 
+       /* 0x 80 */ 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x35, 0x30, 0x36, 
+       /* 0x 88 */ 0x30, 0x34, 0x31, 0x31, 0x30, 0x34, 0x33, 0x38, 
+       /* 0x 90 */ 0x5A, 0x17, 0x0D, 0x33, 0x35, 0x30, 0x36, 0x30, 
+       /* 0x 98 */ 0x34, 0x31, 0x31, 0x30, 0x34, 0x33, 0x38, 0x5A, 
+       /* 0x a0 */ 0x30, 0x4F, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 
+       /* 0x a8 */ 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 
+       /* 0x b0 */ 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x0A, 
+       /* 0x b8 */ 0x13, 0x20, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 
+       /* 0x c0 */ 0x65, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 
+       /* 0x c8 */ 0x69, 0x74, 0x79, 0x20, 0x52, 0x65, 0x73, 0x65, 
+       /* 0x d0 */ 0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6F, 
+       /* 0x d8 */ 0x75, 0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 
+       /* 0x e0 */ 0x55, 0x04, 0x03, 0x13, 0x0C, 0x49, 0x53, 0x52, 
+       /* 0x e8 */ 0x47, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x58, 
+       /* 0x f0 */ 0x31, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0D, 0x06, 
+       /* 0x f8 */ 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 
+       /* 0x100 */ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0F, 
+       /* 0x108 */ 0x00, 0x30, 0x82, 0x02, 0x0A, 0x02, 0x82, 0x02, 
+       /* 0x110 */ 0x01, 0x00, 0xAD, 0xE8, 0x24, 0x73, 0xF4, 0x14, 
+       /* 0x118 */ 0x37, 0xF3, 0x9B, 0x9E, 0x2B, 0x57, 0x28, 0x1C, 
+       /* 0x120 */ 0x87, 0xBE, 0xDC, 0xB7, 0xDF, 0x38, 0x90, 0x8C, 
+       /* 0x128 */ 0x6E, 0x3C, 0xE6, 0x57, 0xA0, 0x78, 0xF7, 0x75, 
+       /* 0x130 */ 0xC2, 0xA2, 0xFE, 0xF5, 0x6A, 0x6E, 0xF6, 0x00, 
+       /* 0x138 */ 0x4F, 0x28, 0xDB, 0xDE, 0x68, 0x86, 0x6C, 0x44, 
+       /* 0x140 */ 0x93, 0xB6, 0xB1, 0x63, 0xFD, 0x14, 0x12, 0x6B, 
+       /* 0x148 */ 0xBF, 0x1F, 0xD2, 0xEA, 0x31, 0x9B, 0x21, 0x7E, 
+       /* 0x150 */ 0xD1, 0x33, 0x3C, 0xBA, 0x48, 0xF5, 0xDD, 0x79, 
+       /* 0x158 */ 0xDF, 0xB3, 0xB8, 0xFF, 0x12, 0xF1, 0x21, 0x9A, 
+       /* 0x160 */ 0x4B, 0xC1, 0x8A, 0x86, 0x71, 0x69, 0x4A, 0x66, 
+       /* 0x168 */ 0x66, 0x6C, 0x8F, 0x7E, 0x3C, 0x70, 0xBF, 0xAD, 
+       /* 0x170 */ 0x29, 0x22, 0x06, 0xF3, 0xE4, 0xC0, 0xE6, 0x80, 
+       /* 0x178 */ 0xAE, 0xE2, 0x4B, 0x8F, 0xB7, 0x99, 0x7E, 0x94, 
+       /* 0x180 */ 0x03, 0x9F, 0xD3, 0x47, 0x97, 0x7C, 0x99, 0x48, 
+       /* 0x188 */ 0x23, 0x53, 0xE8, 0x38, 0xAE, 0x4F, 0x0A, 0x6F, 
+       /* 0x190 */ 0x83, 0x2E, 0xD1, 0x49, 0x57, 0x8C, 0x80, 0x74, 
+       /* 0x198 */ 0xB6, 0xDA, 0x2F, 0xD0, 0x38, 0x8D, 0x7B, 0x03, 
+       /* 0x1a0 */ 0x70, 0x21, 0x1B, 0x75, 0xF2, 0x30, 0x3C, 0xFA, 
+       /* 0x1a8 */ 0x8F, 0xAE, 0xDD, 0xDA, 0x63, 0xAB, 0xEB, 0x16, 
+       /* 0x1b0 */ 0x4F, 0xC2, 0x8E, 0x11, 0x4B, 0x7E, 0xCF, 0x0B, 
+       /* 0x1b8 */ 0xE8, 0xFF, 0xB5, 0x77, 0x2E, 0xF4, 0xB2, 0x7B, 
+       /* 0x1c0 */ 0x4A, 0xE0, 0x4C, 0x12, 0x25, 0x0C, 0x70, 0x8D, 
+       /* 0x1c8 */ 0x03, 0x29, 0xA0, 0xE1, 0x53, 0x24, 0xEC, 0x13, 
+       /* 0x1d0 */ 0xD9, 0xEE, 0x19, 0xBF, 0x10, 0xB3, 0x4A, 0x8C, 
+       /* 0x1d8 */ 0x3F, 0x89, 0xA3, 0x61, 0x51, 0xDE, 0xAC, 0x87, 
+       /* 0x1e0 */ 0x07, 0x94, 0xF4, 0x63, 0x71, 0xEC, 0x2E, 0xE2, 
+       /* 0x1e8 */ 0x6F, 0x5B, 0x98, 0x81, 0xE1, 0x89, 0x5C, 0x34, 
+       /* 0x1f0 */ 0x79, 0x6C, 0x76, 0xEF, 0x3B, 0x90, 0x62, 0x79, 
+       /* 0x1f8 */ 0xE6, 0xDB, 0xA4, 0x9A, 0x2F, 0x26, 0xC5, 0xD0, 
+       /* 0x200 */ 0x10, 0xE1, 0x0E, 0xDE, 0xD9, 0x10, 0x8E, 0x16, 
+       /* 0x208 */ 0xFB, 0xB7, 0xF7, 0xA8, 0xF7, 0xC7, 0xE5, 0x02, 
+       /* 0x210 */ 0x07, 0x98, 0x8F, 0x36, 0x08, 0x95, 0xE7, 0xE2, 
+       /* 0x218 */ 0x37, 0x96, 0x0D, 0x36, 0x75, 0x9E, 0xFB, 0x0E, 
+       /* 0x220 */ 0x72, 0xB1, 0x1D, 0x9B, 0xBC, 0x03, 0xF9, 0x49, 
+       /* 0x228 */ 0x05, 0xD8, 0x81, 0xDD, 0x05, 0xB4, 0x2A, 0xD6, 
+       /* 0x230 */ 0x41, 0xE9, 0xAC, 0x01, 0x76, 0x95, 0x0A, 0x0F, 
+       /* 0x238 */ 0xD8, 0xDF, 0xD5, 0xBD, 0x12, 0x1F, 0x35, 0x2F, 
+       /* 0x240 */ 0x28, 0x17, 0x6C, 0xD2, 0x98, 0xC1, 0xA8, 0x09, 
+       /* 0x248 */ 0x64, 0x77, 0x6E, 0x47, 0x37, 0xBA, 0xCE, 0xAC, 
+       /* 0x250 */ 0x59, 0x5E, 0x68, 0x9D, 0x7F, 0x72, 0xD6, 0x89, 
+       /* 0x258 */ 0xC5, 0x06, 0x41, 0x29, 0x3E, 0x59, 0x3E, 0xDD, 
+       /* 0x260 */ 0x26, 0xF5, 0x24, 0xC9, 0x11, 0xA7, 0x5A, 0xA3, 
+       /* 0x268 */ 0x4C, 0x40, 0x1F, 0x46, 0xA1, 0x99, 0xB5, 0xA7, 
+       /* 0x270 */ 0x3A, 0x51, 0x6E, 0x86, 0x3B, 0x9E, 0x7D, 0x72, 
+       /* 0x278 */ 0xA7, 0x12, 0x05, 0x78, 0x59, 0xED, 0x3E, 0x51, 
+       /* 0x280 */ 0x78, 0x15, 0x0B, 0x03, 0x8F, 0x8D, 0xD0, 0x2F, 
+       /* 0x288 */ 0x05, 0xB2, 0x3E, 0x7B, 0x4A, 0x1C, 0x4B, 0x73, 
+       /* 0x290 */ 0x05, 0x12, 0xFC, 0xC6, 0xEA, 0xE0, 0x50, 0x13, 
+       /* 0x298 */ 0x7C, 0x43, 0x93, 0x74, 0xB3, 0xCA, 0x74, 0xE7, 
+       /* 0x2a0 */ 0x8E, 0x1F, 0x01, 0x08, 0xD0, 0x30, 0xD4, 0x5B, 
+       /* 0x2a8 */ 0x71, 0x36, 0xB4, 0x07, 0xBA, 0xC1, 0x30, 0x30, 
+       /* 0x2b0 */ 0x5C, 0x48, 0xB7, 0x82, 0x3B, 0x98, 0xA6, 0x7D, 
+       /* 0x2b8 */ 0x60, 0x8A, 0xA2, 0xA3, 0x29, 0x82, 0xCC, 0xBA, 
+       /* 0x2c0 */ 0xBD, 0x83, 0x04, 0x1B, 0xA2, 0x83, 0x03, 0x41, 
+       /* 0x2c8 */ 0xA1, 0xD6, 0x05, 0xF1, 0x1B, 0xC2, 0xB6, 0xF0, 
+       /* 0x2d0 */ 0xA8, 0x7C, 0x86, 0x3B, 0x46, 0xA8, 0x48, 0x2A, 
+       /* 0x2d8 */ 0x88, 0xDC, 0x76, 0x9A, 0x76, 0xBF, 0x1F, 0x6A, 
+       /* 0x2e0 */ 0xA5, 0x3D, 0x19, 0x8F, 0xEB, 0x38, 0xF3, 0x64, 
+       /* 0x2e8 */ 0xDE, 0xC8, 0x2B, 0x0D, 0x0A, 0x28, 0xFF, 0xF7, 
+       /* 0x2f0 */ 0xDB, 0xE2, 0x15, 0x42, 0xD4, 0x22, 0xD0, 0x27, 
+       /* 0x2f8 */ 0x5D, 0xE1, 0x79, 0xFE, 0x18, 0xE7, 0x70, 0x88, 
+       /* 0x300 */ 0xAD, 0x4E, 0xE6, 0xD9, 0x8B, 0x3A, 0xC6, 0xDD, 
+       /* 0x308 */ 0x27, 0x51, 0x6E, 0xFF, 0xBC, 0x64, 0xF5, 0x33, 
+       /* 0x310 */ 0x43, 0x4F, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 
+       /* 0x318 */ 0x42, 0x30, 0x40, 0x30, 0x0E, 0x06, 0x03, 0x55, 
+       /* 0x320 */ 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 
+       /* 0x328 */ 0x02, 0x01, 0x06, 0x30, 0x0F, 0x06, 0x03, 0x55, 
+       /* 0x330 */ 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x05, 0x30, 
+       /* 0x338 */ 0x03, 0x01, 0x01, 0xFF, 0x30, 0x1D, 0x06, 0x03, 
+       /* 0x340 */ 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x79, 
+       /* 0x348 */ 0xB4, 0x59, 0xE6, 0x7B, 0xB6, 0xE5, 0xE4, 0x01, 
+       /* 0x350 */ 0x73, 0x80, 0x08, 0x88, 0xC8, 0x1A, 0x58, 0xF6, 
+       /* 0x358 */ 0xE9, 0x9B, 0x6E, 0x30, 0x0D, 0x06, 0x09, 0x2A, 
+       /* 0x360 */ 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 
+       /* 0x368 */ 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x55, 
+       /* 0x370 */ 0x1F, 0x58, 0xA9, 0xBC, 0xB2, 0xA8, 0x50, 0xD0, 
+       /* 0x378 */ 0x0C, 0xB1, 0xD8, 0x1A, 0x69, 0x20, 0x27, 0x29, 
+       /* 0x380 */ 0x08, 0xAC, 0x61, 0x75, 0x5C, 0x8A, 0x6E, 0xF8, 
+       /* 0x388 */ 0x82, 0xE5, 0x69, 0x2F, 0xD5, 0xF6, 0x56, 0x4B, 
+       /* 0x390 */ 0xB9, 0xB8, 0x73, 0x10, 0x59, 0xD3, 0x21, 0x97, 
+       /* 0x398 */ 0x7E, 0xE7, 0x4C, 0x71, 0xFB, 0xB2, 0xD2, 0x60, 
+       /* 0x3a0 */ 0xAD, 0x39, 0xA8, 0x0B, 0xEA, 0x17, 0x21, 0x56, 
+       /* 0x3a8 */ 0x85, 0xF1, 0x50, 0x0E, 0x59, 0xEB, 0xCE, 0xE0, 
+       /* 0x3b0 */ 0x59, 0xE9, 0xBA, 0xC9, 0x15, 0xEF, 0x86, 0x9D, 
+       /* 0x3b8 */ 0x8F, 0x84, 0x80, 0xF6, 0xE4, 0xE9, 0x91, 0x90, 
+       /* 0x3c0 */ 0xDC, 0x17, 0x9B, 0x62, 0x1B, 0x45, 0xF0, 0x66, 
+       /* 0x3c8 */ 0x95, 0xD2, 0x7C, 0x6F, 0xC2, 0xEA, 0x3B, 0xEF, 
+       /* 0x3d0 */ 0x1F, 0xCF, 0xCB, 0xD6, 0xAE, 0x27, 0xF1, 0xA9, 
+       /* 0x3d8 */ 0xB0, 0xC8, 0xAE, 0xFD, 0x7D, 0x7E, 0x9A, 0xFA, 
+       /* 0x3e0 */ 0x22, 0x04, 0xEB, 0xFF, 0xD9, 0x7F, 0xEA, 0x91, 
+       /* 0x3e8 */ 0x2B, 0x22, 0xB1, 0x17, 0x0E, 0x8F, 0xF2, 0x8A, 
+       /* 0x3f0 */ 0x34, 0x5B, 0x58, 0xD8, 0xFC, 0x01, 0xC9, 0x54, 
+       /* 0x3f8 */ 0xB9, 0xB8, 0x26, 0xCC, 0x8A, 0x88, 0x33, 0x89, 
+       /* 0x400 */ 0x4C, 0x2D, 0x84, 0x3C, 0x82, 0xDF, 0xEE, 0x96, 
+       /* 0x408 */ 0x57, 0x05, 0xBA, 0x2C, 0xBB, 0xF7, 0xC4, 0xB7, 
+       /* 0x410 */ 0xC7, 0x4E, 0x3B, 0x82, 0xBE, 0x31, 0xC8, 0x22, 
+       /* 0x418 */ 0x73, 0x73, 0x92, 0xD1, 0xC2, 0x80, 0xA4, 0x39, 
+       /* 0x420 */ 0x39, 0x10, 0x33, 0x23, 0x82, 0x4C, 0x3C, 0x9F, 
+       /* 0x428 */ 0x86, 0xB2, 0x55, 0x98, 0x1D, 0xBE, 0x29, 0x86, 
+       /* 0x430 */ 0x8C, 0x22, 0x9B, 0x9E, 0xE2, 0x6B, 0x3B, 0x57, 
+       /* 0x438 */ 0x3A, 0x82, 0x70, 0x4D, 0xDC, 0x09, 0xC7, 0x89, 
+       /* 0x440 */ 0xCB, 0x0A, 0x07, 0x4D, 0x6C, 0xE8, 0x5D, 0x8E, 
+       /* 0x448 */ 0xC9, 0xEF, 0xCE, 0xAB, 0xC7, 0xBB, 0xB5, 0x2B, 
+       /* 0x450 */ 0x4E, 0x45, 0xD6, 0x4A, 0xD0, 0x26, 0xCC, 0xE5, 
+       /* 0x458 */ 0x72, 0xCA, 0x08, 0x6A, 0xA5, 0x95, 0xE3, 0x15, 
+       /* 0x460 */ 0xA1, 0xF7, 0xA4, 0xED, 0xC9, 0x2C, 0x5F, 0xA5, 
+       /* 0x468 */ 0xFB, 0xFF, 0xAC, 0x28, 0x02, 0x2E, 0xBE, 0xD7, 
+       /* 0x470 */ 0x7B, 0xBB, 0xE3, 0x71, 0x7B, 0x90, 0x16, 0xD3, 
+       /* 0x478 */ 0x07, 0x5E, 0x46, 0x53, 0x7C, 0x37, 0x07, 0x42, 
+       /* 0x480 */ 0x8C, 0xD3, 0xC4, 0x96, 0x9C, 0xD5, 0x99, 0xB5, 
+       /* 0x488 */ 0x2A, 0xE0, 0x95, 0x1A, 0x80, 0x48, 0xAE, 0x4C, 
+       /* 0x490 */ 0x39, 0x07, 0xCE, 0xCC, 0x47, 0xA4, 0x52, 0x95, 
+       /* 0x498 */ 0x2B, 0xBA, 0xB8, 0xFB, 0xAD, 0xD2, 0x33, 0x53, 
+       /* 0x4a0 */ 0x7D, 0xE5, 0x1D, 0x4D, 0x6D, 0xD5, 0xA1, 0xB1, 
+       /* 0x4a8 */ 0xC7, 0x42, 0x6F, 0xE6, 0x40, 0x27, 0x35, 0x5C, 
+       /* 0x4b0 */ 0xA3, 0x28, 0xB7, 0x07, 0x8D, 0xE7, 0x8D, 0x33, 
+       /* 0x4b8 */ 0x90, 0xE7, 0x23, 0x9F, 0xFB, 0x50, 0x9C, 0x79, 
+       /* 0x4c0 */ 0x6C, 0x46, 0xD5, 0xB4, 0x15, 0xB3, 0x96, 0x6E, 
+       /* 0x4c8 */ 0x7E, 0x9B, 0x0C, 0x96, 0x3A, 0xB8, 0x52, 0x2D, 
+       /* 0x4d0 */ 0x3F, 0xD6, 0x5B, 0xE1, 0xFB, 0x08, 0xC2, 0x84, 
+       /* 0x4d8 */ 0xFE, 0x24, 0xA8, 0xA3, 0x89, 0xDA, 0xAC, 0x6A, 
+       /* 0x4e0 */ 0xE1, 0x18, 0x2A, 0xB1, 0xA8, 0x43, 0x61, 0x5B, 
+       /* 0x4e8 */ 0xD3, 0x1F, 0xDC, 0x3B, 0x8D, 0x76, 0xF2, 0x2D, 
+       /* 0x4f0 */ 0xE8, 0x8D, 0x75, 0xDF, 0x17, 0x33, 0x6C, 0x3D, 
+       /* 0x4f8 */ 0x53, 0xFB, 0x7B, 0xCB, 0x41, 0x5F, 0xFF, 0xDC, 
+       /* 0x500 */ 0xA2, 0xD0, 0x61, 0x38, 0xE1, 0x96, 0xB8, 0xAC, 
+       /* 0x508 */ 0x5D, 0x8B, 0x37, 0xD7, 0x75, 0xD5, 0x33, 0xC0, 
+       /* 0x510 */ 0x99, 0x11, 0xAE, 0x9D, 0x41, 0xC1, 0x72, 0x75, 
+       /* 0x518 */ 0x84, 0xBE, 0x02, 0x41, 0x42, 0x5F, 0x67, 0x24, 
+       /* 0x520 */ 0x48, 0x94, 0xD1, 0x9B, 0x27, 0xBE, 0x07, 0x3F, 
+       /* 0x528 */ 0xB9, 0xB8, 0x4F, 0x81, 0x74, 0x51, 0xE1, 0x7A, 
+       /* 0x530 */ 0xB7, 0xED, 0x9D, 0x23, 0xE2, 0xBE, 0xE0, 0xD5, 
+       /* 0x538 */ 0x28, 0x04, 0x13, 0x3C, 0x31, 0x03, 0x9E, 0xDD, 
+       /* 0x540 */ 0x7A, 0x6C, 0x8F, 0xC6, 0x07, 0x18, 0xC6, 0x7F, 
+       /* 0x548 */ 0xDE, 0x47, 0x8E, 0x3F, 0x28, 0x9E, 0x04, 0x06, 
+       /* 0x550 */ 0xCF, 0xA5, 0x54, 0x34, 0x77, 0xBD, 0xEC, 0x89, 
+       /* 0x558 */ 0x9B, 0xE9, 0x17, 0x43, 0xDF, 0x5B, 0xDB, 0x5F, 
+       /* 0x560 */ 0xFE, 0x8E, 0x1E, 0x57, 0xA2, 0xCD, 0x40, 0x9D, 
+       /* 0x568 */ 0x7E, 0x62, 0x22, 0xDA, 0xDE, 0x18, 0x27, 
+};
+static const lws_ss_x509_t _ss_x509_isrg_root_x1 = {
+       .vhost_name = "isrg_root_x1",
+       .ca_der = _ss_der_isrg_root_x1,
+       .ca_der_len = 1391,
+};
+static const lws_ss_trust_store_t _ss_ts_le_via_isrg = {
+       .name = "le_via_isrg",
+       .count = 1,
+       .ssx509 = {
+               &_ss_x509_isrg_root_x1,
+       }
+};
+
+static const lws_ss_policy_t _ssp_captive_portal_detect = {
+       .streamtype = "captive_portal_detect",
+       .endpoint = "connectivitycheck.android.com",
+       .u = {
+               .http = {
+                       .method = "GET",
+                       .url = "generate_204",
+                       .resp_expect = 204,
+                       .fail_redirect = 1,
+               }
+       },
+       .flags = 0x1,
+       .priority = 0x0,
+       .port = 80,
+       .protocol = 0,
+},
+_ssp_test_stream = {
+       .next = (void *)&_ssp_captive_portal_detect,
+       .streamtype = "test_stream",
+       .endpoint = "warmcat.com",
+       .u = {
+               .http = {
+                       .method = "GET",
+                       .url = "index.html",
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x11,
+       .priority = 0x0,
+       .port = 443,
+       .protocol = 1,
+       .trust = {.store = &_ss_ts_le_via_isrg},
+};
+#define _ss_static_policy_entry _ssp_test_stream
+/* estimated footprint 2043 (when sizeof void * = 8) */
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/partitions.csv b/minimal-examples/embedded/esp32/esp-wrover-kit/partitions.csv
new file mode 100644 (file)
index 0000000..e261b7c
--- /dev/null
@@ -0,0 +1,5 @@
+# ESP-IDF Partition Table
+# Name,   Type, SubType, Offset,  Size, Flags
+nvs,      data, nvs,     0x9000,  0x6000,
+phy_init, data, phy,     0xf000,  0x1000,
+factory,  app,  factory, 0x10000, 2M,
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/rgb565/rgb565.c b/minimal-examples/embedded/esp32/esp-wrover-kit/rgb565/rgb565.c
new file mode 100644 (file)
index 0000000..89b4999
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * gcc /tmp/q.c && convert cat-565.png -depth 8 rgb:- | ./a.out > cat-565.h
+ */
+
+#include <stdio.h>
+
+int main()
+{
+       int r, g, b, w, m = 0;
+
+       while (1) {
+               r = getchar();
+               g = getchar();
+               b = getchar();
+
+               if (r == EOF || g == EOF || b == EOF)
+                       return  r == EOF;
+
+               w = (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11);
+               printf("0x%02X, 0x%02X, ", (w >> 8) & 0xFF, w & 0xFF);
+
+               if (((++m) & 3) == 0)
+                       printf("\n");
+       }
+}
+
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/sdkconfig b/minimal-examples/embedded/esp32/esp-wrover-kit/sdkconfig
new file mode 100644 (file)
index 0000000..859ff00
--- /dev/null
@@ -0,0 +1,1151 @@
+#
+# Automatically generated file. DO NOT EDIT.
+# Espressif IoT Development Framework (ESP-IDF) Project Configuration
+#
+CONFIG_IDF_CMAKE=y
+CONFIG_IDF_TARGET="esp32"
+CONFIG_IDF_TARGET_ESP32=y
+CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
+
+#
+# SDK tool configuration
+#
+CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-"
+# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set
+# end of SDK tool configuration
+
+#
+# Build type
+#
+CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y
+# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set
+CONFIG_APP_BUILD_GENERATE_BINARIES=y
+CONFIG_APP_BUILD_BOOTLOADER=y
+CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y
+# end of Build type
+
+#
+# Application manager
+#
+CONFIG_APP_COMPILE_TIME_DATE=y
+# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
+# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
+# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set
+CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16
+# end of Application manager
+
+#
+# Bootloader config
+#
+CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
+CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
+# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
+CONFIG_BOOTLOADER_LOG_LEVEL=3
+# CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V is not set
+CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
+# CONFIG_BOOTLOADER_FACTORY_RESET is not set
+# CONFIG_BOOTLOADER_APP_TEST is not set
+CONFIG_BOOTLOADER_WDT_ENABLE=y
+# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
+CONFIG_BOOTLOADER_WDT_TIME_MS=9000
+# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set
+CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0
+# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set
+# end of Bootloader config
+
+#
+# Security features
+#
+# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set
+# CONFIG_SECURE_BOOT is not set
+# CONFIG_SECURE_FLASH_ENC_ENABLED is not set
+# end of Security features
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
+# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
+# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE="dio"
+# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
+# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ="40m"
+# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
+# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_BEFORE_RESET=y
+# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
+CONFIG_ESPTOOLPY_BEFORE="default_reset"
+CONFIG_ESPTOOLPY_AFTER_RESET=y
+# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
+CONFIG_ESPTOOLPY_AFTER="hard_reset"
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
+# end of Serial flasher config
+
+#
+# Partition Table
+#
+# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
+# CONFIG_PARTITION_TABLE_TWO_OTA is not set
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_OFFSET=0x8000
+CONFIG_PARTITION_TABLE_MD5=y
+# end of Partition Table
+
+#
+# Compiler options
+#
+CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
+# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
+# CONFIG_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
+CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
+# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
+# CONFIG_COMPILER_CXX_RTTI is not set
+CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
+# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
+# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
+# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set
+# end of Compiler options
+
+#
+# Component config
+#
+
+#
+# Application Level Tracing
+#
+# CONFIG_APPTRACE_DEST_TRAX is not set
+CONFIG_APPTRACE_DEST_NONE=y
+CONFIG_APPTRACE_LOCK_ENABLE=y
+# end of Application Level Tracing
+
+#
+# Bluetooth
+#
+# CONFIG_BT_ENABLED is not set
+CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=0
+CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0
+CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=0
+CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0
+CONFIG_BTDM_CTRL_PINNED_TO_CORE=0
+CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1
+CONFIG_BT_RESERVE_DRAM=0
+# end of Bluetooth
+
+#
+# CoAP Configuration
+#
+CONFIG_COAP_MBEDTLS_PSK=y
+# CONFIG_COAP_MBEDTLS_PKI is not set
+# CONFIG_COAP_MBEDTLS_DEBUG is not set
+CONFIG_COAP_LOG_DEFAULT_LEVEL=0
+# end of CoAP Configuration
+
+#
+# Driver configurations
+#
+
+#
+# ADC configuration
+#
+# CONFIG_ADC_FORCE_XPD_FSM is not set
+CONFIG_ADC_DISABLE_DAC=y
+# end of ADC configuration
+
+#
+# SPI configuration
+#
+# CONFIG_SPI_MASTER_IN_IRAM is not set
+CONFIG_SPI_MASTER_ISR_IN_IRAM=y
+# CONFIG_SPI_SLAVE_IN_IRAM is not set
+CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
+# end of SPI configuration
+
+#
+# UART configuration
+#
+# CONFIG_UART_ISR_IN_IRAM is not set
+# end of UART configuration
+
+#
+# RTCIO configuration
+#
+# CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC is not set
+# end of RTCIO configuration
+# end of Driver configurations
+
+#
+# eFuse Bit Manager
+#
+# CONFIG_EFUSE_CUSTOM_TABLE is not set
+# CONFIG_EFUSE_VIRTUAL is not set
+# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set
+CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y
+# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set
+CONFIG_EFUSE_MAX_BLK_LEN=192
+# end of eFuse Bit Manager
+
+#
+# ESP-TLS
+#
+CONFIG_ESP_TLS_USING_MBEDTLS=y
+# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set
+# CONFIG_ESP_TLS_SERVER is not set
+# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
+# end of ESP-TLS
+
+#
+# ESP32-specific
+#
+CONFIG_ESP32_REV_MIN_0=y
+# CONFIG_ESP32_REV_MIN_1 is not set
+# CONFIG_ESP32_REV_MIN_2 is not set
+# CONFIG_ESP32_REV_MIN_3 is not set
+CONFIG_ESP32_REV_MIN=0
+CONFIG_ESP32_DPORT_WORKAROUND=y
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
+CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_240 is not set
+CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160
+# CONFIG_ESP32_SPIRAM_SUPPORT is not set
+# CONFIG_ESP32_TRAX is not set
+CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0
+# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
+CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y
+CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4
+# CONFIG_ESP32_ULP_COPROC_ENABLED is not set
+CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0
+CONFIG_ESP32_DEBUG_OCDAWARE=y
+CONFIG_ESP32_BROWNOUT_DET=y
+CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set
+CONFIG_ESP32_BROWNOUT_DET_LVL=0
+CONFIG_ESP32_REDUCE_PHY_TX_POWER=y
+CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y
+# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set
+# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set
+# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set
+CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y
+# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set
+# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set
+# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set
+CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024
+CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000
+CONFIG_ESP32_XTAL_FREQ_40=y
+# CONFIG_ESP32_XTAL_FREQ_26 is not set
+# CONFIG_ESP32_XTAL_FREQ_AUTO is not set
+CONFIG_ESP32_XTAL_FREQ=40
+# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set
+# CONFIG_ESP32_NO_BLOBS is not set
+# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
+# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set
+CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5
+# end of ESP32-specific
+
+#
+# Power Management
+#
+# CONFIG_PM_ENABLE is not set
+# end of Power Management
+
+#
+# ADC-Calibration
+#
+CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
+CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
+CONFIG_ADC_CAL_LUT_ENABLE=y
+# end of ADC-Calibration
+
+#
+# Common ESP-related
+#
+CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
+CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=6584
+CONFIG_ESP_IPC_TASK_STACK_SIZE=1024
+CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y
+CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
+CONFIG_ESP_CONSOLE_UART_DEFAULT=y
+# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_UART_NONE is not set
+CONFIG_ESP_CONSOLE_UART_NUM=0
+CONFIG_ESP_CONSOLE_UART_TX_GPIO=1
+CONFIG_ESP_CONSOLE_UART_RX_GPIO=3
+CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
+CONFIG_ESP_INT_WDT=y
+CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
+CONFIG_ESP_INT_WDT_CHECK_CPU1=y
+CONFIG_ESP_TASK_WDT=y
+# CONFIG_ESP_TASK_WDT_PANIC is not set
+CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
+CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
+# CONFIG_ESP_PANIC_HANDLER_IRAM is not set
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
+# end of Common ESP-related
+
+#
+# Ethernet
+#
+CONFIG_ETH_ENABLED=y
+CONFIG_ETH_USE_ESP32_EMAC=y
+CONFIG_ETH_PHY_INTERFACE_RMII=y
+# CONFIG_ETH_PHY_INTERFACE_MII is not set
+CONFIG_ETH_RMII_CLK_INPUT=y
+# CONFIG_ETH_RMII_CLK_OUTPUT is not set
+CONFIG_ETH_RMII_CLK_IN_GPIO=0
+CONFIG_ETH_DMA_BUFFER_SIZE=512
+CONFIG_ETH_DMA_RX_BUFFER_NUM=10
+CONFIG_ETH_DMA_TX_BUFFER_NUM=10
+CONFIG_ETH_USE_SPI_ETHERNET=y
+# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set
+# CONFIG_ETH_USE_OPENETH is not set
+# end of Ethernet
+
+#
+# Event Loop Library
+#
+# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
+CONFIG_ESP_EVENT_POST_FROM_ISR=y
+CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
+# end of Event Loop Library
+
+#
+# GDB Stub
+#
+# end of GDB Stub
+
+#
+# ESP HTTP client
+#
+CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
+# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
+# end of ESP HTTP client
+
+#
+# HTTP Server
+#
+CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
+CONFIG_HTTPD_MAX_URI_LEN=512
+CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
+CONFIG_HTTPD_PURGE_BUF_LEN=32
+# CONFIG_HTTPD_LOG_PURGE_DATA is not set
+# CONFIG_HTTPD_WS_SUPPORT is not set
+# end of HTTP Server
+
+#
+# ESP HTTPS OTA
+#
+# CONFIG_OTA_ALLOW_HTTP is not set
+# end of ESP HTTPS OTA
+
+#
+# ESP HTTPS server
+#
+# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
+# end of ESP HTTPS server
+
+#
+# ESP NETIF Adapter
+#
+CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
+CONFIG_ESP_NETIF_TCPIP_LWIP=y
+# CONFIG_ESP_NETIF_LOOPBACK is not set
+CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y
+# end of ESP NETIF Adapter
+
+#
+# ESP System Settings
+#
+# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
+CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
+# end of ESP System Settings
+
+#
+# High resolution timer (esp_timer)
+#
+# CONFIG_ESP_TIMER_PROFILING is not set
+CONFIG_ESP_TIMER_TASK_STACK_SIZE=6584
+# CONFIG_ESP_TIMER_IMPL_FRC2 is not set
+CONFIG_ESP_TIMER_IMPL_TG0_LAC=y
+# end of High resolution timer (esp_timer)
+
+#
+# Wi-Fi
+#
+CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y
+CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
+CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP32_WIFI_TX_BA_WIN=6
+CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP32_WIFI_RX_BA_WIN=6
+CONFIG_ESP32_WIFI_NVS_ENABLED=y
+CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
+# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set
+CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752
+CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
+# CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE is not set
+CONFIG_ESP32_WIFI_IRAM_OPT=y
+CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
+# end of Wi-Fi
+
+#
+# PHY
+#
+CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
+# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
+CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
+CONFIG_ESP32_PHY_MAX_TX_POWER=20
+# end of PHY
+
+#
+# Core dump
+#
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
+CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
+# end of Core dump
+
+#
+# FAT Filesystem support
+#
+# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set
+CONFIG_FATFS_CODEPAGE_437=y
+# CONFIG_FATFS_CODEPAGE_720 is not set
+# CONFIG_FATFS_CODEPAGE_737 is not set
+# CONFIG_FATFS_CODEPAGE_771 is not set
+# CONFIG_FATFS_CODEPAGE_775 is not set
+# CONFIG_FATFS_CODEPAGE_850 is not set
+# CONFIG_FATFS_CODEPAGE_852 is not set
+# CONFIG_FATFS_CODEPAGE_855 is not set
+# CONFIG_FATFS_CODEPAGE_857 is not set
+# CONFIG_FATFS_CODEPAGE_860 is not set
+# CONFIG_FATFS_CODEPAGE_861 is not set
+# CONFIG_FATFS_CODEPAGE_862 is not set
+# CONFIG_FATFS_CODEPAGE_863 is not set
+# CONFIG_FATFS_CODEPAGE_864 is not set
+# CONFIG_FATFS_CODEPAGE_865 is not set
+# CONFIG_FATFS_CODEPAGE_866 is not set
+# CONFIG_FATFS_CODEPAGE_869 is not set
+# CONFIG_FATFS_CODEPAGE_932 is not set
+# CONFIG_FATFS_CODEPAGE_936 is not set
+# CONFIG_FATFS_CODEPAGE_949 is not set
+# CONFIG_FATFS_CODEPAGE_950 is not set
+CONFIG_FATFS_CODEPAGE=437
+CONFIG_FATFS_LFN_NONE=y
+# CONFIG_FATFS_LFN_HEAP is not set
+# CONFIG_FATFS_LFN_STACK is not set
+CONFIG_FATFS_FS_LOCK=0
+CONFIG_FATFS_TIMEOUT_MS=10000
+CONFIG_FATFS_PER_FILE_CACHE=y
+# end of FAT Filesystem support
+
+#
+# Modbus configuration
+#
+CONFIG_FMB_COMM_MODE_RTU_EN=y
+CONFIG_FMB_COMM_MODE_ASCII_EN=y
+CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_FMB_QUEUE_LENGTH=20
+CONFIG_FMB_SERIAL_TASK_STACK_SIZE=2048
+CONFIG_FMB_SERIAL_BUF_SIZE=256
+CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8
+CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000
+CONFIG_FMB_SERIAL_TASK_PRIO=10
+# CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT is not set
+CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_FMB_CONTROLLER_STACK_SIZE=4096
+CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20
+CONFIG_FMB_TIMER_PORT_ENABLED=y
+CONFIG_FMB_TIMER_GROUP=0
+CONFIG_FMB_TIMER_INDEX=0
+# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set
+# end of Modbus configuration
+
+#
+# FreeRTOS
+#
+# CONFIG_FREERTOS_UNICORE is not set
+CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
+CONFIG_FREERTOS_CORETIMER_0=y
+# CONFIG_FREERTOS_CORETIMER_1 is not set
+CONFIG_FREERTOS_HZ=100
+CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
+# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
+CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
+CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
+CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
+# CONFIG_FREERTOS_ASSERT_DISABLE is not set
+CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
+CONFIG_FREERTOS_ISR_STACKSIZE=1536
+# CONFIG_FREERTOS_LEGACY_HOOKS is not set
+CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
+# CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION is not set
+CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=6048
+CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
+CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
+# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
+# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
+CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y
+CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
+# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
+CONFIG_FREERTOS_DEBUG_OCDAWARE=y
+# CONFIG_FREERTOS_FPU_IN_ISR is not set
+# end of FreeRTOS
+
+#
+# Heap memory debugging
+#
+CONFIG_HEAP_POISONING_DISABLED=y
+# CONFIG_HEAP_POISONING_LIGHT is not set
+# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set
+CONFIG_HEAP_TRACING_OFF=y
+# CONFIG_HEAP_TRACING_STANDALONE is not set
+# CONFIG_HEAP_TRACING_TOHOST is not set
+# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set
+# end of Heap memory debugging
+
+#
+# jsmn
+#
+# CONFIG_JSMN_PARENT_LINKS is not set
+# CONFIG_JSMN_STRICT is not set
+# end of jsmn
+
+#
+# libsodium
+#
+# end of libsodium
+
+#
+# Log output
+#
+# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
+# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
+# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
+CONFIG_LOG_DEFAULT_LEVEL_INFO=y
+# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
+# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_LOG_COLORS=y
+CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
+# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set
+# end of Log output
+
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
+CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
+# CONFIG_LWIP_L2_TO_L3_COPY is not set
+# CONFIG_LWIP_IRAM_OPTIMIZATION is not set
+CONFIG_LWIP_TIMERS_ONDEMAND=y
+CONFIG_LWIP_MAX_SOCKETS=10
+# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
+CONFIG_LWIP_SO_REUSE=y
+CONFIG_LWIP_SO_REUSE_RXTOALL=y
+# CONFIG_LWIP_SO_RCVBUF is not set
+# CONFIG_LWIP_NETBUF_RECVINFO is not set
+CONFIG_LWIP_IP_FRAG=y
+# CONFIG_LWIP_IP_REASSEMBLY is not set
+# CONFIG_LWIP_IP_FORWARD is not set
+# CONFIG_LWIP_STATS is not set
+# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
+CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
+CONFIG_LWIP_GARP_TMR_INTERVAL=60
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
+# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
+
+#
+# DHCP server
+#
+CONFIG_LWIP_DHCPS_LEASE_UNIT=60
+CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
+# end of DHCP server
+
+# CONFIG_LWIP_AUTOIP is not set
+# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
+CONFIG_LWIP_NETIF_LOOPBACK=y
+CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
+
+#
+# TCP
+#
+CONFIG_LWIP_MAX_ACTIVE_TCP=16
+CONFIG_LWIP_MAX_LISTENING_TCP=16
+CONFIG_LWIP_TCP_MAXRTX=12
+CONFIG_LWIP_TCP_SYNMAXRTX=6
+CONFIG_LWIP_TCP_MSS=1440
+CONFIG_LWIP_TCP_TMR_INTERVAL=250
+CONFIG_LWIP_TCP_MSL=60000
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744
+CONFIG_LWIP_TCP_WND_DEFAULT=5744
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
+CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
+# CONFIG_LWIP_TCP_SACK_OUT is not set
+# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_LWIP_TCP_OVERSIZE_MSS=y
+# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
+# end of TCP
+
+#
+# UDP
+#
+CONFIG_LWIP_MAX_UDP_PCBS=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=6
+# end of UDP
+
+CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
+# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set
+CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_LWIP_PPP_SUPPORT is not set
+
+#
+# ICMP
+#
+# CONFIG_LWIP_MULTICAST_PING is not set
+# CONFIG_LWIP_BROADCAST_PING is not set
+# end of ICMP
+
+#
+# LWIP RAW API
+#
+CONFIG_LWIP_MAX_RAW_PCBS=16
+# end of LWIP RAW API
+
+#
+# SNTP
+#
+CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
+CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
+# end of SNTP
+
+CONFIG_LWIP_ESP_LWIP_ASSERT=y
+# end of LWIP
+
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
+# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
+# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
+CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
+CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
+CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
+# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set
+# CONFIG_MBEDTLS_DEBUG is not set
+
+#
+# Certificate Bundle
+#
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
+# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
+# end of Certificate Bundle
+
+# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
+# CONFIG_MBEDTLS_CMAC_C is not set
+CONFIG_MBEDTLS_HARDWARE_AES=y
+CONFIG_MBEDTLS_HARDWARE_MPI=y
+CONFIG_MBEDTLS_HARDWARE_SHA=y
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set
+CONFIG_MBEDTLS_HAVE_TIME=y
+# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
+CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y
+CONFIG_MBEDTLS_SHA512_C=y
+CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
+# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
+# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
+# CONFIG_MBEDTLS_TLS_DISABLED is not set
+CONFIG_MBEDTLS_TLS_SERVER=y
+CONFIG_MBEDTLS_TLS_CLIENT=y
+CONFIG_MBEDTLS_TLS_ENABLED=y
+
+#
+# TLS Key Exchange Methods
+#
+# CONFIG_MBEDTLS_PSK_MODES is not set
+CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
+# end of TLS Key Exchange Methods
+
+CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
+# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set
+CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
+# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
+CONFIG_MBEDTLS_SSL_ALPN=y
+CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y
+CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y
+
+#
+# Symmetric Ciphers
+#
+CONFIG_MBEDTLS_AES_C=y
+# CONFIG_MBEDTLS_CAMELLIA_C is not set
+# CONFIG_MBEDTLS_DES_C is not set
+CONFIG_MBEDTLS_RC4_DISABLED=y
+# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set
+# CONFIG_MBEDTLS_RC4_ENABLED is not set
+# CONFIG_MBEDTLS_BLOWFISH_C is not set
+# CONFIG_MBEDTLS_XTEA_C is not set
+CONFIG_MBEDTLS_CCM_C=y
+CONFIG_MBEDTLS_GCM_C=y
+# end of Symmetric Ciphers
+
+# CONFIG_MBEDTLS_RIPEMD160_C is not set
+
+#
+# Certificates
+#
+CONFIG_MBEDTLS_PEM_PARSE_C=y
+CONFIG_MBEDTLS_PEM_WRITE_C=y
+CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
+CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
+# end of Certificates
+
+CONFIG_MBEDTLS_ECP_C=y
+CONFIG_MBEDTLS_ECDH_C=y
+CONFIG_MBEDTLS_ECDSA_C=y
+# CONFIG_MBEDTLS_ECJPAKE_C is not set
+CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
+CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
+# CONFIG_MBEDTLS_POLY1305_C is not set
+# CONFIG_MBEDTLS_CHACHA20_C is not set
+# CONFIG_MBEDTLS_HKDF_C is not set
+# CONFIG_MBEDTLS_THREADING_C is not set
+# CONFIG_MBEDTLS_SECURITY_RISKS is not set
+# end of mbedTLS
+
+#
+# mDNS
+#
+CONFIG_MDNS_MAX_SERVICES=10
+CONFIG_MDNS_TASK_PRIORITY=1
+CONFIG_MDNS_TASK_STACK_SIZE=4096
+# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_MDNS_TASK_AFFINITY_CPU0=y
+# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set
+CONFIG_MDNS_TASK_AFFINITY=0x0
+CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000
+CONFIG_MDNS_TIMER_PERIOD_MS=100
+# end of mDNS
+
+#
+# ESP-MQTT Configurations
+#
+CONFIG_MQTT_PROTOCOL_311=y
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set
+# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set
+# CONFIG_MQTT_CUSTOM_OUTBOX is not set
+# end of ESP-MQTT Configurations
+
+#
+# Newlib
+#
+CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set
+CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
+# CONFIG_NEWLIB_NANO_FORMAT is not set
+# end of Newlib
+
+#
+# NVS
+#
+# end of NVS
+
+#
+# OpenSSL
+#
+# CONFIG_OPENSSL_DEBUG is not set
+# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set
+CONFIG_OPENSSL_ASSERT_EXIT=y
+# end of OpenSSL
+
+#
+# PThreads
+#
+CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_PTHREAD_STACK_MIN=768
+CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y
+# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set
+# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set
+CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
+# end of PThreads
+
+#
+# SPI Flash driver
+#
+# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
+# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
+CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
+CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set
+# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set
+# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set
+# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set
+CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y
+CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20
+CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1
+
+#
+# Auto-detect flash chips
+#
+CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
+# end of Auto-detect flash chips
+# end of SPI Flash driver
+
+#
+# SPIFFS Configuration
+#
+CONFIG_SPIFFS_MAX_PARTITIONS=3
+
+#
+# SPIFFS Cache Configuration
+#
+CONFIG_SPIFFS_CACHE=y
+CONFIG_SPIFFS_CACHE_WR=y
+# CONFIG_SPIFFS_CACHE_STATS is not set
+# end of SPIFFS Cache Configuration
+
+CONFIG_SPIFFS_PAGE_CHECK=y
+CONFIG_SPIFFS_GC_MAX_RUNS=10
+# CONFIG_SPIFFS_GC_STATS is not set
+CONFIG_SPIFFS_PAGE_SIZE=256
+CONFIG_SPIFFS_OBJ_NAME_LEN=32
+# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set
+CONFIG_SPIFFS_USE_MAGIC=y
+CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
+CONFIG_SPIFFS_META_LENGTH=4
+CONFIG_SPIFFS_USE_MTIME=y
+
+#
+# Debug Configuration
+#
+# CONFIG_SPIFFS_DBG is not set
+# CONFIG_SPIFFS_API_DBG is not set
+# CONFIG_SPIFFS_GC_DBG is not set
+# CONFIG_SPIFFS_CACHE_DBG is not set
+# CONFIG_SPIFFS_CHECK_DBG is not set
+# CONFIG_SPIFFS_TEST_VISUALISATION is not set
+# end of Debug Configuration
+# end of SPIFFS Configuration
+
+#
+# TinyUSB
+#
+
+#
+# Descriptor configuration
+#
+CONFIG_USB_DESC_CUSTOM_VID=0x1234
+CONFIG_USB_DESC_CUSTOM_PID=0x5678
+# end of Descriptor configuration
+# end of TinyUSB
+
+#
+# Unity unit testing library
+#
+CONFIG_UNITY_ENABLE_FLOAT=y
+CONFIG_UNITY_ENABLE_DOUBLE=y
+# CONFIG_UNITY_ENABLE_COLOR is not set
+CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
+# CONFIG_UNITY_ENABLE_FIXTURE is not set
+# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set
+# end of Unity unit testing library
+
+#
+# Virtual file system
+#
+CONFIG_VFS_SUPPORT_IO=y
+CONFIG_VFS_SUPPORT_DIR=y
+CONFIG_VFS_SUPPORT_SELECT=y
+CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_VFS_SUPPORT_TERMIOS=y
+
+#
+# Host File System I/O (Semihosting)
+#
+CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
+# end of Host File System I/O (Semihosting)
+# end of Virtual file system
+
+#
+# Wear Levelling
+#
+# CONFIG_WL_SECTOR_SIZE_512 is not set
+CONFIG_WL_SECTOR_SIZE_4096=y
+CONFIG_WL_SECTOR_SIZE=4096
+# end of Wear Levelling
+
+#
+# Wi-Fi Provisioning Manager
+#
+CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
+CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
+# end of Wi-Fi Provisioning Manager
+
+#
+# Supplicant
+#
+CONFIG_WPA_MBEDTLS_CRYPTO=y
+# CONFIG_WPA_DEBUG_PRINT is not set
+# CONFIG_WPA_TESTING_OPTIONS is not set
+# CONFIG_WPA_TLS_V12 is not set
+# CONFIG_WPA_WPS_WARS is not set
+# end of Supplicant
+# end of Component config
+
+#
+# Compatibility options
+#
+# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
+# end of Compatibility options
+
+# Deprecated options for backward compatibility
+CONFIG_TOOLPREFIX="xtensa-esp32-elf-"
+# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
+CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
+# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
+CONFIG_LOG_BOOTLOADER_LEVEL=3
+# CONFIG_APP_ROLLBACK_ENABLE is not set
+# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
+# CONFIG_FLASHMODE_QIO is not set
+# CONFIG_FLASHMODE_QOUT is not set
+CONFIG_FLASHMODE_DIO=y
+# CONFIG_FLASHMODE_DOUT is not set
+# CONFIG_MONITOR_BAUD_9600B is not set
+# CONFIG_MONITOR_BAUD_57600B is not set
+CONFIG_MONITOR_BAUD_115200B=y
+# CONFIG_MONITOR_BAUD_230400B is not set
+# CONFIG_MONITOR_BAUD_921600B is not set
+# CONFIG_MONITOR_BAUD_2MB is not set
+# CONFIG_MONITOR_BAUD_OTHER is not set
+CONFIG_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_MONITOR_BAUD=115200
+CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
+# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
+CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
+# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
+# CONFIG_CXX_EXCEPTIONS is not set
+CONFIG_STACK_CHECK_NONE=y
+# CONFIG_STACK_CHECK_NORM is not set
+# CONFIG_STACK_CHECK_STRONG is not set
+# CONFIG_STACK_CHECK_ALL is not set
+# CONFIG_WARN_WRITE_STRINGS is not set
+# CONFIG_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
+CONFIG_ESP32_APPTRACE_DEST_NONE=y
+CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
+CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
+CONFIG_ADC2_DISABLE_DAC=y
+# CONFIG_SPIRAM_SUPPORT is not set
+CONFIG_TRACEMEM_RESERVE_DRAM=0x0
+# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set
+CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y
+CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4
+# CONFIG_ULP_COPROC_ENABLED is not set
+CONFIG_ULP_COPROC_RESERVE_MEM=0
+CONFIG_BROWNOUT_DET=y
+CONFIG_BROWNOUT_DET_LVL_SEL_0=y
+# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set
+CONFIG_BROWNOUT_DET_LVL=0
+CONFIG_REDUCE_PHY_TX_POWER=y
+CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y
+# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set
+# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set
+# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set
+# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set
+# CONFIG_NO_BLOBS is not set
+# CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
+CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
+CONFIG_MAIN_TASK_STACK_SIZE=3584
+CONFIG_IPC_TASK_STACK_SIZE=1024
+CONFIG_CONSOLE_UART_DEFAULT=y
+# CONFIG_CONSOLE_UART_CUSTOM is not set
+# CONFIG_CONSOLE_UART_NONE is not set
+CONFIG_CONSOLE_UART_NUM=0
+CONFIG_CONSOLE_UART_TX_GPIO=1
+CONFIG_CONSOLE_UART_RX_GPIO=3
+CONFIG_CONSOLE_UART_BAUDRATE=115200
+CONFIG_INT_WDT=y
+CONFIG_INT_WDT_TIMEOUT_MS=300
+CONFIG_INT_WDT_CHECK_CPU1=y
+CONFIG_TASK_WDT=y
+# CONFIG_TASK_WDT_PANIC is not set
+CONFIG_TASK_WDT_TIMEOUT_S=5
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
+# CONFIG_EVENT_LOOP_PROFILING is not set
+CONFIG_POST_EVENTS_FROM_ISR=y
+CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
+# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set
+CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP32S2_PANIC_GDBSTUB is not set
+CONFIG_TIMER_TASK_STACK_SIZE=6584
+CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_MB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_MB_QUEUE_LENGTH=20
+CONFIG_MB_SERIAL_TASK_STACK_SIZE=2048
+CONFIG_MB_SERIAL_BUF_SIZE=256
+CONFIG_MB_SERIAL_TASK_PRIO=10
+# CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT is not set
+CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_MB_CONTROLLER_STACK_SIZE=4096
+CONFIG_MB_EVENT_QUEUE_TIMEOUT=20
+CONFIG_MB_TIMER_PORT_ENABLED=y
+CONFIG_MB_TIMER_GROUP=0
+CONFIG_MB_TIMER_INDEX=0
+# CONFIG_SUPPORT_STATIC_ALLOCATION is not set
+CONFIG_TIMER_TASK_PRIORITY=1
+CONFIG_TIMER_TASK_STACK_DEPTH=6048
+CONFIG_TIMER_QUEUE_LENGTH=10
+# CONFIG_L2_TO_L3_COPY is not set
+# CONFIG_USE_ONLY_LWIP_SELECT is not set
+CONFIG_ESP_GRATUITOUS_ARP=y
+CONFIG_GARP_TMR_INTERVAL=60
+CONFIG_TCPIP_RECVMBOX_SIZE=32
+CONFIG_TCP_MAXRTX=12
+CONFIG_TCP_SYNMAXRTX=6
+CONFIG_TCP_MSS=1440
+CONFIG_TCP_MSL=60000
+CONFIG_TCP_SND_BUF_DEFAULT=5744
+CONFIG_TCP_WND_DEFAULT=5744
+CONFIG_TCP_RECVMBOX_SIZE=6
+CONFIG_TCP_QUEUE_OOSEQ=y
+# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_TCP_OVERSIZE_MSS=y
+# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_TCP_OVERSIZE_DISABLE is not set
+CONFIG_UDP_RECVMBOX_SIZE=6
+CONFIG_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set
+# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set
+CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_PPP_SUPPORT is not set
+CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_ESP32_PTHREAD_STACK_MIN=768
+CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y
+# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set
+# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set
+CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
+CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
+CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_SUPPORT_TERMIOS=y
+CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
+# End of deprecated options
diff --git a/minimal-examples/embedded/esp32/esp-wrover-kit/sdkconfig.h b/minimal-examples/embedded/esp32/esp-wrover-kit/sdkconfig.h
new file mode 100644 (file)
index 0000000..0ace05c
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * Automatically generated file. DO NOT EDIT.
+ * Espressif IoT Development Framework (ESP-IDF) Configuration Header
+ */
+#pragma once
+#define CONFIG_IDF_CMAKE 1
+#define CONFIG_IDF_TARGET "esp32"
+#define CONFIG_IDF_TARGET_ESP32 1
+#define CONFIG_IDF_FIRMWARE_CHIP_ID 0x0000
+#define CONFIG_SDK_TOOLPREFIX "xtensa-esp32-elf-"
+#define CONFIG_APP_BUILD_TYPE_APP_2NDBOOT 1
+#define CONFIG_APP_BUILD_GENERATE_BINARIES 1
+#define CONFIG_APP_BUILD_BOOTLOADER 1
+#define CONFIG_APP_BUILD_USE_FLASH_SECTIONS 1
+#define CONFIG_APP_COMPILE_TIME_DATE 1
+#define CONFIG_APP_RETRIEVE_LEN_ELF_SHA 16
+#define CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE 1
+#define CONFIG_BOOTLOADER_LOG_LEVEL_INFO 1
+#define CONFIG_BOOTLOADER_LOG_LEVEL 3
+#define CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V 1
+#define CONFIG_BOOTLOADER_WDT_ENABLE 1
+#define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
+#define CONFIG_BOOTLOADER_RESERVE_RTC_SIZE 0x0
+#define CONFIG_ESPTOOLPY_BAUD_OTHER_VAL 115200
+#define CONFIG_ESPTOOLPY_FLASHMODE_DIO 1
+#define CONFIG_ESPTOOLPY_FLASHMODE "dio"
+#define CONFIG_ESPTOOLPY_FLASHFREQ_40M 1
+#define CONFIG_ESPTOOLPY_FLASHFREQ "40m"
+#define CONFIG_ESPTOOLPY_FLASHSIZE_4MB 1
+#define CONFIG_ESPTOOLPY_FLASHSIZE "4MB"
+#define CONFIG_ESPTOOLPY_FLASHSIZE_DETECT 1
+#define CONFIG_ESPTOOLPY_BEFORE_RESET 1
+#define CONFIG_ESPTOOLPY_BEFORE "default_reset"
+#define CONFIG_ESPTOOLPY_AFTER_RESET 1
+#define CONFIG_ESPTOOLPY_AFTER "hard_reset"
+#define CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B 1
+#define CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL 115200
+#define CONFIG_ESPTOOLPY_MONITOR_BAUD 115200
+#define CONFIG_PARTITION_TABLE_SINGLE_APP 1
+#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv"
+#define CONFIG_PARTITION_TABLE_FILENAME "partitions_singleapp.csv"
+#define CONFIG_PARTITION_TABLE_OFFSET 0x8000
+#define CONFIG_PARTITION_TABLE_MD5 1
+#define CONFIG_COMPILER_OPTIMIZATION_DEFAULT 1
+#define CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE 1
+#define CONFIG_COMPILER_STACK_CHECK_MODE_NONE 1
+#define CONFIG_APPTRACE_DEST_NONE 1
+#define CONFIG_APPTRACE_LOCK_ENABLE 1
+#define CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF 0
+#define CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF 0
+#define CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF 0
+#define CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF 0
+#define CONFIG_BTDM_CTRL_PINNED_TO_CORE 0
+#define CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF 1
+#define CONFIG_BT_RESERVE_DRAM 0x0
+#define CONFIG_COAP_MBEDTLS_PSK 1
+#define CONFIG_COAP_LOG_DEFAULT_LEVEL 0
+#define CONFIG_ADC_DISABLE_DAC 1
+#define CONFIG_SPI_MASTER_ISR_IN_IRAM 1
+#define CONFIG_SPI_SLAVE_ISR_IN_IRAM 1
+#define CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4 1
+#define CONFIG_EFUSE_MAX_BLK_LEN 192
+#define CONFIG_ESP_TLS_USING_MBEDTLS 1
+#define CONFIG_ESP32_REV_MIN_0 1
+#define CONFIG_ESP32_REV_MIN 0
+#define CONFIG_ESP32_DPORT_WORKAROUND 1
+#define CONFIG_ESP32_DEFAULT_CPU_FREQ_160 1
+#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 160
+#define CONFIG_ESP32_TRACEMEM_RESERVE_DRAM 0x0
+#define CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR 1
+#define CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES 4
+#define CONFIG_ESP32_ULP_COPROC_RESERVE_MEM 0
+#define CONFIG_ESP32_DEBUG_OCDAWARE 1
+#define CONFIG_ESP32_BROWNOUT_DET 1
+#define CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0 1
+#define CONFIG_ESP32_BROWNOUT_DET_LVL 0
+#define CONFIG_ESP32_REDUCE_PHY_TX_POWER 1
+#define CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 1
+#define CONFIG_ESP32_RTC_CLK_SRC_INT_RC 1
+#define CONFIG_ESP32_RTC_CLK_CAL_CYCLES 1024
+#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000
+#define CONFIG_ESP32_XTAL_FREQ_40 1
+#define CONFIG_ESP32_XTAL_FREQ 40
+#define CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL 5
+#define CONFIG_ADC_CAL_EFUSE_TP_ENABLE 1
+#define CONFIG_ADC_CAL_EFUSE_VREF_ENABLE 1
+#define CONFIG_ADC_CAL_LUT_ENABLE 1
+#define CONFIG_ESP_ERR_TO_NAME_LOOKUP 1
+#define CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE 32
+#define CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE 2304
+#define CONFIG_ESP_MAIN_TASK_STACK_SIZE 6584
+#define CONFIG_ESP_IPC_TASK_STACK_SIZE 1024
+#define CONFIG_ESP_IPC_USES_CALLERS_PRIORITY 1
+#define CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE 2048
+#define CONFIG_ESP_CONSOLE_UART_DEFAULT 1
+#define CONFIG_ESP_CONSOLE_UART_NUM 0
+#define CONFIG_ESP_CONSOLE_UART_TX_GPIO 1
+#define CONFIG_ESP_CONSOLE_UART_RX_GPIO 3
+#define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200
+#define CONFIG_ESP_INT_WDT 1
+#define CONFIG_ESP_INT_WDT_TIMEOUT_MS 300
+#define CONFIG_ESP_INT_WDT_CHECK_CPU1 1
+#define CONFIG_ESP_TASK_WDT 1
+#define CONFIG_ESP_TASK_WDT_TIMEOUT_S 5
+#define CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 1
+#define CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_BT 1
+#define CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH 1
+#define CONFIG_ETH_ENABLED 1
+#define CONFIG_ETH_USE_ESP32_EMAC 1
+#define CONFIG_ETH_PHY_INTERFACE_RMII 1
+#define CONFIG_ETH_RMII_CLK_INPUT 1
+#define CONFIG_ETH_RMII_CLK_IN_GPIO 0
+#define CONFIG_ETH_DMA_BUFFER_SIZE 512
+#define CONFIG_ETH_DMA_RX_BUFFER_NUM 10
+#define CONFIG_ETH_DMA_TX_BUFFER_NUM 10
+#define CONFIG_ETH_USE_SPI_ETHERNET 1
+#define CONFIG_ESP_EVENT_POST_FROM_ISR 1
+#define CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR 1
+#define CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS 1
+#define CONFIG_HTTPD_MAX_REQ_HDR_LEN 512
+#define CONFIG_HTTPD_MAX_URI_LEN 512
+#define CONFIG_HTTPD_ERR_RESP_NO_DELAY 1
+#define CONFIG_HTTPD_PURGE_BUF_LEN 32
+#define CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL 120
+#define CONFIG_ESP_NETIF_TCPIP_LWIP 1
+#define CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER 1
+#define CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT 1
+#define CONFIG_ESP_TIMER_TASK_STACK_SIZE 6584
+#define CONFIG_ESP_TIMER_IMPL_TG0_LAC 1
+#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 10
+#define CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 32
+#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER 1
+#define CONFIG_ESP32_WIFI_TX_BUFFER_TYPE 1
+#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32
+#define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 1
+#define CONFIG_ESP32_WIFI_TX_BA_WIN 6
+#define CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED 1
+#define CONFIG_ESP32_WIFI_RX_BA_WIN 6
+#define CONFIG_ESP32_WIFI_NVS_ENABLED 1
+#define CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 1
+#define CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN 752
+#define CONFIG_ESP32_WIFI_MGMT_SBUF_NUM 32
+#define CONFIG_ESP32_WIFI_IRAM_OPT 1
+#define CONFIG_ESP32_WIFI_RX_IRAM_OPT 1
+#define CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE 1
+#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1
+#define CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER 20
+#define CONFIG_ESP32_PHY_MAX_TX_POWER 20
+#define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1
+#define CONFIG_FATFS_CODEPAGE_437 1
+#define CONFIG_FATFS_CODEPAGE 437
+#define CONFIG_FATFS_LFN_NONE 1
+#define CONFIG_FATFS_FS_LOCK 0
+#define CONFIG_FATFS_TIMEOUT_MS 10000
+#define CONFIG_FATFS_PER_FILE_CACHE 1
+#define CONFIG_FMB_COMM_MODE_RTU_EN 1
+#define CONFIG_FMB_COMM_MODE_ASCII_EN 1
+#define CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND 150
+#define CONFIG_FMB_MASTER_DELAY_MS_CONVERT 200
+#define CONFIG_FMB_QUEUE_LENGTH 20
+#define CONFIG_FMB_SERIAL_TASK_STACK_SIZE 2048
+#define CONFIG_FMB_SERIAL_BUF_SIZE 256
+#define CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB 8
+#define CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS 1000
+#define CONFIG_FMB_SERIAL_TASK_PRIO 10
+#define CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT 20
+#define CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE 20
+#define CONFIG_FMB_CONTROLLER_STACK_SIZE 4096
+#define CONFIG_FMB_EVENT_QUEUE_TIMEOUT 20
+#define CONFIG_FMB_TIMER_PORT_ENABLED 1
+#define CONFIG_FMB_TIMER_GROUP 0
+#define CONFIG_FMB_TIMER_INDEX 0
+#define CONFIG_FREERTOS_NO_AFFINITY 0x7FFFFFFF
+#define CONFIG_FREERTOS_CORETIMER_0 1
+#define CONFIG_FREERTOS_HZ 100
+#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1
+#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY 1
+#define CONFIG_FREERTOS_INTERRUPT_BACKTRACE 1
+#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 1
+#define CONFIG_FREERTOS_ASSERT_FAIL_ABORT 1
+#define CONFIG_FREERTOS_IDLE_TASK_STACKSIZE 1536
+#define CONFIG_FREERTOS_ISR_STACKSIZE 1536
+#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16
+#define CONFIG_FREERTOS_TIMER_TASK_PRIORITY 1
+#define CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH 6048
+#define CONFIG_FREERTOS_TIMER_QUEUE_LENGTH 10
+#define CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE 0
+#define CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER 1
+#define CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER 1
+#define CONFIG_FREERTOS_DEBUG_OCDAWARE 1
+#define CONFIG_HEAP_POISONING_DISABLED 1
+#define CONFIG_HEAP_TRACING_OFF 1
+#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1
+#define CONFIG_LOG_DEFAULT_LEVEL 3
+#define CONFIG_LOG_COLORS 1
+#define CONFIG_LOG_TIMESTAMP_SOURCE_RTOS 1
+#define CONFIG_LWIP_LOCAL_HOSTNAME "espressif"
+#define CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES 1
+#define CONFIG_LWIP_TIMERS_ONDEMAND 1
+#define CONFIG_LWIP_MAX_SOCKETS 10
+#define CONFIG_LWIP_SO_REUSE 1
+#define CONFIG_LWIP_SO_REUSE_RXTOALL 1
+#define CONFIG_LWIP_IP_FRAG 1
+#define CONFIG_LWIP_ESP_GRATUITOUS_ARP 1
+#define CONFIG_LWIP_GARP_TMR_INTERVAL 60
+#define CONFIG_LWIP_TCPIP_RECVMBOX_SIZE 32
+#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1
+#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60
+#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8
+#define CONFIG_LWIP_NETIF_LOOPBACK 1
+#define CONFIG_LWIP_LOOPBACK_MAX_PBUFS 8
+#define CONFIG_LWIP_MAX_ACTIVE_TCP 16
+#define CONFIG_LWIP_MAX_LISTENING_TCP 16
+#define CONFIG_LWIP_TCP_MAXRTX 12
+#define CONFIG_LWIP_TCP_SYNMAXRTX 6
+#define CONFIG_LWIP_TCP_MSS 1440
+#define CONFIG_LWIP_TCP_TMR_INTERVAL 250
+#define CONFIG_LWIP_TCP_MSL 60000
+#define CONFIG_LWIP_TCP_SND_BUF_DEFAULT 5744
+#define CONFIG_LWIP_TCP_WND_DEFAULT 5744
+#define CONFIG_LWIP_TCP_RECVMBOX_SIZE 6
+#define CONFIG_LWIP_TCP_QUEUE_OOSEQ 1
+#define CONFIG_LWIP_TCP_OVERSIZE_MSS 1
+#define CONFIG_LWIP_MAX_UDP_PCBS 16
+#define CONFIG_LWIP_UDP_RECVMBOX_SIZE 6
+#define CONFIG_LWIP_TCPIP_TASK_STACK_SIZE 3072
+#define CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY 1
+#define CONFIG_LWIP_TCPIP_TASK_AFFINITY 0x7FFFFFFF
+#define CONFIG_LWIP_MAX_RAW_PCBS 16
+#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1
+#define CONFIG_LWIP_SNTP_UPDATE_DELAY 3600000
+#define CONFIG_LWIP_ESP_LWIP_ASSERT 1
+#define CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC 1
+#define CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN 1
+#define CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN 16384
+#define CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN 4096
+#define CONFIG_MBEDTLS_CERTIFICATE_BUNDLE 1
+#define CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL 1
+#define CONFIG_MBEDTLS_HARDWARE_AES 1
+#define CONFIG_MBEDTLS_HARDWARE_MPI 1
+#define CONFIG_MBEDTLS_HARDWARE_SHA 1
+#define CONFIG_MBEDTLS_HAVE_TIME 1
+#define CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT 1
+#define CONFIG_MBEDTLS_TLS_SERVER 1
+#define CONFIG_MBEDTLS_TLS_CLIENT 1
+#define CONFIG_MBEDTLS_TLS_ENABLED 1
+#define CONFIG_MBEDTLS_PSK_MODES 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA 1
+#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA 1
+#define CONFIG_MBEDTLS_SSL_RENEGOTIATION 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_1 1
+#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 1
+#define CONFIG_MBEDTLS_SSL_PROTO_DTLS 1
+#define CONFIG_MBEDTLS_SSL_ALPN 1
+#define CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS 1
+#define CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS 1
+#define CONFIG_MBEDTLS_AES_C 1
+#define CONFIG_MBEDTLS_RC4_DISABLED 1
+#define CONFIG_MBEDTLS_CCM_C 1
+#define CONFIG_MBEDTLS_GCM_C 1
+#define CONFIG_MBEDTLS_PEM_PARSE_C 1
+#define CONFIG_MBEDTLS_PEM_WRITE_C 1
+#define CONFIG_MBEDTLS_X509_CRL_PARSE_C 1
+#define CONFIG_MBEDTLS_X509_CSR_PARSE_C 1
+#define CONFIG_MBEDTLS_ECP_C 1
+#define CONFIG_MBEDTLS_ECDH_C 1
+#define CONFIG_MBEDTLS_ECDSA_C 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1
+#define CONFIG_MBEDTLS_ECP_NIST_OPTIM 1
+#define CONFIG_MDNS_MAX_SERVICES 10
+#define CONFIG_MDNS_TASK_PRIORITY 1
+#define CONFIG_MDNS_TASK_AFFINITY_CPU0 1
+#define CONFIG_MDNS_TASK_AFFINITY 0x0
+#define CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS 2000
+#define CONFIG_MDNS_TIMER_PERIOD_MS 100
+#define CONFIG_MQTT_PROTOCOL_311 1
+#define CONFIG_MQTT_TRANSPORT_SSL 1
+#define CONFIG_MQTT_TRANSPORT_WEBSOCKET 1
+#define CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE 1
+#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF 1
+#define CONFIG_NEWLIB_STDIN_LINE_ENDING_CR 1
+#define CONFIG_OPENSSL_ASSERT_EXIT 1
+#define CONFIG_PTHREAD_TASK_PRIO_DEFAULT 5
+#define CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT 3072
+#define CONFIG_PTHREAD_STACK_MIN 768
+#define CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY 1
+#define CONFIG_PTHREAD_TASK_CORE_DEFAULT -1
+#define CONFIG_PTHREAD_TASK_NAME_DEFAULT "pthread"
+#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1
+#define CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS 1
+#define CONFIG_SPI_FLASH_YIELD_DURING_ERASE 1
+#define CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS 20
+#define CONFIG_SPI_FLASH_ERASE_YIELD_TICKS 1
+#define CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP 1
+#define CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP 1
+#define CONFIG_SPI_FLASH_SUPPORT_GD_CHIP 1
+#define CONFIG_SPIFFS_MAX_PARTITIONS 3
+#define CONFIG_SPIFFS_CACHE 1
+#define CONFIG_SPIFFS_CACHE_WR 1
+#define CONFIG_SPIFFS_PAGE_CHECK 1
+#define CONFIG_SPIFFS_GC_MAX_RUNS 10
+#define CONFIG_SPIFFS_PAGE_SIZE 256
+#define CONFIG_SPIFFS_OBJ_NAME_LEN 32
+#define CONFIG_SPIFFS_USE_MAGIC 1
+#define CONFIG_SPIFFS_USE_MAGIC_LENGTH 1
+#define CONFIG_SPIFFS_META_LENGTH 4
+#define CONFIG_SPIFFS_USE_MTIME 1
+#define CONFIG_USB_DESC_CUSTOM_VID 0x1234
+#define CONFIG_USB_DESC_CUSTOM_PID 0x5678
+#define CONFIG_UNITY_ENABLE_FLOAT 1
+#define CONFIG_UNITY_ENABLE_DOUBLE 1
+#define CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER 1
+#define CONFIG_VFS_SUPPORT_IO 1
+#define CONFIG_VFS_SUPPORT_DIR 1
+#define CONFIG_VFS_SUPPORT_SELECT 1
+#define CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT 1
+#define CONFIG_VFS_SUPPORT_TERMIOS 1
+#define CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS 1
+#define CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN 128
+#define CONFIG_WL_SECTOR_SIZE_4096 1
+#define CONFIG_WL_SECTOR_SIZE 4096
+#define CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES 16
+#define CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT 30
+#define CONFIG_WPA_MBEDTLS_CRYPTO 1
+
+/* List of deprecated options */
+#define CONFIG_ADC2_DISABLE_DAC CONFIG_ADC_DISABLE_DAC
+#define CONFIG_BROWNOUT_DET CONFIG_ESP32_BROWNOUT_DET
+#define CONFIG_BROWNOUT_DET_LVL_SEL_0 CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0
+#define CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG CONFIG_COMPILER_OPTIMIZATION_DEFAULT
+#define CONFIG_CONSOLE_UART_BAUDRATE CONFIG_ESP_CONSOLE_UART_BAUDRATE
+#define CONFIG_CONSOLE_UART_DEFAULT CONFIG_ESP_CONSOLE_UART_DEFAULT
+#define CONFIG_CONSOLE_UART_RX_GPIO CONFIG_ESP_CONSOLE_UART_RX_GPIO
+#define CONFIG_CONSOLE_UART_TX_GPIO CONFIG_ESP_CONSOLE_UART_TX_GPIO
+#define CONFIG_ESP32S2_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT
+#define CONFIG_ESP32_APPTRACE_DEST_NONE CONFIG_APPTRACE_DEST_NONE
+#define CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY
+#define CONFIG_ESP32_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT
+#define CONFIG_ESP32_PTHREAD_STACK_MIN CONFIG_PTHREAD_STACK_MIN
+#define CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT CONFIG_PTHREAD_TASK_NAME_DEFAULT
+#define CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT CONFIG_PTHREAD_TASK_PRIO_DEFAULT
+#define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT
+#define CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC CONFIG_ESP32_RTC_CLK_SRC_INT_RC
+#define CONFIG_ESP_GRATUITOUS_ARP CONFIG_LWIP_ESP_GRATUITOUS_ARP
+#define CONFIG_FLASHMODE_DIO CONFIG_ESPTOOLPY_FLASHMODE_DIO
+#define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR
+#define CONFIG_GARP_TMR_INTERVAL CONFIG_LWIP_GARP_TMR_INTERVAL
+#define CONFIG_INT_WDT CONFIG_ESP_INT_WDT
+#define CONFIG_INT_WDT_CHECK_CPU1 CONFIG_ESP_INT_WDT_CHECK_CPU1
+#define CONFIG_INT_WDT_TIMEOUT_MS CONFIG_ESP_INT_WDT_TIMEOUT_MS
+#define CONFIG_IPC_TASK_STACK_SIZE CONFIG_ESP_IPC_TASK_STACK_SIZE
+#define CONFIG_LOG_BOOTLOADER_LEVEL_INFO CONFIG_BOOTLOADER_LOG_LEVEL_INFO
+#define CONFIG_MAIN_TASK_STACK_SIZE CONFIG_ESP_MAIN_TASK_STACK_SIZE
+#define CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE
+#define CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT
+#define CONFIG_MB_CONTROLLER_STACK_SIZE CONFIG_FMB_CONTROLLER_STACK_SIZE
+#define CONFIG_MB_EVENT_QUEUE_TIMEOUT CONFIG_FMB_EVENT_QUEUE_TIMEOUT
+#define CONFIG_MB_MASTER_DELAY_MS_CONVERT CONFIG_FMB_MASTER_DELAY_MS_CONVERT
+#define CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND
+#define CONFIG_MB_QUEUE_LENGTH CONFIG_FMB_QUEUE_LENGTH
+#define CONFIG_MB_SERIAL_BUF_SIZE CONFIG_FMB_SERIAL_BUF_SIZE
+#define CONFIG_MB_SERIAL_TASK_PRIO CONFIG_FMB_SERIAL_TASK_PRIO
+#define CONFIG_MB_SERIAL_TASK_STACK_SIZE CONFIG_FMB_SERIAL_TASK_STACK_SIZE
+#define CONFIG_MB_TIMER_GROUP CONFIG_FMB_TIMER_GROUP
+#define CONFIG_MB_TIMER_INDEX CONFIG_FMB_TIMER_INDEX
+#define CONFIG_MB_TIMER_PORT_ENABLED CONFIG_FMB_TIMER_PORT_ENABLED
+#define CONFIG_MONITOR_BAUD_115200B CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B
+#define CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE
+#define CONFIG_OPTIMIZATION_LEVEL_DEBUG CONFIG_COMPILER_OPTIMIZATION_DEFAULT
+#define CONFIG_POST_EVENTS_FROM_IRAM_ISR CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR
+#define CONFIG_POST_EVENTS_FROM_ISR CONFIG_ESP_EVENT_POST_FROM_ISR
+#define CONFIG_REDUCE_PHY_TX_POWER CONFIG_ESP32_REDUCE_PHY_TX_POWER
+#define CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN
+#define CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS
+#define CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS
+#define CONFIG_STACK_CHECK_NONE CONFIG_COMPILER_STACK_CHECK_MODE_NONE
+#define CONFIG_SUPPORT_TERMIOS CONFIG_VFS_SUPPORT_TERMIOS
+#define CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT
+#define CONFIG_SYSTEM_EVENT_QUEUE_SIZE CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE
+#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE
+#define CONFIG_TASK_WDT CONFIG_ESP_TASK_WDT
+#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
+#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
+#define CONFIG_TASK_WDT_TIMEOUT_S CONFIG_ESP_TASK_WDT_TIMEOUT_S
+#define CONFIG_TCPIP_RECVMBOX_SIZE CONFIG_LWIP_TCPIP_RECVMBOX_SIZE
+#define CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY
+#define CONFIG_TCPIP_TASK_STACK_SIZE CONFIG_LWIP_TCPIP_TASK_STACK_SIZE
+#define CONFIG_TCP_MAXRTX CONFIG_LWIP_TCP_MAXRTX
+#define CONFIG_TCP_MSL CONFIG_LWIP_TCP_MSL
+#define CONFIG_TCP_MSS CONFIG_LWIP_TCP_MSS
+#define CONFIG_TCP_OVERSIZE_MSS CONFIG_LWIP_TCP_OVERSIZE_MSS
+#define CONFIG_TCP_QUEUE_OOSEQ CONFIG_LWIP_TCP_QUEUE_OOSEQ
+#define CONFIG_TCP_RECVMBOX_SIZE CONFIG_LWIP_TCP_RECVMBOX_SIZE
+#define CONFIG_TCP_SND_BUF_DEFAULT CONFIG_LWIP_TCP_SND_BUF_DEFAULT
+#define CONFIG_TCP_SYNMAXRTX CONFIG_LWIP_TCP_SYNMAXRTX
+#define CONFIG_TCP_WND_DEFAULT CONFIG_LWIP_TCP_WND_DEFAULT
+#define CONFIG_TIMER_QUEUE_LENGTH CONFIG_FREERTOS_TIMER_QUEUE_LENGTH
+#define CONFIG_TIMER_TASK_PRIORITY CONFIG_FREERTOS_TIMER_TASK_PRIORITY
+#define CONFIG_TIMER_TASK_STACK_DEPTH CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH
+#define CONFIG_TIMER_TASK_STACK_SIZE CONFIG_ESP_TIMER_TASK_STACK_SIZE
+#define CONFIG_TOOLPREFIX CONFIG_SDK_TOOLPREFIX
+#define CONFIG_UDP_RECVMBOX_SIZE CONFIG_LWIP_UDP_RECVMBOX_SIZE
diff --git a/minimal-examples/gtk/minimal-gtk/CMakeLists.txt b/minimal-examples/gtk/minimal-gtk/CMakeLists.txt
new file mode 100644 (file)
index 0000000..27587f4
--- /dev/null
@@ -0,0 +1,47 @@
+project(lws-minimal-gtk C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-gtk)
+set(SRCS main.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_GLIB 1 requirements)
+require_lws_config(LWS_WITH_GTK 1 requirements)
+
+if (requirements)
+
+# gtk pieces
+       
+       include (FindPkgConfig)
+       
+       set(LWS_GTK_INCLUDE_DIRS CACHE PATH "Path to the gtk include directory")
+       set(LWS_GTK_LIBRARIES CACHE PATH "Path to the gtk library")
+       PKG_SEARCH_MODULE(LWS_GTK2 gtk+-3.0)
+       if (LWS_GTK2_FOUND)
+               list(APPEND LWS_GTK_INCLUDE_DIRS "${LWS_GTK2_INCLUDE_DIRS}")
+               list(APPEND LWS_GTK_LIBRARIES "${LWS_GTK2_LIBRARIES}")
+       endif()
+       message("gtk include dir: ${LWS_GTK_INCLUDE_DIRS}")
+       message("gtk libraries: ${LWS_GTK_LIBRARIES}")
+       include_directories("${LWS_GTK_INCLUDE_DIRS}")
+       set(extralibs ${extralibs} ${LWS_GTK_LIBRARIES})
+       
+       
+       
+       message("Extra libs: ${extralibs}")
+
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${extralibs} ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${extralibs} ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/gtk/minimal-gtk/README.md b/minimal-examples/gtk/minimal-gtk/README.md
new file mode 100644 (file)
index 0000000..f85e594
--- /dev/null
@@ -0,0 +1,32 @@
+# lws minimal http client gtk
+
+The application goes to https://warmcat.com and receives the page data,
+from inside a gtk app using gtk / glib main loop directly.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+
+```
+$
+t1_main: started
+[2020/02/08 18:04:07:6647] N: Loading client CA for verification ./warmcat.com.cer
+[2020/02/08 18:04:07:7744] U: Connected to 46.105.127.147, http response: 200
+[2020/02/08 18:04:07:7762] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2020/02/08 18:04:07:7762] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2020/02/08 18:04:07:7928] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2020/02/08 18:04:07:7929] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2020/02/08 18:04:07:7956] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2020/02/08 18:04:07:7956] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2020/02/08 18:04:07:7956] U: RECEIVE_CLIENT_HTTP_READ: read 1971
+[2020/02/08 18:04:07:7956] U: LWS_CALLBACK_COMPLETED_CLIENT_HTTP
+Hello World
+$
+```
+
+
diff --git a/minimal-examples/gtk/minimal-gtk/main.c b/minimal-examples/gtk/minimal-gtk/main.c
new file mode 100644 (file)
index 0000000..56f234c
--- /dev/null
@@ -0,0 +1,211 @@
+#include <gtk/gtk.h>
+#include <libwebsockets.h>
+
+static int status = 0;
+
+static void
+print_hello(GtkWidget *widget, gpointer data)
+{
+       g_print("Hello World\n");
+}
+
+static void
+activate(GtkApplication *app, gpointer user_data)
+{
+       GtkWidget *window;
+       GtkWidget *button, *bbox;
+
+       window = gtk_application_window_new(app);
+       gtk_window_set_title(GTK_WINDOW(window), "mywindow");
+       gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
+
+       bbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
+       gtk_container_add(GTK_CONTAINER(window), bbox);
+
+       button = gtk_button_new_with_label("Hello World");
+       g_signal_connect(button, "clicked", G_CALLBACK(print_hello), NULL);
+       g_signal_connect_swapped(button, "clicked",
+                                G_CALLBACK(gtk_widget_destroy), window);
+       gtk_container_add(GTK_CONTAINER(bbox), button);
+
+       gtk_widget_show_all(window);
+}
+
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                  int current, int target)
+{
+       struct lws_context *context = mgr->parent;
+       struct lws_client_connect_info i;
+
+       if (current != LWS_SYSTATE_OPERATIONAL ||
+           target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       lwsl_notice("%s: operational\n", __func__);
+
+       memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
+       i.context = context;
+       i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
+                          LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
+       i.port = 443;
+       i.address = "warmcat.com";
+       i.path = "/";
+       i.host = i.address;
+       i.origin = i.address;
+       i.method = "GET";
+
+       i.protocol = "http";
+
+       return !lws_client_connect_via_info(&i);
+}
+
+static int
+callback_http(struct lws *wsi, enum lws_callback_reasons reason,
+             void *user, void *in, size_t len)
+{
+       switch (reason) {
+
+       /* because we are protocols[0] ... */
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+               break;
+
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+               {
+                       char buf[128];
+
+                       lws_get_peer_simple(wsi, buf, sizeof(buf));
+                       status = lws_http_client_http_response(wsi);
+
+                       lwsl_user("Connected to %s, http response: %d\n",
+                                       buf, status);
+               }
+               break;
+
+       /* chunks of chunked content, with header removed */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+               lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
+               return 0; /* don't passthru */
+
+       /* uninterpreted http content */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+               {
+                       char buffer[1024 + LWS_PRE];
+                       char *px = buffer + LWS_PRE;
+                       int lenx = sizeof(buffer) - LWS_PRE;
+
+                       if (lws_http_client_read(wsi, &px, &lenx) < 0)
+                               return -1;
+               }
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
+               lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static const struct lws_protocols protocols[] = {
+       {
+               "http",
+               callback_http,
+               0,
+               0,
+       },
+       { NULL, NULL, 0, 0 }
+};
+
+static gpointer
+t1_main (gpointer user_data)
+{
+       lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
+                                               system_notify_cb, "app" };
+       lws_state_notify_link_t *na[] = { &notifier, NULL };
+       GMainContext *t1_mc = (GMainContext *)user_data;
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       void *foreign_loops[1];
+       GMainLoop *ml;
+
+       g_print("%s: started\n", __func__);
+
+       g_main_context_push_thread_default(t1_mc);
+
+       ml = g_main_loop_new(t1_mc, FALSE);
+
+       /* attach our lws activities to the main loop of this thread */
+
+       lws_set_log_level(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE, NULL);
+       memset(&info, 0, sizeof info);
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+                      LWS_SERVER_OPTION_GLIB;
+       info.protocols = protocols;
+       foreign_loops[0] = (void *)ml;
+       info.foreign_loops = foreign_loops;
+       info.register_notifier_list = na;
+
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+       /*
+        * OpenSSL uses the system trust store.  mbedTLS has to be told which
+        * CA to trust explicitly.
+        */
+       info.client_ssl_ca_filepath = "./warmcat.com.cer";
+#endif
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return NULL;
+       }
+
+       /*
+        * We created the lws_context and bound it to this thread's main loop,
+        * let's run the thread's main loop now...
+        */
+
+       g_main_loop_run(ml);
+       g_main_loop_unref(ml);
+
+       g_main_context_pop_thread_default(t1_mc);
+       g_main_context_unref(t1_mc);
+
+       g_print("%s: ending\n", __func__);
+
+       lws_context_destroy(context);
+
+       return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+       GMainContext *t1_mc = g_main_context_new();
+       GtkApplication *app;
+       GThread *t1;
+       int status;
+
+       t1 = g_thread_new ("t1", t1_main, g_main_context_ref (t1_mc));
+       (void)t1;
+
+       app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
+       g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
+
+       status = g_application_run(G_APPLICATION(app), argc, argv);
+       g_object_unref(app);
+
+       return status;
+}
+
diff --git a/minimal-examples/gtk/minimal-gtk/warmcat.com.cer b/minimal-examples/gtk/minimal-gtk/warmcat.com.cer
new file mode 100644 (file)
index 0000000..01ad0dc
--- /dev/null
@@ -0,0 +1,32 @@
+-----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-----
+
diff --git a/minimal-examples/http-client/minimal-http-client-attach/CMakeLists.txt b/minimal-examples/http-client/minimal-http-client-attach/CMakeLists.txt
new file mode 100644 (file)
index 0000000..909efca
--- /dev/null
@@ -0,0 +1,26 @@
+project(lws-minimal-http-client-attach C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-http-client-attach)
+set(SRCS minimal-http-client-attach.c)
+
+set(requirements 1)
+require_pthreads(requirements)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+
+if (requirements AND NOT WIN32)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/http-client/minimal-http-client-attach/README.md b/minimal-examples/http-client/minimal-http-client-attach/README.md
new file mode 100644 (file)
index 0000000..81d6310
--- /dev/null
@@ -0,0 +1,35 @@
+# lws minimal http client attach
+
+This demonstrates how other threads can reach out to an existing lws_context
+and join its event loop cleanly and safely.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+Pthreads is required on your system.
+
+## usage
+
+```
+ $ ./lws-minimal-http-client-attach
+[2019/12/31 18:30:49:3495] U: main: main thread tid 0x503e1c0
+[2019/12/31 18:30:50:3584] U: LWS minimal http client attach
+[2019/12/31 18:30:50:4002] U: lws_create: tid 0x5c41700
+[2019/12/31 18:30:50:5727] E: callback_ntpc: set up system ops for set_clock
+[2019/12/31 18:30:50:2110] N: callback_ntpc: Unix time: 1577817053
+[2019/12/31 18:30:50:2136] U: attach_callback: called from tid 0x5c41700
+[2019/12/31 18:30:51:8733] U: Connected to 46.105.127.147, http response: 200
+[2019/12/31 18:30:51:8818] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2019/12/31 18:30:51:8823] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2019/12/31 18:30:51:8846] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2019/12/31 18:30:51:8847] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2019/12/31 18:30:51:8855] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2019/12/31 18:30:51:8856] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2019/12/31 18:30:51:8860] U: RECEIVE_CLIENT_HTTP_READ: read 1971
+[2019/12/31 18:30:51:8873] U: LWS_CALLBACK_COMPLETED_CLIENT_HTTP
+[2019/12/31 18:30:51:9629] U: main: finished
+```
+
diff --git a/minimal-examples/http-client/minimal-http-client-attach/minimal-http-client-attach.c b/minimal-examples/http-client/minimal-http-client-attach/minimal-http-client-attach.c
new file mode 100644 (file)
index 0000000..460f946
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * lws-minimal-http-client-attach
+ *
+ * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates how to use the lws_system (*attach) api to allow a
+ * different thread to arrange to join an existing lws event loop safely.  The
+ * attached stuff does an http client GET from the lws event loop, even though
+ * it was originally requested from a different thread than the lws event loop.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
+#include <pthread.h>
+
+static struct lws_context *context;
+static pthread_t lws_thread;
+static pthread_mutex_t lock;
+static int interrupted, bad = 1, status;
+
+static int
+callback_http(struct lws *wsi, enum lws_callback_reasons reason,
+             void *user, void *in, size_t len)
+{
+       switch (reason) {
+
+       /* because we are protocols[0] ... */
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+               interrupted = 1;
+               break;
+
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+               {
+                       char buf[128];
+
+                       lws_get_peer_simple(wsi, buf, sizeof(buf));
+                       status = (int)lws_http_client_http_response(wsi);
+
+                       lwsl_user("Connected to %s, http response: %d\n",
+                                       buf, status);
+               }
+               break;
+
+       /* chunks of chunked content, with header removed */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+               lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
+
+#if 0  /* enable to dump the html */
+               {
+                       const char *p = in;
+
+                       while (len--)
+                               if (*p < 0x7f)
+                                       putchar(*p++);
+                               else
+                                       putchar('.');
+               }
+#endif
+               return 0; /* don't passthru */
+
+       /* uninterpreted http content */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+               {
+                       char buffer[1024 + LWS_PRE];
+                       char *px = buffer + LWS_PRE;
+                       int lenx = sizeof(buffer) - LWS_PRE;
+
+                       if (lws_http_client_read(wsi, &px, &lenx) < 0)
+                               return -1;
+               }
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
+               lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
+               interrupted = 1;
+               bad = status != 200;
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               interrupted = 1;
+               bad = status != 200;
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static const struct lws_protocols protocols[] = {
+       {
+               "http",
+               callback_http,
+               0, 0, 0, NULL, 0
+       },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static void
+attach_callback(struct lws_context *context, int tsi, void *opaque)
+{
+       struct lws_client_connect_info i;
+
+       /*
+        * Even though it was asked for from a different thread, we are called
+        * back by lws from the lws event loop thread context
+        *
+        * We can set up our operations on the lws event loop and return so
+        * they can happen asynchronously
+        */
+
+       memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
+       i.context = context;
+       i.ssl_connection = LCCSCF_USE_SSL;
+       i.ssl_connection |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
+                           LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
+       i.port = 443;
+       i.address = "warmcat.com";
+       i.path = "/";
+       i.host = i.address;
+       i.origin = i.address;
+       i.method = "GET";
+
+       i.protocol = protocols[0].name;
+
+       lws_client_connect_via_info(&i);
+}
+
+
+static int
+lws_attach_with_pthreads_locking(struct lws_context *context, int tsi,
+                                lws_attach_cb_t cb, lws_system_states_t state,
+                                void *opaque, struct lws_attach_item **get)
+{
+       int n;
+
+       pthread_mutex_lock(&lock);
+       /*
+        * We just provide system-specific locking around the lws non-threadsafe
+        * helper that adds and removes things from the pt list
+        */
+       n = __lws_system_attach(context, tsi, cb, state, opaque, get);
+       pthread_mutex_unlock(&lock);
+
+       return n;
+}
+
+
+lws_system_ops_t ops = {
+       .attach = lws_attach_with_pthreads_locking
+};
+
+/*
+ * We made this into a different thread to model it being run from completely
+ * different codebase that's all linked together
+ */
+
+static void *
+lws_create(void *d)
+{
+       struct lws_context_creation_info info;
+
+       lwsl_user("%s: tid %p\n", __func__, (void *)(intptr_t)pthread_self());
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.system_ops = &ops;
+       info.protocols = protocols;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               goto bail;
+       }
+
+       /* start the event loop */
+
+       while (!interrupted)
+               if (lws_service(context, 0))
+                       interrupted = 1;
+
+       lws_context_destroy(context);
+
+bail:
+       pthread_exit(NULL);
+
+       return NULL;
+}
+
+int main(int argc, const char **argv)
+{
+       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       const char *p;
+       void *retval;
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS minimal http client attach\n");
+
+       pthread_mutex_init(&lock, NULL);
+
+       /*
+        * The idea of the example is we're going to split the lws context and
+        * event loop off to be created from its own thread... this is like it
+        * was actually started by some completely different code...
+        */
+
+       if (pthread_create(&lws_thread, NULL, lws_create, NULL)) {
+               lwsl_err("thread creation failed\n");
+               goto bail1;
+       }
+
+       /*
+        * Now on the original / different thread representing a different
+        * codebase that wants to join this existing event loop, we'll ask to
+        * get a callback from the event loop context when the event loop
+        * thread is operational.  We have to wait around a bit because we
+        * may run before the lws context was created.
+        */
+
+       while (!context && n++ < 30)
+               usleep(10000);
+
+       if (!context) {
+               lwsl_err("%s: context didn't start\n", __func__);
+               goto bail;
+       }
+
+       /*
+        * From our different, non event loop thread, ask for our attach
+        * callback to get called when lws system state is OPERATIONAL
+        */
+
+       lws_system_get_ops(context)->attach(context, 0, attach_callback,
+                                           LWS_SYSTATE_OPERATIONAL,
+                                           NULL, NULL);
+
+       /*
+        * That's all we wanted to do with our thread.  Just wait for the lws
+        * thread to exit as well.
+        */
+
+bail:
+       pthread_join(lws_thread, &retval);
+bail1:
+       pthread_mutex_destroy(&lock);
+
+       lwsl_user("%s: finished\n", __func__);
+
+       return 0;
+}
diff --git a/minimal-examples/http-client/minimal-http-client-captive-portal/CMakeLists.txt b/minimal-examples/http-client/minimal-http-client-captive-portal/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f332dc5
--- /dev/null
@@ -0,0 +1,28 @@
+project(lws-minimal-http-client-captive-portal C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-http-client-captive-portal)
+set(SRCS minimal-http-client-captive-portal.c)
+
+set(requirements 1)
+require_pthreads(requirements)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (NOT WIN32 AND requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/http-client/minimal-http-client-captive-portal/README.md b/minimal-examples/http-client/minimal-http-client-captive-portal/README.md
new file mode 100644 (file)
index 0000000..8db2002
--- /dev/null
@@ -0,0 +1,45 @@
+# lws minimal http client captive portal detect
+
+This demonstrates how to perform captive portal detection integrated
+with `lws_system` states.
+
+After reaching the `lws_system` DHCP state, the application tries to
+connect through to `http://connectivitycheck.android.com/generate_204`
+over http... if it succeeds, it will get a 204 response and set the
+captive portal detection state to `LWS_CPD_INTERNET_OK` and perform
+a GET from warmcat.com.
+
+If there is a problem detected, the captive portal detection state is
+set accordingly and the app will respond by exiting without trying the
+read from warmcat.com.
+
+The captive portal detection scheme is implemented in the user code
+and can be modified according to the strategy that's desired for
+captive portal detection.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+```
+$ ./bin/lws-minimal-http-client-captive-portal
+[2020/03/11 13:07:07:4519] U: LWS minimal http client captive portal detect
+[2020/03/11 13:07:07:4519] N: lws_create_context: using ss proxy bind '(null)', port 0, ads '(null)'
+[2020/03/11 13:07:07:5022] U: callback_cpd_http: established with resp 204
+[2020/03/11 13:07:07:5023] U: app_system_state_nf: OPERATIONAL, cpd 1
+[2020/03/11 13:07:07:5896] U: Connected to 46.105.127.147, http response: 200
+[2020/03/11 13:07:07:5931] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2020/03/11 13:07:07:5931] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2020/03/11 13:07:07:6092] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2020/03/11 13:07:07:6092] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2020/03/11 13:07:07:6112] U: RECEIVE_CLIENT_HTTP_READ: read 4087
+[2020/03/11 13:07:07:6113] U: RECEIVE_CLIENT_HTTP_READ: read 4096
+[2020/03/11 13:07:07:6113] U: RECEIVE_CLIENT_HTTP_READ: read 2657
+[2020/03/11 13:07:07:6113] U: LWS_CALLBACK_COMPLETED_CLIENT_HTTP
+[2020/03/11 13:07:07:6119] U: main: finished OK
+```
+
diff --git a/minimal-examples/http-client/minimal-http-client-captive-portal/minimal-http-client-captive-portal.c b/minimal-examples/http-client/minimal-http-client-captive-portal/minimal-http-client-captive-portal.c
new file mode 100644 (file)
index 0000000..d9a00bc
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * lws-minimal-http-client-captive-portal
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates how to use the lws_system captive portal detect integration
+ *
+ * We check for a captive portal by doing a GET from
+ * http://connectivitycheck.android.com/generate_204, if we really are going
+ * out on the Internet he'll return with a 204 response code and we will
+ * understand there's no captive portal.  If we get something else, we take it
+ * there is a captive portal.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static struct lws_context *context;
+static int interrupted, bad = 1, status;
+static lws_state_notify_link_t nl;
+
+/*
+ * this is the user code http handler
+ */
+
+static int
+callback_http(struct lws *wsi, enum lws_callback_reasons reason,
+             void *user, void *in, size_t len)
+{
+       switch (reason) {
+
+       /* because we are protocols[0] ... */
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+               interrupted = 1;
+               break;
+
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+               {
+                       char buf[128];
+
+                       lws_get_peer_simple(wsi, buf, sizeof(buf));
+                       status = (int)lws_http_client_http_response(wsi);
+
+                       lwsl_user("Connected to %s, http response: %d\n",
+                                       buf, status);
+               }
+               break;
+
+       /* chunks of chunked content, with header removed */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+               lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
+
+#if 0  /* enable to dump the html */
+               {
+                       const char *p = in;
+
+                       while (len--)
+                               if (*p < 0x7f)
+                                       putchar(*p++);
+                               else
+                                       putchar('.');
+               }
+#endif
+               return 0; /* don't passthru */
+
+       /* uninterpreted http content */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+               {
+                       char buffer[1024 + LWS_PRE];
+                       char *px = buffer + LWS_PRE;
+                       int lenx = sizeof(buffer) - LWS_PRE;
+
+                       if (lws_http_client_read(wsi, &px, &lenx) < 0)
+                               return -1;
+               }
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
+               lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
+               interrupted = 1;
+               bad = status != 200;
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               interrupted = 1;
+               bad = status != 200;
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+/*
+ * This is the platform's custom captive portal detection handler
+ */
+
+static int
+callback_cpd_http(struct lws *wsi, enum lws_callback_reasons reason,
+                 void *user, void *in, size_t len)
+{
+       int resp;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+               resp = (int)lws_http_client_http_response(wsi);
+               if (!resp)
+                       break;
+               lwsl_user("%s: established with resp %d\n", __func__, resp);
+               switch (resp) {
+
+               case HTTP_STATUS_NO_CONTENT:
+                       /*
+                        * We got the 204 which is used to distinguish the real
+                        * endpoint
+                        */
+                       lws_system_cpd_set(lws_get_context(wsi),
+                                          LWS_CPD_INTERNET_OK);
+                       return 0;
+
+               /* also case HTTP_STATUS_OK: ... */
+               default:
+                       break;
+               }
+
+               /* fallthru */
+
+       case LWS_CALLBACK_CLIENT_HTTP_REDIRECT:
+               lws_system_cpd_set(lws_get_context(wsi), LWS_CPD_CAPTIVE_PORTAL);
+               /* don't follow it, just report it */
+               return 1;
+
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               /* only the first result counts */
+               lws_system_cpd_set(lws_get_context(wsi), LWS_CPD_NO_INTERNET);
+               break;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static const struct lws_protocols protocols[] = {
+       {
+               "http",
+               callback_http,
+               0, 0, 0, NULL, 0
+       }, {
+               "lws-cpd-http",
+               callback_cpd_http,
+               0, 0, 0, NULL, 0
+       },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+/*
+ * This triggers our platform implementation of captive portal detection, the
+ * actual test can be whatever you need.
+ *
+ * In this example, we detect it using Android's
+ *
+ *   http://connectivitycheck.android.com/generate_204
+ *
+ * and seeing if we get an http 204 back.
+ */
+
+static int
+captive_portal_detect_request(struct lws_context *context)
+{
+       struct lws_client_connect_info i;
+
+       memset(&i, 0, sizeof i);
+       i.context = context;
+       i.port = 80;
+       i.address = "connectivitycheck.android.com";
+       i.path = "/generate_204";
+       i.host = i.address;
+       i.origin = i.address;
+       i.method = "GET";
+
+       i.protocol = "lws-cpd-http";
+
+       return !lws_client_connect_via_info(&i);
+}
+
+
+lws_system_ops_t ops = {
+       .captive_portal_detect_request = captive_portal_detect_request
+};
+
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *cx = lws_system_context_from_system_mgr(mgr);
+
+       switch (target) {
+       case LWS_SYSTATE_CPD_PRE_TIME:
+               if (lws_system_cpd_state_get(cx))
+                       return 0; /* allow it */
+
+               lwsl_info("%s: LWS_SYSTATE_CPD_PRE_TIME\n", __func__);
+               lws_system_cpd_start(cx);
+               /* we'll move the state on when we get a result */
+               return 1;
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+                       struct lws_client_connect_info i;
+
+                       lwsl_user("%s: OPERATIONAL, cpd %d\n", __func__,
+                                       lws_system_cpd_state_get(cx));
+
+                       /*
+                        * When we reach the OPERATIONAL lws_system state, we
+                        * can do our main job knowing we have DHCP, ntpclient,
+                        * captive portal testing done.
+                        */
+
+                       if (lws_system_cpd_state_get(cx) != LWS_CPD_INTERNET_OK) {
+                               lwsl_warn("%s: There's no internet...\n", __func__);
+                               interrupted = 1;
+                               break;
+                       }
+
+                       memset(&i, 0, sizeof i);
+                       i.context = context;
+                       i.ssl_connection = LCCSCF_USE_SSL;
+                       i.ssl_connection |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
+                                           LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
+                       i.port = 443;
+                       i.address = "warmcat.com";
+                       i.path = "/";
+                       i.host = i.address;
+                       i.origin = i.address;
+                       i.method = "GET";
+
+                       i.protocol = protocols[0].name;
+
+                       lws_client_connect_via_info(&i);
+                       break;
+               }
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+/*
+ * We made this into a different thread to model it being run from completely
+ * different codebase that's all linked together
+ */
+
+
+int main(int argc, const char **argv)
+{
+       int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       struct lws_context_creation_info info;
+       const char *p;
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS minimal http client captive portal detect\n");
+
+       memset(&info, 0, sizeof info);
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.system_ops = &ops;
+       info.protocols = protocols;
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       while (!interrupted)
+               if (lws_service(context, 0))
+                       interrupted = 1;
+
+       lws_context_destroy(context);
+
+       lwsl_user("%s: finished %s\n", __func__, bad ? "FAIL": "OK");
+
+       return bad;
+}
index 1bc44df..07ff4e2 100644 (file)
@@ -1,80 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-client-certinfo C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-client-certinfo)
 set(SRCS minimal-http-client-certinfo.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
-require_lws_config(LWS_OPENSSL_SUPPORT 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 99454f1..9f3bf04 100644 (file)
@@ -26,6 +26,9 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
        uint8_t buf[1280];
        union lws_tls_cert_info_results *ci =
                (union lws_tls_cert_info_results *)buf;
+#if defined(LWS_HAVE_CTIME_R)
+       char date[32];
+#endif
 
        switch (reason) {
 
@@ -37,7 +40,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
                break;
 
        case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
-               status = lws_http_client_http_response(wsi);
+               status = (int)lws_http_client_http_response(wsi);
                lwsl_notice("lws_http_client_http_response %d\n", status);
 
                if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME,
@@ -50,11 +53,22 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
 
                if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_VALIDITY_FROM,
                                            ci, 0))
-                       lwsl_notice(" Peer Cert Valid from: %s", ctime(&ci->time));
-
+#if defined(LWS_HAVE_CTIME_R)
+                       lwsl_notice(" Peer Cert Valid from: %s", 
+                                               ctime_r(&ci->time, date));
+#else
+                       lwsl_notice(" Peer Cert Valid from: %s", 
+                                               ctime(&ci->time));
+#endif
                if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_VALIDITY_TO,
                                            ci, 0))
-                       lwsl_notice(" Peer Cert Valid to  : %s", ctime(&ci->time));
+#if defined(LWS_HAVE_CTIME_R)
+                       lwsl_notice(" Peer Cert Valid to  : %s",
+                                               ctime_r(&ci->time, date));
+#else
+                       lwsl_notice(" Peer Cert Valid to  : %s",
+                                               ctime(&ci->time));
+#endif
                if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_USAGE,
                                            ci, 0))
                        lwsl_notice(" Peer Cert usage bits: 0x%x\n", ci->usage);
@@ -62,8 +76,30 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
                                            LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY,
                                            ci, sizeof(buf) - sizeof(*ci))) {
                        lwsl_notice(" Peer Cert public key:\n");
-                       lwsl_hexdump_notice(ci->ns.name, ci->ns.len);
+                       lwsl_hexdump_notice(ci->ns.name, (unsigned int)ci->ns.len);
+               }
+
+               if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID,
+                                           ci, 0)) {
+                       lwsl_notice(" AUTHORITY_KEY_ID\n");
+                       lwsl_hexdump_notice(ci->ns.name, (size_t)ci->ns.len);
                }
+               if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER,
+                                           ci, 0)) {
+                       lwsl_notice(" AUTHORITY_KEY_ID ISSUER\n");
+                       lwsl_hexdump_notice(ci->ns.name, (size_t)ci->ns.len);
+               }
+               if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_SERIAL,
+                                           ci, 0)) {
+                       lwsl_notice(" AUTHORITY_KEY_ID SERIAL\n");
+                       lwsl_hexdump_notice(ci->ns.name, (size_t)ci->ns.len);
+               }
+               if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_SUBJECT_KEY_ID,
+                                           ci, 0)) {
+                       lwsl_notice(" AUTHORITY_KEY_ID SUBJECT_KEY_ID\n");
+                       lwsl_hexdump_notice(ci->ns.name, (size_t)ci->ns.len);
+               }
+
                break;
 
        /* chunks of chunked content, with header removed */
@@ -118,10 +154,9 @@ static const struct lws_protocols protocols[] = {
        {
                "http",
                callback_http,
-               0,
-               0,
+               0, 0, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 }
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static void
@@ -167,7 +202,7 @@ int main(int argc, const char **argv)
         */
        info.fd_limit_per_thread = 1 + 1 + 1;
 
-#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
        /*
         * OpenSSL uses the system trust store.  mbedTLS has to be told which
         * CA to trust explicitly.
@@ -193,6 +228,10 @@ int main(int argc, const char **argv)
                i.port = 443;
                i.address = "warmcat.com";
        }
+
+       if ((p = lws_cmdline_option(argc, argv, "-s")))
+               i.address = p;
+
        i.path = "/";
        i.host = i.address;
        i.origin = i.address;
index 550393d..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFUDCCBDigAwIBAgISA4mJfIm3iCGbU9+o8YQa+4nUMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5MjNaFw0x
-OTEyMDYwNzA5MjNaMBYxFDASBgNVBAMTC3dhcm1jYXQuY29tMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwnEoH9JW3GvpadpxHGZPb5wv1Q6KfAIMWtdq
-YCOfotFxaYULuzHVxmrTTgmEqJr+eBqUBkXKmGuRR/9UipOmTu5j02qFyWHotFdF
-ZGyp//8z+Rle9Qt1nL68oNIZLDtWkybh5x00b1uo4eyEszXUaa0aLqKP3lH7Q4jI
-aSVARZ8snrJR640Gp3ByudvNTYkGz469bpWzRC/8wSNtzzY02DvHs1GxQx9tMXw+
-BbtUxeP7lpYFKEFBjgZaIKLv+4g8ItJIuO7gMSzG2JfpQHxdhrlhxpx7dsaMUcyM
-nnYXysNL5JG3KEMhkxbtdpCaEQ8jLSPbl/rnF/+mgce+lSjMuQIDAQABo4ICYjCC
-Al4wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
-AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSI9ai12zLFeNTEDHKI9Ghkqcpa2TAf
-BgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEw
-LgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcw
-LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
-MBYGA1UdEQQPMA2CC3dhcm1jYXQuY29tMEwGA1UdIARFMEMwCAYGZ4EMAQIBMDcG
-CysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5
-cHQub3JnMIIBBgYKKwYBBAHWeQIEAgSB9wSB9ADyAHcAY/Lbzeg7zCzPC3KEJ1dr
-M6SNYXePvXWmOLHHaFRL2I0AAAFtCsVHHAAABAMASDBGAiEAy0q1cR4VwPL3iviL
-cBWN67kjJRXk+DwhodmeoM3kb3gCIQC2soAHFs0Umo+0RNdFrL41+hMuidh2cXbb
-Ovc6nh5tOQB3AOJpS64m6OlACeiGG7Y7g9Q+5/50iPukjyiTAZ3d8dv+AAABbQrF
-R48AAAQDAEgwRgIhANqKQm4t9by263CJ7/DLOaZCjtcK29KgJjPwhv08UMn1AiEA
-h35nGTASR8/E7xz+56ZUleqD7U1ABFgWZRZskIzsFO8wDQYJKoZIhvcNAQELBQAD
-ggEBADDJBVbKe2LPHmi8k2vxErB3Y0Ty+3gwgPEXKYtEvQ7tos89eE+QmOXAzH5J
-GwRarFf7kzmKeJv04tMebiEtshpap47oJfxCxfrtpja8hP8Cdu/v/Ae6eEzu3yet
-0N08GJdxQKfgCFaoGUptbaF2RCIZS12SVcX4TPpdP+xaiZdmIx4dGM6tReQ8+y8B
-10b4Hi2+d/zW0W1z6+FAemU6yleWriJDUik5oas9XZF5LAAMDb/WgF5eIB6P9CUG
-LuAO8lWlk9nBgXvMLTxZ74SJb17H4kFEIrIjvABNshz5gBW8xw9nfr5YIfANtwEj
-BDsq06Df3UORYVs/j3T97gPAEZ4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
index a81d45d..0a69c0b 100644 (file)
@@ -1,79 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-client-custom-headers C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-client-custom-headers)
 set(SRCS minimal-http-client-custom-headers.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 377d970..6868371 100644 (file)
@@ -51,7 +51,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
        }
 
        case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
-               status = lws_http_client_http_response(wsi);
+               status = (int)lws_http_client_http_response(wsi);
                lwsl_user("Connected with server response: %d\n", status);
 
                /*
@@ -128,10 +128,9 @@ static const struct lws_protocols protocols[] = {
        {
                "http",
                callback_http,
-               0,
-               0,
+               0, 0, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 }
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static void
@@ -177,7 +176,7 @@ int main(int argc, const char **argv)
         */
        info.fd_limit_per_thread = 1 + 1 + 1;
 
-#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
        /*
         * OpenSSL uses the system trust store.  mbedTLS has to be told which
         * CA to trust explicitly.
index 550393d..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFUDCCBDigAwIBAgISA4mJfIm3iCGbU9+o8YQa+4nUMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5MjNaFw0x
-OTEyMDYwNzA5MjNaMBYxFDASBgNVBAMTC3dhcm1jYXQuY29tMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwnEoH9JW3GvpadpxHGZPb5wv1Q6KfAIMWtdq
-YCOfotFxaYULuzHVxmrTTgmEqJr+eBqUBkXKmGuRR/9UipOmTu5j02qFyWHotFdF
-ZGyp//8z+Rle9Qt1nL68oNIZLDtWkybh5x00b1uo4eyEszXUaa0aLqKP3lH7Q4jI
-aSVARZ8snrJR640Gp3ByudvNTYkGz469bpWzRC/8wSNtzzY02DvHs1GxQx9tMXw+
-BbtUxeP7lpYFKEFBjgZaIKLv+4g8ItJIuO7gMSzG2JfpQHxdhrlhxpx7dsaMUcyM
-nnYXysNL5JG3KEMhkxbtdpCaEQ8jLSPbl/rnF/+mgce+lSjMuQIDAQABo4ICYjCC
-Al4wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
-AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSI9ai12zLFeNTEDHKI9Ghkqcpa2TAf
-BgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEw
-LgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcw
-LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
-MBYGA1UdEQQPMA2CC3dhcm1jYXQuY29tMEwGA1UdIARFMEMwCAYGZ4EMAQIBMDcG
-CysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5
-cHQub3JnMIIBBgYKKwYBBAHWeQIEAgSB9wSB9ADyAHcAY/Lbzeg7zCzPC3KEJ1dr
-M6SNYXePvXWmOLHHaFRL2I0AAAFtCsVHHAAABAMASDBGAiEAy0q1cR4VwPL3iviL
-cBWN67kjJRXk+DwhodmeoM3kb3gCIQC2soAHFs0Umo+0RNdFrL41+hMuidh2cXbb
-Ovc6nh5tOQB3AOJpS64m6OlACeiGG7Y7g9Q+5/50iPukjyiTAZ3d8dv+AAABbQrF
-R48AAAQDAEgwRgIhANqKQm4t9by263CJ7/DLOaZCjtcK29KgJjPwhv08UMn1AiEA
-h35nGTASR8/E7xz+56ZUleqD7U1ABFgWZRZskIzsFO8wDQYJKoZIhvcNAQELBQAD
-ggEBADDJBVbKe2LPHmi8k2vxErB3Y0Ty+3gwgPEXKYtEvQ7tos89eE+QmOXAzH5J
-GwRarFf7kzmKeJv04tMebiEtshpap47oJfxCxfrtpja8hP8Cdu/v/Ae6eEzu3yet
-0N08GJdxQKfgCFaoGUptbaF2RCIZS12SVcX4TPpdP+xaiZdmIx4dGM6tReQ8+y8B
-10b4Hi2+d/zW0W1z6+FAemU6yleWriJDUik5oas9XZF5LAAMDb/WgF5eIB6P9CUG
-LuAO8lWlk9nBgXvMLTxZ74SJb17H4kFEIrIjvABNshz5gBW8xw9nfr5YIfANtwEj
-BDsq06Df3UORYVs/j3T97gPAEZ4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
diff --git a/minimal-examples/http-client/minimal-http-client-h2-rxflow/CMakeLists.txt b/minimal-examples/http-client/minimal-http-client-h2-rxflow/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9a2dc65
--- /dev/null
@@ -0,0 +1,35 @@
+project(lws-minimal-http-client-h2-rxflow C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-http-client-h2-rxflow)
+set(SRCS minimal-http-client.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H2 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+       if (LWS_CTEST_INTERNET_AVAILABLE)
+               add_test(NAME http-client-h2-rxflow-warmcat COMMAND lws-minimal-http-client-h2-rxflow)
+               add_test(NAME http-client-h2-rxflow-warmcat-h1 COMMAND lws-minimal-http-client-h2-rxflow --h1)
+               set_tests_properties(http-client-h2-rxflow-warmcat
+                                    http-client-h2-rxflow-warmcat-h1
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client-h2-rxflow
+                                    TIMEOUT 30)
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/http-client/minimal-http-client-h2-rxflow/README.md b/minimal-examples/http-client/minimal-http-client-h2-rxflow/README.md
new file mode 100644 (file)
index 0000000..1593d26
--- /dev/null
@@ -0,0 +1,53 @@
+# lws minimal http client-h2-rxflow
+
+The application reads from a server with tightly controlled and rate-limited
+receive flow control using h2 tx credit.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-l| Connect to https://localhost:7681 and accept selfsigned cert
+--server <name>|set server name to connect to
+--path <path>|URL path to access on server
+-k|Apply tls option LCCSCF_ALLOW_INSECURE
+-j|Apply tls option LCCSCF_ALLOW_SELFSIGNED
+-m|Apply tls option LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
+-e|Apply tls option LCCSCF_ALLOW_EXPIRED
+-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
+--nossl| disable ssl connection
+-f <initial credit>|Indicate we will manually manage tx credit and set a new connection-specific initial tx credit
+
+RX is constrained to 1024 bytes every 250ms
+
+```
+ $ ./lws-minimal-http-client-h2-rxflow  --server phys.org --path "/" -f 1024
+[2019/12/26 13:32:59:6801] U: LWS minimal http client [-d<verbosity>] [-l] [--h1]
+[2019/12/26 13:33:00:5087] N: system_notify_cb: manual peer tx credit 1024
+[2019/12/26 13:33:01:7390] U: Connected to 72.251.236.55, http response: 200
+[2019/12/26 13:33:01:7441] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:01:0855] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:02:3367] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:02:5858] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:02:8384] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:02:0886] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+...
+[2019/12/26 13:33:46:1152] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:47:3650] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:47:6150] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:47:8666] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:47:1154] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:48:3656] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2019/12/26 13:33:48:6157] U: RECEIVE_CLIENT_HTTP_READ: read 380
+[2019/12/26 13:33:48:6219] U: LWS_CALLBACK_COMPLETED_CLIENT_HTTP
+[2019/12/26 13:33:48:7050] U: Completed: OK
+
+```
+
diff --git a/minimal-examples/http-client/minimal-http-client-h2-rxflow/minimal-http-client.c b/minimal-examples/http-client/minimal-http-client-h2-rxflow/minimal-http-client.c
new file mode 100644 (file)
index 0000000..dbd04b8
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * lws-minimal-http-client-h2-rxflow
+ *
+ * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates the a minimal http client using lws.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.  You
+ * can dump the page data by changing the #if 0 below.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted, bad = 1, status, each = 1024;
+static struct lws *client_wsi;
+
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping = 3,
+       .secs_since_valid_hangup = 10,
+};
+
+struct pss {
+       lws_sorted_usec_list_t sul;
+       struct lws *wsi;
+};
+
+/*
+ * Once we're established, we ask the server for another 1KB every 250ms
+ * until we have it all.
+ */
+
+static void
+drain_cb(lws_sorted_usec_list_t *sul)
+{
+       struct pss *pss = lws_container_of(sul, struct pss, sul);
+
+       lws_wsi_tx_credit(pss->wsi, LWSTXCR_PEER_TO_US, each);
+
+       lws_sul_schedule(lws_get_context(pss->wsi), 0, &pss->sul, drain_cb,
+                        250 * LWS_US_PER_MS);
+}
+
+
+static int
+callback_http(struct lws *wsi, enum lws_callback_reasons reason,
+             void *user, void *in, size_t len)
+{
+       struct pss *pss = (struct pss *)user;
+
+       switch (reason) {
+
+       /* because we are protocols[0] ... */
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+               interrupted = 1;
+               break;
+
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+               {
+                       char buf[128];
+
+                       lws_get_peer_simple(wsi, buf, sizeof(buf));
+                       status = (int)lws_http_client_http_response(wsi);
+
+                       lwsl_user("Connected to %s, http response: %d\n",
+                                       buf, status);
+               }
+               pss->wsi = wsi;
+               lws_sul_schedule(lws_get_context(wsi), 0, &pss->sul, drain_cb,
+                                250 * LWS_US_PER_MS);
+               break;
+
+       /* chunks of chunked content, with header removed */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+               lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
+
+#if 0  /* enable to dump the html */
+               {
+                       const char *p = in;
+
+                       while (len--)
+                               if (*p < 0x7f)
+                                       putchar(*p++);
+                               else
+                                       putchar('.');
+               }
+#endif
+               return 0; /* don't passthru */
+
+       /* uninterpreted http content */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+               {
+                       char buffer[1024 + LWS_PRE];
+                       char *px = buffer + LWS_PRE;
+                       int lenx = sizeof(buffer) - LWS_PRE;
+
+                       if (lws_http_client_read(wsi, &px, &lenx) < 0)
+                               return -1;
+               }
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
+               lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
+               interrupted = 1;
+               bad = status != 200;
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               interrupted = 1;
+               bad = status != 200;
+               lws_sul_cancel(&pss->sul);
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static const struct lws_protocols protocols[] = {
+       {
+               "http",
+               callback_http,
+               sizeof(struct pss),
+               0, 0, NULL, 0
+       },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+struct args {
+       int argc;
+       const char **argv;
+};
+
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                  int current, int target)
+{
+       struct lws_context *context = mgr->parent;
+       struct lws_client_connect_info i;
+       struct args *a = lws_context_user(context);
+       const char *p;
+
+       if (current != LWS_SYSTATE_OPERATIONAL || target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       lwsl_info("%s: operational\n", __func__);
+
+       memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
+       i.context = context;
+       if (!lws_cmdline_option(a->argc, a->argv, "-n"))
+               i.ssl_connection = LCCSCF_USE_SSL;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-l")) {
+               i.port = 7681;
+               i.address = "localhost";
+               i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
+       } else {
+               i.port = 443;
+               i.address = "warmcat.com";
+       }
+
+       if (lws_cmdline_option(a->argc, a->argv, "--nossl"))
+               i.ssl_connection = 0;
+
+       i.ssl_connection |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
+                           LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
+
+       i.alpn = "h2";
+       if (lws_cmdline_option(a->argc, a->argv, "--h1"))
+               i.alpn = "http/1.1";
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "-p")))
+               i.port = atoi(p);
+
+       if (lws_cmdline_option(a->argc, a->argv, "-j"))
+               i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-k"))
+               i.ssl_connection |= LCCSCF_ALLOW_INSECURE;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-m"))
+               i.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-e"))
+               i.ssl_connection |= LCCSCF_ALLOW_EXPIRED;
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "-f"))) {
+               i.ssl_connection |= LCCSCF_H2_MANUAL_RXFLOW;
+               i.manual_initial_tx_credit = atoi(p);
+               lwsl_notice("%s: manual peer tx credit %d\n", __func__,
+                               i.manual_initial_tx_credit);
+       }
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--each")))
+               each = atoi(p);
+
+       /* the default validity check is 5m / 5m10s... -v = 3s / 10s */
+
+       if (lws_cmdline_option(a->argc, a->argv, "-v"))
+               i.retry_and_idle_policy = &retry;
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--server")))
+               i.address = p;
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--path")))
+               i.path = p;
+       else
+               i.path = "/";
+
+       i.host = i.address;
+       i.origin = i.address;
+       i.method = "GET";
+
+       i.protocol = protocols[0].name;
+       i.pwsi = &client_wsi;
+
+       return !lws_client_connect_via_info(&i);
+}
+
+int main(int argc, const char **argv)
+{
+       lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
+                                               system_notify_cb, "app" };
+       lws_state_notify_link_t *na[] = { &notifier, NULL };
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       struct args args;
+       int n = 0;
+       // uint8_t memcert[4096];
+
+       args.argc = argc;
+       args.argv = argv;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS minimal http client [-d<verbosity>] [-l] [--h1]\n");
+
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
+       info.protocols = protocols;
+       info.user = &args;
+       info.register_notifier_list = na;
+       info.timeout_secs = 10;
+       info.connect_timeout_secs = 30;
+
+       /*
+        * since we know this lws context is only ever going to be used with
+        * one client wsis / fds / sockets at a time, let lws know it doesn't
+        * have to use the default allocations for fd tables up to ulimit -n.
+        * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
+        * will use.
+        */
+       info.fd_limit_per_thread = 1 + 1 + 1;
+
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+       /*
+        * OpenSSL uses the system trust store.  mbedTLS has to be told which
+        * CA to trust explicitly.
+        */
+       info.client_ssl_ca_filepath = "./warmcat.com.cer";
+#endif
+#if 0
+       n = open("./warmcat.com.cer", O_RDONLY);
+       if (n >= 0) {
+               info.client_ssl_ca_mem_len = read(n, memcert, sizeof(memcert));
+               info.client_ssl_ca_mem = memcert;
+               close(n);
+               n = 0;
+               memcert[info.client_ssl_ca_mem_len++] = '\0';
+       }
+#endif
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/http-client/minimal-http-client-h2-rxflow/warmcat.com.cer b/minimal-examples/http-client/minimal-http-client-h2-rxflow/warmcat.com.cer
new file mode 100644 (file)
index 0000000..01ad0dc
--- /dev/null
@@ -0,0 +1,32 @@
+-----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-----
+
index 22a3011..cb42d1f 100644 (file)
@@ -1,78 +1,49 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-client-hugeurl C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-client-hugeurl)
 set(SRCS minimal-http-client-hugeurl.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
+       if (LWS_CTEST_INTERNET_AVAILABLE)
+
+               #
+               # creates a fixture res_hchugeurlw to get a lease on the
+               # server resources
+               #
+               sai_resource(warmcat_conns 1 40 hchugeurlw)
+       
+               add_test(NAME http-client-hugeurl-warmcat COMMAND lws-minimal-http-client-hugeurl )
+               add_test(NAME http-client-hugeurl-warmcat-h1 COMMAND lws-minimal-http-client-hugeurl  --h1)
+               set_tests_properties(http-client-hugeurl-warmcat
+                                    http-client-hugeurl-warmcat-h1
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client-hugeurl
+                                    TIMEOUT 20)
+               if (DEFINED ENV{SAI_OVN})
+                       set_tests_properties(http-client-hugeurl-warmcat
+                                            http-client-hugeurl-warmcat-h1
+                                            PROPERTIES
+                                               FIXTURES_REQUIRED "res_hchugeurlw")     
+               endif()
+
+       endif()
+
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 174ddb9..a3cda5d 100644 (file)
@@ -77,7 +77,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
                break;
 
        case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
-               status = lws_http_client_http_response(wsi);
+               status = (int)lws_http_client_http_response(wsi);
                lwsl_user("Connected with server response: %d\n", status);
                break;
 
@@ -132,10 +132,9 @@ static const struct lws_protocols protocols[] = {
        {
                "http",
                callback_http,
-               0,
-               0,
+               0, 0, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 }
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static void
@@ -149,26 +148,21 @@ int main(int argc, const char **argv)
        struct lws_context_creation_info info;
        struct lws_client_connect_info i;
        struct lws_context *context;
-       const char *p;
-       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
-                       /* for LLL_ verbosity above NOTICE to be built into lws,
-                        * lws must have been configured and built with
-                        * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
-                       /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
-                       /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
-                       /* | LLL_DEBUG */;
-
-       if ((p = lws_cmdline_option(argc, argv, "-d")))
-               logs = atoi(p);
+       int n = 0;
 
        signal(SIGINT, sigint_handler);
-       lws_set_log_level(logs, NULL);
-       lwsl_user("LWS minimal http client hugeurl [-d <verbosity>] [-l] [--h1]\n");
 
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS minimal http client hugeurl [-d <verbosity>] [-l] [--h1]\n");
+
        info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
        info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
        info.protocols = protocols;
+       info.pt_serv_buf_size = 8192;
+       info.timeout_secs = 10;
+       info.connect_timeout_secs = 30;
        /*
         * since we know this lws context is only ever going to be used with
         * one client wsis / fds / sockets at a time, let lws know it doesn't
@@ -178,7 +172,7 @@ int main(int argc, const char **argv)
         */
        info.fd_limit_per_thread = 1 + 1 + 1;
 
-#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
        /*
         * OpenSSL uses the system trust store.  mbedTLS has to be told which
         * CA to trust explicitly.
diff --git a/minimal-examples/http-client/minimal-http-client-hugeurl/selftest.sh b/minimal-examples/http-client/minimal-http-client-hugeurl/selftest.sh
deleted file mode 100755 (executable)
index 2da54b6..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=6
-
-dotest $1 $2 warmcat
-dotest $1 $2 warmcat-h1 --h1
-
-spawn "" $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost -l
-spawn $SPID $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost-h1 -l --h1
-kill $SPID 2>/dev/null
-wait $SPID 2>/dev/null
-
-
-if [ -z "$TRAVIS_OS_NAME" ] ; then
-       SPID=""
-       spawn "" $5/http-server/minimal-http-server-eventlib $1/lws-minimal-http-server-eventlib --uv -s
-       dotest $1 $2 localhost-suv -l
-       spawn $SPID $5/http-server/minimal-http-server-eventlib $1/lws-minimal-http-server-eventlib --uv -s
-       dotest $1 $2 localhost-suv-h1 -l --h1
-
-       kill $SPID 2>/dev/null
-       wait $SPID 2>/dev/null
-fi
-
-exit $FAILS
-
-
index 550393d..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFUDCCBDigAwIBAgISA4mJfIm3iCGbU9+o8YQa+4nUMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5MjNaFw0x
-OTEyMDYwNzA5MjNaMBYxFDASBgNVBAMTC3dhcm1jYXQuY29tMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwnEoH9JW3GvpadpxHGZPb5wv1Q6KfAIMWtdq
-YCOfotFxaYULuzHVxmrTTgmEqJr+eBqUBkXKmGuRR/9UipOmTu5j02qFyWHotFdF
-ZGyp//8z+Rle9Qt1nL68oNIZLDtWkybh5x00b1uo4eyEszXUaa0aLqKP3lH7Q4jI
-aSVARZ8snrJR640Gp3ByudvNTYkGz469bpWzRC/8wSNtzzY02DvHs1GxQx9tMXw+
-BbtUxeP7lpYFKEFBjgZaIKLv+4g8ItJIuO7gMSzG2JfpQHxdhrlhxpx7dsaMUcyM
-nnYXysNL5JG3KEMhkxbtdpCaEQ8jLSPbl/rnF/+mgce+lSjMuQIDAQABo4ICYjCC
-Al4wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
-AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSI9ai12zLFeNTEDHKI9Ghkqcpa2TAf
-BgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEw
-LgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcw
-LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
-MBYGA1UdEQQPMA2CC3dhcm1jYXQuY29tMEwGA1UdIARFMEMwCAYGZ4EMAQIBMDcG
-CysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5
-cHQub3JnMIIBBgYKKwYBBAHWeQIEAgSB9wSB9ADyAHcAY/Lbzeg7zCzPC3KEJ1dr
-M6SNYXePvXWmOLHHaFRL2I0AAAFtCsVHHAAABAMASDBGAiEAy0q1cR4VwPL3iviL
-cBWN67kjJRXk+DwhodmeoM3kb3gCIQC2soAHFs0Umo+0RNdFrL41+hMuidh2cXbb
-Ovc6nh5tOQB3AOJpS64m6OlACeiGG7Y7g9Q+5/50iPukjyiTAZ3d8dv+AAABbQrF
-R48AAAQDAEgwRgIhANqKQm4t9by263CJ7/DLOaZCjtcK29KgJjPwhv08UMn1AiEA
-h35nGTASR8/E7xz+56ZUleqD7U1ABFgWZRZskIzsFO8wDQYJKoZIhvcNAQELBQAD
-ggEBADDJBVbKe2LPHmi8k2vxErB3Y0Ty+3gwgPEXKYtEvQ7tos89eE+QmOXAzH5J
-GwRarFf7kzmKeJv04tMebiEtshpap47oJfxCxfrtpja8hP8Cdu/v/Ae6eEzu3yet
-0N08GJdxQKfgCFaoGUptbaF2RCIZS12SVcX4TPpdP+xaiZdmIx4dGM6tReQ8+y8B
-10b4Hi2+d/zW0W1z6+FAemU6yleWriJDUik5oas9XZF5LAAMDb/WgF5eIB6P9CUG
-LuAO8lWlk9nBgXvMLTxZ74SJb17H4kFEIrIjvABNshz5gBW8xw9nfr5YIfANtwEj
-BDsq06Df3UORYVs/j3T97gPAEZ4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
diff --git a/minimal-examples/http-client/minimal-http-client-jit-trust/CMakeLists.txt b/minimal-examples/http-client/minimal-http-client-jit-trust/CMakeLists.txt
new file mode 100644 (file)
index 0000000..eef5cd8
--- /dev/null
@@ -0,0 +1,157 @@
+project(lws-minimal-http-client-jit-trust C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-http-client-jit-trust)
+set(SRCS minimal-http-client.c)
+
+set(has_fault_injection 1)
+set(has_h2 1)
+set(has_plugins 1)
+set(has_ss_policy_parse 1)
+set(has_no_system_vhost 1)
+set(has_async_dns 1)
+
+set(requirements 1)
+
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+require_lws_config(LWS_WITH_TLS_JIT_TRUST 1 requirements)
+
+require_lws_config(LWS_ROLE_H2 1 has_h2)
+require_lws_config(LWS_WITH_SYS_FAULT_INJECTION 1 has_fault_injection)
+require_lws_config(LWS_WITH_EVLIB_PLUGINS 1 has_plugins)
+require_lws_config(LWS_WITH_EVENT_LIBS 1 has_plugins)
+
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 has_ss_policy_parse)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 has_ss_policy_parse)
+
+require_lws_config(LWS_WITH_SYS_ASYNC_DNS 0 has_no_system_vhost)
+require_lws_config(LWS_WITH_SYS_NTPCLIENT 0 has_no_system_vhost)
+require_lws_config(LWS_WITH_SYS_DHCP_CLIENT 0 has_no_system_vhost)
+
+require_lws_config(LWS_WITH_SYS_ASYNC_DNS 1 has_async_dns)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       find_program(VALGRIND "valgrind")
+       
+       sai_resource(warmcat_conns 1 40 http_client_warmcat)
+
+       if (LWS_CTEST_INTERNET_AVAILABLE)
+               set(mytests http-client-warmcat-h1)
+               if (has_h2)
+                       add_test(NAME http-client-warmcat COMMAND lws-minimal-http-client )
+                       list(APPEND mytests http-client-warmcat)
+               endif()
+
+
+               add_test(NAME http-client-warmcat-h1 COMMAND lws-minimal-http-client  --h1)
+                                    
+               if (has_fault_injection)
+               
+                       # creation related faults
+               
+                       list(APPEND mytests http-client-fi-ctx1)
+                       add_test(NAME http-client-fi-ctx1 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail1")
+                       
+                       # if (has_plugins)
+                       # !!! need to actually select an available evlib plugin to trigger this
+                       #       list(APPEND mytests http-client-fi-pi)
+                       #       add_test(NAME http-client-fi-pi COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_plugin_init")
+                       # endif()
+
+                       list(APPEND mytests http-client-fi-ctx2)
+                       add_test(NAME http-client-fi-ctx2 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_evlib_sel")
+                       
+                       list(APPEND mytests http-client-fi-ctx3)
+                       add_test(NAME http-client-fi-ctx3 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_oom_ctx")
+                       
+                       list(APPEND mytests http-client-fi-ctx4)
+                       add_test(NAME http-client-fi-ctx4 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_privdrop")
+
+                       list(APPEND mytests http-client-fi-ctx5)
+                       add_test(NAME http-client-fi-ctx5 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_maxfds")
+                       
+                       list(APPEND mytests http-client-fi-ctx6)
+                       add_test(NAME http-client-fi-ctx6 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_oom_fds")
+                       
+                       list(APPEND mytests http-client-fi-ctx7)
+                       add_test(NAME http-client-fi-ctx7 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_plat_init")
+                       
+                       list(APPEND mytests http-client-fi-ctx8)
+                       add_test(NAME http-client-fi-ctx8 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_evlib_init")
+                       
+                       list(APPEND mytests http-client-fi-ctx9)
+                       add_test(NAME http-client-fi-ctx9 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_evlib_pt")
+                       
+                       if (NOT has_no_system_vhost)
+                       
+                               list(APPEND mytests http-client-fi-ctx10)
+                               add_test(NAME http-client-fi-ctx10 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_sys_vh")
+                       
+                               list(APPEND mytests http-client-fi-ctx11)
+                               add_test(NAME http-client-fi-ctx11 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_sys_vh_init")
+                               
+                       endif()
+                       
+                       list(APPEND mytests http-client-fi-ctx12)
+                       add_test(NAME http-client-fi-ctx12 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_def_vh")
+                       
+
+                       list(APPEND mytests http-client-fi-vh1)
+                       add_test(NAME http-client-fi-vh1 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_oom")
+                       
+                       list(APPEND mytests http-client-fi-vh2)
+                       add_test(NAME http-client-fi-vh2 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_pcols_oom")
+                       
+                       list(APPEND mytests http-client-fi-vh3)
+                       add_test(NAME http-client-fi-vh3 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_ssl_srv")
+
+                       list(APPEND mytests http-client-fi-vh4)
+                       add_test(NAME http-client-fi-vh4 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_ssl_cli")
+                       
+                       list(APPEND mytests http-client-fi-vh5)
+                       add_test(NAME http-client-fi-vh5 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_srv_init")
+
+
+                       list(APPEND mytests http-client-fi-dnsfail)
+                       add_test(NAME http-client-fi-dnsfail COMMAND lws-minimal-http-client --expected-exit 3 --fault-injection "wsi=user/dnsfail")
+                       
+                       if (has_async_dns)
+                               list(APPEND mytests http-client-fi-connfail)
+                               add_test(NAME http-client-fi-connfail COMMAND lws-minimal-http-client --expected-exit 3 --fault-injection "wsi=user/connfail")
+                       else()
+                               list(APPEND mytests http-client-fi-connfail)
+                               add_test(NAME http-client-fi-connfail COMMAND lws-minimal-http-client --expected-exit 2 --fault-injection "wsi=user/connfail")
+                       endif()
+                       
+                       list(APPEND mytests http-client-fi-user-est-fail)
+                       add_test(NAME http-client-fi-user-est-fail COMMAND lws-minimal-http-client --expected-exit 3 --fault-injection "wsi/user_reject_at_est")        
+               
+                       
+               endif()
+               
+               set_tests_properties(${mytests} PROPERTIES
+                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client
+                    TIMEOUT 20)
+                                    
+               if (DEFINED ENV{SAI_OVN})
+                       set_tests_properties(${mytests} PROPERTIES
+                                            FIXTURES_REQUIRED "res_http_client_warmcat")
+               endif()         
+       
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/http-client/minimal-http-client-jit-trust/README.md b/minimal-examples/http-client/minimal-http-client-jit-trust/README.md
new file mode 100644 (file)
index 0000000..024f739
--- /dev/null
@@ -0,0 +1,96 @@
+# lws minimal http client JIT Trust
+
+This example turns off any existing trusted CAs and then tries to connect to a server, by default, warmcat.com.
+
+It validates the remote certificates using trusted CAs from a JIT Trust blob compiled into the code.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-l| Connect to https://localhost:7681 and accept selfsigned cert
+--h1|Specify http/1.1 only using ALPN, rejects h2 even if server supports it
+--server <name>|set server name to connect to
+-k|Apply tls option LCCSCF_ALLOW_INSECURE
+-j|Apply tls option LCCSCF_ALLOW_SELFSIGNED
+-m|Apply tls option LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
+-e|Apply tls option LCCSCF_ALLOW_EXPIRED
+-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
+--nossl| disable ssl connection
+--user <username>| Set Basic Auth username
+--password <password> | Set Basic Auth password
+
+```
+ $ ./bin/lws-minimal-http-client-jit-trust --h1 --server ebay.com --path /
+==1302866== 
+[2021/06/17 14:33:54:7500] U: LWS minimal http client JIT Trust [-d<verbosity>] [-l] [--h1]
+[2021/06/17 14:33:54:7956] N: LWS: 4.2.99-v4.2.0-70-g80e7e39bae, loglevel 1031
+[2021/06/17 14:33:54:7960] N: NET CLI SRV H1 H2 WS MbedTLS ConMon IPv6-absent
+[2021/06/17 14:33:54:8165] N:  ++ [wsi|0|pipe] (1)
+[2021/06/17 14:33:54:8227] N:  ++ [vh|0|netlink] (1)
+[2021/06/17 14:33:54:8319] N:  ++ [vh|1|default||-1] (2)
+[2021/06/17 14:33:55:0107] N:  ++ [wsicli|0|GET/h1/ebay.com] (1)
+[2021/06/17 14:33:56:0291] N:  ++ [vh|2|jitt-7F69A044||-1] (3)
+[2021/06/17 14:33:56:0355] E: CLIENT_CONNECTION_ERROR: server's cert didn't look good, invalidca (use_ssl 0x20000061) X509_V_ERR = 24: CA is not trusted
+
+[2021/06/17 14:33:56:0376] N:  ++ [wsicli|1|GET/h1/ebay.com] (2)
+[2021/06/17 14:33:56:0746] N:  -- [wsicli|0|GET/h1/ebay.com] (1) 1.061s
+[2021/06/17 14:33:56:7555] N: lws_client_reset: REDIRECT www.ebay.com:443, path='/', ssl = 1, alpn='http/1.1'
+[2021/06/17 14:33:57:0205] N:  ++ [vh|3|jitt-DFF2B5B4||-1] (4)
+[2021/06/17 14:33:57:0208] E: CLIENT_CONNECTION_ERROR: server's cert didn't look good, invalidca (use_ssl 0x1) X509_V_ERR = 24: CA is not trusted
+
+[2021/06/17 14:33:57:0210] N:  ++ [wsicli|2|GET/h1/ebay.com] (2)
+[2021/06/17 14:33:57:0288] N:  -- [wsicli|1|GET/h1/ebay.com] (1) 991.119ms
+[2021/06/17 14:33:57:7528] N: lws_client_reset: REDIRECT www.ebay.com:443, path='/', ssl = 1, alpn='http/1.1'
+[2021/06/17 14:33:58:1564] U: Connected to 195.95.193.127, http response: 200
+[2021/06/17 14:33:58:1637] U: RECEIVE_CLIENT_HTTP_READ: read 209
+[2021/06/17 14:33:58:1796] U: RECEIVE_CLIENT_HTTP_READ: read 197
+[2021/06/17 14:33:58:1822] U: RECEIVE_CLIENT_HTTP_READ: read 1014
+[2021/06/17 14:33:58:1847] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:1851] U: RECEIVE_CLIENT_HTTP_READ: read 1022
+[2021/06/17 14:33:58:2748] U: RECEIVE_CLIENT_HTTP_READ: read 242
+[2021/06/17 14:33:58:2782] U: RECEIVE_CLIENT_HTTP_READ: read 1014
+[2021/06/17 14:33:58:2784] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:2785] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+...
+[2021/06/17 14:33:58:4661] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4662] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4663] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4664] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4665] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4666] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4667] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4668] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4669] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4670] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4671] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4672] U: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2021/06/17 14:33:58:4673] U: RECEIVE_CLIENT_HTTP_READ: read 286
+[2021/06/17 14:33:58:4690] U: LWS_CALLBACK_COMPLETED_CLIENT_HTTP
+[2021/06/17 14:33:58:4712] E: main: destroying context, interrupted = 1
+[2021/06/17 14:33:58:4774] N:  -- [wsi|0|pipe] (0) 3.661s
+[2021/06/17 14:33:58:4780] N: callback_http: LWS_CALLBACK_CLOSED_CLIENT_HTTP
+[2021/06/17 14:33:58:4829] N:  -- [vh|3|jitt-DFF2B5B4||-1] (3) 1.462s
+[2021/06/17 14:33:58:4833] N:  -- [wsicli|2|GET/h1/ebay.com] (0) 1.462s
+[2021/06/17 14:33:58:4834] N:  -- [vh|0|netlink] (2) 3.660s
+[2021/06/17 14:33:58:4858] N:  -- [vh|1|default||-1] (1) 3.654s
+[2021/06/17 14:33:58:4860] N:  -- [vh|2|jitt-7F69A044||-1] (0) 2.456s
+[2021/06/17 14:33:58:4974] U: Completed: OK (seen expected 0)
+```
+
+You can also test the client Basic Auth support against the http-server/minimal-http-server-basicauth
+example.  In one console window run the server and in the other
+
+```
+$ lws-minimal-http-client -l --nossl --path /secret/index.html --user user --password password
+```
+
+The Basic Auth credentials for the test server are literally username "user" and password "password".
+
diff --git a/minimal-examples/http-client/minimal-http-client-jit-trust/minimal-http-client.c b/minimal-examples/http-client/minimal-http-client-jit-trust/minimal-http-client.c
new file mode 100644 (file)
index 0000000..92fd04e
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * lws-minimal-http-client-jit-trust
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates the a minimal http client using lws.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.  You
+ * can dump the page data by changing the #if 0 below.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted, bad = 1, status, conmon;
+#if defined(LWS_WITH_HTTP2)
+static int long_poll;
+#endif
+static struct lws *client_wsi;
+static const char *ba_user, *ba_password;
+static int budget = 6;
+
+/*
+ * For this example, we import the C-formatted array version of the trust blob
+ * directly.  This is produced by running scripts/mozilla-trust-gen.sh and can
+ * be found in ./_trust after that.
+ */
+
+static uint8_t jit_trust_blob[] = {
+#include "./trust_blob.h"
+};
+
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping = 3,
+       .secs_since_valid_hangup = 10,
+};
+
+#if defined(LWS_WITH_CONMON)
+void
+dump_conmon_data(struct lws *wsi)
+{
+       const struct addrinfo *ai;
+       struct lws_conmon cm;
+       char ads[48];
+
+       lws_conmon_wsi_take(wsi, &cm);
+
+       lws_sa46_write_numeric_address(&cm.peer46, ads, sizeof(ads));
+       lwsl_notice("%s: peer %s, dns: %uus, sockconn: %uus, "
+                   "tls: %uus, txn_resp: %uus\n",
+                   __func__, ads,
+                   (unsigned int)cm.ciu_dns,
+                   (unsigned int)cm.ciu_sockconn,
+                   (unsigned int)cm.ciu_tls,
+                   (unsigned int)cm.ciu_txn_resp);
+
+       ai = cm.dns_results_copy;
+       while (ai) {
+               lws_sa46_write_numeric_address((lws_sockaddr46 *)ai->ai_addr,
+                                               ads, sizeof(ads));
+               lwsl_notice("%s: DNS %s\n", __func__, ads);
+               ai = ai->ai_next;
+       }
+
+       /*
+        * This destroys the DNS list in the lws_conmon that we took
+        * responsibility for when we used lws_conmon_wsi_take()
+        */
+
+       lws_conmon_release(&cm);
+}
+#endif
+
+struct args {
+       int argc;
+       const char **argv;
+};
+
+static const struct lws_protocols protocols[];
+
+static int
+try_connect(struct lws_context *cx)
+{
+       struct lws_client_connect_info i;
+       struct args *a = lws_context_user(cx);
+       const char *p;
+
+       memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
+       i.context = cx;
+       if (!lws_cmdline_option(a->argc, a->argv, "-n")) {
+               i.ssl_connection = LCCSCF_USE_SSL;
+#if defined(LWS_WITH_HTTP2)
+               /* requires h2 */
+               if (lws_cmdline_option(a->argc, a->argv, "--long-poll")) {
+                       lwsl_user("%s: long poll mode\n", __func__);
+                       long_poll = 1;
+               }
+#endif
+       }
+
+       if (lws_cmdline_option(a->argc, a->argv, "-l")) {
+               i.port = 7681;
+               i.address = "localhost";
+               i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
+       } else {
+               i.port = 443;
+               i.address = "warmcat.com";
+       }
+
+       if (lws_cmdline_option(a->argc, a->argv, "--nossl"))
+               i.ssl_connection = 0;
+
+       i.ssl_connection |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
+                           LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM |
+                           LCCSCF_ACCEPT_TLS_DOWNGRADE_REDIRECTS;
+
+       i.alpn = "h2,http/1.1";
+       if (lws_cmdline_option(a->argc, a->argv, "--h1"))
+               i.alpn = "http/1.1";
+
+       if (lws_cmdline_option(a->argc, a->argv, "--h2-prior-knowledge"))
+               i.ssl_connection |= LCCSCF_H2_PRIOR_KNOWLEDGE;
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "-p")))
+               i.port = atoi(p);
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--user")))
+               ba_user = p;
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--password")))
+               ba_password = p;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-j"))
+               i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-k"))
+               i.ssl_connection |= LCCSCF_ALLOW_INSECURE;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-m"))
+               i.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-e"))
+               i.ssl_connection |= LCCSCF_ALLOW_EXPIRED;
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "-f"))) {
+               i.ssl_connection |= LCCSCF_H2_MANUAL_RXFLOW;
+               i.manual_initial_tx_credit = atoi(p);
+               lwsl_notice("%s: manual peer tx credit %d\n", __func__,
+                               i.manual_initial_tx_credit);
+       }
+
+#if defined(LWS_WITH_CONMON)
+       if (lws_cmdline_option(a->argc, a->argv, "--conmon")) {
+               i.ssl_connection |= LCCSCF_CONMON;
+               conmon = 1;
+       }
+#endif
+
+       /* the default validity check is 5m / 5m10s... -v = 3s / 10s */
+
+       if (lws_cmdline_option(a->argc, a->argv, "-v"))
+               i.retry_and_idle_policy = &retry;
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--server")))
+               i.address = p;
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--path")))
+               i.path = p;
+       else
+               i.path = "/";
+
+       i.host = i.address;
+       i.origin = i.address;
+       i.method = "GET";
+
+       i.protocol = protocols[0].name;
+       i.pwsi = &client_wsi;
+       i.fi_wsi_name = "user";
+
+       if (!lws_client_connect_via_info(&i)) {
+               lwsl_err("Client creation failed\n");
+               interrupted = 1;
+               bad = 2; /* could not even start client connection */
+               lws_cancel_service(cx);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static const char *ua = "Mozilla/5.0 (X11; Linux x86_64) "
+                       "AppleWebKit/537.36 (KHTML, like Gecko) "
+                       "Chrome/51.0.2704.103 Safari/537.36",
+                 *acc = "*/*";
+
+static int
+callback_http(struct lws *wsi, enum lws_callback_reasons reason,
+             void *user, void *in, size_t len)
+{
+       switch (reason) {
+
+       /* because we are protocols[0] ... */
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+
+               if (budget--) {
+                       try_connect(lws_get_context(wsi));
+                       break;
+               }
+
+               interrupted = 1;
+               bad = 3; /* connection failed before we could make connection */
+               lws_cancel_service(lws_get_context(wsi));
+
+#if defined(LWS_WITH_CONMON)
+       if (conmon)
+               dump_conmon_data(wsi);
+#endif
+               break;
+
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+               {
+                       char buf[128];
+
+                       lws_get_peer_simple(wsi, buf, sizeof(buf));
+                       status = (int)lws_http_client_http_response(wsi);
+
+                       lwsl_user("Connected to %s, http response: %d\n",
+                                       buf, status);
+               }
+#if defined(LWS_WITH_HTTP2)
+               if (long_poll) {
+                       lwsl_user("%s: Client entering long poll mode\n", __func__);
+                       lws_h2_client_stream_long_poll_rxonly(wsi);
+               }
+#endif
+
+               if (lws_fi_user_wsi_fi(wsi, "user_reject_at_est"))
+                       return -1;
+
+               break;
+
+
+       case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
+       {
+               unsigned char **p = (unsigned char **)in, *end = (*p) + len;
+
+               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_USER_AGENT,
+                               (unsigned char *)ua, (int)strlen(ua), p, end))
+                       return -1;
+
+               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ACCEPT,
+                               (unsigned char *)acc, (int)strlen(acc), p, end))
+                       return -1;
+
+#if defined(LWS_WITH_HTTP_BASIC_AUTH)
+               {
+               char b[128];
+
+       /* you only need this if you need to do Basic Auth */
+
+               if (!ba_user || !ba_password)
+                       break;
+
+               if (lws_http_basic_auth_gen(ba_user, ba_password, b, sizeof(b)))
+                       break;
+               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION,
+                               (unsigned char *)b, (int)strlen(b), p, end))
+                       return -1;
+               }
+#endif
+
+               break;
+       }
+
+       /* chunks of chunked content, with header removed */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+               lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
+#if defined(LWS_WITH_HTTP2)
+               if (long_poll) {
+                       char dotstar[128];
+                       lws_strnncpy(dotstar, (const char *)in, len,
+                                    sizeof(dotstar));
+                       lwsl_notice("long poll rx: %d '%s'\n", (int)len,
+                                       dotstar);
+               }
+#endif
+#if 0
+               lwsl_hexdump_notice(in, len);
+#endif
+
+               return 0; /* don't passthru */
+
+       /* uninterpreted http content */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+               {
+                       char buffer[1024 + LWS_PRE];
+                       char *px = buffer + LWS_PRE;
+                       int lenx = sizeof(buffer) - LWS_PRE;
+
+                       if (lws_fi_user_wsi_fi(wsi, "user_reject_at_rx"))
+                               return -1;
+
+                       if (lws_http_client_read(wsi, &px, &lenx) < 0)
+                               return -1;
+               }
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
+               lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
+               interrupted = 1;
+               bad = 0; // we accept 403 or whatever for this test status != 200;
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+               break;
+
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               lwsl_notice("%s: LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", __func__);
+               interrupted = 1;
+               bad = 0; // status != 200;
+               lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+#if defined(LWS_WITH_CONMON)
+               if (conmon)
+                       dump_conmon_data(wsi);
+#endif
+               break;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static const struct lws_protocols protocols[] = {
+       {
+               "http",
+               callback_http,
+               0, 0, 0, NULL, 0
+       },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                  int current, int target)
+{
+       struct lws_context *cx = mgr->parent;
+
+       if (current != LWS_SYSTATE_OPERATIONAL ||
+           target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       lwsl_info("%s: operational\n", __func__);
+
+       try_connect(cx);
+
+       return 0;
+}
+
+static int
+jit_trust_query(struct lws_context *cx, const uint8_t *skid,
+               size_t skid_len, void *got_opaque)
+{
+       const uint8_t *der = NULL;
+       size_t der_len = 0;
+
+       lwsl_info("%s\n", __func__);
+       lwsl_hexdump_info(skid, skid_len);
+
+       /*
+        * For this example, we look up SKIDs using a trust table that's
+        * compiled in, synchronously.  Lws provides the necessary helper.
+        *
+        * DER will remain NULL if no match.
+        */
+
+       lws_tls_jit_trust_blob_queury_skid(jit_trust_blob,
+                                          sizeof(jit_trust_blob), skid,
+                                          skid_len, &der, &der_len);
+
+       if (der)
+               lwsl_info("%s: found len %d\n", __func__, (int)der_len);
+       else
+               lwsl_info("%s: not trusted\n", __func__);
+
+       /* Once we have a result, pass it to the completion helper */
+
+       return lws_tls_jit_trust_got_cert_cb(cx, got_opaque, skid, skid_len,
+                                            der, der_len);
+}
+
+static lws_system_ops_t system_ops = {
+       .jit_trust_query                = jit_trust_query
+};
+
+int main(int argc, const char **argv)
+{
+       lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
+                                               system_notify_cb, "app" };
+       lws_state_notify_link_t *na[] = { &notifier, NULL };
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0, expected = 0;
+       struct args args;
+       const char *p;
+
+       args.argc = argc;
+       args.argv = argv;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS minimal http client JIT Trust [-d<verbosity>] [-l] [--h1]\n");
+
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+                      /* we start off not trusting anything */
+                      LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW;
+       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
+       info.protocols = protocols;
+       info.user = &args;
+       info.register_notifier_list = na;
+       info.connect_timeout_secs = 30;
+       info.system_ops = &system_ops;
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.max_http_header_data = 8192;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               bad = 5;
+               goto bail;
+       }
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lwsl_err("%s: destroying context, interrupted = %d\n", __func__,
+                       interrupted);
+
+       lws_context_destroy(context);
+
+bail:
+       if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
+               expected = atoi(p);
+
+       if (bad == expected) {
+               lwsl_user("Completed: OK (seen expected %d)\n", expected);
+               return 0;
+       }
+
+       lwsl_err("Completed: failed: exit %d, expected %d\n", bad, expected);
+
+       return 1;
+}
diff --git a/minimal-examples/http-client/minimal-http-client-jit-trust/trust_blob.h b/minimal-examples/http-client/minimal-http-client-jit-trust/trust_blob.h
new file mode 100644 (file)
index 0000000..615d1df
--- /dev/null
@@ -0,0 +1,8931 @@
+0x54, 0x42, 0x4c, 0x42, 0x00, 0x01, 0x00, 0x80, 0x60, 0xc6, 0xf3, 0x12, 0x00, 0x02, 0x22, 0xd8,
+0x00, 0x02, 0x23, 0xd8, 0x00, 0x02, 0x24, 0x58, 0x00, 0x02, 0x2e, 0x30, 0x30, 0x82, 0x05, 0x82,
+0x30, 0x82, 0x03, 0x6a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0b, 0x5a, 0x4b, 0xbd, 0x5a, 0xfb,
+0x4f, 0x8a, 0x5b, 0xfa, 0x65, 0xe5, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x4d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x41, 0x54, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1a, 0x65,
+0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x65, 0x20, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
+0x72, 0x69, 0x6e, 0x67, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x13, 0x10, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
+0x32, 0x30, 0x32, 0x30, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x32, 0x31, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x30, 0x30, 0x36, 0x31, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x5a, 0x30, 0x4d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x41, 0x54, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1a, 0x65, 0x2d,
+0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x65, 0x20, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
+0x69, 0x6e, 0x67, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x10, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x32,
+0x30, 0x32, 0x30, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02,
+0x82, 0x02, 0x01, 0x00, 0xae, 0x2e, 0x56, 0xad, 0x1b, 0x1c, 0xef, 0xf6, 0x95, 0x8f, 0xa0, 0x77,
+0x1b, 0x2b, 0xd3, 0x63, 0x8f, 0x84, 0x4d, 0x45, 0xa2, 0x0f, 0x9f, 0x5b, 0x45, 0xab, 0x59, 0x7b,
+0x51, 0x34, 0xf9, 0xec, 0x8b, 0x8a, 0x78, 0xc5, 0xdd, 0x6b, 0xaf, 0xbd, 0xc4, 0xdf, 0x93, 0x45,
+0x1e, 0xbf, 0x91, 0x38, 0x0b, 0xae, 0x0e, 0x16, 0xe7, 0x41, 0x73, 0xf8, 0xdb, 0xbb, 0xd1, 0xb8,
+0x51, 0xe0, 0xcb, 0x83, 0x3b, 0x73, 0x38, 0x6e, 0x77, 0x8a, 0x0f, 0x59, 0x63, 0x26, 0xcd, 0xa7,
+0x2a, 0xce, 0x54, 0xfb, 0xb8, 0xe2, 0xc0, 0x7c, 0x47, 0xce, 0x60, 0x7c, 0x3f, 0xb2, 0x73, 0xf2,
+0xc0, 0x19, 0xb6, 0x8a, 0x92, 0x87, 0x35, 0x0d, 0x90, 0x28, 0xa2, 0xe4, 0x15, 0x04, 0x63, 0x3e,
+0xba, 0xaf, 0xee, 0x7c, 0x5e, 0xcc, 0xa6, 0x8b, 0x50, 0xb2, 0x38, 0xf7, 0x41, 0x63, 0xca, 0xce,
+0xff, 0x69, 0x8f, 0x68, 0x0e, 0x95, 0x36, 0xe5, 0xcc, 0xb9, 0x8c, 0x09, 0xca, 0x4b, 0xdd, 0x31,
+0x90, 0x96, 0xc8, 0xcc, 0x1f, 0xfd, 0x56, 0x96, 0x34, 0xdb, 0x8e, 0x1c, 0xea, 0x2c, 0xbe, 0x85,
+0x2e, 0x63, 0xdd, 0xaa, 0xa9, 0x95, 0xd3, 0xfd, 0x29, 0x95, 0x13, 0xf0, 0xc8, 0x98, 0x93, 0xd9,
+0x2d, 0x16, 0x47, 0x90, 0x11, 0x83, 0xa2, 0x3a, 0x22, 0xa2, 0x28, 0x57, 0xa2, 0xeb, 0xfe, 0xc0,
+0x8c, 0x28, 0xa0, 0xa6, 0x7d, 0xe7, 0x2a, 0x42, 0x3b, 0x82, 0x80, 0x63, 0xa5, 0x63, 0x1f, 0x19,
+0xcc, 0x7c, 0xb2, 0x66, 0xa8, 0xc2, 0xd3, 0x6d, 0x37, 0x6f, 0xe2, 0x7e, 0x06, 0x51, 0xd9, 0x45,
+0x84, 0x1f, 0x12, 0xce, 0x24, 0x52, 0x64, 0x85, 0x0b, 0x48, 0x80, 0x4e, 0x87, 0xb1, 0x22, 0x22,
+0x30, 0xaa, 0xeb, 0xae, 0xbe, 0xe0, 0x02, 0xe0, 0x40, 0xe8, 0xb0, 0x42, 0x80, 0x03, 0x51, 0xaa,
+0xb4, 0x7e, 0xaa, 0x44, 0xd7, 0x43, 0x61, 0xf3, 0xa2, 0x6b, 0x16, 0x89, 0x49, 0xa4, 0xa3, 0xa4,
+0x2b, 0x8a, 0x02, 0xc4, 0x78, 0xf4, 0x68, 0x8a, 0xc1, 0xe4, 0x7a, 0x36, 0xb1, 0x6f, 0x1b, 0x96,
+0x1b, 0x77, 0x49, 0x8d, 0xd4, 0xc9, 0x06, 0x72, 0x8f, 0xcf, 0x53, 0xe3, 0xdc, 0x17, 0x85, 0x20,
+0x4a, 0xdc, 0x98, 0x27, 0xd3, 0x91, 0x26, 0x2b, 0x47, 0x1e, 0x69, 0x07, 0xaf, 0xde, 0xa2, 0xe4,
+0xe4, 0xd4, 0x6b, 0x0b, 0xb3, 0x5e, 0x7c, 0xd4, 0x24, 0x80, 0x47, 0x29, 0x69, 0x3b, 0x6e, 0xe8,
+0xac, 0xfd, 0x40, 0xeb, 0xd8, 0xed, 0x71, 0x71, 0x2b, 0xf2, 0xe8, 0x58, 0x1d, 0xeb, 0x41, 0x97,
+0x22, 0xc5, 0x1f, 0xd4, 0x39, 0xd0, 0x27, 0x8f, 0x87, 0xe3, 0x18, 0xf4, 0xe0, 0xa9, 0x46, 0x0d,
+0xf5, 0x74, 0x3a, 0x82, 0x2e, 0xd0, 0x6e, 0x2c, 0x91, 0xa3, 0x31, 0x5c, 0x3b, 0x46, 0xea, 0x7b,
+0x04, 0x10, 0x56, 0x5e, 0x80, 0x1d, 0xf5, 0xa5, 0x65, 0xe8, 0x82, 0xfc, 0xe2, 0x07, 0x8c, 0x62,
+0x45, 0xf5, 0x20, 0xde, 0x46, 0x70, 0x86, 0xa1, 0xbc, 0x93, 0xd3, 0x1e, 0x74, 0xa6, 0x6c, 0xb0,
+0x2c, 0xf7, 0x03, 0x0c, 0x88, 0x0c, 0xcb, 0xd4, 0x72, 0x53, 0x86, 0xbc, 0x60, 0x46, 0xf3, 0x98,
+0x6a, 0xc2, 0xf1, 0xbf, 0x43, 0xf9, 0x70, 0x20, 0x77, 0xca, 0x37, 0x41, 0x79, 0x55, 0x52, 0x63,
+0x8d, 0x5b, 0x12, 0x9f, 0xc5, 0x68, 0xc4, 0x88, 0x9d, 0xac, 0xf2, 0x30, 0xab, 0xb7, 0xa3, 0x31,
+0x97, 0x67, 0xad, 0x8f, 0x17, 0x0f, 0x6c, 0xc7, 0x73, 0xed, 0x24, 0x94, 0x6b, 0xc8, 0x83, 0x9a,
+0xd0, 0x9a, 0x37, 0x49, 0x04, 0xab, 0xb1, 0x16, 0xc8, 0x6c, 0x49, 0x49, 0x2d, 0xab, 0xa1, 0xd0,
+0x8c, 0x92, 0xf2, 0x41, 0x4a, 0x79, 0x21, 0x25, 0xdb, 0x63, 0xd7, 0xb6, 0x9c, 0xa7, 0x7e, 0x42,
+0x69, 0xfb, 0x3a, 0x63, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e,
+0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xdc, 0x2e, 0x1f, 0xd1, 0x61, 0x37, 0x79,
+0xe4, 0xab, 0xd5, 0xd5, 0xb3, 0x12, 0x71, 0x68, 0x3d, 0x6a, 0x68, 0x9c, 0x22, 0x30, 0x1f, 0x06,
+0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xdc, 0x2e, 0x1f, 0xd1, 0x61, 0x37,
+0x79, 0xe4, 0xab, 0xd5, 0xd5, 0xb3, 0x12, 0x71, 0x68, 0x3d, 0x6a, 0x68, 0x9c, 0x22, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
+0x01, 0x00, 0x91, 0xf0, 0x42, 0x02, 0x68, 0x40, 0xee, 0xc3, 0x68, 0xc0, 0x54, 0x2f, 0xdf, 0xec,
+0x62, 0xc3, 0xc3, 0x9e, 0x8a, 0xa0, 0x31, 0x28, 0xaa, 0x83, 0x8e, 0xa4, 0x56, 0x96, 0x12, 0x10,
+0x86, 0x56, 0xba, 0x97, 0x72, 0xd2, 0x54, 0x30, 0x7c, 0xad, 0x19, 0xd5, 0x1d, 0x68, 0x6f, 0xfb,
+0x14, 0x42, 0xd8, 0x8d, 0x0e, 0xf3, 0xb5, 0xd1, 0xa5, 0xe3, 0x02, 0x42, 0x5e, 0xdc, 0xe8, 0x46,
+0x58, 0x07, 0x35, 0x02, 0x30, 0xe0, 0xbc, 0x74, 0x4a, 0xc1, 0x43, 0x2a, 0xff, 0xdb, 0x1a, 0xd0,
+0xb0, 0xaf, 0x6c, 0xc3, 0xfd, 0xcb, 0xb3, 0xf5, 0x7f, 0x6d, 0x03, 0x2e, 0x59, 0x56, 0x9d, 0x2d,
+0x2d, 0x35, 0x8c, 0xb2, 0xd6, 0x43, 0x17, 0x2c, 0x92, 0x0a, 0xcb, 0x5d, 0xe8, 0x8c, 0x0f, 0x4b,
+0x70, 0x43, 0xd0, 0x82, 0xff, 0xa8, 0xcc, 0xbf, 0xa4, 0x94, 0xc0, 0xbe, 0x87, 0xbd, 0x8a, 0xe3,
+0x93, 0x7b, 0xc6, 0x8f, 0x9b, 0x16, 0x9d, 0x27, 0x65, 0xbc, 0x7a, 0xc5, 0x42, 0x82, 0x6c, 0x5c,
+0x07, 0xd0, 0xa9, 0xc1, 0x88, 0x60, 0x44, 0xe9, 0x98, 0x85, 0x16, 0x5f, 0xf8, 0x8f, 0xca, 0x01,
+0x10, 0xce, 0x25, 0xc3, 0xf9, 0x60, 0x1b, 0xa0, 0xc5, 0x97, 0xc3, 0xd3, 0x2c, 0x88, 0x31, 0xa2,
+0xbd, 0x30, 0xec, 0xd0, 0xd0, 0xc0, 0x12, 0xf1, 0xc1, 0x39, 0xe3, 0xe5, 0xf5, 0xf8, 0xd6, 0x4a,
+0xdd, 0x34, 0xcd, 0xfb, 0x6f, 0xc1, 0x4f, 0xe3, 0x00, 0x8b, 0x56, 0xe2, 0x92, 0xf7, 0x28, 0xb2,
+0x42, 0x77, 0x72, 0x23, 0x67, 0xc7, 0x3f, 0x11, 0x15, 0xb2, 0xc4, 0x03, 0x05, 0xbe, 0xbb, 0x11,
+0x7b, 0x0a, 0xbf, 0xa8, 0x6e, 0xe7, 0xff, 0x58, 0x43, 0xcf, 0x9b, 0x67, 0xa0, 0x80, 0x07, 0xb6,
+0x1d, 0xca, 0xad, 0x6d, 0xea, 0x41, 0x11, 0x7e, 0x2d, 0x74, 0x93, 0xfb, 0xc2, 0xbc, 0xbe, 0x51,
+0x44, 0xc5, 0xef, 0x68, 0x25, 0x27, 0x80, 0xe3, 0xc8, 0xa0, 0xd4, 0x12, 0xec, 0xd9, 0xa5, 0x37,
+0x1d, 0x37, 0x7c, 0xb4, 0x91, 0xca, 0xda, 0xd4, 0xb1, 0x96, 0x81, 0xef, 0x68, 0x5c, 0x76, 0x10,
+0x49, 0xaf, 0x7e, 0xa5, 0x37, 0x80, 0xb1, 0x1c, 0x52, 0xbd, 0x33, 0x81, 0x4c, 0x8f, 0xf9, 0xdd,
+0x65, 0xd9, 0x14, 0xcd, 0x8a, 0x25, 0x58, 0xf4, 0xe2, 0xc5, 0x83, 0xa5, 0x09, 0x90, 0xd4, 0x6c,
+0x14, 0x63, 0xb5, 0x40, 0xdf, 0xeb, 0xc0, 0xfc, 0xc4, 0x58, 0x7e, 0x0d, 0x14, 0x16, 0x87, 0x54,
+0x27, 0x6e, 0x56, 0xe4, 0x70, 0x84, 0xb8, 0x6c, 0x32, 0x12, 0x7e, 0x82, 0x31, 0x43, 0xbe, 0xd7,
+0xdd, 0x7c, 0xa1, 0xad, 0xae, 0xd6, 0xab, 0x20, 0x12, 0xef, 0x0a, 0xc3, 0x10, 0x8c, 0x49, 0x96,
+0x35, 0xdc, 0x0b, 0x75, 0x5e, 0xb1, 0x4f, 0xd5, 0x4f, 0x34, 0x0e, 0x11, 0x20, 0x07, 0x75, 0x43,
+0x45, 0xe9, 0xa3, 0x11, 0xda, 0xac, 0xa3, 0x99, 0xc2, 0xb6, 0x79, 0x27, 0xe2, 0xb9, 0xef, 0xc8,
+0xe2, 0xf6, 0x35, 0x29, 0x7a, 0x74, 0xfa, 0xc5, 0x7f, 0x82, 0x05, 0x62, 0xa6, 0x0a, 0xea, 0x68,
+0xb2, 0x79, 0x47, 0x06, 0x6e, 0xf2, 0x57, 0xa8, 0x15, 0x33, 0xc6, 0xf7, 0x78, 0x4a, 0x3d, 0x42,
+0x7b, 0x6b, 0x7e, 0xfe, 0xf7, 0x46, 0xea, 0xd1, 0xeb, 0x8e, 0xef, 0x88, 0x68, 0x5b, 0xe8, 0xc1,
+0xd9, 0x71, 0x7e, 0xfd, 0x64, 0xef, 0xff, 0x67, 0x47, 0x88, 0x58, 0x25, 0x2f, 0x3e, 0x86, 0x07,
+0xbd, 0xfb, 0xa8, 0xe5, 0x82, 0xa8, 0xac, 0xa5, 0xd3, 0x69, 0x43, 0xcd, 0x31, 0x88, 0x49, 0x84,
+0x53, 0x92, 0xc0, 0xb1, 0x39, 0x1b, 0x39, 0x83, 0x01, 0x30, 0xc4, 0xf2, 0xa9, 0xfa, 0xd0, 0x03,
+0xbd, 0x72, 0x37, 0x60, 0x56, 0x1f, 0x36, 0x7c, 0xbd, 0x39, 0x91, 0xf5, 0x6d, 0x0d, 0xbf, 0x7b,
+0xd7, 0x92, 0x30, 0x82, 0x02, 0x59, 0x30, 0x82, 0x01, 0xdf, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+0x10, 0x66, 0xf2, 0x3d, 0xaf, 0x87, 0xde, 0x8b, 0xb1, 0x4a, 0xea, 0x0c, 0x57, 0x31, 0x01, 0xc2,
+0xec, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x65, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1e, 0x30, 0x1c,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
+0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x36, 0x30, 0x34,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
+0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
+0x32, 0x30, 0x31, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x31, 0x38, 0x32, 0x33,
+0x30, 0x36, 0x34, 0x35, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x37, 0x31, 0x38, 0x32, 0x33, 0x31,
+0x36, 0x30, 0x34, 0x5a, 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x55, 0x53, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69,
+0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
+0x69, 0x6f, 0x6e, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, 0x4d, 0x69,
+0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
+0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x32, 0x30, 0x31, 0x37, 0x30, 0x76, 0x30, 0x10, 0x06,
+0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03,
+0x62, 0x00, 0x04, 0xd4, 0xbc, 0x3d, 0x02, 0x42, 0x75, 0x41, 0x13, 0x23, 0xcd, 0x80, 0x04, 0x86,
+0x02, 0x51, 0x2f, 0x6a, 0xa8, 0x81, 0x62, 0x0b, 0x65, 0xcc, 0xf6, 0xca, 0x9d, 0x1e, 0x6f, 0x4a,
+0x66, 0x51, 0xa2, 0x03, 0xd9, 0x9d, 0x91, 0xfa, 0xb6, 0x16, 0xb1, 0x8c, 0x6e, 0xde, 0x7c, 0xcd,
+0xdb, 0x79, 0xa6, 0x2f, 0xce, 0xbb, 0xce, 0x71, 0x2f, 0xe5, 0xa5, 0xab, 0x28, 0xec, 0x63, 0x04,
+0x66, 0x99, 0xf8, 0xfa, 0xf2, 0x93, 0x10, 0x05, 0xe1, 0x81, 0x28, 0x42, 0xe3, 0xc6, 0x68, 0xf4,
+0xe6, 0x1b, 0x84, 0x60, 0x4a, 0x89, 0xaf, 0xed, 0x79, 0x0f, 0x3b, 0xce, 0xf1, 0xf6, 0x44, 0xf5,
+0x01, 0x78, 0xc0, 0xa3, 0x54, 0x30, 0x52, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+0x16, 0x04, 0x14, 0xc8, 0xcb, 0x99, 0x72, 0x70, 0x52, 0x0c, 0xf8, 0xe6, 0xbe, 0xb2, 0x04, 0x57,
+0x29, 0x2a, 0xcf, 0x42, 0x10, 0xed, 0x35, 0x30, 0x10, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01,
+0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
+0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x30, 0x58, 0xf2, 0x4d, 0xea,
+0x0c, 0xf9, 0x5f, 0x5e, 0xee, 0x60, 0x29, 0xcb, 0x3a, 0xf2, 0xdb, 0xd6, 0x32, 0x84, 0x19, 0x3f,
+0x7c, 0xd5, 0x2f, 0xc2, 0xb1, 0xcc, 0x93, 0xae, 0x50, 0xbb, 0x09, 0x32, 0xc6, 0xc6, 0xed, 0x7e,
+0xc9, 0x36, 0x94, 0x12, 0xe4, 0x68, 0x85, 0x06, 0xa2, 0x1b, 0xd0, 0x2f, 0x02, 0x31, 0x00, 0x99,
+0xe9, 0x16, 0xb4, 0x0e, 0xfa, 0x56, 0x48, 0xd4, 0xa4, 0x30, 0x16, 0x91, 0x78, 0xdb, 0x54, 0x8c,
+0x65, 0x01, 0x8a, 0xe7, 0x50, 0x66, 0xc2, 0x31, 0xb7, 0x39, 0xba, 0xb8, 0x1a, 0x22, 0x07, 0x4e,
+0xfc, 0x6b, 0x54, 0x16, 0x20, 0xff, 0x2b, 0xb5, 0xe7, 0x4c, 0x0c, 0x4d, 0xa6, 0x4f, 0x73, 0x30,
+0x82, 0x05, 0xa8, 0x30, 0x82, 0x03, 0x90, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x1e, 0xd3,
+0x97, 0x09, 0x5f, 0xd8, 0xb4, 0xb3, 0x47, 0x70, 0x1e, 0xaa, 0xbe, 0x7f, 0x45, 0xb3, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x30, 0x65, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1e, 0x30, 0x1c,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
+0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x36, 0x30, 0x34,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
+0x20, 0x52, 0x53, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
+0x32, 0x30, 0x31, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x31, 0x38, 0x32, 0x32,
+0x35, 0x31, 0x32, 0x32, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x37, 0x31, 0x38, 0x32, 0x33, 0x30,
+0x30, 0x32, 0x33, 0x5a, 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x55, 0x53, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69,
+0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
+0x69, 0x6f, 0x6e, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, 0x4d, 0x69,
+0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x52, 0x53, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
+0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x32, 0x30, 0x31, 0x37, 0x30, 0x82, 0x02, 0x22, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
+0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xca, 0x5b, 0xbe, 0x94,
+0x33, 0x8c, 0x29, 0x95, 0x91, 0x16, 0x0a, 0x95, 0xbd, 0x47, 0x62, 0xc1, 0x89, 0xf3, 0x99, 0x36,
+0xdf, 0x46, 0x90, 0xc9, 0xa5, 0xed, 0x78, 0x6a, 0x6f, 0x47, 0x91, 0x68, 0xf8, 0x27, 0x67, 0x50,
+0x33, 0x1d, 0xa1, 0xa6, 0xfb, 0xe0, 0xe5, 0x43, 0xa3, 0x84, 0x02, 0x57, 0x01, 0x5d, 0x9c, 0x48,
+0x40, 0x82, 0x53, 0x10, 0xbc, 0xbf, 0xc7, 0x3b, 0x68, 0x90, 0xb6, 0x82, 0x2d, 0xe5, 0xf4, 0x65,
+0xd0, 0xcc, 0x6d, 0x19, 0xcc, 0x95, 0xf9, 0x7b, 0xac, 0x4a, 0x94, 0xad, 0x0e, 0xde, 0x4b, 0x43,
+0x1d, 0x87, 0x07, 0x92, 0x13, 0x90, 0x80, 0x83, 0x64, 0x35, 0x39, 0x04, 0xfc, 0xe5, 0xe9, 0x6c,
+0xb3, 0xb6, 0x1f, 0x50, 0x94, 0x38, 0x65, 0x50, 0x5c, 0x17, 0x46, 0xb9, 0xb6, 0x85, 0xb5, 0x1c,
+0xb5, 0x17, 0xe8, 0xd6, 0x45, 0x9d, 0xd8, 0xb2, 0x26, 0xb0, 0xca, 0xc4, 0x70, 0x4a, 0xae, 0x60,
+0xa4, 0xdd, 0xb3, 0xd9, 0xec, 0xfc, 0x3b, 0xd5, 0x57, 0x72, 0xbc, 0x3f, 0xc8, 0xc9, 0xb2, 0xde,
+0x4b, 0x6b, 0xf8, 0x23, 0x6c, 0x03, 0xc0, 0x05, 0xbd, 0x95, 0xc7, 0xcd, 0x73, 0x3b, 0x66, 0x80,
+0x64, 0xe3, 0x1a, 0xac, 0x2e, 0xf9, 0x47, 0x05, 0xf2, 0x06, 0xb6, 0x9b, 0x73, 0xf5, 0x78, 0x33,
+0x5b, 0xc7, 0xa1, 0xfb, 0x27, 0x2a, 0xa1, 0xb4, 0x9a, 0x91, 0x8c, 0x91, 0xd3, 0x3a, 0x82, 0x3e,
+0x76, 0x40, 0xb4, 0xcd, 0x52, 0x61, 0x51, 0x70, 0x28, 0x3f, 0xc5, 0xc5, 0x5a, 0xf2, 0xc9, 0x8c,
+0x49, 0xbb, 0x14, 0x5b, 0x4d, 0xc8, 0xff, 0x67, 0x4d, 0x4c, 0x12, 0x96, 0xad, 0xf5, 0xfe, 0x78,
+0xa8, 0x97, 0x87, 0xd7, 0xfd, 0x5e, 0x20, 0x80, 0xdc, 0xa1, 0x4b, 0x22, 0xfb, 0xd4, 0x89, 0xad,
+0xba, 0xce, 0x47, 0x97, 0x47, 0x55, 0x7b, 0x8f, 0x45, 0xc8, 0x67, 0x28, 0x84, 0x95, 0x1c, 0x68,
+0x30, 0xef, 0xef, 0x49, 0xe0, 0x35, 0x7b, 0x64, 0xe7, 0x98, 0xb0, 0x94, 0xda, 0x4d, 0x85, 0x3b,
+0x3e, 0x55, 0xc4, 0x28, 0xaf, 0x57, 0xf3, 0x9e, 0x13, 0xdb, 0x46, 0x27, 0x9f, 0x1e, 0xa2, 0x5e,
+0x44, 0x83, 0xa4, 0xa5, 0xca, 0xd5, 0x13, 0xb3, 0x4b, 0x3f, 0xc4, 0xe3, 0xc2, 0xe6, 0x86, 0x61,
+0xa4, 0x52, 0x30, 0xb9, 0x7a, 0x20, 0x4f, 0x6f, 0x0f, 0x38, 0x53, 0xcb, 0x33, 0x0c, 0x13, 0x2b,
+0x8f, 0xd6, 0x9a, 0xbd, 0x2a, 0xc8, 0x2d, 0xb1, 0x1c, 0x7d, 0x4b, 0x51, 0xca, 0x47, 0xd1, 0x48,
+0x27, 0x72, 0x5d, 0x87, 0xeb, 0xd5, 0x45, 0xe6, 0x48, 0x65, 0x9d, 0xaf, 0x52, 0x90, 0xba, 0x5b,
+0xa2, 0x18, 0x65, 0x57, 0x12, 0x9f, 0x68, 0xb9, 0xd4, 0x15, 0x6b, 0x94, 0xc4, 0x69, 0x22, 0x98,
+0xf4, 0x33, 0xe0, 0xed, 0xf9, 0x51, 0x8e, 0x41, 0x50, 0xc9, 0x34, 0x4f, 0x76, 0x90, 0xac, 0xfc,
+0x38, 0xc1, 0xd8, 0xe1, 0x7b, 0xb9, 0xe3, 0xe3, 0x94, 0xe1, 0x46, 0x69, 0xcb, 0x0e, 0x0a, 0x50,
+0x6b, 0x13, 0xba, 0xac, 0x0f, 0x37, 0x5a, 0xb7, 0x12, 0xb5, 0x90, 0x81, 0x1e, 0x56, 0xae, 0x57,
+0x22, 0x86, 0xd9, 0xc9, 0xd2, 0xd1, 0xd7, 0x51, 0xe3, 0xab, 0x3b, 0xc6, 0x55, 0xfd, 0x1e, 0x0e,
+0xd3, 0x74, 0x0a, 0xd1, 0xda, 0xaa, 0xea, 0x69, 0xb8, 0x97, 0x28, 0x8f, 0x48, 0xc4, 0x07, 0xf8,
+0x52, 0x43, 0x3a, 0xf4, 0xca, 0x55, 0x35, 0x2c, 0xb0, 0xa6, 0x6a, 0xc0, 0x9c, 0xf9, 0xf2, 0x81,
+0xe1, 0x12, 0x6a, 0xc0, 0x45, 0xd9, 0x67, 0xb3, 0xce, 0xff, 0x23, 0xa2, 0x89, 0x0a, 0x54, 0xd4,
+0x14, 0xb9, 0x2a, 0xa8, 0xd7, 0xec, 0xf9, 0xab, 0xcd, 0x25, 0x58, 0x32, 0x79, 0x8f, 0x90, 0x5b,
+0x98, 0x39, 0xc4, 0x08, 0x06, 0xc1, 0xac, 0x7f, 0x0e, 0x3d, 0x00, 0xa5, 0x02, 0x03, 0x01, 0x00,
+0x01, 0xa3, 0x54, 0x30, 0x52, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+0x14, 0x09, 0xcb, 0x59, 0x7f, 0x86, 0xb2, 0x70, 0x8f, 0x1a, 0xc3, 0x39, 0xe3, 0xc0, 0xd9, 0xe9,
+0xbf, 0xbb, 0x4d, 0xb2, 0x23, 0x30, 0x10, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37,
+0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0xac, 0xaf, 0x3e, 0x5d, 0xc2,
+0x11, 0x96, 0x89, 0x8e, 0xa3, 0xe7, 0x92, 0xd6, 0x97, 0x15, 0xb8, 0x13, 0xa2, 0xa6, 0x42, 0x2e,
+0x02, 0xcd, 0x16, 0x05, 0x59, 0x27, 0xca, 0x20, 0xe8, 0xba, 0xb8, 0xe8, 0x1a, 0xec, 0x4d, 0xa8,
+0x97, 0x56, 0xae, 0x65, 0x43, 0xb1, 0x8f, 0x00, 0x9b, 0x52, 0xcd, 0x55, 0xcd, 0x53, 0x39, 0x6d,
+0x62, 0x4c, 0x8b, 0x0d, 0x5b, 0x7c, 0x2e, 0x44, 0xbf, 0x83, 0x10, 0x8f, 0xf3, 0x53, 0x82, 0x80,
+0xc3, 0x4f, 0x3a, 0xc7, 0x6e, 0x11, 0x3f, 0xe6, 0xe3, 0x16, 0x91, 0x84, 0xfb, 0x6d, 0x84, 0x7f,
+0x34, 0x74, 0xad, 0x89, 0xa7, 0xce, 0xb9, 0xd7, 0xd7, 0x9f, 0x84, 0x64, 0x92, 0xbe, 0x95, 0xa1,
+0xad, 0x09, 0x53, 0x33, 0xdd, 0xee, 0x0a, 0xea, 0x4a, 0x51, 0x8e, 0x6f, 0x55, 0xab, 0xba, 0xb5,
+0x94, 0x46, 0xae, 0x8c, 0x7f, 0xd8, 0xa2, 0x50, 0x25, 0x65, 0x60, 0x80, 0x46, 0xdb, 0x33, 0x04,
+0xae, 0x6c, 0xb5, 0x98, 0x74, 0x54, 0x25, 0xdc, 0x93, 0xe4, 0xf8, 0xe3, 0x55, 0x15, 0x3d, 0xb8,
+0x6d, 0xc3, 0x0a, 0xa4, 0x12, 0xc1, 0x69, 0x85, 0x6e, 0xdf, 0x64, 0xf1, 0x53, 0x99, 0xe1, 0x4a,
+0x75, 0x20, 0x9d, 0x95, 0x0f, 0xe4, 0xd6, 0xdc, 0x03, 0xf1, 0x59, 0x18, 0xe8, 0x47, 0x89, 0xb2,
+0x57, 0x5a, 0x94, 0xb6, 0xa9, 0xd8, 0x17, 0x2b, 0x17, 0x49, 0xe5, 0x76, 0xcb, 0xc1, 0x56, 0x99,
+0x3a, 0x37, 0xb1, 0xff, 0x69, 0x2c, 0x91, 0x91, 0x93, 0xe1, 0xdf, 0x4c, 0xa3, 0x37, 0x76, 0x4d,
+0xa1, 0x9f, 0xf8, 0x6d, 0x1e, 0x1d, 0xd3, 0xfa, 0xec, 0xfb, 0xf4, 0x45, 0x1d, 0x13, 0x6d, 0xcf,
+0xf7, 0x59, 0xe5, 0x22, 0x27, 0x72, 0x2b, 0x86, 0xf3, 0x57, 0xbb, 0x30, 0xed, 0x24, 0x4d, 0xdc,
+0x7d, 0x56, 0xbb, 0xa3, 0xb3, 0xf8, 0x34, 0x79, 0x89, 0xc1, 0xe0, 0xf2, 0x02, 0x61, 0xf7, 0xa6,
+0xfc, 0x0f, 0xbb, 0x1c, 0x17, 0x0b, 0xae, 0x41, 0xd9, 0x7c, 0xbd, 0x27, 0xa3, 0xfd, 0x2e, 0x3a,
+0xd1, 0x93, 0x94, 0xb1, 0x73, 0x1d, 0x24, 0x8b, 0xaf, 0x5b, 0x20, 0x89, 0xad, 0xb7, 0x67, 0x66,
+0x79, 0xf5, 0x3a, 0xc6, 0xa6, 0x96, 0x33, 0xfe, 0x53, 0x92, 0xc8, 0x46, 0xb1, 0x11, 0x91, 0xc6,
+0x99, 0x7f, 0x8f, 0xc9, 0xd6, 0x66, 0x31, 0x20, 0x41, 0x10, 0x87, 0x2d, 0x0c, 0xd6, 0xc1, 0xaf,
+0x34, 0x98, 0xca, 0x64, 0x83, 0xfb, 0x13, 0x57, 0xd1, 0xc1, 0xf0, 0x3c, 0x7a, 0x8c, 0xa5, 0xc1,
+0xfd, 0x95, 0x21, 0xa0, 0x71, 0xc1, 0x93, 0x67, 0x71, 0x12, 0xea, 0x8f, 0x88, 0x0a, 0x69, 0x19,
+0x64, 0x99, 0x23, 0x56, 0xfb, 0xac, 0x2a, 0x2e, 0x70, 0xbe, 0x66, 0xc4, 0x0c, 0x84, 0xef, 0xe5,
+0x8b, 0xf3, 0x93, 0x01, 0xf8, 0x6a, 0x90, 0x93, 0x67, 0x4b, 0xb2, 0x68, 0xa3, 0xb5, 0x62, 0x8f,
+0xe9, 0x3f, 0x8c, 0x7a, 0x3b, 0x5e, 0x0f, 0xe7, 0x8c, 0xb8, 0xc6, 0x7c, 0xef, 0x37, 0xfd, 0x74,
+0xe2, 0xc8, 0x4f, 0x33, 0x72, 0xe1, 0x94, 0x39, 0x6d, 0xbd, 0x12, 0xaf, 0xbe, 0x0c, 0x4e, 0x70,
+0x7c, 0x1b, 0x6f, 0x8d, 0xb3, 0x32, 0x93, 0x73, 0x44, 0x16, 0x6d, 0xe8, 0xf4, 0xf7, 0xe0, 0x95,
+0x80, 0x8f, 0x96, 0x5d, 0x38, 0xa4, 0xf4, 0xab, 0xde, 0x0a, 0x30, 0x87, 0x93, 0xd8, 0x4d, 0x00,
+0x71, 0x62, 0x45, 0x27, 0x4b, 0x3a, 0x42, 0x84, 0x5b, 0x7f, 0x65, 0xb7, 0x67, 0x34, 0x52, 0x2d,
+0x9c, 0x16, 0x6b, 0xaa, 0xa8, 0xd8, 0x7b, 0xa3, 0x42, 0x4c, 0x71, 0xc7, 0x0c, 0xca, 0x3e, 0x83,
+0xe4, 0xa6, 0xef, 0xb7, 0x01, 0x30, 0x5e, 0x51, 0xa3, 0x79, 0xf5, 0x70, 0x69, 0xa6, 0x41, 0x44,
+0x0f, 0x86, 0xb0, 0x2c, 0x91, 0xc6, 0x3d, 0xea, 0xae, 0x0f, 0x84, 0x30, 0x82, 0x05, 0xef, 0x30,
+0x82, 0x03, 0xd7, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x0d, 0xd3, 0xe3, 0xbc, 0x6c, 0xf9,
+0x6b, 0xb1, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+0x00, 0x30, 0x81, 0x84, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13, 0x09, 0x47,
+0x36, 0x33, 0x32, 0x38, 0x37, 0x35, 0x31, 0x30, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e,
+0x41, 0x4e, 0x46, 0x20, 0x41, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x64, 0x20, 0x64, 0x65,
+0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x6e, 0x31, 0x14,
+0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0b, 0x41, 0x4e, 0x46, 0x20, 0x43, 0x41, 0x20,
+0x52, 0x61, 0x69, 0x7a, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x41,
+0x4e, 0x46, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x30, 0x39,
+0x30, 0x34, 0x31, 0x30, 0x30, 0x30, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x30, 0x38, 0x33,
+0x30, 0x31, 0x30, 0x30, 0x30, 0x33, 0x38, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x12, 0x30, 0x10, 0x06,
+0x03, 0x55, 0x04, 0x05, 0x13, 0x09, 0x47, 0x36, 0x33, 0x32, 0x38, 0x37, 0x35, 0x31, 0x30, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x27, 0x30, 0x25,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1e, 0x41, 0x4e, 0x46, 0x20, 0x41, 0x75, 0x74, 0x6f, 0x72,
+0x69, 0x64, 0x61, 0x64, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+0x61, 0x63, 0x69, 0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0b,
+0x41, 0x4e, 0x46, 0x20, 0x43, 0x41, 0x20, 0x52, 0x61, 0x69, 0x7a, 0x31, 0x22, 0x30, 0x20, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x41, 0x4e, 0x46, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65,
+0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30,
+0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00,
+0xdb, 0xeb, 0x6b, 0x2b, 0xe6, 0x64, 0x54, 0x95, 0x82, 0x90, 0xa3, 0x72, 0xa4, 0x19, 0x01, 0x9d,
+0x9c, 0x0b, 0x81, 0x5f, 0x73, 0x49, 0xba, 0xa7, 0xac, 0xf3, 0x04, 0x4e, 0x7b, 0x96, 0x0b, 0xec,
+0x11, 0xe0, 0x5b, 0xa6, 0x1c, 0xce, 0x1b, 0xd2, 0x0d, 0x83, 0x1c, 0x2b, 0xb8, 0x9e, 0x1d, 0x7e,
+0x45, 0x32, 0x60, 0x0f, 0x07, 0xe9, 0x77, 0x58, 0x7e, 0x9f, 0x6a, 0xc8, 0x61, 0x4e, 0xb6, 0x26,
+0xc1, 0x4c, 0x8d, 0xff, 0x4c, 0xef, 0x34, 0xb2, 0x1f, 0x65, 0xd8, 0xb9, 0x78, 0xf5, 0xad, 0xa9,
+0x71, 0xb9, 0xef, 0x4f, 0x58, 0x1d, 0xa5, 0xde, 0x74, 0x20, 0x97, 0xa1, 0xed, 0x68, 0x4c, 0xde,
+0x92, 0x17, 0x4b, 0xbc, 0xab, 0xff, 0x65, 0x9a, 0x9e, 0xfb, 0x47, 0xd9, 0x57, 0x72, 0xf3, 0x09,
+0xa1, 0xae, 0x76, 0x44, 0x13, 0x6e, 0x9c, 0x2d, 0x44, 0x39, 0xbc, 0xf9, 0xc7, 0x3b, 0xa4, 0x58,
+0x3d, 0x41, 0xbd, 0xb4, 0xc2, 0x49, 0xa3, 0xc8, 0x0d, 0xd2, 0x97, 0x2f, 0x07, 0x65, 0x52, 0x00,
+0xa7, 0x6e, 0xc8, 0xaf, 0x68, 0xec, 0xf4, 0x14, 0x96, 0xb6, 0x57, 0x1f, 0x56, 0xc3, 0x39, 0x9f,
+0x2b, 0x6d, 0xe4, 0xf3, 0x3e, 0xf6, 0x35, 0x64, 0xda, 0x0c, 0x1c, 0xa1, 0x84, 0x4b, 0x2f, 0x4b,
+0x4b, 0xe2, 0x2c, 0x24, 0x9d, 0x6d, 0x93, 0x40, 0xeb, 0xb5, 0x23, 0x8e, 0x32, 0xca, 0x6f, 0x45,
+0xd3, 0xa8, 0x89, 0x7b, 0x1e, 0xcf, 0x1e, 0xfa, 0x5b, 0x43, 0x8b, 0xcd, 0xcd, 0xa8, 0x0f, 0x6a,
+0xca, 0x0c, 0x5e, 0xb9, 0x9e, 0x47, 0x8f, 0xf0, 0xd9, 0xb6, 0x0a, 0x0b, 0x58, 0x65, 0x17, 0x33,
+0xb9, 0x23, 0xe4, 0x77, 0x19, 0x7d, 0xcb, 0x4a, 0x2e, 0x92, 0x7b, 0x4f, 0x2f, 0x10, 0x77, 0xb1,
+0x8d, 0x2f, 0x68, 0x9c, 0x62, 0xcc, 0xe0, 0x50, 0xf8, 0xec, 0x91, 0xa7, 0x54, 0x4c, 0x57, 0x09,
+0xd5, 0x76, 0x63, 0xc5, 0xe8, 0x65, 0x1e, 0xee, 0x6d, 0x6a, 0xcf, 0x09, 0x9d, 0xfa, 0x7c, 0x4f,
+0xad, 0x60, 0x08, 0xfd, 0x56, 0x99, 0x0f, 0x15, 0x2c, 0x7b, 0xa9, 0x80, 0xab, 0x8c, 0x61, 0x8f,
+0x4a, 0x07, 0x76, 0x42, 0xde, 0x3d, 0xf4, 0xdd, 0xb2, 0x24, 0x33, 0x5b, 0xb8, 0xb5, 0xa3, 0x44,
+0xc9, 0xac, 0x7f, 0x77, 0x3c, 0x1d, 0x23, 0xec, 0x82, 0xa9, 0xa6, 0xe2, 0xc8, 0x06, 0x4c, 0x02,
+0xfe, 0xac, 0x5c, 0x99, 0x99, 0x0b, 0x2f, 0x10, 0x8a, 0xa6, 0xf4, 0x7f, 0xd5, 0x87, 0x74, 0x0d,
+0x59, 0x49, 0x45, 0xf6, 0xf0, 0x71, 0x5c, 0x39, 0x29, 0xd6, 0xbf, 0x4a, 0x23, 0x8b, 0xf5, 0x5f,
+0x01, 0x63, 0xd2, 0x87, 0x73, 0x28, 0xb5, 0x4b, 0x0a, 0xf5, 0xf8, 0xab, 0x82, 0x2c, 0x7e, 0x73,
+0x25, 0x32, 0x1d, 0x0b, 0x63, 0x0a, 0x17, 0x81, 0x00, 0xff, 0xb6, 0x76, 0x5e, 0xe7, 0xb4, 0xb1,
+0x40, 0xca, 0x21, 0xbb, 0xd5, 0x80, 0x51, 0xe5, 0x48, 0x52, 0x67, 0x2c, 0xd2, 0x61, 0x89, 0x07,
+0x0d, 0x0f, 0xce, 0x42, 0x77, 0xc0, 0x44, 0x73, 0x9c, 0x44, 0x50, 0xa0, 0xdb, 0x10, 0x0a, 0x2d,
+0x95, 0x1c, 0x81, 0xaf, 0xe4, 0x1c, 0xe5, 0x14, 0x1e, 0xf1, 0x36, 0x41, 0x01, 0x02, 0x2f, 0x7d,
+0x73, 0xa7, 0xde, 0x42, 0xcc, 0x4c, 0xe9, 0x89, 0x0d, 0x56, 0xf7, 0x9f, 0x91, 0xd4, 0x03, 0xc6,
+0x6c, 0xc9, 0x8f, 0xdb, 0xd8, 0x1c, 0xe0, 0x40, 0x98, 0x5d, 0x66, 0x99, 0x98, 0x80, 0x6e, 0x2d,
+0xff, 0x01, 0xc5, 0xce, 0xcb, 0x46, 0x1f, 0xac, 0x02, 0xc6, 0x43, 0xe6, 0xae, 0xa2, 0x84, 0x3c,
+0xc5, 0x4e, 0x1e, 0x3d, 0x6d, 0xc9, 0x14, 0x4c, 0xe3, 0x2e, 0x41, 0xbb, 0xca, 0x39, 0xbf, 0x36,
+0x3c, 0x2a, 0x19, 0xaa, 0x41, 0x87, 0x4e, 0xa5, 0xce, 0x4b, 0x32, 0x79, 0xdd, 0x90, 0x49, 0x7f,
+0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
+0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x9c, 0x5f, 0xd0, 0x6c, 0x63, 0xa3, 0x5f, 0x93, 0xca, 0x93,
+0x98, 0x08, 0xad, 0x8c, 0x87, 0xa5, 0x2c, 0x5c, 0xc1, 0x37, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+0x0e, 0x04, 0x16, 0x04, 0x14, 0x9c, 0x5f, 0xd0, 0x6c, 0x63, 0xa3, 0x5f, 0x93, 0xca, 0x93, 0x98,
+0x08, 0xad, 0x8c, 0x87, 0xa5, 0x2c, 0x5c, 0xc1, 0x37, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13,
+0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x4e, 0x1e,
+0xb9, 0x8a, 0xc6, 0xa0, 0x98, 0x3f, 0x6e, 0xc3, 0x69, 0xc0, 0x6a, 0x5c, 0x49, 0x52, 0xac, 0xcb,
+0x2b, 0x5d, 0x78, 0x38, 0xc1, 0xd5, 0x54, 0x84, 0x9f, 0x93, 0xf0, 0x87, 0x19, 0x3d, 0x2c, 0x66,
+0x89, 0xeb, 0x0d, 0x42, 0xfc, 0xcc, 0xf0, 0x75, 0x85, 0x3f, 0x8b, 0xf4, 0x80, 0x5d, 0x79, 0xe5,
+0x17, 0x67, 0xbd, 0x35, 0x82, 0xe2, 0xf2, 0x3c, 0x8e, 0x7d, 0x5b, 0x36, 0xcb, 0x5a, 0x80, 0x00,
+0x29, 0xf2, 0xce, 0x2b, 0x2c, 0xf1, 0x8f, 0xaa, 0x6d, 0x05, 0x93, 0x6c, 0x72, 0xc7, 0x56, 0xeb,
+0xdf, 0x50, 0x23, 0x28, 0xe5, 0x45, 0x10, 0x3d, 0xe8, 0x67, 0xa3, 0xaf, 0x0e, 0x55, 0x0f, 0x90,
+0x09, 0x62, 0xef, 0x4b, 0x59, 0xa2, 0xf6, 0x53, 0xf1, 0xc0, 0x35, 0xe4, 0x2f, 0xc1, 0x24, 0xbd,
+0x79, 0x2f, 0x4e, 0x20, 0x22, 0x3b, 0xfd, 0x1a, 0x20, 0xb0, 0xa4, 0x0e, 0x2c, 0x70, 0xed, 0x74,
+0x3f, 0xb8, 0x13, 0x95, 0x06, 0x51, 0xc8, 0xe8, 0x87, 0x26, 0xca, 0xa4, 0x5b, 0x6a, 0x16, 0x21,
+0x92, 0xdd, 0x73, 0x60, 0x9e, 0x10, 0x18, 0xde, 0x3c, 0x81, 0xea, 0xe8, 0x18, 0xc3, 0x7c, 0x89,
+0xf2, 0x8b, 0x50, 0x3e, 0xbd, 0x11, 0xe2, 0x15, 0x03, 0xa8, 0x36, 0x7d, 0x33, 0x01, 0x6c, 0x48,
+0x15, 0xd7, 0x88, 0x90, 0x99, 0x04, 0xc5, 0xcc, 0xe6, 0x07, 0xf4, 0xbc, 0xf4, 0x90, 0xed, 0x13,
+0xe2, 0xea, 0x8b, 0xc3, 0x8f, 0xa3, 0x33, 0x0f, 0xc1, 0x29, 0x4c, 0x13, 0x4e, 0xda, 0x15, 0x56,
+0x71, 0x73, 0x72, 0x82, 0x50, 0xf6, 0x9a, 0x33, 0x7c, 0xa2, 0xb1, 0xa8, 0x1a, 0x34, 0x74, 0x65,
+0x5c, 0xce, 0xd1, 0xeb, 0xab, 0x53, 0xe0, 0x1a, 0x80, 0xd8, 0xea, 0x3a, 0x49, 0xe4, 0x26, 0x30,
+0x9b, 0xe5, 0x1c, 0x8a, 0xa8, 0xa9, 0x15, 0x32, 0x86, 0x99, 0x92, 0x0a, 0x10, 0x23, 0x56, 0x12,
+0xe0, 0xf6, 0xce, 0x4c, 0xe2, 0xbb, 0xbe, 0xdb, 0x8d, 0x92, 0x73, 0x01, 0x66, 0x2f, 0x62, 0x3e,
+0xb2, 0x72, 0x27, 0x45, 0x36, 0xed, 0x4d, 0x56, 0xe3, 0x97, 0x99, 0xff, 0x3a, 0x35, 0x3e, 0xa5,
+0x54, 0x4a, 0x52, 0x59, 0x4b, 0x60, 0xdb, 0xee, 0xfe, 0x78, 0x11, 0x7f, 0x4a, 0xdc, 0x14, 0x79,
+0x60, 0xb6, 0x6b, 0x64, 0x03, 0xdb, 0x15, 0x83, 0xe1, 0xa2, 0xbe, 0xf6, 0x23, 0x97, 0x50, 0xf0,
+0x09, 0x33, 0x36, 0xa7, 0x71, 0x96, 0x25, 0xf3, 0xb9, 0x42, 0x7d, 0xdb, 0x38, 0x3f, 0x2c, 0x58,
+0xac, 0xe8, 0x42, 0xe1, 0x0e, 0xd8, 0xd3, 0x3b, 0x4c, 0x2e, 0x82, 0xe9, 0x83, 0x2e, 0x6b, 0x31,
+0xd9, 0xdd, 0x47, 0x86, 0x4f, 0x6d, 0x97, 0x91, 0x2e, 0x4f, 0xe2, 0x28, 0x71, 0x35, 0x16, 0xd1,
+0xf2, 0x73, 0xfe, 0x25, 0x2b, 0x07, 0x47, 0x24, 0x63, 0x27, 0xc8, 0xf8, 0xf6, 0xd9, 0x6b, 0xfc,
+0x12, 0x31, 0x56, 0x08, 0xc0, 0x53, 0x42, 0xaf, 0x9c, 0xd0, 0x33, 0x7e, 0xfc, 0x06, 0xf0, 0x31,
+0x44, 0x03, 0x14, 0xf1, 0x58, 0xea, 0xf2, 0x6a, 0x0d, 0xa9, 0x11, 0xb2, 0x83, 0xbe, 0xc5, 0x1a,
+0xbf, 0x07, 0xea, 0x59, 0xdc, 0xa3, 0x88, 0x35, 0xef, 0x9c, 0x76, 0x32, 0x3c, 0x4d, 0x06, 0x22,
+0xce, 0x15, 0xe5, 0xdd, 0x9e, 0xd8, 0x8f, 0xda, 0xde, 0xd2, 0xc4, 0x39, 0xe5, 0x17, 0x81, 0xcf,
+0x38, 0x47, 0xeb, 0x7f, 0x88, 0x6d, 0x59, 0x1b, 0xdf, 0x9f, 0x42, 0x14, 0xae, 0x7e, 0xcf, 0xa8,
+0xb0, 0x66, 0x65, 0xda, 0x37, 0xaf, 0x9f, 0xaa, 0x3d, 0xea, 0x28, 0xb6, 0xde, 0xd5, 0x31, 0x58,
+0x16, 0x82, 0x5b, 0xea, 0xbb, 0x19, 0x75, 0x02, 0x73, 0x1a, 0xca, 0x48, 0x1a, 0x21, 0x93, 0x90,
+0x0a, 0x8e, 0x93, 0x84, 0xa7, 0x7d, 0x3b, 0x23, 0x18, 0x92, 0x89, 0xa0, 0x8d, 0xac, 0x30, 0x82,
+0x02, 0x65, 0x30, 0x82, 0x01, 0xeb, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x78, 0x8f, 0x27,
+0x5c, 0x81, 0x12, 0x52, 0x20, 0xa5, 0x04, 0xd0, 0x2d, 0xdd, 0xba, 0x73, 0xf4, 0x30, 0x0a, 0x06,
+0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x4c, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x18, 0x41, 0x73, 0x73, 0x65, 0x63, 0x6f, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x53,
+0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06,
+0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x74, 0x79, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x43,
+0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x45, 0x43, 0x2d, 0x33, 0x38, 0x34, 0x20, 0x43, 0x41, 0x30,
+0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x33, 0x32, 0x36, 0x30, 0x37, 0x32, 0x34, 0x35, 0x34, 0x5a,
+0x17, 0x0d, 0x34, 0x33, 0x30, 0x33, 0x32, 0x36, 0x30, 0x37, 0x32, 0x34, 0x35, 0x34, 0x5a, 0x30,
+0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x4c, 0x31, 0x21,
+0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x41, 0x73, 0x73, 0x65, 0x63, 0x6f, 0x20,
+0x44, 0x61, 0x74, 0x61, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e, 0x41,
+0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x43, 0x65, 0x72, 0x74,
+0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x13, 0x10, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x45, 0x43, 0x2d, 0x33,
+0x38, 0x34, 0x20, 0x43, 0x41, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xc4, 0x28, 0x8e,
+0xab, 0x18, 0x5b, 0x6a, 0xbe, 0x6e, 0x64, 0x37, 0x63, 0xe4, 0xcd, 0xec, 0xab, 0x3a, 0xf7, 0xcc,
+0xa1, 0xb8, 0x0e, 0x82, 0x49, 0xd7, 0x86, 0x29, 0x9f, 0xa1, 0x94, 0xf2, 0xe3, 0x60, 0x78, 0x98,
+0x81, 0x78, 0x06, 0x4d, 0xf2, 0xec, 0x9a, 0x0e, 0x57, 0x60, 0x83, 0x9f, 0xb4, 0xe6, 0x17, 0x2f,
+0x1a, 0xb3, 0x5d, 0x02, 0x5b, 0x89, 0x23, 0x3c, 0xc2, 0x11, 0x05, 0x2a, 0xa7, 0x88, 0x13, 0x18,
+0xf3, 0x50, 0x84, 0xd7, 0xbd, 0x34, 0x2c, 0x27, 0x89, 0x55, 0xff, 0xce, 0x4c, 0xe7, 0xdf, 0xa6,
+0x1f, 0x28, 0xc4, 0xf0, 0x54, 0xc3, 0xb9, 0x7c, 0xb7, 0x53, 0xad, 0xeb, 0xc2, 0xa3, 0x42, 0x30,
+0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x8d, 0x06, 0x66,
+0x74, 0x24, 0x76, 0x3a, 0xf3, 0x89, 0xf7, 0xbc, 0xd6, 0xbd, 0x47, 0x7d, 0x2f, 0xbc, 0x10, 0x5f,
+0x4b, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01,
+0x06, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x68, 0x00,
+0x30, 0x65, 0x02, 0x30, 0x03, 0x55, 0x2d, 0xa6, 0xe6, 0x18, 0xc4, 0x7c, 0xef, 0xc9, 0x50, 0x6e,
+0xc1, 0x27, 0x0f, 0x9c, 0x87, 0xaf, 0x6e, 0xd5, 0x1b, 0x08, 0x18, 0xbd, 0x92, 0x29, 0xc1, 0xef,
+0x94, 0x91, 0x78, 0xd2, 0x3a, 0x1c, 0x55, 0x89, 0x62, 0xe5, 0x1b, 0x09, 0x1e, 0xba, 0x64, 0x6b,
+0xf1, 0x76, 0xb4, 0xd4, 0x02, 0x31, 0x00, 0xb4, 0x42, 0x84, 0x99, 0xff, 0xab, 0xe7, 0x9e, 0xfb,
+0x91, 0x97, 0x27, 0x5d, 0xdc, 0xb0, 0x5b, 0x30, 0x71, 0xce, 0x5e, 0x38, 0x1a, 0x6a, 0xd9, 0x25,
+0xe7, 0xea, 0xf7, 0x61, 0x92, 0x56, 0xf8, 0xea, 0xda, 0x36, 0xc2, 0x87, 0x65, 0x96, 0x2e, 0x72,
+0x25, 0x2f, 0x7f, 0xdf, 0xc3, 0x13, 0xc9, 0x30, 0x82, 0x05, 0xc0, 0x30, 0x82, 0x03, 0xa8, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x1e, 0xbf, 0x59, 0x50, 0xb8, 0xc9, 0x80, 0x37, 0x4c, 0x06,
+0xf7, 0xeb, 0x55, 0x4f, 0xb5, 0xed, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x0d, 0x05, 0x00, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x50, 0x4c, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x41,
+0x73, 0x73, 0x65, 0x63, 0x6f, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
+0x6d, 0x73, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x13, 0x1e, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x43, 0x65, 0x72, 0x74, 0x75,
+0x6d, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
+0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x33, 0x31, 0x36, 0x31, 0x32, 0x31, 0x30, 0x31,
+0x33, 0x5a, 0x17, 0x0d, 0x34, 0x33, 0x30, 0x33, 0x31, 0x36, 0x31, 0x32, 0x31, 0x30, 0x31, 0x33,
+0x5a, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x4c,
+0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x41, 0x73, 0x73, 0x65, 0x63,
+0x6f, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x53,
+0x2e, 0x41, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x43, 0x65,
+0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x1f, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x54, 0x72,
+0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x02,
+0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xd1, 0x2d,
+0x8e, 0xbb, 0xb7, 0x36, 0xea, 0x6d, 0x37, 0x91, 0x9f, 0x4e, 0x93, 0xa7, 0x05, 0xe4, 0x29, 0x03,
+0x25, 0xce, 0x1c, 0x82, 0xf7, 0x7c, 0x99, 0x9f, 0x41, 0x06, 0xcd, 0xed, 0xa3, 0xba, 0xc0, 0xdb,
+0x09, 0x2c, 0xc1, 0x7c, 0xdf, 0x29, 0x7e, 0x4b, 0x65, 0x2f, 0x93, 0xa7, 0xd4, 0x01, 0x6b, 0x03,
+0x28, 0x18, 0xa3, 0xd8, 0x9d, 0x05, 0xc1, 0x2a, 0xd8, 0x45, 0xf1, 0x91, 0xde, 0xdf, 0x3b, 0xd0,
+0x80, 0x02, 0x8c, 0xcf, 0x38, 0x0f, 0xea, 0xa7, 0x5c, 0x78, 0x11, 0xa4, 0xc1, 0xc8, 0x85, 0x5c,
+0x25, 0xd3, 0xd3, 0xb2, 0xe7, 0x25, 0xcf, 0x11, 0x54, 0x97, 0xab, 0x35, 0xc0, 0x1e, 0x76, 0x1c,
+0xef, 0x00, 0x53, 0x9f, 0x39, 0xdc, 0x14, 0xa5, 0x2c, 0x22, 0x25, 0xb3, 0x72, 0x72, 0xfc, 0x8d,
+0xb3, 0xe5, 0x3e, 0x08, 0x1e, 0x14, 0x2a, 0x37, 0x0b, 0x88, 0x3c, 0xca, 0xb0, 0xf4, 0xc8, 0xc2,
+0xa1, 0xae, 0xbc, 0xc1, 0xbe, 0x29, 0x67, 0x55, 0xe2, 0xfc, 0xad, 0x59, 0x5c, 0xfe, 0xbd, 0x57,
+0x2c, 0xb0, 0x90, 0x8d, 0xc2, 0xed, 0x37, 0xb6, 0x7c, 0x99, 0x88, 0xb5, 0xd5, 0x03, 0x9a, 0x3d,
+0x15, 0x0d, 0x3d, 0x3a, 0xa8, 0xa8, 0x45, 0xf0, 0x95, 0x4e, 0x25, 0x59, 0x1d, 0xcd, 0x98, 0x69,
+0xbb, 0xd3, 0xcc, 0x32, 0xc9, 0x8d, 0xef, 0x81, 0xfe, 0xad, 0x7d, 0x89, 0xbb, 0xba, 0x60, 0x13,
+0xca, 0x65, 0x95, 0x67, 0xa0, 0xf3, 0x19, 0xf6, 0x03, 0x56, 0xd4, 0x6a, 0xd3, 0x27, 0xe2, 0xa1,
+0xad, 0x83, 0xf0, 0x4a, 0x12, 0x22, 0x77, 0x1c, 0x05, 0x73, 0xe2, 0x19, 0x71, 0x42, 0xc0, 0xec,
+0x75, 0x46, 0x9a, 0x90, 0x58, 0xe0, 0x6a, 0x8e, 0x2b, 0xa5, 0x46, 0x30, 0x04, 0x8e, 0x19, 0xb2,
+0x17, 0xe3, 0xbe, 0xa9, 0xba, 0x7f, 0x56, 0xf1, 0x24, 0x03, 0xd7, 0xb2, 0x21, 0x28, 0x76, 0x0e,
+0x36, 0x30, 0x4c, 0x79, 0xd5, 0x41, 0x9a, 0x9a, 0xa8, 0xb8, 0x35, 0xba, 0x0c, 0x3a, 0xf2, 0x44,
+0x1b, 0x20, 0x88, 0xf7, 0xc5, 0x25, 0xd7, 0x3d, 0xc6, 0xe3, 0x3e, 0x43, 0xdd, 0x87, 0xfe, 0xc4,
+0xea, 0xf5, 0x53, 0x3e, 0x4c, 0x65, 0xff, 0x3b, 0x4a, 0xcb, 0x78, 0x5a, 0x6b, 0x17, 0x5f, 0x0d,
+0xc7, 0xc3, 0x4f, 0x4e, 0x9a, 0x2a, 0xa2, 0xed, 0x57, 0x4d, 0x22, 0xe2, 0x46, 0x9a, 0x3f, 0x0f,
+0x91, 0x34, 0x24, 0x7d, 0x55, 0xe3, 0x8c, 0x95, 0x37, 0xd3, 0x1a, 0xf0, 0x09, 0x2b, 0x2c, 0xd2,
+0xc9, 0x8d, 0xb4, 0x0d, 0x00, 0xab, 0x67, 0x29, 0x28, 0xd8, 0x01, 0xf5, 0x19, 0x04, 0xb6, 0x1d,
+0xbe, 0x76, 0xfe, 0x72, 0x5c, 0xc4, 0x85, 0xca, 0xd2, 0x80, 0x41, 0xdf, 0x05, 0xa8, 0xa3, 0xd5,
+0x84, 0x90, 0x4f, 0x0b, 0xf3, 0xe0, 0x3f, 0x9b, 0x19, 0xd2, 0x37, 0x89, 0x3f, 0xf2, 0x7b, 0x52,
+0x1c, 0x8c, 0xf6, 0xe1, 0xf7, 0x3c, 0x07, 0x97, 0x8c, 0x0e, 0xa2, 0x59, 0x81, 0x0c, 0xb2, 0x90,
+0x3d, 0xd3, 0xe3, 0x59, 0x46, 0xed, 0x0f, 0xa9, 0xa7, 0xde, 0x80, 0x6b, 0x5a, 0xaa, 0x07, 0xb6,
+0x19, 0xcb, 0xbc, 0x57, 0xf3, 0x97, 0x21, 0x7a, 0x0c, 0xb1, 0x2b, 0x74, 0x3e, 0xeb, 0xda, 0xa7,
+0x67, 0x2d, 0x4c, 0xc4, 0x98, 0x9e, 0x36, 0x09, 0x76, 0x66, 0x66, 0xfc, 0x1a, 0x3f, 0xea, 0x48,
+0x54, 0x1c, 0xbe, 0x30, 0xbd, 0x80, 0x50, 0xbf, 0x7c, 0xb5, 0xce, 0x00, 0xf6, 0x0c, 0x61, 0xd9,
+0xe7, 0x24, 0x03, 0xe0, 0xe3, 0x01, 0x81, 0x0e, 0xbd, 0xd8, 0x85, 0x34, 0x88, 0xbd, 0xb2, 0x36,
+0xa8, 0x7b, 0x5c, 0x08, 0xe5, 0x44, 0x80, 0x8c, 0x6f, 0xf8, 0x2f, 0xd5, 0x21, 0xca, 0x1d, 0x1c,
+0xd0, 0xfb, 0xc4, 0xb5, 0x87, 0xd1, 0x3a, 0x4e, 0xc7, 0x76, 0xb5, 0x35, 0x48, 0xb5, 0x02, 0x03,
+0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+0x16, 0x04, 0x14, 0x8c, 0xfb, 0x1c, 0x75, 0xbc, 0x02, 0xd3, 0x9f, 0x4e, 0x2e, 0x48, 0xd9, 0xf9,
+0x60, 0x54, 0xaa, 0xc4, 0xb3, 0x4f, 0xfa, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x48, 0xa2, 0xd5, 0x00, 0x0b,
+0x2e, 0xd0, 0x3f, 0xbc, 0x1c, 0xd5, 0xb5, 0x54, 0x49, 0x1e, 0x5a, 0x6b, 0xf4, 0xe4, 0xf2, 0xe0,
+0x40, 0x37, 0xe0, 0xcc, 0x14, 0x7b, 0xb9, 0xc9, 0xfa, 0x35, 0xb5, 0x75, 0x17, 0x93, 0x6a, 0x05,
+0x69, 0x85, 0x9c, 0xcd, 0x4f, 0x19, 0x78, 0x5b, 0x19, 0x81, 0xf3, 0x63, 0x3e, 0xc3, 0xce, 0x5b,
+0x8f, 0xf5, 0x2f, 0x5e, 0x01, 0x76, 0x13, 0x3f, 0x2c, 0x00, 0xb9, 0xcd, 0x96, 0x52, 0x39, 0x49,
+0x6d, 0x04, 0x4e, 0xc5, 0xe9, 0x0f, 0x86, 0x0d, 0xe1, 0xfa, 0xb3, 0x5f, 0x82, 0x12, 0xf1, 0x3a,
+0xce, 0x66, 0x06, 0x24, 0x34, 0x2b, 0xe8, 0xcc, 0xca, 0xe7, 0x69, 0xdc, 0x87, 0x9d, 0xc2, 0x34,
+0xd7, 0x79, 0xd1, 0xd3, 0x77, 0xb8, 0xaa, 0x59, 0x58, 0xfe, 0x9d, 0x26, 0xfa, 0x38, 0x86, 0x3e,
+0x9d, 0x8a, 0x87, 0x64, 0x57, 0xe5, 0x17, 0x3a, 0xe2, 0xf9, 0x8d, 0xb9, 0xe3, 0x33, 0x78, 0xc1,
+0x90, 0xd8, 0xb8, 0xdd, 0xb7, 0x83, 0x51, 0xe4, 0xc4, 0xcc, 0x23, 0xd5, 0x06, 0x7c, 0xe6, 0x51,
+0xd3, 0xcd, 0x34, 0x31, 0xc0, 0xf6, 0x46, 0xbb, 0x0b, 0xad, 0xfc, 0x3d, 0x10, 0x05, 0x2a, 0x3b,
+0x4a, 0x91, 0x25, 0xee, 0x8c, 0xd4, 0x84, 0x87, 0x80, 0x2a, 0xbc, 0x09, 0x8c, 0xaa, 0x3a, 0x13,
+0x5f, 0xe8, 0x34, 0x79, 0x50, 0xc1, 0x10, 0x19, 0xf9, 0xd3, 0x28, 0x1e, 0xd4, 0xd1, 0x51, 0x30,
+0x29, 0xb3, 0xae, 0x90, 0x67, 0xd6, 0x1f, 0x0a, 0x63, 0xb1, 0xc5, 0xa9, 0xc6, 0x42, 0x31, 0x63,
+0x17, 0x94, 0xef, 0x69, 0xcb, 0x2f, 0xfa, 0x8c, 0x14, 0x7d, 0xc4, 0x43, 0x18, 0x89, 0xd9, 0xf0,
+0x32, 0x40, 0xe6, 0x80, 0xe2, 0x46, 0x5f, 0xe5, 0xe3, 0xc1, 0x00, 0x59, 0xa8, 0xf9, 0xe8, 0x20,
+0xbc, 0x89, 0x2c, 0x0e, 0x47, 0x34, 0x0b, 0xea, 0x57, 0xc2, 0x53, 0x36, 0xfc, 0xa7, 0xd4, 0xaf,
+0x31, 0xcd, 0xfe, 0x02, 0xe5, 0x75, 0xfa, 0xb9, 0x27, 0x09, 0xf9, 0xf3, 0xf5, 0x3b, 0xca, 0x7d,
+0x9f, 0xa9, 0x22, 0xcb, 0x88, 0xc9, 0xaa, 0xd1, 0x47, 0x3d, 0x36, 0x77, 0xa8, 0x59, 0x64, 0x6b,
+0x27, 0xcf, 0xef, 0x27, 0xc1, 0xe3, 0x24, 0xb5, 0x86, 0xf7, 0xae, 0x7e, 0x32, 0x4d, 0xb0, 0x79,
+0x68, 0xd1, 0x39, 0xe8, 0x90, 0x58, 0xc3, 0x83, 0xbc, 0x0f, 0x2c, 0xd6, 0x97, 0xeb, 0xce, 0x0c,
+0xe1, 0x20, 0xc7, 0xda, 0xb7, 0x3e, 0xc3, 0x3f, 0xbf, 0x2f, 0xdc, 0x34, 0xa4, 0xfb, 0x2b, 0x21,
+0xcd, 0x67, 0x8f, 0x4b, 0xf4, 0xe3, 0xea, 0xd4, 0x3f, 0xe7, 0x4f, 0xba, 0xb9, 0xa5, 0x93, 0x45,
+0x1c, 0x66, 0x1f, 0x21, 0xfa, 0x64, 0x5e, 0x6f, 0xe0, 0x76, 0x94, 0x32, 0xcb, 0x75, 0xf5, 0x6e,
+0xe5, 0xf6, 0x8f, 0xc7, 0xb8, 0xa4, 0xcc, 0xa8, 0x96, 0x7d, 0x64, 0xfb, 0x24, 0x5a, 0x4a, 0x03,
+0x6c, 0x6b, 0x38, 0xc6, 0xe8, 0x03, 0x43, 0x9a, 0xf7, 0x57, 0xb9, 0xb3, 0x29, 0x69, 0x93, 0x38,
+0xf4, 0x03, 0xf2, 0xbb, 0xfb, 0x82, 0x6b, 0x07, 0x20, 0xd1, 0x52, 0x1f, 0x9a, 0x64, 0x02, 0x7b,
+0x98, 0x66, 0xdb, 0x5c, 0x4d, 0x5a, 0x0f, 0xd0, 0x84, 0x95, 0xa0, 0x3c, 0x14, 0x43, 0x06, 0xca,
+0xca, 0xdb, 0xb8, 0x41, 0x36, 0xda, 0x6a, 0x44, 0x67, 0x87, 0xaf, 0xaf, 0xe3, 0x45, 0x11, 0x15,
+0x69, 0x08, 0xb2, 0xbe, 0x16, 0x39, 0x97, 0x24, 0x6f, 0x12, 0x45, 0xd1, 0x67, 0x5d, 0x09, 0xa8,
+0xc9, 0x15, 0xda, 0xfa, 0xd2, 0xa6, 0x5f, 0x13, 0x61, 0x1f, 0xbf, 0x85, 0xac, 0xb4, 0xad, 0xad,
+0x05, 0x94, 0x08, 0x83, 0x1e, 0x75, 0x17, 0xd3, 0x71, 0x3b, 0x93, 0x50, 0x23, 0x59, 0xa0, 0xed,
+0x3c, 0x91, 0x54, 0x9d, 0x76, 0x00, 0xc5, 0xc3, 0xb8, 0x38, 0xdb, 0x30, 0x82, 0x05, 0xcf, 0x30,
+0x82, 0x03, 0xb7, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x08, 0x16, 0x5f, 0x8a, 0x4c, 0xa5,
+0xec, 0x00, 0xc9, 0x93, 0x40, 0xdf, 0xc4, 0xc6, 0xae, 0x23, 0xb8, 0x1c, 0x5a, 0xa4, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x6f, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x4b, 0x31, 0x12, 0x30, 0x10,
+0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x09, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f, 0x6e, 0x67,
+0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x48, 0x6f, 0x6e, 0x67, 0x20,
+0x4b, 0x6f, 0x6e, 0x67, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x48,
+0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x31, 0x20, 0x30, 0x1e,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20,
+0x50, 0x6f, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x30, 0x1e,
+0x17, 0x0d, 0x31, 0x37, 0x30, 0x36, 0x30, 0x33, 0x30, 0x32, 0x32, 0x39, 0x34, 0x36, 0x5a, 0x17,
+0x0d, 0x34, 0x32, 0x30, 0x36, 0x30, 0x33, 0x30, 0x32, 0x32, 0x39, 0x34, 0x36, 0x5a, 0x30, 0x6f,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x4b, 0x31, 0x12, 0x30,
+0x10, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x09, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f, 0x6e,
+0x67, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x48, 0x6f, 0x6e, 0x67,
+0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d,
+0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x31, 0x20, 0x30,
+0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67,
+0x20, 0x50, 0x6f, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x30,
+0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00,
+0xb3, 0x88, 0xd7, 0xea, 0xce, 0x0f, 0x20, 0x4e, 0xbe, 0xe6, 0xd6, 0x03, 0x6d, 0xee, 0x59, 0xfc,
+0xc2, 0x57, 0xdf, 0x29, 0x68, 0xa1, 0x83, 0x0e, 0x3e, 0x68, 0xc7, 0x68, 0x58, 0x9c, 0x1c, 0x60,
+0x4b, 0x89, 0x43, 0x0c, 0xb9, 0xd4, 0x15, 0xb2, 0xee, 0xc1, 0x4e, 0x75, 0xe9, 0xb5, 0xa7, 0xef,
+0xe5, 0xe9, 0x35, 0x99, 0xe4, 0xcc, 0x1c, 0xe7, 0x4b, 0x5f, 0x8d, 0x33, 0x30, 0x20, 0x33, 0x53,
+0xd9, 0xa6, 0xbb, 0xd5, 0x3e, 0x13, 0x8e, 0xe9, 0x1f, 0x87, 0x49, 0xad, 0x50, 0x2d, 0x50, 0xca,
+0x18, 0xbe, 0x01, 0x58, 0xa2, 0x13, 0x70, 0x96, 0xbb, 0x89, 0x88, 0x56, 0x80, 0x5c, 0xf8, 0xbd,
+0x2c, 0x3c, 0xe1, 0x4c, 0x57, 0x88, 0xbb, 0xd3, 0xb9, 0x95, 0xef, 0xcb, 0xc7, 0xf6, 0xda, 0x31,
+0x74, 0x28, 0xa6, 0xe6, 0x54, 0x89, 0xf5, 0x41, 0x31, 0xca, 0xe5, 0x26, 0x1a, 0xcd, 0x82, 0xe0,
+0x70, 0xda, 0x3b, 0x29, 0xbb, 0xd5, 0x03, 0xf5, 0x99, 0xba, 0x55, 0xf5, 0x64, 0xd1, 0x60, 0x0e,
+0xb3, 0x89, 0x49, 0xb8, 0x8a, 0x2f, 0x05, 0xd2, 0x84, 0x45, 0x28, 0x7c, 0x8f, 0x68, 0x50, 0x12,
+0x78, 0xfc, 0x0b, 0xb5, 0x53, 0xcb, 0xc2, 0x98, 0x1c, 0x84, 0xa3, 0x9e, 0xb0, 0xbe, 0x23, 0xa4,
+0xda, 0xdc, 0xc8, 0x2b, 0x1e, 0xda, 0x6e, 0x45, 0x1e, 0x89, 0x98, 0xda, 0xf9, 0x00, 0x2e, 0x06,
+0xe9, 0x0c, 0x3b, 0x70, 0xd5, 0x50, 0x25, 0x88, 0x99, 0xcb, 0xcd, 0x73, 0x60, 0xf7, 0xd5, 0xff,
+0x35, 0x67, 0xc5, 0xa1, 0xbc, 0x5e, 0xab, 0xcd, 0x4a, 0xb8, 0x45, 0xeb, 0xc8, 0x68, 0x1e, 0x0d,
+0x0d, 0x14, 0x46, 0x12, 0xe3, 0xd2, 0x64, 0x62, 0x8a, 0x42, 0x98, 0xbc, 0xb4, 0xc6, 0x08, 0x08,
+0xf8, 0xfd, 0xa8, 0x4c, 0x64, 0x9c, 0x76, 0x01, 0xbd, 0x2f, 0xa9, 0x6c, 0x33, 0x0f, 0xd8, 0x3f,
+0x28, 0xb8, 0x3c, 0x69, 0x01, 0x42, 0x86, 0x7e, 0x69, 0xc1, 0xc9, 0x06, 0xca, 0xe5, 0x7a, 0x46,
+0x65, 0xe9, 0xc2, 0xd6, 0x50, 0x41, 0x2e, 0x3f, 0xb7, 0xe4, 0xed, 0x6c, 0xd7, 0xbf, 0x26, 0x01,
+0x11, 0xa2, 0x16, 0x29, 0x4a, 0x6b, 0x34, 0x06, 0x90, 0xec, 0x13, 0xd2, 0xb6, 0xfb, 0x6a, 0x76,
+0xd2, 0x3c, 0xed, 0xf0, 0xd6, 0x2d, 0xdd, 0xe1, 0x15, 0xec, 0xa3, 0x9b, 0x2f, 0x2c, 0xc9, 0x3e,
+0x2b, 0xe4, 0x69, 0x3b, 0xff, 0x72, 0x25, 0xb1, 0x36, 0x86, 0x5b, 0xc7, 0x7f, 0x6b, 0x8b, 0x55,
+0x1b, 0x4a, 0xc5, 0x20, 0x61, 0x3d, 0xae, 0xcb, 0x50, 0xe1, 0x08, 0x3a, 0xbe, 0xb0, 0x8f, 0x63,
+0x41, 0x53, 0x30, 0x08, 0x59, 0x3c, 0x98, 0x1d, 0x77, 0xba, 0x63, 0x91, 0x7a, 0xca, 0x10, 0x50,
+0x60, 0xbf, 0xf0, 0xd7, 0xbc, 0x95, 0x87, 0x8f, 0x97, 0xc5, 0xfe, 0x97, 0x6a, 0x01, 0x94, 0xa3,
+0x7c, 0x5b, 0x85, 0x1d, 0x2a, 0x39, 0x3a, 0xd0, 0x54, 0xa1, 0xd1, 0x39, 0x71, 0x9d, 0xfd, 0x21,
+0xf9, 0xb5, 0x7b, 0xf0, 0xe2, 0xe0, 0x02, 0x8f, 0x6e, 0x96, 0x24, 0x25, 0x2c, 0xa0, 0x1e, 0x2c,
+0xa8, 0xc4, 0x89, 0xa7, 0xef, 0xed, 0x99, 0x06, 0x2f, 0xb6, 0x0a, 0x4c, 0x4f, 0xdb, 0xa2, 0xcc,
+0x37, 0x1a, 0xaf, 0x47, 0x85, 0x2d, 0x8a, 0x5f, 0xc4, 0x34, 0x34, 0x4c, 0x00, 0xfd, 0x18, 0x93,
+0x67, 0x13, 0xd1, 0x37, 0xe6, 0x48, 0xb4, 0x8b, 0x06, 0xc5, 0x57, 0x7b, 0x19, 0x86, 0x0a, 0x79,
+0xcb, 0x00, 0xc9, 0x52, 0xaf, 0x42, 0xff, 0x37, 0x8f, 0xe1, 0xa3, 0x1e, 0x7a, 0x3d, 0x50, 0xab,
+0x63, 0x06, 0xe7, 0x15, 0xb5, 0x3f, 0xb6, 0x45, 0x37, 0x94, 0x37, 0xb1, 0x7e, 0xf2, 0x48, 0xc3,
+0x7f, 0xc5, 0x75, 0xfe, 0x97, 0x8d, 0x45, 0x8f, 0x1a, 0xa7, 0x1a, 0x72, 0x28, 0x1a, 0x40, 0x0f,
+0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13,
+0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x17, 0x9d, 0xcd, 0x1e, 0x8b, 0xd6, 0x39, 0x2b, 0x70,
+0xd3, 0x5c, 0xd4, 0xa0, 0xb8, 0x1f, 0xb0, 0x00, 0xfc, 0xc5, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55,
+0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x17, 0x9d, 0xcd, 0x1e, 0x8b, 0xd6, 0x39, 0x2b, 0x70, 0xd3,
+0x5c, 0xd4, 0xa0, 0xb8, 0x1f, 0xb0, 0x00, 0xfc, 0xc5, 0x61, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x56, 0xd5,
+0x7b, 0x6e, 0xe6, 0x22, 0x01, 0xd2, 0x42, 0x9b, 0x18, 0xd5, 0x0e, 0xd7, 0x66, 0x23, 0x5c, 0xe3,
+0xfe, 0xa0, 0xc7, 0x92, 0xd2, 0xe9, 0x94, 0xad, 0x4b, 0xa2, 0xc6, 0xec, 0x12, 0x7c, 0x74, 0xd5,
+0x48, 0xd2, 0x59, 0x14, 0x99, 0xc0, 0xeb, 0xb9, 0xd1, 0xeb, 0xf4, 0x48, 0x30, 0x5b, 0xad, 0xa7,
+0x57, 0x73, 0x99, 0xa9, 0xd3, 0xe5, 0xb7, 0xd1, 0x2e, 0x59, 0x24, 0x58, 0xdc, 0x68, 0x2e, 0x2e,
+0x62, 0xd8, 0x6a, 0xe4, 0x70, 0x0b, 0x2d, 0x20, 0x50, 0x20, 0xa4, 0x32, 0x95, 0xd1, 0x00, 0x98,
+0xbb, 0xd3, 0xfd, 0xf7, 0x32, 0xf2, 0x49, 0xae, 0xc6, 0x7a, 0xe0, 0x47, 0xbe, 0x6e, 0xce, 0xcb,
+0xa3, 0x72, 0x3a, 0x2d, 0x69, 0x5d, 0xcb, 0xc8, 0xe8, 0x45, 0x39, 0xd4, 0xfa, 0x42, 0xc1, 0x11,
+0x4c, 0x77, 0x5d, 0x92, 0xfb, 0x6a, 0xff, 0x58, 0x44, 0xe5, 0xeb, 0x81, 0x9e, 0xaf, 0xa0, 0x99,
+0xad, 0xbe, 0xa9, 0x01, 0x66, 0xcb, 0x38, 0x1d, 0x3c, 0xdf, 0x43, 0x1f, 0xf4, 0x4d, 0x6e, 0xb4,
+0xba, 0x17, 0x46, 0xfc, 0x7d, 0xfd, 0x87, 0x81, 0x79, 0x6a, 0x0d, 0x33, 0x0f, 0xfa, 0x2f, 0xf8,
+0x14, 0xb9, 0x80, 0xb3, 0x5d, 0x4d, 0xaa, 0x97, 0xe1, 0xf9, 0xe4, 0x18, 0xc5, 0xf8, 0xd5, 0x38,
+0x8c, 0x26, 0x3c, 0xfd, 0xf2, 0x28, 0xe2, 0xee, 0x5a, 0x49, 0x88, 0x2c, 0xdf, 0x79, 0x3d, 0x8e,
+0x9e, 0x90, 0x3c, 0xbd, 0x41, 0x4a, 0x3a, 0xdd, 0x5b, 0xf6, 0x9a, 0xb4, 0xce, 0x3f, 0x25, 0x30,
+0x7f, 0x32, 0x7d, 0xa2, 0x03, 0x94, 0xd0, 0xdc, 0x7a, 0xa1, 0x52, 0xde, 0x6e, 0x93, 0x8d, 0x18,
+0x26, 0xfd, 0x55, 0xac, 0xbd, 0x8f, 0x9b, 0xd2, 0xcf, 0xaf, 0xe7, 0x86, 0x2c, 0xcb, 0x1f, 0x09,
+0x6f, 0xa3, 0x6f, 0xa9, 0x84, 0xd4, 0x73, 0xbf, 0x4d, 0xa1, 0x74, 0x1b, 0x4e, 0x23, 0x60, 0xf2,
+0xcc, 0x0e, 0xaa, 0x7f, 0xa4, 0x9c, 0x4c, 0x25, 0xa8, 0xb2, 0x66, 0x3b, 0x38, 0xff, 0xd9, 0x94,
+0x30, 0xf6, 0x72, 0x84, 0xbe, 0x68, 0x55, 0x10, 0x0f, 0xc6, 0x73, 0x2c, 0x16, 0x69, 0x93, 0x07,
+0xfe, 0xb1, 0x45, 0xed, 0xbb, 0xa2, 0x55, 0x6a, 0xb0, 0xda, 0xb5, 0x4a, 0x02, 0x25, 0x27, 0x85,
+0xd7, 0xb7, 0xb7, 0x86, 0x44, 0x16, 0x89, 0x6c, 0x80, 0x2b, 0x3e, 0x97, 0xa9, 0x9c, 0xd5, 0x7e,
+0x55, 0x4c, 0xc6, 0xde, 0x45, 0x10, 0x1c, 0xea, 0xe9, 0x3b, 0x9f, 0x03, 0x53, 0xee, 0xee, 0x7a,
+0x01, 0x02, 0x16, 0x78, 0xd4, 0xe8, 0xc2, 0xbe, 0x46, 0x76, 0x88, 0x13, 0x3f, 0x22, 0xbb, 0x48,
+0x12, 0x1d, 0x52, 0x00, 0xb4, 0x02, 0x7e, 0x21, 0x1a, 0x1e, 0x9c, 0x25, 0xf4, 0xf3, 0x3d, 0x5e,
+0x1e, 0xd2, 0x1c, 0xf9, 0xb3, 0x2d, 0xb6, 0xf7, 0x37, 0x5c, 0xc6, 0xcb, 0x21, 0x4e, 0xb0, 0xf7,
+0x99, 0x47, 0x18, 0x85, 0xc1, 0x2b, 0xba, 0x55, 0xae, 0x06, 0xea, 0xd0, 0x07, 0xb2, 0xdc, 0xab,
+0xd0, 0x82, 0x96, 0x75, 0xce, 0xd2, 0x50, 0xfe, 0x99, 0xe7, 0xcf, 0x2f, 0x9f, 0xe7, 0x76, 0xd1,
+0x61, 0x2a, 0xfb, 0x21, 0xbb, 0x31, 0xd0, 0xaa, 0x9f, 0x47, 0xa4, 0xb2, 0x22, 0xca, 0x16, 0x3a,
+0x50, 0x57, 0xc4, 0x5b, 0x43, 0x67, 0xc5, 0x65, 0x62, 0x03, 0x49, 0x01, 0xeb, 0x43, 0xd9, 0xd8,
+0xf8, 0x9e, 0xad, 0xcf, 0xb1, 0x63, 0x0e, 0x45, 0xf4, 0xa0, 0x5a, 0x2c, 0x9b, 0x2d, 0xc5, 0xa6,
+0xc0, 0xad, 0xa8, 0x47, 0xf4, 0x27, 0x4c, 0x38, 0x0d, 0x2e, 0x1b, 0x49, 0x3b, 0x52, 0xf4, 0xe8,
+0x88, 0x83, 0x2b, 0x54, 0x28, 0xd4, 0xf2, 0x35, 0x52, 0xb4, 0x32, 0x83, 0x62, 0x69, 0x64, 0x0c,
+0x91, 0x9c, 0x9f, 0x97, 0xea, 0x74, 0x16, 0xfd, 0x1f, 0x11, 0x06, 0x9a, 0x9b, 0xf4, 0x30, 0x82,
+0x05, 0xeb, 0x30, 0x82, 0x03, 0xd3, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x56, 0xb6, 0x29,
+0xcd, 0x34, 0xbc, 0x78, 0xf6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54,
+0x65, 0x78, 0x61, 0x73, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x48,
+0x6f, 0x75, 0x73, 0x74, 0x6f, 0x6e, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+0x0f, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2e, 0x53, 0x53, 0x4c, 0x2e, 0x63,
+0x6f, 0x6d, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+0x74, 0x79, 0x20, 0x52, 0x53, 0x41, 0x20, 0x52, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30,
+0x35, 0x33, 0x31, 0x31, 0x38, 0x31, 0x34, 0x33, 0x37, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x35,
+0x33, 0x30, 0x31, 0x38, 0x31, 0x34, 0x33, 0x37, 0x5a, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55,
+0x04, 0x08, 0x0c, 0x05, 0x54, 0x65, 0x78, 0x61, 0x73, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
+0x04, 0x07, 0x0c, 0x07, 0x48, 0x6f, 0x75, 0x73, 0x74, 0x6f, 0x6e, 0x31, 0x18, 0x30, 0x16, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72,
+0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2e,
+0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x53, 0x41, 0x20, 0x52, 0x32, 0x30, 0x82,
+0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0x8f,
+0x36, 0x65, 0x40, 0xe1, 0xd6, 0x4d, 0xc0, 0xd7, 0xb4, 0xe9, 0x46, 0xda, 0x6b, 0xea, 0x33, 0x47,
+0xcd, 0x4c, 0xf9, 0x7d, 0x7d, 0xbe, 0xbd, 0x2d, 0x3d, 0xf0, 0xdb, 0x78, 0xe1, 0x86, 0xa5, 0xd9,
+0xba, 0x09, 0x57, 0x68, 0xed, 0x57, 0x3e, 0xa0, 0xd0, 0x08, 0x41, 0x83, 0xe7, 0x28, 0x41, 0x24,
+0x1f, 0xe3, 0x72, 0x15, 0xd0, 0x01, 0x1a, 0xfb, 0x5e, 0x70, 0x23, 0xb2, 0xcb, 0x9f, 0x39, 0xe3,
+0xcf, 0xc5, 0x4e, 0xc6, 0x92, 0x6d, 0x26, 0xc6, 0x7b, 0xbb, 0xb3, 0xda, 0x27, 0x9d, 0x0a, 0x86,
+0xe9, 0x81, 0x37, 0x05, 0xfe, 0xf0, 0x71, 0x71, 0xec, 0xc3, 0x1c, 0xe9, 0x63, 0xa2, 0x17, 0x14,
+0x9d, 0xef, 0x1b, 0x67, 0xd3, 0x85, 0x55, 0x02, 0x02, 0xd6, 0x49, 0xc9, 0xcc, 0x5a, 0xe1, 0xb1,
+0xf7, 0x6f, 0x32, 0x9f, 0xc9, 0xd4, 0x3b, 0x88, 0x41, 0xa8, 0x9c, 0xbd, 0xcb, 0xab, 0xdb, 0x6d,
+0x7b, 0x09, 0x1f, 0xa2, 0x4c, 0x72, 0x90, 0xda, 0x2b, 0x08, 0xfc, 0xcf, 0x3c, 0x54, 0xce, 0x67,
+0x0f, 0xa8, 0xcf, 0x5d, 0x96, 0x19, 0x0b, 0xc4, 0xe3, 0x72, 0xeb, 0xad, 0xd1, 0x7d, 0x1d, 0x27,
+0xef, 0x92, 0xeb, 0x10, 0xbf, 0x5b, 0xeb, 0x3b, 0xaf, 0xcf, 0x80, 0xdd, 0xc1, 0xd2, 0x96, 0x04,
+0x5b, 0x7a, 0x7e, 0xa4, 0xa9, 0x3c, 0x38, 0x76, 0xa4, 0x62, 0x8e, 0xa0, 0x39, 0x5e, 0xea, 0x77,
+0xcf, 0x5d, 0x00, 0x59, 0x8f, 0x66, 0x2c, 0x3e, 0x07, 0xa2, 0xa3, 0x05, 0x26, 0x11, 0x69, 0x97,
+0xea, 0x85, 0xb7, 0x0f, 0x96, 0x0b, 0x4b, 0xc8, 0x40, 0xe1, 0x50, 0xba, 0x2e, 0x8a, 0xcb, 0xf7,
+0x0f, 0x9a, 0x22, 0xe7, 0x7f, 0x9a, 0x37, 0x13, 0xcd, 0xf2, 0x4d, 0x13, 0x6b, 0x21, 0xd1, 0xc0,
+0xcc, 0x22, 0xf2, 0xa1, 0x46, 0xf6, 0x44, 0x69, 0x9c, 0xca, 0x61, 0x35, 0x07, 0x00, 0x6f, 0xd6,
+0x61, 0x08, 0x11, 0xea, 0xba, 0xb8, 0xf6, 0xe9, 0xb3, 0x60, 0xe5, 0x4d, 0xb9, 0xec, 0x9f, 0x14,
+0x66, 0xc9, 0x57, 0x58, 0xdb, 0xcd, 0x87, 0x69, 0xf8, 0x8a, 0x86, 0x12, 0x03, 0x47, 0xbf, 0x66,
+0x13, 0x76, 0xac, 0x77, 0x7d, 0x34, 0x24, 0x85, 0x83, 0xcd, 0xd7, 0xaa, 0x9c, 0x90, 0x1a, 0x9f,
+0x21, 0x2c, 0x7f, 0x78, 0xb7, 0x64, 0xb8, 0xd8, 0xe8, 0xa6, 0xf4, 0x78, 0xb3, 0x55, 0xcb, 0x84,
+0xd2, 0x32, 0xc4, 0x78, 0xae, 0xa3, 0x8f, 0x61, 0xdd, 0xce, 0x08, 0x53, 0xad, 0xec, 0x88, 0xfc,
+0x15, 0xe4, 0x9a, 0x0d, 0xe6, 0x9f, 0x1a, 0x77, 0xce, 0x4c, 0x8f, 0xb8, 0x14, 0x15, 0x3d, 0x62,
+0x9c, 0x86, 0x38, 0x06, 0x00, 0x66, 0x12, 0xe4, 0x59, 0x76, 0x5a, 0x53, 0xc0, 0x02, 0x98, 0xa2,
+0x10, 0x2b, 0x68, 0x44, 0x7b, 0x8e, 0x79, 0xce, 0x33, 0x4a, 0x76, 0xaa, 0x5b, 0x81, 0x16, 0x1b,
+0xb5, 0x8a, 0xd8, 0xd0, 0x00, 0x7b, 0x5e, 0x62, 0xb4, 0x09, 0xd6, 0x86, 0x63, 0x0e, 0xa6, 0x05,
+0x95, 0x49, 0xba, 0x28, 0x8b, 0x88, 0x93, 0xb2, 0x34, 0x1c, 0xd8, 0xa4, 0x55, 0x6e, 0xb7, 0x1c,
+0xd0, 0xde, 0x99, 0x55, 0x3b, 0x23, 0xf4, 0x22, 0xe0, 0xf9, 0x29, 0x66, 0x26, 0xec, 0x20, 0x50,
+0x77, 0xdb, 0x4a, 0x0b, 0x8f, 0xbe, 0xe5, 0x02, 0x60, 0x70, 0x41, 0x5e, 0xd4, 0xae, 0x50, 0x39,
+0x22, 0x14, 0x26, 0xcb, 0xb2, 0x3b, 0x73, 0x74, 0x55, 0x47, 0x07, 0x79, 0x81, 0x39, 0xa8, 0x30,
+0x13, 0x44, 0xe5, 0x04, 0x8a, 0xae, 0x96, 0x13, 0x25, 0x42, 0x0f, 0xb9, 0x53, 0xc4, 0x9b, 0xfc,
+0xcd, 0xe4, 0x1c, 0xde, 0x3c, 0xfa, 0xab, 0xd6, 0x06, 0x4a, 0x1f, 0x67, 0xa6, 0x98, 0x30, 0x1c,
+0xdd, 0x2c, 0xdb, 0xdc, 0x18, 0x95, 0x57, 0x66, 0xc6, 0xff, 0x5c, 0x8b, 0x56, 0xf5, 0x77, 0x02,
+0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
+0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xf9, 0x60, 0xbb, 0xd4, 0xe3, 0xd5, 0x34, 0xf6, 0xb8, 0xf5,
+0x06, 0x80, 0x25, 0xa7, 0x73, 0xdb, 0x46, 0x69, 0xa8, 0x9e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+0x0e, 0x04, 0x16, 0x04, 0x14, 0xf9, 0x60, 0xbb, 0xd4, 0xe3, 0xd5, 0x34, 0xf6, 0xb8, 0xf5, 0x06,
+0x80, 0x25, 0xa7, 0x73, 0xdb, 0x46, 0x69, 0xa8, 0x9e, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x56, 0xb3, 0x8e,
+0xcb, 0x0a, 0x9d, 0x49, 0x8e, 0xbf, 0xa4, 0xc4, 0x91, 0xbb, 0x66, 0x17, 0x05, 0x51, 0x98, 0x75,
+0xfb, 0xe5, 0x50, 0x2c, 0x7a, 0x9e, 0xf1, 0x14, 0xfa, 0xab, 0xd3, 0x8a, 0x3e, 0xff, 0x91, 0x29,
+0x8f, 0x63, 0x8b, 0xd8, 0xb4, 0xa9, 0x54, 0x01, 0x0d, 0xbe, 0x93, 0x86, 0x2f, 0xf9, 0x4a, 0x6d,
+0xc7, 0x5e, 0xf5, 0x57, 0xf9, 0xca, 0x55, 0x1c, 0x12, 0xbe, 0x47, 0x0f, 0x36, 0xc5, 0xdf, 0x6a,
+0xb7, 0xdb, 0x75, 0xc2, 0x47, 0x25, 0x7f, 0xb9, 0xf1, 0x63, 0xf8, 0x68, 0x2d, 0x55, 0x04, 0xd1,
+0xf2, 0x8d, 0xb0, 0xa4, 0xcf, 0xbc, 0x3c, 0x5e, 0x1f, 0x78, 0xe7, 0xa5, 0xa0, 0x20, 0x70, 0xb0,
+0x04, 0xc5, 0xb7, 0xf7, 0x72, 0xa7, 0xde, 0x22, 0x0d, 0xbd, 0x33, 0x25, 0x46, 0x8c, 0x64, 0x92,
+0x26, 0xe3, 0x3e, 0x2e, 0x63, 0x96, 0xda, 0x9b, 0x8c, 0x3d, 0xf8, 0x18, 0x09, 0xd7, 0x03, 0xcc,
+0x7d, 0x86, 0x82, 0xe0, 0xca, 0x04, 0x07, 0x51, 0x50, 0xd7, 0xff, 0x92, 0xd5, 0x0c, 0xef, 0xda,
+0x86, 0x9f, 0x99, 0xd7, 0xeb, 0xb7, 0xaf, 0x68, 0xe2, 0x39, 0x26, 0x94, 0xba, 0x68, 0xb7, 0xbf,
+0x83, 0xd3, 0xea, 0x7a, 0x67, 0x3d, 0x62, 0x67, 0xae, 0x25, 0xe5, 0x72, 0xe8, 0xe2, 0xe4, 0xec,
+0xae, 0x12, 0xf6, 0x4b, 0x2b, 0x3c, 0x9f, 0xe9, 0xb0, 0x40, 0xf3, 0x38, 0x54, 0xb3, 0xfd, 0xb7,
+0x68, 0xc8, 0xda, 0xc6, 0x8f, 0x51, 0x3c, 0xb2, 0xfb, 0x91, 0xdc, 0x1c, 0xe7, 0x9b, 0x9d, 0xe1,
+0xb7, 0x0d, 0x72, 0x8f, 0xe2, 0xa4, 0xc4, 0xa9, 0x78, 0xf9, 0xeb, 0x14, 0xac, 0xc6, 0x43, 0x05,
+0xc2, 0x65, 0x39, 0x28, 0x18, 0x02, 0xc3, 0x82, 0xb2, 0x9d, 0x05, 0xbe, 0x65, 0xed, 0x96, 0x5f,
+0x65, 0x74, 0x3c, 0xfb, 0x09, 0x35, 0x2e, 0x7b, 0x9c, 0x13, 0xfd, 0x1b, 0x0f, 0x5d, 0xc7, 0x6d,
+0x81, 0x3a, 0x56, 0x0f, 0xcc, 0x3b, 0xe1, 0xaf, 0x02, 0x2f, 0x22, 0xac, 0x46, 0xca, 0x46, 0x3c,
+0xa0, 0x1c, 0x4c, 0xd6, 0x44, 0xb4, 0x5e, 0x2e, 0x5c, 0x15, 0x66, 0x09, 0xe1, 0x26, 0x29, 0xfe,
+0xc6, 0x52, 0x61, 0xba, 0xb1, 0x73, 0xff, 0xc3, 0x0c, 0x9c, 0xe5, 0x6c, 0x6a, 0x94, 0x3f, 0x14,
+0xca, 0x40, 0x16, 0x95, 0x84, 0xf3, 0x59, 0xa9, 0xac, 0x5f, 0x4c, 0x61, 0x93, 0x6d, 0xd1, 0x3b,
+0xcc, 0xa2, 0x95, 0x0c, 0x22, 0xa6, 0x67, 0x67, 0x44, 0x2e, 0xb9, 0xd9, 0xd2, 0x8a, 0x41, 0xb3,
+0x66, 0x0b, 0x5a, 0xfb, 0x7d, 0x23, 0xa5, 0xf2, 0x1a, 0xb0, 0xff, 0xde, 0x9b, 0x83, 0x94, 0x2e,
+0xd1, 0x3f, 0xdf, 0x92, 0xb7, 0x91, 0xaf, 0x05, 0x3b, 0x65, 0xc7, 0xa0, 0x6c, 0xb1, 0xcd, 0x62,
+0x12, 0xc3, 0x90, 0x1b, 0xe3, 0x25, 0xce, 0x34, 0xbc, 0x6f, 0x77, 0x76, 0xb1, 0x10, 0xc3, 0xf7,
+0x05, 0x1a, 0xc0, 0xd6, 0xaf, 0x74, 0x62, 0x48, 0x17, 0x77, 0x92, 0x69, 0x90, 0x61, 0x1c, 0xde,
+0x95, 0x80, 0x74, 0x54, 0x8f, 0x18, 0x1c, 0xc3, 0xf3, 0x03, 0xd0, 0xbf, 0xa4, 0x43, 0x75, 0x86,
+0x53, 0x18, 0x7a, 0x0a, 0x2e, 0x09, 0x1c, 0x36, 0x9f, 0x91, 0xfd, 0x82, 0x8a, 0x22, 0x4b, 0xd1,
+0x0e, 0x50, 0x25, 0xdd, 0xcb, 0x03, 0x0c, 0x17, 0xc9, 0x83, 0x00, 0x08, 0x4e, 0x35, 0x4d, 0x8a,
+0x8b, 0xed, 0xf0, 0x02, 0x94, 0x66, 0x2c, 0x44, 0x7f, 0xcb, 0x95, 0x27, 0x96, 0x17, 0xad, 0x09,
+0x30, 0xac, 0xb6, 0x71, 0x17, 0x6e, 0x8b, 0x17, 0xf6, 0x1c, 0x09, 0xd4, 0x2d, 0x3b, 0x98, 0xa5,
+0x71, 0xd3, 0x54, 0x13, 0xd9, 0x60, 0xf3, 0xf5, 0x4b, 0x66, 0x4f, 0xfa, 0xf1, 0xee, 0x20, 0x12,
+0x8d, 0xb4, 0xac, 0x57, 0xb1, 0x45, 0x63, 0xa1, 0xac, 0x76, 0xa9, 0xc2, 0xfb, 0x30, 0x82, 0x05,
+0x47, 0x30, 0x82, 0x03, 0x2f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x11, 0x00, 0x34, 0xb6,
+0x4e, 0xc6, 0x36, 0x2d, 0x36, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x0b, 0x05, 0x00, 0x30, 0x41, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x52, 0x4f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x43, 0x45,
+0x52, 0x54, 0x53, 0x49, 0x47, 0x4e, 0x20, 0x53, 0x41, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x13, 0x13, 0x63, 0x65, 0x72, 0x74, 0x53, 0x49, 0x47, 0x4e, 0x20, 0x52, 0x4f, 0x4f,
+0x54, 0x20, 0x43, 0x41, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x32, 0x30,
+0x36, 0x30, 0x39, 0x32, 0x37, 0x33, 0x35, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x32, 0x30, 0x36,
+0x30, 0x39, 0x32, 0x37, 0x33, 0x35, 0x5a, 0x30, 0x41, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x52, 0x4f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x0b, 0x43, 0x45, 0x52, 0x54, 0x53, 0x49, 0x47, 0x4e, 0x20, 0x53, 0x41, 0x31, 0x1c, 0x30, 0x1a,
+0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x13, 0x63, 0x65, 0x72, 0x74, 0x53, 0x49, 0x47, 0x4e, 0x20,
+0x52, 0x4f, 0x4f, 0x54, 0x20, 0x43, 0x41, 0x20, 0x47, 0x32, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02,
+0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xc0, 0xc5, 0x75, 0x19, 0x91,
+0x7d, 0x44, 0x74, 0x74, 0x87, 0xfe, 0x0e, 0x3b, 0x96, 0xdc, 0xd8, 0x01, 0x16, 0xcc, 0xee, 0x63,
+0x91, 0xe7, 0x0b, 0x6f, 0xce, 0x3b, 0x0a, 0x69, 0x1a, 0x7c, 0xc2, 0xe3, 0xaf, 0x82, 0x8e, 0x86,
+0xd7, 0x5e, 0x8f, 0x57, 0xeb, 0xd3, 0x21, 0x59, 0xfd, 0x39, 0x37, 0x42, 0x30, 0xbe, 0x50, 0xea,
+0xb6, 0x0f, 0xa9, 0x88, 0xd8, 0x2e, 0x2d, 0x69, 0x21, 0xe7, 0xd1, 0x37, 0x18, 0x4e, 0x7d, 0x91,
+0xd5, 0x16, 0x5f, 0x6b, 0x5b, 0x00, 0xc2, 0x39, 0x43, 0x0d, 0x36, 0x85, 0x52, 0xb9, 0x53, 0x65,
+0x0f, 0x1d, 0x42, 0xe5, 0x8f, 0xcf, 0x05, 0xd3, 0xee, 0xdc, 0x0c, 0x1a, 0xd9, 0xb8, 0x8b, 0x78,
+0x22, 0x67, 0xe4, 0x69, 0xb0, 0x68, 0xc5, 0x3c, 0xe4, 0x6c, 0x5a, 0x46, 0xe7, 0xcd, 0xc7, 0xfa,
+0xef, 0xc4, 0xec, 0x4b, 0xbd, 0x6a, 0xa4, 0xac, 0xfd, 0xcc, 0x28, 0x51, 0xef, 0x92, 0xb4, 0x29,
+0xab, 0xab, 0x35, 0x9a, 0x4c, 0xe4, 0xc4, 0x08, 0xc6, 0x26, 0xcc, 0xf8, 0x69, 0x9f, 0xe4, 0x9c,
+0xf0, 0x29, 0xd3, 0x5c, 0xf9, 0xc6, 0x16, 0x25, 0x9e, 0x23, 0xc3, 0x20, 0xc1, 0x3d, 0x0f, 0x3f,
+0x38, 0x40, 0xb0, 0xfe, 0x82, 0x44, 0x38, 0xaa, 0x5a, 0x1a, 0x8a, 0x6b, 0x63, 0x58, 0x38, 0xb4,
+0x15, 0xd3, 0xb6, 0x11, 0x69, 0x7b, 0x1e, 0x54, 0xee, 0x8c, 0x1a, 0x22, 0xac, 0x72, 0x97, 0x3f,
+0x23, 0x59, 0x9b, 0xc9, 0x22, 0x84, 0xc1, 0x07, 0x4f, 0xcc, 0x7f, 0xe2, 0x57, 0xca, 0x12, 0x70,
+0xbb, 0xa6, 0x65, 0xf3, 0x69, 0x75, 0x63, 0xbd, 0x95, 0xfb, 0x1b, 0x97, 0xcd, 0xe4, 0xa8, 0xaf,
+0xf6, 0xd1, 0x4e, 0xa8, 0xd9, 0x8a, 0x71, 0x24, 0xcd, 0x36, 0x3d, 0xbc, 0x96, 0xc4, 0xf1, 0x6c,
+0xa9, 0xae, 0xe5, 0xcf, 0x0d, 0x6e, 0x28, 0x0d, 0xb0, 0x0e, 0xb5, 0xca, 0x51, 0x7b, 0x78, 0x14,
+0xc3, 0x20, 0x2f, 0x7f, 0xfb, 0x14, 0x55, 0xe1, 0x11, 0x99, 0xfd, 0xd5, 0x0a, 0xa1, 0x9e, 0x02,
+0xe3, 0x62, 0x5f, 0xeb, 0x35, 0x4b, 0x2c, 0xb8, 0x72, 0xe8, 0x3e, 0x3d, 0x4f, 0xac, 0x2c, 0xbb,
+0x2e, 0x86, 0xe2, 0xa3, 0x76, 0x8f, 0xe5, 0x93, 0x2a, 0xcf, 0xa5, 0xab, 0xc8, 0x5c, 0x8d, 0x4b,
+0x06, 0xff, 0x12, 0x46, 0xac, 0x78, 0xcb, 0x14, 0x07, 0x35, 0xe0, 0xa9, 0xdf, 0x8b, 0xe9, 0xaf,
+0x15, 0x4f, 0x16, 0x89, 0x5b, 0xbd, 0xf6, 0x8d, 0xc6, 0x59, 0xae, 0x88, 0x85, 0x0e, 0xc1, 0x89,
+0xeb, 0x1f, 0x67, 0xc5, 0x45, 0x8e, 0xff, 0x6d, 0x37, 0x36, 0x2b, 0x78, 0x66, 0x83, 0x91, 0x51,
+0x2b, 0x3d, 0xff, 0x51, 0x77, 0x76, 0x62, 0xa1, 0xec, 0x67, 0x3e, 0x3e, 0x81, 0x83, 0xe0, 0x56,
+0xa9, 0x50, 0x1f, 0x1f, 0x7a, 0x99, 0xab, 0x63, 0xbf, 0x84, 0x17, 0x77, 0xf1, 0x0d, 0x3b, 0xdf,
+0xf7, 0x9c, 0x61, 0xb3, 0x35, 0x98, 0x8a, 0x3a, 0xb2, 0xec, 0x3c, 0x1a, 0x37, 0x3f, 0x7e, 0x8f,
+0x92, 0xcf, 0xd9, 0x12, 0x14, 0x64, 0xda, 0x10, 0x02, 0x15, 0x41, 0xff, 0x4f, 0xc4, 0xeb, 0x1c,
+0xa3, 0xc9, 0xfa, 0x99, 0xf7, 0x46, 0xe9, 0xe1, 0x18, 0xd9, 0xb1, 0xb8, 0x32, 0x2d, 0xcb, 0x14,
+0x0c, 0x50, 0xd8, 0x83, 0x65, 0x83, 0xee, 0xb9, 0x5c, 0xcf, 0xcb, 0x05, 0x5a, 0x4c, 0xfa, 0x19,
+0x97, 0x6b, 0xd6, 0x5d, 0x13, 0xd3, 0xc2, 0x5c, 0x54, 0xbc, 0x32, 0x73, 0xa0, 0x78, 0xf5, 0xf1,
+0x6d, 0x1e, 0xcb, 0x9f, 0xa5, 0xa6, 0x9f, 0x22, 0xdc, 0xd1, 0x51, 0x9e, 0x82, 0x79, 0x64, 0x60,
+0x29, 0x13, 0x3e, 0xa3, 0xfd, 0x4f, 0x72, 0x6a, 0xab, 0xe2, 0xd4, 0xe5, 0xb8, 0x24, 0x55, 0x2c,
+0x44, 0x4b, 0x8a, 0x88, 0x44, 0x9c, 0xca, 0x84, 0xd3, 0x2a, 0x3b, 0x02, 0x03, 0x01, 0x00, 0x01,
+0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05,
+0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+0x82, 0x21, 0x2d, 0x66, 0xc6, 0xd7, 0xa0, 0xe0, 0x15, 0xeb, 0xce, 0x4c, 0x09, 0x77, 0xc4, 0x60,
+0x9e, 0x54, 0x6e, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x60, 0xde, 0x1a, 0xb8, 0xe7, 0xf2, 0x60, 0x82,
+0xd5, 0x03, 0x33, 0x81, 0xcb, 0x06, 0x8a, 0xf1, 0x22, 0x49, 0xe9, 0xe8, 0xea, 0x91, 0x7f, 0xc6,
+0x33, 0x5e, 0x68, 0x19, 0x03, 0x86, 0x3b, 0x43, 0x01, 0xcf, 0x07, 0x70, 0xe4, 0x08, 0x1e, 0x65,
+0x85, 0x91, 0xe6, 0x11, 0x22, 0xb7, 0xf5, 0x02, 0x23, 0x8e, 0xae, 0xb9, 0x1e, 0x7d, 0x1f, 0x7e,
+0x6c, 0xe6, 0xbd, 0x25, 0xd5, 0x95, 0x1a, 0xf2, 0x05, 0xa6, 0xaf, 0x85, 0x02, 0x6f, 0xae, 0xf8,
+0xd6, 0x31, 0xff, 0x25, 0xc9, 0x4a, 0xc8, 0xc7, 0x8a, 0xa9, 0xd9, 0x9f, 0x4b, 0x49, 0x9b, 0x11,
+0x57, 0x99, 0x92, 0x43, 0x11, 0xde, 0xb6, 0x33, 0xa4, 0xcc, 0xd7, 0x8d, 0x64, 0x7d, 0xd4, 0xcd,
+0x3c, 0x28, 0x2c, 0xb4, 0x9a, 0x96, 0xea, 0x4d, 0xf5, 0xc4, 0x44, 0xc4, 0x25, 0xaa, 0x20, 0x80,
+0xd8, 0x29, 0x55, 0xf7, 0xe0, 0x41, 0xfc, 0x06, 0x26, 0xff, 0xb9, 0x36, 0xf5, 0x43, 0x14, 0x03,
+0x66, 0x78, 0xe1, 0x11, 0xb1, 0xda, 0x20, 0x5f, 0x46, 0x00, 0x78, 0x00, 0x21, 0xa5, 0x1e, 0x00,
+0x28, 0x61, 0x78, 0x6f, 0xa8, 0x01, 0x01, 0x8f, 0x9d, 0x34, 0x9a, 0xff, 0xf4, 0x38, 0x90, 0xfb,
+0xb8, 0xd1, 0xb3, 0x72, 0x06, 0xc9, 0x71, 0xe6, 0x81, 0xc5, 0x79, 0xed, 0x0b, 0xa6, 0x79, 0xf2,
+0x13, 0x0b, 0x9c, 0xf7, 0x5d, 0x0e, 0x7b, 0x24, 0x93, 0xb4, 0x48, 0xdb, 0x86, 0x5f, 0xde, 0x50,
+0x86, 0x78, 0xe7, 0x40, 0xe6, 0x31, 0xa8, 0x90, 0x76, 0x70, 0x61, 0xaf, 0x9c, 0x37, 0x2c, 0x11,
+0xb5, 0x82, 0xb7, 0xaa, 0xae, 0x24, 0x34, 0x5b, 0x72, 0x0c, 0x69, 0x0d, 0xcd, 0x59, 0x9f, 0xf6,
+0x71, 0xaf, 0x9c, 0x0b, 0xd1, 0x0a, 0x38, 0xf9, 0x06, 0x22, 0x83, 0x53, 0x25, 0x0c, 0xfc, 0x51,
+0xc4, 0xe6, 0xbe, 0xe2, 0x39, 0x95, 0x0b, 0x24, 0xad, 0xaf, 0xd1, 0x95, 0xe4, 0x96, 0xd7, 0x74,
+0x64, 0x6b, 0x71, 0x4e, 0x02, 0x3c, 0xaa, 0x85, 0xf3, 0x20, 0xa3, 0x43, 0x39, 0x76, 0x5b, 0x6c,
+0x50, 0xfe, 0x9a, 0x9c, 0x14, 0x1e, 0x65, 0x14, 0x8a, 0x15, 0xbd, 0xa3, 0x82, 0x45, 0x5a, 0x49,
+0x56, 0x6a, 0xd2, 0x9c, 0xb1, 0x63, 0x32, 0xe5, 0x61, 0xe0, 0x53, 0x22, 0x0e, 0xa7, 0x0a, 0x49,
+0xea, 0xcb, 0x7e, 0x1f, 0xa8, 0xe2, 0x62, 0x80, 0xf6, 0x10, 0x45, 0x52, 0x98, 0x06, 0x18, 0xde,
+0xa5, 0xcd, 0x2f, 0x7f, 0xaa, 0xd4, 0xe9, 0x3e, 0x08, 0x72, 0xec, 0x23, 0x03, 0x02, 0x3c, 0xa6,
+0xaa, 0xd8, 0xbc, 0x67, 0x74, 0x3d, 0x14, 0x17, 0xfb, 0x54, 0x4b, 0x17, 0xe3, 0xd3, 0x79, 0x3d,
+0x6d, 0x6b, 0x49, 0xc9, 0x28, 0x0e, 0x2e, 0x74, 0x50, 0xbf, 0x0c, 0xd9, 0x46, 0x3a, 0x10, 0x86,
+0xc9, 0xa7, 0x3f, 0xe9, 0xa0, 0xec, 0x7f, 0xeb, 0xa5, 0x77, 0x58, 0x69, 0x71, 0xe6, 0x83, 0x0a,
+0x37, 0xf2, 0x86, 0x49, 0x6a, 0xbe, 0x79, 0x08, 0x90, 0xf6, 0x02, 0x16, 0x64, 0x3e, 0xe5, 0xda,
+0x4c, 0x7e, 0x0c, 0x34, 0xc9, 0xf9, 0x5f, 0xb6, 0xb3, 0x28, 0x51, 0xa7, 0xa7, 0x2b, 0xaa, 0x49,
+0xfa, 0x8d, 0x65, 0x29, 0x4e, 0xe3, 0x6b, 0x13, 0xa7, 0x94, 0xa3, 0x2d, 0x51, 0x6d, 0x78, 0x0c,
+0x44, 0xcb, 0xdf, 0xde, 0x08, 0x6f, 0xce, 0xa3, 0x64, 0xab, 0xd3, 0x95, 0x84, 0xd4, 0xb9, 0x52,
+0x54, 0x72, 0x7b, 0x96, 0x25, 0xcc, 0xbc, 0x69, 0xe3, 0x48, 0x6e, 0x0d, 0xd0, 0xc7, 0x9d, 0x27,
+0x9a, 0xaa, 0xf8, 0x13, 0x92, 0xdd, 0x1e, 0xdf, 0x63, 0x9f, 0x35, 0xa9, 0x16, 0x36, 0xec, 0x8c,
+0xb8, 0x83, 0xf4, 0x3d, 0x89, 0x8f, 0xcd, 0xb4, 0x17, 0x5e, 0xd7, 0xb3, 0x17, 0x41, 0x10, 0x5d,
+0x27, 0x73, 0x60, 0x85, 0x57, 0x49, 0x22, 0x07, 0x30, 0x82, 0x02, 0x69, 0x30, 0x82, 0x01, 0xef,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x21, 0x2a, 0x56, 0x0c, 0xae, 0xda, 0x0c, 0xab, 0x40,
+0x45, 0xbf, 0x2b, 0xa2, 0x2d, 0x3a, 0xea, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+0x04, 0x03, 0x03, 0x30, 0x6d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x43, 0x48, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x57, 0x49, 0x53,
+0x65, 0x4b, 0x65, 0x79, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x4f,
+0x49, 0x53, 0x54, 0x45, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x64, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x1f, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79,
+0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x43, 0x20,
+0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x35, 0x30, 0x39, 0x30, 0x39, 0x34, 0x38,
+0x33, 0x34, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x35, 0x30, 0x39, 0x30, 0x39, 0x35, 0x38, 0x33,
+0x33, 0x5a, 0x30, 0x6d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43,
+0x48, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x57, 0x49, 0x53, 0x65,
+0x4b, 0x65, 0x79, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x4f, 0x49,
+0x53, 0x54, 0x45, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45,
+0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x64, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x1f, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20,
+0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x43, 0x20, 0x43,
+0x41, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05,
+0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x4c, 0xe9, 0x50, 0xc0, 0xc6, 0x0f, 0x72,
+0x18, 0xbc, 0xd8, 0xf1, 0xba, 0xb3, 0x89, 0xe2, 0x79, 0x4a, 0xa3, 0x16, 0xa7, 0x6b, 0x54, 0x24,
+0xdb, 0x51, 0xff, 0xea, 0xf4, 0x09, 0x24, 0xc3, 0x0b, 0x22, 0x9f, 0xcb, 0x6a, 0x27, 0x82, 0x81,
+0x0d, 0xd2, 0xc0, 0xaf, 0x31, 0xe4, 0x74, 0x82, 0x6e, 0xca, 0x25, 0xd9, 0x8c, 0x75, 0x9d, 0xf1,
+0xdb, 0xd0, 0x9a, 0xa2, 0x4b, 0x21, 0x7e, 0x16, 0xa7, 0x63, 0x90, 0xd2, 0x39, 0xd4, 0xb1, 0x87,
+0x78, 0x5f, 0x18, 0x96, 0x0f, 0x50, 0x1b, 0x35, 0x37, 0x0f, 0x6a, 0xc6, 0xdc, 0xd9, 0x13, 0x4d,
+0xa4, 0x8e, 0x90, 0x37, 0xe6, 0xbd, 0x5b, 0x31, 0x91, 0xa3, 0x54, 0x30, 0x52, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x48, 0x87, 0x14, 0xac, 0xe3, 0xc3, 0x9e,
+0x90, 0x60, 0x3a, 0xd7, 0xca, 0x89, 0xee, 0xd3, 0xad, 0x8c, 0xb4, 0x50, 0x66, 0x30, 0x10, 0x06,
+0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30,
+0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x68, 0x00, 0x30, 0x65,
+0x02, 0x30, 0x26, 0xc7, 0x69, 0x5b, 0xdc, 0xd5, 0xe7, 0xb2, 0xe7, 0xc8, 0x0c, 0x8c, 0x8c, 0xc3,
+0xdd, 0x79, 0x8c, 0x1b, 0x63, 0xd5, 0xc9, 0x52, 0x94, 0x4e, 0x4d, 0x82, 0x4a, 0x73, 0x1e, 0xb2,
+0x80, 0x84, 0xa9, 0x25, 0xc0, 0x4c, 0x5a, 0x6d, 0x49, 0x29, 0x60, 0x78, 0x13, 0xe2, 0x7e, 0x48,
+0xeb, 0x64, 0x02, 0x31, 0x00, 0xdb, 0x34, 0x20, 0x32, 0x08, 0xff, 0x9a, 0x49, 0x02, 0xb6, 0x88,
+0xde, 0x14, 0xaf, 0x5d, 0x6c, 0x99, 0x71, 0x8d, 0x1a, 0x3f, 0x8b, 0xd7, 0xe0, 0xa2, 0x36, 0x86,
+0x1c, 0x07, 0x82, 0x3a, 0x76, 0x53, 0xfd, 0xc2, 0xa2, 0xed, 0xef, 0x7b, 0xb0, 0x80, 0x4f, 0x58,
+0x0f, 0x4b, 0x53, 0x39, 0xbd, 0x30, 0x82, 0x03, 0xb5, 0x30, 0x82, 0x02, 0x9d, 0xa0, 0x03, 0x02,
+0x01, 0x02, 0x02, 0x10, 0x76, 0xb1, 0x20, 0x52, 0x74, 0xf0, 0x85, 0x87, 0x46, 0xb3, 0xf8, 0x23,
+0x1a, 0xf6, 0xc2, 0xc0, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x30, 0x6d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x43, 0x48, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x57, 0x49, 0x53,
+0x65, 0x4b, 0x65, 0x79, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x4f,
+0x49, 0x53, 0x54, 0x45, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+0x45, 0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x64, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x1f, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79,
+0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x42, 0x20,
+0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x30, 0x31, 0x31, 0x35, 0x30, 0x30,
+0x33, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x31, 0x32, 0x30, 0x31, 0x31, 0x35, 0x31, 0x30, 0x33,
+0x31, 0x5a, 0x30, 0x6d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43,
+0x48, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x57, 0x49, 0x53, 0x65,
+0x4b, 0x65, 0x79, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x19, 0x4f, 0x49,
+0x53, 0x54, 0x45, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x45,
+0x6e, 0x64, 0x6f, 0x72, 0x73, 0x65, 0x64, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x1f, 0x4f, 0x49, 0x53, 0x54, 0x45, 0x20, 0x57, 0x49, 0x53, 0x65, 0x4b, 0x65, 0x79, 0x20,
+0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x42, 0x20, 0x43,
+0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01,
+0x01, 0x00, 0xd8, 0x17, 0xb7, 0x1c, 0x4a, 0x24, 0x2a, 0xd6, 0x97, 0xb1, 0xca, 0xe2, 0x1e, 0xfb,
+0x7d, 0x38, 0xef, 0x98, 0xf5, 0xb2, 0x39, 0x98, 0x4e, 0x27, 0xb8, 0x11, 0x5d, 0x7b, 0xd2, 0x25,
+0x94, 0x88, 0x82, 0x15, 0x26, 0x6a, 0x1b, 0x31, 0xbb, 0xa8, 0x5b, 0x21, 0x21, 0x2b, 0xd8, 0x0f,
+0x4e, 0x9f, 0x5a, 0xf1, 0xb1, 0x5a, 0xe4, 0x79, 0xd6, 0x32, 0x23, 0x2b, 0xe1, 0x53, 0xcc, 0x99,
+0x45, 0x5c, 0x7b, 0x4f, 0xad, 0xbc, 0xbf, 0x87, 0x4a, 0x0b, 0x4b, 0x97, 0x5a, 0xa8, 0xf6, 0x48,
+0xec, 0x7d, 0x7b, 0x0d, 0xcd, 0x21, 0x06, 0xdf, 0x9e, 0x15, 0xfd, 0x41, 0x8a, 0x48, 0xb7, 0x20,
+0xf4, 0xa1, 0x7a, 0x1b, 0x57, 0xd4, 0x5d, 0x50, 0xff, 0xba, 0x67, 0xd8, 0x23, 0x99, 0x1f, 0xc8,
+0x3f, 0xe3, 0xde, 0xff, 0x6f, 0x5b, 0x77, 0xb1, 0x6b, 0x6e, 0xb8, 0xc9, 0x64, 0xf7, 0xe1, 0xca,
+0x41, 0x46, 0x0e, 0x29, 0x71, 0xd0, 0xb9, 0x23, 0xfc, 0xc9, 0x81, 0x5f, 0x4e, 0xf7, 0x6f, 0xdf,
+0xbf, 0x84, 0xad, 0x73, 0x64, 0xbb, 0xb7, 0x42, 0x8e, 0x69, 0xf6, 0xd4, 0x76, 0x1d, 0x7e, 0x9d,
+0xa7, 0xb8, 0x57, 0x8a, 0x51, 0x67, 0x72, 0xd7, 0xd4, 0xa8, 0xb8, 0x95, 0x54, 0x40, 0x73, 0x03,
+0xf6, 0xea, 0xf4, 0xeb, 0xfe, 0x28, 0x42, 0x77, 0x3f, 0x9d, 0x23, 0x1b, 0xb2, 0xb6, 0x3d, 0x80,
+0x14, 0x07, 0x4c, 0x2e, 0x4f, 0xf7, 0xd5, 0x0a, 0x16, 0x0d, 0xbd, 0x66, 0x43, 0x37, 0x7e, 0x23,
+0x43, 0x79, 0xc3, 0x40, 0x86, 0xf5, 0x4c, 0x29, 0xda, 0x8e, 0x9a, 0xad, 0x0d, 0xa5, 0x04, 0x87,
+0x88, 0x1e, 0x85, 0xe3, 0xe9, 0x53, 0xd5, 0x9b, 0xc8, 0x8b, 0x03, 0x63, 0x78, 0xeb, 0xe0, 0x19,
+0x4a, 0x6e, 0xbb, 0x2f, 0x6b, 0x33, 0x64, 0x58, 0x93, 0xad, 0x69, 0xbf, 0x8f, 0x1b, 0xef, 0x82,
+0x48, 0xc7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x51, 0x30, 0x4f, 0x30, 0x0b, 0x06, 0x03, 0x55,
+0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+0x04, 0x16, 0x04, 0x14, 0x35, 0x0f, 0xc8, 0x36, 0x63, 0x5e, 0xe2, 0xa3, 0xec, 0xf9, 0x3b, 0x66,
+0x15, 0xce, 0x51, 0x52, 0xe3, 0x91, 0x9a, 0x3d, 0x30, 0x10, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04,
+0x01, 0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x40, 0x4c,
+0xfb, 0x87, 0xb2, 0x99, 0x81, 0x90, 0x7e, 0x9d, 0xc5, 0xb0, 0xb0, 0x26, 0xcd, 0x88, 0x7b, 0x2b,
+0x32, 0x8d, 0x6e, 0xb8, 0x21, 0x71, 0x58, 0x97, 0x7d, 0xae, 0x37, 0x14, 0xaf, 0x3e, 0xe7, 0xf7,
+0x9a, 0xe2, 0x7d, 0xf6, 0x71, 0x98, 0x99, 0x04, 0xaa, 0x43, 0x74, 0x78, 0xa3, 0xe3, 0x49, 0x61,
+0x3e, 0x73, 0x8c, 0x4d, 0x94, 0xe0, 0xf9, 0x71, 0xc4, 0xb6, 0x16, 0x0e, 0x53, 0x78, 0x1f, 0xd6,
+0xa2, 0x87, 0x2f, 0x02, 0x39, 0x81, 0x29, 0x3c, 0xaf, 0x15, 0x98, 0x21, 0x30, 0xfe, 0x28, 0x90,
+0x00, 0x8c, 0xd1, 0xe1, 0xcb, 0xfa, 0x5e, 0xc8, 0xfd, 0xf8, 0x10, 0x46, 0x3b, 0xa2, 0x78, 0x42,
+0x91, 0x17, 0x74, 0x55, 0x0a, 0xde, 0x50, 0x67, 0x4d, 0x66, 0xd1, 0xa7, 0xff, 0xfd, 0xd9, 0xc0,
+0xb5, 0xa8, 0xa3, 0x8a, 0xce, 0x66, 0xf5, 0x0f, 0x43, 0xcd, 0xa7, 0x2b, 0x57, 0x7b, 0x63, 0x46,
+0x6a, 0xaa, 0x2e, 0x52, 0xd8, 0xf4, 0xed, 0xe1, 0x6d, 0xad, 0x29, 0x90, 0x78, 0x48, 0xba, 0xe1,
+0x23, 0xaa, 0xa3, 0x89, 0xec, 0xb5, 0xab, 0x96, 0xc0, 0xb4, 0x4b, 0xa2, 0x1d, 0x97, 0x9e, 0x7a,
+0xf2, 0x6e, 0x40, 0x71, 0xdf, 0x68, 0xf1, 0x65, 0x4d, 0xce, 0x7c, 0x05, 0xdf, 0x53, 0x65, 0xa9,
+0xa5, 0xf0, 0xb1, 0x97, 0x04, 0x70, 0x15, 0x46, 0x03, 0x98, 0xd4, 0xd2, 0xbf, 0x54, 0xb4, 0xa0,
+0x58, 0x7d, 0x52, 0x6f, 0xda, 0x56, 0x26, 0x62, 0xd4, 0xd8, 0xdb, 0x89, 0x31, 0x6f, 0x1c, 0xf0,
+0x22, 0xc2, 0xd3, 0x62, 0x1c, 0x35, 0xcd, 0x4c, 0x69, 0x15, 0x54, 0x1a, 0x90, 0x98, 0xde, 0xeb,
+0x1e, 0x5f, 0xca, 0x77, 0xc7, 0xcb, 0x8e, 0x3d, 0x43, 0x69, 0x9c, 0x9a, 0x58, 0xd0, 0x24, 0x3b,
+0xdf, 0x1b, 0x40, 0x96, 0x7e, 0x35, 0xad, 0x81, 0xc7, 0x4e, 0x71, 0xba, 0x88, 0x13, 0x30, 0x82,
+0x03, 0x72, 0x30, 0x82, 0x02, 0x5a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x3e, 0x8a, 0x5d,
+0x07, 0xec, 0x55, 0xd2, 0x32, 0xd5, 0xb7, 0xe3, 0xb6, 0x5f, 0x01, 0xeb, 0x2d, 0xdc, 0xe4, 0xd6,
+0xe4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+0x30, 0x51, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x4c, 0x31,
+0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1f, 0x4b, 0x72, 0x61, 0x6a, 0x6f, 0x77,
+0x61, 0x20, 0x49, 0x7a, 0x62, 0x61, 0x20, 0x52, 0x6f, 0x7a, 0x6c, 0x69, 0x63, 0x7a, 0x65, 0x6e,
+0x69, 0x6f, 0x77, 0x61, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x0c, 0x0f, 0x53, 0x5a, 0x41, 0x46, 0x49, 0x52, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x20,
+0x43, 0x41, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x31, 0x30, 0x31, 0x39, 0x30, 0x37, 0x34,
+0x33, 0x33, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x35, 0x31, 0x30, 0x31, 0x39, 0x30, 0x37, 0x34, 0x33,
+0x33, 0x30, 0x5a, 0x30, 0x51, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x50, 0x4c, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1f, 0x4b, 0x72, 0x61,
+0x6a, 0x6f, 0x77, 0x61, 0x20, 0x49, 0x7a, 0x62, 0x61, 0x20, 0x52, 0x6f, 0x7a, 0x6c, 0x69, 0x63,
+0x7a, 0x65, 0x6e, 0x69, 0x6f, 0x77, 0x61, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x31, 0x18, 0x30, 0x16,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x53, 0x5a, 0x41, 0x46, 0x49, 0x52, 0x20, 0x52, 0x4f,
+0x4f, 0x54, 0x20, 0x43, 0x41, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
+0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb7, 0xbc, 0x3e, 0x50, 0xa8, 0x4b, 0xcd, 0x40, 0xb5,
+0xce, 0x61, 0xe7, 0x96, 0xca, 0xb4, 0xa1, 0xda, 0x0c, 0x22, 0xb0, 0xfa, 0xb5, 0x7b, 0x76, 0x00,
+0x77, 0x8c, 0x0b, 0xcf, 0x7d, 0xa8, 0x86, 0xcc, 0x26, 0x51, 0xe4, 0x20, 0x3d, 0x85, 0x0c, 0xd6,
+0x58, 0xe3, 0xe7, 0xf4, 0x2a, 0x18, 0x9d, 0xda, 0xd1, 0xae, 0x26, 0xee, 0xeb, 0x53, 0xdc, 0xf4,
+0x90, 0xd6, 0x13, 0x4a, 0x0c, 0x90, 0x3c, 0xc3, 0xf4, 0xda, 0xd2, 0x8e, 0x0d, 0x92, 0x3a, 0xdc,
+0xb1, 0xb1, 0xff, 0x38, 0xde, 0xc3, 0xba, 0x2d, 0x5f, 0x80, 0xb9, 0x02, 0xbd, 0x4a, 0x9d, 0x1b,
+0x0f, 0xb4, 0xc3, 0xc2, 0xc1, 0x67, 0x03, 0xdd, 0xdc, 0x1b, 0x9c, 0x3d, 0xb3, 0xb0, 0xde, 0x00,
+0x1e, 0xa8, 0x34, 0x47, 0xbb, 0x9a, 0xeb, 0xfe, 0x0b, 0x14, 0xbd, 0x36, 0x84, 0xda, 0x0d, 0x20,
+0xbf, 0xfa, 0x5b, 0xcb, 0xa9, 0x16, 0x20, 0xad, 0x39, 0x60, 0xee, 0x2f, 0x75, 0xb6, 0xe7, 0x97,
+0x9c, 0xf9, 0x3e, 0xfd, 0x7e, 0x4d, 0x6f, 0x4d, 0x2f, 0xef, 0x88, 0x0d, 0x6a, 0xfa, 0xdd, 0xf1,
+0x3d, 0x6e, 0x20, 0xa5, 0xa0, 0x12, 0xb4, 0x4d, 0x70, 0xb9, 0xce, 0xd7, 0x72, 0x3b, 0x89, 0x93,
+0xa7, 0x80, 0x84, 0x1c, 0x27, 0x49, 0x72, 0x49, 0xb5, 0xff, 0x3b, 0x95, 0x9e, 0xc1, 0xcc, 0xc8,
+0x01, 0xec, 0xe8, 0x0e, 0x8a, 0x0a, 0x96, 0xe7, 0xb3, 0xa6, 0x87, 0xe5, 0xd6, 0xf9, 0x05, 0x2b,
+0x0d, 0x97, 0x40, 0x70, 0x3c, 0xba, 0xac, 0x75, 0x5a, 0x9c, 0xd5, 0x4d, 0x9d, 0x02, 0x0a, 0xd2,
+0x4b, 0x9b, 0x66, 0x4b, 0x46, 0x07, 0x17, 0x65, 0xad, 0x9f, 0x6c, 0x88, 0x00, 0xdc, 0x22, 0x89,
+0xe0, 0xe1, 0x64, 0xd4, 0x67, 0xbc, 0x31, 0x79, 0x61, 0x3c, 0xbb, 0xca, 0x41, 0xcd, 0x5c, 0x6a,
+0x00, 0xc8, 0x3c, 0x38, 0x8e, 0x58, 0xaf, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01,
+0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2e, 0x16, 0xa9, 0x4a,
+0x18, 0xb5, 0xcb, 0xcc, 0xf5, 0x6f, 0x50, 0xf3, 0x23, 0x5f, 0xf8, 0x5d, 0xe7, 0xac, 0xf0, 0xc8,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+0x82, 0x01, 0x01, 0x00, 0xb5, 0x73, 0xf8, 0x03, 0xdc, 0x59, 0x5b, 0x1d, 0x76, 0xe9, 0xa3, 0x2a,
+0x7b, 0x90, 0x28, 0xb2, 0x4d, 0xc0, 0x33, 0x4f, 0xaa, 0x9a, 0xb1, 0xd4, 0xb8, 0xe4, 0x27, 0xff,
+0xa9, 0x96, 0x99, 0xce, 0x46, 0xe0, 0x6d, 0x7c, 0x4c, 0xa2, 0x38, 0xa4, 0x06, 0x70, 0xf0, 0xf4,
+0x41, 0x11, 0xec, 0x3f, 0x47, 0x8d, 0x3f, 0x72, 0x87, 0xf9, 0x3b, 0xfd, 0xa4, 0x6f, 0x2b, 0x53,
+0x00, 0xe0, 0xff, 0x39, 0xb9, 0x6a, 0x07, 0x0e, 0xeb, 0x1d, 0x1c, 0xf6, 0xa2, 0x72, 0x90, 0xcb,
+0x82, 0x3d, 0x11, 0x82, 0x8b, 0xd2, 0xbb, 0x9f, 0x2a, 0xaf, 0x21, 0xe6, 0x63, 0x86, 0x9d, 0x79,
+0x19, 0xef, 0xf7, 0xbb, 0x0c, 0x35, 0x90, 0xc3, 0x8a, 0xed, 0x4f, 0x0f, 0xf5, 0xcc, 0x12, 0xd9,
+0xa4, 0x3e, 0xbb, 0xa0, 0xfc, 0x20, 0x95, 0x5f, 0x4f, 0x26, 0x2f, 0x11, 0x23, 0x83, 0x4e, 0x75,
+0x07, 0x0f, 0xbf, 0x9b, 0xd1, 0xb4, 0x1d, 0xe9, 0x10, 0x04, 0xfe, 0xca, 0x60, 0x8f, 0xa2, 0x4c,
+0xb8, 0xad, 0xcf, 0xe1, 0x90, 0x0f, 0xcd, 0xae, 0x0a, 0xc7, 0x5d, 0x7b, 0xb7, 0x50, 0xd2, 0xd4,
+0x61, 0xfa, 0xd5, 0x15, 0xdb, 0xd7, 0x9f, 0x87, 0x51, 0x54, 0xeb, 0xa5, 0xe3, 0xeb, 0xc9, 0x85,
+0xa0, 0x25, 0x20, 0x37, 0xfb, 0x8e, 0xce, 0x0c, 0x34, 0x84, 0xe1, 0x3c, 0x81, 0xb2, 0x77, 0x4e,
+0x43, 0xa5, 0x88, 0x5f, 0x86, 0x67, 0xa1, 0x3d, 0xe6, 0xb4, 0x5c, 0x61, 0xb6, 0x3e, 0xdb, 0xfe,
+0xb7, 0x28, 0xc5, 0xa2, 0x07, 0xae, 0xb5, 0xca, 0xca, 0x8d, 0x2a, 0x12, 0xef, 0x97, 0xed, 0xc2,
+0x30, 0xa4, 0xc9, 0x2a, 0x7a, 0xfb, 0xf3, 0x4d, 0x23, 0x1b, 0x99, 0x33, 0x34, 0xa0, 0x2e, 0xf5,
+0xa9, 0x0b, 0x3f, 0xd4, 0x5d, 0xe1, 0xcf, 0x84, 0x9f, 0xe2, 0x19, 0xc2, 0x5f, 0x8a, 0xd6, 0x20,
+0x1e, 0xe3, 0x73, 0xb7, 0x30, 0x82, 0x05, 0xd2, 0x30, 0x82, 0x03, 0xba, 0xa0, 0x03, 0x02, 0x01,
+0x02, 0x02, 0x10, 0x21, 0xd6, 0xd0, 0x4a, 0x4f, 0x25, 0x0f, 0xc9, 0x32, 0x37, 0xfc, 0xaa, 0x5e,
+0x12, 0x8d, 0xe9, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d,
+0x05, 0x00, 0x30, 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x50, 0x4c, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x19, 0x55, 0x6e, 0x69,
+0x7a, 0x65, 0x74, 0x6f, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65,
+0x73, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+0x1e, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
+0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1b, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d,
+0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x31, 0x31, 0x30, 0x30,
+0x36, 0x30, 0x38, 0x33, 0x39, 0x35, 0x36, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x34, 0x36, 0x31, 0x30,
+0x30, 0x36, 0x30, 0x38, 0x33, 0x39, 0x35, 0x36, 0x5a, 0x30, 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x4c, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x19, 0x55, 0x6e, 0x69, 0x7a, 0x65, 0x74, 0x6f, 0x20, 0x54, 0x65, 0x63, 0x68,
+0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x31, 0x27, 0x30,
+0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43,
+0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
+0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+0x1b, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20,
+0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x82, 0x02, 0x22,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xbd, 0xf9, 0x78,
+0xf8, 0xe6, 0xd5, 0x80, 0x0c, 0x64, 0x9d, 0x86, 0x1b, 0x96, 0x64, 0x67, 0x3f, 0x22, 0x3a, 0x1e,
+0x75, 0x01, 0x7d, 0xef, 0xfb, 0x5c, 0x67, 0x8c, 0xc9, 0xcc, 0x5c, 0x6b, 0xa9, 0x91, 0xe6, 0xb9,
+0x42, 0xe5, 0x20, 0x4b, 0x9b, 0xda, 0x9b, 0x7b, 0xb9, 0x99, 0x5d, 0xd9, 0x9b, 0x80, 0x4b, 0xd7,
+0x84, 0x40, 0x2b, 0x27, 0xd3, 0xe8, 0xba, 0x30, 0xbb, 0x3e, 0x09, 0x1a, 0xa7, 0x49, 0x95, 0xef,
+0x2b, 0x40, 0x24, 0xc2, 0x97, 0xc7, 0xa7, 0xee, 0x9b, 0x25, 0xef, 0xa8, 0x0a, 0x00, 0x97, 0x85,
+0x5a, 0xaa, 0x9d, 0xdc, 0x29, 0xc9, 0xe2, 0x35, 0x07, 0xeb, 0x70, 0x4d, 0x4a, 0xd6, 0xc1, 0xb3,
+0x56, 0xb8, 0xa1, 0x41, 0x38, 0x9b, 0xd1, 0xfb, 0x31, 0x7f, 0x8f, 0xe0, 0x5f, 0xe1, 0xb1, 0x3f,
+0x0f, 0x8e, 0x16, 0x49, 0x60, 0xd7, 0x06, 0x8d, 0x18, 0xf9, 0xaa, 0x26, 0x10, 0xab, 0x2a, 0xd3,
+0xd0, 0xd1, 0x67, 0x8d, 0x1b, 0x46, 0xbe, 0x47, 0x30, 0xd5, 0x2e, 0x72, 0xd1, 0xc5, 0x63, 0xda,
+0xe7, 0x63, 0x79, 0x44, 0x7e, 0x4b, 0x63, 0x24, 0x89, 0x86, 0x2e, 0x34, 0x3f, 0x29, 0x4c, 0x52,
+0x8b, 0x2a, 0xa7, 0xc0, 0xe2, 0x91, 0x28, 0x89, 0xb9, 0xc0, 0x5b, 0xf9, 0x1d, 0xd9, 0xe7, 0x27,
+0xad, 0xff, 0x9a, 0x02, 0x97, 0xc1, 0xc6, 0x50, 0x92, 0x9b, 0x02, 0x2c, 0xbd, 0xa9, 0xb9, 0x34,
+0x59, 0x0a, 0xbf, 0x84, 0x4a, 0xff, 0xdf, 0xfe, 0xb3, 0x9f, 0xeb, 0xd9, 0x9e, 0xe0, 0x98, 0x23,
+0xec, 0xa6, 0x6b, 0x77, 0x16, 0x2a, 0xdb, 0xcc, 0xad, 0x3b, 0x1c, 0xa4, 0x87, 0xdc, 0x46, 0x73,
+0x5e, 0x19, 0x62, 0x68, 0x45, 0x57, 0xe4, 0x90, 0x82, 0x42, 0xbb, 0x42, 0xd6, 0xf0, 0x61, 0xe0,
+0xc1, 0xa3, 0x3d, 0x66, 0xa3, 0x5d, 0xf4, 0x18, 0xee, 0x88, 0xc9, 0x8d, 0x17, 0x45, 0x29, 0x99,
+0x32, 0x75, 0x02, 0x31, 0xee, 0x29, 0x26, 0xc8, 0x6b, 0x02, 0xe6, 0xb5, 0x62, 0x45, 0x7f, 0x37,
+0x15, 0x5a, 0x23, 0x68, 0x89, 0xd4, 0x3e, 0xde, 0x4e, 0x27, 0xb0, 0xf0, 0x40, 0x0c, 0xbc, 0x4d,
+0x17, 0xcb, 0x4d, 0xa2, 0xb3, 0x1e, 0xd0, 0x06, 0x5a, 0xdd, 0xf6, 0x93, 0xcf, 0x57, 0x75, 0x99,
+0xf5, 0xfa, 0x86, 0x1a, 0x67, 0x78, 0xb3, 0xbf, 0x96, 0xfe, 0x34, 0xdc, 0xbd, 0xe7, 0x52, 0x56,
+0xe5, 0xb3, 0xe5, 0x75, 0x7b, 0xd7, 0x41, 0x91, 0x05, 0xdc, 0x5d, 0x69, 0xe3, 0x95, 0x0d, 0x43,
+0xb9, 0xfc, 0x83, 0x96, 0x39, 0x95, 0x7b, 0x6c, 0x80, 0x5a, 0x4f, 0x13, 0x72, 0xc6, 0xd7, 0x7d,
+0x29, 0x7a, 0x44, 0xba, 0x52, 0xa4, 0x2a, 0xd5, 0x41, 0x46, 0x09, 0x20, 0xfe, 0x22, 0xa0, 0xb6,
+0x5b, 0x30, 0x8d, 0xbc, 0x89, 0x0c, 0xd5, 0xd7, 0x70, 0xf8, 0x87, 0x52, 0xfd, 0xda, 0xef, 0xac,
+0x51, 0x2e, 0x07, 0xb3, 0x4e, 0xfe, 0xd0, 0x09, 0xda, 0x70, 0xef, 0x98, 0xfa, 0x56, 0xe6, 0x6d,
+0xdb, 0xb5, 0x57, 0x4b, 0xdc, 0xe5, 0x2c, 0x25, 0x15, 0xc8, 0x9e, 0x2e, 0x78, 0x4e, 0xf8, 0xda,
+0x9c, 0x9e, 0x86, 0x2c, 0xca, 0x57, 0xf3, 0x1a, 0xe5, 0xc8, 0x92, 0x8b, 0x1a, 0x82, 0x96, 0x7a,
+0xc3, 0xbc, 0x50, 0x12, 0x69, 0xd8, 0x0e, 0x5a, 0x46, 0x8b, 0x3a, 0xeb, 0x26, 0xfa, 0x23, 0xc9,
+0xb6, 0xb0, 0x81, 0xbe, 0x42, 0x00, 0xa4, 0xf8, 0xd6, 0xfe, 0x30, 0x2e, 0xc7, 0xd2, 0x46, 0xf6,
+0xe5, 0x8e, 0x75, 0xfd, 0xf2, 0xcc, 0xb9, 0xd0, 0x87, 0x5b, 0xcc, 0x06, 0x10, 0x60, 0xbb, 0x83,
+0x35, 0xb7, 0x5e, 0x67, 0xde, 0x47, 0xec, 0x99, 0x48, 0xf1, 0xa4, 0xa1, 0x15, 0xfe, 0xad, 0x8c,
+0x62, 0x8e, 0x39, 0x55, 0x4f, 0x39, 0x16, 0xb9, 0xb1, 0x63, 0x9d, 0xff, 0xb7, 0x02, 0x03, 0x01,
+0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+0x04, 0x14, 0xb6, 0xa1, 0x54, 0x39, 0x02, 0xc3, 0xa0, 0x3f, 0x8e, 0x8a, 0xbc, 0xfa, 0xd4, 0xf8,
+0x1c, 0xa6, 0xd1, 0x3a, 0x0e, 0xfd, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x0d, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x71, 0xa5, 0x0e, 0xce, 0xe4, 0xe9,
+0xbf, 0x3f, 0x38, 0xd5, 0x89, 0x5a, 0xc4, 0x02, 0x61, 0xfb, 0x4c, 0xc5, 0x14, 0x17, 0x2d, 0x8b,
+0x4f, 0x53, 0x6b, 0x10, 0x17, 0xfc, 0x65, 0x84, 0xc7, 0x10, 0x49, 0x90, 0xde, 0xdb, 0xc7, 0x26,
+0x93, 0x88, 0x26, 0x6f, 0x70, 0xd6, 0x02, 0x5e, 0x39, 0xa0, 0xf7, 0x8f, 0xab, 0x96, 0xb5, 0xa5,
+0x13, 0x5c, 0x81, 0x14, 0x6d, 0x0e, 0x81, 0x82, 0x11, 0x1b, 0x8a, 0x4e, 0xc6, 0x4f, 0xa5, 0xdd,
+0x62, 0x1e, 0x44, 0xdf, 0x09, 0x59, 0xf4, 0x5b, 0x77, 0x0b, 0x37, 0xe9, 0x8b, 0x20, 0xc6, 0xf8,
+0x0a, 0x4e, 0x2e, 0x58, 0x1c, 0xeb, 0x33, 0xd0, 0xcf, 0x86, 0x60, 0xc9, 0xda, 0xfb, 0x80, 0x2f,
+0x9e, 0x4c, 0x60, 0x84, 0x78, 0x3d, 0x21, 0x64, 0xd6, 0xfb, 0x41, 0x1f, 0x18, 0x0f, 0xe7, 0xc9,
+0x75, 0x71, 0xbd, 0xbd, 0x5c, 0xde, 0x34, 0x87, 0x3e, 0x41, 0xb0, 0x0e, 0xf6, 0xb9, 0xd6, 0x3f,
+0x09, 0x13, 0x96, 0x14, 0x2f, 0xde, 0x9a, 0x1d, 0x5a, 0xb9, 0x56, 0xce, 0x35, 0x3a, 0xb0, 0x5f,
+0x70, 0x4d, 0x5e, 0xe3, 0x29, 0xf1, 0x23, 0x28, 0x72, 0x59, 0xb6, 0xab, 0xc2, 0x8c, 0x66, 0x26,
+0x1c, 0x77, 0x2c, 0x26, 0x76, 0x35, 0x8b, 0x28, 0xa7, 0x69, 0xa0, 0xf9, 0x3b, 0xf5, 0x23, 0xdd,
+0x85, 0x10, 0x74, 0xc9, 0x90, 0x03, 0x56, 0x91, 0xe7, 0xaf, 0xba, 0x47, 0xd4, 0x12, 0x97, 0x11,
+0x22, 0xe3, 0xa2, 0x49, 0x94, 0x6c, 0xe7, 0xb7, 0x94, 0x4b, 0xba, 0x2d, 0xa4, 0xda, 0x33, 0x8b,
+0x4c, 0xa6, 0x44, 0xff, 0x5a, 0x3c, 0xc6, 0x1d, 0x64, 0xd8, 0xb5, 0x31, 0xe4, 0xa6, 0x3c, 0x7a,
+0xa8, 0x57, 0x0b, 0xdb, 0xed, 0x61, 0x1a, 0xcb, 0xf1, 0xce, 0x73, 0x77, 0x63, 0xa4, 0x87, 0x6f,
+0x4c, 0x51, 0x38, 0xd6, 0xe4, 0x5f, 0xc7, 0x9f, 0xb6, 0x81, 0x2a, 0xe4, 0x85, 0x48, 0x79, 0x58,
+0x5e, 0x3b, 0xf8, 0xdb, 0x02, 0x82, 0x67, 0xc1, 0x39, 0xdb, 0xc3, 0x74, 0x4b, 0x3d, 0x36, 0x1e,
+0xf9, 0x29, 0x93, 0x88, 0x68, 0x5b, 0xa8, 0x44, 0x19, 0x21, 0xf0, 0xa7, 0xe8, 0x81, 0x0d, 0x2c,
+0xe8, 0x93, 0x36, 0xb4, 0x37, 0xb2, 0xca, 0xb0, 0x1b, 0x26, 0x7a, 0x9a, 0x25, 0x1f, 0x9a, 0x9a,
+0x80, 0x9e, 0x4b, 0x2a, 0x3f, 0xfb, 0xa3, 0x9a, 0xfe, 0x73, 0x32, 0x71, 0xc2, 0x9e, 0xc6, 0x72,
+0xe1, 0x8a, 0x68, 0x27, 0xf1, 0xe4, 0x0f, 0xb4, 0xc4, 0x4c, 0xa5, 0x61, 0x93, 0xf8, 0x97, 0x10,
+0x07, 0x2a, 0x30, 0x25, 0xa9, 0xb9, 0xc8, 0x71, 0xb8, 0xef, 0x68, 0xcc, 0x2d, 0x7e, 0xf5, 0xe0,
+0x7e, 0x0f, 0x82, 0xa8, 0x6f, 0xb6, 0xba, 0x6c, 0x83, 0x43, 0x77, 0xcd, 0x8a, 0x92, 0x17, 0xa1,
+0x9e, 0x5b, 0x78, 0x16, 0x3d, 0x45, 0xe2, 0x33, 0x72, 0xdd, 0xe1, 0x66, 0xca, 0x99, 0xd3, 0xc9,
+0xc5, 0x26, 0xfd, 0x0d, 0x68, 0x04, 0x46, 0xae, 0xb6, 0xd9, 0x9b, 0x8c, 0xbe, 0x19, 0xbe, 0xb1,
+0xc6, 0xf2, 0x19, 0xe3, 0x5c, 0x02, 0xca, 0x2c, 0xd8, 0x6f, 0x4a, 0x07, 0xd9, 0xc9, 0x35, 0xda,
+0x40, 0x75, 0xf2, 0xc4, 0xa7, 0x19, 0x6f, 0x9e, 0x42, 0x10, 0x98, 0x75, 0xe6, 0x95, 0x8b, 0x60,
+0xbc, 0xed, 0xc5, 0x12, 0xd7, 0x8a, 0xce, 0xd5, 0x98, 0x5c, 0x56, 0x96, 0x03, 0xc5, 0xee, 0x77,
+0x06, 0x35, 0xff, 0xcf, 0xe4, 0xee, 0x3f, 0x13, 0x61, 0xee, 0xdb, 0xda, 0x2d, 0x85, 0xf0, 0xcd,
+0xae, 0x9d, 0xb2, 0x18, 0x09, 0x45, 0xc3, 0x92, 0xa1, 0x72, 0x17, 0xfc, 0x47, 0xb6, 0xa0, 0x0b,
+0x2c, 0xf1, 0xc4, 0xde, 0x43, 0x68, 0x08, 0x6a, 0x5f, 0x3b, 0xf0, 0x76, 0x63, 0xfb, 0xcc, 0x06,
+0x2c, 0xa6, 0xc6, 0xe2, 0x0e, 0xb5, 0xb9, 0xbe, 0x24, 0x8f, 0x30, 0x82, 0x02, 0x6e, 0x30, 0x82,
+0x01, 0xf3, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x62, 0xf6, 0x32, 0x6c, 0xe5, 0xc4, 0xe3,
+0x68, 0x5c, 0x1b, 0x62, 0xdd, 0x9c, 0x2e, 0x9d, 0x95, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
+0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x78, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x45, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x46,
+0x4e, 0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x0c, 0x05, 0x43, 0x65, 0x72, 0x65, 0x73, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x61,
+0x0c, 0x0f, 0x56, 0x41, 0x54, 0x45, 0x53, 0x2d, 0x51, 0x32, 0x38, 0x32, 0x36, 0x30, 0x30, 0x34,
+0x4a, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x23, 0x41, 0x43, 0x20, 0x52,
+0x41, 0x49, 0x5a, 0x20, 0x46, 0x4e, 0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, 0x20, 0x53, 0x45, 0x52,
+0x56, 0x49, 0x44, 0x4f, 0x52, 0x45, 0x53, 0x20, 0x53, 0x45, 0x47, 0x55, 0x52, 0x4f, 0x53, 0x30,
+0x1e, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x32, 0x32, 0x30, 0x30, 0x39, 0x33, 0x37, 0x33, 0x33, 0x5a,
+0x17, 0x0d, 0x34, 0x33, 0x31, 0x32, 0x32, 0x30, 0x30, 0x39, 0x33, 0x37, 0x33, 0x33, 0x5a, 0x30,
+0x78, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x11,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x46, 0x4e, 0x4d, 0x54, 0x2d, 0x52, 0x43,
+0x4d, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x05, 0x43, 0x65, 0x72, 0x65,
+0x73, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x61, 0x0c, 0x0f, 0x56, 0x41, 0x54, 0x45,
+0x53, 0x2d, 0x51, 0x32, 0x38, 0x32, 0x36, 0x30, 0x30, 0x34, 0x4a, 0x31, 0x2c, 0x30, 0x2a, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x0c, 0x23, 0x41, 0x43, 0x20, 0x52, 0x41, 0x49, 0x5a, 0x20, 0x46, 0x4e,
+0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, 0x20, 0x53, 0x45, 0x52, 0x56, 0x49, 0x44, 0x4f, 0x52, 0x45,
+0x53, 0x20, 0x53, 0x45, 0x47, 0x55, 0x52, 0x4f, 0x53, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a,
+0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00,
+0x04, 0xf6, 0xba, 0x57, 0x53, 0xc8, 0xca, 0xab, 0xdf, 0x36, 0x4a, 0x52, 0x21, 0xe4, 0x97, 0xd2,
+0x83, 0x67, 0x9e, 0xf0, 0x65, 0x51, 0xd0, 0x5e, 0x87, 0xc7, 0x47, 0xb1, 0x59, 0xf2, 0x57, 0x47,
+0x9b, 0x00, 0x02, 0x93, 0x44, 0x17, 0x69, 0xdb, 0x42, 0xc7, 0xb1, 0xb2, 0x3a, 0x18, 0x0e, 0xb4,
+0x5d, 0x8c, 0xb3, 0x66, 0x5d, 0xa1, 0x34, 0xf9, 0x36, 0x2c, 0x49, 0xdb, 0xf3, 0x46, 0xfc, 0xb3,
+0x44, 0x69, 0x44, 0x13, 0x66, 0xfd, 0xd7, 0xc5, 0xfd, 0xaf, 0x36, 0x4d, 0xce, 0x03, 0x4d, 0x07,
+0x71, 0xcf, 0xaf, 0x6a, 0x05, 0xd2, 0xa2, 0x43, 0x5a, 0x0a, 0x52, 0x6f, 0x01, 0x03, 0x4e, 0x8e,
+0x8b, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+0x14, 0x01, 0xb9, 0x2f, 0xef, 0xbf, 0x11, 0x86, 0x60, 0xf2, 0x4f, 0xd0, 0x41, 0x6e, 0xab, 0x73,
+0x1f, 0xe7, 0xd2, 0x6e, 0x49, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03,
+0x03, 0x03, 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00, 0xae, 0x4a, 0xe3, 0x2b, 0x40, 0xc3, 0x74,
+0x11, 0xf2, 0x95, 0xad, 0x16, 0x23, 0xde, 0x4e, 0x0c, 0x1a, 0xe6, 0x5d, 0xa5, 0x24, 0x5e, 0x6b,
+0x44, 0x7b, 0xfc, 0x38, 0xe2, 0x4f, 0xcb, 0x9c, 0x45, 0x17, 0x11, 0x4c, 0x14, 0x27, 0x26, 0x55,
+0x39, 0x75, 0x4a, 0x03, 0xcc, 0x13, 0x90, 0x9f, 0x92, 0x02, 0x31, 0x00, 0xfa, 0x4a, 0x6c, 0x60,
+0x88, 0x73, 0xf3, 0xee, 0xb8, 0x98, 0x62, 0xa9, 0xce, 0x2b, 0xc2, 0xd9, 0x8a, 0xa6, 0x70, 0x31,
+0x1d, 0xaf, 0xb0, 0x94, 0x4c, 0xeb, 0x4f, 0xc6, 0xe3, 0xd1, 0xf3, 0x62, 0xa7, 0x3c, 0xff, 0x93,
+0x2e, 0x07, 0x5c, 0x49, 0x01, 0x67, 0x69, 0x12, 0x02, 0x72, 0xbf, 0xe7, 0x30, 0x82, 0x05, 0x6b,
+0x30, 0x82, 0x03, 0x53, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 0x82, 0x10, 0xcf, 0xb0,
+0xd2, 0x40, 0xe3, 0x59, 0x44, 0x63, 0xe0, 0xbb, 0x63, 0x82, 0x8b, 0x00, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x4f, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x53, 0x65,
+0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20,
+0x47, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0c,
+0x49, 0x53, 0x52, 0x47, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x58, 0x31, 0x30, 0x1e, 0x17, 0x0d,
+0x31, 0x35, 0x30, 0x36, 0x30, 0x34, 0x31, 0x31, 0x30, 0x34, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x33,
+0x35, 0x30, 0x36, 0x30, 0x34, 0x31, 0x31, 0x30, 0x34, 0x33, 0x38, 0x5a, 0x30, 0x4f, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x29, 0x30, 0x27, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x53,
+0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68,
+0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+0x0c, 0x49, 0x53, 0x52, 0x47, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x58, 0x31, 0x30, 0x82, 0x02,
+0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xad, 0xe8,
+0x24, 0x73, 0xf4, 0x14, 0x37, 0xf3, 0x9b, 0x9e, 0x2b, 0x57, 0x28, 0x1c, 0x87, 0xbe, 0xdc, 0xb7,
+0xdf, 0x38, 0x90, 0x8c, 0x6e, 0x3c, 0xe6, 0x57, 0xa0, 0x78, 0xf7, 0x75, 0xc2, 0xa2, 0xfe, 0xf5,
+0x6a, 0x6e, 0xf6, 0x00, 0x4f, 0x28, 0xdb, 0xde, 0x68, 0x86, 0x6c, 0x44, 0x93, 0xb6, 0xb1, 0x63,
+0xfd, 0x14, 0x12, 0x6b, 0xbf, 0x1f, 0xd2, 0xea, 0x31, 0x9b, 0x21, 0x7e, 0xd1, 0x33, 0x3c, 0xba,
+0x48, 0xf5, 0xdd, 0x79, 0xdf, 0xb3, 0xb8, 0xff, 0x12, 0xf1, 0x21, 0x9a, 0x4b, 0xc1, 0x8a, 0x86,
+0x71, 0x69, 0x4a, 0x66, 0x66, 0x6c, 0x8f, 0x7e, 0x3c, 0x70, 0xbf, 0xad, 0x29, 0x22, 0x06, 0xf3,
+0xe4, 0xc0, 0xe6, 0x80, 0xae, 0xe2, 0x4b, 0x8f, 0xb7, 0x99, 0x7e, 0x94, 0x03, 0x9f, 0xd3, 0x47,
+0x97, 0x7c, 0x99, 0x48, 0x23, 0x53, 0xe8, 0x38, 0xae, 0x4f, 0x0a, 0x6f, 0x83, 0x2e, 0xd1, 0x49,
+0x57, 0x8c, 0x80, 0x74, 0xb6, 0xda, 0x2f, 0xd0, 0x38, 0x8d, 0x7b, 0x03, 0x70, 0x21, 0x1b, 0x75,
+0xf2, 0x30, 0x3c, 0xfa, 0x8f, 0xae, 0xdd, 0xda, 0x63, 0xab, 0xeb, 0x16, 0x4f, 0xc2, 0x8e, 0x11,
+0x4b, 0x7e, 0xcf, 0x0b, 0xe8, 0xff, 0xb5, 0x77, 0x2e, 0xf4, 0xb2, 0x7b, 0x4a, 0xe0, 0x4c, 0x12,
+0x25, 0x0c, 0x70, 0x8d, 0x03, 0x29, 0xa0, 0xe1, 0x53, 0x24, 0xec, 0x13, 0xd9, 0xee, 0x19, 0xbf,
+0x10, 0xb3, 0x4a, 0x8c, 0x3f, 0x89, 0xa3, 0x61, 0x51, 0xde, 0xac, 0x87, 0x07, 0x94, 0xf4, 0x63,
+0x71, 0xec, 0x2e, 0xe2, 0x6f, 0x5b, 0x98, 0x81, 0xe1, 0x89, 0x5c, 0x34, 0x79, 0x6c, 0x76, 0xef,
+0x3b, 0x90, 0x62, 0x79, 0xe6, 0xdb, 0xa4, 0x9a, 0x2f, 0x26, 0xc5, 0xd0, 0x10, 0xe1, 0x0e, 0xde,
+0xd9, 0x10, 0x8e, 0x16, 0xfb, 0xb7, 0xf7, 0xa8, 0xf7, 0xc7, 0xe5, 0x02, 0x07, 0x98, 0x8f, 0x36,
+0x08, 0x95, 0xe7, 0xe2, 0x37, 0x96, 0x0d, 0x36, 0x75, 0x9e, 0xfb, 0x0e, 0x72, 0xb1, 0x1d, 0x9b,
+0xbc, 0x03, 0xf9, 0x49, 0x05, 0xd8, 0x81, 0xdd, 0x05, 0xb4, 0x2a, 0xd6, 0x41, 0xe9, 0xac, 0x01,
+0x76, 0x95, 0x0a, 0x0f, 0xd8, 0xdf, 0xd5, 0xbd, 0x12, 0x1f, 0x35, 0x2f, 0x28, 0x17, 0x6c, 0xd2,
+0x98, 0xc1, 0xa8, 0x09, 0x64, 0x77, 0x6e, 0x47, 0x37, 0xba, 0xce, 0xac, 0x59, 0x5e, 0x68, 0x9d,
+0x7f, 0x72, 0xd6, 0x89, 0xc5, 0x06, 0x41, 0x29, 0x3e, 0x59, 0x3e, 0xdd, 0x26, 0xf5, 0x24, 0xc9,
+0x11, 0xa7, 0x5a, 0xa3, 0x4c, 0x40, 0x1f, 0x46, 0xa1, 0x99, 0xb5, 0xa7, 0x3a, 0x51, 0x6e, 0x86,
+0x3b, 0x9e, 0x7d, 0x72, 0xa7, 0x12, 0x05, 0x78, 0x59, 0xed, 0x3e, 0x51, 0x78, 0x15, 0x0b, 0x03,
+0x8f, 0x8d, 0xd0, 0x2f, 0x05, 0xb2, 0x3e, 0x7b, 0x4a, 0x1c, 0x4b, 0x73, 0x05, 0x12, 0xfc, 0xc6,
+0xea, 0xe0, 0x50, 0x13, 0x7c, 0x43, 0x93, 0x74, 0xb3, 0xca, 0x74, 0xe7, 0x8e, 0x1f, 0x01, 0x08,
+0xd0, 0x30, 0xd4, 0x5b, 0x71, 0x36, 0xb4, 0x07, 0xba, 0xc1, 0x30, 0x30, 0x5c, 0x48, 0xb7, 0x82,
+0x3b, 0x98, 0xa6, 0x7d, 0x60, 0x8a, 0xa2, 0xa3, 0x29, 0x82, 0xcc, 0xba, 0xbd, 0x83, 0x04, 0x1b,
+0xa2, 0x83, 0x03, 0x41, 0xa1, 0xd6, 0x05, 0xf1, 0x1b, 0xc2, 0xb6, 0xf0, 0xa8, 0x7c, 0x86, 0x3b,
+0x46, 0xa8, 0x48, 0x2a, 0x88, 0xdc, 0x76, 0x9a, 0x76, 0xbf, 0x1f, 0x6a, 0xa5, 0x3d, 0x19, 0x8f,
+0xeb, 0x38, 0xf3, 0x64, 0xde, 0xc8, 0x2b, 0x0d, 0x0a, 0x28, 0xff, 0xf7, 0xdb, 0xe2, 0x15, 0x42,
+0xd4, 0x22, 0xd0, 0x27, 0x5d, 0xe1, 0x79, 0xfe, 0x18, 0xe7, 0x70, 0x88, 0xad, 0x4e, 0xe6, 0xd9,
+0x8b, 0x3a, 0xc6, 0xdd, 0x27, 0x51, 0x6e, 0xff, 0xbc, 0x64, 0xf5, 0x33, 0x43, 0x4f, 0x02, 0x03,
+0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+0x16, 0x04, 0x14, 0x79, 0xb4, 0x59, 0xe6, 0x7b, 0xb6, 0xe5, 0xe4, 0x01, 0x73, 0x80, 0x08, 0x88,
+0xc8, 0x1a, 0x58, 0xf6, 0xe9, 0x9b, 0x6e, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x55, 0x1f, 0x58, 0xa9, 0xbc,
+0xb2, 0xa8, 0x50, 0xd0, 0x0c, 0xb1, 0xd8, 0x1a, 0x69, 0x20, 0x27, 0x29, 0x08, 0xac, 0x61, 0x75,
+0x5c, 0x8a, 0x6e, 0xf8, 0x82, 0xe5, 0x69, 0x2f, 0xd5, 0xf6, 0x56, 0x4b, 0xb9, 0xb8, 0x73, 0x10,
+0x59, 0xd3, 0x21, 0x97, 0x7e, 0xe7, 0x4c, 0x71, 0xfb, 0xb2, 0xd2, 0x60, 0xad, 0x39, 0xa8, 0x0b,
+0xea, 0x17, 0x21, 0x56, 0x85, 0xf1, 0x50, 0x0e, 0x59, 0xeb, 0xce, 0xe0, 0x59, 0xe9, 0xba, 0xc9,
+0x15, 0xef, 0x86, 0x9d, 0x8f, 0x84, 0x80, 0xf6, 0xe4, 0xe9, 0x91, 0x90, 0xdc, 0x17, 0x9b, 0x62,
+0x1b, 0x45, 0xf0, 0x66, 0x95, 0xd2, 0x7c, 0x6f, 0xc2, 0xea, 0x3b, 0xef, 0x1f, 0xcf, 0xcb, 0xd6,
+0xae, 0x27, 0xf1, 0xa9, 0xb0, 0xc8, 0xae, 0xfd, 0x7d, 0x7e, 0x9a, 0xfa, 0x22, 0x04, 0xeb, 0xff,
+0xd9, 0x7f, 0xea, 0x91, 0x2b, 0x22, 0xb1, 0x17, 0x0e, 0x8f, 0xf2, 0x8a, 0x34, 0x5b, 0x58, 0xd8,
+0xfc, 0x01, 0xc9, 0x54, 0xb9, 0xb8, 0x26, 0xcc, 0x8a, 0x88, 0x33, 0x89, 0x4c, 0x2d, 0x84, 0x3c,
+0x82, 0xdf, 0xee, 0x96, 0x57, 0x05, 0xba, 0x2c, 0xbb, 0xf7, 0xc4, 0xb7, 0xc7, 0x4e, 0x3b, 0x82,
+0xbe, 0x31, 0xc8, 0x22, 0x73, 0x73, 0x92, 0xd1, 0xc2, 0x80, 0xa4, 0x39, 0x39, 0x10, 0x33, 0x23,
+0x82, 0x4c, 0x3c, 0x9f, 0x86, 0xb2, 0x55, 0x98, 0x1d, 0xbe, 0x29, 0x86, 0x8c, 0x22, 0x9b, 0x9e,
+0xe2, 0x6b, 0x3b, 0x57, 0x3a, 0x82, 0x70, 0x4d, 0xdc, 0x09, 0xc7, 0x89, 0xcb, 0x0a, 0x07, 0x4d,
+0x6c, 0xe8, 0x5d, 0x8e, 0xc9, 0xef, 0xce, 0xab, 0xc7, 0xbb, 0xb5, 0x2b, 0x4e, 0x45, 0xd6, 0x4a,
+0xd0, 0x26, 0xcc, 0xe5, 0x72, 0xca, 0x08, 0x6a, 0xa5, 0x95, 0xe3, 0x15, 0xa1, 0xf7, 0xa4, 0xed,
+0xc9, 0x2c, 0x5f, 0xa5, 0xfb, 0xff, 0xac, 0x28, 0x02, 0x2e, 0xbe, 0xd7, 0x7b, 0xbb, 0xe3, 0x71,
+0x7b, 0x90, 0x16, 0xd3, 0x07, 0x5e, 0x46, 0x53, 0x7c, 0x37, 0x07, 0x42, 0x8c, 0xd3, 0xc4, 0x96,
+0x9c, 0xd5, 0x99, 0xb5, 0x2a, 0xe0, 0x95, 0x1a, 0x80, 0x48, 0xae, 0x4c, 0x39, 0x07, 0xce, 0xcc,
+0x47, 0xa4, 0x52, 0x95, 0x2b, 0xba, 0xb8, 0xfb, 0xad, 0xd2, 0x33, 0x53, 0x7d, 0xe5, 0x1d, 0x4d,
+0x6d, 0xd5, 0xa1, 0xb1, 0xc7, 0x42, 0x6f, 0xe6, 0x40, 0x27, 0x35, 0x5c, 0xa3, 0x28, 0xb7, 0x07,
+0x8d, 0xe7, 0x8d, 0x33, 0x90, 0xe7, 0x23, 0x9f, 0xfb, 0x50, 0x9c, 0x79, 0x6c, 0x46, 0xd5, 0xb4,
+0x15, 0xb3, 0x96, 0x6e, 0x7e, 0x9b, 0x0c, 0x96, 0x3a, 0xb8, 0x52, 0x2d, 0x3f, 0xd6, 0x5b, 0xe1,
+0xfb, 0x08, 0xc2, 0x84, 0xfe, 0x24, 0xa8, 0xa3, 0x89, 0xda, 0xac, 0x6a, 0xe1, 0x18, 0x2a, 0xb1,
+0xa8, 0x43, 0x61, 0x5b, 0xd3, 0x1f, 0xdc, 0x3b, 0x8d, 0x76, 0xf2, 0x2d, 0xe8, 0x8d, 0x75, 0xdf,
+0x17, 0x33, 0x6c, 0x3d, 0x53, 0xfb, 0x7b, 0xcb, 0x41, 0x5f, 0xff, 0xdc, 0xa2, 0xd0, 0x61, 0x38,
+0xe1, 0x96, 0xb8, 0xac, 0x5d, 0x8b, 0x37, 0xd7, 0x75, 0xd5, 0x33, 0xc0, 0x99, 0x11, 0xae, 0x9d,
+0x41, 0xc1, 0x72, 0x75, 0x84, 0xbe, 0x02, 0x41, 0x42, 0x5f, 0x67, 0x24, 0x48, 0x94, 0xd1, 0x9b,
+0x27, 0xbe, 0x07, 0x3f, 0xb9, 0xb8, 0x4f, 0x81, 0x74, 0x51, 0xe1, 0x7a, 0xb7, 0xed, 0x9d, 0x23,
+0xe2, 0xbe, 0xe0, 0xd5, 0x28, 0x04, 0x13, 0x3c, 0x31, 0x03, 0x9e, 0xdd, 0x7a, 0x6c, 0x8f, 0xc6,
+0x07, 0x18, 0xc6, 0x7f, 0xde, 0x47, 0x8e, 0x3f, 0x28, 0x9e, 0x04, 0x06, 0xcf, 0xa5, 0x54, 0x34,
+0x77, 0xbd, 0xec, 0x89, 0x9b, 0xe9, 0x17, 0x43, 0xdf, 0x5b, 0xdb, 0x5f, 0xfe, 0x8e, 0x1e, 0x57,
+0xa2, 0xcd, 0x40, 0x9d, 0x7e, 0x62, 0x22, 0xda, 0xde, 0x18, 0x27, 0x30, 0x82, 0x04, 0x63, 0x30,
+0x82, 0x03, 0x4b, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xd2, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54, 0x52, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
+0x55, 0x04, 0x07, 0x13, 0x0f, 0x47, 0x65, 0x62, 0x7a, 0x65, 0x20, 0x2d, 0x20, 0x4b, 0x6f, 0x63,
+0x61, 0x65, 0x6c, 0x69, 0x31, 0x42, 0x30, 0x40, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x39, 0x54,
+0x75, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x20, 0x42, 0x69, 0x6c, 0x69, 0x6d, 0x73, 0x65, 0x6c, 0x20,
+0x76, 0x65, 0x20, 0x54, 0x65, 0x6b, 0x6e, 0x6f, 0x6c, 0x6f, 0x6a, 0x69, 0x6b, 0x20, 0x41, 0x72,
+0x61, 0x73, 0x74, 0x69, 0x72, 0x6d, 0x61, 0x20, 0x4b, 0x75, 0x72, 0x75, 0x6d, 0x75, 0x20, 0x2d,
+0x20, 0x54, 0x55, 0x42, 0x49, 0x54, 0x41, 0x4b, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04,
+0x0b, 0x13, 0x24, 0x4b, 0x61, 0x6d, 0x75, 0x20, 0x53, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x6b,
+0x61, 0x73, 0x79, 0x6f, 0x6e, 0x20, 0x4d, 0x65, 0x72, 0x6b, 0x65, 0x7a, 0x69, 0x20, 0x2d, 0x20,
+0x4b, 0x61, 0x6d, 0x75, 0x20, 0x53, 0x4d, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x2d, 0x54, 0x55, 0x42, 0x49, 0x54, 0x41, 0x4b, 0x20, 0x4b, 0x61, 0x6d, 0x75, 0x20, 0x53,
+0x4d, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x4b, 0x6f, 0x6b, 0x20, 0x53, 0x65, 0x72, 0x74, 0x69, 0x66,
+0x69, 0x6b, 0x61, 0x73, 0x69, 0x20, 0x2d, 0x20, 0x53, 0x75, 0x72, 0x75, 0x6d, 0x20, 0x31, 0x30,
+0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31, 0x31, 0x32, 0x35, 0x30, 0x38, 0x32, 0x35, 0x35, 0x35, 0x5a,
+0x17, 0x0d, 0x34, 0x33, 0x31, 0x30, 0x32, 0x35, 0x30, 0x38, 0x32, 0x35, 0x35, 0x35, 0x5a, 0x30,
+0x81, 0xd2, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54, 0x52, 0x31,
+0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0f, 0x47, 0x65, 0x62, 0x7a, 0x65, 0x20,
+0x2d, 0x20, 0x4b, 0x6f, 0x63, 0x61, 0x65, 0x6c, 0x69, 0x31, 0x42, 0x30, 0x40, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x39, 0x54, 0x75, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x20, 0x42, 0x69, 0x6c, 0x69,
+0x6d, 0x73, 0x65, 0x6c, 0x20, 0x76, 0x65, 0x20, 0x54, 0x65, 0x6b, 0x6e, 0x6f, 0x6c, 0x6f, 0x6a,
+0x69, 0x6b, 0x20, 0x41, 0x72, 0x61, 0x73, 0x74, 0x69, 0x72, 0x6d, 0x61, 0x20, 0x4b, 0x75, 0x72,
+0x75, 0x6d, 0x75, 0x20, 0x2d, 0x20, 0x54, 0x55, 0x42, 0x49, 0x54, 0x41, 0x4b, 0x31, 0x2d, 0x30,
+0x2b, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x24, 0x4b, 0x61, 0x6d, 0x75, 0x20, 0x53, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x6b, 0x61, 0x73, 0x79, 0x6f, 0x6e, 0x20, 0x4d, 0x65, 0x72, 0x6b, 0x65,
+0x7a, 0x69, 0x20, 0x2d, 0x20, 0x4b, 0x61, 0x6d, 0x75, 0x20, 0x53, 0x4d, 0x31, 0x36, 0x30, 0x34,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, 0x54, 0x55, 0x42, 0x49, 0x54, 0x41, 0x4b, 0x20, 0x4b,
+0x61, 0x6d, 0x75, 0x20, 0x53, 0x4d, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x4b, 0x6f, 0x6b, 0x20, 0x53,
+0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x6b, 0x61, 0x73, 0x69, 0x20, 0x2d, 0x20, 0x53, 0x75, 0x72,
+0x75, 0x6d, 0x20, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, 0x75, 0x30, 0x33, 0xaa, 0xbb, 0x6b, 0xd3, 0x99, 0x2c, 0x12,
+0x37, 0x84, 0xd9, 0x8d, 0x7b, 0x97, 0x80, 0xd3, 0x6e, 0xe7, 0xff, 0x9b, 0x50, 0x95, 0x3e, 0x90,
+0x95, 0x56, 0x42, 0xd7, 0x19, 0x7c, 0x26, 0x84, 0x8d, 0x92, 0xfa, 0x01, 0x1d, 0x3a, 0x0f, 0xe2,
+0x64, 0x38, 0xb7, 0x8c, 0xbc, 0xe8, 0x88, 0xf9, 0x8b, 0x24, 0xab, 0x2e, 0xa3, 0xf5, 0x37, 0xe4,
+0x40, 0x8e, 0x18, 0x25, 0x79, 0x83, 0x75, 0x1f, 0x3b, 0xff, 0x6c, 0xa8, 0xc5, 0xc6, 0x56, 0xf8,
+0xb4, 0xed, 0x8a, 0x44, 0xa3, 0xab, 0x6c, 0x4c, 0xfc, 0x1d, 0xd0, 0xdc, 0xef, 0x68, 0xbd, 0xcf,
+0xe4, 0xaa, 0xce, 0xf0, 0x55, 0xf7, 0xa2, 0x34, 0xd4, 0x83, 0x6b, 0x37, 0x7c, 0x1c, 0xc2, 0xfe,
+0xb5, 0x03, 0xec, 0x57, 0xce, 0xbc, 0xb4, 0xb5, 0xc5, 0xed, 0x00, 0x0f, 0x53, 0x37, 0x2a, 0x4d,
+0xf4, 0x4f, 0x0c, 0x83, 0xfb, 0x86, 0xcf, 0xcb, 0xfe, 0x8c, 0x4e, 0xbd, 0x87, 0xf9, 0xa7, 0x8b,
+0x21, 0x57, 0x9c, 0x7a, 0xdf, 0x03, 0x67, 0x89, 0x2c, 0x9d, 0x97, 0x61, 0xa7, 0x10, 0xb8, 0x55,
+0x90, 0x7f, 0x0e, 0x2d, 0x27, 0x38, 0x74, 0xdf, 0xe7, 0xfd, 0xda, 0x4e, 0x12, 0xe3, 0x4d, 0x15,
+0x22, 0x02, 0xc8, 0xe0, 0xe0, 0xfc, 0x0f, 0xad, 0x8a, 0xd7, 0xc9, 0x54, 0x50, 0xcc, 0x3b, 0x0f,
+0xca, 0x16, 0x80, 0x84, 0xd0, 0x51, 0x56, 0xc3, 0x8e, 0x56, 0x7f, 0x89, 0x22, 0x33, 0x2f, 0xe6,
+0x85, 0x0a, 0xbd, 0xa5, 0xa8, 0x1b, 0x36, 0xde, 0xd3, 0xdc, 0x2c, 0x6d, 0x3b, 0xc7, 0x13, 0xbd,
+0x59, 0x23, 0x2c, 0xe6, 0xe5, 0xa4, 0xf7, 0xd8, 0x0b, 0xed, 0xea, 0x90, 0x40, 0x44, 0xa8, 0x95,
+0xbb, 0x93, 0xd5, 0xd0, 0x80, 0x34, 0xb6, 0x46, 0x78, 0x0e, 0x1f, 0x00, 0x93, 0x46, 0xe1, 0xee,
+0xe9, 0xf9, 0xec, 0x4f, 0x17, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0x3f, 0xc7, 0x8a, 0x86, 0xc6, 0x3c,
+0xdd, 0x3c, 0x54, 0x5c, 0x35, 0xf8, 0x3a, 0xed, 0x52, 0x0c, 0x47, 0x57, 0xc8, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01,
+0x01, 0x00, 0x2a, 0x3f, 0xe1, 0xf1, 0x32, 0x8e, 0xae, 0xe1, 0x98, 0x5c, 0x4b, 0x5e, 0xcf, 0x6b,
+0x1e, 0x6a, 0x09, 0xd2, 0x22, 0xa9, 0x12, 0xc7, 0x5e, 0x57, 0x7d, 0x73, 0x56, 0x64, 0x80, 0x84,
+0x7a, 0x93, 0xe4, 0x09, 0xb9, 0x10, 0xcd, 0x9f, 0x2a, 0x27, 0xe1, 0x00, 0x77, 0xbe, 0x48, 0xc8,
+0x35, 0xa8, 0x81, 0x9f, 0xe4, 0xb8, 0x2c, 0xc9, 0x7f, 0x0e, 0xb0, 0xd2, 0x4b, 0x37, 0x5d, 0xea,
+0xb9, 0xd5, 0x0b, 0x5e, 0x34, 0xbd, 0xf4, 0x73, 0x29, 0xc3, 0xed, 0x26, 0x15, 0x9c, 0x7e, 0x08,
+0x53, 0x8a, 0x58, 0x8d, 0xd0, 0x4b, 0x28, 0xdf, 0xc1, 0xb3, 0xdf, 0x20, 0xf3, 0xf9, 0xe3, 0xe3,
+0x3a, 0xdf, 0xcc, 0x9c, 0x94, 0xd8, 0x4e, 0x4f, 0xc3, 0x6b, 0x17, 0xb7, 0xf7, 0x72, 0xe8, 0xad,
+0x66, 0x33, 0xb5, 0x25, 0x53, 0xab, 0xe0, 0xf8, 0x4c, 0xa9, 0x9d, 0xfd, 0xf2, 0x0d, 0xba, 0xae,
+0xb9, 0xd9, 0xaa, 0xc6, 0x6b, 0xf9, 0x93, 0xbb, 0xae, 0xab, 0xb8, 0x97, 0x3c, 0x03, 0x1a, 0xba,
+0x43, 0xc6, 0x96, 0xb9, 0x45, 0x72, 0x38, 0xb3, 0xa7, 0xa1, 0x96, 0x3d, 0x91, 0x7b, 0x7e, 0xc0,
+0x21, 0x53, 0x4c, 0x87, 0xed, 0xf2, 0x0b, 0x54, 0x95, 0x51, 0x93, 0xd5, 0x22, 0xa5, 0x0d, 0x8a,
+0xf1, 0x93, 0x0e, 0x3e, 0x54, 0x0e, 0xb0, 0xd8, 0xc9, 0x4e, 0xdc, 0xf2, 0x31, 0x32, 0x56, 0xea,
+0x64, 0xf9, 0xea, 0xb5, 0x9d, 0x16, 0x66, 0x42, 0x72, 0xf3, 0x7f, 0xd3, 0xb1, 0x31, 0x43, 0xfc,
+0xa4, 0x8e, 0x17, 0xf1, 0x6d, 0x23, 0xab, 0x94, 0x66, 0xf8, 0xad, 0xfb, 0x0f, 0x08, 0x6e, 0x26,
+0x2d, 0x7f, 0x17, 0x07, 0x09, 0xb2, 0x8c, 0xfb, 0x50, 0xc0, 0x9f, 0x96, 0x8d, 0xcf, 0xb6, 0xfd,
+0x00, 0x9d, 0x5a, 0x14, 0x9a, 0xbf, 0x02, 0x44, 0xf5, 0xc1, 0xc2, 0x9f, 0x22, 0x5e, 0xa2, 0x0f,
+0xa1, 0xe3, 0x30, 0x82, 0x01, 0xb6, 0x30, 0x82, 0x01, 0x5b, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+0x13, 0x06, 0x6c, 0x9f, 0xd5, 0x74, 0x97, 0x36, 0x66, 0x3f, 0x3b, 0x0b, 0x9a, 0xd9, 0xe8, 0x9e,
+0x76, 0x03, 0xf2, 0x4a, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+0x30, 0x39, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x06, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e,
+0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 0x6d, 0x61, 0x7a, 0x6f,
+0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+0x35, 0x30, 0x35, 0x32, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x30,
+0x30, 0x35, 0x32, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x39, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x06, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x31, 0x19, 0x30, 0x17, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f,
+0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce,
+0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
+0x04, 0x29, 0x97, 0xa7, 0xc6, 0x41, 0x7f, 0xc0, 0x0d, 0x9b, 0xe8, 0x01, 0x1b, 0x56, 0xc6, 0xf2,
+0x52, 0xa5, 0xba, 0x2d, 0xb2, 0x12, 0xe8, 0xd2, 0x2e, 0xd7, 0xfa, 0xc9, 0xc5, 0xd8, 0xaa, 0x6d,
+0x1f, 0x73, 0x81, 0x3b, 0x3b, 0x98, 0x6b, 0x39, 0x7c, 0x33, 0xa5, 0xc5, 0x4e, 0x86, 0x8e, 0x80,
+0x17, 0x68, 0x62, 0x45, 0x57, 0x7d, 0x44, 0x58, 0x1d, 0xb3, 0x37, 0xe5, 0x67, 0x08, 0xeb, 0x66,
+0xde, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+0x14, 0xab, 0xb6, 0xdb, 0xd7, 0x06, 0x9e, 0x37, 0xac, 0x30, 0x86, 0x07, 0x91, 0x70, 0xc7, 0x9c,
+0xc4, 0x19, 0xb1, 0x78, 0xc0, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03,
+0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0xe0, 0x85, 0x92, 0xa3, 0x17, 0xb7, 0x8d,
+0xf9, 0x2b, 0x06, 0xa5, 0x93, 0xac, 0x1a, 0x98, 0x68, 0x61, 0x72, 0xfa, 0xe1, 0xa1, 0xd0, 0xfb,
+0x1c, 0x78, 0x60, 0xa6, 0x43, 0x99, 0xc5, 0xb8, 0xc4, 0x02, 0x21, 0x00, 0x9c, 0x02, 0xef, 0xf1,
+0x94, 0x9c, 0xb3, 0x96, 0xf9, 0xeb, 0xc6, 0x2a, 0xf8, 0xb6, 0x2c, 0xfe, 0x3a, 0x90, 0x14, 0x16,
+0xd7, 0x8c, 0x63, 0x24, 0x48, 0x1c, 0xdf, 0x30, 0x7d, 0xd5, 0x68, 0x3b, 0x30, 0x82, 0x05, 0x88,
+0x30, 0x82, 0x03, 0x70, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x7d, 0x09, 0x97, 0xfe, 0xf0,
+0x47, 0xea, 0x7a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+0x05, 0x00, 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43,
+0x4e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x29, 0x47, 0x55, 0x41, 0x4e,
+0x47, 0x20, 0x44, 0x4f, 0x4e, 0x47, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41,
+0x54, 0x45, 0x20, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x20, 0x43, 0x4f, 0x2e,
+0x2c, 0x4c, 0x54, 0x44, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16,
+0x47, 0x44, 0x43, 0x41, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x41, 0x55, 0x54, 0x48, 0x20, 0x52,
+0x35, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x31, 0x32, 0x36,
+0x30, 0x35, 0x31, 0x33, 0x31, 0x35, 0x5a, 0x17, 0x0d, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x31,
+0x35, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x43, 0x4e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x29,
+0x47, 0x55, 0x41, 0x4e, 0x47, 0x20, 0x44, 0x4f, 0x4e, 0x47, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
+0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x20, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59,
+0x20, 0x43, 0x4f, 0x2e, 0x2c, 0x4c, 0x54, 0x44, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x0c, 0x16, 0x47, 0x44, 0x43, 0x41, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x41, 0x55,
+0x54, 0x48, 0x20, 0x52, 0x35, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02,
+0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xd9, 0xa3, 0x16, 0xf0, 0xc8,
+0x74, 0x74, 0x77, 0x9b, 0xef, 0x33, 0x0d, 0x3b, 0x06, 0x7e, 0x55, 0xfc, 0xb5, 0x60, 0x8f, 0x76,
+0x86, 0x12, 0x42, 0x7d, 0x56, 0x66, 0x3e, 0x88, 0x82, 0xed, 0x72, 0x63, 0x0e, 0x9e, 0x8b, 0xdd,
+0x34, 0x2c, 0x02, 0x51, 0x51, 0xc3, 0x19, 0xfd, 0x59, 0x54, 0x84, 0xc9, 0xf1, 0x6b, 0xb3, 0x4c,
+0xb0, 0xe9, 0xe8, 0x46, 0x5d, 0x38, 0xc6, 0xa2, 0xa7, 0x2e, 0x11, 0x57, 0xba, 0x82, 0x15, 0xa2,
+0x9c, 0x8f, 0x6d, 0xb0, 0x99, 0x4a, 0x0a, 0xf2, 0xeb, 0x89, 0x70, 0x63, 0x4e, 0x79, 0xc4, 0xb7,
+0x5b, 0xbd, 0xa2, 0x5d, 0xb1, 0xf2, 0x41, 0x02, 0x2b, 0xad, 0xa9, 0x3a, 0xa3, 0xec, 0x79, 0x0a,
+0xec, 0x5f, 0x3a, 0xe3, 0xfd, 0xef, 0x80, 0x3c, 0xad, 0x34, 0x9b, 0x1a, 0xab, 0x88, 0x26, 0x7b,
+0x56, 0xa2, 0x82, 0x86, 0x1f, 0xeb, 0x35, 0x89, 0x83, 0x7f, 0x5f, 0xae, 0x29, 0x4e, 0x3d, 0xb6,
+0x6e, 0xec, 0xae, 0xc1, 0xf0, 0x27, 0x9b, 0xae, 0xe3, 0xf4, 0xec, 0xef, 0xae, 0x7f, 0xf7, 0x86,
+0x3d, 0x72, 0x7a, 0xeb, 0xa5, 0xfb, 0x59, 0x4e, 0xa7, 0xeb, 0x95, 0x8c, 0x22, 0x39, 0x79, 0xe1,
+0x2d, 0x08, 0x8f, 0xcc, 0xbc, 0x91, 0xb8, 0x41, 0xf7, 0x14, 0xc1, 0x23, 0xa9, 0xc3, 0xad, 0x9a,
+0x45, 0x44, 0xb3, 0xb2, 0xd7, 0x2c, 0xcd, 0xc6, 0x29, 0xe2, 0x50, 0x10, 0xae, 0x5c, 0xcb, 0x82,
+0x8e, 0x17, 0x18, 0x36, 0x7d, 0x97, 0xe6, 0x88, 0x9a, 0xb0, 0x4d, 0x34, 0x09, 0xf4, 0x2c, 0xb9,
+0x5a, 0x66, 0x2a, 0xb0, 0x17, 0x9b, 0x9e, 0x1e, 0x76, 0x9d, 0x4a, 0x66, 0x31, 0x41, 0xdf, 0x3f,
+0xfb, 0xc5, 0x06, 0xef, 0x1b, 0xb6, 0x7e, 0x1a, 0x46, 0x36, 0xf7, 0x64, 0x63, 0x3b, 0xe3, 0x39,
+0x18, 0x23, 0xe7, 0x67, 0x75, 0x14, 0xd5, 0x75, 0x57, 0x92, 0x37, 0xbd, 0xbe, 0x6a, 0x1b, 0x26,
+0x50, 0xf2, 0x36, 0x26, 0x06, 0x90, 0xc5, 0x70, 0x01, 0x64, 0x6d, 0x76, 0x66, 0xe1, 0x91, 0xdb,
+0x6e, 0x07, 0xc0, 0x61, 0x80, 0x2e, 0xb2, 0x2e, 0x2f, 0x8c, 0x70, 0xa7, 0xd1, 0x3b, 0x3c, 0xb3,
+0x91, 0xe4, 0x6e, 0xb6, 0xc4, 0x3b, 0x70, 0xf2, 0x6c, 0x92, 0x97, 0x09, 0xcd, 0x47, 0x7d, 0x18,
+0xc0, 0xf3, 0xbb, 0x9e, 0x0f, 0xd6, 0x8b, 0xae, 0x07, 0xb6, 0x5a, 0x0f, 0xce, 0x0b, 0x0c, 0x47,
+0xa7, 0xe5, 0x3e, 0xb8, 0xbd, 0x7d, 0xc7, 0x9b, 0x35, 0xa0, 0x61, 0x97, 0x3a, 0x41, 0x75, 0x17,
+0xcc, 0x2b, 0x96, 0x77, 0x2a, 0x92, 0x21, 0x1e, 0xd9, 0x95, 0x76, 0x20, 0x67, 0x68, 0xcf, 0x0d,
+0xbd, 0xdf, 0xd6, 0x1f, 0x09, 0x6a, 0x9a, 0xe2, 0xcc, 0x73, 0x71, 0xa4, 0x2f, 0x7d, 0x12, 0x80,
+0xb7, 0x53, 0x30, 0x46, 0x5e, 0x4b, 0x54, 0x99, 0x0f, 0x67, 0xc9, 0xa5, 0xc8, 0xf2, 0x20, 0xc1,
+0x82, 0xec, 0x9d, 0x11, 0xdf, 0xc2, 0x02, 0xfb, 0x1a, 0x3b, 0xd1, 0xed, 0x20, 0x9a, 0xef, 0x65,
+0x64, 0x92, 0x10, 0x0d, 0x2a, 0xe2, 0xde, 0x70, 0xf1, 0x18, 0x67, 0x82, 0x8c, 0x61, 0xde, 0xb8,
+0xbc, 0xd1, 0x2f, 0x9c, 0xfb, 0x0f, 0xd0, 0x2b, 0xed, 0x1b, 0x76, 0xb9, 0xe4, 0x39, 0x55, 0xf8,
+0xf8, 0xa1, 0x1d, 0xb8, 0xaa, 0x80, 0x00, 0x4c, 0x82, 0xe7, 0xb2, 0x7f, 0x09, 0xb8, 0xbc, 0x30,
+0xa0, 0x2f, 0x0d, 0xf5, 0x52, 0x9e, 0x8e, 0xf7, 0x92, 0xb3, 0x0a, 0x00, 0x1d, 0x00, 0x54, 0x97,
+0x06, 0xe0, 0xb1, 0x07, 0xd9, 0xc7, 0x0f, 0x5c, 0x65, 0x7d, 0x3c, 0x6d, 0x59, 0x57, 0xe4, 0xed,
+0xa5, 0x8d, 0xe9, 0x40, 0x53, 0x9f, 0x15, 0x4b, 0xa0, 0x71, 0xf6, 0x1a, 0x21, 0xe3, 0xda, 0x70,
+0x06, 0x21, 0x58, 0x14, 0x87, 0x85, 0x77, 0x79, 0xaa, 0x82, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01,
+0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xe2,
+0xc9, 0x40, 0x9f, 0x4d, 0xce, 0xe8, 0x9a, 0xa1, 0x7c, 0xcf, 0x0e, 0x3f, 0x65, 0xc5, 0x29, 0x88,
+0x6a, 0x19, 0x51, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x86, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0xd1, 0x49, 0x57, 0xe0, 0xa7, 0xcc, 0x68, 0x58,
+0xba, 0x01, 0x0f, 0x2b, 0x19, 0xcd, 0x8d, 0xb0, 0x61, 0x45, 0xac, 0x11, 0xed, 0x63, 0x50, 0x69,
+0xf8, 0x1f, 0x7f, 0xbe, 0x16, 0x8f, 0xfd, 0x9d, 0xeb, 0x0b, 0xaa, 0x32, 0x47, 0x76, 0xd2, 0x67,
+0x24, 0xed, 0xbd, 0x7c, 0x33, 0x32, 0x97, 0x2a, 0xc7, 0x05, 0x86, 0x66, 0x0d, 0x17, 0x7d, 0x14,
+0x15, 0x1b, 0xd4, 0xeb, 0xfd, 0x1f, 0x9a, 0xf6, 0x5e, 0x97, 0x69, 0xb7, 0x1a, 0x25, 0xa4, 0x0a,
+0xb3, 0x91, 0x3f, 0x5f, 0x36, 0xac, 0x8b, 0xec, 0x57, 0xa8, 0x3e, 0xe7, 0x81, 0x8a, 0x18, 0x57,
+0x39, 0x85, 0x74, 0x1a, 0x42, 0xc7, 0xe9, 0x5b, 0x13, 0x5f, 0x8f, 0xf9, 0x08, 0xe9, 0x92, 0x74,
+0x8d, 0xf5, 0x47, 0xd2, 0xab, 0x3b, 0xd6, 0xfb, 0x78, 0x66, 0x4e, 0x36, 0x7d, 0xf9, 0xe9, 0x92,
+0xe9, 0x04, 0xde, 0xfd, 0x49, 0x63, 0xfc, 0x6d, 0xfb, 0x14, 0x71, 0x93, 0x67, 0x2f, 0x47, 0x4a,
+0xb7, 0xb9, 0xff, 0x1e, 0x2a, 0x73, 0x70, 0x46, 0x30, 0xbf, 0x5a, 0xf2, 0x2f, 0x79, 0xa5, 0xe1,
+0x8d, 0x0c, 0xd9, 0xf9, 0xb2, 0x63, 0x37, 0x8c, 0x37, 0x65, 0x85, 0x70, 0x6a, 0x5c, 0x5b, 0x09,
+0x72, 0xb9, 0xad, 0x63, 0x3c, 0xb1, 0xdd, 0xf8, 0xfc, 0x32, 0xbf, 0x37, 0x86, 0xe4, 0xbb, 0x8e,
+0x98, 0x27, 0x7e, 0xba, 0x1f, 0x16, 0xe1, 0x70, 0x11, 0xf2, 0x03, 0xdf, 0x25, 0x62, 0x32, 0x27,
+0x26, 0x18, 0x32, 0x84, 0x9f, 0xff, 0x00, 0x3a, 0x13, 0xba, 0x9a, 0x4d, 0xf4, 0x4f, 0xb8, 0x14,
+0x70, 0x22, 0xb1, 0xca, 0x2b, 0x90, 0xce, 0x29, 0xc1, 0x70, 0xf4, 0x2f, 0x9d, 0x7f, 0xf2, 0x90,
+0x1e, 0xd6, 0x5a, 0xdf, 0xb7, 0x46, 0xfc, 0xe6, 0x86, 0xfa, 0xcb, 0xe0, 0x20, 0x76, 0x7a, 0xba,
+0xa6, 0xcb, 0xf5, 0x7c, 0xde, 0x62, 0xa5, 0xb1, 0x8b, 0xee, 0xde, 0x82, 0x66, 0x8a, 0x4e, 0x3a,
+0x30, 0x1f, 0x3f, 0x80, 0xcb, 0xad, 0x27, 0xba, 0x0c, 0x5e, 0xd7, 0xd0, 0xb1, 0x56, 0xca, 0x77,
+0x71, 0xb2, 0xb5, 0x75, 0xa1, 0x50, 0xa9, 0x40, 0x43, 0x17, 0xc2, 0x28, 0xd9, 0xcf, 0x52, 0x8b,
+0x5b, 0xc8, 0x63, 0xd4, 0x42, 0x3e, 0xa0, 0x33, 0x7a, 0x46, 0x2e, 0xf7, 0x0a, 0x20, 0x46, 0x54,
+0x7e, 0x6a, 0x4f, 0x31, 0xf1, 0x81, 0x7e, 0x42, 0x74, 0x38, 0x65, 0x73, 0x27, 0xee, 0xc6, 0x7c,
+0xb8, 0x8e, 0xd7, 0xa5, 0x3a, 0xd7, 0x98, 0xa1, 0x9c, 0x8c, 0x10, 0x55, 0xd3, 0xdb, 0x4b, 0xec,
+0x40, 0x90, 0xf2, 0xcd, 0x6e, 0x57, 0xd2, 0x62, 0x0e, 0x7c, 0x57, 0x93, 0xb1, 0xa7, 0x6d, 0xcd,
+0x9d, 0x83, 0xbb, 0x2a, 0xe7, 0xe5, 0xb6, 0x3b, 0x71, 0x58, 0xad, 0xfd, 0xd1, 0x45, 0xbc, 0x5a,
+0x91, 0xee, 0x53, 0x15, 0x6f, 0xd3, 0x45, 0x09, 0x75, 0x6e, 0xba, 0x90, 0x5d, 0x1e, 0x04, 0xcf,
+0x37, 0xdf, 0x1e, 0xa8, 0x66, 0xb1, 0x8c, 0xe6, 0x20, 0x6a, 0xef, 0xfc, 0x48, 0x4e, 0x74, 0x98,
+0x42, 0xaf, 0x29, 0x6f, 0x2e, 0x6a, 0xc7, 0xfb, 0x7d, 0xd1, 0x66, 0x31, 0x22, 0xcc, 0x86, 0x00,
+0x7e, 0x66, 0x83, 0x0c, 0x42, 0xf4, 0xbd, 0x34, 0x92, 0xc3, 0x1a, 0xea, 0x4f, 0xca, 0x7e, 0x72,
+0x4d, 0x0b, 0x70, 0x8c, 0xa6, 0x48, 0xbb, 0xa6, 0xa1, 0x14, 0xf6, 0xfb, 0x58, 0x44, 0x99, 0x14,
+0xae, 0xaa, 0x0b, 0x93, 0x69, 0xa0, 0x29, 0x25, 0x4a, 0xa5, 0xcb, 0x2b, 0xdd, 0x8a, 0x66, 0x07,
+0x16, 0x78, 0x15, 0x57, 0x71, 0x1b, 0xec, 0xf5, 0x47, 0x84, 0xf3, 0x9e, 0x31, 0x37, 0x7a, 0xd5,
+0x7f, 0x24, 0xad, 0xe4, 0xbc, 0xfd, 0xfd, 0xcc, 0x6e, 0x83, 0xe8, 0x0c, 0xa8, 0xb7, 0x41, 0x6c,
+0x07, 0xdd, 0xbd, 0x3c, 0x86, 0x97, 0x2f, 0xd2, 0x30, 0x82, 0x05, 0x41, 0x30, 0x82, 0x03, 0x29,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x06, 0x6c, 0x9f, 0xd2, 0x96, 0x35, 0x86, 0x9f, 0x0a,
+0x0f, 0xe5, 0x86, 0x78, 0xf8, 0x5b, 0x26, 0xbb, 0x8a, 0x37, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x30, 0x39, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x06, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x13, 0x10, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x43, 0x41, 0x20, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x35, 0x32, 0x36, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x30, 0x30, 0x35, 0x32, 0x36, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x5a, 0x30, 0x39, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x55, 0x53, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x06, 0x41, 0x6d,
+0x61, 0x7a, 0x6f, 0x6e, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41,
+0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30,
+0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00,
+0xad, 0x96, 0x9f, 0x2d, 0x9c, 0x4a, 0x4c, 0x4a, 0x81, 0x79, 0x51, 0x99, 0xec, 0x8a, 0xcb, 0x6b,
+0x60, 0x51, 0x13, 0xbc, 0x4d, 0x6d, 0x06, 0xfc, 0xb0, 0x08, 0x8d, 0xdd, 0x19, 0x10, 0x6a, 0xc7,
+0x26, 0x0c, 0x35, 0xd8, 0xc0, 0x6f, 0x20, 0x84, 0xe9, 0x94, 0xb1, 0x9b, 0x85, 0x03, 0xc3, 0x5b,
+0xdb, 0x4a, 0xe8, 0xc8, 0xf8, 0x90, 0x76, 0xd9, 0x5b, 0x4f, 0xe3, 0x4c, 0xe8, 0x06, 0x36, 0x4d,
+0xcc, 0x9a, 0xac, 0x3d, 0x0c, 0x90, 0x2b, 0x92, 0xd4, 0x06, 0x19, 0x60, 0xac, 0x37, 0x44, 0x79,
+0x85, 0x81, 0x82, 0xad, 0x5a, 0x37, 0xe0, 0x0d, 0xcc, 0x9d, 0xa6, 0x4c, 0x52, 0x76, 0xea, 0x43,
+0x9d, 0xb7, 0x04, 0xd1, 0x50, 0xf6, 0x55, 0xe0, 0xd5, 0xd2, 0xa6, 0x49, 0x85, 0xe9, 0x37, 0xe9,
+0xca, 0x7e, 0xae, 0x5c, 0x95, 0x4d, 0x48, 0x9a, 0x3f, 0xae, 0x20, 0x5a, 0x6d, 0x88, 0x95, 0xd9,
+0x34, 0xb8, 0x52, 0x1a, 0x43, 0x90, 0xb0, 0xbf, 0x6c, 0x05, 0xb9, 0xb6, 0x78, 0xb7, 0xea, 0xd0,
+0xe4, 0x3a, 0x3c, 0x12, 0x53, 0x62, 0xff, 0x4a, 0xf2, 0x7b, 0xbe, 0x35, 0x05, 0xa9, 0x12, 0x34,
+0xe3, 0xf3, 0x64, 0x74, 0x62, 0x2c, 0x3d, 0x00, 0x49, 0x5a, 0x28, 0xfe, 0x32, 0x44, 0xbb, 0x87,
+0xdd, 0x65, 0x27, 0x02, 0x71, 0x3b, 0xda, 0x4a, 0xf7, 0x1f, 0xda, 0xcd, 0xf7, 0x21, 0x55, 0x90,
+0x4f, 0x0f, 0xec, 0xae, 0x82, 0xe1, 0x9f, 0x6b, 0xd9, 0x45, 0xd3, 0xbb, 0xf0, 0x5f, 0x87, 0xed,
+0x3c, 0x2c, 0x39, 0x86, 0xda, 0x3f, 0xde, 0xec, 0x72, 0x55, 0xeb, 0x79, 0xa3, 0xad, 0xdb, 0xdd,
+0x7c, 0xb0, 0xba, 0x1c, 0xce, 0xfc, 0xde, 0x4f, 0x35, 0x76, 0xcf, 0x0f, 0xf8, 0x78, 0x1f, 0x6a,
+0x36, 0x51, 0x46, 0x27, 0x61, 0x5b, 0xe9, 0x9e, 0xcf, 0xf0, 0xa2, 0x55, 0x7d, 0x7c, 0x25, 0x8a,
+0x6f, 0x2f, 0xb4, 0xc5, 0xcf, 0x84, 0x2e, 0x2b, 0xfd, 0x0d, 0x51, 0x10, 0x6c, 0xfb, 0x5f, 0x1b,
+0xbc, 0x1b, 0x7e, 0xc5, 0xae, 0x3b, 0x98, 0x01, 0x31, 0x92, 0xff, 0x0b, 0x57, 0xf4, 0x9a, 0xb2,
+0xb9, 0x57, 0xe9, 0xab, 0xef, 0x0d, 0x76, 0xd1, 0xf0, 0xee, 0xf4, 0xce, 0x86, 0xa7, 0xe0, 0x6e,
+0xe9, 0xb4, 0x69, 0xa1, 0xdf, 0x69, 0xf6, 0x33, 0xc6, 0x69, 0x2e, 0x97, 0x13, 0x9e, 0xa5, 0x87,
+0xb0, 0x57, 0x10, 0x81, 0x37, 0xc9, 0x53, 0xb3, 0xbb, 0x7f, 0xf6, 0x92, 0xd1, 0x9c, 0xd0, 0x18,
+0xf4, 0x92, 0x6e, 0xda, 0x83, 0x4f, 0xa6, 0x63, 0x99, 0x4c, 0xa5, 0xfb, 0x5e, 0xef, 0x21, 0x64,
+0x7a, 0x20, 0x5f, 0x6c, 0x64, 0x85, 0x15, 0xcb, 0x37, 0xe9, 0x62, 0x0c, 0x0b, 0x2a, 0x16, 0xdc,
+0x01, 0x2e, 0x32, 0xda, 0x3e, 0x4b, 0xf5, 0x9e, 0x3a, 0xf6, 0x17, 0x40, 0x94, 0xef, 0x9e, 0x91,
+0x08, 0x86, 0xfa, 0xbe, 0x63, 0xa8, 0x5a, 0x33, 0xec, 0xcb, 0x74, 0x43, 0x95, 0xf9, 0x6c, 0x69,
+0x52, 0x36, 0xc7, 0x29, 0x6f, 0xfc, 0x55, 0x03, 0x5c, 0x1f, 0xfb, 0x9f, 0xbd, 0x47, 0xeb, 0xe7,
+0x49, 0x47, 0x95, 0x0b, 0x4e, 0x89, 0x22, 0x09, 0x49, 0xe0, 0xf5, 0x61, 0x1e, 0xf1, 0xbf, 0x2e,
+0x8a, 0x72, 0x6e, 0x80, 0x59, 0xff, 0x57, 0x3a, 0xf9, 0x75, 0x32, 0xa3, 0x4e, 0x5f, 0xec, 0xed,
+0x28, 0x62, 0xd9, 0x4d, 0x73, 0xf2, 0xcc, 0x81, 0x17, 0x60, 0xed, 0xcd, 0xeb, 0xdc, 0xdb, 0xa7,
+0xca, 0xc5, 0x7e, 0x02, 0xbd, 0xf2, 0x54, 0x08, 0x54, 0xfd, 0xb4, 0x2d, 0x09, 0x2c, 0x17, 0x54,
+0x4a, 0x98, 0xd1, 0x54, 0xe1, 0x51, 0x67, 0x08, 0xd2, 0xed, 0x6e, 0x7e, 0x6f, 0x3f, 0xd2, 0x2d,
+0x81, 0x59, 0x29, 0x66, 0xcb, 0x90, 0x39, 0x95, 0x11, 0x1e, 0x74, 0x27, 0xfe, 0xdd, 0xeb, 0xaf,
+0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13,
+0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+0x0e, 0x04, 0x16, 0x04, 0x14, 0xb0, 0x0c, 0xf0, 0x4c, 0x30, 0xf4, 0x05, 0x58, 0x02, 0x48, 0xfd,
+0x33, 0xe5, 0x52, 0xaf, 0x4b, 0x84, 0xe3, 0x66, 0x52, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0xaa, 0xa8, 0x80,
+0x8f, 0x0e, 0x78, 0xa3, 0xe0, 0xa2, 0xd4, 0xcd, 0xe6, 0xf5, 0x98, 0x7a, 0x3b, 0xea, 0x00, 0x03,
+0xb0, 0x97, 0x0e, 0x93, 0xbc, 0x5a, 0xa8, 0xf6, 0x2c, 0x8c, 0x72, 0x87, 0xa9, 0xb1, 0xfc, 0x7f,
+0x73, 0xfd, 0x63, 0x71, 0x78, 0xa5, 0x87, 0x59, 0xcf, 0x30, 0xe1, 0x0d, 0x10, 0xb2, 0x13, 0x5a,
+0x6d, 0x82, 0xf5, 0x6a, 0xe6, 0x80, 0x9f, 0xa0, 0x05, 0x0b, 0x68, 0xe4, 0x47, 0x6b, 0xc7, 0x6a,
+0xdf, 0xb6, 0xfd, 0x77, 0x32, 0x72, 0xe5, 0x18, 0xfa, 0x09, 0xf4, 0xa0, 0x93, 0x2c, 0x5d, 0xd2,
+0x8c, 0x75, 0x85, 0x76, 0x65, 0x90, 0x0c, 0x03, 0x79, 0xb7, 0x31, 0x23, 0x63, 0xad, 0x78, 0x83,
+0x09, 0x86, 0x68, 0x84, 0xca, 0xff, 0xf9, 0xcf, 0x26, 0x9a, 0x92, 0x79, 0xe7, 0xcd, 0x4b, 0xc5,
+0xe7, 0x61, 0xa7, 0x17, 0xcb, 0xf3, 0xa9, 0x12, 0x93, 0x93, 0x6b, 0xa7, 0xe8, 0x2f, 0x53, 0x92,
+0xc4, 0x60, 0x58, 0xb0, 0xcc, 0x02, 0x51, 0x18, 0x5b, 0x85, 0x8d, 0x62, 0x59, 0x63, 0xb6, 0xad,
+0xb4, 0xde, 0x9a, 0xfb, 0x26, 0xf7, 0x00, 0x27, 0xc0, 0x5d, 0x55, 0x37, 0x74, 0x99, 0xc9, 0x50,
+0x7f, 0xe3, 0x59, 0x2e, 0x44, 0xe3, 0x2c, 0x25, 0xee, 0xec, 0x4c, 0x32, 0x77, 0xb4, 0x9f, 0x1a,
+0xe9, 0x4b, 0x5d, 0x20, 0xc5, 0xda, 0xfd, 0x1c, 0x87, 0x16, 0xc6, 0x43, 0xe8, 0xd4, 0xbb, 0x26,
+0x9a, 0x45, 0x70, 0x5e, 0xa9, 0x0b, 0x37, 0x53, 0xe2, 0x46, 0x7b, 0x27, 0xfd, 0xe0, 0x46, 0xf2,
+0x89, 0xb7, 0xcc, 0x42, 0xb6, 0xcb, 0x28, 0x26, 0x6e, 0xd9, 0xa5, 0xc9, 0x3a, 0xc8, 0x41, 0x13,
+0x60, 0xf7, 0x50, 0x8c, 0x15, 0xae, 0xb2, 0x6d, 0x1a, 0x15, 0x1a, 0x57, 0x78, 0xe6, 0x92, 0x2a,
+0xd9, 0x65, 0x90, 0x82, 0x3f, 0x6c, 0x02, 0xaf, 0xae, 0x12, 0x3a, 0x27, 0x96, 0x36, 0x04, 0xd7,
+0x1d, 0xa2, 0x80, 0x63, 0xa9, 0x9b, 0xf1, 0xe5, 0xba, 0xb4, 0x7c, 0x14, 0xb0, 0x4e, 0xc9, 0xb1,
+0x1f, 0x74, 0x5f, 0x38, 0xf6, 0x51, 0xea, 0x9b, 0xfa, 0x2c, 0xa2, 0x11, 0xd4, 0xa9, 0x2d, 0x27,
+0x1a, 0x45, 0xb1, 0xaf, 0xb2, 0x4e, 0x71, 0x0d, 0xc0, 0x58, 0x46, 0xd6, 0x69, 0x06, 0xcb, 0x53,
+0xcb, 0xb3, 0xfe, 0x6b, 0x41, 0xcd, 0x41, 0x7e, 0x7d, 0x4c, 0x0f, 0x7c, 0x72, 0x79, 0x7a, 0x59,
+0xcd, 0x5e, 0x4a, 0x0e, 0xac, 0x9b, 0xa9, 0x98, 0x73, 0x79, 0x7c, 0xb4, 0xf4, 0xcc, 0xb9, 0xb8,
+0x07, 0x0c, 0xb2, 0x74, 0x5c, 0xb8, 0xc7, 0x6f, 0x88, 0xa1, 0x90, 0xa7, 0xf4, 0xaa, 0xf9, 0xbf,
+0x67, 0x3a, 0xf4, 0x1a, 0x15, 0x62, 0x1e, 0xb7, 0x9f, 0xbe, 0x3d, 0xb1, 0x29, 0xaf, 0x67, 0xa1,
+0x12, 0xf2, 0x58, 0x10, 0x19, 0x53, 0x03, 0x30, 0x1b, 0xb8, 0x1a, 0x89, 0xf6, 0x9c, 0xbd, 0x97,
+0x03, 0x8e, 0xa3, 0x09, 0xf3, 0x1d, 0x8b, 0x21, 0xf1, 0xb4, 0xdf, 0xe4, 0x1c, 0xd1, 0x9f, 0x65,
+0x02, 0x06, 0xea, 0x5c, 0xd6, 0x13, 0xb3, 0x84, 0xef, 0xa2, 0xa5, 0x5c, 0x8c, 0x77, 0x29, 0xa7,
+0x68, 0xc0, 0x6b, 0xae, 0x40, 0xd2, 0xa8, 0xb4, 0xea, 0xcd, 0xf0, 0x8d, 0x4b, 0x38, 0x9c, 0x19,
+0x9a, 0x1b, 0x28, 0x54, 0xb8, 0x89, 0x90, 0xef, 0xca, 0x75, 0x81, 0x3e, 0x1e, 0xf2, 0x64, 0x24,
+0xc7, 0x18, 0xaf, 0x4e, 0xff, 0x47, 0x9e, 0x07, 0xf6, 0x35, 0x65, 0xa4, 0xd3, 0x0a, 0x56, 0xff,
+0xf5, 0x17, 0x64, 0x6c, 0xef, 0xa8, 0x22, 0x25, 0x49, 0x93, 0xb6, 0xdf, 0x00, 0x17, 0xda, 0x58,
+0x7e, 0x5d, 0xee, 0xc5, 0x1b, 0xb0, 0xd1, 0xd1, 0x5f, 0x21, 0x10, 0xc7, 0xf9, 0xf3, 0xba, 0x02,
+0x0a, 0x27, 0x07, 0xc5, 0xf1, 0xd6, 0xc7, 0xd3, 0xe0, 0xfb, 0x09, 0x60, 0x6c, 0x30, 0x82, 0x03,
+0x41, 0x30, 0x82, 0x02, 0x29, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x06, 0x6c, 0x9f, 0xcf,
+0x99, 0xbf, 0x8c, 0x0a, 0x39, 0xe2, 0xf0, 0x78, 0x8a, 0x43, 0xe6, 0x96, 0x36, 0x5b, 0xca, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x39,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0f, 0x30,
+0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x06, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x31, 0x19,
+0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30,
+0x35, 0x32, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31,
+0x31, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x39, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x06, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x13, 0x10, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x43, 0x41, 0x20, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+0x02, 0x82, 0x01, 0x01, 0x00, 0xb2, 0x78, 0x80, 0x71, 0xca, 0x78, 0xd5, 0xe3, 0x71, 0xaf, 0x47,
+0x80, 0x50, 0x74, 0x7d, 0x6e, 0xd8, 0xd7, 0x88, 0x76, 0xf4, 0x99, 0x68, 0xf7, 0x58, 0x21, 0x60,
+0xf9, 0x74, 0x84, 0x01, 0x2f, 0xac, 0x02, 0x2d, 0x86, 0xd3, 0xa0, 0x43, 0x7a, 0x4e, 0xb2, 0xa4,
+0xd0, 0x36, 0xba, 0x01, 0xbe, 0x8d, 0xdb, 0x48, 0xc8, 0x07, 0x17, 0x36, 0x4c, 0xf4, 0xee, 0x88,
+0x23, 0xc7, 0x3e, 0xeb, 0x37, 0xf5, 0xb5, 0x19, 0xf8, 0x49, 0x68, 0xb0, 0xde, 0xd7, 0xb9, 0x76,
+0x38, 0x1d, 0x61, 0x9e, 0xa4, 0xfe, 0x82, 0x36, 0xa5, 0xe5, 0x4a, 0x56, 0xe4, 0x45, 0xe1, 0xf9,
+0xfd, 0xb4, 0x16, 0xfa, 0x74, 0xda, 0x9c, 0x9b, 0x35, 0x39, 0x2f, 0xfa, 0xb0, 0x20, 0x50, 0x06,
+0x6c, 0x7a, 0xd0, 0x80, 0xb2, 0xa6, 0xf9, 0xaf, 0xec, 0x47, 0x19, 0x8f, 0x50, 0x38, 0x07, 0xdc,
+0xa2, 0x87, 0x39, 0x58, 0xf8, 0xba, 0xd5, 0xa9, 0xf9, 0x48, 0x67, 0x30, 0x96, 0xee, 0x94, 0x78,
+0x5e, 0x6f, 0x89, 0xa3, 0x51, 0xc0, 0x30, 0x86, 0x66, 0xa1, 0x45, 0x66, 0xba, 0x54, 0xeb, 0xa3,
+0xc3, 0x91, 0xf9, 0x48, 0xdc, 0xff, 0xd1, 0xe8, 0x30, 0x2d, 0x7d, 0x2d, 0x74, 0x70, 0x35, 0xd7,
+0x88, 0x24, 0xf7, 0x9e, 0xc4, 0x59, 0x6e, 0xbb, 0x73, 0x87, 0x17, 0xf2, 0x32, 0x46, 0x28, 0xb8,
+0x43, 0xfa, 0xb7, 0x1d, 0xaa, 0xca, 0xb4, 0xf2, 0x9f, 0x24, 0x0e, 0x2d, 0x4b, 0xf7, 0x71, 0x5c,
+0x5e, 0x69, 0xff, 0xea, 0x95, 0x02, 0xcb, 0x38, 0x8a, 0xae, 0x50, 0x38, 0x6f, 0xdb, 0xfb, 0x2d,
+0x62, 0x1b, 0xc5, 0xc7, 0x1e, 0x54, 0xe1, 0x77, 0xe0, 0x67, 0xc8, 0x0f, 0x9c, 0x87, 0x23, 0xd6,
+0x3f, 0x40, 0x20, 0x7f, 0x20, 0x80, 0xc4, 0x80, 0x4c, 0x3e, 0x3b, 0x24, 0x26, 0x8e, 0x04, 0xae,
+0x6c, 0x9a, 0xc8, 0xaa, 0x0d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f,
+0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x84, 0x18, 0xcc, 0x85, 0x34, 0xec,
+0xbc, 0x0c, 0x94, 0x94, 0x2e, 0x08, 0x59, 0x9c, 0xc7, 0xb2, 0x10, 0x4e, 0x0a, 0x08, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01,
+0x01, 0x00, 0x98, 0xf2, 0x37, 0x5a, 0x41, 0x90, 0xa1, 0x1a, 0xc5, 0x76, 0x51, 0x28, 0x20, 0x36,
+0x23, 0x0e, 0xae, 0xe6, 0x28, 0xbb, 0xaa, 0xf8, 0x94, 0xae, 0x48, 0xa4, 0x30, 0x7f, 0x1b, 0xfc,
+0x24, 0x8d, 0x4b, 0xb4, 0xc8, 0xa1, 0x97, 0xf6, 0xb6, 0xf1, 0x7a, 0x70, 0xc8, 0x53, 0x93, 0xcc,
+0x08, 0x28, 0xe3, 0x98, 0x25, 0xcf, 0x23, 0xa4, 0xf9, 0xde, 0x21, 0xd3, 0x7c, 0x85, 0x09, 0xad,
+0x4e, 0x9a, 0x75, 0x3a, 0xc2, 0x0b, 0x6a, 0x89, 0x78, 0x76, 0x44, 0x47, 0x18, 0x65, 0x6c, 0x8d,
+0x41, 0x8e, 0x3b, 0x7f, 0x9a, 0xcb, 0xf4, 0xb5, 0xa7, 0x50, 0xd7, 0x05, 0x2c, 0x37, 0xe8, 0x03,
+0x4b, 0xad, 0xe9, 0x61, 0xa0, 0x02, 0x6e, 0xf5, 0xf2, 0xf0, 0xc5, 0xb2, 0xed, 0x5b, 0xb7, 0xdc,
+0xfa, 0x94, 0x5c, 0x77, 0x9e, 0x13, 0xa5, 0x7f, 0x52, 0xad, 0x95, 0xf2, 0xf8, 0x93, 0x3b, 0xde,
+0x8b, 0x5c, 0x5b, 0xca, 0x5a, 0x52, 0x5b, 0x60, 0xaf, 0x14, 0xf7, 0x4b, 0xef, 0xa3, 0xfb, 0x9f,
+0x40, 0x95, 0x6d, 0x31, 0x54, 0xfc, 0x42, 0xd3, 0xc7, 0x46, 0x1f, 0x23, 0xad, 0xd9, 0x0f, 0x48,
+0x70, 0x9a, 0xd9, 0x75, 0x78, 0x71, 0xd1, 0x72, 0x43, 0x34, 0x75, 0x6e, 0x57, 0x59, 0xc2, 0x02,
+0x5c, 0x26, 0x60, 0x29, 0xcf, 0x23, 0x19, 0x16, 0x8e, 0x88, 0x43, 0xa5, 0xd4, 0xe4, 0xcb, 0x08,
+0xfb, 0x23, 0x11, 0x43, 0xe8, 0x43, 0x29, 0x72, 0x62, 0xa1, 0xa9, 0x5d, 0x5e, 0x08, 0xd4, 0x90,
+0xae, 0xb8, 0xd8, 0xce, 0x14, 0xc2, 0xd0, 0x55, 0xf2, 0x86, 0xf6, 0xc4, 0x93, 0x43, 0x77, 0x66,
+0x61, 0xc0, 0xb9, 0xe8, 0x41, 0xd7, 0x97, 0x78, 0x60, 0x03, 0x6e, 0x4a, 0x72, 0xae, 0xa5, 0xd1,
+0x7d, 0xba, 0x10, 0x9e, 0x86, 0x6c, 0x1b, 0x8a, 0xb9, 0x59, 0x33, 0xf8, 0xeb, 0xc4, 0x90, 0xbe,
+0xf1, 0xb9, 0x30, 0x82, 0x01, 0xf2, 0x30, 0x82, 0x01, 0x78, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+0x13, 0x06, 0x6c, 0x9f, 0xd7, 0xc1, 0xbb, 0x10, 0x4c, 0x29, 0x43, 0xe5, 0x71, 0x7b, 0x7b, 0x2c,
+0xc8, 0x1a, 0xc1, 0x0e, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03,
+0x30, 0x39, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x06, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e,
+0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 0x6d, 0x61, 0x7a, 0x6f,
+0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x34, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+0x35, 0x30, 0x35, 0x32, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x30,
+0x30, 0x35, 0x32, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x39, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x06, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x31, 0x19, 0x30, 0x17, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f,
+0x74, 0x20, 0x43, 0x41, 0x20, 0x34, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce,
+0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xd2, 0xab,
+0x8a, 0x37, 0x4f, 0xa3, 0x53, 0x0d, 0xfe, 0xc1, 0x8a, 0x7b, 0x4b, 0xa8, 0x7b, 0x46, 0x4b, 0x63,
+0xb0, 0x62, 0xf6, 0x2d, 0x1b, 0xdb, 0x08, 0x71, 0x21, 0xd2, 0x00, 0xe8, 0x63, 0xbd, 0x9a, 0x27,
+0xfb, 0xf0, 0x39, 0x6e, 0x5d, 0xea, 0x3d, 0xa5, 0xc9, 0x81, 0xaa, 0xa3, 0x5b, 0x20, 0x98, 0x45,
+0x5d, 0x16, 0xdb, 0xfd, 0xe8, 0x10, 0x6d, 0xe3, 0x9c, 0xe0, 0xe3, 0xbd, 0x5f, 0x84, 0x62, 0xf3,
+0x70, 0x64, 0x33, 0xa0, 0xcb, 0x24, 0x2f, 0x70, 0xba, 0x88, 0xa1, 0x2a, 0xa0, 0x75, 0xf8, 0x81,
+0xae, 0x62, 0x06, 0xc4, 0x81, 0xdb, 0x39, 0x6e, 0x29, 0xb0, 0x1e, 0xfa, 0x2e, 0x5c, 0xa3, 0x42,
+0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd3, 0xec,
+0xc7, 0x3a, 0x65, 0x6e, 0xcc, 0xe1, 0xda, 0x76, 0x9a, 0x56, 0xfb, 0x9c, 0xf3, 0x86, 0x6d, 0x57,
+0xe5, 0x81, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x68,
+0x00, 0x30, 0x65, 0x02, 0x30, 0x3a, 0x8b, 0x21, 0xf1, 0xbd, 0x7e, 0x11, 0xad, 0xd0, 0xef, 0x58,
+0x96, 0x2f, 0xd6, 0xeb, 0x9d, 0x7e, 0x90, 0x8d, 0x2b, 0xcf, 0x66, 0x55, 0xc3, 0x2c, 0xe3, 0x28,
+0xa9, 0x70, 0x0a, 0x47, 0x0e, 0xf0, 0x37, 0x59, 0x12, 0xff, 0x2d, 0x99, 0x94, 0x28, 0x4e, 0x2a,
+0x4f, 0x35, 0x4d, 0x33, 0x5a, 0x02, 0x31, 0x00, 0xea, 0x75, 0x00, 0x4e, 0x3b, 0xc4, 0x3a, 0x94,
+0x12, 0x91, 0xc9, 0x58, 0x46, 0x9d, 0x21, 0x13, 0x72, 0xa7, 0x88, 0x9c, 0x8a, 0xe4, 0x4c, 0x4a,
+0xdb, 0x96, 0xd4, 0xac, 0x8b, 0x6b, 0x6b, 0x49, 0x12, 0x53, 0x33, 0xad, 0xd7, 0xe4, 0xbe, 0x24,
+0xfc, 0xb5, 0x0a, 0x76, 0xd4, 0xa5, 0xbc, 0x10, 0x30, 0x82, 0x06, 0x0b, 0x30, 0x82, 0x03, 0xf3,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xa6, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07,
+0x13, 0x06, 0x41, 0x74, 0x68, 0x65, 0x6e, 0x73, 0x31, 0x44, 0x30, 0x42, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x3b, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64,
+0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63,
+0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43,
+0x65, 0x72, 0x74, 0x2e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x40,
+0x30, 0x3e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x37, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69,
+0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52,
+0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74,
+0x69, 0x6f, 0x6e, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35,
+0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x37, 0x30, 0x37, 0x31, 0x30, 0x31, 0x31, 0x32, 0x31,
+0x5a, 0x17, 0x0d, 0x34, 0x30, 0x30, 0x36, 0x33, 0x30, 0x31, 0x30, 0x31, 0x31, 0x32, 0x31, 0x5a,
+0x30, 0x81, 0xa6, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x52,
+0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x06, 0x41, 0x74, 0x68, 0x65, 0x6e,
+0x73, 0x31, 0x44, 0x30, 0x42, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x3b, 0x48, 0x65, 0x6c, 0x6c,
+0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e,
+0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69,
+0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x2e, 0x20, 0x41, 0x75,
+0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x40, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x37, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65,
+0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68,
+0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f,
+0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xc2, 0xf8, 0xa9, 0x3f, 0x1b, 0x89,
+0xfc, 0x3c, 0x3c, 0x04, 0x5d, 0x3d, 0x90, 0x36, 0xb0, 0x91, 0x3a, 0x79, 0x3c, 0x66, 0x5a, 0xef,
+0x6d, 0x39, 0x01, 0x49, 0x1a, 0xb4, 0xb7, 0xcf, 0x7f, 0x4d, 0x23, 0x53, 0xb7, 0x90, 0x00, 0xe3,
+0x13, 0x2a, 0x28, 0xa6, 0x31, 0xf1, 0x91, 0x00, 0xe3, 0x28, 0xec, 0xae, 0x21, 0x41, 0xce, 0x1f,
+0xda, 0xfd, 0x7d, 0x12, 0x5b, 0x01, 0x83, 0x0f, 0xb9, 0xb0, 0x5f, 0x99, 0xe1, 0xf2, 0x12, 0x83,
+0x80, 0x4d, 0x06, 0x3e, 0xdf, 0xac, 0xaf, 0xe7, 0xa1, 0x88, 0x6b, 0x31, 0xaf, 0xf0, 0x8b, 0xd0,
+0x18, 0x33, 0xb8, 0xdb, 0x45, 0x6a, 0x34, 0xf4, 0x02, 0x80, 0x24, 0x28, 0x0a, 0x02, 0x15, 0x95,
+0x5e, 0x76, 0x2a, 0x0d, 0x99, 0x3a, 0x14, 0x5b, 0xf6, 0xcb, 0xcb, 0x53, 0xbc, 0x13, 0x4d, 0x01,
+0x88, 0x37, 0x94, 0x25, 0x1b, 0x42, 0xbc, 0x22, 0xd8, 0x8e, 0xa3, 0x96, 0x5e, 0x3a, 0xd9, 0x32,
+0xdb, 0x3e, 0xe8, 0xf0, 0x10, 0x65, 0xed, 0x74, 0xe1, 0x2f, 0xa7, 0x7c, 0xaf, 0x27, 0x34, 0xbb,
+0x29, 0x7d, 0x9b, 0xb6, 0xcf, 0x09, 0xc8, 0xe5, 0xd3, 0x0a, 0xfc, 0x88, 0x65, 0x65, 0x74, 0x0a,
+0xdc, 0x73, 0x1c, 0x5c, 0xcd, 0x40, 0xb1, 0x1c, 0xd4, 0xb6, 0x84, 0x8c, 0x4c, 0x50, 0xcf, 0x68,
+0x8e, 0xa8, 0x59, 0xae, 0xc2, 0x27, 0x4e, 0x82, 0xa2, 0x35, 0xdd, 0x14, 0xf4, 0x1f, 0xff, 0xb2,
+0x77, 0xd5, 0x87, 0x2f, 0xaa, 0x6e, 0x7d, 0x24, 0x27, 0xe7, 0xc6, 0xcb, 0x26, 0xe6, 0xe5, 0xfe,
+0x67, 0x07, 0x63, 0xd8, 0x45, 0x0d, 0xdd, 0x3a, 0x59, 0x65, 0x39, 0x58, 0x7a, 0x92, 0x99, 0x72,
+0x3d, 0x9c, 0x84, 0x5e, 0x88, 0x21, 0xb8, 0xd5, 0xf4, 0x2c, 0xfc, 0xd9, 0x70, 0x52, 0x4f, 0x78,
+0xb8, 0xbd, 0x3c, 0x2b, 0x8b, 0x95, 0x98, 0xf5, 0xb3, 0xd1, 0x68, 0xcf, 0x20, 0x14, 0x7e, 0x4c,
+0x5c, 0x5f, 0xe7, 0x8b, 0xe5, 0xf5, 0x35, 0x81, 0x19, 0x37, 0xd7, 0x11, 0x08, 0xb7, 0x66, 0xbe,
+0xd3, 0x4a, 0xce, 0x83, 0x57, 0x00, 0x3a, 0xc3, 0x81, 0xf8, 0x17, 0xcb, 0x92, 0x36, 0x5d, 0xd1,
+0xa3, 0xd8, 0x75, 0x1b, 0xe1, 0x8b, 0x27, 0xea, 0x7a, 0x48, 0x41, 0xfd, 0x45, 0x19, 0x06, 0xad,
+0x27, 0x99, 0x4e, 0xc1, 0x70, 0x47, 0xdd, 0xb5, 0x9f, 0x81, 0x53, 0x12, 0xe5, 0xb1, 0x8c, 0x48,
+0x5d, 0x31, 0x43, 0x17, 0xe3, 0x8c, 0xc6, 0x7a, 0x63, 0x96, 0x4b, 0x29, 0x30, 0x4e, 0x84, 0x4e,
+0x62, 0x19, 0x5e, 0x3c, 0xce, 0x97, 0x90, 0xa5, 0x7f, 0x01, 0xeb, 0x9d, 0xe0, 0xf8, 0x8b, 0x89,
+0xdd, 0x25, 0x98, 0x3d, 0x92, 0xb6, 0x7e, 0xef, 0xd9, 0xf1, 0x51, 0x51, 0x7d, 0x2d, 0x26, 0xc8,
+0x69, 0x59, 0x61, 0xe0, 0xac, 0x6a, 0xb8, 0x2a, 0x36, 0x11, 0x04, 0x7a, 0x50, 0xbd, 0x32, 0x84,
+0xbe, 0x2f, 0xdc, 0x72, 0xd5, 0xd7, 0x1d, 0x16, 0x47, 0xe4, 0x47, 0x66, 0x20, 0x3f, 0xf4, 0x96,
+0xc5, 0xaf, 0x8e, 0x01, 0x7a, 0xa5, 0x0f, 0x7a, 0x64, 0xf5, 0x0d, 0x18, 0x87, 0xd9, 0xae, 0x88,
+0xd5, 0xfa, 0x84, 0xc1, 0x3a, 0xc0, 0x69, 0x28, 0x2d, 0xf2, 0x0d, 0x68, 0x51, 0xaa, 0xe3, 0xa5,
+0x77, 0xc6, 0xa4, 0x90, 0x0e, 0xa1, 0x37, 0x8b, 0x31, 0x23, 0x47, 0xc1, 0x09, 0x08, 0xeb, 0x6e,
+0xf7, 0x78, 0x9b, 0xd7, 0x82, 0xfc, 0x84, 0x20, 0x99, 0x49, 0x19, 0xb6, 0x12, 0x46, 0xb1, 0xfb,
+0x45, 0x55, 0x16, 0xa9, 0xa3, 0x65, 0xac, 0x9c, 0x07, 0x0f, 0xea, 0x6b, 0xdc, 0x1f, 0x2e, 0x06,
+0x72, 0xec, 0x86, 0x88, 0x12, 0xe4, 0x2d, 0xdb, 0x5f, 0x05, 0x2f, 0xe4, 0xf0, 0x03, 0xd3, 0x26,
+0x33, 0xe7, 0x80, 0xc2, 0xcd, 0x42, 0xa1, 0x17, 0x34, 0x0b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x71,
+0x15, 0x67, 0xc8, 0xc8, 0xc9, 0xbd, 0x75, 0x5d, 0x72, 0xd0, 0x38, 0x18, 0x6a, 0x9d, 0xf3, 0x71,
+0x24, 0x54, 0x0b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x75, 0xbb, 0x6d, 0x54, 0x4b, 0xaa, 0x10, 0x58, 0x46,
+0x34, 0xf2, 0x62, 0xd7, 0x16, 0x36, 0x5d, 0x08, 0x5e, 0xd5, 0x6c, 0xc8, 0x87, 0xbd, 0xb4, 0x2e,
+0x46, 0xf2, 0x31, 0xf8, 0x7c, 0xea, 0x42, 0xb5, 0x93, 0x16, 0x55, 0xdc, 0xa1, 0x0c, 0x12, 0xa0,
+0xda, 0x61, 0x7e, 0x0f, 0x58, 0x58, 0x73, 0x64, 0x72, 0xc7, 0xe8, 0x45, 0x8e, 0xdc, 0xa9, 0xf2,
+0x26, 0x3f, 0xc6, 0x79, 0x8c, 0xb1, 0x53, 0x08, 0x33, 0x81, 0xb0, 0x56, 0x13, 0xbe, 0xe6, 0x51,
+0x5c, 0xd8, 0x9b, 0x0a, 0x4f, 0x4b, 0x9c, 0x56, 0x53, 0x02, 0xe9, 0x4f, 0xf6, 0x0d, 0x60, 0xea,
+0x4d, 0x42, 0x55, 0xe8, 0x7c, 0x1b, 0x21, 0x21, 0xd3, 0x1b, 0x3a, 0xcc, 0x77, 0xf2, 0xb8, 0x90,
+0xf1, 0x68, 0xc7, 0xf9, 0x5a, 0xfe, 0xfa, 0x2d, 0xf4, 0xbf, 0xc9, 0xf5, 0x45, 0x1b, 0xce, 0x38,
+0x10, 0x2a, 0x37, 0x8a, 0x79, 0xa3, 0xb4, 0xe3, 0x09, 0x6c, 0x85, 0x86, 0x93, 0xff, 0x89, 0x96,
+0x27, 0x78, 0x81, 0x8f, 0x67, 0xe3, 0x46, 0x74, 0x54, 0x8e, 0xd9, 0x0d, 0x69, 0xe2, 0x4a, 0xf4,
+0x4d, 0x74, 0x03, 0xff, 0xb2, 0x77, 0xed, 0x95, 0x67, 0x97, 0xe4, 0xb1, 0xc5, 0xab, 0xbf, 0x6a,
+0x23, 0xe8, 0xd4, 0x94, 0xe2, 0x44, 0x28, 0x62, 0xc4, 0x4b, 0xe2, 0xf0, 0xd8, 0xe2, 0x29, 0x6b,
+0x1a, 0x70, 0x7e, 0x24, 0x61, 0x93, 0x7b, 0x4f, 0x03, 0x32, 0x25, 0x0d, 0x45, 0x24, 0x2b, 0x96,
+0xb4, 0x46, 0x6a, 0xbf, 0x4a, 0x0b, 0xf7, 0x9a, 0x8f, 0xc1, 0xac, 0x1a, 0xc5, 0x67, 0xf3, 0x6f,
+0x34, 0xd2, 0xfa, 0x73, 0x63, 0x8c, 0xef, 0x16, 0xb0, 0xa8, 0xa4, 0x46, 0x2a, 0xf8, 0xeb, 0x12,
+0xec, 0x72, 0xb4, 0xef, 0xf8, 0x2b, 0x7e, 0x8c, 0x52, 0xc0, 0x8b, 0x84, 0x54, 0xf9, 0x2f, 0x3e,
+0xe3, 0x55, 0xa8, 0xdc, 0x66, 0xb1, 0xd9, 0xe1, 0x5f, 0xd8, 0xb3, 0x8c, 0x59, 0x34, 0x59, 0xa4,
+0xab, 0x4f, 0x6c, 0xbb, 0x1f, 0x18, 0xdb, 0x75, 0xab, 0xd8, 0xcb, 0x92, 0xcd, 0x94, 0x38, 0x61,
+0x0e, 0x07, 0x06, 0x1f, 0x4b, 0x46, 0x10, 0xf1, 0x15, 0xbe, 0x8d, 0x85, 0x5c, 0x3b, 0x4a, 0x2b,
+0x81, 0x79, 0x0f, 0xb4, 0x69, 0x9f, 0x49, 0x50, 0x97, 0x4d, 0xf7, 0x0e, 0x56, 0x5d, 0xc0, 0x95,
+0x6a, 0xc2, 0x36, 0xc3, 0x1b, 0x68, 0xc9, 0xf5, 0x2a, 0xdc, 0x47, 0x9a, 0xbe, 0xb2, 0xce, 0xc5,
+0x25, 0xe8, 0xfa, 0x03, 0xb9, 0xda, 0xf9, 0x16, 0x6e, 0x91, 0x84, 0xf5, 0x1c, 0x28, 0xc8, 0xfc,
+0x26, 0xcc, 0xd7, 0x1c, 0x90, 0x56, 0xa7, 0x5f, 0x6f, 0x3a, 0x04, 0xbc, 0xcd, 0x78, 0x89, 0x0b,
+0x8e, 0x0f, 0x2f, 0xa3, 0xaa, 0x4f, 0xa2, 0x1b, 0x12, 0x3d, 0x16, 0x08, 0x40, 0x0f, 0xf1, 0x46,
+0x4c, 0xd7, 0xaa, 0x7b, 0x08, 0xc1, 0x0a, 0xf5, 0x6d, 0x27, 0xde, 0x02, 0x8f, 0xca, 0xc3, 0xb5,
+0x2b, 0xca, 0xe9, 0xeb, 0xc8, 0x21, 0x53, 0x38, 0xa5, 0xcc, 0x3b, 0xd8, 0x77, 0x37, 0x30, 0xa2,
+0x4f, 0xd9, 0x6f, 0xd1, 0xf2, 0x40, 0xad, 0x41, 0x7a, 0x17, 0xc5, 0xd6, 0x4a, 0x35, 0x89, 0xb7,
+0x41, 0xd5, 0x7c, 0x86, 0x7f, 0x55, 0x4d, 0x83, 0x4a, 0xa5, 0x73, 0x20, 0xc0, 0x3a, 0xaf, 0x90,
+0xf1, 0x9a, 0x24, 0x8e, 0xd9, 0x8e, 0x71, 0xca, 0x7b, 0xb8, 0x86, 0xda, 0xb2, 0x8f, 0x99, 0x3e,
+0x1d, 0x13, 0x0d, 0x12, 0x11, 0xee, 0xd4, 0xab, 0xf0, 0xe9, 0x15, 0x76, 0x02, 0xe4, 0xe0, 0xdf,
+0xaa, 0x20, 0x1e, 0x5b, 0x61, 0x85, 0x64, 0x40, 0xa9, 0x90, 0x97, 0x0d, 0xad, 0x53, 0xd2, 0x5a,
+0x1d, 0x87, 0x6a, 0x00, 0x97, 0x65, 0x62, 0xb4, 0xbe, 0x6f, 0x6a, 0xa7, 0xf5, 0x2c, 0x42, 0xed,
+0x32, 0xad, 0xb6, 0x21, 0x9e, 0xbe, 0xbc, 0x30, 0x82, 0x02, 0xc3, 0x30, 0x82, 0x02, 0x4a, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+0x04, 0x03, 0x02, 0x30, 0x81, 0xaa, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x47, 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x06, 0x41, 0x74,
+0x68, 0x65, 0x6e, 0x73, 0x31, 0x44, 0x30, 0x42, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x3b, 0x48,
+0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63,
+0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e,
+0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x2e,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x44, 0x30, 0x42, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x13, 0x3b, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63,
+0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61,
+0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35,
+0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x37, 0x30, 0x37, 0x31, 0x30, 0x33, 0x37, 0x31, 0x32,
+0x5a, 0x17, 0x0d, 0x34, 0x30, 0x30, 0x36, 0x33, 0x30, 0x31, 0x30, 0x33, 0x37, 0x31, 0x32, 0x5a,
+0x30, 0x81, 0xaa, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x52,
+0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x06, 0x41, 0x74, 0x68, 0x65, 0x6e,
+0x73, 0x31, 0x44, 0x30, 0x42, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x3b, 0x48, 0x65, 0x6c, 0x6c,
+0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e,
+0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69,
+0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x2e, 0x20, 0x41, 0x75,
+0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x44, 0x30, 0x42, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x3b, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65,
+0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68,
+0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x45, 0x43,
+0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x35, 0x30, 0x76, 0x30,
+0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
+0x22, 0x03, 0x62, 0x00, 0x04, 0x92, 0xa0, 0x41, 0xe8, 0x4b, 0x82, 0x84, 0x5c, 0xe2, 0xf8, 0x31,
+0x11, 0x99, 0x86, 0x64, 0x4e, 0x09, 0x25, 0x2f, 0x9d, 0x41, 0x2f, 0x0a, 0xae, 0x35, 0x4f, 0x74,
+0x95, 0xb2, 0x51, 0x64, 0x6b, 0x8d, 0x6b, 0xe6, 0x3f, 0x70, 0x95, 0xf0, 0x05, 0x44, 0x47, 0xa6,
+0x72, 0x38, 0x50, 0x76, 0x95, 0x02, 0x5a, 0x8e, 0xae, 0x28, 0x9e, 0xf9, 0x2d, 0x4e, 0x99, 0xef,
+0x2c, 0x48, 0x6f, 0x4c, 0x25, 0x29, 0xe8, 0xd1, 0x71, 0x5b, 0xdf, 0x1d, 0xc1, 0x75, 0x37, 0xb4,
+0xd7, 0xfa, 0x7b, 0x7a, 0x42, 0x9c, 0x6a, 0x0a, 0x56, 0x5a, 0x7c, 0x69, 0x0b, 0xaa, 0x80, 0x09,
+0x24, 0x6c, 0x7e, 0xc1, 0x46, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13,
+0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+0x0e, 0x04, 0x16, 0x04, 0x14, 0xb4, 0x22, 0x0b, 0x82, 0x99, 0x24, 0x01, 0x0e, 0x9c, 0xbb, 0xe4,
+0x0e, 0xfd, 0xbf, 0xfb, 0x97, 0x20, 0x93, 0x99, 0x2a, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
+0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x67, 0x00, 0x30, 0x64, 0x02, 0x30, 0x67, 0xce, 0x16, 0x62,
+0x38, 0xa2, 0xac, 0x62, 0x45, 0xa7, 0xa9, 0x95, 0x24, 0xc0, 0x1a, 0x27, 0x9c, 0x32, 0x3b, 0xc0,
+0xc0, 0xd5, 0xba, 0xa9, 0xe7, 0xf8, 0x04, 0x43, 0x53, 0x85, 0xee, 0x52, 0x21, 0xde, 0x9d, 0xf5,
+0x25, 0x83, 0x3e, 0x9e, 0x58, 0x4b, 0x2f, 0xd7, 0x67, 0x13, 0x0e, 0x21, 0x02, 0x30, 0x05, 0xe1,
+0x75, 0x01, 0xde, 0x68, 0xed, 0x2a, 0x1f, 0x4d, 0x4c, 0x09, 0x08, 0x0d, 0xec, 0x4b, 0xad, 0x64,
+0x17, 0x28, 0xe7, 0x75, 0xce, 0x45, 0x65, 0x72, 0x21, 0x17, 0xcb, 0x22, 0x41, 0x0e, 0x8c, 0x13,
+0x98, 0x38, 0x9a, 0x54, 0x6d, 0x9b, 0xca, 0xe2, 0x7c, 0xea, 0x02, 0x58, 0x22, 0x91, 0x30, 0x82,
+0x06, 0x5b, 0x30, 0x82, 0x04, 0x43, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 0xca, 0xe9,
+0x1b, 0x89, 0xf1, 0x55, 0x03, 0x0d, 0xa3, 0xe6, 0x41, 0x6d, 0xc4, 0xe3, 0xa6, 0xe1, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x12, 0x30, 0x10,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x44, 0x68, 0x69, 0x6d, 0x79, 0x6f, 0x74, 0x69, 0x73,
+0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x13, 0x30, 0x30, 0x30, 0x32, 0x20,
+0x34, 0x38, 0x31, 0x34, 0x36, 0x33, 0x30, 0x38, 0x31, 0x30, 0x30, 0x30, 0x33, 0x36, 0x31, 0x19,
+0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e,
+0x61, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x31,
+0x30, 0x30, 0x31, 0x30, 0x38, 0x33, 0x32, 0x32, 0x37, 0x5a, 0x17, 0x0d, 0x33, 0x33, 0x31, 0x30,
+0x30, 0x31, 0x30, 0x38, 0x33, 0x32, 0x32, 0x37, 0x5a, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x0c, 0x09, 0x44, 0x68, 0x69, 0x6d, 0x79, 0x6f, 0x74, 0x69, 0x73, 0x31, 0x1c, 0x30, 0x1a,
+0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x13, 0x30, 0x30, 0x30, 0x32, 0x20, 0x34, 0x38, 0x31, 0x34,
+0x36, 0x33, 0x30, 0x38, 0x31, 0x30, 0x30, 0x30, 0x33, 0x36, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x0c, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
+0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xcd, 0x18, 0x39, 0x65, 0x1a, 0x59, 0xb1, 0xea, 0x64, 0x16,
+0x0e, 0x8c, 0x94, 0x24, 0x95, 0x7c, 0x83, 0xd3, 0xc5, 0x39, 0x26, 0xdc, 0x0c, 0xef, 0x16, 0x57,
+0x8d, 0xd7, 0xd8, 0xac, 0xa3, 0x42, 0x7f, 0x82, 0xca, 0xed, 0xcd, 0x5b, 0xdb, 0x0e, 0xb7, 0x2d,
+0xed, 0x45, 0x08, 0x17, 0xb2, 0xd9, 0xb3, 0xcb, 0xd6, 0x17, 0x52, 0x72, 0x28, 0xdb, 0x8e, 0x4e,
+0x9e, 0x8a, 0xb6, 0x0b, 0xf9, 0x9e, 0x84, 0x9a, 0x4d, 0x76, 0xde, 0x22, 0x29, 0x5c, 0xd2, 0xb3,
+0xd2, 0x06, 0x3e, 0x30, 0x39, 0xa9, 0x74, 0xa3, 0x92, 0x56, 0x1c, 0xa1, 0x6f, 0x4c, 0x0a, 0x20,
+0x6d, 0x9f, 0x23, 0x7a, 0xb4, 0xc6, 0xda, 0x2c, 0xe4, 0x1d, 0x2c, 0xdc, 0xb3, 0x28, 0xd0, 0x13,
+0xf2, 0x4c, 0x4e, 0x02, 0x49, 0xa1, 0x54, 0x40, 0x9e, 0xe6, 0xe5, 0x05, 0xa0, 0x2d, 0x84, 0xc8,
+0xff, 0x98, 0x6c, 0xd0, 0xeb, 0x8a, 0x1a, 0x84, 0x08, 0x1e, 0xb7, 0x68, 0x23, 0xee, 0x23, 0xd5,
+0x70, 0xce, 0x6d, 0x51, 0x69, 0x10, 0xee, 0xa1, 0x7a, 0xc2, 0xd1, 0x22, 0x31, 0xc2, 0x82, 0x85,
+0xd2, 0xf2, 0x55, 0x76, 0x50, 0x7c, 0x25, 0x7a, 0xc9, 0x84, 0x5c, 0x0b, 0xac, 0xdd, 0x42, 0x4e,
+0x2b, 0xe7, 0x82, 0xa2, 0x24, 0x89, 0xcb, 0x90, 0xb2, 0xd0, 0xee, 0x23, 0xba, 0x66, 0x4c, 0xbb,
+0x62, 0xa4, 0xf9, 0x53, 0x5a, 0x64, 0x7b, 0x7c, 0x98, 0xfa, 0xa3, 0x48, 0x9e, 0x0f, 0x95, 0xae,
+0xa7, 0x18, 0xf4, 0x6a, 0xec, 0x2e, 0x03, 0x45, 0xaf, 0xf0, 0x74, 0xf8, 0x2a, 0xcd, 0x7a, 0x5d,
+0xd1, 0xbe, 0x44, 0x26, 0x32, 0x29, 0xf1, 0xf1, 0xf5, 0x6c, 0xcc, 0x7e, 0x02, 0x21, 0x0b, 0x9f,
+0x6f, 0xa4, 0x3f, 0xbe, 0x9d, 0x53, 0xe2, 0xcf, 0x7d, 0xa9, 0x2c, 0x7c, 0x58, 0x1a, 0x97, 0xe1,
+0x3d, 0x37, 0x37, 0x18, 0x66, 0x28, 0xd2, 0x40, 0xc5, 0x51, 0x8a, 0x8c, 0xc3, 0x2d, 0xce, 0x53,
+0x88, 0x24, 0x58, 0x64, 0x30, 0x16, 0xc5, 0xaa, 0xe0, 0xd6, 0x0a, 0xa6, 0x40, 0xdf, 0x78, 0xf6,
+0xf5, 0x04, 0x7c, 0x69, 0x13, 0x84, 0xbc, 0xd1, 0xd1, 0xa7, 0x06, 0xcf, 0x01, 0xf7, 0x68, 0xc0,
+0xa8, 0x57, 0xbb, 0x3a, 0x61, 0xad, 0x04, 0x8c, 0x93, 0xe3, 0xad, 0xfc, 0xf0, 0xdb, 0x44, 0x6d,
+0x59, 0xdc, 0x49, 0x59, 0xae, 0xac, 0x9a, 0x99, 0x36, 0x30, 0x41, 0x7b, 0x76, 0x33, 0x22, 0x87,
+0xa3, 0xc2, 0x92, 0x86, 0x6e, 0xf9, 0x70, 0xee, 0xae, 0x87, 0x87, 0x95, 0x1b, 0xc4, 0x7a, 0xbd,
+0x31, 0xf3, 0xd4, 0xd2, 0xe5, 0x99, 0xff, 0xbe, 0x48, 0xec, 0x75, 0xf5, 0x78, 0x16, 0x1d, 0xa6,
+0x70, 0xc1, 0x7f, 0x3c, 0x1b, 0xa1, 0x92, 0xfb, 0xcf, 0xc8, 0x3c, 0xd6, 0xc5, 0x93, 0x0a, 0x8f,
+0xf5, 0x55, 0x3a, 0x76, 0x95, 0xce, 0x59, 0x98, 0x8a, 0x09, 0x95, 0x77, 0x32, 0x9a, 0x83, 0xba,
+0x2c, 0x04, 0x3a, 0x97, 0xbd, 0xd4, 0x2f, 0xbe, 0xd7, 0x6c, 0x9b, 0xa2, 0xca, 0x7d, 0x6d, 0x26,
+0xc9, 0x55, 0xd5, 0xcf, 0xc3, 0x79, 0x52, 0x08, 0x09, 0x99, 0x07, 0x24, 0x2d, 0x64, 0x25, 0x6b,
+0xa6, 0x21, 0x69, 0x9b, 0x6a, 0xdd, 0x74, 0x4d, 0x6b, 0x97, 0x7a, 0x41, 0xbd, 0xab, 0x17, 0xf9,
+0x90, 0x17, 0x48, 0x8f, 0x36, 0xf9, 0x2d, 0xd5, 0xc5, 0xdb, 0xee, 0xaa, 0x85, 0x45, 0x41, 0xfa,
+0xcd, 0x3a, 0x45, 0xb1, 0x68, 0xe6, 0x36, 0x4c, 0x9b, 0x90, 0x57, 0xec, 0x23, 0xb9, 0x87, 0x08,
+0xc2, 0xc4, 0x09, 0xf1, 0x97, 0x86, 0x2a, 0x28, 0x4d, 0xe2, 0x74, 0xc0, 0xda, 0xc4, 0x8c, 0xdb,
+0xdf, 0xe2, 0xa1, 0x17, 0x59, 0xce, 0x24, 0x59, 0x74, 0x31, 0xda, 0x7f, 0xfd, 0x30, 0x6d, 0xd9,
+0xdc, 0xe1, 0x6a, 0xe1, 0xfc, 0x5f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1a, 0x30,
+0x82, 0x01, 0x16, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x18,
+0x87, 0x56, 0xe0, 0x6e, 0x77, 0xee, 0x24, 0x35, 0x3c, 0x4e, 0x73, 0x9a, 0x1f, 0xd6, 0xe1, 0xe2,
+0x79, 0x7e, 0x2b, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+0x18, 0x87, 0x56, 0xe0, 0x6e, 0x77, 0xee, 0x24, 0x35, 0x3c, 0x4e, 0x73, 0x9a, 0x1f, 0xd6, 0xe1,
+0xe2, 0x79, 0x7e, 0x2b, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3d, 0x30, 0x3b, 0x30,
+0x39, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x31, 0x30, 0x2f, 0x06, 0x08, 0x2b, 0x06, 0x01,
+0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x23, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
+0x77, 0x77, 0x77, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61, 0x2e, 0x66, 0x72, 0x2f,
+0x61, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x2f, 0x30, 0x6d, 0x06, 0x03, 0x55, 0x1d,
+0x1f, 0x04, 0x66, 0x30, 0x64, 0x30, 0x2f, 0xa0, 0x2d, 0xa0, 0x2b, 0x86, 0x29, 0x68, 0x74, 0x74,
+0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61,
+0x2e, 0x66, 0x72, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61, 0x72, 0x6f, 0x6f, 0x74,
+0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x31, 0xa0, 0x2f, 0xa0, 0x2d, 0x86, 0x2b, 0x68, 0x74,
+0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x64, 0x68, 0x69, 0x6d, 0x79, 0x6f, 0x74,
+0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61, 0x72,
+0x6f, 0x6f, 0x74, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x94, 0xb8, 0x9e,
+0x4f, 0xf0, 0xe3, 0x95, 0x08, 0x22, 0xe7, 0xcd, 0x68, 0x41, 0xf7, 0x1c, 0x55, 0xd5, 0x7c, 0x00,
+0xe2, 0x2d, 0x3a, 0x89, 0x5d, 0x68, 0x38, 0x2f, 0x51, 0x22, 0x0b, 0x4a, 0x8d, 0xcb, 0xe9, 0xbb,
+0x5d, 0x3e, 0xbb, 0x5c, 0x3d, 0xb1, 0x28, 0xfe, 0xe4, 0x53, 0x55, 0x13, 0xcf, 0xa1, 0x90, 0x1b,
+0x02, 0x1d, 0x5f, 0x66, 0x46, 0x09, 0x33, 0x28, 0xe1, 0x0d, 0x24, 0x97, 0x70, 0xd3, 0x10, 0x1f,
+0xea, 0x64, 0x57, 0x96, 0xbb, 0x5d, 0xda, 0xe7, 0xc4, 0x8c, 0x4f, 0x4c, 0x64, 0x46, 0x1d, 0x5c,
+0x87, 0xe3, 0x59, 0xde, 0x42, 0xd1, 0x9b, 0xa8, 0x7e, 0xa6, 0x89, 0xdd, 0x8f, 0x1c, 0xc9, 0x30,
+0x82, 0xed, 0x3b, 0x9c, 0xcd, 0xc0, 0xe9, 0x19, 0xe0, 0x6a, 0xd8, 0x02, 0x75, 0x37, 0xab, 0xf7,
+0x34, 0x28, 0x28, 0x91, 0xf2, 0x04, 0x0a, 0x4f, 0x35, 0xe3, 0x60, 0x26, 0x01, 0xfa, 0xd0, 0x11,
+0x8c, 0xf9, 0x11, 0x6a, 0xee, 0xaf, 0x3d, 0xc3, 0x50, 0xd3, 0x8f, 0x5f, 0x33, 0x79, 0x3c, 0x86,
+0xa8, 0x73, 0x45, 0x90, 0x8c, 0x20, 0xb6, 0x72, 0x73, 0x17, 0x23, 0xbe, 0x07, 0x65, 0xe5, 0x78,
+0x92, 0x0d, 0xba, 0x01, 0xc0, 0xeb, 0x8c, 0x1c, 0x66, 0xbf, 0xac, 0x86, 0x77, 0x01, 0x94, 0x0d,
+0x9c, 0xe6, 0xe9, 0x39, 0x8d, 0x1f, 0xa6, 0x51, 0x8c, 0x99, 0x0c, 0x39, 0x77, 0xe1, 0xb4, 0x9b,
+0xfa, 0x1c, 0x67, 0x57, 0x6f, 0x6a, 0x6a, 0x8e, 0xa9, 0x2b, 0x4c, 0x57, 0x79, 0x7a, 0x57, 0x22,
+0xcf, 0xcd, 0x5f, 0x63, 0x46, 0x8d, 0x5c, 0x59, 0x3a, 0x86, 0xf8, 0x32, 0x47, 0x62, 0xa3, 0x67,
+0x0d, 0x18, 0x91, 0xdc, 0xfb, 0xa6, 0x6b, 0xf5, 0x48, 0x61, 0x73, 0x23, 0x59, 0x8e, 0x02, 0xa7,
+0xbc, 0x44, 0xea, 0xf4, 0x49, 0x9d, 0xf1, 0x54, 0x58, 0xf9, 0x60, 0xaf, 0xda, 0x18, 0xa4, 0x2f,
+0x28, 0x45, 0xdc, 0x7a, 0xa0, 0x88, 0x86, 0x5d, 0xf3, 0x3b, 0xe7, 0xff, 0x29, 0x35, 0x80, 0xfc,
+0x64, 0x43, 0x94, 0xe6, 0xe3, 0x1c, 0x6f, 0xbe, 0xad, 0x0e, 0x2a, 0x63, 0x99, 0x2b, 0xc9, 0x7e,
+0x85, 0xf6, 0x71, 0xe8, 0x06, 0x03, 0x95, 0xfe, 0xde, 0x8f, 0x48, 0x1c, 0x5a, 0xd4, 0x92, 0xe8,
+0x2b, 0xee, 0xe7, 0x31, 0xdb, 0xba, 0x04, 0x6a, 0x87, 0x98, 0xe7, 0xc5, 0x5f, 0xef, 0x7d, 0xa7,
+0x22, 0xf7, 0x01, 0xd8, 0x4d, 0xf9, 0x89, 0xd0, 0x0e, 0x9a, 0x05, 0x59, 0xa4, 0x9e, 0x98, 0xd9,
+0x6f, 0x2b, 0xca, 0x70, 0xbe, 0x64, 0xc2, 0x55, 0xa3, 0xf4, 0xe9, 0xaf, 0xc3, 0x92, 0x29, 0xdc,
+0x88, 0x16, 0x24, 0x99, 0x3c, 0x8d, 0x26, 0x98, 0xb6, 0x5b, 0xb7, 0xcc, 0xce, 0xb7, 0x37, 0x07,
+0xfd, 0x26, 0xd9, 0x98, 0x85, 0x24, 0xff, 0x59, 0x23, 0x03, 0x9a, 0xed, 0x9d, 0x9d, 0xa8, 0xe4,
+0x5e, 0x38, 0xce, 0xd7, 0x52, 0x0d, 0x6f, 0xd2, 0x3f, 0x6d, 0xb1, 0x05, 0x6b, 0x49, 0xce, 0x8a,
+0x91, 0x46, 0x73, 0xf4, 0xf6, 0x2f, 0xf0, 0xa8, 0x73, 0x77, 0x0e, 0x65, 0xac, 0xa1, 0x8d, 0x66,
+0x52, 0x69, 0x7e, 0x4b, 0x68, 0x0c, 0xc7, 0x1e, 0x37, 0x27, 0x83, 0xa5, 0x8c, 0xc7, 0x02, 0xe4,
+0x14, 0xcd, 0x49, 0x01, 0xb0, 0x73, 0xb3, 0xfd, 0xc6, 0x90, 0x3a, 0x6f, 0xd2, 0x6c, 0xed, 0x3b,
+0xee, 0xec, 0x91, 0xbe, 0xa2, 0x43, 0x5d, 0x8b, 0x00, 0x4a, 0x66, 0x25, 0x44, 0x70, 0xde, 0x40,
+0x0f, 0xf8, 0x7c, 0x15, 0xf7, 0xa2, 0xce, 0x3c, 0xd7, 0x5e, 0x13, 0x8c, 0x81, 0x17, 0x18, 0x17,
+0xd1, 0xbd, 0xf1, 0x77, 0x10, 0x3a, 0xd4, 0x65, 0x39, 0xc1, 0x27, 0xac, 0x57, 0x2c, 0x25, 0x54,
+0xff, 0xa2, 0xda, 0x4f, 0x8a, 0x61, 0x39, 0x5e, 0xae, 0x3d, 0x4a, 0x8c, 0xbd, 0x30, 0x82, 0x04,
+0x20, 0x30, 0x82, 0x03, 0x08, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x84, 0x82, 0x2c,
+0x5f, 0x1c, 0x62, 0xd0, 0x40, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x9c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x50, 0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x50,
+0x61, 0x6e, 0x61, 0x6d, 0x61, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0b,
+0x50, 0x61, 0x6e, 0x61, 0x6d, 0x61, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53,
+0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20, 0x52, 0x2e, 0x4c,
+0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1e, 0x54, 0x72, 0x75, 0x73,
+0x74, 0x43, 0x6f, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x0c, 0x0e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x45, 0x43,
+0x41, 0x2d, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x32, 0x30, 0x34, 0x31, 0x32, 0x33,
+0x32, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x31, 0x32, 0x33, 0x31, 0x31, 0x37, 0x32, 0x38,
+0x30, 0x37, 0x5a, 0x30, 0x81, 0x9c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x50, 0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x50, 0x61,
+0x6e, 0x61, 0x6d, 0x61, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0b, 0x50,
+0x61, 0x6e, 0x61, 0x6d, 0x61, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x0c, 0x1b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53, 0x79,
+0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20, 0x52, 0x2e, 0x4c, 0x2e,
+0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1e, 0x54, 0x72, 0x75, 0x73, 0x74,
+0x43, 0x6f, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
+0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x0c, 0x0e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x45, 0x43, 0x41,
+0x2d, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
+0x01, 0x01, 0x00, 0xcf, 0x8f, 0xe0, 0x11, 0xb5, 0x9f, 0xa8, 0x76, 0x76, 0xdb, 0xdf, 0x0f, 0x54,
+0xef, 0x73, 0x63, 0x29, 0x82, 0xad, 0x47, 0xc6, 0xa3, 0x6b, 0xed, 0xfe, 0x5f, 0x33, 0xf8, 0x43,
+0x51, 0xe9, 0x1a, 0x33, 0x91, 0x31, 0x17, 0xa0, 0x74, 0xc4, 0xd4, 0xa7, 0x01, 0xe6, 0xb2, 0x92,
+0x3e, 0x6a, 0x9d, 0xed, 0x0e, 0xf9, 0x74, 0x98, 0x40, 0xd3, 0x3f, 0x03, 0x80, 0x06, 0x82, 0x40,
+0xe8, 0xb1, 0xe2, 0xa7, 0x51, 0xa7, 0x1d, 0x83, 0x26, 0x6b, 0xab, 0xde, 0xfa, 0x17, 0x91, 0x2b,
+0xd8, 0xc6, 0xac, 0x1e, 0xb1, 0x9e, 0x19, 0x01, 0xd5, 0x97, 0xa6, 0xea, 0x0d, 0xb7, 0xc4, 0x55,
+0x1f, 0x27, 0x7c, 0xd2, 0x08, 0xd5, 0x76, 0x1f, 0x29, 0x15, 0x87, 0x40, 0x39, 0xdd, 0x38, 0x45,
+0x11, 0x75, 0xd0, 0x9a, 0xa7, 0x34, 0xe0, 0xbf, 0xcd, 0xc8, 0x52, 0x1d, 0xb9, 0x47, 0x7e, 0x0d,
+0xb8, 0xbb, 0xc6, 0x0c, 0xf6, 0x73, 0x57, 0x16, 0x5a, 0x7e, 0x43, 0x91, 0x1f, 0x55, 0x3a, 0xc6,
+0x6d, 0x44, 0x04, 0xaa, 0x9c, 0xa9, 0x9c, 0xa7, 0x4c, 0x89, 0x17, 0x83, 0xae, 0xa3, 0x04, 0x5e,
+0x52, 0x80, 0x8b, 0x1e, 0x12, 0x25, 0x11, 0x19, 0xd7, 0x0c, 0x7d, 0x7d, 0x31, 0x44, 0x41, 0xea,
+0xdb, 0xaf, 0xb0, 0x1c, 0xef, 0x81, 0xd0, 0x2c, 0xc5, 0x9a, 0x21, 0x9b, 0x3d, 0xed, 0x42, 0x3b,
+0x50, 0x26, 0xf2, 0xec, 0xce, 0x71, 0x61, 0x06, 0x62, 0x21, 0x54, 0x4e, 0x7f, 0xc1, 0x9d, 0x3e,
+0x7f, 0x20, 0x8c, 0x80, 0xcb, 0x2a, 0xd8, 0x97, 0x62, 0xc8, 0x83, 0x33, 0x91, 0x7d, 0xb0, 0xa2,
+0x5a, 0x0f, 0x57, 0xe8, 0x3b, 0xcc, 0xf2, 0x25, 0xb2, 0xd4, 0x7c, 0x2f, 0xec, 0x4d, 0xc6, 0xa1,
+0x3a, 0x15, 0x7a, 0xe7, 0xb6, 0x5d, 0x35, 0xf5, 0xf6, 0x48, 0x4a, 0x36, 0x45, 0x66, 0xd4, 0xba,
+0x98, 0x58, 0xc1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03,
+0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x44, 0x9e, 0x48, 0xf5, 0xcc, 0x6d, 0x48, 0xd4, 0xa0,
+0x4b, 0x7f, 0xfe, 0x59, 0x24, 0x2f, 0x83, 0x97, 0x99, 0x9a, 0x86, 0x30, 0x1f, 0x06, 0x03, 0x55,
+0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x44, 0x9e, 0x48, 0xf5, 0xcc, 0x6d, 0x48, 0xd4,
+0xa0, 0x4b, 0x7f, 0xfe, 0x59, 0x24, 0x2f, 0x83, 0x97, 0x99, 0x9a, 0x86, 0x30, 0x0f, 0x06, 0x03,
+0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+0x00, 0x05, 0x3e, 0x35, 0x5c, 0x15, 0x70, 0x9b, 0xc9, 0xc7, 0x73, 0x61, 0x6f, 0x72, 0x2b, 0xd4,
+0xc2, 0x8f, 0xf2, 0x43, 0x5d, 0x02, 0xce, 0xc4, 0x94, 0xb9, 0x94, 0x11, 0x83, 0x67, 0x5d, 0xe2,
+0x67, 0x6c, 0x75, 0x76, 0xbf, 0xbb, 0x0c, 0xaa, 0x36, 0xc6, 0xad, 0x47, 0x93, 0x63, 0xdc, 0x1e,
+0x7e, 0xd6, 0xde, 0x2e, 0xfe, 0xe9, 0x19, 0x32, 0x38, 0x03, 0x7f, 0x14, 0xf6, 0x00, 0x73, 0x2c,
+0x59, 0xb1, 0x21, 0x06, 0xe1, 0xfb, 0xac, 0x18, 0x95, 0x0c, 0xa3, 0xff, 0x99, 0x96, 0xf7, 0x2b,
+0x27, 0x9b, 0xd5, 0x24, 0xcc, 0x1d, 0xdd, 0xc1, 0x3a, 0xe0, 0x98, 0x44, 0xb0, 0xc4, 0xe4, 0x3e,
+0x77, 0xb1, 0x73, 0xa9, 0x64, 0x2c, 0xf6, 0x1c, 0x01, 0x7c, 0x3f, 0x5d, 0x45, 0x85, 0xc0, 0x85,
+0xe7, 0x25, 0x8f, 0x95, 0xdc, 0x17, 0xf3, 0x3c, 0x9f, 0x1a, 0x6e, 0xb0, 0xca, 0xe3, 0x1d, 0x2a,
+0xe9, 0x4c, 0x63, 0xfa, 0x24, 0x61, 0x62, 0xd6, 0xda, 0x7e, 0xb6, 0x1c, 0x6c, 0xf5, 0x02, 0x1d,
+0xd4, 0x2a, 0xdd, 0x55, 0x90, 0xeb, 0x2a, 0x11, 0x47, 0x3c, 0x2e, 0x5e, 0x74, 0xb2, 0x82, 0x22,
+0xa5, 0x7d, 0x53, 0x1f, 0x45, 0xec, 0x27, 0x91, 0x7d, 0xe7, 0x22, 0x16, 0xe8, 0xc0, 0x68, 0x36,
+0xd8, 0xc6, 0xf1, 0x4f, 0x80, 0x44, 0x32, 0xf9, 0xe1, 0xd1, 0xd1, 0x1d, 0xaa, 0xde, 0xa8, 0xab,
+0x9c, 0x04, 0xaf, 0xad, 0x20, 0x0e, 0x64, 0x98, 0x4d, 0xa5, 0x6b, 0xc0, 0x48, 0x58, 0x96, 0x69,
+0x4d, 0xdc, 0x07, 0x8c, 0x51, 0x93, 0xa2, 0xdf, 0x9f, 0x0f, 0x3d, 0x8b, 0x60, 0xb4, 0x82, 0x8d,
+0xaa, 0x08, 0x4e, 0x62, 0x45, 0xe0, 0xf9, 0x0b, 0xd2, 0xe0, 0xe0, 0x3c, 0x5b, 0xde, 0x5c, 0x71,
+0x27, 0x25, 0xc2, 0xe6, 0x03, 0x81, 0x8b, 0x10, 0x53, 0xe3, 0xc7, 0x55, 0xa2, 0xb4, 0x9f, 0xd7,
+0xe6, 0x30, 0x82, 0x06, 0x2f, 0x30, 0x82, 0x04, 0x17, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08,
+0x25, 0xa1, 0xdf, 0xca, 0x33, 0xcb, 0x59, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xa4, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08,
+0x0c, 0x06, 0x50, 0x61, 0x6e, 0x61, 0x6d, 0x61, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04,
+0x07, 0x0c, 0x0b, 0x50, 0x61, 0x6e, 0x61, 0x6d, 0x61, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x24,
+0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f,
+0x72, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20,
+0x52, 0x2e, 0x4c, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1e, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x1f, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x41, 0x2d, 0x32, 0x30, 0x1e,
+0x17, 0x0d, 0x31, 0x36, 0x30, 0x32, 0x30, 0x34, 0x31, 0x32, 0x33, 0x32, 0x32, 0x33, 0x5a, 0x17,
+0x0d, 0x33, 0x34, 0x31, 0x32, 0x33, 0x31, 0x31, 0x37, 0x32, 0x36, 0x33, 0x39, 0x5a, 0x30, 0x81,
+0xa4, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x41, 0x31, 0x0f,
+0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x50, 0x61, 0x6e, 0x61, 0x6d, 0x61, 0x31,
+0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0b, 0x50, 0x61, 0x6e, 0x61, 0x6d, 0x61,
+0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1b,
+0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73,
+0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20, 0x52, 0x2e, 0x4c, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06,
+0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x43,
+0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x74, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74,
+0x20, 0x43, 0x41, 0x2d, 0x32, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
+0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xa7, 0x20, 0x6e, 0xc2, 0x2a, 0xa2, 0x62, 0x24, 0x95, 0x90,
+0x76, 0xc8, 0x38, 0x7e, 0x80, 0xd2, 0xab, 0xc1, 0x9b, 0x65, 0x05, 0x94, 0xf4, 0xc1, 0x0a, 0x10,
+0xd5, 0x02, 0xac, 0xed, 0x9f, 0x93, 0xc7, 0x87, 0xc8, 0xb0, 0x27, 0x2b, 0x42, 0x0c, 0x3d, 0x0a,
+0x3e, 0x41, 0x5a, 0x9e, 0x75, 0xdd, 0x8d, 0xca, 0xe0, 0x9b, 0xec, 0x68, 0x32, 0xa4, 0x69, 0x92,
+0x68, 0x8c, 0x0b, 0x81, 0x0e, 0x56, 0xa0, 0x3e, 0x1a, 0xdd, 0x2c, 0x25, 0x14, 0x82, 0x2f, 0x97,
+0xd3, 0x64, 0x46, 0xf4, 0x54, 0xa9, 0xdc, 0x3a, 0x54, 0x2d, 0x31, 0x2b, 0x99, 0x82, 0xf2, 0xd9,
+0x2a, 0xd7, 0xef, 0x71, 0x00, 0xb8, 0x31, 0xa4, 0xbe, 0x7a, 0x24, 0x07, 0xc3, 0x42, 0x20, 0xf2,
+0x8a, 0xd4, 0x92, 0x04, 0x1b, 0x65, 0x56, 0x4c, 0x6c, 0xd4, 0xfb, 0xb6, 0x61, 0x5a, 0x47, 0x23,
+0xb4, 0xd8, 0x69, 0xb4, 0xb7, 0x3a, 0xd0, 0x74, 0x3c, 0x0c, 0x75, 0xa1, 0x8c, 0x4e, 0x76, 0xa1,
+0xe9, 0xdb, 0x2a, 0xa5, 0x3b, 0xfa, 0xce, 0xb0, 0xff, 0x7e, 0x6a, 0x28, 0xfd, 0x27, 0x1c, 0xc8,
+0xb1, 0xe9, 0x29, 0xf1, 0x57, 0x6e, 0x64, 0xb4, 0xd0, 0xc1, 0x15, 0x6d, 0x0e, 0xbe, 0x2e, 0x0e,
+0x46, 0xc8, 0x5e, 0xf4, 0x51, 0xfe, 0xef, 0x0e, 0x63, 0x3a, 0x3b, 0x71, 0xba, 0xcf, 0x6f, 0x59,
+0xca, 0x0c, 0xe3, 0x9b, 0x5d, 0x49, 0xb8, 0x4c, 0xe2, 0x57, 0xb1, 0x98, 0x8a, 0x42, 0x57, 0x9c,
+0x76, 0xef, 0xef, 0xbd, 0xd1, 0x68, 0xa8, 0xd2, 0xf4, 0x09, 0xbb, 0x77, 0x35, 0xbe, 0x25, 0x82,
+0x08, 0xc4, 0x16, 0x2c, 0x44, 0x20, 0x56, 0xa9, 0x44, 0x11, 0x77, 0xef, 0x5d, 0xb4, 0x1d, 0xaa,
+0x5e, 0x6b, 0x3e, 0x8b, 0x32, 0xf6, 0x07, 0x2f, 0x57, 0x04, 0x92, 0xca, 0xf5, 0xfe, 0x9d, 0xc2,
+0xe9, 0xe8, 0xb3, 0x8e, 0x4c, 0x4b, 0x02, 0x31, 0xd9, 0xe4, 0x3c, 0x48, 0x82, 0x27, 0xf7, 0x18,
+0x82, 0x76, 0x48, 0x3a, 0x71, 0xb1, 0x13, 0xa1, 0x39, 0xd5, 0x2e, 0xc5, 0x34, 0xc2, 0x1d, 0x62,
+0x85, 0xdf, 0x03, 0xfe, 0x4d, 0xf4, 0xaf, 0x3d, 0xdf, 0x5c, 0x5b, 0x8d, 0xfa, 0x70, 0xe1, 0xa5,
+0x7e, 0x27, 0xc7, 0x86, 0x2e, 0x6a, 0x8f, 0x12, 0xc6, 0x84, 0x5e, 0x43, 0x51, 0x50, 0x9c, 0x19,
+0x9b, 0x78, 0xe6, 0xfc, 0xf6, 0xed, 0x47, 0x7e, 0x7b, 0x3d, 0x66, 0xef, 0x13, 0x13, 0x88, 0x5f,
+0x3c, 0xa1, 0x63, 0xfb, 0xf9, 0xac, 0x87, 0x35, 0x9f, 0xf3, 0x82, 0x9e, 0xa4, 0x3f, 0x0a, 0x9c,
+0x31, 0x69, 0x8b, 0x99, 0xa4, 0x88, 0x4a, 0x8e, 0x6e, 0x66, 0x4d, 0xef, 0x16, 0xc4, 0x0f, 0x79,
+0x28, 0x21, 0x60, 0x0d, 0x85, 0x16, 0x7d, 0xd7, 0x54, 0x38, 0xf1, 0x92, 0x56, 0xfd, 0xb5, 0x33,
+0x4c, 0x83, 0xdc, 0xd7, 0x10, 0x9f, 0x4b, 0xfd, 0xc6, 0xf8, 0x42, 0xbd, 0xba, 0x7c, 0x73, 0x02,
+0xe0, 0xff, 0x7d, 0xcd, 0x5b, 0xe1, 0xd4, 0xac, 0x61, 0x7b, 0x57, 0xd5, 0x4a, 0x7b, 0x5b, 0xd4,
+0x85, 0x58, 0x27, 0x5d, 0xbf, 0xf8, 0x2b, 0x60, 0xac, 0xa0, 0x26, 0xae, 0x14, 0x21, 0x27, 0xc6,
+0x77, 0x9a, 0x33, 0x80, 0x3c, 0x5e, 0x46, 0x3f, 0xf7, 0xc3, 0xb1, 0xa3, 0x86, 0x33, 0xc6, 0xe8,
+0x5e, 0x0d, 0xb9, 0x35, 0x2c, 0xaa, 0x46, 0xc1, 0x85, 0x02, 0x75, 0x80, 0xa0, 0xeb, 0x24, 0xfb,
+0x15, 0xaa, 0xe4, 0x67, 0x7f, 0x6e, 0x77, 0x3f, 0xf4, 0x04, 0x8a, 0x2f, 0x7c, 0x7b, 0xe3, 0x17,
+0x61, 0xf0, 0xdd, 0x09, 0xa9, 0x20, 0xc8, 0xbe, 0x09, 0xa4, 0xd0, 0x7e, 0x44, 0xc3, 0xb2, 0x30,
+0x4a, 0x38, 0xaa, 0xa9, 0xec, 0x18, 0x9a, 0x07, 0x82, 0x2b, 0xdb, 0xb8, 0x9c, 0x18, 0xad, 0xda,
+0xe0, 0x46, 0x17, 0xac, 0xcf, 0x5d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd9, 0xfe, 0x21, 0x40, 0x6e, 0x94,
+0x9e, 0xbc, 0x9b, 0x3d, 0x9c, 0x7d, 0x98, 0x20, 0x19, 0xe5, 0x8c, 0x30, 0x62, 0xb2, 0x30, 0x1f,
+0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xd9, 0xfe, 0x21, 0x40, 0x6e,
+0x94, 0x9e, 0xbc, 0x9b, 0x3d, 0x9c, 0x7d, 0x98, 0x20, 0x19, 0xe5, 0x8c, 0x30, 0x62, 0xb2, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+0x82, 0x02, 0x01, 0x00, 0x9e, 0x45, 0x9e, 0x0c, 0x3b, 0xb6, 0xef, 0xe1, 0x3a, 0xc8, 0x7c, 0xd1,
+0x00, 0x3d, 0xcf, 0xe2, 0xea, 0x06, 0xb5, 0xb2, 0x3a, 0xbb, 0x06, 0x4b, 0x68, 0x7a, 0xd0, 0x23,
+0x97, 0x74, 0xa7, 0x2c, 0xf0, 0x08, 0xd8, 0x79, 0x5a, 0xd7, 0x5a, 0x84, 0x8a, 0xd8, 0x12, 0x9a,
+0x1b, 0xd9, 0x7d, 0x5c, 0x4d, 0x70, 0xc5, 0xa5, 0xf9, 0xab, 0xe5, 0xa3, 0x89, 0x89, 0xdd, 0x01,
+0xfa, 0xec, 0xdd, 0xf9, 0xe9, 0x92, 0x97, 0xdb, 0xb0, 0x46, 0x42, 0xf3, 0xd3, 0x62, 0xaa, 0x95,
+0xfe, 0x31, 0x67, 0x14, 0x69, 0x58, 0x90, 0x0a, 0xaa, 0x0b, 0xee, 0x37, 0x23, 0xc7, 0x50, 0x51,
+0xb4, 0xf5, 0x7e, 0x9e, 0xe3, 0x7b, 0xf7, 0xe4, 0xcc, 0x42, 0x32, 0x2d, 0x49, 0x0c, 0xcb, 0xff,
+0x49, 0x0c, 0x9b, 0x1e, 0x34, 0xfd, 0x6e, 0x6e, 0x96, 0x8a, 0x79, 0x03, 0xb6, 0x6f, 0xdb, 0x09,
+0xcb, 0xfd, 0x5f, 0x65, 0x14, 0x37, 0xe1, 0x38, 0xf5, 0xf3, 0x61, 0x16, 0x58, 0xe4, 0xb5, 0x6d,
+0x0d, 0x0b, 0x04, 0x1b, 0x3f, 0x50, 0x2d, 0x7f, 0xb3, 0xc7, 0x7a, 0x1a, 0x16, 0x80, 0x60, 0xf8,
+0x8a, 0x1f, 0xe9, 0x1b, 0x2a, 0xc6, 0xf9, 0xba, 0x01, 0x1a, 0x69, 0xbf, 0xd2, 0x58, 0xc7, 0x54,
+0x57, 0x08, 0x8f, 0xe1, 0x39, 0x60, 0x77, 0x4b, 0xac, 0x59, 0x84, 0x1a, 0x88, 0xf1, 0xdd, 0xcb,
+0x4f, 0x78, 0xd7, 0xe7, 0xe1, 0x33, 0x2d, 0xfc, 0xee, 0x41, 0xfa, 0x20, 0xb0, 0xbe, 0xcb, 0xf7,
+0x38, 0x94, 0xc0, 0xe1, 0xd0, 0x85, 0x0f, 0xbb, 0xed, 0x2c, 0x73, 0xab, 0xed, 0xfe, 0x92, 0x76,
+0x1a, 0x64, 0x7f, 0x5b, 0x0d, 0x33, 0x09, 0x07, 0x33, 0x7b, 0x06, 0x3f, 0x11, 0xa4, 0x5c, 0x70,
+0x3c, 0x85, 0xc0, 0xcf, 0xe3, 0x90, 0xa8, 0x83, 0x77, 0xfa, 0xdb, 0xe6, 0xc5, 0x8c, 0x68, 0x67,
+0x10, 0x67, 0xa5, 0x52, 0x2d, 0xf0, 0xc4, 0x99, 0x8f, 0x7f, 0xbf, 0xd1, 0x6b, 0xe2, 0xb5, 0x47,
+0xd6, 0xd9, 0xd0, 0x85, 0x99, 0x4d, 0x94, 0x9b, 0x0f, 0x4b, 0x8d, 0xee, 0x00, 0x5a, 0x47, 0x1d,
+0x11, 0x03, 0xac, 0x41, 0x18, 0xaf, 0x87, 0xb7, 0x6f, 0x0c, 0x3a, 0x8f, 0xca, 0xcf, 0xdc, 0x03,
+0xc1, 0xa2, 0x09, 0xc8, 0xe5, 0xfd, 0x80, 0x5e, 0xc8, 0x60, 0x42, 0x01, 0x1b, 0x1a, 0x53, 0x5a,
+0xbb, 0x37, 0xa6, 0xb7, 0xbc, 0xba, 0x84, 0xe9, 0x1e, 0x6c, 0x1a, 0xd4, 0x64, 0xda, 0xd4, 0x43,
+0xfe, 0x93, 0x8b, 0x4b, 0xf2, 0x2c, 0x79, 0x16, 0x10, 0xd4, 0x93, 0x0b, 0x88, 0x8f, 0xa1, 0xd8,
+0x86, 0x14, 0x46, 0x91, 0x47, 0x9b, 0x28, 0x24, 0xef, 0x57, 0x52, 0x4e, 0x5c, 0x42, 0x9c, 0xaa,
+0xf7, 0x49, 0xec, 0x27, 0xe8, 0x40, 0x1e, 0xb3, 0xa6, 0x89, 0x22, 0x72, 0x9c, 0xf5, 0x0d, 0x33,
+0xb4, 0x58, 0xa3, 0x30, 0x3b, 0xdd, 0xd4, 0x6a, 0x54, 0x93, 0xbe, 0x1a, 0x4d, 0xf3, 0x93, 0x94,
+0xf7, 0xfc, 0x84, 0x0b, 0x3f, 0x84, 0x20, 0x5c, 0x34, 0x03, 0x44, 0xc5, 0xda, 0xad, 0xbc, 0x0a,
+0xc1, 0x02, 0xcf, 0x1e, 0xe5, 0x94, 0xd9, 0xf3, 0x8e, 0x5b, 0xd8, 0x4c, 0xf0, 0x9d, 0xec, 0x61,
+0x17, 0xbb, 0x14, 0x32, 0x54, 0x0c, 0x02, 0x29, 0x93, 0x1e, 0x92, 0x86, 0xf6, 0x7f, 0xef, 0xe7,
+0x92, 0x05, 0x0e, 0x59, 0xdd, 0x99, 0x08, 0x2e, 0x2e, 0xfa, 0x9c, 0x00, 0x52, 0xd3, 0xc5, 0x66,
+0x29, 0xe4, 0xa7, 0x97, 0x44, 0xa4, 0x0e, 0x28, 0x81, 0x13, 0x35, 0xc5, 0xf6, 0x6f, 0x64, 0xe6,
+0x41, 0xc4, 0xd5, 0x2f, 0xcc, 0x34, 0x45, 0x25, 0xcf, 0x41, 0x00, 0x96, 0x3d, 0x4a, 0x2e, 0xc2,
+0x96, 0x98, 0x4f, 0x4e, 0x4a, 0x9c, 0x97, 0xb7, 0xdb, 0x1f, 0x92, 0x32, 0xc8, 0xff, 0x0f, 0x51,
+0x6e, 0xd6, 0xec, 0x09, 0x30, 0x82, 0x04, 0x30, 0x30, 0x82, 0x03, 0x18, 0xa0, 0x03, 0x02, 0x01,
+0x02, 0x02, 0x09, 0x00, 0xda, 0x9b, 0xec, 0x71, 0xf3, 0x03, 0xb0, 0x19, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xa4, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06,
+0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x50, 0x61, 0x6e, 0x61, 0x6d, 0x61, 0x31, 0x14, 0x30, 0x12,
+0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0b, 0x50, 0x61, 0x6e, 0x61, 0x6d, 0x61, 0x20, 0x43, 0x69,
+0x74, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1b, 0x54, 0x72, 0x75,
+0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e,
+0x20, 0x64, 0x65, 0x20, 0x52, 0x2e, 0x4c, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04,
+0x0b, 0x0c, 0x1e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74,
+0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x54, 0x72, 0x75, 0x73,
+0x74, 0x43, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x41,
+0x2d, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x32, 0x30, 0x34, 0x31, 0x32, 0x33, 0x32,
+0x31, 0x36, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x31, 0x32, 0x33, 0x31, 0x31, 0x37, 0x32, 0x33, 0x31,
+0x36, 0x5a, 0x30, 0x81, 0xa4, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x50, 0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x06, 0x50, 0x61, 0x6e,
+0x61, 0x6d, 0x61, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0b, 0x50, 0x61,
+0x6e, 0x61, 0x6d, 0x61, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x0c, 0x1b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x53, 0x79, 0x73,
+0x74, 0x65, 0x6d, 0x73, 0x20, 0x53, 0x2e, 0x20, 0x64, 0x65, 0x20, 0x52, 0x2e, 0x4c, 0x2e, 0x31,
+0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43,
+0x6f, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41,
+0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x0c, 0x16, 0x54, 0x72, 0x75, 0x73, 0x74, 0x43, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x43, 0x65, 0x72, 0x74, 0x20, 0x43, 0x41, 0x2d, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf, 0x8e, 0xb7, 0x95, 0xe2, 0xc2,
+0x26, 0x12, 0x6b, 0x33, 0x19, 0xc7, 0x40, 0x58, 0x0a, 0xab, 0x59, 0xaa, 0x8d, 0x00, 0xa3, 0xfc,
+0x80, 0xc7, 0x50, 0x7b, 0x8e, 0xd4, 0x20, 0x26, 0xba, 0x32, 0x12, 0xd8, 0x23, 0x54, 0x49, 0x25,
+0x10, 0x22, 0x98, 0x9d, 0x46, 0xd2, 0xc1, 0xc9, 0x9e, 0x4e, 0x1b, 0x2e, 0x2c, 0x0e, 0x38, 0xf3,
+0x1a, 0x25, 0x68, 0x1c, 0xa6, 0x5a, 0x05, 0xe6, 0x1e, 0x8b, 0x48, 0xbf, 0x98, 0x96, 0x74, 0x3e,
+0x69, 0xca, 0xe9, 0xb5, 0x78, 0xa5, 0x06, 0xbc, 0xd5, 0x00, 0x5e, 0x09, 0x0a, 0xf2, 0x27, 0x7a,
+0x52, 0xfc, 0x2d, 0xd5, 0xb1, 0xea, 0xb4, 0x89, 0x61, 0x24, 0xf3, 0x1a, 0x13, 0xdb, 0xa9, 0xcf,
+0x52, 0xed, 0x0c, 0x24, 0xba, 0xb9, 0x9e, 0xec, 0x7e, 0x00, 0x74, 0xfa, 0x93, 0xad, 0x6c, 0x29,
+0x92, 0xae, 0x51, 0xb4, 0xbb, 0xd3, 0x57, 0xbf, 0xb3, 0xf3, 0xa8, 0x8d, 0x9c, 0xf4, 0x24, 0x4b,
+0x2a, 0xd6, 0x99, 0x9e, 0xf4, 0x9e, 0xfe, 0xc0, 0x7e, 0x42, 0x3a, 0xe7, 0x0b, 0x95, 0x53, 0xda,
+0xb7, 0x68, 0x0e, 0x90, 0x4c, 0xfb, 0x70, 0x3f, 0x8f, 0x4a, 0x2c, 0x94, 0xf3, 0x26, 0xdd, 0x63,
+0x69, 0xa9, 0x94, 0xd8, 0x10, 0x4e, 0xc5, 0x47, 0x08, 0x90, 0x99, 0x1b, 0x17, 0x4d, 0xb9, 0x6c,
+0x6e, 0xef, 0x60, 0x95, 0x11, 0x8e, 0x21, 0x80, 0xb5, 0xbd, 0xa0, 0x73, 0xd8, 0xd0, 0xb2, 0x77,
+0xc4, 0x45, 0xea, 0x5a, 0x26, 0xfb, 0x66, 0x76, 0x76, 0xf8, 0x06, 0x1f, 0x61, 0x6d, 0x0f, 0x55,
+0xc5, 0x83, 0xb7, 0x10, 0x56, 0x72, 0x06, 0x07, 0xa5, 0xf3, 0xb1, 0x1a, 0x03, 0x05, 0x64, 0x0e,
+0x9d, 0x5a, 0x8a, 0xd6, 0x86, 0x70, 0x1b, 0x24, 0xde, 0xfe, 0x28, 0x8a, 0x2b, 0xd0, 0x6a, 0xb0,
+0xfc, 0x7a, 0xa2, 0xdc, 0xb2, 0x79, 0x0e, 0x8b, 0x65, 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xee, 0x6b,
+0x49, 0x3c, 0x7a, 0x3f, 0x0d, 0xe3, 0xb1, 0x09, 0xb7, 0x8a, 0xc8, 0xab, 0x19, 0x9f, 0x73, 0x33,
+0x50, 0xe7, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xee,
+0x6b, 0x49, 0x3c, 0x7a, 0x3f, 0x0d, 0xe3, 0xb1, 0x09, 0xb7, 0x8a, 0xc8, 0xab, 0x19, 0x9f, 0x73,
+0x33, 0x50, 0xe7, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x86, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x25, 0x18, 0xd4, 0x91, 0x8f, 0x13, 0xee, 0x8f,
+0x1e, 0x1d, 0x11, 0x53, 0xda, 0x2d, 0x44, 0x29, 0x19, 0xa0, 0x1e, 0x6b, 0x31, 0x9e, 0x4d, 0x0e,
+0x9e, 0xad, 0x3d, 0x5c, 0x41, 0x6f, 0x95, 0x2b, 0x24, 0xa1, 0x79, 0x98, 0x3a, 0x38, 0x36, 0xfb,
+0xbb, 0x66, 0x9e, 0x48, 0xff, 0x90, 0x90, 0xef, 0x3d, 0xd4, 0xb8, 0x9b, 0xb4, 0x87, 0x75, 0x3f,
+0x20, 0x9b, 0xce, 0x72, 0xcf, 0xa1, 0x55, 0xc1, 0x4d, 0x64, 0xa2, 0x19, 0x06, 0xa1, 0x07, 0x33,
+0x0c, 0x0b, 0x29, 0xe5, 0xf1, 0xea, 0xab, 0xa3, 0xec, 0xb5, 0x0a, 0x74, 0x90, 0xc7, 0x7d, 0x72,
+0xf2, 0xd7, 0x5c, 0x9f, 0x91, 0xef, 0x91, 0x8b, 0xb7, 0xdc, 0xed, 0x66, 0xa2, 0xcf, 0x8e, 0x66,
+0x3b, 0xbc, 0x9f, 0x3a, 0x02, 0xe0, 0x27, 0xdd, 0x16, 0x98, 0xc0, 0x95, 0xd4, 0x0a, 0xa4, 0xe4,
+0x81, 0x9a, 0x75, 0x94, 0x35, 0x9c, 0x90, 0x5f, 0x88, 0x37, 0x06, 0xad, 0x59, 0x95, 0x0a, 0xb0,
+0xd1, 0x67, 0xd3, 0x19, 0xca, 0x89, 0xe7, 0x32, 0x5a, 0x36, 0x1c, 0x3e, 0x82, 0xa8, 0x5a, 0x93,
+0xbe, 0xc6, 0xd0, 0x64, 0x91, 0xb6, 0xcf, 0xd9, 0xb6, 0x18, 0xcf, 0xdb, 0x7e, 0xd2, 0x65, 0xa3,
+0xa6, 0xc4, 0x8e, 0x17, 0x31, 0xc1, 0xfb, 0x7e, 0x76, 0xdb, 0xd3, 0x85, 0xe3, 0x58, 0xb2, 0x77,
+0x7a, 0x76, 0x3b, 0x6c, 0x2f, 0x50, 0x1c, 0xe7, 0xdb, 0xf6, 0x67, 0x79, 0x1f, 0xf5, 0x82, 0x95,
+0x9a, 0x07, 0xa7, 0x14, 0xaf, 0x8f, 0xdc, 0x28, 0x21, 0x67, 0x09, 0xd2, 0xd6, 0x4d, 0x5a, 0x1c,
+0x19, 0x1c, 0x8e, 0x77, 0x5c, 0xc3, 0x94, 0x24, 0x3d, 0x32, 0x6b, 0x4b, 0x7e, 0xd4, 0x78, 0x94,
+0x83, 0xbe, 0x37, 0x4d, 0xce, 0x5f, 0xc7, 0x1e, 0x4e, 0x3c, 0xe0, 0x89, 0x33, 0x95, 0x0b, 0x0f,
+0xa5, 0x32, 0xd6, 0x3c, 0x5a, 0x79, 0x2c, 0x19, 0x30, 0x82, 0x05, 0x5a, 0x30, 0x82, 0x03, 0x42,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x4f, 0xd2, 0x2b, 0x8f, 0xf5, 0x64, 0xc8, 0x33, 0x9e,
+0x4f, 0x34, 0x58, 0x66, 0x23, 0x70, 0x60, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x43, 0x4e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08,
+0x55, 0x6e, 0x69, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x0c, 0x1c, 0x55, 0x43, 0x41, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20,
+0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30,
+0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
+0x17, 0x0d, 0x33, 0x38, 0x31, 0x32, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30,
+0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4e, 0x31, 0x11,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x55, 0x6e, 0x69, 0x54, 0x72, 0x75, 0x73,
+0x74, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x55, 0x43, 0x41, 0x20,
+0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
+0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00,
+0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xa9, 0x09, 0x07, 0x28, 0x13, 0x02, 0xb0,
+0x99, 0xe0, 0x64, 0xaa, 0x1e, 0x43, 0x16, 0x7a, 0x73, 0xb1, 0x91, 0xa0, 0x75, 0x3e, 0xa8, 0xfa,
+0xe3, 0x38, 0x00, 0x7a, 0xec, 0x89, 0x6a, 0x20, 0x0f, 0x8b, 0xc5, 0xb0, 0x9b, 0x33, 0x03, 0x5a,
+0x86, 0xc6, 0x58, 0x86, 0xd5, 0xc1, 0x85, 0xbb, 0x4f, 0xc6, 0x9c, 0x40, 0x4d, 0xca, 0xbe, 0xee,
+0x69, 0x96, 0xb8, 0xad, 0x81, 0x30, 0x9a, 0x7c, 0x92, 0x05, 0xeb, 0x05, 0x2b, 0x9a, 0x48, 0xd0,
+0xb8, 0x76, 0x3e, 0x96, 0xc8, 0x20, 0xbb, 0xd2, 0xb0, 0xf1, 0x8f, 0xd8, 0xac, 0x45, 0x46, 0xff,
+0xaa, 0x67, 0x60, 0xb4, 0x77, 0x7e, 0x6a, 0x1f, 0x3c, 0x1a, 0x52, 0x7a, 0x04, 0x3d, 0x07, 0x3c,
+0x85, 0x0d, 0x84, 0xd0, 0x1f, 0x76, 0x0a, 0xf7, 0x6a, 0x14, 0xdf, 0x72, 0xe3, 0x34, 0x7c, 0x57,
+0x4e, 0x56, 0x01, 0x3e, 0x79, 0xf1, 0xaa, 0x29, 0x3b, 0x6c, 0xfa, 0xf8, 0x8f, 0x6d, 0x4d, 0xc8,
+0x35, 0xdf, 0xae, 0xeb, 0xdc, 0x24, 0xee, 0x79, 0x45, 0xa7, 0x85, 0xb6, 0x05, 0x88, 0xde, 0x88,
+0x5d, 0x25, 0x7c, 0x97, 0x64, 0x67, 0x09, 0xd9, 0xbf, 0x5a, 0x15, 0x05, 0x86, 0xf3, 0x09, 0x1e,
+0xec, 0x58, 0x32, 0x33, 0x11, 0xf3, 0x77, 0x64, 0xb0, 0x76, 0x1f, 0xe4, 0x10, 0x35, 0x17, 0x1b,
+0xf2, 0x0e, 0xb1, 0x6c, 0xa4, 0x2a, 0xa3, 0x73, 0xfc, 0x09, 0x1f, 0x1e, 0x32, 0x19, 0x53, 0x11,
+0xe7, 0xd9, 0xb3, 0x2c, 0x2e, 0x76, 0x2e, 0xa1, 0xa3, 0xde, 0x7e, 0x6a, 0x88, 0x09, 0xe8, 0xf2,
+0x07, 0x8a, 0xf8, 0xb2, 0xcd, 0x10, 0xe7, 0xe2, 0x73, 0x40, 0x93, 0xbb, 0x08, 0xd1, 0x3f, 0xe1,
+0xfc, 0x0b, 0x94, 0xb3, 0x25, 0xef, 0x7c, 0xa6, 0xd7, 0xd1, 0xaf, 0x9f, 0xff, 0x96, 0x9a, 0xf5,
+0x91, 0x7b, 0x98, 0x0b, 0x77, 0xd4, 0x7e, 0xe8, 0x07, 0xd2, 0x62, 0xb5, 0x95, 0x39, 0xe3, 0xf3,
+0xf1, 0x6d, 0x0f, 0x0e, 0x65, 0x84, 0x8a, 0x63, 0x54, 0xc5, 0x80, 0xb6, 0xe0, 0x9e, 0x4b, 0x7d,
+0x47, 0x26, 0xa7, 0x01, 0x08, 0x5d, 0xd1, 0x88, 0x9e, 0xd7, 0xc3, 0x32, 0x44, 0xfa, 0x82, 0x4a,
+0x0a, 0x68, 0x54, 0x7f, 0x38, 0x53, 0x03, 0xcc, 0xa4, 0x00, 0x33, 0x64, 0x51, 0x59, 0x0b, 0xa3,
+0x82, 0x91, 0x7a, 0x5e, 0xec, 0x16, 0xc2, 0xf3, 0x2a, 0xe6, 0x62, 0xda, 0x2a, 0xdb, 0x59, 0x62,
+0x10, 0x25, 0x4a, 0x2a, 0x81, 0x0b, 0x47, 0x07, 0x43, 0x06, 0x70, 0x87, 0xd2, 0xfa, 0x93, 0x11,
+0x29, 0x7a, 0x48, 0x4d, 0xeb, 0x94, 0xc7, 0x70, 0x4d, 0xaf, 0x67, 0xd5, 0x51, 0xb1, 0x80, 0x20,
+0x01, 0x01, 0xb4, 0x7a, 0x08, 0xa6, 0x90, 0x7f, 0x4e, 0xe0, 0xef, 0x07, 0x41, 0x87, 0xaf, 0x6a,
+0xa5, 0x5e, 0x8b, 0xfb, 0xcf, 0x50, 0xb2, 0x9a, 0x54, 0xaf, 0xc3, 0x89, 0xba, 0x58, 0x2d, 0xf5,
+0x30, 0x98, 0xb1, 0x36, 0x72, 0x39, 0x7e, 0x49, 0x04, 0xfd, 0x29, 0xa7, 0x4c, 0x79, 0xe4, 0x05,
+0x57, 0xdb, 0x94, 0xb9, 0x16, 0x53, 0x8d, 0x46, 0xb3, 0x1d, 0x95, 0x61, 0x57, 0x56, 0x7f, 0xaf,
+0xf0, 0x16, 0x5b, 0x61, 0x58, 0x6f, 0x36, 0x50, 0x11, 0x0b, 0xd8, 0xac, 0x2b, 0x95, 0x16, 0x1a,
+0x0e, 0x1f, 0x08, 0xcd, 0x36, 0x34, 0x65, 0x10, 0x62, 0x66, 0xd5, 0x80, 0x5f, 0x14, 0x20, 0x5f,
+0x2d, 0x0c, 0xa0, 0x78, 0x0a, 0x68, 0xd6, 0x2c, 0xd7, 0xe9, 0x6f, 0x2b, 0xd2, 0x4a, 0x05, 0x93,
+0xfc, 0x9e, 0x6f, 0x6b, 0x67, 0xff, 0x88, 0xf1, 0x4e, 0xa5, 0x69, 0x4a, 0x52, 0x37, 0x05, 0xea,
+0xc6, 0x16, 0x8d, 0xd2, 0xc4, 0x99, 0xd1, 0x82, 0x2b, 0x3b, 0xba, 0x35, 0x75, 0xf7, 0x51, 0x51,
+0x58, 0xf3, 0xc8, 0x07, 0xdd, 0xe4, 0xb4, 0x03, 0x7f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42,
+0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd9, 0x74, 0x3a,
+0xe4, 0x30, 0x3d, 0x0d, 0xf7, 0x12, 0xdc, 0x7e, 0x5a, 0x05, 0x9f, 0x1e, 0x34, 0x9a, 0xf7, 0xe1,
+0x14, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x86, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x36, 0x8d, 0x97, 0xcc, 0x42, 0x15, 0x64, 0x29, 0x37, 0x9b,
+0x26, 0x2c, 0xd6, 0xfb, 0xae, 0x15, 0x69, 0x2c, 0x6b, 0x1a, 0x1a, 0xf7, 0x5f, 0xb6, 0xf9, 0x07,
+0x4c, 0x59, 0xea, 0xf3, 0xc9, 0xc8, 0xb9, 0xae, 0xcc, 0xba, 0x2e, 0x7a, 0xdc, 0xc0, 0xf5, 0xb0,
+0x2d, 0xc0, 0x3b, 0xaf, 0x9f, 0x70, 0x05, 0x11, 0x6a, 0x9f, 0x25, 0x4f, 0x01, 0x29, 0x70, 0xe3,
+0xe5, 0x0c, 0xe1, 0xea, 0x5a, 0x7c, 0xdc, 0x49, 0xbb, 0xc1, 0x1e, 0x2a, 0x81, 0xf5, 0x16, 0x4b,
+0x72, 0x91, 0xc8, 0xa2, 0x31, 0xb9, 0xaa, 0xda, 0xfc, 0x9d, 0x1f, 0xf3, 0x5d, 0x40, 0x02, 0x13,
+0xfc, 0x4e, 0x1c, 0x06, 0xca, 0xb3, 0x14, 0x90, 0x54, 0x17, 0x19, 0x12, 0x1a, 0xf1, 0x1f, 0xd7,
+0x0c, 0x69, 0x5a, 0xf6, 0x71, 0x78, 0xf4, 0x94, 0x7d, 0x91, 0x0b, 0x8e, 0xec, 0x90, 0x54, 0x8e,
+0xbc, 0x6f, 0xa1, 0x4c, 0xab, 0xfc, 0x74, 0x64, 0xfd, 0x71, 0x9a, 0xf8, 0x41, 0x07, 0xa1, 0xcd,
+0x91, 0xe4, 0x3c, 0x9a, 0xe0, 0x9b, 0x32, 0x39, 0x73, 0xab, 0x2a, 0xd5, 0x69, 0xc8, 0x78, 0x91,
+0x26, 0x31, 0x7d, 0xe2, 0xc7, 0x30, 0xf1, 0xfc, 0x14, 0x78, 0x77, 0x12, 0x0e, 0x13, 0xf4, 0xdd,
+0x16, 0x94, 0xbf, 0x4b, 0x67, 0x7b, 0x70, 0x53, 0x85, 0xca, 0xb0, 0xbb, 0xf3, 0x38, 0x4d, 0x2c,
+0x90, 0x39, 0xc0, 0x0d, 0xc2, 0x5d, 0x6b, 0xe9, 0xe2, 0xe5, 0xd5, 0x88, 0x8d, 0xd6, 0x2c, 0xbf,
+0xab, 0x1b, 0xbe, 0xb5, 0x28, 0x87, 0x12, 0x17, 0x74, 0x6e, 0xfc, 0x7d, 0xfc, 0x8f, 0xd0, 0x87,
+0x26, 0xb0, 0x1b, 0xfb, 0xb9, 0x6c, 0xab, 0xe2, 0x9e, 0x3d, 0x15, 0xc1, 0x3b, 0x2e, 0x67, 0x02,
+0x58, 0x91, 0x9f, 0xef, 0xf8, 0x42, 0x1f, 0x2c, 0xb7, 0x68, 0xf5, 0x75, 0xad, 0xcf, 0xb5, 0xf6,
+0xff, 0x11, 0x7d, 0xc2, 0xf0, 0x24, 0xa5, 0xad, 0xd3, 0xfa, 0xa0, 0x3c, 0xa9, 0xfa, 0x5d, 0xdc,
+0xa5, 0xa0, 0xef, 0x44, 0xa4, 0xbe, 0xd6, 0xe8, 0xe5, 0xe4, 0x13, 0x96, 0x17, 0x7b, 0x06, 0x3e,
+0x32, 0xed, 0xc7, 0xb7, 0x42, 0xbc, 0x76, 0xa3, 0xd8, 0x65, 0x38, 0x2b, 0x38, 0x35, 0x51, 0x21,
+0x0e, 0x0e, 0x6f, 0x2e, 0x34, 0x13, 0x40, 0xe1, 0x2b, 0x67, 0x0c, 0x6d, 0x4a, 0x41, 0x30, 0x18,
+0x23, 0x5a, 0x32, 0x55, 0x99, 0xc9, 0x17, 0xe0, 0x3c, 0xde, 0xf6, 0xec, 0x79, 0xad, 0x2b, 0x58,
+0x19, 0xa2, 0xad, 0x2c, 0x22, 0x1a, 0x95, 0x8e, 0xbe, 0x96, 0x90, 0x5d, 0x42, 0x57, 0xc4, 0xf9,
+0x14, 0x03, 0x35, 0x2b, 0x1c, 0x2d, 0x51, 0x57, 0x08, 0xa7, 0x3a, 0xde, 0x3f, 0xe4, 0xc8, 0xb4,
+0x03, 0x73, 0xc2, 0xc1, 0x26, 0x80, 0xbb, 0x0b, 0x42, 0x1f, 0xad, 0x0d, 0xaf, 0x26, 0x72, 0xda,
+0xcc, 0xbe, 0xb3, 0xa3, 0x83, 0x58, 0x0d, 0x82, 0xc5, 0x1f, 0x46, 0x51, 0xe3, 0x9c, 0x18, 0xcc,
+0x8d, 0x9b, 0x8d, 0xec, 0x49, 0xeb, 0x75, 0x50, 0xd5, 0x8c, 0x28, 0x59, 0xca, 0x74, 0x34, 0xda,
+0x8c, 0x0b, 0x21, 0xab, 0x1e, 0xea, 0x1b, 0xe5, 0xc7, 0xfd, 0x15, 0x3e, 0xc0, 0x17, 0xaa, 0xfb,
+0x23, 0x6e, 0x26, 0x46, 0xcb, 0xfa, 0xf9, 0xb1, 0x72, 0x6b, 0x69, 0xcf, 0x22, 0x84, 0x0b, 0x62,
+0x0f, 0xac, 0xd9, 0x19, 0x00, 0x94, 0xa2, 0x76, 0x3c, 0xd4, 0x2d, 0x9a, 0xed, 0x04, 0x9e, 0x2d,
+0x06, 0x62, 0x10, 0x37, 0x52, 0x1c, 0x85, 0x72, 0x1b, 0x27, 0xe5, 0xcc, 0xc6, 0x31, 0xec, 0x37,
+0xec, 0x63, 0x59, 0x9b, 0x0b, 0x1d, 0x76, 0xcc, 0x7e, 0x32, 0x9a, 0x88, 0x95, 0x08, 0x36, 0x52,
+0xbb, 0xde, 0x76, 0x5f, 0x76, 0x49, 0x49, 0xad, 0x7f, 0xbd, 0x65, 0x20, 0xb2, 0xc9, 0xc1, 0x2b,
+0x76, 0x18, 0x76, 0x9f, 0x56, 0xb1, 0x30, 0x82, 0x05, 0x46, 0x30, 0x82, 0x03, 0x2e, 0xa0, 0x03,
+0x02, 0x01, 0x02, 0x02, 0x10, 0x5d, 0xdf, 0xb1, 0xda, 0x5a, 0xa3, 0xed, 0x5d, 0xbe, 0x5a, 0x65,
+0x20, 0x65, 0x03, 0x90, 0xef, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x0b, 0x05, 0x00, 0x30, 0x3d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x43, 0x4e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x55, 0x6e,
+0x69, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+0x12, 0x55, 0x43, 0x41, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x47, 0x32, 0x20, 0x52,
+0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x33, 0x31, 0x31, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x5a, 0x30, 0x3d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x43, 0x4e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x55, 0x6e, 0x69,
+0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x12,
+0x55, 0x43, 0x41, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x47, 0x32, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82,
+0x02, 0x01, 0x00, 0xc5, 0xe6, 0x2b, 0x6f, 0x7c, 0xef, 0x26, 0x05, 0x27, 0xa3, 0x81, 0x24, 0xda,
+0x6f, 0xcb, 0x01, 0xf9, 0x99, 0x9a, 0xa9, 0x32, 0xc2, 0x22, 0x87, 0x61, 0x41, 0x91, 0x3b, 0xcb,
+0xc3, 0x68, 0x1b, 0x06, 0xc5, 0x4c, 0xa9, 0x2b, 0xc1, 0x67, 0x17, 0x22, 0x1d, 0x2b, 0xed, 0xf9,
+0x29, 0x89, 0x93, 0xa2, 0x78, 0xbd, 0x92, 0x6b, 0xa0, 0xa3, 0x0d, 0xa2, 0x7e, 0xca, 0x93, 0xb3,
+0xa6, 0xd1, 0x8c, 0x35, 0xd5, 0x75, 0xf9, 0x17, 0xf6, 0xcf, 0x45, 0xc5, 0xe5, 0x7a, 0xec, 0x77,
+0x93, 0xa0, 0x8f, 0x23, 0xae, 0x0e, 0x1a, 0x03, 0x7f, 0xbe, 0xd4, 0xd0, 0xed, 0x2e, 0x7b, 0xab,
+0x46, 0x23, 0x5b, 0xff, 0x2c, 0xe6, 0x54, 0x7a, 0x94, 0xc0, 0x2a, 0x15, 0xf0, 0xc9, 0x8d, 0xb0,
+0x7a, 0x3b, 0x24, 0xe1, 0xd7, 0x68, 0xe2, 0x31, 0x3c, 0x06, 0x33, 0x46, 0xb6, 0x54, 0x11, 0xa6,
+0xa5, 0x2f, 0x22, 0x54, 0x2a, 0x58, 0x0d, 0x01, 0x02, 0xf1, 0xfa, 0x15, 0x51, 0x67, 0x6c, 0xc0,
+0xfa, 0xd7, 0xb6, 0x1b, 0x7f, 0xd1, 0x56, 0x88, 0x2f, 0x1a, 0x3a, 0x8d, 0x3b, 0xbb, 0x82, 0x11,
+0xe0, 0x47, 0x00, 0xd0, 0x52, 0x87, 0xab, 0xfb, 0x86, 0x7e, 0x0f, 0x24, 0x6b, 0x40, 0x9d, 0x34,
+0x67, 0xbc, 0x8d, 0xc7, 0x2d, 0x86, 0x6f, 0x79, 0x3e, 0x8e, 0xa9, 0x3c, 0x17, 0x4b, 0x7f, 0xb0,
+0x99, 0xe3, 0xb0, 0x71, 0x60, 0xdc, 0x0b, 0xf5, 0x64, 0xc3, 0xce, 0x43, 0xbc, 0x6d, 0x71, 0xb9,
+0xd2, 0xde, 0x27, 0x5b, 0x8a, 0xe8, 0xd8, 0xc6, 0xae, 0xe1, 0x59, 0x7d, 0xcf, 0x28, 0x2d, 0x35,
+0xb8, 0x95, 0x56, 0x1a, 0xf1, 0xb2, 0x58, 0x4b, 0xb7, 0x12, 0x37, 0xc8, 0x7c, 0xb3, 0xed, 0x4b,
+0x80, 0xe1, 0x8d, 0xfa, 0x32, 0x23, 0xb6, 0x6f, 0xb7, 0x48, 0x95, 0x08, 0xb1, 0x44, 0x4e, 0x85,
+0x8c, 0x3a, 0x02, 0x54, 0x20, 0x2f, 0xdf, 0xbf, 0x57, 0x4f, 0x3b, 0x3a, 0x90, 0x21, 0xd7, 0xc1,
+0x26, 0x35, 0x54, 0x20, 0xec, 0xc7, 0x3f, 0x47, 0xec, 0xef, 0x5a, 0xbf, 0x4b, 0x7a, 0xc1, 0xad,
+0x3b, 0x17, 0x50, 0x5c, 0x62, 0xd8, 0x0f, 0x4b, 0x4a, 0xdc, 0x2b, 0xfa, 0x6e, 0xbc, 0x73, 0x92,
+0xcd, 0xec, 0xc7, 0x50, 0xe8, 0x41, 0x96, 0xd7, 0xa9, 0x7e, 0x6d, 0xd8, 0xe9, 0x1d, 0x8f, 0x8a,
+0xb5, 0xb9, 0x58, 0x92, 0xba, 0x4a, 0x92, 0x2b, 0x0c, 0x56, 0xfd, 0x80, 0xeb, 0x08, 0xf0, 0x5e,
+0x29, 0x6e, 0x1b, 0x1c, 0x0c, 0xaf, 0x8f, 0x93, 0x89, 0xad, 0xdb, 0xbd, 0xa3, 0x9e, 0x21, 0xca,
+0x89, 0x19, 0xec, 0xdf, 0xb5, 0xc3, 0x1a, 0xeb, 0x16, 0xfe, 0x78, 0x36, 0x4c, 0xd6, 0x6e, 0xd0,
+0x3e, 0x17, 0x1c, 0x90, 0x17, 0x6b, 0x26, 0xba, 0xfb, 0x7a, 0x2f, 0xbf, 0x11, 0x1c, 0x18, 0x0e,
+0x2d, 0x73, 0x03, 0x8f, 0xa0, 0xe5, 0x35, 0xa0, 0x5a, 0xe2, 0x4c, 0x75, 0x1d, 0x71, 0xe1, 0x39,
+0x38, 0x53, 0x78, 0x40, 0xcc, 0x83, 0x93, 0xd7, 0x0a, 0x9e, 0x9d, 0x5b, 0x8f, 0x8a, 0xe4, 0xe5,
+0xe0, 0x48, 0xe4, 0x48, 0xb2, 0x47, 0xcd, 0x4e, 0x2a, 0x75, 0x2a, 0x7b, 0xf2, 0x22, 0xf6, 0xc9,
+0xbe, 0x09, 0x91, 0x96, 0x57, 0x7a, 0x88, 0x88, 0xac, 0xee, 0x70, 0xac, 0xf9, 0xdc, 0x29, 0xe3,
+0x0c, 0x1c, 0x3b, 0x12, 0x4e, 0x44, 0xd6, 0xa7, 0x4e, 0xb0, 0x26, 0xc8, 0xf3, 0xd9, 0x1a, 0x97,
+0x91, 0x68, 0xea, 0xef, 0x8d, 0x46, 0x06, 0xd2, 0x56, 0x45, 0x58, 0x9a, 0x3c, 0x0c, 0x0f, 0x83,
+0xb8, 0x05, 0x25, 0xc3, 0x39, 0xcf, 0x3b, 0xa4, 0x34, 0x89, 0xb7, 0x79, 0x12, 0x2f, 0x47, 0xc5,
+0xe7, 0xa9, 0x97, 0x69, 0xfc, 0xa6, 0x77, 0x67, 0xb5, 0xdf, 0x7b, 0xf1, 0x7a, 0x65, 0x15, 0xe4,
+0x61, 0x56, 0x65, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03,
+0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03,
+0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06,
+0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x81, 0xc4, 0x8c, 0xcc, 0xf5, 0xe4, 0x30, 0xff,
+0xa5, 0x0c, 0x08, 0x5f, 0x8c, 0x15, 0x67, 0x21, 0x74, 0x01, 0xdf, 0xdf, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00,
+0x13, 0x65, 0x22, 0xf5, 0x8e, 0x2b, 0xad, 0x44, 0xe4, 0xcb, 0xff, 0xb9, 0x68, 0xe6, 0xc3, 0x80,
+0x48, 0x3d, 0x04, 0x7b, 0xfa, 0x23, 0x2f, 0x7a, 0xed, 0x36, 0xda, 0xb2, 0xce, 0x6d, 0xf6, 0xe6,
+0x9e, 0xe5, 0x5f, 0x58, 0x8f, 0xcb, 0x37, 0x32, 0xa1, 0xc8, 0x65, 0xb6, 0xae, 0x38, 0x3d, 0x35,
+0x1b, 0x3e, 0xbc, 0x3b, 0xb6, 0x04, 0xd0, 0xbc, 0xf9, 0x49, 0xf5, 0x9b, 0xf7, 0x85, 0xc5, 0x36,
+0xb6, 0xcb, 0xbc, 0xf8, 0xc8, 0x39, 0xd5, 0xe4, 0x5f, 0x07, 0xbd, 0x15, 0x54, 0x97, 0x74, 0xca,
+0xca, 0xed, 0x4f, 0xba, 0xba, 0x64, 0x76, 0x9f, 0x81, 0xb8, 0x84, 0x45, 0x49, 0x4c, 0x8d, 0x6f,
+0xa2, 0xeb, 0xb1, 0xcc, 0xd1, 0xc3, 0x94, 0xda, 0x44, 0xc2, 0xe6, 0xe2, 0xea, 0x18, 0xe8, 0xa2,
+0x1f, 0x27, 0x05, 0xba, 0xd7, 0xe5, 0xd6, 0xa9, 0xcd, 0xdd, 0xef, 0x76, 0x98, 0x8d, 0x00, 0x0e,
+0xcd, 0x1b, 0xfa, 0x03, 0xb7, 0x8e, 0x80, 0x58, 0x0e, 0x27, 0x3f, 0x52, 0xfb, 0x94, 0xa2, 0xca,
+0x5e, 0x65, 0xc9, 0xd6, 0x84, 0xda, 0xb9, 0x35, 0x71, 0xf3, 0x26, 0xc0, 0x4f, 0x77, 0xe6, 0x81,
+0x27, 0xd2, 0x77, 0x3b, 0x9a, 0x14, 0x6f, 0x79, 0xf4, 0xf6, 0xd0, 0xe1, 0xd3, 0x94, 0xba, 0xd0,
+0x57, 0x51, 0xbd, 0x27, 0x05, 0x0d, 0xc1, 0xfd, 0xc8, 0x12, 0x30, 0xee, 0x6f, 0x8d, 0x11, 0x2b,
+0x08, 0x9d, 0xd4, 0xd4, 0xbf, 0x80, 0x45, 0x14, 0x9a, 0x88, 0x44, 0xda, 0x30, 0xea, 0xb4, 0xa7,
+0xe3, 0xee, 0xef, 0x5b, 0x82, 0xd5, 0x3e, 0xd6, 0xad, 0x78, 0x92, 0xdb, 0x5c, 0x3c, 0xf3, 0xd8,
+0xad, 0xfa, 0xb8, 0x6b, 0x7f, 0xc4, 0x36, 0x28, 0xb6, 0x02, 0x15, 0x8a, 0x54, 0x2c, 0x9c, 0xb0,
+0x17, 0x73, 0x8e, 0xd0, 0x37, 0xa3, 0x14, 0x3c, 0x98, 0x95, 0x00, 0x0c, 0x29, 0x05, 0x5b, 0x9e,
+0x49, 0x49, 0xb1, 0x5f, 0xc7, 0xe3, 0xcb, 0xcf, 0x27, 0x65, 0x8e, 0x35, 0x17, 0xb7, 0x57, 0xc8,
+0x30, 0xd9, 0x41, 0x5b, 0xb9, 0x14, 0xb6, 0xe8, 0xc2, 0x0f, 0x94, 0x31, 0xa7, 0x94, 0x98, 0xcc,
+0x6a, 0xeb, 0xb5, 0xe1, 0x27, 0xf5, 0x10, 0xa8, 0x01, 0xe8, 0x8e, 0x12, 0x62, 0xe8, 0x88, 0xcc,
+0xb5, 0x7f, 0x46, 0x97, 0xc0, 0x9b, 0x10, 0x66, 0x38, 0x1a, 0x36, 0x46, 0x5f, 0x22, 0x68, 0x3d,
+0xdf, 0xc9, 0xc6, 0x13, 0x27, 0xab, 0x53, 0x06, 0xac, 0xa2, 0x3c, 0x86, 0x06, 0x65, 0x6f, 0xb1,
+0x7e, 0xb1, 0x29, 0x44, 0x9a, 0xa3, 0xba, 0x49, 0x69, 0x28, 0x69, 0x8f, 0xd7, 0xe5, 0x5f, 0xad,
+0x04, 0x86, 0x64, 0x6f, 0x1a, 0xa0, 0x0c, 0xc5, 0x08, 0x62, 0xce, 0x80, 0xa3, 0xd0, 0xf3, 0xec,
+0x68, 0xde, 0xbe, 0x33, 0xc7, 0x17, 0x5b, 0x7f, 0x80, 0xc4, 0x4c, 0x4c, 0xb1, 0xa6, 0x84, 0x8a,
+0xc3, 0x3b, 0xb8, 0x09, 0xcd, 0x14, 0x81, 0xba, 0x18, 0xe3, 0x54, 0x57, 0x36, 0xfe, 0xdb, 0x2f,
+0x7c, 0x47, 0xa1, 0x3a, 0x33, 0xc8, 0xf9, 0x58, 0x3b, 0x44, 0x4f, 0xb1, 0xca, 0x02, 0x89, 0x04,
+0x96, 0x28, 0x68, 0xc5, 0x4b, 0xb8, 0x26, 0x89, 0xbb, 0xd6, 0x33, 0x2f, 0x50, 0xd5, 0xfe, 0x9a,
+0x89, 0xba, 0x18, 0x32, 0x92, 0x54, 0xc6, 0x5b, 0xe0, 0x9d, 0xf9, 0x5e, 0xe5, 0x0d, 0x22, 0x9b,
+0xf6, 0xda, 0xe2, 0xc8, 0x21, 0xb2, 0x62, 0x21, 0xaa, 0x86, 0x40, 0xb2, 0x2e, 0x64, 0xd3, 0x5f,
+0xc8, 0xe3, 0x7e, 0x11, 0x67, 0x45, 0x1f, 0x05, 0xfe, 0xe3, 0xa2, 0xef, 0xb3, 0xa8, 0xb3, 0xf3,
+0x7d, 0x8f, 0xf8, 0x0c, 0x1f, 0x22, 0x1f, 0x2d, 0x70, 0xb4, 0xb8, 0x01, 0x34, 0x76, 0x30, 0x00,
+0xe5, 0x23, 0x78, 0xa7, 0x56, 0xd7, 0x50, 0x1f, 0x8a, 0xfb, 0x06, 0xf5, 0xc2, 0x19, 0xf0, 0xd0,
+0x30, 0x82, 0x02, 0x94, 0x30, 0x82, 0x02, 0x1a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x2c,
+0x29, 0x9c, 0x5b, 0x16, 0xed, 0x05, 0x95, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+0x04, 0x03, 0x02, 0x30, 0x7f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x65, 0x78,
+0x61, 0x73, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x48, 0x6f, 0x75,
+0x73, 0x74, 0x6f, 0x6e, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x53,
+0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x34,
+0x30, 0x32, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2b, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d,
+0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x20, 0x45, 0x43, 0x43, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x32, 0x31, 0x32, 0x31, 0x38,
+0x31, 0x35, 0x32, 0x33, 0x5a, 0x17, 0x0d, 0x34, 0x31, 0x30, 0x32, 0x31, 0x32, 0x31, 0x38, 0x31,
+0x35, 0x32, 0x33, 0x5a, 0x30, 0x7f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x65,
+0x78, 0x61, 0x73, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x48, 0x6f,
+0x75, 0x73, 0x74, 0x6f, 0x6e, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f,
+0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31,
+0x34, 0x30, 0x32, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2b, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f,
+0x6d, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+0x79, 0x20, 0x45, 0x43, 0x43, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xaa, 0x12, 0x47,
+0x90, 0x98, 0x1b, 0xfb, 0xef, 0xc3, 0x40, 0x07, 0x83, 0x20, 0x4e, 0xf1, 0x30, 0x82, 0xa2, 0x06,
+0xd1, 0xf2, 0x92, 0x86, 0x61, 0xf2, 0xf6, 0x21, 0x68, 0xca, 0x00, 0xc4, 0xc7, 0xea, 0x43, 0x00,
+0x54, 0x86, 0xdc, 0xfd, 0x1f, 0xdf, 0x00, 0xb8, 0x41, 0x62, 0x5c, 0xdc, 0x70, 0x16, 0x32, 0xde,
+0x1f, 0x99, 0xd4, 0xcc, 0xc5, 0x07, 0xc8, 0x08, 0x1f, 0x61, 0x16, 0x07, 0x51, 0x3d, 0x7d, 0x5c,
+0x07, 0x53, 0xe3, 0x35, 0x38, 0x8c, 0xdf, 0xcd, 0x9f, 0xd9, 0x2e, 0x0d, 0x4a, 0xb6, 0x19, 0x2e,
+0x5a, 0x70, 0x5a, 0x06, 0xed, 0xbe, 0xf0, 0xa1, 0xb0, 0xca, 0xd0, 0x09, 0x29, 0xa3, 0x63, 0x30,
+0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x5b, 0xca, 0x5e, 0xe5,
+0xde, 0xd2, 0x81, 0xaa, 0xcd, 0xa8, 0x2d, 0x64, 0x51, 0xb6, 0xd9, 0x72, 0x9b, 0x97, 0xe6, 0x4f,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x5b, 0xca,
+0x5e, 0xe5, 0xde, 0xd2, 0x81, 0xaa, 0xcd, 0xa8, 0x2d, 0x64, 0x51, 0xb6, 0xd9, 0x72, 0x9b, 0x97,
+0xe6, 0x4f, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x86, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x68,
+0x00, 0x30, 0x65, 0x02, 0x31, 0x00, 0x8a, 0xe6, 0x40, 0x89, 0x37, 0xeb, 0xe9, 0xd5, 0x13, 0xd9,
+0xca, 0xd4, 0x6b, 0x24, 0xf3, 0xb0, 0x3d, 0x87, 0x46, 0x58, 0x1a, 0xec, 0xb1, 0xdf, 0x6f, 0xfb,
+0x56, 0xba, 0x70, 0x6b, 0xc7, 0x38, 0xcc, 0xe8, 0xb1, 0x8c, 0x4f, 0x0f, 0xf7, 0xf1, 0x67, 0x76,
+0x0e, 0x83, 0xd0, 0x1e, 0x51, 0x8f, 0x02, 0x30, 0x3d, 0xf6, 0x23, 0x28, 0x26, 0x4c, 0xc6, 0x60,
+0x87, 0x93, 0x26, 0x9b, 0xb2, 0x35, 0x1e, 0xba, 0xd6, 0xf7, 0x3c, 0xd1, 0x1c, 0xce, 0xfa, 0x25,
+0x3c, 0xa6, 0x1a, 0x81, 0x15, 0x5b, 0xf3, 0x12, 0x0f, 0x6c, 0xee, 0x65, 0x8a, 0xc9, 0x87, 0xa8,
+0xf9, 0x07, 0xe0, 0x62, 0x9a, 0x8c, 0x5c, 0x4a, 0x30, 0x82, 0x02, 0x8d, 0x30, 0x82, 0x02, 0x14,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x75, 0xe6, 0xdf, 0xcb, 0xc1, 0x68, 0x5b, 0xa8, 0x30,
+0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x7c, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03,
+0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x65, 0x78, 0x61, 0x73, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
+0x55, 0x04, 0x07, 0x0c, 0x07, 0x48, 0x6f, 0x75, 0x73, 0x74, 0x6f, 0x6e, 0x31, 0x18, 0x30, 0x16,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f,
+0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+0x28, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65,
+0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, 0x43, 0x43, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30,
+0x32, 0x31, 0x32, 0x31, 0x38, 0x31, 0x34, 0x30, 0x33, 0x5a, 0x17, 0x0d, 0x34, 0x31, 0x30, 0x32,
+0x31, 0x32, 0x31, 0x38, 0x31, 0x34, 0x30, 0x33, 0x5a, 0x30, 0x7c, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04,
+0x08, 0x0c, 0x05, 0x54, 0x65, 0x78, 0x61, 0x73, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
+0x07, 0x0c, 0x07, 0x48, 0x6f, 0x75, 0x73, 0x74, 0x6f, 0x6e, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61,
+0x74, 0x69, 0x6f, 0x6e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x28, 0x53,
+0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+0x69, 0x74, 0x79, 0x20, 0x45, 0x43, 0x43, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48,
+0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x45,
+0x6e, 0xa9, 0x50, 0xc4, 0xa6, 0x23, 0x36, 0x9e, 0x5f, 0x28, 0x8d, 0x17, 0xcb, 0x96, 0x22, 0x64,
+0x3f, 0xdc, 0x7a, 0x8e, 0x1d, 0xcc, 0x08, 0xb3, 0xa2, 0x71, 0x24, 0xba, 0x8e, 0x49, 0xb9, 0x04,
+0x1b, 0x47, 0x96, 0x58, 0xab, 0x2d, 0x95, 0xc8, 0xed, 0x9e, 0x08, 0x35, 0xc8, 0x27, 0xeb, 0x89,
+0x8c, 0x53, 0x58, 0xeb, 0x62, 0x8a, 0xfe, 0xf0, 0x5b, 0x0f, 0x6b, 0x31, 0x52, 0x63, 0x41, 0x3b,
+0x89, 0xcd, 0xec, 0xec, 0xb6, 0x8d, 0x19, 0xd3, 0x34, 0x07, 0xdc, 0xbb, 0xc6, 0x06, 0x7f, 0xc2,
+0x45, 0x95, 0xec, 0xcb, 0x7f, 0xa8, 0x23, 0xe0, 0x09, 0xe9, 0x81, 0xfa, 0xf3, 0x47, 0xd3, 0xa3,
+0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x82, 0xd1,
+0x85, 0x73, 0x30, 0xe7, 0x35, 0x04, 0xd3, 0x8e, 0x02, 0x92, 0xfb, 0xe5, 0xa4, 0xd1, 0xc4, 0x21,
+0xe8, 0xcd, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+0x01, 0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+0x82, 0xd1, 0x85, 0x73, 0x30, 0xe7, 0x35, 0x04, 0xd3, 0x8e, 0x02, 0x92, 0xfb, 0xe5, 0xa4, 0xd1,
+0xc4, 0x21, 0xe8, 0xcd, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x86, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+0x03, 0x67, 0x00, 0x30, 0x64, 0x02, 0x30, 0x6f, 0xe7, 0xeb, 0x59, 0x11, 0xa4, 0x60, 0xcf, 0x61,
+0xb0, 0x96, 0x7b, 0xed, 0x05, 0xf9, 0x2f, 0x13, 0x91, 0xdc, 0xed, 0xe5, 0xfc, 0x50, 0x6b, 0x11,
+0x46, 0x46, 0xb3, 0x1c, 0x21, 0x00, 0x62, 0xbb, 0xbe, 0xc3, 0xe7, 0xe8, 0xcd, 0x07, 0x99, 0xf9,
+0x0d, 0x0b, 0x5d, 0x72, 0x3e, 0xc4, 0xaa, 0x02, 0x30, 0x1f, 0xbc, 0xba, 0x0b, 0xe2, 0x30, 0x24,
+0xfb, 0x7c, 0x6d, 0x80, 0x55, 0x0a, 0x99, 0x3e, 0x80, 0x0d, 0x33, 0xe5, 0x66, 0xa3, 0xb3, 0xa3,
+0xbb, 0xa5, 0xd5, 0x8b, 0x8f, 0x09, 0x2c, 0xa6, 0x5d, 0x7e, 0xe2, 0xf0, 0x07, 0x08, 0x68, 0x6d,
+0xd2, 0x7c, 0x69, 0x6e, 0x5f, 0xdf, 0xe5, 0x6a, 0x65, 0x30, 0x82, 0x05, 0xdd, 0x30, 0x82, 0x03,
+0xc5, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x7b, 0x2c, 0x9b, 0xd3, 0x16, 0x80, 0x32, 0x99,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+0x7c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e,
+0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x65, 0x78, 0x61, 0x73, 0x31, 0x10,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x48, 0x6f, 0x75, 0x73, 0x74, 0x6f, 0x6e,
+0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x53, 0x53, 0x4c, 0x20, 0x43,
+0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x0c, 0x28, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x52, 0x6f, 0x6f,
+0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x53, 0x41, 0x30, 0x1e, 0x17,
+0x0d, 0x31, 0x36, 0x30, 0x32, 0x31, 0x32, 0x31, 0x37, 0x33, 0x39, 0x33, 0x39, 0x5a, 0x17, 0x0d,
+0x34, 0x31, 0x30, 0x32, 0x31, 0x32, 0x31, 0x37, 0x33, 0x39, 0x33, 0x39, 0x5a, 0x30, 0x7c, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c,
+0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x65, 0x78, 0x61, 0x73, 0x31, 0x10, 0x30, 0x0e,
+0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x48, 0x6f, 0x75, 0x73, 0x74, 0x6f, 0x6e, 0x31, 0x18,
+0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x6f, 0x72,
+0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x0c, 0x28, 0x53, 0x53, 0x4c, 0x2e, 0x63, 0x6f, 0x6d, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x53, 0x41, 0x30, 0x82, 0x02, 0x22, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
+0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xf9, 0x0f, 0xdd, 0xa3,
+0x2b, 0x7d, 0xcb, 0xd0, 0x2a, 0xfe, 0xec, 0x67, 0x85, 0xa6, 0xe7, 0x2e, 0x1b, 0xba, 0x77, 0xe1,
+0xe3, 0xf5, 0xaf, 0xa4, 0xec, 0xfa, 0x4a, 0x5d, 0x91, 0xc4, 0x57, 0x47, 0x6b, 0x18, 0x77, 0x6b,
+0x76, 0xf2, 0xfd, 0x93, 0xe4, 0x3d, 0x0f, 0xc2, 0x16, 0x9e, 0x0b, 0x66, 0xc3, 0x56, 0x94, 0x9e,
+0x17, 0x83, 0x85, 0xce, 0x56, 0xef, 0xf2, 0x16, 0xfd, 0x00, 0x62, 0xf5, 0x22, 0x09, 0x54, 0xe8,
+0x65, 0x17, 0x4e, 0x41, 0xb9, 0xe0, 0x4f, 0x46, 0x97, 0xaa, 0x1b, 0xc8, 0xb8, 0x6e, 0x62, 0x5e,
+0x69, 0xb1, 0x5f, 0xdb, 0x2a, 0x02, 0x7e, 0xfc, 0x6c, 0xca, 0xf3, 0x41, 0xd8, 0xed, 0xd0, 0xe8,
+0xfc, 0x3f, 0x61, 0x48, 0xed, 0xb0, 0x03, 0x14, 0x1d, 0x10, 0x0e, 0x4b, 0x19, 0xe0, 0xbb, 0x4e,
+0xec, 0x86, 0x65, 0xff, 0x36, 0xf3, 0x5e, 0x67, 0x02, 0x0b, 0x9d, 0x86, 0x55, 0x61, 0xfd, 0x7a,
+0x38, 0xed, 0xfe, 0xe2, 0x19, 0x00, 0xb7, 0x6f, 0xa1, 0x50, 0x62, 0x75, 0x74, 0x3c, 0xa0, 0xfa,
+0xc8, 0x25, 0x92, 0xb4, 0x6e, 0x7a, 0x22, 0xc7, 0xf8, 0x1e, 0xa1, 0xe3, 0xb2, 0xdd, 0x91, 0x31,
+0xab, 0x2b, 0x1d, 0x04, 0xff, 0xa5, 0x4a, 0x04, 0x37, 0xe9, 0x85, 0xa4, 0x33, 0x2b, 0xfd, 0xe2,
+0xd6, 0x55, 0x34, 0x7c, 0x19, 0xa4, 0x4a, 0x68, 0xc7, 0xb2, 0xa8, 0xd3, 0xb7, 0xca, 0xa1, 0x93,
+0x88, 0xeb, 0xc1, 0x97, 0xbc, 0x8c, 0xf9, 0x1d, 0xd9, 0x22, 0x84, 0x24, 0x74, 0xc7, 0x04, 0x3d,
+0x6a, 0xa9, 0x29, 0x93, 0xcc, 0xeb, 0xb8, 0x5b, 0xe1, 0xfe, 0x5f, 0x25, 0xaa, 0x34, 0x58, 0xc8,
+0xc1, 0x23, 0x54, 0x9d, 0x1b, 0x98, 0x11, 0xc3, 0x38, 0x9c, 0x7e, 0x3d, 0x86, 0x6c, 0xa5, 0x0f,
+0x40, 0x86, 0x7c, 0x02, 0xf4, 0x5c, 0x02, 0x4f, 0x28, 0xcb, 0xae, 0x71, 0x9f, 0x0f, 0x3a, 0xc8,
+0x33, 0xfe, 0x11, 0x25, 0x35, 0xea, 0xfc, 0xba, 0xc5, 0x60, 0x3d, 0xd9, 0x7c, 0x18, 0xd5, 0xb2,
+0xa9, 0xd3, 0x75, 0x78, 0x03, 0x72, 0x22, 0xca, 0x3a, 0xc3, 0x1f, 0xef, 0x2c, 0xe5, 0x2e, 0xa9,
+0xfa, 0x9e, 0x2c, 0xb6, 0x51, 0x46, 0xfd, 0xaf, 0x03, 0xd6, 0xea, 0x60, 0x68, 0xea, 0x85, 0x16,
+0x36, 0x6b, 0x85, 0xe9, 0x1e, 0xc0, 0xb3, 0xdd, 0xc4, 0x24, 0xdc, 0x80, 0x2a, 0x81, 0x41, 0x6d,
+0x94, 0x3e, 0xc8, 0xe0, 0xc9, 0x81, 0x41, 0x00, 0x9e, 0x5e, 0xbf, 0x7f, 0xc5, 0x08, 0x98, 0xa2,
+0x18, 0x2c, 0x42, 0x40, 0xb3, 0xf9, 0x6f, 0x38, 0x27, 0x4b, 0x4e, 0x80, 0xf4, 0x3d, 0x81, 0x47,
+0xe0, 0x88, 0x7c, 0xea, 0x1c, 0xce, 0xb5, 0x75, 0x5c, 0x51, 0x2e, 0x1c, 0x2b, 0x7f, 0x1a, 0x72,
+0x28, 0xe7, 0x00, 0xb5, 0xd1, 0x74, 0xc6, 0xd7, 0xe4, 0x9f, 0xad, 0x07, 0x93, 0xb6, 0x53, 0x35,
+0x35, 0xfc, 0x37, 0xe4, 0xc3, 0xf6, 0x5d, 0x16, 0xbe, 0x21, 0x73, 0xde, 0x92, 0x0a, 0xf8, 0xa0,
+0x63, 0x6a, 0xbc, 0x96, 0x92, 0x6a, 0x3e, 0xf8, 0xbc, 0x65, 0x55, 0x9b, 0xde, 0xf5, 0x0d, 0x89,
+0x26, 0x04, 0xfc, 0x25, 0x1a, 0xa6, 0x25, 0x69, 0xcb, 0xc2, 0x6d, 0xca, 0x7c, 0xe2, 0x59, 0x5f,
+0x97, 0xac, 0xeb, 0xef, 0x2e, 0xc8, 0xbc, 0xd7, 0x1b, 0x59, 0x3c, 0x2b, 0xcc, 0xf2, 0x19, 0xc8,
+0x93, 0x6b, 0x27, 0x63, 0x19, 0xcf, 0xfc, 0xe9, 0x26, 0xf8, 0xca, 0x71, 0x9b, 0x7f, 0x93, 0xfe,
+0x34, 0x67, 0x84, 0x4e, 0x99, 0xeb, 0xfc, 0xb3, 0x78, 0x09, 0x33, 0x70, 0xba, 0x66, 0xa6, 0x76,
+0xed, 0x1b, 0x73, 0xeb, 0x1a, 0xa5, 0x0d, 0xc4, 0x22, 0x13, 0x20, 0x94, 0x56, 0x0a, 0x4e, 0x2c,
+0x6c, 0x4e, 0xb1, 0xfd, 0xcf, 0x9c, 0x09, 0xba, 0xa2, 0x33, 0xed, 0x87, 0x02, 0x03, 0x01, 0x00,
+0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+0xdd, 0x04, 0x09, 0x07, 0xa2, 0xf5, 0x7a, 0x7d, 0x52, 0x53, 0x12, 0x92, 0x95, 0xee, 0x38, 0x80,
+0x25, 0x0d, 0xa6, 0x59, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05,
+0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+0x80, 0x14, 0xdd, 0x04, 0x09, 0x07, 0xa2, 0xf5, 0x7a, 0x7d, 0x52, 0x53, 0x12, 0x92, 0x95, 0xee,
+0x38, 0x80, 0x25, 0x0d, 0xa6, 0x59, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x20, 0x18, 0x11, 0x94, 0x29, 0xfb,
+0x26, 0x9d, 0x1c, 0x1e, 0x1e, 0x70, 0x61, 0xf1, 0x95, 0x72, 0x93, 0x71, 0x24, 0xad, 0x68, 0x93,
+0x58, 0x8e, 0x32, 0xaf, 0x1b, 0xb3, 0x70, 0x03, 0xfc, 0x25, 0x2b, 0x74, 0x85, 0x90, 0x3d, 0x78,
+0x6a, 0xf4, 0xb9, 0x8b, 0xa5, 0x97, 0x3b, 0xb5, 0x18, 0x91, 0xbb, 0x1e, 0xa7, 0xf9, 0x40, 0x5b,
+0x91, 0xf9, 0x55, 0x99, 0xaf, 0x1e, 0x11, 0xd0, 0x5c, 0x1d, 0xa7, 0x66, 0xe3, 0xb1, 0x94, 0x07,
+0x0c, 0x32, 0x39, 0xa6, 0xea, 0x1b, 0xb0, 0x79, 0xd8, 0x1d, 0x9c, 0x70, 0x44, 0xe3, 0x8a, 0xdd,
+0xc4, 0xf9, 0x95, 0x1f, 0x8a, 0x38, 0x43, 0x3f, 0x01, 0x85, 0xa5, 0x47, 0xa7, 0x3d, 0x46, 0xb2,
+0xbc, 0xe5, 0x22, 0x68, 0xf7, 0x7b, 0x9c, 0xd8, 0x2c, 0x3e, 0x0a, 0x21, 0xc8, 0x2d, 0x33, 0xac,
+0xbf, 0xc5, 0x81, 0x99, 0x31, 0x74, 0xc1, 0x75, 0x71, 0xc5, 0xbe, 0xb1, 0xf0, 0x23, 0x45, 0xf4,
+0x9d, 0x6b, 0xfc, 0x19, 0x63, 0x9d, 0xa3, 0xbc, 0x04, 0xc6, 0x18, 0x0b, 0x25, 0xbb, 0x53, 0x89,
+0x0f, 0xb3, 0x80, 0x50, 0xde, 0x45, 0xee, 0x44, 0x7f, 0xab, 0x94, 0x78, 0x64, 0x98, 0xd3, 0xf6,
+0x28, 0xdd, 0x87, 0xd8, 0x70, 0x65, 0x74, 0xfb, 0x0e, 0xb9, 0x13, 0xeb, 0xa7, 0x0f, 0x61, 0xa9,
+0x32, 0x96, 0xcc, 0xde, 0xbb, 0xed, 0x63, 0x4c, 0x18, 0xbb, 0xa9, 0x40, 0xf7, 0xa0, 0x54, 0x6e,
+0x20, 0x88, 0x71, 0x75, 0x18, 0xea, 0x7a, 0xb4, 0x34, 0x72, 0xe0, 0x23, 0x27, 0x77, 0x5c, 0xb6,
+0x90, 0xea, 0x86, 0x25, 0x40, 0xab, 0xef, 0x33, 0x0f, 0xcb, 0x9f, 0x82, 0xbe, 0xa2, 0x20, 0xfb,
+0xf6, 0xb5, 0x2d, 0x1a, 0xe6, 0xc2, 0x85, 0xb1, 0x74, 0x0f, 0xfb, 0xc8, 0x65, 0x02, 0xa4, 0x52,
+0x01, 0x47, 0xdd, 0x49, 0x22, 0xc1, 0xbf, 0xd8, 0xeb, 0x6b, 0xac, 0x7e, 0xde, 0xec, 0x63, 0x33,
+0x15, 0xb7, 0x23, 0x08, 0x8f, 0xc6, 0x0f, 0x8d, 0x41, 0x5a, 0xdd, 0x8e, 0xc5, 0xb9, 0x8f, 0xe5,
+0x45, 0x3f, 0x78, 0xdb, 0xba, 0xd2, 0x1b, 0x40, 0xb1, 0xfe, 0x71, 0x4d, 0x3f, 0xe0, 0x81, 0xa2,
+0xba, 0x5e, 0xb4, 0xec, 0x15, 0xe0, 0x93, 0xdd, 0x08, 0x1f, 0x7e, 0xe1, 0x55, 0x99, 0x0b, 0x21,
+0xde, 0x93, 0x9e, 0x0a, 0xfb, 0xe6, 0xa3, 0x49, 0xbd, 0x36, 0x30, 0xfe, 0xe7, 0x77, 0xb2, 0xa0,
+0x75, 0x97, 0xb5, 0x2d, 0x81, 0x88, 0x17, 0x65, 0x20, 0xf7, 0xda, 0x90, 0x00, 0x9f, 0xc9, 0x52,
+0xcc, 0x32, 0xca, 0x35, 0x7c, 0xf5, 0x3d, 0x0f, 0xd8, 0x2b, 0xd7, 0xf5, 0x26, 0x6c, 0xc9, 0x06,
+0x34, 0x96, 0x16, 0xea, 0x70, 0x59, 0x1a, 0x32, 0x79, 0x79, 0x0b, 0xb6, 0x88, 0x7f, 0x0f, 0x52,
+0x48, 0x3d, 0xbf, 0x6c, 0xd8, 0xa2, 0x44, 0x2e, 0xd1, 0x4e, 0xb7, 0x72, 0x58, 0xd3, 0x89, 0x13,
+0x95, 0xfe, 0x44, 0xab, 0xf8, 0xd7, 0x8b, 0x1b, 0x6e, 0x9c, 0xbc, 0x2c, 0xa0, 0x5b, 0xd5, 0x6a,
+0x00, 0xaf, 0x5f, 0x37, 0xe1, 0xd5, 0xfa, 0x10, 0x0b, 0x98, 0x9c, 0x86, 0xe7, 0x26, 0x8f, 0xce,
+0xf0, 0xec, 0x6e, 0x8a, 0x57, 0x0b, 0x80, 0xe3, 0x4e, 0xb2, 0xc0, 0xa0, 0x63, 0x61, 0x90, 0xba,
+0x55, 0x68, 0x37, 0x74, 0x6a, 0xb6, 0x92, 0xdb, 0x9f, 0xa1, 0x86, 0x22, 0xb6, 0x65, 0x27, 0x0e,
+0xec, 0xb6, 0x9f, 0x42, 0x60, 0xe4, 0x67, 0xc2, 0xb5, 0xda, 0x41, 0x0b, 0xc4, 0xd3, 0x8b, 0x61,
+0x1b, 0xbc, 0xfa, 0x1f, 0x91, 0x2b, 0xd7, 0x44, 0x07, 0x5e, 0xba, 0x29, 0xac, 0xd9, 0xc5, 0xe9,
+0xef, 0x53, 0x48, 0x5a, 0xeb, 0x80, 0xf1, 0x28, 0x58, 0x21, 0xcd, 0xb0, 0x06, 0x55, 0xfb, 0x27,
+0x3f, 0x53, 0x90, 0x70, 0xa9, 0x04, 0x1e, 0x57, 0x27, 0xb9, 0x30, 0x82, 0x05, 0x83, 0x30, 0x82,
+0x03, 0x6b, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0f, 0x5d, 0x93, 0x8d, 0x30, 0x67, 0x36, 0xc8,
+0x06, 0x1d, 0x1a, 0xc7, 0x54, 0x84, 0x69, 0x07, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+0x08, 0x46, 0x4e, 0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x0c, 0x10, 0x41, 0x43, 0x20, 0x52, 0x41, 0x49, 0x5a, 0x20, 0x46, 0x4e, 0x4d, 0x54,
+0x2d, 0x52, 0x43, 0x4d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x31, 0x30, 0x32, 0x39, 0x31, 0x35,
+0x35, 0x39, 0x35, 0x36, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x5a, 0x30, 0x3b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x45, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x46, 0x4e,
+0x4d, 0x54, 0x2d, 0x52, 0x43, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
+0x10, 0x41, 0x43, 0x20, 0x52, 0x41, 0x49, 0x5a, 0x20, 0x46, 0x4e, 0x4d, 0x54, 0x2d, 0x52, 0x43,
+0x4d, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02,
+0x01, 0x00, 0xba, 0x71, 0x80, 0x7a, 0x4c, 0x86, 0x6e, 0x7f, 0xc8, 0x13, 0x6d, 0xc0, 0xc6, 0x7d,
+0x1c, 0x00, 0x97, 0x8f, 0x2c, 0x0c, 0x23, 0xbb, 0x10, 0x9a, 0x40, 0xa9, 0x1a, 0xb7, 0x87, 0x88,
+0xf8, 0x9b, 0x56, 0x6a, 0xfb, 0xe6, 0x7b, 0x8e, 0x8b, 0x92, 0x8e, 0xa7, 0x25, 0x5d, 0x59, 0x11,
+0xdb, 0x36, 0x2e, 0xb7, 0x51, 0x17, 0x1f, 0xa9, 0x08, 0x1f, 0x04, 0x17, 0x24, 0x58, 0xaa, 0x37,
+0x4a, 0x18, 0xdf, 0xe5, 0x39, 0xd4, 0x57, 0xfd, 0xd7, 0xc1, 0x2c, 0x91, 0x01, 0x91, 0xe2, 0x22,
+0xd4, 0x03, 0xc0, 0x58, 0xfc, 0x77, 0x47, 0xec, 0x8f, 0x3e, 0x74, 0x43, 0xba, 0xac, 0x34, 0x8d,
+0x4d, 0x38, 0x76, 0x67, 0x8e, 0xb0, 0xc8, 0x6f, 0x30, 0x33, 0x58, 0x71, 0x5c, 0xb4, 0xf5, 0x6b,
+0x6e, 0xd4, 0x01, 0x50, 0xb8, 0x13, 0x7e, 0x6c, 0x4a, 0xa3, 0x49, 0xd1, 0x20, 0x19, 0xee, 0xbc,
+0xc0, 0x29, 0x18, 0x65, 0xa7, 0xde, 0xfe, 0xef, 0xdd, 0x0a, 0x90, 0x21, 0xe7, 0x1a, 0x67, 0x92,
+0x42, 0x10, 0x98, 0x5f, 0x4f, 0x30, 0xbc, 0x3e, 0x1c, 0x45, 0xb4, 0x10, 0xd7, 0x68, 0x40, 0x14,
+0xc0, 0x40, 0xfa, 0xe7, 0x77, 0x17, 0x7a, 0xe6, 0x0b, 0x8f, 0x65, 0x5b, 0x3c, 0xd9, 0x9a, 0x52,
+0xdb, 0xb5, 0xbd, 0x9e, 0x46, 0xcf, 0x3d, 0xeb, 0x91, 0x05, 0x02, 0xc0, 0x96, 0xb2, 0x76, 0x4c,
+0x4d, 0x10, 0x96, 0x3b, 0x92, 0xfa, 0x9c, 0x7f, 0x0f, 0x99, 0xdf, 0xbe, 0x23, 0x35, 0x45, 0x1e,
+0x02, 0x5c, 0xfe, 0xb5, 0xa8, 0x9b, 0x99, 0x25, 0xda, 0x5e, 0xf3, 0x22, 0xc3, 0x39, 0xf5, 0xe4,
+0x2a, 0x2e, 0xd3, 0xc6, 0x1f, 0xc4, 0x6c, 0xaa, 0xc5, 0x1c, 0x6a, 0x01, 0x05, 0x4a, 0x2f, 0xd2,
+0xc5, 0xc1, 0xa8, 0x34, 0x26, 0x5d, 0x66, 0xa5, 0xd2, 0x02, 0x21, 0xf9, 0x18, 0xb7, 0x06, 0xf5,
+0x4e, 0x99, 0x6f, 0xa8, 0xab, 0x4c, 0x51, 0xe8, 0xcf, 0x50, 0x18, 0xc5, 0x77, 0xc8, 0x39, 0x09,
+0x2c, 0x49, 0x92, 0x32, 0x99, 0xa8, 0xbb, 0x17, 0x17, 0x79, 0xb0, 0x5a, 0xc5, 0xe6, 0xa3, 0xc4,
+0x59, 0x65, 0x47, 0x35, 0x83, 0x5e, 0xa9, 0xe8, 0x35, 0x0b, 0x99, 0xbb, 0xe4, 0xcd, 0x20, 0xc6,
+0x9b, 0x4a, 0x06, 0x39, 0xb5, 0x68, 0xfc, 0x22, 0xba, 0xee, 0x55, 0x8c, 0x2b, 0x4e, 0xea, 0xf3,
+0xb1, 0xe3, 0xfc, 0xb6, 0x99, 0x9a, 0xd5, 0x42, 0xfa, 0x71, 0x4d, 0x08, 0xcf, 0x87, 0x1e, 0x6a,
+0x71, 0x7d, 0xf9, 0xd3, 0xb4, 0xe9, 0xa5, 0x71, 0x81, 0x7b, 0xc2, 0x4e, 0x47, 0x96, 0xa5, 0xf6,
+0x76, 0x85, 0xa3, 0x28, 0x8f, 0xe9, 0x80, 0x6e, 0x81, 0x53, 0xa5, 0x6d, 0x5f, 0xb8, 0x48, 0xf9,
+0xc2, 0xf9, 0x36, 0xa6, 0x2e, 0x49, 0xff, 0xb8, 0x96, 0xc2, 0x8c, 0x07, 0xb3, 0x9b, 0x88, 0x58,
+0xfc, 0xeb, 0x1b, 0x1c, 0xde, 0x2d, 0x70, 0xe2, 0x97, 0x92, 0x30, 0xa1, 0x89, 0xe3, 0xbc, 0x55,
+0xa8, 0x27, 0xd6, 0x4b, 0xed, 0x90, 0xad, 0x8b, 0xfa, 0x63, 0x25, 0x59, 0x2d, 0xa8, 0x35, 0xdd,
+0xca, 0x97, 0x33, 0xbc, 0xe5, 0xcd, 0xc7, 0x9d, 0xd1, 0xec, 0xef, 0x5e, 0x0e, 0x4a, 0x90, 0x06,
+0x26, 0x63, 0xad, 0xb9, 0xd9, 0x35, 0x2d, 0x07, 0xba, 0x76, 0x65, 0x2c, 0xac, 0x57, 0x8f, 0x7d,
+0xf4, 0x07, 0x94, 0xd7, 0x81, 0x02, 0x96, 0x5d, 0xa3, 0x07, 0x49, 0xd5, 0x7a, 0xd0, 0x57, 0xf9,
+0x1b, 0xe7, 0x53, 0x46, 0x75, 0xaa, 0xb0, 0x79, 0x42, 0xcb, 0x68, 0x71, 0x08, 0xe9, 0x60, 0xbd,
+0x39, 0x69, 0xce, 0xf4, 0xaf, 0xc3, 0x56, 0x40, 0xc7, 0xad, 0x52, 0xa2, 0x09, 0xe4, 0x6f, 0x86,
+0x47, 0x8a, 0x1f, 0xeb, 0x28, 0x27, 0x5d, 0x83, 0x20, 0xaf, 0x04, 0xc9, 0x6c, 0x56, 0x9a, 0x8b,
+0x46, 0xf5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0x83, 0x30, 0x81, 0x80, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e,
+0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf7, 0x7d, 0xc5, 0xfd, 0xc4, 0xe8, 0x9a,
+0x1b, 0x77, 0x64, 0xa7, 0xf5, 0x1d, 0xa0, 0xcc, 0xbf, 0x87, 0x60, 0x9a, 0x6d, 0x30, 0x3e, 0x06,
+0x03, 0x55, 0x1d, 0x20, 0x04, 0x37, 0x30, 0x35, 0x30, 0x33, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00,
+0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1d,
+0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x2e,
+0x66, 0x6e, 0x6d, 0x74, 0x2e, 0x65, 0x73, 0x2f, 0x64, 0x70, 0x63, 0x73, 0x2f, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
+0x00, 0x07, 0x90, 0x4a, 0xdf, 0xf3, 0x23, 0x4e, 0xf0, 0xc3, 0x9c, 0x51, 0x65, 0x9b, 0x9c, 0x22,
+0xa2, 0x8a, 0x0c, 0x85, 0xf3, 0x73, 0x29, 0x6b, 0x4d, 0xfe, 0x01, 0xe2, 0xa9, 0x0c, 0x63, 0x01,
+0xbf, 0x04, 0x67, 0xa5, 0x9d, 0x98, 0x5f, 0xfd, 0x01, 0x13, 0xfa, 0xec, 0x9a, 0x62, 0xe9, 0x86,
+0xfe, 0xb6, 0x62, 0xd2, 0x6e, 0x4c, 0x94, 0xfb, 0xc0, 0x75, 0x45, 0x7c, 0x65, 0x0c, 0xf8, 0xb2,
+0x37, 0xcf, 0xac, 0x0f, 0xcf, 0x8d, 0x6f, 0xf9, 0x19, 0xf7, 0x8f, 0xec, 0x1e, 0xf2, 0x70, 0x9e,
+0xf0, 0xca, 0xb8, 0xef, 0xb7, 0xff, 0x76, 0x37, 0x76, 0x5b, 0xf6, 0x6e, 0x88, 0xf3, 0xaf, 0x62,
+0x32, 0x22, 0x93, 0x0d, 0x3a, 0x6a, 0x8e, 0x14, 0x66, 0x0c, 0x2d, 0x53, 0x74, 0x57, 0x65, 0x1e,
+0xd5, 0xb2, 0xdd, 0x23, 0x81, 0x3b, 0xa5, 0x66, 0x23, 0x27, 0x67, 0x09, 0x8f, 0xe1, 0x77, 0xaa,
+0x43, 0xcd, 0x65, 0x51, 0x08, 0xed, 0x51, 0x58, 0xfe, 0xe6, 0x39, 0xf9, 0xcb, 0x47, 0x84, 0xa4,
+0x15, 0xf1, 0x76, 0xbb, 0xa4, 0xee, 0xa4, 0x3b, 0xc4, 0x5f, 0xef, 0xb2, 0x33, 0x96, 0x11, 0x18,
+0xb7, 0xc9, 0x65, 0xbe, 0x18, 0xe1, 0xa3, 0xa4, 0xdc, 0xfa, 0x18, 0xf9, 0xd3, 0xbc, 0x13, 0x9b,
+0x39, 0x7a, 0x34, 0xba, 0xd3, 0x41, 0xfb, 0xfa, 0x32, 0x8a, 0x2a, 0xb7, 0x2b, 0x86, 0x0b, 0x69,
+0x83, 0x38, 0xbe, 0xcd, 0x8a, 0x2e, 0x0b, 0x70, 0xad, 0x8d, 0x26, 0x92, 0xee, 0x1e, 0xf5, 0x01,
+0x2b, 0x0a, 0xd9, 0xd6, 0x97, 0x9b, 0x6e, 0xe0, 0xa8, 0x19, 0x1c, 0x3a, 0x21, 0x8b, 0x0c, 0x1e,
+0x40, 0xad, 0x03, 0xe7, 0xdd, 0x66, 0x7e, 0xf5, 0xb9, 0x20, 0x0d, 0x03, 0xe8, 0x96, 0xf9, 0x82,
+0x45, 0xd4, 0x39, 0xe0, 0xa0, 0x00, 0x5d, 0xd7, 0x98, 0xe6, 0x7d, 0x9e, 0x67, 0x73, 0xc3, 0x9a,
+0x2a, 0xf7, 0xab, 0x8b, 0xa1, 0x3a, 0x14, 0xef, 0x34, 0xbc, 0x52, 0x0e, 0x89, 0x98, 0x9a, 0x04,
+0x40, 0x84, 0x1d, 0x7e, 0x45, 0x69, 0x93, 0x57, 0xce, 0xeb, 0xce, 0xf8, 0x50, 0x7c, 0x4f, 0x1c,
+0x6e, 0x04, 0x43, 0x9b, 0xf9, 0xd6, 0x3b, 0x23, 0x18, 0xe9, 0xea, 0x8e, 0xd1, 0x4d, 0x46, 0x8d,
+0xf1, 0x3b, 0xe4, 0x6a, 0xca, 0xba, 0xfb, 0x23, 0xb7, 0x9b, 0xfa, 0x99, 0x01, 0x29, 0x5a, 0x58,
+0x5a, 0x2d, 0xe3, 0xf9, 0xd4, 0x6d, 0x0e, 0x26, 0xad, 0xc1, 0x6e, 0x34, 0xbc, 0x32, 0xf8, 0x0c,
+0x05, 0xfa, 0x65, 0xa3, 0xdb, 0x3b, 0x37, 0x83, 0x22, 0xe9, 0xd6, 0xdc, 0x72, 0x33, 0xfd, 0x5d,
+0xf2, 0x20, 0xbd, 0x76, 0x3c, 0x23, 0xda, 0x28, 0xf7, 0xf9, 0x1b, 0xeb, 0x59, 0x64, 0xd5, 0xdc,
+0x5f, 0x72, 0x7e, 0x20, 0xfc, 0xcd, 0x89, 0xb5, 0x90, 0x67, 0x4d, 0x62, 0x7a, 0x3f, 0x4e, 0xad,
+0x1d, 0xc3, 0x39, 0xfe, 0x7a, 0xf4, 0x28, 0x16, 0xdf, 0x41, 0xf6, 0x48, 0x80, 0x05, 0xd7, 0x0f,
+0x51, 0x79, 0xac, 0x10, 0xab, 0xd4, 0xec, 0x03, 0x66, 0xe6, 0x6a, 0xb0, 0xba, 0x31, 0x92, 0x42,
+0x40, 0x6a, 0xbe, 0x3a, 0xd3, 0x72, 0xe1, 0x6a, 0x37, 0x55, 0xbc, 0xac, 0x1d, 0x95, 0xb7, 0x69,
+0x61, 0xf2, 0x43, 0x91, 0x74, 0xe6, 0xa0, 0xd3, 0x0a, 0x24, 0x46, 0xa1, 0x08, 0xaf, 0xd6, 0xda,
+0x45, 0x19, 0x96, 0xd4, 0x53, 0x1d, 0x5b, 0x84, 0x79, 0xf0, 0xc0, 0xf7, 0x47, 0xef, 0x8b, 0x8f,
+0xc5, 0x06, 0xae, 0x9d, 0x4c, 0x62, 0x9d, 0xff, 0x46, 0x04, 0xf8, 0xd3, 0xc9, 0xb6, 0x10, 0x25,
+0x40, 0x75, 0xfe, 0x16, 0xaa, 0xc9, 0x4a, 0x60, 0x86, 0x2f, 0xba, 0xef, 0x30, 0x77, 0xe4, 0x54,
+0xe2, 0xb8, 0x84, 0x99, 0x58, 0x80, 0xaa, 0x13, 0x8b, 0x51, 0x3a, 0x4f, 0x48, 0xf6, 0x8b, 0xb6,
+0xb3, 0x30, 0x82, 0x05, 0x8d, 0x30, 0x82, 0x03, 0x75, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04,
+0x18, 0x4a, 0xcc, 0xd6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x30, 0x56, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x43, 0x4e, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x27, 0x43, 0x68, 0x69,
+0x6e, 0x61, 0x20, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x74, 0x79, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0c, 0x43,
+0x46, 0x43, 0x41, 0x20, 0x45, 0x56, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+0x32, 0x30, 0x38, 0x30, 0x38, 0x30, 0x33, 0x30, 0x37, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x39,
+0x31, 0x32, 0x33, 0x31, 0x30, 0x33, 0x30, 0x37, 0x30, 0x31, 0x5a, 0x30, 0x56, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4e, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x0c, 0x27, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x20, 0x46, 0x69, 0x6e, 0x61, 0x6e,
+0x63, 0x69, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x15, 0x30, 0x13,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0c, 0x43, 0x46, 0x43, 0x41, 0x20, 0x45, 0x56, 0x20, 0x52,
+0x4f, 0x4f, 0x54, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02,
+0x82, 0x02, 0x01, 0x00, 0xd7, 0x5d, 0x6b, 0xcd, 0x10, 0x3f, 0x1f, 0x05, 0x59, 0xd5, 0x05, 0x4d,
+0x37, 0xb1, 0x0e, 0xec, 0x98, 0x2b, 0x8e, 0x15, 0x1d, 0xfa, 0x93, 0x4b, 0x17, 0x82, 0x21, 0x71,
+0x10, 0x52, 0xd7, 0x51, 0x64, 0x70, 0x16, 0xc2, 0x55, 0x69, 0x4d, 0x8e, 0x15, 0x6d, 0x9f, 0xbf,
+0x0c, 0x1b, 0xc2, 0xe0, 0xa3, 0x67, 0xd6, 0x0c, 0xac, 0xcf, 0x22, 0xae, 0xaf, 0x77, 0x54, 0x2a,
+0x4b, 0x4c, 0x8a, 0x53, 0x52, 0x7a, 0xc3, 0xee, 0x2e, 0xde, 0xb3, 0x71, 0x25, 0xc1, 0xe9, 0x5d,
+0x3d, 0xee, 0xa1, 0x2f, 0xa3, 0xf7, 0x2a, 0x3c, 0xc9, 0x23, 0x1d, 0x6a, 0xab, 0x1d, 0xa1, 0xa7,
+0xf1, 0xf3, 0xec, 0xa0, 0xd5, 0x44, 0xcf, 0x15, 0xcf, 0x72, 0x2f, 0x1d, 0x63, 0x97, 0xe8, 0x99,
+0xf9, 0xfd, 0x93, 0xa4, 0x54, 0x80, 0x4c, 0x52, 0xd4, 0x52, 0xab, 0x2e, 0x49, 0xdf, 0x90, 0xcd,
+0xb8, 0x5f, 0xbe, 0x3f, 0xde, 0xa1, 0xca, 0x4d, 0x20, 0xd4, 0x25, 0xe8, 0x84, 0x29, 0x53, 0xb7,
+0xb1, 0x88, 0x1f, 0xff, 0xfa, 0xda, 0x90, 0x9f, 0x0a, 0xa9, 0x2d, 0x41, 0x3f, 0xb1, 0xf1, 0x18,
+0x29, 0xee, 0x16, 0x59, 0x2c, 0x34, 0x49, 0x1a, 0xa8, 0x06, 0xd7, 0xa8, 0x88, 0xd2, 0x03, 0x72,
+0x7a, 0x32, 0xe2, 0xea, 0x68, 0x4d, 0x6e, 0x2c, 0x96, 0x65, 0x7b, 0xca, 0x59, 0xfa, 0xf2, 0xe2,
+0xdd, 0xee, 0x30, 0x2c, 0xfb, 0xcc, 0x46, 0xac, 0xc4, 0x63, 0xeb, 0x6f, 0x7f, 0x36, 0x2b, 0x34,
+0x73, 0x12, 0x94, 0x7f, 0xdf, 0xcc, 0x26, 0x9e, 0xf1, 0x72, 0x5d, 0x50, 0x65, 0x59, 0x8f, 0x69,
+0xb3, 0x87, 0x5e, 0x32, 0x6f, 0xc3, 0x18, 0x8a, 0xb5, 0x95, 0x8f, 0xb0, 0x7a, 0x37, 0xde, 0x5a,
+0x45, 0x3b, 0xc7, 0x36, 0xe1, 0xef, 0x67, 0xd1, 0x39, 0xd3, 0x97, 0x5b, 0x73, 0x62, 0x19, 0x48,
+0x2d, 0x87, 0x1c, 0x06, 0xfb, 0x74, 0x98, 0x20, 0x49, 0x73, 0xf0, 0x05, 0xd2, 0x1b, 0xb1, 0xa0,
+0xa3, 0xb7, 0x1b, 0x70, 0xd3, 0x88, 0x69, 0xb9, 0x5a, 0xd6, 0x38, 0xf4, 0x62, 0xdc, 0x25, 0x8b,
+0x78, 0xbf, 0xf8, 0xe8, 0x7e, 0xb8, 0x5c, 0xc9, 0x95, 0x4f, 0x5f, 0xa7, 0x2d, 0xb9, 0x20, 0x6b,
+0xcf, 0x6b, 0xdd, 0xf5, 0x0d, 0xf4, 0x82, 0xb7, 0xf4, 0xb2, 0x66, 0x2e, 0x10, 0x28, 0xf6, 0x97,
+0x5a, 0x7b, 0x96, 0x16, 0x8f, 0x01, 0x19, 0x2d, 0x6c, 0x6e, 0x7f, 0x39, 0x58, 0x06, 0x64, 0x83,
+0x01, 0x83, 0x83, 0xc3, 0x4d, 0x92, 0xdd, 0x32, 0xc6, 0x87, 0xa4, 0x37, 0xe9, 0x16, 0xce, 0xaa,
+0x2d, 0x68, 0xaf, 0x0a, 0x81, 0x65, 0x3a, 0x70, 0xc1, 0x9b, 0xad, 0x4d, 0x6d, 0x54, 0xca, 0x2a,
+0x2d, 0x4b, 0x85, 0x1b, 0xb3, 0x80, 0xe6, 0x70, 0x45, 0x0d, 0x6b, 0x5e, 0x35, 0xf0, 0x7f, 0x3b,
+0xb8, 0x9c, 0xe4, 0x04, 0x70, 0x89, 0x12, 0x25, 0x93, 0xda, 0x0a, 0x99, 0x22, 0x60, 0x6a, 0x63,
+0x60, 0x4e, 0x76, 0x06, 0x98, 0x4e, 0xbd, 0x83, 0xad, 0x1d, 0x58, 0x8a, 0x25, 0x85, 0xd2, 0xc7,
+0x65, 0x1e, 0x2d, 0x8e, 0xc6, 0xdf, 0xb6, 0xc6, 0xe1, 0x7f, 0x8a, 0x04, 0x21, 0x15, 0x29, 0x74,
+0xf0, 0x3e, 0x9c, 0x90, 0x9d, 0x0c, 0x2e, 0xf1, 0x8a, 0x3e, 0x5a, 0xaa, 0x0c, 0x09, 0x1e, 0xc7,
+0xd5, 0x3c, 0xa3, 0xed, 0x97, 0xc3, 0x1e, 0x34, 0xfa, 0x38, 0xf9, 0x08, 0x0e, 0xe3, 0xc0, 0x5d,
+0x2b, 0x83, 0xd1, 0x56, 0x6a, 0xc9, 0xb6, 0xa8, 0x54, 0x53, 0x2e, 0x78, 0x32, 0x67, 0x3d, 0x82,
+0x7f, 0x74, 0xd0, 0xfb, 0xe1, 0xb6, 0x05, 0x60, 0xb9, 0x70, 0xdb, 0x8e, 0x0b, 0xf9, 0x13, 0x58,
+0x6f, 0x71, 0x60, 0x10, 0x52, 0x10, 0xb9, 0xc1, 0x41, 0x09, 0xef, 0x72, 0x1f, 0x67, 0x31, 0x78,
+0xff, 0x96, 0x05, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1f, 0x06,
+0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe3, 0xfe, 0x2d, 0xfd, 0x28, 0xd0,
+0x0b, 0xb5, 0xba, 0xb6, 0xa2, 0xc4, 0xbf, 0x06, 0xaa, 0x05, 0x8c, 0x93, 0xfb, 0x2f, 0x30, 0x0f,
+0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xe3, 0xfe, 0x2d, 0xfd, 0x28, 0xd0,
+0x0b, 0xb5, 0xba, 0xb6, 0xa2, 0xc4, 0xbf, 0x06, 0xaa, 0x05, 0x8c, 0x93, 0xfb, 0x2f, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02,
+0x01, 0x00, 0x25, 0xc6, 0xba, 0x6b, 0xeb, 0x87, 0xcb, 0xde, 0x82, 0x39, 0x96, 0x3d, 0xf0, 0x44,
+0xa7, 0x6b, 0x84, 0x73, 0x03, 0xde, 0x9d, 0x2b, 0x4f, 0xba, 0x20, 0x7f, 0xbc, 0x78, 0xb2, 0xcf,
+0x97, 0xb0, 0x1b, 0x9c, 0xf3, 0xd7, 0x79, 0x2e, 0xf5, 0x48, 0xb6, 0xd2, 0xfb, 0x17, 0x88, 0xe6,
+0xd3, 0x7a, 0x3f, 0xed, 0x53, 0x13, 0xd0, 0xe2, 0x2f, 0x6a, 0x79, 0xcb, 0x00, 0x23, 0x28, 0xe6,
+0x1e, 0x37, 0x57, 0x35, 0x89, 0x84, 0xc2, 0x76, 0x4f, 0x34, 0x36, 0xad, 0x67, 0xc3, 0xce, 0x41,
+0x06, 0x88, 0xc5, 0xf7, 0xee, 0xd8, 0x1a, 0xb8, 0xd6, 0x0b, 0x7f, 0x50, 0xff, 0x93, 0xaa, 0x17,
+0x4b, 0x8c, 0xec, 0xed, 0x52, 0x60, 0xb2, 0xa4, 0x06, 0xea, 0x4e, 0xeb, 0xf4, 0x6b, 0x19, 0xfd,
+0xeb, 0xf5, 0x1a, 0xe0, 0x25, 0x2a, 0x9a, 0xdc, 0xc7, 0x41, 0x36, 0xf7, 0xc8, 0x74, 0x05, 0x84,
+0x39, 0x95, 0x39, 0xd6, 0x0b, 0x3b, 0xa4, 0x27, 0xfa, 0x08, 0xd8, 0x5c, 0x1e, 0xf8, 0x04, 0x60,
+0x52, 0x11, 0x28, 0x28, 0x03, 0xff, 0xef, 0x53, 0x66, 0x00, 0xa5, 0x4a, 0x34, 0x16, 0x66, 0x7c,
+0xfd, 0x09, 0xa4, 0xae, 0x9e, 0x67, 0x1a, 0x6f, 0x41, 0x0b, 0x6b, 0x06, 0x13, 0x9b, 0x8f, 0x86,
+0x71, 0x05, 0xb4, 0x2f, 0x8d, 0x89, 0x66, 0x33, 0x29, 0x76, 0x54, 0x9a, 0x11, 0xf8, 0x27, 0xfa,
+0xb2, 0x3f, 0x91, 0xe0, 0xce, 0x0d, 0x1b, 0xf3, 0x30, 0x1a, 0xad, 0xbf, 0x22, 0x5d, 0x1b, 0xd3,
+0xbf, 0x25, 0x05, 0x4d, 0xe1, 0x92, 0x1a, 0x7f, 0x99, 0x9f, 0x3c, 0x44, 0x93, 0xca, 0xd4, 0x40,
+0x49, 0x6c, 0x80, 0x87, 0xd7, 0x04, 0x3a, 0xc3, 0x32, 0x52, 0x35, 0x0e, 0x56, 0xf8, 0xa5, 0xdd,
+0x7d, 0xc4, 0x8b, 0x0d, 0x11, 0x1f, 0x53, 0xcb, 0x1e, 0xb2, 0x17, 0xb6, 0x68, 0x77, 0x5a, 0xe0,
+0xd4, 0xcb, 0xc8, 0x07, 0xae, 0xf5, 0x3a, 0x2e, 0x8e, 0x37, 0xb7, 0xd0, 0x01, 0x4b, 0x43, 0x29,
+0x77, 0x8c, 0x39, 0x97, 0x8f, 0x82, 0x5a, 0xf8, 0x51, 0xe5, 0x89, 0xa0, 0x18, 0xe7, 0x68, 0x7f,
+0x5d, 0x0a, 0x2e, 0xfb, 0xa3, 0x47, 0x0e, 0x3d, 0xa6, 0x23, 0x7a, 0xc6, 0x01, 0xc7, 0x8f, 0xc8,
+0x5e, 0xbf, 0x6d, 0x80, 0x56, 0xbe, 0x8a, 0x24, 0xba, 0x33, 0xea, 0x9f, 0xe1, 0x32, 0x11, 0x9e,
+0xf1, 0xd2, 0x4f, 0x80, 0xf6, 0x1b, 0x40, 0xaf, 0x38, 0x9e, 0x11, 0x50, 0x79, 0x73, 0x12, 0x12,
+0xcd, 0xe6, 0x6c, 0x9d, 0x2c, 0x88, 0x72, 0x3c, 0x30, 0x81, 0x06, 0x91, 0x22, 0xea, 0x59, 0xad,
+0xda, 0x19, 0x2e, 0x22, 0xc2, 0x8d, 0xb9, 0x8c, 0x87, 0xe0, 0x66, 0xbc, 0x73, 0x23, 0x5f, 0x21,
+0x64, 0x63, 0x80, 0x48, 0xf5, 0xa0, 0x3c, 0x18, 0x3d, 0x94, 0xc8, 0x48, 0x41, 0x1d, 0x40, 0xba,
+0x5e, 0xfe, 0xfe, 0x56, 0x39, 0xa1, 0xc8, 0xcf, 0x5e, 0x9e, 0x19, 0x64, 0x46, 0x10, 0xda, 0x17,
+0x91, 0xb7, 0x05, 0x80, 0xac, 0x8b, 0x99, 0x92, 0x7d, 0xe7, 0xa2, 0xd8, 0x07, 0x0b, 0x36, 0x27,
+0xe7, 0x48, 0x79, 0x60, 0x8a, 0xc3, 0xd7, 0x13, 0x5c, 0xf8, 0x72, 0x40, 0xdf, 0x4a, 0xcb, 0xcf,
+0x99, 0x00, 0x0a, 0x00, 0x0b, 0x11, 0x95, 0xda, 0x56, 0x45, 0x03, 0x88, 0x0a, 0x9f, 0x67, 0xd0,
+0xd5, 0x79, 0xb1, 0xa8, 0x8d, 0x40, 0x6d, 0x0d, 0xc2, 0x7a, 0x40, 0xfa, 0xf3, 0x5f, 0x64, 0x47,
+0x92, 0xcb, 0x53, 0xb9, 0xbb, 0x59, 0xce, 0x4f, 0xfd, 0xd0, 0x15, 0x53, 0x01, 0xd8, 0xdf, 0xeb,
+0xd9, 0xe6, 0x76, 0xef, 0xd0, 0x23, 0xbb, 0x3b, 0xa9, 0x79, 0xb3, 0xd5, 0x02, 0x29, 0xcd, 0x89,
+0xa3, 0x96, 0x0f, 0x4a, 0x35, 0xe7, 0x4e, 0x42, 0xc0, 0x75, 0xcd, 0x07, 0xcf, 0xe6, 0x2c, 0xeb,
+0x7b, 0x2e, 0x30, 0x82, 0x04, 0x15, 0x30, 0x82, 0x02, 0xfd, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+0x06, 0x49, 0x41, 0x2c, 0xe4, 0x00, 0x10, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xa7, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x48, 0x55, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
+0x08, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65, 0x73, 0x74, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x0c, 0x0c, 0x4e, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x4b, 0x66, 0x74, 0x2e,
+0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x2e, 0x54, 0x61, 0x6e, 0xc3, 0xba,
+0x73, 0xc3, 0xad, 0x74, 0x76, 0xc3, 0xa1, 0x6e, 0x79, 0x6b, 0x69, 0x61, 0x64, 0xc3, 0xb3, 0x6b,
+0x20, 0x28, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x29, 0x31, 0x35, 0x30, 0x33, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x0c, 0x2c, 0x4e, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x41, 0x72, 0x61, 0x6e,
+0x79, 0x20, 0x28, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x47, 0x6f, 0x6c, 0x64, 0x29, 0x20, 0x46,
+0xc5, 0x91, 0x74, 0x61, 0x6e, 0xc3, 0xba, 0x73, 0xc3, 0xad, 0x74, 0x76, 0xc3, 0xa1, 0x6e, 0x79,
+0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x31, 0x32, 0x31, 0x31, 0x31, 0x35, 0x30, 0x38, 0x32, 0x31,
+0x5a, 0x17, 0x0d, 0x32, 0x38, 0x31, 0x32, 0x30, 0x36, 0x31, 0x35, 0x30, 0x38, 0x32, 0x31, 0x5a,
+0x30, 0x81, 0xa7, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55,
+0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70,
+0x65, 0x73, 0x74, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x4e, 0x65,
+0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x4b, 0x66, 0x74, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03,
+0x55, 0x04, 0x0b, 0x0c, 0x2e, 0x54, 0x61, 0x6e, 0xc3, 0xba, 0x73, 0xc3, 0xad, 0x74, 0x76, 0xc3,
+0xa1, 0x6e, 0x79, 0x6b, 0x69, 0x61, 0x64, 0xc3, 0xb3, 0x6b, 0x20, 0x28, 0x43, 0x65, 0x72, 0x74,
+0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+0x65, 0x73, 0x29, 0x31, 0x35, 0x30, 0x33, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2c, 0x4e, 0x65,
+0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x20, 0x41, 0x72, 0x61, 0x6e, 0x79, 0x20, 0x28, 0x43, 0x6c, 0x61,
+0x73, 0x73, 0x20, 0x47, 0x6f, 0x6c, 0x64, 0x29, 0x20, 0x46, 0xc5, 0x91, 0x74, 0x61, 0x6e, 0xc3,
+0xba, 0x73, 0xc3, 0xad, 0x74, 0x76, 0xc3, 0xa1, 0x6e, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
+0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc4, 0x24, 0x5e, 0x73, 0xbe,
+0x4b, 0x6d, 0x14, 0xc3, 0xa1, 0xf4, 0xe3, 0x97, 0x90, 0x6e, 0xd2, 0x30, 0x45, 0x1e, 0x3c, 0xee,
+0x67, 0xd9, 0x64, 0xe0, 0x1a, 0x8a, 0x7f, 0xca, 0x30, 0xca, 0x83, 0xe3, 0x20, 0xc1, 0xe3, 0xf4,
+0x3a, 0xd3, 0x94, 0x5f, 0x1a, 0x7c, 0x5b, 0x6d, 0xbf, 0x30, 0x4f, 0x84, 0x27, 0xf6, 0x9f, 0x1f,
+0x49, 0xbc, 0xc6, 0x99, 0x0a, 0x90, 0xf2, 0x0f, 0xf5, 0x7f, 0x43, 0x84, 0x37, 0x63, 0x51, 0x8b,
+0x7a, 0xa5, 0x70, 0xfc, 0x7a, 0x58, 0xcd, 0x8e, 0x9b, 0xed, 0xc3, 0x46, 0x6c, 0x84, 0x70, 0x5d,
+0xda, 0xf3, 0x01, 0x90, 0x23, 0xfc, 0x4e, 0x30, 0xa9, 0x7e, 0xe1, 0x27, 0x63, 0xe7, 0xed, 0x64,
+0x3c, 0xa0, 0xb8, 0xc9, 0x33, 0x63, 0xfe, 0x16, 0x90, 0xff, 0xb0, 0xb8, 0xfd, 0xd7, 0xa8, 0xc0,
+0xc0, 0x94, 0x43, 0x0b, 0xb6, 0xd5, 0x59, 0xa6, 0x9e, 0x56, 0xd0, 0x24, 0x1f, 0x70, 0x79, 0xaf,
+0xdb, 0x39, 0x54, 0x0d, 0x65, 0x75, 0xd9, 0x15, 0x41, 0x94, 0x01, 0xaf, 0x5e, 0xec, 0xf6, 0x8d,
+0xf1, 0xff, 0xad, 0x64, 0xfe, 0x20, 0x9a, 0xd7, 0x5c, 0xeb, 0xfe, 0xa6, 0x1f, 0x08, 0x64, 0xa3,
+0x8b, 0x76, 0x55, 0xad, 0x1e, 0x3b, 0x28, 0x60, 0x2e, 0x87, 0x25, 0xe8, 0xaa, 0xaf, 0x1f, 0xc6,
+0x64, 0x46, 0x20, 0xb7, 0x70, 0x7f, 0x3c, 0xde, 0x48, 0xdb, 0x96, 0x53, 0xb7, 0x39, 0x77, 0xe4,
+0x1a, 0xe2, 0xc7, 0x16, 0x84, 0x76, 0x97, 0x5b, 0x2f, 0xbb, 0x19, 0x15, 0x85, 0xf8, 0x69, 0x85,
+0xf5, 0x99, 0xa7, 0xa9, 0xf2, 0x34, 0xa7, 0xa9, 0xb6, 0xa6, 0x03, 0xfc, 0x6f, 0x86, 0x3d, 0x54,
+0x7c, 0x76, 0x04, 0x9b, 0x6b, 0xf9, 0x40, 0x5d, 0x00, 0x34, 0xc7, 0x2e, 0x99, 0x75, 0x9d, 0xe5,
+0x88, 0x03, 0xaa, 0x4d, 0xf8, 0x03, 0xd2, 0x42, 0x76, 0xc0, 0x1b, 0x02, 0x03, 0x00, 0xa8, 0x8b,
+0xa3, 0x45, 0x30, 0x43, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
+0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x04, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+0x16, 0x04, 0x14, 0xcc, 0xfa, 0x67, 0x93, 0xf0, 0xb6, 0xb8, 0xd0, 0xa5, 0xc0, 0x1e, 0xf3, 0x53,
+0xfd, 0x8c, 0x53, 0xdf, 0x83, 0xd7, 0x96, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xab, 0x7f, 0xee, 0x1c, 0x16,
+0xa9, 0x9c, 0x3c, 0x51, 0x00, 0xa0, 0xc0, 0x11, 0x08, 0x05, 0xa7, 0x99, 0xe6, 0x6f, 0x01, 0x88,
+0x54, 0x61, 0x6e, 0xf1, 0xb9, 0x18, 0xad, 0x4a, 0xad, 0xfe, 0x81, 0x40, 0x23, 0x94, 0x2f, 0xfb,
+0x75, 0x7c, 0x2f, 0x28, 0x4b, 0x62, 0x24, 0x81, 0x82, 0x0b, 0xf5, 0x61, 0xf1, 0x1c, 0x6e, 0xb8,
+0x61, 0x38, 0xeb, 0x81, 0xfa, 0x62, 0xa1, 0x3b, 0x5a, 0x62, 0xd3, 0x94, 0x65, 0xc4, 0xe1, 0xe6,
+0x6d, 0x82, 0xf8, 0x2f, 0x25, 0x70, 0xb2, 0x21, 0x26, 0xc1, 0x72, 0x51, 0x1f, 0x8c, 0x2c, 0xc3,
+0x84, 0x90, 0xc3, 0x5a, 0x8f, 0xba, 0xcf, 0xf4, 0xa7, 0x65, 0xa5, 0xeb, 0x98, 0xd1, 0xfb, 0x05,
+0xb2, 0x46, 0x75, 0x15, 0x23, 0x6a, 0x6f, 0x85, 0x63, 0x30, 0x80, 0xf0, 0xd5, 0x9e, 0x1f, 0x29,
+0x1c, 0xc2, 0x6c, 0xb0, 0x50, 0x59, 0x5d, 0x90, 0x5b, 0x3b, 0xa8, 0x0d, 0x30, 0xcf, 0xbf, 0x7d,
+0x7f, 0xce, 0xf1, 0x9d, 0x83, 0xbd, 0xc9, 0x46, 0x6e, 0x20, 0xa6, 0xf9, 0x61, 0x51, 0xba, 0x21,
+0x2f, 0x7b, 0xbe, 0xa5, 0x15, 0x63, 0xa1, 0xd4, 0x95, 0x87, 0xf1, 0x9e, 0xb9, 0xf3, 0x89, 0xf3,
+0x3d, 0x85, 0xb8, 0xb8, 0xdb, 0xbe, 0xb5, 0xb9, 0x29, 0xf9, 0xda, 0x37, 0x05, 0x00, 0x49, 0x94,
+0x03, 0x84, 0x44, 0xe7, 0xbf, 0x43, 0x31, 0xcf, 0x75, 0x8b, 0x25, 0xd1, 0xf4, 0xa6, 0x64, 0xf5,
+0x92, 0xf6, 0xab, 0x05, 0xeb, 0x3d, 0xe9, 0xa5, 0x0b, 0x36, 0x62, 0xda, 0xcc, 0x06, 0x5f, 0x36,
+0x8b, 0xb6, 0x5e, 0x31, 0xb8, 0x2a, 0xfb, 0x5e, 0xf6, 0x71, 0xdf, 0x44, 0x26, 0x9e, 0xc4, 0xe6,
+0x0d, 0x91, 0xb4, 0x2e, 0x75, 0x95, 0x80, 0x51, 0x6a, 0x4b, 0x30, 0xa6, 0xb0, 0x62, 0xa1, 0x93,
+0xf1, 0x9b, 0xd8, 0xce, 0xc4, 0x63, 0x75, 0x3f, 0x59, 0x47, 0xb1, 0x30, 0x82, 0x03, 0x4a, 0x30,
+0x82, 0x02, 0x32, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x44, 0xaf, 0xb0, 0x80, 0xd6, 0xa3,
+0x27, 0xba, 0x89, 0x30, 0x39, 0x86, 0x2e, 0xf8, 0x40, 0x6b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x3f, 0x31, 0x24, 0x30, 0x22, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x1b, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x53, 0x69,
+0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f,
+0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e, 0x44, 0x53, 0x54, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x58, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x30,
+0x30, 0x39, 0x33, 0x30, 0x32, 0x31, 0x31, 0x32, 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x30,
+0x39, 0x33, 0x30, 0x31, 0x34, 0x30, 0x31, 0x31, 0x35, 0x5a, 0x30, 0x3f, 0x31, 0x24, 0x30, 0x22,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1b, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x53,
+0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43,
+0x6f, 0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e, 0x44, 0x53, 0x54,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x58, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
+0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdf, 0xaf, 0xe9, 0x97,
+0x50, 0x08, 0x83, 0x57, 0xb4, 0xcc, 0x62, 0x65, 0xf6, 0x90, 0x82, 0xec, 0xc7, 0xd3, 0x2c, 0x6b,
+0x30, 0xca, 0x5b, 0xec, 0xd9, 0xc3, 0x7d, 0xc7, 0x40, 0xc1, 0x18, 0x14, 0x8b, 0xe0, 0xe8, 0x33,
+0x76, 0x49, 0x2a, 0xe3, 0x3f, 0x21, 0x49, 0x93, 0xac, 0x4e, 0x0e, 0xaf, 0x3e, 0x48, 0xcb, 0x65,
+0xee, 0xfc, 0xd3, 0x21, 0x0f, 0x65, 0xd2, 0x2a, 0xd9, 0x32, 0x8f, 0x8c, 0xe5, 0xf7, 0x77, 0xb0,
+0x12, 0x7b, 0xb5, 0x95, 0xc0, 0x89, 0xa3, 0xa9, 0xba, 0xed, 0x73, 0x2e, 0x7a, 0x0c, 0x06, 0x32,
+0x83, 0xa2, 0x7e, 0x8a, 0x14, 0x30, 0xcd, 0x11, 0xa0, 0xe1, 0x2a, 0x38, 0xb9, 0x79, 0x0a, 0x31,
+0xfd, 0x50, 0xbd, 0x80, 0x65, 0xdf, 0xb7, 0x51, 0x63, 0x83, 0xc8, 0xe2, 0x88, 0x61, 0xea, 0x4b,
+0x61, 0x81, 0xec, 0x52, 0x6b, 0xb9, 0xa2, 0xe2, 0x4b, 0x1a, 0x28, 0x9f, 0x48, 0xa3, 0x9e, 0x0c,
+0xda, 0x09, 0x8e, 0x3e, 0x17, 0x2e, 0x1e, 0xdd, 0x20, 0xdf, 0x5b, 0xc6, 0x2a, 0x8a, 0xab, 0x2e,
+0xbd, 0x70, 0xad, 0xc5, 0x0b, 0x1a, 0x25, 0x90, 0x74, 0x72, 0xc5, 0x7b, 0x6a, 0xab, 0x34, 0xd6,
+0x30, 0x89, 0xff, 0xe5, 0x68, 0x13, 0x7b, 0x54, 0x0b, 0xc8, 0xd6, 0xae, 0xec, 0x5a, 0x9c, 0x92,
+0x1e, 0x3d, 0x64, 0xb3, 0x8c, 0xc6, 0xdf, 0xbf, 0xc9, 0x41, 0x70, 0xec, 0x16, 0x72, 0xd5, 0x26,
+0xec, 0x38, 0x55, 0x39, 0x43, 0xd0, 0xfc, 0xfd, 0x18, 0x5c, 0x40, 0xf1, 0x97, 0xeb, 0xd5, 0x9a,
+0x9b, 0x8d, 0x1d, 0xba, 0xda, 0x25, 0xb9, 0xc6, 0xd8, 0xdf, 0xc1, 0x15, 0x02, 0x3a, 0xab, 0xda,
+0x6e, 0xf1, 0x3e, 0x2e, 0xf5, 0x5c, 0x08, 0x9c, 0x3c, 0xd6, 0x83, 0x69, 0xe4, 0x10, 0x9b, 0x19,
+0x2a, 0xb6, 0x29, 0x57, 0xe3, 0xe5, 0x3d, 0x9b, 0x9f, 0xf0, 0x02, 0x5d, 0x02, 0x03, 0x01, 0x00,
+0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+0x14, 0xc4, 0xa7, 0xb1, 0xa4, 0x7b, 0x2c, 0x71, 0xfa, 0xdb, 0xe1, 0x4b, 0x90, 0x75, 0xff, 0xc4,
+0x15, 0x60, 0x85, 0x89, 0x10, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x1a, 0x2c, 0x9b, 0x17, 0x00, 0x5c,
+0xa9, 0x1e, 0xee, 0x28, 0x66, 0x37, 0x3a, 0xbf, 0x83, 0xc7, 0x3f, 0x4b, 0xc3, 0x09, 0xa0, 0x95,
+0x20, 0x5d, 0xe3, 0xd9, 0x59, 0x44, 0xd2, 0x3e, 0x0d, 0x3e, 0xbd, 0x8a, 0x4b, 0xa0, 0x74, 0x1f,
+0xce, 0x10, 0x82, 0x9c, 0x74, 0x1a, 0x1d, 0x7e, 0x98, 0x1a, 0xdd, 0xcb, 0x13, 0x4b, 0xb3, 0x20,
+0x44, 0xe4, 0x91, 0xe9, 0xcc, 0xfc, 0x7d, 0xa5, 0xdb, 0x6a, 0xe5, 0xfe, 0xe6, 0xfd, 0xe0, 0x4e,
+0xdd, 0xb7, 0x00, 0x3a, 0xb5, 0x70, 0x49, 0xaf, 0xf2, 0xe5, 0xeb, 0x02, 0xf1, 0xd1, 0x02, 0x8b,
+0x19, 0xcb, 0x94, 0x3a, 0x5e, 0x48, 0xc4, 0x18, 0x1e, 0x58, 0x19, 0x5f, 0x1e, 0x02, 0x5a, 0xf0,
+0x0c, 0xf1, 0xb1, 0xad, 0xa9, 0xdc, 0x59, 0x86, 0x8b, 0x6e, 0xe9, 0x91, 0xf5, 0x86, 0xca, 0xfa,
+0xb9, 0x66, 0x33, 0xaa, 0x59, 0x5b, 0xce, 0xe2, 0xa7, 0x16, 0x73, 0x47, 0xcb, 0x2b, 0xcc, 0x99,
+0xb0, 0x37, 0x48, 0xcf, 0xe3, 0x56, 0x4b, 0xf5, 0xcf, 0x0f, 0x0c, 0x72, 0x32, 0x87, 0xc6, 0xf0,
+0x44, 0xbb, 0x53, 0x72, 0x6d, 0x43, 0xf5, 0x26, 0x48, 0x9a, 0x52, 0x67, 0xb7, 0x58, 0xab, 0xfe,
+0x67, 0x76, 0x71, 0x78, 0xdb, 0x0d, 0xa2, 0x56, 0x14, 0x13, 0x39, 0x24, 0x31, 0x85, 0xa2, 0xa8,
+0x02, 0x5a, 0x30, 0x47, 0xe1, 0xdd, 0x50, 0x07, 0xbc, 0x02, 0x09, 0x90, 0x00, 0xeb, 0x64, 0x63,
+0x60, 0x9b, 0x16, 0xbc, 0x88, 0xc9, 0x12, 0xe6, 0xd2, 0x7d, 0x91, 0x8b, 0xf9, 0x3d, 0x32, 0x8d,
+0x65, 0xb4, 0xe9, 0x7c, 0xb1, 0x57, 0x76, 0xea, 0xc5, 0xb6, 0x28, 0x39, 0xbf, 0x15, 0x65, 0x1c,
+0xc8, 0xf6, 0x77, 0x96, 0x6a, 0x0a, 0x8d, 0x77, 0x0b, 0xd8, 0x91, 0x0b, 0x04, 0x8e, 0x07, 0xdb,
+0x29, 0xb6, 0x0a, 0xee, 0x9d, 0x82, 0x35, 0x35, 0x10, 0x30, 0x82, 0x03, 0xe6, 0x30, 0x82, 0x02,
+0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x57, 0xcb, 0x33, 0x6f, 0xc2, 0x5c, 0x16, 0xe6,
+0x47, 0x16, 0x17, 0xe3, 0x90, 0x31, 0x68, 0xe0, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x18, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f,
+0x6e, 0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, 0x43, 0x2e, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x13, 0x27, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c, 0x75,
+0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30,
+0x36, 0x31, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x39,
+0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x62, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x18, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x53, 0x6f, 0x6c,
+0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x4c, 0x2e, 0x4c, 0x2e, 0x43, 0x2e, 0x31, 0x30, 0x30,
+0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x27, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
+0x53, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30,
+0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
+0xe4, 0xbc, 0x7e, 0x92, 0x30, 0x6d, 0xc6, 0xd8, 0x8e, 0x2b, 0x0b, 0xbc, 0x46, 0xce, 0xe0, 0x27,
+0x96, 0xde, 0xde, 0xf9, 0xfa, 0x12, 0xd3, 0x3c, 0x33, 0x73, 0xb3, 0x04, 0x2f, 0xbc, 0x71, 0x8c,
+0xe5, 0x9f, 0xb6, 0x22, 0x60, 0x3e, 0x5f, 0x5d, 0xce, 0x09, 0xff, 0x82, 0x0c, 0x1b, 0x9a, 0x51,
+0x50, 0x1a, 0x26, 0x89, 0xdd, 0xd5, 0x61, 0x5d, 0x19, 0xdc, 0x12, 0x0f, 0x2d, 0x0a, 0xa2, 0x43,
+0x5d, 0x17, 0xd0, 0x34, 0x92, 0x20, 0xea, 0x73, 0xcf, 0x38, 0x2c, 0x06, 0x26, 0x09, 0x7a, 0x72,
+0xf7, 0xfa, 0x50, 0x32, 0xf8, 0xc2, 0x93, 0xd3, 0x69, 0xa2, 0x23, 0xce, 0x41, 0xb1, 0xcc, 0xe4,
+0xd5, 0x1f, 0x36, 0xd1, 0x8a, 0x3a, 0xf8, 0x8c, 0x63, 0xe2, 0x14, 0x59, 0x69, 0xed, 0x0d, 0xd3,
+0x7f, 0x6b, 0xe8, 0xb8, 0x03, 0xe5, 0x4f, 0x6a, 0xe5, 0x98, 0x63, 0x69, 0x48, 0x05, 0xbe, 0x2e,
+0xff, 0x33, 0xb6, 0xe9, 0x97, 0x59, 0x69, 0xf8, 0x67, 0x19, 0xae, 0x93, 0x61, 0x96, 0x44, 0x15,
+0xd3, 0x72, 0xb0, 0x3f, 0xbc, 0x6a, 0x7d, 0xec, 0x48, 0x7f, 0x8d, 0xc3, 0xab, 0xaa, 0x71, 0x2b,
+0x53, 0x69, 0x41, 0x53, 0x34, 0xb5, 0xb0, 0xb9, 0xc5, 0x06, 0x0a, 0xc4, 0xb0, 0x45, 0xf5, 0x41,
+0x5d, 0x6e, 0x89, 0x45, 0x7b, 0x3d, 0x3b, 0x26, 0x8c, 0x74, 0xc2, 0xe5, 0xd2, 0xd1, 0x7d, 0xb2,
+0x11, 0xd4, 0xfb, 0x58, 0x32, 0x22, 0x9a, 0x80, 0xc9, 0xdc, 0xfd, 0x0c, 0xe9, 0x7f, 0x5e, 0x03,
+0x97, 0xce, 0x3b, 0x00, 0x14, 0x87, 0x27, 0x70, 0x38, 0xa9, 0x8e, 0x6e, 0xb3, 0x27, 0x76, 0x98,
+0x51, 0xe0, 0x05, 0xe3, 0x21, 0xab, 0x1a, 0xd5, 0x85, 0x22, 0x3c, 0x29, 0xb5, 0x9a, 0x16, 0xc5,
+0x80, 0xa8, 0xf4, 0xbb, 0x6b, 0x30, 0x8f, 0x2f, 0x46, 0x02, 0xa2, 0xb1, 0x0c, 0x22, 0xe0, 0xd3,
+0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0x97, 0x30, 0x81, 0x94, 0x30, 0x1d, 0x06, 0x03, 0x55,
+0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x21, 0x30, 0xc9, 0xfb, 0x00, 0xd7, 0x4e, 0x98, 0xda, 0x87,
+0xaa, 0x2a, 0xd0, 0xa7, 0x2e, 0xb1, 0x40, 0x31, 0xa7, 0x4c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
+0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x52, 0x06, 0x03, 0x55,
+0x1d, 0x1f, 0x04, 0x4b, 0x30, 0x49, 0x30, 0x47, 0xa0, 0x45, 0xa0, 0x43, 0x86, 0x41, 0x68, 0x74,
+0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x6e, 0x65, 0x74, 0x73, 0x6f, 0x6c, 0x73,
+0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x53, 0x6f,
+0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x2e, 0x63, 0x72, 0x6c, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
+0x01, 0x01, 0x00, 0xbb, 0xae, 0x4b, 0xe7, 0xb7, 0x57, 0xeb, 0x7f, 0xaa, 0x2d, 0xb7, 0x73, 0x47,
+0x85, 0x6a, 0xc1, 0xe4, 0xa5, 0x1d, 0xe4, 0xe7, 0x3c, 0xe9, 0xf4, 0x59, 0x65, 0x77, 0xb5, 0x7a,
+0x5b, 0x5a, 0x8d, 0x25, 0x36, 0xe0, 0x7a, 0x97, 0x2e, 0x38, 0xc0, 0x57, 0x60, 0x83, 0x98, 0x06,
+0x83, 0x9f, 0xb9, 0x76, 0x7a, 0x6e, 0x50, 0xe0, 0xba, 0x88, 0x2c, 0xfc, 0x45, 0xcc, 0x18, 0xb0,
+0x99, 0x95, 0x51, 0x0e, 0xec, 0x1d, 0xb8, 0x88, 0xff, 0x87, 0x50, 0x1c, 0x82, 0xc2, 0xe3, 0xe0,
+0x32, 0x80, 0xbf, 0xa0, 0x0b, 0x47, 0xc8, 0xc3, 0x31, 0xef, 0x99, 0x67, 0x32, 0x80, 0x4f, 0x17,
+0x21, 0x79, 0x0c, 0x69, 0x5c, 0xde, 0x5e, 0x34, 0xae, 0x02, 0xb5, 0x26, 0xea, 0x50, 0xdf, 0x7f,
+0x18, 0x65, 0x2c, 0xc9, 0xf2, 0x63, 0xe1, 0xa9, 0x07, 0xfe, 0x7c, 0x71, 0x1f, 0x6b, 0x33, 0x24,
+0x6a, 0x1e, 0x05, 0xf7, 0x05, 0x68, 0xc0, 0x6a, 0x12, 0xcb, 0x2e, 0x5e, 0x61, 0xcb, 0xae, 0x28,
+0xd3, 0x7e, 0xc2, 0xb4, 0x66, 0x91, 0x26, 0x5f, 0x3c, 0x2e, 0x24, 0x5f, 0xcb, 0x58, 0x0f, 0xeb,
+0x28, 0xec, 0xaf, 0x11, 0x96, 0xf3, 0xdc, 0x7b, 0x6f, 0xc0, 0xa7, 0x88, 0xf2, 0x53, 0x77, 0xb3,
+0x60, 0x5e, 0xae, 0xae, 0x28, 0xda, 0x35, 0x2c, 0x6f, 0x34, 0x45, 0xd3, 0x26, 0xe1, 0xde, 0xec,
+0x5b, 0x4f, 0x27, 0x6b, 0x16, 0x7c, 0xbd, 0x44, 0x04, 0x18, 0x82, 0xb3, 0x89, 0x79, 0x17, 0x10,
+0x71, 0x3d, 0x7a, 0xa2, 0x16, 0x4e, 0xf5, 0x01, 0xcd, 0xa4, 0x6c, 0x65, 0x68, 0xa1, 0x49, 0x76,
+0x5c, 0x43, 0xc9, 0xd8, 0xbc, 0x36, 0x67, 0x6c, 0xa5, 0x94, 0xb5, 0xd4, 0xcc, 0xb9, 0xbd, 0x6a,
+0x35, 0x56, 0x21, 0xde, 0xd8, 0xc3, 0xeb, 0xfb, 0xcb, 0xa4, 0x60, 0x4c, 0xb0, 0x55, 0xa0, 0xa0,
+0x7b, 0x57, 0xb2, 0x30, 0x82, 0x05, 0x60, 0x30, 0x82, 0x03, 0x48, 0xa0, 0x03, 0x02, 0x01, 0x02,
+0x02, 0x14, 0x78, 0x58, 0x5f, 0x2e, 0xad, 0x2c, 0x19, 0x4b, 0xe3, 0x37, 0x07, 0x35, 0x34, 0x13,
+0x28, 0xb5, 0x96, 0xd4, 0x65, 0x93, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x48, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x42, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x51,
+0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31,
+0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64,
+0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x20, 0x47, 0x33, 0x30,
+0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x31, 0x31, 0x32, 0x31, 0x37, 0x32, 0x37, 0x34, 0x34, 0x5a,
+0x17, 0x0d, 0x34, 0x32, 0x30, 0x31, 0x31, 0x32, 0x31, 0x37, 0x32, 0x37, 0x34, 0x34, 0x5a, 0x30,
+0x48, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x4d, 0x31, 0x19,
+0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69,
+0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x13, 0x15, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f,
+0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x20, 0x47, 0x33, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f,
+0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xa0, 0xbe, 0x50, 0x10, 0x8e, 0xe9,
+0xf2, 0x6c, 0x40, 0xb4, 0x04, 0x9c, 0x85, 0xb9, 0x31, 0xca, 0xdc, 0x2d, 0xe4, 0x11, 0xa9, 0x04,
+0x3c, 0x1b, 0x55, 0xc1, 0xe7, 0x58, 0x30, 0x1d, 0x24, 0xb4, 0xc3, 0xef, 0x85, 0xde, 0x8c, 0x2c,
+0xe1, 0xc1, 0x3d, 0xdf, 0x82, 0xe6, 0x4f, 0xad, 0x47, 0x87, 0x6c, 0xec, 0x5b, 0x49, 0xc1, 0x4a,
+0xd5, 0xbb, 0x8f, 0xec, 0x87, 0xac, 0x7f, 0x82, 0x9a, 0x86, 0xec, 0x3d, 0x03, 0x99, 0x52, 0x01,
+0xd2, 0x35, 0x9e, 0xac, 0xda, 0xf0, 0x53, 0xc9, 0x66, 0x3c, 0xd4, 0xac, 0x02, 0x01, 0xda, 0x24,
+0xd3, 0x3b, 0xa8, 0x02, 0x46, 0xaf, 0xa4, 0x1c, 0xe3, 0xf8, 0x73, 0x58, 0x76, 0xb7, 0xf6, 0x0e,
+0x90, 0x0d, 0xb5, 0xf0, 0xcf, 0xcc, 0xfa, 0xf9, 0xc6, 0x4c, 0xe5, 0xc3, 0x86, 0x30, 0x0a, 0x8d,
+0x17, 0x7e, 0x35, 0xeb, 0xc5, 0xdf, 0xbb, 0x0e, 0x9c, 0xc0, 0x8d, 0x87, 0xe3, 0x88, 0x38, 0x85,
+0x67, 0xfa, 0x3e, 0xc7, 0xab, 0xe0, 0x13, 0x9c, 0x05, 0x18, 0x98, 0xcf, 0x93, 0xf5, 0xb1, 0x92,
+0xb4, 0xfc, 0x23, 0xd3, 0xcf, 0xd5, 0xc4, 0x27, 0x49, 0xe0, 0x9e, 0x3c, 0x9b, 0x08, 0xa3, 0x8b,
+0x5d, 0x2a, 0x21, 0xe0, 0xfc, 0x39, 0xaa, 0x53, 0xda, 0x7d, 0x7e, 0xcf, 0x1a, 0x09, 0x53, 0xbc,
+0x5d, 0x05, 0x04, 0xcf, 0xa1, 0x4a, 0x8f, 0x8b, 0x76, 0x82, 0x0d, 0xa1, 0xf8, 0xd2, 0xc7, 0x14,
+0x77, 0x5b, 0x90, 0x36, 0x07, 0x81, 0x9b, 0x3e, 0x06, 0xfa, 0x52, 0x5e, 0x63, 0xc5, 0xa6, 0x00,
+0xfe, 0xa5, 0xe9, 0x52, 0x1b, 0x52, 0xb5, 0x92, 0x39, 0x72, 0x03, 0x09, 0x62, 0xbd, 0xb0, 0x60,
+0x16, 0x6e, 0xa6, 0xdd, 0x25, 0xc2, 0x03, 0x66, 0xdd, 0xf3, 0x04, 0xd1, 0x40, 0xe2, 0x4e, 0x8b,
+0x86, 0xf4, 0x6f, 0xe5, 0x83, 0xa0, 0x27, 0x84, 0x5e, 0x04, 0xc1, 0xf5, 0x90, 0xbd, 0x30, 0x3d,
+0xc4, 0xef, 0xa8, 0x69, 0xbc, 0x38, 0x9b, 0xa4, 0xa4, 0x96, 0xd1, 0x62, 0xda, 0x69, 0xc0, 0x01,
+0x96, 0xae, 0xcb, 0xc4, 0x51, 0x34, 0xea, 0x0c, 0xaa, 0xff, 0x21, 0x8e, 0x59, 0x8f, 0x4a, 0x5c,
+0xe4, 0x61, 0x9a, 0xa7, 0xd2, 0xe9, 0x2a, 0x78, 0x8d, 0x51, 0x3d, 0x3a, 0x15, 0xee, 0xa2, 0x59,
+0x8e, 0xa9, 0x5c, 0xde, 0xc5, 0xf9, 0x90, 0x22, 0xe5, 0x88, 0x45, 0x71, 0xdd, 0x91, 0x99, 0x6c,
+0x7a, 0x9f, 0x3d, 0x3d, 0x98, 0x7c, 0x5e, 0xf6, 0xbe, 0x16, 0x68, 0xa0, 0x5e, 0xae, 0x0b, 0x23,
+0xfc, 0x5a, 0x0f, 0xaa, 0x22, 0x76, 0x2d, 0xc9, 0xa1, 0x10, 0x1d, 0xe4, 0xd3, 0x44, 0x23, 0x90,
+0x88, 0x9f, 0xc6, 0x2a, 0xe6, 0xd7, 0xf5, 0x9a, 0xb3, 0x58, 0x1e, 0x2f, 0x30, 0x89, 0x08, 0x1b,
+0x54, 0xa2, 0xb5, 0x98, 0x23, 0xec, 0x08, 0x77, 0x1c, 0x95, 0x5d, 0x61, 0xd1, 0xcb, 0x89, 0x9c,
+0x5f, 0xa2, 0x4a, 0x91, 0x9a, 0xef, 0x21, 0xaa, 0x49, 0x16, 0x08, 0xa8, 0xbd, 0x61, 0x28, 0x31,
+0xc9, 0x74, 0xad, 0x85, 0xf6, 0xd9, 0xc5, 0xb1, 0x8b, 0xd1, 0xe5, 0x10, 0x32, 0x4d, 0x5f, 0x8b,
+0x20, 0x3a, 0x3c, 0x49, 0x1f, 0x33, 0x85, 0x59, 0x0d, 0xdb, 0xcb, 0x09, 0x75, 0x43, 0x69, 0x73,
+0xfb, 0x6b, 0x71, 0x7d, 0xf0, 0xdf, 0xc4, 0x4c, 0x7d, 0xc6, 0xa3, 0x2e, 0xc8, 0x95, 0x79, 0xcb,
+0x73, 0xa2, 0x8e, 0x4e, 0x4d, 0x24, 0xfb, 0x5e, 0xe4, 0x04, 0xbe, 0x72, 0x1b, 0xa6, 0x27, 0x2d,
+0x49, 0x5a, 0x99, 0x7a, 0xd7, 0x5c, 0x09, 0x20, 0xb7, 0x7f, 0x94, 0xb9, 0x4f, 0xf1, 0x0d, 0x1c,
+0x5e, 0x88, 0x42, 0x1b, 0x11, 0xb7, 0xe7, 0x91, 0xdb, 0x9e, 0x6c, 0xf4, 0x6a, 0xdf, 0x8c, 0x06,
+0x98, 0x03, 0xad, 0xcc, 0x28, 0xef, 0xa5, 0x47, 0xf3, 0x53, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa3,
+0x97, 0xd6, 0xf3, 0x5e, 0xa2, 0x10, 0xe1, 0xab, 0x45, 0x9f, 0x3c, 0x17, 0x64, 0x3c, 0xee, 0x01,
+0x70, 0x9c, 0xcc, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x18, 0xfa, 0x5b, 0x75, 0xfc, 0x3e, 0x7a, 0xc7, 0x5f,
+0x77, 0xc7, 0xca, 0xdf, 0xcf, 0x5f, 0xc3, 0x12, 0xc4, 0x40, 0x5d, 0xd4, 0x32, 0xaa, 0xb8, 0x6a,
+0xd7, 0xd5, 0x15, 0x15, 0x46, 0x98, 0x23, 0xa5, 0xe6, 0x90, 0x5b, 0x18, 0x99, 0x4c, 0xe3, 0xad,
+0x42, 0xa3, 0x82, 0x31, 0x36, 0x88, 0xcd, 0xe9, 0xfb, 0xc4, 0x04, 0x96, 0x48, 0x8b, 0x01, 0xc7,
+0x8d, 0x01, 0xcf, 0x5b, 0x33, 0x06, 0x96, 0x46, 0x66, 0x74, 0x1d, 0x4f, 0xed, 0xc1, 0xb6, 0xb9,
+0xb4, 0x0d, 0x61, 0xcc, 0x63, 0x7e, 0xd7, 0x2e, 0x77, 0x8c, 0x96, 0x1c, 0x2a, 0x23, 0x68, 0x6b,
+0x85, 0x57, 0x76, 0x70, 0x33, 0x13, 0xfe, 0xe1, 0x4f, 0xa6, 0x23, 0x77, 0x18, 0xfa, 0x1a, 0x8c,
+0xe8, 0xbd, 0x65, 0xc9, 0xcf, 0x3f, 0xf4, 0xc9, 0x17, 0xdc, 0xeb, 0xc7, 0xbc, 0xc0, 0x04, 0x2e,
+0x2d, 0x46, 0x2f, 0x69, 0x66, 0xc3, 0x1b, 0x8f, 0xfe, 0xec, 0x3e, 0xd3, 0xca, 0x94, 0xbf, 0x76,
+0x0a, 0x25, 0x0d, 0xa9, 0x7b, 0x02, 0x1c, 0xa9, 0xd0, 0x3b, 0x5f, 0x0b, 0xc0, 0x81, 0x3a, 0x3d,
+0x64, 0xe1, 0xbf, 0xa7, 0x2d, 0x4e, 0xbd, 0x4d, 0xc4, 0xd8, 0x29, 0xc6, 0x22, 0x18, 0xd0, 0xc5,
+0xac, 0x72, 0x02, 0x82, 0x3f, 0xaa, 0x3a, 0xa2, 0x3a, 0x22, 0x97, 0x31, 0xdd, 0x08, 0x63, 0xc3,
+0x75, 0x14, 0xb9, 0x60, 0x28, 0x2d, 0x5b, 0x68, 0xe0, 0x16, 0xa9, 0x66, 0x82, 0x23, 0x51, 0xf5,
+0xeb, 0x53, 0xd8, 0x31, 0x9b, 0x7b, 0xe9, 0xb7, 0x9d, 0x4b, 0xeb, 0x88, 0x16, 0xcf, 0xf9, 0x5d,
+0x38, 0x8a, 0x49, 0x30, 0x8f, 0xed, 0xf1, 0xeb, 0x19, 0xf4, 0x77, 0x1a, 0x31, 0x18, 0x4d, 0x67,
+0x54, 0x6c, 0x2f, 0x6f, 0x65, 0xf9, 0xdb, 0x3d, 0xec, 0x21, 0xec, 0x5e, 0xf4, 0xf4, 0x8b, 0xca,
+0x60, 0x65, 0x54, 0xd1, 0x71, 0x64, 0xf4, 0xf9, 0xa6, 0xa3, 0x81, 0x33, 0x36, 0x33, 0x71, 0xf0,
+0xa4, 0x78, 0x5f, 0x4e, 0xad, 0x83, 0x21, 0xde, 0x34, 0x49, 0x8d, 0xe8, 0x59, 0xac, 0x9d, 0xf2,
+0x76, 0x5a, 0x36, 0xf2, 0x13, 0xf4, 0xaf, 0xe0, 0x09, 0xc7, 0x61, 0x2a, 0x6c, 0xf7, 0xe0, 0x9d,
+0xae, 0xbb, 0x86, 0x4a, 0x28, 0x6f, 0x2e, 0xee, 0xb4, 0x79, 0xcd, 0x90, 0x33, 0xc3, 0xb3, 0x76,
+0xfa, 0xf5, 0xf0, 0x6c, 0x9d, 0x01, 0x90, 0xfa, 0x9e, 0x90, 0xf6, 0x9c, 0x72, 0xcf, 0x47, 0xda,
+0xc3, 0x1f, 0xe4, 0x35, 0x20, 0x53, 0xf2, 0x54, 0xd1, 0xdf, 0x61, 0x83, 0xa6, 0x02, 0xe2, 0x25,
+0x38, 0xde, 0x85, 0x32, 0x2d, 0x5e, 0x73, 0x90, 0x52, 0x5d, 0x42, 0xc4, 0xce, 0x3d, 0x4b, 0xe1,
+0xf9, 0x19, 0x84, 0x1d, 0xd5, 0xa2, 0x50, 0xcc, 0x41, 0xfb, 0x41, 0x14, 0xc3, 0xbd, 0xd6, 0xc9,
+0x5a, 0xa3, 0x63, 0x66, 0x02, 0x80, 0xbd, 0x05, 0x3a, 0x3b, 0x47, 0x9c, 0xec, 0x00, 0x26, 0x4c,
+0xf5, 0x88, 0x51, 0xbf, 0xa8, 0x23, 0x7f, 0x18, 0x07, 0xb0, 0x0b, 0xed, 0x8b, 0x26, 0xa1, 0x64,
+0xd3, 0x61, 0x4a, 0xeb, 0x5c, 0x9f, 0xde, 0xb3, 0xaf, 0x67, 0x03, 0xb3, 0x1f, 0xdd, 0x6d, 0x5d,
+0x69, 0x68, 0x69, 0xab, 0x5e, 0x3a, 0xec, 0x7c, 0x69, 0xbc, 0xc7, 0x3b, 0x85, 0x4e, 0x9e, 0x15,
+0xb9, 0xb4, 0x15, 0x4f, 0xc3, 0x95, 0x7a, 0x58, 0xd7, 0xc9, 0x6c, 0xe9, 0x6c, 0xb9, 0xf3, 0x29,
+0x63, 0x5e, 0xb4, 0x2c, 0xf0, 0x2d, 0x3d, 0xed, 0x5a, 0x65, 0xe0, 0xa9, 0x5b, 0x40, 0xc2, 0x48,
+0x99, 0x81, 0x6d, 0x9e, 0x1f, 0x06, 0x2a, 0x3c, 0x12, 0xb4, 0x8b, 0x0f, 0x9b, 0xa2, 0x24, 0xf0,
+0xa6, 0x8d, 0xd6, 0x7a, 0xe0, 0x4b, 0xb6, 0x64, 0x96, 0x63, 0x95, 0x84, 0xc2, 0x4a, 0xcd, 0x1c,
+0x2e, 0x24, 0x87, 0x33, 0x60, 0xe5, 0xc3, 0x30, 0x82, 0x05, 0xb7, 0x30, 0x82, 0x03, 0x9f, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x05, 0x09, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x42, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x10, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65,
+0x64, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x51, 0x75, 0x6f, 0x56,
+0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x1e,
+0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x32, 0x34, 0x31, 0x38, 0x32, 0x37, 0x30, 0x30, 0x5a, 0x17,
+0x0d, 0x33, 0x31, 0x31, 0x31, 0x32, 0x34, 0x31, 0x38, 0x32, 0x33, 0x33, 0x33, 0x5a, 0x30, 0x45,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x4d, 0x31, 0x19, 0x30,
+0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73,
+0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x12, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
+0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0x9a, 0x18, 0xca, 0x4b, 0x94, 0x0d, 0x00, 0x2d, 0xaf, 0x03,
+0x29, 0x8a, 0xf0, 0x0f, 0x81, 0xc8, 0xae, 0x4c, 0x19, 0x85, 0x1d, 0x08, 0x9f, 0xab, 0x29, 0x44,
+0x85, 0xf3, 0x2f, 0x81, 0xad, 0x32, 0x1e, 0x90, 0x46, 0xbf, 0xa3, 0x86, 0x26, 0x1a, 0x1e, 0xfe,
+0x7e, 0x1c, 0x18, 0x3a, 0x5c, 0x9c, 0x60, 0x17, 0x2a, 0x3a, 0x74, 0x83, 0x33, 0x30, 0x7d, 0x61,
+0x54, 0x11, 0xcb, 0xed, 0xab, 0xe0, 0xe6, 0xd2, 0xa2, 0x7e, 0xf5, 0x6b, 0x6f, 0x18, 0xb7, 0x0a,
+0x0b, 0x2d, 0xfd, 0xe9, 0x3e, 0xef, 0x0a, 0xc6, 0xb3, 0x10, 0xe9, 0xdc, 0xc2, 0x46, 0x17, 0xf8,
+0x5d, 0xfd, 0xa4, 0xda, 0xff, 0x9e, 0x49, 0x5a, 0x9c, 0xe6, 0x33, 0xe6, 0x24, 0x96, 0xf7, 0x3f,
+0xba, 0x5b, 0x2b, 0x1c, 0x7a, 0x35, 0xc2, 0xd6, 0x67, 0xfe, 0xab, 0x66, 0x50, 0x8b, 0x6d, 0x28,
+0x60, 0x2b, 0xef, 0xd7, 0x60, 0xc3, 0xc7, 0x93, 0xbc, 0x8d, 0x36, 0x91, 0xf3, 0x7f, 0xf8, 0xdb,
+0x11, 0x13, 0xc4, 0x9c, 0x77, 0x76, 0xc1, 0xae, 0xb7, 0x02, 0x6a, 0x81, 0x7a, 0xa9, 0x45, 0x83,
+0xe2, 0x05, 0xe6, 0xb9, 0x56, 0xc1, 0x94, 0x37, 0x8f, 0x48, 0x71, 0x63, 0x22, 0xec, 0x17, 0x65,
+0x07, 0x95, 0x8a, 0x4b, 0xdf, 0x8f, 0xc6, 0x5a, 0x0a, 0xe5, 0xb0, 0xe3, 0x5f, 0x5e, 0x6b, 0x11,
+0xab, 0x0c, 0xf9, 0x85, 0xeb, 0x44, 0xe9, 0xf8, 0x04, 0x73, 0xf2, 0xe9, 0xfe, 0x5c, 0x98, 0x8c,
+0xf5, 0x73, 0xaf, 0x6b, 0xb4, 0x7e, 0xcd, 0xd4, 0x5c, 0x02, 0x2b, 0x4c, 0x39, 0xe1, 0xb2, 0x95,
+0x95, 0x2d, 0x42, 0x87, 0xd7, 0xd5, 0xb3, 0x90, 0x43, 0xb7, 0x6c, 0x13, 0xf1, 0xde, 0xdd, 0xf6,
+0xc4, 0xf8, 0x89, 0x3f, 0xd1, 0x75, 0xf5, 0x92, 0xc3, 0x91, 0xd5, 0x8a, 0x88, 0xd0, 0x90, 0xec,
+0xdc, 0x6d, 0xde, 0x89, 0xc2, 0x65, 0x71, 0x96, 0x8b, 0x0d, 0x03, 0xfd, 0x9c, 0xbf, 0x5b, 0x16,
+0xac, 0x92, 0xdb, 0xea, 0xfe, 0x79, 0x7c, 0xad, 0xeb, 0xaf, 0xf7, 0x16, 0xcb, 0xdb, 0xcd, 0x25,
+0x2b, 0xe5, 0x1f, 0xfb, 0x9a, 0x9f, 0xe2, 0x51, 0xcc, 0x3a, 0x53, 0x0c, 0x48, 0xe6, 0x0e, 0xbd,
+0xc9, 0xb4, 0x76, 0x06, 0x52, 0xe6, 0x11, 0x13, 0x85, 0x72, 0x63, 0x03, 0x04, 0xe0, 0x04, 0x36,
+0x2b, 0x20, 0x19, 0x02, 0xe8, 0x74, 0xa7, 0x1f, 0xb6, 0xc9, 0x56, 0x66, 0xf0, 0x75, 0x25, 0xdc,
+0x67, 0xc1, 0x0e, 0x61, 0x60, 0x88, 0xb3, 0x3e, 0xd1, 0xa8, 0xfc, 0xa3, 0xda, 0x1d, 0xb0, 0xd1,
+0xb1, 0x23, 0x54, 0xdf, 0x44, 0x76, 0x6d, 0xed, 0x41, 0xd8, 0xc1, 0xb2, 0x22, 0xb6, 0x53, 0x1c,
+0xdf, 0x35, 0x1d, 0xdc, 0xa1, 0x77, 0x2a, 0x31, 0xe4, 0x2d, 0xf5, 0xe5, 0xe5, 0xdb, 0xc8, 0xe0,
+0xff, 0xe5, 0x80, 0xd7, 0x0b, 0x63, 0xa0, 0xff, 0x33, 0xa1, 0x0f, 0xba, 0x2c, 0x15, 0x15, 0xea,
+0x97, 0xb3, 0xd2, 0xa2, 0xb5, 0xbe, 0xf2, 0x8c, 0x96, 0x1e, 0x1a, 0x8f, 0x1d, 0x6c, 0xa4, 0x61,
+0x37, 0xb9, 0x86, 0x73, 0x33, 0xd7, 0x97, 0x96, 0x9e, 0x23, 0x7d, 0x82, 0xa4, 0x4c, 0x81, 0xe2,
+0xa1, 0xd1, 0xba, 0x67, 0x5f, 0x95, 0x07, 0xa3, 0x27, 0x11, 0xee, 0x16, 0x10, 0x7b, 0xbc, 0x45,
+0x4a, 0x4c, 0xb2, 0x04, 0xd2, 0xab, 0xef, 0xd5, 0xfd, 0x0c, 0x51, 0xce, 0x50, 0x6a, 0x08, 0x31,
+0xf9, 0x91, 0xda, 0x0c, 0x8f, 0x64, 0x5c, 0x03, 0xc3, 0x3a, 0x8b, 0x20, 0x3f, 0x6e, 0x8d, 0x67,
+0x3d, 0x3a, 0xd6, 0xfe, 0x7d, 0x5b, 0x88, 0xc9, 0x5e, 0xfb, 0xcc, 0x61, 0xdc, 0x8b, 0x33, 0x77,
+0xd3, 0x44, 0x32, 0x35, 0x09, 0x62, 0x04, 0x92, 0x16, 0x10, 0xd8, 0x9e, 0x27, 0x47, 0xfb, 0x3b,
+0x21, 0xe3, 0xf8, 0xeb, 0x1d, 0x5b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xb0, 0x30, 0x81,
+0xad, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x1a, 0x84, 0x62, 0xbc, 0x48, 0x4c,
+0x33, 0x25, 0x04, 0xd4, 0xee, 0xd0, 0xf6, 0x03, 0xc4, 0x19, 0x46, 0xd1, 0x94, 0x6b, 0x30, 0x6e,
+0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x67, 0x30, 0x65, 0x80, 0x14, 0x1a, 0x84, 0x62, 0xbc, 0x48,
+0x4c, 0x33, 0x25, 0x04, 0xd4, 0xee, 0xd0, 0xf6, 0x03, 0xc4, 0x19, 0x46, 0xd1, 0x94, 0x6b, 0xa1,
+0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x42, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x51, 0x75, 0x6f,
+0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x1b, 0x30,
+0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x82, 0x02, 0x05, 0x09, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x02,
+0x01, 0x00, 0x3e, 0x0a, 0x16, 0x4d, 0x9f, 0x06, 0x5b, 0xa8, 0xae, 0x71, 0x5d, 0x2f, 0x05, 0x2f,
+0x67, 0xe6, 0x13, 0x45, 0x83, 0xc4, 0x36, 0xf6, 0xf3, 0xc0, 0x26, 0x0c, 0x0d, 0xb5, 0x47, 0x64,
+0x5d, 0xf8, 0xb4, 0x72, 0xc9, 0x46, 0xa5, 0x03, 0x18, 0x27, 0x55, 0x89, 0x78, 0x7d, 0x76, 0xea,
+0x96, 0x34, 0x80, 0x17, 0x20, 0xdc, 0xe7, 0x83, 0xf8, 0x8d, 0xfc, 0x07, 0xb8, 0xda, 0x5f, 0x4d,
+0x2e, 0x67, 0xb2, 0x84, 0xfd, 0xd9, 0x44, 0xfc, 0x77, 0x50, 0x81, 0xe6, 0x7c, 0xb4, 0xc9, 0x0d,
+0x0b, 0x72, 0x53, 0xf8, 0x76, 0x07, 0x07, 0x41, 0x47, 0x96, 0x0c, 0xfb, 0xe0, 0x82, 0x26, 0x93,
+0x55, 0x8c, 0xfe, 0x22, 0x1f, 0x60, 0x65, 0x7c, 0x5f, 0xe7, 0x26, 0xb3, 0xf7, 0x32, 0x90, 0x98,
+0x50, 0xd4, 0x37, 0x71, 0x55, 0xf6, 0x92, 0x21, 0x78, 0xf7, 0x95, 0x79, 0xfa, 0xf8, 0x2d, 0x26,
+0x87, 0x66, 0x56, 0x30, 0x77, 0xa6, 0x37, 0x78, 0x33, 0x52, 0x10, 0x58, 0xae, 0x3f, 0x61, 0x8e,
+0xf2, 0x6a, 0xb1, 0xef, 0x18, 0x7e, 0x4a, 0x59, 0x63, 0xca, 0x8d, 0xa2, 0x56, 0xd5, 0xa7, 0x2f,
+0xbc, 0x56, 0x1f, 0xcf, 0x39, 0xc1, 0xe2, 0xfb, 0x0a, 0xa8, 0x15, 0x2c, 0x7d, 0x4d, 0x7a, 0x63,
+0xc6, 0x6c, 0x97, 0x44, 0x3c, 0xd2, 0x6f, 0xc3, 0x4a, 0x17, 0x0a, 0xf8, 0x90, 0xd2, 0x57, 0xa2,
+0x19, 0x51, 0xa5, 0x2d, 0x97, 0x41, 0xda, 0x07, 0x4f, 0xa9, 0x50, 0xda, 0x90, 0x8d, 0x94, 0x46,
+0xe1, 0x3e, 0xf0, 0x94, 0xfd, 0x10, 0x00, 0x38, 0xf5, 0x3b, 0xe8, 0x40, 0xe1, 0xb4, 0x6e, 0x56,
+0x1a, 0x20, 0xcc, 0x6f, 0x58, 0x8d, 0xed, 0x2e, 0x45, 0x8f, 0xd6, 0xe9, 0x93, 0x3f, 0xe7, 0xb1,
+0x2c, 0xdf, 0x3a, 0xd6, 0x22, 0x8c, 0xdc, 0x84, 0xbb, 0x22, 0x6f, 0xd0, 0xf8, 0xe4, 0xc6, 0x39,
+0xe9, 0x04, 0x88, 0x3c, 0xc3, 0xba, 0xeb, 0x55, 0x7a, 0x6d, 0x80, 0x99, 0x24, 0xf5, 0x6c, 0x01,
+0xfb, 0xf8, 0x97, 0xb0, 0x94, 0x5b, 0xeb, 0xfd, 0xd2, 0x6f, 0xf1, 0x77, 0x68, 0x0d, 0x35, 0x64,
+0x23, 0xac, 0xb8, 0x55, 0xa1, 0x03, 0xd1, 0x4d, 0x42, 0x19, 0xdc, 0xf8, 0x75, 0x59, 0x56, 0xa3,
+0xf9, 0xa8, 0x49, 0x79, 0xf8, 0xaf, 0x0e, 0xb9, 0x11, 0xa0, 0x7c, 0xb7, 0x6a, 0xed, 0x34, 0xd0,
+0xb6, 0x26, 0x62, 0x38, 0x1a, 0x87, 0x0c, 0xf8, 0xe8, 0xfd, 0x2e, 0xd3, 0x90, 0x7f, 0x07, 0x91,
+0x2a, 0x1d, 0xd6, 0x7e, 0x5c, 0x85, 0x83, 0x99, 0xb0, 0x38, 0x08, 0x3f, 0xe9, 0x5e, 0xf9, 0x35,
+0x07, 0xe4, 0xc9, 0x62, 0x6e, 0x57, 0x7f, 0xa7, 0x50, 0x95, 0xf7, 0xba, 0xc8, 0x9b, 0xe6, 0x8e,
+0xa2, 0x01, 0xc5, 0xd6, 0x66, 0xbf, 0x79, 0x61, 0xf3, 0x3c, 0x1c, 0xe1, 0xb9, 0x82, 0x5c, 0x5d,
+0xa0, 0xc3, 0xe9, 0xd8, 0x48, 0xbd, 0x19, 0xa2, 0x11, 0x14, 0x19, 0x6e, 0xb2, 0x86, 0x1b, 0x68,
+0x3e, 0x48, 0x37, 0x1a, 0x88, 0xb7, 0x5d, 0x96, 0x5e, 0x9c, 0xc7, 0xef, 0x27, 0x62, 0x08, 0xe2,
+0x91, 0x19, 0x5c, 0xd2, 0xf1, 0x21, 0xdd, 0xba, 0x17, 0x42, 0x82, 0x97, 0x71, 0x81, 0x53, 0x31,
+0xa9, 0x9f, 0xf6, 0x7d, 0x62, 0xbf, 0x72, 0xe1, 0xa3, 0x93, 0x1d, 0xcc, 0x8a, 0x26, 0x5a, 0x09,
+0x38, 0xd0, 0xce, 0xd7, 0x0d, 0x80, 0x16, 0xb4, 0x78, 0xa5, 0x3a, 0x87, 0x4c, 0x8d, 0x8a, 0xa5,
+0xd5, 0x46, 0x97, 0xf2, 0x2c, 0x10, 0xb9, 0xbc, 0x54, 0x22, 0xc0, 0x01, 0x50, 0x69, 0x43, 0x9e,
+0xf4, 0xb2, 0xef, 0x6d, 0xf8, 0xec, 0xda, 0xf1, 0xe3, 0xb1, 0xef, 0xdf, 0x91, 0x8f, 0x54, 0x2a,
+0x0b, 0x25, 0xc1, 0x26, 0x19, 0xc4, 0x52, 0x10, 0x05, 0x65, 0xd5, 0x82, 0x10, 0xea, 0xc2, 0x31,
+0xcd, 0x2e, 0x30, 0x82, 0x05, 0x60, 0x30, 0x82, 0x03, 0x48, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+0x14, 0x44, 0x57, 0x34, 0x24, 0x5b, 0x81, 0x89, 0x9b, 0x35, 0xf2, 0xce, 0xb8, 0x2b, 0x3b, 0x5b,
+0xa7, 0x26, 0xf0, 0x75, 0x28, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x0b, 0x05, 0x00, 0x30, 0x48, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x42, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x51, 0x75,
+0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x1e,
+0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69,
+0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x47, 0x33, 0x30, 0x1e,
+0x17, 0x0d, 0x31, 0x32, 0x30, 0x31, 0x31, 0x32, 0x31, 0x38, 0x35, 0x39, 0x33, 0x32, 0x5a, 0x17,
+0x0d, 0x34, 0x32, 0x30, 0x31, 0x31, 0x32, 0x31, 0x38, 0x35, 0x39, 0x33, 0x32, 0x5a, 0x30, 0x48,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x4d, 0x31, 0x19, 0x30,
+0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73,
+0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x15, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x47, 0x33, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00,
+0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xa1, 0xae, 0x25, 0xb2, 0x01, 0x18, 0xdc,
+0x57, 0x88, 0x3f, 0x46, 0xeb, 0xf9, 0xaf, 0xe2, 0xeb, 0x23, 0x71, 0xe2, 0x9a, 0xd1, 0x61, 0x66,
+0x21, 0x5f, 0xaa, 0xaf, 0x27, 0x51, 0xe5, 0x6e, 0x1b, 0x16, 0xd4, 0x2d, 0x7d, 0x50, 0xb0, 0x53,
+0x77, 0xbd, 0x78, 0x3a, 0x60, 0xe2, 0x64, 0x02, 0x9b, 0x7c, 0x86, 0x9b, 0xd6, 0x1a, 0x8e, 0xad,
+0xff, 0x1f, 0x15, 0x7f, 0xd5, 0x95, 0x1e, 0x12, 0xcb, 0xe6, 0x14, 0x84, 0x04, 0xc1, 0xdf, 0x36,
+0xb3, 0x16, 0x9f, 0x8a, 0xe3, 0xc9, 0xdb, 0x98, 0x34, 0xce, 0xd8, 0x33, 0x17, 0x28, 0x46, 0xfc,
+0xa7, 0xc9, 0xf0, 0xd2, 0xb4, 0xd5, 0x4d, 0x09, 0x72, 0x49, 0xf9, 0xf2, 0x87, 0xe3, 0xa9, 0xda,
+0x7d, 0xa1, 0x7d, 0x6b, 0xb2, 0x3a, 0x25, 0xa9, 0x6d, 0x52, 0x44, 0xac, 0xf8, 0xbe, 0x6e, 0xfb,
+0xdc, 0xa6, 0x73, 0x91, 0x90, 0x61, 0xa6, 0x03, 0x14, 0x20, 0xf2, 0xe7, 0x87, 0xa3, 0x88, 0xad,
+0xad, 0xa0, 0x8c, 0xff, 0xa6, 0x0b, 0x25, 0x52, 0x25, 0xe7, 0x16, 0x01, 0xd5, 0xcb, 0xb8, 0x35,
+0x81, 0x0c, 0xa3, 0x3b, 0xf0, 0xe1, 0xe1, 0xfc, 0x5a, 0x5d, 0xce, 0x80, 0x71, 0x6d, 0xf8, 0x49,
+0xab, 0x3e, 0x3b, 0xba, 0xb8, 0xd7, 0x80, 0x01, 0xfb, 0xa5, 0xeb, 0x5b, 0xb3, 0xc5, 0x5e, 0x60,
+0x2a, 0x31, 0xa0, 0xaf, 0x37, 0xe8, 0x20, 0x3a, 0x9f, 0xa8, 0x32, 0x2c, 0x0c, 0xcc, 0x09, 0x1d,
+0xd3, 0x9e, 0x8e, 0x5d, 0xbc, 0x4c, 0x98, 0xee, 0xc5, 0x1a, 0x68, 0x7b, 0xec, 0x53, 0xa6, 0xe9,
+0x14, 0x35, 0xa3, 0xdf, 0xcd, 0x80, 0x9f, 0x0c, 0x48, 0xfb, 0x1c, 0xf4, 0xf1, 0xbf, 0x4a, 0xb8,
+0xfa, 0xd5, 0x8c, 0x71, 0x4a, 0xc7, 0x1f, 0xad, 0xfe, 0x41, 0x9a, 0xb3, 0x83, 0x5d, 0xf2, 0x84,
+0x56, 0xef, 0xa5, 0x57, 0x43, 0xce, 0x29, 0xad, 0x8c, 0xab, 0x55, 0xbf, 0xc4, 0xfb, 0x5b, 0x01,
+0xdd, 0x23, 0x21, 0xa1, 0x58, 0x00, 0x8e, 0xc3, 0xd0, 0x6a, 0x13, 0xed, 0x13, 0xe3, 0x12, 0x2b,
+0x80, 0xdc, 0x67, 0xe6, 0x95, 0xb2, 0xcd, 0x1e, 0x22, 0x6e, 0x2a, 0xf8, 0x41, 0xd4, 0xf2, 0xca,
+0x14, 0x07, 0x8d, 0x8a, 0x55, 0x12, 0xc6, 0x69, 0xf5, 0xb8, 0x86, 0x68, 0x2f, 0x53, 0x5e, 0xb0,
+0xd2, 0xaa, 0x21, 0xc1, 0x98, 0xe6, 0x30, 0xe3, 0x67, 0x55, 0xc7, 0x9b, 0x6e, 0xac, 0x19, 0xa8,
+0x55, 0xa6, 0x45, 0x06, 0xd0, 0x23, 0x3a, 0xdb, 0xeb, 0x65, 0x5d, 0x2a, 0x11, 0x11, 0xf0, 0x3b,
+0x4f, 0xca, 0x6d, 0xf4, 0x34, 0xc4, 0x71, 0xe4, 0xff, 0x00, 0x5a, 0xf6, 0x5c, 0xae, 0x23, 0x60,
+0x85, 0x73, 0xf1, 0xe4, 0x10, 0xb1, 0x25, 0xae, 0xd5, 0x92, 0xbb, 0x13, 0xc1, 0x0c, 0xe0, 0x39,
+0xda, 0xb4, 0x39, 0x57, 0xb5, 0xab, 0x35, 0xaa, 0x72, 0x21, 0x3b, 0x83, 0x35, 0xe7, 0x31, 0xdf,
+0x7a, 0x21, 0x6e, 0xb8, 0x32, 0x08, 0x7d, 0x1d, 0x32, 0x91, 0x15, 0x4a, 0x62, 0x72, 0xcf, 0xe3,
+0x77, 0xa1, 0xbc, 0xd5, 0x11, 0x1b, 0x76, 0x01, 0x67, 0x08, 0xe0, 0x41, 0x0b, 0xc3, 0xeb, 0x15,
+0x6e, 0xf8, 0xa4, 0x19, 0xd9, 0xa2, 0xab, 0xaf, 0xe2, 0x27, 0x52, 0x56, 0x2b, 0x02, 0x8a, 0x2c,
+0x14, 0x24, 0xf9, 0xbf, 0x42, 0x02, 0xbf, 0x26, 0xc8, 0xc6, 0x8f, 0xe0, 0x6e, 0x38, 0x7d, 0x53,
+0x2d, 0xe5, 0xed, 0x98, 0xb3, 0x95, 0x63, 0x68, 0x7f, 0xf9, 0x35, 0xf4, 0xdf, 0x88, 0xc5, 0x60,
+0x35, 0x92, 0xc0, 0x7c, 0x69, 0x1c, 0x61, 0x95, 0x16, 0xd0, 0xeb, 0xde, 0x0b, 0xaf, 0x3e, 0x04,
+0x10, 0x45, 0x65, 0x58, 0x50, 0x38, 0xaf, 0x48, 0xf2, 0x59, 0xb6, 0x16, 0xf2, 0x3c, 0x0d, 0x90,
+0x02, 0xc6, 0x70, 0x2e, 0x01, 0xad, 0x3c, 0x15, 0xd7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42,
+0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xed, 0xe7,
+0x6f, 0x76, 0x5a, 0xbf, 0x60, 0xec, 0x49, 0x5b, 0xc6, 0xa5, 0x77, 0xbb, 0x72, 0x16, 0x71, 0x9b,
+0xc4, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x91, 0xdf, 0x80, 0x3f, 0x43, 0x09, 0x7e, 0x71, 0xc2, 0xf7,
+0xeb, 0xb3, 0x88, 0x8f, 0xe1, 0x51, 0xb2, 0xbc, 0x3d, 0x75, 0xf9, 0x28, 0x5d, 0xc8, 0xbc, 0x99,
+0x9b, 0x7b, 0x5d, 0xaa, 0xe5, 0xca, 0xe1, 0x0a, 0xf7, 0xe8, 0xb2, 0xd3, 0x9f, 0xdd, 0x67, 0x31,
+0x7e, 0xba, 0x01, 0xaa, 0xc7, 0x6a, 0x41, 0x3b, 0x90, 0xd4, 0x08, 0x5c, 0xb2, 0x60, 0x6a, 0x90,
+0xf0, 0xc8, 0xce, 0x03, 0x62, 0xf9, 0x8b, 0xed, 0xfb, 0x6e, 0x2a, 0xdc, 0x06, 0x4d, 0x3c, 0x29,
+0x0f, 0x89, 0x16, 0x8a, 0x58, 0x4c, 0x48, 0x0f, 0xe8, 0x84, 0x61, 0xea, 0x3c, 0x72, 0xa6, 0x77,
+0xe4, 0x42, 0xae, 0x88, 0xa3, 0x43, 0x58, 0x79, 0x7e, 0xae, 0xca, 0xa5, 0x53, 0x0d, 0xa9, 0x3d,
+0x70, 0xbd, 0x20, 0x19, 0x61, 0xa4, 0x6c, 0x38, 0xfc, 0x43, 0x32, 0xe1, 0xc1, 0x47, 0xff, 0xf8,
+0xec, 0xf1, 0x11, 0x22, 0x32, 0x96, 0x9c, 0xc2, 0xf6, 0x5b, 0x69, 0x96, 0x7b, 0x20, 0x0c, 0x43,
+0x41, 0x9a, 0x5b, 0xf6, 0x59, 0x19, 0x88, 0xde, 0x55, 0x88, 0x37, 0x51, 0x0b, 0x78, 0x5c, 0x0a,
+0x1e, 0xa3, 0x42, 0xfd, 0xc7, 0x9d, 0x88, 0x0f, 0xc0, 0xf2, 0x78, 0x02, 0x24, 0x54, 0x93, 0xaf,
+0x89, 0x87, 0x88, 0xc9, 0x4a, 0x80, 0x1d, 0xea, 0xd0, 0x6e, 0x3e, 0x61, 0x2e, 0x36, 0xbb, 0x35,
+0x0e, 0x27, 0x96, 0xfd, 0x66, 0x34, 0x3b, 0x61, 0x72, 0x73, 0xf1, 0x16, 0x5c, 0x47, 0x06, 0x54,
+0x49, 0x00, 0x7a, 0x58, 0x12, 0xb0, 0x0a, 0xef, 0x85, 0xfd, 0xb1, 0xb8, 0x33, 0x75, 0x6a, 0x93,
+0x1c, 0x12, 0xe6, 0x60, 0x5e, 0x6f, 0x1d, 0x7f, 0xc9, 0x1f, 0x23, 0xcb, 0x84, 0x61, 0x9f, 0x1e,
+0x82, 0x44, 0xf9, 0x5f, 0xad, 0x62, 0x55, 0x24, 0x9a, 0x52, 0x98, 0xed, 0x51, 0xe7, 0xa1, 0x7e,
+0x97, 0x3a, 0xe6, 0x2f, 0x1f, 0x11, 0xda, 0x53, 0x80, 0x2c, 0x85, 0x9e, 0xab, 0x35, 0x10, 0xdb,
+0x22, 0x5f, 0x6a, 0xc5, 0x5e, 0x97, 0x53, 0xf2, 0x32, 0x02, 0x09, 0x30, 0xa3, 0x58, 0xf0, 0x0d,
+0x01, 0xd5, 0x72, 0xc6, 0xb1, 0x7c, 0x69, 0x7b, 0xc3, 0xf5, 0x36, 0x45, 0xcc, 0x61, 0x6e, 0x5e,
+0x4c, 0x94, 0xc5, 0x5e, 0xae, 0xe8, 0x0e, 0x5e, 0x8b, 0xbf, 0xf7, 0xcd, 0xe0, 0xed, 0xa1, 0x0e,
+0x1b, 0x33, 0xee, 0x54, 0x18, 0xfe, 0x0f, 0xbe, 0xef, 0x7e, 0x84, 0x6b, 0x43, 0xe3, 0x70, 0x98,
+0xdb, 0x5d, 0x75, 0xb2, 0x0d, 0x59, 0x07, 0x85, 0x15, 0x23, 0x39, 0xd6, 0xf1, 0xdf, 0xa9, 0x26,
+0x0f, 0xd6, 0x48, 0xc7, 0xb3, 0xa6, 0x22, 0xf5, 0x33, 0x37, 0x5a, 0x95, 0x47, 0x9f, 0x7b, 0xba,
+0x18, 0x15, 0x6f, 0xff, 0xd6, 0x14, 0x64, 0x83, 0x49, 0xd2, 0x0a, 0x67, 0x21, 0xdb, 0x0f, 0x35,
+0x63, 0x60, 0x28, 0x22, 0xe3, 0xb1, 0x95, 0x83, 0xcd, 0x85, 0xa6, 0xdd, 0x2f, 0x0f, 0xe7, 0x67,
+0x52, 0x6e, 0xbb, 0x2f, 0x85, 0x7c, 0xf5, 0x4a, 0x73, 0xe7, 0xc5, 0x3e, 0xc0, 0xbd, 0x21, 0x12,
+0x05, 0x3f, 0xfc, 0xb7, 0x03, 0x49, 0x02, 0x5b, 0xc8, 0x25, 0xe6, 0xe2, 0x54, 0x38, 0xf5, 0x79,
+0x87, 0x8c, 0x1d, 0x53, 0xb2, 0x4e, 0x85, 0x7b, 0x06, 0x38, 0xc7, 0x2c, 0xf8, 0xf8, 0xb0, 0x72,
+0x8d, 0x25, 0xe5, 0x77, 0x52, 0xf4, 0x03, 0x1c, 0x48, 0xa6, 0x50, 0x5f, 0x88, 0x20, 0x30, 0x6e,
+0xf2, 0x82, 0x43, 0xab, 0x3d, 0x97, 0x84, 0xe7, 0x53, 0xfb, 0x21, 0xc1, 0x4f, 0x0f, 0x22, 0x9a,
+0x86, 0xb8, 0x59, 0x2a, 0xf6, 0x47, 0x3d, 0x19, 0x88, 0x2d, 0xe8, 0x85, 0xe1, 0x9e, 0xec, 0x85,
+0x08, 0x6a, 0xb1, 0x6c, 0x34, 0xc9, 0x1d, 0xec, 0x48, 0x2b, 0x3b, 0x78, 0xed, 0x66, 0xc4, 0x8e,
+0x79, 0x69, 0x83, 0xde, 0x7f, 0x8c, 0x30, 0x82, 0x06, 0x9d, 0x30, 0x82, 0x04, 0x85, 0xa0, 0x03,
+0x02, 0x01, 0x02, 0x02, 0x02, 0x05, 0xc6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x42, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10,
+0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64,
+0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x51, 0x75, 0x6f, 0x56, 0x61,
+0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x30, 0x1e, 0x17,
+0x0d, 0x30, 0x36, 0x31, 0x31, 0x32, 0x34, 0x31, 0x39, 0x31, 0x31, 0x32, 0x33, 0x5a, 0x17, 0x0d,
+0x33, 0x31, 0x31, 0x31, 0x32, 0x34, 0x31, 0x39, 0x30, 0x36, 0x34, 0x34, 0x5a, 0x30, 0x45, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x4d, 0x31, 0x19, 0x30, 0x17,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20,
+0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x12, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x43, 0x41, 0x20, 0x33, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a,
+0x02, 0x82, 0x02, 0x01, 0x00, 0xcc, 0x57, 0x42, 0x16, 0x54, 0x9c, 0xe6, 0x98, 0xd3, 0xd3, 0x4d,
+0xee, 0xfe, 0xed, 0xc7, 0x9f, 0x43, 0x39, 0x4a, 0x65, 0xb3, 0xe8, 0x16, 0x88, 0x34, 0xdb, 0x0d,
+0x59, 0x91, 0x74, 0xcf, 0x92, 0xb8, 0x04, 0x40, 0xad, 0x02, 0x4b, 0x31, 0xab, 0xbc, 0x8d, 0x91,
+0x68, 0xd8, 0x20, 0x0e, 0x1a, 0x01, 0xe2, 0x1a, 0x7b, 0x4e, 0x17, 0x5d, 0xe2, 0x8a, 0xb7, 0x3f,
+0x99, 0x1a, 0xcd, 0xeb, 0x61, 0xab, 0xc2, 0x65, 0xa6, 0x1f, 0xb7, 0xb7, 0xbd, 0xb7, 0x8f, 0xfc,
+0xfd, 0x70, 0x8f, 0x0b, 0xa0, 0x67, 0xbe, 0x01, 0xa2, 0x59, 0xcf, 0x71, 0xe6, 0x0f, 0x29, 0x76,
+0xff, 0xb1, 0x56, 0x79, 0x45, 0x2b, 0x1f, 0x9e, 0x7a, 0x54, 0xe8, 0xa3, 0x29, 0x35, 0x68, 0xa4,
+0x01, 0x4f, 0x0f, 0xa4, 0x2e, 0x37, 0xef, 0x1b, 0xbf, 0xe3, 0x8f, 0x10, 0xa8, 0x72, 0xab, 0x58,
+0x57, 0xe7, 0x54, 0x86, 0xc8, 0xc9, 0xf3, 0x5b, 0xda, 0x2c, 0xda, 0x5d, 0x8e, 0x6e, 0x3c, 0xa3,
+0x3e, 0xda, 0xfb, 0x82, 0xe5, 0xdd, 0xf2, 0x5c, 0xb2, 0x05, 0x33, 0x6f, 0x8a, 0x36, 0xce, 0xd0,
+0x13, 0x4e, 0xff, 0xbf, 0x4a, 0x0c, 0x34, 0x4c, 0xa6, 0xc3, 0x21, 0xbd, 0x50, 0x04, 0x55, 0xeb,
+0xb1, 0xbb, 0x9d, 0xfb, 0x45, 0x1e, 0x64, 0x15, 0xde, 0x55, 0x01, 0x8c, 0x02, 0x76, 0xb5, 0xcb,
+0xa1, 0x3f, 0x42, 0x69, 0xbc, 0x2f, 0xbd, 0x68, 0x43, 0x16, 0x56, 0x89, 0x2a, 0x37, 0x61, 0x91,
+0xfd, 0xa6, 0xae, 0x4e, 0xc0, 0xcb, 0x14, 0x65, 0x94, 0x37, 0x4b, 0x92, 0x06, 0xef, 0x04, 0xd0,
+0xc8, 0x9c, 0x88, 0xdb, 0x0b, 0x7b, 0x81, 0xaf, 0xb1, 0x3d, 0x2a, 0xc4, 0x65, 0x3a, 0x78, 0xb6,
+0xee, 0xdc, 0x80, 0xb1, 0xd2, 0xd3, 0x99, 0x9c, 0x3a, 0xee, 0x6b, 0x5a, 0x6b, 0xb3, 0x8d, 0xb7,
+0xd5, 0xce, 0x9c, 0xc2, 0xbe, 0xa5, 0x4b, 0x2f, 0x16, 0xb1, 0x9e, 0x68, 0x3b, 0x06, 0x6f, 0xae,
+0x7d, 0x9f, 0xf8, 0xde, 0xec, 0xcc, 0x29, 0xa7, 0x98, 0xa3, 0x25, 0x43, 0x2f, 0xef, 0xf1, 0x5f,
+0x26, 0xe1, 0x88, 0x4d, 0xf8, 0x5e, 0x6e, 0xd7, 0xd9, 0x14, 0x6e, 0x19, 0x33, 0x69, 0xa7, 0x3b,
+0x84, 0x89, 0x93, 0xc4, 0x53, 0x55, 0x13, 0xa1, 0x51, 0x78, 0x40, 0xf8, 0xb8, 0xc9, 0xa2, 0xee,
+0x7b, 0xba, 0x52, 0x42, 0x83, 0x9e, 0x14, 0xed, 0x05, 0x52, 0x5a, 0x59, 0x56, 0xa7, 0x97, 0xfc,
+0x9d, 0x3f, 0x0a, 0x29, 0xd8, 0xdc, 0x4f, 0x91, 0x0e, 0x13, 0xbc, 0xde, 0x95, 0xa4, 0xdf, 0x8b,
+0x99, 0xbe, 0xac, 0x9b, 0x33, 0x88, 0xef, 0xb5, 0x81, 0xaf, 0x1b, 0xc6, 0x22, 0x53, 0xc8, 0xf6,
+0xc7, 0xee, 0x97, 0x14, 0xb0, 0xc5, 0x7c, 0x78, 0x52, 0xc8, 0xf0, 0xce, 0x6e, 0x77, 0x60, 0x84,
+0xa6, 0xe9, 0x2a, 0x76, 0x20, 0xed, 0x58, 0x01, 0x17, 0x30, 0x93, 0xe9, 0x1a, 0x8b, 0xe0, 0x73,
+0x63, 0xd9, 0x6a, 0x92, 0x94, 0x49, 0x4e, 0xb4, 0xad, 0x4a, 0x85, 0xc4, 0xa3, 0x22, 0x30, 0xfc,
+0x09, 0xed, 0x68, 0x22, 0x73, 0xa6, 0x88, 0x0c, 0x55, 0x21, 0x58, 0xc5, 0xe1, 0x3a, 0x9f, 0x2a,
+0xdd, 0xca, 0xe1, 0x90, 0xe0, 0xd9, 0x73, 0xab, 0x6c, 0x80, 0xb8, 0xe8, 0x0b, 0x64, 0x93, 0xa0,
+0x9c, 0x8c, 0x19, 0xff, 0xb3, 0xd2, 0x0c, 0xec, 0x91, 0x26, 0x87, 0x8a, 0xb3, 0xa2, 0xe1, 0x70,
+0x8f, 0x2c, 0x0a, 0xe5, 0xcd, 0x6d, 0x68, 0x51, 0xeb, 0xda, 0x3f, 0x05, 0x7f, 0x8b, 0x32, 0xe6,
+0x13, 0x5c, 0x6b, 0xfe, 0x5f, 0x40, 0xe2, 0x22, 0xc8, 0xb4, 0xb4, 0x64, 0x4f, 0xd6, 0xba, 0x7d,
+0x48, 0x3e, 0xa8, 0x69, 0x0c, 0xd7, 0xbb, 0x86, 0x71, 0xc9, 0x73, 0xb8, 0x3f, 0x3b, 0x9d, 0x25,
+0x4b, 0xda, 0xff, 0x40, 0xeb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x95, 0x30, 0x82,
+0x01, 0x91, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+0x01, 0x01, 0xff, 0x30, 0x81, 0xe1, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x81, 0xd9, 0x30, 0x81,
+0xd6, 0x30, 0x81, 0xd3, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xbe, 0x58, 0x00, 0x03, 0x30,
+0x81, 0xc5, 0x30, 0x81, 0x93, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30,
+0x81, 0x86, 0x1a, 0x81, 0x83, 0x41, 0x6e, 0x79, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20,
+0x74, 0x68, 0x69, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x65, 0x73, 0x20, 0x61, 0x63, 0x63,
+0x65, 0x70, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51,
+0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20,
+0x33, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x50, 0x6f,
+0x6c, 0x69, 0x63, 0x79, 0x20, 0x2f, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+0x74, 0x69, 0x6f, 0x6e, 0x20, 0x50, 0x72, 0x61, 0x63, 0x74, 0x69, 0x63, 0x65, 0x20, 0x53, 0x74,
+0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x30, 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+0x05, 0x07, 0x02, 0x01, 0x16, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+0x2e, 0x71, 0x75, 0x6f, 0x76, 0x61, 0x64, 0x69, 0x73, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e,
+0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf2,
+0xc0, 0x13, 0xe0, 0x82, 0x43, 0x3e, 0xfb, 0xee, 0x2f, 0x67, 0x32, 0x96, 0x35, 0x5c, 0xdb, 0xb8,
+0xcb, 0x02, 0xd0, 0x30, 0x6e, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x67, 0x30, 0x65, 0x80, 0x14,
+0xf2, 0xc0, 0x13, 0xe0, 0x82, 0x43, 0x3e, 0xfb, 0xee, 0x2f, 0x67, 0x32, 0x96, 0x35, 0x5c, 0xdb,
+0xb8, 0xcb, 0x02, 0xd0, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x13, 0x10, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74,
+0x65, 0x64, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x51, 0x75, 0x6f,
+0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x82,
+0x02, 0x05, 0xc6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x4f, 0xad, 0xa0, 0x2c, 0x4c, 0xfa, 0xc0, 0xf2, 0x6f,
+0xf7, 0x66, 0x55, 0xab, 0x23, 0x34, 0xee, 0xe7, 0x29, 0xda, 0xc3, 0x5b, 0xb6, 0xb0, 0x83, 0xd9,
+0xd0, 0xd0, 0xe2, 0x21, 0xfb, 0xf3, 0x60, 0xa7, 0x3b, 0x5d, 0x60, 0x53, 0x27, 0xa2, 0x9b, 0xf6,
+0x08, 0x22, 0x2a, 0xe7, 0xbf, 0xa0, 0x72, 0xe5, 0x9c, 0x24, 0x6a, 0x31, 0xb1, 0x90, 0x7a, 0x27,
+0xdb, 0x84, 0x11, 0x89, 0x27, 0xa6, 0x77, 0x5a, 0x38, 0xd7, 0xbf, 0xac, 0x86, 0xfc, 0xee, 0x5d,
+0x83, 0xbc, 0x06, 0xc6, 0xd1, 0x77, 0x6b, 0x0f, 0x6d, 0x24, 0x2f, 0x4b, 0x7a, 0x6c, 0xa7, 0x07,
+0x96, 0xca, 0xe3, 0x84, 0x9f, 0xad, 0x88, 0x8b, 0x1d, 0xab, 0x16, 0x8d, 0x5b, 0x66, 0x17, 0xd9,
+0x16, 0xf4, 0x8b, 0x80, 0xd2, 0xdd, 0xf8, 0xb2, 0x76, 0xc3, 0xfc, 0x38, 0x13, 0xaa, 0x0c, 0xde,
+0x42, 0x69, 0x2b, 0x6e, 0xf3, 0x3c, 0xeb, 0x80, 0x27, 0xdb, 0xf5, 0xa6, 0x44, 0x0d, 0x9f, 0x5a,
+0x55, 0x59, 0x0b, 0xd5, 0x0d, 0x52, 0x48, 0xc5, 0xae, 0x9f, 0xf2, 0x2f, 0x80, 0xc5, 0xea, 0x32,
+0x50, 0x35, 0x12, 0x97, 0x2e, 0xc1, 0xe1, 0xff, 0xf1, 0x23, 0x88, 0x51, 0x38, 0x9f, 0xf2, 0x66,
+0x56, 0x76, 0xe7, 0x0f, 0x51, 0x97, 0xa5, 0x52, 0x0c, 0x4d, 0x49, 0x51, 0x95, 0x36, 0x3d, 0xbf,
+0xa2, 0x4b, 0x0c, 0x10, 0x1d, 0x86, 0x99, 0x4c, 0xaa, 0xf3, 0x72, 0x11, 0x93, 0xe4, 0xea, 0xf6,
+0x9b, 0xda, 0xa8, 0x5d, 0xa7, 0x4d, 0xb7, 0x9e, 0x02, 0xae, 0x73, 0x00, 0xc8, 0xda, 0x23, 0x03,
+0xe8, 0xf9, 0xea, 0x19, 0x74, 0x62, 0x00, 0x94, 0xcb, 0x22, 0x20, 0xbe, 0x94, 0xa7, 0x59, 0xb5,
+0x82, 0x6a, 0xbe, 0x99, 0x79, 0x7a, 0xa9, 0xf2, 0x4a, 0x24, 0x52, 0xf7, 0x74, 0xfd, 0xba, 0x4e,
+0xe6, 0xa8, 0x1d, 0x02, 0x6e, 0xb1, 0x0d, 0x80, 0x44, 0xc1, 0xae, 0xd3, 0x23, 0x37, 0x5f, 0xbb,
+0x85, 0x7c, 0x2b, 0x92, 0x2e, 0xe8, 0x7e, 0xa5, 0x8b, 0xdd, 0x99, 0xe1, 0xbf, 0x27, 0x6f, 0x2d,
+0x5d, 0xaa, 0x7b, 0x87, 0xfe, 0x0a, 0xdd, 0x4b, 0xfc, 0x8e, 0xf5, 0x26, 0xe4, 0x6e, 0x70, 0x42,
+0x6e, 0x33, 0xec, 0x31, 0x9e, 0x7b, 0x93, 0xc1, 0xe4, 0xc9, 0x69, 0x1a, 0x3d, 0xc0, 0x6b, 0x4e,
+0x22, 0x6d, 0xee, 0xab, 0x58, 0x4d, 0xc6, 0xd0, 0x41, 0xc1, 0x2b, 0xea, 0x4f, 0x12, 0x87, 0x5e,
+0xeb, 0x45, 0xd8, 0x6c, 0xf5, 0x98, 0x02, 0xd3, 0xa0, 0xd8, 0x55, 0x8a, 0x06, 0x99, 0x19, 0xa2,
+0xa0, 0x77, 0xd1, 0x30, 0x9e, 0xac, 0xcc, 0x75, 0xee, 0x83, 0xf5, 0xb0, 0x62, 0x39, 0xcf, 0x6c,
+0x57, 0xe2, 0x4c, 0xd2, 0x91, 0x0b, 0x0e, 0x75, 0x28, 0x1b, 0x9a, 0xbf, 0xfd, 0x1a, 0x43, 0xf1,
+0xca, 0x77, 0xfb, 0x3b, 0x8f, 0x61, 0xb8, 0x69, 0x28, 0x16, 0x42, 0x04, 0x5e, 0x70, 0x2a, 0x1c,
+0x21, 0xd8, 0x8f, 0xe1, 0xbd, 0x23, 0x5b, 0x2d, 0x74, 0x40, 0x92, 0xd9, 0x63, 0x19, 0x0d, 0x73,
+0xdd, 0x69, 0xbc, 0x62, 0x47, 0xbc, 0xe0, 0x74, 0x2b, 0xb2, 0xeb, 0x7d, 0xbe, 0x41, 0x1b, 0xb5,
+0xc0, 0x46, 0xc5, 0xa1, 0x22, 0xcb, 0x5f, 0x4e, 0xc1, 0x28, 0x92, 0xde, 0x18, 0xba, 0xd5, 0x2a,
+0x28, 0xbb, 0x11, 0x8b, 0x17, 0x93, 0x98, 0x99, 0x60, 0x94, 0x5c, 0x23, 0xcf, 0x5a, 0x27, 0x97,
+0x5e, 0x0b, 0x05, 0x06, 0x93, 0x37, 0x1e, 0x3b, 0x69, 0x36, 0xeb, 0xa9, 0x9e, 0x61, 0x1d, 0x8f,
+0x32, 0xda, 0x8e, 0x0c, 0xd6, 0x74, 0x3e, 0x7b, 0x09, 0x24, 0xda, 0x01, 0x77, 0x47, 0xc4, 0x3b,
+0xcd, 0x34, 0x8c, 0x99, 0xf5, 0xca, 0xe1, 0x25, 0x61, 0x33, 0xb2, 0x59, 0x1b, 0xe2, 0x6e, 0xd7,
+0x37, 0x57, 0xb6, 0x0d, 0xa9, 0x12, 0xda, 0x30, 0x82, 0x05, 0x60, 0x30, 0x82, 0x03, 0x48, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x2e, 0xf5, 0x9b, 0x02, 0x28, 0xa7, 0xdb, 0x7a, 0xff, 0xd5,
+0xa3, 0xa9, 0xee, 0xbd, 0x03, 0xa0, 0xcf, 0x12, 0x6a, 0x1d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x48, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x10, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69,
+0x74, 0x65, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x51, 0x75,
+0x6f, 0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33,
+0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x31, 0x31, 0x32, 0x32, 0x30, 0x32,
+0x36, 0x33, 0x32, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x31, 0x31, 0x32, 0x32, 0x30, 0x32, 0x36,
+0x33, 0x32, 0x5a, 0x30, 0x48, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x42, 0x4d, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x51, 0x75, 0x6f,
+0x56, 0x61, 0x64, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x1e, 0x30,
+0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x51, 0x75, 0x6f, 0x56, 0x61, 0x64, 0x69, 0x73,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x33, 0x20, 0x47, 0x33, 0x30, 0x82, 0x02,
+0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb3, 0xcb,
+0x0e, 0x10, 0x67, 0x8e, 0xea, 0x14, 0x97, 0xa7, 0x32, 0x2a, 0x0a, 0x56, 0x36, 0x7f, 0x68, 0x4c,
+0xc7, 0xb3, 0x6f, 0x3a, 0x23, 0x14, 0x91, 0xff, 0x19, 0x7f, 0xa5, 0xca, 0xac, 0xee, 0xb3, 0x76,
+0x9d, 0x7a, 0xe9, 0x8b, 0x1b, 0xab, 0x6b, 0x31, 0xdb, 0xfa, 0x0b, 0x53, 0x4c, 0xaf, 0xc5, 0xa5,
+0x1a, 0x79, 0x3c, 0x8a, 0x4c, 0xff, 0xac, 0xdf, 0x25, 0xde, 0x4e, 0xd9, 0x82, 0x32, 0x0b, 0x44,
+0xde, 0xca, 0xdb, 0x8c, 0xac, 0xa3, 0x6e, 0x16, 0x83, 0x3b, 0xa6, 0x64, 0x4b, 0x32, 0x89, 0xfb,
+0x16, 0x16, 0x38, 0x7e, 0xeb, 0x43, 0xe2, 0xd3, 0x74, 0x4a, 0xc2, 0x62, 0x0a, 0x73, 0x0a, 0xdd,
+0x49, 0xb3, 0x57, 0xd2, 0xb0, 0x0a, 0x85, 0x9d, 0x71, 0x3c, 0xde, 0xa3, 0xcb, 0xc0, 0x32, 0xf3,
+0x01, 0x39, 0x20, 0x43, 0x1b, 0x35, 0xd1, 0x53, 0xb3, 0xb1, 0xee, 0xc5, 0x93, 0x69, 0x82, 0x3e,
+0x16, 0xb5, 0x28, 0x46, 0xa1, 0xde, 0xea, 0x89, 0x09, 0xed, 0x43, 0xb8, 0x05, 0x46, 0x8a, 0x86,
+0xf5, 0x59, 0x47, 0xbe, 0x1b, 0x6f, 0x01, 0x21, 0x10, 0xb9, 0xfd, 0xa9, 0xd2, 0x28, 0xca, 0x10,
+0x39, 0x09, 0xca, 0x13, 0x36, 0xcf, 0x9c, 0xad, 0xad, 0x40, 0x74, 0x79, 0x2b, 0x02, 0x3f, 0x34,
+0xff, 0xfa, 0x20, 0x69, 0x7d, 0xd3, 0xee, 0x61, 0xf5, 0xba, 0xb3, 0xe7, 0x30, 0xd0, 0x37, 0x23,
+0x86, 0x72, 0x61, 0x45, 0x29, 0x48, 0x59, 0x68, 0x6f, 0x77, 0xa6, 0x2e, 0x81, 0xbe, 0x07, 0x4d,
+0x6f, 0xaf, 0xce, 0xc4, 0x45, 0x13, 0x91, 0x14, 0x70, 0x06, 0x8f, 0x1f, 0x9f, 0xf8, 0x87, 0x69,
+0xb1, 0x0e, 0xef, 0xc3, 0x89, 0x19, 0xeb, 0xea, 0x1c, 0x61, 0xfc, 0x7a, 0x6c, 0x8a, 0xdc, 0xd6,
+0x03, 0x0b, 0x9e, 0x26, 0xba, 0x12, 0xdd, 0xd4, 0x54, 0x39, 0xab, 0x26, 0xa3, 0x33, 0xea, 0x75,
+0x81, 0xda, 0x2d, 0xcd, 0x0f, 0x4f, 0xe4, 0x03, 0xd1, 0xef, 0x15, 0x97, 0x1b, 0x6b, 0x90, 0xc5,
+0x02, 0x90, 0x93, 0x66, 0x02, 0x21, 0xb1, 0x47, 0xde, 0x8b, 0x9a, 0x4a, 0x80, 0xb9, 0x55, 0x8f,
+0xb5, 0xa2, 0x2f, 0xc0, 0xd6, 0x33, 0x67, 0xda, 0x7e, 0xc4, 0xa7, 0xb4, 0x04, 0x44, 0xeb, 0x47,
+0xfb, 0xe6, 0x58, 0xb9, 0xf7, 0x0c, 0xf0, 0x7b, 0x2b, 0xb1, 0xc0, 0x70, 0x29, 0xc3, 0x40, 0x62,
+0x2d, 0x3b, 0x48, 0x69, 0xdc, 0x23, 0x3c, 0x48, 0xeb, 0x7b, 0x09, 0x79, 0xa9, 0x6d, 0xda, 0xa8,
+0x30, 0x98, 0xcf, 0x80, 0x72, 0x03, 0x88, 0xa6, 0x5b, 0x46, 0xae, 0x72, 0x79, 0x7c, 0x08, 0x03,
+0x21, 0x65, 0xae, 0xb7, 0xe1, 0x1c, 0xa5, 0xb1, 0x2a, 0xa2, 0x31, 0xde, 0x66, 0x04, 0xf7, 0xc0,
+0x74, 0xe8, 0x71, 0xde, 0xff, 0x3d, 0x59, 0xcc, 0x96, 0x26, 0x12, 0x8b, 0x85, 0x95, 0x57, 0x1a,
+0xab, 0x6b, 0x75, 0x0b, 0x44, 0x3d, 0x11, 0x28, 0x3c, 0x7b, 0x61, 0xb7, 0xe2, 0x8f, 0x67, 0x4f,
+0xe5, 0xec, 0x3c, 0x4c, 0x60, 0x80, 0x69, 0x57, 0x38, 0x1e, 0x01, 0x5b, 0x8d, 0x55, 0xe8, 0xc7,
+0xdf, 0xc0, 0xcc, 0x77, 0x23, 0x34, 0x49, 0x75, 0x7c, 0xf6, 0x98, 0x11, 0xeb, 0x2d, 0xde, 0xed,
+0x41, 0x2e, 0x14, 0x05, 0x02, 0x7f, 0xe0, 0xfe, 0x20, 0xeb, 0x35, 0xe7, 0x11, 0xac, 0x22, 0xce,
+0x57, 0x3d, 0xde, 0xc9, 0x30, 0x6d, 0x10, 0x03, 0x85, 0xcd, 0xf1, 0xff, 0x8c, 0x16, 0xb5, 0xc1,
+0xb2, 0x3e, 0x88, 0x6c, 0x60, 0x7f, 0x90, 0x4f, 0x95, 0xf7, 0xf6, 0x2d, 0xad, 0x01, 0x39, 0x07,
+0x04, 0xfa, 0x75, 0x80, 0x7d, 0xbf, 0x49, 0x50, 0xed, 0xef, 0xc9, 0xc4, 0x7c, 0x1c, 0xeb, 0x80,
+0x7e, 0xdb, 0xb6, 0xd0, 0xdd, 0x13, 0xfe, 0xc9, 0xd3, 0x9c, 0xd7, 0xb2, 0x97, 0xa9, 0x02, 0x03,
+0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+0x16, 0x04, 0x14, 0xc6, 0x17, 0xd0, 0xbc, 0xa8, 0xea, 0x02, 0x43, 0xf2, 0x1b, 0x06, 0x99, 0x5d,
+0x2b, 0x90, 0x20, 0xb9, 0xd7, 0x9c, 0xe4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x34, 0x61, 0xd9, 0x56, 0xb5,
+0x12, 0x87, 0x55, 0x4d, 0xdd, 0xa3, 0x35, 0x31, 0x46, 0xbb, 0xa4, 0x07, 0x72, 0xbc, 0x5f, 0x61,
+0x62, 0xe8, 0xa5, 0xfb, 0x0b, 0x37, 0xb1, 0x3c, 0xb6, 0xb3, 0xfa, 0x29, 0x9d, 0x7f, 0x02, 0xf5,
+0xa4, 0xc9, 0xa8, 0x93, 0xb7, 0x7a, 0x71, 0x28, 0x69, 0x8f, 0x73, 0xe1, 0x52, 0x90, 0xda, 0xd5,
+0xbe, 0x3a, 0xe5, 0xb7, 0x76, 0x6a, 0x56, 0x80, 0x21, 0xdf, 0x5d, 0xe6, 0xe9, 0x3a, 0x9e, 0xe5,
+0x3e, 0xf6, 0xa2, 0x69, 0xc7, 0x2a, 0x0a, 0xb0, 0x18, 0x47, 0xdc, 0x20, 0x70, 0x7d, 0x52, 0xa3,
+0x3e, 0x59, 0x7c, 0xc1, 0xba, 0xc9, 0xc8, 0x15, 0x40, 0x61, 0xca, 0x72, 0xd6, 0x70, 0xac, 0xd2,
+0xb7, 0xf0, 0x1c, 0xe4, 0x86, 0x29, 0xf0, 0xce, 0xef, 0x68, 0x63, 0xd0, 0xb5, 0x20, 0x8a, 0x15,
+0x61, 0x9a, 0x7e, 0x86, 0x98, 0xb4, 0xc9, 0xc2, 0x76, 0xfb, 0xcc, 0xba, 0x30, 0x16, 0xcc, 0xa3,
+0x61, 0xc6, 0x74, 0x13, 0xe5, 0x6b, 0xef, 0xa3, 0x15, 0xea, 0x03, 0xfe, 0x13, 0x8b, 0x64, 0xe4,
+0xd3, 0xc1, 0xd2, 0xe8, 0x84, 0xfb, 0x49, 0xd1, 0x10, 0x4d, 0x79, 0x66, 0xeb, 0xaa, 0xfd, 0xf4,
+0x8d, 0x31, 0x1e, 0x70, 0x14, 0xad, 0xdc, 0xde, 0x67, 0x13, 0x4c, 0x81, 0x15, 0x61, 0xbc, 0xb7,
+0xd9, 0x91, 0x77, 0x71, 0x19, 0x81, 0x60, 0xbb, 0xf0, 0x58, 0xa5, 0xb5, 0x9c, 0x0b, 0xf7, 0x8f,
+0x22, 0x55, 0x27, 0xc0, 0x4b, 0x01, 0x6d, 0x3b, 0x99, 0x0d, 0xd4, 0x1d, 0x9b, 0x63, 0x67, 0x2f,
+0xd0, 0xee, 0x0d, 0xca, 0x66, 0xbc, 0x94, 0x4f, 0xa6, 0xad, 0xed, 0xfc, 0xee, 0x63, 0xac, 0x57,
+0x3f, 0x65, 0x25, 0xcf, 0xb2, 0x86, 0x8f, 0xd0, 0x08, 0xff, 0xb8, 0x76, 0x14, 0x6e, 0xde, 0xe5,
+0x27, 0xec, 0xab, 0x78, 0xb5, 0x53, 0xb9, 0xb6, 0x3f, 0xe8, 0x20, 0xf9, 0xd2, 0xa8, 0xbe, 0x61,
+0x46, 0xca, 0x87, 0x8c, 0x84, 0xf3, 0xf9, 0xf1, 0xa0, 0x68, 0x9b, 0x22, 0x1e, 0x81, 0x26, 0x9b,
+0x10, 0x04, 0x91, 0x71, 0xc0, 0x06, 0x1f, 0xdc, 0xa0, 0xd3, 0xb9, 0x56, 0xa7, 0xe3, 0x98, 0x2d,
+0x7f, 0x83, 0x9d, 0xdf, 0x8c, 0x2b, 0x9c, 0x32, 0x8e, 0x32, 0x94, 0xf0, 0x01, 0x3c, 0x22, 0x2a,
+0x9f, 0x43, 0xc2, 0x2e, 0xc3, 0x98, 0x39, 0x07, 0x38, 0x7b, 0xfc, 0x5e, 0x00, 0x42, 0x1f, 0xf3,
+0x32, 0x26, 0x79, 0x83, 0x84, 0xf6, 0xe5, 0xf0, 0xc1, 0x51, 0x12, 0xc0, 0x0b, 0x1e, 0x04, 0x23,
+0x0c, 0x54, 0xa5, 0x4c, 0x2f, 0x49, 0xc5, 0x4a, 0xd1, 0xb6, 0x6e, 0x60, 0x0d, 0x6b, 0xfc, 0x6b,
+0x8b, 0x85, 0x24, 0x64, 0xb7, 0x89, 0x0e, 0xab, 0x25, 0x47, 0x5b, 0x3c, 0xcf, 0x7e, 0x49, 0xbd,
+0xc7, 0xe9, 0x0a, 0xc6, 0xda, 0xf7, 0x7e, 0x0e, 0x17, 0x08, 0xd3, 0x48, 0x97, 0xd0, 0x71, 0x92,
+0xf0, 0x0f, 0x39, 0x3e, 0x34, 0x6a, 0x1c, 0x7d, 0xd8, 0xf2, 0x22, 0xae, 0xbb, 0x69, 0xf4, 0x33,
+0xb4, 0xa6, 0x48, 0x55, 0xd1, 0x0f, 0x0e, 0x26, 0xe8, 0xec, 0xb6, 0x0b, 0x2d, 0xa7, 0x85, 0x35,
+0xcd, 0xfd, 0x59, 0xc8, 0x9f, 0xd1, 0xcd, 0x3e, 0x5a, 0x29, 0x34, 0xb9, 0x3d, 0x84, 0xce, 0xb1,
+0x65, 0xd4, 0x59, 0x91, 0x91, 0x56, 0x75, 0x21, 0xc1, 0x77, 0x9e, 0xf9, 0x7a, 0xe1, 0x60, 0x9d,
+0xd3, 0xad, 0x04, 0x18, 0xf4, 0x7c, 0xeb, 0x5e, 0x93, 0x8f, 0x53, 0x4a, 0x22, 0x29, 0xf8, 0x48,
+0x2b, 0x3e, 0x4d, 0x86, 0xac, 0x5b, 0x7f, 0xcb, 0x06, 0x99, 0x59, 0x60, 0xd8, 0x58, 0x65, 0x95,
+0x8d, 0x44, 0xd1, 0xf7, 0x7f, 0x7e, 0x27, 0x7f, 0x7d, 0xae, 0x80, 0xf5, 0x07, 0x4c, 0xb6, 0x3e,
+0x9c, 0x71, 0x54, 0x99, 0x04, 0x4b, 0xfd, 0x58, 0xf9, 0x98, 0xf4, 0x30, 0x82, 0x03, 0x6d, 0x30,
+0x82, 0x02, 0x55, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x58, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x22, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
+0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+0x13, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x43, 0x41, 0x31, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x34, 0x30, 0x38, 0x30, 0x34,
+0x35, 0x36, 0x34, 0x37, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x34, 0x30, 0x38, 0x30, 0x34, 0x35,
+0x36, 0x34, 0x37, 0x5a, 0x30, 0x58, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x4a, 0x50, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x22, 0x4a, 0x61,
+0x70, 0x61, 0x6e, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+0x6e, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x53, 0x65, 0x63, 0x75, 0x72,
+0x65, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x31, 0x31, 0x30, 0x82,
+0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xfd,
+0x77, 0xaa, 0xa5, 0x1c, 0x90, 0x05, 0x3b, 0xcb, 0x4c, 0x9b, 0x33, 0x8b, 0x5a, 0x14, 0x45, 0xa4,
+0xe7, 0x90, 0x16, 0xd1, 0xdf, 0x57, 0xd2, 0x21, 0x10, 0xa4, 0x17, 0xfd, 0xdf, 0xac, 0xd6, 0x1f,
+0xa7, 0xe4, 0xdb, 0x7c, 0xf7, 0xec, 0xdf, 0xb8, 0x03, 0xda, 0x94, 0x58, 0xfd, 0x5d, 0x72, 0x7c,
+0x8c, 0x3f, 0x5f, 0x01, 0x67, 0x74, 0x15, 0x96, 0xe3, 0x02, 0x3c, 0x87, 0xdb, 0xae, 0xcb, 0x01,
+0x8e, 0xc2, 0xf3, 0x66, 0xc6, 0x85, 0x45, 0xf4, 0x02, 0xc6, 0x3a, 0xb5, 0x62, 0xb2, 0xaf, 0xfa,
+0x9c, 0xbf, 0xa4, 0xe6, 0xd4, 0x80, 0x30, 0x98, 0xf3, 0x0d, 0xb6, 0x93, 0x8f, 0xa9, 0xd4, 0xd8,
+0x36, 0xf2, 0xb0, 0xfc, 0x8a, 0xca, 0x2c, 0xa1, 0x15, 0x33, 0x95, 0x31, 0xda, 0xc0, 0x1b, 0xf2,
+0xee, 0x62, 0x99, 0x86, 0x63, 0x3f, 0xbf, 0xdd, 0x93, 0x2a, 0x83, 0xa8, 0x76, 0xb9, 0x13, 0x1f,
+0xb7, 0xce, 0x4e, 0x42, 0x85, 0x8f, 0x22, 0xe7, 0x2e, 0x1a, 0xf2, 0x95, 0x09, 0xb2, 0x05, 0xb5,
+0x44, 0x4e, 0x77, 0xa1, 0x20, 0xbd, 0xa9, 0xf2, 0x4e, 0x0a, 0x7d, 0x50, 0xad, 0xf5, 0x05, 0x0d,
+0x45, 0x4f, 0x46, 0x71, 0xfd, 0x28, 0x3e, 0x53, 0xfb, 0x04, 0xd8, 0x2d, 0xd7, 0x65, 0x1d, 0x4a,
+0x1b, 0xfa, 0xcf, 0x3b, 0xb0, 0x31, 0x9a, 0x35, 0x6e, 0xc8, 0x8b, 0x06, 0xd3, 0x00, 0x91, 0xf2,
+0x94, 0x08, 0x65, 0x4c, 0xb1, 0x34, 0x06, 0x00, 0x7a, 0x89, 0xe2, 0xf0, 0xc7, 0x03, 0x59, 0xcf,
+0xd5, 0xd6, 0xe8, 0xa7, 0x32, 0xb3, 0xe6, 0x98, 0x40, 0x86, 0xc5, 0xcd, 0x27, 0x12, 0x8b, 0xcc,
+0x7b, 0xce, 0xb7, 0x11, 0x3c, 0x62, 0x60, 0x07, 0x23, 0x3e, 0x2b, 0x40, 0x6e, 0x94, 0x80, 0x09,
+0x6d, 0xb6, 0xb3, 0x6f, 0x77, 0x6f, 0x35, 0x08, 0x50, 0xfb, 0x02, 0x87, 0xc5, 0x3e, 0x89, 0x02,
+0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+0x16, 0x04, 0x14, 0x5b, 0xf8, 0x4d, 0x4f, 0xb2, 0xa5, 0x86, 0xd4, 0x3a, 0xd2, 0xf1, 0x63, 0x9a,
+0xa0, 0xbe, 0x09, 0xf6, 0x57, 0xb7, 0xde, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa0, 0xa1, 0x38, 0x16,
+0x66, 0x2e, 0xa7, 0x56, 0x1f, 0x21, 0x9c, 0x06, 0xfa, 0x1d, 0xed, 0xb9, 0x22, 0xc5, 0x38, 0x26,
+0xd8, 0x4e, 0x4f, 0xec, 0xa3, 0x7f, 0x79, 0xde, 0x46, 0x21, 0xa1, 0x87, 0x77, 0x8f, 0x07, 0x08,
+0x9a, 0xb2, 0xa4, 0xc5, 0xaf, 0x0f, 0x32, 0x98, 0x0b, 0x7c, 0x66, 0x29, 0xb6, 0x9b, 0x7d, 0x25,
+0x52, 0x49, 0x43, 0xab, 0x4c, 0x2e, 0x2b, 0x6e, 0x7a, 0x70, 0xaf, 0x16, 0x0e, 0xe3, 0x02, 0x6c,
+0xfb, 0x42, 0xe6, 0x18, 0x9d, 0x45, 0xd8, 0x55, 0xc8, 0xe8, 0x3b, 0xdd, 0xe7, 0xe1, 0xf4, 0x2e,
+0x0b, 0x1c, 0x34, 0x5c, 0x6c, 0x58, 0x4a, 0xfb, 0x8c, 0x88, 0x50, 0x5f, 0x95, 0x1c, 0xbf, 0xed,
+0xab, 0x22, 0xb5, 0x65, 0xb3, 0x85, 0xba, 0x9e, 0x0f, 0xb8, 0xad, 0xe5, 0x7a, 0x1b, 0x8a, 0x50,
+0x3a, 0x1d, 0xbd, 0x0d, 0xbc, 0x7b, 0x54, 0x50, 0x0b, 0xb9, 0x42, 0xaf, 0x55, 0xa0, 0x18, 0x81,
+0xad, 0x65, 0x99, 0xef, 0xbe, 0xe4, 0x9c, 0xbf, 0xc4, 0x85, 0xab, 0x41, 0xb2, 0x54, 0x6f, 0xdc,
+0x25, 0xcd, 0xed, 0x78, 0xe2, 0x8e, 0x0c, 0x8d, 0x09, 0x49, 0xdd, 0x63, 0x7b, 0x5a, 0x69, 0x96,
+0x02, 0x21, 0xa8, 0xbd, 0x52, 0x59, 0xe9, 0x7d, 0x35, 0xcb, 0xc8, 0x52, 0xca, 0x7f, 0x81, 0xfe,
+0xd9, 0x6b, 0xd3, 0xf7, 0x11, 0xed, 0x25, 0xdf, 0xf8, 0xe7, 0xf9, 0xa4, 0xfa, 0x72, 0x97, 0x84,
+0x53, 0x0d, 0xa5, 0xd0, 0x32, 0x18, 0x51, 0x76, 0x59, 0x14, 0x6c, 0x0f, 0xeb, 0xec, 0x5f, 0x80,
+0x8c, 0x75, 0x43, 0x83, 0xc3, 0x85, 0x98, 0xff, 0x4c, 0x9e, 0x2d, 0x0d, 0xe4, 0x77, 0x83, 0x93,
+0x4e, 0xb5, 0x96, 0x07, 0x8b, 0x28, 0x13, 0x9b, 0x8c, 0x19, 0x8d, 0x41, 0x27, 0x49, 0x40, 0xee,
+0xde, 0xe6, 0x23, 0x44, 0x39, 0xdc, 0xa1, 0x22, 0xd6, 0xba, 0x03, 0xf2, 0x30, 0x82, 0x03, 0x5a,
+0x30, 0x82, 0x02, 0x42, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x50, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x0f, 0x53, 0x45, 0x43, 0x4f, 0x4d, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
+0x2e, 0x6e, 0x65, 0x74, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x53,
+0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63,
+0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x31, 0x30, 0x1e, 0x17,
+0x0d, 0x30, 0x33, 0x30, 0x39, 0x33, 0x30, 0x30, 0x34, 0x32, 0x30, 0x34, 0x39, 0x5a, 0x17, 0x0d,
+0x32, 0x33, 0x30, 0x39, 0x33, 0x30, 0x30, 0x34, 0x32, 0x30, 0x34, 0x39, 0x5a, 0x30, 0x50, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x18, 0x30, 0x16,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x53, 0x45, 0x43, 0x4f, 0x4d, 0x20, 0x54, 0x72, 0x75,
+0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+0x1e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e,
+0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x31, 0x30,
+0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
+0xb3, 0xb3, 0xfe, 0x7f, 0xd3, 0x6d, 0xb1, 0xef, 0x16, 0x7c, 0x57, 0xa5, 0x0c, 0x6d, 0x76, 0x8a,
+0x2f, 0x4b, 0xbf, 0x64, 0xfb, 0x4c, 0xee, 0x8a, 0xf0, 0xf3, 0x29, 0x7c, 0xf5, 0xff, 0xee, 0x2a,
+0xe0, 0xe9, 0xe9, 0xba, 0x5b, 0x64, 0x22, 0x9a, 0x9a, 0x6f, 0x2c, 0x3a, 0x26, 0x69, 0x51, 0x05,
+0x99, 0x26, 0xdc, 0xd5, 0x1c, 0x6a, 0x71, 0xc6, 0x9a, 0x7d, 0x1e, 0x9d, 0xdd, 0x7c, 0x6c, 0xc6,
+0x8c, 0x67, 0x67, 0x4a, 0x3e, 0xf8, 0x71, 0xb0, 0x19, 0x27, 0xa9, 0x09, 0x0c, 0xa6, 0x95, 0xbf,
+0x4b, 0x8c, 0x0c, 0xfa, 0x55, 0x98, 0x3b, 0xd8, 0xe8, 0x22, 0xa1, 0x4b, 0x71, 0x38, 0x79, 0xac,
+0x97, 0x92, 0x69, 0xb3, 0x89, 0x7e, 0xea, 0x21, 0x68, 0x06, 0x98, 0x14, 0x96, 0x87, 0xd2, 0x61,
+0x36, 0xbc, 0x6d, 0x27, 0x56, 0x9e, 0x57, 0xee, 0xc0, 0xc0, 0x56, 0xfd, 0x32, 0xcf, 0xa4, 0xd9,
+0x8e, 0xc2, 0x23, 0xd7, 0x8d, 0xa8, 0xf3, 0xd8, 0x25, 0xac, 0x97, 0xe4, 0x70, 0x38, 0xf4, 0xb6,
+0x3a, 0xb4, 0x9d, 0x3b, 0x97, 0x26, 0x43, 0xa3, 0xa1, 0xbc, 0x49, 0x59, 0x72, 0x4c, 0x23, 0x30,
+0x87, 0x01, 0x58, 0xf6, 0x4e, 0xbe, 0x1c, 0x68, 0x56, 0x66, 0xaf, 0xcd, 0x41, 0x5d, 0xc8, 0xb3,
+0x4d, 0x2a, 0x55, 0x46, 0xab, 0x1f, 0xda, 0x1e, 0xe2, 0x40, 0x3d, 0xdb, 0xcd, 0x7d, 0xb9, 0x92,
+0x80, 0x9c, 0x37, 0xdd, 0x0c, 0x96, 0x64, 0x9d, 0xdc, 0x22, 0xf7, 0x64, 0x8b, 0xdf, 0x61, 0xde,
+0x15, 0x94, 0x52, 0x15, 0xa0, 0x7d, 0x52, 0xc9, 0x4b, 0xa8, 0x21, 0xc9, 0xc6, 0xb1, 0xed, 0xcb,
+0xc3, 0x95, 0x60, 0xd1, 0x0f, 0xf0, 0xab, 0x70, 0xf8, 0xdf, 0xcb, 0x4d, 0x7e, 0xec, 0xd6, 0xfa,
+0xab, 0xd9, 0xbd, 0x7f, 0x54, 0xf2, 0xa5, 0xe9, 0x79, 0xfa, 0xd9, 0xd6, 0x76, 0x24, 0x28, 0x73,
+0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x3f, 0x30, 0x3d, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+0x04, 0x16, 0x04, 0x14, 0xa0, 0x73, 0x49, 0x99, 0x68, 0xdc, 0x85, 0x5b, 0x65, 0xe3, 0x9b, 0x28,
+0x2f, 0x57, 0x9f, 0xbd, 0x33, 0xbc, 0x07, 0x48, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x68, 0x40, 0xa9, 0xa8, 0xbb, 0xe4,
+0x4f, 0x5d, 0x79, 0xb3, 0x05, 0xb5, 0x17, 0xb3, 0x60, 0x13, 0xeb, 0xc6, 0x92, 0x5d, 0xe0, 0xd1,
+0xd3, 0x6a, 0xfe, 0xfb, 0xbe, 0x9b, 0x6d, 0xbf, 0xc7, 0x05, 0x6d, 0x59, 0x20, 0xc4, 0x1c, 0xf0,
+0xb7, 0xda, 0x84, 0x58, 0x02, 0x63, 0xfa, 0x48, 0x16, 0xef, 0x4f, 0xa5, 0x0b, 0xf7, 0x4a, 0x98,
+0xf2, 0x3f, 0x9e, 0x1b, 0xad, 0x47, 0x6b, 0x63, 0xce, 0x08, 0x47, 0xeb, 0x52, 0x3f, 0x78, 0x9c,
+0xaf, 0x4d, 0xae, 0xf8, 0xd5, 0x4f, 0xcf, 0x9a, 0x98, 0x2a, 0x10, 0x41, 0x39, 0x52, 0xc4, 0xdd,
+0xd9, 0x9b, 0x0e, 0xef, 0x93, 0x01, 0xae, 0xb2, 0x2e, 0xca, 0x68, 0x42, 0x24, 0x42, 0x6c, 0xb0,
+0xb3, 0x3a, 0x3e, 0xcd, 0xe9, 0xda, 0x48, 0xc4, 0x15, 0xcb, 0xe9, 0xf9, 0x07, 0x0f, 0x92, 0x50,
+0x49, 0x8a, 0xdd, 0x31, 0x97, 0x5f, 0xc9, 0xe9, 0x37, 0xaa, 0x3b, 0x59, 0x65, 0x97, 0x94, 0x32,
+0xc9, 0xb3, 0x9f, 0x3e, 0x3a, 0x62, 0x58, 0xc5, 0x49, 0xad, 0x62, 0x0e, 0x71, 0xa5, 0x32, 0xaa,
+0x2f, 0xc6, 0x89, 0x76, 0x43, 0x40, 0x13, 0x13, 0x67, 0x3d, 0xa2, 0x54, 0x25, 0x10, 0xcb, 0xf1,
+0x3a, 0xf2, 0xd9, 0xfa, 0xdb, 0x49, 0x56, 0xbb, 0xa6, 0xfe, 0xa7, 0x41, 0x35, 0xc3, 0xe0, 0x88,
+0x61, 0xc9, 0x88, 0xc7, 0xdf, 0x36, 0x10, 0x22, 0x98, 0x59, 0xea, 0xb0, 0x4a, 0xfb, 0x56, 0x16,
+0x73, 0x6e, 0xac, 0x4d, 0xf7, 0x22, 0xa1, 0x4f, 0xad, 0x1d, 0x7a, 0x2d, 0x45, 0x27, 0xe5, 0x30,
+0xc1, 0x5e, 0xf2, 0xda, 0x13, 0xcb, 0x25, 0x42, 0x51, 0x95, 0x47, 0x03, 0x8c, 0x6c, 0x21, 0xcc,
+0x74, 0x42, 0xed, 0x53, 0xff, 0x33, 0x8b, 0x8f, 0x0f, 0x57, 0x01, 0x16, 0x2f, 0xcf, 0xa6, 0xee,
+0xc9, 0x70, 0x22, 0x14, 0xbd, 0xfd, 0xbe, 0x6c, 0x0b, 0x03, 0x30, 0x82, 0x03, 0x77, 0x30, 0x82,
+0x02, 0x5f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x1c, 0x53, 0x45, 0x43, 0x4f, 0x4d, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53,
+0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x43, 0x4f, 0x2e, 0x2c, 0x4c, 0x54, 0x44, 0x2e, 0x31,
+0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69,
+0x74, 0x79, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x35,
+0x32, 0x39, 0x30, 0x35, 0x30, 0x30, 0x33, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x35, 0x32,
+0x39, 0x30, 0x35, 0x30, 0x30, 0x33, 0x39, 0x5a, 0x30, 0x5d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x13, 0x1c, 0x53, 0x45, 0x43, 0x4f, 0x4d, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x79,
+0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x43, 0x4f, 0x2e, 0x2c, 0x4c, 0x54, 0x44, 0x2e, 0x31, 0x27,
+0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+0x79, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
+0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd0, 0x15, 0x39, 0x52, 0xb1, 0x52, 0xb3, 0xba,
+0xc5, 0x59, 0x82, 0xc4, 0x5d, 0x52, 0xae, 0x3a, 0x43, 0x65, 0x80, 0x4b, 0xc7, 0xf2, 0x96, 0xbc,
+0xdb, 0x36, 0x97, 0xd6, 0xa6, 0x64, 0x8c, 0xa8, 0x5e, 0xf0, 0xe3, 0x0a, 0x1c, 0xf7, 0xdf, 0x97,
+0x3d, 0x4b, 0xae, 0xf6, 0x5d, 0xec, 0x21, 0xb5, 0x41, 0xab, 0xcd, 0xb9, 0x7e, 0x76, 0x9f, 0xbe,
+0xf9, 0x3e, 0x36, 0x34, 0xa0, 0x3b, 0xc1, 0xf6, 0x31, 0x11, 0x45, 0x74, 0x93, 0x3d, 0x57, 0x80,
+0xc5, 0xf9, 0x89, 0x99, 0xca, 0xe5, 0xab, 0x6a, 0xd4, 0xb5, 0xda, 0x41, 0x90, 0x10, 0xc1, 0xd6,
+0xd6, 0x42, 0x89, 0xc2, 0xbf, 0xf4, 0x38, 0x12, 0x95, 0x4c, 0x54, 0x05, 0xf7, 0x36, 0xe4, 0x45,
+0x83, 0x7b, 0x14, 0x65, 0xd6, 0xdc, 0x0c, 0x4d, 0xd1, 0xde, 0x7e, 0x0c, 0xab, 0x3b, 0xc4, 0x15,
+0xbe, 0x3a, 0x56, 0xa6, 0x5a, 0x6f, 0x76, 0x69, 0x52, 0xa9, 0x7a, 0xb9, 0xc8, 0xeb, 0x6a, 0x9a,
+0x5d, 0x52, 0xd0, 0x2d, 0x0a, 0x6b, 0x35, 0x16, 0x09, 0x10, 0x84, 0xd0, 0x6a, 0xca, 0x3a, 0x06,
+0x00, 0x37, 0x47, 0xe4, 0x7e, 0x57, 0x4f, 0x3f, 0x8b, 0xeb, 0x67, 0xb8, 0x88, 0xaa, 0xc5, 0xbe,
+0x53, 0x55, 0xb2, 0x91, 0xc4, 0x7d, 0xb9, 0xb0, 0x85, 0x19, 0x06, 0x78, 0x2e, 0xdb, 0x61, 0x1a,
+0xfa, 0x85, 0xf5, 0x4a, 0x91, 0xa1, 0xe7, 0x16, 0xd5, 0x8e, 0xa2, 0x39, 0xdf, 0x94, 0xb8, 0x70,
+0x1f, 0x28, 0x3f, 0x8b, 0xfc, 0x40, 0x5e, 0x63, 0x83, 0x3c, 0x83, 0x2a, 0x1a, 0x99, 0x6b, 0xcf,
+0xde, 0x59, 0x6a, 0x3b, 0xfc, 0x6f, 0x16, 0xd7, 0x1f, 0xfd, 0x4a, 0x10, 0xeb, 0x4e, 0x82, 0x16,
+0x3a, 0xac, 0x27, 0x0c, 0x53, 0xf1, 0xad, 0xd5, 0x24, 0xb0, 0x6b, 0x03, 0x50, 0xc1, 0x2d, 0x3c,
+0x16, 0xdd, 0x44, 0x34, 0x27, 0x1a, 0x75, 0xfb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30,
+0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x0a, 0x85, 0xa9, 0x77,
+0x65, 0x05, 0x98, 0x7c, 0x40, 0x81, 0xf8, 0x0f, 0x97, 0x2c, 0x38, 0xf1, 0x0a, 0xec, 0x3c, 0xcf,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+0x03, 0x82, 0x01, 0x01, 0x00, 0x4c, 0x3a, 0xa3, 0x44, 0xac, 0xb9, 0x45, 0xb1, 0xc7, 0x93, 0x7e,
+0xc8, 0x0b, 0x0a, 0x42, 0xdf, 0x64, 0xea, 0x1c, 0xee, 0x59, 0x6c, 0x08, 0xba, 0x89, 0x5f, 0x6a,
+0xca, 0x4a, 0x95, 0x9e, 0x7a, 0x8f, 0x07, 0xc5, 0xda, 0x45, 0x72, 0x82, 0x71, 0x0e, 0x3a, 0xd2,
+0xcc, 0x6f, 0xa7, 0xb4, 0xa1, 0x23, 0xbb, 0xf6, 0x24, 0x9f, 0xcb, 0x17, 0xfe, 0x8c, 0xa6, 0xce,
+0xc2, 0xd2, 0xdb, 0xcc, 0x8d, 0xfc, 0x71, 0xfc, 0x03, 0x29, 0xc1, 0x6c, 0x5d, 0x33, 0x5f, 0x64,
+0xb6, 0x65, 0x3b, 0x89, 0x6f, 0x18, 0x76, 0x78, 0xf5, 0xdc, 0xa2, 0x48, 0x1f, 0x19, 0x3f, 0x8e,
+0x93, 0xeb, 0xf1, 0xfa, 0x17, 0xee, 0xcd, 0x4e, 0xe3, 0x04, 0x12, 0x55, 0xd6, 0xe5, 0xe4, 0xdd,
+0xfb, 0x3e, 0x05, 0x7c, 0xe2, 0x1d, 0x5e, 0xc6, 0xa7, 0xbc, 0x97, 0x4f, 0x68, 0x3a, 0xf5, 0xe9,
+0x2e, 0x0a, 0x43, 0xb6, 0xaf, 0x57, 0x5c, 0x62, 0x68, 0x7c, 0xb7, 0xfd, 0xa3, 0x8a, 0x84, 0xa0,
+0xac, 0x62, 0xbe, 0x2b, 0x09, 0x87, 0x34, 0xf0, 0x6a, 0x01, 0xbb, 0x9b, 0x29, 0x56, 0x3c, 0xfe,
+0x00, 0x37, 0xcf, 0x23, 0x6c, 0xf1, 0x4e, 0xaa, 0xb6, 0x74, 0x46, 0x12, 0x6c, 0x91, 0xee, 0x34,
+0xd5, 0xec, 0x9a, 0x91, 0xe7, 0x44, 0xbe, 0x90, 0x31, 0x72, 0xd5, 0x49, 0x02, 0xf6, 0x02, 0xe5,
+0xf4, 0x1f, 0xeb, 0x7c, 0xd9, 0x96, 0x55, 0xa9, 0xff, 0xec, 0x8a, 0xf9, 0x99, 0x47, 0xff, 0x35,
+0x5a, 0x02, 0xaa, 0x04, 0xcb, 0x8a, 0x5b, 0x87, 0x71, 0x29, 0x91, 0xbd, 0xa4, 0xb4, 0x7a, 0x0d,
+0xbd, 0x9a, 0xf5, 0x57, 0x23, 0x00, 0x07, 0x21, 0x17, 0x3f, 0x4a, 0x39, 0xd1, 0x05, 0x49, 0x0b,
+0xa7, 0xb6, 0x37, 0x81, 0xa5, 0x5d, 0x8c, 0xaa, 0x33, 0x5e, 0x81, 0x28, 0x7c, 0xa7, 0x7d, 0x27,
+0xeb, 0x00, 0xae, 0x8d, 0x37, 0x30, 0x82, 0x05, 0xd8, 0x30, 0x82, 0x03, 0xc0, 0xa0, 0x03, 0x02,
+0x01, 0x02, 0x02, 0x10, 0x4c, 0xaa, 0xf9, 0xca, 0xdb, 0x63, 0x6f, 0xe0, 0x1f, 0xf7, 0x4e, 0xd8,
+0x5b, 0x03, 0x86, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0c, 0x05, 0x00, 0x30, 0x81, 0x85, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x47, 0x42, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x12, 0x47, 0x72,
+0x65, 0x61, 0x74, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x73, 0x74, 0x65, 0x72,
+0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x61, 0x6c, 0x66, 0x6f,
+0x72, 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43, 0x4f, 0x4d,
+0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x2b,
+0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20,
+0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+0x30, 0x30, 0x31, 0x31, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38,
+0x30, 0x31, 0x31, 0x38, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0x85, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x30, 0x19, 0x06,
+0x03, 0x55, 0x04, 0x08, 0x13, 0x12, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, 0x4d, 0x61,
+0x6e, 0x63, 0x68, 0x65, 0x73, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
+0x07, 0x13, 0x07, 0x53, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x11, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c,
+0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+0x22, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74,
+0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+0x69, 0x74, 0x79, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02,
+0x82, 0x02, 0x01, 0x00, 0x91, 0xe8, 0x54, 0x92, 0xd2, 0x0a, 0x56, 0xb1, 0xac, 0x0d, 0x24, 0xdd,
+0xc5, 0xcf, 0x44, 0x67, 0x74, 0x99, 0x2b, 0x37, 0xa3, 0x7d, 0x23, 0x70, 0x00, 0x71, 0xbc, 0x53,
+0xdf, 0xc4, 0xfa, 0x2a, 0x12, 0x8f, 0x4b, 0x7f, 0x10, 0x56, 0xbd, 0x9f, 0x70, 0x72, 0xb7, 0x61,
+0x7f, 0xc9, 0x4b, 0x0f, 0x17, 0xa7, 0x3d, 0xe3, 0xb0, 0x04, 0x61, 0xee, 0xff, 0x11, 0x97, 0xc7,
+0xf4, 0x86, 0x3e, 0x0a, 0xfa, 0x3e, 0x5c, 0xf9, 0x93, 0xe6, 0x34, 0x7a, 0xd9, 0x14, 0x6b, 0xe7,
+0x9c, 0xb3, 0x85, 0xa0, 0x82, 0x7a, 0x76, 0xaf, 0x71, 0x90, 0xd7, 0xec, 0xfd, 0x0d, 0xfa, 0x9c,
+0x6c, 0xfa, 0xdf, 0xb0, 0x82, 0xf4, 0x14, 0x7e, 0xf9, 0xbe, 0xc4, 0xa6, 0x2f, 0x4f, 0x7f, 0x99,
+0x7f, 0xb5, 0xfc, 0x67, 0x43, 0x72, 0xbd, 0x0c, 0x00, 0xd6, 0x89, 0xeb, 0x6b, 0x2c, 0xd3, 0xed,
+0x8f, 0x98, 0x1c, 0x14, 0xab, 0x7e, 0xe5, 0xe3, 0x6e, 0xfc, 0xd8, 0xa8, 0xe4, 0x92, 0x24, 0xda,
+0x43, 0x6b, 0x62, 0xb8, 0x55, 0xfd, 0xea, 0xc1, 0xbc, 0x6c, 0xb6, 0x8b, 0xf3, 0x0e, 0x8d, 0x9a,
+0xe4, 0x9b, 0x6c, 0x69, 0x99, 0xf8, 0x78, 0x48, 0x30, 0x45, 0xd5, 0xad, 0xe1, 0x0d, 0x3c, 0x45,
+0x60, 0xfc, 0x32, 0x96, 0x51, 0x27, 0xbc, 0x67, 0xc3, 0xca, 0x2e, 0xb6, 0x6b, 0xea, 0x46, 0xc7,
+0xc7, 0x20, 0xa0, 0xb1, 0x1f, 0x65, 0xde, 0x48, 0x08, 0xba, 0xa4, 0x4e, 0xa9, 0xf2, 0x83, 0x46,
+0x37, 0x84, 0xeb, 0xe8, 0xcc, 0x81, 0x48, 0x43, 0x67, 0x4e, 0x72, 0x2a, 0x9b, 0x5c, 0xbd, 0x4c,
+0x1b, 0x28, 0x8a, 0x5c, 0x22, 0x7b, 0xb4, 0xab, 0x98, 0xd9, 0xee, 0xe0, 0x51, 0x83, 0xc3, 0x09,
+0x46, 0x4e, 0x6d, 0x3e, 0x99, 0xfa, 0x95, 0x17, 0xda, 0x7c, 0x33, 0x57, 0x41, 0x3c, 0x8d, 0x51,
+0xed, 0x0b, 0xb6, 0x5c, 0xaf, 0x2c, 0x63, 0x1a, 0xdf, 0x57, 0xc8, 0x3f, 0xbc, 0xe9, 0x5d, 0xc4,
+0x9b, 0xaf, 0x45, 0x99, 0xe2, 0xa3, 0x5a, 0x24, 0xb4, 0xba, 0xa9, 0x56, 0x3d, 0xcf, 0x6f, 0xaa,
+0xff, 0x49, 0x58, 0xbe, 0xf0, 0xa8, 0xff, 0xf4, 0xb8, 0xad, 0xe9, 0x37, 0xfb, 0xba, 0xb8, 0xf4,
+0x0b, 0x3a, 0xf9, 0xe8, 0x43, 0x42, 0x1e, 0x89, 0xd8, 0x84, 0xcb, 0x13, 0xf1, 0xd9, 0xbb, 0xe1,
+0x89, 0x60, 0xb8, 0x8c, 0x28, 0x56, 0xac, 0x14, 0x1d, 0x9c, 0x0a, 0xe7, 0x71, 0xeb, 0xcf, 0x0e,
+0xdd, 0x3d, 0xa9, 0x96, 0xa1, 0x48, 0xbd, 0x3c, 0xf7, 0xaf, 0xb5, 0x0d, 0x22, 0x4c, 0xc0, 0x11,
+0x81, 0xec, 0x56, 0x3b, 0xf6, 0xd3, 0xa2, 0xe2, 0x5b, 0xb7, 0xb2, 0x04, 0x22, 0x52, 0x95, 0x80,
+0x93, 0x69, 0xe8, 0x8e, 0x4c, 0x65, 0xf1, 0x91, 0x03, 0x2d, 0x70, 0x74, 0x02, 0xea, 0x8b, 0x67,
+0x15, 0x29, 0x69, 0x52, 0x02, 0xbb, 0xd7, 0xdf, 0x50, 0x6a, 0x55, 0x46, 0xbf, 0xa0, 0xa3, 0x28,
+0x61, 0x7f, 0x70, 0xd0, 0xc3, 0xa2, 0xaa, 0x2c, 0x21, 0xaa, 0x47, 0xce, 0x28, 0x9c, 0x06, 0x45,
+0x76, 0xbf, 0x82, 0x18, 0x27, 0xb4, 0xd5, 0xae, 0xb4, 0xcb, 0x50, 0xe6, 0x6b, 0xf4, 0x4c, 0x86,
+0x71, 0x30, 0xe9, 0xa6, 0xdf, 0x16, 0x86, 0xe0, 0xd8, 0xff, 0x40, 0xdd, 0xfb, 0xd0, 0x42, 0x88,
+0x7f, 0xa3, 0x33, 0x3a, 0x2e, 0x5c, 0x1e, 0x41, 0x11, 0x81, 0x63, 0xce, 0x18, 0x71, 0x6b, 0x2b,
+0xec, 0xa6, 0x8a, 0xb7, 0x31, 0x5c, 0x3a, 0x6a, 0x47, 0xe0, 0xc3, 0x79, 0x59, 0xd6, 0x20, 0x1a,
+0xaf, 0xf2, 0x6a, 0x98, 0xaa, 0x72, 0xbc, 0x57, 0x4a, 0xd2, 0x4b, 0x9d, 0xbb, 0x10, 0xfc, 0xb0,
+0x4c, 0x41, 0xe5, 0xed, 0x1d, 0x3d, 0x5e, 0x28, 0x9d, 0x9c, 0xcc, 0xbf, 0xb3, 0x51, 0xda, 0xa7,
+0x47, 0xe5, 0x84, 0x53, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06,
+0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xbb, 0xaf, 0x7e, 0x02, 0x3d, 0xfa, 0xa6, 0xf1,
+0x3c, 0x84, 0x8e, 0xad, 0xee, 0x38, 0x98, 0xec, 0xd9, 0x32, 0x32, 0xd4, 0x30, 0x0e, 0x06, 0x03,
+0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03,
+0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
+0x00, 0x0a, 0xf1, 0xd5, 0x46, 0x84, 0xb7, 0xae, 0x51, 0xbb, 0x6c, 0xb2, 0x4d, 0x41, 0x14, 0x00,
+0x93, 0x4c, 0x9c, 0xcb, 0xe5, 0xc0, 0x54, 0xcf, 0xa0, 0x25, 0x8e, 0x02, 0xf9, 0xfd, 0xb0, 0xa2,
+0x0d, 0xf5, 0x20, 0x98, 0x3c, 0x13, 0x2d, 0xac, 0x56, 0xa2, 0xb0, 0xd6, 0x7e, 0x11, 0x92, 0xe9,
+0x2e, 0xba, 0x9e, 0x2e, 0x9a, 0x72, 0xb1, 0xbd, 0x19, 0x44, 0x6c, 0x61, 0x35, 0xa2, 0x9a, 0xb4,
+0x16, 0x12, 0x69, 0x5a, 0x8c, 0xe1, 0xd7, 0x3e, 0xa4, 0x1a, 0xe8, 0x2f, 0x03, 0xf4, 0xae, 0x61,
+0x1d, 0x10, 0x1b, 0x2a, 0xa4, 0x8b, 0x7a, 0xc5, 0xfe, 0x05, 0xa6, 0xe1, 0xc0, 0xd6, 0xc8, 0xfe,
+0x9e, 0xae, 0x8f, 0x2b, 0xba, 0x3d, 0x99, 0xf8, 0xd8, 0x73, 0x09, 0x58, 0x46, 0x6e, 0xa6, 0x9c,
+0xf4, 0xd7, 0x27, 0xd3, 0x95, 0xda, 0x37, 0x83, 0x72, 0x1c, 0xd3, 0x73, 0xe0, 0xa2, 0x47, 0x99,
+0x03, 0x38, 0x5d, 0xd5, 0x49, 0x79, 0x00, 0x29, 0x1c, 0xc7, 0xec, 0x9b, 0x20, 0x1c, 0x07, 0x24,
+0x69, 0x57, 0x78, 0xb2, 0x39, 0xfc, 0x3a, 0x84, 0xa0, 0xb5, 0x9c, 0x7c, 0x8d, 0xbf, 0x2e, 0x93,
+0x62, 0x27, 0xb7, 0x39, 0xda, 0x17, 0x18, 0xae, 0xbd, 0x3c, 0x09, 0x68, 0xff, 0x84, 0x9b, 0x3c,
+0xd5, 0xd6, 0x0b, 0x03, 0xe3, 0x57, 0x9e, 0x14, 0xf7, 0xd1, 0xeb, 0x4f, 0xc8, 0xbd, 0x87, 0x23,
+0xb7, 0xb6, 0x49, 0x43, 0x79, 0x85, 0x5c, 0xba, 0xeb, 0x92, 0x0b, 0xa1, 0xc6, 0xe8, 0x68, 0xa8,
+0x4c, 0x16, 0xb1, 0x1a, 0x99, 0x0a, 0xe8, 0x53, 0x2c, 0x92, 0xbb, 0xa1, 0x09, 0x18, 0x75, 0x0c,
+0x65, 0xa8, 0x7b, 0xcb, 0x23, 0xb7, 0x1a, 0xc2, 0x28, 0x85, 0xc3, 0x1b, 0xff, 0xd0, 0x2b, 0x62,
+0xef, 0xa4, 0x7b, 0x09, 0x91, 0x98, 0x67, 0x8c, 0x14, 0x01, 0xcd, 0x68, 0x06, 0x6a, 0x63, 0x21,
+0x75, 0x03, 0x80, 0x88, 0x8a, 0x6e, 0x81, 0xc6, 0x85, 0xf2, 0xa9, 0xa4, 0x2d, 0xe7, 0xf4, 0xa5,
+0x24, 0x10, 0x47, 0x83, 0xca, 0xcd, 0xf4, 0x8d, 0x79, 0x58, 0xb1, 0x06, 0x9b, 0xe7, 0x1a, 0x2a,
+0xd9, 0x9d, 0x01, 0xd7, 0x94, 0x7d, 0xed, 0x03, 0x4a, 0xca, 0xf0, 0xdb, 0xe8, 0xa9, 0x01, 0x3e,
+0xf5, 0x56, 0x99, 0xc9, 0x1e, 0x8e, 0x49, 0x3d, 0xbb, 0xe5, 0x09, 0xb9, 0xe0, 0x4f, 0x49, 0x92,
+0x3d, 0x16, 0x82, 0x40, 0xcc, 0xcc, 0x59, 0xc6, 0xe6, 0x3a, 0xed, 0x12, 0x2e, 0x69, 0x3c, 0x6c,
+0x95, 0xb1, 0xfd, 0xaa, 0x1d, 0x7b, 0x7f, 0x86, 0xbe, 0x1e, 0x0e, 0x32, 0x46, 0xfb, 0xfb, 0x13,
+0x8f, 0x75, 0x7f, 0x4c, 0x8b, 0x4b, 0x46, 0x63, 0xfe, 0x00, 0x34, 0x40, 0x70, 0xc1, 0xc3, 0xb9,
+0xa1, 0xdd, 0xa6, 0x70, 0xe2, 0x04, 0xb3, 0x41, 0xbc, 0xe9, 0x80, 0x91, 0xea, 0x64, 0x9c, 0x7a,
+0xe1, 0x22, 0x03, 0xa9, 0x9c, 0x6e, 0x6f, 0x0e, 0x65, 0x4f, 0x6c, 0x87, 0x87, 0x5e, 0xf3, 0x6e,
+0xa0, 0xf9, 0x75, 0xa5, 0x9b, 0x40, 0xe8, 0x53, 0xb2, 0x27, 0x9d, 0x4a, 0xb9, 0xc0, 0x77, 0x21,
+0x8d, 0xff, 0x87, 0xf2, 0xde, 0xbc, 0x8c, 0xef, 0x17, 0xdf, 0xb7, 0x49, 0x0b, 0xd1, 0xf2, 0x6e,
+0x30, 0x0b, 0x1a, 0x0e, 0x4e, 0x76, 0xed, 0x11, 0xfc, 0xf5, 0xe9, 0x56, 0xb2, 0x7d, 0xbf, 0xc7,
+0x6d, 0x0a, 0x93, 0x8c, 0xa5, 0xd0, 0xc0, 0xb6, 0x1d, 0xbe, 0x3a, 0x4e, 0x94, 0xa2, 0xd7, 0x6e,
+0x6c, 0x0b, 0xc2, 0x8a, 0x7c, 0xfa, 0x20, 0xf3, 0xc4, 0xe4, 0xe5, 0xcd, 0x0d, 0xa8, 0xcb, 0x91,
+0x92, 0xb1, 0x7c, 0x85, 0xec, 0xb5, 0x14, 0x69, 0x66, 0x0e, 0x82, 0xe7, 0xcd, 0xce, 0xc8, 0x2d,
+0xa6, 0x51, 0x7f, 0x21, 0xc1, 0x35, 0x53, 0x85, 0x06, 0x4a, 0x5d, 0x9f, 0xad, 0xbb, 0x1b, 0x5f,
+0x74, 0x30, 0x82, 0x04, 0x0f, 0x30, 0x82, 0x02, 0xf7, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01,
+0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69,
+0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73,
+0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73,
+0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x34,
+0x30, 0x36, 0x32, 0x39, 0x31, 0x37, 0x33, 0x39, 0x31, 0x36, 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30,
+0x36, 0x32, 0x39, 0x31, 0x37, 0x33, 0x39, 0x31, 0x36, 0x5a, 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65,
+0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66,
+0x69, 0x65, 0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x01, 0x20, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0d, 0x00, 0x30, 0x82, 0x01, 0x08,
+0x02, 0x82, 0x01, 0x01, 0x00, 0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c,
+0x11, 0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab, 0xfb, 0x3c, 0xa6,
+0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b, 0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84,
+0xf0, 0x9e, 0xe8, 0x5f, 0xec, 0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a,
+0xf0, 0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66, 0x1c, 0x39, 0xa7,
+0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb, 0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99,
+0x25, 0x14, 0x54, 0xeb, 0x26, 0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46,
+0x2a, 0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4, 0xf9, 0x89, 0xa5,
+0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66, 0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c,
+0x3a, 0x3e, 0x10, 0xc8, 0x3b, 0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71,
+0x51, 0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c, 0xc3, 0x23, 0x56,
+0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3, 0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82,
+0xb8, 0x36, 0x3d, 0xea, 0x9c, 0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd,
+0x64, 0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87, 0xb4, 0x9d, 0x1a,
+0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b, 0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2,
+0xea, 0x3e, 0xbb, 0x78, 0x0d, 0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b,
+0xf2, 0x44, 0xa0, 0x01, 0xab, 0x02, 0x01, 0x03, 0xa3, 0x81, 0xc5, 0x30, 0x81, 0xc2, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xbf, 0x5f, 0xb7, 0xd1, 0xce, 0xdd, 0x1f,
+0x86, 0xf4, 0x5b, 0x55, 0xac, 0xdc, 0xd7, 0x10, 0xc2, 0x0e, 0xa9, 0x88, 0xe7, 0x30, 0x81, 0x92,
+0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0x8a, 0x30, 0x81, 0x87, 0x80, 0x14, 0xbf, 0x5f, 0xb7,
+0xd1, 0xce, 0xdd, 0x1f, 0x86, 0xf4, 0x5b, 0x55, 0xac, 0xdc, 0xd7, 0x10, 0xc2, 0x0e, 0xa9, 0x88,
+0xe7, 0xa1, 0x6c, 0xa4, 0x6a, 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53,
+0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c,
+0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06,
+0x03, 0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
+0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x82,
+0x01, 0x00, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
+0x82, 0x01, 0x01, 0x00, 0x05, 0x9d, 0x3f, 0x88, 0x9d, 0xd1, 0xc9, 0x1a, 0x55, 0xa1, 0xac, 0x69,
+0xf3, 0xf3, 0x59, 0xda, 0x9b, 0x01, 0x87, 0x1a, 0x4f, 0x57, 0xa9, 0xa1, 0x79, 0x09, 0x2a, 0xdb,
+0xf7, 0x2f, 0xb2, 0x1e, 0xcc, 0xc7, 0x5e, 0x6a, 0xd8, 0x83, 0x87, 0xa1, 0x97, 0xef, 0x49, 0x35,
+0x3e, 0x77, 0x06, 0x41, 0x58, 0x62, 0xbf, 0x8e, 0x58, 0xb8, 0x0a, 0x67, 0x3f, 0xec, 0xb3, 0xdd,
+0x21, 0x66, 0x1f, 0xc9, 0x54, 0xfa, 0x72, 0xcc, 0x3d, 0x4c, 0x40, 0xd8, 0x81, 0xaf, 0x77, 0x9e,
+0x83, 0x7a, 0xbb, 0xa2, 0xc7, 0xf5, 0x34, 0x17, 0x8e, 0xd9, 0x11, 0x40, 0xf4, 0xfc, 0x2c, 0x2a,
+0x4d, 0x15, 0x7f, 0xa7, 0x62, 0x5d, 0x2e, 0x25, 0xd3, 0x00, 0x0b, 0x20, 0x1a, 0x1d, 0x68, 0xf9,
+0x17, 0xb8, 0xf4, 0xbd, 0x8b, 0xed, 0x28, 0x59, 0xdd, 0x4d, 0x16, 0x8b, 0x17, 0x83, 0xc8, 0xb2,
+0x65, 0xc7, 0x2d, 0x7a, 0xa5, 0xaa, 0xbc, 0x53, 0x86, 0x6d, 0xdd, 0x57, 0xa4, 0xca, 0xf8, 0x20,
+0x41, 0x0b, 0x68, 0xf0, 0xf4, 0xfb, 0x74, 0xbe, 0x56, 0x5d, 0x7a, 0x79, 0xf5, 0xf9, 0x1d, 0x85,
+0xe3, 0x2d, 0x95, 0xbe, 0xf5, 0x71, 0x90, 0x43, 0xcc, 0x8d, 0x1f, 0x9a, 0x00, 0x0a, 0x87, 0x29,
+0xe9, 0x55, 0x22, 0x58, 0x00, 0x23, 0xea, 0xe3, 0x12, 0x43, 0x29, 0x5b, 0x47, 0x08, 0xdd, 0x8c,
+0x41, 0x6a, 0x65, 0x06, 0xa8, 0xe5, 0x21, 0xaa, 0x41, 0xb4, 0x95, 0x21, 0x95, 0xb9, 0x7d, 0xd1,
+0x34, 0xab, 0x13, 0xd6, 0xad, 0xbc, 0xdc, 0xe2, 0x3d, 0x39, 0xcd, 0xbd, 0x3e, 0x75, 0x70, 0xa1,
+0x18, 0x59, 0x03, 0xc9, 0x22, 0xb4, 0x8f, 0x9c, 0xd5, 0x5e, 0x2a, 0xd7, 0xa5, 0xb6, 0xd4, 0x0a,
+0x6d, 0xf8, 0xb7, 0x40, 0x11, 0x46, 0x9a, 0x1f, 0x79, 0x0e, 0x62, 0xbf, 0x0f, 0x97, 0xec, 0xe0,
+0x2f, 0x1f, 0x17, 0x94, 0x30, 0x82, 0x03, 0xdd, 0x30, 0x82, 0x02, 0xc5, 0xa0, 0x03, 0x02, 0x01,
+0x02, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x30, 0x81, 0x8f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72,
+0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a,
+0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54,
+0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72,
+0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x39, 0x30, 0x31, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33,
+0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0x8f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07,
+0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07,
+0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x25, 0x30, 0x23,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64,
+0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49,
+0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x29, 0x53, 0x74,
+0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
+0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0xed, 0xc1, 0x03, 0xfc, 0xf6, 0x8f, 0xfc,
+0x02, 0xb1, 0x6f, 0x5b, 0x9f, 0x48, 0xd9, 0x9d, 0x79, 0xe2, 0xa2, 0xb7, 0x03, 0x61, 0x56, 0x18,
+0xc3, 0x47, 0xb6, 0xd7, 0xca, 0x3d, 0x35, 0x2e, 0x89, 0x43, 0xf7, 0xa1, 0x69, 0x9b, 0xde, 0x8a,
+0x1a, 0xfd, 0x13, 0x20, 0x9c, 0xb4, 0x49, 0x77, 0x32, 0x29, 0x56, 0xfd, 0xb9, 0xec, 0x8c, 0xdd,
+0x22, 0xfa, 0x72, 0xdc, 0x27, 0x61, 0x97, 0xee, 0xf6, 0x5a, 0x84, 0xec, 0x6e, 0x19, 0xb9, 0x89,
+0x2c, 0xdc, 0x84, 0x5b, 0xd5, 0x74, 0xfb, 0x6b, 0x5f, 0xc5, 0x89, 0xa5, 0x10, 0x52, 0x89, 0x46,
+0x55, 0xf4, 0xb8, 0x75, 0x1c, 0xe6, 0x7f, 0xe4, 0x54, 0xae, 0x4b, 0xf8, 0x55, 0x72, 0x57, 0x02,
+0x19, 0xf8, 0x17, 0x71, 0x59, 0xeb, 0x1e, 0x28, 0x07, 0x74, 0xc5, 0x9d, 0x48, 0xbe, 0x6c, 0xb4,
+0xf4, 0xa4, 0xb0, 0xf3, 0x64, 0x37, 0x79, 0x92, 0xc0, 0xec, 0x46, 0x5e, 0x7f, 0xe1, 0x6d, 0x53,
+0x4c, 0x62, 0xaf, 0xcd, 0x1f, 0x0b, 0x63, 0xbb, 0x3a, 0x9d, 0xfb, 0xfc, 0x79, 0x00, 0x98, 0x61,
+0x74, 0xcf, 0x26, 0x82, 0x40, 0x63, 0xf3, 0xb2, 0x72, 0x6a, 0x19, 0x0d, 0x99, 0xca, 0xd4, 0x0e,
+0x75, 0xcc, 0x37, 0xfb, 0x8b, 0x89, 0xc1, 0x59, 0xf1, 0x62, 0x7f, 0x5f, 0xb3, 0x5f, 0x65, 0x30,
+0xf8, 0xa7, 0xb7, 0x4d, 0x76, 0x5a, 0x1e, 0x76, 0x5e, 0x34, 0xc0, 0xe8, 0x96, 0x56, 0x99, 0x8a,
+0xb3, 0xf0, 0x7f, 0xa4, 0xcd, 0xbd, 0xdc, 0x32, 0x31, 0x7c, 0x91, 0xcf, 0xe0, 0x5f, 0x11, 0xf8,
+0x6b, 0xaa, 0x49, 0x5c, 0xd1, 0x99, 0x94, 0xd1, 0xa2, 0xe3, 0x63, 0x5b, 0x09, 0x76, 0xb5, 0x56,
+0x62, 0xe1, 0x4b, 0x74, 0x1d, 0x96, 0xd4, 0x26, 0xd4, 0x08, 0x04, 0x59, 0xd0, 0x98, 0x0e, 0x0e,
+0xe6, 0xde, 0xfc, 0xc3, 0xec, 0x1f, 0x90, 0xf1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30,
+0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x7c, 0x0c, 0x32,
+0x1f, 0xa7, 0xd9, 0x30, 0x7f, 0xc4, 0x7d, 0x68, 0xa3, 0x62, 0xa8, 0xa1, 0xce, 0xab, 0x07, 0x5b,
+0x27, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+0x03, 0x82, 0x01, 0x01, 0x00, 0x11, 0x59, 0xfa, 0x25, 0x4f, 0x03, 0x6f, 0x94, 0x99, 0x3b, 0x9a,
+0x1f, 0x82, 0x85, 0x39, 0xd4, 0x76, 0x05, 0x94, 0x5e, 0xe1, 0x28, 0x93, 0x6d, 0x62, 0x5d, 0x09,
+0xc2, 0xa0, 0xa8, 0xd4, 0xb0, 0x75, 0x38, 0xf1, 0x34, 0x6a, 0x9d, 0xe4, 0x9f, 0x8a, 0x86, 0x26,
+0x51, 0xe6, 0x2c, 0xd1, 0xc6, 0x2d, 0x6e, 0x95, 0x20, 0x4a, 0x92, 0x01, 0xec, 0xb8, 0x8a, 0x67,
+0x7b, 0x31, 0xe2, 0x67, 0x2e, 0x8c, 0x95, 0x03, 0x26, 0x2e, 0x43, 0x9d, 0x4a, 0x31, 0xf6, 0x0e,
+0xb5, 0x0c, 0xbb, 0xb7, 0xe2, 0x37, 0x7f, 0x22, 0xba, 0x00, 0xa3, 0x0e, 0x7b, 0x52, 0xfb, 0x6b,
+0xbb, 0x3b, 0xc4, 0xd3, 0x79, 0x51, 0x4e, 0xcd, 0x90, 0xf4, 0x67, 0x07, 0x19, 0xc8, 0x3c, 0x46,
+0x7a, 0x0d, 0x01, 0x7d, 0xc5, 0x58, 0xe7, 0x6d, 0xe6, 0x85, 0x30, 0x17, 0x9a, 0x24, 0xc4, 0x10,
+0xe0, 0x04, 0xf7, 0xe0, 0xf2, 0x7f, 0xd4, 0xaa, 0x0a, 0xff, 0x42, 0x1d, 0x37, 0xed, 0x94, 0xe5,
+0x64, 0x59, 0x12, 0x20, 0x77, 0x38, 0xd3, 0x32, 0x3e, 0x38, 0x81, 0x75, 0x96, 0x73, 0xfa, 0x68,
+0x8f, 0xb1, 0xcb, 0xce, 0x1f, 0xc5, 0xec, 0xfa, 0x9c, 0x7e, 0xcf, 0x7e, 0xb1, 0xf1, 0x07, 0x2d,
+0xb6, 0xfc, 0xbf, 0xca, 0xa4, 0xbf, 0xd0, 0x97, 0x05, 0x4a, 0xbc, 0xea, 0x18, 0x28, 0x02, 0x90,
+0xbd, 0x54, 0x78, 0x09, 0x21, 0x71, 0xd3, 0xd1, 0x7d, 0x1d, 0xd9, 0x16, 0xb0, 0xa9, 0x61, 0x3d,
+0xd0, 0x0a, 0x00, 0x22, 0xfc, 0xc7, 0x7b, 0xcb, 0x09, 0x64, 0x45, 0x0b, 0x3b, 0x40, 0x81, 0xf7,
+0x7d, 0x7c, 0x32, 0xf5, 0x98, 0xca, 0x58, 0x8e, 0x7d, 0x2a, 0xee, 0x90, 0x59, 0x73, 0x64, 0xf9,
+0x36, 0x74, 0x5e, 0x25, 0xa1, 0xf5, 0x66, 0x05, 0x2e, 0x7f, 0x39, 0x15, 0xa9, 0x2a, 0xfb, 0x50,
+0x8b, 0x8e, 0x85, 0x69, 0xf4, 0x30, 0x82, 0x03, 0xef, 0x30, 0x82, 0x02, 0xd7, 0xa0, 0x03, 0x02,
+0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41,
+0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
+0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x25, 0x30, 0x23, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
+0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e,
+0x63, 0x2e, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x32, 0x53, 0x74, 0x61,
+0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30,
+0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x39, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
+0x17, 0x0d, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30,
+0x81, 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e,
+0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74,
+0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e,
+0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x3b, 0x30,
+0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x32, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c,
+0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
+0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd5, 0x0c, 0x3a, 0xc4, 0x2a,
+0xf9, 0x4e, 0xe2, 0xf5, 0xbe, 0x19, 0x97, 0x5f, 0x8e, 0x88, 0x53, 0xb1, 0x1f, 0x3f, 0xcb, 0xcf,
+0x9f, 0x20, 0x13, 0x6d, 0x29, 0x3a, 0xc8, 0x0f, 0x7d, 0x3c, 0xf7, 0x6b, 0x76, 0x38, 0x63, 0xd9,
+0x36, 0x60, 0xa8, 0x9b, 0x5e, 0x5c, 0x00, 0x80, 0xb2, 0x2f, 0x59, 0x7f, 0xf6, 0x87, 0xf9, 0x25,
+0x43, 0x86, 0xe7, 0x69, 0x1b, 0x52, 0x9a, 0x90, 0xe1, 0x71, 0xe3, 0xd8, 0x2d, 0x0d, 0x4e, 0x6f,
+0xf6, 0xc8, 0x49, 0xd9, 0xb6, 0xf3, 0x1a, 0x56, 0xae, 0x2b, 0xb6, 0x74, 0x14, 0xeb, 0xcf, 0xfb,
+0x26, 0xe3, 0x1a, 0xba, 0x1d, 0x96, 0x2e, 0x6a, 0x3b, 0x58, 0x94, 0x89, 0x47, 0x56, 0xff, 0x25,
+0xa0, 0x93, 0x70, 0x53, 0x83, 0xda, 0x84, 0x74, 0x14, 0xc3, 0x67, 0x9e, 0x04, 0x68, 0x3a, 0xdf,
+0x8e, 0x40, 0x5a, 0x1d, 0x4a, 0x4e, 0xcf, 0x43, 0x91, 0x3b, 0xe7, 0x56, 0xd6, 0x00, 0x70, 0xcb,
+0x52, 0xee, 0x7b, 0x7d, 0xae, 0x3a, 0xe7, 0xbc, 0x31, 0xf9, 0x45, 0xf6, 0xc2, 0x60, 0xcf, 0x13,
+0x59, 0x02, 0x2b, 0x80, 0xcc, 0x34, 0x47, 0xdf, 0xb9, 0xde, 0x90, 0x65, 0x6d, 0x02, 0xcf, 0x2c,
+0x91, 0xa6, 0xa6, 0xe7, 0xde, 0x85, 0x18, 0x49, 0x7c, 0x66, 0x4e, 0xa3, 0x3a, 0x6d, 0xa9, 0xb5,
+0xee, 0x34, 0x2e, 0xba, 0x0d, 0x03, 0xb8, 0x33, 0xdf, 0x47, 0xeb, 0xb1, 0x6b, 0x8d, 0x25, 0xd9,
+0x9b, 0xce, 0x81, 0xd1, 0x45, 0x46, 0x32, 0x96, 0x70, 0x87, 0xde, 0x02, 0x0e, 0x49, 0x43, 0x85,
+0xb6, 0x6c, 0x73, 0xbb, 0x64, 0xea, 0x61, 0x41, 0xac, 0xc9, 0xd4, 0x54, 0xdf, 0x87, 0x2f, 0xc7,
+0x22, 0xb2, 0x26, 0xcc, 0x9f, 0x59, 0x54, 0x68, 0x9f, 0xfc, 0xbe, 0x2a, 0x2f, 0xc4, 0x55, 0x1c,
+0x75, 0x40, 0x60, 0x17, 0x85, 0x02, 0x55, 0x39, 0x8b, 0x7f, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01,
+0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05,
+0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+0x9c, 0x5f, 0x00, 0xdf, 0xaa, 0x01, 0xd7, 0x30, 0x2b, 0x38, 0x88, 0xa2, 0xb8, 0x6d, 0x4a, 0x9c,
+0xf2, 0x11, 0x91, 0x83, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4b, 0x36, 0xa6, 0x84, 0x77, 0x69, 0xdd, 0x3b,
+0x19, 0x9f, 0x67, 0x23, 0x08, 0x6f, 0x0e, 0x61, 0xc9, 0xfd, 0x84, 0xdc, 0x5f, 0xd8, 0x36, 0x81,
+0xcd, 0xd8, 0x1b, 0x41, 0x2d, 0x9f, 0x60, 0xdd, 0xc7, 0x1a, 0x68, 0xd9, 0xd1, 0x6e, 0x86, 0xe1,
+0x88, 0x23, 0xcf, 0x13, 0xde, 0x43, 0xcf, 0xe2, 0x34, 0xb3, 0x04, 0x9d, 0x1f, 0x29, 0xd5, 0xbf,
+0xf8, 0x5e, 0xc8, 0xd5, 0xc1, 0xbd, 0xee, 0x92, 0x6f, 0x32, 0x74, 0xf2, 0x91, 0x82, 0x2f, 0xbd,
+0x82, 0x42, 0x7a, 0xad, 0x2a, 0xb7, 0x20, 0x7d, 0x4d, 0xbc, 0x7a, 0x55, 0x12, 0xc2, 0x15, 0xea,
+0xbd, 0xf7, 0x6a, 0x95, 0x2e, 0x6c, 0x74, 0x9f, 0xcf, 0x1c, 0xb4, 0xf2, 0xc5, 0x01, 0xa3, 0x85,
+0xd0, 0x72, 0x3e, 0xad, 0x73, 0xab, 0x0b, 0x9b, 0x75, 0x0c, 0x6d, 0x45, 0xb7, 0x8e, 0x94, 0xac,
+0x96, 0x37, 0xb5, 0xa0, 0xd0, 0x8f, 0x15, 0x47, 0x0e, 0xe3, 0xe8, 0x83, 0xdd, 0x8f, 0xfd, 0xef,
+0x41, 0x01, 0x77, 0xcc, 0x27, 0xa9, 0x62, 0x85, 0x33, 0xf2, 0x37, 0x08, 0xef, 0x71, 0xcf, 0x77,
+0x06, 0xde, 0xc8, 0x19, 0x1d, 0x88, 0x40, 0xcf, 0x7d, 0x46, 0x1d, 0xff, 0x1e, 0xc7, 0xe1, 0xce,
+0xff, 0x23, 0xdb, 0xc6, 0xfa, 0x8d, 0x55, 0x4e, 0xa9, 0x02, 0xe7, 0x47, 0x11, 0x46, 0x3e, 0xf4,
+0xfd, 0xbd, 0x7b, 0x29, 0x26, 0xbb, 0xa9, 0x61, 0x62, 0x37, 0x28, 0xb6, 0x2d, 0x2a, 0xf6, 0x10,
+0x86, 0x64, 0xc9, 0x70, 0xa7, 0xd2, 0xad, 0xb7, 0x29, 0x70, 0x79, 0xea, 0x3c, 0xda, 0x63, 0x25,
+0x9f, 0xfd, 0x68, 0xb7, 0x30, 0xec, 0x70, 0xfb, 0x75, 0x8a, 0xb7, 0x6d, 0x60, 0x67, 0xb2, 0x1e,
+0xc8, 0xb9, 0xe9, 0xd8, 0xa8, 0x6f, 0x02, 0x8b, 0x67, 0x0d, 0x4d, 0x26, 0x57, 0x71, 0xda, 0x20,
+0xfc, 0xc1, 0x4a, 0x50, 0x8d, 0xb1, 0x28, 0xba, 0x30, 0x82, 0x05, 0xde, 0x30, 0x82, 0x03, 0xc6,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, 0xfd, 0x6d, 0x30, 0xfc, 0xa3, 0xca, 0x51, 0xa8,
+0x1b, 0xbc, 0x64, 0x0e, 0x35, 0x03, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+0x0a, 0x4e, 0x65, 0x77, 0x20, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06,
+0x03, 0x55, 0x04, 0x07, 0x13, 0x0b, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x20, 0x43, 0x69, 0x74,
+0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20,
+0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
+0x6b, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x55, 0x53, 0x45, 0x52,
+0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31, 0x38, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39,
+0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x4e, 0x65, 0x77, 0x20,
+0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
+0x0b, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54,
+0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x2e, 0x30, 0x2c,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x55, 0x53, 0x45, 0x52, 0x54, 0x72, 0x75, 0x73, 0x74,
+0x20, 0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x02, 0x22,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0x80, 0x12, 0x65,
+0x17, 0x36, 0x0e, 0xc3, 0xdb, 0x08, 0xb3, 0xd0, 0xac, 0x57, 0x0d, 0x76, 0xed, 0xcd, 0x27, 0xd3,
+0x4c, 0xad, 0x50, 0x83, 0x61, 0xe2, 0xaa, 0x20, 0x4d, 0x09, 0x2d, 0x64, 0x09, 0xdc, 0xce, 0x89,
+0x9f, 0xcc, 0x3d, 0xa9, 0xec, 0xf6, 0xcf, 0xc1, 0xdc, 0xf1, 0xd3, 0xb1, 0xd6, 0x7b, 0x37, 0x28,
+0x11, 0x2b, 0x47, 0xda, 0x39, 0xc6, 0xbc, 0x3a, 0x19, 0xb4, 0x5f, 0xa6, 0xbd, 0x7d, 0x9d, 0xa3,
+0x63, 0x42, 0xb6, 0x76, 0xf2, 0xa9, 0x3b, 0x2b, 0x91, 0xf8, 0xe2, 0x6f, 0xd0, 0xec, 0x16, 0x20,
+0x90, 0x09, 0x3e, 0xe2, 0xe8, 0x74, 0xc9, 0x18, 0xb4, 0x91, 0xd4, 0x62, 0x64, 0xdb, 0x7f, 0xa3,
+0x06, 0xf1, 0x88, 0x18, 0x6a, 0x90, 0x22, 0x3c, 0xbc, 0xfe, 0x13, 0xf0, 0x87, 0x14, 0x7b, 0xf6,
+0xe4, 0x1f, 0x8e, 0xd4, 0xe4, 0x51, 0xc6, 0x11, 0x67, 0x46, 0x08, 0x51, 0xcb, 0x86, 0x14, 0x54,
+0x3f, 0xbc, 0x33, 0xfe, 0x7e, 0x6c, 0x9c, 0xff, 0x16, 0x9d, 0x18, 0xbd, 0x51, 0x8e, 0x35, 0xa6,
+0xa7, 0x66, 0xc8, 0x72, 0x67, 0xdb, 0x21, 0x66, 0xb1, 0xd4, 0x9b, 0x78, 0x03, 0xc0, 0x50, 0x3a,
+0xe8, 0xcc, 0xf0, 0xdc, 0xbc, 0x9e, 0x4c, 0xfe, 0xaf, 0x05, 0x96, 0x35, 0x1f, 0x57, 0x5a, 0xb7,
+0xff, 0xce, 0xf9, 0x3d, 0xb7, 0x2c, 0xb6, 0xf6, 0x54, 0xdd, 0xc8, 0xe7, 0x12, 0x3a, 0x4d, 0xae,
+0x4c, 0x8a, 0xb7, 0x5c, 0x9a, 0xb4, 0xb7, 0x20, 0x3d, 0xca, 0x7f, 0x22, 0x34, 0xae, 0x7e, 0x3b,
+0x68, 0x66, 0x01, 0x44, 0xe7, 0x01, 0x4e, 0x46, 0x53, 0x9b, 0x33, 0x60, 0xf7, 0x94, 0xbe, 0x53,
+0x37, 0x90, 0x73, 0x43, 0xf3, 0x32, 0xc3, 0x53, 0xef, 0xdb, 0xaa, 0xfe, 0x74, 0x4e, 0x69, 0xc7,
+0x6b, 0x8c, 0x60, 0x93, 0xde, 0xc4, 0xc7, 0x0c, 0xdf, 0xe1, 0x32, 0xae, 0xcc, 0x93, 0x3b, 0x51,
+0x78, 0x95, 0x67, 0x8b, 0xee, 0x3d, 0x56, 0xfe, 0x0c, 0xd0, 0x69, 0x0f, 0x1b, 0x0f, 0xf3, 0x25,
+0x26, 0x6b, 0x33, 0x6d, 0xf7, 0x6e, 0x47, 0xfa, 0x73, 0x43, 0xe5, 0x7e, 0x0e, 0xa5, 0x66, 0xb1,
+0x29, 0x7c, 0x32, 0x84, 0x63, 0x55, 0x89, 0xc4, 0x0d, 0xc1, 0x93, 0x54, 0x30, 0x19, 0x13, 0xac,
+0xd3, 0x7d, 0x37, 0xa7, 0xeb, 0x5d, 0x3a, 0x6c, 0x35, 0x5c, 0xdb, 0x41, 0xd7, 0x12, 0xda, 0xa9,
+0x49, 0x0b, 0xdf, 0xd8, 0x80, 0x8a, 0x09, 0x93, 0x62, 0x8e, 0xb5, 0x66, 0xcf, 0x25, 0x88, 0xcd,
+0x84, 0xb8, 0xb1, 0x3f, 0xa4, 0x39, 0x0f, 0xd9, 0x02, 0x9e, 0xeb, 0x12, 0x4c, 0x95, 0x7c, 0xf3,
+0x6b, 0x05, 0xa9, 0x5e, 0x16, 0x83, 0xcc, 0xb8, 0x67, 0xe2, 0xe8, 0x13, 0x9d, 0xcc, 0x5b, 0x82,
+0xd3, 0x4c, 0xb3, 0xed, 0x5b, 0xff, 0xde, 0xe5, 0x73, 0xac, 0x23, 0x3b, 0x2d, 0x00, 0xbf, 0x35,
+0x55, 0x74, 0x09, 0x49, 0xd8, 0x49, 0x58, 0x1a, 0x7f, 0x92, 0x36, 0xe6, 0x51, 0x92, 0x0e, 0xf3,
+0x26, 0x7d, 0x1c, 0x4d, 0x17, 0xbc, 0xc9, 0xec, 0x43, 0x26, 0xd0, 0xbf, 0x41, 0x5f, 0x40, 0xa9,
+0x44, 0x44, 0xf4, 0x99, 0xe7, 0x57, 0x87, 0x9e, 0x50, 0x1f, 0x57, 0x54, 0xa8, 0x3e, 0xfd, 0x74,
+0x63, 0x2f, 0xb1, 0x50, 0x65, 0x09, 0xe6, 0x58, 0x42, 0x2e, 0x43, 0x1a, 0x4c, 0xb4, 0xf0, 0x25,
+0x47, 0x59, 0xfa, 0x04, 0x1e, 0x93, 0xd4, 0x26, 0x46, 0x4a, 0x50, 0x81, 0xb2, 0xde, 0xbe, 0x78,
+0xb7, 0xfc, 0x67, 0x15, 0xe1, 0xc9, 0x57, 0x84, 0x1e, 0x0f, 0x63, 0xd6, 0xe9, 0x62, 0xba, 0xd6,
+0x5f, 0x55, 0x2e, 0xea, 0x5c, 0xc6, 0x28, 0x08, 0x04, 0x25, 0x39, 0xb8, 0x0e, 0x2b, 0xa9, 0xf2,
+0x4c, 0x97, 0x1c, 0x07, 0x3f, 0x0d, 0x52, 0xf5, 0xed, 0xef, 0x2f, 0x82, 0x0f, 0x02, 0x03, 0x01,
+0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+0x14, 0x53, 0x79, 0xbf, 0x5a, 0xaa, 0x2b, 0x4a, 0xcf, 0x54, 0x80, 0xe1, 0xd8, 0x9b, 0xc0, 0x9d,
+0xf2, 0xb2, 0x03, 0x66, 0xcb, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x0c, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x5c, 0xd4, 0x7c, 0x0d, 0xcf, 0xf7,
+0x01, 0x7d, 0x41, 0x99, 0x65, 0x0c, 0x73, 0xc5, 0x52, 0x9f, 0xcb, 0xf8, 0xcf, 0x99, 0x06, 0x7f,
+0x1b, 0xda, 0x43, 0x15, 0x9f, 0x9e, 0x02, 0x55, 0x57, 0x96, 0x14, 0xf1, 0x52, 0x3c, 0x27, 0x87,
+0x94, 0x28, 0xed, 0x1f, 0x3a, 0x01, 0x37, 0xa2, 0x76, 0xfc, 0x53, 0x50, 0xc0, 0x84, 0x9b, 0xc6,
+0x6b, 0x4e, 0xba, 0x8c, 0x21, 0x4f, 0xa2, 0x8e, 0x55, 0x62, 0x91, 0xf3, 0x69, 0x15, 0xd8, 0xbc,
+0x88, 0xe3, 0xc4, 0xaa, 0x0b, 0xfd, 0xef, 0xa8, 0xe9, 0x4b, 0x55, 0x2a, 0x06, 0x20, 0x6d, 0x55,
+0x78, 0x29, 0x19, 0xee, 0x5f, 0x30, 0x5c, 0x4b, 0x24, 0x11, 0x55, 0xff, 0x24, 0x9a, 0x6e, 0x5e,
+0x2a, 0x2b, 0xee, 0x0b, 0x4d, 0x9f, 0x7f, 0xf7, 0x01, 0x38, 0x94, 0x14, 0x95, 0x43, 0x07, 0x09,
+0xfb, 0x60, 0xa9, 0xee, 0x1c, 0xab, 0x12, 0x8c, 0xa0, 0x9a, 0x5e, 0xa7, 0x98, 0x6a, 0x59, 0x6d,
+0x8b, 0x3f, 0x08, 0xfb, 0xc8, 0xd1, 0x45, 0xaf, 0x18, 0x15, 0x64, 0x90, 0x12, 0x0f, 0x73, 0x28,
+0x2e, 0xc5, 0xe2, 0x24, 0x4e, 0xfc, 0x58, 0xec, 0xf0, 0xf4, 0x45, 0xfe, 0x22, 0xb3, 0xeb, 0x2f,
+0x8e, 0xd2, 0xd9, 0x45, 0x61, 0x05, 0xc1, 0x97, 0x6f, 0xa8, 0x76, 0x72, 0x8f, 0x8b, 0x8c, 0x36,
+0xaf, 0xbf, 0x0d, 0x05, 0xce, 0x71, 0x8d, 0xe6, 0xa6, 0x6f, 0x1f, 0x6c, 0xa6, 0x71, 0x62, 0xc5,
+0xd8, 0xd0, 0x83, 0x72, 0x0c, 0xf1, 0x67, 0x11, 0x89, 0x0c, 0x9c, 0x13, 0x4c, 0x72, 0x34, 0xdf,
+0xbc, 0xd5, 0x71, 0xdf, 0xaa, 0x71, 0xdd, 0xe1, 0xb9, 0x6c, 0x8c, 0x3c, 0x12, 0x5d, 0x65, 0xda,
+0xbd, 0x57, 0x12, 0xb6, 0x43, 0x6b, 0xff, 0xe5, 0xde, 0x4d, 0x66, 0x11, 0x51, 0xcf, 0x99, 0xae,
+0xec, 0x17, 0xb6, 0xe8, 0x71, 0x91, 0x8c, 0xde, 0x49, 0xfe, 0xdd, 0x35, 0x71, 0xa2, 0x15, 0x27,
+0x94, 0x1c, 0xcf, 0x61, 0xe3, 0x26, 0xbb, 0x6f, 0xa3, 0x67, 0x25, 0x21, 0x5d, 0xe6, 0xdd, 0x1d,
+0x0b, 0x2e, 0x68, 0x1b, 0x3b, 0x82, 0xaf, 0xec, 0x83, 0x67, 0x85, 0xd4, 0x98, 0x51, 0x74, 0xb1,
+0xb9, 0x99, 0x80, 0x89, 0xff, 0x7f, 0x78, 0x19, 0x5c, 0x79, 0x4a, 0x60, 0x2e, 0x92, 0x40, 0xae,
+0x4c, 0x37, 0x2a, 0x2c, 0xc9, 0xc7, 0x62, 0xc8, 0x0e, 0x5d, 0xf7, 0x36, 0x5b, 0xca, 0xe0, 0x25,
+0x25, 0x01, 0xb4, 0xdd, 0x1a, 0x07, 0x9c, 0x77, 0x00, 0x3f, 0xd0, 0xdc, 0xd5, 0xec, 0x3d, 0xd4,
+0xfa, 0xbb, 0x3f, 0xcc, 0x85, 0xd6, 0x6f, 0x7f, 0xa9, 0x2d, 0xdf, 0xb9, 0x02, 0xf7, 0xf5, 0x97,
+0x9a, 0xb5, 0x35, 0xda, 0xc3, 0x67, 0xb0, 0x87, 0x4a, 0xa9, 0x28, 0x9e, 0x23, 0x8e, 0xff, 0x5c,
+0x27, 0x6b, 0xe1, 0xb0, 0x4f, 0xf3, 0x07, 0xee, 0x00, 0x2e, 0xd4, 0x59, 0x87, 0xcb, 0x52, 0x41,
+0x95, 0xea, 0xf4, 0x47, 0xd7, 0xee, 0x64, 0x41, 0x55, 0x7c, 0x8d, 0x59, 0x02, 0x95, 0xdd, 0x62,
+0x9d, 0xc2, 0xb9, 0xee, 0x5a, 0x28, 0x74, 0x84, 0xa5, 0x9b, 0xb7, 0x90, 0xc7, 0x0c, 0x07, 0xdf,
+0xf5, 0x89, 0x36, 0x74, 0x32, 0xd6, 0x28, 0xc1, 0xb0, 0xb0, 0x0b, 0xe0, 0x9c, 0x4c, 0xc3, 0x1c,
+0xd6, 0xfc, 0xe3, 0x69, 0xb5, 0x47, 0x46, 0x81, 0x2f, 0xa2, 0x82, 0xab, 0xd3, 0x63, 0x44, 0x70,
+0xc4, 0x8d, 0xff, 0x2d, 0x33, 0xba, 0xad, 0x8f, 0x7b, 0xb5, 0x70, 0x88, 0xae, 0x3e, 0x19, 0xcf,
+0x40, 0x28, 0xd8, 0xfc, 0xc8, 0x90, 0xbb, 0x5d, 0x99, 0x22, 0xf5, 0x52, 0xe6, 0x58, 0xc5, 0x1f,
+0x88, 0x31, 0x43, 0xee, 0x88, 0x1d, 0xd7, 0xc6, 0x8e, 0x3c, 0x43, 0x6a, 0x1d, 0xa7, 0x18, 0xde,
+0x7d, 0x3d, 0x16, 0xf1, 0x62, 0xf9, 0xca, 0x90, 0xa8, 0xfd, 0x30, 0x82, 0x02, 0x8f, 0x30, 0x82,
+0x02, 0x15, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x5c, 0x8b, 0x99, 0xc5, 0x5a, 0x94, 0xc5,
+0xd2, 0x71, 0x56, 0xde, 0xcd, 0x89, 0x80, 0xcc, 0x26, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
+0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
+0x4e, 0x65, 0x77, 0x20, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03,
+0x55, 0x04, 0x07, 0x13, 0x0b, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x20, 0x43, 0x69, 0x74, 0x79,
+0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55,
+0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x55, 0x53, 0x45, 0x52, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x43, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31, 0x38, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a,
+0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
+0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x4e, 0x65, 0x77, 0x20, 0x4a,
+0x65, 0x72, 0x73, 0x65, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0b,
+0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52,
+0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x2e, 0x30, 0x2c, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x55, 0x53, 0x45, 0x52, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+0x45, 0x43, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x76, 0x30, 0x10, 0x06,
+0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03,
+0x62, 0x00, 0x04, 0x1a, 0xac, 0x54, 0x5a, 0xa9, 0xf9, 0x68, 0x23, 0xe7, 0x7a, 0xd5, 0x24, 0x6f,
+0x53, 0xc6, 0x5a, 0xd8, 0x4b, 0xab, 0xc6, 0xd5, 0xb6, 0xd1, 0xe6, 0x73, 0x71, 0xae, 0xdd, 0x9c,
+0xd6, 0x0c, 0x61, 0xfd, 0xdb, 0xa0, 0x89, 0x03, 0xb8, 0x05, 0x14, 0xec, 0x57, 0xce, 0xee, 0x5d,
+0x3f, 0xe2, 0x21, 0xb3, 0xce, 0xf7, 0xd4, 0x8a, 0x79, 0xe0, 0xa3, 0x83, 0x7e, 0x2d, 0x97, 0xd0,
+0x61, 0xc4, 0xf1, 0x99, 0xdc, 0x25, 0x91, 0x63, 0xab, 0x7f, 0x30, 0xa3, 0xb4, 0x70, 0xe2, 0xc7,
+0xa1, 0x33, 0x9c, 0xf3, 0xbf, 0x2e, 0x5c, 0x53, 0xb1, 0x5f, 0xb3, 0x7d, 0x32, 0x7f, 0x8a, 0x34,
+0xe3, 0x79, 0x79, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+0x04, 0x14, 0x3a, 0xe1, 0x09, 0x86, 0xd4, 0xcf, 0x19, 0xc2, 0x96, 0x76, 0x74, 0x49, 0x76, 0xdc,
+0xe0, 0x35, 0xc6, 0x63, 0x63, 0x9a, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+0x04, 0x03, 0x03, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x30, 0x36, 0x67, 0xa1, 0x16, 0x08, 0xdc,
+0xe4, 0x97, 0x00, 0x41, 0x1d, 0x4e, 0xbe, 0xe1, 0x63, 0x01, 0xcf, 0x3b, 0xaa, 0x42, 0x11, 0x64,
+0xa0, 0x9d, 0x94, 0x39, 0x02, 0x11, 0x79, 0x5c, 0x7b, 0x1d, 0xfa, 0x64, 0xb9, 0xee, 0x16, 0x42,
+0xb3, 0xbf, 0x8a, 0xc2, 0x09, 0xc4, 0xec, 0xe4, 0xb1, 0x4d, 0x02, 0x31, 0x00, 0xe9, 0x2a, 0x61,
+0x47, 0x8c, 0x52, 0x4a, 0x4b, 0x4e, 0x18, 0x70, 0xf6, 0xd6, 0x44, 0xd6, 0x6e, 0xf5, 0x83, 0xba,
+0x6d, 0x58, 0xbd, 0x24, 0xd9, 0x56, 0x48, 0xea, 0xef, 0xc4, 0xa2, 0x46, 0x81, 0x88, 0x6a, 0x3a,
+0x46, 0xd1, 0xa9, 0x9b, 0x4d, 0xc9, 0x61, 0xda, 0xd1, 0x5d, 0x57, 0x6a, 0x18, 0x30, 0x82, 0x04,
+0x91, 0x30, 0x82, 0x03, 0x79, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x45, 0x6b, 0x50, 0x54,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
+0x81, 0xb0, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73,
+0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x13, 0x30, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65,
+0x74, 0x2f, 0x43, 0x50, 0x53, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f,
+0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
+0x63, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x28, 0x63, 0x29,
+0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49,
+0x6e, 0x63, 0x2e, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x45, 0x6e,
+0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x32, 0x37, 0x32, 0x30, 0x32, 0x33,
+0x34, 0x32, 0x5a, 0x17, 0x0d, 0x32, 0x36, 0x31, 0x31, 0x32, 0x37, 0x32, 0x30, 0x35, 0x33, 0x34,
+0x32, 0x5a, 0x30, 0x81, 0xb0, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74,
+0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03,
+0x55, 0x04, 0x0b, 0x13, 0x30, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74,
+0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6f,
+0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x65,
+0x72, 0x65, 0x6e, 0x63, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16,
+0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74,
+0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+0x24, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65,
+0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
+0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb6, 0x95, 0xb6, 0x43, 0x42, 0xfa, 0xc6, 0x6d, 0x2a, 0x6f,
+0x48, 0xdf, 0x94, 0x4c, 0x39, 0x57, 0x05, 0xee, 0xc3, 0x79, 0x11, 0x41, 0x68, 0x36, 0xed, 0xec,
+0xfe, 0x9a, 0x01, 0x8f, 0xa1, 0x38, 0x28, 0xfc, 0xf7, 0x10, 0x46, 0x66, 0x2e, 0x4d, 0x1e, 0x1a,
+0xb1, 0x1a, 0x4e, 0xc6, 0xd1, 0xc0, 0x95, 0x88, 0xb0, 0xc9, 0xff, 0x31, 0x8b, 0x33, 0x03, 0xdb,
+0xb7, 0x83, 0x7b, 0x3e, 0x20, 0x84, 0x5e, 0xed, 0xb2, 0x56, 0x28, 0xa7, 0xf8, 0xe0, 0xb9, 0x40,
+0x71, 0x37, 0xc5, 0xcb, 0x47, 0x0e, 0x97, 0x2a, 0x68, 0xc0, 0x22, 0x95, 0x62, 0x15, 0xdb, 0x47,
+0xd9, 0xf5, 0xd0, 0x2b, 0xff, 0x82, 0x4b, 0xc9, 0xad, 0x3e, 0xde, 0x4c, 0xdb, 0x90, 0x80, 0x50,
+0x3f, 0x09, 0x8a, 0x84, 0x00, 0xec, 0x30, 0x0a, 0x3d, 0x18, 0xcd, 0xfb, 0xfd, 0x2a, 0x59, 0x9a,
+0x23, 0x95, 0x17, 0x2c, 0x45, 0x9e, 0x1f, 0x6e, 0x43, 0x79, 0x6d, 0x0c, 0x5c, 0x98, 0xfe, 0x48,
+0xa7, 0xc5, 0x23, 0x47, 0x5c, 0x5e, 0xfd, 0x6e, 0xe7, 0x1e, 0xb4, 0xf6, 0x68, 0x45, 0xd1, 0x86,
+0x83, 0x5b, 0xa2, 0x8a, 0x8d, 0xb1, 0xe3, 0x29, 0x80, 0xfe, 0x25, 0x71, 0x88, 0xad, 0xbe, 0xbc,
+0x8f, 0xac, 0x52, 0x96, 0x4b, 0xaa, 0x51, 0x8d, 0xe4, 0x13, 0x31, 0x19, 0xe8, 0x4e, 0x4d, 0x9f,
+0xdb, 0xac, 0xb3, 0x6a, 0xd5, 0xbc, 0x39, 0x54, 0x71, 0xca, 0x7a, 0x7a, 0x7f, 0x90, 0xdd, 0x7d,
+0x1d, 0x80, 0xd9, 0x81, 0xbb, 0x59, 0x26, 0xc2, 0x11, 0xfe, 0xe6, 0x93, 0xe2, 0xf7, 0x80, 0xe4,
+0x65, 0xfb, 0x34, 0x37, 0x0e, 0x29, 0x80, 0x70, 0x4d, 0xaf, 0x38, 0x86, 0x2e, 0x9e, 0x7f, 0x57,
+0xaf, 0x9e, 0x17, 0xae, 0xeb, 0x1c, 0xcb, 0x28, 0x21, 0x5f, 0xb6, 0x1c, 0xd8, 0xe7, 0xa2, 0x04,
+0x22, 0xf9, 0xd3, 0xda, 0xd8, 0xcb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xb0, 0x30, 0x81,
+0xad, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01,
+0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x1d, 0x10, 0x04, 0x24, 0x30, 0x22, 0x80, 0x0f, 0x32,
+0x30, 0x30, 0x36, 0x31, 0x31, 0x32, 0x37, 0x32, 0x30, 0x32, 0x33, 0x34, 0x32, 0x5a, 0x81, 0x0f,
+0x32, 0x30, 0x32, 0x36, 0x31, 0x31, 0x32, 0x37, 0x32, 0x30, 0x35, 0x33, 0x34, 0x32, 0x5a, 0x30,
+0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x68, 0x90, 0xe4, 0x67,
+0xa4, 0xa6, 0x53, 0x80, 0xc7, 0x86, 0x66, 0xa4, 0xf1, 0xf7, 0x4b, 0x43, 0xfb, 0x84, 0xbd, 0x6d,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x68, 0x90, 0xe4, 0x67, 0xa4,
+0xa6, 0x53, 0x80, 0xc7, 0x86, 0x66, 0xa4, 0xf1, 0xf7, 0x4b, 0x43, 0xfb, 0x84, 0xbd, 0x6d, 0x30,
+0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf6, 0x7d, 0x07, 0x41, 0x00, 0x04, 0x10, 0x30, 0x0e,
+0x1b, 0x08, 0x56, 0x37, 0x2e, 0x31, 0x3a, 0x34, 0x2e, 0x30, 0x03, 0x02, 0x04, 0x90, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01,
+0x01, 0x00, 0x93, 0xd4, 0x30, 0xb0, 0xd7, 0x03, 0x20, 0x2a, 0xd0, 0xf9, 0x63, 0xe8, 0x91, 0x0c,
+0x05, 0x20, 0xa9, 0x5f, 0x19, 0xca, 0x7b, 0x72, 0x4e, 0xd4, 0xb1, 0xdb, 0xd0, 0x96, 0xfb, 0x54,
+0x5a, 0x19, 0x2c, 0x0c, 0x08, 0xf7, 0xb2, 0xbc, 0x85, 0xa8, 0x9d, 0x7f, 0x6d, 0x3b, 0x52, 0xb3,
+0x2a, 0xdb, 0xe7, 0xd4, 0x84, 0x8c, 0x63, 0xf6, 0x0f, 0xcb, 0x26, 0x01, 0x91, 0x50, 0x6c, 0xf4,
+0x5f, 0x14, 0xe2, 0x93, 0x74, 0xc0, 0x13, 0x9e, 0x30, 0x3a, 0x50, 0xe3, 0xb4, 0x60, 0xc5, 0x1c,
+0xf0, 0x22, 0x44, 0x8d, 0x71, 0x47, 0xac, 0xc8, 0x1a, 0xc9, 0xe9, 0x9b, 0x9a, 0x00, 0x60, 0x13,
+0xff, 0x70, 0x7e, 0x5f, 0x11, 0x4d, 0x49, 0x1b, 0xb3, 0x15, 0x52, 0x7b, 0xc9, 0x54, 0xda, 0xbf,
+0x9d, 0x95, 0xaf, 0x6b, 0x9a, 0xd8, 0x9e, 0xe9, 0xf1, 0xe4, 0x43, 0x8d, 0xe2, 0x11, 0x44, 0x3a,
+0xbf, 0xaf, 0xbd, 0x83, 0x42, 0x73, 0x52, 0x8b, 0xaa, 0xbb, 0xa7, 0x29, 0xcf, 0xf5, 0x64, 0x1c,
+0x0a, 0x4d, 0xd1, 0xbc, 0xaa, 0xac, 0x9f, 0x2a, 0xd0, 0xff, 0x7f, 0x7f, 0xda, 0x7d, 0xea, 0xb1,
+0xed, 0x30, 0x25, 0xc1, 0x84, 0xda, 0x34, 0xd2, 0x5b, 0x78, 0x83, 0x56, 0xec, 0x9c, 0x36, 0xc3,
+0x26, 0xe2, 0x11, 0xf6, 0x67, 0x49, 0x1d, 0x92, 0xab, 0x8c, 0xfb, 0xeb, 0xff, 0x7a, 0xee, 0x85,
+0x4a, 0xa7, 0x50, 0x80, 0xf0, 0xa7, 0x5c, 0x4a, 0x94, 0x2e, 0x5f, 0x05, 0x99, 0x3c, 0x52, 0x41,
+0xe0, 0xcd, 0xb4, 0x63, 0xcf, 0x01, 0x43, 0xba, 0x9c, 0x83, 0xdc, 0x8f, 0x60, 0x3b, 0xf3, 0x5a,
+0xb4, 0xb4, 0x7b, 0xae, 0xda, 0x0b, 0x90, 0x38, 0x75, 0xef, 0x81, 0x1d, 0x66, 0xd2, 0xf7, 0x57,
+0x70, 0x36, 0xb3, 0xbf, 0xfc, 0x28, 0xaf, 0x71, 0x25, 0x85, 0x5b, 0x13, 0xfe, 0x1e, 0x7f, 0x5a,
+0xb4, 0x3c, 0x30, 0x82, 0x05, 0x56, 0x30, 0x82, 0x04, 0x3e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+0x10, 0xee, 0x2b, 0x3d, 0xeb, 0xd4, 0x21, 0xde, 0x14, 0xa8, 0x62, 0xac, 0x04, 0xf3, 0xdd, 0xc4,
+0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+0x30, 0x81, 0xf3, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53,
+0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x32, 0x41, 0x67, 0x65, 0x6e, 0x63,
+0x69, 0x61, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x61, 0x6e, 0x61, 0x20, 0x64, 0x65, 0x20, 0x43,
+0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x20, 0x28, 0x4e, 0x49, 0x46,
+0x20, 0x51, 0x2d, 0x30, 0x38, 0x30, 0x31, 0x31, 0x37, 0x36, 0x2d, 0x49, 0x29, 0x31, 0x28, 0x30,
+0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x72, 0x76, 0x65, 0x69, 0x73, 0x20,
+0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x73, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x31, 0x35, 0x30, 0x33, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x13, 0x2c, 0x56, 0x65, 0x67, 0x65, 0x75, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
+0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x74, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
+0x76, 0x65, 0x72, 0x61, 0x72, 0x72, 0x65, 0x6c, 0x20, 0x28, 0x63, 0x29, 0x30, 0x33, 0x31, 0x35,
+0x30, 0x33, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2c, 0x4a, 0x65, 0x72, 0x61, 0x72, 0x71, 0x75,
+0x69, 0x61, 0x20, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x61, 0x74, 0x73, 0x20, 0x64, 0x65, 0x20, 0x43,
+0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x20, 0x43, 0x61, 0x74, 0x61,
+0x6c, 0x61, 0x6e, 0x65, 0x73, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06,
+0x45, 0x43, 0x2d, 0x41, 0x43, 0x43, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x33, 0x30, 0x31, 0x30, 0x37,
+0x32, 0x33, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x31, 0x30, 0x37, 0x32,
+0x32, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xf3, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x32, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x61, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x61, 0x6e,
+0x61, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69,
+0x6f, 0x20, 0x28, 0x4e, 0x49, 0x46, 0x20, 0x51, 0x2d, 0x30, 0x38, 0x30, 0x31, 0x31, 0x37, 0x36,
+0x2d, 0x49, 0x29, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65,
+0x72, 0x76, 0x65, 0x69, 0x73, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x73, 0x20, 0x64, 0x65,
+0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x31, 0x35, 0x30,
+0x33, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2c, 0x56, 0x65, 0x67, 0x65, 0x75, 0x20, 0x68, 0x74,
+0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x74, 0x63, 0x65, 0x72,
+0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x65, 0x72, 0x61, 0x72, 0x72, 0x65, 0x6c, 0x20, 0x28,
+0x63, 0x29, 0x30, 0x33, 0x31, 0x35, 0x30, 0x33, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2c, 0x4a,
+0x65, 0x72, 0x61, 0x72, 0x71, 0x75, 0x69, 0x61, 0x20, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x61, 0x74,
+0x73, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69,
+0x6f, 0x20, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x61, 0x6e, 0x65, 0x73, 0x31, 0x0f, 0x30, 0x0d, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x45, 0x43, 0x2d, 0x41, 0x43, 0x43, 0x30, 0x82, 0x01, 0x22,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb3, 0x22, 0xc7,
+0x4f, 0xe2, 0x97, 0x42, 0x95, 0x88, 0x47, 0x83, 0x40, 0xf6, 0x1d, 0x17, 0xf3, 0x83, 0x73, 0x24,
+0x1e, 0x51, 0xf3, 0x98, 0x8a, 0xc3, 0x92, 0xb8, 0xff, 0x40, 0x90, 0x05, 0x70, 0x87, 0x60, 0xc9,
+0x00, 0xa9, 0xb5, 0x94, 0x65, 0x19, 0x22, 0x15, 0x17, 0xc2, 0x43, 0x6c, 0x66, 0x44, 0x9a, 0x0d,
+0x04, 0x3e, 0x39, 0x6f, 0xa5, 0x4b, 0x7a, 0xaa, 0x63, 0xb7, 0x8a, 0x44, 0x9d, 0xd9, 0x63, 0x91,
+0x84, 0x66, 0xe0, 0x28, 0x0f, 0xba, 0x42, 0xe3, 0x6e, 0x8e, 0xf7, 0x14, 0x27, 0x93, 0x69, 0xee,
+0x91, 0x0e, 0xa3, 0x5f, 0x0e, 0xb1, 0xeb, 0x66, 0xa2, 0x72, 0x4f, 0x12, 0x13, 0x86, 0x65, 0x7a,
+0x3e, 0xdb, 0x4f, 0x07, 0xf4, 0xa7, 0x09, 0x60, 0xda, 0x3a, 0x42, 0x99, 0xc7, 0xb2, 0x7f, 0xb3,
+0x16, 0x95, 0x1c, 0xc7, 0xf9, 0x34, 0xb5, 0x94, 0x85, 0xd5, 0x99, 0x5e, 0xa0, 0x48, 0xa0, 0x7e,
+0xe7, 0x17, 0x65, 0xb8, 0xa2, 0x75, 0xb8, 0x1e, 0xf3, 0xe5, 0x42, 0x7d, 0xaf, 0xed, 0xf3, 0x8a,
+0x48, 0x64, 0x5d, 0x82, 0x14, 0x93, 0xd8, 0xc0, 0xe4, 0xff, 0xb3, 0x50, 0x72, 0xf2, 0x76, 0xf6,
+0xb3, 0x5d, 0x42, 0x50, 0x79, 0xd0, 0x94, 0x3e, 0x6b, 0x0c, 0x00, 0xbe, 0xd8, 0x6b, 0x0e, 0x4e,
+0x2a, 0xec, 0x3e, 0xd2, 0xcc, 0x82, 0xa2, 0x18, 0x65, 0x33, 0x13, 0x77, 0x9e, 0x9a, 0x5d, 0x1a,
+0x13, 0xd8, 0xc3, 0xdb, 0x3d, 0xc8, 0x97, 0x7a, 0xee, 0x70, 0xed, 0xa7, 0xe6, 0x7c, 0xdb, 0x71,
+0xcf, 0x2d, 0x94, 0x62, 0xdf, 0x6d, 0xd6, 0xf5, 0x38, 0xbe, 0x3f, 0xa5, 0x85, 0x0a, 0x19, 0xb8,
+0xa8, 0xd8, 0x09, 0x75, 0x42, 0x70, 0xc4, 0xea, 0xef, 0xcb, 0x0e, 0xc8, 0x34, 0xa8, 0x12, 0x22,
+0x98, 0x0c, 0xb8, 0x13, 0x94, 0xb6, 0x4b, 0xec, 0xf0, 0xd0, 0x90, 0xe7, 0x27, 0x02, 0x03, 0x01,
+0x00, 0x01, 0xa3, 0x81, 0xe3, 0x30, 0x81, 0xe0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04,
+0x16, 0x30, 0x14, 0x81, 0x12, 0x65, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x40, 0x63, 0x61, 0x74, 0x63,
+0x65, 0x72, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+0x16, 0x04, 0x14, 0xa0, 0xc3, 0x8b, 0x44, 0xaa, 0x37, 0xa5, 0x45, 0xbf, 0x97, 0x80, 0x5a, 0xd1,
+0xf1, 0x78, 0xa2, 0x9b, 0xe9, 0x5d, 0x8d, 0x30, 0x7f, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x78,
+0x30, 0x76, 0x30, 0x74, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xf5, 0x78, 0x01, 0x03, 0x01,
+0x0a, 0x30, 0x65, 0x30, 0x2c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16,
+0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x74,
+0x63, 0x65, 0x72, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x65, 0x72, 0x61, 0x72, 0x72, 0x65,
+0x6c, 0x30, 0x35, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x29, 0x1a,
+0x27, 0x56, 0x65, 0x67, 0x65, 0x75, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
+0x77, 0x77, 0x2e, 0x63, 0x61, 0x74, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x76,
+0x65, 0x72, 0x61, 0x72, 0x72, 0x65, 0x6c, 0x20, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa0, 0x48, 0x5b, 0x82,
+0x01, 0xf6, 0x4d, 0x48, 0xb8, 0x39, 0x55, 0x35, 0x9c, 0x80, 0x7a, 0x53, 0x99, 0xd5, 0x5a, 0xff,
+0xb1, 0x71, 0x3b, 0xcc, 0x39, 0x09, 0x94, 0x5e, 0xd6, 0xda, 0xef, 0xbe, 0x01, 0x5b, 0x5d, 0xd3,
+0x1e, 0xd8, 0xfd, 0x7d, 0x4f, 0xcd, 0xa0, 0x41, 0xe0, 0x34, 0x93, 0xbf, 0xcb, 0xe2, 0x86, 0x9c,
+0x37, 0x92, 0x90, 0x56, 0x1c, 0xdc, 0xeb, 0x29, 0x05, 0xe5, 0xc4, 0x9e, 0xc7, 0x35, 0xdf, 0x8a,
+0x0c, 0xcd, 0xc5, 0x21, 0x43, 0xe9, 0xaa, 0x88, 0xe5, 0x35, 0xc0, 0x19, 0x42, 0x63, 0x5a, 0x02,
+0x5e, 0xa4, 0x48, 0x18, 0x3a, 0x85, 0x6f, 0xdc, 0x9d, 0xbc, 0x3f, 0x9d, 0x9c, 0xc1, 0x87, 0xb8,
+0x7a, 0x61, 0x08, 0xe9, 0x77, 0x0b, 0x7f, 0x70, 0xab, 0x7a, 0xdd, 0xd9, 0x97, 0x2c, 0x64, 0x1e,
+0x85, 0xbf, 0xbc, 0x74, 0x96, 0xa1, 0xc3, 0x7a, 0x12, 0xec, 0x0c, 0x1a, 0x6e, 0x83, 0x0c, 0x3c,
+0xe8, 0x72, 0x46, 0x9f, 0xfb, 0x48, 0xd5, 0x5e, 0x97, 0xe6, 0xb1, 0xa1, 0xf8, 0xe4, 0xef, 0x46,
+0x25, 0x94, 0x9c, 0x89, 0xdb, 0x69, 0x38, 0xbe, 0xec, 0x5c, 0x0e, 0x56, 0xc7, 0x65, 0x51, 0xe5,
+0x50, 0x88, 0x88, 0xbf, 0x42, 0xd5, 0x2b, 0x3d, 0xe5, 0xf9, 0xba, 0x9e, 0x2e, 0xb3, 0xca, 0xf4,
+0x73, 0x92, 0x02, 0x0b, 0xbe, 0x4c, 0x66, 0xeb, 0x20, 0xfe, 0xb9, 0xcb, 0xb5, 0x99, 0x7f, 0xe6,
+0xb6, 0x13, 0xfa, 0xca, 0x4b, 0x4d, 0xd9, 0xee, 0x53, 0x46, 0x06, 0x3b, 0xc6, 0x4e, 0xad, 0x93,
+0x5a, 0x81, 0x7e, 0x6c, 0x2a, 0x4b, 0x6a, 0x05, 0x45, 0x8c, 0xf2, 0x21, 0xa4, 0x31, 0x90, 0x87,
+0x6c, 0x65, 0x9c, 0x9d, 0xa5, 0x60, 0x95, 0x3a, 0x52, 0x7f, 0xf5, 0xd1, 0xab, 0x08, 0x6e, 0xf3,
+0xee, 0x5b, 0xf9, 0x88, 0x3d, 0x7e, 0xb8, 0x6f, 0x6e, 0x03, 0xe4, 0x42, 0x30, 0x82, 0x04, 0x2a,
+0x30, 0x82, 0x03, 0x12, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x38, 0x63, 0xde, 0xf8, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
+0xb4, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x45, 0x6e, 0x74, 0x72,
+0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x31, 0x40, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x14, 0x37, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65,
+0x74, 0x2f, 0x43, 0x50, 0x53, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72,
+0x70, 0x2e, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x2e, 0x20, 0x28, 0x6c, 0x69, 0x6d, 0x69,
+0x74, 0x73, 0x20, 0x6c, 0x69, 0x61, 0x62, 0x2e, 0x29, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x13, 0x1c, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x45, 0x6e, 0x74,
+0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64,
+0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2a, 0x45, 0x6e, 0x74, 0x72, 0x75,
+0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x28,
+0x32, 0x30, 0x34, 0x38, 0x29, 0x30, 0x1e, 0x17, 0x0d, 0x39, 0x39, 0x31, 0x32, 0x32, 0x34, 0x31,
+0x37, 0x35, 0x30, 0x35, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x37, 0x32, 0x34, 0x31, 0x34,
+0x31, 0x35, 0x31, 0x32, 0x5a, 0x30, 0x81, 0xb4, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x0b, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x31, 0x40,
+0x30, 0x3e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x14, 0x37, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74,
+0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x5f, 0x32, 0x30, 0x34,
+0x38, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66,
+0x2e, 0x20, 0x28, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x20, 0x6c, 0x69, 0x61, 0x62, 0x2e, 0x29,
+0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1c, 0x28, 0x63, 0x29, 0x20, 0x31,
+0x39, 0x39, 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20,
+0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x2a, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x43, 0x65,
+0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x28, 0x32, 0x30, 0x34, 0x38, 0x29, 0x30, 0x82, 0x01, 0x22,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xad, 0x4d, 0x4b,
+0xa9, 0x12, 0x86, 0xb2, 0xea, 0xa3, 0x20, 0x07, 0x15, 0x16, 0x64, 0x2a, 0x2b, 0x4b, 0xd1, 0xbf,
+0x0b, 0x4a, 0x4d, 0x8e, 0xed, 0x80, 0x76, 0xa5, 0x67, 0xb7, 0x78, 0x40, 0xc0, 0x73, 0x42, 0xc8,
+0x68, 0xc0, 0xdb, 0x53, 0x2b, 0xdd, 0x5e, 0xb8, 0x76, 0x98, 0x35, 0x93, 0x8b, 0x1a, 0x9d, 0x7c,
+0x13, 0x3a, 0x0e, 0x1f, 0x5b, 0xb7, 0x1e, 0xcf, 0xe5, 0x24, 0x14, 0x1e, 0xb1, 0x81, 0xa9, 0x8d,
+0x7d, 0xb8, 0xcc, 0x6b, 0x4b, 0x03, 0xf1, 0x02, 0x0c, 0xdc, 0xab, 0xa5, 0x40, 0x24, 0x00, 0x7f,
+0x74, 0x94, 0xa1, 0x9d, 0x08, 0x29, 0xb3, 0x88, 0x0b, 0xf5, 0x87, 0x77, 0x9d, 0x55, 0xcd, 0xe4,
+0xc3, 0x7e, 0xd7, 0x6a, 0x64, 0xab, 0x85, 0x14, 0x86, 0x95, 0x5b, 0x97, 0x32, 0x50, 0x6f, 0x3d,
+0xc8, 0xba, 0x66, 0x0c, 0xe3, 0xfc, 0xbd, 0xb8, 0x49, 0xc1, 0x76, 0x89, 0x49, 0x19, 0xfd, 0xc0,
+0xa8, 0xbd, 0x89, 0xa3, 0x67, 0x2f, 0xc6, 0x9f, 0xbc, 0x71, 0x19, 0x60, 0xb8, 0x2d, 0xe9, 0x2c,
+0xc9, 0x90, 0x76, 0x66, 0x7b, 0x94, 0xe2, 0xaf, 0x78, 0xd6, 0x65, 0x53, 0x5d, 0x3c, 0xd6, 0x9c,
+0xb2, 0xcf, 0x29, 0x03, 0xf9, 0x2f, 0xa4, 0x50, 0xb2, 0xd4, 0x48, 0xce, 0x05, 0x32, 0x55, 0x8a,
+0xfd, 0xb2, 0x64, 0x4c, 0x0e, 0xe4, 0x98, 0x07, 0x75, 0xdb, 0x7f, 0xdf, 0xb9, 0x08, 0x55, 0x60,
+0x85, 0x30, 0x29, 0xf9, 0x7b, 0x48, 0xa4, 0x69, 0x86, 0xe3, 0x35, 0x3f, 0x1e, 0x86, 0x5d, 0x7a,
+0x7a, 0x15, 0xbd, 0xef, 0x00, 0x8e, 0x15, 0x22, 0x54, 0x17, 0x00, 0x90, 0x26, 0x93, 0xbc, 0x0e,
+0x49, 0x68, 0x91, 0xbf, 0xf8, 0x47, 0xd3, 0x9d, 0x95, 0x42, 0xc1, 0x0e, 0x4d, 0xdf, 0x6f, 0x26,
+0xcf, 0xc3, 0x18, 0x21, 0x62, 0x66, 0x43, 0x70, 0xd6, 0xd5, 0xc0, 0x07, 0xe1, 0x02, 0x03, 0x01,
+0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+0x04, 0x14, 0x55, 0xe4, 0x81, 0xd1, 0x11, 0x80, 0xbe, 0xd8, 0x89, 0xb9, 0x08, 0xa3, 0x31, 0xf9,
+0xa1, 0x24, 0x09, 0x16, 0xb9, 0x70, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3b, 0x9b, 0x8f, 0x56, 0x9b, 0x30,
+0xe7, 0x53, 0x99, 0x7c, 0x7a, 0x79, 0xa7, 0x4d, 0x97, 0xd7, 0x19, 0x95, 0x90, 0xfb, 0x06, 0x1f,
+0xca, 0x33, 0x7c, 0x46, 0x63, 0x8f, 0x96, 0x66, 0x24, 0xfa, 0x40, 0x1b, 0x21, 0x27, 0xca, 0xe6,
+0x72, 0x73, 0xf2, 0x4f, 0xfe, 0x31, 0x99, 0xfd, 0xc8, 0x0c, 0x4c, 0x68, 0x53, 0xc6, 0x80, 0x82,
+0x13, 0x98, 0xfa, 0xb6, 0xad, 0xda, 0x5d, 0x3d, 0xf1, 0xce, 0x6e, 0xf6, 0x15, 0x11, 0x94, 0x82,
+0x0c, 0xee, 0x3f, 0x95, 0xaf, 0x11, 0xab, 0x0f, 0xd7, 0x2f, 0xde, 0x1f, 0x03, 0x8f, 0x57, 0x2c,
+0x1e, 0xc9, 0xbb, 0x9a, 0x1a, 0x44, 0x95, 0xeb, 0x18, 0x4f, 0xa6, 0x1f, 0xcd, 0x7d, 0x57, 0x10,
+0x2f, 0x9b, 0x04, 0x09, 0x5a, 0x84, 0xb5, 0x6e, 0xd8, 0x1d, 0x3a, 0xe1, 0xd6, 0x9e, 0xd1, 0x6c,
+0x79, 0x5e, 0x79, 0x1c, 0x14, 0xc5, 0xe3, 0xd0, 0x4c, 0x93, 0x3b, 0x65, 0x3c, 0xed, 0xdf, 0x3d,
+0xbe, 0xa6, 0xe5, 0x95, 0x1a, 0xc3, 0xb5, 0x19, 0xc3, 0xbd, 0x5e, 0x5b, 0xbb, 0xff, 0x23, 0xef,
+0x68, 0x19, 0xcb, 0x12, 0x93, 0x27, 0x5c, 0x03, 0x2d, 0x6f, 0x30, 0xd0, 0x1e, 0xb6, 0x1a, 0xac,
+0xde, 0x5a, 0xf7, 0xd1, 0xaa, 0xa8, 0x27, 0xa6, 0xfe, 0x79, 0x81, 0xc4, 0x79, 0x99, 0x33, 0x57,
+0xba, 0x12, 0xb0, 0xa9, 0xe0, 0x42, 0x6c, 0x93, 0xca, 0x56, 0xde, 0xfe, 0x6d, 0x84, 0x0b, 0x08,
+0x8b, 0x7e, 0x8d, 0xea, 0xd7, 0x98, 0x21, 0xc6, 0xf3, 0xe7, 0x3c, 0x79, 0x2f, 0x5e, 0x9c, 0xd1,
+0x4c, 0x15, 0x8d, 0xe1, 0xec, 0x22, 0x37, 0xcc, 0x9a, 0x43, 0x0b, 0x97, 0xdc, 0x80, 0x90, 0x8d,
+0xb3, 0x67, 0x9b, 0x6f, 0x48, 0x08, 0x15, 0x56, 0xcf, 0xbf, 0xf1, 0x2b, 0x7c, 0x5e, 0x9a, 0x76,
+0xe9, 0x59, 0x90, 0xc5, 0x7c, 0x83, 0x35, 0x11, 0x65, 0x51, 0x30, 0x82, 0x04, 0x32, 0x30, 0x82,
+0x03, 0x1a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x7b, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
+0x08, 0x0c, 0x12, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x63, 0x68,
+0x65, 0x73, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07,
+0x53, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x0c, 0x11, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69,
+0x74, 0x65, 0x64, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x18, 0x41, 0x41,
+0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x65,
+0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x31, 0x30, 0x31,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x31, 0x32, 0x33, 0x31, 0x32,
+0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x7b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x12,
+0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x73, 0x74,
+0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x61, 0x6c,
+0x66, 0x6f, 0x72, 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x11, 0x43,
+0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64,
+0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x18, 0x41, 0x41, 0x41, 0x20, 0x43,
+0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69,
+0x63, 0x65, 0x73, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
+0x82, 0x01, 0x01, 0x00, 0xbe, 0x40, 0x9d, 0xf4, 0x6e, 0xe1, 0xea, 0x76, 0x87, 0x1c, 0x4d, 0x45,
+0x44, 0x8e, 0xbe, 0x46, 0xc8, 0x83, 0x06, 0x9d, 0xc1, 0x2a, 0xfe, 0x18, 0x1f, 0x8e, 0xe4, 0x02,
+0xfa, 0xf3, 0xab, 0x5d, 0x50, 0x8a, 0x16, 0x31, 0x0b, 0x9a, 0x06, 0xd0, 0xc5, 0x70, 0x22, 0xcd,
+0x49, 0x2d, 0x54, 0x63, 0xcc, 0xb6, 0x6e, 0x68, 0x46, 0x0b, 0x53, 0xea, 0xcb, 0x4c, 0x24, 0xc0,
+0xbc, 0x72, 0x4e, 0xea, 0xf1, 0x15, 0xae, 0xf4, 0x54, 0x9a, 0x12, 0x0a, 0xc3, 0x7a, 0xb2, 0x33,
+0x60, 0xe2, 0xda, 0x89, 0x55, 0xf3, 0x22, 0x58, 0xf3, 0xde, 0xdc, 0xcf, 0xef, 0x83, 0x86, 0xa2,
+0x8c, 0x94, 0x4f, 0x9f, 0x68, 0xf2, 0x98, 0x90, 0x46, 0x84, 0x27, 0xc7, 0x76, 0xbf, 0xe3, 0xcc,
+0x35, 0x2c, 0x8b, 0x5e, 0x07, 0x64, 0x65, 0x82, 0xc0, 0x48, 0xb0, 0xa8, 0x91, 0xf9, 0x61, 0x9f,
+0x76, 0x20, 0x50, 0xa8, 0x91, 0xc7, 0x66, 0xb5, 0xeb, 0x78, 0x62, 0x03, 0x56, 0xf0, 0x8a, 0x1a,
+0x13, 0xea, 0x31, 0xa3, 0x1e, 0xa0, 0x99, 0xfd, 0x38, 0xf6, 0xf6, 0x27, 0x32, 0x58, 0x6f, 0x07,
+0xf5, 0x6b, 0xb8, 0xfb, 0x14, 0x2b, 0xaf, 0xb7, 0xaa, 0xcc, 0xd6, 0x63, 0x5f, 0x73, 0x8c, 0xda,
+0x05, 0x99, 0xa8, 0x38, 0xa8, 0xcb, 0x17, 0x78, 0x36, 0x51, 0xac, 0xe9, 0x9e, 0xf4, 0x78, 0x3a,
+0x8d, 0xcf, 0x0f, 0xd9, 0x42, 0xe2, 0x98, 0x0c, 0xab, 0x2f, 0x9f, 0x0e, 0x01, 0xde, 0xef, 0x9f,
+0x99, 0x49, 0xf1, 0x2d, 0xdf, 0xac, 0x74, 0x4d, 0x1b, 0x98, 0xb5, 0x47, 0xc5, 0xe5, 0x29, 0xd1,
+0xf9, 0x90, 0x18, 0xc7, 0x62, 0x9c, 0xbe, 0x83, 0xc7, 0x26, 0x7b, 0x3e, 0x8a, 0x25, 0xc7, 0xc0,
+0xdd, 0x9d, 0xe6, 0x35, 0x68, 0x10, 0x20, 0x9d, 0x8f, 0xd8, 0xde, 0xd2, 0xc3, 0x84, 0x9c, 0x0d,
+0x5e, 0xe8, 0x2f, 0xc9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xc0, 0x30, 0x81, 0xbd, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa0, 0x11, 0x0a, 0x23, 0x3e, 0x96,
+0xf1, 0x07, 0xec, 0xe2, 0xaf, 0x29, 0xef, 0x82, 0xa5, 0x7f, 0xd0, 0x30, 0xa4, 0xb4, 0x30, 0x0e,
+0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f,
+0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+0x7b, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x38, 0xa0, 0x36, 0xa0, 0x34,
+0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d,
+0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x41, 0x41, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
+0x2e, 0x63, 0x72, 0x6c, 0x30, 0x36, 0xa0, 0x34, 0xa0, 0x32, 0x86, 0x30, 0x68, 0x74, 0x74, 0x70,
+0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x6e, 0x65,
+0x74, 0x2f, 0x41, 0x41, 0x41, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+0x08, 0x56, 0xfc, 0x02, 0xf0, 0x9b, 0xe8, 0xff, 0xa4, 0xfa, 0xd6, 0x7b, 0xc6, 0x44, 0x80, 0xce,
+0x4f, 0xc4, 0xc5, 0xf6, 0x00, 0x58, 0xcc, 0xa6, 0xb6, 0xbc, 0x14, 0x49, 0x68, 0x04, 0x76, 0xe8,
+0xe6, 0xee, 0x5d, 0xec, 0x02, 0x0f, 0x60, 0xd6, 0x8d, 0x50, 0x18, 0x4f, 0x26, 0x4e, 0x01, 0xe3,
+0xe6, 0xb0, 0xa5, 0xee, 0xbf, 0xbc, 0x74, 0x54, 0x41, 0xbf, 0xfd, 0xfc, 0x12, 0xb8, 0xc7, 0x4f,
+0x5a, 0xf4, 0x89, 0x60, 0x05, 0x7f, 0x60, 0xb7, 0x05, 0x4a, 0xf3, 0xf6, 0xf1, 0xc2, 0xbf, 0xc4,
+0xb9, 0x74, 0x86, 0xb6, 0x2d, 0x7d, 0x6b, 0xcc, 0xd2, 0xf3, 0x46, 0xdd, 0x2f, 0xc6, 0xe0, 0x6a,
+0xc3, 0xc3, 0x34, 0x03, 0x2c, 0x7d, 0x96, 0xdd, 0x5a, 0xc2, 0x0e, 0xa7, 0x0a, 0x99, 0xc1, 0x05,
+0x8b, 0xab, 0x0c, 0x2f, 0xf3, 0x5c, 0x3a, 0xcf, 0x6c, 0x37, 0x55, 0x09, 0x87, 0xde, 0x53, 0x40,
+0x6c, 0x58, 0xef, 0xfc, 0xb6, 0xab, 0x65, 0x6e, 0x04, 0xf6, 0x1b, 0xdc, 0x3c, 0xe0, 0x5a, 0x15,
+0xc6, 0x9e, 0xd9, 0xf1, 0x59, 0x48, 0x30, 0x21, 0x65, 0x03, 0x6c, 0xec, 0xe9, 0x21, 0x73, 0xec,
+0x9b, 0x03, 0xa1, 0xe0, 0x37, 0xad, 0xa0, 0x15, 0x18, 0x8f, 0xfa, 0xba, 0x02, 0xce, 0xa7, 0x2c,
+0xa9, 0x10, 0x13, 0x2c, 0xd4, 0xe5, 0x08, 0x26, 0xab, 0x22, 0x97, 0x60, 0xf8, 0x90, 0x5e, 0x74,
+0xd4, 0xa2, 0x9a, 0x53, 0xbd, 0xf2, 0xa9, 0x68, 0xe0, 0xa2, 0x6e, 0xc2, 0xd7, 0x6c, 0xb1, 0xa3,
+0x0f, 0x9e, 0xbf, 0xeb, 0x68, 0xe7, 0x56, 0xf2, 0xae, 0xf2, 0xe3, 0x2b, 0x38, 0x3a, 0x09, 0x81,
+0xb5, 0x6b, 0x85, 0xd7, 0xbe, 0x2d, 0xed, 0x3f, 0x1a, 0xb7, 0xb2, 0x63, 0xe2, 0xf5, 0x62, 0x2c,
+0x82, 0xd4, 0x6a, 0x00, 0x41, 0x50, 0xf1, 0x39, 0x83, 0x9f, 0x95, 0xe9, 0x36, 0x96, 0x98, 0x6e,
+0x30, 0x82, 0x07, 0xd3, 0x30, 0x82, 0x05, 0xbb, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5e,
+0xc3, 0xb7, 0xa6, 0x43, 0x7f, 0xa4, 0xe0, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x42, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x0c, 0x09, 0x41, 0x43, 0x43, 0x56, 0x52, 0x41, 0x49, 0x5a, 0x31, 0x31, 0x10, 0x30, 0x0e,
+0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x50, 0x4b, 0x49, 0x41, 0x43, 0x43, 0x56, 0x31, 0x0d,
+0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x04, 0x41, 0x43, 0x43, 0x56, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31,
+0x30, 0x35, 0x30, 0x35, 0x30, 0x39, 0x33, 0x37, 0x33, 0x37, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31,
+0x32, 0x33, 0x31, 0x30, 0x39, 0x33, 0x37, 0x33, 0x37, 0x5a, 0x30, 0x42, 0x31, 0x12, 0x30, 0x10,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x41, 0x43, 0x43, 0x56, 0x52, 0x41, 0x49, 0x5a, 0x31,
+0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x50, 0x4b, 0x49, 0x41, 0x43,
+0x43, 0x56, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x04, 0x41, 0x43, 0x43,
+0x56, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x30, 0x82,
+0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0x9b,
+0xa9, 0xab, 0xbf, 0x61, 0x4a, 0x97, 0xaf, 0x2f, 0x97, 0x66, 0x9a, 0x74, 0x5f, 0xd0, 0xd9, 0x96,
+0xfd, 0xcf, 0xe2, 0xe4, 0x66, 0xef, 0x1f, 0x1f, 0x47, 0x33, 0xc2, 0x44, 0xa3, 0xdf, 0x9a, 0xde,
+0x1f, 0xb5, 0x54, 0xdd, 0x15, 0x7c, 0x69, 0x35, 0x11, 0x6f, 0xbb, 0xc8, 0x0c, 0x8e, 0x6a, 0x18,
+0x1e, 0xd8, 0x8f, 0xd9, 0x16, 0xbc, 0x10, 0x48, 0x36, 0x5c, 0xf0, 0x63, 0xb3, 0x90, 0x5a, 0x5c,
+0x24, 0x37, 0xd7, 0xa3, 0xd6, 0xcb, 0x09, 0x71, 0xb9, 0xf1, 0x01, 0x72, 0x84, 0xb0, 0x7d, 0xdb,
+0x4d, 0x80, 0xcd, 0xfc, 0xd3, 0x6f, 0xc9, 0xf8, 0xda, 0xb6, 0x0e, 0x82, 0xd2, 0x45, 0x85, 0xa8,
+0x1b, 0x68, 0xa8, 0x3d, 0xe8, 0xf4, 0x44, 0x6c, 0xbd, 0xa1, 0xc2, 0xcb, 0x03, 0xbe, 0x8c, 0x3e,
+0x13, 0x00, 0x84, 0xdf, 0x4a, 0x48, 0xc0, 0xe3, 0x22, 0x0a, 0xe8, 0xe9, 0x37, 0xa7, 0x18, 0x4c,
+0xb1, 0x09, 0x0d, 0x23, 0x56, 0x7f, 0x04, 0x4d, 0xd9, 0x17, 0x84, 0x18, 0xa5, 0xc8, 0xda, 0x40,
+0x94, 0x73, 0xeb, 0xce, 0x0e, 0x57, 0x3c, 0x03, 0x81, 0x3a, 0x9d, 0x0a, 0xa1, 0x57, 0x43, 0x69,
+0xac, 0x57, 0x6d, 0x79, 0x90, 0x78, 0xe5, 0xb5, 0xb4, 0x3b, 0xd8, 0xbc, 0x4c, 0x8d, 0x28, 0xa1,
+0xa7, 0xa3, 0xa7, 0xba, 0x02, 0x4e, 0x25, 0xd1, 0x2a, 0xae, 0xed, 0xae, 0x03, 0x22, 0xb8, 0x6b,
+0x20, 0x0f, 0x30, 0x28, 0x54, 0x95, 0x7f, 0xe0, 0xee, 0xce, 0x0a, 0x66, 0x9d, 0xd1, 0x40, 0x2d,
+0x6e, 0x22, 0xaf, 0x9d, 0x1a, 0xc1, 0x05, 0x19, 0xd2, 0x6f, 0xc0, 0xf2, 0x9f, 0xf8, 0x7b, 0xb3,
+0x02, 0x42, 0xfb, 0x50, 0xa9, 0x1d, 0x2d, 0x93, 0x0f, 0x23, 0xab, 0xc6, 0xc1, 0x0f, 0x92, 0xff,
+0xd0, 0xa2, 0x15, 0xf5, 0x53, 0x09, 0x71, 0x1c, 0xff, 0x45, 0x13, 0x84, 0xe6, 0x26, 0x5e, 0xf8,
+0xe0, 0x88, 0x1c, 0x0a, 0xfc, 0x16, 0xb6, 0xa8, 0x73, 0x06, 0xb8, 0xf0, 0x63, 0x84, 0x02, 0xa0,
+0xc6, 0x5a, 0xec, 0xe7, 0x74, 0xdf, 0x70, 0xae, 0xa3, 0x83, 0x25, 0xea, 0xd6, 0xc7, 0x97, 0x87,
+0x93, 0xa7, 0xc6, 0x8a, 0x8a, 0x33, 0x97, 0x60, 0x37, 0x10, 0x3e, 0x97, 0x3e, 0x6e, 0x29, 0x15,
+0xd6, 0xa1, 0x0f, 0xd1, 0x88, 0x2c, 0x12, 0x9f, 0x6f, 0xaa, 0xa4, 0xc6, 0x42, 0xeb, 0x41, 0xa2,
+0xe3, 0x95, 0x43, 0xd3, 0x01, 0x85, 0x6d, 0x8e, 0xbb, 0x3b, 0xf3, 0x23, 0x36, 0xc7, 0xfe, 0x3b,
+0xe0, 0xa1, 0x25, 0x07, 0x48, 0xab, 0xc9, 0x89, 0x74, 0xff, 0x08, 0x8f, 0x80, 0xbf, 0xc0, 0x96,
+0x65, 0xf3, 0xee, 0xec, 0x4b, 0x68, 0xbd, 0x9d, 0x88, 0xc3, 0x31, 0xb3, 0x40, 0xf1, 0xe8, 0xcf,
+0xf6, 0x38, 0xbb, 0x9c, 0xe4, 0xd1, 0x7f, 0xd4, 0xe5, 0x58, 0x9b, 0x7c, 0xfa, 0xd4, 0xf3, 0x0e,
+0x9b, 0x75, 0x91, 0xe4, 0xba, 0x52, 0x2e, 0x19, 0x7e, 0xd1, 0xf5, 0xcd, 0x5a, 0x19, 0xfc, 0xba,
+0x06, 0xf6, 0xfb, 0x52, 0xa8, 0x4b, 0x99, 0x04, 0xdd, 0xf8, 0xf9, 0xb4, 0x8b, 0x50, 0xa3, 0x4e,
+0x62, 0x89, 0xf0, 0x87, 0x24, 0xfa, 0x83, 0x42, 0xc1, 0x87, 0xfa, 0xd5, 0x2d, 0x29, 0x2a, 0x5a,
+0x71, 0x7a, 0x64, 0x6a, 0xd7, 0x27, 0x60, 0x63, 0x0d, 0xdb, 0xce, 0x49, 0xf5, 0x8d, 0x1f, 0x90,
+0x89, 0x32, 0x17, 0xf8, 0x73, 0x43, 0xb8, 0xd2, 0x5a, 0x93, 0x86, 0x61, 0xd6, 0xe1, 0x75, 0x0a,
+0xea, 0x79, 0x66, 0x76, 0x88, 0x4f, 0x71, 0xeb, 0x04, 0x25, 0xd6, 0x0a, 0x5a, 0x7a, 0x93, 0xe5,
+0xb9, 0x4b, 0x17, 0x40, 0x0f, 0xb1, 0xb6, 0xb9, 0xf5, 0xde, 0x4f, 0xdc, 0xe0, 0xb3, 0xac, 0x3b,
+0x11, 0x70, 0x60, 0x84, 0x4a, 0x43, 0x6e, 0x99, 0x20, 0xc0, 0x29, 0x71, 0x0a, 0xc0, 0x65, 0x02,
+0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0xcb, 0x30, 0x82, 0x02, 0xc7, 0x30, 0x7d, 0x06, 0x08,
+0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x71, 0x30, 0x6f, 0x30, 0x4c, 0x06, 0x08,
+0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x40, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x63, 0x63, 0x76, 0x2e, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x6c,
+0x65, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x6f, 0x73, 0x2f,
+0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x64, 0x6f, 0x73, 0x2f, 0x72, 0x61, 0x69,
+0x7a, 0x61, 0x63, 0x63, 0x76, 0x31, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06,
+0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x13, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f,
+0x63, 0x73, 0x70, 0x2e, 0x61, 0x63, 0x63, 0x76, 0x2e, 0x65, 0x73, 0x30, 0x1d, 0x06, 0x03, 0x55,
+0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd2, 0x87, 0xb4, 0xe3, 0xdf, 0x37, 0x27, 0x93, 0x55, 0xf6,
+0x56, 0xea, 0x81, 0xe5, 0x36, 0xcc, 0x8c, 0x1e, 0x3f, 0xbd, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
+0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55,
+0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xd2, 0x87, 0xb4, 0xe3, 0xdf, 0x37, 0x27, 0x93,
+0x55, 0xf6, 0x56, 0xea, 0x81, 0xe5, 0x36, 0xcc, 0x8c, 0x1e, 0x3f, 0xbd, 0x30, 0x82, 0x01, 0x73,
+0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x82, 0x01, 0x6a, 0x30, 0x82, 0x01, 0x66, 0x30, 0x82, 0x01,
+0x62, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x82, 0x01, 0x58, 0x30, 0x82, 0x01, 0x22, 0x06,
+0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x82, 0x01, 0x14, 0x1e, 0x82, 0x01,
+0x10, 0x00, 0x41, 0x00, 0x75, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x69, 0x00, 0x64, 0x00,
+0x61, 0x00, 0x64, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, 0x00, 0x43, 0x00, 0x65, 0x00,
+0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x63, 0x00,
+0x69, 0x00, 0xf3, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x52, 0x00, 0x61, 0x00, 0xed, 0x00, 0x7a, 0x00,
+0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x20, 0x00, 0x41, 0x00,
+0x43, 0x00, 0x43, 0x00, 0x56, 0x00, 0x20, 0x00, 0x28, 0x00, 0x41, 0x00, 0x67, 0x00, 0x65, 0x00,
+0x6e, 0x00, 0x63, 0x00, 0x69, 0x00, 0x61, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, 0x00,
+0x54, 0x00, 0x65, 0x00, 0x63, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x67, 0x00,
+0xed, 0x00, 0x61, 0x00, 0x20, 0x00, 0x79, 0x00, 0x20, 0x00, 0x43, 0x00, 0x65, 0x00, 0x72, 0x00,
+0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x63, 0x00, 0x69, 0x00,
+0xf3, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x45, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00,
+0x72, 0x00, 0xf3, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x2c, 0x00, 0x20, 0x00,
+0x43, 0x00, 0x49, 0x00, 0x46, 0x00, 0x20, 0x00, 0x51, 0x00, 0x34, 0x00, 0x36, 0x00, 0x30, 0x00,
+0x31, 0x00, 0x31, 0x00, 0x35, 0x00, 0x36, 0x00, 0x45, 0x00, 0x29, 0x00, 0x2e, 0x00, 0x20, 0x00,
+0x43, 0x00, 0x50, 0x00, 0x53, 0x00, 0x20, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x68, 0x00,
+0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, 0x77, 0x00,
+0x77, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x63, 0x00, 0x63, 0x00, 0x76, 0x00, 0x2e, 0x00, 0x65, 0x00,
+0x73, 0x30, 0x30, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x24, 0x68,
+0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x63, 0x63, 0x76, 0x2e, 0x65,
+0x73, 0x2f, 0x6c, 0x65, 0x67, 0x69, 0x73, 0x6c, 0x61, 0x63, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x2e,
+0x68, 0x74, 0x6d, 0x30, 0x55, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x4e, 0x30, 0x4c, 0x30, 0x4a,
+0xa0, 0x48, 0xa0, 0x46, 0x86, 0x44, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+0x2e, 0x61, 0x63, 0x63, 0x76, 0x2e, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x61, 0x64, 0x6d,
+0x69, 0x6e, 0x2f, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x6f, 0x73, 0x2f, 0x63, 0x65, 0x72, 0x74,
+0x69, 0x66, 0x69, 0x63, 0x61, 0x64, 0x6f, 0x73, 0x2f, 0x72, 0x61, 0x69, 0x7a, 0x61, 0x63, 0x63,
+0x76, 0x31, 0x5f, 0x64, 0x65, 0x72, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d,
+0x11, 0x04, 0x10, 0x30, 0x0e, 0x81, 0x0c, 0x61, 0x63, 0x63, 0x76, 0x40, 0x61, 0x63, 0x63, 0x76,
+0x2e, 0x65, 0x73, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x97, 0x31, 0x02, 0x9f, 0xe7, 0xfd, 0x43, 0x67, 0x48,
+0x44, 0x14, 0xe4, 0x29, 0x87, 0xed, 0x4c, 0x28, 0x66, 0xd0, 0x8f, 0x35, 0xda, 0x4d, 0x61, 0xb7,
+0x4a, 0x97, 0x4d, 0xb5, 0xdb, 0x90, 0xe0, 0x05, 0x2e, 0x0e, 0xc6, 0x79, 0xd0, 0xf2, 0x97, 0x69,
+0x0f, 0xbd, 0x04, 0x47, 0xd9, 0xbe, 0xdb, 0xb5, 0x29, 0xda, 0x9b, 0xd9, 0xae, 0xa9, 0x99, 0xd5,
+0xd3, 0x3c, 0x30, 0x93, 0xf5, 0x8d, 0xa1, 0xa8, 0xfc, 0x06, 0x8d, 0x44, 0xf4, 0xca, 0x16, 0x95,
+0x7c, 0x33, 0xdc, 0x62, 0x8b, 0xa8, 0x37, 0xf8, 0x27, 0xd8, 0x09, 0x2d, 0x1b, 0xef, 0xc8, 0x14,
+0x27, 0x20, 0xa9, 0x64, 0x44, 0xff, 0x2e, 0xd6, 0x75, 0xaa, 0x6c, 0x4d, 0x60, 0x40, 0x19, 0x49,
+0x43, 0x54, 0x63, 0xda, 0xe2, 0xcc, 0xba, 0x66, 0xe5, 0x4f, 0x44, 0x7a, 0x5b, 0xd9, 0x6a, 0x81,
+0x2b, 0x40, 0xd5, 0x7f, 0xf9, 0x01, 0x27, 0x58, 0x2c, 0xc8, 0xed, 0x48, 0x91, 0x7c, 0x3f, 0xa6,
+0x00, 0xcf, 0xc4, 0x29, 0x73, 0x11, 0x36, 0xde, 0x86, 0x19, 0x3e, 0x9d, 0xee, 0x19, 0x8a, 0x1b,
+0xd5, 0xb0, 0xed, 0x8e, 0x3d, 0x9c, 0x2a, 0xc0, 0x0d, 0xd8, 0x3d, 0x66, 0xe3, 0x3c, 0x0d, 0xbd,
+0xd5, 0x94, 0x5c, 0xe2, 0xe2, 0xa7, 0x35, 0x1b, 0x04, 0x00, 0xf6, 0x3f, 0x5a, 0x8d, 0xea, 0x43,
+0xbd, 0x5f, 0x89, 0x1d, 0xa9, 0xc1, 0xb0, 0xcc, 0x99, 0xe2, 0x4d, 0x00, 0x0a, 0xda, 0xc9, 0x27,
+0x5b, 0xe7, 0x13, 0x90, 0x5c, 0xe4, 0xf5, 0x33, 0xa2, 0x55, 0x6d, 0xdc, 0xe0, 0x09, 0x4d, 0x2f,
+0xb1, 0x26, 0x5b, 0x27, 0x75, 0x00, 0x09, 0xc4, 0x62, 0x77, 0x29, 0x08, 0x5f, 0x9e, 0x59, 0xac,
+0xb6, 0x7e, 0xad, 0x9f, 0x54, 0x30, 0x22, 0x03, 0xc1, 0x1e, 0x71, 0x64, 0xfe, 0xf9, 0x38, 0x0a,
+0x96, 0x18, 0xdd, 0x02, 0x14, 0xac, 0x23, 0xcb, 0x06, 0x1c, 0x1e, 0xa4, 0x7d, 0x8d, 0x0d, 0xde,
+0x27, 0x41, 0xe8, 0xad, 0xda, 0x15, 0xb7, 0xb0, 0x23, 0xdd, 0x2b, 0xa8, 0xd3, 0xda, 0x25, 0x87,
+0xed, 0xe8, 0x55, 0x44, 0x4d, 0x88, 0xf4, 0x36, 0x7e, 0x84, 0x9a, 0x78, 0xac, 0xf7, 0x0e, 0x56,
+0x49, 0x0e, 0xd6, 0x33, 0x25, 0xd6, 0x84, 0x50, 0x42, 0x6c, 0x20, 0x12, 0x1d, 0x2a, 0xd5, 0xbe,
+0xbc, 0xf2, 0x70, 0x81, 0xa4, 0x70, 0x60, 0xbe, 0x05, 0xb5, 0x9b, 0x9e, 0x04, 0x44, 0xbe, 0x61,
+0x23, 0xac, 0xe9, 0xa5, 0x24, 0x8c, 0x11, 0x80, 0x94, 0x5a, 0xa2, 0xa2, 0xb9, 0x49, 0xd2, 0xc1,
+0xdc, 0xd1, 0xa7, 0xed, 0x31, 0x11, 0x2c, 0x9e, 0x19, 0xa6, 0xee, 0xe1, 0x55, 0xe1, 0xc0, 0xea,
+0xcf, 0x0d, 0x84, 0xe4, 0x17, 0xb7, 0xa2, 0x7c, 0xa5, 0xde, 0x55, 0x25, 0x06, 0xee, 0xcc, 0xc0,
+0x87, 0x5c, 0x40, 0xda, 0xcc, 0x95, 0x3f, 0x55, 0xe0, 0x35, 0xc7, 0xb8, 0x84, 0xbe, 0xb4, 0x5d,
+0xcd, 0x7a, 0x83, 0x01, 0x72, 0xee, 0x87, 0xe6, 0x5f, 0x1d, 0xae, 0xb5, 0x85, 0xc6, 0x26, 0xdf,
+0xe6, 0xc1, 0x9a, 0xe9, 0x1e, 0x02, 0x47, 0x9f, 0x2a, 0xa8, 0x6d, 0xa9, 0x5b, 0xcf, 0xec, 0x45,
+0x77, 0x7f, 0x98, 0x27, 0x9a, 0x32, 0x5d, 0x2a, 0xe3, 0x84, 0xee, 0xc5, 0x98, 0x66, 0x2f, 0x96,
+0x20, 0x1d, 0xdd, 0xd8, 0xc3, 0x27, 0xd7, 0xb0, 0xf9, 0xfe, 0xd9, 0x7d, 0xcd, 0xd0, 0x9f, 0x8f,
+0x0b, 0x14, 0x58, 0x51, 0x9f, 0x2f, 0x8b, 0xc3, 0x38, 0x2d, 0xde, 0xe8, 0x8f, 0xd6, 0x8d, 0x87,
+0xa4, 0xf5, 0x56, 0x43, 0x16, 0x99, 0x2c, 0xf4, 0xa4, 0x56, 0xb4, 0x34, 0xb8, 0x61, 0x37, 0xc9,
+0xc2, 0x58, 0x80, 0x1b, 0xa0, 0x97, 0xa1, 0xfc, 0x59, 0x8d, 0xe9, 0x11, 0xf6, 0xd1, 0x0f, 0x4b,
+0x55, 0x34, 0x46, 0x2a, 0x8b, 0x86, 0x3b, 0x30, 0x82, 0x05, 0xbb, 0x30, 0x82, 0x03, 0xa3, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x57, 0x0a, 0x11, 0x97, 0x42, 0xc4, 0xe3, 0xcc, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x6b, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x54, 0x31, 0x0e, 0x30, 0x0c,
+0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x4d, 0x69, 0x6c, 0x61, 0x6e, 0x31, 0x23, 0x30, 0x21,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1a, 0x41, 0x63, 0x74, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x53,
+0x2e, 0x70, 0x2e, 0x41, 0x2e, 0x2f, 0x30, 0x33, 0x33, 0x35, 0x38, 0x35, 0x32, 0x30, 0x39, 0x36,
+0x37, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x41, 0x63, 0x74, 0x61,
+0x6c, 0x69, 0x73, 0x20, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69,
+0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31,
+0x30, 0x39, 0x32, 0x32, 0x31, 0x31, 0x32, 0x32, 0x30, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x30,
+0x39, 0x32, 0x32, 0x31, 0x31, 0x32, 0x32, 0x30, 0x32, 0x5a, 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x54, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55,
+0x04, 0x07, 0x0c, 0x05, 0x4d, 0x69, 0x6c, 0x61, 0x6e, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x0c, 0x1a, 0x41, 0x63, 0x74, 0x61, 0x6c, 0x69, 0x73, 0x20, 0x53, 0x2e, 0x70, 0x2e,
+0x41, 0x2e, 0x2f, 0x30, 0x33, 0x33, 0x35, 0x38, 0x35, 0x32, 0x30, 0x39, 0x36, 0x37, 0x31, 0x27,
+0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x41, 0x63, 0x74, 0x61, 0x6c, 0x69, 0x73,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30,
+0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xa7, 0xc6, 0xc4, 0xa5, 0x29, 0xa4, 0x2c, 0xef,
+0xe5, 0x18, 0xc5, 0xb0, 0x50, 0xa3, 0x6f, 0x51, 0x3b, 0x9f, 0x0a, 0x5a, 0xc9, 0xc2, 0x48, 0x38,
+0x0a, 0xc2, 0x1c, 0xa0, 0x18, 0x7f, 0x91, 0xb5, 0x87, 0xb9, 0x40, 0x3f, 0xdd, 0x1d, 0x68, 0x1f,
+0x08, 0x83, 0xd5, 0x2d, 0x1e, 0x88, 0xa0, 0xf8, 0x8f, 0x56, 0x8f, 0x6d, 0x99, 0x02, 0x92, 0x90,
+0x16, 0xd5, 0x5f, 0x08, 0x6c, 0x89, 0xd7, 0xe1, 0xac, 0xbc, 0x20, 0xc2, 0xb1, 0xe0, 0x83, 0x51,
+0x8a, 0x69, 0x4d, 0x00, 0x96, 0x5a, 0x6f, 0x2f, 0xc0, 0x44, 0x7e, 0xa3, 0x0e, 0xe4, 0x91, 0xcd,
+0x58, 0xee, 0xdc, 0xfb, 0xc7, 0x1e, 0x45, 0x47, 0xdd, 0x27, 0xb9, 0x08, 0x01, 0x9f, 0xa6, 0x21,
+0x1d, 0xf5, 0x41, 0x2d, 0x2f, 0x4c, 0xfd, 0x28, 0xad, 0xe0, 0x8a, 0xad, 0x22, 0xb4, 0x56, 0x65,
+0x8e, 0x86, 0x54, 0x8f, 0x93, 0x43, 0x29, 0xde, 0x39, 0x46, 0x78, 0xa3, 0x30, 0x23, 0xba, 0xcd,
+0xf0, 0x7d, 0x13, 0x57, 0xc0, 0x5d, 0xd2, 0x83, 0x6b, 0x48, 0x4c, 0xc4, 0xab, 0x9f, 0x80, 0x5a,
+0x5b, 0x3a, 0xbd, 0xc9, 0xa7, 0x22, 0x3f, 0x80, 0x27, 0x33, 0x5b, 0x0e, 0xb7, 0x8a, 0x0c, 0x5d,
+0x07, 0x37, 0x08, 0xcb, 0x6c, 0xd2, 0x7a, 0x47, 0x22, 0x44, 0x35, 0xc5, 0xcc, 0xcc, 0x2e, 0x8e,
+0xdd, 0x2a, 0xed, 0xb7, 0x7d, 0x66, 0x0d, 0x5f, 0x61, 0x51, 0x22, 0x55, 0x1b, 0xe3, 0x46, 0xe3,
+0xe3, 0x3d, 0xd0, 0x35, 0x62, 0x9a, 0xdb, 0xaf, 0x14, 0xc8, 0x5b, 0xa1, 0xcc, 0x89, 0x1b, 0xe1,
+0x30, 0x26, 0xfc, 0xa0, 0x9b, 0x1f, 0x81, 0xa7, 0x47, 0x1f, 0x04, 0xeb, 0xa3, 0x39, 0x92, 0x06,
+0x9f, 0x99, 0xd3, 0xbf, 0xd3, 0xea, 0x4f, 0x50, 0x9c, 0x19, 0xfe, 0x96, 0x87, 0x1e, 0x3c, 0x65,
+0xf6, 0xa3, 0x18, 0x24, 0x83, 0x86, 0x10, 0xe7, 0x54, 0x3e, 0xa8, 0x3a, 0x76, 0x24, 0x4f, 0x81,
+0x21, 0xc5, 0xe3, 0x0f, 0x02, 0xf8, 0x93, 0x94, 0x47, 0x20, 0xbb, 0xfe, 0xd4, 0x0e, 0xd3, 0x68,
+0xb9, 0xdd, 0xc4, 0x7a, 0x84, 0x82, 0xe3, 0x53, 0x54, 0x79, 0xdd, 0xdb, 0x9c, 0xd2, 0xf2, 0x07,
+0x9b, 0x2e, 0xb6, 0xbc, 0x3e, 0xed, 0x85, 0x6d, 0xef, 0x25, 0x11, 0xf2, 0x97, 0x1a, 0x42, 0x61,
+0xf7, 0x4a, 0x97, 0xe8, 0x8b, 0xb1, 0x10, 0x07, 0xfa, 0x65, 0x81, 0xb2, 0xa2, 0x39, 0xcf, 0xf7,
+0x3c, 0xff, 0x18, 0xfb, 0xc6, 0xf1, 0x5a, 0x8b, 0x59, 0xe2, 0x02, 0xac, 0x7b, 0x92, 0xd0, 0x4e,
+0x14, 0x4f, 0x59, 0x45, 0xf6, 0x0c, 0x5e, 0x28, 0x5f, 0xb0, 0xe8, 0x3f, 0x45, 0xcf, 0xcf, 0xaf,
+0x9b, 0x6f, 0xfb, 0x84, 0xd3, 0x77, 0x5a, 0x95, 0x6f, 0xac, 0x94, 0x84, 0x9e, 0xee, 0xbc, 0xc0,
+0x4a, 0x8f, 0x4a, 0x93, 0xf8, 0x44, 0x21, 0xe2, 0x31, 0x45, 0x61, 0x50, 0x4e, 0x10, 0xd8, 0xe3,
+0x35, 0x7c, 0x4c, 0x19, 0xb4, 0xde, 0x05, 0xbf, 0xa3, 0x06, 0x9f, 0xc8, 0xb5, 0xcd, 0xe4, 0x1f,
+0xd7, 0x17, 0x06, 0x0d, 0x7a, 0x95, 0x74, 0x55, 0x0d, 0x68, 0x1a, 0xfc, 0x10, 0x1b, 0x62, 0x64,
+0x9d, 0x6d, 0xe0, 0x95, 0xa0, 0xc3, 0x94, 0x07, 0x57, 0x0d, 0x14, 0xe6, 0xbd, 0x05, 0xfb, 0xb8,
+0x9f, 0xe6, 0xdf, 0x8b, 0xe2, 0xc6, 0xe7, 0x7e, 0x96, 0xf6, 0x53, 0xc5, 0x80, 0x34, 0x50, 0x28,
+0x58, 0xf0, 0x12, 0x50, 0x71, 0x17, 0x30, 0xba, 0xe6, 0x78, 0x63, 0xbc, 0xf4, 0xb2, 0xad, 0x9b,
+0x2b, 0xb2, 0xfe, 0xe1, 0x39, 0x8c, 0x5e, 0xba, 0x0b, 0x20, 0x94, 0xde, 0x7b, 0x83, 0xb8, 0xff,
+0xe3, 0x56, 0x8d, 0xb7, 0x11, 0xe9, 0x3b, 0x8c, 0xf2, 0xb1, 0xc1, 0x5d, 0x9d, 0xa4, 0x0b, 0x4c,
+0x2b, 0xd9, 0xb2, 0x18, 0xf5, 0xb5, 0x9f, 0x4b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30,
+0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x52, 0xd8, 0x88, 0x3a,
+0xc8, 0x9f, 0x78, 0x66, 0xed, 0x89, 0xf3, 0x7b, 0x38, 0x70, 0x94, 0xc9, 0x02, 0x02, 0x36, 0xd0,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x52, 0xd8,
+0x88, 0x3a, 0xc8, 0x9f, 0x78, 0x66, 0xed, 0x89, 0xf3, 0x7b, 0x38, 0x70, 0x94, 0xc9, 0x02, 0x02,
+0x36, 0xd0, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x0b, 0x7b, 0x72, 0x87, 0xc0, 0x60, 0xa6, 0x49, 0x4c, 0x88,
+0x58, 0xe6, 0x1d, 0x88, 0xf7, 0x14, 0x64, 0x48, 0xa6, 0xd8, 0x58, 0x0a, 0x0e, 0x4f, 0x13, 0x35,
+0xdf, 0x35, 0x1d, 0xd4, 0xed, 0x06, 0x31, 0xc8, 0x81, 0x3e, 0x6a, 0xd5, 0xdd, 0x3b, 0x1a, 0x32,
+0xee, 0x90, 0x3d, 0x11, 0xd2, 0x2e, 0xf4, 0x8e, 0xc3, 0x63, 0x2e, 0x23, 0x66, 0xb0, 0x67, 0xbe,
+0x6f, 0xb6, 0xc0, 0x13, 0x39, 0x60, 0xaa, 0xa2, 0x34, 0x25, 0x93, 0x75, 0x52, 0xde, 0xa7, 0x9d,
+0xad, 0x0e, 0x87, 0x89, 0x52, 0x71, 0x6a, 0x16, 0x3c, 0x19, 0x1d, 0x83, 0xf8, 0x9a, 0x29, 0x65,
+0xbe, 0xf4, 0x3f, 0x9a, 0xd9, 0xf0, 0xf3, 0x5a, 0x87, 0x21, 0x71, 0x80, 0x4d, 0xcb, 0xe0, 0x38,
+0x9b, 0x3f, 0xbb, 0xfa, 0xe0, 0x30, 0x4d, 0xcf, 0x86, 0xd3, 0x65, 0x10, 0x19, 0x18, 0xd1, 0x97,
+0x02, 0xb1, 0x2b, 0x72, 0x42, 0x68, 0xac, 0xa0, 0xbd, 0x4e, 0x5a, 0xda, 0x18, 0xbf, 0x6b, 0x98,
+0x81, 0xd0, 0xfd, 0x9a, 0xbe, 0x5e, 0x15, 0x48, 0xcd, 0x11, 0x15, 0xb9, 0xc0, 0x29, 0x5c, 0xb4,
+0xe8, 0x88, 0xf7, 0x3e, 0x36, 0xae, 0xb7, 0x62, 0xfd, 0x1e, 0x62, 0xde, 0x70, 0x78, 0x10, 0x1c,
+0x48, 0x5b, 0xda, 0xbc, 0xa4, 0x38, 0xba, 0x67, 0xed, 0x55, 0x3e, 0x5e, 0x57, 0xdf, 0xd4, 0x03,
+0x40, 0x4c, 0x81, 0xa4, 0xd2, 0x4f, 0x63, 0xa7, 0x09, 0x42, 0x09, 0x14, 0xfc, 0x00, 0xa9, 0xc2,
+0x80, 0x73, 0x4f, 0x2e, 0xc0, 0x40, 0xd9, 0x11, 0x7b, 0x48, 0xea, 0x7a, 0x02, 0xc0, 0xd3, 0xeb,
+0x28, 0x01, 0x26, 0x58, 0x74, 0xc1, 0xc0, 0x73, 0x22, 0x6d, 0x93, 0x95, 0xfd, 0x39, 0x7d, 0xbb,
+0x2a, 0xe3, 0xf6, 0x82, 0xe3, 0x2c, 0x97, 0x5f, 0x4e, 0x1f, 0x91, 0x94, 0xfa, 0xfe, 0x2c, 0xa3,
+0xd8, 0x76, 0x1a, 0xb8, 0x4d, 0xb2, 0x38, 0x4f, 0x9b, 0xfa, 0x1d, 0x48, 0x60, 0x79, 0x26, 0xe2,
+0xf3, 0xfd, 0xa9, 0xd0, 0x9a, 0xe8, 0x70, 0x8f, 0x49, 0x7a, 0xd6, 0xe5, 0xbd, 0x0a, 0x0e, 0xdb,
+0x2d, 0xf3, 0x8d, 0xbf, 0xeb, 0xe3, 0xa4, 0x7d, 0xcb, 0xc7, 0x95, 0x71, 0xe8, 0xda, 0xa3, 0x7c,
+0xc5, 0xc2, 0xf8, 0x74, 0x92, 0x04, 0x1b, 0x86, 0xac, 0xa4, 0x22, 0x53, 0x40, 0xb6, 0xac, 0xfe,
+0x4c, 0x76, 0xcf, 0xfb, 0x94, 0x32, 0xc0, 0x35, 0x9f, 0x76, 0x3f, 0x6e, 0xe5, 0x90, 0x6e, 0xa0,
+0xa6, 0x26, 0xa2, 0xb8, 0x2c, 0xbe, 0xd1, 0x2b, 0x85, 0xfd, 0xa7, 0x68, 0xc8, 0xba, 0x01, 0x2b,
+0xb1, 0x6c, 0x74, 0x1d, 0xb8, 0x73, 0x95, 0xe7, 0xee, 0xb7, 0xc7, 0x25, 0xf0, 0x00, 0x4c, 0x00,
+0xb2, 0x7e, 0xb6, 0x0b, 0x8b, 0x1c, 0xf3, 0xc0, 0x50, 0x9e, 0x25, 0xb9, 0xe0, 0x08, 0xde, 0x36,
+0x66, 0xff, 0x37, 0xa5, 0xd1, 0xbb, 0x54, 0x64, 0x2c, 0xc9, 0x27, 0xb5, 0x4b, 0x92, 0x7e, 0x65,
+0xff, 0xd3, 0x2d, 0xe1, 0xb9, 0x4e, 0xbc, 0x7f, 0xa4, 0x41, 0x21, 0x90, 0x41, 0x77, 0xa6, 0x39,
+0x1f, 0xea, 0x9e, 0xe3, 0x9f, 0xd0, 0x66, 0x6f, 0x05, 0xec, 0xaa, 0x76, 0x7e, 0xbf, 0x6b, 0x16,
+0xa0, 0xeb, 0xb5, 0xc7, 0xfc, 0x92, 0x54, 0x2f, 0x2b, 0x11, 0x27, 0x25, 0x37, 0x78, 0x4c, 0x51,
+0x6a, 0xb0, 0xf3, 0xcc, 0x58, 0x5d, 0x14, 0xf1, 0x6a, 0x48, 0x15, 0xff, 0xc2, 0x07, 0xb6, 0xb1,
+0x8d, 0x0f, 0x8e, 0x5c, 0x50, 0x46, 0xb3, 0x3d, 0xbf, 0x01, 0x98, 0x4f, 0xb2, 0x59, 0x54, 0x47,
+0x3e, 0x34, 0x7b, 0x78, 0x6d, 0x56, 0x93, 0x2e, 0x73, 0xea, 0x66, 0x28, 0x78, 0xcd, 0x1d, 0x14,
+0xbf, 0xa0, 0x8f, 0x2f, 0x2e, 0xb8, 0x2e, 0x8e, 0xf2, 0x14, 0x8a, 0xcc, 0xe9, 0xb5, 0x7c, 0xfb,
+0x6c, 0x9d, 0x0c, 0xa5, 0xe1, 0x96, 0x30, 0x82, 0x03, 0x4c, 0x30, 0x82, 0x02, 0x34, 0xa0, 0x03,
+0x02, 0x01, 0x02, 0x02, 0x08, 0x77, 0x77, 0x06, 0x27, 0x26, 0xa9, 0xb1, 0x7c, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x44, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73,
+0x74, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x41, 0x66, 0x66, 0x69,
+0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69,
+0x61, 0x6c, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x31, 0x32, 0x39, 0x31, 0x34, 0x30, 0x36,
+0x30, 0x36, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31, 0x32, 0x33, 0x31, 0x31, 0x34, 0x30, 0x36, 0x30,
+0x36, 0x5a, 0x30, 0x44, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x66, 0x66, 0x69,
+0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x0c, 0x16, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f,
+0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
+0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xf6, 0x1b, 0x4f, 0x67, 0x07, 0x2b, 0xa1,
+0x15, 0xf5, 0x06, 0x22, 0xcb, 0x1f, 0x01, 0xb2, 0xe3, 0x73, 0x45, 0x06, 0x44, 0x49, 0x2c, 0xbb,
+0x49, 0x25, 0x14, 0xd6, 0xce, 0xc3, 0xb7, 0xab, 0x2c, 0x4f, 0xc6, 0x41, 0x32, 0x94, 0x57, 0xfa,
+0x12, 0xa7, 0x5b, 0x0e, 0xe2, 0x8f, 0x1f, 0x1e, 0x86, 0x19, 0xa7, 0xaa, 0xb5, 0x2d, 0xb9, 0x5f,
+0x0d, 0x8a, 0xc2, 0xaf, 0x85, 0x35, 0x79, 0x32, 0x2d, 0xbb, 0x1c, 0x62, 0x37, 0xf2, 0xb1, 0x5b,
+0x4a, 0x3d, 0xca, 0xcd, 0x71, 0x5f, 0xe9, 0x42, 0xbe, 0x94, 0xe8, 0xc8, 0xde, 0xf9, 0x22, 0x48,
+0x64, 0xc6, 0xe5, 0xab, 0xc6, 0x2b, 0x6d, 0xad, 0x05, 0xf0, 0xfa, 0xd5, 0x0b, 0xcf, 0x9a, 0xe5,
+0xf0, 0x50, 0xa4, 0x8b, 0x3b, 0x47, 0xa5, 0x23, 0x5b, 0x7a, 0x7a, 0xf8, 0x33, 0x3f, 0xb8, 0xef,
+0x99, 0x97, 0xe3, 0x20, 0xc1, 0xd6, 0x28, 0x89, 0xcf, 0x94, 0xfb, 0xb9, 0x45, 0xed, 0xe3, 0x40,
+0x17, 0x11, 0xd4, 0x74, 0xf0, 0x0b, 0x31, 0xe2, 0x2b, 0x26, 0x6a, 0x9b, 0x4c, 0x57, 0xae, 0xac,
+0x20, 0x3e, 0xba, 0x45, 0x7a, 0x05, 0xf3, 0xbd, 0x9b, 0x69, 0x15, 0xae, 0x7d, 0x4e, 0x20, 0x63,
+0xc4, 0x35, 0x76, 0x3a, 0x07, 0x02, 0xc9, 0x37, 0xfd, 0xc7, 0x47, 0xee, 0xe8, 0xf1, 0x76, 0x1d,
+0x73, 0x15, 0xf2, 0x97, 0xa4, 0xb5, 0xc8, 0x7a, 0x79, 0xd9, 0x42, 0xaa, 0x2b, 0x7f, 0x5c, 0xfe,
+0xce, 0x26, 0x4f, 0xa3, 0x66, 0x81, 0x35, 0xaf, 0x44, 0xba, 0x54, 0x1e, 0x1c, 0x30, 0x32, 0x65,
+0x9d, 0xe6, 0x3c, 0x93, 0x5e, 0x50, 0x4e, 0x7a, 0xe3, 0x3a, 0xd4, 0x6e, 0xcc, 0x1a, 0xfb, 0xf9,
+0xd2, 0x37, 0xae, 0x24, 0x2a, 0xab, 0x57, 0x03, 0x22, 0x28, 0x0d, 0x49, 0x75, 0x7f, 0xb7, 0x28,
+0xda, 0x75, 0xbf, 0x8e, 0xe3, 0xdc, 0x0e, 0x79, 0x31, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42,
+0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9d, 0x93, 0xc6,
+0x53, 0x8b, 0x5e, 0xca, 0xaf, 0x3f, 0x9f, 0x1e, 0x0f, 0xe5, 0x99, 0x95, 0xbc, 0x24, 0xf6, 0x94,
+0x8f, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x58, 0xac, 0xf4, 0x04, 0x0e, 0xcd, 0xc0, 0x0d, 0xff, 0x0a,
+0xfd, 0xd4, 0xba, 0x16, 0x5f, 0x29, 0xbd, 0x7b, 0x68, 0x99, 0x58, 0x49, 0xd2, 0xb4, 0x1d, 0x37,
+0x4d, 0x7f, 0x27, 0x7d, 0x46, 0x06, 0x5d, 0x43, 0xc6, 0x86, 0x2e, 0x3e, 0x73, 0xb2, 0x26, 0x7d,
+0x4f, 0x93, 0xa9, 0xb6, 0xc4, 0x2a, 0x9a, 0xab, 0x21, 0x97, 0x14, 0xb1, 0xde, 0x8c, 0xd3, 0xab,
+0x89, 0x15, 0xd8, 0x6b, 0x24, 0xd4, 0xf1, 0x16, 0xae, 0xd8, 0xa4, 0x5c, 0xd4, 0x7f, 0x51, 0x8e,
+0xed, 0x18, 0x01, 0xb1, 0x93, 0x63, 0xbd, 0xbc, 0xf8, 0x61, 0x80, 0x9a, 0x9e, 0xb1, 0xce, 0x42,
+0x70, 0xe2, 0xa9, 0x7d, 0x06, 0x25, 0x7d, 0x27, 0xa1, 0xfe, 0x6f, 0xec, 0xb3, 0x1e, 0x24, 0xda,
+0xe3, 0x4b, 0x55, 0x1a, 0x00, 0x3b, 0x35, 0xb4, 0x3b, 0xd9, 0xd7, 0x5d, 0x30, 0xfd, 0x81, 0x13,
+0x89, 0xf2, 0xc2, 0x06, 0x2b, 0xed, 0x67, 0xc4, 0x8e, 0xc9, 0x43, 0xb2, 0x5c, 0x6b, 0x15, 0x89,
+0x02, 0xbc, 0x62, 0xfc, 0x4e, 0xf2, 0xb5, 0x33, 0xaa, 0xb2, 0x6f, 0xd3, 0x0a, 0xa2, 0x50, 0xe3,
+0xf6, 0x3b, 0xe8, 0x2e, 0x44, 0xc2, 0xdb, 0x66, 0x38, 0xa9, 0x33, 0x56, 0x48, 0xf1, 0x6d, 0x1b,
+0x33, 0x8d, 0x0d, 0x8c, 0x3f, 0x60, 0x37, 0x9d, 0xd3, 0xca, 0x6d, 0x7e, 0x34, 0x7e, 0x0d, 0x9f,
+0x72, 0x76, 0x8b, 0x1b, 0x9f, 0x72, 0xfd, 0x52, 0x35, 0x41, 0x45, 0x02, 0x96, 0x2f, 0x1c, 0xb2,
+0x9a, 0x73, 0x49, 0x21, 0xb1, 0x49, 0x47, 0x45, 0x47, 0xb4, 0xef, 0x6a, 0x34, 0x11, 0xc9, 0x4d,
+0x9a, 0xcc, 0x59, 0xb7, 0xd6, 0x02, 0x9e, 0x5a, 0x4e, 0x65, 0xb5, 0x94, 0xae, 0x1b, 0xdf, 0x29,
+0xb0, 0x16, 0xf1, 0xbf, 0x00, 0x9e, 0x07, 0x3a, 0x17, 0x64, 0xb5, 0x04, 0xb5, 0x23, 0x21, 0x99,
+0x0a, 0x95, 0x3b, 0x97, 0x7c, 0xef, 0x30, 0x82, 0x05, 0xb0, 0x30, 0x82, 0x03, 0x98, 0xa0, 0x03,
+0x02, 0x01, 0x02, 0x02, 0x10, 0x15, 0xc8, 0xbd, 0x65, 0x47, 0x5c, 0xaf, 0xb8, 0x97, 0x00, 0x5e,
+0xe4, 0x06, 0xd2, 0xbc, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x05, 0x05, 0x00, 0x30, 0x5e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x54, 0x57, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1a, 0x43, 0x68,
+0x75, 0x6e, 0x67, 0x68, 0x77, 0x61, 0x20, 0x54, 0x65, 0x6c, 0x65, 0x63, 0x6f, 0x6d, 0x20, 0x43,
+0x6f, 0x2e, 0x2c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04,
+0x0b, 0x0c, 0x21, 0x65, 0x50, 0x4b, 0x49, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x34, 0x31, 0x32, 0x32, 0x30, 0x30, 0x32,
+0x33, 0x31, 0x32, 0x37, 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x31, 0x32, 0x32, 0x30, 0x30, 0x32, 0x33,
+0x31, 0x32, 0x37, 0x5a, 0x30, 0x5e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x54, 0x57, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1a, 0x43, 0x68,
+0x75, 0x6e, 0x67, 0x68, 0x77, 0x61, 0x20, 0x54, 0x65, 0x6c, 0x65, 0x63, 0x6f, 0x6d, 0x20, 0x43,
+0x6f, 0x2e, 0x2c, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04,
+0x0b, 0x0c, 0x21, 0x65, 0x50, 0x4b, 0x49, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a,
+0x02, 0x82, 0x02, 0x01, 0x00, 0xe1, 0x25, 0x0f, 0xee, 0x8d, 0xdb, 0x88, 0x33, 0x75, 0x67, 0xcd,
+0xad, 0x1f, 0x7d, 0x3a, 0x4e, 0x6d, 0x9d, 0xd3, 0x2f, 0x14, 0xf3, 0x63, 0x74, 0xcb, 0x01, 0x21,
+0x6a, 0x37, 0xea, 0x84, 0x50, 0x07, 0x4b, 0x26, 0x5b, 0x09, 0x43, 0x6c, 0x21, 0x9e, 0x6a, 0xc8,
+0xd5, 0x03, 0xf5, 0x60, 0x69, 0x8f, 0xcc, 0xf0, 0x22, 0xe4, 0x1f, 0xe7, 0xf7, 0x6a, 0x22, 0x31,
+0xb7, 0x2c, 0x15, 0xf2, 0xe0, 0xfe, 0x00, 0x6a, 0x43, 0xff, 0x87, 0x65, 0xc6, 0xb5, 0x1a, 0xc1,
+0xa7, 0x4c, 0x6d, 0x22, 0x70, 0x21, 0x8a, 0x31, 0xf2, 0x97, 0x74, 0x89, 0x09, 0x12, 0x26, 0x1c,
+0x9e, 0xca, 0xd9, 0x12, 0xa2, 0x95, 0x3c, 0xda, 0xe9, 0x67, 0xbf, 0x08, 0xa0, 0x64, 0xe3, 0xd6,
+0x42, 0xb7, 0x45, 0xef, 0x97, 0xf4, 0xf6, 0xf5, 0xd7, 0xb5, 0x4a, 0x15, 0x02, 0x58, 0x7d, 0x98,
+0x58, 0x4b, 0x60, 0xbc, 0xcd, 0xd7, 0x0d, 0x9a, 0x13, 0x33, 0x53, 0xd1, 0x61, 0xf9, 0x7a, 0xd5,
+0xd7, 0x78, 0xb3, 0x9a, 0x33, 0xf7, 0x00, 0x86, 0xce, 0x1d, 0x4d, 0x94, 0x38, 0xaf, 0xa8, 0xec,
+0x78, 0x51, 0x70, 0x8a, 0x5c, 0x10, 0x83, 0x51, 0x21, 0xf7, 0x11, 0x3d, 0x34, 0x86, 0x5e, 0xe5,
+0x48, 0xcd, 0x97, 0x81, 0x82, 0x35, 0x4c, 0x19, 0xec, 0x65, 0xf6, 0x6b, 0xc5, 0x05, 0xa1, 0xee,
+0x47, 0x13, 0xd6, 0xb3, 0x21, 0x27, 0x94, 0x10, 0x0a, 0xd9, 0x24, 0x3b, 0xba, 0xbe, 0x44, 0x13,
+0x46, 0x30, 0x3f, 0x97, 0x3c, 0xd8, 0xd7, 0xd7, 0x6a, 0xee, 0x3b, 0x38, 0xe3, 0x2b, 0xd4, 0x97,
+0x0e, 0xb9, 0x1b, 0xe7, 0x07, 0x49, 0x7f, 0x37, 0x2a, 0xf9, 0x77, 0x78, 0xcf, 0x54, 0xed, 0x5b,
+0x46, 0x9d, 0xa3, 0x80, 0x0e, 0x91, 0x43, 0xc1, 0xd6, 0x5b, 0x5f, 0x14, 0xba, 0x9f, 0xa6, 0x8d,
+0x24, 0x47, 0x40, 0x59, 0xbf, 0x72, 0x38, 0xb2, 0x36, 0x6c, 0x37, 0xff, 0x99, 0xd1, 0x5d, 0x0e,
+0x59, 0x0a, 0xab, 0x69, 0xf7, 0xc0, 0xb2, 0x04, 0x45, 0x7a, 0x54, 0x00, 0xae, 0xbe, 0x53, 0xf6,
+0xb5, 0xe7, 0xe1, 0xf8, 0x3c, 0xa3, 0x31, 0xd2, 0xa9, 0xfe, 0x21, 0x52, 0x64, 0xc5, 0xa6, 0x67,
+0xf0, 0x75, 0x07, 0x06, 0x94, 0x14, 0x81, 0x55, 0xc6, 0x27, 0xe4, 0x01, 0x8f, 0x17, 0xc1, 0x6a,
+0x71, 0xd7, 0xbe, 0x4b, 0xfb, 0x94, 0x58, 0x7d, 0x7e, 0x11, 0x33, 0xb1, 0x42, 0xf7, 0x62, 0x6c,
+0x18, 0xd6, 0xcf, 0x09, 0x68, 0x3e, 0x7f, 0x6c, 0xf6, 0x1e, 0x8f, 0x62, 0xad, 0xa5, 0x63, 0xdb,
+0x09, 0xa7, 0x1f, 0x22, 0x42, 0x41, 0x1e, 0x6f, 0x99, 0x8a, 0x3e, 0xd7, 0xf9, 0x3f, 0x40, 0x7a,
+0x79, 0xb0, 0xa5, 0x01, 0x92, 0xd2, 0x9d, 0x3d, 0x08, 0x15, 0xa5, 0x10, 0x01, 0x2d, 0xb3, 0x32,
+0x76, 0xa8, 0x95, 0x0d, 0xb3, 0x7a, 0x9a, 0xfb, 0x07, 0x10, 0x78, 0x11, 0x6f, 0xe1, 0x8f, 0xc7,
+0xba, 0x0f, 0x25, 0x1a, 0x74, 0x2a, 0xe5, 0x1c, 0x98, 0x41, 0x99, 0xdf, 0x21, 0x87, 0xe8, 0x95,
+0x06, 0x6a, 0x0a, 0xb3, 0x6a, 0x47, 0x76, 0x65, 0xf6, 0x3a, 0xcf, 0x8f, 0x62, 0x17, 0x19, 0x7b,
+0x0a, 0x28, 0xcd, 0x1a, 0xd2, 0x83, 0x1e, 0x21, 0xc7, 0x2c, 0xbf, 0xbe, 0xff, 0x61, 0x68, 0xb7,
+0x67, 0x1b, 0xbb, 0x78, 0x4d, 0x8d, 0xce, 0x67, 0xe5, 0xe4, 0xc1, 0x8e, 0xb7, 0x23, 0x66, 0xe2,
+0x9d, 0x90, 0x75, 0x34, 0x98, 0xa9, 0x36, 0x2b, 0x8a, 0x9a, 0x94, 0xb9, 0x9d, 0xec, 0xcc, 0x8a,
+0xb1, 0xf8, 0x25, 0x89, 0x5c, 0x5a, 0xb6, 0x2f, 0x8c, 0x1f, 0x6d, 0x79, 0x24, 0xa7, 0x52, 0x68,
+0xc3, 0x84, 0x35, 0xe2, 0x66, 0x8d, 0x63, 0x0e, 0x25, 0x4d, 0xd5, 0x19, 0xb2, 0xe6, 0x79, 0x37,
+0xa7, 0x22, 0x9d, 0x54, 0x31, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x6a, 0x30, 0x68, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x1e, 0x0c, 0xf7, 0xb6, 0x67, 0xf2, 0xe1,
+0x92, 0x26, 0x09, 0x45, 0xc0, 0x55, 0x39, 0x2e, 0x77, 0x3f, 0x42, 0x4a, 0xa2, 0x30, 0x0c, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x39, 0x06, 0x04, 0x67,
+0x2a, 0x07, 0x00, 0x04, 0x31, 0x30, 0x2f, 0x30, 0x2d, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x05,
+0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x30, 0x07, 0x06, 0x05, 0x67, 0x2a, 0x03, 0x00, 0x00,
+0x04, 0x14, 0x45, 0xb0, 0xc2, 0xc7, 0x0a, 0x56, 0x7c, 0xee, 0x5b, 0x78, 0x0c, 0x95, 0xf9, 0x18,
+0x53, 0xc1, 0xa6, 0x1c, 0xd8, 0x10, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x09, 0xb3, 0x83, 0x53, 0x59, 0x01,
+0x3e, 0x95, 0x49, 0xb9, 0xf1, 0x81, 0xba, 0xf9, 0x76, 0x20, 0x23, 0xb5, 0x27, 0x60, 0x74, 0xd4,
+0x6a, 0x99, 0x34, 0x5e, 0x6c, 0x00, 0x53, 0xd9, 0x9f, 0xf2, 0xa6, 0xb1, 0x24, 0x07, 0x44, 0x6a,
+0x2a, 0xc6, 0xa5, 0x8e, 0x78, 0x12, 0xe8, 0x47, 0xd9, 0x58, 0x1b, 0x13, 0x2a, 0x5e, 0x79, 0x9b,
+0x9f, 0x0a, 0x2a, 0x67, 0xa6, 0x25, 0x3f, 0x06, 0x69, 0x56, 0x73, 0xc3, 0x8a, 0x66, 0x48, 0xfb,
+0x29, 0x81, 0x57, 0x74, 0x06, 0xca, 0x9c, 0xea, 0x28, 0xe8, 0x38, 0x67, 0x26, 0x2b, 0xf1, 0xd5,
+0xb5, 0x3f, 0x65, 0x93, 0xf8, 0x36, 0x5d, 0x8e, 0x8d, 0x8d, 0x40, 0x20, 0x87, 0x19, 0xea, 0xef,
+0x27, 0xc0, 0x3d, 0xb4, 0x39, 0x0f, 0x25, 0x7b, 0x68, 0x50, 0x74, 0x55, 0x9c, 0x0c, 0x59, 0x7d,
+0x5a, 0x3d, 0x41, 0x94, 0x25, 0x52, 0x08, 0xe0, 0x47, 0x2c, 0x15, 0x31, 0x19, 0xd5, 0xbf, 0x07,
+0x55, 0xc6, 0xbb, 0x12, 0xb5, 0x97, 0xf4, 0x5f, 0x83, 0x85, 0xba, 0x71, 0xc1, 0xd9, 0x6c, 0x81,
+0x11, 0x76, 0x0a, 0x0a, 0xb0, 0xbf, 0x82, 0x97, 0xf7, 0xea, 0x3d, 0xfa, 0xfa, 0xec, 0x2d, 0xa9,
+0x28, 0x94, 0x3b, 0x56, 0xdd, 0xd2, 0x51, 0x2e, 0xae, 0xc0, 0xbd, 0x08, 0x15, 0x8c, 0x77, 0x52,
+0x34, 0x96, 0xd6, 0x9b, 0xac, 0xd3, 0x1d, 0x8e, 0x61, 0x0f, 0x35, 0x7b, 0x9b, 0xae, 0x39, 0x69,
+0x0b, 0x62, 0x60, 0x40, 0x20, 0x36, 0x8f, 0xaf, 0xfb, 0x36, 0xee, 0x2d, 0x08, 0x4a, 0x1d, 0xb8,
+0xbf, 0x9b, 0x5c, 0xf8, 0xea, 0xa5, 0x1b, 0xa0, 0x73, 0xa6, 0xd8, 0xf8, 0x6e, 0xe0, 0x33, 0x04,
+0x5f, 0x68, 0xaa, 0x27, 0x87, 0xed, 0xd9, 0xc1, 0x90, 0x9c, 0xed, 0xbd, 0xe3, 0x6a, 0x35, 0xaf,
+0x63, 0xdf, 0xab, 0x18, 0xd9, 0xba, 0xe6, 0xe9, 0x4a, 0xea, 0x50, 0x8a, 0x0f, 0x61, 0x93, 0x1e,
+0xe2, 0x2d, 0x19, 0xe2, 0x30, 0x94, 0x35, 0x92, 0x5d, 0x0e, 0xb6, 0x07, 0xaf, 0x19, 0x80, 0x8f,
+0x47, 0x90, 0x51, 0x4b, 0x2e, 0x4d, 0xdd, 0x85, 0xe2, 0xd2, 0x0a, 0x52, 0x0a, 0x17, 0x9a, 0xfc,
+0x1a, 0xb0, 0x50, 0x02, 0xe5, 0x01, 0xa3, 0x63, 0x37, 0x21, 0x4c, 0x44, 0xc4, 0x9b, 0x51, 0x99,
+0x11, 0x0e, 0x73, 0x9c, 0x06, 0x8f, 0x54, 0x2e, 0xa7, 0x28, 0x5e, 0x44, 0x39, 0x87, 0x56, 0x2d,
+0x37, 0xbd, 0x85, 0x44, 0x94, 0xe1, 0x0c, 0x4b, 0x2c, 0x9c, 0xc3, 0x92, 0x85, 0x34, 0x61, 0xcb,
+0x0f, 0xb8, 0x9b, 0x4a, 0x43, 0x52, 0xfe, 0x34, 0x3a, 0x7d, 0xb8, 0xe9, 0x29, 0xdc, 0x76, 0xa9,
+0xc8, 0x30, 0xf8, 0x14, 0x71, 0x80, 0xc6, 0x1e, 0x36, 0x48, 0x74, 0x22, 0x41, 0x5c, 0x87, 0x82,
+0xe8, 0x18, 0x71, 0x8b, 0x41, 0x89, 0x44, 0xe7, 0x7e, 0x58, 0x5b, 0xa8, 0xb8, 0x8d, 0x13, 0xe9,
+0xa7, 0x6c, 0xc3, 0x47, 0xed, 0xb3, 0x1a, 0x9d, 0x62, 0xae, 0x8d, 0x82, 0xea, 0x94, 0x9e, 0xdd,
+0x59, 0x10, 0xc3, 0xad, 0xdd, 0xe2, 0x4d, 0xe3, 0x31, 0xd5, 0xc7, 0xec, 0xe8, 0xf2, 0xb0, 0xfe,
+0x92, 0x1e, 0x16, 0x0a, 0x1a, 0xfc, 0xd9, 0xf3, 0xf8, 0x27, 0xb6, 0xc9, 0xbe, 0x1d, 0xb4, 0x6c,
+0x64, 0x90, 0x7f, 0xf4, 0xe4, 0xc4, 0x5b, 0xd7, 0x37, 0xae, 0x42, 0x0e, 0xdd, 0xa4, 0x1a, 0x6f,
+0x7c, 0x88, 0x54, 0xc5, 0x16, 0x6e, 0xe1, 0x7a, 0x68, 0x2e, 0xf8, 0x3a, 0xbf, 0x0d, 0xa4, 0x3c,
+0x89, 0x3b, 0x78, 0xa7, 0x4e, 0x63, 0x83, 0x04, 0x21, 0x08, 0x67, 0x8d, 0xf2, 0x82, 0x49, 0xd0,
+0x5b, 0xfd, 0xb1, 0xcd, 0x0f, 0x83, 0x84, 0xd4, 0x3e, 0x20, 0x85, 0xf7, 0x4a, 0x3d, 0x2b, 0x9c,
+0xfd, 0x2a, 0x0a, 0x09, 0x4d, 0xea, 0x81, 0xf8, 0x11, 0x9c, 0x30, 0x82, 0x05, 0x46, 0x30, 0x82,
+0x03, 0x2e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x6d, 0x8c, 0x14, 0x46, 0xb1, 0xa6, 0x0a,
+0xee, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00,
+0x30, 0x41, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d,
+0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x13,
+0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x65, 0x6d,
+0x69, 0x75, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x31, 0x32, 0x39, 0x31, 0x34, 0x31,
+0x30, 0x33, 0x36, 0x5a, 0x17, 0x0d, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x31, 0x34, 0x31, 0x30,
+0x33, 0x36, 0x5a, 0x30, 0x41, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x66, 0x66,
+0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x0c, 0x13, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50,
+0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82,
+0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xc4, 0x12, 0xdf, 0xa9, 0x5f, 0xfe, 0x41, 0xdd, 0xdd,
+0xf5, 0x9f, 0x8a, 0xe3, 0xf6, 0xac, 0xe1, 0x3c, 0x78, 0x9a, 0xbc, 0xd8, 0xf0, 0x7f, 0x7a, 0xa0,
+0x33, 0x2a, 0xdc, 0x8d, 0x20, 0x5b, 0xae, 0x2d, 0x6f, 0xe7, 0x93, 0xd9, 0x36, 0x70, 0x6a, 0x68,
+0xcf, 0x8e, 0x51, 0xa3, 0x85, 0x5b, 0x67, 0x04, 0xa0, 0x10, 0x24, 0x6f, 0x5d, 0x28, 0x82, 0xc1,
+0x97, 0x57, 0xd8, 0x48, 0x29, 0x13, 0xb6, 0xe1, 0xbe, 0x91, 0x4d, 0xdf, 0x85, 0x0c, 0x53, 0x18,
+0x9a, 0x1e, 0x24, 0xa2, 0x4f, 0x8f, 0xf0, 0xa2, 0x85, 0x0b, 0xcb, 0xf4, 0x29, 0x7f, 0xd2, 0xa4,
+0x58, 0xee, 0x26, 0x4d, 0xc9, 0xaa, 0xa8, 0x7b, 0x9a, 0xd9, 0xfa, 0x38, 0xde, 0x44, 0x57, 0x15,
+0xe5, 0xf8, 0x8c, 0xc8, 0xd9, 0x48, 0xe2, 0x0d, 0x16, 0x27, 0x1d, 0x1e, 0xc8, 0x83, 0x85, 0x25,
+0xb7, 0xba, 0xaa, 0x55, 0x41, 0xcc, 0x03, 0x22, 0x4b, 0x2d, 0x91, 0x8d, 0x8b, 0xe6, 0x89, 0xaf,
+0x66, 0xc7, 0xe9, 0xff, 0x2b, 0xe9, 0x3c, 0xac, 0xda, 0xd2, 0xb3, 0xc3, 0xe1, 0x68, 0x9c, 0x89,
+0xf8, 0x7a, 0x00, 0x56, 0xde, 0xf4, 0x55, 0x95, 0x6c, 0xfb, 0xba, 0x64, 0xdd, 0x62, 0x8b, 0xdf,
+0x0b, 0x77, 0x32, 0xeb, 0x62, 0xcc, 0x26, 0x9a, 0x9b, 0xbb, 0xaa, 0x62, 0x83, 0x4c, 0xb4, 0x06,
+0x7a, 0x30, 0xc8, 0x29, 0xbf, 0xed, 0x06, 0x4d, 0x97, 0xb9, 0x1c, 0xc4, 0x31, 0x2b, 0xd5, 0x5f,
+0xbc, 0x53, 0x12, 0x17, 0x9c, 0x99, 0x57, 0x29, 0x66, 0x77, 0x61, 0x21, 0x31, 0x07, 0x2e, 0x25,
+0x49, 0x9d, 0x18, 0xf2, 0xee, 0xf3, 0x2b, 0x71, 0x8c, 0xb5, 0xba, 0x39, 0x07, 0x49, 0x77, 0xfc,
+0xef, 0x2e, 0x92, 0x90, 0x05, 0x8d, 0x2d, 0x2f, 0x77, 0x7b, 0xef, 0x43, 0xbf, 0x35, 0xbb, 0x9a,
+0xd8, 0xf9, 0x73, 0xa7, 0x2c, 0xf2, 0xd0, 0x57, 0xee, 0x28, 0x4e, 0x26, 0x5f, 0x8f, 0x90, 0x68,
+0x09, 0x2f, 0xb8, 0xf8, 0xdc, 0x06, 0xe9, 0x2e, 0x9a, 0x3e, 0x51, 0xa7, 0xd1, 0x22, 0xc4, 0x0a,
+0xa7, 0x38, 0x48, 0x6c, 0xb3, 0xf9, 0xff, 0x7d, 0xab, 0x86, 0x57, 0xe3, 0xba, 0xd6, 0x85, 0x78,
+0x77, 0xba, 0x43, 0xea, 0x48, 0x7f, 0xf6, 0xd8, 0xbe, 0x23, 0x6d, 0x1e, 0xbf, 0xd1, 0x36, 0x6c,
+0x58, 0x5c, 0xf1, 0xee, 0xa4, 0x19, 0x54, 0x1a, 0xf5, 0x03, 0xd2, 0x76, 0xe6, 0xe1, 0x8c, 0xbd,
+0x3c, 0xb3, 0xd3, 0x48, 0x4b, 0xe2, 0xc8, 0xf8, 0x7f, 0x92, 0xa8, 0x76, 0x46, 0x9c, 0x42, 0x65,
+0x3e, 0xa4, 0x1e, 0xc1, 0x07, 0x03, 0x5a, 0x46, 0x2d, 0xb8, 0x97, 0xf3, 0xb7, 0xd5, 0xb2, 0x55,
+0x21, 0xef, 0xba, 0xdc, 0x4c, 0x00, 0x97, 0xfb, 0x14, 0x95, 0x27, 0x33, 0xbf, 0xe8, 0x43, 0x47,
+0x46, 0xd2, 0x08, 0x99, 0x16, 0x60, 0x3b, 0x9a, 0x7e, 0xd2, 0xe6, 0xed, 0x38, 0xea, 0xec, 0x01,
+0x1e, 0x3c, 0x48, 0x56, 0x49, 0x09, 0xc7, 0x4c, 0x37, 0x00, 0x9e, 0x88, 0x0e, 0xc0, 0x73, 0xe1,
+0x6f, 0x66, 0xe9, 0x72, 0x47, 0x30, 0x3e, 0x10, 0xe5, 0x0b, 0x03, 0xc9, 0x9a, 0x42, 0x00, 0x6c,
+0xc5, 0x94, 0x7e, 0x61, 0xc4, 0x8a, 0xdf, 0x7f, 0x82, 0x1a, 0x0b, 0x59, 0xc4, 0x59, 0x32, 0x77,
+0xb3, 0xbc, 0x60, 0x69, 0x56, 0x39, 0xfd, 0xb4, 0x06, 0x7b, 0x2c, 0xd6, 0x64, 0x36, 0xd9, 0xbd,
+0x48, 0xed, 0x84, 0x1f, 0x7e, 0xa5, 0x22, 0x8f, 0x2a, 0xb8, 0x42, 0xf4, 0x82, 0xb7, 0xd4, 0x53,
+0x90, 0x78, 0x4e, 0x2d, 0x1a, 0xfd, 0x81, 0x6f, 0x44, 0xd7, 0x3b, 0x01, 0x74, 0x96, 0x42, 0xe0,
+0x00, 0xe2, 0x2e, 0x6b, 0xea, 0xc5, 0xee, 0x72, 0xac, 0xbb, 0xbf, 0xfe, 0xea, 0xaa, 0xa8, 0xf8,
+0xdc, 0xf6, 0xb2, 0x79, 0x8a, 0xb6, 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9d, 0xc0, 0x67, 0xa6, 0x0c,
+0x22, 0xd9, 0x26, 0xf5, 0x45, 0xab, 0xa6, 0x65, 0x52, 0x11, 0x27, 0xd8, 0x45, 0xac, 0x63, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x03,
+0x82, 0x02, 0x01, 0x00, 0xb3, 0x57, 0x4d, 0x10, 0x62, 0x4e, 0x3a, 0xe4, 0xac, 0xea, 0xb8, 0x1c,
+0xaf, 0x32, 0x23, 0xc8, 0xb3, 0x49, 0x5a, 0x51, 0x9c, 0x76, 0x28, 0x8d, 0x79, 0xaa, 0x57, 0x46,
+0x17, 0xd5, 0xf5, 0x52, 0xf6, 0xb7, 0x44, 0xe8, 0x08, 0x44, 0xbf, 0x18, 0x84, 0xd2, 0x0b, 0x80,
+0xcd, 0xc5, 0x12, 0xfd, 0x00, 0x55, 0x05, 0x61, 0x87, 0x41, 0xdc, 0xb5, 0x24, 0x9e, 0x3c, 0xc4,
+0xd8, 0xc8, 0xfb, 0x70, 0x9e, 0x2f, 0x78, 0x96, 0x83, 0x20, 0x36, 0xde, 0x7c, 0x0f, 0x69, 0x13,
+0x88, 0xa5, 0x75, 0x36, 0x98, 0x08, 0xa6, 0xc6, 0xdf, 0xac, 0xce, 0xe3, 0x58, 0xd6, 0xb7, 0x3e,
+0xde, 0xba, 0xf3, 0xeb, 0x34, 0x40, 0xd8, 0xa2, 0x81, 0xf5, 0x78, 0x3f, 0x2f, 0xd5, 0xa5, 0xfc,
+0xd9, 0xa2, 0xd4, 0x5e, 0x04, 0x0e, 0x17, 0xad, 0xfe, 0x41, 0xf0, 0xe5, 0xb2, 0x72, 0xfa, 0x44,
+0x82, 0x33, 0x42, 0xe8, 0x2d, 0x58, 0xf7, 0x56, 0x8c, 0x62, 0x3f, 0xba, 0x42, 0xb0, 0x9c, 0x0c,
+0x5c, 0x7e, 0x2e, 0x65, 0x26, 0x5c, 0x53, 0x4f, 0x00, 0xb2, 0x78, 0x7e, 0xa1, 0x0d, 0x99, 0x2d,
+0x8d, 0xb8, 0x1d, 0x8e, 0xa2, 0xc4, 0xb0, 0xfd, 0x60, 0xd0, 0x30, 0xa4, 0x8e, 0xc8, 0x04, 0x62,
+0xa9, 0xc4, 0xed, 0x35, 0xde, 0x7a, 0x97, 0xed, 0x0e, 0x38, 0x5e, 0x92, 0x2f, 0x93, 0x70, 0xa5,
+0xa9, 0x9c, 0x6f, 0xa7, 0x7d, 0x13, 0x1d, 0x7e, 0xc6, 0x08, 0x48, 0xb1, 0x5e, 0x67, 0xeb, 0x51,
+0x08, 0x25, 0xe9, 0xe6, 0x25, 0x6b, 0x52, 0x29, 0x91, 0x9c, 0xd2, 0x39, 0x73, 0x08, 0x57, 0xde,
+0x99, 0x06, 0xb4, 0x5b, 0x9d, 0x10, 0x06, 0xe1, 0xc2, 0x00, 0xa8, 0xb8, 0x1c, 0x4a, 0x02, 0x0a,
+0x14, 0xd0, 0xc1, 0x41, 0xca, 0xfb, 0x8c, 0x35, 0x21, 0x7d, 0x82, 0x38, 0xf2, 0xa9, 0x54, 0x91,
+0x19, 0x35, 0x93, 0x94, 0x6d, 0x6a, 0x3a, 0xc5, 0xb2, 0xd0, 0xbb, 0x89, 0x86, 0x93, 0xe8, 0x9b,
+0xc9, 0x0f, 0x3a, 0xa7, 0x7a, 0xb8, 0xa1, 0xf0, 0x78, 0x46, 0xfa, 0xfc, 0x37, 0x2f, 0xe5, 0x8a,
+0x84, 0xf3, 0xdf, 0xfe, 0x04, 0xd9, 0xa1, 0x68, 0xa0, 0x2f, 0x24, 0xe2, 0x09, 0x95, 0x06, 0xd5,
+0x95, 0xca, 0xe1, 0x24, 0x96, 0xeb, 0x7c, 0xf6, 0x93, 0x05, 0xbb, 0xed, 0x73, 0xe9, 0x2d, 0xd1,
+0x75, 0x39, 0xd7, 0xe7, 0x24, 0xdb, 0xd8, 0x4e, 0x5f, 0x43, 0x8f, 0x9e, 0xd0, 0x14, 0x39, 0xbf,
+0x55, 0x70, 0x48, 0x99, 0x57, 0x31, 0xb4, 0x9c, 0xee, 0x4a, 0x98, 0x03, 0x96, 0x30, 0x1f, 0x60,
+0x06, 0xee, 0x1b, 0x23, 0xfe, 0x81, 0x60, 0x23, 0x1a, 0x47, 0x62, 0x85, 0xa5, 0xcc, 0x19, 0x34,
+0x80, 0x6f, 0xb3, 0xac, 0x1a, 0xe3, 0x9f, 0xf0, 0x7b, 0x48, 0xad, 0xd5, 0x01, 0xd9, 0x67, 0xb6,
+0xa9, 0x72, 0x93, 0xea, 0x2d, 0x66, 0xb5, 0xb2, 0xb8, 0xe4, 0x3d, 0x3c, 0xb2, 0xef, 0x4c, 0x8c,
+0xea, 0xeb, 0x07, 0xbf, 0xab, 0x35, 0x9a, 0x55, 0x86, 0xbc, 0x18, 0xa6, 0xb5, 0xa8, 0x5e, 0xb4,
+0x83, 0x6c, 0x6b, 0x69, 0x40, 0xd3, 0x9f, 0xdc, 0xf1, 0xc3, 0x69, 0x6b, 0xb9, 0xe1, 0x6d, 0x09,
+0xf4, 0xf1, 0xaa, 0x50, 0x76, 0x0a, 0x7a, 0x7d, 0x7a, 0x17, 0xa1, 0x55, 0x96, 0x42, 0x99, 0x31,
+0x09, 0xdd, 0x60, 0x11, 0x8d, 0x05, 0x30, 0x7e, 0xe6, 0x8e, 0x46, 0xd1, 0x9d, 0x14, 0xda, 0xc7,
+0x17, 0xe4, 0x05, 0x96, 0x8c, 0xc4, 0x24, 0xb5, 0x1b, 0xcf, 0x14, 0x07, 0xb2, 0x40, 0xf8, 0xa3,
+0x9e, 0x41, 0x86, 0xbc, 0x04, 0xd0, 0x6b, 0x96, 0xc8, 0x2a, 0x80, 0x34, 0xfd, 0xbf, 0xef, 0x06,
+0xa3, 0xdd, 0x58, 0xc5, 0x85, 0x3d, 0x3e, 0x8f, 0xfe, 0x9e, 0x29, 0xe0, 0xb6, 0xb8, 0x09, 0x68,
+0x19, 0x1c, 0x18, 0x43, 0x30, 0x82, 0x01, 0xfe, 0x30, 0x82, 0x01, 0x85, 0xa0, 0x03, 0x02, 0x01,
+0x02, 0x02, 0x08, 0x74, 0x97, 0x25, 0x8a, 0xc7, 0x3f, 0x7a, 0x54, 0x30, 0x0a, 0x06, 0x08, 0x2a,
+0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+0x0b, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x20, 0x30, 0x1e,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x17, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75,
+0x73, 0x74, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x45, 0x43, 0x43, 0x30, 0x1e,
+0x17, 0x0d, 0x31, 0x30, 0x30, 0x31, 0x32, 0x39, 0x31, 0x34, 0x32, 0x30, 0x32, 0x34, 0x5a, 0x17,
+0x0d, 0x34, 0x30, 0x31, 0x32, 0x33, 0x31, 0x31, 0x34, 0x32, 0x30, 0x32, 0x34, 0x5a, 0x30, 0x45,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30,
+0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72,
+0x75, 0x73, 0x74, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x17, 0x41, 0x66,
+0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75,
+0x6d, 0x20, 0x45, 0x43, 0x43, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x0d, 0x30, 0x5e,
+0x1b, 0x15, 0x9d, 0x03, 0xd0, 0xa1, 0x79, 0x35, 0xb7, 0x3a, 0x3c, 0x92, 0x7a, 0xca, 0x15, 0x1c,
+0xcd, 0x62, 0xf3, 0x9c, 0x26, 0x5c, 0x07, 0x3d, 0xe5, 0x54, 0xfa, 0xa3, 0xd6, 0xcc, 0x12, 0xea,
+0xf4, 0x14, 0x5f, 0xe8, 0x8e, 0x19, 0xab, 0x2f, 0x2e, 0x48, 0xe6, 0xac, 0x18, 0x43, 0x78, 0xac,
+0xd0, 0x37, 0xc3, 0xbd, 0xb2, 0xcd, 0x2c, 0xe6, 0x47, 0xe2, 0x1a, 0xe6, 0x63, 0xb8, 0x3d, 0x2e,
+0x2f, 0x78, 0xc4, 0x4f, 0xdb, 0xf4, 0x0f, 0xa4, 0x68, 0x4c, 0x55, 0x72, 0x6b, 0x95, 0x1d, 0x4e,
+0x18, 0x42, 0x95, 0x78, 0xcc, 0x37, 0x3c, 0x91, 0xe2, 0x9b, 0x65, 0x2b, 0x29, 0xa3, 0x42, 0x30,
+0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9a, 0xaf, 0x29, 0x7a,
+0xc0, 0x11, 0x35, 0x35, 0x26, 0x51, 0x30, 0x00, 0xc3, 0x6a, 0xfe, 0x40, 0xd5, 0xae, 0xd6, 0x3c,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01,
+0x06, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x67, 0x00,
+0x30, 0x64, 0x02, 0x30, 0x17, 0x09, 0xf3, 0x87, 0x88, 0x50, 0x5a, 0xaf, 0xc8, 0xc0, 0x42, 0xbf,
+0x47, 0x5f, 0xf5, 0x6c, 0x6a, 0x86, 0xe0, 0xc4, 0x27, 0x74, 0xe4, 0x38, 0x53, 0xd7, 0x05, 0x7f,
+0x1b, 0x34, 0xe3, 0xc6, 0x2f, 0xb3, 0xca, 0x09, 0x3c, 0x37, 0x9d, 0xd7, 0xe7, 0xb8, 0x46, 0xf1,
+0xfd, 0xa1, 0xe2, 0x71, 0x02, 0x30, 0x42, 0x59, 0x87, 0x43, 0xd4, 0x51, 0xdf, 0xba, 0xd3, 0x09,
+0x32, 0x5a, 0xce, 0x88, 0x7e, 0x57, 0x3d, 0x9c, 0x5f, 0x42, 0x6b, 0xf5, 0x07, 0x2d, 0xb5, 0xf0,
+0x82, 0x93, 0xf9, 0x59, 0x6f, 0xae, 0x64, 0xfa, 0x58, 0xe5, 0x8b, 0x1e, 0xe3, 0x63, 0xbe, 0xb5,
+0x81, 0xcd, 0x6f, 0x02, 0x8c, 0x79, 0x30, 0x82, 0x03, 0x4c, 0x30, 0x82, 0x02, 0x34, 0xa0, 0x03,
+0x02, 0x01, 0x02, 0x02, 0x08, 0x7c, 0x4f, 0x04, 0x39, 0x1c, 0xd4, 0x99, 0x2d, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x44, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73,
+0x74, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x41, 0x66, 0x66, 0x69,
+0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69,
+0x6e, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x31, 0x32, 0x39, 0x31, 0x34, 0x30, 0x38,
+0x32, 0x34, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31, 0x32, 0x33, 0x31, 0x31, 0x34, 0x30, 0x38, 0x32,
+0x34, 0x5a, 0x30, 0x44, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x66, 0x66, 0x69,
+0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x0c, 0x16, 0x41, 0x66, 0x66, 0x69, 0x72, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65,
+0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
+0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb4, 0x84, 0xcc, 0x33, 0x17, 0x2e, 0x6b,
+0x94, 0x6c, 0x6b, 0x61, 0x52, 0xa0, 0xeb, 0xa3, 0xcf, 0x79, 0x94, 0x4c, 0xe5, 0x94, 0x80, 0x99,
+0xcb, 0x55, 0x64, 0x44, 0x65, 0x8f, 0x67, 0x64, 0xe2, 0x06, 0xe3, 0x5c, 0x37, 0x49, 0xf6, 0x2f,
+0x9b, 0x84, 0x84, 0x1e, 0x2d, 0xf2, 0x60, 0x9d, 0x30, 0x4e, 0xcc, 0x84, 0x85, 0xe2, 0x2c, 0xcf,
+0x1e, 0x9e, 0xfe, 0x36, 0xab, 0x33, 0x77, 0x35, 0x44, 0xd8, 0x35, 0x96, 0x1a, 0x3d, 0x36, 0xe8,
+0x7a, 0x0e, 0xd8, 0xd5, 0x47, 0xa1, 0x6a, 0x69, 0x8b, 0xd9, 0xfc, 0xbb, 0x3a, 0xae, 0x79, 0x5a,
+0xd5, 0xf4, 0xd6, 0x71, 0xbb, 0x9a, 0x90, 0x23, 0x6b, 0x9a, 0xb7, 0x88, 0x74, 0x87, 0x0c, 0x1e,
+0x5f, 0xb9, 0x9e, 0x2d, 0xfa, 0xab, 0x53, 0x2b, 0xdc, 0xbb, 0x76, 0x3e, 0x93, 0x4c, 0x08, 0x08,
+0x8c, 0x1e, 0xa2, 0x23, 0x1c, 0xd4, 0x6a, 0xad, 0x22, 0xba, 0x99, 0x01, 0x2e, 0x6d, 0x65, 0xcb,
+0xbe, 0x24, 0x66, 0x55, 0x24, 0x4b, 0x40, 0x44, 0xb1, 0x1b, 0xd7, 0xe1, 0xc2, 0x85, 0xc0, 0xde,
+0x10, 0x3f, 0x3d, 0xed, 0xb8, 0xfc, 0xf1, 0xf1, 0x23, 0x53, 0xdc, 0xbf, 0x65, 0x97, 0x6f, 0xd9,
+0xf9, 0x40, 0x71, 0x8d, 0x7d, 0xbd, 0x95, 0xd4, 0xce, 0xbe, 0xa0, 0x5e, 0x27, 0x23, 0xde, 0xfd,
+0xa6, 0xd0, 0x26, 0x0e, 0x00, 0x29, 0xeb, 0x3c, 0x46, 0xf0, 0x3d, 0x60, 0xbf, 0x3f, 0x50, 0xd2,
+0xdc, 0x26, 0x41, 0x51, 0x9e, 0x14, 0x37, 0x42, 0x04, 0xa3, 0x70, 0x57, 0xa8, 0x1b, 0x87, 0xed,
+0x2d, 0xfa, 0x7b, 0xee, 0x8c, 0x0a, 0xe3, 0xa9, 0x66, 0x89, 0x19, 0xcb, 0x41, 0xf9, 0xdd, 0x44,
+0x36, 0x61, 0xcf, 0xe2, 0x77, 0x46, 0xc8, 0x7d, 0xf6, 0xf4, 0x92, 0x81, 0x36, 0xfd, 0xdb, 0x34,
+0xf1, 0x72, 0x7e, 0xf3, 0x0c, 0x16, 0xbd, 0xb4, 0x15, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42,
+0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x07, 0x1f, 0xd2,
+0xe7, 0x9c, 0xda, 0xc2, 0x6e, 0xa2, 0x40, 0xb4, 0xb0, 0x7a, 0x50, 0x10, 0x50, 0x74, 0xc4, 0xc8,
+0xbd, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x89, 0x57, 0xb2, 0x16, 0x7a, 0xa8, 0xc2, 0xfd, 0xd6, 0xd9,
+0x9b, 0x9b, 0x34, 0xc2, 0x9c, 0xb4, 0x32, 0x14, 0x4d, 0xa7, 0xa4, 0xdf, 0xec, 0xbe, 0xa7, 0xbe,
+0xf8, 0x43, 0xdb, 0x91, 0x37, 0xce, 0xb4, 0x32, 0x2e, 0x50, 0x55, 0x1a, 0x35, 0x4e, 0x76, 0x43,
+0x71, 0x20, 0xef, 0x93, 0x77, 0x4e, 0x15, 0x70, 0x2e, 0x87, 0xc3, 0xc1, 0x1d, 0x6d, 0xdc, 0xcb,
+0xb5, 0x27, 0xd4, 0x2c, 0x56, 0xd1, 0x52, 0x53, 0x3a, 0x44, 0xd2, 0x73, 0xc8, 0xc4, 0x1b, 0x05,
+0x65, 0x5a, 0x62, 0x92, 0x9c, 0xee, 0x41, 0x8d, 0x31, 0xdb, 0xe7, 0x34, 0xea, 0x59, 0x21, 0xd5,
+0x01, 0x7a, 0xd7, 0x64, 0xb8, 0x64, 0x39, 0xcd, 0xc9, 0xed, 0xaf, 0xed, 0x4b, 0x03, 0x48, 0xa7,
+0xa0, 0x99, 0x01, 0x80, 0xdc, 0x65, 0xa3, 0x36, 0xae, 0x65, 0x59, 0x48, 0x4f, 0x82, 0x4b, 0xc8,
+0x65, 0xf1, 0x57, 0x1d, 0xe5, 0x59, 0x2e, 0x0a, 0x3f, 0x6c, 0xd8, 0xd1, 0xf5, 0xe5, 0x09, 0xb4,
+0x6c, 0x54, 0x00, 0x0a, 0xe0, 0x15, 0x4d, 0x87, 0x75, 0x6d, 0xb7, 0x58, 0x96, 0x5a, 0xdd, 0x6d,
+0xd2, 0x00, 0xa0, 0xf4, 0x9b, 0x48, 0xbe, 0xc3, 0x37, 0xa4, 0xba, 0x36, 0xe0, 0x7c, 0x87, 0x85,
+0x97, 0x1a, 0x15, 0xa2, 0xde, 0x2e, 0xa2, 0x5b, 0xbd, 0xaf, 0x18, 0xf9, 0x90, 0x50, 0xcd, 0x70,
+0x59, 0xf8, 0x27, 0x67, 0x47, 0xcb, 0xc7, 0xa0, 0x07, 0x3a, 0x7d, 0xd1, 0x2c, 0x5d, 0x6c, 0x19,
+0x3a, 0x66, 0xb5, 0x7d, 0xfd, 0x91, 0x6f, 0x82, 0xb1, 0xbe, 0x08, 0x93, 0xdb, 0x14, 0x47, 0xf1,
+0xa2, 0x37, 0xc7, 0x45, 0x9e, 0x3c, 0xc7, 0x77, 0xaf, 0x64, 0xa8, 0x93, 0xdf, 0xf6, 0x69, 0x83,
+0x82, 0x60, 0xf2, 0x49, 0x42, 0x34, 0xed, 0x5a, 0x00, 0x54, 0x85, 0x1c, 0x16, 0x36, 0x92, 0x0c,
+0x5c, 0xfa, 0xa6, 0xad, 0xbf, 0xdb, 0x30, 0x82, 0x06, 0x14, 0x30, 0x82, 0x03, 0xfc, 0xa0, 0x03,
+0x02, 0x01, 0x02, 0x02, 0x08, 0x53, 0xec, 0x3b, 0xee, 0xfb, 0xb2, 0x48, 0x5f, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x51, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x42, 0x30, 0x40, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x0c, 0x39, 0x41, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x64, 0x20,
+0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63, 0x69, 0x6f, 0x6e,
+0x20, 0x46, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x72, 0x6f, 0x66, 0x65, 0x73, 0x69, 0x6f, 0x6e, 0x61,
+0x6c, 0x20, 0x43, 0x49, 0x46, 0x20, 0x41, 0x36, 0x32, 0x36, 0x33, 0x34, 0x30, 0x36, 0x38, 0x30,
+0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x35, 0x32, 0x30, 0x30, 0x38, 0x33, 0x38, 0x31, 0x35, 0x5a,
+0x17, 0x0d, 0x33, 0x30, 0x31, 0x32, 0x33, 0x31, 0x30, 0x38, 0x33, 0x38, 0x31, 0x35, 0x5a, 0x30,
+0x51, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x42,
+0x30, 0x40, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x39, 0x41, 0x75, 0x74, 0x6f, 0x72, 0x69, 0x64,
+0x61, 0x64, 0x20, 0x64, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x63,
+0x69, 0x6f, 0x6e, 0x20, 0x46, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x72, 0x6f, 0x66, 0x65, 0x73, 0x69,
+0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x49, 0x46, 0x20, 0x41, 0x36, 0x32, 0x36, 0x33, 0x34, 0x30,
+0x36, 0x38, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82,
+0x02, 0x01, 0x00, 0xca, 0x96, 0x6b, 0x8e, 0xea, 0xf8, 0xfb, 0xf1, 0xa2, 0x35, 0xe0, 0x7f, 0x4c,
+0xda, 0xe0, 0xc3, 0x52, 0xd7, 0x7d, 0xb6, 0x10, 0xc8, 0x02, 0x5e, 0xb3, 0x43, 0x2a, 0xc4, 0x4f,
+0x6a, 0xb2, 0xca, 0x1c, 0x5d, 0x28, 0x9a, 0x78, 0x11, 0x1a, 0x69, 0x59, 0x57, 0xaf, 0xb5, 0x20,
+0x42, 0xe4, 0x8b, 0x0f, 0xe6, 0xdf, 0x5b, 0xa6, 0x03, 0x92, 0x2f, 0xf5, 0x11, 0xe4, 0x62, 0xd7,
+0x32, 0x71, 0x38, 0xd9, 0x04, 0x0c, 0x71, 0xab, 0x3d, 0x51, 0x7e, 0x0f, 0x07, 0xdf, 0x63, 0x05,
+0x5c, 0xe9, 0xbf, 0x94, 0x6f, 0xc1, 0x29, 0x82, 0xc0, 0xb4, 0xda, 0x51, 0xb0, 0xc1, 0x3c, 0xbb,
+0xad, 0x37, 0x4a, 0x5c, 0xca, 0xf1, 0x4b, 0x36, 0x0e, 0x24, 0xab, 0xbf, 0xc3, 0x84, 0x77, 0xfd,
+0xa8, 0x50, 0xf4, 0xb1, 0xe7, 0xc6, 0x2f, 0xd2, 0x2d, 0x59, 0x8d, 0x7a, 0x0a, 0x4e, 0x96, 0x69,
+0x52, 0x02, 0xaa, 0x36, 0x98, 0xec, 0xfc, 0xfa, 0x14, 0x83, 0x0c, 0x37, 0x1f, 0xc9, 0x92, 0x37,
+0x7f, 0xd7, 0x81, 0x2d, 0xe5, 0xc4, 0xb9, 0xe0, 0x3e, 0x34, 0xfe, 0x67, 0xf4, 0x3e, 0x66, 0xd1,
+0xd3, 0xf4, 0x40, 0xcf, 0x5e, 0x62, 0x34, 0x0f, 0x70, 0x06, 0x3e, 0x20, 0x18, 0x5a, 0xce, 0xf7,
+0x72, 0x1b, 0x25, 0x6c, 0x93, 0x74, 0x14, 0x93, 0xa3, 0x73, 0xb1, 0x0e, 0xaa, 0x87, 0x10, 0x23,
+0x59, 0x5f, 0x20, 0x05, 0x19, 0x47, 0xed, 0x68, 0x8e, 0x92, 0x12, 0xca, 0x5d, 0xfc, 0xd6, 0x2b,
+0xb2, 0x92, 0x3c, 0x20, 0xcf, 0xe1, 0x5f, 0xaf, 0x20, 0xbe, 0xa0, 0x76, 0x7f, 0x76, 0xe5, 0xec,
+0x1a, 0x86, 0x61, 0x33, 0x3e, 0xe7, 0x7b, 0xb4, 0x3f, 0xa0, 0x0f, 0x8e, 0xa2, 0xb9, 0x6a, 0x6f,
+0xb9, 0x87, 0x26, 0x6f, 0x41, 0x6c, 0x88, 0xa6, 0x50, 0xfd, 0x6a, 0x63, 0x0b, 0xf5, 0x93, 0x16,
+0x1b, 0x19, 0x8f, 0xb2, 0xed, 0x9b, 0x9b, 0xc9, 0x90, 0xf5, 0x01, 0x0c, 0xdf, 0x19, 0x3d, 0x0f,
+0x3e, 0x38, 0x23, 0xc9, 0x2f, 0x8f, 0x0c, 0xd1, 0x02, 0xfe, 0x1b, 0x55, 0xd6, 0x4e, 0xd0, 0x8d,
+0x3c, 0xaf, 0x4f, 0xa4, 0xf3, 0xfe, 0xaf, 0x2a, 0xd3, 0x05, 0x9d, 0x79, 0x08, 0xa1, 0xcb, 0x57,
+0x31, 0xb4, 0x9c, 0xc8, 0x90, 0xb2, 0x67, 0xf4, 0x18, 0x16, 0x93, 0x3a, 0xfc, 0x47, 0xd8, 0xd1,
+0x78, 0x96, 0x31, 0x1f, 0xba, 0x2b, 0x0c, 0x5f, 0x5d, 0x99, 0xad, 0x63, 0x89, 0x5a, 0x24, 0x20,
+0x76, 0xd8, 0xdf, 0xfd, 0xab, 0x4e, 0xa6, 0x22, 0xaa, 0x9d, 0x5e, 0xe6, 0x27, 0x8a, 0x7d, 0x68,
+0x29, 0xa3, 0xe7, 0x8a, 0xb8, 0xda, 0x11, 0xbb, 0x17, 0x2d, 0x99, 0x9d, 0x13, 0x24, 0x46, 0xf7,
+0xc5, 0xe2, 0xd8, 0x9f, 0x8e, 0x7f, 0xc7, 0x8f, 0x74, 0x6d, 0x5a, 0xb2, 0xe8, 0x72, 0xf5, 0xac,
+0xee, 0x24, 0x10, 0xad, 0x2f, 0x14, 0xda, 0xff, 0x2d, 0x9a, 0x46, 0x71, 0x47, 0xbe, 0x42, 0xdf,
+0xbb, 0x01, 0xdb, 0xf4, 0x7f, 0xd3, 0x28, 0x8f, 0x31, 0x59, 0x5b, 0xd3, 0xc9, 0x02, 0xa6, 0xb4,
+0x52, 0xca, 0x6e, 0x97, 0xfb, 0x43, 0xc5, 0x08, 0x26, 0x6f, 0x8a, 0xf4, 0xbb, 0xfd, 0x9f, 0x28,
+0xaa, 0x0d, 0xd5, 0x45, 0xf3, 0x13, 0x3a, 0x1d, 0xd8, 0xc0, 0x78, 0x8f, 0x41, 0x67, 0x3c, 0x1e,
+0x94, 0x64, 0xae, 0x7b, 0x0b, 0xc5, 0xe8, 0xd9, 0x01, 0x88, 0x39, 0x1a, 0x97, 0x86, 0x64, 0x41,
+0xd5, 0x3b, 0x87, 0x0c, 0x6e, 0xfa, 0x0f, 0xc6, 0xbd, 0x48, 0x14, 0xbf, 0x39, 0x4d, 0xd4, 0x9e,
+0x41, 0xb6, 0x8f, 0x96, 0x1d, 0x63, 0x96, 0x93, 0xd9, 0x95, 0x06, 0x78, 0x31, 0x68, 0x9e, 0x37,
+0x06, 0x3b, 0x80, 0x89, 0x45, 0x61, 0x39, 0x23, 0xc7, 0x1b, 0x44, 0xa3, 0x15, 0xe5, 0x1c, 0xf8,
+0x92, 0x30, 0xbb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xef, 0x30, 0x81, 0xec, 0x30, 0x12,
+0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02,
+0x01, 0x01, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0xcd, 0xeb,
+0xab, 0x35, 0x1e, 0x00, 0x3e, 0x7e, 0xd5, 0x74, 0xc0, 0x1c, 0xb4, 0x73, 0x47, 0x0e, 0x1a, 0x64,
+0x2f, 0x30, 0x81, 0xa6, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x81, 0x9e, 0x30, 0x81, 0x9b, 0x30,
+0x81, 0x98, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x81, 0x8f, 0x30, 0x2f, 0x06, 0x08, 0x2b,
+0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+0x77, 0x77, 0x77, 0x2e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x70, 0x72, 0x6f, 0x66, 0x65, 0x73, 0x69,
+0x6f, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x5c, 0x06, 0x08,
+0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x50, 0x1e, 0x4e, 0x00, 0x50, 0x00, 0x61,
+0x00, 0x73, 0x00, 0x65, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6c,
+0x00, 0x61, 0x00, 0x20, 0x00, 0x42, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x6f,
+0x00, 0x76, 0x00, 0x61, 0x00, 0x20, 0x00, 0x34, 0x00, 0x37, 0x00, 0x20, 0x00, 0x42, 0x00, 0x61,
+0x00, 0x72, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x20,
+0x00, 0x30, 0x00, 0x38, 0x00, 0x30, 0x00, 0x31, 0x00, 0x37, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x17, 0x7d,
+0xa0, 0xf9, 0xb4, 0xdd, 0xc5, 0xc5, 0xeb, 0xad, 0x4b, 0x24, 0xb5, 0xa1, 0x02, 0xab, 0xdd, 0xa5,
+0x88, 0x4a, 0xb2, 0x0f, 0x55, 0x4b, 0x2b, 0x57, 0x8c, 0x3b, 0xe5, 0x31, 0xdd, 0xfe, 0xc4, 0x32,
+0xf1, 0xe7, 0x5b, 0x64, 0x96, 0x36, 0x32, 0x18, 0xec, 0xa5, 0x32, 0x77, 0xd7, 0xe3, 0x44, 0xb6,
+0xc0, 0x11, 0x2a, 0x80, 0xb9, 0x3d, 0x6a, 0x6e, 0x7c, 0x9b, 0xd3, 0xad, 0xfc, 0xc3, 0xd6, 0xa3,
+0xe6, 0x64, 0x29, 0x7c, 0xd1, 0xe1, 0x38, 0x1e, 0x82, 0x2b, 0xff, 0x27, 0x65, 0xaf, 0xfb, 0x16,
+0x15, 0xc4, 0x2e, 0x71, 0x84, 0xe5, 0xb5, 0xff, 0xfa, 0xa4, 0x47, 0xbd, 0x64, 0x32, 0xbb, 0xf6,
+0x25, 0x84, 0xa2, 0x27, 0x42, 0xf5, 0x20, 0xb0, 0xc2, 0x13, 0x10, 0x11, 0xcd, 0x10, 0x15, 0xba,
+0x42, 0x90, 0x2a, 0xd2, 0x44, 0xe1, 0x96, 0x26, 0xeb, 0x31, 0x48, 0x12, 0xfd, 0x2a, 0xda, 0xc9,
+0x06, 0xcf, 0x74, 0x1e, 0xa9, 0x4b, 0xd5, 0x87, 0x28, 0xf9, 0x79, 0x34, 0x92, 0x3e, 0x2e, 0x44,
+0xe8, 0xf6, 0x8f, 0x4f, 0x8f, 0x35, 0x3f, 0x25, 0xb3, 0x39, 0xdc, 0x63, 0x2a, 0x90, 0x6b, 0x20,
+0x5f, 0xc4, 0x52, 0x12, 0x4e, 0x97, 0x2c, 0x2a, 0xac, 0x9d, 0x97, 0xde, 0x48, 0xf2, 0xa3, 0x66,
+0xdb, 0xc2, 0xd2, 0x83, 0x95, 0xa6, 0x66, 0xa7, 0x9e, 0x25, 0x0f, 0xe9, 0x0b, 0x33, 0x91, 0x65,
+0x0a, 0x5a, 0xc3, 0xd9, 0x54, 0x12, 0xdd, 0xaf, 0xc3, 0x4e, 0x0e, 0x1f, 0x26, 0x5e, 0x0d, 0xdc,
+0xb3, 0x8d, 0xec, 0xd5, 0x81, 0x70, 0xde, 0xd2, 0x4f, 0x24, 0x05, 0xf3, 0x6c, 0x4e, 0xf5, 0x4c,
+0x49, 0x66, 0x8d, 0xd1, 0xff, 0xd2, 0x0b, 0x25, 0x41, 0x48, 0xfe, 0x51, 0x84, 0xc6, 0x42, 0xaf,
+0x80, 0x04, 0xcf, 0xd0, 0x7e, 0x64, 0x49, 0xe4, 0xf2, 0xdf, 0xa2, 0xec, 0xb1, 0x4c, 0xc0, 0x2a,
+0x1d, 0xe7, 0xb4, 0xb1, 0x65, 0xa2, 0xc4, 0xbc, 0xf1, 0x98, 0xf4, 0xaa, 0x70, 0x07, 0x63, 0xb4,
+0xb8, 0xda, 0x3b, 0x4c, 0xfa, 0x40, 0x22, 0x30, 0x5b, 0x11, 0xa6, 0xf0, 0x05, 0x0e, 0xc6, 0x02,
+0x03, 0x48, 0xab, 0x86, 0x9b, 0x85, 0xdd, 0xdb, 0xdd, 0xea, 0xa2, 0x76, 0x80, 0x73, 0x7d, 0xf5,
+0x9c, 0x04, 0xc4, 0x45, 0x8d, 0xe7, 0xb9, 0x1c, 0x8b, 0x9e, 0xea, 0xd7, 0x75, 0xd1, 0x72, 0xb1,
+0xde, 0x75, 0x44, 0xe7, 0x42, 0x7d, 0xe2, 0x57, 0x6b, 0x7d, 0xdc, 0x99, 0xbc, 0x3d, 0x83, 0x28,
+0xea, 0x80, 0x93, 0x8d, 0xc5, 0x4c, 0x65, 0xc1, 0x70, 0x81, 0xb8, 0x38, 0xfc, 0x43, 0x31, 0xb2,
+0xf6, 0x03, 0x34, 0x47, 0xb2, 0xac, 0xfb, 0x22, 0x06, 0xcb, 0x1e, 0xdd, 0x17, 0x47, 0x1c, 0x5f,
+0x66, 0xb9, 0xd3, 0x1a, 0xa2, 0xda, 0x11, 0xb1, 0xa4, 0xbc, 0x23, 0xc9, 0xe4, 0xbe, 0x87, 0xff,
+0xb9, 0x94, 0xb6, 0xf8, 0x5d, 0x20, 0x4a, 0xd4, 0x5f, 0xe7, 0xbd, 0x68, 0x7b, 0x65, 0xf2, 0x15,
+0x1e, 0xd2, 0x3a, 0xa9, 0x2d, 0xe9, 0xd8, 0x6b, 0x24, 0xac, 0x97, 0x58, 0x44, 0x47, 0xad, 0x59,
+0x18, 0xf1, 0x21, 0x65, 0x70, 0xde, 0xce, 0x34, 0x60, 0xa8, 0x40, 0xf1, 0xf3, 0x3c, 0xa4, 0xc3,
+0x28, 0x23, 0x8c, 0xfe, 0x27, 0x33, 0x43, 0x40, 0xa0, 0x17, 0x3c, 0xeb, 0xea, 0x3b, 0xb0, 0x72,
+0xa6, 0xa3, 0xb9, 0x4a, 0x4b, 0x5e, 0x16, 0x48, 0xf4, 0xb2, 0xbc, 0xc8, 0x8c, 0x92, 0xc5, 0x9d,
+0x9f, 0xac, 0x72, 0x36, 0xbc, 0x34, 0x80, 0x34, 0x6b, 0xa9, 0x8b, 0x92, 0xc0, 0xb8, 0x17, 0xed,
+0xec, 0x76, 0x53, 0xf5, 0x24, 0x01, 0x8c, 0xb3, 0x22, 0xe8, 0x4b, 0x7c, 0x55, 0xc6, 0x9d, 0xfa,
+0xa3, 0x14, 0xbb, 0x65, 0x85, 0x6e, 0x6e, 0x4f, 0x12, 0x7e, 0x0a, 0x3c, 0x9d, 0x95, 0x30, 0x82,
+0x03, 0x77, 0x30, 0x82, 0x02, 0x5f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x02, 0x00, 0x00,
+0xb9, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x45, 0x31,
+0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d,
+0x6f, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79,
+0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x19, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x43, 0x79, 0x62,
+0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d,
+0x30, 0x30, 0x30, 0x35, 0x31, 0x32, 0x31, 0x38, 0x34, 0x36, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32,
+0x35, 0x30, 0x35, 0x31, 0x32, 0x32, 0x33, 0x35, 0x39, 0x30, 0x30, 0x5a, 0x30, 0x5a, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x45, 0x31, 0x12, 0x30, 0x10, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x42, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x31,
+0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x42,
+0x61, 0x6c, 0x74, 0x69, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72,
+0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
+0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa3, 0x04, 0xbb, 0x22, 0xab, 0x98, 0x3d,
+0x57, 0xe8, 0x26, 0x72, 0x9a, 0xb5, 0x79, 0xd4, 0x29, 0xe2, 0xe1, 0xe8, 0x95, 0x80, 0xb1, 0xb0,
+0xe3, 0x5b, 0x8e, 0x2b, 0x29, 0x9a, 0x64, 0xdf, 0xa1, 0x5d, 0xed, 0xb0, 0x09, 0x05, 0x6d, 0xdb,
+0x28, 0x2e, 0xce, 0x62, 0xa2, 0x62, 0xfe, 0xb4, 0x88, 0xda, 0x12, 0xeb, 0x38, 0xeb, 0x21, 0x9d,
+0xc0, 0x41, 0x2b, 0x01, 0x52, 0x7b, 0x88, 0x77, 0xd3, 0x1c, 0x8f, 0xc7, 0xba, 0xb9, 0x88, 0xb5,
+0x6a, 0x09, 0xe7, 0x73, 0xe8, 0x11, 0x40, 0xa7, 0xd1, 0xcc, 0xca, 0x62, 0x8d, 0x2d, 0xe5, 0x8f,
+0x0b, 0xa6, 0x50, 0xd2, 0xa8, 0x50, 0xc3, 0x28, 0xea, 0xf5, 0xab, 0x25, 0x87, 0x8a, 0x9a, 0x96,
+0x1c, 0xa9, 0x67, 0xb8, 0x3f, 0x0c, 0xd5, 0xf7, 0xf9, 0x52, 0x13, 0x2f, 0xc2, 0x1b, 0xd5, 0x70,
+0x70, 0xf0, 0x8f, 0xc0, 0x12, 0xca, 0x06, 0xcb, 0x9a, 0xe1, 0xd9, 0xca, 0x33, 0x7a, 0x77, 0xd6,
+0xf8, 0xec, 0xb9, 0xf1, 0x68, 0x44, 0x42, 0x48, 0x13, 0xd2, 0xc0, 0xc2, 0xa4, 0xae, 0x5e, 0x60,
+0xfe, 0xb6, 0xa6, 0x05, 0xfc, 0xb4, 0xdd, 0x07, 0x59, 0x02, 0xd4, 0x59, 0x18, 0x98, 0x63, 0xf5,
+0xa5, 0x63, 0xe0, 0x90, 0x0c, 0x7d, 0x5d, 0xb2, 0x06, 0x7a, 0xf3, 0x85, 0xea, 0xeb, 0xd4, 0x03,
+0xae, 0x5e, 0x84, 0x3e, 0x5f, 0xff, 0x15, 0xed, 0x69, 0xbc, 0xf9, 0x39, 0x36, 0x72, 0x75, 0xcf,
+0x77, 0x52, 0x4d, 0xf3, 0xc9, 0x90, 0x2c, 0xb9, 0x3d, 0xe5, 0xc9, 0x23, 0x53, 0x3f, 0x1f, 0x24,
+0x98, 0x21, 0x5c, 0x07, 0x99, 0x29, 0xbd, 0xc6, 0x3a, 0xec, 0xe7, 0x6e, 0x86, 0x3a, 0x6b, 0x97,
+0x74, 0x63, 0x33, 0xbd, 0x68, 0x18, 0x31, 0xf0, 0x78, 0x8d, 0x76, 0xbf, 0xfc, 0x9e, 0x8e, 0x5d,
+0x2a, 0x86, 0xa7, 0x4d, 0x90, 0xdc, 0x27, 0x1a, 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x45,
+0x30, 0x43, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xe5, 0x9d, 0x59,
+0x30, 0x82, 0x47, 0x58, 0xcc, 0xac, 0xfa, 0x08, 0x54, 0x36, 0x86, 0x7b, 0x3a, 0xb5, 0x04, 0x4d,
+0xf0, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01,
+0x01, 0xff, 0x02, 0x01, 0x03, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x85, 0x0c, 0x5d, 0x8e, 0xe4, 0x6f, 0x51,
+0x68, 0x42, 0x05, 0xa0, 0xdd, 0xbb, 0x4f, 0x27, 0x25, 0x84, 0x03, 0xbd, 0xf7, 0x64, 0xfd, 0x2d,
+0xd7, 0x30, 0xe3, 0xa4, 0x10, 0x17, 0xeb, 0xda, 0x29, 0x29, 0xb6, 0x79, 0x3f, 0x76, 0xf6, 0x19,
+0x13, 0x23, 0xb8, 0x10, 0x0a, 0xf9, 0x58, 0xa4, 0xd4, 0x61, 0x70, 0xbd, 0x04, 0x61, 0x6a, 0x12,
+0x8a, 0x17, 0xd5, 0x0a, 0xbd, 0xc5, 0xbc, 0x30, 0x7c, 0xd6, 0xe9, 0x0c, 0x25, 0x8d, 0x86, 0x40,
+0x4f, 0xec, 0xcc, 0xa3, 0x7e, 0x38, 0xc6, 0x37, 0x11, 0x4f, 0xed, 0xdd, 0x68, 0x31, 0x8e, 0x4c,
+0xd2, 0xb3, 0x01, 0x74, 0xee, 0xbe, 0x75, 0x5e, 0x07, 0x48, 0x1a, 0x7f, 0x70, 0xff, 0x16, 0x5c,
+0x84, 0xc0, 0x79, 0x85, 0xb8, 0x05, 0xfd, 0x7f, 0xbe, 0x65, 0x11, 0xa3, 0x0f, 0xc0, 0x02, 0xb4,
+0xf8, 0x52, 0x37, 0x39, 0x04, 0xd5, 0xa9, 0x31, 0x7a, 0x18, 0xbf, 0xa0, 0x2a, 0xf4, 0x12, 0x99,
+0xf7, 0xa3, 0x45, 0x82, 0xe3, 0x3c, 0x5e, 0xf5, 0x9d, 0x9e, 0xb5, 0xc8, 0x9e, 0x7c, 0x2e, 0xc8,
+0xa4, 0x9e, 0x4e, 0x08, 0x14, 0x4b, 0x6d, 0xfd, 0x70, 0x6d, 0x6b, 0x1a, 0x63, 0xbd, 0x64, 0xe6,
+0x1f, 0xb7, 0xce, 0xf0, 0xf2, 0x9f, 0x2e, 0xbb, 0x1b, 0xb7, 0xf2, 0x50, 0x88, 0x73, 0x92, 0xc2,
+0xe2, 0xe3, 0x16, 0x8d, 0x9a, 0x32, 0x02, 0xab, 0x8e, 0x18, 0xdd, 0xe9, 0x10, 0x11, 0xee, 0x7e,
+0x35, 0xab, 0x90, 0xaf, 0x3e, 0x30, 0x94, 0x7a, 0xd0, 0x33, 0x3d, 0xa7, 0x65, 0x0f, 0xf5, 0xfc,
+0x8e, 0x9e, 0x62, 0xcf, 0x47, 0x44, 0x2c, 0x01, 0x5d, 0xbb, 0x1d, 0xb5, 0x32, 0xd2, 0x47, 0xd2,
+0x38, 0x2e, 0xd0, 0xfe, 0x81, 0xdc, 0x32, 0x6a, 0x1e, 0xb5, 0xee, 0x3c, 0xd5, 0xfc, 0xe7, 0x81,
+0x1d, 0x19, 0xc3, 0x24, 0x42, 0xea, 0x63, 0x39, 0xa9, 0x30, 0x82, 0x05, 0x59, 0x30, 0x82, 0x03,
+0x41, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4f, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x0c, 0x14, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73, 0x20, 0x41, 0x53, 0x2d, 0x39, 0x38, 0x33,
+0x31, 0x36, 0x33, 0x33, 0x32, 0x37, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+0x17, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x31, 0x30,
+0x32, 0x36, 0x30, 0x38, 0x33, 0x38, 0x30, 0x33, 0x5a, 0x17, 0x0d, 0x34, 0x30, 0x31, 0x30, 0x32,
+0x36, 0x30, 0x38, 0x33, 0x38, 0x30, 0x33, 0x5a, 0x30, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4f, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x0c, 0x14, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73, 0x20, 0x41, 0x53, 0x2d, 0x39, 0x38, 0x33,
+0x31, 0x36, 0x33, 0x33, 0x32, 0x37, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+0x17, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00,
+0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xd7, 0xc7, 0x5e, 0xf7, 0xc1, 0x07, 0xd4,
+0x77, 0xfb, 0x43, 0x21, 0xf4, 0xf4, 0xf5, 0x69, 0xe4, 0xee, 0x32, 0x01, 0xdb, 0xa3, 0x86, 0x1f,
+0xe4, 0x59, 0x0d, 0xba, 0xe7, 0x75, 0x83, 0x52, 0xeb, 0xea, 0x1c, 0x61, 0x15, 0x48, 0xbb, 0x1d,
+0x07, 0xca, 0x8c, 0xae, 0xb0, 0xdc, 0x96, 0x9d, 0xea, 0xc3, 0x60, 0x92, 0x86, 0x82, 0x28, 0x73,
+0x9c, 0x56, 0x06, 0xff, 0x4b, 0x64, 0xf0, 0x0c, 0x2a, 0x37, 0x49, 0xb5, 0xe5, 0xcf, 0x0c, 0x7c,
+0xee, 0xf1, 0x4a, 0xbb, 0x73, 0x30, 0x65, 0xf3, 0xd5, 0x2f, 0x83, 0xb6, 0x7e, 0xe3, 0xe7, 0xf5,
+0x9e, 0xab, 0x60, 0xf9, 0xd3, 0xf1, 0x9d, 0x92, 0x74, 0x8a, 0xe4, 0x1c, 0x96, 0xac, 0x5b, 0x80,
+0xe9, 0xb5, 0xf4, 0x31, 0x87, 0xa3, 0x51, 0xfc, 0xc7, 0x7e, 0xa1, 0x6f, 0x8e, 0x53, 0x77, 0xd4,
+0x97, 0xc1, 0x55, 0x33, 0x92, 0x3e, 0x18, 0x2f, 0x75, 0xd4, 0xad, 0x86, 0x49, 0xcb, 0x95, 0xaf,
+0x54, 0x06, 0x6c, 0xd8, 0x06, 0x13, 0x8d, 0x5b, 0xff, 0xe1, 0x26, 0x19, 0x59, 0xc0, 0x24, 0xba,
+0x81, 0x71, 0x79, 0x90, 0x44, 0x50, 0x68, 0x24, 0x94, 0x5f, 0xb8, 0xb3, 0x11, 0xf1, 0x29, 0x41,
+0x61, 0xa3, 0x41, 0xcb, 0x23, 0x36, 0xd5, 0xc1, 0xf1, 0x32, 0x50, 0x10, 0x4e, 0x7f, 0xf4, 0x86,
+0x93, 0xec, 0x84, 0xd3, 0x8e, 0xbc, 0x4b, 0xbf, 0x5c, 0x01, 0x4e, 0x07, 0x3d, 0xdc, 0x14, 0x8a,
+0x94, 0x0a, 0xa4, 0xea, 0x73, 0xfb, 0x0b, 0x51, 0xe8, 0x13, 0x07, 0x18, 0xfa, 0x0e, 0xf1, 0x2b,
+0xd1, 0x54, 0x15, 0x7d, 0x3c, 0xe1, 0xf7, 0xb4, 0x19, 0x42, 0x67, 0x62, 0x5e, 0x77, 0xe0, 0xa2,
+0x55, 0xec, 0xb6, 0xd9, 0x69, 0x17, 0xd5, 0x3a, 0xaf, 0x44, 0xed, 0x4a, 0xc5, 0x9e, 0xe4, 0x7a,
+0x27, 0x7c, 0xe5, 0x75, 0xd7, 0xaa, 0xcb, 0x25, 0xe7, 0xdf, 0x6b, 0x0a, 0xdb, 0x0f, 0x4d, 0x93,
+0x4e, 0xa8, 0xa0, 0xcd, 0x7b, 0x2e, 0xf2, 0x59, 0x01, 0x6a, 0xb7, 0x0d, 0xb8, 0x07, 0x81, 0x7e,
+0x8b, 0x38, 0x1b, 0x38, 0xe6, 0x0a, 0x57, 0x99, 0x3d, 0xee, 0x21, 0xe8, 0xa3, 0xf5, 0x0c, 0x16,
+0xdd, 0x8b, 0xec, 0x34, 0x8e, 0x9c, 0x2a, 0x1c, 0x00, 0x15, 0x17, 0x8d, 0x68, 0x83, 0xd2, 0x70,
+0x9f, 0x18, 0x08, 0xcd, 0x11, 0x68, 0xd5, 0xc9, 0x6b, 0x52, 0xcd, 0xc4, 0x46, 0x8f, 0xdc, 0xb5,
+0xf3, 0xd8, 0x57, 0x73, 0x1e, 0xe9, 0x94, 0x39, 0x04, 0xbf, 0xd3, 0xde, 0x38, 0xde, 0xb4, 0x53,
+0xec, 0x69, 0x1c, 0xa2, 0x7e, 0xc4, 0x8f, 0xe4, 0x1b, 0x70, 0xad, 0xf2, 0xa2, 0xf9, 0xfb, 0xf7,
+0x16, 0x64, 0x66, 0x69, 0x9f, 0x49, 0x51, 0xa2, 0xe2, 0x15, 0x18, 0x67, 0x06, 0x4a, 0x7f, 0xd5,
+0x6c, 0xb5, 0x4d, 0xb3, 0x33, 0xe0, 0x61, 0xeb, 0x5d, 0xbe, 0xe9, 0x98, 0x0f, 0x32, 0xd7, 0x1d,
+0x4b, 0x3c, 0x2e, 0x5a, 0x01, 0x52, 0x91, 0x09, 0xf2, 0xdf, 0xea, 0x8d, 0xd8, 0x06, 0x40, 0x63,
+0xaa, 0x11, 0xe4, 0xfe, 0xc3, 0x37, 0x9e, 0x14, 0x52, 0x3f, 0xf4, 0xe2, 0xcc, 0xf2, 0x61, 0x93,
+0xd1, 0xfd, 0x67, 0x6b, 0xd7, 0x52, 0xae, 0xbf, 0x68, 0xab, 0x40, 0x43, 0xa0, 0x57, 0x35, 0x53,
+0x78, 0xf0, 0x53, 0xf8, 0x61, 0x42, 0x07, 0x64, 0xc6, 0xd7, 0x6f, 0x9b, 0x4c, 0x38, 0x0d, 0x63,
+0xac, 0x62, 0xaf, 0x36, 0x8b, 0xa2, 0x73, 0x0a, 0x0d, 0xf5, 0x21, 0xbd, 0x74, 0xaa, 0x4d, 0xea,
+0x72, 0x03, 0x49, 0xdb, 0xc7, 0x5f, 0x1d, 0x62, 0x63, 0xc7, 0xfd, 0xdd, 0x91, 0xec, 0x33, 0xee,
+0xf5, 0x6d, 0xb4, 0x6e, 0x30, 0x68, 0xde, 0xc8, 0xd6, 0x26, 0xb0, 0x75, 0x5e, 0x7b, 0xb4, 0x07,
+0x20, 0x98, 0xa1, 0x76, 0x32, 0xb8, 0x4d, 0x6c, 0x4f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42,
+0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc9, 0x80,
+0x77, 0xe0, 0x62, 0x92, 0x82, 0xf5, 0x46, 0x9c, 0xf3, 0xba, 0xf7, 0x4c, 0xc3, 0xde, 0xb8, 0xa3,
+0xad, 0x39, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x53, 0x5f, 0x21, 0xf5, 0xba, 0xb0, 0x3a, 0x52, 0x39, 0x2c,
+0x92, 0xb0, 0x6c, 0x00, 0xc9, 0xef, 0xce, 0x20, 0xef, 0x06, 0xf2, 0x96, 0x9e, 0xe9, 0xa4, 0x74,
+0x7f, 0x7a, 0x16, 0xfc, 0xb7, 0xf5, 0xb6, 0xfb, 0x15, 0x1b, 0x3f, 0xab, 0xa6, 0xc0, 0x72, 0x5d,
+0x10, 0xb1, 0x71, 0xee, 0xbc, 0x4f, 0xe3, 0xad, 0xac, 0x03, 0x6d, 0x2e, 0x71, 0x2e, 0xaf, 0xc4,
+0xe3, 0xad, 0xa3, 0xbd, 0x0c, 0x11, 0xa7, 0xb4, 0xff, 0x4a, 0xb2, 0x7b, 0x10, 0x10, 0x1f, 0xa7,
+0x57, 0x41, 0xb2, 0xc0, 0xae, 0xf4, 0x2c, 0x59, 0xd6, 0x47, 0x10, 0x88, 0xf3, 0x21, 0x51, 0x29,
+0x30, 0xca, 0x60, 0x86, 0xaf, 0x46, 0xab, 0x1d, 0xed, 0x3a, 0x5b, 0xb0, 0x94, 0xde, 0x44, 0xe3,
+0x41, 0x08, 0xa2, 0xc1, 0xec, 0x1d, 0xd6, 0xfd, 0x4f, 0xb6, 0xd6, 0x47, 0xd0, 0x14, 0x0b, 0xca,
+0xe6, 0xca, 0xb5, 0x7b, 0x77, 0x7e, 0x41, 0x1f, 0x5e, 0x83, 0xc7, 0xb6, 0x8c, 0x39, 0x96, 0xb0,
+0x3f, 0x96, 0x81, 0x41, 0x6f, 0x60, 0x90, 0xe2, 0xe8, 0xf9, 0xfb, 0x22, 0x71, 0xd9, 0x7d, 0xb3,
+0x3d, 0x46, 0xbf, 0xb4, 0x84, 0xaf, 0x90, 0x1c, 0x0f, 0x8f, 0x12, 0x6a, 0xaf, 0xef, 0xee, 0x1e,
+0x7a, 0xae, 0x02, 0x4a, 0x8a, 0x17, 0x2b, 0x76, 0xfe, 0xac, 0x54, 0x89, 0x24, 0x2c, 0x4f, 0x3f,
+0xb6, 0xb2, 0xa7, 0x4e, 0x8c, 0xa8, 0x91, 0x97, 0xfb, 0x29, 0xc6, 0x7b, 0x5c, 0x2d, 0xb9, 0xcb,
+0x66, 0xb6, 0xb7, 0xa8, 0x5b, 0x12, 0x51, 0x85, 0xb5, 0x09, 0x7e, 0x62, 0x78, 0x70, 0xfe, 0xa9,
+0x6a, 0x60, 0xb6, 0x1d, 0x0e, 0x79, 0x0c, 0xfd, 0xca, 0xea, 0x24, 0x80, 0x72, 0xc3, 0x97, 0x3f,
+0xf2, 0x77, 0xab, 0x43, 0x22, 0x0a, 0xc7, 0xeb, 0xb6, 0x0c, 0x84, 0x82, 0x2c, 0x80, 0x6b, 0x41,
+0x8a, 0x08, 0xc0, 0xeb, 0xa5, 0x6b, 0xdf, 0x99, 0x12, 0xcb, 0x8a, 0xd5, 0x5e, 0x80, 0x0c, 0x91,
+0xe0, 0x26, 0x08, 0x36, 0x48, 0xc5, 0xfa, 0x38, 0x11, 0x35, 0xff, 0x25, 0x83, 0x2d, 0xf2, 0x7a,
+0xbf, 0xda, 0xfd, 0x8e, 0xfe, 0xa5, 0xcb, 0x45, 0x2c, 0x1f, 0xc4, 0x88, 0x53, 0xae, 0x77, 0x0e,
+0xd9, 0x9a, 0x76, 0xc5, 0x8e, 0x2c, 0x1d, 0xa3, 0xba, 0xd5, 0xec, 0x32, 0xae, 0xc0, 0xaa, 0xac,
+0xf7, 0xd1, 0x7a, 0x4d, 0xeb, 0xd4, 0x07, 0xe2, 0x48, 0xf7, 0x22, 0x8e, 0xb0, 0xa4, 0x9f, 0x6a,
+0xce, 0x8e, 0xb2, 0xb2, 0x60, 0xf4, 0xa3, 0x22, 0xd0, 0x23, 0xeb, 0x94, 0x5a, 0x7a, 0x69, 0xdd,
+0x0f, 0xbf, 0x40, 0x57, 0xac, 0x6b, 0x59, 0x50, 0xd9, 0xa3, 0x99, 0xe1, 0x6e, 0xfe, 0x8d, 0x01,
+0x79, 0x27, 0x23, 0x15, 0xde, 0x92, 0x9d, 0x7b, 0x09, 0x4d, 0x5a, 0xe7, 0x4b, 0x48, 0x30, 0x5a,
+0x18, 0xe6, 0x0a, 0x6d, 0xe6, 0x8f, 0xe0, 0xd2, 0xbb, 0xe6, 0xdf, 0x7c, 0x6e, 0x21, 0x82, 0xc1,
+0x68, 0x39, 0x4d, 0xb4, 0x98, 0x58, 0x66, 0x62, 0xcc, 0x4a, 0x90, 0x5e, 0xc3, 0xfa, 0x27, 0x04,
+0xb1, 0x79, 0x15, 0x74, 0x99, 0xcc, 0xbe, 0xad, 0x20, 0xde, 0x26, 0x60, 0x1c, 0xeb, 0x56, 0x51,
+0xa6, 0xa3, 0xea, 0xe4, 0xa3, 0x3f, 0xa7, 0xff, 0x61, 0xdc, 0xf1, 0x5a, 0x4d, 0x6c, 0x32, 0x23,
+0x43, 0xee, 0xac, 0xa8, 0xee, 0xee, 0x4a, 0x12, 0x09, 0x3c, 0x5d, 0x71, 0xc2, 0xbe, 0x79, 0xfa,
+0xc2, 0x87, 0x68, 0x1d, 0x0b, 0xfd, 0x5c, 0x69, 0xcc, 0x06, 0xd0, 0x9a, 0x7d, 0x54, 0x99, 0x2a,
+0xc9, 0x39, 0x1a, 0x19, 0xaf, 0x4b, 0x2a, 0x43, 0xf3, 0x63, 0x5d, 0x5a, 0x58, 0xe2, 0x2f, 0xe3,
+0x1d, 0xe4, 0xa9, 0xd6, 0xd0, 0x0a, 0xd0, 0x9e, 0xbf, 0xd7, 0x81, 0x09, 0xf1, 0xc9, 0xc7, 0x26,
+0x0d, 0xac, 0x98, 0x16, 0x56, 0xa0, 0x30, 0x82, 0x03, 0x77, 0x30, 0x82, 0x02, 0x5f, 0xa0, 0x03,
+0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x33, 0xcb, 0x62, 0x2c, 0x5f, 0xb3, 0x32, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x3c, 0x31, 0x1e,
+0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, 0x41, 0x74, 0x6f, 0x73, 0x20, 0x54, 0x72,
+0x75, 0x73, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x32, 0x30, 0x31, 0x31, 0x31, 0x0d,
+0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x04, 0x41, 0x74, 0x6f, 0x73, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31,
+0x30, 0x37, 0x30, 0x37, 0x31, 0x34, 0x35, 0x38, 0x33, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31,
+0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x3c, 0x31, 0x1e, 0x30, 0x1c,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, 0x41, 0x74, 0x6f, 0x73, 0x20, 0x54, 0x72, 0x75, 0x73,
+0x74, 0x65, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x32, 0x30, 0x31, 0x31, 0x31, 0x0d, 0x30, 0x0b,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x04, 0x41, 0x74, 0x6f, 0x73, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
+0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x95, 0x85, 0x3b, 0x97, 0x6f, 0x2a, 0x3b,
+0x2e, 0x3b, 0xcf, 0xa6, 0xf3, 0x29, 0x35, 0xbe, 0xcf, 0x18, 0xac, 0x3e, 0xaa, 0xd9, 0xf8, 0x4d,
+0xa0, 0x3e, 0x1a, 0x47, 0xb9, 0xbc, 0x9a, 0xdf, 0xf2, 0xfe, 0xcc, 0x3e, 0x47, 0xe8, 0x7a, 0x96,
+0xc2, 0x24, 0x8e, 0x35, 0xf4, 0xa9, 0x0c, 0xfc, 0x82, 0xfd, 0x6d, 0xc1, 0x72, 0x62, 0x27, 0xbd,
+0xea, 0x6b, 0xeb, 0xe7, 0x8a, 0xcc, 0x54, 0x3e, 0x90, 0x50, 0xcf, 0x80, 0xd4, 0x95, 0xfb, 0xe8,
+0xb5, 0x82, 0xd4, 0x14, 0xc5, 0xb6, 0xa9, 0x55, 0x25, 0x57, 0xdb, 0xb1, 0x50, 0xf6, 0xb0, 0x60,
+0x64, 0x59, 0x7a, 0x69, 0xcf, 0x03, 0xb7, 0x6f, 0x0d, 0xbe, 0xca, 0x3e, 0x6f, 0x74, 0x72, 0xea,
+0xaa, 0x30, 0x2a, 0x73, 0x62, 0xbe, 0x49, 0x91, 0x61, 0xc8, 0x11, 0xfe, 0x0e, 0x03, 0x2a, 0xf7,
+0x6a, 0x20, 0xdc, 0x02, 0x15, 0x0d, 0x5e, 0x15, 0x6a, 0xfc, 0xe3, 0x82, 0xc1, 0xb5, 0xc5, 0x9d,
+0x64, 0x09, 0x6c, 0xa3, 0x59, 0x98, 0x07, 0x27, 0xc7, 0x1b, 0x96, 0x2b, 0x61, 0x74, 0x71, 0x6c,
+0x43, 0xf1, 0xf7, 0x35, 0x89, 0x10, 0xe0, 0x9e, 0xec, 0x55, 0xa1, 0x37, 0x22, 0xa2, 0x87, 0x04,
+0x05, 0x2c, 0x47, 0x7d, 0xb4, 0x1c, 0xb9, 0x62, 0x29, 0x66, 0x28, 0xca, 0xb7, 0xe1, 0x93, 0xf5,
+0xa4, 0x94, 0x03, 0x99, 0xb9, 0x70, 0x85, 0xb5, 0xe6, 0x48, 0xea, 0x8d, 0x50, 0xfc, 0xd9, 0xde,
+0xcc, 0x6f, 0x07, 0x0e, 0xdd, 0x0b, 0x72, 0x9d, 0x80, 0x30, 0x16, 0x07, 0x95, 0x3f, 0x28, 0x0e,
+0xfd, 0xc5, 0x75, 0x4f, 0x53, 0xd6, 0x74, 0x9a, 0xb4, 0x24, 0x2e, 0x8e, 0x02, 0x91, 0xcf, 0x76,
+0xc5, 0x9b, 0x1e, 0x55, 0x74, 0x9c, 0x78, 0x21, 0xb1, 0xf0, 0x2d, 0xf1, 0x0b, 0x9f, 0xc2, 0xd5,
+0x96, 0x18, 0x1f, 0xf0, 0x54, 0x22, 0x7a, 0x8c, 0x07, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x7d,
+0x30, 0x7b, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa7, 0xa5, 0x06,
+0xb1, 0x2c, 0xa6, 0x09, 0x60, 0xee, 0xd1, 0x97, 0xe9, 0x70, 0xae, 0xbc, 0x3b, 0x19, 0x6c, 0xdb,
+0x21, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xa7,
+0xa5, 0x06, 0xb1, 0x2c, 0xa6, 0x09, 0x60, 0xee, 0xd1, 0x97, 0xe9, 0x70, 0xae, 0xbc, 0x3b, 0x19,
+0x6c, 0xdb, 0x21, 0x30, 0x18, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x11, 0x30, 0x0f, 0x30, 0x0d,
+0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb0, 0x2d, 0x03, 0x04, 0x01, 0x01, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+0x00, 0x26, 0x77, 0x34, 0xdb, 0x94, 0x48, 0x86, 0x2a, 0x41, 0x9d, 0x2c, 0x3e, 0x06, 0x90, 0x60,
+0xc4, 0x8c, 0xac, 0x0b, 0x54, 0xb8, 0x1f, 0xb9, 0x7b, 0xd3, 0x07, 0x39, 0xe4, 0xfa, 0x3e, 0x7b,
+0xb2, 0x3d, 0x4e, 0xed, 0x9f, 0x23, 0xbd, 0x97, 0xf3, 0x6b, 0x5c, 0xef, 0xee, 0xfd, 0x40, 0xa6,
+0xdf, 0xa1, 0x93, 0xa1, 0x0a, 0x86, 0xac, 0xef, 0x20, 0xd0, 0x79, 0x01, 0xbd, 0x78, 0xf7, 0x19,
+0xd8, 0x24, 0x31, 0x34, 0x04, 0x01, 0xa6, 0xba, 0x15, 0x9a, 0xc3, 0x27, 0xdc, 0xd8, 0x4f, 0x0f,
+0xcc, 0x18, 0x63, 0xff, 0x99, 0x0f, 0x0e, 0x91, 0x6b, 0x75, 0x16, 0xe1, 0x21, 0xfc, 0xd8, 0x26,
+0xc7, 0x47, 0xb7, 0xa6, 0xcf, 0x58, 0x72, 0x71, 0x7e, 0xba, 0xe1, 0x4d, 0x95, 0x47, 0x3b, 0xc9,
+0xaf, 0x6d, 0xa1, 0xb4, 0xc1, 0xec, 0x89, 0xf6, 0xb4, 0x0f, 0x38, 0xb5, 0xe2, 0x64, 0xdc, 0x25,
+0xcf, 0xa6, 0xdb, 0xeb, 0x9a, 0x5c, 0x99, 0xa1, 0xc5, 0x08, 0xde, 0xfd, 0xe6, 0xda, 0xd5, 0xd6,
+0x5a, 0x45, 0x0c, 0xc4, 0xb7, 0xc2, 0xb5, 0x14, 0xef, 0xb4, 0x11, 0xff, 0x0e, 0x15, 0xb5, 0xf5,
+0xf5, 0xdb, 0xc6, 0xbd, 0xeb, 0x5a, 0xa7, 0xf0, 0x56, 0x22, 0xa9, 0x3c, 0x65, 0x54, 0xc6, 0x15,
+0xa8, 0xbd, 0x86, 0x9e, 0xcd, 0x83, 0x96, 0x68, 0x7a, 0x71, 0x81, 0x89, 0xe1, 0x0b, 0xe1, 0xea,
+0x11, 0x1b, 0x68, 0x08, 0xcc, 0x69, 0x9e, 0xec, 0x9e, 0x41, 0x9e, 0x44, 0x32, 0x26, 0x7a, 0xe2,
+0x87, 0x0a, 0x71, 0x3d, 0xeb, 0xe4, 0x5a, 0xa4, 0xd2, 0xdb, 0xc5, 0xcd, 0xc6, 0xde, 0x60, 0x7f,
+0xb9, 0xf3, 0x4f, 0x44, 0x92, 0xef, 0x2a, 0xb7, 0x18, 0x3e, 0xa7, 0x19, 0xd9, 0x0b, 0x7d, 0xb1,
+0x37, 0x41, 0x42, 0xb0, 0xba, 0x60, 0x1d, 0xf2, 0xfe, 0x09, 0x11, 0xb0, 0xf0, 0x87, 0x7b, 0xa7,
+0x9d, 0x30, 0x82, 0x05, 0x59, 0x30, 0x82, 0x03, 0x41, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01,
+0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+0x30, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4f, 0x31,
+0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x14, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73,
+0x73, 0x20, 0x41, 0x53, 0x2d, 0x39, 0x38, 0x33, 0x31, 0x36, 0x33, 0x33, 0x32, 0x37, 0x31, 0x20,
+0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x17, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73,
+0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x31, 0x30, 0x32, 0x36, 0x30, 0x38, 0x32, 0x38, 0x35, 0x38,
+0x5a, 0x17, 0x0d, 0x34, 0x30, 0x31, 0x30, 0x32, 0x36, 0x30, 0x38, 0x32, 0x38, 0x35, 0x38, 0x5a,
+0x30, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4f, 0x31,
+0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x14, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73,
+0x73, 0x20, 0x41, 0x53, 0x2d, 0x39, 0x38, 0x33, 0x31, 0x36, 0x33, 0x33, 0x32, 0x37, 0x31, 0x20,
+0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x17, 0x42, 0x75, 0x79, 0x70, 0x61, 0x73, 0x73,
+0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01,
+0x00, 0xa5, 0xda, 0x0a, 0x95, 0x16, 0x50, 0xe3, 0x95, 0xf2, 0x5e, 0x9d, 0x76, 0x31, 0x06, 0x32,
+0x7a, 0x9b, 0xf1, 0x10, 0x76, 0xb8, 0x00, 0x9a, 0xb5, 0x52, 0x36, 0xcd, 0x24, 0x47, 0xb0, 0x9f,
+0x18, 0x64, 0xbc, 0x9a, 0xf6, 0xfa, 0xd5, 0x79, 0xd8, 0x90, 0x62, 0x4c, 0x22, 0x2f, 0xde, 0x38,
+0x3d, 0xd6, 0xe0, 0xa8, 0xe9, 0x1c, 0x2c, 0xdb, 0x78, 0x11, 0xe9, 0x8e, 0x68, 0x51, 0x15, 0x72,
+0xc7, 0xf3, 0x33, 0x87, 0xe4, 0xa0, 0x5d, 0x0b, 0x5c, 0xe0, 0x57, 0x07, 0x2a, 0x30, 0xf5, 0xcd,
+0xc4, 0x37, 0x77, 0x28, 0x4d, 0x18, 0x91, 0xe6, 0xbf, 0xd5, 0x52, 0xfd, 0x71, 0x2d, 0x70, 0x3e,
+0xe7, 0xc6, 0xc4, 0x8a, 0xe3, 0xf0, 0x28, 0x0b, 0xf4, 0x76, 0x98, 0xa1, 0x8b, 0x87, 0x55, 0xb2,
+0x3a, 0x13, 0xfc, 0xb7, 0x3e, 0x27, 0x37, 0x8e, 0x22, 0xe3, 0xa8, 0x4f, 0x2a, 0xef, 0x60, 0xbb,
+0x3d, 0xb7, 0x39, 0xc3, 0x0e, 0x01, 0x47, 0x99, 0x5d, 0x12, 0x4f, 0xdb, 0x43, 0xfa, 0x57, 0xa1,
+0xed, 0xf9, 0x9d, 0xbe, 0x11, 0x47, 0x26, 0x5b, 0x13, 0x98, 0xab, 0x5d, 0x16, 0x8a, 0xb0, 0x37,
+0x1c, 0x57, 0x9d, 0x45, 0xff, 0x88, 0x96, 0x36, 0xbf, 0xbb, 0xca, 0x07, 0x7b, 0x6f, 0x87, 0x63,
+0xd7, 0xd0, 0x32, 0x6a, 0xd6, 0x5d, 0x6c, 0x0c, 0xf1, 0xb3, 0x6e, 0x39, 0xe2, 0x6b, 0x31, 0x2e,
+0x39, 0x00, 0x27, 0x14, 0xde, 0x38, 0xc0, 0xec, 0x19, 0x66, 0x86, 0x12, 0xe8, 0x9d, 0x72, 0x16,
+0x13, 0x64, 0x52, 0xc7, 0xa9, 0x37, 0x1c, 0xfd, 0x82, 0x30, 0xed, 0x84, 0x18, 0x1d, 0xf4, 0xae,
+0x5c, 0xff, 0x70, 0x13, 0x00, 0xeb, 0xb1, 0xf5, 0x33, 0x7a, 0x4b, 0xd6, 0x55, 0xf8, 0x05, 0x8d,
+0x4b, 0x69, 0xb0, 0xf5, 0xb3, 0x28, 0x36, 0x5c, 0x14, 0xc4, 0x51, 0x73, 0x4d, 0x6b, 0x0b, 0xf1,
+0x34, 0x07, 0xdb, 0x17, 0x39, 0xd7, 0xdc, 0x28, 0x7b, 0x6b, 0xf5, 0x9f, 0xf3, 0x2e, 0xc1, 0x4f,
+0x17, 0x2a, 0x10, 0xf3, 0xcc, 0xca, 0xe8, 0xeb, 0xfd, 0x6b, 0xab, 0x2e, 0x9a, 0x9f, 0x2d, 0x82,
+0x6e, 0x04, 0xd4, 0x52, 0x01, 0x93, 0x2d, 0x3d, 0x86, 0xfc, 0x7e, 0xfc, 0xdf, 0xef, 0x42, 0x1d,
+0xa6, 0x6b, 0xef, 0xb9, 0x20, 0xc6, 0xf7, 0xbd, 0xa0, 0xa7, 0x95, 0xfd, 0xa7, 0xe6, 0x89, 0x24,
+0xd8, 0xcc, 0x8c, 0x34, 0x6c, 0xe2, 0x23, 0x2f, 0xd9, 0x12, 0x1a, 0x21, 0xb9, 0x55, 0x91, 0x6f,
+0x0b, 0x91, 0x79, 0x19, 0x0c, 0xad, 0x40, 0x88, 0x0b, 0x70, 0xe2, 0x7a, 0xd2, 0x0e, 0xd8, 0x68,
+0x48, 0xbb, 0x82, 0x13, 0x39, 0x10, 0x58, 0xe9, 0xd8, 0x2a, 0x07, 0xc6, 0x12, 0xdb, 0x58, 0xdb,
+0xd2, 0x3b, 0x55, 0x10, 0x47, 0x05, 0x15, 0x67, 0x62, 0x7e, 0x18, 0x63, 0xa6, 0x46, 0x3f, 0x09,
+0x0e, 0x54, 0x32, 0x5e, 0xbf, 0x0d, 0x62, 0x7a, 0x27, 0xef, 0x80, 0xe8, 0xdb, 0xd9, 0x4b, 0x06,
+0x5a, 0x37, 0x5a, 0x25, 0xd0, 0x08, 0x12, 0x77, 0xd4, 0x6f, 0x09, 0x50, 0x97, 0x3d, 0xc8, 0x1d,
+0xc3, 0xdf, 0x8c, 0x45, 0x30, 0x56, 0xc6, 0xd3, 0x64, 0xab, 0x66, 0xf3, 0xc0, 0x5e, 0x96, 0x9c,
+0xc3, 0xc4, 0xef, 0xc3, 0x7c, 0x6b, 0x8b, 0x3a, 0x79, 0x7f, 0xb3, 0x49, 0xcf, 0x3d, 0xe2, 0x89,
+0x9f, 0xa0, 0x30, 0x4b, 0x85, 0xb9, 0x9c, 0x94, 0x24, 0x79, 0x8f, 0x7d, 0x6b, 0xa9, 0x45, 0x68,
+0x0f, 0x2b, 0xd0, 0xf1, 0xda, 0x1c, 0xcb, 0x69, 0xb8, 0xca, 0x49, 0x62, 0x6d, 0xc8, 0xd0, 0x63,
+0x62, 0xdd, 0x60, 0x0f, 0x58, 0xaa, 0x8f, 0xa1, 0xbc, 0x05, 0xa5, 0x66, 0xa2, 0xcf, 0x1b, 0x76,
+0xb2, 0x84, 0x64, 0xb1, 0x4c, 0x39, 0x52, 0xc0, 0x30, 0xba, 0xf0, 0x8c, 0x4b, 0x02, 0xb0, 0xb6,
+0xb7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
+0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55,
+0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x47, 0xb8, 0xcd, 0xff, 0xe5, 0x6f, 0xee, 0xf8, 0xb2, 0xec,
+0x2f, 0x4e, 0x0e, 0xf9, 0x25, 0xb0, 0x8e, 0x3c, 0x6b, 0xc3, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x00, 0x20,
+0x23, 0x41, 0x35, 0x04, 0x90, 0xc2, 0x40, 0x62, 0x60, 0xef, 0xe2, 0x35, 0x4c, 0xd7, 0x3f, 0xac,
+0xe2, 0x34, 0x90, 0xb8, 0xa1, 0x6f, 0x76, 0xfa, 0x16, 0x16, 0xa4, 0x48, 0x37, 0x2c, 0xe9, 0x90,
+0xc2, 0xf2, 0x3c, 0xf8, 0x0a, 0x9f, 0xd8, 0x81, 0xe5, 0xbb, 0x5b, 0xda, 0x25, 0x2c, 0xa4, 0xa7,
+0x55, 0x71, 0x24, 0x32, 0xf6, 0xc8, 0x0b, 0xf2, 0xbc, 0x6a, 0xf8, 0x93, 0xac, 0xb2, 0x07, 0xc2,
+0x5f, 0x9f, 0xdb, 0xcc, 0xc8, 0x8a, 0xaa, 0xbe, 0x6a, 0x6f, 0xe1, 0x49, 0x10, 0xcc, 0x31, 0xd7,
+0x80, 0xbb, 0xbb, 0xc8, 0xd8, 0xa2, 0x0e, 0x64, 0x57, 0xea, 0xa2, 0xf5, 0xc2, 0xa9, 0x31, 0x15,
+0xd2, 0x20, 0x6a, 0xec, 0xfc, 0x22, 0x01, 0x28, 0xcf, 0x86, 0xb8, 0x80, 0x1e, 0xa9, 0xcc, 0x11,
+0xa5, 0x3c, 0xf2, 0x16, 0xb3, 0x47, 0x9d, 0xfc, 0xd2, 0x80, 0x21, 0xc4, 0xcb, 0xd0, 0x47, 0x70,
+0x41, 0xa1, 0xca, 0x83, 0x19, 0x08, 0x2c, 0x6d, 0xf2, 0x5d, 0x77, 0x9c, 0x8a, 0x14, 0x13, 0xd4,
+0x36, 0x1c, 0x92, 0xf0, 0xe5, 0x06, 0x37, 0xdc, 0xa6, 0xe6, 0x90, 0x9b, 0x38, 0x8f, 0x5c, 0x6b,
+0x1b, 0x46, 0x86, 0x43, 0x42, 0x5f, 0x3e, 0x01, 0x07, 0x53, 0x54, 0x5d, 0x65, 0x7d, 0xf7, 0x8a,
+0x73, 0xa1, 0x9a, 0x54, 0x5a, 0x1f, 0x29, 0x43, 0x14, 0x27, 0xc2, 0x85, 0x0f, 0xb5, 0x88, 0x7b,
+0x1a, 0x3b, 0x94, 0xb7, 0x1d, 0x60, 0xa7, 0xb5, 0x9c, 0xe7, 0x29, 0x69, 0x57, 0x5a, 0x9b, 0x93,
+0x7a, 0x43, 0x30, 0x1b, 0x03, 0xd7, 0x62, 0xc8, 0x40, 0xa6, 0xaa, 0xfc, 0x64, 0xe4, 0x4a, 0xd7,
+0x91, 0x53, 0x01, 0xa8, 0x20, 0x88, 0x6e, 0x9c, 0x5f, 0x44, 0xb9, 0xcb, 0x60, 0x81, 0x34, 0xec,
+0x6f, 0xd3, 0x7d, 0xda, 0x48, 0x5f, 0xeb, 0xb4, 0x90, 0xbc, 0x2d, 0xa9, 0x1c, 0x0b, 0xac, 0x1c,
+0xd5, 0xa2, 0x68, 0x20, 0x80, 0x04, 0xd6, 0xfc, 0xb1, 0x8f, 0x2f, 0xbb, 0x4a, 0x31, 0x0d, 0x4a,
+0x86, 0x1c, 0xeb, 0xe2, 0x36, 0x29, 0x26, 0xf5, 0xda, 0xd8, 0xc4, 0xf2, 0x75, 0x61, 0xcf, 0x7e,
+0xae, 0x76, 0x63, 0x4a, 0x7a, 0x40, 0x65, 0x93, 0x87, 0xf8, 0x1e, 0x80, 0x8c, 0x86, 0xe5, 0x86,
+0xd6, 0x8f, 0x0e, 0xfc, 0x53, 0x2c, 0x60, 0xe8, 0x16, 0x61, 0x1a, 0xa2, 0x3e, 0x43, 0x7b, 0xcd,
+0x39, 0x60, 0x54, 0x6a, 0xf5, 0xf2, 0x89, 0x26, 0x01, 0x68, 0x83, 0x48, 0xa2, 0x33, 0xe8, 0xc9,
+0x04, 0x91, 0xb2, 0x11, 0x34, 0x11, 0x3e, 0xea, 0xd0, 0x43, 0x19, 0x1f, 0x03, 0x93, 0x90, 0x0c,
+0xff, 0x51, 0x3d, 0x57, 0xf4, 0x41, 0x6e, 0xe1, 0xcb, 0xa0, 0xbe, 0xeb, 0xc9, 0x63, 0xcd, 0x6d,
+0xcc, 0xe4, 0xf8, 0x36, 0xaa, 0x68, 0x9d, 0xed, 0xbd, 0x5d, 0x97, 0x70, 0x44, 0x0d, 0xb6, 0x0e,
+0x35, 0xdc, 0xe1, 0x0c, 0x5d, 0xbb, 0xa0, 0x51, 0x94, 0xcb, 0x7e, 0x16, 0xeb, 0x11, 0x2f, 0xa3,
+0x92, 0x45, 0xc8, 0x4c, 0x71, 0xd9, 0xbc, 0xc9, 0x99, 0x52, 0x57, 0x46, 0x2f, 0x50, 0xcf, 0xbd,
+0x35, 0x69, 0xf4, 0x3d, 0x15, 0xce, 0x06, 0xa5, 0x2c, 0x0f, 0x3e, 0xf6, 0x81, 0xba, 0x94, 0xbb,
+0xc3, 0xbb, 0xbf, 0x65, 0x78, 0xd2, 0x86, 0x79, 0xff, 0x49, 0x3b, 0x1a, 0x83, 0x0c, 0xf0, 0xde,
+0x78, 0xec, 0xc8, 0xf2, 0x4d, 0x4c, 0x1a, 0xde, 0x82, 0x29, 0xf8, 0xc1, 0x5a, 0xda, 0xed, 0xee,
+0xe6, 0x27, 0x5e, 0xe8, 0x45, 0xd0, 0x9d, 0x1c, 0x51, 0xa8, 0x68, 0xab, 0x44, 0xe3, 0xd0, 0x8b,
+0x6a, 0xe3, 0xf8, 0x3b, 0xbb, 0xdc, 0x4d, 0xd7, 0x64, 0xf2, 0x51, 0xbe, 0xe6, 0xaa, 0xab, 0x5a,
+0xe9, 0x31, 0xee, 0x06, 0xbc, 0x73, 0xbf, 0x13, 0x62, 0x0a, 0x9f, 0xc7, 0xb9, 0x97, 0x30, 0x82,
+0x05, 0x69, 0x30, 0x82, 0x03, 0x51, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x92, 0xb8,
+0x88, 0xdb, 0xb0, 0x8a, 0xc1, 0x63, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x52, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x53, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x42,
+0x72, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x61, 0x76, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x0a, 0x44, 0x69, 0x73, 0x69, 0x67, 0x20, 0x61, 0x2e, 0x73, 0x2e, 0x31, 0x19,
+0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x43, 0x41, 0x20, 0x44, 0x69, 0x73, 0x69,
+0x67, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30,
+0x37, 0x31, 0x39, 0x30, 0x39, 0x31, 0x35, 0x33, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x37,
+0x31, 0x39, 0x30, 0x39, 0x31, 0x35, 0x33, 0x30, 0x5a, 0x30, 0x52, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x53, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+0x07, 0x13, 0x0a, 0x42, 0x72, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x61, 0x76, 0x61, 0x31, 0x13, 0x30,
+0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x44, 0x69, 0x73, 0x69, 0x67, 0x20, 0x61, 0x2e,
+0x73, 0x2e, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x43, 0x41, 0x20,
+0x44, 0x69, 0x73, 0x69, 0x67, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x32, 0x30, 0x82, 0x02,
+0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xa2, 0xa3,
+0xc4, 0x00, 0x09, 0xd6, 0x85, 0x5d, 0x2d, 0x6d, 0x14, 0xf6, 0xc2, 0xc3, 0x73, 0x9e, 0x35, 0xc2,
+0x71, 0x55, 0x7e, 0x81, 0xfb, 0xab, 0x46, 0x50, 0xe0, 0xc1, 0x7c, 0x49, 0x78, 0xe6, 0xab, 0x79,
+0x58, 0x3c, 0xda, 0xff, 0x7c, 0x1c, 0x9f, 0xd8, 0x97, 0x02, 0x78, 0x3e, 0x6b, 0x41, 0x04, 0xe9,
+0x41, 0xbd, 0xbe, 0x03, 0x2c, 0x45, 0xf6, 0x2f, 0x64, 0xd4, 0xab, 0x5d, 0xa3, 0x47, 0x3d, 0x64,
+0x9b, 0xe9, 0x68, 0x9a, 0xc6, 0xcc, 0x1b, 0x3f, 0xba, 0xbe, 0xb2, 0x8b, 0x34, 0x02, 0x2e, 0x98,
+0x55, 0x19, 0xfc, 0x8c, 0x6f, 0xaa, 0x5f, 0xda, 0x4c, 0xce, 0x4d, 0x03, 0x21, 0xa3, 0xd8, 0xd2,
+0x34, 0x93, 0x56, 0x96, 0xcb, 0x4c, 0x0c, 0x00, 0x16, 0x3c, 0x5f, 0x1a, 0xcd, 0xc8, 0xc7, 0x6c,
+0xa6, 0xad, 0xd3, 0x31, 0xa7, 0xbc, 0xe8, 0xe5, 0xe1, 0x66, 0xd6, 0xd2, 0xfb, 0x03, 0xb4, 0x41,
+0x65, 0xc9, 0x10, 0xae, 0x0e, 0x05, 0x63, 0xc6, 0x80, 0x6a, 0x69, 0x30, 0xfd, 0xd2, 0xee, 0x90,
+0xef, 0x0d, 0x27, 0xdf, 0x9f, 0x95, 0x73, 0xf4, 0xe1, 0x25, 0xda, 0x6c, 0x16, 0xde, 0x41, 0x38,
+0x34, 0xea, 0x8b, 0xfc, 0xd1, 0xe8, 0x04, 0x14, 0x61, 0x2d, 0x41, 0x7e, 0xac, 0xc7, 0x77, 0x4e,
+0xcb, 0x51, 0x54, 0xfb, 0x5e, 0x92, 0x18, 0x1b, 0x04, 0x5a, 0x68, 0xc6, 0xc9, 0xc4, 0xfa, 0xb7,
+0x13, 0xa0, 0x98, 0xb7, 0x11, 0x2b, 0xb7, 0xd6, 0x57, 0xcc, 0x7c, 0x9e, 0x17, 0xd1, 0xcb, 0x25,
+0xfe, 0x86, 0x4e, 0x24, 0x2e, 0x56, 0x0c, 0x78, 0x4d, 0x9e, 0x01, 0x12, 0xa6, 0x2b, 0xa7, 0x01,
+0x65, 0x6e, 0x7c, 0x62, 0x1d, 0x84, 0x84, 0xdf, 0xea, 0xc0, 0x6b, 0xb5, 0xa5, 0x2a, 0x95, 0x83,
+0xc3, 0x53, 0x11, 0x0c, 0x73, 0x1d, 0x0b, 0xb2, 0x46, 0x90, 0xd1, 0x42, 0x3a, 0xce, 0x40, 0x6e,
+0x95, 0xad, 0xff, 0xc6, 0x94, 0xad, 0x6e, 0x97, 0x84, 0x8e, 0x7d, 0x6f, 0x9e, 0x8a, 0x80, 0x0d,
+0x49, 0x6d, 0x73, 0xe2, 0x7b, 0x92, 0x1e, 0xc3, 0xf3, 0xc1, 0xf3, 0xeb, 0x2e, 0x05, 0x6f, 0xd9,
+0x1b, 0xcf, 0x37, 0x76, 0x04, 0xc8, 0xb4, 0x5a, 0xe4, 0x17, 0xa7, 0xcb, 0xdd, 0x76, 0x1f, 0xd0,
+0x19, 0x76, 0xe8, 0x2c, 0x05, 0xb3, 0xd6, 0x9c, 0x34, 0xd8, 0x96, 0xdc, 0x61, 0x87, 0x91, 0x05,
+0xe4, 0x44, 0x08, 0x33, 0xc1, 0xda, 0xb9, 0x08, 0x65, 0xd4, 0xae, 0xb2, 0x36, 0x0d, 0xeb, 0xba,
+0x38, 0xba, 0x0c, 0xe5, 0x9b, 0x9e, 0xeb, 0x8d, 0x66, 0xdd, 0x99, 0xcf, 0xd6, 0x89, 0x41, 0xf6,
+0x04, 0x92, 0x8a, 0x29, 0x29, 0x6d, 0x6b, 0x3a, 0x1c, 0xe7, 0x75, 0x7d, 0x02, 0x71, 0x0e, 0xf3,
+0xc0, 0xe7, 0xbd, 0xcb, 0x19, 0xdd, 0x9d, 0x60, 0xb2, 0xc2, 0x66, 0x60, 0xb6, 0xb1, 0x04, 0xee,
+0xc9, 0xe6, 0x86, 0xb9, 0x9a, 0x66, 0x40, 0xa8, 0xe7, 0x11, 0xed, 0x81, 0x45, 0x03, 0x8b, 0xf6,
+0x67, 0x59, 0xe8, 0xc1, 0x06, 0x11, 0xbd, 0xdd, 0xcf, 0x80, 0x02, 0x4f, 0x65, 0x40, 0x78, 0x5c,
+0x47, 0x50, 0xc8, 0x9b, 0xe6, 0x1f, 0x81, 0x7b, 0xe4, 0x44, 0xa8, 0x5b, 0x85, 0x9a, 0xe2, 0xde,
+0x5a, 0xd5, 0xc7, 0xf9, 0x3a, 0x44, 0x66, 0x4b, 0xe4, 0x32, 0x54, 0x7c, 0xe4, 0x6c, 0x9c, 0xb3,
+0x0e, 0x3d, 0x17, 0xa2, 0xb2, 0x34, 0x12, 0xd6, 0x7e, 0xb2, 0xa8, 0x49, 0xbb, 0xd1, 0x7a, 0x28,
+0x40, 0xbe, 0xa2, 0x16, 0x1f, 0xdf, 0xe4, 0x37, 0x1f, 0x11, 0x73, 0xfb, 0x90, 0x0a, 0x65, 0x43,
+0xa2, 0x0d, 0x7c, 0xf8, 0x06, 0x01, 0x55, 0x33, 0x7d, 0xb0, 0x0d, 0xb8, 0xf4, 0xf5, 0xae, 0xa5,
+0x42, 0x57, 0x7c, 0x36, 0x11, 0x8c, 0x7b, 0x5e, 0xc4, 0x03, 0x9d, 0x8c, 0x79, 0x9d, 0x02, 0x03,
+0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+0x16, 0x04, 0x14, 0xb5, 0x99, 0xf8, 0xaf, 0xb0, 0x94, 0xf5, 0xe3, 0x20, 0xd6, 0x0a, 0xad, 0xce,
+0x4e, 0x56, 0xa4, 0x2e, 0x6e, 0x42, 0xed, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x26, 0x06, 0x5e, 0x70, 0xe7,
+0x65, 0x33, 0xc8, 0x82, 0x6e, 0xd9, 0x9c, 0x17, 0x3a, 0x1b, 0x7a, 0x66, 0xb2, 0x01, 0xf6, 0x78,
+0x3b, 0x69, 0x5e, 0x2f, 0xea, 0xff, 0x4e, 0xf9, 0x28, 0xc3, 0x98, 0x2a, 0x61, 0x4c, 0xb4, 0x24,
+0x12, 0x8a, 0x7d, 0x6d, 0x11, 0x14, 0xf7, 0x9c, 0xb5, 0xca, 0xe6, 0xbc, 0x9e, 0x27, 0x8e, 0x4c,
+0x19, 0xc8, 0xa9, 0xbd, 0x7a, 0xc0, 0xd7, 0x36, 0x0e, 0x6d, 0x85, 0x72, 0x6e, 0xa8, 0xc6, 0xa2,
+0x6d, 0xf6, 0xfa, 0x73, 0x63, 0x7f, 0xbc, 0x6e, 0x79, 0x08, 0x1c, 0x9d, 0x8a, 0x9f, 0x1a, 0x8a,
+0x53, 0xa6, 0xd8, 0xbb, 0xd9, 0x35, 0x55, 0xb1, 0x11, 0xc5, 0xa9, 0x03, 0xb3, 0x56, 0x3b, 0xb9,
+0x84, 0x93, 0x22, 0x5e, 0x7e, 0xc1, 0xf6, 0x12, 0x52, 0x8b, 0xea, 0x2c, 0x67, 0xbc, 0xfe, 0x36,
+0x4c, 0xf5, 0xb8, 0xcf, 0xd1, 0xb3, 0x49, 0x92, 0x3b, 0xd3, 0x29, 0x0e, 0x99, 0x1b, 0x96, 0xf7,
+0x61, 0xb8, 0x3b, 0xc4, 0x2b, 0xb6, 0x78, 0x6c, 0xb4, 0x23, 0x6f, 0xf0, 0xfd, 0xd3, 0xb2, 0x5e,
+0x75, 0x1f, 0x99, 0x95, 0xa8, 0xac, 0xf6, 0xda, 0xe1, 0xc5, 0x31, 0x7b, 0xfb, 0xd1, 0x46, 0xb3,
+0xd2, 0xbc, 0x67, 0xb4, 0x62, 0x54, 0xba, 0x09, 0xf7, 0x63, 0xb0, 0x93, 0xa2, 0x9a, 0xf9, 0xe9,
+0x52, 0x2e, 0x8b, 0x60, 0x12, 0xab, 0xfc, 0xf5, 0x60, 0x56, 0xef, 0x10, 0x5c, 0x8b, 0xc4, 0x1a,
+0x42, 0xdc, 0x83, 0x5b, 0x64, 0x0e, 0xcb, 0xb5, 0xbc, 0xd6, 0x4f, 0xc1, 0x7c, 0x3c, 0x6e, 0x8d,
+0x13, 0x6d, 0xfb, 0x7b, 0xeb, 0x30, 0xd0, 0xdc, 0x4d, 0xaf, 0xc5, 0xd5, 0xb6, 0xa5, 0x4c, 0x5b,
+0x71, 0xc9, 0xe8, 0x31, 0xbe, 0xe8, 0x38, 0x06, 0x48, 0xa1, 0x1a, 0xe2, 0xea, 0xd2, 0xde, 0x12,
+0x39, 0x58, 0x1a, 0xff, 0x80, 0x0e, 0x82, 0x75, 0xe6, 0xb7, 0xc9, 0x07, 0x6c, 0x0e, 0xef, 0xff,
+0x38, 0xf1, 0x98, 0x71, 0xc4, 0xb7, 0x7f, 0x0e, 0x15, 0xd0, 0x25, 0x69, 0xbd, 0x22, 0x9d, 0x2b,
+0xed, 0x05, 0xf6, 0x46, 0x47, 0xac, 0xed, 0xc0, 0xf0, 0xd4, 0x3b, 0xe2, 0xec, 0xee, 0x96, 0x5b,
+0x90, 0x13, 0x4e, 0x1e, 0x56, 0x3a, 0xeb, 0xb0, 0xef, 0x96, 0xbb, 0x96, 0x23, 0x11, 0xba, 0xf2,
+0x43, 0x86, 0x74, 0x64, 0x95, 0xc8, 0x28, 0x75, 0xdf, 0x1d, 0x35, 0xba, 0xd2, 0x37, 0x83, 0x38,
+0x53, 0x38, 0x36, 0x3b, 0xcf, 0x6c, 0xe9, 0xf9, 0x6b, 0x0e, 0xd0, 0xfb, 0x04, 0xe8, 0x4f, 0x77,
+0xd7, 0x65, 0x01, 0x78, 0x86, 0x0c, 0x7a, 0x3e, 0x21, 0x62, 0xf1, 0x7f, 0x63, 0x71, 0x0c, 0xc9,
+0x9f, 0x44, 0xdb, 0xa8, 0x27, 0xa2, 0x75, 0xbe, 0x6e, 0x81, 0x3e, 0xd7, 0xc0, 0xeb, 0x1b, 0x98,
+0x0f, 0x70, 0x5c, 0x34, 0xb2, 0x8a, 0xcc, 0xc0, 0x85, 0x18, 0xeb, 0x6e, 0x7a, 0xb3, 0xf7, 0x5a,
+0xa1, 0x07, 0xbf, 0xa9, 0x42, 0x92, 0xf3, 0x60, 0x22, 0x97, 0xe4, 0x14, 0xa1, 0x07, 0x9b, 0x4e,
+0x76, 0xc0, 0x8e, 0x7d, 0xfd, 0xa4, 0x25, 0xc7, 0x47, 0xed, 0xff, 0x1f, 0x73, 0xac, 0xcc, 0xc3,
+0xa5, 0xe9, 0x6f, 0x0a, 0x8e, 0x9b, 0x65, 0xc2, 0x50, 0x85, 0xb5, 0xa3, 0xa0, 0x53, 0x12, 0xcc,
+0x55, 0x87, 0x61, 0xf3, 0x81, 0xae, 0x10, 0x46, 0x61, 0xbd, 0x44, 0x21, 0xb8, 0xc2, 0x3d, 0x74,
+0xcf, 0x7e, 0x24, 0x35, 0xfa, 0x1c, 0x07, 0x0e, 0x9b, 0x3d, 0x22, 0xca, 0xef, 0x31, 0x2f, 0x8c,
+0xac, 0x12, 0xbd, 0xef, 0x40, 0x28, 0xfc, 0x29, 0x67, 0x9f, 0xb2, 0x13, 0x4f, 0x66, 0x24, 0xc4,
+0x53, 0x19, 0xe9, 0x1e, 0x29, 0x15, 0xef, 0xe6, 0x6d, 0xb0, 0x7f, 0x2d, 0x67, 0xfd, 0xf3, 0x6c,
+0x1b, 0x75, 0x46, 0xa3, 0xe5, 0x4a, 0x17, 0xe9, 0xa4, 0xd7, 0x0b, 0x30, 0x82, 0x03, 0xa8, 0x30,
+0x82, 0x02, 0x90, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xfe, 0xdc, 0xe3, 0x01, 0x0f,
+0xc9, 0x48, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+0x05, 0x00, 0x30, 0x34, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46,
+0x52, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x44, 0x68, 0x69, 0x6d,
+0x79, 0x6f, 0x74, 0x69, 0x73, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
+0x43, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36,
+0x32, 0x39, 0x31, 0x35, 0x31, 0x33, 0x30, 0x35, 0x5a, 0x17, 0x0d, 0x32, 0x37, 0x30, 0x36, 0x32,
+0x39, 0x31, 0x35, 0x31, 0x33, 0x30, 0x35, 0x5a, 0x30, 0x34, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x0c, 0x09, 0x44, 0x68, 0x69, 0x6d, 0x79, 0x6f, 0x74, 0x69, 0x73, 0x31, 0x11, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x43, 0x65, 0x72, 0x74, 0x69, 0x67, 0x6e, 0x61, 0x30, 0x82,
+0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc8,
+0x68, 0xf1, 0xc9, 0xd6, 0xd6, 0xb3, 0x34, 0x75, 0x26, 0x82, 0x1e, 0xec, 0xb4, 0xbe, 0xea, 0x5c,
+0xe1, 0x26, 0xed, 0x11, 0x47, 0x61, 0xe1, 0xa2, 0x7c, 0x16, 0x78, 0x40, 0x21, 0xe4, 0x60, 0x9e,
+0x5a, 0xc8, 0x63, 0xe1, 0xc4, 0xb1, 0x96, 0x92, 0xff, 0x18, 0x6d, 0x69, 0x23, 0xe1, 0x2b, 0x62,
+0xf7, 0xdd, 0xe2, 0x36, 0x2f, 0x91, 0x07, 0xb9, 0x48, 0xcf, 0x0e, 0xec, 0x79, 0xb6, 0x2c, 0xe7,
+0x34, 0x4b, 0x70, 0x08, 0x25, 0xa3, 0x3c, 0x87, 0x1b, 0x19, 0xf2, 0x81, 0x07, 0x0f, 0x38, 0x90,
+0x19, 0xd3, 0x11, 0xfe, 0x86, 0xb4, 0xf2, 0xd1, 0x5e, 0x1e, 0x1e, 0x96, 0xcd, 0x80, 0x6c, 0xce,
+0x3b, 0x31, 0x93, 0xb6, 0xf2, 0xa0, 0xd0, 0xa9, 0x95, 0x12, 0x7d, 0xa5, 0x9a, 0xcc, 0x6b, 0xc8,
+0x84, 0x56, 0x8a, 0x33, 0xa9, 0xe7, 0x22, 0x15, 0x53, 0x16, 0xf0, 0xcc, 0x17, 0xec, 0x57, 0x5f,
+0xe9, 0xa2, 0x0a, 0x98, 0x09, 0xde, 0xe3, 0x5f, 0x9c, 0x6f, 0xdc, 0x48, 0xe3, 0x85, 0x0b, 0x15,
+0x5a, 0xa6, 0xba, 0x9f, 0xac, 0x48, 0xe3, 0x09, 0xb2, 0xf7, 0xf4, 0x32, 0xde, 0x5e, 0x34, 0xbe,
+0x1c, 0x78, 0x5d, 0x42, 0x5b, 0xce, 0x0e, 0x22, 0x8f, 0x4d, 0x90, 0xd7, 0x7d, 0x32, 0x18, 0xb3,
+0x0b, 0x2c, 0x6a, 0xbf, 0x8e, 0x3f, 0x14, 0x11, 0x89, 0x20, 0x0e, 0x77, 0x14, 0xb5, 0x3d, 0x94,
+0x08, 0x87, 0xf7, 0x25, 0x1e, 0xd5, 0xb2, 0x60, 0x00, 0xec, 0x6f, 0x2a, 0x28, 0x25, 0x6e, 0x2a,
+0x3e, 0x18, 0x63, 0x17, 0x25, 0x3f, 0x3e, 0x44, 0x20, 0x16, 0xf6, 0x26, 0xc8, 0x25, 0xae, 0x05,
+0x4a, 0xb4, 0xe7, 0x63, 0x2c, 0xf3, 0x8c, 0x16, 0x53, 0x7e, 0x5c, 0xfb, 0x11, 0x1a, 0x08, 0xc1,
+0x46, 0x62, 0x9f, 0x22, 0xb8, 0xf1, 0xc2, 0x8d, 0x69, 0xdc, 0xfa, 0x3a, 0x58, 0x06, 0xdf, 0x02,
+0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xbc, 0x30, 0x81, 0xb9, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
+0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55,
+0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x1a, 0xed, 0xfe, 0x41, 0x39, 0x90, 0xb4, 0x24, 0x59, 0xbe,
+0x01, 0xf2, 0x52, 0xd5, 0x45, 0xf6, 0x5a, 0x39, 0xdc, 0x11, 0x30, 0x64, 0x06, 0x03, 0x55, 0x1d,
+0x23, 0x04, 0x5d, 0x30, 0x5b, 0x80, 0x14, 0x1a, 0xed, 0xfe, 0x41, 0x39, 0x90, 0xb4, 0x24, 0x59,
+0xbe, 0x01, 0xf2, 0x52, 0xd5, 0x45, 0xf6, 0x5a, 0x39, 0xdc, 0x11, 0xa1, 0x38, 0xa4, 0x36, 0x30,
+0x34, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x12,
+0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x44, 0x68, 0x69, 0x6d, 0x79, 0x6f, 0x74,
+0x69, 0x73, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x67, 0x6e, 0x61, 0x82, 0x09, 0x00, 0xfe, 0xdc, 0xe3, 0x01, 0x0f, 0xc9, 0x48, 0xff,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+0x30, 0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03,
+0x02, 0x00, 0x07, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x85, 0x03, 0x1e, 0x92, 0x71, 0xf6, 0x42, 0xaf, 0xe1,
+0xa3, 0x61, 0x9e, 0xeb, 0xf3, 0xc0, 0x0f, 0xf2, 0xa5, 0xd4, 0xda, 0x95, 0xe6, 0xd6, 0xbe, 0x68,
+0x36, 0x3d, 0x7e, 0x6e, 0x1f, 0x4c, 0x8a, 0xef, 0xd1, 0x0f, 0x21, 0x6d, 0x5e, 0xa5, 0x52, 0x63,
+0xce, 0x12, 0xf8, 0xef, 0x2a, 0xda, 0x6f, 0xeb, 0x37, 0xfe, 0x13, 0x02, 0xc7, 0xcb, 0x3b, 0x3e,
+0x22, 0x6b, 0xda, 0x61, 0x2e, 0x7f, 0xd4, 0x72, 0x3d, 0xdd, 0x30, 0xe1, 0x1e, 0x4c, 0x40, 0x19,
+0x8c, 0x0f, 0xd7, 0x9c, 0xd1, 0x83, 0x30, 0x7b, 0x98, 0x59, 0xdc, 0x7d, 0xc6, 0xb9, 0x0c, 0x29,
+0x4c, 0xa1, 0x33, 0xa2, 0xeb, 0x67, 0x3a, 0x65, 0x84, 0xd3, 0x96, 0xe2, 0xed, 0x76, 0x45, 0x70,
+0x8f, 0xb5, 0x2b, 0xde, 0xf9, 0x23, 0xd6, 0x49, 0x6e, 0x3c, 0x14, 0xb5, 0xc6, 0x9f, 0x35, 0x1e,
+0x50, 0xd0, 0xc1, 0x8f, 0x6a, 0x70, 0x44, 0x02, 0x62, 0xcb, 0xae, 0x1d, 0x68, 0x41, 0xa7, 0xaa,
+0x57, 0xe8, 0x53, 0xaa, 0x07, 0xd2, 0x06, 0xf6, 0xd5, 0x14, 0x06, 0x0b, 0x91, 0x03, 0x75, 0x2c,
+0x6c, 0x72, 0xb5, 0x61, 0x95, 0x9a, 0x0d, 0x8b, 0xb9, 0x0d, 0xe7, 0xf5, 0xdf, 0x54, 0xcd, 0xde,
+0xe6, 0xd8, 0xd6, 0x09, 0x08, 0x97, 0x63, 0xe5, 0xc1, 0x2e, 0xb0, 0xb7, 0x44, 0x26, 0xc0, 0x26,
+0xc0, 0xaf, 0x55, 0x30, 0x9e, 0x3b, 0xd5, 0x36, 0x2a, 0x19, 0x04, 0xf4, 0x5c, 0x1e, 0xff, 0xcf,
+0x2c, 0xb7, 0xff, 0xd0, 0xfd, 0x87, 0x40, 0x11, 0xd5, 0x11, 0x23, 0xbb, 0x48, 0xc0, 0x21, 0xa9,
+0xa4, 0x28, 0x2d, 0xfd, 0x15, 0xf8, 0xb0, 0x4e, 0x2b, 0xf4, 0x30, 0x5b, 0x21, 0xfc, 0x11, 0x91,
+0x34, 0xbe, 0x41, 0xef, 0x7b, 0x9d, 0x97, 0x75, 0xff, 0x97, 0x95, 0xc0, 0x96, 0x58, 0x2f, 0xea,
+0xbb, 0x46, 0xd7, 0xbb, 0xe4, 0xd9, 0x2e, 0x30, 0x82, 0x05, 0x38, 0x30, 0x82, 0x03, 0x20, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 0x95, 0xbe, 0x16, 0xa0, 0xf7, 0x2e, 0x46, 0xf1, 0x7b,
+0x39, 0x82, 0x72, 0xfa, 0x8b, 0xcd, 0x96, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x37, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x0c, 0x0b, 0x54, 0x65, 0x6c, 0x69, 0x61, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x31, 0x1f,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x54, 0x65, 0x6c, 0x69, 0x61, 0x53, 0x6f,
+0x6e, 0x65, 0x72, 0x61, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x76, 0x31, 0x30,
+0x1e, 0x17, 0x0d, 0x30, 0x37, 0x31, 0x30, 0x31, 0x38, 0x31, 0x32, 0x30, 0x30, 0x35, 0x30, 0x5a,
+0x17, 0x0d, 0x33, 0x32, 0x31, 0x30, 0x31, 0x38, 0x31, 0x32, 0x30, 0x30, 0x35, 0x30, 0x5a, 0x30,
+0x37, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x54, 0x65, 0x6c, 0x69,
+0x61, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x0c, 0x16, 0x54, 0x65, 0x6c, 0x69, 0x61, 0x53, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x76, 0x31, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00,
+0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xc2, 0xbe, 0xeb, 0x27, 0xf0, 0x21, 0xa3,
+0xf3, 0x69, 0x26, 0x55, 0x7e, 0x9d, 0xc5, 0x55, 0x16, 0x91, 0x5c, 0xfd, 0xef, 0x21, 0xbf, 0x53,
+0x80, 0x7a, 0x2d, 0xd2, 0x91, 0x8c, 0x63, 0x31, 0xf0, 0xec, 0x24, 0xf0, 0xc3, 0xa5, 0xd2, 0x72,
+0x7c, 0x10, 0x6d, 0xf4, 0x37, 0xb7, 0xe5, 0xe6, 0x7c, 0x79, 0xea, 0x8c, 0xb5, 0x82, 0x8b, 0xae,
+0x48, 0xb6, 0xac, 0x00, 0xdc, 0x65, 0x75, 0xec, 0x2a, 0x4d, 0x5f, 0xc1, 0x87, 0xf5, 0x20, 0x65,
+0x2b, 0x81, 0xa8, 0x47, 0x3e, 0x89, 0x23, 0x95, 0x30, 0x16, 0x90, 0x7f, 0xe8, 0x57, 0x07, 0x48,
+0xe7, 0x19, 0xae, 0xbf, 0x45, 0x67, 0xb1, 0x37, 0x1b, 0x06, 0x2a, 0xfe, 0xde, 0xf9, 0xac, 0x7d,
+0x83, 0xfb, 0x5e, 0xba, 0xe4, 0x8f, 0x97, 0x67, 0xbe, 0x4b, 0x8e, 0x8d, 0x64, 0x07, 0x57, 0x38,
+0x55, 0x69, 0x34, 0x36, 0x3d, 0x13, 0x48, 0xef, 0x4f, 0xe2, 0xd3, 0x66, 0x1e, 0xa4, 0xcf, 0x1a,
+0xb7, 0x5e, 0x36, 0x33, 0xd4, 0xb4, 0x06, 0xbd, 0x18, 0x01, 0xfd, 0x77, 0x84, 0x50, 0x00, 0x45,
+0xf5, 0x8c, 0x5d, 0xe8, 0x23, 0xbc, 0x7e, 0xfe, 0x35, 0xe1, 0xed, 0x50, 0x7b, 0xa9, 0x30, 0x8d,
+0x19, 0xd3, 0x09, 0x8e, 0x68, 0x67, 0x5d, 0xbf, 0x3c, 0x97, 0x18, 0x53, 0xbb, 0x29, 0x62, 0xc5,
+0xca, 0x5e, 0x72, 0xc1, 0xc7, 0x96, 0xd4, 0xdb, 0x2d, 0xa0, 0xb4, 0x1f, 0x69, 0x03, 0xec, 0xea,
+0xe2, 0x50, 0xf1, 0x0c, 0x3c, 0xf0, 0xac, 0xf3, 0x53, 0x2d, 0xf0, 0x1c, 0xf5, 0xed, 0x6c, 0x39,
+0x39, 0x73, 0x80, 0x16, 0xc8, 0x52, 0xb0, 0x23, 0xcd, 0xe0, 0x3e, 0xdc, 0xdd, 0x3c, 0x47, 0xa0,
+0xbb, 0x35, 0x8a, 0xe2, 0x98, 0x68, 0x8b, 0xbe, 0xe5, 0xbf, 0x72, 0xee, 0xd2, 0xfa, 0xa5, 0xed,
+0x12, 0xed, 0xfc, 0x98, 0x18, 0xa9, 0x26, 0x76, 0xdc, 0x28, 0x4b, 0x10, 0x20, 0x1c, 0xd3, 0x7f,
+0x16, 0x77, 0x2d, 0xed, 0x6f, 0x80, 0xf7, 0x49, 0xbb, 0x53, 0x05, 0xbb, 0x5d, 0x68, 0xc7, 0xd4,
+0xc8, 0x75, 0x16, 0x3f, 0x89, 0x5a, 0x8b, 0xf7, 0x17, 0x47, 0xd4, 0x4c, 0xf1, 0xd2, 0x89, 0x79,
+0x3e, 0x4d, 0x3d, 0x98, 0xa8, 0x61, 0xde, 0x3a, 0x1e, 0xd2, 0xf8, 0x5e, 0x03, 0xe0, 0xc1, 0xc9,
+0x1c, 0x8c, 0xd3, 0x8d, 0x4d, 0xd3, 0x95, 0x36, 0xb3, 0x37, 0x5f, 0x63, 0x63, 0x9b, 0x33, 0x14,
+0xf0, 0x2d, 0x26, 0x6b, 0x53, 0x7c, 0x89, 0x8c, 0x32, 0xc2, 0x6e, 0xec, 0x3d, 0x21, 0x00, 0x39,
+0xc9, 0xa1, 0x68, 0xe2, 0x50, 0x83, 0x2e, 0xb0, 0x3a, 0x2b, 0xf3, 0x36, 0xa0, 0xac, 0x2f, 0xe4,
+0x6f, 0x61, 0xc2, 0x51, 0x09, 0x39, 0x3e, 0x8b, 0x53, 0xb9, 0xbb, 0x67, 0xda, 0xdc, 0x53, 0xb9,
+0x76, 0x59, 0x36, 0x9d, 0x43, 0xe5, 0x20, 0xe0, 0x3d, 0x32, 0x60, 0x85, 0x22, 0x51, 0xb7, 0xc7,
+0x33, 0xbb, 0xdd, 0x15, 0x2f, 0xa4, 0x78, 0xa6, 0x07, 0x7b, 0x81, 0x46, 0x36, 0x04, 0x86, 0xdd,
+0x79, 0x35, 0xc7, 0x95, 0x2c, 0x3b, 0xb0, 0xa3, 0x17, 0x35, 0xe5, 0x73, 0x1f, 0xb4, 0x5c, 0x59,
+0xef, 0xda, 0xea, 0x10, 0x65, 0x7b, 0x7a, 0xd0, 0x7f, 0x9f, 0xb3, 0xb4, 0x2a, 0x37, 0x3b, 0x70,
+0x8b, 0x9b, 0x5b, 0xb9, 0x2b, 0xb7, 0xec, 0xb2, 0x51, 0x12, 0x97, 0x53, 0x29, 0x5a, 0xd4, 0xf0,
+0x12, 0x10, 0xdc, 0x4f, 0x02, 0xbb, 0x12, 0x92, 0x2f, 0x62, 0xd4, 0x3f, 0x69, 0x43, 0x7c, 0x0d,
+0xd6, 0xfc, 0x58, 0x75, 0x01, 0x88, 0x9d, 0x58, 0x16, 0x4b, 0xde, 0xba, 0x90, 0xff, 0x47, 0x01,
+0x89, 0x06, 0x6a, 0xf6, 0x5f, 0xb2, 0x90, 0x6a, 0xb3, 0x02, 0xa6, 0x02, 0x88, 0xbf, 0xb3, 0x47,
+0x7e, 0x2a, 0xd9, 0xd5, 0xfa, 0x68, 0x78, 0x35, 0x4d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x3f,
+0x30, 0x3d, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
+0x01, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xf0, 0x8f, 0x59, 0x38, 0x00,
+0xb3, 0xf5, 0x8f, 0x9a, 0x96, 0x0c, 0xd5, 0xeb, 0xfa, 0x7b, 0xaa, 0x17, 0xe8, 0x13, 0x12, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
+0x02, 0x01, 0x00, 0xbe, 0xe4, 0x5c, 0x62, 0x4e, 0x24, 0xf4, 0x0c, 0x08, 0xff, 0xf0, 0xd3, 0x0c,
+0x68, 0xe4, 0x93, 0x49, 0x22, 0x3f, 0x44, 0x27, 0x6f, 0xbb, 0x6d, 0xde, 0x83, 0x66, 0xce, 0xa8,
+0xcc, 0x0d, 0xfc, 0xf5, 0x9a, 0x06, 0xe5, 0x77, 0x14, 0x91, 0xeb, 0x9d, 0x41, 0x7b, 0x99, 0x2a,
+0x84, 0xe5, 0xff, 0xfc, 0x21, 0xc1, 0x5d, 0xf0, 0xe4, 0x1f, 0x57, 0xb7, 0x75, 0xa9, 0xa1, 0x5f,
+0x02, 0x26, 0xff, 0xd7, 0xc7, 0xf7, 0x4e, 0xde, 0x4f, 0xf8, 0xf7, 0x1c, 0x46, 0xc0, 0x7a, 0x4f,
+0x40, 0x2c, 0x22, 0x35, 0xf0, 0x19, 0xb1, 0xd0, 0x6b, 0x67, 0x2c, 0xb0, 0xa8, 0xe0, 0xc0, 0x40,
+0x37, 0x35, 0xf6, 0x84, 0x5c, 0x5c, 0xe3, 0xaf, 0x42, 0x78, 0xfe, 0xa7, 0xc9, 0x0d, 0x50, 0xea,
+0x0d, 0x84, 0x76, 0xf6, 0x51, 0xef, 0x83, 0x53, 0xc6, 0x7a, 0xff, 0x0e, 0x56, 0x49, 0x2e, 0x8f,
+0x7a, 0xd6, 0x0c, 0xe6, 0x27, 0x54, 0xe3, 0x4d, 0x0a, 0x60, 0x72, 0x62, 0xcd, 0x91, 0x07, 0xd6,
+0xa5, 0xbf, 0xc8, 0x99, 0x6b, 0xed, 0xc4, 0x19, 0xe6, 0xab, 0x4c, 0x11, 0x38, 0xc5, 0x6f, 0x31,
+0xe2, 0x6e, 0x49, 0xc8, 0x3f, 0x76, 0x80, 0x26, 0x03, 0x26, 0x29, 0xe0, 0x36, 0xf6, 0xf6, 0x20,
+0x53, 0xe3, 0x17, 0x70, 0x34, 0x17, 0x9d, 0x63, 0x68, 0x1e, 0x6b, 0xec, 0xc3, 0x4d, 0x86, 0xb8,
+0x13, 0x30, 0x2f, 0x5d, 0x46, 0x0d, 0x47, 0x43, 0xd5, 0x1b, 0xaa, 0x59, 0x0e, 0xb9, 0x5c, 0x8d,
+0x06, 0x48, 0xad, 0x74, 0x87, 0x5f, 0xc7, 0xfc, 0x31, 0x54, 0x41, 0x13, 0xe2, 0xc7, 0x21, 0x0e,
+0x9e, 0xe0, 0x1e, 0x0d, 0xe1, 0xc0, 0x7b, 0x43, 0x85, 0x90, 0xc5, 0x8a, 0x58, 0xc6, 0x65, 0x0a,
+0x78, 0x57, 0xf2, 0xc6, 0x23, 0x0f, 0x01, 0xd9, 0x20, 0x4b, 0xde, 0x0f, 0xfb, 0x92, 0x85, 0x75,
+0x2a, 0x5c, 0x73, 0x8d, 0x6d, 0x7b, 0x25, 0x91, 0xca, 0xee, 0x45, 0xae, 0x06, 0x4b, 0x00, 0xcc,
+0xd3, 0xb1, 0x59, 0x50, 0xda, 0x3a, 0x88, 0x3b, 0x29, 0x43, 0x46, 0x5e, 0x97, 0x2b, 0x54, 0xce,
+0x53, 0x6f, 0x8d, 0x4a, 0xe7, 0x96, 0xfa, 0xbf, 0x71, 0x0e, 0x42, 0x8b, 0x7c, 0xfd, 0x28, 0xa0,
+0xd0, 0x48, 0xca, 0xda, 0xc4, 0x81, 0x4c, 0xbb, 0xa2, 0x73, 0x93, 0x26, 0xc8, 0xeb, 0x0c, 0xd6,
+0x26, 0x88, 0xb6, 0xc0, 0x24, 0xcf, 0xbb, 0xbd, 0x5b, 0xeb, 0x75, 0x7d, 0xe9, 0x08, 0x8e, 0x86,
+0x33, 0x2c, 0x79, 0x77, 0x09, 0x69, 0xa5, 0x89, 0xfc, 0xb3, 0x70, 0x90, 0x87, 0x76, 0x8f, 0xd3,
+0x22, 0xbb, 0x42, 0xce, 0xbd, 0x73, 0x0b, 0x20, 0x26, 0x2a, 0xd0, 0x9b, 0x3d, 0x70, 0x1e, 0x24,
+0x6c, 0xcd, 0x87, 0x76, 0xa9, 0x17, 0x96, 0xb7, 0xcf, 0x0d, 0x92, 0xfb, 0x8e, 0x18, 0xa9, 0x98,
+0x49, 0xd1, 0x9e, 0xfe, 0x60, 0x44, 0x72, 0x21, 0xb9, 0x19, 0xed, 0xc2, 0xf5, 0x31, 0xf1, 0x39,
+0x48, 0x88, 0x90, 0x24, 0x75, 0x54, 0x16, 0xad, 0xce, 0xf4, 0xf8, 0x69, 0x14, 0x64, 0x39, 0xfb,
+0xa3, 0xb8, 0xba, 0x70, 0x40, 0xc7, 0x27, 0x1c, 0xbf, 0xc4, 0x56, 0x53, 0xfa, 0x63, 0x65, 0xd0,
+0xf3, 0x1c, 0x0e, 0x16, 0xf5, 0x6b, 0x86, 0x58, 0x4d, 0x18, 0xd4, 0xe4, 0x0d, 0x8e, 0xa5, 0x9d,
+0x5b, 0x91, 0xdc, 0x76, 0x24, 0x50, 0x3f, 0xc6, 0x2a, 0xfb, 0xd9, 0xb7, 0x9c, 0xb5, 0xd6, 0xe6,
+0xd0, 0xd9, 0xe8, 0x19, 0x8b, 0x15, 0x71, 0x48, 0xad, 0xb7, 0xea, 0xd8, 0x59, 0x88, 0xd4, 0x90,
+0xbf, 0x16, 0xb3, 0xd9, 0xe9, 0xac, 0x59, 0x61, 0x54, 0xc8, 0x1c, 0xba, 0xca, 0xc1, 0xca, 0xe1,
+0xb9, 0x20, 0x4c, 0x8f, 0x3a, 0x93, 0x89, 0xa5, 0xa0, 0xcc, 0xbf, 0xd3, 0xf6, 0x75, 0xa4, 0x75,
+0x96, 0x6d, 0x56, 0x30, 0x82, 0x05, 0x60, 0x30, 0x82, 0x03, 0x48, 0xa0, 0x03, 0x02, 0x01, 0x02,
+0x02, 0x10, 0x0a, 0x01, 0x42, 0x80, 0x00, 0x00, 0x01, 0x45, 0x23, 0xc8, 0x44, 0xb5, 0x00, 0x00,
+0x00, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+0x00, 0x30, 0x4a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
+0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x49, 0x64, 0x65, 0x6e, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1e, 0x49,
+0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63,
+0x69, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x30, 0x1e, 0x17,
+0x0d, 0x31, 0x34, 0x30, 0x31, 0x31, 0x36, 0x31, 0x38, 0x31, 0x32, 0x32, 0x33, 0x5a, 0x17, 0x0d,
+0x33, 0x34, 0x30, 0x31, 0x31, 0x36, 0x31, 0x38, 0x31, 0x32, 0x32, 0x33, 0x5a, 0x30, 0x4a, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x12, 0x30, 0x10,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x49, 0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74,
+0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1e, 0x49, 0x64, 0x65, 0x6e, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f,
+0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xa7, 0x50, 0x19, 0xde, 0x3f, 0x99,
+0x3d, 0xd4, 0x33, 0x46, 0xf1, 0x6f, 0x51, 0x61, 0x82, 0xb2, 0xa9, 0x4f, 0x8f, 0x67, 0x89, 0x5d,
+0x84, 0xd9, 0x53, 0xdd, 0x0c, 0x28, 0xd9, 0xd7, 0xf0, 0xff, 0xae, 0x95, 0x43, 0x72, 0x99, 0xf9,
+0xb5, 0x5d, 0x7c, 0x8a, 0xc1, 0x42, 0xe1, 0x31, 0x50, 0x74, 0xd1, 0x81, 0x0d, 0x7c, 0xcd, 0x9b,
+0x21, 0xab, 0x43, 0xe2, 0xac, 0xad, 0x5e, 0x86, 0x6e, 0xf3, 0x09, 0x8a, 0x1f, 0x5a, 0x32, 0xbd,
+0xa2, 0xeb, 0x94, 0xf9, 0xe8, 0x5c, 0x0a, 0xec, 0xff, 0x98, 0xd2, 0xaf, 0x71, 0xb3, 0xb4, 0x53,
+0x9f, 0x4e, 0x87, 0xef, 0x92, 0xbc, 0xbd, 0xec, 0x4f, 0x32, 0x30, 0x88, 0x4b, 0x17, 0x5e, 0x57,
+0xc4, 0x53, 0xc2, 0xf6, 0x02, 0x97, 0x8d, 0xd9, 0x62, 0x2b, 0xbf, 0x24, 0x1f, 0x62, 0x8d, 0xdf,
+0xc3, 0xb8, 0x29, 0x4b, 0x49, 0x78, 0x3c, 0x93, 0x60, 0x88, 0x22, 0xfc, 0x99, 0xda, 0x36, 0xc8,
+0xc2, 0xa2, 0xd4, 0x2c, 0x54, 0x00, 0x67, 0x35, 0x6e, 0x73, 0xbf, 0x02, 0x58, 0xf0, 0xa4, 0xdd,
+0xe5, 0xb0, 0xa2, 0x26, 0x7a, 0xca, 0xe0, 0x36, 0xa5, 0x19, 0x16, 0xf5, 0xfd, 0xb7, 0xef, 0xae,
+0x3f, 0x40, 0xf5, 0x6d, 0x5a, 0x04, 0xfd, 0xce, 0x34, 0xca, 0x24, 0xdc, 0x74, 0x23, 0x1b, 0x5d,
+0x33, 0x13, 0x12, 0x5d, 0xc4, 0x01, 0x25, 0xf6, 0x30, 0xdd, 0x02, 0x5d, 0x9f, 0xe0, 0xd5, 0x47,
+0xbd, 0xb4, 0xeb, 0x1b, 0xa1, 0xbb, 0x49, 0x49, 0xd8, 0x9f, 0x5b, 0x02, 0xf3, 0x8a, 0xe4, 0x24,
+0x90, 0xe4, 0x62, 0x4f, 0x4f, 0xc1, 0xaf, 0x8b, 0x0e, 0x74, 0x17, 0xa8, 0xd1, 0x72, 0x88, 0x6a,
+0x7a, 0x01, 0x49, 0xcc, 0xb4, 0x46, 0x79, 0xc6, 0x17, 0xb1, 0xda, 0x98, 0x1e, 0x07, 0x59, 0xfa,
+0x75, 0x21, 0x85, 0x65, 0xdd, 0x90, 0x56, 0xce, 0xfb, 0xab, 0xa5, 0x60, 0x9d, 0xc4, 0x9d, 0xf9,
+0x52, 0xb0, 0x8b, 0xbd, 0x87, 0xf9, 0x8f, 0x2b, 0x23, 0x0a, 0x23, 0x76, 0x3b, 0xf7, 0x33, 0xe1,
+0xc9, 0x00, 0xf3, 0x69, 0xf9, 0x4b, 0xa2, 0xe0, 0x4e, 0xbc, 0x7e, 0x93, 0x39, 0x84, 0x07, 0xf7,
+0x44, 0x70, 0x7e, 0xfe, 0x07, 0x5a, 0xe5, 0xb1, 0xac, 0xd1, 0x18, 0xcc, 0xf2, 0x35, 0xe5, 0x49,
+0x49, 0x08, 0xca, 0x56, 0xc9, 0x3d, 0xfb, 0x0f, 0x18, 0x7d, 0x8b, 0x3b, 0xc1, 0x13, 0xc2, 0x4d,
+0x8f, 0xc9, 0x4f, 0x0e, 0x37, 0xe9, 0x1f, 0xa1, 0x0e, 0x6a, 0xdf, 0x62, 0x2e, 0xcb, 0x35, 0x06,
+0x51, 0x79, 0x2c, 0xc8, 0x25, 0x38, 0xf4, 0xfa, 0x4b, 0xa7, 0x89, 0x5c, 0x9c, 0xd2, 0xe3, 0x0d,
+0x39, 0x86, 0x4a, 0x74, 0x7c, 0xd5, 0x59, 0x87, 0xc2, 0x3f, 0x4e, 0x0c, 0x5c, 0x52, 0xf4, 0x3d,
+0xf7, 0x52, 0x82, 0xf1, 0xea, 0xa3, 0xac, 0xfd, 0x49, 0x34, 0x1a, 0x28, 0xf3, 0x41, 0x88, 0x3a,
+0x13, 0xee, 0xe8, 0xde, 0xff, 0x99, 0x1d, 0x5f, 0xba, 0xcb, 0xe8, 0x1e, 0xf2, 0xb9, 0x50, 0x60,
+0xc0, 0x31, 0xd3, 0x73, 0xe5, 0xef, 0xbe, 0xa0, 0xed, 0x33, 0x0b, 0x74, 0xbe, 0x20, 0x20, 0xc4,
+0x67, 0x6c, 0xf0, 0x08, 0x03, 0x7a, 0x55, 0x80, 0x7f, 0x46, 0x4e, 0x96, 0xa7, 0xf4, 0x1e, 0x3e,
+0xe1, 0xf6, 0xd8, 0x09, 0xe1, 0x33, 0x64, 0x2b, 0x63, 0xd7, 0x32, 0x5e, 0x9f, 0xf9, 0xc0, 0x7b,
+0x0f, 0x78, 0x6f, 0x97, 0xbc, 0x93, 0x9a, 0xf9, 0x9c, 0x12, 0x90, 0x78, 0x7a, 0x80, 0x87, 0x15,
+0xd7, 0x72, 0x74, 0x9c, 0x55, 0x74, 0x78, 0xb1, 0xba, 0xe1, 0x6e, 0x70, 0x04, 0xba, 0x4f, 0xa0,
+0xba, 0x68, 0xc3, 0x7b, 0xff, 0x31, 0xf0, 0x73, 0x3d, 0x3d, 0x94, 0x2a, 0xb1, 0x0b, 0x41, 0x0e,
+0xa0, 0xfe, 0x4d, 0x88, 0x65, 0x6b, 0x79, 0x33, 0xb4, 0xd7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xed,
+0x44, 0x19, 0xc0, 0xd3, 0xf0, 0x06, 0x8b, 0xee, 0xa4, 0x7b, 0xbe, 0x42, 0xe7, 0x26, 0x54, 0xc8,
+0x8e, 0x36, 0x76, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x0d, 0xae, 0x90, 0x32, 0xf6, 0xa6, 0x4b, 0x7c, 0x44,
+0x76, 0x19, 0x61, 0x1e, 0x27, 0x28, 0xcd, 0x5e, 0x54, 0xef, 0x25, 0xbc, 0xe3, 0x08, 0x90, 0xf9,
+0x29, 0xd7, 0xae, 0x68, 0x08, 0xe1, 0x94, 0x00, 0x58, 0xef, 0x2e, 0x2e, 0x7e, 0x53, 0x52, 0x8c,
+0xb6, 0x5c, 0x07, 0xea, 0x88, 0xba, 0x99, 0x8b, 0x50, 0x94, 0xd7, 0x82, 0x80, 0xdf, 0x61, 0x09,
+0x00, 0x93, 0xad, 0x0d, 0x14, 0xe6, 0xce, 0xc1, 0xf2, 0x37, 0x94, 0x78, 0xb0, 0x5f, 0x9c, 0xb3,
+0xa2, 0x73, 0xb8, 0x8f, 0x05, 0x93, 0x38, 0xcd, 0x8d, 0x3e, 0xb0, 0xb8, 0xfb, 0xc0, 0xcf, 0xb1,
+0xf2, 0xec, 0x2d, 0x2d, 0x1b, 0xcc, 0xec, 0xaa, 0x9a, 0xb3, 0xaa, 0x60, 0x82, 0x1b, 0x2d, 0x3b,
+0xc3, 0x84, 0x3d, 0x57, 0x8a, 0x96, 0x1e, 0x9c, 0x75, 0xb8, 0xd3, 0x30, 0xcd, 0x60, 0x08, 0x83,
+0x90, 0xd3, 0x8e, 0x54, 0xf1, 0x4d, 0x66, 0xc0, 0x5d, 0x74, 0x03, 0x40, 0xa3, 0xee, 0x85, 0x7e,
+0xc2, 0x1f, 0x77, 0x9c, 0x06, 0xe8, 0xc1, 0xa7, 0x18, 0x5d, 0x52, 0x95, 0xed, 0xc9, 0xdd, 0x25,
+0x9e, 0x6d, 0xfa, 0xa9, 0xed, 0xa3, 0x3a, 0x34, 0xd0, 0x59, 0x7b, 0xda, 0xed, 0x50, 0xf3, 0x35,
+0xbf, 0xed, 0xeb, 0x14, 0x4d, 0x31, 0xc7, 0x60, 0xf4, 0xda, 0xf1, 0x87, 0x9c, 0xe2, 0x48, 0xe2,
+0xc6, 0xc5, 0x37, 0xfb, 0x06, 0x10, 0xfa, 0x75, 0x59, 0x66, 0x31, 0x47, 0x29, 0xda, 0x76, 0x9a,
+0x1c, 0xe9, 0x82, 0xae, 0xef, 0x9a, 0xb9, 0x51, 0xf7, 0x88, 0x23, 0x9a, 0x69, 0x95, 0x62, 0x3c,
+0xe5, 0x55, 0x80, 0x36, 0xd7, 0x54, 0x02, 0xff, 0xf1, 0xb9, 0x5d, 0xce, 0xd4, 0x23, 0x6f, 0xd8,
+0x45, 0x84, 0x4a, 0x5b, 0x65, 0xef, 0x89, 0x0c, 0xdd, 0x14, 0xa7, 0x20, 0xcb, 0x18, 0xa5, 0x25,
+0xb4, 0x0d, 0xf9, 0x01, 0xf0, 0xa2, 0xd2, 0xf4, 0x00, 0xc8, 0x74, 0x8e, 0xa1, 0x2a, 0x48, 0x8e,
+0x65, 0xdb, 0x13, 0xc4, 0xe2, 0x25, 0x17, 0x7d, 0xeb, 0xbe, 0x87, 0x5b, 0x17, 0x20, 0x54, 0x51,
+0x93, 0x4a, 0x53, 0x03, 0x0b, 0xec, 0x5d, 0xca, 0x33, 0xed, 0x62, 0xfd, 0x45, 0xc7, 0x2f, 0x5b,
+0xdc, 0x58, 0xa0, 0x80, 0x39, 0xe6, 0xfa, 0xd7, 0xfe, 0x13, 0x14, 0xa6, 0xed, 0x3d, 0x94, 0x4a,
+0x42, 0x74, 0xd4, 0xc3, 0x77, 0x59, 0x73, 0xcd, 0x8f, 0x46, 0xbe, 0x55, 0x38, 0xef, 0xfa, 0xe8,
+0x91, 0x32, 0xea, 0x97, 0x58, 0x04, 0x22, 0xde, 0x38, 0xc3, 0xcc, 0xbc, 0x6d, 0xc9, 0x33, 0x3a,
+0x6a, 0x0a, 0x69, 0x3f, 0xa0, 0xc8, 0xea, 0x72, 0x8f, 0x8c, 0x63, 0x86, 0x23, 0xbd, 0x6d, 0x3c,
+0x96, 0x9e, 0x95, 0xe0, 0x49, 0x4c, 0xaa, 0xa2, 0xb9, 0x2a, 0x1b, 0x9c, 0x36, 0x81, 0x78, 0xed,
+0xc3, 0xe8, 0x46, 0xe2, 0x26, 0x59, 0x44, 0x75, 0x1e, 0xd9, 0x75, 0x89, 0x51, 0xcd, 0x10, 0x84,
+0x9d, 0x61, 0x60, 0xcb, 0x5d, 0xf9, 0x97, 0x22, 0x4d, 0x8e, 0x98, 0xe6, 0xe3, 0x7f, 0xf6, 0x5b,
+0xbb, 0xae, 0xcd, 0xca, 0x4a, 0x81, 0x6b, 0x5e, 0x0b, 0xf3, 0x51, 0xe1, 0x74, 0x2b, 0xe9, 0x7e,
+0x27, 0xa7, 0xd9, 0x99, 0x49, 0x4e, 0xf8, 0xa5, 0x80, 0xdb, 0x25, 0x0f, 0x1c, 0x63, 0x62, 0x8a,
+0xc9, 0x33, 0x67, 0x6b, 0x3c, 0x10, 0x83, 0xc6, 0xad, 0xde, 0xa8, 0xcd, 0x16, 0x8e, 0x8d, 0xf0,
+0x07, 0x37, 0x71, 0x9f, 0xf2, 0xab, 0xfc, 0x41, 0xf5, 0xc1, 0x8b, 0xec, 0x00, 0x37, 0x5d, 0x09,
+0xe5, 0x4e, 0x80, 0xef, 0xfa, 0xb1, 0x5c, 0x38, 0x06, 0xa5, 0x1b, 0x4a, 0xe1, 0xdc, 0x38, 0x2d,
+0x3c, 0xdc, 0xab, 0x1f, 0x90, 0x1a, 0xd5, 0x4a, 0x9c, 0xee, 0xd1, 0x70, 0x6c, 0xcc, 0xee, 0xf4,
+0x57, 0xf8, 0x18, 0xba, 0x84, 0x6e, 0x87, 0x30, 0x82, 0x05, 0x66, 0x30, 0x82, 0x03, 0x4e, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x0a, 0x01, 0x42, 0x80, 0x00, 0x00, 0x01, 0x45, 0x23, 0xcf,
+0x46, 0x7c, 0x00, 0x00, 0x00, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x4d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x55, 0x53, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x49,
+0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x21, 0x49, 0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x75, 0x62,
+0x6c, 0x69, 0x63, 0x20, 0x53, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x43, 0x41, 0x20, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, 0x31, 0x36, 0x31, 0x37,
+0x35, 0x33, 0x33, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30, 0x31, 0x31, 0x36, 0x31, 0x37, 0x35,
+0x33, 0x33, 0x32, 0x5a, 0x30, 0x4d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x55, 0x53, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x49, 0x64,
+0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x21, 0x49, 0x64, 0x65, 0x6e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x50, 0x75, 0x62, 0x6c,
+0x69, 0x63, 0x20, 0x53, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
+0x41, 0x20, 0x31, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02,
+0x82, 0x02, 0x01, 0x00, 0xb6, 0x22, 0x94, 0xfc, 0xa4, 0x48, 0xaf, 0xe8, 0x47, 0x6b, 0x0a, 0xfb,
+0x27, 0x76, 0xe4, 0xf2, 0x3f, 0x8a, 0x3b, 0x7a, 0x4a, 0x2c, 0x31, 0x2a, 0x8c, 0x8d, 0xb0, 0xa9,
+0xc3, 0x31, 0x6b, 0xa8, 0x77, 0x76, 0x84, 0x26, 0xb6, 0xac, 0x81, 0x42, 0x0d, 0x08, 0xeb, 0x55,
+0x58, 0xbb, 0x7a, 0xf8, 0xbc, 0x65, 0x7d, 0xf2, 0xa0, 0x6d, 0x8b, 0xa8, 0x47, 0xe9, 0x62, 0x76,
+0x1e, 0x11, 0xee, 0x08, 0x14, 0xd1, 0xb2, 0x44, 0x16, 0xf4, 0xea, 0xd0, 0xfa, 0x1e, 0x2f, 0x5e,
+0xdb, 0xcb, 0x73, 0x41, 0xae, 0xbc, 0x00, 0xb0, 0x4a, 0x2b, 0x40, 0xb2, 0xac, 0xe1, 0x3b, 0x4b,
+0xc2, 0x2d, 0x9d, 0xe4, 0xa1, 0x9b, 0xec, 0x1a, 0x3a, 0x1e, 0xf0, 0x08, 0xb3, 0xd0, 0xe4, 0x24,
+0x35, 0x07, 0x9f, 0x9c, 0xb4, 0xc9, 0x52, 0x6d, 0xdb, 0x07, 0xca, 0x8f, 0xb5, 0x5b, 0xf0, 0x83,
+0xf3, 0x4f, 0xc7, 0x2d, 0xa5, 0xc8, 0xad, 0xcb, 0x95, 0x20, 0xa4, 0x31, 0x28, 0x57, 0x58, 0x5a,
+0xe4, 0x8d, 0x1b, 0x9a, 0xab, 0x9e, 0x0d, 0x0c, 0xf2, 0x0a, 0x33, 0x39, 0x22, 0x39, 0x0a, 0x97,
+0x2e, 0xf3, 0x53, 0x77, 0xb9, 0x44, 0x45, 0xfd, 0x84, 0xcb, 0x36, 0x20, 0x81, 0x59, 0x2d, 0x9a,
+0x6f, 0x6d, 0x48, 0x48, 0x61, 0xca, 0x4c, 0xdf, 0x53, 0xd1, 0xaf, 0x52, 0xbc, 0x44, 0x9f, 0xab,
+0x2f, 0x6b, 0x83, 0x72, 0xef, 0x75, 0x80, 0xda, 0x06, 0x33, 0x1b, 0x5d, 0xc8, 0xda, 0x63, 0xc6,
+0x4d, 0xcd, 0xac, 0x66, 0x31, 0xcd, 0xd1, 0xde, 0x3e, 0x87, 0x10, 0x36, 0xe1, 0xb9, 0xa4, 0x7a,
+0xef, 0x60, 0x50, 0xb2, 0xcb, 0xca, 0xa6, 0x56, 0xe0, 0x37, 0xaf, 0xab, 0x34, 0x13, 0x39, 0x25,
+0xe8, 0x39, 0x66, 0xe4, 0x98, 0x7a, 0xaa, 0x12, 0x98, 0x9c, 0x59, 0x66, 0x86, 0x3e, 0xad, 0xf1,
+0xb0, 0xca, 0x3e, 0x06, 0x0f, 0x7b, 0xf0, 0x11, 0x4b, 0x37, 0xa0, 0x44, 0x6d, 0x7b, 0xcb, 0xa8,
+0x8c, 0x71, 0xf4, 0xd5, 0xb5, 0x91, 0x36, 0xcc, 0xf0, 0x15, 0xc6, 0x2b, 0xde, 0x51, 0x17, 0xb1,
+0x97, 0x4c, 0x50, 0x3d, 0xb1, 0x95, 0x59, 0x7c, 0x05, 0x7d, 0x2d, 0x21, 0xd5, 0x00, 0xbf, 0x01,
+0x67, 0xa2, 0x5e, 0x7b, 0xa6, 0x5c, 0xf2, 0xf7, 0x22, 0xf1, 0x90, 0x0d, 0x93, 0xdb, 0xaa, 0x44,
+0x51, 0x66, 0xcc, 0x7d, 0x76, 0x03, 0xeb, 0x6a, 0xa8, 0x2a, 0x38, 0x19, 0x97, 0x76, 0x0d, 0x6b,
+0x8a, 0x61, 0xf9, 0xbc, 0xf6, 0xee, 0x76, 0xfd, 0x70, 0x2b, 0xdd, 0x29, 0x3c, 0xf8, 0x0a, 0x1e,
+0x5b, 0x42, 0x1c, 0x8b, 0x56, 0x2f, 0x55, 0x1b, 0x1c, 0xa1, 0x2e, 0xb5, 0xc7, 0x16, 0xe6, 0xf8,
+0xaa, 0x3c, 0x92, 0x8e, 0x69, 0xb6, 0x01, 0xc1, 0xb5, 0x86, 0x9d, 0x89, 0x0f, 0x0b, 0x38, 0x94,
+0x54, 0xe8, 0xea, 0xdc, 0x9e, 0x3d, 0x25, 0xbc, 0x53, 0x26, 0xed, 0xd5, 0xab, 0x39, 0xaa, 0xc5,
+0x40, 0x4c, 0x54, 0xab, 0xb2, 0xb4, 0xd9, 0xd9, 0xf8, 0xd7, 0x72, 0xdb, 0x1c, 0xbc, 0x6d, 0xbd,
+0x65, 0x5f, 0xef, 0x88, 0x35, 0x2a, 0x66, 0x2f, 0xee, 0xf6, 0xb3, 0x65, 0xf0, 0x33, 0x8d, 0x7c,
+0x98, 0x41, 0x69, 0x46, 0x0f, 0x43, 0x1c, 0x69, 0xfa, 0x9b, 0xb5, 0xd0, 0x61, 0x6a, 0xcd, 0xca,
+0x4b, 0xd9, 0x4c, 0x90, 0x46, 0xab, 0x15, 0x59, 0xa1, 0x47, 0x54, 0x29, 0x2e, 0x83, 0x28, 0x5f,
+0x1c, 0xc2, 0xa2, 0xab, 0x72, 0x17, 0x00, 0x06, 0x8e, 0x45, 0xec, 0x8b, 0xe2, 0x33, 0x3d, 0x7f,
+0xda, 0x19, 0x44, 0xe4, 0x62, 0x72, 0xc3, 0xdf, 0x22, 0xc6, 0xf2, 0x56, 0xd4, 0xdd, 0x5f, 0x95,
+0x72, 0xed, 0x6d, 0x5f, 0xf7, 0x48, 0x03, 0x5b, 0xfd, 0xc5, 0x2a, 0xa0, 0xf6, 0x73, 0x23, 0x84,
+0x10, 0x1b, 0x01, 0xe7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xe3, 0x71, 0xe0, 0x9e, 0xd8, 0xa7, 0x42,
+0xd9, 0xdb, 0x71, 0x91, 0x6b, 0x94, 0x93, 0xeb, 0xc3, 0xa3, 0xd1, 0x14, 0xa3, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
+0x00, 0x47, 0xfa, 0xdd, 0x0a, 0xb0, 0x11, 0x91, 0x38, 0xad, 0x4d, 0x5d, 0xf7, 0xe5, 0x0e, 0x97,
+0x54, 0x19, 0x82, 0x48, 0x87, 0x54, 0x8c, 0xaa, 0x64, 0x99, 0xd8, 0x5a, 0xfe, 0x88, 0x01, 0xc5,
+0x58, 0xa5, 0x99, 0xb1, 0x23, 0x54, 0x23, 0xb7, 0x6a, 0x1d, 0x20, 0x57, 0xe5, 0x01, 0x62, 0x41,
+0x17, 0xd3, 0x09, 0xdb, 0x75, 0xcb, 0x6e, 0x54, 0x90, 0x75, 0xfe, 0x1a, 0x9f, 0x81, 0x0a, 0xc2,
+0xdd, 0xd7, 0xf7, 0x09, 0xd0, 0x5b, 0x72, 0x15, 0xe4, 0x1e, 0x09, 0x6a, 0x3d, 0x33, 0xf3, 0x21,
+0x9a, 0xe6, 0x15, 0x7e, 0xad, 0x51, 0xd5, 0x0d, 0x10, 0xed, 0x7d, 0x42, 0xc0, 0x8f, 0xee, 0xc0,
+0x9a, 0x08, 0xd5, 0x41, 0xd6, 0x5c, 0x0e, 0x21, 0x69, 0x6e, 0x80, 0x61, 0x0e, 0x15, 0xc0, 0xb8,
+0xcf, 0xc5, 0x49, 0x12, 0x52, 0xcc, 0xbe, 0x3a, 0xcc, 0xd4, 0x2e, 0x38, 0x05, 0xde, 0x35, 0xfd,
+0x1f, 0x6f, 0xb8, 0x80, 0x68, 0x98, 0x3d, 0x4d, 0xa0, 0xca, 0x40, 0x65, 0xd2, 0x73, 0x7c, 0xf5,
+0x8b, 0xd9, 0x0a, 0x95, 0x3f, 0xd8, 0x3f, 0x23, 0x6d, 0x1a, 0xd1, 0x2a, 0x24, 0x19, 0xd9, 0x85,
+0xb3, 0x17, 0xef, 0x78, 0x6e, 0xa9, 0x58, 0xd1, 0x23, 0xd3, 0xc7, 0x13, 0xed, 0x72, 0x25, 0x7f,
+0x5d, 0xb1, 0x73, 0x70, 0xd0, 0x7f, 0x06, 0x97, 0x09, 0x84, 0x29, 0x80, 0x61, 0x1d, 0xfa, 0x5e,
+0xff, 0x73, 0xac, 0xa0, 0xe3, 0x89, 0xb8, 0x1c, 0x71, 0x15, 0xc6, 0xde, 0x31, 0x7f, 0x12, 0xdc,
+0xe1, 0x6d, 0x9b, 0xaf, 0xe7, 0xe8, 0x9f, 0x75, 0x78, 0x4c, 0xab, 0x46, 0x3b, 0x9a, 0xce, 0xbf,
+0x05, 0x18, 0x5d, 0x4d, 0x15, 0x3c, 0x16, 0x9a, 0x19, 0x50, 0x04, 0x9a, 0xb2, 0x9a, 0x6f, 0x65,
+0x8b, 0x52, 0x5f, 0x3c, 0x58, 0x04, 0x28, 0x25, 0xc0, 0x66, 0x61, 0x31, 0x7e, 0xb9, 0xe0, 0x75,
+0xb9, 0x1a, 0xa8, 0x81, 0xd6, 0x72, 0x17, 0xb3, 0xc5, 0x03, 0x31, 0x35, 0x11, 0x78, 0x78, 0xa2,
+0xe0, 0xe9, 0x30, 0x8c, 0x7f, 0x80, 0xdf, 0x58, 0xdf, 0x3c, 0xba, 0x27, 0x96, 0xe2, 0x80, 0x34,
+0x6d, 0xe3, 0x98, 0xd3, 0x64, 0x27, 0xac, 0x48, 0x7e, 0x28, 0x77, 0x5c, 0xc6, 0x25, 0x61, 0x25,
+0xf8, 0x85, 0x0c, 0x65, 0xfa, 0xc4, 0x32, 0x2f, 0xa5, 0x98, 0x05, 0xe4, 0xf8, 0x0b, 0x67, 0x16,
+0x16, 0xc6, 0x82, 0xb8, 0x32, 0x19, 0xf9, 0xf9, 0xb9, 0x79, 0xdc, 0x1f, 0xcd, 0xeb, 0xaf, 0xab,
+0x0e, 0xdd, 0x1b, 0xdb, 0x45, 0xe4, 0x7a, 0xe7, 0x02, 0xe2, 0x95, 0x5d, 0xfc, 0x69, 0xf0, 0x53,
+0x69, 0x61, 0x95, 0x75, 0x79, 0x0b, 0x5e, 0x55, 0xe6, 0x38, 0x1c, 0x94, 0xa9, 0x59, 0x33, 0x9e,
+0xc8, 0x71, 0x74, 0x79, 0x7f, 0x51, 0x89, 0xb6, 0xc8, 0x6a, 0xb8, 0x30, 0xc8, 0x6a, 0x38, 0xc3,
+0x6e, 0x9e, 0xe1, 0x37, 0x16, 0xea, 0x05, 0x62, 0x4c, 0x5b, 0x12, 0x47, 0xed, 0xa7, 0xb4, 0xb3,
+0x58, 0x56, 0xc7, 0x49, 0xf3, 0x7f, 0x12, 0x68, 0x09, 0x31, 0x71, 0xf0, 0x6d, 0xf8, 0x4e, 0x47,
+0xfb, 0xd6, 0x85, 0xee, 0xc5, 0x58, 0x40, 0x19, 0xa4, 0x1d, 0xa7, 0xf9, 0x4b, 0x43, 0x37, 0xdc,
+0x68, 0x5a, 0x4f, 0xcf, 0xeb, 0xc2, 0x64, 0x74, 0xde, 0xb4, 0x15, 0xd9, 0xf4, 0x54, 0x54, 0x1a,
+0x2f, 0x1c, 0xd7, 0x97, 0x71, 0x54, 0x90, 0x8e, 0xd9, 0x20, 0x9d, 0x53, 0x2b, 0x7f, 0xab, 0x8f,
+0xe2, 0xea, 0x30, 0xbc, 0x50, 0x37, 0xef, 0xf1, 0x47, 0xb5, 0x7d, 0x7c, 0x2c, 0x04, 0xec, 0x68,
+0x9d, 0xb4, 0x49, 0x44, 0x10, 0xf4, 0x72, 0x4b, 0x1c, 0x64, 0xe7, 0xfc, 0xe6, 0x6b, 0x90, 0xdd,
+0x69, 0x7d, 0x69, 0xfd, 0x00, 0x56, 0xa5, 0xb7, 0xac, 0xb6, 0xad, 0xb7, 0xca, 0x3e, 0x01, 0xef,
+0x9c, 0x30, 0x82, 0x05, 0x70, 0x30, 0x82, 0x03, 0x58, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04,
+0x00, 0x98, 0x96, 0x8d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x30, 0x58, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x4e, 0x4c, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x15, 0x53, 0x74, 0x61,
+0x61, 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64,
+0x65, 0x6e, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x20, 0x53, 0x74, 0x61,
+0x61, 0x74, 0x20, 0x64, 0x65, 0x72, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64,
+0x65, 0x6e, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17,
+0x0d, 0x31, 0x30, 0x31, 0x32, 0x30, 0x38, 0x31, 0x31, 0x31, 0x39, 0x32, 0x39, 0x5a, 0x17, 0x0d,
+0x32, 0x32, 0x31, 0x32, 0x30, 0x38, 0x31, 0x31, 0x31, 0x30, 0x32, 0x38, 0x5a, 0x30, 0x58, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x1e, 0x30, 0x1c,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x15, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, 0x72,
+0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x31, 0x29, 0x30, 0x27,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x20, 0x53, 0x74, 0x61, 0x61, 0x74, 0x20, 0x64, 0x65, 0x72,
+0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x6e, 0x20, 0x45, 0x56, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30,
+0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xe3, 0xc7, 0x7e, 0x89, 0xf9, 0x24, 0x4b, 0x3a,
+0xd2, 0x33, 0x83, 0x35, 0x2c, 0x69, 0xec, 0xdc, 0x09, 0xa4, 0xe3, 0x51, 0xa8, 0x25, 0x2b, 0x79,
+0xb8, 0x08, 0x3d, 0xe0, 0x91, 0xba, 0x84, 0x85, 0xc6, 0x85, 0xa4, 0xca, 0xe6, 0xc9, 0x2e, 0x53,
+0xa4, 0xc9, 0x24, 0x1e, 0xfd, 0x55, 0x66, 0x71, 0x5d, 0x2c, 0xc5, 0x60, 0x68, 0x04, 0xb7, 0xd9,
+0xc2, 0x52, 0x26, 0x38, 0x88, 0xa4, 0xd6, 0x3b, 0x40, 0xa6, 0xc2, 0xcd, 0x3f, 0xcd, 0x98, 0x93,
+0xb3, 0x54, 0x14, 0x58, 0x96, 0x55, 0xd5, 0x50, 0xfe, 0x86, 0xad, 0xa4, 0x63, 0x7f, 0x5c, 0x87,
+0xf6, 0x8e, 0xe6, 0x27, 0x92, 0x67, 0x17, 0x92, 0x02, 0x03, 0x2c, 0xdc, 0xd6, 0x66, 0x74, 0xed,
+0xdd, 0x67, 0xff, 0xc1, 0x61, 0x8d, 0x63, 0x4f, 0x0f, 0x9b, 0x6d, 0x17, 0x30, 0x26, 0xef, 0xab,
+0xd2, 0x1f, 0x10, 0xa0, 0xf9, 0xc5, 0x7f, 0x16, 0x69, 0x81, 0x03, 0x47, 0xed, 0x1e, 0x68, 0x8d,
+0x72, 0xa1, 0x4d, 0xb2, 0x26, 0xc6, 0xba, 0x6c, 0x5f, 0x6d, 0xd6, 0xaf, 0xd1, 0xb1, 0x13, 0x8e,
+0xa9, 0xad, 0xf3, 0x5e, 0x69, 0x75, 0x26, 0x18, 0x3e, 0x41, 0x2b, 0x21, 0x7f, 0xee, 0x8b, 0x5d,
+0x07, 0x06, 0x9d, 0x43, 0xc4, 0x29, 0x0a, 0x2b, 0xfc, 0x2a, 0x3e, 0x86, 0xcb, 0x3c, 0x83, 0x3a,
+0xf9, 0xc9, 0x0d, 0xda, 0xc5, 0x99, 0xe2, 0xbc, 0x78, 0x41, 0x33, 0x76, 0xe1, 0xbf, 0x2f, 0x5d,
+0xe5, 0xa4, 0x98, 0x50, 0x0c, 0x15, 0xdd, 0xe0, 0xfa, 0x9c, 0x7f, 0x38, 0x68, 0xd0, 0xb2, 0xa6,
+0x7a, 0xa7, 0xd1, 0x31, 0xbd, 0x7e, 0x8a, 0x58, 0x27, 0x43, 0xb3, 0xba, 0x33, 0x91, 0xd3, 0xa7,
+0x98, 0x15, 0x5c, 0x9a, 0xe6, 0xd3, 0x0f, 0x75, 0xd9, 0xfc, 0x41, 0x98, 0x97, 0x3e, 0xaa, 0x25,
+0xdb, 0x8f, 0x92, 0x2e, 0xb0, 0x7b, 0x0c, 0x5f, 0xf1, 0x63, 0xa9, 0x37, 0xf9, 0x9b, 0x75, 0x69,
+0x4c, 0x28, 0x26, 0x25, 0xda, 0xd5, 0xf2, 0x12, 0x70, 0x45, 0x55, 0xe3, 0xdf, 0x73, 0x5e, 0x37,
+0xf5, 0x21, 0x6c, 0x90, 0x8e, 0x35, 0x5a, 0xc9, 0xd3, 0x23, 0xeb, 0xd3, 0xc0, 0xbe, 0x78, 0xac,
+0x42, 0x28, 0x58, 0x66, 0xa5, 0x46, 0x6d, 0x70, 0x02, 0xd7, 0x10, 0xf9, 0x4b, 0x54, 0xfc, 0x5d,
+0x86, 0x4a, 0x87, 0xcf, 0x7f, 0xca, 0x45, 0xac, 0x11, 0x5a, 0xb5, 0x20, 0x51, 0x8d, 0x2f, 0x88,
+0x47, 0x97, 0x39, 0xc0, 0xcf, 0xba, 0xc0, 0x42, 0x01, 0x40, 0x99, 0x48, 0x21, 0x0b, 0x6b, 0xa7,
+0xd2, 0xfd, 0x96, 0xd5, 0xd1, 0xbe, 0x46, 0x9d, 0x49, 0xe0, 0x0b, 0xa6, 0xa0, 0x22, 0x4e, 0x38,
+0xd0, 0xc1, 0x3c, 0x30, 0xbc, 0x70, 0x8f, 0x2c, 0x75, 0xcc, 0xd0, 0xc5, 0x8c, 0x51, 0x3b, 0x3d,
+0x94, 0x08, 0x64, 0x26, 0x61, 0x7d, 0xb9, 0xc3, 0x65, 0x8f, 0x14, 0x9c, 0x21, 0xd0, 0xaa, 0xfd,
+0x17, 0x72, 0x03, 0x8f, 0xbd, 0x9b, 0x8c, 0xe6, 0x5e, 0x53, 0x9e, 0xb9, 0x9d, 0xef, 0x82, 0xbb,
+0xe1, 0xbc, 0xe2, 0x72, 0x41, 0x5b, 0x21, 0x94, 0xd3, 0x45, 0x37, 0x94, 0xd1, 0xdf, 0x09, 0x39,
+0x5d, 0xe7, 0x23, 0xaa, 0x9a, 0x1d, 0xca, 0x6d, 0xa8, 0x0a, 0x86, 0x85, 0x8a, 0x82, 0xbe, 0x42,
+0x07, 0xd6, 0xf2, 0x38, 0x82, 0x73, 0xda, 0x87, 0x5b, 0xe5, 0x3c, 0xd3, 0x9e, 0x3e, 0xa7, 0x3b,
+0x9e, 0xf4, 0x03, 0xb3, 0xf9, 0xf1, 0x7d, 0x13, 0x74, 0x02, 0xff, 0xbb, 0xa1, 0xe5, 0xfa, 0x00,
+0x79, 0x1c, 0xa6, 0x66, 0x41, 0x88, 0x5c, 0x60, 0x57, 0xa6, 0x2e, 0x09, 0xc4, 0xba, 0xfd, 0x9a,
+0xcf, 0xa7, 0x1f, 0x40, 0xc3, 0xbb, 0xcc, 0x5a, 0x0a, 0x55, 0x4b, 0x3b, 0x38, 0x76, 0x51, 0xb8,
+0x63, 0x8b, 0x84, 0x94, 0x16, 0xe6, 0x56, 0xf3, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30,
+0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xfe, 0xab, 0x00,
+0x90, 0x98, 0x9e, 0x24, 0xfc, 0xa9, 0xcc, 0x1a, 0x8a, 0xfb, 0x27, 0xb8, 0xbf, 0x30, 0x6e, 0xa8,
+0x3b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+0x03, 0x82, 0x02, 0x01, 0x00, 0xcf, 0x77, 0x2c, 0x6e, 0x56, 0xbe, 0x4e, 0xb3, 0xb6, 0x84, 0x00,
+0x94, 0xab, 0x47, 0xc9, 0x0d, 0xd2, 0x76, 0xc7, 0x86, 0x9f, 0x1d, 0x07, 0xd3, 0xb6, 0xb4, 0xbb,
+0x08, 0x78, 0xaf, 0x69, 0xd2, 0x0b, 0x49, 0xde, 0x33, 0xc5, 0xac, 0xad, 0xc2, 0x88, 0x02, 0x7d,
+0x06, 0xb7, 0x35, 0x02, 0xc1, 0x60, 0xc9, 0xbf, 0xc4, 0xe8, 0x94, 0xde, 0xd4, 0xd3, 0xa9, 0x13,
+0x25, 0x5a, 0xfe, 0x6e, 0xa2, 0xae, 0x7d, 0x05, 0xdc, 0x7d, 0xf3, 0x6c, 0xf0, 0x7e, 0xa6, 0x8d,
+0xee, 0xd9, 0xd7, 0xce, 0x58, 0x17, 0xe8, 0xa9, 0x29, 0xae, 0x73, 0x48, 0x87, 0xe7, 0x9b, 0xca,
+0x6e, 0x29, 0xa1, 0x64, 0x5f, 0x19, 0x13, 0xf7, 0xae, 0x06, 0x10, 0xff, 0x51, 0xc6, 0x9b, 0x4d,
+0x55, 0x25, 0x4f, 0x93, 0x99, 0x10, 0x01, 0x53, 0x75, 0xf1, 0x13, 0xce, 0xc7, 0xa6, 0x41, 0x41,
+0xd2, 0xbf, 0x88, 0xa5, 0x7f, 0x45, 0xfc, 0xac, 0xb8, 0xa5, 0xb5, 0x33, 0x0c, 0x82, 0xc4, 0xfb,
+0x07, 0xf6, 0x6a, 0xe5, 0x25, 0x84, 0x5f, 0x06, 0xca, 0xc1, 0x86, 0x39, 0x11, 0xdb, 0x58, 0xcd,
+0x77, 0x3b, 0x2c, 0xc2, 0x4c, 0x0f, 0x5e, 0x9a, 0xe3, 0xf0, 0xab, 0x3e, 0x61, 0x1b, 0x50, 0x24,
+0xc2, 0xc0, 0xf4, 0xf1, 0x19, 0xf0, 0x11, 0x29, 0xb6, 0xa5, 0x18, 0x02, 0x9b, 0xd7, 0x63, 0x4c,
+0x70, 0x8c, 0x47, 0xa3, 0x03, 0x43, 0x5c, 0xb9, 0x5d, 0x46, 0xa0, 0x0d, 0x6f, 0xff, 0x59, 0x8e,
+0xbe, 0xdd, 0x9f, 0x72, 0xc3, 0x5b, 0x2b, 0xdf, 0x8c, 0x5b, 0xce, 0xe5, 0x0c, 0x46, 0x6c, 0x92,
+0xb2, 0x0a, 0xa3, 0x4c, 0x54, 0x42, 0x18, 0x15, 0x12, 0x18, 0xbd, 0xda, 0xfc, 0xba, 0x74, 0x6e,
+0xff, 0xc1, 0xb6, 0xa0, 0x64, 0xd8, 0xa9, 0x5f, 0x55, 0xae, 0x9f, 0x5c, 0x6a, 0x76, 0x96, 0xd8,
+0x73, 0x67, 0x87, 0xfb, 0x4d, 0x7f, 0x5c, 0xee, 0x69, 0xca, 0x73, 0x10, 0xfb, 0x8a, 0xa9, 0xfd,
+0x9e, 0xbd, 0x36, 0x38, 0x49, 0x49, 0x87, 0xf4, 0x0e, 0x14, 0xf0, 0xe9, 0x87, 0xb8, 0x3f, 0xa7,
+0x4f, 0x7a, 0x5a, 0x8e, 0x79, 0xd4, 0x93, 0xe4, 0xbb, 0x68, 0x52, 0x84, 0xac, 0x6c, 0xe9, 0xf3,
+0x98, 0x70, 0x55, 0x72, 0x32, 0xf9, 0x34, 0xab, 0x2b, 0x49, 0xb5, 0xcd, 0x20, 0x62, 0xe4, 0x3a,
+0x7a, 0x67, 0x63, 0xab, 0x96, 0xdc, 0x6d, 0xae, 0x97, 0xec, 0xfc, 0x9f, 0x76, 0x56, 0x88, 0x2e,
+0x66, 0xcf, 0x5b, 0xb6, 0xc9, 0xa4, 0xb0, 0xd7, 0x05, 0xba, 0xe1, 0x27, 0x2f, 0x93, 0xbb, 0x26,
+0x2a, 0xa2, 0x93, 0xb0, 0x1b, 0xf3, 0x8e, 0xbe, 0x1d, 0x40, 0xa3, 0xb9, 0x36, 0x8f, 0x3e, 0x82,
+0x1a, 0x1a, 0x5e, 0x88, 0xea, 0x50, 0xf8, 0x59, 0xe2, 0x83, 0x46, 0x29, 0x0b, 0xe3, 0x44, 0x5c,
+0xe1, 0x95, 0xb6, 0x69, 0x90, 0x9a, 0x14, 0x6f, 0x97, 0xae, 0x81, 0xcf, 0x68, 0xef, 0x99, 0x9a,
+0xbe, 0xb5, 0xe7, 0xe1, 0x7f, 0xf8, 0xfa, 0x13, 0x47, 0x16, 0x4c, 0xcc, 0x6d, 0x08, 0x40, 0xe7,
+0x8b, 0x78, 0x6f, 0x50, 0x82, 0x44, 0x50, 0x3f, 0x66, 0x06, 0x8a, 0xab, 0x43, 0x84, 0x56, 0x4a,
+0x0f, 0x20, 0x2d, 0x86, 0x0e, 0xf5, 0xd2, 0xdb, 0xd2, 0x7a, 0x8a, 0x4b, 0xcd, 0xa5, 0xe8, 0x4e,
+0xf1, 0x5e, 0x26, 0x25, 0x01, 0x59, 0x23, 0xa0, 0x7e, 0xd2, 0xf6, 0x7e, 0x21, 0x57, 0xd7, 0x27,
+0xbc, 0x15, 0x57, 0x4c, 0xa4, 0x46, 0xc1, 0xe0, 0x83, 0x1e, 0x0c, 0x4c, 0x4d, 0x1f, 0x4f, 0x06,
+0x19, 0xe2, 0xf9, 0xa8, 0xf4, 0x3a, 0x82, 0xa1, 0xb2, 0x79, 0x43, 0x79, 0xd6, 0xad, 0x6f, 0x7a,
+0x27, 0x90, 0x03, 0xa4, 0xea, 0x24, 0x87, 0x3f, 0xd9, 0xbd, 0xd9, 0xe9, 0xf2, 0x5f, 0x50, 0x49,
+0x1c, 0xee, 0xec, 0xd7, 0x2e, 0x30, 0x82, 0x04, 0x3e, 0x30, 0x82, 0x03, 0x26, 0xa0, 0x03, 0x02,
+0x01, 0x02, 0x02, 0x04, 0x4a, 0x53, 0x8c, 0x28, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xbe, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
+0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x65, 0x20, 0x77, 0x77,
+0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65,
+0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x45, 0x6e, 0x74,
+0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72,
+0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20,
+0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x29, 0x45,
+0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
+0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x37,
+0x30, 0x37, 0x31, 0x37, 0x32, 0x35, 0x35, 0x34, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31, 0x32, 0x30,
+0x37, 0x31, 0x37, 0x35, 0x35, 0x35, 0x34, 0x5a, 0x30, 0x81, 0xbe, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x65, 0x20, 0x77,
+0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c,
+0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03,
+0x55, 0x04, 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x45, 0x6e,
+0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f,
+0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65,
+0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x29,
+0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xba, 0x84, 0xb6, 0x72, 0xdb, 0x9e,
+0x0c, 0x6b, 0xe2, 0x99, 0xe9, 0x30, 0x01, 0xa7, 0x76, 0xea, 0x32, 0xb8, 0x95, 0x41, 0x1a, 0xc9,
+0xda, 0x61, 0x4e, 0x58, 0x72, 0xcf, 0xfe, 0xf6, 0x82, 0x79, 0xbf, 0x73, 0x61, 0x06, 0x0a, 0xa5,
+0x27, 0xd8, 0xb3, 0x5f, 0xd3, 0x45, 0x4e, 0x1c, 0x72, 0xd6, 0x4e, 0x32, 0xf2, 0x72, 0x8a, 0x0f,
+0xf7, 0x83, 0x19, 0xd0, 0x6a, 0x80, 0x80, 0x00, 0x45, 0x1e, 0xb0, 0xc7, 0xe7, 0x9a, 0xbf, 0x12,
+0x57, 0x27, 0x1c, 0xa3, 0x68, 0x2f, 0x0a, 0x87, 0xbd, 0x6a, 0x6b, 0x0e, 0x5e, 0x65, 0xf3, 0x1c,
+0x77, 0xd5, 0xd4, 0x85, 0x8d, 0x70, 0x21, 0xb4, 0xb3, 0x32, 0xe7, 0x8b, 0xa2, 0xd5, 0x86, 0x39,
+0x02, 0xb1, 0xb8, 0xd2, 0x47, 0xce, 0xe4, 0xc9, 0x49, 0xc4, 0x3b, 0xa7, 0xde, 0xfb, 0x54, 0x7d,
+0x57, 0xbe, 0xf0, 0xe8, 0x6e, 0xc2, 0x79, 0xb2, 0x3a, 0x0b, 0x55, 0xe2, 0x50, 0x98, 0x16, 0x32,
+0x13, 0x5c, 0x2f, 0x78, 0x56, 0xc1, 0xc2, 0x94, 0xb3, 0xf2, 0x5a, 0xe4, 0x27, 0x9a, 0x9f, 0x24,
+0xd7, 0xc6, 0xec, 0xd0, 0x9b, 0x25, 0x82, 0xe3, 0xcc, 0xc2, 0xc4, 0x45, 0xc5, 0x8c, 0x97, 0x7a,
+0x06, 0x6b, 0x2a, 0x11, 0x9f, 0xa9, 0x0a, 0x6e, 0x48, 0x3b, 0x6f, 0xdb, 0xd4, 0x11, 0x19, 0x42,
+0xf7, 0x8f, 0x07, 0xbf, 0xf5, 0x53, 0x5f, 0x9c, 0x3e, 0xf4, 0x17, 0x2c, 0xe6, 0x69, 0xac, 0x4e,
+0x32, 0x4c, 0x62, 0x77, 0xea, 0xb7, 0xe8, 0xe5, 0xbb, 0x34, 0xbc, 0x19, 0x8b, 0xae, 0x9c, 0x51,
+0xe7, 0xb7, 0x7e, 0xb5, 0x53, 0xb1, 0x33, 0x22, 0xe5, 0x6d, 0xcf, 0x70, 0x3c, 0x1a, 0xfa, 0xe2,
+0x9b, 0x67, 0xb6, 0x83, 0xf4, 0x8d, 0xa5, 0xaf, 0x62, 0x4c, 0x4d, 0xe0, 0x58, 0xac, 0x64, 0x34,
+0x12, 0x03, 0xf8, 0xb6, 0x8d, 0x94, 0x63, 0x24, 0xa4, 0x71, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6a,
+0x72, 0x26, 0x7a, 0xd0, 0x1e, 0xef, 0x7d, 0xe7, 0x3b, 0x69, 0x51, 0xd4, 0x6c, 0x8d, 0x9f, 0x90,
+0x12, 0x66, 0xab, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x79, 0x9f, 0x1d, 0x96, 0xc6, 0xb6, 0x79, 0x3f, 0x22,
+0x8d, 0x87, 0xd3, 0x87, 0x03, 0x04, 0x60, 0x6a, 0x6b, 0x9a, 0x2e, 0x59, 0x89, 0x73, 0x11, 0xac,
+0x43, 0xd1, 0xf5, 0x13, 0xff, 0x8d, 0x39, 0x2b, 0xc0, 0xf2, 0xbd, 0x4f, 0x70, 0x8c, 0xa9, 0x2f,
+0xea, 0x17, 0xc4, 0x0b, 0x54, 0x9e, 0xd4, 0x1b, 0x96, 0x98, 0x33, 0x3c, 0xa8, 0xad, 0x62, 0xa2,
+0x00, 0x76, 0xab, 0x59, 0x69, 0x6e, 0x06, 0x1d, 0x7e, 0xc4, 0xb9, 0x44, 0x8d, 0x98, 0xaf, 0x12,
+0xd4, 0x61, 0xdb, 0x0a, 0x19, 0x46, 0x47, 0xf3, 0xeb, 0xf7, 0x63, 0xc1, 0x40, 0x05, 0x40, 0xa5,
+0xd2, 0xb7, 0xf4, 0xb5, 0x9a, 0x36, 0xbf, 0xa9, 0x88, 0x76, 0x88, 0x04, 0x55, 0x04, 0x2b, 0x9c,
+0x87, 0x7f, 0x1a, 0x37, 0x3c, 0x7e, 0x2d, 0xa5, 0x1a, 0xd8, 0xd4, 0x89, 0x5e, 0xca, 0xbd, 0xac,
+0x3d, 0x6c, 0xd8, 0x6d, 0xaf, 0xd5, 0xf3, 0x76, 0x0f, 0xcd, 0x3b, 0x88, 0x38, 0x22, 0x9d, 0x6c,
+0x93, 0x9a, 0xc4, 0x3d, 0xbf, 0x82, 0x1b, 0x65, 0x3f, 0xa6, 0x0f, 0x5d, 0xaa, 0xfc, 0xe5, 0xb2,
+0x15, 0xca, 0xb5, 0xad, 0xc6, 0xbc, 0x3d, 0xd0, 0x84, 0xe8, 0xea, 0x06, 0x72, 0xb0, 0x4d, 0x39,
+0x32, 0x78, 0xbf, 0x3e, 0x11, 0x9c, 0x0b, 0xa4, 0x9d, 0x9a, 0x21, 0xf3, 0xf0, 0x9b, 0x0b, 0x30,
+0x78, 0xdb, 0xc1, 0xdc, 0x87, 0x43, 0xfe, 0xbc, 0x63, 0x9a, 0xca, 0xc5, 0xc2, 0x1c, 0xc9, 0xc7,
+0x8d, 0xff, 0x3b, 0x12, 0x58, 0x08, 0xe6, 0xb6, 0x3d, 0xec, 0x7a, 0x2c, 0x4e, 0xfb, 0x83, 0x96,
+0xce, 0x0c, 0x3c, 0x69, 0x87, 0x54, 0x73, 0xa4, 0x73, 0xc2, 0x93, 0xff, 0x51, 0x10, 0xac, 0x15,
+0x54, 0x01, 0xd8, 0xfc, 0x05, 0xb1, 0x89, 0xa1, 0x7f, 0x74, 0x83, 0x9a, 0x49, 0xd7, 0xdc, 0x4e,
+0x7b, 0x8a, 0x48, 0x6f, 0x8b, 0x45, 0xf6, 0x30, 0x82, 0x02, 0xf9, 0x30, 0x82, 0x02, 0x80, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x0d, 0x00, 0xa6, 0x8b, 0x79, 0x29, 0x00, 0x00, 0x00, 0x00, 0x50,
+0xd0, 0x91, 0xf9, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30,
+0x81, 0xbf, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73,
+0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x13, 0x1f, 0x53, 0x65, 0x65, 0x20, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73,
+0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d,
+0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20,
+0x32, 0x30, 0x31, 0x32, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e,
+0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x31,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2a, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52,
+0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x45, 0x43,
+0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31, 0x32, 0x31, 0x38, 0x31, 0x35, 0x32, 0x35, 0x33,
+0x36, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x32, 0x31, 0x38, 0x31, 0x35, 0x35, 0x35, 0x33, 0x36,
+0x5a, 0x30, 0x81, 0xbf, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72,
+0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x65, 0x20, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72,
+0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65,
+0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x30, 0x28, 0x63,
+0x29, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20,
+0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x33,
+0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2a, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20,
+0x45, 0x43, 0x31, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
+0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x84, 0x13, 0xc9, 0xd0, 0xba,
+0x6d, 0x41, 0x7b, 0xe2, 0x6c, 0xd0, 0xeb, 0x55, 0x5f, 0x66, 0x02, 0x1a, 0x24, 0xf4, 0x5b, 0x89,
+0x69, 0x47, 0xe3, 0xb8, 0xc2, 0x7d, 0xf1, 0xf2, 0x02, 0xc5, 0x9f, 0xa0, 0xf6, 0x5b, 0xd5, 0x8b,
+0x06, 0x19, 0x86, 0x4f, 0x53, 0x10, 0x6d, 0x07, 0x24, 0x27, 0xa1, 0xa0, 0xf8, 0xd5, 0x47, 0x19,
+0x61, 0x4c, 0x7d, 0xca, 0x93, 0x27, 0xea, 0x74, 0x0c, 0xef, 0x6f, 0x96, 0x09, 0xfe, 0x63, 0xec,
+0x70, 0x5d, 0x36, 0xad, 0x67, 0x77, 0xae, 0xc9, 0x9d, 0x7c, 0x55, 0x44, 0x3a, 0xa2, 0x63, 0x51,
+0x1f, 0xf5, 0xe3, 0x62, 0xd4, 0xa9, 0x47, 0x07, 0x3e, 0xcc, 0x20, 0xa3, 0x42, 0x30, 0x40, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb7, 0x63, 0xe7, 0x1a, 0xdd,
+0x8d, 0xe9, 0x08, 0xa6, 0x55, 0x83, 0xa4, 0xe0, 0x6a, 0x50, 0x41, 0x65, 0x11, 0x42, 0x49, 0x30,
+0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x67, 0x00, 0x30, 0x64,
+0x02, 0x30, 0x61, 0x79, 0xd8, 0xe5, 0x42, 0x47, 0xdf, 0x1c, 0xae, 0x53, 0x99, 0x17, 0xb6, 0x6f,
+0x1c, 0x7d, 0xe1, 0xbf, 0x11, 0x94, 0xd1, 0x03, 0x88, 0x75, 0xe4, 0x8d, 0x89, 0xa4, 0x8a, 0x77,
+0x46, 0xde, 0x6d, 0x61, 0xef, 0x02, 0xf5, 0xfb, 0xb5, 0xdf, 0xcc, 0xfe, 0x4e, 0xff, 0xfe, 0xa9,
+0xe6, 0xa7, 0x02, 0x30, 0x5b, 0x99, 0xd7, 0x85, 0x37, 0x06, 0xb5, 0x7b, 0x08, 0xfd, 0xeb, 0x27,
+0x8b, 0x4a, 0x94, 0xf9, 0xe1, 0xfa, 0xa7, 0x8e, 0x26, 0x08, 0xe8, 0x7c, 0x92, 0x68, 0x6d, 0x73,
+0xd8, 0x6f, 0x26, 0xac, 0x21, 0x02, 0xb8, 0x99, 0xb7, 0x26, 0x41, 0x5b, 0x25, 0x60, 0xae, 0xd0,
+0x48, 0x1a, 0xee, 0x06, 0x30, 0x82, 0x03, 0x38, 0x30, 0x82, 0x02, 0x20, 0xa0, 0x03, 0x02, 0x01,
+0x02, 0x02, 0x06, 0x20, 0x06, 0x05, 0x16, 0x70, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x3b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x52, 0x4f, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x13, 0x08, 0x63, 0x65, 0x72, 0x74, 0x53, 0x49, 0x47, 0x4e, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03,
+0x55, 0x04, 0x0b, 0x13, 0x10, 0x63, 0x65, 0x72, 0x74, 0x53, 0x49, 0x47, 0x4e, 0x20, 0x52, 0x4f,
+0x4f, 0x54, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x37, 0x30, 0x34, 0x31,
+0x37, 0x32, 0x30, 0x30, 0x34, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x37, 0x30, 0x34, 0x31, 0x37,
+0x32, 0x30, 0x30, 0x34, 0x5a, 0x30, 0x3b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x52, 0x4f, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x63,
+0x65, 0x72, 0x74, 0x53, 0x49, 0x47, 0x4e, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x13, 0x10, 0x63, 0x65, 0x72, 0x74, 0x53, 0x49, 0x47, 0x4e, 0x20, 0x52, 0x4f, 0x4f, 0x54, 0x20,
+0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
+0x01, 0x01, 0x00, 0xb7, 0x33, 0xb9, 0x7e, 0xc8, 0x25, 0x4a, 0x8e, 0xb5, 0xdb, 0xb4, 0x28, 0x1b,
+0xaa, 0x57, 0x90, 0xe8, 0xd1, 0x22, 0xd3, 0x64, 0xba, 0xd3, 0x93, 0xe8, 0xd4, 0xac, 0x86, 0x61,
+0x40, 0x6a, 0x60, 0x57, 0x68, 0x54, 0x84, 0x4d, 0xbc, 0x6a, 0x54, 0x02, 0x05, 0xff, 0xdf, 0x9b,
+0x9a, 0x2a, 0xae, 0x5d, 0x07, 0x8f, 0x4a, 0xc3, 0x28, 0x7f, 0xef, 0xfb, 0x2b, 0xfa, 0x79, 0xf1,
+0xc7, 0xad, 0xf0, 0x10, 0x53, 0x24, 0x90, 0x8b, 0x66, 0xc9, 0xa8, 0x88, 0xab, 0xaf, 0x5a, 0xa3,
+0x00, 0xe9, 0xbe, 0xba, 0x46, 0xee, 0x5b, 0x73, 0x7b, 0x2c, 0x17, 0x82, 0x81, 0x5e, 0x62, 0x2c,
+0xa1, 0x02, 0x65, 0xb3, 0xbd, 0xc5, 0x2b, 0x00, 0x7e, 0xc4, 0xfc, 0x03, 0x33, 0x57, 0x0d, 0xed,
+0xe2, 0xfa, 0xce, 0x5d, 0x45, 0xd6, 0x38, 0xcd, 0x35, 0xb6, 0xb2, 0xc1, 0xd0, 0x9c, 0x81, 0x4a,
+0xaa, 0xe4, 0xb2, 0x01, 0x5c, 0x1d, 0x8f, 0x5f, 0x99, 0xc4, 0xb1, 0xad, 0xdb, 0x88, 0x21, 0xeb,
+0x90, 0x08, 0x82, 0x80, 0xf3, 0x30, 0xa3, 0x43, 0xe6, 0x90, 0x82, 0xae, 0x55, 0x28, 0x49, 0xed,
+0x5b, 0xd7, 0xa9, 0x10, 0x38, 0x0e, 0xfe, 0x8f, 0x4c, 0x5b, 0x9b, 0x46, 0xea, 0x41, 0xf5, 0xb0,
+0x08, 0x74, 0xc3, 0xd0, 0x88, 0x33, 0xb6, 0x7c, 0xd7, 0x74, 0xdf, 0xdc, 0x84, 0xd1, 0x43, 0x0e,
+0x75, 0x39, 0xa1, 0x25, 0x40, 0x28, 0xea, 0x78, 0xcb, 0x0e, 0x2c, 0x2e, 0x39, 0x9d, 0x8c, 0x8b,
+0x6e, 0x16, 0x1c, 0x2f, 0x26, 0x82, 0x10, 0xe2, 0xe3, 0x65, 0x94, 0x0a, 0x04, 0xc0, 0x5e, 0xf7,
+0x5d, 0x5b, 0xf8, 0x10, 0xe2, 0xd0, 0xba, 0x7a, 0x4b, 0xfb, 0xde, 0x37, 0x00, 0x00, 0x1a, 0x5b,
+0x28, 0xe3, 0xd2, 0x9c, 0x73, 0x3e, 0x32, 0x87, 0x98, 0xa1, 0xc9, 0x51, 0x2f, 0xd7, 0xde, 0xac,
+0x33, 0xb3, 0x4f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03,
+0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0xc6, 0x30, 0x1d, 0x06,
+0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xe0, 0x8c, 0x9b, 0xdb, 0x25, 0x49, 0xb3, 0xf1,
+0x7c, 0x86, 0xd6, 0xb2, 0x42, 0x87, 0x0b, 0xd0, 0x6b, 0xa0, 0xd9, 0xe4, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+0x3e, 0xd2, 0x1c, 0x89, 0x2e, 0x35, 0xfc, 0xf8, 0x75, 0xdd, 0xe6, 0x7f, 0x65, 0x88, 0xf4, 0x72,
+0x4c, 0xc9, 0x2c, 0xd7, 0x32, 0x4e, 0xf3, 0xdd, 0x19, 0x79, 0x47, 0xbd, 0x8e, 0x3b, 0x5b, 0x93,
+0x0f, 0x50, 0x49, 0x24, 0x13, 0x6b, 0x14, 0x06, 0x72, 0xef, 0x09, 0xd3, 0xa1, 0xa1, 0xe3, 0x40,
+0x84, 0xc9, 0xe7, 0x18, 0x32, 0x74, 0x3c, 0x48, 0x6e, 0x0f, 0x9f, 0x4b, 0xd4, 0xf7, 0x1e, 0xd3,
+0x93, 0x86, 0x64, 0x54, 0x97, 0x63, 0x72, 0x50, 0xd5, 0x55, 0xcf, 0xfa, 0x20, 0x93, 0x02, 0xa2,
+0x9b, 0xc3, 0x23, 0x93, 0x4e, 0x16, 0x55, 0x76, 0xa0, 0x70, 0x79, 0x6d, 0xcd, 0x21, 0x1f, 0xcf,
+0x2f, 0x2d, 0xbc, 0x19, 0xe3, 0x88, 0x31, 0xf8, 0x59, 0x1a, 0x81, 0x09, 0xc8, 0x97, 0xa6, 0x74,
+0xc7, 0x60, 0xc4, 0x5b, 0xcc, 0x57, 0x8e, 0xb2, 0x75, 0xfd, 0x1b, 0x02, 0x09, 0xdb, 0x59, 0x6f,
+0x72, 0x93, 0x69, 0xf7, 0x31, 0x41, 0xd6, 0x88, 0x38, 0xbf, 0x87, 0xb2, 0xbd, 0x16, 0x79, 0xf9,
+0xaa, 0xe4, 0xbe, 0x88, 0x25, 0xdd, 0x61, 0x27, 0x23, 0x1c, 0xb5, 0x31, 0x07, 0x04, 0x36, 0xb4,
+0x1a, 0x90, 0xbd, 0xa0, 0x74, 0x71, 0x50, 0x89, 0x6d, 0xbc, 0x14, 0xe3, 0x0f, 0x86, 0xae, 0xf1,
+0xab, 0x3e, 0xc7, 0xa0, 0x09, 0xcc, 0xa3, 0x48, 0xd1, 0xe0, 0xdb, 0x64, 0xe7, 0x92, 0xb5, 0xcf,
+0xaf, 0x72, 0x43, 0x70, 0x8b, 0xf9, 0xc3, 0x84, 0x3c, 0x13, 0xaa, 0x7e, 0x92, 0x9b, 0x57, 0x53,
+0x93, 0xfa, 0x70, 0xc2, 0x91, 0x0e, 0x31, 0xf9, 0x9b, 0x67, 0x5d, 0xe9, 0x96, 0x38, 0x5e, 0x5f,
+0xb3, 0x73, 0x4e, 0x88, 0x15, 0x67, 0xde, 0x9e, 0x76, 0x10, 0x62, 0x20, 0xbe, 0x55, 0x69, 0x95,
+0x43, 0x00, 0x39, 0x4d, 0xf6, 0xee, 0xb0, 0x5a, 0x4e, 0x49, 0x44, 0x54, 0x58, 0x5f, 0x42, 0x83,
+0x30, 0x82, 0x03, 0xbb, 0x30, 0x82, 0x02, 0xa3, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x04,
+0x44, 0xc0, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+0x00, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x4c,
+0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x19, 0x55, 0x6e, 0x69, 0x7a, 0x65,
+0x74, 0x6f, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20,
+0x53, 0x2e, 0x41, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x43,
+0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x22, 0x30,
+0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43,
+0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x31, 0x30, 0x32, 0x32, 0x31, 0x32, 0x30, 0x37, 0x33,
+0x37, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x31, 0x32, 0x33, 0x31, 0x31, 0x32, 0x30, 0x37, 0x33, 0x37,
+0x5a, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50, 0x4c,
+0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x19, 0x55, 0x6e, 0x69, 0x7a, 0x65,
+0x74, 0x6f, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20,
+0x53, 0x2e, 0x41, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1e, 0x43,
+0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x22, 0x30,
+0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43, 0x65, 0x72, 0x74, 0x75, 0x6d, 0x20, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43,
+0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01,
+0x01, 0x00, 0xe3, 0xfb, 0x7d, 0xa3, 0x72, 0xba, 0xc2, 0xf0, 0xc9, 0x14, 0x87, 0xf5, 0x6b, 0x01,
+0x4e, 0xe1, 0x6e, 0x40, 0x07, 0xba, 0x6d, 0x27, 0x5d, 0x7f, 0xf7, 0x5b, 0x2d, 0xb3, 0x5a, 0xc7,
+0x51, 0x5f, 0xab, 0xa4, 0x32, 0xa6, 0x61, 0x87, 0xb6, 0x6e, 0x0f, 0x86, 0xd2, 0x30, 0x02, 0x97,
+0xf8, 0xd7, 0x69, 0x57, 0xa1, 0x18, 0x39, 0x5d, 0x6a, 0x64, 0x79, 0xc6, 0x01, 0x59, 0xac, 0x3c,
+0x31, 0x4a, 0x38, 0x7c, 0xd2, 0x04, 0xd2, 0x4b, 0x28, 0xe8, 0x20, 0x5f, 0x3b, 0x07, 0xa2, 0xcc,
+0x4d, 0x73, 0xdb, 0xf3, 0xae, 0x4f, 0xc7, 0x56, 0xd5, 0x5a, 0xa7, 0x96, 0x89, 0xfa, 0xf3, 0xab,
+0x68, 0xd4, 0x23, 0x86, 0x59, 0x27, 0xcf, 0x09, 0x27, 0xbc, 0xac, 0x6e, 0x72, 0x83, 0x1c, 0x30,
+0x72, 0xdf, 0xe0, 0xa2, 0xe9, 0xd2, 0xe1, 0x74, 0x75, 0x19, 0xbd, 0x2a, 0x9e, 0x7b, 0x15, 0x54,
+0x04, 0x1b, 0xd7, 0x43, 0x39, 0xad, 0x55, 0x28, 0xc5, 0xe2, 0x1a, 0xbb, 0xf4, 0xc0, 0xe4, 0xae,
+0x38, 0x49, 0x33, 0xcc, 0x76, 0x85, 0x9f, 0x39, 0x45, 0xd2, 0xa4, 0x9e, 0xf2, 0x12, 0x8c, 0x51,
+0xf8, 0x7c, 0xe4, 0x2d, 0x7f, 0xf5, 0xac, 0x5f, 0xeb, 0x16, 0x9f, 0xb1, 0x2d, 0xd1, 0xba, 0xcc,
+0x91, 0x42, 0x77, 0x4c, 0x25, 0xc9, 0x90, 0x38, 0x6f, 0xdb, 0xf0, 0xcc, 0xfb, 0x8e, 0x1e, 0x97,
+0x59, 0x3e, 0xd5, 0x60, 0x4e, 0xe6, 0x05, 0x28, 0xed, 0x49, 0x79, 0x13, 0x4b, 0xba, 0x48, 0xdb,
+0x2f, 0xf9, 0x72, 0xd3, 0x39, 0xca, 0xfe, 0x1f, 0xd8, 0x34, 0x72, 0xf5, 0xb4, 0x40, 0xcf, 0x31,
+0x01, 0xc3, 0xec, 0xde, 0x11, 0x2d, 0x17, 0x5d, 0x1f, 0xb8, 0x50, 0xd1, 0x5e, 0x19, 0xa7, 0x69,
+0xde, 0x07, 0x33, 0x28, 0xca, 0x50, 0x95, 0xf9, 0xa7, 0x54, 0xcb, 0x54, 0x86, 0x50, 0x45, 0xa9,
+0xf9, 0x49, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55,
+0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03,
+0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x08, 0x76, 0xcd, 0xcb, 0x07, 0xff, 0x24, 0xf6, 0xc5,
+0xcd, 0xed, 0xbb, 0x90, 0xbc, 0xe2, 0x84, 0x37, 0x46, 0x75, 0xf7, 0x30, 0x0e, 0x06, 0x03, 0x55,
+0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa6,
+0xa8, 0xad, 0x22, 0xce, 0x01, 0x3d, 0xa6, 0xa3, 0xff, 0x62, 0xd0, 0x48, 0x9d, 0x8b, 0x5e, 0x72,
+0xb0, 0x78, 0x44, 0xe3, 0xdc, 0x1c, 0xaf, 0x09, 0xfd, 0x23, 0x48, 0xfa, 0xbd, 0x2a, 0xc4, 0xb9,
+0x55, 0x04, 0xb5, 0x10, 0xa3, 0x8d, 0x27, 0xde, 0x0b, 0x82, 0x63, 0xd0, 0xee, 0xde, 0x0c, 0x37,
+0x79, 0x41, 0x5b, 0x22, 0xb2, 0xb0, 0x9a, 0x41, 0x5c, 0xa6, 0x70, 0xe0, 0xd4, 0xd0, 0x77, 0xcb,
+0x23, 0xd3, 0x00, 0xe0, 0x6c, 0x56, 0x2f, 0xe1, 0x69, 0x0d, 0x0d, 0xd9, 0xaa, 0xbf, 0x21, 0x81,
+0x50, 0xd9, 0x06, 0xa5, 0xa8, 0xff, 0x95, 0x37, 0xd0, 0xaa, 0xfe, 0xe2, 0xb3, 0xf5, 0x99, 0x2d,
+0x45, 0x84, 0x8a, 0xe5, 0x42, 0x09, 0xd7, 0x74, 0x02, 0x2f, 0xf7, 0x89, 0xd8, 0x99, 0xe9, 0xbc,
+0x27, 0xd4, 0x47, 0x8d, 0xba, 0x0d, 0x46, 0x1c, 0x77, 0xcf, 0x14, 0xa4, 0x1c, 0xb9, 0xa4, 0x31,
+0xc4, 0x9c, 0x28, 0x74, 0x03, 0x34, 0xff, 0x33, 0x19, 0x26, 0xa5, 0xe9, 0x0d, 0x74, 0xb7, 0x3e,
+0x97, 0xc6, 0x76, 0xe8, 0x27, 0x96, 0xa3, 0x66, 0xdd, 0xe1, 0xae, 0xf2, 0x41, 0x5b, 0xca, 0x98,
+0x56, 0x83, 0x73, 0x70, 0xe4, 0x86, 0x1a, 0xd2, 0x31, 0x41, 0xba, 0x2f, 0xbe, 0x2d, 0x13, 0x5a,
+0x76, 0x6f, 0x4e, 0xe8, 0x4e, 0x81, 0x0e, 0x3f, 0x5b, 0x03, 0x22, 0xa0, 0x12, 0xbe, 0x66, 0x58,
+0x11, 0x4a, 0xcb, 0x03, 0xc4, 0xb4, 0x2a, 0x2a, 0x2d, 0x96, 0x17, 0xe0, 0x39, 0x54, 0xbc, 0x48,
+0xd3, 0x76, 0x27, 0x9d, 0x9a, 0x2d, 0x06, 0xa6, 0xc9, 0xec, 0x39, 0xd2, 0xab, 0xdb, 0x9f, 0x9a,
+0x0b, 0x27, 0x02, 0x35, 0x29, 0xb1, 0x40, 0x95, 0xe7, 0xf9, 0xe8, 0x9c, 0x55, 0x88, 0x19, 0x46,
+0xd6, 0xb7, 0x34, 0xf5, 0x7e, 0xce, 0x39, 0x9a, 0xd9, 0x38, 0xf1, 0x51, 0xf7, 0x4f, 0x2c, 0x30,
+0x82, 0x04, 0x1d, 0x30, 0x82, 0x03, 0x05, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x4e, 0x81,
+0x2d, 0x8a, 0x82, 0x65, 0xe0, 0x0b, 0x02, 0xee, 0x3e, 0x35, 0x02, 0x46, 0xe5, 0x3d, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x81,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x30,
+0x19, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x12, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20,
+0x4d, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x73, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
+0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x64, 0x31, 0x1a, 0x30, 0x18,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41,
+0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x1e, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
+0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x32, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39,
+0x5a, 0x30, 0x81, 0x81, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
+0x42, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x12, 0x47, 0x72, 0x65, 0x61,
+0x74, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x73, 0x74, 0x65, 0x72, 0x31, 0x10,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x64,
+0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43, 0x4f, 0x4d, 0x4f, 0x44,
+0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x27, 0x30, 0x25,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1e, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x65,
+0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
+0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd0, 0x40, 0x8b, 0x8b, 0x72, 0xe3, 0x91, 0x1b, 0xf7, 0x51,
+0xc1, 0x1b, 0x54, 0x04, 0x98, 0xd3, 0xa9, 0xbf, 0xc1, 0xe6, 0x8a, 0x5d, 0x3b, 0x87, 0xfb, 0xbb,
+0x88, 0xce, 0x0d, 0xe3, 0x2f, 0x3f, 0x06, 0x96, 0xf0, 0xa2, 0x29, 0x50, 0x99, 0xae, 0xdb, 0x3b,
+0xa1, 0x57, 0xb0, 0x74, 0x51, 0x71, 0xcd, 0xed, 0x42, 0x91, 0x4d, 0x41, 0xfe, 0xa9, 0xc8, 0xd8,
+0x6a, 0x86, 0x77, 0x44, 0xbb, 0x59, 0x66, 0x97, 0x50, 0x5e, 0xb4, 0xd4, 0x2c, 0x70, 0x44, 0xcf,
+0xda, 0x37, 0x95, 0x42, 0x69, 0x3c, 0x30, 0xc4, 0x71, 0xb3, 0x52, 0xf0, 0x21, 0x4d, 0xa1, 0xd8,
+0xba, 0x39, 0x7c, 0x1c, 0x9e, 0xa3, 0x24, 0x9d, 0xf2, 0x83, 0x16, 0x98, 0xaa, 0x16, 0x7c, 0x43,
+0x9b, 0x15, 0x5b, 0xb7, 0xae, 0x34, 0x91, 0xfe, 0xd4, 0x62, 0x26, 0x18, 0x46, 0x9a, 0x3f, 0xeb,
+0xc1, 0xf9, 0xf1, 0x90, 0x57, 0xeb, 0xac, 0x7a, 0x0d, 0x8b, 0xdb, 0x72, 0x30, 0x6a, 0x66, 0xd5,
+0xe0, 0x46, 0xa3, 0x70, 0xdc, 0x68, 0xd9, 0xff, 0x04, 0x48, 0x89, 0x77, 0xde, 0xb5, 0xe9, 0xfb,
+0x67, 0x6d, 0x41, 0xe9, 0xbc, 0x39, 0xbd, 0x32, 0xd9, 0x62, 0x02, 0xf1, 0xb1, 0xa8, 0x3d, 0x6e,
+0x37, 0x9c, 0xe2, 0x2f, 0xe2, 0xd3, 0xa2, 0x26, 0x8b, 0xc6, 0xb8, 0x55, 0x43, 0x88, 0xe1, 0x23,
+0x3e, 0xa5, 0xd2, 0x24, 0x39, 0x6a, 0x47, 0xab, 0x00, 0xd4, 0xa1, 0xb3, 0xa9, 0x25, 0xfe, 0x0d,
+0x3f, 0xa7, 0x1d, 0xba, 0xd3, 0x51, 0xc1, 0x0b, 0xa4, 0xda, 0xac, 0x38, 0xef, 0x55, 0x50, 0x24,
+0x05, 0x65, 0x46, 0x93, 0x34, 0x4f, 0x2d, 0x8d, 0xad, 0xc6, 0xd4, 0x21, 0x19, 0xd2, 0x8e, 0xca,
+0x05, 0x61, 0x71, 0x07, 0x73, 0x47, 0xe5, 0x8a, 0x19, 0x12, 0xbd, 0x04, 0x4d, 0xce, 0x4e, 0x9c,
+0xa5, 0x48, 0xac, 0xbb, 0x26, 0xf7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0x8e, 0x30, 0x81,
+0x8b, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x0b, 0x58, 0xe5, 0x8b,
+0xc6, 0x4c, 0x15, 0x37, 0xa4, 0x40, 0xa9, 0x30, 0xa9, 0x21, 0xbe, 0x47, 0x36, 0x5a, 0x56, 0xff,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+0xff, 0x30, 0x49, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x42, 0x30, 0x40, 0x30, 0x3e, 0xa0, 0x3c,
+0xa0, 0x3a, 0x86, 0x38, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63,
+0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x4f, 0x4d, 0x4f,
+0x44, 0x4f, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41,
+0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+0x3e, 0x98, 0x9e, 0x9b, 0xf6, 0x1b, 0xe9, 0xd7, 0x39, 0xb7, 0x78, 0xae, 0x1d, 0x72, 0x18, 0x49,
+0xd3, 0x87, 0xe4, 0x43, 0x82, 0xeb, 0x3f, 0xc9, 0xaa, 0xf5, 0xa8, 0xb5, 0xef, 0x55, 0x7c, 0x21,
+0x52, 0x65, 0xf9, 0xd5, 0x0d, 0xe1, 0x6c, 0xf4, 0x3e, 0x8c, 0x93, 0x73, 0x91, 0x2e, 0x02, 0xc4,
+0x4e, 0x07, 0x71, 0x6f, 0xc0, 0x8f, 0x38, 0x61, 0x08, 0xa8, 0x1e, 0x81, 0x0a, 0xc0, 0x2f, 0x20,
+0x2f, 0x41, 0x8b, 0x91, 0xdc, 0x48, 0x45, 0xbc, 0xf1, 0xc6, 0xde, 0xba, 0x76, 0x6b, 0x33, 0xc8,
+0x00, 0x2d, 0x31, 0x46, 0x4c, 0xed, 0xe7, 0x9d, 0xcf, 0x88, 0x94, 0xff, 0x33, 0xc0, 0x56, 0xe8,
+0x24, 0x86, 0x26, 0xb8, 0xd8, 0x38, 0x38, 0xdf, 0x2a, 0x6b, 0xdd, 0x12, 0xcc, 0xc7, 0x3f, 0x47,
+0x17, 0x4c, 0xa2, 0xc2, 0x06, 0x96, 0x09, 0xd6, 0xdb, 0xfe, 0x3f, 0x3c, 0x46, 0x41, 0xdf, 0x58,
+0xe2, 0x56, 0x0f, 0x3c, 0x3b, 0xc1, 0x1c, 0x93, 0x35, 0xd9, 0x38, 0x52, 0xac, 0xee, 0xc8, 0xec,
+0x2e, 0x30, 0x4e, 0x94, 0x35, 0xb4, 0x24, 0x1f, 0x4b, 0x78, 0x69, 0xda, 0xf2, 0x02, 0x38, 0xcc,
+0x95, 0x52, 0x93, 0xf0, 0x70, 0x25, 0x59, 0x9c, 0x20, 0x67, 0xc4, 0xee, 0xf9, 0x8b, 0x57, 0x61,
+0xf4, 0x92, 0x76, 0x7d, 0x3f, 0x84, 0x8d, 0x55, 0xb7, 0xe8, 0xe5, 0xac, 0xd5, 0xf1, 0xf5, 0x19,
+0x56, 0xa6, 0x5a, 0xfb, 0x90, 0x1c, 0xaf, 0x93, 0xeb, 0xe5, 0x1c, 0xd4, 0x67, 0x97, 0x5d, 0x04,
+0x0e, 0xbe, 0x0b, 0x83, 0xa6, 0x17, 0x83, 0xb9, 0x30, 0x12, 0xa0, 0xc5, 0x33, 0x15, 0x05, 0xb9,
+0x0d, 0xfb, 0xc7, 0x05, 0x76, 0xe3, 0xd8, 0x4a, 0x8d, 0xfc, 0x34, 0x17, 0xa3, 0xc6, 0x21, 0x28,
+0xbe, 0x30, 0x45, 0x31, 0x1e, 0xc7, 0x78, 0xbe, 0x58, 0x61, 0x38, 0xac, 0x3b, 0xe2, 0x01, 0x65,
+0x30, 0x82, 0x03, 0xa1, 0x30, 0x82, 0x02, 0x89, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0b, 0x04,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x85, 0xaa, 0x2d, 0x48, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x3b, 0x31, 0x18, 0x30, 0x16, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74,
+0x2c, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16,
+0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61,
+0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x32, 0x31, 0x35,
+0x30, 0x38, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x32, 0x31, 0x35, 0x30,
+0x38, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x3b, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x0f, 0x43, 0x79, 0x62, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49,
+0x6e, 0x63, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x43, 0x79, 0x62,
+0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52,
+0x6f, 0x6f, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
+0x82, 0x01, 0x01, 0x00, 0xf8, 0xc8, 0xbc, 0xbd, 0x14, 0x50, 0x66, 0x13, 0xff, 0xf0, 0xd3, 0x79,
+0xec, 0x23, 0xf2, 0xb7, 0x1a, 0xc7, 0x8e, 0x85, 0xf1, 0x12, 0x73, 0xa6, 0x19, 0xaa, 0x10, 0xdb,
+0x9c, 0xa2, 0x65, 0x74, 0x5a, 0x77, 0x3e, 0x51, 0x7d, 0x56, 0xf6, 0xdc, 0x23, 0xb6, 0xd4, 0xed,
+0x5f, 0x58, 0xb1, 0x37, 0x4d, 0xd5, 0x49, 0x0e, 0x6e, 0xf5, 0x6a, 0x87, 0xd6, 0xd2, 0x8c, 0xd2,
+0x27, 0xc6, 0xe2, 0xff, 0x36, 0x9f, 0x98, 0x65, 0xa0, 0x13, 0x4e, 0xc6, 0x2a, 0x64, 0x9b, 0xd5,
+0x90, 0x12, 0xcf, 0x14, 0x06, 0xf4, 0x3b, 0xe3, 0xd4, 0x28, 0xbe, 0xe8, 0x0e, 0xf8, 0xab, 0x4e,
+0x48, 0x94, 0x6d, 0x8e, 0x95, 0x31, 0x10, 0x5c, 0xed, 0xa2, 0x2d, 0xbd, 0xd5, 0x3a, 0x6d, 0xb2,
+0x1c, 0xbb, 0x60, 0xc0, 0x46, 0x4b, 0x01, 0xf5, 0x49, 0xae, 0x7e, 0x46, 0x8a, 0xd0, 0x74, 0x8d,
+0xa1, 0x0c, 0x02, 0xce, 0xee, 0xfc, 0xe7, 0x8f, 0xb8, 0x6b, 0x66, 0xf3, 0x7f, 0x44, 0x00, 0xbf,
+0x66, 0x25, 0x14, 0x2b, 0xdd, 0x10, 0x30, 0x1d, 0x07, 0x96, 0x3f, 0x4d, 0xf6, 0x6b, 0xb8, 0x8f,
+0xb7, 0x7b, 0x0c, 0xa5, 0x38, 0xeb, 0xde, 0x47, 0xdb, 0xd5, 0x5d, 0x39, 0xfc, 0x88, 0xa7, 0xf3,
+0xd7, 0x2a, 0x74, 0xf1, 0xe8, 0x5a, 0xa2, 0x3b, 0x9f, 0x50, 0xba, 0xa6, 0x8c, 0x45, 0x35, 0xc2,
+0x50, 0x65, 0x95, 0xdc, 0x63, 0x82, 0xef, 0xdd, 0xbf, 0x77, 0x4d, 0x9c, 0x62, 0xc9, 0x63, 0x73,
+0x16, 0xd0, 0x29, 0x0f, 0x49, 0xa9, 0x48, 0xf0, 0xb3, 0xaa, 0xb7, 0x6c, 0xc5, 0xa7, 0x30, 0x39,
+0x40, 0x5d, 0xae, 0xc4, 0xe2, 0x5d, 0x26, 0x53, 0xf0, 0xce, 0x1c, 0x23, 0x08, 0x61, 0xa8, 0x94,
+0x19, 0xba, 0x04, 0x62, 0x40, 0xec, 0x1f, 0x38, 0x70, 0x77, 0x12, 0x06, 0x71, 0xa7, 0x30, 0x18,
+0x5d, 0x25, 0x27, 0xa5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa5, 0x30, 0x81, 0xa2, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb6, 0x08, 0x7b, 0x0d, 0x7a,
+0xcc, 0xac, 0x20, 0x4c, 0x86, 0x56, 0x32, 0x5e, 0xcf, 0xab, 0x6e, 0x85, 0x2d, 0x70, 0x57, 0x30,
+0x3f, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x38, 0x30, 0x36, 0x30, 0x34, 0xa0, 0x32, 0xa0, 0x30,
+0x86, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x32, 0x2e, 0x70, 0x75,
+0x62, 0x6c, 0x69, 0x63, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
+0x72, 0x6c, 0x2f, 0x63, 0x74, 0x2f, 0x63, 0x74, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c,
+0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb6, 0x08, 0x7b,
+0x0d, 0x7a, 0xcc, 0xac, 0x20, 0x4c, 0x86, 0x56, 0x32, 0x5e, 0xcf, 0xab, 0x6e, 0x85, 0x2d, 0x70,
+0x57, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+0x03, 0x82, 0x01, 0x01, 0x00, 0x56, 0xef, 0x0a, 0x23, 0xa0, 0x54, 0x4e, 0x95, 0x97, 0xc9, 0xf8,
+0x89, 0xda, 0x45, 0xc1, 0xd4, 0xa3, 0x00, 0x25, 0xf4, 0x1f, 0x13, 0xab, 0xb7, 0xa3, 0x85, 0x58,
+0x69, 0xc2, 0x30, 0xad, 0xd8, 0x15, 0x8a, 0x2d, 0xe3, 0xc9, 0xcd, 0x81, 0x5a, 0xf8, 0x73, 0x23,
+0x5a, 0xa7, 0x7c, 0x05, 0xf3, 0xfd, 0x22, 0x3b, 0x0e, 0xd1, 0x06, 0xc4, 0xdb, 0x36, 0x4c, 0x73,
+0x04, 0x8e, 0xe5, 0xb0, 0x22, 0xe4, 0xc5, 0xf3, 0x2e, 0xa5, 0xd9, 0x23, 0xe3, 0xb8, 0x4e, 0x4a,
+0x20, 0xa7, 0x6e, 0x02, 0x24, 0x9f, 0x22, 0x60, 0x67, 0x7b, 0x8b, 0x1d, 0x72, 0x09, 0xc5, 0x31,
+0x5c, 0xe9, 0x79, 0x9f, 0x80, 0x47, 0x3d, 0xad, 0xa1, 0x0b, 0x07, 0x14, 0x3d, 0x47, 0xff, 0x03,
+0x69, 0x1a, 0x0c, 0x0b, 0x44, 0xe7, 0x63, 0x25, 0xa7, 0x7f, 0xb2, 0xc9, 0xb8, 0x76, 0x84, 0xed,
+0x23, 0xf6, 0x7d, 0x07, 0xab, 0x45, 0x7e, 0xd3, 0xdf, 0xb3, 0xbf, 0xe9, 0x8a, 0xb6, 0xcd, 0xa8,
+0xa2, 0x67, 0x2b, 0x52, 0xd5, 0xb7, 0x65, 0xf0, 0x39, 0x4c, 0x63, 0xa0, 0x91, 0x79, 0x93, 0x52,
+0x0f, 0x54, 0xdd, 0x83, 0xbb, 0x9f, 0xd1, 0x8f, 0xa7, 0x53, 0x73, 0xc3, 0xcb, 0xff, 0x30, 0xec,
+0x7c, 0x04, 0xb8, 0xd8, 0x44, 0x1f, 0x93, 0x5f, 0x71, 0x09, 0x22, 0xb7, 0x6e, 0x3e, 0xea, 0x1c,
+0x03, 0x4e, 0x9d, 0x1a, 0x20, 0x61, 0xfb, 0x81, 0x37, 0xec, 0x5e, 0xfc, 0x0a, 0x45, 0xab, 0xd7,
+0xe7, 0x17, 0x55, 0xd0, 0xa0, 0xea, 0x60, 0x9b, 0xa6, 0xf6, 0xe3, 0x8c, 0x5b, 0x29, 0xc2, 0x06,
+0x60, 0x14, 0x9d, 0x2d, 0x97, 0x4c, 0xa9, 0x93, 0x15, 0x9d, 0x61, 0xc4, 0x01, 0x5f, 0x48, 0xd6,
+0x58, 0xbd, 0x56, 0x31, 0x12, 0x4e, 0x11, 0xc8, 0x21, 0xe0, 0xb3, 0x11, 0x91, 0x65, 0xdb, 0xb4,
+0xa6, 0x88, 0x38, 0xce, 0x55, 0x30, 0x82, 0x02, 0x89, 0x30, 0x82, 0x02, 0x0f, 0xa0, 0x03, 0x02,
+0x01, 0x02, 0x02, 0x10, 0x1f, 0x47, 0xaf, 0xaa, 0x62, 0x00, 0x70, 0x50, 0x54, 0x4c, 0x01, 0x9e,
+0x9b, 0x63, 0x99, 0x2a, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03,
+0x30, 0x81, 0x85, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42,
+0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x12, 0x47, 0x72, 0x65, 0x61, 0x74,
+0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x73, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x64, 0x31,
+0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f,
+0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x2b, 0x30, 0x29, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x45, 0x43, 0x43,
+0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
+0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33,
+0x30, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31,
+0x38, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0x85, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
+0x08, 0x13, 0x12, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x63, 0x68,
+0x65, 0x73, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07,
+0x53, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x13, 0x11, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, 0x20, 0x4c, 0x69, 0x6d, 0x69,
+0x74, 0x65, 0x64, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x43, 0x4f,
+0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x45, 0x43, 0x43, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
+0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x03, 0x47, 0x7b, 0x2f, 0x75, 0xc9, 0x82, 0x15,
+0x85, 0xfb, 0x75, 0xe4, 0x91, 0x16, 0xd4, 0xab, 0x62, 0x99, 0xf5, 0x3e, 0x52, 0x0b, 0x06, 0xce,
+0x41, 0x00, 0x7f, 0x97, 0xe1, 0x0a, 0x24, 0x3c, 0x1d, 0x01, 0x04, 0xee, 0x3d, 0xd2, 0x8d, 0x09,
+0x97, 0x0c, 0xe0, 0x75, 0xe4, 0xfa, 0xfb, 0x77, 0x8a, 0x2a, 0xf5, 0x03, 0x60, 0x4b, 0x36, 0x8b,
+0x16, 0x23, 0x16, 0xad, 0x09, 0x71, 0xf4, 0x4a, 0xf4, 0x28, 0x50, 0xb4, 0xfe, 0x88, 0x1c, 0x6e,
+0x3f, 0x6c, 0x2f, 0x2f, 0x09, 0x59, 0x5b, 0xa5, 0x5b, 0x0b, 0x33, 0x99, 0xe2, 0xc3, 0x3d, 0x89,
+0xf9, 0x6a, 0x2c, 0xef, 0xb2, 0xd3, 0x06, 0xe9, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03,
+0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x75, 0x71, 0xa7, 0x19, 0x48, 0x19, 0xbc, 0x9d, 0x9d,
+0xea, 0x41, 0x47, 0xdf, 0x94, 0xc4, 0x48, 0x77, 0x99, 0xd3, 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55,
+0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55,
+0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06, 0x08,
+0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x31, 0x00,
+0xef, 0x03, 0x5b, 0x7a, 0xac, 0xb7, 0x78, 0x0a, 0x72, 0xb7, 0x88, 0xdf, 0xff, 0xb5, 0x46, 0x14,
+0x09, 0x0a, 0xfa, 0xa0, 0xe6, 0x7d, 0x08, 0xc6, 0x1a, 0x87, 0xbd, 0x18, 0xa8, 0x73, 0xbd, 0x26,
+0xca, 0x60, 0x0c, 0x9d, 0xce, 0x99, 0x9f, 0xcf, 0x5c, 0x0f, 0x30, 0xe1, 0xbe, 0x14, 0x31, 0xea,
+0x02, 0x30, 0x14, 0xf4, 0x93, 0x3c, 0x49, 0xa7, 0x33, 0x7a, 0x90, 0x46, 0x47, 0xb3, 0x63, 0x7d,
+0x13, 0x9b, 0x4e, 0xb7, 0x6f, 0x18, 0x37, 0x80, 0x53, 0xfe, 0xdd, 0x20, 0xe0, 0x35, 0x9a, 0x36,
+0xd1, 0xc7, 0x01, 0xb9, 0xe6, 0xdc, 0xdd, 0xf3, 0xff, 0x1d, 0x2c, 0x3a, 0x16, 0x57, 0xd9, 0x92,
+0x39, 0xd6, 0x30, 0x82, 0x03, 0xb7, 0x30, 0x82, 0x02, 0x9f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+0x10, 0x0c, 0xe7, 0xe0, 0xe5, 0x17, 0xd8, 0x46, 0xfe, 0x8f, 0xe5, 0x60, 0xfc, 0x1b, 0xf0, 0x30,
+0x39, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65,
+0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f,
+0x6d, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1b, 0x44, 0x69, 0x67, 0x69,
+0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x31,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x31, 0x31, 0x31, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, 0x30,
+0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69,
+0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x1b, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75,
+0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82,
+0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xad,
+0x0e, 0x15, 0xce, 0xe4, 0x43, 0x80, 0x5c, 0xb1, 0x87, 0xf3, 0xb7, 0x60, 0xf9, 0x71, 0x12, 0xa5,
+0xae, 0xdc, 0x26, 0x94, 0x88, 0xaa, 0xf4, 0xce, 0xf5, 0x20, 0x39, 0x28, 0x58, 0x60, 0x0c, 0xf8,
+0x80, 0xda, 0xa9, 0x15, 0x95, 0x32, 0x61, 0x3c, 0xb5, 0xb1, 0x28, 0x84, 0x8a, 0x8a, 0xdc, 0x9f,
+0x0a, 0x0c, 0x83, 0x17, 0x7a, 0x8f, 0x90, 0xac, 0x8a, 0xe7, 0x79, 0x53, 0x5c, 0x31, 0x84, 0x2a,
+0xf6, 0x0f, 0x98, 0x32, 0x36, 0x76, 0xcc, 0xde, 0xdd, 0x3c, 0xa8, 0xa2, 0xef, 0x6a, 0xfb, 0x21,
+0xf2, 0x52, 0x61, 0xdf, 0x9f, 0x20, 0xd7, 0x1f, 0xe2, 0xb1, 0xd9, 0xfe, 0x18, 0x64, 0xd2, 0x12,
+0x5b, 0x5f, 0xf9, 0x58, 0x18, 0x35, 0xbc, 0x47, 0xcd, 0xa1, 0x36, 0xf9, 0x6b, 0x7f, 0xd4, 0xb0,
+0x38, 0x3e, 0xc1, 0x1b, 0xc3, 0x8c, 0x33, 0xd9, 0xd8, 0x2f, 0x18, 0xfe, 0x28, 0x0f, 0xb3, 0xa7,
+0x83, 0xd6, 0xc3, 0x6e, 0x44, 0xc0, 0x61, 0x35, 0x96, 0x16, 0xfe, 0x59, 0x9c, 0x8b, 0x76, 0x6d,
+0xd7, 0xf1, 0xa2, 0x4b, 0x0d, 0x2b, 0xff, 0x0b, 0x72, 0xda, 0x9e, 0x60, 0xd0, 0x8e, 0x90, 0x35,
+0xc6, 0x78, 0x55, 0x87, 0x20, 0xa1, 0xcf, 0xe5, 0x6d, 0x0a, 0xc8, 0x49, 0x7c, 0x31, 0x98, 0x33,
+0x6c, 0x22, 0xe9, 0x87, 0xd0, 0x32, 0x5a, 0xa2, 0xba, 0x13, 0x82, 0x11, 0xed, 0x39, 0x17, 0x9d,
+0x99, 0x3a, 0x72, 0xa1, 0xe6, 0xfa, 0xa4, 0xd9, 0xd5, 0x17, 0x31, 0x75, 0xae, 0x85, 0x7d, 0x22,
+0xae, 0x3f, 0x01, 0x46, 0x86, 0xf6, 0x28, 0x79, 0xc8, 0xb1, 0xda, 0xe4, 0x57, 0x17, 0xc4, 0x7e,
+0x1c, 0x0e, 0xb0, 0xb4, 0x92, 0xa6, 0x56, 0xb3, 0xbd, 0xb2, 0x97, 0xed, 0xaa, 0xa7, 0xf0, 0xb7,
+0xc5, 0xa8, 0x3f, 0x95, 0x16, 0xd0, 0xff, 0xa1, 0x96, 0xeb, 0x08, 0x5f, 0x18, 0x77, 0x4f, 0x02,
+0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+0x04, 0x16, 0x04, 0x14, 0x45, 0xeb, 0xa2, 0xaf, 0xf4, 0x92, 0xcb, 0x82, 0x31, 0x2d, 0x51, 0x8b,
+0xa7, 0xa7, 0x21, 0x9d, 0xf3, 0x6d, 0xc8, 0x0f, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+0x18, 0x30, 0x16, 0x80, 0x14, 0x45, 0xeb, 0xa2, 0xaf, 0xf4, 0x92, 0xcb, 0x82, 0x31, 0x2d, 0x51,
+0x8b, 0xa7, 0xa7, 0x21, 0x9d, 0xf3, 0x6d, 0xc8, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa2, 0x0e, 0xbc,
+0xdf, 0xe2, 0xed, 0xf0, 0xe3, 0x72, 0x73, 0x7a, 0x64, 0x94, 0xbf, 0xf7, 0x72, 0x66, 0xd8, 0x32,
+0xe4, 0x42, 0x75, 0x62, 0xae, 0x87, 0xeb, 0xf2, 0xd5, 0xd9, 0xde, 0x56, 0xb3, 0x9f, 0xcc, 0xce,
+0x14, 0x28, 0xb9, 0x0d, 0x97, 0x60, 0x5c, 0x12, 0x4c, 0x58, 0xe4, 0xd3, 0x3d, 0x83, 0x49, 0x45,
+0x58, 0x97, 0x35, 0x69, 0x1a, 0xa8, 0x47, 0xea, 0x56, 0xc6, 0x79, 0xab, 0x12, 0xd8, 0x67, 0x81,
+0x84, 0xdf, 0x7f, 0x09, 0x3c, 0x94, 0xe6, 0xb8, 0x26, 0x2c, 0x20, 0xbd, 0x3d, 0xb3, 0x28, 0x89,
+0xf7, 0x5f, 0xff, 0x22, 0xe2, 0x97, 0x84, 0x1f, 0xe9, 0x65, 0xef, 0x87, 0xe0, 0xdf, 0xc1, 0x67,
+0x49, 0xb3, 0x5d, 0xeb, 0xb2, 0x09, 0x2a, 0xeb, 0x26, 0xed, 0x78, 0xbe, 0x7d, 0x3f, 0x2b, 0xf3,
+0xb7, 0x26, 0x35, 0x6d, 0x5f, 0x89, 0x01, 0xb6, 0x49, 0x5b, 0x9f, 0x01, 0x05, 0x9b, 0xab, 0x3d,
+0x25, 0xc1, 0xcc, 0xb6, 0x7f, 0xc2, 0xf1, 0x6f, 0x86, 0xc6, 0xfa, 0x64, 0x68, 0xeb, 0x81, 0x2d,
+0x94, 0xeb, 0x42, 0xb7, 0xfa, 0x8c, 0x1e, 0xdd, 0x62, 0xf1, 0xbe, 0x50, 0x67, 0xb7, 0x6c, 0xbd,
+0xf3, 0xf1, 0x1f, 0x6b, 0x0c, 0x36, 0x07, 0x16, 0x7f, 0x37, 0x7c, 0xa9, 0x5b, 0x6d, 0x7a, 0xf1,
+0x12, 0x46, 0x60, 0x83, 0xd7, 0x27, 0x04, 0xbe, 0x4b, 0xce, 0x97, 0xbe, 0xc3, 0x67, 0x2a, 0x68,
+0x11, 0xdf, 0x80, 0xe7, 0x0c, 0x33, 0x66, 0xbf, 0x13, 0x0d, 0x14, 0x6e, 0xf3, 0x7f, 0x1f, 0x63,
+0x10, 0x1e, 0xfa, 0x8d, 0x1b, 0x25, 0x6d, 0x6c, 0x8f, 0xa5, 0xb7, 0x61, 0x01, 0xb1, 0xd2, 0xa3,
+0x26, 0xa1, 0x10, 0x71, 0x9d, 0xad, 0xe2, 0xc3, 0xf9, 0xc3, 0x99, 0x51, 0xb7, 0x2b, 0x07, 0x08,
+0xce, 0x2e, 0xe6, 0x50, 0xb2, 0xa7, 0xfa, 0x0a, 0x45, 0x2f, 0xa2, 0xf0, 0xf2, 0x30, 0x82, 0x03,
+0x96, 0x30, 0x82, 0x02, 0x7e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x0b, 0x93, 0x1c, 0x3a,
+0xd6, 0x39, 0x67, 0xea, 0x67, 0x23, 0xbf, 0xc3, 0xaf, 0x9a, 0xf4, 0x4b, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x65, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e,
+0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e,
+0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x24, 0x30, 0x22,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1b, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20,
+0x41, 0x73, 0x73, 0x75, 0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x38, 0x30, 0x31, 0x31, 0x32, 0x30, 0x30,
+0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31, 0x35, 0x31, 0x32, 0x30, 0x30, 0x30,
+0x30, 0x5a, 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69,
+0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04,
+0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
+0x63, 0x6f, 0x6d, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1b, 0x44, 0x69,
+0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, 0x64, 0x20, 0x49,
+0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd9, 0xe7, 0x28, 0x2f, 0x52, 0x3f,
+0x36, 0x72, 0x49, 0x88, 0x93, 0x34, 0xf3, 0xf8, 0x6a, 0x1e, 0x31, 0x54, 0x80, 0x9f, 0xad, 0x54,
+0x41, 0xb5, 0x47, 0xdf, 0x96, 0xa8, 0xd4, 0xaf, 0x80, 0x2d, 0xb9, 0x0a, 0xcf, 0x75, 0xfd, 0x89,
+0xa5, 0x7d, 0x24, 0xfa, 0xe3, 0x22, 0x0c, 0x2b, 0xbc, 0x95, 0x17, 0x0b, 0x33, 0xbf, 0x19, 0x4d,
+0x41, 0x06, 0x90, 0x00, 0xbd, 0x0c, 0x4d, 0x10, 0xfe, 0x07, 0xb5, 0xe7, 0x1c, 0x6e, 0x22, 0x55,
+0x31, 0x65, 0x97, 0xbd, 0xd3, 0x17, 0xd2, 0x1e, 0x62, 0xf3, 0xdb, 0xea, 0x6c, 0x50, 0x8c, 0x3f,
+0x84, 0x0c, 0x96, 0xcf, 0xb7, 0xcb, 0x03, 0xe0, 0xca, 0x6d, 0xa1, 0x14, 0x4c, 0x1b, 0x89, 0xdd,
+0xed, 0x00, 0xb0, 0x52, 0x7c, 0xaf, 0x91, 0x6c, 0xb1, 0x38, 0x13, 0xd1, 0xe9, 0x12, 0x08, 0xc0,
+0x00, 0xb0, 0x1c, 0x2b, 0x11, 0xda, 0x77, 0x70, 0x36, 0x9b, 0xae, 0xce, 0x79, 0x87, 0xdc, 0x82,
+0x70, 0xe6, 0x09, 0x74, 0x70, 0x55, 0x69, 0xaf, 0xa3, 0x68, 0x9f, 0xbf, 0xdd, 0xb6, 0x79, 0xb3,
+0xf2, 0x9d, 0x70, 0x29, 0x55, 0xf4, 0xab, 0xff, 0x95, 0x61, 0xf3, 0xc9, 0x40, 0x6f, 0x1d, 0xd1,
+0xbe, 0x93, 0xbb, 0xd3, 0x88, 0x2a, 0xbb, 0x9d, 0xbf, 0x72, 0x5a, 0x56, 0x71, 0x3b, 0x3f, 0xd4,
+0xf3, 0xd1, 0x0a, 0xfe, 0x28, 0xef, 0xa3, 0xee, 0xd9, 0x99, 0xaf, 0x03, 0xd3, 0x8f, 0x60, 0xb7,
+0xf2, 0x92, 0xa1, 0xb1, 0xbd, 0x89, 0x89, 0x1f, 0x30, 0xcd, 0xc3, 0xa6, 0x2e, 0x62, 0x33, 0xae,
+0x16, 0x02, 0x77, 0x44, 0x5a, 0xe7, 0x81, 0x0a, 0x3c, 0xa7, 0x44, 0x2e, 0x79, 0xb8, 0x3f, 0x04,
+0xbc, 0x5c, 0xa0, 0x87, 0xe1, 0x1b, 0xaf, 0x51, 0x8e, 0xcd, 0xec, 0x2c, 0xfa, 0xf8, 0xfe, 0x6d,
+0xf0, 0x3a, 0x7c, 0xaa, 0x8b, 0xe4, 0x67, 0x95, 0x31, 0x8d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xce,
+0xc3, 0x4a, 0xb9, 0x99, 0x55, 0xf2, 0xb8, 0xdb, 0x60, 0xbf, 0xa9, 0x7e, 0xbd, 0x56, 0xb5, 0x97,
+0x36, 0xa7, 0xd6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xca, 0xa5, 0x55, 0x8c, 0xe3, 0xc8, 0x41, 0x6e, 0x69,
+0x27, 0xa7, 0x75, 0x11, 0xef, 0x3c, 0x86, 0x36, 0x6f, 0xd2, 0x9d, 0xc6, 0x78, 0x38, 0x1d, 0x69,
+0x96, 0xa2, 0x92, 0x69, 0x2e, 0x38, 0x6c, 0x9b, 0x7d, 0x04, 0xd4, 0x89, 0xa5, 0xb1, 0x31, 0x37,
+0x8a, 0xc9, 0x21, 0xcc, 0xab, 0x6c, 0xcd, 0x8b, 0x1c, 0x9a, 0xd6, 0xbf, 0x48, 0xd2, 0x32, 0x66,
+0xc1, 0x8a, 0xc0, 0xf3, 0x2f, 0x3a, 0xef, 0xc0, 0xe3, 0xd4, 0x91, 0x86, 0xd1, 0x50, 0xe3, 0x03,
+0xdb, 0x73, 0x77, 0x6f, 0x4a, 0x39, 0x53, 0xed, 0xde, 0x26, 0xc7, 0xb5, 0x7d, 0xaf, 0x2b, 0x42,
+0xd1, 0x75, 0x62, 0xe3, 0x4a, 0x2b, 0x02, 0xc7, 0x50, 0x4b, 0xe0, 0x69, 0xe2, 0x96, 0x6c, 0x0e,
+0x44, 0x66, 0x10, 0x44, 0x8f, 0xad, 0x05, 0xeb, 0xf8, 0x79, 0xac, 0xa6, 0x1b, 0xe8, 0x37, 0x34,
+0x9d, 0x53, 0xc9, 0x61, 0xaa, 0xa2, 0x52, 0xaf, 0x4a, 0x70, 0x16, 0x86, 0xc2, 0x3a, 0xc8, 0xb1,
+0x13, 0x70, 0x36, 0xd8, 0xcf, 0xee, 0xf4, 0x0a, 0x34, 0xd5, 0x5b, 0x4c, 0xfd, 0x07, 0x9c, 0xa2,
+0xba, 0xd9, 0x01, 0x72, 0x5c, 0xf3, 0x4d, 0xc1, 0xdd, 0x0e, 0xb1, 0x1c, 0x0d, 0xc4, 0x63, 0xbe,
+0xad, 0xf4, 0x14, 0xfb, 0x89, 0xec, 0xa2, 0x41, 0x0e, 0x4c, 0xcc, 0xc8, 0x57, 0x40, 0xd0, 0x6e,
+0x03, 0xaa, 0xcd, 0x0c, 0x8e, 0x89, 0x99, 0x99, 0x6c, 0xf0, 0x3c, 0x30, 0xaf, 0x38, 0xdf, 0x6f,
+0xbc, 0xa3, 0xbe, 0x29, 0x20, 0x27, 0xab, 0x74, 0xff, 0x13, 0x22, 0x78, 0xde, 0x97, 0x52, 0x55,
+0x1e, 0x83, 0xb5, 0x54, 0x20, 0x03, 0xee, 0xae, 0xc0, 0x4f, 0x56, 0xde, 0x37, 0xcc, 0xc3, 0x7f,
+0xaa, 0x04, 0x27, 0xbb, 0xd3, 0x77, 0xb8, 0x62, 0xdb, 0x17, 0x7c, 0x9c, 0x28, 0x22, 0x13, 0x73,
+0x6c, 0xcf, 0x26, 0xf5, 0x8a, 0x29, 0xe7, 0x30, 0x82, 0x03, 0xaf, 0x30, 0x82, 0x02, 0x97, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x08, 0x3b, 0xe0, 0x56, 0x90, 0x42, 0x46, 0xb1, 0xa1, 0x75,
+0x6a, 0xc9, 0x59, 0x91, 0xc7, 0x4a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x61, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44,
+0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06,
+0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65,
+0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31,
+0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x31, 0x31, 0x31,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x61, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19,
+0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67,
+0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f,
+0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
+0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe2, 0x3b, 0xe1, 0x11,
+0x72, 0xde, 0xa8, 0xa4, 0xd3, 0xa3, 0x57, 0xaa, 0x50, 0xa2, 0x8f, 0x0b, 0x77, 0x90, 0xc9, 0xa2,
+0xa5, 0xee, 0x12, 0xce, 0x96, 0x5b, 0x01, 0x09, 0x20, 0xcc, 0x01, 0x93, 0xa7, 0x4e, 0x30, 0xb7,
+0x53, 0xf7, 0x43, 0xc4, 0x69, 0x00, 0x57, 0x9d, 0xe2, 0x8d, 0x22, 0xdd, 0x87, 0x06, 0x40, 0x00,
+0x81, 0x09, 0xce, 0xce, 0x1b, 0x83, 0xbf, 0xdf, 0xcd, 0x3b, 0x71, 0x46, 0xe2, 0xd6, 0x66, 0xc7,
+0x05, 0xb3, 0x76, 0x27, 0x16, 0x8f, 0x7b, 0x9e, 0x1e, 0x95, 0x7d, 0xee, 0xb7, 0x48, 0xa3, 0x08,
+0xda, 0xd6, 0xaf, 0x7a, 0x0c, 0x39, 0x06, 0x65, 0x7f, 0x4a, 0x5d, 0x1f, 0xbc, 0x17, 0xf8, 0xab,
+0xbe, 0xee, 0x28, 0xd7, 0x74, 0x7f, 0x7a, 0x78, 0x99, 0x59, 0x85, 0x68, 0x6e, 0x5c, 0x23, 0x32,
+0x4b, 0xbf, 0x4e, 0xc0, 0xe8, 0x5a, 0x6d, 0xe3, 0x70, 0xbf, 0x77, 0x10, 0xbf, 0xfc, 0x01, 0xf6,
+0x85, 0xd9, 0xa8, 0x44, 0x10, 0x58, 0x32, 0xa9, 0x75, 0x18, 0xd5, 0xd1, 0xa2, 0xbe, 0x47, 0xe2,
+0x27, 0x6a, 0xf4, 0x9a, 0x33, 0xf8, 0x49, 0x08, 0x60, 0x8b, 0xd4, 0x5f, 0xb4, 0x3a, 0x84, 0xbf,
+0xa1, 0xaa, 0x4a, 0x4c, 0x7d, 0x3e, 0xcf, 0x4f, 0x5f, 0x6c, 0x76, 0x5e, 0xa0, 0x4b, 0x37, 0x91,
+0x9e, 0xdc, 0x22, 0xe6, 0x6d, 0xce, 0x14, 0x1a, 0x8e, 0x6a, 0xcb, 0xfe, 0xcd, 0xb3, 0x14, 0x64,
+0x17, 0xc7, 0x5b, 0x29, 0x9e, 0x32, 0xbf, 0xf2, 0xee, 0xfa, 0xd3, 0x0b, 0x42, 0xd4, 0xab, 0xb7,
+0x41, 0x32, 0xda, 0x0c, 0xd4, 0xef, 0xf8, 0x81, 0xd5, 0xbb, 0x8d, 0x58, 0x3f, 0xb5, 0x1b, 0xe8,
+0x49, 0x28, 0xa2, 0x70, 0xda, 0x31, 0x04, 0xdd, 0xf7, 0xb2, 0x16, 0xf2, 0x4c, 0x0a, 0x4e, 0x07,
+0xa8, 0xed, 0x4a, 0x3d, 0x5e, 0xb5, 0x7f, 0xa3, 0x90, 0xc3, 0xaf, 0x27, 0x02, 0x03, 0x01, 0x00,
+0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+0x14, 0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, 0x66, 0xf0, 0xa3, 0xe2, 0x1b, 0x1b, 0xc3,
+0x97, 0xb2, 0x3d, 0xd1, 0x55, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+0x80, 0x14, 0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, 0x66, 0xf0, 0xa3, 0xe2, 0x1b, 0x1b,
+0xc3, 0x97, 0xb2, 0x3d, 0xd1, 0x55, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xcb, 0x9c, 0x37, 0xaa, 0x48, 0x13,
+0x12, 0x0a, 0xfa, 0xdd, 0x44, 0x9c, 0x4f, 0x52, 0xb0, 0xf4, 0xdf, 0xae, 0x04, 0xf5, 0x79, 0x79,
+0x08, 0xa3, 0x24, 0x18, 0xfc, 0x4b, 0x2b, 0x84, 0xc0, 0x2d, 0xb9, 0xd5, 0xc7, 0xfe, 0xf4, 0xc1,
+0x1f, 0x58, 0xcb, 0xb8, 0x6d, 0x9c, 0x7a, 0x74, 0xe7, 0x98, 0x29, 0xab, 0x11, 0xb5, 0xe3, 0x70,
+0xa0, 0xa1, 0xcd, 0x4c, 0x88, 0x99, 0x93, 0x8c, 0x91, 0x70, 0xe2, 0xab, 0x0f, 0x1c, 0xbe, 0x93,
+0xa9, 0xff, 0x63, 0xd5, 0xe4, 0x07, 0x60, 0xd3, 0xa3, 0xbf, 0x9d, 0x5b, 0x09, 0xf1, 0xd5, 0x8e,
+0xe3, 0x53, 0xf4, 0x8e, 0x63, 0xfa, 0x3f, 0xa7, 0xdb, 0xb4, 0x66, 0xdf, 0x62, 0x66, 0xd6, 0xd1,
+0x6e, 0x41, 0x8d, 0xf2, 0x2d, 0xb5, 0xea, 0x77, 0x4a, 0x9f, 0x9d, 0x58, 0xe2, 0x2b, 0x59, 0xc0,
+0x40, 0x23, 0xed, 0x2d, 0x28, 0x82, 0x45, 0x3e, 0x79, 0x54, 0x92, 0x26, 0x98, 0xe0, 0x80, 0x48,
+0xa8, 0x37, 0xef, 0xf0, 0xd6, 0x79, 0x60, 0x16, 0xde, 0xac, 0xe8, 0x0e, 0xcd, 0x6e, 0xac, 0x44,
+0x17, 0x38, 0x2f, 0x49, 0xda, 0xe1, 0x45, 0x3e, 0x2a, 0xb9, 0x36, 0x53, 0xcf, 0x3a, 0x50, 0x06,
+0xf7, 0x2e, 0xe8, 0xc4, 0x57, 0x49, 0x6c, 0x61, 0x21, 0x18, 0xd5, 0x04, 0xad, 0x78, 0x3c, 0x2c,
+0x3a, 0x80, 0x6b, 0xa7, 0xeb, 0xaf, 0x15, 0x14, 0xe9, 0xd8, 0x89, 0xc1, 0xb9, 0x38, 0x6c, 0xe2,
+0x91, 0x6c, 0x8a, 0xff, 0x64, 0xb9, 0x77, 0x25, 0x57, 0x30, 0xc0, 0x1b, 0x24, 0xa3, 0xe1, 0xdc,
+0xe9, 0xdf, 0x47, 0x7c, 0xb5, 0xb4, 0x24, 0x08, 0x05, 0x30, 0xec, 0x2d, 0xbd, 0x0b, 0xbf, 0x45,
+0xbf, 0x50, 0xb9, 0xa9, 0xf3, 0xeb, 0x98, 0x01, 0x12, 0xad, 0xc8, 0x88, 0xc6, 0x98, 0x34, 0x5f,
+0x8d, 0x0a, 0x3c, 0xc6, 0xe9, 0xd5, 0x95, 0x95, 0x6d, 0xde, 0x30, 0x82, 0x03, 0x8e, 0x30, 0x82,
+0x02, 0x76, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x03, 0x3a, 0xf1, 0xe6, 0xa7, 0x11, 0xa9,
+0xa0, 0xbb, 0x28, 0x64, 0xb1, 0x1d, 0x09, 0xfa, 0xe5, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x61, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19,
+0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67,
+0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f,
+0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+0x33, 0x30, 0x38, 0x30, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38,
+0x30, 0x31, 0x31, 0x35, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x61, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e,
+0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e,
+0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20,
+0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x32, 0x30, 0x82,
+0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbb,
+0x37, 0xcd, 0x34, 0xdc, 0x7b, 0x6b, 0xc9, 0xb2, 0x68, 0x90, 0xad, 0x4a, 0x75, 0xff, 0x46, 0xba,
+0x21, 0x0a, 0x08, 0x8d, 0xf5, 0x19, 0x54, 0xc9, 0xfb, 0x88, 0xdb, 0xf3, 0xae, 0xf2, 0x3a, 0x89,
+0x91, 0x3c, 0x7a, 0xe6, 0xab, 0x06, 0x1a, 0x6b, 0xcf, 0xac, 0x2d, 0xe8, 0x5e, 0x09, 0x24, 0x44,
+0xba, 0x62, 0x9a, 0x7e, 0xd6, 0xa3, 0xa8, 0x7e, 0xe0, 0x54, 0x75, 0x20, 0x05, 0xac, 0x50, 0xb7,
+0x9c, 0x63, 0x1a, 0x6c, 0x30, 0xdc, 0xda, 0x1f, 0x19, 0xb1, 0xd7, 0x1e, 0xde, 0xfd, 0xd7, 0xe0,
+0xcb, 0x94, 0x83, 0x37, 0xae, 0xec, 0x1f, 0x43, 0x4e, 0xdd, 0x7b, 0x2c, 0xd2, 0xbd, 0x2e, 0xa5,
+0x2f, 0xe4, 0xa9, 0xb8, 0xad, 0x3a, 0xd4, 0x99, 0xa4, 0xb6, 0x25, 0xe9, 0x9b, 0x6b, 0x00, 0x60,
+0x92, 0x60, 0xff, 0x4f, 0x21, 0x49, 0x18, 0xf7, 0x67, 0x90, 0xab, 0x61, 0x06, 0x9c, 0x8f, 0xf2,
+0xba, 0xe9, 0xb4, 0xe9, 0x92, 0x32, 0x6b, 0xb5, 0xf3, 0x57, 0xe8, 0x5d, 0x1b, 0xcd, 0x8c, 0x1d,
+0xab, 0x95, 0x04, 0x95, 0x49, 0xf3, 0x35, 0x2d, 0x96, 0xe3, 0x49, 0x6d, 0xdd, 0x77, 0xe3, 0xfb,
+0x49, 0x4b, 0xb4, 0xac, 0x55, 0x07, 0xa9, 0x8f, 0x95, 0xb3, 0xb4, 0x23, 0xbb, 0x4c, 0x6d, 0x45,
+0xf0, 0xf6, 0xa9, 0xb2, 0x95, 0x30, 0xb4, 0xfd, 0x4c, 0x55, 0x8c, 0x27, 0x4a, 0x57, 0x14, 0x7c,
+0x82, 0x9d, 0xcd, 0x73, 0x92, 0xd3, 0x16, 0x4a, 0x06, 0x0c, 0x8c, 0x50, 0xd1, 0x8f, 0x1e, 0x09,
+0xbe, 0x17, 0xa1, 0xe6, 0x21, 0xca, 0xfd, 0x83, 0xe5, 0x10, 0xbc, 0x83, 0xa5, 0x0a, 0xc4, 0x67,
+0x28, 0xf6, 0x73, 0x14, 0x14, 0x3d, 0x46, 0x76, 0xc3, 0x87, 0x14, 0x89, 0x21, 0x34, 0x4d, 0xaf,
+0x0f, 0x45, 0x0c, 0xa6, 0x49, 0xa1, 0xba, 0xbb, 0x9c, 0xc5, 0xb1, 0x33, 0x83, 0x29, 0x85, 0x02,
+0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+0x04, 0x16, 0x04, 0x14, 0x4e, 0x22, 0x54, 0x20, 0x18, 0x95, 0xe6, 0xe3, 0x6e, 0xe6, 0x0f, 0xfa,
+0xfa, 0xb9, 0x12, 0xed, 0x06, 0x17, 0x8f, 0x39, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x60, 0x67, 0x28, 0x94,
+0x6f, 0x0e, 0x48, 0x63, 0xeb, 0x31, 0xdd, 0xea, 0x67, 0x18, 0xd5, 0x89, 0x7d, 0x3c, 0xc5, 0x8b,
+0x4a, 0x7f, 0xe9, 0xbe, 0xdb, 0x2b, 0x17, 0xdf, 0xb0, 0x5f, 0x73, 0x77, 0x2a, 0x32, 0x13, 0x39,
+0x81, 0x67, 0x42, 0x84, 0x23, 0xf2, 0x45, 0x67, 0x35, 0xec, 0x88, 0xbf, 0xf8, 0x8f, 0xb0, 0x61,
+0x0c, 0x34, 0xa4, 0xae, 0x20, 0x4c, 0x84, 0xc6, 0xdb, 0xf8, 0x35, 0xe1, 0x76, 0xd9, 0xdf, 0xa6,
+0x42, 0xbb, 0xc7, 0x44, 0x08, 0x86, 0x7f, 0x36, 0x74, 0x24, 0x5a, 0xda, 0x6c, 0x0d, 0x14, 0x59,
+0x35, 0xbd, 0xf2, 0x49, 0xdd, 0xb6, 0x1f, 0xc9, 0xb3, 0x0d, 0x47, 0x2a, 0x3d, 0x99, 0x2f, 0xbb,
+0x5c, 0xbb, 0xb5, 0xd4, 0x20, 0xe1, 0x99, 0x5f, 0x53, 0x46, 0x15, 0xdb, 0x68, 0x9b, 0xf0, 0xf3,
+0x30, 0xd5, 0x3e, 0x31, 0xe2, 0x8d, 0x84, 0x9e, 0xe3, 0x8a, 0xda, 0xda, 0x96, 0x3e, 0x35, 0x13,
+0xa5, 0x5f, 0xf0, 0xf9, 0x70, 0x50, 0x70, 0x47, 0x41, 0x11, 0x57, 0x19, 0x4e, 0xc0, 0x8f, 0xae,
+0x06, 0xc4, 0x95, 0x13, 0x17, 0x2f, 0x1b, 0x25, 0x9f, 0x75, 0xf2, 0xb1, 0x8e, 0x99, 0xa1, 0x6f,
+0x13, 0xb1, 0x41, 0x71, 0xfe, 0x88, 0x2a, 0xc8, 0x4f, 0x10, 0x20, 0x55, 0xd7, 0xf3, 0x14, 0x45,
+0xe5, 0xe0, 0x44, 0xf4, 0xea, 0x87, 0x95, 0x32, 0x93, 0x0e, 0xfe, 0x53, 0x46, 0xfa, 0x2c, 0x9d,
+0xff, 0x8b, 0x22, 0xb9, 0x4b, 0xd9, 0x09, 0x45, 0xa4, 0xde, 0xa4, 0xb8, 0x9a, 0x58, 0xdd, 0x1b,
+0x7d, 0x52, 0x9f, 0x8e, 0x59, 0x43, 0x88, 0x81, 0xa4, 0x9e, 0x26, 0xd5, 0x6f, 0xad, 0xdd, 0x0d,
+0xc6, 0x37, 0x7d, 0xed, 0x03, 0x92, 0x1b, 0xe5, 0x77, 0x5f, 0x76, 0xee, 0x3c, 0x8d, 0xc4, 0x5d,
+0x56, 0x5b, 0xa2, 0xd9, 0x66, 0x6e, 0xb3, 0x35, 0x37, 0xe5, 0x32, 0xb6, 0x30, 0x82, 0x02, 0x3f,
+0x30, 0x82, 0x01, 0xc5, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x05, 0x55, 0x56, 0xbc, 0xf2,
+0x5e, 0xa4, 0x35, 0x35, 0xc3, 0xa4, 0x0f, 0xd5, 0xab, 0x45, 0x72, 0x30, 0x0a, 0x06, 0x08, 0x2a,
+0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x61, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, 0x30,
+0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69,
+0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62,
+0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33,
+0x30, 0x38, 0x30, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30,
+0x31, 0x31, 0x35, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x61, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63,
+0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64,
+0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47,
+0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x33, 0x30, 0x76, 0x30,
+0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
+0x22, 0x03, 0x62, 0x00, 0x04, 0xdd, 0xa7, 0xd9, 0xbb, 0x8a, 0xb8, 0x0b, 0xfb, 0x0b, 0x7f, 0x21,
+0xd2, 0xf0, 0xbe, 0xbe, 0x73, 0xf3, 0x33, 0x5d, 0x1a, 0xbc, 0x34, 0xea, 0xde, 0xc6, 0x9b, 0xbc,
+0xd0, 0x95, 0xf6, 0xf0, 0xcc, 0xd0, 0x0b, 0xba, 0x61, 0x5b, 0x51, 0x46, 0x7e, 0x9e, 0x2d, 0x9f,
+0xee, 0x8e, 0x63, 0x0c, 0x17, 0xec, 0x07, 0x70, 0xf5, 0xcf, 0x84, 0x2e, 0x40, 0x83, 0x9c, 0xe8,
+0x3f, 0x41, 0x6d, 0x3b, 0xad, 0xd3, 0xa4, 0x14, 0x59, 0x36, 0x78, 0x9d, 0x03, 0x43, 0xee, 0x10,
+0x13, 0x6c, 0x72, 0xde, 0xae, 0x88, 0xa7, 0xa1, 0x6b, 0xb5, 0x43, 0xce, 0x67, 0xdc, 0x23, 0xff,
+0x03, 0x1c, 0xa3, 0xe2, 0x3e, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13,
+0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+0x0e, 0x04, 0x16, 0x04, 0x14, 0xb3, 0xdb, 0x48, 0xa4, 0xf9, 0xa1, 0xc5, 0xd8, 0xae, 0x36, 0x41,
+0xcc, 0x11, 0x63, 0x69, 0x62, 0x29, 0xbc, 0x4b, 0xc6, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
+0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x31, 0x00, 0xad, 0xbc, 0xf2,
+0x6c, 0x3f, 0x12, 0x4a, 0xd1, 0x2d, 0x39, 0xc3, 0x0a, 0x09, 0x97, 0x73, 0xf4, 0x88, 0x36, 0x8c,
+0x88, 0x27, 0xbb, 0xe6, 0x88, 0x8d, 0x50, 0x85, 0xa7, 0x63, 0xf9, 0x9e, 0x32, 0xde, 0x66, 0x93,
+0x0f, 0xf1, 0xcc, 0xb1, 0x09, 0x8f, 0xdd, 0x6c, 0xab, 0xfa, 0x6b, 0x7f, 0xa0, 0x02, 0x30, 0x39,
+0x66, 0x5b, 0xc2, 0x64, 0x8d, 0xb8, 0x9e, 0x50, 0xdc, 0xa8, 0xd5, 0x49, 0xa2, 0xed, 0xc7, 0xdc,
+0xd1, 0x49, 0x7f, 0x17, 0x01, 0xb8, 0xc8, 0x86, 0x8f, 0x4e, 0x8c, 0x88, 0x2b, 0xa8, 0x9a, 0xa9,
+0x8a, 0xc5, 0xd1, 0x00, 0xbd, 0xf8, 0x54, 0xe2, 0x9a, 0xe5, 0x5b, 0x7c, 0xb3, 0x27, 0x17, 0x30,
+0x82, 0x03, 0xc5, 0x30, 0x82, 0x02, 0xad, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x02, 0xac,
+0x5c, 0x26, 0x6a, 0x0b, 0x40, 0x9b, 0x8f, 0x0b, 0x79, 0xf2, 0xae, 0x46, 0x25, 0x77, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x6c, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20,
+0x49, 0x6e, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77,
+0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x2b,
+0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72,
+0x74, 0x20, 0x48, 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65,
+0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30,
+0x36, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31,
+0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6c, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e,
+0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e,
+0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20,
+0x48, 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x45,
+0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc6, 0xcc, 0xe5, 0x73, 0xe6, 0xfb,
+0xd4, 0xbb, 0xe5, 0x2d, 0x2d, 0x32, 0xa6, 0xdf, 0xe5, 0x81, 0x3f, 0xc9, 0xcd, 0x25, 0x49, 0xb6,
+0x71, 0x2a, 0xc3, 0xd5, 0x94, 0x34, 0x67, 0xa2, 0x0a, 0x1c, 0xb0, 0x5f, 0x69, 0xa6, 0x40, 0xb1,
+0xc4, 0xb7, 0xb2, 0x8f, 0xd0, 0x98, 0xa4, 0xa9, 0x41, 0x59, 0x3a, 0xd3, 0xdc, 0x94, 0xd6, 0x3c,
+0xdb, 0x74, 0x38, 0xa4, 0x4a, 0xcc, 0x4d, 0x25, 0x82, 0xf7, 0x4a, 0xa5, 0x53, 0x12, 0x38, 0xee,
+0xf3, 0x49, 0x6d, 0x71, 0x91, 0x7e, 0x63, 0xb6, 0xab, 0xa6, 0x5f, 0xc3, 0xa4, 0x84, 0xf8, 0x4f,
+0x62, 0x51, 0xbe, 0xf8, 0xc5, 0xec, 0xdb, 0x38, 0x92, 0xe3, 0x06, 0xe5, 0x08, 0x91, 0x0c, 0xc4,
+0x28, 0x41, 0x55, 0xfb, 0xcb, 0x5a, 0x89, 0x15, 0x7e, 0x71, 0xe8, 0x35, 0xbf, 0x4d, 0x72, 0x09,
+0x3d, 0xbe, 0x3a, 0x38, 0x50, 0x5b, 0x77, 0x31, 0x1b, 0x8d, 0xb3, 0xc7, 0x24, 0x45, 0x9a, 0xa7,
+0xac, 0x6d, 0x00, 0x14, 0x5a, 0x04, 0xb7, 0xba, 0x13, 0xeb, 0x51, 0x0a, 0x98, 0x41, 0x41, 0x22,
+0x4e, 0x65, 0x61, 0x87, 0x81, 0x41, 0x50, 0xa6, 0x79, 0x5c, 0x89, 0xde, 0x19, 0x4a, 0x57, 0xd5,
+0x2e, 0xe6, 0x5d, 0x1c, 0x53, 0x2c, 0x7e, 0x98, 0xcd, 0x1a, 0x06, 0x16, 0xa4, 0x68, 0x73, 0xd0,
+0x34, 0x04, 0x13, 0x5c, 0xa1, 0x71, 0xd3, 0x5a, 0x7c, 0x55, 0xdb, 0x5e, 0x64, 0xe1, 0x37, 0x87,
+0x30, 0x56, 0x04, 0xe5, 0x11, 0xb4, 0x29, 0x80, 0x12, 0xf1, 0x79, 0x39, 0x88, 0xa2, 0x02, 0x11,
+0x7c, 0x27, 0x66, 0xb7, 0x88, 0xb7, 0x78, 0xf2, 0xca, 0x0a, 0xa8, 0x38, 0xab, 0x0a, 0x64, 0xc2,
+0xbf, 0x66, 0x5d, 0x95, 0x84, 0xc1, 0xa1, 0x25, 0x1e, 0x87, 0x5d, 0x1a, 0x50, 0x0b, 0x20, 0x12,
+0xcc, 0x41, 0xbb, 0x6e, 0x0b, 0x51, 0x38, 0xb8, 0x4b, 0xcb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+0x63, 0x30, 0x61, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1,
+0x3e, 0xc3, 0x69, 0x03, 0xf8, 0xbf, 0x47, 0x01, 0xd4, 0x98, 0x26, 0x1a, 0x08, 0x02, 0xef, 0x63,
+0x64, 0x2b, 0xc3, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+0xb1, 0x3e, 0xc3, 0x69, 0x03, 0xf8, 0xbf, 0x47, 0x01, 0xd4, 0x98, 0x26, 0x1a, 0x08, 0x02, 0xef,
+0x63, 0x64, 0x2b, 0xc3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x1c, 0x1a, 0x06, 0x97, 0xdc, 0xd7, 0x9c, 0x9f,
+0x3c, 0x88, 0x66, 0x06, 0x08, 0x57, 0x21, 0xdb, 0x21, 0x47, 0xf8, 0x2a, 0x67, 0xaa, 0xbf, 0x18,
+0x32, 0x76, 0x40, 0x10, 0x57, 0xc1, 0x8a, 0xf3, 0x7a, 0xd9, 0x11, 0x65, 0x8e, 0x35, 0xfa, 0x9e,
+0xfc, 0x45, 0xb5, 0x9e, 0xd9, 0x4c, 0x31, 0x4b, 0xb8, 0x91, 0xe8, 0x43, 0x2c, 0x8e, 0xb3, 0x78,
+0xce, 0xdb, 0xe3, 0x53, 0x79, 0x71, 0xd6, 0xe5, 0x21, 0x94, 0x01, 0xda, 0x55, 0x87, 0x9a, 0x24,
+0x64, 0xf6, 0x8a, 0x66, 0xcc, 0xde, 0x9c, 0x37, 0xcd, 0xa8, 0x34, 0xb1, 0x69, 0x9b, 0x23, 0xc8,
+0x9e, 0x78, 0x22, 0x2b, 0x70, 0x43, 0xe3, 0x55, 0x47, 0x31, 0x61, 0x19, 0xef, 0x58, 0xc5, 0x85,
+0x2f, 0x4e, 0x30, 0xf6, 0xa0, 0x31, 0x16, 0x23, 0xc8, 0xe7, 0xe2, 0x65, 0x16, 0x33, 0xcb, 0xbf,
+0x1a, 0x1b, 0xa0, 0x3d, 0xf8, 0xca, 0x5e, 0x8b, 0x31, 0x8b, 0x60, 0x08, 0x89, 0x2d, 0x0c, 0x06,
+0x5c, 0x52, 0xb7, 0xc4, 0xf9, 0x0a, 0x98, 0xd1, 0x15, 0x5f, 0x9f, 0x12, 0xbe, 0x7c, 0x36, 0x63,
+0x38, 0xbd, 0x44, 0xa4, 0x7f, 0xe4, 0x26, 0x2b, 0x0a, 0xc4, 0x97, 0x69, 0x0d, 0xe9, 0x8c, 0xe2,
+0xc0, 0x10, 0x57, 0xb8, 0xc8, 0x76, 0x12, 0x91, 0x55, 0xf2, 0x48, 0x69, 0xd8, 0xbc, 0x2a, 0x02,
+0x5b, 0x0f, 0x44, 0xd4, 0x20, 0x31, 0xdb, 0xf4, 0xba, 0x70, 0x26, 0x5d, 0x90, 0x60, 0x9e, 0xbc,
+0x4b, 0x17, 0x09, 0x2f, 0xb4, 0xcb, 0x1e, 0x43, 0x68, 0xc9, 0x07, 0x27, 0xc1, 0xd2, 0x5c, 0xf7,
+0xea, 0x21, 0xb9, 0x68, 0x12, 0x9c, 0x3c, 0x9c, 0xbf, 0x9e, 0xfc, 0x80, 0x5c, 0x9b, 0x63, 0xcd,
+0xec, 0x47, 0xaa, 0x25, 0x27, 0x67, 0xa0, 0x37, 0xf3, 0x00, 0x82, 0x7d, 0x54, 0xd7, 0xa9, 0xf8,
+0xe9, 0x2e, 0x13, 0xa3, 0x77, 0xe8, 0x1f, 0x4a, 0x30, 0x82, 0x05, 0x90, 0x30, 0x82, 0x03, 0x78,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x05, 0x9b, 0x1b, 0x57, 0x9e, 0x8e, 0x21, 0x32, 0xe2,
+0x39, 0x07, 0xbd, 0xa7, 0x77, 0x75, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c,
+0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, 0x30, 0x17,
+0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63,
+0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x18, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
+0x65, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x34, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33,
+0x30, 0x38, 0x30, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30,
+0x31, 0x31, 0x35, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x62, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63,
+0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64,
+0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x34, 0x30, 0x82,
+0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xbf,
+0xe6, 0x90, 0x73, 0x68, 0xde, 0xbb, 0xe4, 0x5d, 0x4a, 0x3c, 0x30, 0x22, 0x30, 0x69, 0x33, 0xec,
+0xc2, 0xa7, 0x25, 0x2e, 0xc9, 0x21, 0x3d, 0xf2, 0x8a, 0xd8, 0x59, 0xc2, 0xe1, 0x29, 0xa7, 0x3d,
+0x58, 0xab, 0x76, 0x9a, 0xcd, 0xae, 0x7b, 0x1b, 0x84, 0x0d, 0xc4, 0x30, 0x1f, 0xf3, 0x1b, 0xa4,
+0x38, 0x16, 0xeb, 0x56, 0xc6, 0x97, 0x6d, 0x1d, 0xab, 0xb2, 0x79, 0xf2, 0xca, 0x11, 0xd2, 0xe4,
+0x5f, 0xd6, 0x05, 0x3c, 0x52, 0x0f, 0x52, 0x1f, 0xc6, 0x9e, 0x15, 0xa5, 0x7e, 0xbe, 0x9f, 0xa9,
+0x57, 0x16, 0x59, 0x55, 0x72, 0xaf, 0x68, 0x93, 0x70, 0xc2, 0xb2, 0xba, 0x75, 0x99, 0x6a, 0x73,
+0x32, 0x94, 0xd1, 0x10, 0x44, 0x10, 0x2e, 0xdf, 0x82, 0xf3, 0x07, 0x84, 0xe6, 0x74, 0x3b, 0x6d,
+0x71, 0xe2, 0x2d, 0x0c, 0x1b, 0xee, 0x20, 0xd5, 0xc9, 0x20, 0x1d, 0x63, 0x29, 0x2d, 0xce, 0xec,
+0x5e, 0x4e, 0xc8, 0x93, 0xf8, 0x21, 0x61, 0x9b, 0x34, 0xeb, 0x05, 0xc6, 0x5e, 0xec, 0x5b, 0x1a,
+0xbc, 0xeb, 0xc9, 0xcf, 0xcd, 0xac, 0x34, 0x40, 0x5f, 0xb1, 0x7a, 0x66, 0xee, 0x77, 0xc8, 0x48,
+0xa8, 0x66, 0x57, 0x57, 0x9f, 0x54, 0x58, 0x8e, 0x0c, 0x2b, 0xb7, 0x4f, 0xa7, 0x30, 0xd9, 0x56,
+0xee, 0xca, 0x7b, 0x5d, 0xe3, 0xad, 0xc9, 0x4f, 0x5e, 0xe5, 0x35, 0xe7, 0x31, 0xcb, 0xda, 0x93,
+0x5e, 0xdc, 0x8e, 0x8f, 0x80, 0xda, 0xb6, 0x91, 0x98, 0x40, 0x90, 0x79, 0xc3, 0x78, 0xc7, 0xb6,
+0xb1, 0xc4, 0xb5, 0x6a, 0x18, 0x38, 0x03, 0x10, 0x8d, 0xd8, 0xd4, 0x37, 0xa4, 0x2e, 0x05, 0x7d,
+0x88, 0xf5, 0x82, 0x3e, 0x10, 0x91, 0x70, 0xab, 0x55, 0x82, 0x41, 0x32, 0xd7, 0xdb, 0x04, 0x73,
+0x2a, 0x6e, 0x91, 0x01, 0x7c, 0x21, 0x4c, 0xd4, 0xbc, 0xae, 0x1b, 0x03, 0x75, 0x5d, 0x78, 0x66,
+0xd9, 0x3a, 0x31, 0x44, 0x9a, 0x33, 0x40, 0xbf, 0x08, 0xd7, 0x5a, 0x49, 0xa4, 0xc2, 0xe6, 0xa9,
+0xa0, 0x67, 0xdd, 0xa4, 0x27, 0xbc, 0xa1, 0x4f, 0x39, 0xb5, 0x11, 0x58, 0x17, 0xf7, 0x24, 0x5c,
+0x46, 0x8f, 0x64, 0xf7, 0xc1, 0x69, 0x88, 0x76, 0x98, 0x76, 0x3d, 0x59, 0x5d, 0x42, 0x76, 0x87,
+0x89, 0x97, 0x69, 0x7a, 0x48, 0xf0, 0xe0, 0xa2, 0x12, 0x1b, 0x66, 0x9a, 0x74, 0xca, 0xde, 0x4b,
+0x1e, 0xe7, 0x0e, 0x63, 0xae, 0xe6, 0xd4, 0xef, 0x92, 0x92, 0x3a, 0x9e, 0x3d, 0xdc, 0x00, 0xe4,
+0x45, 0x25, 0x89, 0xb6, 0x9a, 0x44, 0x19, 0x2b, 0x7e, 0xc0, 0x94, 0xb4, 0xd2, 0x61, 0x6d, 0xeb,
+0x33, 0xd9, 0xc5, 0xdf, 0x4b, 0x04, 0x00, 0xcc, 0x7d, 0x1c, 0x95, 0xc3, 0x8f, 0xf7, 0x21, 0xb2,
+0xb2, 0x11, 0xb7, 0xbb, 0x7f, 0xf2, 0xd5, 0x8c, 0x70, 0x2c, 0x41, 0x60, 0xaa, 0xb1, 0x63, 0x18,
+0x44, 0x95, 0x1a, 0x76, 0x62, 0x7e, 0xf6, 0x80, 0xb0, 0xfb, 0xe8, 0x64, 0xa6, 0x33, 0xd1, 0x89,
+0x07, 0xe1, 0xbd, 0xb7, 0xe6, 0x43, 0xa4, 0x18, 0xb8, 0xa6, 0x77, 0x01, 0xe1, 0x0f, 0x94, 0x0c,
+0x21, 0x1d, 0xb2, 0x54, 0x29, 0x25, 0x89, 0x6c, 0xe5, 0x0e, 0x52, 0x51, 0x47, 0x74, 0xbe, 0x26,
+0xac, 0xb6, 0x41, 0x75, 0xde, 0x7a, 0xac, 0x5f, 0x8d, 0x3f, 0xc9, 0xbc, 0xd3, 0x41, 0x11, 0x12,
+0x5b, 0xe5, 0x10, 0x50, 0xeb, 0x31, 0xc5, 0xca, 0x72, 0x16, 0x22, 0x09, 0xdf, 0x7c, 0x4c, 0x75,
+0x3f, 0x63, 0xec, 0x21, 0x5f, 0xc4, 0x20, 0x51, 0x6b, 0x6f, 0xb1, 0xab, 0x86, 0x8b, 0x4f, 0xc2,
+0xd6, 0x45, 0x5f, 0x9d, 0x20, 0xfc, 0xa1, 0x1e, 0xc5, 0xc0, 0x8f, 0xa2, 0xb1, 0x7e, 0x0a, 0x26,
+0x99, 0xf5, 0xe4, 0x69, 0x2f, 0x98, 0x1d, 0x2d, 0xf5, 0xd9, 0xa9, 0xb2, 0x1d, 0xe5, 0x1b, 0x02,
+0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+0x04, 0x16, 0x04, 0x14, 0xec, 0xd7, 0xe3, 0x82, 0xd2, 0x71, 0x5d, 0x64, 0x4c, 0xdf, 0x2e, 0x67,
+0x3f, 0xe7, 0xba, 0x98, 0xae, 0x1c, 0x0f, 0x4f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0xbb, 0x61, 0xd9, 0x7d,
+0xa9, 0x6c, 0xbe, 0x17, 0xc4, 0x91, 0x1b, 0xc3, 0xa1, 0xa2, 0x00, 0x8d, 0xe3, 0x64, 0x68, 0x0f,
+0x56, 0xcf, 0x77, 0xae, 0x70, 0xf9, 0xfd, 0x9a, 0x4a, 0x99, 0xb9, 0xc9, 0x78, 0x5c, 0x0c, 0x0c,
+0x5f, 0xe4, 0xe6, 0x14, 0x29, 0x56, 0x0b, 0x36, 0x49, 0x5d, 0x44, 0x63, 0xe0, 0xad, 0x9c, 0x96,
+0x18, 0x66, 0x1b, 0x23, 0x0d, 0x3d, 0x79, 0xe9, 0x6d, 0x6b, 0xd6, 0x54, 0xf8, 0xd2, 0x3c, 0xc1,
+0x43, 0x40, 0xae, 0x1d, 0x50, 0xf5, 0x52, 0xfc, 0x90, 0x3b, 0xbb, 0x98, 0x99, 0x69, 0x6b, 0xc7,
+0xc1, 0xa7, 0xa8, 0x68, 0xa4, 0x27, 0xdc, 0x9d, 0xf9, 0x27, 0xae, 0x30, 0x85, 0xb9, 0xf6, 0x67,
+0x4d, 0x3a, 0x3e, 0x8f, 0x59, 0x39, 0x22, 0x53, 0x44, 0xeb, 0xc8, 0x5d, 0x03, 0xca, 0xed, 0x50,
+0x7a, 0x7d, 0x62, 0x21, 0x0a, 0x80, 0xc8, 0x73, 0x66, 0xd1, 0xa0, 0x05, 0x60, 0x5f, 0xe8, 0xa5,
+0xb4, 0xa7, 0xaf, 0xa8, 0xf7, 0x6d, 0x35, 0x9c, 0x7c, 0x5a, 0x8a, 0xd6, 0xa2, 0x38, 0x99, 0xf3,
+0x78, 0x8b, 0xf4, 0x4d, 0xd2, 0x20, 0x0b, 0xde, 0x04, 0xee, 0x8c, 0x9b, 0x47, 0x81, 0x72, 0x0d,
+0xc0, 0x14, 0x32, 0xef, 0x30, 0x59, 0x2e, 0xae, 0xe0, 0x71, 0xf2, 0x56, 0xe4, 0x6a, 0x97, 0x6f,
+0x92, 0x50, 0x6d, 0x96, 0x8d, 0x68, 0x7a, 0x9a, 0xb2, 0x36, 0x14, 0x7a, 0x06, 0xf2, 0x24, 0xb9,
+0x09, 0x11, 0x50, 0xd7, 0x08, 0xb1, 0xb8, 0x89, 0x7a, 0x84, 0x23, 0x61, 0x42, 0x29, 0xe5, 0xa3,
+0xcd, 0xa2, 0x20, 0x41, 0xd7, 0xd1, 0x9c, 0x64, 0xd9, 0xea, 0x26, 0xa1, 0x8b, 0x14, 0xd7, 0x4c,
+0x19, 0xb2, 0x50, 0x41, 0x71, 0x3d, 0x3f, 0x4d, 0x70, 0x23, 0x86, 0x0c, 0x4a, 0xdc, 0x81, 0xd2,
+0xcc, 0x32, 0x94, 0x84, 0x0d, 0x08, 0x09, 0x97, 0x1c, 0x4f, 0xc0, 0xee, 0x6b, 0x20, 0x74, 0x30,
+0xd2, 0xe0, 0x39, 0x34, 0x10, 0x85, 0x21, 0x15, 0x01, 0x08, 0xe8, 0x55, 0x32, 0xde, 0x71, 0x49,
+0xd9, 0x28, 0x17, 0x50, 0x4d, 0xe6, 0xbe, 0x4d, 0xd1, 0x75, 0xac, 0xd0, 0xca, 0xfb, 0x41, 0xb8,
+0x43, 0xa5, 0xaa, 0xd3, 0xc3, 0x05, 0x44, 0x4f, 0x2c, 0x36, 0x9b, 0xe2, 0xfa, 0xe2, 0x45, 0xb8,
+0x23, 0x53, 0x6c, 0x06, 0x6f, 0x67, 0x55, 0x7f, 0x46, 0xb5, 0x4c, 0x3f, 0x6e, 0x28, 0x5a, 0x79,
+0x26, 0xd2, 0xa4, 0xa8, 0x62, 0x97, 0xd2, 0x1e, 0xe2, 0xed, 0x4a, 0x8b, 0xbc, 0x1b, 0xfd, 0x47,
+0x4a, 0x0d, 0xdf, 0x67, 0x66, 0x7e, 0xb2, 0x5b, 0x41, 0xd0, 0x3b, 0xe4, 0xf4, 0x3b, 0xf4, 0x04,
+0x63, 0xe9, 0xef, 0xc2, 0x54, 0x00, 0x51, 0xa0, 0x8a, 0x2a, 0xc9, 0xce, 0x78, 0xcc, 0xd5, 0xea,
+0x87, 0x04, 0x18, 0xb3, 0xce, 0xaf, 0x49, 0x88, 0xaf, 0xf3, 0x92, 0x99, 0xb6, 0xb3, 0xe6, 0x61,
+0x0f, 0xd2, 0x85, 0x00, 0xe7, 0x50, 0x1a, 0xe4, 0x1b, 0x95, 0x9d, 0x19, 0xa1, 0xb9, 0x9c, 0xb1,
+0x9b, 0xb1, 0x00, 0x1e, 0xef, 0xd0, 0x0f, 0x4f, 0x42, 0x6c, 0xc9, 0x0a, 0xbc, 0xee, 0x43, 0xfa,
+0x3a, 0x71, 0xa5, 0xc8, 0x4d, 0x26, 0xa5, 0x35, 0xfd, 0x89, 0x5d, 0xbc, 0x85, 0x62, 0x1d, 0x32,
+0xd2, 0xa0, 0x2b, 0x54, 0xed, 0x9a, 0x57, 0xc1, 0xdb, 0xfa, 0x10, 0xcf, 0x19, 0xb7, 0x8b, 0x4a,
+0x1b, 0x8f, 0x01, 0xb6, 0x27, 0x95, 0x53, 0xe8, 0xb6, 0x89, 0x6d, 0x5b, 0xbc, 0x68, 0xd4, 0x23,
+0xe8, 0x8b, 0x51, 0xa2, 0x56, 0xf9, 0xf0, 0xa6, 0x80, 0xa0, 0xd6, 0x1e, 0xb3, 0xbc, 0x0f, 0x0f,
+0x53, 0x75, 0x29, 0xaa, 0xea, 0x13, 0x77, 0xe4, 0xde, 0x8c, 0x81, 0x21, 0xad, 0x07, 0x10, 0x47,
+0x11, 0xad, 0x87, 0x3d, 0x07, 0xd1, 0x75, 0xbc, 0xcf, 0xf3, 0x66, 0x7e, 0x30, 0x82, 0x02, 0x46,
+0x30, 0x82, 0x01, 0xcd, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x0b, 0xa1, 0x5a, 0xfa, 0x1d,
+0xdf, 0xa0, 0xb5, 0x49, 0x44, 0xaf, 0xcd, 0x24, 0xa0, 0x6c, 0xec, 0x30, 0x0a, 0x06, 0x08, 0x2a,
+0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, 0x30,
+0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69,
+0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x1b, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75,
+0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x47, 0x33, 0x30, 0x1e,
+0x17, 0x0d, 0x31, 0x33, 0x30, 0x38, 0x30, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17,
+0x0d, 0x33, 0x38, 0x30, 0x31, 0x31, 0x35, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x65,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30,
+0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
+0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77,
+0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31,
+0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1b, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65,
+0x72, 0x74, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x65, 0x64, 0x20, 0x49, 0x44, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x47, 0x33, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x19, 0xe7, 0xbc,
+0xac, 0x44, 0x65, 0xed, 0xcd, 0xb8, 0x3f, 0x58, 0xfb, 0x8d, 0xb1, 0x57, 0xa9, 0x44, 0x2d, 0x05,
+0x15, 0xf2, 0xef, 0x0b, 0xff, 0x10, 0x74, 0x9f, 0xb5, 0x62, 0x52, 0x5f, 0x66, 0x7e, 0x1f, 0xe5,
+0xdc, 0x1b, 0x45, 0x79, 0x0b, 0xcc, 0xc6, 0x53, 0x0a, 0x9d, 0x8d, 0x5d, 0x02, 0xd9, 0xa9, 0x59,
+0xde, 0x02, 0x5a, 0xf6, 0x95, 0x2a, 0x0e, 0x8d, 0x38, 0x4a, 0x8a, 0x49, 0xc6, 0xbc, 0xc6, 0x03,
+0x38, 0x07, 0x5f, 0x55, 0xda, 0x7e, 0x09, 0x6e, 0xe2, 0x7f, 0x5e, 0xd0, 0x45, 0x20, 0x0f, 0x59,
+0x76, 0x10, 0xd6, 0xa0, 0x24, 0xf0, 0x2d, 0xde, 0x36, 0xf2, 0x6c, 0x29, 0x39, 0xa3, 0x42, 0x30,
+0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xcb, 0xd0, 0xbd,
+0xa9, 0xe1, 0x98, 0x05, 0x51, 0xa1, 0x4d, 0x37, 0xa2, 0x83, 0x79, 0xce, 0x8d, 0x1d, 0x2a, 0xe4,
+0x84, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x67, 0x00,
+0x30, 0x64, 0x02, 0x30, 0x25, 0xa4, 0x81, 0x45, 0x02, 0x6b, 0x12, 0x4b, 0x75, 0x74, 0x4f, 0xc8,
+0x23, 0xe3, 0x70, 0xf2, 0x75, 0x72, 0xde, 0x7c, 0x89, 0xf0, 0xcf, 0x91, 0x72, 0x61, 0x9e, 0x5e,
+0x10, 0x92, 0x59, 0x56, 0xb9, 0x83, 0xc7, 0x10, 0xe7, 0x38, 0xe9, 0x58, 0x26, 0x36, 0x7d, 0xd5,
+0xe4, 0x34, 0x86, 0x39, 0x02, 0x30, 0x7c, 0x36, 0x53, 0xf0, 0x30, 0xe5, 0x62, 0x63, 0x3a, 0x99,
+0xe2, 0xb6, 0xa3, 0x3b, 0x9b, 0x34, 0xfa, 0x1e, 0xda, 0x10, 0x92, 0x71, 0x5e, 0x91, 0x13, 0xa7,
+0xdd, 0xa4, 0x6e, 0x92, 0xcc, 0x32, 0xd6, 0xf5, 0x21, 0x66, 0xc7, 0x2f, 0xea, 0x96, 0x63, 0x6a,
+0x65, 0x45, 0x92, 0x95, 0x01, 0xb4, 0x30, 0x82, 0x04, 0x00, 0x30, 0x82, 0x02, 0xe8, 0xa0, 0x03,
+0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x63, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x55, 0x53, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x54,
+0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x47, 0x72, 0x6f, 0x75,
+0x70, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x13, 0x28, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73,
+0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x34,
+0x30, 0x36, 0x32, 0x39, 0x31, 0x37, 0x30, 0x36, 0x32, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x30,
+0x36, 0x32, 0x39, 0x31, 0x37, 0x30, 0x36, 0x32, 0x30, 0x5a, 0x30, 0x63, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x18, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79,
+0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f,
+0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20,
+0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30,
+0x82, 0x01, 0x20, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+0x05, 0x00, 0x03, 0x82, 0x01, 0x0d, 0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00,
+0xde, 0x9d, 0xd7, 0xea, 0x57, 0x18, 0x49, 0xa1, 0x5b, 0xeb, 0xd7, 0x5f, 0x48, 0x86, 0xea, 0xbe,
+0xdd, 0xff, 0xe4, 0xef, 0x67, 0x1c, 0xf4, 0x65, 0x68, 0xb3, 0x57, 0x71, 0xa0, 0x5e, 0x77, 0xbb,
+0xed, 0x9b, 0x49, 0xe9, 0x70, 0x80, 0x3d, 0x56, 0x18, 0x63, 0x08, 0x6f, 0xda, 0xf2, 0xcc, 0xd0,
+0x3f, 0x7f, 0x02, 0x54, 0x22, 0x54, 0x10, 0xd8, 0xb2, 0x81, 0xd4, 0xc0, 0x75, 0x3d, 0x4b, 0x7f,
+0xc7, 0x77, 0xc3, 0x3e, 0x78, 0xab, 0x1a, 0x03, 0xb5, 0x20, 0x6b, 0x2f, 0x6a, 0x2b, 0xb1, 0xc5,
+0x88, 0x7e, 0xc4, 0xbb, 0x1e, 0xb0, 0xc1, 0xd8, 0x45, 0x27, 0x6f, 0xaa, 0x37, 0x58, 0xf7, 0x87,
+0x26, 0xd7, 0xd8, 0x2d, 0xf6, 0xa9, 0x17, 0xb7, 0x1f, 0x72, 0x36, 0x4e, 0xa6, 0x17, 0x3f, 0x65,
+0x98, 0x92, 0xdb, 0x2a, 0x6e, 0x5d, 0xa2, 0xfe, 0x88, 0xe0, 0x0b, 0xde, 0x7f, 0xe5, 0x8d, 0x15,
+0xe1, 0xeb, 0xcb, 0x3a, 0xd5, 0xe2, 0x12, 0xa2, 0x13, 0x2d, 0xd8, 0x8e, 0xaf, 0x5f, 0x12, 0x3d,
+0xa0, 0x08, 0x05, 0x08, 0xb6, 0x5c, 0xa5, 0x65, 0x38, 0x04, 0x45, 0x99, 0x1e, 0xa3, 0x60, 0x60,
+0x74, 0xc5, 0x41, 0xa5, 0x72, 0x62, 0x1b, 0x62, 0xc5, 0x1f, 0x6f, 0x5f, 0x1a, 0x42, 0xbe, 0x02,
+0x51, 0x65, 0xa8, 0xae, 0x23, 0x18, 0x6a, 0xfc, 0x78, 0x03, 0xa9, 0x4d, 0x7f, 0x80, 0xc3, 0xfa,
+0xab, 0x5a, 0xfc, 0xa1, 0x40, 0xa4, 0xca, 0x19, 0x16, 0xfe, 0xb2, 0xc8, 0xef, 0x5e, 0x73, 0x0d,
+0xee, 0x77, 0xbd, 0x9a, 0xf6, 0x79, 0x98, 0xbc, 0xb1, 0x07, 0x67, 0xa2, 0x15, 0x0d, 0xdd, 0xa0,
+0x58, 0xc6, 0x44, 0x7b, 0x0a, 0x3e, 0x62, 0x28, 0x5f, 0xba, 0x41, 0x07, 0x53, 0x58, 0xcf, 0x11,
+0x7e, 0x38, 0x74, 0xc5, 0xf8, 0xff, 0xb5, 0x69, 0x90, 0x8f, 0x84, 0x74, 0xea, 0x97, 0x1b, 0xaf,
+0x02, 0x01, 0x03, 0xa3, 0x81, 0xc0, 0x30, 0x81, 0xbd, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+0x04, 0x16, 0x04, 0x14, 0xd2, 0xc4, 0xb0, 0xd2, 0x91, 0xd4, 0x4c, 0x11, 0x71, 0xb3, 0x61, 0xcb,
+0x3d, 0xa1, 0xfe, 0xdd, 0xa8, 0x6a, 0xd4, 0xe3, 0x30, 0x81, 0x8d, 0x06, 0x03, 0x55, 0x1d, 0x23,
+0x04, 0x81, 0x85, 0x30, 0x81, 0x82, 0x80, 0x14, 0xd2, 0xc4, 0xb0, 0xd2, 0x91, 0xd4, 0x4c, 0x11,
+0x71, 0xb3, 0x61, 0xcb, 0x3d, 0xa1, 0xfe, 0xdd, 0xa8, 0x6a, 0xd4, 0xe3, 0xa1, 0x67, 0xa4, 0x65,
+0x30, 0x63, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f,
+0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2c, 0x20, 0x49, 0x6e,
+0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x47, 0x6f, 0x20,
+0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 0x65,
+0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x82, 0x01, 0x00, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04,
+0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x32, 0x4b, 0xf3, 0xb2, 0xca, 0x3e,
+0x91, 0xfc, 0x12, 0xc6, 0xa1, 0x07, 0x8c, 0x8e, 0x77, 0xa0, 0x33, 0x06, 0x14, 0x5c, 0x90, 0x1e,
+0x18, 0xf7, 0x08, 0xa6, 0x3d, 0x0a, 0x19, 0xf9, 0x87, 0x80, 0x11, 0x6e, 0x69, 0xe4, 0x96, 0x17,
+0x30, 0xff, 0x34, 0x91, 0x63, 0x72, 0x38, 0xee, 0xcc, 0x1c, 0x01, 0xa3, 0x1d, 0x94, 0x28, 0xa4,
+0x31, 0xf6, 0x7a, 0xc4, 0x54, 0xd7, 0xf6, 0xe5, 0x31, 0x58, 0x03, 0xa2, 0xcc, 0xce, 0x62, 0xdb,
+0x94, 0x45, 0x73, 0xb5, 0xbf, 0x45, 0xc9, 0x24, 0xb5, 0xd5, 0x82, 0x02, 0xad, 0x23, 0x79, 0x69,
+0x8d, 0xb8, 0xb6, 0x4d, 0xce, 0xcf, 0x4c, 0xca, 0x33, 0x23, 0xe8, 0x1c, 0x88, 0xaa, 0x9d, 0x8b,
+0x41, 0x6e, 0x16, 0xc9, 0x20, 0xe5, 0x89, 0x9e, 0xcd, 0x3b, 0xda, 0x70, 0xf7, 0x7e, 0x99, 0x26,
+0x20, 0x14, 0x54, 0x25, 0xab, 0x6e, 0x73, 0x85, 0xe6, 0x9b, 0x21, 0x9d, 0x0a, 0x6c, 0x82, 0x0e,
+0xa8, 0xf8, 0xc2, 0x0c, 0xfa, 0x10, 0x1e, 0x6c, 0x96, 0xef, 0x87, 0x0d, 0xc4, 0x0f, 0x61, 0x8b,
+0xad, 0xee, 0x83, 0x2b, 0x95, 0xf8, 0x8e, 0x92, 0x84, 0x72, 0x39, 0xeb, 0x20, 0xea, 0x83, 0xed,
+0x83, 0xcd, 0x97, 0x6e, 0x08, 0xbc, 0xeb, 0x4e, 0x26, 0xb6, 0x73, 0x2b, 0xe4, 0xd3, 0xf6, 0x4c,
+0xfe, 0x26, 0x71, 0xe2, 0x61, 0x11, 0x74, 0x4a, 0xff, 0x57, 0x1a, 0x87, 0x0f, 0x75, 0x48, 0x2e,
+0xcf, 0x51, 0x69, 0x17, 0xa0, 0x02, 0x12, 0x61, 0x95, 0xd5, 0xd1, 0x40, 0xb2, 0x10, 0x4c, 0xee,
+0xc4, 0xac, 0x10, 0x43, 0xa6, 0xa5, 0x9e, 0x0a, 0xd5, 0x95, 0x62, 0x9a, 0x0d, 0xcf, 0x88, 0x82,
+0xc5, 0x32, 0x0c, 0xe4, 0x2b, 0x9f, 0x45, 0xe6, 0x0d, 0x9f, 0x28, 0x9c, 0xb1, 0xb9, 0x2a, 0x5a,
+0x57, 0xad, 0x37, 0x0f, 0xaf, 0x1d, 0x7f, 0xdb, 0xbd, 0x9f, 0x30, 0x82, 0x03, 0xc5, 0x30, 0x82,
+0x02, 0xad, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x83, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
+0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30, 0x11, 0x06,
+0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65,
+0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64,
+0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30,
+0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x39, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
+0x17, 0x0d, 0x33, 0x37, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30,
+0x81, 0x83, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e,
+0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74,
+0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e,
+0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, 0x47, 0x6f, 0x20,
+0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
+0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf, 0x71, 0x62, 0x08, 0xf1, 0xfa, 0x59, 0x34, 0xf7, 0x1b,
+0xc9, 0x18, 0xa3, 0xf7, 0x80, 0x49, 0x58, 0xe9, 0x22, 0x83, 0x13, 0xa6, 0xc5, 0x20, 0x43, 0x01,
+0x3b, 0x84, 0xf1, 0xe6, 0x85, 0x49, 0x9f, 0x27, 0xea, 0xf6, 0x84, 0x1b, 0x4e, 0xa0, 0xb4, 0xdb,
+0x70, 0x98, 0xc7, 0x32, 0x01, 0xb1, 0x05, 0x3e, 0x07, 0x4e, 0xee, 0xf4, 0xfa, 0x4f, 0x2f, 0x59,
+0x30, 0x22, 0xe7, 0xab, 0x19, 0x56, 0x6b, 0xe2, 0x80, 0x07, 0xfc, 0xf3, 0x16, 0x75, 0x80, 0x39,
+0x51, 0x7b, 0xe5, 0xf9, 0x35, 0xb6, 0x74, 0x4e, 0xa9, 0x8d, 0x82, 0x13, 0xe4, 0xb6, 0x3f, 0xa9,
+0x03, 0x83, 0xfa, 0xa2, 0xbe, 0x8a, 0x15, 0x6a, 0x7f, 0xde, 0x0b, 0xc3, 0xb6, 0x19, 0x14, 0x05,
+0xca, 0xea, 0xc3, 0xa8, 0x04, 0x94, 0x3b, 0x46, 0x7c, 0x32, 0x0d, 0xf3, 0x00, 0x66, 0x22, 0xc8,
+0x8d, 0x69, 0x6d, 0x36, 0x8c, 0x11, 0x18, 0xb7, 0xd3, 0xb2, 0x1c, 0x60, 0xb4, 0x38, 0xfa, 0x02,
+0x8c, 0xce, 0xd3, 0xdd, 0x46, 0x07, 0xde, 0x0a, 0x3e, 0xeb, 0x5d, 0x7c, 0xc8, 0x7c, 0xfb, 0xb0,
+0x2b, 0x53, 0xa4, 0x92, 0x62, 0x69, 0x51, 0x25, 0x05, 0x61, 0x1a, 0x44, 0x81, 0x8c, 0x2c, 0xa9,
+0x43, 0x96, 0x23, 0xdf, 0xac, 0x3a, 0x81, 0x9a, 0x0e, 0x29, 0xc5, 0x1c, 0xa9, 0xe9, 0x5d, 0x1e,
+0xb6, 0x9e, 0x9e, 0x30, 0x0a, 0x39, 0xce, 0xf1, 0x88, 0x80, 0xfb, 0x4b, 0x5d, 0xcc, 0x32, 0xec,
+0x85, 0x62, 0x43, 0x25, 0x34, 0x02, 0x56, 0x27, 0x01, 0x91, 0xb4, 0x3b, 0x70, 0x2a, 0x3f, 0x6e,
+0xb1, 0xe8, 0x9c, 0x88, 0x01, 0x7d, 0x9f, 0xd4, 0xf9, 0xdb, 0x53, 0x6d, 0x60, 0x9d, 0xbf, 0x2c,
+0xe7, 0x58, 0xab, 0xb8, 0x5f, 0x46, 0xfc, 0xce, 0xc4, 0x1b, 0x03, 0x3c, 0x09, 0xeb, 0x49, 0x31,
+0x5c, 0x69, 0x46, 0xb3, 0xe0, 0x47, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x3a, 0x9a, 0x85, 0x07, 0x10,
+0x67, 0x28, 0xb6, 0xef, 0xf6, 0xbd, 0x05, 0x41, 0x6e, 0x20, 0xc1, 0x94, 0xda, 0x0f, 0xde, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82,
+0x01, 0x01, 0x00, 0x99, 0xdb, 0x5d, 0x79, 0xd5, 0xf9, 0x97, 0x59, 0x67, 0x03, 0x61, 0xf1, 0x7e,
+0x3b, 0x06, 0x31, 0x75, 0x2d, 0xa1, 0x20, 0x8e, 0x4f, 0x65, 0x87, 0xb4, 0xf7, 0xa6, 0x9c, 0xbc,
+0xd8, 0xe9, 0x2f, 0xd0, 0xdb, 0x5a, 0xee, 0xcf, 0x74, 0x8c, 0x73, 0xb4, 0x38, 0x42, 0xda, 0x05,
+0x7b, 0xf8, 0x02, 0x75, 0xb8, 0xfd, 0xa5, 0xb1, 0xd7, 0xae, 0xf6, 0xd7, 0xde, 0x13, 0xcb, 0x53,
+0x10, 0x7e, 0x8a, 0x46, 0xd1, 0x97, 0xfa, 0xb7, 0x2e, 0x2b, 0x11, 0xab, 0x90, 0xb0, 0x27, 0x80,
+0xf9, 0xe8, 0x9f, 0x5a, 0xe9, 0x37, 0x9f, 0xab, 0xe4, 0xdf, 0x6c, 0xb3, 0x85, 0x17, 0x9d, 0x3d,
+0xd9, 0x24, 0x4f, 0x79, 0x91, 0x35, 0xd6, 0x5f, 0x04, 0xeb, 0x80, 0x83, 0xab, 0x9a, 0x02, 0x2d,
+0xb5, 0x10, 0xf4, 0xd8, 0x90, 0xc7, 0x04, 0x73, 0x40, 0xed, 0x72, 0x25, 0xa0, 0xa9, 0x9f, 0xec,
+0x9e, 0xab, 0x68, 0x12, 0x99, 0x57, 0xc6, 0x8f, 0x12, 0x3a, 0x09, 0xa4, 0xbd, 0x44, 0xfd, 0x06,
+0x15, 0x37, 0xc1, 0x9b, 0xe4, 0x32, 0xa3, 0xed, 0x38, 0xe8, 0xd8, 0x64, 0xf3, 0x2c, 0x7e, 0x14,
+0xfc, 0x02, 0xea, 0x9f, 0xcd, 0xff, 0x07, 0x68, 0x17, 0xdb, 0x22, 0x90, 0x38, 0x2d, 0x7a, 0x8d,
+0xd1, 0x54, 0xf1, 0x69, 0xe3, 0x5f, 0x33, 0xca, 0x7a, 0x3d, 0x7b, 0x0a, 0xe3, 0xca, 0x7f, 0x5f,
+0x39, 0xe5, 0xe2, 0x75, 0xba, 0xc5, 0x76, 0x18, 0x33, 0xce, 0x2c, 0xf0, 0x2f, 0x4c, 0xad, 0xf7,
+0xb1, 0xe7, 0xce, 0x4f, 0xa8, 0xc4, 0x9b, 0x4a, 0x54, 0x06, 0xc5, 0x7f, 0x7d, 0xd5, 0x08, 0x0f,
+0xe2, 0x1c, 0xfe, 0x7e, 0x17, 0xb8, 0xac, 0x5e, 0xf6, 0xd4, 0x16, 0xb2, 0x43, 0x09, 0x0c, 0x4d,
+0xf6, 0xa7, 0x6b, 0xb4, 0x99, 0x84, 0x65, 0xca, 0x7a, 0x88, 0xe2, 0xe2, 0x44, 0xbe, 0x5c, 0xf7,
+0xea, 0x1c, 0xf5, 0x30, 0x82, 0x04, 0x31, 0x30, 0x82, 0x03, 0x19, 0xa0, 0x03, 0x02, 0x01, 0x02,
+0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+0x05, 0x00, 0x30, 0x81, 0x95, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x47, 0x52, 0x31, 0x44, 0x30, 0x42, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x3b, 0x48, 0x65, 0x6c,
+0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61,
+0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74,
+0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x43, 0x65, 0x72, 0x74, 0x2e, 0x20, 0x41,
+0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x40, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x37, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64,
+0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63,
+0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x52,
+0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31,
+0x31, 0x32, 0x30, 0x36, 0x31, 0x33, 0x34, 0x39, 0x35, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x31,
+0x32, 0x30, 0x31, 0x31, 0x33, 0x34, 0x39, 0x35, 0x32, 0x5a, 0x30, 0x81, 0x95, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x52, 0x31, 0x44, 0x30, 0x42, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x3b, 0x48, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x69, 0x63, 0x20, 0x41, 0x63,
+0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61,
+0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+0x20, 0x43, 0x65, 0x72, 0x74, 0x2e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x31, 0x40, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x37, 0x48, 0x65, 0x6c, 0x6c, 0x65,
+0x6e, 0x69, 0x63, 0x20, 0x41, 0x63, 0x61, 0x64, 0x65, 0x6d, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64,
+0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x69, 0x74,
+0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41, 0x20, 0x32, 0x30,
+0x31, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
+0x01, 0x01, 0x00, 0xa9, 0x53, 0x00, 0xe3, 0x2e, 0xa6, 0xf6, 0x8e, 0xfa, 0x60, 0xd8, 0x2d, 0x95,
+0x3e, 0xf8, 0x2c, 0x2a, 0x54, 0x4e, 0xcd, 0xb9, 0x84, 0x61, 0x94, 0x58, 0x4f, 0x8f, 0x3d, 0x8b,
+0xe4, 0x43, 0xf3, 0x75, 0x89, 0x8d, 0x51, 0xe4, 0xc3, 0x37, 0xd2, 0x8a, 0x88, 0x4d, 0x79, 0x1e,
+0xb7, 0x12, 0xdd, 0x43, 0x78, 0x4a, 0x8a, 0x92, 0xe6, 0xd7, 0x48, 0xd5, 0x0f, 0xa4, 0x3a, 0x29,
+0x44, 0x35, 0xb8, 0x07, 0xf6, 0x68, 0x1d, 0x55, 0xcd, 0x38, 0x51, 0xf0, 0x8c, 0x24, 0x31, 0x85,
+0xaf, 0x83, 0xc9, 0x7d, 0xe9, 0x77, 0xaf, 0xed, 0x1a, 0x7b, 0x9d, 0x17, 0xf9, 0xb3, 0x9d, 0x38,
+0x50, 0x0f, 0xa6, 0x5a, 0x79, 0x91, 0x80, 0xaf, 0x37, 0xae, 0xa6, 0xd3, 0x31, 0xfb, 0xb5, 0x26,
+0x09, 0x9d, 0x3c, 0x5a, 0xef, 0x51, 0xc5, 0x2b, 0xdf, 0x96, 0x5d, 0xeb, 0x32, 0x1e, 0x02, 0xda,
+0x70, 0x49, 0xec, 0x6e, 0x0c, 0xc8, 0x9a, 0x37, 0x8d, 0xf7, 0xf1, 0x36, 0x60, 0x4b, 0x26, 0x2c,
+0x82, 0x9e, 0xd0, 0x78, 0xf3, 0x0d, 0x0f, 0x63, 0xa4, 0x51, 0x30, 0xe1, 0xf9, 0x2b, 0x27, 0x12,
+0x07, 0xd8, 0xea, 0xbd, 0x18, 0x62, 0x98, 0xb0, 0x59, 0x37, 0x7d, 0xbe, 0xee, 0xf3, 0x20, 0x51,
+0x42, 0x5a, 0x83, 0xef, 0x93, 0xba, 0x69, 0x15, 0xf1, 0x62, 0x9d, 0x9f, 0x99, 0x39, 0x82, 0xa1,
+0xb7, 0x74, 0x2e, 0x8b, 0xd4, 0xc5, 0x0b, 0x7b, 0x2f, 0xf0, 0xc8, 0x0a, 0xda, 0x3d, 0x79, 0x0a,
+0x9a, 0x93, 0x1c, 0xa5, 0x28, 0x72, 0x73, 0x91, 0x43, 0x9a, 0xa7, 0xd1, 0x4d, 0x85, 0x84, 0xb9,
+0xa9, 0x74, 0x8f, 0x14, 0x40, 0xc7, 0xdc, 0xde, 0xac, 0x41, 0x64, 0x6c, 0xb4, 0x19, 0x9b, 0x02,
+0x63, 0x6d, 0x24, 0x64, 0x8f, 0x44, 0xb2, 0x25, 0xea, 0xce, 0x5d, 0x74, 0x0c, 0x63, 0x32, 0x5c,
+0x8d, 0x87, 0xe5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0x89, 0x30, 0x81, 0x86, 0x30, 0x0f,
+0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03,
+0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa6, 0x91, 0x42, 0xfd, 0x13, 0x61, 0x4a, 0x23, 0x9e,
+0x08, 0xa4, 0x29, 0xe5, 0xd8, 0x13, 0x04, 0x23, 0xee, 0x41, 0x25, 0x30, 0x47, 0x06, 0x03, 0x55,
+0x1d, 0x1e, 0x04, 0x40, 0x30, 0x3e, 0xa0, 0x3c, 0x30, 0x05, 0x82, 0x03, 0x2e, 0x67, 0x72, 0x30,
+0x05, 0x82, 0x03, 0x2e, 0x65, 0x75, 0x30, 0x06, 0x82, 0x04, 0x2e, 0x65, 0x64, 0x75, 0x30, 0x06,
+0x82, 0x04, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x05, 0x81, 0x03, 0x2e, 0x67, 0x72, 0x30, 0x05, 0x81,
+0x03, 0x2e, 0x65, 0x75, 0x30, 0x06, 0x81, 0x04, 0x2e, 0x65, 0x64, 0x75, 0x30, 0x06, 0x81, 0x04,
+0x2e, 0x6f, 0x72, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x1f, 0xef, 0x79, 0x41, 0xe1, 0x7b, 0x6e, 0x3f,
+0xb2, 0x8c, 0x86, 0x37, 0x42, 0x4a, 0x4e, 0x1c, 0x37, 0x1e, 0x8d, 0x66, 0xba, 0x24, 0x81, 0xc9,
+0x4f, 0x12, 0x0f, 0x21, 0xc0, 0x03, 0x97, 0x86, 0x25, 0x6d, 0x5d, 0xd3, 0x22, 0x29, 0xa8, 0x6c,
+0xa2, 0x0d, 0xa9, 0xeb, 0x3d, 0x06, 0x5b, 0x99, 0x3a, 0xc7, 0xcc, 0xc3, 0x9a, 0x34, 0x7f, 0xab,
+0x0e, 0xc8, 0x4e, 0x1c, 0xe1, 0xfa, 0xe4, 0xdc, 0xcd, 0x0d, 0xbe, 0xbf, 0x24, 0xfe, 0x6c, 0xe7,
+0x6b, 0xc2, 0x0d, 0xc8, 0x06, 0x9e, 0x4e, 0x8d, 0x61, 0x28, 0xa6, 0x6a, 0xfd, 0xe5, 0xf6, 0x62,
+0xea, 0x18, 0x3c, 0x4e, 0xa0, 0x53, 0x9d, 0xb2, 0x3a, 0x9c, 0xeb, 0xa5, 0x9c, 0x91, 0x16, 0xb6,
+0x4d, 0x82, 0xe0, 0x0c, 0x05, 0x48, 0xa9, 0x6c, 0xf5, 0xcc, 0xf8, 0xcb, 0x9d, 0x49, 0xb4, 0xf0,
+0x02, 0xa5, 0xfd, 0x70, 0x03, 0xed, 0x8a, 0x21, 0xa5, 0xae, 0x13, 0x86, 0x49, 0xc3, 0x33, 0x73,
+0xbe, 0x87, 0x3b, 0x74, 0x8b, 0x17, 0x45, 0x26, 0x4c, 0x16, 0x91, 0x83, 0xfe, 0x67, 0x7d, 0xcd,
+0x4d, 0x63, 0x67, 0xfa, 0xf3, 0x03, 0x12, 0x96, 0x78, 0x06, 0x8d, 0xb1, 0x67, 0xed, 0x8e, 0x3f,
+0xbe, 0x9f, 0x4f, 0x02, 0xf5, 0xb3, 0x09, 0x2f, 0xf3, 0x4c, 0x87, 0xdf, 0x2a, 0xcb, 0x95, 0x7c,
+0x01, 0xcc, 0xac, 0x36, 0x7a, 0xbf, 0xa2, 0x73, 0x7a, 0xf7, 0x8f, 0xc1, 0xb5, 0x9a, 0xa1, 0x14,
+0xb2, 0x8f, 0x33, 0x9f, 0x0d, 0xef, 0x22, 0xdc, 0x66, 0x7b, 0x84, 0xbd, 0x45, 0x17, 0x06, 0x3d,
+0x3c, 0xca, 0xb9, 0x77, 0x34, 0x8f, 0xca, 0xea, 0xcf, 0x3f, 0x31, 0x3e, 0xe3, 0x88, 0xe3, 0x80,
+0x49, 0x25, 0xc8, 0x97, 0xb5, 0x9d, 0x9a, 0x99, 0x4d, 0xb0, 0x3c, 0xf8, 0x4a, 0x00, 0x9b, 0x64,
+0xdd, 0x9f, 0x39, 0x4b, 0xd1, 0x27, 0xd7, 0xb8, 0x30, 0x82, 0x03, 0x30, 0x30, 0x82, 0x02, 0x18,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0xe8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x4b, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x13, 0x0d, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x31,
+0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f,
+0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20,
+0x31, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x33, 0x30, 0x35, 0x31, 0x35, 0x30, 0x35, 0x31, 0x33, 0x31,
+0x34, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x35, 0x31, 0x35, 0x30, 0x34, 0x35, 0x32, 0x32, 0x39,
+0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x4b,
+0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x48, 0x6f, 0x6e, 0x67, 0x6b,
+0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x17, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x20, 0x50, 0x6f, 0x73, 0x74,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
+0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xac, 0xff, 0x38, 0xb6, 0xe9,
+0x66, 0x02, 0x49, 0xe3, 0xa2, 0xb4, 0xe1, 0x90, 0xf9, 0x40, 0x8f, 0x79, 0xf9, 0xe2, 0xbd, 0x79,
+0xfe, 0x02, 0xbd, 0xee, 0x24, 0x92, 0x1d, 0x22, 0xf6, 0xda, 0x85, 0x72, 0x69, 0xfe, 0xd7, 0x3f,
+0x09, 0xd4, 0xdd, 0x91, 0xb5, 0x02, 0x9c, 0xd0, 0x8d, 0x5a, 0xe1, 0x55, 0xc3, 0x50, 0x86, 0xb9,
+0x29, 0x26, 0xc2, 0xe3, 0xd9, 0xa0, 0xf1, 0x69, 0x03, 0x28, 0x20, 0x80, 0x45, 0x22, 0x2d, 0x56,
+0xa7, 0x3b, 0x54, 0x95, 0x56, 0x22, 0x59, 0x1f, 0x28, 0xdf, 0x1f, 0x20, 0x3d, 0x6d, 0xa2, 0x36,
+0xbe, 0x23, 0xa0, 0xb1, 0x6e, 0xb5, 0xb1, 0x27, 0x3f, 0x39, 0x53, 0x09, 0xea, 0xab, 0x6a, 0xe8,
+0x74, 0xb2, 0xc2, 0x65, 0x5c, 0x8e, 0xbf, 0x7c, 0xc3, 0x78, 0x84, 0xcd, 0x9e, 0x16, 0xfc, 0xf5,
+0x2e, 0x4f, 0x20, 0x2a, 0x08, 0x9f, 0x77, 0xf3, 0xc5, 0x1e, 0xc4, 0x9a, 0x52, 0x66, 0x1e, 0x48,
+0x5e, 0xe3, 0x10, 0x06, 0x8f, 0x22, 0x98, 0xe1, 0x65, 0x8e, 0x1b, 0x5d, 0x23, 0x66, 0x3b, 0xb8,
+0xa5, 0x32, 0x51, 0xc8, 0x86, 0xaa, 0xa1, 0xa9, 0x9e, 0x7f, 0x76, 0x94, 0xc2, 0xa6, 0x6c, 0xb7,
+0x41, 0xf0, 0xd5, 0xc8, 0x06, 0x38, 0xe6, 0xd4, 0x0c, 0xe2, 0xf3, 0x3b, 0x4c, 0x6d, 0x50, 0x8c,
+0xc4, 0x83, 0x27, 0xc1, 0x13, 0x84, 0x59, 0x3d, 0x9e, 0x75, 0x74, 0xb6, 0xd8, 0x02, 0x5e, 0x3a,
+0x90, 0x7a, 0xc0, 0x42, 0x36, 0x72, 0xec, 0x6a, 0x4d, 0xdc, 0xef, 0xc4, 0x00, 0xdf, 0x13, 0x18,
+0x57, 0x5f, 0x26, 0x78, 0xc8, 0xd6, 0x0a, 0x79, 0x77, 0xbf, 0xf7, 0xaf, 0xb7, 0x76, 0xb9, 0xa5,
+0x0b, 0x84, 0x17, 0x5d, 0x10, 0xea, 0x6f, 0xe1, 0xab, 0x95, 0x11, 0x5f, 0x6d, 0x3c, 0xa3, 0x5c,
+0x4d, 0x83, 0x5b, 0xf2, 0xb3, 0x19, 0x8a, 0x80, 0x8b, 0x0b, 0x87, 0x02, 0x03, 0x01, 0x00, 0x01,
+0xa3, 0x26, 0x30, 0x24, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
+0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x03, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0xc6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x0e, 0x46, 0xd5, 0x3c,
+0xae, 0xe2, 0x87, 0xd9, 0x5e, 0x81, 0x8b, 0x02, 0x98, 0x41, 0x08, 0x8c, 0x4c, 0xbc, 0xda, 0xdb,
+0xee, 0x27, 0x1b, 0x82, 0xe7, 0x6a, 0x45, 0xec, 0x16, 0x8b, 0x4f, 0x85, 0xa0, 0xf3, 0xb2, 0x70,
+0xbd, 0x5a, 0x96, 0xba, 0xca, 0x6e, 0x6d, 0xee, 0x46, 0x8b, 0x6e, 0xe7, 0x2a, 0x2e, 0x96, 0xb3,
+0x19, 0x33, 0xeb, 0xb4, 0x9f, 0xa8, 0xb2, 0x37, 0xee, 0x98, 0xa8, 0x97, 0xb6, 0x2e, 0xb6, 0x67,
+0x27, 0xd4, 0xa6, 0x49, 0xfd, 0x1c, 0x93, 0x65, 0x76, 0x9e, 0x42, 0x2f, 0xdc, 0x22, 0x6c, 0x9a,
+0x4f, 0xf2, 0x5a, 0x15, 0x39, 0xb1, 0x71, 0xd7, 0x2b, 0x51, 0xe8, 0x6d, 0x1c, 0x98, 0xc0, 0xd9,
+0x2a, 0xf4, 0xa1, 0x82, 0x7b, 0xd5, 0xc9, 0x41, 0xa2, 0x23, 0x01, 0x74, 0x38, 0x55, 0x8b, 0x0f,
+0xb9, 0x2e, 0x67, 0xa2, 0x20, 0x04, 0x37, 0xda, 0x9c, 0x0b, 0xd3, 0x17, 0x21, 0xe0, 0x8f, 0x97,
+0x79, 0x34, 0x6f, 0x84, 0x48, 0x02, 0x20, 0x33, 0x1b, 0xe6, 0x34, 0x44, 0x9f, 0x91, 0x70, 0xf4,
+0x80, 0x5e, 0x84, 0x43, 0xc2, 0x29, 0xd2, 0x6c, 0x12, 0x14, 0xe4, 0x61, 0x8d, 0xac, 0x10, 0x90,
+0x9e, 0x84, 0x50, 0xbb, 0xf0, 0x96, 0x6f, 0x45, 0x9f, 0x8a, 0xf3, 0xca, 0x6c, 0x4f, 0xfa, 0x11,
+0x3a, 0x15, 0x15, 0x46, 0xc3, 0xcd, 0x1f, 0x83, 0x5b, 0x2d, 0x41, 0x12, 0xed, 0x50, 0x67, 0x41,
+0x13, 0x3d, 0x21, 0xab, 0x94, 0x8a, 0xaa, 0x4e, 0x7c, 0xc1, 0xb1, 0xfb, 0xa7, 0xd6, 0xb5, 0x27,
+0x2f, 0x97, 0xab, 0x6e, 0xe0, 0x1d, 0xe2, 0xd1, 0x1c, 0x2c, 0x1f, 0x44, 0xe2, 0xfc, 0xbe, 0x91,
+0xa1, 0x9c, 0xfb, 0xd6, 0x29, 0x53, 0x73, 0x86, 0x9f, 0x53, 0xd8, 0x43, 0x0e, 0x5d, 0xd6, 0x63,
+0x82, 0x71, 0x1d, 0x80, 0x74, 0xca, 0xf6, 0xe2, 0x02, 0x6b, 0xd9, 0x5a, 0x30, 0x82, 0x05, 0xf1,
+0x30, 0x82, 0x03, 0xd9, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00, 0xb0, 0xb7, 0x5a, 0x16,
+0x48, 0x5f, 0xbf, 0xe1, 0xcb, 0xf5, 0x8b, 0xd7, 0x19, 0xe6, 0x7d, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x38, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x0c, 0x0b, 0x49, 0x5a, 0x45, 0x4e, 0x50, 0x45, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x31,
+0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x49, 0x7a, 0x65, 0x6e, 0x70, 0x65,
+0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x37, 0x31, 0x32, 0x31, 0x33, 0x31, 0x33,
+0x30, 0x38, 0x32, 0x38, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x32, 0x31, 0x33, 0x30, 0x38, 0x32,
+0x37, 0x32, 0x35, 0x5a, 0x30, 0x38, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x45, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x49, 0x5a,
+0x45, 0x4e, 0x50, 0x45, 0x20, 0x53, 0x2e, 0x41, 0x2e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x0c, 0x0a, 0x49, 0x7a, 0x65, 0x6e, 0x70, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82,
+0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xc9,
+0xd3, 0x7a, 0xca, 0x0f, 0x1e, 0xac, 0xa7, 0x86, 0xe8, 0x16, 0x65, 0x6a, 0xb1, 0xc2, 0x1b, 0x45,
+0x32, 0x71, 0x95, 0xd9, 0xfe, 0x10, 0x5b, 0xcc, 0xaf, 0xe7, 0xa5, 0x79, 0x01, 0x8f, 0x89, 0xc3,
+0xca, 0xf2, 0x55, 0x71, 0xf7, 0x77, 0xbe, 0x77, 0x94, 0xf3, 0x72, 0xa4, 0x2c, 0x44, 0xd8, 0x9e,
+0x92, 0x9b, 0x14, 0x3a, 0xa1, 0xe7, 0x24, 0x90, 0x0a, 0x0a, 0x56, 0x8e, 0xc5, 0xd8, 0x26, 0x94,
+0xe1, 0xd9, 0x48, 0xe1, 0x2d, 0x3e, 0xda, 0x0a, 0x72, 0xdd, 0xa3, 0x99, 0x15, 0xda, 0x81, 0xa2,
+0x87, 0xf4, 0x7b, 0x6e, 0x26, 0x77, 0x89, 0x58, 0xad, 0xd6, 0xeb, 0x0c, 0xb2, 0x41, 0x7a, 0x73,
+0x6e, 0x6d, 0xdb, 0x7a, 0x78, 0x41, 0xe9, 0x08, 0x88, 0x12, 0x7e, 0x87, 0x2e, 0x66, 0x11, 0x63,
+0x6c, 0x54, 0xfb, 0x3c, 0x9d, 0x72, 0xc0, 0xbc, 0x2e, 0xff, 0xc2, 0xb7, 0xdd, 0x0d, 0x76, 0xe3,
+0x3a, 0xd7, 0xf7, 0xb4, 0x68, 0xbe, 0xa2, 0xf5, 0xe3, 0x81, 0x6e, 0xc1, 0x46, 0x6f, 0x5d, 0x8d,
+0xe0, 0x4d, 0xc6, 0x54, 0x55, 0x89, 0x1a, 0x33, 0x31, 0x0a, 0xb1, 0x57, 0xb9, 0xa3, 0x8a, 0x98,
+0xc3, 0xec, 0x3b, 0x34, 0xc5, 0x95, 0x41, 0x69, 0x7e, 0x75, 0xc2, 0x3c, 0x20, 0xc5, 0x61, 0xba,
+0x51, 0x47, 0xa0, 0x20, 0x90, 0x93, 0xa1, 0x90, 0x4b, 0xf3, 0x4e, 0x7c, 0x85, 0x45, 0x54, 0x9a,
+0xd1, 0x05, 0x26, 0x41, 0xb0, 0xb5, 0x4d, 0x1d, 0x33, 0xbe, 0xc4, 0x03, 0xc8, 0x25, 0x7c, 0xc1,
+0x70, 0xdb, 0x3b, 0xf4, 0x09, 0x2d, 0x54, 0x27, 0x48, 0xac, 0x2f, 0xe1, 0xc4, 0xac, 0x3e, 0xc8,
+0xcb, 0x92, 0x4c, 0x53, 0x39, 0x37, 0x23, 0xec, 0xd3, 0x01, 0xf9, 0xe0, 0x09, 0x44, 0x4d, 0x4d,
+0x64, 0xc0, 0xe1, 0x0d, 0x5a, 0x87, 0x22, 0xbc, 0xad, 0x1b, 0xa3, 0xfe, 0x26, 0xb5, 0x15, 0xf3,
+0xa7, 0xfc, 0x84, 0x19, 0xe9, 0xec, 0xa1, 0x88, 0xb4, 0x44, 0x69, 0x84, 0x83, 0xf3, 0x89, 0xd1,
+0x74, 0x06, 0xa9, 0xcc, 0x0b, 0xd6, 0xc2, 0xde, 0x27, 0x85, 0x50, 0x26, 0xca, 0x17, 0xb8, 0xc9,
+0x7a, 0x87, 0x56, 0x2c, 0x1a, 0x01, 0x1e, 0x6c, 0xbe, 0x13, 0xad, 0x10, 0xac, 0xb5, 0x24, 0xf5,
+0x38, 0x91, 0xa1, 0xd6, 0x4b, 0xda, 0xf1, 0xbb, 0xd2, 0xde, 0x47, 0xb5, 0xf1, 0xbc, 0x81, 0xf6,
+0x59, 0x6b, 0xcf, 0x19, 0x53, 0xe9, 0x8d, 0x15, 0xcb, 0x4a, 0xcb, 0xa9, 0x6f, 0x44, 0xe5, 0x1b,
+0x41, 0xcf, 0xe1, 0x86, 0xa7, 0xca, 0xd0, 0x6a, 0x9f, 0xbc, 0x4c, 0x8d, 0x06, 0x33, 0x5a, 0xa2,
+0x85, 0xe5, 0x90, 0x35, 0xa0, 0x62, 0x5c, 0x16, 0x4e, 0xf0, 0xe3, 0xa2, 0xfa, 0x03, 0x1a, 0xb4,
+0x2c, 0x71, 0xb3, 0x58, 0x2c, 0xde, 0x7b, 0x0b, 0xdb, 0x1a, 0x0f, 0xeb, 0xde, 0x21, 0x1f, 0x06,
+0x77, 0x06, 0x03, 0xb0, 0xc9, 0xef, 0x99, 0xfc, 0xc0, 0xb9, 0x4f, 0x0b, 0x86, 0x28, 0xfe, 0xd2,
+0xb9, 0xea, 0xe3, 0xda, 0xa5, 0xc3, 0x47, 0x69, 0x12, 0xe0, 0xdb, 0xf0, 0xf6, 0x19, 0x8b, 0xed,
+0x7b, 0x70, 0xd7, 0x02, 0xd6, 0xed, 0x87, 0x18, 0x28, 0x2c, 0x04, 0x24, 0x4c, 0x77, 0xe4, 0x48,
+0x8a, 0x1a, 0xc6, 0x3b, 0x9a, 0xd4, 0x0f, 0xca, 0xfa, 0x75, 0xd2, 0x01, 0x40, 0x5a, 0x8d, 0x79,
+0xbf, 0x8b, 0xcf, 0x4b, 0xcf, 0xaa, 0x16, 0xc1, 0x95, 0xe4, 0xad, 0x4c, 0x8a, 0x3e, 0x17, 0x91,
+0xd4, 0xb1, 0x62, 0xe5, 0x82, 0xe5, 0x80, 0x04, 0xa4, 0x03, 0x7e, 0x8d, 0xbf, 0xda, 0x7f, 0xa2,
+0x0f, 0x97, 0x4f, 0x0c, 0xd3, 0x0d, 0xfb, 0xd7, 0xd1, 0xe5, 0x72, 0x7e, 0x1c, 0xc8, 0x77, 0xff,
+0x5b, 0x9a, 0x0f, 0xb7, 0xae, 0x05, 0x46, 0xe5, 0xf1, 0xa8, 0x16, 0xec, 0x47, 0xa4, 0x17, 0x02,
+0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xf6, 0x30, 0x81, 0xf3, 0x30, 0x81, 0xb0, 0x06, 0x03, 0x55,
+0x1d, 0x11, 0x04, 0x81, 0xa8, 0x30, 0x81, 0xa5, 0x81, 0x0f, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x69,
+0x7a, 0x65, 0x6e, 0x70, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0xa4, 0x81, 0x91, 0x30, 0x81, 0x8e, 0x31,
+0x47, 0x30, 0x45, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x3e, 0x49, 0x5a, 0x45, 0x4e, 0x50, 0x45,
+0x20, 0x53, 0x2e, 0x41, 0x2e, 0x20, 0x2d, 0x20, 0x43, 0x49, 0x46, 0x20, 0x41, 0x30, 0x31, 0x33,
+0x33, 0x37, 0x32, 0x36, 0x30, 0x2d, 0x52, 0x4d, 0x65, 0x72, 0x63, 0x2e, 0x56, 0x69, 0x74, 0x6f,
+0x72, 0x69, 0x61, 0x2d, 0x47, 0x61, 0x73, 0x74, 0x65, 0x69, 0x7a, 0x20, 0x54, 0x31, 0x30, 0x35,
+0x35, 0x20, 0x46, 0x36, 0x32, 0x20, 0x53, 0x38, 0x31, 0x43, 0x30, 0x41, 0x06, 0x03, 0x55, 0x04,
+0x09, 0x0c, 0x3a, 0x41, 0x76, 0x64, 0x61, 0x20, 0x64, 0x65, 0x6c, 0x20, 0x4d, 0x65, 0x64, 0x69,
+0x74, 0x65, 0x72, 0x72, 0x61, 0x6e, 0x65, 0x6f, 0x20, 0x45, 0x74, 0x6f, 0x72, 0x62, 0x69, 0x64,
+0x65, 0x61, 0x20, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x30, 0x31, 0x30, 0x31, 0x30, 0x20, 0x56, 0x69,
+0x74, 0x6f, 0x72, 0x69, 0x61, 0x2d, 0x47, 0x61, 0x73, 0x74, 0x65, 0x69, 0x7a, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e,
+0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x1d, 0x1c, 0x65, 0x0e, 0xa8, 0xf2, 0x25,
+0x7b, 0xb4, 0x91, 0xcf, 0xe4, 0xb1, 0xb1, 0xe6, 0xbd, 0x55, 0x74, 0x6c, 0x05, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
+0x00, 0x78, 0xa6, 0x0c, 0x16, 0x4a, 0x9f, 0x4c, 0x88, 0x3a, 0xc0, 0xcb, 0x0e, 0xa5, 0x16, 0x7d,
+0x9f, 0xb9, 0x48, 0x5f, 0x18, 0x8f, 0x0d, 0x62, 0x36, 0xf6, 0xcd, 0x19, 0x6b, 0xac, 0xab, 0xd5,
+0xf6, 0x91, 0x7d, 0xae, 0x71, 0xf3, 0x3f, 0xb3, 0x0e, 0x78, 0x85, 0x9b, 0x95, 0xa4, 0x27, 0x21,
+0x47, 0x42, 0x4a, 0x7c, 0x48, 0x3a, 0xf5, 0x45, 0x7c, 0xb3, 0x0c, 0x8e, 0x51, 0x78, 0xac, 0x95,
+0x13, 0xde, 0xc6, 0xfd, 0x7d, 0xb8, 0x1a, 0x90, 0x4c, 0xab, 0x92, 0x03, 0xc7, 0xed, 0x42, 0x01,
+0xce, 0x0f, 0xd8, 0xb1, 0xfa, 0xa2, 0x92, 0xe1, 0x60, 0x6d, 0xae, 0x7a, 0x6b, 0x09, 0xaa, 0xc6,
+0x29, 0xee, 0x68, 0x49, 0x67, 0x30, 0x80, 0x24, 0x7a, 0x31, 0x16, 0x39, 0x5b, 0x7e, 0xf1, 0x1c,
+0x2e, 0xdd, 0x6c, 0x09, 0xad, 0xf2, 0x31, 0xc1, 0x82, 0x4e, 0xb9, 0xbb, 0xf9, 0xbe, 0xbf, 0x2a,
+0x85, 0x3f, 0xc0, 0x40, 0xa3, 0x3a, 0x59, 0xfc, 0x59, 0x4b, 0x3c, 0x28, 0x24, 0xdb, 0xb4, 0x15,
+0x75, 0xae, 0x0d, 0x88, 0xba, 0x2e, 0x73, 0xc0, 0xbd, 0x58, 0x87, 0xe5, 0x42, 0xf2, 0xeb, 0x5e,
+0xee, 0x1e, 0x30, 0x22, 0x99, 0xcb, 0x37, 0xd1, 0xc4, 0x21, 0x6c, 0x81, 0xec, 0xbe, 0x6d, 0x26,
+0xe6, 0x1c, 0xe4, 0x42, 0x20, 0x9e, 0x47, 0xb0, 0xac, 0x83, 0x59, 0x70, 0x2c, 0x35, 0xd6, 0xaf,
+0x36, 0x34, 0xb4, 0xcd, 0x3b, 0xf8, 0x32, 0xa8, 0xef, 0xe3, 0x78, 0x89, 0xfb, 0x8d, 0x45, 0x2c,
+0xda, 0x9c, 0xb8, 0x7e, 0x40, 0x1c, 0x61, 0xe7, 0x3e, 0xa2, 0x92, 0x2c, 0x4b, 0xf2, 0xcd, 0xfa,
+0x98, 0xb6, 0x29, 0xff, 0xf3, 0xf2, 0x7b, 0xa9, 0x1f, 0x2e, 0xa0, 0x93, 0x57, 0x2b, 0xde, 0x85,
+0x03, 0xf9, 0x69, 0x37, 0xcb, 0x9e, 0x78, 0x6a, 0x05, 0xb4, 0xc5, 0x31, 0x78, 0x89, 0xec, 0x7a,
+0xa7, 0x85, 0xe1, 0xb9, 0x7b, 0x3c, 0xde, 0xbe, 0x1e, 0x79, 0x84, 0xce, 0x9f, 0x70, 0x0e, 0x59,
+0xc2, 0x35, 0x2e, 0x90, 0x2a, 0x31, 0xd9, 0xe4, 0x45, 0x7a, 0x41, 0xa4, 0x2e, 0x13, 0x9b, 0x34,
+0x0e, 0x66, 0x7b, 0x49, 0xab, 0x64, 0x97, 0xd0, 0x46, 0xc3, 0x79, 0x9d, 0x72, 0x50, 0x63, 0xa6,
+0x98, 0x5b, 0x06, 0xbd, 0x48, 0x6d, 0xd8, 0x39, 0x83, 0x70, 0xe8, 0x35, 0xf0, 0x05, 0xd1, 0xaa,
+0xbc, 0xe3, 0xdb, 0xc8, 0x02, 0xea, 0x7c, 0xfd, 0x82, 0xda, 0xc2, 0x5b, 0x52, 0x35, 0xae, 0x98,
+0x3a, 0xad, 0xba, 0x35, 0x93, 0x23, 0xa7, 0x1f, 0x48, 0xdd, 0x35, 0x46, 0x98, 0xb2, 0x10, 0x68,
+0xe4, 0xa5, 0x31, 0xc2, 0x0a, 0x58, 0x2e, 0x19, 0x81, 0x10, 0xc9, 0x50, 0x75, 0xfc, 0xea, 0x5a,
+0x16, 0xce, 0x11, 0xd7, 0xee, 0xef, 0x50, 0x88, 0x2d, 0x61, 0xff, 0x3f, 0x42, 0x73, 0x05, 0x94,
+0x43, 0xd5, 0x8e, 0x3c, 0x4e, 0x01, 0x3a, 0x19, 0xa5, 0x1f, 0x46, 0x4e, 0x77, 0xd0, 0x5d, 0xe5,
+0x81, 0x22, 0x21, 0x87, 0xfe, 0x94, 0x7d, 0x84, 0xd8, 0x93, 0xad, 0xd6, 0x68, 0x43, 0x48, 0xb2,
+0xdb, 0xeb, 0x73, 0x24, 0xe7, 0x91, 0x7f, 0x54, 0xa4, 0xb6, 0x80, 0x3e, 0x9d, 0xa3, 0x3c, 0x4c,
+0x72, 0xc2, 0x57, 0xc4, 0xa0, 0xd4, 0xcc, 0x38, 0x27, 0xce, 0xd5, 0x06, 0x9e, 0xa2, 0x48, 0xd9,
+0xe9, 0x9f, 0xce, 0x82, 0x70, 0x36, 0x93, 0x9a, 0x3b, 0xdf, 0x96, 0x21, 0xe3, 0x59, 0xb7, 0x0c,
+0xda, 0x91, 0x37, 0xf0, 0xfd, 0x59, 0x5a, 0xb3, 0x99, 0xc8, 0x69, 0x6c, 0x43, 0x26, 0x01, 0x35,
+0x63, 0x60, 0x55, 0x89, 0x03, 0x3a, 0x75, 0xd8, 0xba, 0x4a, 0xd9, 0x54, 0xff, 0xee, 0xde, 0x80,
+0xd8, 0x2d, 0xd1, 0x38, 0xd5, 0x5e, 0x2d, 0x0b, 0x98, 0x7d, 0x3e, 0x6c, 0xdb, 0xfc, 0x26, 0x88,
+0xc7, 0x30, 0x82, 0x03, 0xc3, 0x30, 0x82, 0x02, 0xab, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01,
+0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45,
+0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x22, 0x54, 0x2d, 0x53, 0x79, 0x73,
+0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20,
+0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x31, 0x1f, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x16, 0x54, 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
+0x73, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x31, 0x25,
+0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x54, 0x2d, 0x54, 0x65, 0x6c, 0x65, 0x53,
+0x65, 0x63, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c,
+0x61, 0x73, 0x73, 0x20, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x31, 0x30, 0x30, 0x31, 0x31,
+0x30, 0x34, 0x30, 0x31, 0x34, 0x5a, 0x17, 0x0d, 0x33, 0x33, 0x31, 0x30, 0x30, 0x31, 0x32, 0x33,
+0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x44, 0x45, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x22,
+0x54, 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70,
+0x72, 0x69, 0x73, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x47, 0x6d,
+0x62, 0x48, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x16, 0x54, 0x2d, 0x53,
+0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x65, 0x6e,
+0x74, 0x65, 0x72, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x54, 0x2d,
+0x54, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
+0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x5f, 0xda, 0x1b, 0x5f,
+0xe8, 0x73, 0x91, 0xe5, 0xda, 0x5c, 0xf4, 0xa2, 0xe6, 0x47, 0xe5, 0xf3, 0x68, 0x55, 0x60, 0x05,
+0x1d, 0x02, 0xa4, 0xb3, 0x9b, 0x59, 0xf3, 0x1e, 0x8a, 0xaf, 0x34, 0xad, 0xfc, 0x0d, 0xc2, 0xd9,
+0x48, 0x19, 0xee, 0x69, 0x8f, 0xc9, 0x20, 0xfc, 0x21, 0xaa, 0x07, 0x19, 0xed, 0xb0, 0x5c, 0xac,
+0x65, 0xc7, 0x5f, 0xed, 0x02, 0x7c, 0x7b, 0x7c, 0x2d, 0x1b, 0xd6, 0xba, 0xb9, 0x80, 0xc2, 0x18,
+0x82, 0x16, 0x84, 0xfa, 0x66, 0xb0, 0x08, 0xc6, 0x54, 0x23, 0x81, 0xe4, 0xcd, 0xb9, 0x49, 0x3f,
+0xf6, 0x4f, 0x6e, 0x37, 0x48, 0x28, 0x38, 0x0f, 0xc5, 0xbe, 0xe7, 0x68, 0x70, 0xfd, 0x39, 0x97,
+0x4d, 0xd2, 0xc7, 0x98, 0x91, 0x50, 0xaa, 0xc4, 0x44, 0xb3, 0x23, 0x7d, 0x39, 0x47, 0xe9, 0x52,
+0x62, 0xd6, 0x12, 0x93, 0x5e, 0xb7, 0x31, 0x96, 0x42, 0x05, 0xfb, 0x76, 0xa7, 0x1e, 0xa3, 0xf5,
+0xc2, 0xfc, 0xe9, 0x7a, 0xc5, 0x6c, 0xa9, 0x71, 0x4f, 0xea, 0xcb, 0x78, 0xbc, 0x60, 0xaf, 0xc7,
+0xde, 0xf4, 0xd9, 0xcb, 0xbe, 0x7e, 0x33, 0xa5, 0x6e, 0x94, 0x83, 0xf0, 0x34, 0xfa, 0x21, 0xab,
+0xea, 0x8e, 0x72, 0xa0, 0x3f, 0xa4, 0xde, 0x30, 0x5b, 0xef, 0x86, 0x4d, 0x6a, 0x95, 0x5b, 0x43,
+0x44, 0xa8, 0x10, 0x15, 0x1c, 0xe5, 0x01, 0x57, 0xc5, 0x98, 0xf1, 0xe6, 0x06, 0x28, 0x91, 0xaa,
+0x20, 0xc5, 0xb7, 0x53, 0x26, 0x51, 0x43, 0xb2, 0x0b, 0x11, 0x95, 0x58, 0xe1, 0xc0, 0x0f, 0x76,
+0xd9, 0xc0, 0x8d, 0x7c, 0x81, 0xf3, 0x72, 0x70, 0x9e, 0x6f, 0xfe, 0x1a, 0x8e, 0xd9, 0x5f, 0x35,
+0xc6, 0xb2, 0x6f, 0x34, 0x7c, 0xbe, 0x48, 0x4f, 0xe2, 0x5a, 0x39, 0xd7, 0xd8, 0x9d, 0x78, 0x9e,
+0x9f, 0x86, 0x3e, 0x03, 0x5e, 0x19, 0x8b, 0x44, 0xa2, 0xd5, 0xc7, 0x02, 0x03, 0x01, 0x00, 0x01,
+0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05,
+0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+0xbf, 0x59, 0x20, 0x36, 0x00, 0x79, 0xa0, 0xa0, 0x22, 0x6b, 0x8c, 0xd5, 0xf2, 0x61, 0xd2, 0xb8,
+0x2c, 0xcb, 0x82, 0x4a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x31, 0x03, 0xa2, 0x61, 0x0b, 0x1f, 0x74, 0xe8,
+0x72, 0x36, 0xc6, 0x6d, 0xf9, 0x4d, 0x9e, 0xfa, 0x22, 0xa8, 0xe1, 0x81, 0x56, 0xcf, 0xcd, 0xbb,
+0x9f, 0xea, 0xab, 0x91, 0x19, 0x38, 0xaf, 0xaa, 0x7c, 0x15, 0x4d, 0xf3, 0xb6, 0xa3, 0x8d, 0xa5,
+0xf4, 0x8e, 0xf6, 0x44, 0xa9, 0xa7, 0xe8, 0x21, 0x95, 0xad, 0x3e, 0x00, 0x62, 0x16, 0x88, 0xf0,
+0x02, 0xba, 0xfc, 0x61, 0x23, 0xe6, 0x33, 0x9b, 0x30, 0x7a, 0x6b, 0x36, 0x62, 0x7b, 0xad, 0x04,
+0x23, 0x84, 0x58, 0x65, 0xe2, 0xdb, 0x2b, 0x8a, 0xe7, 0x25, 0x53, 0x37, 0x62, 0x53, 0x5f, 0xbc,
+0xda, 0x01, 0x62, 0x29, 0xa2, 0xa6, 0x27, 0x71, 0xe6, 0x3a, 0x22, 0x7e, 0xc1, 0x6f, 0x1d, 0x95,
+0x70, 0x20, 0x4a, 0x07, 0x34, 0xdf, 0xea, 0xff, 0x15, 0x80, 0xe5, 0xba, 0xd7, 0x7a, 0xd8, 0x5b,
+0x75, 0x7c, 0x05, 0x7a, 0x29, 0x47, 0x7e, 0x40, 0xa8, 0x31, 0x13, 0x77, 0xcd, 0x40, 0x3b, 0xb4,
+0x51, 0x47, 0x7a, 0x2e, 0x11, 0xe3, 0x47, 0x11, 0xde, 0x9d, 0x66, 0xd0, 0x8b, 0xd5, 0x54, 0x66,
+0xfa, 0x83, 0x55, 0xea, 0x7c, 0xc2, 0x29, 0x89, 0x1b, 0xe9, 0x6f, 0xb3, 0xce, 0xe2, 0x05, 0x84,
+0xc9, 0x2f, 0x3e, 0x78, 0x85, 0x62, 0x6e, 0xc9, 0x5f, 0xc1, 0x78, 0x63, 0x74, 0x58, 0xc0, 0x48,
+0x18, 0x0c, 0x99, 0x39, 0xeb, 0xa4, 0xcc, 0x1a, 0xb5, 0x79, 0x5a, 0x8d, 0x15, 0x9c, 0xd8, 0x14,
+0x0d, 0xf6, 0x7a, 0x07, 0x57, 0xc7, 0x22, 0x83, 0x05, 0x2d, 0x3c, 0x9b, 0x25, 0x26, 0x3d, 0x18,
+0xb3, 0xa9, 0x43, 0x7c, 0xc8, 0xc8, 0xab, 0x64, 0x8f, 0x0e, 0xa3, 0xbf, 0x9c, 0x1b, 0x9d, 0x30,
+0xdb, 0xda, 0xd0, 0x19, 0x2e, 0xaa, 0x3c, 0xf1, 0xfb, 0x33, 0x80, 0x76, 0xe4, 0xcd, 0xad, 0x19,
+0x4f, 0x05, 0x27, 0x8e, 0x13, 0xa1, 0x6e, 0xc2, 0x30, 0x82, 0x03, 0xc3, 0x30, 0x82, 0x02, 0xab,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x0c, 0x22, 0x54, 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, 0x6e, 0x74, 0x65,
+0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20,
+0x47, 0x6d, 0x62, 0x48, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x16, 0x54,
+0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43,
+0x65, 0x6e, 0x74, 0x65, 0x72, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c,
+0x54, 0x2d, 0x54, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x30, 0x1e, 0x17, 0x0d,
+0x30, 0x38, 0x31, 0x30, 0x30, 0x31, 0x31, 0x30, 0x32, 0x39, 0x35, 0x36, 0x5a, 0x17, 0x0d, 0x33,
+0x33, 0x31, 0x30, 0x30, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0x82, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, 0x2b, 0x30, 0x29,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x22, 0x54, 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73,
+0x20, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76,
+0x69, 0x63, 0x65, 0x73, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x0c, 0x16, 0x54, 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x54, 0x72,
+0x75, 0x73, 0x74, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x0c, 0x1c, 0x54, 0x2d, 0x54, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x20, 0x47,
+0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20,
+0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01,
+0x01, 0x00, 0xbd, 0x75, 0x93, 0xf0, 0x62, 0x22, 0x6f, 0x24, 0xae, 0xe0, 0x7a, 0x76, 0xac, 0x7d,
+0xbd, 0xd9, 0x24, 0xd5, 0xb8, 0xb7, 0xfc, 0xcd, 0xf0, 0x42, 0xe0, 0xeb, 0x78, 0x88, 0x56, 0x5e,
+0x9b, 0x9a, 0x54, 0x1d, 0x4d, 0x0c, 0x8a, 0xf6, 0xd3, 0xcf, 0x70, 0xf4, 0x52, 0xb5, 0xd8, 0x93,
+0x04, 0xe3, 0x46, 0x86, 0x71, 0x41, 0x4a, 0x2b, 0xf0, 0x2a, 0x2c, 0x55, 0x03, 0xd6, 0x48, 0xc3,
+0xe0, 0x39, 0x38, 0xed, 0xf2, 0x5c, 0x3c, 0x3f, 0x44, 0xbc, 0x93, 0x3d, 0x61, 0xab, 0x4e, 0xcd,
+0x0d, 0xbe, 0xf0, 0x20, 0x27, 0x58, 0x0e, 0x44, 0x7f, 0x04, 0x1a, 0x87, 0xa5, 0xd7, 0x96, 0x14,
+0x36, 0x90, 0xd0, 0x49, 0x7b, 0xa1, 0x75, 0xfb, 0x1a, 0x6b, 0x73, 0xb1, 0xf8, 0xce, 0xa9, 0x09,
+0x2c, 0xf2, 0x53, 0xd5, 0xc3, 0x14, 0x44, 0xb8, 0x86, 0xa5, 0xf6, 0x8b, 0x2b, 0x39, 0xda, 0xa3,
+0x33, 0x54, 0xd9, 0xfa, 0x72, 0x1a, 0xf7, 0x22, 0x15, 0x1c, 0x88, 0x91, 0x6b, 0x7f, 0x66, 0xe5,
+0xc3, 0x6a, 0x80, 0xb0, 0x24, 0xf3, 0xdf, 0x86, 0x45, 0x88, 0xfd, 0x19, 0x7f, 0x75, 0x87, 0x1f,
+0x1f, 0xb1, 0x1b, 0x0a, 0x73, 0x24, 0x5b, 0xb9, 0x65, 0xe0, 0x2c, 0x54, 0xc8, 0x60, 0xd3, 0x66,
+0x17, 0x3f, 0xe1, 0xcc, 0x54, 0x33, 0x73, 0x91, 0x02, 0x3a, 0xa6, 0x7f, 0x7b, 0x76, 0x39, 0xa2,
+0x1f, 0x96, 0xb6, 0x38, 0xae, 0xb5, 0xc8, 0x93, 0x74, 0x1d, 0x9e, 0xb9, 0xb4, 0xe5, 0x60, 0x9d,
+0x2f, 0x56, 0xd1, 0xe0, 0xeb, 0x5e, 0x5b, 0x4c, 0x12, 0x70, 0x0c, 0x6c, 0x44, 0x20, 0xab, 0x11,
+0xd8, 0xf4, 0x19, 0xf6, 0xd2, 0x9c, 0x52, 0x37, 0xe7, 0xfa, 0xb6, 0xc2, 0x31, 0x3b, 0x4a, 0xd4,
+0x14, 0x99, 0xad, 0xc7, 0x1a, 0xf5, 0x5d, 0x5f, 0xfa, 0x07, 0xb8, 0x7c, 0x0d, 0x1f, 0xd6, 0x83,
+0x1e, 0xb3, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55,
+0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03,
+0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03,
+0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb5, 0x03, 0xf7, 0x76, 0x3b, 0x61, 0x82, 0x6a, 0x12,
+0xaa, 0x18, 0x53, 0xeb, 0x03, 0x21, 0x94, 0xbf, 0xfe, 0xce, 0xca, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x56,
+0x3d, 0xef, 0x94, 0xd5, 0xbd, 0xda, 0x73, 0xb2, 0x58, 0xbe, 0xae, 0x90, 0xad, 0x98, 0x27, 0x97,
+0xfe, 0x01, 0xb1, 0xb0, 0x52, 0x00, 0xb8, 0x4d, 0xe4, 0x1b, 0x21, 0x74, 0x1b, 0x7e, 0xc0, 0xee,
+0x5e, 0x69, 0x2a, 0x25, 0xaf, 0x5c, 0xd6, 0x1d, 0xda, 0xd2, 0x79, 0xc9, 0xf3, 0x97, 0x29, 0xe0,
+0x86, 0x87, 0xde, 0x04, 0x59, 0x0f, 0xf1, 0x59, 0xd4, 0x64, 0x85, 0x4b, 0x99, 0xaf, 0x25, 0x04,
+0x1e, 0xc9, 0x46, 0xa9, 0x97, 0xde, 0x82, 0xb2, 0x1b, 0x70, 0x9f, 0x9c, 0xf6, 0xaf, 0x71, 0x31,
+0xdd, 0x7b, 0x05, 0xa5, 0x2c, 0xd3, 0xb9, 0xca, 0x47, 0xf6, 0xca, 0xf2, 0xf6, 0xe7, 0xad, 0xb9,
+0x48, 0x3f, 0xbc, 0x16, 0xb7, 0xc1, 0x6d, 0xf4, 0xea, 0x09, 0xaf, 0xec, 0xf3, 0xb5, 0xe7, 0x05,
+0x9e, 0xa6, 0x1e, 0x8a, 0x53, 0x51, 0xd6, 0x93, 0x81, 0xcc, 0x74, 0x93, 0xf6, 0xb9, 0xda, 0xa6,
+0x25, 0x05, 0x74, 0x79, 0x5a, 0x7e, 0x40, 0x3e, 0x82, 0x4b, 0x26, 0x11, 0x30, 0x6e, 0xe1, 0x3f,
+0x41, 0xc7, 0x47, 0x00, 0x35, 0xd5, 0xf5, 0xd3, 0xf7, 0x54, 0x3e, 0x81, 0x3d, 0xda, 0x49, 0x6a,
+0x9a, 0xb3, 0xef, 0x10, 0x3d, 0xe6, 0xeb, 0x6f, 0xd1, 0xc8, 0x22, 0x47, 0xcb, 0xcc, 0xcf, 0x01,
+0x31, 0x92, 0xd9, 0x18, 0xe3, 0x22, 0xbe, 0x09, 0x1e, 0x1a, 0x3e, 0x5a, 0xb2, 0xe4, 0x6b, 0x0c,
+0x54, 0x7a, 0x7d, 0x43, 0x4e, 0xb8, 0x89, 0xa5, 0x7b, 0xd7, 0xa2, 0x3d, 0x96, 0x86, 0xcc, 0xf2,
+0x26, 0x34, 0x2d, 0x6a, 0x92, 0x9d, 0x9a, 0x1a, 0xd0, 0x30, 0xe2, 0x5d, 0x4e, 0x04, 0xb0, 0x5f,
+0x8b, 0x20, 0x7e, 0x77, 0xc1, 0x3d, 0x95, 0x82, 0xd1, 0x46, 0x9a, 0x3b, 0x3c, 0x78, 0xb8, 0x6f,
+0xa1, 0xd0, 0x0d, 0x64, 0xa2, 0x78, 0x1e, 0x29, 0x4e, 0x93, 0xc3, 0xa4, 0x54, 0x14, 0x5b, 0x30,
+0x82, 0x05, 0x41, 0x30, 0x82, 0x03, 0x29, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x0c, 0xbe,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+0x51, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54, 0x57, 0x31, 0x12,
+0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x54, 0x41, 0x49, 0x57, 0x41, 0x4e, 0x2d,
+0x43, 0x41, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, 0x6f,
+0x74, 0x20, 0x43, 0x41, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x54,
+0x57, 0x43, 0x41, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x36, 0x32, 0x37, 0x30, 0x36, 0x32, 0x38,
+0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31, 0x32, 0x33, 0x31, 0x31, 0x35, 0x35, 0x39, 0x35,
+0x39, 0x5a, 0x30, 0x51, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54,
+0x57, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x54, 0x41, 0x49, 0x57,
+0x41, 0x4e, 0x2d, 0x43, 0x41, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x13, 0x13, 0x54, 0x57, 0x43, 0x41, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
+0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb0, 0x05, 0xdb, 0xc8, 0xeb, 0x8c, 0xc4, 0x6e, 0x8a, 0x21,
+0xef, 0x8e, 0x4d, 0x9c, 0x71, 0x0a, 0x1f, 0x52, 0x70, 0xed, 0x6d, 0x82, 0x9c, 0x97, 0xc5, 0xd7,
+0x4c, 0x4e, 0x45, 0x49, 0xcb, 0x40, 0x42, 0xb5, 0x12, 0x34, 0x6c, 0x19, 0xc2, 0x74, 0xa4, 0x31,
+0x5f, 0x85, 0x02, 0x97, 0xec, 0x43, 0x33, 0x0a, 0x53, 0xd2, 0x9c, 0x8c, 0x8e, 0xb7, 0xb8, 0x79,
+0xdb, 0x2b, 0xd5, 0x6a, 0xf2, 0x8e, 0x66, 0xc4, 0xee, 0x2b, 0x01, 0x07, 0x92, 0xd4, 0xb3, 0xd0,
+0x02, 0xdf, 0x50, 0xf6, 0x55, 0xaf, 0x66, 0x0e, 0xcb, 0xe0, 0x47, 0x60, 0x2f, 0x2b, 0x32, 0x39,
+0x35, 0x52, 0x3a, 0x28, 0x83, 0xf8, 0x7b, 0x16, 0xc6, 0x18, 0xb8, 0x62, 0xd6, 0x47, 0x25, 0x91,
+0xce, 0xf0, 0x19, 0x12, 0x4d, 0xad, 0x63, 0xf5, 0xd3, 0x3f, 0x75, 0x5f, 0x29, 0xf0, 0xa1, 0x30,
+0x1c, 0x2a, 0xa0, 0x98, 0xa6, 0x15, 0xbd, 0xee, 0xfd, 0x19, 0x36, 0xf0, 0xe2, 0x91, 0x43, 0x8f,
+0xfa, 0xca, 0xd6, 0x10, 0x27, 0x49, 0x4c, 0xef, 0xdd, 0xc1, 0xf1, 0x85, 0x70, 0x9b, 0xca, 0xea,
+0xa8, 0x5a, 0x43, 0xfc, 0x6d, 0x86, 0x6f, 0x73, 0xe9, 0x37, 0x45, 0xa9, 0xf0, 0x36, 0xc7, 0xcc,
+0x88, 0x75, 0x1e, 0xbb, 0x6c, 0x06, 0xff, 0x9b, 0x6b, 0x3e, 0x17, 0xec, 0x61, 0xaa, 0x71, 0x7c,
+0xc6, 0x1d, 0xa2, 0xf7, 0x49, 0xe9, 0x15, 0xb5, 0x3c, 0xd6, 0xa1, 0x61, 0xf5, 0x11, 0xf7, 0x05,
+0x6f, 0x1d, 0xfd, 0x11, 0xbe, 0xd0, 0x30, 0x07, 0xc2, 0x29, 0xb0, 0x09, 0x4e, 0x26, 0xdc, 0xe3,
+0xa2, 0xa8, 0x91, 0x6a, 0x1f, 0xc2, 0x91, 0x45, 0x88, 0x5c, 0xe5, 0x98, 0xb8, 0x71, 0xa5, 0x15,
+0x19, 0xc9, 0x7c, 0x75, 0x11, 0xcc, 0x70, 0x74, 0x4f, 0x2d, 0x9b, 0x1d, 0x91, 0x44, 0xfd, 0x56,
+0x28, 0xa0, 0xfe, 0xbb, 0x86, 0x6a, 0xc8, 0xfa, 0x5c, 0x0b, 0x58, 0xdc, 0xc6, 0x4b, 0x76, 0xc8,
+0xab, 0x22, 0xd9, 0x73, 0x0f, 0xa5, 0xf4, 0x5a, 0x02, 0x89, 0x3f, 0x4f, 0x9e, 0x22, 0x82, 0xee,
+0xa2, 0x74, 0x53, 0x2a, 0x3d, 0x53, 0x27, 0x69, 0x1d, 0x6c, 0x8e, 0x32, 0x2c, 0x64, 0x00, 0x26,
+0x63, 0x61, 0x36, 0x4e, 0xa3, 0x46, 0xb7, 0x3f, 0x7d, 0xb3, 0x2d, 0xac, 0x6d, 0x90, 0xa2, 0x95,
+0xa2, 0xce, 0xcf, 0xda, 0x82, 0xe7, 0x07, 0x34, 0x19, 0x96, 0xe9, 0xb8, 0x21, 0xaa, 0x29, 0x7e,
+0xa6, 0x38, 0xbe, 0x8e, 0x29, 0x4a, 0x21, 0x66, 0x79, 0x1f, 0xb3, 0xc3, 0xb5, 0x09, 0x67, 0xde,
+0xd6, 0xd4, 0x07, 0x46, 0xf3, 0x2a, 0xda, 0xe6, 0x22, 0x37, 0x60, 0xcb, 0x81, 0xb6, 0x0f, 0xa0,
+0x0f, 0xe9, 0xc8, 0x95, 0x7f, 0xbf, 0x55, 0x91, 0x05, 0x7a, 0xcf, 0x3d, 0x15, 0xc0, 0x6f, 0xde,
+0x09, 0x94, 0x01, 0x83, 0xd7, 0x34, 0x1b, 0xcc, 0x40, 0xa5, 0xf0, 0xb8, 0x9b, 0x67, 0xd5, 0x98,
+0x91, 0x3b, 0xa7, 0x84, 0x78, 0x95, 0x26, 0xa4, 0x5a, 0x08, 0xf8, 0x2b, 0x74, 0xb4, 0x00, 0x04,
+0x3c, 0xdf, 0xb8, 0x14, 0x8e, 0xe8, 0xdf, 0xa9, 0x8d, 0x6c, 0x67, 0x92, 0x33, 0x1d, 0xc0, 0xb7,
+0xd2, 0xec, 0x92, 0xc8, 0xbe, 0x09, 0xbf, 0x2c, 0x29, 0x05, 0x6f, 0x02, 0x6b, 0x9e, 0xef, 0xbc,
+0xbf, 0x2a, 0xbc, 0x5b, 0xc0, 0x50, 0x8f, 0x41, 0x70, 0x71, 0x87, 0xb2, 0x4d, 0xb7, 0x04, 0xa9,
+0x84, 0xa3, 0x32, 0xaf, 0xae, 0xee, 0x6b, 0x17, 0x8b, 0xb2, 0xb1, 0xfe, 0x6c, 0xe1, 0x90, 0x8c,
+0x88, 0xa8, 0x97, 0x48, 0xce, 0xc8, 0x4d, 0xcb, 0xf3, 0x06, 0xcf, 0x5f, 0x6a, 0x0a, 0x42, 0xb1,
+0x1e, 0x1e, 0x77, 0x2f, 0x8e, 0xa0, 0xe6, 0x92, 0x0e, 0x06, 0xfc, 0x05, 0x22, 0xd2, 0x26, 0xe1,
+0x31, 0x51, 0x7d, 0x32, 0xdc, 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
+0x82, 0x02, 0x01, 0x00, 0x5f, 0x34, 0x81, 0x76, 0xef, 0x96, 0x1d, 0xd5, 0xe5, 0xb5, 0xd9, 0x02,
+0x63, 0x84, 0x16, 0xc1, 0xae, 0xa0, 0x70, 0x51, 0xa7, 0xf7, 0x4c, 0x47, 0x35, 0xc8, 0x0b, 0xd7,
+0x28, 0x3d, 0x89, 0x71, 0xd9, 0xaa, 0x33, 0x41, 0xea, 0x14, 0x1b, 0x6c, 0x21, 0x00, 0xc0, 0x6c,
+0x42, 0x19, 0x7e, 0x9f, 0x69, 0x5b, 0x20, 0x42, 0xdf, 0xa2, 0xd2, 0xda, 0xc4, 0x7c, 0x97, 0x4b,
+0x8d, 0xb0, 0xe8, 0xac, 0xc8, 0xee, 0xa5, 0x69, 0x04, 0x99, 0x0a, 0x92, 0xa6, 0xab, 0x27, 0x2e,
+0x1a, 0x4d, 0x81, 0xbf, 0x84, 0xd4, 0x70, 0x1e, 0xad, 0x47, 0xfe, 0xfd, 0x4a, 0x9d, 0x33, 0xe0,
+0xf2, 0xb9, 0xc4, 0x45, 0x08, 0x21, 0x0a, 0xda, 0x69, 0x69, 0x73, 0x72, 0x0d, 0xbe, 0x34, 0xfe,
+0x94, 0x8b, 0xad, 0xc3, 0x1e, 0x35, 0xd7, 0xa2, 0x83, 0xef, 0xe5, 0x38, 0xc7, 0xa5, 0x85, 0x1f,
+0xab, 0xcf, 0x34, 0xec, 0x3f, 0x28, 0xfe, 0x0c, 0xf1, 0x57, 0x86, 0x4e, 0xc9, 0x55, 0xf7, 0x1c,
+0xd4, 0xd8, 0xa5, 0x7d, 0x06, 0x7a, 0x6f, 0xd5, 0xdf, 0x10, 0xdf, 0x81, 0x4e, 0x21, 0x65, 0xb1,
+0xb6, 0xe1, 0x17, 0x79, 0x95, 0x45, 0x06, 0xce, 0x5f, 0xcc, 0xdc, 0x46, 0x89, 0x63, 0x68, 0x44,
+0x8d, 0x93, 0xf4, 0x64, 0x70, 0xa0, 0x3d, 0x9d, 0x28, 0x05, 0xc3, 0x39, 0x70, 0xb8, 0x62, 0x7b,
+0x20, 0xfd, 0xe4, 0xdb, 0xe9, 0x08, 0xa1, 0xb8, 0x9e, 0x3d, 0x09, 0xc7, 0x4f, 0xfb, 0x2c, 0xf8,
+0x93, 0x76, 0x41, 0xde, 0x52, 0xe0, 0xe1, 0x57, 0xd2, 0x9d, 0x03, 0xbc, 0x77, 0x9e, 0xfe, 0x9e,
+0x29, 0x5e, 0xf7, 0xc1, 0x51, 0x60, 0x1f, 0xde, 0xda, 0x0b, 0xb2, 0x2d, 0x75, 0xb7, 0x43, 0x48,
+0x93, 0xe7, 0xf6, 0x79, 0xc6, 0x84, 0x5d, 0x80, 0x59, 0x60, 0x94, 0xfc, 0x78, 0x98, 0x8f, 0x3c,
+0x93, 0x51, 0xed, 0x40, 0x90, 0x07, 0xdf, 0x64, 0x63, 0x24, 0xcb, 0x4e, 0x71, 0x05, 0xa1, 0xd7,
+0x94, 0x1a, 0x88, 0x32, 0xf1, 0x22, 0x74, 0x22, 0xae, 0xa5, 0xa6, 0xd8, 0x12, 0x69, 0x4c, 0x60,
+0xa3, 0x02, 0xee, 0x2b, 0xec, 0xd4, 0x63, 0x92, 0x0b, 0x5e, 0xbe, 0x2f, 0x76, 0x6b, 0xa3, 0xb6,
+0x26, 0xbc, 0x8f, 0x03, 0xd8, 0x0a, 0xf2, 0x4c, 0x64, 0x46, 0xbd, 0x39, 0x62, 0xe5, 0x96, 0xeb,
+0x34, 0x63, 0x11, 0x28, 0xcc, 0x95, 0xf1, 0xad, 0xef, 0xef, 0xdc, 0x80, 0x58, 0x48, 0xe9, 0x4b,
+0xb8, 0xea, 0x65, 0xac, 0xe9, 0xfc, 0x80, 0xb5, 0xb5, 0xc8, 0x45, 0xf9, 0xac, 0xc1, 0x9f, 0xd9,
+0xb9, 0xea, 0x62, 0x88, 0x8e, 0xc4, 0xf1, 0x4b, 0x83, 0x12, 0xad, 0xe6, 0x8b, 0x84, 0xd6, 0x9e,
+0xc2, 0xeb, 0x83, 0x18, 0x9f, 0x6a, 0xbb, 0x1b, 0x24, 0x60, 0x33, 0x70, 0xcc, 0xec, 0xf7, 0x32,
+0xf3, 0x5c, 0xd9, 0x79, 0x7d, 0xef, 0x9e, 0xa4, 0xfe, 0xc9, 0x23, 0xc3, 0x24, 0xee, 0x15, 0x92,
+0xb1, 0x3d, 0x91, 0x4f, 0x26, 0x86, 0xbd, 0x66, 0x73, 0x24, 0x13, 0xea, 0xa4, 0xae, 0x63, 0xc1,
+0xad, 0x7d, 0x84, 0x03, 0x3c, 0x10, 0x78, 0x86, 0x1b, 0x79, 0xe3, 0xc4, 0xf3, 0xf2, 0x04, 0x95,
+0x20, 0xae, 0x23, 0x82, 0xc4, 0xb3, 0x3a, 0x00, 0x62, 0xbf, 0xe6, 0x36, 0x24, 0xe1, 0x57, 0xba,
+0xc7, 0x1e, 0x90, 0x75, 0xd5, 0x5f, 0x3f, 0x95, 0x61, 0x2b, 0xc1, 0x3b, 0xcd, 0xe5, 0xb3, 0x68,
+0x61, 0xd0, 0x46, 0x26, 0xa9, 0x21, 0x52, 0x69, 0x2d, 0xeb, 0x2e, 0xc7, 0xeb, 0x77, 0xce, 0xa6,
+0x3a, 0xb5, 0x03, 0x33, 0x4f, 0x76, 0xd1, 0xe7, 0x5c, 0x54, 0x01, 0x5d, 0xcb, 0x78, 0xf4, 0xc9,
+0x0c, 0xbf, 0xcf, 0x12, 0x8e, 0x17, 0x2d, 0x23, 0x68, 0x94, 0xe7, 0xab, 0xfe, 0xa9, 0xb2, 0x2b,
+0x06, 0xd0, 0x04, 0xcd, 0x30, 0x82, 0x03, 0x7b, 0x30, 0x82, 0x02, 0x63, 0xa0, 0x03, 0x02, 0x01,
+0x02, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x05, 0x05, 0x00, 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x54, 0x57, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x54, 0x41, 0x49,
+0x57, 0x41, 0x4e, 0x2d, 0x43, 0x41, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
+0x07, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x0c, 0x21, 0x54, 0x57, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x38, 0x32, 0x38, 0x30, 0x37,
+0x32, 0x34, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x31, 0x32, 0x33, 0x31, 0x31, 0x35, 0x35,
+0x39, 0x35, 0x39, 0x5a, 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x54, 0x57, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x54, 0x41,
+0x49, 0x57, 0x41, 0x4e, 0x2d, 0x43, 0x41, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x0c, 0x07, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x0c, 0x21, 0x54, 0x57, 0x43, 0x41, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65,
+0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
+0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb0, 0x7e, 0x72, 0xb8, 0xa4, 0x03, 0x94, 0xe6, 0xa7, 0xde,
+0x09, 0x38, 0x91, 0x4a, 0x11, 0x40, 0x87, 0xa7, 0x7c, 0x59, 0x64, 0x14, 0x7b, 0xb5, 0x11, 0x10,
+0xdd, 0xfe, 0xbf, 0xd5, 0xc0, 0xbb, 0x56, 0xe2, 0x85, 0x25, 0xf4, 0x35, 0x72, 0x0f, 0xf8, 0x53,
+0xd0, 0x41, 0xe1, 0x44, 0x01, 0xc2, 0xb4, 0x1c, 0xc3, 0x31, 0x42, 0x16, 0x47, 0x85, 0x33, 0x22,
+0x76, 0xb2, 0x0a, 0x6f, 0x0f, 0xe5, 0x25, 0x50, 0x4f, 0x85, 0x86, 0xbe, 0xbf, 0x98, 0x2e, 0x10,
+0x67, 0x1e, 0xbe, 0x11, 0x05, 0x86, 0x05, 0x90, 0xc4, 0x59, 0xd0, 0x7c, 0x78, 0x10, 0xb0, 0x80,
+0x5c, 0xb7, 0xe1, 0xc7, 0x2b, 0x75, 0xcb, 0x7c, 0x9f, 0xae, 0xb5, 0xd1, 0x9d, 0x23, 0x37, 0x63,
+0xa7, 0xdc, 0x42, 0xa2, 0x2d, 0x92, 0x04, 0x1b, 0x50, 0xc1, 0x7b, 0xb8, 0x3e, 0x1b, 0xc9, 0x56,
+0x04, 0x8b, 0x2f, 0x52, 0x9b, 0xad, 0xa9, 0x56, 0xe9, 0xc1, 0xff, 0xad, 0xa9, 0x58, 0x87, 0x30,
+0xb6, 0x81, 0xf7, 0x97, 0x45, 0xfc, 0x19, 0x57, 0x3b, 0x2b, 0x6f, 0xe4, 0x47, 0xf4, 0x99, 0x45,
+0xfe, 0x1d, 0xf1, 0xf8, 0x97, 0xa3, 0x88, 0x1d, 0x37, 0x1c, 0x5c, 0x8f, 0xe0, 0x76, 0x25, 0x9a,
+0x50, 0xf8, 0xa0, 0x54, 0xff, 0x44, 0x90, 0x76, 0x23, 0xd2, 0x32, 0xc6, 0xc3, 0xab, 0x06, 0xbf,
+0xfc, 0xfb, 0xbf, 0xf3, 0xad, 0x7d, 0x92, 0x62, 0x02, 0x5b, 0x29, 0xd3, 0x35, 0xa3, 0x93, 0x9a,
+0x43, 0x64, 0x60, 0x5d, 0xb2, 0xfa, 0x32, 0xff, 0x3b, 0x04, 0xaf, 0x4d, 0x40, 0x6a, 0xf9, 0xc7,
+0xe3, 0xef, 0x23, 0xfd, 0x6b, 0xcb, 0xe5, 0x0f, 0x8b, 0x38, 0x0d, 0xee, 0x0a, 0xfc, 0xfe, 0x0f,
+0x98, 0x9f, 0x30, 0x31, 0xdd, 0x6c, 0x52, 0x65, 0xf9, 0x8b, 0x81, 0xbe, 0x22, 0xe1, 0x1c, 0x58,
+0x03, 0xba, 0x91, 0x1b, 0x89, 0x07, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6a, 0x38, 0x5b, 0x26, 0x8d,
+0xde, 0x8b, 0x5a, 0xf2, 0x4f, 0x7a, 0x54, 0x83, 0x19, 0x18, 0xe3, 0x08, 0x35, 0xa6, 0xba, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
+0x01, 0x01, 0x00, 0x3c, 0xd5, 0x77, 0x3d, 0xda, 0xdf, 0x89, 0xba, 0x87, 0x0c, 0x08, 0x54, 0x6a,
+0x20, 0x50, 0x92, 0xbe, 0xb0, 0x41, 0x3d, 0xb9, 0x26, 0x64, 0x83, 0x0a, 0x2f, 0xe8, 0x40, 0xc0,
+0x97, 0x28, 0x27, 0x82, 0x30, 0x4a, 0xc9, 0x93, 0xff, 0x6a, 0xe7, 0xa6, 0x00, 0x7f, 0x89, 0x42,
+0x9a, 0xd6, 0x11, 0xe5, 0x53, 0xce, 0x2f, 0xcc, 0xf2, 0xda, 0x05, 0xc4, 0xfe, 0xe2, 0x50, 0xc4,
+0x3a, 0x86, 0x7d, 0xcc, 0xda, 0x7e, 0x10, 0x09, 0x3b, 0x92, 0x35, 0x2a, 0x53, 0xb2, 0xfe, 0xeb,
+0x2b, 0x05, 0xd9, 0x6c, 0x5d, 0xe6, 0xd0, 0xef, 0xd3, 0x6a, 0x66, 0x9e, 0x15, 0x28, 0x85, 0x7a,
+0xe8, 0x82, 0x00, 0xac, 0x1e, 0xa7, 0x09, 0x69, 0x56, 0x42, 0xd3, 0x68, 0x51, 0x18, 0xbe, 0x54,
+0x9a, 0xbf, 0x44, 0x41, 0xba, 0x49, 0xbe, 0x20, 0xba, 0x69, 0x5c, 0xee, 0xb8, 0x77, 0xcd, 0xce,
+0x6c, 0x1f, 0xad, 0x83, 0x96, 0x18, 0x7d, 0x0e, 0xb5, 0x14, 0x39, 0x84, 0xf1, 0x28, 0xe9, 0x2d,
+0xa3, 0x9e, 0x7b, 0x1e, 0x7a, 0x72, 0x5a, 0x83, 0xb3, 0x79, 0x6f, 0xef, 0xb4, 0xfc, 0xd0, 0x0a,
+0xa5, 0x58, 0x4f, 0x46, 0xdf, 0xfb, 0x6d, 0x79, 0x59, 0xf2, 0x84, 0x22, 0x52, 0xae, 0x0f, 0xcc,
+0xfb, 0x7c, 0x3b, 0xe7, 0x6a, 0xca, 0x47, 0x61, 0xc3, 0x7a, 0xf8, 0xd3, 0x92, 0x04, 0x1f, 0xb8,
+0x20, 0x84, 0xe1, 0x36, 0x54, 0x16, 0xc7, 0x40, 0xde, 0x3b, 0x8a, 0x73, 0xdc, 0xdf, 0xc6, 0x09,
+0x4c, 0xdf, 0xec, 0xda, 0xff, 0xd4, 0x53, 0x42, 0xa1, 0xc9, 0xf2, 0x62, 0x1d, 0x22, 0x83, 0x3c,
+0x97, 0xc5, 0xf9, 0x19, 0x62, 0x27, 0xac, 0x65, 0x22, 0xd7, 0xd3, 0x3c, 0xc6, 0xe5, 0x8e, 0xb2,
+0x53, 0xcc, 0x49, 0xce, 0xbc, 0x30, 0xfe, 0x7b, 0x0e, 0x33, 0x90, 0xfb, 0xed, 0xd2, 0x14, 0x91,
+0x1f, 0x07, 0xaf, 0x30, 0x82, 0x05, 0xa2, 0x30, 0x82, 0x03, 0x8a, 0xa0, 0x03, 0x02, 0x01, 0x02,
+0x02, 0x14, 0x01, 0x94, 0x30, 0x1e, 0xa2, 0x0b, 0xdd, 0xf5, 0xc5, 0x33, 0x2a, 0xb1, 0x43, 0x44,
+0x71, 0xf8, 0xd6, 0x50, 0x4d, 0x0d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x0c, 0x05, 0x00, 0x30, 0x69, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x4b, 0x52, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1d, 0x4e,
+0x41, 0x56, 0x45, 0x52, 0x20, 0x42, 0x55, 0x53, 0x49, 0x4e, 0x45, 0x53, 0x53, 0x20, 0x50, 0x4c,
+0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x2e, 0x31, 0x32, 0x30, 0x30,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x29, 0x4e, 0x41, 0x56, 0x45, 0x52, 0x20, 0x47, 0x6c, 0x6f,
+0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x38, 0x31, 0x38, 0x30, 0x38, 0x35, 0x38, 0x34, 0x32,
+0x5a, 0x17, 0x0d, 0x33, 0x37, 0x30, 0x38, 0x31, 0x38, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a,
+0x30, 0x69, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4b, 0x52, 0x31,
+0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x1d, 0x4e, 0x41, 0x56, 0x45, 0x52, 0x20,
+0x42, 0x55, 0x53, 0x49, 0x4e, 0x45, 0x53, 0x53, 0x20, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52,
+0x4d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03,
+0x0c, 0x29, 0x4e, 0x41, 0x56, 0x45, 0x52, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52,
+0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x02, 0x22, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
+0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb6, 0xd4, 0xf1, 0x93,
+0x5c, 0xb5, 0x40, 0x89, 0x0a, 0xab, 0x0d, 0x90, 0x5b, 0x50, 0x63, 0xae, 0x90, 0x94, 0x74, 0x17,
+0x45, 0x72, 0xd6, 0x7b, 0x65, 0x5a, 0x29, 0x4b, 0xa7, 0x56, 0xa0, 0x4b, 0xb8, 0x2f, 0x42, 0x75,
+0xe9, 0xd9, 0x7b, 0x24, 0x5a, 0x31, 0x65, 0xab, 0x17, 0x17, 0xd1, 0x33, 0x3a, 0xd9, 0x11, 0xdc,
+0x40, 0x36, 0x87, 0xdf, 0xc7, 0x6a, 0xe9, 0x26, 0x5e, 0x59, 0x8a, 0x77, 0xe3, 0xe8, 0x48, 0x9c,
+0x31, 0x16, 0xfa, 0x3e, 0x91, 0xb1, 0xca, 0xc9, 0xa3, 0xe2, 0x9f, 0xce, 0x21, 0x53, 0xa3, 0x02,
+0x36, 0x30, 0xcb, 0x52, 0x02, 0xe5, 0xda, 0x32, 0x5d, 0xc3, 0xc5, 0xe6, 0xf9, 0xee, 0x11, 0xc7,
+0x8b, 0xc9, 0x44, 0x1e, 0x84, 0x93, 0x18, 0x4a, 0xb4, 0x9f, 0xe5, 0x12, 0x64, 0x69, 0xd0, 0x26,
+0x85, 0x62, 0x01, 0xb6, 0xc9, 0x02, 0x1d, 0xbe, 0x83, 0x51, 0xbb, 0x5c, 0xda, 0xf8, 0xad, 0x15,
+0x6a, 0x99, 0xf7, 0x92, 0x54, 0xf7, 0x34, 0x5b, 0xe9, 0xbf, 0xea, 0x29, 0x81, 0x12, 0xd4, 0x53,
+0x91, 0x96, 0xb3, 0x91, 0x5a, 0xdd, 0xfe, 0x90, 0x73, 0x28, 0xfb, 0x30, 0x46, 0xb5, 0xca, 0x08,
+0x07, 0xc7, 0x71, 0x72, 0xc9, 0x66, 0xd3, 0x34, 0x97, 0xf6, 0x8c, 0xf4, 0x18, 0x4a, 0xe1, 0xd0,
+0x3d, 0x5a, 0x45, 0xb6, 0x69, 0xa7, 0x29, 0xfb, 0x23, 0xce, 0x88, 0xd8, 0x12, 0x9c, 0x00, 0x48,
+0xa8, 0xa6, 0x0f, 0xb3, 0x3b, 0x92, 0x8d, 0x71, 0x0e, 0x74, 0xc5, 0x8b, 0xc8, 0x4c, 0xf9, 0xf4,
+0x9b, 0x8e, 0xb8, 0x3c, 0x69, 0xed, 0x6f, 0x3b, 0x50, 0x2f, 0x58, 0xed, 0xc4, 0xb0, 0xd0, 0x1c,
+0x1b, 0x6a, 0x0c, 0xe2, 0xbc, 0x44, 0xaa, 0xd8, 0xcd, 0x14, 0x5d, 0x94, 0x78, 0x61, 0xbf, 0x0e,
+0x6e, 0xda, 0x2a, 0xbc, 0x2f, 0x0c, 0x0b, 0x71, 0xa6, 0xb3, 0x16, 0x3f, 0x9c, 0xe6, 0xf9, 0xcc,
+0x9f, 0x53, 0x35, 0xe2, 0x03, 0xa0, 0xa0, 0x18, 0xbf, 0xbb, 0xf1, 0xbe, 0xf4, 0xd6, 0x8c, 0x87,
+0x0d, 0x42, 0xf7, 0x06, 0xb9, 0xf1, 0x6d, 0xed, 0x04, 0x94, 0xa8, 0xfe, 0xb6, 0xd3, 0x06, 0xc6,
+0x40, 0x61, 0xdf, 0x9d, 0x9d, 0xf3, 0x54, 0x76, 0xce, 0x53, 0x3a, 0x01, 0xa6, 0x92, 0x41, 0xec,
+0x04, 0xa3, 0x8f, 0x0d, 0xa2, 0xd5, 0x09, 0xca, 0xd6, 0xcb, 0x9a, 0xf1, 0xef, 0x43, 0x5d, 0xc0,
+0xab, 0xa5, 0x41, 0xcf, 0x5c, 0x53, 0x70, 0x70, 0xc9, 0x88, 0xa6, 0x2d, 0xd4, 0x6b, 0x61, 0x73,
+0x50, 0x26, 0x86, 0x61, 0x0e, 0x5f, 0x1b, 0xc2, 0x2b, 0xe2, 0x8c, 0xd5, 0xbb, 0x9d, 0xc1, 0x03,
+0x42, 0xba, 0x94, 0xda, 0x5f, 0xa9, 0xb0, 0xca, 0xcc, 0x4d, 0x0a, 0xef, 0x47, 0x69, 0x03, 0x2f,
+0x22, 0xfb, 0xf1, 0x28, 0xce, 0xbf, 0x5d, 0x50, 0x65, 0xa8, 0x90, 0x6d, 0xb3, 0x74, 0xb0, 0x08,
+0xc7, 0xac, 0xa8, 0xd1, 0xeb, 0x3e, 0x9c, 0xfc, 0x5d, 0x1a, 0x83, 0x2e, 0x2b, 0xcb, 0xb5, 0xf3,
+0x44, 0x9d, 0x3a, 0xa7, 0x17, 0x61, 0x96, 0xa2, 0x71, 0xd3, 0x70, 0x96, 0x15, 0x4d, 0xb7, 0x4c,
+0x73, 0xee, 0x19, 0x5c, 0xc5, 0x5b, 0x3e, 0x41, 0xfe, 0xac, 0x75, 0x60, 0x3b, 0x1b, 0x63, 0xce,
+0x00, 0xdd, 0xda, 0x08, 0x90, 0x62, 0xb4, 0xe5, 0x2d, 0xee, 0x48, 0xa7, 0x6b, 0x17, 0x99, 0x54,
+0xbe, 0x87, 0x4a, 0xe3, 0xa9, 0x5e, 0x04, 0x4c, 0xeb, 0x10, 0x6d, 0x54, 0xd6, 0xef, 0xf1, 0xe8,
+0xf2, 0x62, 0x16, 0xcb, 0x80, 0x6b, 0xed, 0x3d, 0xed, 0xf5, 0x1f, 0x30, 0xa5, 0xae, 0x4b, 0xc9,
+0x13, 0xed, 0x8a, 0x01, 0x01, 0xc9, 0xb8, 0x51, 0x58, 0xc0, 0x66, 0x3a, 0xb1, 0x66, 0x4b, 0xc4,
+0xd5, 0x31, 0x02, 0x62, 0xe9, 0x74, 0x84, 0x0c, 0xdb, 0x4d, 0x46, 0x2d, 0x02, 0x03, 0x01, 0x00,
+0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+0xd2, 0x9f, 0x88, 0xdf, 0xa1, 0xcd, 0x2c, 0xbd, 0xec, 0xf5, 0x3b, 0x01, 0x01, 0x93, 0x33, 0x27,
+0xb2, 0xeb, 0x60, 0x4b, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05,
+0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x0c, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x32, 0xca, 0x80, 0xb3, 0x9d, 0x3d, 0x54,
+0x06, 0xdd, 0xd2, 0xd2, 0x2e, 0xf0, 0xa4, 0x01, 0x21, 0x0b, 0x67, 0x48, 0xca, 0x6d, 0x8e, 0xe0,
+0xc8, 0xaa, 0x0d, 0xaa, 0x8d, 0x21, 0x57, 0x8f, 0xc6, 0x3e, 0x7a, 0xca, 0xdb, 0x51, 0xd4, 0x52,
+0xb3, 0xd4, 0x96, 0x84, 0xa5, 0x58, 0x60, 0x7f, 0xe5, 0x0b, 0x8e, 0x1f, 0xf5, 0xdc, 0x0a, 0x15,
+0x81, 0xe5, 0x3b, 0xb6, 0xb7, 0x22, 0x2f, 0x09, 0x9c, 0x13, 0x16, 0xb1, 0x6c, 0x0c, 0x35, 0x08,
+0x6d, 0xab, 0x63, 0x72, 0xed, 0xdc, 0xbe, 0xec, 0xc7, 0x57, 0xe6, 0x30, 0x20, 0x71, 0xd6, 0xd7,
+0x10, 0xc1, 0x13, 0x55, 0x01, 0x8c, 0x2a, 0x43, 0xe4, 0x41, 0xf1, 0xcf, 0x3a, 0x7a, 0x53, 0x92,
+0xce, 0xa2, 0x03, 0x05, 0x0d, 0x38, 0xdf, 0x02, 0xbb, 0x10, 0x2e, 0xd9, 0x3b, 0xd2, 0x9b, 0x7a,
+0xc0, 0xa1, 0xa6, 0xf8, 0xb5, 0x31, 0xe6, 0xf4, 0x75, 0xc9, 0xb9, 0x53, 0x99, 0x75, 0x47, 0x22,
+0x5a, 0x14, 0x15, 0xc7, 0x78, 0x1b, 0xb6, 0x9d, 0xe9, 0x0c, 0xf8, 0x1b, 0x76, 0xf1, 0x85, 0x84,
+0xde, 0xa1, 0xda, 0x12, 0xef, 0xa4, 0xe2, 0x10, 0x97, 0x7a, 0x78, 0xde, 0x0c, 0x51, 0x97, 0xa8,
+0x21, 0x40, 0x8b, 0x86, 0xbd, 0x0d, 0xf0, 0x5e, 0x4e, 0x4b, 0x36, 0xbb, 0x3b, 0x20, 0x1f, 0x8a,
+0x42, 0x56, 0xe1, 0x0b, 0x1a, 0xbf, 0x7b, 0xd0, 0x22, 0x43, 0x2c, 0x44, 0x8c, 0xfb, 0xe5, 0x2a,
+0xb4, 0x6c, 0x1c, 0x1c, 0xba, 0x94, 0xe0, 0x13, 0x7e, 0x21, 0xe6, 0x9a, 0xc2, 0xcb, 0xc5, 0x42,
+0x64, 0xb4, 0x1e, 0x94, 0x7b, 0x08, 0x25, 0xc8, 0x71, 0xcc, 0x87, 0x45, 0x57, 0x85, 0xd3, 0x9f,
+0x29, 0x62, 0x22, 0x83, 0x51, 0x97, 0x00, 0x18, 0x97, 0x77, 0x6a, 0x98, 0x92, 0xc9, 0x7c, 0x60,
+0x6c, 0xdf, 0x6c, 0x7d, 0x4a, 0xe4, 0x70, 0x4c, 0xc2, 0x9e, 0xb8, 0x1d, 0xf7, 0xd0, 0x34, 0xc7,
+0x0f, 0xcc, 0xfb, 0xa7, 0xff, 0x03, 0xbe, 0xad, 0x70, 0x90, 0xda, 0x0b, 0xdd, 0xc8, 0x6d, 0x97,
+0x5f, 0x9a, 0x7f, 0x09, 0x32, 0x41, 0xfd, 0xcd, 0xa2, 0xcc, 0x5a, 0x6d, 0x4c, 0xf2, 0xaa, 0x49,
+0xfe, 0x66, 0xf8, 0xe9, 0xd8, 0x35, 0xeb, 0x0e, 0x28, 0x1e, 0xee, 0x48, 0x2f, 0x3a, 0xd0, 0x79,
+0x09, 0x38, 0x7c, 0xa6, 0x22, 0x82, 0x93, 0x95, 0xd0, 0x03, 0xbe, 0xbe, 0x02, 0xa0, 0x05, 0xdd,
+0x20, 0x22, 0xe3, 0x6f, 0x1d, 0x88, 0x34, 0x60, 0xc6, 0xe6, 0x0a, 0xb9, 0x09, 0x75, 0x0b, 0xf0,
+0x07, 0xe8, 0x69, 0x96, 0x35, 0xc7, 0xfb, 0x23, 0x81, 0x8e, 0x38, 0x39, 0xb8, 0x45, 0x2b, 0x43,
+0x78, 0xa2, 0xd1, 0x2c, 0x14, 0xff, 0x0d, 0x28, 0x72, 0x72, 0x95, 0x9b, 0x5e, 0x09, 0xdb, 0x89,
+0x44, 0x98, 0xaa, 0xa1, 0x49, 0xbb, 0x71, 0x52, 0xf2, 0xbf, 0xf6, 0xff, 0x27, 0xa1, 0x36, 0xaf,
+0xb8, 0xb6, 0x77, 0x88, 0xdd, 0x3a, 0xa4, 0x6d, 0x9b, 0x34, 0x90, 0xdc, 0x14, 0x5d, 0x30, 0xbf,
+0xb7, 0xeb, 0x17, 0xe4, 0x87, 0xb7, 0x71, 0xd0, 0xa1, 0xd7, 0x77, 0x15, 0xd4, 0x42, 0xd7, 0xf2,
+0xf3, 0x31, 0x99, 0x5d, 0x9b, 0xdd, 0x16, 0x6d, 0x3f, 0xea, 0x06, 0x23, 0xf8, 0x46, 0xa2, 0x22,
+0xed, 0x93, 0xf6, 0xdd, 0x9a, 0xe6, 0x2a, 0x87, 0xb1, 0x98, 0x54, 0xf1, 0x22, 0xf7, 0x6b, 0x45,
+0xe3, 0xe2, 0x8e, 0x76, 0x1d, 0x9a, 0x8d, 0xc4, 0x06, 0x8d, 0x36, 0xb7, 0x14, 0xf3, 0x9d, 0x54,
+0x69, 0xb7, 0x8e, 0x3c, 0xd5, 0xa4, 0x6d, 0x93, 0x81, 0xb7, 0xad, 0xf6, 0xbd, 0x64, 0x7b, 0xc2,
+0xc9, 0x68, 0x39, 0xa0, 0x92, 0x9c, 0xcd, 0x34, 0x86, 0x91, 0x90, 0xfa, 0x64, 0x51, 0x9d, 0xfe,
+0xfe, 0xeb, 0xa5, 0xf5, 0x75, 0xde, 0x89, 0xf7, 0x72, 0x30, 0x82, 0x05, 0x5a, 0x30, 0x82, 0x03,
+0x42, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x6e, 0x47, 0xa9, 0xc6, 0x5a, 0xb3, 0xe7, 0x20,
+0xc5, 0x30, 0x9a, 0x3f, 0x68, 0x52, 0xf2, 0x6f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x19, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x65,
+0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x13, 0x0b, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x32,
+0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x36, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x36, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
+0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x19, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20,
+0x4c, 0x4c, 0x43, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0b, 0x47, 0x54,
+0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x32, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f,
+0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xce, 0xde, 0xfd, 0xa6, 0xfb, 0xec,
+0xec, 0x14, 0x34, 0x3c, 0x07, 0x06, 0x5a, 0x6c, 0x59, 0xf7, 0x19, 0x35, 0xdd, 0xf7, 0xc1, 0x9d,
+0x55, 0xaa, 0xd3, 0xcd, 0x3b, 0xa4, 0x93, 0x72, 0xef, 0x0a, 0xfa, 0x6d, 0x9d, 0xf6, 0xf0, 0x85,
+0x80, 0x5b, 0xa1, 0x48, 0x52, 0x9f, 0x39, 0xc5, 0xb7, 0xee, 0x28, 0xac, 0xef, 0xcb, 0x76, 0x68,
+0x14, 0xb9, 0xdf, 0xad, 0x01, 0x6c, 0x99, 0x1f, 0xc4, 0x22, 0x1d, 0x9f, 0xfe, 0x72, 0x77, 0xe0,
+0x2c, 0x5b, 0xaf, 0xe4, 0x04, 0xbf, 0x4f, 0x72, 0xa0, 0x1a, 0x34, 0x98, 0xe8, 0x39, 0x68, 0xec,
+0x95, 0x25, 0x7b, 0x76, 0xa1, 0xe6, 0x69, 0xb9, 0x85, 0x19, 0xbd, 0x89, 0x8c, 0xfe, 0xad, 0xed,
+0x36, 0xea, 0x73, 0xbc, 0xff, 0x83, 0xe2, 0xcb, 0x7d, 0xc1, 0xd2, 0xce, 0x4a, 0xb3, 0x8d, 0x05,
+0x9e, 0x8b, 0x49, 0x93, 0xdf, 0xc1, 0x5b, 0xd0, 0x6e, 0x5e, 0xf0, 0x2e, 0x30, 0x2e, 0x82, 0xfc,
+0xfa, 0xbc, 0xb4, 0x17, 0x0a, 0x48, 0xe5, 0x88, 0x9b, 0xc5, 0x9b, 0x6b, 0xde, 0xb0, 0xca, 0xb4,
+0x03, 0xf0, 0xda, 0xf4, 0x90, 0xb8, 0x65, 0x64, 0xf7, 0x5c, 0x4c, 0xad, 0xe8, 0x7e, 0x66, 0x5e,
+0x99, 0xd7, 0xb8, 0xc2, 0x3e, 0xc8, 0xd0, 0x13, 0x9d, 0xad, 0xee, 0xe4, 0x45, 0x7b, 0x89, 0x55,
+0xf7, 0x8a, 0x1f, 0x62, 0x52, 0x84, 0x12, 0xb3, 0xc2, 0x40, 0x97, 0xe3, 0x8a, 0x1f, 0x47, 0x91,
+0xa6, 0x74, 0x5a, 0xd2, 0xf8, 0xb1, 0x63, 0x28, 0x10, 0xb8, 0xb3, 0x09, 0xb8, 0x56, 0x77, 0x40,
+0xa2, 0x26, 0x98, 0x79, 0xc6, 0xfe, 0xdf, 0x25, 0xee, 0x3e, 0xe5, 0xa0, 0x7f, 0xd4, 0x61, 0x0f,
+0x51, 0x4b, 0x3c, 0x3f, 0x8c, 0xda, 0xe1, 0x70, 0x74, 0xd8, 0xc2, 0x68, 0xa1, 0xf9, 0xc1, 0x0c,
+0xe9, 0xa1, 0xe2, 0x7f, 0xbb, 0x55, 0x3c, 0x76, 0x06, 0xee, 0x6a, 0x4e, 0xcc, 0x92, 0x88, 0x30,
+0x4d, 0x9a, 0xbd, 0x4f, 0x0b, 0x48, 0x9a, 0x84, 0xb5, 0x98, 0xa3, 0xd5, 0xfb, 0x73, 0xc1, 0x57,
+0x61, 0xdd, 0x28, 0x56, 0x75, 0x13, 0xae, 0x87, 0x8e, 0xe7, 0x0c, 0x51, 0x09, 0x10, 0x75, 0x88,
+0x4c, 0xbc, 0x8d, 0xf9, 0x7b, 0x3c, 0xd4, 0x22, 0x48, 0x1f, 0x2a, 0xdc, 0xeb, 0x6b, 0xbb, 0x44,
+0xb1, 0xcb, 0x33, 0x71, 0x32, 0x46, 0xaf, 0xad, 0x4a, 0xf1, 0x8c, 0xe8, 0x74, 0x3a, 0xac, 0xe7,
+0x1a, 0x22, 0x73, 0x80, 0xd2, 0x30, 0xf7, 0x25, 0x42, 0xc7, 0x22, 0x3b, 0x3b, 0x12, 0xad, 0x96,
+0x2e, 0xc6, 0xc3, 0x76, 0x07, 0xaa, 0x20, 0xb7, 0x35, 0x49, 0x57, 0xe9, 0x92, 0x49, 0xe8, 0x76,
+0x16, 0x72, 0x31, 0x67, 0x2b, 0x96, 0x7e, 0x8a, 0xa3, 0xc7, 0x94, 0x56, 0x22, 0xbf, 0x6a, 0x4b,
+0x7e, 0x01, 0x21, 0xb2, 0x23, 0x32, 0xdf, 0xe4, 0x9a, 0x44, 0x6d, 0x59, 0x5b, 0x5d, 0xf5, 0x00,
+0xa0, 0x1c, 0x9b, 0xc6, 0x78, 0x97, 0x8d, 0x90, 0xff, 0x9b, 0xc8, 0xaa, 0xb4, 0xaf, 0x11, 0x51,
+0x39, 0x5e, 0xd9, 0xfb, 0x67, 0xad, 0xd5, 0x5b, 0x11, 0x9d, 0x32, 0x9a, 0x1b, 0xbd, 0xd5, 0xba,
+0x5b, 0xa5, 0xc9, 0xcb, 0x25, 0x69, 0x53, 0x55, 0x27, 0x5c, 0xe0, 0xca, 0x36, 0xcb, 0x88, 0x61,
+0xfb, 0x1e, 0xb7, 0xd0, 0xcb, 0xee, 0x16, 0xfb, 0xd3, 0xa6, 0x4c, 0xde, 0x92, 0xa5, 0xd4, 0xe2,
+0xdf, 0xf5, 0x06, 0x54, 0xde, 0x2e, 0x9d, 0x4b, 0xb4, 0x93, 0x30, 0xaa, 0x81, 0xce, 0xdd, 0x1a,
+0xdc, 0x51, 0x73, 0x0d, 0x4f, 0x70, 0xe9, 0xe5, 0xb6, 0x16, 0x21, 0x19, 0x79, 0xb2, 0xe6, 0x89,
+0x0b, 0x75, 0x64, 0xca, 0xd5, 0xab, 0xbc, 0x09, 0xc1, 0x18, 0xa1, 0xff, 0xd4, 0x54, 0xa1, 0x85,
+0x3c, 0xfd, 0x14, 0x24, 0x03, 0xb2, 0x87, 0xd3, 0xa4, 0xb7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xbb,
+0xff, 0xca, 0x8e, 0x23, 0x9f, 0x4f, 0x99, 0xca, 0xdb, 0xe2, 0x68, 0xa6, 0xa5, 0x15, 0x27, 0x17,
+0x1e, 0xd9, 0x0e, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c,
+0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0xb6, 0x69, 0xf0, 0xa6, 0x77, 0xfe, 0x9e, 0xee, 0x0b,
+0x81, 0xad, 0xe1, 0xc0, 0xa9, 0xc7, 0xf9, 0x35, 0x1d, 0x40, 0x82, 0xab, 0xe6, 0x04, 0xb4, 0xdf,
+0xcb, 0xf7, 0x1d, 0x0f, 0x83, 0xf0, 0x7e, 0x13, 0x4d, 0x8d, 0x8c, 0xee, 0xe3, 0x33, 0x22, 0xc3,
+0x39, 0xfc, 0x40, 0xdf, 0x6e, 0x41, 0x4b, 0x42, 0x53, 0xbe, 0x16, 0x88, 0xf1, 0xd2, 0x38, 0x5e,
+0xc4, 0x68, 0x99, 0x1c, 0x98, 0x52, 0x93, 0x8c, 0xe7, 0x68, 0xed, 0x1b, 0x6a, 0x73, 0x7a, 0x05,
+0x40, 0x4d, 0x7f, 0x65, 0x3b, 0xd6, 0x58, 0xf1, 0xce, 0x83, 0x47, 0x60, 0xe3, 0xff, 0x97, 0xa9,
+0x9c, 0x60, 0x77, 0x18, 0x55, 0xb5, 0x7e, 0x08, 0x93, 0xcf, 0xd0, 0xf6, 0x3c, 0x67, 0x03, 0x15,
+0x61, 0x09, 0xf9, 0x81, 0x79, 0xf5, 0xec, 0x53, 0xa4, 0x9f, 0xc9, 0x8f, 0x01, 0x8b, 0x73, 0xc4,
+0x77, 0x76, 0xdc, 0x83, 0xa2, 0xf5, 0x0c, 0x49, 0x1a, 0xa8, 0x76, 0xde, 0x92, 0x9b, 0x64, 0xf8,
+0xb3, 0x2c, 0xc5, 0x27, 0xd3, 0x07, 0xc0, 0x08, 0x80, 0xa4, 0x98, 0x92, 0xe3, 0x01, 0x96, 0x02,
+0xaa, 0x02, 0xee, 0x8f, 0x3b, 0xc5, 0xd1, 0x6d, 0x0a, 0x33, 0x30, 0x73, 0x78, 0xb9, 0x4f, 0x54,
+0x16, 0xbf, 0x0b, 0x07, 0xa1, 0xa4, 0x5c, 0xe6, 0xcb, 0xc9, 0x5c, 0x84, 0x8f, 0x0f, 0xe0, 0x15,
+0x77, 0x2c, 0x7e, 0x26, 0x7e, 0xda, 0xc4, 0x4b, 0xdb, 0xa7, 0x16, 0x77, 0x07, 0xb0, 0xcd, 0x75,
+0xe8, 0x72, 0x42, 0xd6, 0x95, 0x84, 0x9d, 0x86, 0x83, 0xf2, 0xe4, 0x90, 0xcd, 0x09, 0x47, 0xd4,
+0x8b, 0x03, 0x70, 0xda, 0x5a, 0xc6, 0x03, 0x42, 0xf4, 0xed, 0x37, 0xa2, 0xf0, 0x1b, 0x50, 0x54,
+0x4b, 0x0e, 0xd8, 0x84, 0xde, 0x19, 0x28, 0x99, 0x81, 0x47, 0xae, 0x09, 0x1b, 0x3f, 0x48, 0xd1,
+0xc3, 0x6f, 0xe2, 0xb0, 0x60, 0x17, 0xf5, 0xee, 0x23, 0x02, 0xa5, 0xda, 0x00, 0x5b, 0x6d, 0x90,
+0xab, 0xee, 0xa2, 0xe9, 0x1b, 0x3b, 0xe9, 0xc7, 0x44, 0x27, 0x45, 0x8e, 0x6b, 0x9f, 0xf5, 0xa4,
+0x84, 0xbc, 0x77, 0xf9, 0x6b, 0x97, 0xac, 0x3e, 0x51, 0x45, 0xa2, 0x11, 0xa6, 0xcc, 0x85, 0xee,
+0x0a, 0x68, 0xf2, 0x3e, 0x50, 0x38, 0x7a, 0x24, 0x62, 0x1e, 0x17, 0x20, 0x37, 0x6d, 0x6a, 0x4d,
+0xb7, 0x09, 0x9b, 0xc9, 0xfc, 0xa4, 0x58, 0xf5, 0xb6, 0xfb, 0x9c, 0x4e, 0x18, 0xbb, 0x95, 0x02,
+0xe7, 0xa1, 0xad, 0x9b, 0x07, 0xee, 0x36, 0x6b, 0x24, 0xd2, 0x39, 0x86, 0xc1, 0x93, 0x83, 0x50,
+0xd2, 0x81, 0x46, 0xa8, 0x5f, 0x62, 0x57, 0x2c, 0xbb, 0x6c, 0x64, 0x88, 0x08, 0x6e, 0xef, 0x13,
+0x54, 0x5f, 0xdd, 0x2d, 0xc4, 0x67, 0x63, 0xd3, 0xcf, 0x89, 0x37, 0xbf, 0x9d, 0x20, 0xf4, 0xfb,
+0x7a, 0x83, 0x9b, 0xa0, 0x1e, 0x81, 0x00, 0x50, 0xc2, 0xe4, 0x0c, 0x22, 0x59, 0x52, 0x10, 0xed,
+0x43, 0x56, 0x87, 0x00, 0xf8, 0x14, 0x52, 0xa7, 0x1d, 0x8b, 0x93, 0x8c, 0xa2, 0x4d, 0x46, 0x7f,
+0x27, 0xc6, 0x71, 0x9b, 0x24, 0xde, 0xe4, 0xda, 0x86, 0x8b, 0x0d, 0x7e, 0x6b, 0x20, 0xc1, 0xc0,
+0x9e, 0xe1, 0x65, 0xd8, 0x6a, 0xa3, 0xa6, 0xe8, 0x85, 0x8b, 0x3a, 0x07, 0x08, 0x1c, 0xba, 0xf5,
+0x8f, 0x55, 0x9a, 0x18, 0x75, 0x7e, 0xe5, 0xec, 0x81, 0x66, 0xd1, 0x21, 0x73, 0xa1, 0x35, 0x44,
+0x0b, 0x80, 0x3d, 0x5b, 0x9c, 0x5e, 0x6f, 0x2a, 0x17, 0x96, 0xd1, 0x83, 0x23, 0x88, 0x66, 0x6d,
+0xe6, 0x86, 0xe2, 0x70, 0x32, 0x2f, 0x52, 0x22, 0xe7, 0xc8, 0xe7, 0x7f, 0xc4, 0x2c, 0x60, 0x5d,
+0x2f, 0xc3, 0xaf, 0x9e, 0x45, 0x05, 0xc3, 0x84, 0x02, 0xb7, 0xfd, 0x2c, 0x08, 0x52, 0x4f, 0x82,
+0xdd, 0xa3, 0xf0, 0xd4, 0x86, 0x09, 0x02, 0x30, 0x82, 0x02, 0x0c, 0x30, 0x82, 0x01, 0x91, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x6e, 0x47, 0xa9, 0xc7, 0x6c, 0xa9, 0x73, 0x24, 0x40, 0x89,
+0x0f, 0x03, 0x55, 0xdd, 0x8d, 0x1d, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
+0x03, 0x03, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+0x53, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x19, 0x47, 0x6f, 0x6f, 0x67,
+0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+0x73, 0x20, 0x4c, 0x4c, 0x43, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0b,
+0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+0x36, 0x30, 0x36, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x36,
+0x30, 0x36, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x19, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73,
+0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x31, 0x14,
+0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0b, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f,
+0x74, 0x20, 0x52, 0x33, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x1f, 0x4f, 0x33, 0x87,
+0x33, 0x29, 0x8a, 0xa1, 0x84, 0xde, 0xcb, 0xc7, 0x21, 0x58, 0x41, 0x89, 0xea, 0x56, 0x9d, 0x2b,
+0x4b, 0x85, 0xc6, 0x1d, 0x4c, 0x27, 0xbc, 0x7f, 0x26, 0x51, 0x72, 0x6f, 0xe2, 0x9f, 0xd6, 0xa3,
+0xca, 0xcc, 0x45, 0x14, 0x46, 0x8b, 0xad, 0xef, 0x7e, 0x86, 0x8c, 0xec, 0xb1, 0x7e, 0x2f, 0xff,
+0xa9, 0x71, 0x9d, 0x18, 0x84, 0x45, 0x04, 0x41, 0x55, 0x6e, 0x2b, 0xea, 0x26, 0x7f, 0xbb, 0x90,
+0x01, 0xe3, 0x4b, 0x19, 0xba, 0xe4, 0x54, 0x96, 0x45, 0x09, 0xb1, 0xd5, 0x6c, 0x91, 0x44, 0xad,
+0x84, 0x13, 0x8e, 0x9a, 0x8c, 0x0d, 0x80, 0x0c, 0x32, 0xf6, 0xe0, 0x27, 0xa3, 0x42, 0x30, 0x40,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc1, 0xf1, 0x26, 0xba,
+0xa0, 0x2d, 0xae, 0x85, 0x81, 0xcf, 0xd3, 0xf1, 0x2a, 0x12, 0xbd, 0xb8, 0x0a, 0x67, 0xfd, 0xbc,
+0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x69, 0x00, 0x30,
+0x66, 0x02, 0x31, 0x00, 0x80, 0x5b, 0xa4, 0x7c, 0x23, 0xc0, 0x95, 0xa5, 0x2c, 0xdc, 0xbe, 0x89,
+0x6f, 0x23, 0xb9, 0xa3, 0xdd, 0x65, 0x00, 0x52, 0x5e, 0x91, 0xac, 0xc8, 0x9d, 0x72, 0x74, 0x82,
+0x53, 0x0b, 0x7d, 0xa9, 0x40, 0xbd, 0x68, 0x60, 0xc5, 0xe1, 0xb8, 0x54, 0x3b, 0xc1, 0x36, 0x17,
+0x25, 0xd8, 0xc1, 0xbd, 0x02, 0x31, 0x00, 0x9e, 0x35, 0x92, 0x74, 0x85, 0x25, 0x51, 0xf5, 0x24,
+0xec, 0x64, 0x52, 0x24, 0x50, 0xa5, 0x1f, 0xdb, 0xe8, 0xcb, 0xc9, 0x76, 0xec, 0xec, 0x82, 0x6e,
+0xf5, 0x85, 0x18, 0x53, 0xe8, 0xb8, 0xe3, 0x9a, 0x29, 0xaa, 0x96, 0xd3, 0x83, 0x23, 0xc9, 0xa4,
+0x7b, 0x61, 0xb3, 0xcc, 0x02, 0xe8, 0x5d, 0x30, 0x82, 0x02, 0x0a, 0x30, 0x82, 0x01, 0x91, 0xa0,
+0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x6e, 0x47, 0xa9, 0xc8, 0x8b, 0x94, 0xb6, 0xe8, 0xbb, 0x3b,
+0x2a, 0xd8, 0xa2, 0xb2, 0xc1, 0x99, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
+0x03, 0x03, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+0x53, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x19, 0x47, 0x6f, 0x6f, 0x67,
+0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+0x73, 0x20, 0x4c, 0x4c, 0x43, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0b,
+0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x34, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+0x36, 0x30, 0x36, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x36,
+0x30, 0x36, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x19, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73,
+0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x31, 0x14,
+0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0b, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f,
+0x74, 0x20, 0x52, 0x34, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xf3, 0x74, 0x73, 0xa7,
+0x68, 0x8b, 0x60, 0xae, 0x43, 0xb8, 0x35, 0xc5, 0x81, 0x30, 0x7b, 0x4b, 0x49, 0x9d, 0xfb, 0xc1,
+0x61, 0xce, 0xe6, 0xde, 0x46, 0xbd, 0x6b, 0xd5, 0x61, 0x18, 0x35, 0xae, 0x40, 0xdd, 0x73, 0xf7,
+0x89, 0x91, 0x30, 0x5a, 0xeb, 0x3c, 0xee, 0x85, 0x7c, 0xa2, 0x40, 0x76, 0x3b, 0xa9, 0xc6, 0xb8,
+0x47, 0xd8, 0x2a, 0xe7, 0x92, 0x91, 0x6a, 0x73, 0xe9, 0xb1, 0x72, 0x39, 0x9f, 0x29, 0x9f, 0xa2,
+0x98, 0xd3, 0x5f, 0x5e, 0x58, 0x86, 0x65, 0x0f, 0xa1, 0x84, 0x65, 0x06, 0xd1, 0xdc, 0x8b, 0xc9,
+0xc7, 0x73, 0xc8, 0x8c, 0x6a, 0x2f, 0xe5, 0xc4, 0xab, 0xd1, 0x1d, 0x8a, 0xa3, 0x42, 0x30, 0x40,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x80, 0x4c, 0xd6, 0xeb,
+0x74, 0xff, 0x49, 0x36, 0xa3, 0xd5, 0xd8, 0xfc, 0xb5, 0x3e, 0xc5, 0x6a, 0xf0, 0x94, 0x1d, 0x8c,
+0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x67, 0x00, 0x30,
+0x64, 0x02, 0x30, 0x6a, 0x50, 0x52, 0x74, 0x08, 0xc4, 0x70, 0xdc, 0x9e, 0x50, 0x74, 0x21, 0xe8,
+0x8d, 0x7a, 0x21, 0xc3, 0x4f, 0x96, 0x6e, 0x15, 0xd1, 0x22, 0x35, 0x61, 0x2d, 0xfa, 0x08, 0x37,
+0xee, 0x19, 0x6d, 0xad, 0xdb, 0xb2, 0xcc, 0x7d, 0x07, 0x34, 0xf5, 0x60, 0x19, 0x2c, 0xb5, 0x34,
+0xd9, 0x6f, 0x20, 0x02, 0x30, 0x03, 0x71, 0xb1, 0xba, 0xa3, 0x60, 0x0b, 0x86, 0xed, 0x9a, 0x08,
+0x6a, 0x95, 0x68, 0x9f, 0xe2, 0xb3, 0xe1, 0x93, 0x64, 0x7c, 0x5e, 0x93, 0xa6, 0xdf, 0x79, 0x2d,
+0x8d, 0x85, 0xe3, 0x94, 0xcf, 0x23, 0x5d, 0x71, 0xcc, 0xf2, 0xb0, 0x4d, 0xd6, 0xfe, 0x99, 0xc8,
+0x94, 0xa9, 0x75, 0xa2, 0xe3, 0x30, 0x82, 0x05, 0x5a, 0x30, 0x82, 0x03, 0x42, 0xa0, 0x03, 0x02,
+0x01, 0x02, 0x02, 0x10, 0x6e, 0x47, 0xa9, 0xc5, 0x4b, 0x47, 0x0c, 0x0d, 0xec, 0x33, 0xd0, 0x89,
+0xb9, 0x1c, 0xf4, 0xe1, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0c, 0x05, 0x00, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x55, 0x53, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x19, 0x47, 0x6f, 0x6f,
+0x67, 0x6c, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+0x65, 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+0x0b, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x31, 0x30, 0x1e, 0x17, 0x0d,
+0x31, 0x36, 0x30, 0x36, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33,
+0x36, 0x30, 0x36, 0x32, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x47, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x22, 0x30, 0x20, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x19, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x72, 0x75,
+0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x4c, 0x4c, 0x43, 0x31,
+0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0b, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x52, 0x31, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
+0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb6, 0x11, 0x02, 0x8b, 0x1e, 0xe3, 0xa1, 0x77, 0x9b, 0x3b,
+0xdc, 0xbf, 0x94, 0x3e, 0xb7, 0x95, 0xa7, 0x40, 0x3c, 0xa1, 0xfd, 0x82, 0xf9, 0x7d, 0x32, 0x06,
+0x82, 0x71, 0xf6, 0xf6, 0x8c, 0x7f, 0xfb, 0xe8, 0xdb, 0xbc, 0x6a, 0x2e, 0x97, 0x97, 0xa3, 0x8c,
+0x4b, 0xf9, 0x2b, 0xf6, 0xb1, 0xf9, 0xce, 0x84, 0x1d, 0xb1, 0xf9, 0xc5, 0x97, 0xde, 0xef, 0xb9,
+0xf2, 0xa3, 0xe9, 0xbc, 0x12, 0x89, 0x5e, 0xa7, 0xaa, 0x52, 0xab, 0xf8, 0x23, 0x27, 0xcb, 0xa4,
+0xb1, 0x9c, 0x63, 0xdb, 0xd7, 0x99, 0x7e, 0xf0, 0x0a, 0x5e, 0xeb, 0x68, 0xa6, 0xf4, 0xc6, 0x5a,
+0x47, 0x0d, 0x4d, 0x10, 0x33, 0xe3, 0x4e, 0xb1, 0x13, 0xa3, 0xc8, 0x18, 0x6c, 0x4b, 0xec, 0xfc,
+0x09, 0x90, 0xdf, 0x9d, 0x64, 0x29, 0x25, 0x23, 0x07, 0xa1, 0xb4, 0xd2, 0x3d, 0x2e, 0x60, 0xe0,
+0xcf, 0xd2, 0x09, 0x87, 0xbb, 0xcd, 0x48, 0xf0, 0x4d, 0xc2, 0xc2, 0x7a, 0x88, 0x8a, 0xbb, 0xba,
+0xcf, 0x59, 0x19, 0xd6, 0xaf, 0x8f, 0xb0, 0x07, 0xb0, 0x9e, 0x31, 0xf1, 0x82, 0xc1, 0xc0, 0xdf,
+0x2e, 0xa6, 0x6d, 0x6c, 0x19, 0x0e, 0xb5, 0xd8, 0x7e, 0x26, 0x1a, 0x45, 0x03, 0x3d, 0xb0, 0x79,
+0xa4, 0x94, 0x28, 0xad, 0x0f, 0x7f, 0x26, 0xe5, 0xa8, 0x08, 0xfe, 0x96, 0xe8, 0x3c, 0x68, 0x94,
+0x53, 0xee, 0x83, 0x3a, 0x88, 0x2b, 0x15, 0x96, 0x09, 0xb2, 0xe0, 0x7a, 0x8c, 0x2e, 0x75, 0xd6,
+0x9c, 0xeb, 0xa7, 0x56, 0x64, 0x8f, 0x96, 0x4f, 0x68, 0xae, 0x3d, 0x97, 0xc2, 0x84, 0x8f, 0xc0,
+0xbc, 0x40, 0xc0, 0x0b, 0x5c, 0xbd, 0xf6, 0x87, 0xb3, 0x35, 0x6c, 0xac, 0x18, 0x50, 0x7f, 0x84,
+0xe0, 0x4c, 0xcd, 0x92, 0xd3, 0x20, 0xe9, 0x33, 0xbc, 0x52, 0x99, 0xaf, 0x32, 0xb5, 0x29, 0xb3,
+0x25, 0x2a, 0xb4, 0x48, 0xf9, 0x72, 0xe1, 0xca, 0x64, 0xf7, 0xe6, 0x82, 0x10, 0x8d, 0xe8, 0x9d,
+0xc2, 0x8a, 0x88, 0xfa, 0x38, 0x66, 0x8a, 0xfc, 0x63, 0xf9, 0x01, 0xf9, 0x78, 0xfd, 0x7b, 0x5c,
+0x77, 0xfa, 0x76, 0x87, 0xfa, 0xec, 0xdf, 0xb1, 0x0e, 0x79, 0x95, 0x57, 0xb4, 0xbd, 0x26, 0xef,
+0xd6, 0x01, 0xd1, 0xeb, 0x16, 0x0a, 0xbb, 0x8e, 0x0b, 0xb5, 0xc5, 0xc5, 0x8a, 0x55, 0xab, 0xd3,
+0xac, 0xea, 0x91, 0x4b, 0x29, 0xcc, 0x19, 0xa4, 0x32, 0x25, 0x4e, 0x2a, 0xf1, 0x65, 0x44, 0xd0,
+0x02, 0xce, 0xaa, 0xce, 0x49, 0xb4, 0xea, 0x9f, 0x7c, 0x83, 0xb0, 0x40, 0x7b, 0xe7, 0x43, 0xab,
+0xa7, 0x6c, 0xa3, 0x8f, 0x7d, 0x89, 0x81, 0xfa, 0x4c, 0xa5, 0xff, 0xd5, 0x8e, 0xc3, 0xce, 0x4b,
+0xe0, 0xb5, 0xd8, 0xb3, 0x8e, 0x45, 0xcf, 0x76, 0xc0, 0xed, 0x40, 0x2b, 0xfd, 0x53, 0x0f, 0xb0,
+0xa7, 0xd5, 0x3b, 0x0d, 0xb1, 0x8a, 0xa2, 0x03, 0xde, 0x31, 0xad, 0xcc, 0x77, 0xea, 0x6f, 0x7b,
+0x3e, 0xd6, 0xdf, 0x91, 0x22, 0x12, 0xe6, 0xbe, 0xfa, 0xd8, 0x32, 0xfc, 0x10, 0x63, 0x14, 0x51,
+0x72, 0xde, 0x5d, 0xd6, 0x16, 0x93, 0xbd, 0x29, 0x68, 0x33, 0xef, 0x3a, 0x66, 0xec, 0x07, 0x8a,
+0x26, 0xdf, 0x13, 0xd7, 0x57, 0x65, 0x78, 0x27, 0xde, 0x5e, 0x49, 0x14, 0x00, 0xa2, 0x00, 0x7f,
+0x9a, 0xa8, 0x21, 0xb6, 0xa9, 0xb1, 0x95, 0xb0, 0xa5, 0xb9, 0x0d, 0x16, 0x11, 0xda, 0xc7, 0x6c,
+0x48, 0x3c, 0x40, 0xe0, 0x7e, 0x0d, 0x5a, 0xcd, 0x56, 0x3c, 0xd1, 0x97, 0x05, 0xb9, 0xcb, 0x4b,
+0xed, 0x39, 0x4b, 0x9c, 0xc4, 0x3f, 0xd2, 0x55, 0x13, 0x6e, 0x24, 0xb0, 0xd6, 0x71, 0xfa, 0xf4,
+0xc1, 0xba, 0xcc, 0xed, 0x1b, 0xf5, 0xfe, 0x81, 0x41, 0xd8, 0x00, 0x98, 0x3d, 0x3a, 0xc8, 0xae,
+0x7a, 0x98, 0x37, 0x18, 0x05, 0x95, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xe4, 0xaf, 0x2b, 0x26, 0x71,
+0x1a, 0x2b, 0x48, 0x27, 0x85, 0x2f, 0x52, 0x66, 0x2c, 0xef, 0xf0, 0x89, 0x13, 0x71, 0x3e, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x03, 0x82,
+0x02, 0x01, 0x00, 0x38, 0x96, 0x0a, 0xee, 0x3d, 0xb4, 0x96, 0x1e, 0x5f, 0xef, 0x9d, 0x9c, 0x0b,
+0x33, 0x9f, 0x2b, 0xe0, 0xca, 0xfd, 0xd2, 0x8e, 0x0a, 0x1f, 0x41, 0x74, 0xa5, 0x7c, 0xaa, 0x84,
+0xd4, 0xe5, 0xf2, 0x1e, 0xe6, 0x37, 0x52, 0x32, 0x9c, 0x0b, 0xd1, 0x61, 0x1d, 0xbf, 0x28, 0xc1,
+0xb6, 0x44, 0x29, 0x35, 0x75, 0x77, 0x98, 0xb2, 0x7c, 0xd9, 0xbd, 0x74, 0xac, 0x8a, 0x68, 0xe3,
+0xa9, 0x31, 0x09, 0x29, 0x01, 0x60, 0x73, 0xe3, 0x47, 0x7c, 0x53, 0xa8, 0x90, 0x4a, 0x27, 0xef,
+0x4b, 0xd7, 0x9f, 0x93, 0xe7, 0x82, 0x36, 0xce, 0x9a, 0x68, 0x0c, 0x82, 0xe7, 0xcf, 0xd4, 0x10,
+0x16, 0x6f, 0x5f, 0x0e, 0x99, 0x5c, 0xf6, 0x1f, 0x71, 0x7d, 0xef, 0xef, 0x7b, 0x2f, 0x7e, 0xea,
+0x36, 0xd6, 0x97, 0x70, 0x0b, 0x15, 0xee, 0xd7, 0x5c, 0x56, 0x6a, 0x33, 0xa5, 0xe3, 0x49, 0x38,
+0x0c, 0xb8, 0x7d, 0xfb, 0x8d, 0x85, 0xa4, 0xb1, 0x59, 0x5e, 0xf4, 0x6a, 0xe1, 0xdd, 0xa1, 0xf6,
+0x64, 0x44, 0xae, 0xe6, 0x51, 0x83, 0x21, 0x66, 0xc6, 0x11, 0x3e, 0xf3, 0xce, 0x47, 0xee, 0x9c,
+0x28, 0x1f, 0x25, 0xda, 0xff, 0xac, 0x66, 0x95, 0xdd, 0x35, 0x0f, 0x5c, 0xef, 0x20, 0x2c, 0x62,
+0xfd, 0x91, 0xba, 0xa9, 0xcc, 0xfc, 0x5a, 0x9c, 0x93, 0x81, 0x83, 0x29, 0x97, 0x4a, 0x7c, 0x5a,
+0x72, 0xb4, 0x39, 0xd0, 0xb7, 0x77, 0xcb, 0x79, 0xfd, 0x69, 0x3a, 0x92, 0x37, 0xed, 0x6e, 0x38,
+0x65, 0x46, 0x7e, 0xe9, 0x60, 0xbd, 0x79, 0x88, 0x97, 0x5f, 0x38, 0x12, 0xf4, 0xee, 0xaf, 0x5b,
+0x82, 0xc8, 0x86, 0xd5, 0xe1, 0x99, 0x6d, 0x8c, 0x04, 0xf2, 0x76, 0xba, 0x49, 0xf6, 0x6e, 0xe9,
+0x6d, 0x1e, 0x5f, 0xa0, 0xef, 0x27, 0x82, 0x76, 0x40, 0xf8, 0xa6, 0xd3, 0x58, 0x5c, 0x0f, 0x2c,
+0x42, 0xda, 0x42, 0xc6, 0x7b, 0x88, 0x34, 0xc7, 0xc1, 0xd8, 0x45, 0x9b, 0xc1, 0x3e, 0xc5, 0x61,
+0x1d, 0xd9, 0x63, 0x50, 0x49, 0xf6, 0x34, 0x85, 0x6a, 0xe0, 0x18, 0xc5, 0x6e, 0x47, 0xab, 0x41,
+0x42, 0x29, 0x9b, 0xf6, 0x60, 0x0d, 0xd2, 0x31, 0xd3, 0x63, 0x98, 0x23, 0x93, 0x5a, 0x00, 0x81,
+0x48, 0xb4, 0xef, 0xcd, 0x8a, 0xcd, 0xc9, 0xcf, 0x99, 0xee, 0xd9, 0x9e, 0xaa, 0x36, 0xe1, 0x68,
+0x4b, 0x71, 0x49, 0x14, 0x36, 0x28, 0x3a, 0x3d, 0x1d, 0xce, 0x9a, 0x8f, 0x25, 0xe6, 0x80, 0x71,
+0x61, 0x2b, 0xb5, 0x7b, 0xcc, 0xf9, 0x25, 0x16, 0x81, 0xe1, 0x31, 0x5f, 0xa1, 0xa3, 0x7e, 0x16,
+0xa4, 0x9c, 0x16, 0x6a, 0x97, 0x18, 0xbd, 0x76, 0x72, 0xa5, 0x0b, 0x9e, 0x1d, 0x36, 0xe6, 0x2f,
+0xa1, 0x2f, 0xbe, 0x70, 0x91, 0x0f, 0xa8, 0xe6, 0xda, 0xf8, 0xc4, 0x92, 0x40, 0x6c, 0x25, 0x7e,
+0x7b, 0xb3, 0x09, 0xdc, 0xb2, 0x17, 0xad, 0x80, 0x44, 0xf0, 0x68, 0xa5, 0x8f, 0x94, 0x75, 0xff,
+0x74, 0x5a, 0xe8, 0xa8, 0x02, 0x7c, 0x0c, 0x09, 0xe2, 0xa9, 0x4b, 0x0b, 0xa0, 0x85, 0x0b, 0x62,
+0xb9, 0xef, 0xa1, 0x31, 0x92, 0xfb, 0xef, 0xf6, 0x51, 0x04, 0x89, 0x6c, 0xe8, 0xa9, 0x74, 0xa1,
+0xbb, 0x17, 0xb3, 0xb5, 0xfd, 0x49, 0x0f, 0x7c, 0x3c, 0xec, 0x83, 0x18, 0x20, 0x43, 0x4e, 0xd5,
+0x93, 0xba, 0xb4, 0x34, 0xb1, 0x1f, 0x16, 0x36, 0x1f, 0x0c, 0xe6, 0x64, 0x39, 0x16, 0x4c, 0xdc,
+0xe0, 0xfe, 0x1d, 0xc8, 0xa9, 0x62, 0x3d, 0x40, 0xea, 0xca, 0xc5, 0x34, 0x02, 0xb4, 0xae, 0x89,
+0x88, 0x33, 0x35, 0xdc, 0x2c, 0x13, 0x73, 0xd8, 0x27, 0xf1, 0xd0, 0x72, 0xee, 0x75, 0x3b, 0x22,
+0xde, 0x98, 0x68, 0x66, 0x5b, 0xf1, 0xc6, 0x63, 0x47, 0x55, 0x1c, 0xba, 0xa5, 0x08, 0x51, 0x75,
+0xa6, 0x48, 0x25, 0x30, 0x82, 0x05, 0x5a, 0x30, 0x82, 0x03, 0x42, 0xa0, 0x03, 0x02, 0x01, 0x02,
+0x02, 0x12, 0x11, 0xd2, 0xbb, 0xb9, 0xd7, 0x23, 0x18, 0x9e, 0x40, 0x5f, 0x0a, 0x9d, 0x2d, 0xd0,
+0xdf, 0x25, 0x67, 0xd1, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0c, 0x05, 0x00, 0x30, 0x46, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x42, 0x45, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f,
+0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, 0x1c, 0x30,
+0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69,
+0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x52, 0x34, 0x36, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+0x39, 0x30, 0x33, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x36,
+0x30, 0x33, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x46, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20,
+0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13,
+0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x52, 0x34, 0x36, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02,
+0x82, 0x02, 0x01, 0x00, 0xac, 0xac, 0x74, 0x32, 0xe8, 0xb3, 0x65, 0xe5, 0xba, 0xed, 0x43, 0x26,
+0x1d, 0xa6, 0x89, 0x0d, 0x45, 0xba, 0x29, 0x88, 0xb2, 0xa4, 0x1d, 0x63, 0xdd, 0xd3, 0xc1, 0x2c,
+0x09, 0x57, 0x89, 0x39, 0xa1, 0x55, 0xe9, 0x67, 0x34, 0x77, 0x0c, 0x6e, 0xe4, 0x55, 0x1d, 0x52,
+0x25, 0xd2, 0x13, 0x6b, 0x5e, 0xe1, 0x1d, 0xa9, 0xb7, 0x7d, 0x89, 0x32, 0x5f, 0x0d, 0x9e, 0x9f,
+0x2c, 0x7a, 0x63, 0x60, 0x40, 0x1f, 0xa6, 0xb0, 0xb6, 0x78, 0x8f, 0x99, 0x54, 0x96, 0x08, 0x58,
+0xae, 0xe4, 0x06, 0xbc, 0x62, 0x05, 0x02, 0x16, 0xbf, 0xaf, 0xa8, 0x23, 0x03, 0xb6, 0x94, 0x0f,
+0xbc, 0x6e, 0x6c, 0xc2, 0xcb, 0xd5, 0xa6, 0xbb, 0x0c, 0xe9, 0xf6, 0xc1, 0x02, 0xfb, 0x21, 0xde,
+0x66, 0xdd, 0x17, 0xab, 0x74, 0x42, 0xef, 0xf0, 0x74, 0x2f, 0x25, 0xf4, 0xea, 0x6b, 0x55, 0x5b,
+0x90, 0xdb, 0x9d, 0xdf, 0x5e, 0x87, 0x0a, 0x40, 0xfb, 0xad, 0x19, 0x6b, 0xfb, 0xf7, 0xca, 0x60,
+0x88, 0xde, 0xda, 0xc1, 0x8f, 0xd6, 0xae, 0xd5, 0x7f, 0xd4, 0x3c, 0x83, 0xee, 0xd7, 0x16, 0x4c,
+0x83, 0x45, 0x33, 0x6b, 0x27, 0xd0, 0x86, 0xd0, 0x1c, 0x2d, 0x6b, 0xf3, 0xab, 0x7d, 0xf1, 0x85,
+0xa9, 0xf5, 0x28, 0xd2, 0xad, 0xef, 0xf3, 0x84, 0x4b, 0x1c, 0x87, 0xfc, 0x13, 0xa3, 0x3a, 0x72,
+0xa2, 0x5a, 0x11, 0x2b, 0xd6, 0x27, 0x71, 0x27, 0xed, 0x81, 0x2d, 0x6d, 0x66, 0x81, 0x92, 0x87,
+0xb4, 0x1b, 0x58, 0x7a, 0xcc, 0x3f, 0x0a, 0xfa, 0x46, 0x4f, 0x4d, 0x78, 0x5c, 0xf8, 0x2b, 0x48,
+0xe3, 0x04, 0x84, 0xcb, 0x5d, 0xf6, 0xb4, 0x6a, 0xb3, 0x65, 0xfc, 0x42, 0x9e, 0x51, 0x26, 0x23,
+0x20, 0xcb, 0x3d, 0x14, 0xf9, 0x81, 0xed, 0x65, 0x16, 0x00, 0x4f, 0x1a, 0x64, 0x97, 0x66, 0x08,
+0xcf, 0x8c, 0x7b, 0xe3, 0x2b, 0xc0, 0x9d, 0xf9, 0x14, 0xf2, 0x1b, 0xf1, 0x56, 0x6a, 0x16, 0xbf,
+0x2c, 0x85, 0x85, 0xcd, 0x78, 0x38, 0x9a, 0xeb, 0x42, 0x6a, 0x02, 0x34, 0x18, 0x83, 0x17, 0x4e,
+0x94, 0x56, 0xf8, 0xb6, 0x82, 0xb5, 0xf3, 0x96, 0xdd, 0x3d, 0xf3, 0xbe, 0x7f, 0x20, 0x77, 0x3e,
+0x7b, 0x19, 0x23, 0x6b, 0x2c, 0xd4, 0x72, 0x73, 0x43, 0x57, 0x7d, 0xe0, 0xf8, 0xd7, 0x69, 0x4f,
+0x17, 0x36, 0x04, 0xf9, 0xc0, 0x90, 0x60, 0x37, 0x45, 0xde, 0xe6, 0x0c, 0xd8, 0x74, 0x8d, 0xae,
+0x9c, 0xa2, 0x6d, 0x74, 0x5d, 0x42, 0xbe, 0x06, 0xf5, 0xd9, 0x64, 0x6e, 0x02, 0x10, 0xac, 0x89,
+0xb0, 0x4c, 0x3b, 0x07, 0x4d, 0x40, 0x7e, 0x24, 0xc5, 0x8a, 0x98, 0x82, 0x79, 0x8e, 0xa4, 0xa7,
+0x82, 0x20, 0x8d, 0x23, 0xfa, 0x27, 0x71, 0xc9, 0xdf, 0xc6, 0x41, 0x74, 0xa0, 0x4d, 0xf6, 0x91,
+0x16, 0xdc, 0x46, 0x8c, 0x5f, 0x29, 0x63, 0x31, 0x59, 0x71, 0x0c, 0xd8, 0x6f, 0xc2, 0xb6, 0x32,
+0x7d, 0xfb, 0xe6, 0x5d, 0x53, 0xa6, 0x7e, 0x15, 0xfc, 0xbb, 0x75, 0x7c, 0x5d, 0xec, 0xf8, 0xf6,
+0x17, 0x1c, 0xec, 0xc7, 0x6b, 0x19, 0xcb, 0xf3, 0x7b, 0xf0, 0x2b, 0x07, 0xa5, 0xd9, 0x6c, 0x79,
+0x54, 0x76, 0x6c, 0x9d, 0x1c, 0xa6, 0x6e, 0x0e, 0xe9, 0x79, 0x0c, 0xa8, 0x23, 0x6a, 0xa3, 0xdf,
+0x1b, 0x30, 0x31, 0x9f, 0xb1, 0x54, 0x7b, 0xfe, 0x6a, 0xcb, 0x66, 0xaa, 0xdc, 0x65, 0xd0, 0xa2,
+0x9e, 0x4a, 0x9a, 0x07, 0x21, 0x6b, 0x81, 0x8f, 0xdb, 0xc4, 0x59, 0xfa, 0xde, 0x22, 0xc0, 0x04,
+0x9c, 0xe3, 0xaa, 0x5b, 0x36, 0x93, 0xe8, 0x3d, 0xbd, 0x7a, 0xa1, 0x9d, 0x0b, 0x76, 0xb1, 0x0b,
+0xc7, 0x9d, 0xfd, 0xcf, 0x98, 0xa8, 0x06, 0xc2, 0xf8, 0x2a, 0xa3, 0xa1, 0x83, 0xa0, 0xb7, 0x25,
+0x72, 0xa5, 0x02, 0xe3, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x03, 0x5c, 0xab, 0x73, 0x81, 0x87, 0xa8,
+0xcc, 0xb0, 0xa6, 0xd5, 0x94, 0xe2, 0x36, 0x96, 0x49, 0xff, 0x05, 0x99, 0x2c, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
+0x00, 0x7c, 0x78, 0xec, 0xf6, 0x02, 0x2c, 0xbb, 0x5b, 0x7e, 0x92, 0x2b, 0x5d, 0x39, 0xdc, 0xbe,
+0xd8, 0x1d, 0xa2, 0x42, 0x33, 0x4d, 0xf9, 0xef, 0xa4, 0x2a, 0x3b, 0x44, 0x69, 0x1e, 0xac, 0xd9,
+0x45, 0xa3, 0x4e, 0x3c, 0xa7, 0xd8, 0x24, 0x51, 0xb2, 0x54, 0x1c, 0x93, 0x4e, 0xc4, 0xef, 0x7b,
+0x93, 0x85, 0x60, 0x26, 0xea, 0x09, 0x48, 0xe0, 0xf5, 0xbb, 0xc7, 0xe9, 0x68, 0xd2, 0xbb, 0x6a,
+0x31, 0x71, 0xcc, 0x79, 0xae, 0x11, 0xa8, 0xf0, 0x99, 0xfd, 0xe5, 0x1f, 0xbc, 0x2f, 0xa8, 0xcc,
+0x57, 0xeb, 0x76, 0xc4, 0x21, 0xa6, 0x47, 0x53, 0x55, 0x4d, 0x68, 0xbf, 0x05, 0xa4, 0xee, 0xd7,
+0x26, 0xab, 0x62, 0xda, 0x43, 0x37, 0x4b, 0xe2, 0xc6, 0xb5, 0xe5, 0xb2, 0x83, 0x19, 0x3a, 0xc7,
+0xd3, 0xdb, 0x4d, 0x9e, 0x08, 0x7a, 0xf3, 0xee, 0xcf, 0x3e, 0x62, 0xfb, 0xac, 0xe8, 0x60, 0xcc,
+0xd1, 0xc7, 0xa1, 0x5c, 0x83, 0x45, 0xc4, 0x45, 0xcc, 0xf3, 0x17, 0x6b, 0x14, 0xc9, 0x04, 0x02,
+0x3e, 0xd2, 0x24, 0xa6, 0x79, 0xe9, 0x1e, 0xce, 0xa2, 0xe7, 0xc1, 0x59, 0x15, 0x9f, 0x1d, 0xe2,
+0x4b, 0x9a, 0x3e, 0x9f, 0x76, 0x08, 0x2d, 0x6b, 0xd8, 0xba, 0x57, 0x14, 0xda, 0x83, 0xea, 0xfe,
+0x8c, 0x55, 0xe9, 0xd0, 0x4e, 0xa9, 0xcc, 0x77, 0x31, 0xb1, 0x44, 0x11, 0x7a, 0x5c, 0xb1, 0x3e,
+0xd3, 0x14, 0x45, 0x15, 0x18, 0x62, 0x24, 0x13, 0xd2, 0xcb, 0x4d, 0xce, 0x5c, 0x83, 0xc1, 0x36,
+0xf2, 0x10, 0xb5, 0x0e, 0x88, 0x6d, 0xb8, 0xe1, 0x56, 0x9f, 0x89, 0xde, 0x96, 0x66, 0x39, 0x47,
+0x64, 0x2c, 0x6e, 0x4d, 0xae, 0x62, 0x7b, 0xbf, 0x60, 0x74, 0x19, 0xb8, 0x56, 0xac, 0x92, 0xac,
+0x16, 0x32, 0xed, 0xad, 0x68, 0x55, 0xfe, 0x98, 0xba, 0xd3, 0x34, 0xde, 0xf4, 0xc9, 0x61, 0xc3,
+0x0e, 0x86, 0xf6, 0x4b, 0x84, 0x60, 0xee, 0x0d, 0x7b, 0xb5, 0x32, 0x58, 0x79, 0x91, 0x55, 0x2c,
+0x81, 0x43, 0xb3, 0x74, 0x1f, 0x7a, 0xaa, 0x25, 0x9e, 0x1d, 0xd7, 0xa1, 0x8b, 0xb9, 0xcd, 0x42,
+0x2e, 0x04, 0xa4, 0x66, 0x83, 0x4d, 0x89, 0x35, 0xb6, 0x6c, 0xa8, 0x36, 0x4a, 0x79, 0x21, 0x78,
+0x22, 0xd0, 0x42, 0xbc, 0xd1, 0x40, 0x31, 0x90, 0xa1, 0xbe, 0x04, 0xcf, 0xca, 0x67, 0xed, 0xf5,
+0xf0, 0x80, 0xd3, 0x60, 0xc9, 0x83, 0x2a, 0x22, 0x05, 0xd0, 0x07, 0x3b, 0x52, 0xbf, 0x0c, 0x9e,
+0xaa, 0x2b, 0xf9, 0xbb, 0xe6, 0x1f, 0x8f, 0x25, 0xba, 0x85, 0x8d, 0x17, 0x1e, 0x02, 0xfe, 0x5d,
+0x50, 0x04, 0x57, 0xcf, 0xfe, 0x2d, 0xbc, 0xef, 0x5c, 0xc0, 0x1a, 0xab, 0xb6, 0x9f, 0x24, 0xc6,
+0xdf, 0x73, 0x68, 0x48, 0x90, 0x2c, 0x14, 0xf4, 0x3f, 0x52, 0x1a, 0xe4, 0xd2, 0xcb, 0x14, 0xc3,
+0x61, 0x69, 0xcf, 0xe2, 0xf9, 0x18, 0xc5, 0xba, 0x33, 0x9f, 0x14, 0xa3, 0x04, 0x5d, 0xb9, 0x71,
+0xf7, 0xb5, 0x94, 0xd8, 0xf6, 0x33, 0xc1, 0x5a, 0xc1, 0x34, 0x8b, 0x7c, 0x9b, 0xdd, 0x93, 0x3a,
+0xe7, 0x13, 0xa2, 0x70, 0x61, 0x9f, 0xaf, 0x8f, 0xeb, 0xd8, 0xc5, 0x75, 0xf8, 0x33, 0x66, 0xd4,
+0x74, 0x67, 0x3a, 0x37, 0x77, 0x9c, 0xe7, 0xdd, 0xa4, 0x0f, 0x76, 0x43, 0x66, 0x8a, 0x43, 0xf2,
+0x9f, 0xfb, 0x0c, 0x42, 0x78, 0x63, 0xd1, 0xe2, 0x0f, 0x6f, 0x7b, 0xd4, 0xa1, 0x3d, 0x74, 0x97,
+0x85, 0xb7, 0x48, 0x39, 0x41, 0xd6, 0x20, 0xfc, 0xd0, 0x3a, 0xb3, 0xfa, 0xe8, 0x6f, 0xc4, 0x8a,
+0xba, 0x71, 0x37, 0xbe, 0x8b, 0x97, 0xb1, 0x78, 0x31, 0x4f, 0xb3, 0xe7, 0xb6, 0x03, 0x13, 0xce,
+0x54, 0x9d, 0xae, 0x25, 0x59, 0xcc, 0x7f, 0x35, 0x5f, 0x08, 0xf7, 0x40, 0x45, 0x31, 0x78, 0x2a,
+0x7a, 0x30, 0x82, 0x02, 0x0b, 0x30, 0x82, 0x01, 0x91, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x12,
+0x11, 0xd2, 0xbb, 0xba, 0x33, 0x6e, 0xd4, 0xbc, 0xe6, 0x24, 0x68, 0xc5, 0x0d, 0x84, 0x1d, 0x98,
+0xe8, 0x43, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x46,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30,
+0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69,
+0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x13, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x45, 0x34, 0x36, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x30, 0x33, 0x32, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x36, 0x30, 0x33, 0x32, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x46, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10,
+0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61,
+0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x47, 0x6c, 0x6f, 0x62, 0x61,
+0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x45, 0x34, 0x36, 0x30, 0x76,
+0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04,
+0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x9c, 0x0e, 0xb1, 0xcf, 0xb7, 0xe8, 0x9e, 0x52, 0x77, 0x75,
+0x34, 0xfa, 0xa5, 0x46, 0xa7, 0xad, 0x32, 0x19, 0x32, 0xb4, 0x07, 0xa9, 0x27, 0xca, 0x94, 0xbb,
+0x0c, 0xd2, 0x0a, 0x10, 0xc7, 0xda, 0x89, 0xb0, 0x97, 0x0c, 0x70, 0x13, 0x09, 0x01, 0x8e, 0xd8,
+0xea, 0x47, 0xea, 0xbe, 0xb2, 0x80, 0x2b, 0xcd, 0xfc, 0x28, 0x0d, 0xdb, 0xac, 0xbc, 0xa4, 0x86,
+0x37, 0xed, 0x70, 0x08, 0x00, 0x75, 0xea, 0x93, 0x0b, 0x7b, 0x2e, 0x52, 0x9c, 0x23, 0x68, 0x23,
+0x06, 0x43, 0xec, 0x92, 0x2f, 0x53, 0x84, 0xdb, 0xfb, 0x47, 0x14, 0x07, 0xe8, 0x5f, 0x94, 0x67,
+0x5d, 0xc9, 0x7a, 0x81, 0x3c, 0x20, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
+0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55,
+0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x31, 0x0a, 0x90, 0x8f, 0xb6, 0xc6, 0x9d, 0xd2, 0x44, 0x4b,
+0x80, 0xb5, 0xa2, 0xe6, 0x1f, 0xb1, 0x12, 0x4f, 0x1b, 0x95, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
+0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x31, 0x00, 0xdf, 0x54,
+0x90, 0xed, 0x9b, 0xef, 0x8b, 0x94, 0x02, 0x93, 0x17, 0x82, 0x99, 0xbe, 0xb3, 0x9e, 0x2c, 0xf6,
+0x0b, 0x91, 0x8c, 0x9f, 0x4a, 0x14, 0xb1, 0xf6, 0x64, 0xbc, 0xbb, 0x68, 0x51, 0x13, 0x0c, 0x03,
+0xf7, 0x15, 0x8b, 0x84, 0x60, 0xb9, 0x8b, 0xff, 0x52, 0x8e, 0xe7, 0x8c, 0xbc, 0x1c, 0x02, 0x30,
+0x3c, 0xf9, 0x11, 0xd4, 0x8c, 0x4e, 0xc0, 0xc1, 0x61, 0xc2, 0x15, 0x4c, 0xaa, 0xab, 0x1d, 0x0b,
+0x31, 0x5f, 0x3b, 0x1c, 0xe2, 0x00, 0x97, 0x44, 0x31, 0xe6, 0xfe, 0x73, 0x96, 0x2f, 0xda, 0x96,
+0xd3, 0xfe, 0x08, 0x07, 0xb3, 0x34, 0x89, 0xbc, 0x05, 0x9f, 0xf7, 0x1e, 0x86, 0xee, 0x8b, 0x70,
+0x30, 0x82, 0x03, 0xba, 0x30, 0x82, 0x02, 0xa2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0b, 0x04,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x86, 0x26, 0xe6, 0x0d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06,
+0x03, 0x55, 0x04, 0x0b, 0x13, 0x17, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e,
+0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x32, 0x31, 0x13, 0x30,
+0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69,
+0x67, 0x6e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f,
+0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x32, 0x31,
+0x35, 0x30, 0x38, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x32, 0x31, 0x35,
+0x30, 0x38, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x13, 0x17, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52,
+0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x32, 0x31, 0x13, 0x30, 0x11, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e,
+0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61,
+0x6c, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
+0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa6, 0xcf, 0x24, 0x0e, 0xbe, 0x2e, 0x6f, 0x28, 0x99, 0x45,
+0x42, 0xc4, 0xab, 0x3e, 0x21, 0x54, 0x9b, 0x0b, 0xd3, 0x7f, 0x84, 0x70, 0xfa, 0x12, 0xb3, 0xcb,
+0xbf, 0x87, 0x5f, 0xc6, 0x7f, 0x86, 0xd3, 0xb2, 0x30, 0x5c, 0xd6, 0xfd, 0xad, 0xf1, 0x7b, 0xdc,
+0xe5, 0xf8, 0x60, 0x96, 0x09, 0x92, 0x10, 0xf5, 0xd0, 0x53, 0xde, 0xfb, 0x7b, 0x7e, 0x73, 0x88,
+0xac, 0x52, 0x88, 0x7b, 0x4a, 0xa6, 0xca, 0x49, 0xa6, 0x5e, 0xa8, 0xa7, 0x8c, 0x5a, 0x11, 0xbc,
+0x7a, 0x82, 0xeb, 0xbe, 0x8c, 0xe9, 0xb3, 0xac, 0x96, 0x25, 0x07, 0x97, 0x4a, 0x99, 0x2a, 0x07,
+0x2f, 0xb4, 0x1e, 0x77, 0xbf, 0x8a, 0x0f, 0xb5, 0x02, 0x7c, 0x1b, 0x96, 0xb8, 0xc5, 0xb9, 0x3a,
+0x2c, 0xbc, 0xd6, 0x12, 0xb9, 0xeb, 0x59, 0x7d, 0xe2, 0xd0, 0x06, 0x86, 0x5f, 0x5e, 0x49, 0x6a,
+0xb5, 0x39, 0x5e, 0x88, 0x34, 0xec, 0xbc, 0x78, 0x0c, 0x08, 0x98, 0x84, 0x6c, 0xa8, 0xcd, 0x4b,
+0xb4, 0xa0, 0x7d, 0x0c, 0x79, 0x4d, 0xf0, 0xb8, 0x2d, 0xcb, 0x21, 0xca, 0xd5, 0x6c, 0x5b, 0x7d,
+0xe1, 0xa0, 0x29, 0x84, 0xa1, 0xf9, 0xd3, 0x94, 0x49, 0xcb, 0x24, 0x62, 0x91, 0x20, 0xbc, 0xdd,
+0x0b, 0xd5, 0xd9, 0xcc, 0xf9, 0xea, 0x27, 0x0a, 0x2b, 0x73, 0x91, 0xc6, 0x9d, 0x1b, 0xac, 0xc8,
+0xcb, 0xe8, 0xe0, 0xa0, 0xf4, 0x2f, 0x90, 0x8b, 0x4d, 0xfb, 0xb0, 0x36, 0x1b, 0xf6, 0x19, 0x7a,
+0x85, 0xe0, 0x6d, 0xf2, 0x61, 0x13, 0x88, 0x5c, 0x9f, 0xe0, 0x93, 0x0a, 0x51, 0x97, 0x8a, 0x5a,
+0xce, 0xaf, 0xab, 0xd5, 0xf7, 0xaa, 0x09, 0xaa, 0x60, 0xbd, 0xdc, 0xd9, 0x5f, 0xdf, 0x72, 0xa9,
+0x60, 0x13, 0x5e, 0x00, 0x01, 0xc9, 0x4a, 0xfa, 0x3f, 0xa4, 0xea, 0x07, 0x03, 0x21, 0x02, 0x8e,
+0x82, 0xca, 0x03, 0xc2, 0x9b, 0x8f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0x9c, 0x30, 0x81,
+0x99, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01,
+0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9b, 0xe2, 0x07,
+0x57, 0x67, 0x1c, 0x1e, 0xc0, 0x6a, 0x06, 0xde, 0x59, 0xb4, 0x9a, 0x2d, 0xdf, 0xdc, 0x19, 0x86,
+0x2e, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29,
+0xa0, 0x27, 0x86, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67,
+0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x72, 0x6f,
+0x6f, 0x74, 0x2d, 0x72, 0x32, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
+0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x9b, 0xe2, 0x07, 0x57, 0x67, 0x1c, 0x1e, 0xc0, 0x6a, 0x06,
+0xde, 0x59, 0xb4, 0x9a, 0x2d, 0xdf, 0xdc, 0x19, 0x86, 0x2e, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x99, 0x81,
+0x53, 0x87, 0x1c, 0x68, 0x97, 0x86, 0x91, 0xec, 0xe0, 0x4a, 0xb8, 0x44, 0x0b, 0xab, 0x81, 0xac,
+0x27, 0x4f, 0xd6, 0xc1, 0xb8, 0x1c, 0x43, 0x78, 0xb3, 0x0c, 0x9a, 0xfc, 0xea, 0x2c, 0x3c, 0x6e,
+0x61, 0x1b, 0x4d, 0x4b, 0x29, 0xf5, 0x9f, 0x05, 0x1d, 0x26, 0xc1, 0xb8, 0xe9, 0x83, 0x00, 0x62,
+0x45, 0xb6, 0xa9, 0x08, 0x93, 0xb9, 0xa9, 0x33, 0x4b, 0x18, 0x9a, 0xc2, 0xf8, 0x87, 0x88, 0x4e,
+0xdb, 0xdd, 0x71, 0x34, 0x1a, 0xc1, 0x54, 0xda, 0x46, 0x3f, 0xe0, 0xd3, 0x2a, 0xab, 0x6d, 0x54,
+0x22, 0xf5, 0x3a, 0x62, 0xcd, 0x20, 0x6f, 0xba, 0x29, 0x89, 0xd7, 0xdd, 0x91, 0xee, 0xd3, 0x5c,
+0xa2, 0x3e, 0xa1, 0x5b, 0x41, 0xf5, 0xdf, 0xe5, 0x64, 0x43, 0x2d, 0xe9, 0xd5, 0x39, 0xab, 0xd2,
+0xa2, 0xdf, 0xb7, 0x8b, 0xd0, 0xc0, 0x80, 0x19, 0x1c, 0x45, 0xc0, 0x2d, 0x8c, 0xe8, 0xf8, 0x2d,
+0xa4, 0x74, 0x56, 0x49, 0xc5, 0x05, 0xb5, 0x4f, 0x15, 0xde, 0x6e, 0x44, 0x78, 0x39, 0x87, 0xa8,
+0x7e, 0xbb, 0xf3, 0x79, 0x18, 0x91, 0xbb, 0xf4, 0x6f, 0x9d, 0xc1, 0xf0, 0x8c, 0x35, 0x8c, 0x5d,
+0x01, 0xfb, 0xc3, 0x6d, 0xb9, 0xef, 0x44, 0x6d, 0x79, 0x46, 0x31, 0x7e, 0x0a, 0xfe, 0xa9, 0x82,
+0xc1, 0xff, 0xef, 0xab, 0x6e, 0x20, 0xc4, 0x50, 0xc9, 0x5f, 0x9d, 0x4d, 0x9b, 0x17, 0x8c, 0x0c,
+0xe5, 0x01, 0xc9, 0xa0, 0x41, 0x6a, 0x73, 0x53, 0xfa, 0xa5, 0x50, 0xb4, 0x6e, 0x25, 0x0f, 0xfb,
+0x4c, 0x18, 0xf4, 0xfd, 0x52, 0xd9, 0x8e, 0x69, 0xb1, 0xe8, 0x11, 0x0f, 0xde, 0x88, 0xd8, 0xfb,
+0x1d, 0x49, 0xf7, 0xaa, 0xde, 0x95, 0xcf, 0x20, 0x78, 0xc2, 0x60, 0x12, 0xdb, 0x25, 0x40, 0x8c,
+0x6a, 0xfc, 0x7e, 0x42, 0x38, 0x40, 0x64, 0x12, 0xf7, 0x9e, 0x81, 0xe1, 0x93, 0x2e, 0x30, 0x82,
+0x03, 0x5f, 0x30, 0x82, 0x02, 0x47, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0b, 0x04, 0x00, 0x00,
+0x00, 0x00, 0x01, 0x21, 0x58, 0x53, 0x08, 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x13, 0x17, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52,
+0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x33, 0x31, 0x13, 0x30, 0x11, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e,
+0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61,
+0x6c, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x33, 0x31, 0x38, 0x31,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x30, 0x33, 0x31, 0x38, 0x31, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x0b,
+0x13, 0x17, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f,
+0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x33, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x31, 0x13,
+0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53,
+0x69, 0x67, 0x6e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
+0x82, 0x01, 0x01, 0x00, 0xcc, 0x25, 0x76, 0x90, 0x79, 0x06, 0x78, 0x22, 0x16, 0xf5, 0xc0, 0x83,
+0xb6, 0x84, 0xca, 0x28, 0x9e, 0xfd, 0x05, 0x76, 0x11, 0xc5, 0xad, 0x88, 0x72, 0xfc, 0x46, 0x02,
+0x43, 0xc7, 0xb2, 0x8a, 0x9d, 0x04, 0x5f, 0x24, 0xcb, 0x2e, 0x4b, 0xe1, 0x60, 0x82, 0x46, 0xe1,
+0x52, 0xab, 0x0c, 0x81, 0x47, 0x70, 0x6c, 0xdd, 0x64, 0xd1, 0xeb, 0xf5, 0x2c, 0xa3, 0x0f, 0x82,
+0x3d, 0x0c, 0x2b, 0xae, 0x97, 0xd7, 0xb6, 0x14, 0x86, 0x10, 0x79, 0xbb, 0x3b, 0x13, 0x80, 0x77,
+0x8c, 0x08, 0xe1, 0x49, 0xd2, 0x6a, 0x62, 0x2f, 0x1f, 0x5e, 0xfa, 0x96, 0x68, 0xdf, 0x89, 0x27,
+0x95, 0x38, 0x9f, 0x06, 0xd7, 0x3e, 0xc9, 0xcb, 0x26, 0x59, 0x0d, 0x73, 0xde, 0xb0, 0xc8, 0xe9,
+0x26, 0x0e, 0x83, 0x15, 0xc6, 0xef, 0x5b, 0x8b, 0xd2, 0x04, 0x60, 0xca, 0x49, 0xa6, 0x28, 0xf6,
+0x69, 0x3b, 0xf6, 0xcb, 0xc8, 0x28, 0x91, 0xe5, 0x9d, 0x8a, 0x61, 0x57, 0x37, 0xac, 0x74, 0x14,
+0xdc, 0x74, 0xe0, 0x3a, 0xee, 0x72, 0x2f, 0x2e, 0x9c, 0xfb, 0xd0, 0xbb, 0xbf, 0xf5, 0x3d, 0x00,
+0xe1, 0x06, 0x33, 0xe8, 0x82, 0x2b, 0xae, 0x53, 0xa6, 0x3a, 0x16, 0x73, 0x8c, 0xdd, 0x41, 0x0e,
+0x20, 0x3a, 0xc0, 0xb4, 0xa7, 0xa1, 0xe9, 0xb2, 0x4f, 0x90, 0x2e, 0x32, 0x60, 0xe9, 0x57, 0xcb,
+0xb9, 0x04, 0x92, 0x68, 0x68, 0xe5, 0x38, 0x26, 0x60, 0x75, 0xb2, 0x9f, 0x77, 0xff, 0x91, 0x14,
+0xef, 0xae, 0x20, 0x49, 0xfc, 0xad, 0x40, 0x15, 0x48, 0xd1, 0x02, 0x31, 0x61, 0x19, 0x5e, 0xb8,
+0x97, 0xef, 0xad, 0x77, 0xb7, 0x64, 0x9a, 0x7a, 0xbf, 0x5f, 0xc1, 0x13, 0xef, 0x9b, 0x62, 0xfb,
+0x0d, 0x6c, 0xe0, 0x54, 0x69, 0x16, 0xa9, 0x03, 0xda, 0x6e, 0xe9, 0x83, 0x93, 0x71, 0x76, 0xc6,
+0x69, 0x85, 0x82, 0x17, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x8f, 0xf0, 0x4b, 0x7f, 0xa8, 0x2e, 0x45,
+0x24, 0xae, 0x4d, 0x50, 0xfa, 0x63, 0x9a, 0x8b, 0xde, 0xe2, 0xdd, 0x1b, 0xbc, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+0x00, 0x4b, 0x40, 0xdb, 0xc0, 0x50, 0xaa, 0xfe, 0xc8, 0x0c, 0xef, 0xf7, 0x96, 0x54, 0x45, 0x49,
+0xbb, 0x96, 0x00, 0x09, 0x41, 0xac, 0xb3, 0x13, 0x86, 0x86, 0x28, 0x07, 0x33, 0xca, 0x6b, 0xe6,
+0x74, 0xb9, 0xba, 0x00, 0x2d, 0xae, 0xa4, 0x0a, 0xd3, 0xf5, 0xf1, 0xf1, 0x0f, 0x8a, 0xbf, 0x73,
+0x67, 0x4a, 0x83, 0xc7, 0x44, 0x7b, 0x78, 0xe0, 0xaf, 0x6e, 0x6c, 0x6f, 0x03, 0x29, 0x8e, 0x33,
+0x39, 0x45, 0xc3, 0x8e, 0xe4, 0xb9, 0x57, 0x6c, 0xaa, 0xfc, 0x12, 0x96, 0xec, 0x53, 0xc6, 0x2d,
+0xe4, 0x24, 0x6c, 0xb9, 0x94, 0x63, 0xfb, 0xdc, 0x53, 0x68, 0x67, 0x56, 0x3e, 0x83, 0xb8, 0xcf,
+0x35, 0x21, 0xc3, 0xc9, 0x68, 0xfe, 0xce, 0xda, 0xc2, 0x53, 0xaa, 0xcc, 0x90, 0x8a, 0xe9, 0xf0,
+0x5d, 0x46, 0x8c, 0x95, 0xdd, 0x7a, 0x58, 0x28, 0x1a, 0x2f, 0x1d, 0xde, 0xcd, 0x00, 0x37, 0x41,
+0x8f, 0xed, 0x44, 0x6d, 0xd7, 0x53, 0x28, 0x97, 0x7e, 0xf3, 0x67, 0x04, 0x1e, 0x15, 0xd7, 0x8a,
+0x96, 0xb4, 0xd3, 0xde, 0x4c, 0x27, 0xa4, 0x4c, 0x1b, 0x73, 0x73, 0x76, 0xf4, 0x17, 0x99, 0xc2,
+0x1f, 0x7a, 0x0e, 0xe3, 0x2d, 0x08, 0xad, 0x0a, 0x1c, 0x2c, 0xff, 0x3c, 0xab, 0x55, 0x0e, 0x0f,
+0x91, 0x7e, 0x36, 0xeb, 0xc3, 0x57, 0x49, 0xbe, 0xe1, 0x2e, 0x2d, 0x7c, 0x60, 0x8b, 0xc3, 0x41,
+0x51, 0x13, 0x23, 0x9d, 0xce, 0xf7, 0x32, 0x6b, 0x94, 0x01, 0xa8, 0x99, 0xe7, 0x2c, 0x33, 0x1f,
+0x3a, 0x3b, 0x25, 0xd2, 0x86, 0x40, 0xce, 0x3b, 0x2c, 0x86, 0x78, 0xc9, 0x61, 0x2f, 0x14, 0xba,
+0xee, 0xdb, 0x55, 0x6f, 0xdf, 0x84, 0xee, 0x05, 0x09, 0x4d, 0xbd, 0x28, 0xd8, 0x72, 0xce, 0xd3,
+0x62, 0x50, 0x65, 0x1e, 0xeb, 0x92, 0x97, 0x83, 0x31, 0xd9, 0xb3, 0xb5, 0xca, 0x47, 0x58, 0x3f,
+0x5f, 0x30, 0x82, 0x03, 0x75, 0x30, 0x82, 0x02, 0x5d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0b,
+0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x15, 0x4b, 0x5a, 0xc3, 0x94, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x42, 0x45, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e,
+0x76, 0x2d, 0x73, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52,
+0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x39, 0x38, 0x30, 0x39, 0x30, 0x31, 0x31, 0x32, 0x30,
+0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x31, 0x32, 0x38, 0x31, 0x32, 0x30, 0x30,
+0x30, 0x30, 0x5a, 0x30, 0x57, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x42, 0x45, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x10, 0x47, 0x6c, 0x6f,
+0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x6e, 0x76, 0x2d, 0x73, 0x61, 0x31, 0x10, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31,
+0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xda, 0x0e, 0xe6,
+0x99, 0x8d, 0xce, 0xa3, 0xe3, 0x4f, 0x8a, 0x7e, 0xfb, 0xf1, 0x8b, 0x83, 0x25, 0x6b, 0xea, 0x48,
+0x1f, 0xf1, 0x2a, 0xb0, 0xb9, 0x95, 0x11, 0x04, 0xbd, 0xf0, 0x63, 0xd1, 0xe2, 0x67, 0x66, 0xcf,
+0x1c, 0xdd, 0xcf, 0x1b, 0x48, 0x2b, 0xee, 0x8d, 0x89, 0x8e, 0x9a, 0xaf, 0x29, 0x80, 0x65, 0xab,
+0xe9, 0xc7, 0x2d, 0x12, 0xcb, 0xab, 0x1c, 0x4c, 0x70, 0x07, 0xa1, 0x3d, 0x0a, 0x30, 0xcd, 0x15,
+0x8d, 0x4f, 0xf8, 0xdd, 0xd4, 0x8c, 0x50, 0x15, 0x1c, 0xef, 0x50, 0xee, 0xc4, 0x2e, 0xf7, 0xfc,
+0xe9, 0x52, 0xf2, 0x91, 0x7d, 0xe0, 0x6d, 0xd5, 0x35, 0x30, 0x8e, 0x5e, 0x43, 0x73, 0xf2, 0x41,
+0xe9, 0xd5, 0x6a, 0xe3, 0xb2, 0x89, 0x3a, 0x56, 0x39, 0x38, 0x6f, 0x06, 0x3c, 0x88, 0x69, 0x5b,
+0x2a, 0x4d, 0xc5, 0xa7, 0x54, 0xb8, 0x6c, 0x89, 0xcc, 0x9b, 0xf9, 0x3c, 0xca, 0xe5, 0xfd, 0x89,
+0xf5, 0x12, 0x3c, 0x92, 0x78, 0x96, 0xd6, 0xdc, 0x74, 0x6e, 0x93, 0x44, 0x61, 0xd1, 0x8d, 0xc7,
+0x46, 0xb2, 0x75, 0x0e, 0x86, 0xe8, 0x19, 0x8a, 0xd5, 0x6d, 0x6c, 0xd5, 0x78, 0x16, 0x95, 0xa2,
+0xe9, 0xc8, 0x0a, 0x38, 0xeb, 0xf2, 0x24, 0x13, 0x4f, 0x73, 0x54, 0x93, 0x13, 0x85, 0x3a, 0x1b,
+0xbc, 0x1e, 0x34, 0xb5, 0x8b, 0x05, 0x8c, 0xb9, 0x77, 0x8b, 0xb1, 0xdb, 0x1f, 0x20, 0x91, 0xab,
+0x09, 0x53, 0x6e, 0x90, 0xce, 0x7b, 0x37, 0x74, 0xb9, 0x70, 0x47, 0x91, 0x22, 0x51, 0x63, 0x16,
+0x79, 0xae, 0xb1, 0xae, 0x41, 0x26, 0x08, 0xc8, 0x19, 0x2b, 0xd1, 0x46, 0xaa, 0x48, 0xd6, 0x64,
+0x2a, 0xd7, 0x83, 0x34, 0xff, 0x2c, 0x2a, 0xc1, 0x6c, 0x19, 0x43, 0x4a, 0x07, 0x85, 0xe7, 0xd3,
+0x7c, 0xf6, 0x21, 0x68, 0xef, 0xea, 0xf2, 0x52, 0x9f, 0x7f, 0x93, 0x90, 0xcf, 0x02, 0x03, 0x01,
+0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+0x04, 0x14, 0x60, 0x7b, 0x66, 0x1a, 0x45, 0x0d, 0x97, 0xca, 0x89, 0x50, 0x2f, 0x7d, 0x04, 0xcd,
+0x34, 0xa8, 0xff, 0xfc, 0xfd, 0x4b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xd6, 0x73, 0xe7, 0x7c, 0x4f, 0x76,
+0xd0, 0x8d, 0xbf, 0xec, 0xba, 0xa2, 0xbe, 0x34, 0xc5, 0x28, 0x32, 0xb5, 0x7c, 0xfc, 0x6c, 0x9c,
+0x2c, 0x2b, 0xbd, 0x09, 0x9e, 0x53, 0xbf, 0x6b, 0x5e, 0xaa, 0x11, 0x48, 0xb6, 0xe5, 0x08, 0xa3,
+0xb3, 0xca, 0x3d, 0x61, 0x4d, 0xd3, 0x46, 0x09, 0xb3, 0x3e, 0xc3, 0xa0, 0xe3, 0x63, 0x55, 0x1b,
+0xf2, 0xba, 0xef, 0xad, 0x39, 0xe1, 0x43, 0xb9, 0x38, 0xa3, 0xe6, 0x2f, 0x8a, 0x26, 0x3b, 0xef,
+0xa0, 0x50, 0x56, 0xf9, 0xc6, 0x0a, 0xfd, 0x38, 0xcd, 0xc4, 0x0b, 0x70, 0x51, 0x94, 0x97, 0x98,
+0x04, 0xdf, 0xc3, 0x5f, 0x94, 0xd5, 0x15, 0xc9, 0x14, 0x41, 0x9c, 0xc4, 0x5d, 0x75, 0x64, 0x15,
+0x0d, 0xff, 0x55, 0x30, 0xec, 0x86, 0x8f, 0xff, 0x0d, 0xef, 0x2c, 0xb9, 0x63, 0x46, 0xf6, 0xaa,
+0xfc, 0xdf, 0xbc, 0x69, 0xfd, 0x2e, 0x12, 0x48, 0x64, 0x9a, 0xe0, 0x95, 0xf0, 0xa6, 0xef, 0x29,
+0x8f, 0x01, 0xb1, 0x15, 0xb5, 0x0c, 0x1d, 0xa5, 0xfe, 0x69, 0x2c, 0x69, 0x24, 0x78, 0x1e, 0xb3,
+0xa7, 0x1c, 0x71, 0x62, 0xee, 0xca, 0xc8, 0x97, 0xac, 0x17, 0x5d, 0x8a, 0xc2, 0xf8, 0x47, 0x86,
+0x6e, 0x2a, 0xc4, 0x56, 0x31, 0x95, 0xd0, 0x67, 0x89, 0x85, 0x2b, 0xf9, 0x6c, 0xa6, 0x5d, 0x46,
+0x9d, 0x0c, 0xaa, 0x82, 0xe4, 0x99, 0x51, 0xdd, 0x70, 0xb7, 0xdb, 0x56, 0x3d, 0x61, 0xe4, 0x6a,
+0xe1, 0x5c, 0xd6, 0xf6, 0xfe, 0x3d, 0xde, 0x41, 0xcc, 0x07, 0xae, 0x63, 0x52, 0xbf, 0x53, 0x53,
+0xf4, 0x2b, 0xe9, 0xc7, 0xfd, 0xb6, 0xf7, 0x82, 0x5f, 0x85, 0xd2, 0x41, 0x18, 0xdb, 0x81, 0xb3,
+0x04, 0x1c, 0xc5, 0x1f, 0xa4, 0x80, 0x6f, 0x15, 0x20, 0xc9, 0xde, 0x0c, 0x88, 0x0a, 0x1d, 0xd6,
+0x66, 0x55, 0xe2, 0xfc, 0x48, 0xc9, 0x29, 0x26, 0x69, 0xe0, 0x30, 0x82, 0x02, 0x1e, 0x30, 0x82,
+0x01, 0xa4, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x11, 0x60, 0x59, 0x49, 0xe0, 0x26, 0x2e, 0xbb,
+0x55, 0xf9, 0x0a, 0x77, 0x8a, 0x71, 0xf9, 0x4a, 0xd8, 0x6c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
+0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x50, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04,
+0x0b, 0x13, 0x1b, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43,
+0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x35, 0x31, 0x13,
+0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53,
+0x69, 0x67, 0x6e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c,
+0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31, 0x31,
+0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31,
+0x39, 0x30, 0x33, 0x31, 0x34, 0x30, 0x37, 0x5a, 0x30, 0x50, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03,
+0x55, 0x04, 0x0b, 0x13, 0x1b, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20,
+0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x35,
+0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61,
+0x6c, 0x53, 0x69, 0x67, 0x6e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a,
+0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07,
+0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62,
+0x00, 0x04, 0x47, 0x45, 0x0e, 0x96, 0xfb, 0x7d, 0x5d, 0xbf, 0xe9, 0x39, 0xd1, 0x21, 0xf8, 0x9f,
+0x0b, 0xb6, 0xd5, 0x7b, 0x1e, 0x92, 0x3a, 0x48, 0x59, 0x1c, 0xf0, 0x62, 0x31, 0x2d, 0xc0, 0x7a,
+0x28, 0xfe, 0x1a, 0xa7, 0x5c, 0xb3, 0xb6, 0xcc, 0x97, 0xe7, 0x45, 0xd4, 0x58, 0xfa, 0xd1, 0x77,
+0x6d, 0x43, 0xa2, 0xc0, 0x87, 0x65, 0x34, 0x0a, 0x1f, 0x7a, 0xdd, 0xeb, 0x3c, 0x33, 0xa1, 0xc5,
+0x9d, 0x4d, 0xa4, 0x6f, 0x41, 0x95, 0x38, 0x7f, 0xc9, 0x1e, 0x84, 0xeb, 0xd1, 0x9e, 0x49, 0x92,
+0x87, 0x94, 0x87, 0x0c, 0x3a, 0x85, 0x4a, 0x66, 0x9f, 0x9d, 0x59, 0x93, 0x4d, 0x97, 0x61, 0x06,
+0x86, 0x4a, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+0x04, 0x14, 0x3d, 0xe6, 0x29, 0x48, 0x9b, 0xea, 0x07, 0xca, 0x21, 0x44, 0x4a, 0x26, 0xde, 0x6e,
+0xde, 0xd2, 0x83, 0xd0, 0x9f, 0x59, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
+0x03, 0x03, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x31, 0x00, 0xe5, 0x69, 0x12, 0xc9, 0x6e, 0xdb,
+0xc6, 0x31, 0xba, 0x09, 0x41, 0xe1, 0x97, 0xf8, 0xfb, 0xfd, 0x9a, 0xe2, 0x7d, 0x12, 0xc9, 0xed,
+0x7c, 0x64, 0xd3, 0xcb, 0x05, 0x25, 0x8b, 0x56, 0xd9, 0xa0, 0xe7, 0x5e, 0x5d, 0x4e, 0x0b, 0x83,
+0x9c, 0x5b, 0x76, 0x29, 0xa0, 0x09, 0x26, 0x21, 0x6a, 0x62, 0x02, 0x30, 0x71, 0xd2, 0xb5, 0x8f,
+0x5c, 0xea, 0x3b, 0xe1, 0x78, 0x09, 0x85, 0xa8, 0x75, 0x92, 0x3b, 0xc8, 0x5c, 0xfd, 0x48, 0xef,
+0x0d, 0x74, 0x22, 0xa8, 0x08, 0xe2, 0x6e, 0xc5, 0x49, 0xce, 0xc7, 0x0c, 0xbc, 0xa7, 0x61, 0x69,
+0xf1, 0xf7, 0x3b, 0xe1, 0x2a, 0xcb, 0xf9, 0x2b, 0xf3, 0x66, 0x90, 0x37, 0x30, 0x82, 0x05, 0x83,
+0x30, 0x82, 0x03, 0x6b, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0e, 0x45, 0xe6, 0xbb, 0x03, 0x83,
+0x33, 0xc3, 0x85, 0x65, 0x48, 0xe6, 0xff, 0x45, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03,
+0x55, 0x04, 0x0b, 0x13, 0x17, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20,
+0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x36, 0x31, 0x13, 0x30, 0x11,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67,
+0x6e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62,
+0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x34, 0x31, 0x32, 0x31, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04,
+0x0b, 0x13, 0x17, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x36, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x31,
+0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+0x53, 0x69, 0x67, 0x6e, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a,
+0x02, 0x82, 0x02, 0x01, 0x00, 0x95, 0x07, 0xe8, 0x73, 0xca, 0x66, 0xf9, 0xec, 0x14, 0xca, 0x7b,
+0x3c, 0xf7, 0x0d, 0x08, 0xf1, 0xb4, 0x45, 0x0b, 0x2c, 0x82, 0xb4, 0x48, 0xc6, 0xeb, 0x5b, 0x3c,
+0xae, 0x83, 0xb8, 0x41, 0x92, 0x33, 0x14, 0xa4, 0x6f, 0x7f, 0xe9, 0x2a, 0xcc, 0xc6, 0xb0, 0x88,
+0x6b, 0xc5, 0xb6, 0x89, 0xd1, 0xc6, 0xb2, 0xff, 0x14, 0xce, 0x51, 0x14, 0x21, 0xec, 0x4a, 0xdd,
+0x1b, 0x5a, 0xc6, 0xd6, 0x87, 0xee, 0x4d, 0x3a, 0x15, 0x06, 0xed, 0x64, 0x66, 0x0b, 0x92, 0x80,
+0xca, 0x44, 0xde, 0x73, 0x94, 0x4e, 0xf3, 0xa7, 0x89, 0x7f, 0x4f, 0x78, 0x63, 0x08, 0xc8, 0x12,
+0x50, 0x6d, 0x42, 0x66, 0x2f, 0x4d, 0xb9, 0x79, 0x28, 0x4d, 0x52, 0x1a, 0x8a, 0x1a, 0x80, 0xb7,
+0x19, 0x81, 0x0e, 0x7e, 0xc4, 0x8a, 0xbc, 0x64, 0x4c, 0x21, 0x1c, 0x43, 0x68, 0xd7, 0x3d, 0x3c,
+0x8a, 0xc5, 0xb2, 0x66, 0xd5, 0x90, 0x9a, 0xb7, 0x31, 0x06, 0xc5, 0xbe, 0xe2, 0x6d, 0x32, 0x06,
+0xa6, 0x1e, 0xf9, 0xb9, 0xeb, 0xaa, 0xa3, 0xb8, 0xbf, 0xbe, 0x82, 0x63, 0x50, 0xd0, 0xf0, 0x18,
+0x89, 0xdf, 0xe4, 0x0f, 0x79, 0xf5, 0xea, 0xa2, 0x1f, 0x2a, 0xd2, 0x70, 0x2e, 0x7b, 0xe7, 0xbc,
+0x93, 0xbb, 0x6d, 0x53, 0xe2, 0x48, 0x7c, 0x8c, 0x10, 0x07, 0x38, 0xff, 0x66, 0xb2, 0x77, 0x61,
+0x7e, 0xe0, 0xea, 0x8c, 0x3c, 0xaa, 0xb4, 0xa4, 0xf6, 0xf3, 0x95, 0x4a, 0x12, 0x07, 0x6d, 0xfd,
+0x8c, 0xb2, 0x89, 0xcf, 0xd0, 0xa0, 0x61, 0x77, 0xc8, 0x58, 0x74, 0xb0, 0xd4, 0x23, 0x3a, 0xf7,
+0x5d, 0x3a, 0xca, 0xa2, 0xdb, 0x9d, 0x09, 0xde, 0x5d, 0x44, 0x2d, 0x90, 0xf1, 0x81, 0xcd, 0x57,
+0x92, 0xfa, 0x7e, 0xbc, 0x50, 0x04, 0x63, 0x34, 0xdf, 0x6b, 0x93, 0x18, 0xbe, 0x6b, 0x36, 0xb2,
+0x39, 0xe4, 0xac, 0x24, 0x36, 0xb7, 0xf0, 0xef, 0xb6, 0x1c, 0x13, 0x57, 0x93, 0xb6, 0xde, 0xb2,
+0xf8, 0xe2, 0x85, 0xb7, 0x73, 0xa2, 0xb8, 0x35, 0xaa, 0x45, 0xf2, 0xe0, 0x9d, 0x36, 0xa1, 0x6f,
+0x54, 0x8a, 0xf1, 0x72, 0x56, 0x6e, 0x2e, 0x88, 0xc5, 0x51, 0x42, 0x44, 0x15, 0x94, 0xee, 0xa3,
+0xc5, 0x38, 0x96, 0x9b, 0x4e, 0x4e, 0x5a, 0x0b, 0x47, 0xf3, 0x06, 0x36, 0x49, 0x77, 0x30, 0xbc,
+0x71, 0x37, 0xe5, 0xa6, 0xec, 0x21, 0x08, 0x75, 0xfc, 0xe6, 0x61, 0x16, 0x3f, 0x77, 0xd5, 0xd9,
+0x91, 0x97, 0x84, 0x0a, 0x6c, 0xd4, 0x02, 0x4d, 0x74, 0xc0, 0x14, 0xed, 0xfd, 0x39, 0xfb, 0x83,
+0xf2, 0x5e, 0x14, 0xa1, 0x04, 0xb0, 0x0b, 0xe9, 0xfe, 0xee, 0x8f, 0xe1, 0x6e, 0x0b, 0xb2, 0x08,
+0xb3, 0x61, 0x66, 0x09, 0x6a, 0xb1, 0x06, 0x3a, 0x65, 0x96, 0x59, 0xc0, 0xf0, 0x35, 0xfd, 0xc9,
+0xda, 0x28, 0x8d, 0x1a, 0x11, 0x87, 0x70, 0x81, 0x0a, 0xa8, 0x9a, 0x75, 0x1d, 0x9e, 0x3a, 0x86,
+0x05, 0x00, 0x9e, 0xdb, 0x80, 0xd6, 0x25, 0xf9, 0xdc, 0x05, 0x9e, 0x27, 0x59, 0x4c, 0x76, 0x39,
+0x5b, 0xea, 0xf9, 0xa5, 0xa1, 0xd8, 0x83, 0x0f, 0xd1, 0xff, 0xdf, 0x30, 0x11, 0xf9, 0x85, 0xcf,
+0x33, 0x48, 0xf5, 0xca, 0x6d, 0x64, 0x14, 0x2c, 0x7a, 0x58, 0x4f, 0xd3, 0x4b, 0x08, 0x49, 0xc5,
+0x95, 0x64, 0x1a, 0x63, 0x0e, 0x79, 0x3d, 0xf5, 0xb3, 0x8c, 0xca, 0x58, 0xad, 0x9c, 0x42, 0x45,
+0x79, 0x6e, 0x0e, 0x87, 0x19, 0x5c, 0x54, 0xb1, 0x65, 0xb6, 0xbf, 0x8c, 0x9b, 0xdc, 0x13, 0xe9,
+0x0d, 0x6f, 0xb8, 0x2e, 0xdc, 0x67, 0x6e, 0xc9, 0x8b, 0x11, 0xb5, 0x84, 0x14, 0x8a, 0x00, 0x19,
+0x70, 0x83, 0x79, 0x91, 0x97, 0x91, 0xd4, 0x1a, 0x27, 0xbf, 0x37, 0x1e, 0x32, 0x07, 0xd8, 0x14,
+0x63, 0x3c, 0x28, 0x4c, 0xaf, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0e,
+0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f,
+0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xae, 0x6c, 0x05, 0xa3, 0x93, 0x13,
+0xe2, 0xa2, 0xe7, 0xe2, 0xd7, 0x1c, 0xd6, 0xc7, 0xf0, 0x7f, 0xc8, 0x67, 0x53, 0xa0, 0x30, 0x1f,
+0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xae, 0x6c, 0x05, 0xa3, 0x93,
+0x13, 0xe2, 0xa2, 0xe7, 0xe2, 0xd7, 0x1c, 0xd6, 0xc7, 0xf0, 0x7f, 0xc8, 0x67, 0x53, 0xa0, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x03, 0x82,
+0x02, 0x01, 0x00, 0x83, 0x25, 0xed, 0xe8, 0xd1, 0xfd, 0x95, 0x52, 0xcd, 0x9e, 0xc0, 0x04, 0xa0,
+0x91, 0x69, 0xe6, 0x5c, 0xd0, 0x84, 0xde, 0xdc, 0xad, 0xa2, 0x4f, 0xe8, 0x47, 0x78, 0xd6, 0x65,
+0x98, 0xa9, 0x5b, 0xa8, 0x3c, 0x87, 0x7c, 0x02, 0x8a, 0xd1, 0x6e, 0xb7, 0x16, 0x73, 0xe6, 0x5f,
+0xc0, 0x54, 0x98, 0xd5, 0x74, 0xbe, 0xc1, 0xcd, 0xe2, 0x11, 0x91, 0xad, 0x23, 0x18, 0x3d, 0xdd,
+0xe1, 0x72, 0x44, 0x96, 0xb4, 0x95, 0x5e, 0xc0, 0x7b, 0x8e, 0x99, 0x78, 0x16, 0x43, 0x13, 0x56,
+0x57, 0xb3, 0xa2, 0xb3, 0x3b, 0xb5, 0x77, 0xdc, 0x40, 0x72, 0xac, 0xa3, 0xeb, 0x9b, 0x35, 0x3e,
+0xb1, 0x08, 0x21, 0xa1, 0xe7, 0xc4, 0x43, 0x37, 0x79, 0x32, 0xbe, 0xb5, 0xe7, 0x9c, 0x2c, 0x4c,
+0xbc, 0x43, 0x29, 0x99, 0x8e, 0x30, 0xd3, 0xac, 0x21, 0xe0, 0xe3, 0x1d, 0xfa, 0xd8, 0x07, 0x33,
+0x76, 0x54, 0x00, 0x22, 0x2a, 0xb9, 0x4d, 0x20, 0x2e, 0x70, 0x68, 0xda, 0xe5, 0x53, 0xfc, 0x83,
+0x5c, 0xd3, 0x9d, 0xf2, 0xff, 0x44, 0x0c, 0x44, 0x66, 0xf2, 0xd2, 0xe3, 0xbd, 0x46, 0x00, 0x1a,
+0x6d, 0x02, 0xba, 0x25, 0x5d, 0x8d, 0xa1, 0x31, 0x51, 0xdd, 0x54, 0x46, 0x1c, 0x4d, 0xdb, 0x99,
+0x96, 0xef, 0x1a, 0x1c, 0x04, 0x5c, 0xa6, 0x15, 0xef, 0x78, 0xe0, 0x79, 0xfe, 0x5d, 0xdb, 0x3e,
+0xaa, 0x4c, 0x55, 0xfd, 0x9a, 0x15, 0xa9, 0x6f, 0xe1, 0xa6, 0xfb, 0xdf, 0x70, 0x30, 0xe9, 0xc3,
+0xee, 0x42, 0x46, 0xed, 0xc2, 0x93, 0x05, 0x89, 0xfa, 0x7d, 0x63, 0x7b, 0x3f, 0xd0, 0x71, 0x81,
+0x7c, 0x00, 0xe8, 0x98, 0xae, 0x0e, 0x78, 0x34, 0xc3, 0x25, 0xfb, 0xaf, 0x0a, 0x9f, 0x20, 0x6b,
+0xdd, 0x3b, 0x13, 0x8f, 0x12, 0x8c, 0xe2, 0x41, 0x1a, 0x48, 0x7a, 0x73, 0xa0, 0x77, 0x69, 0xc7,
+0xb6, 0x5c, 0x7f, 0x82, 0xc8, 0x1e, 0xfe, 0x58, 0x1b, 0x28, 0x2b, 0xa8, 0x6c, 0xad, 0x5e, 0x6d,
+0xc0, 0x05, 0xd2, 0x7b, 0xb7, 0xeb, 0x80, 0xfe, 0x25, 0x37, 0xfe, 0x02, 0x9b, 0x68, 0xac, 0x42,
+0x5d, 0xc3, 0xee, 0xf5, 0xcc, 0xdc, 0xf0, 0x50, 0x75, 0xd2, 0x36, 0x69, 0x9c, 0xe6, 0x7b, 0x04,
+0xdf, 0x6e, 0x06, 0x69, 0xb6, 0xde, 0x0a, 0x09, 0x48, 0x59, 0x87, 0xeb, 0x7b, 0x14, 0x60, 0x7a,
+0x64, 0xaa, 0x69, 0x43, 0xef, 0x91, 0xc7, 0x4c, 0xec, 0x18, 0xdd, 0x6c, 0xef, 0x53, 0x2d, 0x8c,
+0x99, 0xe1, 0x5e, 0xf2, 0x72, 0x3e, 0xcf, 0x54, 0xc8, 0xbd, 0x67, 0xec, 0xa4, 0x0f, 0x4c, 0x45,
+0xff, 0xd3, 0xb9, 0x30, 0x23, 0x07, 0x4c, 0x8f, 0x10, 0xbf, 0x86, 0x96, 0xd9, 0x99, 0x5a, 0xb4,
+0x99, 0x57, 0x1c, 0xa4, 0xcc, 0xbb, 0x15, 0x89, 0x53, 0xba, 0x2c, 0x05, 0x0f, 0xe4, 0xc4, 0x9e,
+0x19, 0xb1, 0x18, 0x34, 0xd5, 0x4c, 0x9d, 0xba, 0xed, 0xf7, 0x1f, 0xaf, 0x24, 0x95, 0x04, 0x78,
+0xa8, 0x03, 0xbb, 0xee, 0x81, 0xe5, 0xda, 0x5f, 0x7c, 0x8b, 0x4a, 0xa1, 0x90, 0x74, 0x25, 0xa7,
+0xb3, 0x3e, 0x4b, 0xc8, 0x2c, 0x56, 0xbd, 0xc7, 0xc8, 0xef, 0x38, 0xe2, 0x5c, 0x92, 0xf0, 0x79,
+0xf7, 0x9c, 0x84, 0xba, 0x74, 0x2d, 0x61, 0x01, 0x20, 0x7e, 0x7e, 0xd1, 0xf2, 0x4f, 0x07, 0x59,
+0x5f, 0x8b, 0x2d, 0x43, 0x52, 0xeb, 0x46, 0x0c, 0x94, 0xe1, 0xf5, 0x66, 0x47, 0x79, 0x77, 0xd5,
+0x54, 0x5b, 0x1f, 0xad, 0x24, 0x37, 0xcb, 0x45, 0x5a, 0x4e, 0xa0, 0x44, 0x48, 0xc8, 0xd8, 0xb0,
+0x99, 0xc5, 0x15, 0x84, 0x09, 0xf6, 0xd6, 0x49, 0x49, 0xc0, 0x65, 0xb8, 0xe6, 0x1a, 0x71, 0x6e,
+0xa0, 0xa8, 0xf1, 0x82, 0xe8, 0x45, 0x3e, 0x6c, 0xd6, 0x02, 0xd7, 0x0a, 0x67, 0x83, 0x05, 0x5a,
+0xc9, 0xa4, 0x10, 0x30, 0x82, 0x04, 0x0a, 0x30, 0x82, 0x02, 0xf2, 0xa0, 0x03, 0x02, 0x01, 0x02,
+0x02, 0x09, 0x00, 0xc2, 0x7e, 0x43, 0x04, 0x4e, 0x47, 0x3f, 0x19, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65, 0x73, 0x74, 0x31, 0x16, 0x30,
+0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63,
+0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e,
+0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x65, 0x2d, 0x53, 0x7a, 0x69, 0x67, 0x6e,
+0x6f, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x30, 0x39, 0x31, 0x1f,
+0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69,
+0x6e, 0x66, 0x6f, 0x40, 0x65, 0x2d, 0x73, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x2e, 0x68, 0x75, 0x30,
+0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x36, 0x31, 0x36, 0x31, 0x31, 0x33, 0x30, 0x31, 0x38, 0x5a,
+0x17, 0x0d, 0x32, 0x39, 0x31, 0x32, 0x33, 0x30, 0x31, 0x31, 0x33, 0x30, 0x31, 0x38, 0x5a, 0x30,
+0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48, 0x55, 0x31,
+0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65,
+0x73, 0x74, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0d, 0x4d, 0x69, 0x63,
+0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x0c, 0x1e, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x65, 0x2d,
+0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x32,
+0x30, 0x30, 0x39, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x65, 0x2d, 0x73, 0x7a, 0x69, 0x67, 0x6e,
+0x6f, 0x2e, 0x68, 0x75, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
+0x02, 0x82, 0x01, 0x01, 0x00, 0xe9, 0xf8, 0x8f, 0xf3, 0x63, 0xad, 0xda, 0x86, 0xd8, 0xa7, 0xe0,
+0x42, 0xfb, 0xcf, 0x91, 0xde, 0xa6, 0x26, 0xf8, 0x99, 0xa5, 0x63, 0x70, 0xad, 0x9b, 0xae, 0xca,
+0x33, 0x40, 0x7d, 0x6d, 0x96, 0x6e, 0xa1, 0x0e, 0x44, 0xee, 0xe1, 0x13, 0x9d, 0x94, 0x42, 0x52,
+0x9a, 0xbd, 0x75, 0x85, 0x74, 0x2c, 0xa8, 0x0e, 0x1d, 0x93, 0xb6, 0x18, 0xb7, 0x8c, 0x2c, 0xa8,
+0xcf, 0xfb, 0x5c, 0x71, 0xb9, 0xda, 0xec, 0xfe, 0xe8, 0x7e, 0x8f, 0xe4, 0x2f, 0x1d, 0xb2, 0xa8,
+0x75, 0x87, 0xd8, 0xb7, 0xa1, 0xe5, 0x3b, 0xcf, 0x99, 0x4a, 0x46, 0xd0, 0x83, 0x19, 0x7d, 0xc0,
+0xa1, 0x12, 0x1c, 0x95, 0x6d, 0x4a, 0xf4, 0xd8, 0xc7, 0xa5, 0x4d, 0x33, 0x2e, 0x85, 0x39, 0x40,
+0x75, 0x7e, 0x14, 0x7c, 0x80, 0x12, 0x98, 0x50, 0xc7, 0x41, 0x67, 0xb8, 0xa0, 0x80, 0x61, 0x54,
+0xa6, 0x6c, 0x4e, 0x1f, 0xe0, 0x9d, 0x0e, 0x07, 0xe9, 0xc9, 0xba, 0x33, 0xe7, 0xfe, 0xc0, 0x55,
+0x28, 0x2c, 0x02, 0x80, 0xa7, 0x19, 0xf5, 0x9e, 0xdc, 0x55, 0x53, 0x03, 0x97, 0x7b, 0x07, 0x48,
+0xff, 0x99, 0xfb, 0x37, 0x8a, 0x24, 0xc4, 0x59, 0xcc, 0x50, 0x10, 0x63, 0x8e, 0xaa, 0xa9, 0x1a,
+0xb0, 0x84, 0x1a, 0x86, 0xf9, 0x5f, 0xbb, 0xb1, 0x50, 0x6e, 0xa4, 0xd1, 0x0a, 0xcc, 0xd5, 0x71,
+0x7e, 0x1f, 0xa7, 0x1b, 0x7c, 0xf5, 0x53, 0x6e, 0x22, 0x5f, 0xcb, 0x2b, 0xe6, 0xd4, 0x7c, 0x5d,
+0xae, 0xd6, 0xc2, 0xc6, 0x4c, 0xe5, 0x05, 0x01, 0xd9, 0xed, 0x57, 0xfc, 0xc1, 0x23, 0x79, 0xfc,
+0xfa, 0xc8, 0x24, 0x83, 0x95, 0xf3, 0xb5, 0x6a, 0x51, 0x01, 0xd0, 0x77, 0xd6, 0xe9, 0x12, 0xa1,
+0xf9, 0x1a, 0x83, 0xfb, 0x82, 0x1b, 0xb9, 0xb0, 0x97, 0xf4, 0x76, 0x06, 0x33, 0x43, 0x49, 0xa0,
+0xff, 0x0b, 0xb5, 0xfa, 0xb5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0x80, 0x30, 0x7e, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xcb, 0x0f, 0xc6, 0xdf, 0x42,
+0x43, 0xcc, 0x3d, 0xcb, 0xb5, 0x48, 0x23, 0xa1, 0x1a, 0x7a, 0xa6, 0x2a, 0xbb, 0x34, 0x68, 0x30,
+0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xcb, 0x0f, 0xc6, 0xdf,
+0x42, 0x43, 0xcc, 0x3d, 0xcb, 0xb5, 0x48, 0x23, 0xa1, 0x1a, 0x7a, 0xa6, 0x2a, 0xbb, 0x34, 0x68,
+0x30, 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x14, 0x30, 0x12, 0x81, 0x10, 0x69, 0x6e, 0x66,
+0x6f, 0x40, 0x65, 0x2d, 0x73, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x2e, 0x68, 0x75, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+0x00, 0xc9, 0xd1, 0x0e, 0x5e, 0x2e, 0xd5, 0xcc, 0xb3, 0x7c, 0x3e, 0xcb, 0xfc, 0x3d, 0xff, 0x0d,
+0x28, 0x95, 0x93, 0x04, 0xc8, 0xbf, 0xda, 0xcd, 0x79, 0xb8, 0x43, 0x90, 0xf0, 0xa4, 0xbe, 0xef,
+0xf2, 0xef, 0x21, 0x98, 0xbc, 0xd4, 0xd4, 0x5d, 0x06, 0xf6, 0xee, 0x42, 0xec, 0x30, 0x6c, 0xa0,
+0xaa, 0xa9, 0xca, 0xf1, 0xaf, 0x8a, 0xfa, 0x3f, 0x0b, 0x73, 0x6a, 0x3e, 0xea, 0x2e, 0x40, 0x7e,
+0x1f, 0xae, 0x54, 0x61, 0x79, 0xeb, 0x2e, 0x08, 0x37, 0xd7, 0x23, 0xf3, 0x8c, 0x9f, 0xbe, 0x1d,
+0xb1, 0xe1, 0xa4, 0x75, 0xdb, 0xa0, 0xe2, 0x54, 0x14, 0xb1, 0xba, 0x1c, 0x29, 0xa4, 0x18, 0xf6,
+0x12, 0xba, 0xa2, 0x14, 0x14, 0xe3, 0x31, 0x35, 0xc8, 0x40, 0xff, 0xb7, 0xe0, 0x05, 0x76, 0x57,
+0xc1, 0x1c, 0x59, 0xf2, 0xf8, 0xbf, 0xe4, 0xed, 0x25, 0x62, 0x5c, 0x84, 0xf0, 0x7e, 0x7e, 0x1f,
+0xb3, 0xbe, 0xf9, 0xb7, 0x21, 0x11, 0xcc, 0x03, 0x01, 0x56, 0x70, 0xa7, 0x10, 0x92, 0x1e, 0x1b,
+0x34, 0x81, 0x1e, 0xad, 0x9c, 0x1a, 0xc3, 0x04, 0x3c, 0xed, 0x02, 0x61, 0xd6, 0x1e, 0x06, 0xf3,
+0x5f, 0x3a, 0x87, 0xf2, 0x2b, 0xf1, 0x45, 0x87, 0xe5, 0x3d, 0xac, 0xd1, 0xc7, 0x57, 0x84, 0xbd,
+0x6b, 0xae, 0xdc, 0xd8, 0xf9, 0xb6, 0x1b, 0x62, 0x70, 0x0b, 0x3d, 0x36, 0xc9, 0x42, 0xf2, 0x32,
+0xd7, 0x7a, 0x61, 0xe6, 0xd2, 0xdb, 0x3d, 0xcf, 0xc8, 0xa9, 0xc9, 0x9b, 0xdc, 0xdb, 0x58, 0x44,
+0xd7, 0x6f, 0x38, 0xaf, 0x7f, 0x78, 0xd3, 0xa3, 0xad, 0x1a, 0x75, 0xba, 0x1c, 0xc1, 0x36, 0x7c,
+0x8f, 0x1e, 0x6d, 0x1c, 0xc3, 0x75, 0x46, 0xae, 0x35, 0x05, 0xa6, 0xf6, 0x5c, 0x3d, 0x21, 0xee,
+0x56, 0xf0, 0xc9, 0x82, 0x22, 0x2d, 0x7a, 0x54, 0xab, 0x70, 0xc3, 0x7d, 0x22, 0x65, 0x82, 0x70,
+0x96, 0x30, 0x82, 0x03, 0xbc, 0x30, 0x82, 0x02, 0xa4, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10,
+0x07, 0x56, 0x22, 0xa4, 0xe8, 0xd4, 0x8a, 0x89, 0x4d, 0xf4, 0x13, 0xc8, 0xf0, 0xf8, 0xea, 0xa5,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
+0x4a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x20,
+0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x17, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x53, 0x65, 0x63, 0x75, 0x72,
+0x65, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30,
+0x36, 0x31, 0x31, 0x30, 0x37, 0x31, 0x39, 0x34, 0x32, 0x32, 0x38, 0x5a, 0x17, 0x0d, 0x32, 0x39,
+0x31, 0x32, 0x33, 0x31, 0x31, 0x39, 0x35, 0x32, 0x30, 0x36, 0x5a, 0x30, 0x4a, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x17, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74,
+0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x19, 0x30, 0x17,
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x47, 0x6c,
+0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
+0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, 0x35, 0x2e, 0xd8, 0xac, 0x6c, 0x55, 0x69,
+0x06, 0x71, 0xe5, 0x13, 0x68, 0x24, 0xb3, 0x4f, 0xd8, 0xcc, 0x21, 0x47, 0xf8, 0xf1, 0x60, 0x38,
+0x89, 0x89, 0x03, 0xe9, 0xbd, 0xea, 0x5e, 0x46, 0x53, 0x09, 0xdc, 0x5c, 0xf5, 0x5a, 0xe8, 0xf7,
+0x45, 0x2a, 0x02, 0xeb, 0x31, 0x61, 0xd7, 0x29, 0x33, 0x4c, 0xce, 0xc7, 0x7c, 0x0a, 0x37, 0x7e,
+0x0f, 0xba, 0x32, 0x98, 0xe1, 0x1d, 0x97, 0xaf, 0x8f, 0xc7, 0xdc, 0xc9, 0x38, 0x96, 0xf3, 0xdb,
+0x1a, 0xfc, 0x51, 0xed, 0x68, 0xc6, 0xd0, 0x6e, 0xa4, 0x7c, 0x24, 0xd1, 0xae, 0x42, 0xc8, 0x96,
+0x50, 0x63, 0x2e, 0xe0, 0xfe, 0x75, 0xfe, 0x98, 0xa7, 0x5f, 0x49, 0x2e, 0x95, 0xe3, 0x39, 0x33,
+0x64, 0x8e, 0x1e, 0xa4, 0x5f, 0x90, 0xd2, 0x67, 0x3c, 0xb2, 0xd9, 0xfe, 0x41, 0xb9, 0x55, 0xa7,
+0x09, 0x8e, 0x72, 0x05, 0x1e, 0x8b, 0xdd, 0x44, 0x85, 0x82, 0x42, 0xd0, 0x49, 0xc0, 0x1d, 0x60,
+0xf0, 0xd1, 0x17, 0x2c, 0x95, 0xeb, 0xf6, 0xa5, 0xc1, 0x92, 0xa3, 0xc5, 0xc2, 0xa7, 0x08, 0x60,
+0x0d, 0x60, 0x04, 0x10, 0x96, 0x79, 0x9e, 0x16, 0x34, 0xe6, 0xa9, 0xb6, 0xfa, 0x25, 0x45, 0x39,
+0xc8, 0x1e, 0x65, 0xf9, 0x93, 0xf5, 0xaa, 0xf1, 0x52, 0xdc, 0x99, 0x98, 0x3d, 0xa5, 0x86, 0x1a,
+0x0c, 0x35, 0x33, 0xfa, 0x4b, 0xa5, 0x04, 0x06, 0x15, 0x1c, 0x31, 0x80, 0xef, 0xaa, 0x18, 0x6b,
+0xc2, 0x7b, 0xd7, 0xda, 0xce, 0xf9, 0x33, 0x20, 0xd5, 0xf5, 0xbd, 0x6a, 0x33, 0x2d, 0x81, 0x04,
+0xfb, 0xb0, 0x5c, 0xd4, 0x9c, 0xa3, 0xe2, 0x5c, 0x1d, 0xe3, 0xa9, 0x42, 0x75, 0x5e, 0x7b, 0xd4,
+0x77, 0xef, 0x39, 0x54, 0xba, 0xc9, 0x0a, 0x18, 0x1b, 0x12, 0x99, 0x49, 0x2f, 0x88, 0x4b, 0xfd,
+0x50, 0x62, 0xd1, 0x73, 0xe7, 0x8f, 0x7a, 0x43, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0x9d,
+0x30, 0x81, 0x9a, 0x30, 0x13, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02,
+0x04, 0x06, 0x1e, 0x04, 0x00, 0x43, 0x00, 0x41, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+0x14, 0xaf, 0x44, 0x04, 0xc2, 0x41, 0x7e, 0x48, 0x83, 0xdb, 0x4e, 0x39, 0x02, 0xec, 0xec, 0x84,
+0x7a, 0xe6, 0xce, 0xc9, 0xa4, 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2d, 0x30, 0x2b,
+0x30, 0x29, 0xa0, 0x27, 0xa0, 0x25, 0x86, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63,
+0x72, 0x6c, 0x2e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
+0x6f, 0x6d, 0x2f, 0x53, 0x47, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x10, 0x06, 0x09, 0x2b,
+0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+0x00, 0x63, 0x1a, 0x08, 0x40, 0x7d, 0xa4, 0x5e, 0x53, 0x0d, 0x77, 0xd8, 0x7a, 0xae, 0x1f, 0x0d,
+0x0b, 0x51, 0x16, 0x03, 0xef, 0x18, 0x7c, 0xc8, 0xe3, 0xaf, 0x6a, 0x58, 0x93, 0x14, 0x60, 0x91,
+0xb2, 0x84, 0xdc, 0x88, 0x4e, 0xbe, 0x39, 0x8a, 0x3a, 0xf3, 0xe6, 0x82, 0x89, 0x5d, 0x01, 0x37,
+0xb3, 0xab, 0x24, 0xa4, 0x15, 0x0e, 0x92, 0x35, 0x5a, 0x4a, 0x44, 0x5e, 0x4e, 0x57, 0xfa, 0x75,
+0xce, 0x1f, 0x48, 0xce, 0x66, 0xf4, 0x3c, 0x40, 0x26, 0x92, 0x98, 0x6c, 0x1b, 0xee, 0x24, 0x46,
+0x0c, 0x17, 0xb3, 0x52, 0xa5, 0xdb, 0xa5, 0x91, 0x91, 0xcf, 0x37, 0xd3, 0x6f, 0xe7, 0x27, 0x08,
+0x3a, 0x4e, 0x19, 0x1f, 0x3a, 0xa7, 0x58, 0x5c, 0x17, 0xcf, 0x79, 0x3f, 0x8b, 0xe4, 0xa7, 0xd3,
+0x26, 0x23, 0x9d, 0x26, 0x0f, 0x58, 0x69, 0xfc, 0x47, 0x7e, 0xb2, 0xd0, 0x8d, 0x8b, 0x93, 0xbf,
+0x29, 0x4f, 0x43, 0x69, 0x74, 0x76, 0x67, 0x4b, 0xcf, 0x07, 0x8c, 0xe6, 0x02, 0xf7, 0xb5, 0xe1,
+0xb4, 0x43, 0xb5, 0x4b, 0x2d, 0x14, 0x9f, 0xf9, 0xdc, 0x26, 0x0d, 0xbf, 0xa6, 0x47, 0x74, 0x06,
+0xd8, 0x88, 0xd1, 0x3a, 0x29, 0x30, 0x84, 0xce, 0xd2, 0x39, 0x80, 0x62, 0x1b, 0xa8, 0xc7, 0x57,
+0x49, 0xbc, 0x6a, 0x55, 0x51, 0x67, 0x15, 0x4a, 0xbe, 0x35, 0x07, 0xe4, 0xd5, 0x75, 0x98, 0x37,
+0x79, 0x30, 0x14, 0xdb, 0x29, 0x9d, 0x6c, 0xc5, 0x69, 0xcc, 0x47, 0x55, 0xa2, 0x30, 0xf7, 0xcc,
+0x5c, 0x7f, 0xc2, 0xc3, 0x98, 0x1c, 0x6b, 0x4e, 0x16, 0x80, 0xeb, 0x7a, 0x78, 0x65, 0x45, 0xa2,
+0x00, 0x1a, 0xaf, 0x0c, 0x0d, 0x55, 0x64, 0x34, 0x48, 0xb8, 0x92, 0xb9, 0xf1, 0xb4, 0x50, 0x29,
+0xf2, 0x4f, 0x23, 0x1f, 0xda, 0x6c, 0xac, 0x1f, 0x44, 0xe1, 0xdd, 0x23, 0x78, 0x51, 0x5b, 0xc7,
+0x16, 0x30, 0x82, 0x03, 0xb8, 0x30, 0x82, 0x02, 0xa0, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10,
+0x0c, 0xf0, 0x8e, 0x5c, 0x08, 0x16, 0xa5, 0xad, 0x42, 0x7f, 0xf0, 0xeb, 0x27, 0x18, 0x59, 0xd0,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
+0x48, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x20,
+0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x17, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e, 0x53, 0x65, 0x63, 0x75, 0x72,
+0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31,
+0x31, 0x30, 0x37, 0x31, 0x39, 0x33, 0x31, 0x31, 0x38, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x31, 0x32,
+0x33, 0x31, 0x31, 0x39, 0x34, 0x30, 0x35, 0x35, 0x5a, 0x30, 0x48, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x17, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43,
+0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x13, 0x0e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74,
+0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
+0x82, 0x01, 0x01, 0x00, 0xab, 0xa4, 0x81, 0xe5, 0x95, 0xcd, 0xf5, 0xf6, 0x14, 0x8e, 0xc2, 0x4f,
+0xca, 0xd4, 0xe2, 0x78, 0x95, 0x58, 0x9c, 0x41, 0xe1, 0x0d, 0x99, 0x40, 0x24, 0x17, 0x39, 0x91,
+0x33, 0x66, 0xe9, 0xbe, 0xe1, 0x83, 0xaf, 0x62, 0x5c, 0x89, 0xd1, 0xfc, 0x24, 0x5b, 0x61, 0xb3,
+0xe0, 0x11, 0x11, 0x41, 0x1c, 0x1d, 0x6e, 0xf0, 0xb8, 0xbb, 0xf8, 0xde, 0xa7, 0x81, 0xba, 0xa6,
+0x48, 0xc6, 0x9f, 0x1d, 0xbd, 0xbe, 0x8e, 0xa9, 0x41, 0x3e, 0xb8, 0x94, 0xed, 0x29, 0x1a, 0xd4,
+0x8e, 0xd2, 0x03, 0x1d, 0x03, 0xef, 0x6d, 0x0d, 0x67, 0x1c, 0x57, 0xd7, 0x06, 0xad, 0xca, 0xc8,
+0xf5, 0xfe, 0x0e, 0xaf, 0x66, 0x25, 0x48, 0x04, 0x96, 0x0b, 0x5d, 0xa3, 0xba, 0x16, 0xc3, 0x08,
+0x4f, 0xd1, 0x46, 0xf8, 0x14, 0x5c, 0xf2, 0xc8, 0x5e, 0x01, 0x99, 0x6d, 0xfd, 0x88, 0xcc, 0x86,
+0xa8, 0xc1, 0x6f, 0x31, 0x42, 0x6c, 0x52, 0x3e, 0x68, 0xcb, 0xf3, 0x19, 0x34, 0xdf, 0xbb, 0x87,
+0x18, 0x56, 0x80, 0x26, 0xc4, 0xd0, 0xdc, 0xc0, 0x6f, 0xdf, 0xde, 0xa0, 0xc2, 0x91, 0x16, 0xa0,
+0x64, 0x11, 0x4b, 0x44, 0xbc, 0x1e, 0xf6, 0xe7, 0xfa, 0x63, 0xde, 0x66, 0xac, 0x76, 0xa4, 0x71,
+0xa3, 0xec, 0x36, 0x94, 0x68, 0x7a, 0x77, 0xa4, 0xb1, 0xe7, 0x0e, 0x2f, 0x81, 0x7a, 0xe2, 0xb5,
+0x72, 0x86, 0xef, 0xa2, 0x6b, 0x8b, 0xf0, 0x0f, 0xdb, 0xd3, 0x59, 0x3f, 0xba, 0x72, 0xbc, 0x44,
+0x24, 0x9c, 0xe3, 0x73, 0xb3, 0xf7, 0xaf, 0x57, 0x2f, 0x42, 0x26, 0x9d, 0xa9, 0x74, 0xba, 0x00,
+0x52, 0xf2, 0x4b, 0xcd, 0x53, 0x7c, 0x47, 0x0b, 0x36, 0x85, 0x0e, 0x66, 0xa9, 0x08, 0x97, 0x16,
+0x34, 0x57, 0xc1, 0x66, 0xf7, 0x80, 0xe3, 0xed, 0x70, 0x54, 0xc7, 0x93, 0xe0, 0x2e, 0x28, 0x15,
+0x59, 0x87, 0xba, 0xbb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0x9d, 0x30, 0x81, 0x9a, 0x30,
+0x13, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x04, 0x06, 0x1e, 0x04,
+0x00, 0x43, 0x00, 0x41, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01,
+0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x42, 0x32, 0xb6,
+0x16, 0xfa, 0x04, 0xfd, 0xfe, 0x5d, 0x4b, 0x7a, 0xc3, 0xfd, 0xf7, 0x4c, 0x40, 0x1d, 0x5a, 0x43,
+0xaf, 0x30, 0x34, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2d, 0x30, 0x2b, 0x30, 0x29, 0xa0, 0x27,
+0xa0, 0x25, 0x86, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x73,
+0x65, 0x63, 0x75, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53,
+0x54, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x10, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01,
+0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x30, 0xed, 0x4f,
+0x4a, 0xe1, 0x58, 0x3a, 0x52, 0x72, 0x5b, 0xb5, 0xa6, 0xa3, 0x65, 0x18, 0xa6, 0xbb, 0x51, 0x3b,
+0x77, 0xe9, 0x9d, 0xea, 0xd3, 0x9f, 0x5c, 0xe0, 0x45, 0x65, 0x7b, 0x0d, 0xca, 0x5b, 0xe2, 0x70,
+0x50, 0xb2, 0x94, 0x05, 0x14, 0xae, 0x49, 0xc7, 0x8d, 0x41, 0x07, 0x12, 0x73, 0x94, 0x7e, 0x0c,
+0x23, 0x21, 0xfd, 0xbc, 0x10, 0x7f, 0x60, 0x10, 0x5a, 0x72, 0xf5, 0x98, 0x0e, 0xac, 0xec, 0xb9,
+0x7f, 0xdd, 0x7a, 0x6f, 0x5d, 0xd3, 0x1c, 0xf4, 0xff, 0x88, 0x05, 0x69, 0x42, 0xa9, 0x05, 0x71,
+0xc8, 0xb7, 0xac, 0x26, 0xe8, 0x2e, 0xb4, 0x8c, 0x6a, 0xff, 0x71, 0xdc, 0xb8, 0xb1, 0xdf, 0x99,
+0xbc, 0x7c, 0x21, 0x54, 0x2b, 0xe4, 0x58, 0xa2, 0xbb, 0x57, 0x29, 0xae, 0x9e, 0xa9, 0xa3, 0x19,
+0x26, 0x0f, 0x99, 0x2e, 0x08, 0xb0, 0xef, 0xfd, 0x69, 0xcf, 0x99, 0x1a, 0x09, 0x8d, 0xe3, 0xa7,
+0x9f, 0x2b, 0xc9, 0x36, 0x34, 0x7b, 0x24, 0xb3, 0x78, 0x4c, 0x95, 0x17, 0xa4, 0x06, 0x26, 0x1e,
+0xb6, 0x64, 0x52, 0x36, 0x5f, 0x60, 0x67, 0xd9, 0x9c, 0xc5, 0x05, 0x74, 0x0b, 0xe7, 0x67, 0x23,
+0xd2, 0x08, 0xfc, 0x88, 0xe9, 0xae, 0x8b, 0x7f, 0xe1, 0x30, 0xf4, 0x37, 0x7e, 0xfd, 0xc6, 0x32,
+0xda, 0x2d, 0x9e, 0x44, 0x30, 0x30, 0x6c, 0xee, 0x07, 0xde, 0xd2, 0x34, 0xfc, 0xd2, 0xff, 0x40,
+0xf6, 0x4b, 0xf4, 0x66, 0x46, 0x06, 0x54, 0xa6, 0xf2, 0x32, 0x0a, 0x63, 0x26, 0x30, 0x6b, 0x9b,
+0xd1, 0xdc, 0x8b, 0x47, 0xba, 0xe1, 0xb9, 0xd5, 0x62, 0xd0, 0xa2, 0xa0, 0xf4, 0x67, 0x05, 0x78,
+0x29, 0x63, 0x1a, 0x6f, 0x04, 0xd6, 0xf8, 0xc6, 0x4c, 0xa3, 0x9a, 0xb1, 0x37, 0xb4, 0x8d, 0xe5,
+0x28, 0x4b, 0x1d, 0x9e, 0x2c, 0xc2, 0xb8, 0x68, 0xbc, 0xed, 0x02, 0xee, 0x31, 0x30, 0x82, 0x05,
+0xba, 0x30, 0x82, 0x03, 0xa2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xbb, 0x40, 0x1c,
+0x43, 0xf5, 0x5e, 0x4f, 0xb0, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x43, 0x48, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x53, 0x77,
+0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x41, 0x47, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x13, 0x16, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x47,
+0x6f, 0x6c, 0x64, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x30,
+0x36, 0x31, 0x30, 0x32, 0x35, 0x30, 0x38, 0x33, 0x30, 0x33, 0x35, 0x5a, 0x17, 0x0d, 0x33, 0x36,
+0x31, 0x30, 0x32, 0x35, 0x30, 0x38, 0x33, 0x30, 0x33, 0x35, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x0c, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x41,
+0x47, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x53, 0x77, 0x69, 0x73,
+0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x47, 0x6f, 0x6c, 0x64, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20,
+0x47, 0x32, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82,
+0x02, 0x01, 0x00, 0xaf, 0xe4, 0xee, 0x7e, 0x8b, 0x24, 0x0e, 0x12, 0x6e, 0xa9, 0x50, 0x2d, 0x16,
+0x44, 0x3b, 0x92, 0x92, 0x5c, 0xca, 0xb8, 0x5d, 0x84, 0x92, 0x42, 0x13, 0x2a, 0xbc, 0x65, 0x57,
+0x82, 0x40, 0x3e, 0x57, 0x24, 0xcd, 0x50, 0x8b, 0x25, 0x2a, 0xb7, 0x6f, 0xfc, 0xef, 0xa2, 0xd0,
+0xc0, 0x1f, 0x02, 0x24, 0x4a, 0x13, 0x96, 0x8f, 0x23, 0x13, 0xe6, 0x28, 0x58, 0x00, 0xa3, 0x47,
+0xc7, 0x06, 0xa7, 0x84, 0x23, 0x2b, 0xbb, 0xbd, 0x96, 0x2b, 0x7f, 0x55, 0xcc, 0x8b, 0xc1, 0x57,
+0x1f, 0x0e, 0x62, 0x65, 0x0f, 0xdd, 0x3d, 0x56, 0x8a, 0x73, 0xda, 0xae, 0x7e, 0x6d, 0xba, 0x81,
+0x1c, 0x7e, 0x42, 0x8c, 0x20, 0x35, 0xd9, 0x43, 0x4d, 0x84, 0xfa, 0x84, 0xdb, 0x52, 0x2c, 0xf3,
+0x0e, 0x27, 0x77, 0x0b, 0x6b, 0xbf, 0x11, 0x2f, 0x72, 0x78, 0x9f, 0x2e, 0xd8, 0x3e, 0xe6, 0x18,
+0x37, 0x5a, 0x2a, 0x72, 0xf9, 0xda, 0x62, 0x90, 0x92, 0x95, 0xca, 0x1f, 0x9c, 0xe9, 0xb3, 0x3c,
+0x2b, 0xcb, 0xf3, 0x01, 0x13, 0xbf, 0x5a, 0xcf, 0xc1, 0xb5, 0x0a, 0x60, 0xbd, 0xdd, 0xb5, 0x99,
+0x64, 0x53, 0xb8, 0xa0, 0x96, 0xb3, 0x6f, 0xe2, 0x26, 0x77, 0x91, 0x8c, 0xe0, 0x62, 0x10, 0x02,
+0x9f, 0x34, 0x0f, 0xa4, 0xd5, 0x92, 0x33, 0x51, 0xde, 0xbe, 0x8d, 0xba, 0x84, 0x7a, 0x60, 0x3c,
+0x6a, 0xdb, 0x9f, 0x2b, 0xec, 0xde, 0xde, 0x01, 0x3f, 0x6e, 0x4d, 0xe5, 0x50, 0x86, 0xcb, 0xb4,
+0xaf, 0xed, 0x44, 0x40, 0xc5, 0xca, 0x5a, 0x8c, 0xda, 0xd2, 0x2b, 0x7c, 0xa8, 0xee, 0xbe, 0xa6,
+0xe5, 0x0a, 0xaa, 0x0e, 0xa5, 0xdf, 0x05, 0x52, 0xb7, 0x55, 0xc7, 0x22, 0x5d, 0x32, 0x6a, 0x97,
+0x97, 0x63, 0x13, 0xdb, 0xc9, 0xdb, 0x79, 0x36, 0x7b, 0x85, 0x3a, 0x4a, 0xc5, 0x52, 0x89, 0xf9,
+0x24, 0xe7, 0x9d, 0x77, 0xa9, 0x82, 0xff, 0x55, 0x1c, 0xa5, 0x71, 0x69, 0x2b, 0xd1, 0x02, 0x24,
+0xf2, 0xb3, 0x26, 0xd4, 0x6b, 0xda, 0x04, 0x55, 0xe5, 0xc1, 0x0a, 0xc7, 0x6d, 0x30, 0x37, 0x90,
+0x2a, 0xe4, 0x9e, 0x14, 0x33, 0x5e, 0x16, 0x17, 0x55, 0xc5, 0x5b, 0xb5, 0xcb, 0x34, 0x89, 0x92,
+0xf1, 0x9d, 0x26, 0x8f, 0xa1, 0x07, 0xd4, 0xc6, 0xb2, 0x78, 0x50, 0xdb, 0x0c, 0x0c, 0x0b, 0x7c,
+0x0b, 0x8c, 0x41, 0xd7, 0xb9, 0xe9, 0xdd, 0x8c, 0x88, 0xf7, 0xa3, 0x4d, 0xb2, 0x32, 0xcc, 0xd8,
+0x17, 0xda, 0xcd, 0xb7, 0xce, 0x66, 0x9d, 0xd4, 0xfd, 0x5e, 0xff, 0xbd, 0x97, 0x3e, 0x29, 0x75,
+0xe7, 0x7e, 0xa7, 0x62, 0x58, 0xaf, 0x25, 0x34, 0xa5, 0x41, 0xc7, 0x3d, 0xbc, 0x0d, 0x50, 0xca,
+0x03, 0x03, 0x0f, 0x08, 0x5a, 0x1f, 0x95, 0x73, 0x78, 0x62, 0xbf, 0xaf, 0x72, 0x14, 0x69, 0x0e,
+0xa5, 0xe5, 0x03, 0x0e, 0x78, 0x8e, 0x26, 0x28, 0x42, 0xf0, 0x07, 0x0b, 0x62, 0x20, 0x10, 0x67,
+0x39, 0x46, 0xfa, 0xa9, 0x03, 0xcc, 0x04, 0x38, 0x7a, 0x66, 0xef, 0x20, 0x83, 0xb5, 0x8c, 0x4a,
+0x56, 0x8e, 0x91, 0x00, 0xfc, 0x8e, 0x5c, 0x82, 0xde, 0x88, 0xa0, 0xc3, 0xe2, 0x68, 0x6e, 0x7d,
+0x8d, 0xef, 0x3c, 0xdd, 0x65, 0xf4, 0x5d, 0xac, 0x51, 0xef, 0x24, 0x80, 0xae, 0xaa, 0x56, 0x97,
+0x6f, 0xf9, 0xad, 0x7d, 0xda, 0x61, 0x3f, 0x98, 0x77, 0x3c, 0xa5, 0x91, 0xb6, 0x1c, 0x8c, 0x26,
+0xda, 0x65, 0xa2, 0x09, 0x6d, 0xc1, 0xe2, 0x54, 0xe3, 0xb9, 0xca, 0x4c, 0x4c, 0x80, 0x8f, 0x77,
+0x7b, 0x60, 0x9a, 0x1e, 0xdf, 0xb6, 0xf2, 0x48, 0x1e, 0x0e, 0xba, 0x4e, 0x54, 0x6d, 0x98, 0xe0,
+0xe1, 0xa2, 0x1a, 0xa2, 0x77, 0x50, 0xcf, 0xc4, 0x63, 0x92, 0xec, 0x47, 0x19, 0x9d, 0xeb, 0xe6,
+0x6b, 0xce, 0xc1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xac, 0x30, 0x81, 0xa9, 0x30, 0x0e,
+0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f,
+0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x5b, 0x25, 0x7b, 0x96, 0xa4, 0x65,
+0x51, 0x7e, 0xb8, 0x39, 0xf3, 0xc0, 0x78, 0x66, 0x5e, 0xe8, 0x3a, 0xe7, 0xf0, 0xee, 0x30, 0x1f,
+0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x5b, 0x25, 0x7b, 0x96, 0xa4,
+0x65, 0x51, 0x7e, 0xb8, 0x39, 0xf3, 0xc0, 0x78, 0x66, 0x5e, 0xe8, 0x3a, 0xe7, 0xf0, 0xee, 0x30,
+0x46, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x09, 0x60, 0x85,
+0x74, 0x01, 0x59, 0x01, 0x02, 0x01, 0x01, 0x30, 0x2e, 0x30, 0x2c, 0x06, 0x08, 0x2b, 0x06, 0x01,
+0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x72, 0x65,
+0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x73, 0x77, 0x69, 0x73, 0x73, 0x73, 0x69,
+0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x27, 0xba, 0xe3, 0x94, 0x7c,
+0xf1, 0xae, 0xc0, 0xde, 0x17, 0xe6, 0xe5, 0xd8, 0xd5, 0xf5, 0x54, 0xb0, 0x83, 0xf4, 0xbb, 0xcd,
+0x5e, 0x05, 0x7b, 0x4f, 0x9f, 0x75, 0x66, 0xaf, 0x3c, 0xe8, 0x56, 0x7e, 0xfc, 0x72, 0x78, 0x38,
+0x03, 0xd9, 0x2b, 0x62, 0x1b, 0x00, 0xb9, 0xf8, 0xe9, 0x60, 0xcd, 0xcc, 0xce, 0x51, 0x8a, 0xc7,
+0x50, 0x31, 0x6e, 0xe1, 0x4a, 0x7e, 0x18, 0x2f, 0x69, 0x59, 0xb6, 0x3d, 0x64, 0x81, 0x2b, 0xe3,
+0x83, 0x84, 0xe6, 0x22, 0x87, 0x8e, 0x7d, 0xe0, 0xee, 0x02, 0x99, 0x61, 0xb8, 0x1e, 0xf4, 0xb8,
+0x2b, 0x88, 0x12, 0x16, 0x84, 0xc2, 0x31, 0x93, 0x38, 0x96, 0x31, 0xa6, 0xb9, 0x3b, 0x53, 0x3f,
+0xc3, 0x24, 0x93, 0x56, 0x5b, 0x69, 0x92, 0xec, 0xc5, 0xc1, 0xbb, 0x38, 0x00, 0xe3, 0xec, 0x17,
+0xa9, 0xb8, 0xdc, 0xc7, 0x7c, 0x01, 0x83, 0x9f, 0x32, 0x47, 0xba, 0x52, 0x22, 0x34, 0x1d, 0x32,
+0x7a, 0x09, 0x56, 0xa7, 0x7c, 0x25, 0x36, 0xa9, 0x3d, 0x4b, 0xda, 0xc0, 0x82, 0x6f, 0x0a, 0xbb,
+0x12, 0xc8, 0x87, 0x4b, 0x27, 0x11, 0xf9, 0x1e, 0x2d, 0xc7, 0x93, 0x3f, 0x9e, 0xdb, 0x5f, 0x26,
+0x6b, 0x52, 0xd9, 0x2e, 0x8a, 0xf1, 0x14, 0xc6, 0x44, 0x8d, 0x15, 0xa9, 0xb7, 0xbf, 0xbd, 0xde,
+0xa6, 0x1a, 0xee, 0xae, 0x2d, 0xfb, 0x48, 0x77, 0x17, 0xfe, 0xbb, 0xec, 0xaf, 0x18, 0xf5, 0x2a,
+0x51, 0xf0, 0x39, 0x84, 0x97, 0x95, 0x6c, 0x6e, 0x1b, 0xc3, 0x2b, 0xc4, 0x74, 0x60, 0x79, 0x25,
+0xb0, 0x0a, 0x27, 0xdf, 0xdf, 0x5e, 0xd2, 0x39, 0xcf, 0x45, 0x7d, 0x42, 0x4b, 0xdf, 0xb3, 0x2c,
+0x1e, 0xc5, 0xc6, 0x5d, 0xca, 0x55, 0x3a, 0xa0, 0x9c, 0x69, 0x9a, 0x8f, 0xda, 0xef, 0xb2, 0xb0,
+0x3c, 0x9f, 0x87, 0x6c, 0x12, 0x2b, 0x65, 0x70, 0x15, 0x52, 0x31, 0x1a, 0x24, 0xcf, 0x6f, 0x31,
+0x23, 0x50, 0x1f, 0x8c, 0x4f, 0x8f, 0x23, 0xc3, 0x74, 0x41, 0x63, 0x1c, 0x55, 0xa8, 0x14, 0xdd,
+0x3e, 0xe0, 0x51, 0x50, 0xcf, 0xf1, 0x1b, 0x30, 0x56, 0x0e, 0x92, 0xb0, 0x82, 0x85, 0xd8, 0x83,
+0xcb, 0x22, 0x64, 0xbc, 0x2d, 0xb8, 0x25, 0xd5, 0x54, 0xa2, 0xb8, 0x06, 0xea, 0xad, 0x92, 0xa4,
+0x24, 0xa0, 0xc1, 0x86, 0xb5, 0x4a, 0x13, 0x6a, 0x47, 0xcf, 0x2e, 0x0b, 0x56, 0x95, 0x54, 0xcb,
+0xce, 0x9a, 0xdb, 0x6a, 0xb4, 0xa6, 0xb2, 0xdb, 0x41, 0x08, 0x86, 0x27, 0x77, 0xf7, 0x6a, 0xa0,
+0x42, 0x6c, 0x0b, 0x38, 0xce, 0xd7, 0x75, 0x50, 0x32, 0x92, 0xc2, 0xdf, 0x2b, 0x30, 0x22, 0x48,
+0xd0, 0xd5, 0x41, 0x38, 0x25, 0x5d, 0xa4, 0xe9, 0x5d, 0x9f, 0xc6, 0x94, 0x75, 0xd0, 0x45, 0xfd,
+0x30, 0x97, 0x43, 0x8f, 0x90, 0xab, 0x0a, 0xc7, 0x86, 0x73, 0x60, 0x4a, 0x69, 0x2d, 0xde, 0xa5,
+0x78, 0xd7, 0x06, 0xda, 0x6a, 0x9e, 0x4b, 0x3e, 0x77, 0x3a, 0x20, 0x13, 0x22, 0x01, 0xd0, 0xbf,
+0x68, 0x9e, 0x63, 0x60, 0x6b, 0x35, 0x4d, 0x0b, 0x6d, 0xba, 0xa1, 0x3d, 0xc0, 0x93, 0xe0, 0x7f,
+0x23, 0xb3, 0x55, 0xad, 0x72, 0x25, 0x4e, 0x46, 0xf9, 0xd2, 0x16, 0xef, 0xb0, 0x64, 0xc1, 0x01,
+0x9e, 0xe9, 0xca, 0xa0, 0x6a, 0x98, 0x0e, 0xcf, 0xd8, 0x60, 0xf2, 0x2f, 0x49, 0xb8, 0xe4, 0x42,
+0xe1, 0x38, 0x35, 0x16, 0xf4, 0xc8, 0x6e, 0x4f, 0xf7, 0x81, 0x56, 0xe8, 0xba, 0xa3, 0xbe, 0x23,
+0xaf, 0xae, 0xfd, 0x6f, 0x03, 0xe0, 0x02, 0x3b, 0x30, 0x76, 0xfa, 0x1b, 0x6d, 0x41, 0xcf, 0x01,
+0xb1, 0xe9, 0xb8, 0xc9, 0x66, 0xf4, 0xdb, 0x26, 0xf3, 0x3a, 0xa4, 0x74, 0xf2, 0x49, 0x24, 0x5b,
+0xc9, 0xb0, 0xd0, 0x57, 0xc1, 0xfa, 0x3e, 0x7a, 0xe1, 0x97, 0xc9, 0x30, 0x82, 0x02, 0x40, 0x30,
+0x82, 0x01, 0xe5, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0c, 0x01, 0x54, 0x48, 0xef, 0x21, 0xfd,
+0x97, 0x59, 0x0d, 0xf5, 0x04, 0x0a, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
+0x03, 0x02, 0x30, 0x71, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x48,
+0x55, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x75, 0x64, 0x61,
+0x70, 0x65, 0x73, 0x74, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0d, 0x4d,
+0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x17, 0x30, 0x15,
+0x06, 0x03, 0x55, 0x04, 0x61, 0x0c, 0x0e, 0x56, 0x41, 0x54, 0x48, 0x55, 0x2d, 0x32, 0x33, 0x35,
+0x38, 0x34, 0x34, 0x39, 0x37, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15,
+0x65, 0x2d, 0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+0x20, 0x32, 0x30, 0x31, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x38, 0x32, 0x32, 0x31,
+0x32, 0x30, 0x37, 0x30, 0x36, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x38, 0x32, 0x32, 0x31, 0x32,
+0x30, 0x37, 0x30, 0x36, 0x5a, 0x30, 0x71, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x48, 0x55, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x42,
+0x75, 0x64, 0x61, 0x70, 0x65, 0x73, 0x74, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x0c, 0x0d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x65, 0x63, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31,
+0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x61, 0x0c, 0x0e, 0x56, 0x41, 0x54, 0x48, 0x55, 0x2d,
+0x32, 0x33, 0x35, 0x38, 0x34, 0x34, 0x39, 0x37, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x0c, 0x15, 0x65, 0x2d, 0x53, 0x7a, 0x69, 0x67, 0x6e, 0x6f, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x20, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x37, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+0x42, 0x00, 0x04, 0x96, 0xdc, 0x3d, 0x8a, 0xd8, 0xb0, 0x7b, 0x6f, 0xc6, 0x27, 0xbe, 0x44, 0x90,
+0xb1, 0xb3, 0x56, 0x15, 0x7b, 0x8e, 0x43, 0x24, 0x7d, 0x1a, 0x84, 0x59, 0xee, 0x63, 0x68, 0xb2,
+0xc6, 0x5e, 0x87, 0xd0, 0x15, 0x48, 0x1e, 0xa8, 0x90, 0xad, 0xbd, 0x53, 0xa2, 0xda, 0xde, 0x3a,
+0x90, 0xa6, 0x60, 0x5f, 0x68, 0x32, 0xb5, 0x86, 0x41, 0xdf, 0x87, 0x5b, 0x2c, 0x7b, 0xc5, 0xfe,
+0x7c, 0x7a, 0xda, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+0x16, 0x04, 0x14, 0x87, 0x11, 0x15, 0x08, 0xd1, 0xaa, 0xc1, 0x78, 0x0c, 0xb1, 0xaf, 0xce, 0xc6,
+0xc9, 0x90, 0xef, 0xbf, 0x30, 0x04, 0xc0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+0x30, 0x16, 0x80, 0x14, 0x87, 0x11, 0x15, 0x08, 0xd1, 0xaa, 0xc1, 0x78, 0x0c, 0xb1, 0xaf, 0xce,
+0xc6, 0xc9, 0x90, 0xef, 0xbf, 0x30, 0x04, 0xc0, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
+0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0xb5, 0x57, 0xdd, 0xd7,
+0x8a, 0x55, 0x0b, 0x36, 0xe1, 0x86, 0x44, 0xfa, 0xd4, 0xd9, 0x68, 0x8d, 0xb8, 0xdc, 0x23, 0x8a,
+0x8a, 0x0d, 0xd4, 0x2f, 0x7d, 0xea, 0x73, 0xec, 0xbf, 0x4d, 0x6c, 0xa8, 0x02, 0x21, 0x00, 0xcb,
+0xa5, 0xb4, 0x12, 0xfa, 0xe7, 0xb5, 0xe8, 0xcf, 0x7e, 0x93, 0xfc, 0xf3, 0x35, 0x8f, 0x6f, 0x4e,
+0x5a, 0x7c, 0xb4, 0xbc, 0x4e, 0xb2, 0xfc, 0x72, 0xaa, 0x5b, 0x59, 0xf9, 0xe7, 0xdc, 0x31, 0x30,
+0x82, 0x02, 0x60, 0x30, 0x82, 0x02, 0x07, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0c, 0x0d, 0x6a,
+0x5f, 0x08, 0x3f, 0x28, 0x5c, 0x3e, 0x51, 0x95, 0xdf, 0x5d, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
+0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, 0x91, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+0x08, 0x49, 0x6c, 0x6c, 0x69, 0x6e, 0x6f, 0x69, 0x73, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
+0x04, 0x07, 0x13, 0x07, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x31, 0x21, 0x30, 0x1f, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x54, 0x72, 0x75, 0x73, 0x74, 0x77, 0x61, 0x76, 0x65, 0x20,
+0x48, 0x6f, 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x3a,
+0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x31, 0x54, 0x72, 0x75, 0x73, 0x74, 0x77, 0x61,
+0x76, 0x65, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x45, 0x43, 0x43, 0x20, 0x50, 0x32,
+0x35, 0x36, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37,
+0x30, 0x38, 0x32, 0x33, 0x31, 0x39, 0x33, 0x35, 0x31, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30,
+0x38, 0x32, 0x33, 0x31, 0x39, 0x33, 0x35, 0x31, 0x30, 0x5a, 0x30, 0x81, 0x91, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+0x55, 0x04, 0x08, 0x13, 0x08, 0x49, 0x6c, 0x6c, 0x69, 0x6e, 0x6f, 0x69, 0x73, 0x31, 0x10, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x31,
+0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x54, 0x72, 0x75, 0x73, 0x74, 0x77,
+0x61, 0x76, 0x65, 0x20, 0x48, 0x6f, 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x20, 0x49, 0x6e,
+0x63, 0x2e, 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x31, 0x54, 0x72, 0x75,
+0x73, 0x74, 0x77, 0x61, 0x76, 0x65, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x45, 0x43,
+0x43, 0x20, 0x50, 0x32, 0x35, 0x36, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x59,
+0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x7e, 0xfb, 0x6c, 0xe6, 0x23, 0xe3, 0x73,
+0x32, 0x08, 0xca, 0x60, 0xe6, 0x53, 0x9c, 0xba, 0x74, 0x8d, 0x18, 0xb0, 0x78, 0x90, 0x52, 0x80,
+0xdd, 0x38, 0xc0, 0x4a, 0x1d, 0xd1, 0xa8, 0xcc, 0x93, 0xa4, 0x97, 0x06, 0x38, 0xca, 0x0d, 0x15,
+0x62, 0xc6, 0x8e, 0x01, 0x2a, 0x65, 0x9d, 0xaa, 0xdf, 0x34, 0x91, 0x2e, 0x81, 0xc1, 0xe4, 0x33,
+0x92, 0x31, 0xc4, 0xfd, 0x09, 0x3a, 0xa6, 0x3f, 0xad, 0xa3, 0x43, 0x30, 0x41, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0f,
+0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x05, 0x03, 0x03, 0x07, 0x06, 0x00, 0x30,
+0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa3, 0x41, 0x06, 0xac, 0x90, 0x6d,
+0xd1, 0x4a, 0xeb, 0x75, 0xa5, 0x4a, 0x10, 0x99, 0xb3, 0xb1, 0xa1, 0x8b, 0x4a, 0xf7, 0x30, 0x0a,
+0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02,
+0x20, 0x07, 0xe6, 0x54, 0xda, 0x0e, 0xa0, 0x5a, 0xb2, 0xae, 0x11, 0x9f, 0x87, 0xc5, 0xb6, 0xff,
+0x69, 0xde, 0x25, 0xbe, 0xf8, 0xa0, 0xb7, 0x08, 0xf3, 0x44, 0xce, 0x2a, 0xdf, 0x08, 0x21, 0x0c,
+0x37, 0x02, 0x20, 0x2d, 0x26, 0x03, 0xa0, 0x05, 0xbd, 0x6b, 0xd1, 0xf6, 0x5c, 0xf8, 0x65, 0xcc,
+0x86, 0x6d, 0xb3, 0x9c, 0x34, 0x48, 0x63, 0x84, 0x09, 0xc5, 0x8d, 0x77, 0x1a, 0xe2, 0xcc, 0x9c,
+0xe1, 0x74, 0x7b, 0x30, 0x82, 0x05, 0xda, 0x30, 0x82, 0x03, 0xc2, 0xa0, 0x03, 0x02, 0x01, 0x02,
+0x02, 0x0c, 0x05, 0xf7, 0x0e, 0x86, 0xda, 0x49, 0xf3, 0x46, 0x35, 0x2e, 0xba, 0xb2, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x88,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x49, 0x6c, 0x6c, 0x69, 0x6e, 0x6f, 0x69, 0x73,
+0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x43, 0x68, 0x69, 0x63, 0x61,
+0x67, 0x6f, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x54, 0x72, 0x75,
+0x73, 0x74, 0x77, 0x61, 0x76, 0x65, 0x20, 0x48, 0x6f, 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x2c,
+0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x28,
+0x54, 0x72, 0x75, 0x73, 0x74, 0x77, 0x61, 0x76, 0x65, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
+0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x38,
+0x32, 0x33, 0x31, 0x39, 0x33, 0x34, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x30, 0x38, 0x32,
+0x33, 0x31, 0x39, 0x33, 0x34, 0x31, 0x32, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+0x08, 0x0c, 0x08, 0x49, 0x6c, 0x6c, 0x69, 0x6e, 0x6f, 0x69, 0x73, 0x31, 0x10, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x31, 0x21, 0x30,
+0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x54, 0x72, 0x75, 0x73, 0x74, 0x77, 0x61, 0x76,
+0x65, 0x20, 0x48, 0x6f, 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x28, 0x54, 0x72, 0x75, 0x73, 0x74,
+0x77, 0x61, 0x76, 0x65, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74,
+0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+0x69, 0x74, 0x79, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02,
+0x82, 0x02, 0x01, 0x00, 0xb9, 0x5d, 0x51, 0x28, 0x4b, 0x3c, 0x37, 0x92, 0xd1, 0x82, 0xce, 0xbd,
+0x1d, 0xbd, 0xcd, 0xdd, 0xb8, 0xab, 0xcf, 0x0a, 0x3e, 0xe1, 0x5d, 0xe5, 0xdc, 0xaa, 0x09, 0xb9,
+0x57, 0x02, 0x3e, 0xe6, 0x63, 0x61, 0xdf, 0xf2, 0x0f, 0x82, 0x63, 0xae, 0xa3, 0xf7, 0xac, 0x73,
+0xd1, 0x7c, 0xe7, 0xb3, 0x0b, 0xaf, 0x08, 0x00, 0x09, 0x59, 0x7f, 0xcd, 0x29, 0x2a, 0x88, 0x93,
+0x87, 0x17, 0x18, 0x80, 0xed, 0x88, 0xb2, 0xb4, 0xb6, 0x10, 0x1f, 0x2d, 0xd6, 0x5f, 0x55, 0xa2,
+0x13, 0x5d, 0xd1, 0xc6, 0xeb, 0x06, 0x56, 0x89, 0x88, 0xfe, 0xac, 0x32, 0x9d, 0xfd, 0x5c, 0xc3,
+0x05, 0xc7, 0x6e, 0xee, 0x86, 0x89, 0xba, 0x88, 0x03, 0x9d, 0x72, 0x21, 0x86, 0x90, 0xae, 0x8f,
+0x03, 0xa5, 0xdc, 0x9f, 0x88, 0x28, 0xcb, 0xa3, 0x92, 0x49, 0x0f, 0xec, 0xd0, 0x0f, 0xe2, 0x6d,
+0x44, 0x4f, 0x80, 0x6a, 0xb2, 0xd4, 0xe7, 0xa0, 0x0a, 0x53, 0x01, 0xba, 0x8e, 0x97, 0x91, 0x76,
+0x6e, 0xbc, 0xfc, 0xd5, 0x6b, 0x36, 0xe6, 0x40, 0x88, 0xd6, 0x7b, 0x2f, 0x5f, 0x05, 0xe8, 0x2c,
+0x6d, 0x11, 0xf3, 0xe7, 0xb2, 0xbe, 0x92, 0x44, 0x4c, 0xd2, 0x97, 0xa4, 0xfe, 0xd2, 0x72, 0x81,
+0x43, 0x07, 0x9c, 0xe9, 0x11, 0x3e, 0xf5, 0x8b, 0x1a, 0x59, 0x7d, 0x1f, 0x68, 0x58, 0xdd, 0x04,
+0x00, 0x2c, 0x96, 0xf3, 0x43, 0xb3, 0x7e, 0x98, 0x19, 0x74, 0xd9, 0x9c, 0x73, 0xd9, 0x18, 0xbe,
+0x41, 0xc7, 0x34, 0x79, 0xd9, 0xf4, 0x62, 0xc2, 0x43, 0xb9, 0xb3, 0x27, 0xb0, 0x22, 0xcb, 0xf9,
+0x3d, 0x52, 0xc7, 0x30, 0x47, 0xb3, 0xc9, 0x3e, 0xb8, 0x6a, 0xe2, 0xe7, 0xe8, 0x81, 0x70, 0x5e,
+0x42, 0x8b, 0x4f, 0x26, 0xa5, 0xfe, 0x3a, 0xc2, 0x20, 0x6e, 0xbb, 0xf8, 0x16, 0x8e, 0xcd, 0x0c,
+0xa9, 0xb4, 0x1b, 0x6c, 0x76, 0x10, 0xe1, 0x58, 0x79, 0x46, 0x3e, 0x54, 0xce, 0x80, 0xa8, 0x57,
+0x09, 0x37, 0x29, 0x1b, 0x99, 0x13, 0x8f, 0x0c, 0xc8, 0xd6, 0x2c, 0x1c, 0xfb, 0x05, 0xe8, 0x08,
+0x95, 0x3d, 0x65, 0x46, 0xdc, 0xee, 0xcd, 0x69, 0xe2, 0x4d, 0x8f, 0x87, 0x28, 0x4e, 0x34, 0x0b,
+0x3e, 0xcf, 0x14, 0xd9, 0xbb, 0xdd, 0xb6, 0x50, 0x9a, 0xad, 0x77, 0xd4, 0x19, 0xd6, 0xda, 0x1a,
+0x88, 0xc8, 0x4e, 0x1b, 0x27, 0x75, 0xd8, 0xb2, 0x08, 0xf1, 0xae, 0x83, 0x30, 0xb9, 0x11, 0x0e,
+0xcd, 0x87, 0xf0, 0x84, 0x8d, 0x15, 0x72, 0x7c, 0xa1, 0xef, 0xcc, 0xf2, 0x88, 0x61, 0xba, 0xf4,
+0x69, 0xbb, 0x0c, 0x8c, 0x0b, 0x75, 0x57, 0x04, 0xb8, 0x4e, 0x2a, 0x14, 0x2e, 0x3d, 0x0f, 0x1c,
+0x1e, 0x32, 0xa6, 0x62, 0x36, 0xee, 0x66, 0xe2, 0x22, 0xb8, 0x05, 0x40, 0x63, 0x10, 0x22, 0xf3,
+0x33, 0x1d, 0x74, 0x72, 0x8a, 0x2c, 0xf5, 0x39, 0x29, 0xa0, 0xd3, 0xe7, 0x1b, 0x80, 0x84, 0x2d,
+0xc5, 0x3d, 0xe3, 0x4d, 0xb1, 0xfd, 0x1a, 0x6f, 0xba, 0x65, 0x07, 0x3b, 0x58, 0xec, 0x42, 0x45,
+0x26, 0xfb, 0xd8, 0xda, 0x25, 0x72, 0xc4, 0xf6, 0x00, 0xb1, 0x22, 0x79, 0xbd, 0xe3, 0x7c, 0x59,
+0x62, 0x4a, 0x9c, 0x05, 0x6f, 0x3d, 0xce, 0xe6, 0xd6, 0x47, 0x63, 0x99, 0xc6, 0x24, 0x6f, 0x72,
+0x12, 0xc8, 0xac, 0x7f, 0x90, 0xb4, 0x0b, 0x91, 0x70, 0xe8, 0xb7, 0xe6, 0x16, 0x10, 0x71, 0x17,
+0xce, 0xde, 0x06, 0x4f, 0x48, 0x41, 0x7d, 0x35, 0x4a, 0xa3, 0x89, 0xf2, 0xc9, 0x4b, 0x7b, 0x41,
+0x11, 0x6d, 0x67, 0xb7, 0x08, 0x98, 0x4c, 0xe5, 0x11, 0x19, 0xae, 0x42, 0x80, 0xdc, 0xfb, 0x90,
+0x05, 0xd4, 0xf8, 0x50, 0xca, 0xbe, 0xe4, 0xad, 0xc7, 0xc2, 0x94, 0xd7, 0x16, 0x9d, 0xe6, 0x17,
+0x8f, 0xaf, 0x36, 0xfb, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x99, 0xe0, 0x19, 0x67, 0x0d, 0x62, 0xdb,
+0x76, 0xb3, 0xda, 0x3d, 0xb8, 0x5b, 0xe8, 0xfd, 0x42, 0xd2, 0x31, 0x0e, 0x87, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
+0x00, 0x98, 0x73, 0x70, 0xe2, 0xb0, 0xd3, 0xed, 0x39, 0xec, 0x4c, 0x60, 0xd9, 0xa9, 0x12, 0x86,
+0x17, 0x1e, 0x96, 0xd0, 0xe8, 0x54, 0x28, 0x3b, 0x64, 0x2d, 0x21, 0xa6, 0xf8, 0x9d, 0x56, 0x13,
+0x6a, 0x48, 0x3d, 0x4f, 0xc7, 0x3e, 0x29, 0xdb, 0x6d, 0x58, 0x83, 0x54, 0x3d, 0x87, 0x7d, 0x23,
+0x05, 0xd4, 0xe4, 0x1c, 0xdc, 0xe8, 0x38, 0x65, 0x86, 0xc5, 0x75, 0xa7, 0x5a, 0xdb, 0x35, 0x05,
+0xbd, 0x77, 0xde, 0xbb, 0x29, 0x37, 0x40, 0x05, 0x07, 0xc3, 0x94, 0x52, 0x9f, 0xca, 0x64, 0xdd,
+0xf1, 0x1b, 0x2b, 0xdc, 0x46, 0x0a, 0x10, 0x02, 0x31, 0xfd, 0x4a, 0x68, 0x0d, 0x07, 0x64, 0x90,
+0xe6, 0x1e, 0xf5, 0x2a, 0xa1, 0xa8, 0xbb, 0x3c, 0x5d, 0xf9, 0xa3, 0x08, 0x0b, 0x11, 0x0c, 0xf1,
+0x3f, 0x2d, 0x10, 0x94, 0x6f, 0xfe, 0xe2, 0x34, 0x87, 0x83, 0xd6, 0xcf, 0xe5, 0x1b, 0x35, 0x6d,
+0xd2, 0x03, 0xe1, 0xb0, 0x0d, 0xa8, 0xa0, 0xaa, 0x46, 0x27, 0x82, 0x36, 0xa7, 0x15, 0xb6, 0x08,
+0xa6, 0x42, 0x54, 0x57, 0xb6, 0x99, 0x5a, 0xe2, 0x0b, 0x79, 0x90, 0xd7, 0x57, 0x12, 0x51, 0x35,
+0x19, 0x88, 0x41, 0x68, 0x25, 0xd4, 0x37, 0x17, 0x84, 0x15, 0xfb, 0x01, 0x72, 0xdc, 0x95, 0xde,
+0x52, 0x26, 0x20, 0x98, 0x26, 0xe2, 0x76, 0xf5, 0x27, 0x6f, 0xfa, 0x00, 0x3b, 0x4a, 0x61, 0xd9,
+0x0d, 0xcb, 0x51, 0x93, 0x2a, 0xfd, 0x16, 0x06, 0x96, 0xa7, 0x23, 0x9a, 0x23, 0x48, 0xfe, 0x51,
+0xbd, 0xb6, 0xc4, 0xb0, 0xb1, 0x54, 0xce, 0xde, 0x6c, 0x41, 0xad, 0x16, 0x67, 0x7e, 0xdb, 0xfd,
+0x38, 0xcd, 0xb9, 0x38, 0x4e, 0xb2, 0xc1, 0x60, 0xcb, 0x9d, 0x17, 0xdf, 0x58, 0x9e, 0x7a, 0x62,
+0xb2, 0x26, 0x8f, 0x74, 0x95, 0x9b, 0xe4, 0x5b, 0x1d, 0xd2, 0x0f, 0xdd, 0x98, 0x1c, 0x9b, 0x59,
+0xb9, 0x23, 0xd3, 0x31, 0xa0, 0xa6, 0xff, 0x38, 0xdd, 0xcf, 0x20, 0x4f, 0xe9, 0x58, 0x56, 0x3a,
+0x67, 0xc3, 0xd1, 0xf6, 0x99, 0x99, 0x9d, 0xba, 0x36, 0xb6, 0x80, 0x2f, 0x88, 0x47, 0x4f, 0x86,
+0xbf, 0x44, 0x3a, 0x80, 0xe4, 0x37, 0x1c, 0xa6, 0xba, 0xea, 0x97, 0x98, 0x11, 0xd0, 0x84, 0x62,
+0x47, 0x64, 0x1e, 0xaa, 0xee, 0x40, 0xbf, 0x34, 0xb1, 0x9c, 0x8f, 0x4e, 0xe1, 0xf2, 0x92, 0x4f,
+0x1f, 0x8e, 0xf3, 0x9e, 0x97, 0xde, 0xf3, 0xa6, 0x79, 0x6a, 0x89, 0x71, 0x4f, 0x4b, 0x27, 0x17,
+0x48, 0xfe, 0xec, 0xf4, 0x50, 0x0f, 0x4f, 0x49, 0x7d, 0xcc, 0x45, 0xe3, 0xbd, 0x7a, 0x40, 0xc5,
+0x41, 0xdc, 0x61, 0x56, 0x27, 0x06, 0x69, 0xe5, 0x72, 0x41, 0x81, 0xd3, 0xb6, 0x01, 0x89, 0xa0,
+0x2f, 0x3a, 0x72, 0x79, 0xfe, 0x3a, 0x30, 0xbf, 0x41, 0xec, 0xc7, 0x62, 0x3e, 0x91, 0x4b, 0xc7,
+0xd9, 0x31, 0x76, 0x42, 0xf9, 0xf7, 0x3c, 0x63, 0xec, 0x26, 0x8c, 0x73, 0x0c, 0x7d, 0x1a, 0x1d,
+0xea, 0xa8, 0x7c, 0x87, 0xa8, 0xc2, 0x27, 0x7c, 0xe1, 0x33, 0x41, 0x0f, 0xcf, 0xcf, 0xfc, 0x00,
+0xa0, 0x22, 0x80, 0x9e, 0x4a, 0xa7, 0x6f, 0x00, 0xb0, 0x41, 0x45, 0xb7, 0x22, 0xca, 0x68, 0x48,
+0xc5, 0x42, 0xa2, 0xae, 0xdd, 0x1d, 0xf2, 0xe0, 0x6e, 0x4e, 0x05, 0x58, 0xb1, 0xc0, 0x90, 0x16,
+0x2a, 0xa4, 0x3d, 0x10, 0x40, 0xbe, 0x8f, 0x62, 0x63, 0x83, 0xa9, 0x9c, 0x82, 0x7d, 0x2d, 0x02,
+0xe9, 0x83, 0x30, 0x7c, 0xcb, 0x27, 0xc9, 0xfd, 0x1e, 0x66, 0x00, 0xb0, 0x2e, 0xd3, 0x21, 0x2f,
+0x8e, 0x33, 0x16, 0x6c, 0x98, 0xed, 0x10, 0xa8, 0x07, 0xd6, 0xcc, 0x93, 0xcf, 0xdb, 0xd1, 0x69,
+0x1c, 0xe4, 0xca, 0xc9, 0xe0, 0xb6, 0x9c, 0xe9, 0xce, 0x71, 0x71, 0xde, 0x6c, 0x3f, 0x16, 0xa4,
+0x79, 0x30, 0x82, 0x02, 0x9d, 0x30, 0x82, 0x02, 0x24, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0c,
+0x08, 0xbd, 0x85, 0x97, 0x6c, 0x99, 0x27, 0xa4, 0x80, 0x68, 0x47, 0x3b, 0x30, 0x0a, 0x06, 0x08,
+0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x81, 0x91, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+0x08, 0x13, 0x08, 0x49, 0x6c, 0x6c, 0x69, 0x6e, 0x6f, 0x69, 0x73, 0x31, 0x10, 0x30, 0x0e, 0x06,
+0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x31, 0x21, 0x30,
+0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x54, 0x72, 0x75, 0x73, 0x74, 0x77, 0x61, 0x76,
+0x65, 0x20, 0x48, 0x6f, 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x31, 0x54, 0x72, 0x75, 0x73, 0x74,
+0x77, 0x61, 0x76, 0x65, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x45, 0x43, 0x43, 0x20,
+0x50, 0x33, 0x38, 0x34, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d,
+0x31, 0x37, 0x30, 0x38, 0x32, 0x33, 0x31, 0x39, 0x33, 0x36, 0x34, 0x33, 0x5a, 0x17, 0x0d, 0x34,
+0x32, 0x30, 0x38, 0x32, 0x33, 0x31, 0x39, 0x33, 0x36, 0x34, 0x33, 0x5a, 0x30, 0x81, 0x91, 0x31,
+0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f,
+0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x08, 0x49, 0x6c, 0x6c, 0x69, 0x6e, 0x6f, 0x69, 0x73, 0x31,
+0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67,
+0x6f, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x54, 0x72, 0x75, 0x73,
+0x74, 0x77, 0x61, 0x76, 0x65, 0x20, 0x48, 0x6f, 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x2c, 0x20,
+0x49, 0x6e, 0x63, 0x2e, 0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x31, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x77, 0x61, 0x76, 0x65, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20,
+0x45, 0x43, 0x43, 0x20, 0x50, 0x33, 0x38, 0x34, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
+0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x6b, 0xda, 0x0d, 0x75, 0x35, 0x08, 0x31, 0x47,
+0x05, 0xae, 0x45, 0x99, 0x55, 0xf1, 0x11, 0x13, 0x2e, 0x4a, 0xf8, 0x10, 0x31, 0x23, 0xa3, 0x7e,
+0x83, 0xd3, 0x7f, 0x28, 0x08, 0x3a, 0x26, 0x1a, 0x3a, 0xcf, 0x97, 0x82, 0x1f, 0x80, 0xb7, 0x27,
+0x09, 0x8f, 0xd1, 0x8e, 0x30, 0xc4, 0x0a, 0x9b, 0x0e, 0xac, 0x58, 0x04, 0xab, 0xf7, 0x36, 0x7d,
+0x94, 0x23, 0xa4, 0x9b, 0x0a, 0x8a, 0x8b, 0xab, 0xeb, 0xfd, 0x39, 0x25, 0x66, 0xf1, 0x5e, 0xfe,
+0x8c, 0xae, 0x8d, 0x41, 0x79, 0x9d, 0x09, 0x60, 0xce, 0x28, 0xa9, 0xd3, 0x8a, 0x6d, 0xf3, 0xd6,
+0x45, 0xd4, 0xf2, 0x98, 0x84, 0x38, 0x65, 0xa0, 0xa3, 0x43, 0x30, 0x41, 0x30, 0x0f, 0x06, 0x03,
+0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0f, 0x06,
+0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x05, 0x03, 0x03, 0x07, 0x06, 0x00, 0x30, 0x1d,
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x55, 0xa9, 0x84, 0x89, 0xd2, 0xc1, 0x32,
+0xbd, 0x18, 0xcb, 0x6c, 0xa6, 0x07, 0x4e, 0xc8, 0xe7, 0x9d, 0xbe, 0x82, 0x90, 0x30, 0x0a, 0x06,
+0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x67, 0x00, 0x30, 0x64, 0x02, 0x30,
+0x37, 0x01, 0x92, 0x97, 0x45, 0x12, 0x7e, 0xa0, 0xf3, 0x3e, 0xad, 0x19, 0x3a, 0x72, 0xdd, 0xf4,
+0x50, 0x93, 0x03, 0x12, 0xbe, 0x44, 0xd2, 0x4f, 0x41, 0xa4, 0x8c, 0x9c, 0x9d, 0x1f, 0xa3, 0xf6,
+0xc2, 0x92, 0xe7, 0x48, 0x14, 0xfe, 0x4e, 0x9b, 0xa5, 0x91, 0x57, 0xae, 0xc6, 0x37, 0x72, 0xbb,
+0x02, 0x30, 0x67, 0x25, 0x0a, 0xb1, 0x0c, 0x5e, 0xee, 0xa9, 0x63, 0x92, 0x6f, 0xe5, 0x90, 0x0b,
+0xfe, 0x66, 0x22, 0xca, 0x47, 0xfd, 0x8a, 0x31, 0xf7, 0x83, 0xfe, 0x7a, 0xbf, 0x10, 0xbe, 0x18,
+0x2b, 0x1e, 0x8f, 0xf6, 0x29, 0x1e, 0x94, 0x59, 0xef, 0x8e, 0x21, 0x37, 0xcb, 0x51, 0x98, 0xa5,
+0x6e, 0x4b, 0x30, 0x82, 0x04, 0x33, 0x30, 0x82, 0x03, 0x1b, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+0x03, 0x09, 0x83, 0xf3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x30, 0x4d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x44, 0x45, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x44, 0x2d, 0x54,
+0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x0c, 0x1e, 0x44, 0x2d, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x32, 0x30,
+0x30, 0x39, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x31, 0x31, 0x30, 0x35, 0x30, 0x38, 0x33, 0x35,
+0x35, 0x38, 0x5a, 0x17, 0x0d, 0x32, 0x39, 0x31, 0x31, 0x30, 0x35, 0x30, 0x38, 0x33, 0x35, 0x35,
+0x38, 0x5a, 0x30, 0x4d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44,
+0x45, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x44, 0x2d, 0x54, 0x72,
+0x75, 0x73, 0x74, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x0c, 0x1e, 0x44, 0x2d, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
+0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x32, 0x30, 0x30,
+0x39, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01,
+0x01, 0x00, 0xd3, 0xb2, 0x4a, 0xcf, 0x7a, 0x47, 0xef, 0x75, 0x9b, 0x23, 0xfa, 0x3a, 0x2f, 0xd6,
+0x50, 0x45, 0x89, 0x35, 0x3a, 0xc6, 0x6b, 0xdb, 0xfe, 0xdb, 0x00, 0x68, 0xa8, 0xe0, 0x03, 0x11,
+0x1d, 0x37, 0x50, 0x08, 0x9f, 0x4d, 0x4a, 0x68, 0x94, 0x35, 0xb3, 0x53, 0xd1, 0x94, 0x63, 0xa7,
+0x20, 0x56, 0xaf, 0xde, 0x51, 0x78, 0xec, 0x2a, 0x3d, 0xf3, 0x48, 0x48, 0x50, 0x3e, 0x0a, 0xdf,
+0x46, 0x55, 0x8b, 0x27, 0x6d, 0xc3, 0x10, 0x4d, 0x0d, 0x91, 0x52, 0x43, 0xd8, 0x87, 0xe0, 0x5d,
+0x4e, 0x36, 0xb5, 0x21, 0xca, 0x5f, 0x39, 0x40, 0x04, 0x5f, 0x5b, 0x7e, 0xcc, 0xa3, 0xc6, 0x2b,
+0xa9, 0x40, 0x1e, 0xd9, 0x36, 0x84, 0xd6, 0x48, 0xf3, 0x92, 0x1e, 0x34, 0x46, 0x20, 0x24, 0xc1,
+0xa4, 0x51, 0x8e, 0x4a, 0x1a, 0xef, 0x50, 0x3f, 0x69, 0x5d, 0x19, 0x7f, 0x45, 0xc3, 0xc7, 0x01,
+0x8f, 0x51, 0xc9, 0x23, 0xe8, 0x72, 0xae, 0xb4, 0xbc, 0x56, 0x09, 0x7f, 0x12, 0xcb, 0x1c, 0xb1,
+0xaf, 0x29, 0x90, 0x0a, 0xc9, 0x55, 0xcc, 0x0f, 0xd3, 0xb4, 0x1a, 0xed, 0x47, 0x35, 0x5a, 0x4a,
+0xed, 0x9c, 0x73, 0x04, 0x21, 0xd0, 0xaa, 0xbd, 0x0c, 0x13, 0xb5, 0x00, 0xca, 0x26, 0x6c, 0xc4,
+0x6b, 0x0c, 0x94, 0x5a, 0x95, 0x94, 0xda, 0x50, 0x9a, 0xf1, 0xff, 0xa5, 0x2b, 0x66, 0x31, 0xa4,
+0xc9, 0x38, 0xa0, 0xdf, 0x1d, 0x1f, 0xb8, 0x09, 0x2e, 0xf3, 0xa7, 0xe8, 0x67, 0x52, 0xab, 0x95,
+0x1f, 0xe0, 0x46, 0x3e, 0xd8, 0xa4, 0xc3, 0xca, 0x5a, 0xc5, 0x31, 0x80, 0xe8, 0x48, 0x9a, 0x9f,
+0x94, 0x69, 0xfe, 0x19, 0xdd, 0xd8, 0x73, 0x7c, 0x81, 0xca, 0x96, 0xde, 0x8e, 0xed, 0xb3, 0x32,
+0x05, 0x65, 0x84, 0x34, 0xe6, 0xe6, 0xfd, 0x57, 0x10, 0xb5, 0x5f, 0x76, 0xbf, 0x2f, 0xb0, 0x10,
+0x0d, 0xc5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1a, 0x30, 0x82, 0x01, 0x16, 0x30,
+0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xfd, 0xda, 0x14, 0xc4, 0x9f,
+0x30, 0xde, 0x21, 0xbd, 0x1e, 0x42, 0x39, 0xfc, 0xab, 0x63, 0x23, 0x49, 0xe0, 0xf1, 0x84, 0x30,
+0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
+0x81, 0xd3, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, 0xcb, 0x30, 0x81, 0xc8, 0x30, 0x81, 0x80,
+0xa0, 0x7e, 0xa0, 0x7c, 0x86, 0x7a, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x64, 0x69, 0x72,
+0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x64, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e,
+0x65, 0x74, 0x2f, 0x43, 0x4e, 0x3d, 0x44, 0x2d, 0x54, 0x52, 0x55, 0x53, 0x54, 0x25, 0x32, 0x30,
+0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x25, 0x32, 0x30, 0x33,
+0x25, 0x32, 0x30, 0x43, 0x41, 0x25, 0x32, 0x30, 0x32, 0x25, 0x32, 0x30, 0x32, 0x30, 0x30, 0x39,
+0x2c, 0x4f, 0x3d, 0x44, 0x2d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x25, 0x32, 0x30, 0x47, 0x6d, 0x62,
+0x48, 0x2c, 0x43, 0x3d, 0x44, 0x45, 0x3f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+0x74, 0x65, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x6c, 0x69, 0x73, 0x74,
+0x30, 0x43, 0xa0, 0x41, 0xa0, 0x3f, 0x86, 0x3d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+0x77, 0x77, 0x2e, 0x64, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x63,
+0x72, 0x6c, 0x2f, 0x64, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f,
+0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x33, 0x5f, 0x63, 0x61, 0x5f, 0x32, 0x5f, 0x32, 0x30, 0x30,
+0x39, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7f, 0x97, 0xdb, 0x30, 0xc8, 0xdf, 0xa4,
+0x9c, 0x7d, 0x21, 0x7a, 0x80, 0x70, 0xce, 0x14, 0x12, 0x69, 0x88, 0x14, 0x95, 0x60, 0x44, 0x01,
+0xac, 0xb2, 0xe9, 0x30, 0x4f, 0x9b, 0x50, 0xc2, 0x66, 0xd8, 0x7e, 0x8d, 0x30, 0xb5, 0x70, 0x31,
+0xe9, 0xe2, 0x69, 0xc7, 0xf3, 0x70, 0xdb, 0x20, 0x15, 0x86, 0xd0, 0x0d, 0xf0, 0xbe, 0xac, 0x01,
+0x75, 0x84, 0xce, 0x7e, 0x9f, 0x4d, 0xbf, 0xb7, 0x60, 0x3b, 0x9c, 0xf3, 0xca, 0x1d, 0xe2, 0x5e,
+0x68, 0xd8, 0xa3, 0x9d, 0x97, 0xe5, 0x40, 0x60, 0xd2, 0x36, 0x21, 0xfe, 0xd0, 0xb4, 0xb8, 0x17,
+0xda, 0x74, 0xa3, 0x7f, 0xd4, 0xdf, 0xb0, 0x98, 0x02, 0xac, 0x6f, 0x6b, 0x6b, 0x2c, 0x25, 0x24,
+0x72, 0xa1, 0x65, 0xee, 0x25, 0x5a, 0xe5, 0xe6, 0x32, 0xe7, 0xf2, 0xdf, 0xab, 0x49, 0xfa, 0xf3,
+0x90, 0x69, 0x23, 0xdb, 0x04, 0xd9, 0xe7, 0x5c, 0x58, 0xfc, 0x65, 0xd4, 0x97, 0xbe, 0xcc, 0xfc,
+0x2e, 0x0a, 0xcc, 0x25, 0x2a, 0x35, 0x04, 0xf8, 0x60, 0x91, 0x15, 0x75, 0x3d, 0x41, 0xff, 0x23,
+0x1f, 0x19, 0xc8, 0x6c, 0xeb, 0x82, 0x53, 0x04, 0xa6, 0xe4, 0x4c, 0x22, 0x4d, 0x8d, 0x8c, 0xba,
+0xce, 0x5b, 0x73, 0xec, 0x64, 0x54, 0x50, 0x6d, 0xd1, 0x9c, 0x55, 0xfb, 0x69, 0xc3, 0x36, 0xc3,
+0x8c, 0xbc, 0x3c, 0x85, 0xa6, 0x6b, 0x0a, 0x26, 0x0d, 0xe0, 0x93, 0x98, 0x60, 0xae, 0x7e, 0xc6,
+0x24, 0x97, 0x8a, 0x61, 0x5f, 0x91, 0x8e, 0x66, 0x92, 0x09, 0x87, 0x36, 0xcd, 0x8b, 0x9b, 0x2d,
+0x3e, 0xf6, 0x51, 0xd4, 0x50, 0xd4, 0x59, 0x28, 0xbd, 0x83, 0xf2, 0xcc, 0x28, 0x7b, 0x53, 0x86,
+0x6d, 0xd8, 0x26, 0x88, 0x70, 0xd7, 0xea, 0x91, 0xcd, 0x3e, 0xb9, 0xca, 0xc0, 0x90, 0x6e, 0x5a,
+0xc6, 0x5e, 0x74, 0x65, 0xd7, 0x5c, 0xfe, 0xa3, 0xe2, 0x30, 0x82, 0x04, 0x43, 0x30, 0x82, 0x03,
+0x2b, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x09, 0x83, 0xf4, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x50, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x0c, 0x0c, 0x44, 0x2d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6d, 0x62, 0x48,
+0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x21, 0x44, 0x2d, 0x54, 0x52, 0x55,
+0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20,
+0x43, 0x41, 0x20, 0x32, 0x20, 0x45, 0x56, 0x20, 0x32, 0x30, 0x30, 0x39, 0x30, 0x1e, 0x17, 0x0d,
+0x30, 0x39, 0x31, 0x31, 0x30, 0x35, 0x30, 0x38, 0x35, 0x30, 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x32,
+0x39, 0x31, 0x31, 0x30, 0x35, 0x30, 0x38, 0x35, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x50, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, 0x15, 0x30, 0x13, 0x06,
+0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x44, 0x2d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x47, 0x6d,
+0x62, 0x48, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x21, 0x44, 0x2d, 0x54,
+0x52, 0x55, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20,
+0x33, 0x20, 0x43, 0x41, 0x20, 0x32, 0x20, 0x45, 0x56, 0x20, 0x32, 0x30, 0x30, 0x39, 0x30, 0x82,
+0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x99,
+0xf1, 0x84, 0x34, 0x70, 0xba, 0x2f, 0xb7, 0x30, 0xa0, 0x8e, 0xbd, 0x7c, 0x04, 0xcf, 0xbe, 0x62,
+0xbc, 0x99, 0xfd, 0x82, 0x97, 0xd2, 0x7a, 0x0a, 0x67, 0x96, 0x38, 0x09, 0xf6, 0x10, 0x4e, 0x95,
+0x22, 0x73, 0x99, 0x8d, 0xda, 0x15, 0x2d, 0xe7, 0x05, 0xfc, 0x19, 0x73, 0x22, 0xb7, 0x8e, 0x98,
+0x00, 0xbc, 0x3c, 0x3d, 0xac, 0xa1, 0x6c, 0xfb, 0xd6, 0x79, 0x25, 0x4b, 0xad, 0xf0, 0xcc, 0x64,
+0xda, 0x88, 0x3e, 0x29, 0xb8, 0x0f, 0x09, 0xd3, 0x34, 0xdd, 0x33, 0xf5, 0x62, 0xd1, 0xe1, 0xcd,
+0x19, 0xe9, 0xee, 0x18, 0x4f, 0x4c, 0x58, 0xae, 0xe2, 0x1e, 0xd6, 0x0c, 0x5b, 0x15, 0x5a, 0xd8,
+0x3a, 0xb8, 0xc4, 0x18, 0x64, 0x1e, 0xe3, 0x33, 0xb2, 0xb5, 0x89, 0x77, 0x4e, 0x0c, 0xbf, 0xd9,
+0x94, 0x6b, 0x13, 0x97, 0x6f, 0x12, 0xa3, 0xfe, 0x99, 0xa9, 0x04, 0xcc, 0x15, 0xec, 0x60, 0x68,
+0x36, 0xed, 0x08, 0x7b, 0xb7, 0xf5, 0xbf, 0x93, 0xed, 0x66, 0x31, 0x83, 0x8c, 0xc6, 0x71, 0x34,
+0x87, 0x4e, 0x17, 0xea, 0xaf, 0x8b, 0x91, 0x8d, 0x1c, 0x56, 0x41, 0xae, 0x22, 0x37, 0x5e, 0x37,
+0xf2, 0x1d, 0xd9, 0xd1, 0x2d, 0x0d, 0x2f, 0x69, 0x51, 0xa7, 0xbe, 0x66, 0xa6, 0x8a, 0x3a, 0x2a,
+0xbd, 0xc7, 0x1a, 0xb1, 0xe1, 0x14, 0xf0, 0xbe, 0x3a, 0x1d, 0xb9, 0xcf, 0x5b, 0xb1, 0x6a, 0xfe,
+0xb4, 0xb1, 0x46, 0x20, 0xa2, 0xfb, 0x1e, 0x3b, 0x70, 0xef, 0x93, 0x98, 0x7d, 0x8c, 0x73, 0x96,
+0xf2, 0xc5, 0xef, 0x85, 0x70, 0xad, 0x29, 0x26, 0xfc, 0x1e, 0x04, 0x3e, 0x1c, 0xa0, 0xd8, 0x0f,
+0xcb, 0x52, 0x83, 0x62, 0x7c, 0xee, 0x8b, 0x53, 0x95, 0x90, 0xa9, 0x57, 0xa2, 0xea, 0x61, 0x05,
+0xd8, 0xf9, 0x4d, 0xc4, 0x27, 0xfa, 0x6e, 0xad, 0xed, 0xf9, 0xd7, 0x51, 0xf7, 0x6b, 0xa5, 0x02,
+0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x24, 0x30, 0x82, 0x01, 0x20, 0x30, 0x0f, 0x06, 0x03,
+0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06,
+0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd3, 0x94, 0x8a, 0x4c, 0x62, 0x13, 0x2a, 0x19,
+0x2e, 0xcc, 0xaf, 0x72, 0x8a, 0x7d, 0x36, 0xd7, 0x9a, 0x1c, 0xdc, 0x67, 0x30, 0x0e, 0x06, 0x03,
+0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x81, 0xdd, 0x06,
+0x03, 0x55, 0x1d, 0x1f, 0x04, 0x81, 0xd5, 0x30, 0x81, 0xd2, 0x30, 0x81, 0x87, 0xa0, 0x81, 0x84,
+0xa0, 0x81, 0x81, 0x86, 0x7f, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x64, 0x69, 0x72, 0x65,
+0x63, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x64, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65,
+0x74, 0x2f, 0x43, 0x4e, 0x3d, 0x44, 0x2d, 0x54, 0x52, 0x55, 0x53, 0x54, 0x25, 0x32, 0x30, 0x52,
+0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x25, 0x32, 0x30, 0x33, 0x25,
+0x32, 0x30, 0x43, 0x41, 0x25, 0x32, 0x30, 0x32, 0x25, 0x32, 0x30, 0x45, 0x56, 0x25, 0x32, 0x30,
+0x32, 0x30, 0x30, 0x39, 0x2c, 0x4f, 0x3d, 0x44, 0x2d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x25, 0x32,
+0x30, 0x47, 0x6d, 0x62, 0x48, 0x2c, 0x43, 0x3d, 0x44, 0x45, 0x3f, 0x63, 0x65, 0x72, 0x74, 0x69,
+0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+0x6c, 0x69, 0x73, 0x74, 0x30, 0x46, 0xa0, 0x44, 0xa0, 0x42, 0x86, 0x40, 0x68, 0x74, 0x74, 0x70,
+0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x64, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e,
+0x65, 0x74, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x64, 0x2d, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x72,
+0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x33, 0x5f, 0x63, 0x61, 0x5f, 0x32,
+0x5f, 0x65, 0x76, 0x5f, 0x32, 0x30, 0x30, 0x39, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+0x34, 0xed, 0x7b, 0x5a, 0x3c, 0xa4, 0x94, 0x88, 0xef, 0x1a, 0x11, 0x75, 0x07, 0x2f, 0xb3, 0xfe,
+0x3c, 0xfa, 0x1e, 0x51, 0x26, 0xeb, 0x87, 0xf6, 0x29, 0xde, 0xe0, 0xf1, 0xd4, 0xc6, 0x24, 0x09,
+0xe9, 0xc1, 0xcf, 0x55, 0x1b, 0xb4, 0x30, 0xd9, 0xce, 0x1a, 0xfe, 0x06, 0x51, 0xa6, 0x15, 0xa4,
+0x2d, 0xef, 0xb2, 0x4b, 0xbf, 0x20, 0x28, 0x25, 0x49, 0xd1, 0xa6, 0x36, 0x77, 0x34, 0xe8, 0x64,
+0xdf, 0x52, 0xb1, 0x11, 0xc7, 0x73, 0x7a, 0xcd, 0x39, 0x9e, 0xc2, 0xad, 0x8c, 0x71, 0x21, 0xf2,
+0x5a, 0x6b, 0xaf, 0xdf, 0x3c, 0x4e, 0x55, 0xaf, 0xb2, 0x84, 0x65, 0x14, 0x89, 0xb9, 0x77, 0xcb,
+0x2a, 0x31, 0xbe, 0xcf, 0xa3, 0x6d, 0xcf, 0x6f, 0x48, 0x94, 0x32, 0x46, 0x6f, 0xe7, 0x71, 0x8c,
+0xa0, 0xa6, 0x84, 0x19, 0x37, 0x07, 0xf2, 0x03, 0x45, 0x09, 0x2b, 0x86, 0x75, 0x7c, 0xdf, 0x5f,
+0x69, 0x57, 0x00, 0xdb, 0x6e, 0xd8, 0xa6, 0x72, 0x22, 0x4b, 0x50, 0xd4, 0x75, 0x98, 0x56, 0xdf,
+0xb7, 0x18, 0xff, 0x43, 0x43, 0x50, 0xae, 0x7a, 0x44, 0x7b, 0xf0, 0x79, 0x51, 0xd7, 0x43, 0x3d,
+0xa7, 0xd3, 0x81, 0xd3, 0xf0, 0xc9, 0x4f, 0xb9, 0xda, 0xc6, 0x97, 0x86, 0xd0, 0x82, 0xc3, 0xe4,
+0x42, 0x6d, 0xfe, 0xb0, 0xe2, 0x64, 0x4e, 0x0e, 0x26, 0xe7, 0x40, 0x34, 0x26, 0xb5, 0x08, 0x89,
+0xd7, 0x08, 0x63, 0x63, 0x38, 0x27, 0x75, 0x1e, 0x33, 0xea, 0x6e, 0xa8, 0xdd, 0x9f, 0x99, 0x4f,
+0x74, 0x4d, 0x81, 0x89, 0x80, 0x4b, 0xdd, 0x9a, 0x97, 0x29, 0x5c, 0x2f, 0xbe, 0x81, 0x41, 0xb9,
+0x8c, 0xff, 0xea, 0x7d, 0x60, 0x06, 0x9e, 0xcd, 0xd7, 0x3d, 0xd3, 0x2e, 0xa3, 0x15, 0xbc, 0xa8,
+0xe6, 0x26, 0xe5, 0x6f, 0xc3, 0xdc, 0xb8, 0x03, 0x21, 0xea, 0x9f, 0x16, 0xf1, 0x2c, 0x54, 0xb5,
+0x30, 0x82, 0x06, 0x4b, 0x30, 0x82, 0x04, 0x33, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x6a,
+0x68, 0x3e, 0x9c, 0x51, 0x9b, 0xcb, 0x53, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xb2, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+0x04, 0x06, 0x13, 0x02, 0x54, 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
+0x06, 0x41, 0x6e, 0x6b, 0x61, 0x72, 0x61, 0x31, 0x40, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x0c, 0x37, 0x45, 0x2d, 0x54, 0x75, 0xc4, 0x9f, 0x72, 0x61, 0x20, 0x45, 0x42, 0x47, 0x20, 0x42,
+0x69, 0x6c, 0x69, 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x54, 0x65, 0x6b, 0x6e, 0x6f, 0x6c, 0x6f, 0x6a,
+0x69, 0x6c, 0x65, 0x72, 0x69, 0x20, 0x76, 0x65, 0x20, 0x48, 0x69, 0x7a, 0x6d, 0x65, 0x74, 0x6c,
+0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5, 0x9e, 0x2e, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x0c, 0x1d, 0x45, 0x2d, 0x54, 0x75, 0x67, 0x72, 0x61, 0x20, 0x53, 0x65, 0x72, 0x74,
+0x69, 0x66, 0x69, 0x6b, 0x61, 0x73, 0x79, 0x6f, 0x6e, 0x20, 0x4d, 0x65, 0x72, 0x6b, 0x65, 0x7a,
+0x69, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x45, 0x2d, 0x54, 0x75,
+0x67, 0x72, 0x61, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+0x33, 0x30, 0x33, 0x30, 0x35, 0x31, 0x32, 0x30, 0x39, 0x34, 0x38, 0x5a, 0x17, 0x0d, 0x32, 0x33,
+0x30, 0x33, 0x30, 0x33, 0x31, 0x32, 0x30, 0x39, 0x34, 0x38, 0x5a, 0x30, 0x81, 0xb2, 0x31, 0x0b,
+0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x54, 0x52, 0x31, 0x0f, 0x30, 0x0d, 0x06,
+0x03, 0x55, 0x04, 0x07, 0x0c, 0x06, 0x41, 0x6e, 0x6b, 0x61, 0x72, 0x61, 0x31, 0x40, 0x30, 0x3e,
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x37, 0x45, 0x2d, 0x54, 0x75, 0xc4, 0x9f, 0x72, 0x61, 0x20,
+0x45, 0x42, 0x47, 0x20, 0x42, 0x69, 0x6c, 0x69, 0xc5, 0x9f, 0x69, 0x6d, 0x20, 0x54, 0x65, 0x6b,
+0x6e, 0x6f, 0x6c, 0x6f, 0x6a, 0x69, 0x6c, 0x65, 0x72, 0x69, 0x20, 0x76, 0x65, 0x20, 0x48, 0x69,
+0x7a, 0x6d, 0x65, 0x74, 0x6c, 0x65, 0x72, 0x69, 0x20, 0x41, 0x2e, 0xc5, 0x9e, 0x2e, 0x31, 0x26,
+0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x45, 0x2d, 0x54, 0x75, 0x67, 0x72, 0x61,
+0x20, 0x53, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x6b, 0x61, 0x73, 0x79, 0x6f, 0x6e, 0x20, 0x4d,
+0x65, 0x72, 0x6b, 0x65, 0x7a, 0x69, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+0x1f, 0x45, 0x2d, 0x54, 0x75, 0x67, 0x72, 0x61, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
+0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01,
+0x00, 0xe2, 0xf5, 0x3f, 0x93, 0x05, 0x51, 0x1e, 0x85, 0x62, 0x54, 0x5e, 0x7a, 0x0b, 0xf5, 0x18,
+0x07, 0x83, 0xae, 0x7e, 0xaf, 0x7c, 0xf7, 0xd4, 0x8a, 0x6b, 0xa5, 0x63, 0x43, 0x39, 0xb9, 0x4b,
+0xf7, 0xc3, 0xc6, 0x64, 0x89, 0x3d, 0x94, 0x2e, 0x54, 0x80, 0x52, 0x39, 0x39, 0x07, 0x4b, 0x4b,
+0xdd, 0x85, 0x07, 0x76, 0x87, 0xcc, 0xbf, 0x2f, 0x95, 0x4c, 0xcc, 0x7d, 0xa7, 0x3d, 0xbc, 0x47,
+0x0f, 0x98, 0x70, 0xf8, 0x8c, 0x85, 0x1e, 0x74, 0x8e, 0x92, 0x6d, 0x1b, 0x40, 0xd1, 0x99, 0x0d,
+0xbb, 0x75, 0x6e, 0xc8, 0xa9, 0x6b, 0x9a, 0xc0, 0x84, 0x31, 0xaf, 0xca, 0x43, 0xcb, 0xeb, 0x2b,
+0x34, 0xe8, 0x8f, 0x97, 0x6b, 0x01, 0x9b, 0xd5, 0x0e, 0x4a, 0x08, 0xaa, 0x5b, 0x92, 0x74, 0x85,
+0x43, 0xd3, 0x80, 0xae, 0xa1, 0x88, 0x5b, 0xae, 0xb3, 0xea, 0x5e, 0xcb, 0x16, 0x9a, 0x77, 0x44,
+0xc8, 0xa1, 0xf6, 0x54, 0x68, 0xce, 0xde, 0x8f, 0x97, 0x2b, 0xba, 0x5b, 0x40, 0x02, 0x0c, 0x64,
+0x17, 0xc0, 0xb5, 0x93, 0xcd, 0xe1, 0xf1, 0x13, 0x66, 0xce, 0x0c, 0x79, 0xef, 0xd1, 0x91, 0x28,
+0xab, 0x5f, 0xa0, 0x12, 0x52, 0x30, 0x73, 0x19, 0x8e, 0x8f, 0xe1, 0x8c, 0x07, 0xa2, 0xc3, 0xbb,
+0x4a, 0xf0, 0xea, 0x1f, 0x15, 0xa8, 0xee, 0x25, 0xcc, 0xa4, 0x46, 0xf8, 0x1b, 0x22, 0xef, 0xb3,
+0x0e, 0x43, 0xba, 0x2c, 0x24, 0xb8, 0xc5, 0x2c, 0x5c, 0xd4, 0x1c, 0xf8, 0x5d, 0x64, 0xbd, 0xc3,
+0x93, 0x5e, 0x28, 0xa7, 0x3f, 0x27, 0xf1, 0x8e, 0x1e, 0xd3, 0x2a, 0x50, 0x05, 0xa3, 0x55, 0xd9,
+0xcb, 0xe7, 0x39, 0x53, 0xc0, 0x98, 0x9e, 0x8c, 0x54, 0x62, 0x8b, 0x26, 0xb0, 0xf7, 0x7d, 0x8d,
+0x7c, 0xe4, 0xc6, 0x9e, 0x66, 0x42, 0x55, 0x82, 0x47, 0xe7, 0xb2, 0x58, 0x8d, 0x66, 0xf7, 0x07,
+0x7c, 0x2e, 0x36, 0xe6, 0x50, 0x1c, 0x3f, 0xdb, 0x43, 0x24, 0xc5, 0xbf, 0x86, 0x47, 0x79, 0xb3,
+0x79, 0x1c, 0xf7, 0x5a, 0xf4, 0x13, 0xec, 0x6c, 0xf8, 0x3f, 0xe2, 0x59, 0x1f, 0x95, 0xee, 0x42,
+0x3e, 0xb9, 0xad, 0xa8, 0x32, 0x85, 0x49, 0x97, 0x46, 0xfe, 0x4b, 0x31, 0x8f, 0x5a, 0xcb, 0xad,
+0x74, 0x47, 0x1f, 0xe9, 0x91, 0xb7, 0xdf, 0x28, 0x04, 0x22, 0xa0, 0xd4, 0x0f, 0x5d, 0xe2, 0x79,
+0x4f, 0xea, 0x6c, 0x85, 0x86, 0xbd, 0xa8, 0xa6, 0xce, 0xe4, 0xfa, 0xc3, 0xe1, 0xb3, 0xae, 0xde,
+0x3c, 0x51, 0xee, 0xcb, 0x13, 0x7c, 0x01, 0x7f, 0x84, 0x0e, 0x5d, 0x51, 0x94, 0x9e, 0x13, 0x0c,
+0xb6, 0x2e, 0xa5, 0x4c, 0xf9, 0x39, 0x70, 0x36, 0x6f, 0x96, 0xca, 0x2e, 0x0c, 0x44, 0x55, 0xc5,
+0xca, 0xfa, 0x5d, 0x02, 0xa3, 0xdf, 0xd6, 0x64, 0x8c, 0x5a, 0xb3, 0x01, 0x0a, 0xa9, 0xb5, 0x0a,
+0x47, 0x17, 0xff, 0xef, 0x91, 0x40, 0x2a, 0x8e, 0xa1, 0x46, 0x3a, 0x31, 0x98, 0xe5, 0x11, 0xfc,
+0xcc, 0xbb, 0x49, 0x56, 0x8a, 0xfc, 0xb9, 0xd0, 0x61, 0x9a, 0x6f, 0x65, 0x6c, 0xe6, 0xc3, 0xcb,
+0x3e, 0x75, 0x49, 0xfe, 0x8f, 0xa7, 0xe2, 0x89, 0xc5, 0x67, 0xd7, 0x9d, 0x46, 0x13, 0x4e, 0x31,
+0x76, 0x3b, 0x24, 0xb3, 0x9e, 0x11, 0x65, 0x86, 0xab, 0x7f, 0xef, 0x1d, 0xd4, 0xf8, 0xbc, 0xe7,
+0xac, 0x5a, 0x5c, 0xb7, 0x5a, 0x47, 0x5c, 0x55, 0xce, 0x55, 0xb4, 0x22, 0x71, 0x5b, 0x5b, 0x0b,
+0xf0, 0xcf, 0xdc, 0xa0, 0x61, 0x64, 0xea, 0xa9, 0xd7, 0x68, 0x0a, 0x63, 0xa7, 0xe0, 0x0d, 0x3f,
+0xa0, 0xaf, 0xd3, 0xaa, 0xd2, 0x7e, 0xef, 0x51, 0xa0, 0xe6, 0x51, 0x2b, 0x55, 0x92, 0x15, 0x17,
+0x53, 0xcb, 0xb7, 0x66, 0x0e, 0x66, 0x4c, 0xf8, 0xf9, 0x75, 0x4c, 0x90, 0xe7, 0x12, 0x70, 0xc7,
+0x45, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+0x0e, 0x04, 0x16, 0x04, 0x14, 0x2e, 0xe3, 0xdb, 0xb2, 0x49, 0xd0, 0x9c, 0x54, 0x79, 0x5c, 0xfa,
+0x27, 0x2a, 0xfe, 0xcc, 0x4e, 0xd2, 0xe8, 0x4e, 0x54, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13,
+0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x2e, 0xe3, 0xdb, 0xb2, 0x49, 0xd0, 0x9c, 0x54, 0x79,
+0x5c, 0xfa, 0x27, 0x2a, 0xfe, 0xcc, 0x4e, 0xd2, 0xe8, 0x4e, 0x54, 0x30, 0x0e, 0x06, 0x03, 0x55,
+0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x05,
+0x37, 0x3a, 0xf4, 0x4d, 0xb7, 0x45, 0xe2, 0x45, 0x75, 0x24, 0x8f, 0xb6, 0x77, 0x52, 0xe8, 0x1c,
+0xd8, 0x10, 0x93, 0x65, 0xf3, 0xf2, 0x59, 0x06, 0xa4, 0x3e, 0x1e, 0x29, 0xec, 0x5d, 0xd1, 0xd0,
+0xab, 0x7c, 0xe0, 0x0a, 0x90, 0x48, 0x78, 0xed, 0x4e, 0x98, 0x03, 0x99, 0xfe, 0x28, 0x60, 0x91,
+0x1d, 0x30, 0x1d, 0xb8, 0x63, 0x7c, 0xa8, 0xe6, 0x35, 0xb5, 0xfa, 0xd3, 0x61, 0x76, 0xe6, 0xd6,
+0x07, 0x4b, 0xca, 0x69, 0x9a, 0xb2, 0x84, 0x7a, 0x77, 0x93, 0x45, 0x17, 0x15, 0x9f, 0x24, 0xd0,
+0x98, 0x13, 0x12, 0xff, 0xbb, 0xa0, 0x2e, 0xfd, 0x4e, 0x4c, 0x87, 0xf8, 0xce, 0x5c, 0xaa, 0x98,
+0x1b, 0x05, 0xe0, 0x00, 0x46, 0x4a, 0x82, 0x80, 0xa5, 0x33, 0x8b, 0x28, 0xdc, 0xed, 0x38, 0xd3,
+0xdf, 0xe5, 0x3e, 0xe9, 0xfe, 0xfb, 0x59, 0xdd, 0x61, 0x84, 0x4f, 0xd2, 0x54, 0x96, 0x13, 0x61,
+0x13, 0x3e, 0x8f, 0x80, 0x69, 0xbe, 0x93, 0x47, 0xb5, 0x35, 0x43, 0xd2, 0x5a, 0xbb, 0x3d, 0x5c,
+0xef, 0xb3, 0x42, 0x47, 0xcd, 0x3b, 0x55, 0x13, 0x06, 0xb0, 0x09, 0xdb, 0xfd, 0x63, 0xf6, 0x3a,
+0x88, 0x0a, 0x99, 0x6f, 0x7e, 0xe1, 0xce, 0x1b, 0x53, 0x6a, 0x44, 0x66, 0x23, 0x51, 0x08, 0x7b,
+0xbc, 0x5b, 0x52, 0xa2, 0xfd, 0x06, 0x37, 0x38, 0x40, 0x61, 0x8f, 0x4a, 0x96, 0xb8, 0x90, 0x37,
+0xf8, 0x66, 0xc7, 0x78, 0x90, 0x00, 0x15, 0x2e, 0x8b, 0xad, 0x51, 0x35, 0x53, 0x07, 0xa8, 0x6b,
+0x68, 0xae, 0xf9, 0x4e, 0x3c, 0x07, 0x26, 0xcd, 0x08, 0x05, 0x70, 0xcc, 0x39, 0x3f, 0x76, 0xbd,
+0xa5, 0xd3, 0x67, 0x26, 0x01, 0x86, 0xa6, 0x53, 0xd2, 0x60, 0x3b, 0x7c, 0x43, 0x7f, 0x55, 0x8a,
+0xbc, 0x95, 0x1a, 0xc1, 0x28, 0x39, 0x4c, 0x1f, 0x43, 0xd2, 0x91, 0xf4, 0x72, 0x59, 0x8a, 0xb9,
+0x56, 0xfc, 0x3f, 0xb4, 0x9d, 0xda, 0x70, 0x9c, 0x76, 0x5a, 0x8c, 0x43, 0x50, 0xee, 0x8e, 0x30,
+0x72, 0x4d, 0xdf, 0xff, 0x49, 0xf7, 0xc6, 0xa9, 0x67, 0xd9, 0x6d, 0xac, 0x02, 0x11, 0xe2, 0x3a,
+0x16, 0x25, 0xa7, 0x58, 0x08, 0xcb, 0x6f, 0x53, 0x41, 0x9c, 0x48, 0x38, 0x47, 0x68, 0x33, 0xd1,
+0xd7, 0xc7, 0x8f, 0xd4, 0x74, 0x21, 0xd4, 0xc3, 0x05, 0x90, 0x7a, 0xff, 0xce, 0x96, 0x88, 0xb1,
+0x15, 0x29, 0x5d, 0x23, 0xab, 0xd0, 0x60, 0xa1, 0x12, 0x4f, 0xde, 0xf4, 0x17, 0xcd, 0x32, 0xe5,
+0xc9, 0xbf, 0xc8, 0x43, 0xad, 0xfd, 0x2e, 0x8e, 0xf1, 0xaf, 0xe2, 0xf4, 0x98, 0xfa, 0x12, 0x1f,
+0x20, 0xd8, 0xc0, 0xa7, 0x0c, 0x85, 0xc5, 0x90, 0xf4, 0x3b, 0x2d, 0x96, 0x26, 0xb1, 0x2c, 0xbe,
+0x4c, 0xab, 0xeb, 0xb1, 0xd2, 0x8a, 0xc9, 0xdb, 0x78, 0x13, 0x0f, 0x1e, 0x09, 0x9d, 0x6d, 0x8f,
+0x00, 0x9f, 0x02, 0xda, 0xc1, 0xfa, 0x1f, 0x7a, 0x7a, 0x09, 0xc4, 0x4a, 0xe6, 0x88, 0x2a, 0x97,
+0x9f, 0x89, 0x8b, 0xfd, 0x37, 0x5f, 0x5f, 0x3a, 0xce, 0x38, 0x59, 0x86, 0x4b, 0xaf, 0x71, 0x0b,
+0xb4, 0xd8, 0xf2, 0x70, 0x4f, 0x9f, 0x32, 0x13, 0xe3, 0xb0, 0xa7, 0x57, 0xe5, 0xda, 0xda, 0x43,
+0xcb, 0x84, 0x34, 0xf2, 0x28, 0xc4, 0xea, 0x6d, 0xf4, 0x2a, 0xef, 0xc1, 0x6b, 0x76, 0xda, 0xfb,
+0x7e, 0xbb, 0x85, 0x3c, 0xd2, 0x53, 0xc2, 0x4d, 0xbe, 0x71, 0xe1, 0x45, 0xd1, 0xfd, 0x23, 0x67,
+0x0d, 0x13, 0x75, 0xfb, 0xcf, 0x65, 0x67, 0x22, 0x9d, 0xae, 0xb0, 0x09, 0xd1, 0x09, 0xff, 0x1d,
+0x34, 0xbf, 0xfe, 0x23, 0x97, 0x37, 0xd2, 0x39, 0xfa, 0x3d, 0x0d, 0x06, 0x0b, 0xb4, 0xdb, 0x3b,
+0xa3, 0xab, 0x6f, 0x5c, 0x1d, 0xb6, 0x7e, 0xe8, 0xb3, 0x82, 0x34, 0xed, 0x06, 0x5c, 0x24, 0x30,
+0x82, 0x05, 0xbd, 0x30, 0x82, 0x03, 0xa5, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x4f, 0x1b,
+0xd4, 0x2f, 0x54, 0xbb, 0x2f, 0x4b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x43, 0x48, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x53,
+0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x41, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20,
+0x53, 0x69, 0x6c, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x1e,
+0x17, 0x0d, 0x30, 0x36, 0x31, 0x30, 0x32, 0x35, 0x30, 0x38, 0x33, 0x32, 0x34, 0x36, 0x5a, 0x17,
+0x0d, 0x33, 0x36, 0x31, 0x30, 0x32, 0x35, 0x30, 0x38, 0x33, 0x32, 0x34, 0x36, 0x5a, 0x30, 0x47,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x48, 0x31, 0x15, 0x30,
+0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x53, 0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67,
+0x6e, 0x20, 0x41, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x18, 0x53,
+0x77, 0x69, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x53, 0x69, 0x6c, 0x76, 0x65, 0x72, 0x20,
+0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x32, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30,
+0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xc4, 0xf1, 0x87, 0x7f, 0xd3, 0x78, 0x31, 0xf7,
+0x38, 0xc9, 0xf8, 0xc3, 0x99, 0x43, 0xbc, 0xc7, 0xf7, 0xbc, 0x37, 0xe7, 0x4e, 0x71, 0xba, 0x4b,
+0x8f, 0xa5, 0x73, 0x1d, 0x5c, 0x6e, 0x98, 0xae, 0x03, 0x57, 0xae, 0x38, 0x37, 0x43, 0x2f, 0x17,
+0x3d, 0x1f, 0xc8, 0xce, 0x68, 0x10, 0xc1, 0x78, 0xae, 0x19, 0x03, 0x2b, 0x10, 0xfa, 0x2c, 0x79,
+0x83, 0xf6, 0xe8, 0xb9, 0x68, 0xb9, 0x55, 0xf2, 0x04, 0x44, 0xa7, 0x39, 0xf9, 0xfc, 0x04, 0x8b,
+0x1e, 0xf1, 0xa2, 0x4d, 0x27, 0xf9, 0x61, 0x7b, 0xba, 0xb7, 0xe5, 0xa2, 0x13, 0xb6, 0xeb, 0x61,
+0x3e, 0xd0, 0x6c, 0xd1, 0xe6, 0xfb, 0xfa, 0x5e, 0xed, 0x1d, 0xb4, 0x9e, 0xa0, 0x35, 0x5b, 0xa1,
+0x92, 0xcb, 0xf0, 0x49, 0x92, 0xfe, 0x85, 0x0a, 0x05, 0x3e, 0xe6, 0xd9, 0x0b, 0xe2, 0x4f, 0xbb,
+0xdc, 0x95, 0x37, 0xfc, 0x91, 0xe9, 0x32, 0x35, 0x22, 0xd1, 0x1f, 0x3a, 0x4e, 0x27, 0x85, 0x9d,
+0xb0, 0x15, 0x94, 0x32, 0xda, 0x61, 0x0d, 0x47, 0x4d, 0x60, 0x42, 0xae, 0x92, 0x47, 0xe8, 0x83,
+0x5a, 0x50, 0x58, 0xe9, 0x8a, 0x8b, 0xb9, 0x5d, 0xa1, 0xdc, 0xdd, 0x99, 0x4a, 0x1f, 0x36, 0x67,
+0xbb, 0x48, 0xe4, 0x83, 0xb6, 0x37, 0xeb, 0x48, 0x3a, 0xaf, 0x0f, 0x67, 0x8f, 0x17, 0x07, 0xe8,
+0x04, 0xca, 0xef, 0x6a, 0x31, 0x87, 0xd4, 0xc0, 0xb6, 0xf9, 0x94, 0x71, 0x7b, 0x67, 0x64, 0xb8,
+0xb6, 0x91, 0x4a, 0x42, 0x7b, 0x65, 0x2e, 0x30, 0x6a, 0x0c, 0xf5, 0x90, 0xee, 0x95, 0xe6, 0xf2,
+0xcd, 0x82, 0xec, 0xd9, 0xa1, 0x4a, 0xec, 0xf6, 0xb2, 0x4b, 0xe5, 0x45, 0x85, 0xe6, 0x6d, 0x78,
+0x93, 0x04, 0x2e, 0x9c, 0x82, 0x6d, 0x36, 0xa9, 0xc4, 0x31, 0x64, 0x1f, 0x86, 0x83, 0x0b, 0x2a,
+0xf4, 0x35, 0x0a, 0x78, 0xc9, 0x55, 0xcf, 0x41, 0xb0, 0x47, 0xe9, 0x30, 0x9f, 0x99, 0xbe, 0x61,
+0xa8, 0x06, 0x84, 0xb9, 0x28, 0x7a, 0x5f, 0x38, 0xd9, 0x1b, 0xa9, 0x38, 0xb0, 0x83, 0x7f, 0x73,
+0xc1, 0xc3, 0x3b, 0x48, 0x2a, 0x82, 0x0f, 0x21, 0x9b, 0xb8, 0xcc, 0xa8, 0x35, 0xc3, 0x84, 0x1b,
+0x83, 0xb3, 0x3e, 0xbe, 0xa4, 0x95, 0x69, 0x01, 0x3a, 0x89, 0x00, 0x78, 0x04, 0xd9, 0xc9, 0xf4,
+0x99, 0x19, 0xab, 0x56, 0x7e, 0x5b, 0x8b, 0x86, 0x39, 0x15, 0x91, 0xa4, 0x10, 0x2c, 0x09, 0x32,
+0x80, 0x60, 0xb3, 0x93, 0xc0, 0x2a, 0xb6, 0x18, 0x0b, 0x9d, 0x7e, 0x8d, 0x49, 0xf2, 0x10, 0x4a,
+0x7f, 0xf9, 0xd5, 0x46, 0x2f, 0x19, 0x92, 0xa3, 0x99, 0xa7, 0x26, 0xac, 0xbb, 0x8c, 0x3c, 0xe6,
+0x0e, 0xbc, 0x47, 0x07, 0xdc, 0x73, 0x51, 0xf1, 0x70, 0x64, 0x2f, 0x08, 0xf9, 0xb4, 0x47, 0x1d,
+0x30, 0x6c, 0x44, 0xea, 0x29, 0x37, 0x85, 0x92, 0x68, 0x66, 0xbc, 0x83, 0x38, 0xfe, 0x7b, 0x39,
+0x2e, 0xd3, 0x50, 0xf0, 0x1f, 0xfb, 0x5e, 0x60, 0xb6, 0xa9, 0xa6, 0xfa, 0x27, 0x41, 0xf1, 0x9b,
+0x18, 0x72, 0xf2, 0xf5, 0x84, 0x74, 0x4a, 0xc9, 0x67, 0xc4, 0x54, 0xae, 0x48, 0x64, 0xdf, 0x8c,
+0xd1, 0x6e, 0xb0, 0x1d, 0xe1, 0x07, 0x8f, 0x08, 0x1e, 0x99, 0x9c, 0x71, 0xe9, 0x4c, 0xd8, 0xa5,
+0xf7, 0x47, 0x12, 0x1f, 0x74, 0xd1, 0x51, 0x9e, 0x86, 0xf3, 0xc2, 0xa2, 0x23, 0x40, 0x0b, 0x73,
+0xdb, 0x4b, 0xa6, 0xe7, 0x73, 0x06, 0x8c, 0xc1, 0xa0, 0xe9, 0xc1, 0x59, 0xac, 0x46, 0xfa, 0xe6,
+0x2f, 0xf8, 0xcf, 0x71, 0x9c, 0x46, 0x6d, 0xb9, 0xc4, 0x15, 0x8d, 0x38, 0x79, 0x03, 0x45, 0x48,
+0xef, 0xc4, 0x5d, 0xd7, 0x08, 0xee, 0x87, 0x39, 0x22, 0x86, 0xb2, 0x0d, 0x0f, 0x58, 0x43, 0xf7,
+0x71, 0xa9, 0x48, 0x2e, 0xfd, 0xea, 0xd6, 0x1f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xac,
+0x30, 0x81, 0xa9, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x17,
+0xa0, 0xcd, 0xc1, 0xe4, 0x41, 0xb6, 0x3a, 0x5b, 0x3b, 0xcb, 0x45, 0x9d, 0xbd, 0x1c, 0xc2, 0x98,
+0xfa, 0x86, 0x58, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+0x17, 0xa0, 0xcd, 0xc1, 0xe4, 0x41, 0xb6, 0x3a, 0x5b, 0x3b, 0xcb, 0x45, 0x9d, 0xbd, 0x1c, 0xc2,
+0x98, 0xfa, 0x86, 0x58, 0x30, 0x46, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30,
+0x3b, 0x06, 0x09, 0x60, 0x85, 0x74, 0x01, 0x59, 0x01, 0x03, 0x01, 0x01, 0x30, 0x2e, 0x30, 0x2c,
+0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x20, 0x68, 0x74, 0x74, 0x70,
+0x3a, 0x2f, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x73, 0x77,
+0x69, 0x73, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00,
+0x73, 0xc6, 0x81, 0xe0, 0x27, 0xd2, 0x2d, 0x0f, 0xe0, 0x95, 0x30, 0xe2, 0x9a, 0x41, 0x7f, 0x50,
+0x2c, 0x5f, 0x5f, 0x62, 0x61, 0xa9, 0x86, 0x6a, 0x69, 0x18, 0x0c, 0x74, 0x49, 0xd6, 0x5d, 0x84,
+0xea, 0x41, 0x52, 0x18, 0x6f, 0x58, 0xad, 0x50, 0x56, 0x20, 0x6a, 0xc6, 0xbd, 0x28, 0x69, 0x58,
+0x91, 0xdc, 0x91, 0x11, 0x35, 0xa9, 0x3a, 0x1d, 0xbc, 0x1a, 0xa5, 0x60, 0x9e, 0xd8, 0x1f, 0x7f,
+0x45, 0x91, 0x69, 0xd9, 0x7e, 0xbb, 0x78, 0x72, 0xc1, 0x06, 0x0f, 0x2a, 0xce, 0x8f, 0x85, 0x70,
+0x61, 0xac, 0xa0, 0xcd, 0x0b, 0xb8, 0x39, 0x29, 0x56, 0x84, 0x32, 0x4e, 0x86, 0xbb, 0x3d, 0xc4,
+0x2a, 0xd9, 0xd7, 0x1f, 0x72, 0xee, 0xfe, 0x51, 0xa1, 0x22, 0x41, 0xb1, 0x71, 0x02, 0x63, 0x1a,
+0x82, 0xb0, 0x62, 0xab, 0x5e, 0x57, 0x12, 0x1f, 0xdf, 0xcb, 0xdd, 0x75, 0xa0, 0xc0, 0x5d, 0x79,
+0x90, 0x8c, 0x1b, 0xe0, 0x50, 0xe6, 0xde, 0x31, 0xfe, 0x98, 0x7b, 0x70, 0x5f, 0xa5, 0x90, 0xd8,
+0xad, 0xf8, 0x02, 0xb6, 0x6f, 0xd3, 0x60, 0xdd, 0x40, 0x4b, 0x22, 0xc5, 0x3d, 0xad, 0x3a, 0x7a,
+0x9f, 0x1a, 0x1a, 0x47, 0x91, 0x79, 0x33, 0xba, 0x82, 0xdc, 0x32, 0x69, 0x03, 0x96, 0x6e, 0x1f,
+0x4b, 0xf0, 0x71, 0xfe, 0xe3, 0x67, 0x72, 0xa0, 0xb1, 0xbf, 0x5c, 0x8b, 0xe4, 0xfa, 0x99, 0x22,
+0xc7, 0x84, 0xb9, 0x1b, 0x8d, 0x23, 0x97, 0x3f, 0xed, 0x25, 0xe0, 0xcf, 0x65, 0xbb, 0xf5, 0x61,
+0x04, 0xef, 0xdd, 0x1e, 0xb2, 0x5a, 0x41, 0x22, 0x5a, 0xa1, 0x9f, 0x5d, 0x2c, 0xe8, 0x5b, 0xc9,
+0x6d, 0xa9, 0x0c, 0x0c, 0x78, 0xaa, 0x60, 0xc6, 0x56, 0x8f, 0x01, 0x5a, 0x0c, 0x68, 0xbc, 0x69,
+0x19, 0x79, 0xc4, 0x1f, 0x7e, 0x97, 0x05, 0xbf, 0xc5, 0xe9, 0x24, 0x51, 0x5e, 0xd4, 0xd5, 0x4b,
+0x53, 0xed, 0xd9, 0x23, 0x5a, 0x36, 0x03, 0x65, 0xa3, 0xc1, 0x03, 0xad, 0x41, 0x30, 0xf3, 0x46,
+0x1b, 0x85, 0x90, 0xaf, 0x65, 0xb5, 0xd5, 0xb1, 0xe4, 0x16, 0x5b, 0x78, 0x75, 0x1d, 0x97, 0x7a,
+0x6d, 0x59, 0xa9, 0x2a, 0x8f, 0x7b, 0xde, 0xc3, 0x87, 0x89, 0x10, 0x99, 0x49, 0x73, 0x78, 0xc8,
+0x3d, 0xbd, 0x51, 0x35, 0x74, 0x2a, 0xd5, 0xf1, 0x7e, 0x69, 0x1b, 0x2a, 0xbb, 0x3b, 0xbd, 0x25,
+0xb8, 0x9a, 0x5a, 0x3d, 0x72, 0x61, 0x90, 0x66, 0x87, 0xee, 0x0c, 0xd6, 0x4d, 0xd4, 0x11, 0x74,
+0x0b, 0x6a, 0xfe, 0x0b, 0x03, 0xfc, 0xa3, 0x55, 0x57, 0x89, 0xfe, 0x4a, 0xcb, 0xae, 0x5b, 0x17,
+0x05, 0xc8, 0xf2, 0x8d, 0x23, 0x31, 0x53, 0x38, 0xd2, 0x2d, 0x6a, 0x3f, 0x82, 0xb9, 0x8d, 0x08,
+0x6a, 0xf7, 0x5e, 0x41, 0x74, 0x6e, 0xc3, 0x11, 0x7e, 0x07, 0xac, 0x29, 0x60, 0x91, 0x3f, 0x38,
+0xca, 0x57, 0x10, 0x0d, 0xbd, 0x30, 0x2f, 0xc7, 0xa5, 0xe6, 0x41, 0xa0, 0xda, 0xae, 0x05, 0x87,
+0x9a, 0xa0, 0xa4, 0x65, 0x6c, 0x4c, 0x09, 0x0c, 0x89, 0xba, 0xb8, 0xd3, 0xb9, 0xc0, 0x93, 0x8a,
+0x30, 0xfa, 0x8d, 0xe5, 0x9a, 0x6b, 0x15, 0x01, 0x4e, 0x67, 0xaa, 0xda, 0x62, 0x56, 0x3e, 0x84,
+0x08, 0x66, 0xd2, 0xc4, 0x36, 0x7d, 0xa7, 0x3e, 0x10, 0xfc, 0x88, 0xe0, 0xd4, 0x80, 0xe5, 0x00,
+0xbd, 0xaa, 0xf3, 0x4e, 0x06, 0xa3, 0x7a, 0x6a, 0xf9, 0x62, 0x72, 0xe3, 0x09, 0x4f, 0xeb, 0x9b,
+0x0e, 0x01, 0x23, 0xf1, 0x9f, 0xbb, 0x7c, 0xdc, 0xdc, 0x6c, 0x11, 0x97, 0x25, 0xb2, 0xf2, 0xb4,
+0x63, 0x14, 0xd2, 0x06, 0x2a, 0x67, 0x8c, 0x83, 0xf5, 0xce, 0xea, 0x07, 0xd8, 0x9a, 0x6a, 0x1e,
+0xec, 0xe4, 0x0a, 0xbb, 0x2a, 0x4c, 0xeb, 0x09, 0x60, 0x39, 0xce, 0xca, 0x62, 0xd8, 0x2e, 0x6e,
+0x30, 0x82, 0x04, 0x30, 0x30, 0x82, 0x03, 0x18, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x50,
+0x94, 0x6c, 0xec, 0x18, 0xea, 0xd5, 0x9c, 0x4d, 0xd5, 0x97, 0xef, 0x75, 0x8f, 0xa0, 0xad, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
+0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1e,
+0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x77, 0x77, 0x77, 0x2e, 0x78, 0x72, 0x61,
+0x6d, 0x70, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x24,
+0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1b, 0x58, 0x52, 0x61, 0x6d, 0x70, 0x20, 0x53,
+0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
+0x20, 0x49, 0x6e, 0x63, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x58,
+0x52, 0x61, 0x6d, 0x70, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74,
+0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x34, 0x31, 0x31, 0x30, 0x31, 0x31, 0x37, 0x31,
+0x34, 0x30, 0x34, 0x5a, 0x17, 0x0d, 0x33, 0x35, 0x30, 0x31, 0x30, 0x31, 0x30, 0x35, 0x33, 0x37,
+0x31, 0x39, 0x5a, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+0x02, 0x55, 0x53, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x77, 0x77,
+0x77, 0x2e, 0x78, 0x72, 0x61, 0x6d, 0x70, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2e,
+0x63, 0x6f, 0x6d, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1b, 0x58, 0x52,
+0x61, 0x6d, 0x70, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x53, 0x65, 0x72,
+0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55,
+0x04, 0x03, 0x13, 0x24, 0x58, 0x52, 0x61, 0x6d, 0x70, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
+0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
+0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x98, 0x24, 0x1e, 0xbd, 0x15, 0xb4, 0xba,
+0xdf, 0xc7, 0x8c, 0xa5, 0x27, 0xb6, 0x38, 0x0b, 0x69, 0xf3, 0xb6, 0x4e, 0xa8, 0x2c, 0x2e, 0x21,
+0x1d, 0x5c, 0x44, 0xdf, 0x21, 0x5d, 0x7e, 0x23, 0x74, 0xfe, 0x5e, 0x7e, 0xb4, 0x4a, 0xb7, 0xa6,
+0xad, 0x1f, 0xae, 0xe0, 0x06, 0x16, 0xe2, 0x9b, 0x5b, 0xd9, 0x67, 0x74, 0x6b, 0x5d, 0x80, 0x8f,
+0x29, 0x9d, 0x86, 0x1b, 0xd9, 0x9c, 0x0d, 0x98, 0x6d, 0x76, 0x10, 0x28, 0x58, 0xe4, 0x65, 0xb0,
+0x7f, 0x4a, 0x98, 0x79, 0x9f, 0xe0, 0xc3, 0x31, 0x7e, 0x80, 0x2b, 0xb5, 0x8c, 0xc0, 0x40, 0x3b,
+0x11, 0x86, 0xd0, 0xcb, 0xa2, 0x86, 0x36, 0x60, 0xa4, 0xd5, 0x30, 0x82, 0x6d, 0xd9, 0x6e, 0xd0,
+0x0f, 0x12, 0x04, 0x33, 0x97, 0x5f, 0x4f, 0x61, 0x5a, 0xf0, 0xe4, 0xf9, 0x91, 0xab, 0xe7, 0x1d,
+0x3b, 0xbc, 0xe8, 0xcf, 0xf4, 0x6b, 0x2d, 0x34, 0x7c, 0xe2, 0x48, 0x61, 0x1c, 0x8e, 0xf3, 0x61,
+0x44, 0xcc, 0x6f, 0xa0, 0x4a, 0xa9, 0x94, 0xb0, 0x4d, 0xda, 0xe7, 0xa9, 0x34, 0x7a, 0x72, 0x38,
+0xa8, 0x41, 0xcc, 0x3c, 0x94, 0x11, 0x7d, 0xeb, 0xc8, 0xa6, 0x8c, 0xb7, 0x86, 0xcb, 0xca, 0x33,
+0x3b, 0xd9, 0x3d, 0x37, 0x8b, 0xfb, 0x7a, 0x3e, 0x86, 0x2c, 0xe7, 0x73, 0xd7, 0x0a, 0x57, 0xac,
+0x64, 0x9b, 0x19, 0xeb, 0xf4, 0x0f, 0x04, 0x08, 0x8a, 0xac, 0x03, 0x17, 0x19, 0x64, 0xf4, 0x5a,
+0x25, 0x22, 0x8d, 0x34, 0x2c, 0xb2, 0xf6, 0x68, 0x1d, 0x12, 0x6d, 0xd3, 0x8a, 0x1e, 0x14, 0xda,
+0xc4, 0x8f, 0xa6, 0xe2, 0x23, 0x85, 0xd5, 0x7a, 0x0d, 0xbd, 0x6a, 0xe0, 0xe9, 0xec, 0xec, 0x17,
+0xbb, 0x42, 0x1b, 0x67, 0xaa, 0x25, 0xed, 0x45, 0x83, 0x21, 0xfc, 0xc1, 0xc9, 0x7c, 0xd5, 0x62,
+0x3e, 0xfa, 0xf2, 0xc5, 0x2d, 0xd3, 0xfd, 0xd4, 0x65, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
+0x9f, 0x30, 0x81, 0x9c, 0x30, 0x13, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14,
+0x02, 0x04, 0x06, 0x1e, 0x04, 0x00, 0x43, 0x00, 0x41, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+0x04, 0x14, 0xc6, 0x4f, 0xa2, 0x3d, 0x06, 0x63, 0x84, 0x09, 0x9c, 0xce, 0x62, 0xe4, 0x04, 0xac,
+0x8d, 0x5c, 0xb5, 0xe9, 0xb6, 0x1b, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2f, 0x30,
+0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, 0x86, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+0x63, 0x72, 0x6c, 0x2e, 0x78, 0x72, 0x61, 0x6d, 0x70, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
+0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x58, 0x47, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x10,
+0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x01,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
+0x82, 0x01, 0x01, 0x00, 0x91, 0x15, 0x39, 0x03, 0x01, 0x1b, 0x67, 0xfb, 0x4a, 0x1c, 0xf9, 0x0a,
+0x60, 0x5b, 0xa1, 0xda, 0x4d, 0x97, 0x62, 0xf9, 0x24, 0x53, 0x27, 0xd7, 0x82, 0x64, 0x4e, 0x90,
+0x2e, 0xc3, 0x49, 0x1b, 0x2b, 0x9a, 0xdc, 0xfc, 0xa8, 0x78, 0x67, 0x35, 0xf1, 0x1d, 0xf0, 0x11,
+0xbd, 0xb7, 0x48, 0xe3, 0x10, 0xf6, 0x0d, 0xdf, 0x3f, 0xd2, 0xc9, 0xb6, 0xaa, 0x55, 0xa4, 0x48,
+0xba, 0x02, 0xdb, 0xde, 0x59, 0x2e, 0x15, 0x5b, 0x3b, 0x9d, 0x16, 0x7d, 0x47, 0xd7, 0x37, 0xea,
+0x5f, 0x4d, 0x76, 0x12, 0x36, 0xbb, 0x1f, 0xd7, 0xa1, 0x81, 0x04, 0x46, 0x20, 0xa3, 0x2c, 0x6d,
+0xa9, 0x9e, 0x01, 0x7e, 0x3f, 0x29, 0xce, 0x00, 0x93, 0xdf, 0xfd, 0xc9, 0x92, 0x73, 0x89, 0x89,
+0x64, 0x9e, 0xe7, 0x2b, 0xe4, 0x1c, 0x91, 0x2c, 0xd2, 0xb9, 0xce, 0x7d, 0xce, 0x6f, 0x31, 0x99,
+0xd3, 0xe6, 0xbe, 0xd2, 0x1e, 0x90, 0xf0, 0x09, 0x14, 0x79, 0x5c, 0x23, 0xab, 0x4d, 0xd2, 0xda,
+0x21, 0x1f, 0x4d, 0x99, 0x79, 0x9d, 0xe1, 0xcf, 0x27, 0x9f, 0x10, 0x9b, 0x1c, 0x88, 0x0d, 0xb0,
+0x8a, 0x64, 0x41, 0x31, 0xb8, 0x0e, 0x6c, 0x90, 0x24, 0xa4, 0x9b, 0x5c, 0x71, 0x8f, 0xba, 0xbb,
+0x7e, 0x1c, 0x1b, 0xdb, 0x6a, 0x80, 0x0f, 0x21, 0xbc, 0xe9, 0xdb, 0xa6, 0xb7, 0x40, 0xf4, 0xb2,
+0x8b, 0xa9, 0xb1, 0xe4, 0xef, 0x9a, 0x1a, 0xd0, 0x3d, 0x69, 0x99, 0xee, 0xa8, 0x28, 0xa3, 0xe1,
+0x3c, 0xb3, 0xf0, 0xb2, 0x11, 0x9c, 0xcf, 0x7c, 0x40, 0xe6, 0xdd, 0xe7, 0x43, 0x7d, 0xa2, 0xd8,
+0x3a, 0xb5, 0xa9, 0x8d, 0xf2, 0x34, 0x99, 0xc4, 0xd4, 0x10, 0xe1, 0x06, 0xfd, 0x09, 0x84, 0x10,
+0x3b, 0xee, 0xc4, 0x4c, 0xf4, 0xec, 0x27, 0x7c, 0x42, 0xc2, 0x74, 0x7c, 0x82, 0x8a, 0x09, 0xc9,
+0xb4, 0x03, 0x25, 0xbc, 0x30, 0x82, 0x01, 0xe1, 0x30, 0x82, 0x01, 0x87, 0xa0, 0x03, 0x02, 0x01,
+0x02, 0x02, 0x11, 0x2a, 0x38, 0xa4, 0x1c, 0x96, 0x0a, 0x04, 0xde, 0x42, 0xb2, 0x28, 0xa5, 0x0b,
+0xe8, 0x34, 0x98, 0x02, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+0x30, 0x50, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1b, 0x47, 0x6c, 0x6f,
+0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x34, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x31, 0x13, 0x30,
+0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69,
+0x67, 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31, 0x31, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31, 0x39, 0x30, 0x33, 0x31, 0x34, 0x30,
+0x37, 0x5a, 0x30, 0x50, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1b, 0x47,
+0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x34, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x31,
+0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+0x53, 0x69, 0x67, 0x6e, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xb8,
+0xc6, 0x79, 0xd3, 0x8f, 0x6c, 0x25, 0x0e, 0x9f, 0x2e, 0x39, 0x19, 0x1c, 0x03, 0xa4, 0xae, 0x9a,
+0xe5, 0x39, 0x07, 0x09, 0x16, 0xca, 0x63, 0xb1, 0xb9, 0x86, 0xf8, 0x8a, 0x57, 0xc1, 0x57, 0xce,
+0x42, 0xfa, 0x73, 0xa1, 0xf7, 0x65, 0x42, 0xff, 0x1e, 0xc1, 0x00, 0xb2, 0x6e, 0x73, 0x0e, 0xff,
+0xc7, 0x21, 0xe5, 0x18, 0xa4, 0xaa, 0xd9, 0x71, 0x3f, 0xa8, 0xd4, 0xb9, 0xce, 0x8c, 0x1d, 0xa3,
+0x42, 0x30, 0x40, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x54,
+0xb0, 0x7b, 0xad, 0x45, 0xb8, 0xe2, 0x40, 0x7f, 0xfb, 0x0a, 0x6e, 0xfb, 0xbe, 0x33, 0xc9, 0x3c,
+0xa3, 0x84, 0xd5, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03,
+0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xdc, 0x92, 0xa1, 0xa0, 0x13, 0xa6, 0xcf, 0x03, 0xb0,
+0xe6, 0xc4, 0x21, 0x97, 0x90, 0xfa, 0x14, 0x57, 0x2d, 0x03, 0xec, 0xee, 0x3c, 0xd3, 0x6e, 0xca,
+0xa8, 0x6c, 0x76, 0xbc, 0xa2, 0xde, 0xbb, 0x02, 0x20, 0x27, 0xa8, 0x85, 0x27, 0x35, 0x9b, 0x56,
+0xc6, 0xa3, 0xf2, 0x47, 0xd2, 0xb7, 0x6e, 0x1b, 0x02, 0x00, 0x17, 0xaa, 0x67, 0xa6, 0x15, 0x91,
+0xde, 0xfa, 0x94, 0xec, 0x7b, 0x0b, 0xf8, 0x9f, 0x84, 0x30, 0x82, 0x06, 0x4b, 0x30, 0x82, 0x04,
+0x33, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 0xd9, 0xb5, 0x43, 0x7f, 0xaf, 0xa9, 0x39,
+0x0f, 0x00, 0x00, 0x00, 0x00, 0x55, 0x65, 0xad, 0x58, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xbe, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
+0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x65, 0x20, 0x77,
+0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x6c,
+0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06, 0x03,
+0x55, 0x04, 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x35, 0x20, 0x45, 0x6e,
+0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66, 0x6f,
+0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73, 0x65,
+0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x29,
+0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72,
+0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
+0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30,
+0x35, 0x32, 0x37, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x32,
+0x32, 0x37, 0x31, 0x31, 0x34, 0x31, 0x31, 0x36, 0x5a, 0x30, 0x81, 0xbe, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x0d, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+0x2e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x53, 0x65, 0x65, 0x20,
+0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
+0x6c, 0x65, 0x67, 0x61, 0x6c, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x31, 0x39, 0x30, 0x37, 0x06,
+0x03, 0x55, 0x04, 0x0b, 0x13, 0x30, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x35, 0x20, 0x45,
+0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x66,
+0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x20, 0x75, 0x73,
+0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+0x29, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65,
+0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47, 0x34, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d,
+0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02,
+0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb1, 0xec, 0x2c, 0x42, 0xee,
+0xe2, 0xd1, 0x30, 0xff, 0xa5, 0x92, 0x47, 0xe2, 0x2d, 0xc3, 0xba, 0x64, 0x97, 0x6d, 0xca, 0xf7,
+0x0d, 0xb5, 0x59, 0xc1, 0xb3, 0xcb, 0xa8, 0x68, 0x19, 0xd8, 0xaf, 0x84, 0x6d, 0x30, 0x70, 0x5d,
+0x7e, 0xf3, 0x2e, 0xd2, 0x53, 0x99, 0xe1, 0xfe, 0x1f, 0x5e, 0xd9, 0x48, 0xaf, 0x5d, 0x13, 0x8d,
+0xdb, 0xff, 0x63, 0x33, 0x4d, 0xd3, 0x00, 0x02, 0xbc, 0xc4, 0xf8, 0xd1, 0x06, 0x08, 0x94, 0x79,
+0x58, 0x8a, 0x15, 0xde, 0x29, 0xb3, 0xfd, 0xfd, 0xc4, 0x4f, 0xe8, 0xaa, 0xe2, 0xa0, 0x3b, 0x79,
+0xcd, 0xbf, 0x6b, 0x43, 0x32, 0xdd, 0xd9, 0x74, 0x10, 0xb9, 0xf7, 0xf4, 0x68, 0xd4, 0xbb, 0xd0,
+0x87, 0xd5, 0xaa, 0x4b, 0x8a, 0x2a, 0x6f, 0x2a, 0x04, 0xb5, 0xb2, 0xa6, 0xc7, 0xa0, 0x7a, 0xe6,
+0x48, 0xab, 0xd2, 0xd1, 0x59, 0xcc, 0xd6, 0x7e, 0x23, 0xe6, 0x97, 0x6c, 0xf0, 0x42, 0xe5, 0xdc,
+0x51, 0x4b, 0x15, 0x41, 0xed, 0x49, 0x4a, 0xc9, 0xde, 0x10, 0x97, 0xd6, 0x76, 0xc1, 0xef, 0xa5,
+0xb5, 0x36, 0x14, 0x97, 0x35, 0xd8, 0x78, 0x22, 0x35, 0x52, 0xef, 0x43, 0xbd, 0xdb, 0x27, 0xdb,
+0x61, 0x56, 0x82, 0x34, 0xdc, 0xcb, 0x88, 0x60, 0x0c, 0x0b, 0x5a, 0xe5, 0x2c, 0x01, 0xc6, 0x54,
+0xaf, 0xd7, 0xaa, 0xc1, 0x10, 0x7b, 0xd2, 0x05, 0x5a, 0xb8, 0x40, 0x9e, 0x86, 0xa7, 0xc3, 0x90,
+0x86, 0x02, 0x56, 0x52, 0x09, 0x7a, 0x9c, 0xd2, 0x27, 0x82, 0x53, 0x4a, 0x65, 0x52, 0x6a, 0xf5,
+0x3c, 0xe7, 0xa8, 0xf2, 0x9c, 0xaf, 0x8b, 0xbd, 0xd3, 0x0e, 0xd4, 0xd4, 0x5e, 0x6e, 0x87, 0x9e,
+0x6a, 0x3d, 0x45, 0x1d, 0xd1, 0x5d, 0x1b, 0xf4, 0xe9, 0x0a, 0xac, 0x60, 0x99, 0xfb, 0x89, 0xb4,
+0xff, 0x98, 0x2c, 0xcf, 0x7c, 0x1d, 0xe9, 0x02, 0xaa, 0x04, 0x9a, 0x1e, 0xb8, 0xdc, 0x88, 0x6e,
+0x25, 0xb3, 0x6c, 0x66, 0xf7, 0x3c, 0x90, 0xf3, 0x57, 0xc1, 0xb3, 0x2f, 0xf5, 0x6d, 0xf2, 0xfb,
+0xca, 0xa1, 0xf8, 0x29, 0x9d, 0x46, 0x8b, 0xb3, 0x6a, 0xf6, 0xe6, 0x67, 0x07, 0xbe, 0x2c, 0x67,
+0x0a, 0x2a, 0x1f, 0x5a, 0xb2, 0x3e, 0x57, 0xc4, 0xd3, 0x21, 0x21, 0x63, 0x65, 0x52, 0x91, 0x1b,
+0xb1, 0x99, 0x8e, 0x79, 0x7e, 0xe6, 0xeb, 0x8d, 0x00, 0xd9, 0x5a, 0xaa, 0xea, 0x73, 0xe8, 0xa4,
+0x82, 0x02, 0x47, 0x96, 0xfe, 0x5b, 0x8e, 0x54, 0x61, 0xa3, 0xeb, 0x2f, 0x4b, 0x30, 0xb0, 0x8b,
+0x23, 0x75, 0x72, 0x7c, 0x21, 0x3c, 0xc8, 0xf6, 0xf1, 0x74, 0xd4, 0x1c, 0x7b, 0xa3, 0x05, 0x55,
+0xee, 0xbb, 0x4d, 0x3b, 0x32, 0xbe, 0x9a, 0x77, 0x66, 0x9e, 0xac, 0x69, 0x90, 0x22, 0x07, 0x1f,
+0x61, 0x3a, 0x96, 0xbe, 0xe5, 0x9a, 0x4f, 0xcc, 0x05, 0x3c, 0x28, 0x59, 0xd3, 0xc1, 0x0c, 0x54,
+0xa8, 0x59, 0x61, 0xbd, 0xc8, 0x72, 0x4c, 0xe8, 0xdc, 0x9f, 0x87, 0x7f, 0xbd, 0x9c, 0x48, 0x36,
+0x5e, 0x95, 0xa3, 0x0e, 0xb9, 0x38, 0x24, 0x55, 0xfc, 0x75, 0x66, 0xeb, 0x02, 0xe3, 0x08, 0x34,
+0x29, 0x4a, 0xc6, 0xe3, 0x2b, 0x2f, 0x33, 0xa0, 0xda, 0xa3, 0x86, 0xa5, 0x12, 0x97, 0xfd, 0x80,
+0x2b, 0xda, 0x14, 0x42, 0xe3, 0x92, 0xbd, 0x3e, 0xf2, 0x5d, 0x5e, 0x67, 0x74, 0x2e, 0x1c, 0x88,
+0x47, 0x29, 0x34, 0x5f, 0xe2, 0x32, 0xa8, 0x9c, 0x25, 0x37, 0x8c, 0xba, 0x98, 0x00, 0x97, 0x8b,
+0x49, 0x96, 0x1e, 0xfd, 0x25, 0x8a, 0xac, 0xdc, 0xda, 0xd8, 0x5d, 0x74, 0x6e, 0x66, 0xb0, 0xff,
+0x44, 0xdf, 0xa1, 0x18, 0xc6, 0xbe, 0x48, 0x2f, 0x37, 0x94, 0x78, 0xf8, 0x95, 0x4a, 0x3f, 0x7f,
+0x13, 0x5e, 0x5d, 0x59, 0xfd, 0x74, 0x86, 0x43, 0x63, 0x73, 0x49, 0x02, 0x03, 0x01, 0x00, 0x01,
+0xa3, 0x42, 0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05,
+0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+0x9f, 0x38, 0xc4, 0x56, 0x23, 0xc3, 0x39, 0xe8, 0xa0, 0x71, 0x6c, 0xe8, 0x54, 0x4c, 0xe4, 0xe8,
+0x3a, 0xb1, 0xbf, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x12, 0xe5, 0x42, 0xa6, 0x7b, 0x8b, 0x0f, 0x0c,
+0xe4, 0x46, 0xa5, 0xb6, 0x60, 0x40, 0x87, 0x8c, 0x25, 0x7e, 0xad, 0xb8, 0x68, 0x2e, 0x5b, 0xc6,
+0x40, 0x76, 0x3c, 0x03, 0xf8, 0xc9, 0x59, 0xf4, 0xf3, 0xab, 0x62, 0xce, 0x10, 0x8d, 0xb4, 0x5a,
+0x64, 0x8c, 0x68, 0xc0, 0xb0, 0x72, 0x43, 0x34, 0xd2, 0x1b, 0x0b, 0xf6, 0x2c, 0x53, 0xd2, 0xca,
+0x90, 0x4b, 0x86, 0x66, 0xfc, 0xaa, 0x83, 0x22, 0xf4, 0x8b, 0x1a, 0x6f, 0x26, 0x48, 0xac, 0x76,
+0x77, 0x08, 0xbf, 0xc5, 0x98, 0x5c, 0xf4, 0x26, 0x89, 0x9e, 0x7b, 0xc3, 0xb9, 0x64, 0x32, 0x01,
+0x7f, 0xd3, 0xc3, 0xdd, 0x58, 0x6d, 0xec, 0xb1, 0xab, 0x84, 0x55, 0x74, 0x77, 0x84, 0x04, 0x27,
+0x52, 0x6b, 0x86, 0x4c, 0xce, 0xdd, 0xb9, 0x65, 0xff, 0xd6, 0xc6, 0x5e, 0x9f, 0x9a, 0x10, 0x99,
+0x4b, 0x75, 0x6a, 0xfe, 0x6a, 0xe9, 0x97, 0x20, 0xe4, 0xe4, 0x76, 0x7a, 0xc6, 0xd0, 0x24, 0xaa,
+0x90, 0xcd, 0x20, 0x90, 0xba, 0x47, 0x64, 0xfb, 0x7f, 0x07, 0xb3, 0x53, 0x78, 0xb5, 0x0a, 0x62,
+0xf2, 0x73, 0x43, 0xce, 0x41, 0x2b, 0x81, 0x6a, 0x2e, 0x85, 0x16, 0x94, 0x53, 0xd4, 0x6b, 0x5f,
+0x72, 0x22, 0xab, 0x51, 0x2d, 0x42, 0xd5, 0x00, 0x9c, 0x99, 0xbf, 0xde, 0xbb, 0x94, 0x3b, 0x57,
+0xfd, 0x9a, 0xf5, 0x86, 0xcb, 0x56, 0x3b, 0x5b, 0x88, 0x01, 0xe5, 0x7c, 0x28, 0x4b, 0x03, 0xf9,
+0x49, 0x83, 0x7c, 0xb2, 0x7f, 0x7c, 0xe3, 0xed, 0x8e, 0xa1, 0x7f, 0x60, 0x53, 0x8e, 0x55, 0x9d,
+0x50, 0x34, 0x12, 0x0f, 0xb7, 0x97, 0x7b, 0x6c, 0x87, 0x4a, 0x44, 0xe7, 0xf5, 0x6d, 0xec, 0x80,
+0x37, 0xf0, 0x58, 0x19, 0x6e, 0x4a, 0x68, 0x76, 0xf0, 0x1f, 0x92, 0xe4, 0xea, 0xb5, 0x92, 0xd3,
+0x61, 0x51, 0x10, 0x0b, 0xad, 0xa7, 0xd9, 0x5f, 0xc7, 0x5f, 0xdc, 0x1f, 0xa3, 0x5c, 0x8c, 0xa1,
+0x7e, 0x9b, 0xb7, 0x9e, 0xd3, 0x56, 0x6f, 0x66, 0x5e, 0x07, 0x96, 0x20, 0xed, 0x0b, 0x74, 0xfb,
+0x66, 0x4e, 0x8b, 0x11, 0x15, 0xe9, 0x81, 0x49, 0x7e, 0x6f, 0xb0, 0xd4, 0x50, 0x7f, 0x22, 0xd7,
+0x5f, 0x65, 0x02, 0x0d, 0xa6, 0xf4, 0x85, 0x1e, 0xd8, 0xae, 0x06, 0x4b, 0x4a, 0xa7, 0xd2, 0x31,
+0x66, 0xc2, 0xf8, 0xce, 0xe5, 0x08, 0xa6, 0xa4, 0x02, 0x96, 0x44, 0x68, 0x57, 0xc4, 0xd5, 0x33,
+0xcf, 0x19, 0x2f, 0x14, 0xc4, 0x94, 0x1c, 0x7b, 0xa4, 0xd9, 0xf0, 0x9f, 0x0e, 0xb1, 0x80, 0xe2,
+0xd1, 0x9e, 0x11, 0x64, 0xa9, 0x88, 0x11, 0x3a, 0x76, 0x82, 0xe5, 0x62, 0xc2, 0x80, 0xd8, 0xa4,
+0x83, 0xed, 0x93, 0xef, 0x7c, 0x2f, 0x90, 0xb0, 0x32, 0x4c, 0x96, 0x15, 0x68, 0x48, 0x52, 0xd4,
+0x99, 0x08, 0xc0, 0x24, 0xe8, 0x1c, 0xe3, 0xb3, 0xa5, 0x21, 0x0e, 0x92, 0xc0, 0x90, 0x1f, 0xcf,
+0x20, 0x5f, 0xca, 0x3b, 0x38, 0xc7, 0xb7, 0x6d, 0x3a, 0xf3, 0xe6, 0x44, 0xb8, 0x0e, 0x31, 0x6b,
+0x88, 0x8e, 0x70, 0xeb, 0x9c, 0x17, 0x52, 0xa8, 0x41, 0x94, 0x2e, 0x87, 0xb6, 0xe7, 0xa6, 0x12,
+0xc5, 0x75, 0xdf, 0x5b, 0xc0, 0x0a, 0x6e, 0x7b, 0xa4, 0xe4, 0x5e, 0x86, 0xf9, 0x36, 0x94, 0xdf,
+0x77, 0xc3, 0xe9, 0x0d, 0xc0, 0x39, 0xf1, 0x79, 0xbb, 0x46, 0x8e, 0xab, 0x43, 0x59, 0x27, 0xb7,
+0x20, 0xbb, 0x23, 0xe9, 0x56, 0x40, 0x21, 0xec, 0x31, 0x3d, 0x65, 0xaa, 0x43, 0xf2, 0x3d, 0xdf,
+0x70, 0x44, 0xe1, 0xba, 0x4d, 0x26, 0x10, 0x3b, 0x98, 0x9f, 0xf3, 0xc8, 0x8e, 0x1b, 0x38, 0x56,
+0x21, 0x6a, 0x51, 0x93, 0xd3, 0x91, 0xca, 0x46, 0xda, 0x89, 0xb7, 0x3d, 0x53, 0x83, 0x2c, 0x08,
+0x1f, 0x8b, 0x8f, 0x53, 0xdd, 0xff, 0xac, 0x1f, 0x30, 0x82, 0x03, 0x94, 0x30, 0x82, 0x02, 0x7c,
+0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x31, 0xf5, 0xe4, 0x62, 0x0c, 0x6c, 0x58, 0xed, 0xd6,
+0xd8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+0x30, 0x67, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4e, 0x31,
+0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e,
+0x20, 0x50, 0x4b, 0x49, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x65,
+0x4d, 0x75, 0x64, 0x68, 0x72, 0x61, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67,
+0x69, 0x65, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x1c, 0x30, 0x1a, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f,
+0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30,
+0x32, 0x31, 0x38, 0x31, 0x38, 0x33, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x33, 0x30, 0x32,
+0x31, 0x38, 0x31, 0x38, 0x33, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x67, 0x31, 0x0b, 0x30, 0x09, 0x06,
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+0x0b, 0x13, 0x0a, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x31, 0x25, 0x30,
+0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x65, 0x4d, 0x75, 0x64, 0x68, 0x72, 0x61, 0x20,
+0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20, 0x4c, 0x69, 0x6d,
+0x69, 0x74, 0x65, 0x64, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x65,
+0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20,
+0x47, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
+0x01, 0x01, 0x00, 0x93, 0x4b, 0xbb, 0xe9, 0x66, 0x8a, 0xee, 0x9d, 0x5b, 0xd5, 0x34, 0x93, 0xd0,
+0x1b, 0x1e, 0xc3, 0xe7, 0x9e, 0xb8, 0x64, 0x33, 0x7f, 0x63, 0x78, 0x68, 0xb4, 0xcd, 0x2e, 0x71,
+0x75, 0xd7, 0x9b, 0x20, 0xc6, 0x4d, 0x29, 0xbc, 0xb6, 0x68, 0x60, 0x8a, 0xf7, 0x21, 0x9a, 0x56,
+0x35, 0x5a, 0xf3, 0x76, 0xbd, 0xd8, 0xcd, 0x9a, 0xff, 0x93, 0x56, 0x4b, 0xa5, 0x59, 0x06, 0xa1,
+0x93, 0x34, 0x29, 0xdd, 0x16, 0x34, 0x75, 0x4e, 0xf2, 0x81, 0xb4, 0xc7, 0x96, 0x4e, 0xad, 0x19,
+0x15, 0x52, 0x4a, 0xfe, 0x3c, 0x70, 0x75, 0x70, 0xcd, 0xaf, 0x2b, 0xab, 0x15, 0x9a, 0x33, 0x3c,
+0xaa, 0xb3, 0x8b, 0xaa, 0xcd, 0x43, 0xfd, 0xf5, 0xea, 0x70, 0xff, 0xed, 0xcf, 0x11, 0x3b, 0x94,
+0xce, 0x4e, 0x32, 0x16, 0xd3, 0x23, 0x40, 0x2a, 0x77, 0xb3, 0xaf, 0x3c, 0x01, 0x2c, 0x6c, 0xed,
+0x99, 0x2c, 0x8b, 0xd9, 0x4e, 0x69, 0x98, 0xb2, 0xf7, 0x8f, 0x41, 0xb0, 0x32, 0x78, 0x61, 0xd6,
+0x0d, 0x5f, 0xc3, 0xfa, 0xa2, 0x40, 0x92, 0x1d, 0x5c, 0x17, 0xe6, 0x70, 0x3e, 0x35, 0xe7, 0xa2,
+0xb7, 0xc2, 0x62, 0xe2, 0xab, 0xa4, 0x38, 0x4c, 0xb5, 0x39, 0x35, 0x6f, 0xea, 0x03, 0x69, 0xfa,
+0x3a, 0x54, 0x68, 0x85, 0x6d, 0xd6, 0xf2, 0x2f, 0x43, 0x55, 0x1e, 0x91, 0x0d, 0x0e, 0xd8, 0xd5,
+0x6a, 0xa4, 0x96, 0xd1, 0x13, 0x3c, 0x2c, 0x78, 0x50, 0xe8, 0x3a, 0x92, 0xd2, 0x17, 0x56, 0xe5,
+0x35, 0x1a, 0x40, 0x1c, 0x3e, 0x8d, 0x2c, 0xed, 0x39, 0xdf, 0x42, 0xe0, 0x83, 0x41, 0x74, 0xdf,
+0xa3, 0xcd, 0xc2, 0x86, 0x60, 0x48, 0x68, 0xe3, 0x69, 0x0b, 0x54, 0x00, 0x8b, 0xe4, 0x76, 0x69,
+0x21, 0x0d, 0x79, 0x4e, 0x34, 0x08, 0x5e, 0x14, 0xc2, 0xcc, 0xb1, 0xb7, 0xad, 0xd7, 0x7c, 0x70,
+0x8a, 0xc7, 0x85, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03,
+0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xfb, 0xef, 0x0d, 0x86, 0x9e, 0xb0, 0xe3, 0xdd, 0xa9,
+0xb9, 0xf1, 0x21, 0x17, 0x7f, 0x3e, 0xfc, 0xf0, 0x77, 0x2b, 0x1a, 0x30, 0x0e, 0x06, 0x03, 0x55,
+0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55,
+0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+0x59, 0xff, 0xf2, 0x8c, 0xf5, 0x87, 0x7d, 0x71, 0x3d, 0xa3, 0x9f, 0x1b, 0x5b, 0xd1, 0xda, 0xf8,
+0xd3, 0x9c, 0x6b, 0x36, 0xbd, 0x9b, 0xa9, 0x61, 0xeb, 0xde, 0x16, 0x2c, 0x74, 0x3d, 0x9e, 0xe6,
+0x75, 0xda, 0xd7, 0xba, 0xa7, 0xbc, 0x42, 0x17, 0xe7, 0x3d, 0x91, 0xeb, 0xe5, 0x7d, 0xdd, 0x3e,
+0x9c, 0xf1, 0xcf, 0x92, 0xac, 0x6c, 0x48, 0xcc, 0xc2, 0x22, 0x3f, 0x69, 0x3b, 0xc5, 0xb6, 0x15,
+0x2f, 0xa3, 0x35, 0xc6, 0x68, 0x2a, 0x1c, 0x57, 0xaf, 0x39, 0xef, 0x8d, 0xd0, 0x35, 0xc3, 0x18,
+0x0c, 0x7b, 0x00, 0x56, 0x1c, 0xcd, 0x8b, 0x19, 0x74, 0xde, 0xbe, 0x0f, 0x12, 0xe0, 0xd0, 0xaa,
+0xa1, 0x3f, 0x02, 0x34, 0xb1, 0x70, 0xce, 0x9d, 0x18, 0xd6, 0x08, 0x03, 0x09, 0x46, 0xee, 0x60,
+0xe0, 0x7e, 0xb6, 0xc4, 0x49, 0x04, 0x51, 0x7d, 0x70, 0x60, 0xbc, 0xaa, 0xb2, 0xff, 0x79, 0x72,
+0x7a, 0xa6, 0x1d, 0x3d, 0x5f, 0x2a, 0xf8, 0xca, 0xe2, 0xfd, 0x39, 0xb7, 0x47, 0xb9, 0xeb, 0x7e,
+0xdf, 0x04, 0x23, 0xaf, 0xfa, 0x9c, 0x06, 0x07, 0xe9, 0xfb, 0x63, 0x93, 0x80, 0x40, 0xb5, 0xc6,
+0x6c, 0x0a, 0x31, 0x28, 0xce, 0x0c, 0x9f, 0xcf, 0xb3, 0x23, 0x35, 0x80, 0x41, 0x8d, 0x6c, 0xc4,
+0x37, 0x7b, 0x81, 0x2f, 0x80, 0xa1, 0x40, 0x42, 0x85, 0xe9, 0xd9, 0x38, 0x8d, 0xe8, 0xa1, 0x53,
+0xcd, 0x01, 0xbf, 0x69, 0xe8, 0x5a, 0x06, 0xf2, 0x45, 0x0b, 0x90, 0xfa, 0xae, 0xe1, 0xbf, 0x9d,
+0xf2, 0xae, 0x57, 0x3c, 0xa5, 0xae, 0xb2, 0x56, 0xf4, 0x8b, 0x65, 0x40, 0xe9, 0xfd, 0x31, 0x81,
+0x2c, 0xf4, 0x39, 0x09, 0xd8, 0xee, 0x6b, 0xa7, 0xb4, 0xa6, 0x1d, 0x15, 0xa5, 0x98, 0xf7, 0x01,
+0x81, 0xd8, 0x85, 0x7d, 0xf3, 0x51, 0x5c, 0x71, 0x88, 0xde, 0xba, 0xcc, 0x1f, 0x80, 0x7e, 0x4a,
+0x30, 0x82, 0x02, 0x4e, 0x30, 0x82, 0x01, 0xd3, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x3c,
+0xf6, 0x07, 0xa9, 0x68, 0x70, 0x0e, 0xda, 0x8b, 0x84, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
+0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+0x13, 0x02, 0x49, 0x4e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x65,
+0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55,
+0x04, 0x0a, 0x13, 0x1c, 0x65, 0x4d, 0x75, 0x64, 0x68, 0x72, 0x61, 0x20, 0x54, 0x65, 0x63, 0x68,
+0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64,
+0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x65, 0x6d, 0x53, 0x69, 0x67,
+0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20,
+0x47, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x32, 0x31, 0x38, 0x31, 0x38, 0x33, 0x30,
+0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x33, 0x30, 0x32, 0x31, 0x38, 0x31, 0x38, 0x33, 0x30, 0x30,
+0x30, 0x5a, 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49,
+0x4e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x65, 0x6d, 0x53, 0x69,
+0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+0x1c, 0x65, 0x4d, 0x75, 0x64, 0x68, 0x72, 0x61, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c,
+0x6f, 0x67, 0x69, 0x65, 0x73, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x20, 0x30,
+0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45,
+0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30,
+0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81,
+0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0x23, 0xa5, 0x0c, 0xb8, 0x2d, 0x12, 0xf5, 0x28, 0xf3,
+0xb1, 0xb2, 0xdd, 0xe2, 0x02, 0x12, 0x80, 0x9e, 0x39, 0x5f, 0x49, 0x4d, 0x9f, 0xc9, 0x25, 0x34,
+0x59, 0x74, 0xec, 0xbb, 0x06, 0x1c, 0xe7, 0xc0, 0x72, 0xaf, 0xe8, 0xae, 0x2f, 0xe1, 0x41, 0x54,
+0x87, 0x14, 0xa8, 0x4a, 0xb2, 0xe8, 0x7c, 0x82, 0xe6, 0x5b, 0x6a, 0xb5, 0xdc, 0xb3, 0x75, 0xce,
+0x8b, 0x06, 0xd0, 0x86, 0x23, 0xbf, 0x46, 0xd5, 0x8e, 0x0f, 0x3f, 0x04, 0xf4, 0xd7, 0x1c, 0x92,
+0x7e, 0xf6, 0xa5, 0x63, 0xc2, 0xf5, 0x5f, 0x8e, 0x2e, 0x4f, 0xa1, 0x18, 0x19, 0x02, 0x2b, 0x32,
+0x0a, 0x82, 0x64, 0x7d, 0x16, 0x93, 0xd1, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55,
+0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x7c, 0x5d, 0x02, 0x84, 0x13, 0xd4, 0xcc, 0x8a, 0x9b, 0x81,
+0xce, 0x17, 0x1c, 0x2e, 0x29, 0x1e, 0x9c, 0x48, 0x63, 0x42, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
+0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a,
+0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00, 0xbe,
+0xf3, 0x61, 0xcf, 0x02, 0x10, 0x1d, 0x64, 0x95, 0x07, 0xb8, 0x18, 0x6e, 0x88, 0x85, 0x05, 0x2f,
+0x83, 0x08, 0x17, 0x90, 0xca, 0x1f, 0x8a, 0x4c, 0xe8, 0x0d, 0x1b, 0x7a, 0xb1, 0xad, 0xd5, 0x81,
+0x09, 0x47, 0xef, 0x3b, 0xac, 0x08, 0x04, 0x7c, 0x5c, 0x99, 0xb1, 0xed, 0x47, 0x07, 0xd2, 0x02,
+0x31, 0x00, 0x9d, 0xba, 0x55, 0xfc, 0xa9, 0x4a, 0xe8, 0xed, 0xed, 0xe6, 0x76, 0x01, 0x42, 0x7b,
+0xc8, 0xf8, 0x60, 0xd9, 0x8d, 0x51, 0x8b, 0x55, 0x3b, 0xfb, 0x8c, 0x7b, 0xeb, 0x65, 0x09, 0xc3,
+0xf8, 0x96, 0xcd, 0x47, 0xa8, 0x82, 0xf2, 0x16, 0x55, 0x77, 0x24, 0x7e, 0x12, 0x10, 0x95, 0x04,
+0x2c, 0xa3, 0x30, 0x82, 0x03, 0x73, 0x30, 0x82, 0x02, 0x5b, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+0x0b, 0x00, 0xae, 0xcf, 0x00, 0xba, 0xc4, 0xcf, 0x32, 0xf8, 0x43, 0xb2, 0x30, 0x0d, 0x06, 0x09,
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x56, 0x31, 0x0b, 0x30,
+0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+0x55, 0x04, 0x0b, 0x13, 0x0a, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x31,
+0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x65, 0x4d, 0x75, 0x64, 0x68, 0x72,
+0x61, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13,
+0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d,
+0x20, 0x43, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x32, 0x31, 0x38, 0x31, 0x38, 0x33,
+0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x33, 0x30, 0x32, 0x31, 0x38, 0x31, 0x38, 0x33, 0x30,
+0x30, 0x30, 0x5a, 0x30, 0x56, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x65, 0x6d, 0x53,
+0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x13, 0x0b, 0x65, 0x4d, 0x75, 0x64, 0x68, 0x72, 0x61, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x1c, 0x30,
+0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52,
+0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x43, 0x31, 0x30, 0x82, 0x01, 0x22, 0x30,
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
+0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xcf, 0xeb, 0xa9, 0xb9,
+0xf1, 0x99, 0x05, 0xcc, 0xd8, 0x28, 0x21, 0x4a, 0xf3, 0x73, 0x34, 0x51, 0x84, 0x56, 0x10, 0xf5,
+0xa0, 0x4f, 0x2c, 0x12, 0xe3, 0xfa, 0x13, 0x9a, 0x27, 0xd0, 0xcf, 0xf9, 0x79, 0x1a, 0x74, 0x5f,
+0x1d, 0x79, 0x39, 0xfc, 0x5b, 0xf8, 0x70, 0x8e, 0xe0, 0x92, 0x52, 0xf7, 0xe4, 0x25, 0xf9, 0x54,
+0x83, 0xd9, 0x1d, 0xd3, 0xc8, 0x5a, 0x85, 0x3f, 0x5e, 0xc7, 0xb6, 0x07, 0xee, 0x3e, 0xc0, 0xce,
+0x9a, 0xaf, 0xac, 0x56, 0x42, 0x2a, 0x39, 0x25, 0x70, 0xd6, 0xbf, 0xb5, 0x7b, 0x36, 0xad, 0xac,
+0xf6, 0x73, 0xdc, 0xcd, 0xd7, 0x1d, 0x8a, 0x83, 0xa5, 0xfb, 0x2b, 0x90, 0x15, 0x37, 0x6b, 0x1c,
+0x26, 0x47, 0xdc, 0x3b, 0x29, 0x56, 0x93, 0x6a, 0xb3, 0xc1, 0x6a, 0x3a, 0x9d, 0x3d, 0xf5, 0xc1,
+0x97, 0x38, 0x58, 0x05, 0x8b, 0x1c, 0x11, 0xe3, 0xe4, 0xb4, 0xb8, 0x5d, 0x85, 0x1d, 0x83, 0xfe,
+0x78, 0x5f, 0x0b, 0x45, 0x68, 0x18, 0x48, 0xa5, 0x46, 0x73, 0x34, 0x3b, 0xfe, 0x0f, 0xc8, 0x76,
+0xbb, 0xc7, 0x18, 0xf3, 0x05, 0xd1, 0x86, 0xf3, 0x85, 0xed, 0xe7, 0xb9, 0xd9, 0x32, 0xad, 0x55,
+0x88, 0xce, 0xa6, 0xb6, 0x91, 0xb0, 0x4f, 0xac, 0x7e, 0x15, 0x23, 0x96, 0xf6, 0x3f, 0xf0, 0x20,
+0x34, 0x16, 0xde, 0x0a, 0xc6, 0xc4, 0x04, 0x45, 0x79, 0x7f, 0xa7, 0xfd, 0xbe, 0xd2, 0xa9, 0xa5,
+0xaf, 0x9c, 0xc5, 0x23, 0x2a, 0xf7, 0x3c, 0x21, 0x6c, 0xbd, 0xaf, 0x8f, 0x4e, 0xc5, 0x3a, 0xb2,
+0xf3, 0x34, 0x12, 0xfc, 0xdf, 0x80, 0x1a, 0x49, 0xa4, 0xd4, 0xa9, 0x95, 0xf7, 0x9e, 0x89, 0x5e,
+0xa2, 0x89, 0xac, 0x94, 0xcb, 0xa8, 0x68, 0x9b, 0xaf, 0x8a, 0x65, 0x27, 0xcd, 0x89, 0xee, 0xdd,
+0x8c, 0xb5, 0x6b, 0x29, 0x70, 0x43, 0xa0, 0x69, 0x0b, 0xe4, 0xb9, 0x0f, 0x02, 0x03, 0x01, 0x00,
+0x01, 0xa3, 0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+0xfe, 0xa1, 0xe0, 0x70, 0x1e, 0x2a, 0x03, 0x39, 0x52, 0x5a, 0x42, 0xbe, 0x5c, 0x91, 0x85, 0x7a,
+0x18, 0xaa, 0x4d, 0xb5, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
+0x03, 0x02, 0x01, 0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05,
+0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xc2, 0x4a, 0x56, 0xfa, 0x15, 0x21, 0x7b,
+0x28, 0xa2, 0xe9, 0xe5, 0x1d, 0xfb, 0xf8, 0x2d, 0xc4, 0x39, 0x96, 0x41, 0x4c, 0x3b, 0x27, 0x2c,
+0xc4, 0x6c, 0x18, 0x15, 0x80, 0xc6, 0xac, 0xaf, 0x47, 0x59, 0x2f, 0x26, 0x0b, 0xe3, 0x36, 0xb0,
+0xef, 0x3b, 0xfe, 0x43, 0x97, 0x49, 0x32, 0x99, 0x12, 0x15, 0x5b, 0xdf, 0x11, 0x29, 0xff, 0xab,
+0x53, 0xf8, 0xbb, 0xc1, 0x78, 0x0f, 0xac, 0x9c, 0x53, 0xaf, 0x57, 0xbd, 0x68, 0x8c, 0x3d, 0x69,
+0x33, 0xf0, 0xa3, 0xa0, 0x23, 0x63, 0x3b, 0x64, 0x67, 0x22, 0x44, 0xad, 0xd5, 0x71, 0xcb, 0x56,
+0x2a, 0x78, 0x92, 0xa3, 0x4f, 0x12, 0x31, 0x36, 0x36, 0xe2, 0xde, 0xfe, 0x00, 0xc4, 0xa3, 0x60,
+0x0f, 0x27, 0xad, 0xa0, 0xb0, 0x8a, 0xb5, 0x36, 0x7a, 0x52, 0xa1, 0xbd, 0x27, 0xf4, 0x20, 0x27,
+0x62, 0xe8, 0x4d, 0x94, 0x24, 0x13, 0xe4, 0x0a, 0x04, 0xe9, 0x3c, 0xab, 0x2e, 0xc8, 0x43, 0x09,
+0x4a, 0xc6, 0x61, 0x04, 0xe5, 0x49, 0x34, 0x7e, 0xd3, 0xc4, 0xc8, 0xf5, 0x0f, 0xc0, 0xaa, 0xe9,
+0xba, 0x54, 0x5e, 0xf3, 0x63, 0x2b, 0x4f, 0x4f, 0x50, 0xd4, 0xfe, 0xb9, 0x7b, 0x99, 0x8c, 0x3d,
+0xc0, 0x2e, 0xbc, 0x02, 0x2b, 0xd3, 0xc4, 0x40, 0xe4, 0x8a, 0x07, 0x31, 0x1e, 0x9b, 0xce, 0x26,
+0x99, 0x13, 0xfb, 0x11, 0xea, 0x9a, 0x22, 0x0c, 0x11, 0x19, 0xc7, 0x5e, 0x1b, 0x81, 0x50, 0x30,
+0xc8, 0x96, 0x12, 0x6e, 0xe7, 0xcb, 0x41, 0x7f, 0x91, 0x3b, 0xa2, 0x47, 0xb7, 0x54, 0x80, 0x1b,
+0xdc, 0x00, 0xcc, 0x9a, 0x90, 0xea, 0xc3, 0xc3, 0x50, 0x06, 0x62, 0x0c, 0x30, 0xc0, 0x15, 0x48,
+0xa7, 0xa8, 0x59, 0x7c, 0xe1, 0xae, 0x22, 0xa2, 0xe2, 0x0a, 0x7a, 0x0f, 0xfa, 0x62, 0xab, 0x52,
+0x4c, 0xe1, 0xf1, 0xdf, 0xca, 0xbe, 0x83, 0x0d, 0x42, 0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01,
+0xb1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x7b, 0x71, 0xb6, 0x82, 0x56, 0xb8, 0x12, 0x7c,
+0x9c, 0xa8, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x5a,
+0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30,
+0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50,
+0x4b, 0x49, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x65, 0x4d, 0x75,
+0x64, 0x68, 0x72, 0x61, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04,
+0x03, 0x13, 0x17, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f,
+0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x43, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38,
+0x30, 0x32, 0x31, 0x38, 0x31, 0x38, 0x33, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x34, 0x33, 0x30,
+0x32, 0x31, 0x38, 0x31, 0x38, 0x33, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09,
+0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+0x04, 0x0b, 0x13, 0x0a, 0x65, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x50, 0x4b, 0x49, 0x31, 0x14,
+0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x65, 0x4d, 0x75, 0x64, 0x68, 0x72, 0x61,
+0x20, 0x49, 0x6e, 0x63, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x65,
+0x6d, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x45, 0x43, 0x43, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
+0x41, 0x20, 0x2d, 0x20, 0x43, 0x33, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce,
+0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xfd, 0xa5,
+0x61, 0xae, 0x7b, 0x26, 0x10, 0x1d, 0xe9, 0xb7, 0x22, 0x30, 0xae, 0x06, 0xf4, 0x81, 0xb3, 0xb1,
+0x42, 0x71, 0x95, 0x39, 0xbc, 0xd3, 0x52, 0xe3, 0xaf, 0xaf, 0xf9, 0xf2, 0x97, 0x35, 0x92, 0x36,
+0x46, 0x0e, 0x87, 0x95, 0x8d, 0xb9, 0x39, 0x5a, 0xe9, 0xbb, 0xdf, 0xd0, 0xfe, 0xc8, 0x07, 0x41,
+0x3c, 0xbb, 0x55, 0x6f, 0x83, 0xa3, 0x6a, 0xfb, 0x62, 0xb0, 0x81, 0x89, 0x02, 0x70, 0x7d, 0x48,
+0xc5, 0x4a, 0xe3, 0xe9, 0x22, 0x54, 0x22, 0x4d, 0x93, 0xbb, 0x42, 0x0c, 0xaf, 0x77, 0x9c, 0x23,
+0xa6, 0x7d, 0xd7, 0x61, 0x11, 0xce, 0x65, 0xc7, 0xf8, 0x7f, 0xfe, 0xf5, 0xf2, 0xa9, 0xa3, 0x42,
+0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xfb, 0x5a, 0x48,
+0xd0, 0x80, 0x20, 0x40, 0xf2, 0xa8, 0xe9, 0x00, 0x07, 0x69, 0x19, 0x77, 0xa7, 0xe6, 0xc3, 0xf4,
+0xcf, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01,
+0x06, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x03, 0x68,
+0x00, 0x30, 0x65, 0x02, 0x31, 0x00, 0xb4, 0xd8, 0x2f, 0x02, 0x89, 0xfd, 0xb6, 0x4c, 0x62, 0xba,
+0x43, 0x4e, 0x13, 0x84, 0x72, 0xb5, 0xae, 0xdd, 0x1c, 0xde, 0xd6, 0xb5, 0xdc, 0x56, 0x8f, 0x58,
+0x40, 0x5a, 0x2d, 0xde, 0x20, 0x4c, 0x22, 0x83, 0xca, 0x93, 0xa8, 0x7e, 0xee, 0x12, 0x40, 0xc7,
+0xd6, 0x87, 0x4f, 0xf8, 0xdf, 0x85, 0x02, 0x30, 0x1c, 0x14, 0x64, 0xe4, 0x7c, 0x96, 0x83, 0x11,
+0x9c, 0xb0, 0xd1, 0x5a, 0x61, 0x4b, 0xa6, 0x0f, 0x49, 0xd3, 0x00, 0xfc, 0xa1, 0xfc, 0xe4, 0xa5,
+0xff, 0x7f, 0xad, 0xd7, 0x30, 0xd0, 0xc7, 0x77, 0x7f, 0xbe, 0x81, 0x07, 0x55, 0x30, 0x50, 0x20,
+0x14, 0xf5, 0x57, 0x38, 0x0a, 0xa8, 0x31, 0x51, 0x05, 0x86, 0x02, 0x5d, 0x05, 0xac, 0x05, 0xf3,
+0x02, 0x69, 0x05, 0xc4, 0x05, 0xd3, 0x05, 0xef, 0x05, 0x4b, 0x02, 0x6d, 0x03, 0xb9, 0x03, 0x76,
+0x05, 0xd6, 0x02, 0x72, 0x05, 0x6f, 0x04, 0x67, 0x01, 0xba, 0x05, 0x8c, 0x05, 0x45, 0x03, 0x45,
+0x01, 0xf6, 0x06, 0x0f, 0x02, 0xc7, 0x06, 0x5f, 0x04, 0x24, 0x06, 0x33, 0x04, 0x34, 0x05, 0x5e,
+0x05, 0x4a, 0x02, 0x98, 0x02, 0x91, 0x05, 0xe1, 0x05, 0x87, 0x05, 0x91, 0x04, 0x19, 0x03, 0x4e,
+0x03, 0xea, 0x05, 0x64, 0x05, 0xbb, 0x05, 0x64, 0x06, 0xa1, 0x05, 0x64, 0x03, 0x71, 0x03, 0x5e,
+0x03, 0x7b, 0x05, 0xdc, 0x04, 0x13, 0x03, 0xe1, 0x03, 0xf3, 0x05, 0xe2, 0x02, 0x93, 0x04, 0x95,
+0x05, 0x5a, 0x04, 0x2e, 0x04, 0x36, 0x07, 0xd7, 0x05, 0xbf, 0x03, 0x50, 0x05, 0xb4, 0x05, 0x4a,
+0x02, 0x02, 0x03, 0x50, 0x06, 0x18, 0x03, 0x7b, 0x05, 0x5d, 0x03, 0x7b, 0x05, 0x5d, 0x05, 0x6d,
+0x03, 0xac, 0x05, 0x3c, 0x05, 0x64, 0x05, 0x6a, 0x05, 0x74, 0x04, 0x42, 0x02, 0xfd, 0x03, 0x3c,
+0x03, 0xbf, 0x04, 0x21, 0x03, 0xa5, 0x02, 0x8d, 0x03, 0xbb, 0x03, 0x9a, 0x03, 0xb3, 0x03, 0x92,
+0x02, 0x43, 0x03, 0xc9, 0x05, 0x94, 0x02, 0x4a, 0x04, 0x04, 0x03, 0xc9, 0x04, 0x35, 0x03, 0x34,
+0x05, 0xf5, 0x03, 0xc7, 0x03, 0xc7, 0x05, 0x45, 0x03, 0x7f, 0x05, 0xa6, 0x05, 0x5e, 0x02, 0x10,
+0x02, 0x0e, 0x05, 0x5e, 0x05, 0x5e, 0x02, 0x0f, 0x03, 0xbe, 0x03, 0x63, 0x03, 0x79, 0x02, 0x22,
+0x05, 0x87, 0x04, 0x0e, 0x03, 0xc0, 0x03, 0xbc, 0x05, 0xbe, 0x02, 0x44, 0x02, 0x64, 0x05, 0xde,
+0x02, 0xa1, 0x04, 0x37, 0x04, 0x47, 0x06, 0x4f, 0x05, 0xc1, 0x04, 0x34, 0x01, 0xe5, 0x06, 0x4f,
+0x03, 0x98, 0x02, 0x52, 0x03, 0x77, 0x02, 0x2f, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+0x14, 0x14, 0x14, 0x00, 0x14, 0x14, 0x14, 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xdc, 0x2e, 0x1f, 0xd1, 0x61, 0x37, 0x79, 0xe4,
+0xab, 0xd5, 0xd5, 0xb3, 0x12, 0x71, 0x68, 0x3d, 0x6a, 0x68, 0x9c, 0x22, 0xc8, 0xcb, 0x99, 0x72,
+0x70, 0x52, 0x0c, 0xf8, 0xe6, 0xbe, 0xb2, 0x04, 0x57, 0x29, 0x2a, 0xcf, 0x42, 0x10, 0xed, 0x35,
+0x09, 0xcb, 0x59, 0x7f, 0x86, 0xb2, 0x70, 0x8f, 0x1a, 0xc3, 0x39, 0xe3, 0xc0, 0xd9, 0xe9, 0xbf,
+0xbb, 0x4d, 0xb2, 0x23, 0x9c, 0x5f, 0xd0, 0x6c, 0x63, 0xa3, 0x5f, 0x93, 0xca, 0x93, 0x98, 0x08,
+0xad, 0x8c, 0x87, 0xa5, 0x2c, 0x5c, 0xc1, 0x37, 0x8d, 0x06, 0x66, 0x74, 0x24, 0x76, 0x3a, 0xf3,
+0x89, 0xf7, 0xbc, 0xd6, 0xbd, 0x47, 0x7d, 0x2f, 0xbc, 0x10, 0x5f, 0x4b, 0x8c, 0xfb, 0x1c, 0x75,
+0xbc, 0x02, 0xd3, 0x9f, 0x4e, 0x2e, 0x48, 0xd9, 0xf9, 0x60, 0x54, 0xaa, 0xc4, 0xb3, 0x4f, 0xfa,
+0x17, 0x9d, 0xcd, 0x1e, 0x8b, 0xd6, 0x39, 0x2b, 0x70, 0xd3, 0x5c, 0xd4, 0xa0, 0xb8, 0x1f, 0xb0,
+0x00, 0xfc, 0xc5, 0x61, 0xf9, 0x60, 0xbb, 0xd4, 0xe3, 0xd5, 0x34, 0xf6, 0xb8, 0xf5, 0x06, 0x80,
+0x25, 0xa7, 0x73, 0xdb, 0x46, 0x69, 0xa8, 0x9e, 0x82, 0x21, 0x2d, 0x66, 0xc6, 0xd7, 0xa0, 0xe0,
+0x15, 0xeb, 0xce, 0x4c, 0x09, 0x77, 0xc4, 0x60, 0x9e, 0x54, 0x6e, 0x03, 0x48, 0x87, 0x14, 0xac,
+0xe3, 0xc3, 0x9e, 0x90, 0x60, 0x3a, 0xd7, 0xca, 0x89, 0xee, 0xd3, 0xad, 0x8c, 0xb4, 0x50, 0x66,
+0x35, 0x0f, 0xc8, 0x36, 0x63, 0x5e, 0xe2, 0xa3, 0xec, 0xf9, 0x3b, 0x66, 0x15, 0xce, 0x51, 0x52,
+0xe3, 0x91, 0x9a, 0x3d, 0x2e, 0x16, 0xa9, 0x4a, 0x18, 0xb5, 0xcb, 0xcc, 0xf5, 0x6f, 0x50, 0xf3,
+0x23, 0x5f, 0xf8, 0x5d, 0xe7, 0xac, 0xf0, 0xc8, 0xb6, 0xa1, 0x54, 0x39, 0x02, 0xc3, 0xa0, 0x3f,
+0x8e, 0x8a, 0xbc, 0xfa, 0xd4, 0xf8, 0x1c, 0xa6, 0xd1, 0x3a, 0x0e, 0xfd, 0x01, 0xb9, 0x2f, 0xef,
+0xbf, 0x11, 0x86, 0x60, 0xf2, 0x4f, 0xd0, 0x41, 0x6e, 0xab, 0x73, 0x1f, 0xe7, 0xd2, 0x6e, 0x49,
+0x79, 0xb4, 0x59, 0xe6, 0x7b, 0xb6, 0xe5, 0xe4, 0x01, 0x73, 0x80, 0x08, 0x88, 0xc8, 0x1a, 0x58,
+0xf6, 0xe9, 0x9b, 0x6e, 0x65, 0x3f, 0xc7, 0x8a, 0x86, 0xc6, 0x3c, 0xdd, 0x3c, 0x54, 0x5c, 0x35,
+0xf8, 0x3a, 0xed, 0x52, 0x0c, 0x47, 0x57, 0xc8, 0xab, 0xb6, 0xdb, 0xd7, 0x06, 0x9e, 0x37, 0xac,
+0x30, 0x86, 0x07, 0x91, 0x70, 0xc7, 0x9c, 0xc4, 0x19, 0xb1, 0x78, 0xc0, 0xe2, 0xc9, 0x40, 0x9f,
+0x4d, 0xce, 0xe8, 0x9a, 0xa1, 0x7c, 0xcf, 0x0e, 0x3f, 0x65, 0xc5, 0x29, 0x88, 0x6a, 0x19, 0x51,
+0xb0, 0x0c, 0xf0, 0x4c, 0x30, 0xf4, 0x05, 0x58, 0x02, 0x48, 0xfd, 0x33, 0xe5, 0x52, 0xaf, 0x4b,
+0x84, 0xe3, 0x66, 0x52, 0x84, 0x18, 0xcc, 0x85, 0x34, 0xec, 0xbc, 0x0c, 0x94, 0x94, 0x2e, 0x08,
+0x59, 0x9c, 0xc7, 0xb2, 0x10, 0x4e, 0x0a, 0x08, 0xd3, 0xec, 0xc7, 0x3a, 0x65, 0x6e, 0xcc, 0xe1,
+0xda, 0x76, 0x9a, 0x56, 0xfb, 0x9c, 0xf3, 0x86, 0x6d, 0x57, 0xe5, 0x81, 0x71, 0x15, 0x67, 0xc8,
+0xc8, 0xc9, 0xbd, 0x75, 0x5d, 0x72, 0xd0, 0x38, 0x18, 0x6a, 0x9d, 0xf3, 0x71, 0x24, 0x54, 0x0b,
+0xb4, 0x22, 0x0b, 0x82, 0x99, 0x24, 0x01, 0x0e, 0x9c, 0xbb, 0xe4, 0x0e, 0xfd, 0xbf, 0xfb, 0x97,
+0x20, 0x93, 0x99, 0x2a, 0x18, 0x87, 0x56, 0xe0, 0x6e, 0x77, 0xee, 0x24, 0x35, 0x3c, 0x4e, 0x73,
+0x9a, 0x1f, 0xd6, 0xe1, 0xe2, 0x79, 0x7e, 0x2b, 0x44, 0x9e, 0x48, 0xf5, 0xcc, 0x6d, 0x48, 0xd4,
+0xa0, 0x4b, 0x7f, 0xfe, 0x59, 0x24, 0x2f, 0x83, 0x97, 0x99, 0x9a, 0x86, 0xd9, 0xfe, 0x21, 0x40,
+0x6e, 0x94, 0x9e, 0xbc, 0x9b, 0x3d, 0x9c, 0x7d, 0x98, 0x20, 0x19, 0xe5, 0x8c, 0x30, 0x62, 0xb2,
+0xee, 0x6b, 0x49, 0x3c, 0x7a, 0x3f, 0x0d, 0xe3, 0xb1, 0x09, 0xb7, 0x8a, 0xc8, 0xab, 0x19, 0x9f,
+0x73, 0x33, 0x50, 0xe7, 0xd9, 0x74, 0x3a, 0xe4, 0x30, 0x3d, 0x0d, 0xf7, 0x12, 0xdc, 0x7e, 0x5a,
+0x05, 0x9f, 0x1e, 0x34, 0x9a, 0xf7, 0xe1, 0x14, 0x81, 0xc4, 0x8c, 0xcc, 0xf5, 0xe4, 0x30, 0xff,
+0xa5, 0x0c, 0x08, 0x5f, 0x8c, 0x15, 0x67, 0x21, 0x74, 0x01, 0xdf, 0xdf, 0x5b, 0xca, 0x5e, 0xe5,
+0xde, 0xd2, 0x81, 0xaa, 0xcd, 0xa8, 0x2d, 0x64, 0x51, 0xb6, 0xd9, 0x72, 0x9b, 0x97, 0xe6, 0x4f,
+0x82, 0xd1, 0x85, 0x73, 0x30, 0xe7, 0x35, 0x04, 0xd3, 0x8e, 0x02, 0x92, 0xfb, 0xe5, 0xa4, 0xd1,
+0xc4, 0x21, 0xe8, 0xcd, 0xdd, 0x04, 0x09, 0x07, 0xa2, 0xf5, 0x7a, 0x7d, 0x52, 0x53, 0x12, 0x92,
+0x95, 0xee, 0x38, 0x80, 0x25, 0x0d, 0xa6, 0x59, 0xf7, 0x7d, 0xc5, 0xfd, 0xc4, 0xe8, 0x9a, 0x1b,
+0x77, 0x64, 0xa7, 0xf5, 0x1d, 0xa0, 0xcc, 0xbf, 0x87, 0x60, 0x9a, 0x6d, 0xe3, 0xfe, 0x2d, 0xfd,
+0x28, 0xd0, 0x0b, 0xb5, 0xba, 0xb6, 0xa2, 0xc4, 0xbf, 0x06, 0xaa, 0x05, 0x8c, 0x93, 0xfb, 0x2f,
+0xcc, 0xfa, 0x67, 0x93, 0xf0, 0xb6, 0xb8, 0xd0, 0xa5, 0xc0, 0x1e, 0xf3, 0x53, 0xfd, 0x8c, 0x53,
+0xdf, 0x83, 0xd7, 0x96, 0xc4, 0xa7, 0xb1, 0xa4, 0x7b, 0x2c, 0x71, 0xfa, 0xdb, 0xe1, 0x4b, 0x90,
+0x75, 0xff, 0xc4, 0x15, 0x60, 0x85, 0x89, 0x10, 0x21, 0x30, 0xc9, 0xfb, 0x00, 0xd7, 0x4e, 0x98,
+0xda, 0x87, 0xaa, 0x2a, 0xd0, 0xa7, 0x2e, 0xb1, 0x40, 0x31, 0xa7, 0x4c, 0xa3, 0x97, 0xd6, 0xf3,
+0x5e, 0xa2, 0x10, 0xe1, 0xab, 0x45, 0x9f, 0x3c, 0x17, 0x64, 0x3c, 0xee, 0x01, 0x70, 0x9c, 0xcc,
+0x1a, 0x84, 0x62, 0xbc, 0x48, 0x4c, 0x33, 0x25, 0x04, 0xd4, 0xee, 0xd0, 0xf6, 0x03, 0xc4, 0x19,
+0x46, 0xd1, 0x94, 0x6b, 0xed, 0xe7, 0x6f, 0x76, 0x5a, 0xbf, 0x60, 0xec, 0x49, 0x5b, 0xc6, 0xa5,
+0x77, 0xbb, 0x72, 0x16, 0x71, 0x9b, 0xc4, 0x3d, 0xf2, 0xc0, 0x13, 0xe0, 0x82, 0x43, 0x3e, 0xfb,
+0xee, 0x2f, 0x67, 0x32, 0x96, 0x35, 0x5c, 0xdb, 0xb8, 0xcb, 0x02, 0xd0, 0xc6, 0x17, 0xd0, 0xbc,
+0xa8, 0xea, 0x02, 0x43, 0xf2, 0x1b, 0x06, 0x99, 0x5d, 0x2b, 0x90, 0x20, 0xb9, 0xd7, 0x9c, 0xe4,
+0x5b, 0xf8, 0x4d, 0x4f, 0xb2, 0xa5, 0x86, 0xd4, 0x3a, 0xd2, 0xf1, 0x63, 0x9a, 0xa0, 0xbe, 0x09,
+0xf6, 0x57, 0xb7, 0xde, 0xa0, 0x73, 0x49, 0x99, 0x68, 0xdc, 0x85, 0x5b, 0x65, 0xe3, 0x9b, 0x28,
+0x2f, 0x57, 0x9f, 0xbd, 0x33, 0xbc, 0x07, 0x48, 0x0a, 0x85, 0xa9, 0x77, 0x65, 0x05, 0x98, 0x7c,
+0x40, 0x81, 0xf8, 0x0f, 0x97, 0x2c, 0x38, 0xf1, 0x0a, 0xec, 0x3c, 0xcf, 0xbb, 0xaf, 0x7e, 0x02,
+0x3d, 0xfa, 0xa6, 0xf1, 0x3c, 0x84, 0x8e, 0xad, 0xee, 0x38, 0x98, 0xec, 0xd9, 0x32, 0x32, 0xd4,
+0xbf, 0x5f, 0xb7, 0xd1, 0xce, 0xdd, 0x1f, 0x86, 0xf4, 0x5b, 0x55, 0xac, 0xdc, 0xd7, 0x10, 0xc2,
+0x0e, 0xa9, 0x88, 0xe7, 0x7c, 0x0c, 0x32, 0x1f, 0xa7, 0xd9, 0x30, 0x7f, 0xc4, 0x7d, 0x68, 0xa3,
+0x62, 0xa8, 0xa1, 0xce, 0xab, 0x07, 0x5b, 0x27, 0x9c, 0x5f, 0x00, 0xdf, 0xaa, 0x01, 0xd7, 0x30,
+0x2b, 0x38, 0x88, 0xa2, 0xb8, 0x6d, 0x4a, 0x9c, 0xf2, 0x11, 0x91, 0x83, 0x53, 0x79, 0xbf, 0x5a,
+0xaa, 0x2b, 0x4a, 0xcf, 0x54, 0x80, 0xe1, 0xd8, 0x9b, 0xc0, 0x9d, 0xf2, 0xb2, 0x03, 0x66, 0xcb,
+0x3a, 0xe1, 0x09, 0x86, 0xd4, 0xcf, 0x19, 0xc2, 0x96, 0x76, 0x74, 0x49, 0x76, 0xdc, 0xe0, 0x35,
+0xc6, 0x63, 0x63, 0x9a, 0x68, 0x90, 0xe4, 0x67, 0xa4, 0xa6, 0x53, 0x80, 0xc7, 0x86, 0x66, 0xa4,
+0xf1, 0xf7, 0x4b, 0x43, 0xfb, 0x84, 0xbd, 0x6d, 0xa0, 0xc3, 0x8b, 0x44, 0xaa, 0x37, 0xa5, 0x45,
+0xbf, 0x97, 0x80, 0x5a, 0xd1, 0xf1, 0x78, 0xa2, 0x9b, 0xe9, 0x5d, 0x8d, 0x55, 0xe4, 0x81, 0xd1,
+0x11, 0x80, 0xbe, 0xd8, 0x89, 0xb9, 0x08, 0xa3, 0x31, 0xf9, 0xa1, 0x24, 0x09, 0x16, 0xb9, 0x70,
+0xa0, 0x11, 0x0a, 0x23, 0x3e, 0x96, 0xf1, 0x07, 0xec, 0xe2, 0xaf, 0x29, 0xef, 0x82, 0xa5, 0x7f,
+0xd0, 0x30, 0xa4, 0xb4, 0xd2, 0x87, 0xb4, 0xe3, 0xdf, 0x37, 0x27, 0x93, 0x55, 0xf6, 0x56, 0xea,
+0x81, 0xe5, 0x36, 0xcc, 0x8c, 0x1e, 0x3f, 0xbd, 0x52, 0xd8, 0x88, 0x3a, 0xc8, 0x9f, 0x78, 0x66,
+0xed, 0x89, 0xf3, 0x7b, 0x38, 0x70, 0x94, 0xc9, 0x02, 0x02, 0x36, 0xd0, 0x9d, 0x93, 0xc6, 0x53,
+0x8b, 0x5e, 0xca, 0xaf, 0x3f, 0x9f, 0x1e, 0x0f, 0xe5, 0x99, 0x95, 0xbc, 0x24, 0xf6, 0x94, 0x8f,
+0x1e, 0x0c, 0xf7, 0xb6, 0x67, 0xf2, 0xe1, 0x92, 0x26, 0x09, 0x45, 0xc0, 0x55, 0x39, 0x2e, 0x77,
+0x3f, 0x42, 0x4a, 0xa2, 0x9d, 0xc0, 0x67, 0xa6, 0x0c, 0x22, 0xd9, 0x26, 0xf5, 0x45, 0xab, 0xa6,
+0x65, 0x52, 0x11, 0x27, 0xd8, 0x45, 0xac, 0x63, 0x9a, 0xaf, 0x29, 0x7a, 0xc0, 0x11, 0x35, 0x35,
+0x26, 0x51, 0x30, 0x00, 0xc3, 0x6a, 0xfe, 0x40, 0xd5, 0xae, 0xd6, 0x3c, 0x07, 0x1f, 0xd2, 0xe7,
+0x9c, 0xda, 0xc2, 0x6e, 0xa2, 0x40, 0xb4, 0xb0, 0x7a, 0x50, 0x10, 0x50, 0x74, 0xc4, 0xc8, 0xbd,
+0x65, 0xcd, 0xeb, 0xab, 0x35, 0x1e, 0x00, 0x3e, 0x7e, 0xd5, 0x74, 0xc0, 0x1c, 0xb4, 0x73, 0x47,
+0x0e, 0x1a, 0x64, 0x2f, 0xe5, 0x9d, 0x59, 0x30, 0x82, 0x47, 0x58, 0xcc, 0xac, 0xfa, 0x08, 0x54,
+0x36, 0x86, 0x7b, 0x3a, 0xb5, 0x04, 0x4d, 0xf0, 0xc9, 0x80, 0x77, 0xe0, 0x62, 0x92, 0x82, 0xf5,
+0x46, 0x9c, 0xf3, 0xba, 0xf7, 0x4c, 0xc3, 0xde, 0xb8, 0xa3, 0xad, 0x39, 0xa7, 0xa5, 0x06, 0xb1,
+0x2c, 0xa6, 0x09, 0x60, 0xee, 0xd1, 0x97, 0xe9, 0x70, 0xae, 0xbc, 0x3b, 0x19, 0x6c, 0xdb, 0x21,
+0x47, 0xb8, 0xcd, 0xff, 0xe5, 0x6f, 0xee, 0xf8, 0xb2, 0xec, 0x2f, 0x4e, 0x0e, 0xf9, 0x25, 0xb0,
+0x8e, 0x3c, 0x6b, 0xc3, 0xb5, 0x99, 0xf8, 0xaf, 0xb0, 0x94, 0xf5, 0xe3, 0x20, 0xd6, 0x0a, 0xad,
+0xce, 0x4e, 0x56, 0xa4, 0x2e, 0x6e, 0x42, 0xed, 0x1a, 0xed, 0xfe, 0x41, 0x39, 0x90, 0xb4, 0x24,
+0x59, 0xbe, 0x01, 0xf2, 0x52, 0xd5, 0x45, 0xf6, 0x5a, 0x39, 0xdc, 0x11, 0xf0, 0x8f, 0x59, 0x38,
+0x00, 0xb3, 0xf5, 0x8f, 0x9a, 0x96, 0x0c, 0xd5, 0xeb, 0xfa, 0x7b, 0xaa, 0x17, 0xe8, 0x13, 0x12,
+0xed, 0x44, 0x19, 0xc0, 0xd3, 0xf0, 0x06, 0x8b, 0xee, 0xa4, 0x7b, 0xbe, 0x42, 0xe7, 0x26, 0x54,
+0xc8, 0x8e, 0x36, 0x76, 0xe3, 0x71, 0xe0, 0x9e, 0xd8, 0xa7, 0x42, 0xd9, 0xdb, 0x71, 0x91, 0x6b,
+0x94, 0x93, 0xeb, 0xc3, 0xa3, 0xd1, 0x14, 0xa3, 0xfe, 0xab, 0x00, 0x90, 0x98, 0x9e, 0x24, 0xfc,
+0xa9, 0xcc, 0x1a, 0x8a, 0xfb, 0x27, 0xb8, 0xbf, 0x30, 0x6e, 0xa8, 0x3b, 0x6a, 0x72, 0x26, 0x7a,
+0xd0, 0x1e, 0xef, 0x7d, 0xe7, 0x3b, 0x69, 0x51, 0xd4, 0x6c, 0x8d, 0x9f, 0x90, 0x12, 0x66, 0xab,
+0xb7, 0x63, 0xe7, 0x1a, 0xdd, 0x8d, 0xe9, 0x08, 0xa6, 0x55, 0x83, 0xa4, 0xe0, 0x6a, 0x50, 0x41,
+0x65, 0x11, 0x42, 0x49, 0xe0, 0x8c, 0x9b, 0xdb, 0x25, 0x49, 0xb3, 0xf1, 0x7c, 0x86, 0xd6, 0xb2,
+0x42, 0x87, 0x0b, 0xd0, 0x6b, 0xa0, 0xd9, 0xe4, 0x08, 0x76, 0xcd, 0xcb, 0x07, 0xff, 0x24, 0xf6,
+0xc5, 0xcd, 0xed, 0xbb, 0x90, 0xbc, 0xe2, 0x84, 0x37, 0x46, 0x75, 0xf7, 0x0b, 0x58, 0xe5, 0x8b,
+0xc6, 0x4c, 0x15, 0x37, 0xa4, 0x40, 0xa9, 0x30, 0xa9, 0x21, 0xbe, 0x47, 0x36, 0x5a, 0x56, 0xff,
+0xb6, 0x08, 0x7b, 0x0d, 0x7a, 0xcc, 0xac, 0x20, 0x4c, 0x86, 0x56, 0x32, 0x5e, 0xcf, 0xab, 0x6e,
+0x85, 0x2d, 0x70, 0x57, 0x75, 0x71, 0xa7, 0x19, 0x48, 0x19, 0xbc, 0x9d, 0x9d, 0xea, 0x41, 0x47,
+0xdf, 0x94, 0xc4, 0x48, 0x77, 0x99, 0xd3, 0x79, 0x45, 0xeb, 0xa2, 0xaf, 0xf4, 0x92, 0xcb, 0x82,
+0x31, 0x2d, 0x51, 0x8b, 0xa7, 0xa7, 0x21, 0x9d, 0xf3, 0x6d, 0xc8, 0x0f, 0xce, 0xc3, 0x4a, 0xb9,
+0x99, 0x55, 0xf2, 0xb8, 0xdb, 0x60, 0xbf, 0xa9, 0x7e, 0xbd, 0x56, 0xb5, 0x97, 0x36, 0xa7, 0xd6,
+0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, 0x66, 0xf0, 0xa3, 0xe2, 0x1b, 0x1b, 0xc3, 0x97,
+0xb2, 0x3d, 0xd1, 0x55, 0x4e, 0x22, 0x54, 0x20, 0x18, 0x95, 0xe6, 0xe3, 0x6e, 0xe6, 0x0f, 0xfa,
+0xfa, 0xb9, 0x12, 0xed, 0x06, 0x17, 0x8f, 0x39, 0xb3, 0xdb, 0x48, 0xa4, 0xf9, 0xa1, 0xc5, 0xd8,
+0xae, 0x36, 0x41, 0xcc, 0x11, 0x63, 0x69, 0x62, 0x29, 0xbc, 0x4b, 0xc6, 0xb1, 0x3e, 0xc3, 0x69,
+0x03, 0xf8, 0xbf, 0x47, 0x01, 0xd4, 0x98, 0x26, 0x1a, 0x08, 0x02, 0xef, 0x63, 0x64, 0x2b, 0xc3,
+0xec, 0xd7, 0xe3, 0x82, 0xd2, 0x71, 0x5d, 0x64, 0x4c, 0xdf, 0x2e, 0x67, 0x3f, 0xe7, 0xba, 0x98,
+0xae, 0x1c, 0x0f, 0x4f, 0xcb, 0xd0, 0xbd, 0xa9, 0xe1, 0x98, 0x05, 0x51, 0xa1, 0x4d, 0x37, 0xa2,
+0x83, 0x79, 0xce, 0x8d, 0x1d, 0x2a, 0xe4, 0x84, 0xd2, 0xc4, 0xb0, 0xd2, 0x91, 0xd4, 0x4c, 0x11,
+0x71, 0xb3, 0x61, 0xcb, 0x3d, 0xa1, 0xfe, 0xdd, 0xa8, 0x6a, 0xd4, 0xe3, 0x3a, 0x9a, 0x85, 0x07,
+0x10, 0x67, 0x28, 0xb6, 0xef, 0xf6, 0xbd, 0x05, 0x41, 0x6e, 0x20, 0xc1, 0x94, 0xda, 0x0f, 0xde,
+0xa6, 0x91, 0x42, 0xfd, 0x13, 0x61, 0x4a, 0x23, 0x9e, 0x08, 0xa4, 0x29, 0xe5, 0xd8, 0x13, 0x04,
+0x23, 0xee, 0x41, 0x25, 0x1d, 0x1c, 0x65, 0x0e, 0xa8, 0xf2, 0x25, 0x7b, 0xb4, 0x91, 0xcf, 0xe4,
+0xb1, 0xb1, 0xe6, 0xbd, 0x55, 0x74, 0x6c, 0x05, 0xbf, 0x59, 0x20, 0x36, 0x00, 0x79, 0xa0, 0xa0,
+0x22, 0x6b, 0x8c, 0xd5, 0xf2, 0x61, 0xd2, 0xb8, 0x2c, 0xcb, 0x82, 0x4a, 0xb5, 0x03, 0xf7, 0x76,
+0x3b, 0x61, 0x82, 0x6a, 0x12, 0xaa, 0x18, 0x53, 0xeb, 0x03, 0x21, 0x94, 0xbf, 0xfe, 0xce, 0xca,
+0x6a, 0x38, 0x5b, 0x26, 0x8d, 0xde, 0x8b, 0x5a, 0xf2, 0x4f, 0x7a, 0x54, 0x83, 0x19, 0x18, 0xe3,
+0x08, 0x35, 0xa6, 0xba, 0xd2, 0x9f, 0x88, 0xdf, 0xa1, 0xcd, 0x2c, 0xbd, 0xec, 0xf5, 0x3b, 0x01,
+0x01, 0x93, 0x33, 0x27, 0xb2, 0xeb, 0x60, 0x4b, 0xbb, 0xff, 0xca, 0x8e, 0x23, 0x9f, 0x4f, 0x99,
+0xca, 0xdb, 0xe2, 0x68, 0xa6, 0xa5, 0x15, 0x27, 0x17, 0x1e, 0xd9, 0x0e, 0xc1, 0xf1, 0x26, 0xba,
+0xa0, 0x2d, 0xae, 0x85, 0x81, 0xcf, 0xd3, 0xf1, 0x2a, 0x12, 0xbd, 0xb8, 0x0a, 0x67, 0xfd, 0xbc,
+0x80, 0x4c, 0xd6, 0xeb, 0x74, 0xff, 0x49, 0x36, 0xa3, 0xd5, 0xd8, 0xfc, 0xb5, 0x3e, 0xc5, 0x6a,
+0xf0, 0x94, 0x1d, 0x8c, 0xe4, 0xaf, 0x2b, 0x26, 0x71, 0x1a, 0x2b, 0x48, 0x27, 0x85, 0x2f, 0x52,
+0x66, 0x2c, 0xef, 0xf0, 0x89, 0x13, 0x71, 0x3e, 0x03, 0x5c, 0xab, 0x73, 0x81, 0x87, 0xa8, 0xcc,
+0xb0, 0xa6, 0xd5, 0x94, 0xe2, 0x36, 0x96, 0x49, 0xff, 0x05, 0x99, 0x2c, 0x31, 0x0a, 0x90, 0x8f,
+0xb6, 0xc6, 0x9d, 0xd2, 0x44, 0x4b, 0x80, 0xb5, 0xa2, 0xe6, 0x1f, 0xb1, 0x12, 0x4f, 0x1b, 0x95,
+0x9b, 0xe2, 0x07, 0x57, 0x67, 0x1c, 0x1e, 0xc0, 0x6a, 0x06, 0xde, 0x59, 0xb4, 0x9a, 0x2d, 0xdf,
+0xdc, 0x19, 0x86, 0x2e, 0x8f, 0xf0, 0x4b, 0x7f, 0xa8, 0x2e, 0x45, 0x24, 0xae, 0x4d, 0x50, 0xfa,
+0x63, 0x9a, 0x8b, 0xde, 0xe2, 0xdd, 0x1b, 0xbc, 0x60, 0x7b, 0x66, 0x1a, 0x45, 0x0d, 0x97, 0xca,
+0x89, 0x50, 0x2f, 0x7d, 0x04, 0xcd, 0x34, 0xa8, 0xff, 0xfc, 0xfd, 0x4b, 0x3d, 0xe6, 0x29, 0x48,
+0x9b, 0xea, 0x07, 0xca, 0x21, 0x44, 0x4a, 0x26, 0xde, 0x6e, 0xde, 0xd2, 0x83, 0xd0, 0x9f, 0x59,
+0xae, 0x6c, 0x05, 0xa3, 0x93, 0x13, 0xe2, 0xa2, 0xe7, 0xe2, 0xd7, 0x1c, 0xd6, 0xc7, 0xf0, 0x7f,
+0xc8, 0x67, 0x53, 0xa0, 0xcb, 0x0f, 0xc6, 0xdf, 0x42, 0x43, 0xcc, 0x3d, 0xcb, 0xb5, 0x48, 0x23,
+0xa1, 0x1a, 0x7a, 0xa6, 0x2a, 0xbb, 0x34, 0x68, 0xaf, 0x44, 0x04, 0xc2, 0x41, 0x7e, 0x48, 0x83,
+0xdb, 0x4e, 0x39, 0x02, 0xec, 0xec, 0x84, 0x7a, 0xe6, 0xce, 0xc9, 0xa4, 0x42, 0x32, 0xb6, 0x16,
+0xfa, 0x04, 0xfd, 0xfe, 0x5d, 0x4b, 0x7a, 0xc3, 0xfd, 0xf7, 0x4c, 0x40, 0x1d, 0x5a, 0x43, 0xaf,
+0x5b, 0x25, 0x7b, 0x96, 0xa4, 0x65, 0x51, 0x7e, 0xb8, 0x39, 0xf3, 0xc0, 0x78, 0x66, 0x5e, 0xe8,
+0x3a, 0xe7, 0xf0, 0xee, 0x87, 0x11, 0x15, 0x08, 0xd1, 0xaa, 0xc1, 0x78, 0x0c, 0xb1, 0xaf, 0xce,
+0xc6, 0xc9, 0x90, 0xef, 0xbf, 0x30, 0x04, 0xc0, 0xa3, 0x41, 0x06, 0xac, 0x90, 0x6d, 0xd1, 0x4a,
+0xeb, 0x75, 0xa5, 0x4a, 0x10, 0x99, 0xb3, 0xb1, 0xa1, 0x8b, 0x4a, 0xf7, 0x99, 0xe0, 0x19, 0x67,
+0x0d, 0x62, 0xdb, 0x76, 0xb3, 0xda, 0x3d, 0xb8, 0x5b, 0xe8, 0xfd, 0x42, 0xd2, 0x31, 0x0e, 0x87,
+0x55, 0xa9, 0x84, 0x89, 0xd2, 0xc1, 0x32, 0xbd, 0x18, 0xcb, 0x6c, 0xa6, 0x07, 0x4e, 0xc8, 0xe7,
+0x9d, 0xbe, 0x82, 0x90, 0xfd, 0xda, 0x14, 0xc4, 0x9f, 0x30, 0xde, 0x21, 0xbd, 0x1e, 0x42, 0x39,
+0xfc, 0xab, 0x63, 0x23, 0x49, 0xe0, 0xf1, 0x84, 0xd3, 0x94, 0x8a, 0x4c, 0x62, 0x13, 0x2a, 0x19,
+0x2e, 0xcc, 0xaf, 0x72, 0x8a, 0x7d, 0x36, 0xd7, 0x9a, 0x1c, 0xdc, 0x67, 0x2e, 0xe3, 0xdb, 0xb2,
+0x49, 0xd0, 0x9c, 0x54, 0x79, 0x5c, 0xfa, 0x27, 0x2a, 0xfe, 0xcc, 0x4e, 0xd2, 0xe8, 0x4e, 0x54,
+0x17, 0xa0, 0xcd, 0xc1, 0xe4, 0x41, 0xb6, 0x3a, 0x5b, 0x3b, 0xcb, 0x45, 0x9d, 0xbd, 0x1c, 0xc2,
+0x98, 0xfa, 0x86, 0x58, 0xc6, 0x4f, 0xa2, 0x3d, 0x06, 0x63, 0x84, 0x09, 0x9c, 0xce, 0x62, 0xe4,
+0x04, 0xac, 0x8d, 0x5c, 0xb5, 0xe9, 0xb6, 0x1b, 0x54, 0xb0, 0x7b, 0xad, 0x45, 0xb8, 0xe2, 0x40,
+0x7f, 0xfb, 0x0a, 0x6e, 0xfb, 0xbe, 0x33, 0xc9, 0x3c, 0xa3, 0x84, 0xd5, 0x9f, 0x38, 0xc4, 0x56,
+0x23, 0xc3, 0x39, 0xe8, 0xa0, 0x71, 0x6c, 0xe8, 0x54, 0x4c, 0xe4, 0xe8, 0x3a, 0xb1, 0xbf, 0x67,
+0xfb, 0xef, 0x0d, 0x86, 0x9e, 0xb0, 0xe3, 0xdd, 0xa9, 0xb9, 0xf1, 0x21, 0x17, 0x7f, 0x3e, 0xfc,
+0xf0, 0x77, 0x2b, 0x1a, 0x7c, 0x5d, 0x02, 0x84, 0x13, 0xd4, 0xcc, 0x8a, 0x9b, 0x81, 0xce, 0x17,
+0x1c, 0x2e, 0x29, 0x1e, 0x9c, 0x48, 0x63, 0x42, 0xfe, 0xa1, 0xe0, 0x70, 0x1e, 0x2a, 0x03, 0x39,
+0x52, 0x5a, 0x42, 0xbe, 0x5c, 0x91, 0x85, 0x7a, 0x18, 0xaa, 0x4d, 0xb5, 0xfb, 0x5a, 0x48, 0xd0,
+0x80, 0x20, 0x40, 0xf2, 0xa8, 0xe9, 0x00, 0x07, 0x69, 0x19, 0x77, 0xa7, 0xe6, 0xc3, 0xf4, 0xcf,
diff --git a/minimal-examples/http-client/minimal-http-client-jit-trust/warmcat.com.cer b/minimal-examples/http-client/minimal-http-client-jit-trust/warmcat.com.cer
new file mode 100644 (file)
index 0000000..01ad0dc
--- /dev/null
@@ -0,0 +1,32 @@
+-----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-----
+
index be0314e..22d138c 100644 (file)
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-client-multi C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-client-multi)
 set(SRCS minimal-http-client-multi.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
+set(requirements 1)
+set(MBEDTLS 0)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
 
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
+require_lws_config(LWS_WITH_MBEDTLS 1 MBEDTLS)
 
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
        
+       find_program(VALGRIND "valgrind")
+       
+       #
+       # instantiate the server per sai builder instance, they are running in the same
+       # machine context in parallel so they can tread on each other otherwise
+       #
+       set(PORT_HCM_SRV "7670")
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0")
+               set(PORT_HCM_SRV 7671)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1")
+               set(PORT_HCM_SRV 7672)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2")
+               set(PORT_HCM_SRV 7673)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3")
+               set(PORT_HCM_SRV 7674)
+       endif()
+
+
+# hack
+if (NOT WIN32 AND LWS_WITH_SERVER)
+
+       #
+       # Tests against built server running locally (needs daemonization...)
+       #
+
+if (WIN32)
+       add_test(NAME st_hcm_srv COMMAND cmd.exe /c start /b $<TARGET_FILE:lws-minimal-http-server-tls> --port ${PORT_HCM_SRV})
+       add_test(NAME ki_hcm_srv COMMAND taskkill /F /IM $<TARGET_FILE_NAME:lws-minimal-http-server-tls> /T)
+       add_test(NAME st_hcmp_srv COMMAND cmd.exe /c start /b $<TARGET_FILE:test-server> -s --port 1${PORT_HCM_SRV})
+       add_test(NAME ki_hcmp_srv COMMAND taskkill /F /IM $<TARGET_FILE_NAME:test-server> /T)
+else()
+       #
+       # mbedtls is too slow to keep up on some targets, when ctest is in parallel
+       #
+       if (VALGRIND AND NOT MBEDTLS)
+               add_test(NAME st_hcm_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               hcm_srv ${VALGRIND} --tool=memcheck $<TARGET_FILE:lws-minimal-http-server-tls>
+                               --port ${PORT_HCM_SRV})
+               add_test(NAME ki_hcm_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                               hcm_srv ${VALGRIND} $<TARGET_FILE_NAME:lws-minimal-http-server-tls>
+                                       --port ${PORT_HCM_SRV})
+               add_test(NAME st_hcmp_srv COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                                       hcmp_srv ${VALGRIND} --tool=memcheck $<TARGET_FILE:test-server> -s
+                                       -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/
+                                       --port 1${PORT_HCM_SRV})
+               add_test(NAME ki_hcmp_srv COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                                       hcmp_srv ${VALGRIND} $<TARGET_FILE_NAME:test-server>
+                                       --port 1${PORT_HCM_SRV})
+       else()
+               add_test(NAME st_hcm_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               hcm_srv $<TARGET_FILE:lws-minimal-http-server-tls>
+                               --port ${PORT_HCM_SRV} )
+               add_test(NAME ki_hcm_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                               hcm_srv $<TARGET_FILE_NAME:lws-minimal-http-server-tls>
+                                       --port ${PORT_HCM_SRV})
+               add_test(NAME st_hcmp_srv COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                                       hcmp_srv $<TARGET_FILE:test-server> -s
+                                       -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/
+                                       --port 1${PORT_HCM_SRV} )
+               add_test(NAME ki_hcmp_srv COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                                       hcmp_srv $<TARGET_FILE_NAME:test-server>
+                                       --port 1${PORT_HCM_SRV})
        endif()
-ENDMACRO()
+endif()
 
+       set_tests_properties(st_hcm_srv PROPERTIES
+                       WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-tls
+               FIXTURES_SETUP hcm_srv
+               TIMEOUT 800)
+       set_tests_properties(ki_hcm_srv PROPERTIES
+               FIXTURES_CLEANUP hcm_srv)
 
-set(requirements 1)
-require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+       set_tests_properties(st_hcmp_srv PROPERTIES
+                       WORKING_DIRECTORY .
+               FIXTURES_SETUP hcmp_srv
+               TIMEOUT 800)
+       set_tests_properties(ki_hcmp_srv PROPERTIES
+               FIXTURES_CLEANUP hcmp_srv)
 
-if (requirements)
-       add_executable(${SAMP} ${SRCS})
+       #
+       # Tests against local server peer
+       #
+
+       add_test(NAME http-client-multi COMMAND lws-minimal-http-client-multi
+                       -l --port ${PORT_HCM_SRV} -d 1151)
+       add_test(NAME http-client-multi-h1 COMMAND lws-minimal-http-client-multi
+                       --h1 -l --port ${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-pipe COMMAND lws-minimal-http-client-multi
+                       -p -l --port ${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-h1-pipe COMMAND lws-minimal-http-client-multi
+                       --h1 -p -l --port ${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-stag COMMAND lws-minimal-http-client-multi
+                       -s -l --port ${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-stag-h1 COMMAND lws-minimal-http-client-multi
+                       --h1 -s -l --port ${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-stag-pipe COMMAND lws-minimal-http-client-multi
+                       -p -s -l --port ${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-stag-h1-pipe COMMAND lws-minimal-http-client-multi
+                       --h1 -p -s -l --port ${PORT_HCM_SRV} -d1151)
+
+       # confirm that the pipelined mode really is doing it in one connection
+       add_test(NAME http-client-multi-restrict-pipe COMMAND lws-minimal-http-client-multi -d1151 --limit 1 -p -l --port ${PORT_HCM_SRV})
+       add_test(NAME http-client-multi-restrict-h1-pipe COMMAND lws-minimal-http-client-multi -d1151 --limit 1 --h1 -p -l --port ${PORT_HCM_SRV})
+       add_test(NAME http-client-multi-restrict-stag-pipe COMMAND lws-minimal-http-client-multi -d1151 --limit 1 -p -s -l --port ${PORT_HCM_SRV})
+       add_test(NAME http-client-multi-restrict-stag-h1-pipe COMMAND lws-minimal-http-client-multi -d1151 --limit 1 --h1 -p -s -l --port ${PORT_HCM_SRV})
+       # confirm that we do fail with a one connection limit and no pipelining
+       add_test(NAME http-client-multi-restrict-nopipe-fail COMMAND lws-minimal-http-client-multi --limit 1 -l --port ${PORT_HCM_SRV} -d1151)
+       set_property(TEST http-client-multi-restrict-nopipe-fail PROPERTY WILL_FAIL TRUE)
+       add_test(NAME http-client-multi-restrict-h1-nopipe-fail COMMAND lws-minimal-http-client-multi --limit 1 --h1 -l --port ${PORT_HCM_SRV} -d1151)
+       set_property(TEST http-client-multi-restrict-h1-nopipe-fail PROPERTY WILL_FAIL TRUE)
+
+       set_tests_properties(http-client-multi-restrict-pipe
+                            http-client-multi-restrict-h1-pipe
+                            http-client-multi-restrict-stag-pipe
+                            http-client-multi-restrict-stag-h1-pipe
+                            http-client-multi-restrict-nopipe-fail
+                            http-client-multi-restrict-h1-nopipe-fail
+                            http-client-multi
+                            http-client-multi-h1
+                            http-client-multi-pipe
+                            http-client-multi-h1-pipe
+                            http-client-multi-stag
+                            http-client-multi-stag-h1
+                            http-client-multi-stag-pipe
+                            http-client-multi-stag-h1-pipe
+                            PROPERTIES
+                            FIXTURES_REQUIRED "hcm_srv"
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client-multi
+                            TIMEOUT 50)
+
+       # POSTs against local http-server-form-post
+       add_test(NAME http-client-multi-post COMMAND lws-minimal-http-client-multi
+                       --post -l --port 1${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-post-h1 COMMAND lws-minimal-http-client-multi
+                       --post --h1 -l --port 1${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-post-pipe COMMAND lws-minimal-http-client-multi
+                       --post -p -l --port 1${PORT_HCM_SRV} -d1151)
+       if (VALGRIND)
+               add_test(NAME http-client-multi-post-h1-pipe COMMAND ${VALGRIND} --tool=memcheck $<TARGET_FILE:lws-minimal-http-client-multi>
+                       --post --h1 -p -l --port 1${PORT_HCM_SRV} -d1151)       
+       else()
+               add_test(NAME http-client-multi-post-h1-pipe COMMAND lws-minimal-http-client-multi
+                       --post --h1 -p -l --port 1${PORT_HCM_SRV} -d1151)
+       endif()
+       add_test(NAME http-client-multi-post-stag COMMAND lws-minimal-http-client-multi
+                       --post -s -l -d1151 --port 1${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-post-stag-h1 COMMAND lws-minimal-http-client-multi
+                       --post --h1 -d1151 -s -l --port 1${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-post-stag-pipe COMMAND lws-minimal-http-client-multi
+                       --post -p -s -l --port 1${PORT_HCM_SRV} -d1151)
+       add_test(NAME http-client-multi-post-stag-h1-pipe COMMAND lws-minimal-http-client-multi
+                       --post --h1 -p -s -l --port 1${PORT_HCM_SRV} -d1151)
+       set_tests_properties(http-client-multi-post
+                            http-client-multi-post-h1
+                            http-client-multi-post-pipe
+                            http-client-multi-post-h1-pipe
+                            http-client-multi-post-stag
+                            http-client-multi-post-stag-h1
+                            http-client-multi-post-stag-pipe
+                            http-client-multi-post-stag-h1-pipe
+                            PROPERTIES
+                               FIXTURES_REQUIRED "hcmp_srv"
+                               WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client-multi
+                               TIMEOUT 20)
+
+endif(NOT WIN32 AND LWS_WITH_SERVER)
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 7eaac9d..784e5cb 100644 (file)
@@ -22,4 +22,9 @@ Option|Meaning
 --h1|Force http/1 only
 -l|Connect to server on https://localhost:7681 instead of https://warmcat.com:443
 -n|Read numbered files like /1.png, /2.png etc.  Default is just read /
-
+--uv|Use libuv event loop if lws built for it
+--event|Use libevent event loop if lws built for it
+--ev|Use libev event loop if lws built for it
+--post|POST to the server rather than GET
+-c<n>|Create n connections (n can be 1 .. 8)
+--path <path>|Force the URL path (should start with /)
\ No newline at end of file
index de348f6..d0d11f3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-minimal-http-client-multi
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
  * HTTP/1.0: Pipelining only possible if Keep-Alive: yes sent by server
  * HTTP/1.1: always possible... serializes requests
  * HTTP/2:   always possible... all requests sent as individual streams in parallel
+ *
+ * Note: stats are kept on tls session reuse and checked depending on mode
+ *
+ *  - default: no reuse expected (connections made too quickly at once)
+ *  - staggered, no pipeline: n - 1 reuse expected
+ *  - staggered, pipelined: no reuse expected
  */
 
 #include <libwebsockets.h>
 #include <signal.h>
 #include <assert.h>
 #include <time.h>
+#if !defined(WIN32)
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
 
 #define COUNT 8
 
-struct user {
+struct cliuser {
        int index;
 };
 
-static int interrupted, completed, failed, numbered, stagger_idx;
-static struct lws *client_wsi[COUNT];
-static struct user user[COUNT];
+static int completed, failed, numbered, stagger_idx, posting, count = COUNT,
+#if defined(LWS_WITH_TLS_SESSIONS)
+          reuse,
+#endif
+          staggered;
 static lws_sorted_usec_list_t sul_stagger;
 static struct lws_client_connect_info i;
-struct lws_context *context;
+static struct lws *client_wsi[COUNT];
+static char urlpath[64], intr;
+static struct lws_context *context;
+
+/* we only need this for tracking POST emit state */
+
+struct pss {
+       char body_part;
+};
+
+#if defined(LWS_WITH_TLS_SESSIONS) && !defined(LWS_WITH_MBEDTLS) && !defined(WIN32)
+
+/* this should work OK on win32, but not adapted for non-posix file apis */
+
+static int
+sess_save_cb(struct lws_context *cx, struct lws_tls_session_dump *info)
+{
+       char path[128];
+       int fd, n;
+
+       lws_snprintf(path, sizeof(path), "%s/lws_tls_sess_%s", (const char *)info->opaque,
+                       info->tag);
+       fd = open(path, LWS_O_WRONLY | O_CREAT | O_TRUNC, 0600);
+       if (fd < 0) {
+               lwsl_warn("%s: cannot open %s\n", __func__, path);
+               return 1;
+       }
+
+       n = (int)write(fd, info->blob, info->blob_len);
+
+       close(fd);
+
+       return n != (int)info->blob_len;
+}
+
+static int
+sess_load_cb(struct lws_context *cx, struct lws_tls_session_dump *info)
+{
+       struct stat sta;
+       char path[128];
+       int fd, n;
+
+       lws_snprintf(path, sizeof(path), "%s/lws_tls_sess_%s", (const char *)info->opaque,
+                       info->tag);
+       fd = open(path, LWS_O_RDONLY);
+       if (fd < 0)
+               return 1;
+
+       if (fstat(fd, &sta) || !sta.st_size)
+               goto bail;
+
+       info->blob = malloc((size_t)sta.st_size);
+       /* caller will free this */
+       if (!info->blob)
+               goto bail;
+
+       info->blob_len = (size_t)sta.st_size;
+
+       n = (int)read(fd, info->blob, info->blob_len);
+       close(fd);
+
+       return n != (int)info->blob_len;
+
+bail:
+       close(fd);
+
+       return 1;
+}
+#endif
+
+#if defined(LWS_WITH_CONMON)
+void
+dump_conmon_data(struct lws *wsi)
+{
+       const struct addrinfo *ai;
+       struct lws_conmon cm;
+       char ads[48];
+
+       lws_conmon_wsi_take(wsi, &cm);
+
+       lws_sa46_write_numeric_address(&cm.peer46, ads, sizeof(ads));
+       lwsl_notice("%s: peer %s, dns: %uus, sockconn: %uus, tls: %uus, txn_resp: %uus\n",
+                   __func__, ads,
+                   (unsigned int)cm.ciu_dns,
+                   (unsigned int)cm.ciu_sockconn,
+                   (unsigned int)cm.ciu_tls,
+                   (unsigned int)cm.ciu_txn_resp);
+
+       ai = cm.dns_results_copy;
+       while (ai) {
+               lws_sa46_write_numeric_address((lws_sockaddr46 *)ai->ai_addr, ads, sizeof(ads));
+               lwsl_notice("%s: DNS %s\n", __func__, ads);
+               ai = ai->ai_next;
+       }
+
+       /*
+        * This destroys the DNS list in the lws_conmon that we took
+        * responsibility for when we used lws_conmon_wsi_take()
+        */
+
+       lws_conmon_release(&cm);
+}
+#endif
 
 static int
 callback_http(struct lws *wsi, enum lws_callback_reasons reason,
              void *user, void *in, size_t len)
 {
-       struct user *u = (struct user *)user;
+       char buf[LWS_PRE + 1024], *start = &buf[LWS_PRE], *p = start,
+            *end = &buf[sizeof(buf) - LWS_PRE - 1];
+       int n, idx = (int)(intptr_t)lws_get_opaque_user_data(wsi);
+       struct pss *pss = (struct pss *)user;
 
        switch (reason) {
 
        case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
-               lwsl_user("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: resp %u\n",
-                               lws_http_client_http_response(wsi));
+               lwsl_user("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: idx: %d, resp %u\n",
+                               idx, lws_http_client_http_response(wsi));
+
+#if defined(LWS_WITH_TLS_SESSIONS) && !defined(LWS_WITH_MBEDTLS) && !defined(WIN32)
+               if (lws_tls_session_is_reused(wsi))
+                       reuse++;
+               else
+                       /*
+                        * Attempt to store any new session into
+                        * external storage
+                        */
+                       if (lws_tls_session_dump_save(lws_get_vhost_by_name(context, "default"),
+                                       i.host, (uint16_t)i.port,
+                                       sess_save_cb, "/tmp"))
+               lwsl_warn("%s: session save failed\n", __func__);
+#endif
                break;
 
        /* because we are protocols[0] ... */
        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
                lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
                         in ? (char *)in : "(null)");
-               client_wsi[u->index] = NULL;
+               client_wsi[idx] = NULL;
                failed++;
-               if (++completed == COUNT) {
-                       lwsl_err("Done: failed: %d\n", failed);
-                       interrupted = 1;
-               }
-               break;
+
+#if defined(LWS_WITH_CONMON)
+               dump_conmon_data(wsi);
+#endif
+
+               goto finished;
 
        /* chunks of chunked content, with header removed */
        case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
-               lwsl_user("RECEIVE_CLIENT_HTTP_READ: conn %d: read %d\n",
-                       u->index, (int)len);
-#if 0  /* enable to dump the html */
-               {
-                       const char *p = in;
-
-                       while (len--)
-                               if (*p < 0x7f)
-                                       putchar(*p++);
-                               else
-                                       putchar('.');
-               }
-#endif
+               lwsl_user("RECEIVE_CLIENT_HTTP_READ: conn %d: read %d\n", idx, (int)len);
+               lwsl_hexdump_info(in, len);
                return 0; /* don't passthru */
 
+       case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
+
+               /*
+                * Tell lws we are going to send the body next...
+                */
+               if (posting && !lws_http_is_redirected_to_get(wsi)) {
+                       lwsl_user("%s: conn %d, doing POST flow\n", __func__, idx);
+                       lws_client_http_body_pending(wsi, 1);
+                       lws_callback_on_writable(wsi);
+               } else
+                       lwsl_user("%s: conn %d, doing GET flow\n", __func__, idx);
+               break;
+
        /* uninterpreted http content */
        case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
                {
@@ -102,34 +237,89 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
                return 0; /* don't passthru */
 
        case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
-               lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP %p: idx %d\n",
-                         wsi, u->index);
-               client_wsi[u->index] = NULL;
-               if (++completed == COUNT) {
-                       if (!failed)
-                               lwsl_user("Done: all OK\n");
-                       else
-                               lwsl_err("Done: failed: %d\n", failed);
-                       interrupted = 1;
-                       /* so we exit immediately */
-                       lws_cancel_service(lws_get_context(wsi));
-               }
-               break;
+               lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP %s: idx %d\n",
+                         lws_wsi_tag(wsi), idx);
+               client_wsi[idx] = NULL;
+               goto finished;
 
        case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
-               if (u && client_wsi[u->index]) {
+               lwsl_info("%s: closed: %s\n", __func__, lws_wsi_tag(client_wsi[idx]));
+
+#if defined(LWS_WITH_CONMON)
+               dump_conmon_data(wsi);
+#endif
+
+               if (client_wsi[idx]) {
                        /*
                         * If it completed normally, it will have been set to
                         * NULL then already.  So we are dealing with an
                         * abnormal, failing, close
                         */
-                       client_wsi[u->index] = NULL;
+                       client_wsi[idx] = NULL;
                        failed++;
-                       if (++completed == COUNT) {
-                               lwsl_err("Done: failed: %d\n", failed);
-                               interrupted = 1;
-                       }
+                       goto finished;
+               }
+               break;
+
+       case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
+               if (!posting)
+                       break;
+               if (lws_http_is_redirected_to_get(wsi))
+                       break;
+               lwsl_info("LWS_CALLBACK_CLIENT_HTTP_WRITEABLE: %s, idx %d,"
+                               " part %d\n", lws_wsi_tag(wsi), idx, pss->body_part);
+
+               n = LWS_WRITE_HTTP;
+
+               /*
+                * For a small body like this, we could prepare it in memory and
+                * send it all at once.  But to show how to handle, eg,
+                * arbitrary-sized file payloads, or huge form-data fields, the
+                * sending is done in multiple passes through the event loop.
+                */
+
+               switch (pss->body_part++) {
+               case 0:
+                       if (lws_client_http_multipart(wsi, "text", NULL, NULL,
+                                                     &p, end))
+                               return -1;
+                       /* notice every usage of the boundary starts with -- */
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "my text field\xd\xa");
+                       break;
+               case 1:
+                       if (lws_client_http_multipart(wsi, "file", "myfile.txt",
+                                                     "text/plain", &p, end))
+                               return -1;
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                       "This is the contents of the "
+                                       "uploaded file.\xd\xa"
+                                       "\xd\xa");
+                       break;
+               case 2:
+                       if (lws_client_http_multipart(wsi, NULL, NULL, NULL,
+                                                     &p, end))
+                               return -1;
+                       lws_client_http_body_pending(wsi, 0);
+                        /* necessary to support H2, it means we will write no
+                         * more on this stream */
+                       n = LWS_WRITE_HTTP_FINAL;
+                       break;
+
+               default:
+                       /*
+                        * We can get extra callbacks here, if nothing to do,
+                        * then do nothing.
+                        */
+                       return 0;
                }
+
+               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff_size_t(p, start), (enum lws_write_protocol)n)
+                               != lws_ptr_diff(p, start))
+                       return 1;
+
+               if (n != LWS_WRITE_HTTP_FINAL)
+                       lws_callback_on_writable(wsi);
+
                break;
 
        default:
@@ -137,17 +327,131 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
        }
 
        return lws_callback_http_dummy(wsi, reason, user, in, len);
+
+finished:
+       if (++completed == count) {
+               if (!failed)
+                       lwsl_user("Done: all OK\n");
+               else
+                       lwsl_err("Done: failed: %d\n", failed);
+               intr = 1;
+               /*
+                * This is how we can exit the event loop even when it's an
+                * event library backing it... it will start and stage the
+                * destroy to happen after we exited this service for each pt
+                */
+               lws_context_destroy(lws_get_context(wsi));
+       }
+
+       return 0;
 }
 
 static const struct lws_protocols protocols[] = {
-       { "http", callback_http, 0, 0, },
-       { NULL, NULL, 0, 0 }
+       { "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+#if defined(LWS_WITH_SYS_METRICS)
+
+static int
+my_metric_report(lws_metric_pub_t *mp)
+{
+       lws_metric_bucket_t *sub = mp->u.hist.head;
+       char buf[192];
+
+       do {
+               if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
+                       lwsl_user("%s: %s\n", __func__, buf);
+       } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
+
+       /* 0 = leave metric to accumulate, 1 = reset the metric */
+
+       return 1;
+}
+
+static const lws_system_ops_t system_ops = {
+       .metric_report = my_metric_report,
 };
 
+#endif
+
+static void
+stagger_cb(lws_sorted_usec_list_t *sul);
+
+static void
+lws_try_client_connection(struct lws_client_connect_info *i, int m)
+{
+       char path[128];
+
+       if (numbered) {
+               lws_snprintf(path, sizeof(path), "/%d.png", m + 1);
+               i->path = path;
+       } else
+               i->path = urlpath;
+
+       i->pwsi = &client_wsi[m];
+       i->opaque_user_data = (void *)(intptr_t)m;
+
+       if (!lws_client_connect_via_info(i)) {
+               failed++;
+               lwsl_user("%s: failed: conn idx %d\n", __func__, m);
+               if (++completed == count) {
+                       lwsl_user("Done: failed: %d\n", failed);
+                       lws_context_destroy(context);
+               }
+       } else
+               lwsl_user("started connection %s: idx %d (%s)\n",
+                         lws_wsi_tag(client_wsi[m]), m, i->path);
+}
+
+
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                  int current, int target)
+{
+       struct lws_context *context = mgr->parent;
+       int m;
+
+       if (current != LWS_SYSTATE_OPERATIONAL || target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       /* all the system prerequisites are ready */
+
+       if (!staggered)
+               /*
+                * just pile on all the connections at once, testing the
+                * pipeline queuing before the first is connected
+                */
+               for (m = 0; m < count; m++)
+                       lws_try_client_connection(&i, m);
+       else
+               /*
+                * delay the connections slightly
+                */
+               lws_sul_schedule(context, 0, &sul_stagger, stagger_cb,
+                                50 * LWS_US_PER_MS);
+
+       return 0;
+}
+
+static void
+signal_cb(void *handle, int signum)
+{
+       switch (signum) {
+       case SIGTERM:
+       case SIGINT:
+               break;
+       default:
+               lwsl_err("%s: signal %d\n", __func__, signum);
+               break;
+       }
+       lws_context_destroy(context);
+}
+
 static void
 sigint_handler(int sig)
 {
-       interrupted = 1;
+       signal_cb(NULL, sig);
 }
 
 #if defined(WIN32)
@@ -179,33 +483,7 @@ unsigned long long us(void)
 
        gettimeofday(&t, NULL);
 
-       return (t.tv_sec * 1000000ull) + t.tv_usec;
-}
-
-static void
-lws_try_client_connection(struct lws_client_connect_info *i, int m)
-{
-       char path[128];
-
-       if (numbered) {
-               lws_snprintf(path, sizeof(path), "/%d.png", m + 1);
-               i->path = path;
-       } else
-               i->path = "/";
-
-       i->pwsi = &client_wsi[m];
-       user[m].index = m;
-       i->userdata = &user[m];
-
-       if (!lws_client_connect_via_info(i)) {
-               failed++;
-               if (++completed == COUNT) {
-                       lwsl_user("Done: failed: %d\n", failed);
-                       interrupted = 1;
-               }
-       } else
-               lwsl_user("started connection %p: idx %d (%s)\n",
-                         client_wsi[m], m, i->path);
+       return ((unsigned long long)t.tv_sec * 1000000ull) + (unsigned long long)t.tv_usec;
 }
 
 static void
@@ -220,45 +498,61 @@ stagger_cb(lws_sorted_usec_list_t *sul)
         */
        lws_try_client_connection(&i, stagger_idx++);
 
-       if (stagger_idx == (int)LWS_ARRAY_SIZE(client_wsi))
+       if (stagger_idx == count)
                return;
 
-       next = 300 * LWS_US_PER_MS;
-       if (stagger_idx == (int)LWS_ARRAY_SIZE(client_wsi) - 1)
-               next += 700 * LWS_US_PER_MS;
+       next = 150 * LWS_US_PER_MS;
+       if (stagger_idx == count - 1)
+               next += 400 * LWS_US_PER_MS;
+
+#if defined(LWS_WITH_TLS_SESSIONS)
+       if (stagger_idx == 1)
+               next += 600 * LWS_US_PER_MS;
+#endif
 
        lws_sul_schedule(context, 0, &sul_stagger, stagger_cb, next);
 }
 
 int main(int argc, const char **argv)
 {
+       lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
+                                               system_notify_cb, "app" };
+       lws_state_notify_link_t *na[] = { &notifier, NULL };
        struct lws_context_creation_info info;
        unsigned long long start;
        const char *p;
-       int n = 0, m, staggered = 0, logs =
-               LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
-               /* for LLL_ verbosity above NOTICE to be built into lws,
-                * lws must have been configured and built with
-                * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
-               /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
-               /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
-               /* | LLL_DEBUG */;
-
-       signal(SIGINT, sigint_handler);
+#if defined(LWS_WITH_TLS_SESSIONS)
+       int pl = 0;
+#endif
 
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
        memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
 
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       info.signal_cb = signal_cb;
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+
+       if (lws_cmdline_option(argc, argv, "--uv"))
+               info.options |= LWS_SERVER_OPTION_LIBUV;
+       else
+               if (lws_cmdline_option(argc, argv, "--event"))
+                       info.options |= LWS_SERVER_OPTION_LIBEVENT;
+               else
+                       if (lws_cmdline_option(argc, argv, "--ev"))
+                               info.options |= LWS_SERVER_OPTION_LIBEV;
+                       else
+                               if (lws_cmdline_option(argc, argv, "--glib"))
+                                       info.options |= LWS_SERVER_OPTION_GLIB;
+                               else
+                                       signal(SIGINT, sigint_handler);
+
        staggered = !!lws_cmdline_option(argc, argv, "-s");
-       if ((p = lws_cmdline_option(argc, argv, "-d")))
-               logs = atoi(p);
 
-       lws_set_log_level(logs, NULL);
        lwsl_user("LWS minimal http client [-s (staggered)] [-p (pipeline)]\n");
        lwsl_user("   [--h1 (http/1 only)] [-l (localhost)] [-d <logs>]\n");
-       lwsl_user("   [-n (numbered)]\n");
+       lwsl_user("   [-n (numbered)] [--post]\n");
 
-       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
-       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
        info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
        info.protocols = protocols;
        /*
@@ -269,8 +563,14 @@ int main(int argc, const char **argv)
         * network wsi) that we will use.
         */
        info.fd_limit_per_thread = 1 + COUNT + 1;
+       info.register_notifier_list = na;
+       info.pcontext = &context;
+
+#if defined(LWS_WITH_SYS_METRICS)
+       info.system_ops = &system_ops;
+#endif
 
-#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
        /*
         * OpenSSL uses the system trust store.  mbedTLS has to be told which
         * CA to trust explicitly.
@@ -278,66 +578,128 @@ int main(int argc, const char **argv)
        info.client_ssl_ca_filepath = "./warmcat.com.cer";
 #endif
 
+       /* vhost option allowing tls session reuse, requires
+        * LWS_WITH_TLS_SESSIONS build option */
+       if (lws_cmdline_option(argc, argv, "--no-tls-session-reuse"))
+               info.options |= LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE;
+
+       if ((p = lws_cmdline_option(argc, argv, "--limit")))
+               info.simultaneous_ssl_restriction = atoi(p);
+
+       if ((p = lws_cmdline_option(argc, argv, "--ssl-handshake-serialize")))
+               /* We only consider simultaneous_ssl_restriction > 1 use cases.
+                * If ssl isn't limited or only 1 is allowed, we don't care.
+                */
+               info.simultaneous_ssl_handshake_restriction = atoi(p);
+
        context = lws_create_context(&info);
        if (!context) {
                lwsl_err("lws init failed\n");
                return 1;
        }
 
+#if defined(LWS_ROLE_H2) && defined(LWS_ROLE_H1)
+       i.alpn = "h2,http/1.1";
+#elif defined(LWS_ROLE_H2)
+       i.alpn = "h2";
+#elif defined(LWS_ROLE_H1)
+       i.alpn = "http/1.1";
+#endif
+
        i.context = context;
-       i.ssl_connection = LCCSCF_USE_SSL;
+       i.ssl_connection = LCCSCF_USE_SSL |
+                          LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
+                          LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
+
+       if (lws_cmdline_option(argc, argv, "--post")) {
+               posting = 1;
+               i.method = "POST";
+               i.ssl_connection |= LCCSCF_HTTP_MULTIPART_MIME;
+       } else
+               i.method = "GET";
 
        /* enables h1 or h2 connection sharing */
-       if (lws_cmdline_option(argc, argv, "-p"))
+       if (lws_cmdline_option(argc, argv, "-p")) {
                i.ssl_connection |= LCCSCF_PIPELINE;
+#if defined(LWS_WITH_TLS_SESSIONS)
+               pl = 1;
+#endif
+       }
+
+#if defined(LWS_WITH_CONMON)
+       if (lws_cmdline_option(argc, argv, "--conmon"))
+               i.ssl_connection |= LCCSCF_CONMON;
+#endif
 
        /* force h1 even if h2 available */
        if (lws_cmdline_option(argc, argv, "--h1"))
                i.alpn = "http/1.1";
 
+       strcpy(urlpath, "/");
+
        if (lws_cmdline_option(argc, argv, "-l")) {
                i.port = 7681;
                i.address = "localhost";
                i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
+               if (posting)
+                       strcpy(urlpath, "/formtest");
        } else {
                i.port = 443;
-               i.address = "warmcat.com";
+               i.address = "libwebsockets.org";
+               if (posting)
+                       strcpy(urlpath, "/testserver/formtest");
        }
 
+       if (lws_cmdline_option(argc, argv, "--no-tls"))
+               i.ssl_connection &= ~(LCCSCF_USE_SSL);
+
        if (lws_cmdline_option(argc, argv, "-n"))
                numbered = 1;
 
+       if ((p = lws_cmdline_option(argc, argv, "--server")))
+               i.address = p;
+
        if ((p = lws_cmdline_option(argc, argv, "--port")))
                i.port = atoi(p);
 
+       if ((p = lws_cmdline_option(argc, argv, "--path")))
+               lws_strncpy(urlpath, p, sizeof(urlpath));
+
+       if ((p = lws_cmdline_option(argc, argv, "-c")))
+               if (atoi(p) <= COUNT && atoi(p))
+                       count = atoi(p);
+
        i.host = i.address;
        i.origin = i.address;
-       i.method = "GET";
        i.protocol = protocols[0].name;
 
-       if (!staggered)
-               /*
-                * just pile on all the connections at once, testing the
-                * pipeline queuing before the first is connected
-                */
-               for (m = 0; m < (int)LWS_ARRAY_SIZE(client_wsi); m++)
-                       lws_try_client_connection(&i, m);
-       else
-               /*
-                * delay the connections slightly
-                */
-               lws_sul_schedule(context, 0, &sul_stagger, stagger_cb,
-                                100 * LWS_US_PER_MS);
+#if defined(LWS_WITH_TLS_SESSIONS) && !defined(LWS_WITH_MBEDTLS) && !defined(WIN32)
+       /*
+        * Attempt to preload a session from external storage
+        */
+       if (lws_tls_session_dump_load(lws_get_vhost_by_name(context, "default"),
+                                 i.host, (uint16_t)i.port, sess_load_cb, "/tmp"))
+               lwsl_warn("%s: session load failed\n", __func__);
+#endif
 
        start = us();
-       m = 0;
-       while (n >= 0 && !interrupted)
-               n = lws_service(context, 0);
+       while (!intr && !lws_service(context, 0))
+               ;
+
+#if defined(LWS_WITH_TLS_SESSIONS)
+       lwsl_user("%s: session reuse count %d\n", __func__, reuse);
+
+       if (staggered && !pl && !reuse) {
+               lwsl_err("%s: failing, expected 1 .. %d reused\n", __func__, count - 1);
+               // too difficult to reproduce in CI
+               // failed = 1;
+       }
+#endif
 
        lwsl_user("Duration: %lldms\n", (us() - start) / 1000);
        lws_context_destroy(context);
 
-       lwsl_user("Exiting with %d\n", failed || completed != COUNT);
+       lwsl_user("Exiting with %d\n", failed || completed != count);
 
-       return failed || completed != COUNT;
+       return failed || completed != count;
 }
diff --git a/minimal-examples/http-client/minimal-http-client-multi/selftest.sh b/minimal-examples/http-client/minimal-http-client-multi/selftest.sh
deleted file mode 100755 (executable)
index 49d61a1..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=16
-
-dotest $1 $2 warmcat
-dotest $1 $2 warmcat-pipe -p
-dotest $1 $2 warmcat-h1 --h1
-dotest $1 $2 warmcat-h1-pipe --h1 -p
-dotest $1 $2 warmcat-stag -s
-dotest $1 $2 warmcat-pipe-stag -p -s
-dotest $1 $2 warmcat-h1-stag --h1 -s
-dotest $1 $2 warmcat-h1-pipe-stag --h1 -p -s
-
-spawn "" $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost -l
-spawn $SPID $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost-pipe -l -p
-spawn $SPID $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost-h1 -l --h1
-spawn $SPID $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost-h1-pipe -l --h1 -p
-spawn $SPID $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost-stag -l -s
-spawn $SPID $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost-pipe-stag -l -p -s
-spawn $SPID $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost-h1-stag -l --h1 -s
-spawn $SPID $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost-h1-pipe-stag -l --h1 -p -s
-
-kill $SPID 2>/dev/null
-wait $SPID 2>/dev/null
-exit $FAILS
-
index 550393d..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFUDCCBDigAwIBAgISA4mJfIm3iCGbU9+o8YQa+4nUMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5MjNaFw0x
-OTEyMDYwNzA5MjNaMBYxFDASBgNVBAMTC3dhcm1jYXQuY29tMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwnEoH9JW3GvpadpxHGZPb5wv1Q6KfAIMWtdq
-YCOfotFxaYULuzHVxmrTTgmEqJr+eBqUBkXKmGuRR/9UipOmTu5j02qFyWHotFdF
-ZGyp//8z+Rle9Qt1nL68oNIZLDtWkybh5x00b1uo4eyEszXUaa0aLqKP3lH7Q4jI
-aSVARZ8snrJR640Gp3ByudvNTYkGz469bpWzRC/8wSNtzzY02DvHs1GxQx9tMXw+
-BbtUxeP7lpYFKEFBjgZaIKLv+4g8ItJIuO7gMSzG2JfpQHxdhrlhxpx7dsaMUcyM
-nnYXysNL5JG3KEMhkxbtdpCaEQ8jLSPbl/rnF/+mgce+lSjMuQIDAQABo4ICYjCC
-Al4wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
-AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSI9ai12zLFeNTEDHKI9Ghkqcpa2TAf
-BgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEw
-LgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcw
-LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
-MBYGA1UdEQQPMA2CC3dhcm1jYXQuY29tMEwGA1UdIARFMEMwCAYGZ4EMAQIBMDcG
-CysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5
-cHQub3JnMIIBBgYKKwYBBAHWeQIEAgSB9wSB9ADyAHcAY/Lbzeg7zCzPC3KEJ1dr
-M6SNYXePvXWmOLHHaFRL2I0AAAFtCsVHHAAABAMASDBGAiEAy0q1cR4VwPL3iviL
-cBWN67kjJRXk+DwhodmeoM3kb3gCIQC2soAHFs0Umo+0RNdFrL41+hMuidh2cXbb
-Ovc6nh5tOQB3AOJpS64m6OlACeiGG7Y7g9Q+5/50iPukjyiTAZ3d8dv+AAABbQrF
-R48AAAQDAEgwRgIhANqKQm4t9by263CJ7/DLOaZCjtcK29KgJjPwhv08UMn1AiEA
-h35nGTASR8/E7xz+56ZUleqD7U1ABFgWZRZskIzsFO8wDQYJKoZIhvcNAQELBQAD
-ggEBADDJBVbKe2LPHmi8k2vxErB3Y0Ty+3gwgPEXKYtEvQ7tos89eE+QmOXAzH5J
-GwRarFf7kzmKeJv04tMebiEtshpap47oJfxCxfrtpja8hP8Cdu/v/Ae6eEzu3yet
-0N08GJdxQKfgCFaoGUptbaF2RCIZS12SVcX4TPpdP+xaiZdmIx4dGM6tReQ8+y8B
-10b4Hi2+d/zW0W1z6+FAemU6yleWriJDUik5oas9XZF5LAAMDb/WgF5eIB6P9CUG
-LuAO8lWlk9nBgXvMLTxZ74SJb17H4kFEIrIjvABNshz5gBW8xw9nfr5YIfANtwEj
-BDsq06Df3UORYVs/j3T97gPAEZ4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
index 9fe8d51..b4e4b74 100644 (file)
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-client-post C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-client-post)
 set(SRCS minimal-http-client-post.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
+set(requirements 1)
+set(MBEDTLS 0)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
+require_lws_config(LWS_WITH_MBEDTLS 1 MBEDTLS)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+       find_program(VALGRIND "valgrind")
+       
+       #
+       # instantiate the server per sai builder instance, they are running in the same
+       # machine context in parallel so they can tread on each other otherwise
+       #
+       set(PORT_HCP_SRV "7640")
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0")
+               set(PORT_HCP_SRV 7641)
        endif()
-       else()
-               set(rq 0)
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1")
+               set(PORT_HCP_SRV 7642)
        endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2")
+               set(PORT_HCP_SRV 7643)
        endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3")
+               set(PORT_HCP_SRV 7644)
+       endif()
+       
+# hack
+if (NOT WIN32 AND LWS_WITH_SERVER)
+
+       #
+       # Tests against built server running locally (needs daemonization...)
+       #
 
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
+if (WIN32)
+       add_test(NAME st_hcp_srv COMMAND cmd.exe /c start /b $<TARGET_FILE:test-server> -s --port ${PORT_HCP_SRV})
+       add_test(NAME ki_hcp_srv COMMAND taskkill /F /IM $<TARGET_FILE_NAME:test-server> /T)
+else()
+       #
+       # mbedtls is too slow to keep up on some targets, when ctest is in parallel
+       #
+       if (VALGRIND AND NOT MBEDTLS)
+               add_test(NAME st_hcp_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                                       hcp_srv ${VALGRIND} --tool=memcheck 
+                                       $<TARGET_FILE:test-server>
+                                       -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/
+                                       -s --port ${PORT_HCP_SRV} -d1151)
+               add_test(NAME ki_hcp_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh hcp_srv ${VALGRIND}
+                                       $<TARGET_FILE_NAME:test-server> --port ${PORT_HCP_SRV})
        else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
+               add_test(NAME st_hcp_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                                       hcp_srv
+                                       $<TARGET_FILE:test-server>
+                                       -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/
+                                       -s --port ${PORT_HCP_SRV} )
+               add_test(NAME ki_hcp_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh hcp_srv
+                                       $<TARGET_FILE_NAME:test-server> --port ${PORT_HCP_SRV})
        endif()
-ENDMACRO()
+endif()
 
+       set_tests_properties(st_hcp_srv PROPERTIES
+                                            WORKING_DIRECTORY .
+                                            FIXTURES_SETUP hcp_srv
+                                            TIMEOUT 800)
+       set_tests_properties(ki_hcp_srv PROPERTIES
+                                            FIXTURES_CLEANUP hcp_srv)
 
-set(requirements 1)
-require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+       add_test(NAME http-client-post COMMAND
+               lws-minimal-http-client-post -l --port ${PORT_HCP_SRV})
+       add_test(NAME http-client-post-m COMMAND
+               lws-minimal-http-client-post -l -m --port ${PORT_HCP_SRV})
+       add_test(NAME http-client-post-h1 COMMAND
+               lws-minimal-http-client-post -l --h1 --port ${PORT_HCP_SRV})
+       add_test(NAME http-client-post-m-h1 COMMAND
+               lws-minimal-http-client-post -l -m --h1 --port ${PORT_HCP_SRV})
+       set_tests_properties(http-client-post
+                            http-client-post-m
+                            http-client-post-h1
+                            http-client-post-m-h1
+                            PROPERTIES
+                            FIXTURES_REQUIRED "hcp_srv"
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client-post
+                            TIMEOUT 20)
+endif()
 
-if (requirements)
-       add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 4a9fb35..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFWjCCBEKgAwIBAgISA9x0/oj5PLdW46hsmR82/7ytMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5NDBaFw0x
-OTEyMDYwNzA5NDBaMBwxGjAYBgNVBAMTEWxpYndlYnNvY2tldHMub3JnMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPinIkleLmvEcA/YuBss6ASXVi7g
-yr6Sss7cB3vTy7Fp8OB2c1N25prHZxVpORAUo0UreiaY2Ws4NFvDaYp08ZffevuC
-UhThsEJlbkD0uvt7dPapJt9PNJtlxjNFWyvHEy6PijzIaMYDROiStcCJQn7kAew/
-Za2+5kNVgKqT+7OXukJEFdSdVZI6QC/npeQlkIrFSq1WVthCGBNJehxxES0hSWzk
-0gNVKlkD3/SbkupsfUpe73XiawMtrtsSE7cdnul7VZmiP8I/3sJr1+4/3xZ+DEYg
-mVB82B0vd08VJYzU7Nf0pz0PWusAmzRoRn81IXkOfBg9ohlSSEoZhHYS7QIDAQAB
-o4ICZjCCAmIwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
-BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRmKKyGjufWgp7pR2x0tWxG
-D9G+WTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcB
-AQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlw
-dC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlw
-dC5vcmcvMBwGA1UdEQQVMBOCEWxpYndlYnNvY2tldHMub3JnMEwGA1UdIARFMEMw
-CAYGZ4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9j
-cHMubGV0c2VuY3J5cHQub3JnMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcAdH7a
-gzGtMxCRIZzOJU9CcMK//V5CIAjGNzV55hB7zFYAAAFtCsWIfgAABAMASDBGAiEA
-0H55VqSKV3otHK7uHNbcR0QwoUYtCmeObhsqxzCnmDwCIQD3mtuSKrxTD3oA+Yde
-nmTgWfFyS4TNgLNEPCJYo2s75gB1ACk8UZZUyDlluqpQ/FgH1Ldvv1h6KXLcpMMM
-9OVFR/R4AAABbQrFil4AAAQDAEYwRAIgNSpvz/1JA2aP6fh6ujGNuYfrAvWjlxXo
-CJtVGe4XaDYCIGmK1/9tl1uQbVD46P5NswnULq06KQmuOrlI3HO4r86HMA0GCSqG
-SIb3DQEBCwUAA4IBAQBiAlV7wkCsWE99VmZHBmcbZChWyWUHG3LM1hnaQRQjTSYk
-CIlauCpWzlUd6weuvra85KqBbCYo+1hxbwITI796uAdgtHmBE8nj0VltHwKeSq2s
-KKiGXBRT7Z7t0VHYSLOlGOVn1auuQFaWBArc0cQ/m1ZsoHvOiHTlKQvVsA4HnIxA
-CjGY9OOQoh0c36ecbJZ44XKnU9J/OXtDx00aW6QodaZmgMp/OOCghFQUvufkgTUL
-LZid873/8dJVWjAaj1VdadO1nSbdAfBbeWXy93+vg1aAoig80RoscrzYCaNlwmR7
-EO5zWxL3l+xUZogQSJuICgUgNzVB3wjn8HeHGsqt
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
index d6b080a..3bff115 100644 (file)
@@ -21,7 +21,6 @@ static int interrupted, bad = 0, status, count_clients = 1, completed;
 static struct lws *client_wsi[4];
 
 struct pss {
-       char boundary[32];
        char body_part;
 };
 
@@ -31,9 +30,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
 {
        struct pss *pss = (struct pss *)user;
        char buf[LWS_PRE + 1024], *start = &buf[LWS_PRE], *p = start,
-               *end = &buf[sizeof(buf) - 1];
-       uint8_t **up, *uend;
-       uint32_t r;
+               *end = &buf[sizeof(buf) - LWS_PRE - 1];
        int n;
 
        switch (reason) {
@@ -61,7 +58,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
        /* ...callbacks related to receiving the result... */
 
        case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
-               status = lws_http_client_http_response(wsi);
+               status = (int)lws_http_client_http_response(wsi);
                lwsl_user("Connected with server response: %d\n", status);
                break;
 
@@ -96,36 +93,20 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
        /* ...callbacks related to generating the POST... */
 
        case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
-               lwsl_user("LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER\n");
-               up = (uint8_t **)in;
-               uend = *up + len - 1;
-
-               /* generate a random boundary string */
-
-               lws_get_random(lws_get_context(wsi), &r, sizeof(r));
-               lws_snprintf(pss->boundary, sizeof(pss->boundary) - 1,
-                               "---boundary-%08x", r);
-
-               n = lws_snprintf(buf, sizeof(buf) - 1,
-                       "multipart/form-data; boundary=%s", pss->boundary);
-               if (lws_add_http_header_by_token(wsi,
-                               WSI_TOKEN_HTTP_CONTENT_TYPE,
-                               (uint8_t *)buf, n, up, uend))
-                       return 1;
                /*
-                * Notice because we are sending multipart/form-data we can
-                * usually rely on the server to understand where the form
-                * payload ends without having to give it an overall
-                * content-length (which can be troublesome to compute ahead
-                * of generating the data to send).
-                *
                 * Tell lws we are going to send the body next...
                 */
-               lws_client_http_body_pending(wsi, 1);
-               lws_callback_on_writable(wsi);
+               if (!lws_http_is_redirected_to_get(wsi)) {
+                       lwsl_user("%s: doing POST flow\n", __func__);
+                       lws_client_http_body_pending(wsi, 1);
+                       lws_callback_on_writable(wsi);
+               } else
+                       lwsl_user("%s: doing GET flow\n", __func__);
                break;
 
        case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
+               if (lws_http_is_redirected_to_get(wsi))
+                       break;
                lwsl_user("LWS_CALLBACK_CLIENT_HTTP_WRITEABLE\n");
                n = LWS_WRITE_HTTP;
 
@@ -138,28 +119,25 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
 
                switch (pss->body_part++) {
                case 0:
+                       if (lws_client_http_multipart(wsi, "text", NULL, NULL,
+                                                     &p, end))
+                               return -1;
                        /* notice every usage of the boundary starts with -- */
-                       p += lws_snprintf(p, end - p, "--%s\xd\xa"
-                               "content-disposition: "
-                                       "form-data; name=\"text\"\xd\xa"
-                               "\xd\xa"
-                               "my text field"
-                               "\xd\xa", pss->boundary);
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "my text field\xd\xa");
                        break;
                case 1:
-                       p += lws_snprintf(p, end - p,
-                               "--%s\xd\xa"
-                               "content-disposition: form-data; name=\"file\";"
-                               "filename=\"myfile.txt\"\xd\xa"
-                               "content-type: text/plain\xd\xa"
-                               "\xd\xa"
+                       if (lws_client_http_multipart(wsi, "file", "myfile.txt",
+                                                     "text/plain", &p, end))
+                               return -1;
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
                                        "This is the contents of the "
                                        "uploaded file.\xd\xa"
-                               "\xd\xa", pss->boundary);
+                                       "\xd\xa");
                        break;
                case 2:
-                       p += lws_snprintf(p, end - p, "--%s--\xd\xa",
-                                         pss->boundary);
+                       if (lws_client_http_multipart(wsi, NULL, NULL, NULL,
+                                                     &p, end))
+                               return -1;
                        lws_client_http_body_pending(wsi, 0);
                         /* necessary to support H2, it means we will write no
                          * more on this stream */
@@ -174,7 +152,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
                        return 0;
                }
 
-               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff(p, start), n)
+               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff_size_t(p, start), (enum lws_write_protocol)n)
                                != lws_ptr_diff(p, start))
                        return 1;
 
@@ -195,9 +173,9 @@ static const struct lws_protocols protocols[] = {
                "http",
                callback_http,
                sizeof(struct pss),
-               0,
+               0, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 }
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static void
@@ -212,28 +190,17 @@ int main(int argc, const char **argv)
        struct lws_client_connect_info i;
        struct lws_context *context;
        const char *p;
-       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
-                  /*
-                   * For LLL_ verbosity above NOTICE to be built into lws,
-                   * lws must have been configured and built with
-                   * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE
-                   *
-                   * | LLL_INFO   | LLL_PARSER  | LLL_HEADER | LLL_EXT |
-                   *   LLL_CLIENT | LLL_LATENCY | LLL_DEBUG
-                   */ ;
+       int n = 0;
 
        signal(SIGINT, sigint_handler);
 
-       if ((p = lws_cmdline_option(argc, argv, "-d")))
-               logs = atoi(p);
-
-       lws_set_log_level(logs, NULL);
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
        lwsl_user("LWS minimal http client - POST [-d<verbosity>] [-l] [--h1]\n");
 
        if (lws_cmdline_option(argc, argv, "-m"))
                count_clients = LWS_ARRAY_SIZE(client_wsi);
 
-       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
        info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
        info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
        info.protocols = protocols;
@@ -244,9 +211,9 @@ int main(int argc, const char **argv)
         * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
         * will use.
         */
-       info.fd_limit_per_thread = 1 + count_clients + 1;
+       info.fd_limit_per_thread = (unsigned int)(1 + count_clients + 1);
 
-#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
        /*
         * OpenSSL uses the system trust store.  mbedTLS has to be told which
         * CA to trust explicitly.
@@ -263,7 +230,7 @@ int main(int argc, const char **argv)
 
        memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
        i.context = context;
-       i.ssl_connection = LCCSCF_USE_SSL;
+       i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_HTTP_MULTIPART_MIME;
 
        if (lws_cmdline_option(argc, argv, "-l")) {
                i.port = 7681;
@@ -276,6 +243,12 @@ int main(int argc, const char **argv)
                i.path = "/testserver/formtest";
        }
 
+       if (lws_cmdline_option(argc, argv, "--form1"))
+               i.path = "/form1";
+
+       if ((p = lws_cmdline_option(argc, argv, "--port")))
+               i.port = atoi(p);
+
        i.host = i.address;
        i.origin = i.address;
        i.method = "POST";
@@ -288,6 +261,8 @@ int main(int argc, const char **argv)
 
        for (n = 0; n < count_clients; n++) {
                i.pwsi = &client_wsi[n];
+               lwsl_notice("%s: connecting to %s:%d\n", __func__,
+                           i.address, i.port);
                if (!lws_client_connect_via_info(&i))
                        completed++;
        }
diff --git a/minimal-examples/http-client/minimal-http-client-post/selftest.sh b/minimal-examples/http-client/minimal-http-client-post/selftest.sh
deleted file mode 100755 (executable)
index 2f887f2..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=8
-
-dotest $1 $2 warmcat
-dotest $1 $2 warmcat-h1 --h1
-dotest $1 $2 warmcat-m -m
-dotest $1 $2 warmcat-m-h1 -m --h1
-
-spawn "" $5 $1/libwebsockets-test-server -s
-dotest $1 $2 localhost -l
-spawn $SPID $5 $1/libwebsockets-test-server -s
-dotest $1 $2 localhost-h1 -l --h1
-spawn $SPID $5 $1/libwebsockets-test-server -s
-dotest $1 $2 localhost-m -l -m
-spawn $SPID $5 $1/libwebsockets-test-server -s
-dotest $1 $2 localhost-m-h1 -l -m --h1
-
-kill $SPID 2>/dev/null
-wait $SPID 2>/dev/null
-exit $FAILS
index 6181371..8c42ae9 100644 (file)
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-client C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-client)
 set(SRCS minimal-http-client.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
+set(has_fault_injection 1)
+set(has_h2 1)
+set(has_plugins 1)
+set(has_ss_policy_parse 1)
+set(has_no_system_vhost 1)
+set(has_async_dns 1)
+set(has_mbedtls 1)
 
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
+set(requirements 1)
 
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+require_lws_config(LWS_ROLE_H2 1 has_h2)
+require_lws_config(LWS_WITH_SYS_FAULT_INJECTION 1 has_fault_injection)
+require_lws_config(LWS_WITH_EVLIB_PLUGINS 1 has_plugins)
+require_lws_config(LWS_WITH_EVENT_LIBS 1 has_plugins)
+
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 has_ss_policy_parse)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 has_ss_policy_parse)
+
+require_lws_config(LWS_WITH_SYS_ASYNC_DNS 0 has_no_system_vhost)
+require_lws_config(LWS_WITH_SYS_NTPCLIENT 0 has_no_system_vhost)
+require_lws_config(LWS_WITH_SYS_DHCP_CLIENT 0 has_no_system_vhost)
+
+require_lws_config(LWS_WITH_SYS_ASYNC_DNS 1 has_async_dns)
+require_lws_config(LWS_WITH_MBEDTLS 1 has_mbedtls)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       find_program(VALGRIND "valgrind")
+       
+       sai_resource(warmcat_conns 1 40 http_client_warmcat)
+
+       if (LWS_CTEST_INTERNET_AVAILABLE)
+               set(mytests http-client-warmcat-h1)
+               if (has_h2)
+                       add_test(NAME http-client-warmcat COMMAND lws-minimal-http-client )
+                       list(APPEND mytests http-client-warmcat)
                endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
+
+
+               add_test(NAME http-client-warmcat-h1 COMMAND lws-minimal-http-client  --h1)
+                                    
+               if (has_fault_injection)
+               
+                       # creation related faults
+               
+                       list(APPEND mytests http-client-fi-ctx1)
+                       add_test(NAME http-client-fi-ctx1 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail1")
+                       
+                       # if (has_plugins)
+                       # !!! need to actually select an available evlib plugin to trigger this
+                       #       list(APPEND mytests http-client-fi-pi)
+                       #       add_test(NAME http-client-fi-pi COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_plugin_init")
+                       # endif()
+
+                       list(APPEND mytests http-client-fi-ctx2)
+                       add_test(NAME http-client-fi-ctx2 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_evlib_sel")
+                       
+                       list(APPEND mytests http-client-fi-ctx3)
+                       add_test(NAME http-client-fi-ctx3 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_oom_ctx")
+                       
+                       list(APPEND mytests http-client-fi-ctx4)
+                       add_test(NAME http-client-fi-ctx4 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_privdrop")
+
+                       list(APPEND mytests http-client-fi-ctx5)
+                       add_test(NAME http-client-fi-ctx5 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_maxfds")
+                       
+                       list(APPEND mytests http-client-fi-ctx6)
+                       add_test(NAME http-client-fi-ctx6 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_oom_fds")
+                       
+                       list(APPEND mytests http-client-fi-ctx7)
+                       add_test(NAME http-client-fi-ctx7 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_plat_init")
+                       
+                       list(APPEND mytests http-client-fi-ctx8)
+                       add_test(NAME http-client-fi-ctx8 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_evlib_init")
+                       
+                       list(APPEND mytests http-client-fi-ctx9)
+                       add_test(NAME http-client-fi-ctx9 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_evlib_pt")
+                       
+                       if (NOT has_no_system_vhost)
+                       
+                               list(APPEND mytests http-client-fi-ctx10)
+                               add_test(NAME http-client-fi-ctx10 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_sys_vh")
+                       
+                               list(APPEND mytests http-client-fi-ctx11)
+                               add_test(NAME http-client-fi-ctx11 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_sys_vh_init")
+                               
                        endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
+                       
+                       list(APPEND mytests http-client-fi-ctx12)
+                       add_test(NAME http-client-fi-ctx12 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "ctx_createfail_def_vh")
+                       
+
+                       list(APPEND mytests http-client-fi-vh1)
+                       add_test(NAME http-client-fi-vh1 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_oom")
+                       
+                       list(APPEND mytests http-client-fi-vh2)
+                       add_test(NAME http-client-fi-vh2 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_pcols_oom")
+                       
+                       list(APPEND mytests http-client-fi-vh3)
+                       add_test(NAME http-client-fi-vh3 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_ssl_srv")
+
+                       list(APPEND mytests http-client-fi-vh4)
+                       add_test(NAME http-client-fi-vh4 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_ssl_cli")
+                       
+                       list(APPEND mytests http-client-fi-vh5)
+                       add_test(NAME http-client-fi-vh5 COMMAND lws-minimal-http-client --expected-exit 5 --fault-injection "vh/vh_create_srv_init")
+
+
+                       list(APPEND mytests http-client-fi-dnsfail)
+                       add_test(NAME http-client-fi-dnsfail COMMAND lws-minimal-http-client --expected-exit 3 --fault-injection "wsi=user/dnsfail")
+                       
+                       if (has_async_dns)
+                               list(APPEND mytests http-client-fi-connfail)
+                               add_test(NAME http-client-fi-connfail COMMAND lws-minimal-http-client --expected-exit 2 --fault-injection "wsi=user/connfail")
                        else()
-                               set(MET 0)
+                               list(APPEND mytests http-client-fi-connfail)
+                               add_test(NAME http-client-fi-connfail COMMAND lws-minimal-http-client --expected-exit 2 --fault-injection "wsi=user/connfail")
                        endif()
+                       
+                       list(APPEND mytests http-client-fi-user-est-fail)
+                       add_test(NAME http-client-fi-user-est-fail COMMAND lws-minimal-http-client --expected-exit 3 --fault-injection "wsi/user_reject_at_est")        
+                       
                endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
+               if (has_mbedtls)
+                       list(APPEND mytests http-client-mbedtls-wrong-ca)
+                       add_test(NAME http-client-mbedtls-wrong-ca COMMAND lws-minimal-http-client -w --expected-exit 3)
+                       message("... adding mbedtls wrong CA test")
+               else()
+                       message("... skipping mbedtls wrong CA test")
                endif()
        
+               set_tests_properties(${mytests} PROPERTIES
+                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-client/minimal-http-client
+                    TIMEOUT 20)
+                                    
+               if (DEFINED ENV{SAI_OVN})
+                       set_tests_properties(${mytests} PROPERTIES
+                                            FIXTURES_REQUIRED "res_http_client_warmcat")
+               endif()         
+       
        endif()
-ENDMACRO()
-
-
-set(requirements 1)
-require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
-
-if (requirements)
-       add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
-endif()
\ No newline at end of file
+endif()
index 3113aa0..09df8ef 100644 (file)
@@ -21,6 +21,13 @@ Commandline option|Meaning
 -j|Apply tls option LCCSCF_ALLOW_SELFSIGNED
 -m|Apply tls option LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
 -e|Apply tls option LCCSCF_ALLOW_EXPIRED
+-b|Apply tls option LCCSCF_CACHE_COOKIES
+-w|For mbedtls/wolfssl, load wrong CA cert (expected to fail)
+-c <cookie jar file>|Set filepath used for cookie jar
+-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
+--nossl| disable ssl connection
+--user <username>| Set Basic Auth username
+--password <password> | Set Basic Auth password
 
 ```
  $ ./lws-minimal-http-client
@@ -61,4 +68,12 @@ Commandline option|Meaning
 [2018/03/04 14:43:23:3042] USER: Completed
 ```
 
+You can also test the client Basic Auth support against the http-server/minimal-http-server-basicauth
+example.  In one console window run the server and in the other
+
+```
+$ lws-minimal-http-client -l --nossl --path /secret/index.html --user user --password password
+```
+
+The Basic Auth credentials for the test server are literally username "user" and password "password".
 
index 54a420e..f151356 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-minimal-http-client
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
 #include <string.h>
 #include <signal.h>
 
-static int interrupted, bad = 1, status;
+static int interrupted, bad = 1, status, conmon;
+#if defined(LWS_WITH_HTTP2)
+static int long_poll;
+#endif
 static struct lws *client_wsi;
+static const char *ba_user, *ba_password;
+
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping = 3,
+       .secs_since_valid_hangup = 10,
+};
+
+#if defined(LWS_WITH_CONMON)
+void
+dump_conmon_data(struct lws *wsi)
+{
+       const struct addrinfo *ai;
+       struct lws_conmon cm;
+       char ads[48];
+
+       lws_conmon_wsi_take(wsi, &cm);
+
+       lws_sa46_write_numeric_address(&cm.peer46, ads, sizeof(ads));
+       lwsl_notice("%s: peer %s, dns: %uus, sockconn: %uus, tls: %uus, txn_resp: %uus\n",
+                   __func__, ads,
+                   (unsigned int)cm.ciu_dns,
+                   (unsigned int)cm.ciu_sockconn,
+                   (unsigned int)cm.ciu_tls,
+                   (unsigned int)cm.ciu_txn_resp);
+
+       ai = cm.dns_results_copy;
+       while (ai) {
+               lws_sa46_write_numeric_address((lws_sockaddr46 *)ai->ai_addr, ads, sizeof(ads));
+               lwsl_notice("%s: DNS %s\n", __func__, ads);
+               ai = ai->ai_next;
+       }
+
+       /*
+        * This destroys the DNS list in the lws_conmon that we took
+        * responsibility for when we used lws_conmon_wsi_take()
+        */
+
+       lws_conmon_release(&cm);
+}
+#endif
+
+static const char *ua = "Mozilla/5.0 (X11; Linux x86_64) "
+                       "AppleWebKit/537.36 (KHTML, like Gecko) "
+                       "Chrome/51.0.2704.103 Safari/537.36",
+                 *acc = "*/*";
 
 static int
 callback_http(struct lws *wsi, enum lws_callback_reasons reason,
@@ -29,28 +77,83 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
                lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
                         in ? (char *)in : "(null)");
-               client_wsi = NULL;
+               interrupted = 1;
+               bad = 3; /* connection failed before we could make connection */
+               lws_cancel_service(lws_get_context(wsi));
+
+#if defined(LWS_WITH_CONMON)
+       if (conmon)
+               dump_conmon_data(wsi);
+#endif
                break;
 
        case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
-               status = lws_http_client_http_response(wsi);
-               lwsl_user("Connected with server response: %d\n", status);
+               {
+                       char buf[128];
+
+                       lws_get_peer_simple(wsi, buf, sizeof(buf));
+                       status = (int)lws_http_client_http_response(wsi);
+
+                       lwsl_user("Connected to %s, http response: %d\n",
+                                       buf, status);
+               }
+#if defined(LWS_WITH_HTTP2)
+               if (long_poll) {
+                       lwsl_user("%s: Client entering long poll mode\n", __func__);
+                       lws_h2_client_stream_long_poll_rxonly(wsi);
+               }
+#endif
+
+               if (lws_fi_user_wsi_fi(wsi, "user_reject_at_est"))
+                       return -1;
+
                break;
 
+       /* you only need this if you need to do Basic Auth */
+       case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
+       {
+               unsigned char **p = (unsigned char **)in, *end = (*p) + len;
+
+               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_USER_AGENT,
+                               (unsigned char *)ua, (int)strlen(ua), p, end))
+                       return -1;
+
+               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ACCEPT,
+                               (unsigned char *)acc, (int)strlen(acc), p, end))
+                       return -1;
+#if defined(LWS_WITH_HTTP_BASIC_AUTH)
+               {
+               char b[128];
+
+               if (!ba_user || !ba_password)
+                       break;
+
+               if (lws_http_basic_auth_gen(ba_user, ba_password, b, sizeof(b)))
+                       break;
+               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION,
+                               (unsigned char *)b, (int)strlen(b), p, end))
+                       return -1;
+               }
+#endif
+               break;
+       }
+
        /* chunks of chunked content, with header removed */
        case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
                lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
-#if 0  /* enable to dump the html */
-               {
-                       const char *p = in;
-
-                       while (len--)
-                               if (*p < 0x7f)
-                                       putchar(*p++);
-                               else
-                                       putchar('.');
+#if defined(LWS_WITH_HTTP2)
+               if (long_poll) {
+                       char dotstar[128];
+                       lws_strnncpy(dotstar, (const char *)in, len,
+                                    sizeof(dotstar));
+                       lwsl_notice("long poll rx: %d '%s'\n", (int)len,
+                                       dotstar);
                }
 #endif
+#if 0
+               lwsl_hexdump_notice(in, len);
+#endif
+
                return 0; /* don't passthru */
 
        /* uninterpreted http content */
@@ -60,6 +163,9 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
                        char *px = buffer + LWS_PRE;
                        int lenx = sizeof(buffer) - LWS_PRE;
 
+                       if (lws_fi_user_wsi_fi(wsi, "user_reject_at_rx"))
+                               return -1;
+
                        if (lws_http_client_read(wsi, &px, &lenx) < 0)
                                return -1;
                }
@@ -67,15 +173,19 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
 
        case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
                lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
-               client_wsi = NULL;
+               interrupted = 1;
                bad = status != 200;
                lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
                break;
 
        case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
-               client_wsi = NULL;
+               interrupted = 1;
                bad = status != 200;
                lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
+#if defined(LWS_WITH_CONMON)
+               if (conmon)
+                       dump_conmon_data(wsi);
+#endif
                break;
 
        default:
@@ -89,10 +199,9 @@ static const struct lws_protocols protocols[] = {
        {
                "http",
                callback_http,
-               0,
-               0,
+               0, 0, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 }
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static void
@@ -101,64 +210,39 @@ sigint_handler(int sig)
        interrupted = 1;
 }
 
-int main(int argc, const char **argv)
+struct args {
+       int argc;
+       const char **argv;
+};
+
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                  int current, int target)
 {
-       struct lws_context_creation_info info;
+       struct lws_context *context = mgr->parent;
        struct lws_client_connect_info i;
-       struct lws_context *context;
+       struct args *a = lws_context_user(context);
        const char *p;
-       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
-                  /*
-                   * For LLL_ verbosity above NOTICE to be built into lws,
-                   * lws must have been configured and built with
-                   * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE
-                   *
-                   * | LLL_INFO   | LLL_PARSER  | LLL_HEADER | LLL_EXT |
-                   *   LLL_CLIENT | LLL_LATENCY | LLL_DEBUG
-                   */ ;
-
-       signal(SIGINT, sigint_handler);
-
-       if ((p = lws_cmdline_option(argc, argv, "-d")))
-               logs = atoi(p);
-
-       lws_set_log_level(logs, NULL);
-       lwsl_user("LWS minimal http client [-d<verbosity>] [-l] [--h1]\n");
 
-       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
-       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
-       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
-       info.protocols = protocols;
+       if (current != LWS_SYSTATE_OPERATIONAL || target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
 
-       /*
-        * since we know this lws context is only ever going to be used with
-        * one client wsis / fds / sockets at a time, let lws know it doesn't
-        * have to use the default allocations for fd tables up to ulimit -n.
-        * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
-        * will use.
-        */
-       info.fd_limit_per_thread = 1 + 1 + 1;
-
-#if defined(LWS_WITH_MBEDTLS)
-       /*
-        * OpenSSL uses the system trust store.  mbedTLS has to be told which
-        * CA to trust explicitly.
-        */
-       info.client_ssl_ca_filepath = "./warmcat.com.cer";
-#endif
-
-       context = lws_create_context(&info);
-       if (!context) {
-               lwsl_err("lws init failed\n");
-               return 1;
-       }
+       lwsl_info("%s: operational\n", __func__);
 
        memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
        i.context = context;
-       if (!lws_cmdline_option(argc, argv, "-n"))
+       if (!lws_cmdline_option(a->argc, a->argv, "-n")) {
                i.ssl_connection = LCCSCF_USE_SSL;
+#if defined(LWS_WITH_HTTP2)
+               /* requires h2 */
+               if (lws_cmdline_option(a->argc, a->argv, "--long-poll")) {
+                       lwsl_user("%s: long poll mode\n", __func__);
+                       long_poll = 1;
+               }
+#endif
+       }
 
-       if (lws_cmdline_option(argc, argv, "-l")) {
+       if (lws_cmdline_option(a->argc, a->argv, "-l")) {
                i.port = 7681;
                i.address = "localhost";
                i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
@@ -167,41 +251,177 @@ int main(int argc, const char **argv)
                i.address = "warmcat.com";
        }
 
-       if (lws_cmdline_option(argc, argv, "--h1"))
+       if (lws_cmdline_option(a->argc, a->argv, "--nossl"))
+               i.ssl_connection = 0;
+
+       i.ssl_connection |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
+                           LCCSCF_ACCEPT_TLS_DOWNGRADE_REDIRECTS |
+                           LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
+
+       i.alpn = "h2,http/1.1";
+       if (lws_cmdline_option(a->argc, a->argv, "--h1"))
                i.alpn = "http/1.1";
 
-       if ((p = lws_cmdline_option(argc, argv, "-p")))
+       if (lws_cmdline_option(a->argc, a->argv, "--h2-prior-knowledge"))
+               i.ssl_connection |= LCCSCF_H2_PRIOR_KNOWLEDGE;
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "-p")))
                i.port = atoi(p);
 
-       if (lws_cmdline_option(argc, argv, "-j"))
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--user")))
+               ba_user = p;
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--password")))
+               ba_password = p;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-j"))
                i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
 
-       if (lws_cmdline_option(argc, argv, "-k"))
+       if (lws_cmdline_option(a->argc, a->argv, "-k"))
                i.ssl_connection |= LCCSCF_ALLOW_INSECURE;
 
-       if (lws_cmdline_option(argc, argv, "-m"))
+       if (lws_cmdline_option(a->argc, a->argv, "-b"))
+               i.ssl_connection |= LCCSCF_CACHE_COOKIES;
+
+       if (lws_cmdline_option(a->argc, a->argv, "-m"))
                i.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
 
-       if (lws_cmdline_option(argc, argv, "-e"))
+       if (lws_cmdline_option(a->argc, a->argv, "-e"))
                i.ssl_connection |= LCCSCF_ALLOW_EXPIRED;
 
-       if ((p = lws_cmdline_option(argc, argv, "--server")))
+       if ((p = lws_cmdline_option(a->argc, a->argv, "-f"))) {
+               i.ssl_connection |= LCCSCF_H2_MANUAL_RXFLOW;
+               i.manual_initial_tx_credit = atoi(p);
+               lwsl_notice("%s: manual peer tx credit %d\n", __func__,
+                               i.manual_initial_tx_credit);
+       }
+
+#if defined(LWS_WITH_CONMON)
+       if (lws_cmdline_option(a->argc, a->argv, "--conmon")) {
+               i.ssl_connection |= LCCSCF_CONMON;
+               conmon = 1;
+       }
+#endif
+
+       /* the default validity check is 5m / 5m10s... -v = 3s / 10s */
+
+       if (lws_cmdline_option(a->argc, a->argv, "-v"))
+               i.retry_and_idle_policy = &retry;
+
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--server")))
                i.address = p;
 
-       i.path = "/";
+       if ((p = lws_cmdline_option(a->argc, a->argv, "--path")))
+               i.path = p;
+       else
+               i.path = "/";
+
        i.host = i.address;
        i.origin = i.address;
        i.method = "GET";
 
        i.protocol = protocols[0].name;
        i.pwsi = &client_wsi;
-       lws_client_connect_via_info(&i);
+       i.fi_wsi_name = "user";
+
+       if (!lws_client_connect_via_info(&i)) {
+               lwsl_err("Client creation failed\n");
+               interrupted = 1;
+               bad = 2; /* could not even start client connection */
+               lws_cancel_service(context);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+int main(int argc, const char **argv)
+{
+       lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
+                                            system_notify_cb, "app" };
+       lws_state_notify_link_t *na[] = { &notifier, NULL };
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0, expected = 0;
+       struct args args;
+       const char *p;
+       // uint8_t memcert[4096];
 
-       while (n >= 0 && client_wsi && !interrupted)
+       args.argc = argc;
+       args.argv = argv;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS minimal http client [-d<verbosity>] [-l] [--h1]\n");
+
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW;
+       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
+       info.protocols = protocols;
+       info.user = &args;
+       info.register_notifier_list = na;
+       info.connect_timeout_secs = 30;
+
+#if defined(LWS_WITH_CACHE_NSCOOKIEJAR)
+       info.http_nsc_filepath = "./cookies.txt";
+       if ((p = lws_cmdline_option(argc, argv, "-c")))
+               info.http_nsc_filepath = p;
+#endif
+
+       /*
+        * since we know this lws context is only ever going to be used with
+        * one client wsis / fds / sockets at a time, let lws know it doesn't
+        * have to use the default allocations for fd tables up to ulimit -n.
+        * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
+        * will use.
+        */
+       info.fd_limit_per_thread = 1 + 1 + 1;
+
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+       /*
+        * OpenSSL uses the system trust store.  mbedTLS has to be told which
+        * CA to trust explicitly.
+        */
+       if (lws_cmdline_option(argc, argv, "-w"))
+               /* option to confirm we are validating against the right cert */
+               info.client_ssl_ca_filepath = "./wrong.cer";
+       else
+               info.client_ssl_ca_filepath = "./warmcat.com.cer";
+#endif
+#if 0
+       n = open("./warmcat.com.cer", O_RDONLY);
+       if (n >= 0) {
+               info.client_ssl_ca_mem_len = read(n, memcert, sizeof(memcert));
+               info.client_ssl_ca_mem = memcert;
+               close(n);
+               n = 0;
+               memcert[info.client_ssl_ca_mem_len++] = '\0';
+       }
+#endif
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               bad = 5;
+               goto bail;
+       }
+
+       while (n >= 0 && !interrupted)
                n = lws_service(context, 0);
 
        lws_context_destroy(context);
-       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
 
-       return bad;
+bail:
+       if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
+               expected = atoi(p);
+
+       if (bad == expected) {
+               lwsl_user("Completed: OK (seen expected %d)\n", expected);
+               return 0;
+       } else
+               lwsl_err("Completed: failed: exit %d, expected %d\n", bad, expected);
+
+       return 1;
 }
diff --git a/minimal-examples/http-client/minimal-http-client/selftest.sh b/minimal-examples/http-client/minimal-http-client/selftest.sh
deleted file mode 100755 (executable)
index c065b44..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=4
-
-dotest $1 $2 warmcat
-dotest $1 $2 warmcat-h1 --h1
-
-spawn "" $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost -l
-spawn $SPID $5/http-server/minimal-http-server-tls $1/lws-minimal-http-server-tls
-dotest $1 $2 localhost-h1 -l --h1
-
-kill $SPID 2>/dev/null
-wait $SPID 2>/dev/null
-exit $FAILS
index 550393d..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFUDCCBDigAwIBAgISA4mJfIm3iCGbU9+o8YQa+4nUMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5MjNaFw0x
-OTEyMDYwNzA5MjNaMBYxFDASBgNVBAMTC3dhcm1jYXQuY29tMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwnEoH9JW3GvpadpxHGZPb5wv1Q6KfAIMWtdq
-YCOfotFxaYULuzHVxmrTTgmEqJr+eBqUBkXKmGuRR/9UipOmTu5j02qFyWHotFdF
-ZGyp//8z+Rle9Qt1nL68oNIZLDtWkybh5x00b1uo4eyEszXUaa0aLqKP3lH7Q4jI
-aSVARZ8snrJR640Gp3ByudvNTYkGz469bpWzRC/8wSNtzzY02DvHs1GxQx9tMXw+
-BbtUxeP7lpYFKEFBjgZaIKLv+4g8ItJIuO7gMSzG2JfpQHxdhrlhxpx7dsaMUcyM
-nnYXysNL5JG3KEMhkxbtdpCaEQ8jLSPbl/rnF/+mgce+lSjMuQIDAQABo4ICYjCC
-Al4wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
-AjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSI9ai12zLFeNTEDHKI9Ghkqcpa2TAf
-BgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEw
-LgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcw
-LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
-MBYGA1UdEQQPMA2CC3dhcm1jYXQuY29tMEwGA1UdIARFMEMwCAYGZ4EMAQIBMDcG
-CysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5
-cHQub3JnMIIBBgYKKwYBBAHWeQIEAgSB9wSB9ADyAHcAY/Lbzeg7zCzPC3KEJ1dr
-M6SNYXePvXWmOLHHaFRL2I0AAAFtCsVHHAAABAMASDBGAiEAy0q1cR4VwPL3iviL
-cBWN67kjJRXk+DwhodmeoM3kb3gCIQC2soAHFs0Umo+0RNdFrL41+hMuidh2cXbb
-Ovc6nh5tOQB3AOJpS64m6OlACeiGG7Y7g9Q+5/50iPukjyiTAZ3d8dv+AAABbQrF
-R48AAAQDAEgwRgIhANqKQm4t9by263CJ7/DLOaZCjtcK29KgJjPwhv08UMn1AiEA
-h35nGTASR8/E7xz+56ZUleqD7U1ABFgWZRZskIzsFO8wDQYJKoZIhvcNAQELBQAD
-ggEBADDJBVbKe2LPHmi8k2vxErB3Y0Ty+3gwgPEXKYtEvQ7tos89eE+QmOXAzH5J
-GwRarFf7kzmKeJv04tMebiEtshpap47oJfxCxfrtpja8hP8Cdu/v/Ae6eEzu3yet
-0N08GJdxQKfgCFaoGUptbaF2RCIZS12SVcX4TPpdP+xaiZdmIx4dGM6tReQ8+y8B
-10b4Hi2+d/zW0W1z6+FAemU6yleWriJDUik5oas9XZF5LAAMDb/WgF5eIB6P9CUG
-LuAO8lWlk9nBgXvMLTxZ74SJb17H4kFEIrIjvABNshz5gBW8xw9nfr5YIfANtwEj
-BDsq06Df3UORYVs/j3T97gPAEZ4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
diff --git a/minimal-examples/http-client/minimal-http-client/wrong.cer b/minimal-examples/http-client/minimal-http-client/wrong.cer
new file mode 100644 (file)
index 0000000..3503566
--- /dev/null
@@ -0,0 +1,21 @@
+-----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-----
+
index c1bb2ce..ac5e278 100644 (file)
@@ -1,77 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-basicauth C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-basicauth)
 set(SRCS minimal-http-server-basicauth.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_HTTP_BASIC_AUTH 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
diff --git a/minimal-examples/http-server/minimal-http-server-cgi/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-cgi/CMakeLists.txt
new file mode 100644 (file)
index 0000000..18ef350
--- /dev/null
@@ -0,0 +1,25 @@
+project(lws-minimal-http-server-cgi C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-http-server-cgi)
+set(SRCS minimal-http-server.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CGI 1 requirements)
+require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/http-server/minimal-http-server-cgi/README.md b/minimal-examples/http-server/minimal-http-server-cgi/README.md
new file mode 100644 (file)
index 0000000..9f3143a
--- /dev/null
@@ -0,0 +1,28 @@
+# lws minimal http server-cgi
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+This example runs a script ./my-cgi-script.sh when you vist /
+
+The script dumps some information from /proc on stdout, which
+is proxied back to the browser, script output on stderr is
+printed in the console.
+
+It's able to serve the script output over h1 using chunked encoding,
+and over h2 having stripped the chunked encoding from the script
+output.
+
+```
+ $ ./lws-minimal-http-server-cgi
+[2019/11/18 16:31:29:5481] U: LWS minimal http server | visit http://localhost:7681
+[2019/11/18 16:31:40:2176] N: CGI-stderr: lwstest script stderr: REQUEST_METHOD was GET
+```
+
+Visit http://localhost:7681
+
diff --git a/minimal-examples/http-server/minimal-http-server-cgi/minimal-http-server.c b/minimal-examples/http-server/minimal-http-server-cgi/minimal-http-server.c
new file mode 100644 (file)
index 0000000..1e8bc91
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * lws-minimal-http-server-cgi
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates the most minimal http server you can make with lws.
+ *
+ * To keep it simple, it serves stuff from the subdirectory 
+ * "./mount-origin" of the directory it was started in.
+ * You can change that by changing mount.origin below.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted;
+static char cgi_script_fullpath[256];
+
+static const struct lws_http_mount mount = {
+       /* .mount_next */               NULL,           /* linked-list "next" */
+       /* .mountpoint */               "/",            /* mountpoint URL */
+       /* .origin */                   cgi_script_fullpath, /* cgi script */
+       /* .def */                      "/",    /* default filename */
+       /* .protocol */                 NULL,
+       /* .cgienv */                   NULL,
+       /* .extra_mimetypes */          NULL,
+       /* .interpret */                NULL,
+       /* .cgi_timeout */              0,
+       /* .cache_max_age */            0,
+       /* .auth_mask */                0,
+       /* .cache_reusable */           0,
+       /* .cache_revalidate */         0,
+       /* .cache_intermediaries */     0,
+       /* .origin_protocol */          LWSMPRO_CGI,    /* files in a dir */
+       /* .mountpoint_len */           1,              /* char count */
+       /* .basic_auth_login_file */    NULL,
+};
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
+                       /* for LLL_ verbosity above NOTICE to be built into lws,
+                        * lws must have been configured and built with
+                        * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
+                       /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
+                       /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
+                       /* | LLL_DEBUG */;
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS minimal http server | visit http://localhost:7681\n");
+
+       {
+               char cwd[128];
+               cwd[0] = '\0';
+               getcwd(cwd, sizeof(cwd));
+
+               lws_snprintf(cgi_script_fullpath, sizeof(cgi_script_fullpath),
+                               "%s/my-cgi-script.sh", cwd);
+       }
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.port = 7681;
+       info.mounts = &mount;
+       info.error_document_404 = "/404.html";
+       info.options =
+               LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
+
+#if defined(LWS_WITH_TLS)
+       if (lws_cmdline_option(argc, argv, "-s")) {
+               info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+               info.ssl_cert_filepath = "localhost-100y.cert";
+               info.ssl_private_key_filepath = "localhost-100y.key";
+       }
+#endif
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 1000);
+
+       lws_context_destroy(context);
+
+       return 0;
+}
diff --git a/minimal-examples/http-server/minimal-http-server-cgi/my-cgi-script.sh b/minimal-examples/http-server/minimal-http-server-cgi/my-cgi-script.sh
new file mode 100755 (executable)
index 0000000..5a96c37
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+echo -e -n "content-type: text/html\x0d\x0a"
+echo -e -n "transfer-encoding: chunked\x0d\x0a"
+echo -e -n "\x0d\x0a"
+
+echo "<html><meta charset="UTF-8"><body>"
+echo "<h1>lwstest script stdout</h1>"
+>&2 echo -n "lwstest script stderr: REQUEST_METHOD was $REQUEST_METHOD"
+
+echo "<h2>REQUEST_METHOD=$REQUEST_METHOD</h2>"
+
+if [ "$REQUEST_METHOD" = "POST" ] ; then
+       >&2 echo "lwstest script stderr: doing read"
+       echo "CONTENT_LENGTH=$CONTENT_LENGTH"
+       read -n $CONTENT_LENGTH line
+       >&2 echo "lwstest script stderr: done read $line"
+
+       echo "read=\"$line\""
+else
+       echo "<table>"
+       echo "<tr><td colspan=\"2\">/proc/meminfo</td></tr>"
+       cat /proc/meminfo | while read line ; do
+               A=`echo "$line" | cut -d: -f1`
+               B=`echo "$line" | tr -s ' ' | cut -d' ' -f2-`
+               echo -e "<tr><td>$A</td>"
+               echo -e "<td>$B</td></tr>"
+       done
+       echo "</table>"
+fi
+
+echo "<br/>done"
+echo "</body></html>"
+sleep 0.5
+exit 0
+
index 92d0d18..f113424 100644 (file)
@@ -1,78 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-custom-headers C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-custom-headers)
 set(SRCS minimal-http-server-custom-headers.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
 require_lws_config(LWS_WITH_CUSTOM_HEADERS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index dcdb0b8..d9a1f31 100644 (file)
@@ -40,7 +40,8 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
                *end = &buf[sizeof(buf) - LWS_PRE - 1];
        struct pss *pss = (struct pss *)user;
        char value[32], *pr = &pss->result[LWS_PRE];
-       int n, e = sizeof(pss->result) - LWS_PRE;
+       size_t e = sizeof(pss->result) - LWS_PRE;
+       int n;
 
        switch (reason) {
        case LWS_CALLBACK_HTTP:
@@ -63,18 +64,18 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
                                        "%s: DNT length %d<br>", __func__, n);
                        n = lws_hdr_custom_copy(wsi, value, sizeof(value), "dnt:", 4);
                        if (n < 0)
-                               pss->len += lws_snprintf(pr + pss->len, e - pss->len,
+                               pss->len += lws_snprintf(pr + pss->len, e - (unsigned int)pss->len,
                                        "%s: unable to get DNT value\n", __func__);
                        else
 
-                               pss->len += lws_snprintf(pr + pss->len , e - pss->len,
+                               pss->len += lws_snprintf(pr + pss->len , e - (unsigned int)pss->len,
                                        "%s: DNT value '%s'\n", __func__, value);
                }
 
                lwsl_user("%s\n", pr);
 
                if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
-                               "text/html", pss->len, &p, end))
+                               "text/html", (lws_filepos_t)pss->len, &p, end))
                        return 1;
 
                if (lws_finalize_write_http_header(wsi, start, &p, end))
@@ -89,7 +90,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
 
                strcpy((char *)start, "hello");
 
-               if (lws_write(wsi, (uint8_t *)pr, pss->len, LWS_WRITE_HTTP_FINAL) != pss->len)
+               if (lws_write(wsi, (uint8_t *)pr, (unsigned int)pss->len, LWS_WRITE_HTTP_FINAL) != pss->len)
                        return 1;
 
                if (lws_http_transaction_completed(wsi))
@@ -104,8 +105,8 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
 }
 
 static struct lws_protocols protocols[] = {
-       { "http", callback_http, sizeof(struct pss), 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static const struct lws_http_mount mount_dyn = {
@@ -201,8 +202,10 @@ int main(int argc, const char **argv)
 
        info.port = 7682;
        info.error_document_404 = "/404.html";
+#if defined(LWS_WITH_TLS)
        info.ssl_cert_filepath = "localhost-100y.cert";
        info.ssl_private_key_filepath = "localhost-100y.key";
+#endif
        info.vhost_name = "https";
 
        if (!lws_create_vhost(context, &info)) {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index d5f5188..fee8fbc 100644 (file)
@@ -1,5 +1,9 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-deaddrop C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-deaddrop)
 set(SRCS minimal-http-server-deaddrop.c)
@@ -8,69 +12,13 @@ set(SRCS minimal-http-server-deaddrop.c)
 # to the lws plugins dir so it can pick up the plugin source.  Eg,
 # cmake . -DLWS_PLUGINS_DIR=~/libwebsockets/plugins
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_HTTP_BASIC_AUTH 1 requirements)
 
-if (requirements)
+if (requirements AND UNIX)
        add_executable(${SAMP} ${SRCS})
 
        if (LWS_PLUGINS_DIR)
@@ -78,9 +26,9 @@ if (requirements)
        endif()
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index fe06412..97902ac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-minimal-http-server-deaddrop
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
@@ -23,7 +23,7 @@
 
 static struct lws_protocols protocols[] = {
        LWS_PLUGIN_PROTOCOL_DEADDROP,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 
@@ -153,8 +153,10 @@ int main(int argc, const char **argv)
        info.error_document_404 = "/404.html";
        info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
+#if defined(LWS_WITH_TLS)
        info.ssl_cert_filepath = "localhost-100y.cert";
        info.ssl_private_key_filepath = "localhost-100y.key";
+#endif
 
        context = lws_create_context(&info);
        if (!context) {
index ebb6e12..5168859 100644 (file)
@@ -74,7 +74,7 @@
        }
 
        function clear_errors() {
-               var t = document.getElementById("ongoing");
+               var n, t = document.getElementById("ongoing");
 
                for (n = 0; n < t.rows.length; n++)
                        if (t.rows[n].cells[0].classList.contains("err"))
        }
 
        function upl_button(e) {
-               var fi = document.getElementById("file"),
-               da = document.getElementById("da");
+               var fi = document.getElementById("file");
 
                clear_errors();
                e.preventDefault();
 
        function new_ws(urlpath, protocol)
        {
-               if (typeof MozWebSocket != "undefined")
-                       return new MozWebSocket(urlpath, protocol);
-
                return new WebSocket(urlpath, protocol);
        }
 
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 5b5794c..e8affdb 100644 (file)
@@ -1,78 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-dynamic C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-dynamic)
 set(SRCS minimal-http-server-dynamic.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index bb537eb..f919146 100644 (file)
@@ -45,12 +45,47 @@ callback_dynamic_http(struct lws *wsi, enum lws_callback_reasons reason,
                *end = &buf[sizeof(buf) - LWS_PRE - 1];
        time_t t;
        int n;
+#if defined(LWS_HAVE_CTIME_R)
+       char date[32];
+#endif
 
        switch (reason) {
        case LWS_CALLBACK_HTTP:
 
-               /* in contains the url part after our mountpoint /dyn, if any */
-               lws_snprintf(pss->path, sizeof(pss->path), "%s", (const char *)in);
+               /*
+                * If you want to know the full url path used, you can get it
+                * like this
+                *
+                * n = lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_GET_URI);
+                *
+                * The base path is the first (n - strlen((const char *)in))
+                * chars in buf.
+                */
+
+               /*
+                * In contains the url part after the place the mount was
+                * positioned at, eg, if positioned at "/dyn" and given
+                * "/dyn/mypath", in will contain /mypath
+                */
+               lws_snprintf(pss->path, sizeof(pss->path), "%s",
+                               (const char *)in);
+
+               lws_get_peer_simple(wsi, (char *)buf, sizeof(buf));
+               lwsl_notice("%s: HTTP: connection %s, path %s\n", __func__,
+                               (const char *)buf, pss->path);
+
+               /*
+                * Demonstrates how to retreive a urlarg x=value
+                */
+
+               {
+                       char value[100];
+                       int z = lws_get_urlarg_by_name_safe(wsi, "x", value,
+                                          sizeof(value) - 1);
+
+                       if (z >= 0)
+                               lwsl_hexdump_notice(value, (size_t)z);
+               }
 
                /*
                 * prepare and write http headers... with regards to content-
@@ -126,14 +161,19 @@ callback_dynamic_http(struct lws *wsi, enum lws_callback_reasons reason,
                         * to work with http/2, we must take care about LWS_PRE
                         * valid behind the buffer we will send.
                         */
-                       p += lws_snprintf((char *)p, end - p, "<html>"
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "<html>"
                                "<head><meta charset=utf-8 "
                                "http-equiv=\"Content-Language\" "
                                "content=\"en\"/></head><body>"
                                "<img src=\"/libwebsockets.org-logo.svg\">"
                                "<br>Dynamic content for '%s' from mountpoint."
                                "<br>Time: %s<br><br>"
-                               "</body></html>", pss->path, ctime(&t));
+                               "</body></html>", pss->path,
+#if defined(LWS_HAVE_CTIME_R)
+                               ctime_r(&t, date));
+#else
+                               ctime(&t));
+#endif
                } else {
                        /*
                         * after the first time, we create bulk content.
@@ -143,15 +183,15 @@ callback_dynamic_http(struct lws *wsi, enum lws_callback_reasons reason,
                         */
 
                        while (lws_ptr_diff(end, p) > 80)
-                               p += lws_snprintf((char *)p, end - p,
+                               p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                        "%d.%d: this is some content... ",
                                        pss->times, pss->content_lines++);
 
-                       p += lws_snprintf((char *)p, end - p, "<br><br>");
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "<br><br>");
                }
 
                pss->times++;
-               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff(p, start), n) !=
+               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff_size_t(p, start), (enum lws_write_protocol)n) !=
                                lws_ptr_diff(p, start))
                        return 1;
 
@@ -175,10 +215,11 @@ callback_dynamic_http(struct lws *wsi, enum lws_callback_reasons reason,
        return lws_callback_http_dummy(wsi, reason, user, in, len);
 }
 
-static const struct lws_protocols protocol =
-       { "http", callback_dynamic_http, sizeof(struct pss), 0 };
+static const struct lws_protocols defprot =
+       { "defprot", lws_callback_http_dummy, 0, 0, 0, NULL, 0 }, protocol =
+       { "http", callback_dynamic_http, sizeof(struct pss), 0, 0, NULL, 0 };
 
-static const struct lws_protocols *pprotocols[] = { &protocol, NULL };
+static const struct lws_protocols *pprotocols[] = { &defprot, &protocol, NULL };
 
 /* override the default mount for /dyn in the URL space */
 
@@ -281,8 +322,10 @@ int main(int argc, const char **argv)
 
        info.port = 7682;
        info.error_document_404 = "/404.html";
+#if defined(LWS_WITH_TLS)
        info.ssl_cert_filepath = "localhost-100y.cert";
        info.ssl_private_key_filepath = "localhost-100y.key";
+#endif
        info.vhost_name = "localhost";
 
        if (!lws_create_vhost(context, &info)) {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-custom/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-eventlib-custom/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5f023f9
--- /dev/null
@@ -0,0 +1,28 @@
+project(lws-minimal-http-server-eventlib-custom C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-http-server-eventlib-custom)
+set(SRCS minimal-http-server.c)
+
+if (WIN32)
+else()
+       set(requirements 1)
+       require_lws_config(LWS_ROLE_H1 1 requirements)
+       require_lws_config(LWS_WITH_SERVER 1 requirements)
+       require_lws_config(LWS_WITH_CLIENT 1 requirements)
+
+       if (requirements)
+               add_executable(${SAMP} ${SRCS})
+
+               if (websockets_shared)
+                       target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP} websockets_shared)
+               else()
+                       target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+endif()
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-custom/README.md b/minimal-examples/http-server/minimal-http-server-eventlib-custom/README.md
new file mode 100644 (file)
index 0000000..cc8794b
--- /dev/null
@@ -0,0 +1,18 @@
+# lws minimal http server
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+```
+ $ ./lws-minimal-http-server
+[2018/03/04 09:30:02:7986] USER: LWS minimal http server | visit http://localhost:7681
+[2018/03/04 09:30:02:7986] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 on
+```
+
+Visit http://localhost:7681
+
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-custom/minimal-http-server.c b/minimal-examples/http-server/minimal-http-server-eventlib-custom/minimal-http-server.c
new file mode 100644 (file)
index 0000000..e969fea
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * lws-minimal-http-server-eventlib-custom
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a minimal http server using lws, on top of a custom "event
+ * library" that uses an existing application POLL loop.
+ *
+ * To keep it simple, it serves stuff from the subdirectory  "./mount-origin" of
+ * the dir it was started in.  Change mount.origin to serve from elsewhere.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted;
+static struct lws_context *context;
+
+#define MAX_CUSTOM_POLLFDS     64
+
+/* this represents the existing application poll loop context we want lws
+ * to cooperate with */
+
+typedef struct custom_poll_ctx {
+       struct lws_pollfd       pollfds[MAX_CUSTOM_POLLFDS];
+       int                     count_pollfds;
+} custom_poll_ctx_t;
+
+/* for this example we just have the one, but it is passed into lws as a
+ * foreign loop pointer, and all callbacks have access to it via that, so it
+ * is not needed to be defined at file scope. */
+static custom_poll_ctx_t a_cpcx;
+
+/*
+ * These are the custom event loop operators that just make the custom event
+ * loop able to work by itself.  These would already exist in some form in an
+ * existing application.
+ */
+
+static struct lws_pollfd *
+custom_poll_find_fd(custom_poll_ctx_t *cpcx, lws_sockfd_type fd)
+{
+       int n;
+
+       for (n = 0; n < cpcx->count_pollfds; n++)
+               if (cpcx->pollfds[n].fd == fd)
+                       return &cpcx->pollfds[n];
+
+       return NULL;
+}
+
+static int
+custom_poll_add_fd(custom_poll_ctx_t *cpcx, lws_sockfd_type fd, int events)
+{
+       struct lws_pollfd *pfd;
+
+       lwsl_info("%s: ADD fd %d, ev %d\n", __func__, fd, events);
+
+       pfd = custom_poll_find_fd(cpcx, fd);
+       if (pfd) {
+               lwsl_err("%s: ADD fd %d already in ext table\n", __func__, fd);
+               return 1;
+       }
+
+       if (cpcx->count_pollfds == LWS_ARRAY_SIZE(cpcx->pollfds)) {
+               lwsl_err("%s: no room left\n", __func__);
+               return 1;
+       }
+
+       pfd = &cpcx->pollfds[cpcx->count_pollfds++];
+       pfd->fd = fd;
+       pfd->events = (short)events;
+       pfd->revents = 0;
+
+       return 0;
+}
+
+static int
+custom_poll_del_fd(custom_poll_ctx_t *cpcx, lws_sockfd_type fd)
+{
+       struct lws_pollfd *pfd;
+
+       lwsl_info("%s: DEL fd %d\n", __func__, fd);
+
+       pfd = custom_poll_find_fd(cpcx, fd);
+       if (!pfd) {
+               lwsl_err("%s: DEL fd %d missing in ext table\n", __func__, fd);
+               return 1;
+       }
+
+       if (cpcx->count_pollfds > 1)
+               *pfd = cpcx->pollfds[cpcx->count_pollfds - 1];
+
+       cpcx->count_pollfds--;
+
+       return 0;
+}
+
+static int
+custom_poll_change_fd(custom_poll_ctx_t *cpcx, lws_sockfd_type fd,
+                    int events_add, int events_remove)
+{
+       struct lws_pollfd *pfd;
+
+       lwsl_info("%s: CHG fd %d, ev_add %d, ev_rem %d\n", __func__, fd,
+                       events_add, events_remove);
+
+       pfd = custom_poll_find_fd(cpcx, fd);
+       if (!pfd)
+               return 1;
+
+       pfd->events = (short)((pfd->events & (~events_remove)) | events_add);
+
+       return 0;
+}
+
+int
+custom_poll_run(custom_poll_ctx_t *cpcx)
+{
+       int n;
+
+       while (!interrupted) {
+
+               /*
+                * Notice that the existing loop must consult with lws about
+                * the maximum wait timeout to use.  Lws will reduce the
+                * timeout to the earliest scheduled event time if any earlier
+                * than the provided timeout.
+                */
+
+               n = lws_service_adjust_timeout(context, 5000, 0);
+
+               lwsl_debug("%s: entering poll wait %dms\n", __func__, n);
+
+               n = poll(cpcx->pollfds, (nfds_t)cpcx->count_pollfds, n);
+
+               lwsl_debug("%s: exiting poll ret %d\n", __func__, n);
+
+               if (n <= 0)
+                       continue;
+
+               for (n = 0; n < cpcx->count_pollfds; n++) {
+                       lws_sockfd_type fd = cpcx->pollfds[n].fd;
+                       int m;
+
+                       if (!cpcx->pollfds[n].revents)
+                               continue;
+
+                       m = lws_service_fd(context, &cpcx->pollfds[n]);
+
+                       /* if something closed, retry this slot since may have been
+                        * swapped with end fd */
+                       if (m && cpcx->pollfds[n].fd != fd)
+                               n--;
+
+                       if (m < 0)
+                               /* lws feels something bad happened, but
+                                * the outer application may not care */
+                               continue;
+                       if (!m) {
+                               /* check if it is an fd owned by the
+                                * application */
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+/*
+ * These is the custom "event library" interface layer between lws event lib
+ * support and the custom loop implementation above.  We only need to support
+ * a few key apis.
+ *
+ * We are user code, so all the internal lws objects are opaque.  But there are
+ * enough public helpers to get everything done.
+ */
+
+/* one of these is appended to each pt for our use */
+struct pt_eventlibs_custom {
+       custom_poll_ctx_t               *io_loop;
+};
+
+/*
+ * During lws context creation, we get called with the foreign loop pointer
+ * that was passed in the creation info struct.  Stash it in our private part
+ * of the pt, so we can reference it in the other callbacks subsequently.
+ */
+
+static int
+init_pt_custom(struct lws_context *cx, void *_loop, int tsi)
+{
+       struct pt_eventlibs_custom *priv = (struct pt_eventlibs_custom *)
+                                            lws_evlib_tsi_to_evlib_pt(cx, tsi);
+
+       /* store the loop we are bound to in our private part of the pt */
+
+       priv->io_loop = (custom_poll_ctx_t *)_loop;
+
+       return 0;
+}
+
+static int
+sock_accept_custom(struct lws *wsi)
+{
+       struct pt_eventlibs_custom *priv = (struct pt_eventlibs_custom *)
+                                               lws_evlib_wsi_to_evlib_pt(wsi);
+
+       return custom_poll_add_fd(priv->io_loop, lws_get_socket_fd(wsi), POLLIN);
+}
+
+static void
+io_custom(struct lws *wsi, unsigned int flags)
+{
+       struct pt_eventlibs_custom *priv = (struct pt_eventlibs_custom *)
+                                               lws_evlib_wsi_to_evlib_pt(wsi);
+       int e_add = 0, e_remove = 0;
+
+       if (flags & LWS_EV_START) {
+               if (flags & LWS_EV_WRITE)
+                       e_add |= POLLOUT;
+
+               if (flags & LWS_EV_READ)
+                       e_add |= POLLIN;
+       } else {
+               if (flags & LWS_EV_WRITE)
+                       e_remove |= POLLOUT;
+
+               if (flags & LWS_EV_READ)
+                       e_remove |= POLLIN;
+       }
+
+       custom_poll_change_fd(priv->io_loop, lws_get_socket_fd(wsi),
+                             e_add, e_remove);
+}
+
+static int
+wsi_logical_close_custom(struct lws *wsi)
+{
+       struct pt_eventlibs_custom *priv = (struct pt_eventlibs_custom *)
+                                               lws_evlib_wsi_to_evlib_pt(wsi);
+       return custom_poll_del_fd(priv->io_loop, lws_get_socket_fd(wsi));
+}
+
+static const struct lws_event_loop_ops event_loop_ops_custom = {
+       .name                           = "custom",
+
+       .init_pt                        = init_pt_custom,
+       .init_vhost_listen_wsi          = sock_accept_custom,
+       .sock_accept                    = sock_accept_custom,
+       .io                             = io_custom,
+       .wsi_logical_close              = wsi_logical_close_custom,
+
+       .evlib_size_pt                  = sizeof(struct pt_eventlibs_custom)
+};
+
+static const lws_plugin_evlib_t evlib_custom = {
+       .hdr = {
+               "custom event loop",
+               "lws_evlib_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .ops    = &event_loop_ops_custom
+};
+
+/*
+ * The rest is just the normal minimal example for lws, with a couple of extra
+ * lines wiring up the custom event library handlers above.
+ */
+
+static const struct lws_http_mount mount = {
+       /* .mount_next */               NULL,           /* linked-list "next" */
+       /* .mountpoint */               "/",            /* mountpoint URL */
+       /* .origin */                   "./mount-origin", /* serve from dir */
+       /* .def */                      "index.html",   /* default filename */
+       /* .protocol */                 NULL,
+       /* .cgienv */                   NULL,
+       /* .extra_mimetypes */          NULL,
+       /* .interpret */                NULL,
+       /* .cgi_timeout */              0,
+       /* .cache_max_age */            0,
+       /* .auth_mask */                0,
+       /* .cache_reusable */           0,
+       /* .cache_revalidate */         0,
+       /* .cache_intermediaries */     0,
+       /* .origin_protocol */          LWSMPRO_FILE,   /* files in a dir */
+       /* .mountpoint_len */           1,              /* char count */
+       /* .basic_auth_login_file */    NULL,
+};
+
+/*
+ * This demonstrates a client connection operating on the same loop
+ * It's optional...
+ */
+
+static int
+callback_http(struct lws *wsi, enum lws_callback_reasons reason,
+             void *user, void *in, size_t len)
+{
+       switch (reason) {
+
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+               lwsl_user("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: resp %u\n",
+                               lws_http_client_http_response(wsi));
+               break;
+
+       /* because we are protocols[0] ... */
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+               break;
+
+       /* chunks of chunked content, with header removed */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+               lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
+               lwsl_hexdump_info(in, len);
+               return 0; /* don't passthru */
+
+       /* uninterpreted http content */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+               {
+                       char buffer[1024 + LWS_PRE];
+                       char *px = buffer + LWS_PRE;
+                       int lenx = sizeof(buffer) - LWS_PRE;
+
+                       if (lws_http_client_read(wsi, &px, &lenx) < 0)
+                               return -1;
+               }
+               return 0; /* don't passthru */
+
+       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
+               lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP %s\n",
+                         lws_wsi_tag(wsi));
+               break;
+
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               lwsl_info("%s: closed: %s\n", __func__, lws_wsi_tag(wsi));
+               break;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static const struct lws_protocols protocols[] = {
+       { "httptest", callback_http, 0, 0, 0, NULL, 0},
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static int
+do_client_conn(void)
+{
+       struct lws_client_connect_info i;
+
+       memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
+
+       i.context               = context;
+
+       i.ssl_connection        = LCCSCF_USE_SSL;
+       i.port                  = 443;
+       i.address               = "warmcat.com";
+
+       i.ssl_connection        |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
+                                  LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
+       i.path                  = "/";
+       i.host                  = i.address;
+       i.origin                = i.address;
+       i.method                = "GET";
+       i.protocol      = protocols[0].name;
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       i.fi_wsi_name           = "user";
+#endif
+
+       if (!lws_client_connect_via_info(&i)) {
+               lwsl_err("Client creation failed\n");
+
+               return 1;
+       }
+
+       lwsl_notice("Client creation OK\n");
+
+       return 0;
+}
+
+/*
+ * End of client part
+ *
+ * Initialization part -->
+ */
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       const char *p;
+       int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       void *foreign_loops[1];
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       /*
+        * init the existing custom event loop here if anything to do, don't
+        * run it yet. In our example, no init required.
+        */
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS minimal http server | visit http://localhost:7681\n");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.port = 7681;
+       info.mounts = &mount;
+       info.error_document_404 = "/404.html";
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+               LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
+
+       info.event_lib_custom = &evlib_custom; /* bind lws to our custom event
+                                               * lib implementation above */
+       foreign_loops[0] = &a_cpcx; /* pass in the custom poll object as the
+                                    * foreign loop object we will bind to */
+       info.foreign_loops = foreign_loops;
+
+       /* optional to demonstrate client connection */
+       info.protocols = protocols;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* optional to demonstrate client connection */
+       do_client_conn();
+
+       /*
+        * We're going to run the custom loop now, instead of the lws loop.
+        * We have told lws to cooperate with this loop to get stuff done.
+        *
+        * We only come back from this when interrupted gets set by SIGINT
+        */
+
+       custom_poll_run(&a_cpcx);
+
+       /* clean up lws part */
+
+       lws_context_destroy(context);
+
+       return 0;
+}
@@ -1,9 +1,7 @@
 <meta charset="UTF-8"> 
 <html>
        <body>
-               <img src="libwebsockets.org-logo.svg">
-               <img src="strict-csp.svg"><br>
-
+               <img src="libwebsockets.org-logo.svg"><br>
                <h1>404</h1>
                Sorry, that file doesn't exist.
        </body>
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/index.html b/minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/index.html
new file mode 100644 (file)
index 0000000..bc9ffa4
--- /dev/null
@@ -0,0 +1,15 @@
+<html>
+ <head>
+  <meta charset=utf-8 http-equiv="Content-Language" content="en"/>
+ </head>
+       <body>
+               <img src="libwebsockets.org-logo.svg">
+               <img src="strict-csp.svg"><br>
+
+               Hello from the <b>minimal http server example</b>.
+               <br>
+               You can confirm the 404 page handler by going to this
+               nonexistant <a href="notextant.html">page</a>.
+       </body>
+</html>
+
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/libwebsockets.org-logo.svg b/minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/libwebsockets.org-logo.svg
new file mode 100644 (file)
index 0000000..ef241b3
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
+</svg>
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/symlink.html b/minimal-examples/http-server/minimal-http-server-eventlib-custom/mount-origin/symlink.html
new file mode 120000 (symlink)
index 0000000..64233a9
--- /dev/null
@@ -0,0 +1 @@
+index.html
\ No newline at end of file
index 593d687..6fe0548 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-eventlib-demos C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-eventlib-demos)
 set(SRCS minimal-http-server-eventlib-demos.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index eaad580..be060da 100644 (file)
@@ -29,22 +29,40 @@ static struct lws_context *context;
 static struct lws_protocols protocols[] = {
        /* first protocol must always be HTTP handler */
 
-       { "http-only", lws_callback_http_dummy, 0, 0, },
+       { "http-only", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
        LWS_PLUGIN_PROTOCOL_MIRROR,
        LWS_PLUGIN_PROTOCOL_LWS_STATUS,
        LWS_PLUGIN_PROTOCOL_POST_DEMO,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 /*
  * mount handlers for sections of the URL space
  */
 
-static const struct lws_http_mount mount_ziptest = {
+static const struct lws_http_mount mount_ziptest_uncomm = {
        NULL,                   /* linked-list pointer to next*/
+       "/uncommziptest",               /* mountpoint in URL namespace on this vhost */
+       "./mount-origin/candide-uncompressed.zip",      /* handler */
+       NULL,   /* default filename if none given */
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       LWSMPRO_FILE,   /* origin points to a callback */
+       14,                     /* strlen("/ziptest"), ie length of the mountpoint */
+       NULL,
+}, mount_ziptest = {
+       (struct lws_http_mount *)&mount_ziptest_uncomm,                 /* linked-list pointer to next*/
        "/ziptest",             /* mountpoint in URL namespace on this vhost */
-       "candide.zip",  /* handler */
+       "./mount-origin/candide.zip",   /* handler */
        NULL,   /* default filename if none given */
        NULL,
        NULL,
@@ -60,10 +78,7 @@ static const struct lws_http_mount mount_ziptest = {
        8,                      /* strlen("/ziptest"), ie length of the mountpoint */
        NULL,
 
-       { NULL, NULL } // sentinel
-};
-
-static const struct lws_http_mount mount_post = {
+}, mount_post = {
        (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/
        "/formtest",            /* mountpoint in URL namespace on this vhost */
        "protocol-post-demo",   /* handler */
@@ -82,11 +97,7 @@ static const struct lws_http_mount mount_post = {
        9,                      /* strlen("/formtest"), ie length of the mountpoint */
        NULL,
 
-       { NULL, NULL } // sentinel
-};
-
-
-static const struct lws_http_mount mount = {
+}, mount = {
        /* .mount_next */               &mount_post,    /* linked-list "next" */
        /* .mountpoint */               "/",            /* mountpoint URL */
        /* .origin */                   "./mount-origin", /* serve from dir */
@@ -157,8 +168,10 @@ int main(int argc, const char **argv)
 
        if (lws_cmdline_option(argc, argv, "-s")) {
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#if defined(LWS_WITH_TLS)
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
+#endif
        }
 
        if (lws_cmdline_option(argc, argv, "--uv"))
@@ -170,7 +183,10 @@ int main(int argc, const char **argv)
                        if (lws_cmdline_option(argc, argv, "--ev"))
                                info.options |= LWS_SERVER_OPTION_LIBEV;
                        else
-                               signal(SIGINT, sigint_handler);
+                               if (lws_cmdline_option(argc, argv, "--glib"))
+                                       info.options |= LWS_SERVER_OPTION_GLIB;
+                               else
+                                       signal(SIGINT, sigint_handler);
 
        context = lws_create_context(&info);
        if (!context) {
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide-uncompressed.zip b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide-uncompressed.zip
new file mode 100644 (file)
index 0000000..55856bc
Binary files /dev/null and b/minimal-examples/http-server/minimal-http-server-eventlib-demos/mount-origin/candide-uncompressed.zip differ
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 5d56ca2..096909f 100644 (file)
@@ -113,9 +113,6 @@ function lws_gray_out(vis, _options) {
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
  
index 2d804a7..fc22523 100644 (file)
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-eventlib-foreign C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckIncludeFile)
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-eventlib-foreign)
 set(SRCS minimal-http-server-eventlib-foreign.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
+require_pthreads(requirements)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
 
 CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBUV)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBUV)
 CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBEVENT)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBEVENT)
 CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBEV)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBEV)
+CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_GLIB)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_GLIB)
+CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_SDEVENT)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_SDEVENT)
+CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_ULOOP)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_ULOOP)
 
 if (LWS_WITH_LIBUV)
-       set(extralibs ${extralibs} uv)
+       find_path(LIBUV_INCLUDE_DIRS NAMES uv.h)
+       find_library(LIBUV_LIBRARIES NAMES uv)
+       message("libuv include dir: ${LIBUV_INCLUDE_DIRS}")
+       message("libuv libraries: ${LIBUV_LIBRARIES}")
+       include_directories("${LIBUV_INCLUDE_DIRS}")
+       set(extralibs ${extralibs} ${LIBUV_LIBRARIES})
+       list(APPEND SRCS libuv.c)
 endif()
 if (LWS_WITH_LIBEVENT)
-       set(extralibs ${extralibs} event)
+       find_path(LIBEVENT_INCLUDE_DIRS NAMES event2/event.h)
+       find_library(LIBEVENT_LIBRARIES NAMES event)
+       message("libevent include dir: ${LIBEVENT_INCLUDE_DIRS}")
+       message("libevent libraries: ${LIBEVENT_LIBRARIES}")
+       include_directories("${LIBEVENT_INCLUDE_DIRS}")
+       set(extralibs ${extralibs} ${LIBEVENT_LIBRARIES})
+       list(APPEND SRCS libevent.c)
 endif()
 if (LWS_WITH_LIBEV)
-       set(extralibs ${extralibs} ev)
+       find_path(LIBEV_INCLUDE_DIRS NAMES ev.h)
+       find_library(LIBEV_LIBRARIES NAMES ev)
+       message("libev include dir: ${LIBEV_INCLUDE_DIRS}")
+       message("libev libraries: ${LIBEV_LIBRARIES}")
+       include_directories("${LIBEV_INCLUDE_DIRS}")
+       set(extralibs ${extralibs} ${LIBEV_LIBRARIES})
+       list(APPEND SRCS libev.c)
+endif()
+if (LWS_WITH_GLIB)
+       set(LWS_GLIB_INCLUDE_DIRS CACHE PATH "Path to the glib include directory")
+       set(LWS_GLIB_LIBRARIES CACHE PATH "Path to the glib library")
+               include (FindPkgConfig)
+       if (NOT GLIB_FOUND)
+               find_path(GLIB_INCLUDE_DIRS NAMES glib-2.0/glib.h)
+               find_library(GLIB_LIBRARIES NAMES glib-2.0)
+               if(GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES)
+                       set(GLIB_FOUND 1)
+               endif()
+               if (GLIB_INCLUDE_DIRS)
+                       set(GLIB_INCLUDE_DIRS "${GLIB_INCLUDE_DIRS}/glib-2.0")
+               endif()
+       endif()
+       PKG_SEARCH_MODULE(LWS_GLIB2 glib-2.0)
+       if (LWS_GLIB2_FOUND)
+               list(APPEND GLIB_INCLUDE_DIRS "${LWS_GLIB2_INCLUDE_DIRS}")
+       endif()
+       message("glib include dir: ${GLIB_INCLUDE_DIRS}")
+       message("glib libraries: ${GLIB_LIBRARIES}")
+       include_directories("${GLIB_INCLUDE_DIRS}")
+       set(extralibs ${extralibs} ${GLIB_LIBRARIES})
+       list(APPEND SRCS glib.c)
+endif()
+if (LWS_WITH_SDEVENT)
+       find_path(LIBSYSTEMD_INCLUDE_DIRS NAMES systemd/sd-event.h)
+       find_library(LIBSYSTEMD_LIBRARIES NAMES systemd)
+       message("libsystemd include dir: ${LIBSYSTEMD_INCLUDE_DIRS}")
+       message("libsystemd libraries: ${LIBSYSTEMD_LIBRARIES}")
+       include_directories("${LIBSYSTEMD_INCLUDE_DIRS}")
+       set(extralibs ${extralibs} ${LIBSYSTEMD_LIBRARIES})
+       list(APPEND SRCS libsdevent.c)
+endif()
+if (LWS_WITH_ULOOP)
+       find_path(LIBUBOX_INCLUDE_DIRS NAMES libubox/uloop.h)
+       find_library(LIBUBOX_LIBRARIES NAMES ubox)
+       message("libubox include dir: ${LIBUBOX_INCLUDE_DIRS}")
+       message("libubox libraries: ${LIBUBOX_LIBRARIES}")
+       include_directories("${LIBUBOX_INCLUDE_DIRS}")
+       set(extralibs ${extralibs} ${LIBUBOX_LIBRARIES})
+       list(APPEND SRCS uloop.c)
 endif()
 
 message("Extra libs: ${extralibs}")
 
-if (NOT LWS_WITH_LIBUV AND NOT LWS_WITH_LIBEVENT AND NOT LWS_WITH_LIBEV)
+if (NOT LWS_WITH_LIBUV AND NOT LWS_WITH_LIBEVENT AND NOT LWS_WITH_LIBEV AND NOT LWS_WITH_GLIB AND NOT LWS_WITH_ULOOP)
        set(requirements 0)
 endif()
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
+       
+       #
+       # tests are running in the same machine context in parallel so they
+       # compete for the same ports.  Select a base port from which sai
+       # instance we are running in, add another digit at the actual test
+       # according to which subtest it is.  Then there can be no clashes
+       # regardless of how many build and tests in parallel.
+       #
+
+       set(PORT_HSEF_SRV "961")
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0")
+               set(PORT_HSEF_SRV 962)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1")
+               set(PORT_HSEF_SRV 963)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2")
+               set(PORT_HSEF_SRV 964)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3")
+               set(PORT_HSEF_SRV 965)
+       endif()
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared ${extralibs})
+               target_link_libraries(${SAMP} websockets_shared ${extralibs} ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets ${extralibs})
+               target_link_libraries(${SAMP} websockets ${extralibs} ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+       
+       # notice we override the evlib plugin source via LD_LIBRARY_PATH so
+       # we are using the evlibs we just built, if any
+       
+       if (LWS_WITH_LIBUV)
+               add_test(NAME hs_evlib_foreign_uv COMMAND lws-minimal-http-server-eventlib-foreign --uv -p ${PORT_HSEF_SRV}1)
+               set_tests_properties(hs_evlib_foreign_uv
+                            PROPERTIES
+                            ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib"
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-eventlib-foreign
+                            TIMEOUT 50)
+       endif()
+       if (LWS_WITH_LIBEVENT)
+               add_test(NAME hs_evlib_foreign_event COMMAND lws-minimal-http-server-eventlib-foreign --event -p ${PORT_HSEF_SRV}2)
+               set_tests_properties(hs_evlib_foreign_event
+                            PROPERTIES
+                            ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib"
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-eventlib-foreign
+                            TIMEOUT 50)
+       endif()
+       if (LWS_WITH_LIBEV)
+               add_test(NAME hs_evlib_foreign_ev COMMAND lws-minimal-http-server-eventlib-foreign --ev -p ${PORT_HSEF_SRV}3)
+               set_tests_properties(hs_evlib_foreign_ev
+                            PROPERTIES
+                            ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib"
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-eventlib-foreign
+                            TIMEOUT 50)
+       endif()
+       if (LWS_WITH_GLIB)
+               add_test(NAME hs_evlib_foreign_glib COMMAND lws-minimal-http-server-eventlib-foreign --glib -p ${PORT_HSEF_SRV}4)
+               set_tests_properties(hs_evlib_foreign_glib
+                            PROPERTIES
+                            ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib"
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-eventlib-foreign
+                            TIMEOUT 50)
+       endif()
+       if (LWS_WITH_SDEVENT)
+               add_test(NAME hs_evlib_foreign_sd COMMAND lws-minimal-http-server-eventlib-foreign --sd -p ${PORT_HSEF_SRV}5)
+               set_tests_properties(hs_evlib_foreign_sd
+                            PROPERTIES
+                            ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib"
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-eventlib-foreign
+                            TIMEOUT 50)
+       endif()
+       if (LWS_WITH_SDEVENT)
+               add_test(NAME hs_evlib_foreign_uloop COMMAND lws-minimal-http-server-eventlib-foreign --uloop -p ${PORT_HSEF_SRV}5)
+               set_tests_properties(hs_evlib_foreign_uloop
+                            PROPERTIES
+                            ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib"
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-eventlib-foreign
+                            TIMEOUT 50)
        endif()
+       
 endif()
index 4c21fa1..0a4aa5f 100644 (file)
@@ -6,6 +6,7 @@ Commandline option|Meaning
 --uv|Use the libuv event library (lws must have been configured with `-DLWS_WITH_LIBUV=1`)
 --event|Use the libevent library (lws must have been configured with `-DLWS_WITH_LIBEVENT=1`)
 --ev|Use the libev event library (lws must have been configured with `-DLWS_WITH_LIBEV=1`)
+--sd|Use the systemd event library (lws must have been configured with `-DLWS_WITH_SDEVENT=1`)
 
 Notice libevent and libev cannot coexist in the one library.  But all the other combinations are OK.
 
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/glib.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/glib.c
new file mode 100644 (file)
index 0000000..fd06e8b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * lws-minimal-http-server-eventlib-foreign
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The glib specific code
+ */
+
+#include <libwebsockets.h>
+
+#include <string.h>
+#include <signal.h>
+
+#include <glib-2.0/glib.h>
+#include <glib-unix.h>
+
+#include "private.h"
+
+#if !defined(G_SOURCE_FUNC)
+#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
+#endif
+
+typedef struct lws_glib_tag {
+       GSource                 *gs;
+       guint                   tag;
+} lws_glib_tag_t;
+
+#define lws_gs_valid(t)                  (t.gs)
+#define lws_gs_destroy(t)        if (lws_gs_valid(t)) { \
+                                       g_source_remove(t.tag); \
+                                       g_source_unref(t.gs); \
+                                       t.gs = NULL; t.tag = 0; }
+
+static GMainLoop *loop_glib;
+static lws_glib_tag_t timer_outer_glib, sighandler_glib;
+
+static int
+timer_cb_glib(void *p)
+{
+       foreign_timer_service(loop_glib);
+       return 1;
+}
+
+static void
+signal_cb_glib(void *p)
+{
+       signal_cb(SIGINT);
+}
+
+static void
+foreign_event_loop_init_and_run_glib(void)
+{
+       /* we create and start our "foreign loop" */
+
+       loop_glib = g_main_loop_new(NULL, 0);
+
+       sighandler_glib.gs = g_unix_signal_source_new(SIGINT);
+       g_source_set_callback(sighandler_glib.gs, G_SOURCE_FUNC(signal_cb_glib),
+                             NULL, NULL);
+       sighandler_glib.tag = g_source_attach(sighandler_glib.gs,
+                                           g_main_loop_get_context(loop_glib));
+
+       timer_outer_glib.gs = g_timeout_source_new(1000);
+       g_source_set_callback(timer_outer_glib.gs, timer_cb_glib, NULL, NULL);
+       timer_outer_glib.tag = g_source_attach(timer_outer_glib.gs,
+                                          g_main_loop_get_context(loop_glib));
+
+       g_main_loop_run(loop_glib);
+}
+
+static void
+foreign_event_loop_stop_glib(void)
+{
+       g_main_loop_quit(loop_glib);
+}
+
+static void
+foreign_event_loop_cleanup_glib(void)
+{
+       /* cleanup the foreign loop assets */
+
+       lws_gs_destroy(sighandler_glib);
+       lws_gs_destroy(timer_outer_glib);
+
+       g_main_loop_unref(loop_glib);
+       loop_glib = NULL;
+}
+
+const struct ops ops_glib = {
+       foreign_event_loop_init_and_run_glib,
+       foreign_event_loop_stop_glib,
+       foreign_event_loop_cleanup_glib
+};
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libev.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libev.c
new file mode 100644 (file)
index 0000000..dcab933
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * lws-minimal-http-server-eventlib-foreign
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The libev specific code
+ */
+
+#include <libwebsockets.h>
+
+#include <ev.h>
+
+#include <string.h>
+#include <signal.h>
+
+#include "private.h"
+
+static struct ev_loop *loop_ev;
+static struct ev_timer timer_outer_ev;
+static struct ev_signal sighandler_ev;
+
+static void
+timer_cb_ev(struct ev_loop *loop, struct ev_timer *watcher, int revents)
+{
+       foreign_timer_service(loop_ev);
+}
+
+static void
+signal_cb_ev(struct ev_loop *loop, struct ev_signal *watcher, int revents)
+{
+       signal_cb(watcher->signum);
+}
+
+static void
+foreign_event_loop_init_and_run_libev(void)
+{
+       /* we create and start our "foreign loop" */
+
+       loop_ev = ev_loop_new(0);
+
+       ev_signal_init(&sighandler_ev, signal_cb_ev, SIGINT);
+       ev_signal_start(loop_ev, &sighandler_ev);
+
+       ev_timer_init(&timer_outer_ev, timer_cb_ev, 0, 1);
+       ev_timer_start(loop_ev, &timer_outer_ev);
+
+       ev_run(loop_ev, 0);
+}
+
+static void
+foreign_event_loop_stop_libev(void)
+{
+       ev_break(loop_ev, EVBREAK_ALL);
+}
+
+static void
+foreign_event_loop_cleanup_libev(void)
+{
+       /* cleanup the foreign loop assets */
+
+       ev_timer_stop(loop_ev, &timer_outer_ev);
+       ev_signal_stop(loop_ev, &sighandler_ev);
+
+       ev_run(loop_ev, 0);
+       ev_loop_destroy(loop_ev);
+}
+
+const struct ops ops_libev = {
+       foreign_event_loop_init_and_run_libev,
+       foreign_event_loop_stop_libev,
+       foreign_event_loop_cleanup_libev
+};
+
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libevent.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libevent.c
new file mode 100644 (file)
index 0000000..a6c8510
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * lws-minimal-http-server-eventlib-foreign
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The libevent specific code
+ */
+
+#include <libwebsockets.h>
+
+#include <event2/event.h>
+
+#include <string.h>
+#include <signal.h>
+
+#include "private.h"
+
+static struct event_base *loop_event;
+static struct event *timer_outer_event;
+static struct event *sighandler_event;
+
+static void
+timer_cb_event(evutil_socket_t fd, short event, void *arg)
+{
+       foreign_timer_service(loop_event);
+}
+
+static void
+signal_cb_event(evutil_socket_t fd, short event, void *arg)
+{
+       signal_cb((int)(lws_intptr_t)arg);
+}
+
+static void
+foreign_event_loop_init_and_run_libevent(void)
+{
+       struct timeval tv;
+
+       /* we create and start our "foreign loop" */
+
+       tv.tv_sec = 1;
+       tv.tv_usec = 0;
+       event_enable_debug_mode();
+
+       loop_event = event_base_new();
+       sighandler_event = evsignal_new((struct event_base *)loop_event, SIGINT, signal_cb_event,
+                                       (void*)SIGINT);
+
+       timer_outer_event = event_new((struct event_base *)loop_event, -1, EV_PERSIST,
+                                     timer_cb_event, NULL);
+       //evtimer_new(loop_event, timer_cb_event, NULL);
+       evtimer_add(timer_outer_event, &tv);
+
+       event_base_loop(loop_event, 0);
+}
+
+static void
+foreign_event_loop_stop_libevent(void)
+{
+       event_base_loopexit(loop_event, NULL);
+}
+
+static void
+foreign_event_loop_cleanup_libevent(void)
+{
+       /* cleanup the foreign loop assets */
+
+       evtimer_del(timer_outer_event);
+       event_free(timer_outer_event);
+       evsignal_del(sighandler_event);
+       event_free(sighandler_event);
+
+       event_base_loop(loop_event, 0);
+       event_base_free(loop_event);
+}
+
+const struct ops ops_libevent = {
+       foreign_event_loop_init_and_run_libevent,
+       foreign_event_loop_stop_libevent,
+       foreign_event_loop_cleanup_libevent
+};
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libsdevent.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libsdevent.c
new file mode 100644 (file)
index 0000000..bc712c4
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * lws-minimal-http-server-eventlib-foreign
+ *
+ * Written in 2020 by Christian Fuchs <christian.fuchs@scs.ch>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The sdevent specific code
+ */
+
+#include <libwebsockets.h>
+
+#include <string.h>
+#include <signal.h>
+
+#include <systemd/sd-event.h>
+
+#include "private.h"
+
+static struct sd_event *sd_loop;
+static sd_event_source *sd_timer;
+static sd_event_source *sd_signal;
+
+static int
+timer_cb_sd(sd_event_source *source, uint64_t now, void *user)
+{
+       foreign_timer_service(sd_loop);
+
+       if (sd_timer) {
+               sd_event_source_set_time(sd_timer, now + 1000000);
+               sd_event_source_set_enabled(sd_timer, SD_EVENT_ON);
+       }
+
+       return 0;
+}
+
+static int
+signal_cb_sd(sd_event_source *source, const struct signalfd_siginfo *si,
+             void *user)
+{
+       signal_cb((int)si->ssi_signo);
+       return 0;
+}
+
+static void
+foreign_event_loop_init_and_run_libsdevent(void)
+{
+       uint64_t now;
+
+       /* we create and start our "foreign loop" */
+
+       sd_event_default(&sd_loop);
+       sd_event_add_signal(sd_loop, &sd_signal, SIGINT, signal_cb_sd, NULL);
+
+       sd_event_now(sd_loop, CLOCK_MONOTONIC, &now);
+       sd_event_add_time(sd_loop, &sd_timer, CLOCK_MONOTONIC, now,
+                         (uint64_t) 1000, timer_cb_sd, NULL);
+
+       sd_event_loop(sd_loop);
+}
+
+static void
+foreign_event_loop_stop_libsdevent(void)
+{
+       sd_event_exit(sd_loop, 0);
+}
+
+static void
+foreign_event_loop_cleanup_libsdevent(void)
+{
+       sd_event_source_set_enabled(sd_timer, SD_EVENT_OFF);
+       sd_timer = sd_event_source_unref(sd_timer);
+
+       sd_event_source_set_enabled(sd_signal, SD_EVENT_OFF);
+       sd_signal = sd_event_source_unref(sd_signal);
+
+       sd_loop = sd_event_unref(sd_loop);
+}
+
+const struct ops ops_sdevent = {
+       foreign_event_loop_init_and_run_libsdevent,
+       foreign_event_loop_stop_libsdevent,
+       foreign_event_loop_cleanup_libsdevent
+};
+
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libuv.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libuv.c
new file mode 100644 (file)
index 0000000..df1550d
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * lws-minimal-http-server-eventlib-foreign
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The libuv specific code
+ */
+
+#include <libwebsockets.h>
+
+#include <string.h>
+#include <signal.h>
+
+#include <uv.h>
+#ifdef LWS_HAVE_UV_VERSION_H
+#include <uv-version.h>
+#endif
+#ifdef LWS_HAVE_NEW_UV_VERSION_H
+#include <uv/version.h>
+#endif
+
+#include "private.h"
+
+static uv_loop_t loop_uv;
+static uv_timer_t timer_outer_uv;
+static uv_signal_t sighandler_uv;
+
+static void
+timer_cb_uv(uv_timer_t *t)
+{
+       foreign_timer_service(&loop_uv);
+}
+
+static void
+signal_cb_uv(uv_signal_t *watcher, int signum)
+{
+       signal_cb(signum);
+}
+
+static void
+foreign_event_loop_init_and_run_libuv(void)
+{
+       /* we create and start our "foreign loop" */
+
+#if (UV_VERSION_MAJOR > 0) // Travis...
+       uv_loop_init(&loop_uv);
+#endif
+       uv_signal_init(&loop_uv, &sighandler_uv);
+       uv_signal_start(&sighandler_uv, signal_cb_uv, SIGINT);
+
+       uv_timer_init(&loop_uv, &timer_outer_uv);
+#if (UV_VERSION_MAJOR > 0) // Travis...
+       uv_timer_start(&timer_outer_uv, timer_cb_uv, 0, 1000);
+#else
+       (void)timer_cb_uv;
+#endif
+
+       uv_run(&loop_uv, UV_RUN_DEFAULT);
+}
+
+static void
+foreign_event_loop_stop_libuv(void)
+{
+       uv_stop(&loop_uv);
+}
+
+static void
+foreign_event_loop_cleanup_libuv(void)
+{
+       /* cleanup the foreign loop assets */
+
+       uv_timer_stop(&timer_outer_uv);
+       uv_close((uv_handle_t*)&timer_outer_uv, NULL);
+       uv_signal_stop(&sighandler_uv);
+       uv_close((uv_handle_t *)&sighandler_uv, NULL);
+
+       uv_run(&loop_uv, UV_RUN_DEFAULT);
+#if (UV_VERSION_MAJOR > 0) // Travis...
+       uv_loop_close(&loop_uv);
+#endif
+}
+
+const struct ops ops_libuv = {
+       foreign_event_loop_init_and_run_libuv,
+       foreign_event_loop_stop_libuv,
+       foreign_event_loop_cleanup_libuv
+};
+
index 053f1bf..a2a695d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-minimal-http-server-eventlib-foreign
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
 #include <string.h>
 #include <signal.h>
 
-struct lws_context_creation_info info;
-static struct lws_context *context;
-static int lifetime = 5, reported;
+#include "private.h"
 
-static void foreign_timer_service(void *foreign_loop);
+static struct lws_context_creation_info info;
+static const struct ops *ops = NULL;
+struct lws_context *context;
+int lifetime = 5, reported;
 
 enum {
        TEST_STATE_CREATE_LWS_CONTEXT,
@@ -57,7 +58,7 @@ static const struct lws_http_mount mount = {
        /* .basic_auth_login_file */    NULL,
 };
 
-static void
+void
 signal_cb(int signum)
 {
        lwsl_notice("Signal %d caught, exiting...\n", signum);
@@ -73,195 +74,99 @@ signal_cb(int signum)
        lws_context_destroy(context);
 }
 
-/*
- * The event-loop specific foreign loop code, one set for each event loop lib
- *
- * Only the code in this section is specific to the event library used.
- */
-
-#if defined(LWS_WITH_LIBUV)
-
-static uv_loop_t loop_uv;
-static uv_timer_t timer_outer_uv;
-static uv_signal_t sighandler_uv;
-
-static void
-timer_cb_uv(uv_timer_t *t)
+static int
+callback_http(struct lws *wsi, enum lws_callback_reasons reason,
+             void *user, void *in, size_t len)
 {
-       foreign_timer_service(&loop_uv);
-}
-
-static void
-signal_cb_uv(uv_signal_t *watcher, int signum)
-{
-       signal_cb(signum);
-}
+       switch (reason) {
 
-static void
-foreign_event_loop_init_and_run_libuv(void)
-{
-       /* we create and start our "foreign loop" */
-
-#if (UV_VERSION_MAJOR > 0) // Travis...
-       uv_loop_init(&loop_uv);
-#endif
-       uv_signal_init(&loop_uv, &sighandler_uv);
-       uv_signal_start(&sighandler_uv, signal_cb_uv, SIGINT);
-
-       uv_timer_init(&loop_uv, &timer_outer_uv);
-#if (UV_VERSION_MAJOR > 0) // Travis...
-       uv_timer_start(&timer_outer_uv, timer_cb_uv, 0, 1000);
-#else
-       (void)timer_cb_uv;
-#endif
-
-       uv_run(&loop_uv, UV_RUN_DEFAULT);
-}
-
-static void
-foreign_event_loop_stop_libuv(void)
-{
-       uv_stop(&loop_uv);
-}
-
-static void
-foreign_event_loop_cleanup_libuv(void)
-{
-       /* cleanup the foreign loop assets */
-
-       uv_timer_stop(&timer_outer_uv);
-       uv_close((uv_handle_t*)&timer_outer_uv, NULL);
-       uv_signal_stop(&sighandler_uv);
-       uv_close((uv_handle_t *)&sighandler_uv, NULL);
+       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
+               lwsl_user("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: resp %u\n",
+                               lws_http_client_http_response(wsi));
+               break;
 
-       uv_run(&loop_uv, UV_RUN_DEFAULT);
-#if (UV_VERSION_MAJOR > 0) // Travis...
-       uv_loop_close(&loop_uv);
-#endif
-}
+       /* because we are protocols[0] ... */
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+               break;
 
-#endif
+       /* chunks of chunked content, with header removed */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+               lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
+               lwsl_hexdump_info(in, len);
+               return 0; /* don't passthru */
+
+       /* uninterpreted http content */
+       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+               {
+                       char buffer[1024 + LWS_PRE];
+                       char *px = buffer + LWS_PRE;
+                       int lenx = sizeof(buffer) - LWS_PRE;
+
+                       if (lws_http_client_read(wsi, &px, &lenx) < 0)
+                               return -1;
+               }
+               return 0; /* don't passthru */
 
-#if defined(LWS_WITH_LIBEVENT)
+       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
+               lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP %s\n",
+                         lws_wsi_tag(wsi));
+               break;
 
-static struct event_base *loop_event;
-static struct event *timer_outer_event;
-static struct event *sighandler_event;
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               lwsl_info("%s: closed: %s\n", __func__, lws_wsi_tag(wsi));
+               break;
 
-static void
-timer_cb_event(int fd, short event, void *arg)
-{
-       foreign_timer_service(loop_event);
-}
+       default:
+               break;
+       }
 
-static void
-signal_cb_event(int fd, short event, void *arg)
-{
-       signal_cb((int)(lws_intptr_t)arg);
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
 }
 
-static void
-foreign_event_loop_init_and_run_libevent(void)
-{
-       struct timeval tv;
-
-       /* we create and start our "foreign loop" */
-
-       tv.tv_sec = 1;
-       tv.tv_usec = 0;
-
-       loop_event = event_base_new();
-
-       sighandler_event = evsignal_new(loop_event, SIGINT, signal_cb_event,
-                                       (void*)SIGINT);
-
-       timer_outer_event = event_new(loop_event, -1, EV_PERSIST,
-                                     timer_cb_event, NULL);
-       //evtimer_new(loop_event, timer_cb_event, NULL);
-       evtimer_add(timer_outer_event, &tv);
-
-       event_base_loop(loop_event, 0);
-}
+static const struct lws_protocols protocols[] = {
+       { "httptest", callback_http, 0, 0, 0, NULL, 0},
+       LWS_PROTOCOL_LIST_TERM
+};
 
-static void
-foreign_event_loop_stop_libevent(void)
+static int
+do_client_conn(void)
 {
-       event_base_loopexit(loop_event, NULL);
-}
+       struct lws_client_connect_info i;
 
-static void
-foreign_event_loop_cleanup_libevent(void)
-{
-       /* cleanup the foreign loop assets */
+       memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
 
-       evtimer_del(timer_outer_event);
-       event_free(timer_outer_event);
-       evsignal_del(sighandler_event);
-       event_free(sighandler_event);
+       i.context               = context;
 
-       event_base_loop(loop_event, 0);
-       event_base_free(loop_event);
-}
+       i.ssl_connection        = LCCSCF_USE_SSL;
+       i.port                  = 443;
+       i.address               = "warmcat.com";
 
+       i.ssl_connection        |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
+                                  LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
+       i.path                  = "/";
+       i.host                  = i.address;
+       i.origin                = i.address;
+       i.method                = "GET";
+       i.local_protocol_name   = protocols[0].name;
+#if defined(LWS_WITH_SYS_FAULT_INJECTION)
+       i.fi_wsi_name           = "user";
 #endif
 
-#if defined(LWS_WITH_LIBEV)
-
-static struct ev_loop *loop_ev;
-static struct ev_timer timer_outer_ev;
-static struct ev_signal sighandler_ev;
+       if (!lws_client_connect_via_info(&i)) {
+               lwsl_err("Client creation failed\n");
 
-static void
-timer_cb_ev(struct ev_loop *loop, struct ev_timer *watcher, int revents)
-{
-       foreign_timer_service(loop_ev);
-}
-
-static void
-signal_cb_ev(struct ev_loop *loop, struct ev_signal *watcher, int revents)
-{
-       signal_cb(watcher->signum);
-}
-
-static void
-foreign_event_loop_init_and_run_libev(void)
-{
-       /* we create and start our "foreign loop" */
-
-       loop_ev = ev_loop_new(0);
-
-       ev_signal_init(&sighandler_ev, signal_cb_ev, SIGINT);
-       ev_signal_start(loop_ev, &sighandler_ev);
-
-       ev_timer_init(&timer_outer_ev, timer_cb_ev, 0, 1);
-       ev_timer_start(loop_ev, &timer_outer_ev);
-
-       ev_run(loop_ev, 0);
-}
-
-static void
-foreign_event_loop_stop_libev(void)
-{
-       ev_break(loop_ev, EVBREAK_ALL);
-}
-
-static void
-foreign_event_loop_cleanup_libev(void)
-{
-       /* cleanup the foreign loop assets */
-
-       ev_timer_stop(loop_ev, &timer_outer_ev);
-       ev_signal_stop(loop_ev, &sighandler_ev);
+               return 1;
+       }
 
-       ev_run(loop_ev, UV_RUN_DEFAULT);
-       ev_loop_destroy(loop_ev);
+       return 0;
 }
 
-#endif
 
 /* this is called at 1Hz using a foreign loop timer */
 
-static void
+void
 foreign_timer_service(void *foreign_loop)
 {
        void *foreign_loops[1];
@@ -292,6 +197,9 @@ foreign_timer_service(void *foreign_loop)
                        return;
                }
                lwsl_user("LWS Context created and will be active for 10s\n");
+
+               do_client_conn();
+
                lifetime = 11;
                break;
 
@@ -304,18 +212,7 @@ foreign_timer_service(void *foreign_loop)
 
        case TEST_STATE_EXIT:
                lwsl_user("Deciding to exit foreign loop too\n");
-#if defined(LWS_WITH_LIBUV)
-               if (info.options & LWS_SERVER_OPTION_LIBUV)
-                       foreign_event_loop_stop_libuv();
-#endif
-#if defined(LWS_WITH_LIBEVENT)
-               if (info.options & LWS_SERVER_OPTION_LIBEVENT)
-                       foreign_event_loop_stop_libevent();
-#endif
-#if defined(LWS_WITH_LIBEV)
-               if (info.options & LWS_SERVER_OPTION_LIBEV)
-                       foreign_event_loop_stop_libev();
-#endif
+               ops->stop();
                break;
        default:
                break;
@@ -348,32 +245,73 @@ int main(int argc, const char **argv)
 
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
        info.port = 7681;
+       if ((p = lws_cmdline_option(argc, argv, "-p")))
+               info.port = atoi(p);
        info.mounts = &mount;
        info.error_document_404 = "/404.html";
        info.pcontext = &context;
-       info.options =
+       info.protocols = protocols;
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
 
        if (lws_cmdline_option(argc, argv, "-s")) {
-               info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
        }
 
-       if (lws_cmdline_option(argc, argv, "--uv"))
+       /*
+        * We configure lws to use the chosen event loop, and select the
+        * matching event-lib specific code for our demo operations
+        */
+
+#if defined(LWS_WITH_LIBUV)
+       if (lws_cmdline_option(argc, argv, "--uv")) {
                info.options |= LWS_SERVER_OPTION_LIBUV;
-       else
-               if (lws_cmdline_option(argc, argv, "--event"))
+               ops = &ops_libuv;
+               lwsl_notice("%s: using libuv event loop\n", __func__);
+       } else
+#endif
+#if defined(LWS_WITH_LIBEVENT)
+               if (lws_cmdline_option(argc, argv, "--event")) {
                        info.options |= LWS_SERVER_OPTION_LIBEVENT;
-               else
-                       if (lws_cmdline_option(argc, argv, "--ev"))
+                       ops = &ops_libevent;
+                       lwsl_notice("%s: using libevent loop\n", __func__);
+               } else
+#endif
+#if defined(LWS_WITH_LIBEV)
+                       if (lws_cmdline_option(argc, argv, "--ev")) {
                                info.options |= LWS_SERVER_OPTION_LIBEV;
-                       else {
+                               ops = &ops_libev;
+                               lwsl_notice("%s: using libev loop\n", __func__);
+                       } else
+#endif
+#if defined(LWS_WITH_GLIB)
+                               if (lws_cmdline_option(argc, argv, "--glib")) {
+                                       info.options |= LWS_SERVER_OPTION_GLIB;
+                                       ops = &ops_glib;
+                                       lwsl_notice("%s: using glib loop\n", __func__);
+                               } else
+#endif
+#if defined(LWS_WITH_SDEVENT)
+                                       if (lws_cmdline_option(argc, argv, "--sd")) {
+                                               info.options |= LWS_SERVER_OPTION_SDEVENT;
+                                               ops = &ops_sdevent;
+                                               lwsl_notice("%s: using sd-event loop\n", __func__);
+                                       } else
+#endif
+#if defined(LWS_WITH_ULOOP)
+                                       if (lws_cmdline_option(argc, argv, "--uloop")) {
+                                               info.options |= LWS_SERVER_OPTION_ULOOP;
+                                               ops = &ops_uloop;
+                                               lwsl_notice("%s: using uloop loop\n", __func__);
+                                       } else
+#endif
+                               {
                                lwsl_err("This app only makes sense when used\n");
-                               lwsl_err(" with a foreign loop, --uv, --event, or --ev\n");
+                               lwsl_err(" with a foreign loop, --uv, --event, --glib, --ev or --sd\n");
 
                                return 1;
-                       }
+                               }
 
        lwsl_user("  This app creates a foreign event loop with a timer +\n");
        lwsl_user("  signalhandler, and performs a test in three phases:\n");
@@ -389,35 +327,13 @@ int main(int argc, const char **argv)
 
        /* foreign loop specific startup and run */
 
-#if defined(LWS_WITH_LIBUV)
-       if (info.options & LWS_SERVER_OPTION_LIBUV)
-               foreign_event_loop_init_and_run_libuv();
-#endif
-#if defined(LWS_WITH_LIBEVENT)
-       if (info.options & LWS_SERVER_OPTION_LIBEVENT)
-               foreign_event_loop_init_and_run_libevent();
-#endif
-#if defined(LWS_WITH_LIBEV)
-       if (info.options & LWS_SERVER_OPTION_LIBEV)
-               foreign_event_loop_init_and_run_libev();
-#endif
+       ops->init_and_run();
 
        lws_context_destroy(context);
 
        /* foreign loop specific cleanup and exit */
 
-#if defined(LWS_WITH_LIBUV)
-       if (info.options & LWS_SERVER_OPTION_LIBUV)
-               foreign_event_loop_cleanup_libuv();
-#endif
-#if defined(LWS_WITH_LIBEVENT)
-       if (info.options & LWS_SERVER_OPTION_LIBEVENT)
-               foreign_event_loop_cleanup_libevent();
-#endif
-#if defined(LWS_WITH_LIBEV)
-       if (info.options & LWS_SERVER_OPTION_LIBEV)
-               foreign_event_loop_cleanup_libev();
-#endif
+       ops->cleanup();
 
        lwsl_user("%s: exiting...\n", __func__);
 
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h
new file mode 100644 (file)
index 0000000..17928c6
--- /dev/null
@@ -0,0 +1,15 @@
+
+
+struct ops {
+       void (*init_and_run)(void);
+       void (*stop)(void);
+       void (*cleanup)(void);
+};
+
+extern struct lws_context *context;
+extern int lifetime, reported;
+
+void foreign_timer_service(void *foreign_loop);
+void signal_cb(int signum);
+
+extern const struct ops ops_libuv, ops_libevent, ops_glib, ops_libev, ops_sdevent, ops_uloop;
diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/uloop.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/uloop.c
new file mode 100644 (file)
index 0000000..c528e89
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * lws-minimal-http-server-eventlib-foreign
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The uloop specific code
+ */
+
+#include <libwebsockets.h>
+
+#include <libubox/uloop.h>
+
+#include <string.h>
+#include <signal.h>
+
+#include "private.h"
+
+static struct uloop_timeout timer_outer_uloop;
+
+static void
+timer_cb_uloop(struct uloop_timeout *ti)
+{
+       foreign_timer_service(NULL);
+       uloop_timeout_set(&timer_outer_uloop, 1090);
+}
+
+static void
+foreign_event_loop_init_and_run_uloop(void)
+{
+       uloop_init();
+
+       timer_outer_uloop.cb = timer_cb_uloop;
+       uloop_timeout_add(&timer_outer_uloop);
+
+       uloop_timeout_set(&timer_outer_uloop, 1090);
+
+       uloop_run();
+}
+
+static void
+foreign_event_loop_stop_uloop(void)
+{
+       uloop_end();
+}
+
+static void
+foreign_event_loop_cleanup_uloop(void)
+{
+       uloop_timeout_cancel(&timer_outer_uloop);
+}
+
+const struct ops ops_uloop = {
+       foreign_event_loop_init_and_run_uloop,
+       foreign_event_loop_stop_uloop,
+       foreign_event_loop_cleanup_uloop
+};
index a60b3d6..087202d 100644 (file)
@@ -1,91 +1,26 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-eventlib-smp C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckIncludeFile)
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-eventlib-smp)
 set(SRCS minimal-http-server-eventlib-smp.c)
 
-MACRO(require_pthreads result)
-       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
-       if (NOT LWS_HAVE_PTHREAD_H)
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(result 0)
-               else()
-                       message(FATAL_ERROR "threading support requires pthreads")
-               endif()
-       endif()
-ENDMACRO()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_pthreads(requirements)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared pthread)
-               add_dependencies(${SAMP} websockets_shared pthread)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared ${PTHREAD_LIB})
        else()
-               target_link_libraries(${SAMP} websockets pthread)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 7e166e6..7a7f3f7 100644 (file)
 #include <string.h>
 #include <signal.h>
 
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
+
 #include <pthread.h>
 
 #define COUNT_THREADS 8
@@ -109,17 +116,19 @@ int main(int argc, const char **argv)
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
 
        if ((p = lws_cmdline_option(argc, argv, "-t"))) {
-               info.count_threads = atoi(p);
+               info.count_threads = (unsigned int)atoi(p);
                if (info.count_threads < 1 || info.count_threads > LWS_MAX_SMP)
                        return 1;
        } else
                info.count_threads = COUNT_THREADS;
 
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
        }
+#endif
 
        if (lws_cmdline_option(argc, argv, "--uv"))
                info.options |= LWS_SERVER_OPTION_LIBUV;
@@ -130,7 +139,10 @@ int main(int argc, const char **argv)
                        if (lws_cmdline_option(argc, argv, "--ev"))
                                info.options |= LWS_SERVER_OPTION_LIBEV;
                        else
-                               signal(SIGINT, sigint_handler);
+                               if (lws_cmdline_option(argc, argv, "--glib"))
+                                       info.options |= LWS_SERVER_OPTION_GLIB;
+                               else
+                                       signal(SIGINT, sigint_handler);
 
        context = lws_create_context(&info);
        if (!context) {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 66a4452..57badf3 100644 (file)
@@ -1,78 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-eventlib C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-eventlib)
 set(SRCS minimal-http-server-eventlib.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 9c2d49c..a1fed6d 100644 (file)
@@ -86,11 +86,13 @@ int main(int argc, const char **argv)
        info.options =
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
 
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
        }
+#endif
 
        if (lws_cmdline_option(argc, argv, "--uv"))
                info.options |= LWS_SERVER_OPTION_LIBUV;
@@ -101,7 +103,10 @@ int main(int argc, const char **argv)
                        if (lws_cmdline_option(argc, argv, "--ev"))
                                info.options |= LWS_SERVER_OPTION_LIBEV;
                        else
-                               signal(SIGINT, sigint_handler);
+                               if (lws_cmdline_option(argc, argv, "--glib"))
+                                       info.options |= LWS_SERVER_OPTION_GLIB;
+                               else
+                                       signal(SIGINT, sigint_handler);
 
        context = lws_create_context(&info);
        if (!context) {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 1b43056..0ef0f3c 100644 (file)
@@ -1,77 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-form-get C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-form-get)
 set(SRCS minimal-http-server-form-get.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index de149ac..d0ce969 100644 (file)
@@ -29,7 +29,6 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
        uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE],
                *start = &buf[LWS_PRE], *p = start,
                *end = &buf[sizeof(buf) - 1];
-       const char *val;
        int n;
 
        switch (reason) {
@@ -46,13 +45,13 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                /* we just dump the decoded things to the log */
 
                for (n = 0; n < (int)LWS_ARRAY_SIZE(param_names); n++) {
-                       val = lws_get_urlarg_by_name(wsi, param_names[n],
+                       int rv = lws_get_urlarg_by_name_safe(wsi, param_names[n],
                                        (char *)buf, sizeof(buf));
-                       if (!val)
+                       if (rv < 0)
                                lwsl_user("%s: undefined\n", param_names[n]);
                        else
                                lwsl_user("%s: (len %d) '%s'\n", param_names[n],
-                                         (int)strlen((const char *)buf),buf);
+                                         (int)rv, buf);
                }
 
                /*
@@ -74,8 +73,8 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 }
 
 static struct lws_protocols protocols[] = {
-       { "http", callback_http, 0, 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "http", callback_http, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 /* default mount serves the URL space from ./mount-origin */
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 1cffb98..f1b5c36 100644 (file)
@@ -1,77 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-form-post-file C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-form-post-file)
 set(SRCS minimal-http-server-form-post-file.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 14d78cd..0b41f40 100644 (file)
@@ -15,7 +15,9 @@
 #include <libwebsockets.h>
 #include <string.h>
 #include <signal.h>
+#if !defined(WIN32)
 #include <unistd.h>
+#endif
 #include <fcntl.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -69,9 +71,9 @@ file_upload_cb(void *data, const char *name, const char *filename,
                if (len) {
                        int n;
 
-                       pss->file_length += len;
+                       pss->file_length += (unsigned int)len;
 
-                       n = write(pss->fd, buf, len);
+                       n = (int)write(pss->fd, buf, (unsigned int)len);
                        if (n < len) {
                                lwsl_notice("Problem writing file %d\n", errno);
                        }
@@ -186,8 +188,8 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 }
 
 static struct lws_protocols protocols[] = {
-       { "http", callback_http, sizeof(struct pss), 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 /* default mount serves the URL space from ./mount-origin */
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index eec5b06..c7e0a11 100644 (file)
@@ -1,77 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-form-post-lwsac C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-form-post-lwsac)
 set(SRCS minimal-http-server-form-post.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 5acc255..225cdd6 100644 (file)
@@ -137,8 +137,8 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 }
 
 static struct lws_protocols protocols[] = {
-       { "http", callback_http, sizeof(struct pss), 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 /* default mount serves the URL space from ./mount-origin */
@@ -198,8 +198,10 @@ int main(int argc, const char **argv)
 
        if (lws_cmdline_option(argc, argv, "-s")) {
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#if defined(LWS_WITH_TLS)
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
+#endif
        }
 
        context = lws_create_context(&info);
index 32a9f76..ac3e4ff 100644 (file)
@@ -1,77 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-form-post C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-form-post)
 set(SRCS minimal-http-server-form-post.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index c7d0943..58af16e 100644 (file)
@@ -24,7 +24,7 @@ struct pss {
        struct lws_spa *spa;
 };
 
-static int interrupted;
+static int interrupted, use303;
 
 static const char * const param_names[] = {
        "text1",
@@ -81,6 +81,11 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                        return -1;
                break;
 
+       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
+               if (pss->spa && lws_spa_destroy(pss->spa))
+                       return -1;
+               break;
+
        case LWS_CALLBACK_HTTP_BODY_COMPLETION:
 
                /* inform the spa no more payload data coming */
@@ -90,22 +95,24 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 
                /* we just dump the decoded things to the log */
 
-               for (n = 0; n < (int)LWS_ARRAY_SIZE(param_names); n++) {
-                       if (!lws_spa_get_string(pss->spa, n))
-                               lwsl_user("%s: undefined\n", param_names[n]);
-                       else
-                               lwsl_user("%s: (len %d) '%s'\n",
-                                   param_names[n],
-                                   lws_spa_get_length(pss->spa, n),
-                                   lws_spa_get_string(pss->spa, n));
-               }
+               if (pss->spa)
+                       for (n = 0; n < (int)LWS_ARRAY_SIZE(param_names); n++) {
+                               if (!lws_spa_get_string(pss->spa, n))
+                                       lwsl_user("%s: undefined\n", param_names[n]);
+                               else
+                                       lwsl_user("%s: (len %d) '%s'\n",
+                                           param_names[n],
+                                           lws_spa_get_length(pss->spa, n),
+                                           lws_spa_get_string(pss->spa, n));
+                       }
 
                /*
                 * Our response is to redirect to a static page.  We could
                 * have generated a dynamic html page here instead.
                 */
 
-               if (lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
+               if (lws_http_redirect(wsi, use303 ? HTTP_STATUS_SEE_OTHER :
+                                          HTTP_STATUS_MOVED_PERMANENTLY,
                                      (unsigned char *)"after-form1.html",
                                      16, &p, end) < 0)
                        return -1;
@@ -127,8 +134,8 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 }
 
 static struct lws_protocols protocols[] = {
-       { "http", callback_http, sizeof(struct pss), 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 /* default mount serves the URL space from ./mount-origin */
@@ -185,12 +192,21 @@ int main(int argc, const char **argv)
        info.mounts = &mount;
        info.options =
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
-
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
        }
+#endif
+
+       if ((p = lws_cmdline_option(argc, argv, "--port")))
+               info.port = atoi(p);
+
+       if (lws_cmdline_option(argc, argv, "--303")) {
+               lwsl_user("%s: using 303 redirect\n", __func__);
+               use303 = 1;
+       }
 
        context = lws_create_context(&info);
        if (!context) {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 6032845..160e054 100644 (file)
@@ -1,82 +1,27 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-fulltext-search C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-fulltext-search)
 set(SRCS minimal-http-server.c)
 
 include_directories(../../../plugins)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
 require_lws_config(LWS_WITH_FTS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 29b3ec3..010ef74 100644 (file)
@@ -21,7 +21,7 @@ static int interrupted;
 
 static struct lws_protocols protocols[] = {
        LWS_PLUGIN_PROTOCOL_FULLTEXT_DEMO,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static struct lws_protocol_vhost_options pvo_idx = {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 8da940b..af4731a 100644 (file)
@@ -1,21 +1,35 @@
 /* lws-fts.js - JS supporting lws fulltext search
  *
- * Copyright (C) 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
+
 (function() {
        
        var last_ac = "";
        
        function san(s)
        {
-               s.replace("<", "!");
-               s.replace("%", "!");
+               s.replace(/</g, "!");
+               s.replace(/%/g, "!");
                
                return s;
        }
                };
 
                xhr.onload = function(e) {      
-                       var jj, n, m, s = "", x, lic = 0, hl, re;
+                       var jj, n, m, s = "", lic = 0;
                        var sr = document.getElementById("searchresults");
-                       var ac = document.getElementById("acomplete");
                        var inp = document.getElementById("lws_fts");
                        sr.style.width = (parseInt(sr.parentNode.offsetWidth, 10) - 88) + "px";
                        sr.style.opacity = "1";
                        inp.blur();
                        
-                       hl = document.getElementById("lws_fts").value;
-                       re = new RegExp(hl, "gi");
-                       
                        // console.log(xhr.responseText);
                        jj = JSON.parse(xhr.responseText);
                        
                        if (jj.fp) {
                                lic = jj.fp.length;                                             
                                for (n = 0; n < lic; n++) {
-                                       var q;
                                        
                                        s += "<div class='filepath'>" + jj.fp[n].path + "</div>";
                                        
                        xhr.setRequestHeader("cache-control", "max-age=0");
                };
                xhr.onload = function(e) {
-                       var jj, n, s = "", x, lic = 0;
+                       var jj, n, s = "", lic = 0;
                        var inp = document.getElementById("lws_fts");
                        var ac = document.getElementById("acomplete");
                        
 
        }, false);
        
-}());
\ No newline at end of file
+}());
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-generic-sessions/CMakeLists.txt
deleted file mode 100644 (file)
index dc9b0f4..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-cmake_minimum_required(VERSION 2.8)
-include(CheckCSourceCompiles)
-
-set(SAMP lws-minimal-http-server-generic-sessions)
-set(SRCS minimal-http-server-generic-sessions.c)
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
-set(requirements 1)
-require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
-require_lws_config(LWS_OPENSSL_SUPPORT 1 requirements)
-require_lws_config(LWS_WITH_GENERIC_SESSIONS 1 requirements)
-require_lws_config(LWS_WITH_LIBUV 1 requirements)
-require_lws_config(LWS_WITH_PLUGINS 1 requirements)
-
-if (requirements)
-       add_executable(${SAMP} ${SRCS})
-
-       if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
-               add_dependencies(${SAMP} websockets_shared)
-       else()
-               target_link_libraries(${SAMP} websockets)
-       endif()
-endif()
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/README.md b/minimal-examples/http-server/minimal-http-server-generic-sessions/README.md
deleted file mode 100644 (file)
index 976aea6..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# lws minimal http server with generic-sessions
-
-## build
-
-```
- $ cmake . && make
-```
-
-## usage
-
-```
- $ ./lws-minimal-http-server-tls
-[2018/03/20 13:23:13:0131] USER: LWS minimal http server TLS | visit https://localhost:7681
-[2018/03/20 13:23:13:0142] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 off
-[2018/03/20 13:23:13:0142] NOTICE:  Using SSL mode
-[2018/03/20 13:23:13:0146] NOTICE:  SSL ECDH curve 'prime256v1'
-[2018/03/20 13:23:13:0146] NOTICE:  HTTP2 / ALPN enabled
-[2018/03/20 13:23:13:0195] NOTICE: lws_tls_client_create_vhost_context: doing cert filepath localhost-100y.cert
-[2018/03/20 13:23:13:0195] NOTICE: Loaded client cert localhost-100y.cert
-[2018/03/20 13:23:13:0195] NOTICE: lws_tls_client_create_vhost_context: doing private key filepath
-[2018/03/20 13:23:13:0196] NOTICE: Loaded client cert private key localhost-100y.key
-[2018/03/20 13:23:13:0196] NOTICE: created client ssl context for default
-[2018/03/20 13:23:14:0207] NOTICE:    vhost default: cert expiry: 730459d
-```
-
-
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/minimal-http-server-generic-sessions.c b/minimal-examples/http-server/minimal-http-server-generic-sessions/minimal-http-server-generic-sessions.c
deleted file mode 100644 (file)
index f4e11e6..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * lws-minimal-http-server-generic-sessions
- *
- * Copyright (C) 2019 Andy Green <andy@warmcat.com>
- *
- * This file is made available under the Creative Commons CC0 1.0
- * Universal Public Domain Dedication.
- *
- * This demonstrates setting up and using generic sessions
- */
-
-#include <libwebsockets.h>
-#include <string.h>
-#include <signal.h>
-
-static int interrupted;
-struct lws_context *context;
-
-static const struct lws_protocol_vhost_options
-   pvo_mm1 = {
-       NULL, NULL, "message-db", (void *)"/var/www/sessions/messageboard.sqlite3"
-}, pvo_m1 = {
-       NULL, &pvo_mm1, "protocol-lws-messageboard", ""
-},
-
-   pvo13 = {
-       NULL, NULL, "email-confirm-url-base", (void *)"https://localhost:7681/"
-}, pvo12 = {
-       &pvo13, NULL, "urlroot", (void *)"https://127.0.0.1:7681/"
-}, pvo11 = {
-       &pvo12, NULL, "email-contact-person", (void *)"andy@warmcat.com"
-}, pvo10 = {
-       &pvo11, NULL, "email-helo", (void *)"warmcat.com"
-}, pvo9 = {
-       &pvo10, NULL, "email-expire", (void *)"3600"
-}, pvo8 = {
-       &pvo9,  NULL, "email-smtp-ip", (void *)"127.0.0.1"
-}, pvo7 = {
-       &pvo8,  NULL, "email-from", (void *)"noreply@warmcat.com"
-}, pvo6 = {
-       &pvo7,  NULL, "confounder", (void *)"some kind of secret confounder"
-}, pvo5 = {
-       &pvo6,  NULL, "timeout-anon-idle-secs", (void *)"1200"
-}, pvo4 = {
-       &pvo5,  NULL, "timeout-idle-secs", (void *)"6000"
-}, pvo3 = {
-       &pvo4,  NULL, "session-db", (void *)"/var/www/sessions/lws.sqlite3"
-}, pvo2 = {
-       &pvo3, NULL, "admin-password-sha256",
-       (void *)"25d08521d996bad92605f5a40fe71179dc968e70f669cb1db6190dcd53258200"      /* pvo value */
-}, pvo1 = {
-       &pvo2, NULL, "admin-user", (void *)"admin"
-}, pvo = {
-       &pvo_m1, &pvo1, "protocol-generic-sessions", ""
-},
-
-   interpret1 = {
-       NULL, NULL, ".js", "protocol-lws-messageboard"
-},
-
-   pvo_hsbph[] = {{
-       NULL, NULL,             "referrer-policy:", "no-referrer"
-}, {
-       &pvo_hsbph[0], NULL,    "x-xss-protection:", "1; mode=block"
-}, {
-       &pvo_hsbph[1], NULL,    "x-content-type-options:", "nosniff"
-}, {
-       &pvo_hsbph[2], NULL,    "content-security-policy:",
-                               "default-src 'self'; "
-                               "img-src https://www.gravatar.com 'self' data: ; "
-                               "script-src 'self'; "
-                               "font-src 'self'; "
-                               "style-src 'self'; "
-                               "connect-src 'self'; "
-                               "frame-ancestors 'self'; "
-                               "base-uri 'none'; "
-                               "form-action  'self';"
-}};
-
- static const struct lws_http_mount mount2 = {
-       /* .mount_next */               NULL,   /* linked-list "next" */
-       /* .mountpoint */               "/needadmin",           /* mountpoint URL */
-       /* .origin */                   "./mount-origin/needadmin", /* serve from dir */
-       /* .def */                      "index.html",   /* default filename */
-       /* .protocol */                 "protocol-lws-messageboard",
-       /* .cgienv */                   NULL,
-       /* .extra_mimetypes */          NULL,
-       /* .interpret */                &interpret1,
-       /* .cgi_timeout */              0,
-       /* .cache_max_age */            0,
-       /* .auth_mask */                7,
-       /* .cache_reusable */           0,
-       /* .cache_revalidate */         0,
-       /* .cache_intermediaries */     0,
-       /* .origin_protocol */          LWSMPRO_FILE,   /* files in a dir */
-       /* .mountpoint_len */           1,              /* char count */
-       /* .basic_auth_login_file */    NULL,
- };
-
- static const struct lws_http_mount mount1 = {
-       /* .mount_next */               &mount2,        /* linked-list "next" */
-       /* .mountpoint */               "/needauth",            /* mountpoint URL */
-       /* .origin */                   "./mount-origin/needauth", /* serve from dir */
-       /* .def */                      "index.html",   /* default filename */
-       /* .protocol */                 "protocol-lws-messageboard",
-       /* .cgienv */                   NULL,
-       /* .extra_mimetypes */          NULL,
-       /* .interpret */                &interpret1,
-       /* .cgi_timeout */              0,
-       /* .cache_max_age */            0,
-       /* .auth_mask */                5,
-       /* .cache_reusable */           0,
-       /* .cache_revalidate */         0,
-       /* .cache_intermediaries */     0,
-       /* .origin_protocol */          LWSMPRO_FILE,   /* files in a dir */
-       /* .mountpoint_len */           1,              /* char count */
-       /* .basic_auth_login_file */    NULL,
- };
-
-static const struct lws_http_mount mount = {
-       /* .mount_next */               &mount1,        /* linked-list "next" */
-       /* .mountpoint */               "/",            /* mountpoint URL */
-       /* .origin */                   "./mount-origin", /* serve from dir */
-       /* .def */                      "index.html",   /* default filename */
-       /* .protocol */                 "protocol-lws-messageboard",
-       /* .cgienv */                   NULL,
-       /* .extra_mimetypes */          NULL,
-       /* .interpret */                &interpret1,
-       /* .cgi_timeout */              0,
-       /* .cache_max_age */            0,
-       /* .auth_mask */                0,
-       /* .cache_reusable */           0,
-       /* .cache_revalidate */         0,
-       /* .cache_intermediaries */     0,
-       /* .origin_protocol */          LWSMPRO_FILE,   /* files in a dir */
-       /* .mountpoint_len */           1,              /* char count */
-       /* .basic_auth_login_file */    NULL,
-};
-
-void sigint_handler(int sig)
-{
-       lws_context_destroy(context);
-
-       interrupted = 1;
-}
-
-int main(int argc, const char **argv)
-{
-       struct lws_context_creation_info info;
-       const char *p, *plugin_dirs[] = {
-               "/usr/local/share/libwebsockets-test-server/plugins",
-               NULL };
-       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
-                       /* for LLL_ verbosity above NOTICE to be built into lws,
-                        * lws must have been configured and built with
-                        * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
-                       /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
-                       /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
-                       /* | LLL_DEBUG */;
-
-       if ((p = lws_cmdline_option(argc, argv, "-d")))
-               logs = atoi(p);
-
-       lws_set_log_level(logs, NULL);
-       lwsl_user("LWS minimal http server TLS | visit https://localhost:7681\n");
-
-       signal(SIGINT, sigint_handler);
-
-       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
-       info.port = 7681;
-       info.mounts = &mount;
-       info.error_document_404 = "/404.html";
-       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
-                      LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
-       info.ssl_cert_filepath = "localhost-100y.cert";
-       info.ssl_private_key_filepath = "localhost-100y.key";
-       info.plugin_dirs = plugin_dirs;
-       info.pvo = &pvo;
-
-       if (lws_cmdline_option(argc, argv, "-h"))
-               info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
-
-       context = lws_create_context(&info);
-       if (!context) {
-               lwsl_err("lws init failed\n");
-               return 1;
-       }
-
-       info.headers = &pvo_hsbph[3];
-
-       if (!lws_create_vhost(context, &info)) {
-               lwsl_err("lws init failed\n");
-               return 1;
-       }
-
-       while (n >= 0 && !interrupted)
-               n = lws_service(context, 0);
-
-       lws_context_destroy(context);
-
-       return 0;
-}
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/admin-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/admin-login.html
deleted file mode 100644 (file)
index 113df9c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-This is an example destination that will appear after successful Admin login.
-
-This URL cannot be served if you're not logged in as admin.
-</html>
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/example.js b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/example.js
deleted file mode 100644 (file)
index 1606ea0..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-document.addEventListener("DOMContentLoaded", function() {
-
-       var transport_protocol = "";
-       
-       if ( performance && performance.timing.nextHopProtocol ) {
-           transport_protocol = performance.timing.nextHopProtocol;
-       } else if ( window.chrome && window.chrome.loadTimes ) {
-           transport_protocol = window.chrome.loadTimes().connectionInfo;
-       } else {
-       
-         var p = performance.getEntriesByType("resource");
-         for (var i=0; i < p.length; i++) {
-               var value = "nextHopProtocol" in p[i];
-                 if (value)
-                   transport_protocol = p[i].nextHopProtocol;
-           }
-          }
-          
-          if (transport_protocol == "h2")
-               document.getElementById("transport").innerHTML = "<img src=\"/http2.png\">";
-       }
-}, false);
\ No newline at end of file
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/failed-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/failed-login.html
deleted file mode 100644 (file)
index 9ab065b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<html>
-This is an example destination that will appear after a failed login
-</html>
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/http2.png b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/http2.png
deleted file mode 100644 (file)
index 439bfa4..0000000
Binary files a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/http2.png and /dev/null differ
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/index.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/index.html
deleted file mode 100644 (file)
index 0695d5d..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-<html>
- <head>
- <meta charset="UTF-8"> 
-  <script src="/lws-common.js"></script>
-  <link rel="stylesheet" type="text/css" href="lwsgs.css"/>
-  <script src="lwsgs.js"></script>
-  </head>
-
-  <body class="seats">
-    <table class="lwsgs">
-     <tr>
-      <td class="logo">
-       <img src="lwsgs.svg">
-      </td>
-      <td class="">
-       <div id=lwsgs class="lwsgs"></div>
-      </td>
-            <td class="rlogo">
-       <img src="strict-csp.svg">
-      </td>
-     </tr>
-     
-     <tr><td colspan="3" class="h99">
-        <table class="c100"><tr>
-        <td class="c">
-       <span id="nolog" class="group2">
-       This is a demo application for lws generic-sessions.<br><br>
-       It's a simple messageboard.<br><br>
-       What's interesting about it is there is <b>no serverside scripting</b>,<br>
-       instead client js makes a wss:// connection back to the server<br>
-       and then reacts to JSON from the ws protocol.  Sessions stuff is <br>
-       handled by lws generic sessions, making the <a href="https://libwebsockets.org/git/libwebsockets/tree/plugins/generic-sessions/protocol_generic_sessions.c">actual<br>
-       test application</a> <a href="https://libwebsockets.org/git/libwebsockets/tree/plugins/generic-sessions/protocol_lws_messageboard.c">very small</a>.<br><br>
-       And because it's natively websocket, it's naturally connected<br>
-       for dynamic events and easy to maintain.
-       <br><br>
-       Register / Login at the top right to see and create new messages.
-       </span>
-       <span id="logged" class="group2">
-       <div id="newmsg">
-               <form action="/msg" method="post" target="hidden">
-               New message<br>
-         <textarea id="msg" placeholder="type your message here" cols="40" rows="5" name="msg"></textarea><br>
-               <input type="submit" id="send" name="send" disabled=1>
-               </form>
-       </div>
-       </span>
-       <div id="dmessages">
-        <span id="messages" ></span>
-       </div>
-       <span id="debug" class="group2"></span>
-       </td></tr></table>
-     </td></tr>
-    </table>
-   <iframe name="hidden" class="hidden"></iframe>
- </body>
-</html>
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/libwebsockets.org-logo.svg b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/libwebsockets.org-logo.svg
deleted file mode 100644 (file)
index 7baea64..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
-</svg>
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lws-common.js b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lws-common.js
deleted file mode 100644 (file)
index 5d56ca2..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * This section around grayOut came from here:
- * http://www.codingforums.com/archive/index.php/t-151720.html
- * Assumed public domain
- *
- * Init like this in your main html script, this also reapplies the gray
- *
- *    lws_gray_out(true,{'zindex':'499'});
- *
- * To remove the gray
- *
- *    lws_gray_out(false);
- *
- */
-
-function gsize(ptype)
-{
-       var h = document.compatMode === "CSS1Compat" &&
-               !window.opera ?
-                       document.documentElement.clientHeight :
-                                               document.body.clientHeight;
-       var w = document.compatMode === "CSS1Compat" &&
-               !window.opera ? 
-                       document.documentElement.clientWidth :
-                                               document.body.clientWidth;
-       var pageWidth, pageHeight, t;
-
-       if (document.body && 
-                   (document.body.scrollWidth || document.body.scrollHeight)) {
-               t = document.body.scrollWidth;
-               pageWidth = (w > t) ? ("" + w + "px") : ("" + (t) + "px");
-               t = document.body.scrollHeight;
-               pageHeight = (h > t) ? ("" + h + "px") : ("" + (t) + "px");
-       } else if (document.body.offsetWidth) {
-               t = document.body.offsetWidth;
-               pageWidth = (w > t) ? ("" + w + "px") : ("" + (t) + "px");
-               t = document.body.offsetHeight;
-               pageHeight =(h > t) ? ("" + h + "px") : ("" + (t) + "px");
-       } else {
-               pageWidth = "100%";
-               pageHeight = "100%";
-       }
-       return (ptype === 1) ? pageWidth : pageHeight;
-}
-
-function addEvent( obj, type, fn ) {
-       if ( obj.attachEvent ) {
-               obj["e" + type + fn] = fn;
-               obj[type+fn] = function() { obj["e" + type + fn]( window.event );};
-               obj.attachEvent("on" + type, obj[type + fn]);
-       } else
-               obj.addEventListener(type, fn, false);
-}
-
-function removeEvent( obj, type, fn ) {
-       if ( obj.detachEvent ) {
-               obj.detachEvent("on" + type, obj[type + fn]);
-               obj[type + fn] = null;
-       } else
-               obj.removeEventListener(type, fn, false);
-}
-
-function lws_gray_out(vis, _options) {
-
-       var options = _options || {};
-       var zindex = options.zindex || 50;
-       var opacity = options.opacity || 70;
-       var opaque = (opacity / 100);
-       var bgcolor = options.bgcolor || "#000000";
-       var dark = document.getElementById("darkenScreenObject");
-
-       if (!dark) {
-               var tbody = document.getElementsByTagName("body")[0];
-               var tnode = document.createElement("div");
-               tnode.style.position = "absolute";
-               tnode.style.top = "0px";
-               tnode.style.left = "0px";
-               tnode.style.overflow = "hidden";
-               tnode.style.display ="none";
-               tnode.id = "darkenScreenObject";
-               tbody.appendChild(tnode);
-               dark = document.getElementById("darkenScreenObject");
-       }
-       if (vis) {
-               dark.style.opacity = opaque;
-               dark.style.MozOpacity = opaque;
-               // dark.style.filter ='alpha(opacity='+opacity+')';
-               dark.style.zIndex = zindex;
-               dark.style.backgroundColor = bgcolor;
-               dark.style.width = gsize(1);
-               dark.style.height = gsize(0);
-               dark.style.display = "block";
-               addEvent(window, "resize",
-                       function() {
-                               dark.style.height = gsize(0);
-                               dark.style.width = gsize(1);
-                       }
-               );
-       } else {
-               dark.style.display = "none";
-               removeEvent(window, "resize",
-                       function() {
-                               dark.style.height = gsize(0);
-                               dark.style.width = gsize(1);
-                       }
-               );
-       }
-}
-
-/*
- * end of grayOut related stuff
- */
-
-function new_ws(urlpath, protocol)
-{
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
-       return new WebSocket(urlpath, protocol);
-}
-function lws_san(s)
-{
-       if (s.search("<") !== -1)
-               return "invalid string";
-       
-       return s;
-}
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs-logo.png b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs-logo.png
deleted file mode 100644 (file)
index 723a124..0000000
Binary files a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs-logo.png and /dev/null differ
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.css b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.css
deleted file mode 100644 (file)
index 907851f..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-.body { font-size: 12px }
-.gstitle { font-size: 18px }
-
-.group1 {
-       vertical-align:middle;
-       text-align:center;
-       background:#f0f0e0; 
-       padding:12px;
-       border-radius:10px;
-}
-.group2 {
-       display:block;
-       vertical-align:middle;
-       font-size: 22px;
-       text-align:center;
-       margin:auto;
-       align:center;
-       background-color: rgba(255, 255, 255, 0.8);
-       padding:12px;
-       border-radius:10px;
-}
-       
-body {
-       background-color: rgba(205, 205, 205, 1);
-}
-
-div.lwsgs {
-       z-index: 3;
-       text-align:right;
-       background-color: rgba(255, 255, 255, 0.8);
-}
-
-table.lwsgs {
-       width:100%;
-       height:100%;
-       transition: max-height 2s;
-}
-table.c100 {
-       text-align:center;
-       width:100%;
-}
-
-table.r {
-       vertical-align:top;
-       text-align:right;
-}
-
-table.l {
-       vertical-align:top;
-       text-align:left;
-}
-
-table.fixed {
-       table-layout: fixed;
-}
-
-td.logo {
-       vertical-align:top;
-       text-align:left;
-       width:200px
-}
-
-td.rlogo {
-       vertical-align:top;
-       text-align:right
-}
-
-td.lwsgs {
-       vertical-align:top;
-       float:right;
-}
-
-td.h99 {
-       height:99%;
-       vertical-align:middle;
-}
-
-td.c {
-       margin:auto;
-       align:center
-}
-
-td.tac {
-       text-align:center
-}
-
-td.ava {
-       display:inline-block;
-       vertical-align:top;
-       word-wrap:break-word;
-}
-
-iframe.hidden {
-       display:none;
-}
-
-div.hidden {
-       display:none;
-}
-
-div.hiddenr {
-       display:none;
-       text-align:right;
-}
-
-input {
-       margin: 2px;
-       padding: 2px;
-}
-
-input.em {
-       margin: 4px;
-       font-weight:bold;
-}
-
-input.wide {
-       margin: 6px;
-       padding: 6px;
-}
-
-input.hidden {
-       display: none;
-}
-
-form.r {
-       text-align:right;
-}
-
-span.bad {
-       color: red;
-}
-
-span.small {
-       font-size:8pt;
-}
-
-img.av {
-       width: 64px;
-       height: 64px;
-}
-
-.green {
-       color: green;
-}
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.js b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/lwsgs.js
deleted file mode 100644 (file)
index 059ad11..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-<!-- lwsgs rewrites the below $vars $v $v into the correct values on the fly -->
-
-var lwsgs_user = "$lwsgs_user";
-var lwsgs_auth = "$lwsgs_auth";
-var lwsgs_email = "$lwsgs_email";
-
-var lwsgs_html = '\
-       <div id="dlogin" class="hidden"> \
-        <form action="lwsgs-login" method="post"> \
-         <input type="hidden" name="admin" value="needadmin/admin-login.html"> \
-         <input type="hidden" name="good" value="index.html"> \
-         <input type="hidden" name="bad" value="failed-login.html"> \
-         <input type="hidden" name="forgot-good" value="sent-forgot-ok.html"> \
-         <input type="hidden" name="forgot-bad" value="sent-forgot-fail.html">\
-         <input type="hidden" name="forgot-post-good" value="post-forgot-ok.html">\
-         <input type="hidden" name="forgot-post-bad" value="post-forgot-fail.html">\
-        <table class="r">\
-          <tr>\
-           <td>User Name\
-            <input type="text" size="10" id="username" name="username"></td>\
-           <td>Password\
-            <input type="password" id="password" size="10" name="password"><div id="pw1"></div></td>\
-            </tr><tr>\
-          <td colspan="2" class="c">\
-       <input type="submit" id="login" name="login" value="Login" class="em">\
-      &nbsp;<input type="submit" id="forgot" name="forgot" value="Forgot password">\
-           &nbsp;<input id="doreg" type="button" value="Sign up"></td>\
-          </tr>\
-         </table>\
-        </form>\
-       </div>\
-\
-       <div id="dlogout" class="hiddenr">\
-        <form action="lwsgs-logout" method="post" class="r">\
-         <input type="hidden" name="good" value="index.html">\
-         <table class="r">\
-          <tr><td><table><tr><td><span id=grav></span></td></tr><tr><td>\
-       <a href="#" id="clink">\
-       <span id="curuser"></span></a></td></tr></table></td>\
-           <td class="tac"><input type="submit" name="logout" value="Logout"></td>\
-          </tr></table></td></tr>\
-         </table>\
-        </form></div>\
-\
-       <div id="dregister" class="hidden">\
-        <form action="lwsgs-login" method="post">\
-         <input type="hidden" name="admin" value="needadmin/admin-login.html">\
-         <input type="hidden" name="good" value="successful-login.html">\
-         <input type="hidden" name="bad" value="failed-login.html">\
-         <input type="hidden" name="reg-good" value="post-register-ok.html">\
-         <input type="hidden" name="reg-bad" value="post-register-fail.html">\
-         <input type="hidden" name="forgot-good" value="sent-forgot-ok.html">\
-         <input type="hidden" name="forgot-bad" value="sent-forgot-fail.html">\
-         <input type="hidden" name="forgot-post-good" value="post-forgot-ok.html">\
-         <input type="hidden" name="forgot-post-bad" value="post-forgot-fail.html">\
-         <table class="l">\
-            <tr>\
-             <td colspan=2 align=center>\
-               <span id="curuser"></span>\
-              <b>Please enter your details to register</b>:\
-             </td>\
-            </tr>\
-           <tr><td align=right>\
-            User Name:</td>\
-            <td><input type="text" size="10" id="rusername" name="username" &nbsp;<span id=uchk></span></td>\
-           </tr>\
-           <tr>\
-            <td align=right>Password:</td>\
-            <td><input type="password" size="10" id="rpassword" name="password">&nbsp;<span id="rpw1"></span></td>\
-           </tr>\
-           <tr>\
-           </tr>\
-           <tr>\
-            <td align=right><span id="pw2">Password (again):</span></td>\
-            <td><input type="password" size="10" id="password2" name="password2">&nbsp;<span id="match"></span></td>\
-           </tr>\
-           <tr>\
-            <td align=right>Email:</td>\
-            <td><input type="email" size="10" id="email" name="email"\
-                 placeholder="me@example.com" &nbsp;<span id=echk></span></td>\
-           </tr>\
-           <tr>\
-            <td colspan=2 align=center>\
-<input type="submit" id="register" name="register" value="Register" >\
-<input type="submit" id="rforgot" name="forgot" value="Forgot Password" class="hidden">\
-<input type="button" id="cancel" name="cancel" value="Cancel">\
-            </td>\
-           </tr>\
-         </table>\
-        </form>\
-       </div>\
-       \
-       <div id="dchange" class="hidden">\
-        <form action="lwsgs-change" method="post">\
-         <input type="hidden" id="cusername" name="username">\
-         <input type="hidden" name="admin" value="needadmin/admin-login.html">\
-         <input type="hidden" name="good" value="index.html">\
-         <input type="hidden" name="bad" value="failed-login.html">\
-         <input type="hidden" name="reg-good" value="post-register-ok.html">\
-         <input type="hidden" name="reg-bad" value="post-register-fail.html">\
-         <input type="hidden" name="forgot-good" value="sent-forgot-ok.html">\
-         <input type="hidden" name="forgot-bad" value="sent-forgot-fail.html">\
-         <input type="hidden" name="forgot-post-good" value="post-forgot-ok.html">\
-         <input type="hidden" name="forgot-post-bad" value="post-forgot-fail.html">\
-         <table class="l">\
-            <tr>\
-             <td colspan=2 align=center>\
-               <span id="ccuruser"></span>\
-              <b>Please enter your details to change</b>:\
-             </td>\
-            </tr>\
-           <tr><td align=right id="ccurpw_name">\
-            Current Password:</td>\
-            <td><input type="password" size="10" id="ccurpw" name="curpw"\
-                >&nbsp;<span id=cuchk></span></td>\
-           </tr>\
-           <tr>\
-            <td align=right>Password:</td>\
-            <td><input type="password" size="10" id="cpassword" name="password"\
-                 &nbsp;<span id="cpw1"></span></td>\
-           </tr>\
-           <tr>\
-            <td align=right><span id="pw2">Password (again)</span></td>\
-            <td><input type="password" size="10" id="cpassword2" name="password2"\
-                >&nbsp;<span id="cmatch"></span></td>\
-           </tr>\
-       <!-- not supported yet\
-           <tr>\
-            <td align=right id="cemail_name">Email:</td>\
-            <td><input type="email" size="10" id="cemail" name="email"\
-                 placeholder="?" \
-                 &nbsp;<span id=cechk></span></td>\
-           </tr> -->\
-           <tr>\
-            <td colspan=2 align=center>\
-             <input type="submit" id="change" name="change"\
-              value="Change" class="wide">\
-             <input type="submit" id="cforgot" name="forgot"\
-              value="Forgot Password" class="wide hidden">\
-             <input type="button" id="cancel2" name="cancel"\
-              value="Cancel" class="wide">\
-            </td>\
-           </tr>\
-           <tr>\
-            <td colspan=2>\
-             <input type="checkbox" id="showdel" name="showdel"\
-              > Show Delete&nbsp;\
-             <input type="submit" id="delete" name="delete" \
-              value="Delete Account" class="wide hidden">\
-            </td>\
-           </tr>\
-         </table>\
-        </form>\
-       </div>\
-       \
-       <div id="dadmin" class="hidden">\
-         Admin settings TBD\
-       </div>\
-';
-
-/*-- this came from
-  -- https://raw.githubusercontent.com/blueimp/JavaScript-MD5/master/js/md5.min.js
-  -- under MIT license */
-!function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t),e=(n>>16)+(t>>16)+(r>>16);return e<<16|65535&r}function r(n,t){return n<<t|n>>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<<r%32,n[(r+64>>>9<<4)+14]=r;var e,i,a,h,d,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,h=v,d=m,l=o(l,g,v,m,n[e],7,-680876936),m=o(m,l,g,v,n[e+1],12,-389564586),v=o(v,m,l,g,n[e+2],17,606105819),g=o(g,v,m,l,n[e+3],22,-1044525330),l=o(l,g,v,m,n[e+4],7,-176418897),m=o(m,l,g,v,n[e+5],12,1200080426),v=o(v,m,l,g,n[e+6],17,-1473231341),g=o(g,v,m,l,n[e+7],22,-45705983),l=o(l,g,v,m,n[e+8],7,1770035416),m=o(m,l,g,v,n[e+9],12,-1958414417),v=o(v,m,l,g,n[e+10],17,-42063),g=o(g,v,m,l,n[e+11],22,-1990404162),l=o(l,g,v,m,n[e+12],7,1804603682),m=o(m,l,g,v,n[e+13],12,-40341101),v=o(v,m,l,g,n[e+14],17,-1502002290),g=o(g,v,m,l,n[e+15],22,1236535329),l=u(l,g,v,m,n[e+1],5,-165796510),m=u(m,l,g,v,n[e+6],9,-1069501632),v=u(v,m,l,g,n[e+11],14,643717713),g=u(g,v,m,l,n[e],20,-373897302),l=u(l,g,v,m,n[e+5],5,-701558691),m=u(m,l,g,v,n[e+10],9,38016083),v=u(v,m,l,g,n[e+15],14,-660478335),g=u(g,v,m,l,n[e+4],20,-405537848),l=u(l,g,v,m,n[e+9],5,568446438),m=u(m,l,g,v,n[e+14],9,-1019803690),v=u(v,m,l,g,n[e+3],14,-187363961),g=u(g,v,m,l,n[e+8],20,1163531501),l=u(l,g,v,m,n[e+13],5,-1444681467),m=u(m,l,g,v,n[e+2],9,-51403784),v=u(v,m,l,g,n[e+7],14,1735328473),g=u(g,v,m,l,n[e+12],20,-1926607734),l=c(l,g,v,m,n[e+5],4,-378558),m=c(m,l,g,v,n[e+8],11,-2022574463),v=c(v,m,l,g,n[e+11],16,1839030562),g=c(g,v,m,l,n[e+14],23,-35309556),l=c(l,g,v,m,n[e+1],4,-1530992060),m=c(m,l,g,v,n[e+4],11,1272893353),v=c(v,m,l,g,n[e+7],16,-155497632),g=c(g,v,m,l,n[e+10],23,-1094730640),l=c(l,g,v,m,n[e+13],4,681279174),m=c(m,l,g,v,n[e],11,-358537222),v=c(v,m,l,g,n[e+3],16,-722521979),g=c(g,v,m,l,n[e+6],23,76029189),l=c(l,g,v,m,n[e+9],4,-640364487),m=c(m,l,g,v,n[e+12],11,-421815835),v=c(v,m,l,g,n[e+15],16,530742520),g=c(g,v,m,l,n[e+2],23,-995338651),l=f(l,g,v,m,n[e],6,-198630844),m=f(m,l,g,v,n[e+7],10,1126891415),v=f(v,m,l,g,n[e+14],15,-1416354905),g=f(g,v,m,l,n[e+5],21,-57434055),l=f(l,g,v,m,n[e+12],6,1700485571),m=f(m,l,g,v,n[e+3],10,-1894986606),v=f(v,m,l,g,n[e+10],15,-1051523),g=f(g,v,m,l,n[e+1],21,-2054922799),l=f(l,g,v,m,n[e+8],6,1873313359),m=f(m,l,g,v,n[e+15],10,-30611744),v=f(v,m,l,g,n[e+6],15,-1560198380),g=f(g,v,m,l,n[e+13],21,1309151649),l=f(l,g,v,m,n[e+4],6,-145523070),m=f(m,l,g,v,n[e+11],10,-1120210379),v=f(v,m,l,g,n[e+2],15,718787259),g=f(g,v,m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,h),m=t(m,d);return[l,g,v,m]}function a(n){var t,r="";for(t=0;t<32*n.length;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function h(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;for(t=0;t<8*n.length;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function d(n){return a(i(h(n),8*n.length))}function l(n,t){var r,e,o=h(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>16&&(o=i(o,8*n.length)),r=0;16>r;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(h(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="0123456789abcdef",o="";for(r=0;r<n.length;r+=1)t=n.charCodeAt(r),o+=e.charAt(t>>>4&15)+e.charAt(15&t);return o}function v(n){return unescape(encodeURIComponent(n))}function m(n){return d(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this);
-
-if (lwsgs_user.substring(0, 1) == "$") {
-       alert("lwsgs.js: lws generic sessions misconfigured and not providing vars");
-}
-function lwsgs_san(s)
-{
-       if (s.search("<") != -1)
-               return "invalid string";
-       
-       return s;
-}
-
-function lwsgs_update()
-{
-       var en_login = 1, en_forgot = 1;
-       
-       if (document.getElementById('password').value.length &&
-           document.getElementById('password').value.length < 8)
-               en_login = 0;
-       
-       if (!document.getElementById('username').value ||
-           !document.getElementById('password').value)
-               en_login = 0;
-       
-       if (!document.getElementById('username').value ||
-            document.getElementById('password').value)
-               en_forgot = 0;
-       
-       document.getElementById('login').disabled = !en_login;
-       document.getElementById('forgot').disabled = !en_forgot;
-       
-       if (lwsgs_user)
-               document.getElementById("curuser").innerHTML = lwsgs_san(lwsgs_user);
-
-       if (lwsgs_user === "")
-               document.getElementById("dlogin").style.display = "inline";
-       else
-               document.getElementById("dlogout").style.display = "inline";
- }
-
-function lwsgs_open_registration()
-{
-       document.getElementById("dadmin").style.display = "none";
-       document.getElementById("dlogin").style.display = "none";
-       document.getElementById("dlogout").style.display = "none";
-       document.getElementById("dchange").style.display = "none";
-       document.getElementById("dregister").style.display = "inline";
-}
-
-function lwsgs_cancel_registration()
-{
-       document.getElementById("dadmin").style.display = "none";
-       document.getElementById("dregister").style.display = "none";
-       document.getElementById("dchange").style.display = "none";
-
-       if (lwsgs_user === "")
-               document.getElementById("dlogin").style.display = "inline";
-       else
-               document.getElementById("dlogout").style.display = "inline";
-}
-
-function lwsgs_select_change()
-{
-       document.getElementById("dlogin").style.display = "none";
-       document.getElementById("dlogout").style.display = "none";
-       document.getElementById("dregister").style.display = "none";
-       if (lwsgs_auth & 2) {
-               document.getElementById("dadmin").style.display = "inline";
-               document.getElementById("dchange").style.display = "none";
-       } else {
-               document.getElementById("dadmin").style.display = "none";
-               document.getElementById("dchange").style.display = "inline";
-       }
-
-       event.preventDefault()
-}
-
-var lwsgs_user_check = '0';
-var lwsgs_email_check = '0';
-
-function lwsgs_rupdate()
-{
-       var en_register = 1, en_forgot = 0;
-
-       if (document.getElementById('rpassword').value ==
-           document.getElementById('password2').value) {
-               if (document.getElementById('rpassword').value.length)
-                       document.getElementById('match').innerHTML = 
-                               "<b class=\"green\">\u2713</b>";
-               else
-                       document.getElementById('match').innerHTML = "";
-               document.getElementById('pw2').style = "";
-       } else {
-               if (document.getElementById('password2').value ||
-                   document.getElementById('email').value) { // ie, he is filling in "register" path and cares
-                       document.getElementById('match').innerHTML =
-                               "<span class=\"bad\">\u2718 <b>Passwords do not match</b></span>";
-               } else
-                       document.getElementById('match').innerHTML =
-                               "<span class=\"bad\">\u2718 Passwords do not match</span>";
-
-               en_register = 0;
-       }
-
-       if (document.getElementById('rpassword').value.length &&
-           document.getElementById('rpassword').value.length < 8) {
-               en_register = 0;
-               document.getElementById('rpw1').innerHTML = "Need 8 chars";
-       } else
-               if (document.getElementById('rpassword').value.length)
-                       document.getElementById('rpw1').innerHTML = "<b class=\"green\">\u2713</b>";
-               else
-                       document.getElementById('rpw1').innerHTML = "";
-
-       if (!document.getElementById('rpassword').value ||
-           !document.getElementById('password2').value ||
-           !document.getElementById('rusername').value ||
-           !document.getElementById('email').value ||
-           lwsgs_email_check === '1'||
-           lwsgs_user_check === '1')
-               en_register = 0;
-
-       document.getElementById('register').disabled = !en_register;
-       document.getElementById('rpassword').disabled = lwsgs_user_check === '1';
-       document.getElementById('password2').disabled = lwsgs_user_check === '1';
-       document.getElementById('email').disabled = lwsgs_user_check === '1';
-
-       if (lwsgs_user_check === '0') {
-               var uc = document.getElementById('uchk');
-
-               if (uc) {
-                       if (document.getElementById('rusername').value)
-                               uc.innerHTML = "<b class=\"green\">\u2713</b>";
-                       else
-                               uc.innerHTML = "";
-               }
-       } else {
-               if (document.getElementById('uchk'))
-                       ocument.getElementById('uchk').innerHTML = "<b class=\"red\">\u2718 Already registered</b>";
-               en_forgot = 1;
-       }
-
-       if (lwsgs_email_check === '0') {
-               var ec = document.getElementById('echk');
-
-               if (ec) {
-                       if (document.getElementById('email').value)
-                               ec.innerHTML = "<b class=\"green\">\u2713</b>";
-                       else
-                               ec.innerHTML = "";
-               }
-       } else {
-               if (document.getElementById('echk'))
-                       document.getElementById('echk').innerHTML = "<b class=\"red\">\u2718 Already registered</b>";
-               en_forgot = 1;
-       }
-
-       if (en_forgot)
-               document.getElementById('rforgot').style.display = "inline";
-       else
-               document.getElementById('rforgot').style.display = "none";
-
-       if (lwsgs_user_check === '1')
-               op = '0.5';
-       else
-               op = '1.0';
-       document.getElementById('rpassword').style.opacity = op;
-       document.getElementById('password2').style.opacity = op;
-       document.getElementById('email').style.opacity = op;
- }
-
-function lwsgs_cupdate()
-{
-       var en_change = 1, en_forgot = 1, pwok = 1;
-       
-       if (lwsgs_auth & 8) {
-               document.getElementById('ccurpw').style.display = "none";
-               document.getElementById('ccurpw_name').style.display = "none";
-       } else {
-               if (!document.getElementById('ccurpw').value ||
-                   document.getElementById('ccurpw').value.length < 8) {
-                       en_change = 0;
-                       pwok = 0;
-                       document.getElementById('cuchk').innerHTML = "<b class=\"red\">\u2718</b>";
-               } else {
-                       en_forgot = 0;
-                       document.getElementById('cuchk').innerHTML = "";
-               }
-               document.getElementById('ccurpw').style.display = "inline";
-               document.getElementById('ccurpw_name').style.display = "inline";
-       }
-
-       if (document.getElementById('cpassword').value ==
-           document.getElementById('cpassword2').value) {
-               if (document.getElementById('cpassword').value.length)
-                       document.getElementById('cmatch').innerHTML = "<b class=\"green\">\u2713</b>";
-               else
-                       document.getElementById('cmatch').innerHTML = "";
-               document.getElementById('pw2').style = "";
-       } else {
-               if (document.getElementById('cpassword2').value //||
-                   //document.getElementById('cemail').value
-               ) { // ie, he is filling in "register" path and cares
-                       document.getElementById('cmatch').innerHTML =
-                               "<span class=\"red\">\u2718 <b>Passwords do not match</b></span>";
-               } else
-                       document.getElementById('cmatch').innerHTML = "<span class=\"red\">\u2718 Passwords do not match</span>";
-
-               en_change = 0;
-       }
-
-       if (document.getElementById('cpassword').value.length &&
-           document.getElementById('cpassword').value.length < 8) {
-               en_change = 0;
-               document.getElementById('cpw1').innerHTML = "Need 8 chars";
-       } else {
-               var cpw = document.getElementById('cpw1');
-
-               if (cpw) {
-                       if (document.getElementById('cpassword').value.length)
-                               cpw.innerHTML = "<b class=\"green\">\u2713</b>";
-                       else
-                               cpw.innerHTML = "";
-               }
-       }
-
-       if (!document.getElementById('cpassword').value ||
-           !document.getElementById('cpassword2').value ||
-           pwok === 0)
-               en_change = 0;
-       
-       if (document.getElementById('showdel').checked)
-               document.getElementById('delete').style.display = "inline";
-       else
-               document.getElementById('delete').style.display = "none";
-
-       document.getElementById('change').disabled = !en_change;
-       document.getElementById('cpassword').disabled = pwok === 0;
-       document.getElementById('cpassword2').disabled = pwok === 0;
-       document.getElementById('showdel').disabled = pwok === 0;
-       document.getElementById('delete').disabled = pwok === 0;
-       //document.getElementById('cemail').disabled = pwok === 0;
-
-       /*
-       if (lwsgs_auth & 8) {
-               document.getElementById('cemail').style.display = "none";
-               document.getElementById('cemail_name').style.display = "none";
-       } else {
-               document.getElementById('cemail').style.display = "inline";
-               document.getElementById('cemail_name').style.display = "inline";
-               if (lwsgs_email_check === '0'  &&
-                   document.getElementById('cemail').value != lwsgs_email) {
-                       if (document.getElementById('cemail').value)
-                               document.getElementById('cechk').innerHTML = "<b style=\"color:green\">\u2713</b>";
-                       else
-                               document.getElementById('cechk').innerHTML = "";
-               } else {
-                       document.getElementById('cechk').innerHTML = "<b style=\"color:red\">\u2718 Already registered</b>";
-                       en_forgot = 1;
-               }
-       } */
-       
-       if (lwsgs_auth & 8)
-               en_forgot = 0;
-
-       if (en_forgot)
-               document.getElementById('cforgot').style.display = "inline";
-       else
-               document.getElementById('cforgot').style.display = "none";
-
-       if (pwok === 0)
-               op = '0.5';
-       else
-               op = '1.0';
-       document.getElementById('cpassword').style.opacity = op;
-       document.getElementById('cpassword2').style.opacity = op;
-       // document.getElementById('cemail').style.opacity = op;
- }
-
-function lwsgs_check_user()
-{
-    var xmlHttp = new XMLHttpRequest();
-    xmlHttp.onreadystatechange = function() { 
-        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
-            lwsgs_user_check = xmlHttp.responseText;
-           lwsgs_rupdate();
-        }
-    }
-    xmlHttp.open("GET", "lwsgs-check/username="+document.getElementById('rusername').value, true);
-    xmlHttp.send(null);
-}
-
-function lwsgs_check_email(id)
-{
-    var xmlHttp = new XMLHttpRequest();
-    xmlHttp.onreadystatechange = function() { 
-        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
-            lwsgs_email_check = xmlHttp.responseText;
-           lwsgs_rupdate();
-        }
-    }
-    xmlHttp.open("GET", "lwsgs-check/email="+document.getElementById(id).value, true);
-    xmlHttp.send(null);
-}
-
-function rupdate_user()
-{
-       lwsgs_rupdate();
-       lwsgs_check_user();
-}
-
-function rupdate_email()
-{
-       lwsgs_rupdate();
-       lwsgs_check_email('email');
-}
-
-function cupdate_email()
-{
-       lwsgs_cupdate();
-       lwsgs_check_email('cemail');
-}
-
-
-function lwsgs_initial()
-{
-       document.getElementById('lwsgs').innerHTML = lwsgs_html;
-
-       if (lwsgs_user) {
-               document.getElementById("curuser").innerHTML =
-                       "currently logged in as " + lwsgs_san(lwsgs_user) + "</br>";
-
-               document.getElementById("ccuruser").innerHTML =
-                 "<span class=\"gstitle\">Login settings for " +
-                 lwsgs_san(lwsgs_user) + "</span></br>";
-       }
-
-       document.getElementById('username').oninput = lwsgs_update;
-       document.getElementById('username').onchange = lwsgs_update;
-       document.getElementById('password').oninput = lwsgs_update;
-       document.getElementById('password').onchange = lwsgs_update;
-       document.getElementById('doreg').onclick = lwsgs_open_registration;
-       document.getElementById('clink').onclick = lwsgs_select_change;
-       document.getElementById('cancel').onclick =lwsgs_cancel_registration;
-       document.getElementById('cancel2').onclick =lwsgs_cancel_registration;
-       document.getElementById('rpassword').oninput = lwsgs_rupdate;
-       document.getElementById('password2').oninput = lwsgs_rupdate;
-       document.getElementById('rusername').oninput = rupdate_user;
-       document.getElementById('email').oninput  = rupdate_email;
-       document.getElementById('ccurpw').oninput = lwsgs_cupdate;
-       document.getElementById('cpassword').oninput = lwsgs_cupdate;
-       document.getElementById('cpassword2').oninput = lwsgs_cupdate;
-<!--   document.getElementById('cemail').oninput = cupdate_email;-->
-       document.getElementById('showdel').onchange = lwsgs_cupdate;
-
-       if (lwsgs_email)
-               document.getElementById('grav').innerHTML =
-                       "<img class='av' " +
-                       "src=\"https://www.gravatar.com/avatar/" +
-                       md5(lwsgs_email) +
-                       "?d=identicon\">";
-       //if (lwsgs_email)
-               //document.getElementById('cemail').placeholder = lwsgs_email;
-       document.getElementById('cusername').value = lwsgs_user;
-       lwsgs_update();
-       lwsgs_cupdate();
-}
-
-window.addEventListener("load", function() {
-       lwsgs_initial();
-       document.getElementById("nolog").style.display = !!lwsgs_user ? "none" : "inline-block";
-       document.getElementById("logged").style.display = !lwsgs_user ? "none" : "inline-block";
-
-       document.getElementById("msg").onkeyup = mupd;
-       document.getElementById("msg").onchange = mupd;
-
-       var ws;
-
-       function mb_format(s)
-       {
-               var r = "", n, wos = 0;
-               
-               for (n = 0; n < s.length; n++) {
-                       if (s[n] == ' ')
-                               wos = 0;
-                       else {
-                               wos++;
-                               if (wos === 40) {
-                                       wos = 0;
-                                       r = r + ' ';
-                               }
-                       }
-                       if (s[n] == '<') {
-                               r = r + "&lt;";
-                               continue;
-                       }
-                       if (s[n] == '\n') {
-                               r = r + "<br>";
-                               continue;
-                       }
-                               
-                       r = r + s[n];
-               }
-               
-               return r;
-       }
-
-       function add_div(n, m)
-       {
-               var q = document.getElementById(n);
-               var d = new Date(m.time * 1000), s = d.toTimeString(), t;
-               
-               t = s.indexOf('(');
-               if (t)
-                       s = s.substring(0, t);
-               
-               q.innerHTML = "<br><div class=\"group2\"><table class=\"fixed\"><tr><td>" +
-                       "<img class=\"av\" src=\"https://www.gravatar.com/avatar/" + md5(m.email) +
-                       "?d=identicon\"><br>" +
-                       "<b>" + lwsgs_san(m.username) + "</b><br>" +
-                       "<span class=\"small\">" + d.toDateString() +
-                         "<br>" + s + "</span><br>" +
-                       "IP: " + lwsgs_san(m.ip) +
-                       "</td><td class=\"ava\"><span>" +
-                       mb_format(m.content) +
-                       "</span></td></tr></table></div><br>" + q.innerHTML;
-       }
-
-       function get_appropriate_ws_url()
-       {
-               var pcol;
-               var u = document.URL;
-
-               if (u.substring(0, 5) == "https") {
-                       pcol = "wss://";
-                       u = u.substr(8);
-               } else {
-                       pcol = "ws://";
-                       if (u.substring(0, 4) == "http")
-                               u = u.substr(7);
-               }
-               u = u.split('/');
-
-               return pcol + u[0] + "/xxx";
-       }
-
-       if (lwsgs_user) {
-               if (typeof MozWebSocket != "undefined")
-                       ws = new MozWebSocket(get_appropriate_ws_url(),
-                                          "protocol-lws-messageboard");
-               else
-                       ws = new WebSocket(get_appropriate_ws_url(),
-                                          "protocol-lws-messageboard");
-
-               try {
-                       ws.onopen = function() {
-                               document.getElementById("debug").textContent = "ws opened";
-                       }
-                       ws.onmessage =function got_packet(msg) {
-                               add_div("messages", JSON.parse(msg.data));
-                       }
-                       ws.onclose = function(){
-                       }
-               } catch(exception) {
-                       alert('<p>Error' + exception);  
-               }
-       }
-
-       function mupd()
-       {
-               document.getElementById("send").disabled = !document.getElementById("msg").value;
-       }
-}, false);
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/md5.min.js b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/md5.min.js
deleted file mode 100644 (file)
index 4bd9de1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-!function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t),e=(n>>16)+(t>>16)+(r>>16);return e<<16|65535&r}function r(n,t){return n<<t|n>>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<<r%32,n[(r+64>>>9<<4)+14]=r;var e,i,a,h,d,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,h=v,d=m,l=o(l,g,v,m,n[e],7,-680876936),m=o(m,l,g,v,n[e+1],12,-389564586),v=o(v,m,l,g,n[e+2],17,606105819),g=o(g,v,m,l,n[e+3],22,-1044525330),l=o(l,g,v,m,n[e+4],7,-176418897),m=o(m,l,g,v,n[e+5],12,1200080426),v=o(v,m,l,g,n[e+6],17,-1473231341),g=o(g,v,m,l,n[e+7],22,-45705983),l=o(l,g,v,m,n[e+8],7,1770035416),m=o(m,l,g,v,n[e+9],12,-1958414417),v=o(v,m,l,g,n[e+10],17,-42063),g=o(g,v,m,l,n[e+11],22,-1990404162),l=o(l,g,v,m,n[e+12],7,1804603682),m=o(m,l,g,v,n[e+13],12,-40341101),v=o(v,m,l,g,n[e+14],17,-1502002290),g=o(g,v,m,l,n[e+15],22,1236535329),l=u(l,g,v,m,n[e+1],5,-165796510),m=u(m,l,g,v,n[e+6],9,-1069501632),v=u(v,m,l,g,n[e+11],14,643717713),g=u(g,v,m,l,n[e],20,-373897302),l=u(l,g,v,m,n[e+5],5,-701558691),m=u(m,l,g,v,n[e+10],9,38016083),v=u(v,m,l,g,n[e+15],14,-660478335),g=u(g,v,m,l,n[e+4],20,-405537848),l=u(l,g,v,m,n[e+9],5,568446438),m=u(m,l,g,v,n[e+14],9,-1019803690),v=u(v,m,l,g,n[e+3],14,-187363961),g=u(g,v,m,l,n[e+8],20,1163531501),l=u(l,g,v,m,n[e+13],5,-1444681467),m=u(m,l,g,v,n[e+2],9,-51403784),v=u(v,m,l,g,n[e+7],14,1735328473),g=u(g,v,m,l,n[e+12],20,-1926607734),l=c(l,g,v,m,n[e+5],4,-378558),m=c(m,l,g,v,n[e+8],11,-2022574463),v=c(v,m,l,g,n[e+11],16,1839030562),g=c(g,v,m,l,n[e+14],23,-35309556),l=c(l,g,v,m,n[e+1],4,-1530992060),m=c(m,l,g,v,n[e+4],11,1272893353),v=c(v,m,l,g,n[e+7],16,-155497632),g=c(g,v,m,l,n[e+10],23,-1094730640),l=c(l,g,v,m,n[e+13],4,681279174),m=c(m,l,g,v,n[e],11,-358537222),v=c(v,m,l,g,n[e+3],16,-722521979),g=c(g,v,m,l,n[e+6],23,76029189),l=c(l,g,v,m,n[e+9],4,-640364487),m=c(m,l,g,v,n[e+12],11,-421815835),v=c(v,m,l,g,n[e+15],16,530742520),g=c(g,v,m,l,n[e+2],23,-995338651),l=f(l,g,v,m,n[e],6,-198630844),m=f(m,l,g,v,n[e+7],10,1126891415),v=f(v,m,l,g,n[e+14],15,-1416354905),g=f(g,v,m,l,n[e+5],21,-57434055),l=f(l,g,v,m,n[e+12],6,1700485571),m=f(m,l,g,v,n[e+3],10,-1894986606),v=f(v,m,l,g,n[e+10],15,-1051523),g=f(g,v,m,l,n[e+1],21,-2054922799),l=f(l,g,v,m,n[e+8],6,1873313359),m=f(m,l,g,v,n[e+15],10,-30611744),v=f(v,m,l,g,n[e+6],15,-1560198380),g=f(g,v,m,l,n[e+13],21,1309151649),l=f(l,g,v,m,n[e+4],6,-145523070),m=f(m,l,g,v,n[e+11],10,-1120210379),v=f(v,m,l,g,n[e+2],15,718787259),g=f(g,v,m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,h),m=t(m,d);return[l,g,v,m]}function a(n){var t,r="";for(t=0;t<32*n.length;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function h(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;for(t=0;t<8*n.length;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function d(n){return a(i(h(n),8*n.length))}function l(n,t){var r,e,o=h(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>16&&(o=i(o,8*n.length)),r=0;16>r;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(h(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="0123456789abcdef",o="";for(r=0;r<n.length;r+=1)t=n.charCodeAt(r),o+=e.charAt(t>>>4&15)+e.charAt(15&t);return o}function v(n){return unescape(encodeURIComponent(n))}function m(n){return d(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this);
-//# sourceMappingURL=md5.min.js.map
\ No newline at end of file
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needadmin/admin-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needadmin/admin-login.html
deleted file mode 100644 (file)
index 113df9c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-This is an example destination that will appear after successful Admin login.
-
-This URL cannot be served if you're not logged in as admin.
-</html>
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needauth/successful-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/needauth/successful-login.html
deleted file mode 100644 (file)
index dfc25cf..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<html>
-This is an example destination that will appear after successful non-Admin login
-</html>
-
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-fail.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-fail.html
deleted file mode 100644 (file)
index ead3d13..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-Sorry, something went wrong.
-
-Click <a href="../">here</a> to continue.
-</html>
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-ok.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-forgot-ok.html
deleted file mode 100644 (file)
index 3e8e9cf..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-This is a one-time password recovery login.
-
-Please click <a href="./">here</a> and click your username at the top to reset your password.
-</html>
-
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-fail.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-fail.html
deleted file mode 100644 (file)
index 063c3c5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Registration failed, sorry
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-ok.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-register-ok.html
deleted file mode 100644 (file)
index c00c3f3..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<html>
- <head>
-  <script src="lwsgs.js" nonce=lwscaro></script>
- </head>
- <body>
-  <table>
-    <tr>
-     <td colspan=2 align=center>
-      <img src="lwsgs-logo.png">
-     </td>
-    </tr>
-    <tr>
-     <td>
-      Your registration as <span id="u"></span> is accepted,<br>
-      you will receive an email shortly with instructions<br>
-      to verify and enable the account for normal use.<br><br>
-      The link is only valid for an hour, after that if it has<br>
-      not been verified your account will be deleted.
-     </td>
-    </tr>
-   </table>
-  </body>
- <script nonce=lwscaro>
-       document.getElementById('u').innerHTML = "<b>" + lwsgs_san(lwsgs_user) + "</b>";
- </script>
-</html>
-
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-fail.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-fail.html
deleted file mode 100644 (file)
index d1d89ca..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<html>
- <head>
-  <script src="lwsgs.js"></script>
- </head>
- <body>
-  <table>
-    <tr>
-     <td colspan=2 align=center>
-      <img src="lwsws-logo.png">
-     </td>
-    </tr>
-    <tr>
-     <td>
-       Sorry, the link was invalid.
-     </td>
-    </tr>
-   </table>
-  </body>
-</html>
-
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-ok.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/post-verify-ok.html
deleted file mode 100644 (file)
index ae647fc..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<html>
- <head>
-  <script src="lwsgs.js"></script>
- </head>
- <body>
-  <table>
-    <tr>
-     <td colspan=2 align=center>
-      <img src="lwsgs-logo.png">
-     </td>
-    </tr>
-    <tr>
-     <td>
-        Thanks for signing up, your registration as <span id="u"></span> is verified.<br>
-       <br>
-       Click <a href="/lwsgs">here</a> to continue.
-     </td>
-    </tr>
-   </table>
-  </body>
- <script nonce="lwscaro">
-       document.getElementById('u').innerHTML = "<b>" + san(lwsgs_user) + "</b>";
- </script>
-</html>
-
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/seats.jpg b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/seats.jpg
deleted file mode 100644 (file)
index 5bed40d..0000000
Binary files a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/seats.jpg and /dev/null differ
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-fail.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-fail.html
deleted file mode 100644 (file)
index ead3d13..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-Sorry, something went wrong.
-
-Click <a href="../">here</a> to continue.
-</html>
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-ok.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/sent-forgot-ok.html
deleted file mode 100644 (file)
index 83df751..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-An email has been sent to your registered address.
-
-Please follow the instructions to reset your password.
-
diff --git a/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/successful-login.html b/minimal-examples/http-server/minimal-http-server-generic-sessions/mount-origin/successful-login.html
deleted file mode 100644 (file)
index dfc25cf..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<html>
-This is an example destination that will appear after successful non-Admin login
-</html>
-
diff --git a/minimal-examples/http-server/minimal-http-server-h2-long-poll/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-h2-long-poll/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2cabcc3
--- /dev/null
@@ -0,0 +1,25 @@
+project(lws-minimal-http-server-h2-long-poll C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-http-server-h2-long-poll)
+set(SRCS minimal-http-server.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_HTTP2 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/http-server/minimal-http-server-h2-long-poll/README.md b/minimal-examples/http-server/minimal-http-server-h2-long-poll/README.md
new file mode 100644 (file)
index 0000000..c327e8f
--- /dev/null
@@ -0,0 +1,25 @@
+# lws minimal http server
+
+## build
+
+```
+ $ cmake . && make
+```
+## Commandline Options
+
+Option|Meaning
+---|---
+-d|Set logging verbosity
+-s|Serve using TLS selfsigned cert (ie, connect to it with https://...)
+-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
+
+## usage
+
+```
+ $ ./lws-minimal-http-server
+[2018/03/04 09:30:02:7986] USER: LWS minimal http server | visit http://localhost:7681
+[2018/03/04 09:30:02:7986] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 on
+```
+
+Visit http://localhost:7681
+
diff --git a/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c b/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c
new file mode 100644 (file)
index 0000000..c5614e5
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * lws-minimal-http-server-h2-long-poll
+ *
+ * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates an h2 server that supports "long poll"
+ * immortal client connections.  For simplicity it doesn't serve
+ * any regular files, you can add a mount to do it if you want.
+ *
+ * The protocol keeps the long poll h2 stream open, and sends
+ * the time on the stream once per minute.  Normally idle h2
+ * connections are closed by default within 30s, so this demonstrates
+ * the stream and network connection are operating as "immortal"
+ * on both sides.
+ *
+ * See http-client/minimal-http-client-h2-long-poll for the
+ * client example that connects and transitions the stream to the
+ * immortal long poll mode.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted;
+
+struct pss {
+       struct lws *wsi;
+       lws_sorted_usec_list_t sul;
+       char pending;
+};
+
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping = 5,
+       .secs_since_valid_hangup = 10,
+};
+
+static void
+sul_cb(lws_sorted_usec_list_t *sul)
+{
+       struct pss *pss = (struct pss *)lws_container_of(sul, struct pss, sul);
+
+       pss->pending = 1;
+       lws_callback_on_writable(pss->wsi);
+       /* interval 1min... longer than any normal timeout */
+       lws_sul_schedule(lws_get_context(pss->wsi), 0, &pss->sul, sul_cb,
+                               60 * LWS_US_PER_SEC);
+}
+
+static int
+callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+             void *in, size_t len)
+{
+       struct pss * pss = (struct pss *)user;
+       uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE],
+               *start = &buf[LWS_PRE], *p = start,
+               *end = p + sizeof(buf) - LWS_PRE;
+       int m, n;
+
+       switch (reason) {
+       case LWS_CALLBACK_HTTP:
+               lwsl_user("%s: connect\n", __func__);
+               pss->wsi = wsi;
+
+               if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
+                               "text/html",
+                               LWS_ILLEGAL_HTTP_CONTENT_LEN, /* no content len */
+                               &p, end))
+                       return 1;
+               if (lws_finalize_write_http_header(wsi, start, &p, end))
+                       return 1;
+
+               sul_cb(&pss->sul);
+               return 0;
+
+       case LWS_CALLBACK_CLOSED_HTTP:
+               if (!pss)
+                       break;
+               lws_sul_cancel(&pss->sul);
+               break;
+
+       case LWS_CALLBACK_HTTP_WRITEABLE:
+               if (!pss->pending)
+                       break;
+               n = lws_snprintf((char *)p, sizeof(buf) - LWS_PRE, "%llu",
+                                (unsigned long long)lws_now_usecs());
+               m = lws_write(wsi, p, (unsigned int)n, LWS_WRITE_HTTP);
+               if (m < n) {
+                       lwsl_err("ERROR %d writing to socket\n", n);
+                       return -1;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static struct lws_protocols protocols[] = {
+       { "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS minimal http server h2 long poll\n");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.port = 7681;
+#if defined(LWS_WITH_TLS)
+       info.ssl_cert_filepath = "localhost-100y.cert";
+       info.ssl_private_key_filepath = "localhost-100y.key";
+#endif
+       info.protocols = protocols;
+       info.options =
+               LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+               LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL |
+               LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
+
+       /* the default validity check is 5m / 5m10s... -v = 5s / 10s */
+
+       if (lws_cmdline_option(argc, argv, "-v"))
+               info.retry_and_idle_policy = &retry;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       return 0;
+}
index d270d7b..c0e9328 100644 (file)
@@ -1,79 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-mimetypes C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-mimetypes)
 set(SRCS minimal-http-server-mimetypes.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index ace0d7c..c4c5c45 100644 (file)
@@ -1,77 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-multivhost C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-multivhost)
 set(SRCS minimal-http-server.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
\ No newline at end of file
index b3677a2..0e90016 100644 (file)
@@ -89,6 +89,7 @@ int main(int argc, const char **argv)
 {
        struct lws_context_creation_info info;
        struct lws_context *context;
+       struct lws_vhost *new_vhost;
        const char *p;
        int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
                        /* for LLL_ verbosity above NOTICE to be built into lws,
@@ -147,9 +148,12 @@ int main(int argc, const char **argv)
        info.error_document_404 = "/404.html";
        info.vhost_name = "localhost2";
 
-       if (!lws_create_vhost(context, &info)) {
-               lwsl_err("Failed to create second vhost\n");
-               goto bail;
+       if (!lws_cmdline_option(argc, argv, "--kill-7682")) {
+
+               if (!lws_create_vhost(context, &info)) {
+                       lwsl_err("Failed to create second vhost\n");
+                       goto bail;
+               }
        }
 
        /* a second vhost listens on port 7682 */
@@ -159,11 +163,15 @@ int main(int argc, const char **argv)
        info.finalize = vh_destruction_notification;
        info.finalize_arg = NULL;
 
-       if (!lws_create_vhost(context, &info)) {
+       new_vhost = lws_create_vhost(context, &info);
+       if (!new_vhost) {
                lwsl_err("Failed to create third vhost\n");
                goto bail;
        }
 
+       if (lws_cmdline_option(argc, argv, "--kill-7682"))
+               lws_vhost_destroy(new_vhost);
+
        if (lws_cmdline_option(argc, argv, "--die-after-vhost")) {
                lwsl_warn("bailing after creating vhosts\n");
                goto bail;
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 4c582a0..59c53a3 100644 (file)
@@ -1,80 +1,26 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-proxy C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-proxy)
 set(SRCS minimal-http-server-proxy.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 require_lws_config(LWS_WITH_HTTP_PROXY 1 requirements)
-require_lws_config(LWS_OPENSSL_SUPPORT 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index ab2718e..3f6a91d 100644 (file)
@@ -1,91 +1,26 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-smp C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckIncludeFile)
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-smp)
 set(SRCS minimal-http-server-smp.c)
 
-MACRO(require_pthreads result)
-       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
-       if (NOT LWS_HAVE_PTHREAD_H)
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(result 0)
-               else()
-                       message(FATAL_ERROR "threading support requires pthreads")
-               endif()
-       endif()
-ENDMACRO()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_pthreads(requirements)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared pthread)
-               add_dependencies(${SAMP} websockets_shared pthread)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets pthread)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
\ No newline at end of file
index 6bc0096..33471a7 100644 (file)
@@ -4,7 +4,7 @@ Lws supports multithreaded service... build lws with `-DLWS_MAP_SMP=<max number
 default is 1.  If nonzero, some extra pthreads locking is built into lws and it supports multiple
 independent service threads.
 
-![lws-smp-overview](../../doc-assets/lws-smp-ov.png)
+![lws-smp-overview](/doc-assets/lws-smp-ov.png)
 
 When an incoming connection is accepted, it is bound to the pt with the lowest current wsi
 count, to keep the load on the threads balanced.  Only the pt the wsi is bound to can service
@@ -13,7 +13,7 @@ service threads, a wsi can only be service by the pt it is bound to.
 
 The effectiveness of the scalability depends on the load.  Here is an example of roughly what can be expected
 
-![lws-smp-example](../../doc-assets/lws-smp-example.png)
+![lws-smp-example](/doc-assets/lws-smp-example.png)
 
 ## build
 
index ae07e4a..b542c64 100644 (file)
 #include <libwebsockets.h>
 #include <string.h>
 #include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 
 #define COUNT_THREADS 8
@@ -94,17 +100,19 @@ int main(int argc, const char **argv)
        info.options =
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
        if ((p = lws_cmdline_option(argc, argv, "-t"))) {
-               info.count_threads = atoi(p);
+               info.count_threads = (unsigned int)atoi(p);
                if (info.count_threads < 1 || info.count_threads > LWS_MAX_SMP)
                        return 1;
        } else
                info.count_threads = COUNT_THREADS;
 
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
-               info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
+               info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
        }
+#endif
 
        context = lws_create_context(&info);
        if (!context) {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 464cfbe..e5e2e7b 100644 (file)
@@ -1,91 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-sse-ring C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
 include(CheckIncludeFile)
 include(CheckCSourceCompiles)
 
 set(SAMP lws-minimal-http-server-sse-ring)
 set(SRCS minimal-http-server-sse-ring.c)
 
-MACRO(require_pthreads result)
-       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
-       if (NOT LWS_HAVE_PTHREAD_H)
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(result 0)
-               else()
-                       message(FATAL_ERROR "threading support requires pthreads")
-               endif()
-       endif()
-ENDMACRO()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_pthreads(requirements)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared pthread)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets pthread)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 2e51c2f..faef2f6 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 #include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 #include <time.h>
 
@@ -86,7 +92,11 @@ thread_spam(void *d)
 {
        struct vhd *vhd = (struct vhd *)d;
        struct msg amsg;
-       int len = 128, index = 1, n;
+       int len = 128, index = 1, n, whoami = 0;
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
+               if (pthread_equal(pthread_self(), vhd->pthread_spam[n]))
+                       whoami = n + 1;
 
        do {
                /* don't generate output if nobody connected */
@@ -102,16 +112,15 @@ thread_spam(void *d)
                        goto wait_unlock;
                }
 
-               amsg.payload = malloc(len);
+               amsg.payload = malloc((unsigned int)len);
                if (!amsg.payload) {
                        lwsl_user("OOM: dropping\n");
                        goto wait_unlock;
                }
-               n = lws_snprintf((char *)amsg.payload, len,
-                                "%s: tid: %p, msg: %d", __func__,
-                                (void *)pthread_self(), index++);
-               amsg.len = n;
-               n = lws_ring_insert(vhd->ring, &amsg, 1);
+               n = lws_snprintf((char *)amsg.payload, (unsigned int)len,
+                                "%s: tid: %d, msg: %d", __func__, whoami, index++);
+               amsg.len = (unsigned int)n;
+               n = (int)lws_ring_insert(vhd->ring, &amsg, 1);
                if (n != 1) {
                        __minimal_destroy_message(&amsg);
                        lwsl_user("dropping!\n");
@@ -127,11 +136,11 @@ wait_unlock:
 
 wait:
                /* rand() would make more sense but coverity shrieks */
-               usleep(100000 + (time(NULL) & 0xffff));
+               usleep((useconds_t)(100000 + (time(NULL) & 0xffff)));
 
        } while (!vhd->finished);
 
-       lwsl_notice("thread_spam %p exiting\n", (void *)pthread_self());
+       lwsl_notice("thread_spam %d exiting\n", whoami);
 
        pthread_exit(NULL);
 
@@ -186,8 +195,7 @@ callback_sse(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                init_fail:
                vhd->finished = 1;
                for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
-                       if (vhd->pthread_spam[n])
-                               pthread_join(vhd->pthread_spam[n], &retval);
+                       pthread_join(vhd->pthread_spam[n], &retval);
 
                if (vhd->ring)
                        lws_ring_destroy(vhd->ring);
@@ -254,11 +262,11 @@ callback_sse(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                if (!pmsg)
                        break;
 
-               p += lws_snprintf((char *)p, end - p,
+               p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                  "data: %s\x0d\x0a\x0d\x0a",
                                  (const char *)pmsg->payload);
 
-               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff(p, start),
+               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff_size_t(p, start),
                              LWS_WRITE_HTTP) != lws_ptr_diff(p, start))
                        return 1;
 
@@ -298,9 +306,9 @@ callback_sse(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 }
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
-       { "sse", callback_sse, sizeof(struct pss), 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
+       { "sse", callback_sse, sizeof(struct pss), 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 /* override the default mount for /sse in the URL space */
index b32bf0b..ed9bba1 100644 (file)
@@ -1,6 +1,6 @@
 document.addEventListener("DOMContentLoaded", function() {
 
-       var head = 0, tail = 0, ring = new Array();
+       var head = 0, tail = 0, ring = new Array(), es;
 
        es = new EventSource("/sse/sourcename");
        try {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index c22a71f..116052d 100644 (file)
@@ -1,78 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-sse C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-sse)
 set(SRCS minimal-http-server-sse.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
+require_pthreads(requirements)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index cb60774..a87a7c2 100644 (file)
 #include <string.h>
 #include <signal.h>
 #include <time.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 
 /*
@@ -92,12 +98,12 @@ callback_sse(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                 * own private data and timer.
                 */
 
-               p += lws_snprintf((char *)p, end - p,
+               p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                  "data: %llu\x0d\x0a\x0d\x0a",
-                                 (unsigned long long)time(NULL) -
-                                 pss->established);
+                                 (unsigned long long)(time(NULL) -
+                                 pss->established));
 
-               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff(p, start),
+               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff_size_t(p, start),
                              LWS_WRITE_HTTP) != lws_ptr_diff(p, start))
                        return 1;
 
@@ -120,9 +126,9 @@ callback_sse(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 }
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
-       { "sse", callback_sse, sizeof(struct pss), 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
+       { "sse", callback_sse, sizeof(struct pss), 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 /* override the default mount for /sse in the URL space */
@@ -202,12 +208,15 @@ int main(int argc, const char **argv)
        info.options =
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
        info.port = 7681;
+
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
                info.port = 443;
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
        }
+#endif
 
        context = lws_create_context(&info);
        if (!context) {
index af73512..cfb89ea 100644 (file)
@@ -1,6 +1,6 @@
 document.addEventListener("DOMContentLoaded", function() {
 
-var head = 0, tail = 0, ring = new Array();
+var head = 0, tail = 0, ring = new Array(), es;
 
        es = new EventSource("/sse/sourcename");
        try {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 01305f8..46ac74c 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-tls-80 C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-tls-80)
 set(SRCS minimal-http-server-tls-80.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
-require_lws_config(LWS_OPENSSL_SUPPORT 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index e6ea90a..1f8f63f 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-tls-mem C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-tls-mem)
 set(SRCS minimal-http-server-tls-mem.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
-require_lws_config(LWS_OPENSSL_SUPPORT 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index b3953fb..56304bf 100644 (file)
@@ -429,9 +429,9 @@ int main(int argc, const char **argv)
        info.mounts = &mount;
        info.error_document_404 = "/404.html";
        info.server_ssl_cert_mem                = cert_pem;
-       info.server_ssl_cert_mem_len            = strlen(cert_pem);
+       info.server_ssl_cert_mem_len            = (unsigned int)strlen(cert_pem);
        info.server_ssl_private_key_mem         = key_pem;
-       info.server_ssl_private_key_mem_len     = strlen(key_pem);
+       info.server_ssl_private_key_mem_len     = (unsigned int)strlen(key_pem);
        info.vhost_name = "first";
 
        if (!lws_create_vhost(context, &info)) {
@@ -443,9 +443,9 @@ int main(int argc, const char **argv)
        info.mounts = &mount;
        info.error_document_404 = "/404.html";
        info.server_ssl_cert_mem                = cert_der;
-       info.server_ssl_cert_mem_len            = sizeof(cert_der);
+       info.server_ssl_cert_mem_len            = (unsigned int)sizeof(cert_der);
        info.server_ssl_private_key_mem         = key_der;
-       info.server_ssl_private_key_mem_len     = sizeof(key_der);
+       info.server_ssl_private_key_mem_len     = (unsigned int)sizeof(key_der);
        info.vhost_name = "second";
 
        if (!lws_create_vhost(context, &info)) {
index 1606ea0..88c245a 100644 (file)
@@ -16,7 +16,7 @@ document.addEventListener("DOMContentLoaded", function() {
            }
           }
           
-          if (transport_protocol == "h2")
+          if (transport_protocol === "h2")
                document.getElementById("transport").innerHTML = "<img src=\"/http2.png\">";
-       }
+
 }, false);
\ No newline at end of file
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 758d973..9e771b3 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server-tls C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server-tls)
 set(SRCS minimal-http-server-tls.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
-require_lws_config(LWS_OPENSSL_SUPPORT 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 3cda698..a72a231 100644 (file)
 #include <libwebsockets.h>
 #include <string.h>
 #include <signal.h>
+#include <errno.h>
 
 static int interrupted;
 
-static const struct lws_http_mount mount = {
+#if defined(LWS_WITH_PLUGINS)
+static const char * const plugin_dirs[] = {
+       LWS_INSTALL_DATADIR"/libwebsockets-test-server/plugins/",
+       NULL
+};
+#endif
+
+static const struct lws_http_mount
+#if defined(LWS_WITH_SYS_METRICS)
+       mount_metrics = {
+       /* .mount_next */               NULL,           /* linked-list "next" */
+       /* .mountpoint */               "/metrics",             /* mountpoint URL */
+       /* .origin */                   "lws-openmetrics", /* serve from dir */
+       /* .def */                      "x",    /* default filename */
+       /* .protocol */                 "lws-openmetrics",
+       /* .cgienv */                   NULL,
+       /* .extra_mimetypes */          NULL,
+       /* .interpret */                NULL,
+       /* .cgi_timeout */              0,
+       /* .cache_max_age */            0,
+       /* .auth_mask */                0,
+       /* .cache_reusable */           0,
+       /* .cache_revalidate */         0,
+       /* .cache_intermediaries */     0,
+       /* .origin_protocol */          LWSMPRO_CALLBACK, /* bind to callback */
+       /* .mountpoint_len */           8,              /* char count */
+       /* .basic_auth_login_file */    NULL,
+       },
+#endif
+       mount = {
+#if defined(LWS_WITH_SYS_METRICS)
+       /* .mount_next */               &mount_metrics,         /* linked-list "next" */
+#else
        /* .mount_next */               NULL,           /* linked-list "next" */
+#endif
        /* .mountpoint */               "/",            /* mountpoint URL */
        /* .origin */                   "./mount-origin", /* serve from dir */
        /* .def */                      "index.html",   /* default filename */
-       /* .protocol */                 NULL,
+       /* .protocol */                 "http-only",
        /* .cgienv */                   NULL,
        /* .extra_mimetypes */          NULL,
        /* .interpret */                NULL,
@@ -42,40 +76,61 @@ static const struct lws_http_mount mount = {
        /* .basic_auth_login_file */    NULL,
 };
 
+#if !defined(WIN32)
+void sigint_handler(int sig, siginfo_t *siginfo, void *context)
+{
+       pid_t sender_pid = siginfo->si_pid;
+       lwsl_err("%s: sig %d from pid %lu\n", __func__, sig, (unsigned long)sender_pid);
+       interrupted = 1;
+}
+#else
 void sigint_handler(int sig)
 {
        interrupted = 1;
 }
+#endif
 
 int main(int argc, const char **argv)
 {
        struct lws_context_creation_info info;
        struct lws_context *context;
+#if !defined(WIN32)
+       struct sigaction siga;
+#endif
        const char *p;
-       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
-                       /* for LLL_ verbosity above NOTICE to be built into lws,
-                        * lws must have been configured and built with
-                        * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
-                       /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
-                       /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
-                       /* | LLL_DEBUG */;
+       int n = 0;
 
-       if ((p = lws_cmdline_option(argc, argv, "-d")))
-               logs = atoi(p);
-
-       lws_set_log_level(logs, NULL);
-       lwsl_user("LWS minimal http server TLS | visit https://localhost:7681\n");
+#if !defined(WIN32)
+       memset(&siga, 0, sizeof(siga));
+       siga.sa_sigaction = sigint_handler;
+       siga.sa_flags |= SA_SIGINFO; // get detail info
 
+           // change signal action,
+       if (sigaction(SIGINT, &siga, NULL) != 0) {
+               printf("error sigaction()");
+               return errno;
+           }
+#else
        signal(SIGINT, sigint_handler);
-
+#endif
        memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+       lwsl_user("LWS minimal http server TLS | visit https://localhost:7681\n");
+
        info.port = 7681;
+       if ((p = lws_cmdline_option(argc, argv, "--port")))
+               info.port = atoi(p);
        info.mounts = &mount;
        info.error_document_404 = "/404.html";
        info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
        info.ssl_cert_filepath = "localhost-100y.cert";
        info.ssl_private_key_filepath = "localhost-100y.key";
+       info.fo_listen_queue = 32;
+
+#if defined(LWS_WITH_PLUGINS)
+       info.plugin_dirs = plugin_dirs;
+#endif
 
        if (lws_cmdline_option(argc, argv, "-h"))
                info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
index 1606ea0..a90e446 100644 (file)
@@ -16,7 +16,6 @@ document.addEventListener("DOMContentLoaded", function() {
            }
           }
           
-          if (transport_protocol == "h2")
+          if (transport_protocol === "h2")
                document.getElementById("transport").innerHTML = "<img src=\"/http2.png\">";
-       }
-}, false);
\ No newline at end of file
+}, false);
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index a0fa4ec..b1df7af 100644 (file)
@@ -1,79 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-http-server C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-http-server)
 set(SRCS minimal-http-server.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
\ No newline at end of file
index 1cd2622..7bd74e2 100644 (file)
@@ -72,6 +72,9 @@ int main(int argc, const char **argv)
        info.options =
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
 
+       if (lws_cmdline_option(argc, argv, "--h2-prior-knowledge"))
+               info.options |= LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE;
+
        context = lws_create_context(&info);
        if (!context) {
                lwsl_err("lws init failed\n");
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
diff --git a/minimal-examples/mqtt-client/README.md b/minimal-examples/mqtt-client/README.md
new file mode 100644 (file)
index 0000000..625e9c7
--- /dev/null
@@ -0,0 +1,4 @@
+|name|demonstrates|
+---|---
+minimal-mqtt-client|Simple demo for mqtt client operation
+minimal-mqtt-client-multi|Demonstrates automatic binding / muxing of independent connections to share a single tcp / tls connection
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client-multi/CMakeLists.txt b/minimal-examples/mqtt-client/minimal-mqtt-client-multi/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bb03aae
--- /dev/null
@@ -0,0 +1,25 @@
+project(lws-minimal-mqtt-client-multi C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-mqtt-client-multi)
+set(SRCS minimal-mqtt-client-multi.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_MQTT 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client-multi/README.md b/minimal-examples/mqtt-client/minimal-mqtt-client-multi/README.md
new file mode 100644 (file)
index 0000000..a999ba5
--- /dev/null
@@ -0,0 +1,24 @@
+# lws minimal MQTT client multi
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+The application goes to https://warmcat.com and receives the page data
+same as minimal http client.
+
+However it does it for 8 client connections concurrently.
+
+## Commandline Options
+
+Option|Meaning
+---|---
+-c <conns>|Count of simultaneous connections (default 8)
+-s|Stagger the connections by 100ms, the last by 1s
+-p|Use stream binding
+
+
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client-multi/minimal-mqtt-client-multi.c b/minimal-examples/mqtt-client/minimal-mqtt-client-multi/minimal-mqtt-client-multi.c
new file mode 100644 (file)
index 0000000..a523e09
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * lws-minimal-mqtt-client
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *                         Sakthi Kannan <saktr@amazon.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
+#include <pthread.h>
+#include <assert.h>
+
+#define COUNT 8
+
+struct test_item {
+       struct lws_context              *context;
+       struct lws                      *wsi;
+       lws_sorted_usec_list_t          sul;
+} items[COUNT];
+
+enum {
+       STATE_SUBSCRIBE,        /* subscribe to the topic */
+       STATE_WAIT_SUBACK,
+       STATE_PUBLISH_QOS0,     /* Send the message in QoS0 */
+       STATE_WAIT_ACK0,        /* Wait for the synthetic "ack" */
+       STATE_PUBLISH_QOS1,     /* Send the message in QoS1 */
+       STATE_WAIT_ACK1,        /* Wait for the real ack (or timeout + retry) */
+       STATE_UNSUBSCRIBE,
+       STATE_WAIT_UNSUBACK,
+
+       STATE_TEST_FINISH
+};
+
+static int interrupted, do_ssl, pipeline, stagger_us = 5000, okay,
+          done, count = COUNT;
+
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping          = 20, /* if idle, PINGREQ after secs */
+       .secs_since_valid_hangup        = 25, /* hangup if still idle secs */
+};
+
+static const lws_mqtt_client_connect_param_t client_connect_param = {
+       .client_id                      = NULL,
+       .keep_alive                     = 60,
+       .clean_start                    = 1,
+       .client_id_nofree               = 1,
+       .username_nofree                = 1,
+       .password_nofree                = 1,
+       .will_param = {
+               .topic                  = "good/bye",
+               .message                = "sign-off",
+               .qos                    = 0,
+               .retain                 = 0,
+       },
+       .username                       = "lwsUser",
+       .password                       = "mySecretPassword",
+};
+
+static lws_mqtt_topic_elem_t topics[] = {
+       [0] = { .name = "test/topic0", .qos = QOS0 },
+       [1] = { .name = "test/topic1", .qos = QOS1 },
+};
+
+static lws_mqtt_subscribe_param_t sub_param = {
+       .topic                          = &topics[0],
+       .num_topics                     = LWS_ARRAY_SIZE(topics),
+};
+
+static const char * const test_string =
+       "No one would have believed in the last years of the nineteenth "
+       "century that this world was being watched keenly and closely by "
+       "intelligences greater than man's and yet as mortal as his own; that as "
+       "men busied themselves about their various concerns they were "
+       "scrutinised and studied, perhaps almost as narrowly as a man with a "
+       "microscope might scrutinise the transient creatures that swarm and "
+       "multiply in a drop of water.  With infinite complacency men went to "
+       "and fro over this globe about their little affairs, serene in their "
+       "assurance of their empire over matter. It is possible that the "
+       "infusoria under the microscope do the same.  No one gave a thought to "
+       "the older worlds of space as sources of human danger, or thought of "
+       "them only to dismiss the idea of life upon them as impossible or "
+       "improbable.  It is curious to recall some of the mental habits of "
+       "those departed days.  At most terrestrial men fancied there might be "
+       "other men upon Mars, perhaps inferior to themselves and ready to "
+       "welcome a missionary enterprise. Yet across the gulf of space, minds "
+       "that are to our minds as ours are to those of the beasts that perish, "
+       "intellects vast and cool and unsympathetic, regarded this earth with "
+       "envious eyes, and slowly and surely drew their plans against us.  And "
+       "early in the twentieth century came the great disillusionment. ";
+
+/* this reflects the length of the string above */
+#define TEST_STRING_LEN 1337
+
+struct pss {
+       lws_mqtt_publish_param_t        pub_param;
+       int                             state;
+       size_t                          pos;
+       int                             retries;
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static int
+connect_client(struct lws_context *context, struct test_item *item)
+{
+       struct lws_client_connect_info i;
+
+       memset(&i, 0, sizeof i);
+
+       i.mqtt_cp = &client_connect_param;
+       i.opaque_user_data = item;
+       i.protocol = "test-mqtt";
+       i.address = "localhost";
+       i.host = "localhost";
+       i.pwsi = &item->wsi;
+       i.context = context;
+       i.method = "MQTT";
+       i.alpn = "mqtt";
+       i.port = 1883;
+
+       if (do_ssl) {
+               i.ssl_connection = LCCSCF_USE_SSL;
+               i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
+               i.port = 8883;
+       }
+
+       if (pipeline)
+               i.ssl_connection |= LCCSCF_PIPELINE;
+
+       if (!lws_client_connect_via_info(&i)) {
+               lwsl_err("%s: Client Connect Failed\n", __func__);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static void
+start_conn(struct lws_sorted_usec_list *sul)
+{
+       struct test_item *item = lws_container_of(sul, struct test_item, sul);
+
+       lwsl_notice("%s: item %d\n", __func__, (int)(item - &items[0]));
+
+       if (connect_client(item->context, item))
+               interrupted = 1;
+}
+
+
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                int current, int target)
+{
+       struct lws_context *context = mgr->parent;
+       int n;
+
+       if (current != LWS_SYSTATE_OPERATIONAL ||
+           target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       /*
+       * We delay trying to do the client connection until the protocols have
+       * been initialized for each vhost... this happens after we have network
+       * and time so we can judge tls cert validity.
+       *
+       * Stagger the connection attempts so we get some joining before the
+       * first has connected and some afterwards
+       */
+
+       for (n = 0; n < count; n++) {
+               items[n].context = context;
+               lws_sul_schedule(context, 0, &items[n].sul, start_conn,
+                                n * stagger_us);
+       }
+
+       return 0;
+}
+
+
+static int
+callback_mqtt(struct lws *wsi, enum lws_callback_reasons reason,
+             void *user, void *in, size_t len)
+{
+       struct test_item *item = (struct test_item *)lws_get_opaque_user_data(wsi);
+       struct pss *pss = (struct pss *)user;
+       lws_mqtt_publish_param_t *pub;
+       size_t chunk;
+
+       switch (reason) {
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("%s: CLIENT_CONNECTION_ERROR: %s\n", __func__,
+                        in ? (char *)in : "(null)");
+
+               if (++done == count)
+                       goto finish_test;
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_CLOSED:
+               lwsl_user("%s: item %d: CLIENT_CLOSED %p\n", __func__, (int)(item - &items[0]), wsi);
+
+               if (++done == count)
+                       goto finish_test;
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_ESTABLISHED:
+               lwsl_user("%s: MQTT_CLIENT_ESTABLISHED: %p\n", __func__, wsi);
+               lws_callback_on_writable(wsi);
+
+               return 0;
+
+       case LWS_CALLBACK_MQTT_SUBSCRIBED:
+               lwsl_user("%s: MQTT_SUBSCRIBED\n", __func__);
+
+               /* then we can get on with the actual test part */
+
+               pss->state++;
+               lws_callback_on_writable(wsi);
+               break;
+
+       case LWS_CALLBACK_MQTT_UNSUBSCRIBED:
+               lwsl_user("%s: item %d: UNSUBSCRIBED: %p: Received unsuback\n",
+                         __func__, (int)(item - &item[0]), wsi);
+               okay++;
+
+               if (++pss->state == STATE_TEST_FINISH) {
+                       lwsl_notice("%s: MQTT_UNSUBACK ending stream %d successfully(%d/%d)\n",
+                                   __func__, (int)(item - &items[0]), okay, count);
+                       /* We are done, request to close */
+                       return -1;
+               }
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_WRITEABLE:
+
+               /*
+                * Extra WRITEABLE may appear here other than ones we asked
+                * for, so we must consult our own state to decide if we want
+                * to make use of the opportunity
+                */
+
+               switch (pss->state) {
+               case STATE_SUBSCRIBE:
+                       lwsl_user("%s: item %d: WRITEABLE: %p: Subscribing\n", __func__, (int)(item - &items[0]), wsi);
+
+                       if (lws_mqtt_client_send_subcribe(wsi, &sub_param)) {
+                               lwsl_notice("%s: subscribe failed\n", __func__);
+
+                               return -1;
+                       }
+                       pss->state++;
+                       break;
+
+               case STATE_PUBLISH_QOS0:
+               case STATE_PUBLISH_QOS1:
+
+                       lwsl_user("%s: item %d: WRITEABLE: %p: Publish\n", __func__, (int)(item - &items[0]), wsi);
+
+                       pss->pub_param.topic    = pss->state == STATE_PUBLISH_QOS0 ?
+                                               "test/topic0" : "test/topic1";
+                       pss->pub_param.topic_len = (uint16_t)strlen(pss->pub_param.topic);
+                       pss->pub_param.qos =
+                               pss->state == STATE_PUBLISH_QOS0 ? QOS0 : QOS1;
+                       pss->pub_param.payload_len = TEST_STRING_LEN;
+
+                       /* We send the message out 300 bytes or less at at time */
+
+                       chunk = 300;
+
+                       if (chunk > TEST_STRING_LEN - pss->pos)
+                               chunk = TEST_STRING_LEN - pss->pos;
+
+                       lwsl_notice("%s: sending %d at +%d\n", __func__,
+                                       (int)chunk, (int)pss->pos);
+
+                       if (lws_mqtt_client_send_publish(wsi, &pss->pub_param,
+                                       test_string + pss->pos, (uint32_t)chunk,
+                                       (pss->pos + chunk == TEST_STRING_LEN))) {
+                               lwsl_notice("%s: publish failed\n", __func__);
+                               return -1;
+                       }
+
+                       pss->pos += chunk;
+
+                       if (pss->pos == TEST_STRING_LEN) {
+                               lwsl_debug("%s: sent message\n", __func__);
+                               pss->pos = 0;
+                               pss->state++;
+                       }
+                       break;
+
+               case STATE_UNSUBSCRIBE:
+                       lwsl_user("%s: item %d: UNSUBSCRIBE: %p: Send unsub\n",
+                                 __func__, (int)(item - &item[0]), wsi);
+                       pss->state++;
+                       if (lws_mqtt_client_send_unsubcribe(wsi, &sub_param)) {
+                               lwsl_notice("%s: subscribe failed\n", __func__);
+                               return -1;
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               return 0;
+
+       case LWS_CALLBACK_MQTT_ACK:
+               lwsl_user("%s: item %d: MQTT_ACK (state %d)\n", __func__, (int)(item - &items[0]), pss->state);
+               /*
+                * We can forget about the message we just sent, it's done.
+                *
+                * For our test, that's the indication we can close the wsi.
+                */
+
+               pss->state++;
+               if (pss->state != STATE_TEST_FINISH) {
+                       lws_callback_on_writable(wsi);
+                       break;
+               }
+
+               break;
+
+       case LWS_CALLBACK_MQTT_RESEND:
+               lwsl_user("%s: MQTT_RESEND\n", __func__);
+               /*
+                * We must resend the packet ID mentioned in len
+                */
+               if (++pss->retries == 3) {
+                       lwsl_notice("%s: too many retries\n", __func__);
+                       return 1; /* kill the connection */
+               }
+               pss->state--;
+               pss->pos = 0;
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_RX:
+               pub = (lws_mqtt_publish_param_t *)in;
+               assert(pub);
+               lwsl_user("%s: item %d: MQTT_CLIENT_RX (%s) pos %d/%d len %d\n", __func__,
+                         (int)(item - &items[0]), pub->topic, (int)pub->payload_pos,
+                         (int)pub->payload_len, (int)len);
+
+               //lwsl_hexdump_info(pub->payload, len);
+
+               return 0;
+
+       default:
+               break;
+       }
+
+       return 0;
+
+finish_test:
+       interrupted = 1;
+       lws_cancel_service(lws_get_context(wsi));
+
+       return 0;
+}
+
+static const struct lws_protocols protocols[] = {
+       {
+               .name                   = "test-mqtt",
+               .callback               = callback_mqtt,
+               .per_session_data_size  = sizeof(struct pss)
+       },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+int main(int argc, const char **argv)
+{
+       lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
+                                            system_notify_cb, "app" };
+       lws_state_notify_link_t *na[] = { &notifier, NULL };
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       do_ssl = !!lws_cmdline_option(argc, argv, "-s");
+       if (do_ssl)
+               info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+
+       if (lws_cmdline_option(argc, argv, "-p"))
+               pipeline = 1;
+
+       if ((p = lws_cmdline_option(argc, argv, "-i")))
+               stagger_us = atoi(p);
+
+       if ((p = lws_cmdline_option(argc, argv, "-c")))
+               count = atoi(p);
+
+       if (count > COUNT) {
+               count = COUNT;
+               lwsl_err("%s: clipped count at max %d\n", __func__, count);
+       }
+
+       lwsl_user("LWS minimal MQTT client %s [-d<verbosity>][-s]\n",
+                       do_ssl ? "tls enabled": "unencrypted");
+
+       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
+       info.protocols = protocols;
+       info.register_notifier_list = na;
+       info.fd_limit_per_thread = 1 + COUNT + 1;
+       info.retry_and_idle_policy = &retry;
+
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+       /*
+        * OpenSSL uses the system trust store.  mbedTLS has to be told which
+        * CA to trust explicitly.
+        */
+       info.client_ssl_ca_filepath = "./mosq-ca.crt";
+#endif
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* Event loop */
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lwsl_user("%s: Completed: %d/%d ok, %s\n", __func__, okay, count,
+                       okay != count ? "failed" : "OK");
+       lws_context_destroy(context);
+
+       return okay != count;
+}
 
 COUNT_TESTS=1
 
-dotest $1 $2 warmcat
+#dotest $1 $2 warmcat
 
+Q=`which mosquitto`
+spawn "" /tmp $Q -v
+dotest $1 $2 -p-i100000 -p -i 100000
+
+kill $SPID 2>/dev/null
+wait $SPID 2>/dev/null
 exit $FAILS
 
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client-multi/warmcat.com.cer b/minimal-examples/mqtt-client/minimal-mqtt-client-multi/warmcat.com.cer
new file mode 100644 (file)
index 0000000..01ad0dc
--- /dev/null
@@ -0,0 +1,32 @@
+-----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-----
+
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client-multi/wget-log b/minimal-examples/mqtt-client/minimal-mqtt-client-multi/wget-log
new file mode 100644 (file)
index 0000000..bf3c762
--- /dev/null
@@ -0,0 +1,11 @@
+--2018-11-25 07:54:30--  https://www.gravatar.com/avatar/c50933ca2aa61e0fe2c43d46bb6b59cb/?s=128
+Resolving www.gravatar.com (www.gravatar.com)... 192.0.73.2, 2a04:fa87:fffe::c000:4902
+Connecting to www.gravatar.com (www.gravatar.com)|192.0.73.2|:443... connected.
+HTTP request sent, awaiting response... 200 OK
+Length: 24761 (24K) [image/png]
+Saving to: ‘/tmp/q’
+
+\r/tmp/q                     0%[                                 ]       0  --.-KB/s               \r/tmp/q                   100%[================================>]  24.18K  --.-KB/s    in 0.01s
+
+2018-11-25 07:54:31 (2.04 MB/s) - ‘/tmp/q’ saved [24761/24761]
+
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client/CMakeLists.txt b/minimal-examples/mqtt-client/minimal-mqtt-client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1b688c7
--- /dev/null
@@ -0,0 +1,23 @@
+project(lws-minimal-mqtt-client C)
+cmake_minimum_required(VERSION 2.8.12)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-mqtt-client)
+set(SRCS minimal-mqtt-client.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_MQTT 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client/README.md b/minimal-examples/mqtt-client/minimal-mqtt-client/README.md
new file mode 100644 (file)
index 0000000..909f672
--- /dev/null
@@ -0,0 +1,51 @@
+# lws minimal MQTT client
+
+The application connects to a broker at localhost 1883 (unencrypted) or
+8883 (tls)
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-s| Use tls and connect to port 8883 instead of 1883
+
+Start mosquitto server locally
+
+```
+$ mosquitto
+```
+
+Run the example
+
+```
+[2020/01/31 10:40:23:7789] U: LWS minimal MQTT client unencrypted [-d<verbosity>][-s]
+[2020/01/31 10:40:23:8539] N: lws_mqtt_generate_id: User space provided a client ID 'lwsMqttClient'
+[2020/01/31 10:40:23:9893] N: _lws_mqtt_rx_parser: migrated nwsi 0x50febd0 to sid 1 0x5106820
+[2020/01/31 10:40:23:9899] U: callback_mqtt: MQTT_CLIENT_ESTABLISHED
+[2020/01/31 10:40:23:9967] U: callback_mqtt: WRITEABLE: Subscribing
+[2020/01/31 10:40:24:0068] U: callback_mqtt: MQTT_SUBSCRIBED
+```
+
+Send something to the test client
+
+
+```
+mosquitto_pub -h 127.0.0.1 -p 1883 -t test/topic0 -m "hello"
+```
+
+Observe it received at the test client
+
+```
+[2020/01/31 10:40:27:1845] U: callback_mqtt: MQTT_CLIENT_RX
+[2020/01/31 10:40:27:1870] N: 
+[2020/01/31 10:40:27:1945] N: 0000: 74 65 73 74 2F 74 6F 70 69 63 30                   test/topic0     
+[2020/01/31 10:40:27:1952] N: 
+
+```
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client/minimal-mqtt-client.c b/minimal-examples/mqtt-client/minimal-mqtt-client/minimal-mqtt-client.c
new file mode 100644 (file)
index 0000000..5ff00c6
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * lws-minimal-mqtt-client
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *                         Sakthi Kannan <saktr@amazon.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
+#include <pthread.h>
+#include <assert.h>
+
+enum {
+       STATE_SUBSCRIBE,        /* subscribe to the topic */
+       STATE_PUBLISH_QOS0,     /* Send the message in QoS0 */
+       STATE_WAIT_ACK0,        /* Wait for the synthetic "ack" */
+       STATE_PUBLISH_QOS1,     /* Send the message in QoS1 */
+       STATE_WAIT_ACK1,        /* Wait for the real ack (or timeout + retry) */
+
+       STATE_TEST_FINISH
+};
+
+static int interrupted, bad = 1, do_ssl;
+
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping          = 20, /* if idle, PINGREQ after secs */
+       .secs_since_valid_hangup        = 25, /* hangup if still idle secs */
+};
+
+static const lws_mqtt_client_connect_param_t client_connect_param = {
+       .client_id                      = "lwsMqttClient",
+       .keep_alive                     = 60,
+       .clean_start                    = 1,
+       .client_id_nofree               = 1,
+       .username_nofree                = 1,
+       .password_nofree                = 1,
+       .will_param = {
+               .topic                  = "good/bye",
+               .message                = "sign-off",
+               .qos                    = 0,
+               .retain                 = 0,
+       },
+       .username                       = "lwsUser",
+       .password                       = "mySecretPassword",
+};
+
+static lws_mqtt_publish_param_t pub_param;
+
+static lws_mqtt_topic_elem_t topics[] = {
+       [0] = { .name = "test/topic0", .qos = QOS0 },
+       [1] = { .name = "test/topic1", .qos = QOS1 },
+};
+
+static lws_mqtt_subscribe_param_t sub_param = {
+       .topic                          = &topics[0],
+       .num_topics                     = LWS_ARRAY_SIZE(topics),
+};
+
+static const char * const test_string =
+       "No one would have believed in the last years of the nineteenth "
+       "century that this world was being watched keenly and closely by "
+       "intelligences greater than man's and yet as mortal as his own; that as "
+       "men busied themselves about their various concerns they were "
+       "scrutinised and studied, perhaps almost as narrowly as a man with a "
+       "microscope might scrutinise the transient creatures that swarm and "
+       "multiply in a drop of water.  With infinite complacency men went to "
+       "and fro over this globe about their little affairs, serene in their "
+       "assurance of their empire over matter. It is possible that the "
+       "infusoria under the microscope do the same.  No one gave a thought to "
+       "the older worlds of space as sources of human danger, or thought of "
+       "them only to dismiss the idea of life upon them as impossible or "
+       "improbable.  It is curious to recall some of the mental habits of "
+       "those departed days.  At most terrestrial men fancied there might be "
+       "other men upon Mars, perhaps inferior to themselves and ready to "
+       "welcome a missionary enterprise. Yet across the gulf of space, minds "
+       "that are to our minds as ours are to those of the beasts that perish, "
+       "intellects vast and cool and unsympathetic, regarded this earth with "
+       "envious eyes, and slowly and surely drew their plans against us.  And "
+       "early in the twentieth century came the great disillusionment. ";
+
+/* this reflects the length of the string above */
+#define TEST_STRING_LEN 1337
+
+struct pss {
+       int             state;
+       size_t          pos;
+       int             retries;
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static int
+connect_client(struct lws_context *context)
+{
+       struct lws_client_connect_info i;
+
+       memset(&i, 0, sizeof i);
+
+       i.mqtt_cp = &client_connect_param;
+       i.address = "localhost";
+       i.host = "localhost";
+       i.protocol = "mqtt";
+       i.context = context;
+       i.method = "MQTT";
+       i.alpn = "mqtt";
+       i.port = 1883;
+
+       if (do_ssl) {
+               i.ssl_connection = LCCSCF_USE_SSL;
+               i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
+               i.port = 8883;
+       }
+
+       if (!lws_client_connect_via_info(&i)) {
+               lwsl_err("%s: Client Connect Failed\n", __func__);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                int current, int target)
+{
+       struct lws_context *context = mgr->parent;
+
+       if (current != LWS_SYSTATE_OPERATIONAL ||
+           target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       /*
+       * We delay trying to do the client connection until
+       * the protocols have been initialized for each
+       * vhost... this happens after we have network and
+       * time so we can judge tls cert validity.
+       */
+
+       if (connect_client(context))
+               interrupted = 1;
+
+       return 0;
+ }
+
+
+static int
+callback_mqtt(struct lws *wsi, enum lws_callback_reasons reason,
+             void *user, void *in, size_t len)
+{
+       struct pss *pss = (struct pss *)user;
+       lws_mqtt_publish_param_t *pub;
+       size_t chunk;
+
+       switch (reason) {
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("%s: CLIENT_CONNECTION_ERROR: %s\n", __func__,
+                        in ? (char *)in : "(null)");
+               interrupted = 1;
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_CLOSED:
+               lwsl_user("%s: CLIENT_CLOSED\n", __func__);
+               interrupted = 1;
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_ESTABLISHED:
+               lwsl_user("%s: MQTT_CLIENT_ESTABLISHED\n", __func__);
+               lws_callback_on_writable(wsi);
+
+               return 0;
+
+       case LWS_CALLBACK_MQTT_SUBSCRIBED:
+               lwsl_user("%s: MQTT_SUBSCRIBED\n", __func__);
+               lws_callback_on_writable(wsi);
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_WRITEABLE:
+               /*
+                * Extra WRITEABLE may appear here other than ones we asked
+                * for, so we must consult our own state to decide if we want
+                * to make use of the opportunity
+                */
+
+               switch (pss->state) {
+               case STATE_SUBSCRIBE:
+                       lwsl_user("%s: WRITEABLE: Subscribing\n", __func__);
+
+                       if (lws_mqtt_client_send_subcribe(wsi, &sub_param)) {
+                               lwsl_notice("%s: subscribe failed\n", __func__);
+
+                               return -1;
+                       }
+                       pss->state++;
+                       break;
+
+               case STATE_PUBLISH_QOS0:
+               case STATE_PUBLISH_QOS1:
+
+                       lwsl_user("%s: WRITEABLE: Publish\n", __func__);
+
+                       pub_param.topic = "test/topic";
+                       pub_param.topic_len = (uint16_t)strlen(pub_param.topic);
+                       pub_param.qos = pss->state == STATE_PUBLISH_QOS0 ? QOS0 : QOS1;
+                       pub_param.payload_len = TEST_STRING_LEN;
+
+                       /* We send the message out 300 bytes or less at at time */
+
+                       chunk = 300;
+
+                       if (chunk > TEST_STRING_LEN - pss->pos)
+                               chunk = TEST_STRING_LEN - pss->pos;
+
+                       if (lws_mqtt_client_send_publish(wsi, &pub_param,
+                                       test_string + pss->pos, (uint32_t)chunk,
+                                       (pss->pos + chunk == TEST_STRING_LEN)))
+                               return -1;
+
+                       pss->pos += chunk;
+
+                       if (pss->pos == TEST_STRING_LEN) {
+                               pss->pos = 0;
+                               pss->state++;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+
+               return 0;
+
+       case LWS_CALLBACK_MQTT_ACK:
+               lwsl_user("%s: MQTT_ACK\n", __func__);
+               /*
+                * We can forget about the message we just sent, it's done.
+                *
+                * For our test, that's the indication we can close the wsi.
+                */
+
+               pss->state++;
+               if (pss->state != STATE_TEST_FINISH) {
+                       lws_callback_on_writable(wsi);
+                       break;
+               }
+
+               /* Oh we are done then */
+
+               bad = 0;
+               interrupted = 1;
+               lws_cancel_service(lws_get_context(wsi));
+               break;
+
+       case LWS_CALLBACK_MQTT_RESEND:
+               lwsl_user("%s: MQTT_RESEND\n", __func__);
+               /*
+                * We must resend the packet ID mentioned in len
+                */
+               if (++pss->retries == 3) {
+                       interrupted = 1;
+                       break;
+               }
+               pss->state--;
+               pss->pos = 0;
+               break;
+
+       case LWS_CALLBACK_MQTT_CLIENT_RX:
+               lwsl_user("%s: MQTT_CLIENT_RX\n", __func__);
+
+               pub = (lws_mqtt_publish_param_t *)in;
+               assert(pub);
+
+               lwsl_hexdump_notice(pub->topic, pub->topic_len);
+               lwsl_hexdump_notice(pub->payload, pub->payload_len);
+
+               return 0;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const struct lws_protocols protocols[] = {
+       {
+               .name                   = "mqtt",
+               .callback               = callback_mqtt,
+               .per_session_data_size  = sizeof(struct pss)
+       },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+int main(int argc, const char **argv)
+{
+       lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
+                                            system_notify_cb, "app" };
+       lws_state_notify_link_t *na[] = { &notifier, NULL };
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       do_ssl = !!lws_cmdline_option(argc, argv, "-s");
+       if (do_ssl)
+               info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+
+       lwsl_user("LWS minimal MQTT client %s [-d<verbosity>][-s]\n",
+                       do_ssl ? "tls enabled": "unencrypted");
+
+       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
+       info.protocols = protocols;
+       info.register_notifier_list = na;
+       info.fd_limit_per_thread = 1 + 1 + 1;
+       info.retry_and_idle_policy = &retry;
+
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+       /*
+        * OpenSSL uses the system trust store.  mbedTLS has to be told which
+        * CA to trust explicitly.
+        */
+       info.client_ssl_ca_filepath = "./mosq-ca.crt";
+#endif
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* Event loop */
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+       lws_context_destroy(context);
+
+       return bad;
+}
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client/mosq-ca.crt b/minimal-examples/mqtt-client/minimal-mqtt-client/mosq-ca.crt
new file mode 100644 (file)
index 0000000..ee3d976
--- /dev/null
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDjzCCAnegAwIBAgIUAVMnfaOq8yiLnvIB/obE689mulMwDQYJKoZIhvcNAQEL
+BQAwVjELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE
+CgwTRGVmYXVsdCBDb21wYW55IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTE5
+MTEyMDA1NTYyNFoYDzIxMTkxMDI3MDU1NjI0WjBWMQswCQYDVQQGEwJYWDEVMBMG
+A1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRk
+MRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCyw+kBLg9lCGlBceil0lNqgh7fyguin8IFm5X60bfSJ/pV6i8dZZplVjE+
+g75iFEFBYyfn+6bOPdinfQ7Uu+l6t6y2HWbK6MkoypF/g7cdtUFy9s4cUX0467BZ
+hMPJUc4UfnD+bYcXoguPJ6/OH84+Ayg6uvm5nJ32pDiXr6gMd5YljdXaJpCeeh4w
+O2UBD1HffyPIklIPT59lxv2ZvKnZbE4UE1uaLLvTWiT+X+gA3i0Syxkq5RlZ61DE
+3MyIYAUVSf3coNXCSdJ9wrOsGoP+X+T+aDjnFCCnqus3QX3JOHTKf4+tBoF65cNP
+mnHXb5/ZQCcR9HMofacalMpjiGb7AgMBAAGjUzBRMB0GA1UdDgQWBBTl3poLE/22
+R4RXTMoXPHMlc3QRjzAfBgNVHSMEGDAWgBTl3poLE/22R4RXTMoXPHMlc3QRjzAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCwWVnNjKRH9CCBv3yT
+Djah51q3NH3E+f1IcBZz2c5WbJHxEtP4QC57ou2x3hC7Cur9iOqIO57VW8vnFP2Y
+bD9oHb46grsGhwuaSuA2AlFZ5EuUAe2cgEj5/3Ihd3HYsXN3rfRO1PVGN1iRG1sE
+xAxENNm6nOS1Ht1Zy5YmMiSPzghcsTnpg44AqsmowbIED75EpumLwY2NbAl9/7JL
+EJil3cxEZ8rl2DVWPU3hAwrOfhl/rkQTCcigyPvZvAqsJ9vYhZftrF6njUsqr5kL
+KHENu5ySKPNk5gFR17WjWoqT6iEOZN25qyfFhBRzjpCX6zD1gx0sYcVryCnTH5Y4
+Drjh
+-----END CERTIFICATE-----
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client/mosq-server.crt b/minimal-examples/mqtt-client/minimal-mqtt-client/mosq-server.crt
new file mode 100644 (file)
index 0000000..46952b5
--- /dev/null
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDNTCCAh0CFFu5XIMrh5gPYnjTr8UrXA3UiWqHMA0GCSqGSIb3DQEBCwUAMFYx
+CzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl
+ZmF1bHQgQ29tcGFueSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAgFw0xOTExMjAw
+NTU4NTdaGA8yMTE5MTAyNzA1NTg1N1owVjELMAkGA1UEBhMCWFgxFTATBgNVBAcM
+DERlZmF1bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDESMBAG
+A1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+tldZ5yGrBsLR/7G4b48pwQSSG6fp4egiZdeFV7SRNfbMzpuIDlFdZM9zdcoQQrTl
+24aVIGwkvfsMD33Hb/D1WW+r8UFnq4CutigwXArXUxoFX6fa0rwEEjuxwG3f7+xm
+vb6p/KXomyWcdAUmAvALaDXIUDEc3tH+Hxik5z36YjIqRjH16jhhs/6T8B3xAWuR
+jnDknJWv36QruMIyPUqYYkl2zl4VXUKBgWZr31Opm08kb/FrWJ6lQ7912jZC8G2L
+rtwZJB/1psBrX3Oj/Quj+BWHmzkosqVae2G5zAhphZ2NMrdSVfxdctNmakH8oTwf
+hRas8DE2olW3whUkfKG2DQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAKEQ7LpPdU
+XbJKushJ7wmuljQn3pmW9SjzFMlL9o59KLHWAmxzTDaAm6r3SGgHeSz3ZLwqtJ8I
+7pCxQxI6V1ySMkWI1mfi4KPSavxBRaST4o8+YIKJt4c5aLB1seHoghx3Q/jXEGEB
+9dFyLMK6u3EhYSletQNeMVGaeK1q/nVZdHNk4LXVIHsXnKlxyMnW3v18iaV3ZhVd
+doAWMpnbY91AyCXjOmQrfQaHLL6n3r1Xk2L+cRO3nSor54UIXqIJxHZtj+ZYOy3Z
+C5AkQ1yyTTOtEz9WB0Bk2O4ZfNgJO+1MbQSfL0m0YKpuaFnMHD9g5ufUlJGR2aMI
+nw1F/oGZoNUl
+-----END CERTIFICATE-----
diff --git a/minimal-examples/mqtt-client/minimal-mqtt-client/mosq-server.key b/minimal-examples/mqtt-client/minimal-mqtt-client/mosq-server.key
new file mode 100644 (file)
index 0000000..255528d
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAtldZ5yGrBsLR/7G4b48pwQSSG6fp4egiZdeFV7SRNfbMzpuI
+DlFdZM9zdcoQQrTl24aVIGwkvfsMD33Hb/D1WW+r8UFnq4CutigwXArXUxoFX6fa
+0rwEEjuxwG3f7+xmvb6p/KXomyWcdAUmAvALaDXIUDEc3tH+Hxik5z36YjIqRjH1
+6jhhs/6T8B3xAWuRjnDknJWv36QruMIyPUqYYkl2zl4VXUKBgWZr31Opm08kb/Fr
+WJ6lQ7912jZC8G2LrtwZJB/1psBrX3Oj/Quj+BWHmzkosqVae2G5zAhphZ2NMrdS
+VfxdctNmakH8oTwfhRas8DE2olW3whUkfKG2DQIDAQABAoIBACMctwc3CIQIx/+A
+7Y8t9lBg3PHOZ89EsDsEQX0eHEhT+iRe9tgq+t0KxaUNAAyYYRrg056mtHyQ90WU
+Zu87a0OJqYaPnbL82KfjHUzcGZK7FAXTgOPLqM0KCbSQc+rzjuVC7eDk4eHeYD5H
+L4apSskKckRe8LxHm7PJPxf4a1q1EuMEfAyJhh7Tot0oVsG/wABGFUuJVJWXnec1
+0ukPowKh9bg7UyEecwyeYGzXqNqvbjhS3J0dBkjG5vfxuVHae2yIeXk6ZNsCw6tO
+K8bklmsmbWAFR5SKpsNve8X/6nlclP0taDDZsz0KSbxJEd2DuRhFcdiRWEoryZVp
+7DOORFECgYEA5sdsRjQoHaU85QZuM7ff6NpNT7kMIJbjHRdiauEBakLHs8yVLNEp
+Vvg5fcZY4PumqPKyGEjUD6DenlLvb4OBGqzKGGhAJaLz9cpVoWWPz8y1NRBfPjlB
+FQdB4GdtBQGXwnZoD9kXPjYHlk4nwZZ/Sitm2w6RibiIxE0adnwLhP8CgYEAykTE
+5NZ88OGGf0RWUt54OxTl4fChAcvK93KkdlK9nbokXHs7VIl4QpKPFu1nuMDrkVI4
+fVYwRDcZUjyxqbpBSf/M6T/kuEsMWBYYGv5c9/U87y0UWHbphN0TSdML2DJp9BTy
+uy4RleQovof2kOr6sOsKP8lhBGSlhXyJDKn1iPMCgYEAnpvc7HsYPxe7vGQpBV6Q
+g0bV777seNF7EhlqSK6P/GodOpOWyxCN6vn6+ViC6U3Lgz4Z7NrQ9FTJ6+JwMSIe
+byjmVNQBklxmcz02kRBuQJEe0XOJIgjTlBJC0moC4Xfwx3P9nTbE5LrZiBH6/O/k
+WCNwM4nVuOOdC906HMiwWh0CgYEAqn3m3ODydXQTk2i9vqIpA9vsnVLf1Ay8a3El
+sVqy26VQCugQrYQmay7wD6pS2Ec9CMQeO3+PtaAf5tKkCmWlrMNCLIWfu7v+jq0o
+6m/nW1ZKY2xDDwJEeaqDHKIZBMYRyxxxMVd2mTq1IUynh6WZY9DqVbPf4/0WC/tZ
+5ePIxAMCgYEAwwBNT2xjG1mWD4eANvKjQgrsxKFttmaXXCiixZJR+tsQc5bff5Yb
+IgvvkIwLHoNpL2Nk7sEjS4sUtAKwzCtIMwvPnhQedICnOEteZ8NPfaFmPewcovcL
+gv9k+mFActZ7H8i9FXLrZHyEzOXZaM/vY/mHbrlJSWnSDZsvnVzQv+o=
+-----END RSA PRIVATE KEY-----
index 6ee4fb8..ec79159 100644 (file)
@@ -1,76 +1,23 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-raw-adopt-tcp C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-raw-adopt-tcp)
 set(SRCS minimal-raw-adopt-tcp.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif() 
-       endif()
-ENDMACRO()
-
 set(requirements 1)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 1134234..a3ff2be 100644 (file)
@@ -31,7 +31,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#if !defined(WIN32)
 #include <unistd.h>
+#endif
 #include <errno.h>
 
 static int
@@ -74,8 +76,8 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 }
 
 static struct lws_protocols protocols[] = {
-       { "raw-test", callback_raw_test, 0, 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "raw-test", callback_raw_test, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
index 7262705..84f8cd4 100644 (file)
@@ -1,76 +1,26 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-raw-adopt-udp C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-raw-adopt-udp)
 set(SRCS minimal-raw-adopt-udp.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif() 
-       endif()
-ENDMACRO()
-
 set(requirements 1)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_UDP 1 requirements)
+
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 5689563..a2a7489 100644 (file)
@@ -28,7 +28,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#if !defined(WIN32)
 #include <unistd.h>
+#endif
 #include <errno.h>
 
 static uint8_t sendbuf[4096];
@@ -40,7 +42,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
                        void *user, void *in, size_t len)
 {
        ssize_t n;
-       int fd;
+       lws_sockfd_type fd;
 
        switch (reason) {
 
@@ -84,8 +86,13 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
                        break;
 
                fd = lws_get_socket_fd(wsi);
+#if defined(WIN32)
+               if ((int)fd < 0)
+                       break;
+#else
                if (fd < 0) /* keep Coverity happy: actually it cannot be < 0 */
                        break;
+#endif
 
                /*
                 * We can write directly on the UDP socket, specifying
@@ -102,7 +109,12 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 #if defined(WIN32)
                                (const char *)
 #endif
-                       sendbuf, sendlen, 0, &udp.sa, udp.salen);
+                       sendbuf,
+#if defined(WIN32)
+                       (int)
+#endif
+                       sendlen, 0, sa46_sockaddr(&udp.sa46),
+                       sa46_socklen(&udp.sa46));
                if (n < (ssize_t)len)
                        lwsl_notice("%s: send returned %d\n", __func__, (int)n);
                break;
@@ -115,8 +127,8 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 }
 
 static struct lws_protocols protocols[] = {
-       { "raw-test", callback_raw_test, 0, 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "raw-test", callback_raw_test, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
@@ -169,8 +181,9 @@ int main(int argc, const char **argv)
        /*
         * Create our own "foreign" UDP socket bound to 7681/udp
         */
-       if (!lws_create_adopt_udp(vhost, 7681, LWS_CAUDP_BIND,
-                                 protocols[0].name, NULL)) {
+       if (!lws_create_adopt_udp(vhost, NULL, 7681, LWS_CAUDP_BIND,
+                                 protocols[0].name, NULL, NULL, NULL, NULL,
+                                 "user")) {
                lwsl_err("%s: foreign socket adoption failed\n", __func__);
                goto bail;
        }
diff --git a/minimal-examples/raw/minimal-raw-audio/CMakeLists.txt b/minimal-examples/raw/minimal-raw-audio/CMakeLists.txt
new file mode 100644 (file)
index 0000000..21361e7
--- /dev/null
@@ -0,0 +1,24 @@
+project(lws-minimal-raw-audio C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-raw-audio)
+set(SRCS audio.c)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_ALSA 1 requirements)
+require_lws_config(LWS_WITH_NETWORK 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared asound ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets asound ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/raw/minimal-raw-audio/README.md b/minimal-examples/raw/minimal-raw-audio/README.md
new file mode 100644 (file)
index 0000000..8d54b8f
--- /dev/null
@@ -0,0 +1,37 @@
+# lws minimal raw audio
+
+This demonstrates operating ALSA playback and capture using the lws event loop
+via raw file descriptors.
+
+You need the lws cmake option `-DLWS_WITH_ALSA=1`
+
+This example opens the default ALSA playback and capture devices and pipes the
+capture data into the playback with something over 1s delay via a ringbuffer.
+
+ALSA doesn't really lend itself to direct use with event loops... this example
+uses the capture channel which does create POLLIN normally as the timesource
+for the playback as well; they're both set to 16000Hz sample rate.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+```
+ $ ./lws-minimal-raw-audio
+[2019/10/14 18:58:49:3288] U: LWS minimal raw audio
+[2019/10/14 18:58:50:3438] N: LWS_CALLBACK_RAW_ADOPT_FILE
+[2019/10/14 18:58:50:3455] N: LWS_CALLBACK_RAW_ADOPT_FILE
+[2019/10/14 18:58:50:4764] N: LWS_CALLBACK_RAW_RX_FILE: 2062 samples
+[2019/10/14 18:58:50:6132] N: LWS_CALLBACK_RAW_RX_FILE: 2205 samples
+[2019/10/14 18:58:50:7592] N: LWS_CALLBACK_RAW_RX_FILE: 2328 samples
+...
+^C[2019/10/14 18:58:56:8460] N: LWS_CALLBACK_RAW_CLOSE_FILE
+[2019/10/14 18:58:56:8461] N: LWS_CALLBACK_RAW_CLOSE_FILE
+[2019/10/14 18:58:56:8461] N: LWS_CALLBACK_PROTOCOL_DESTROY
+$
+
+```
diff --git a/minimal-examples/raw/minimal-raw-audio/audio.c b/minimal-examples/raw/minimal-raw-audio/audio.c
new file mode 100644 (file)
index 0000000..6b59539
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * lws-minimal-raw-audio
+ *
+ * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates adopting and managing audio device file descriptors in the
+ * event loop.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <alsa/asoundlib.h>
+
+static unsigned int sample_rate = 16000;
+
+struct raw_vhd {
+       uint8_t simplebuf[32768 * 2];
+       snd_pcm_t *pcm_capture;
+       snd_pcm_t *pcm_playback;
+       snd_pcm_hw_params_t *params;
+       snd_pcm_uframes_t frames;
+       int filefd;
+       int rpos;
+       int wpos;
+       int times;
+};
+
+static int
+set_hw_params(struct lws_vhost *vh, snd_pcm_t **pcm, int type)
+{
+       unsigned int rate = sample_rate;
+       snd_pcm_hw_params_t *params;
+       lws_sock_file_fd_type u;
+       struct pollfd pfd;
+       struct lws *wsi1;
+       int n;
+
+       n = snd_pcm_open(pcm, "default", type, SND_PCM_NONBLOCK);
+       if (n < 0) {
+               lwsl_err("%s: Can't open default for playback: %s\n",
+                        __func__, snd_strerror(n));
+
+               return -1;
+       }
+
+       if (snd_pcm_poll_descriptors(*pcm, &pfd, 1) != 1) {
+               lwsl_err("%s: failed to get playback desc\n", __func__);
+               return -1;
+       }
+
+       u.filefd = (lws_filefd_type)(long long)pfd.fd;
+       wsi1 = lws_adopt_descriptor_vhost(vh, LWS_ADOPT_RAW_FILE_DESC, u,
+                                         "lws-audio-test", NULL);
+       if (!wsi1) {
+               lwsl_err("%s: Failed to adopt playback desc\n", __func__);
+               goto bail;
+       }
+       if (type == SND_PCM_STREAM_PLAYBACK)
+               lws_rx_flow_control(wsi1, 0); /* no POLLIN */
+
+       snd_pcm_hw_params_malloc(&params);
+       snd_pcm_hw_params_any(*pcm, params);
+
+       n = snd_pcm_hw_params_set_access(*pcm, params,
+                                        SND_PCM_ACCESS_RW_INTERLEAVED);
+       if (n < 0)
+               goto bail1;
+
+       n = snd_pcm_hw_params_set_format(*pcm, params, SND_PCM_FORMAT_S16_LE);
+       if (n < 0)
+               goto bail1;
+
+       n = snd_pcm_hw_params_set_channels(*pcm, params, 1);
+       if (n < 0)
+               goto bail1;
+
+       n = snd_pcm_hw_params_set_rate_near(*pcm, params, &rate, 0);
+       if (n < 0)
+               goto bail1;
+
+       n = snd_pcm_hw_params(*pcm, params);
+       snd_pcm_hw_params_free(params);
+       if (n < 0)
+               goto bail;
+
+       return 0;
+
+bail1:
+       snd_pcm_hw_params_free(params);
+bail:
+       lwsl_err("%s: Set hw params failed: %s\n", __func__, snd_strerror(n));
+
+       return -1;
+}
+
+static int
+callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
+                       void *user, void *in, size_t len)
+{
+       struct raw_vhd *vhd = (struct raw_vhd *)lws_protocol_vh_priv_get(
+                                    lws_get_vhost(wsi), lws_get_protocol(wsi));
+       int n;
+
+       switch (reason) {
+       case LWS_CALLBACK_PROTOCOL_INIT:
+               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                               lws_get_protocol(wsi), sizeof(struct raw_vhd));
+
+               if (set_hw_params(lws_get_vhost(wsi), &vhd->pcm_playback,
+                                 SND_PCM_STREAM_PLAYBACK))  {
+                       lwsl_err("%s: Can't open default for playback\n",
+                                __func__);
+
+                       return -1;
+               }
+
+               if (set_hw_params(lws_get_vhost(wsi), &vhd->pcm_capture,
+                                 SND_PCM_STREAM_CAPTURE))  {
+                       lwsl_err("%s: Can't open default for capture\n",
+                                __func__);
+
+                       return -1;
+               }
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               lwsl_notice("LWS_CALLBACK_PROTOCOL_DESTROY\n");
+               if (vhd && vhd->pcm_playback) {
+                       snd_pcm_drain(vhd->pcm_playback);
+                       snd_pcm_close(vhd->pcm_playback);
+                       vhd->pcm_playback = NULL;
+               }
+               if (vhd && vhd->pcm_capture) {
+                       snd_pcm_close(vhd->pcm_capture);
+                       vhd->pcm_capture = NULL;
+               }
+               break;
+
+       case LWS_CALLBACK_RAW_RX_FILE:
+               if (vhd->times >= 6) {  /* delay amount decided by this */
+                       n = snd_pcm_writei(vhd->pcm_playback,
+                                          &vhd->simplebuf[vhd->rpos],
+                                          ((vhd->wpos - vhd->rpos) &
+                                           (sizeof(vhd->simplebuf) - 1)) / 2);
+                       vhd->rpos =  (vhd->rpos + (n * 2)) &
+                                       (sizeof(vhd->simplebuf) - 1);
+               }
+
+               n = snd_pcm_readi(vhd->pcm_capture, &vhd->simplebuf[vhd->wpos],
+                                 (sizeof(vhd->simplebuf) - vhd->wpos) / 2);
+               lwsl_notice("LWS_CALLBACK_RAW_RX_FILE: %d samples\n", n);
+               vhd->times++;
+
+               vhd->wpos = (vhd->wpos + (n * 2)) & (sizeof(vhd->simplebuf) - 1);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct lws_protocols protocols[] = {
+       { "lws-audio-test", callback_raw_test, 0, 0 },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static int interrupted;
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS minimal raw audio\n");
+
+       info.port = CONTEXT_PORT_NO_LISTEN_SERVER;
+       info.protocols = protocols;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       return 0;
+}
index f0cb7b4..c52810a 100644 (file)
@@ -1,79 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-raw-fallback-http-server C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-raw-fallback-http-server)
 set(SRCS minimal-raw-fallback-http-server.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_H1 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 1a7edaa..59f95af 100644 (file)
@@ -63,7 +63,7 @@ callback_raw_echo(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                if (len > sizeof(pss->buf))
                        len = sizeof(pss->buf);
                memcpy(pss->buf, in, len);
-               pss->len = len;
+               pss->len = (int)len;
                lws_callback_on_writable(wsi);
                break;
 
@@ -73,7 +73,7 @@ callback_raw_echo(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 
        case LWS_CALLBACK_RAW_WRITEABLE:
                lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE\n");
-               lws_write(wsi, pss->buf, pss->len, LWS_WRITE_HTTP);
+               lws_write(wsi, pss->buf, (unsigned int)pss->len, LWS_WRITE_HTTP);
                break;
        default:
                break;
@@ -83,8 +83,8 @@ callback_raw_echo(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 }
 
 static const struct lws_protocols protocols[] = {
-       { "raw-echo", callback_raw_echo, sizeof(struct pss__raw_echo), 2048 },
-       { NULL, NULL, 0, 0 }
+       { "raw-echo", callback_raw_echo, sizeof(struct pss__raw_echo), 2048, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 void sigint_handler(int sig)
@@ -119,6 +119,7 @@ int main(int argc, const char **argv)
        info.listen_accept_role = "raw-skt";
        info.listen_accept_protocol = "raw-echo";
 
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
                                LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
@@ -131,6 +132,7 @@ int main(int argc, const char **argv)
                if (lws_cmdline_option(argc, argv, "-h"))
                        info.options |= LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER;
        }
+#endif
 
        context = lws_create_context(&info);
        if (!context) {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index dc0f863..986dc06 100644 (file)
@@ -1,77 +1,23 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-raw-file C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-raw-file)
 set(SRCS minimal-raw-file.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
\ No newline at end of file
index 21c5c48..7f1cb05 100644 (file)
@@ -69,13 +69,13 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 
        case LWS_CALLBACK_RAW_RX_FILE:
                lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n");
-               n = read(vhd->filefd, buf, sizeof(buf));
+               n = (int)read(vhd->filefd, buf, sizeof(buf));
                if (n < 0) {
                        lwsl_err("Reading from %s failed\n", filepath);
 
                        return 1;
                }
-               lwsl_hexdump_level(LLL_NOTICE, buf, n);
+               lwsl_hexdump_level(LLL_NOTICE, buf, (unsigned int)n);
                break;
 
        case LWS_CALLBACK_RAW_CLOSE_FILE:
@@ -98,8 +98,8 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 }
 
 static struct lws_protocols protocols[] = {
-       { "raw-test", callback_raw_test, 0, 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "raw-test", callback_raw_test, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
index ba3997d..4e4b2ba 100644 (file)
@@ -1,76 +1,23 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-raw-netcat C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-raw-netcat)
 set(SRCS minimal-raw-netcat.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif() 
-       endif()
-ENDMACRO()
-
 set(requirements 1)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 1d8b59d..13c1ead 100644 (file)
@@ -26,7 +26,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#if !defined(WIN32)
 #include <unistd.h>
+#endif
 #include <errno.h>
 
 static struct lws *raw_wsi, *stdin_wsi;
@@ -63,7 +65,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 
        case LWS_CALLBACK_RAW_RX_FILE:
                lwsl_user("LWS_CALLBACK_RAW_RX_FILE\n");
-               waiting = read(0, buf, sizeof(buf));
+               waiting = (int)read(0, buf, sizeof(buf));
                lwsl_notice("raw file read %d\n", waiting);
                if (waiting < 0)
                        return -1;
@@ -105,7 +107,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
                // lwsl_hexdump_info(buf, waiting);
                if (stdin_wsi)
                        lws_rx_flow_control(stdin_wsi, 1);
-               if (lws_write(wsi, buf, waiting, LWS_WRITE_RAW) != waiting) {
+               if (lws_write(wsi, buf, (unsigned int)waiting, LWS_WRITE_RAW) != waiting) {
                        lwsl_notice("%s: raw skt write failed\n", __func__);
 
                        return -1;
@@ -126,8 +128,8 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 }
 
 static struct lws_protocols protocols[] = {
-       { "raw-test", callback_raw_test, 0, 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "raw-test", callback_raw_test, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 void sigint_handler(int sig)
index c0f72ce..bd08cd4 100644 (file)
@@ -1,5 +1,9 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-raw-proxy-fallback C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-raw-proxy-fallback)
 set(SRCS minimal-raw-proxy-fallback.c)
@@ -8,63 +12,6 @@ set(SRCS minimal-raw-proxy-fallback.c)
 # to the lws plugins dir so it can pick up the plugin source.  Eg,
 # cmake . -DLWS_PLUGINS_DIR=~/libwebsockets/plugins
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif() 
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_RAW_PROXY 1 requirements)
 
@@ -76,9 +23,9 @@ if (requirements)
        endif()
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 98572ae..2d290ec 100644 (file)
@@ -28,7 +28,7 @@
 
 static struct lws_protocols protocols[] = {
        LWS_PLUGIN_PROTOCOL_RAW_PROXY,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static const struct lws_http_mount mount = {
@@ -106,6 +106,7 @@ int main(int argc, const char **argv)
        info.listen_accept_role = "raw-proxy";
        info.listen_accept_protocol = "raw-proxy";
 
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
                                LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
@@ -118,6 +119,7 @@ int main(int argc, const char **argv)
                if (lws_cmdline_option(argc, argv, "-h"))
                        info.options |= LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER;
        }
+#endif
 
        context = lws_create_context(&info);
        if (!context) {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index da033dd..75fb8f9 100644 (file)
@@ -1,5 +1,9 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-raw-proxy C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-raw-proxy)
 set(SRCS minimal-raw-proxy.c)
@@ -8,63 +12,6 @@ set(SRCS minimal-raw-proxy.c)
 # to the lws plugins dir so it can pick up the plugin source.  Eg,
 # cmake . -DLWS_PLUGINS_DIR=~/libwebsockets/plugins
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif() 
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_RAW_PROXY 1 requirements)
 
@@ -76,9 +23,9 @@ if (requirements)
        endif()
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 0999780..1634a80 100644 (file)
@@ -22,7 +22,7 @@
 
 static struct lws_protocols protocols[] = {
        LWS_PLUGIN_PROTOCOL_RAW_PROXY,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
diff --git a/minimal-examples/raw/minimal-raw-serial/CMakeLists.txt b/minimal-examples/raw/minimal-raw-serial/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5dfae02
--- /dev/null
@@ -0,0 +1,23 @@
+project(lws-minimal-raw-serial C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-raw-serial)
+set(SRCS minimal-raw-file.c)
+
+set(requirements 1)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+
+if (requirements AND UNIX)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/raw/minimal-raw-serial/README.md b/minimal-examples/raw/minimal-raw-serial/README.md
new file mode 100644 (file)
index 0000000..128b789
--- /dev/null
@@ -0,0 +1,46 @@
+# lws minimal raw serial example
+
+This demonstrates adopting a file descriptor representing a serial device
+into the event loop, printing a string on it every couple of seconds and
+showing any serial that is received.
+
+The serial terminal is configured for 115200 8N1.
+
+
+```
+ $ ./lws-minimal-raw-serial <tty, eg, /dev/ttyUSB0>
+```
+
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+```
+[2019/12/08 16:30:53:4436] U: LWS minimal raw serial
+[2019/12/08 16:30:53:5016] E: callback_ntpc: set up system ops for set_clock
+[2019/12/08 16:30:54:8061] N: callback_ntpc: Unix time: 1575822654
+[2019/12/08 16:30:54:8253] N: LWS_CALLBACK_RAW_ADOPT_FILE
+[2019/12/08 16:30:54:8364] N: callback_ntpc: LWS_CALLBACK_RAW_CLOSE
+[2019/12/08 16:30:54:8456] N: LWS_CALLBACK_RAW_WRITEABLE_FILE
+[2019/12/08 16:30:56:8455] N: LWS_CALLBACK_RAW_WRITEABLE_FILE
+[2019/12/08 16:30:58:8460] N: LWS_CALLBACK_RAW_WRITEABLE_FILE
+[2019/12/08 16:30:59:1570] N: LWS_CALLBACK_RAW_RX_FILE
+[2019/12/08 16:30:59:1604] N: 
+[2019/12/08 16:30:59:1641] N: 0000: 62                                                 b               
+[2019/12/08 16:30:59:1644] N: 
+[2019/12/08 16:31:00:8463] N: LWS_CALLBACK_RAW_WRITEABLE_FILE
+[2019/12/08 16:31:01:6392] N: LWS_CALLBACK_RAW_RX_FILE
+[2019/12/08 16:31:01:6397] N: 
+[2019/12/08 16:31:01:6407] N: 0000: 65                                                 e               
+[2019/12/08 16:31:01:6411] N: 
+[2019/12/08 16:31:02:8463] N: LWS_CALLBACK_RAW_WRITEABLE_FILE
+...                                               .               
+
+```
+
+The remote serial connection will show the string sent every 2s.
diff --git a/minimal-examples/raw/minimal-raw-serial/minimal-raw-file.c b/minimal-examples/raw/minimal-raw-serial/minimal-raw-file.c
new file mode 100644 (file)
index 0000000..57ba8f0
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * lws-minimal-raw-file
+ *
+ * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates dealing with a serial port
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <termios.h>
+#include <sys/ioctl.h>
+
+#if defined(__linux__)
+#include <asm/ioctls.h>
+#include <linux/serial.h>
+#endif
+
+struct raw_vhd {
+       lws_sorted_usec_list_t sul;
+       struct lws *wsi;
+       int filefd;
+};
+
+static char filepath[256];
+
+static void
+sul_cb(lws_sorted_usec_list_t *sul)
+{
+       struct raw_vhd *v = lws_container_of(sul, struct raw_vhd, sul);
+
+       lws_callback_on_writable(v->wsi);
+
+       lws_sul_schedule(lws_get_context(v->wsi), 0, &v->sul, sul_cb,
+                        2 * LWS_USEC_PER_SEC);
+}
+
+static int
+callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
+                       void *user, void *in, size_t len)
+{
+       struct raw_vhd *vhd = (struct raw_vhd *)lws_protocol_vh_priv_get(
+                                    lws_get_vhost(wsi), lws_get_protocol(wsi));
+#if defined(__linux__)
+       struct serial_struct s_s;
+#endif
+       lws_sock_file_fd_type u;
+       struct termios tio;
+       uint8_t buf[1024];
+       int n;
+
+       switch (reason) {
+       case LWS_CALLBACK_PROTOCOL_INIT:
+               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                               lws_get_protocol(wsi), sizeof(struct raw_vhd));
+               vhd->filefd = lws_open(filepath, O_RDWR);
+               if (vhd->filefd == -1) {
+                       lwsl_err("Unable to open %s\n", filepath);
+
+                       return 1;
+               }
+
+               tcflush(vhd->filefd, TCIOFLUSH);
+
+#if defined(__linux__)
+               if (ioctl(vhd->filefd, TIOCGSERIAL, &s_s) == 0) {
+                       s_s.closing_wait = ASYNC_CLOSING_WAIT_NONE;
+                       ioctl(vhd->filefd, TIOCSSERIAL, &s_s);
+               }
+#endif
+
+               /* enforce suitable tty state */
+
+               memset(&tio, 0, sizeof tio);
+               if (tcgetattr(vhd->filefd, &tio)) {
+                       close(vhd->filefd);
+                       vhd->filefd = -1;
+                       return -1;
+               }
+
+               cfsetispeed(&tio, B115200);
+               cfsetospeed(&tio, B115200);
+
+               tio.c_lflag &= (tcflag_t)~(ISIG | ICANON | IEXTEN | ECHO |
+#if defined(__linux__)
+                               XCASE |
+#endif
+                                ECHOE | ECHOK | ECHONL | ECHOCTL | ECHOKE);
+               tio.c_iflag &= (tcflag_t)~(INLCR | IGNBRK | IGNPAR | IGNCR | ICRNL |
+                                IMAXBEL | IXON | IXOFF | IXANY
+#if defined(__linux__)
+                                | IUCLC
+#endif
+                               | 0xff);
+               tio.c_oflag = 0;
+
+               tio.c_cc[VMIN]  = 1;
+               tio.c_cc[VTIME] = 0;
+               tio.c_cc[VEOF] = 1;
+               tio.c_cflag = tio.c_cflag & (unsigned long) ~(
+#if defined(__linux__)
+                               CBAUD |
+#endif
+                               CSIZE | CSTOPB | PARENB
+#if !defined(__QNX__)
+                               | CRTSCTS
+#endif
+               );
+               tio.c_cflag |= 0x1412 | CS8 | CREAD | CLOCAL;
+
+               tcsetattr(vhd->filefd, TCSANOW, &tio);
+
+               u.filefd = (lws_filefd_type)(long long)vhd->filefd;
+               if (!lws_adopt_descriptor_vhost(lws_get_vhost(wsi),
+                                               LWS_ADOPT_RAW_FILE_DESC, u,
+                                               "raw-test", NULL)) {
+                       lwsl_err("Failed to adopt fifo descriptor\n");
+                       close(vhd->filefd);
+                       vhd->filefd = -1;
+
+                       return 1;
+               }
+
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               if (vhd && vhd->filefd != -1)
+                       close(vhd->filefd);
+               break;
+
+       /* callbacks related to raw file descriptor */
+
+       case LWS_CALLBACK_RAW_ADOPT_FILE:
+               lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n");
+               vhd->wsi = wsi;
+               lws_sul_schedule(lws_get_context(wsi), 0, &vhd->sul, sul_cb, 1);
+               break;
+
+       case LWS_CALLBACK_RAW_RX_FILE:
+               lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n");
+               n = (int)read(vhd->filefd, buf, sizeof(buf));
+               if (n < 0) {
+                       lwsl_err("Reading from %s failed\n", filepath);
+
+                       return 1;
+               }
+               lwsl_hexdump_level(LLL_NOTICE, buf, (unsigned int)n);
+               break;
+
+       case LWS_CALLBACK_RAW_CLOSE_FILE:
+               lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n");
+               lws_sul_cancel(&vhd->sul);
+               break;
+
+       case LWS_CALLBACK_RAW_WRITEABLE_FILE:
+               lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE_FILE\n");
+               if (lws_write(wsi, (uint8_t *)"hello-this-is-written-every-couple-of-seconds\r\n", 47, LWS_WRITE_RAW) != 47)
+                       return -1;
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct lws_protocols protocols[] = {
+       { "raw-test", callback_raw_test, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static int interrupted;
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
+                       /* for LLL_ verbosity above NOTICE to be built into lws,
+                        * lws must have been configured and built with
+                        * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
+                       /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
+                       /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
+                       /* | LLL_DEBUG */;
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS minimal raw serial\n");
+       if (argc < 2) {
+               lwsl_user("Usage: %s <serial device>  "
+                         " eg, /dev/ttyUSB0\n", argv[0]);
+
+               return 1;
+       }
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.port = CONTEXT_PORT_NO_LISTEN_SERVER; /* no listen socket for demo */
+       info.protocols = protocols;
+
+       lws_strncpy(filepath, argv[1], sizeof(filepath));
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       return 0;
+}
index db4810b..4e578df 100644 (file)
@@ -1,76 +1,23 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-raw-vhost C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-raw-vhost)
 set(SRCS minimal-raw-vhost.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif() 
-       endif()
-ENDMACRO()
-
 set(requirements 1)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 097abef..48267ba 100644 (file)
@@ -53,7 +53,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 
        switch (reason) {
        case LWS_CALLBACK_PROTOCOL_INIT:
-               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+               lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                                lws_get_protocol(wsi), sizeof(struct raw_vhd));
                break;
 
@@ -75,17 +75,17 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 
        case LWS_CALLBACK_RAW_RX:
                lwsl_user("LWS_CALLBACK_RAW_RX: %d\n", (int)len);
-               vhd->len = len;
+               vhd->len = (int)len;
                if (vhd->len > (int)sizeof(vhd->buf))
                        vhd->len = sizeof(vhd->buf);
-               memcpy(vhd->buf, in, vhd->len);
+               memcpy(vhd->buf, in, (unsigned int)vhd->len);
                lws_start_foreach_llp(struct raw_pss **, ppss, vhd->pss_list) {
                        lws_callback_on_writable((*ppss)->wsi);
                } lws_end_foreach_llp(ppss, pss_list);
                break;
 
        case LWS_CALLBACK_RAW_WRITEABLE:
-               if (lws_write(wsi, vhd->buf, vhd->len, LWS_WRITE_RAW) !=
+               if (lws_write(wsi, vhd->buf, (unsigned int)vhd->len, LWS_WRITE_RAW) !=
                    vhd->len) {
                        lwsl_notice("%s: raw write failed\n", __func__);
                        return 1;
@@ -100,8 +100,8 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
 }
 
 static struct lws_protocols protocols[] = {
-       { "raw-test", callback_raw_test, sizeof(struct raw_pss), 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "raw-test", callback_raw_test, sizeof(struct raw_pss), 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
@@ -137,11 +137,13 @@ int main(int argc, const char **argv)
        info.protocols = protocols;
        info.options = LWS_SERVER_OPTION_ONLY_RAW; /* vhost accepts RAW */
 
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
        }
+#endif
 
        context = lws_create_context(&info);
        if (!context) {
diff --git a/minimal-examples/secure-streams/README.md b/minimal-examples/secure-streams/README.md
new file mode 100644 (file)
index 0000000..5815630
--- /dev/null
@@ -0,0 +1,14 @@
+# Secure Streams
+
+Secure Streams is a client API that strictly decouples the policy for connections
+from the payloads.  The user code only deals with the stream type name and payloads,
+a policy database set at `lws_context` creation time decides all policy about the
+connection, including the endpoint, tls CA, and even the wire protocol.
+
+|name|demonstrates|
+---|---
+minimal-secure-streams|Minimal secure streams client / proxy example
+minimal-secure-streams-tx|Proxy used for client-tx test below
+minimal-secure-streams-client-tx|Secure streams client showing tx and rx
+
+
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-alexa/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5400c24
--- /dev/null
@@ -0,0 +1,43 @@
+project(lws-minimal-secure-streams-alexa C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-alexa)
+set(SRCS main.c alexa.c audio.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_ALSA 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared asound pv_porcupine mpg123 ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets asound pv_porcupine mpg123 ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client ${SRCS})
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared asound pv_porcupine mpg123 ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets asound pv_porcupine mpg123 ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+       
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/README.md b/minimal-examples/secure-streams/minimal-secure-streams-alexa/README.md
new file mode 100644 (file)
index 0000000..66fed37
--- /dev/null
@@ -0,0 +1,77 @@
+# lws secure streams alexa
+
+This demonstrates AVS Alexa usage using secure streams.  It connects to AVS,
+uses your linux computer's microphone to wait for the 'alexa' wakeword, sends
+the utterance to AVS and plays back the result.
+
+## build
+
+There are some special build considerations:
+
+1) Build lws with cmake options `-DLWS_WITH_ALSA=1 -DLWS_WITH_SECURE_STREAMS=1`
+
+2) Install distro build dependency packages:
+
+ |Dependency|Ubuntu package|Fedora Package|
+ |---|---|---|
+ |libasound|libasound2-dev|alsa-lib-devel|
+ |mpg123|libmpg123-dev|mpg123-devel|
+
+3) Clone Picovoice Porcupine Apache-licensed demo version from here
+
+   https://github.com/Picovoice/porcupine
+
+   It provides binary libs for wakeword detection on various platforms.  Copy
+   the headers and binary lib to your build context, eg, for native x86_64
+
+```
+   $ sudo cp ./include/* /usr/include
+   $ sudo cp ./lib/linux/x86_64/libpv_porcupine.* /usr/lib
+   $ sudo ldconfig
+```
+
+   Enter the minimal example dir for secure-streams-alexa and make the sample
+
+```
+   $ cd ./minimal-examples/secure-streams/minimal-secure-streams-alexa
+   $ cmake .
+   $ make
+```
+
+## usage
+
+```
+ $ ./lws-minimal-secure-streams-alexa
+[2019/10/16 16:22:01:1097] U: LWS secure streams - Alex voice test [-d<verb>]
+[2019/10/16 16:22:01:1115] N: lws_create_context: creating Secure Streams policy
+[2019/10/16 16:22:01:1115] N: lwsac_use: alloc 1532 for 1
+[2019/10/16 16:22:01:1119] N: lwsac_use: alloc 288 for 168
+[2019/10/16 16:22:01:1119] N: lws_ss_policy_set: policy lwsac size:     1.796KiB, pad 11%
+[2019/10/16 16:22:02:4114] N: lws_ss_client_connect: connecting 0 api.amazon.com /auth/o2/token
+[2019/10/16 16:22:02:8686] N: auth_api_amazon_com_parser_cb: expires in 3600
+[2019/10/16 16:22:02:8686] N: ss_api_amazon_auth_rx: acquired 656-byte api.amazon.com auth token
+[2019/10/16 16:22:02:8754] N: lws_ss_client_connect: connecting 1 alexa.na.gateway.devices.a2z.com /v20160207/directives
+[2019/10/16 16:22:02:3182] N: secstream_h2: h2 client entering LONG_POLL
+[2019/10/16 16:22:02:3183] U: Connected to Alexa... speak "Alexa, ..."
+[2019/10/16 16:22:06:9380] W: ************* Wakeword
+[2019/10/16 16:22:06:9380] N: avs_query_start:
+[2019/10/16 16:22:06:9381] N: lws_ss_client_connect: connecting 1 alexa.na.gateway.devices.a2z.com /v20160207/events
+[2019/10/16 16:22:06:9381] N: lws_vhost_active_conns: just join h2 directly
+[2019/10/16 16:22:06:9384] N: metadata done
+[2019/10/16 16:22:06:1524] N: est: 42 1
+[2019/10/16 16:22:06:3723] N: est: 108 1
+[2019/10/16 16:22:07:5914] N: est: 352 1
+[2019/10/16 16:22:07:8112] N: est: 4284 1
+[2019/10/16 16:22:07:0300] N: est: 3369 1
+[2019/10/16 16:22:07:2325] N: est: 577 1
+[2019/10/16 16:22:08:4519] N: est: 9 1
+[2019/10/16 16:22:08:6716] N: est: 3 1
+[2019/10/16 16:22:08:6718] N: est: 11 1
+[2019/10/16 16:22:08:8915] N: est: 10 1
+[2019/10/16 16:22:08:8915] W: callback_audio: ended capture
+[2019/10/16 16:22:09:0993] N: identified reply...
+^C[2019/10/16 16:22:14:3067] U: Disconnected from Alexa
+[2019/10/16 16:22:14:3123] U: Completed
+$
+
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa.c b/minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa.c
new file mode 100644 (file)
index 0000000..41a46cf
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * lws-minimal-secure-streams-alexa
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <mpg123.h>
+
+#include "private.h"
+
+struct lws_ss_handle *hss_avs_event, *hss_avs_sync;
+
+/* this is the type for the long poll event channel */
+
+typedef struct ss_avs_event {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+
+       struct lejp_ctx         jctx;
+} ss_avs_event_t;
+
+enum {
+       LAMP3STATE_IDLE,
+       LAMP3STATE_SPOOLING,
+       LAMP3STATE_DRAINING,
+};
+
+/* this is the type for the utterance metadata (and audio rideshares) */
+
+typedef struct ss_avs_metadata {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+
+       struct lws_buflist      *dribble; /* next mp3 data while draining last */
+
+       struct lejp_ctx         jctx;
+       size_t                  pos;
+       size_t                  mp3_in;
+       mpg123_handle           *mh;
+
+       lws_sorted_usec_list_t  sul;
+
+       uint8_t                 stash_eom[16];
+
+       uint8_t                 se_head;
+       uint8_t                 se_tail;
+
+       char                    mp3_state;
+       char                    first_mp3;
+       uint8_t                 mp3_mime_match;
+       uint8_t                 seen;
+       uint8_t                 inside_mp3;
+
+} ss_avs_metadata_t;
+
+/*
+ * The remote server only seems to give us a budget of 10s to consume the
+ * results, after that it doesn't drop the stream, but doesn't send us anything
+ * further on it.
+ *
+ * This makes it impossible to optimize buffering for incoming mp3 since we
+ * have to go ahead and take it before the 10s is up.
+ */
+
+#define MAX_MP3_IN_BUFFERING_BYTES 32768
+
+/*
+ * Structure of JSON metadata for utterance handling
+ */
+
+static const char *metadata = "{"
+       "\"event\": {"
+               "\"header\": {"
+                       "\"namespace\": \"SpeechRecognizer\","
+                       "\"name\": \"Recognize\","
+                       "\"messageId\": \"message-123\","
+                       "\"dialogRequestId\": \"dialog-request-321\""
+               "},"
+               "\"payload\": {"
+                       "\"profile\":"  "\"CLOSE_TALK\","
+                       "\"format\":"   "\"AUDIO_L16_RATE_16000_CHANNELS_1\""
+               "}"
+       "}"
+"}";
+
+/*
+ * avs metadata
+ */
+
+static void
+use_buffer_250ms(lws_sorted_usec_list_t *sul)
+{
+       ss_avs_metadata_t *m = lws_container_of(sul, ss_avs_metadata_t, sul);
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       int est = lws_ss_get_est_peer_tx_credit(m->ss);
+
+       lwsl_notice("%s: est txcr %d\n", __func__, est);
+
+       if (est < MAX_MP3_IN_BUFFERING_BYTES - (MAX_MP3_IN_BUFFERING_BYTES / 4)) {
+               lwsl_notice("   adding %d\n", MAX_MP3_IN_BUFFERING_BYTES / 4);
+               lws_ss_add_peer_tx_credit(m->ss, MAX_MP3_IN_BUFFERING_BYTES / 4);
+       }
+
+       lws_sul_schedule(context, 0, &m->sul, use_buffer_250ms,
+                        250 * LWS_US_PER_MS);
+}
+
+static const char *mp3_mimetype = "application/octet-stream",
+                 *match2 = "\x0d\x0a\x0d\x0a";
+
+static int
+ss_avs_mp3_open(ss_avs_metadata_t *m)
+{
+       int r;
+
+       lwsl_notice("%s\n", __func__);
+
+       m->first_mp3 = 1;
+       m->mh = mpg123_new(NULL, NULL);
+       if (!m->mh) {
+               lwsl_err("%s: unable to make new mp3\n",
+                               __func__);
+               goto bail;
+       }
+       mpg123_format_none(m->mh);
+       r = mpg123_format(m->mh, 16000, MPG123_M_MONO,
+                         MPG123_ENC_SIGNED_16);
+       if (r) {
+               lwsl_err("%s: mpg123 format failed %d\n",
+                               __func__, r);
+               goto bail1;
+       }
+       r = mpg123_open_feed(m->mh);
+       if (r) {
+               lwsl_err("%s: mpg123 open feed failed %d\n",
+                               __func__, r);
+               goto bail1;
+       }
+
+       return 0;
+
+bail1:
+       mpg123_delete(m->mh);
+       m->mh = NULL;
+
+bail:
+       return 1;
+}
+
+static lws_ss_state_return_t
+ss_avs_metadata_rx(void *userobj, const uint8_t *buf, size_t len, int flags);
+
+/*
+ * This is called when the mp3 has drained it's input buffer and destroyed
+ * itself.
+ */
+
+static int
+drain_end_cb(void *v)
+{
+       ss_avs_metadata_t *m = (ss_avs_metadata_t *)v;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       int tot = 0;
+
+       lwsl_err("%s\n", __func__);
+
+       /*
+        * We have drained and destroyed the existing mp3 session.  Is there
+        * a new one pending?
+        */
+
+       m->first_mp3 = 1;
+       m->mp3_state = LAMP3STATE_IDLE;
+
+       if (lws_buflist_total_len(&m->dribble)) {
+               /* we started another one */
+
+               /* resume tx credit top up */
+               lws_sul_schedule(context, 0, &m->sul, use_buffer_250ms, 1);
+
+               if (ss_avs_mp3_open(m))
+                       return 1;
+
+               m->mp3_state = LAMP3STATE_SPOOLING;
+
+               /*
+                * Dump what we stashed from draining into the new mp3
+                */
+
+               while (lws_buflist_total_len(&m->dribble)) {
+                       size_t s;
+                       uint8_t *u, t;
+
+                       s = lws_buflist_next_segment_len(&m->dribble, &u);
+                       t = m->stash_eom[m->se_tail];
+                       lwsl_notice("%s: preload %d: %d\n", __func__, (int)s, t);
+
+                       mpg123_feed(m->mh, u, s);
+                       lws_buflist_use_segment(&m->dribble, s);
+                       if (m->first_mp3) {
+                               play_mp3(m->mh, NULL, NULL);
+                               m->first_mp3 = 0;
+                       }
+
+                       tot += s;
+
+                       m->se_tail = (m->se_tail + 1) % sizeof(m->stash_eom);
+                       if (t) {
+                               lwsl_notice("%s: preloaded EOM\n", __func__);
+
+                               /*
+                                * We stashed the whole of the message, we need
+                                * to also do the EOM processing.  We will come
+                                * back here if there's another message in the
+                                * stash.
+                                */
+
+                               m->mp3_state = LAMP3STATE_DRAINING;
+                               if (m->mh)
+                                       play_mp3(NULL, drain_end_cb, m);
+
+                               lws_ss_add_peer_tx_credit(m->ss, tot);
+#if 0
+                               /*
+                                * Put a hold on bringing in any more data
+                                */
+                               lws_sul_cancel(&m->sul);
+#endif
+                               /* destroy our copy of the handle */
+                               m->mh = NULL;
+
+                               break;
+                       }
+               }
+
+               lws_ss_add_peer_tx_credit(m->ss, tot);
+       }
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+ss_avs_metadata_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       int n = 0, hit = 0;
+
+       lwsl_notice("%s: len %d, flags %d (est peer txcr %d)\n", __func__,
+                   (int)len, flags, lws_ss_get_est_peer_tx_credit(m->ss));
+
+       // lwsl_hexdump_warn(buf, len);
+
+       if ((flags & LWSSS_FLAG_SOM) && !m->mh && !m->seen) {
+               m->mp3_mime_match = 0;
+               m->seen = 0;
+               m->inside_mp3 = 0;
+       }
+
+       if (!m->inside_mp3) {
+               /*
+                * Identify the part with the mp3 in, if any
+                */
+
+               while (n < (int)len - 24) {
+                       if (!m->seen) {
+                               if (buf[n] == mp3_mimetype[m->mp3_mime_match]) {
+                                       m->mp3_mime_match++;
+                                       if (m->mp3_mime_match == 24) {
+                                               m->mp3_mime_match = 0;
+                                               m->seen = 1;
+                                               n++;
+                                               continue;
+                                       }
+                               } else
+                                       m->mp3_mime_match = 0;
+                       } else {
+                               if (buf[n] == match2[m->mp3_mime_match]) {
+                                       m->mp3_mime_match++;
+                                       if (m->mp3_mime_match == 4) {
+                                               m->seen = 0;
+                                               m->mp3_mime_match = 0;
+                                               hit = 1;
+                                               n++;
+                                               buf += n;
+                                               len -= n;
+                                               lwsl_notice("identified reply...\n");
+                                               m->inside_mp3 = 1;
+                                               break;
+                                       }
+                               } else
+                                       m->mp3_mime_match = 0;
+                       }
+
+                       n++;
+               }
+
+               if (!hit) {
+                       lws_ss_add_peer_tx_credit(m->ss, len);
+                       return 0;
+               }
+       }
+
+       // lwsl_notice("%s: state %d\n", __func__, m->mp3_state);
+
+       switch (m->mp3_state) {
+       case LAMP3STATE_IDLE:
+
+               if (hit) {
+
+                       lws_ss_add_peer_tx_credit(m->ss, n);
+
+                       if (ss_avs_mp3_open(m))
+                               goto bail;
+
+                       lws_sul_schedule(context, 0, &m->sul, use_buffer_250ms, 1);
+                       m->mp3_state = LAMP3STATE_SPOOLING;
+                       break;
+               }
+
+               lws_ss_add_peer_tx_credit(m->ss, len);
+
+               if (!m->inside_mp3)
+                       break;
+
+               /* fallthru */
+
+       case LAMP3STATE_SPOOLING:
+
+               if (m->dribble)
+                       goto draining;
+
+               if (len) {
+                       /*
+                        * We are shoving encoded mp3 into mpg123-allocated heap
+                        * buffers... unfortunately mpg123 doesn't seem to
+                        * expose where it is in its allocated input so we can
+                        * track how much is stashed.  Instead while in playback
+                        * mode, we assume 64kbps mp3 encoding, ie, 8KB/s, and
+                        * run a sul that allows an additional 2KB tx credit
+                        * every 250ms, with 4KB initial credit.
+                        */
+                       lwsl_notice("%s: SPOOL %d\n", __func__, (int)len);
+                       mpg123_feed(m->mh, buf, len);
+
+                       if (m->first_mp3) {
+                               lws_sul_schedule(context, 0, &m->sul,
+                                                use_buffer_250ms, 1);
+               //              lws_ss_add_peer_tx_credit(m->ss,
+               //                      len + (MAX_MP3_IN_BUFFERING_BYTES / 2));
+                               play_mp3(m->mh, NULL, NULL);
+                       } //else
+               //              lws_ss_add_peer_tx_credit(m->ss, len);
+                       m->first_mp3 = 0;
+               }
+
+               if (flags & LWSSS_FLAG_EOM) {
+                       /*
+                        * This means one "message" / mime part with mp3 data
+                        * has finished coming in.  But there may be whole other
+                        * parts with other mp3s following, with potentially
+                        * different mp3 parameters.  So we want to tell this
+                        * one to drain and finish and destroy the current mp3
+                        * object before we go on.
+                        *
+                        * But not knowing the length of the current one, there
+                        * will already be outstanding tx credit at the server,
+                        * so it's going to spam us with the next part before we
+                        * have the new mp3 sink for it.
+                        */
+                       lwsl_notice("%s: EOM\n", __func__);
+                       m->mp3_mime_match = 0;
+                       m->seen = 0;
+                       m->mp3_state = LAMP3STATE_DRAINING;
+                       /* from input POV, we're no longer inside an mp3 */
+                       m->inside_mp3 = 0;
+                       if (m->mh)
+                               play_mp3(NULL, drain_end_cb, m);
+#if 0
+                       /*
+                        * Put a hold on bringing in any more data
+                        */
+                       lws_sul_cancel(&m->sul);
+#endif
+                       /* destroy our copy of the handle */
+                       m->mh = NULL;
+               }
+               break;
+
+       case LAMP3STATE_DRAINING:
+
+draining:
+               if (buf && len && m->inside_mp3) {
+                       lwsl_notice("%s: DRAINING: stashing %d: %d %d %d\n",
+                                   __func__, (int)len, !!(flags & LWSSS_FLAG_EOM),
+                                   m->se_head, m->se_tail);
+                       lwsl_hexdump_notice(buf, len);
+                       if (lws_buflist_append_segment(&m->dribble, buf, len) < 0)
+                               goto bail;
+
+                       m->stash_eom[m->se_head] = !!(flags & LWSSS_FLAG_EOM);
+                       m->se_head = (m->se_head + 1) % sizeof(m->stash_eom);
+                       lwsl_notice("%s: next head %d\n", __func__, m->se_head);
+
+                       lws_ss_add_peer_tx_credit(m->ss, len);
+               }
+
+               if (flags & LWSSS_FLAG_EOM) {
+                       if (!len && m->se_head != m->se_tail) {
+                               /* 0-len EOM... retrospectively mark last stash */
+                               lwsl_notice("%s: retro EOM\n", __func__);
+                               m->stash_eom[(m->se_head - 1) % sizeof(m->stash_eom)] = 1;
+                       }
+
+                       lwsl_notice("%s: Draining EOM\n", __func__);
+                       m->inside_mp3 = 0;
+               }
+               /*
+                * Don't provide any additional tx credit... we're just
+                * mopping up the overspill from the previous mp3 credit
+                */
+               break;
+       }
+
+       return 0;
+
+bail:
+       return -1;
+}
+
+/*
+ * Because this is multipart mime in h2 currently, use a "rideshare" to handle
+ * first the native metadata on this secure stream, then the "rideshare" audio
+ * stream mentioned in the policy.
+ *
+ * Lws takes care of interleaving the multipart mime pieces since the policy
+ * calls for it.
+ */
+
+static lws_ss_state_return_t
+ss_avs_metadata_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                  size_t *len, int *flags)
+{
+       ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj;
+       size_t tot;
+       int n;
+
+       // lwsl_notice("%s %d\n", __func__, (int)m->pos);
+
+       if ((long)m->pos < 0) {
+               *len = 0;
+               lwsl_info("%s: skip\n", __func__);
+               return 1;
+       }
+
+       if (!strcmp(lws_ss_rideshare(m->ss), "avs_audio")) {
+
+               /* audio rideshare part */
+
+               if (!m->pos)
+                       *flags |= LWSSS_FLAG_SOM;
+
+               n = spool_capture(buf, *len);
+               if (n > 0)
+                       *len = n;
+               else
+                       *len = 0;
+               if (!n) {
+                       lwsl_info("%s: trying to skip tx\n", __func__);
+                       return 1;
+               }
+
+               m->pos += *len;
+
+               if (n < 0) {
+                       *flags |= LWSSS_FLAG_EOM;
+                       m->pos = (long)-1l; /* ban subsequent until new stream */
+               }
+
+               lwsl_notice("%s: tx audio %d\n", __func__, (int)*len);
+
+#if 0
+               {
+                       int ff = open("/tmp/z1", O_RDWR | O_CREAT | O_APPEND, 0666);
+                       if (ff == -1)
+                               lwsl_err("%s: errno %d\n", __func__, errno);
+                       write(ff, buf, *len);
+                       close(ff);
+               }
+#endif
+
+               return 0;
+       }
+
+       /* metadata part */
+
+       tot = strlen(metadata);
+
+       if (!m->pos)
+               *flags |= LWSSS_FLAG_SOM;
+
+       if (*len > tot - m->pos)
+               *len = tot - m->pos;
+
+       memcpy(buf, metadata + m->pos, *len);
+
+       m->pos += *len;
+
+       if (m->pos == tot) {
+               lwsl_notice("metadata done\n");
+               *flags |= LWSSS_FLAG_EOM;
+               m->pos = 0; /* for next time */
+       }
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+ss_avs_metadata_state(void *userobj, void *sh,
+                     lws_ss_constate_t state, lws_ss_tx_ordinal_t ack)
+{
+       ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+
+       lwsl_notice("%s: %p: %s, ord 0x%x\n", __func__, m->ss,
+                   lws_ss_state_name(state), (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_CONNECTING:
+               m->pos = 0;
+               break;
+       case LWSSSCS_CONNECTED:
+               lwsl_info("%s: CONNECTED\n", __func__);
+               return lws_ss_request_tx(m->ss);
+
+       case LWSSSCS_DISCONNECTED:
+               lws_sul_cancel(&m->sul);
+               //if (m->mh) {
+                       play_mp3(NULL, NULL, NULL);
+                       m->mh = NULL;
+               //}
+               /*
+                * For this stream encapsulating an alexa exchange, dropping
+                * is the end of its life
+                */
+               return 1;
+
+       case LWSSSCS_DESTROYING:
+               lws_buflist_destroy_all_segments(&m->dribble);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * avs event
+ */
+
+static lws_ss_state_return_t
+ss_avs_event_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       return 0;
+}
+
+static lws_ss_state_return_t
+ss_avs_event_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                     size_t *len, int *flags)
+{
+       return 1; /* don't transmit anything */
+}
+
+static lws_ss_state_return_t
+ss_avs_event_state(void *userobj, void *sh,
+                  lws_ss_constate_t state, lws_ss_tx_ordinal_t ack)
+{
+       lwsl_info("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               mpg123_init();
+               break;
+       case LWSSSCS_CONNECTING:
+               break;
+       case LWSSSCS_CONNECTED:
+               lwsl_user("Connected to Alexa... speak \"Alexa, ...\"\n");
+               break;
+       case LWSSSCS_DISCONNECTED:
+               lwsl_user("Disconnected from Alexa\n");
+               break;
+       case LWSSSCS_DESTROYING:
+               mpg123_exit();
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+int
+avs_query_start(struct lws_context *context)
+{
+       lws_ss_info_t ssi;
+
+       lwsl_notice("%s:\n", __func__);
+
+       memset(&ssi, 0, sizeof(ssi));
+       ssi.handle_offset           = offsetof(ss_avs_metadata_t, ss);
+       ssi.opaque_user_data_offset = offsetof(ss_avs_metadata_t, opaque_data);
+       ssi.rx                      = ss_avs_metadata_rx;
+       ssi.tx                      = ss_avs_metadata_tx;
+       ssi.state                   = ss_avs_metadata_state;
+       ssi.user_alloc              = sizeof(ss_avs_metadata_t);
+       ssi.streamtype              = "avs_metadata";
+
+       ssi.manual_initial_tx_credit = 8192;
+
+       if (lws_ss_create(context, 0, &ssi, context, &hss_avs_sync, NULL, NULL)) {
+               lwsl_err("%s: failed to create avs metadata secstream\n",
+                        __func__);
+
+               return 1;
+       }
+
+       lwsl_user("%s: created query stream %p\n", __func__, hss_avs_sync);
+
+       return 0;
+}
+
+int
+avs_example_start(struct lws_context *context)
+{
+       lws_ss_info_t ssi;
+
+       if (hss_avs_event)
+               return 0;
+
+       lwsl_info("%s: Starting AVS stream\n", __func__);
+
+       /* AVS wants us to establish the long poll event stream first */
+
+       memset(&ssi, 0, sizeof(ssi));
+       ssi.handle_offset           = offsetof(ss_avs_event_t, ss);
+       ssi.opaque_user_data_offset = offsetof(ss_avs_event_t, opaque_data);
+       ssi.rx                      = ss_avs_event_rx;
+       ssi.tx                      = ss_avs_event_tx;
+       ssi.state                   = ss_avs_event_state;
+       ssi.user_alloc              = sizeof(ss_avs_event_t);
+       ssi.streamtype              = "avs_event";
+
+       if (lws_ss_create(context, 0, &ssi, context, &hss_avs_event, NULL, NULL)) {
+               lwsl_err("%s: failed to create avs event secure stream\n",
+                        __func__);
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa_linux.ppn b/minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa_linux.ppn
new file mode 100644 (file)
index 0000000..839156d
Binary files /dev/null and b/minimal-examples/secure-streams/minimal-secure-streams-alexa/alexa_linux.ppn differ
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/audio.c b/minimal-examples/secure-streams/minimal-secure-streams-alexa/audio.c
new file mode 100644 (file)
index 0000000..6233db4
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * alsa audio handling
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <alsa/asoundlib.h>
+#include <pv_porcupine.h>
+
+#include <mpg123.h>
+
+#include "private.h"
+
+extern struct lws_ss_handle *hss_avs_event, *hss_avs_sync;
+
+int
+avs_query_start(struct lws_context *context);
+
+enum {
+       MODE_IDLE,
+       MODE_CAPTURING,
+       MODE_PLAYING
+};
+
+struct raw_vhd {
+       int16_t                 p[8 * 1024]; /* 500ms at 16kHz 16-bit PCM */
+       pv_porcupine_object_t   *porc;
+       snd_pcm_t               *pcm_capture;
+       snd_pcm_t               *pcm_playback;
+       snd_pcm_hw_params_t     *params;
+       snd_pcm_uframes_t       frames;
+       int16_t                 *porcbuf;
+
+       mpg123_handle           *mh;
+
+       mp3_done_cb             done_cb;
+       void                    *opaque;
+
+       int                     mode;
+       int                     rate;
+
+       int                     porc_spf;
+       int                     filefd;
+       int                     rpos;
+       int                     wpos;
+       int                     porcpos;
+       int                     npos;
+       int                     times;
+       int                     quietcount;
+       int                     anycount;
+
+       int                     wplay;
+       int                     rplay;
+
+       char                    last_wake_detect;
+       char                    destroy_mh_on_drain;
+};
+
+static struct raw_vhd *avhd;
+
+/*
+ * called from alexa.c to grab the next chunk of audio capture buffer
+ * for upload
+ */
+
+int
+spool_capture(uint8_t *buf, size_t len)
+{
+       int16_t *sam = (int16_t *)buf;
+       size_t s, os;
+
+       if (avhd->mode != MODE_CAPTURING)
+               return -1;
+
+       os = s = len / 2;
+
+       while (s && avhd->wpos != avhd->npos) {
+               *sam++ = avhd->p[avhd->npos];
+               avhd->npos = (avhd->npos + 1)  % LWS_ARRAY_SIZE(avhd->p);
+               s--;
+       }
+
+       lwsl_info("Copied %d samples (%d %d)\n", (int)(os - s),
+                       avhd->wpos, avhd->npos);
+
+       return (os - s) * 2;
+}
+
+/*
+ * Called from alexa.c to control when the mp3 playback should begin and end
+ */
+
+int
+play_mp3(mpg123_handle *mh, mp3_done_cb cb, void *opaque)
+{
+       if (mh) {
+               avhd->mh = mh;
+               avhd->mode = MODE_PLAYING;
+               snd_pcm_prepare(avhd->pcm_playback);
+
+               return 0;
+       }
+
+       avhd->destroy_mh_on_drain = 1;
+       avhd->done_cb = cb;
+       avhd->opaque = opaque;
+
+       return 0;
+}
+
+/*
+ * Helper used to set alsa hwparams on both capture and playback channels
+ */
+
+static int
+set_hw_params(struct lws_vhost *vh, snd_pcm_t **pcm, int type)
+{
+       unsigned int rate = pv_sample_rate(); /* it's 16kHz */
+       snd_pcm_hw_params_t *params;
+       lws_sock_file_fd_type u;
+       struct pollfd pfd;
+       struct lws *wsi1;
+       int n;
+
+       n = snd_pcm_open(pcm, "default", type, SND_PCM_NONBLOCK);
+       if (n < 0) {
+               lwsl_err("%s: Can't open default for playback: %s\n",
+                        __func__, snd_strerror(n));
+
+               return -1;
+       }
+
+       if (snd_pcm_poll_descriptors(*pcm, &pfd, 1) != 1) {
+               lwsl_err("%s: failed to get playback desc\n", __func__);
+               return -1;
+       }
+
+       u.filefd = (lws_filefd_type)(long long)pfd.fd;
+       wsi1 = lws_adopt_descriptor_vhost(vh, LWS_ADOPT_RAW_FILE_DESC, u,
+                                         "lws-audio-test", NULL);
+       if (!wsi1) {
+               lwsl_err("%s: Failed to adopt playback desc\n", __func__);
+               goto bail;
+       }
+       if (type == SND_PCM_STREAM_PLAYBACK)
+               lws_rx_flow_control(wsi1, 0); /* no POLLIN */
+
+       snd_pcm_hw_params_malloc(&params);
+       snd_pcm_hw_params_any(*pcm, params);
+
+       n = snd_pcm_hw_params_set_access(*pcm, params,
+                                        SND_PCM_ACCESS_RW_INTERLEAVED);
+       if (n < 0)
+               goto bail1;
+
+       n = snd_pcm_hw_params_set_format(*pcm, params, SND_PCM_FORMAT_S16_LE);
+       if (n < 0)
+               goto bail1;
+
+       n = snd_pcm_hw_params_set_channels(*pcm, params, 1);
+       if (n < 0)
+               goto bail1;
+
+       n = snd_pcm_hw_params_set_rate_near(*pcm, params, &rate, 0);
+       if (n < 0)
+               goto bail1;
+
+       lwsl_notice("%s: %s rate %d\n", __func__,
+               type == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture", rate);
+
+       n = snd_pcm_hw_params(*pcm, params);
+       snd_pcm_hw_params_free(params);
+       if (n < 0)
+               goto bail;
+
+       return 0;
+
+bail1:
+       snd_pcm_hw_params_free(params);
+bail:
+       lwsl_err("%s: Set hw params failed: %s\n", __func__, snd_strerror(n));
+
+       return -1;
+}
+
+/*
+ * The lws RAW file protocol handler that wraps ALSA.
+ *
+ * The timing is coming from ALSA capture channel... since they are both set to
+ * 16kHz, it's enough just to have the one.
+ */
+
+static int
+callback_audio(struct lws *wsi, enum lws_callback_reasons reason, void *user,
+              void *in, size_t len)
+{
+       struct raw_vhd *vhd = (struct raw_vhd *)lws_protocol_vh_priv_get(
+                                  lws_get_vhost(wsi), lws_get_protocol(wsi));
+       uint16_t rands[50];
+       int16_t temp[256];
+       bool det;
+       long avg;
+       int n, s;
+
+       switch (reason) {
+       case LWS_CALLBACK_PROTOCOL_INIT:
+
+               if (avhd) /* just on one vhost */
+                       return 0;
+
+               avhd = vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                               lws_get_protocol(wsi), sizeof(struct raw_vhd));
+
+               /*
+                * Set up the wakeword library
+                */
+
+               n = pv_porcupine_init("porcupine_params.pv", "alexa_linux.ppn",
+                                       1.0, &vhd->porc);
+               if (n) {
+                       lwsl_err("%s: porcupine init fail %d\n", __func__, n);
+
+                       return -1;
+               }
+               vhd->porc_spf = pv_porcupine_frame_length();
+               vhd->porcbuf = malloc(vhd->porc_spf * 2);
+               lwsl_info("%s: %s porc frame length is %d samples\n", __func__,
+                               lws_get_vhost_name(lws_get_vhost(wsi)),
+                               vhd->porc_spf);
+
+               vhd->rate = pv_sample_rate(); /* 16kHz */
+
+               /* set up alsa */
+
+               if (set_hw_params(lws_get_vhost(wsi), &vhd->pcm_playback,
+                                 SND_PCM_STREAM_PLAYBACK))  {
+                       lwsl_err("%s: Can't open default for playback\n",
+                                __func__);
+
+                       return -1;
+               }
+
+               if (set_hw_params(lws_get_vhost(wsi), &vhd->pcm_capture,
+                                 SND_PCM_STREAM_CAPTURE))  {
+                       lwsl_err("%s: Can't open default for capture\n",
+                                __func__);
+
+                       return -1;
+               }
+
+               snd_config_update_free_global();
+
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               lwsl_info("%s: LWS_CALLBACK_PROTOCOL_DESTROY\n", __func__);
+               if (!vhd)
+                       break;
+
+               if (vhd->porcbuf) {
+                       free(vhd->porcbuf);
+                       vhd->porcbuf = NULL;
+               }
+               if (vhd->pcm_playback) {
+                       snd_pcm_drop(vhd->pcm_playback);
+                       snd_pcm_close(vhd->pcm_playback);
+                       vhd->pcm_playback = NULL;
+               }
+               if (vhd->pcm_capture) {
+                       snd_pcm_drop(vhd->pcm_capture);
+                       snd_pcm_close(vhd->pcm_capture);
+                       vhd->pcm_capture = NULL;
+               }
+               if (vhd->porc) {
+                       pv_porcupine_delete(vhd->porc);
+                       vhd->porc = NULL;
+               }
+
+               /* avoid most of the valgrind mess from alsa */
+               snd_config_update_free_global();
+
+               break;
+
+       case LWS_CALLBACK_RAW_CLOSE_FILE:
+               lwsl_info("%s: closed\n", __func__);
+               break;
+
+       case LWS_CALLBACK_RAW_RX_FILE:
+               /* we come here about every 250ms */
+
+               /*
+                * Playing back the mp3?
+                */
+               if (vhd->mode == MODE_PLAYING && vhd->mh) {
+                       size_t amt, try;
+
+                       do {
+                               try = snd_pcm_avail(vhd->pcm_playback);
+                               if (try > LWS_ARRAY_SIZE(vhd->p))
+                                       try = LWS_ARRAY_SIZE(vhd->p);
+
+                               n = mpg123_read(vhd->mh, (uint8_t *)vhd->p,
+                                               try * 2, &amt);
+                               lwsl_info("%s: PLAYING: mpg123 read %d, n %d\n",
+                                               __func__, (int)amt, n);
+                               if (n == MPG123_NEW_FORMAT) {
+                                       snd_pcm_start(vhd->pcm_playback);
+                                       memset(vhd->p, 0, try);
+                                       snd_pcm_writei(vhd->pcm_playback,
+                                                      vhd->p, try / 2);
+                                       snd_pcm_prepare(vhd->pcm_playback);
+                               }
+                       } while (n == MPG123_NEW_FORMAT);
+
+                       if (amt) {
+                               n = snd_pcm_writei(vhd->pcm_playback,
+                                                  vhd->p, amt / 2);
+                               if (n < 0)
+                                       lwsl_notice("%s: snd_pcm_writei: %d %s\n",
+                                                   __func__, n, snd_strerror(n));
+                               if (n == -EPIPE) {
+                                       lwsl_err("%s: did EPIPE prep\n", __func__);
+                                       snd_pcm_prepare(vhd->pcm_playback);
+                               }
+                       } else
+                               if (vhd->destroy_mh_on_drain &&
+                                   n != MPG123_NEW_FORMAT) {
+                                       snd_pcm_drain(vhd->pcm_playback);
+                                       vhd->destroy_mh_on_drain = 0;
+                                       lwsl_notice("%s: mp3 destroyed\n",
+                                                       __func__);
+                                       mpg123_close(vhd->mh);
+                                       mpg123_delete(vhd->mh);
+                                       vhd->mh = NULL;
+                                       vhd->mode = MODE_IDLE;
+
+                                       if (vhd->done_cb)
+                                               vhd->done_cb(vhd->opaque);
+                               }
+               }
+
+               /*
+                * Get the capture data
+                */
+
+               n = snd_pcm_readi(vhd->pcm_capture, temp, LWS_ARRAY_SIZE(temp));
+               s = 0;
+               while (s < n) {
+                       vhd->p[(vhd->wpos + s) % LWS_ARRAY_SIZE(vhd->p)] = temp[s];
+                       s++;
+               }
+
+               if (vhd->mode == MODE_CAPTURING) {
+
+                       /*
+                        * We are recording an utterance.
+                        *
+                        * Estimate the sound density in the frame by picking 50
+                        * samples at random and averaging the sampled
+                        * [abs()^2] / 10000 to create a Figure of Merit.
+                        *
+                        * Speaking on my laptop gets us 1000 - 5000, silence
+                        * is typ under 30.  The wakeword tells us there was
+                        * speech at the start, end the capture when there's
+                        * ~750ms (12000 samples) under 125 FOM.
+                        */
+
+#define SILENCE_THRESH 125
+
+                       avg = 0;
+                       lws_get_random(lws_get_context(wsi), rands, sizeof(rands));
+                       for (s = 0; s < (int)LWS_ARRAY_SIZE(rands); s++) {
+                               long q;
+
+                               q = temp[rands[s] % n];
+
+                               avg += (q * q);
+                       }
+                       avg = (avg / (int)LWS_ARRAY_SIZE(rands)) / 10000;
+
+                       lwsl_notice("est audio energy: %ld %d\n", avg, vhd->mode);
+
+                       /*
+                        * Only start looking for "silence" after 1.5s, in case
+                        * he does a long pause after the wakeword
+                        */
+
+                       if (vhd->anycount < (3 *vhd->rate) / 2 &&
+                           avg < SILENCE_THRESH) {
+                               vhd->quietcount += n;
+                               /* then 500ms of "silence" does it for us */
+                               if (vhd->quietcount >= ((vhd->rate * 3) / 4)) {
+                                       lwsl_warn("%s: ended capture\n", __func__);
+                                       vhd->mode = MODE_IDLE;
+                                       vhd->quietcount = 0;
+                               }
+                       }
+
+                       /* if we're not "silent", reset the count */
+                       if (avg > SILENCE_THRESH * 2)
+                               vhd->quietcount = 0;
+
+                       /*
+                        * Since we are in capturing mode, we have something
+                        * new to send now.
+                        *
+                        * We must send an extra one at the end so we can finish
+                        * the tx.
+                        */
+                       lws_ss_request_tx(hss_avs_sync);
+               }
+
+               /*
+                * Just waiting for a wakeword
+                */
+
+               while (vhd->mode == MODE_IDLE) {
+                       int m = 0, ppold = vhd->porcpos;
+
+                       s = (vhd->wpos - vhd->porcpos) % LWS_ARRAY_SIZE(vhd->p);
+                       if (s < vhd->porc_spf)
+                               goto eol;
+
+                       while (m < vhd->porc_spf) {
+                               vhd->porcbuf[m++] = avhd->p[vhd->porcpos];
+                               vhd->porcpos = (vhd->porcpos + 1) %
+                                                       LWS_ARRAY_SIZE(vhd->p);
+                       }
+
+                       if (pv_porcupine_process(vhd->porc, vhd->porcbuf, &det))
+                               lwsl_err("%s: porc_process failed\n", __func__);
+
+                       if (!det && vhd->last_wake_detect &&
+                           vhd->mode == MODE_IDLE) {
+                               lwsl_warn("************* Wakeword\n");
+                               if (!avs_query_start(lws_get_context(wsi))) {
+                                       vhd->mode = MODE_CAPTURING;
+                                       vhd->quietcount = 0;
+                                       vhd->last_wake_detect = det;
+                                       vhd->npos = ppold;
+                                       break;
+                               }
+                       }
+                       vhd->last_wake_detect = det;
+               }
+
+eol:
+               vhd->wpos = (vhd->wpos + n) % LWS_ARRAY_SIZE(vhd->p);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+struct lws_protocols protocol_audio_test =
+       { "lws-audio-test", callback_audio, 0, 0 };
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/main.c b/minimal-examples/secure-streams/minimal-secure-streams-alexa/main.c
new file mode 100644 (file)
index 0000000..f6a24d7
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * lws-minimal-secure-streams-alexa
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+extern int
+avs_example_start(struct lws_context *context);
+
+static int interrupted;
+static lws_state_notify_link_t nl;
+
+#if !defined(LWS_SS_USE_SSPC)
+
+/*
+ * If not using the proxy, we need to bring our own policy
+ */
+
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "60,"
+                       "\"svalidhup\":"        "64"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               "{\"digicert_global_root_g2\": \"" /* api.amazon.com 2038-01 */
+       "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="
+               "\"},"
+               "{\"digicert_global_ca_g2\": \"" /* api.amazon.com 2028-08 */
+       "MIIEizCCA3OgAwIBAgIQDI7gyQ1qiRWIBAYe4kH5rzANBgkqhkiG9w0BAQsFADBh"
+       "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3"
+       "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH"
+       "MjAeFw0xMzA4MDExMjAwMDBaFw0yODA4MDExMjAwMDBaMEQxCzAJBgNVBAYTAlVT"
+       "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEdsb2Jh"
+       "bCBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANNIfL7zBYZd"
+       "W9UvhU5L4IatFaxhz1uvPmoKR/uadpFgC4przc/cV35gmAvkVNlW7SHMArZagV+X"
+       "au4CLyMnuG3UsOcGAngLH1ypmTb+u6wbBfpXzYEQQGfWMItYNdSWYb7QjHqXnxr5"
+       "IuYUL6nG6AEfq/gmD6yOTSwyOR2Bm40cZbIc22GoiS9g5+vCShjEbyrpEJIJ7RfR"
+       "ACvmfe8EiRROM6GyD5eHn7OgzS+8LOy4g2gxPR/VSpAQGQuBldYpdlH5NnbQtwl6"
+       "OErXb4y/E3w57bqukPyV93t4CTZedJMeJfD/1K2uaGvG/w/VNfFVbkhJ+Pi474j4"
+       "8V4Rd6rfArMCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0P"
+       "AQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29j"
+       "c3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmw0LmRp"
+       "Z2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOGMWh0dHA6"
+       "Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwPQYD"
+       "VR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2lj"
+       "ZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFCRuKy3QapJRUSVpAaqaR6aJ50AgMB8GA1Ud"
+       "IwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA0GCSqGSIb3DQEBCwUAA4IBAQAL"
+       "OYSR+ZfrqoGvhOlaOJL84mxZvzbIRacxAxHhBsCsMsdaVSnaT0AC9aHesO3ewPj2"
+       "dZ12uYf+QYB6z13jAMZbAuabeGLJ3LhimnftiQjXS8X9Q9ViIyfEBFltcT8jW+rZ"
+       "8uckJ2/0lYDblizkVIvP6hnZf1WZUXoOLRg9eFhSvGNoVwvdRLNXSmDmyHBwW4co"
+       "atc7TlJFGa8kBpJIERqLrqwYElesA8u49L3KJg6nwd3jM+/AVTANlVlOnAM2BvjA"
+       "jxSZnE0qnsHhfTuvcqdFuhOWKU4Z0BqYBvQ3lBetoxi6PrABDJXWKTUgNX31EGDk"
+       "92hiHuwZ4STyhxGs6QiA"
+               "\"},"
+               "{\"amazon_root_ca_1\": \""
+       "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"
+               "\"},"
+               "{\"starfield_services_root_ca\": \""
+       "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"
+               "\"},"
+               "{\"starfield_class_2_ca\": \""
+       "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="
+               "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"  /* chain for alexa.na.gateway.devices.a2z.com */
+                       "\"name\": \"avs_via_starfield\","
+                       "\"stack\": ["
+                               "\"starfield_class_2_ca\","
+                               "\"starfield_services_root_ca\""
+                       "]"
+               "},"
+               "{" /* chain for api.amazon.com */
+                       "\"name\": \"api_amazon_com\","
+                       "\"stack\": ["
+                               "\"digicert_global_ca_g2\","
+                               "\"digicert_global_root_g2\""
+                       "]"
+               "}"
+         "],"
+         "\"auth\": [" /* available auth type bindings */
+               "{"
+                 "\"name\":"           "\"lwa\","
+                 "\"streamtype\":"     "\"api_amazon_com_lwa\","
+                 "\"blob\":"           "0"
+               "}"
+         "],"
+         "\"s\": [" /* the supported stream types */
+               "{\"api_amazon_com_lwa\": {"
+                       "\"endpoint\":"                 "\"api.amazon.com\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h1\","
+                       "\"http_method\":"              "\"POST\","
+                       "\"http_url\":"                 "\"auth/o2/token\","
+                       "\"opportunistic\":"            "true,"
+                       "\"tls\":"                      "true,"
+                       "\"h2q_oflow_txcr\":"           "true,"
+                       "\"http_www_form_urlencoded\":" "true,"
+                       "\"http_no_content_length\":"   "true,"
+                       "\"retry\":"                    "\"default\","
+                       "\"tls_trust_store\":"          "\"api_amazon_com\""
+               "}},"
+               /*
+                * long poll event listener
+                */
+               "{\"avs_event\": {"
+                       "\"endpoint\":"                 "\"alexa.na.gateway.devices.a2z.com\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h2\","
+                       "\"http_method\":"              "\"GET\","
+                       "\"http_url\":"                 "\"v20160207/directives\","
+                       "\"use_auth\":"                 "\"lwa\","
+                       "\"h2q_oflow_txcr\":"           "true,"
+                       "\"http_auth_header\":"         "\"authorization:\","
+                       "\"http_auth_preamble\":"       "\"Bearer \","
+                       "\"http_multipart_ss_in\":"     "true,"
+                       "\"nailed_up\":"                "true,"
+                       "\"long_poll\":"                "true,"
+                       "\"retry\":"                    "\"default\","
+                       "\"tls\":"                      "true,"
+                       "\"tls_trust_store\":"          "\"avs_via_starfield\""
+               "}},"
+               /*
+                * Utterance metadata and audio send and reply processing.
+                *
+                * "Rideshare" and http_multipart_mime means these both go out
+                * in one multipart http transaction.
+                */
+               "{\"avs_metadata\": {"
+                       "\"endpoint\":"                 "\"alexa.na.gateway.devices.a2z.com\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h2\","
+                       "\"http_method\":"              "\"POST\","
+                       "\"http_url\":"                 "\"v20160207/events\","
+                       "\"use_auth\":"                 "\"lwa\","
+                       "\"opportunistic\":"            "true,"
+                       "\"h2q_oflow_txcr\":"           "true,"
+                       "\"http_auth_header\":"         "\"authorization:\","
+                       "\"http_auth_preamble\":"       "\"Bearer \","
+                       "\"http_multipart_name\":"      "\"metadata\","
+                       "\"http_mime_content_type\":"   "\"application/json; charset=UTF-8\","
+                       "\"http_no_content_length\":"   "true,"
+                       "\"http_multipart_ss_in\":"     "true,"
+                       "\"rideshare\":"                "\"avs_audio\","
+                       "\"retry\":"                    "\"default\","
+                       "\"tls\":"                      "true,"
+                       "\"tls_trust_store\":"          "\"avs_via_starfield\""
+               "}},"
+               "{\"avs_audio\": {"
+                       "\"endpoint\":"                 "\"alexa.na.gateway.devices.a2z.com\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h2\","
+                       "\"http_method\":"              "\"POST\","
+                       "\"http_url\":"                 "\"v20160207/events\","
+                       "\"use_auth\":"                 "\"lwa\","
+                       "\"tls\":"                      "true,"
+                       "\"h2q_oflow_txcr\":"           "true,"
+                       "\"http_auth_header\":"         "\"authorization:\","
+                       "\"http_auth_preamble\":"       "\"Bearer \","
+                       "\"http_multipart_ss_in\":"     "true,"
+                       "\"http_multipart_name\":"      "\"audio\","
+                       "\"http_mime_content_type\":"   "\"application/octet-stream\","
+                       "\"http_no_content_length\":"   "true,"
+                       "\"retry\":"                    "\"default\","
+                       "\"tls_trust_store\":"          "\"avs_via_starfield\""
+               "}}"
+         "]"
+       "}"
+;
+
+#endif
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+/*
+ * Register the root token, and make the sticky AVS connection at the
+ * appropriate times during system startup
+ */
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == target)
+                       avs_example_start(context);
+               break;
+       case LWS_SYSTATE_POLICY_INVALID:
+               /*
+                * This is a NOP since we used direct set... but in a real
+                * system this could easily change to be done on the heap, then
+                * this would be important
+                */
+               lws_system_blob_destroy(lws_system_get_blob(context,
+                                       LWS_SYSBLOB_TYPE_AUTH,
+                                       1 /* AUTH_IDX_ROOT */));
+               break;
+       }
+
+       return 0;
+}
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+extern struct lws_protocols protocol_audio_test;
+static const struct lws_protocols *protocols[] = {
+       &protocol_audio_test,
+#if defined(LWS_SS_USE_SSPC)
+       lws_sspc_protocols,
+#endif
+       NULL
+};
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams - Alexa voice test [-d<verb>]\n");
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+#if !defined(LWS_SS_USE_SSPC)
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.pss_policies_json = default_ss_policy;
+#else
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#endif
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.pprotocols = protocols;
+
+       /* integrate us with lws system state management when context created */
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* create an explicit vhost so the sound protocol is initialized */
+
+       info.vhost_name = "asound";
+       if (!lws_create_vhost(context, &info)) {
+               lwsl_err("lws init failed\n");
+               goto bail;
+       }
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+bail:
+       lws_context_destroy(context);
+       lwsl_user("Completed\n");
+
+       return 0;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/porcupine_params.pv b/minimal-examples/secure-streams/minimal-secure-streams-alexa/porcupine_params.pv
new file mode 100644 (file)
index 0000000..4d88bb5
Binary files /dev/null and b/minimal-examples/secure-streams/minimal-secure-streams-alexa/porcupine_params.pv differ
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/private.h b/minimal-examples/secure-streams/minimal-secure-streams-alexa/private.h
new file mode 100644 (file)
index 0000000..a4920b1
--- /dev/null
@@ -0,0 +1,8 @@
+typedef int (*mp3_done_cb)(void *opaque);
+
+int
+play_mp3(mpg123_handle *mh, mp3_done_cb cb, void *opaque);
+
+
+int
+spool_capture(uint8_t *buf, size_t len);
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-avs/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-avs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1ec1318
--- /dev/null
@@ -0,0 +1,41 @@
+project(lws-minimal-secure-streams-avs C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-avs)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} main.c avs.c)
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client main-client.c avs.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c b/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c
new file mode 100644 (file)
index 0000000..bb453bf
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * lws-minimal-secure-streams-avs
+ *
+ * Written in 2019-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This sends a canned WAV and received (and discards) the mp3 response.
+ * However it rate-limits the response reception to manage a small ringbuffer
+ * using ss / h2 flow control apis, reflecting consumption at 64kbps and only
+ * and 8KB buffer, indtended to model optimizing rx buffering on mp3 playback
+ * on a constrained device.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if !defined(WIN32)
+#include <unistd.h>
+#endif
+#include <assert.h>
+#include <fcntl.h>
+
+extern int interrupted, bad;
+static struct lws_ss_handle *hss_avs_event, *hss_avs_sync;
+static uint8_t *wav;
+static size_t wav_len;
+
+typedef struct ss_avs_event {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+       struct lejp_ctx         jctx;
+} ss_avs_event_t;
+
+typedef struct ss_avs_metadata {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+       struct lejp_ctx         jctx;
+       size_t                  pos;
+
+       /*
+        * We simulate a ringbuffer that is used up by a sul at 64Kbit/sec
+        * rate, and managed at the same rate using tx credit
+        */
+
+       lws_sorted_usec_list_t  sul;
+       uint8_t                 buf[256 * 1024]; /* to test rate-limiting, set to 8 * 1024 */
+       int                     head;
+       int                     tail;
+
+       char                    filled;
+
+} ss_avs_metadata_t;
+
+static const char *metadata = "{"
+       "\"event\": {"
+               "\"header\": {"
+                       "\"namespace\": \"SpeechRecognizer\","
+                       "\"name\": \"Recognize\","
+                       "\"messageId\": \"message-123\","
+                       "\"dialogRequestId\": \"dialog-request-321\""
+               "},"
+               "\"payload\": {"
+                       "\"profile\":"  "\"CLOSE_TALK\","
+                       "\"format\":"   "\"AUDIO_L16_RATE_16000_CHANNELS_1\""
+               "}"
+       "}"
+"}";
+
+/*
+ * avs metadata
+ */
+
+static void
+use_buffer_50ms(lws_sorted_usec_list_t *sul)
+{
+       ss_avs_metadata_t *m = lws_container_of(sul, ss_avs_metadata_t, sul);
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       size_t n;
+       int e;
+
+       /*
+        * Use up 50ms-worth (8KB / 20) == 401 bytes of buffered data
+        */
+
+       /* remaining data in buffer */
+       n = ((size_t)(m->head - m->tail) % sizeof(m->buf));
+       lwsl_info("%s: avail %d\n", __func__, (int)n);
+
+       if (n < 401)
+               lwsl_err("%s: underrun\n", __func__);
+
+       m->tail = ((size_t)m->tail + 401) % sizeof(m->buf);
+       n = ((size_t)(m->head - m->tail) % sizeof(m->buf));
+
+       e = lws_ss_get_est_peer_tx_credit(m->ss);
+
+       lwsl_info("%s: avail after: %d, curr est %d\n", __func__, (int)n, e);
+
+       if (n < (sizeof(m->buf) * 2) / 3 && e < (int)(sizeof(m->buf) - 1 - n)) {
+               lwsl_info("%s: requesting additional %d\n", __func__,
+                               (int)sizeof(m->buf) - 1 - e - (int)n);
+               lws_ss_add_peer_tx_credit(m->ss, (int32_t)((int)sizeof(m->buf) - 1 - e - (int)n));
+       }
+
+       lws_sul_schedule(context, 0, &m->sul, use_buffer_50ms,
+                        50 * LWS_US_PER_MS);
+}
+
+static lws_ss_state_return_t
+ss_avs_metadata_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       size_t n, n1;
+
+       lwsl_notice("%s: rideshare %s, len %d, flags 0x%x\n", __func__,
+                       lws_ss_rideshare(m->ss), (int)len, flags);
+#if 0
+       lwsl_hexdump_warn(buf, len);
+#endif
+
+       n = sizeof(m->buf) - ((size_t)(m->head - m->tail) % sizeof(m->buf));
+       lwsl_info("%s: len %d, buf h %d, t %d, space %d\n", __func__,
+                   (int)len, (int)m->head, (int)m->tail, (int)n);
+       lws_ss_get_est_peer_tx_credit(m->ss);
+       if (len > n) {
+               lwsl_err("%s: bad len: len %d, n %d\n", __func__, (int)len, (int)n);
+               assert(0);
+
+               return 1;
+       }
+
+       if (m->head < m->tail)                          /* |****h-------t**| */
+               memcpy(&m->buf[m->head], buf, len);
+       else {                                          /* |---t*****h-----| */
+               n1 = sizeof(m->buf) - (size_t)m->head;
+               if (len < n1)
+                       n1 = len;
+               memcpy(&m->buf[m->head], buf, n1);
+               if (n1 != len)
+                       memcpy(m->buf, buf, len - n1);
+       }
+
+       m->head = (((size_t)m->head) + len) % sizeof(m->buf);
+
+       lws_sul_schedule(context, 0, &m->sul, use_buffer_50ms,
+                        50 * LWS_US_PER_MS);
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+ss_avs_metadata_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                  size_t *len, int *flags)
+{
+       ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj;
+       //struct lws_context *context = (struct lws_context *)m->opaque_data;
+       size_t tot;
+
+       if ((long)m->pos < 0) {
+               *len = 0;
+               lwsl_debug("%s: skip tx\n", __func__);
+               return 1;
+       }
+
+//     lwsl_notice("%s: rideshare '%s'\n", __func__, lws_ss_rideshare(m->ss));
+
+       if (!strcmp(lws_ss_rideshare(m->ss), "avs_audio")) {
+               /* audio rideshare */
+
+               if (!m->pos)
+                       *flags |= LWSSS_FLAG_SOM;
+
+               if (*len > wav_len - m->pos)
+                       *len = wav_len - m->pos;
+
+               memcpy(buf, wav + m->pos, *len);
+               m->pos += *len;
+
+               if (m->pos == wav_len) {
+                       *flags |= LWSSS_FLAG_EOM;
+                       lwsl_info("%s: tx done\n", __func__);
+                       m->pos = (size_t)-1l; /* ban subsequent until new stream */
+               } else
+                       return lws_ss_request_tx(m->ss);
+
+               lwsl_hexdump_info(buf, *len);
+
+               return 0;
+       }
+
+       /* metadata part */
+
+       tot = strlen(metadata);
+
+       if (!m->pos)
+               *flags |= LWSSS_FLAG_SOM;
+
+       if (*len > tot - m->pos)
+               *len = tot - m->pos;
+
+       memcpy(buf, metadata + m->pos, *len);
+
+       m->pos += *len;
+
+       if (m->pos == tot) {
+               *flags |= LWSSS_FLAG_EOM;
+               m->pos = 0; /* for next time */
+               return lws_ss_request_tx(m->ss);
+       }
+
+       lwsl_hexdump_info(buf, *len);
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+ss_avs_metadata_state(void *userobj, void *sh,
+                     lws_ss_constate_t state, lws_ss_tx_ordinal_t ack)
+{
+
+       ss_avs_metadata_t *m = (ss_avs_metadata_t *)userobj;
+       // struct lws_context *context = (struct lws_context *)m->opaque_data;
+
+       lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               lwsl_user("%s: CREATING\n", __func__);
+               m->pos = 0;
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_CONNECTING:
+               break;
+       case LWSSSCS_CONNECTED:
+               return lws_ss_request_tx(m->ss);
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* for this demo app, we want to exit on fail to connect */
+       case LWSSSCS_DISCONNECTED:
+               /* for this demo app, we want to exit after complete flow */
+               lws_sul_cancel(&m->sul);
+               interrupted = 1;
+               break;
+       case LWSSSCS_DESTROYING:
+               lws_sul_cancel(&m->sul);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * avs event
+ */
+
+static lws_ss_state_return_t
+ss_avs_event_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+#if !defined(LWS_WITH_NO_LOGS)
+       ss_avs_event_t *m = (ss_avs_event_t *)userobj;
+       // struct lws_context *context = (struct lws_context *)m->opaque_data;
+
+       lwsl_notice("%s: rideshare %s, len %d, flags 0x%x\n", __func__,
+                       lws_ss_rideshare(m->ss), (int)len, flags);
+#endif
+//     lwsl_hexdump_warn(buf, len);
+
+       bad = 0; /* for this demo, receiving something here == success */
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+ss_avs_event_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
+                     size_t *len, int *flags)
+{
+#if !defined(LWS_WITH_NO_LOGS)
+       ss_avs_event_t *m = (ss_avs_event_t *)userobj;
+       lwsl_notice("%s: rideshare %s\n", __func__, lws_ss_rideshare(m->ss));
+#endif
+       return 1; /* don't transmit anything */
+}
+
+static lws_ss_state_return_t
+ss_avs_event_state(void *userobj, void *sh,
+                  lws_ss_constate_t state, lws_ss_tx_ordinal_t ack)
+{
+       ss_avs_event_t *m = (ss_avs_event_t *)userobj;
+       struct lws_context *context = (struct lws_context *)m->opaque_data;
+       lws_ss_info_t ssi;
+
+       lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+       case LWSSSCS_CONNECTING:
+               break;
+       case LWSSSCS_CONNECTED:
+               if (hss_avs_sync)
+                       break;
+
+               lwsl_notice("%s: starting the second avs stream\n", __func__);
+
+               /*
+                * When we have established the event stream, we must POST
+                * on another stream within 10s
+                */
+
+               memset(&ssi, 0, sizeof(ssi));
+               ssi.handle_offset           = offsetof(ss_avs_metadata_t, ss);
+               ssi.opaque_user_data_offset = offsetof(ss_avs_metadata_t,
+                                                      opaque_data);
+               ssi.rx                      = ss_avs_metadata_rx;
+               ssi.tx                      = ss_avs_metadata_tx;
+               ssi.state                   = ss_avs_metadata_state;
+               ssi.user_alloc              = sizeof(ss_avs_metadata_t);
+               ssi.streamtype              = "avs_metadata";
+
+               /*
+                * We want to allow the other side to fill our buffer, but no
+                * more.  But it's a bit tricky when the payload is inside
+                * framing like multipart MIME and contains other parts
+                */
+
+               /* uncomment to test rate-limiting, doesn't work with AVS servers */
+//             ssi.manual_initial_tx_credit =
+//                             sizeof(((ss_avs_metadata_t *)0)->buf) / 2;
+
+               if (lws_ss_create(context, 0, &ssi, context, &hss_avs_sync,
+                                 NULL, NULL)) {
+                       lwsl_err("%s: failed to create avs metadata secstream\n",
+                                __func__);
+               }
+               break;
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* for this demo app, we want to exit on fail to connect */
+               interrupted = 1;
+               break;
+       case LWSSSCS_DISCONNECTED:
+               break;
+       case LWSSSCS_DESTROYING:
+               lwsl_notice("%s: DESTROYING\n", __func__);
+               if (wav) {
+                       free(wav);
+                       wav = NULL;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+int
+avs_example_start(struct lws_context *context)
+{
+       lws_ss_info_t ssi;
+       struct stat stat;
+       int fd;
+
+       if (hss_avs_event)
+               return 0;
+
+       fd = open("./year.wav", O_RDONLY);
+       if (fd < 0) {
+               lwsl_err("%s: failed to open wav file\n", __func__);
+
+               return 1;
+       }
+       if (fstat(fd, &stat) < 0) {
+               lwsl_err("%s: failed to stat wav file\n", __func__);
+
+               goto bail;
+       }
+
+       wav_len = (size_t)stat.st_size;
+       wav = malloc(wav_len);
+       if (!wav) {
+               lwsl_err("%s: failed to alloc wav buffer", __func__);
+
+               goto bail;
+       }
+       if (read(fd, wav,
+#if defined(WIN32)
+               (unsigned int)
+#endif
+                       wav_len) != (int)wav_len) {
+               lwsl_err("%s: failed to read wav\n", __func__);
+
+               goto bail;
+       }
+       close(fd);
+
+       lwsl_user("%s: Starting AVS stream\n", __func__);
+
+       /* AVS wants us to establish the long poll event stream first */
+
+       memset(&ssi, 0, sizeof(ssi));
+       ssi.handle_offset           = offsetof(ss_avs_event_t, ss);
+       ssi.opaque_user_data_offset = offsetof(ss_avs_event_t, opaque_data);
+       ssi.rx                      = ss_avs_event_rx;
+       ssi.tx                      = ss_avs_event_tx;
+       ssi.state                   = ss_avs_event_state;
+       ssi.user_alloc              = sizeof(ss_avs_event_t);
+       ssi.streamtype              = "avs_event";
+
+       if (lws_ss_create(context, 0, &ssi, context, &hss_avs_event, NULL, NULL)) {
+               lwsl_err("%s: failed to create avs event secure stream\n",
+                        __func__);
+               free(wav);
+               wav = NULL;
+               return 1;
+       }
+
+       return 0;
+
+bail:
+       close(fd);
+
+       return 1;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-avs/main-client.c b/minimal-examples/secure-streams/minimal-secure-streams-avs/main-client.c
new file mode 100644 (file)
index 0000000..0f62d43
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * lws-minimal-secure-streams-avs
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+extern int
+avs_example_start(struct lws_context *context);
+
+int interrupted, bad = 1;
+static lws_state_notify_link_t nl;
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL)
+                       avs_example_start(context);
+               break;
+       case LWS_SYSTATE_POLICY_INVALID:
+               /*
+                * This is a NOP since we used direct set... but in a real
+                * system this could easily change to be done on the heap, then
+                * this would be important
+                */
+               lws_system_blob_destroy(lws_system_get_blob(context,
+                                       LWS_SYSBLOB_TYPE_AUTH,
+                                       1 /* AUTH_IDX_ROOT */));
+               break;
+       }
+
+       return 0;
+}
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams - AVS test client [-d<verb>]\n");
+
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.protocols = lws_sspc_protocols;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+
+       /* integrate us with lws system state management when context created */
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-avs/main.c b/minimal-examples/secure-streams/minimal-secure-streams-avs/main.c
new file mode 100644 (file)
index 0000000..56ca531
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * lws-minimal-secure-streams-avs
+ *
+ * Written in 2019-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+extern int
+avs_example_start(struct lws_context *context);
+
+int interrupted, bad = 1;
+static lws_state_notify_link_t nl;
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+//       "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "60,"
+                       "\"svalidhup\":"        "64"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               "{\"digicert_global_root_g2\": \"" /* api.amazon.com 2038-01 */
+       "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="
+               "\"},"
+               "{\"digicert_global_ca_g2\": \"" /* api.amazon.com 2028-08 */
+       "MIIEizCCA3OgAwIBAgIQDI7gyQ1qiRWIBAYe4kH5rzANBgkqhkiG9w0BAQsFADBh"
+       "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3"
+       "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH"
+       "MjAeFw0xMzA4MDExMjAwMDBaFw0yODA4MDExMjAwMDBaMEQxCzAJBgNVBAYTAlVT"
+       "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEdsb2Jh"
+       "bCBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANNIfL7zBYZd"
+       "W9UvhU5L4IatFaxhz1uvPmoKR/uadpFgC4przc/cV35gmAvkVNlW7SHMArZagV+X"
+       "au4CLyMnuG3UsOcGAngLH1ypmTb+u6wbBfpXzYEQQGfWMItYNdSWYb7QjHqXnxr5"
+       "IuYUL6nG6AEfq/gmD6yOTSwyOR2Bm40cZbIc22GoiS9g5+vCShjEbyrpEJIJ7RfR"
+       "ACvmfe8EiRROM6GyD5eHn7OgzS+8LOy4g2gxPR/VSpAQGQuBldYpdlH5NnbQtwl6"
+       "OErXb4y/E3w57bqukPyV93t4CTZedJMeJfD/1K2uaGvG/w/VNfFVbkhJ+Pi474j4"
+       "8V4Rd6rfArMCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0P"
+       "AQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29j"
+       "c3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmw0LmRp"
+       "Z2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOGMWh0dHA6"
+       "Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwPQYD"
+       "VR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2lj"
+       "ZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFCRuKy3QapJRUSVpAaqaR6aJ50AgMB8GA1Ud"
+       "IwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA0GCSqGSIb3DQEBCwUAA4IBAQAL"
+       "OYSR+ZfrqoGvhOlaOJL84mxZvzbIRacxAxHhBsCsMsdaVSnaT0AC9aHesO3ewPj2"
+       "dZ12uYf+QYB6z13jAMZbAuabeGLJ3LhimnftiQjXS8X9Q9ViIyfEBFltcT8jW+rZ"
+       "8uckJ2/0lYDblizkVIvP6hnZf1WZUXoOLRg9eFhSvGNoVwvdRLNXSmDmyHBwW4co"
+       "atc7TlJFGa8kBpJIERqLrqwYElesA8u49L3KJg6nwd3jM+/AVTANlVlOnAM2BvjA"
+       "jxSZnE0qnsHhfTuvcqdFuhOWKU4Z0BqYBvQ3lBetoxi6PrABDJXWKTUgNX31EGDk"
+       "92hiHuwZ4STyhxGs6QiA"
+               "\"},"
+               "{\"starfield_services_root_ca\": \""
+       "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"
+               "\"},"
+               "{\"starfield_class_2_ca\": \""
+       "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="
+               "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"  /* chain for alexa.na.gateway.devices.a2z.com */
+                       "\"name\": \"avs_via_starfield\","
+                       "\"stack\": ["
+                               "\"starfield_class_2_ca\","
+                               "\"starfield_services_root_ca\""
+                       "]"
+               "},"
+               "{" /* chain for api.amazon.com */
+                       "\"name\": \"api_amazon_com\","
+                       "\"stack\": ["
+                               "\"digicert_global_ca_g2\","
+                               "\"digicert_global_root_g2\""
+                       "]"
+               "}"
+         "],"
+         "\"auth\": [" /* available auth type bindings */
+               "{"
+                 "\"name\":"           "\"lwa\","
+                 "\"streamtype\":"     "\"api_amazon_com_lwa\","
+                 "\"blob\":"           "0"
+               "}"
+         "],"
+         "\"s\": [" /* the supported stream types */
+               "{\"api_amazon_com_lwa\": {"
+                       "\"endpoint\":"                 "\"api.amazon.com\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h1\","
+                       "\"http_method\":"              "\"POST\","
+                       "\"http_url\":"                 "\"auth/o2/token\","
+                       "\"opportunistic\":"            "true,"
+                       "\"tls\":"                      "true,"
+                       "\"h2q_oflow_txcr\":"           "true,"
+                       "\"http_www_form_urlencoded\":" "true,"
+                       "\"http_no_content_length\":"   "true,"
+                       "\"retry\":"                    "\"default\","
+                       "\"tls_trust_store\":"          "\"api_amazon_com\""
+               "}},"
+               "{\"avs_event\": {"
+                       "\"endpoint\":"                 "\"alexa.na.gateway.devices.a2z.com\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h2\","
+                       "\"http_method\":"              "\"GET\","
+                       "\"http_url\":"                 "\"v20160207/directives\","
+                       "\"h2q_oflow_txcr\":"           "true,"
+                       "\"http_auth_header\":"         "\"authorization:\","
+                       "\"http_auth_preamble\":"       "\"Bearer \","
+                       "\"use_auth\":"                 "\"lwa\","
+                       "\"nailed_up\":"                "true,"
+                       "\"long_poll\":"                "true,"
+                       "\"retry\":"                    "\"default\","
+                       "\"tls\":"                      "true,"
+                       "\"tls_trust_store\":"          "\"avs_via_starfield\""
+               "}},"
+               "{\"avs_metadata\": {"
+                       "\"endpoint\":"                 "\"alexa.na.gateway.devices.a2z.com\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h2\","
+                       "\"http_method\":"              "\"POST\","
+                       "\"http_url\":"                 "\"v20160207/events\","
+                       "\"http_no_content_length\":"   "true,"
+                       "\"h2q_oflow_txcr\":"           "true,"
+                       "\"use_auth\":"                 "\"lwa\","
+                       "\"http_auth_header\":"         "\"authorization:\","
+                       "\"http_auth_preamble\":"       "\"Bearer \","
+                       "\"http_multipart_name\":"      "\"metadata\","
+                       "\"http_mime_content_type\":"   "\"application/json; charset=UTF-8\","
+#if 1
+                       "\"http_multipart_ss_in\":"     "true,"
+#endif
+                       "\"rideshare\":"                "\"avs_audio\","
+                       "\"retry\":"                    "\"default\","
+                       "\"tls\":"                      "true,"
+                       "\"tls_trust_store\":"          "\"avs_via_starfield\""
+               "}},"
+               "{\"avs_audio\": {"
+                       "\"endpoint\":"                 "\"alexa.na.gateway.devices.a2z.com\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h2\","
+                       "\"http_method\":"              "\"POST\","
+                       "\"http_url\":"                 "\"v20160207/events\","
+                       "\"http_no_content_length\":"   "true,"
+                       "\"tls\":"                      "true,"
+                       "\"h2q_oflow_txcr\":"           "true,"
+#if 1
+                       "\"http_multipart_ss_in\":"     "true,"
+#endif
+                       "\"use_auth\":"                 "\"lwa\","
+                       "\"http_auth_header\":"         "\"authorization:\","
+                       "\"http_auth_preamble\":"       "\"Bearer \","
+                       "\"http_multipart_name\":"      "\"audio\","
+                       "\"http_mime_content_type\":"   "\"application/octet-stream\","
+                       "\"retry\":"                    "\"default\","
+                       "\"tls_trust_store\":"          "\"avs_via_starfield\""
+               "}}"
+         "]"
+       "}"
+;
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL)
+                       avs_example_start(context);
+               break;
+       case LWS_SYSTATE_POLICY_INVALID:
+               /*
+                * This is a NOP since we used direct set... but in a real
+                * system this could easily change to be done on the heap, then
+                * this would be important
+                */
+               lws_system_blob_destroy(lws_system_get_blob(context,
+                                       LWS_SYSBLOB_TYPE_AUTH,
+                                       1 /* AUTH_IDX_ROOT */));
+               break;
+       }
+
+       return 0;
+}
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams - AVS test [-d<verb>]\n");
+
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.pss_policies_json = default_ss_policy;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+
+#if defined(LWS_SS_USE_SSPC)
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#endif
+
+       /* integrate us with lws system state management when context created */
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       puts(default_ss_policy);
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-avs/year.wav b/minimal-examples/secure-streams/minimal-secure-streams-avs/year.wav
new file mode 100644 (file)
index 0000000..333b057
Binary files /dev/null and b/minimal-examples/secure-streams/minimal-secure-streams-avs/year.wav differ
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-binance/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-binance/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e1f3647
--- /dev/null
@@ -0,0 +1,27 @@
+project(lws-minimal-secure-streams-binance C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-binance)
+set(SRCS main.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_WS 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITHOUT_EXTENSIONS 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-binance/README.md b/minimal-examples/secure-streams/minimal-secure-streams-binance/README.md
new file mode 100644 (file)
index 0000000..5155ddd
--- /dev/null
@@ -0,0 +1,56 @@
+# lws minimal secure streams binance
+
+This is a Secure Streams version of minimal-ws-client-binance.
+
+"policy.json" contains all the information about endpoints, protocols and
+connection validation, tagged by streamtype name.
+
+The example tries to load it from the cwd, it lives in
+./minimal-examples/secure-streams/minimal-secure-streams-binance dir, so
+either run it from there, or copy the policy.json to your cwd.  It's also
+possible to put the policy json in the code as a string and pass that at
+context creation time.
+
+The secure stream object represents a nailed-up connection that outlives any
+single socket connection, and can manage reconnections / retries according to
+the policy to keep the connection nailed up automatically.
+
+Secure Streams provides the same simplified communication api without any
+protocol dependencies.
+
+## build
+
+Lws must have been built with `LWS_ROLE_WS=1`, `LWS_WITH_SECURE_STREAMS=1`, and
+`LWS_WITHOUT_EXTENSIONS=0`
+
+```
+ $ cmake . && make
+```
+
+## Commandline Options
+
+Option|Meaning
+---|---
+-d|Set logging verbosity
+
+## usage
+
+```
+$ ./bin/lws-minimal-ws-client-binance 
+[2021/08/15 06:42:40:8409] U: LWS minimal Secure Streams binance client
+[2021/08/15 06:42:40:8410] N: LWS: 4.2.99-v4.2.0-156-g8f352f65e8, NET CLI SRV H1 H2 WS SS-JSON-POL SSPROX ConMon FLTINJ IPV6-on
+[2021/08/15 06:42:40:8410] N:  ++ [495958|wsi|0|pipe] (1)
+[2021/08/15 06:42:40:8411] N:  ++ [495958|vh|0|netlink] (1)
+[2021/08/15 06:42:40:8433] N:  ++ [495958|vh|1|digicert||-1] (2)
+[2021/08/15 06:42:40:8471] N:  ++ [495958|wsiSScli|0|binance] (1)
+[2021/08/15 06:42:40:8471] N: [495958|wsiSScli|0|binance]: lws_ss_check_next_state_ss: (unset) -> LWSSSCS_CREATING
+[2021/08/15 06:42:40:8472] N: [495958|wsiSScli|0|binance]: lws_ss_check_next_state_ss: LWSSSCS_CREATING -> LWSSSCS_CONNECTING
+[2021/08/15 06:42:40:8472] N:  ++ [495958|wsicli|0|WS/h1/fstream.binance.com/([495958|wsiSScli|0|binance])] (1)
+[2021/08/15 06:42:41:8802] N: [495958|wsiSScli|0|binance]: lws_ss_check_next_state_ss: LWSSSCS_CONNECTING -> LWSSSCS_CONNECTED
+[2021/08/15 06:42:42:8803] N: sul_hz_cb: price: min: 4669185¢, max: 4672159¢, avg: 4670061¢, (53 prices/s)
+[2021/08/15 06:42:42:8803] N: sul_hz_cb: elatency: min: 131ms, max: 292ms, avg: 154ms, (53 msg/s)
+[2021/08/15 06:42:43:8803] N: sul_hz_cb: price: min: 4669646¢, max: 4672159¢, avg: 4669953¢, (34 prices/s)
+[2021/08/15 06:42:43:8803] N: sul_hz_cb: elatency: min: 130ms, max: 149ms, avg: 133ms, (34 msg/s)
+[2021/08/15 06:42:44:8804] N: sul_hz_cb: price: min: 4669455¢, max: 4672159¢, avg: 4669904¢, (26 prices/s)
+...
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-binance/main.c b/minimal-examples/secure-streams/minimal-secure-streams-binance/main.c
new file mode 100644 (file)
index 0000000..8327f3e
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * lws-minimal-secure-streams-binance
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *                         Kutoga <kutoga@user.github.invalid>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a Secure Streams implementation of a client that connects
+ * to binance ws server efficiently.
+ *
+ * Build lws with -DLWS_WITH_SECURE_STREAMS=1 -DLWS_WITHOUT_EXTENSIONS=0
+ *
+ * "policy.json" contains all the information about endpoints, protocols and
+ * connection validation, tagged by streamtype name.
+ *
+ * The example tries to load it from the cwd, it lives
+ * in ./minimal-examples/secure-streams/minimal-secure-streams-binance dir, so
+ * either run it from there, or copy the policy.json to your cwd.  It's also
+ * possible to put the policy json in the code as a string and pass that at
+ * context creation time.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+
+static int interrupted;
+
+typedef struct range {
+       uint64_t                sum;
+       uint64_t                lowest;
+       uint64_t                highest;
+
+       unsigned int            samples;
+} range_t;
+
+typedef struct binance {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+
+       lws_sorted_usec_list_t  sul_hz;      /* 1hz summary dump */
+
+       range_t                 e_lat_range;
+       range_t                 price_range;
+} binance_t;
+
+/****** Part 1 / 3: application data processing */
+
+static void
+range_reset(range_t *r)
+{
+       r->sum = r->highest = 0;
+       r->lowest = 999999999999ull;
+       r->samples = 0;
+}
+
+static uint64_t
+get_us_timeofday(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+
+       return (uint64_t)((lws_usec_t)tv.tv_sec * LWS_US_PER_SEC) +
+                         (uint64_t)tv.tv_usec;
+}
+
+static uint64_t
+pennies(const char *s)
+{
+       uint64_t price = (uint64_t)atoll(s) * 100;
+
+       s = strchr(s, '.');
+
+       if (s && isdigit(s[1]) && isdigit(s[2]))
+               price = price + (uint64_t)((10 * (s[1] - '0')) + (s[2] - '0'));
+
+       return price;
+}
+
+static void
+sul_hz_cb(lws_sorted_usec_list_t *sul)
+{
+       binance_t *bin = lws_container_of(sul, binance_t, sul_hz);
+
+       /*
+        * We are called once a second to dump statistics on the connection
+        */
+
+       lws_sul_schedule(lws_ss_get_context(bin->ss), 0, &bin->sul_hz,
+                        sul_hz_cb, LWS_US_PER_SEC);
+
+       if (bin->price_range.samples)
+               lwsl_notice("%s: price: min: %llu¢, max: %llu¢, avg: %llu¢, "
+                           "(%d prices/s)\n", __func__,
+                           (unsigned long long)bin->price_range.lowest,
+                           (unsigned long long)bin->price_range.highest,
+                           (unsigned long long)(bin->price_range.sum /
+                                                   bin->price_range.samples),
+                           bin->price_range.samples);
+       if (bin->e_lat_range.samples)
+               lwsl_notice("%s: elatency: min: %llums, max: %llums, "
+                           "avg: %llums, (%d msg/s)\n", __func__,
+                           (unsigned long long)bin->e_lat_range.lowest / 1000,
+                           (unsigned long long)bin->e_lat_range.highest / 1000,
+                           (unsigned long long)(bin->e_lat_range.sum /
+                                          bin->e_lat_range.samples) / 1000,
+                           bin->e_lat_range.samples);
+
+       range_reset(&bin->e_lat_range);
+       range_reset(&bin->price_range);
+}
+
+/****** Part 2 / 3: communication */
+
+static lws_ss_state_return_t
+binance_rx(void *userobj, const uint8_t *in, size_t len, int flags)
+{
+       binance_t *bin = (binance_t *)userobj;
+       uint64_t latency_us, now_us;
+       char numbuf[16];
+       uint64_t price;
+       const char *p;
+       size_t alen;
+
+       now_us = (uint64_t)get_us_timeofday();
+
+       p = lws_json_simple_find((const char *)in, len, "\"depthUpdate\"",
+                                &alen);
+       if (!p)
+               return LWSSSSRET_OK;
+
+       p = lws_json_simple_find((const char *)in, len, "\"E\":", &alen);
+       if (!p) {
+               lwsl_err("%s: no E JSON\n", __func__);
+               return LWSSSSRET_OK;
+       }
+
+       lws_strnncpy(numbuf, p, alen, sizeof(numbuf));
+       latency_us = now_us - ((uint64_t)atoll(numbuf) * LWS_US_PER_MS);
+
+       if (latency_us < bin->e_lat_range.lowest)
+               bin->e_lat_range.lowest = latency_us;
+       if (latency_us > bin->e_lat_range.highest)
+               bin->e_lat_range.highest = latency_us;
+
+       bin->e_lat_range.sum += latency_us;
+       bin->e_lat_range.samples++;
+
+       p = lws_json_simple_find((const char *)in, len, "\"a\":[[\"", &alen);
+       if (!p)
+               return LWSSSSRET_OK;
+
+       lws_strnncpy(numbuf, p, alen, sizeof(numbuf));
+       price = pennies(numbuf);
+
+       if (price < bin->price_range.lowest)
+               bin->price_range.lowest = price;
+       if (price > bin->price_range.highest)
+               bin->price_range.highest = price;
+
+       bin->price_range.sum += price;
+       bin->price_range.samples++;
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+binance_state(void *userobj, void *h_src, lws_ss_constate_t state,
+             lws_ss_tx_ordinal_t ack)
+{
+       binance_t *bin = (binance_t *)userobj;
+
+       lwsl_ss_info(bin->ss, "%s (%d), ord 0x%x",
+                    lws_ss_state_name((int)state), state, (unsigned int)ack);
+
+       switch (state) {
+
+       case LWSSSCS_CONNECTED:
+               lws_sul_schedule(lws_ss_get_context(bin->ss), 0, &bin->sul_hz,
+                                sul_hz_cb, LWS_US_PER_SEC);
+               range_reset(&bin->e_lat_range);
+               range_reset(&bin->price_range);
+
+               return LWSSSSRET_OK;
+
+       case LWSSSCS_DISCONNECTED:
+               lws_sul_cancel(&bin->sul_hz);
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static const lws_ss_info_t ssi_binance = {
+       .handle_offset            = offsetof(binance_t, ss),
+       .opaque_user_data_offset  = offsetof(binance_t, opaque_data),
+       .rx                       = binance_rx,
+       .state                    = binance_state,
+       .user_alloc               = sizeof(binance_t),
+       .streamtype               = "binance", /* bind to corresponding policy */
+};
+
+/****** Part 3 / 3: init and event loop */
+
+static const struct lws_extension extensions[] = {
+       {
+               "permessage-deflate", lws_extension_callback_pm_deflate,
+               "permessage-deflate" "; client_no_context_takeover"
+                "; client_max_window_bits"
+       },
+       { NULL, NULL, NULL /* terminator */ }
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *cx;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS minimal Secure Streams binance client\n");
+
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+                      LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
+       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
+       info.fd_limit_per_thread = 1 + 1 + 1;
+       info.extensions = extensions;
+       info.pss_policies_json = "policy.json"; /* literal JSON, or path */
+
+       cx = lws_create_context(&info);
+       if (!cx) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       if (lws_ss_create(cx, 0, &ssi_binance, NULL, NULL, NULL, NULL)) {
+               lwsl_cx_err(cx, "failed to create secure stream");
+               interrupted = 1;
+       }
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(cx, 0);
+
+       lws_context_destroy(cx);
+
+       lwsl_user("Completed\n");
+
+       return 0;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-binance/policy.json b/minimal-examples/secure-streams/minimal-secure-streams-binance/policy.json
new file mode 100644 (file)
index 0000000..1ff4e04
--- /dev/null
@@ -0,0 +1,38 @@
+{
+       "release": "01234567",
+       "product": "myproduct",
+       "schema-version": 1,
+       "retry": [{
+               "default": {
+                       "backoff": [1000, 2000, 3000, 4000, 5000],
+                       "conceal": 65535,
+                       "jitterpc": 20,
+                       "svalidping": 30,
+                       "svalidhup": 35
+               }
+       }],
+       "certs": [{
+               "digicert_global_root": "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQkCAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4="
+       }
+       ],
+               "trust_stores": [{
+                       "name": "digicert",
+                       "stack": ["digicert_global_root"]
+               }
+       ],
+       "s": [
+               { "binance": {
+                       "endpoint":             "fstream.binance.com",
+                       "port":                 443,
+                       "protocol":             "ws",
+                       "http_url":             "/stream?streams=btcusdt@depth@0ms/btcusdt@bookTicker/btcusdt@aggTrade",
+                       "nailed_up":            true,
+                       "ws_prioritize_reads":  true,
+                       "tls":                  true,
+                       "tls_trust_store":      "digicert",
+                       "retry":                "default"
+                       }
+               }
+       ]
+}
+
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-blob/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-blob/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7fc59da
--- /dev/null
@@ -0,0 +1,134 @@
+project(lws-minimal-secure-streams-blob C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-blob)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+require_lws_config(LWS_WITH_GENCRYPTO 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams.c)
+
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32)
+       
+               #
+               # When running in CI, wait for a lease on the resources
+               # before starting this test, so the server does not get
+               # thousands of simultaneous tls connection attempts
+               #
+               # sai-resource holds the lease on the resources until
+               # the time given in seconds or the sai-resource instance
+               # exits, whichever happens first
+               #
+               # If running under Sai, creates a lock test called "res_sspcmin" 
+               #
+               
+               sai_resource(warmcat_conns 1 40 sspcminblob)
+               
+               #
+               # simple test not via proxy
+               #
+       
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME ssblob-warmcat COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams>)
+               else()
+                       add_test(NAME ssblob-warmcat COMMAND lws-minimal-secure-streams)
+               endif()
+
+               set_tests_properties(ssblob-warmcat
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams
+                                    TIMEOUT 40)
+               if (DEFINED ENV{SAI_OVN})
+                       set_tests_properties(ssblob-warmcat PROPERTIES FIXTURES_REQUIRED "res_sspcmin")              
+               endif()
+
+               if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+                       #
+                       # Define test dep to bring up and take down the test
+                       # proxy
+                       #
+
+                       if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                               # uds abstract namespace for linux
+                               set(CTEST_SOCKET_PATH "@ctest-ssblobproxy-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       else()
+                               # filesystem socket for others
+                               set(CTEST_SOCKET_PATH "/tmp/ctest-ssblobproxy-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       endif()
+                       add_test(NAME st_ssblobproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               ssblobproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH} )
+                       set_tests_properties(st_ssblobproxy PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP ssblobproxy TIMEOUT 800)
+
+                       add_test(NAME ki_ssblobproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                               ssblobproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH})
+                       set_tests_properties(ki_ssblobproxy PROPERTIES FIXTURES_CLEANUP ssblobproxy)
+
+                       #
+                       # the client part that will connect to the proxy
+                       #
+
+                       if (VALGRIND)
+                               message("testing via valgrind")
+                               add_test(NAME sspcblob-minimal COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-client> -i +${CTEST_SOCKET_PATH})
+                       else()
+                               add_test(NAME sspcblob-minimal COMMAND lws-minimal-secure-streams-client -i +${CTEST_SOCKET_PATH})
+                       endif()
+                       
+                       set(fixlist "ssblobproxy")
+                       if (DEFINED ENV{SAI_OVN})
+                               list(APPEND fixlist "res_ssblobproxy")
+                       endif()
+                       
+                       set_tests_properties(sspcblob-minimal PROPERTIES
+                               WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams
+                               FIXTURES_REQUIRED "${fixlist}"
+                               TIMEOUT 40)
+
+               endif()
+
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client minimal-secure-streams.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-blob/README.md b/minimal-examples/secure-streams/minimal-secure-streams-blob/README.md
new file mode 100644 (file)
index 0000000..78f0a1b
--- /dev/null
@@ -0,0 +1,67 @@
+# lws minimal secure streams
+
+The application goes to https://warmcat.com and reads index.html there.
+
+It does it using Secure Streams... the main code in minimal-secure-streams.c
+just sets up the context and opens a secure stream of type "mintest".
+
+The handler for state changes and payloads for "mintest" is in ss-myss.c
+
+The information about how a "mintest" stream should connect and the
+protocol it uses is kept separated in policy-database.c
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-f| Force connecting to the wrong endpoint to check backoff retry flow
+-p| Run as proxy server for clients to connect to over unix domain socket
+--force-portal|Force the SS Captive Portal Detection to feel it's behind a portal
+--force-no-internet|Force the SS Captive Portal Detection to feel it can't reach the internet
+--blob|Download a 50MiB blob from warmact.com, using flow control at the proxy
+
+```
+[2019/08/12 07:16:11:0045] USR: LWS minimal secure streams [-d<verbosity>] [-f]
+[2019/08/12 07:16:12:6102] USR: myss_state: LWSSSCS_CREATING, ord 0x0
+[2019/08/12 07:16:12:6107] USR: myss_state: LWSSSCS_POLL, ord 0x0
+[2019/08/12 07:16:12:6117] N: lws_ss_client_connect: connecting h1get warmcat.com /
+[2019/08/12 07:16:12:6118] USR: myss_state: LWSSSCS_CONNECTING, ord 0x0
+[2019/08/12 07:16:13:4171] USR: myss_state: LWSSSCS_CONNECTED, ord 0x0
+[2019/08/12 07:16:13:4222] USR: myss_rx: len 1024, flags: 1
+[2019/08/12 07:16:13:4243] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4244] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4244] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4245] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4246] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4247] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4252] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4264] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4265] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4266] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4267] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4268] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4268] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4269] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4270] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4278] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4279] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4280] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4281] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4282] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4283] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4283] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4284] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4287] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4288] USR: myss_rx: len 947, flags: 0
+[2019/08/12 07:16:13:4293] USR: myss_rx: len 0, flags: 2
+[2019/08/12 07:16:13:4399] USR: myss_state: LWSSSCS_DISCONNECTED, ord 0x0
+[2019/08/12 07:16:13:4761] USR: myss_state: LWSSSCS_DESTROYING, ord 0x0
+[2019/08/12 07:16:13:4781] USR: Completed: OK
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-blob/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams-blob/minimal-secure-streams.c
new file mode 100644 (file)
index 0000000..8574e2e
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ * lws-minimal-secure-streams
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates a minimal http client using secure streams api.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.
+ *
+ * This example is built two different ways from the same source... one includes
+ * the policy everything needed to fulfil the stream directly.  The other -client
+ * variant has no policy itself and some other minor init changes, and connects
+ * to the -proxy example to actually get the connection done.
+ *
+ * In the -client build case, the example does not even init the tls libraries
+ * since the proxy part will take care of all that.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+// #define FORCE_OS_TRUST_STORE
+
+/*
+ * uncomment to force network traffic through 127.0.0.1:1080
+ *
+ * On your local machine, you can run a SOCKS5 proxy like this
+ *
+ * $ ssh -N -D 0.0.0.0:1080 localhost -v
+ *
+ * If enabled, this also fetches a remote policy that also
+ * specifies that all traffic should go through the remote
+ * proxy.
+ */
+// #define VIA_LOCALHOST_SOCKS
+
+static int interrupted, bad = 1, force_cpd_fail_portal,
+          force_cpd_fail_no_internet, test_respmap, test_blob, test_ots;
+static unsigned int timeout_ms = 3000;
+static lws_state_notify_link_t nl;
+
+/*
+ * If the -proxy app is fulfilling our connection, then we don't need to have
+ * the policy in the client.
+ *
+ * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over
+ * a Unix Domain Socket.  To test that, you need to separately run the
+ * ./lws-minimal-secure-streams-proxy test app on the same machine.
+ */
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+#if defined(VIA_LOCALHOST_SOCKS)
+         "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+#endif
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+#if !defined(FORCE_OS_TRUST_STORE)
+               "{\"isrg_root_x1\": \""
+"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="
+         "\"}"
+#endif
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+#if !defined(FORCE_OS_TRUST_STORE)
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+#endif
+         "],"
+         "\"s\": ["
+               /*
+                * "fetch_policy" decides from where the real policy
+                * will be fetched, if present.  Otherwise the initial
+                * policy is treated as the whole, hardcoded, policy.
+                */
+               "{\"fetch_policy\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+#if defined(VIA_LOCALHOST_SOCKS)
+                       "\"http_url\":"         "\"policy/minimal-proxy-socks.json\","
+#else
+                       "\"http_url\":"         "\"policy/minimal-proxy-v4.2-v2.json\","
+#endif
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+#if !defined(FORCE_OS_TRUST_STORE)
+                       "\"tls_trust_store\":"  "\"le_via_isrg\","
+#endif
+                       "\"retry\":"            "\"default\""
+               "}},{"
+                       /*
+                        * "captive_portal_detect" describes
+                        * what to do in order to check if the path to
+                        * the Internet is being interrupted by a
+                        * captive portal.  If there's a larger policy
+                        * fetched from elsewhere, it should also include
+                        * this since it needs to be done at least after
+                        * every DHCP acquisition
+                        */
+                   "\"captive_portal_detect\": {"
+                        "\"endpoint\": \"connectivitycheck.android.com\","
+                       "\"http_url\": \"generate_204\","
+                       "\"port\": 80,"
+                        "\"protocol\": \"h1\","
+                        "\"http_method\": \"GET\","
+                        "\"opportunistic\": true,"
+                        "\"http_expect\": 204,"
+                       "\"http_fail_redirect\": true"
+                "}}"
+       "]}"
+;
+
+#endif
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+       size_t                          amt;
+
+       struct lws_genhash_ctx          hash_ctx;
+} myss_t;
+
+#if !defined(LWS_SS_USE_SSPC)
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+#endif
+
+/* secure streams payload interface */
+
+static const uint8_t expected_blob_hash[] = {
+       0xed, 0x57, 0x20, 0xc1, 0x68, 0x30, 0x81, 0x0e,
+       0x58, 0x29, 0xdf, 0xb9, 0xb6, 0x6c, 0x96, 0xb2,
+       0xe2, 0x4e, 0xfc, 0x4f, 0x93, 0xaa, 0x5e, 0x38,
+       0xc7, 0xff, 0x41, 0x50, 0xd3, 0x1c, 0xfb, 0xbf
+};
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+       const char *md_srv = "not set", *md_test = "not set";
+       size_t md_srv_len = 7, md_test_len = 7;
+
+       if (flags & LWSSS_FLAG_PERF_JSON)
+               return LWSSSSRET_OK;
+
+       if (test_blob) {
+
+               if (flags & LWSSS_FLAG_SOM) {
+                       if (lws_genhash_init(&m->hash_ctx, LWS_GENHASH_TYPE_SHA256))
+                               lwsl_err("%s: hash init failed\n", __func__);
+                       m->amt = 0;
+               }
+
+               if (lws_genhash_update(&m->hash_ctx, buf, len))
+                       lwsl_err("%s: hash failed\n", __func__);
+
+               if ((m->amt + len) / 102400 != (m->amt / 102400)) {
+
+                       lwsl_user("%s: blob test: rx %uKiB\n", __func__,
+                                       (unsigned int)((m->amt + len) / 1024));
+                       /*
+                        * Let's make it hard for client to keep up with onward
+                        * server, delay 50ms after every 100K received, so we
+                        * are forcing the flow control action at the proxy
+                        */
+                       usleep(50000);
+               }
+
+               m->amt += len;
+
+               if (flags & LWSSS_FLAG_EOM) {
+                       uint8_t digest[32];
+                       lws_genhash_destroy(&m->hash_ctx, digest);
+
+                       if (!memcmp(expected_blob_hash, digest, 32)) {
+                               lwsl_user("%s: SHA256 match\n", __func__);
+                               bad = 0;
+                       }
+
+                       interrupted = 1;
+               }
+
+               return LWSSSSRET_OK;
+       }
+
+       lws_ss_get_metadata(m->ss, "srv", (const void **)&md_srv, &md_srv_len);
+       lws_ss_get_metadata(m->ss, "test", (const void **)&md_test, &md_test_len);
+
+       lwsl_user("%s: len %d, flags: %d, srv: %.*s, test: %.*s\n", __func__,
+                 (int)len, flags, (int)md_srv_len, md_srv,
+                 (int)md_test_len, md_test);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       //myss_t *m = (myss_t *)userobj;
+
+       /* in this example, we don't send stuff */
+
+       return LWSSSSRET_TX_DONT_SEND;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %s (%d), ord 0x%x\n", __func__,
+                 lws_ss_state_name((int)state), state, (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_CONNECTING:
+               lws_ss_start_timeout(m->ss, timeout_ms);
+
+               if (!test_blob) {
+                       if (lws_ss_set_metadata(m->ss, "uptag", "myuptag123", 10))
+                               /* can fail, eg due to OOM, retry later if so */
+                               return LWSSSSRET_DISCONNECT_ME;
+
+                       if (lws_ss_set_metadata(m->ss, "ctype", "myctype", 7))
+                               /* can fail, eg due to OOM, retry later if so */
+                               return LWSSSSRET_DISCONNECT_ME;
+               }
+               break;
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               bad = 2;
+               break;
+
+       case LWSSSCS_QOS_ACK_REMOTE:
+               lwsl_notice("%s: LWSSSCS_QOS_ACK_REMOTE\n", __func__);
+               break;
+
+       case LWSSSCS_TIMEOUT:
+               lwsl_notice("%s: LWSSSCS_TIMEOUT\n", __func__);
+               /* if we're out of time */
+               interrupted = 1;
+               bad = 3;
+               break;
+
+       case LWSSSCS_USER_BASE:
+               lwsl_notice("%s: LWSSSCS_USER_BASE\n", __func__);
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+#if !defined(LWS_SS_USE_SSPC)
+
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+#endif
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+
+#if !defined(LWS_SS_USE_SSPC)
+
+       /*
+        * The proxy takes responsibility for this stuff if we get things
+        * done through that
+        */
+
+       case LWS_SYSTATE_INITIALIZED: /* overlay on the hardcoded policy */
+       case LWS_SYSTATE_POLICY_VALID: /* overlay on the loaded policy */
+
+               if (target != current)
+                       break;
+
+               if (force_cpd_fail_portal)
+
+                       /* this makes it look like we're behind a captive portal
+                        * because the overriden address does a redirect */
+
+                       lws_ss_policy_overlay(context,
+                                     "{\"s\": [{\"captive_portal_detect\": {"
+                                        "\"endpoint\": \"google.com\","
+                                        "\"http_url\": \"/\","
+                                        "\"port\": 80"
+                                     "}}]}");
+
+               if (force_cpd_fail_no_internet)
+
+                       /* this looks like no internet, because the overridden
+                        * port doesn't have anything that will connect to us */
+
+                       lws_ss_policy_overlay(context,
+                                     "{\"s\": [{\"captive_portal_detect\": {"
+                                        "\"endpoint\": \"warmcat.com\","
+                                        "\"http_url\": \"/\","
+                                        "\"port\": 999"
+                                     "}}]}");
+               break;
+
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+
+#endif
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+                       lws_ss_info_t ssi;
+
+                       /* We're making an outgoing secure stream ourselves */
+
+                       memset(&ssi, 0, sizeof(ssi));
+                       ssi.handle_offset = offsetof(myss_t, ss);
+                       ssi.opaque_user_data_offset = offsetof(myss_t,
+                                                              opaque_data);
+                       ssi.rx = myss_rx;
+                       ssi.tx = myss_tx;
+                       ssi.state = myss_state;
+                       ssi.user_alloc = sizeof(myss_t);
+                       ssi.streamtype = test_ots ? "mintest-ots" :
+                                       (test_blob ? "bulkproxflow" :
+                                        (test_respmap ? "respmap" : "mintest"));
+
+                       if (lws_ss_create(context, 0, &ssi, NULL, NULL,
+                                         NULL, NULL)) {
+                               lwsl_err("%s: failed to create secure stream\n",
+                                        __func__);
+                               return -1;
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+#if defined(LWS_WITH_SYS_METRICS)
+
+static int
+my_metric_report(lws_metric_pub_t *mp)
+{
+       lws_metric_bucket_t *sub = mp->u.hist.head;
+       char buf[192];
+
+       do {
+               if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
+                       lwsl_user("%s: %s\n", __func__, buf);
+       } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
+
+       /* 0 = leave metric to accumulate, 1 = reset the metric */
+
+       return 1;
+}
+
+static const lws_system_ops_t system_ops = {
+       .metric_report = my_metric_report,
+};
+
+#endif
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0, expected = 0;
+       const char *p;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams test client [-d<verb>]\n");
+
+       /* these options are mutually exclusive if given */
+
+       if (lws_cmdline_option(argc, argv, "--force-portal"))
+               force_cpd_fail_portal = 1;
+
+       if (lws_cmdline_option(argc, argv, "--force-no-internet"))
+               force_cpd_fail_no_internet = 1;
+
+       if (lws_cmdline_option(argc, argv, "--respmap"))
+               test_respmap = 1;
+
+       if (lws_cmdline_option(argc, argv, "--ots"))
+               /*
+                * Use a streamtype that relies on the OS trust store for
+                * validation
+                */
+               test_ots = 1;
+
+       if ((p = lws_cmdline_option(argc, argv, "--timeout_ms")))
+               timeout_ms = (unsigned int)atoi(p);
+
+       if (lws_cmdline_option(argc, argv, "--blob")) {
+               test_blob = 1;
+               if (timeout_ms == 3000)
+                       /*
+                        * Don't use default 3s, we're going to be a lot
+                        * slower
+                        */
+                       timeout_ms = 60000;
+       }
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#else
+       info.pss_policies_json = default_ss_policy;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+#if defined(LWS_WITH_MBEDTLS)
+
+       /* uncomment to force mbedtls to load a system trust store like
+        * openssl does
+        *
+        * info.mbedtls_client_preload_filepath =
+        *              "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem";
+        */
+#endif
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+
+#if defined(LWS_WITH_SYS_METRICS)
+       info.system_ops = &system_ops;
+       info.metrics_prefix = "ssmex";
+#endif
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               goto bail;
+       }
+
+#if !defined(LWS_SS_USE_SSPC)
+       /*
+        * If we're being a proxied client, the proxy does all this
+        */
+
+       /*
+        * Set the related lws_system blobs
+        *
+        * ...direct_set() sets a pointer, so the thing pointed to has to have
+        * a suitable lifetime, eg, something that already exists on the heap or
+        * a const string in .rodata like this
+        */
+
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_SERIAL, 0),
+                                  (const uint8_t *)"SN12345678", 10);
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION, 0),
+                                  (const uint8_t *)"v0.01", 5);
+
+       /*
+        * ..._heap_append() appends to a buflist kind of arrangement on heap,
+        * just one block is fine, otherwise it will concatenate the fragments
+        * in the order they were appended (and take care of freeing them at
+        * context destroy time). ..._heap_empty() is also available to remove
+        * everything that was already allocated.
+        *
+        * Here we use _heap_append() just so it's tested as well as direct set.
+        */
+
+       lws_system_blob_heap_append(lws_system_get_blob(context,
+                                   LWS_SYSBLOB_TYPE_DEVICE_TYPE, 0),
+                                  (const uint8_t *)"spacerocket", 11);
+#endif
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+bail:
+       if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
+               expected = atoi(p);
+
+       if (bad == expected) {
+               lwsl_user("Completed: OK (seen expected %d)\n", expected);
+               return 0;
+       } else
+               lwsl_err("Completed: failed: exit %d, expected %d\n", bad, expected);
+
+       return 1;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-client-tx/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-client-tx/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1a943b9
--- /dev/null
@@ -0,0 +1,76 @@
+project(lws-minimal-secure-streams-client-tx C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-client-tx)
+set(SRCS minimal-secure-streams-client-tx.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_PROXY_API 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+       add_compile_options(-DLWS_SS_USE_SSPC)
+       
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32)
+
+               #
+               # Define test dep to bring up and take down the test
+               # proxy
+               #
+
+               if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                       # uds abstract namespace for linux
+                       set(CTEST_SOCKET_PATH "@ctest-sspctx-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               else()
+                       # filesystem socket for others
+                       set(CTEST_SOCKET_PATH "/tmp/ctest-sspctx-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               endif()
+               add_test(NAME st_ssproxyctx COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                       ssproxyctx $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH} )
+               set_tests_properties(st_ssproxyctx PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP ssproxyctx TIMEOUT 800)
+
+               add_test(NAME ki_ssproxyctx COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                       ssproxyctx $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH})
+               set_tests_properties(ki_ssproxyctx PROPERTIES FIXTURES_CLEANUP ssproxyctx)
+
+               #
+               # the client part that will connect to the proxy
+               #
+
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME sspc-minimaltx COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-client-tx> -i +${CTEST_SOCKET_PATH})
+               else()
+                       add_test(NAME sspc-minimaltx COMMAND lws-minimal-secure-streams-client-tx -i +${CTEST_SOCKET_PATH})
+               endif()
+               set_tests_properties(sspc-minimaltx PROPERTIES
+                       WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-client-tx
+                       FIXTURES_REQUIRED "ssproxyctx"
+                       TIMEOUT 40)
+
+       endif()
+       
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-client-tx/README.md b/minimal-examples/secure-streams/minimal-secure-streams-client-tx/README.md
new file mode 100644 (file)
index 0000000..19b74c6
--- /dev/null
@@ -0,0 +1,40 @@
+# lws minimal secure streams client tx
+
+The application connects to the secure stream proxy, and opens a streamtype
+"spam"... this is a websocket connection to libwebsockets.org.
+
+It then issues 100 x ws messages at 20Hz and exits.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-f| Force connecting to the wrong endpoint to check backoff retry flow
+-p| Run as proxy server for clients to connect to over unix domain socket
+
+```
+[2021/02/19 11:25:20:1396] U: LWS secure streams client TX [-d<verb>]
+[2021/02/19 11:25:20:1756] N: LWS: 4.1.99-v4.1.0-280-ga329c51485, loglevel 1031
+[2021/02/19 11:25:20:1761] N: NET CLI SRV H1 H2 WS SS-JSON-POL SSPROX IPV6-on
+[2021/02/19 11:25:20:2055] N:  ++ [1100944|wsi|0|pipe] (1)
+[2021/02/19 11:25:20:2133] N:  ++ [1100944|vh|0|netlink] (1)
+[2021/02/19 11:25:20:3647] N:  ++ [1100944|vh|1|default] (2)
+[2021/02/19 11:25:20:8590] N:  ++ [1100944|SSPcli|0|spam] (1)
+[2021/02/19 11:25:20:8810] N:  ++ [1100944|wsiSSPcli|0|RAW/raw-skt/+@proxy.ss.lws/([1100944|SSPcli|0|spam])] (1)
+[2021/02/19 11:25:20:9103] N: lws_sspc_sul_retry_cb: [1100944|wsiSSPcli|0|RAW/raw-skt/+@proxy.ss.lws/([1100944|SSPcli|0|spam|default])]
+[2021/02/19 11:25:20:9795] U: myss_state: LWSSSCS_CREATING, ord 0x0
+[2021/02/19 11:25:20:9869] U: myss_state: LWSSSCS_CONNECTING, ord 0x0
+[2021/02/19 11:25:21:0791] U: myss_state: LWSSSCS_CONNECTED, ord 0x0
+[2021/02/19 11:25:21:1444] U: myss_tx: sending pkt 1
+[2021/02/19 11:25:21:1945] U: myss_tx: sending pkt 2
+[2021/02/19 11:25:21:2459] U: myss_tx: sending pkt 3
+[2021/02/19 11:25:21:2971] U: myss_tx: sending pkt 4
+...
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-client-tx/minimal-secure-streams-client-tx.c b/minimal-examples/secure-streams/minimal-secure-streams-client-tx/minimal-secure-streams-client-tx.c
new file mode 100644 (file)
index 0000000..0899010
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * lws-minimal-secure-streams-tx
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates proxied mass tx from secure streams, this example is a
+ * client that has no policy of its own, but gets stuff done via the ss proxy.
+ *
+ * It opens a websocket stream and fires 100 x small 80-byte payloads on it
+ * at 20Hz (50ms)
+ */
+
+#define LWS_SS_USE_SSPC
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+#define PKT_SIZE 80
+#define RATE_US 50000
+
+static int interrupted, bad = 1, reads = 100;
+
+typedef struct myss {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t  sul;
+
+       int                     count;
+       char                    due;
+} myss_t;
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       /* this example isn't interested in rx */
+       return LWSSSSRET_OK;
+}
+
+static void
+txcb(struct lws_sorted_usec_list *sul)
+{
+       myss_t *m = lws_container_of(sul, myss_t, sul);
+
+       /*
+        * We want to do 100 of these ws messages, and then exit, so we can run
+        * this as a pass / fail test.
+        */
+
+       if (m->count == reads) {
+               interrupted = 1;
+               bad = 0;
+       } else {
+               m->due = 1;
+               lws_ss_request_tx(m->ss);
+       }
+
+       lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, txcb, RATE_US);
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       if (!m->due)
+               return LWSSSSRET_TX_DONT_SEND;
+
+       m->due = 0;
+
+       if (lws_get_random(lws_ss_get_context(m->ss), buf, PKT_SIZE) != PKT_SIZE)
+               return LWSSSSRET_TX_DONT_SEND;
+
+       *len = PKT_SIZE;
+       *flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
+
+       m->count++;
+
+       lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, txcb, RATE_US);
+
+       lwsl_user("%s: sending pkt %d\n", __func__, m->count);
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+               lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+       struct lws_context *context = lws_ss_get_context(m->ss);
+
+       lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_CONNECTED:
+               lws_sul_schedule(context, 0, &m->sul, txcb, RATE_US);
+               break;
+       case LWSSSCS_DISCONNECTED:
+               lws_sul_cancel(&m->sul);
+               break;
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static const lws_ss_info_t ssi = {
+       .handle_offset                  = offsetof(myss_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_t, opaque_data),
+       .rx                             = myss_rx,
+       .tx                             = myss_tx,
+       .state                          = myss_state,
+       .user_alloc                     = sizeof(myss_t),
+       .streamtype                     = "spam"
+};
+
+int main(int argc, const char **argv)
+{
+       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       if ((p = lws_cmdline_option(argc, argv, "-c")))
+               reads = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS secure streams client TX [-d<verb>]\n");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.protocols = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               goto bail1;
+       }
+
+       if (lws_ss_create(context, 0, &ssi, NULL, NULL, NULL, NULL)) {
+               lwsl_err("%s: create secure stream failed\n", __func__);
+               goto bail;
+       }
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+bail:
+       lws_context_destroy(context);
+
+bail1:
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-cpp/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-cpp/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1f26c57
--- /dev/null
@@ -0,0 +1,50 @@
+project(lws-minimal-secure-streams-cpp CXX)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-cpp)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_MBEDTLS 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_CPP 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+
+if (requirements)
+       add_executable(${SAMP} main.cxx)
+
+       if (LWS_CTEST_INTERNET_AVAILABLE)
+               add_test(NAME sscpp-warmcat COMMAND lws-minimal-secure-streams-cpp)
+               set_tests_properties(sscpp-warmcat
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-cpp
+                                    TIMEOUT 20)
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client main.cxx)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-cpp/main.cxx b/minimal-examples/secure-streams/minimal-secure-streams-cpp/main.cxx
new file mode 100644 (file)
index 0000000..e6f051f
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * lws-minimal-secure-streams-cpp
+ *
+ * Written in 2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a minimal http client using secure streams C++ api to
+ * fetch files over https to the local filesystem
+ */
+
+#include <libwebsockets.hxx>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted, bad = 1, concurrent = 1, completed;
+
+static int
+lss_completion(lss *lss, lws_ss_constate_t state, void *arg)
+{
+       lssFile *lf = (lssFile *)lss;
+
+       if (state == LWSSSCS_QOS_ACK_REMOTE) {
+               lwsl_notice("%s: %s: len %llu, done OK %dms\n", __func__,
+                           lf->path.c_str(), (unsigned long long)lf->rxlen,
+                           (int)((lws_now_usecs() - lf->us_start) / 1000));
+       } else
+               lwsl_notice("%s: %s: failed\n", __func__, lf->path.c_str());
+
+       if (++completed == concurrent) {
+               interrupted = 1;
+               bad = 0;
+       }
+
+       return 0;
+}
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       if ((p = lws_cmdline_option(argc, argv, "-c")))
+               concurrent = atoi(p);
+
+       if (concurrent > 12)
+               concurrent = 12;
+
+       lwsl_user("LWS secure streams cpp test client "
+                       "[-d<verb>] [-c<concurrent>]\n");
+
+       info.fd_limit_per_thread = 1 + 12 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       try {
+
+               for (int n = 0; n < concurrent; n++) {
+                       std::string url, filepath;
+
+                       url = "https://warmcat.com/test-";
+                       url += ('a' + n);
+                       url += ".bin";
+
+                       filepath = "/tmp/test-";
+                       filepath += ('a' + n);
+                       filepath += ".bin";
+
+                       new lssFile(context, url, filepath, lss_completion, 0);
+               }
+       } catch (std::exception &e) {
+               lwsl_err("%s: failed to create ss: %s\n", __func__, e.what());
+               interrupted = 1;
+       }
+
+       /* the event loop */
+
+       while (!interrupted && lws_service(context, 0) >= 0)
+               ;
+
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-hugeurl/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-hugeurl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e0ac200
--- /dev/null
@@ -0,0 +1,133 @@
+project(lws-minimal-secure-streams-hugeurl C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-hugeurl)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams.c)
+
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32)
+       
+               #
+               # When running in CI, wait for a lease on the resources
+               # before starting this test, so the server does not get
+               # thousands of simultaneous tls connection attempts
+               #
+               # sai-resource holds the lease on the resources until
+               # the time given in seconds or the sai-resource instance
+               # exits, whichever happens first
+               #
+               # If running under Sai, creates a lock test called "res_sspcmin_hurl" 
+               #
+               
+               sai_resource(warmcat_conns 1 40 sspcmin_hurl)
+               
+               #
+               # simple test not via proxy
+               #
+       
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME ss-warmcat-hurl COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-hugeurl>)
+               else()
+                       add_test(NAME ss-warmcat-hurl COMMAND lws-minimal-secure-streams-hugeurl)
+               endif()
+
+               set_tests_properties(ss-warmcat-hurl
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams
+                                    TIMEOUT 20)
+               if (DEFINED ENV{SAI_OVN})
+                       set_tests_properties(ss-warmcat-hurl PROPERTIES FIXTURES_REQUIRED "res_sspcmin_hurl")                
+               endif()
+
+               if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+                       #
+                       # Define test dep to bring up and take down the test
+                       # proxy
+                       #
+
+                       if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                               # uds abstract namespace for linux
+                               set(CTEST_SOCKET_PATH "@ctest-ssp-hurl-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       else()
+                               # filesystem socket for others
+                               set(CTEST_SOCKET_PATH "/tmp/ctest-ssp-hurl-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       endif()
+                       add_test(NAME st_ssproxy-hurl COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               ssproxy-hurl $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH} )
+                       set_tests_properties(st_ssproxy-hurl PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP ssproxy-hurl TIMEOUT 800)
+
+                       add_test(NAME ki_ssproxy-hurl COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                               ssproxy-hurl $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH})
+                       set_tests_properties(ki_ssproxy-hurl PROPERTIES FIXTURES_CLEANUP ssproxy-hurl)
+
+                       #
+                       # the client part that will connect to the proxy
+                       #
+
+                       if (VALGRIND)
+                               message("testing via valgrind")
+                               add_test(NAME sspc-minimal-hurl COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-client> -i +${CTEST_SOCKET_PATH})
+                       else()
+                               add_test(NAME sspc-minimal-hurl COMMAND lws-minimal-secure-streams-client -i +${CTEST_SOCKET_PATH})
+                       endif()
+                       
+                       set(fixlist "ssproxy-hurl")
+                       if (DEFINED ENV{SAI_OVN})
+                               list(APPEND fixlist "res_ssproxy-hurl")
+                       endif()
+                       
+                       set_tests_properties(sspc-minimal-hurl PROPERTIES
+                               WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams
+                               FIXTURES_REQUIRED "${fixlist}"
+                               TIMEOUT 40)
+
+               endif()
+
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client minimal-secure-streams.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-hugeurl/README.md b/minimal-examples/secure-streams/minimal-secure-streams-hugeurl/README.md
new file mode 100644 (file)
index 0000000..41c99b2
--- /dev/null
@@ -0,0 +1,72 @@
+# lws minimal secure streams hugeurl
+
+This application sends a huge url to httpbin.org, by default 4000 bytes in
+a urlarg ?x=xxxxxx..., where the argument is a random string in hex.
+
+Notice that httpbin.org has its own limit for urlsize, of 4094 bytes for
+the entire URL.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-h <hugeurl size>|Default 4000
+--h1|Force http/1.1 instead of default h2
+
+```
+[2021/03/02 16:38:00:2662] U: LWS secure streams hugeurl test client [-d<verb>][-h <urlarg len>]
+[2021/03/02 16:38:00:2662] U: main: huge argument size: 4000 bytes
+[2021/03/02 16:38:00:2662] N: LWS: 4.1.99-v4.1.0-294-g85c1fe07a7, loglevel 1031
+[2021/03/02 16:38:00:2662] N: NET CLI SRV H1 H2 WS SS-JSON-POL SSPROX IPV6-on
+[2021/03/02 16:38:00:2663] N:  ++ [1903157|wsi|0|pipe] (1)
+[2021/03/02 16:38:00:2663] N:  ++ [1903157|vh|0|netlink] (1)
+[2021/03/02 16:38:00:2677] N:  ++ [1903157|vh|1|_ss_default||-1] (2)
+[2021/03/02 16:38:00:2736] N:  ++ [1903157|vh|2|arca1||-1] (3)
+[2021/03/02 16:38:00:2798] N:  ++ [1903157|wsiSScli|0|captive_portal_detect] (1)
+[2021/03/02 16:38:00:2798] N: lws_ss_check_next_state: [1903157|wsiSScli|0|captive_portal_detect]: (unset) -> LWSSSCS_CREATING
+[2021/03/02 16:38:00:2798] N: lws_ss_check_next_state: [1903157|wsiSScli|0|captive_portal_detect]: LWSSSCS_CREATING -> LWSSSCS_POLL
+[2021/03/02 16:38:00:2800] N: lws_ss_check_next_state: [1903157|wsiSScli|0|captive_portal_detect]: LWSSSCS_POLL -> LWSSSCS_CONNECTING
+[2021/03/02 16:38:00:2801] N:  ++ [1903157|wsicli|0|GET/h1/connectivitycheck.android.com/([1903157|wsiSScli|0|captive_portal_det] (1)
+[2021/03/02 16:38:00:3227] W: lws_metrics_hist_bump_priv_tagged: 'ss="captive_portal_detect",http_resp="204"'
+[2021/03/02 16:38:00:3227] N: lws_ss_check_next_state: [1903157|wsiSScli|0|captive_portal_detect|204]: LWSSSCS_CONNECTING -> LWSSSCS_CONNECTED
+[2021/03/02 16:38:00:3227] N: lws_ss_check_next_state: [1903157|wsiSScli|0|captive_portal_detect|204]: LWSSSCS_CONNECTED -> LWSSSCS_QOS_ACK_REMOTE
+[2021/03/02 16:38:00:3227] N: lws_system_cpd_set: setting CPD result OK
+[2021/03/02 16:38:00:3227] N: lws_ss_check_next_state: [1903157|wsiSScli|0|captive_portal_detect|204]: LWSSSCS_QOS_ACK_REMOTE -> LWSSSCS_DISCONNECTED
+[2021/03/02 16:38:00:3228] N: lws_ss_check_next_state: [1903157|wsiSScli|0|captive_portal_detect|204]: LWSSSCS_DISCONNECTED -> LWSSSCS_DESTROYING
+[2021/03/02 16:38:00:3228] N:  -- [1903157|wsiSScli|0|captive_portal_detect|204] (0) 42.928ms
+[2021/03/02 16:38:00:3231] N:  -- [1903157|wsicli|0|GET/h1/connectivitycheck.android.com/([1903157|wsiSScli|0|captive_portal_det] (0) 42.994ms
+[2021/03/02 16:38:00:3853] N:  ++ [1903157|wsiSScli|1|httpbin_anything] (1)
+[2021/03/02 16:38:00:3854] N: lws_ss_check_next_state: [1903157|wsiSScli|1|httpbin_anything]: (unset) -> LWSSSCS_CREATING
+[2021/03/02 16:38:00:3854] U: myss_state: LWSSSCS_CREATING (1), ord 0x0
+[2021/03/02 16:38:00:3855] N: lws_ss_check_next_state: [1903157|wsiSScli|1|httpbin_anything]: LWSSSCS_CREATING -> LWSSSCS_CONNECTING
+[2021/03/02 16:38:00:3855] U: myss_state: LWSSSCS_CONNECTING (6), ord 0x0
+[2021/03/02 16:38:00:3855] N:  ++ [1903157|wsicli|1|GET/h1/httpbin.org/([1903157|wsiSScli|1|httpbin_anything])] (1)
+[2021/03/02 16:38:00:6855] N:  ++ [1903157|mux|0|h2_sid1_(1903157|wsicli|1)] (1)
+[2021/03/02 16:38:00:6857] N: secstream_h1: [1903157|wsiSScli|1|httpbin_anything] no handle / tx
+[2021/03/02 16:38:00:7904] W: lws_metrics_hist_bump_priv_tagged: 'ss="httpbin_anything",http_resp="200"'
+[2021/03/02 16:38:00:7904] N: lws_ss_check_next_state: [1903157|wsiSScli|1|httpbin_anything|200]: LWSSSCS_CONNECTING -> LWSSSCS_CONNECTED
+[2021/03/02 16:38:00:7904] U: myss_state: LWSSSCS_CONNECTED (5), ord 0x0
+[2021/03/02 16:38:00:7907] U: myss_rx: return hugeurl len 4000 matches OK
+[2021/03/02 16:38:00:7907] N: lws_ss_check_next_state: [1903157|wsiSScli|1|httpbin_anything|200]: LWSSSCS_CONNECTED -> LWSSSCS_QOS_ACK_REMOTE
+[2021/03/02 16:38:00:7907] U: myss_state: LWSSSCS_QOS_ACK_REMOTE (10), ord 0x0
+[2021/03/02 16:38:00:7908] N: myss_state: LWSSSCS_QOS_ACK_REMOTE
+[2021/03/02 16:38:00:7908] N:  -- [1903157|wsi|0|pipe] (0) 524.500ms
+[2021/03/02 16:38:00:7908] N:  -- [1903157|mux|0|h2_sid1_(1903157|wsicli|1)] (0) 105.284ms
+[2021/03/02 16:38:00:7912] N:  -- [1903157|vh|2|arca1||-1] (2) 517.621ms
+[2021/03/02 16:38:00:7912] N:  -- [1903157|wsicli|1|GET/h1/httpbin.org/([1903157|wsiSScli|1|httpbin_anything|arca1|h2|h2])] (0) 405.690ms
+[2021/03/02 16:38:00:7912] N:  -- [1903157|vh|0|netlink] (1) 524.918ms
+[2021/03/02 16:38:00:7913] N: lws_ss_check_next_state: [1903157|wsiSScli|1|httpbin_anything|200]: LWSSSCS_QOS_ACK_REMOTE -> LWSSSCS_DISCONNECTED
+[2021/03/02 16:38:00:7913] U: myss_state: LWSSSCS_DISCONNECTED (2), ord 0x0
+[2021/03/02 16:38:00:7913] N: lws_ss_check_next_state: [1903157|wsiSScli|1|httpbin_anything|200]: LWSSSCS_DISCONNECTED -> LWSSSCS_DESTROYING
+[2021/03/02 16:38:00:7913] U: myss_state: LWSSSCS_DESTROYING (7), ord 0x0
+[2021/03/02 16:38:00:7913] N:  -- [1903157|wsiSScli|1|httpbin_anything|200] (0) 405.986ms
+[2021/03/02 16:38:00:7925] N:  -- [1903157|vh|1|_ss_default||-1] (0) 524.844ms
+[2021/03/02 16:38:00:7926] U: Completed: OK
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-hugeurl/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams-hugeurl/minimal-secure-streams.c
new file mode 100644 (file)
index 0000000..67e4f91
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * lws-minimal-secure-streams-hugeurl
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This checks huge url operations via httpbin.org
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static unsigned int timeout_ms = 3000;
+static int interrupted, bad = 1, h1;
+static lws_state_notify_link_t nl;
+static size_t hugeurl_size = 4000;
+static char *hugeurl, *check;
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+#if defined(VIA_LOCALHOST_SOCKS)
+         "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+#endif
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+               "{\"amazon_root_ca_1\": \""
+                 "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0"
+                 "BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQ"
+                 "QDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExN"
+                 "zAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcG"
+                 "A1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggE"
+                 "PADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrA"
+                 "IthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdY"
+                 "Z6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH"
+                 "3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0"
+                 "tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyz"
+                 "iKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIq"
+                 "g0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw"
+                 "HQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwU"
+                 "AA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9r"
+                 "bxenDIU5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/m"
+                 "sv0tadQ1wUsN+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96L"
+                 "XFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bld"
+                 "ZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8o"
+                 "b2xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5"
+               "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"arca1\","
+                       "\"stack\": ["
+                               "\"amazon_root_ca_1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": [{"
+
+               "\"httpbin_anything_h1\": {"
+                       "\"endpoint\":"                 "\"httpbin.org\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h1\","
+                       "\"http_method\":"              "\"GET\","
+                       "\"http_url\":"                 "\"anything?x=${hugearg}\","
+                       "\"nghttp2_quirk_end_stream\":" "true,"
+                       "\"h2q_oflow_txcr\":"           "true,"
+                       "\"metadata\": [{"
+                               "\"hugearg\":"          "\"\""
+                       "}],"
+                       "\"tls\":"                      "true,"
+                       "\"opportunistic\":"            "true,"
+                       "\"retry\":"                    "\"default\","
+                       "\"tls_trust_store\":"          "\"arca1\""
+               "}},{"
+                       "\"httpbin_anything_h2\": {"
+                       "\"endpoint\":"                 "\"httpbin.org\","
+                       "\"port\":"                     "443,"
+                       "\"protocol\":"                 "\"h2\","
+                       "\"http_method\":"              "\"GET\","
+                       "\"http_url\":"                 "\"anything?x=${hugearg}\","
+                       "\"nghttp2_quirk_end_stream\":" "true,"
+                       "\"h2q_oflow_txcr\":"           "true,"
+                       "\"metadata\": [{"
+                               "\"hugearg\":"          "\"\""
+                       "}],"
+                       "\"tls\":"                      "true,"
+                       "\"opportunistic\":"            "true,"
+                       "\"retry\":"                    "\"default\","
+                       "\"tls_trust_store\":"          "\"arca1\""
+               "}},{"
+                       /*
+                        * "captive_portal_detect" describes
+                        * what to do in order to check if the path to
+                        * the Internet is being interrupted by a
+                        * captive portal.  If there's a larger policy
+                        * fetched from elsewhere, it should also include
+                        * this since it needs to be done at least after
+                        * every DHCP acquisition
+                        */
+                   "\"captive_portal_detect\": {"
+                        "\"endpoint\": \"connectivitycheck.android.com\","
+                       "\"http_url\": \"generate_204\","
+                       "\"port\": 80,"
+                        "\"protocol\": \"h1\","
+                        "\"http_method\": \"GET\","
+                        "\"opportunistic\": true,"
+                        "\"http_expect\": 204,"
+                       "\"http_fail_redirect\": true"
+                "}}"
+       "]}"
+;
+
+#endif
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+       struct lejp_ctx                 ctx;
+       size_t                          comp;
+
+       char                            started;
+} myss_t;
+
+
+static const char * const lejp_tokens[] = {
+       "url"
+};
+
+/*
+ * Parse the "url" member of the JSON, and collect the part after the first '='
+ * into the prepared buffer "check".
+ */
+
+static signed char
+lws_httpbin_json_cb(struct lejp_ctx *ctx, char reason)
+{
+       myss_t *m = (myss_t *)ctx->user;
+       const char *p = ctx->buf;
+       size_t l = ctx->npos;
+
+       if (!(reason & LEJP_FLAG_CB_IS_VALUE))
+               return 0;
+
+       if (ctx->path_match - 1)
+               return 0;
+
+       if (!m->started)
+               while (l--)
+                       if (*p++ == '=') {
+                               m->started = 1;
+                               break;
+                       }
+
+       if (!m->started)
+               return 0;
+
+       if (m->comp + l > hugeurl_size) {
+               lwsl_err("%s: returned url string too large %u, %u\n",
+                        __func__, (unsigned int)m->comp, (unsigned int)l);
+
+               return -1;
+       }
+
+       memcpy(check + m->comp, p, l);
+       m->comp += l;
+
+       return 0;
+}
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       if (flags & LWSSS_FLAG_SOM)
+               lejp_construct(&m->ctx, lws_httpbin_json_cb, m,
+                               lejp_tokens, LWS_ARRAY_SIZE(lejp_tokens));
+
+       if (len) {
+               int pr = lejp_parse(&m->ctx, buf, (int)len);
+
+               if (pr != LEJP_CONTINUE && pr < 0) {
+                       lwsl_err("%s: parse failed line %u: %d: %s\n", __func__,
+                                (unsigned int)m->ctx.line, pr,
+                                lejp_error_to_string(pr));
+
+                       return LWSSSSRET_DESTROY_ME;
+               }
+       }
+
+       if (flags & LWSSS_FLAG_EOM) {
+
+               interrupted = 1;
+
+               /* confirm that what we collected is the expected size */
+
+               if (m->comp != hugeurl_size) {
+                       lwsl_err("%s: wrong urlarg size recovered %d %d\n",
+                                __func__, (int)m->comp, (int)hugeurl_size);
+                       return LWSSSSRET_OK;
+               }
+
+               /* confirm what we sent is the same as what we collected */
+
+               if (memcmp(hugeurl, check, hugeurl_size)) {
+                       lwsl_err("%s: huge url content mismatch\n", __func__);
+
+                       return LWSSSSRET_OK;
+               }
+
+               lwsl_user("%s: return hugeurl len %u matches OK\n", __func__,
+                               (unsigned int)hugeurl_size);
+
+               bad = 0;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %s (%d), ord 0x%x\n", __func__,
+                 lws_ss_state_name((int)state), state, (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               lws_ss_start_timeout(m->ss, timeout_ms);
+
+               /* let's make the hugeurl part */
+
+               hugeurl = malloc(hugeurl_size + 1);
+               if (!hugeurl) {
+                       lwsl_err("OOM\n");
+                       return LWSSSSRET_DESTROY_ME;
+               }
+
+               check = malloc(hugeurl_size + 1);
+               if (!check) {
+                       lwsl_err("OOM\n");
+                       free(hugeurl);
+                       hugeurl = NULL;
+                       return LWSSSSRET_DESTROY_ME;
+               }
+
+               /* Create the big, random, urlarg */
+
+               lws_hex_random(lws_ss_get_context(m->ss), hugeurl,
+                              hugeurl_size + 1);
+               if (lws_ss_set_metadata(m->ss, "hugearg", hugeurl, hugeurl_size))
+                       return LWSSSSRET_DISCONNECT_ME;
+
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               break;
+       case LWSSSCS_QOS_ACK_REMOTE:
+               lwsl_notice("%s: LWSSSCS_QOS_ACK_REMOTE\n", __func__);
+               break;
+
+       case LWSSSCS_TIMEOUT:
+               lwsl_notice("%s: LWSSSCS_TIMEOUT\n", __func__);
+               break;
+
+       case LWSSSCS_USER_BASE:
+               lwsl_notice("%s: LWSSSCS_USER_BASE\n", __func__);
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_info_t ssi = {
+       .handle_offset                  = offsetof(myss_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_t, opaque_data),
+       .rx                             = myss_rx,
+       .state                          = myss_state,
+       .user_alloc                     = sizeof(myss_t),
+       .streamtype                     = "httpbin_anything_h2"
+};
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       if (target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       if (current != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       if (h1)
+               ssi.streamtype = "httpbin_anything_h1";
+
+       if (!lws_ss_create(context, 0, &ssi, NULL, NULL, NULL, NULL))
+               return 0;
+
+       lwsl_err("%s: failed to create secure stream\n", __func__);
+
+       return -1;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams hugeurl test client [-d<verb>][-h <urlarg len>]\n");
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+
+       /* connect to ssproxy via UDS by default, else via
+        * tcp connection to this port */
+       if ((p = lws_cmdline_option(argc, argv, "-p")))
+               info.ss_proxy_port = (uint16_t)atoi(p);
+
+       /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+        * path; when -p given this can specify the network interface
+        * to bind to */
+       if ((p = lws_cmdline_option(argc, argv, "-i")))
+               info.ss_proxy_bind = p;
+
+       /* if -p given, -a specifies the proxy address to connect to */
+       if ((p = lws_cmdline_option(argc, argv, "-a")))
+               info.ss_proxy_address = p;
+#else
+       info.pss_policies_json = default_ss_policy;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+       if (lws_cmdline_option(argc, argv, "--h1"))
+               h1 = 1;
+
+       if ((p = lws_cmdline_option(argc, argv, "-h")))
+               hugeurl_size = (size_t)atol(p);
+
+       if (hugeurl_size < 1 || hugeurl_size > 16384) {
+               lwsl_err("%s: -h should be between 1 and 16384\n", __func__);
+               return 1;
+       }
+
+       lwsl_user("%s: huge argument size: %u bytes\n", __func__,
+                       (unsigned int)hugeurl_size);
+
+       info.pt_serv_buf_size = (unsigned int)((hugeurl_size * 2) + 2048);
+       info.max_http_header_data = (unsigned short)(hugeurl_size + 2048);
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       if (hugeurl)
+               free(hugeurl);
+       if (check)
+               free(check);
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-metadata/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-metadata/CMakeLists.txt
new file mode 100644 (file)
index 0000000..67c946a
--- /dev/null
@@ -0,0 +1,41 @@
+project(lws-minimal-secure-streams-metadata C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-metadata)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams.c)
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client minimal-secure-streams.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-metadata/README.md b/minimal-examples/secure-streams/minimal-secure-streams-metadata/README.md
new file mode 100644 (file)
index 0000000..cb9b3b3
--- /dev/null
@@ -0,0 +1,66 @@
+# lws minimal secure streams
+
+The application goes to https://warmcat.com and reads index.html there.
+
+It does it using Secure Streams... the main code in minimal-secure-streams.c
+just sets up the context and opens a secure stream of type "mintest".
+
+The handler for state changes and payloads for "mintest" is in ss-myss.c
+
+The information about how a "mintest" stream should connect and the
+protocol it uses is kept separated in policy-database.c
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-f| Force connecting to the wrong endpoint to check backoff retry flow
+-p| Run as proxy server for clients to connect to over unix domain socket
+--force-portal|Force the SS Captive Portal Detection to feel it's behind a portal
+--force-no-internet|Force the SS Captive Portal Detection to feel it can't reach the internet
+
+```
+[2019/08/12 07:16:11:0045] USR: LWS minimal secure streams [-d<verbosity>] [-f]
+[2019/08/12 07:16:12:6102] USR: myss_state: LWSSSCS_CREATING, ord 0x0
+[2019/08/12 07:16:12:6107] USR: myss_state: LWSSSCS_POLL, ord 0x0
+[2019/08/12 07:16:12:6117] N: lws_ss_client_connect: connecting h1get warmcat.com /
+[2019/08/12 07:16:12:6118] USR: myss_state: LWSSSCS_CONNECTING, ord 0x0
+[2019/08/12 07:16:13:4171] USR: myss_state: LWSSSCS_CONNECTED, ord 0x0
+[2019/08/12 07:16:13:4222] USR: myss_rx: len 1024, flags: 1
+[2019/08/12 07:16:13:4243] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4244] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4244] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4245] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4246] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4247] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4252] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4264] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4265] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4266] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4267] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4268] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4268] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4269] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4270] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4278] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4279] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4280] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4281] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4282] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4283] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4283] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4284] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4287] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4288] USR: myss_rx: len 947, flags: 0
+[2019/08/12 07:16:13:4293] USR: myss_rx: len 0, flags: 2
+[2019/08/12 07:16:13:4399] USR: myss_state: LWSSSCS_DISCONNECTED, ord 0x0
+[2019/08/12 07:16:13:4761] USR: myss_state: LWSSSCS_DESTROYING, ord 0x0
+[2019/08/12 07:16:13:4781] USR: Completed: OK
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-metadata/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams-metadata/minimal-secure-streams.c
new file mode 100644 (file)
index 0000000..46fbd90
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * lws-minimal-secure-streams-metadata
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates a minimal http client using secure streams api.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.
+ *
+ * This example is built two different ways from the same source... one includes
+ * the policy everything needed to fulfil the stream directly.  The other -client
+ * variant has no policy itself and some other minor init changes, and connects
+ * to the -proxy example to actually get the connection done.
+ *
+ * In the -client build case, the example does not even init the tls libraries
+ * since the proxy part will take care of all that.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+/*
+ * uncomment to force network traffic through 127.0.0.1:1080
+ *
+ * On your local machine, you can run a SOCKS5 proxy like this
+ *
+ * $ ssh -N -D 0.0.0.0:1080 localhost -v
+ *
+ * If enabled, this also fetches a remote policy that also
+ * specifies that all traffic should go through the remote
+ * proxy.
+ */
+// #define VIA_LOCALHOST_SOCKS
+
+static int interrupted, bad = 1, force_cpd_fail_portal,
+          force_cpd_fail_no_internet;
+static lws_state_notify_link_t nl;
+static const char *server_name_or_url = "warmcat.com";
+
+/*
+ * If the -proxy app is fulfilling our connection, then we don't need to have
+ * the policy in the client.
+ *
+ * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over
+ * a Unix Domain Socket.  To test that, you need to separately run the
+ * ./lws-minimal-secure-streams-proxy test app on the same machine.
+ */
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+#if defined(VIA_LOCALHOST_SOCKS)
+         "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+#endif
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+               "{\"isrg_root_x1\": \""
+"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="
+         "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": ["
+               "{\"mintest\": {"
+                       "\"endpoint\":"         "\"${servername}\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"\","
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\","
+                       "\"metadata\": ["
+                               "{\"servername\": \"\"}"
+                       "]"
+               "}}"
+       "]}"
+;
+
+#endif
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+} myss_t;
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+//     myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       //myss_t *m = (myss_t *)userobj;
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               lwsl_notice("%s: CREATING: setting servername metadata to %s\n",
+                               __func__, server_name_or_url);
+               if (lws_ss_set_metadata(m->ss, "servername", server_name_or_url,
+                                       strlen(server_name_or_url)))
+                       return LWSSSSRET_DISCONNECT_ME;
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               break;
+       case LWSSSCS_QOS_ACK_REMOTE:
+               lwsl_notice("%s: LWSSSCS_QOS_ACK_REMOTE\n", __func__);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+                       lws_ss_info_t ssi;
+
+                       /* We're making an outgoing secure stream ourselves */
+
+                       memset(&ssi, 0, sizeof(ssi));
+                       ssi.handle_offset = offsetof(myss_t, ss);
+                       ssi.opaque_user_data_offset = offsetof(myss_t,
+                                                              opaque_data);
+                       ssi.rx = myss_rx;
+                       ssi.tx = myss_tx;
+                       ssi.state = myss_state;
+                       ssi.user_alloc = sizeof(myss_t);
+                       ssi.streamtype = "mintest";
+
+                       if (lws_ss_create(context, 0, &ssi, NULL, NULL,
+                                         NULL, NULL)) {
+                               lwsl_err("%s: failed to create secure stream\n",
+                                        __func__);
+                               return -1;
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams test client [-d<verb>]\n");
+
+       /* these options are mutually exclusive if given */
+
+       if (lws_cmdline_option(argc, argv, "--force-portal"))
+               force_cpd_fail_portal = 1;
+
+       if (lws_cmdline_option(argc, argv, "--force-no-internet"))
+               force_cpd_fail_no_internet = 1;
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+
+       /* connect to ssproxy via UDS by default, else via
+        * tcp connection to this port */
+       if ((p = lws_cmdline_option(argc, argv, "-p")))
+               info.ss_proxy_port = (uint16_t)atoi(p);
+
+       /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+        * path; when -p given this can specify the network interface
+        * to bind to */
+       if ((p = lws_cmdline_option(argc, argv, "-i")))
+               info.ss_proxy_bind = p;
+
+       /* if -p given, -a specifies the proxy address to connect to */
+       if ((p = lws_cmdline_option(argc, argv, "-a")))
+               info.ss_proxy_address = p;
+#else
+       info.pss_policies_json = default_ss_policy;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+       if ((p = lws_cmdline_option(argc, argv, "-u")))
+               server_name_or_url = p;
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-metrics-proxy/metrics-proxy-policy.json b/minimal-examples/secure-streams/minimal-secure-streams-metrics-proxy/metrics-proxy-policy.json
new file mode 100644 (file)
index 0000000..d742014
--- /dev/null
@@ -0,0 +1,60 @@
+{
+       "release":"01234567",
+       "product":"myproduct",
+       "schema-version":1,
+       "retry": [{
+               "default": {
+                       "backoff": [1000,2000,3000,5000,10000],
+                       "conceal":5,
+                       "jitterpc":20,
+                       "svalidping":300,
+                       "svalidhup":310
+               }}],
+       "certs": [{
+               "isrg_root_x1": "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZLubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc="},
+               {"self_localhost": "MIIF5jCCA86gAwIBAgIJANq50IuwPFKgMA0GCSqGSIb3DQEBCwUAMIGGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRXJld2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEbMBkGA1UECgwSbGlid2Vic29ja2V0cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEG5vbmVAaW52YWxpZC5vcmcwIBcNMTgwMzIwMDQxNjA3WhgPMjExODAyMjQwNDE2MDdaMIGGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRXJld2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEbMBkGA1UECgwSbGlid2Vic29ja2V0cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEG5vbmVAaW52YWxpZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCjYtuWaICCY0tJPubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8Di3DAmHKnSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTekLWcfI5ZZtoGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnHKT/m6DSU0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6jzhNyMBTJ1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQUjy5N8pSNp7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAzTK4l2pHNuC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBKIzv9cgi9fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0nPN1IMSnzXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzoGMTvP/AuehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9psNcjTMaBQLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABo1MwUTAdBgNVHQ4EFgQU9mYU23tW2zsomkKTAXarjr2vjuswHwYDVR0jBBgwFoAU9mYU23tW2zsomkKTAXarjr2vjuswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEANjIBMrowYNCbhAJdP7dhlhT2RUFRdeRUJD0IxrH/hkvb6myHHnK8nOYezFPjUlmRKUgNEDuAxbnXZzPdCRNV9V2mShbXvCyiDY7WCQE2Bn44z26O0uWVk+7DNNLH9BnkwUtOnM9PwtmD9phWexm4q2GnTsiL6Ul6cy0QlTJWKVLEUQQ6yda582e23J1AXqtqFcpfoE34H3afEiGy882b+ZBiwkeV+oq6XVF8sFyr9zYrv9CvWTYlkpTQfLTZSsgPdEHYVcjvxQ2D+XyDR0aRLRlvxUa9dHGFHLICG34Juq5Ai6lM1EsoD8HSsJpMcmrH7MWw2cKkujC3rMdFTtte83wF1uuF4FjUC72+SmcQN7A386BC/nk2TTsJawTDzqwOu/VdZv2g1WpTHlumlClZeP+G/jkSyDwqNnTu1aodDmUa4xZodfhP1HWPwUKFcq8oQr148QYAAOlbUOJQU7QwRWd1VbnwhDtQWXC92A2w1n/xkZSR1BM/NUSDhkBSUU1WjMbWg6GgmnIZLRerQCu1Oozr87rOQqQakPkyt8BUSNK3K42j2qcfhAONdRl8Hq8Qs5pupy+s8sdCGDlwR3JNCMv6u48OK87F4mcIxhkSefFJUFII25pCGN5WtE4p5l+9cnO1GrIXe2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE="},{"self_localhost_key": "MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCjYtuWaICCY0tJPubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8Di3DAmHKnSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTekLWcfI5ZZtoGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnHKT/m6DSU0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6jzhNyMBTJ1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQUjy5N8pSNp7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAzTK4l2pHNuC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBKIzv9cgi9fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0nPN1IMSnzXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzoGMTvP/AuehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9psNcjTMaBQLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABAoICAFWe8MQZb37k2gdAV3Y6aq8fqokKQqbCNLd3giGFwYkezHXoJfg6Di7oZxNcKyw35LFEghkgtQqErQqo35VPIoH+vXUpWOjnCmM4muFA9/cX6mYMc8TmJsg0ewLdBCOZVw+wPABlaqz+0UOiSMMftpk9fz9JwGd8ERyBsT+tk3Qi6D0vPZVsC1KqxxL/cwIFd3Hf2ZBtJXe0KBn1pktWht5AKqx9mld2Ovl7NjgiC1Fx9r+fZw/iOabFFwQA4dr+R8mEMK/7bd4VXfQ1o/QGGbMTG+ulFrsiDyP+rBIAaGC0i7gDjLAIBQeDhP409ZhswIEc/GBtODU372a2CQK/u4Q/HBQvuBtKFNkGUooLgCCbFxzgNUGc83GB/6IwbEM7R5uXqsFiE71LpmroDyjKTlQ8YZkpIcLNVLw0usoGYHFm2rvCyEVlfsE3Ub8cFyTFk50SeOcF2QL2xzKmmbZEpXglxBHR0hjgon0IKJDGfor4bHO7Nt+1Ece8u2oTEKvpz5aIn44OeC5mApRGy83/0bvsesnWjDE/bGpoT8qFuy+0urDEPNId44XcJm1IRIlG56ErxC3l0s11wrIpTmXXckqwzFR9s2z7f0zjeyxqZg4NTPI7wkM3M8BXlvp2GTBIeoxrWB4V3YArwu8QF80QBgVzmgHl24nTg00UH1OjZsABAoIBAQDOxftSDbSqGytcWqPYP3SZHAWDA0O4ACEM+eCwau9ASutl0IDlNDMJ8nC2ph25BMe5hHDWp2cGQJog7pZ/3qQogQho2gUniKDifN7740QdykllTzTVROqmP8+efreIvqlzHmuqaGfGs5oTkZaWj5su+B+bT+9rIwZcwfs5YRINhQRx17qa++xh5mfE25c+M9fiIBTiNSo4lTxWMBShnK8xrGaMEmN7W0qTMbFHPgQz5FcxRjCCqwHilwNBeLDTp/ZECEB7y34khVh531mBE2mNzSVIQcGZP1I/DvXjW7UUNdgFwii/GW+6M0uUDy23UVQpbFzcV8o1C2nZc4Fb4zwBAoIBAQDKSJkFwwuRnaVJS6WxOKjX8MCu9/cKPnwBv2mmI2jgGxHTw5sr3ahmF5eTb8Zo19BowytN+tr62ZFoIBA9Ubc9esEAU8l3fggdfM82cuR9sGcfQVoCh8tMg6BP8IBLOmbSUhN3PG2m39I802u0fFNVQCJKhx1m1MFFLOu7lVcDS9JN+oYVPb6MDfBLm5jOiPuYkFZ4gH79J7gXI0/YKhaJ7yXthYVkdrSF6Eooer4RZgma62Dd1VNzSq3JBo6rYjF7Lvd+RwDCR1thHrmf/IXplxpNVkoMVxtzbrrbgnC25QmvRYc0rlS/kvM4yQhMH3eA7IycDZMpY+0xm7I7jTT7AoIBAGKzKIMDXdCxBWKhNYJ8z7hiItNl1IZZMW2TPUiY0rl6yaChBVXjM9W0r07QPnHZsUiByqb743adkbTUjmxdJzjaVtxN7ZXwZvOVrY7I7fPWYnCEfXCr4+IVpZI/ZHZWpGX6CGSgT6EOjCZ5IUufIvEpqVSmtF8MqfXO9o9uIYLokrWQx1dBl5UnuTLDqw8bChq7O5y6yfuWaOWvL7nxI8NvSsfj4y635gIa/0dFeBYZEfHIUlGdNVomwXwYEzgE/c19ruIowX7HU/NgxMWTMZhpazlxgesXybel+YNcfDQ4e3RMOMz3ZFiaMaJsGGNf4++d9TmMgk4Ns6oDs6Tb9AECggEBAJYzd+SOYo26iBu3nw3L65uEeh6xou8pXH0Tu4gQrPQTRZZ/nT3iNgOwqu1gRuxcq7TOjt41UdqIKO8vN7/AaJavCpaKoIMowy/aGCbvAvjNPpU3unU8jdl/t08EXs79S5IKPcgAx87sTTi7KDN5SYt4tr2uPEe53NTXuSatilG5QCyExIELOuzWAMKzg7CAiIlNS9foWeLyVkBgCQ6Sme/L8ta+mUDy37K6vC34jh9vK9yrwF6X44ItRoOJafCaVfGI+175q/eWcqTX4q+IG4tKls4sL4mgOJLq+ra50aYMxbcuommctPMXU6CrrYyQpPTHMNVDQy2ttFdsq9iKTncCggEBAMmt/8yvPflS+xv3kg/ZBvR9JB1In2n3rUCYYD47ReKFqJ03Vmq5C9nY56s9w7OUO8perBXlJYmKZQhO4293lvxZD2Iq4NcZbVSCMoHAUzhzY3brdgtSIxa2gGveGAezZ38qKIU26dkz7deECY4vrsRkwhpTW0LGVCpjcQoaKvymAoCmAs8V2oMrZiw1YQ9uOUoWwOqm1wZqmVcOXvPIS2gWAs3fQlWjH9hkcQTMsUaXQDOD0aqkSY3ENqOvbCV1/oUpRi3076khCoAXI1bKSn/AvR3KDP14B5toHI/F5OTSEiGhhHesgRrsfBrpEY1IATtPq1taBZZogRqI3rOkkPk="
+       }],
+       "trust_stores": [
+               {"name": "le_via_isrg",
+                "stack": ["isrg_root_x1"]
+               }
+       ], "s": [
+               {
+                       "mintest": {
+                               "endpoint":"warmcat.com",
+                               "port":443,
+                               "protocol":"h2",
+                               "http_method":"GET",
+                               "http_url":"index.html",
+                               "tls":true,
+                               "retry":"default",
+                               "tls_trust_store":"le_via_isrg"
+               }},{
+                       "forscraper": {
+                               "server":true,
+                               "port":19090,
+                               "protocol":"h1",
+                               "metadata": [{
+                                       "mime": "Content-Type:",
+                                       "method": "",
+                                       "path": ""
+                               }
+                       ]
+               }},{
+                       "forclients": {
+                               "server":true,
+                               "port":19091,
+                               "protocol":"h1",
+                               "metadata": [{
+                                       "mime": "Content-Type:",
+                                       "method": "",
+                                       "path": ""
+                               }],
+                               "tls":true,
+                               "ws_subprotocol":"lws-metrics-proxy",
+                               "server_cert":"self_localhost",
+                               "server_key":"self_localhost_key"
+               }}
+       ]
+}
+
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-perf/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-perf/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c0beb26
--- /dev/null
@@ -0,0 +1,133 @@
+project(lws-minimal-secure-streams-perf C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-perf)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams.c)
+
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32)
+       
+               #
+               # When running in CI, wait for a lease on the resources
+               # before starting this test, so the server does not get
+               # thousands of simultaneous tls connection attempts
+               #
+               # sai-resource holds the lease on the resources until
+               # the time given in seconds or the sai-resource instance
+               # exits, whichever happens first
+               #
+               # If running under Sai, creates a lock test called "res_sspcmin" 
+               #
+               
+               sai_resource(warmcat_conns 1 40 ssperfpcmin)
+               
+               #
+               # simple test not via proxy
+               #
+       
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME ssperf-warmcat COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-perf>)
+               else()
+                       add_test(NAME ssperf-warmcat COMMAND lws-minimal-secure-streams-perf)
+               endif()
+
+               set_tests_properties(ssperf-warmcat
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams
+                                    TIMEOUT 40)
+               if (DEFINED ENV{SAI_OVN})
+                       set_tests_properties(ssperf-warmcat PROPERTIES FIXTURES_REQUIRED "res_ssperfpcmin")
+               endif()
+
+               if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+                       #
+                       # Define test dep to bring up and take down the test
+                       # proxy
+                       #
+
+                       if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                               # uds abstract namespace for linux
+                               set(CTEST_SOCKET_PATH "@ctest-ssperfp-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       else()
+                               # filesystem socket for others
+                               set(CTEST_SOCKET_PATH "/tmp/ctest-ssperfp-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       endif()
+                       add_test(NAME st_ssperfproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               ssperfproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH} )
+                       set_tests_properties(st_ssperfproxy PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP ssperfproxy TIMEOUT 800)
+
+                       add_test(NAME ki_ssperfproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                               ssperfproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH})
+                       set_tests_properties(ki_ssperfproxy PROPERTIES FIXTURES_CLEANUP ssperfproxy)
+
+                       #
+                       # the client part that will connect to the proxy
+                       #
+
+                       if (VALGRIND)
+                               message("testing via valgrind")
+                               add_test(NAME ssperfpc-minimal COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-perf-client> -i +${CTEST_SOCKET_PATH})
+                       else()
+                               add_test(NAME ssperfpc-minimal COMMAND lws-minimal-secure-streams-perf-client -i +${CTEST_SOCKET_PATH})
+                       endif()
+                       
+                       set(fixlist "ssperfproxy")
+                       if (DEFINED ENV{SAI_OVN})
+                               list(APPEND fixlist "res_ssperfproxy")
+                       endif()
+                       
+                       set_tests_properties(ssperfpc-minimal PROPERTIES
+                               WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-perf
+                               FIXTURES_REQUIRED "${fixlist}"
+                               TIMEOUT 40)
+
+               endif()
+
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client minimal-secure-streams.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-perf/README.md b/minimal-examples/secure-streams/minimal-secure-streams-perf/README.md
new file mode 100644 (file)
index 0000000..bddaacd
--- /dev/null
@@ -0,0 +1,104 @@
+# lws minimal secure streams perf
+
+The application goes to https://warmcat.com and reads index.html there.
+
+The streamtype used is marked with a "perf": true policy, it returns additional
+rx payload marked with the `LWSSS_FLAG_PERF_JSON` flag containing a JSON rundown
+of the connection performance.
+
+This builds both lws-minimal-secure-streams-perf that connects directly, and
+lws-minimal-secure-streams-perf-client that connects via the proxy, giving the
+same results.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+[2021/03/31 15:29:46:5162] U: LWS secure streams test client [-d<verb>]
+[2021/03/31 15:29:46:5625] N: LWS: 4.1.99-v4.2-rc1-50-g8b5acf835c, loglevel 1031
+[2021/03/31 15:29:46:5629] N: NET CLI SRV H1 H2 WS SS-JSON-POL SSPROX ConMon IPV6-on
+[2021/03/31 15:29:46:5829] N:  ++ [795209|wsi|0|pipe] (1)
+[2021/03/31 15:29:46:5892] N:  ++ [795209|vh|0|netlink] (1)
+[2021/03/31 15:29:46:5983] N:  ++ [795209|vh|1|default||-1] (2)
+[2021/03/31 15:29:46:7638] N:  ++ [795209|SSPcli|0|mintest] (1)
+[2021/03/31 15:29:46:7957] N:  ++ [795209|wsiSSPcli|0|RAW/raw-skt/+@proxy.ss.lws/([795209|SSPcli|0|mintest])] (1)
+[2021/03/31 15:29:46:8335] N:  -- [795209|wsiSSPcli|0|RAW/raw-skt/+@proxy.ss.lws/([795209|SSPcli|0|mintest])] (0) 35.608ms
+[2021/03/31 15:29:47:9096] N:  ++ [795209|wsiSSPcli|1|RAW/raw-skt/+@proxy.ss.lws/([795209|SSPcli|0|mintest])] (1)
+[2021/03/31 15:29:47:9103] N:  -- [795209|wsiSSPcli|1|RAW/raw-skt/+@proxy.ss.lws/([795209|SSPcli|0|mintest])] (0) 215μs
+[2021/03/31 15:29:48:9117] N:  ++ [795209|wsiSSPcli|2|RAW/raw-skt/+@proxy.ss.lws/([795209|SSPcli|0|mintest])] (1)
+[2021/03/31 15:29:48:9339] N: lws_sspc_sul_retry_cb: [795209|wsiSSPcli|2|RAW/raw-skt/+@proxy.ss.lws/([795209|SSPcli|0|mintest])]
+[2021/03/31 15:29:48:9625] N: lws_ss_check_next_state: [795209|SSPcli|0|mintest]: (unset) -> LWSSSCS_CREATING
+[2021/03/31 15:29:48:9633] U: myss_state: LWSSSCS_CREATING (1), ord 0x0
+[2021/03/31 15:29:48:9728] N: lws_ss_check_next_state: [795209|SSPcli|0|mintest]: LWSSSCS_CREATING -> LWSSSCS_CONNECTING
+[2021/03/31 15:29:48:9731] U: myss_state: LWSSSCS_CONNECTING (6), ord 0x0
+[2021/03/31 15:29:49:0670] N: lws_ss_deserialize_parse: RX METADATA test
+[2021/03/31 15:29:49:0696] N: lws_ss_check_next_state: [795209|SSPcli|0|mintest]: LWSSSCS_CONNECTING -> LWSSSCS_CONNECTED
+[2021/03/31 15:29:49:0698] U: myss_state: LWSSSCS_CONNECTED (5), ord 0x0
+[2021/03/31 15:29:49:0716] N: lws_ss_deserialize_parse: RX METADATA srv
+[2021/03/31 15:29:49:0882] U: myss_rx: len 1380, flags: 1, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0907] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0926] U: {"peer":"46.105.127.147","dns_us":536,"sockconn_us":30183,"tls_us":29343,"txn_resp_us":25990,"dns":["2001:41d0:2:ee93::1","46.105.127.147"]}
+[2021/03/31 15:29:49:0937] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0938] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0940] U: myss_rx: len 829, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0942] U: myss_rx: len 691, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0943] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0944] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0945] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0947] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0948] U: myss_rx: len 292, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0950] U: myss_rx: len 291, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0951] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0952] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0953] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0955] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0956] U: myss_rx: len 692, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0957] U: myss_rx: len 828, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0958] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0960] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0961] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0962] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0963] U: myss_rx: len 155, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0965] U: myss_rx: len 428, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0966] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0967] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0968] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0969] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0970] U: myss_rx: len 555, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0972] U: myss_rx: len 965, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0973] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0975] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0976] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0977] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0978] U: myss_rx: len 18, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0979] U: myss_rx: len 565, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0980] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0981] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0982] U: myss_rx: len 1380, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0983] U: myss_rx: len 140, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0984] U: myss_rx: len 418, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0985] U: myss_rx: len 44, flags: 0, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0989] U: myss_rx: len 0, flags: 2, srv: lwsws, test: hello
+[2021/03/31 15:29:49:0994] N: lws_ss_check_next_state: [795209|SSPcli|0|mintest]: LWSSSCS_CONNECTED -> LWSSSCS_QOS_ACK_REMOTE
+[2021/03/31 15:29:49:0995] U: myss_state: LWSSSCS_QOS_ACK_REMOTE (10), ord 0x0
+[2021/03/31 15:29:49:0998] N: myss_state: LWSSSCS_QOS_ACK_REMOTE
+[2021/03/31 15:29:49:1008] N: lws_ss_check_next_state: [795209|SSPcli|0|mintest]: LWSSSCS_QOS_ACK_REMOTE -> LWSSSCS_DISCONNECTED
+[2021/03/31 15:29:49:1010] U: myss_state: LWSSSCS_DISCONNECTED (2), ord 0x0
+[2021/03/31 15:29:49:1106] N:  -- [795209|wsi|0|pipe] (0) 2.527s
+[2021/03/31 15:29:49:1169] N:  -- [795209|vh|1|default||-1] (1) 2.518s
+[2021/03/31 15:29:49:1172] N:  -- [795209|wsiSSPcli|2|RAW/raw-skt/+@proxy.ss.lws/([795209|SSPcli|0|mintest])] (0) 205.495ms
+[2021/03/31 15:29:49:1174] N:  -- [795209|vh|0|netlink] (0) 2.528s
+[2021/03/31 15:29:49:1203] N: lws_ss_check_next_state: [795209|SSPcli|0|mintest]: LWSSSCS_DISCONNECTED -> LWSSSCS_DESTROYING
+[2021/03/31 15:29:49:1206] U: myss_state: LWSSSCS_DESTROYING (7), ord 0x0
+[2021/03/31 15:29:49:1210] N:  -- [795209|SSPcli|0|mintest] (0) 2.357s
+[2021/03/31 15:29:49:1292] U: Completed: OK (seen expected 0)
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-perf/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams-perf/minimal-secure-streams.c
new file mode 100644 (file)
index 0000000..f3b9b9b
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * lws-minimal-secure-streams
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates a minimal http client using secure streams api.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.
+ *
+ * This example is built two different ways from the same source... one includes
+ * the policy everything needed to fulfil the stream directly.  The other -client
+ * variant has no policy itself and some other minor init changes, and connects
+ * to the -proxy example to actually get the connection done.
+ *
+ * In the -client build case, the example does not even init the tls libraries
+ * since the proxy part will take care of all that.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+/*
+ * uncomment to force network traffic through 127.0.0.1:1080
+ *
+ * On your local machine, you can run a SOCKS5 proxy like this
+ *
+ * $ ssh -N -D 0.0.0.0:1080 localhost -v
+ *
+ * If enabled, this also fetches a remote policy that also
+ * specifies that all traffic should go through the remote
+ * proxy.
+ */
+// #define VIA_LOCALHOST_SOCKS
+
+static int interrupted, bad = 1, force_cpd_fail_portal,
+          force_cpd_fail_no_internet, test_respmap;
+static const char *streamtype = "mintest";
+static unsigned int timeout_ms = 3000;
+static lws_state_notify_link_t nl;
+
+/*
+ * If the -proxy app is fulfilling our connection, then we don't need to have
+ * the policy in the client.
+ *
+ * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over
+ * a Unix Domain Socket.  To test that, you need to separately run the
+ * ./lws-minimal-secure-streams-proxy test app on the same machine.
+ */
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+#if defined(VIA_LOCALHOST_SOCKS)
+         "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+#endif
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+               "{\"isrg_root_x1\": \""
+       "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="
+         "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": ["
+               /*
+                * "fetch_policy" decides from where the real policy
+                * will be fetched, if present.  Otherwise the initial
+                * policy is treated as the whole, hardcoded, policy.
+                */
+               "{\"fetch_policy\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+#if defined(VIA_LOCALHOST_SOCKS)
+                       "\"http_url\":"         "\"policy/minimal-proxy-socks.json\","
+#else
+                       "\"http_url\":"         "\"policy/minimal-proxy-v4.2-v2.json\","
+#endif
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}},{"
+                       /*
+                        * "captive_portal_detect" describes
+                        * what to do in order to check if the path to
+                        * the Internet is being interrupted by a
+                        * captive portal.  If there's a larger policy
+                        * fetched from elsewhere, it should also include
+                        * this since it needs to be done at least after
+                        * every DHCP acquisition
+                        */
+                   "\"captive_portal_detect\": {"
+                        "\"endpoint\": \"connectivitycheck.android.com\","
+                       "\"http_url\": \"generate_204\","
+                       "\"port\": 80,"
+                        "\"protocol\": \"h1\","
+                        "\"http_method\": \"GET\","
+                        "\"opportunistic\": true,"
+                        "\"http_expect\": 204,"
+                       "\"http_fail_redirect\": true"
+                "}}"
+       "]}"
+;
+
+#endif
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+} myss_t;
+
+#if !defined(LWS_SS_USE_SSPC)
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+#endif
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+       const char *md_srv = "not set", *md_test = "not set";
+       size_t md_srv_len = 7, md_test_len = 7;
+
+       if (flags & LWSSS_FLAG_PERF_JSON) {
+               lwsl_user("%.*s\n", (int)len, (const char *)buf);
+
+               return LWSSSSRET_OK;
+       }
+
+       lws_ss_get_metadata(m->ss, "srv", (const void **)&md_srv, &md_srv_len);
+       lws_ss_get_metadata(m->ss, "test", (const void **)&md_test, &md_test_len);
+
+       lwsl_user("%s: len %d, flags: %d, srv: %.*s, test: %.*s\n", __func__,
+                 (int)len, flags, (int)md_srv_len, md_srv,
+                 (int)md_test_len, md_test);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       //myss_t *m = (myss_t *)userobj;
+
+       /* in this example, we don't send stuff */
+
+       return LWSSSSRET_TX_DONT_SEND;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %s (%d), ord 0x%x\n", __func__,
+                 lws_ss_state_name((int)state), state, (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_CONNECTING:
+               lws_ss_start_timeout(m->ss, timeout_ms);
+               if (lws_ss_set_metadata(m->ss, "uptag", "myuptag123", 10))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+
+               if (lws_ss_set_metadata(m->ss, "ctype", "myctype", 7))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+               break;
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               bad = 2;
+               break;
+
+       case LWSSSCS_QOS_ACK_REMOTE:
+               lwsl_notice("%s: LWSSSCS_QOS_ACK_REMOTE\n", __func__);
+               break;
+
+       case LWSSSCS_TIMEOUT:
+               lwsl_notice("%s: LWSSSCS_TIMEOUT\n", __func__);
+               /* if we're out of time */
+               interrupted = 1;
+               bad = 3;
+               break;
+
+       case LWSSSCS_USER_BASE:
+               lwsl_notice("%s: LWSSSCS_USER_BASE\n", __func__);
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+#if !defined(LWS_SS_USE_SSPC)
+
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+#endif
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+
+#if !defined(LWS_SS_USE_SSPC)
+
+       /*
+        * The proxy takes responsibility for this stuff if we get things
+        * done through that
+        */
+
+       case LWS_SYSTATE_INITIALIZED: /* overlay on the hardcoded policy */
+       case LWS_SYSTATE_POLICY_VALID: /* overlay on the loaded policy */
+
+               if (target != current)
+                       break;
+
+               if (force_cpd_fail_portal)
+
+                       /* this makes it look like we're behind a captive portal
+                        * because the overriden address does a redirect */
+
+                       lws_ss_policy_overlay(context,
+                                     "{\"s\": [{\"captive_portal_detect\": {"
+                                        "\"endpoint\": \"google.com\","
+                                        "\"http_url\": \"/\","
+                                        "\"port\": 80"
+                                     "}}]}");
+
+               if (force_cpd_fail_no_internet)
+
+                       /* this looks like no internet, because the overridden
+                        * port doesn't have anything that will connect to us */
+
+                       lws_ss_policy_overlay(context,
+                                     "{\"s\": [{\"captive_portal_detect\": {"
+                                        "\"endpoint\": \"warmcat.com\","
+                                        "\"http_url\": \"/\","
+                                        "\"port\": 999"
+                                     "}}]}");
+               break;
+
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+
+#endif
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+                       lws_ss_info_t ssi;
+
+                       /* We're making an outgoing secure stream ourselves */
+
+                       memset(&ssi, 0, sizeof(ssi));
+                       ssi.handle_offset = offsetof(myss_t, ss);
+                       ssi.opaque_user_data_offset = offsetof(myss_t,
+                                                              opaque_data);
+                       ssi.rx = myss_rx;
+                       ssi.tx = myss_tx;
+                       ssi.state = myss_state;
+                       ssi.user_alloc = sizeof(myss_t);
+                       ssi.streamtype = test_respmap ? "respmap" : streamtype;
+
+                       if (lws_ss_create(context, 0, &ssi, NULL, NULL,
+                                         NULL, NULL)) {
+                               lwsl_err("%s: failed to create secure stream\n",
+                                        __func__);
+                               return -1;
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+#if defined(LWS_WITH_SYS_METRICS)
+
+static int
+my_metric_report(lws_metric_pub_t *mp)
+{
+       lws_metric_bucket_t *sub = mp->u.hist.head;
+       char buf[192];
+
+       do {
+               if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
+                       lwsl_user("%s: %s\n", __func__, buf);
+       } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
+
+       /* 0 = leave metric to accumulate, 1 = reset the metric */
+
+       return 1;
+}
+
+static const lws_system_ops_t system_ops = {
+       .metric_report = my_metric_report,
+};
+
+#endif
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0, expected = 0;
+       const char *p;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams test client PERF [-d<verb>]\n");
+
+       /* these options are mutually exclusive if given */
+
+       if (lws_cmdline_option(argc, argv, "--force-portal"))
+               force_cpd_fail_portal = 1;
+
+       if (lws_cmdline_option(argc, argv, "--force-no-internet"))
+               force_cpd_fail_no_internet = 1;
+
+       if (lws_cmdline_option(argc, argv, "--respmap"))
+               test_respmap = 1;
+
+       if (lws_cmdline_option(argc, argv, "--test404"))
+               streamtype = "mintest404";
+
+       if (lws_cmdline_option(argc, argv, "--test404red"))
+               streamtype = "mintest404red";
+
+       if (lws_cmdline_option(argc, argv, "--test404redref"))
+               streamtype = "mintest404redref";
+
+       if ((p = lws_cmdline_option(argc, argv, "--timeout_ms")))
+               timeout_ms = (unsigned int)atoi(p);
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#else
+       info.pss_policies_json = default_ss_policy;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+
+#if defined(LWS_WITH_SYS_METRICS)
+       info.system_ops = &system_ops;
+       info.metrics_prefix = "ssmex";
+#endif
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               goto bail;
+       }
+
+#if !defined(LWS_SS_USE_SSPC)
+       /*
+        * If we're being a proxied client, the proxy does all this
+        */
+
+       /*
+        * Set the related lws_system blobs
+        *
+        * ...direct_set() sets a pointer, so the thing pointed to has to have
+        * a suitable lifetime, eg, something that already exists on the heap or
+        * a const string in .rodata like this
+        */
+
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_SERIAL, 0),
+                                  (const uint8_t *)"SN12345678", 10);
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION, 0),
+                                  (const uint8_t *)"v0.01", 5);
+
+       /*
+        * ..._heap_append() appends to a buflist kind of arrangement on heap,
+        * just one block is fine, otherwise it will concatenate the fragments
+        * in the order they were appended (and take care of freeing them at
+        * context destroy time). ..._heap_empty() is also available to remove
+        * everything that was already allocated.
+        *
+        * Here we use _heap_append() just so it's tested as well as direct set.
+        */
+
+       lws_system_blob_heap_append(lws_system_get_blob(context,
+                                   LWS_SYSBLOB_TYPE_DEVICE_TYPE, 0),
+                                  (const uint8_t *)"spacerocket", 11);
+#endif
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+bail:
+       if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
+               expected = atoi(p);
+
+       if (bad == expected) {
+               lwsl_user("Completed: OK (seen expected %d)\n", expected);
+               return 0;
+       } else
+               lwsl_err("Completed: failed: exit %d, expected %d\n", bad, expected);
+
+       return 1;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-policy2c/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-policy2c/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f8272f3
--- /dev/null
@@ -0,0 +1,28 @@
+project(lws-minimal-secure-streams-policy2c C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-policy2c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_ROLE_H2 1 requirements)
+require_lws_config(LWS_ROLE_MQTT 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams.c)
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-policy2c/README.md b/minimal-examples/secure-streams/minimal-secure-streams-policy2c/README.md
new file mode 100644 (file)
index 0000000..8e093ea
--- /dev/null
@@ -0,0 +1,49 @@
+# lws minimal secure streams policy2c
+
+This application parses a JSON policy passed on stdin and emits the
+equivalent of it in C structs ready for compilation.
+
+This is useful in the case your platform doesn't use a dynamic JSON
+policy and is space-constrained, you can still form and maintain the
+policy in JSON, but with this utility convert it into compileable C.
+
+**Notice** this depends on LWS_ROLE_H1, LWS_ROLE_H2, LWS_ROLE_WS and
+LWS_ROLE_MQTT build of lws, since it has to be able to work with any kind
+of policy content.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+$ cat mypolicy.json | lws-minimal-secure-streams-policy2c
+
+(on stdout) 
+
+static const uint32_t _rbo_bo_0[] = {
+ 1000,  2000,  3000,  5000,  10000, 
+};
+static const lws_retry_bo_t _rbo_0 = {
+       .retry_ms_table = _rbo_bo_0,
+       .retry_ms_table_count = 5,
+       .conceal_count = 5,
+       .secs_since_valid_ping = 30,
+       .secs_since_valid_hangup = 35,
+       .jitter_percent = 20,
+};
+static const uint8_t _ss_der_amazon_root_ca_1[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x03, 0x41, 0x30, 0x82, 0x02, 0x29, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x06, 
+       /* 0x 10 */ 0x6C, 0x9F, 0xCF, 0x99, 0xBF, 0x8C, 0x0A, 0x39, 
+       /* 0x 18 */ 0xE2, 0xF0, 0x78, 0x8A, 0x43, 0xE6, 0x96, 0x36, 
+       /* 0x 20 */ 0x5B, 0xCA, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 
+...
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-policy2c/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams-policy2c/minimal-secure-streams.c
new file mode 100644 (file)
index 0000000..f3a0b69
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+ * lws-minimal-secure-streams-policy2c
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This reads policy JSON on stdin and emits it as compileable
+ * C structs.
+ *
+ * It's useful if your platform is too space-constrained for a
+ * JSON policy and needs to build a static policy in C via
+ * LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY... this way you can
+ * still create and maintain the JSON policy but implement it directly
+ * as C structs in your code.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#include <stdio.h>
+#include <assert.h>
+
+static int interrupted, bad = 1;
+
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+struct aggstr {
+       struct aggstr *next;
+
+       const char *orig;
+       size_t offset;
+};
+
+static struct aggstr *rbomap,  /* retry / backoff object map */
+                    *trustmap, /* trust store map */
+                    *certmap;  /* x.509 cert map */
+static size_t last_offset;
+
+
+
+static const char *
+purify_csymbol(const char *in, char *temp, size_t templen)
+{
+       const char *otemp = temp;
+
+       assert (strlen(in) < templen);
+
+       while (*in) {
+               if ((*in >= 'a' && *in <= 'z') || (*in >= 'A' && *in <= 'Z') ||
+                   (*in >= '0' && *in <= '9'))
+                       *temp++ = *in;
+               else
+                       *temp++ = '_';
+
+               in++;
+       }
+
+       *temp = '\0';
+
+       return otemp;
+}
+
+int main(int argc, const char **argv)
+{
+       const lws_ss_policy_t *pol, *lastpol = NULL;
+       struct lws_context_creation_info info;
+       size_t json_size = 0, est = 0;
+       struct lws_context *context;
+       const lws_ss_auth_t *auth;
+       char prev[128], curr[128];
+       int unique_rbo = 0, m, n;
+       char buf[64], buf1[64];
+       lws_ss_metadata_t *md;
+       struct aggstr *a, *a1;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams policy2c [-d<verb>]\n");
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       lws_ss_policy_parse_begin(context, 0);
+
+       printf("/*\n * Autogenerated from the following JSON policy\n */\n\n#if 0\n");
+
+       do {
+               int m, n = (int)read(0, buf, sizeof(buf));
+
+               if (n < 1)
+                       break;
+
+               m = lws_ss_policy_parse(context, (uint8_t *)buf, (size_t)n);
+
+               printf("%.*s", n, buf);
+               json_size += (unsigned int)n;
+
+               if (m < 0 && m != LEJP_CONTINUE) {
+                       lwsl_err("%s: policy parse failed... lws has WITH_ROLEs"
+                                "for what's in the JSON?\n", __func__);
+                       goto bail;
+               }
+       } while (1);
+
+       printf("\n\n Original JSON size: %zu\n#endif\n\n", json_size);
+
+       lwsl_notice("%s: parsed JSON\n", __func__);
+
+       /*
+        * Well, this is fun, isn't it... we have parsed the JSON into in-memory
+        * policy objects, and it has set the context policy pointer to the head
+        * of those but has not set the new policy (which would free the x.509).
+        *
+        * We want to walk the streamtype list first discovering unique objects
+        * and strings referenced there and emitting them compactly as C data,
+        * and then second to emit the streamtype linked-list referring to those
+        * objects.
+        *
+        * For const strings, we aggregate them and avoid generating extra
+        * pointers by encoding the reference as &_lws_ss_staticpol_str[xxx]
+        * where xxx is the fixed offset in the aggregated monster-string.  When
+        * doing that, we keep a map of original pointers to offsets.
+        *
+        * Although we want to minimize memory used by the emitted C, we don't
+        * have to sweat memory during this conversion since it's happening on a
+        * PC
+        */
+
+       pol = lws_ss_policy_get(context);
+
+       while (pol) {
+
+               /*
+                * Walk the metadata list gathering strings and issuing the
+                * C struct
+                */
+
+               md = pol->metadata;
+
+               if (md) {
+                       int idx = 0;
+
+                       printf("\nstatic const lws_ss_metadata_t ");
+
+                       prev[0] = '\0';
+                       md = pol->metadata;
+                       while (md) {
+
+                               est += sizeof(lws_ss_metadata_t);
+
+                               lws_snprintf(curr, sizeof(curr), "_md_%s_%s",
+                                       purify_csymbol(pol->streamtype, buf,
+                                                      sizeof(buf)),
+                                       purify_csymbol(md->name, buf1,
+                                                      sizeof(buf1)));
+
+                               printf("%s = {\n", curr);
+                               if (prev[0])
+                                       printf("\t.next = (void *)&%s, \n", prev);
+
+                               printf("\t.name = \"%s\",\n", (const char *)md->name);
+                               if (md->value__may_own_heap) {
+                                       printf("\t.value__may_own_heap = (void *)\"%s\",\n",
+                                                       (const char *)md->value__may_own_heap);
+                                       printf("\t.value_length = 0x%x,\n",
+                                               (unsigned int)strlen(
+                                                       (const char *)md->value__may_own_heap));
+                               }
+
+                               printf("\t.length = %d,\n", idx++); // md->length);
+                               printf("\t.value_is_http_token = 0x%x,\n",
+                                       (unsigned int)md->value_is_http_token);
+                               printf("}");
+                               if (md->next)
+                                       printf(",\n");
+
+                               lws_strncpy(prev, curr, sizeof(prev));
+
+                               md = md->next;
+                       }
+
+                       printf(";\n\n");
+               }
+
+               /*
+                * Create unique retry policies... have we seen this guy?
+                */
+
+               if (pol->retry_bo) {
+                       a = rbomap;
+                       while (a) {
+                               if (a->orig == (const char *)pol->retry_bo)
+                                       break;
+
+                               a = a->next;
+                       }
+
+                       if (!a) {
+
+                               /* We haven't seen it before and need to create it */
+
+                               a = malloc(sizeof(*a));
+                               if (!a)
+                                       goto bail;
+                               a->next = rbomap;
+                               a->offset = (unsigned int)unique_rbo++;
+                               a->orig = (const char *)pol->retry_bo;
+                               rbomap = a;
+
+                               printf("static const uint32_t _rbo_bo_%zu[] = {\n",
+                                       a->offset);
+                               for (n = 0; n < pol->retry_bo->retry_ms_table_count; n++)
+                                       printf(" %u, ", (unsigned int)
+                                              pol->retry_bo->retry_ms_table[n]);
+
+                               est += sizeof(uint32_t) *
+                                       pol->retry_bo->retry_ms_table_count;
+
+                               printf("\n};\nstatic const "
+                                      "lws_retry_bo_t _rbo_%zu = {\n", a->offset);
+
+                               printf("\t.retry_ms_table = _rbo_bo_%zu,\n",
+                                       a->offset);
+                               printf("\t.retry_ms_table_count = %u,\n",
+                                       pol->retry_bo->retry_ms_table_count);
+                               printf("\t.conceal_count = %u,\n",
+                                       pol->retry_bo->conceal_count);
+                               printf("\t.secs_since_valid_ping = %u,\n",
+                                       pol->retry_bo->secs_since_valid_ping);
+                               printf("\t.secs_since_valid_hangup = %u,\n",
+                                       pol->retry_bo->secs_since_valid_hangup);
+                               printf("\t.jitter_percent = %u,\n",
+                                       pol->retry_bo->jitter_percent);
+                               printf("};\n");
+
+                               est += sizeof(lws_retry_bo_t);
+                       }
+               }
+
+               /*
+                * How about his trust store, it's new to us?
+                */
+
+               if (pol->trust.store) {
+                       a = trustmap;
+                       while (a) {
+                               if (a->orig == (const char *)pol->trust.store)
+                                       break;
+
+                               a = a->next;
+                       }
+
+                       if (!a) {
+
+                               /* it's new to us... */
+
+                               a = malloc(sizeof(*a));
+                               if (!a)
+                                       goto bail;
+                               a->next = trustmap;
+                               a->offset = 0; /* don't care, just track seen */
+                               a->orig = (const char *)pol->trust.store;
+                               trustmap = a;
+
+                               /*
+                                * Have a look through his x.509 stack...
+                                * any that're new to us?
+                                */
+
+                               for (n = 0; n < pol->trust.store->count; n++) {
+                                       if (!pol->trust.store->ssx509[n])
+                                               continue;
+                                       a1 = certmap;
+                                       while (a1) {
+                                               if (a1->orig == (const char *)pol->trust.store->ssx509[n])
+                                                       break;
+                                               a1 = a1->next;
+                                       }
+
+                                       if (!a1) {
+                                               /*
+                                                * This x.509 cert is new to us...
+                                                * let's capture the DER
+                                                */
+
+                                               a1 = malloc(sizeof(*a1));
+                                               if (!a1)
+                                                       goto bail;
+                                               a1->next = certmap;
+                                               a1->offset = 0; /* don't care, just track seen */
+                                               a1->orig = (const char *)pol->trust.store->ssx509[n];
+                                               certmap = a1;
+
+                                               printf("static const uint8_t _ss_der_%s[] = {\n",
+                                                       purify_csymbol(pol->trust.store->ssx509[n]->vhost_name,
+                                                                       buf, sizeof(buf)));
+
+                                               for (m = 0; m < (int)pol->trust.store->ssx509[n]->ca_der_len; m++) {
+                                                       if ((m & 7) == 0)
+                                                               printf("\t/* 0x%3x */ ", m);
+
+                                                       printf("0x%02X, ", pol->trust.store->ssx509[n]->ca_der[m]);
+                                                       if ((m & 7) == 7)
+                                                               printf("\n");
+                                               }
+
+                                               printf("\n};\nstatic const lws_ss_x509_t _ss_x509_%s = {\n",
+                                                               purify_csymbol(pol->trust.store->ssx509[n]->vhost_name,
+                                                               buf, sizeof(buf)));
+                                               printf("\t.vhost_name = \"%s\",\n", pol->trust.store->ssx509[n]->vhost_name);
+                                               printf("\t.ca_der = _ss_der_%s,\n",
+                                                       purify_csymbol(pol->trust.store->ssx509[n]->vhost_name,
+                                                               buf, sizeof(buf)));
+                                               printf("\t.ca_der_len = %zu,\n", pol->trust.store->ssx509[n]->ca_der_len);
+                                               printf("};\n");
+
+                                               est += sizeof(lws_ss_x509_t) + pol->trust.store->ssx509[n]->ca_der_len;
+                                       }
+
+                               }
+
+
+                               printf("static const lws_ss_trust_store_t _ss_ts_%s = {\n",
+                                       purify_csymbol(pol->trust.store->name,
+                                                       buf, sizeof(buf)));
+
+                               printf("\t.name = \"%s\",\n", pol->trust.store->name);
+                               printf("\t.count = %d,\n", pol->trust.store->count);
+                               printf("\t.ssx509 = {\n");
+
+                               for (n = pol->trust.store->count - 1; n >= 0 ; n--)
+                                       printf("\t\t&_ss_x509_%s,\n",
+                                               pol->trust.store->ssx509[n]->vhost_name);
+
+                               printf("\t}\n};\n");
+
+                               est += sizeof(lws_ss_trust_store_t);
+
+                       }
+               }
+
+               pol = pol->next;
+       }
+
+
+       /* dump any streamtype's http resp map */
+
+       pol = lws_ss_policy_get(context);
+       m = 0;
+
+       while (pol) {
+
+               lws_snprintf(curr, sizeof(curr), "_ssp_%s",
+                       purify_csymbol(pol->streamtype, buf, sizeof(buf)));
+
+               /* if relevant, dump http resp map */
+
+               switch (pol->protocol) {
+               case LWSSSP_H1:
+               case LWSSSP_H2:
+               case LWSSSP_WS:
+
+                       if (!pol->u.http.count_respmap)
+                               break;
+
+                       if (!m)
+                               printf("\nstatic const lws_ss_http_respmap_t ");
+                       else
+                               printf(",\n");
+                       m++;
+
+                       printf("%s_http_respmap[] = {\n", curr);
+                       for (n = 0; n < pol->u.http.count_respmap; n++) {
+                               printf("\t{ %d, 0x%x },\n",
+                                               pol->u.http.respmap[n].resp,
+                                               pol->u.http.respmap[n].state);
+
+                               est += sizeof(lws_ss_http_respmap_t);
+                       }
+                       printf("}");
+                       break;
+               }
+
+               pol = pol->next;
+       }
+
+       if (m)
+               printf(";\n");
+
+       /*
+        * The auth map
+        */
+
+       auth = lws_ss_auth_get(context);
+       if (auth)
+               printf("\nstatic const lws_ss_auth_t ");
+       prev[0] = '\0';
+
+       while (auth) {
+               lws_snprintf(curr, sizeof(curr), "_ssau_%s",
+                       purify_csymbol(auth->name, buf, sizeof(buf)));
+
+               printf("%s = {\n", curr);
+               if (prev[0])
+                       printf("\t.next = (void *)&%s,\n", prev);
+
+               printf("\t.name = \"%s\",\n", auth->name);
+               printf("\t.type= \"%s\",\n", auth->type);
+               printf("\t.streamtype = \"%s\",\n", auth->streamtype);
+               printf("\t.blob_index = %d,\n", auth->blob_index);
+               printf("}");
+               if (auth->next)
+                       printf(",");
+               else
+                       printf(";");
+               printf("\n");
+
+               lws_strncpy(prev, curr, sizeof(prev));
+
+               auth = auth->next;
+       }
+
+       if (lws_ss_auth_get(context))
+               printf("\n");
+
+       /*
+        * The streamtypes
+        */
+
+       pol = lws_ss_policy_get(context);
+
+       printf("\nstatic const lws_ss_policy_t ");
+       prev[0] = '\0';
+
+       while (pol) {
+
+               est += sizeof(*pol);
+
+               lws_snprintf(curr, sizeof(curr), "_ssp_%s",
+                       purify_csymbol(pol->streamtype, buf, sizeof(buf)));
+
+               printf("%s = {\n", curr);
+
+               if (prev[0])
+                       printf("\t.next = (void *)&%s,\n", prev);
+
+               printf("\t.streamtype = \"%s\",\n", pol->streamtype);
+               if (pol->endpoint)
+                       printf("\t.endpoint = \"%s\",\n", pol->endpoint);
+               if (pol->rideshare_streamtype)
+                       printf("\t.rideshare_streamtype = \"%s\",\n",
+                               pol->rideshare_streamtype);
+               if (pol->payload_fmt)
+                       printf("\t.payload_fmt = \"%s\",\n",
+                               pol->payload_fmt);
+               if (pol->socks5_proxy)
+                       printf("\t.socks5_proxy = \"%s\",\n",
+                               pol->socks5_proxy);
+
+               if (pol->auth)
+                       printf("\t.auth = &_ssau_%s,\n",
+                              purify_csymbol(pol->auth->name, buf, sizeof(buf)));
+
+               {
+                       lws_ss_metadata_t *nv = pol->metadata, *last = NULL;
+
+                       while (nv) {
+                               last = nv;
+                               nv = nv->next;
+                       }
+                       if (pol->metadata)
+                               printf("\t.metadata = (void *)&_md_%s_%s,\n",
+                                       purify_csymbol(pol->streamtype, buf, sizeof(buf)),
+                                       purify_csymbol(last->name, buf1, sizeof(buf1)));
+               }
+
+
+               switch (pol->protocol) {
+               case LWSSSP_H1:
+               case LWSSSP_H2:
+               case LWSSSP_WS:
+
+                       printf("\t.u = {\n\t\t.http = {\n");
+
+                       if (pol->u.http.method)
+                               printf("\t\t\t.method = \"%s\",\n",
+                                       pol->u.http.method);
+                       if (pol->u.http.url)
+                               printf("\t\t\t.url = \"%s\",\n",
+                                       pol->u.http.url);
+                       if (pol->u.http.multipart_name)
+                               printf("\t\t\t.multipart_name = \"%s\",\n",
+                                       pol->u.http.multipart_name);
+                       if (pol->u.http.multipart_filename)
+                               printf("\t\t\t.multipart_filename = \"%s\",\n",
+                                       pol->u.http.multipart_filename);
+                       if (pol->u.http.multipart_content_type)
+                               printf("\t\t\t.multipart_content_type = \"%s\",\n",
+                                       pol->u.http.multipart_content_type);
+                       if (pol->u.http.auth_preamble)
+                               printf("\t\t\t.auth_preamble = \"%s\",\n",
+                                       pol->u.http.auth_preamble);
+
+                       if (pol->u.http.respmap) {
+                               printf("\t\t\t.respmap = (void *)&%s_http_respmap,\n",
+                                               curr);
+                               printf("\t\t\t.count_respmap = %d,\n",
+                                               pol->u.http.count_respmap);
+                       }
+
+                       if (pol->u.http.blob_header[0]) {
+                               printf("\t\t\t.blob_header = {\n");
+                               for (n = 0; n < (int)LWS_ARRAY_SIZE(pol->u.http.blob_header); n++)
+                                       if (pol->u.http.blob_header[n])
+                                               printf("\t\t\t\t\"%s\",\n",
+                                                       pol->u.http.blob_header[n]);
+
+                               printf("\t\t\t},\n");
+                       }
+
+                       if (pol->protocol == LWSSSP_WS) {
+                               printf("\t\t\t.u = {\n\t\t\t\t.ws = {\n");
+                               if (pol->u.http.u.ws.subprotocol)
+                                       printf("\t\t\t\t\t.subprotocol = \"%s\",\n",
+                                               pol->u.http.u.ws.subprotocol);
+                               printf("\t\t\t\t\t.binary = %u\n", pol->u.http.u.ws.binary);
+                               printf("\t\t\t\t}\n\t\t\t},\n");
+                       }
+
+                       if (pol->u.http.resp_expect)
+                               printf("\t\t\t.resp_expect = %u,\n", pol->u.http.resp_expect);
+                       if (pol->u.http.fail_redirect)
+                               printf("\t\t\t.fail_redirect = %u,\n", pol->u.http.fail_redirect);
+
+                       printf("\t\t}\n\t},\n");
+
+                       break;
+               case LWSSSP_MQTT:
+
+                       printf("\t.u = {\n\t\t.mqtt = {\n");
+
+                       if (pol->u.mqtt.topic)
+                               printf("\t\t\t.topic = \"%s\",\n",
+                                       pol->u.mqtt.topic);
+                       if (pol->u.mqtt.subscribe)
+                               printf("\t\t\t.subscribe = \"%s\",\n",
+                                       pol->u.mqtt.subscribe);
+                       if (pol->u.mqtt.will_topic)
+                               printf("\t\t\t.will_topic = \"%s\",\n",
+                                       pol->u.mqtt.will_topic);
+                       if (pol->u.mqtt.will_message)
+                               printf("\t\t\t.will_message = \"%s\",\n",
+                                       pol->u.mqtt.will_message);
+
+                       if (pol->u.mqtt.keep_alive)
+                               printf("\t\t\t.keep_alive = %u,\n",
+                                       pol->u.mqtt.keep_alive);
+                       if (pol->u.mqtt.qos)
+                               printf("\t\t\t.qos = %u,\n",
+                                       pol->u.mqtt.qos);
+                       if (pol->u.mqtt.clean_start)
+                               printf("\t\t\t.clean_start = %u,\n",
+                                       pol->u.mqtt.clean_start);
+                       if (pol->u.mqtt.will_qos)
+                               printf("\t\t\t.will_qos = %u,\n",
+                                       pol->u.mqtt.will_qos);
+                       if (pol->u.mqtt.will_retain)
+                               printf("\t\t\t.will_retain = %u,\n",
+                                       pol->u.mqtt.will_retain);
+
+                       printf("\t\t}\n\t},\n");
+
+                       break;
+               default:
+                       lwsl_err("%s: unknown ss protocol index %d\n", __func__,
+                                       pol->protocol);
+                       goto bail;
+               }
+
+#if 0
+               const lws_ss_trust_store_t *trust_store; /**< CA certs needed for conn
+                      validation, only set between policy parsing and vhost creation */
+#endif
+
+               if (pol->retry_bo) {
+                       a = rbomap;
+                       while (a) {
+                               if (a->orig == (const char *)pol->retry_bo)
+                                       break;
+
+                               a = a->next;
+                       }
+                       if (!a)
+                               goto bail;
+
+                       printf("\t.retry_bo = &_rbo_%zu,\n", a->offset);
+               }
+
+               if (pol->timeout_ms)
+                       printf("\t.timeout_ms = %u,\n", pol->timeout_ms);
+               if (pol->flags)
+                       printf("\t.flags = 0x%x,\n", pol->flags);
+               if (pol->flags)
+                       printf("\t.priority = 0x%x,\n", (unsigned int)pol->priority);
+               if (pol->port)
+                       printf("\t.port = %u,\n", pol->port);
+               if (pol->metadata_count)
+                       printf("\t.metadata_count = %u,\n", pol->metadata_count);
+               printf("\t.protocol = %u,\n", pol->protocol);
+               if (pol->client_cert)
+                       printf("\t.client_cert = %u,\n", pol->client_cert);
+
+               if (pol->trust.store)
+                       printf("\t.trust = {.store = &_ss_ts_%s},\n",
+                               purify_csymbol(pol->trust.store->name,
+                                                       buf, sizeof(buf)));
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+               if (pol->aws_region)
+                       printf("\t.aws_region= \"%s\",\n", pol->aws_region);
+               if (pol->aws_service)
+                       printf("\t.aws_service= \"%s\",\n", pol->aws_service);
+
+#endif
+
+
+               printf("}");
+               if (pol->next)
+                       printf(",\n");
+
+               lws_strncpy(prev, curr, sizeof(prev));
+
+               lastpol = pol;
+
+               pol = pol->next;
+       }
+
+       printf(";\n");
+       if (lastpol)
+               printf("#define _ss_static_policy_entry _ssp_%s\n",
+                       purify_csymbol(lastpol->streamtype, buf, sizeof(buf)));
+
+       est += last_offset;
+
+       printf("/* estimated footprint %zu (when sizeof void * = %zu) */\n",
+                       est, sizeof(void *));
+
+       lws_ss_policy_parse_abandon(context);
+       bad = 0;
+
+bail:
+
+
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-post/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-post/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6240415
--- /dev/null
@@ -0,0 +1,61 @@
+project(lws-minimal-secure-streams-post C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-post)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams-post.c)
+       
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE)
+               if (VALGRIND)
+                       add_test(NAME sspost-warmcat COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               post_hcm_srv
+                               ${VALGRIND} --tool=memcheck
+                               $<TARGET_FILE:lws-minimal-secure-streams-post>
+                       )
+               else()
+                       add_test(NAME sspost-warmcat
+                               COMMAND lws-minimal-secure-streams-post)
+               endif()
+               set_tests_properties(sspost-warmcat
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-post
+                                    TIMEOUT 20)
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client minimal-secure-streams-post.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-post/README.md b/minimal-examples/secure-streams/minimal-secure-streams-post/README.md
new file mode 100644 (file)
index 0000000..cb9b3b3
--- /dev/null
@@ -0,0 +1,66 @@
+# lws minimal secure streams
+
+The application goes to https://warmcat.com and reads index.html there.
+
+It does it using Secure Streams... the main code in minimal-secure-streams.c
+just sets up the context and opens a secure stream of type "mintest".
+
+The handler for state changes and payloads for "mintest" is in ss-myss.c
+
+The information about how a "mintest" stream should connect and the
+protocol it uses is kept separated in policy-database.c
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-f| Force connecting to the wrong endpoint to check backoff retry flow
+-p| Run as proxy server for clients to connect to over unix domain socket
+--force-portal|Force the SS Captive Portal Detection to feel it's behind a portal
+--force-no-internet|Force the SS Captive Portal Detection to feel it can't reach the internet
+
+```
+[2019/08/12 07:16:11:0045] USR: LWS minimal secure streams [-d<verbosity>] [-f]
+[2019/08/12 07:16:12:6102] USR: myss_state: LWSSSCS_CREATING, ord 0x0
+[2019/08/12 07:16:12:6107] USR: myss_state: LWSSSCS_POLL, ord 0x0
+[2019/08/12 07:16:12:6117] N: lws_ss_client_connect: connecting h1get warmcat.com /
+[2019/08/12 07:16:12:6118] USR: myss_state: LWSSSCS_CONNECTING, ord 0x0
+[2019/08/12 07:16:13:4171] USR: myss_state: LWSSSCS_CONNECTED, ord 0x0
+[2019/08/12 07:16:13:4222] USR: myss_rx: len 1024, flags: 1
+[2019/08/12 07:16:13:4243] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4244] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4244] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4245] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4246] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4247] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4252] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4264] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4265] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4266] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4267] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4268] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4268] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4269] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4270] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4278] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4279] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4280] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4281] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4282] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4283] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4283] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4284] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4287] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4288] USR: myss_rx: len 947, flags: 0
+[2019/08/12 07:16:13:4293] USR: myss_rx: len 0, flags: 2
+[2019/08/12 07:16:13:4399] USR: myss_state: LWSSSCS_DISCONNECTED, ord 0x0
+[2019/08/12 07:16:13:4761] USR: myss_state: LWSSSCS_DESTROYING, ord 0x0
+[2019/08/12 07:16:13:4781] USR: Completed: OK
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-post/minimal-secure-streams-post.c b/minimal-examples/secure-streams/minimal-secure-streams-post/minimal-secure-streams-post.c
new file mode 100644 (file)
index 0000000..b5a5f34
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+ * lws-minimal-secure-streams-post
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates a minimal http client using secure streams api.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.
+ *
+ * This example is built two different ways from the same source... one includes
+ * the policy everything needed to fulfil the stream directly.  The other -client
+ * variant has no policy itself and some other minor init changes, and connects
+ * to the -proxy example to actually get the connection done.
+ *
+ * In the -client build case, the example does not even init the tls libraries
+ * since the proxy part will take care of all that.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#include <assert.h>
+
+/*
+ * uncomment to force network traffic through 127.0.0.1:1080
+ *
+ * On your local machine, you can run a SOCKS5 proxy like this
+ *
+ * $ ssh -N -D 0.0.0.0:1080 localhost -v
+ *
+ * If enabled, this also fetches a remote policy that also
+ * specifies that all traffic should go through the remote
+ * proxy.
+ */
+// #define VIA_LOCALHOST_SOCKS
+
+static int interrupted, bad = 1, force_cpd_fail_portal,
+          force_cpd_fail_no_internet;
+static unsigned int timeout_ms = 3000;
+static lws_state_notify_link_t nl;
+
+static const char * const postbody =
+       "--boundary\r\n"
+       "Content-Disposition: form-data; name=\"text\"\r\n"
+       "\r\n"
+       "value1\r\n"
+       "--boundary\r\n"
+       "Content-Disposition: form-data; "
+               "name=\"field2\"; filename=\"example.txt\"\r\n"
+       "\r\n"
+       "value2\r\n"
+       "00-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "01-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "02-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "03-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "04-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "05-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "06-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "07-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "08-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "09-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "0a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "0b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "0c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "0d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "0e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "0f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "10-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "11-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "12-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "13-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "14-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "15-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "16-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "17-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "18-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "19-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "1a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "1b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "1c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "1d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "1e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "1f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "20-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "21-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "22-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "23-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "24-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "25-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "26-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "27-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "28-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "29-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "2a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "2b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "2c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "2d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "2e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "2f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "30-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "31-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "32-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "33-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "34-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "35-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "36-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "37-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "38-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "39-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "3a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "3b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "3c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "3d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "3e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "3f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "40-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "41-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "42-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "43-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "44-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "45-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "46-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "47-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "48-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "49-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "4a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "4b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "4c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "4d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "4e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "4f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
+       "--boundary--\r\n";
+
+/*
+ * If the -proxy app is fulfilling our connection, then we don't need to have
+ * the policy in the client.
+ *
+ * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over
+ * a Unix Domain Socket.  To test that, you need to separately run the
+ * ./lws-minimal-secure-streams-proxy test app on the same machine.
+ */
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+#if defined(VIA_LOCALHOST_SOCKS)
+         "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+#endif
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+               "{\"isrg_root_x1\": \""
+       "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="
+                "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": ["
+               /*
+                * "fetch_policy" decides from where the real policy
+                * will be fetched, if present.  Otherwise the initial
+                * policy is treated as the whole, hardcoded, policy.
+                */
+               "{\"fetch_policy\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+#if defined(VIA_LOCALHOST_SOCKS)
+                       "\"http_url\":"         "\"policy/minimal-proxy-socks.json\","
+#else
+                       "\"http_url\":"         "\"policy/minimal-proxy.json\","
+#endif
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}},{"
+                       /*
+                        * "captive_portal_detect" describes
+                        * what to do in order to check if the path to
+                        * the Internet is being interrupted by a
+                        * captive portal.  If there's a larger policy
+                        * fetched from elsewhere, it should also include
+                        * this since it needs to be done at least after
+                        * every DHCP acquisition
+                        */
+                   "\"captive_portal_detect\": {"
+                        "\"endpoint\": \"connectivitycheck.android.com\","
+                       "\"http_url\": \"generate_204\","
+                       "\"port\": 80,"
+                        "\"protocol\": \"h1\","
+                        "\"http_method\": \"GET\","
+                        "\"opportunistic\": true,"
+                        "\"http_expect\": 204,"
+                       "\"http_fail_redirect\": true"
+                "}}"
+       "]}"
+;
+
+#endif
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+
+       size_t pos;
+       size_t len;
+} myss_t;
+
+#if !defined(LWS_SS_USE_SSPC)
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+#endif
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+//     myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       if (m->pos == m->len)
+               return LWSSSSRET_TX_DONT_SEND;
+
+       if (m->len - m->pos < *len)
+               *len = m->len - m->pos;
+
+       *flags = 0;
+       if (!m->pos)
+               *flags |= LWSSS_FLAG_SOM;
+
+       memcpy(buf, postbody + m->pos, *len);
+
+       m->pos += *len;
+
+       if (m->pos == m->len)
+               *flags |= LWSSS_FLAG_EOM;
+
+       lwsl_notice("%s: write %d flags %d\n", __func__, (int)*len, (int)*flags);
+
+       if (m->pos != m->len)
+               return lws_ss_request_tx(m->ss);
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: h %p, %s, ord 0x%x\n", __func__, m->ss,
+                       lws_ss_state_name((int)state), (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+
+               /*
+                * CREATING is only coming after we have asked the upstream
+                * proxy to create the stream and it has been allowed.
+                */
+
+               if (lws_ss_set_metadata(m->ss, "ctype",
+                                   "multipart/form-data;boundary=\"boundary\"",
+                                   39))
+                       return LWSSSSRET_DISCONNECT_ME;
+
+               /* provide a hint about the payload size */
+               m->pos = 0;
+               m->len = strlen(postbody);
+
+               return lws_ss_request_tx_len(m->ss, (unsigned long)strlen(postbody));
+
+       case LWSSSCS_CONNECTED:
+               return lws_ss_request_tx(m->ss);
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               break;
+       case LWSSSCS_QOS_ACK_REMOTE:
+               lwsl_notice("%s: LWSSSCS_QOS_ACK_REMOTE\n", __func__);
+               break;
+
+       case LWSSSCS_TIMEOUT:
+               lwsl_notice("%s: LWSSSCS_TIMEOUT\n", __func__);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+#if !defined(LWS_SS_USE_SSPC)
+
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+#endif
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+
+#if !defined(LWS_SS_USE_SSPC)
+
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+
+#endif
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+                       lws_ss_info_t ssi;
+
+                       /* We're making an outgoing secure stream ourselves */
+
+                       memset(&ssi, 0, sizeof(ssi));
+                       ssi.handle_offset = offsetof(myss_t, ss);
+                       ssi.opaque_user_data_offset = offsetof(myss_t,
+                                                              opaque_data);
+                       ssi.rx = myss_rx;
+                       ssi.tx = myss_tx;
+                       ssi.state = myss_state;
+                       ssi.user_alloc = sizeof(myss_t);
+                       ssi.streamtype = "minpost";
+
+                       if (lws_ss_create(context, 0, &ssi, NULL, NULL,
+                                         NULL, NULL)) {
+                               lwsl_err("%s: failed to create secure stream\n",
+                                        __func__);
+                               return -1;
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams test client [-d<verb>]\n");
+
+       /* these options are mutually exclusive if given */
+
+       if (lws_cmdline_option(argc, argv, "--force-portal"))
+               force_cpd_fail_portal = 1;
+
+       if (lws_cmdline_option(argc, argv, "--force-no-internet"))
+               force_cpd_fail_no_internet = 1;
+
+       if ((p = lws_cmdline_option(argc, argv, "--timeout_ms")))
+               timeout_ms = (unsigned int)atoi(p);
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#else
+       info.pss_policies_json = default_ss_policy;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+#if !defined(LWS_SS_USE_SSPC)
+       /*
+        * If we're being a proxied client, the proxy does all this
+        */
+
+       /*
+        * Set the related lws_system blobs
+        *
+        * ...direct_set() sets a pointer, so the thing pointed to has to have
+        * a suitable lifetime, eg, something that already exists on the heap or
+        * a const string in .rodata like this
+        */
+
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_SERIAL, 0),
+                                  (const uint8_t *)"SN12345678", 10);
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION, 0),
+                                  (const uint8_t *)"v0.01", 5);
+
+       /*
+        * ..._heap_append() appends to a buflist kind of arrangement on heap,
+        * just one block is fine, otherwise it will concatenate the fragments
+        * in the order they were appended (and take care of freeing them at
+        * context destroy time). ..._heap_empty() is also available to remove
+        * everything that was already allocated.
+        *
+        * Here we use _heap_append() just so it's tested as well as direct set.
+        */
+
+       lws_system_blob_heap_append(lws_system_get_blob(context,
+                                   LWS_SYSBLOB_TYPE_DEVICE_TYPE, 0),
+                                  (const uint8_t *)"spacerocket", 11);
+#endif
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-proxy/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-proxy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0d0f548
--- /dev/null
@@ -0,0 +1,28 @@
+project(lws-minimal-secure-streams-proxy C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-proxy)
+set(SRCS main.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_PROXY_API 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-proxy/README.md b/minimal-examples/secure-streams/minimal-secure-streams-proxy/README.md
new file mode 100644 (file)
index 0000000..ab5cbcb
--- /dev/null
@@ -0,0 +1,33 @@
+# lws minimal secure streams proxy
+
+Operates as a secure streams proxy, by default on a listening unix domain socket
+"proxy.ss.lws" in the Linux abstract namespace.
+
+Give -p <port> to have it listen on a specific tcp port instead.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-f| Force connecting to the wrong endpoint to check backoff retry flow
+-p <port>|If not given, proxy listens on a Unix Domain Socket, if given listen on specified tcp port
+-i <iface>|Optionally specify the UDS path (no -p) or network interface to bind to (if -p also given)
+
+```
+[2020/02/26 15:41:27:5768] U: LWS secure streams Proxy [-d<verb>]
+[2020/02/26 15:41:27:5770] N: lws_ss_policy_set:     2.064KiB, pad 70%: hardcoded
+[2020/02/26 15:41:27:5771] N: lws_tls_client_create_vhost_context: using mem client CA cert 1391
+[2020/02/26 15:41:27:8681] N: lws_ss_policy_set:     4.512KiB, pad 15%: updated
+[2020/02/26 15:41:27:8682] N: lws_tls_client_create_vhost_context: using mem client CA cert 837
+[2020/02/26 15:41:27:8683] N: lws_tls_client_create_vhost_context: using mem client CA cert 1043
+[2020/02/26 15:41:27:8684] N: lws_tls_client_create_vhost_context: using mem client CA cert 1167
+[2020/02/26 15:41:27:8684] N: lws_tls_client_create_vhost_context: using mem client CA cert 1391
+[2020/02/26 15:41:28:4226] N: ss_api_amazon_auth_rx: acquired 567-byte api.amazon.com auth token, exp 3600s
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-proxy/main.c b/minimal-examples/secure-streams/minimal-secure-streams-proxy/main.c
new file mode 100644 (file)
index 0000000..0e1fbb5
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * lws-minimal-secure-streams-proxy
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This is the proxy part for examples built to use it to connect to... it has
+ * the policy and the core SS function, but it doesn't contain any of the user
+ * code "business logic"... that's in the clients.
+ *
+ * The proxy side has the policy and performs the onward connection proxying
+ * fulfilment.  The clients state the streamtype name they want and ask for the
+ * client to do the connection part.
+ *
+ * Rideshare information is being parsed out at the proxy side; the SSS RX part
+ * also brings with it rideshare names.
+ *
+ * Metadata is passed back over SSS from the client in the TX messages for the
+ * proxy to use per the policy.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+#if defined(__APPLE__) || defined(__linux__)
+#include <execinfo.h>
+#include <assert.h>
+#endif
+
+static int interrupted, bad = 1, port = 0 /* unix domain socket */;
+static const char *ibind = NULL; /* default to unix domain skt "proxy.ss.lws" */
+static lws_state_notify_link_t nl;
+static struct lws_context *context;
+
+/*
+ * We just define enough policy so it can fetch the latest one securely
+ */
+
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+               "{\"isrg_root_x1\": \""
+       "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="
+               "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": [{"
+               "\"captive_portal_detect\": {"
+                       "\"endpoint\": \"connectivitycheck.android.com\","
+                       "\"http_url\": \"generate_204\","
+                       "\"port\": 80,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"opportunistic\": true,"
+                       "\"http_expect\": 204,"
+                       "\"http_fail_redirect\": true"
+               "},"
+               "\"fetch_policy\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"policy/minimal-proxy-v4.2-v2.json\","
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}}"
+       "}"
+;
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+static char *aws_keyid = NULL,
+           *aws_key = NULL;
+#endif
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+
+                       if (lws_aws_filesystem_credentials_helper(
+                                                 "~/.aws/credentials",
+                                                 "aws_access_key_id",
+                                                 "aws_secret_access_key",
+                                                 &aws_keyid, &aws_key))
+                               return -1;
+
+                       lws_ss_sigv4_set_aws_key(context, 0, aws_keyid, aws_key);
+#endif
+                       /*
+                        * At this point we have DHCP, ntp, system auth token
+                        * and we can reasonably create the proxy
+                        */
+                       if (lws_ss_proxy_create(context, ibind, port)) {
+                               lwsl_err("%s: failed to create ss proxy\n",
+                                               __func__);
+                               return -1;
+                       }
+               }
+               break;
+       case LWS_SYSTATE_POLICY_INVALID:
+               /*
+                * This is a NOP since we used direct set... but in a real
+                * system this could easily change to be done on the heap, then
+                * this would be important
+                */
+               lws_system_blob_destroy(lws_system_get_blob(context,
+                                       LWS_SYSBLOB_TYPE_AUTH,
+                                       1 /* AUTH_IDX_ROOT */));
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+#if defined(LWS_WITH_SYS_METRICS)
+
+static int
+my_metric_report(lws_metric_pub_t *mp)
+{
+       lws_metric_bucket_t *sub = mp->u.hist.head;
+       char buf[192];
+
+       do {
+               if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
+                       lwsl_user("%s: %s\n", __func__, buf);
+       } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
+
+       /* 0 = leave metric to accumulate, 1 = reset the metric */
+
+       return 1;
+}
+
+static const lws_system_ops_t system_ops = {
+       .metric_report = my_metric_report,
+};
+
+#endif
+
+static void
+sigint_handler(int sig)
+{
+       lwsl_notice("%s\n", __func__);
+       interrupted = 1;
+       lws_cancel_service(context);
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       const char *p;
+       int n = 0;
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       signal(SIGINT, sigint_handler);
+
+       /* connect to ssproxy via UDS by default, else via tcp with this port */
+       if ((p = lws_cmdline_option(argc, argv, "-p")))
+               port = atoi(p);
+
+       /* UDS "proxy.ss.lws" in abstract namespace, else this socket path;
+        * when -p given this can specify the network interface to bind to */
+       if ((p = lws_cmdline_option(argc, argv, "-i")))
+               ibind = p;
+
+       lwsl_user("LWS secure streams Proxy [-d<verb>]\n");
+
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.fd_limit_per_thread = 1 + 26 + 1;
+       info.pss_policies_json = default_ss_policy;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+
+       /* integrate us with lws system state management when context created */
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       info.pt_serv_buf_size = (unsigned int)((6144 * 2) + 2048);
+       info.max_http_header_data = (unsigned short)(6144 + 2048);
+
+#if defined(LWS_WITH_SYS_METRICS)
+       info.system_ops = &system_ops;
+       info.metrics_prefix = "ssproxy";
+#endif
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* the event loop */
+
+       do {
+               n = lws_service(context, 0);
+       } while (n >= 0 && !interrupted);
+
+       bad = 0;
+
+#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
+       if (aws_keyid)
+               free(aws_keyid);
+       if (aws_key)
+               free(aws_key);
+#endif
+
+       lws_context_destroy(context);
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-seq/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-seq/CMakeLists.txt
new file mode 100644 (file)
index 0000000..47317ba
--- /dev/null
@@ -0,0 +1,27 @@
+project(lws-minimal-secure-streams-seq C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-seq)
+set(SRCS minimal-secure-streams.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SEQUENCER 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-seq/README.md b/minimal-examples/secure-streams/minimal-secure-streams-seq/README.md
new file mode 100644 (file)
index 0000000..6af2e25
--- /dev/null
@@ -0,0 +1,65 @@
+# lws minimal sequre streams seq
+
+The application goes to https://warmcat.com and reads index.html there.
+
+It does it using Secure Streams... the main code in minimal-secure-streams.c
+just sets up the context and opens a secure stream of type "mintest".
+
+The handler for state changes and payloads for "mintest" is in ss-myss.c
+
+The information about how a "mintest" stream should connect and the
+protocol it uses is kept separated in policy-database.c
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-f| Force connecting to the wrong endpoint to check backoff retry flow
+
+```
+ $ ./lws-minimal-secure-streams-seq
+[2018/03/04 14:43:20:8562] USER: LWS minimal http client
+[2018/03/04 14:43:20:8571] NOTICE: Creating Vhost 'default' port -1, 1 protocols, IPv6 on
+[2018/03/04 14:43:20:8616] NOTICE: created client ssl context for default
+[2018/03/04 14:43:20:8617] NOTICE: lws_client_connect_2: 0x1814dc0: address warmcat.com
+[2018/03/04 14:43:21:1496] NOTICE: lws_client_connect_2: 0x1814dc0: address warmcat.com
+[2018/03/04 14:43:22:0154] NOTICE: lws_client_interpret_server_handshake: incoming content length 26520
+[2018/03/04 14:43:22:0154] NOTICE: lws_client_interpret_server_handshake: client connection up
+[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:0169] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
+[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:0174] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
+[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:0179] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
+[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3010] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
+[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3015] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
+[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3020] USER: RECEIVE_CLIENT_HTTP_READ: read 1015
+[2018/03/04 14:43:22:3022] USER: RECEIVE_CLIENT_HTTP_READ: read 1024
+[2018/03/04 14:43:22:3022] USER: RECEIVE_CLIENT_HTTP_READ: read 974
+[2018/03/04 14:43:22:3022] NOTICE: lws_http_client_read: transaction completed says -1
+[2018/03/04 14:43:23:3042] USER: Completed
+```
+
+
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-seq/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams-seq/minimal-secure-streams.c
new file mode 100644 (file)
index 0000000..0e21efb
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * lws-minimal-secure-streams-seq
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates the a minimal http client using secure streams api.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.
+ *
+ * This is the "secure streams" api equivalent of minimal-http-client...
+ * it shows how to use a sequencer to make it easy to build more complex
+ * schemes on top of this example.
+ *
+ * The layering looks like this
+ *
+ *                        lifetime
+ *
+ * ------   app   ------  process
+ * ----  sequencer  ----  process
+ * --- secure stream ---  process
+ * -------  wsi  -------  connection
+ *
+ * see minimal-secure-streams for a similar example without the sequencer.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted, bad = 1, flag_conn_fail, flag_h1post;
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "300,"
+                       "\"svalidhup\":"        "310"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Need to be in order from root cert... notice sometimes as
+                * with Let's Encrypt there are multiple possible validation
+                * paths, all the pieces for one validation path must be
+                * given, excluding the server cert itself.  Let's Encrypt
+                * intermediate is signed by their ISRG Root CA but also is
+                * cross-signed by an IdenTrust intermediate that's widely
+                * deployed in browsers.  We use the ISRG path because that
+                * way we can skip the extra IdenTrust root cert.
+                */
+               "{\"isrg_root_x1\": \""
+       "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="
+                 "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": [" /* the supported stream types */
+               "{\"mintest\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"index.html\","
+                       "\"plugins\":"          "[],"
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}},"
+               "{\"mintest-fail\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "22,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"index.html\","
+                       "\"plugins\":"          "[],"
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}},"
+               "{\"minpost\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"POST\","
+                       "\"http_url\":"         "\"testserver/formtest\","
+                       "\"plugins\":"          "[],"
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}}"
+         "]"
+       "}"
+;
+
+typedef struct myss {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+} myss_t;
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+//     myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, we let the sequencer know it
+        * was a success
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       // myss_t *m = (myss_t *)userobj;
+
+       /* in this example, we don't send any payload */
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+               lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_request_tx(m->ss);
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+typedef enum {
+       SEQ_IDLE,
+       SEQ_TRY_CONNECT,
+       SEQ_RECONNECT_WAIT,
+       SEQ_CONNECTED,
+} myseq_state_t;
+
+typedef struct myseq {
+       struct lws_ss_handle    *ss;
+
+       myseq_state_t           state;
+       int                     http_resp;
+
+       uint16_t                try;
+} myseq_t;
+
+/*
+ * This defines the sequence of things the test app does.
+ */
+
+static lws_seq_cb_return_t
+min_sec_str_sequencer_cb(struct lws_sequencer *seq, void *user, int event,
+                        void *v, void *a)
+{
+       struct myseq *s = (struct myseq *)user;
+       lws_ss_info_t ssi;
+
+       switch ((int)event) {
+
+       /* these messages are created just by virtue of being a sequencer */
+
+       case LWSSEQ_CREATED: /* our sequencer just got started */
+               s->state = SEQ_IDLE;
+               lwsl_notice("%s: LWSSEQ_CREATED\n", __func__);
+
+               /* We're making an outgoing secure stream ourselves */
+
+               memset(&ssi, 0, sizeof(ssi));
+               ssi.handle_offset = offsetof(myss_t, ss);
+               ssi.opaque_user_data_offset = offsetof(myss_t, opaque_data);
+               ssi.rx = myss_rx;
+               ssi.tx = myss_tx;
+               ssi.state = myss_state;
+               ssi.user_alloc = sizeof(myss_t);
+
+               /* requested to fail (to check backoff)? */
+               if (flag_conn_fail)
+                       ssi.streamtype = "mintest-fail";
+               else
+                       /* request to check h1 POST */
+                       if (flag_h1post)
+                               ssi.streamtype = "minpost";
+                       else
+                               /* default to h1 GET */
+                               ssi.streamtype = "mintest";
+
+               if (lws_ss_create(lws_seq_get_context(seq), 0, &ssi, NULL,
+                                 &s->ss, seq, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+
+                       return LWSSEQ_RET_DESTROY;
+               }
+               break;
+
+       case LWSSEQ_DESTROYED:
+               lwsl_notice("%s: LWSSEQ_DESTROYED\n", __func__);
+               break;
+
+       case LWSSEQ_TIMED_OUT: /* current step timed out */
+               if (s->state == SEQ_RECONNECT_WAIT)
+                       return lws_ss_request_tx(s->ss);
+               break;
+
+       /*
+        * These messages are created because we have a secure stream that was
+        * bound to this sequencer at creation time.  It copies its state
+        * events to us as its sequencer parent.  v is the lws_ss_handle_t *
+        */
+
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_CREATING:
+               lwsl_info("%s: seq LWSSSCS_CREATING\n", __func__);
+               return lws_ss_request_tx(s->ss);
+
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_DISCONNECTED:
+               lwsl_info("%s: seq LWSSSCS_DISCONNECTED\n", __func__);
+               break;
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_UNREACHABLE:
+               lwsl_info("%s: seq LWSSSCS_UNREACHABLE\n", __func__);
+               break;
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_AUTH_FAILED:
+               lwsl_info("%s: seq LWSSSCS_AUTH_FAILED\n", __func__);
+               break;
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_CONNECTED:
+               lwsl_info("%s: seq LWSSSCS_CONNECTED\n", __func__);
+               break;
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_CONNECTING:
+               lwsl_info("%s: seq LWSSSCS_CONNECTING\n", __func__);
+               break;
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_DESTROYING:
+               lwsl_info("%s: seq LWSSSCS_DESTROYING\n", __func__);
+               break;
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_POLL:
+               /* somebody called lws_ss_poll() on the stream */
+               lwsl_info("%s: seq LWSSSCS_POLL\n", __func__);
+               break;
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_ALL_RETRIES_FAILED:
+               lwsl_info("%s: seq LWSSSCS_ALL_RETRIES_FAILED\n", __func__);
+               interrupted = 1;
+               break;
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_QOS_ACK_REMOTE:
+               lwsl_info("%s: seq LWSSSCS_QOS_ACK_REMOTE\n", __func__);
+               break;
+       case LWSSEQ_SS_STATE_BASE + LWSSSCS_QOS_ACK_LOCAL:
+               lwsl_info("%s: seq LWSSSCS_QOS_ACK_LOCAL\n", __func__);
+               break;
+
+       /*
+        * This is the message we send from the ss handler to inform the
+        * sequencer we had the payload properly
+        */
+
+       case LWSSEQ_USER_BASE:
+               bad = 0;
+               interrupted = 1;
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSEQ_RET_CONTINUE;
+}
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       lws_seq_info_t i;
+       const char *p;
+       myseq_t *ms;
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS minimal secure streams [-d<verbosity>][-f][--h1post]\n");
+
+       flag_conn_fail = !!lws_cmdline_option(argc, argv, "-f");
+       flag_h1post = !!lws_cmdline_option(argc, argv, "--h1post");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.fd_limit_per_thread = 1 + 1 + 1;
+       info.pss_policies_json = default_ss_policy;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /*
+        * Create the sequencer that performs the steps of the test action
+        * from inside the event loop.
+        */
+
+       memset(&i, 0, sizeof(i));
+       i.context       = context;
+       i.user_size     = sizeof(myseq_t);
+       i.puser         = (void **)&ms;
+       i.cb            = min_sec_str_sequencer_cb;
+       i.name          = "min-sec-stream-seq";
+
+       if (!lws_seq_create(&i)) {
+               lwsl_err("%s: failed to create sequencer\n", __func__);
+               goto bail;
+       }
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+bail:
+       lws_context_destroy(context);
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server-raw/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-server-raw/CMakeLists.txt
new file mode 100644 (file)
index 0000000..205f502
--- /dev/null
@@ -0,0 +1,27 @@
+project(lws-minimal-secure-streams-server-raw C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-server-raw)
+set(SRCS main.c ss-server.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_SYS_SMD 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server-raw/README.md b/minimal-examples/secure-streams/minimal-secure-streams-server-raw/README.md
new file mode 100644 (file)
index 0000000..9580c4e
--- /dev/null
@@ -0,0 +1,54 @@
+# lws minimal secure streams server raw
+
+The application sets up a raw tcp server on localhost:7681
+
+It does it using Secure Streams... information about how the server should
+operate is held in JSON policy in main.c
+
+Connecting to the server using `echo "hello" | nc --no-shutdown 127.0.0.1 7681`
+will send "hello" which is hexdumped to console by the rx function, then
+will receive an incrementing message at 100ms intervals.
+
+Note there are two incomaptible versions of netcat around, this is from Fedora's
+nmap-ncat, the --no-shutdown is needed to stop it hanging up itself after it
+has sent its stdin.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+[2020/07/28 10:25:54:6747] U: LWS Secure Streams Server Raw
+[2020/07/28 10:25:54:7194] N: LWS: 4.0.99-v4.0.0-247-g58be599aa, loglevel 1031
+[2020/07/28 10:25:54:7198] N: NET CLI SRV H1 H2 WS MQTT SS-JSON-POL SSPROX ASYNC_DNS IPv6-absent
+[2020/07/28 10:25:54:9376] N: lws_adopt_descriptor_vhost2: wsi 0x5317d30, vhost system ss_handle (nil)
+[2020/07/28 10:25:54:9442] N: lws_adopt_descriptor_vhost2: wsi 0x53182c0, vhost system ss_handle (nil)
+[2020/07/28 10:25:54:9920] N: smd_cb: creating server stream
+[2020/07/28 10:25:54:9963] N: lws_ss_create: created server myrawserver
+[2020/07/28 10:26:00:1065] N: secstream_raw: RAW_ADOPT
+[2020/07/28 10:26:00:1068] N: lws_adopt_descriptor_vhost2: wsi 0x531a6b0, vhost myrawserver ss_handle 0x5319ac0
+[2020/07/28 10:26:00:1088] U: myss_raw_state: 0x531aad0 LWSSSCS_CREATING, ord 0x0
+[2020/07/28 10:26:00:1094] U: myss_raw_state: 0x531aad0 LWSSSCS_CONNECTING, ord 0x0
+[2020/07/28 10:26:00:1096] U: myss_raw_state: 0x531aad0 LWSSSCS_CONNECTED, ord 0x0
+[2020/07/28 10:26:00:1172] U: myss_raw_rx: len 6, flags: 0
+[2020/07/28 10:26:02:8516] U: myss_raw_state: 0x531aad0 LWSSSCS_DISCONNECTED, ord 0x0
+[2020/07/28 10:26:02:8545] U: myss_raw_state: 0x531aad0 LWSSSCS_DESTROYING, ord 0x0
+^C[2020/07/28 10:26:04:9608] U: myss_raw_state: 0x5319ac0 LWSSSCS_DESTROYING, ord 0x0
+[2020/07/28 10:26:04:9723] U: Completed: OK
+```
+
+```
+$ echo "hello" | nc --no-shutdown 127.0.0.1 7681
+hello from raw 0
+hello from raw 1
+hello from raw 2
+...
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server-raw/main.c b/minimal-examples/secure-streams/minimal-secure-streams-server-raw/main.c
new file mode 100644 (file)
index 0000000..95c49f4
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * lws-minimal-secure-streams-server
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+extern const lws_ss_info_t ssi_client, ssi_server;
+
+static struct lws_context *context;
+int interrupted, bad = 1;
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+         "\"s\": ["
+
+               /*
+                * This streamtype represents a raw server listening on :7681,
+                * without tls
+                */
+
+               "{\"myrawserver\": {"
+                       /* if given, "endpoint" is network if to bind to */
+                       "\"server\":"           "true,"
+                       "\"port\":"             "7681,"
+                       "\"protocol\":"         "\"raw\""
+               "}}"
+
+         "]"
+       "}"
+;
+
+static int
+smd_cb(void *opaque, lws_smd_class_t c, lws_usec_t ts, void *buf, size_t len)
+{
+       if ((c & LWSSMDCL_SYSTEM_STATE) &&
+           !lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
+
+               /* create the secure streams */
+
+               lwsl_notice("%s: creating server stream\n", __func__);
+
+               if (lws_ss_create(context, 0, &ssi_server, NULL, NULL,
+                                 NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+       lwsl_user("LWS Secure Streams Server Raw\n");
+
+       info.options                    = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                                         LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.fd_limit_per_thread        = 1 + 6 + 1;
+       info.pss_policies_json          = default_ss_policy;
+       info.port                       = CONTEXT_PORT_NO_LISTEN;
+       info.early_smd_cb               = smd_cb;
+       info.early_smd_class_filter     = LWSSMDCL_SYSTEM_STATE;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       bad = 0;
+
+       lws_context_destroy(context);
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server-raw/ss-server.c b/minimal-examples/secure-streams/minimal-secure-streams-server-raw/ss-server.c
new file mode 100644 (file)
index 0000000..4d395d4
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * lws-minimal-secure-streams-server
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <assert.h>
+
+extern int interrupted, bad;
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+
+       lws_sorted_usec_list_t          sul;
+       int                             count;
+       char                            upgraded;
+
+} myss_srv_t;
+
+/*
+ * This is the Secure Streams Server RX and TX
+ */
+
+static lws_ss_state_return_t
+myss_raw_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+//     myss_srv_t *m = (myss_srv_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+/* this is the callback that mediates sending the incrementing number */
+
+static void
+spam_sul_cb(struct lws_sorted_usec_list *sul)
+{
+       myss_srv_t *m = lws_container_of(sul, myss_srv_t, sul);
+
+       if (!lws_ss_request_tx(m->ss))
+               lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, spam_sul_cb,
+                        100 * LWS_US_PER_MS);
+}
+
+static lws_ss_state_return_t
+myss_raw_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       myss_srv_t *m = (myss_srv_t *)userobj;
+
+       *flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
+
+       *len = (unsigned int)lws_snprintf((char *)buf, *len, "hello from raw %d\n", m->count++);
+
+       lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, spam_sul_cb,
+                        100 * LWS_US_PER_MS);
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_raw_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_srv_t *m = (myss_srv_t *)userobj;
+
+       lwsl_user("%s: %p %s, ord 0x%x\n", __func__, m->ss,
+                 lws_ss_state_name((int)state), (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_DISCONNECTED:
+               lws_sul_cancel(&m->sul);
+               break;
+       case LWSSSCS_CONNECTED:
+               return lws_ss_request_tx(m->ss);
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+const lws_ss_info_t ssi_server = {
+       .handle_offset                  = offsetof(myss_srv_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_srv_t, opaque_data),
+       .streamtype                     = "myrawserver",
+       .rx                             = myss_raw_rx,
+       .tx                             = myss_raw_tx,
+       .state                          = myss_raw_state,
+       .user_alloc                     = sizeof(myss_srv_t),
+};
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-server/CMakeLists.txt
new file mode 100644 (file)
index 0000000..19dff5a
--- /dev/null
@@ -0,0 +1,28 @@
+project(lws-minimal-secure-streams-server C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-server)
+set(SRCS main.c ss-client.c ss-server.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_SYS_SMD 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server/README.md b/minimal-examples/secure-streams/minimal-secure-streams-server/README.md
new file mode 100644 (file)
index 0000000..6e98f11
--- /dev/null
@@ -0,0 +1,72 @@
+# lws minimal secure streams server
+
+The application sets up a tls + ws server on https://localhost:7681
+
+It does it using Secure Streams... information about how the server should
+operate is held in JSON policy in main.c
+
+Visiting the server in a modern browser will fetch some html + JS, the JS will
+create a ws link back to the server and the server will spam an incrementing
+number that is displayed in the browser every 100ms.
+
+The app also has a SS client that works, but it's disabled by default since
+we're interested in server.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+[2020/07/27 10:51:04:8994] U: LWS Secure Streams Server
+[2020/07/27 10:51:04:9440] N: LWS: 4.0.99-v4.0.0-245-ge6eb4417a, loglevel 1031
+[2020/07/27 10:51:04:9444] N: NET CLI SRV H1 H2 WS MQTT SS-JSON-POL SSPROX ASYNC_DNS IPv6-absent
+[2020/07/27 10:51:05:1685] N: lws_adopt_descriptor_vhost2: wsi 0x5317d30, vhost system ss_handle (nil)
+[2020/07/27 10:51:05:1753] N: lws_adopt_descriptor_vhost2: wsi 0x53182c0, vhost system ss_handle (nil)
+[2020/07/27 10:51:05:2129] N: lws_ss_policy_parser_cb: server 'self_localhost' keep 52 0x5318cc0
+[2020/07/27 10:51:05:2134] N: lws_ss_policy_parser_cb: server 'self_localhost_key' keep 53 0x5318cf8
+[2020/07/27 10:51:05:2192] N: lws_ss_policy_ref_trust_store: le_via_isrg trust store initial 'isrg_root_x1'
+[2020/07/27 10:51:05:7804] N: smd_cb: creating server stream
+[2020/07/27 10:51:05:7851] N:  Vhost 'myserver' using TLS mode
+[2020/07/27 10:51:05:8660] N:  SSL ECDH curve 'prime256v1'
+[2020/07/27 10:51:06:1035] N:    vhost myserver: cert expiry: 729599d
+[2020/07/27 10:51:06:1039] N: lws_ss_create: created server myserver
+[2020/07/27 10:51:11:8650] N: lws_adopt_descriptor_vhost2: wsi 0x5b046e0, vhost myserver ss_handle 0x56e2be0
+[2020/07/27 10:51:11:8672] U: myss_srv_state: 0x5b52f60 LWSSSCS_CREATING, ord 0x0
+[2020/07/27 10:51:11:8693] U: myss_srv_state: 0x5b52f60 LWSSSCS_CONNECTING, ord 0x0
+[2020/07/27 10:51:11:8696] U: myss_srv_state: 0x5b52f60 LWSSSCS_CONNECTED, ord 0x0
+[2020/07/27 10:51:11:9743] U: myss_srv_state: 0x5ba2bd0 LWSSSCS_CREATING, ord 0x0
+[2020/07/27 10:51:11:9747] U: myss_srv_state: 0x5ba2bd0 LWSSSCS_CONNECTING, ord 0x0
+[2020/07/27 10:51:11:9747] U: myss_srv_state: 0x5ba2bd0 LWSSSCS_CONNECTED, ord 0x0
+[2020/07/27 10:51:12:0192] U: myss_srv_state: 0x5bad0a0 LWSSSCS_CREATING, ord 0x0
+[2020/07/27 10:51:12:0193] U: myss_srv_state: 0x5bad0a0 LWSSSCS_CONNECTING, ord 0x0
+[2020/07/27 10:51:12:0194] U: myss_srv_state: 0x5bad0a0 LWSSSCS_CONNECTED, ord 0x0
+[2020/07/27 10:51:12:0306] N: secstream_h1: LWS_CALLBACK_HTTP
+[2020/07/27 10:51:12:0329] U: myss_srv_state: 0x5bad0a0 LWSSSCS_SERVER_TXN, ord 0x0
+[2020/07/27 10:51:12:0481] N: lws_h2_ws_handshake: Server SS 0x5ba2bd0 .wsi 0x5ba27b0 switching to ws protocol
+[2020/07/27 10:51:12:0484] U: myss_srv_state: 0x5ba2bd0 LWSSSCS_SERVER_UPGRADE, ord 0x0
+[2020/07/27 10:51:12:0541] U: myss_srv_state: 0x5ba2bd0 LWSSSCS_CONNECTED, ord 0x0
+[2020/07/27 10:51:12:1222] U: myss_srv_state: 0x5bd1100 LWSSSCS_CREATING, ord 0x0
+[2020/07/27 10:51:12:1222] U: myss_srv_state: 0x5bd1100 LWSSSCS_CONNECTING, ord 0x0
+[2020/07/27 10:51:12:1223] U: myss_srv_state: 0x5bd1100 LWSSSCS_CONNECTED, ord 0x0
+[2020/07/27 10:51:12:1242] N: lws_h2_ws_handshake: Server SS 0x5bd1100 .wsi 0x5bd0ce0 switching to ws protocol
+[2020/07/27 10:51:12:1243] U: myss_srv_state: 0x5bd1100 LWSSSCS_SERVER_UPGRADE, ord 0x0
+[2020/07/27 10:51:12:1246] U: myss_srv_state: 0x5bd1100 LWSSSCS_CONNECTED, ord 0x0
+^C[2020/07/27 10:51:15:2809] U: myss_srv_state: 0x5bad0a0 LWSSSCS_DISCONNECTED, ord 0x0
+[2020/07/27 10:51:15:2838] U: myss_srv_state: 0x5bad0a0 LWSSSCS_DESTROYING, ord 0x0
+[2020/07/27 10:51:15:2938] U: myss_srv_state: 0x5ba2bd0 LWSSSCS_DISCONNECTED, ord 0x0
+[2020/07/27 10:51:15:2946] U: myss_srv_state: 0x5ba2bd0 LWSSSCS_DESTROYING, ord 0x0
+[2020/07/27 10:51:15:2952] U: myss_srv_state: 0x5bd1100 LWSSSCS_DISCONNECTED, ord 0x0
+[2020/07/27 10:51:15:2953] U: myss_srv_state: 0x5bd1100 LWSSSCS_DESTROYING, ord 0x0
+[2020/07/27 10:51:15:2960] U: myss_srv_state: 0x5b52f60 LWSSSCS_DISCONNECTED, ord 0x0
+[2020/07/27 10:51:15:2961] U: myss_srv_state: 0x5b52f60 LWSSSCS_DESTROYING, ord 0x0
+[2020/07/27 10:51:15:3042] U: myss_srv_state: 0x56e2be0 LWSSSCS_DESTROYING, ord 0x0
+[2020/07/27 10:51:15:3378] U: Completed: OK
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server/main.c b/minimal-examples/secure-streams/minimal-secure-streams-server/main.c
new file mode 100644 (file)
index 0000000..167b0a2
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * lws-minimal-secure-streams-server
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+extern const lws_ss_info_t ssi_client, ssi_server;
+
+static struct lws_context *context;
+int interrupted, bad = 1, multipart;
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "300,"
+                       "\"svalidhup\":"        "310"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Need to be in order from root cert... notice sometimes as
+                * with Let's Encrypt there are multiple possible validation
+                * paths, all the pieces for one validation path must be
+                * given, excluding the server cert itself.  Let's Encrypt
+                * intermediate is signed by their ISRG Root CA but also is
+                * cross-signed by an IdenTrust intermediate that's widely
+                * deployed in browsers.  We use the ISRG path because that
+                * way we can skip the extra IdenTrust root cert.
+                */
+                       "{\"isrg_root_x1\": \""
+       "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="
+         "\"},"
+               /*
+                * a selfsigned cert for localhost for 100 years
+                */
+               "{\"self_localhost\": \""
+       "MIIF5jCCA86gAwIBAgIJANq50IuwPFKgMA0GCSqGSIb3DQEBCwUAMIGGMQswCQYD"
+       "VQQGEwJHQjEQMA4GA1UECAwHRXJld2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEb"
+       "MBkGA1UECgwSbGlid2Vic29ja2V0cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3Qx"
+       "HzAdBgkqhkiG9w0BCQEWEG5vbmVAaW52YWxpZC5vcmcwIBcNMTgwMzIwMDQxNjA3"
+       "WhgPMjExODAyMjQwNDE2MDdaMIGGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRXJl"
+       "d2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEbMBkGA1UECgwSbGlid2Vic29ja2V0"
+       "cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEG5vbmVA"
+       "aW52YWxpZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCjYtuW"
+       "aICCY0tJPubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8"
+       "Di3DAmHKnSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTek"
+       "LWcfI5ZZtoGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnH"
+       "KT/m6DSU0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6"
+       "jzhNyMBTJ1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQ"
+       "Ujy5N8pSNp7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAz"
+       "TK4l2pHNuC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBK"
+       "Izv9cgi9fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0"
+       "nPN1IMSnzXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzo"
+       "GMTvP/AuehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9p"
+       "sNcjTMaBQLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABo1MwUTAdBgNVHQ4EFgQU"
+       "9mYU23tW2zsomkKTAXarjr2vjuswHwYDVR0jBBgwFoAU9mYU23tW2zsomkKTAXar"
+       "jr2vjuswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEANjIBMrow"
+       "YNCbhAJdP7dhlhT2RUFRdeRUJD0IxrH/hkvb6myHHnK8nOYezFPjUlmRKUgNEDuA"
+       "xbnXZzPdCRNV9V2mShbXvCyiDY7WCQE2Bn44z26O0uWVk+7DNNLH9BnkwUtOnM9P"
+       "wtmD9phWexm4q2GnTsiL6Ul6cy0QlTJWKVLEUQQ6yda582e23J1AXqtqFcpfoE34"
+       "H3afEiGy882b+ZBiwkeV+oq6XVF8sFyr9zYrv9CvWTYlkpTQfLTZSsgPdEHYVcjv"
+       "xQ2D+XyDR0aRLRlvxUa9dHGFHLICG34Juq5Ai6lM1EsoD8HSsJpMcmrH7MWw2cKk"
+       "ujC3rMdFTtte83wF1uuF4FjUC72+SmcQN7A386BC/nk2TTsJawTDzqwOu/VdZv2g"
+       "1WpTHlumlClZeP+G/jkSyDwqNnTu1aodDmUa4xZodfhP1HWPwUKFcq8oQr148QYA"
+       "AOlbUOJQU7QwRWd1VbnwhDtQWXC92A2w1n/xkZSR1BM/NUSDhkBSUU1WjMbWg6Gg"
+       "mnIZLRerQCu1Oozr87rOQqQakPkyt8BUSNK3K42j2qcfhAONdRl8Hq8Qs5pupy+s"
+       "8sdCGDlwR3JNCMv6u48OK87F4mcIxhkSefFJUFII25pCGN5WtE4p5l+9cnO1GrIX"
+       "e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE="
+               "\"},"
+               /*
+                * the private key for above
+                */
+               "{\"self_localhost_key\": \""
+       "MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCjYtuWaICCY0tJ"
+       "PubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8Di3DAmHK"
+       "nSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTekLWcfI5ZZ"
+       "toGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnHKT/m6DSU"
+       "0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6jzhNyMBT"
+       "J1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQUjy5N8pS"
+       "Np7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAzTK4l2pHN"
+       "uC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBKIzv9cgi9"
+       "fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0nPN1IMSn"
+       "zXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzoGMTvP/Au"
+       "ehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9psNcjTMaB"
+       "QLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABAoICAFWe8MQZb37k2gdAV3Y6aq8f"
+       "qokKQqbCNLd3giGFwYkezHXoJfg6Di7oZxNcKyw35LFEghkgtQqErQqo35VPIoH+"
+       "vXUpWOjnCmM4muFA9/cX6mYMc8TmJsg0ewLdBCOZVw+wPABlaqz+0UOiSMMftpk9"
+       "fz9JwGd8ERyBsT+tk3Qi6D0vPZVsC1KqxxL/cwIFd3Hf2ZBtJXe0KBn1pktWht5A"
+       "Kqx9mld2Ovl7NjgiC1Fx9r+fZw/iOabFFwQA4dr+R8mEMK/7bd4VXfQ1o/QGGbMT"
+       "G+ulFrsiDyP+rBIAaGC0i7gDjLAIBQeDhP409ZhswIEc/GBtODU372a2CQK/u4Q/"
+       "HBQvuBtKFNkGUooLgCCbFxzgNUGc83GB/6IwbEM7R5uXqsFiE71LpmroDyjKTlQ8"
+       "YZkpIcLNVLw0usoGYHFm2rvCyEVlfsE3Ub8cFyTFk50SeOcF2QL2xzKmmbZEpXgl"
+       "xBHR0hjgon0IKJDGfor4bHO7Nt+1Ece8u2oTEKvpz5aIn44OeC5mApRGy83/0bvs"
+       "esnWjDE/bGpoT8qFuy+0urDEPNId44XcJm1IRIlG56ErxC3l0s11wrIpTmXXckqw"
+       "zFR9s2z7f0zjeyxqZg4NTPI7wkM3M8BXlvp2GTBIeoxrWB4V3YArwu8QF80QBgVz"
+       "mgHl24nTg00UH1OjZsABAoIBAQDOxftSDbSqGytcWqPYP3SZHAWDA0O4ACEM+eCw"
+       "au9ASutl0IDlNDMJ8nC2ph25BMe5hHDWp2cGQJog7pZ/3qQogQho2gUniKDifN77"
+       "40QdykllTzTVROqmP8+efreIvqlzHmuqaGfGs5oTkZaWj5su+B+bT+9rIwZcwfs5"
+       "YRINhQRx17qa++xh5mfE25c+M9fiIBTiNSo4lTxWMBShnK8xrGaMEmN7W0qTMbFH"
+       "PgQz5FcxRjCCqwHilwNBeLDTp/ZECEB7y34khVh531mBE2mNzSVIQcGZP1I/DvXj"
+       "W7UUNdgFwii/GW+6M0uUDy23UVQpbFzcV8o1C2nZc4Fb4zwBAoIBAQDKSJkFwwuR"
+       "naVJS6WxOKjX8MCu9/cKPnwBv2mmI2jgGxHTw5sr3ahmF5eTb8Zo19BowytN+tr6"
+       "2ZFoIBA9Ubc9esEAU8l3fggdfM82cuR9sGcfQVoCh8tMg6BP8IBLOmbSUhN3PG2m"
+       "39I802u0fFNVQCJKhx1m1MFFLOu7lVcDS9JN+oYVPb6MDfBLm5jOiPuYkFZ4gH79"
+       "J7gXI0/YKhaJ7yXthYVkdrSF6Eooer4RZgma62Dd1VNzSq3JBo6rYjF7Lvd+RwDC"
+       "R1thHrmf/IXplxpNVkoMVxtzbrrbgnC25QmvRYc0rlS/kvM4yQhMH3eA7IycDZMp"
+       "Y+0xm7I7jTT7AoIBAGKzKIMDXdCxBWKhNYJ8z7hiItNl1IZZMW2TPUiY0rl6yaCh"
+       "BVXjM9W0r07QPnHZsUiByqb743adkbTUjmxdJzjaVtxN7ZXwZvOVrY7I7fPWYnCE"
+       "fXCr4+IVpZI/ZHZWpGX6CGSgT6EOjCZ5IUufIvEpqVSmtF8MqfXO9o9uIYLokrWQ"
+       "x1dBl5UnuTLDqw8bChq7O5y6yfuWaOWvL7nxI8NvSsfj4y635gIa/0dFeBYZEfHI"
+       "UlGdNVomwXwYEzgE/c19ruIowX7HU/NgxMWTMZhpazlxgesXybel+YNcfDQ4e3RM"
+       "OMz3ZFiaMaJsGGNf4++d9TmMgk4Ns6oDs6Tb9AECggEBAJYzd+SOYo26iBu3nw3L"
+       "65uEeh6xou8pXH0Tu4gQrPQTRZZ/nT3iNgOwqu1gRuxcq7TOjt41UdqIKO8vN7/A"
+       "aJavCpaKoIMowy/aGCbvAvjNPpU3unU8jdl/t08EXs79S5IKPcgAx87sTTi7KDN5"
+       "SYt4tr2uPEe53NTXuSatilG5QCyExIELOuzWAMKzg7CAiIlNS9foWeLyVkBgCQ6S"
+       "me/L8ta+mUDy37K6vC34jh9vK9yrwF6X44ItRoOJafCaVfGI+175q/eWcqTX4q+I"
+       "G4tKls4sL4mgOJLq+ra50aYMxbcuommctPMXU6CrrYyQpPTHMNVDQy2ttFdsq9iK"
+       "TncCggEBAMmt/8yvPflS+xv3kg/ZBvR9JB1In2n3rUCYYD47ReKFqJ03Vmq5C9nY"
+       "56s9w7OUO8perBXlJYmKZQhO4293lvxZD2Iq4NcZbVSCMoHAUzhzY3brdgtSIxa2"
+       "gGveGAezZ38qKIU26dkz7deECY4vrsRkwhpTW0LGVCpjcQoaKvymAoCmAs8V2oMr"
+       "Ziw1YQ9uOUoWwOqm1wZqmVcOXvPIS2gWAs3fQlWjH9hkcQTMsUaXQDOD0aqkSY3E"
+       "NqOvbCV1/oUpRi3076khCoAXI1bKSn/AvR3KDP14B5toHI/F5OTSEiGhhHesgRrs"
+       "fBrpEY1IATtPq1taBZZogRqI3rOkkPk="
+               "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": ["
+               /*
+                * Client streamtypes
+                */
+
+               "{\"mintest\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h2\","
+                       "\"http_method\":"      "\"GET\","
+                       "\"http_url\":"         "\"index.html\","
+                       "\"tls\":"              "true,"
+                       "\"retry\":"            "\"default\","
+                       "\"tls_trust_store\":"  "\"le_via_isrg\""
+               "}},"
+
+               /*
+                * This streamtype represents an h2 server listening on :7681,
+                * using a 100-y self-signed tls cert
+                */
+
+               "{\"myserver\": {"
+                       /* if given, "endpoint" is network if to bind to */
+                       "\"server\":"           "true,"
+                       "\"port\":"             "7681,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"metadata\": [{"
+                               "\"mime\": \"Content-Type:\","
+                               "\"method\": \"\","
+                               "\"path\": \"\""
+                       "}],"
+                       "\"tls\":"              "true,"
+                       /*
+                        * A ws server is an http server, if you give a
+                        * ws_subprotocol here it's understood we also serve
+                        * that ove ws or wss according to tls
+                        */
+                       "\"ws_subprotocol\":"   "\"mywsprotocol\","
+                       "\"server_cert\":"      "\"self_localhost\","
+                       "\"server_key\":"       "\"self_localhost_key\""
+               "}},"
+
+         "]"
+       "}"
+;
+
+static int
+smd_cb(void *opaque, lws_smd_class_t c, lws_usec_t ts, void *buf, size_t len)
+{
+       if ((c & LWSSMDCL_SYSTEM_STATE) &&
+           !lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
+
+               /* create the secure streams */
+
+               lwsl_notice("%s: creating server stream\n", __func__);
+
+               if (lws_ss_create(context, 0, &ssi_server, NULL, NULL,
+                                 NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+                       bad = 1;
+                       interrupted = 1;
+                       lws_cancel_service(context);
+                       return -1;
+               }
+#if 0
+               lwsl_notice("%s: creating client stream\n", __func__);
+
+               if (lws_ss_create(context, 0, &ssi_client, NULL, NULL,
+                                 NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+                       return -1;
+               }
+#endif
+       }
+
+       return 0;
+}
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       if (lws_cmdline_option(argc, argv, "-m"))
+               multipart = 1;
+
+       lwsl_user("LWS Secure Streams Server\n");
+
+       info.options                    = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                                         LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.fd_limit_per_thread        = 1 + 6 + 1;
+       info.pss_policies_json          = default_ss_policy;
+       info.port                       = CONTEXT_PORT_NO_LISTEN;
+       info.early_smd_cb               = smd_cb;
+       info.early_smd_class_filter     = LWSSMDCL_SYSTEM_STATE;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       bad = 0;
+
+       lws_context_destroy(context);
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server/ss-client.c b/minimal-examples/secure-streams/minimal-secure-streams-server/ss-client.c
new file mode 100644 (file)
index 0000000..58c0fd9
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * lws-minimal-secure-streams-server
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+
+extern int interrupted, bad;
+
+typedef struct myss {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t  sul;
+
+       int                     count;
+} myss_t;
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+//     myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       //myss_t *m = (myss_t *)userobj;
+
+       return LWSSSSRET_TX_DONT_SEND; /* don't want to write */
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %p %s, ord 0x%x\n", __func__, m->ss,
+                 lws_ss_state_name((int)state), (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_request_tx(m->ss);
+               break;
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+const lws_ss_info_t ssi_client = {
+       .handle_offset                  = offsetof(myss_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_t, opaque_data),
+       .streamtype                     = "mintest",
+       .rx                             = myss_rx,
+       .tx                             = myss_tx,
+       .state                          = myss_state,
+       .user_alloc                     = sizeof(myss_t),
+};
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c b/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c
new file mode 100644 (file)
index 0000000..1b04545
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * lws-minimal-secure-streams-server
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <assert.h>
+
+extern int interrupted, bad, multipart;
+
+static const char *html =
+               /* normally we serve this... */
+       "<head><meta content=\"text/html;charset=utf-8\" "
+                       "http-equiv=\"Content-Type\"><script>"
+       " var ws = new WebSocket(\"wss://localhost:7681\", \"mywsprotocol\");"
+       "try { ws.onopen = function() { console.log(\"open\"); }; "
+               "ws.onmessage = function got_packet(msg) { "
+                  "var s=\"\"; s += msg.data; "
+                  "document.getElementById(\"wsd\").innerHTML = s; };"
+               "} catch(exception) {"
+               "alert(\"<p>Error\" + exception); }"
+       "</script></head><html><body>"
+         "Hello from the web server<br>"
+         "<div id=\"wsd\"></div>"
+       "</body></html>",
+
+*multipart_html =
+       /*
+        * If you use -m commandline switch we send this instead, as
+        * multipart/form-data
+        */
+       "--aBoundaryString\r\n"
+       "Content-Disposition: form-data; name=\"myFile\"; filename=\"xxx.txt\"\r\n"
+       "Content-Type: text/plain\r\n"
+       "\r\n"
+       "The file contents\r\n"
+       "--aBoundaryString\r\n"
+       "Content-Disposition: form-data; name=\"myField\"\r\n"
+       "\r\n"
+       "(data)\r\n"
+       "--aBoundaryString--\r\n";
+
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+
+       lws_sorted_usec_list_t          sul;
+       int                             count;
+       char                            upgraded;
+
+} myss_srv_t;
+
+/*
+ * This is the Secure Streams Server RX and TX for HTTP(S)
+ */
+
+static lws_ss_state_return_t
+myss_srv_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+//     myss_srv_t *m = (myss_srv_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_srv_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       myss_srv_t *m = (myss_srv_t *)userobj;
+       const char *send = html;
+
+       if (m->upgraded)
+               return LWSSSSRET_TX_DONT_SEND;
+
+       if (multipart)
+               send = multipart_html;
+
+       *flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
+
+       lws_strncpy((char *)buf, send, *len);
+       *len = strlen(send);
+
+       return 0;
+}
+
+/*
+ * This is the Secure Streams Server RX and TX for WS(S)... when we get a
+ * state that the underlying connection upgraded protocol, we switch the stream
+ * rx and tx handlers to here.
+ */
+
+static lws_ss_state_return_t
+myss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+//     myss_srv_t *m = (myss_srv_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+/* this is the callback that mediates sending the incrementing number */
+
+static void
+spam_sul_cb(struct lws_sorted_usec_list *sul)
+{
+       myss_srv_t *m = lws_container_of(sul, myss_srv_t, sul);
+
+       if (!lws_ss_request_tx(m->ss))
+               lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, spam_sul_cb,
+                        100 * LWS_US_PER_MS);
+}
+
+static lws_ss_state_return_t
+myss_ws_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       myss_srv_t *m = (myss_srv_t *)userobj;
+
+       *flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
+
+       *len = (unsigned int)lws_snprintf((char *)buf, *len, "hello from ws %d", m->count++);
+
+       lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, spam_sul_cb,
+                        100 * LWS_US_PER_MS);
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_srv_t *m = (myss_srv_t *)userobj;
+
+       lwsl_user("%s: %p %s, ord 0x%x\n", __func__, m->ss,
+                 lws_ss_state_name((int)state), (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_DISCONNECTED:
+               lws_sul_cancel(&m->sul);
+               break;
+       case LWSSSCS_CREATING:
+               return lws_ss_request_tx(m->ss);
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               break;
+
+       case LWSSSCS_SERVER_TXN:
+               /*
+                * The underlying protocol started a transaction, let's
+                * describe how we want to complete it.  We can defer this until
+                * later, eg, after we have consumed any rx that's coming with
+                * the client's transaction initiation phase, but in this
+                * example we know what we want to do already.
+                *
+                * We do want to ack the transaction...
+                */
+               lws_ss_server_ack(m->ss, 0);
+               /*
+                * ... it's going to be either text/html or multipart ...
+                */
+               if (multipart) {
+                       if (lws_ss_set_metadata(m->ss, "mime",
+                          "multipart/form-data; boundary=aBoundaryString", 45))
+                               return LWSSSSRET_DISCONNECT_ME;
+               } else
+                       if (lws_ss_set_metadata(m->ss, "mime", "text/html", 9))
+                               return LWSSSSRET_DISCONNECT_ME;
+               /*
+                * ...it's going to be whatever size it is (and request tx)
+                */
+               return lws_ss_request_tx_len(m->ss, (unsigned long)
+                               (multipart ? strlen(multipart_html) :
+                                                        strlen(html)));
+
+       case LWSSSCS_SERVER_UPGRADE:
+
+               /*
+                * This is sent when the underlying protocol has experienced
+                * an upgrade, eg, http->ws... it's a one-way upgrade on this
+                * stream, change the handlers to deal with the kind of
+                * messages we send on ws
+                */
+
+               m->upgraded = 1;
+               lws_ss_change_handlers(m->ss, myss_ws_rx, myss_ws_tx, NULL);
+               return lws_ss_request_tx(m->ss); /* we want to start sending numbers */
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+const lws_ss_info_t ssi_server = {
+       .handle_offset                  = offsetof(myss_srv_t, ss),
+       .opaque_user_data_offset        = offsetof(myss_srv_t, opaque_data),
+       .streamtype                     = "myserver",
+       .rx                             = myss_srv_rx,
+       .tx                             = myss_srv_tx,
+       .state                          = myss_srv_state,
+       .user_alloc                     = sizeof(myss_srv_t),
+};
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-sigv4/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-sigv4/CMakeLists.txt
new file mode 100644 (file)
index 0000000..47deb88
--- /dev/null
@@ -0,0 +1,102 @@
+project(lws-minimal-secure-streams-sigv4 C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-sigv4)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ss-s3-main.c ss-s3-ss.c)
+       
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32 AND 0)
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME ss-sigv4 COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-sigv4>)
+               else()
+                       add_test(NAME ss-sigv4 COMMAND lws-minimal-secure-streams-sigv4)
+               endif()
+
+               set_tests_properties(ss-sigv4
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-sigv4
+                                    TIMEOUT 20)
+
+               if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+                       #
+                       # Define test dep to bring up and take down the test
+                       # proxy
+                       #
+
+                       if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                               # uds abstract namespace for linux
+                               set(CTEST_SOCKET_PATH "@ctest-sspsigv4-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       else()
+                               # filesystem socket for others
+                               set(CTEST_SOCKET_PATH "/tmp/ctest-sspsigv4-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       endif()
+                       add_test(NAME st_ssproxysigv4 COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               ssproxysigv4 $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH} )
+                       set_tests_properties(st_ssproxysigv4 PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP ssproxysigv4 TIMEOUT 800)
+
+                       add_test(NAME ki_ssproxysigv4 COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                               ssproxysigv4 $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH})
+                       set_tests_properties(ki_ssproxysigv4 PROPERTIES FIXTURES_CLEANUP ssproxysigv4)
+
+                       #
+                       # the client part that will connect to the proxy
+                       #
+
+                       if (VALGRIND)
+                               message("testing via valgrind")
+                               add_test(NAME sspc-sigv4 COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-sigv4-client> -i +${CTEST_SOCKET_PATH})
+                       else()
+                               add_test(NAME sspc-sigv4 COMMAND lws-minimal-secure-streams-sigv4-client -i +${CTEST_SOCKET_PATH})
+                       endif()
+                       set_tests_properties(sspc-sigv4 PROPERTIES
+                               WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-sigv4
+                               FIXTURES_REQUIRED "ssproxysigv4"
+                               TIMEOUT 40)
+
+               endif()
+
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared)
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets)
+       endif()
+
+       if (LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client ss-s3-main.c ss-s3-ss.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared)
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets)
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-sigv4/README.md b/minimal-examples/secure-streams/minimal-secure-streams-sigv4/README.md
new file mode 100644 (file)
index 0000000..15b1051
--- /dev/null
@@ -0,0 +1,46 @@
+# lws minimal secure streams sigv4
+
+The application put a test file to AWS S3, using sigv4 auth.
+
+It does it using Secure Streams... the streamtype is "s3PutObj", along with main
+are in ss-s3-main.c
+
+The handler for state changes and payloads for "s3PutObj" is in ss-s3-ss.c
+
+
+## metadata
+ "aws_region" and "aws_service" are configured through metadata. Also, at least
+ "x-amz-content-sha256:" and ""x-amz-date:" headers need to be in metadata.
+
+
+## credentials
+credentials are read from ~/.aws/credentials, make sure you have valid keyid and
+key.  One need to call lws_ss_sigv4_set_aws_key() to plug in aws credentials into
+Secure Streams and the index need to be match of the "blob_index" in entry of "auth"
+the policy.  In addition, you need to change the S3 bucket name to your own, as
+bucket name is unique globally in S3.
+
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+
+```
+[2020/12/19 15:25:06:9763] U: LWS minimal secure streams sigv4
+[2020/12/19 15:25:07:0768] U: ss_s3_state: LWSSSCS_CREATING, ord 0x0
+[2020/12/19 15:25:07:0769] U: ss_s3_state: LWSSSCS_POLL, ord 0x0
+[2020/12/19 15:25:07:0770] U: ss_s3_state: LWSSSCS_CONNECTING, ord 0x0
+[2020/12/19 15:25:07:2317] U: SS / TX Payload
+[2020/12/19 15:25:07:2317] U: SS / TX Payload Total = 1024, Pos = 0
+[2020/12/19 15:25:07:3267] U: ss_s3_state: LWSSSCS_CONNECTED, ord 0x0
+[2020/12/19 15:25:07:3267] U: ss_s3_state: LWSSSCS_QOS_ACK_REMOTE, ord 0x0
+[2020/12/19 15:25:07:3267] U: ss_s3_state: LWSSSCS_DISCONNECTED, ord 0x0
+[2020/12/19 15:25:07:3268] U: ss_s3_state: LWSSSCS_DESTROYING, ord 0x0
+[2020/12/19 15:25:07:3269] U: Completed: OK
+
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-sigv4/policy.json b/minimal-examples/secure-streams/minimal-secure-streams-sigv4/policy.json
new file mode 100644 (file)
index 0000000..6e44685
--- /dev/null
@@ -0,0 +1 @@
+{"release":"01234567","product":"myproduct","schema-version":1,"retry": [{"default": {"backoff": [100,200,300,500,1000],"conceal":5,"jitterpc":20,"svalidping":30,"svalidhup":35}}],"certs": [{"amazon_root_ca_1": "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5"},{"starfield_services_root_ca": "MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkdiEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6"},{"baltimore_cybertrust_root": "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp"}],"trust_stores": [{"name": "s3-root-cert","stack": ["baltimore_cybertrust_root","amazon_root_ca_1","starfield_services_root_ca"]}],"auth": [{"name": "sigv4_br","type": "sigv4","blob": 0}],"s": [{"s3PutObj": {"endpoint":"${s3bucket}.s3.amazonaws.com","port":443,"protocol":"h1","http_method":"PUT","http_url":"${s3Obj}","http_no_content_length": false,"tls":true,"tls_trust_store":"s3-root-cert","opportunistic":true,"retry":"default","use_auth":"sigv4_br","aws_region":"region","aws_service":"service","metadata": [{"region": ""},{"service": ""},{"s3bucket": ""},{"s3Obj": ""},{"ctype": "content-type:"},{"xcsha256": "x-amz-content-sha256:"},{"xdate": "x-amz-date:"},{"xacl": "x-amz-acl:"}]}}]}
\ No newline at end of file
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-sigv4/ss-s3-main.c b/minimal-examples/secure-streams/minimal-secure-streams-sigv4/ss-s3-main.c
new file mode 100644 (file)
index 0000000..9ab9952
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * S3 Put Object via Secure Streams minimal sigv4 example
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *                        Amit Pachore <apachor@amazon.com>
+ *                         securestreams-dev@amazon.com
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "ss-s3-put.h"
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+#include "static_policy.h"
+#endif
+
+int interrupted, bad = 1;
+static lws_state_notify_link_t nl;
+extern const lws_ss_info_t s3_ssi;
+
+#if !defined(LWS_SS_USE_SSPC)
+
+#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "100,"
+                                                "200,"
+                                                "300,"
+                                                "500,"
+                                               "1000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+                         "{\"amazon_root_ca_1\": \""
+        "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFA"
+        "DA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b2"
+        "4gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAk"
+        "GA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg"
+        "Q0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXjca9Hg"
+        "FB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8"
+        "c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHr"
+        "QgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5"
+        "SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6"
+        "pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg"
+        "0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0"
+        "OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUAA4IBAQCY8jda"
+        "QZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PMCCjjmCXPI"
+        "6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbv"
+        "Xy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtP"
+        "HRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJi"
+        "oaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5W"
+        "TP468SQvvG5"
+                 "\"},"
+                            "{\"starfield_services_root_ca\": \""
+        "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"
+            "\"},"
+               "{\"baltimore_cybertrust_root\": \"" /* LE X3 signed by ISRG X1 root */
+                       "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"
+               "\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"s3-root-cert\","
+                       "\"stack\": ["
+                                               "\"baltimore_cybertrust_root\","
+                                               "\"amazon_root_ca_1\","
+                                               "\"starfield_services_root_ca\""
+                       "]"
+               "}"
+         "],"
+         "\"auth\": [" /* named cert chains */
+              "{"
+                       "\"name\": \"sigv4_br\","
+                       "\"type\": \"sigv4\","
+                       "\"blob\": 0"
+               "}"
+
+         "],"
+         "\"s\": ["
+               "{\"s3PutObj\": {"
+                       "\"endpoint\":" "\"${s3bucket}.s3.amazonaws.com\","
+                       "\"port\":"     "443,"
+                       "\"protocol\":" "\"h1\","
+                       "\"http_method\":" "\"PUT\","
+                       "\"http_url\":" "\"${s3Obj}\","
+                       "\"http_no_content_length\": false,"
+                       "\"tls\":" "true,"
+                       "\"tls_trust_store\":"  "\"s3-root-cert\","
+                       "\"opportunistic\":" "true,"
+                       "\"retry\":" "\"default\","
+                       "\"use_auth\":" "\"sigv4_br\","
+                       "\"aws_region\":" "\"region\","
+                       "\"aws_service\":" "\"service\","
+                       "\"metadata\": ["
+                               "{\"region\": \"\"},"
+                               "{\"service\": \"\"},"
+                               "{\"s3bucket\": \"\"},"
+                               "{\"s3Obj\": \"\"},"
+                               "{\"ctype\": \"content-type:\"},"
+                                "{\"xcsha256\": \"x-amz-content-sha256:\"},"
+                                "{\"xdate\": \"x-amz-date:\"},"
+                               "{\"xacl\": \"x-amz-acl:\"}"
+                       "]"
+               "}}"
+          "]"
+       "}"
+;
+#endif
+
+static char *aws_keyid, *aws_key;
+#endif
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+       struct lws_ss_handle *h;
+
+       switch (target) {
+       case LWS_SYSTATE_REGISTERED:
+               break;
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current != LWS_SYSTATE_OPERATIONAL)
+                       break;
+
+#if !defined(LWS_SS_USE_SSPC)
+               if (lws_aws_filesystem_credentials_helper(
+                                         "~/.aws/credentials",
+                                         "aws_access_key_id",
+                                         "aws_secret_access_key",
+                                         &aws_keyid, &aws_key))
+                       return -1;
+               lws_ss_sigv4_set_aws_key(context, 0, aws_keyid, aws_key);
+#endif
+
+               if (lws_ss_create(context, 0, &s3_ssi, NULL, &h,
+                                 NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+
+                       return -1;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       int logs = LLL_USER | LLL_ERR | LLL_WARN /* | LLL_NOTICE */ ;
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+       lws_set_log_level(logs, NULL);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS minimal secure streams sigv4 \n");
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#else
+#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
+       info.pss_policies = &_ss_static_policy_entry;
+#else
+       info.pss_policies_json = default_ss_policy;
+#endif
+
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       lws_system_blob_heap_append(lws_system_get_blob(context,
+                                   LWS_SYSBLOB_TYPE_DEVICE_TYPE, 0),
+                                   (const uint8_t *)"beerfountain", 12);
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+#if !defined(LWS_SS_USE_SSPC)
+       if (aws_key)
+               free(aws_key);
+       if (aws_keyid)
+               free(aws_keyid);
+#endif
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-sigv4/ss-s3-put.h b/minimal-examples/secure-streams/minimal-secure-streams-sigv4/ss-s3-put.h
new file mode 100644 (file)
index 0000000..ee2e99b
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * S3 Put Object via Secure Streams minimal sigv4 example
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *                        Amit Pachore <apachor@amazon.com>
+ *                        securestreams-dev@amazon.com
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+typedef struct ss_s3_put {
+       struct lws_ss_handle    *ss;
+       void                    *opaque_data;
+
+       /* ... application specific state ... */
+
+       size_t                  total;
+       size_t                  pos;
+       uint8_t                 *buf;
+} ss_s3_put_t;
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-sigv4/ss-s3-ss.c b/minimal-examples/secure-streams/minimal-secure-streams-sigv4/ss-s3-ss.c
new file mode 100644 (file)
index 0000000..1acd431
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * S3 Put Object via Secure Streams minimal siv4 example
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *                        Amit Pachore <apachor@amazon.com>
+ *                         securestreams-dev@amazon.com
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#include <libwebsockets.h>
+#include <assert.h>
+#include "ss-s3-put.h"
+
+extern int interrupted, bad;
+
+static lws_ss_state_return_t
+ss_s3_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       // ss_s3_put_t *m = (ss_s3_put_t *)userobj;
+
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1; /* this example wants to exit after rx */
+               return LWSSSSRET_DESTROY_ME;
+       }
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       lwsl_hexdump_err(buf, len);
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+ss_s3_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+        int *flags)
+{
+       ss_s3_put_t *m = (ss_s3_put_t *)userobj;
+
+       if (!m->pos)
+               *flags |= LWSSS_FLAG_SOM;
+
+       lwsl_user("%s: Send... total: %ld, pos: %ld\n", __func__,
+                 (long)m->total, (long)m->pos);
+
+       if (*len > m->total - m->pos)
+               *len = m->total - m->pos;
+
+       if (!*len)
+               return LWSSSSRET_TX_DONT_SEND;
+
+       memcpy(buf, m->buf + m->pos, *len);
+       m->pos += *len;
+
+       if (m->pos == m->total) {
+               *flags |= LWSSS_FLAG_EOM;
+               // m->pos = 0; /* we only want to send once */
+       } else
+               return lws_ss_request_tx(m->ss);
+
+       return LWSSSSRET_OK;
+}
+
+static const char *awsService  = "s3",
+                 *awsRegion    = "us-west-2",
+                 *s3bucketName = "sstest2020",
+#if 1
+                 *s3ObjName    = "SSs3upload2.txt";
+#else
+                 /* test huge string sigv4 hashing works */
+                 *s3ObjName    = "SSs3uploadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2.txt";
+#endif
+static char timestamp[32], payload_hash[65];
+static uint8_t jpl[1 * 1024];
+
+
+static void
+create_payload(uint8_t *buf, size_t s)
+{
+       int i;
+
+       for (i = 0; i < (int)s; i++)
+               buf[i] = (uint8_t)('a' + i % 16);
+}
+
+static void set_time(char *t)
+{
+       /*20150830T123600Z*/
+       time_t ti = time(NULL);
+#if defined(LWS_HAVE_GMTIME_R)
+       struct tm tmp;
+       struct tm *tm = gmtime_r(&ti, &tmp);
+#else
+       struct tm *tm = gmtime(&ti);
+#endif
+       assert(tm);
+       strftime(t, 20, "%Y%m%dT%H%M%SZ", tm);
+}
+
+static void bin2hex(uint8_t *in, size_t len, char *out)
+{
+       static const char *hex = "0123456789abcdef";
+       size_t n;
+
+       for (n = 0; n < len; n++) {
+               *out++ = hex[(in[n] >> 4) & 0xf];
+               *out++ = hex[in[n] & 15];
+       }
+       *out = '\0';
+}
+
+static void sigv4_sha256hash_payload(uint8_t *payload, size_t len, char *hash)
+{
+       struct lws_genhash_ctx hash_ctx;
+       uint8_t hash_bin[32];
+
+       if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256) ||
+               /*
+                * If there is no payload, you must provide the hash of an
+                * empty string...
+                */
+           lws_genhash_update(&hash_ctx,
+                              payload ? (void *)payload : (void *)"",
+                              payload ? len : 0u) ||
+           lws_genhash_destroy(&hash_ctx, hash_bin))
+       {
+
+               lws_genhash_destroy(&hash_ctx, NULL);
+               lwsl_err("%s lws_genhash failed\n", __func__);
+
+               return;
+       }
+
+       bin2hex(hash_bin, 32, hash);
+}
+
+static lws_ss_state_return_t
+ss_s3_state(void *userobj, void *sh, lws_ss_constate_t state,
+                    lws_ss_tx_ordinal_t ack)
+{
+       ss_s3_put_t *m = (ss_s3_put_t *)userobj;
+
+       lwsl_user("%s: %s %s, ord 0x%x\n", __func__, lws_ss_tag(m->ss),
+                 lws_ss_state_name((int)state), (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               create_payload(jpl, sizeof(jpl));
+               m->buf = (uint8_t *)jpl;
+               m->total = sizeof(jpl);
+
+               sigv4_sha256hash_payload(m->buf, m->total, payload_hash);
+               memset(timestamp, 0, sizeof(timestamp));
+               set_time(timestamp);
+
+               if (lws_ss_set_metadata(m->ss, "s3bucket",
+                                   s3bucketName, strlen(s3bucketName)) ||
+                  lws_ss_set_metadata(m->ss, "s3Obj",
+                                   s3ObjName, strlen(s3ObjName)) ||
+                  lws_ss_set_metadata(m->ss, "ctype",
+                                   "text/plain", strlen("text/plain")) ||
+                  lws_ss_set_metadata(m->ss, "region",
+                                   awsRegion, strlen(awsRegion)) ||
+                  lws_ss_set_metadata(m->ss, "service",
+                                   awsService, strlen(awsService)) ||
+                  lws_ss_set_metadata(m->ss, "xacl",
+                                   "bucket-owner-full-control",
+                                   strlen("bucket-owner-full-control")) ||
+                  lws_ss_set_metadata(m->ss, "xcsha256",
+                                   payload_hash, strlen(payload_hash)) ||
+                  lws_ss_set_metadata(m->ss, "xdate",
+                                   timestamp, strlen(timestamp)))
+                       return LWSSSSRET_DESTROY_ME;
+
+               return lws_ss_request_tx_len(m->ss, m->total);
+
+       case LWSSSCS_CONNECTED:
+               return lws_ss_request_tx(m->ss);
+
+       case LWSSSCS_DISCONNECTED:
+               return LWSSSSRET_DESTROY_ME;
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               bad = 1;
+               return LWSSSSRET_DESTROY_ME;
+
+       case LWSSSCS_QOS_ACK_REMOTE:
+               bad = 0;
+               break;
+
+       case LWSSSCS_QOS_NACK_REMOTE:
+               bad = 1;
+               break;
+
+       case LWSSSCS_DESTROYING:
+               interrupted = 1;
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+const lws_ss_info_t s3_ssi = {
+       .handle_offset           = offsetof(ss_s3_put_t, ss),
+       .opaque_user_data_offset = offsetof(ss_s3_put_t, opaque_data),
+       .rx                      = ss_s3_rx,
+       .tx                      = ss_s3_tx,
+       .state                   = ss_s3_state,
+       .user_alloc              = sizeof(ss_s3_put_t),
+       .streamtype              = "s3PutObj"
+};
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-sigv4/static_policy.h b/minimal-examples/secure-streams/minimal-secure-streams-sigv4/static_policy.h
new file mode 100644 (file)
index 0000000..0f94c5d
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * Autogenerated from the following JSON policy
+ */
+
+#if 0
+{"release":"01234567","product":"myproduct","schema-version":1,"retry": [{"default": {"backoff": [100,200,300,500,1000],"conceal":5,"jitterpc":20,"svalidping":30,"svalidhup":35}}],"certs": [{"amazon_root_ca_1": "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5"},{"starfield_services_root_ca": "MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkdiEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6"},{"baltimore_cybertrust_root": "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp"}],"trust_stores": [{"name": "s3-root-cert","stack": ["baltimore_cybertrust_root","amazon_root_ca_1","starfield_services_root_ca"]}],"auth": [{"name": "sigv4_br","type": "sigv4","blob": 0}],"s": [{"s3PutObj": {"endpoint":"${s3bucket}.s3.amazonaws.com","port":443,"protocol":"h1","http_method":"PUT","http_url":"${s3Obj}","http_no_content_length": false,"tls":true,"tls_trust_store":"s3-root-cert","opportunistic":true,"retry":"default","use_auth":"sigv4_br","aws_region":"region","aws_service":"service","metadata": [{"region": ""},{"service": ""},{"s3bucket": ""},{"s3Obj": ""},{"ctype": "content-type:"},{"xcsha256": "x-amz-content-sha256:"},{"xdate": "x-amz-date:"},{"xacl": "x-amz-acl:"}]}}]}
+
+ Original JSON size: 4630
+#endif
+
+
+static const lws_ss_metadata_t _md_s3PutObj_xacl = {
+       .name = "xacl",
+       .value__may_own_heap = (void *)"x-amz-acl:",
+       .value_length = 0xa,
+       .length = 0,
+       .value_is_http_token = 0xff,
+},
+_md_s3PutObj_xdate = {
+       .next = (void *)&_md_s3PutObj_xacl, 
+       .name = "xdate",
+       .value__may_own_heap = (void *)"x-amz-date:",
+       .value_length = 0xb,
+       .length = 1,
+       .value_is_http_token = 0xff,
+},
+_md_s3PutObj_xcsha256 = {
+       .next = (void *)&_md_s3PutObj_xdate, 
+       .name = "xcsha256",
+       .value__may_own_heap = (void *)"x-amz-content-sha256:",
+       .value_length = 0x15,
+       .length = 2,
+       .value_is_http_token = 0xff,
+},
+_md_s3PutObj_ctype = {
+       .next = (void *)&_md_s3PutObj_xcsha256, 
+       .name = "ctype",
+       .value__may_own_heap = (void *)"content-type:",
+       .value_length = 0xd,
+       .length = 3,
+       .value_is_http_token = 0x1c,
+},
+_md_s3PutObj_s3Obj = {
+       .next = (void *)&_md_s3PutObj_ctype, 
+       .name = "s3Obj",
+       .value__may_own_heap = (void *)"",
+       .value_length = 0x0,
+       .length = 4,
+       .value_is_http_token = 0x0,
+},
+_md_s3PutObj_s3bucket = {
+       .next = (void *)&_md_s3PutObj_s3Obj, 
+       .name = "s3bucket",
+       .value__may_own_heap = (void *)"",
+       .value_length = 0x0,
+       .length = 5,
+       .value_is_http_token = 0x0,
+},
+_md_s3PutObj_service = {
+       .next = (void *)&_md_s3PutObj_s3bucket, 
+       .name = "service",
+       .value__may_own_heap = (void *)"",
+       .value_length = 0x0,
+       .length = 6,
+       .value_is_http_token = 0x0,
+},
+_md_s3PutObj_region = {
+       .next = (void *)&_md_s3PutObj_service, 
+       .name = "region",
+       .value__may_own_heap = (void *)"",
+       .value_length = 0x0,
+       .length = 7,
+       .value_is_http_token = 0x0,
+};
+
+static const uint32_t _rbo_bo_0[] = {
+ 100,  200,  300,  500,  1000, 
+};
+static const lws_retry_bo_t _rbo_0 = {
+       .retry_ms_table = _rbo_bo_0,
+       .retry_ms_table_count = 5,
+       .conceal_count = 5,
+       .secs_since_valid_ping = 30,
+       .secs_since_valid_hangup = 35,
+       .jitter_percent = 20,
+};
+static const uint8_t _ss_der_baltimore_cybertrust_root[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x03, 0x77, 0x30, 0x82, 0x02, 0x5F, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x02, 
+       /* 0x 10 */ 0x00, 0x00, 0xB9, 0x30, 0x0D, 0x06, 0x09, 0x2A, 
+       /* 0x 18 */ 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 
+       /* 0x 20 */ 0x05, 0x00, 0x30, 0x5A, 0x31, 0x0B, 0x30, 0x09, 
+       /* 0x 28 */ 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 
+       /* 0x 30 */ 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 
+       /* 0x 38 */ 0x04, 0x0A, 0x13, 0x09, 0x42, 0x61, 0x6C, 0x74, 
+       /* 0x 40 */ 0x69, 0x6D, 0x6F, 0x72, 0x65, 0x31, 0x13, 0x30, 
+       /* 0x 48 */ 0x11, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x0A, 
+       /* 0x 50 */ 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 
+       /* 0x 58 */ 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 
+       /* 0x 60 */ 0x55, 0x04, 0x03, 0x13, 0x19, 0x42, 0x61, 0x6C, 
+       /* 0x 68 */ 0x74, 0x69, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x43, 
+       /* 0x 70 */ 0x79, 0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 
+       /* 0x 78 */ 0x74, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x30, 0x1E, 
+       /* 0x 80 */ 0x17, 0x0D, 0x30, 0x30, 0x30, 0x35, 0x31, 0x32, 
+       /* 0x 88 */ 0x31, 0x38, 0x34, 0x36, 0x30, 0x30, 0x5A, 0x17, 
+       /* 0x 90 */ 0x0D, 0x32, 0x35, 0x30, 0x35, 0x31, 0x32, 0x32, 
+       /* 0x 98 */ 0x33, 0x35, 0x39, 0x30, 0x30, 0x5A, 0x30, 0x5A, 
+       /* 0x a0 */ 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x a8 */ 0x06, 0x13, 0x02, 0x49, 0x45, 0x31, 0x12, 0x30, 
+       /* 0x b0 */ 0x10, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x09, 
+       /* 0x b8 */ 0x42, 0x61, 0x6C, 0x74, 0x69, 0x6D, 0x6F, 0x72, 
+       /* 0x c0 */ 0x65, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 
+       /* 0x c8 */ 0x04, 0x0B, 0x13, 0x0A, 0x43, 0x79, 0x62, 0x65, 
+       /* 0x d0 */ 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 
+       /* 0x d8 */ 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 
+       /* 0x e0 */ 0x19, 0x42, 0x61, 0x6C, 0x74, 0x69, 0x6D, 0x6F, 
+       /* 0x e8 */ 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 
+       /* 0x f0 */ 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x52, 0x6F, 
+       /* 0x f8 */ 0x6F, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 
+       /* 0x100 */ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 
+       /* 0x108 */ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 
+       /* 0x110 */ 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 
+       /* 0x118 */ 0x01, 0x01, 0x00, 0xA3, 0x04, 0xBB, 0x22, 0xAB, 
+       /* 0x120 */ 0x98, 0x3D, 0x57, 0xE8, 0x26, 0x72, 0x9A, 0xB5, 
+       /* 0x128 */ 0x79, 0xD4, 0x29, 0xE2, 0xE1, 0xE8, 0x95, 0x80, 
+       /* 0x130 */ 0xB1, 0xB0, 0xE3, 0x5B, 0x8E, 0x2B, 0x29, 0x9A, 
+       /* 0x138 */ 0x64, 0xDF, 0xA1, 0x5D, 0xED, 0xB0, 0x09, 0x05, 
+       /* 0x140 */ 0x6D, 0xDB, 0x28, 0x2E, 0xCE, 0x62, 0xA2, 0x62, 
+       /* 0x148 */ 0xFE, 0xB4, 0x88, 0xDA, 0x12, 0xEB, 0x38, 0xEB, 
+       /* 0x150 */ 0x21, 0x9D, 0xC0, 0x41, 0x2B, 0x01, 0x52, 0x7B, 
+       /* 0x158 */ 0x88, 0x77, 0xD3, 0x1C, 0x8F, 0xC7, 0xBA, 0xB9, 
+       /* 0x160 */ 0x88, 0xB5, 0x6A, 0x09, 0xE7, 0x73, 0xE8, 0x11, 
+       /* 0x168 */ 0x40, 0xA7, 0xD1, 0xCC, 0xCA, 0x62, 0x8D, 0x2D, 
+       /* 0x170 */ 0xE5, 0x8F, 0x0B, 0xA6, 0x50, 0xD2, 0xA8, 0x50, 
+       /* 0x178 */ 0xC3, 0x28, 0xEA, 0xF5, 0xAB, 0x25, 0x87, 0x8A, 
+       /* 0x180 */ 0x9A, 0x96, 0x1C, 0xA9, 0x67, 0xB8, 0x3F, 0x0C, 
+       /* 0x188 */ 0xD5, 0xF7, 0xF9, 0x52, 0x13, 0x2F, 0xC2, 0x1B, 
+       /* 0x190 */ 0xD5, 0x70, 0x70, 0xF0, 0x8F, 0xC0, 0x12, 0xCA, 
+       /* 0x198 */ 0x06, 0xCB, 0x9A, 0xE1, 0xD9, 0xCA, 0x33, 0x7A, 
+       /* 0x1a0 */ 0x77, 0xD6, 0xF8, 0xEC, 0xB9, 0xF1, 0x68, 0x44, 
+       /* 0x1a8 */ 0x42, 0x48, 0x13, 0xD2, 0xC0, 0xC2, 0xA4, 0xAE, 
+       /* 0x1b0 */ 0x5E, 0x60, 0xFE, 0xB6, 0xA6, 0x05, 0xFC, 0xB4, 
+       /* 0x1b8 */ 0xDD, 0x07, 0x59, 0x02, 0xD4, 0x59, 0x18, 0x98, 
+       /* 0x1c0 */ 0x63, 0xF5, 0xA5, 0x63, 0xE0, 0x90, 0x0C, 0x7D, 
+       /* 0x1c8 */ 0x5D, 0xB2, 0x06, 0x7A, 0xF3, 0x85, 0xEA, 0xEB, 
+       /* 0x1d0 */ 0xD4, 0x03, 0xAE, 0x5E, 0x84, 0x3E, 0x5F, 0xFF, 
+       /* 0x1d8 */ 0x15, 0xED, 0x69, 0xBC, 0xF9, 0x39, 0x36, 0x72, 
+       /* 0x1e0 */ 0x75, 0xCF, 0x77, 0x52, 0x4D, 0xF3, 0xC9, 0x90, 
+       /* 0x1e8 */ 0x2C, 0xB9, 0x3D, 0xE5, 0xC9, 0x23, 0x53, 0x3F, 
+       /* 0x1f0 */ 0x1F, 0x24, 0x98, 0x21, 0x5C, 0x07, 0x99, 0x29, 
+       /* 0x1f8 */ 0xBD, 0xC6, 0x3A, 0xEC, 0xE7, 0x6E, 0x86, 0x3A, 
+       /* 0x200 */ 0x6B, 0x97, 0x74, 0x63, 0x33, 0xBD, 0x68, 0x18, 
+       /* 0x208 */ 0x31, 0xF0, 0x78, 0x8D, 0x76, 0xBF, 0xFC, 0x9E, 
+       /* 0x210 */ 0x8E, 0x5D, 0x2A, 0x86, 0xA7, 0x4D, 0x90, 0xDC, 
+       /* 0x218 */ 0x27, 0x1A, 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 
+       /* 0x220 */ 0xA3, 0x45, 0x30, 0x43, 0x30, 0x1D, 0x06, 0x03, 
+       /* 0x228 */ 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xE5, 
+       /* 0x230 */ 0x9D, 0x59, 0x30, 0x82, 0x47, 0x58, 0xCC, 0xAC, 
+       /* 0x238 */ 0xFA, 0x08, 0x54, 0x36, 0x86, 0x7B, 0x3A, 0xB5, 
+       /* 0x240 */ 0x04, 0x4D, 0xF0, 0x30, 0x12, 0x06, 0x03, 0x55, 
+       /* 0x248 */ 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x08, 0x30, 
+       /* 0x250 */ 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01, 0x03, 0x30, 
+       /* 0x258 */ 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 
+       /* 0x260 */ 0xFF, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 
+       /* 0x268 */ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 
+       /* 0x270 */ 0x0D, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 
+       /* 0x278 */ 0x01, 0x01, 0x00, 0x85, 0x0C, 0x5D, 0x8E, 0xE4, 
+       /* 0x280 */ 0x6F, 0x51, 0x68, 0x42, 0x05, 0xA0, 0xDD, 0xBB, 
+       /* 0x288 */ 0x4F, 0x27, 0x25, 0x84, 0x03, 0xBD, 0xF7, 0x64, 
+       /* 0x290 */ 0xFD, 0x2D, 0xD7, 0x30, 0xE3, 0xA4, 0x10, 0x17, 
+       /* 0x298 */ 0xEB, 0xDA, 0x29, 0x29, 0xB6, 0x79, 0x3F, 0x76, 
+       /* 0x2a0 */ 0xF6, 0x19, 0x13, 0x23, 0xB8, 0x10, 0x0A, 0xF9, 
+       /* 0x2a8 */ 0x58, 0xA4, 0xD4, 0x61, 0x70, 0xBD, 0x04, 0x61, 
+       /* 0x2b0 */ 0x6A, 0x12, 0x8A, 0x17, 0xD5, 0x0A, 0xBD, 0xC5, 
+       /* 0x2b8 */ 0xBC, 0x30, 0x7C, 0xD6, 0xE9, 0x0C, 0x25, 0x8D, 
+       /* 0x2c0 */ 0x86, 0x40, 0x4F, 0xEC, 0xCC, 0xA3, 0x7E, 0x38, 
+       /* 0x2c8 */ 0xC6, 0x37, 0x11, 0x4F, 0xED, 0xDD, 0x68, 0x31, 
+       /* 0x2d0 */ 0x8E, 0x4C, 0xD2, 0xB3, 0x01, 0x74, 0xEE, 0xBE, 
+       /* 0x2d8 */ 0x75, 0x5E, 0x07, 0x48, 0x1A, 0x7F, 0x70, 0xFF, 
+       /* 0x2e0 */ 0x16, 0x5C, 0x84, 0xC0, 0x79, 0x85, 0xB8, 0x05, 
+       /* 0x2e8 */ 0xFD, 0x7F, 0xBE, 0x65, 0x11, 0xA3, 0x0F, 0xC0, 
+       /* 0x2f0 */ 0x02, 0xB4, 0xF8, 0x52, 0x37, 0x39, 0x04, 0xD5, 
+       /* 0x2f8 */ 0xA9, 0x31, 0x7A, 0x18, 0xBF, 0xA0, 0x2A, 0xF4, 
+       /* 0x300 */ 0x12, 0x99, 0xF7, 0xA3, 0x45, 0x82, 0xE3, 0x3C, 
+       /* 0x308 */ 0x5E, 0xF5, 0x9D, 0x9E, 0xB5, 0xC8, 0x9E, 0x7C, 
+       /* 0x310 */ 0x2E, 0xC8, 0xA4, 0x9E, 0x4E, 0x08, 0x14, 0x4B, 
+       /* 0x318 */ 0x6D, 0xFD, 0x70, 0x6D, 0x6B, 0x1A, 0x63, 0xBD, 
+       /* 0x320 */ 0x64, 0xE6, 0x1F, 0xB7, 0xCE, 0xF0, 0xF2, 0x9F, 
+       /* 0x328 */ 0x2E, 0xBB, 0x1B, 0xB7, 0xF2, 0x50, 0x88, 0x73, 
+       /* 0x330 */ 0x92, 0xC2, 0xE2, 0xE3, 0x16, 0x8D, 0x9A, 0x32, 
+       /* 0x338 */ 0x02, 0xAB, 0x8E, 0x18, 0xDD, 0xE9, 0x10, 0x11, 
+       /* 0x340 */ 0xEE, 0x7E, 0x35, 0xAB, 0x90, 0xAF, 0x3E, 0x30, 
+       /* 0x348 */ 0x94, 0x7A, 0xD0, 0x33, 0x3D, 0xA7, 0x65, 0x0F, 
+       /* 0x350 */ 0xF5, 0xFC, 0x8E, 0x9E, 0x62, 0xCF, 0x47, 0x44, 
+       /* 0x358 */ 0x2C, 0x01, 0x5D, 0xBB, 0x1D, 0xB5, 0x32, 0xD2, 
+       /* 0x360 */ 0x47, 0xD2, 0x38, 0x2E, 0xD0, 0xFE, 0x81, 0xDC, 
+       /* 0x368 */ 0x32, 0x6A, 0x1E, 0xB5, 0xEE, 0x3C, 0xD5, 0xFC, 
+       /* 0x370 */ 0xE7, 0x81, 0x1D, 0x19, 0xC3, 0x24, 0x42, 0xEA, 
+       /* 0x378 */ 0x63, 0x39, 0xA9, 
+};
+static const lws_ss_x509_t _ss_x509_baltimore_cybertrust_root = {
+       .vhost_name = "baltimore_cybertrust_root",
+       .ca_der = _ss_der_baltimore_cybertrust_root,
+       .ca_der_len = 891,
+};
+static const uint8_t _ss_der_amazon_root_ca_1[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x03, 0x41, 0x30, 0x82, 0x02, 0x29, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x06, 
+       /* 0x 10 */ 0x6C, 0x9F, 0xCF, 0x99, 0xBF, 0x8C, 0x0A, 0x39, 
+       /* 0x 18 */ 0xE2, 0xF0, 0x78, 0x8A, 0x43, 0xE6, 0x96, 0x36, 
+       /* 0x 20 */ 0x5B, 0xCA, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 
+       /* 0x 28 */ 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 
+       /* 0x 30 */ 0x00, 0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 
+       /* 0x 38 */ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 
+       /* 0x 40 */ 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x 48 */ 0x0A, 0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 
+       /* 0x 50 */ 0x6E, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 
+       /* 0x 58 */ 0x04, 0x03, 0x13, 0x10, 0x41, 0x6D, 0x61, 0x7A, 
+       /* 0x 60 */ 0x6F, 0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 
+       /* 0x 68 */ 0x43, 0x41, 0x20, 0x31, 0x30, 0x1E, 0x17, 0x0D, 
+       /* 0x 70 */ 0x31, 0x35, 0x30, 0x35, 0x32, 0x36, 0x30, 0x30, 
+       /* 0x 78 */ 0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x33, 
+       /* 0x 80 */ 0x38, 0x30, 0x31, 0x31, 0x37, 0x30, 0x30, 0x30, 
+       /* 0x 88 */ 0x30, 0x30, 0x30, 0x5A, 0x30, 0x39, 0x31, 0x0B, 
+       /* 0x 90 */ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 
+       /* 0x 98 */ 0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 
+       /* 0x a0 */ 0x03, 0x55, 0x04, 0x0A, 0x13, 0x06, 0x41, 0x6D, 
+       /* 0x a8 */ 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17, 
+       /* 0x b0 */ 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 
+       /* 0x b8 */ 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x20, 0x52, 0x6F, 
+       /* 0x c0 */ 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x30, 
+       /* 0x c8 */ 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 
+       /* 0x d0 */ 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 
+       /* 0x d8 */ 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 
+       /* 0x e0 */ 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 
+       /* 0x e8 */ 0xB2, 0x78, 0x80, 0x71, 0xCA, 0x78, 0xD5, 0xE3, 
+       /* 0x f0 */ 0x71, 0xAF, 0x47, 0x80, 0x50, 0x74, 0x7D, 0x6E, 
+       /* 0x f8 */ 0xD8, 0xD7, 0x88, 0x76, 0xF4, 0x99, 0x68, 0xF7, 
+       /* 0x100 */ 0x58, 0x21, 0x60, 0xF9, 0x74, 0x84, 0x01, 0x2F, 
+       /* 0x108 */ 0xAC, 0x02, 0x2D, 0x86, 0xD3, 0xA0, 0x43, 0x7A, 
+       /* 0x110 */ 0x4E, 0xB2, 0xA4, 0xD0, 0x36, 0xBA, 0x01, 0xBE, 
+       /* 0x118 */ 0x8D, 0xDB, 0x48, 0xC8, 0x07, 0x17, 0x36, 0x4C, 
+       /* 0x120 */ 0xF4, 0xEE, 0x88, 0x23, 0xC7, 0x3E, 0xEB, 0x37, 
+       /* 0x128 */ 0xF5, 0xB5, 0x19, 0xF8, 0x49, 0x68, 0xB0, 0xDE, 
+       /* 0x130 */ 0xD7, 0xB9, 0x76, 0x38, 0x1D, 0x61, 0x9E, 0xA4, 
+       /* 0x138 */ 0xFE, 0x82, 0x36, 0xA5, 0xE5, 0x4A, 0x56, 0xE4, 
+       /* 0x140 */ 0x45, 0xE1, 0xF9, 0xFD, 0xB4, 0x16, 0xFA, 0x74, 
+       /* 0x148 */ 0xDA, 0x9C, 0x9B, 0x35, 0x39, 0x2F, 0xFA, 0xB0, 
+       /* 0x150 */ 0x20, 0x50, 0x06, 0x6C, 0x7A, 0xD0, 0x80, 0xB2, 
+       /* 0x158 */ 0xA6, 0xF9, 0xAF, 0xEC, 0x47, 0x19, 0x8F, 0x50, 
+       /* 0x160 */ 0x38, 0x07, 0xDC, 0xA2, 0x87, 0x39, 0x58, 0xF8, 
+       /* 0x168 */ 0xBA, 0xD5, 0xA9, 0xF9, 0x48, 0x67, 0x30, 0x96, 
+       /* 0x170 */ 0xEE, 0x94, 0x78, 0x5E, 0x6F, 0x89, 0xA3, 0x51, 
+       /* 0x178 */ 0xC0, 0x30, 0x86, 0x66, 0xA1, 0x45, 0x66, 0xBA, 
+       /* 0x180 */ 0x54, 0xEB, 0xA3, 0xC3, 0x91, 0xF9, 0x48, 0xDC, 
+       /* 0x188 */ 0xFF, 0xD1, 0xE8, 0x30, 0x2D, 0x7D, 0x2D, 0x74, 
+       /* 0x190 */ 0x70, 0x35, 0xD7, 0x88, 0x24, 0xF7, 0x9E, 0xC4, 
+       /* 0x198 */ 0x59, 0x6E, 0xBB, 0x73, 0x87, 0x17, 0xF2, 0x32, 
+       /* 0x1a0 */ 0x46, 0x28, 0xB8, 0x43, 0xFA, 0xB7, 0x1D, 0xAA, 
+       /* 0x1a8 */ 0xCA, 0xB4, 0xF2, 0x9F, 0x24, 0x0E, 0x2D, 0x4B, 
+       /* 0x1b0 */ 0xF7, 0x71, 0x5C, 0x5E, 0x69, 0xFF, 0xEA, 0x95, 
+       /* 0x1b8 */ 0x02, 0xCB, 0x38, 0x8A, 0xAE, 0x50, 0x38, 0x6F, 
+       /* 0x1c0 */ 0xDB, 0xFB, 0x2D, 0x62, 0x1B, 0xC5, 0xC7, 0x1E, 
+       /* 0x1c8 */ 0x54, 0xE1, 0x77, 0xE0, 0x67, 0xC8, 0x0F, 0x9C, 
+       /* 0x1d0 */ 0x87, 0x23, 0xD6, 0x3F, 0x40, 0x20, 0x7F, 0x20, 
+       /* 0x1d8 */ 0x80, 0xC4, 0x80, 0x4C, 0x3E, 0x3B, 0x24, 0x26, 
+       /* 0x1e0 */ 0x8E, 0x04, 0xAE, 0x6C, 0x9A, 0xC8, 0xAA, 0x0D, 
+       /* 0x1e8 */ 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x42, 0x30, 
+       /* 0x1f0 */ 0x40, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 
+       /* 0x1f8 */ 0x01, 0x01, 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 
+       /* 0x200 */ 0x01, 0xFF, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 
+       /* 0x208 */ 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, 
+       /* 0x210 */ 0x01, 0x86, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 
+       /* 0x218 */ 0x0E, 0x04, 0x16, 0x04, 0x14, 0x84, 0x18, 0xCC, 
+       /* 0x220 */ 0x85, 0x34, 0xEC, 0xBC, 0x0C, 0x94, 0x94, 0x2E, 
+       /* 0x228 */ 0x08, 0x59, 0x9C, 0xC7, 0xB2, 0x10, 0x4E, 0x0A, 
+       /* 0x230 */ 0x08, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 
+       /* 0x238 */ 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 
+       /* 0x240 */ 0x03, 0x82, 0x01, 0x01, 0x00, 0x98, 0xF2, 0x37, 
+       /* 0x248 */ 0x5A, 0x41, 0x90, 0xA1, 0x1A, 0xC5, 0x76, 0x51, 
+       /* 0x250 */ 0x28, 0x20, 0x36, 0x23, 0x0E, 0xAE, 0xE6, 0x28, 
+       /* 0x258 */ 0xBB, 0xAA, 0xF8, 0x94, 0xAE, 0x48, 0xA4, 0x30, 
+       /* 0x260 */ 0x7F, 0x1B, 0xFC, 0x24, 0x8D, 0x4B, 0xB4, 0xC8, 
+       /* 0x268 */ 0xA1, 0x97, 0xF6, 0xB6, 0xF1, 0x7A, 0x70, 0xC8, 
+       /* 0x270 */ 0x53, 0x93, 0xCC, 0x08, 0x28, 0xE3, 0x98, 0x25, 
+       /* 0x278 */ 0xCF, 0x23, 0xA4, 0xF9, 0xDE, 0x21, 0xD3, 0x7C, 
+       /* 0x280 */ 0x85, 0x09, 0xAD, 0x4E, 0x9A, 0x75, 0x3A, 0xC2, 
+       /* 0x288 */ 0x0B, 0x6A, 0x89, 0x78, 0x76, 0x44, 0x47, 0x18, 
+       /* 0x290 */ 0x65, 0x6C, 0x8D, 0x41, 0x8E, 0x3B, 0x7F, 0x9A, 
+       /* 0x298 */ 0xCB, 0xF4, 0xB5, 0xA7, 0x50, 0xD7, 0x05, 0x2C, 
+       /* 0x2a0 */ 0x37, 0xE8, 0x03, 0x4B, 0xAD, 0xE9, 0x61, 0xA0, 
+       /* 0x2a8 */ 0x02, 0x6E, 0xF5, 0xF2, 0xF0, 0xC5, 0xB2, 0xED, 
+       /* 0x2b0 */ 0x5B, 0xB7, 0xDC, 0xFA, 0x94, 0x5C, 0x77, 0x9E, 
+       /* 0x2b8 */ 0x13, 0xA5, 0x7F, 0x52, 0xAD, 0x95, 0xF2, 0xF8, 
+       /* 0x2c0 */ 0x93, 0x3B, 0xDE, 0x8B, 0x5C, 0x5B, 0xCA, 0x5A, 
+       /* 0x2c8 */ 0x52, 0x5B, 0x60, 0xAF, 0x14, 0xF7, 0x4B, 0xEF, 
+       /* 0x2d0 */ 0xA3, 0xFB, 0x9F, 0x40, 0x95, 0x6D, 0x31, 0x54, 
+       /* 0x2d8 */ 0xFC, 0x42, 0xD3, 0xC7, 0x46, 0x1F, 0x23, 0xAD, 
+       /* 0x2e0 */ 0xD9, 0x0F, 0x48, 0x70, 0x9A, 0xD9, 0x75, 0x78, 
+       /* 0x2e8 */ 0x71, 0xD1, 0x72, 0x43, 0x34, 0x75, 0x6E, 0x57, 
+       /* 0x2f0 */ 0x59, 0xC2, 0x02, 0x5C, 0x26, 0x60, 0x29, 0xCF, 
+       /* 0x2f8 */ 0x23, 0x19, 0x16, 0x8E, 0x88, 0x43, 0xA5, 0xD4, 
+       /* 0x300 */ 0xE4, 0xCB, 0x08, 0xFB, 0x23, 0x11, 0x43, 0xE8, 
+       /* 0x308 */ 0x43, 0x29, 0x72, 0x62, 0xA1, 0xA9, 0x5D, 0x5E, 
+       /* 0x310 */ 0x08, 0xD4, 0x90, 0xAE, 0xB8, 0xD8, 0xCE, 0x14, 
+       /* 0x318 */ 0xC2, 0xD0, 0x55, 0xF2, 0x86, 0xF6, 0xC4, 0x93, 
+       /* 0x320 */ 0x43, 0x77, 0x66, 0x61, 0xC0, 0xB9, 0xE8, 0x41, 
+       /* 0x328 */ 0xD7, 0x97, 0x78, 0x60, 0x03, 0x6E, 0x4A, 0x72, 
+       /* 0x330 */ 0xAE, 0xA5, 0xD1, 0x7D, 0xBA, 0x10, 0x9E, 0x86, 
+       /* 0x338 */ 0x6C, 0x1B, 0x8A, 0xB9, 0x59, 0x33, 0xF8, 0xEB, 
+       /* 0x340 */ 0xC4, 0x90, 0xBE, 0xF1, 0xB9, 
+};
+static const lws_ss_x509_t _ss_x509_amazon_root_ca_1 = {
+       .vhost_name = "amazon_root_ca_1",
+       .ca_der = _ss_der_amazon_root_ca_1,
+       .ca_der_len = 837,
+};
+static const uint8_t _ss_der_starfield_services_root_ca[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x03, 0xEF, 0x30, 0x82, 0x02, 0xD7, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 
+       /* 0x 10 */ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+       /* 0x 18 */ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 
+       /* 0x 20 */ 0x81, 0x98, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 
+       /* 0x 28 */ 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 
+       /* 0x 30 */ 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 
+       /* 0x 38 */ 0x13, 0x07, 0x41, 0x72, 0x69, 0x7A, 0x6F, 0x6E, 
+       /* 0x 40 */ 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 
+       /* 0x 48 */ 0x04, 0x07, 0x13, 0x0A, 0x53, 0x63, 0x6F, 0x74, 
+       /* 0x 50 */ 0x74, 0x73, 0x64, 0x61, 0x6C, 0x65, 0x31, 0x25, 
+       /* 0x 58 */ 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 
+       /* 0x 60 */ 0x1C, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 
+       /* 0x 68 */ 0x6C, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6E, 
+       /* 0x 70 */ 0x6F, 0x6C, 0x6F, 0x67, 0x69, 0x65, 0x73, 0x2C, 
+       /* 0x 78 */ 0x20, 0x49, 0x6E, 0x63, 0x2E, 0x31, 0x3B, 0x30, 
+       /* 0x 80 */ 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x32, 
+       /* 0x 88 */ 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6C, 
+       /* 0x 90 */ 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 
+       /* 0x 98 */ 0x65, 0x73, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 
+       /* 0x a0 */ 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 
+       /* 0x a8 */ 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 
+       /* 0x b0 */ 0x6F, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2D, 0x20, 
+       /* 0x b8 */ 0x47, 0x32, 0x30, 0x1E, 0x17, 0x0D, 0x30, 0x39, 
+       /* 0x c0 */ 0x30, 0x39, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 
+       /* 0x c8 */ 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x33, 0x37, 0x31, 
+       /* 0x d0 */ 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 
+       /* 0x d8 */ 0x39, 0x5A, 0x30, 0x81, 0x98, 0x31, 0x0B, 0x30, 
+       /* 0x e0 */ 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 
+       /* 0x e8 */ 0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 
+       /* 0x f0 */ 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 
+       /* 0x f8 */ 0x7A, 0x6F, 0x6E, 0x61, 0x31, 0x13, 0x30, 0x11, 
+       /* 0x100 */ 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0A, 0x53, 
+       /* 0x108 */ 0x63, 0x6F, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6C, 
+       /* 0x110 */ 0x65, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 
+       /* 0x118 */ 0x04, 0x0A, 0x13, 0x1C, 0x53, 0x74, 0x61, 0x72, 
+       /* 0x120 */ 0x66, 0x69, 0x65, 0x6C, 0x64, 0x20, 0x54, 0x65, 
+       /* 0x128 */ 0x63, 0x68, 0x6E, 0x6F, 0x6C, 0x6F, 0x67, 0x69, 
+       /* 0x130 */ 0x65, 0x73, 0x2C, 0x20, 0x49, 0x6E, 0x63, 0x2E, 
+       /* 0x138 */ 0x31, 0x3B, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x140 */ 0x03, 0x13, 0x32, 0x53, 0x74, 0x61, 0x72, 0x66, 
+       /* 0x148 */ 0x69, 0x65, 0x6C, 0x64, 0x20, 0x53, 0x65, 0x72, 
+       /* 0x150 */ 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x52, 0x6F, 
+       /* 0x158 */ 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 
+       /* 0x160 */ 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 
+       /* 0x168 */ 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 
+       /* 0x170 */ 0x20, 0x2D, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 
+       /* 0x178 */ 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 
+       /* 0x180 */ 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 
+       /* 0x188 */ 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 
+       /* 0x190 */ 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xD5, 0x0C, 
+       /* 0x198 */ 0x3A, 0xC4, 0x2A, 0xF9, 0x4E, 0xE2, 0xF5, 0xBE, 
+       /* 0x1a0 */ 0x19, 0x97, 0x5F, 0x8E, 0x88, 0x53, 0xB1, 0x1F, 
+       /* 0x1a8 */ 0x3F, 0xCB, 0xCF, 0x9F, 0x20, 0x13, 0x6D, 0x29, 
+       /* 0x1b0 */ 0x3A, 0xC8, 0x0F, 0x7D, 0x3C, 0xF7, 0x6B, 0x76, 
+       /* 0x1b8 */ 0x38, 0x63, 0xD9, 0x36, 0x60, 0xA8, 0x9B, 0x5E, 
+       /* 0x1c0 */ 0x5C, 0x00, 0x80, 0xB2, 0x2F, 0x59, 0x7F, 0xF6, 
+       /* 0x1c8 */ 0x87, 0xF9, 0x25, 0x43, 0x86, 0xE7, 0x69, 0x1B, 
+       /* 0x1d0 */ 0x52, 0x9A, 0x90, 0xE1, 0x71, 0xE3, 0xD8, 0x2D, 
+       /* 0x1d8 */ 0x0D, 0x4E, 0x6F, 0xF6, 0xC8, 0x49, 0xD9, 0xB6, 
+       /* 0x1e0 */ 0xF3, 0x1A, 0x56, 0xAE, 0x2B, 0xB6, 0x74, 0x14, 
+       /* 0x1e8 */ 0xEB, 0xCF, 0xFB, 0x26, 0xE3, 0x1A, 0xBA, 0x1D, 
+       /* 0x1f0 */ 0x96, 0x2E, 0x6A, 0x3B, 0x58, 0x94, 0x89, 0x47, 
+       /* 0x1f8 */ 0x56, 0xFF, 0x25, 0xA0, 0x93, 0x70, 0x53, 0x83, 
+       /* 0x200 */ 0xDA, 0x84, 0x74, 0x14, 0xC3, 0x67, 0x9E, 0x04, 
+       /* 0x208 */ 0x68, 0x3A, 0xDF, 0x8E, 0x40, 0x5A, 0x1D, 0x4A, 
+       /* 0x210 */ 0x4E, 0xCF, 0x43, 0x91, 0x3B, 0xE7, 0x56, 0xD6, 
+       /* 0x218 */ 0x00, 0x70, 0xCB, 0x52, 0xEE, 0x7B, 0x7D, 0xAE, 
+       /* 0x220 */ 0x3A, 0xE7, 0xBC, 0x31, 0xF9, 0x45, 0xF6, 0xC2, 
+       /* 0x228 */ 0x60, 0xCF, 0x13, 0x59, 0x02, 0x2B, 0x80, 0xCC, 
+       /* 0x230 */ 0x34, 0x47, 0xDF, 0xB9, 0xDE, 0x90, 0x65, 0x6D, 
+       /* 0x238 */ 0x02, 0xCF, 0x2C, 0x91, 0xA6, 0xA6, 0xE7, 0xDE, 
+       /* 0x240 */ 0x85, 0x18, 0x49, 0x7C, 0x66, 0x4E, 0xA3, 0x3A, 
+       /* 0x248 */ 0x6D, 0xA9, 0xB5, 0xEE, 0x34, 0x2E, 0xBA, 0x0D, 
+       /* 0x250 */ 0x03, 0xB8, 0x33, 0xDF, 0x47, 0xEB, 0xB1, 0x6B, 
+       /* 0x258 */ 0x8D, 0x25, 0xD9, 0x9B, 0xCE, 0x81, 0xD1, 0x45, 
+       /* 0x260 */ 0x46, 0x32, 0x96, 0x70, 0x87, 0xDE, 0x02, 0x0E, 
+       /* 0x268 */ 0x49, 0x43, 0x85, 0xB6, 0x6C, 0x73, 0xBB, 0x64, 
+       /* 0x270 */ 0xEA, 0x61, 0x41, 0xAC, 0xC9, 0xD4, 0x54, 0xDF, 
+       /* 0x278 */ 0x87, 0x2F, 0xC7, 0x22, 0xB2, 0x26, 0xCC, 0x9F, 
+       /* 0x280 */ 0x59, 0x54, 0x68, 0x9F, 0xFC, 0xBE, 0x2A, 0x2F, 
+       /* 0x288 */ 0xC4, 0x55, 0x1C, 0x75, 0x40, 0x60, 0x17, 0x85, 
+       /* 0x290 */ 0x02, 0x55, 0x39, 0x8B, 0x7F, 0x05, 0x02, 0x03, 
+       /* 0x298 */ 0x01, 0x00, 0x01, 0xA3, 0x42, 0x30, 0x40, 0x30, 
+       /* 0x2a0 */ 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 
+       /* 0x2a8 */ 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 
+       /* 0x2b0 */ 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 
+       /* 0x2b8 */ 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 
+       /* 0x2c0 */ 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 
+       /* 0x2c8 */ 0x16, 0x04, 0x14, 0x9C, 0x5F, 0x00, 0xDF, 0xAA, 
+       /* 0x2d0 */ 0x01, 0xD7, 0x30, 0x2B, 0x38, 0x88, 0xA2, 0xB8, 
+       /* 0x2d8 */ 0x6D, 0x4A, 0x9C, 0xF2, 0x11, 0x91, 0x83, 0x30, 
+       /* 0x2e0 */ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 
+       /* 0x2e8 */ 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 
+       /* 0x2f0 */ 0x01, 0x01, 0x00, 0x4B, 0x36, 0xA6, 0x84, 0x77, 
+       /* 0x2f8 */ 0x69, 0xDD, 0x3B, 0x19, 0x9F, 0x67, 0x23, 0x08, 
+       /* 0x300 */ 0x6F, 0x0E, 0x61, 0xC9, 0xFD, 0x84, 0xDC, 0x5F, 
+       /* 0x308 */ 0xD8, 0x36, 0x81, 0xCD, 0xD8, 0x1B, 0x41, 0x2D, 
+       /* 0x310 */ 0x9F, 0x60, 0xDD, 0xC7, 0x1A, 0x68, 0xD9, 0xD1, 
+       /* 0x318 */ 0x6E, 0x86, 0xE1, 0x88, 0x23, 0xCF, 0x13, 0xDE, 
+       /* 0x320 */ 0x43, 0xCF, 0xE2, 0x34, 0xB3, 0x04, 0x9D, 0x1F, 
+       /* 0x328 */ 0x29, 0xD5, 0xBF, 0xF8, 0x5E, 0xC8, 0xD5, 0xC1, 
+       /* 0x330 */ 0xBD, 0xEE, 0x92, 0x6F, 0x32, 0x74, 0xF2, 0x91, 
+       /* 0x338 */ 0x82, 0x2F, 0xBD, 0x82, 0x42, 0x7A, 0xAD, 0x2A, 
+       /* 0x340 */ 0xB7, 0x20, 0x7D, 0x4D, 0xBC, 0x7A, 0x55, 0x12, 
+       /* 0x348 */ 0xC2, 0x15, 0xEA, 0xBD, 0xF7, 0x6A, 0x95, 0x2E, 
+       /* 0x350 */ 0x6C, 0x74, 0x9F, 0xCF, 0x1C, 0xB4, 0xF2, 0xC5, 
+       /* 0x358 */ 0x01, 0xA3, 0x85, 0xD0, 0x72, 0x3E, 0xAD, 0x73, 
+       /* 0x360 */ 0xAB, 0x0B, 0x9B, 0x75, 0x0C, 0x6D, 0x45, 0xB7, 
+       /* 0x368 */ 0x8E, 0x94, 0xAC, 0x96, 0x37, 0xB5, 0xA0, 0xD0, 
+       /* 0x370 */ 0x8F, 0x15, 0x47, 0x0E, 0xE3, 0xE8, 0x83, 0xDD, 
+       /* 0x378 */ 0x8F, 0xFD, 0xEF, 0x41, 0x01, 0x77, 0xCC, 0x27, 
+       /* 0x380 */ 0xA9, 0x62, 0x85, 0x33, 0xF2, 0x37, 0x08, 0xEF, 
+       /* 0x388 */ 0x71, 0xCF, 0x77, 0x06, 0xDE, 0xC8, 0x19, 0x1D, 
+       /* 0x390 */ 0x88, 0x40, 0xCF, 0x7D, 0x46, 0x1D, 0xFF, 0x1E, 
+       /* 0x398 */ 0xC7, 0xE1, 0xCE, 0xFF, 0x23, 0xDB, 0xC6, 0xFA, 
+       /* 0x3a0 */ 0x8D, 0x55, 0x4E, 0xA9, 0x02, 0xE7, 0x47, 0x11, 
+       /* 0x3a8 */ 0x46, 0x3E, 0xF4, 0xFD, 0xBD, 0x7B, 0x29, 0x26, 
+       /* 0x3b0 */ 0xBB, 0xA9, 0x61, 0x62, 0x37, 0x28, 0xB6, 0x2D, 
+       /* 0x3b8 */ 0x2A, 0xF6, 0x10, 0x86, 0x64, 0xC9, 0x70, 0xA7, 
+       /* 0x3c0 */ 0xD2, 0xAD, 0xB7, 0x29, 0x70, 0x79, 0xEA, 0x3C, 
+       /* 0x3c8 */ 0xDA, 0x63, 0x25, 0x9F, 0xFD, 0x68, 0xB7, 0x30, 
+       /* 0x3d0 */ 0xEC, 0x70, 0xFB, 0x75, 0x8A, 0xB7, 0x6D, 0x60, 
+       /* 0x3d8 */ 0x67, 0xB2, 0x1E, 0xC8, 0xB9, 0xE9, 0xD8, 0xA8, 
+       /* 0x3e0 */ 0x6F, 0x02, 0x8B, 0x67, 0x0D, 0x4D, 0x26, 0x57, 
+       /* 0x3e8 */ 0x71, 0xDA, 0x20, 0xFC, 0xC1, 0x4A, 0x50, 0x8D, 
+       /* 0x3f0 */ 0xB1, 0x28, 0xBA, 
+};
+static const lws_ss_x509_t _ss_x509_starfield_services_root_ca = {
+       .vhost_name = "starfield_services_root_ca",
+       .ca_der = _ss_der_starfield_services_root_ca,
+       .ca_der_len = 1011,
+};
+static const lws_ss_trust_store_t _ss_ts_s3_root_cert = {
+       .name = "s3-root-cert",
+       .count = 3,
+       .ssx509 = {
+               &_ss_x509_starfield_services_root_ca,
+               &_ss_x509_amazon_root_ca_1,
+               &_ss_x509_baltimore_cybertrust_root,
+       }
+};
+
+static const lws_ss_auth_t _ssau_sigv4_br = {
+       .name = "sigv4_br",
+       .type= "sigv4",
+       .streamtype = "(null)",
+       .blob_index = 0,
+};
+
+
+static const lws_ss_policy_t _ssp_s3PutObj = {
+       .streamtype = "s3PutObj",
+       .endpoint = "${s3bucket}.s3.amazonaws.com",
+       .auth = &_ssau_sigv4_br,
+       .metadata = (void *)&_md_s3PutObj_region,
+       .u = {
+               .http = {
+                       .method = "PUT",
+                       .url = "${s3Obj}",
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x11,
+       .priority = 0x0,
+       .port = 443,
+       .metadata_count = 8,
+       .protocol = 0,
+       .trust = {.store = &_ss_ts_s3_root_cert},
+       .aws_region= "region",
+       .aws_service= "service",
+};
+#define _ss_static_policy_entry _ssp_s3PutObj
+/* estimated footprint 3559 (when sizeof void * = 8) */
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-smd/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-smd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..db2f9eb
--- /dev/null
@@ -0,0 +1,187 @@
+project(lws-minimal-secure-streams-smd C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SYS_SMD 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+require_lws_config(LWS_WITH_SYS_FAULT_INJECTION 1 has_fault_injection)
+
+if (requirements)
+       add_executable(${PROJECT_NAME} minimal-secure-streams-smd.c)
+       
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32)
+       
+               if (VALGRIND)
+                       add_test(NAME ss-smd COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-smd>)
+               else()
+       
+                       add_test(NAME ss-smd COMMAND lws-minimal-secure-streams-smd)
+               endif()
+               set_tests_properties(ss-smd
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-smd
+                                    TIMEOUT 10)
+
+               if (has_fault_injection)
+                       if (VALGRIND)
+                               add_test(NAME ss-smd-fi1 COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-smd>
+                                       --fault-injection "ss/ss_create_smd"
+                                       --expected-exit 1)
+                               add_test(NAME ss-smd-fi2 COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-smd>
+                                       --fault-injection "ss/ss_create_smd_1"
+                                       --expected-exit 1)
+                               add_test(NAME ss-smd-fi3 COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-smd>
+                                       --fault-injection "ss/ss_create_smd_2"
+                                       --expected-exit 1)
+                      else()
+                               add_test(NAME ss-smd-fi1 COMMAND lws-minimal-secure-streams-smd
+                                        --fault-injection "ss/ss_create_smd"
+                                        --expected-exit 1)
+                               add_test(NAME ss-smd-fi2 COMMAND lws-minimal-secure-streams-smd
+                                        --fault-injection "ss/ss_create_smd_1"
+                                        --expected-exit 1)
+                                add_test(NAME ss-smd-fi3 COMMAND lws-minimal-secure-streams-smd
+                                        --fault-injection "ss/ss_create_smd_2"
+                                        --expected-exit 1) 
+                       endif()
+
+                       set_tests_properties(ss-smd-fi1
+                                           ss-smd-fi2
+                                           ss-smd-fi3
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-smd
+                                    TIMEOUT 5)
+               endif()
+     
+       
+       
+        endif()
+
+       if (websockets_shared)
+               target_link_libraries(${PROJECT_NAME} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${PROJECT_NAME} websockets_shared)
+       else()
+               target_link_libraries(${PROJECT_NAME} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${PROJECT_NAME}-client minimal-secure-streams-smd.c multi.c)
+
+               if (websockets_shared)
+                       target_link_libraries(${PROJECT_NAME}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${PROJECT_NAME}-client websockets_shared)
+               else()
+                       target_link_libraries(${PROJECT_NAME}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+               
+               #
+               # Define test dep to bring up and take down the test
+               # proxy
+               #
+
+               if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                       # uds abstract namespace for linux
+                       set(CTEST_SOCKET_PATH "@ctest-sspsmd_sspc-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               else()
+                       # filesystem socket for others
+                       set(CTEST_SOCKET_PATH "/tmp/ctest-sspsmd_sspc-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               endif()
+
+               add_test(NAME st_ssprxsmd_sspc COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                       ssproxysmd_sspc $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH}  -d1039)
+               set_tests_properties(st_ssprxsmd_sspc PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP ssproxysmd_sspc TIMEOUT 800)
+
+               add_test(NAME ki_ssprxsmd_sspc COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                       ssproxysmd_sspc $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH}  -d1039)
+               set_tests_properties(ki_ssprxsmd_sspc PROPERTIES FIXTURES_CLEANUP ssproxysmd_sspc)
+
+               #
+               # the client part that will connect to the proxy
+               #
+
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME sspcsmd_sspc COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-smd-client> -i +${CTEST_SOCKET_PATH})
+               else()
+                       add_test(NAME sspcsmd_sspc COMMAND lws-minimal-secure-streams-smd-client -i +${CTEST_SOCKET_PATH})
+               endif()
+               set_tests_properties(sspcsmd_sspc PROPERTIES
+                       WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-smd
+                       FIXTURES_REQUIRED "ssproxysmd_sspc"
+                       TIMEOUT 80)
+                       
+               
+               #
+               # Define test dep to bring up and take down the test
+               # proxy
+               #
+
+               if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                       # uds abstract namespace for linux
+                       set(CTEST_SOCKET_PATH "@ctest-mul-sspsmd_sspc-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               else()
+                       # filesystem socket for others
+                       set(CTEST_SOCKET_PATH "/tmp/ctest-mul-sspsmd_sspc-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               endif()
+
+               add_test(NAME st_mulssprxsmd_sspc COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                       mulssproxysmd_sspc $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH}  -d1039)
+               set_tests_properties(st_mulssprxsmd_sspc PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP mulssproxysmd_sspc TIMEOUT 800)
+
+               add_test(NAME ki_mulssprxsmd_sspc COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                       mulssproxysmd_sspc $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH}  -d1039)
+               set_tests_properties(ki_mulssprxsmd_sspc PROPERTIES FIXTURES_CLEANUP mulssproxysmd_sspc)
+
+               #
+               # multi tests for the client part that will connect to the proxy
+               #
+
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME mulsspcsmd_sspc COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-smd-client> -i +${CTEST_SOCKET_PATH} --multi -d1039)
+               else()
+                       add_test(NAME mulsspcsmd_sspc COMMAND lws-minimal-secure-streams-smd-client -i +${CTEST_SOCKET_PATH} --multi -d1039)
+               endif()
+               set_tests_properties(mulsspcsmd_sspc PROPERTIES
+                       WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-smd
+                       FIXTURES_REQUIRED "mulssproxysmd_sspc"
+                       TIMEOUT 80)
+               
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-smd/README.md b/minimal-examples/secure-streams/minimal-secure-streams-smd/README.md
new file mode 100644 (file)
index 0000000..41e9c7e
--- /dev/null
@@ -0,0 +1,132 @@
+# lws minimal secure streams SMD
+
+This application creates a Secure Stream link to LWS SMD, System
+Message Distribution.
+
+The SS is able to receive system messages matching a specified
+class filter, and issue system messages also using SS payload
+semantics.
+
+Both a direct api lws_smd participant and an SS based one are instantiated.
+They both filter on system messages.
+
+When the Secure Stream is created, it asks to send using normal the SS api.
+In the SS tx callback, it prepares a header and then send a NETWORK class
+message.
+
+Numbers of messages received each way and sent is compared after 2s and the
+test exits with a success or a fail.
+
+### Building and testing
+
+Build with
+
+ -DLWS_WITH_SECURE_STREAMS=1
+ -DLWS_WITH_SECURE_STREAMS_PROXY_API=1
+ -DLWS_WITH_MINIMAL_EXAMPLES=1
+
+The run ./bin/lws-minimal-secure-streams-smd alone (local SS and direct SMD tests)
+and after run ./bin/lws-minimal-secure-streams-proxy in one console and
+./bin-lws-minimal-secure-streams-smd-client in the other (SS proxy tests)
+
+### What's going on in the -client test
+
+The -client build version contains the test logic as usual, but outsources the
+policy and smd_ server part to the Secure Streams Proxy.
+
+ - start lws-minimal-secure-streams-proxy first
+ - start lws-minimal-secure-streams-smd-client
+1) When the client starts, we waits to hear the client state is OPERATIONAL in
+a direct smd participant callback.  When it is, he creates a Secure Stream of
+streamtype "_lws_smd", creating a local SS handle.
+
+2) The SS creation request is proxied to the SS proxy process over Unix Domain
+Sockets.  There it creates a Secure Stream object proxyside, and registers as
+an SMD participant... this smd-related behaviour is tied to the special
+streamtype name "_lws_smd".  The SMD registration uses a class mask passed to
+the proxy in the tx credit field of the serialization.
+
+3) SMD messages that pass the class mask filter are proxied back to the client
+over the connection.
+
+4) SMD messages created at the client are passed to the proxy and added to the
+proxy's SMD queue, if the same connection's class mask accepts the message then
+it will be proxied back to the client same as other messages.
+
+The minimal example produces a variety of messages on the SS link, including
+CPD detect trigger.  The SS link is set up to only accept messages of classes
+LWSSMDCL_SYSTEM_STATE and LWSSMDCL_NETWORK, INTERACTION type messages are
+not accepted.
+
+### multi via proxy
+
+If the -client version is run with `--multi`, it spawns four worker processes
+which send and confirm SMD messages between each other via the SS proxy.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+--multi|Fork four worker processes that send and check messages to each other over sspc proxy
+
+```
+$ ./bin/lws-minimal-secure-streams-smd -d 1151
+[2020/06/18 21:44:54:5148] U: LWS Secure Streams SMD test client [-d<verb>]
+[2020/06/18 21:44:54:5601] I: Initial logging level 1151
+[2020/06/18 21:44:54:5605] I: Libwebsockets version: 4.0.99-v4.0.0-174-ga8a2eb954 v4.0.0-174-ga8a2eb954
+[2020/06/18 21:44:54:5607] I: IPV6 not compiled in
+...
+[2020/06/18 21:44:54:7906] D: _lws_state_transition: system: changed 11 'AUTH2' -> 12 'OPERATIONAL'
+[2020/06/18 21:44:54:7906] D: _realloc: size 81: lws_smd_msg_alloc
+[2020/06/18 21:44:54:7907] I: lws_cancel_service
+[2020/06/18 21:44:54:7912] I: lws_state_transition_steps: CONTEXT_CREATED -> OPERATIONAL
+[2020/06/18 21:44:54:7919] N: myss_tx: sending SS smd
+[2020/06/18 21:44:54:7940] D: _realloc: size 84: lws_smd_msg_alloc
+[2020/06/18 21:44:54:7944] I: lws_cancel_service
+[2020/06/18 21:44:54:7966] D: direct_smd_cb: class: 0x2, ts: 3139600721554
+[2020/06/18 21:44:54:7972] D: 
+[2020/06/18 21:44:54:7990] D: 0000: 7B 22 73 74 61 74 65 22 3A 22 49 4E 49 54 49 41    {"state":"INITIA
+[2020/06/18 21:44:54:7998] D: 0010: 4C 49 5A 45 44 22 7D                               LIZED"}         
+[2020/06/18 21:44:54:8001] D: 
+[2020/06/18 21:44:54:8016] I: myss_rx: len 39, flags: 3
+[2020/06/18 21:44:54:8018] I: 
+[2020/06/18 21:44:54:8021] I: 0000: 00 00 00 00 00 00 00 02 00 00 02 DA FE C9 26 92    ..............&.
+[2020/06/18 21:44:54:8022] I: 0010: 7B 22 73 74 61 74 65 22 3A 22 49 4E 49 54 49 41    {"state":"INITIA
+[2020/06/18 21:44:54:8023] I: 0020: 4C 49 5A 45 44 22 7D                               LIZED"}         
+[2020/06/18 21:44:54:8023] I: 
+[2020/06/18 21:44:54:8029] D: direct_smd_cb: class: 0x2, ts: 3139600724243
+[2020/06/18 21:44:54:8029] D: 
+[2020/06/18 21:44:54:8030] D: 0000: 7B 22 73 74 61 74 65 22 3A 22 49 46 41 43 45 5F    {"state":"IFACE_
+[2020/06/18 21:44:54:8031] D: 0010: 43 4F 4C 44 50 4C 55 47 22 7D                      COLDPLUG"}      
+[2020/06/18 21:44:54:8032] D: 
+...
+[2020/06/18 21:44:54:8112] D: direct_smd_cb: class: 0x4, ts: 3139600732952
+[2020/06/18 21:44:54:8112] D: 
+[2020/06/18 21:44:54:8114] D: 0000: 7B 22 73 6F 6D 74 68 69 6E 67 22 3A 22 6E 6F 74    {"somthing":"not
+[2020/06/18 21:44:54:8115] D: 0010: 73 65 65 6E 62 79 73 73 72 78 22 7D                seenbyssrx"}    
+[2020/06/18 21:44:54:8115] D: 
+[2020/06/18 21:44:57:5823] I: 11 12 1
+[2020/06/18 21:44:57:5838] I: lws_context_destroy: ctx 0x4f61db0
+[2020/06/18 21:44:57:5849] D: _lws_state_transition: system: changed 12 'OPERATIONAL' -> 13 'POLICY_INVALID'
+[2020/06/18 21:44:57:5851] D: _realloc: size 84: lws_smd_msg_alloc
+[2020/06/18 21:44:57:5853] I: lws_cancel_service
+[2020/06/18 21:44:57:5871] I: lws_destroy_event_pipe
+[2020/06/18 21:44:57:5906] I: lws_pt_destroy: pt destroyed
+[2020/06/18 21:44:57:5913] I: lws_context_destroy2: ctx 0x4f61db0
+[2020/06/18 21:44:57:5936] D: lwsac_free: head (nil)
+[2020/06/18 21:44:57:5947] D: 0x455970: post vh listl
+[2020/06/18 21:44:57:5950] D: 0x455970: post pdl
+[2020/06/18 21:44:57:5961] D: 0x455970: baggage
+[2020/06/18 21:44:57:5968] D: 0x455970: post dc2
+[2020/06/18 21:44:57:6010] D: lws_context_destroy3: ctx 0x4f61db0 freed
+[2020/06/18 21:44:57:6014] U: Completed: OK
+```
\ No newline at end of file
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-smd/minimal-secure-streams-smd.c b/minimal-examples/secure-streams/minimal-secure-streams-smd/minimal-secure-streams-smd.c
new file mode 100644 (file)
index 0000000..1abb074
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * lws-minimal-secure-streams-smd
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates a minimal http client using secure streams to access the
+ * SMD api.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted, bad = 1, count_p1, count_p2, count_tx, expected = 0;
+static unsigned int how_many_msg = 100, usec_interval = 1000;
+static lws_sorted_usec_list_t sul_timeout;
+
+/*
+ * If the -proxy app is fulfilling our connection, then we don't need to have
+ * the policy in the client.
+ *
+ * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over
+ * a Unix Domain Socket.  To test that, you need to separately run the
+ * ./lws-minimal-secure-streams-proxy test app on the same machine.
+ */
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+               "\"schema-version\":1,"
+               "\"s\": ["
+                       "{"
+                               /*
+                                * "captive_portal_detect" describes
+                                * what to do in order to check if the path to
+                                * the Internet is being interrupted by a
+                                * captive portal.  If there's a larger policy
+                                * fetched from elsewhere, it should also include
+                                * this since it needs to be done at least after
+                                * every DHCP acquisition
+                                */
+                               "\"captive_portal_detect\": {"
+                                       "\"endpoint\": \"connectivitycheck.android.com\","
+                                       "\"http_url\": \"generate_204\","
+                                       "\"port\": 80,"
+                                       "\"protocol\": \"h1\","
+                                       "\"http_method\": \"GET\","
+                                       "\"opportunistic\": true,"
+                                       "\"http_expect\": 204,"
+                                       "\"http_fail_redirect\": true"
+                               "}"
+                       "}"
+               "]"
+       "}"
+;
+
+#endif
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+       char                            alternate;
+} myss_t;
+
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       /*
+        * Call the helper to translate into a real smd message and forward to
+        * this context / process smd participants... except us, since we
+        * definitely already received it
+        */
+
+       if (lws_smd_ss_rx_forward(userobj, buf, len))
+               lwsl_warn("%s: forward failed\n", __func__);
+
+       count_p1++;
+
+       return LWSSSSRET_OK;
+}
+
+static void
+sul_tx_periodic_cb(lws_sorted_usec_list_t *sul)
+{
+       myss_t *m = lws_container_of(sul, myss_t, sul);
+
+       lwsl_info("%s: requesting TX\n", __func__);
+       if (lws_ss_request_tx(m->ss))
+               lwsl_info("%s: req failed\n", __func__);
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_info("%s: sending SS smd\n", __func__);
+
+       /*
+        * The SS RX isn't going to see INTERACTION messages, because its class
+        * filter doesn't accept INTERACTION class messages.  The direct
+        * participant we also set up for the test will see them though.
+        *
+        * Let's alternate between sending NETWORK class smd messages and
+        * INTERACTION so we can test both rx paths
+        */
+
+       m->alternate++;
+
+       if (m->alternate == 4) {
+               /*
+                * after a few, let's request a CPD check
+                */
+
+               if (lws_smd_ss_msg_printf(lws_ss_tag(m->ss), buf, len, LWSSMDCL_NETWORK,
+                                         "{\"trigger\": \"cpdcheck\", "
+                                          "\"src\":\"SS-test\"}"))
+                       return LWSSSSRET_TX_DONT_SEND;
+       } else
+               if (lws_smd_ss_msg_printf(lws_ss_tag(m->ss), buf, len,
+                                         (m->alternate & 1) ? LWSSMDCL_NETWORK :
+                                                              LWSSMDCL_INTERACTION,
+                                         (m->alternate & 1) ?
+                                              "{\"class\":\"NETWORK\",\"x\":%d}" :
+                                              "{\"class\":\"INTERACTION\",\"x\":%d}",
+                                              count_tx))
+                       return LWSSSSRET_TX_DONT_SEND;
+
+       *flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
+
+       count_tx++;
+
+       lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul,
+                        sul_tx_periodic_cb, usec_interval);
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *h_src, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_notice("%s: %s: %s (%d), ord 0x%x\n", __func__, lws_ss_tag(m->ss),
+                   lws_ss_state_name((int)state), state, (unsigned int)ack);
+
+       if (state == LWSSSCS_DESTROYING) {
+               lws_sul_cancel(&m->sul);
+               return LWSSSSRET_OK;
+       }
+
+       if (state == LWSSSCS_CONNECTED) {
+               lwsl_notice("%s: CONNECTED\n", __func__);
+               lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul,
+                                sul_tx_periodic_cb, 1);
+               return LWSSSSRET_OK;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static const lws_ss_info_t ssi_lws_smd = {
+       .handle_offset            = offsetof(myss_t, ss),
+       .opaque_user_data_offset  = offsetof(myss_t, opaque_data),
+       .rx                       = myss_rx,
+       .tx                       = myss_tx,
+       .state                    = myss_state,
+       .user_alloc               = sizeof(myss_t),
+       .streamtype               = LWS_SMD_STREAMTYPENAME,
+       .manual_initial_tx_credit = LWSSMDCL_SYSTEM_STATE |
+                                   LWSSMDCL_METRICS |
+                                   LWSSMDCL_NETWORK,
+};
+
+/* for comparison, this is a non-SS lws_smd participant */
+
+static int
+direct_smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
+             void *buf, size_t len)
+{
+       struct lws_context **pctx = (struct lws_context **)opaque;
+
+//     lwsl_notice("%s: class: 0x%x, ts: %llu\n", __func__, _class,
+//               (unsigned long long)timestamp);
+//     lwsl_hexdump_notice(buf, len);
+
+       count_p2++;
+
+       if (_class != LWSSMDCL_SYSTEM_STATE)
+               return 0;
+
+       if (!lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
+
+#if !defined(LWS_SS_USE_SSPC)
+               /*
+                * Let's trigger a CPD check, just as a test.  SS can't see it
+                * anyway since it doesn't listen for NETWORK but the direct /
+                * local participant will see it and the result
+                *
+                * This process doesn't run the smd / captive portal action
+                * when it's a client of the SS proxy.  SMD has to be passed
+                * via the SS _lws_smd proxied connection in that case.
+                */
+               (void)lws_smd_msg_printf(*pctx, LWSSMDCL_NETWORK,
+                                  "{\"trigger\": \"cpdcheck\", \"src\":\"direct-test\"}");
+#endif
+
+               /*
+                * Create the SS link to lws_smd... notice in ssi_lws_smd
+                * above, we tell this link to use a class filter that excludes
+                * NETWORK messages.
+                */
+
+               if (lws_ss_create(*pctx, 0, &ssi_lws_smd, NULL, NULL, NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+                       interrupted = 1;
+                       lws_cancel_service(*pctx);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+
+static void
+sul_timeout_cb(lws_sorted_usec_list_t *sul)
+{
+       lwsl_notice("%s: test finishing\n", __func__);
+       interrupted = 1;
+}
+
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+extern int smd_ss_multi_test(int argc, const char **argv);
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+
+#if defined(LWS_SS_USE_SSPC)
+       if (lws_cmdline_option(argc, argv, "--multi"))
+               return smd_ss_multi_test(argc, argv);
+#endif
+
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       if ((p = lws_cmdline_option(argc, argv, "--count")))
+               how_many_msg = (unsigned int)atol(p);
+
+       if ((p = lws_cmdline_option(argc, argv, "--interval")))
+               usec_interval = (unsigned int)atol(p);
+
+       lwsl_user("LWS Secure Streams SMD test client [-d<verb>]: "
+                 "%u msgs at %uus interval\n", how_many_msg, usec_interval);
+
+       info.fd_limit_per_thread        = 1 + 6 + 1;
+       info.port                       = CONTEXT_PORT_NO_LISTEN;
+#if !defined(LWS_SS_USE_SSPC)
+       info.pss_policies_json          = default_ss_policy;
+#else
+       info.protocols                  = lws_sspc_protocols;
+       {
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#endif
+       info.options                    = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                                         LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+
+       info.early_smd_cb               = direct_smd_cb;
+       info.early_smd_class_filter     = 0xffffffff;
+       info.early_smd_opaque           = &context;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+#if defined(LWS_SS_USE_SSPC)
+       if (!lws_create_vhost(context, &info)) {
+               lwsl_err("%s: failed to create default vhost\n", __func__);
+               goto bail;
+       }
+#endif
+
+       /* set up the test timeout */
+
+       lws_sul_schedule(context, 0, &sul_timeout, sul_timeout_cb,
+                        (how_many_msg * (usec_interval + 50000)) + LWS_US_PER_SEC);
+
+       /* the event loop */
+
+       while (lws_service(context, 0) >= 0 && !interrupted)
+               ;
+
+       /* compare what happened with what we expect */
+
+#if defined(LWS_SS_USE_SSPC)
+       /* if SSPC
+        *
+        *  - the SS _lws_smd link does not enable INTERACTION class, so doesn't
+        *    see these messages (count_p1 is half count_tx)
+        *
+        *  - the direct smd participant sees local state, but it doesn't send
+        *    any local CPD request, since as a client it doesn't do CPD
+        *    directly (count_p2 -= 1 compared to non-SSPC)
+        *
+        *  - one CPD trigger is sent on the proxied SS link (countp1 += 1)
+        */
+       if (count_p1 >= 6 && count_p2 >= 11 && count_tx >= 12)
+#else
+       /* if not SSPC, then we can see direct smd activity */
+       if (count_p1 >= 2 && count_p2 >= 15 && count_tx >= 5)
+#endif
+               bad = 0;
+
+       lwsl_notice("%d %d %d\n", count_p1, count_p2, count_tx);
+
+#if defined(LWS_SS_USE_SSPC)
+bail:
+#endif
+       lws_context_destroy(context);
+
+       if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
+               expected = atoi(p);
+
+       if (bad == expected) {
+               lwsl_user("Completed: OK (seen expected %d)\n", expected);
+               return 0;
+       }
+
+       lwsl_err("Completed: failed: exit %d, expected %d\n", bad, expected);
+
+       return 1;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-smd/multi.c b/minimal-examples/secure-streams/minimal-secure-streams-smd/multi.c
new file mode 100644 (file)
index 0000000..fcf851d
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * lws-minimal-secure-streams-smd
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates a minimal http client using secure streams to access the
+ * SMD api.  This file is only built when LWS_SS_USE_SSPC defined.
+ *
+ * This is an alternative test implementation selected by --multi at runtime,
+ * it's in its own file to stop muddying up the main test sources.  It's only
+ * available when built with SSPC / produces -client executable.
+ *
+ * We will fork several times, the original thread and the forks hook up to
+ * the proxy with smd SS, each fork waits a second for everyone to have joined,
+ * and then each fork (NOT the original process) sends a bunch of user messages
+ * that all the forks should receive, having been distributed by SMD and the
+ * ss proxy.
+ *
+ * The participants check they received all the messages expected from everyone
+ * and then send a final message indicating success and exits.  The original
+ * fork is watching for these to arrive before the timeout, if so it's a PASS.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int bad = 1, interrupted;
+
+/* number of forks */
+#define FORKS 4
+/* number of messages each will send, eg, 4 forks 64 message == 256 messages */
+#define MSGCOUNT 64
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       uint64_t                        seen_mask[FORKS];
+       int                             seen_msgs[FORKS];
+       lws_sorted_usec_list_t          sul;
+       int                             count;
+       char                            seen_all;
+       char                            send_seen_all;
+       char                            starting;
+} myss_t;
+
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+multi_myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+       const char *p;
+       int fk, t, n;
+       size_t al;
+
+       /* ignore our and other forks announcing their result */
+
+       if (lws_json_simple_find((const char *)buf, len, "\"seen_all\":", &al))
+               return LWSSSSRET_OK;
+
+       /*
+        * otherwise once we saw the expected messages, any other messages
+        * coming in this class are wrong
+        */
+
+       if (m->seen_all) {
+               lwsl_err("%s: unexpected extra messages\n", __func__);
+               return LWSSSSRET_DESTROY_ME;
+       }
+
+       p = lws_json_simple_find((const char *)buf, len, "\"fork\":", &al);
+       if (!p)
+               return LWSSSSRET_DESTROY_ME;
+       fk = atoi(p);
+       if (fk < 1 || fk > FORKS)
+               return LWSSSSRET_DESTROY_ME;
+
+       p = lws_json_simple_find((const char *)buf, len, "\"test\":", &al);
+       if (!p)
+               return LWSSSSRET_DESTROY_ME;
+       t = atoi(p);
+
+       if (t < 0 || t >= MSGCOUNT)
+               return LWSSSSRET_DESTROY_ME;
+
+       m->seen_mask[fk - 1] |= 1ull << t;
+       m->seen_msgs[fk - 1]++; /* keep an eye on dupes */
+
+       /* Have we seen a full set of messages from everyone? */
+
+       for (n = 0; n < FORKS; n++) {
+               if (m->seen_msgs[n] != (int)MSGCOUNT)
+                       return LWSSSSRET_OK;
+               if (m->seen_mask[n] != 0xffffffffffffffffull)
+                       return LWSSSSRET_OK;
+       }
+
+       /*
+        * Oh... so we have finished collecting messages
+        */
+
+       lwsl_user("%s: test thread %d: %s received all messages\n", __func__,
+                       (int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)),
+                       lws_ss_tag(m->ss));
+       m->seen_all = m->send_seen_all = 1;
+
+       /*
+        * Prepare to inform the original process we saw everything
+        * from everyone OK
+        */
+
+       lws_ss_request_tx(m->ss);
+
+       return LWSSSSRET_OK;
+}
+
+static void
+sul_multi_tx_periodic_cb(lws_sorted_usec_list_t *sul)
+{
+       myss_t *m = lws_container_of(sul, myss_t, sul);
+
+       if (!m->send_seen_all && m->seen_all) {
+               lws_ss_destroy(&m->ss);
+               return;
+       }
+
+       m->starting = 1;
+       if (m->count < MSGCOUNT ||  m->send_seen_all)
+               lws_ss_request_tx(m->ss);
+}
+
+static lws_ss_state_return_t
+multi_myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       /*
+        * We want to send exactly MSGCOUNT user class smd messages
+        */
+
+       if (!m->starting || (m->count == MSGCOUNT && !m->send_seen_all))
+               return LWSSSSRET_TX_DONT_SEND;
+
+//     lwsl_notice("%s: sending SS smd\n", __func__);
+
+       lws_ser_wu64be(buf, 1 << LWSSMDCL_USER_BASE_BITNUM);
+       lws_ser_wu64be(buf + 8, 0); /* valgrind notices uninitialized if left */
+
+       if (m->send_seen_all) {
+               *len = LWS_SMD_SS_RX_HEADER_LEN + (unsigned int)
+                       lws_snprintf((char *)buf + LWS_SMD_SS_RX_HEADER_LEN, *len,
+                            "{\"class\":\"user\",\"fork\": %d,\"seen_all\":true}",
+                            (int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)));
+
+               m->send_seen_all = 0;
+               lwsl_info("%s: test thread %d: sent summary message\n", __func__,
+                               (int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)));
+       } else
+               *len = LWS_SMD_SS_RX_HEADER_LEN + (unsigned int)
+                       lws_snprintf((char *)buf + LWS_SMD_SS_RX_HEADER_LEN, *len,
+                            "{\"class\":\"user\",\"fork\": %d,\"test\":%u}",
+                            (int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)),
+                            m->count++);
+
+       *flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
+
+       lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul,
+                       sul_multi_tx_periodic_cb, 25 * LWS_US_PER_MS);
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+multi_myss_state(void *userobj, void *h_src, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+       int n;
+
+       lwsl_notice("%s: %s: %s (%d), ord 0x%x\n", __func__, lws_ss_tag(m->ss),
+                   lws_ss_state_name((int)state), state, (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_DESTROYING:
+               lws_sul_cancel(&m->sul);
+               interrupted = 1;
+               return 0;
+
+       case LWSSSCS_CONNECTED:
+               lwsl_notice("%s: CONNECTED: test fork %d\n", __func__,
+                               (int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)));
+               /*
+                * Because in this test everybody is watching and counting
+                * everybody else's messages from different forks, we have to
+                * hold off starting sending for 2s so all forks can join the
+                * proxy first and not miss anything
+                */
+               lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul,
+                               sul_multi_tx_periodic_cb, 2 * LWS_US_PER_SEC);
+               m->starting = 0;
+               return 0;
+       case LWSSSCS_DISCONNECTED:
+               for (n = 0; n < FORKS; n++)
+                       lwsl_notice("%s: testfork %d: peer %d: seen_msg = %d, "
+                                   "seen make = 0x%llx\n", __func__,
+                                   (int)(intptr_t)lws_context_user(lws_ss_get_context(m->ss)),
+                                   n, m->seen_msgs[n],
+                                   (unsigned long long)m->seen_mask[n]);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const lws_ss_info_t ssi_multi_lws_smd = {
+       .handle_offset            = offsetof(myss_t, ss),
+       .opaque_user_data_offset  = offsetof(myss_t, opaque_data),
+       .rx                       = multi_myss_rx,
+       .tx                       = multi_myss_tx,
+       .state                    = multi_myss_state,
+       .user_alloc               = sizeof(myss_t),
+       .streamtype               = LWS_SMD_STREAMTYPENAME,
+       .manual_initial_tx_credit = 1 << LWSSMDCL_USER_BASE_BITNUM,
+};
+
+static lws_ss_state_return_t
+multi_myss_rx_monitor(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+       const char *p;
+       size_t al;
+       int fk, n;
+
+       /* ignore our and other forks announcing their result */
+
+       if (!lws_json_simple_find((const char *)buf, len, "\"seen_all\":", &al))
+               return LWSSSSRET_OK;
+
+       p = lws_json_simple_find((const char *)buf, len, "\"fork\":", &al);
+       if (!p)
+               return LWSSSSRET_DESTROY_ME;
+       fk = atoi(p);
+       if (fk < 1 || fk > FORKS)
+               return LWSSSSRET_DESTROY_ME;
+
+       if (m->seen_msgs[fk - 1])
+               /* expected only once ... dupe */
+               return LWSSSSRET_DESTROY_ME;
+
+       m->seen_msgs[fk - 1] = 1;
+
+       for (n = 0; n < FORKS; n++)
+               if (!m->seen_msgs[n])
+                       return LWSSSSRET_OK;
+
+       /* the test has succeeded */
+
+       bad = 0;
+       interrupted = 1;
+
+       return LWSSSSRET_OK;
+}
+
+static const lws_ss_info_t ssi_multi_lws_smd_monitor = {
+       .handle_offset            = offsetof(myss_t, ss),
+       .opaque_user_data_offset  = offsetof(myss_t, opaque_data),
+       .rx                       = multi_myss_rx_monitor,
+//     .state                    = multi_myss_state_monitor,
+       .user_alloc               = sizeof(myss_t),
+       .streamtype               = LWS_SMD_STREAMTYPENAME,
+       .manual_initial_tx_credit = 1 << LWSSMDCL_USER_BASE_BITNUM,
+};
+
+/* for comparison, this is a non-SS lws_smd participant */
+
+static int
+direct_smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
+             void *buf, size_t len)
+{
+       struct lws_context **pctx = (struct lws_context **)opaque;
+
+       if (_class != LWSSMDCL_SYSTEM_STATE)
+               return 0;
+
+       if (!lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
+
+               /*
+                * Create the SSPC link to lws_smd... notice in ssi_lws_smd
+                * above, we tell this link to use the user class filter.
+                *
+                * If context->user is zero, we are the original process
+                * monitoring the progress of the others, otherwise we are
+                * 1 .. FORKS and producing / checking the smd messages
+                */
+
+               lwsl_info("%s: starting ss for test fork %d\n", __func__,
+                               (int)(intptr_t)lws_context_user(*pctx));
+
+               if (lws_ss_create(*pctx, 0, lws_context_user(*pctx) ?
+                               &ssi_multi_lws_smd /* forked process send / check */:
+                               &ssi_multi_lws_smd_monitor /* original monitors */,
+                               NULL, NULL, NULL, NULL)) {
+                       lwsl_err("%s: failed to create secure stream\n",
+                                __func__);
+
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+
+static void
+sul_timeout_cb(lws_sorted_usec_list_t *sul)
+{
+       interrupted = 1;
+}
+
+int
+smd_ss_multi_test(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       lws_sorted_usec_list_t sul_timeout;
+       struct lws_context *context;
+       pid_t pid;
+       int n;
+
+       lwsl_user("LWS Secure Streams SMD MULTI test client [-d<verb>]\n");
+
+       for (n = 0; n < FORKS; n++) {
+               pid = fork();
+               if (!pid) /* forked child */ {
+                       break;
+               }
+               lwsl_notice("%s: forked test process %u\n", __func__, pid);
+       }
+
+       if (n == FORKS)
+               /* the original process */
+               n = -1; /* so original ends up with context.user as 0 below */
+
+       memset(&info, 0, sizeof info);
+       memset(&sul_timeout, 0, sizeof sul_timeout);
+
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+
+       info.fd_limit_per_thread        = 1 + 6 + 1;
+       info.port                       = CONTEXT_PORT_NO_LISTEN;
+       info.protocols                  = lws_sspc_protocols;
+       info.options                    = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                                         LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+
+       info.early_smd_cb               = direct_smd_cb;
+       info.early_smd_class_filter     = 0xffffffff;
+       info.early_smd_opaque           = &context;
+
+       info.user                       = (void *)(intptr_t)(n + 1);
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       if (!lws_create_vhost(context, &info)) {
+               lwsl_err("%s: failed to create default vhost\n", __func__);
+               goto bail;
+       }
+
+       /* set up the test timeout */
+
+       lws_sul_schedule(context, 0, &sul_timeout, sul_timeout_cb,
+                        10 * LWS_US_PER_SEC);
+
+       /* the event loop */
+
+       while (lws_service(context, 0) >= 0 && !interrupted)
+               ;
+
+bail:
+       lws_context_destroy(context);
+
+       if (n == -1)
+               lwsl_user("%s: finished %s\n", __func__, bad ? "FAIL" : "PASS");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..da53721
--- /dev/null
@@ -0,0 +1,26 @@
+project(lws-minimal-secure-streams-staticpolicy C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-staticpolicy)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams.c)
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/README.md b/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/README.md
new file mode 100644 (file)
index 0000000..64002b2
--- /dev/null
@@ -0,0 +1,61 @@
+# lws minimal secure streams static policy
+
+The application goes to https://warmcat.com and reads index.html there.
+
+It does it using a static Secure Streams policy generated from JSON by
+policy2c example. 
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
+```
+$ ./lws-minimal-secure-streams-staticpolicy
+[2020/03/26 15:49:12:6640] U: LWS secure streams static policy test client [-d<verb>]
+[2020/03/26 15:49:12:7067] N: lws_create_context: using ss proxy bind '(null)', port 0, ads '(null)'
+[2020/03/26 15:49:12:7567] N: lws_tls_client_create_vhost_context: using mem client CA cert 914
+[2020/03/26 15:49:12:7597] N: lws_tls_client_create_vhost_context: using mem client CA cert 1011
+[2020/03/26 15:49:12:7603] N: lws_tls_client_create_vhost_context: using mem client CA cert 1425
+[2020/03/26 15:49:12:7605] N: lws_tls_client_create_vhost_context: using mem client CA cert 1011
+[2020/03/26 15:49:12:9713] N: lws_system_cpd_set: setting CPD result OK
+[2020/03/26 15:49:13:9625] N: ss_api_amazon_auth_rx: acquired 588-byte api.amazon.com auth token, exp 3600s
+[2020/03/26 15:49:13:9747] U: myss_state: LWSSSCS_CREATING, ord 0x0
+[2020/03/26 15:49:13:9774] U: myss_state: LWSSSCS_CONNECTING, ord 0x0
+[2020/03/26 15:49:14:1897] U: myss_state: LWSSSCS_CONNECTED, ord 0x0
+[2020/03/26 15:49:14:1926] U: myss_rx: len 1520, flags: 1
+[2020/03/26 15:49:14:1945] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:1946] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:1947] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:1948] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:1949] U: myss_rx: len 583, flags: 0
+[2020/03/26 15:49:14:2087] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2089] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2090] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2091] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2092] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2093] U: myss_rx: len 583, flags: 0
+[2020/03/26 15:49:14:2109] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2110] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2111] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2112] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2113] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2114] U: myss_rx: len 583, flags: 0
+[2020/03/26 15:49:14:2135] U: myss_rx: len 1520, flags: 0
+[2020/03/26 15:49:14:2136] U: myss_rx: len 1358, flags: 0
+[2020/03/26 15:49:14:2136] U: myss_rx: len 0, flags: 2
+[2020/03/26 15:49:14:2138] U: myss_state: LWSSSCS_QOS_ACK_REMOTE, ord 0x0
+[2020/03/26 15:49:14:2139] N: myss_state: LWSSSCS_QOS_ACK_REMOTE
+[2020/03/26 15:49:14:2170] U: myss_state: LWSSSCS_DISCONNECTED, ord 0x0
+[2020/03/26 15:49:14:2192] U: myss_state: LWSSSCS_DESTROYING, ord 0x0
+[2020/03/26 15:49:14:2265] E: lws_context_destroy3
+[2020/03/26 15:49:14:2282] U: Completed: OK
+
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/minimal-secure-streams.c
new file mode 100644 (file)
index 0000000..1d7b869
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * lws-minimal-secure-streams-staticpolicy
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates a minimal http client using secure streams api.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.
+ *
+ * This example is built two different ways from the same source... one includes
+ * the policy everything needed to fulfil the stream directly.  The other -client
+ * variant has no policy itself and some other minor init changes, and connects
+ * to the -proxy example to actually get the connection done.
+ *
+ * In the -client build case, the example does not even init the tls libraries
+ * since the proxy part will take care of all that.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted, bad = 1, force_cpd_fail_portal,
+          force_cpd_fail_no_internet;
+static lws_state_notify_link_t nl;
+
+/*
+ * This is example builds with a static policy autogenerated from a JSON
+ * policy...
+ */
+#include "static-policy.h"
+
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+} myss_t;
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+/* secure streams payload interface */
+
+static int
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+//     myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
+       lwsl_hexdump_info(buf, len);
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+static int
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       //myss_t *m = (myss_t *)userobj;
+
+       return 0;
+}
+
+static int
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
+                 (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               if (lws_ss_set_metadata(m->ss, "uptag", "myuptag123", 10))
+                       lwsl_err("%s set metadata uptag failed\n", __func__);
+               if (lws_ss_set_metadata(m->ss, "ctype", "myctype", 7))
+                       lwsl_err("%s set metadata ctype failed\n", __func__);
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               break;
+       case LWSSSCS_QOS_ACK_REMOTE:
+               lwsl_notice("%s: LWSSSCS_QOS_ACK_REMOTE\n", __func__);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+                       lws_ss_info_t ssi;
+
+                       /* We're making an outgoing secure stream ourselves */
+
+                       memset(&ssi, 0, sizeof(ssi));
+                       ssi.handle_offset = offsetof(myss_t, ss);
+                       ssi.opaque_user_data_offset = offsetof(myss_t,
+                                                              opaque_data);
+                       ssi.rx = myss_rx;
+                       ssi.tx = myss_tx;
+                       ssi.state = myss_state;
+                       ssi.user_alloc = sizeof(myss_t);
+                       ssi.streamtype = "mintest";
+
+                       if (lws_ss_create(context, 0, &ssi, NULL, NULL,
+                                         NULL, NULL)) {
+                               lwsl_err("%s: failed to create secure stream\n",
+                                        __func__);
+                               return -1;
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS secure streams static policy test client [-d<verb>]\n");
+
+       /* these options are mutually exclusive if given */
+
+       if (lws_cmdline_option(argc, argv, "--force-portal"))
+               force_cpd_fail_portal = 1;
+
+       if (lws_cmdline_option(argc, argv, "--force-no-internet"))
+               force_cpd_fail_no_internet = 1;
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#else
+       info.pss_policies = &_ss_static_policy_entry;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /*
+        * Set the related lws_system blobs
+        *
+        * ...direct_set() sets a pointer, so the thing pointed to has to have
+        * a suitable lifetime, eg, something that already exists on the heap or
+        * a const string in .rodata like this
+        */
+
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_SERIAL, 0),
+                                  (const uint8_t *)"SN12345678", 10);
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION, 0),
+                                  (const uint8_t *)"v0.01", 5);
+
+       /*
+        * ..._heap_append() appends to a buflist kind of arrangement on heap,
+        * just one block is fine, otherwise it will concatenate the fragments
+        * in the order they were appended (and take care of freeing them at
+        * context destroy time). ..._heap_empty() is also available to remove
+        * everything that was already allocated.
+        *
+        * Here we use _heap_append() just so it's tested as well as direct set.
+        */
+
+       lws_system_blob_heap_append(lws_system_get_blob(context,
+                                   LWS_SYSBLOB_TYPE_DEVICE_TYPE, 0),
+                                   (const uint8_t *)"spacerocket", 11);
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/static-policy.h b/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/static-policy.h
new file mode 100644 (file)
index 0000000..b772a6a
--- /dev/null
@@ -0,0 +1,1513 @@
+/*
+ * Autogenerated from the following JSON policy
+ */
+
+#if 0
+{
+       "release": "01234567",
+       "product": "myproduct",
+       "schema-version": 1,
+       "retry": [{
+               "default": {
+                       "backoff": [1000, 2000, 3000, 5000, 10000],
+                       "conceal": 5,
+                       "jitterpc": 20,
+                       "svalidping": 30,
+                       "svalidhup": 35
+               }
+       }],
+       "certs": [{
+               "isrg_root_x1": "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZLubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc="
+       }, {
+               "LEX3_isrg_root_x1": "MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrXNSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHlNpi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7DcGu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgzuEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMBAAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEFBQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsGAQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYDVR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIBABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGxA/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRMUM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOuOsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vwp7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKRPB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5brUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt"
+       }, {
+       "amazon_root_ca_1": "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5"
+       }, {
+               "digicert_global_root_g2": "MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTflMrY="
+       }, {
+               "digicert_global_ca_g2": "MIIEizCCA3OgAwIBAgIQDI7gyQ1qiRWIBAYe4kH5rzANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0yODA4MDExMjAwMDBaMEQxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEdsb2JhbCBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANNIfL7zBYZdW9UvhU5L4IatFaxhz1uvPmoKR/uadpFgC4przc/cV35gmAvkVNlW7SHMArZagV+Xau4CLyMnuG3UsOcGAngLH1ypmTb+u6wbBfpXzYEQQGfWMItYNdSWYb7QjHqXnxr5IuYUL6nG6AEfq/gmD6yOTSwyOR2Bm40cZbIc22GoiS9g5+vCShjEbyrpEJIJ7RfRACvmfe8EiRROM6GyD5eHn7OgzS+8LOy4g2gxPR/VSpAQGQuBldYpdlH5NnbQtwl6OErXb4y/E3w57bqukPyV93t4CTZedJMeJfD/1K2uaGvG/w/VNfFVbkhJ+Pi474j48V4Rd6rfArMCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFCRuKy3QapJRUSVpAaqaR6aJ50AgMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA0GCSqGSIb3DQEBCwUAA4IBAQALOYSR+ZfrqoGvhOlaOJL84mxZvzbIRacxAxHhBsCsMsdaVSnaT0AC9aHesO3ewPj2dZ12uYf+QYB6z13jAMZbAuabeGLJ3LhimnftiQjXS8X9Q9ViIyfEBFltcT8jW+rZ8uckJ2/0lYDblizkVIvP6hnZf1WZUXoOLRg9eFhSvGNoVwvdRLNXSmDmyHBwW4coatc7TlJFGa8kBpJIERqLrqwYElesA8u49L3KJg6nwd3jM+/AVTANlVlOnAM2BvjAjxSZnE0qnsHhfTuvcqdFuhOWKU4Z0BqYBvQ3lBetoxi6PrABDJXWKTUgNX31EGDk92hiHuwZ4STyhxGs6QiA"
+       }, {
+               "starfield_services_root_ca": "MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkdiEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6"
+       }, {
+               "starfield_class_2_ca": "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJlxy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q="
+       }],
+       "trust_stores": [{
+               "name": "le_via_isrg",
+               "stack": ["isrg_root_x1", "LEX3_isrg_root_x1"]
+       }, {
+               "name": "api_amazon_com",
+               "stack": ["digicert_global_ca_g2", "digicert_global_root_g2"]
+       }, {
+               "name": "avs_via_starfield",
+               "stack": ["starfield_class_2_ca", "starfield_services_root_ca"]
+       }, {
+               "name": "mqtt_amz_iot",
+               "stack": ["amazon_root_ca_1", "starfield_class_2_ca", "starfield_services_root_ca"]
+       }],
+       "s": [{
+               "api_amazon_com_auth": {
+                       "endpoint": "api.amazon.com",
+                       "port": 443,
+                       "protocol": "h1",
+                       "http_method": "POST",
+                       "http_url": "auth/o2/token",
+                       "plugins": [],
+                       "opportunistic": true,
+                       "tls": true,
+                       "h2q_oflow_txcr": true,
+                       "http_www_form_urlencoded": true,
+                       "http_no_content_length": true,
+                       "retry": "default",
+                       "tls_trust_store": "api_amazon_com"
+               }
+       }, {
+               "avs_event": {
+                       "endpoint": "alexa.na.gateway.devices.a2z.com",
+                       "port": 443,
+                       "protocol": "h2",
+                       "http_method": "GET",
+                       "http_url": "v20160207/directives",
+                       "h2q_oflow_txcr": true,
+                       "http_auth_header": "authorization:",
+                       "http_auth_preamble": "Bearer ",
+                       "http_no_content_length": true,
+                       "nailed_up": true,
+                       "long_poll": true,
+                       "retry": "default",
+                       "plugins": [],
+                       "tls": true,
+                       "tls_trust_store": "avs_via_starfield"
+               }
+       }, {
+               "avs_metadata": {
+                       "endpoint": "alexa.na.gateway.devices.a2z.com",
+                       "port": 443,
+                       "protocol": "h2",
+                       "http_method": "POST",
+                       "http_url": "v20160207/events",
+                       "opportunistic": true,
+                       "h2q_oflow_txcr": true,
+                       "http_auth_header": "authorization:",
+                       "http_auth_preamble": "Bearer ",
+                       "http_multipart_name": "metadata",
+                       "http_mime_content_type": "application/json; charset=UTF-8",
+                       "http_no_content_length": true,
+                       "rideshare": "avs_audio",
+                       "retry": "default",
+                       "plugins": [],
+                       "tls": true,
+                       "tls_trust_store": "avs_via_starfield"
+               }
+       }, {
+               "avs_audio": {
+                       "endpoint": "alexa.na.gateway.devices.a2z.com",
+                       "port": 443,
+                       "protocol": "h2",
+                       "http_method": "POST",
+                       "http_url": "v20160207/events",
+                       "plugins": [],
+                       "tls": true,
+                       "h2q_oflow_txcr": true,
+                       "http_auth_header": "authorization:",
+                       "http_auth_preamble": "Bearer ",
+                       "http_multipart_name": "audio",
+                       "http_mime_content_type": "application/octet-stream",
+                       "http_no_content_length": true,
+                       "retry": "default",
+                       "tls_trust_store": "avs_via_starfield"
+               }
+       }, {
+               "mintest": {
+                       "endpoint": "warmcat.com",
+                       "port": 443,
+                       "protocol": "h1",
+                       "http_method": "GET",
+                       "http_url": "index.html?uptag=${uptag}",
+                       "http_dsn_header": "x-dsn:",
+                       "http_fwv_header": "x-fw-version:",
+                       "http_devtype_header": "x-devtype:",
+                       "metadata": [{
+                               "uptag": "X-Upload-Tag:"
+                       }, {
+                               "ctype": "Content-Type:"
+                       }, {
+                               "xctype": "X-Content-Type:"
+                       }],
+                       "plugins": [],
+                       "tls": true,
+                       "opportunistic": true,
+                       "retry": "default",
+                       "tls_trust_store": "le_via_isrg"
+               }
+       }, {
+               "h2longpolltest": {
+                       "endpoint": "warmcat.com",
+                       "port": 443,
+                       "protocol": "h2",
+                       "http_method": "GET",
+                       "http_url": "index.html",
+                       "plugins": [],
+                       "tls": true,
+                       "nailed_up": true,
+                       "long_poll": true,
+                       "retry": "default",
+                       "tls_trust_store": "le_via_isrg"
+               }
+       }, {
+               "mintest-fail": {
+                       "endpoint": "warmcat.com",
+                       "port": 22,
+                       "protocol": "h1",
+                       "http_method": "GET",
+                       "http_url": "index.html",
+                       "plugins": [],
+                       "tls": true,
+                       "opportunistic": true,
+                       "retry": "default",
+                       "tls_trust_store": "le_via_isrg"
+               }
+       }, {
+               "minpost": {
+                       "endpoint": "warmcat.com",
+                       "port": 443,
+                       "protocol": "h1",
+                       "http_method": "POST",
+                       "http_url": "testserver/formtest",
+                       "plugins": [],
+                       "tls": true,
+                       "opportunistic": true,
+                       "retry": "default",
+                       "tls_trust_store": "le_via_isrg"
+               }
+       }, {
+               "mqtt_test": {
+                       "endpoint":             "a1ygonr3im5cv2-ats.iot.us-west-2.amazonaws.com",
+                       "port":                 443,
+                       "tls":                  true,
+                       "client_cert":          0,
+                       "tls_trust_store":      "mqtt_amz_iot",
+                       "protocol":             "mqtt",
+                       "mqtt_topic":           "test/topic0",
+                       "mqtt_subscribe":       "test/topic0",
+                       "mqtt_qos":             0,
+                       "retry":                "default"
+               }
+       }, {
+               "mqtt_test1": {
+                       "endpoint":             "a1ygonr3im5cv2-ats.iot.us-west-2.amazonaws.com",
+                       "port":                 443,
+                       "tls":                  true,
+                       "client_cert":          0,
+                       "tls_trust_store":      "mqtt_amz_iot",
+                       "protocol":             "mqtt",
+                       "mqtt_topic":           "test/topic1",
+                       "mqtt_subscribe":       "test/topic1",
+                       "mqtt_qos":             1,
+                       "retry":                "default"
+               }
+       }, {
+               "captive_portal_detect": {
+                       "endpoint": "connectivitycheck.android.com",
+                       "port": 80,
+                       "protocol": "h1",
+                       "http_method": "GET",
+                       "http_url": "generate_204",
+                       "opportunistic": true,
+                       "http_expect": 204,
+                       "http_fail_redirect": true
+               }
+       }
+       ]
+}
+
+
+
+
+ Original JSON size: 15493
+#endif
+
+static const uint32_t _rbo_bo_0[] = {
+ 1000,  2000,  3000,  5000,  10000, 
+};
+static const lws_retry_bo_t _rbo_0 = {
+       .retry_ms_table = _rbo_bo_0,
+       .retry_ms_table_count = 5,
+       .conceal_count = 5,
+       .secs_since_valid_ping = 30,
+       .secs_since_valid_hangup = 35,
+       .jitter_percent = 20,
+};
+static const uint8_t _ss_der_amazon_root_ca_1[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x03, 0x41, 0x30, 0x82, 0x02, 0x29, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x06, 
+       /* 0x 10 */ 0x6C, 0x9F, 0xCF, 0x99, 0xBF, 0x8C, 0x0A, 0x39, 
+       /* 0x 18 */ 0xE2, 0xF0, 0x78, 0x8A, 0x43, 0xE6, 0x96, 0x36, 
+       /* 0x 20 */ 0x5B, 0xCA, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 
+       /* 0x 28 */ 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 
+       /* 0x 30 */ 0x00, 0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 
+       /* 0x 38 */ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 
+       /* 0x 40 */ 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x 48 */ 0x0A, 0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 
+       /* 0x 50 */ 0x6E, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 
+       /* 0x 58 */ 0x04, 0x03, 0x13, 0x10, 0x41, 0x6D, 0x61, 0x7A, 
+       /* 0x 60 */ 0x6F, 0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 
+       /* 0x 68 */ 0x43, 0x41, 0x20, 0x31, 0x30, 0x1E, 0x17, 0x0D, 
+       /* 0x 70 */ 0x31, 0x35, 0x30, 0x35, 0x32, 0x36, 0x30, 0x30, 
+       /* 0x 78 */ 0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x33, 
+       /* 0x 80 */ 0x38, 0x30, 0x31, 0x31, 0x37, 0x30, 0x30, 0x30, 
+       /* 0x 88 */ 0x30, 0x30, 0x30, 0x5A, 0x30, 0x39, 0x31, 0x0B, 
+       /* 0x 90 */ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 
+       /* 0x 98 */ 0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 
+       /* 0x a0 */ 0x03, 0x55, 0x04, 0x0A, 0x13, 0x06, 0x41, 0x6D, 
+       /* 0x a8 */ 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17, 
+       /* 0x b0 */ 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x41, 
+       /* 0x b8 */ 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x20, 0x52, 0x6F, 
+       /* 0x c0 */ 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31, 0x30, 
+       /* 0x c8 */ 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 
+       /* 0x d0 */ 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 
+       /* 0x d8 */ 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 
+       /* 0x e0 */ 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 
+       /* 0x e8 */ 0xB2, 0x78, 0x80, 0x71, 0xCA, 0x78, 0xD5, 0xE3, 
+       /* 0x f0 */ 0x71, 0xAF, 0x47, 0x80, 0x50, 0x74, 0x7D, 0x6E, 
+       /* 0x f8 */ 0xD8, 0xD7, 0x88, 0x76, 0xF4, 0x99, 0x68, 0xF7, 
+       /* 0x100 */ 0x58, 0x21, 0x60, 0xF9, 0x74, 0x84, 0x01, 0x2F, 
+       /* 0x108 */ 0xAC, 0x02, 0x2D, 0x86, 0xD3, 0xA0, 0x43, 0x7A, 
+       /* 0x110 */ 0x4E, 0xB2, 0xA4, 0xD0, 0x36, 0xBA, 0x01, 0xBE, 
+       /* 0x118 */ 0x8D, 0xDB, 0x48, 0xC8, 0x07, 0x17, 0x36, 0x4C, 
+       /* 0x120 */ 0xF4, 0xEE, 0x88, 0x23, 0xC7, 0x3E, 0xEB, 0x37, 
+       /* 0x128 */ 0xF5, 0xB5, 0x19, 0xF8, 0x49, 0x68, 0xB0, 0xDE, 
+       /* 0x130 */ 0xD7, 0xB9, 0x76, 0x38, 0x1D, 0x61, 0x9E, 0xA4, 
+       /* 0x138 */ 0xFE, 0x82, 0x36, 0xA5, 0xE5, 0x4A, 0x56, 0xE4, 
+       /* 0x140 */ 0x45, 0xE1, 0xF9, 0xFD, 0xB4, 0x16, 0xFA, 0x74, 
+       /* 0x148 */ 0xDA, 0x9C, 0x9B, 0x35, 0x39, 0x2F, 0xFA, 0xB0, 
+       /* 0x150 */ 0x20, 0x50, 0x06, 0x6C, 0x7A, 0xD0, 0x80, 0xB2, 
+       /* 0x158 */ 0xA6, 0xF9, 0xAF, 0xEC, 0x47, 0x19, 0x8F, 0x50, 
+       /* 0x160 */ 0x38, 0x07, 0xDC, 0xA2, 0x87, 0x39, 0x58, 0xF8, 
+       /* 0x168 */ 0xBA, 0xD5, 0xA9, 0xF9, 0x48, 0x67, 0x30, 0x96, 
+       /* 0x170 */ 0xEE, 0x94, 0x78, 0x5E, 0x6F, 0x89, 0xA3, 0x51, 
+       /* 0x178 */ 0xC0, 0x30, 0x86, 0x66, 0xA1, 0x45, 0x66, 0xBA, 
+       /* 0x180 */ 0x54, 0xEB, 0xA3, 0xC3, 0x91, 0xF9, 0x48, 0xDC, 
+       /* 0x188 */ 0xFF, 0xD1, 0xE8, 0x30, 0x2D, 0x7D, 0x2D, 0x74, 
+       /* 0x190 */ 0x70, 0x35, 0xD7, 0x88, 0x24, 0xF7, 0x9E, 0xC4, 
+       /* 0x198 */ 0x59, 0x6E, 0xBB, 0x73, 0x87, 0x17, 0xF2, 0x32, 
+       /* 0x1a0 */ 0x46, 0x28, 0xB8, 0x43, 0xFA, 0xB7, 0x1D, 0xAA, 
+       /* 0x1a8 */ 0xCA, 0xB4, 0xF2, 0x9F, 0x24, 0x0E, 0x2D, 0x4B, 
+       /* 0x1b0 */ 0xF7, 0x71, 0x5C, 0x5E, 0x69, 0xFF, 0xEA, 0x95, 
+       /* 0x1b8 */ 0x02, 0xCB, 0x38, 0x8A, 0xAE, 0x50, 0x38, 0x6F, 
+       /* 0x1c0 */ 0xDB, 0xFB, 0x2D, 0x62, 0x1B, 0xC5, 0xC7, 0x1E, 
+       /* 0x1c8 */ 0x54, 0xE1, 0x77, 0xE0, 0x67, 0xC8, 0x0F, 0x9C, 
+       /* 0x1d0 */ 0x87, 0x23, 0xD6, 0x3F, 0x40, 0x20, 0x7F, 0x20, 
+       /* 0x1d8 */ 0x80, 0xC4, 0x80, 0x4C, 0x3E, 0x3B, 0x24, 0x26, 
+       /* 0x1e0 */ 0x8E, 0x04, 0xAE, 0x6C, 0x9A, 0xC8, 0xAA, 0x0D, 
+       /* 0x1e8 */ 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x42, 0x30, 
+       /* 0x1f0 */ 0x40, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 
+       /* 0x1f8 */ 0x01, 0x01, 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 
+       /* 0x200 */ 0x01, 0xFF, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 
+       /* 0x208 */ 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, 
+       /* 0x210 */ 0x01, 0x86, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 
+       /* 0x218 */ 0x0E, 0x04, 0x16, 0x04, 0x14, 0x84, 0x18, 0xCC, 
+       /* 0x220 */ 0x85, 0x34, 0xEC, 0xBC, 0x0C, 0x94, 0x94, 0x2E, 
+       /* 0x228 */ 0x08, 0x59, 0x9C, 0xC7, 0xB2, 0x10, 0x4E, 0x0A, 
+       /* 0x230 */ 0x08, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 
+       /* 0x238 */ 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 
+       /* 0x240 */ 0x03, 0x82, 0x01, 0x01, 0x00, 0x98, 0xF2, 0x37, 
+       /* 0x248 */ 0x5A, 0x41, 0x90, 0xA1, 0x1A, 0xC5, 0x76, 0x51, 
+       /* 0x250 */ 0x28, 0x20, 0x36, 0x23, 0x0E, 0xAE, 0xE6, 0x28, 
+       /* 0x258 */ 0xBB, 0xAA, 0xF8, 0x94, 0xAE, 0x48, 0xA4, 0x30, 
+       /* 0x260 */ 0x7F, 0x1B, 0xFC, 0x24, 0x8D, 0x4B, 0xB4, 0xC8, 
+       /* 0x268 */ 0xA1, 0x97, 0xF6, 0xB6, 0xF1, 0x7A, 0x70, 0xC8, 
+       /* 0x270 */ 0x53, 0x93, 0xCC, 0x08, 0x28, 0xE3, 0x98, 0x25, 
+       /* 0x278 */ 0xCF, 0x23, 0xA4, 0xF9, 0xDE, 0x21, 0xD3, 0x7C, 
+       /* 0x280 */ 0x85, 0x09, 0xAD, 0x4E, 0x9A, 0x75, 0x3A, 0xC2, 
+       /* 0x288 */ 0x0B, 0x6A, 0x89, 0x78, 0x76, 0x44, 0x47, 0x18, 
+       /* 0x290 */ 0x65, 0x6C, 0x8D, 0x41, 0x8E, 0x3B, 0x7F, 0x9A, 
+       /* 0x298 */ 0xCB, 0xF4, 0xB5, 0xA7, 0x50, 0xD7, 0x05, 0x2C, 
+       /* 0x2a0 */ 0x37, 0xE8, 0x03, 0x4B, 0xAD, 0xE9, 0x61, 0xA0, 
+       /* 0x2a8 */ 0x02, 0x6E, 0xF5, 0xF2, 0xF0, 0xC5, 0xB2, 0xED, 
+       /* 0x2b0 */ 0x5B, 0xB7, 0xDC, 0xFA, 0x94, 0x5C, 0x77, 0x9E, 
+       /* 0x2b8 */ 0x13, 0xA5, 0x7F, 0x52, 0xAD, 0x95, 0xF2, 0xF8, 
+       /* 0x2c0 */ 0x93, 0x3B, 0xDE, 0x8B, 0x5C, 0x5B, 0xCA, 0x5A, 
+       /* 0x2c8 */ 0x52, 0x5B, 0x60, 0xAF, 0x14, 0xF7, 0x4B, 0xEF, 
+       /* 0x2d0 */ 0xA3, 0xFB, 0x9F, 0x40, 0x95, 0x6D, 0x31, 0x54, 
+       /* 0x2d8 */ 0xFC, 0x42, 0xD3, 0xC7, 0x46, 0x1F, 0x23, 0xAD, 
+       /* 0x2e0 */ 0xD9, 0x0F, 0x48, 0x70, 0x9A, 0xD9, 0x75, 0x78, 
+       /* 0x2e8 */ 0x71, 0xD1, 0x72, 0x43, 0x34, 0x75, 0x6E, 0x57, 
+       /* 0x2f0 */ 0x59, 0xC2, 0x02, 0x5C, 0x26, 0x60, 0x29, 0xCF, 
+       /* 0x2f8 */ 0x23, 0x19, 0x16, 0x8E, 0x88, 0x43, 0xA5, 0xD4, 
+       /* 0x300 */ 0xE4, 0xCB, 0x08, 0xFB, 0x23, 0x11, 0x43, 0xE8, 
+       /* 0x308 */ 0x43, 0x29, 0x72, 0x62, 0xA1, 0xA9, 0x5D, 0x5E, 
+       /* 0x310 */ 0x08, 0xD4, 0x90, 0xAE, 0xB8, 0xD8, 0xCE, 0x14, 
+       /* 0x318 */ 0xC2, 0xD0, 0x55, 0xF2, 0x86, 0xF6, 0xC4, 0x93, 
+       /* 0x320 */ 0x43, 0x77, 0x66, 0x61, 0xC0, 0xB9, 0xE8, 0x41, 
+       /* 0x328 */ 0xD7, 0x97, 0x78, 0x60, 0x03, 0x6E, 0x4A, 0x72, 
+       /* 0x330 */ 0xAE, 0xA5, 0xD1, 0x7D, 0xBA, 0x10, 0x9E, 0x86, 
+       /* 0x338 */ 0x6C, 0x1B, 0x8A, 0xB9, 0x59, 0x33, 0xF8, 0xEB, 
+       /* 0x340 */ 0xC4, 0x90, 0xBE, 0xF1, 0xB9, 
+};
+static const lws_ss_x509_t _ss_x509_amazon_root_ca_1 = {
+       .vhost_name = "amazon_root_ca_1",
+       .ca_der = _ss_der_amazon_root_ca_1,
+       .ca_der_len = 837,
+};
+static const uint8_t _ss_der_starfield_class_2_ca[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x04, 0x0F, 0x30, 0x82, 0x02, 0xF7, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 
+       /* 0x 10 */ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+       /* 0x 18 */ 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 
+       /* 0x 20 */ 0x68, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 
+       /* 0x 28 */ 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x25, 
+       /* 0x 30 */ 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 
+       /* 0x 38 */ 0x1C, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 
+       /* 0x 40 */ 0x6C, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6E, 
+       /* 0x 48 */ 0x6F, 0x6C, 0x6F, 0x67, 0x69, 0x65, 0x73, 0x2C, 
+       /* 0x 50 */ 0x20, 0x49, 0x6E, 0x63, 0x2E, 0x31, 0x32, 0x30, 
+       /* 0x 58 */ 0x30, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x29, 
+       /* 0x 60 */ 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6C, 
+       /* 0x 68 */ 0x64, 0x20, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x20, 
+       /* 0x 70 */ 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 
+       /* 0x 78 */ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 
+       /* 0x 80 */ 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 
+       /* 0x 88 */ 0x79, 0x30, 0x1E, 0x17, 0x0D, 0x30, 0x34, 0x30, 
+       /* 0x 90 */ 0x36, 0x32, 0x39, 0x31, 0x37, 0x33, 0x39, 0x31, 
+       /* 0x 98 */ 0x36, 0x5A, 0x17, 0x0D, 0x33, 0x34, 0x30, 0x36, 
+       /* 0x a0 */ 0x32, 0x39, 0x31, 0x37, 0x33, 0x39, 0x31, 0x36, 
+       /* 0x a8 */ 0x5A, 0x30, 0x68, 0x31, 0x0B, 0x30, 0x09, 0x06, 
+       /* 0x b0 */ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 
+       /* 0x b8 */ 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x c0 */ 0x0A, 0x13, 0x1C, 0x53, 0x74, 0x61, 0x72, 0x66, 
+       /* 0x c8 */ 0x69, 0x65, 0x6C, 0x64, 0x20, 0x54, 0x65, 0x63, 
+       /* 0x d0 */ 0x68, 0x6E, 0x6F, 0x6C, 0x6F, 0x67, 0x69, 0x65, 
+       /* 0x d8 */ 0x73, 0x2C, 0x20, 0x49, 0x6E, 0x63, 0x2E, 0x31, 
+       /* 0x e0 */ 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0B, 
+       /* 0x e8 */ 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 
+       /* 0x f0 */ 0x65, 0x6C, 0x64, 0x20, 0x43, 0x6C, 0x61, 0x73, 
+       /* 0x f8 */ 0x73, 0x20, 0x32, 0x20, 0x43, 0x65, 0x72, 0x74, 
+       /* 0x100 */ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 
+       /* 0x108 */ 0x6E, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 
+       /* 0x110 */ 0x69, 0x74, 0x79, 0x30, 0x82, 0x01, 0x20, 0x30, 
+       /* 0x118 */ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 
+       /* 0x120 */ 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 
+       /* 0x128 */ 0x01, 0x0D, 0x00, 0x30, 0x82, 0x01, 0x08, 0x02, 
+       /* 0x130 */ 0x82, 0x01, 0x01, 0x00, 0xB7, 0x32, 0xC8, 0xFE, 
+       /* 0x138 */ 0xE9, 0x71, 0xA6, 0x04, 0x85, 0xAD, 0x0C, 0x11, 
+       /* 0x140 */ 0x64, 0xDF, 0xCE, 0x4D, 0xEF, 0xC8, 0x03, 0x18, 
+       /* 0x148 */ 0x87, 0x3F, 0xA1, 0xAB, 0xFB, 0x3C, 0xA6, 0x9F, 
+       /* 0x150 */ 0xF0, 0xC3, 0xA1, 0xDA, 0xD4, 0xD8, 0x6E, 0x2B, 
+       /* 0x158 */ 0x53, 0x90, 0xFB, 0x24, 0xA4, 0x3E, 0x84, 0xF0, 
+       /* 0x160 */ 0x9E, 0xE8, 0x5F, 0xEC, 0xE5, 0x27, 0x44, 0xF5, 
+       /* 0x168 */ 0x28, 0xA6, 0x3F, 0x7B, 0xDE, 0xE0, 0x2A, 0xF0, 
+       /* 0x170 */ 0xC8, 0xAF, 0x53, 0x2F, 0x9E, 0xCA, 0x05, 0x01, 
+       /* 0x178 */ 0x93, 0x1E, 0x8F, 0x66, 0x1C, 0x39, 0xA7, 0x4D, 
+       /* 0x180 */ 0xFA, 0x5A, 0xB6, 0x73, 0x04, 0x25, 0x66, 0xEB, 
+       /* 0x188 */ 0x77, 0x7F, 0xE7, 0x59, 0xC6, 0x4A, 0x99, 0x25, 
+       /* 0x190 */ 0x14, 0x54, 0xEB, 0x26, 0xC7, 0xF3, 0x7F, 0x19, 
+       /* 0x198 */ 0xD5, 0x30, 0x70, 0x8F, 0xAF, 0xB0, 0x46, 0x2A, 
+       /* 0x1a0 */ 0xFF, 0xAD, 0xEB, 0x29, 0xED, 0xD7, 0x9F, 0xAA, 
+       /* 0x1a8 */ 0x04, 0x87, 0xA3, 0xD4, 0xF9, 0x89, 0xA5, 0x34, 
+       /* 0x1b0 */ 0x5F, 0xDB, 0x43, 0x91, 0x82, 0x36, 0xD9, 0x66, 
+       /* 0x1b8 */ 0x3C, 0xB1, 0xB8, 0xB9, 0x82, 0xFD, 0x9C, 0x3A, 
+       /* 0x1c0 */ 0x3E, 0x10, 0xC8, 0x3B, 0xEF, 0x06, 0x65, 0x66, 
+       /* 0x1c8 */ 0x7A, 0x9B, 0x19, 0x18, 0x3D, 0xFF, 0x71, 0x51, 
+       /* 0x1d0 */ 0x3C, 0x30, 0x2E, 0x5F, 0xBE, 0x3D, 0x77, 0x73, 
+       /* 0x1d8 */ 0xB2, 0x5D, 0x06, 0x6C, 0xC3, 0x23, 0x56, 0x9A, 
+       /* 0x1e0 */ 0x2B, 0x85, 0x26, 0x92, 0x1C, 0xA7, 0x02, 0xB3, 
+       /* 0x1e8 */ 0xE4, 0x3F, 0x0D, 0xAF, 0x08, 0x79, 0x82, 0xB8, 
+       /* 0x1f0 */ 0x36, 0x3D, 0xEA, 0x9C, 0xD3, 0x35, 0xB3, 0xBC, 
+       /* 0x1f8 */ 0x69, 0xCA, 0xF5, 0xCC, 0x9D, 0xE8, 0xFD, 0x64, 
+       /* 0x200 */ 0x8D, 0x17, 0x80, 0x33, 0x6E, 0x5E, 0x4A, 0x5D, 
+       /* 0x208 */ 0x99, 0xC9, 0x1E, 0x87, 0xB4, 0x9D, 0x1A, 0xC0, 
+       /* 0x210 */ 0xD5, 0x6E, 0x13, 0x35, 0x23, 0x5E, 0xDF, 0x9B, 
+       /* 0x218 */ 0x5F, 0x3D, 0xEF, 0xD6, 0xF7, 0x76, 0xC2, 0xEA, 
+       /* 0x220 */ 0x3E, 0xBB, 0x78, 0x0D, 0x1C, 0x42, 0x67, 0x6B, 
+       /* 0x228 */ 0x04, 0xD8, 0xF8, 0xD6, 0xDA, 0x6F, 0x8B, 0xF2, 
+       /* 0x230 */ 0x44, 0xA0, 0x01, 0xAB, 0x02, 0x01, 0x03, 0xA3, 
+       /* 0x238 */ 0x81, 0xC5, 0x30, 0x81, 0xC2, 0x30, 0x1D, 0x06, 
+       /* 0x240 */ 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 
+       /* 0x248 */ 0xBF, 0x5F, 0xB7, 0xD1, 0xCE, 0xDD, 0x1F, 0x86, 
+       /* 0x250 */ 0xF4, 0x5B, 0x55, 0xAC, 0xDC, 0xD7, 0x10, 0xC2, 
+       /* 0x258 */ 0x0E, 0xA9, 0x88, 0xE7, 0x30, 0x81, 0x92, 0x06, 
+       /* 0x260 */ 0x03, 0x55, 0x1D, 0x23, 0x04, 0x81, 0x8A, 0x30, 
+       /* 0x268 */ 0x81, 0x87, 0x80, 0x14, 0xBF, 0x5F, 0xB7, 0xD1, 
+       /* 0x270 */ 0xCE, 0xDD, 0x1F, 0x86, 0xF4, 0x5B, 0x55, 0xAC, 
+       /* 0x278 */ 0xDC, 0xD7, 0x10, 0xC2, 0x0E, 0xA9, 0x88, 0xE7, 
+       /* 0x280 */ 0xA1, 0x6C, 0xA4, 0x6A, 0x30, 0x68, 0x31, 0x0B, 
+       /* 0x288 */ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 
+       /* 0x290 */ 0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 
+       /* 0x298 */ 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1C, 0x53, 0x74, 
+       /* 0x2a0 */ 0x61, 0x72, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x20, 
+       /* 0x2a8 */ 0x54, 0x65, 0x63, 0x68, 0x6E, 0x6F, 0x6C, 0x6F, 
+       /* 0x2b0 */ 0x67, 0x69, 0x65, 0x73, 0x2C, 0x20, 0x49, 0x6E, 
+       /* 0x2b8 */ 0x63, 0x2E, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 
+       /* 0x2c0 */ 0x55, 0x04, 0x0B, 0x13, 0x29, 0x53, 0x74, 0x61, 
+       /* 0x2c8 */ 0x72, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x20, 0x43, 
+       /* 0x2d0 */ 0x6C, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43, 
+       /* 0x2d8 */ 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 
+       /* 0x2e0 */ 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x75, 0x74, 
+       /* 0x2e8 */ 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x82, 0x01, 
+       /* 0x2f0 */ 0x00, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 
+       /* 0x2f8 */ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 
+       /* 0x300 */ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 
+       /* 0x308 */ 0x0D, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 
+       /* 0x310 */ 0x01, 0x01, 0x00, 0x05, 0x9D, 0x3F, 0x88, 0x9D, 
+       /* 0x318 */ 0xD1, 0xC9, 0x1A, 0x55, 0xA1, 0xAC, 0x69, 0xF3, 
+       /* 0x320 */ 0xF3, 0x59, 0xDA, 0x9B, 0x01, 0x87, 0x1A, 0x4F, 
+       /* 0x328 */ 0x57, 0xA9, 0xA1, 0x79, 0x09, 0x2A, 0xDB, 0xF7, 
+       /* 0x330 */ 0x2F, 0xB2, 0x1E, 0xCC, 0xC7, 0x5E, 0x6A, 0xD8, 
+       /* 0x338 */ 0x83, 0x87, 0xA1, 0x97, 0xEF, 0x49, 0x35, 0x3E, 
+       /* 0x340 */ 0x77, 0x06, 0x41, 0x58, 0x62, 0xBF, 0x8E, 0x58, 
+       /* 0x348 */ 0xB8, 0x0A, 0x67, 0x3F, 0xEC, 0xB3, 0xDD, 0x21, 
+       /* 0x350 */ 0x66, 0x1F, 0xC9, 0x54, 0xFA, 0x72, 0xCC, 0x3D, 
+       /* 0x358 */ 0x4C, 0x40, 0xD8, 0x81, 0xAF, 0x77, 0x9E, 0x83, 
+       /* 0x360 */ 0x7A, 0xBB, 0xA2, 0xC7, 0xF5, 0x34, 0x17, 0x8E, 
+       /* 0x368 */ 0xD9, 0x11, 0x40, 0xF4, 0xFC, 0x2C, 0x2A, 0x4D, 
+       /* 0x370 */ 0x15, 0x7F, 0xA7, 0x62, 0x5D, 0x2E, 0x25, 0xD3, 
+       /* 0x378 */ 0x00, 0x0B, 0x20, 0x1A, 0x1D, 0x68, 0xF9, 0x17, 
+       /* 0x380 */ 0xB8, 0xF4, 0xBD, 0x8B, 0xED, 0x28, 0x59, 0xDD, 
+       /* 0x388 */ 0x4D, 0x16, 0x8B, 0x17, 0x83, 0xC8, 0xB2, 0x65, 
+       /* 0x390 */ 0xC7, 0x2D, 0x7A, 0xA5, 0xAA, 0xBC, 0x53, 0x86, 
+       /* 0x398 */ 0x6D, 0xDD, 0x57, 0xA4, 0xCA, 0xF8, 0x20, 0x41, 
+       /* 0x3a0 */ 0x0B, 0x68, 0xF0, 0xF4, 0xFB, 0x74, 0xBE, 0x56, 
+       /* 0x3a8 */ 0x5D, 0x7A, 0x79, 0xF5, 0xF9, 0x1D, 0x85, 0xE3, 
+       /* 0x3b0 */ 0x2D, 0x95, 0xBE, 0xF5, 0x71, 0x90, 0x43, 0xCC, 
+       /* 0x3b8 */ 0x8D, 0x1F, 0x9A, 0x00, 0x0A, 0x87, 0x29, 0xE9, 
+       /* 0x3c0 */ 0x55, 0x22, 0x58, 0x00, 0x23, 0xEA, 0xE3, 0x12, 
+       /* 0x3c8 */ 0x43, 0x29, 0x5B, 0x47, 0x08, 0xDD, 0x8C, 0x41, 
+       /* 0x3d0 */ 0x6A, 0x65, 0x06, 0xA8, 0xE5, 0x21, 0xAA, 0x41, 
+       /* 0x3d8 */ 0xB4, 0x95, 0x21, 0x95, 0xB9, 0x7D, 0xD1, 0x34, 
+       /* 0x3e0 */ 0xAB, 0x13, 0xD6, 0xAD, 0xBC, 0xDC, 0xE2, 0x3D, 
+       /* 0x3e8 */ 0x39, 0xCD, 0xBD, 0x3E, 0x75, 0x70, 0xA1, 0x18, 
+       /* 0x3f0 */ 0x59, 0x03, 0xC9, 0x22, 0xB4, 0x8F, 0x9C, 0xD5, 
+       /* 0x3f8 */ 0x5E, 0x2A, 0xD7, 0xA5, 0xB6, 0xD4, 0x0A, 0x6D, 
+       /* 0x400 */ 0xF8, 0xB7, 0x40, 0x11, 0x46, 0x9A, 0x1F, 0x79, 
+       /* 0x408 */ 0x0E, 0x62, 0xBF, 0x0F, 0x97, 0xEC, 0xE0, 0x2F, 
+       /* 0x410 */ 0x1F, 0x17, 0x94, 
+};
+static const lws_ss_x509_t _ss_x509_starfield_class_2_ca = {
+       .vhost_name = "starfield_class_2_ca",
+       .ca_der = _ss_der_starfield_class_2_ca,
+       .ca_der_len = 1043,
+};
+static const uint8_t _ss_der_starfield_services_root_ca[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x03, 0xEF, 0x30, 0x82, 0x02, 0xD7, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 
+       /* 0x 10 */ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+       /* 0x 18 */ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 
+       /* 0x 20 */ 0x81, 0x98, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 
+       /* 0x 28 */ 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 
+       /* 0x 30 */ 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 
+       /* 0x 38 */ 0x13, 0x07, 0x41, 0x72, 0x69, 0x7A, 0x6F, 0x6E, 
+       /* 0x 40 */ 0x61, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 
+       /* 0x 48 */ 0x04, 0x07, 0x13, 0x0A, 0x53, 0x63, 0x6F, 0x74, 
+       /* 0x 50 */ 0x74, 0x73, 0x64, 0x61, 0x6C, 0x65, 0x31, 0x25, 
+       /* 0x 58 */ 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 
+       /* 0x 60 */ 0x1C, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 
+       /* 0x 68 */ 0x6C, 0x64, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6E, 
+       /* 0x 70 */ 0x6F, 0x6C, 0x6F, 0x67, 0x69, 0x65, 0x73, 0x2C, 
+       /* 0x 78 */ 0x20, 0x49, 0x6E, 0x63, 0x2E, 0x31, 0x3B, 0x30, 
+       /* 0x 80 */ 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x32, 
+       /* 0x 88 */ 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6C, 
+       /* 0x 90 */ 0x64, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 
+       /* 0x 98 */ 0x65, 0x73, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 
+       /* 0x a0 */ 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 
+       /* 0x a8 */ 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 
+       /* 0x b0 */ 0x6F, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2D, 0x20, 
+       /* 0x b8 */ 0x47, 0x32, 0x30, 0x1E, 0x17, 0x0D, 0x30, 0x39, 
+       /* 0x c0 */ 0x30, 0x39, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 
+       /* 0x c8 */ 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x33, 0x37, 0x31, 
+       /* 0x d0 */ 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 
+       /* 0x d8 */ 0x39, 0x5A, 0x30, 0x81, 0x98, 0x31, 0x0B, 0x30, 
+       /* 0x e0 */ 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 
+       /* 0x e8 */ 0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 
+       /* 0x f0 */ 0x55, 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 
+       /* 0x f8 */ 0x7A, 0x6F, 0x6E, 0x61, 0x31, 0x13, 0x30, 0x11, 
+       /* 0x100 */ 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0A, 0x53, 
+       /* 0x108 */ 0x63, 0x6F, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6C, 
+       /* 0x110 */ 0x65, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 
+       /* 0x118 */ 0x04, 0x0A, 0x13, 0x1C, 0x53, 0x74, 0x61, 0x72, 
+       /* 0x120 */ 0x66, 0x69, 0x65, 0x6C, 0x64, 0x20, 0x54, 0x65, 
+       /* 0x128 */ 0x63, 0x68, 0x6E, 0x6F, 0x6C, 0x6F, 0x67, 0x69, 
+       /* 0x130 */ 0x65, 0x73, 0x2C, 0x20, 0x49, 0x6E, 0x63, 0x2E, 
+       /* 0x138 */ 0x31, 0x3B, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x140 */ 0x03, 0x13, 0x32, 0x53, 0x74, 0x61, 0x72, 0x66, 
+       /* 0x148 */ 0x69, 0x65, 0x6C, 0x64, 0x20, 0x53, 0x65, 0x72, 
+       /* 0x150 */ 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x52, 0x6F, 
+       /* 0x158 */ 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 
+       /* 0x160 */ 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 
+       /* 0x168 */ 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 
+       /* 0x170 */ 0x20, 0x2D, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 
+       /* 0x178 */ 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 
+       /* 0x180 */ 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 
+       /* 0x188 */ 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 
+       /* 0x190 */ 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xD5, 0x0C, 
+       /* 0x198 */ 0x3A, 0xC4, 0x2A, 0xF9, 0x4E, 0xE2, 0xF5, 0xBE, 
+       /* 0x1a0 */ 0x19, 0x97, 0x5F, 0x8E, 0x88, 0x53, 0xB1, 0x1F, 
+       /* 0x1a8 */ 0x3F, 0xCB, 0xCF, 0x9F, 0x20, 0x13, 0x6D, 0x29, 
+       /* 0x1b0 */ 0x3A, 0xC8, 0x0F, 0x7D, 0x3C, 0xF7, 0x6B, 0x76, 
+       /* 0x1b8 */ 0x38, 0x63, 0xD9, 0x36, 0x60, 0xA8, 0x9B, 0x5E, 
+       /* 0x1c0 */ 0x5C, 0x00, 0x80, 0xB2, 0x2F, 0x59, 0x7F, 0xF6, 
+       /* 0x1c8 */ 0x87, 0xF9, 0x25, 0x43, 0x86, 0xE7, 0x69, 0x1B, 
+       /* 0x1d0 */ 0x52, 0x9A, 0x90, 0xE1, 0x71, 0xE3, 0xD8, 0x2D, 
+       /* 0x1d8 */ 0x0D, 0x4E, 0x6F, 0xF6, 0xC8, 0x49, 0xD9, 0xB6, 
+       /* 0x1e0 */ 0xF3, 0x1A, 0x56, 0xAE, 0x2B, 0xB6, 0x74, 0x14, 
+       /* 0x1e8 */ 0xEB, 0xCF, 0xFB, 0x26, 0xE3, 0x1A, 0xBA, 0x1D, 
+       /* 0x1f0 */ 0x96, 0x2E, 0x6A, 0x3B, 0x58, 0x94, 0x89, 0x47, 
+       /* 0x1f8 */ 0x56, 0xFF, 0x25, 0xA0, 0x93, 0x70, 0x53, 0x83, 
+       /* 0x200 */ 0xDA, 0x84, 0x74, 0x14, 0xC3, 0x67, 0x9E, 0x04, 
+       /* 0x208 */ 0x68, 0x3A, 0xDF, 0x8E, 0x40, 0x5A, 0x1D, 0x4A, 
+       /* 0x210 */ 0x4E, 0xCF, 0x43, 0x91, 0x3B, 0xE7, 0x56, 0xD6, 
+       /* 0x218 */ 0x00, 0x70, 0xCB, 0x52, 0xEE, 0x7B, 0x7D, 0xAE, 
+       /* 0x220 */ 0x3A, 0xE7, 0xBC, 0x31, 0xF9, 0x45, 0xF6, 0xC2, 
+       /* 0x228 */ 0x60, 0xCF, 0x13, 0x59, 0x02, 0x2B, 0x80, 0xCC, 
+       /* 0x230 */ 0x34, 0x47, 0xDF, 0xB9, 0xDE, 0x90, 0x65, 0x6D, 
+       /* 0x238 */ 0x02, 0xCF, 0x2C, 0x91, 0xA6, 0xA6, 0xE7, 0xDE, 
+       /* 0x240 */ 0x85, 0x18, 0x49, 0x7C, 0x66, 0x4E, 0xA3, 0x3A, 
+       /* 0x248 */ 0x6D, 0xA9, 0xB5, 0xEE, 0x34, 0x2E, 0xBA, 0x0D, 
+       /* 0x250 */ 0x03, 0xB8, 0x33, 0xDF, 0x47, 0xEB, 0xB1, 0x6B, 
+       /* 0x258 */ 0x8D, 0x25, 0xD9, 0x9B, 0xCE, 0x81, 0xD1, 0x45, 
+       /* 0x260 */ 0x46, 0x32, 0x96, 0x70, 0x87, 0xDE, 0x02, 0x0E, 
+       /* 0x268 */ 0x49, 0x43, 0x85, 0xB6, 0x6C, 0x73, 0xBB, 0x64, 
+       /* 0x270 */ 0xEA, 0x61, 0x41, 0xAC, 0xC9, 0xD4, 0x54, 0xDF, 
+       /* 0x278 */ 0x87, 0x2F, 0xC7, 0x22, 0xB2, 0x26, 0xCC, 0x9F, 
+       /* 0x280 */ 0x59, 0x54, 0x68, 0x9F, 0xFC, 0xBE, 0x2A, 0x2F, 
+       /* 0x288 */ 0xC4, 0x55, 0x1C, 0x75, 0x40, 0x60, 0x17, 0x85, 
+       /* 0x290 */ 0x02, 0x55, 0x39, 0x8B, 0x7F, 0x05, 0x02, 0x03, 
+       /* 0x298 */ 0x01, 0x00, 0x01, 0xA3, 0x42, 0x30, 0x40, 0x30, 
+       /* 0x2a0 */ 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 
+       /* 0x2a8 */ 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 
+       /* 0x2b0 */ 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 
+       /* 0x2b8 */ 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 
+       /* 0x2c0 */ 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 
+       /* 0x2c8 */ 0x16, 0x04, 0x14, 0x9C, 0x5F, 0x00, 0xDF, 0xAA, 
+       /* 0x2d0 */ 0x01, 0xD7, 0x30, 0x2B, 0x38, 0x88, 0xA2, 0xB8, 
+       /* 0x2d8 */ 0x6D, 0x4A, 0x9C, 0xF2, 0x11, 0x91, 0x83, 0x30, 
+       /* 0x2e0 */ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 
+       /* 0x2e8 */ 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 
+       /* 0x2f0 */ 0x01, 0x01, 0x00, 0x4B, 0x36, 0xA6, 0x84, 0x77, 
+       /* 0x2f8 */ 0x69, 0xDD, 0x3B, 0x19, 0x9F, 0x67, 0x23, 0x08, 
+       /* 0x300 */ 0x6F, 0x0E, 0x61, 0xC9, 0xFD, 0x84, 0xDC, 0x5F, 
+       /* 0x308 */ 0xD8, 0x36, 0x81, 0xCD, 0xD8, 0x1B, 0x41, 0x2D, 
+       /* 0x310 */ 0x9F, 0x60, 0xDD, 0xC7, 0x1A, 0x68, 0xD9, 0xD1, 
+       /* 0x318 */ 0x6E, 0x86, 0xE1, 0x88, 0x23, 0xCF, 0x13, 0xDE, 
+       /* 0x320 */ 0x43, 0xCF, 0xE2, 0x34, 0xB3, 0x04, 0x9D, 0x1F, 
+       /* 0x328 */ 0x29, 0xD5, 0xBF, 0xF8, 0x5E, 0xC8, 0xD5, 0xC1, 
+       /* 0x330 */ 0xBD, 0xEE, 0x92, 0x6F, 0x32, 0x74, 0xF2, 0x91, 
+       /* 0x338 */ 0x82, 0x2F, 0xBD, 0x82, 0x42, 0x7A, 0xAD, 0x2A, 
+       /* 0x340 */ 0xB7, 0x20, 0x7D, 0x4D, 0xBC, 0x7A, 0x55, 0x12, 
+       /* 0x348 */ 0xC2, 0x15, 0xEA, 0xBD, 0xF7, 0x6A, 0x95, 0x2E, 
+       /* 0x350 */ 0x6C, 0x74, 0x9F, 0xCF, 0x1C, 0xB4, 0xF2, 0xC5, 
+       /* 0x358 */ 0x01, 0xA3, 0x85, 0xD0, 0x72, 0x3E, 0xAD, 0x73, 
+       /* 0x360 */ 0xAB, 0x0B, 0x9B, 0x75, 0x0C, 0x6D, 0x45, 0xB7, 
+       /* 0x368 */ 0x8E, 0x94, 0xAC, 0x96, 0x37, 0xB5, 0xA0, 0xD0, 
+       /* 0x370 */ 0x8F, 0x15, 0x47, 0x0E, 0xE3, 0xE8, 0x83, 0xDD, 
+       /* 0x378 */ 0x8F, 0xFD, 0xEF, 0x41, 0x01, 0x77, 0xCC, 0x27, 
+       /* 0x380 */ 0xA9, 0x62, 0x85, 0x33, 0xF2, 0x37, 0x08, 0xEF, 
+       /* 0x388 */ 0x71, 0xCF, 0x77, 0x06, 0xDE, 0xC8, 0x19, 0x1D, 
+       /* 0x390 */ 0x88, 0x40, 0xCF, 0x7D, 0x46, 0x1D, 0xFF, 0x1E, 
+       /* 0x398 */ 0xC7, 0xE1, 0xCE, 0xFF, 0x23, 0xDB, 0xC6, 0xFA, 
+       /* 0x3a0 */ 0x8D, 0x55, 0x4E, 0xA9, 0x02, 0xE7, 0x47, 0x11, 
+       /* 0x3a8 */ 0x46, 0x3E, 0xF4, 0xFD, 0xBD, 0x7B, 0x29, 0x26, 
+       /* 0x3b0 */ 0xBB, 0xA9, 0x61, 0x62, 0x37, 0x28, 0xB6, 0x2D, 
+       /* 0x3b8 */ 0x2A, 0xF6, 0x10, 0x86, 0x64, 0xC9, 0x70, 0xA7, 
+       /* 0x3c0 */ 0xD2, 0xAD, 0xB7, 0x29, 0x70, 0x79, 0xEA, 0x3C, 
+       /* 0x3c8 */ 0xDA, 0x63, 0x25, 0x9F, 0xFD, 0x68, 0xB7, 0x30, 
+       /* 0x3d0 */ 0xEC, 0x70, 0xFB, 0x75, 0x8A, 0xB7, 0x6D, 0x60, 
+       /* 0x3d8 */ 0x67, 0xB2, 0x1E, 0xC8, 0xB9, 0xE9, 0xD8, 0xA8, 
+       /* 0x3e0 */ 0x6F, 0x02, 0x8B, 0x67, 0x0D, 0x4D, 0x26, 0x57, 
+       /* 0x3e8 */ 0x71, 0xDA, 0x20, 0xFC, 0xC1, 0x4A, 0x50, 0x8D, 
+       /* 0x3f0 */ 0xB1, 0x28, 0xBA, 
+};
+static const lws_ss_x509_t _ss_x509_starfield_services_root_ca = {
+       .vhost_name = "starfield_services_root_ca",
+       .ca_der = _ss_der_starfield_services_root_ca,
+       .ca_der_len = 1011,
+};
+static const lws_ss_trust_store_t _ss_ts_mqtt_amz_iot = {
+       .name = "mqtt_amz_iot",
+       .ssx509 = {
+               &_ss_x509_starfield_services_root_ca,
+               &_ss_x509_starfield_class_2_ca,
+               &_ss_x509_amazon_root_ca_1,
+       }
+};
+static const uint8_t _ss_der_isrg_root_x1[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x05, 0x6B, 0x30, 0x82, 0x03, 0x53, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 
+       /* 0x 10 */ 0x82, 0x10, 0xCF, 0xB0, 0xD2, 0x40, 0xE3, 0x59, 
+       /* 0x 18 */ 0x44, 0x63, 0xE0, 0xBB, 0x63, 0x82, 0x8B, 0x00, 
+       /* 0x 20 */ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+       /* 0x 28 */ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 
+       /* 0x 30 */ 0x4F, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 
+       /* 0x 38 */ 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x29, 
+       /* 0x 40 */ 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 
+       /* 0x 48 */ 0x20, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 
+       /* 0x 50 */ 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 
+       /* 0x 58 */ 0x74, 0x79, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 
+       /* 0x 60 */ 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6F, 0x75, 
+       /* 0x 68 */ 0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 
+       /* 0x 70 */ 0x04, 0x03, 0x13, 0x0C, 0x49, 0x53, 0x52, 0x47, 
+       /* 0x 78 */ 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x58, 0x31, 
+       /* 0x 80 */ 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x35, 0x30, 0x36, 
+       /* 0x 88 */ 0x30, 0x34, 0x31, 0x31, 0x30, 0x34, 0x33, 0x38, 
+       /* 0x 90 */ 0x5A, 0x17, 0x0D, 0x33, 0x35, 0x30, 0x36, 0x30, 
+       /* 0x 98 */ 0x34, 0x31, 0x31, 0x30, 0x34, 0x33, 0x38, 0x5A, 
+       /* 0x a0 */ 0x30, 0x4F, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 
+       /* 0x a8 */ 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 
+       /* 0x b0 */ 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x0A, 
+       /* 0x b8 */ 0x13, 0x20, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 
+       /* 0x c0 */ 0x65, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 
+       /* 0x c8 */ 0x69, 0x74, 0x79, 0x20, 0x52, 0x65, 0x73, 0x65, 
+       /* 0x d0 */ 0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6F, 
+       /* 0x d8 */ 0x75, 0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 
+       /* 0x e0 */ 0x55, 0x04, 0x03, 0x13, 0x0C, 0x49, 0x53, 0x52, 
+       /* 0x e8 */ 0x47, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x58, 
+       /* 0x f0 */ 0x31, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0D, 0x06, 
+       /* 0x f8 */ 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 
+       /* 0x100 */ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0F, 
+       /* 0x108 */ 0x00, 0x30, 0x82, 0x02, 0x0A, 0x02, 0x82, 0x02, 
+       /* 0x110 */ 0x01, 0x00, 0xAD, 0xE8, 0x24, 0x73, 0xF4, 0x14, 
+       /* 0x118 */ 0x37, 0xF3, 0x9B, 0x9E, 0x2B, 0x57, 0x28, 0x1C, 
+       /* 0x120 */ 0x87, 0xBE, 0xDC, 0xB7, 0xDF, 0x38, 0x90, 0x8C, 
+       /* 0x128 */ 0x6E, 0x3C, 0xE6, 0x57, 0xA0, 0x78, 0xF7, 0x75, 
+       /* 0x130 */ 0xC2, 0xA2, 0xFE, 0xF5, 0x6A, 0x6E, 0xF6, 0x00, 
+       /* 0x138 */ 0x4F, 0x28, 0xDB, 0xDE, 0x68, 0x86, 0x6C, 0x44, 
+       /* 0x140 */ 0x93, 0xB6, 0xB1, 0x63, 0xFD, 0x14, 0x12, 0x6B, 
+       /* 0x148 */ 0xBF, 0x1F, 0xD2, 0xEA, 0x31, 0x9B, 0x21, 0x7E, 
+       /* 0x150 */ 0xD1, 0x33, 0x3C, 0xBA, 0x48, 0xF5, 0xDD, 0x79, 
+       /* 0x158 */ 0xDF, 0xB3, 0xB8, 0xFF, 0x12, 0xF1, 0x21, 0x9A, 
+       /* 0x160 */ 0x4B, 0xC1, 0x8A, 0x86, 0x71, 0x69, 0x4A, 0x66, 
+       /* 0x168 */ 0x66, 0x6C, 0x8F, 0x7E, 0x3C, 0x70, 0xBF, 0xAD, 
+       /* 0x170 */ 0x29, 0x22, 0x06, 0xF3, 0xE4, 0xC0, 0xE6, 0x80, 
+       /* 0x178 */ 0xAE, 0xE2, 0x4B, 0x8F, 0xB7, 0x99, 0x7E, 0x94, 
+       /* 0x180 */ 0x03, 0x9F, 0xD3, 0x47, 0x97, 0x7C, 0x99, 0x48, 
+       /* 0x188 */ 0x23, 0x53, 0xE8, 0x38, 0xAE, 0x4F, 0x0A, 0x6F, 
+       /* 0x190 */ 0x83, 0x2E, 0xD1, 0x49, 0x57, 0x8C, 0x80, 0x74, 
+       /* 0x198 */ 0xB6, 0xDA, 0x2F, 0xD0, 0x38, 0x8D, 0x7B, 0x03, 
+       /* 0x1a0 */ 0x70, 0x21, 0x1B, 0x75, 0xF2, 0x30, 0x3C, 0xFA, 
+       /* 0x1a8 */ 0x8F, 0xAE, 0xDD, 0xDA, 0x63, 0xAB, 0xEB, 0x16, 
+       /* 0x1b0 */ 0x4F, 0xC2, 0x8E, 0x11, 0x4B, 0x7E, 0xCF, 0x0B, 
+       /* 0x1b8 */ 0xE8, 0xFF, 0xB5, 0x77, 0x2E, 0xF4, 0xB2, 0x7B, 
+       /* 0x1c0 */ 0x4A, 0xE0, 0x4C, 0x12, 0x25, 0x0C, 0x70, 0x8D, 
+       /* 0x1c8 */ 0x03, 0x29, 0xA0, 0xE1, 0x53, 0x24, 0xEC, 0x13, 
+       /* 0x1d0 */ 0xD9, 0xEE, 0x19, 0xBF, 0x10, 0xB3, 0x4A, 0x8C, 
+       /* 0x1d8 */ 0x3F, 0x89, 0xA3, 0x61, 0x51, 0xDE, 0xAC, 0x87, 
+       /* 0x1e0 */ 0x07, 0x94, 0xF4, 0x63, 0x71, 0xEC, 0x2E, 0xE2, 
+       /* 0x1e8 */ 0x6F, 0x5B, 0x98, 0x81, 0xE1, 0x89, 0x5C, 0x34, 
+       /* 0x1f0 */ 0x79, 0x6C, 0x76, 0xEF, 0x3B, 0x90, 0x62, 0x79, 
+       /* 0x1f8 */ 0xE6, 0xDB, 0xA4, 0x9A, 0x2F, 0x26, 0xC5, 0xD0, 
+       /* 0x200 */ 0x10, 0xE1, 0x0E, 0xDE, 0xD9, 0x10, 0x8E, 0x16, 
+       /* 0x208 */ 0xFB, 0xB7, 0xF7, 0xA8, 0xF7, 0xC7, 0xE5, 0x02, 
+       /* 0x210 */ 0x07, 0x98, 0x8F, 0x36, 0x08, 0x95, 0xE7, 0xE2, 
+       /* 0x218 */ 0x37, 0x96, 0x0D, 0x36, 0x75, 0x9E, 0xFB, 0x0E, 
+       /* 0x220 */ 0x72, 0xB1, 0x1D, 0x9B, 0xBC, 0x03, 0xF9, 0x49, 
+       /* 0x228 */ 0x05, 0xD8, 0x81, 0xDD, 0x05, 0xB4, 0x2A, 0xD6, 
+       /* 0x230 */ 0x41, 0xE9, 0xAC, 0x01, 0x76, 0x95, 0x0A, 0x0F, 
+       /* 0x238 */ 0xD8, 0xDF, 0xD5, 0xBD, 0x12, 0x1F, 0x35, 0x2F, 
+       /* 0x240 */ 0x28, 0x17, 0x6C, 0xD2, 0x98, 0xC1, 0xA8, 0x09, 
+       /* 0x248 */ 0x64, 0x77, 0x6E, 0x47, 0x37, 0xBA, 0xCE, 0xAC, 
+       /* 0x250 */ 0x59, 0x5E, 0x68, 0x9D, 0x7F, 0x72, 0xD6, 0x89, 
+       /* 0x258 */ 0xC5, 0x06, 0x41, 0x29, 0x3E, 0x59, 0x3E, 0xDD, 
+       /* 0x260 */ 0x26, 0xF5, 0x24, 0xC9, 0x11, 0xA7, 0x5A, 0xA3, 
+       /* 0x268 */ 0x4C, 0x40, 0x1F, 0x46, 0xA1, 0x99, 0xB5, 0xA7, 
+       /* 0x270 */ 0x3A, 0x51, 0x6E, 0x86, 0x3B, 0x9E, 0x7D, 0x72, 
+       /* 0x278 */ 0xA7, 0x12, 0x05, 0x78, 0x59, 0xED, 0x3E, 0x51, 
+       /* 0x280 */ 0x78, 0x15, 0x0B, 0x03, 0x8F, 0x8D, 0xD0, 0x2F, 
+       /* 0x288 */ 0x05, 0xB2, 0x3E, 0x7B, 0x4A, 0x1C, 0x4B, 0x73, 
+       /* 0x290 */ 0x05, 0x12, 0xFC, 0xC6, 0xEA, 0xE0, 0x50, 0x13, 
+       /* 0x298 */ 0x7C, 0x43, 0x93, 0x74, 0xB3, 0xCA, 0x74, 0xE7, 
+       /* 0x2a0 */ 0x8E, 0x1F, 0x01, 0x08, 0xD0, 0x30, 0xD4, 0x5B, 
+       /* 0x2a8 */ 0x71, 0x36, 0xB4, 0x07, 0xBA, 0xC1, 0x30, 0x30, 
+       /* 0x2b0 */ 0x5C, 0x48, 0xB7, 0x82, 0x3B, 0x98, 0xA6, 0x7D, 
+       /* 0x2b8 */ 0x60, 0x8A, 0xA2, 0xA3, 0x29, 0x82, 0xCC, 0xBA, 
+       /* 0x2c0 */ 0xBD, 0x83, 0x04, 0x1B, 0xA2, 0x83, 0x03, 0x41, 
+       /* 0x2c8 */ 0xA1, 0xD6, 0x05, 0xF1, 0x1B, 0xC2, 0xB6, 0xF0, 
+       /* 0x2d0 */ 0xA8, 0x7C, 0x86, 0x3B, 0x46, 0xA8, 0x48, 0x2A, 
+       /* 0x2d8 */ 0x88, 0xDC, 0x76, 0x9A, 0x76, 0xBF, 0x1F, 0x6A, 
+       /* 0x2e0 */ 0xA5, 0x3D, 0x19, 0x8F, 0xEB, 0x38, 0xF3, 0x64, 
+       /* 0x2e8 */ 0xDE, 0xC8, 0x2B, 0x0D, 0x0A, 0x28, 0xFF, 0xF7, 
+       /* 0x2f0 */ 0xDB, 0xE2, 0x15, 0x42, 0xD4, 0x22, 0xD0, 0x27, 
+       /* 0x2f8 */ 0x5D, 0xE1, 0x79, 0xFE, 0x18, 0xE7, 0x70, 0x88, 
+       /* 0x300 */ 0xAD, 0x4E, 0xE6, 0xD9, 0x8B, 0x3A, 0xC6, 0xDD, 
+       /* 0x308 */ 0x27, 0x51, 0x6E, 0xFF, 0xBC, 0x64, 0xF5, 0x33, 
+       /* 0x310 */ 0x43, 0x4F, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 
+       /* 0x318 */ 0x42, 0x30, 0x40, 0x30, 0x0E, 0x06, 0x03, 0x55, 
+       /* 0x320 */ 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 
+       /* 0x328 */ 0x02, 0x01, 0x06, 0x30, 0x0F, 0x06, 0x03, 0x55, 
+       /* 0x330 */ 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x05, 0x30, 
+       /* 0x338 */ 0x03, 0x01, 0x01, 0xFF, 0x30, 0x1D, 0x06, 0x03, 
+       /* 0x340 */ 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x79, 
+       /* 0x348 */ 0xB4, 0x59, 0xE6, 0x7B, 0xB6, 0xE5, 0xE4, 0x01, 
+       /* 0x350 */ 0x73, 0x80, 0x08, 0x88, 0xC8, 0x1A, 0x58, 0xF6, 
+       /* 0x358 */ 0xE9, 0x9B, 0x6E, 0x30, 0x0D, 0x06, 0x09, 0x2A, 
+       /* 0x360 */ 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 
+       /* 0x368 */ 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x55, 
+       /* 0x370 */ 0x1F, 0x58, 0xA9, 0xBC, 0xB2, 0xA8, 0x50, 0xD0, 
+       /* 0x378 */ 0x0C, 0xB1, 0xD8, 0x1A, 0x69, 0x20, 0x27, 0x29, 
+       /* 0x380 */ 0x08, 0xAC, 0x61, 0x75, 0x5C, 0x8A, 0x6E, 0xF8, 
+       /* 0x388 */ 0x82, 0xE5, 0x69, 0x2F, 0xD5, 0xF6, 0x56, 0x4B, 
+       /* 0x390 */ 0xB9, 0xB8, 0x73, 0x10, 0x59, 0xD3, 0x21, 0x97, 
+       /* 0x398 */ 0x7E, 0xE7, 0x4C, 0x71, 0xFB, 0xB2, 0xD2, 0x60, 
+       /* 0x3a0 */ 0xAD, 0x39, 0xA8, 0x0B, 0xEA, 0x17, 0x21, 0x56, 
+       /* 0x3a8 */ 0x85, 0xF1, 0x50, 0x0E, 0x59, 0xEB, 0xCE, 0xE0, 
+       /* 0x3b0 */ 0x59, 0xE9, 0xBA, 0xC9, 0x15, 0xEF, 0x86, 0x9D, 
+       /* 0x3b8 */ 0x8F, 0x84, 0x80, 0xF6, 0xE4, 0xE9, 0x91, 0x90, 
+       /* 0x3c0 */ 0xDC, 0x17, 0x9B, 0x62, 0x1B, 0x45, 0xF0, 0x66, 
+       /* 0x3c8 */ 0x95, 0xD2, 0x7C, 0x6F, 0xC2, 0xEA, 0x3B, 0xEF, 
+       /* 0x3d0 */ 0x1F, 0xCF, 0xCB, 0xD6, 0xAE, 0x27, 0xF1, 0xA9, 
+       /* 0x3d8 */ 0xB0, 0xC8, 0xAE, 0xFD, 0x7D, 0x7E, 0x9A, 0xFA, 
+       /* 0x3e0 */ 0x22, 0x04, 0xEB, 0xFF, 0xD9, 0x7F, 0xEA, 0x91, 
+       /* 0x3e8 */ 0x2B, 0x22, 0xB1, 0x17, 0x0E, 0x8F, 0xF2, 0x8A, 
+       /* 0x3f0 */ 0x34, 0x5B, 0x58, 0xD8, 0xFC, 0x01, 0xC9, 0x54, 
+       /* 0x3f8 */ 0xB9, 0xB8, 0x26, 0xCC, 0x8A, 0x88, 0x33, 0x89, 
+       /* 0x400 */ 0x4C, 0x2D, 0x84, 0x3C, 0x82, 0xDF, 0xEE, 0x96, 
+       /* 0x408 */ 0x57, 0x05, 0xBA, 0x2C, 0xBB, 0xF7, 0xC4, 0xB7, 
+       /* 0x410 */ 0xC7, 0x4E, 0x3B, 0x82, 0xBE, 0x31, 0xC8, 0x22, 
+       /* 0x418 */ 0x73, 0x73, 0x92, 0xD1, 0xC2, 0x80, 0xA4, 0x39, 
+       /* 0x420 */ 0x39, 0x10, 0x33, 0x23, 0x82, 0x4C, 0x3C, 0x9F, 
+       /* 0x428 */ 0x86, 0xB2, 0x55, 0x98, 0x1D, 0xBE, 0x29, 0x86, 
+       /* 0x430 */ 0x8C, 0x22, 0x9B, 0x9E, 0xE2, 0x6B, 0x3B, 0x57, 
+       /* 0x438 */ 0x3A, 0x82, 0x70, 0x4D, 0xDC, 0x09, 0xC7, 0x89, 
+       /* 0x440 */ 0xCB, 0x0A, 0x07, 0x4D, 0x6C, 0xE8, 0x5D, 0x8E, 
+       /* 0x448 */ 0xC9, 0xEF, 0xCE, 0xAB, 0xC7, 0xBB, 0xB5, 0x2B, 
+       /* 0x450 */ 0x4E, 0x45, 0xD6, 0x4A, 0xD0, 0x26, 0xCC, 0xE5, 
+       /* 0x458 */ 0x72, 0xCA, 0x08, 0x6A, 0xA5, 0x95, 0xE3, 0x15, 
+       /* 0x460 */ 0xA1, 0xF7, 0xA4, 0xED, 0xC9, 0x2C, 0x5F, 0xA5, 
+       /* 0x468 */ 0xFB, 0xFF, 0xAC, 0x28, 0x02, 0x2E, 0xBE, 0xD7, 
+       /* 0x470 */ 0x7B, 0xBB, 0xE3, 0x71, 0x7B, 0x90, 0x16, 0xD3, 
+       /* 0x478 */ 0x07, 0x5E, 0x46, 0x53, 0x7C, 0x37, 0x07, 0x42, 
+       /* 0x480 */ 0x8C, 0xD3, 0xC4, 0x96, 0x9C, 0xD5, 0x99, 0xB5, 
+       /* 0x488 */ 0x2A, 0xE0, 0x95, 0x1A, 0x80, 0x48, 0xAE, 0x4C, 
+       /* 0x490 */ 0x39, 0x07, 0xCE, 0xCC, 0x47, 0xA4, 0x52, 0x95, 
+       /* 0x498 */ 0x2B, 0xBA, 0xB8, 0xFB, 0xAD, 0xD2, 0x33, 0x53, 
+       /* 0x4a0 */ 0x7D, 0xE5, 0x1D, 0x4D, 0x6D, 0xD5, 0xA1, 0xB1, 
+       /* 0x4a8 */ 0xC7, 0x42, 0x6F, 0xE6, 0x40, 0x27, 0x35, 0x5C, 
+       /* 0x4b0 */ 0xA3, 0x28, 0xB7, 0x07, 0x8D, 0xE7, 0x8D, 0x33, 
+       /* 0x4b8 */ 0x90, 0xE7, 0x23, 0x9F, 0xFB, 0x50, 0x9C, 0x79, 
+       /* 0x4c0 */ 0x6C, 0x46, 0xD5, 0xB4, 0x15, 0xB3, 0x96, 0x6E, 
+       /* 0x4c8 */ 0x7E, 0x9B, 0x0C, 0x96, 0x3A, 0xB8, 0x52, 0x2D, 
+       /* 0x4d0 */ 0x3F, 0xD6, 0x5B, 0xE1, 0xFB, 0x08, 0xC2, 0x84, 
+       /* 0x4d8 */ 0xFE, 0x24, 0xA8, 0xA3, 0x89, 0xDA, 0xAC, 0x6A, 
+       /* 0x4e0 */ 0xE1, 0x18, 0x2A, 0xB1, 0xA8, 0x43, 0x61, 0x5B, 
+       /* 0x4e8 */ 0xD3, 0x1F, 0xDC, 0x3B, 0x8D, 0x76, 0xF2, 0x2D, 
+       /* 0x4f0 */ 0xE8, 0x8D, 0x75, 0xDF, 0x17, 0x33, 0x6C, 0x3D, 
+       /* 0x4f8 */ 0x53, 0xFB, 0x7B, 0xCB, 0x41, 0x5F, 0xFF, 0xDC, 
+       /* 0x500 */ 0xA2, 0xD0, 0x61, 0x38, 0xE1, 0x96, 0xB8, 0xAC, 
+       /* 0x508 */ 0x5D, 0x8B, 0x37, 0xD7, 0x75, 0xD5, 0x33, 0xC0, 
+       /* 0x510 */ 0x99, 0x11, 0xAE, 0x9D, 0x41, 0xC1, 0x72, 0x75, 
+       /* 0x518 */ 0x84, 0xBE, 0x02, 0x41, 0x42, 0x5F, 0x67, 0x24, 
+       /* 0x520 */ 0x48, 0x94, 0xD1, 0x9B, 0x27, 0xBE, 0x07, 0x3F, 
+       /* 0x528 */ 0xB9, 0xB8, 0x4F, 0x81, 0x74, 0x51, 0xE1, 0x7A, 
+       /* 0x530 */ 0xB7, 0xED, 0x9D, 0x23, 0xE2, 0xBE, 0xE0, 0xD5, 
+       /* 0x538 */ 0x28, 0x04, 0x13, 0x3C, 0x31, 0x03, 0x9E, 0xDD, 
+       /* 0x540 */ 0x7A, 0x6C, 0x8F, 0xC6, 0x07, 0x18, 0xC6, 0x7F, 
+       /* 0x548 */ 0xDE, 0x47, 0x8E, 0x3F, 0x28, 0x9E, 0x04, 0x06, 
+       /* 0x550 */ 0xCF, 0xA5, 0x54, 0x34, 0x77, 0xBD, 0xEC, 0x89, 
+       /* 0x558 */ 0x9B, 0xE9, 0x17, 0x43, 0xDF, 0x5B, 0xDB, 0x5F, 
+       /* 0x560 */ 0xFE, 0x8E, 0x1E, 0x57, 0xA2, 0xCD, 0x40, 0x9D, 
+       /* 0x568 */ 0x7E, 0x62, 0x22, 0xDA, 0xDE, 0x18, 0x27, 
+};
+static const lws_ss_x509_t _ss_x509_isrg_root_x1 = {
+       .vhost_name = "isrg_root_x1",
+       .ca_der = _ss_der_isrg_root_x1,
+       .ca_der_len = 1391,
+};
+static const uint8_t _ss_der_LEX3_isrg_root_x1[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x05, 0x8D, 0x30, 0x82, 0x03, 0x75, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 
+       /* 0x 10 */ 0xD3, 0xB1, 0x72, 0x26, 0x34, 0x23, 0x32, 0xDC, 
+       /* 0x 18 */ 0xF4, 0x05, 0x28, 0x51, 0x2A, 0xEC, 0x9C, 0x6A, 
+       /* 0x 20 */ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+       /* 0x 28 */ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 
+       /* 0x 30 */ 0x4F, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 
+       /* 0x 38 */ 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x29, 
+       /* 0x 40 */ 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 
+       /* 0x 48 */ 0x20, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 
+       /* 0x 50 */ 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 
+       /* 0x 58 */ 0x74, 0x79, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 
+       /* 0x 60 */ 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6F, 0x75, 
+       /* 0x 68 */ 0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 
+       /* 0x 70 */ 0x04, 0x03, 0x13, 0x0C, 0x49, 0x53, 0x52, 0x47, 
+       /* 0x 78 */ 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x58, 0x31, 
+       /* 0x 80 */ 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x36, 0x31, 0x30, 
+       /* 0x 88 */ 0x30, 0x36, 0x31, 0x35, 0x34, 0x33, 0x35, 0x35, 
+       /* 0x 90 */ 0x5A, 0x17, 0x0D, 0x32, 0x31, 0x31, 0x30, 0x30, 
+       /* 0x 98 */ 0x36, 0x31, 0x35, 0x34, 0x33, 0x35, 0x35, 0x5A, 
+       /* 0x a0 */ 0x30, 0x4A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 
+       /* 0x a8 */ 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 
+       /* 0x b0 */ 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A, 
+       /* 0x b8 */ 0x13, 0x0D, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 
+       /* 0x c0 */ 0x45, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74, 0x31, 
+       /* 0x c8 */ 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 
+       /* 0x d0 */ 0x13, 0x1A, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 
+       /* 0x d8 */ 0x45, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74, 0x20, 
+       /* 0x e0 */ 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 
+       /* 0x e8 */ 0x79, 0x20, 0x58, 0x33, 0x30, 0x82, 0x01, 0x22, 
+       /* 0x f0 */ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+       /* 0x f8 */ 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 
+       /* 0x100 */ 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 
+       /* 0x108 */ 0x02, 0x82, 0x01, 0x01, 0x00, 0x9C, 0xD3, 0x0C, 
+       /* 0x110 */ 0xF0, 0x5A, 0xE5, 0x2E, 0x47, 0xB7, 0x72, 0x5D, 
+       /* 0x118 */ 0x37, 0x83, 0xB3, 0x68, 0x63, 0x30, 0xEA, 0xD7, 
+       /* 0x120 */ 0x35, 0x26, 0x19, 0x25, 0xE1, 0xBD, 0xBE, 0x35, 
+       /* 0x128 */ 0xF1, 0x70, 0x92, 0x2F, 0xB7, 0xB8, 0x4B, 0x41, 
+       /* 0x130 */ 0x05, 0xAB, 0xA9, 0x9E, 0x35, 0x08, 0x58, 0xEC, 
+       /* 0x138 */ 0xB1, 0x2A, 0xC4, 0x68, 0x87, 0x0B, 0xA3, 0xE3, 
+       /* 0x140 */ 0x75, 0xE4, 0xE6, 0xF3, 0xA7, 0x62, 0x71, 0xBA, 
+       /* 0x148 */ 0x79, 0x81, 0x60, 0x1F, 0xD7, 0x91, 0x9A, 0x9F, 
+       /* 0x150 */ 0xF3, 0xD0, 0x78, 0x67, 0x71, 0xC8, 0x69, 0x0E, 
+       /* 0x158 */ 0x95, 0x91, 0xCF, 0xFE, 0xE6, 0x99, 0xE9, 0x60, 
+       /* 0x160 */ 0x3C, 0x48, 0xCC, 0x7E, 0xCA, 0x4D, 0x77, 0x12, 
+       /* 0x168 */ 0x24, 0x9D, 0x47, 0x1B, 0x5A, 0xEB, 0xB9, 0xEC, 
+       /* 0x170 */ 0x1E, 0x37, 0x00, 0x1C, 0x9C, 0xAC, 0x7B, 0xA7, 
+       /* 0x178 */ 0x05, 0xEA, 0xCE, 0x4A, 0xEB, 0xBD, 0x41, 0xE5, 
+       /* 0x180 */ 0x36, 0x98, 0xB9, 0xCB, 0xFD, 0x6D, 0x3C, 0x96, 
+       /* 0x188 */ 0x68, 0xDF, 0x23, 0x2A, 0x42, 0x90, 0x0C, 0x86, 
+       /* 0x190 */ 0x74, 0x67, 0xC8, 0x7F, 0xA5, 0x9A, 0xB8, 0x52, 
+       /* 0x198 */ 0x61, 0x14, 0x13, 0x3F, 0x65, 0xE9, 0x82, 0x87, 
+       /* 0x1a0 */ 0xCB, 0xDB, 0xFA, 0x0E, 0x56, 0xF6, 0x86, 0x89, 
+       /* 0x1a8 */ 0xF3, 0x85, 0x3F, 0x97, 0x86, 0xAF, 0xB0, 0xDC, 
+       /* 0x1b0 */ 0x1A, 0xEF, 0x6B, 0x0D, 0x95, 0x16, 0x7D, 0xC4, 
+       /* 0x1b8 */ 0x2B, 0xA0, 0x65, 0xB2, 0x99, 0x04, 0x36, 0x75, 
+       /* 0x1c0 */ 0x80, 0x6B, 0xAC, 0x4A, 0xF3, 0x1B, 0x90, 0x49, 
+       /* 0x1c8 */ 0x78, 0x2F, 0xA2, 0x96, 0x4F, 0x2A, 0x20, 0x25, 
+       /* 0x1d0 */ 0x29, 0x04, 0xC6, 0x74, 0xC0, 0xD0, 0x31, 0xCD, 
+       /* 0x1d8 */ 0x8F, 0x31, 0x38, 0x95, 0x16, 0xBA, 0xA8, 0x33, 
+       /* 0x1e0 */ 0xB8, 0x43, 0xF1, 0xB1, 0x1F, 0xC3, 0x30, 0x7F, 
+       /* 0x1e8 */ 0xA2, 0x79, 0x31, 0x13, 0x3D, 0x2D, 0x36, 0xF8, 
+       /* 0x1f0 */ 0xE3, 0xFC, 0xF2, 0x33, 0x6A, 0xB9, 0x39, 0x31, 
+       /* 0x1f8 */ 0xC5, 0xAF, 0xC4, 0x8D, 0x0D, 0x1D, 0x64, 0x16, 
+       /* 0x200 */ 0x33, 0xAA, 0xFA, 0x84, 0x29, 0xB6, 0xD4, 0x0B, 
+       /* 0x208 */ 0xC0, 0xD8, 0x7D, 0xC3, 0x93, 0x02, 0x03, 0x01, 
+       /* 0x210 */ 0x00, 0x01, 0xA3, 0x82, 0x01, 0x67, 0x30, 0x82, 
+       /* 0x218 */ 0x01, 0x63, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 
+       /* 0x220 */ 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, 
+       /* 0x228 */ 0x01, 0x86, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1D, 
+       /* 0x230 */ 0x13, 0x01, 0x01, 0xFF, 0x04, 0x08, 0x30, 0x06, 
+       /* 0x238 */ 0x01, 0x01, 0xFF, 0x02, 0x01, 0x00, 0x30, 0x54, 
+       /* 0x240 */ 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04, 0x4D, 0x30, 
+       /* 0x248 */ 0x4B, 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0C, 
+       /* 0x250 */ 0x01, 0x02, 0x01, 0x30, 0x3F, 0x06, 0x0B, 0x2B, 
+       /* 0x258 */ 0x06, 0x01, 0x04, 0x01, 0x82, 0xDF, 0x13, 0x01, 
+       /* 0x260 */ 0x01, 0x01, 0x30, 0x30, 0x30, 0x2E, 0x06, 0x08, 
+       /* 0x268 */ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 
+       /* 0x270 */ 0x16, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 
+       /* 0x278 */ 0x2F, 0x63, 0x70, 0x73, 0x2E, 0x72, 0x6F, 0x6F, 
+       /* 0x280 */ 0x74, 0x2D, 0x78, 0x31, 0x2E, 0x6C, 0x65, 0x74, 
+       /* 0x288 */ 0x73, 0x65, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74, 
+       /* 0x290 */ 0x2E, 0x6F, 0x72, 0x67, 0x30, 0x1D, 0x06, 0x03, 
+       /* 0x298 */ 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xA8, 
+       /* 0x2a0 */ 0x4A, 0x6A, 0x63, 0x04, 0x7D, 0xDD, 0xBA, 0xE6, 
+       /* 0x2a8 */ 0xD1, 0x39, 0xB7, 0xA6, 0x45, 0x65, 0xEF, 0xF3, 
+       /* 0x2b0 */ 0xA8, 0xEC, 0xA1, 0x30, 0x33, 0x06, 0x03, 0x55, 
+       /* 0x2b8 */ 0x1D, 0x1F, 0x04, 0x2C, 0x30, 0x2A, 0x30, 0x28, 
+       /* 0x2c0 */ 0xA0, 0x26, 0xA0, 0x24, 0x86, 0x22, 0x68, 0x74, 
+       /* 0x2c8 */ 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x63, 0x72, 0x6C, 
+       /* 0x2d0 */ 0x2E, 0x72, 0x6F, 0x6F, 0x74, 0x2D, 0x78, 0x31, 
+       /* 0x2d8 */ 0x2E, 0x6C, 0x65, 0x74, 0x73, 0x65, 0x6E, 0x63, 
+       /* 0x2e0 */ 0x72, 0x79, 0x70, 0x74, 0x2E, 0x6F, 0x72, 0x67, 
+       /* 0x2e8 */ 0x30, 0x72, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 
+       /* 0x2f0 */ 0x05, 0x07, 0x01, 0x01, 0x04, 0x66, 0x30, 0x64, 
+       /* 0x2f8 */ 0x30, 0x30, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 
+       /* 0x300 */ 0x05, 0x07, 0x30, 0x01, 0x86, 0x24, 0x68, 0x74, 
+       /* 0x308 */ 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x6F, 0x63, 0x73, 
+       /* 0x310 */ 0x70, 0x2E, 0x72, 0x6F, 0x6F, 0x74, 0x2D, 0x78, 
+       /* 0x318 */ 0x31, 0x2E, 0x6C, 0x65, 0x74, 0x73, 0x65, 0x6E, 
+       /* 0x320 */ 0x63, 0x72, 0x79, 0x70, 0x74, 0x2E, 0x6F, 0x72, 
+       /* 0x328 */ 0x67, 0x2F, 0x30, 0x30, 0x06, 0x08, 0x2B, 0x06, 
+       /* 0x330 */ 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x24, 
+       /* 0x338 */ 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x63, 
+       /* 0x340 */ 0x65, 0x72, 0x74, 0x2E, 0x72, 0x6F, 0x6F, 0x74, 
+       /* 0x348 */ 0x2D, 0x78, 0x31, 0x2E, 0x6C, 0x65, 0x74, 0x73, 
+       /* 0x350 */ 0x65, 0x6E, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2E, 
+       /* 0x358 */ 0x6F, 0x72, 0x67, 0x2F, 0x30, 0x1F, 0x06, 0x03, 
+       /* 0x360 */ 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 
+       /* 0x368 */ 0x14, 0x79, 0xB4, 0x59, 0xE6, 0x7B, 0xB6, 0xE5, 
+       /* 0x370 */ 0xE4, 0x01, 0x73, 0x80, 0x08, 0x88, 0xC8, 0x1A, 
+       /* 0x378 */ 0x58, 0xF6, 0xE9, 0x9B, 0x6E, 0x30, 0x0D, 0x06, 
+       /* 0x380 */ 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 
+       /* 0x388 */ 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 
+       /* 0x390 */ 0x00, 0x19, 0xCF, 0x75, 0x20, 0x34, 0x2D, 0x3A, 
+       /* 0x398 */ 0xA6, 0x45, 0xFF, 0xD0, 0xD5, 0xE6, 0x8C, 0xDA, 
+       /* 0x3a0 */ 0x32, 0xE8, 0x9C, 0x6E, 0x1B, 0x41, 0xD1, 0x27, 
+       /* 0x3a8 */ 0xA8, 0xE2, 0x50, 0xF2, 0x70, 0xAA, 0xC4, 0xE7, 
+       /* 0x3b0 */ 0x93, 0x46, 0xB4, 0xE8, 0x10, 0xAB, 0x70, 0x4F, 
+       /* 0x3b8 */ 0xEF, 0xB7, 0xEA, 0x04, 0xD2, 0x94, 0x11, 0xB1, 
+       /* 0x3c0 */ 0x03, 0xFE, 0x5D, 0xBA, 0xDF, 0x36, 0x8C, 0x94, 
+       /* 0x3c8 */ 0x36, 0x8F, 0x13, 0x7C, 0x44, 0x8F, 0x0B, 0xF5, 
+       /* 0x3d0 */ 0x01, 0x57, 0xAD, 0x68, 0xB8, 0xC5, 0x79, 0xC0, 
+       /* 0x3d8 */ 0xD8, 0x4A, 0x80, 0xD7, 0x4C, 0xA3, 0x1E, 0x24, 
+       /* 0x3e0 */ 0x7A, 0x1F, 0xD7, 0x23, 0xE8, 0xC1, 0x62, 0x3A, 
+       /* 0x3e8 */ 0x76, 0xF9, 0x22, 0x7D, 0x5E, 0x5A, 0xC4, 0x4C, 
+       /* 0x3f0 */ 0x50, 0xCD, 0xAF, 0xDD, 0xEF, 0x6D, 0x36, 0xC0, 
+       /* 0x3f8 */ 0x80, 0x80, 0x1B, 0xA4, 0x3C, 0x70, 0x20, 0xD6, 
+       /* 0x400 */ 0x54, 0x21, 0xD3, 0xBA, 0xEF, 0x14, 0xA9, 0xBF, 
+       /* 0x408 */ 0x07, 0x3F, 0x41, 0x0A, 0x36, 0xB1, 0xA2, 0xB0, 
+       /* 0x410 */ 0x0B, 0x20, 0xD5, 0x1F, 0x67, 0xD0, 0xC3, 0xEB, 
+       /* 0x418 */ 0x88, 0xF6, 0x8A, 0x02, 0xC8, 0xC6, 0x57, 0xB6, 
+       /* 0x420 */ 0x0C, 0xFC, 0x56, 0xF1, 0xD2, 0x3F, 0x17, 0x69, 
+       /* 0x428 */ 0x68, 0x1C, 0xC8, 0xD7, 0x66, 0x3A, 0x86, 0xF1, 
+       /* 0x430 */ 0x19, 0x2A, 0x65, 0x47, 0x68, 0xC6, 0xD2, 0x03, 
+       /* 0x438 */ 0xE7, 0xEF, 0x74, 0x16, 0x0B, 0x06, 0x21, 0xF9, 
+       /* 0x440 */ 0x0C, 0xA6, 0xA8, 0x11, 0x4B, 0x4E, 0x5F, 0xE3, 
+       /* 0x448 */ 0x33, 0xDB, 0x08, 0x41, 0xEA, 0x09, 0x79, 0x75, 
+       /* 0x450 */ 0x78, 0xEE, 0x47, 0xC8, 0x42, 0xD3, 0x81, 0xC5, 
+       /* 0x458 */ 0x65, 0x2D, 0x75, 0xD0, 0x0E, 0x00, 0x16, 0x9D, 
+       /* 0x460 */ 0x1C, 0xEE, 0xB7, 0x58, 0x45, 0x25, 0xE7, 0x33, 
+       /* 0x468 */ 0x63, 0x5B, 0x63, 0x41, 0x09, 0xE8, 0xE9, 0xFE, 
+       /* 0x470 */ 0xAC, 0xFA, 0x73, 0x32, 0x74, 0xB3, 0x76, 0xE9, 
+       /* 0x478 */ 0x6B, 0x94, 0xE2, 0xCD, 0xD4, 0x62, 0xF3, 0xAE, 
+       /* 0x480 */ 0x3A, 0xC5, 0x31, 0x46, 0x52, 0x6E, 0xED, 0x34, 
+       /* 0x488 */ 0x91, 0x1E, 0xA0, 0xC2, 0xDE, 0x54, 0x84, 0xE5, 
+       /* 0x490 */ 0x78, 0x20, 0x56, 0x4C, 0xDD, 0x68, 0xF9, 0x2E, 
+       /* 0x498 */ 0x28, 0x64, 0x1B, 0x1A, 0x99, 0xF2, 0xFB, 0x4D, 
+       /* 0x4a0 */ 0x7F, 0xE3, 0xB8, 0x5F, 0x5D, 0x73, 0x41, 0xEC, 
+       /* 0x4a8 */ 0x79, 0xED, 0x58, 0xD6, 0x7A, 0x37, 0x65, 0x70, 
+       /* 0x4b0 */ 0xA7, 0xB1, 0xBA, 0x39, 0xF6, 0x3E, 0x61, 0x0A, 
+       /* 0x4b8 */ 0xD9, 0xC0, 0x86, 0x90, 0x9A, 0x1A, 0xC8, 0xA8, 
+       /* 0x4c0 */ 0x96, 0x6E, 0x8A, 0x0B, 0x2B, 0x6D, 0xED, 0xD6, 
+       /* 0x4c8 */ 0xFA, 0x07, 0x67, 0xE7, 0x29, 0x04, 0xF7, 0xE2, 
+       /* 0x4d0 */ 0xB2, 0xD1, 0x58, 0x15, 0x52, 0xC7, 0xF1, 0xA3, 
+       /* 0x4d8 */ 0x9D, 0xA6, 0xC0, 0x56, 0x2C, 0xD4, 0x92, 0x98, 
+       /* 0x4e0 */ 0xD8, 0xF1, 0x83, 0xB9, 0x6C, 0x7C, 0x33, 0xA0, 
+       /* 0x4e8 */ 0xE5, 0x4B, 0xAA, 0x90, 0x92, 0xF1, 0xDA, 0x45, 
+       /* 0x4f0 */ 0x4A, 0x34, 0x14, 0xC7, 0x7C, 0x4E, 0xC4, 0xA5, 
+       /* 0x4f8 */ 0x6C, 0x5D, 0x3F, 0xBF, 0xDE, 0xB9, 0xA8, 0x61, 
+       /* 0x500 */ 0x4A, 0x85, 0x20, 0xDE, 0x42, 0x83, 0x29, 0x62, 
+       /* 0x508 */ 0x7C, 0x1C, 0x99, 0x08, 0xA5, 0x46, 0x1F, 0xF4, 
+       /* 0x510 */ 0x6B, 0x22, 0xD3, 0x86, 0x51, 0xCB, 0x37, 0xCD, 
+       /* 0x518 */ 0x60, 0x4A, 0x42, 0x63, 0x56, 0xB3, 0xC8, 0xD1, 
+       /* 0x520 */ 0x8F, 0x31, 0x09, 0x53, 0xC1, 0xE2, 0xDC, 0x1B, 
+       /* 0x528 */ 0xD4, 0xF1, 0x54, 0x77, 0x67, 0xCF, 0x33, 0x7B, 
+       /* 0x530 */ 0x00, 0xD6, 0xD2, 0x7C, 0xDE, 0xC6, 0x79, 0xBF, 
+       /* 0x538 */ 0xCB, 0xE0, 0x16, 0xFD, 0xB2, 0xA1, 0xF2, 0x91, 
+       /* 0x540 */ 0x3C, 0x1D, 0x2D, 0xE8, 0x9C, 0xD4, 0x03, 0xCD, 
+       /* 0x548 */ 0x66, 0x4A, 0xA3, 0x37, 0x93, 0x19, 0x79, 0x7B, 
+       /* 0x550 */ 0xE2, 0x19, 0xC2, 0x16, 0x00, 0xC8, 0xED, 0x0E, 
+       /* 0x558 */ 0x4E, 0x0D, 0xFF, 0x7E, 0xCF, 0x07, 0xA8, 0x64, 
+       /* 0x560 */ 0xCD, 0x29, 0xDF, 0x41, 0xAA, 0x85, 0x30, 0x49, 
+       /* 0x568 */ 0x10, 0x73, 0xA7, 0x4E, 0x89, 0x32, 0x0E, 0x5B, 
+       /* 0x570 */ 0xAD, 0x40, 0x86, 0xC1, 0xB0, 0x94, 0x0C, 0x8D, 
+       /* 0x578 */ 0x26, 0xC5, 0xA7, 0x49, 0xDC, 0x1C, 0xF8, 0x5B, 
+       /* 0x580 */ 0x14, 0x7A, 0x7F, 0x23, 0x69, 0x04, 0xAD, 0xB2, 
+       /* 0x588 */ 0x02, 0x29, 0xD6, 0x12, 0xC8, 0xA4, 0xC6, 0xA1, 
+       /* 0x590 */ 0x2D, 
+};
+static const lws_ss_x509_t _ss_x509_LEX3_isrg_root_x1 = {
+       .vhost_name = "LEX3_isrg_root_x1",
+       .ca_der = _ss_der_LEX3_isrg_root_x1,
+       .ca_der_len = 1425,
+};
+static const lws_ss_trust_store_t _ss_ts_le_via_isrg = {
+       .name = "le_via_isrg",
+       .ssx509 = {
+               &_ss_x509_LEX3_isrg_root_x1,
+               &_ss_x509_isrg_root_x1,
+       }
+};
+
+static const lws_ss_metadata_t _md_mintest_xctype = {
+       .name = "xctype",
+       .value__may_own_heap = (void *)"X-Content-Type:",
+       .length = 0,
+},
+_md_mintest_ctype = {
+       .next = (void *)&_md_mintest_xctype, 
+       .name = "ctype",
+       .value__may_own_heap = (void *)"Content-Type:",
+       .length = 1,
+},
+_md_mintest_uptag = {
+       .next = (void *)&_md_mintest_ctype, 
+       .name = "uptag",
+       .value__may_own_heap = (void *)"X-Upload-Tag:",
+       .length = 2,
+};
+
+static const lws_ss_trust_store_t _ss_ts_avs_via_starfield = {
+       .name = "avs_via_starfield",
+       .ssx509 = {
+               &_ss_x509_starfield_services_root_ca,
+               &_ss_x509_starfield_class_2_ca,
+       }
+};
+static const uint8_t _ss_der_digicert_global_ca_g2[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x04, 0x8B, 0x30, 0x82, 0x03, 0x73, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x0C, 
+       /* 0x 10 */ 0x8E, 0xE0, 0xC9, 0x0D, 0x6A, 0x89, 0x15, 0x88, 
+       /* 0x 18 */ 0x04, 0x06, 0x1E, 0xE2, 0x41, 0xF9, 0xAF, 0x30, 
+       /* 0x 20 */ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 
+       /* 0x 28 */ 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x61, 
+       /* 0x 30 */ 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x 38 */ 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 
+       /* 0x 40 */ 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x0C, 
+       /* 0x 48 */ 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 
+       /* 0x 50 */ 0x20, 0x49, 0x6E, 0x63, 0x31, 0x19, 0x30, 0x17, 
+       /* 0x 58 */ 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x10, 0x77, 
+       /* 0x 60 */ 0x77, 0x77, 0x2E, 0x64, 0x69, 0x67, 0x69, 0x63, 
+       /* 0x 68 */ 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 
+       /* 0x 70 */ 0x20, 0x30, 0x1E, 0x06, 0x03, 0x55, 0x04, 0x03, 
+       /* 0x 78 */ 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 
+       /* 0x 80 */ 0x72, 0x74, 0x20, 0x47, 0x6C, 0x6F, 0x62, 0x61, 
+       /* 0x 88 */ 0x6C, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x47, 
+       /* 0x 90 */ 0x32, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x33, 0x30, 
+       /* 0x 98 */ 0x38, 0x30, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 
+       /* 0x a0 */ 0x30, 0x5A, 0x17, 0x0D, 0x32, 0x38, 0x30, 0x38, 
+       /* 0x a8 */ 0x30, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 
+       /* 0x b0 */ 0x5A, 0x30, 0x44, 0x31, 0x0B, 0x30, 0x09, 0x06, 
+       /* 0x b8 */ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 
+       /* 0x c0 */ 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x c8 */ 0x0A, 0x13, 0x0C, 0x44, 0x69, 0x67, 0x69, 0x43, 
+       /* 0x d0 */ 0x65, 0x72, 0x74, 0x20, 0x49, 0x6E, 0x63, 0x31, 
+       /* 0x d8 */ 0x1E, 0x30, 0x1C, 0x06, 0x03, 0x55, 0x04, 0x03, 
+       /* 0x e0 */ 0x13, 0x15, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 
+       /* 0x e8 */ 0x72, 0x74, 0x20, 0x47, 0x6C, 0x6F, 0x62, 0x61, 
+       /* 0x f0 */ 0x6C, 0x20, 0x43, 0x41, 0x20, 0x47, 0x32, 0x30, 
+       /* 0x f8 */ 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 
+       /* 0x100 */ 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 
+       /* 0x108 */ 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 
+       /* 0x110 */ 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 
+       /* 0x118 */ 0xD3, 0x48, 0x7C, 0xBE, 0xF3, 0x05, 0x86, 0x5D, 
+       /* 0x120 */ 0x5B, 0xD5, 0x2F, 0x85, 0x4E, 0x4B, 0xE0, 0x86, 
+       /* 0x128 */ 0xAD, 0x15, 0xAC, 0x61, 0xCF, 0x5B, 0xAF, 0x3E, 
+       /* 0x130 */ 0x6A, 0x0A, 0x47, 0xFB, 0x9A, 0x76, 0x91, 0x60, 
+       /* 0x138 */ 0x0B, 0x8A, 0x6B, 0xCD, 0xCF, 0xDC, 0x57, 0x7E, 
+       /* 0x140 */ 0x60, 0x98, 0x0B, 0xE4, 0x54, 0xD9, 0x56, 0xED, 
+       /* 0x148 */ 0x21, 0xCC, 0x02, 0xB6, 0x5A, 0x81, 0x5F, 0x97, 
+       /* 0x150 */ 0x6A, 0xEE, 0x02, 0x2F, 0x23, 0x27, 0xB8, 0x6D, 
+       /* 0x158 */ 0xD4, 0xB0, 0xE7, 0x06, 0x02, 0x78, 0x0B, 0x1F, 
+       /* 0x160 */ 0x5C, 0xA9, 0x99, 0x36, 0xFE, 0xBB, 0xAC, 0x1B, 
+       /* 0x168 */ 0x05, 0xFA, 0x57, 0xCD, 0x81, 0x10, 0x40, 0x67, 
+       /* 0x170 */ 0xD6, 0x30, 0x8B, 0x58, 0x35, 0xD4, 0x96, 0x61, 
+       /* 0x178 */ 0xBE, 0xD0, 0x8C, 0x7A, 0x97, 0x9F, 0x1A, 0xF9, 
+       /* 0x180 */ 0x22, 0xE6, 0x14, 0x2F, 0xA9, 0xC6, 0xE8, 0x01, 
+       /* 0x188 */ 0x1F, 0xAB, 0xF8, 0x26, 0x0F, 0xAC, 0x8E, 0x4D, 
+       /* 0x190 */ 0x2C, 0x32, 0x39, 0x1D, 0x81, 0x9B, 0x8D, 0x1C, 
+       /* 0x198 */ 0x65, 0xB2, 0x1C, 0xDB, 0x61, 0xA8, 0x89, 0x2F, 
+       /* 0x1a0 */ 0x60, 0xE7, 0xEB, 0xC2, 0x4A, 0x18, 0xC4, 0x6F, 
+       /* 0x1a8 */ 0x2A, 0xE9, 0x10, 0x92, 0x09, 0xED, 0x17, 0xD1, 
+       /* 0x1b0 */ 0x00, 0x2B, 0xE6, 0x7D, 0xEF, 0x04, 0x89, 0x14, 
+       /* 0x1b8 */ 0x4E, 0x33, 0xA1, 0xB2, 0x0F, 0x97, 0x87, 0x9F, 
+       /* 0x1c0 */ 0xB3, 0xA0, 0xCD, 0x2F, 0xBC, 0x2C, 0xEC, 0xB8, 
+       /* 0x1c8 */ 0x83, 0x68, 0x31, 0x3D, 0x1F, 0xD5, 0x4A, 0x90, 
+       /* 0x1d0 */ 0x10, 0x19, 0x0B, 0x81, 0x95, 0xD6, 0x29, 0x76, 
+       /* 0x1d8 */ 0x51, 0xF9, 0x36, 0x76, 0xD0, 0xB7, 0x09, 0x7A, 
+       /* 0x1e0 */ 0x38, 0x4A, 0xD7, 0x6F, 0x8C, 0xBF, 0x13, 0x7C, 
+       /* 0x1e8 */ 0x39, 0xED, 0xBA, 0xAE, 0x90, 0xFC, 0x95, 0xF7, 
+       /* 0x1f0 */ 0x7B, 0x78, 0x09, 0x36, 0x5E, 0x74, 0x93, 0x1E, 
+       /* 0x1f8 */ 0x25, 0xF0, 0xFF, 0xD4, 0xAD, 0xAE, 0x68, 0x6B, 
+       /* 0x200 */ 0xC6, 0xFF, 0x0F, 0xD5, 0x35, 0xF1, 0x55, 0x6E, 
+       /* 0x208 */ 0x48, 0x49, 0xF8, 0xF8, 0xB8, 0xEF, 0x88, 0xF8, 
+       /* 0x210 */ 0xF1, 0x5E, 0x11, 0x77, 0xAA, 0xDF, 0x02, 0xB3, 
+       /* 0x218 */ 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x82, 0x01, 
+       /* 0x220 */ 0x5A, 0x30, 0x82, 0x01, 0x56, 0x30, 0x12, 0x06, 
+       /* 0x228 */ 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 
+       /* 0x230 */ 0x08, 0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01, 
+       /* 0x238 */ 0x00, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 
+       /* 0x240 */ 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, 0x01, 
+       /* 0x248 */ 0x86, 0x30, 0x34, 0x06, 0x08, 0x2B, 0x06, 0x01, 
+       /* 0x250 */ 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 
+       /* 0x258 */ 0x26, 0x30, 0x24, 0x06, 0x08, 0x2B, 0x06, 0x01, 
+       /* 0x260 */ 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 
+       /* 0x268 */ 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x6F, 0x63, 
+       /* 0x270 */ 0x73, 0x70, 0x2E, 0x64, 0x69, 0x67, 0x69, 0x63, 
+       /* 0x278 */ 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x30, 
+       /* 0x280 */ 0x7B, 0x06, 0x03, 0x55, 0x1D, 0x1F, 0x04, 0x74, 
+       /* 0x288 */ 0x30, 0x72, 0x30, 0x37, 0xA0, 0x35, 0xA0, 0x33, 
+       /* 0x290 */ 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 
+       /* 0x298 */ 0x2F, 0x63, 0x72, 0x6C, 0x34, 0x2E, 0x64, 0x69, 
+       /* 0x2a0 */ 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63, 
+       /* 0x2a8 */ 0x6F, 0x6D, 0x2F, 0x44, 0x69, 0x67, 0x69, 0x43, 
+       /* 0x2b0 */ 0x65, 0x72, 0x74, 0x47, 0x6C, 0x6F, 0x62, 0x61, 
+       /* 0x2b8 */ 0x6C, 0x52, 0x6F, 0x6F, 0x74, 0x47, 0x32, 0x2E, 
+       /* 0x2c0 */ 0x63, 0x72, 0x6C, 0x30, 0x37, 0xA0, 0x35, 0xA0, 
+       /* 0x2c8 */ 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3A, 
+       /* 0x2d0 */ 0x2F, 0x2F, 0x63, 0x72, 0x6C, 0x33, 0x2E, 0x64, 
+       /* 0x2d8 */ 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2E, 
+       /* 0x2e0 */ 0x63, 0x6F, 0x6D, 0x2F, 0x44, 0x69, 0x67, 0x69, 
+       /* 0x2e8 */ 0x43, 0x65, 0x72, 0x74, 0x47, 0x6C, 0x6F, 0x62, 
+       /* 0x2f0 */ 0x61, 0x6C, 0x52, 0x6F, 0x6F, 0x74, 0x47, 0x32, 
+       /* 0x2f8 */ 0x2E, 0x63, 0x72, 0x6C, 0x30, 0x3D, 0x06, 0x03, 
+       /* 0x300 */ 0x55, 0x1D, 0x20, 0x04, 0x36, 0x30, 0x34, 0x30, 
+       /* 0x308 */ 0x32, 0x06, 0x04, 0x55, 0x1D, 0x20, 0x00, 0x30, 
+       /* 0x310 */ 0x2A, 0x30, 0x28, 0x06, 0x08, 0x2B, 0x06, 0x01, 
+       /* 0x318 */ 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1C, 0x68, 
+       /* 0x320 */ 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 
+       /* 0x328 */ 0x77, 0x77, 0x2E, 0x64, 0x69, 0x67, 0x69, 0x63, 
+       /* 0x330 */ 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 
+       /* 0x338 */ 0x43, 0x50, 0x53, 0x30, 0x1D, 0x06, 0x03, 0x55, 
+       /* 0x340 */ 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x24, 0x6E, 
+       /* 0x348 */ 0x2B, 0x2D, 0xD0, 0x6A, 0x92, 0x51, 0x51, 0x25, 
+       /* 0x350 */ 0x69, 0x01, 0xAA, 0x9A, 0x47, 0xA6, 0x89, 0xE7, 
+       /* 0x358 */ 0x40, 0x20, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 
+       /* 0x360 */ 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x4E, 
+       /* 0x368 */ 0x22, 0x54, 0x20, 0x18, 0x95, 0xE6, 0xE3, 0x6E, 
+       /* 0x370 */ 0xE6, 0x0F, 0xFA, 0xFA, 0xB9, 0x12, 0xED, 0x06, 
+       /* 0x378 */ 0x17, 0x8F, 0x39, 0x30, 0x0D, 0x06, 0x09, 0x2A, 
+       /* 0x380 */ 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 
+       /* 0x388 */ 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x0B, 
+       /* 0x390 */ 0x39, 0x84, 0x91, 0xF9, 0x97, 0xEB, 0xAA, 0x81, 
+       /* 0x398 */ 0xAF, 0x84, 0xE9, 0x5A, 0x38, 0x92, 0xFC, 0xE2, 
+       /* 0x3a0 */ 0x6C, 0x59, 0xBF, 0x36, 0xC8, 0x45, 0xA7, 0x31, 
+       /* 0x3a8 */ 0x03, 0x11, 0xE1, 0x06, 0xC0, 0xAC, 0x32, 0xC7, 
+       /* 0x3b0 */ 0x5A, 0x55, 0x29, 0xDA, 0x4F, 0x40, 0x02, 0xF5, 
+       /* 0x3b8 */ 0xA1, 0xDE, 0xB0, 0xED, 0xDE, 0xC0, 0xF8, 0xF6, 
+       /* 0x3c0 */ 0x75, 0x9D, 0x76, 0xB9, 0x87, 0xFE, 0x41, 0x80, 
+       /* 0x3c8 */ 0x7A, 0xCF, 0x5D, 0xE3, 0x00, 0xC6, 0x5B, 0x02, 
+       /* 0x3d0 */ 0xE6, 0x9B, 0x78, 0x62, 0xC9, 0xDC, 0xB8, 0x62, 
+       /* 0x3d8 */ 0x9A, 0x77, 0xED, 0x89, 0x08, 0xD7, 0x4B, 0xC5, 
+       /* 0x3e0 */ 0xFD, 0x43, 0xD5, 0x62, 0x23, 0x27, 0xC4, 0x04, 
+       /* 0x3e8 */ 0x59, 0x6D, 0x71, 0x3F, 0x23, 0x5B, 0xEA, 0xD9, 
+       /* 0x3f0 */ 0xF2, 0xE7, 0x24, 0x27, 0x6F, 0xF4, 0x95, 0x80, 
+       /* 0x3f8 */ 0xDB, 0x96, 0x2C, 0xE4, 0x54, 0x8B, 0xCF, 0xEA, 
+       /* 0x400 */ 0x19, 0xD9, 0x7F, 0x55, 0x99, 0x51, 0x7A, 0x0E, 
+       /* 0x408 */ 0x2D, 0x18, 0x3D, 0x78, 0x58, 0x52, 0xBC, 0x63, 
+       /* 0x410 */ 0x68, 0x57, 0x0B, 0xDD, 0x44, 0xB3, 0x57, 0x4A, 
+       /* 0x418 */ 0x60, 0xE6, 0xC8, 0x70, 0x70, 0x5B, 0x87, 0x28, 
+       /* 0x420 */ 0x6A, 0xD7, 0x3B, 0x4E, 0x52, 0x45, 0x19, 0xAF, 
+       /* 0x428 */ 0x24, 0x06, 0x92, 0x48, 0x11, 0x1A, 0x8B, 0xAE, 
+       /* 0x430 */ 0xAC, 0x18, 0x12, 0x57, 0xAC, 0x03, 0xCB, 0xB8, 
+       /* 0x438 */ 0xF4, 0xBD, 0xCA, 0x26, 0x0E, 0xA7, 0xC1, 0xDD, 
+       /* 0x440 */ 0xE3, 0x33, 0xEF, 0xC0, 0x55, 0x30, 0x0D, 0x95, 
+       /* 0x448 */ 0x59, 0x4E, 0x9C, 0x03, 0x36, 0x06, 0xF8, 0xC0, 
+       /* 0x450 */ 0x8F, 0x14, 0x99, 0x9C, 0x4D, 0x2A, 0x9E, 0xC1, 
+       /* 0x458 */ 0xE1, 0x7D, 0x3B, 0xAF, 0x72, 0xA7, 0x45, 0xBA, 
+       /* 0x460 */ 0x13, 0x96, 0x29, 0x4E, 0x19, 0xD0, 0x1A, 0x98, 
+       /* 0x468 */ 0x06, 0xF4, 0x37, 0x94, 0x17, 0xAD, 0xA3, 0x18, 
+       /* 0x470 */ 0xBA, 0x3E, 0xB0, 0x01, 0x0C, 0x95, 0xD6, 0x29, 
+       /* 0x478 */ 0x35, 0x20, 0x35, 0x7D, 0xF5, 0x10, 0x60, 0xE4, 
+       /* 0x480 */ 0xF7, 0x68, 0x62, 0x1E, 0xEC, 0x19, 0xE1, 0x24, 
+       /* 0x488 */ 0xF2, 0x87, 0x11, 0xAC, 0xE9, 0x08, 0x80, 
+};
+static const lws_ss_x509_t _ss_x509_digicert_global_ca_g2 = {
+       .vhost_name = "digicert_global_ca_g2",
+       .ca_der = _ss_der_digicert_global_ca_g2,
+       .ca_der_len = 1167,
+};
+static const uint8_t _ss_der_digicert_global_root_g2[] = {
+       /* 0x  0 */ 0x30, 0x82, 0x03, 0x8E, 0x30, 0x82, 0x02, 0x76, 
+       /* 0x  8 */ 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x03, 
+       /* 0x 10 */ 0x3A, 0xF1, 0xE6, 0xA7, 0x11, 0xA9, 0xA0, 0xBB, 
+       /* 0x 18 */ 0x28, 0x64, 0xB1, 0x1D, 0x09, 0xFA, 0xE5, 0x30, 
+       /* 0x 20 */ 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 
+       /* 0x 28 */ 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x61, 
+       /* 0x 30 */ 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x 38 */ 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 
+       /* 0x 40 */ 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x0C, 
+       /* 0x 48 */ 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 
+       /* 0x 50 */ 0x20, 0x49, 0x6E, 0x63, 0x31, 0x19, 0x30, 0x17, 
+       /* 0x 58 */ 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x10, 0x77, 
+       /* 0x 60 */ 0x77, 0x77, 0x2E, 0x64, 0x69, 0x67, 0x69, 0x63, 
+       /* 0x 68 */ 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 
+       /* 0x 70 */ 0x20, 0x30, 0x1E, 0x06, 0x03, 0x55, 0x04, 0x03, 
+       /* 0x 78 */ 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 
+       /* 0x 80 */ 0x72, 0x74, 0x20, 0x47, 0x6C, 0x6F, 0x62, 0x61, 
+       /* 0x 88 */ 0x6C, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x47, 
+       /* 0x 90 */ 0x32, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x33, 0x30, 
+       /* 0x 98 */ 0x38, 0x30, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 
+       /* 0x a0 */ 0x30, 0x5A, 0x17, 0x0D, 0x33, 0x38, 0x30, 0x31, 
+       /* 0x a8 */ 0x31, 0x35, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 
+       /* 0x b0 */ 0x5A, 0x30, 0x61, 0x31, 0x0B, 0x30, 0x09, 0x06, 
+       /* 0x b8 */ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 
+       /* 0x c0 */ 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 
+       /* 0x c8 */ 0x0A, 0x13, 0x0C, 0x44, 0x69, 0x67, 0x69, 0x43, 
+       /* 0x d0 */ 0x65, 0x72, 0x74, 0x20, 0x49, 0x6E, 0x63, 0x31, 
+       /* 0x d8 */ 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0B, 
+       /* 0x e0 */ 0x13, 0x10, 0x77, 0x77, 0x77, 0x2E, 0x64, 0x69, 
+       /* 0x e8 */ 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63, 
+       /* 0x f0 */ 0x6F, 0x6D, 0x31, 0x20, 0x30, 0x1E, 0x06, 0x03, 
+       /* 0x f8 */ 0x55, 0x04, 0x03, 0x13, 0x17, 0x44, 0x69, 0x67, 
+       /* 0x100 */ 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, 0x6C, 
+       /* 0x108 */ 0x6F, 0x62, 0x61, 0x6C, 0x20, 0x52, 0x6F, 0x6F, 
+       /* 0x110 */ 0x74, 0x20, 0x47, 0x32, 0x30, 0x82, 0x01, 0x22, 
+       /* 0x118 */ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 
+       /* 0x120 */ 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 
+       /* 0x128 */ 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 
+       /* 0x130 */ 0x02, 0x82, 0x01, 0x01, 0x00, 0xBB, 0x37, 0xCD, 
+       /* 0x138 */ 0x34, 0xDC, 0x7B, 0x6B, 0xC9, 0xB2, 0x68, 0x90, 
+       /* 0x140 */ 0xAD, 0x4A, 0x75, 0xFF, 0x46, 0xBA, 0x21, 0x0A, 
+       /* 0x148 */ 0x08, 0x8D, 0xF5, 0x19, 0x54, 0xC9, 0xFB, 0x88, 
+       /* 0x150 */ 0xDB, 0xF3, 0xAE, 0xF2, 0x3A, 0x89, 0x91, 0x3C, 
+       /* 0x158 */ 0x7A, 0xE6, 0xAB, 0x06, 0x1A, 0x6B, 0xCF, 0xAC, 
+       /* 0x160 */ 0x2D, 0xE8, 0x5E, 0x09, 0x24, 0x44, 0xBA, 0x62, 
+       /* 0x168 */ 0x9A, 0x7E, 0xD6, 0xA3, 0xA8, 0x7E, 0xE0, 0x54, 
+       /* 0x170 */ 0x75, 0x20, 0x05, 0xAC, 0x50, 0xB7, 0x9C, 0x63, 
+       /* 0x178 */ 0x1A, 0x6C, 0x30, 0xDC, 0xDA, 0x1F, 0x19, 0xB1, 
+       /* 0x180 */ 0xD7, 0x1E, 0xDE, 0xFD, 0xD7, 0xE0, 0xCB, 0x94, 
+       /* 0x188 */ 0x83, 0x37, 0xAE, 0xEC, 0x1F, 0x43, 0x4E, 0xDD, 
+       /* 0x190 */ 0x7B, 0x2C, 0xD2, 0xBD, 0x2E, 0xA5, 0x2F, 0xE4, 
+       /* 0x198 */ 0xA9, 0xB8, 0xAD, 0x3A, 0xD4, 0x99, 0xA4, 0xB6, 
+       /* 0x1a0 */ 0x25, 0xE9, 0x9B, 0x6B, 0x00, 0x60, 0x92, 0x60, 
+       /* 0x1a8 */ 0xFF, 0x4F, 0x21, 0x49, 0x18, 0xF7, 0x67, 0x90, 
+       /* 0x1b0 */ 0xAB, 0x61, 0x06, 0x9C, 0x8F, 0xF2, 0xBA, 0xE9, 
+       /* 0x1b8 */ 0xB4, 0xE9, 0x92, 0x32, 0x6B, 0xB5, 0xF3, 0x57, 
+       /* 0x1c0 */ 0xE8, 0x5D, 0x1B, 0xCD, 0x8C, 0x1D, 0xAB, 0x95, 
+       /* 0x1c8 */ 0x04, 0x95, 0x49, 0xF3, 0x35, 0x2D, 0x96, 0xE3, 
+       /* 0x1d0 */ 0x49, 0x6D, 0xDD, 0x77, 0xE3, 0xFB, 0x49, 0x4B, 
+       /* 0x1d8 */ 0xB4, 0xAC, 0x55, 0x07, 0xA9, 0x8F, 0x95, 0xB3, 
+       /* 0x1e0 */ 0xB4, 0x23, 0xBB, 0x4C, 0x6D, 0x45, 0xF0, 0xF6, 
+       /* 0x1e8 */ 0xA9, 0xB2, 0x95, 0x30, 0xB4, 0xFD, 0x4C, 0x55, 
+       /* 0x1f0 */ 0x8C, 0x27, 0x4A, 0x57, 0x14, 0x7C, 0x82, 0x9D, 
+       /* 0x1f8 */ 0xCD, 0x73, 0x92, 0xD3, 0x16, 0x4A, 0x06, 0x0C, 
+       /* 0x200 */ 0x8C, 0x50, 0xD1, 0x8F, 0x1E, 0x09, 0xBE, 0x17, 
+       /* 0x208 */ 0xA1, 0xE6, 0x21, 0xCA, 0xFD, 0x83, 0xE5, 0x10, 
+       /* 0x210 */ 0xBC, 0x83, 0xA5, 0x0A, 0xC4, 0x67, 0x28, 0xF6, 
+       /* 0x218 */ 0x73, 0x14, 0x14, 0x3D, 0x46, 0x76, 0xC3, 0x87, 
+       /* 0x220 */ 0x14, 0x89, 0x21, 0x34, 0x4D, 0xAF, 0x0F, 0x45, 
+       /* 0x228 */ 0x0C, 0xA6, 0x49, 0xA1, 0xBA, 0xBB, 0x9C, 0xC5, 
+       /* 0x230 */ 0xB1, 0x33, 0x83, 0x29, 0x85, 0x02, 0x03, 0x01, 
+       /* 0x238 */ 0x00, 0x01, 0xA3, 0x42, 0x30, 0x40, 0x30, 0x0F, 
+       /* 0x240 */ 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 
+       /* 0x248 */ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 
+       /* 0x250 */ 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 
+       /* 0x258 */ 0xFF, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 
+       /* 0x260 */ 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 
+       /* 0x268 */ 0x04, 0x14, 0x4E, 0x22, 0x54, 0x20, 0x18, 0x95, 
+       /* 0x270 */ 0xE6, 0xE3, 0x6E, 0xE6, 0x0F, 0xFA, 0xFA, 0xB9, 
+       /* 0x278 */ 0x12, 0xED, 0x06, 0x17, 0x8F, 0x39, 0x30, 0x0D, 
+       /* 0x280 */ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 
+       /* 0x288 */ 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 
+       /* 0x290 */ 0x01, 0x00, 0x60, 0x67, 0x28, 0x94, 0x6F, 0x0E, 
+       /* 0x298 */ 0x48, 0x63, 0xEB, 0x31, 0xDD, 0xEA, 0x67, 0x18, 
+       /* 0x2a0 */ 0xD5, 0x89, 0x7D, 0x3C, 0xC5, 0x8B, 0x4A, 0x7F, 
+       /* 0x2a8 */ 0xE9, 0xBE, 0xDB, 0x2B, 0x17, 0xDF, 0xB0, 0x5F, 
+       /* 0x2b0 */ 0x73, 0x77, 0x2A, 0x32, 0x13, 0x39, 0x81, 0x67, 
+       /* 0x2b8 */ 0x42, 0x84, 0x23, 0xF2, 0x45, 0x67, 0x35, 0xEC, 
+       /* 0x2c0 */ 0x88, 0xBF, 0xF8, 0x8F, 0xB0, 0x61, 0x0C, 0x34, 
+       /* 0x2c8 */ 0xA4, 0xAE, 0x20, 0x4C, 0x84, 0xC6, 0xDB, 0xF8, 
+       /* 0x2d0 */ 0x35, 0xE1, 0x76, 0xD9, 0xDF, 0xA6, 0x42, 0xBB, 
+       /* 0x2d8 */ 0xC7, 0x44, 0x08, 0x86, 0x7F, 0x36, 0x74, 0x24, 
+       /* 0x2e0 */ 0x5A, 0xDA, 0x6C, 0x0D, 0x14, 0x59, 0x35, 0xBD, 
+       /* 0x2e8 */ 0xF2, 0x49, 0xDD, 0xB6, 0x1F, 0xC9, 0xB3, 0x0D, 
+       /* 0x2f0 */ 0x47, 0x2A, 0x3D, 0x99, 0x2F, 0xBB, 0x5C, 0xBB, 
+       /* 0x2f8 */ 0xB5, 0xD4, 0x20, 0xE1, 0x99, 0x5F, 0x53, 0x46, 
+       /* 0x300 */ 0x15, 0xDB, 0x68, 0x9B, 0xF0, 0xF3, 0x30, 0xD5, 
+       /* 0x308 */ 0x3E, 0x31, 0xE2, 0x8D, 0x84, 0x9E, 0xE3, 0x8A, 
+       /* 0x310 */ 0xDA, 0xDA, 0x96, 0x3E, 0x35, 0x13, 0xA5, 0x5F, 
+       /* 0x318 */ 0xF0, 0xF9, 0x70, 0x50, 0x70, 0x47, 0x41, 0x11, 
+       /* 0x320 */ 0x57, 0x19, 0x4E, 0xC0, 0x8F, 0xAE, 0x06, 0xC4, 
+       /* 0x328 */ 0x95, 0x13, 0x17, 0x2F, 0x1B, 0x25, 0x9F, 0x75, 
+       /* 0x330 */ 0xF2, 0xB1, 0x8E, 0x99, 0xA1, 0x6F, 0x13, 0xB1, 
+       /* 0x338 */ 0x41, 0x71, 0xFE, 0x88, 0x2A, 0xC8, 0x4F, 0x10, 
+       /* 0x340 */ 0x20, 0x55, 0xD7, 0xF3, 0x14, 0x45, 0xE5, 0xE0, 
+       /* 0x348 */ 0x44, 0xF4, 0xEA, 0x87, 0x95, 0x32, 0x93, 0x0E, 
+       /* 0x350 */ 0xFE, 0x53, 0x46, 0xFA, 0x2C, 0x9D, 0xFF, 0x8B, 
+       /* 0x358 */ 0x22, 0xB9, 0x4B, 0xD9, 0x09, 0x45, 0xA4, 0xDE, 
+       /* 0x360 */ 0xA4, 0xB8, 0x9A, 0x58, 0xDD, 0x1B, 0x7D, 0x52, 
+       /* 0x368 */ 0x9F, 0x8E, 0x59, 0x43, 0x88, 0x81, 0xA4, 0x9E, 
+       /* 0x370 */ 0x26, 0xD5, 0x6F, 0xAD, 0xDD, 0x0D, 0xC6, 0x37, 
+       /* 0x378 */ 0x7D, 0xED, 0x03, 0x92, 0x1B, 0xE5, 0x77, 0x5F, 
+       /* 0x380 */ 0x76, 0xEE, 0x3C, 0x8D, 0xC4, 0x5D, 0x56, 0x5B, 
+       /* 0x388 */ 0xA2, 0xD9, 0x66, 0x6E, 0xB3, 0x35, 0x37, 0xE5, 
+       /* 0x390 */ 0x32, 0xB6, 
+};
+static const lws_ss_x509_t _ss_x509_digicert_global_root_g2 = {
+       .vhost_name = "digicert_global_root_g2",
+       .ca_der = _ss_der_digicert_global_root_g2,
+       .ca_der_len = 914,
+};
+static const lws_ss_trust_store_t _ss_ts_api_amazon_com = {
+       .name = "api_amazon_com",
+       .ssx509 = {
+               &_ss_x509_digicert_global_root_g2,
+               &_ss_x509_digicert_global_ca_g2,
+       }
+};
+
+static const lws_ss_policy_t _ssp_captive_portal_detect = {
+       .streamtype = "captive_portal_detect",
+       .endpoint = "connectivitycheck.android.com",
+       .u = {
+               .http = {
+                       .method = "GET",
+                       .url = "generate_204",
+                       .resp_expect = 204,
+                       .fail_redirect = 1,
+               }
+       },
+       .flags = 0x1,
+       .port = 80,
+       .protocol = 0,
+},
+_ssp_mqtt_test1 = {
+       .next = (void *)&_ssp_captive_portal_detect,
+       .streamtype = "mqtt_test1",
+       .endpoint = "a1ygonr3im5cv2-ats.iot.us-west-2.amazonaws.com",
+       .u = {
+               .mqtt = {
+                       .topic = "test/topic1",
+                       .subscribe = "test/topic1",
+                       .qos = 1,
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x10,
+       .port = 443,
+       .protocol = 3,
+       .client_cert = 1,
+       .trust = {.store = &_ss_ts_mqtt_amz_iot},
+},
+_ssp_mqtt_test = {
+       .next = (void *)&_ssp_mqtt_test1,
+       .streamtype = "mqtt_test",
+       .endpoint = "a1ygonr3im5cv2-ats.iot.us-west-2.amazonaws.com",
+       .u = {
+               .mqtt = {
+                       .topic = "test/topic0",
+                       .subscribe = "test/topic0",
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x10,
+       .port = 443,
+       .protocol = 3,
+       .client_cert = 1,
+       .trust = {.store = &_ss_ts_mqtt_amz_iot},
+},
+_ssp_minpost = {
+       .next = (void *)&_ssp_mqtt_test,
+       .streamtype = "minpost",
+       .endpoint = "warmcat.com",
+       .u = {
+               .http = {
+                       .method = "POST",
+                       .url = "testserver/formtest",
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x11,
+       .port = 443,
+       .protocol = 0,
+       .trust = {.store = &_ss_ts_le_via_isrg},
+},
+_ssp_mintest_fail = {
+       .next = (void *)&_ssp_minpost,
+       .streamtype = "mintest-fail",
+       .endpoint = "warmcat.com",
+       .u = {
+               .http = {
+                       .method = "GET",
+                       .url = "index.html",
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x11,
+       .port = 22,
+       .protocol = 0,
+       .trust = {.store = &_ss_ts_le_via_isrg},
+},
+_ssp_h2longpolltest = {
+       .next = (void *)&_ssp_mintest_fail,
+       .streamtype = "h2longpolltest",
+       .endpoint = "warmcat.com",
+       .u = {
+               .http = {
+                       .method = "GET",
+                       .url = "index.html",
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x32,
+       .port = 443,
+       .protocol = 1,
+       .trust = {.store = &_ss_ts_le_via_isrg},
+},
+_ssp_mintest = {
+       .next = (void *)&_ssp_h2longpolltest,
+       .streamtype = "mintest",
+       .endpoint = "warmcat.com",
+       .metadata = (void *)&_md_mintest_uptag,
+       .u = {
+               .http = {
+                       .method = "GET",
+                       .url = "index.html?uptag=${uptag}",
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x11,
+       .port = 443,
+       .metadata_count = 3,
+       .protocol = 0,
+       .trust = {.store = &_ss_ts_le_via_isrg},
+},
+_ssp_avs_audio = {
+       .next = (void *)&_ssp_mintest,
+       .streamtype = "avs_audio",
+       .endpoint = "alexa.na.gateway.devices.a2z.com",
+       .u = {
+               .http = {
+                       .method = "POST",
+                       .url = "v20160207/events",
+                       .multipart_name = "audio",
+                       .multipart_content_type = "application/octet-stream",
+                       .auth_preamble = "Bearer ",
+                       .blob_header = {
+                               "authorization:",
+                       },
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0xa90,
+       .port = 443,
+       .protocol = 1,
+       .trust = {.store = &_ss_ts_avs_via_starfield},
+},
+_ssp_avs_metadata = {
+       .next = (void *)&_ssp_avs_audio,
+       .streamtype = "avs_metadata",
+       .endpoint = "alexa.na.gateway.devices.a2z.com",
+       .rideshare_streamtype = "avs_audio",
+       .u = {
+               .http = {
+                       .method = "POST",
+                       .url = "v20160207/events",
+                       .multipart_name = "metadata",
+                       .multipart_content_type = "application/json; charset=UTF-8",
+                       .auth_preamble = "Bearer ",
+                       .blob_header = {
+                               "authorization:",
+                       },
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0xa91,
+       .port = 443,
+       .protocol = 1,
+       .trust = {.store = &_ss_ts_avs_via_starfield},
+},
+_ssp_avs_event = {
+       .next = (void *)&_ssp_avs_metadata,
+       .streamtype = "avs_event",
+       .endpoint = "alexa.na.gateway.devices.a2z.com",
+       .u = {
+               .http = {
+                       .method = "GET",
+                       .url = "v20160207/directives",
+                       .auth_preamble = "Bearer ",
+                       .blob_header = {
+                               "authorization:",
+                       },
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x2b2,
+       .port = 443,
+       .protocol = 1,
+       .trust = {.store = &_ss_ts_avs_via_starfield},
+},
+_ssp_api_amazon_com_auth = {
+       .next = (void *)&_ssp_avs_event,
+       .streamtype = "api_amazon_com_auth",
+       .endpoint = "api.amazon.com",
+       .u = {
+               .http = {
+                       .method = "POST",
+                       .url = "auth/o2/token",
+               }
+       },
+       .retry_bo = &_rbo_0,
+       .flags = 0x1291,
+       .port = 443,
+       .protocol = 0,
+       .trust = {.store = &_ss_ts_api_amazon_com},
+};
+#define _ss_static_policy_entry _ssp_api_amazon_com_auth
+/* estimated footprint 10720 (when sizeof void * = 8) */
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/static-policy.json b/minimal-examples/secure-streams/minimal-secure-streams-staticpolicy/static-policy.json
new file mode 100644 (file)
index 0000000..6f16fa1
--- /dev/null
@@ -0,0 +1,218 @@
+{
+       "release": "01234567",
+       "product": "myproduct",
+       "schema-version": 1,
+       "retry": [{
+               "default": {
+                       "backoff": [1000, 2000, 3000, 5000, 10000],
+                       "conceal": 5,
+                       "jitterpc": 20,
+                       "svalidping": 30,
+                       "svalidhup": 35
+               }
+       }],
+       "certs": [{
+               "isrg_root_x1": "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZLubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc="
+       }, {
+               "LEX3_isrg_root_x1": "MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrXNSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHlNpi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7DcGu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgzuEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMBAAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEFBQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsGAQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYDVR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIBABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGxA/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRMUM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOuOsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vwp7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKRPB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5brUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt"
+       }, {
+       "amazon_root_ca_1": "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5"
+       }, {
+               "digicert_global_root_g2": "MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTflMrY="
+       }, {
+               "digicert_global_ca_g2": "MIIEizCCA3OgAwIBAgIQDI7gyQ1qiRWIBAYe4kH5rzANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0yODA4MDExMjAwMDBaMEQxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEdsb2JhbCBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANNIfL7zBYZdW9UvhU5L4IatFaxhz1uvPmoKR/uadpFgC4przc/cV35gmAvkVNlW7SHMArZagV+Xau4CLyMnuG3UsOcGAngLH1ypmTb+u6wbBfpXzYEQQGfWMItYNdSWYb7QjHqXnxr5IuYUL6nG6AEfq/gmD6yOTSwyOR2Bm40cZbIc22GoiS9g5+vCShjEbyrpEJIJ7RfRACvmfe8EiRROM6GyD5eHn7OgzS+8LOy4g2gxPR/VSpAQGQuBldYpdlH5NnbQtwl6OErXb4y/E3w57bqukPyV93t4CTZedJMeJfD/1K2uaGvG/w/VNfFVbkhJ+Pi474j48V4Rd6rfArMCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFCRuKy3QapJRUSVpAaqaR6aJ50AgMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485MA0GCSqGSIb3DQEBCwUAA4IBAQALOYSR+ZfrqoGvhOlaOJL84mxZvzbIRacxAxHhBsCsMsdaVSnaT0AC9aHesO3ewPj2dZ12uYf+QYB6z13jAMZbAuabeGLJ3LhimnftiQjXS8X9Q9ViIyfEBFltcT8jW+rZ8uckJ2/0lYDblizkVIvP6hnZf1WZUXoOLRg9eFhSvGNoVwvdRLNXSmDmyHBwW4coatc7TlJFGa8kBpJIERqLrqwYElesA8u49L3KJg6nwd3jM+/AVTANlVlOnAM2BvjAjxSZnE0qnsHhfTuvcqdFuhOWKU4Z0BqYBvQ3lBetoxi6PrABDJXWKTUgNX31EGDk92hiHuwZ4STyhxGs6QiA"
+       }, {
+               "starfield_services_root_ca": "MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkdiEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6"
+       }, {
+               "starfield_class_2_ca": "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJlxy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q="
+       }],
+       "trust_stores": [{
+               "name": "le_via_isrg",
+               "stack": ["isrg_root_x1", "LEX3_isrg_root_x1"]
+       }, {
+               "name": "api_amazon_com",
+               "stack": ["digicert_global_ca_g2", "digicert_global_root_g2"]
+       }, {
+               "name": "avs_via_starfield",
+               "stack": ["starfield_class_2_ca", "starfield_services_root_ca"]
+       }, {
+               "name": "mqtt_amz_iot",
+               "stack": ["amazon_root_ca_1", "starfield_class_2_ca", "starfield_services_root_ca"]
+       }],
+       "s": [{
+               "api_amazon_com_auth": {
+                       "endpoint": "api.amazon.com",
+                       "port": 443,
+                       "protocol": "h1",
+                       "http_method": "POST",
+                       "http_url": "auth/o2/token",
+                       "plugins": [],
+                       "opportunistic": true,
+                       "tls": true,
+                       "h2q_oflow_txcr": true,
+                       "http_www_form_urlencoded": true,
+                       "http_no_content_length": true,
+                       "retry": "default",
+                       "tls_trust_store": "api_amazon_com"
+               }
+       }, {
+               "avs_event": {
+                       "endpoint": "alexa.na.gateway.devices.a2z.com",
+                       "port": 443,
+                       "protocol": "h2",
+                       "http_method": "GET",
+                       "http_url": "v20160207/directives",
+                       "h2q_oflow_txcr": true,
+                       "http_auth_header": "authorization:",
+                       "http_auth_preamble": "Bearer ",
+                       "http_no_content_length": true,
+                       "nailed_up": true,
+                       "long_poll": true,
+                       "retry": "default",
+                       "plugins": [],
+                       "tls": true,
+                       "tls_trust_store": "avs_via_starfield"
+               }
+       }, {
+               "avs_metadata": {
+                       "endpoint": "alexa.na.gateway.devices.a2z.com",
+                       "port": 443,
+                       "protocol": "h2",
+                       "http_method": "POST",
+                       "http_url": "v20160207/events",
+                       "opportunistic": true,
+                       "h2q_oflow_txcr": true,
+                       "http_auth_header": "authorization:",
+                       "http_auth_preamble": "Bearer ",
+                       "http_multipart_name": "metadata",
+                       "http_mime_content_type": "application/json; charset=UTF-8",
+                       "http_no_content_length": true,
+                       "rideshare": "avs_audio",
+                       "retry": "default",
+                       "plugins": [],
+                       "tls": true,
+                       "tls_trust_store": "avs_via_starfield"
+               }
+       }, {
+               "avs_audio": {
+                       "endpoint": "alexa.na.gateway.devices.a2z.com",
+                       "port": 443,
+                       "protocol": "h2",
+                       "http_method": "POST",
+                       "http_url": "v20160207/events",
+                       "plugins": [],
+                       "tls": true,
+                       "h2q_oflow_txcr": true,
+                       "http_auth_header": "authorization:",
+                       "http_auth_preamble": "Bearer ",
+                       "http_multipart_name": "audio",
+                       "http_mime_content_type": "application/octet-stream",
+                       "http_no_content_length": true,
+                       "retry": "default",
+                       "tls_trust_store": "avs_via_starfield"
+               }
+       }, {
+               "mintest": {
+                       "endpoint": "warmcat.com",
+                       "port": 443,
+                       "protocol": "h1",
+                       "http_method": "GET",
+                       "http_url": "index.html?uptag=${uptag}",
+                       "http_dsn_header": "x-dsn:",
+                       "http_fwv_header": "x-fw-version:",
+                       "http_devtype_header": "x-devtype:",
+                       "metadata": [{
+                               "uptag": "X-Upload-Tag:"
+                       }, {
+                               "ctype": "Content-Type:"
+                       }, {
+                               "xctype": "X-Content-Type:"
+                       }],
+                       "plugins": [],
+                       "tls": true,
+                       "opportunistic": true,
+                       "retry": "default",
+                       "tls_trust_store": "le_via_isrg"
+               }
+       }, {
+               "h2longpolltest": {
+                       "endpoint": "warmcat.com",
+                       "port": 443,
+                       "protocol": "h2",
+                       "http_method": "GET",
+                       "http_url": "index.html",
+                       "plugins": [],
+                       "tls": true,
+                       "nailed_up": true,
+                       "long_poll": true,
+                       "retry": "default",
+                       "tls_trust_store": "le_via_isrg"
+               }
+       }, {
+               "mintest-fail": {
+                       "endpoint": "warmcat.com",
+                       "port": 22,
+                       "protocol": "h1",
+                       "http_method": "GET",
+                       "http_url": "index.html",
+                       "plugins": [],
+                       "tls": true,
+                       "opportunistic": true,
+                       "retry": "default",
+                       "tls_trust_store": "le_via_isrg"
+               }
+       }, {
+               "minpost": {
+                       "endpoint": "warmcat.com",
+                       "port": 443,
+                       "protocol": "h1",
+                       "http_method": "POST",
+                       "http_url": "testserver/formtest",
+                       "plugins": [],
+                       "tls": true,
+                       "opportunistic": true,
+                       "retry": "default",
+                       "tls_trust_store": "le_via_isrg"
+               }
+       }, {
+               "mqtt_test": {
+                       "endpoint":             "a1ygonr3im5cv2-ats.iot.us-west-2.amazonaws.com",
+                       "port":                 443,
+                       "tls":                  true,
+                       "client_cert":          0,
+                       "tls_trust_store":      "mqtt_amz_iot",
+                       "protocol":             "mqtt",
+                       "mqtt_topic":           "test/topic0",
+                       "mqtt_subscribe":       "test/topic0",
+                       "mqtt_qos":             0,
+                       "retry":                "default"
+               }
+       }, {
+               "mqtt_test1": {
+                       "endpoint":             "a1ygonr3im5cv2-ats.iot.us-west-2.amazonaws.com",
+                       "port":                 443,
+                       "tls":                  true,
+                       "client_cert":          0,
+                       "tls_trust_store":      "mqtt_amz_iot",
+                       "protocol":             "mqtt",
+                       "mqtt_topic":           "test/topic1",
+                       "mqtt_subscribe":       "test/topic1",
+                       "mqtt_qos":             1,
+                       "retry":                "default"
+               }
+       }, {
+               "captive_portal_detect": {
+                       "endpoint": "connectivitycheck.android.com",
+                       "port": 80,
+                       "protocol": "h1",
+                       "http_method": "GET",
+                       "http_url": "generate_204",
+                       "opportunistic": true,
+                       "http_expect": 204,
+                       "http_fail_redirect": true
+               }
+       }
+       ]
+}
+
+
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-stress/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-stress/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6944e7f
--- /dev/null
@@ -0,0 +1,135 @@
+project(lws-minimal-secure-streams-stress C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-stress)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (NOT WIN32)
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams.c)
+
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32)
+
+               #
+               # When running in CI, wait for a lease on the resources
+               # before starting this test, so the server does not get
+               # thousands of simultaneous tls connection attempts
+               #
+               # sai-resource holds the lease on the resources until
+               # the time given in seconds or the sai-resource instance
+               # exits, whichever happens first
+               #
+               # If running under Sai, creates a lock test called "res_sspcmin"
+               #
+
+               sai_resource(warmcat_conns 1 40 sspcmin)
+
+               #
+               # simple test not via proxy
+               #
+
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME ssstress-warmcat COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-stress> -c 4 --budget 5)
+               else()
+                       add_test(NAME ssstress-warmcat COMMAND lws-minimal-secure-streams-stress -c 4 --budget 5)
+               endif()
+
+               set_tests_properties(ssstress-warmcat
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-stress
+                                    TIMEOUT 60)
+               if (DEFINED ENV{SAI_OVN})
+                       set_tests_properties(ssstress-warmcat PROPERTIES FIXTURES_REQUIRED "res_sspcmin")
+               endif()
+
+               if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+                       #
+                       # Define test dep to bring up and take down the test
+                       # proxy
+                       #
+
+                       if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                               # uds abstract namespace for linux
+                               set(CTEST_SOCKET_PATH "@ctest-sspstress-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       else()
+                               # filesystem socket for others
+                               set(CTEST_SOCKET_PATH "/tmp/ctest-sspstress-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       endif()
+                       add_test(NAME st_ssstressproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               ssstressproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH} )
+                       set_tests_properties(st_ssstressproxy PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP ssstressproxy TIMEOUT 800)
+
+                       add_test(NAME ki_ssstressproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                               ssstressproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH})
+                       set_tests_properties(ki_ssstressproxy PROPERTIES FIXTURES_CLEANUP ssstressproxy)
+
+                       #
+                       # the client part that will connect to the proxy
+                       #
+
+                       if (VALGRIND)
+                               message("testing via valgrind")
+                               add_test(NAME sspc-minimalstress COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-stress-client> -i +${CTEST_SOCKET_PATH} -c 4 --budget 5)
+                       else()
+                               add_test(NAME sspc-minimalstress COMMAND lws-minimal-secure-streams-stress-client -i +${CTEST_SOCKET_PATH} -c 4 --budget 5)
+                       endif()
+
+                       set(fixlist "ssstressproxy")
+                       if (DEFINED ENV{SAI_OVN})
+                               list(APPEND fixlist "res_ssproxy")
+                       endif()
+
+                       set_tests_properties(sspc-minimalstress PROPERTIES
+                               WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-stress
+                               FIXTURES_REQUIRED "${fixlist}"
+                               TIMEOUT 40)
+
+               endif()
+
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client minimal-secure-streams.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-stress/README.md b/minimal-examples/secure-streams/minimal-secure-streams-stress/README.md
new file mode 100644 (file)
index 0000000..2b24f0f
--- /dev/null
@@ -0,0 +1,22 @@
+# lws minimal secure streams stress
+
+This is the same as minimal-secure-streams, except you can have it perform concurrent
+SS connections and a budget of sequential connections.
+
+It basically forks as many times as `-c <concurrent>` and each fork does `--budget <count>`
+SS connections one after the other.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15|
+-c <concurrent>|Fork this many times on init|
+--budget <count>|Each fork sequentially does this many SS connections (default 1)|
+--pass-limit <count>|By default the pass limit is the budget, but if doing fault injection you can set a lower limit here|
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-stress/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams-stress/minimal-secure-streams.c
new file mode 100644 (file)
index 0000000..ad5713a
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * lws-minimal-secure-streams
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates a minimal http client using secure streams api.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.
+ *
+ * This example is built two different ways from the same source... one includes
+ * the policy everything needed to fulfil the stream directly.  The other -client
+ * variant has no policy itself and some other minor init changes, and connects
+ * to the -proxy example to actually get the connection done.
+ *
+ * In the -client build case, the example does not even init the tls libraries
+ * since the proxy part will take care of all that.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+// #define FORCE_OS_TRUST_STORE
+
+/*
+ * uncomment to force network traffic through 127.0.0.1:1080
+ *
+ * On your local machine, you can run a SOCKS5 proxy like this
+ *
+ * $ ssh -N -D 0.0.0.0:1080 localhost -v
+ *
+ * If enabled, this also fetches a remote policy that also
+ * specifies that all traffic should go through the remote
+ * proxy.
+ */
+// #define VIA_LOCALHOST_SOCKS
+
+static int interrupted, bad = 1, force_cpd_fail_portal,
+          force_cpd_fail_no_internet, test_respmap, test_ots,
+          budget = 1, predicted_good = 1, good, orig_budget;
+static unsigned int timeout_ms = 8000;
+static lws_state_notify_link_t nl;
+struct lws_context *context;
+static lws_sorted_usec_list_t sul_timeout; /* for each process to complete */
+
+/*
+ * If the -proxy app is fulfilling our connection, then we don't need to have
+ * the policy in the client.
+ *
+ * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over
+ * a Unix Domain Socket.  To test that, you need to separately run the
+ * ./lws-minimal-secure-streams-proxy test app on the same machine.
+ */
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+#if defined(VIA_LOCALHOST_SOCKS)
+         "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+#endif
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+#if !defined(FORCE_OS_TRUST_STORE)
+                       "{\"isrg_root_x1\": \""
+       "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="
+               "\"}"
+#endif
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+#if !defined(FORCE_OS_TRUST_STORE)
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+#endif
+         "],"
+         "\"s\": ["
+#if !defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+               /*
+                * "fetch_policy" decides from where the real policy
+                * will be fetched, if present.  Otherwise the initial
+                * policy is treated as the whole, hardcoded, policy.
+                */
+               "{\"fetch_policy\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+#if defined(VIA_LOCALHOST_SOCKS)
+                       "\"http_url\":"         "\"policy/minimal-proxy-socks.json\","
+#else
+                       "\"http_url\":"         "\"policy/minimal-proxy-v4.2-v2.json\","
+#endif
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+#if !defined(FORCE_OS_TRUST_STORE)
+                       "\"tls_trust_store\":"  "\"le_via_isrg\","
+#endif
+                       "\"retry\":"            "\"default\""
+#else
+       "{\"mintest\": {"
+                       "\"endpoint\": \"warmcat.com\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"index.html?uptag=${uptag}\","
+                       "\"metadata\": [{"
+                       "       \"uptag\": \"X-Upload-Tag:\""
+                       "}, {"
+                       "       \"xctype\": \"X-Content-Type:\""
+                       "}],"
+                       "\"tls\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"timeout_ms\": 2000,"
+                       "\"direct_proto_str\": true,"
+                       "\"tls_trust_store\": \"le_via_isrg\""
+#endif
+               "}},{"
+                       /*
+                        * "captive_portal_detect" describes
+                        * what to do in order to check if the path to
+                        * the Internet is being interrupted by a
+                        * captive portal.  If there's a larger policy
+                        * fetched from elsewhere, it should also include
+                        * this since it needs to be done at least after
+                        * every DHCP acquisition
+                        */
+                   "\"captive_portal_detect\": {"
+                        "\"endpoint\": \"connectivitycheck.android.com\","
+                       "\"http_url\": \"generate_204\","
+                       "\"port\": 80,"
+                        "\"protocol\": \"h1\","
+                        "\"http_method\": \"GET\","
+                        "\"opportunistic\": true,"
+                        "\"http_expect\": 204,"
+                       "\"http_fail_redirect\": true"
+                "}}"
+       "]}"
+;
+
+#endif
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+       size_t                          amt;
+
+       struct lws_genhash_ctx          hash_ctx;
+} myss_t;
+
+static int
+create_ss(struct lws_context *cx);
+
+#if !defined(LWS_SS_USE_SSPC)
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+#endif
+
+static void
+process_timeout(lws_sorted_usec_list_t *sul)
+{
+       lwsl_err("%s: process timed out\n", __func__);
+
+       exit(1);
+}
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+
+       if (flags & LWSSS_FLAG_PERF_JSON)
+               return LWSSSSRET_OK;
+
+#if !defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       myss_t *m = (myss_t *)userobj;
+       const char *md_srv = "not set", *md_test = "not set";
+       size_t md_srv_len = 7, md_test_len = 7;
+
+       lws_ss_get_metadata(m->ss, "srv", (const void **)&md_srv, &md_srv_len);
+       lws_ss_get_metadata(m->ss, "test", (const void **)&md_test, &md_test_len);
+       lwsl_ss_user(m->ss, "len %d, flags: %d, srv: %.*s, test: %.*s",
+                 (int)len, flags, (int)md_srv_len, md_srv,
+                 (int)md_test_len, md_test);
+
+       lwsl_hexdump_ss_info(m->ss, buf, len);
+#endif
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       //myss_t *m = (myss_t *)userobj;
+
+       /* in this example, we don't send stuff */
+
+       return LWSSSSRET_TX_DONT_SEND;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       const char *md_test = "not set";
+       size_t md_test_len = 7;
+       int i;
+       static const char * imd_test_keys[8] = {
+               "server:",
+               "content-security-policy:",
+               "strict-transport-security:",
+               "test-custom-header:",
+               "x-xss-protection:",
+               "x-content-type-options:",
+               "x-frame-options:",
+               "x-non-exist:",
+               };
+#endif
+
+       lwsl_ss_user(m->ss, "%s (%d), ord 0x%x",
+                 lws_ss_state_name((int)state), state, (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_CONNECTING:
+               lws_ss_start_timeout(m->ss, timeout_ms);
+
+               if (lws_ss_set_metadata(m->ss, "uptag", "myuptag123", 10))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+#if !defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+               if (lws_ss_set_metadata(m->ss, "ctype", "myctype", 7))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+#else
+               if (lws_ss_set_metadata(m->ss, "X-Test-Type1:", "myctype1", 8))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+               if (lws_ss_set_metadata(m->ss, "X-Test-Type2:", "myctype2", 8))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+               if (lws_ss_set_metadata(m->ss, "Content-Type:", "myctype", 7))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+#endif
+               break;
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               bad = 2;
+               break;
+
+       case LWSSSCS_CONNECTED:
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       lwsl_cx_user(context, "get direct metadata");
+       for (i = 0; i < 8; i++) {
+               md_test = "not set";
+               lws_ss_get_metadata(m->ss, imd_test_keys[i],
+                                   (const void **)&md_test, &md_test_len);
+               lwsl_ss_user(m->ss, " test key:[%s], got [%s]",
+                                   imd_test_keys[i], md_test);
+       }
+#endif
+               break;
+
+       case LWSSSCS_QOS_ACK_REMOTE: /* transaction assertively succeeded */
+               lwsl_ss_notice(m->ss, "LWSSSCS_QOS_ACK_REMOTE");
+               good++;
+               break; /* disconnected will move us on */
+
+       case LWSSSCS_QOS_NACK_REMOTE: /* transaction assertively failed */
+               lwsl_ss_notice(m->ss, "LWSSSCS_QOS_NACK_REMOTE");
+               break; /* disconnected will move us on */
+
+       case LWSSSCS_DISCONNECTED: /* attempt is over */
+               if (budget)
+                       create_ss(context);
+               else
+                       interrupted = 1;
+               return LWSSSSRET_DESTROY_ME;
+
+       case LWSSSCS_TIMEOUT:
+               lwsl_ss_notice(m->ss, "LWSSSCS_TIMEOUT");
+               bad = 3;
+               if (budget)
+                       create_ss(context);
+               else
+                       interrupted = 1;
+               return LWSSSSRET_DESTROY_ME;
+
+       case LWSSSCS_USER_BASE:
+               lwsl_ss_notice(m->ss, "LWSSSCS_USER_BASE");
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
+static void
+myss_headers_dump(void *userobj, const uint8_t *buf, size_t len, int done)
+{
+       lwsl_cx_user(context, "%lu done: %s", len, done ? "true" : "false");
+
+       lwsl_hexdump_err(buf, len);
+}
+#endif
+
+static int
+create_ss(struct lws_context *cx)
+{
+       lws_ss_info_t ssi;
+
+       budget--;
+       lwsl_cx_notice(cx, "starting");
+
+       /* We're making an outgoing secure stream ourselves */
+
+       memset(&ssi, 0, sizeof(ssi));
+       ssi.handle_offset = offsetof(myss_t, ss);
+       ssi.opaque_user_data_offset = offsetof(myss_t, opaque_data);
+       ssi.rx = myss_rx;
+       ssi.tx = myss_tx;
+       ssi.state = myss_state;
+#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
+       ssi.dump = myss_headers_dump;
+#endif
+       ssi.user_alloc = sizeof(myss_t);
+       ssi.streamtype = test_ots ? "mintest-ots" :
+                        (test_respmap ? "respmap" : "mintest");
+
+       if (lws_ss_create(cx, 0, &ssi, NULL, NULL, NULL, NULL)) {
+               lwsl_cx_err(context, "failed to create ss");
+               return -1;
+       }
+
+       lwsl_cx_notice(cx, "started");
+
+       return 0;
+}
+
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *cx = lws_system_context_from_system_mgr(mgr);
+#if !defined(LWS_SS_USE_SSPC)
+
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+#endif
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+
+#if !defined(LWS_SS_USE_SSPC)
+
+       /*
+        * The proxy takes responsibility for this stuff if we get things
+        * done through that
+        */
+
+       case LWS_SYSTATE_INITIALIZED: /* overlay on the hardcoded policy */
+       case LWS_SYSTATE_POLICY_VALID: /* overlay on the loaded policy */
+
+               if (target != current)
+                       break;
+
+               if (force_cpd_fail_portal)
+
+                       /* this makes it look like we're behind a captive portal
+                        * because the overriden address does a redirect */
+
+                       lws_ss_policy_overlay(context,
+                                     "{\"s\": [{\"captive_portal_detect\": {"
+                                        "\"endpoint\": \"google.com\","
+                                        "\"http_url\": \"/\","
+                                        "\"port\": 80"
+                                     "}}]}");
+
+               if (force_cpd_fail_no_internet)
+
+                       /* this looks like no internet, because the overridden
+                        * port doesn't have anything that will connect to us */
+
+                       lws_ss_policy_overlay(context,
+                                     "{\"s\": [{\"captive_portal_detect\": {"
+                                        "\"endpoint\": \"warmcat.com\","
+                                        "\"http_url\": \"/\","
+                                        "\"port\": 999"
+                                     "}}]}");
+               break;
+
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+
+#endif
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+                       create_ss(cx);
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+#if defined(LWS_WITH_SYS_METRICS)
+
+static int
+my_metric_report(lws_metric_pub_t *mp)
+{
+       lws_metric_bucket_t *sub = mp->u.hist.head;
+       char buf[192];
+
+       do {
+               if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
+                       lwsl_cx_user(context, "%s: %s\n", __func__, buf);
+       } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
+
+       /* 0 = leave metric to accumulate, 1 = reset the metric */
+
+       return 1;
+}
+
+static const lws_system_ops_t system_ops = {
+       .metric_report = my_metric_report,
+};
+
+#endif
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static lws_log_cx_t my_log_cx = {
+       .lll_flags      = LLLF_LOG_CONTEXT_AWARE |
+                         LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER,
+       .refcount_cb    = lws_log_use_cx_file,
+       .u.emit_cx      = lws_log_emit_cx_file,
+};
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       int n = 0, expected = 0, concurrent = 1;
+       char cxname[16], logpath[128];
+       const char *p;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       if ((p = lws_cmdline_option(argc, argv, "-c")))
+               concurrent = atoi(p);
+
+       if (concurrent < 0 || concurrent > 100)
+               return 1;
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               my_log_cx.lll_flags = (uint32_t)(LLLF_LOG_CONTEXT_AWARE | atoi(p));
+
+       lws_strncpy(cxname, "ctx0", sizeof(cxname));
+
+       for (n = 0; n < concurrent - 1; n++) {
+               if (fork()) {
+#if defined(WIN32)
+                       Sleep(1);
+#else
+                       usleep(1000);
+#endif
+                       lws_snprintf(cxname, sizeof(cxname), "ctx%d", n + 1);
+                       break;
+               }
+       }
+
+       /*
+        * Arrange that each process's context logs to a different file
+        */
+
+       info.log_cx = &my_log_cx;
+       info.vhost_name = cxname;
+       lws_snprintf(logpath, sizeof(logpath), "/tmp/%s.log", cxname);
+       my_log_cx.opaque = (void *)logpath;
+
+       lwsl_user("LWS secure streams test client [-d<verb>]\n");
+
+       /* these options are mutually exclusive if given */
+
+       if (lws_cmdline_option(argc, argv, "--force-portal"))
+               force_cpd_fail_portal = 1;
+
+       if (lws_cmdline_option(argc, argv, "--force-no-internet"))
+               force_cpd_fail_no_internet = 1;
+
+       if (lws_cmdline_option(argc, argv, "--respmap"))
+               test_respmap = 1;
+
+       if (lws_cmdline_option(argc, argv, "--ots"))
+               /*
+                * Use a streamtype that relies on the OS trust store for
+                * validation
+                */
+               test_ots = 1;
+
+       if ((p = lws_cmdline_option(argc, argv, "--timeout_ms")))
+               timeout_ms = (unsigned int)atoi(p);
+
+       if ((p = lws_cmdline_option(argc, argv, "--budget")))
+               budget = atoi(p);
+
+       predicted_good = budget;
+       orig_budget = budget;
+
+       if ((p = lws_cmdline_option(argc, argv, "--pass-limit")))
+               predicted_good = atoi(p);
+
+       info.fd_limit_per_thread = 1 + 26 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#else
+       info.pss_policies_json = default_ss_policy;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+#if defined(LWS_WITH_MBEDTLS)
+
+       /* uncomment to force mbedtls to load a system trust store like
+        * openssl does
+        *
+        * info.mbedtls_client_preload_filepath =
+        *              "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem";
+        */
+#endif
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+#if defined(LWS_WITH_SYS_METRICS)
+       info.system_ops = &system_ops;
+       info.metrics_prefix = "ssmex";
+#endif
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               goto bail;
+       }
+
+       /* timeout for each forked process */
+
+       lws_sul_schedule(context, 0, &sul_timeout, process_timeout,
+                        (lws_usec_t)((lws_usec_t)budget *
+                                      (lws_usec_t)timeout_ms * LWS_US_PER_MS));
+
+#if !defined(LWS_SS_USE_SSPC)
+       /*
+        * If we're being a proxied client, the proxy does all this
+        */
+
+       /*
+        * Set the related lws_system blobs
+        *
+        * ...direct_set() sets a pointer, so the thing pointed to has to have
+        * a suitable lifetime, eg, something that already exists on the heap or
+        * a const string in .rodata like this
+        */
+
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_SERIAL, 0),
+                                  (const uint8_t *)"SN12345678", 10);
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION, 0),
+                                  (const uint8_t *)"v0.01", 5);
+
+       /*
+        * ..._heap_append() appends to a buflist kind of arrangement on heap,
+        * just one block is fine, otherwise it will concatenate the fragments
+        * in the order they were appended (and take care of freeing them at
+        * context destroy time). ..._heap_empty() is also available to remove
+        * everything that was already allocated.
+        *
+        * Here we use _heap_append() just so it's tested as well as direct set.
+        */
+
+       lws_system_blob_heap_append(lws_system_get_blob(context,
+                                   LWS_SYSBLOB_TYPE_DEVICE_TYPE, 0),
+                                  (const uint8_t *)"spacerocket", 11);
+#endif
+
+       /* the event loop */
+
+       n = 0;
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_sul_cancel(&sul_timeout);
+       lws_context_destroy(context);
+
+bail:
+       lwsl_user("  good: %d / %d budget, pass limit %d\n", good, orig_budget,
+                       predicted_good);
+       if (good < predicted_good)
+               bad = 1;
+
+       if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
+               expected = atoi(p);
+
+       if (bad == expected) {
+               lwsl_user("Completed: OK (seen expected %d)\n", expected);
+               return 0;
+       } else
+               lwsl_err("Completed: failed: exit %d, expected %d\n", bad, expected);
+
+       return 1;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-testsfail/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cd194e1
--- /dev/null
@@ -0,0 +1,104 @@
+project(lws-minimal-secure-streams-testsfail C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams-testsfail)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams-testsfail.c)
+
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32)
+               if (VALGRIND)
+                       add_test(NAME ss-tf COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-testsfail>)
+               else()
+                       add_test(NAME ss-tf COMMAND lws-minimal-secure-streams-testsfail)
+               endif()
+
+               set_tests_properties(ss-tf
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-testsfail
+                                    TIMEOUT 440)
+
+               if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+                       #
+                       # Define test dep to bring up and take down the test
+                       # proxy
+                       #
+
+                       if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                               # uds abstract namespace for linux
+                               set(CTEST_SOCKET_PATH "@ctest-ssptf-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       else()
+                               # filesystem socket for others
+                               set(CTEST_SOCKET_PATH "/tmp/ctest-ssptf-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       endif()
+                       add_test(NAME st_sstfproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               sstfproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH}  -d1039)
+                       set_tests_properties(st_sstfproxy PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP sstfproxy TIMEOUT 800)
+
+                       add_test(NAME ki_sstfproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                               sstfproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH})
+                       set_tests_properties(ki_sstfproxy PROPERTIES FIXTURES_CLEANUP sstfproxy)
+
+                       #
+                       # the client part that will connect to the proxy
+                       #
+
+                       if (VALGRIND)
+                               add_test(NAME sspc-minimaltf COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-testsfail-client> -i +${CTEST_SOCKET_PATH} -d1039)
+                       else()
+                               add_test(NAME sspc-minimaltf COMMAND lws-minimal-secure-streams-testsfail-client -i +${CTEST_SOCKET_PATH} -d1039)
+                       endif()
+               
+                       set_tests_properties(sspc-minimaltf PROPERTIES
+                               WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-testsfail
+                               FIXTURES_REQUIRED "sstfproxy"
+                               TIMEOUT 440)
+
+               endif()
+
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client minimal-secure-streams-testsfail.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-testsfail/README.md b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/README.md
new file mode 100644 (file)
index 0000000..70a1b0f
--- /dev/null
@@ -0,0 +1,17 @@
+# lws minimal secure streams
+
+The application runs some bulk and failure path tests on Secure Streams
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+--amount <amount>| Set the amount of bulk data expected, eg, --amount 23456
+
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c
new file mode 100644 (file)
index 0000000..7a09523
--- /dev/null
@@ -0,0 +1,890 @@
+/*
+ * lws-minimal-secure-streams
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates various kinds of successful and failed connection
+ * situations in order to confirm the correct states are coming.
+ *
+ * You can control how much bulk data is requested from the peer using
+ * --amount xxx, the default without that is 12345 bytes.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+static int interrupted, tests, tests_pass, tests_fail;
+static lws_sorted_usec_list_t sul_next_test;
+static lws_state_notify_link_t nl;
+struct lws_context *context;
+size_t amount = 12345;
+
+static void
+tests_start_next(lws_sorted_usec_list_t *sul);
+
+/*
+ * If the -proxy app is fulfilling our connection, then we don't need to have
+ * the policy in the client.
+ *
+ * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over
+ * a Unix Domain Socket.  To test that, you need to separately run the
+ * ./lws-minimal-secure-streams-proxy test app on the same machine.
+ */
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+#if defined(VIA_LOCALHOST_SOCKS)
+         "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+#endif
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": [  1000, 1000, 1000, 1000"
+                               "],"
+                       "\"conceal\":"          "4,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+               "{\"isrg_root_x1\": \""
+       "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="
+         "\"},{"
+       "\"digicert_global_root_g2\": \"MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7K"
+       "GSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMR"
+       "GlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDE"
+       "xdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxM"
+       "TUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxG"
+       "TAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb"
+       "2JhbCBSb290IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNN"
+       "Nx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpim"
+       "n7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kq"
+       "bitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauVB"
+       "JVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdz"
+       "XOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FD"
+       "KZJobq7nMWxM4MphQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/"
+       "wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNA"
+       "QELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQ"
+       "oQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98"
+       "kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8"
+       "PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgR"
+       "PTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3f"
+       "e0Dkhvld1927jyNxF1WW6LZZm6zNTflMrY=\""
+       "}, {"
+               "\"digicert_global_ca_g2\": \"MIIEizCCA3OgAwIBAgIQDI7gyQ1"
+       "qiRWIBAYe4kH5rzANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1U"
+       "EChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgY"
+       "DVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0"
+       "yODA4MDExMjAwMDBaMEQxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCB"
+       "JbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEdsb2JhbCBDQSBHMjCCASIwDQYJKoZIhvc"
+       "NAQEBBQADggEPADCCAQoCggEBANNIfL7zBYZdW9UvhU5L4IatFaxhz1uvPmoKR/u"
+       "adpFgC4przc/cV35gmAvkVNlW7SHMArZagV+Xau4CLyMnuG3UsOcGAngLH1ypmTb"
+       "+u6wbBfpXzYEQQGfWMItYNdSWYb7QjHqXnxr5IuYUL6nG6AEfq/gmD6yOTSwyOR2"
+       "Bm40cZbIc22GoiS9g5+vCShjEbyrpEJIJ7RfRACvmfe8EiRROM6GyD5eHn7OgzS+"
+       "8LOy4g2gxPR/VSpAQGQuBldYpdlH5NnbQtwl6OErXb4y/E3w57bqukPyV93t4CTZ"
+       "edJMeJfD/1K2uaGvG/w/VNfFVbkhJ+Pi474j48V4Rd6rfArMCAwEAAaOCAVowggF"
+       "WMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwE"
+       "BBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1U"
+       "dHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEd"
+       "sb2JhbFJvb3RHMi5jcmwwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9"
+       "EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAY"
+       "IKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBY"
+       "EFCRuKy3QapJRUSVpAaqaR6aJ50AgMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq"
+       "5Eu0GF485MA0GCSqGSIb3DQEBCwUAA4IBAQALOYSR+ZfrqoGvhOlaOJL84mxZvzb"
+       "IRacxAxHhBsCsMsdaVSnaT0AC9aHesO3ewPj2dZ12uYf+QYB6z13jAMZbAuabeGL"
+       "J3LhimnftiQjXS8X9Q9ViIyfEBFltcT8jW+rZ8uckJ2/0lYDblizkVIvP6hnZf1W"
+       "ZUXoOLRg9eFhSvGNoVwvdRLNXSmDmyHBwW4coatc7TlJFGa8kBpJIERqLrqwYEle"
+       "sA8u49L3KJg6nwd3jM+/AVTANlVlOnAM2BvjAjxSZnE0qnsHhfTuvcqdFuhOWKU4"
+       "Z0BqYBvQ3lBetoxi6PrABDJXWKTUgNX31EGDk92hiHuwZ4STyhxGs6QiA\""
+       "},"
+       "{\"amazon_root_ca_1\": \"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikP"
+       "mljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1"
+       "hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFo"
+       "XDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjE"
+       "ZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggE"
+       "PADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtO"
+       "gQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peV"
+       "KVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+Uh"
+       "nMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4c"
+       "X8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34Gf"
+       "ID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAU"
+       "wAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7I"
+       "QTgoIMA0GCSqGSIb3DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5"
+       "IpDB/G/wkjUu0yKGX9rbxenDIU5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZ"
+       "ERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2"
+       "V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR"
+       "1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob"
+       "2xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5\"}"
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+               "{"
+                       "\"name\": \"api_amazon_com\","
+                       "\"stack\": [\"digicert_global_ca_g2\", \"digicert_global_root_g2\"]"
+               "}, { \"name\": \"arca1\", \"stack\": [\"amazon_root_ca_1\"]},"
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+         "],"
+         "\"s\": ["
+
+               "{\"api_amazon_com_auth\": {"
+                       "\"endpoint\": \"api.amazon.com\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"POST\","
+                       "\"http_url\": \"auth/o2/token\","
+                       "\"plugins\": [],"
+                       "\"opportunistic\": true,"
+                       "\"tls\": true,"
+                       "\"h2q_oflow_txcr\": true,"
+                       "\"http_www_form_urlencoded\": true,"
+                       "\"http_no_content_length\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"api_amazon_com\""
+               "}},{"
+
+               /*
+                * Just get a 200 from httpbin.org
+                * on h1:80, h1:443 and h2:443
+                *
+                * sanity check that we're working at all
+                */
+
+                   "\"t_h1\": {"
+                       "\"endpoint\": \"httpbin.org\","
+                       "\"port\": 80,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/status/200\","
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\""
+               "}},{"
+                   "\"t_h1_tls\": {"
+                       "\"endpoint\": \"httpbin.org\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/status/200\","
+                       "\"tls\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"arca1\""
+               "}},{"
+                   "\"t_h2_tls\": {"
+                       "\"endpoint\": \"httpbin.org\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h2\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/status/200\","
+                       "\"tls\": true,"
+                       "\"nghttp2_quirk_end_stream\": true,"
+                       "\"h2q_oflow_txcr\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"arca1\""
+               "}},{"
+
+               /*
+                * 10s delayed response from httpbin.org
+                * on h1:80, h1:443 and h2:443
+                *
+                * used to trigger timeout testing
+                */
+
+                   "\"d_h1\": {"
+                       "\"endpoint\": \"httpbin.org\","
+                       "\"port\": 80,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/delay/10\","
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\""
+               "}},{"
+                   "\"d_h1_tls\": {"
+                       "\"endpoint\": \"httpbin.org\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/delay/10\","
+                       "\"tls\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"arca1\""
+               "}},{"
+                   "\"d_h2_tls\": {"
+                       "\"endpoint\": \"httpbin.org\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h2\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/delay/10\","
+                       "\"tls\": true,"
+                       "\"nghttp2_quirk_end_stream\": true,"
+                       "\"h2q_oflow_txcr\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"arca1\""
+               "}},{"
+
+               /*
+                * get NXDOMAIN for bogus.nope
+                * on h1:80, h1:443 and h2:443
+                *
+                * Triggers unreachable and eventually all_retries_failed
+                */
+
+                   "\"nxd_h1\": {"
+                       "\"endpoint\": \"bogus.nope\","
+                       "\"port\": 80,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/status/200\","
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\""
+               "}},{"
+                   "\"nxd_h1_tls\": {"
+                       "\"endpoint\": \"bogus.nope\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/status/200\","
+                       "\"tls\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"arca1\""
+               "}},{"
+                   "\"nxd_h2_tls\": {"
+                       "\"endpoint\": \"bogus.nope\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h2\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/status/200\","
+                       "\"tls\": true,"
+                       "\"nghttp2_quirk_end_stream\": true,"
+                       "\"h2q_oflow_txcr\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"arca1\""
+               "}},{"
+
+               /*
+                * bulk payload transfer from httpbin.org
+                * on h1:80, h1:443 and h2:443
+                *
+                * Sanity check larger payload
+                */
+
+                   "\"bulk_h1\": {"
+                       "\"endpoint\": \"httpbin.org\","
+                       "\"port\": 80,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"range/${amount}\","
+                       "\"metadata\": [{"
+                                       "\"amount\": \"\""
+                               "}],"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\""
+               "}},{"
+                   "\"bulk_h1_tls\": {"
+                       "\"endpoint\": \"httpbin.org\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"range/${amount}\","
+                       "\"metadata\": [{"
+                                       "\"amount\": \"\""
+                               "}],"
+                       "\"tls\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"arca1\""
+               "}},{"
+                   "\"bulk_h2_tls\": {"
+                       "\"endpoint\": \"httpbin.org\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h2\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"range/${amount}\","
+                       "\"metadata\": [{"
+                                       "\"amount\": \"\""
+                               "}],"
+                       "\"tls\": true,"
+                       "\"nghttp2_quirk_end_stream\": true,"
+                       "\"h2q_oflow_txcr\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"arca1\""
+
+               "}},{"
+
+               /*
+                * Various kinds of tls failure
+                *
+                * hostname.badcert.warmcat.com: serves valid cert but for
+                *                               warmcat.com
+                *
+                * warmcat.com:446: serves valid but expired cert
+                *
+                * I don't have an easy way to make the test for "not valid yet"
+                * cert without root
+                *
+                * invalidca.badcert.warmcat.com:  selfsigned cert for that
+                *                                 hostname
+                */
+
+                   "\"badcert_hostname\": {"
+                       "\"endpoint\": \"hostname.badcert.warmcat.com\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/\","
+                       "\"tls\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"le_via_isrg\""
+               "}},{"
+                   "\"badcert_expired\": {"
+                       "\"endpoint\": \"warmcat.com\","
+                       "\"port\": 446,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/\","
+                       "\"tls\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"le_via_isrg\""
+               "}},{"
+                   "\"badcert_selfsigned\": {"
+                       "\"endpoint\": \"invalidca.badcert.warmcat.com\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"/\","
+                       "\"tls\": true,"
+                       "\"nghttp2_quirk_end_stream\": true,"
+                       "\"h2q_oflow_txcr\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"tls_trust_store\": \"le_via_isrg\""
+                "}}"
+       "]}"
+;
+
+#endif
+
+/*
+ * This is the sequence of test streams we are going to create, the ss timeout,
+ * and a description of what we want to see to understand the test passed, or
+ * failed.  If the test hits destruction without making a explicit pass or fail
+ * decision before, that's a fail.  Or, depending on what state we put in
+ * .must_see, we can count a state like UNREACHABLE as a pass.
+ */
+
+struct tests_seq {
+       const char              *name;
+       const char              *streamtype;
+       uint64_t                timeout_us;
+       lws_ss_constate_t       must_see;
+       unsigned int            mask_unexpected;
+       size_t                  eom_pass;
+} tests_seq[] = {
+
+       /*
+        * We just get a 200 from httpbin.org as a sanity check first
+        */
+
+       {
+               "h1:80 just get 200",
+               "t_h1", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE,
+               (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+                                        (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               0
+       },
+       {
+               "h1:443 just get 200",
+               "t_h1_tls", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE,
+               (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+                                        (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               0
+       },
+       {
+               "h2:443 just get 200",
+               "t_h2_tls", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE,
+               (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+                                        (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               0
+       },
+
+       /*
+        * We arranged that the server will delay 10s before sending the
+        * response, but set our ss timeout for 5s.  So we expect to see
+        * our timeout and not an ACK / 200.
+        */
+
+       {
+               "h1:80 timeout after connection",
+               "d_h1", 5 * LWS_US_PER_SEC, LWSSSCS_TIMEOUT,
+               (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+                                        (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               0
+       },
+       {
+               "h1:443 timeout after connection",
+               "d_h1_tls", 5 * LWS_US_PER_SEC, LWSSSCS_TIMEOUT,
+               (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+                                        (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               0
+       },
+       {
+               "h2:443 timeout after connection",
+               "d_h2_tls", 5 * LWS_US_PER_SEC, LWSSSCS_TIMEOUT,
+               (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+                                        (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               0
+       },
+
+       /*
+        * We are talking to a nonexistant dns address "bogus.nope".  We expect
+        * in each case to hear that is unreachable, before any ss timeout.
+        */
+
+       {
+               "h1:80 NXDOMAIN",
+               "nxd_h1", 65 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE,
+               (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+               (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               0
+       },
+       {
+               "h1:443 NXDOMAIN",
+               "nxd_h1_tls", 35 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE,
+               (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+               (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               0
+       },
+       {
+               "h2:443 NXDOMAIN",
+               "nxd_h2_tls", 35 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE,
+               (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+               (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               0
+       },
+
+       /*
+        * We are talking to a nonexistant dns address "bogus.nope".  We expect
+        * that if we stick around longer, retries will also end up all failing.
+        * We might see the timeout depending on blocking getaddrinfo
+        * behaviour.
+        */
+
+       {
+               "h1:80 NXDOMAIN exhaust retries",
+               "nxd_h1", 65 * LWS_US_PER_SEC, LWSSSCS_ALL_RETRIES_FAILED,
+               (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE),
+               0
+       },
+       {
+               "h1:443 NXDOMAIN exhaust retries",
+               "nxd_h1_tls", 65 * LWS_US_PER_SEC, LWSSSCS_ALL_RETRIES_FAILED,
+               (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE),
+               0
+       },
+       {
+               "h2:443 NXDOMAIN exhaust retries",
+               "nxd_h2_tls", 65 * LWS_US_PER_SEC, LWSSSCS_ALL_RETRIES_FAILED,
+               (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE),
+               0
+       },
+
+       /*
+        * Let's request some bulk data from httpbin.org
+        */
+
+       {
+               "h1:80 read bulk",
+               "bulk_h1", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE,
+               (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+               (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               12345
+       },
+       {
+               "h1:443 read bulk",
+               "bulk_h1_tls", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE,
+               (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+               (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               12345
+       },
+       {
+               "h2:443 read bulk",
+               "bulk_h2_tls", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE,
+               (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
+               (1 << LWSSSCS_ALL_RETRIES_FAILED),
+               12345
+       },
+
+       /*
+        * Let's fail at the tls negotiation various ways
+        */
+
+       {
+               "h1:badcert_hostname",
+               "badcert_hostname", 6 * LWS_US_PER_SEC, LWSSSCS_ALL_RETRIES_FAILED,
+               (1 << LWSSSCS_QOS_NACK_REMOTE),
+               0
+       },
+       {
+               "h1:badcert_expired",
+               "badcert_expired", 6 * LWS_US_PER_SEC, LWSSSCS_ALL_RETRIES_FAILED,
+               (1 << LWSSSCS_QOS_NACK_REMOTE),
+               0
+       },
+       {
+               "h1:badcert_selfsigned",
+               "badcert_selfsigned", 6 * LWS_US_PER_SEC, LWSSSCS_ALL_RETRIES_FAILED,
+               (1 << LWSSSCS_QOS_NACK_REMOTE),
+               0
+       },
+
+};
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+
+       size_t                          rx_seen;
+       char                            result_reported;
+} myss_t;
+
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+       myss_t *m = (myss_t *)userobj;
+
+       m->rx_seen += len;
+
+       if (flags & LWSSS_FLAG_EOM)
+               lwsl_notice("%s: %s len %d, fl %d, received %u bytes\n",
+                               __func__, lws_ss_tag(m->ss), (int)len, flags,
+                               (unsigned int)m->rx_seen);
+
+       return 0;
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       //myss_t *m = (myss_t *)userobj;
+
+       /* in this example, we don't send stuff */
+
+       return LWSSSSRET_TX_DONT_SEND;
+}
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+       struct tests_seq *curr_test = ( struct tests_seq *)m->opaque_data;
+       char buf[8];
+       size_t sl;
+
+       lwsl_info("%s: %s: %s (%d), ord 0x%x\n", __func__, lws_ss_tag(m->ss),
+                 lws_ss_state_name((int)state), state, (unsigned int)ack);
+
+       if (curr_test->mask_unexpected & (1u << state)) {
+               /*
+                * We have definitively failed on an unexpected state received
+                */
+
+               lwsl_warn("%s: failing on unexpected state %s\n",
+                               __func__, lws_ss_state_name((int)state));
+
+fail:
+               m->result_reported = 1;
+               tests_fail++;
+               /* we'll start the next test next time around the event loop */
+               lws_sul_schedule(context, 0, &sul_next_test, tests_start_next, 1);
+
+               return LWSSSSRET_OK;
+       }
+
+       if (state == curr_test->must_see) {
+
+               if (curr_test->eom_pass != m->rx_seen) {
+                       lwsl_notice("%s: failing on rx %d, expected %d\n",
+                                   __func__, (int)m->rx_seen,
+                                   (int)curr_test->eom_pass);
+                       goto fail;
+               }
+
+               lwsl_warn("%s: saw expected state %s\n",
+                               __func__, lws_ss_state_name((int)state));
+               m->result_reported = 1;
+               tests_pass++;
+               /* we'll start the next test next time around the event loop */
+               lws_sul_schedule(context, 0, &sul_next_test, tests_start_next, 1);
+
+               return LWSSSSRET_OK;
+       }
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               lws_ss_start_timeout(m->ss,
+                       (unsigned int)(curr_test->timeout_us / LWS_US_PER_MS));
+               if (curr_test->eom_pass) {
+                       sl = (size_t)lws_snprintf(buf, sizeof(buf), "%u",
+                                       (unsigned int)curr_test->eom_pass);
+                       if (lws_ss_set_metadata(m->ss, "amount", buf, sl))
+                               return LWSSSSRET_DISCONNECT_ME;
+               }
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_DESTROYING:
+               if (!m->result_reported) {
+                       lwsl_user("%s: failing on unexpected destruction\n",
+                                       __func__);
+
+                       tests_fail++;
+                       /* we'll start the next test next time around the event loop */
+                       lws_sul_schedule(context, 0, &sul_next_test, tests_start_next, 1);
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static void
+tests_start_next(lws_sorted_usec_list_t *sul)
+{
+       struct tests_seq *ts;
+       lws_ss_info_t ssi;
+       static struct lws_ss_handle *h;
+
+       /* destroy the old one */
+
+       if (h) {
+               lwsl_info("%s: destroying previous stream\n", __func__);
+               lws_ss_destroy(&h);
+       }
+
+       if ((unsigned int)tests >= LWS_ARRAY_SIZE(tests_seq)) {
+               lwsl_notice("Completed all tests\n");
+               interrupted = 1;
+               return;
+       }
+
+       ts = &tests_seq[tests++];
+
+       /* Create the next test stream */
+
+       memset(&ssi, 0, sizeof(ssi));
+       ssi.handle_offset = offsetof(myss_t, ss);
+       ssi.opaque_user_data_offset = offsetof(myss_t, opaque_data);
+       ssi.rx = myss_rx;
+       ssi.tx = myss_tx;
+       ssi.state = myss_state;
+       ssi.user_alloc = sizeof(myss_t);
+       ssi.streamtype = ts->streamtype;
+
+       lwsl_user("%s: %d: %s\n", __func__, tests, ts->name);
+
+       if (lws_ss_create(context, 0, &ssi, ts, &h, NULL, NULL)) {
+               lwsl_err("%s: failed to create secure stream\n",
+                        __func__);
+               tests_fail++;
+               interrupted = 1;
+               return;
+       }
+}
+
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       switch (target) {
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL)
+                       /* we'll start the next test next time around the event loop */
+                       lws_sul_schedule(context, 0, &sul_next_test, tests_start_next, 1);
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+#if defined(LWS_WITH_SYS_METRICS)
+static int
+my_metric_report(lws_metric_pub_t *mp)
+{
+       lws_metric_bucket_t *sub = mp->u.hist.head;
+       char buf[192];
+
+       do {
+               if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
+                       lwsl_user("%s: %s\n", __func__, buf);
+       } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
+
+       /* 0 = leave metric to accumulate, 1 = reset the metric */
+
+       return 1;
+}
+
+static const lws_system_ops_t system_ops = {
+       .metric_report = my_metric_report,
+};
+
+#endif
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int
+main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       const char *pp;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       if ((pp = lws_cmdline_option(argc, argv, "--amount")))
+               amount = (size_t)atoi(pp);
+
+       /* set the expected payload for the bulk-related tests to amount */
+
+       tests_seq[12].eom_pass = tests_seq[13].eom_pass =
+                                       tests_seq[14].eom_pass = amount;
+#if !defined(LWS_SS_USE_SSPC)
+       // puts(default_ss_policy);
+#endif
+
+       lwsl_user("LWS secure streams error path tests [-d<verb>]\n");
+
+       info.fd_limit_per_thread = 1 + 16 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#else
+       info.pss_policies_json = default_ss_policy;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+#if defined(LWS_WITH_SYS_METRICS)
+       info.system_ops = &system_ops;
+#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
+       info.metrics_prefix = "ssmex";
+#endif
+#endif
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* the event loop */
+
+       do { } while(lws_service(context, 0) >= 0 && !interrupted);
+
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: %s (pass %d, fail %d)\n",
+                 tests_pass == tests && !tests_fail ? "OK" : "failed",
+                                 tests_pass, tests_fail);
+
+       return !(tests_pass == tests && !tests_fail);
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-threads/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-threads/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5272d8f
--- /dev/null
@@ -0,0 +1,130 @@
+project(lws-minimal-secure-streams-threads C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(requirements 1)
+require_pthreads(requirements)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SYS_SMD 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+if (requirements AND NOT WIN32)
+# win32 has problems with pthreads.h and timespec struct redef
+       add_executable(${PROJECT_NAME} minimal-secure-streams-threads.c)
+
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32)
+
+               if (VALGRIND)
+                       add_test(NAME ss-threads COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-threads>)
+               else()
+
+                       add_test(NAME ss-threads COMMAND lws-minimal-secure-streams-threads)
+               endif()
+               set_tests_properties(ss-threads
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-threads
+                                    TIMEOUT 10)
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${PROJECT_NAME} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${PROJECT_NAME} websockets_shared)
+       else()
+               target_link_libraries(${PROJECT_NAME} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${PROJECT_NAME}-client minimal-secure-streams-threads.c)
+
+               if (websockets_shared)
+                       target_link_libraries(${PROJECT_NAME}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${PROJECT_NAME}-client websockets_shared)
+               else()
+                       target_link_libraries(${PROJECT_NAME}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+
+               #
+               # Define test dep to bring up and take down the test
+               # proxy
+               #
+
+               if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                       # uds abstract namespace for linux
+                       set(CTEST_SOCKET_PATH "@ctest-sspthreads_sspc-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               else()
+                       # filesystem socket for others
+                       set(CTEST_SOCKET_PATH "/tmp/ctest-sspthreads_sspc-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               endif()
+
+               add_test(NAME st_ssprxthreads_sspc COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                       ssproxythreads_sspc $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH}  -d1039)
+               set_tests_properties(st_ssprxthreads_sspc PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP ssproxythreads_sspc TIMEOUT 800)
+
+               add_test(NAME ki_ssprxthreads_sspc COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                       ssproxythreads_sspc $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH}  -d1039)
+               set_tests_properties(ki_ssprxthreads_sspc PROPERTIES FIXTURES_CLEANUP ssproxythreads_sspc)
+
+               #
+               # the client part that will connect to the proxy
+               #
+
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME sspcthreads_sspc COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams-threads-client> -i +${CTEST_SOCKET_PATH})
+               else()
+                       add_test(NAME sspcthreads_sspc COMMAND lws-minimal-secure-streams-threads-client -i +${CTEST_SOCKET_PATH})
+               endif()
+               set_tests_properties(sspcthreads_sspc PROPERTIES
+                       WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-threads
+                       FIXTURES_REQUIRED "ssproxythreads_sspc"
+                       TIMEOUT 80)
+
+
+               #
+               # Define test dep to bring up and take down the test
+               # proxy
+               #
+
+               if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                       # uds abstract namespace for linux
+                       set(CTEST_SOCKET_PATH "@ctest-mul-sspthreads_sspc-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               else()
+                       # filesystem socket for others
+                       set(CTEST_SOCKET_PATH "/tmp/ctest-mul-sspthreads_sspc-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+               endif()
+
+               add_test(NAME st_mulssprxthreads_sspc COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                       mulssproxythreads_sspc $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH}  -d1039)
+               set_tests_properties(st_mulssprxthreads_sspc PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP mulssproxythreads_sspc TIMEOUT 800)
+
+               add_test(NAME ki_mulssprxthreads_sspc COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                       mulssproxythreads_sspc $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                       -i ${CTEST_SOCKET_PATH}  -d1039)
+               set_tests_properties(ki_mulssprxthreads_sspc PROPERTIES FIXTURES_CLEANUP mulssproxythreads_sspc)
+
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-threads/README.md b/minimal-examples/secure-streams/minimal-secure-streams-threads/README.md
new file mode 100644 (file)
index 0000000..3f4cb1d
--- /dev/null
@@ -0,0 +1,27 @@
+# lws minimal secure streams threads
+
+This application creates a thread and calls `lws_cancel_service()`
+at 10Hz.
+
+It creates a Secure Stream and checks that it is getting the
+`LWSSSCS_EVENT_WAIT_CANCELLED` state for each `lws_cancel_service()`.
+
+It also demonstrates how to protect a shared data area between the
+thread(s) and the lws event loop thread to put data there that
+describes what the thread wants the service loop to do.
+
+It exits after 3s with a 0 return code if the SS saw the expected
+amount of messages.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-threads/minimal-secure-streams-threads.c b/minimal-examples/secure-streams/minimal-secure-streams-threads/minimal-secure-streams-threads.c
new file mode 100644 (file)
index 0000000..bc4d42f
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * lws-minimal-secure-streams-threads
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates how other threads can wake the lws event loop and ask it
+ * to do things via lws_cancel_service(), notifying Secure Streams using the
+ * LWSSSCS_EVENT_WAIT_CANCELLED state callback.
+ *
+ * Because of what we're testing, we don't actually connect the SS just create
+ * it and wait for the states we are testing for to come at 10Hz.
+ *
+ * We run the test for 3s and check we got an appropriate amount of wakes
+ * to call it a success.
+ *
+ * You can use the same pattern to have any amount of shared data protected by
+ * the mutex, containing whatever the other threads want the lws event loop
+ * thread to do for them.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+#include <pthread.h>
+
+/*
+ * Define this to cause an ss api access from a foreign thread, it will
+ * assert.  This is for testing lws, don't do this in your code.
+ */
+// #define DO_ILLEGAL_API_THREAD
+
+static int interrupted, bad = 1, finished;
+static lws_sorted_usec_list_t sul_timeout;
+static struct lws_context *context;
+static pthread_t pthread_spam;
+static int wakes, started_thread;
+
+#if defined(DO_ILLEGAL_API_THREAD)
+static struct lws_ss_handle *ss; /* only needed for DO_ILLEGAL_API_THREAD */
+#endif
+
+/* the data shared between the spam thread and the lws event loop */
+
+static pthread_mutex_t lock_shared;
+static int shared_counter;
+
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+               "\"schema-version\":1,"
+               "\"s\": ["
+                       "{"
+                               "\"mintest\": {"
+                                       "\"endpoint\": \"connectivitycheck.android.com\","
+                                       "\"http_url\": \"generate_204\","
+                                       "\"port\": 80,"
+                                       "\"protocol\": \"h1\","
+                                       "\"http_method\": \"GET\","
+                                       "\"opportunistic\": true,"
+                                       "\"http_expect\": 204,"
+                                       "\"http_fail_redirect\": true"
+                               "}"
+                       "}"
+               "]"
+       "}"
+;
+
+#endif
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+} myss_t;
+
+static void *
+thread_spam(void *d)
+{
+
+       do {
+               pthread_mutex_lock(&lock_shared); /* --------- shared lock { */
+
+               /*
+                * prepare the shared data area to indicate whatever it is that
+                * we want doing on the main event loop.  In this case, we just
+                * bump a counter, but it can be any amount of data prepared,
+                * eg, whole info struct for a connection we want.
+                */
+
+               shared_counter++;
+
+               lwsl_notice("%s: cancelling wait from spam thread: %d\n",
+                               __func__, shared_counter);
+               lws_cancel_service(context);
+
+#if defined(DO_ILLEGAL_API_THREAD)
+               /*
+                * ILLEGAL...
+                * We cannot call any other lws api from a foreign thread
+                */
+
+               if (ss)
+                       lws_ss_request_tx(ss);
+#endif
+
+               pthread_mutex_unlock(&lock_shared); /* } shared lock ------- */
+
+               usleep(100000); /* wait 100ms and signal main thread again */
+
+       } while (!finished);
+
+       pthread_exit(NULL);
+
+       return NULL;
+}
+
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *h_src, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       // myss_t *m = (myss_t *)userobj;
+       void *retval;
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               if (pthread_create(&pthread_spam, NULL, thread_spam, NULL)) {
+                       lwsl_err("thread creation failed\n");
+                       return LWSSSSRET_DESTROY_ME;
+               }
+               started_thread = 1;
+               break;
+       case LWSSSCS_DESTROYING:
+               finished = 1;
+               if (started_thread)
+                       pthread_join(pthread_spam, &retval);
+               break;
+
+       case LWSSSCS_EVENT_WAIT_CANCELLED:
+               pthread_mutex_lock(&lock_shared); /* --------- shared lock { */
+               lwsl_notice("%s: LWSSSCS_EVENT_WAIT_CANCELLED: %d, shared: %d\n",
+                           __func__, ++wakes, shared_counter);
+               pthread_mutex_unlock(&lock_shared); /* } shared lock ------- */
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static const lws_ss_info_t ssi_lws_threads = {
+       .handle_offset            = offsetof(myss_t, ss),
+       .opaque_user_data_offset  = offsetof(myss_t, opaque_data),
+       /* we don't actually do any rx or tx in this test */
+       .state                    = myss_state,
+       .user_alloc               = sizeof(myss_t),
+       .streamtype               = "mintest",
+       .manual_initial_tx_credit = 0,
+};
+
+static void
+sul_timeout_cb(lws_sorted_usec_list_t *sul)
+{
+       lwsl_notice("%s: test finishing\n", __func__);
+       interrupted = 1;
+}
+
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                  int current, int target)
+{
+       if (current != LWS_SYSTATE_OPERATIONAL || target != LWS_SYSTATE_OPERATIONAL)
+               return 0;
+
+       /* the test SS.. not going to connect it, just see if the cancel_service
+        * messages are coming
+        */
+
+       if (lws_ss_create(context, 0, &ssi_lws_threads, NULL,
+#if defined(DO_ILLEGAL_API_THREAD)
+                       &ss,
+#else
+                       NULL,
+#endif
+                       NULL, NULL)) {
+               lwsl_err("%s: failed to create secure stream\n",
+                        __func__);
+
+               return -1;
+       }
+
+       /* set up the test timeout */
+
+       lws_sul_schedule(context, 0, &sul_timeout, sul_timeout_cb,
+                        3 * LWS_US_PER_SEC);
+
+       return 0;
+}
+
+int main(int argc, const char **argv)
+{
+       lws_state_notify_link_t notifier = { { NULL, NULL, NULL},
+                                            system_notify_cb, "app" };
+       lws_state_notify_link_t *na[] = { &notifier, NULL };
+       struct lws_context_creation_info info;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS Secure Streams threads test client [-d<verb>]\n");
+
+       info.fd_limit_per_thread        = 1 + 6 + 1;
+       info.port                       = CONTEXT_PORT_NO_LISTEN;
+#if !defined(LWS_SS_USE_SSPC)
+       info.pss_policies_json          = default_ss_policy;
+#else
+       info.protocols                  = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#endif
+       info.options                    = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                                         LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.register_notifier_list = na;
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+#if defined(LWS_SS_USE_SSPC)
+       if (!lws_create_vhost(context, &info)) {
+               lwsl_err("%s: failed to create default vhost\n", __func__);
+               goto bail;
+       }
+#endif
+
+       /* the event loop */
+
+       while (lws_service(context, 0) >= 0 && !interrupted)
+               ;
+
+       /* compare what happened with what we expect */
+
+       if (wakes > 10)
+               /* OSX can do the usleep thread slower than 100ms */
+               bad = 0;
+
+       lwsl_notice("wakes %d\n", wakes);
+
+#if defined(LWS_SS_USE_SSPC)
+bail:
+#endif
+       lws_sul_cancel(&sul_timeout);
+       lws_context_destroy(context);
+
+       lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
+
+       return bad;
+}
diff --git a/minimal-examples/secure-streams/minimal-secure-streams/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7f576ed
--- /dev/null
@@ -0,0 +1,165 @@
+project(lws-minimal-secure-streams C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-secure-streams)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_H1 1 requirements)
+require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
+require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
+
+require_lws_config(LWS_WITH_SYS_FAULT_INJECTION 1 has_fault_injection)
+
+if (requirements)
+       add_executable(${SAMP} minimal-secure-streams.c)
+
+       find_program(VALGRIND "valgrind")
+
+       if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32)
+       
+               #
+               # When running in CI, wait for a lease on the resources
+               # before starting this test, so the server does not get
+               # thousands of simultaneous tls connection attempts
+               #
+               # sai-resource holds the lease on the resources until
+               # the time given in seconds or the sai-resource instance
+               # exits, whichever happens first
+               #
+               # If running under Sai, creates a lock test called "res_sspcmin" 
+               #
+               
+               sai_resource(warmcat_conns 1 40 sspcmin)
+               
+               #
+               # simple test not via proxy
+               #
+       
+               if (VALGRIND)
+                       message("testing via valgrind")
+                       add_test(NAME ss-warmcat COMMAND
+                               ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                               $<TARGET_FILE:lws-minimal-secure-streams>)
+               else()
+                       add_test(NAME ss-warmcat COMMAND lws-minimal-secure-streams)
+               endif()
+
+               set_tests_properties(ss-warmcat
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams
+                                    TIMEOUT 40)
+               if (DEFINED ENV{SAI_OVN})
+                       set_tests_properties(ss-warmcat PROPERTIES FIXTURES_REQUIRED "res_sspcmin")                  
+               endif()
+
+               if (has_fault_injection)
+                       if (VALGRIND)
+                               add_test(NAME ss-warmcat-fi1 COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams>
+                                       --fault-injection "ss/ss_create_destroy_me"
+                                       --expected-exit 1)
+                               add_test(NAME ss-warmcat-fi2 COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams>
+                                       --fault-injection "ss/ss_no_streamtype_policy"
+                                       --expected-exit 1)
+                       else()
+                               add_test(NAME ss-warmcat-fi1 COMMAND lws-minimal-secure-streams
+                                        --fault-injection "ss/ss_create_destroy_me"
+                                        --expected-exit 1)
+                               add_test(NAME ss-warmcat-fi2 COMMAND lws-minimal-secure-streams
+                                        --fault-injection "ss/ss_no_streamtype_policy"
+                                        --expected-exit 1)
+                        endif()
+
+                       set_tests_properties(ss-warmcat-fi1
+                                            ss-warmcat-fi2
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams
+                                    TIMEOUT 5)
+
+               endif()
+
+
+               if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+                       #
+                       # Define test dep to bring up and take down the test
+                       # proxy
+                       #
+
+                       if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+                               # uds abstract namespace for linux
+                               set(CTEST_SOCKET_PATH "@ctest-ssp-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       else()
+                               # filesystem socket for others
+                               set(CTEST_SOCKET_PATH "/tmp/ctest-ssp-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}")
+                       endif()
+                       add_test(NAME st_ssproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                               ssproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH} )
+                       set_tests_properties(st_ssproxy PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP ssproxy TIMEOUT 800)
+
+                       add_test(NAME ki_ssproxy COMMAND
+                               ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                               ssproxy $<TARGET_FILE:lws-minimal-secure-streams-proxy>
+                               -i ${CTEST_SOCKET_PATH})
+                       set_tests_properties(ki_ssproxy PROPERTIES FIXTURES_CLEANUP ssproxy)
+
+                       #
+                       # the client part that will connect to the proxy
+                       #
+
+                       if (VALGRIND)
+                               message("testing via valgrind")
+                               add_test(NAME sspc-minimal COMMAND
+                                       ${VALGRIND} --tool=memcheck --leak-check=yes --num-callers=20
+                                       $<TARGET_FILE:lws-minimal-secure-streams-client> -i +${CTEST_SOCKET_PATH})
+                       else()
+                               add_test(NAME sspc-minimal COMMAND lws-minimal-secure-streams-client -i +${CTEST_SOCKET_PATH})
+                       endif()
+                       
+                       set(fixlist "ssproxy")
+                       if (DEFINED ENV{SAI_OVN})
+                               list(APPEND fixlist "res_ssproxy")
+                       endif()
+                       
+                       set_tests_properties(sspc-minimal PROPERTIES
+                               WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams
+                               FIXTURES_REQUIRED "${fixlist}"
+                               TIMEOUT 40)
+
+               endif()
+
+       endif()
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+
+       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API)
+
+       if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API)
+               add_compile_options(-DLWS_SS_USE_SSPC)
+
+               add_executable(${SAMP}-client minimal-secure-streams.c)
+               if (websockets_shared)
+                       target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP}-client websockets_shared)
+               else()
+                       target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+       endif()
+
+endif()
diff --git a/minimal-examples/secure-streams/minimal-secure-streams/README.md b/minimal-examples/secure-streams/minimal-secure-streams/README.md
new file mode 100644 (file)
index 0000000..78f0a1b
--- /dev/null
@@ -0,0 +1,67 @@
+# lws minimal secure streams
+
+The application goes to https://warmcat.com and reads index.html there.
+
+It does it using Secure Streams... the main code in minimal-secure-streams.c
+just sets up the context and opens a secure stream of type "mintest".
+
+The handler for state changes and payloads for "mintest" is in ss-myss.c
+
+The information about how a "mintest" stream should connect and the
+protocol it uses is kept separated in policy-database.c
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## usage
+
+Commandline option|Meaning
+---|---
+-d <loglevel>|Debug verbosity in decimal, eg, -d15
+-f| Force connecting to the wrong endpoint to check backoff retry flow
+-p| Run as proxy server for clients to connect to over unix domain socket
+--force-portal|Force the SS Captive Portal Detection to feel it's behind a portal
+--force-no-internet|Force the SS Captive Portal Detection to feel it can't reach the internet
+--blob|Download a 50MiB blob from warmact.com, using flow control at the proxy
+
+```
+[2019/08/12 07:16:11:0045] USR: LWS minimal secure streams [-d<verbosity>] [-f]
+[2019/08/12 07:16:12:6102] USR: myss_state: LWSSSCS_CREATING, ord 0x0
+[2019/08/12 07:16:12:6107] USR: myss_state: LWSSSCS_POLL, ord 0x0
+[2019/08/12 07:16:12:6117] N: lws_ss_client_connect: connecting h1get warmcat.com /
+[2019/08/12 07:16:12:6118] USR: myss_state: LWSSSCS_CONNECTING, ord 0x0
+[2019/08/12 07:16:13:4171] USR: myss_state: LWSSSCS_CONNECTED, ord 0x0
+[2019/08/12 07:16:13:4222] USR: myss_rx: len 1024, flags: 1
+[2019/08/12 07:16:13:4243] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4244] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4244] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4245] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4246] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4247] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4252] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4264] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4265] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4266] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4267] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4268] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4268] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4269] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4270] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4278] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4279] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4280] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4281] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4282] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4283] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4283] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4284] USR: myss_rx: len 1015, flags: 0
+[2019/08/12 07:16:13:4287] USR: myss_rx: len 1024, flags: 0
+[2019/08/12 07:16:13:4288] USR: myss_rx: len 947, flags: 0
+[2019/08/12 07:16:13:4293] USR: myss_rx: len 0, flags: 2
+[2019/08/12 07:16:13:4399] USR: myss_state: LWSSSCS_DISCONNECTED, ord 0x0
+[2019/08/12 07:16:13:4761] USR: myss_state: LWSSSCS_DESTROYING, ord 0x0
+[2019/08/12 07:16:13:4781] USR: Completed: OK
+```
diff --git a/minimal-examples/secure-streams/minimal-secure-streams/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams/minimal-secure-streams.c
new file mode 100644 (file)
index 0000000..260ec50
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * lws-minimal-secure-streams
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ *
+ * This demonstrates a minimal http client using secure streams api.
+ *
+ * It visits https://warmcat.com/ and receives the html page there.
+ *
+ * This example is built two different ways from the same source... one includes
+ * the policy everything needed to fulfil the stream directly.  The other -client
+ * variant has no policy itself and some other minor init changes, and connects
+ * to the -proxy example to actually get the connection done.
+ *
+ * In the -client build case, the example does not even init the tls libraries
+ * since the proxy part will take care of all that.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+// #define FORCE_OS_TRUST_STORE
+
+/*
+ * uncomment to force network traffic through 127.0.0.1:1080
+ *
+ * On your local machine, you can run a SOCKS5 proxy like this
+ *
+ * $ ssh -N -D 0.0.0.0:1080 localhost -v
+ *
+ * If enabled, this also fetches a remote policy that also
+ * specifies that all traffic should go through the remote
+ * proxy.
+ */
+// #define VIA_LOCALHOST_SOCKS
+
+static int interrupted, bad = 1, force_cpd_fail_portal,
+          force_cpd_fail_no_internet, test_respmap, test_ots, test_local;
+static unsigned int timeout_ms = 3000;
+static lws_state_notify_link_t nl;
+
+/*
+ * If the -proxy app is fulfilling our connection, then we don't need to have
+ * the policy in the client.
+ *
+ * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over
+ * a Unix Domain Socket.  To test that, you need to separately run the
+ * ./lws-minimal-secure-streams-proxy test app on the same machine.
+ */
+
+#if !defined(LWS_SS_USE_SSPC)
+static const char * const default_ss_policy =
+       "{"
+         "\"release\":"                        "\"01234567\","
+         "\"product\":"                        "\"myproduct\","
+         "\"schema-version\":"                 "1,"
+#if defined(VIA_LOCALHOST_SOCKS)
+         "\"via-socks5\":"                     "\"127.0.0.1:1080\","
+#endif
+
+         "\"retry\": ["        /* named backoff / retry strategies */
+               "{\"default\": {"
+                       "\"backoff\": ["         "1000,"
+                                                "2000,"
+                                                "3000,"
+                                                "5000,"
+                                               "10000"
+                               "],"
+                       "\"conceal\":"          "5,"
+                       "\"jitterpc\":"         "20,"
+                       "\"svalidping\":"       "30,"
+                       "\"svalidhup\":"        "35"
+               "}}"
+         "],"
+         "\"certs\": [" /* named individual certificates in BASE64 DER */
+               /*
+                * Let's Encrypt certs for warmcat.com / libwebsockets.org
+                *
+                * We fetch the real policy from there using SS and switch to
+                * using that.
+                */
+#if !defined(FORCE_OS_TRUST_STORE)
+                       "{\"isrg_root_x1\": \""
+       "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="
+               "\"}"
+#endif
+         "],"
+         "\"trust_stores\": [" /* named cert chains */
+#if !defined(FORCE_OS_TRUST_STORE)
+               "{"
+                       "\"name\": \"le_via_isrg\","
+                       "\"stack\": ["
+                               "\"isrg_root_x1\""
+                       "]"
+               "}"
+#endif
+         "],"
+         "\"s\": ["
+#if !defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+               /*
+                * "fetch_policy" decides from where the real policy
+                * will be fetched, if present.  Otherwise the initial
+                * policy is treated as the whole, hardcoded, policy.
+                */
+               "{\"fetch_policy\": {"
+                       "\"endpoint\":"         "\"warmcat.com\","
+                       "\"port\":"             "443,"
+                       "\"protocol\":"         "\"h1\","
+                       "\"http_method\":"      "\"GET\","
+#if defined(VIA_LOCALHOST_SOCKS)
+                       "\"http_url\":"         "\"policy/minimal-proxy-socks.json\","
+#else
+                       "\"http_url\":"         "\"policy/minimal-proxy-v4.2-v2.json\","
+#endif
+                       "\"tls\":"              "true,"
+                       "\"opportunistic\":"    "true,"
+#if !defined(FORCE_OS_TRUST_STORE)
+                       "\"tls_trust_store\":"  "\"le_via_isrg\","
+#endif
+                       "\"retry\":"            "\"default\""
+#else
+       "{\"mintest\": {"
+                       "\"endpoint\":  \"warmcat.com\","
+                       "\"port\": 443,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"http_url\": \"index.html?uptag=${uptag}\","
+                       "\"metadata\": [{"
+                       "       \"uptag\": \"X-Upload-Tag:\""
+                       "}, {"
+                       "       \"xctype\": \"X-Content-Type:\""
+                       "}],"
+                       "\"tls\": true,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"timeout_ms\": 2000,"
+                       "\"direct_proto_str\": true,"
+                       "\"tls_trust_store\": \"le_via_dst\""
+               "}},"
+       "{\"mintest_local\": {"
+                       "\"endpoint\":  \"localhost\","
+                       "\"port\": 8000,"
+                       "\"protocol\": \"h1\","
+                       "\"http_method\": \"GET\","
+                       "\"tls\": false,"
+                       "\"opportunistic\": true,"
+                       "\"retry\": \"default\","
+                       "\"timeout_ms\": 2000,"
+                       "\"direct_proto_str\": true"
+#endif
+               "}},{"
+                       /*
+                        * "captive_portal_detect" describes
+                        * what to do in order to check if the path to
+                        * the Internet is being interrupted by a
+                        * captive portal.  If there's a larger policy
+                        * fetched from elsewhere, it should also include
+                        * this since it needs to be done at least after
+                        * every DHCP acquisition
+                        */
+                   "\"captive_portal_detect\": {"
+                        "\"endpoint\": \"connectivitycheck.android.com\","
+                       "\"http_url\": \"generate_204\","
+                       "\"port\": 80,"
+                        "\"protocol\": \"h1\","
+                        "\"http_method\": \"GET\","
+                        "\"opportunistic\": true,"
+                        "\"http_expect\": 204,"
+                       "\"http_fail_redirect\": true"
+                "}}"
+       "]}"
+;
+
+#endif
+
+typedef struct myss {
+       struct lws_ss_handle            *ss;
+       void                            *opaque_data;
+       /* ... application specific state ... */
+       lws_sorted_usec_list_t          sul;
+       size_t                          amt;
+
+       struct lws_genhash_ctx          hash_ctx;
+} myss_t;
+
+#if !defined(LWS_SS_USE_SSPC)
+
+static const char *canned_root_token_payload =
+       "grant_type=refresh_token"
+       "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg"
+       "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP"
+       "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y"
+       "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW"
+       "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE"
+       "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S"
+       "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc"
+       "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI"
+       "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13"
+       "&client_id="
+               "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d";
+
+#endif
+
+/* secure streams payload interface */
+
+static lws_ss_state_return_t
+myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+
+       if (flags & LWSSS_FLAG_PERF_JSON)
+               return LWSSSSRET_OK;
+
+#if !defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       myss_t *m = (myss_t *)userobj;
+       const char *md_srv = "not set", *md_test = "not set";
+       size_t md_srv_len = 7, md_test_len = 7;
+
+       lws_ss_get_metadata(m->ss, "srv", (const void **)&md_srv, &md_srv_len);
+       lws_ss_get_metadata(m->ss, "test", (const void **)&md_test, &md_test_len);
+       lwsl_user("%s: len %d, flags: %d, srv: %.*s, test: %.*s\n", __func__,
+                 (int)len, flags, (int)md_srv_len, md_srv,
+                 (int)md_test_len, md_test);
+
+       lwsl_hexdump_info(buf, len);
+#endif
+
+       /*
+        * If we received the whole message, for our example it means
+        * we are done.
+        */
+       if (flags & LWSSS_FLAG_EOM) {
+               bad = 0;
+               interrupted = 1;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
+myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
+       int *flags)
+{
+       //myss_t *m = (myss_t *)userobj;
+
+       /* in this example, we don't send stuff */
+
+       return LWSSSSRET_TX_DONT_SEND;
+}
+
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+static const char * long_token_str = "{xxx:AWlKJMMISWJBQpAFqU0UqKNsnSY5usx2YtjOZJUQALNtapRxu/9VJqMk5IFVhxrNvMTj+RCGN6B5OlUK80lbbC8fAmQi7SoFB8DHN9UCRHkENriC62FjMNiBVfgkjMWx+60GioZy4bI2kCcyisd2CujQuSVllUmQFXhVq291cJhFfcKR4c3CUCuhouUfK2e1BY5InDMnzUXozOh+vhjJSeBIfp4HRUAgMpV7FXlHy8D5tgbmPbHs9X81MEsHTcERd3pG10B5fu1PzH+dJbr5F2WTK+VFWZI99B89ijEZWsPg447IK3F+0HHGseZfpRjKw2bY94id/TmncTxS0cqchDJlYg+Jt33U4HkUPqLdRiGIfJb6wSATx4S9ZKUumeJAgXpC6ytlUeqPpxzgnD7Tle5CDVb+eVzRk2FJfjiZdjbYxXhWYntPusLP/PGrorkqLw0ZKw+OJ+fhbkwF+0SCUelWEc8WPtfxCDAIdEQ7X5P4vUlBNEfuHprgHbZry680syFetY2q3ZtCmWemLHhqdDGu4lFgcQPCbb9b8eOE8oAbUQPm9AeV84RXSLevBG44JST/W2JuYguOk8SFlsRkfHb3dvxfB15Lg+mtH0tGRoumSMT0CFJL4ClTiKdpJo1LPgEd2/f13GcukEWirjqDRxpepJYWaVAMbxbaPBNfRHw9S8Fn8qU9/9eAxmbEqOopep5I/Zd99CT2PdE0Qyami1p05/BEc5dgvjg3SNDmAc/8kWC0AcvoSfApXI1TaVzbNh68b79h6IaIvXXorY5274u0lVB357JIRiYo29QbJgNn4bDbIr5ScM8GnFHQdKy29/TZoq4zbGMPX2X2t41vXRVeoZteu7vNWsMQD6eIomVq9qFWnoEEaR30woGF+8ZSIEu9JH5LKVZVFx46lipnjE8CDt5qrYCjwiGIswdLLMmIltxRmDt4aefTFpre7lhgUChv7ndJARvsn8rvtg2Hg1qKyfCAHa/LBblM29cRjLFqp7tWLJO7N27SWiqEhai6pmSmSYzqoPL+rnLS69rkdIuUwkA==}{yyy:jG8akvr66AXK+W1KSUyGIN3Yk4WNRLSIZHWTu8rsvQAuKwv9a/ZxrxIa+R1xW7cwmPSgINcJ4Jo7kGK9n7aDnsSDt3uMSHsu2iNg+UtIaJcO0XO6fPaLmOPLpOIU5AfG9HnbWUjeniNRrUGN8+26JH/9EB1h/X++Ow61CCHm8mKrgR1lXsKuNyqDYIrjoI3KCCVKZkdWygyFAXQ6l0sr+pUyNpv6H5w1xlC8dtI88091b/njuRlHsnoCa1zRtgqH0L4igLNu0zzOkH/ATsVS3Pyn4nsoRiGVFgzJZ0e2jT2McmDTxNeEHcafQSxeN7pztDFHT3ukUU9QFFtFDdzlug==}{vvv:VGbzgaVrLrJ+92ACJ0TEtQ==}{eeee:QURQVG9rZW6FbmNyeXB0aW6uS2v5}{sssss:mG+}";
+#endif
+
+static lws_ss_state_return_t
+myss_state(void *userobj, void *sh, lws_ss_constate_t state,
+          lws_ss_tx_ordinal_t ack)
+{
+       myss_t *m = (myss_t *)userobj;
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       const char *md_test = "not set";
+       size_t md_test_len = 7;
+       int i;
+       static const char * imd_test_keys[8] = {
+               "server:",
+               "content-security-policy:",
+               "strict-transport-security:",
+               "test-custom-header:",
+               "x-xss-protection:",
+               "x-content-type-options:",
+               "x-frame-options:",
+               "x-non-exist:",
+               };
+#endif
+
+       lwsl_user("%s: %s (%d), ord 0x%x\n", __func__,
+                 lws_ss_state_name((int)state), state, (unsigned int)ack);
+
+       switch (state) {
+       case LWSSSCS_CREATING:
+               return lws_ss_client_connect(m->ss);
+
+       case LWSSSCS_CONNECTING:
+               lws_ss_start_timeout(m->ss, timeout_ms);
+
+               if (lws_ss_set_metadata(m->ss, "uptag", "myuptag123", 10))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+#if !defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+               if (lws_ss_set_metadata(m->ss, "ctype", "myctype", 7))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+#else
+               if (lws_ss_set_metadata(m->ss, "X-Test-Type1:", "myctype1", 8))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+               if (lws_ss_set_metadata(m->ss, "X-Test-Type2:", "myctype2", 8))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+               if (lws_ss_set_metadata(m->ss, "Content-Type:", "myctype", 7))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+               if (lws_ss_set_metadata(m->ss, "X-ADP-Authentication-Token:",
+                                       long_token_str, strlen(long_token_str)))
+                       /* can fail, eg due to OOM, retry later if so */
+                       return LWSSSSRET_DISCONNECT_ME;
+
+#endif
+               break;
+
+       case LWSSSCS_ALL_RETRIES_FAILED:
+               /* if we're out of retries, we want to close the app and FAIL */
+               interrupted = 1;
+               bad = 2;
+               break;
+       case LWSSSCS_CONNECTED:
+#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
+       lwsl_user("%s: get direct metadata\n", __func__);
+       for (i = 0; i < 8; i++) {
+               md_test = "not set";
+               lws_ss_get_metadata(m->ss, imd_test_keys[i], (const void **)&md_test, &md_test_len);
+               lwsl_user("%s test key:[%s], got [%s]\n", __func__, imd_test_keys[i], md_test);
+       }
+#endif
+               break;
+
+       case LWSSSCS_QOS_ACK_REMOTE:
+               lwsl_notice("%s: LWSSSCS_QOS_ACK_REMOTE\n", __func__);
+               break;
+
+       case LWSSSCS_TIMEOUT:
+               lwsl_notice("%s: LWSSSCS_TIMEOUT\n", __func__);
+               /* if we're out of time */
+               interrupted = 1;
+               bad = 3;
+               break;
+
+       case LWSSSCS_USER_BASE:
+               lwsl_notice("%s: LWSSSCS_USER_BASE\n", __func__);
+               break;
+
+       default:
+               break;
+       }
+
+       return LWSSSSRET_OK;
+}
+
+#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
+static void
+myss_headers_dump(void *userobj, const uint8_t *buf, size_t len, int done)
+{
+       lwsl_user("%s: %lu done: %s\n", __func__, len, done?"true":"false");
+
+       lwsl_hexdump_err(buf, len);
+}
+#endif
+static int
+app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                   int current, int target)
+{
+       struct lws_context *context = lws_system_context_from_system_mgr(mgr);
+#if !defined(LWS_SS_USE_SSPC)
+
+       lws_system_blob_t *ab = lws_system_get_blob(context,
+                               LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */);
+       size_t size;
+#endif
+
+       /*
+        * For the things we care about, let's notice if we are trying to get
+        * past them when we haven't solved them yet, and make the system
+        * state wait while we trigger the dependent action.
+        */
+       switch (target) {
+
+#if !defined(LWS_SS_USE_SSPC)
+
+       /*
+        * The proxy takes responsibility for this stuff if we get things
+        * done through that
+        */
+
+       case LWS_SYSTATE_INITIALIZED: /* overlay on the hardcoded policy */
+       case LWS_SYSTATE_POLICY_VALID: /* overlay on the loaded policy */
+
+               if (target != current)
+                       break;
+
+               if (force_cpd_fail_portal)
+
+                       /* this makes it look like we're behind a captive portal
+                        * because the overriden address does a redirect */
+
+                       lws_ss_policy_overlay(context,
+                                     "{\"s\": [{\"captive_portal_detect\": {"
+                                        "\"endpoint\": \"google.com\","
+                                        "\"http_url\": \"/\","
+                                        "\"port\": 80"
+                                     "}}]}");
+
+               if (force_cpd_fail_no_internet)
+
+                       /* this looks like no internet, because the overridden
+                        * port doesn't have anything that will connect to us */
+
+                       lws_ss_policy_overlay(context,
+                                     "{\"s\": [{\"captive_portal_detect\": {"
+                                        "\"endpoint\": \"warmcat.com\","
+                                        "\"http_url\": \"/\","
+                                        "\"port\": 999"
+                                     "}}]}");
+               break;
+
+       case LWS_SYSTATE_REGISTERED:
+               size = lws_system_blob_get_size(ab);
+               if (size)
+                       break;
+
+               /* let's register our canned root token so auth can use it */
+               lws_system_blob_direct_set(ab,
+                               (const uint8_t *)canned_root_token_payload,
+                               strlen(canned_root_token_payload));
+               break;
+
+#endif
+
+       case LWS_SYSTATE_OPERATIONAL:
+               if (current == LWS_SYSTATE_OPERATIONAL) {
+                       lws_ss_info_t ssi;
+
+                       /* We're making an outgoing secure stream ourselves */
+
+                       memset(&ssi, 0, sizeof(ssi));
+                       ssi.handle_offset = offsetof(myss_t, ss);
+                       ssi.opaque_user_data_offset = offsetof(myss_t,
+                                                              opaque_data);
+                       ssi.rx = myss_rx;
+                       ssi.tx = myss_tx;
+                       ssi.state = myss_state;
+#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
+                       ssi.dump = myss_headers_dump;
+#endif
+                       ssi.user_alloc = sizeof(myss_t);
+                       ssi.streamtype = test_ots ? "mintest-ots" :
+                                        (test_respmap ? "respmap" :
+                                         (test_local ? "mintest_local" :
+                                         "mintest"));
+
+                       if (lws_ss_create(context, 0, &ssi, NULL, NULL,
+                                         NULL, NULL)) {
+                               lwsl_err("%s: failed to create secure stream\n",
+                                        __func__);
+                               interrupted = 1;
+                               lws_cancel_service(context);
+                               return -1;
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static lws_state_notify_link_t * const app_notifier_list[] = {
+       &nl, NULL
+};
+
+#if defined(LWS_WITH_SYS_METRICS)
+
+static int
+my_metric_report(lws_metric_pub_t *mp)
+{
+       lws_metric_bucket_t *sub = mp->u.hist.head;
+       char buf[192];
+
+       do {
+               if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
+                       lwsl_user("%s: %s\n", __func__, buf);
+       } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
+
+       /* 0 = leave metric to accumulate, 1 = reset the metric */
+
+       return 1;
+}
+
+static const lws_system_ops_t system_ops = {
+       .metric_report = my_metric_report,
+};
+
+#endif
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       int n = 0, expected = 0;
+       const char *p;
+
+       signal(SIGINT, sigint_handler);
+
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       //lws_set_log_level(LLL_USER | LLL_ERR | LLL_DEBUG | LLL_NOTICE | LLL_INFO, NULL);
+
+       lwsl_user("LWS secure streams test client [-d<verb>]\n");
+
+       /* these options are mutually exclusive if given */
+
+       if (lws_cmdline_option(argc, argv, "--force-portal"))
+               force_cpd_fail_portal = 1;
+
+       if (lws_cmdline_option(argc, argv, "--force-no-internet"))
+               force_cpd_fail_no_internet = 1;
+
+       if (lws_cmdline_option(argc, argv, "--respmap"))
+               test_respmap = 1;
+
+       if (lws_cmdline_option(argc, argv, "--ots"))
+               /*
+                * Use a streamtype that relies on the OS trust store for
+                * validation
+                */
+               test_ots = 1;
+
+       if (lws_cmdline_option(argc, argv, "--local"))
+               test_local = 1;
+
+       if ((p = lws_cmdline_option(argc, argv, "--timeout_ms")))
+               timeout_ms = (unsigned int)atoi(p);
+
+       info.fd_limit_per_thread = 1 + 6 + 1;
+       info.port = CONTEXT_PORT_NO_LISTEN;
+#if defined(LWS_SS_USE_SSPC)
+       info.protocols = lws_sspc_protocols;
+       {
+               const char *p;
+
+               /* connect to ssproxy via UDS by default, else via
+                * tcp connection to this port */
+               if ((p = lws_cmdline_option(argc, argv, "-p")))
+                       info.ss_proxy_port = (uint16_t)atoi(p);
+
+               /* UDS "proxy.ss.lws" in abstract namespace, else this socket
+                * path; when -p given this can specify the network interface
+                * to bind to */
+               if ((p = lws_cmdline_option(argc, argv, "-i")))
+                       info.ss_proxy_bind = p;
+
+               /* if -p given, -a specifies the proxy address to connect to */
+               if ((p = lws_cmdline_option(argc, argv, "-a")))
+                       info.ss_proxy_address = p;
+       }
+#else
+       info.pss_policies_json = default_ss_policy;
+       info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
+                      LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW |
+                      LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+#endif
+
+#if defined(LWS_WITH_MBEDTLS)
+
+       /* uncomment to force mbedtls to load a system trust store like
+        * openssl does
+        *
+        * info.mbedtls_client_preload_filepath =
+        *              "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem";
+        */
+#endif
+
+       /* integrate us with lws system state management when context created */
+
+       nl.name = "app";
+       nl.notify_cb = app_system_state_nf;
+       info.register_notifier_list = app_notifier_list;
+
+
+#if defined(LWS_WITH_SYS_METRICS)
+       info.system_ops = &system_ops;
+       info.metrics_prefix = "ssmex";
+#endif
+
+       /* create the context */
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               goto bail;
+       }
+
+#if !defined(LWS_SS_USE_SSPC)
+       /*
+        * If we're being a proxied client, the proxy does all this
+        */
+
+       /*
+        * Set the related lws_system blobs
+        *
+        * ...direct_set() sets a pointer, so the thing pointed to has to have
+        * a suitable lifetime, eg, something that already exists on the heap or
+        * a const string in .rodata like this
+        */
+
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_SERIAL, 0),
+                                  (const uint8_t *)"SN12345678", 10);
+       lws_system_blob_direct_set(lws_system_get_blob(context,
+                                  LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION, 0),
+                                  (const uint8_t *)"v0.01", 5);
+
+       /*
+        * ..._heap_append() appends to a buflist kind of arrangement on heap,
+        * just one block is fine, otherwise it will concatenate the fragments
+        * in the order they were appended (and take care of freeing them at
+        * context destroy time). ..._heap_empty() is also available to remove
+        * everything that was already allocated.
+        *
+        * Here we use _heap_append() just so it's tested as well as direct set.
+        */
+
+       lws_system_blob_heap_append(lws_system_get_blob(context,
+                                   LWS_SYSBLOB_TYPE_DEVICE_TYPE, 0),
+                                  (const uint8_t *)"spacerocket", 11);
+#endif
+
+       /* the event loop */
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+bail:
+       if ((p = lws_cmdline_option(argc, argv, "--expected-exit")))
+               expected = atoi(p);
+
+       if (bad == expected) {
+               lwsl_user("Completed: OK (seen expected %d)\n", expected);
+               return 0;
+       } else
+               lwsl_err("Completed: failed: exit %d, expected %d\n", bad, expected);
+
+       return 1;
+}
diff --git a/minimal-examples/selftests-library.sh b/minimal-examples/selftests-library.sh
deleted file mode 100755 (executable)
index 154e05b..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/bin/bash
-
-if [ -z "$1" -o -z "$2" ] ; then
-       echo "required args missing"
-       exit 1
-fi
-
-IDX=$3
-TOT=$4
-MYTEST=`echo $0 | sed "s/\/[^\/]*\$//g" |sed "s/.*\///g"`
-mkdir -p $2/$MYTEST
-rm -f $2/$MYTEST/*.log $2/$MYTEST/*.result
-FAILS=0
-WHICH=$IDX
-SPID=
-SCRIPT_DIR=`dirname $0`
-SCRIPT_DIR=`readlink -f $SCRIPT_DIR`
-LOGPATH=$2
-
-feedback() {
-       if [ "$2" != "0" ] ; then
-               FAILS=$(( $FAILS + 1 ))
-               echo -n -e "\e[31m"
-       fi
-       T="  ---  killed  ---  "
-       if [ ! -z "`cat $LOGPATH/$MYTEST/$3.time`" ] ; then
-               T="`cat $LOGPATH/$MYTEST/$3.time | grep real | sed "s/.*\ //g"`"
-               T="$T `cat $LOGPATH/$MYTEST/$3.time | grep user | sed "s/.*\ //g"`"
-               T="$T `cat $LOGPATH/$MYTEST/$3.time | grep sys | sed "s/.*\ //g"`"
-       fi
-       printf "%-35s [ %3s/%3s ]: %3s : %8s : %s\n" $1 $WHICH $TOT $2 "$T" $3
-       if [ "$2" != "0" ] ; then
-               echo -n -e "\e[0m"
-       fi
-       WHICH=$(( $WHICH + 1))
-}
-
-spawn() {
-       if [ ! -z "$1" ] ; then
-               if [ `ps $1 | wc -l` -eq 2 ]; then
-#                      echo "prerequisite still up"
-                       return 0
-               fi
-       fi
-
-       QQ=`pwd`
-       cd $SCRIPT_DIR
-       cd $2
-       $3 $4 $5 > $LOGPATH/$MYTEST/serverside.log 2> $LOGPATH/$MYTEST/serverside.log &
-       SPID=$!
-       cd $QQ
-       sleep 0.5s
-#      echo "launched prerequisite $SPID"
-}
-
-dotest() {
-       T=$3
-       (
-               {
-                       /usr/bin/time -p $1/lws-$MYTEST $4 $5 $6 $7 $8 $9 > $2/$MYTEST/$T.log 2> $2/$MYTEST/$T.log ;
-                       echo $? > $2/$MYTEST/$T.result
-               } 2> $2/$MYTEST/$T.time >/dev/null
-       ) >/dev/null 2> /dev/null &
-       W=$!
-       WT=0
-       while [ $WT -le 820 ] ; do
-               kill -0 $W 2>/dev/null
-               if [ $? -ne 0 ] ; then
-                       WT=10000
-               else
-                       if [ $WT -ge 800 ] ; then
-                               WT=10000
-                               kill $W 2>/dev/null
-                               wait $W 2>/dev/null
-                       fi
-               fi
-               sleep 0.1s
-               WT=$(( $WT + 1 ))
-       done
-
-       R=254
-       if [ -e $2/$MYTEST/$T.result ] ; then
-               R=`cat $2/$MYTEST/$T.result`
-               cat $2/$MYTEST/$T.log | tail -n 3 > $2/$MYTEST/$T.time
-               if [ $R -ne 0 ] ; then
-                       pwd
-                       echo
-                       cat $2/$MYTEST/$T.log
-                       echo
-               fi
-       fi
-
-       feedback $MYTEST $R $T
-}
-
diff --git a/minimal-examples/selftests.sh b/minimal-examples/selftests.sh
deleted file mode 100755 (executable)
index 77fbdd4..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/bash
-#
-# run this from your build dir having configured
-# -DLWS_WITH_MINIMAL_EXAMPLES=1 to get all the examples
-# that apply built into ./bin
-#
-# Eg,
-#
-# build $ ../minimal-examples/selftests.sh
-
-echo
-echo "----------------------------------------------"
-echo "-------   tests: lws minimal example selftests"
-echo
-
-LOGGING_PATH=/tmp/logs
-
-# for mebedtls, we need the CA certs in ./build where we run from
-
-cp ../minimal-examples/http-client/minimal-http-client-multi/warmcat.com.cer .
-cp ../minimal-examples/http-client/minimal-http-client-post/libwebsockets.org.cer .
-
-MINEX=`dirname $0`
-MINEX=`realpath $MINEX`
-TESTS=0
-for i in `find $MINEX -name selftest.sh` ; do
-       BN=`echo -n "$i" | sed "s/\/[^\/]*\$//g" | sed "s/.*\///g"`
-       if [ -e `pwd`/bin/lws-$BN ] ; then
-               C=`cat $i | grep COUNT_TESTS= | cut -d= -f2`
-               TESTS=$(( $TESTS + $C ))
-       fi
-done
-
-FAILS=0
-WH=1
-
-for i in `find $MINEX -name selftest.sh` ; do
-       BN=`echo -n "$i" | sed "s/\/[^\/]*\$//g" | sed "s/.*\///g"`
-       if [ -e `pwd`/bin/lws-$BN ] ; then
-               C=`cat $i | grep COUNT_TESTS= | cut -d= -f2`
-               sh $i `pwd`/bin $LOGGING_PATH $WH $TESTS $MINEX
-               FAILS=$(( $FAILS + $? ))
-       
-               L=`ps fax | grep lws- | cut -d' ' -f2`
-               kill $L 2>/dev/null
-               kill -9 $L 2>/dev/null
-               wait $L 2>/dev/null
-       
-               WH=$(( $WH + $C ))
-       fi
-done
-
-if [ $FAILS -eq 0 ] ; then
-       echo "All $TESTS passed"
-       exit 0
-else
-       echo "Failed: $FAILS / $TESTS"
-       exit 1
-fi
-
-
index 10db2fa..9d2ce07 100644 (file)
@@ -1,5 +1,6 @@
 |name|demonstrates|
 ---|---
+minimal-ws-client|Simple client that connects to libwebsockets.org dumb increment protocol and demonstrates retry and backoff
 minimal-ws-client-echo|Simple client that connects to a ws server and echos anything the server sends
 minimal-ws-client-ping|Ws ping test client
 minimal-ws-client-pmd-bulk|Client that sends bulk multifragment data to the minimal-ws-server-pmd-bulk example
diff --git a/minimal-examples/ws-client/minimal-ws-client-binance/CMakeLists.txt b/minimal-examples/ws-client/minimal-ws-client-binance/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d3ccf8c
--- /dev/null
@@ -0,0 +1,26 @@
+project(lws-minimal-ws-client-binance C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-ws-client-binance)
+set(SRCS main.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_WS 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITHOUT_EXTENSIONS 0 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/ws-client/minimal-ws-client-binance/README.md b/minimal-examples/ws-client/minimal-ws-client-binance/README.md
new file mode 100644 (file)
index 0000000..7809a0b
--- /dev/null
@@ -0,0 +1,67 @@
+# lws minimal ws client binance
+
+This connects to the binance ws server and monitors transactions with
+an eye on low latency.
+
+Latency seems to be associated with server-side coalescing at tls
+layer, and the coalescing at server side seems somewhat correlated to number
+of transactions per second, which seems to cause increased packet sizes from the
+server as a reaction.  The relationship is more complex probably according to what
+actually happens at the server backend, but it seems to be broadly related
+reliably.
+
+Typically when showing low latency at ~70msg/s, the messages on the wire are
+eg, ~70 byte packets containing small tls records
+
+10:14:40.682293 IP ec2-54-249-113-172.ap-northeast-1.compute.amazonaws.com.https > constance.42952: Flags [P.], seq 50846:50927, ack 1, win 11, options [nop,nop,TS val 366445630 ecr 3893437035], length 81
+
+under pressure from increased messages per second, the tls records increase above 2KB
+
+08:06:02.825160 IP ec2-54-249-113-172.ap-northeast-1.compute.amazonaws.com.https > constance.42688: Flags [.], seq 512319:513643, ack 1, win 11, options [nop,nop,TS val 3990208942 ecr 3885719233], length 1324
+08:06:02.825290 IP constance.42688 > ec2-54-249-113-172.ap-northeast-1.compute.amazonaws.com.https: Flags [.], ack 513643, win 14248, options [nop,nop,TS val 3885719479 ecr 3990208942], length 0
+08:06:02.891646 IP ec2-54-249-113-172.ap-northeast-1.compute.amazonaws.com.https > constance.42688: Flags [.], seq 513643:516291, ack 1, win 11, options [nop,nop,TS val 3990209006 ecr 3885719296], length 2648
+
+The larger the packets, the longer the first item in the packet had to
+wait before it was sent, and a tls record cannot be authenticated until
+all of it has been received.
+
+The example circumvents this somewhat by using `permessage_deflate`, which reduces
+the packet size before tls by applying compression, making even coalesced packets
+smaller, and a new option for adjusting how lws manages conflicting requirements to
+clear pending rx and allow interleaved tx, `LCCSCF_PRIORITIZE_READS` that causes the
+stream to prioritize handling any pending rx, not just pending at ssl layer, in one
+event loop trip.
+
+## build
+
+Lws must have been built with `LWS_ROLE_WS=1` and `LWS_WITHOUT_EXTENSIONS=0`
+
+```
+ $ cmake . && make
+```
+
+## Commandline Options
+
+Option|Meaning
+---|---
+-d|Set logging verbosity
+
+## usage
+
+```
+$ ./bin/lws-minimal-ws-client-binance 
+[2020/08/23 10:22:49:3003] U: LWS minimal binance client
+[2020/08/23 10:22:49:3005] N: LWS: 4.0.99-v4.1.0-rc2-4-g3cf133aef, loglevel 1031
+[2020/08/23 10:22:49:3005] N: NET CLI SRV H1 H2 WS MQTT SS-JSON-POL SSPROX ASYNC_DNS IPv6-absent
+[2020/08/23 10:22:50:8243] N: checking client ext permessage-deflate
+[2020/08/23 10:22:50:8244] N: instantiating client ext permessage-deflate
+[2020/08/23 10:22:50:8244] U: callback_minimal: established
+[2020/08/23 10:22:51:8244] N: sul_hz_cb: price: min: 1160284¢, max: 1163794¢, avg: 1160516¢, (150 prices/s)
+[2020/08/23 10:22:51:8245] N: sul_hz_cb: elatency: min: 112ms, max: 547ms, avg: 259ms, (155 msg/s)
+[2020/08/23 10:22:52:8244] N: sul_hz_cb: price: min: 1160287¢, max: 1178845¢, avg: 1160897¢, (112 prices/s)
+[2020/08/23 10:22:52:8245] N: sul_hz_cb: elatency: min: 111ms, max: 226ms, avg: 152ms, (134 msg/s)
+[2020/08/23 10:22:53:8247] N: sul_hz_cb: price: min: 1160287¢, max: 1168005¢, avg: 1160806¢, (86 prices/s)
+[2020/08/23 10:22:53:8248] N: sul_hz_cb: elatency: min: 112ms, max: 476ms, avg: 287ms, (101 msg/s)
+[2020/08/23 10:22:54:8247] N: sul_hz_cb: price: min: 1160284¢, max: 1162780¢, avg: 1160698¢, (71 prices/s)
+...
+```
diff --git a/minimal-examples/ws-client/minimal-ws-client-binance/main.c b/minimal-examples/ws-client/minimal-ws-client-binance/main.c
new file mode 100644 (file)
index 0000000..152d393
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * lws-minimal-ws-client-binance
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *                         Kutoga <kutoga@user.github.invalid>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a ws client that connects to binance ws server efficiently
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+
+typedef struct range {
+       uint64_t                sum;
+       uint64_t                lowest;
+       uint64_t                highest;
+
+       unsigned int            samples;
+} range_t;
+
+/*
+ * This represents your object that "contains" the client connection and has
+ * the client connection bound to it
+ */
+
+static struct my_conn {
+       lws_sorted_usec_list_t  sul;         /* schedule connection retry */
+       lws_sorted_usec_list_t  sul_hz;      /* 1hz summary */
+
+       range_t                 e_lat_range;
+       range_t                 price_range;
+
+       struct lws              *wsi;        /* related wsi if any */
+       uint16_t                retry_count; /* count of consequetive retries */
+} mco;
+
+static struct lws_context *context;
+static int interrupted;
+
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+/*
+ * OpenSSL uses the system trust store.  mbedTLS / WolfSSL have to be told which
+ * CA to trust explicitly.
+ */
+static const char * const ca_pem_digicert_global_root =
+       "-----BEGIN CERTIFICATE-----\n"
+       "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n"
+       "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+       "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"
+       "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n"
+       "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
+       "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n"
+       "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n"
+       "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n"
+       "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n"
+       "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n"
+       "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n"
+       "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n"
+       "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n"
+       "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n"
+       "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n"
+       "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n"
+       "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n"
+       "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n"
+       "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n"
+       "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"
+       "-----END CERTIFICATE-----\n";
+#endif
+
+/*
+ * The retry and backoff policy we want to use for our client connections
+ */
+
+static const uint32_t backoff_ms[] = { 1000, 2000, 3000, 4000, 5000 };
+
+static const lws_retry_bo_t retry = {
+       .retry_ms_table                 = backoff_ms,
+       .retry_ms_table_count           = LWS_ARRAY_SIZE(backoff_ms),
+       .conceal_count                  = LWS_ARRAY_SIZE(backoff_ms),
+
+       .secs_since_valid_ping          = 400,  /* force PINGs after secs idle */
+       .secs_since_valid_hangup        = 400, /* hangup after secs idle */
+
+       .jitter_percent                 = 0,
+};
+
+/*
+ * If we don't enable permessage-deflate ws extension, during times when there
+ * are many ws messages per second the server coalesces them inside a smaller
+ * number of larger ssl records, for >100 mps typically >2048 records.
+ *
+ * This is a problem, because the coalesced record cannot be send nor decrypted
+ * until the last part of the record is received, meaning additional latency
+ * for the earlier members of the coalesced record that have just been sitting
+ * there waiting for the last one to go out and be decrypted.
+ *
+ * permessage-deflate reduces the data size before the tls layer, for >100mps
+ * reducing the colesced records to ~1.2KB.
+ */
+
+static const struct lws_extension extensions[] = {
+       {
+               "permessage-deflate",
+               lws_extension_callback_pm_deflate,
+               "permessage-deflate"
+                "; client_no_context_takeover"
+                "; client_max_window_bits"
+       },
+       { NULL, NULL, NULL /* terminator */ }
+};
+/*
+ * Scheduled sul callback that starts the connection attempt
+ */
+
+static void
+connect_client(lws_sorted_usec_list_t *sul)
+{
+       struct my_conn *mco = lws_container_of(sul, struct my_conn, sul);
+       struct lws_client_connect_info i;
+
+       memset(&i, 0, sizeof(i));
+
+       i.context = context;
+       i.port = 443;
+       i.address = "fstream.binance.com";
+       i.path = "/stream?"
+                "streams=btcusdt@depth@0ms/btcusdt@bookTicker/btcusdt@aggTrade";
+       i.host = i.address;
+       i.origin = i.address;
+       i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_PRIORITIZE_READS;
+       i.protocol = NULL;
+       i.local_protocol_name = "lws-minimal-client";
+       i.pwsi = &mco->wsi;
+       i.retry_and_idle_policy = &retry;
+       i.userdata = mco;
+
+       if (!lws_client_connect_via_info(&i))
+               /*
+                * Failed... schedule a retry... we can't use the _retry_wsi()
+                * convenience wrapper api here because no valid wsi at this
+                * point.
+                */
+               if (lws_retry_sul_schedule(context, 0, sul, &retry,
+                                          connect_client, &mco->retry_count)) {
+                       lwsl_err("%s: connection attempts exhausted\n", __func__);
+                       interrupted = 1;
+               }
+}
+
+static void
+range_reset(range_t *r)
+{
+       r->sum = r->highest = 0;
+       r->lowest = 999999999999ull;
+       r->samples = 0;
+}
+
+static uint64_t
+get_us_timeofday(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+
+       return (uint64_t)((lws_usec_t)tv.tv_sec * LWS_US_PER_SEC) + (uint64_t)tv.tv_usec;
+}
+
+static void
+sul_hz_cb(lws_sorted_usec_list_t *sul)
+{
+       struct my_conn *mco = lws_container_of(sul, struct my_conn, sul_hz);
+
+       /*
+        * We are called once a second to dump statistics on the connection
+        */
+
+       lws_sul_schedule(lws_get_context(mco->wsi), 0, &mco->sul_hz,
+                        sul_hz_cb, LWS_US_PER_SEC);
+
+       if (mco->price_range.samples)
+               lwsl_notice("%s: price: min: %llu¢, max: %llu¢, avg: %llu¢, "
+                           "(%d prices/s)\n",
+                           __func__,
+                           (unsigned long long)mco->price_range.lowest,
+                           (unsigned long long)mco->price_range.highest,
+                           (unsigned long long)(mco->price_range.sum / mco->price_range.samples),
+                           mco->price_range.samples);
+       if (mco->e_lat_range.samples)
+               lwsl_notice("%s: elatency: min: %llums, max: %llums, "
+                           "avg: %llums, (%d msg/s)\n", __func__,
+                           (unsigned long long)mco->e_lat_range.lowest / 1000,
+                           (unsigned long long)mco->e_lat_range.highest / 1000,
+                           (unsigned long long)(mco->e_lat_range.sum /
+                                          mco->e_lat_range.samples) / 1000,
+                           mco->e_lat_range.samples);
+
+       range_reset(&mco->e_lat_range);
+       range_reset(&mco->price_range);
+}
+
+static uint64_t
+pennies(const char *s)
+{
+       uint64_t price = (uint64_t)atoll(s) * 100;
+
+       s = strchr(s, '.');
+
+       if (s && isdigit(s[1]) && isdigit(s[2]))
+               price = price + (uint64_t)((10 * (s[1] - '0')) + (s[2] - '0'));
+
+       return price;
+}
+
+static int
+callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
+                void *user, void *in, size_t len)
+{
+       struct my_conn *mco = (struct my_conn *)user;
+       uint64_t latency_us, now_us;
+       uint64_t price;
+       char numbuf[16];
+       const char *p;
+       size_t alen;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+               goto do_retry;
+               break;
+
+       case LWS_CALLBACK_CLIENT_RECEIVE:
+               /*
+                * The messages are a few 100 bytes of JSON each
+                */
+
+               // lwsl_hexdump_notice(in, len);
+
+               now_us = (uint64_t)get_us_timeofday();
+
+               p = lws_json_simple_find((const char *)in, len,
+                                        "\"depthUpdate\"", &alen);
+               /*
+                * Only the JSON with depthUpdate init has the numbers we care
+                * about as well
+                */
+               if (!p)
+                       break;
+
+               p = lws_json_simple_find((const char *)in, len, "\"E\":", &alen);
+               if (!p) {
+                       lwsl_err("%s: no E JSON\n", __func__);
+                       break;
+               }
+               lws_strnncpy(numbuf, p, alen, sizeof(numbuf));
+               latency_us = now_us -
+                               ((uint64_t)atoll(numbuf) * LWS_US_PER_MS);
+
+               if (latency_us < mco->e_lat_range.lowest)
+                       mco->e_lat_range.lowest = latency_us;
+               if (latency_us > mco->e_lat_range.highest)
+                       mco->e_lat_range.highest = latency_us;
+
+               mco->e_lat_range.sum += latency_us;
+               mco->e_lat_range.samples++;
+
+               p = lws_json_simple_find((const char *)in, len,
+                                        "\"a\":[[\"", &alen);
+               if (p) {
+                       lws_strnncpy(numbuf, p, alen, sizeof(numbuf));
+                       price = pennies(numbuf);
+
+                       if (price < mco->price_range.lowest)
+                               mco->price_range.lowest = price;
+                       if (price > mco->price_range.highest)
+                               mco->price_range.highest = price;
+
+                       mco->price_range.sum += price;
+                       mco->price_range.samples++;
+               }
+               break;
+
+       case LWS_CALLBACK_CLIENT_ESTABLISHED:
+               lwsl_user("%s: established\n", __func__);
+               lws_sul_schedule(lws_get_context(wsi), 0, &mco->sul_hz,
+                                sul_hz_cb, LWS_US_PER_SEC);
+               mco->wsi = wsi;
+               range_reset(&mco->e_lat_range);
+               range_reset(&mco->price_range);
+               break;
+
+       case LWS_CALLBACK_CLIENT_CLOSED:
+               lws_sul_cancel(&mco->sul_hz);
+               goto do_retry;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+
+do_retry:
+       /*
+        * retry the connection to keep it nailed up
+        *
+        * For this example, we try to conceal any problem for one set of
+        * backoff retries and then exit the app.
+        *
+        * If you set retry.conceal_count to be larger than the number of
+        * elements in the backoff table, it will never give up and keep
+        * retrying at the last backoff delay plus the random jitter amount.
+        */
+       if (lws_retry_sul_schedule_retry_wsi(wsi, &mco->sul, connect_client,
+                                            &mco->retry_count)) {
+               lwsl_err("%s: connection attempts exhausted\n", __func__);
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+static const struct lws_protocols protocols[] = {
+       { "lws-minimal-client", callback_minimal, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS minimal binance client\n");
+
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
+       info.protocols = protocols;
+       info.fd_limit_per_thread = 1 + 1 + 1;
+       info.extensions = extensions;
+
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+       /*
+        * OpenSSL uses the system trust store.  mbedTLS / WolfSSL have to be
+        * told which CA to trust explicitly.
+        */
+       info.client_ssl_ca_mem = ca_pem_digicert_global_root;
+       info.client_ssl_ca_mem_len = (unsigned int)strlen(ca_pem_digicert_global_root);
+#endif
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* schedule the first client connection attempt to happen immediately */
+       lws_sul_schedule(context, 0, &mco.sul, connect_client, 1);
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+       lwsl_user("Completed\n");
+
+       return 0;
+}
+
index d5162b0..4e88dbc 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8.9)
+project(lws-minimal-ws-client-echo C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-client-echo)
 set(SRCS minimal-ws-client-echo.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 require_lws_config(LWS_WITHOUT_EXTENSIONS 0 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index a74d454..285d17f 100644 (file)
@@ -19,7 +19,7 @@
 
 static struct lws_protocols protocols[] = {
        LWS_PLUGIN_PROTOCOL_MINIMAL_CLIENT_ECHO,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static struct lws_context *context;
index 7023e76..629ad70 100644 (file)
@@ -43,6 +43,8 @@ struct vhd_minimal_client_echo {
        struct lws_vhost *vhost;
        struct lws *client_wsi;
 
+       lws_sorted_usec_list_t sul;
+
        int *interrupted;
        int *options;
        const char **url;
@@ -51,9 +53,11 @@ struct vhd_minimal_client_echo {
        int *port;
 };
 
-static int
-connect_client(struct vhd_minimal_client_echo *vhd)
+static void
+sul_connect_attempt(struct lws_sorted_usec_list *sul)
 {
+       struct vhd_minimal_client_echo *vhd =
+               lws_container_of(sul, struct vhd_minimal_client_echo, sul);
        struct lws_client_connect_info i;
        char host[128];
 
@@ -77,7 +81,9 @@ connect_client(struct vhd_minimal_client_echo *vhd)
 
        lwsl_user("connecting to %s:%d/%s\n", i.address, i.port, i.path);
 
-       return !lws_client_connect_via_info(&i);
+       if (!lws_client_connect_via_info(&i))
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, 10 * LWS_US_PER_SEC);
 }
 
 static void
@@ -90,13 +96,6 @@ __minimal_destroy_message(void *_msg)
        msg->len = 0;
 }
 
-static void
-schedule_callback(struct lws *wsi, int reason, int secs)
-{
-       lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
-               lws_get_protocol(wsi), reason, secs);
-}
-
 static int
 callback_minimal_client_echo(struct lws *wsi, enum lws_callback_reasons reason,
                          void *user, void *in, size_t len)
@@ -142,8 +141,11 @@ callback_minimal_client_echo(struct lws *wsi, enum lws_callback_reasons reason,
                        (const struct lws_protocol_vhost_options *)in,
                        "iface")->value;
 
-               if (connect_client(vhd))
-                       schedule_callback(wsi, LWS_CALLBACK_USER, 1);
+               sul_connect_attempt(&vhd->sul);
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               lws_sul_cancel(&vhd->sul);
                break;
 
        case LWS_CALLBACK_CLIENT_ESTABLISHED:
@@ -176,7 +178,7 @@ callback_minimal_client_echo(struct lws *wsi, enum lws_callback_reasons reason,
 
                /* notice we allowed for LWS_PRE in the payload already */
                m = lws_write(wsi, ((unsigned char *)pmsg->payload) +
-                             LWS_PRE, pmsg->len, flags);
+                             LWS_PRE, pmsg->len, (enum lws_write_protocol)flags);
                if (m < (int)pmsg->len) {
                        lwsl_err("ERROR %d writing to ws socket\n", m);
                        return -1;
@@ -215,9 +217,9 @@ callback_minimal_client_echo(struct lws *wsi, enum lws_callback_reasons reason,
 
                // lwsl_hexdump_notice(in, len);
 
-               amsg.first = lws_is_first_fragment(wsi);
-               amsg.final = lws_is_final_fragment(wsi);
-               amsg.binary = lws_frame_is_binary(wsi);
+               amsg.first = (char)lws_is_first_fragment(wsi);
+               amsg.final = (char)lws_is_final_fragment(wsi);
+               amsg.binary = (char)lws_frame_is_binary(wsi);
                n = (int)lws_ring_get_count_free_elements(pss->ring);
                if (!n) {
                        lwsl_user("dropping!\n");
@@ -250,32 +252,18 @@ callback_minimal_client_echo(struct lws *wsi, enum lws_callback_reasons reason,
                lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
                         in ? (char *)in : "(null)");
                vhd->client_wsi = NULL;
-               //schedule_callback(wsi, LWS_CALLBACK_USER, 1);
-               //if (*vhd->options & 1) {
-                       if (!*vhd->interrupted)
-                               *vhd->interrupted = 3;
-                       lws_cancel_service(lws_get_context(wsi));
-               //}
+               if (!*vhd->interrupted)
+                       *vhd->interrupted = 3;
+               lws_cancel_service(lws_get_context(wsi));
                break;
 
        case LWS_CALLBACK_CLIENT_CLOSED:
                lwsl_user("LWS_CALLBACK_CLIENT_CLOSED\n");
                lws_ring_destroy(pss->ring);
                vhd->client_wsi = NULL;
-               // schedule_callback(wsi, LWS_CALLBACK_USER, 1);
-               //if (*vhd->options & 1) {
-                       if (!*vhd->interrupted)
-                               *vhd->interrupted = 1 + pss->completed;
-                       lws_cancel_service(lws_get_context(wsi));
-       //      }
-               break;
-
-       /* rate-limited client connect retries */
-
-       case LWS_CALLBACK_USER:
-               lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__);
-               if (connect_client(vhd))
-                       schedule_callback(wsi, LWS_CALLBACK_USER, 1);
+               if (!*vhd->interrupted)
+                       *vhd->interrupted = 1 + pss->completed;
+               lws_cancel_service(lws_get_context(wsi));
                break;
 
        default:
@@ -293,36 +281,3 @@ callback_minimal_client_echo(struct lws *wsi, enum lws_callback_reasons reason,
                1024, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL_CLIENT_ECHO
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal_client_echo(struct lws_context *context,
-                              struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal_client_echo(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index b9a265e..976f468 100644 (file)
@@ -1,90 +1,26 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-client-ping C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckIncludeFile)
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-client-ping)
 set(SRCS minimal-ws-client-ping.c)
 
-MACRO(require_pthreads result)
-       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
-       if (NOT LWS_HAVE_PTHREAD_H)
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(result 0)
-               else()
-                       message(FATAL_ERROR "threading support requires pthreads")
-               endif()
-       endif()
-ENDMACRO()
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_pthreads(requirements)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared pthread)
-               add_dependencies(${SAMP} websockets_shared pthread)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets pthread)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 13be92c..4cfc0ec 100644 (file)
@@ -2,7 +2,8 @@
 
 This connects to libwebsockets.org using the lws-mirror-protocol.
 
-It then sends a ws PING every 5s and records any PONG coming back.
+It sets a validity regime of testing validity with PING every 3s and failing
+if it didn't get the PONG back within 10s.
 
 ## build
 
@@ -14,29 +15,103 @@ It then sends a ws PING every 5s and records any PONG coming back.
 
 Option|Meaning
 ---|---
--d|Set logging verbosity
+-d|Set logging verbosity (you want 1039 to see the validity ping / pong)
 --server|Use a specific server instead of libwebsockets.org, eg `--server localhost`.  Implies LCCSCF_ALLOW_SELFSIGNED
 --port|Use a specific port instead of 443, eg `--port 7681`
--z|Send zero-length pings for testing
 --protocol|Use a specific ws subprotocol rather than lws-mirror-protocol, eg, `--protocol myprotocol`
 
+
 ## usage
 
 Just run it, wait for the connect and then there will be PINGs sent
 at 5s intervals.
 
 ```
- $ ./lws-minimal-ws-client-ping
-[2018/05/09 16:55:03:1160] USER: LWS minimal ws client PING
-[2018/05/09 16:55:03:1379] NOTICE: Creating Vhost 'default' (serving disabled), 1 protocols, IPv6 off
-[2018/05/09 16:55:03:1715] NOTICE: client loaded CA for verification ./libwebsockets.org.cer
-[2018/05/09 16:55:03:1717] NOTICE: created client ssl context for default
-[2018/05/09 16:55:04:8332] USER: callback_minimal_broker: established
-[2018/05/09 16:55:09:8389] USER: Sending PING 10...
-[2018/05/09 16:55:10:1491] USER: LWS_CALLBACK_CLIENT_RECEIVE_PONG
-[2018/05/09 16:55:10:1494] NOTICE: 
-[2018/05/09 16:55:10:1514] NOTICE: 0000: 70 69 6E 67 20 62 6F 64 79 21                      ping body!      
-[2018/05/09 16:55:10:1515] NOTICE: 
+ $ ./lws-minimal-ws-client-ping -d1039
+[2020/03/18 13:13:47:1114] U: LWS minimal ws client PING
+[2020/03/18 13:13:47:1503] I: Initial logging level 1039
+[2020/03/18 13:13:47:1507] I: Libwebsockets version: 4.0.99 v4.0.0-20-gc6165f868
+[2020/03/18 13:13:47:1508] I: IPV6 not compiled in
+[2020/03/18 13:13:47:1512] I:  LWS_DEF_HEADER_LEN    : 4096
+[2020/03/18 13:13:47:1514] I:  LWS_MAX_SMP           : 1
+[2020/03/18 13:13:47:1519] I:  sizeof (*info)        : 720
+[2020/03/18 13:13:47:1520] I:  SYSTEM_RANDOM_FILEPATH: '/dev/urandom'
+[2020/03/18 13:13:47:1522] I:  HTTP2 support         : available
+[2020/03/18 13:13:47:1552] N: lws_create_context: using ss proxy bind '(null)', port 0, ads '(null)'
+[2020/03/18 13:13:47:1557] I: context created
+[2020/03/18 13:13:47:1575] I: Using event loop: poll
+[2020/03/18 13:13:47:1583] I: Default ALPN advertisment: h2,http/1.1
+[2020/03/18 13:13:47:1585] I:  default timeout (secs): 20
+[2020/03/18 13:13:47:1614] I:  Threads: 1 each 5 fds
+[2020/03/18 13:13:47:1623] I:  mem: context:          8152 B (4056 ctx + (1 thr x 4096))
+[2020/03/18 13:13:47:1625] I:  mem: http hdr size:   (4096 + 976), max count 5
+[2020/03/18 13:13:47:1629] I:  mem: pollfd map:         40 B
+[2020/03/18 13:13:47:1633] I:  mem: platform fd map:    40 B
+[2020/03/18 13:13:47:1692] I:  Compiled with OpenSSL support
+[2020/03/18 13:13:47:1695] I: Doing SSL library init
+[2020/03/18 13:13:47:3103] I:  canonical_hostname = constance
+[2020/03/18 13:13:47:3140] I: Creating Vhost 'default' (serving disabled), 4 protocols, IPv6 off
+[2020/03/18 13:13:47:4072] I: lws_tls_client_create_vhost_context: vh default: created new client ctx 0
+[2020/03/18 13:13:47:7468] I: created client ssl context for default
+[2020/03/18 13:13:47:7482] I: Creating Vhost 'default' (serving disabled), 4 protocols, IPv6 off
+[2020/03/18 13:13:47:7490] I: lws_tls_client_create_vhost_context: vh default: reusing client ctx 0: use 2
+[2020/03/18 13:13:47:7491] I: created client ssl context for default
+[2020/03/18 13:13:47:7494] I:  mem: per-conn:          792 bytes + protocol rx buf
+[2020/03/18 13:13:47:7497] I: lws_plat_drop_app_privileges: not changing group
+[2020/03/18 13:13:47:7499] I: lws_plat_drop_app_privileges: not changing user
+[2020/03/18 13:13:47:7512] I: lws_cancel_service
+[2020/03/18 13:13:47:7568] I: lws_state_notify_protocol_init: LWS_SYSTATE_CPD_PRE_TIME
+[2020/03/18 13:13:47:7577] N: lws_ss_create: unknown stream type captive_portal_detect
+[2020/03/18 13:13:47:7580] I: lws_ss_sys_cpd: Create stream failed (policy?)
+[2020/03/18 13:13:47:7582] I: lws_state_notify_protocol_init: LWS_SYSTATE_CPD_PRE_TIME
+[2020/03/18 13:13:47:7582] N: lws_ss_create: unknown stream type captive_portal_detect
+[2020/03/18 13:13:47:7583] I: lws_ss_sys_cpd: Create stream failed (policy?)
+[2020/03/18 13:13:47:7585] I: lws_state_notify_protocol_init: doing protocol init on POLICY_VALID
+[2020/03/18 13:13:47:7588] I: lws_protocol_init
+[2020/03/18 13:13:47:7623] I: lws_state_transition_steps: CONTEXT_CREATED -> OPERATIONAL
+[2020/03/18 13:13:47:7628] N: connect_cb: connecting
+[2020/03/18 13:13:47:7656] I: lws_client_connect_via_info: role binding to h1
+[2020/03/18 13:13:47:7662] I: lws_client_connect_via_info: protocol binding to lws-ping-test
+[2020/03/18 13:13:47:7699] I: lws_client_connect_via_info: wsi 0x5669090: h1 lws-ping-test entry
+[2020/03/18 13:13:47:7720] I: lws_header_table_attach: wsi 0x5669090: ah (nil) (tsi 0, count = 0) in
+[2020/03/18 13:13:47:7729] I: _lws_create_ah: created ah 0x5669620 (size 4096): pool length 1
+[2020/03/18 13:13:47:7735] I: lws_header_table_attach: did attach wsi 0x5669090: ah 0x5669620: count 1 (on exit)
+[2020/03/18 13:13:47:7780] I: lws_client_connect_2_dnsreq: 0x5669090: lookup libwebsockets.org:443
+[2020/03/18 13:13:47:8784] I: lws_getaddrinfo46: getaddrinfo 'libwebsockets.org' says 0
+[2020/03/18 13:13:47:8804] I: lws_client_connect_3_connect: libwebsockets.org ipv4 46.105.127.147
+[2020/03/18 13:13:47:9176] I: lws_client_connect_3_connect: getsockopt check: conn OK
+[2020/03/18 13:13:47:9179] I: lws_client_connect_3_connect: Connection started 0x5682cc0
+[2020/03/18 13:13:47:9197] I: lws_client_connect_4_established: wsi 0x5669090: h1 lws-ping-test client created own conn (raw 0) vh defaultm st 0x202
+[2020/03/18 13:13:47:9418] I: h1 client conn using alpn list 'http/1.1'
+[2020/03/18 13:13:48:4523] I: lws_role_call_alpn_negotiated: 'http/1.1'
+[2020/03/18 13:13:48:4531] I: client connect OK
+[2020/03/18 13:13:48:4543] I: lws_openssl_describe_cipher: wsi 0x5669090: TLS_AES_256_GCM_SHA384, TLS_AES_256_GCM_SHA384, 256 bits, TLSv1.3
+[2020/03/18 13:13:48:4717] I: lws_client_socket_service: HANDSHAKE2: 0x5669090: sending headers (wsistate 0x10000204), w sock 5
+[2020/03/18 13:13:48:4992] I: lws_buflist_aware_read: wsi 0x5669090: lws_client_socket_service: ssl_capable_read -4
+[2020/03/18 13:13:48:5005] I: lws_buflist_aware_read: wsi 0x5669090: lws_client_socket_service: ssl_capable_read 174
+[2020/03/18 13:13:48:5166] I: __lws_header_table_detach: wsi 0x5669090: ah 0x5669620 (tsi=0, count = 1)
+[2020/03/18 13:13:48:5171] I: __lws_header_table_detach: nobody usable waiting
+[2020/03/18 13:13:48:5175] I: _lws_destroy_ah: freed ah 0x5669620 : pool length 0
+[2020/03/18 13:13:48:5180] I: __lws_header_table_detach: wsi 0x5669090: ah 0x5669620 (tsi=0, count = 0)
+[2020/03/18 13:13:48:5197] I: _lws_validity_confirmed_role: wsi 0x5669090: setting validity timer 3s (hup 0)
+[2020/03/18 13:13:48:5208] U: callback_minimal_broker: established
+[2020/03/18 13:13:51:5218] I: lws_validity_cb: wsi 0x5669090: scheduling validity check
+[2020/03/18 13:13:51:5325] I: rops_handle_POLLOUT_ws: issuing ping on wsi 0x5669090: ws lws-ping-test h2: 0
+[2020/03/18 13:13:51:5504] I: lws_issue_raw: ssl_capable_write (6) says 6
+[2020/03/18 13:13:51:5809] I: lws_ws_client_rx_sm: client 0x5669090 received pong
+[2020/03/18 13:13:51:5819] I: _lws_validity_confirmed_role: wsi 0x5669090: setting validity timer 3s (hup 0)
+[2020/03/18 13:13:51:5831] I: Client doing pong callback
+[2020/03/18 13:13:54:5821] I: lws_validity_cb: wsi 0x5669090: scheduling validity check
+[2020/03/18 13:13:54:5825] I: rops_handle_POLLOUT_ws: issuing ping on wsi 0x5669090: ws lws-ping-test h2: 0
+[2020/03/18 13:13:54:5833] I: lws_issue_raw: ssl_capable_write (6) says 6
+[2020/03/18 13:13:54:6258] I: lws_ws_client_rx_sm: client 0x5669090 received pong
+[2020/03/18 13:13:54:6261] I: _lws_validity_confirmed_role: wsi 0x5669090: setting validity timer 3s (hup 0)
+[2020/03/18 13:13:54:6263] I: Client doing pong callback
+[2020/03/18 13:13:57:6263] I: lws_validity_cb: wsi 0x5669090: scheduling validity check
+[2020/03/18 13:13:57:6267] I: rops_handle_POLLOUT_ws: issuing ping on wsi 0x5669090: ws lws-ping-test h2: 0
+[2020/03/18 13:13:57:6275] I: lws_issue_raw: ssl_capable_write (6) says 6
+[2020/03/18 13:13:58:0034] I: lws_ws_client_rx_sm: client 0x5669090 received pong
+
 ...
 ```
 
index 4a9fb35..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFWjCCBEKgAwIBAgISA9x0/oj5PLdW46hsmR82/7ytMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5NDBaFw0x
-OTEyMDYwNzA5NDBaMBwxGjAYBgNVBAMTEWxpYndlYnNvY2tldHMub3JnMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPinIkleLmvEcA/YuBss6ASXVi7g
-yr6Sss7cB3vTy7Fp8OB2c1N25prHZxVpORAUo0UreiaY2Ws4NFvDaYp08ZffevuC
-UhThsEJlbkD0uvt7dPapJt9PNJtlxjNFWyvHEy6PijzIaMYDROiStcCJQn7kAew/
-Za2+5kNVgKqT+7OXukJEFdSdVZI6QC/npeQlkIrFSq1WVthCGBNJehxxES0hSWzk
-0gNVKlkD3/SbkupsfUpe73XiawMtrtsSE7cdnul7VZmiP8I/3sJr1+4/3xZ+DEYg
-mVB82B0vd08VJYzU7Nf0pz0PWusAmzRoRn81IXkOfBg9ohlSSEoZhHYS7QIDAQAB
-o4ICZjCCAmIwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
-BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRmKKyGjufWgp7pR2x0tWxG
-D9G+WTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcB
-AQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlw
-dC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlw
-dC5vcmcvMBwGA1UdEQQVMBOCEWxpYndlYnNvY2tldHMub3JnMEwGA1UdIARFMEMw
-CAYGZ4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9j
-cHMubGV0c2VuY3J5cHQub3JnMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcAdH7a
-gzGtMxCRIZzOJU9CcMK//V5CIAjGNzV55hB7zFYAAAFtCsWIfgAABAMASDBGAiEA
-0H55VqSKV3otHK7uHNbcR0QwoUYtCmeObhsqxzCnmDwCIQD3mtuSKrxTD3oA+Yde
-nmTgWfFyS4TNgLNEPCJYo2s75gB1ACk8UZZUyDlluqpQ/FgH1Ldvv1h6KXLcpMMM
-9OVFR/R4AAABbQrFil4AAAQDAEYwRAIgNSpvz/1JA2aP6fh6ujGNuYfrAvWjlxXo
-CJtVGe4XaDYCIGmK1/9tl1uQbVD46P5NswnULq06KQmuOrlI3HO4r86HMA0GCSqG
-SIb3DQEBCwUAA4IBAQBiAlV7wkCsWE99VmZHBmcbZChWyWUHG3LM1hnaQRQjTSYk
-CIlauCpWzlUd6weuvra85KqBbCYo+1hxbwITI796uAdgtHmBE8nj0VltHwKeSq2s
-KKiGXBRT7Z7t0VHYSLOlGOVn1auuQFaWBArc0cQ/m1ZsoHvOiHTlKQvVsA4HnIxA
-CjGY9OOQoh0c36ecbJZ44XKnU9J/OXtDx00aW6QodaZmgMp/OOCghFQUvufkgTUL
-LZid873/8dJVWjAaj1VdadO1nSbdAfBbeWXy93+vg1aAoig80RoscrzYCaNlwmR7
-EO5zWxL3l+xUZogQSJuICgUgNzVB3wjn8HeHGsqt
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
index 49b5d6c..fceee13 100644 (file)
@@ -1,35 +1,45 @@
 /*
  * lws-minimal-ws-client-ping
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
  *
- * This demonstrates a ws client that sends pings from time to time and
- * shows when it receives the PONG
+ * This demonstrates keeping a ws connection validated by the lws validity
+ * timer stuff without having to do anything in the code.  Use debug logging
+ * -d1039 to see lws doing the pings / pongs in the background.
  */
 
 #include <libwebsockets.h>
 #include <string.h>
 #include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 
 static struct lws_context *context;
 static struct lws *client_wsi;
-static int interrupted, zero_length_ping, port = 443,
-          ssl_connection = LCCSCF_USE_SSL;
+static int interrupted, port = 443, ssl_connection = LCCSCF_USE_SSL;
 static const char *server_address = "libwebsockets.org", *pro = "lws-mirror-protocol";
+static lws_sorted_usec_list_t sul;
 
-struct pss {
-       int send_a_ping;
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping = 3,
+       .secs_since_valid_hangup = 10,
 };
 
-static int
-connect_client(void)
+static void
+connect_cb(lws_sorted_usec_list_t *_sul)
 {
        struct lws_client_connect_info i;
 
+       lwsl_notice("%s: connecting\n", __func__);
+
        memset(&i, 0, sizeof(i));
 
        i.context = context;
@@ -40,91 +50,30 @@ connect_client(void)
        i.origin = i.address;
        i.ssl_connection = ssl_connection;
        i.protocol = pro;
+       i.alpn = "h2;http/1.1";
        i.local_protocol_name = "lws-ping-test";
        i.pwsi = &client_wsi;
+       i.retry_and_idle_policy = &retry;
 
-       return !lws_client_connect_via_info(&i);
+       if (!lws_client_connect_via_info(&i))
+               lws_sul_schedule(context, 0, _sul, connect_cb, 5 * LWS_USEC_PER_SEC);
 }
 
 static int
-callback_minimal_broker(struct lws *wsi, enum lws_callback_reasons reason,
-                       void *user, void *in, size_t len)
+callback_minimal_pingtest(struct lws *wsi, enum lws_callback_reasons reason,
+                        void *user, void *in, size_t len)
 {
-       struct pss *pss = (struct pss *)user;
-       int n;
 
        switch (reason) {
 
-       case LWS_CALLBACK_PROTOCOL_INIT:
-               goto try;
-
        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
                lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
                         in ? (char *)in : "(null)");
-               client_wsi = NULL;
-               lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
-                               lws_get_protocol(wsi), LWS_CALLBACK_USER, 1);
+               lws_sul_schedule(context, 0, &sul, connect_cb, 5 * LWS_USEC_PER_SEC);
                break;
 
-       /* --- client callbacks --- */
-
        case LWS_CALLBACK_CLIENT_ESTABLISHED:
                lwsl_user("%s: established\n", __func__);
-               lws_set_timer_usecs(wsi, 5 * LWS_USEC_PER_SEC);
-               break;
-
-       case LWS_CALLBACK_CLIENT_WRITEABLE:
-               if (pss->send_a_ping) {
-                       uint8_t ping[LWS_PRE + 125];
-                       int m;
-
-                       pss->send_a_ping = 0;
-                       n = 0;
-                       if (!zero_length_ping)
-                               n = lws_snprintf((char *)ping + LWS_PRE, 125,
-                                       "ping body!");
-
-                       lwsl_user("Sending PING %d...\n", n);
-
-                       m = lws_write(wsi, ping + LWS_PRE, n, LWS_WRITE_PING);
-                       if (m < n) {
-                               lwsl_err("sending ping failed: %d\n", m);
-
-                               return -1;
-                       }
-                       
-                       lws_callback_on_writable(wsi);
-               }
-               break;
-
-       case LWS_CALLBACK_WS_CLIENT_DROP_PROTOCOL:
-               client_wsi = NULL;
-               lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
-                                              lws_get_protocol(wsi),
-                                              LWS_CALLBACK_USER, 1);
-               break;
-
-       case LWS_CALLBACK_CLIENT_RECEIVE_PONG:
-               lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE_PONG\n");
-               lwsl_hexdump_notice(in, len);
-               break;
-
-       case LWS_CALLBACK_TIMER:
-               /* we want to send a ws PING every few seconds */
-               pss->send_a_ping = 1;
-               lws_callback_on_writable(wsi);
-               lws_set_timer_usecs(wsi, 5 * LWS_USEC_PER_SEC);
-               break;
-
-       /* rate-limited client connect retries */
-
-       case LWS_CALLBACK_USER:
-               lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__);
-try:
-               if (connect_client())
-                       lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
-                                                      lws_get_protocol(wsi),
-                                                      LWS_CALLBACK_USER, 1);
                break;
 
        default:
@@ -137,11 +86,10 @@ try:
 static const struct lws_protocols protocols[] = {
        {
                "lws-ping-test",
-               callback_minimal_broker,
-               sizeof(struct pss),
-               0,
+               callback_minimal_pingtest,
+               0, 0, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 }
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static void
@@ -174,7 +122,7 @@ int main(int argc, const char **argv)
        info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
        info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
        info.protocols = protocols;
-#if defined(LWS_WITH_MBEDTLS)
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
        /*
         * OpenSSL uses the system trust store.  mbedTLS has to be told which
         * CA to trust explicitly.
@@ -182,9 +130,6 @@ int main(int argc, const char **argv)
        info.client_ssl_ca_filepath = "./libwebsockets.org.cer";
 #endif
 
-       if (lws_cmdline_option(argc, argv, "-z"))
-               zero_length_ping = 1;
-
        if ((p = lws_cmdline_option(argc, argv, "--protocol")))
                pro = p;
 
@@ -197,13 +142,6 @@ int main(int argc, const char **argv)
        if ((p = lws_cmdline_option(argc, argv, "--port")))
                port = atoi(p);
 
-       /*
-        * since we know this lws context is only ever going to be used with
-        * one client wsis / fds / sockets at a time, let lws know it doesn't
-        * have to use the default allocations for fd tables up to ulimit -n.
-        * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
-        * will use.
-        */
        info.fd_limit_per_thread = 1 + 1 + 1;
 
        context = lws_create_context(&info);
@@ -212,6 +150,8 @@ int main(int argc, const char **argv)
                return 1;
        }
 
+       lws_sul_schedule(context, 0, &sul, connect_cb, 100);
+
        while (n >= 0 && !interrupted)
                n = lws_service(context, 0);
 
index ace89a5..09fb3e1 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8.9)
+project(lws-minimal-ws-client-pmd-bulk C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-client-pmd-bulk)
 set(SRCS minimal-ws-client-pmd-bulk.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 #require_lws_config(LWS_WITHOUT_EXTENSIONS 0 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 1f6aa47..bdc7058 100644 (file)
@@ -27,9 +27,9 @@
 #include "protocol_lws_minimal_pmd_bulk.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_MINIMAL_PMD_BULK,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted, options;
index a1b38c4..b7f7697 100644 (file)
@@ -65,6 +65,8 @@ struct vhd_minimal_pmd_bulk {
        struct lws_vhost *vhost;
        struct lws *client_wsi;
 
+       lws_sorted_usec_list_t sul;
+
        int *interrupted;
        int *options;
 };
@@ -78,9 +80,11 @@ static uint64_t rng(uint64_t *r)
         return *r;
 }
 
-static int
-connect_client(struct vhd_minimal_pmd_bulk *vhd)
+static void
+sul_connect_attempt(struct lws_sorted_usec_list *sul)
 {
+       struct vhd_minimal_pmd_bulk *vhd =
+               lws_container_of(sul, struct vhd_minimal_pmd_bulk, sul);
        struct lws_client_connect_info i;
 
        memset(&i, 0, sizeof(i));
@@ -96,14 +100,9 @@ connect_client(struct vhd_minimal_pmd_bulk *vhd)
        i.protocol = "lws-minimal-pmd-bulk";
        i.pwsi = &vhd->client_wsi;
 
-       return !lws_client_connect_via_info(&i);
-}
-
-static void
-schedule_callback(struct lws *wsi, int reason, int secs)
-{
-       lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
-               lws_get_protocol(wsi), reason, secs);
+       if (!lws_client_connect_via_info(&i))
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, 10 * LWS_US_PER_SEC);
 }
 
 static int
@@ -138,8 +137,11 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason,
                        (const struct lws_protocol_vhost_options *)in,
                        "options")->value;
 
-               if (connect_client(vhd))
-                       schedule_callback(wsi, LWS_CALLBACK_USER, 1);
+               sul_connect_attempt(&vhd->sul);
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               lws_sul_cancel(&vhd->sul);
                break;
 
        case LWS_CALLBACK_CLIENT_ESTABLISHED:
@@ -177,22 +179,22 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason,
                                size_t s;
 
                                m = pss->position_tx % REPEAT_STRING_LEN;
-                               s = REPEAT_STRING_LEN - m;
+                               s = (unsigned int)(REPEAT_STRING_LEN - m);
                                if (s > (size_t)n)
-                                       s = n;
+                                       s = (unsigned int)n;
                                memcpy(p, &redundant_string[m], s);
-                               pss->position_tx += s;
+                               pss->position_tx += (int)s;
                                p += s;
-                               n -= s;
+                               n -= (int)s;
                        }
                } else {
                        pss->position_tx += n;
                        while (n--)
-                               *p++ = rng(&pss->rng_tx);
+                               *p++ = (uint8_t)rng(&pss->rng_tx);
                }
 
                n = lws_ptr_diff(p, start);
-               m = lws_write(wsi, start, n, flags);
+               m = lws_write(wsi, start, (unsigned int)n, (enum lws_write_protocol)flags);
                if (m < n) {
                        lwsl_err("ERROR %d writing ws\n", m);
                        return -1;
@@ -220,20 +222,20 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason,
                                size_t s;
 
                                m = pss->position_rx % REPEAT_STRING_LEN;
-                               s = REPEAT_STRING_LEN - m;
+                               s = (unsigned int)(REPEAT_STRING_LEN - m);
                                if (s > len)
                                        s = len;
                                if (memcmp(in, &redundant_string[m], s)) {
                                        lwsl_user("echo'd data doesn't match\n");
                                        return -1;
                                }
-                               pss->position_rx += s;
+                               pss->position_rx += (int)s;
                                in = ((unsigned char *)in) + s;
                                len -= s;
                        }
                } else {
                        p = (uint8_t *)in;
-                       pss->position_rx += len;
+                       pss->position_rx += (int)len;
                        while (len--)
                                if (*p++ != (uint8_t)rng(&pss->rng_rx)) {
                                        lwsl_user("echo'd data doesn't match\n");
@@ -253,20 +255,14 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason,
                lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
                         in ? (char *)in : "(null)");
                vhd->client_wsi = NULL;
-               schedule_callback(wsi, LWS_CALLBACK_USER, 1);
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, LWS_US_PER_SEC);
                break;
 
        case LWS_CALLBACK_CLIENT_CLOSED:
                vhd->client_wsi = NULL;
-               schedule_callback(wsi, LWS_CALLBACK_USER, 1);
-               break;
-
-       /* rate-limited client connect retries */
-
-       case LWS_CALLBACK_USER:
-               lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__);
-               if (connect_client(vhd))
-                       schedule_callback(wsi, LWS_CALLBACK_USER, 1);
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, LWS_US_PER_SEC);
                break;
 
        default:
@@ -284,36 +280,3 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason,
                4096, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL_PMD_BULK
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal_pmd_bulk(struct lws_context *context,
-                              struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal_pmd_bulk(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index fb8c938..faad60e 100644 (file)
@@ -1,78 +1,32 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-client-rx C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-client-rx)
 set(SRCS minimal-ws-client.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
+       if (LWS_CTEST_INTERNET_AVAILABLE)
+               add_test(NAME ws-client-rx-warmcat COMMAND lws-minimal-ws-client-rx -t)
+               set_tests_properties(ws-client-rx-warmcat
+                                    PROPERTIES
+                                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/ws-client/minimal-ws-client-rx
+                                    TIMEOUT 20)
+
+       endif()
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
-endif()
\ No newline at end of file
+endif()
index 4a9fb35..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFWjCCBEKgAwIBAgISA9x0/oj5PLdW46hsmR82/7ytMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5NDBaFw0x
-OTEyMDYwNzA5NDBaMBwxGjAYBgNVBAMTEWxpYndlYnNvY2tldHMub3JnMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPinIkleLmvEcA/YuBss6ASXVi7g
-yr6Sss7cB3vTy7Fp8OB2c1N25prHZxVpORAUo0UreiaY2Ws4NFvDaYp08ZffevuC
-UhThsEJlbkD0uvt7dPapJt9PNJtlxjNFWyvHEy6PijzIaMYDROiStcCJQn7kAew/
-Za2+5kNVgKqT+7OXukJEFdSdVZI6QC/npeQlkIrFSq1WVthCGBNJehxxES0hSWzk
-0gNVKlkD3/SbkupsfUpe73XiawMtrtsSE7cdnul7VZmiP8I/3sJr1+4/3xZ+DEYg
-mVB82B0vd08VJYzU7Nf0pz0PWusAmzRoRn81IXkOfBg9ohlSSEoZhHYS7QIDAQAB
-o4ICZjCCAmIwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
-BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRmKKyGjufWgp7pR2x0tWxG
-D9G+WTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcB
-AQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlw
-dC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlw
-dC5vcmcvMBwGA1UdEQQVMBOCEWxpYndlYnNvY2tldHMub3JnMEwGA1UdIARFMEMw
-CAYGZ4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9j
-cHMubGV0c2VuY3J5cHQub3JnMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcAdH7a
-gzGtMxCRIZzOJU9CcMK//V5CIAjGNzV55hB7zFYAAAFtCsWIfgAABAMASDBGAiEA
-0H55VqSKV3otHK7uHNbcR0QwoUYtCmeObhsqxzCnmDwCIQD3mtuSKrxTD3oA+Yde
-nmTgWfFyS4TNgLNEPCJYo2s75gB1ACk8UZZUyDlluqpQ/FgH1Ldvv1h6KXLcpMMM
-9OVFR/R4AAABbQrFil4AAAQDAEYwRAIgNSpvz/1JA2aP6fh6ujGNuYfrAvWjlxXo
-CJtVGe4XaDYCIGmK1/9tl1uQbVD46P5NswnULq06KQmuOrlI3HO4r86HMA0GCSqG
-SIb3DQEBCwUAA4IBAQBiAlV7wkCsWE99VmZHBmcbZChWyWUHG3LM1hnaQRQjTSYk
-CIlauCpWzlUd6weuvra85KqBbCYo+1hxbwITI796uAdgtHmBE8nj0VltHwKeSq2s
-KKiGXBRT7Z7t0VHYSLOlGOVn1auuQFaWBArc0cQ/m1ZsoHvOiHTlKQvVsA4HnIxA
-CjGY9OOQoh0c36ecbJZ44XKnU9J/OXtDx00aW6QodaZmgMp/OOCghFQUvufkgTUL
-LZid873/8dJVWjAaj1VdadO1nSbdAfBbeWXy93+vg1aAoig80RoscrzYCaNlwmR7
-EO5zWxL3l+xUZogQSJuICgUgNzVB3wjn8HeHGsqt
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
index e309260..281a841 100644 (file)
@@ -60,10 +60,9 @@ static const struct lws_protocols protocols[] = {
        {
                "dumb-increment-protocol",
                callback_dumb_increment,
-               0,
-               0,
+               0, 0, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 }
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static void
@@ -99,7 +98,9 @@ int main(int argc, const char **argv)
        info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
        info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
        info.protocols = protocols;
-#if defined(LWS_WITH_MBEDTLS)
+       info.timeout_secs = 10;
+       info.connect_timeout_secs = 30;
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
        /*
         * OpenSSL uses the system trust store.  mbedTLS has to be told which
         * CA to trust explicitly.
diff --git a/minimal-examples/ws-client/minimal-ws-client-rx/selftest.sh b/minimal-examples/ws-client/minimal-ws-client-rx/selftest.sh
deleted file mode 100644 (file)
index 070ef7f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-#
-# $1: path to minimal example binaries...
-#     if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
-#     that will be ./bin from your build dir
-#
-# $2: path for logs and results.  The results will go
-#     in a subdir named after the directory this script
-#     is in
-#
-# $3: offset for test index count
-#
-# $4: total test count
-#
-# $5: path to ./minimal-examples dir in lws
-#
-# Test return code 0: OK, 254: timed out, other: error indication
-
-. $5/selftests-library.sh
-
-COUNT_TESTS=1
-
-dotest $1 $2 warmcat -t
-
-exit $FAILS
diff --git a/minimal-examples/ws-client/minimal-ws-client-spam-tx-rx/CMakeLists.txt b/minimal-examples/ws-client/minimal-ws-client-spam-tx-rx/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5398798
--- /dev/null
@@ -0,0 +1,25 @@
+project(lws-minimal-ws-client-spam-tx-rx C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-ws-client-spam-tx-rx)
+set(SRCS minimal-ws-client.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_WS 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/ws-client/minimal-ws-client-spam-tx-rx/libwebsockets.org.cer b/minimal-examples/ws-client/minimal-ws-client-spam-tx-rx/libwebsockets.org.cer
new file mode 100644 (file)
index 0000000..01ad0dc
--- /dev/null
@@ -0,0 +1,32 @@
+-----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-----
+
diff --git a/minimal-examples/ws-client/minimal-ws-client-spam-tx-rx/minimal-ws-client.c b/minimal-examples/ws-client/minimal-ws-client-spam-tx-rx/minimal-ws-client.c
new file mode 100644 (file)
index 0000000..19a22cc
--- /dev/null
@@ -0,0 +1,226 @@
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
+
+static int nclients = 11;
+unsigned char msg[LWS_PRE+128];
+static int message_delay = 500000; // microseconds
+static int connection_delay = 100000; // microseconds
+static struct lws_context *context;
+static const char *server_address = "localhost", *pro = "lws-minimal";
+static int interrupted = 0, port = 7681, ssl_connection = 0;
+
+static int connect_client()
+{
+       struct lws_client_connect_info i;
+
+       memset(&i, 0, sizeof(i));
+
+       i.context = context;
+       i.port = port;
+       i.address = server_address;
+       i.path = "/";
+       i.host = i.address;
+       i.origin = i.address;
+       i.ssl_connection = ssl_connection;
+       i.protocol = pro;
+       i.local_protocol_name = pro;
+
+       //usleep(connection_delay);
+       lwsl_notice("%s: connection %s:%d\n", __func__, i.address, i.port);
+       if (!lws_client_connect_via_info(&i)) return 1;
+
+       return 0;
+}
+
+static int
+callback(struct lws *wsi, enum lws_callback_reasons reason,
+               void *user, void *in, size_t len)
+{
+       int m= 0, n = 0;
+       short r;
+#if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
+       size_t remain;
+       int first = 0, final = 0;
+#endif
+
+       //lwsl_notice("callback called with reason %d\n", reason);
+       switch (reason) {
+
+       case LWS_CALLBACK_PROTOCOL_INIT:
+               for (n = 0; n < nclients; n++)
+                       connect_client();
+               break;
+
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in :
+                               "(null)");
+               if(--nclients == 0) interrupted = 1;
+               break;
+
+               /* --- client callbacks --- */
+
+       case LWS_CALLBACK_CLIENT_ESTABLISHED:
+               lws_callback_on_writable(wsi);
+               lwsl_user("%s: established connection, wsi = %p\n",
+                               __func__, wsi);
+               break;
+
+       case LWS_CALLBACK_CLIENT_CLOSED:
+               lwsl_user("%s: CLOSED\n", __func__);
+               if(--nclients == 0) interrupted = 1;
+               break;
+
+       case LWS_CALLBACK_CLIENT_WRITEABLE:
+
+               m = lws_write(wsi, msg + LWS_PRE, 128, LWS_WRITE_TEXT);
+               if (m < 128) {
+                       lwsl_err("sending message failed: %d < %d\n", m, n);
+                       return -1;
+               }
+
+               /*
+                * Schedule the timer after minimum message delay plus the
+                * random number of centiseconds.
+                */
+               if (lws_get_random(lws_get_context(wsi), &r, 2) == 2) {
+                       n = message_delay + 10000*(r % 100);
+                       lwsl_debug("set timer on %d usecs\n", n);
+                       lws_set_timer_usecs(wsi, n);
+               }
+               break;
+
+       case LWS_CALLBACK_TIMER:
+               // Let the main loop know we want to send another message to the
+               // server
+               lws_callback_on_writable(wsi);
+               break;
+
+       case LWS_CALLBACK_CLIENT_RECEIVE:
+#if defined(_DEBUG) && !defined(LWS_WITH_NO_LOGS)
+               first = lws_is_first_fragment(wsi);
+               final = lws_is_final_fragment(wsi);
+               remain = lws_remaining_packet_payload(wsi);
+               lwsl_debug("LWS_CALLBACK_RECEIVE: len = %lu, first = %d, "
+                          "final = %d, remains = %lu\n",
+                          (unsigned long)len, first, final,
+                          (unsigned long)remain);
+#endif
+               break;
+
+       case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
+               lwsl_notice("server initiated connection close: len = %lu, "
+                           "in = %s\n", (unsigned long)len, (char*)in);
+               return 0;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static const struct lws_protocols protocols[] = {
+               { "spam-rx-tx", callback, 4096, 4096, 0, NULL, 0 },
+               LWS_PROTOCOL_LIST_TERM
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       const char *p;
+       int n = 0, logs =
+                       LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+#ifndef WIN32
+       srandom((unsigned int)time(0));
+#endif
+
+       memset(msg, 'x', sizeof(msg));
+
+       signal(SIGINT, sigint_handler);
+
+       if (lws_cmdline_option(argc, argv, "-d"))
+               logs |= LLL_INFO | LLL_DEBUG;
+
+       lws_set_log_level(logs, NULL);
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
+       info.protocols = protocols;
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+       /*
+        * OpenSSL uses the system trust store.  mbedTLS has to be told which
+        * CA to trust explicitly.
+        */
+       info.client_ssl_ca_filepath = "./libwebsockets.org.cer";
+#endif
+
+       if ((p = lws_cmdline_option(argc, argv, "-h"))) {
+               server_address = p;
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "-s"))) {
+               ssl_connection |=
+                               LCCSCF_USE_SSL |
+                               LCCSCF_ALLOW_SELFSIGNED |
+                               LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "-p"))) {
+               port = atoi(p);
+               if (port > 65535 || port < 0)
+                       return 1;
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "-n"))) {
+               n = atoi(p);
+               if (n < 1)
+                       n = 1;
+               if (n > LWS_MAX_SMP)
+                       n = LWS_MAX_SMP;
+               if (n < nclients)
+                       nclients = n;
+               lwsl_notice("Start test clients: %d\n", nclients);
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "-c"))) {
+               connection_delay = atoi(p);
+               lwsl_notice("Connection delay: %d\n", connection_delay);
+       }
+
+       if ((p = lws_cmdline_option(argc, argv, "-m"))) {
+               message_delay = atoi(p);
+               lwsl_notice("Message delay: %d\n", connection_delay);
+       }
+
+       info.fd_limit_per_thread = (unsigned int)(1 + nclients + 1);
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lwsl_notice("%s: exiting service loop. n = %d, interrupted = %d\n",
+                       __func__, n, interrupted);
+
+       lws_context_destroy(context);
+
+       return 0;
+}
index 25b9d72..34164e1 100644 (file)
@@ -1,90 +1,86 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-client-spam C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckIncludeFile)
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-client-spam)
 set(SRCS minimal-ws-client-spam.c)
 
-MACRO(require_pthreads result)
-       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
-       if (NOT LWS_HAVE_PTHREAD_H)
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(result 0)
-               else()
-                       message(FATAL_ERROR "threading support requires pthreads")
-               endif()
-       endif()
-ENDMACRO()
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
+set(requirements 1)
+require_pthreads(requirements)
+require_lws_config(LWS_ROLE_WS 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
 
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+       find_program(VALGRIND "valgrind")
+       #
+       # instantiate the server per sai builder instance, they are running in the same
+       # machine context in parallel so they can tread on each other otherwise
+       #
+       set(PORT_WCS_SRV "7620")
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "0")
+              set(PORT_WCS_SRV 7621)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "1")
+              set(PORT_WCS_SRV 7622)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "2")
+              set(PORT_WCS_SRV 7623)
+       endif()
+       if ("$ENV{SAI_INSTANCE_IDX}" STREQUAL "3")
+              set(PORT_WCS_SRV 7624)
+       endif()
 
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
+# hack
+if (WIN32)
+else()
 
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
+if (LWS_WITH_SERVER)
+if (WIN32)
+       add_test(NAME st_wcs_srv COMMAND cmd.exe /c start /b $<TARGET_FILE:test-server> -s --port ${PORT_WCS_SRV})
+       add_test(NAME ki_wcs_srv COMMAND taskkill /F /IM $<TARGET_FILE_NAME:test-server> /T)
+else()
+       if (VALGRIND)
+               add_test(NAME st_wcs_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                       wcs_srv ${VALGRIND} --tool=memcheck $<TARGET_FILE:test-server>
+                               -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/
+                               -s --port ${PORT_WCS_SRV} )
+               add_test(NAME ki_wcs_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                       wcs_srv ${VALGRIND} $<TARGET_FILE_NAME:test-server> --port ${PORT_WCS_SRV})
        else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
+               add_test(NAME st_wcs_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh
+                       wcs_srv $<TARGET_FILE:test-server>
+                               -r ${CMAKE_SOURCE_DIR}/destdir/usr/local/share/libwebsockets-test-server/
+                               -s --port ${PORT_WCS_SRV} )
+               add_test(NAME ki_wcs_srv COMMAND
+                       ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh
+                       wcs_srv $<TARGET_FILE_NAME:test-server> --port ${PORT_WCS_SRV})
        endif()
-ENDMACRO()
+endif()
 
-set(requirements 1)
-require_pthreads(requirements)
-require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+       set_tests_properties(st_wcs_srv PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP wcs_srv TIMEOUT 800)
+       set_tests_properties(ki_wcs_srv PROPERTIES FIXTURES_CLEANUP wcs_srv)
 
-if (requirements)
-       add_executable(${SAMP} ${SRCS})
+       add_test(NAME ws-client-spam COMMAND lws-minimal-ws-client-spam --server localhost --port ${PORT_WCS_SRV} -l 32 -c 3)
+       set_tests_properties(ws-client-spam PROPERTIES
+                            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/ws-client/minimal-ws-client-spam
+                            FIXTURES_REQUIRED "wcs_srv"
+                            TIMEOUT 40)
+endif()
+endif()
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared pthread)
-               add_dependencies(${SAMP} websockets_shared pthread)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets pthread)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 4a9fb35..01ad0dc 100644 (file)
@@ -1,58 +1,32 @@
 -----BEGIN CERTIFICATE-----
-MIIFWjCCBEKgAwIBAgISA9x0/oj5PLdW46hsmR82/7ytMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTA5MDcwNzA5NDBaFw0x
-OTEyMDYwNzA5NDBaMBwxGjAYBgNVBAMTEWxpYndlYnNvY2tldHMub3JnMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPinIkleLmvEcA/YuBss6ASXVi7g
-yr6Sss7cB3vTy7Fp8OB2c1N25prHZxVpORAUo0UreiaY2Ws4NFvDaYp08ZffevuC
-UhThsEJlbkD0uvt7dPapJt9PNJtlxjNFWyvHEy6PijzIaMYDROiStcCJQn7kAew/
-Za2+5kNVgKqT+7OXukJEFdSdVZI6QC/npeQlkIrFSq1WVthCGBNJehxxES0hSWzk
-0gNVKlkD3/SbkupsfUpe73XiawMtrtsSE7cdnul7VZmiP8I/3sJr1+4/3xZ+DEYg
-mVB82B0vd08VJYzU7Nf0pz0PWusAmzRoRn81IXkOfBg9ohlSSEoZhHYS7QIDAQAB
-o4ICZjCCAmIwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
-BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRmKKyGjufWgp7pR2x0tWxG
-D9G+WTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcB
-AQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlw
-dC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlw
-dC5vcmcvMBwGA1UdEQQVMBOCEWxpYndlYnNvY2tldHMub3JnMEwGA1UdIARFMEMw
-CAYGZ4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9j
-cHMubGV0c2VuY3J5cHQub3JnMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcAdH7a
-gzGtMxCRIZzOJU9CcMK//V5CIAjGNzV55hB7zFYAAAFtCsWIfgAABAMASDBGAiEA
-0H55VqSKV3otHK7uHNbcR0QwoUYtCmeObhsqxzCnmDwCIQD3mtuSKrxTD3oA+Yde
-nmTgWfFyS4TNgLNEPCJYo2s75gB1ACk8UZZUyDlluqpQ/FgH1Ldvv1h6KXLcpMMM
-9OVFR/R4AAABbQrFil4AAAQDAEYwRAIgNSpvz/1JA2aP6fh6ujGNuYfrAvWjlxXo
-CJtVGe4XaDYCIGmK1/9tl1uQbVD46P5NswnULq06KQmuOrlI3HO4r86HMA0GCSqG
-SIb3DQEBCwUAA4IBAQBiAlV7wkCsWE99VmZHBmcbZChWyWUHG3LM1hnaQRQjTSYk
-CIlauCpWzlUd6weuvra85KqBbCYo+1hxbwITI796uAdgtHmBE8nj0VltHwKeSq2s
-KKiGXBRT7Z7t0VHYSLOlGOVn1auuQFaWBArc0cQ/m1ZsoHvOiHTlKQvVsA4HnIxA
-CjGY9OOQoh0c36ecbJZ44XKnU9J/OXtDx00aW6QodaZmgMp/OOCghFQUvufkgTUL
-LZid873/8dJVWjAaj1VdadO1nSbdAfBbeWXy93+vg1aAoig80RoscrzYCaNlwmR7
-EO5zWxL3l+xUZogQSJuICgUgNzVB3wjn8HeHGsqt
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+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-----
+
index ec6f523..62580ee 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lws-minimal-ws-client-spam
  *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
  *
  * This file is made available under the Creative Commons CC0 1.0
  * Universal Public Domain Dedication.
 #include <libwebsockets.h>
 #include <string.h>
 #include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 
 enum {
@@ -64,6 +70,7 @@ connect_client(int idx)
        clients[idx].state = CLIENT_CONNECTING;
        tries++;
 
+       lwsl_notice("%s: connection %s:%d\n", __func__, i.address, i.port);
        if (!lws_client_connect_via_info(&i)) {
                clients[idx].wsi = NULL;
                clients[idx].state = CLIENT_IDLE;
@@ -103,8 +110,10 @@ callback_minimal_spam(struct lws *wsi, enum lws_callback_reasons reason,
                                break;
                        }
                }
-               if (tries == closed + errors)
+               if (tries == closed + errors) {
                        interrupted = 1;
+                       lws_cancel_service(lws_get_context(wsi));
+               }
                break;
 
        /* --- client callbacks --- */
@@ -119,8 +128,10 @@ callback_minimal_spam(struct lws *wsi, enum lws_callback_reasons reason,
 
        case LWS_CALLBACK_CLIENT_CLOSED:
                closed++;
-               if (tries == closed + errors)
+               if (tries == closed + errors) {
                        interrupted = 1;
+                       lws_cancel_service(lws_get_context(wsi));
+               }
                if (tries == limit) {
                        lwsl_user("%s: leaving CLOSED (try %d, est %d, sent %d, closed %d, err %d)\n",
                                        __func__, tries, est, sent, closed, errors);
@@ -143,7 +154,7 @@ callback_minimal_spam(struct lws *wsi, enum lws_callback_reasons reason,
                n = lws_snprintf((char *)ping + LWS_PRE, sizeof(ping) - LWS_PRE,
                                          "hello %d", pss->conn);
 
-               m = lws_write(wsi, ping + LWS_PRE, n, LWS_WRITE_TEXT);
+               m = lws_write(wsi, ping + LWS_PRE, (unsigned int)n, LWS_WRITE_TEXT);
                if (m < n) {
                        lwsl_err("sending ping failed: %d\n", m);
 
@@ -164,9 +175,16 @@ static const struct lws_protocols protocols[] = {
                "lws-spam-test",
                callback_minimal_spam,
                sizeof(struct pss),
-               0,
+               0, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 }
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static struct lws_protocol_vhost_options pvo = {
+        NULL,                  /* "next" pvo linked-list */
+        NULL,                 /* "child" pvo linked-list */
+        "lws-spam-test",        /* protocol name we belong to on this vhost */
+        "OK"                     /* ignored */
 };
 
 static void
@@ -199,7 +217,8 @@ int main(int argc, const char **argv)
        info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
        info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
        info.protocols = protocols;
-#if defined(LWS_WITH_MBEDTLS)
+       info.pvo = &pvo;
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
        /*
         * OpenSSL uses the system trust store.  mbedTLS has to be told which
         * CA to trust explicitly.
@@ -241,7 +260,7 @@ int main(int argc, const char **argv)
         * It will just allocate for 1 internal and n (+ 1 http2 nwsi) that we
         * will use.
         */
-       info.fd_limit_per_thread = 1 + concurrent + 1;
+       info.fd_limit_per_thread = (unsigned int)(1 + concurrent + 1);
 
        context = lws_create_context(&info);
        if (!context) {
@@ -252,6 +271,8 @@ int main(int argc, const char **argv)
        while (n >= 0 && !interrupted)
                n = lws_service(context, 0);
 
+       lwsl_notice("%s: exiting service loop\n", __func__);
+
        lws_context_destroy(context);
 
        if (tries == limit && closed == tries) {
index 47f2dc6..45d75c0 100644 (file)
@@ -1,90 +1,26 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-client-tx C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckIncludeFile)
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-client-tx)
 set(SRCS minimal-ws-client.c)
 
-MACRO(require_pthreads result)
-       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
-       if (NOT LWS_HAVE_PTHREAD_H)
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(result 0)
-               else()
-                       message(FATAL_ERROR "threading support requires pthreads")
-               endif()
-       endif()
-ENDMACRO()
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_pthreads(requirements)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_CLIENT 0 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared pthread)
-               add_dependencies(${SAMP} websockets_shared pthread)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets pthread)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
\ No newline at end of file
index 137201d..dd8757c 100644 (file)
 #include <libwebsockets.h>
 #include <string.h>
 #include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 
 static int interrupted;
@@ -38,6 +44,8 @@ struct per_vhost_data__minimal {
        const struct lws_protocols *protocol;
        pthread_t pthread_spam[2];
 
+       lws_sorted_usec_list_t sul;
+
        pthread_mutex_t lock_ring; /* serialize access to the ring buffer */
        struct lws_ring *ring; /* ringbuffer holding unsent messages */
        uint32_t tail;
@@ -70,7 +78,11 @@ thread_spam(void *d)
        struct per_vhost_data__minimal *vhd =
                        (struct per_vhost_data__minimal *)d;
        struct msg amsg;
-       int len = 128, index = 1, n;
+       int len = 128, index = 1, n, whoami = 0;
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
+               if (pthread_equal(pthread_self(), vhd->pthread_spam[n]))
+                       whoami = n + 1;
 
        do {
                /* don't generate output if client not connected */
@@ -86,16 +98,15 @@ thread_spam(void *d)
                        goto wait_unlock;
                }
 
-               amsg.payload = malloc(LWS_PRE + len);
+               amsg.payload = malloc((unsigned int)(LWS_PRE + len));
                if (!amsg.payload) {
                        lwsl_user("OOM: dropping\n");
                        goto wait_unlock;
                }
-               n = lws_snprintf((char *)amsg.payload + LWS_PRE, len,
-                                "tid: %p, msg: %d",
-                                (void *)pthread_self(), index++);
-               amsg.len = n;
-               n = lws_ring_insert(vhd->ring, &amsg, 1);
+               n = lws_snprintf((char *)amsg.payload + LWS_PRE, (unsigned int)len,
+                                "tid: %d, msg: %d", whoami, index++);
+               amsg.len = (unsigned int)n;
+               n = (int)lws_ring_insert(vhd->ring, &amsg, 1);
                if (n != 1) {
                        __minimal_destroy_message(&amsg);
                        lwsl_user("dropping!\n");
@@ -114,16 +125,19 @@ wait:
 
        } while (!vhd->finished);
 
-       lwsl_notice("thread_spam %p exiting\n", (void *)pthread_self());
+       lwsl_notice("thread_spam %d exiting\n", whoami);
 
        pthread_exit(NULL);
 
        return NULL;
 }
 
-static int
-connect_client(struct per_vhost_data__minimal *vhd)
+static void
+sul_connect_attempt(struct lws_sorted_usec_list *sul)
 {
+       struct per_vhost_data__minimal *vhd =
+               lws_container_of(sul, struct per_vhost_data__minimal, sul);
+
        vhd->i.context = vhd->context;
        vhd->i.port = 7681;
        vhd->i.address = "localhost";
@@ -135,7 +149,9 @@ connect_client(struct per_vhost_data__minimal *vhd)
        vhd->i.protocol = "lws-minimal-broker";
        vhd->i.pwsi = &vhd->client_wsi;
 
-       return !lws_client_connect_via_info(&vhd->i);
+       if (!lws_client_connect_via_info(&vhd->i))
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, 10 * LWS_US_PER_SEC);
 }
 
 static int
@@ -179,21 +195,19 @@ callback_minimal_broker(struct lws *wsi, enum lws_callback_reasons reason,
                                goto init_fail;
                        }
 
-               if (connect_client(vhd))
-                       lws_timed_callback_vh_protocol(vhd->vhost,
-                                       vhd->protocol, LWS_CALLBACK_USER, 1);
+               sul_connect_attempt(&vhd->sul);
                break;
 
        case LWS_CALLBACK_PROTOCOL_DESTROY:
 init_fail:
                vhd->finished = 1;
                for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
-                       if (vhd->pthread_spam[n])
-                               pthread_join(vhd->pthread_spam[n], &retval);
+                       pthread_join(vhd->pthread_spam[n], &retval);
 
                if (vhd->ring)
                        lws_ring_destroy(vhd->ring);
 
+               lws_sul_cancel(&vhd->sul);
                pthread_mutex_destroy(&vhd->lock_ring);
 
                return r;
@@ -202,8 +216,8 @@ init_fail:
                lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
                         in ? (char *)in : "(null)");
                vhd->client_wsi = NULL;
-               lws_timed_callback_vh_protocol(vhd->vhost,
-                               vhd->protocol, LWS_CALLBACK_USER, 1);
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, LWS_US_PER_SEC);
                break;
 
        /* --- client callbacks --- */
@@ -242,8 +256,8 @@ skip:
        case LWS_CALLBACK_CLIENT_CLOSED:
                vhd->client_wsi = NULL;
                vhd->established = 0;
-               lws_timed_callback_vh_protocol(vhd->vhost, vhd->protocol,
-                                              LWS_CALLBACK_USER, 1);
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_connect_attempt, LWS_US_PER_SEC);
                break;
 
        case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
@@ -259,16 +273,6 @@ skip:
                        lws_callback_on_writable(vhd->client_wsi);
                break;
 
-       /* rate-limited client connect retries */
-
-       case LWS_CALLBACK_USER:
-               lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__);
-               if (connect_client(vhd))
-                       lws_timed_callback_vh_protocol(vhd->vhost,
-                                               vhd->protocol,
-                                               LWS_CALLBACK_USER, 1);
-               break;
-
        default:
                break;
        }
@@ -280,10 +284,9 @@ static const struct lws_protocols protocols[] = {
        {
                "lws-minimal-broker",
                callback_minimal_broker,
-               0,
-               0,
+               0, 0, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 }
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static void
diff --git a/minimal-examples/ws-client/minimal-ws-client/CMakeLists.txt b/minimal-examples/ws-client/minimal-ws-client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9638145
--- /dev/null
@@ -0,0 +1,25 @@
+project(lws-minimal-ws-client-ping C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-ws-client)
+set(SRCS minimal-ws-client.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_WS 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
diff --git a/minimal-examples/ws-client/minimal-ws-client/README.md b/minimal-examples/ws-client/minimal-ws-client/README.md
new file mode 100644 (file)
index 0000000..5cf297b
--- /dev/null
@@ -0,0 +1,59 @@
+# lws minimal ws client
+
+This connects to libwebsockets.org using the dumb-increment-protocol.
+
+It demonstrates how to use the connection retry and backoff stuff in lws.
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## Commandline Options
+
+Option|Meaning
+---|---
+-d|Set logging verbosity
+-s|Use a specific server instead of libwebsockets.org, eg `--server localhost`.  Implies LCCSCF_ALLOW_SELFSIGNED
+-p|Use a specific port instead of 443, eg `--port 7681`
+-j|Allow selfsigned tls cert
+-k|Allow insecure certs
+-m|Skip server hostname check
+-n|Skip tls usage
+-e|Allow expired certs
+--protocol|Use a specific ws subprotocol rather than dumb-increment-protocol, eg, `--protocol myprotocol`
+
+
+## usage
+
+Just run it, it will connect to libwebsockets.org and spew incrementing numbers
+sent by the server at 20Hz
+
+```
+ $ ./lws-minimal-ws-client
+[2020/01/22 05:38:47:3409] U: LWS minimal ws client
+[2020/01/22 05:38:47:4456] N: Loading client CA for verification ./libwebsockets.org.cer
+[2020/01/22 05:38:48:1649] U: callback_minimal: established
+[2020/01/22 05:38:48:1739] N: 
+[2020/01/22 05:38:48:1763] N: 0000: 30                                                 0               
+[2020/01/22 05:38:48:1765] N: 
+
+...
+```
+
+To test against the lws test server instead of libwebsockets.org, run the test
+server as
+
+```
+$ libwebsockets-test-server -s
+```
+
+and run this test app with
+
+```
+$ ./lws-minimal-ws-client -s localhost -p 7681 -j
+```
+
+You can kill and restart the server to confirm the client connection is re-
+established if done within the backoff period.
diff --git a/minimal-examples/ws-client/minimal-ws-client/libwebsockets.org.cer b/minimal-examples/ws-client/minimal-ws-client/libwebsockets.org.cer
new file mode 100644 (file)
index 0000000..01ad0dc
--- /dev/null
@@ -0,0 +1,32 @@
+-----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-----
+
diff --git a/minimal-examples/ws-client/minimal-ws-client/minimal-ws-client.c b/minimal-examples/ws-client/minimal-ws-client/minimal-ws-client.c
new file mode 100644 (file)
index 0000000..70b2461
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * lws-minimal-ws-client
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a ws client that connects by default to libwebsockets.org
+ * dumb increment ws server.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+
+/*
+ * This represents your object that "contains" the client connection and has
+ * the client connection bound to it
+ */
+
+static struct my_conn {
+       lws_sorted_usec_list_t  sul;         /* schedule connection retry */
+       struct lws              *wsi;        /* related wsi if any */
+       uint16_t                retry_count; /* count of consequetive retries */
+} mco;
+
+static struct lws_context *context;
+static int interrupted, port = 443, ssl_connection = LCCSCF_USE_SSL;
+static const char *server_address = "libwebsockets.org",
+                 *pro = "dumb-increment-protocol";
+
+/*
+ * The retry and backoff policy we want to use for our client connections
+ */
+
+static const uint32_t backoff_ms[] = { 1000, 2000, 3000, 4000, 5000 };
+
+static const lws_retry_bo_t retry = {
+       .retry_ms_table                 = backoff_ms,
+       .retry_ms_table_count           = LWS_ARRAY_SIZE(backoff_ms),
+       .conceal_count                  = LWS_ARRAY_SIZE(backoff_ms),
+
+       .secs_since_valid_ping          = 3,  /* force PINGs after secs idle */
+       .secs_since_valid_hangup        = 10, /* hangup after secs idle */
+
+       .jitter_percent                 = 20,
+};
+
+/*
+ * Scheduled sul callback that starts the connection attempt
+ */
+
+static void
+connect_client(lws_sorted_usec_list_t *sul)
+{
+       struct my_conn *mco = lws_container_of(sul, struct my_conn, sul);
+       struct lws_client_connect_info i;
+
+       memset(&i, 0, sizeof(i));
+
+       i.context = context;
+       i.port = port;
+       i.address = server_address;
+       i.path = "/";
+       i.host = i.address;
+       i.origin = i.address;
+       i.ssl_connection = ssl_connection;
+       i.protocol = pro;
+       i.local_protocol_name = "lws-minimal-client";
+       i.pwsi = &mco->wsi;
+       i.retry_and_idle_policy = &retry;
+       i.userdata = mco;
+
+       if (!lws_client_connect_via_info(&i))
+               /*
+                * Failed... schedule a retry... we can't use the _retry_wsi()
+                * convenience wrapper api here because no valid wsi at this
+                * point.
+                */
+               if (lws_retry_sul_schedule(context, 0, sul, &retry,
+                                          connect_client, &mco->retry_count)) {
+                       lwsl_err("%s: connection attempts exhausted\n", __func__);
+                       interrupted = 1;
+               }
+}
+
+static int
+callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
+                void *user, void *in, size_t len)
+{
+       struct my_conn *mco = (struct my_conn *)user;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+               goto do_retry;
+               break;
+
+       case LWS_CALLBACK_CLIENT_RECEIVE:
+               lwsl_hexdump_notice(in, len);
+               break;
+
+       case LWS_CALLBACK_CLIENT_ESTABLISHED:
+               lwsl_user("%s: established\n", __func__);
+               break;
+
+       case LWS_CALLBACK_CLIENT_CLOSED:
+               goto do_retry;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+
+do_retry:
+       /*
+        * retry the connection to keep it nailed up
+        *
+        * For this example, we try to conceal any problem for one set of
+        * backoff retries and then exit the app.
+        *
+        * If you set retry.conceal_count to be larger than the number of
+        * elements in the backoff table, it will never give up and keep
+        * retrying at the last backoff delay plus the random jitter amount.
+        */
+       if (lws_retry_sul_schedule_retry_wsi(wsi, &mco->sul, connect_client,
+                                            &mco->retry_count)) {
+               lwsl_err("%s: connection attempts exhausted\n", __func__);
+               interrupted = 1;
+       }
+
+       return 0;
+}
+
+static const struct lws_protocols protocols[] = {
+       { "lws-minimal-client", callback_minimal, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static void
+sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       const char *p;
+       int n = 0;
+
+       signal(SIGINT, sigint_handler);
+       memset(&info, 0, sizeof info);
+       lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+       lwsl_user("LWS minimal ws client\n");
+
+       info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+       info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
+       info.protocols = protocols;
+
+#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
+       /*
+        * OpenSSL uses the system trust store.  mbedTLS has to be told which
+        * CA to trust explicitly.
+        */
+       info.client_ssl_ca_filepath = "./libwebsockets.org.cer";
+#endif
+
+       if ((p = lws_cmdline_option(argc, argv, "--protocol")))
+               pro = p;
+
+       if ((p = lws_cmdline_option(argc, argv, "-s")))
+               server_address = p;
+
+       if ((p = lws_cmdline_option(argc, argv, "-p")))
+               port = atoi(p);
+
+       if (lws_cmdline_option(argc, argv, "-n"))
+               ssl_connection &= ~LCCSCF_USE_SSL;
+
+       if (lws_cmdline_option(argc, argv, "-j"))
+               ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
+
+       if (lws_cmdline_option(argc, argv, "-k"))
+               ssl_connection |= LCCSCF_ALLOW_INSECURE;
+
+       if (lws_cmdline_option(argc, argv, "-m"))
+               ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
+
+       if (lws_cmdline_option(argc, argv, "-e"))
+               ssl_connection |= LCCSCF_ALLOW_EXPIRED;
+
+       info.fd_limit_per_thread = 1 + 1 + 1;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       /* schedule the first client connection attempt to happen immediately */
+       lws_sul_schedule(context, 0, &mco.sul, connect_client, 1);
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+       lwsl_user("Completed\n");
+
+       return 0;
+}
index 719147d..0972dd3 100644 (file)
@@ -1,77 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-broker C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-broker)
 set(SRCS minimal-ws-broker.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
\ No newline at end of file
index 88ee988..cab9af5 100644 (file)
@@ -22,9 +22,9 @@
 #include "protocol_lws_minimal.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_MINIMAL,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
index 61c7617..67c8776 100644 (file)
@@ -27,15 +27,12 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
 document.addEventListener("DOMContentLoaded", function() {
 
-       subscriber_ws = new_ws(get_appropriate_ws_url(""), "lws-minimal-broker");
+       var subscriber_ws = new_ws(get_appropriate_ws_url(""), "lws-minimal-broker");
        try {
                subscriber_ws.onopen = function() {
                        document.getElementById("b").disabled = 0;
@@ -55,7 +52,7 @@ document.addEventListener("DOMContentLoaded", function() {
                alert("<p>Error " + exception);  
        }
        
-       publisher_ws = new_ws(get_appropriate_ws_url("/publisher"), "lws-minimal-broker");
+       var publisher_ws = new_ws(get_appropriate_ws_url("/publisher"), "lws-minimal-broker");
        try {
                publisher_ws.onopen = function() {
                        document.getElementById("m").disabled = 0;
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 4ee8981..0ed24e6 100644 (file)
@@ -215,36 +215,3 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                128, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal(struct lws_context *context,
-                     struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal(struct lws_context *context)
-{
-       return 0;
-}
-#endif
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/CMakeLists.txt b/minimal-examples/ws-server/minimal-ws-raw-proxy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3730212
--- /dev/null
@@ -0,0 +1,25 @@
+project(lws-minimal-ws-raw-proxy C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-ws-raw-proxy)
+set(SRCS minimal-ws-raw-proxy.c)
+
+set(requirements 1)
+require_lws_config(LWS_ROLE_WS 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_CLIENT 1 requirements)
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+
+       if (websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
+               add_dependencies(${SAMP} websockets_shared)
+       else()
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
+       endif()
+endif()
\ No newline at end of file
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/README.md b/minimal-examples/ws-server/minimal-ws-raw-proxy/README.md
new file mode 100644 (file)
index 0000000..687162e
--- /dev/null
@@ -0,0 +1,54 @@
+# lws minimal ws - raw proxy
+
+This demonstrates how to use a proxy connection object to bind together two or
+more connections in a proxy.  This particular example has a ws server that
+creates an onward "raw" client connection to 127.0.0.1:1234.
+
+You can make a suitable "raw server" with
+
+```
+$ nc -l 127.0.0.1 1234
+```
+
+## build
+
+```
+ $ cmake . && make
+```
+
+## Commandline Options
+
+Option|Meaning
+---|---
+-d|Set logging verbosity
+
+
+## usage
+
+```
+ $ ./lws-minimal-ws-raw-proxy
+[2021/03/04 21:14:45:0540] U: LWS minimal ws-raw proxy | visit http://localhost:7681 (-s = use TLS / https)
+[2021/03/04 21:14:45:0898] N: LWS: 4.1.99-v4.1.0-294-g2776b4ce65, loglevel 1031
+[2021/03/04 21:14:45:0902] N: NET CLI SRV H1 H2 WS SS-JSON-POL SSPROX IPV6-on
+[2021/03/04 21:14:45:1146] N:  ++ [3224086|wsi|0|pipe] (1)
+[2021/03/04 21:14:45:1203] N:  ++ [3224086|vh|0|netlink] (1)
+[2021/03/04 21:14:45:1284] N:  ++ [3224086|vh|1|localhost||7681] (2)
+[2021/03/04 21:14:45:1401] N: lws_socket_bind: nowsi: source ads ::
+[2021/03/04 21:14:45:1425] N:  ++ [3224086|wsi|1|listen|localhost||7681] (2)
+[2021/03/04 21:14:46:1164] N:  ++ [3224086|wsisrv|0|adopted] (1)
+[2021/03/04 21:14:46:2771] N:  ++ [3224086|wsisrv|1|adopted] (2)
+[2021/03/04 21:14:46:3159] N:  ++ [3224086|wsicli|0|RAW/raw-skt/127.0.0.1] (1)
+[2021/03/04 21:14:46:3451] N:  ++ [3224086|wsisrv|2|adopted] (3)
+
+```
+
+Visit http://localhost:7681 in a browser... it loads JS that opens a ws
+connection to the proxy's ws server side.  That causes the proxy to open a
+raw client connection to 127.0.0.1:1234, and forward anything you type in the
+browser to the raw server, and anything typed in the raw server (you must
+press enter on netcat to get it sent) is proxied back to the browser.
+
+The proxy can handle many ws connections each with their individual onward
+raw client connections, so you could open multiple browser windows.  But you
+will need a better "raw server" than netcat, which is restricted to just the
+one peer at a time. 
\ No newline at end of file
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/localhost-100y.cert b/minimal-examples/ws-server/minimal-ws-raw-proxy/localhost-100y.cert
new file mode 100644 (file)
index 0000000..6f372db
--- /dev/null
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF5jCCA86gAwIBAgIJANq50IuwPFKgMA0GCSqGSIb3DQEBCwUAMIGGMQswCQYD
+VQQGEwJHQjEQMA4GA1UECAwHRXJld2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEb
+MBkGA1UECgwSbGlid2Vic29ja2V0cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3Qx
+HzAdBgkqhkiG9w0BCQEWEG5vbmVAaW52YWxpZC5vcmcwIBcNMTgwMzIwMDQxNjA3
+WhgPMjExODAyMjQwNDE2MDdaMIGGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRXJl
+d2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEbMBkGA1UECgwSbGlid2Vic29ja2V0
+cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEG5vbmVA
+aW52YWxpZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCjYtuW
+aICCY0tJPubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8
+Di3DAmHKnSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTek
+LWcfI5ZZtoGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnH
+KT/m6DSU0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6
+jzhNyMBTJ1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQ
+Ujy5N8pSNp7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAz
+TK4l2pHNuC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBK
+Izv9cgi9fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0
+nPN1IMSnzXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzo
+GMTvP/AuehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9p
+sNcjTMaBQLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABo1MwUTAdBgNVHQ4EFgQU
+9mYU23tW2zsomkKTAXarjr2vjuswHwYDVR0jBBgwFoAU9mYU23tW2zsomkKTAXar
+jr2vjuswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEANjIBMrow
+YNCbhAJdP7dhlhT2RUFRdeRUJD0IxrH/hkvb6myHHnK8nOYezFPjUlmRKUgNEDuA
+xbnXZzPdCRNV9V2mShbXvCyiDY7WCQE2Bn44z26O0uWVk+7DNNLH9BnkwUtOnM9P
+wtmD9phWexm4q2GnTsiL6Ul6cy0QlTJWKVLEUQQ6yda582e23J1AXqtqFcpfoE34
+H3afEiGy882b+ZBiwkeV+oq6XVF8sFyr9zYrv9CvWTYlkpTQfLTZSsgPdEHYVcjv
+xQ2D+XyDR0aRLRlvxUa9dHGFHLICG34Juq5Ai6lM1EsoD8HSsJpMcmrH7MWw2cKk
+ujC3rMdFTtte83wF1uuF4FjUC72+SmcQN7A386BC/nk2TTsJawTDzqwOu/VdZv2g
+1WpTHlumlClZeP+G/jkSyDwqNnTu1aodDmUa4xZodfhP1HWPwUKFcq8oQr148QYA
+AOlbUOJQU7QwRWd1VbnwhDtQWXC92A2w1n/xkZSR1BM/NUSDhkBSUU1WjMbWg6Gg
+mnIZLRerQCu1Oozr87rOQqQakPkyt8BUSNK3K42j2qcfhAONdRl8Hq8Qs5pupy+s
+8sdCGDlwR3JNCMv6u48OK87F4mcIxhkSefFJUFII25pCGN5WtE4p5l+9cnO1GrIX
+e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE=
+-----END CERTIFICATE-----
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/localhost-100y.key b/minimal-examples/ws-server/minimal-ws-raw-proxy/localhost-100y.key
new file mode 100644 (file)
index 0000000..148f859
--- /dev/null
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCjYtuWaICCY0tJ
+PubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8Di3DAmHK
+nSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTekLWcfI5ZZ
+toGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnHKT/m6DSU
+0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6jzhNyMBT
+J1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQUjy5N8pS
+Np7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAzTK4l2pHN
+uC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBKIzv9cgi9
+fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0nPN1IMSn
+zXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzoGMTvP/Au
+ehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9psNcjTMaB
+QLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABAoICAFWe8MQZb37k2gdAV3Y6aq8f
+qokKQqbCNLd3giGFwYkezHXoJfg6Di7oZxNcKyw35LFEghkgtQqErQqo35VPIoH+
+vXUpWOjnCmM4muFA9/cX6mYMc8TmJsg0ewLdBCOZVw+wPABlaqz+0UOiSMMftpk9
+fz9JwGd8ERyBsT+tk3Qi6D0vPZVsC1KqxxL/cwIFd3Hf2ZBtJXe0KBn1pktWht5A
+Kqx9mld2Ovl7NjgiC1Fx9r+fZw/iOabFFwQA4dr+R8mEMK/7bd4VXfQ1o/QGGbMT
+G+ulFrsiDyP+rBIAaGC0i7gDjLAIBQeDhP409ZhswIEc/GBtODU372a2CQK/u4Q/
+HBQvuBtKFNkGUooLgCCbFxzgNUGc83GB/6IwbEM7R5uXqsFiE71LpmroDyjKTlQ8
+YZkpIcLNVLw0usoGYHFm2rvCyEVlfsE3Ub8cFyTFk50SeOcF2QL2xzKmmbZEpXgl
+xBHR0hjgon0IKJDGfor4bHO7Nt+1Ece8u2oTEKvpz5aIn44OeC5mApRGy83/0bvs
+esnWjDE/bGpoT8qFuy+0urDEPNId44XcJm1IRIlG56ErxC3l0s11wrIpTmXXckqw
+zFR9s2z7f0zjeyxqZg4NTPI7wkM3M8BXlvp2GTBIeoxrWB4V3YArwu8QF80QBgVz
+mgHl24nTg00UH1OjZsABAoIBAQDOxftSDbSqGytcWqPYP3SZHAWDA0O4ACEM+eCw
+au9ASutl0IDlNDMJ8nC2ph25BMe5hHDWp2cGQJog7pZ/3qQogQho2gUniKDifN77
+40QdykllTzTVROqmP8+efreIvqlzHmuqaGfGs5oTkZaWj5su+B+bT+9rIwZcwfs5
+YRINhQRx17qa++xh5mfE25c+M9fiIBTiNSo4lTxWMBShnK8xrGaMEmN7W0qTMbFH
+PgQz5FcxRjCCqwHilwNBeLDTp/ZECEB7y34khVh531mBE2mNzSVIQcGZP1I/DvXj
+W7UUNdgFwii/GW+6M0uUDy23UVQpbFzcV8o1C2nZc4Fb4zwBAoIBAQDKSJkFwwuR
+naVJS6WxOKjX8MCu9/cKPnwBv2mmI2jgGxHTw5sr3ahmF5eTb8Zo19BowytN+tr6
+2ZFoIBA9Ubc9esEAU8l3fggdfM82cuR9sGcfQVoCh8tMg6BP8IBLOmbSUhN3PG2m
+39I802u0fFNVQCJKhx1m1MFFLOu7lVcDS9JN+oYVPb6MDfBLm5jOiPuYkFZ4gH79
+J7gXI0/YKhaJ7yXthYVkdrSF6Eooer4RZgma62Dd1VNzSq3JBo6rYjF7Lvd+RwDC
+R1thHrmf/IXplxpNVkoMVxtzbrrbgnC25QmvRYc0rlS/kvM4yQhMH3eA7IycDZMp
+Y+0xm7I7jTT7AoIBAGKzKIMDXdCxBWKhNYJ8z7hiItNl1IZZMW2TPUiY0rl6yaCh
+BVXjM9W0r07QPnHZsUiByqb743adkbTUjmxdJzjaVtxN7ZXwZvOVrY7I7fPWYnCE
+fXCr4+IVpZI/ZHZWpGX6CGSgT6EOjCZ5IUufIvEpqVSmtF8MqfXO9o9uIYLokrWQ
+x1dBl5UnuTLDqw8bChq7O5y6yfuWaOWvL7nxI8NvSsfj4y635gIa/0dFeBYZEfHI
+UlGdNVomwXwYEzgE/c19ruIowX7HU/NgxMWTMZhpazlxgesXybel+YNcfDQ4e3RM
+OMz3ZFiaMaJsGGNf4++d9TmMgk4Ns6oDs6Tb9AECggEBAJYzd+SOYo26iBu3nw3L
+65uEeh6xou8pXH0Tu4gQrPQTRZZ/nT3iNgOwqu1gRuxcq7TOjt41UdqIKO8vN7/A
+aJavCpaKoIMowy/aGCbvAvjNPpU3unU8jdl/t08EXs79S5IKPcgAx87sTTi7KDN5
+SYt4tr2uPEe53NTXuSatilG5QCyExIELOuzWAMKzg7CAiIlNS9foWeLyVkBgCQ6S
+me/L8ta+mUDy37K6vC34jh9vK9yrwF6X44ItRoOJafCaVfGI+175q/eWcqTX4q+I
+G4tKls4sL4mgOJLq+ra50aYMxbcuommctPMXU6CrrYyQpPTHMNVDQy2ttFdsq9iK
+TncCggEBAMmt/8yvPflS+xv3kg/ZBvR9JB1In2n3rUCYYD47ReKFqJ03Vmq5C9nY
+56s9w7OUO8perBXlJYmKZQhO4293lvxZD2Iq4NcZbVSCMoHAUzhzY3brdgtSIxa2
+gGveGAezZ38qKIU26dkz7deECY4vrsRkwhpTW0LGVCpjcQoaKvymAoCmAs8V2oMr
+Ziw1YQ9uOUoWwOqm1wZqmVcOXvPIS2gWAs3fQlWjH9hkcQTMsUaXQDOD0aqkSY3E
+NqOvbCV1/oUpRi3076khCoAXI1bKSn/AvR3KDP14B5toHI/F5OTSEiGhhHesgRrs
+fBrpEY1IATtPq1taBZZogRqI3rOkkPk=
+-----END PRIVATE KEY-----
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/minimal-ws-raw-proxy.c b/minimal-examples/ws-server/minimal-ws-raw-proxy/minimal-ws-raw-proxy.c
new file mode 100644 (file)
index 0000000..6f66c44
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * lws-minimal-ws-raw-proxy
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a ws (server) -> raw (client) proxy,  it's a ws server
+ * that accepts connections, creates an onward client connection to some other
+ * no-protocol server, eg, nc -l 127.0.0.1 1234
+ *
+ * The idea is to show the general approach for making async proxies using lws
+ * that are robust and valgrind-clean.
+ *
+ * There's no vhd or pss on either side.  Instead when the ws server gets an
+ * incoming connection and negotiates the ws link, he creates an object
+ * representing the proxied connection, it is not destroyed automatically when
+ * any particular wsi is closed, instead the last wsi that is part of the
+ * proxied connection destroys it when he is closed.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#include <string.h>
+
+/* one of these created for each pending message that is to be forwarded */
+
+typedef struct proxy_msg {
+       lws_dll2_t              list;
+       size_t                  len;
+       /*
+        * the packet content is overallocated here, if p is a pointer to
+        * this struct, you can get a pointer to the message contents by
+        * ((uint8_t)&p[1]) + LWS_PRE.
+        *
+        * Notice we additionally take care to overallocate LWS_PRE before the
+        * actual message data, so we can simplify sending it.
+        */
+} proxy_msg_t;
+
+/*
+ * One of these is created when a inbound ws connection joins, it represents
+ * the proxy action provoked by that.
+ */
+
+typedef struct proxy_conn {
+       struct lws              *wsi_ws; /* wsi for the inbound ws conn */
+       struct lws              *wsi_raw; /* wsi for the outbound raw conn */
+
+       lws_dll2_owner_t        pending_msg_to_ws;
+       lws_dll2_owner_t        pending_msg_to_raw;
+} proxy_conn_t;
+
+
+static int
+proxy_ws_raw_msg_destroy(struct lws_dll2 *d, void *user)
+{
+       proxy_msg_t *msg = lws_container_of(d, proxy_msg_t, list);
+
+       lws_dll2_remove(d);
+       free(msg);
+
+       return 0;
+}
+
+/*
+ * First the ws server side
+ */
+
+static int
+callback_proxy_ws_server(struct lws *wsi, enum lws_callback_reasons reason,
+                        void *user, void *in, size_t len)
+{
+       proxy_conn_t *pc = (proxy_conn_t *)lws_get_opaque_user_data(wsi);
+       struct lws_client_connect_info i;
+       proxy_msg_t *msg;
+       uint8_t *data;
+       int m, a;
+
+       switch (reason) {
+       case LWS_CALLBACK_ESTABLISHED:
+               /* so let's create the proxy connection object */
+               pc = malloc(sizeof(*pc));
+               memset(pc, 0, sizeof(*pc));
+
+               /* mark this accepted ws connection with the proxy conn obj */
+               lws_set_opaque_user_data(wsi, pc);
+               /* tell the proxy conn object that we are the ws side of it */
+               pc->wsi_ws = wsi;
+
+               /*
+                * For this example proxy, our job is to create a new, onward,
+                * raw client connection to proxy stuff on to
+                */
+
+               memset(&i, 0, sizeof(i));
+
+               i.method = "RAW";
+               i.context = lws_get_context(wsi);
+               i.port = 1234;
+               i.address = "127.0.0.1";
+               i.ssl_connection = 0;
+               i.local_protocol_name = "lws-ws-raw-raw";
+
+               /* also mark the onward, raw client conn with the proxy_conn */
+               i.opaque_user_data = pc;
+               /* if it succeeds, set the wsi into the proxy_conn */
+               i.pwsi = &pc->wsi_raw;
+
+               if (!lws_client_connect_via_info(&i)) {
+                       lwsl_warn("%s: onward connection failed\n", __func__);
+                       return -1; /* hang up on the ws client, triggering
+                                   * _CLOSE flow */
+               }
+
+               break;
+
+       case LWS_CALLBACK_CLOSED:
+               /*
+                * Clean up any pending messages to us that are never going
+                * to get delivered now, we are in the middle of closing
+                */
+               lws_dll2_foreach_safe(&pc->pending_msg_to_ws, NULL,
+                                     proxy_ws_raw_msg_destroy);
+
+               /*
+                * Remove our pointer from the proxy_conn... we are about to
+                * be destroyed.
+                */
+               pc->wsi_ws = NULL;
+               lws_set_opaque_user_data(wsi, NULL);
+
+               if (!pc->wsi_raw) {
+                       /*
+                        * The onward raw conn either never got started or is
+                        * already closed... then we are the last guy still
+                        * holding on to the proxy_conn... and we're going away
+                        * so let's destroy it
+                        */
+
+                       free(pc);
+                       break;
+               }
+
+               /*
+                * Onward conn still alive...
+                * does he have stuff left to deliver?
+                */
+               if (pc->pending_msg_to_raw.count) {
+                       /*
+                        * Yes, let him get on with trying to send
+                        * the remaining pieces... but put a time limit
+                        * on how hard he will try now the ws part is
+                        * disappearing... give him 3s
+                        */
+                       lws_set_timeout(pc->wsi_raw,
+                               PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE, 3);
+                       break;
+               }
+               /*
+                * Onward raw client conn doesn't have anything left
+                * to do, let's close him right after this, he will take care to
+                * destroy the proxy_conn when he goes down after he sees we
+                * have already been closed
+                */
+
+               lws_wsi_close(pc->wsi_raw, LWS_TO_KILL_ASYNC);
+               break;
+
+       case LWS_CALLBACK_SERVER_WRITEABLE:
+               if (!pc || !pc->pending_msg_to_ws.count)
+                       break;
+
+               msg = lws_container_of(pc->pending_msg_to_ws.head,
+                                      proxy_msg_t, list);
+               data = (uint8_t *)&msg[1] + LWS_PRE;
+
+               /* notice we allowed for LWS_PRE in the payload already */
+               m = lws_write(wsi, data, msg->len, LWS_WRITE_TEXT);
+               a = (int)msg->len;
+               lws_dll2_remove(&msg->list);
+               free(msg);
+
+               if (m < a) {
+                       lwsl_err("ERROR %d writing to ws\n", m);
+                       return -1;
+               }
+
+               /*
+                * If more to do...
+                */
+               if (pc->pending_msg_to_ws.count)
+                       lws_callback_on_writable(wsi);
+               break;
+
+       case LWS_CALLBACK_RECEIVE:
+               if (!pc || !pc->wsi_raw)
+                       break;
+
+               /* notice we over-allocate by LWS_PRE + rx len */
+               msg = (proxy_msg_t *)malloc(sizeof(*msg) + LWS_PRE + len);
+               data = (uint8_t *)&msg[1] + LWS_PRE;
+
+               if (!msg) {
+                       lwsl_user("OOM: dropping\n");
+                       break;
+               }
+
+               memset(msg, 0, sizeof(*msg));
+               msg->len = len;
+               memcpy(data, in, len);
+
+               /* add us on to the list of packets to send to the onward conn */
+               lws_dll2_add_tail(&msg->list, &pc->pending_msg_to_raw);
+
+               /* ask to send on the onward proxy client conn */
+               lws_callback_on_writable(pc->wsi_raw);
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * Then the onward, raw client side
+ */
+
+static int
+callback_proxy_raw_client(struct lws *wsi, enum lws_callback_reasons reason,
+                         void *user, void *in, size_t len)
+{
+       proxy_conn_t *pc = (proxy_conn_t *)lws_get_opaque_user_data(wsi);
+       proxy_msg_t *msg;
+       uint8_t *data;
+       int m, a;
+
+       switch (reason) {
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_warn("%s: onward raw connection failed\n", __func__);
+               pc->wsi_raw = NULL;
+               break;
+
+       case LWS_CALLBACK_RAW_ADOPT:
+               lwsl_user("LWS_CALLBACK_RAW_ADOPT\n");
+               pc->wsi_raw = wsi;
+               lws_callback_on_writable(wsi);
+               break;
+
+       case LWS_CALLBACK_RAW_CLOSE:
+               lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
+               /*
+                * Clean up any pending messages to us that are never going
+                * to get delivered now, we are in the middle of closing
+                */
+               lws_dll2_foreach_safe(&pc->pending_msg_to_raw, NULL,
+                                     proxy_ws_raw_msg_destroy);
+
+               /*
+                * Remove our pointer from the proxy_conn... we are about to
+                * be destroyed.
+                */
+               pc->wsi_raw = NULL;
+               lws_set_opaque_user_data(wsi, NULL);
+
+               if (!pc->wsi_ws) {
+                       /*
+                        * The original ws conn is already closed... then we are
+                        * the last guy still holding on to the proxy_conn...
+                        * and we're going away, so let's destroy it
+                        */
+
+                       free(pc);
+                       break;
+               }
+
+               /*
+                * Original ws conn still alive...
+                * does he have stuff left to deliver?
+                */
+               if (pc->pending_msg_to_ws.count) {
+                       /*
+                        * Yes, let him get on with trying to send
+                        * the remaining pieces... but put a time limit
+                        * on how hard he will try now the raw part is
+                        * disappearing... give him 3s
+                        */
+                       lws_set_timeout(pc->wsi_ws,
+                               PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE, 3);
+                       break;
+               }
+               /*
+                * Original ws client conn doesn't have anything left
+                * to do, let's close him right after this, he will take care to
+                * destroy the proxy_conn when he goes down after he sees we
+                * have already been closed
+                */
+
+               lws_wsi_close(pc->wsi_ws, LWS_TO_KILL_ASYNC);
+               break;
+
+       case LWS_CALLBACK_RAW_RX:
+               lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
+               if (!pc || !pc->wsi_ws)
+                       break;
+
+               /* notice we over-allocate by LWS_PRE + rx len */
+               msg = (proxy_msg_t *)malloc(sizeof(*msg) + LWS_PRE + len);
+               data = (uint8_t *)&msg[1] + LWS_PRE;
+
+               if (!msg) {
+                       lwsl_user("OOM: dropping\n");
+                       break;
+               }
+
+               memset(msg, 0, sizeof(*msg));
+               msg->len = len;
+               memcpy(data, in, len);
+
+               /* add us on to the list of packets to send to the onward conn */
+               lws_dll2_add_tail(&msg->list, &pc->pending_msg_to_ws);
+
+               /* ask to send on the onward proxy client conn */
+               lws_callback_on_writable(pc->wsi_ws);
+               break;
+
+       case LWS_CALLBACK_RAW_WRITEABLE:
+               lwsl_user("LWS_CALLBACK_RAW_WRITEABLE\n");
+               if (!pc || !pc->pending_msg_to_raw.count)
+                       break;
+
+               msg = lws_container_of(pc->pending_msg_to_raw.head,
+                                      proxy_msg_t, list);
+               data = (uint8_t *)&msg[1] + LWS_PRE;
+
+               /* notice we allowed for LWS_PRE in the payload already */
+               m = lws_write(wsi, data, msg->len, LWS_WRITE_TEXT);
+               a = (int)msg->len;
+               lws_dll2_remove(&msg->list);
+               free(msg);
+
+               if (m < a) {
+                       lwsl_err("ERROR %d writing to raw\n", m);
+                       return -1;
+               }
+
+               /*
+                * If more to do...
+                */
+               if (pc->pending_msg_to_raw.count)
+                       lws_callback_on_writable(wsi);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct lws_protocols protocols[] = {
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
+       { "lws-ws-raw-ws", callback_proxy_ws_server, 0, 1024, 0, NULL, 0 },
+       { "lws-ws-raw-raw", callback_proxy_raw_client, 0, 1024, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping = 3,
+       .secs_since_valid_hangup = 10,
+};
+
+static int interrupted;
+
+static const struct lws_http_mount mount = {
+       /* .mount_next */               NULL,           /* linked-list "next" */
+       /* .mountpoint */               "/",            /* mountpoint URL */
+       /* .origin */                   "./mount-origin",  /* serve from dir */
+       /* .def */                      "index.html",   /* default filename */
+       /* .protocol */                 NULL,
+       /* .cgienv */                   NULL,
+       /* .extra_mimetypes */          NULL,
+       /* .interpret */                NULL,
+       /* .cgi_timeout */              0,
+       /* .cache_max_age */            0,
+       /* .auth_mask */                0,
+       /* .cache_reusable */           0,
+       /* .cache_revalidate */         0,
+       /* .cache_intermediaries */     0,
+       /* .origin_protocol */          LWSMPRO_FILE,   /* files in a dir */
+       /* .mountpoint_len */           1,              /* char count */
+       /* .basic_auth_login_file */    NULL,
+};
+
+void sigint_handler(int sig)
+{
+       interrupted = 1;
+}
+
+int main(int argc, const char **argv)
+{
+       struct lws_context_creation_info info;
+       struct lws_context *context;
+       const char *p;
+       int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
+                       /* for LLL_ verbosity above NOTICE to be built into lws,
+                        * lws must have been configured and built with
+                        * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
+                       /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
+                       /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
+                       /* | LLL_DEBUG */;
+
+       signal(SIGINT, sigint_handler);
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS minimal ws-raw proxy | visit http://localhost:7681 (-s = use TLS / https)\n");
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.port = 7681;
+       info.mounts = &mount;
+       info.protocols = protocols;
+       info.vhost_name = "localhost";
+       info.options =
+               LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
+
+#if defined(LWS_WITH_TLS)
+       if (lws_cmdline_option(argc, argv, "-s")) {
+               lwsl_user("Server using TLS\n");
+               info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+               info.ssl_cert_filepath = "localhost-100y.cert";
+               info.ssl_private_key_filepath = "localhost-100y.key";
+       }
+#endif
+
+       if (lws_cmdline_option(argc, argv, "-h"))
+               info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
+
+       if (lws_cmdline_option(argc, argv, "-v"))
+               info.retry_and_idle_policy = &retry;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
+
+       lws_context_destroy(context);
+
+       return 0;
+}
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/example.js b/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/example.js
new file mode 100644 (file)
index 0000000..d350dee
--- /dev/null
@@ -0,0 +1,66 @@
+
+function get_appropriate_ws_url(extra_url)
+{
+       var pcol;
+       var u = document.URL;
+
+       /*
+        * We open the websocket encrypted if this page came on an
+        * https:// url itself, otherwise unencrypted
+        */
+
+       if (u.substring(0, 5) === "https") {
+               pcol = "wss://";
+               u = u.substr(8);
+       } else {
+               pcol = "ws://";
+               if (u.substring(0, 4) === "http")
+                       u = u.substr(7);
+       }
+
+       u = u.split("/");
+
+       /* + "/xxx" bit is for IE10 workaround */
+
+       return pcol + u[0] + "/" + extra_url;
+}
+
+function new_ws(urlpath, protocol)
+{
+       return new WebSocket(urlpath, protocol);
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+       
+       var ws = new_ws(get_appropriate_ws_url(""), "lws-ws-raw-ws");
+       try {
+               ws.onopen = function() {
+                       document.getElementById("m").disabled = 0;
+                       document.getElementById("b").disabled = 0;
+               };
+       
+               ws.onmessage =function got_packet(msg) {
+                       document.getElementById("r").value =
+                               document.getElementById("r").value + msg.data + "\n";
+                       document.getElementById("r").scrollTop =
+                               document.getElementById("r").scrollHeight;
+               };
+       
+               ws.onclose = function(){
+                       document.getElementById("m").disabled = 1;
+                       document.getElementById("b").disabled = 1;
+               };
+       } catch(exception) {
+               alert("<p>Error " + exception);  
+       }
+       
+       function sendmsg()
+       {
+               ws.send(document.getElementById("m").value);
+               document.getElementById("m").value = "";
+       }
+       
+       document.getElementById("b").addEventListener("click", sendmsg);
+       
+}, false);
+
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/favicon.ico b/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/favicon.ico
new file mode 100644 (file)
index 0000000..c0cc2e3
Binary files /dev/null and b/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/favicon.ico differ
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/index.html b/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/index.html
new file mode 100644 (file)
index 0000000..9c1dc9a
--- /dev/null
@@ -0,0 +1,19 @@
+<html>
+ <head>
+  <meta charset=utf-8 http-equiv="Content-Language" content="en"/>
+  <script src="/example.js"></script>
+ </head>
+       <body>
+               <img src="libwebsockets.org-logo.svg">
+               <img src="strict-csp.svg"><br>
+       
+               LWS chat <b>minimal ws server example</b>.<br>
+               Chat is sent to all browsers open on this page.
+               <br>
+               <br>
+               <textarea id=r readonly cols=40 rows=10></textarea><br>
+               <input type="text" id=m cols=40 rows=1>
+               <button id=b>Send</button>
+       </body>
+</html>
+
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/libwebsockets.org-logo.svg b/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/libwebsockets.org-logo.svg
new file mode 100644 (file)
index 0000000..ef241b3
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
+</svg>
diff --git a/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/strict-csp.svg b/minimal-examples/ws-server/minimal-ws-raw-proxy/mount-origin/strict-csp.svg
new file mode 100644 (file)
index 0000000..cd128f1
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="24.78mm" height="24.78mm" version="1.1" viewBox="0 0 24.780247 24.780247" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+  <linearGradient id="linearGradient955" x1="66.618" x2="82.588" y1="81.176" y2="64.828" gradientTransform="matrix(.82538 0 0 .82538 -392 -92.399)" gradientUnits="userSpaceOnUse">
+   <stop stop-color="#0aa70b" offset="0"/>
+   <stop stop-color="#3bff39" offset="1"/>
+  </linearGradient>
+  <filter id="filter945" x="-.0516" y="-.0516" width="1.1032" height="1.1032" color-interpolation-filters="sRGB">
+   <feGaussianBlur stdDeviation="0.58510713"/>
+  </filter>
+ </defs>
+ <g transform="translate(342.15 43.638)">
+  <circle transform="matrix(.82538 0 0 .82538 -392 -92.399)" cx="75.406" cy="74.089" r="13.607" filter="url(#filter945)" stroke="#000" stroke-linecap="round" stroke-width="1.565"/>
+  <circle cx="-330.23" cy="-31.716" r="11.231" fill="url(#linearGradient955)" stroke="#000" stroke-linecap="round" stroke-width="1.2917"/>
+  <g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".51676px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Strict">
+   <path d="m-330.78-33.775q0 0.73996-0.53676 1.154-0.53676 0.41407-1.4569 0.41407-0.99684 0-1.5336-0.25688v-0.62878q0.34506 0.14569 0.75147 0.23004 0.4064 0.08435 0.80514 0.08435 0.65177 0 0.9815-0.24538 0.32972-0.24921 0.32972-0.69012 0-0.29138-0.11885-0.47542-0.11502-0.18787-0.39107-0.34506-0.27221-0.15719-0.83198-0.35656-0.78213-0.27988-1.1195-0.66328-0.33356-0.3834-0.33356-1.0007 0-0.64794 0.48692-1.0313 0.48691-0.3834 1.2882-0.3834 0.83581 0 1.5374 0.30672l-0.2032 0.56743q-0.69395-0.29138-1.3496-0.29138-0.51759 0-0.80897 0.22237t-0.29138 0.61727q0 0.29138 0.10735 0.47925 0.10735 0.18403 0.36039 0.34123 0.25688 0.15336 0.78214 0.34122 0.88182 0.31439 1.2115 0.67478 0.33356 0.3604 0.33356 0.93549z"/>
+   <path d="m-328.37-32.732q0.16869 0 0.32589-0.023 0.15719-0.02684 0.24921-0.05368v0.48692q-0.10352 0.04984-0.30672 0.08051-0.19937 0.03451-0.3604 0.03451-1.2192 0-1.2192-1.2844v-2.4998h-0.60194v-0.30672l0.60194-0.26455 0.26838-0.89716h0.36807v0.97384h1.2192v0.49458h-1.2192v2.4729q0 0.37957 0.18019 0.58277 0.1802 0.2032 0.49459 0.2032z"/>
+   <path d="m-325.04-36.562q0.27989 0 0.50226 0.04601l-0.0882 0.59044q-0.26072-0.05751-0.46008-0.05751-0.50993 0-0.87415 0.41407-0.3604 0.41407-0.3604 1.0313v2.2544h-0.63644v-4.2021h0.52525l0.0729 0.7783h0.0307q0.23388-0.41024 0.5636-0.63261 0.32972-0.22237 0.72462-0.22237z"/>
+   <path d="m-323.11-32.284h-0.63644v-4.2021h0.63644zm-0.69012-5.3408q0-0.21854 0.10735-0.31822 0.10735-0.10352 0.26838-0.10352 0.15336 0 0.26455 0.10352 0.11118 0.10352 0.11118 0.31822 0 0.2147-0.11118 0.32206-0.11119 0.10352-0.26455 0.10352-0.16103 0-0.26838-0.10352-0.10735-0.10735-0.10735-0.32206z"/>
+   <path d="m-320.07-32.207q-0.91249 0-1.4147-0.55976-0.49842-0.5636-0.49842-1.5911 0-1.0543 0.50609-1.6294 0.50992-0.5751 1.4492-0.5751 0.30288 0 0.60577 0.06518 0.30288 0.06518 0.47541 0.15336l-0.19553 0.54059q-0.21087-0.08435-0.46008-0.13802-0.24921-0.05751-0.44091-0.05751-1.2806 0-1.2806 1.6333 0 0.77447 0.31055 1.1885 0.31439 0.41407 0.92783 0.41407 0.52526 0 1.0774-0.22621v0.5636q-0.42174 0.21854-1.062 0.21854z"/>
+   <path d="m-316.65-32.732q0.16869 0 0.32589-0.023 0.15719-0.02684 0.24921-0.05368v0.48692q-0.10352 0.04984-0.30672 0.08051-0.19937 0.03451-0.3604 0.03451-1.2192 0-1.2192-1.2844v-2.4998h-0.60194v-0.30672l0.60194-0.26455 0.26838-0.89716h0.36806v0.97384h1.2192v0.49458h-1.2192v2.4729q0 0.37957 0.1802 0.58277 0.1802 0.2032 0.49459 0.2032z"/>
+  </g>
+  <g fill="#fff">
+   <g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".3317px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Content">
+    <path d="m-332.67-30.173q-0.5931 0-0.93764 0.39622-0.34208 0.39376-0.34208 1.0804 0 0.70631 0.32977 1.0927 0.33224 0.38392 0.94503 0.38392 0.37653 0 0.85889-0.13536v0.36669q-0.37407 0.14028-0.92288 0.14028-0.7949 0-1.228-0.48236-0.43067-0.48236-0.43067-1.3708 0-0.55619 0.20672-0.97456 0.20919-0.41837 0.60049-0.64478 0.39376-0.22641 0.92533-0.22641 0.56603 0 0.98933 0.20672l-0.1772 0.35931q-0.40852-0.19196-0.81705-0.19196z"/>
+    <path d="m-328.77-28.248q0 0.65955-0.33224 1.0312-0.33223 0.36915-0.91795 0.36915-0.36177 0-0.64233-0.16981-0.28055-0.16981-0.43313-0.48728-0.15259-0.31747-0.15259-0.74322 0-0.65955 0.32978-1.0262 0.32977-0.36915 0.91549-0.36915 0.56603 0 0.89827 0.37653 0.3347 0.37653 0.3347 1.0189zm-2.0549 0q0 0.51681 0.20672 0.78752 0.20673 0.27071 0.60787 0.27071t0.60787-0.26825q0.20918-0.27071 0.20918-0.78998 0-0.51435-0.20918-0.78014-0.20673-0.26825-0.61279-0.26825-0.40115 0-0.60541 0.26333-0.20426 0.26333-0.20426 0.78506z"/>
+    <path d="m-326.21-26.897v-1.7449q0-0.32978-0.15012-0.4922-0.15012-0.16243-0.47005-0.16243-0.42329 0-0.62017 0.22887-0.19688 0.22887-0.19688 0.75553v1.4151h-0.40853v-2.6973h0.33223l0.0664 0.36915h0.0197q0.12551-0.19934 0.35192-0.30762 0.22642-0.11075 0.50451-0.11075 0.48728 0 0.73338 0.23626 0.2461 0.2338 0.2461 0.75061v1.7596z"/>
+    <path d="m-324.09-27.185q0.10828 0 0.20918-0.01477 0.1009-0.01723 0.15997-0.03445v0.31255q-0.0665 0.03199-0.19688 0.05168-0.12797 0.02215-0.23134 0.02215-0.7826 0-0.7826-0.82444v-1.6046h-0.38637v-0.19688l0.38637-0.16981 0.17227-0.57588h0.23626v0.6251h0.7826v0.31747h-0.7826v1.5873q0 0.24364 0.11567 0.37407 0.11566 0.13043 0.31747 0.13043z"/>
+    <path d="m-322.04-26.848q-0.59802 0-0.94502-0.36423-0.34454-0.36423-0.34454-1.0115 0-0.65217 0.31993-1.0361 0.32239-0.38392 0.86381-0.38392 0.50697 0 0.80229 0.3347 0.29532 0.33224 0.29532 0.87858v0.25841h-1.8581q0.0123 0.47497 0.23872 0.72107 0.22887 0.2461 0.64232 0.2461 0.4356 0 0.86135-0.18212v0.36423q-0.21657 0.09352-0.41099 0.13289-0.19195 0.04184-0.46513 0.04184zm-0.11074-2.4536q-0.32485 0-0.51927 0.21165-0.19196 0.21165-0.22642 0.58572h1.4102q0-0.38638-0.17227-0.59064-0.17227-0.20672-0.4922-0.20672z"/>
+    <path d="m-318.51-26.897v-1.7449q0-0.32978-0.15012-0.4922-0.15013-0.16243-0.47006-0.16243-0.42329 0-0.62017 0.22887-0.19688 0.22887-0.19688 0.75553v1.4151h-0.40853v-2.6973h0.33224l0.0664 0.36915h0.0197q0.12552-0.19934 0.35193-0.30762 0.22641-0.11075 0.5045-0.11075 0.48728 0 0.73338 0.23626 0.2461 0.2338 0.2461 0.75061v1.7596z"/>
+    <path d="m-316.4-27.185q0.10829 0 0.20919-0.01477 0.1009-0.01723 0.15996-0.03445v0.31255q-0.0664 0.03199-0.19688 0.05168-0.12797 0.02215-0.23133 0.02215-0.7826 0-0.7826-0.82444v-1.6046h-0.38638v-0.19688l0.38638-0.16981 0.17227-0.57588h0.23625v0.6251h0.7826v0.31747h-0.7826v1.5873q0 0.24364 0.11567 0.37407 0.11567 0.13043 0.31747 0.13043z"/>
+   </g>
+   <g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".32428px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Security">
+    <path d="m-332.03-22.859q0 0.46434-0.33683 0.72417-0.33682 0.25984-0.91423 0.25984-0.62553 0-0.96236-0.1612v-0.39456q0.21653 0.09142 0.47155 0.14435 0.25503 0.05293 0.50524 0.05293 0.409 0 0.61591-0.15398 0.20691-0.15638 0.20691-0.43306 0-0.18285-0.0746-0.29833-0.0722-0.11789-0.2454-0.21653-0.17082-0.09864-0.52208-0.22375-0.4908-0.17563-0.70252-0.41622-0.20931-0.24059-0.20931-0.62794 0-0.4066 0.30555-0.64718t0.80838-0.24059q0.52448 0 0.96476 0.19247l-0.12751 0.35607q-0.43547-0.18285-0.84687-0.18285-0.3248 0-0.50765 0.13954-0.18284 0.13954-0.18284 0.38735 0 0.18285 0.0674 0.30074 0.0674 0.11548 0.22615 0.21412 0.1612 0.09624 0.4908 0.21412 0.55336 0.19728 0.76027 0.42344 0.20931 0.22615 0.20931 0.58704z"/>
+    <path d="m-330.26-21.875q-0.58463 0-0.92386-0.35607-0.33683-0.35607-0.33683-0.98882 0-0.63756 0.31277-1.0129 0.31517-0.37532 0.84446-0.37532 0.49562 0 0.78432 0.3272 0.28871 0.3248 0.28871 0.8589v0.25262h-1.8164q0.012 0.46434 0.23338 0.70492 0.22374 0.24059 0.62793 0.24059 0.42584 0 0.84206-0.17804v0.35607q-0.21171 0.09142-0.40178 0.12992-0.18766 0.0409-0.45471 0.0409zm-0.10827-2.3987q-0.31757 0-0.50764 0.20691-0.18766 0.20691-0.22134 0.5726h1.3786q0-0.37772-0.16841-0.57741-0.16841-0.2021-0.48118-0.2021z"/>
+    <path d="m-327.56-21.875q-0.5726 0-0.88777-0.35126-0.31277-0.35366-0.31277-0.99844 0-0.66162 0.31758-1.0225 0.31998-0.36088 0.90942-0.36088 0.19007 0 0.38013 0.0409 0.19007 0.0409 0.29833 0.09624l-0.1227 0.33923q-0.13232-0.05293-0.2887-0.08661-0.15639-0.03609-0.27668-0.03609-0.80357 0-0.80357 1.0249 0 0.48599 0.19488 0.74582 0.19728 0.25984 0.58223 0.25984 0.3296 0 0.67605-0.14195v0.35366q-0.26465 0.13714-0.66643 0.13714z"/>
+    <path d="m-325.89-24.56v1.7106q0 0.32239 0.14676 0.48118 0.14675 0.15879 0.45952 0.15879 0.41381 0 0.60388-0.22615 0.19247-0.22615 0.19247-0.73861v-1.3858h0.39938v2.6369h-0.32961l-0.0577-0.35367h-0.0217q-0.1227 0.19488-0.34163 0.29833-0.21653 0.10345-0.49561 0.10345-0.48118 0-0.72177-0.22856-0.23818-0.22856-0.23818-0.73139v-1.725z"/>
+    <path d="m-322.04-24.608q0.17563 0 0.31517 0.02887l-0.0553 0.37051q-0.1636-0.03609-0.2887-0.03609-0.31999 0-0.54855 0.25984-0.22615 0.25984-0.22615 0.64718v1.4147h-0.39938v-2.6369h0.32961l0.0457 0.4884h0.0192q0.14676-0.25743 0.35366-0.39697 0.20691-0.13954 0.45472-0.13954z"/>
+    <path d="m-320.83-21.923h-0.39938v-2.6369h0.39938zm-0.43306-3.3514q0-0.13714 0.0674-0.19969 0.0674-0.06496 0.16841-0.06496 0.0962 0 0.16601 0.06496 0.0698 0.06496 0.0698 0.19969 0 0.13473-0.0698 0.2021-0.0698 0.06496-0.16601 0.06496-0.10105 0-0.16841-0.06496-0.0674-0.06736-0.0674-0.2021z"/>
+    <path d="m-319.13-22.205q0.10586 0 0.2045-0.01443 0.0986-0.01684 0.15638-0.03368v0.30555q-0.065 0.03128-0.19247 0.05052-0.1251 0.02165-0.22615 0.02165-0.76507 0-0.76507-0.80597v-1.5686h-0.37773v-0.19247l0.37773-0.16601 0.16841-0.56298h0.23096v0.6111h0.76508v0.31036h-0.76508v1.5518q0 0.23818 0.11308 0.3657t0.31036 0.12751z"/>
+    <path d="m-318.66-24.56h0.42825l0.57742 1.5037q0.19006 0.51486 0.23577 0.74342h0.0192q0.0313-0.1227 0.12992-0.41862 0.10105-0.29833 0.6544-1.8285h0.42825l-1.1332 3.0025q-0.16841 0.44509-0.39456 0.63034-0.22375 0.18766-0.55095 0.18766-0.18285 0-0.36088-0.0409v-0.31998q0.13232 0.02887 0.29592 0.02887 0.41141 0 0.58704-0.46193l0.14676-0.37532z"/>
+   </g>
+   <g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".32334px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Policy">
+    <path d="m-329.37-19.254q0 0.53256-0.36464 0.82043-0.36224 0.28547-1.0387 0.28547h-0.41261v1.3794h-0.40782v-3.5072h0.90919q1.3146 0 1.3146 1.0219zm-1.816 0.75566h0.36703q0.54215 0 0.78445-0.17512 0.24229-0.17512 0.24229-0.56135 0-0.34784-0.2279-0.51817t-0.71008-0.17032h-0.45579z"/>
+    <path d="m-326.43-18.086q0 0.64291-0.32386 1.0051-0.32385 0.35984-0.89479 0.35984-0.35264 0-0.62612-0.16552t-0.42221-0.47498q-0.14873-0.30946-0.14873-0.72447 0-0.64291 0.32145-1.0003 0.32146-0.35984 0.8924-0.35984 0.55175 0 0.8756 0.36703 0.32626 0.36704 0.32626 0.99315zm-2.0031 0q0 0.50377 0.20151 0.76765t0.59253 0.26388q0.39103 0 0.59254-0.26148 0.2039-0.26388 0.2039-0.77005 0-0.50137-0.2039-0.76046-0.20151-0.26148-0.59733-0.26148-0.39103 0-0.59014 0.25668-0.19911 0.25668-0.19911 0.76525z"/>
+    <path d="m-325.33-16.769h-0.39822v-3.7327h0.39822z"/>
+    <path d="m-324.09-16.769h-0.39822v-2.6292h0.39822zm-0.43181-3.3417q0-0.13674 0.0672-0.19911 0.0672-0.06477 0.16793-0.06477 0.0959 0 0.16552 0.06477 0.0696 0.06477 0.0696 0.19911t-0.0696 0.20151q-0.0696 0.06477-0.16552 0.06477-0.10076 0-0.16793-0.06477-0.0672-0.06717-0.0672-0.20151z"/>
+    <path d="m-322.19-16.721q-0.57094 0-0.8852-0.35024-0.31186-0.35264-0.31186-0.99555 0-0.6597 0.31666-1.0195 0.31906-0.35984 0.90679-0.35984 0.18951 0 0.37903 0.04078 0.18951 0.04078 0.29746 0.09596l-0.12234 0.33825q-0.13194-0.05278-0.28787-0.08636-0.15593-0.03598-0.27588-0.03598-0.80123 0-0.80123 1.0219 0 0.48458 0.19431 0.74366 0.19671 0.25908 0.58054 0.25908 0.32865 0 0.67409-0.14154v0.35264q-0.26388 0.13674-0.6645 0.13674z"/>
+    <path d="m-321.31-19.398h0.427l0.57574 1.4993q0.18952 0.51337 0.2351 0.74127h0.0192q0.0312-0.12234 0.12954-0.41741 0.10076-0.29747 0.65251-1.8232h0.427l-1.1299 2.9938q-0.16792 0.4438-0.39342 0.62852-0.2231 0.18712-0.54935 0.18712-0.18232 0-0.35984-0.04078v-0.31906q0.13194 0.02879 0.29507 0.02879 0.41021 0 0.58533-0.46059l0.14634-0.37423z"/>
+   </g>
+  </g>
+ </g>
+</svg>
index 78823ea..0b8a4e5 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8.9)
+project(lws-minimal-ws-server-echo C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server-echo)
 set(SRCS minimal-ws-server-echo.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 require_lws_config(LWS_WITHOUT_EXTENSIONS 0 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index e3b217f..7a8e946 100644 (file)
@@ -19,7 +19,7 @@
 
 static struct lws_protocols protocols[] = {
        LWS_PLUGIN_PROTOCOL_MINIMAL_SERVER_ECHO,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted, port = 7681, options;
index b2a5531..84c67f1 100644 (file)
@@ -124,7 +124,7 @@ callback_minimal_server_echo(struct lws *wsi, enum lws_callback_reasons reason,
 
                /* notice we allowed for LWS_PRE in the payload already */
                m = lws_write(wsi, ((unsigned char *)pmsg->payload) +
-                             LWS_PRE, pmsg->len, flags);
+                             LWS_PRE, pmsg->len, (enum lws_write_protocol)flags);
                if (m < (int)pmsg->len) {
                        lwsl_err("ERROR %d writing to ws socket\n", m);
                        return -1;
@@ -168,9 +168,9 @@ callback_minimal_server_echo(struct lws *wsi, enum lws_callback_reasons reason,
                        //lwsl_hexdump_notice(in, len);
                }
 
-               amsg.first = lws_is_first_fragment(wsi);
-               amsg.final = lws_is_final_fragment(wsi);
-               amsg.binary = lws_frame_is_binary(wsi);
+               amsg.first = (char)lws_is_first_fragment(wsi);
+               amsg.final = (char)lws_is_final_fragment(wsi);
+               amsg.binary = (char)lws_frame_is_binary(wsi);
                n = (int)lws_ring_get_count_free_elements(pss->ring);
                if (!n) {
                        lwsl_user("dropping!\n");
@@ -180,7 +180,7 @@ callback_minimal_server_echo(struct lws *wsi, enum lws_callback_reasons reason,
                if (amsg.final)
                        pss->msglen = 0;
                else
-                       pss->msglen += len;
+                       pss->msglen += (uint32_t)len;
 
                amsg.len = len;
                /* notice we over-allocate by LWS_PRE */
@@ -230,36 +230,3 @@ callback_minimal_server_echo(struct lws *wsi, enum lws_callback_reasons reason,
                1024, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL_SERVER_ECHO
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal_server_echo(struct lws_context *context,
-                              struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal_server_echo(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index d27769f..5bb69d0 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8.9)
+project(lws-minimal-ws-server-pmd-bulk C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server-pmd-bulk)
 set(SRCS minimal-ws-server-pmd-bulk.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 #require_lws_config(LWS_WITHOUT_EXTENSIONS 0 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 6f655c4..fbda461 100644 (file)
@@ -21,9 +21,9 @@
 #include "protocol_lws_minimal_pmd_bulk.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_MINIMAL_PMD_BULK,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted, options;
index d1c49a7..33911b4 100644 (file)
@@ -27,15 +27,12 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
 document.addEventListener("DOMContentLoaded", function() {
 
-       ws = new_ws(get_appropriate_ws_url(""), "lws-minimal-pmd-bulk");
+       var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal-pmd-bulk");
        try {
                ws.onopen = function() {
                        document.getElementById("r").disabled = 0;
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 09e4307..22b99a1 100644 (file)
@@ -143,22 +143,22 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason,
                                size_t s;
 
                                m = pss->position_tx % REPEAT_STRING_LEN;
-                               s = REPEAT_STRING_LEN - m;
+                               s = (unsigned int)(REPEAT_STRING_LEN - m);
                                if (s > (size_t)n)
-                                       s = n;
+                                       s = (unsigned int)n;
                                memcpy(p, &redundant_string[m], s);
-                               pss->position_tx += s;
+                               pss->position_tx += (int)s;
                                p += s;
-                               n -= s;
+                               n -= (int)s;
                        }
                } else {
                        pss->position_tx += n;
                        while (n--)
-                               *p++ = rng(&pss->rng_tx);
+                               *p++ = (uint8_t)rng(&pss->rng_tx);
                }
 
                n = lws_ptr_diff(p, start);
-               m = lws_write(wsi, start, n, flags);
+               m = lws_write(wsi, start, (unsigned int)n, (enum lws_write_protocol)flags);
                lwsl_user("LWS_CALLBACK_SERVER_WRITEABLE: wrote %d\n", n);
                if (m < n) {
                        lwsl_err("ERROR %d / %d writing ws\n", m, n);
@@ -172,32 +172,32 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason,
                lwsl_user("LWS_CALLBACK_RECEIVE: %4d (pss->pos=%d, rpp %5d, last %d)\n",
                                (int)len, (int)pss->position_rx, (int)lws_remaining_packet_payload(wsi),
                                lws_is_final_fragment(wsi));
-               olen = len;
+               olen = (int)len;
 
                if (*vhd->options & 1) {
                        while (len) {
                                size_t s;
                                m = pss->position_rx % REPEAT_STRING_LEN;
-                               s = REPEAT_STRING_LEN - m;
+                               s = (unsigned int)(REPEAT_STRING_LEN - m);
                                if (s > len)
                                        s = len;
                                if (memcmp(in, &redundant_string[m], s)) {
                                        lwsl_user("echo'd data doesn't match\n");
                                        return -1;
                                }
-                               pss->position_rx += s;
+                               pss->position_rx += (int)s;
                                in = ((char *)in) + s;
                                len -= s;
                        }
                } else {
                        p = (uint8_t *)in;
-                       pss->position_rx += len;
+                       pss->position_rx += (int)len;
                        while (len--) {
                                if (*p++ != (uint8_t)rng(&pss->rng_rx)) {
                                        lwsl_user("echo'd data doesn't match: 0x%02X 0x%02X (%d)\n",
                                                *(p - 1), (int)(0x40 + (pss->rng_rx & 0x3f)),
-                                               (int)((pss->position_rx - olen) + olen - len));
-                                       lwsl_hexdump_notice(in, olen);
+                                               (int)((pss->position_rx - olen) + olen - (int)len));
+                                       lwsl_hexdump_notice(in, (unsigned int)olen);
                                        return -1;
                                }
                        }
@@ -221,36 +221,3 @@ callback_minimal_pmd_bulk(struct lws *wsi, enum lws_callback_reasons reason,
                4096, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL_PMD_BULK
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal_pmd_bulk(struct lws_context *context,
-                              struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal_pmd_bulk(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index 1098d50..9be9eb9 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8.9)
+project(lws-minimal-ws-server-pmd-corner C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server-pmd-corner)
 set(SRCS minimal-ws-server-pmd-corner.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 require_lws_config(LWS_WITHOUT_EXTENSIONS 0 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 7a31a1f..06ecb67 100644 (file)
@@ -21,9 +21,9 @@
 #include "protocol_lws_minimal.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_MINIMAL,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
index ec3a99c..aedf5bf 100644 (file)
@@ -27,9 +27,6 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 1558b37..785fec3 100644 (file)
@@ -241,10 +241,10 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                                corner_lengths[pss->last - 1]);
 
                memcpy(buf + LWS_PRE, uncompressible,
-                      corner_lengths[pss->last - 1]);
+                      (unsigned int)corner_lengths[pss->last - 1]);
 
                /* notice we allowed for LWS_PRE in the payload already */
-               m = lws_write(wsi, buf + LWS_PRE, corner_lengths[pss->last - 1],
+               m = lws_write(wsi, buf + LWS_PRE, (unsigned int)corner_lengths[pss->last - 1],
                                LWS_WRITE_BINARY);
                if (m < corner_lengths[pss->last - 1]) {
                        lwsl_err("ERROR %d writing to ws socket\n", m);
@@ -269,36 +269,3 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                2048, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal(struct lws_context *context,
-                     struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index db9f03e..507ec3e 100644 (file)
@@ -1,79 +1,25 @@
-cmake_minimum_required(VERSION 2.8.9)
+project(lws-minimal-ws-server-pmd C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server-pmd)
 set(SRCS minimal-ws-server-pmd.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 require_lws_config(LWS_WITHOUT_EXTENSIONS 0 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 2b7b567..4496a35 100644 (file)
@@ -21,9 +21,9 @@
 #include "protocol_lws_minimal.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_MINIMAL,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
index 4760a20..d10384a 100644 (file)
@@ -27,15 +27,12 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
 document.addEventListener("DOMContentLoaded", function() {
 
-       ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
+       var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
        try {
                ws.onopen = function() {
                        document.getElementById("m").disabled = 0;
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index be72f82..00287d7 100644 (file)
@@ -158,36 +158,3 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                128, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal(struct lws_context *context,
-                     struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index e199801..7f58124 100644 (file)
@@ -1,78 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-server-ring C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server-ring)
 set(SRCS minimal-ws-server-ring.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index c87ad20..f4e02a2 100644 (file)
@@ -22,9 +22,9 @@
 #include "protocol_lws_minimal.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_MINIMAL,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
index be1037f..6b2cdce 100644 (file)
@@ -26,15 +26,12 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
 document.addEventListener("DOMContentLoaded", function() {
 
-       ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
+       var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
        try {
                ws.onopen = function() {
                        document.getElementById("m").disabled = 0;
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 7b51066..4b6e87e 100644 (file)
@@ -55,7 +55,7 @@ cull_lagging_clients(struct per_vhost_data__minimal *vhd)
 {
        uint32_t oldest_tail = lws_ring_get_oldest_tail(vhd->ring);
        struct per_session_data__minimal *old_pss = NULL;
-       int most = 0, before = lws_ring_get_count_waiting_elements(vhd->ring,
+       int most = 0, before = (int)lws_ring_get_count_waiting_elements(vhd->ring,
                                        &oldest_tail), m;
 
        /*
@@ -111,7 +111,7 @@ cull_lagging_clients(struct per_vhost_data__minimal *vhd)
                         * what is the largest number of pending ring elements
                         * for any survivor.
                         */
-                       m = lws_ring_get_count_waiting_elements(vhd->ring,
+                       m = (int)lws_ring_get_count_waiting_elements(vhd->ring,
                                                        &((*ppss)->tail));
                        if (m > most)
                                most = m;
@@ -129,7 +129,7 @@ cull_lagging_clients(struct per_vhost_data__minimal *vhd)
         */
 
        lws_ring_consume_and_update_oldest_tail(vhd->ring,
-               struct per_session_data__minimal, &old_pss->tail, before - most,
+               struct per_session_data__minimal, &old_pss->tail, (size_t)(before - most),
                vhd->pss_list, tail, pss_list);
 
        lwsl_user("%s: shrunk ring from %d to %d\n", __func__, before, most);
@@ -279,36 +279,3 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                0, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal(struct lws_context *context,
-                     struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index 951e9f6..b7c153f 100644 (file)
@@ -1,92 +1,27 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-server-threadpool C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckIncludeFile)
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server-threadpool)
 set(SRCS minimal-ws-server-threadpool.c)
 
-MACRO(require_pthreads result)
-       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
-       if (NOT LWS_HAVE_PTHREAD_H)
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(result 0)
-               else()
-                       message(FATAL_ERROR "threading support requires pthreads")
-               endif()
-       endif()
-ENDMACRO()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_pthreads(requirements)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 require_lws_config(LWS_WITH_THREADPOOL 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared pthread)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets pthread)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index e0d8a9d..63a1202 100644 (file)
 #include <libwebsockets.h>
 #include <string.h>
 #include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 
 #define LWS_PLUGIN_STATIC
 #include "protocol_lws_minimal_threadpool.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_MINIMAL,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
@@ -125,5 +131,7 @@ int main(int argc, const char **argv)
 
        lws_context_destroy(context);
 
+       lwsl_user("%s: exiting cleanly...\n", __func__);
+
        return 0;
 }
index 783ae13..cccc7d9 100644 (file)
@@ -28,9 +28,6 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
@@ -40,7 +37,7 @@ document.addEventListener("DOMContentLoaded", function() {
        
        for (n = 0; n < 8; n++) {
        
-               ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
+               var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
                wsa.push(ws);
                try {
                        ws.onopen = function() {
@@ -68,7 +65,8 @@ document.addEventListener("DOMContentLoaded", function() {
                        };
 
                        ws.onclose = function(){
-                               if (--alive === 0)
+                               alive--;
+                               if (alive === 0)
                                        document.getElementById("r").disabled = 1;
                        };
                } catch(exception) {
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index aea48e7..c93d742 100644 (file)
@@ -34,6 +34,8 @@
 
 struct per_vhost_data__minimal {
        struct lws_threadpool *tp;
+       struct lws_context *context;
+       lws_sorted_usec_list_t sul;
        const char *config;
 };
 
@@ -43,6 +45,10 @@ struct task_data {
        uint64_t pos, end;
 };
 
+#if defined(WIN32)
+static void usleep(unsigned long l) { Sleep(l / 1000); }
+#endif
+
 /*
  * Create the private data for the task
  *
@@ -129,6 +135,22 @@ task_function(void *user, enum lws_threadpool_task_status s)
        return LWS_TP_RETURN_CHECKING_IN;
 }
 
+
+static void
+sul_tp_dump(struct lws_sorted_usec_list *sul)
+{
+       struct per_vhost_data__minimal *vhd =
+               lws_container_of(sul, struct per_vhost_data__minimal, sul);
+       /*
+        * in debug mode, dump the threadpool stat to the logs once
+        * a second
+        */
+       lws_threadpool_dump(vhd->tp);
+       lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                        sul_tp_dump, LWS_US_PER_SEC);
+}
+
+
 static int
 callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                        void *user, void *in, size_t len)
@@ -155,6 +177,8 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                if (!vhd)
                        return 1;
 
+               vhd->context = lws_get_context(wsi);
+
                /* recover the pointer to the globals struct */
                pvo = lws_pvo_search(
                        (const struct lws_protocol_vhost_options *)in,
@@ -175,27 +199,14 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                if (!vhd->tp)
                        return 1;
 
-               lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
-                                              lws_get_protocol(wsi),
-                                              LWS_CALLBACK_USER, 1);
-
+               lws_sul_schedule(vhd->context, 0, &vhd->sul,
+                                sul_tp_dump, LWS_US_PER_SEC);
                break;
 
        case LWS_CALLBACK_PROTOCOL_DESTROY:
                lws_threadpool_finish(vhd->tp);
                lws_threadpool_destroy(vhd->tp);
-               break;
-
-       case LWS_CALLBACK_USER:
-
-               /*
-                * in debug mode, dump the threadpool stat to the logs once
-                * a second
-                */
-               lws_threadpool_dump(vhd->tp);
-               lws_timed_callback_vh_protocol(lws_get_vhost(wsi),
-                                              lws_get_protocol(wsi),
-                                              LWS_CALLBACK_USER, 1);
+               lws_sul_cancel(&vhd->sul);
                break;
 
        case LWS_CALLBACK_ESTABLISHED:
@@ -237,7 +248,7 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
 
        case LWS_CALLBACK_WS_SERVER_DROP_PROTOCOL:
                lwsl_debug("LWS_CALLBACK_WS_SERVER_DROP_PROTOCOL: %p\n", wsi);
-               lws_threadpool_dequeue(wsi);
+               lws_threadpool_dequeue_task(lws_threadpool_get_task_wsi(wsi));
                break;
 
        case LWS_CALLBACK_SERVER_WRITEABLE:
@@ -253,7 +264,10 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                 * private task data.
                 */
 
-               n = lws_threadpool_task_status_wsi(wsi, &task, &_user);
+               task = lws_threadpool_get_task_wsi(wsi);
+               if (!task)
+                       break;
+               n = (int)lws_threadpool_task_status(task, &_user);
                lwsl_debug("%s: LWS_CALLBACK_SERVER_WRITEABLE: status %d\n",
                           __func__, n);
                switch(n) {
@@ -276,9 +290,9 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
 
                lws_set_timeout(wsi, PENDING_TIMEOUT_THREADPOOL_TASK, 5);
 
-               n = strlen(priv->result + LWS_PRE);
+               n = (int)strlen(priv->result + LWS_PRE);
                m = lws_write(wsi, (unsigned char *)priv->result + LWS_PRE,
-                             n, LWS_WRITE_TEXT);
+                             (unsigned int)n, LWS_WRITE_TEXT);
                if (m < n) {
                        lwsl_err("ERROR %d writing to ws socket\n", m);
                        lws_threadpool_task_sync(task, 1);
@@ -308,36 +322,3 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                128, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal(struct lws_context *context,
-                     struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal(struct lws_context *context)
-{
-       return 0;
-}
-#endif
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/CMakeLists.txt b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/CMakeLists.txt
new file mode 100644 (file)
index 0000000..78fbf29
--- /dev/null
@@ -0,0 +1,44 @@
+project(lws-minimal-ws-server-threads-foreign-libuv-smp C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
+
+set(SAMP lws-minimal-ws-server-threads-foreign-smp)
+set(SRCS minimal-ws-server.c)
+
+set(requirements 1)
+require_pthreads(requirements)
+require_lws_config(LWS_ROLE_WS 1 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_TLS 1 requirements)
+require_lws_config(LWS_WITH_LIBUV 1 requirements)
+
+CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(LWS_WITH_LIBUV)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBUV)
+
+if (NOT LWS_WITH_LIBUV)
+       set(requirements 0)
+endif()
+
+
+if (requirements)
+       add_executable(${SAMP} ${SRCS})
+       
+       find_path(LIBUV_INCLUDE_DIRS NAMES uv.h)
+       find_library(LIBUV_LIBRARIES NAMES uv)
+       message("libuv include dir: ${LIBUV_INCLUDE_DIRS}")
+       message("libuv libraries: ${LIBUV_LIBRARIES}")
+       include_directories("${LIBUV_INCLUDE_DIRS}")
+       set(extralibs ${extralibs} ${LIBUV_LIBRARIES})
+       
+       message("Extra libs: ${extralibs}")
+
+               if (websockets_shared)
+                       target_link_libraries(${SAMP} websockets_shared ${extralibs} ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+                       add_dependencies(${SAMP} websockets_shared)
+               else()
+                       target_link_libraries(${SAMP} websockets ${extralibs} ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
+               endif()
+endif()
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/README.md b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/README.md
new file mode 100644 (file)
index 0000000..e50adaf
--- /dev/null
@@ -0,0 +1,39 @@
+# lws minimal ws server (threads) + SMP
+
+This demonstrates both independent threads creating content as in the
+-threads example, multiple service threads as in the http-server-smp
+example (but with ws), and using the foreign libuv loop.
+
+## build
+
+You must first build libwebsockets itself with cmake `-DLWS_MAX_SMP=8`
+or some other number greater than one, as well as `-DLWS_WITH_LIBUV=1`
+
+```
+ $ cmake . && make
+```
+
+Pthreads is required on your system.
+
+## usage
+
+```
+ $ ./lws-minimal-ws-server-threads-smp
+[2019/01/28 06:59:17:4217] USER: LWS minimal ws server + threads + smp | visit http://localhost:7681
+[2019/01/28 06:59:17:4219] NOTICE:   Service threads: 2
+[2019/01/28 06:59:17:4220] NOTICE: LWS_CALLBACK_EVENT_WAIT_CANCELLED in svc tid 0x7fec48af8700
+[2019/01/28 06:59:17:4220] NOTICE: LWS_CALLBACK_EVENT_WAIT_CANCELLED in svc tid 0x7fec48af8700
+...
+```
+
+Visit http://localhost:7681 on multiple browser windows.  You may need to open
+4 before the second service thread is used (check "svc tid" in the browser output).
+
+Two lws service threads are started.
+
+Two separate asynchronous threads generate strings and add them to a ringbuffer,
+signalling all lws service threads to send new entries to all the browser windows.
+
+This demonstrates how to safely manage asynchronously generated content
+and hook it up to the lws service threads.
+
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/minimal-ws-server.c b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/minimal-ws-server.c
new file mode 100644 (file)
index 0000000..1b8299a
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * lws-minimal-ws-server-threads-foreign-smp
+ *
+ * Written in 2010-2020 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a minimal ws server that can cooperate with
+ * other threads cleanly.  Two other threads are started, which fill
+ * a ringbuffer with strings at 10Hz.
+ *
+ * The actual work and thread spawning etc are done in the protocol
+ * implementation in protocol_lws_minimal.c.
+ *
+ * To keep it simple, it serves stuff in the subdirectory "./mount-origin" of
+ * the directory it was started in.
+ * You can change that by changing mount.origin.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
+#include <pthread.h>
+#include <uv.h>
+
+#define COUNT_THREADS 5
+
+#define LWS_PLUGIN_STATIC
+#include "protocol_lws_minimal.c"
+
+static struct lws_protocols protocols[] = {
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
+       LWS_PLUGIN_PROTOCOL_MINIMAL,
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static struct lws_context *context;
+static int interrupted;
+static uv_loop_t loop[COUNT_THREADS];
+static uv_signal_t *s, signal_outer[COUNT_THREADS];
+
+static const struct lws_http_mount mount = {
+       /* .mount_next */               NULL,           /* linked-list "next" */
+       /* .mountpoint */               "/",            /* mountpoint URL */
+       /* .origin */                   "./mount-origin", /* serve from dir */
+       /* .def */                      "index.html",   /* default filename */
+       /* .protocol */                 NULL,
+       /* .cgienv */                   NULL,
+       /* .extra_mimetypes */          NULL,
+       /* .interpret */                NULL,
+       /* .cgi_timeout */              0,
+       /* .cache_max_age */            0,
+       /* .auth_mask */                0,
+       /* .cache_reusable */           0,
+       /* .cache_revalidate */         0,
+       /* .cache_intermediaries */     0,
+       /* .origin_protocol */          LWSMPRO_FILE,   /* files in a dir */
+       /* .mountpoint_len */           1,              /* char count */
+       /* .basic_auth_login_file */    NULL,
+};
+
+/*
+ * This demonstrates how to pass a pointer into a specific protocol handler
+ * running on a specific vhost.  In this case, it's our default vhost and
+ * we pass the pvo named "config" with the value a const char * "myconfig".
+ *
+ * This is the preferred way to pass configuration into a specific vhost +
+ * protocol instance.
+ */
+
+static const struct lws_protocol_vhost_options pvo_ops = {
+       NULL,
+       NULL,
+       "config",               /* pvo name */
+       (void *)"myconfig"      /* pvo value */
+};
+
+static const struct lws_protocol_vhost_options pvo = {
+       NULL,           /* "next" pvo linked-list */
+       &pvo_ops,       /* "child" pvo linked-list */
+       "lws-minimal",  /* protocol name we belong to on this vhost */
+       ""              /* ignored */
+};
+
+void *thread_service(void *threadid)
+{
+       /*
+        * This is a foreign thread context for each event loop... lws doesn't
+        * know about it, except that it's getting called into from the event
+        * lib bound to each of these.
+        *
+        * When closing, at the point we have detached everything related to
+        * lws from the loop and destroyed the context we can as the "foreign
+        * app" take care of stopping the foreign loop and cloing this thread.
+        *
+        * The call to lws_service_tsi just starts the related event loop
+        */
+       while (lws_service_tsi(context, 0,
+                              (int)(lws_intptr_t)threadid) >= 0 &&
+              !interrupted)
+               lwsl_notice("%s\n", __func__);
+
+       lwsl_info("%s: thr %d: exiting\n", __func__, (int)(lws_intptr_t)threadid);
+
+       pthread_exit(NULL);
+
+       return NULL;
+}
+
+static void
+signal_cb(uv_signal_t *watcher, int signum)
+{
+       int n;
+
+       n = (int)(watcher - signal_outer);
+
+       lwsl_notice("%s: thr %d: signal %d caught\n", __func__, n,
+                       watcher->signum);
+
+       uv_signal_stop(watcher);
+       uv_close((uv_handle_t *)&signal_outer[n], NULL);
+       if (!interrupted) {
+               interrupted = 1;
+               lws_context_destroy(context);
+       }
+}
+
+int main(int argc, const char **argv)
+{
+       int n, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
+       pthread_t pthread_service[COUNT_THREADS];
+       struct lws_context_creation_info info;
+       void *foreign_loops[COUNT_THREADS];
+       int actual_threads;
+       const char *p;
+       void *retval;
+
+       if ((p = lws_cmdline_option(argc, argv, "-d")))
+               logs = atoi(p);
+
+       lws_set_log_level(logs, NULL);
+       lwsl_user("LWS minimal ws server + threads + smp | visit http://localhost:7681\n");
+
+       for (n = 0; n < COUNT_THREADS; n++) {
+               uv_loop_init(&loop[n]);
+
+               s = &signal_outer[n];
+               uv_signal_init(&loop[n], s);
+               uv_signal_start(s, signal_cb, SIGINT);
+
+               foreign_loops[n] = &loop[n];
+       }
+
+       memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
+       info.port = 7681;
+       info.mounts = &mount;
+       info.pcontext = &context;
+       info.protocols = protocols;
+       info.pvo = &pvo; /* per-vhost options */
+       info.foreign_loops = foreign_loops;
+       info.count_threads = COUNT_THREADS;
+       info.options = LWS_SERVER_OPTION_LIBUV |
+               LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
+
+       context = lws_create_context(&info);
+       if (!context) {
+               lwsl_err("lws init failed\n");
+               return 1;
+       }
+
+       actual_threads = lws_get_count_threads(context);
+       lwsl_notice("  Service threads: %d\n", actual_threads);
+
+       /* start all the service threads */
+
+       for (n = 0; n < actual_threads; n++)
+               if (pthread_create(&pthread_service[n], NULL, thread_service,
+                                  (void *)(lws_intptr_t)n))
+                       lwsl_err("Failed to start service thread\n");
+
+       /* wait for all the service threads to exit */
+
+       while ((--n) >= 0)
+               pthread_join(pthread_service[n], &retval);
+
+       lws_context_destroy(context);
+
+       for (n = 0; n < COUNT_THREADS; n++) {
+               int m;
+
+               m = uv_loop_close(&loop[n]);
+               if (m)
+                       lwsl_notice("%s: uv_close_loop %d: %d\n", __func__, n, m);
+       }
+
+       return 0;
+}
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/example.js b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/example.js
new file mode 100644 (file)
index 0000000..b17a826
--- /dev/null
@@ -0,0 +1,68 @@
+var head = 0, tail = 0, ring = new Array();
+
+function get_appropriate_ws_url(extra_url)
+{
+       var pcol;
+       var u = document.URL;
+
+       /*
+        * We open the websocket encrypted if this page came on an
+        * https:// url itself, otherwise unencrypted
+        */
+
+       if (u.substring(0, 5) === "https") {
+               pcol = "wss://";
+               u = u.substr(8);
+       } else {
+               pcol = "ws://";
+               if (u.substring(0, 4) === "http")
+                       u = u.substr(7);
+       }
+
+       u = u.split("/");
+
+       /* + "/xxx" bit is for IE10 workaround */
+
+       return pcol + u[0] + "/" + extra_url;
+}
+
+function new_ws(urlpath, protocol)
+{
+       return new WebSocket(urlpath, protocol);
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+
+       var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
+       try {
+               ws.onopen = function() {
+                       document.getElementById("r").disabled = 0;
+               };
+       
+               ws.onmessage =function got_packet(msg) {
+                       var n, s = "";
+       
+                       ring[head] = msg.data + "\n";
+                       head = (head + 1) % 50;
+                       if (tail === head)
+                               tail = (tail + 1) % 50;
+       
+                       n = tail;
+                       do {
+                               s = s + ring[n];
+                               n = (n + 1) % 50;
+                       } while (n !== head);
+       
+                       document.getElementById("r").value = s; 
+                       document.getElementById("r").scrollTop =
+                               document.getElementById("r").scrollHeight;
+               };
+       
+               ws.onclose = function(){
+                       document.getElementById("r").disabled = 1;
+               };
+       } catch(exception) {
+               alert("<p>Error " + exception);  
+       }
+
+}, false);
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/favicon.ico b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/favicon.ico
new file mode 100644 (file)
index 0000000..c0cc2e3
Binary files /dev/null and b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/favicon.ico differ
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/index.html b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/index.html
new file mode 100644 (file)
index 0000000..13145f6
--- /dev/null
@@ -0,0 +1,19 @@
+<html>
+ <head>
+  <meta charset=utf-8 http-equiv="Content-Language" content="en"/>
+  <script src="/example.js"></script>
+ </head>
+       <body>
+               <img src="libwebsockets.org-logo.svg">
+               <img src="strict-csp.svg"><br>
+
+               <b>Minimal ws server threads SMP example</b>.<br>
+               Strings generated by server threads are sent to
+               all browsers open on this page.<br>
+               The textarea show the last 50 lines received.
+               <br>
+               <br>
+               <textarea id=r readonly cols=80 rows=50></textarea><br>
+       </body>
+</html>
+
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/libwebsockets.org-logo.svg b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/libwebsockets.org-logo.svg
new file mode 100644 (file)
index 0000000..ef241b3
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
+</svg>
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/strict-csp.svg b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/mount-origin/strict-csp.svg
new file mode 100644 (file)
index 0000000..cd128f1
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="24.78mm" height="24.78mm" version="1.1" viewBox="0 0 24.780247 24.780247" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+  <linearGradient id="linearGradient955" x1="66.618" x2="82.588" y1="81.176" y2="64.828" gradientTransform="matrix(.82538 0 0 .82538 -392 -92.399)" gradientUnits="userSpaceOnUse">
+   <stop stop-color="#0aa70b" offset="0"/>
+   <stop stop-color="#3bff39" offset="1"/>
+  </linearGradient>
+  <filter id="filter945" x="-.0516" y="-.0516" width="1.1032" height="1.1032" color-interpolation-filters="sRGB">
+   <feGaussianBlur stdDeviation="0.58510713"/>
+  </filter>
+ </defs>
+ <g transform="translate(342.15 43.638)">
+  <circle transform="matrix(.82538 0 0 .82538 -392 -92.399)" cx="75.406" cy="74.089" r="13.607" filter="url(#filter945)" stroke="#000" stroke-linecap="round" stroke-width="1.565"/>
+  <circle cx="-330.23" cy="-31.716" r="11.231" fill="url(#linearGradient955)" stroke="#000" stroke-linecap="round" stroke-width="1.2917"/>
+  <g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".51676px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Strict">
+   <path d="m-330.78-33.775q0 0.73996-0.53676 1.154-0.53676 0.41407-1.4569 0.41407-0.99684 0-1.5336-0.25688v-0.62878q0.34506 0.14569 0.75147 0.23004 0.4064 0.08435 0.80514 0.08435 0.65177 0 0.9815-0.24538 0.32972-0.24921 0.32972-0.69012 0-0.29138-0.11885-0.47542-0.11502-0.18787-0.39107-0.34506-0.27221-0.15719-0.83198-0.35656-0.78213-0.27988-1.1195-0.66328-0.33356-0.3834-0.33356-1.0007 0-0.64794 0.48692-1.0313 0.48691-0.3834 1.2882-0.3834 0.83581 0 1.5374 0.30672l-0.2032 0.56743q-0.69395-0.29138-1.3496-0.29138-0.51759 0-0.80897 0.22237t-0.29138 0.61727q0 0.29138 0.10735 0.47925 0.10735 0.18403 0.36039 0.34123 0.25688 0.15336 0.78214 0.34122 0.88182 0.31439 1.2115 0.67478 0.33356 0.3604 0.33356 0.93549z"/>
+   <path d="m-328.37-32.732q0.16869 0 0.32589-0.023 0.15719-0.02684 0.24921-0.05368v0.48692q-0.10352 0.04984-0.30672 0.08051-0.19937 0.03451-0.3604 0.03451-1.2192 0-1.2192-1.2844v-2.4998h-0.60194v-0.30672l0.60194-0.26455 0.26838-0.89716h0.36807v0.97384h1.2192v0.49458h-1.2192v2.4729q0 0.37957 0.18019 0.58277 0.1802 0.2032 0.49459 0.2032z"/>
+   <path d="m-325.04-36.562q0.27989 0 0.50226 0.04601l-0.0882 0.59044q-0.26072-0.05751-0.46008-0.05751-0.50993 0-0.87415 0.41407-0.3604 0.41407-0.3604 1.0313v2.2544h-0.63644v-4.2021h0.52525l0.0729 0.7783h0.0307q0.23388-0.41024 0.5636-0.63261 0.32972-0.22237 0.72462-0.22237z"/>
+   <path d="m-323.11-32.284h-0.63644v-4.2021h0.63644zm-0.69012-5.3408q0-0.21854 0.10735-0.31822 0.10735-0.10352 0.26838-0.10352 0.15336 0 0.26455 0.10352 0.11118 0.10352 0.11118 0.31822 0 0.2147-0.11118 0.32206-0.11119 0.10352-0.26455 0.10352-0.16103 0-0.26838-0.10352-0.10735-0.10735-0.10735-0.32206z"/>
+   <path d="m-320.07-32.207q-0.91249 0-1.4147-0.55976-0.49842-0.5636-0.49842-1.5911 0-1.0543 0.50609-1.6294 0.50992-0.5751 1.4492-0.5751 0.30288 0 0.60577 0.06518 0.30288 0.06518 0.47541 0.15336l-0.19553 0.54059q-0.21087-0.08435-0.46008-0.13802-0.24921-0.05751-0.44091-0.05751-1.2806 0-1.2806 1.6333 0 0.77447 0.31055 1.1885 0.31439 0.41407 0.92783 0.41407 0.52526 0 1.0774-0.22621v0.5636q-0.42174 0.21854-1.062 0.21854z"/>
+   <path d="m-316.65-32.732q0.16869 0 0.32589-0.023 0.15719-0.02684 0.24921-0.05368v0.48692q-0.10352 0.04984-0.30672 0.08051-0.19937 0.03451-0.3604 0.03451-1.2192 0-1.2192-1.2844v-2.4998h-0.60194v-0.30672l0.60194-0.26455 0.26838-0.89716h0.36806v0.97384h1.2192v0.49458h-1.2192v2.4729q0 0.37957 0.1802 0.58277 0.1802 0.2032 0.49459 0.2032z"/>
+  </g>
+  <g fill="#fff">
+   <g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".3317px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Content">
+    <path d="m-332.67-30.173q-0.5931 0-0.93764 0.39622-0.34208 0.39376-0.34208 1.0804 0 0.70631 0.32977 1.0927 0.33224 0.38392 0.94503 0.38392 0.37653 0 0.85889-0.13536v0.36669q-0.37407 0.14028-0.92288 0.14028-0.7949 0-1.228-0.48236-0.43067-0.48236-0.43067-1.3708 0-0.55619 0.20672-0.97456 0.20919-0.41837 0.60049-0.64478 0.39376-0.22641 0.92533-0.22641 0.56603 0 0.98933 0.20672l-0.1772 0.35931q-0.40852-0.19196-0.81705-0.19196z"/>
+    <path d="m-328.77-28.248q0 0.65955-0.33224 1.0312-0.33223 0.36915-0.91795 0.36915-0.36177 0-0.64233-0.16981-0.28055-0.16981-0.43313-0.48728-0.15259-0.31747-0.15259-0.74322 0-0.65955 0.32978-1.0262 0.32977-0.36915 0.91549-0.36915 0.56603 0 0.89827 0.37653 0.3347 0.37653 0.3347 1.0189zm-2.0549 0q0 0.51681 0.20672 0.78752 0.20673 0.27071 0.60787 0.27071t0.60787-0.26825q0.20918-0.27071 0.20918-0.78998 0-0.51435-0.20918-0.78014-0.20673-0.26825-0.61279-0.26825-0.40115 0-0.60541 0.26333-0.20426 0.26333-0.20426 0.78506z"/>
+    <path d="m-326.21-26.897v-1.7449q0-0.32978-0.15012-0.4922-0.15012-0.16243-0.47005-0.16243-0.42329 0-0.62017 0.22887-0.19688 0.22887-0.19688 0.75553v1.4151h-0.40853v-2.6973h0.33223l0.0664 0.36915h0.0197q0.12551-0.19934 0.35192-0.30762 0.22642-0.11075 0.50451-0.11075 0.48728 0 0.73338 0.23626 0.2461 0.2338 0.2461 0.75061v1.7596z"/>
+    <path d="m-324.09-27.185q0.10828 0 0.20918-0.01477 0.1009-0.01723 0.15997-0.03445v0.31255q-0.0665 0.03199-0.19688 0.05168-0.12797 0.02215-0.23134 0.02215-0.7826 0-0.7826-0.82444v-1.6046h-0.38637v-0.19688l0.38637-0.16981 0.17227-0.57588h0.23626v0.6251h0.7826v0.31747h-0.7826v1.5873q0 0.24364 0.11567 0.37407 0.11566 0.13043 0.31747 0.13043z"/>
+    <path d="m-322.04-26.848q-0.59802 0-0.94502-0.36423-0.34454-0.36423-0.34454-1.0115 0-0.65217 0.31993-1.0361 0.32239-0.38392 0.86381-0.38392 0.50697 0 0.80229 0.3347 0.29532 0.33224 0.29532 0.87858v0.25841h-1.8581q0.0123 0.47497 0.23872 0.72107 0.22887 0.2461 0.64232 0.2461 0.4356 0 0.86135-0.18212v0.36423q-0.21657 0.09352-0.41099 0.13289-0.19195 0.04184-0.46513 0.04184zm-0.11074-2.4536q-0.32485 0-0.51927 0.21165-0.19196 0.21165-0.22642 0.58572h1.4102q0-0.38638-0.17227-0.59064-0.17227-0.20672-0.4922-0.20672z"/>
+    <path d="m-318.51-26.897v-1.7449q0-0.32978-0.15012-0.4922-0.15013-0.16243-0.47006-0.16243-0.42329 0-0.62017 0.22887-0.19688 0.22887-0.19688 0.75553v1.4151h-0.40853v-2.6973h0.33224l0.0664 0.36915h0.0197q0.12552-0.19934 0.35193-0.30762 0.22641-0.11075 0.5045-0.11075 0.48728 0 0.73338 0.23626 0.2461 0.2338 0.2461 0.75061v1.7596z"/>
+    <path d="m-316.4-27.185q0.10829 0 0.20919-0.01477 0.1009-0.01723 0.15996-0.03445v0.31255q-0.0664 0.03199-0.19688 0.05168-0.12797 0.02215-0.23133 0.02215-0.7826 0-0.7826-0.82444v-1.6046h-0.38638v-0.19688l0.38638-0.16981 0.17227-0.57588h0.23625v0.6251h0.7826v0.31747h-0.7826v1.5873q0 0.24364 0.11567 0.37407 0.11567 0.13043 0.31747 0.13043z"/>
+   </g>
+   <g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".32428px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Security">
+    <path d="m-332.03-22.859q0 0.46434-0.33683 0.72417-0.33682 0.25984-0.91423 0.25984-0.62553 0-0.96236-0.1612v-0.39456q0.21653 0.09142 0.47155 0.14435 0.25503 0.05293 0.50524 0.05293 0.409 0 0.61591-0.15398 0.20691-0.15638 0.20691-0.43306 0-0.18285-0.0746-0.29833-0.0722-0.11789-0.2454-0.21653-0.17082-0.09864-0.52208-0.22375-0.4908-0.17563-0.70252-0.41622-0.20931-0.24059-0.20931-0.62794 0-0.4066 0.30555-0.64718t0.80838-0.24059q0.52448 0 0.96476 0.19247l-0.12751 0.35607q-0.43547-0.18285-0.84687-0.18285-0.3248 0-0.50765 0.13954-0.18284 0.13954-0.18284 0.38735 0 0.18285 0.0674 0.30074 0.0674 0.11548 0.22615 0.21412 0.1612 0.09624 0.4908 0.21412 0.55336 0.19728 0.76027 0.42344 0.20931 0.22615 0.20931 0.58704z"/>
+    <path d="m-330.26-21.875q-0.58463 0-0.92386-0.35607-0.33683-0.35607-0.33683-0.98882 0-0.63756 0.31277-1.0129 0.31517-0.37532 0.84446-0.37532 0.49562 0 0.78432 0.3272 0.28871 0.3248 0.28871 0.8589v0.25262h-1.8164q0.012 0.46434 0.23338 0.70492 0.22374 0.24059 0.62793 0.24059 0.42584 0 0.84206-0.17804v0.35607q-0.21171 0.09142-0.40178 0.12992-0.18766 0.0409-0.45471 0.0409zm-0.10827-2.3987q-0.31757 0-0.50764 0.20691-0.18766 0.20691-0.22134 0.5726h1.3786q0-0.37772-0.16841-0.57741-0.16841-0.2021-0.48118-0.2021z"/>
+    <path d="m-327.56-21.875q-0.5726 0-0.88777-0.35126-0.31277-0.35366-0.31277-0.99844 0-0.66162 0.31758-1.0225 0.31998-0.36088 0.90942-0.36088 0.19007 0 0.38013 0.0409 0.19007 0.0409 0.29833 0.09624l-0.1227 0.33923q-0.13232-0.05293-0.2887-0.08661-0.15639-0.03609-0.27668-0.03609-0.80357 0-0.80357 1.0249 0 0.48599 0.19488 0.74582 0.19728 0.25984 0.58223 0.25984 0.3296 0 0.67605-0.14195v0.35366q-0.26465 0.13714-0.66643 0.13714z"/>
+    <path d="m-325.89-24.56v1.7106q0 0.32239 0.14676 0.48118 0.14675 0.15879 0.45952 0.15879 0.41381 0 0.60388-0.22615 0.19247-0.22615 0.19247-0.73861v-1.3858h0.39938v2.6369h-0.32961l-0.0577-0.35367h-0.0217q-0.1227 0.19488-0.34163 0.29833-0.21653 0.10345-0.49561 0.10345-0.48118 0-0.72177-0.22856-0.23818-0.22856-0.23818-0.73139v-1.725z"/>
+    <path d="m-322.04-24.608q0.17563 0 0.31517 0.02887l-0.0553 0.37051q-0.1636-0.03609-0.2887-0.03609-0.31999 0-0.54855 0.25984-0.22615 0.25984-0.22615 0.64718v1.4147h-0.39938v-2.6369h0.32961l0.0457 0.4884h0.0192q0.14676-0.25743 0.35366-0.39697 0.20691-0.13954 0.45472-0.13954z"/>
+    <path d="m-320.83-21.923h-0.39938v-2.6369h0.39938zm-0.43306-3.3514q0-0.13714 0.0674-0.19969 0.0674-0.06496 0.16841-0.06496 0.0962 0 0.16601 0.06496 0.0698 0.06496 0.0698 0.19969 0 0.13473-0.0698 0.2021-0.0698 0.06496-0.16601 0.06496-0.10105 0-0.16841-0.06496-0.0674-0.06736-0.0674-0.2021z"/>
+    <path d="m-319.13-22.205q0.10586 0 0.2045-0.01443 0.0986-0.01684 0.15638-0.03368v0.30555q-0.065 0.03128-0.19247 0.05052-0.1251 0.02165-0.22615 0.02165-0.76507 0-0.76507-0.80597v-1.5686h-0.37773v-0.19247l0.37773-0.16601 0.16841-0.56298h0.23096v0.6111h0.76508v0.31036h-0.76508v1.5518q0 0.23818 0.11308 0.3657t0.31036 0.12751z"/>
+    <path d="m-318.66-24.56h0.42825l0.57742 1.5037q0.19006 0.51486 0.23577 0.74342h0.0192q0.0313-0.1227 0.12992-0.41862 0.10105-0.29833 0.6544-1.8285h0.42825l-1.1332 3.0025q-0.16841 0.44509-0.39456 0.63034-0.22375 0.18766-0.55095 0.18766-0.18285 0-0.36088-0.0409v-0.31998q0.13232 0.02887 0.29592 0.02887 0.41141 0 0.58704-0.46193l0.14676-0.37532z"/>
+   </g>
+   <g transform="matrix(.70929 0 0 .70929 -99.465 -12.686)" stroke-width=".32334px" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="Policy">
+    <path d="m-329.37-19.254q0 0.53256-0.36464 0.82043-0.36224 0.28547-1.0387 0.28547h-0.41261v1.3794h-0.40782v-3.5072h0.90919q1.3146 0 1.3146 1.0219zm-1.816 0.75566h0.36703q0.54215 0 0.78445-0.17512 0.24229-0.17512 0.24229-0.56135 0-0.34784-0.2279-0.51817t-0.71008-0.17032h-0.45579z"/>
+    <path d="m-326.43-18.086q0 0.64291-0.32386 1.0051-0.32385 0.35984-0.89479 0.35984-0.35264 0-0.62612-0.16552t-0.42221-0.47498q-0.14873-0.30946-0.14873-0.72447 0-0.64291 0.32145-1.0003 0.32146-0.35984 0.8924-0.35984 0.55175 0 0.8756 0.36703 0.32626 0.36704 0.32626 0.99315zm-2.0031 0q0 0.50377 0.20151 0.76765t0.59253 0.26388q0.39103 0 0.59254-0.26148 0.2039-0.26388 0.2039-0.77005 0-0.50137-0.2039-0.76046-0.20151-0.26148-0.59733-0.26148-0.39103 0-0.59014 0.25668-0.19911 0.25668-0.19911 0.76525z"/>
+    <path d="m-325.33-16.769h-0.39822v-3.7327h0.39822z"/>
+    <path d="m-324.09-16.769h-0.39822v-2.6292h0.39822zm-0.43181-3.3417q0-0.13674 0.0672-0.19911 0.0672-0.06477 0.16793-0.06477 0.0959 0 0.16552 0.06477 0.0696 0.06477 0.0696 0.19911t-0.0696 0.20151q-0.0696 0.06477-0.16552 0.06477-0.10076 0-0.16793-0.06477-0.0672-0.06717-0.0672-0.20151z"/>
+    <path d="m-322.19-16.721q-0.57094 0-0.8852-0.35024-0.31186-0.35264-0.31186-0.99555 0-0.6597 0.31666-1.0195 0.31906-0.35984 0.90679-0.35984 0.18951 0 0.37903 0.04078 0.18951 0.04078 0.29746 0.09596l-0.12234 0.33825q-0.13194-0.05278-0.28787-0.08636-0.15593-0.03598-0.27588-0.03598-0.80123 0-0.80123 1.0219 0 0.48458 0.19431 0.74366 0.19671 0.25908 0.58054 0.25908 0.32865 0 0.67409-0.14154v0.35264q-0.26388 0.13674-0.6645 0.13674z"/>
+    <path d="m-321.31-19.398h0.427l0.57574 1.4993q0.18952 0.51337 0.2351 0.74127h0.0192q0.0312-0.12234 0.12954-0.41741 0.10076-0.29747 0.65251-1.8232h0.427l-1.1299 2.9938q-0.16792 0.4438-0.39342 0.62852-0.2231 0.18712-0.54935 0.18712-0.18232 0-0.35984-0.04078v-0.31906q0.13194 0.02879 0.29507 0.02879 0.41021 0 0.58533-0.46059l0.14634-0.37423z"/>
+   </g>
+  </g>
+ </g>
+</svg>
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/protocol_lws_minimal.c b/minimal-examples/ws-server/minimal-ws-server-threads-foreign-libuv-smp/protocol_lws_minimal.c
new file mode 100644 (file)
index 0000000..7feaaca
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * ws protocol handler plugin for "lws-minimal" demonstrating multithread
+ *
+ * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ */
+
+#if !defined (LWS_PLUGIN_STATIC)
+#define LWS_DLL
+#define LWS_INTERNAL
+#include <libwebsockets.h>
+#endif
+
+#include <string.h>
+#include <assert.h>
+
+/* one of these created for each message in the ringbuffer */
+
+struct msg {
+       void *payload; /* is malloc'd */
+       size_t len;
+};
+
+/*
+ * One of these is created for each client connecting to us.
+ *
+ * It is ONLY read or written from the lws service thread context.
+ */
+
+struct per_session_data__minimal {
+       struct per_session_data__minimal *pss_list;
+       struct lws *wsi;
+       uint32_t tail;
+};
+
+/*
+ * One of these is created for each vhost our protocol is used with, that
+ * means it is a shared resource between the SMP threads and must be locked.
+ */
+
+struct per_vhost_data__minimal {
+       struct lws_context *context;
+       struct lws_vhost *vhost;
+       const struct lws_protocols *protocol;
+
+       struct per_session_data__minimal *pss_list; /* linked-list of live pss*/
+       pthread_t pthread_spam[2];
+
+       pthread_mutex_t lock_ring; /* serialize access to the ring buffer */
+       struct lws_ring *ring; /* {lock_ring} ringbuffer holding unsent content */
+
+       const char *config;
+       char finished;
+};
+
+#if defined(WIN32)
+static void usleep(unsigned long l) { Sleep(l / 1000); }
+#endif
+
+/*
+ * This runs under both lws service and "spam threads" contexts.
+ * Access is serialized by vhd->lock_ring.
+ */
+
+static void
+__minimal_destroy_message(void *_msg)
+{
+       struct msg *msg = _msg;
+
+       free(msg->payload);
+       msg->payload = NULL;
+       msg->len = 0;
+}
+
+/*
+ * This runs under the "spam thread" thread context only.
+ *
+ * We spawn two threads that generate messages with this.
+ *
+ */
+
+static void *
+thread_spam(void *d)
+{
+       struct per_vhost_data__minimal *vhd =
+                       (struct per_vhost_data__minimal *)d;
+       struct msg amsg;
+       int len = 128, index = 1, n, whoami = 0;
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
+               if (pthread_equal(pthread_self(), vhd->pthread_spam[n]))
+                       whoami = n + 1;
+
+       do {
+               pthread_mutex_lock(&vhd->lock_ring); /* --------- ring lock { */
+
+               /* don't generate output if nobody connected */
+               if (!vhd->pss_list)
+                       goto wait_unlock;
+
+               /* only create if space in ringbuffer */
+               n = (int)lws_ring_get_count_free_elements(vhd->ring);
+               if (!n) {
+                       // lwsl_user("dropping!\n");
+                       goto wait_unlock;
+               }
+
+               amsg.payload = malloc((unsigned int)(LWS_PRE + len));
+               if (!amsg.payload) {
+                       lwsl_user("OOM: dropping\n");
+                       goto wait_unlock;
+               }
+               n = lws_snprintf((char *)amsg.payload + LWS_PRE, (unsigned int)len,
+                                "%s: spam tid: %d, msg: %d", vhd->config,
+                                whoami, index++);
+               amsg.len = (unsigned int)n;
+               n = (int)lws_ring_insert(vhd->ring, &amsg, 1);
+               if (n != 1) {
+                       __minimal_destroy_message(&amsg);
+                       // lwsl_user("dropping!\n");
+               } else
+                       /*
+                        * This will cause a LWS_CALLBACK_EVENT_WAIT_CANCELLED
+                        * in the lws service thread context.
+                        */
+                       lws_cancel_service(vhd->context);
+
+wait_unlock:
+               pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
+
+               usleep(100000);
+
+       } while (!vhd->finished);
+
+       lwsl_notice("thread_spam %d exiting\n", whoami);
+
+       pthread_exit(NULL);
+
+       return NULL;
+}
+
+/* this runs under the lws service thread context only */
+
+static int
+callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
+                       void *user, void *in, size_t len)
+{
+       struct per_session_data__minimal *pss =
+                       (struct per_session_data__minimal *)user;
+       struct per_vhost_data__minimal *vhd =
+                       (struct per_vhost_data__minimal *)
+                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
+                                       lws_get_protocol(wsi));
+       const struct lws_protocol_vhost_options *pvo;
+       const struct msg *pmsg;
+       char temp[LWS_PRE + 256];
+       void *retval;
+       int n, m, r = 0;
+
+       switch (reason) {
+       case LWS_CALLBACK_PROTOCOL_INIT:
+               /* create our per-vhost struct */
+               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                               lws_get_protocol(wsi),
+                               sizeof(struct per_vhost_data__minimal));
+               if (!vhd)
+                       return 1;
+
+               pthread_mutex_init(&vhd->lock_ring, NULL);
+
+               /* recover the pointer to the globals struct */
+               pvo = lws_pvo_search(
+                       (const struct lws_protocol_vhost_options *)in,
+                       "config");
+               if (!pvo || !pvo->value) {
+                       lwsl_err("%s: Can't find \"config\" pvo\n", __func__);
+                       return 1;
+               }
+               vhd->config = pvo->value;
+
+               vhd->context = lws_get_context(wsi);
+               vhd->protocol = lws_get_protocol(wsi);
+               vhd->vhost = lws_get_vhost(wsi);
+
+               vhd->ring = lws_ring_create(sizeof(struct msg), 8,
+                                           __minimal_destroy_message);
+               if (!vhd->ring) {
+                       lwsl_err("%s: failed to create ring\n", __func__);
+                       return 1;
+               }
+
+               /* start the content-creating threads */
+
+               for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
+                       if (pthread_create(&vhd->pthread_spam[n], NULL,
+                                          thread_spam, vhd)) {
+                               lwsl_err("thread creation failed\n");
+                               r = 1;
+                               goto init_fail;
+                       }
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+init_fail:
+               vhd->finished = 1;
+               for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
+                       pthread_join(vhd->pthread_spam[n], &retval);
+
+               if (vhd->ring)
+                       lws_ring_destroy(vhd->ring);
+
+               pthread_mutex_destroy(&vhd->lock_ring);
+               break;
+
+       case LWS_CALLBACK_ESTABLISHED:
+               /* add ourselves to the list of live pss held in the vhd */
+               pthread_mutex_lock(&vhd->lock_ring);
+               lws_ll_fwd_insert(pss, pss_list, vhd->pss_list);
+               pss->tail = lws_ring_get_oldest_tail(vhd->ring);
+               pss->wsi = wsi;
+               pthread_mutex_unlock(&vhd->lock_ring);
+               break;
+
+       case LWS_CALLBACK_CLOSED:
+               /* doesn't reference ring */
+               pthread_mutex_lock(&vhd->lock_ring);
+               /* remove our closing pss from the list of live pss */
+               lws_ll_fwd_remove(struct per_session_data__minimal, pss_list,
+                                 pss, vhd->pss_list);
+               pthread_mutex_unlock(&vhd->lock_ring);
+               break;
+
+       case LWS_CALLBACK_SERVER_WRITEABLE:
+               pthread_mutex_lock(&vhd->lock_ring); /* --------- ring lock { */
+
+               pmsg = lws_ring_get_element(vhd->ring, &pss->tail);
+               if (!pmsg) {
+                       pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
+
+                       break;
+               }
+
+               assert(pmsg->payload);
+
+               n = lws_snprintf(temp + LWS_PRE, sizeof(temp) - LWS_PRE,
+                             "svc, %s",
+                             (char *)pmsg->payload + LWS_PRE);
+
+               /* notice we allowed for LWS_PRE in the payload already */
+               m = lws_write(wsi, (unsigned char *)temp + LWS_PRE, (unsigned int)n,
+                             LWS_WRITE_TEXT);
+               if (m < n) {
+                       pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
+
+                       lwsl_err("ERROR %d writing to ws socket\n", m);
+                       return -1;
+               }
+
+               lws_ring_consume_and_update_oldest_tail(
+                       vhd->ring,      /* lws_ring object */
+                       struct per_session_data__minimal, /* type of objects with tails */
+                       &pss->tail,     /* tail of guy doing the consuming */
+                       1,              /* number of payload objects being consumed */
+                       vhd->pss_list, /* head of list of objects with tails */
+                       tail,           /* member name of tail in objects with tails */
+                       pss_list        /* member name of next object in objects with tails */
+               );
+
+               /* more to do? */
+               if (lws_ring_get_element(vhd->ring, &pss->tail))
+                       /* come back as soon as we can write more */
+                       lws_callback_on_writable(pss->wsi);
+
+               pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
+
+               break;
+
+       case LWS_CALLBACK_RECEIVE:
+               break;
+
+       case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
+               // lwsl_notice("EVENT_WAIT_CANCELLED tsi %d\n", lws_wsi_tsi(wsi));
+               if (!vhd)
+                       break;
+               /*
+                * When the "spam" threads add a message to the ringbuffer,
+                * they create this event in the lws service thread context
+                * using lws_cancel_service().
+                *
+                * We respond by scheduling a writable callback for all
+                * connected clients.
+                */
+
+               pthread_mutex_lock(&vhd->lock_ring); /* --------- ring lock { */
+
+               lws_start_foreach_llp(struct per_session_data__minimal **,
+                                     ppss, vhd->pss_list) {
+                       if (lws_wsi_tsi((*ppss)->wsi) == lws_wsi_tsi(wsi))
+                               lws_callback_on_writable((*ppss)->wsi);
+               } lws_end_foreach_llp(ppss, pss_list);
+
+               pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
+               break;
+
+       default:
+               break;
+       }
+
+       return r;
+}
+
+#define LWS_PLUGIN_PROTOCOL_MINIMAL \
+       { \
+               "lws-minimal", \
+               callback_minimal, \
+               sizeof(struct per_session_data__minimal), \
+               128, \
+               0, NULL, 0 \
+       }
index 32ecbf5..098a174 100644 (file)
@@ -1,91 +1,27 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-server-threads-smp C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckIncludeFile)
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server-threads-smp)
 set(SRCS minimal-ws-server.c)
 
-MACRO(require_pthreads result)
-       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
-       if (NOT LWS_HAVE_PTHREAD_H)
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(result 0)
-               else()
-                       message(FATAL_ERROR "threading support requires pthreads")
-               endif()
-       endif()
-ENDMACRO()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_pthreads(requirements)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
+require_lws_config(LWS_WITH_SYS_STATE 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared pthread)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets pthread)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 8303f5c..43c5ea3 100644 (file)
 #include <libwebsockets.h>
 #include <string.h>
 #include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 
 #define LWS_PLUGIN_STATIC
 #define COUNT_THREADS 2
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_MINIMAL,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static struct lws_context *context;
-static int interrupted;
+static int interrupted, started;
+static pthread_t pthread_service[COUNT_THREADS];
 
 static const struct lws_http_mount mount = {
        /* .mount_next */               NULL,           /* linked-list "next" */
@@ -92,18 +99,58 @@ void *thread_service(void *threadid)
        return NULL;
 }
 
+static int
+system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
+                  int current, int target)
+{
+       struct lws_context *context = mgr->parent;
+       void *retval;
+
+       if (current != target)
+               return 0;
+
+       switch (current) {
+       case LWS_SYSTATE_OPERATIONAL:
+               lwsl_notice("  Service threads: %d\n",
+                           lws_get_count_threads(context));
+
+               /* start all the service threads */
+
+               for (started = 1; started < lws_get_count_threads(context);
+                    started++)
+                       if (pthread_create(&pthread_service[started], NULL,
+                                          thread_service,
+                                          (void *)(lws_intptr_t)started))
+                               lwsl_err("Failed to start service thread\n");
+               break;
+       case LWS_SYSTATE_CONTEXT_DESTROYING:
+               /* wait for all the service threads to exit */
+
+               while ((--started) >= 1)
+                       pthread_join(pthread_service[started], &retval);
+
+               break;
+       }
+
+       return 0;
+}
+
+lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
+                                    system_notify_cb, "app" };
+lws_state_notify_link_t *na[] = { &notifier, NULL };
+
 void sigint_handler(int sig)
 {
        interrupted = 1;
+       lws_cancel_service(context);
 }
 
 int main(int argc, const char **argv)
 {
-       int n, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
-       pthread_t pthread_service[COUNT_THREADS];
+       int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
        struct lws_context_creation_info info;
        const char *p;
-       void *retval;
+       int n = 0;
 
        signal(SIGINT, sigint_handler);
 
@@ -119,6 +166,7 @@ int main(int argc, const char **argv)
        info.protocols = protocols;
        info.pvo = &pvo; /* per-vhost options */
        info.count_threads = COUNT_THREADS;
+       info.register_notifier_list = na;
        info.options =
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
 
@@ -128,19 +176,8 @@ int main(int argc, const char **argv)
                return 1;
        }
 
-       lwsl_notice("  Service threads: %d\n", lws_get_count_threads(context));
-
-       /* start all the service threads */
-
-       for (n = 0; n < lws_get_count_threads(context); n++)
-               if (pthread_create(&pthread_service[n], NULL, thread_service,
-                                  (void *)(lws_intptr_t)n))
-                       lwsl_err("Failed to start service thread\n");
-
-       /* wait for all the service threads to exit */
-
-       while ((--n) >= 0)
-               pthread_join(pthread_service[n], &retval);
+       while (n >= 0 && !interrupted)
+               n = lws_service(context, 0);
 
        lws_context_destroy(context);
 
index a6ff663..b17a826 100644 (file)
@@ -28,15 +28,12 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
 document.addEventListener("DOMContentLoaded", function() {
 
-       ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
+       var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
        try {
                ws.onopen = function() {
                        document.getElementById("r").disabled = 0;
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 3943307..8c085aa 100644 (file)
@@ -83,7 +83,11 @@ thread_spam(void *d)
        struct per_vhost_data__minimal *vhd =
                        (struct per_vhost_data__minimal *)d;
        struct msg amsg;
-       int len = 128, index = 1, n;
+       int len = 128, index = 1, n, whoami = 0;
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
+               if (pthread_equal(pthread_self(), vhd->pthread_spam[n]))
+                       whoami = n + 1;
 
        do {
                /* don't generate output if nobody connected */
@@ -99,16 +103,16 @@ thread_spam(void *d)
                        goto wait_unlock;
                }
 
-               amsg.payload = malloc(LWS_PRE + len);
+               amsg.payload = malloc((unsigned int)(LWS_PRE + len));
                if (!amsg.payload) {
                        lwsl_user("OOM: dropping\n");
                        goto wait_unlock;
                }
-               n = lws_snprintf((char *)amsg.payload + LWS_PRE, len,
-                                "%s: spam tid: %p, msg: %d", vhd->config,
-                                (void *)pthread_self(), index++);
-               amsg.len = n;
-               n = lws_ring_insert(vhd->ring, &amsg, 1);
+               n = lws_snprintf((char *)amsg.payload + LWS_PRE, (unsigned int)len,
+                                "%s: spam tid: %d, msg: %d", vhd->config,
+                                whoami, index++);
+               amsg.len = (unsigned int)n;
+               n = (int)lws_ring_insert(vhd->ring, &amsg, 1);
                if (n != 1) {
                        __minimal_destroy_message(&amsg);
                        lwsl_user("dropping!\n");
@@ -127,7 +131,7 @@ wait:
 
        } while (!vhd->finished);
 
-       lwsl_notice("thread_spam %p exiting\n", (void *)pthread_self());
+       lwsl_notice("thread_spam %d exiting\n", whoami);
 
        pthread_exit(NULL);
 
@@ -199,8 +203,7 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
 init_fail:
                vhd->finished = 1;
                for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
-                       if (vhd->pthread_spam[n])
-                               pthread_join(vhd->pthread_spam[n], &retval);
+                       pthread_join(vhd->pthread_spam[n], &retval);
 
                if (vhd->ring)
                        lws_ring_destroy(vhd->ring);
@@ -231,11 +234,11 @@ init_fail:
                }
 
                n = lws_snprintf(temp + LWS_PRE, sizeof(temp) - LWS_PRE,
-                             "svc tid:%p, %s", (void *)pthread_self(),
+                             "svc, %s",
                              (char *)pmsg->payload + LWS_PRE);
 
                /* notice we allowed for LWS_PRE in the payload already */
-               m = lws_write(wsi, (unsigned char *)temp + LWS_PRE, n,
+               m = lws_write(wsi, (unsigned char *)temp + LWS_PRE, (unsigned int)n,
                              LWS_WRITE_TEXT);
                if (m < n) {
                        pthread_mutex_unlock(&vhd->lock_ring); /* } ring lock ------- */
@@ -265,8 +268,7 @@ init_fail:
                break;
 
        case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
-               lwsl_notice("LWS_CALLBACK_EVENT_WAIT_CANCELLED in svc tid %p\n",
-                               (void *)pthread_self());
+               lwsl_notice("LWS_CALLBACK_EVENT_WAIT_CANCELLED in svc\n");
                if (!vhd)
                        break;
                /*
@@ -298,36 +300,3 @@ init_fail:
                128, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal(struct lws_context *context,
-                     struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index bf67791..513ea9d 100644 (file)
@@ -1,91 +1,29 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-server-threads C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckIncludeFile)
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server-threads)
 set(SRCS minimal-ws-server.c)
 
-MACRO(require_pthreads result)
-       CHECK_INCLUDE_FILE(pthread.h LWS_HAVE_PTHREAD_H)
-       if (NOT LWS_HAVE_PTHREAD_H)
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(result 0)
-               else()
-                       message(FATAL_ERROR "threading support requires pthreads")
-               endif()
-       endif()
-ENDMACRO()
-
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
+if (WIN32)
+       set(requirements 0)
+endif()
 require_pthreads(requirements)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared pthread)
+               target_link_libraries(${SAMP} websockets_shared ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets pthread)
+               target_link_libraries(${SAMP} websockets ${PTHREAD_LIB} ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 40d7fc7..9e4627e 100644 (file)
 #include <libwebsockets.h>
 #include <string.h>
 #include <signal.h>
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#if defined(pid_t)
+#undef pid_t
+#endif
+#endif
 #include <pthread.h>
 
 #define LWS_PLUGIN_STATIC
 #include "protocol_lws_minimal.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
        LWS_PLUGIN_PROTOCOL_MINIMAL,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
 };
 
 static int interrupted;
index a6ff663..b17a826 100644 (file)
@@ -28,15 +28,12 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
 document.addEventListener("DOMContentLoaded", function() {
 
-       ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
+       var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
        try {
                ws.onopen = function() {
                        document.getElementById("r").disabled = 0;
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 3abd727..e01f64d 100644 (file)
@@ -83,7 +83,11 @@ thread_spam(void *d)
        struct per_vhost_data__minimal *vhd =
                        (struct per_vhost_data__minimal *)d;
        struct msg amsg;
-       int len = 128, index = 1, n;
+       int len = 128, index = 1, n, whoami = 0;
+
+       for (n = 0; n < (int)LWS_ARRAY_SIZE(vhd->pthread_spam); n++)
+               if (pthread_equal(pthread_self(), vhd->pthread_spam[n]))
+                       whoami = n + 1;
 
        do {
                /* don't generate output if nobody connected */
@@ -99,16 +103,16 @@ thread_spam(void *d)
                        goto wait_unlock;
                }
 
-               amsg.payload = malloc(LWS_PRE + len);
+               amsg.payload = malloc((unsigned int)(LWS_PRE + len));
                if (!amsg.payload) {
                        lwsl_user("OOM: dropping\n");
                        goto wait_unlock;
                }
-               n = lws_snprintf((char *)amsg.payload + LWS_PRE, len,
-                                "%s: tid: %p, msg: %d", vhd->config,
-                                (void *)pthread_self(), index++);
-               amsg.len = n;
-               n = lws_ring_insert(vhd->ring, &amsg, 1);
+               n = lws_snprintf((char *)amsg.payload + LWS_PRE, (unsigned int)len,
+                                "%s: tid: %d, msg: %d", vhd->config,
+                                whoami, index++);
+               amsg.len = (unsigned int)n;
+               n = (int)lws_ring_insert(vhd->ring, &amsg, 1);
                if (n != 1) {
                        __minimal_destroy_message(&amsg);
                        lwsl_user("dropping!\n");
@@ -127,7 +131,7 @@ wait:
 
        } while (!vhd->finished);
 
-       lwsl_notice("thread_spam %p exiting\n", (void *)pthread_self());
+       lwsl_notice("thread_spam %d exiting\n", whoami);
 
        pthread_exit(NULL);
 
@@ -291,36 +295,3 @@ init_fail:
                128, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal(struct lws_context *context,
-                     struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index acf3468..bc95805 100644 (file)
@@ -1,67 +1,13 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-server-timer C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server-timer)
 set(SRCS minimal-ws-server.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
 require_lws_config(LWS_WITH_SERVER 1 requirements)
@@ -70,9 +16,9 @@ if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
index 7349030..a7f0d1a 100644 (file)
@@ -48,9 +48,14 @@ callback_protocol(struct lws *wsi, enum lws_callback_reasons reason,
 }
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
-       { "timer", callback_protocol, 0, 0 },
-       { NULL, NULL, 0, 0 } /* terminator */
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0 },
+       { "timer", callback_protocol, 0, 0, 0, NULL, 0 },
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping = 3,
+       .secs_since_valid_hangup = 10,
 };
 
 static int interrupted;
@@ -109,16 +114,21 @@ int main(int argc, const char **argv)
        info.options =
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
 
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
                lwsl_user("Server using TLS\n");
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
        }
+#endif
 
        if (lws_cmdline_option(argc, argv, "-h"))
                info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
 
+       if (lws_cmdline_option(argc, argv, "-v"))
+               info.retry_and_idle_policy = &retry;
+
        context = lws_create_context(&info);
        if (!context) {
                lwsl_err("lws init failed\n");
index 3a638d0..5cc3073 100644 (file)
@@ -27,9 +27,6 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
index e69de29..c0cc2e3 100644 (file)
Binary files a/minimal-examples/ws-server/minimal-ws-server-timer/mount-origin/favicon.ico and b/minimal-examples/ws-server/minimal-ws-server-timer/mount-origin/favicon.ico differ
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 6b938b1..69a6481 100644 (file)
@@ -1,78 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+project(lws-minimal-ws-server C)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
+list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
 include(CheckCSourceCompiles)
+include(LwsCheckRequirements)
 
 set(SAMP lws-minimal-ws-server)
 set(SRCS minimal-ws-server.c)
 
-# If we are being built as part of lws, confirm current build config supports
-# reqconfig, else skip building ourselves.
-#
-# If we are being built externally, confirm installed lws was configured to
-# support reqconfig, else error out with a helpful message about the problem.
-#
-MACRO(require_lws_config reqconfig _val result)
-
-       if (DEFINED ${reqconfig})
-       if (${reqconfig})
-               set (rq 1)
-       else()
-               set (rq 0)
-       endif()
-       else()
-               set(rq 0)
-       endif()
-
-       if (${_val} EQUAL ${rq})
-               set(SAME 1)
-       else()
-               set(SAME 0)
-       endif()
-
-       if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
-               if (${_val})
-                       message("${SAMP}: skipping as lws being built without ${reqconfig}")
-               else()
-                       message("${SAMP}: skipping as lws built with ${reqconfig}")
-               endif()
-               set(${result} 0)
-       else()
-               if (LWS_WITH_MINIMAL_EXAMPLES)
-                       set(MET ${SAME})
-               else()
-                       CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
-                       if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
-                               set(HAS_${reqconfig} 0)
-                       else()
-                               set(HAS_${reqconfig} 1)
-                       endif()
-                       if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
-                               set(MET 1)
-                       else()
-                               set(MET 0)
-                       endif()
-               endif()
-               if (NOT MET)
-                       if (${_val})
-                               message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
-                       else()
-                               message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
-                       endif()
-               endif()
-       
-       endif()
-ENDMACRO()
-
 set(requirements 1)
 require_lws_config(LWS_ROLE_WS 1 requirements)
-require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
+require_lws_config(LWS_WITH_SERVER 1 requirements)
 
 if (requirements)
        add_executable(${SAMP} ${SRCS})
 
        if (websockets_shared)
-               target_link_libraries(${SAMP} websockets_shared)
+               target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
                add_dependencies(${SAMP} websockets_shared)
        else()
-               target_link_libraries(${SAMP} websockets)
+               target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
        endif()
 endif()
\ No newline at end of file
index 9b0a094..5132072 100644 (file)
@@ -13,6 +13,7 @@ Option|Meaning
 -d|Set logging verbosity
 -s|Serve using TLS selfsigned cert (ie, connect to it with https://...)
 -h|Strict Host: header checking against vhost name (localhost) and port
+-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
 
 ## usage
 
index 12e828a..6cfce7f 100644 (file)
 #include "protocol_lws_minimal.c"
 
 static struct lws_protocols protocols[] = {
-       { "http", lws_callback_http_dummy, 0, 0 },
+       { "http", lws_callback_http_dummy, 0, 0, 0, NULL, 0},
        LWS_PLUGIN_PROTOCOL_MINIMAL,
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PROTOCOL_LIST_TERM
+};
+
+static const lws_retry_bo_t retry = {
+       .secs_since_valid_ping = 3,
+       .secs_since_valid_hangup = 10,
 };
 
 static int interrupted;
@@ -49,6 +54,11 @@ static const struct lws_http_mount mount = {
        /* .basic_auth_login_file */    NULL,
 };
 
+#if defined(LWS_WITH_PLUGINS)
+/* if plugins enabled, only protocols explicitly named in pvo bind to vhost */
+static struct lws_protocol_vhost_options pvo = { NULL, NULL, "lws-minimal", "" };
+#endif
+
 void sigint_handler(int sig)
 {
        interrupted = 1;
@@ -80,20 +90,27 @@ int main(int argc, const char **argv)
        info.mounts = &mount;
        info.protocols = protocols;
        info.vhost_name = "localhost";
-       info.ws_ping_pong_interval = 10;
+#if defined(LWS_WITH_PLUGINS)
+       info.pvo = &pvo;
+#endif
        info.options =
                LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
 
+#if defined(LWS_WITH_TLS)
        if (lws_cmdline_option(argc, argv, "-s")) {
                lwsl_user("Server using TLS\n");
                info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
                info.ssl_cert_filepath = "localhost-100y.cert";
                info.ssl_private_key_filepath = "localhost-100y.key";
        }
+#endif
 
        if (lws_cmdline_option(argc, argv, "-h"))
                info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
 
+       if (lws_cmdline_option(argc, argv, "-v"))
+               info.retry_and_idle_policy = &retry;
+
        context = lws_create_context(&info);
        if (!context) {
                lwsl_err("lws init failed\n");
index 189f464..9c0a6ab 100644 (file)
@@ -27,15 +27,12 @@ function get_appropriate_ws_url(extra_url)
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
 
 document.addEventListener("DOMContentLoaded", function() {
        
-       ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
+       var ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
        try {
                ws.onopen = function() {
                        document.getElementById("m").disabled = 0;
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 3c8160b..6e0ed94 100644 (file)
@@ -152,36 +152,3 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                128, \
                0, NULL, 0 \
        }
-
-#if !defined (LWS_PLUGIN_STATIC)
-
-/* boilerplate needed if we are built as a dynamic plugin */
-
-static const struct lws_protocols protocols[] = {
-       LWS_PLUGIN_PROTOCOL_MINIMAL
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_minimal(struct lws_context *context,
-                     struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_minimal(struct lws_context *context)
-{
-       return 0;
-}
-#endif
index 2d213e9..71926b7 100644 (file)
@@ -1,4 +1,5 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8.12)
+find_package(libwebsockets CONFIG REQUIRED)
 
 if(NOT DEFINED CMAKE_BUILD_TYPE)
        set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type")
@@ -56,8 +57,9 @@ set(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
 source_group("Headers Private"   FILES ${PLUGIN_HDR})
 source_group("Sources"   FILES ${PLUGIN_SRCS})
 add_library(${PLUGIN_NAME} SHARED ${PLUGIN_SRCS} ${PLUGIN_HDR})
+target_compile_definitions(${PLUGIN_NAME} PRIVATE LWS_BUILDING_SHARED)
 
-target_link_libraries(${PLUGIN_NAME} -lwebsockets)
+target_link_libraries(${PLUGIN_NAME} -lwebsockets ${LIBWEBSOCKETS_DEP_LIBS})
 
 # Set test app specific defines.
 set_property(TARGET ${PLUGIN_NAME}
index c33f683..a6a177b 100644 (file)
  * outside the library easily.
  */
 
+#if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
+#endif
 
 #include <string.h>
 
@@ -127,26 +133,16 @@ static const struct lws_protocols protocols[] = {
        },
 };
 
-LWS_VISIBLE int
-init_protocol_example_standalone(struct lws_context *context,
-                            struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t protocol_example_standalone = {
+       .hdr = {
+               "standalone",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
 
-LWS_VISIBLE int
-destroy_protocol_example_standalone(struct lws_context *context)
-{
-       return 0;
-}
+       .protocols = protocols,
+       .count_protocols = LWS_ARRAY_SIZE(protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
new file mode 100644 (file)
index 0000000..15acd5b
--- /dev/null
@@ -0,0 +1,242 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+include_directories(.)
+
+if (DEFINED LIB_LIST_AT_END)
+link_libraries(${LIB_LIST_AT_END})
+endif()
+
+if ((LWS_WITH_PLUGINS AND LWS_WITH_SHARED) OR LWS_WITH_PLUGINS_BUILTIN)
+
+       #
+       # Either build the plugins as separate dynamic libs (LWS_WITH_PLUGINS)
+       # or build into the main lws library (LWS_WITH_PLUGINS_BUILTIN)
+       #
+
+       macro(create_plugin PLUGIN_NAME PLUGIN_INCLUDE MAIN_SRC S2 S3)
+
+               if (NOT LWS_WITH_PLUGINS_BUILTIN)
+                       set(PLUGIN_SRCS ${MAIN_SRC})
+
+                       if ("${S2}" STREQUAL "")
+                       else()
+                               list(APPEND PLUGIN_SRCS ${S2})
+                       endif()
+                       if ("${S3}" STREQUAL "")
+                       else()
+                               list(APPEND PLUGIN_SRCS ${S3})
+                       endif()
+
+                       if (WIN32)
+                               list(APPEND PLUGIN_SRCS
+                                       ${WIN32_HELPERS_PATH}/getopt.c
+                                       ${WIN32_HELPERS_PATH}/getopt_long.c
+                                       ${WIN32_HELPERS_PATH}/gettimeofday.c
+                               )
+
+                               list(APPEND PLUGIN_HDR
+                                       ${WIN32_HELPERS_PATH}/getopt.h
+                                       ${WIN32_HELPERS_PATH}/gettimeofday.h
+                               )
+                       endif(WIN32)
+
+                       source_group("Headers Private"   FILES ${PLUGIN_HDR})
+                       source_group("Sources"   FILES ${PLUGIN_SRCS})
+                       add_library(${PLUGIN_NAME} SHARED ${PLUGIN_SRCS} ${PLUGIN_HDR})
+                       target_link_libraries(${PLUGIN_NAME} websockets_shared)
+                       add_dependencies(${PLUGIN_NAME} websockets_shared)
+
+                       # doesn't work inside macro :-O
+                       # target_compile_definitions(${PLUGIN_NAME} PRIVATE LWS_BUILDING_SHARED)
+                       target_include_directories(${PLUGIN_NAME} PRIVATE ${PLUGIN_INCLUDE}
+                                                                         ${LWS_LIB_BUILD_INC_PATHS})
+                       set_property(TARGET ${PLUGIN_NAME}
+                                    PROPERTY COMPILE_DEFINITIONS
+                                    INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/plugins"
+                       )
+
+                       set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+                       list(APPEND PLUGINS_LIST ${PLUGIN_NAME})
+               else()
+                       # let's just build the things into the lib
+
+                       message("Building in plugin ${PLUGIN_NAME}")
+
+                       if ("${PLUGIN_INCLUDE}" STREQUAL "")
+                       else()
+                               list(APPEND LWS_LIB_BUILD_INC_PATHS ../plugins/${PLUGIN_INCLUDE})
+                       endif()
+
+                       if ("${MAIN_SRC}" STREQUAL "")
+                       else()
+                               foreach(A ${MAIN_SRC})
+                                       list(APPEND SOURCES ../plugins/${A})
+                               endforeach()
+                       endif()
+                       if ("${S2}" STREQUAL "")
+                       else()
+                               foreach(A ${S2})
+                                       list(APPEND SOURCES ../plugins/${A})
+                               endforeach()
+                       endif()
+                       if ("${S3}" STREQUAL "")
+                       else()
+                               foreach(A ${S3})
+                                       list(APPEND SOURCES ../plugins/${A})
+                               endforeach()
+                       endif()
+
+               endif(NOT LWS_WITH_PLUGINS_BUILTIN)
+       endmacro()
+               
+if (LWS_ROLE_WS)
+               create_plugin(protocol_dumb_increment ""
+                             "protocol_dumb_increment.c" "" "")
+               if (NOT LWS_WITH_PLUGINS_BUILTIN)
+                       target_compile_definitions(protocol_dumb_increment PRIVATE LWS_BUILDING_SHARED)
+               endif()
+
+               create_plugin(protocol_lws_mirror ""
+                             "protocol_lws_mirror.c" "" "")
+               if (NOT LWS_WITH_PLUGINS_BUILTIN)
+                       target_compile_definitions(protocol_lws_mirror PRIVATE LWS_BUILDING_SHARED)
+               endif()
+
+               create_plugin(protocol_lws_status ""
+                             "protocol_lws_status.c" "" "")
+               if (NOT LWS_WITH_PLUGINS_BUILTIN)
+                       target_compile_definitions(protocol_lws_status PRIVATE LWS_BUILDING_SHARED)
+               endif()
+
+               if (NOT WIN32)
+                       create_plugin(protocol_lws_raw_test ""
+                             "protocol_lws_raw_test.c" "" "")
+                       if (NOT LWS_WITH_PLUGINS_BUILTIN)
+                               target_compile_definitions(protocol_lws_raw_test PRIVATE LWS_BUILDING_SHARED)
+                       endif()
+
+
+                     if (UNIX AND LWS_HAVE_PTHREAD_H)
+                               create_plugin(protocol_deaddrop ""
+                                     "deaddrop/protocol_lws_deaddrop.c" "" "")
+                               if (NOT LWS_WITH_PLUGINS_BUILTIN)
+                                       target_compile_definitions(protocol_deaddrop PRIVATE LWS_BUILDING_SHARED)
+                               endif()
+                       endif()
+               endif()
+
+       if (LWS_WITH_SYS_METRICS)
+                       create_plugin(protocol_lws_openmetrics_export ""
+                                     "protocol_lws_openmetrics_export.c" "" "")
+                       if (NOT LWS_WITH_PLUGINS_BUILTIN)
+                               target_compile_definitions(protocol_lws_openmetrics_export PRIVATE LWS_BUILDING_SHARED)
+                       endif()
+       endif()
+
+       if (NOT LWS_WITHOUT_CLIENT)
+                       create_plugin(protocol_client_loopback_test ""
+                                     "protocol_client_loopback_test.c" "" "")
+                       if (NOT LWS_WITH_PLUGINS_BUILTIN)
+                               target_compile_definitions(protocol_client_loopback_test PRIVATE LWS_BUILDING_SHARED)
+                       endif()
+
+       endif()
+
+endif(LWS_ROLE_WS)
+
+       create_plugin(protocol_post_demo ""
+                     "protocol_post_demo.c" "" "")
+       if (NOT LWS_WITH_PLUGINS_BUILTIN)
+               target_compile_definitions(protocol_post_demo PRIVATE LWS_BUILDING_SHARED)
+       endif()
+
+
+if (LWS_ROLE_RAW_PROXY)
+       create_plugin(protocol_lws_raw_proxy ""
+                     "raw-proxy/protocol_lws_raw_proxy.c" "" "")
+       if (NOT LWS_WITH_PLUGINS_BUILTIN)
+               target_compile_definitions(protocol_lws_raw_proxy PRIVATE LWS_BUILDING_SHARED)
+       endif()
+
+endif()
+
+if (LWS_WITH_FTS)
+       create_plugin(protocol_fulltext_demo ""
+                     "protocol_fulltext_demo.c" "" "")
+       if (NOT LWS_WITH_PLUGINS_BUILTIN)
+               target_compile_definitions(protocol_fulltext_demo PRIVATE LWS_BUILDING_SHARED)
+       endif()
+
+endif()
+
+
+if (LWS_WITH_SSL)
+       create_plugin(protocol_lws_ssh_base "ssh-base/include"
+                     "ssh-base/sshd.c;ssh-base/telnet.c;ssh-base/kex-25519.c" "ssh-base/crypto/chacha.c;ssh-base/crypto/ed25519.c;ssh-base/crypto/fe25519.c;ssh-base/crypto/ge25519.c;ssh-base/crypto/poly1305.c;ssh-base/crypto/sc25519.c;ssh-base/crypto/smult_curve25519_ref.c" "")
+       if (NOT LWS_WITH_PLUGINS_BUILTIN)
+               target_compile_definitions(protocol_lws_ssh_base PRIVATE LWS_BUILDING_SHARED)
+       endif()
+
+       create_plugin(protocol_lws_sshd_demo "ssh-base/include" "protocol_lws_sshd_demo.c" "" "")
+       if (NOT LWS_WITH_PLUGINS_BUILTIN)
+               target_compile_definitions(protocol_lws_sshd_demo PRIVATE LWS_BUILDING_SHARED)
+       endif()
+
+       include_directories("${PROJECT_SOURCE_DIR}/plugins/ssh-base/include")
+endif()
+
+
+
+if (LWS_WITH_ACME)
+       create_plugin(protocol_lws_acme_client ""
+                     "acme-client/protocol_lws_acme_client.c" "" "")
+       if (NOT LWS_WITH_PLUGINS_BUILTIN)
+               target_compile_definitions(protocol_lws_acme_client PRIVATE LWS_BUILDING_SHARED)
+       endif()
+endif()
+
+endif((LWS_WITH_PLUGINS AND LWS_WITH_SHARED) OR LWS_WITH_PLUGINS_BUILTIN)
+
+
+# plugins
+
+if (LWS_WITH_PLUGINS AND NOT LWS_WITH_PLUGINS_BUILTIN)
+
+       install(TARGETS ${PLUGINS_LIST}
+               PERMISSIONS  OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ
+               DESTINATION share/libwebsockets-test-server/plugins
+               COMPONENT plugins)
+
+       if (NOT WIN32)
+               install(FILES deaddrop/assets/index.html;deaddrop/assets/deaddrop.js;deaddrop/assets/deaddrop.css;deaddrop/assets/drop.svg
+                       DESTINATION share/libwebsockets-test-server/deaddrop
+                       COMPONENT plugins)
+       endif()
+
+
+endif()
+
+export_to_parent_intermediate()
+
index b25cce5..d202085 100644 (file)
@@ -1,23 +1,25 @@
 /*
  * libwebsockets ACME client protocol plugin
  *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  *
  *  Acme is in a big messy transition at the moment from a homebrewed api
  *  to an IETF one.  The old repo for the homebrew api (they currently
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
 #include <string.h>
 #include <stdlib.h>
 
+#include <sys/stat.h>
+#include <fcntl.h>
+
 typedef enum {
-       ACME_STATE_DIRECTORY,    /* get the directory JSON using GET + parse */
-       ACME_STATE_NEW_REG,      /* register a new RSA key + email combo */
-       ACME_STATE_NEW_AUTH,     /* start the process to request a cert */
-       ACME_STATE_ACCEPT_CHALL, /* notify server ready for one challenge */
-       ACME_STATE_POLLING,      /* he should be trying our challenge */
-       ACME_STATE_POLLING_CSR,  /* sent CSR, checking result */
+       ACME_STATE_DIRECTORY,   /* get the directory JSON using GET + parse */
+       ACME_STATE_NEW_NONCE,   /* get the replay nonce */
+       ACME_STATE_NEW_ACCOUNT, /* register a new RSA key + email combo */
+       ACME_STATE_NEW_ORDER,   /* start the process to request a cert */
+       ACME_STATE_AUTHZ,       /* */
+       ACME_STATE_START_CHALL, /* notify server ready for one challenge */
+       ACME_STATE_POLLING,     /* he should be trying our challenge */
+       ACME_STATE_POLLING_CSR, /* sent CSR, checking result */
+       ACME_STATE_DOWNLOAD_CERT,
 
        ACME_STATE_FINISHED
 } lws_acme_state;
@@ -58,9 +70,17 @@ struct acme_connection {
        char challenge_uri[256];
        char detail[64];
        char status[16];
-       char san_a[100];
-       char san_b[100];
+       char key_auth[256];
+       char http01_mountpoint[256];
+       struct lws_http_mount mount;
        char urls[6][100]; /* directory contents */
+       char active_url[100];
+       char authz_url[100];
+       char order_url[100];
+       char finalize_url[100];
+       char cert_url[100];
+       char acct_id[100];
+       char *kid;
        lws_acme_state state;
        struct lws_client_connect_info i;
        struct lejp_ctx jctx;
@@ -85,7 +105,7 @@ struct acme_connection {
 
        size_t len_privkey_pem;
 
-       unsigned int yes:2;
+       unsigned int yes;
        unsigned int use:1;
        unsigned int is_sni_02:1;
 };
@@ -117,52 +137,230 @@ struct per_vhost_data__lws_acme_client {
 };
 
 static int
-callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
-                    void *user, void *in, size_t len);
+callback_chall_http01(struct lws *wsi, enum lws_callback_reasons reason,
+        void *user, void *in, size_t len)
+{
+       struct lws_vhost *vhost = lws_get_vhost(wsi);
+       struct acme_connection *ac = lws_vhost_user(vhost);
+       uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start,
+               *end = &buf[sizeof(buf) - LWS_PRE - 1];
+       int n;
 
-#define LWS_PLUGIN_PROTOCOL_LWS_ACME_CLIENT \
-       { \
-               "lws-acme-client", \
-               callback_acme_client, \
-               0, \
-               512, \
-               0, NULL, 0 \
+       switch (reason) {
+       case LWS_CALLBACK_HTTP:
+               lwsl_notice("%s: ca connection received, key_auth %s\n",
+                           __func__, ac->key_auth);
+
+               if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end)) {
+                       lwsl_notice("%s: add status failed\n", __func__);
+                       return -1;
+               }
+
+               if (lws_add_http_header_by_token(wsi,
+                                       WSI_TOKEN_HTTP_CONTENT_TYPE,
+                                       (unsigned char *)"text/plain", 10,
+                                       &p, end)) {
+                       lwsl_notice("%s: add content_type failed\n", __func__);
+                       return -1;
+               }
+
+               n = (int)strlen(ac->key_auth);
+               if (lws_add_http_header_content_length(wsi, (lws_filepos_t)n, &p, end)) {
+                       lwsl_notice("%s: add content_length failed\n",
+                                       __func__);
+                       return -1;
+               }
+
+               if (lws_add_http_header_by_token(wsi,
+                                       WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
+                                       (unsigned char *)"attachment", 10,
+                                       &p, end)) {
+                       lwsl_notice("%s: add content_dispo failed\n", __func__);
+                       return -1;
+               }
+
+               if (lws_finalize_write_http_header(wsi, start, &p, end)) {
+                       lwsl_notice("%s: finalize http header failed\n",
+                                       __func__);
+                       return -1;
+               }
+
+               lws_callback_on_writable(wsi);
+               return 0;
+
+       case LWS_CALLBACK_HTTP_WRITEABLE:
+               p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "%s", ac->key_auth);
+               lwsl_notice("%s: len %d\n", __func__, lws_ptr_diff(p, start));
+               if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff_size_t(p, start),
+                             LWS_WRITE_HTTP_FINAL) != lws_ptr_diff(p, start)) {
+                       lwsl_err("_write content failed\n");
+                       return 1;
+               }
+
+               if (lws_http_transaction_completed(wsi))
+                       return -1;
+
+               return 0;
+
+       default:
+               break;
        }
 
-static const struct lws_protocols acme_protocols[] = {
-       LWS_PLUGIN_PROTOCOL_LWS_ACME_CLIENT,
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static const struct lws_protocols chall_http01_protocols[] = {
+       { "http", callback_chall_http01, 0, 0, 0, NULL, 0 },
        { NULL, NULL, 0, 0, 0, NULL, 0 }
 };
 
+static int
+jws_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,
+                 const char *nonce, const char *url, const char *kid,
+                 char *out, size_t out_len, struct lws_context *context)
+{
+       char *buf, *start, *p, *end, *p1, *end1;
+       struct lws_jws jws;
+       int n, m;
+
+       lws_jws_init(&jws, &jwe->jwk, context);
+
+       /*
+        * This buffer is local to the function, the actual output is prepared
+        * into out.  Only the plaintext protected header
+        * (which contains the public key, 512 bytes for 4096b) goes in
+        * here temporarily.
+        */
+       n = LWS_PRE + 2048;
+       buf = malloc((unsigned int)n);
+       if (!buf) {
+               lwsl_notice("%s: malloc %d failed\n", __func__, n);
+               return -1;
+       }
+
+       p = start = buf + LWS_PRE;
+       end = buf + n - LWS_PRE - 1;
+
+       /*
+        * temporary JWS protected header plaintext
+        */
+       if (!jwe->jose.alg || !jwe->jose.alg->alg)
+               goto bail;
+
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{\"alg\":\"RS256\"");
+       if (kid)
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ",\"kid\":\"%s\"", kid);
+       else {
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ",\"jwk\":");
+               m = lws_ptr_diff(end, p);
+               n = lws_jwk_export(&jwe->jwk, 0, p, &m);
+               if (n < 0) {
+                       lwsl_notice("failed to export jwk\n");
+                       goto bail;
+               }
+               p += n;
+       }
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ",\"url\":\"%s\"", url);
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ",\"nonce\":\"%s\"}", nonce);
+
+       /*
+        * prepare the signed outer JSON with all the parts in
+        */
+       p1 = out;
+       end1 = out + out_len - 1;
+
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "{\"protected\":\"");
+       jws.map_b64.buf[LJWS_JOSE] = p1;
+       n = lws_jws_base64_enc(start, lws_ptr_diff_size_t(p, start), p1, lws_ptr_diff_size_t(end1, p1));
+       if (n < 0) {
+               lwsl_notice("%s: failed to encode protected\n", __func__);
+               goto bail;
+       }
+       jws.map_b64.len[LJWS_JOSE] = (uint32_t)n;
+       p1 += n;
+
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\"payload\":\"");
+       jws.map_b64.buf[LJWS_PYLD] = p1;
+       n = lws_jws_base64_enc(payload, len, p1, lws_ptr_diff_size_t(end1, p1));
+       if (n < 0) {
+               lwsl_notice("%s: failed to encode payload\n", __func__);
+               goto bail;
+       }
+       jws.map_b64.len[LJWS_PYLD] = (uint32_t)n;
+       p1 += n;
+
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\"signature\":\"");
+
+       /*
+        * taking the b64 protected header and the b64 payload, sign them
+        * and place the signature into the packet
+        */
+       n = lws_jws_sign_from_b64(&jwe->jose, &jws, p1, lws_ptr_diff_size_t(end1, p1));
+       if (n < 0) {
+               lwsl_notice("sig gen failed\n");
+
+               goto bail;
+       }
+       jws.map_b64.buf[LJWS_SIG] = p1;
+       jws.map_b64.len[LJWS_SIG] = (uint32_t)n;
+
+       p1 += n;
+       p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\"}");
+
+       free(buf);
+
+       return lws_ptr_diff(p1, out);
+
+bail:
+       lws_jws_destroy(&jws);
+       free(buf);
+
+       return -1;
+}
+
+static int
+callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
+               void *user, void *in, size_t len);
+
+#define LWS_PLUGIN_PROTOCOL_LWS_ACME_CLIENT \
+{ \
+       "lws-acme-client", \
+       callback_acme_client, \
+       0, \
+       512, \
+       0, NULL, 0 \
+}
+
 /* directory JSON parsing */
 
 static const char * const jdir_tok[] = {
-       "key-change",
-       "meta.terms-of-service",
-       "new-authz",
-       "new-cert",
-       "new-reg",
-       "revoke-cert",
+       "keyChange",
+       "meta.termsOfService",
+       "newAccount",
+       "newNonce",
+       "newOrder",
+       "revokeCert",
 };
-enum enum_jhdr_tok {
+
+enum enum_jdir_tok {
        JAD_KEY_CHANGE_URL,
        JAD_TOS_URL,
-       JAD_NEW_AUTHZ_URL,
-       JAD_NEW_CERT_URL,
-       JAD_NEW_REG_URL,
+       JAD_NEW_ACCOUNT_URL,
+       JAD_NEW_NONCE_URL,
+       JAD_NEW_ORDER_URL,
        JAD_REVOKE_CERT_URL,
 };
+
 static signed char
 cb_dir(struct lejp_ctx *ctx, char reason)
 {
        struct per_vhost_data__lws_acme_client *s =
-                       (struct per_vhost_data__lws_acme_client *)ctx->user;
+               (struct per_vhost_data__lws_acme_client *)ctx->user;
 
        if (reason == LEJPCB_VAL_STR_START && ctx->path_match) {
                s->pos = 0;
                s->len = sizeof(s->ac->urls[0]) - 1;
                s->dest = s->ac->urls[ctx->path_match - 1];
-
                return 0;
        }
 
@@ -171,7 +369,6 @@ cb_dir(struct lejp_ctx *ctx, char reason)
 
        if (s->pos + ctx->npos > s->len) {
                lwsl_notice("url too long\n");
-
                return -1;
        }
 
@@ -182,6 +379,66 @@ cb_dir(struct lejp_ctx *ctx, char reason)
        return 0;
 }
 
+
+/* order JSON parsing */
+
+static const char * const jorder_tok[] = {
+       "status",
+       "expires",
+       "identifiers[].type",
+       "identifiers[].value",
+       "authorizations",
+       "finalize",
+       "certificate"
+};
+
+enum enum_jorder_tok {
+       JAO_STATUS,
+       JAO_EXPIRES,
+       JAO_IDENTIFIERS_TYPE,
+       JAO_IDENTIFIERS_VALUE,
+       JAO_AUTHORIZATIONS,
+       JAO_FINALIZE,
+       JAO_CERT
+};
+
+static signed char
+cb_order(struct lejp_ctx *ctx, char reason)
+{
+       struct acme_connection *s = (struct acme_connection *)ctx->user;
+
+       if (reason == LEJPCB_CONSTRUCTED)
+               s->authz_url[0] = '\0';
+
+       if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
+               return 0;
+
+       switch (ctx->path_match - 1) {
+       case JAO_STATUS:
+               lws_strncpy(s->status, ctx->buf, sizeof(s->status));
+               break;
+       case JAO_EXPIRES:
+               break;
+       case JAO_IDENTIFIERS_TYPE:
+               break;
+       case JAO_IDENTIFIERS_VALUE:
+               break;
+       case JAO_AUTHORIZATIONS:
+               lws_snprintf(s->authz_url, sizeof(s->authz_url), "%s",
+                            ctx->buf);
+               break;
+       case JAO_FINALIZE:
+               lws_snprintf(s->finalize_url, sizeof(s->finalize_url), "%s",
+                               ctx->buf);
+               break;
+       case JAO_CERT:
+               lws_snprintf(s->cert_url, sizeof(s->cert_url), "%s", ctx->buf);
+               break;
+       }
+
+       return 0;
+}
+
 /* authz JSON parsing */
 
 static const char * const jauthz_tok[] = {
@@ -191,10 +448,11 @@ static const char * const jauthz_tok[] = {
        "expires",
        "challenges[].type",
        "challenges[].status",
-       "challenges[].uri",
+       "challenges[].url",
        "challenges[].token",
        "detail"
 };
+
 enum enum_jauthz_tok {
        JAAZ_ID_TYPE,
        JAAZ_ID_VALUE,
@@ -202,10 +460,11 @@ enum enum_jauthz_tok {
        JAAZ_EXPIRES,
        JAAZ_CHALLENGES_TYPE,
        JAAZ_CHALLENGES_STATUS,
-       JAAZ_CHALLENGES_URI,
+       JAAZ_CHALLENGES_URL,
        JAAZ_CHALLENGES_TOKEN,
        JAAZ_DETAIL,
 };
+
 static signed char
 cb_authz(struct lejp_ctx *ctx, char reason)
 {
@@ -215,7 +474,6 @@ cb_authz(struct lejp_ctx *ctx, char reason)
                s->yes = 0;
                s->use = 0;
                s->chall_token[0] = '\0';
-               s->is_sni_02 = 0;
        }
 
        if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
@@ -234,28 +492,26 @@ cb_authz(struct lejp_ctx *ctx, char reason)
                lws_snprintf(s->detail, sizeof(s->detail), "%s", ctx->buf);
                break;
        case JAAZ_CHALLENGES_TYPE:
-               if (s->is_sni_02)
-                       break;
-               s->use = !strcmp(ctx->buf, "tls-sni-01") ||
-                        !strcmp(ctx->buf, "tls-sni-02");
-               s->is_sni_02 = !strcmp(ctx->buf, "tls-sni-02");
+               lwsl_notice("JAAZ_CHALLENGES_TYPE: %s\n", ctx->buf);
+               s->use = !strcmp(ctx->buf, "http-01");
                break;
        case JAAZ_CHALLENGES_STATUS:
                lws_strncpy(s->status, ctx->buf, sizeof(s->status));
                break;
-       case JAAZ_CHALLENGES_URI:
+       case JAAZ_CHALLENGES_URL:
+               lwsl_notice("JAAZ_CHALLENGES_URL: %s %d\n", ctx->buf, s->use);
                if (s->use) {
                        lws_strncpy(s->challenge_uri, ctx->buf,
-                               sizeof(s->challenge_uri));
-                       s->yes |= 2;
+                                   sizeof(s->challenge_uri));
+                       s->yes = s->yes | 2;
                }
                break;
        case JAAZ_CHALLENGES_TOKEN:
                lwsl_notice("JAAZ_CHALLENGES_TOKEN: %s %d\n", ctx->buf, s->use);
                if (s->use) {
                        lws_strncpy(s->chall_token, ctx->buf,
-                               sizeof(s->chall_token));
-                       s->yes |= 1;
+                                   sizeof(s->chall_token));
+                       s->yes = s->yes | 1;
                }
                break;
        }
@@ -272,6 +528,7 @@ static const char * const jchac_tok[] = {
        "token",
        "error.detail"
 };
+
 enum enum_jchac_tok {
        JCAC_TYPE,
        JCAC_STATUS,
@@ -279,6 +536,7 @@ enum enum_jchac_tok {
        JCAC_TOKEN,
        JCAC_DETAIL,
 };
+
 static signed char
 cb_chac(struct lejp_ctx *ctx, char reason)
 {
@@ -294,20 +552,18 @@ cb_chac(struct lejp_ctx *ctx, char reason)
 
        switch (ctx->path_match - 1) {
        case JCAC_TYPE:
-               if (strcmp(ctx->buf, "tls-sni-01") &&
-                   strcmp(ctx->buf, "tls-sni-02"))
+               if (strcmp(ctx->buf, "http-01"))
                        return 1;
                break;
        case JCAC_STATUS:
                lws_strncpy(s->status, ctx->buf, sizeof(s->status));
                break;
        case JCAC_URI:
-               s->yes |= 2;
+               s->yes = s->yes | 2;
                break;
        case JCAC_TOKEN:
-               lws_strncpy(s->chall_token, ctx->buf,
-                               sizeof(s->chall_token));
-               s->yes |= 1;
+               lws_strncpy(s->chall_token, ctx->buf, sizeof(s->chall_token));
+               s->yes = s->yes | 1;
                break;
        case JCAC_DETAIL:
                lws_snprintf(s->detail, sizeof(s->detail), "%s", ctx->buf);
@@ -317,34 +573,11 @@ cb_chac(struct lejp_ctx *ctx, char reason)
        return 0;
 }
 
-/* https://github.com/letsencrypt/boulder/blob/release/docs/acme-divergences.md
- *
- * 7.1:
- *
- * Boulder does not implement the new-order resource.
- * Instead of new-order Boulder implements the new-cert resource that is
- * defined in draft-ietf-acme-02 Section 6.5.
- *
- * Boulder also doesn't implement the new-nonce endpoint.
- *
- * Boulder implements the new-account resource only under the new-reg key.
- *
- * Boulder implements Link: rel="next" headers from new-reg to new-authz, and
- * new-authz to new-cert, as specified in draft-02, but these links are not
- * provided in the latest draft, and clients should use URLs from the directory
- * instead.
- *
- * Boulder does not provide the "index" link relation pointing at the
- * directory URL.
- *
- * (ie, just use new-cert instead of new-order, use the directory for links)
- */
-
 static int
 lws_acme_report_status(struct lws_vhost *v, int state, const char *json)
 {
        lws_callback_vhost_protocols_vhost(v, LWS_CALLBACK_VHOST_CERT_UPDATE,
-                                          (void *)json, state);
+                                          (void *)json, (unsigned int)state);
 
        return 0;
 }
@@ -354,8 +587,8 @@ lws_acme_report_status(struct lws_vhost *v, int state, const char *json)
  */
 static struct lws *
 lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,
-                       struct lws **pwsi, struct lws_client_connect_info *i,
-                       char *url, const char *method)
+               struct lws **pwsi, struct lws_client_connect_info *i,
+               char *url, const char *method)
 {
        const char *prot, *p;
        char path[200], _url[256];
@@ -376,7 +609,7 @@ lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,
        i->path = path;
        i->context = context;
        i->vhost = vh;
-       i->ssl_connection = 1;
+       i->ssl_connection = LCCSCF_USE_SSL;
        i->host = i->address;
        i->origin = i->address;
        i->method = method;
@@ -397,7 +630,7 @@ lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,
 static void
 lws_acme_finished(struct per_vhost_data__lws_acme_client *vhd)
 {
-       lwsl_debug("%s\n", __func__);
+       lwsl_notice("%s\n", __func__);
 
        if (vhd->ac) {
                if (vhd->ac->vhost)
@@ -422,6 +655,7 @@ static const char * const pvo_names[] = {
        "locality",
        "organization",
        "common-name",
+       "subject-alt-name",
        "email",
        "directory-url",
        "auth-path",
@@ -431,32 +665,30 @@ static const char * const pvo_names[] = {
 
 static int
 lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd,
-                              int bits)
+               int bits)
 {
        int n;
 
        if (!lws_jwk_load(&vhd->jwk, vhd->pvop[LWS_TLS_SET_AUTH_PATH],
-                         NULL, NULL))
+                               NULL, NULL))
                return 0;
 
        vhd->jwk.kty = LWS_GENCRYPTO_KTY_RSA;
+
        lwsl_notice("Generating ACME %d-bit keypair... "
-                   "will take a little while\n", bits);
+                       "will take a little while\n", bits);
        n = lws_genrsa_new_keypair(vhd->context, &vhd->rsactx, LGRSAM_PKCS1_1_5,
-                                  vhd->jwk.e, bits);
+                       vhd->jwk.e, bits);
        if (n) {
                lwsl_notice("failed to create keypair\n");
-
                return 1;
        }
 
        lwsl_notice("...keypair generated\n");
 
-       if (lws_jwk_save(&vhd->jwk,
-                   vhd->pvop[LWS_TLS_SET_AUTH_PATH])) {
+       if (lws_jwk_save(&vhd->jwk, vhd->pvop[LWS_TLS_SET_AUTH_PATH])) {
                lwsl_notice("unable to save %s\n",
-                     vhd->pvop[LWS_TLS_SET_AUTH_PATH]);
-
+                               vhd->pvop[LWS_TLS_SET_AUTH_PATH]);
                return 1;
        }
 
@@ -465,7 +697,7 @@ lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd,
 
 static int
 lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,
-                          struct lws_vhost *v)
+               struct lws_vhost *v)
 {
        char buf[128];
 
@@ -478,7 +710,7 @@ lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,
         * ...well... we should try to do something about it then...
         */
        lwsl_notice("%s: ACME cert needs creating / updating:  "
-                   "vhost %s\n", __func__, lws_get_vhost_name(vhd->vhost));
+                       "vhost %s\n", __func__, lws_get_vhost_name(vhd->vhost));
 
        vhd->ac = malloc(sizeof(*vhd->ac));
        memset(vhd->ac, 0, sizeof(*vhd->ac));
@@ -502,11 +734,11 @@ lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,
        if (!vhd->ac->urls[0][0]) {
                vhd->ac->state = ACME_STATE_DIRECTORY;
                lws_snprintf(buf, sizeof(buf) - 1, "%s",
-                            vhd->pvop_active[LWS_TLS_SET_DIR_URL]);
+                               vhd->pvop_active[LWS_TLS_SET_DIR_URL]);
        } else {
-               vhd->ac->state = ACME_STATE_NEW_REG;
+               vhd->ac->state = ACME_STATE_NEW_ACCOUNT;
                lws_snprintf(buf, sizeof(buf) - 1, "%s",
-                            vhd->ac->urls[JAD_NEW_REG_URL]);
+                               vhd->ac->urls[JAD_NEW_ACCOUNT_URL]);
        }
 
        vhd->ac->real_vh_port = lws_get_vhost_port(vhd->vhost);
@@ -517,15 +749,15 @@ lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd,
 
 #if defined(LWS_WITH_ESP32)
        lws_acme_report_status(vhd->vhost, LWS_CUS_CREATE_KEYS,
-                              "Generating keys, please wait");
+                       "Generating keys, please wait");
        if (lws_acme_load_create_auth_keys(vhd, 2048))
                goto bail;
        lws_acme_report_status(vhd->vhost, LWS_CUS_CREATE_KEYS,
-                              "Auth keys created");
+                       "Auth keys created");
 #endif
 
        if (lws_acme_client_connect(vhd->context, vhd->vhost,
-                                   &vhd->ac->cwsi, &vhd->ac->i, buf, "GET"))
+                               &vhd->ac->cwsi, &vhd->ac->i, buf, "GET"))
                return 0;
 
 #if defined(LWS_WITH_ESP32)
@@ -539,18 +771,17 @@ bail:
 
 static int
 callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
-                    void *user, void *in, size_t len)
+               void *user, void *in, size_t len)
 {
        struct per_vhost_data__lws_acme_client *vhd =
-                       (struct per_vhost_data__lws_acme_client *)
-                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
-                                       lws_get_protocol(wsi));
+               (struct per_vhost_data__lws_acme_client *)
+               lws_protocol_vh_priv_get(lws_get_vhost(wsi),
+                               lws_get_protocol(wsi));
        char buf[LWS_PRE + 2536], *start = buf + LWS_PRE, *p = start,
-            *end = buf + sizeof(buf) - 1, digest[32], *failreason = NULL;
+                *end = buf + sizeof(buf) - 1, digest[32], *failreason = NULL;
        const struct lws_protocol_vhost_options *pvo;
        struct lws_acme_cert_aging_args *caa;
        struct acme_connection *ac = NULL;
-       struct lws_genhash_ctx hctx;
        unsigned char **pp, *pend;
        const char *content_type;
        struct lws_jwe jwe;
@@ -567,6 +798,9 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
                vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                                lws_get_protocol(wsi),
                                sizeof(struct per_vhost_data__lws_acme_client));
+               if (vhd)
+                       return 0;
+
                vhd->context = lws_get_context(wsi);
                vhd->protocol = lws_get_protocol(wsi);
                vhd->vhost = lws_get_vhost(wsi);
@@ -575,18 +809,18 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
                m = 0;
                pvo = (const struct lws_protocol_vhost_options *)in;
                while (pvo) {
-                       m += strlen(pvo->value) + 1;
+                       m += (int)strlen(pvo->value) + 1;
                        pvo = pvo->next;
                }
-               p = vhd->pvo_data = malloc(m);
+               p = vhd->pvo_data = malloc((unsigned int)m);
                if (!p)
                        return -1;
 
                pvo = (const struct lws_protocol_vhost_options *)in;
                while (pvo) {
                        start = p;
-                       n = strlen(pvo->value) + 1;
-                       memcpy(start, pvo->value, n);
+                       n = (int)strlen(pvo->value) + 1;
+                       memcpy(start, pvo->value, (unsigned int)n);
                        p += n;
 
                        for (m = 0; m < (int)LWS_ARRAY_SIZE(pvo_names); m++)
@@ -597,15 +831,19 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
                }
 
                n = 0;
-               for (m = 0; m < (int)LWS_ARRAY_SIZE(pvo_names); m++)
-                       if (!vhd->pvop[m] && m >= LWS_TLS_REQ_ELEMENT_COMMON_NAME) {
+               for (m = 0; m < (int)LWS_ARRAY_SIZE(pvo_names); m++) {
+                       if (!vhd->pvop[m] &&
+                               m >= LWS_TLS_REQ_ELEMENT_COMMON_NAME &&
+                               m != LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME) {
                                lwsl_notice("%s: require pvo '%s'\n", __func__,
-                                               pvo_names[m]);
+                                           pvo_names[m]);
                                n |= 1;
-                       } else
+                       } else {
                                if (vhd->pvop[m])
                                        lwsl_info("  %s: %s\n", pvo_names[m],
-                                                       vhd->pvop[m]);
+                                                 vhd->pvop[m]);
+                       }
+               }
                if (n) {
                        free(vhd->pvo_data);
                        vhd->pvo_data = NULL;
@@ -626,17 +864,18 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
                 * still have root
                 */
                lws_snprintf(buf, sizeof(buf) - 1, "%s.upd",
-                            vhd->pvop[LWS_TLS_SET_CERT_PATH]);
-               vhd->fd_updated_cert = lws_open(buf, LWS_O_WRONLY | LWS_O_CREAT |
-                                                LWS_O_TRUNC, 0600);
+                               vhd->pvop[LWS_TLS_SET_CERT_PATH]);
+               vhd->fd_updated_cert = lws_open(buf,
+                                               LWS_O_WRONLY | LWS_O_CREAT |
+                                               LWS_O_TRUNC, 0600);
                if (vhd->fd_updated_cert < 0) {
                        lwsl_err("unable to create update cert file %s\n", buf);
                        return -1;
                }
                lws_snprintf(buf, sizeof(buf) - 1, "%s.upd",
-                            vhd->pvop[LWS_TLS_SET_KEY_PATH]);
+                               vhd->pvop[LWS_TLS_SET_KEY_PATH]);
                vhd->fd_updated_key = lws_open(buf, LWS_O_WRONLY | LWS_O_CREAT |
-                                               LWS_O_TRUNC, 0600);
+                               LWS_O_TRUNC, 0600);
                if (vhd->fd_updated_key < 0) {
                        lwsl_err("unable to create update key file %s\n", buf);
                        return -1;
@@ -680,7 +919,8 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
                                vhd->pvop_active[n] = vhd->pvop[n];
 
                lwsl_notice("starting acme acquisition on %s: %s\n",
-                               lws_get_vhost_name(caa->vh), vhd->pvop_active[LWS_TLS_SET_DIR_URL]);
+                               lws_get_vhost_name(caa->vh),
+                               vhd->pvop_active[LWS_TLS_SET_DIR_URL]);
 
                lws_acme_start_acquisition(vhd, caa->vh);
                break;
@@ -706,16 +946,17 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
                break;
 
        case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
-               lwsl_notice("lws_http_client_http_response %d\n",
-                           lws_http_client_http_response(wsi));
+               lwsl_notice("%s: ESTABLISHED_CLIENT_HTTP:"
+                               "%p, state:%d, status:%d\n", __func__, wsi,
+                               ac->state, lws_http_client_http_response(wsi));
                if (!ac)
                        break;
-               ac->resp = lws_http_client_http_response(wsi);
+               ac->resp = (int)lws_http_client_http_response(wsi);
                /* we get a new nonce each time */
                if (lws_hdr_total_length(wsi, WSI_TOKEN_REPLAY_NONCE) &&
-                   lws_hdr_copy(wsi, ac->replay_nonce,
-                                sizeof(ac->replay_nonce),
-                                WSI_TOKEN_REPLAY_NONCE) < 0) {
+                               lws_hdr_copy(wsi, ac->replay_nonce,
+                                       sizeof(ac->replay_nonce),
+                                       WSI_TOKEN_REPLAY_NONCE) < 0) {
                        lwsl_notice("%s: nonce too large\n", __func__);
 
                        goto failed;
@@ -724,41 +965,80 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
                switch (ac->state) {
                case ACME_STATE_DIRECTORY:
                        lejp_construct(&ac->jctx, cb_dir, vhd, jdir_tok,
-                                      LWS_ARRAY_SIZE(jdir_tok));
+                                       LWS_ARRAY_SIZE(jdir_tok));
                        break;
-               case ACME_STATE_NEW_REG:
+               case ACME_STATE_NEW_NONCE:
+                       /*
+                        *  we try to * register our keys next.
+                        *  It's OK if it ends up * they're already registered,
+                        *  this eliminates any * gaps where we stored the key
+                        *  but registration did not complete for some reason...
+                        */
+                       ac->state = ACME_STATE_NEW_ACCOUNT;
+                       lws_acme_report_status(vhd->vhost, LWS_CUS_REG, NULL);
+
+                       strcpy(buf, ac->urls[JAD_NEW_ACCOUNT_URL]);
+                       cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
+                                       &ac->cwsi, &ac->i, buf, "POST");
+                       if (!cwsi) {
+                               lwsl_notice("%s: failed to connect to acme\n",
+                                               __func__);
+                               goto failed;
+                       }
+
+                       return -1;
+
+               case ACME_STATE_NEW_ACCOUNT:
+                       if (!lws_hdr_total_length(wsi,
+                                                 WSI_TOKEN_HTTP_LOCATION)) {
+                               lwsl_notice("%s: no Location\n", __func__);
+                               goto failed;
+                       }
+
+                       if (lws_hdr_copy(wsi, ac->acct_id, sizeof(ac->acct_id),
+                                        WSI_TOKEN_HTTP_LOCATION) < 0) {
+                               lwsl_notice("%s: Location too large\n",
+                                               __func__);
+                               goto failed;
+                       }
+
+                       ac->kid = ac->acct_id;
+
+                       lwsl_notice("Location: %s\n", ac->acct_id);
                        break;
-               case ACME_STATE_NEW_AUTH:
+
+               case ACME_STATE_NEW_ORDER:
+                       if (lws_hdr_copy(wsi, ac->order_url,
+                                        sizeof(ac->order_url),
+                                        WSI_TOKEN_HTTP_LOCATION) < 0) {
+                               lwsl_notice("%s: missing cert location:\n",
+                                               __func__);
+
+                               goto failed;
+                       }
+
+                       lejp_construct(&ac->jctx, cb_order, ac, jorder_tok,
+                                       LWS_ARRAY_SIZE(jorder_tok));
+                       break;
+
+               case ACME_STATE_AUTHZ:
                        lejp_construct(&ac->jctx, cb_authz, ac, jauthz_tok,
                                        LWS_ARRAY_SIZE(jauthz_tok));
                        break;
 
-               case ACME_STATE_POLLING:
-               case ACME_STATE_ACCEPT_CHALL:
+               case ACME_STATE_START_CHALL:
                        lejp_construct(&ac->jctx, cb_chac, ac, jchac_tok,
                                        LWS_ARRAY_SIZE(jchac_tok));
                        break;
 
+               case ACME_STATE_POLLING:
                case ACME_STATE_POLLING_CSR:
-                       ac->cpos = 0;
-                       if (ac->resp != 201)
-                               break;
-                       /*
-                        * He acknowledges he will create the cert...
-                        * get the URL to GET it from in the Location
-                        * header.
-                        */
-                       if (lws_hdr_copy(wsi, ac->challenge_uri,
-                                        sizeof(ac->challenge_uri),
-                                        WSI_TOKEN_HTTP_LOCATION) < 0) {
-                               lwsl_notice("%s: missing cert location:\n",
-                                           __func__);
-
-                               goto failed;
-                       }
+                       lejp_construct(&ac->jctx, cb_order, ac, jorder_tok,
+                                       LWS_ARRAY_SIZE(jorder_tok));
+                       break;
 
-                       lwsl_notice("told to fetch cert from %s\n",
-                                       ac->challenge_uri);
+               case ACME_STATE_DOWNLOAD_CERT:
+                       ac->cpos = 0;
                        break;
 
                default:
@@ -769,38 +1049,40 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
        case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
                if (!ac)
                        break;
-               switch (ac->state) {
 
+               switch (ac->state) {
                case ACME_STATE_DIRECTORY:
+               case ACME_STATE_NEW_NONCE:
                        break;
-               case ACME_STATE_NEW_REG:
-                       p += lws_snprintf(p, end - p, "{"
-                                         "\"resource\":\"new-reg\","
-                                         "\"contact\":["
-                                         "\"mailto:%s\""
-                                         "],\"agreement\":\"%s\""
-                                         "}",
-                                         vhd->pvop_active[LWS_TLS_REQ_ELEMENT_EMAIL],
-                                         ac->urls[JAD_TOS_URL]);
+
+               case ACME_STATE_NEW_ACCOUNT:
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{"
+                               "\"termsOfServiceAgreed\":true"
+                               ",\"contact\": [\"mailto:%s\"]}",
+                               vhd->pvop_active[LWS_TLS_REQ_ELEMENT_EMAIL]);
 
                        puts(start);
+                       strcpy(ac->active_url, ac->urls[JAD_NEW_ACCOUNT_URL]);
 pkt_add_hdrs:
-                       if (lws_gencrypto_jwe_alg_to_definition("RSA1_5", &jwe.jose.alg)) {
+                       if (lws_gencrypto_jwe_alg_to_definition("RSA1_5",
+                                               &jwe.jose.alg)) {
                                ac->len = 0;
                                lwsl_notice("%s: no RSA1_5\n", __func__);
                                goto failed;
                        }
-                       jwe.jws.jwk = &vhd->jwk;
-                       ac->len = lws_jwe_create_packet(&jwe,
-                                                       start, p - start,
-                                                       ac->replay_nonce,
-                                                       &ac->buf[LWS_PRE],
-                                                       sizeof(ac->buf) -
-                                                                LWS_PRE,
-                                                       lws_get_context(wsi));
+                       jwe.jwk = vhd->jwk;
+
+                       ac->len = jws_create_packet(&jwe,
+                                       start, lws_ptr_diff_size_t(p, start),
+                                       ac->replay_nonce,
+                                       ac->active_url,
+                                       ac->kid,
+                                       &ac->buf[LWS_PRE],
+                                       sizeof(ac->buf) - LWS_PRE,
+                                       lws_get_context(wsi));
                        if (ac->len < 0) {
                                ac->len = 0;
-                               lwsl_notice("lws_jwe_create_packet failed\n");
+                               lwsl_notice("jws_create_packet failed\n");
                                goto failed;
                        }
 
@@ -808,164 +1090,84 @@ pkt_add_hdrs:
                        pend = (*pp) + len;
 
                        ac->pos = 0;
-                       content_type =         "application/jose+json";
-                       if (ac->state == ACME_STATE_POLLING_CSR)
-                               content_type = "application/pkix-cert";
+                       content_type = "application/jose+json";
 
                        if (lws_add_http_header_by_token(wsi,
-                                   WSI_TOKEN_HTTP_CONTENT_TYPE,
-                                       (uint8_t *)content_type, 21, pp, pend)) {
+                                               WSI_TOKEN_HTTP_CONTENT_TYPE,
+                                               (uint8_t *)content_type, 21, pp,
+                                               pend)) {
                                lwsl_notice("could not add content type\n");
                                goto failed;
                        }
 
                        n = sprintf(buf, "%d", ac->len);
                        if (lws_add_http_header_by_token(wsi,
-                                       WSI_TOKEN_HTTP_CONTENT_LENGTH,
-                                       (uint8_t *)buf, n, pp, pend)) {
+                                               WSI_TOKEN_HTTP_CONTENT_LENGTH,
+                                               (uint8_t *)buf, n, pp, pend)) {
                                lwsl_notice("could not add content length\n");
                                goto failed;
                        }
 
                        lws_client_http_body_pending(wsi, 1);
                        lws_callback_on_writable(wsi);
-                       lwsl_notice("prepare to send ACME_STATE_NEW_REG\n");
                        break;
-               case ACME_STATE_NEW_AUTH:
-                       p += lws_snprintf(p, end - p,
+
+               case ACME_STATE_NEW_ORDER:
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
                                        "{"
-                                        "\"resource\":\"new-authz\","
-                                        "\"identifier\":{"
-                                         "\"type\":\"http-01\","
-                                         "\"value\":\"%s\""
-                                        "}"
-                                       "}", vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME]);
+                                       "\"identifiers\":[{"
+                                       "\"type\":\"dns\","
+                                       "\"value\":\"%s\""
+                                       "}]"
+                                       "}",
+                       vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME]);
+
+                       puts(start);
+                       strcpy(ac->active_url, ac->urls[JAD_NEW_ORDER_URL]);
                        goto pkt_add_hdrs;
 
-               case ACME_STATE_ACCEPT_CHALL:
-                       /*
-                        * Several of the challenges in this document makes use
-                        * of a key authorization string.  A key authorization
-                        * expresses a domain holder's authorization for a
-                        * specified key to satisfy a specified challenge, by
-                        * concatenating the token for the challenge with a key
-                        * fingerprint, separated by a "." character:
-                        *
-                        * key-authz = token || '.' ||
-                        *             base64(JWK_Thumbprint(accountKey))
-                        *
-                        * The "JWK_Thumbprint" step indicates the computation
-                        * specified in [RFC7638], using the SHA-256 digest.  As
-                        * specified in the individual challenges below, the
-                        * token for a challenge is a JSON string comprised
-                        * entirely of characters in the base64 alphabet.
-                        * The "||" operator indicates concatenation of strings.
-                        *
-                        *    keyAuthorization (required, string):  The key
-                        *  authorization for this challenge.  This value MUST
-                        *  match the token from the challenge and the client's
-                        *  account key.
-                        *
-                        * draft acme-01 tls-sni-01:
-                        *
-                        *    {
-                        *         "keyAuthorization": "evaGxfADs...62jcerQ",
-                        *    }   (Signed as JWS)
-                        *
-                        * draft acme-07 tls-sni-02:
-                        *
-                        * POST /acme/authz/1234/1
-                        * Host: example.com
-                        * Content-Type: application/jose+json
-                        *
-                        * {
-                        *  "protected": base64url({
-                        *    "alg": "ES256",
-                        *    "kid": "https://example.com/acme/acct/1",
-                        *    "nonce": "JHb54aT_KTXBWQOzGYkt9A",
-                        *    "url": "https://example.com/acme/authz/1234/1"
-                        *  }),
-                        *  "payload": base64url({
-                        *     "keyAuthorization": "evaGxfADs...62jcerQ"
-                        *  }),
-                        * "signature": "Q1bURgJoEslbD1c5...3pYdSMLio57mQNN4"
-                        * }
-                        *
-                        * On receiving a response, the server MUST verify that
-                        * the key authorization in the response matches the
-                        * "token" value in the challenge and the client's
-                        * account key.  If they do not match, then the server
-                        * MUST return an HTTP error in response to the POST
-                        * request in which the client sent the challenge.
-                        */
+               case ACME_STATE_AUTHZ:
+                       puts(start);
+                       strcpy(ac->active_url, ac->authz_url);
+                       goto pkt_add_hdrs;
 
-                       lws_jwk_rfc7638_fingerprint(&vhd->jwk, digest);
+               case ACME_STATE_START_CHALL:
                        p = start;
                        end = &buf[sizeof(buf) - 1];
 
-                       p += lws_snprintf(p, end - p,
-                                         "{\"resource\":\"challenge\","
-                                         "\"type\":\"tls-sni-0%d\","
-                                         "\"keyAuthorization\":\"%s.",
-                                         1 + ac->is_sni_02,
-                                         ac->chall_token);
-                       n = lws_jws_base64_enc(digest, 32, p, end - p);
-                       if (n < 0)
-                               goto failed;
-                       p += n;
-                       p += lws_snprintf(p, end - p, "\"}");
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{}");
                        puts(start);
+                       strcpy(ac->active_url, ac->challenge_uri);
                        goto pkt_add_hdrs;
 
                case ACME_STATE_POLLING:
-                       break;
+                       strcpy(ac->active_url, ac->order_url);
+                       goto pkt_add_hdrs;
 
                case ACME_STATE_POLLING_CSR:
-                       /*
-                        * "To obtain a certificate for the domain, the agent
-                        * constructs a PKCS#10 Certificate Signing Request that
-                        * asks the Let’s Encrypt CA to issue a certificate for
-                        * example.com with a specified public key. As usual,
-                        * the CSR includes a signature by the private key
-                        * corresponding to the public key in the CSR. The agent
-                        * also signs the whole CSR with the authorized
-                        * key for example.com so that the Let’s Encrypt CA
-                        * knows it’s authorized."
-                        *
-                        * IOW we must create a new RSA keypair which will be
-                        * the cert public + private key, and put the public
-                        * key in the CSR.  The CSR, just for transport, is also
-                        * signed with our JWK, showing that as the owner of the
-                        * authorized JWK, the request should be allowed.
-                        *
-                        * The cert comes back with our public key in it showing
-                        * that the owner of the matching private key (we
-                        * created that keypair) is the owner of the cert.
-                        *
-                        * We feed the CSR the elements we want in the cert,
-                        * like the CN etc, and it gives us the b64URL-encoded
-                        * CSR and the PEM-encoded (public +)private key in
-                        * memory buffers.
-                        */
                        if (ac->goes_around)
                                break;
 
-                       p += lws_snprintf(p, end - p,
-                                         "{\"resource\":\"new-cert\","
-                                         "\"csr\":\"");
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{\"csr\":\"");
                        n = lws_tls_acme_sni_csr_create(vhd->context,
-                                                       &vhd->pvop_active[0],
-                                                       (uint8_t *)p, end - p,
-                                                       &ac->alloc_privkey_pem,
-                                                       &ac->len_privkey_pem);
+                                       &vhd->pvop_active[0],
+                                       (uint8_t *)p, lws_ptr_diff_size_t(end, p),
+                                       &ac->alloc_privkey_pem,
+                                       &ac->len_privkey_pem);
                        if (n < 0) {
                                lwsl_notice("CSR generation failed\n");
                                goto failed;
                        }
                        p += n;
-                       p += lws_snprintf(p, end - p, "\"}");
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"}");
                        puts(start);
+                       strcpy(ac->active_url, ac->finalize_url);
+                       goto pkt_add_hdrs;
+
+               case ACME_STATE_DOWNLOAD_CERT:
+                       strcpy(ac->active_url, ac->cert_url);
                        goto pkt_add_hdrs;
+                       break;
 
                default:
                        break;
@@ -974,14 +1176,16 @@ pkt_add_hdrs:
 
        case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
                lwsl_notice("LWS_CALLBACK_CLIENT_HTTP_WRITEABLE\n");
+
                if (!ac)
                        break;
+
                if (ac->pos == ac->len)
                        break;
 
                ac->buf[LWS_PRE + ac->len] = '\0';
                if (lws_write(wsi, (uint8_t *)ac->buf + LWS_PRE,
-                             ac->len, LWS_WRITE_HTTP_FINAL) < 0)
+                                       (size_t)ac->len, LWS_WRITE_HTTP_FINAL) < 0)
                        return -1;
                lwsl_notice("wrote %d\n", ac->len);
                ac->pos = ac->len;
@@ -992,32 +1196,36 @@ pkt_add_hdrs:
        case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
                if (!ac)
                        return -1;
+
                switch (ac->state) {
+               case ACME_STATE_POLLING_CSR:
                case ACME_STATE_POLLING:
-               case ACME_STATE_ACCEPT_CHALL:
-               case ACME_STATE_NEW_AUTH:
+               case ACME_STATE_START_CHALL:
+               case ACME_STATE_AUTHZ:
+               case ACME_STATE_NEW_ORDER:
                case ACME_STATE_DIRECTORY:
                        ((char *)in)[len] = '\0';
                        puts(in);
-                       m = (int)(signed char)lejp_parse(&ac->jctx,
-                                                        (uint8_t *)in, len);
+                       m = lejp_parse(&ac->jctx, (uint8_t *)in, (int)len);
                        if (m < 0 && m != LEJP_CONTINUE) {
                                lwsl_notice("lejp parse failed %d\n", m);
                                goto failed;
                        }
                        break;
-               case ACME_STATE_NEW_REG:
+               case ACME_STATE_NEW_ACCOUNT:
                        ((char *)in)[len] = '\0';
                        puts(in);
                        break;
-               case ACME_STATE_POLLING_CSR:
+               case ACME_STATE_DOWNLOAD_CERT:
+                       ((char *)in)[len] = '\0';
+                       puts(in);
                        /* it should be the DER cert! */
-                       if (ac->cpos + len > sizeof(ac->buf)) {
+                       if ((unsigned int)ac->cpos + len > sizeof(ac->buf)) {
                                lwsl_notice("Incoming cert is too large!\n");
                                goto failed;
                        }
                        memcpy(&ac->buf[ac->cpos], in, len);
-                       ac->cpos += len;
+                       ac->cpos += (int)len;
                        break;
                default:
                        break;
@@ -1027,13 +1235,19 @@ pkt_add_hdrs:
        /* unchunked content */
        case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
                lwsl_notice("%s: LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n", __func__);
-               {
-                       char buffer[2048 + LWS_PRE];
-                       char *px = buffer + LWS_PRE;
-                       int lenx = sizeof(buffer) - LWS_PRE;
+               if (!ac)
+                       return -1;
+               switch (ac->state) {
+               default:
+                       {
+                               char buffer[2048 + LWS_PRE];
+                               char *px = buffer + LWS_PRE;
+                               int lenx = sizeof(buffer) - LWS_PRE;
 
-                       if (lws_http_client_read(wsi, &px, &lenx) < 0)
-                               return -1;
+                               if (lws_http_client_read(wsi, &px, &lenx) < 0)
+                                       return -1;
+                       }
+                       break;
                }
                break;
 
@@ -1042,6 +1256,7 @@ pkt_add_hdrs:
 
                if (!ac)
                        return -1;
+
                switch (ac->state) {
                case ACME_STATE_DIRECTORY:
                        lejp_destruct(&ac->jctx);
@@ -1051,212 +1266,125 @@ pkt_add_hdrs:
                        for (n = 0; n < 6; n++)
                                lwsl_notice("   %d: %s\n", n, ac->urls[n]);
 
-                       /*
-                        * So... having the directory now... we try to
-                        * register our keys next.  It's OK if it ends up
-                        * they're already registered... this eliminates any
-                        * gaps where we stored the key but registration did
-                        * not complete for some reason...
-                        */
-                       ac->state = ACME_STATE_NEW_REG;
-                       lws_acme_report_status(vhd->vhost, LWS_CUS_REG, NULL);
+                       ac->state = ACME_STATE_NEW_NONCE;
 
-                       strcpy(buf, ac->urls[JAD_NEW_REG_URL]);
+                       strcpy(buf, ac->urls[JAD_NEW_NONCE_URL]);
                        cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
-                                                      &ac->cwsi, &ac->i, buf,
-                                                      "POST");
+                                       &ac->cwsi, &ac->i, buf,
+                                       "GET");
                        if (!cwsi) {
                                lwsl_notice("%s: failed to connect to acme\n",
-                                           __func__);
+                                               __func__);
                                goto failed;
                        }
                        return -1; /* close the completed client connection */
 
-               case ACME_STATE_NEW_REG:
+               case ACME_STATE_NEW_ACCOUNT:
                        if ((ac->resp >= 200 && ac->resp < 299) ||
-                            ac->resp == 409) {
+                                       ac->resp == 409) {
                                /*
                                 * Our account already existed, or exists now.
                                 *
-                                * Move on to requesting a cert auth.
                                 */
-                               ac->state = ACME_STATE_NEW_AUTH;
-                               lws_acme_report_status(vhd->vhost, LWS_CUS_AUTH,
-                                                       NULL);
+                               ac->state = ACME_STATE_NEW_ORDER;
 
-                               strcpy(buf, ac->urls[JAD_NEW_AUTHZ_URL]);
+                               strcpy(buf, ac->urls[JAD_NEW_ORDER_URL]);
                                cwsi = lws_acme_client_connect(vhd->context,
-                                                       vhd->vhost, &ac->cwsi,
-                                                       &ac->i, buf, "POST");
+                                               vhd->vhost, &ac->cwsi,
+                                               &ac->i, buf, "POST");
                                if (!cwsi)
                                        lwsl_notice("%s: failed to connect\n",
-                                                   __func__);
-                               return -1; /* close the completed client connection */
+                                                       __func__);
+
+                               /* close the completed client connection */
+                               return -1;
                        } else {
-                               lwsl_notice("new-reg replied %d\n", ac->resp);
+                               lwsl_notice("newAccount replied %d\n",
+                                               ac->resp);
                                goto failed;
                        }
                        return -1; /* close the completed client connection */
 
-               case ACME_STATE_NEW_AUTH:
+               case ACME_STATE_NEW_ORDER:
+                       lejp_destruct(&ac->jctx);
+                       if (!ac->authz_url[0]) {
+                               lwsl_notice("no authz\n");
+                               goto failed;
+                       }
+
+                       /*
+                        * Move on to requesting a cert auth.
+                        */
+                       ac->state = ACME_STATE_AUTHZ;
+                       lws_acme_report_status(vhd->vhost, LWS_CUS_AUTH,
+                                       NULL);
+
+                       strcpy(buf, ac->authz_url);
+                       cwsi = lws_acme_client_connect(vhd->context,
+                                       vhd->vhost, &ac->cwsi,
+                                       &ac->i, buf, "POST");
+                       if (!cwsi)
+                               lwsl_notice("%s: failed to connect\n",
+                                               __func__);
+
+                       return -1; /* close the completed client connection */
+
+               case ACME_STATE_AUTHZ:
                        lejp_destruct(&ac->jctx);
                        if (ac->resp / 100 == 4) {
                                lws_snprintf(buf, sizeof(buf),
-                                            "Auth failed: %s", ac->detail);
+                                               "Auth failed: %s", ac->detail);
                                failreason = buf;
                                lwsl_notice("auth failed\n");
                                goto failed;
                        }
-                       lwsl_notice("chall: %s (%d)\n", ac->chall_token, ac->resp);
+                       lwsl_notice("chall: %s (%d)\n", ac->chall_token,
+                                       ac->resp);
                        if (!ac->chall_token[0]) {
                                lwsl_notice("no challenge\n");
                                goto failed;
                        }
 
-
-                       ac->state = ACME_STATE_ACCEPT_CHALL;
+                       ac->state = ACME_STATE_START_CHALL;
                        lws_acme_report_status(vhd->vhost, LWS_CUS_CHALLENGE,
-                                               NULL);
-
-                       /* tls-sni-01 ... what a mess.
-                        * The stuff in
-                        * https://tools.ietf.org/html/
-                        *              draft-ietf-acme-acme-01#section-7.3
-                        * "requires" n but it's missing from let's encrypt
-                        * tls-sni-01 challenge.  The go docs say that they just
-                        * implement one hashing round regardless
-                        * https://godoc.org/golang.org/x/crypto/acme
-                        *
-                        * The go way is what is actually implemented today by
-                        * letsencrypt
-                        *
-                        * "A client responds to this challenge by constructing
-                        * a key authorization from the "token" value provided
-                        * in the challenge and the client's account key.  The
-                        * client first computes the SHA-256 digest Z0 of the
-                        * UTF8-encoded key authorization, and encodes Z0 in
-                        * UTF-8 lower-case hexadecimal form."
-                        */
-
-                       /* tls-sni-02
-                        *
-                        * SAN A MUST be constructed as follows: compute the
-                        * SHA-256 digest of the UTF-8-encoded challenge token
-                        * and encode it in lowercase hexadecimal form.  The
-                        * dNSName is "x.y.token.acme.invalid", where x
-                        * is the first half of the hexadecimal representation
-                        * and y is the second half.
-                        */
+                                       NULL);
 
                        memset(&ac->ci, 0, sizeof(ac->ci));
 
-                       /* first compute the key authorization */
+                       /* compute the key authorization */
 
-                       lws_jwk_rfc7638_fingerprint(&vhd->jwk, digest);
-                       p = start;
-                       end = &buf[sizeof(buf) - 1];
+                       p = ac->key_auth;
+                       end = p + sizeof(ac->key_auth) - 1;
 
-                       p += lws_snprintf(p, end - p, "%s.", ac->chall_token);
-                       n = lws_jws_base64_enc(digest, 32, p, end - p);
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s.", ac->chall_token);
+                       lws_jwk_rfc7638_fingerprint(&vhd->jwk, digest);
+                       n = lws_jws_base64_enc(digest, 32, p, lws_ptr_diff_size_t(end, p));
                        if (n < 0)
                                goto failed;
-                       p += n;
-
-                       if (lws_genhash_init(&hctx, LWS_GENHASH_TYPE_SHA256))
-                               return -1;
 
-                       if (lws_genhash_update(&hctx, (uint8_t *)start,
-                                               lws_ptr_diff(p, start))) {
-                               lws_genhash_destroy(&hctx, NULL);
+                       lwsl_notice("key_auth: '%s'\n", ac->key_auth);
 
-                               return -1;
-                       }
-                       if (lws_genhash_destroy(&hctx, digest))
-                               return -1;
-
-                       p = buf;
-                       for (n = 0; n < 32; n++) {
-                               p += lws_snprintf(p, end - p, "%02x",
-                                                 digest[n] & 0xff);
-                               if (n == (32 / 2) - 1)
-                                       p = buf + 64;
-                       }
-
-                       p = ac->san_a;
-                       if (ac->is_sni_02) {
-                               lws_snprintf(p, sizeof(ac->san_a),
-                                            "%s.%s.token.acme.invalid",
-                                            buf, buf + 64);
+                       lws_snprintf(ac->http01_mountpoint,
+                                       sizeof(ac->http01_mountpoint),
+                                       "/.well-known/acme-challenge/%s",
+                                       ac->chall_token);
 
-                               /*
-                                * SAN B MUST be constructed as follows: compute
-                                * the SHA-256 digest of the UTF-8 encoded key
-                                * authorization and encode it in lowercase
-                                * hexadecimal form.  The dNSName is
-                                * "x.y.ka.acme.invalid" where x is the first
-                                * half of the hexadecimal representation and y
-                                * is the second half.
-                                */
-                               lws_jwk_rfc7638_fingerprint(&vhd->jwk,
-                                                           (char *)digest);
-
-                               p = buf;
-                               for (n = 0; n < 32; n++) {
-                                       p += lws_snprintf(p, end - p, "%02x",
-                                                         digest[n] & 0xff);
-                                       if (n == (32 / 2) - 1)
-                                               p = buf + 64;
-                               }
-
-                               p = ac->san_b;
-                               lws_snprintf(p, sizeof(ac->san_b),
-                                            "%s.%s.ka.acme.invalid",
-                                            buf, buf + 64);
-                       } else {
-                               lws_snprintf(p, sizeof(ac->san_a),
-                                    "%s.%s.acme.invalid", buf, buf + 64);
-                               ac->san_b[0] = '\0';
-                       }
+                       memset(&ac->mount, 0, sizeof (struct lws_http_mount));
+                       ac->mount.protocol = "http";
+                       ac->mount.mountpoint = ac->http01_mountpoint;
+                       ac->mount.mountpoint_len = (unsigned char)
+                               strlen(ac->http01_mountpoint);
+                       ac->mount.origin_protocol = LWSMPRO_CALLBACK;
 
-                       lwsl_notice("san_a: '%s'\n", ac->san_a);
-                       lwsl_notice("san_b: '%s'\n", ac->san_b);
-
-                       /*
-                        * tls-sni-01:
-                        *
-                        * The client then configures the TLS server at the
-                        * domain such that when a handshake is initiated with
-                        * the Server Name Indication extension set to
-                        * "<Zi[0:32]>.<Zi[32:64]>.acme.invalid", the
-                        * corresponding generated certificate is presented.
-                        *
-                        * tls-sni-02:
-                        *
-                        *  The client MUST ensure that the certificate is
-                        *  served to TLS connections specifying a Server Name
-                        *  Indication (SNI) value of SAN A.
-                        */
-                       ac->ci.vhost_name = ac->san_a;
-
-                       /*
-                        * we bind to exact iface of real vhost, so we can
-                        * share the listen socket by SNI
-                        */
-                       ac->ci.iface = ac->real_vh_iface;
+                       ac->ci.mounts = &ac->mount;
 
                        /* listen on the same port as the vhost that triggered
                         * us */
-                       ac->ci.port = ac->real_vh_port;
-                       /* Skip filling in any x509 info into the ssl_ctx.
-                        * It will be done at the callback
-                        * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS
-                        * in this callback handler (below)
-                        */
-                       ac->ci.options = LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX |
-                                        LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT |
-                                        LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+                       ac->ci.port = 80;
+
                        /* make ourselves protocols[0] for the new vhost */
-                       ac->ci.protocols = acme_protocols;
+                       ac->ci.protocols = chall_http01_protocols;
+
                        /*
                         * vhost .user points to the ac associated with the
                         * temporary vhost
@@ -1264,75 +1392,72 @@ pkt_add_hdrs:
                        ac->ci.user = ac;
 
                        ac->vhost = lws_create_vhost(lws_get_context(wsi),
-                                                    &ac->ci);
+                                       &ac->ci);
                        if (!ac->vhost)
                                goto failed;
 
+                       lwsl_notice("challenge_uri %s\n", ac->challenge_uri);
+
                        /*
                         * The challenge-specific vhost is up... let the ACME
                         * server know we are ready to roll...
                         */
-
                        ac->goes_around = 0;
                        cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
                                                       &ac->cwsi, &ac->i,
                                                       ac->challenge_uri,
                                                       "POST");
                        if (!cwsi) {
-                               lwsl_notice("%s: failed to connect\n",
-                                           __func__);
+                               lwsl_notice("%s: connect failed\n", __func__);
                                goto failed;
                        }
                        return -1; /* close the completed client connection */
 
-               case ACME_STATE_ACCEPT_CHALL:
-                       /*
-                        * he returned something like this (which we parsed)
-                        *
-                        * {
-                        *   "type": "tls-sni-01",
-                        *   "status": "pending",
-                        *   "uri": "https://acme-staging.api.letsencrypt.org/
-                        *              acme/challenge/xCt7bT3FaxoIQU3Qry87t5h
-                        *              uKDcC-L-0ERcD5DLAZts/71100507",
-                        *   "token": "j2Vs-vLI_dsza4A35SFHIU03aIe2PzFRijbqCY
-                        *              dIVeE",
-                        *   "keyAuthorization": "j2Vs-vLI_dsza4A35SFHIU03aIe2
-                        *              PzFRijbqCYdIVeE.nmOtdFd8Jikn6K8NnYYmT5
-                        *              vCM_PwSDT8nLdOYoFXhRU"
-                        * }
-                        *
-                        */
-                       lwsl_notice("%s: COMPLETED accept chall: %s\n",
-                                       __func__, ac->challenge_uri);
+               case ACME_STATE_START_CHALL:
+                       lwsl_notice("%s: COMPLETED start chall: %s\n",
+                                   __func__, ac->challenge_uri);
 poll_again:
                        ac->state = ACME_STATE_POLLING;
-                       lws_acme_report_status(vhd->vhost, LWS_CUS_CHALLENGE, NULL);
+                       lws_acme_report_status(vhd->vhost, LWS_CUS_CHALLENGE,
+                                              NULL);
 
                        if (ac->goes_around++ == 20) {
                                lwsl_notice("%s: too many chall retries\n",
-                                           __func__);
+                                               __func__);
 
                                goto failed;
                        }
 
-                       lws_timed_callback_vh_protocol(vhd->vhost, vhd->protocol,
-                                       LWS_CALLBACK_USER + 0xac33, ac->goes_around == 1 ? 10 : 2);
+                       strcpy(buf, ac->order_url);
+                       cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
+                                                      &ac->cwsi, &ac->i, buf,
+                                                      "POST");
+                       if (!cwsi) {
+                               lwsl_notice("%s: failed to connect to acme\n",
+                                               __func__);
+
+                               goto failed;
+                       }
                        return -1; /* close the completed client connection */
 
                case ACME_STATE_POLLING:
 
-                       if (ac->resp == 202 &&
-                           strcmp(ac->status, "invalid") &&
-                           strcmp(ac->status, "valid")) {
+                       if (ac->resp == 202 && strcmp(ac->status, "invalid") &&
+                                              strcmp(ac->status, "valid")) {
+                               lwsl_notice("status: %s\n", ac->status);
+                               goto poll_again;
+                       }
+
+                       if (!strcmp(ac->status, "pending")) {
                                lwsl_notice("status: %s\n", ac->status);
                                goto poll_again;
                        }
 
                        if (!strcmp(ac->status, "invalid")) {
-                               lwsl_notice("%s: polling failed\n", __func__);
+                               lwsl_notice("%s: Challenge failed\n", __func__);
                                lws_snprintf(buf, sizeof(buf),
-                                            "Challenge Invalid: %s", ac->detail);
+                                               "Challenge Invalid: %s",
+                                               ac->detail);
                                failreason = buf;
                                goto failed;
                        }
@@ -1341,7 +1466,7 @@ poll_again:
 
                        /*
                         * The challenge was validated... so delete the
-                        * temp SNI vhost now its job is done
+                        * temp vhost now its job is done
                         */
                        if (ac->vhost)
                                lws_vhost_destroy(ac->vhost);
@@ -1357,224 +1482,141 @@ poll_again:
                        lws_acme_report_status(vhd->vhost, LWS_CUS_REQ, NULL);
                        ac->goes_around = 0;
 
-                       strcpy(buf, ac->urls[JAD_NEW_CERT_URL]);
+                       strcpy(buf, ac->finalize_url);
                        cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
                                                       &ac->cwsi, &ac->i, buf,
                                                       "POST");
                        if (!cwsi) {
                                lwsl_notice("%s: failed to connect to acme\n",
-                                           __func__);
+                                               __func__);
 
                                goto failed;
                        }
                        return -1; /* close the completed client connection */
 
                case ACME_STATE_POLLING_CSR:
-                       /*
-                        * (after POSTing the CSR)...
-                        *
-                        * If the CA decides to issue a certificate, then the
-                        * server creates a new certificate resource and
-                        * returns a URI for it in the Location header field
-                        * of a 201 (Created) response.
-                        *
-                        * HTTP/1.1 201 Created
-                        * Location: https://example.com/acme/cert/asdf
-                        *
-                        * If the certificate is available at the time of the
-                        * response, it is provided in the body of the response.
-                        * If the CA has not yet issued the certificate, the
-                        * body of this response will be empty.  The client
-                        * should then send a GET request to the certificate URI
-                        * to poll for the certificate.  As long as the
-                        * certificate is unavailable, the server MUST provide a
-                        * 202 (Accepted) response and include a Retry-After
-                        * header to indicate when the server believes the
-                        * certificate will be issued.
-                        */
                        if (ac->resp < 200 || ac->resp > 202) {
                                lwsl_notice("CSR poll failed on resp %d\n",
-                                           ac->resp);
+                                               ac->resp);
                                goto failed;
                        }
 
-                       if (ac->resp == 200) {
-                               char *pp;
-                               int max;
-
-                               lwsl_notice("The cert was sent..\n");
-
-                               lws_acme_report_status(vhd->vhost,
-                                               LWS_CUS_ISSUE, NULL);
-
-                               /*
-                                * That means we have the issued cert DER in
-                                * ac->buf, length in ac->cpos; and the key in
-                                * ac->alloc_privkey_pem, length in
-                                * ac->len_privkey_pem.
-                                *
-                                * We write out a PEM copy of the cert, and a
-                                * PEM copy of the private key, using the
-                                * write-only fds we opened while we still
-                                * had root.
-                                *
-                                * Estimate the size of the PEM version of the
-                                * cert and allocate a temp buffer for it.
-                                *
-                                * This is a bit complicated because first we
-                                * drop the b64url version into the buffer at
-                                * +384, then we add the header at 0 and move
-                                * lines of it back + '\n' to make PEM.
-                                *
-                                * This avoids the need for two fullsize
-                                * allocations.
-                                */
-
-                               max = (ac->cpos * 4) / 3 + 16 + 384;
-
-                               start = p = malloc(max);
-                               if (!p)
-                                       goto failed;
+                       if (ac->resp != 200) {
+                               if (ac->goes_around++ == 30) {
+                                       lwsl_notice("%s: too many retries\n",
+                                                       __func__);
 
-                               n = lws_b64_encode_string(ac->buf, ac->cpos,
-                                                         start + 384, max - 384);
-                               if (n < 0) {
-                                       free(start);
                                        goto failed;
                                }
+                               strcpy(buf, ac->finalize_url);
+                               cwsi = lws_acme_client_connect(vhd->context,
+                                               vhd->vhost,
+                                               &ac->cwsi, &ac->i, buf,
+                                               "POST");
+                               if (!cwsi) {
+                                       lwsl_notice("%s: "
+                                               "failed to connect to acme\n",
+                                                       __func__);
 
-                               pp = start + 384;
-                               p += lws_snprintf(start, 64, "%s",
-                                               "-----BEGIN CERTIFICATE-----\n");
-
-                               while (n) {
-                                       m = 65;
-                                       if (n < m)
-                                               m = n;
-                                       memcpy(p, pp, m);
-                                       n -= m;
-                                       p += m;
-                                       pp += m;
-                                       if (n)
-                                               *p++ = '\n';
-                               }
-                               p += lws_snprintf(p,
-                                                 max - lws_ptr_diff(p, start),
-                                                 "%s",
-                                                 "\n-----END CERTIFICATE-----\n");
-
-                               n = lws_plat_write_cert(vhd->vhost, 0,
-                                               vhd->fd_updated_cert, start,
-                                               lws_ptr_diff(p, start));
-                               free(start);
-                               if (n) {
-                                       lwsl_err("unable to write ACME cert! %d\n", n);
                                        goto failed;
                                }
-                               /*
-                                * don't close it... we may update the certs
-                                * again
-                                */
+                               /* close the completed client connection */
+                               return -1;
+                       }
 
-                               if (lws_plat_write_cert(vhd->vhost, 1,
-                                                       vhd->fd_updated_key,
-                                                       ac->alloc_privkey_pem,
-                                                       ac->len_privkey_pem)) {
-                                       lwsl_err("unable to write ACME key!\n");
-                                       goto failed;
-                               }
+                       ac->state = ACME_STATE_DOWNLOAD_CERT;
 
-                               /*
-                                * we have written the persistent copies
-                                */
+                       strcpy(buf, ac->cert_url);
+                       cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
+                                                      &ac->cwsi, &ac->i, buf,
+                                                      "POST");
+                       if (!cwsi) {
+                               lwsl_notice("%s: failed to connect to acme\n",
+                                               __func__);
 
-                               lwsl_notice("%s: Updated certs written for %s "
-                                           "to %s.upd and %s.upd\n", __func__,
-                                           vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME],
-                                           vhd->pvop_active[LWS_TLS_SET_CERT_PATH],
-                                           vhd->pvop_active[LWS_TLS_SET_KEY_PATH]);
+                               goto failed;
+                       }
+                       return -1;
 
-                               /* notify lws there was a cert update */
+               case ACME_STATE_DOWNLOAD_CERT:
 
-                               if (lws_tls_cert_updated(vhd->context,
-                                       vhd->pvop_active[LWS_TLS_SET_CERT_PATH],
-                                       vhd->pvop_active[LWS_TLS_SET_KEY_PATH],
-                                       ac->buf, ac->cpos,
-                                       ac->alloc_privkey_pem,
-                                       ac->len_privkey_pem)) {
-                                       lwsl_notice("problem setting certs\n");
-                               }
+                       if (ac->resp != 200) {
+                               lwsl_notice("download cert failed on resp %d\n",
+                                           ac->resp);
+                               goto failed;
+                       }
+                       lwsl_notice("The cert was sent..\n");
 
-                               lws_acme_finished(vhd);
-                               lws_acme_report_status(vhd->vhost,
-                                                       LWS_CUS_SUCCESS, NULL);
+                       lws_acme_report_status(vhd->vhost, LWS_CUS_ISSUE, NULL);
 
-                               return 0;
+                       /*
+                        * That means we have the issued cert in
+                        * ac->buf, length in ac->cpos; and the key in
+                        * ac->alloc_privkey_pem, length in
+                        * ac->len_privkey_pem.
+                        */
+                       n = lws_plat_write_cert(vhd->vhost, 0,
+                                       vhd->fd_updated_cert,
+                                       ac->buf,
+                                       (size_t)ac->cpos);
+                       if (n) {
+                               lwsl_err("unable to write ACME cert! %d\n", n);
+                               goto failed;
                        }
 
-                       lws_acme_report_status(vhd->vhost, LWS_CUS_CONFIRM, NULL);
+                       /*
+                        * don't close it... we may update the certs
+                        * again
+                        */
+                       if (lws_plat_write_cert(vhd->vhost, 1,
+                                               vhd->fd_updated_key,
+                                               ac->alloc_privkey_pem,
+                                               ac->len_privkey_pem)) {
+                               lwsl_err("unable to write ACME key!\n");
+                               goto failed;
+                       }
 
-                       /* he is preparing the cert, go again with a GET */
+                       /*
+                        * we have written the persistent copies
+                        */
+                       lwsl_notice("%s: Updated certs written for %s "
+                                       "to %s.upd and %s.upd\n", __func__,
+                       vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME],
+                               vhd->pvop_active[LWS_TLS_SET_CERT_PATH],
+                               vhd->pvop_active[LWS_TLS_SET_KEY_PATH]);
 
-                       if (ac->goes_around++ == 30) {
-                               lwsl_notice("%s: too many retries\n",
-                                           __func__);
+                       /* notify lws there was a cert update */
 
-                               goto failed;
+                       if (lws_tls_cert_updated(vhd->context,
+                                       vhd->pvop_active[LWS_TLS_SET_CERT_PATH],
+                                       vhd->pvop_active[LWS_TLS_SET_KEY_PATH],
+                                               ac->buf, (size_t)ac->cpos,
+                                               ac->alloc_privkey_pem,
+                                               ac->len_privkey_pem)) {
+                               lwsl_notice("problem setting certs\n");
                        }
 
-                       strcpy(buf, ac->challenge_uri);
-                       cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
-                                                      &ac->cwsi, &ac->i, buf,
-                                                      "GET");
-                       if (!cwsi) {
-                               lwsl_notice("%s: failed to connect to acme\n",
-                                           __func__);
+                       lws_acme_finished(vhd);
+                       lws_acme_report_status(vhd->vhost,
+                                       LWS_CUS_SUCCESS, NULL);
 
-                               goto failed;
-                       }
-                       return -1; /* close the completed client connection */
+                       return -1;
 
                default:
                        break;
                }
                break;
 
-               case LWS_CALLBACK_USER + 0xac33:
-                       if (!vhd)
-                               break;
-                       cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
-                                                      &ac->cwsi, &ac->i,
-                                                      ac->challenge_uri,
-                                                      "GET");
-                       if (!cwsi) {
-                               lwsl_notice("%s: failed to connect\n", __func__);
-                               goto failed;
-                       }
+       case LWS_CALLBACK_USER + 0xac33:
+               if (!vhd)
                        break;
-
-       case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS:
-               /*
-                * This goes to vhost->protocols[0], but for our temp certs
-                * vhost we created, we have arranged that to be our protocol,
-                * so the callback will come here.
-                *
-                * When we created the temp vhost, we set its pvo to point
-                * to the ac associated with the temp vhost.
-                */
-               lwsl_debug("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS\n");
-               ac = (struct acme_connection *)lws_get_vhost_user(
-                                                       (struct lws_vhost *)in);
-
-               lws_acme_report_status((struct lws_vhost *)in,
-                                       LWS_CUS_CREATE_REQ,
-                                       "creating challenge cert");
-
-               if (lws_tls_acme_sni_cert_create((struct lws_vhost *)in,
-                                                ac->san_a, ac->san_b)) {
-                       lwsl_err("%s: creating the sni test cert failed\n", __func__);
-
-                       return -1;
+               cwsi = lws_acme_client_connect(vhd->context, vhd->vhost,
+                               &ac->cwsi, &ac->i,
+                               ac->challenge_uri,
+                               "GET");
+               if (!cwsi) {
+                       lwsl_notice("%s: failed to connect\n", __func__);
+                       goto failed;
                }
                break;
 
@@ -1585,7 +1627,7 @@ poll_again:
        return 0;
 
 failed:
-       lwsl_err("%s: failed out\n", __func__);
+       lwsl_notice("%s: failed out\n", __func__);
        lws_acme_report_status(vhd->vhost, LWS_CUS_FAILED, failreason);
        lws_acme_finished(vhd);
 
@@ -1594,32 +1636,22 @@ failed:
 
 #if !defined (LWS_PLUGIN_STATIC)
 
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols lws_acme_client_protocols[] = {
        LWS_PLUGIN_PROTOCOL_LWS_ACME_CLIENT
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_lws_acme_client(struct lws_context *context,
-                             struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_lws_acme_client(struct lws_context *context)
-{
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t protocol_lws_acme_client = {
+       .hdr = {
+               "acme client",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = lws_acme_client_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(lws_acme_client_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
 #endif
index ebb6e12..5168859 100644 (file)
@@ -74,7 +74,7 @@
        }
 
        function clear_errors() {
-               var t = document.getElementById("ongoing");
+               var n, t = document.getElementById("ongoing");
 
                for (n = 0; n < t.rows.length; n++)
                        if (t.rows[n].cells[0].classList.contains("err"))
        }
 
        function upl_button(e) {
-               var fi = document.getElementById("file"),
-               da = document.getElementById("da");
+               var fi = document.getElementById("file");
 
                clear_errors();
                e.preventDefault();
 
        function new_ws(urlpath, protocol)
        {
-               if (typeof MozWebSocket != "undefined")
-                       return new MozWebSocket(urlpath, protocol);
-
                return new WebSocket(urlpath, protocol);
        }
 
index 7c40f69..79f736c 100644 (file)
@@ -1,27 +1,34 @@
 /*
- * lws protocol handler plugin for "Dead Drop"
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
@@ -126,11 +133,12 @@ static int
 scan_upload_dir(struct vhd_deaddrop *vhd)
 {
        char filepath[256], subdir[3][128], *p;
-       int m, sp = 0, initial, found = 0;
        struct lwsac *lwsac_head = NULL;
        lws_list_ptr sorted_head = NULL;
+       int i, sp = 0, found = 0;
        struct dir_entry *dire;
        struct dirent *de;
+       size_t initial, m;
        struct stat s;
        DIR *dir[3];
 
@@ -147,25 +155,33 @@ scan_upload_dir(struct vhd_deaddrop *vhd)
                de = readdir(dir[sp]);
                if (!de) {
                        closedir(dir[sp]);
+#if !defined(__COVERITY__)
                        if (!sp)
+#endif
                                break;
+#if !defined(__COVERITY__)
                        sp--;
                        continue;
+#endif
                }
 
                p = filepath;
 
-               for (m = 0; m <= sp; m++)
-                       p += lws_snprintf(p, (filepath + sizeof(filepath)) - p,
-                                         "%s/", subdir[m]);
+               for (i = 0; i <= sp; i++)
+                       p += lws_snprintf(p, lws_ptr_diff_size_t((filepath + sizeof(filepath)), p),
+                                         "%s/", subdir[i]);
 
-               lws_snprintf(p, (filepath + sizeof(filepath)) - p, "%s",
+               lws_snprintf(p, lws_ptr_diff_size_t((filepath + sizeof(filepath)), p), "%s",
                                  de->d_name);
 
                /* ignore temp files */
                if (de->d_name[strlen(de->d_name) - 1] == '~')
                        continue;
-
+#if defined(__COVERITY__)
+               s.st_size = 0;
+               s.st_mtime = 0;
+#else
+               /* coverity[toctou] */
                if (stat(filepath, &s))
                        continue;
 
@@ -189,6 +205,7 @@ scan_upload_dir(struct vhd_deaddrop *vhd)
                        }
                        continue;
                }
+#endif
 
                m = strlen(filepath + initial) + 1;
                dire = lwsac_use(&lwsac_head, sizeof(*dire) + m, 0);
@@ -199,11 +216,13 @@ scan_upload_dir(struct vhd_deaddrop *vhd)
                }
 
                dire->next = NULL;
-               dire->size = s.st_size;
+               dire->size = (unsigned long long)s.st_size;
                dire->mtime = s.st_mtime;
                dire->user[0] = '\0';
+#if !defined(__COVERITY__)
                if (sp)
                        lws_strncpy(dire->user, subdir[1], sizeof(dire->user));
+#endif
 
                found++;
 
@@ -243,10 +262,11 @@ bail:
 
 static int
 file_upload_cb(void *data, const char *name, const char *filename,
-              char *buf, int len, enum lws_spa_fileupload_states state)
+              char *buf, int _len, enum lws_spa_fileupload_states state)
 {
        struct pss_deaddrop *pss = (struct pss_deaddrop *)data;
        char filename2[256];
+       size_t len = (size_t)_len;
        int n;
 
        (void)n;
@@ -286,13 +306,13 @@ file_upload_cb(void *data, const char *name, const char *filename,
        case LWS_UFS_FINAL_CONTENT:
        case LWS_UFS_CONTENT:
                if (len) {
-                       pss->file_length += len;
+                       pss->file_length += (unsigned int)len;
 
                        /* if the file length is too big, drop it */
                        if (pss->file_length > pss->vhd->max_size) {
                                pss->response_code =
                                        HTTP_STATUS_REQ_ENTITY_TOO_LARGE;
-                               close((int)(long long)pss->fd);
+                               close((int)(lws_intptr_t)pss->fd);
                                pss->fd = LWS_INVALID_FILE;
                                unlink(pss->filename);
 
@@ -300,9 +320,9 @@ file_upload_cb(void *data, const char *name, const char *filename,
                        }
 
                        if (pss->fd != LWS_INVALID_FILE) {
-                               n = write((int)(long long)pss->fd, buf, len);
+                               n = (int)write((int)(lws_intptr_t)pss->fd, buf, (unsigned int)len);
                                lwsl_debug("%s: write %d says %d\n", __func__,
-                                          len, n);
+                                          (int)len, n);
                                lws_set_timeout(pss->wsi, PENDING_TIMEOUT_HTTP_CONTENT, 30);
                        }
                }
@@ -310,7 +330,7 @@ file_upload_cb(void *data, const char *name, const char *filename,
                        break;
 
                if (pss->fd != LWS_INVALID_FILE)
-                       close((int)(long long)pss->fd);
+                       close((int)(lws_intptr_t)pss->fd);
 
                /* the temp filename without the ~ */
                lws_strncpy(filename2, pss->filename, sizeof(filename2));
@@ -343,12 +363,12 @@ format_result(struct pss_deaddrop *pss)
        start = p;
        end = p + sizeof(pss->result) - LWS_PRE - 1;
 
-       p += lws_snprintf((char *)p, end -p,
+       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                        "<!DOCTYPE html><html lang=\"en\"><head>"
                        "<meta charset=utf-8 http-equiv=\"Content-Language\" "
                        "content=\"en\"/>"
                        "</head>");
-       p += lws_snprintf((char *)p, end - p, "</body></html>");
+       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "</body></html>");
 
        return (int)lws_ptr_diff(p, start);
 }
@@ -378,6 +398,8 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
                vhd = (struct vhd_deaddrop *)
                        lws_protocol_vh_priv_get(lws_get_vhost(wsi),
                                                 lws_get_protocol(wsi));
+               if (!vhd)
+                       return 0;
 
                vhd->context = lws_get_context(wsi);
                vhd->vh = lws_get_vhost(wsi);
@@ -385,10 +407,10 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
                vhd->max_size = 20 * 1024 * 1024; /* default without pvo */
 
                if (!lws_pvo_get_str(in, "max-size", &cp))
-                       vhd->max_size = atoll(cp);
+                       vhd->max_size = (unsigned long long)atoll(cp);
                if (lws_pvo_get_str(in, "upload-dir", &vhd->upload_dir)) {
-                       lwsl_err("%s: requires 'upload-dir' pvo\n", __func__);
-                       return -1;
+                       lwsl_warn("%s: requires 'upload-dir' pvo\n", __func__);
+                       return 0;
                }
 
                scan_upload_dir(vhd);
@@ -399,7 +421,8 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
                break;
 
        case LWS_CALLBACK_PROTOCOL_DESTROY:
-               lwsac_free(&vhd->lwsac_head);
+               if (vhd)
+                       lwsac_free(&vhd->lwsac_head);
                break;
 
        /* WS-related */
@@ -446,10 +469,10 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
 
                cp = strchr((const char *)in, '/');
                if (cp) {
-                       n = ((void *)cp - in) - 8;
+                       n = (int)(((void *)cp - in)) - 8;
 
                        if ((int)strlen(pss->user) != n ||
-                           memcmp(pss->user, ((const char *)in) + 8, n)) {
+                           memcmp(pss->user, ((const char *)in) + 8, (unsigned int)n)) {
                                lwsl_notice("%s: del: auth mismatch "
                                            " '%s' '%s' (%d)\n",
                                            __func__, pss->user,
@@ -482,7 +505,7 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
 
                was = 0;
                if (pss->first) {
-                       p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                          "{\"max_size\":%llu, \"files\": [",
                                          vhd->max_size);
                        was = 1;
@@ -490,7 +513,7 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
 
                m = 5;
                while (m-- && pss->dire) {
-                       p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                          "%c{\"name\":\"%s\", "
                                          "\"size\":%llu,"
                                          "\"mtime\":%llu,"
@@ -506,7 +529,7 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
                }
 
                if (!pss->dire) {
-                       p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                          "]}");
                        if (pss->lwsac_head) {
                                lwsac_unreference(&pss->lwsac_head);
@@ -514,8 +537,8 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
                        }
                }
 
-               n = lws_write(wsi, start, lws_ptr_diff(p, start),
-                             lws_write_ws_flags(LWS_WRITE_TEXT, was,
+               n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
+                               (enum lws_write_protocol)lws_write_ws_flags(LWS_WRITE_TEXT, was,
                                                 !pss->dire));
                if (n < 0) {
                        lwsl_notice("%s: ws write failed\n", __func__);
@@ -595,7 +618,8 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
                if (!pss->sent_headers) {
                        n = format_result(pss);
 
-                       if (lws_add_http_header_status(wsi, pss->response_code,
+                       if (lws_add_http_header_status(wsi,
+                                       (unsigned int)pss->response_code,
                                                       &p, end))
                                goto bail;
 
@@ -604,13 +628,13 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
                                        (unsigned char *)"text/html", 9,
                                        &p, end))
                                goto bail;
-                       if (lws_add_http_header_content_length(wsi, n, &p, end))
+                       if (lws_add_http_header_content_length(wsi, (lws_filepos_t)n, &p, end))
                                goto bail;
                        if (lws_finalize_http_header(wsi, &p, end))
                                goto bail;
 
                        /* first send the headers ... */
-                       n = lws_write(wsi, start, lws_ptr_diff(p, start),
+                       n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
                                      LWS_WRITE_HTTP_HEADERS |
                                      LWS_WRITE_H2_STREAM_END);
                        if (n < 0)
@@ -623,7 +647,7 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason,
 
                if (!pss->sent_body) {
                        n = format_result(pss);
-                       n = lws_write(wsi, (unsigned char *)start, n,
+                       n = lws_write(wsi, (unsigned char *)start, (unsigned int)n,
                                      LWS_WRITE_HTTP_FINAL);
 
                        pss->sent_body = 1;
@@ -671,32 +695,22 @@ try_to_reuse:
 
 #if !defined (LWS_PLUGIN_STATIC)
 
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols deaddrop_protocols[] = {
        LWS_PLUGIN_PROTOCOL_DEADDROP
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_deaddrop(struct lws_context *context,
-                      struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_deaddrop(struct lws_context *context)
-{
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t deaddrop = {
+       .hdr = {
+               "deaddrop",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = deaddrop_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(deaddrop_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
 #endif
diff --git a/plugins/generic-sessions/assets/admin-login.html b/plugins/generic-sessions/assets/admin-login.html
deleted file mode 100644 (file)
index 113df9c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-This is an example destination that will appear after successful Admin login.
-
-This URL cannot be served if you're not logged in as admin.
-</html>
diff --git a/plugins/generic-sessions/assets/failed-login.html b/plugins/generic-sessions/assets/failed-login.html
deleted file mode 100644 (file)
index 9ab065b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<html>
-This is an example destination that will appear after a failed login
-</html>
diff --git a/plugins/generic-sessions/assets/index.html b/plugins/generic-sessions/assets/index.html
deleted file mode 100644 (file)
index d40904a..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<html>
- <head>
- <meta charset="UTF-8"> 
-  <script src="/lws-common.js"></script>
-  <link rel="stylesheet" type="text/css" href="lwsgs.css"/>
-  <script src="lwsgs.js"></script>
-  </head>
-
-  <body class="seats">
-    <table class="lwsgs">
-     <tr>
-      <td class="logo">
-       <img src="lwsgs-logo.png">
-      </td>
-      <td class="">
-       <div id=lwsgs class="lwsgs"></div>
-      </td>
-     </tr>
-     
-     <tr><td colspan=2 class="h99">
-        <table class="c100"><tr>
-        <td class="c">
-       <span id="nolog" class="group2">
-       This is a demo application for lws generic-sessions.<br><br>
-       It's a simple messageboard.<br><br>
-       What's interesting about it is there is <b>no serverside scripting</b>,<br>
-       instead client js makes a wss:// connection back to the server<br>
-       and then reacts to JSON from the ws protocol.  Sessions stuff is <br>
-       handled by lws generic sessions, making the <a href="https://libwebsockets.org/git/libwebsockets/tree/plugins/generic-sessions/protocol_generic_sessions.c">actual<br>
-       test application</a> <a href="https://libwebsockets.org/git/libwebsockets/tree/plugins/generic-sessions/protocol_lws_messageboard.c">very small</a>.<br><br>
-       And because it's natively websocket, it's naturally connected<br>
-       for dynamic events and easy to maintain.
-       <br><br>
-       Register / Login at the top right to see and create new messages.
-       </span>
-       <span id="logged" class="group2">
-       <div id="newmsg">
-               <form action="msg" method="post" target="hidden">
-               New message<br>
-         <textarea id="msg" placeholder="type your message here" cols="40" rows="5" name="msg">
-               </textarea><br>
-               <input type="submit" id="send" name="send" disabled=1>
-               </form>
-       </div>
-       </span>
-       <div id="dmessages">
-        <span id="messages" ></span>
-       </div>
-       <span id="debug" class="group2"></span>
-       </td></tr></table>
-     </td></tr>
-    </table>
-   </form>
-   <iframe name="hidden" class="hidden"></iframe>
- </body>
-</html>
diff --git a/plugins/generic-sessions/assets/lwsgs-logo.png b/plugins/generic-sessions/assets/lwsgs-logo.png
deleted file mode 100644 (file)
index 723a124..0000000
Binary files a/plugins/generic-sessions/assets/lwsgs-logo.png and /dev/null differ
diff --git a/plugins/generic-sessions/assets/lwsgs.css b/plugins/generic-sessions/assets/lwsgs.css
deleted file mode 100644 (file)
index 9dfde75..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-.body { font-size: 12px }
-.gstitle { font-size: 18px }
-
-.group1 {
-       vertical-align:middle;
-       text-align:center;
-       background:#f0f0e0; 
-       padding:12px;
-       border-radius:10px;
-}
-.group2 {
-       display:none;
-       vertical-align:middle;
-       font-size: 22px;
-       text-align:center;
-       margin:auto;
-       align:center;
-       background-color: rgba(255, 255, 255, 0.8);
-       padding:12px;
-       border-radius:10px;
-}
-       
-body.seats {
-       background-image:url(seats.jpg)
-}
-
-div.lwsgs {
-       z-index: 3;
-       text-align:right;
-       background-color: rgba(255, 255, 255, 0.8);
-}
-
-table.lwsgs {
-       width:100%;
-       height:100%;
-       transition: max-height 2s;
-}
-table.c100 {
-       text-align:center;
-       width:100%;
-}
-
-table.r {
-       vertical-align:top;
-       text-align:right;
-}
-
-table.l {
-       vertical-align:top;
-       text-align:left;
-}
-
-table.fixed {
-       table-layout: fixed;
-}
-
-td.logo {
-       vertical-align:top;
-       text-align:left;
-       width:200px
-}
-
-td.lwsgs {
-       vertical-align:top;
-       float:right;
-}
-
-td.h99 {
-       height:99%;
-       vertical-align:middle;
-}
-
-td.c {
-       margin:auto;
-       align:center
-}
-
-td.tac {
-       text-align:center
-}
-
-td.ava {
-       display:inline-block;
-       vertical-align:top;
-       word-wrap:break-word;
-}
-
-iframe.hidden {
-       display:none;
-}
-
-div.hidden {
-       display:none;
-}
-
-div.hiddenr {
-       display:none;
-       text-align:right;
-}
-
-input {
-       margin: 2px;
-       padding: 2px;
-}
-
-input.em {
-       margin: 4px;
-       font-weight:bold;
-}
-
-input.wide {
-       margin: 6px;
-       padding: 6px;
-}
-
-input.hidden {
-       display: none;
-}
-
-form.r {
-       text-align:right;
-}
-
-span.bad {
-       color: red;
-}
-
-span.small {
-       font-size:8pt;
-}
-
-.green {
-       color: green;
-}
diff --git a/plugins/generic-sessions/assets/lwsgs.js b/plugins/generic-sessions/assets/lwsgs.js
deleted file mode 100644 (file)
index b9bfe16..0000000
+++ /dev/null
@@ -1,631 +0,0 @@
-<!-- lwsgs rewrites the below $vars $v $v into the correct values on the fly -->
-
-var lwsgs_user = "$lwsgs_user";
-var lwsgs_auth = "$lwsgs_auth";
-var lwsgs_email = "$lwsgs_email";
-
-var lwsgs_html = '\
-       <div id="dlogin" class="hidden"> \
-        <form action="lwsgs-login" method="post"> \
-         <input type="hidden" name="admin" value="needadmin/admin-login.html"> \
-         <input type="hidden" name="good" value="index.html"> \
-         <input type="hidden" name="bad" value="failed-login.html"> \
-         <input type="hidden" name="forgot-good" value="sent-forgot-ok.html"> \
-         <input type="hidden" name="forgot-bad" value="sent-forgot-fail.html">\
-         <input type="hidden" name="forgot-post-good" value="post-forgot-ok.html">\
-         <input type="hidden" name="forgot-post-bad" value="post-forgot-fail.html">\
-        <table class="r">\
-          <tr>\
-           <td>User Name\
-            <input type="text" size="10" id="username" name="username"></td>\
-           <td>Password\
-            <input type="password" id="password" size="10" name="password"><div id="pw1"></div></td>\
-            </tr><tr>\
-          <td colspan="2" class="c"><input type="submit" id="login" name="login" value="Login" class="em">\
-      &nbsp;<input type="submit" id="forgot" name="forgot" value="Forgot password">\
-           &nbsp;<input id="doreg" type="button" value="Sign up"></td>\
-          </tr>\
-         </table>\
-        </form>\
-       </div>\
-\
-       <div id="dlogout" class="hiddenr">\
-        <form action="lwsgs-logout" method="post" class="r">\
-         <input type="hidden" name="good" value="index.html">\
-         <table class="r">\
-          <tr><td><span id=grav></span></td>\
-          <td class="tac"><table><tr><td class="tac">\
-               <a href="#" id="clink">\
-               <span id="curuser"></span></a></td></tr><tr>\
-           <td class="tac"><input type="submit" name="logout" value="Logout"></td>\
-          </tr></table></td></tr>\
-         </table>\
-        </form></div>\
-\
-       <div id="dregister" class="hidden">\
-        <form action="lwsgs-login" method="post">\
-         <input type="hidden" name="admin" value="needadmin/admin-login.html">\
-         <input type="hidden" name="good" value="successful-login.html">\
-         <input type="hidden" name="bad" value="failed-login.html">\
-         <input type="hidden" name="reg-good" value="post-register-ok.html">\
-         <input type="hidden" name="reg-bad" value="post-register-fail.html">\
-         <input type="hidden" name="forgot-good" value="sent-forgot-ok.html">\
-         <input type="hidden" name="forgot-bad" value="sent-forgot-fail.html">\
-         <input type="hidden" name="forgot-post-good" value="post-forgot-ok.html">\
-         <input type="hidden" name="forgot-post-bad" value="post-forgot-fail.html">\
-         <table class="l">\
-            <tr>\
-             <td colspan=2 align=center>\
-               <span id="curuser"></span>\
-              <b>Please enter your details to register</b>:\
-             </td>\
-            </tr>\
-           <tr><td align=right>\
-            User Name:</td>\
-            <td><input type="text" size="10" id="rusername" name="username" &nbsp;<span id=uchk></span></td>\
-           </tr>\
-           <tr>\
-            <td align=right>Password:</td>\
-            <td><input type="password" size="10" id="rpassword" name="password">&nbsp;<span id="rpw1"></span></td>\
-           </tr>\
-           <tr>\
-           </tr>\
-           <tr>\
-            <td align=right><span id="pw2">Password (again):</span></td>\
-            <td><input type="password" size="10" id="password2" name="password2">&nbsp;<span id="match"></span></td>\
-           </tr>\
-           <tr>\
-            <td align=right>Email:</td>\
-            <td><input type="email" size="10" id="email" name="email"\
-                 placeholder="me@example.com" &nbsp;<span id=echk></span></td>\
-           </tr>\
-           <tr>\
-            <td colspan=2 align=center>\
-<input type="submit" id="register" name="register" value="Register" >\
-<input type="submit" id="rforgot" name="forgot" value="Forgot Password" class="hidden">\
-<input type="button" id="cancel" name="cancel" value="Cancel">\
-            </td>\
-           </tr>\
-         </table>\
-        </form>\
-       </div>\
-       \
-       <div id="dchange" class="hidden">\
-        <form action="lwsgs-change" method="post">\
-         <input type="hidden" id="cusername" name="username">\
-         <input type="hidden" name="admin" value="needadmin/admin-login.html">\
-         <input type="hidden" name="good" value="index.html">\
-         <input type="hidden" name="bad" value="failed-login.html">\
-         <input type="hidden" name="reg-good" value="post-register-ok.html">\
-         <input type="hidden" name="reg-bad" value="post-register-fail.html">\
-         <input type="hidden" name="forgot-good" value="sent-forgot-ok.html">\
-         <input type="hidden" name="forgot-bad" value="sent-forgot-fail.html">\
-         <input type="hidden" name="forgot-post-good" value="post-forgot-ok.html">\
-         <input type="hidden" name="forgot-post-bad" value="post-forgot-fail.html">\
-         <table class="l">\
-            <tr>\
-             <td colspan=2 align=center>\
-               <span id="ccuruser"></span>\
-              <b>Please enter your details to change</b>:\
-             </td>\
-            </tr>\
-           <tr><td align=right id="ccurpw_name">\
-            Current Password:</td>\
-            <td><input type="password" size="10" id="ccurpw" name="curpw"\
-                >&nbsp;<span id=cuchk></span></td>\
-           </tr>\
-           <tr>\
-            <td align=right>Password:</td>\
-            <td><input type="password" size="10" id="cpassword" name="password"\
-                 &nbsp;<span id="cpw1"></span></td>\
-           </tr>\
-           <tr>\
-            <td align=right><span id="pw2">Password (again)</span></td>\
-            <td><input type="password" size="10" id="cpassword2" name="password2"\
-                >&nbsp;<span id="cmatch"></span></td>\
-           </tr>\
-       <!-- not supported yet\
-           <tr>\
-            <td align=right id="cemail_name">Email:</td>\
-            <td><input type="email" size="10" id="cemail" name="email"\
-                 placeholder="?" \
-                 &nbsp;<span id=cechk></span></td>\
-           </tr> -->\
-           <tr>\
-            <td colspan=2 align=center>\
-             <input type="submit" id="change" name="change"\
-              value="Change" class="wide">\
-             <input type="submit" id="cforgot" name="forgot"\
-              value="Forgot Password" class="wide hidden">\
-             <input type="button" id="cancel2" name="cancel"\
-              value="Cancel" class="wide">\
-            </td>\
-           </tr>\
-           <tr>\
-            <td colspan=2>\
-             <input type="checkbox" id="showdel" name="showdel"\
-              > Show Delete&nbsp;\
-             <input type="submit" id="delete" name="delete" \
-              value="Delete Account" class="wide hidden">\
-            </td>\
-           </tr>\
-         </table>\
-        </form>\
-       </div>\
-       \
-       <div id="dadmin" class="hidden">\
-         Admin settings TBD\
-       </div>\
-';
-
-/*-- this came from
-  -- https://raw.githubusercontent.com/blueimp/JavaScript-MD5/master/js/md5.min.js
-  -- under MIT license */
-!function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t),e=(n>>16)+(t>>16)+(r>>16);return e<<16|65535&r}function r(n,t){return n<<t|n>>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<<r%32,n[(r+64>>>9<<4)+14]=r;var e,i,a,h,d,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,h=v,d=m,l=o(l,g,v,m,n[e],7,-680876936),m=o(m,l,g,v,n[e+1],12,-389564586),v=o(v,m,l,g,n[e+2],17,606105819),g=o(g,v,m,l,n[e+3],22,-1044525330),l=o(l,g,v,m,n[e+4],7,-176418897),m=o(m,l,g,v,n[e+5],12,1200080426),v=o(v,m,l,g,n[e+6],17,-1473231341),g=o(g,v,m,l,n[e+7],22,-45705983),l=o(l,g,v,m,n[e+8],7,1770035416),m=o(m,l,g,v,n[e+9],12,-1958414417),v=o(v,m,l,g,n[e+10],17,-42063),g=o(g,v,m,l,n[e+11],22,-1990404162),l=o(l,g,v,m,n[e+12],7,1804603682),m=o(m,l,g,v,n[e+13],12,-40341101),v=o(v,m,l,g,n[e+14],17,-1502002290),g=o(g,v,m,l,n[e+15],22,1236535329),l=u(l,g,v,m,n[e+1],5,-165796510),m=u(m,l,g,v,n[e+6],9,-1069501632),v=u(v,m,l,g,n[e+11],14,643717713),g=u(g,v,m,l,n[e],20,-373897302),l=u(l,g,v,m,n[e+5],5,-701558691),m=u(m,l,g,v,n[e+10],9,38016083),v=u(v,m,l,g,n[e+15],14,-660478335),g=u(g,v,m,l,n[e+4],20,-405537848),l=u(l,g,v,m,n[e+9],5,568446438),m=u(m,l,g,v,n[e+14],9,-1019803690),v=u(v,m,l,g,n[e+3],14,-187363961),g=u(g,v,m,l,n[e+8],20,1163531501),l=u(l,g,v,m,n[e+13],5,-1444681467),m=u(m,l,g,v,n[e+2],9,-51403784),v=u(v,m,l,g,n[e+7],14,1735328473),g=u(g,v,m,l,n[e+12],20,-1926607734),l=c(l,g,v,m,n[e+5],4,-378558),m=c(m,l,g,v,n[e+8],11,-2022574463),v=c(v,m,l,g,n[e+11],16,1839030562),g=c(g,v,m,l,n[e+14],23,-35309556),l=c(l,g,v,m,n[e+1],4,-1530992060),m=c(m,l,g,v,n[e+4],11,1272893353),v=c(v,m,l,g,n[e+7],16,-155497632),g=c(g,v,m,l,n[e+10],23,-1094730640),l=c(l,g,v,m,n[e+13],4,681279174),m=c(m,l,g,v,n[e],11,-358537222),v=c(v,m,l,g,n[e+3],16,-722521979),g=c(g,v,m,l,n[e+6],23,76029189),l=c(l,g,v,m,n[e+9],4,-640364487),m=c(m,l,g,v,n[e+12],11,-421815835),v=c(v,m,l,g,n[e+15],16,530742520),g=c(g,v,m,l,n[e+2],23,-995338651),l=f(l,g,v,m,n[e],6,-198630844),m=f(m,l,g,v,n[e+7],10,1126891415),v=f(v,m,l,g,n[e+14],15,-1416354905),g=f(g,v,m,l,n[e+5],21,-57434055),l=f(l,g,v,m,n[e+12],6,1700485571),m=f(m,l,g,v,n[e+3],10,-1894986606),v=f(v,m,l,g,n[e+10],15,-1051523),g=f(g,v,m,l,n[e+1],21,-2054922799),l=f(l,g,v,m,n[e+8],6,1873313359),m=f(m,l,g,v,n[e+15],10,-30611744),v=f(v,m,l,g,n[e+6],15,-1560198380),g=f(g,v,m,l,n[e+13],21,1309151649),l=f(l,g,v,m,n[e+4],6,-145523070),m=f(m,l,g,v,n[e+11],10,-1120210379),v=f(v,m,l,g,n[e+2],15,718787259),g=f(g,v,m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,h),m=t(m,d);return[l,g,v,m]}function a(n){var t,r="";for(t=0;t<32*n.length;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function h(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;for(t=0;t<8*n.length;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function d(n){return a(i(h(n),8*n.length))}function l(n,t){var r,e,o=h(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>16&&(o=i(o,8*n.length)),r=0;16>r;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(h(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="0123456789abcdef",o="";for(r=0;r<n.length;r+=1)t=n.charCodeAt(r),o+=e.charAt(t>>>4&15)+e.charAt(15&t);return o}function v(n){return unescape(encodeURIComponent(n))}function m(n){return d(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this);
-
-if (lwsgs_user.substring(0, 1) == "$") {
-       alert("lwsgs.js: lws generic sessions misconfigured and not providing vars");
-}
-function lwsgs_san(s)
-{
-       if (s.search("<") != -1)
-               return "invalid string";
-       
-       return s;
-}
-
-function lwsgs_update()
-{
-       var en_login = 1, en_forgot = 1;
-       
-       if (document.getElementById('password').value.length &&
-           document.getElementById('password').value.length < 8)
-               en_login = 0;
-       
-       if (!document.getElementById('username').value ||
-           !document.getElementById('password').value)
-               en_login = 0;
-       
-       if (!document.getElementById('username').value ||
-            document.getElementById('password').value)
-               en_forgot = 0;
-       
-       document.getElementById('login').disabled = !en_login;
-       document.getElementById('forgot').disabled = !en_forgot;
-       
-       if (lwsgs_user)
-               document.getElementById("curuser").innerHTML = lwsgs_san(lwsgs_user);
-
-       if (lwsgs_user === "")
-               document.getElementById("dlogin").style.display = "inline";
-       else
-               document.getElementById("dlogout").style.display = "inline";
- }
-
-function lwsgs_open_registration()
-{
-       document.getElementById("dadmin").style.display = "none";
-       document.getElementById("dlogin").style.display = "none";
-       document.getElementById("dlogout").style.display = "none";
-       document.getElementById("dchange").style.display = "none";
-       document.getElementById("dregister").style.display = "inline";
-}
-
-function lwsgs_cancel_registration()
-{
-       document.getElementById("dadmin").style.display = "none";
-       document.getElementById("dregister").style.display = "none";
-       document.getElementById("dchange").style.display = "none";
-
-       if (lwsgs_user === "")
-               document.getElementById("dlogin").style.display = "inline";
-       else
-               document.getElementById("dlogout").style.display = "inline";
-}
-
-function lwsgs_select_change()
-{
-       document.getElementById("dlogin").style.display = "none";
-       document.getElementById("dlogout").style.display = "none";
-       document.getElementById("dregister").style.display = "none";
-       if (lwsgs_auth & 2) {
-               document.getElementById("dadmin").style.display = "inline";
-               document.getElementById("dchange").style.display = "none";
-       } else {
-               document.getElementById("dadmin").style.display = "none";
-               document.getElementById("dchange").style.display = "inline";
-       }
-
-       event.preventDefault()
-}
-
-var lwsgs_user_check = '0';
-var lwsgs_email_check = '0';
-
-function lwsgs_rupdate()
-{
-       var en_register = 1, en_forgot = 0;
-
-       if (document.getElementById('rpassword').value ==
-           document.getElementById('password2').value) {
-               if (document.getElementById('rpassword').value.length)
-                       document.getElementById('match').innerHTML = 
-                               "<b class=\"green\">\u2713</b>";
-               else
-                       document.getElementById('match').innerHTML = "";
-               document.getElementById('pw2').style = "";
-       } else {
-               if (document.getElementById('password2').value ||
-                   document.getElementById('email').value) { // ie, he is filling in "register" path and cares
-                       document.getElementById('match').innerHTML =
-                               "<span class=\"bad\">\u2718 <b>Passwords do not match</b></span>";
-               } else
-                       document.getElementById('match').innerHTML =
-                               "<span class=\"bad\">\u2718 Passwords do not match</span>";
-
-               en_register = 0;
-       }
-
-       if (document.getElementById('rpassword').value.length &&
-           document.getElementById('rpassword').value.length < 8) {
-               en_register = 0;
-               document.getElementById('rpw1').innerHTML = "Need 8 chars";
-       } else
-               if (document.getElementById('rpassword').value.length)
-                       document.getElementById('rpw1').innerHTML = "<b class=\"green\">\u2713</b>";
-               else
-                       document.getElementById('rpw1').innerHTML = "";
-
-       if (!document.getElementById('rpassword').value ||
-           !document.getElementById('password2').value ||
-           !document.getElementById('rusername').value ||
-           !document.getElementById('email').value ||
-           lwsgs_email_check === '1'||
-           lwsgs_user_check === '1')
-               en_register = 0;
-
-       document.getElementById('register').disabled = !en_register;
-       document.getElementById('rpassword').disabled = lwsgs_user_check === '1';
-       document.getElementById('password2').disabled = lwsgs_user_check === '1';
-       document.getElementById('email').disabled = lwsgs_user_check === '1';
-
-       if (lwsgs_user_check === '0') {
-               var uc = document.getElementById('uchk');
-
-               if (uc) {
-                       if (document.getElementById('rusername').value)
-                               uc.innerHTML = "<b class=\"green\">\u2713</b>";
-                       else
-                               uc.innerHTML = "";
-               }
-       } else {
-               if (document.getElementById('uchk'))
-                       ocument.getElementById('uchk').innerHTML = "<b class=\"red\">\u2718 Already registered</b>";
-               en_forgot = 1;
-       }
-
-       if (lwsgs_email_check === '0') {
-               var ec = document.getElementById('echk');
-
-               if (ec) {
-                       if (document.getElementById('email').value)
-                               ec.innerHTML = "<b class=\"green\">\u2713</b>";
-                       else
-                               ec.innerHTML = "";
-               }
-       } else {
-               if (document.getElementById('echk'))
-                       document.getElementById('echk').innerHTML = "<b class=\"red\">\u2718 Already registered</b>";
-               en_forgot = 1;
-       }
-
-       if (en_forgot)
-               document.getElementById('rforgot').style.display = "inline";
-       else
-               document.getElementById('rforgot').style.display = "none";
-
-       if (lwsgs_user_check === '1')
-               op = '0.5';
-       else
-               op = '1.0';
-       document.getElementById('rpassword').style.opacity = op;
-       document.getElementById('password2').style.opacity = op;
-       document.getElementById('email').style.opacity = op;
- }
-
-function lwsgs_cupdate()
-{
-       var en_change = 1, en_forgot = 1, pwok = 1;
-       
-       if (lwsgs_auth & 8) {
-               document.getElementById('ccurpw').style.display = "none";
-               document.getElementById('ccurpw_name').style.display = "none";
-       } else {
-               if (!document.getElementById('ccurpw').value ||
-                   document.getElementById('ccurpw').value.length < 8) {
-                       en_change = 0;
-                       pwok = 0;
-                       document.getElementById('cuchk').innerHTML = "<b class=\"red\">\u2718</b>";
-               } else {
-                       en_forgot = 0;
-                       document.getElementById('cuchk').innerHTML = "";
-               }
-               document.getElementById('ccurpw').style.display = "inline";
-               document.getElementById('ccurpw_name').style.display = "inline";
-       }
-
-       if (document.getElementById('cpassword').value ==
-           document.getElementById('cpassword2').value) {
-               if (document.getElementById('cpassword').value.length)
-                       document.getElementById('cmatch').innerHTML = "<b class=\"green\">\u2713</b>";
-               else
-                       document.getElementById('cmatch').innerHTML = "";
-               document.getElementById('pw2').style = "";
-       } else {
-               if (document.getElementById('cpassword2').value //||
-                   //document.getElementById('cemail').value
-               ) { // ie, he is filling in "register" path and cares
-                       document.getElementById('cmatch').innerHTML =
-                               "<span class=\"red\">\u2718 <b>Passwords do not match</b></span>";
-               } else
-                       document.getElementById('cmatch').innerHTML = "<span class=\"red\">\u2718 Passwords do not match</span>";
-
-               en_change = 0;
-       }
-
-       if (document.getElementById('cpassword').value.length &&
-           document.getElementById('cpassword').value.length < 8) {
-               en_change = 0;
-               document.getElementById('cpw1').innerHTML = "Need 8 chars";
-       } else {
-               var cpw = document.getElementById('cpw1');
-
-               if (cpw) {
-                       if (document.getElementById('cpassword').value.length)
-                               cpw.innerHTML = "<b class=\"green\">\u2713</b>";
-                       else
-                               cpw.innerHTML = "";
-               }
-       }
-
-       if (!document.getElementById('cpassword').value ||
-           !document.getElementById('cpassword2').value ||
-           pwok === 0)
-               en_change = 0;
-       
-       if (document.getElementById('showdel').checked)
-               document.getElementById('delete').style.display = "inline";
-       else
-               document.getElementById('delete').style.display = "none";
-
-       document.getElementById('change').disabled = !en_change;
-       document.getElementById('cpassword').disabled = pwok === 0;
-       document.getElementById('cpassword2').disabled = pwok === 0;
-       document.getElementById('showdel').disabled = pwok === 0;
-       document.getElementById('delete').disabled = pwok === 0;
-       //document.getElementById('cemail').disabled = pwok === 0;
-
-       /*
-       if (lwsgs_auth & 8) {
-               document.getElementById('cemail').style.display = "none";
-               document.getElementById('cemail_name').style.display = "none";
-       } else {
-               document.getElementById('cemail').style.display = "inline";
-               document.getElementById('cemail_name').style.display = "inline";
-               if (lwsgs_email_check === '0'  &&
-                   document.getElementById('cemail').value != lwsgs_email) {
-                       if (document.getElementById('cemail').value)
-                               document.getElementById('cechk').innerHTML = "<b style=\"color:green\">\u2713</b>";
-                       else
-                               document.getElementById('cechk').innerHTML = "";
-               } else {
-                       document.getElementById('cechk').innerHTML = "<b style=\"color:red\">\u2718 Already registered</b>";
-                       en_forgot = 1;
-               }
-       } */
-       
-       if (lwsgs_auth & 8)
-               en_forgot = 0;
-
-       if (en_forgot)
-               document.getElementById('cforgot').style.display = "inline";
-       else
-               document.getElementById('cforgot').style.display = "none";
-
-       if (pwok === 0)
-               op = '0.5';
-       else
-               op = '1.0';
-       document.getElementById('cpassword').style.opacity = op;
-       document.getElementById('cpassword2').style.opacity = op;
-       // document.getElementById('cemail').style.opacity = op;
- }
-
-function lwsgs_check_user()
-{
-    var xmlHttp = new XMLHttpRequest();
-    xmlHttp.onreadystatechange = function() { 
-        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
-            lwsgs_user_check = xmlHttp.responseText;
-           lwsgs_rupdate();
-        }
-    }
-    xmlHttp.open("GET", "lwsgs-check?username="+document.getElementById('rusername').value, true);
-    xmlHttp.send(null);
-}
-
-function lwsgs_check_email(id)
-{
-    var xmlHttp = new XMLHttpRequest();
-    xmlHttp.onreadystatechange = function() { 
-        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
-            lwsgs_email_check = xmlHttp.responseText;
-           lwsgs_rupdate();
-        }
-    }
-    xmlHttp.open("GET", "lwsgs-check?email="+document.getElementById(id).value, true);
-    xmlHttp.send(null);
-}
-
-function rupdate_user()
-{
-       lwsgs_rupdate();
-       lwsgs_check_user();
-}
-
-function rupdate_email()
-{
-       lwsgs_rupdate();
-       lwsgs_check_email('email');
-}
-
-function cupdate_email()
-{
-       lwsgs_cupdate();
-       lwsgs_check_email('cemail');
-}
-
-
-function lwsgs_initial()
-{
-       document.getElementById('lwsgs').innerHTML = lwsgs_html;
-
-       if (lwsgs_user) {
-               document.getElementById("curuser").innerHTML =
-                       "currently logged in as " + lwsgs_san(lwsgs_user) + "</br>";
-
-               document.getElementById("ccuruser").innerHTML =
-                 "<span class=\"gstitle\">Login settings for " +
-                 lwsgs_san(lwsgs_user) + "</span></br>";
-       }
-
-       document.getElementById('username').oninput = lwsgs_update;
-       document.getElementById('username').onchange = lwsgs_update;
-       document.getElementById('password').oninput = lwsgs_update;
-       document.getElementById('password').onchange = lwsgs_update;
-       document.getElementById('doreg').onclick = lwsgs_open_registration;
-       document.getElementById('clink').onclick = lwsgs_select_change;
-       document.getElementById('cancel').onclick =lwsgs_cancel_registration;
-       document.getElementById('cancel2').onclick =lwsgs_cancel_registration;
-       document.getElementById('rpassword').oninput = lwsgs_rupdate;
-       document.getElementById('password2').oninput = lwsgs_rupdate;
-       document.getElementById('rusername').oninput = rupdate_user;
-       document.getElementById('email').oninput  = rupdate_email;
-       document.getElementById('ccurpw').oninput = lwsgs_cupdate;
-       document.getElementById('cpassword').oninput = lwsgs_cupdate;
-       document.getElementById('cpassword2').oninput = lwsgs_cupdate;
-<!--   document.getElementById('cemail').oninput = cupdate_email;-->
-       document.getElementById('showdel').onchange = lwsgs_cupdate;
-
-       if (lwsgs_email)
-               document.getElementById('grav').innerHTML =
-                       "<img src=\"https://www.gravatar.com/avatar/" + md5(lwsgs_email) +
-                       "?d=identicon\">";
-       //if (lwsgs_email)
-               //document.getElementById('cemail').placeholder = lwsgs_email;
-       document.getElementById('cusername').value = lwsgs_user;
-       lwsgs_update();
-       lwsgs_cupdate();
-}
-
-window.addEventListener("load", function() {
-       lwsgs_initial();
-       document.getElementById("nolog").style.display = !!lwsgs_user ? "none" : "inline-block";
-       document.getElementById("logged").style.display = !lwsgs_user ? "none" : "inline-block";
-
-       document.getElementById("msg").onkeyup = mupd;
-       document.getElementById("msg").onchange = mupd;
-
-       var ws;
-
-       function mb_format(s)
-       {
-               var r = "", n, wos = 0;
-               
-               for (n = 0; n < s.length; n++) {
-                       if (s[n] == ' ')
-                               wos = 0;
-                       else {
-                               wos++;
-                               if (wos === 40) {
-                                       wos = 0;
-                                       r = r + ' ';
-                               }
-                       }
-                       if (s[n] == '<') {
-                               r = r + "&lt;";
-                               continue;
-                       }
-                       if (s[n] == '\n') {
-                               r = r + "<br>";
-                               continue;
-                       }
-                               
-                       r = r + s[n];
-               }
-               
-               return r;
-       }
-
-       function add_div(n, m)
-       {
-               var q = document.getElementById(n);
-               var d = new Date(m.time * 1000);
-               
-               q.innerHTML = "<br><div class=\"group2\"><table class=\"fixed\"><tr><td>" +
-                       "<img src=\"https://www.gravatar.com/avatar/" + md5(m.email) +
-                       "?d=identicon\"><br>" +
-                       "<b>" + lwsgs_san(m.username) + "</b><br>" +
-                       "<span class=\"small\">" + d.toDateString() +
-                         "<br>" + d.toTimeString() + "</span><br>" +
-                       "IP: " + lwsgs_san(m.ip) +
-                       "</td><td class=\"ava\"><span>" +
-                       mb_format(m.content) +
-                       "</span></td></tr></table></div><br>" + q.innerHTML;
-       }
-
-       function get_appropriate_ws_url()
-       {
-               var pcol;
-               var u = document.URL;
-
-               if (u.substring(0, 5) == "https") {
-                       pcol = "wss://";
-                       u = u.substr(8);
-               } else {
-                       pcol = "ws://";
-                       if (u.substring(0, 4) == "http")
-                               u = u.substr(7);
-               }
-               u = u.split('/');
-
-               return pcol + u[0] + "/xxx";
-       }
-
-       if (lwsgs_user) {
-               if (typeof MozWebSocket != "undefined")
-                       ws = new MozWebSocket(get_appropriate_ws_url(),
-                                          "protocol-lws-messageboard");
-               else
-                       ws = new WebSocket(get_appropriate_ws_url(),
-                                          "protocol-lws-messageboard");
-
-               try {
-                       ws.onopen = function() {
-                               document.getElementById("debug").textContent = "ws opened";
-                       }
-                       ws.onmessage =function got_packet(msg) {
-                               add_div("messages", JSON.parse(msg.data));
-                       }
-                       ws.onclose = function(){
-                       }
-               } catch(exception) {
-                       alert('<p>Error' + exception);  
-               }
-       }
-
-       function mupd()
-       {
-               document.getElementById("send").disabled = !document.getElementById("msg").value;
-       }
-}, false);
diff --git a/plugins/generic-sessions/assets/md5.min.js b/plugins/generic-sessions/assets/md5.min.js
deleted file mode 100644 (file)
index 4bd9de1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-!function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t),e=(n>>16)+(t>>16)+(r>>16);return e<<16|65535&r}function r(n,t){return n<<t|n>>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<<r%32,n[(r+64>>>9<<4)+14]=r;var e,i,a,h,d,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,h=v,d=m,l=o(l,g,v,m,n[e],7,-680876936),m=o(m,l,g,v,n[e+1],12,-389564586),v=o(v,m,l,g,n[e+2],17,606105819),g=o(g,v,m,l,n[e+3],22,-1044525330),l=o(l,g,v,m,n[e+4],7,-176418897),m=o(m,l,g,v,n[e+5],12,1200080426),v=o(v,m,l,g,n[e+6],17,-1473231341),g=o(g,v,m,l,n[e+7],22,-45705983),l=o(l,g,v,m,n[e+8],7,1770035416),m=o(m,l,g,v,n[e+9],12,-1958414417),v=o(v,m,l,g,n[e+10],17,-42063),g=o(g,v,m,l,n[e+11],22,-1990404162),l=o(l,g,v,m,n[e+12],7,1804603682),m=o(m,l,g,v,n[e+13],12,-40341101),v=o(v,m,l,g,n[e+14],17,-1502002290),g=o(g,v,m,l,n[e+15],22,1236535329),l=u(l,g,v,m,n[e+1],5,-165796510),m=u(m,l,g,v,n[e+6],9,-1069501632),v=u(v,m,l,g,n[e+11],14,643717713),g=u(g,v,m,l,n[e],20,-373897302),l=u(l,g,v,m,n[e+5],5,-701558691),m=u(m,l,g,v,n[e+10],9,38016083),v=u(v,m,l,g,n[e+15],14,-660478335),g=u(g,v,m,l,n[e+4],20,-405537848),l=u(l,g,v,m,n[e+9],5,568446438),m=u(m,l,g,v,n[e+14],9,-1019803690),v=u(v,m,l,g,n[e+3],14,-187363961),g=u(g,v,m,l,n[e+8],20,1163531501),l=u(l,g,v,m,n[e+13],5,-1444681467),m=u(m,l,g,v,n[e+2],9,-51403784),v=u(v,m,l,g,n[e+7],14,1735328473),g=u(g,v,m,l,n[e+12],20,-1926607734),l=c(l,g,v,m,n[e+5],4,-378558),m=c(m,l,g,v,n[e+8],11,-2022574463),v=c(v,m,l,g,n[e+11],16,1839030562),g=c(g,v,m,l,n[e+14],23,-35309556),l=c(l,g,v,m,n[e+1],4,-1530992060),m=c(m,l,g,v,n[e+4],11,1272893353),v=c(v,m,l,g,n[e+7],16,-155497632),g=c(g,v,m,l,n[e+10],23,-1094730640),l=c(l,g,v,m,n[e+13],4,681279174),m=c(m,l,g,v,n[e],11,-358537222),v=c(v,m,l,g,n[e+3],16,-722521979),g=c(g,v,m,l,n[e+6],23,76029189),l=c(l,g,v,m,n[e+9],4,-640364487),m=c(m,l,g,v,n[e+12],11,-421815835),v=c(v,m,l,g,n[e+15],16,530742520),g=c(g,v,m,l,n[e+2],23,-995338651),l=f(l,g,v,m,n[e],6,-198630844),m=f(m,l,g,v,n[e+7],10,1126891415),v=f(v,m,l,g,n[e+14],15,-1416354905),g=f(g,v,m,l,n[e+5],21,-57434055),l=f(l,g,v,m,n[e+12],6,1700485571),m=f(m,l,g,v,n[e+3],10,-1894986606),v=f(v,m,l,g,n[e+10],15,-1051523),g=f(g,v,m,l,n[e+1],21,-2054922799),l=f(l,g,v,m,n[e+8],6,1873313359),m=f(m,l,g,v,n[e+15],10,-30611744),v=f(v,m,l,g,n[e+6],15,-1560198380),g=f(g,v,m,l,n[e+13],21,1309151649),l=f(l,g,v,m,n[e+4],6,-145523070),m=f(m,l,g,v,n[e+11],10,-1120210379),v=f(v,m,l,g,n[e+2],15,718787259),g=f(g,v,m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,h),m=t(m,d);return[l,g,v,m]}function a(n){var t,r="";for(t=0;t<32*n.length;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function h(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;for(t=0;t<8*n.length;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function d(n){return a(i(h(n),8*n.length))}function l(n,t){var r,e,o=h(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>16&&(o=i(o,8*n.length)),r=0;16>r;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(h(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="0123456789abcdef",o="";for(r=0;r<n.length;r+=1)t=n.charCodeAt(r),o+=e.charAt(t>>>4&15)+e.charAt(15&t);return o}function v(n){return unescape(encodeURIComponent(n))}function m(n){return d(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this);
-//# sourceMappingURL=md5.min.js.map
\ No newline at end of file
diff --git a/plugins/generic-sessions/assets/post-forgot-fail.html b/plugins/generic-sessions/assets/post-forgot-fail.html
deleted file mode 100644 (file)
index ead3d13..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-Sorry, something went wrong.
-
-Click <a href="../">here</a> to continue.
-</html>
diff --git a/plugins/generic-sessions/assets/post-forgot-ok.html b/plugins/generic-sessions/assets/post-forgot-ok.html
deleted file mode 100644 (file)
index 3e8e9cf..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-This is a one-time password recovery login.
-
-Please click <a href="./">here</a> and click your username at the top to reset your password.
-</html>
-
diff --git a/plugins/generic-sessions/assets/post-register-fail.html b/plugins/generic-sessions/assets/post-register-fail.html
deleted file mode 100644 (file)
index 063c3c5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Registration failed, sorry
diff --git a/plugins/generic-sessions/assets/post-register-ok.html b/plugins/generic-sessions/assets/post-register-ok.html
deleted file mode 100644 (file)
index c00c3f3..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<html>
- <head>
-  <script src="lwsgs.js" nonce=lwscaro></script>
- </head>
- <body>
-  <table>
-    <tr>
-     <td colspan=2 align=center>
-      <img src="lwsgs-logo.png">
-     </td>
-    </tr>
-    <tr>
-     <td>
-      Your registration as <span id="u"></span> is accepted,<br>
-      you will receive an email shortly with instructions<br>
-      to verify and enable the account for normal use.<br><br>
-      The link is only valid for an hour, after that if it has<br>
-      not been verified your account will be deleted.
-     </td>
-    </tr>
-   </table>
-  </body>
- <script nonce=lwscaro>
-       document.getElementById('u').innerHTML = "<b>" + lwsgs_san(lwsgs_user) + "</b>";
- </script>
-</html>
-
diff --git a/plugins/generic-sessions/assets/post-verify-fail.html b/plugins/generic-sessions/assets/post-verify-fail.html
deleted file mode 100644 (file)
index d1d89ca..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<html>
- <head>
-  <script src="lwsgs.js"></script>
- </head>
- <body>
-  <table>
-    <tr>
-     <td colspan=2 align=center>
-      <img src="lwsws-logo.png">
-     </td>
-    </tr>
-    <tr>
-     <td>
-       Sorry, the link was invalid.
-     </td>
-    </tr>
-   </table>
-  </body>
-</html>
-
diff --git a/plugins/generic-sessions/assets/post-verify-ok.html b/plugins/generic-sessions/assets/post-verify-ok.html
deleted file mode 100644 (file)
index ae647fc..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<html>
- <head>
-  <script src="lwsgs.js"></script>
- </head>
- <body>
-  <table>
-    <tr>
-     <td colspan=2 align=center>
-      <img src="lwsgs-logo.png">
-     </td>
-    </tr>
-    <tr>
-     <td>
-        Thanks for signing up, your registration as <span id="u"></span> is verified.<br>
-       <br>
-       Click <a href="/lwsgs">here</a> to continue.
-     </td>
-    </tr>
-   </table>
-  </body>
- <script nonce="lwscaro">
-       document.getElementById('u').innerHTML = "<b>" + san(lwsgs_user) + "</b>";
- </script>
-</html>
-
diff --git a/plugins/generic-sessions/assets/seats.jpg b/plugins/generic-sessions/assets/seats.jpg
deleted file mode 100644 (file)
index 5bed40d..0000000
Binary files a/plugins/generic-sessions/assets/seats.jpg and /dev/null differ
diff --git a/plugins/generic-sessions/assets/sent-forgot-fail.html b/plugins/generic-sessions/assets/sent-forgot-fail.html
deleted file mode 100644 (file)
index ead3d13..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-Sorry, something went wrong.
-
-Click <a href="../">here</a> to continue.
-</html>
diff --git a/plugins/generic-sessions/assets/sent-forgot-ok.html b/plugins/generic-sessions/assets/sent-forgot-ok.html
deleted file mode 100644 (file)
index 83df751..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-An email has been sent to your registered address.
-
-Please follow the instructions to reset your password.
-
diff --git a/plugins/generic-sessions/assets/successful-login.html b/plugins/generic-sessions/assets/successful-login.html
deleted file mode 100644 (file)
index dfc25cf..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<html>
-This is an example destination that will appear after successful non-Admin login
-</html>
-
diff --git a/plugins/generic-sessions/handlers.c b/plugins/generic-sessions/handlers.c
deleted file mode 100644 (file)
index d4fd35a..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * ws protocol handler plugin for "generic sessions"
- *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library 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 library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301  USA
- */
-
-#include "private-lwsgs.h"
-
-static int
-lwsgs_smtp_client_done(struct lws_smtp_email *e, void *buf, size_t len)
-{
-       free(e);
-
-       return 0;
-}
-
-static int
-lwsgs_smtp_client_done_sentvfy(struct lws_smtp_email *e, void *buf, size_t len)
-{
-       struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)e->data;
-       const char *username = (const char *)e->extra;
-       char s[200], esc[96];
-
-       lwsl_notice("%s: registration email sent: %s\n", __func__, username);
-
-       /* mark the user as having sent the verification email */
-       lws_snprintf(s, sizeof(s) - 1,
-                "update users set verified=1 where username='%s' and verified==0;",
-                lws_sql_purify(esc, username, sizeof(esc) - 1));
-       if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
-               lwsl_err("%s: Unable to update user: %s\n", __func__,
-                        sqlite3_errmsg(vhd->pdb));
-               return 1;
-       }
-
-       free(e);
-
-       return 0;
-}
-
-/* handle account confirmation links */
-
-int
-lwsgs_handler_confirm(struct per_vhost_data__gs *vhd, struct lws *wsi,
-                     struct per_session_data__gs *pss)
-{
-       char cookie[1024], s[256], esc[90];
-       struct lws_gs_event_args a;
-       struct lwsgs_user u;
-
-       if (lws_hdr_copy_fragment(wsi, cookie, sizeof(cookie),
-                                 WSI_TOKEN_HTTP_URI_ARGS, 0) < 0) {
-               lwsl_err("%s: missing URI_ARGS\n", __func__);
-               goto verf_fail;
-       }
-
-       if (strncmp(cookie, "token=", 6)) {
-               lwsl_err("%s: missing URI_ARGS token=\n", __func__);
-               goto verf_fail;
-       }
-
-       u.username[0] = '\0';
-       u.verified = -1;
-       lws_snprintf(s, sizeof(s) - 1,
-                "select username,email,verified from users where token = '%s';",
-                lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
-       puts(s);
-       if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
-           SQLITE_OK) {
-               lwsl_err("Unable to lookup token: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               goto verf_fail;
-       }
-
-       if (!u.username[0] || u.verified != 1) {
-               lwsl_notice("verify token %s doesn't map to unverified user (user='%s', verified=%d)\n",
-                               &cookie[6], u.username, u.verified);
-               goto verf_fail;
-       }
-
-       lwsl_notice("Verifying %s\n", u.username);
-       lws_snprintf(s, sizeof(s) - 1,
-                "update users set verified=%d where username='%s';",
-                LWSGS_VERIFIED_ACCEPTED,
-                lws_sql_purify(esc, u.username, sizeof(esc) - 1));
-       if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
-           SQLITE_OK) {
-               lwsl_err("Unable to lookup token: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-
-               goto verf_fail;
-       }
-
-       lwsl_notice("deleting account\n");
-
-       a.event = LWSGSE_CREATED;
-       a.username = u.username;
-       a.email = u.email;
-       lws_callback_vhost_protocols_vhost(lws_get_vhost(wsi),
-                                          LWS_CALLBACK_GS_EVENT, &a, 0);
-
-       lws_snprintf(pss->onward, sizeof(pss->onward),
-                "%s/post-verify-ok.html", vhd->email_confirm_url);
-
-       pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
-
-       pss->delete_session.id[0] = '\0';
-       lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
-
-       /* we need to create a new, authorized session */
-
-       if (lwsgs_new_session_id(vhd, &pss->login_session, u.username,
-                                pss->login_expires))
-               goto verf_fail;
-
-       lwsl_notice("Creating new session: %s, redir to %s\n",
-                   pss->login_session.id, pss->onward);
-
-       return 0;
-
-verf_fail:
-       pss->delete_session.id[0] = '\0';
-       lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
-       pss->login_expires = 0;
-
-       lws_snprintf(pss->onward, sizeof(pss->onward), "%s/post-verify-fail.html",
-                vhd->email_confirm_url);
-
-       return 1;
-}
-
-/* handle forgot password confirmation links */
-
-int
-lwsgs_handler_forgot(struct per_vhost_data__gs *vhd, struct lws *wsi,
-                    struct per_session_data__gs *pss)
-{
-       char cookie[1024], s[256], esc[96];
-       struct lwsgs_user u;
-       const char *a;
-
-       a = lws_get_urlarg_by_name(wsi, "token=", cookie, sizeof(cookie));
-       if (!a)
-               goto forgot_fail;
-
-       u.username[0] = '\0';
-       lws_snprintf(s, sizeof(s) - 1,
-                "select username,verified from users where verified=%d and "
-                "token = '%s' and token_time != 0;",
-                LWSGS_VERIFIED_ACCEPTED,
-                lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
-       if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
-           SQLITE_OK) {
-               lwsl_err("Unable to lookup token: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-
-               goto forgot_fail;
-       }
-
-       if (!u.username[0]) {
-               puts(s);
-               lwsl_notice("forgot token doesn't map to verified user\n");
-               goto forgot_fail;
-       }
-
-       /* mark user as having validated forgot flow just now */
-
-       lws_snprintf(s, sizeof(s) - 1,
-                "update users set token_time=0,last_forgot_validated=%lu "
-                "where username='%s';",
-                (unsigned long)lws_now_secs(),
-                lws_sql_purify(esc, u.username, sizeof(esc) - 1));
-
-       if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
-           SQLITE_OK) {
-               lwsl_err("Unable to lookup token: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               goto forgot_fail;
-       }
-
-       a = lws_get_urlarg_by_name(wsi, "good=", cookie, sizeof(cookie));
-       if (!a)
-               a = "broken-forget-post-good-url";
-
-       lws_snprintf(pss->onward, sizeof(pss->onward),
-                "%s/%s", vhd->email_confirm_url, a);
-
-       pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
-
-       pss->delete_session.id[0] = '\0';
-       lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
-
-       /* we need to create a new, authorized session */
-       if (lwsgs_new_session_id(vhd, &pss->login_session,
-                                u.username,
-                                pss->login_expires))
-               goto forgot_fail;
-
-       lwsl_notice("Creating new session: %s, redir to %s\n",
-                   pss->login_session.id, pss->onward);
-
-       return 0;
-
-forgot_fail:
-       pss->delete_session.id[0] = '\0';
-       lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
-       pss->login_expires = 0;
-
-       a = lws_get_urlarg_by_name(wsi, "bad=", cookie, sizeof(cookie));
-       if (!a)
-               a = "broken-forget-post-bad-url";
-
-       lws_snprintf(pss->onward, sizeof(pss->onward), "%s/%s",
-                vhd->email_confirm_url, a);
-
-       return 1;
-}
-
-/* support dynamic username / email checking */
-
-int
-lwsgs_handler_check(struct per_vhost_data__gs *vhd,
-                   struct lws *wsi, struct per_session_data__gs *pss,
-                   const char *in)
-{
-       static const char * const colname[] = { "username", "email" };
-       char s[256], esc[96], *pc;
-       unsigned char *p, *start, *end, buffer[LWS_PRE + 1024];
-       struct lwsgs_user u;
-       int n;
-
-       /*
-        * either /check/email=xxx@yyy   or: /check/username=xxx
-        * returns '0' if not already registered, else '1'
-        */
-
-       u.username[0] = '\0';
-
-       n = !strncmp(in, "email=", 6);
-       pc = strchr(in, '=');
-       if (!pc) {
-               lwsl_notice("cookie has no =\n");
-               goto reply;
-       }
-       pc++;
-
-       /* admin user cannot be registered in user db */
-       if (!strcmp(vhd->admin_user, pc)) {
-               u.username[0] = 'a';
-               goto reply;
-       }
-
-       lws_snprintf(s, sizeof(s) - 1,
-                "select username, email from users where %s = '%s';",
-                colname[n], lws_sql_purify(esc, pc, sizeof(esc) - 1));
-       if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
-           SQLITE_OK) {
-               lwsl_err("Unable to lookup token: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               goto reply;
-       }
-
-reply:
-       s[0] = '0' + !!u.username[0];
-       p = buffer + LWS_PRE;
-       start = p;
-       end = p + sizeof(buffer) - LWS_PRE;
-
-       if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
-               return -1;
-       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
-                                        (unsigned char *)"text/plain", 10,
-                                        &p, end))
-               return -1;
-
-       if (lws_add_http_header_content_length(wsi, 1, &p, end))
-               return -1;
-
-       if (lws_finalize_http_header(wsi, &p, end))
-               return -1;
-
-       n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
-       if (n != (p - start)) {
-               lwsl_err("_write returned %d from %ld\n", n, (long)(p - start));
-               return -1;
-       }
-
-       pss->check_response_value = s[0];
-       pss->check_response = 1;
-
-       lws_callback_on_writable(wsi);
-
-       return 0;
-}
-
-/* handle forgot password confirmation links */
-
-int
-lwsgs_handler_change_password(struct per_vhost_data__gs *vhd, struct lws *wsi,
-                             struct per_session_data__gs *pss)
-{
-       char s[256], esc[96], username[96];
-       struct lwsgs_user u;
-       lwsgw_hash sid;
-       int n = 0;
-
-       /* see if he's logged in */
-       username[0] = '\0';
-       if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
-               u.username[0] = '\0';
-               if (!lwsgs_lookup_session(vhd, &sid, username, sizeof(username))) {
-                       n = 1; /* yes, logged in */
-                       if (lwsgs_lookup_user(vhd, username, &u))
-                               return 1;
-
-                       /* did a forgot pw ? */
-                       if (u.last_forgot_validated > (time_t)lws_now_secs() - 300) {
-                               n |= LWSGS_AUTH_FORGOT_FLOW;
-                               lwsl_debug("within forgot password flow\n");
-                       }
-               }
-       }
-
-       lwsl_debug("auth value %d\n", n);
-
-       /* if he just did forgot pw flow, don't need old pw */
-       if ((n & (LWSGS_AUTH_FORGOT_FLOW | 1)) != (LWSGS_AUTH_FORGOT_FLOW | 1)) {
-               /* otherwise user:pass must be right */
-               lwsl_debug("checking pw\n");
-               if (lwsgs_check_credentials(vhd,
-                          lws_spa_get_string(pss->spa, FGS_USERNAME),
-                          lws_spa_get_string(pss->spa, FGS_CURPW))) {
-                       lwsl_notice("credentials bad\n");
-                       return 1;
-               }
-
-               lwsl_debug("current pw checks out\n");
-
-               lws_strncpy(u.username, lws_spa_get_string(pss->spa, FGS_USERNAME),
-                           sizeof(u.username));
-       }
-
-       /* does he want to delete his account? */
-
-       if (lws_spa_get_length(pss->spa, FGS_DELETE)) {
-               struct lws_gs_event_args a;
-
-               lwsl_notice("deleting account\n");
-
-               a.event = LWSGSE_DELETED;
-               a.username = u.username;
-               a.email = "";
-               lws_callback_vhost_protocols_vhost(lws_get_vhost(wsi),
-                                                  LWS_CALLBACK_GS_EVENT, &a, 0);
-
-               lws_snprintf(s, sizeof(s) - 1,
-                        "delete from users where username='%s';"
-                        "delete from sessions where username='%s';",
-                        lws_sql_purify(esc, u.username, sizeof(esc) - 1),
-                        lws_sql_purify(esc, u.username, sizeof(esc) - 1));
-               goto sql;
-       }
-
-       if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD), &u))
-               return 1;
-
-       lwsl_notice("updating password hash\n");
-
-       lws_snprintf(s, sizeof(s) - 1,
-                "update users set pwhash='%s', pwsalt='%s', "
-                "last_forgot_validated=0 where username='%s';",
-                u.pwhash.id, u.pwsalt.id,
-                lws_sql_purify(esc, u.username, sizeof(esc) - 1));
-
-sql:
-       if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
-               lwsl_err("Unable to update pw hash: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               return 1;
-       }
-
-       return 0;
-}
-
-int
-lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd,
-                            struct lws *wsi, struct per_session_data__gs *pss)
-{
-       char esc[96], esc1[96], esc2[96], esc3[96], esc4[96];
-       char s[LWSGS_EMAIL_CONTENT_SIZE];
-       unsigned char sid_rand[32];
-       lws_smtp_email_t *em;
-       struct lwsgs_user u;
-       lwsgw_hash hash;
-       int n;
-
-       lwsl_notice("FORGOT %s %s\n",
-                   lws_spa_get_string(pss->spa, FGS_USERNAME),
-                   lws_spa_get_string(pss->spa, FGS_EMAIL));
-
-       if (!lws_spa_get_string(pss->spa, FGS_USERNAME) &&
-           !lws_spa_get_string(pss->spa, FGS_EMAIL)) {
-               lwsl_err("Form must provide either "
-                         "username or email\n");
-               return -1;
-       }
-
-       if (!lws_spa_get_string(pss->spa, FGS_FORGOT_GOOD) ||
-           !lws_spa_get_string(pss->spa, FGS_FORGOT_BAD) ||
-           !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD) ||
-           !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD)) {
-               lwsl_err("Form must provide reg-good "
-                         "and reg-bad (and post-*)"
-                         "targets\n");
-               return -1;
-       }
-
-       u.username[0] = '\0';
-       if (lws_spa_get_string(pss->spa, FGS_USERNAME))
-               lws_snprintf(s, sizeof(s) - 1,
-                "select username,email "
-                "from users where username = '%s';",
-                lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME),
-                                sizeof(esc) - 1));
-       else
-               lws_snprintf(s, sizeof(s) - 1,
-                "select username,email "
-                "from users where email = '%s';",
-                lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc) - 1));
-       if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
-           SQLITE_OK) {
-               lwsl_err("Unable to lookup token: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               return 1;
-       }
-       if (!u.username[0]) {
-               lwsl_err("No match found %s\n", s);
-               return 1;
-       }
-
-       lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
-       if (lws_get_random(vhd->context, sid_rand,
-                          sizeof(sid_rand)) !=
-                          sizeof(sid_rand)) {
-               lwsl_err("Problem getting random for token\n");
-               return 1;
-       }
-       sha256_to_lwsgw_hash(sid_rand, &hash);
-
-       lws_snprintf(s, sizeof(s) - 1,
-                "update users set token='%s',token_time='%ld' where username='%s';",
-                hash.id, (long)lws_now_secs(),
-                lws_sql_purify(esc, u.username, sizeof(esc) - 1));
-       if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) !=
-           SQLITE_OK) {
-               lwsl_err("Unable to set token: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               return 1;
-       }
-
-       n = lws_snprintf(s, sizeof(s),
-               "From: Forgot Password Assistant Noreply <%s>\n"
-               "To: %s <%s>\n"
-                 "Subject: Password reset request\n"
-                 "\n"
-                 "Hello, %s\n\n"
-                 "We received a password reset request from IP %s for this email,\n"
-                 "to confirm you want to do that, please click the link below.\n\n",
-               lws_sql_purify(esc, vhd->email_from, sizeof(esc) - 1),
-               lws_sql_purify(esc1, u.username, sizeof(esc1) - 1),
-               lws_sql_purify(esc2, u.email, sizeof(esc2) - 1),
-               lws_sql_purify(esc3, u.username, sizeof(esc3) - 1),
-               lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1));
-       n += lws_snprintf(s + n, sizeof(s) - n,
-                 "%s/lwsgs-forgot?token=%s"
-                  "&good=%s"
-                  "&bad=%s\n\n"
-                 "If this request is unexpected, please ignore it and\n"
-                 "no further action will be taken.\n\n"
-               "If you have any questions or concerns about this\n"
-               "automated email, you can contact a real person at\n"
-               "%s.\n"
-               "\n.\n",
-               vhd->email_confirm_url, hash.id,
-               lws_urlencode(esc1,
-                            lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD),
-                            sizeof(esc1) - 1),
-               lws_urlencode(esc3,
-                             lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD),
-                             sizeof(esc3) - 1),
-               vhd->email_contact_person);
-
-       puts(s);
-
-       em = lws_smtp_client_alloc_email_helper(s, n, vhd->email_from, u.email,
-                                               u.username, strlen(u.username),
-                                               vhd, lwsgs_smtp_client_done);
-       if (!em)
-               return 1;
-       if (lws_smtp_client_add_email(vhd->smtp_client, em))
-               return 1;
-
-       return 0;
-}
-
-int
-lwsgs_handler_register_form(struct per_vhost_data__gs *vhd,
-                            struct lws *wsi,
-                            struct per_session_data__gs *pss)
-{
-       unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
-       char esc[96], esc1[96], esc2[96], esc3[96], esc4[96];
-       char s[LWSGS_EMAIL_CONTENT_SIZE];
-       unsigned char sid_rand[32];
-       lws_smtp_email_t *em;
-       struct lwsgs_user u;
-       lwsgw_hash hash;
-       size_t n;
-
-       lwsl_notice("REGISTER %s %s %s\n",
-                       lws_spa_get_string(pss->spa, FGS_USERNAME),
-                       lws_spa_get_string(pss->spa, FGS_PASSWORD),
-                       lws_spa_get_string(pss->spa, FGS_EMAIL));
-       if (lwsgs_get_sid_from_wsi(wsi,
-           &pss->login_session))
-               return 1;
-
-       lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
-       lwsl_notice("IP=%s\n", pss->ip);
-
-       if (!lws_spa_get_string(pss->spa, FGS_REG_GOOD) ||
-           !lws_spa_get_string(pss->spa, FGS_REG_BAD)) {
-               lwsl_info("Form must provide reg-good and reg-bad targets\n");
-               return -1;
-       }
-
-       /* admin user cannot be registered in user db */
-       if (!strcmp(vhd->admin_user,
-                   lws_spa_get_string(pss->spa, FGS_USERNAME)))
-               return 1;
-
-       if (!lwsgs_lookup_user(vhd,
-                       lws_spa_get_string(pss->spa, FGS_USERNAME), &u)) {
-               lwsl_notice("user %s already registered\n",
-                           lws_spa_get_string(pss->spa, FGS_USERNAME));
-               return 1;
-       }
-
-       u.username[0] = '\0';
-       lws_snprintf(s, sizeof(s) - 1, "select username, email from users where email = '%s';",
-                lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL),
-                sizeof(esc) - 1));
-
-       if (sqlite3_exec(vhd->pdb, s,
-                        lwsgs_lookup_callback_user, &u, NULL) != SQLITE_OK) {
-               lwsl_err("Unable to lookup token: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               return 1;
-       }
-
-       if (u.username[0]) {
-               lwsl_notice("email %s already in use\n",
-                           lws_spa_get_string(pss->spa, FGS_USERNAME));
-               return 1;
-       }
-
-       if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD),
-                               &u)) {
-               lwsl_err("Password hash failed\n");
-               return 1;
-       }
-
-       if (lws_get_random(vhd->context, sid_rand, sizeof(sid_rand)) !=
-           sizeof(sid_rand)) {
-               lwsl_err("Problem getting random for token\n");
-               return 1;
-       }
-       sha256_to_lwsgw_hash(sid_rand, &hash);
-
-       lws_snprintf((char *)buffer, sizeof(buffer) - 1,
-                "insert into users(username,"
-                " creation_time, ip, email, verified,"
-                " pwhash, pwsalt, token, last_forgot_validated)"
-                " values ('%s', %lu, '%s', '%s', 0,"
-                " '%s', '%s', '%s', 0);",
-               lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc) - 1),
-               (unsigned long)lws_now_secs(),
-               lws_sql_purify(esc1, pss->ip, sizeof(esc1) - 1),
-               lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
-               u.pwhash.id, u.pwsalt.id, hash.id);
-
-       if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL, NULL, NULL) != SQLITE_OK) {
-               lwsl_err("Unable to insert user: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               return 1;
-       }
-
-       n = lws_snprintf(s, sizeof(s),
-               "From: Noreply <%s>\n"
-               "To: %s <%s>\n"
-               "Subject: Registration verification\n"
-               "\n"
-                 "Hello, %s\n\n"
-                 "We received a registration from IP %s using this email,\n"
-                 "to confirm it is legitimate, please click the link below.\n\n"
-                 "%s/lwsgs-confirm?token=%s\n\n"
-                 "If this request is unexpected, please ignore it and\n"
-                 "no further action will be taken.\n\n"
-               "If you have any questions or concerns about this\n"
-               "automated email, you can contact a real person at\n"
-               "%s.\n"
-               "\n.\n",
-               lws_sql_purify(esc, vhd->email_from, sizeof(esc) - 1),
-               lws_sql_purify(esc1, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc1) - 1),
-               lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
-               lws_sql_purify(esc3, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc3) - 1),
-               lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1),
-               vhd->email_confirm_url, hash.id,
-               vhd->email_contact_person);
-
-       em = lws_smtp_client_alloc_email_helper(s, n, vhd->email_from,
-                               lws_spa_get_string(pss->spa, FGS_EMAIL),
-                               lws_spa_get_string(pss->spa, FGS_USERNAME),
-                               strlen(lws_spa_get_string(pss->spa, FGS_USERNAME)),
-                               vhd, lwsgs_smtp_client_done_sentvfy);
-       if (!em)
-               return 1;
-
-       if (lws_smtp_client_add_email(vhd->smtp_client, em))
-               return 1;
-
-       return 0;
-}
diff --git a/plugins/generic-sessions/private-lwsgs.h b/plugins/generic-sessions/private-lwsgs.h
deleted file mode 100644 (file)
index 841ed1a..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * ws protocol handler plugin for "generic sessions"
- *
- * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library 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 library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301  USA
- */
-
-#define LWS_DLL
-#define LWS_INTERNAL
-#include <libwebsockets.h>
-
-#include <sqlite3.h>
-#include <string.h>
-
-#define LWSGS_VERIFIED_ACCEPTED 100
-
-enum {
-       FGS_USERNAME,
-       FGS_PASSWORD,
-       FGS_PASSWORD2,
-       FGS_EMAIL,
-       FGS_REGISTER,
-       FGS_GOOD,
-       FGS_BAD,
-       FGS_REG_GOOD,
-       FGS_REG_BAD,
-       FGS_ADMIN,
-       FGS_FORGOT,
-       FGS_FORGOT_GOOD,
-       FGS_FORGOT_BAD,
-       FGS_FORGOT_POST_GOOD,
-       FGS_FORGOT_POST_BAD,
-       FGS_CHANGE,
-       FGS_CURPW,
-       FGS_DELETE,
-};
-
-struct lwsgs_user {
-       char username[32];
-       char ip[16];
-       lwsgw_hash pwhash;
-       lwsgw_hash pwsalt;
-       lwsgw_hash token;
-       time_t created;
-       time_t last_forgot_validated;
-       char email[100];
-       int verified;
-};
-
-struct per_vhost_data__gs {
-       lws_abs_t *smtp_client;
-       struct lwsgs_user u;
-       lws_token_map_t transport_tokens[3];
-       lws_token_map_t protocol_tokens[2];
-       char helo[64], ip[64];
-       struct lws_context *context;
-       char session_db[256];
-       char admin_user[32];
-       char urlroot[48];
-       char confounder[32];
-       char email_contact_person[128];
-       char email_title[128];
-       char email_template[128];
-       char email_confirm_url[128];
-       char email_from[128];
-       lwsgw_hash admin_password_sha256;
-       sqlite3 *pdb;
-       int timeout_idle_secs;
-       int timeout_absolute_secs;
-       int timeout_anon_absolute_secs;
-       int timeout_email_secs;
-       time_t last_session_expire;
-};
-
-struct per_session_data__gs {
-       struct lws_spa *spa;
-       lwsgw_hash login_session;
-       lwsgw_hash delete_session;
-       unsigned int login_expires;
-       char onward[256];
-       char result[500 + LWS_PRE];
-       char urldec[500 + LWS_PRE];
-       int result_len;
-       char ip[46];
-       struct lws_process_html_state phs;
-       int spos;
-       char check_response_value;
-
-       unsigned int logging_out:1;
-       unsigned int check_response:1;
-};
-
-/* utils.c */
-
-int
-lwsgs_lookup_callback_user(void *priv, int cols, char **col_val,
-                          char **col_name);
-void
-lwsgw_cookie_from_session(lwsgw_hash *sid, time_t expires, char **p, char *end);
-int
-lwsgs_get_sid_from_wsi(struct lws *wsi, lwsgw_hash *sid);
-int
-lwsgs_lookup_session(struct per_vhost_data__gs *vhd,
-                    const lwsgw_hash *sid, char *username, int len);
-int
-lwsgs_get_auth_level(struct per_vhost_data__gs *vhd,
-                    const char *username);
-int
-lwsgs_check_credentials(struct per_vhost_data__gs *vhd,
-                       const char *username, const char *password);
-void
-sha256_to_lwsgw_hash(unsigned char *hash, lwsgw_hash *shash);
-unsigned int
-lwsgs_now_secs(void);
-int
-lwsgw_check_admin(struct per_vhost_data__gs *vhd,
-                 const char *username, const char *password);
-int
-lwsgs_hash_password(struct per_vhost_data__gs *vhd,
-                   const char *password, struct lwsgs_user *u);
-int
-lwsgs_new_session_id(struct per_vhost_data__gs *vhd,
-                    lwsgw_hash *sid, const char *username, int exp);
-int
-lwsgs_lookup_user(struct per_vhost_data__gs *vhd,
-                 const char *username, struct lwsgs_user *u);
-int
-lwsgw_update_session(struct per_vhost_data__gs *vhd,
-                    lwsgw_hash *hash, const char *user);
-int
-lwsgw_expire_old_sessions(struct per_vhost_data__gs *vhd);
-
-
-/* handlers.c */
-
-int
-lwsgs_handler_confirm(struct per_vhost_data__gs *vhd, struct lws *wsi,
-                     struct per_session_data__gs *pss);
-int
-lwsgs_handler_forgot(struct per_vhost_data__gs *vhd, struct lws *wsi,
-                    struct per_session_data__gs *pss);
-int
-lwsgs_handler_check(struct per_vhost_data__gs *vhd, struct lws *wsi,
-                     struct per_session_data__gs *pss, const char *in);
-int
-lwsgs_handler_change_password(struct per_vhost_data__gs *vhd, struct lws *wsi,
-                             struct per_session_data__gs *pss);
-int
-lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd, struct lws *wsi,
-                            struct per_session_data__gs *pss);
-int
-lwsgs_handler_register_form(struct per_vhost_data__gs *vhd, struct lws *wsi,
-                            struct per_session_data__gs *pss);
-
diff --git a/plugins/generic-sessions/protocol_generic_sessions.c b/plugins/generic-sessions/protocol_generic_sessions.c
deleted file mode 100644 (file)
index 3888820..0000000
+++ /dev/null
@@ -1,899 +0,0 @@
-/*
- * ws protocol handler plugin for "generic sessions"
- *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library 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 library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301  USA
- */
-
-#include "private-lwsgs.h"
-#include <stdlib.h>
-
-/* keep changes in sync with the enum in lwsgs.h */
-static const char * const param_names[] = {
-       "username",
-       "password",
-       "password2",
-       "email",
-       "register",
-       "good",
-       "bad",
-       "reg-good",
-       "reg-bad",
-       "admin",
-       "forgot",
-       "forgot-good",
-       "forgot-bad",
-       "forgot-post-good",
-       "forgot-post-bad",
-       "change",
-       "curpw",
-       "delete"
-};
-
-struct lwsgs_fill_args {
-       char *buf;
-       int len;
-};
-
-static const struct lws_protocols protocols[];
-
-struct lwsgs_subst_args
-{
-       struct per_session_data__gs *pss;
-       struct per_vhost_data__gs *vhd;
-       struct lws *wsi;
-};
-
-static const char *
-lwsgs_subst(void *data, int index)
-{
-       struct lwsgs_subst_args *a = (struct lwsgs_subst_args *)data;
-       struct lwsgs_user u;
-       lwsgw_hash sid;
-       char esc[96], s[100];
-       int n;
-
-       a->pss->result[0] = '\0';
-       u.email[0] = '\0';
-       if (!lwsgs_get_sid_from_wsi(a->wsi, &sid)) {
-               if (lwsgs_lookup_session(a->vhd, &sid, a->pss->result, 31)) {
-                       lwsl_notice("sid lookup for %s failed\n", sid.id);
-                       a->pss->delete_session = sid;
-                       return NULL;
-               }
-               lws_snprintf(s, sizeof(s) - 1, "select username,email "
-                        "from users where username = '%s';",
-                        lws_sql_purify(esc, a->pss->result, sizeof(esc) - 1));
-               if (sqlite3_exec(a->vhd->pdb, s, lwsgs_lookup_callback_user,
-                                &u, NULL) != SQLITE_OK) {
-                       lwsl_err("Unable to lookup token: %s\n",
-                                sqlite3_errmsg(a->vhd->pdb));
-                       a->pss->delete_session = sid;
-                       return NULL;
-               }
-       } else
-               lwsl_notice("no sid\n");
-
-       lws_strncpy(a->pss->result + 32, u.email, 100);
-
-       switch (index) {
-       case 0:
-               return a->pss->result;
-
-       case 1:
-               n = lwsgs_get_auth_level(a->vhd, a->pss->result);
-               sprintf(a->pss->result, "%d", n);
-               return a->pss->result;
-       case 2:
-               return a->pss->result + 32;
-       }
-
-       return NULL;
-}
-
-static int
-lws_get_effective_host(struct lws *wsi, char *buf, size_t buflen)
-{
-       /* h2 */
-       if (lws_hdr_copy(wsi, buf, buflen - 1,
-                        WSI_TOKEN_HTTP_COLON_AUTHORITY) > 0)
-               return 0;
-
-       /* h1 */
-       if (lws_hdr_copy(wsi, buf, buflen - 1,  WSI_TOKEN_HOST) > 0)
-               return 0;
-
-       return 1;
-}
-
-static int
-callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
-                         void *user, void *in, size_t len)
-{
-       struct per_session_data__gs *pss = (struct per_session_data__gs *)user;
-       const struct lws_protocol_vhost_options *pvo;
-       struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)
-                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
-                               lws_vhost_name_to_protocol(lws_get_vhost(wsi),
-                                               "protocol-generic-sessions"));
-       char cookie[1024], username[32], *pc = cookie;
-       unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
-       struct lws_process_html_args *args = in;
-       struct lws_session_info *sinfo;
-       char s[LWSGS_EMAIL_CONTENT_SIZE];
-       unsigned char *p, *start, *end;
-       const char *cp, *cp1;
-       sqlite3_stmt *sm;
-       lwsgw_hash sid;
-       lws_abs_t abs;
-       int n;
-
-       switch (reason) {
-       case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
-
-               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
-                       lws_get_protocol(wsi), sizeof(struct per_vhost_data__gs));
-               if (!vhd)
-                       return 1;
-               vhd->context = lws_get_context(wsi);
-
-               /* defaults */
-               vhd->timeout_idle_secs = 600;
-               vhd->timeout_absolute_secs = 36000;
-               vhd->timeout_anon_absolute_secs = 1200;
-               vhd->timeout_email_secs = 24 * 3600;
-
-
-               strcpy(vhd->helo, "unconfigured.com");
-               strcpy(vhd->ip, "127.0.0.1");
-               strcpy(vhd->email_from, "noreply@unconfigured.com");
-               strcpy(vhd->email_title, "Registration Email from unconfigured");
-               vhd->urlroot[0] = '\0';
-
-               pvo = (const struct lws_protocol_vhost_options *)in;
-               while (pvo) {
-                       if (!strcmp(pvo->name, "admin-user"))
-                               lws_strncpy(vhd->admin_user, pvo->value,
-                                       sizeof(vhd->admin_user));
-                       if (!strcmp(pvo->name, "urlroot"))
-                               lws_strncpy(vhd->urlroot, pvo->value,
-                                       sizeof(vhd->urlroot));
-                       if (!strcmp(pvo->name, "admin-password-sha256"))
-                               lws_strncpy(vhd->admin_password_sha256.id, pvo->value,
-                                       sizeof(vhd->admin_password_sha256.id));
-                       if (!strcmp(pvo->name, "session-db"))
-                               lws_strncpy(vhd->session_db, pvo->value,
-                                       sizeof(vhd->session_db));
-                       if (!strcmp(pvo->name, "confounder"))
-                               lws_strncpy(vhd->confounder, pvo->value,
-                                       sizeof(vhd->confounder));
-                       if (!strcmp(pvo->name, "email-from"))
-                               lws_strncpy(vhd->email_from, pvo->value,
-                                       sizeof(vhd->email_from));
-                       if (!strcmp(pvo->name, "email-helo"))
-                               lws_strncpy(vhd->helo, pvo->value, sizeof(vhd->helo));
-                       if (!strcmp(pvo->name, "email-template"))
-                               lws_strncpy(vhd->email_template, pvo->value,
-                                       sizeof(vhd->email_template));
-                       if (!strcmp(pvo->name, "email-title"))
-                               lws_strncpy(vhd->email_title, pvo->value,
-                                       sizeof(vhd->email_title));
-                       if (!strcmp(pvo->name, "email-contact-person"))
-                               lws_strncpy(vhd->email_contact_person, pvo->value,
-                                       sizeof(vhd->email_contact_person));
-                       if (!strcmp(pvo->name, "email-confirm-url-base"))
-                               lws_strncpy(vhd->email_confirm_url, pvo->value,
-                                       sizeof(vhd->email_confirm_url));
-                       if (!strcmp(pvo->name, "email-server-ip"))
-                               lws_strncpy(vhd->ip, pvo->value, sizeof(vhd->ip));
-
-                       if (!strcmp(pvo->name, "timeout-idle-secs"))
-                               vhd->timeout_idle_secs = atoi(pvo->value);
-                       if (!strcmp(pvo->name, "timeout-absolute-secs"))
-                               vhd->timeout_absolute_secs = atoi(pvo->value);
-                       if (!strcmp(pvo->name, "timeout-anon-absolute-secs"))
-                               vhd->timeout_anon_absolute_secs = atoi(pvo->value);
-                       if (!strcmp(pvo->name, "email-expire"))
-                               vhd->timeout_email_secs = atoi(pvo->value);
-                       pvo = pvo->next;
-               }
-               if (!vhd->admin_user[0] ||
-                   !vhd->admin_password_sha256.id[0] ||
-                   !vhd->session_db[0]) {
-                       lwsl_err("generic-sessions: "
-                                "You must give \"admin-user\", "
-                                "\"admin-password-sha256\", "
-                                "and \"session_db\" per-vhost options\n");
-                       return 1;
-               }
-
-               if (lws_struct_sq3_open(lws_get_context(wsi),
-                                       vhd->session_db, &vhd->pdb)) {
-                       lwsl_err("Unable to open session db %s: %s\n",
-                                vhd->session_db, sqlite3_errmsg(vhd->pdb));
-
-                       return 1;
-               }
-
-               if (sqlite3_prepare(vhd->pdb,
-                                   "create table if not exists sessions ("
-                                   " name char(65),"
-                                   " username varchar(32),"
-                                   " expire integer"
-                                   ");",
-                                   -1, &sm, NULL) != SQLITE_OK) {
-                       lwsl_err("Unable to prepare session table init: %s\n",
-                                sqlite3_errmsg(vhd->pdb));
-
-                       return 1;
-               }
-
-               if (sqlite3_step(sm) != SQLITE_DONE) {
-                       lwsl_err("Unable to run session table init: %s\n",
-                                sqlite3_errmsg(vhd->pdb));
-
-                       return 1;
-               }
-               sqlite3_finalize(sm);
-
-               if (sqlite3_exec(vhd->pdb,
-                                "create table if not exists users ("
-                                " username varchar(32),"
-                                " creation_time integer,"
-                                " ip varchar(46),"
-                                " email varchar(100),"
-                                " pwhash varchar(65),"
-                                " pwsalt varchar(65),"
-                                " pwchange_time integer,"
-                                " token varchar(65),"
-                                " verified integer,"
-                                " token_time integer,"
-                                " last_forgot_validated integer,"
-                                " primary key (username)"
-                                ");",
-                                NULL, NULL, NULL) != SQLITE_OK) {
-                       lwsl_err("Unable to create user table: %s\n",
-                                sqlite3_errmsg(vhd->pdb));
-
-                       return 1;
-               }
-
-               memset(&abs, 0, sizeof(abs));
-               abs.vh = lws_get_vhost(wsi);
-
-               /* select the protocol and bind its tokens */
-
-               abs.ap = lws_abs_protocol_get_by_name("smtp");
-               if (!abs.ap)
-                       return 1;
-
-               vhd->protocol_tokens[0].name_index = LTMI_PSMTP_V_HELO;
-               vhd->protocol_tokens[0].u.value = vhd->helo;
-
-               abs.ap_tokens = vhd->protocol_tokens;
-
-               /* select the transport and bind its tokens */
-
-               abs.at = lws_abs_transport_get_by_name("raw_skt");
-               if (!abs.at)
-                       return 1;
-
-               vhd->transport_tokens[0].name_index = LTMI_PEER_V_DNS_ADDRESS;
-               vhd->transport_tokens[0].u.value = vhd->ip;
-               vhd->transport_tokens[1].name_index = LTMI_PEER_LV_PORT;
-               vhd->transport_tokens[1].u.lvalue = 25;
-
-               abs.at_tokens = vhd->transport_tokens;
-
-               vhd->smtp_client = lws_abs_bind_and_create_instance(&abs);
-               if (!vhd->smtp_client)
-                       return 1;
-
-               lwsl_notice("%s: created SMTP client\n", __func__);
-               break;
-
-       case LWS_CALLBACK_PROTOCOL_DESTROY:
-       //      lwsl_notice("gs: LWS_CALLBACK_PROTOCOL_DESTROY: v=%p, ctx=%p\n", vhd, vhd->context);
-               if (vhd->pdb) {
-                       sqlite3_close(vhd->pdb);
-                       vhd->pdb = NULL;
-               }
-               if (vhd->smtp_client)
-                       lws_abs_destroy_instance(&vhd->smtp_client);
-               break;
-
-       case LWS_CALLBACK_HTTP_WRITEABLE:
-                if (!pss->check_response)
-                        break;
-                pss->check_response = 0;
-               n = lws_write(wsi, (unsigned char *)&pss->check_response_value,
-                               1, LWS_WRITE_HTTP | LWS_WRITE_H2_STREAM_END);
-               if (n != 1)
-                       return -1;
-               goto try_to_reuse;
-
-       case LWS_CALLBACK_HTTP:
-               if (!pss) {
-                       lwsl_err("%s: no valid pss\n", __func__);
-                       return 1;
-               }
-
-               pss->login_session.id[0] = '\0';
-               pss->phs.pos = 0;
-
-               cp = in;
-               if ((*(const char *)in == '/'))
-                       cp++;
-
-               if (lws_get_effective_host(wsi, cookie, sizeof(cookie))) {
-                       lwsl_err("%s: HTTP: no effective host\n", __func__);
-                       return 1;
-               }
-
-               lwsl_notice("LWS_CALLBACK_HTTP: %s, HOST '%s'\n",
-                               (const char *)in, cookie);
-
-               n = strlen(cp);
-
-               lws_snprintf(pss->onward, sizeof(pss->onward),
-                            "%s%s", vhd->urlroot, (const char *)in);
-
-               if (n >= 12 &&
-                   !strcmp(cp + n - 12, "lwsgs-forgot")) {
-                       lwsgs_handler_forgot(vhd, wsi, pss);
-                       goto redirect_with_cookie;
-               }
-
-               if (n >= 13 &&
-                   !strcmp(cp + n - 13, "lwsgs-confirm")) {
-                       lwsgs_handler_confirm(vhd, wsi, pss);
-                       goto redirect_with_cookie;
-               }
-               cp = strstr(cp, "lwsgs-check/");
-               if (cp) {
-                       lwsgs_handler_check(vhd, wsi, pss, cp + 12);
-                       /* second, async part will complete transaction */
-                       break;
-               }
-
-               if (n >= 11 && !strcmp(cp + n - 11, "lwsgs-login"))
-                       break;
-               if (n >= 12 && !strcmp(cp + n - 12, "lwsgs-logout"))
-                       break;
-               if (n >= 12 && !strcmp(cp + n - 12, "lwsgs-forgot"))
-                       break;
-               if (n >= 12 && !strcmp(cp + n - 12, "lwsgs-change"))
-                       break;
-
-               /* if no legitimate url for GET, return 404 */
-
-               lwsl_err("http doing 404 on %s\n", cp);
-               lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
-
-               return -1;
-               //goto try_to_reuse;
-
-       case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
-               args = (struct lws_process_html_args *)in;
-               if (!args->chunked)
-                       break;
-       case LWS_CALLBACK_CHECK_ACCESS_RIGHTS:
-               n = 0;
-               username[0] = '\0';
-               sid.id[0] = '\0';
-               args = (struct lws_process_html_args *)in;
-               lwsl_notice("%s: LWS_CALLBACK_CHECK_ACCESS_RIGHTS: need 0x%x\n",
-                               __func__, args->max_len);
-               if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
-                       if (lwsgs_lookup_session(vhd, &sid, username,
-                                                sizeof(username))) {
-
-                               /*
-                                * if we're authenticating for ws, we don't
-                                * want to redirect it or gain a cookie on that,
-                                * he'll need to get the cookie from http
-                                * interactions outside of this.
-                                */
-                               if (args->chunked) {
-                                       lwsl_notice("%s: ws auth failed\n",
-                                                       __func__);
-
-                                       return 1;
-                               }
-
-                               lwsl_notice("session lookup for %s failed, "
-                                           "probably expired\n", sid.id);
-                               pss->delete_session = sid;
-                               args->final = 1; /* signal we dealt with it */
-                               lws_snprintf(pss->onward, sizeof(pss->onward) - 1,
-                                        "%s%s", vhd->urlroot, args->p);
-                               lwsl_notice("redirecting to ourselves with "
-                                           "cookie refresh\n");
-                               /* we need a redirect to ourselves,
-                                * session cookie is expired */
-                               goto redirect_with_cookie;
-                       }
-               } else
-                       lwsl_notice("failed to get sid from wsi\n");
-
-               n = lwsgs_get_auth_level(vhd, username);
-
-               if ((args->max_len & n) != args->max_len) {
-                       lwsl_notice("Access rights fail 0x%X vs 0x%X (cookie %s)\n",
-                                       args->max_len, n, sid.id);
-                       return 1;
-               }
-               lwsl_debug("Access rights OK\n");
-               break;
-
-       case LWS_CALLBACK_SESSION_INFO:
-       {
-               struct lwsgs_user u;
-               sinfo = (struct lws_session_info *)in;
-               sinfo->username[0] = '\0';
-               sinfo->email[0] = '\0';
-               sinfo->ip[0] = '\0';
-               sinfo->session[0] = '\0';
-               sinfo->mask = 0;
-
-               sid.id[0] = '\0';
-               lwsl_debug("LWS_CALLBACK_SESSION_INFO\n");
-               if (lwsgs_get_sid_from_wsi(wsi, &sid))
-                       break;
-               if (lwsgs_lookup_session(vhd, &sid, username, sizeof(username)))
-                       break;
-
-               lws_snprintf(s, sizeof(s) - 1,
-                        "select username, email from users where username='%s';",
-                        username);
-               if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
-                   SQLITE_OK) {
-                       lwsl_err("Unable to lookup token: %s\n",
-                                sqlite3_errmsg(vhd->pdb));
-                       break;
-               }
-               lws_strncpy(sinfo->username, u.username, sizeof(sinfo->username));
-               lws_strncpy(sinfo->email, u.email, sizeof(sinfo->email));
-               lws_strncpy(sinfo->session, sid.id, sizeof(sinfo->session));
-               sinfo->mask = lwsgs_get_auth_level(vhd, username);
-               lws_get_peer_simple(wsi, sinfo->ip, sizeof(sinfo->ip));
-       }
-
-               break;
-
-       case LWS_CALLBACK_PROCESS_HTML:
-
-               args = (struct lws_process_html_args *)in;
-               {
-                       static const char * const vars[] = {
-                               "$lwsgs_user",
-                               "$lwsgs_auth",
-                               "$lwsgs_email"
-                       };
-                       struct lwsgs_subst_args a;
-
-                       a.vhd = vhd;
-                       a.pss = pss;
-                       a.wsi = wsi;
-
-                       pss->phs.vars = vars;
-                       pss->phs.count_vars = LWS_ARRAY_SIZE(vars);
-                       pss->phs.replace = lwsgs_subst;
-                       pss->phs.data = &a;
-
-                       if (lws_chunked_html_process(args, &pss->phs))
-                               return -1;
-               }
-               break;
-
-       case LWS_CALLBACK_HTTP_BODY:
-               if (len < 2)
-                       break;
-
-               if (!pss->spa) {
-                       pss->spa = lws_spa_create(wsi, param_names,
-                                       LWS_ARRAY_SIZE(param_names), 1024,
-                                               NULL, NULL);
-                       if (!pss->spa)
-                               return -1;
-               }
-
-               if (lws_spa_process(pss->spa, in, len)) {
-                       lwsl_notice("spa process blew\n");
-                       return -1;
-               }
-               break;
-
-       case LWS_CALLBACK_HTTP_BODY_COMPLETION:
-
-               if (!pss->spa)
-                       break;
-
-               cp1 = (const char *)pss->onward;
-               if (*cp1 == '/')
-                       cp1++;
-
-
-               lws_spa_finalize(pss->spa);
-               n = strlen(cp1);
-
-               if (lws_get_effective_host(wsi, cookie, sizeof(cookie)))
-                       return 1;
-
-               if (!strcmp(cp1 + n - 12, "lwsgs-change")) {
-                       if (!lwsgs_handler_change_password(vhd, wsi, pss)) {
-                               cp = lws_spa_get_string(pss->spa, FGS_GOOD);
-                               goto pass;
-                       }
-
-                       cp = lws_spa_get_string(pss->spa, FGS_BAD);
-                       lwsl_notice("user/password no good %s\n",
-                               lws_spa_get_string(pss->spa, FGS_USERNAME));
-                       lws_snprintf(pss->onward, sizeof(pss->onward),
-                                    "%s%s", vhd->urlroot, cp);
-
-                       pss->onward[sizeof(pss->onward) - 1] = '\0';
-                       goto completion_flow;
-               }
-
-               if (!strcmp(cp1 + n - 11, "lwsgs-login")) {
-                       lwsl_err("%s: lwsgs-login\n", __func__);
-                       if (lws_spa_get_string(pss->spa, FGS_FORGOT) &&
-                           lws_spa_get_string(pss->spa, FGS_FORGOT)[0]) {
-                               if (lwsgs_handler_forgot_pw_form(vhd, wsi, pss)) {
-                                       n = FGS_FORGOT_BAD;
-                                       goto reg_done;
-                               }
-                               /* get the email monitor to take a look */
-                               lws_smtp_client_kick(vhd->smtp_client);
-                               n = FGS_FORGOT_GOOD;
-                               goto reg_done;
-                       }
-
-                       if (!lws_spa_get_string(pss->spa, FGS_USERNAME) ||
-                           !lws_spa_get_string(pss->spa, FGS_PASSWORD)) {
-                               lwsl_notice("username '%s' or pw '%s' missing\n",
-                                       lws_spa_get_string(pss->spa, FGS_USERNAME),
-                                       lws_spa_get_string(pss->spa, FGS_PASSWORD));
-                               return -1;
-                       }
-
-                       if (lws_spa_get_string(pss->spa, FGS_REGISTER) &&
-                           lws_spa_get_string(pss->spa, FGS_REGISTER)[0]) {
-
-                               if (lwsgs_handler_register_form(vhd, wsi, pss))
-                                       n = FGS_REG_BAD;
-                               else {
-                                       n = FGS_REG_GOOD;
-
-                                       /* get the email monitor to take a look */
-                                       lws_smtp_client_kick(vhd->smtp_client);
-                               }
-reg_done:
-                               lws_snprintf(pss->onward, sizeof(pss->onward),
-                                            "%s%s", vhd->urlroot,
-                                            lws_spa_get_string(pss->spa, n));
-
-                               pss->login_expires = 0;
-                               pss->logging_out = 1;
-                               goto completion_flow;
-                       }
-
-                       /* we have the username and password... check if admin */
-                       if (lwsgw_check_admin(vhd, lws_spa_get_string(pss->spa, FGS_USERNAME),
-                                             lws_spa_get_string(pss->spa, FGS_PASSWORD))) {
-                               if (lws_spa_get_string(pss->spa, FGS_ADMIN))
-                                       cp = lws_spa_get_string(pss->spa, FGS_ADMIN);
-                               else
-                                       if (lws_spa_get_string(pss->spa, FGS_GOOD))
-                                               cp = lws_spa_get_string(pss->spa, FGS_GOOD);
-                                       else {
-                                               lwsl_info("No admin or good target url in form\n");
-                                               return -1;
-                                       }
-                               lwsl_debug("admin\n");
-                               goto pass;
-                       }
-
-                       /* check users in database */
-
-                       if (!lwsgs_check_credentials(vhd,
-                                       lws_spa_get_string(pss->spa, FGS_USERNAME),
-                                       lws_spa_get_string(pss->spa, FGS_PASSWORD))) {
-                               lwsl_notice("pw hash check met\n");
-                               cp = lws_spa_get_string(pss->spa, FGS_GOOD);
-                               goto pass;
-                       } else
-                               lwsl_notice("user/password no good %s %s\n",
-                                               lws_spa_get_string(pss->spa, FGS_USERNAME),
-                                               lws_spa_get_string(pss->spa, FGS_PASSWORD));
-
-                       if (!lws_spa_get_string(pss->spa, FGS_BAD)) {
-                               lwsl_info("No admin or good target url in form\n");
-                               return -1;
-                       }
-
-                       lws_snprintf(pss->onward, sizeof(pss->onward),
-                                    "%s%s", vhd->urlroot,
-                                    lws_spa_get_string(pss->spa, FGS_BAD));
-
-                       lwsl_notice("failed: %s\n", pss->onward);
-
-                       goto completion_flow;
-               }
-
-               if (!strcmp(cp1 + n - 12, "lwsgs-logout")) {
-
-                       lwsl_notice("/logout\n");
-
-                       if (lwsgs_get_sid_from_wsi(wsi, &pss->login_session)) {
-                               lwsl_notice("not logged in...\n");
-                               return 1;
-                       }
-
-                       /*
-                        * We keep the same session, but mark it as not
-                        * being associated to any authenticated user
-                        */
-
-                       lwsgw_update_session(vhd, &pss->login_session, "");
-
-                       if (!lws_spa_get_string(pss->spa, FGS_GOOD)) {
-                               lwsl_info("No admin or good target url in form\n");
-                               return -1;
-                       }
-
-                       lws_snprintf(pss->onward, sizeof(pss->onward),
-                                    "%s%s", vhd->urlroot,
-                                    lws_spa_get_string(pss->spa, FGS_GOOD));
-
-                       pss->login_expires = 0;
-                       pss->logging_out = 1;
-
-                       goto completion_flow;
-               }
-
-               break;
-
-pass:
-               lws_snprintf(pss->onward, sizeof(pss->onward),
-                            "%s%s", vhd->urlroot, cp);
-
-               if (lwsgs_get_sid_from_wsi(wsi, &sid))
-                       sid.id[0] = '\0';
-
-               pss->login_expires = lws_now_secs() +
-                                    vhd->timeout_absolute_secs;
-
-               if (!sid.id[0]) {
-                       /* we need to create a new, authorized session */
-
-                       if (lwsgs_new_session_id(vhd, &pss->login_session,
-                                       lws_spa_get_string(pss->spa, FGS_USERNAME),
-                                       pss->login_expires))
-                               goto try_to_reuse;
-
-                       lwsl_notice("Creating new session: %s\n",
-                                   pss->login_session.id);
-               } else {
-                       /*
-                        * we can just update the existing session to be
-                        * authorized
-                        */
-                       lwsl_notice("Authorizing existing session %s", sid.id);
-                       lwsgw_update_session(vhd, &sid,
-                               lws_spa_get_string(pss->spa, FGS_USERNAME));
-                       pss->login_session = sid;
-               }
-
-completion_flow:
-               lwsgw_expire_old_sessions(vhd);
-               goto redirect_with_cookie;
-
-       case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
-               if (pss && pss->spa) {
-                       lws_spa_destroy(pss->spa);
-                       pss->spa = NULL;
-               }
-               break;
-
-       case LWS_CALLBACK_ADD_HEADERS:
-               lwsgw_expire_old_sessions(vhd);
-
-               lwsl_warn("ADD_HEADERS\n");
-
-               args = (struct lws_process_html_args *)in;
-               if (!pss)
-                       return 1;
-               if (pss->delete_session.id[0]) {
-                       pc = cookie;
-                       lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
-                                                 cookie + sizeof(cookie) - 1);
-
-                       lwsl_notice("deleting cookie '%s'\n", cookie);
-
-                       if (lws_add_http_header_by_name(wsi,
-                                       (unsigned char *)"set-cookie:",
-                                       (unsigned char *)cookie, pc - cookie,
-                                       (unsigned char **)&args->p,
-                                       (unsigned char *)args->p + args->max_len))
-                               return 1;
-               }
-
-               if (!pss->login_session.id[0])
-                       lwsgs_get_sid_from_wsi(wsi, &pss->login_session);
-
-               if (!pss->login_session.id[0] && !pss->logging_out) {
-
-                       pss->login_expires = lws_now_secs() +
-                                            vhd->timeout_anon_absolute_secs;
-                       if (lwsgs_new_session_id(vhd, &pss->login_session, "",
-                                                pss->login_expires))
-                               goto try_to_reuse;
-                       pc = cookie;
-                       lwsgw_cookie_from_session(&pss->login_session,
-                                                 pss->login_expires, &pc,
-                                                 cookie + sizeof(cookie) - 1);
-
-                       lwsl_info("LWS_CALLBACK_ADD_HEADERS: setting cookie '%s'\n", cookie);
-                       if (lws_add_http_header_by_name(wsi,
-                                       (unsigned char *)"set-cookie:",
-                                       (unsigned char *)cookie, pc - cookie,
-                                       (unsigned char **)&args->p,
-                                       (unsigned char *)args->p + args->max_len))
-                               return 1;
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-
-redirect_with_cookie:
-       p = buffer + LWS_PRE;
-       start = p;
-       end = p + sizeof(buffer) - LWS_PRE;
-
-       lwsl_warn("%s: redirect_with_cookie\n", __func__);
-
-       if (lws_add_http_header_status(wsi, HTTP_STATUS_SEE_OTHER, &p, end))
-               return 1;
-
-       {
-               char loc[1024], uria[128];
-
-               uria[0] = '\0';
-               lws_hdr_copy_fragment(wsi, uria, sizeof(uria),
-                                         WSI_TOKEN_HTTP_URI_ARGS, 0);
-               n = lws_snprintf(loc, sizeof(loc), "%s?%s",
-                               pss->onward, uria);
-               lwsl_notice("%s: redirect to '%s'\n", __func__, loc);
-               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION,
-                               (unsigned char *)loc, n, &p, end))
-                       return 1;
-       }
-
-       if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
-                       (unsigned char *)"text/html", 9, &p, end))
-               return 1;
-       if (lws_add_http_header_content_length(wsi, 0, &p, end))
-               return 1;
-
-       if (pss->delete_session.id[0]) {
-               lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
-                                         cookie + sizeof(cookie) - 1);
-
-               lwsl_notice("deleting cookie '%s'\n", cookie);
-
-               if (lws_add_http_header_by_name(wsi,
-                               (unsigned char *)"set-cookie:",
-                               (unsigned char *)cookie, pc - cookie,
-                               &p, end)) {
-                       lwsl_err("fail0\n");
-                       return 1;
-               }
-       }
-
-       if (!pss->login_session.id[0]) {
-               pss->login_expires = lws_now_secs() +
-                                    vhd->timeout_anon_absolute_secs;
-               if (lwsgs_new_session_id(vhd, &pss->login_session, "",
-                                        pss->login_expires)) {
-                       lwsl_err("fail1\n");
-                       return 1;
-               }
-       } else
-               pss->login_expires = lws_now_secs() +
-                                    vhd->timeout_absolute_secs;
-
-       if (pss->login_session.id[0] || pss->logging_out) {
-               /*
-                * we succeeded to login, we must issue a login
-                * cookie with the prepared data
-                */
-               pc = cookie;
-
-               lwsgw_cookie_from_session(&pss->login_session,
-                                         pss->login_expires, &pc,
-                                         cookie + sizeof(cookie) - 1);
-
-               lwsl_err("%s: setting cookie '%s'\n", __func__, cookie);
-
-               pss->logging_out = 0;
-
-               if (lws_add_http_header_by_name(wsi,
-                               (unsigned char *)"set-cookie:",
-                               (unsigned char *)cookie, pc - cookie,
-                               &p, end)) {
-                       lwsl_err("fail2\n");
-                       return 1;
-               }
-       }
-
-       if (lws_finalize_http_header(wsi, &p, end))
-               return 1;
-
-       // lwsl_hexdump_notice(start, p - start);
-
-       n = lws_write(wsi, start, p - start, LWS_WRITE_H2_STREAM_END |
-                                            LWS_WRITE_HTTP_HEADERS);
-       if (n < 0)
-               return 1;
-
-       /* fallthru */
-
-try_to_reuse:
-       if (lws_http_transaction_completed(wsi))
-               return -1;
-
-       return 0;
-}
-
-static const struct lws_protocols protocols[] = {
-       {
-               "protocol-generic-sessions",
-               callback_generic_sessions,
-               sizeof(struct per_session_data__gs),
-               1024,
-       },
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_generic_sessions(struct lws_context *context,
-                       struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_generic_sessions(struct lws_context *context)
-{
-       return 0;
-}
diff --git a/plugins/generic-sessions/protocol_lws_messageboard.c b/plugins/generic-sessions/protocol_lws_messageboard.c
deleted file mode 100644 (file)
index 4fb973f..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * ws protocol handler plugin for messageboard "generic sessions" demo
- *
- * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library 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 library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301  USA
- */
-
-#define LWS_DLL
-#define LWS_INTERNAL
-#include <libwebsockets.h>
-
-#include <sqlite3.h>
-#include <string.h>
-#include <stdlib.h>
-
-struct per_vhost_data__gs_mb {
-       struct lws_vhost *vh;
-       const struct lws_protocols *gsp;
-       sqlite3 *pdb;
-       char message_db[256];
-       unsigned long last_idx;
-};
-
-struct per_session_data__gs_mb {
-       void *pss_gs; /* for use by generic-sessions */
-       struct lws_session_info sinfo;
-       struct lws_spa *spa;
-       unsigned long last_idx;
-       unsigned int our_form:1;
-       char second_http_part;
-};
-
-static const char * const param_names[] = {
-       "send",
-       "msg",
-};
-enum {
-       MBSPA_SUBMIT,
-       MBSPA_MSG,
-};
-
-#define MAX_MSG_LEN 512
-
-struct message {
-       unsigned long idx;
-       unsigned long time;
-       char username[32];
-       char email[100];
-       char ip[72];
-       char content[MAX_MSG_LEN];
-};
-
-static int
-lookup_cb(void *priv, int cols, char **col_val, char **col_name)
-{
-       struct message *m = (struct message *)priv;
-       int n;
-
-       for (n = 0; n < cols; n++) {
-
-               if (!strcmp(col_name[n], "idx") ||
-                   !strcmp(col_name[n], "MAX(idx)")) {
-                       if (!col_val[n])
-                               m->idx = 0;
-                       else
-                               m->idx = atol(col_val[n]);
-                       continue;
-               }
-               if (!strcmp(col_name[n], "time")) {
-                       m->time = atol(col_val[n]);
-                       continue;
-               }
-               if (!strcmp(col_name[n], "username")) {
-                       lws_strncpy(m->username, col_val[n], sizeof(m->username));
-                       continue;
-               }
-               if (!strcmp(col_name[n], "email")) {
-                       lws_strncpy(m->email, col_val[n], sizeof(m->email));
-                       continue;
-               }
-               if (!strcmp(col_name[n], "ip")) {
-                       lws_strncpy(m->ip, col_val[n], sizeof(m->ip));
-                       continue;
-               }
-               if (!strcmp(col_name[n], "content")) {
-                       lws_strncpy(m->content, col_val[n], sizeof(m->content));
-                       continue;
-               }
-       }
-       return 0;
-}
-
-static unsigned long
-get_last_idx(struct per_vhost_data__gs_mb *vhd)
-{
-       struct message m;
-
-       if (sqlite3_exec(vhd->pdb, "SELECT MAX(idx) FROM msg;",
-                        lookup_cb, &m, NULL) != SQLITE_OK) {
-               lwsl_err("Unable to lookup token: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               return 0;
-       }
-
-       return m.idx;
-}
-
-static int
-post_message(struct lws *wsi, struct per_vhost_data__gs_mb *vhd,
-            struct per_session_data__gs_mb *pss)
-{
-       struct lws_session_info sinfo;
-       char s[MAX_MSG_LEN + 512];
-       char esc[MAX_MSG_LEN + 256];
-
-       vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO,
-                          pss->pss_gs, &sinfo, 0);
-
-       lws_snprintf((char *)s, sizeof(s) - 1,
-                "insert into msg(time, username, email, ip, content)"
-                " values (%lu, '%s', '%s', '%s', '%s');",
-                (unsigned long)lws_now_secs(), sinfo.username, sinfo.email, sinfo.ip,
-                lws_sql_purify(esc, lws_spa_get_string(pss->spa, MBSPA_MSG),
-                               sizeof(esc) - 1));
-       if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
-               lwsl_err("Unable to insert msg: %s\n", sqlite3_errmsg(vhd->pdb));
-               return 1;
-       }
-       vhd->last_idx = get_last_idx(vhd);
-
-       /* let everybody connected by this protocol on this vhost know */
-       lws_callback_on_writable_all_protocol_vhost(lws_get_vhost(wsi),
-                                                   lws_get_protocol(wsi));
-
-       return 0;
-}
-
-static int
-callback_messageboard(struct lws *wsi, enum lws_callback_reasons reason,
-                     void *user, void *in, size_t len)
-{
-       struct per_session_data__gs_mb *pss = (struct per_session_data__gs_mb *)user;
-       const struct lws_protocol_vhost_options *pvo;
-       struct per_vhost_data__gs_mb *vhd = (struct per_vhost_data__gs_mb *)
-               lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi));
-       unsigned char *p, *start, *end, buffer[LWS_PRE + 4096];
-       char s[512];
-       int n;
-
-       switch (reason) {
-       case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
-
-               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
-                       lws_get_protocol(wsi), sizeof(struct per_vhost_data__gs_mb));
-               if (!vhd)
-                       return 1;
-               vhd->vh = lws_get_vhost(wsi);
-               vhd->gsp = lws_vhost_name_to_protocol(vhd->vh,
-                                               "protocol-generic-sessions");
-               if (!vhd->gsp) {
-                       lwsl_err("messageboard: requires generic-sessions\n");
-                       return 1;
-               }
-
-               pvo = (const struct lws_protocol_vhost_options *)in;
-               while (pvo) {
-                       if (!strcmp(pvo->name, "message-db"))
-                               strncpy(vhd->message_db, pvo->value,
-                                       sizeof(vhd->message_db) - 1);
-                       pvo = pvo->next;
-               }
-               if (!vhd->message_db[0]) {
-                       lwsl_err("messageboard: \"message-db\" pvo missing\n");
-                       return 1;
-               }
-
-               if (lws_struct_sq3_open(lws_get_context(wsi),
-                                       vhd->message_db, &vhd->pdb)) {
-                       lwsl_err("Unable to open message db %s: %s\n",
-                                vhd->message_db, sqlite3_errmsg(vhd->pdb));
-
-                       return 1;
-               }
-               if (sqlite3_exec(vhd->pdb, "create table if not exists msg ("
-                                " idx integer primary key, time integer,"
-                                " username varchar(32), email varchar(100),"
-                                " ip varchar(80), content blob);",
-                                NULL, NULL, NULL) != SQLITE_OK) {
-                       lwsl_err("Unable to create msg table: %s\n",
-                                sqlite3_errmsg(vhd->pdb));
-
-                       return 1;
-               }
-
-               vhd->last_idx = get_last_idx(vhd);
-               break;
-
-       case LWS_CALLBACK_PROTOCOL_DESTROY:
-               if (vhd && vhd->pdb)
-                       sqlite3_close(vhd->pdb);
-               goto passthru;
-
-       case LWS_CALLBACK_ESTABLISHED:
-               vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO,
-                                  pss->pss_gs, &pss->sinfo, 0);
-               if (!pss->sinfo.username[0]) {
-                       lwsl_notice("messageboard ws attempt with no session\n");
-
-                       return -1;
-               }
-
-               lws_callback_on_writable(wsi);
-               break;
-
-       case LWS_CALLBACK_CLOSED:
-               lwsl_debug("%s: LWS_CALLBACK_CLOSED\n", __func__);
-               if (pss && pss->pss_gs) {
-                       free(pss->pss_gs);
-                       pss->pss_gs = NULL;
-               }
-               break;
-
-       case LWS_CALLBACK_SERVER_WRITEABLE:
-               {
-                       struct message m;
-                       char j[MAX_MSG_LEN + 512], e[MAX_MSG_LEN + 512],
-                               *p = j + LWS_PRE, *start = p,
-                               *end = j + sizeof(j) - LWS_PRE;
-
-                       if (pss->last_idx == vhd->last_idx)
-                               break;
-
-                       /* restrict to last 10 */
-                       if (!pss->last_idx)
-                               if (vhd->last_idx >= 10)
-                                       pss->last_idx = vhd->last_idx - 10;
-
-                       sprintf(s, "select idx, time, username, email, ip, content "
-                                  "from msg where idx > %lu order by idx limit 1;",
-                                  pss->last_idx);
-                       if (sqlite3_exec(vhd->pdb, s, lookup_cb, &m, NULL) != SQLITE_OK) {
-                               lwsl_err("Unable to lookup msg: %s\n",
-                                        sqlite3_errmsg(vhd->pdb));
-                               return 0;
-                       }
-
-                       /* format in JSON */
-                       p += lws_snprintf(p, end - p,
-                                       "{\"idx\":\"%lu\",\"time\":\"%lu\",",
-                                       m.idx, m.time);
-                       p += lws_snprintf(p, end - p, " \"username\":\"%s\",",
-                               lws_json_purify(e, m.username, sizeof(e)));
-                       p += lws_snprintf(p, end - p, " \"email\":\"%s\",",
-                               lws_json_purify(e, m.email, sizeof(e)));
-                       p += lws_snprintf(p, end - p, " \"ip\":\"%s\",",
-                               lws_json_purify(e, m.ip, sizeof(e)));
-                       p += lws_snprintf(p, end - p, " \"content\":\"%s\"}",
-                               lws_json_purify(e, m.content, sizeof(e)));
-
-                       if (lws_write(wsi, (unsigned char *)start, p - start,
-                                     LWS_WRITE_TEXT) < 0)
-                               return -1;
-
-                       pss->last_idx = m.idx;
-                       if (pss->last_idx == vhd->last_idx)
-                               break;
-
-                       lws_callback_on_writable(wsi); /* more to do */
-               }
-               break;
-
-       case LWS_CALLBACK_HTTP:
-               pss->our_form = 0;
-
-               /* ie, it's our messageboard new message form */
-               if (!strcmp((const char *)in, "/msg") ||
-                   !strcmp((const char *)in, "msg")) {
-                       pss->our_form = 1;
-                       break;
-               }
-
-               goto passthru;
-
-       case LWS_CALLBACK_HTTP_BODY:
-               if (!pss->our_form)
-                       goto passthru;
-
-               if (len < 2)
-                       break;
-               if (!pss->spa) {
-                       pss->spa = lws_spa_create(wsi, param_names,
-                                       LWS_ARRAY_SIZE(param_names),
-                                               MAX_MSG_LEN + 1024, NULL, NULL);
-                       if (!pss->spa)
-                               return -1;
-               }
-
-               if (lws_spa_process(pss->spa, in, len)) {
-                       lwsl_notice("spa process blew\n");
-                       return -1;
-               }
-               break;
-
-       case LWS_CALLBACK_HTTP_WRITEABLE:
-               if (!pss->second_http_part)
-                       goto passthru;
-
-               s[0] = '0';
-               n = lws_write(wsi, (unsigned char *)s, 1, LWS_WRITE_HTTP|
-                               LWS_WRITE_H2_STREAM_END);
-               if (n != 1)
-                       return -1;
-
-               goto try_to_reuse;
-
-       case LWS_CALLBACK_HTTP_BODY_COMPLETION:
-               if (!pss->our_form)
-                       goto passthru;
-
-               if (post_message(wsi, vhd, pss))
-                       return -1;
-
-               p = buffer + LWS_PRE;
-               start = p;
-               end = p + sizeof(buffer) - LWS_PRE;
-
-               if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
-                       return -1;
-               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
-                               (unsigned char *)"text/plain", 10, &p, end))
-                       return -1;
-               if (lws_add_http_header_content_length(wsi, 1, &p, end))
-                       return -1;
-               if (lws_finalize_http_header(wsi, &p, end))
-                       return -1;
-
-               n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
-               if (n != (p - start)) {
-                       lwsl_err("_write returned %d from %ld\n", n, (long)(p - start));
-                       return -1;
-               }
-               pss->second_http_part = 1;
-               lws_callback_on_writable(wsi);
-               break;
-
-       case LWS_CALLBACK_HTTP_BIND_PROTOCOL:
-               if (!pss || !vhd || pss->pss_gs)
-                       break;
-
-               pss->pss_gs = malloc(vhd->gsp->per_session_data_size);
-               if (!pss->pss_gs)
-                       return -1;
-
-               memset(pss->pss_gs, 0, vhd->gsp->per_session_data_size);
-               break;
-
-       case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
-               if (vhd->gsp->callback(wsi, reason, pss ? pss->pss_gs : NULL, in, len))
-                       return -1;
-
-               if (pss && pss->spa) {
-                       lws_spa_destroy(pss->spa);
-                       pss->spa = NULL;
-               }
-               if (pss && pss->pss_gs) {
-                       free(pss->pss_gs);
-                       pss->pss_gs = NULL;
-               }
-               break;
-
-       default:
-passthru:
-               if (!pss || !vhd)
-                       break;
-
-               return vhd->gsp->callback(wsi, reason, pss->pss_gs, in, len);
-       }
-
-       return 0;
-
-
-try_to_reuse:
-       if (lws_http_transaction_completed(wsi))
-               return -1;
-
-       return 0;
-}
-
-static const struct lws_protocols protocols[] = {
-       {
-               "protocol-lws-messageboard",
-               callback_messageboard,
-               sizeof(struct per_session_data__gs_mb),
-               4096,
-       },
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_lws_messageboard(struct lws_context *context,
-                              struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_lws_messageboard(struct lws_context *context)
-{
-       return 0;
-}
diff --git a/plugins/generic-sessions/utils.c b/plugins/generic-sessions/utils.c
deleted file mode 100644 (file)
index 0b8959b..0000000
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * ws protocol handler plugin for "generic sessions"
- *
- * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library 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 library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301  USA
- */
-
-#include "private-lwsgs.h"
-#include <stdlib.h>
-
-void
-sha256_to_lwsgw_hash(unsigned char *hash, lwsgw_hash *shash)
-{
-       static const char *hex = "0123456789abcdef";
-       char *p = shash->id;
-       int n;
-
-       for (n = 0; n < (int)lws_genhash_size(LWS_GENHASH_TYPE_SHA256); n++) {
-               *p++ = hex[(hash[n] >> 4) & 0xf];
-               *p++ = hex[hash[n] & 15];
-       }
-
-       *p = '\0';
-}
-
-int
-lwsgw_check_admin(struct per_vhost_data__gs *vhd,
-                 const char *username, const char *password)
-{
-       lwsgw_hash_bin hash_bin;
-       lwsgw_hash pw_hash;
-
-       if (strcmp(vhd->admin_user, username))
-               return 0;
-
-       lws_SHA1((unsigned char *)password, strlen(password), hash_bin.bin);
-       sha256_to_lwsgw_hash(hash_bin.bin, &pw_hash);
-
-       return !strcmp(vhd->admin_password_sha256.id, pw_hash.id);
-}
-
-/*
- * secure cookie: it can only be passed over https where it cannot be
- *               snooped in transit
- * HttpOnly:     it can only be accessed via http[s] transport, it cannot be
- *               gotten at by JS
- */
-void
-lwsgw_cookie_from_session(lwsgw_hash *sid, time_t expires, char **p, char *end)
-{
-       struct tm *tm = gmtime(&expires);
-       time_t n = lws_now_secs();
-
-       *p += lws_snprintf(*p, end - *p, "id=%s;Expires=", sid->id);
-#ifdef WIN32
-       *p += strftime(*p, end - *p, "%Y %H:%M %Z", tm);
-#else
-       *p += strftime(*p, end - *p, "%F %H:%M %Z", tm);
-#endif
-       *p += lws_snprintf(*p, end - *p, ";path=/");
-       *p += lws_snprintf(*p, end - *p, ";Max-Age=%lu", (unsigned long)(expires - n));
-//     *p += lws_snprintf(*p, end - *p, ";secure");
-       *p += lws_snprintf(*p, end - *p, ";HttpOnly");
-}
-
-int
-lwsgw_expire_old_sessions(struct per_vhost_data__gs *vhd)
-{
-       time_t n = lws_now_secs();
-       char s[200];
-
-       if (n - vhd->last_session_expire < 5)
-               return 0;
-
-       vhd->last_session_expire = n;
-
-       lws_snprintf(s, sizeof(s) - 1,
-                "delete from sessions where "
-                "expire <= %lu;", (unsigned long)n);
-
-       if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
-               lwsl_err("Unable to expire sessions: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               return 1;
-       }
-
-       return 0;
-}
-
-int
-lwsgw_update_session(struct per_vhost_data__gs *vhd,
-                    lwsgw_hash *hash, const char *user)
-{
-       time_t n = lws_now_secs();
-       char s[200], esc[96], esc1[96];
-
-       if (user[0])
-               n += vhd->timeout_absolute_secs;
-       else
-               n += vhd->timeout_anon_absolute_secs;
-
-       lws_snprintf(s, sizeof(s) - 1,
-                "update sessions set expire=%lu,username='%s' where name='%s';",
-                (unsigned long)n,
-                lws_sql_purify(esc, user, sizeof(esc)),
-                lws_sql_purify(esc1, hash->id, sizeof(esc1)));
-
-       if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
-               lwsl_err("Unable to update session: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-               return 1;
-       }
-
-       puts(s);
-
-       return 0;
-}
-
-static int
-lwsgw_session_from_cookie(const char *cookie, lwsgw_hash *sid)
-{
-       const char *p = cookie;
-       int n;
-
-       while (*p) {
-               if (p[0] == 'i' && p[1] == 'd' && p[2] == '=') {
-                       p += 3;
-                       break;
-               }
-               p++;
-       }
-       if (!*p) {
-               lwsl_info("no id= in cookie\n");
-               return 1;
-       }
-
-       for (n = 0; n < (int)sizeof(sid->id) - 1 && *p; n++) {
-               /* our SID we issue only has these chars */
-               if ((*p >= '0' && *p <= '9') ||
-                   (*p >= 'a' && *p <= 'f'))
-                       sid->id[n] = *p++;
-               else {
-                       lwsl_info("bad chars in cookie id %c\n", *p);
-                       return 1;
-               }
-       }
-
-       if (n < (int)sizeof(sid->id) - 1) {
-               lwsl_info("cookie id too short\n");
-               return 1;
-       }
-
-       sid->id[sizeof(sid->id) - 1] = '\0';
-
-       return 0;
-}
-
-int
-lwsgs_get_sid_from_wsi(struct lws *wsi, lwsgw_hash *sid)
-{
-       char cookie[1024];
-
-       /* fail it on no cookie */
-       if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
-               lwsl_info("%s: no cookie\n", __func__);
-               return 1;
-       }
-       if (lws_hdr_copy(wsi, cookie, sizeof cookie, WSI_TOKEN_HTTP_COOKIE) < 0) {
-               lwsl_info("cookie copy failed\n");
-               return 1;
-       }
-       /* extract the sid from the cookie */
-       if (lwsgw_session_from_cookie(cookie, sid)) {
-               lwsl_info("%s: session from cookie failed\n", __func__);
-               return 1;
-       }
-
-       return 0;
-}
-
-struct lla {
-       char *username;
-       int len;
-       int results;
-};
-
-static int
-lwsgs_lookup_callback(void *priv, int cols, char **col_val, char **col_name)
-{
-       struct lla *lla = (struct lla *)priv;
-
-       //lwsl_err("%s: %d\n", __func__, cols);
-
-       if (cols)
-               lla->results = 0;
-       if (col_val && col_val[0]) {
-               lws_strncpy(lla->username, col_val[0], lla->len + 1);
-               lwsl_info("%s: %s\n", __func__, lla->username);
-       }
-
-       return 0;
-}
-
-int
-lwsgs_lookup_session(struct per_vhost_data__gs *vhd,
-                    const lwsgw_hash *sid, char *username, int len)
-{
-       struct lla lla = { username, len, 1 };
-       char s[150], esc[96];
-
-       lwsgw_expire_old_sessions(vhd);
-
-       lws_snprintf(s, sizeof(s) - 1,
-                "select username from sessions where name = '%s';",
-                lws_sql_purify(esc, sid->id, sizeof(esc) - 1));
-
-       if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback, &lla, NULL) != SQLITE_OK) {
-               lwsl_err("Unable to create user table: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-
-               return 1;
-       }
-
-       /* 0 if found */
-       return lla.results;
-}
-
-int
-lwsgs_lookup_callback_user(void *priv, int cols, char **col_val, char **col_name)
-{
-       struct lwsgs_user *u = (struct lwsgs_user *)priv;
-       int n;
-
-       for (n = 0; n < cols; n++) {
-               if (!strcmp(col_name[n], "username")) {
-                       lws_strncpy(u->username, col_val[n], sizeof(u->username));
-                       continue;
-               }
-               if (!strcmp(col_name[n], "ip")) {
-                       lws_strncpy(u->ip, col_val[n], sizeof(u->ip));
-                       continue;
-               }
-               if (!strcmp(col_name[n], "creation_time")) {
-                       u->created = atol(col_val[n]);
-                       continue;
-               }
-               if (!strcmp(col_name[n], "last_forgot_validated")) {
-                       if (col_val[n])
-                               u->last_forgot_validated = atol(col_val[n]);
-                       else
-                               u->last_forgot_validated = 0;
-                       continue;
-               }
-               if (!strcmp(col_name[n], "email")) {
-                       lws_strncpy(u->email, col_val[n], sizeof(u->email));
-                       continue;
-               }
-               if (!strcmp(col_name[n], "verified")) {
-                       u->verified = atoi(col_val[n]);
-                       continue;
-               }
-               if (!strcmp(col_name[n], "pwhash")) {
-                       lws_strncpy(u->pwhash.id, col_val[n], sizeof(u->pwhash.id));
-                       continue;
-               }
-               if (!strcmp(col_name[n], "pwsalt")) {
-                       lws_strncpy(u->pwsalt.id, col_val[n], sizeof(u->pwsalt.id));
-                       continue;
-               }
-               if (!strcmp(col_name[n], "token")) {
-                       lws_strncpy(u->token.id, col_val[n], sizeof(u->token.id));
-                       continue;
-               }
-       }
-       return 0;
-}
-
-int
-lwsgs_lookup_user(struct per_vhost_data__gs *vhd,
-                 const char *username, struct lwsgs_user *u)
-{
-       char s[150], esc[96];
-
-       u->username[0] = '\0';
-       lws_snprintf(s, sizeof(s) - 1,
-                "select username,creation_time,ip,email,verified,pwhash,pwsalt,last_forgot_validated "
-                "from users where username = '%s';",
-                lws_sql_purify(esc, username, sizeof(esc) - 1));
-
-       if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, u, NULL) !=
-           SQLITE_OK) {
-               lwsl_err("Unable to lookup user: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-
-               return -1;
-       }
-
-       return !u->username[0];
-}
-
-int
-lwsgs_new_session_id(struct per_vhost_data__gs *vhd,
-                    lwsgw_hash *sid, const char *username, int exp)
-{
-       unsigned char sid_rand[32];
-       const char *u;
-       char s[300], esc[96], esc1[96];
-
-       if (username)
-               u = username;
-       else
-               u = "";
-
-       if (!sid) {
-               lwsl_err("%s: NULL sid\n", __func__);
-               return 1;
-       }
-
-       memset(sid, 0, sizeof(*sid));
-
-       if (lws_get_random(vhd->context, sid_rand, sizeof(sid_rand)) !=
-                          sizeof(sid_rand))
-               return 1;
-
-       sha256_to_lwsgw_hash(sid_rand, sid);
-
-       lws_snprintf(s, sizeof(s) - 1,
-                "insert into sessions(name, username, expire) "
-                "values ('%s', '%s', %u);",
-                lws_sql_purify(esc, sid->id, sizeof(esc) - 1),
-                lws_sql_purify(esc1, u, sizeof(esc1) - 1), exp);
-
-       if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
-               lwsl_err("Unable to insert session: %s\n",
-                        sqlite3_errmsg(vhd->pdb));
-
-               return 1;
-       }
-
-       lwsl_notice("%s: created session %s\n", __func__, sid->id);
-
-       return 0;
-}
-
-int
-lwsgs_get_auth_level(struct per_vhost_data__gs *vhd, const char *username)
-{
-       struct lwsgs_user u;
-       int n = 0;
-
-       /* we are logged in as some kind of user */
-       if (username[0]) {
-               /* we are logged in as admin */
-               if (!strcmp(username, vhd->admin_user))
-                       /* automatically verified */
-                       n |= LWSGS_AUTH_VERIFIED | LWSGS_AUTH_ADMIN;
-       }
-
-       if (!lwsgs_lookup_user(vhd, username, &u)) {
-               if ((u.verified & 0xff) == LWSGS_VERIFIED_ACCEPTED)
-                       n |= LWSGS_AUTH_LOGGED_IN | LWSGS_AUTH_VERIFIED;
-
-               if (u.last_forgot_validated > (time_t)lws_now_secs() - 300)
-                       n |= LWSGS_AUTH_FORGOT_FLOW;
-       }
-
-       return n;
-}
-
-int
-lwsgs_check_credentials(struct per_vhost_data__gs *vhd,
-                       const char *username, const char *password)
-{
-       struct lws_genhash_ctx hash_ctx;
-       lwsgw_hash_bin hash_bin;
-       struct lwsgs_user u;
-       lwsgw_hash hash;
-
-       if (lwsgs_lookup_user(vhd, username, &u))
-               return -1;
-
-       lwsl_info("user %s found, salt '%s'\n", username, u.pwsalt.id);
-
-       /* sha256sum of password + salt */
-
-       if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256) ||
-           lws_genhash_update(&hash_ctx, password, strlen(password)) ||
-           lws_genhash_update(&hash_ctx, "-", 1) ||
-           lws_genhash_update(&hash_ctx, vhd->confounder, strlen(vhd->confounder)) ||
-           lws_genhash_update(&hash_ctx, "-", 1) ||
-           lws_genhash_update(&hash_ctx, u.pwsalt.id, strlen(u.pwsalt.id)) ||
-           lws_genhash_destroy(&hash_ctx, hash_bin.bin)) {
-               lws_genhash_destroy(&hash_ctx, NULL);
-
-               return 1;
-       }
-
-       sha256_to_lwsgw_hash(&hash_bin.bin[0], &hash);
-
-       return !!strcmp(hash.id, u.pwhash.id);
-}
-
-/* sets u->pwsalt and u->pwhash */
-
-int
-lwsgs_hash_password(struct per_vhost_data__gs *vhd,
-                   const char *password, struct lwsgs_user *u)
-{
-       unsigned char sid_rand[32];
-       struct lws_genhash_ctx hash_ctx;
-       lwsgw_hash_bin hash_bin;
-
-       /* create a random salt as big as the hash */
-
-       if (lws_get_random(vhd->context, sid_rand,
-                          sizeof(sid_rand)) !=
-                          sizeof(sid_rand)) {
-               lwsl_err("Problem getting random for salt\n");
-               return 1;
-       }
-       sha256_to_lwsgw_hash(sid_rand, &u->pwsalt);
-/*
-       if (lws_get_random(vhd->context, sid_rand,
-                          sizeof(sid_rand)) !=
-                          sizeof(sid_rand)) {
-               lwsl_err("Problem getting random for token\n");
-               return 1;
-       }
-       sha256_to_lwsgw_hash(sid_rand, &hash);
-*/
-       /* sha256sum of password + salt */
-
-       if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256) ||
-           lws_genhash_update(&hash_ctx, password, strlen(password)) ||
-           lws_genhash_update(&hash_ctx, "-", 1) ||
-           lws_genhash_update(&hash_ctx, vhd->confounder, strlen(vhd->confounder)) ||
-           lws_genhash_update(&hash_ctx, "-", 1) ||
-           lws_genhash_update(&hash_ctx, u->pwsalt.id, strlen(u->pwsalt.id)) ||
-           lws_genhash_destroy(&hash_ctx, hash_bin.bin)) {
-               lws_genhash_destroy(&hash_ctx, NULL);
-
-               return 1;
-       }
-
-       sha256_to_lwsgw_hash(&hash_bin.bin[0], &u->pwhash);
-
-       return 0;
-}
diff --git a/plugins/generic-table/assets/index.html b/plugins/generic-table/assets/index.html
deleted file mode 100644 (file)
index 635d02a..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<html>
- <head>
-  <script src="/lws-common.js"></script>
-  <script src="lwsgt.js"></script>
-  <style>
-       .body { font-size: 12 }
-       .gstitle { font-size: 24; text-align:center }
-       .group1 { vertical-align:middle;text-align:center;background:#f0f0e0; 
-               padding:12px; -webkit-border-radius:10px; 
-               -moz-border-radius:10px;border-radius:10px; }
-       .group2 { vertical-align:middle; font-size: 18;text-align:center;
-               margin:auto; align:center;
-               background-color: rgba(255, 255, 255, 0.8); padding:12px;
-               display:inline-block; -webkit-border-radius:10px; 
-               -moz-border-radius:10px; border-radius:10px; }
-
-       .lwsgt_title { font-size: 24; text-align:center }
-       .lwsgt_breadcrumbs { font-size: 18; text-align:left }
-       .lwsgt_table { font-size: 14; padding:12px; margin: 12px; align:center }
-       .lwsgt_hdr { font-size: 18; text-align:center;
-                    background-color: rgba(40, 40, 40, 0.8); color: white }
-       .lwsgt_tr { padding: 10px  }
-       .lwsgt_td { padding: 3px  }
-  </style>
-  </head>
-  <body>
-       <table>
-               <tr><td class="gstitle">
-                LWS Generic Table demo
-               </td></tr>
-               <tr><td class="group2">
-               This is a demo of lws generic table, using a protocol plugin
-               "protocol-lws-table-dirlisting".  It shows a directory listing,
-               but unlike an oldstyle directory listing done on the
-               server side with a script, this is static html that connects
-               back to the server with a websocket, and gets live JSON from
-               that.
-               <p>
-               Actually the static html is extremely simple, since it uses
-               lwsgt, LWS Generic Table, JS include on the client-side that
-               handles all the table generation from a template sent in JSON
-               over the ws link.   It means there is no custom JS required
-               clientside either.  It's just CSS, this text and a call to
-               initialize lwsgt with the appropriate ws protocol.
-               </td></tr>
-               <tr><td><div id="lwsgt1" class="group1"></div></td></tr>
-               <tr><td class="group2">
-               There's no problem having multiple independent instances per
-               page...
-               </td></tr>
-               <tr><td><div id="lwsgt2" class="group1"></div></td></tr>
-        </table>
-       <div id="debug"></div>
-
-  <script nonce="lwscaro">
-       var v1 = new lwsgt_initial("Dir listing demo",
-                                  "protocol-lws-table-dirlisting",
-                                  "lwsgt1", "lwsgt_dir_click", "v1");
-       var v2 = new lwsgt_initial("Dir listing 2",
-                                  "protocol-lws-table-dirlisting",
-                                  "lwsgt2", "lwsgt_dir_click", "v2");
-       
-function lwsgt_dir_click(gt, u, col, row)
-{
-       if (u[0] == '=') { /* change directory */
-               window[gt].lwsgt_ws.send(u.substring(1, u.length));
-               return;
-       }
-       var win = window.open(u, '_blank');
-       win.focus();
-}
-
-  </script>
- </body>
-</html>
diff --git a/plugins/generic-table/assets/lwsgt.js b/plugins/generic-table/assets/lwsgt.js
deleted file mode 100644 (file)
index dc93895..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-function lwsgt_get_appropriate_ws_url()
-{
-       var pcol;
-       var u = document.URL;
-
-       if (u.substring(0, 5) === "https") {
-               pcol = "wss://";
-               u = u.substr(8);
-       } else {
-               pcol = "ws://";
-               if (u.substring(0, 4) === "http")
-                       u = u.substr(7);
-       }
-
-       return pcol + u;
-}
-
-function lwsgt_app_hdr(j, bc, ws)
-{
-       var s = "", n, m = 0;
-
-       ws.bcq = 0;
-                                       
-       for (n = 0; n < j.cols.length; n++)
-               if (!j.cols[n].hide)
-                       m++;
-
-       s = "<tr><td colspan=\"" + m + "\" class=\"lwsgt_title\">" +
-               ws.lwsgt_title + "</td></tr>";
-
-       if (!!bc) {
-               s += "<tr><td colspan=\"" + m + "\" class=\"lwsgt_breadcrumbs\">";
-               for (n = 0; n < bc.length; n++) {
-                       s += " / ";
-                       if (!bc[n].url && bc[n].url !== "")
-                               s += " " + lws_san(bc[n].name) + " ";
-                       else {
-                               s += "<a href=# id=\"bc_"+ ws.divname + ws.bcq + "\" h=\"" +
-                                   ws.lwsgt_cb + "\" p=\""+ws.lwsgt_parent+"\" aa=\"="+
-                                       lws_san(encodeURI(bc[n].url))+"\" m=\"-1\" n=\"-1\">" +
-                                       lws_san(bc[n].name) + "</a> ";
-                               ws.bcq++;
-                       }
-               }
-               s += "</td></tr>";
-       }
-       s += "<tr>";
-       for (n = 0; n < j.cols.length; n++)
-               if (!j.cols[n].hide)
-                       s = s + "<td class=\"lwsgt_hdr\">" + lws_san(j.cols[n].name) +
-                               "</td>";
-       
-       s += "</tr>";
-       
-       return s;
-}
-
-function lwsgt_click_callthru()
-{
-       window[this.getAttribute("h")](this.getAttribute("p"), this.getAttribute("aa"), this.getAttribute("m"), this.getAttribute("n"));
-       event.preventDefault();
-}
-
-function lwsgt_initial(title, pcol, divname, cb, gname)
-{
-       this.divname = divname;
-       
-       lws_gray_out(true,{"zindex":"499"});
-
-       if (typeof MozWebSocket != "undefined")
-               this.lwsgt_ws = new MozWebSocket(lwsgt_get_appropriate_ws_url(), pcol);
-       else
-               this.lwsgt_ws = new WebSocket(lwsgt_get_appropriate_ws_url(), pcol);
-       this.lwsgt_ws.divname = divname;
-       this.lwsgt_ws.lwsgt_cb = cb;
-       this.lwsgt_ws.lwsgt_parent = gname;
-       this.lwsgt_ws.lwsgt_title = title;
-       try {
-               this.lwsgt_ws.onopen = function() {
-                       lws_gray_out(false);
-               //      document.getElementById("debug").textContent =
-               //              "ws opened " + lwsgt_get_appropriate_ws_url();
-               };
-               this.lwsgt_ws.onmessage = function got_packet(msg) {
-                       var s, m, n, j = JSON.parse(msg.data);
-                       document.getElementById("debug").textContent = msg.data;
-                       if (j.cols) {
-                               this.hdr = j;
-                       }
-                       if (j.breadcrumbs) 
-                               this.breadcrumbs = j.breadcrumbs;
-
-                       if (j.data) {
-                               var q = 0;
-                               s = "<table class=\"lwsgt_table\">" +
-                                       lwsgt_app_hdr(this.hdr, this.breadcrumbs, this);
-                               for (m = 0; m < j.data.length; m++) {
-                                       s = s + "<tr class=\"lwsgt_tr\">";
-                                       for (n = 0; n < this.hdr.cols.length; n++) {
-                                               if (!this.hdr.cols[n].hide) {
-                                                       if (!this.hdr.cols[n].align)
-                                                               s = s + "<td class=\"lwsgt_td\">";
-                                                       else
-                                                               s = s + "<td class=\"lwsgt_td\" style=\"text-align: right\">";
-
-                                                       if (this.hdr.cols[n].href &&
-                                                           !!j.data[m][this.hdr.cols[n].href]) {
-                                                               s = s + "<a href=# id=\""+ this.divname + q + "\" h=\"" + this.lwsgt_cb + "\" p=\""+this.lwsgt_parent+"\" aa=\""+
-                                                                       lws_san(encodeURI(j.data[m][this.hdr.cols[n].href]))+"\" m=\""+m+"\" n=\""+n+"\">" +
-                                                                       lws_san(j.data[m][this.hdr.cols[n].name]) +
-                                                                       "</a>";
-                                                               q++;
-                                                       }
-                                                       else
-                                                               s = s + lws_san(j.data[m][this.hdr.cols[n].name]);
-                       
-                                                       s = s + "</td>";
-                                               }
-                                       }
-       
-                                       s = s + "</tr>";
-                               }
-                               s = s + "</table>";
-                               document.getElementById(this.divname).innerHTML = s;
-                               for (n = 0; n < q; n++)
-                                       document.getElementById(this.divname + n).onclick =
-                                               lwsgt_click_callthru;
-
-                               for (n = 0; n < this.bcq; n++)
-                                       document.getElementById("bc_" + this.divname + n).onclick =
-                                               lwsgt_click_callthru;
-
-                       }               
-               };
-               this.lwsgt_ws.onclose = function(){
-                       lws_gray_out(true,{"zindex":"499"});
-               };
-       } catch(exception) {
-               alert("<p>Error" + exception);  
-       }
-}
-
diff --git a/plugins/generic-table/protocol_table_dirlisting.c b/plugins/generic-table/protocol_table_dirlisting.c
deleted file mode 100644 (file)
index 026ae57..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * ws protocol handler plugin for dirlisting "generic table" demo
- *
- * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library 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 library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA  02110-1301  USA
- */
-
-#define LWS_DLL
-#define LWS_INTERNAL
-#include <libwebsockets.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <uv.h>
-
-struct fobj {
-       struct fobj *next;
-       const char *name, *uri, *icon, *date;
-       time_t m;
-       unsigned long size;
-};
-
-struct per_session_data__tbl_dir {
-       struct fobj base;
-       char strings[64 * 1024];
-       char reldir[256];
-       char *p;
-       const char *dir;
-
-#if UV_VERSION_MAJOR > 0
-       uv_fs_event_t *event_req;
-#endif
-       struct lws *wsi;
-};
-
-#if UV_VERSION_MAJOR > 0
-static void
-mon_cb(uv_fs_event_t *handle, const char *filename, int events, int status)
-{
-       struct per_session_data__tbl_dir *pss = handle->data;
-
-       //lwsl_notice("%s\n", __func__);
-
-       if (pss && pss->wsi)
-               lws_callback_on_writable(pss->wsi);
-}
-
-static void lws_uv_close_cb(uv_handle_t *handle)
-{
-       free(handle);
-}
-
-static void
-lws_protocol_dir_kill_monitor(struct per_session_data__tbl_dir *pss)
-{
-       if (!pss->event_req)
-               return;
-       pss->wsi = NULL;
-       pss->event_req->data = NULL;
-       uv_fs_event_stop(pss->event_req);
-       uv_close((uv_handle_t *)pss->event_req, lws_uv_close_cb);
-       pss->event_req = NULL;
-}
-#endif
-
-static int
-scan_dir(struct lws *wsi, struct per_session_data__tbl_dir *pss)
-{
-/* uuh travis... */
-#if UV_VERSION_MAJOR > 0
-       uv_loop_t *loop = lws_uv_getloop(lws_get_context(wsi), 0);
-       char *end = &(pss->strings[sizeof(pss->strings) - 1]);
-       struct fobj *prev = &pss->base;
-       char path[512], da[200];
-       const char *icon;
-       uv_dirent_t dent;
-       struct fobj *f;
-       struct stat st;
-       struct tm *tm;
-       int ret = 0, n;
-       uv_fs_t req;
-
-       lws_protocol_dir_kill_monitor(pss);
-
-       lws_snprintf(path, sizeof(path) - 1, "%s/%s", pss->dir, pss->reldir);
-       //lwsl_notice("path = %s\n", path);
-
-       pss->event_req = malloc(sizeof(*pss->event_req));
-       if (!pss->event_req)
-               return 2;
-
-       pss->wsi = wsi;
-       pss->event_req->data = pss;
-
-        uv_fs_event_init(lws_uv_getloop(lws_get_context(wsi), 0),
-                        pss->event_req);
-        // The recursive flag watches subdirectories too.
-        n = uv_fs_event_start(pss->event_req, mon_cb, path, UV_FS_EVENT_RECURSIVE);
-        //lwsl_notice("monitoring %s (%d)\n", path, n);
-
-       if (!uv_fs_scandir(loop, &req, path, 0, NULL)) {
-               lwsl_err("Scandir on %s failed\n", path);
-               return 2;
-       }
-
-       pss->p = pss->strings;
-
-       while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
-               lws_snprintf(path, sizeof(path) - 1, "%s/%s/%s", pss->dir, pss->reldir, dent.name);
-
-               if (stat(path, &st)) {
-                       lwsl_info("unable to stat %s\n", path);
-                       continue;
-               }
-               f = malloc(sizeof(*f));
-               f->next = NULL;
-               f->name = pss->p;
-               n = lws_snprintf(pss->p, end - pss->p, "%s", dent.name);
-               pss->p += n + 1;
-               f->uri = NULL;
-               if ((S_IFMT & st.st_mode) == S_IFDIR) {
-                       n = lws_snprintf(pss->p, end - pss->p, "=%s/%s", pss->reldir, dent.name);
-                       f->uri = pss->p;
-               }
-               if (lws_get_mimetype(dent.name, NULL)) {
-                       n = lws_snprintf(pss->p, end - pss->p, "./serve/%s/%s", pss->reldir, dent.name);
-                       f->uri = pss->p;
-               }
-               if (f->uri)
-                       pss->p += n + 1;
-
-               if (end - pss->p < 100) {
-                       free(f);
-                       break;
-               }
-
-               icon = " ";
-               if ((S_IFMT & st.st_mode) == S_IFDIR)
-                       icon = "&#x1f4c2;";
-
-               f->icon = pss->p;
-               n = lws_snprintf(pss->p, end - pss->p, "%s", icon);
-               pss->p += n + 1;
-
-               f->date = pss->p;
-               tm = gmtime(&st.st_mtime);
-               strftime(da, sizeof(da), "%Y-%b-%d %H:%M:%S %z", tm);
-               n = lws_snprintf(pss->p, end - pss->p, "%s", da);
-               pss->p += n + 1;
-
-               f->size = st.st_size;
-               f->m = st.st_mtime;
-               prev->next = f;
-               prev = f;
-       }
-
-       uv_fs_req_cleanup(&req);
-
-       return ret;
-#else
-       return 0;
-#endif
-}
-
-static void
-free_scan_dir(struct per_session_data__tbl_dir *pss)
-{
-       struct fobj *f = pss->base.next, *f1;
-
-       while (f) {
-               f1 = f->next;
-               free(f);
-               f = f1;
-       }
-
-       pss->base.next = NULL;
-}
-
-static int
-callback_lws_table_dirlisting(struct lws *wsi, enum lws_callback_reasons reason,
-                             void *user, void *in, size_t len)
-{
-       struct per_session_data__tbl_dir *pss = (struct per_session_data__tbl_dir *)user;
-       char j[LWS_PRE + 16384], *p = j + LWS_PRE, *start = p, *q, *q1, *w,
-               *end = j + sizeof(j) - LWS_PRE, e[384], s[384], s1[384];
-       const struct lws_protocol_vhost_options *pmo;
-       struct fobj *f;
-       int n, first = 1;
-
-       switch (reason) {
-       case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
-               break;
-
-       case LWS_CALLBACK_ESTABLISHED:
-               lwsl_debug("LWS_CALLBACK_ESTABLISHED\n");
-               /*
-                * send client the lwsgt table layout
-                */
-               start = "{\"cols\":["
-                       "  {\"name\": \"Date\"},"
-                       "  {\"name\": \"Size\", \"align\": \"right\"},"
-                       "  {\"name\": \"Icon\"},"
-                       "  {\"name\": \"Name\", \"href\": \"uri\"},"
-                       "  {\"name\": \"uri\", \"hide\": \"1\" }"
-                       " ]"
-                       "}";
-               if (lws_write(wsi, (unsigned char *)start, strlen(start),
-                             LWS_WRITE_TEXT) < 0)
-                       return -1;
-
-               /* send a view update next */
-               lws_callback_on_writable(wsi);
-               break;
-
-       case LWS_CALLBACK_RECEIVE:
-               if (len > sizeof(pss->reldir) - 1)
-                       len = sizeof(pss->reldir) - 1;
-               if (!strstr(in, "..") && !strchr(in, '~'))
-                       lws_strncpy(pss->reldir, in, len + 1);
-               else
-                       len = 0;
-               pss->reldir[len] = '\0';
-               if (pss->reldir[0] == '/' && !pss->reldir[1])
-                       pss->reldir[0] = '\0';
-               lwsl_info("%s\n", pss->reldir);
-               lws_callback_on_writable(wsi);
-               break;
-
-       case LWS_CALLBACK_SERVER_WRITEABLE:
-
-               if (scan_dir(wsi, pss))
-                       return 1;
-
-               p += lws_snprintf(p, end - p, "{\"breadcrumbs\":[");
-               q = pss->reldir;
-
-               if (!q[0])
-                       p += lws_snprintf(p, end - p, "{\"name\":\"top\"}");
-
-               while (*q) {
-
-                       q1 = strchr(q, '/');
-                       if (!q1) {
-                               if (first)
-                                       strcpy(s, "top1");
-                               else
-                                       strcpy(s, q);
-                               s1[0] = '\0';
-                               q += strlen(q);
-                       } else {
-                               n = lws_ptr_diff(q1, q);
-                               if (n > (int)sizeof(s) - 1)
-                                       n = sizeof(s) - 1;
-                               if (first) {
-                                       strcpy(s1, "/");
-                                       strcpy(s, "top");
-                               } else {
-                                       lws_strncpy(s, q, n + 1);
-
-                                       n = lws_ptr_diff(q1, pss->reldir);
-                                       if (n > (int)sizeof(s1) - 1)
-                                               n = sizeof(s1) - 1;
-                                       lws_strncpy(s1, pss->reldir, n + 1);
-                               }
-                               q = q1 + 1;
-                       }
-                       if (!first)
-                               p += lws_snprintf(p, end - p, ",");
-                       else
-                               first = 0;
-
-                       p += lws_snprintf(p, end - p, "{\"name\":\"%s\"",
-                                       lws_json_purify(e, s, sizeof(e)));
-                       if (*q) {
-                               w = s1;
-                               while (w[0] == '/' && w[1] == '/')
-                                       w++;
-                               p += lws_snprintf(p, end - p, ",\"url\":\"%s\"",
-                                       lws_json_purify(e, w, sizeof(e)));
-                       }
-                       p += lws_snprintf(p, end - p, "}");
-                       if (!q1)
-                               break;
-               }
-
-               p += lws_snprintf(p, end - p, "],\"data\":[");
-
-               f = pss->base.next;
-               while (f) {
-                       /* format in JSON */
-                       p += lws_snprintf(p, end - p, "{\"Icon\":\"%s\",",
-                                       lws_json_purify(e, f->icon, sizeof(e)));
-                       p += lws_snprintf(p, end - p, " \"Date\":\"%s\",",
-                               lws_json_purify(e, f->date, sizeof(e)));
-                       p += lws_snprintf(p, end - p, " \"Size\":\"%ld\",",
-                               f->size);
-                       if (f->uri)
-                               p += lws_snprintf(p, end - p, " \"uri\":\"%s\",",
-                                               lws_json_purify(e, f->uri, sizeof(e)));
-                       p += lws_snprintf(p, end - p, " \"Name\":\"%s\"}",
-                               lws_json_purify(e, f->name, sizeof(e)));
-
-                       f = f->next;
-
-                       if (f)
-                               p += lws_snprintf(p, end - p, ",");
-               }
-
-               p += lws_snprintf(p, end - p, "]}");
-
-               free_scan_dir(pss);
-
-               if (lws_write(wsi, (unsigned char *)start, p - start,
-                             LWS_WRITE_TEXT) < 0)
-                       return -1;
-
-               break;
-
-       case LWS_CALLBACK_HTTP_PMO:
-               /* find the per-mount options we're interested in */
-               lwsl_debug("LWS_CALLBACK_HTTP_PMO\n");
-               pmo = (struct lws_protocol_vhost_options *)in;
-               while (pmo) {
-                       if (!strcmp(pmo->name, "dir")) /* path to list files */
-                               pss->dir = pmo->value;
-                       pmo = pmo->next;
-               }
-               if (!pss->dir[0]) {
-                       lwsl_err("dirlisting: \"dir\" pmo missing\n");
-                       return 1;
-               }
-               break;
-
-       case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
-               //lwsl_notice("LWS_CALLBACK_HTTP_DROP_PROTOCOL\n");
-#if UV_VERSION_MAJOR > 0
-               lws_protocol_dir_kill_monitor(pss);
-#endif
-               break;
-
-       default:
-               return 0;
-       }
-
-       return 0;
-
-}
-
-static const struct lws_protocols protocols[] = {
-       {
-               "protocol-lws-table-dirlisting",
-               callback_lws_table_dirlisting,
-               sizeof(struct per_session_data__tbl_dir),
-               0,
-       },
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_lws_table_dirlisting(struct lws_context *context,
-                              struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_lws_table_dirlisting(struct lws_context *context)
-{
-       return 0;
-}
index 9a7a031..ca9b429 100644 (file)
  * Public Domain.
  */
 
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #include <string.h>
 
@@ -164,35 +168,26 @@ callback_client_loopback_test(struct lws *wsi, enum lws_callback_reasons reason,
        return 0;
 }
 
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols client_loopback_test_protocols[] = {
        {
                "client-loopback-test",
                callback_client_loopback_test,
                sizeof(struct per_session_data__client_loopback_test),
                1024, /* rx buf size must be >= permessage-deflate rx size */
+               0, NULL, 0
        },
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_client_loopback_test(struct lws_context *context,
-                                  struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t client_loopback_test = {
+       .hdr = {
+               "client loopback test",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
 
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_client_loopback_test(struct lws_context *context)
-{
-       return 0;
-}
+       .protocols = client_loopback_test_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(client_loopback_test_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
index 11d6fef..2556f32 100644 (file)
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
@@ -55,7 +59,7 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
                        lws_get_protocol(wsi),
                        sizeof(struct vhd__dumb_increment));
                if (!vhd)
-                       return -1;
+                       return 0;
                if ((opt = lws_pvo_search(
                                (const struct lws_protocol_vhost_options *)in,
                                "options")))
@@ -71,7 +75,7 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
        case LWS_CALLBACK_SERVER_WRITEABLE:
                n = lws_snprintf((char *)p, sizeof(buf) - LWS_PRE, "%d",
                                 pss->number++);
-               m = lws_write(wsi, p, n, LWS_WRITE_TEXT);
+               m = lws_write(wsi, p, (unsigned int)n, LWS_WRITE_TEXT);
                if (m < n) {
                        lwsl_err("ERROR %d writing to di socket\n", n);
                        return -1;
@@ -117,32 +121,22 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
 
 #if !defined (LWS_PLUGIN_STATIC)
                
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols dumb_increment_protocols[] = {
        LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_dumb_increment(struct lws_context *context,
-                            struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_dumb_increment(struct lws_context *context)
-{
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t dumb_increment = {
+       .hdr = {
+               "dumb increment",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = dumb_increment_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(dumb_increment_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
 #endif
diff --git a/plugins/protocol_esp32_lws_group.c b/plugins/protocol_esp32_lws_group.c
deleted file mode 100644 (file)
index 4b20e6f..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * ESP32 Group protocol handler
- *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA*
- *
- */
-#include <string.h>
-#include <nvs.h>
-#include <esp_ota_ops.h>
-
-typedef enum {
-       GROUP_STATE_NONE,
-       GROUP_STATE_INITIAL,
-       GROUP_STATE_MEMBERS,
-       GROUP_STATE_FINAL
-} group_state;
-
-struct per_session_data__lws_group {
-       struct per_session_data__lws_group *next;
-       group_state group_state;
-
-       struct lws_group_member *member;
-
-       unsigned char subsequent:1;
-       unsigned char changed_partway:1;
-};
-
-struct per_vhost_data__lws_group {
-       struct per_session_data__lws_group *live_pss_list;
-       struct lws_context *context;
-       struct lws_vhost *vhost;
-       const struct lws_protocols *protocol;
-       int count_live_pss;
-};
-
-static void render_ip4(char *dest, int len, uint8_t *ip)
-{
-       snprintf(dest, len, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
-}
-
-
-
-static int
-callback_lws_group(struct lws *wsi, enum lws_callback_reasons reason,
-                  void *user, void *in, size_t len)
-{
-       struct per_session_data__lws_group *pss =
-                       (struct per_session_data__lws_group *)user;
-       struct per_vhost_data__lws_group *vhd =
-                       (struct per_vhost_data__lws_group *)
-                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
-                                       lws_get_protocol(wsi));
-       char buffer[1024 + LWS_PRE], ipv4[20];
-       char *start = buffer + LWS_PRE - 1, *p = start,
-                     *end = buffer + sizeof(buffer) - 1;
-       struct lws_group_member *mbr;
-       int n, m;
-
-       switch (reason) {
-
-       case LWS_CALLBACK_PROTOCOL_INIT:
-               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
-                               lws_get_protocol(wsi),
-                               sizeof(struct per_vhost_data__lws_group));
-               vhd->context = lws_get_context(wsi);
-               vhd->protocol = lws_get_protocol(wsi);
-               vhd->vhost = lws_get_vhost(wsi);
-               break;
-
-       case LWS_CALLBACK_PROTOCOL_DESTROY:
-               if (!vhd)
-                       break;
-               break;
-
-       case LWS_CALLBACK_ESTABLISHED:
-               lwsl_notice("%s: ESTABLISHED\n", __func__);
-               vhd->count_live_pss++;
-               pss->next = vhd->live_pss_list;
-               vhd->live_pss_list = pss;
-               pss->group_state = GROUP_STATE_INITIAL;
-               lws_callback_on_writable(wsi);
-               break;
-
-       case LWS_CALLBACK_SERVER_WRITEABLE:
-
-               switch (pss->group_state) {
-
-               case GROUP_STATE_NONE:
-                       /* fallthru */
-
-               case GROUP_STATE_INITIAL:
-
-                       p += snprintf((char *)p, end - p,
-                                     "{\n"
-                                     " \"group\":\"%s\","
-                                     " \"members\":[\n",
-                                     lws_esp32.group);
-
-                       n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
-                       pss->group_state = GROUP_STATE_MEMBERS;
-                       pss->subsequent = 0;
-                       pss->changed_partway = 0;
-                       pss->member = lws_esp32.first;
-                       break;
-
-               case GROUP_STATE_MEMBERS:
-
-                       /* confirm pss->member is still in the list... */
-
-                       mbr = lws_esp32.first;
-                       while (mbr && mbr != pss->member)
-                               mbr = mbr->next;
-
-                       if (!mbr) { /* no longer exists... */
-                               if (lws_esp32.first || pss->member)
-                                       pss->changed_partway = 1;
-                               *p++ = ' ';
-                               pss->member = NULL;
-
-                               /*
-                                * finish the list where we got to, then
-                                * immediately reissue it
-                                */
-                       }
-                       
-                       while (end - p > 100 && pss->member) {
-
-                               if (pss->subsequent)
-                                       *p++ = ',';
-
-                               pss->subsequent = 1;
-                               render_ip4(ipv4, sizeof(ipv4), (uint8_t *)&pss->member->addr);
-
-                               p += snprintf((char *)p, end - p,
-                                             " {\n"
-                                             "  \"mac\":\"%s\",\n"
-                                             "  \"model\":\"%s\",\n"
-                                             "  \"role\":\"%s\",\n"
-                                             "  \"width\":\"%d\",\n"
-                                             "  \"height\":\"%d\",\n"
-                                             "  \"ipv4\":\"%s\"\n"
-                                             " }\n",
-                                               pss->member->mac,
-                                               pss->member->model,
-                                               pss->member->role,
-                                               pss->member->width,
-                                               pss->member->height,
-                                               ipv4
-                                             );
-                               pss->member = pss->member->next;
-                       }
-
-                       lwsl_notice("%s\n", p);
-
-                       n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
-                       if (!pss->member)
-                               pss->group_state = GROUP_STATE_FINAL;
-                       break;
-
-               case GROUP_STATE_FINAL:
-                       n = LWS_WRITE_CONTINUATION;
-                       p += sprintf((char *)p, "],\n \"discard\":\"%d\"}\n",
-                                       pss->changed_partway);
-                       if (pss->changed_partway)
-                               pss->group_state = GROUP_STATE_INITIAL;
-                       else
-                               pss->group_state = GROUP_STATE_NONE;
-                       break;
-               default:
-                       return 0;
-               }
-//             lwsl_notice("issue: %d (%d)\n", p - start, n);
-               m = lws_write(wsi, (unsigned char *)start, p - start, n);
-               if (m < 0) {
-                       lwsl_err("ERROR %d writing to di socket\n", m);
-                       return -1;
-               }
-
-               if (pss->group_state != GROUP_STATE_NONE)
-                       lws_callback_on_writable(wsi);
-
-               break;
-
-       case LWS_CALLBACK_RECEIVE:
-               {
-                       break;
-               }
-
-       case LWS_CALLBACK_CLOSED:
-               {
-                       struct per_session_data__lws_group **p = &vhd->live_pss_list;
-
-                       while (*p) {
-                               if ((*p) == pss) {
-                                       *p = pss->next;
-                                       continue;
-                               }
-
-                               p = &((*p)->next);
-                       }
-
-                       vhd->count_live_pss--;
-               }
-               break;
-
-       case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
-               /* called when our wsi user_space is going to be destroyed */
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-#define LWS_PLUGIN_PROTOCOL_LWS_GROUP \
-       { \
-               "lws-group", \
-               callback_lws_group, \
-               sizeof(struct per_session_data__lws_group), \
-               1024, 0, NULL, 900 \
-       }
-
diff --git a/plugins/protocol_esp32_lws_ota.c b/plugins/protocol_esp32_lws_ota.c
deleted file mode 100644 (file)
index 74f2493..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * ESP32 OTA update protocol handler
- *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA 
- *
- */
-#include <string.h>
-#include <esp_partition.h>
-#include <esp_ota_ops.h>
-#include <nvs.h>
-
-struct per_session_data__esplws_ota {
-       struct lws_spa *spa;
-       char filename[32];
-       char result[LWS_PRE + 512];
-       int result_len;
-       int filename_length;
-       esp_ota_handle_t otahandle;
-       const esp_partition_t *part;
-       long file_length;
-       long last_rep;
-       nvs_handle nvh;
-       TimerHandle_t reboot_timer;
-};
-
-struct per_vhost_data__esplws_ota {
-       struct lws_context *context;
-       struct lws_vhost *vhost;
-       const struct lws_protocols *protocol;
-};
-
-static const char * const ota_param_names[] = {
-       "upload",
-};
-
-enum enum_ota_param_names {
-       EPN_UPLOAD,
-};
-
-static void ota_reboot_timer_cb(TimerHandle_t t)
-{
-       esp_restart();
-}
-
-const esp_partition_t *
-ota_choose_part(void)
-{
-       const esp_partition_t *bootpart, *part = NULL;
-       esp_partition_iterator_t i;
-
-       bootpart = lws_esp_ota_get_boot_partition();
-       i = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);
-       while (i) {
-               part = esp_partition_get(i);
-
-               /* cannot update ourselves */
-               if (part == bootpart)
-                       goto next;
-
-               /* OTA Partition numbering is from _OTA_MIN to less than _OTA_MAX */
-               if (part->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MIN ||
-                   part->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_MAX)
-                       goto next;
-
-               break;
-
-next:
-               i = esp_partition_next(i);
-       }
-
-       if (!i) {
-               lwsl_err("Can't find good OTA part\n");
-               return NULL;
-       }
-       lwsl_notice("Directing OTA to part type %d/%d start 0x%x\n",
-                       part->type, part->subtype,
-                       (uint32_t)part->address);
-
-       return part;
-}
-
-static int
-ota_file_upload_cb(void *data, const char *name, const char *filename,
-              char *buf, int len, enum lws_spa_fileupload_states state)
-{
-       struct per_session_data__esplws_ota *pss =
-                       (struct per_session_data__esplws_ota *)data;
-
-       switch (state) {
-       case LWS_UFS_OPEN:
-               lwsl_notice("LWS_UFS_OPEN Filename %s\n", filename);
-               lws_strncpy(pss->filename, filename, sizeof(pss->filename));
-               if (strcmp(name, "ota"))
-                       return 1;
-
-               pss->part = ota_choose_part();
-               if (!pss->part)
-                       return 1;
-
-               if (esp_ota_begin(pss->part, OTA_SIZE_UNKNOWN, &pss->otahandle) != ESP_OK) {
-                       lwsl_err("OTA: Failed to begin\n");
-                       return 1;
-               }
-
-               pss->file_length = 0;
-               pss->last_rep = -1;
-               break;
-
-       case LWS_UFS_FINAL_CONTENT:
-       case LWS_UFS_CONTENT:
-               if (pss->file_length + len > pss->part->size) {
-                       lwsl_err("OTA: incoming file too large\n");
-                       return 1;
-               }
-
-               if ((pss->file_length & ~0xffff) != (pss->last_rep & ~0xffff)) {
-                       lwsl_notice("writing 0x%lx...\n",
-                                       pss->part->address + pss->file_length);
-                       pss->last_rep = pss->file_length;
-               }
-               if (esp_ota_write(pss->otahandle, buf, len) != ESP_OK) {
-                       lwsl_err("OTA: Failed to write\n");
-                       return 1;
-               }
-               pss->file_length += len;
-
-               if (state == LWS_UFS_CONTENT)
-                       break;
-
-               lwsl_notice("LWS_UFS_FINAL_CONTENT\n");
-               if (esp_ota_end(pss->otahandle) != ESP_OK) {
-                       lwsl_err("OTA: end failed\n");
-                       return 1;
-               }
-
-               if (esp_ota_set_boot_partition(pss->part) != ESP_OK) {
-                       lwsl_err("OTA: set boot part failed\n");
-                       return 1;
-               }
-
-               pss->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, NULL,
-                                                ota_reboot_timer_cb);
-               xTimerStart(pss->reboot_timer, 0);
-               break;
-       }
-
-       return 0;
-}
-
-static int
-callback_esplws_ota(struct lws *wsi, enum lws_callback_reasons reason,
-                   void *user, void *in, size_t len)
-{
-       struct per_session_data__esplws_ota *pss =
-                       (struct per_session_data__esplws_ota *)user;
-       struct per_vhost_data__esplws_ota *vhd =
-                       (struct per_vhost_data__esplws_ota *)
-                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
-                                       lws_get_protocol(wsi));
-       unsigned char buf[LWS_PRE + 384], *start = buf + LWS_PRE - 1, *p = start,
-            *end = buf + sizeof(buf) - 1;
-       int n;
-
-       switch (reason) {
-
-       case LWS_CALLBACK_PROTOCOL_INIT:
-               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
-                               lws_get_protocol(wsi),
-                               sizeof(struct per_vhost_data__esplws_ota));
-               vhd->context = lws_get_context(wsi);
-               vhd->protocol = lws_get_protocol(wsi);
-               vhd->vhost = lws_get_vhost(wsi);
-               break;
-
-       case LWS_CALLBACK_PROTOCOL_DESTROY:
-               if (!vhd)
-                       break;
-               break;
-
-       /* OTA POST handling */
-
-       case LWS_CALLBACK_HTTP_BODY:
-               /* create the POST argument parser if not already existing */
-               // lwsl_notice("LWS_CALLBACK_HTTP_BODY (ota) %d %d %p\n", (int)pss->file_length, (int)len, pss->spa);
-               lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 30);
-               if (!pss->spa) {
-                       pss->spa = lws_spa_create(wsi, ota_param_names,
-                                       LWS_ARRAY_SIZE(ota_param_names), 4096,
-                                       ota_file_upload_cb, pss);
-                       if (!pss->spa)
-                               return -1;
-
-                       pss->filename[0] = '\0';
-                       pss->file_length = 0;
-               }
-               lws_esp32.upload = 1;
-
-               /* let it parse the POST data */
-               if (lws_spa_process(pss->spa, in, len))
-                       return -1;
-               break;
-
-       case LWS_CALLBACK_HTTP_BODY_COMPLETION:
-               lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION (ota)\n");
-               /* call to inform no more payload data coming */
-               lws_spa_finalize(pss->spa);
-
-               pss->result_len = snprintf(pss->result + LWS_PRE, sizeof(pss->result) - LWS_PRE - 1,
-                       "Rebooting after OTA update");
-
-               if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
-                       goto bail;
-
-               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
-                               (unsigned char *)"text/html", 9, &p, end))
-                       goto bail;
-               if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end))
-                       goto bail;
-               if (lws_finalize_http_header(wsi, &p, end))
-                       goto bail;
-
-               n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS | LWS_WRITE_H2_STREAM_END);
-               if (n < 0)
-                       goto bail;
-
-               lws_callback_on_writable(wsi);
-               break;
-
-       case LWS_CALLBACK_HTTP_WRITEABLE:
-               if (!pss->result_len)
-                       break;
-               lwsl_debug("LWS_CALLBACK_HTTP_WRITEABLE: sending %d\n",
-                          pss->result_len);
-               n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
-                             pss->result_len, LWS_WRITE_HTTP);
-               if (n < 0)
-                       return 1;
-
-               if (lws_http_transaction_completed(wsi))
-                       return 1;
-
-               /* stop further service so we don't serve the probe GET to see if we rebooted */
-               while (1);
-
-               break;
-
-       case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
-               /* called when our wsi user_space is going to be destroyed */
-               if (pss->spa) {
-                       lws_spa_destroy(pss->spa);
-                       pss->spa = NULL;
-               }
-               lws_esp32.upload = 0;
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-
-bail:
-       return 1;
-}
-
-#define LWS_PLUGIN_PROTOCOL_ESPLWS_OTA \
-       { \
-               "esplws-ota", \
-               callback_esplws_ota, \
-               sizeof(struct per_session_data__esplws_ota), \
-               4096, 0, NULL, 900 \
-       }
-
diff --git a/plugins/protocol_esp32_lws_reboot_to_factory.c b/plugins/protocol_esp32_lws_reboot_to_factory.c
deleted file mode 100644 (file)
index 058c741..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Example ESP32 app code using Libwebsockets
- *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- *
- * This is intended to be mounted somewhere in your ESP32 user app... if the
- * client touched the mount, the plugin hangs up and reboots into the
- * factory mode one second later.
- *
- * The factory mode will reassociate with the same IP with the same MAC
- * shortly afterwards and be accessible by the same IP / mDNS name.
- */
-#include <string.h>
-#include <esp_partition.h>
-#include <esp_ota_ops.h>
-#include <nvs.h>
-
-static int
-callback_esplws_rtf(struct lws *wsi, enum lws_callback_reasons reason,
-                   void *user, void *in, size_t len)
-{
-       switch (reason) {
-
-       case LWS_CALLBACK_HTTP:
-               
-               lws_esp32_restart_guided(LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY);
-               return 1;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-#define LWS_PLUGIN_PROTOCOL_ESPLWS_RTF \
-       { \
-               "esplws-rtf", \
-               callback_esplws_rtf, \
-               0, \
-               10, 0, NULL, 0 \
-       }
-
diff --git a/plugins/protocol_esp32_lws_scan.c b/plugins/protocol_esp32_lws_scan.c
deleted file mode 100644 (file)
index 80ac558..0000000
+++ /dev/null
@@ -1,1273 +0,0 @@
-/*
- * ESP32 Scan / Factory protocol handler
- *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA*
- *
- */
-#include <string.h>
-#include <nvs.h>
-#include <esp_ota_ops.h>
-
-typedef enum {
-       SCAN_STATE_NONE,
-       SCAN_STATE_INITIAL,
-       SCAN_STATE_INITIAL_MANIFEST,
-       SCAN_STATE_KNOWN,
-       SCAN_STATE_LIST,
-       SCAN_STATE_FINAL
-} scan_state;
-
-struct store_json {
-       const char *j;
-       const char *nvs;
-};
-
-struct per_session_data__esplws_scan {
-       struct per_session_data__esplws_scan *next;
-       scan_state scan_state;
-       struct timeval last_send;
-
-       struct lws_spa *spa;
-       char filename[32];
-       char result[LWS_PRE + 512];
-       unsigned char buffer[4096];
-       int result_len;
-       int filename_length;
-       long file_length;
-       nvs_handle nvh;
-
-       char ap_record;
-       unsigned char subsequent:1;
-       unsigned char changed_partway:1;
-};
-
-#define max_aps 12
-
-struct per_vhost_data__esplws_scan {
-       wifi_ap_record_t ap_records[10];
-       TimerHandle_t timer, reboot_timer;
-       struct per_session_data__esplws_scan *live_pss_list;
-       struct lws_context *context;
-       struct lws_vhost *vhost;
-       const struct lws_protocols *protocol;
-       struct lws_wifi_scan *known_aps_list;
-
-       const esp_partition_t *part;
-       esp_ota_handle_t otahandle;
-       long file_length;
-       long content_length;
-
-       int cert_remaining_days;
-
-       struct lws *cwsi;
-       char json[2048];
-       int json_len;
-
-       int acme_state;
-       char acme_msg[256];
-
-       uint16_t count_ap_records;
-       char count_live_pss;
-       unsigned char scan_ongoing:1;
-       unsigned char completed_any_scan:1;
-       unsigned char reboot:1;
-       unsigned char changed_settings:1;
-       unsigned char checked_updates:1;
-       unsigned char autonomous_update:1;
-       unsigned char autonomous_update_sampled:1;
-};
-
-static const struct store_json store_json[] = {
-       { "\"ssid0\":\"", "0ssid" },
-       { ",\"pw0\":\"", "0password" },
-       { "\"ssid1\":\"", "1ssid" },
-       { ",\"pw1\":\"", "1password" },
-       { "\"ssid2\":\"", "2ssid" },
-       { ",\"pw2\":\"", "2password" },
-       { "\"ssid3\":\"", "3ssid" },
-       { ",\"pw3\":\"", "3password" },
-       { ",\"access_pw\":\"", "access_pw" },
-       { "{\"group\":\"", "group" },
-       { "{\"role\":\"", "role" },
-       { ",\"region\":\"", "region" },
-};
-
-static wifi_scan_config_t scan_config = {
-       .ssid = 0,
-       .bssid = 0,
-       .channel = 0,
-        .show_hidden = true
-};
-
-const esp_partition_t *
-ota_choose_part(void);
-
-static const char * const param_names[] = {
-       "text",
-       "pub",
-       "pri",
-       "serial",
-       "opts",
-       "group",
-       "role",
-       "updsettings",
-};
-
-enum enum_param_names {
-       EPN_TEXT,
-       EPN_PUB,
-       EPN_PRI,
-       EPN_SERIAL,
-       EPN_OPTS,
-       EPN_GROUP,
-       EPN_ROLE,
-       EPN_UPDSETTINGS,
-};
-
-
-static void
-scan_finished(uint16_t count, wifi_ap_record_t *recs, void *v);
-
-static int
-esplws_simple_arg(char *dest, int len, const char *in, const char *match)
-{
-       const char *p = strstr(in, match);
-       int n = 0;
-
-       if (!p)
-               return 1;
-
-       p += strlen(match);
-       while (*p && *p != '\"' && n < len - 1)
-               dest[n++] = *p++;
-       dest[n] = '\0';
-
-       return 0;
-}
-
-static void
-scan_start(struct per_vhost_data__esplws_scan *vhd)
-{
-       int n;
-
-       if (vhd->reboot)
-               esp_restart();
-
-       if (vhd->scan_ongoing)
-               return;
-
-       if (lws_esp32.acme)
-               return;
-
-       if (lws_esp32.upload)
-               return;
-
-       vhd->scan_ongoing = 1;
-       lws_esp32.scan_consumer = scan_finished;
-       lws_esp32.scan_consumer_arg = vhd;
-       n = esp_wifi_scan_start(&scan_config, false);
-       if (n != ESP_OK)
-               lwsl_err("scan start failed %d\n", n);
-}
-
-static int  scan_defer;
-
-static void timer_cb(TimerHandle_t t)
-{
-       struct per_vhost_data__esplws_scan *vhd = pvTimerGetTimerID(t);
-
-//     if (!lws_esp32.inet && ((scan_defer++) & 1))
-/*
- * AP mode + scan does not work well on ESP32... if we didn't connect to an AP
- * ourselves, just scan once at boot.  Then leave us on the AP channel.
- *
- * Do the callback for everyone to keep the heartbeat alive.
- */
-       if (!lws_esp32.inet && scan_defer++) {
-                lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
-
-                return;
-       }
-
-       scan_start(vhd);
-}
-
-static void reboot_timer_cb(TimerHandle_t t)
-{
-       esp_restart();
-}
-
-static int
-client_connection(struct per_vhost_data__esplws_scan *vhd, const char *file)
-{
-#if defined(CONFIG_LWS_IS_FACTORY_APPLICATION)  && defined(CONFIG_LWS_OTA_SERVER_BASE_URL) && \
-    defined(CONFIG_LWS_OTA_SERVER_FQDN)
-       static struct lws_client_connect_info i;
-       char path[256];
-
-       memset(&i, 0, sizeof i);
-
-       snprintf(path, sizeof(path) - 1, CONFIG_LWS_OTA_SERVER_BASE_URL "/" CONFIG_LWS_MODEL_NAME "/%s", file);
-
-       lwsl_notice("Fetching %s\n", path);
-
-       i.port = 443;
-       i.context = vhd->context;
-       i.address = CONFIG_LWS_OTA_SERVER_FQDN;
-       i.ssl_connection = 1;
-       i.host = i.address;
-       i.origin = i.host;
-       i.vhost = vhd->vhost;
-       i.method = "GET";
-       i.path = path;
-       i.protocol = "esplws-scan";
-       i.pwsi = &vhd->cwsi;
-
-       vhd->cwsi = lws_client_connect_via_info(&i);
-       if (!vhd->cwsi) {
-               lwsl_notice("NULL return\n");
-               return 1; /* fail */
-       }
-#endif
-       return 0; /* ongoing */
-}
-
-static int
-lws_wifi_scan_rssi(struct lws_wifi_scan *p)
-{
-       if (!p->count)
-               return -127;
-
-       return p->rssi / p->count;
-}
-
-/*
- * Insert new lws_wifi_scan into linkedlist in rssi-sorted order, trimming the
- * list if needed to keep it at or below max_aps entries.
- */
-
-static int
-lws_wifi_scan_insert_trim(struct lws_wifi_scan **list, struct lws_wifi_scan *ns)
-{
-       int count = 0, ins = 1, worst;
-       struct lws_wifi_scan *newlist, **pworst, *pp1;
-
-       lws_start_foreach_llp(struct lws_wifi_scan **, pp, *list) {
-               /* try to find existing match */
-               if (!strcmp((*pp)->ssid, ns->ssid) &&
-                   !memcmp((*pp)->bssid, ns->bssid, 6)) {
-                       if ((*pp)->count > 127) {
-                               (*pp)->count /= 2;
-                               (*pp)->rssi /= 2;
-                       }
-                       (*pp)->rssi += ns->rssi;
-                       (*pp)->count++;
-                       ins = 0;
-                       break;
-               }
-       } lws_end_foreach_llp(pp, next);
-
-       if (ins) {
-               lws_start_foreach_llp(struct lws_wifi_scan **, pp, *list) {
-                       /* trim any excess guys */
-                       if (count++ >= max_aps - 1) {
-                               pp1 = *pp;
-                               *pp = (*pp)->next;
-                               free(pp1);
-                               continue; /* stay where we are */
-                       }
-               } lws_end_foreach_llp(pp, next);
-
-               /* we are inserting... so alloc a copy of him */
-               pp1 = malloc(sizeof(*pp1));
-               if (!pp1)
-                       return -1;
-
-               memcpy(pp1, ns, sizeof(*pp1));
-               pp1->next = *list;
-               *list = pp1;
-       }
-
-       /* sort the list ... worst first, but added at the newlist head */
-
-       newlist = NULL;
-
-       /* while anybody left on the old list */
-       while (*list) {
-               worst = 0;
-               pworst = NULL;
-
-               /* who is the worst guy still left on the old list? */
-               lws_start_foreach_llp(struct lws_wifi_scan **, pp, *list) {
-                       if (lws_wifi_scan_rssi(*pp) <= worst) {
-                               worst = lws_wifi_scan_rssi(*pp);
-                               pworst = pp;
-                       }
-               } lws_end_foreach_llp(pp, next);
-
-               if (pworst) {
-                       /* move the worst to the head of the new list */
-                       pp1 = *pworst;
-                       *pworst = (*pworst)->next;
-                       pp1->next = newlist;
-                       newlist = pp1;
-               }
-       }
-
-       *list = newlist;
-
-       return 0;
-}
-
-static void
-scan_finished(uint16_t count, wifi_ap_record_t *recs, void *v)
-{
-       struct per_vhost_data__esplws_scan *vhd = v;
-       struct per_session_data__esplws_scan *p = vhd->live_pss_list;
-       struct lws_wifi_scan lws;
-       wifi_ap_record_t *r;
-       int m;
-
-       lwsl_notice("%s: count %d\n", __func__, count);
-
-       vhd->scan_ongoing = 0;
-
-       if (count < LWS_ARRAY_SIZE(vhd->ap_records))
-               vhd->count_ap_records = count;
-       else
-               vhd->count_ap_records = LWS_ARRAY_SIZE(vhd->ap_records);
-
-       memcpy(vhd->ap_records, recs, vhd->count_ap_records * sizeof(*recs));
-       
-       while (p) {
-               if (p->scan_state != SCAN_STATE_INITIAL &&
-                   p->scan_state != SCAN_STATE_NONE)
-                       p->changed_partway = 1;
-               else
-                       p->scan_state = SCAN_STATE_INITIAL;
-               p = p->next;
-       }
-
-       /* convert to generic, cumulative scan results */
-
-       for (m = 0; m < vhd->count_ap_records; m++) {
-
-               r = &vhd->ap_records[m];
-
-               lws.authmode = r->authmode;
-               lws.channel = r->primary;
-               lws.rssi = r->rssi;
-               lws.count = 1;
-               memcpy(&lws.bssid, r->bssid, 6);
-               lws_strncpy(lws.ssid, (const char *)r->ssid, sizeof(lws.ssid));
-
-               lws_wifi_scan_insert_trim(&vhd->known_aps_list, &lws);
-       }
-
-       lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
-
-       if (lws_esp32.inet && !vhd->cwsi && !vhd->checked_updates)
-               client_connection(vhd, "manifest.json");
-
-       if (vhd->changed_settings) {
-               lws_esp32_wlan_nvs_get(1);
-               vhd->changed_settings = 0;
-       } else
-               esp_wifi_connect();
-}
-
-static const char *ssl_names[] = { "ap-cert.pem", "ap-key.pem" };
-
-static int
-file_upload_cb(void *data, const char *name, const char *filename,
-              char *buf, int len, enum lws_spa_fileupload_states state)
-{
-       struct per_session_data__esplws_scan *pss =
-                       (struct per_session_data__esplws_scan *)data;
-       int n;
-
-       switch (state) {
-       case LWS_UFS_OPEN:
-               if (lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
-                       return -1;
-
-               lwsl_notice("LWS_UFS_OPEN Filename %s\n", filename);
-               lws_strncpy(pss->filename, filename, sizeof(pss->filename));
-               if (!strcmp(name, "pub") || !strcmp(name, "pri")) {
-                       if (nvs_open("lws-station", NVS_READWRITE, &pss->nvh))
-                               return 1;
-               } else
-                       return 1;
-               pss->file_length = 0;
-               break;
-
-       case LWS_UFS_FINAL_CONTENT:
-       case LWS_UFS_CONTENT:
-               if (len) {
-                       /* if the file length is too big, drop it */
-                       if (pss->file_length + len > sizeof(pss->buffer))
-                               return 1;
-
-                       memcpy(pss->buffer + pss->file_length, buf, len);
-               }
-               pss->file_length += len;
-
-               if (state == LWS_UFS_CONTENT)
-                       break;
-
-               lwsl_notice("LWS_UFS_FINAL_CONTENT\n");
-               n = 0;
-               if (!strcmp(name, "pri"))
-                       n = 1;
-               lwsl_notice("writing %s\n", ssl_names[n]);
-               n = nvs_set_blob(pss->nvh, ssl_names[n], pss->buffer, pss->file_length);
-               if (n == ESP_OK)
-                       nvs_commit(pss->nvh);
-               nvs_close(pss->nvh);
-               if (n != ESP_OK)
-                       return 1;
-               break;
-       }
-
-       return 0;
-}
-
-static int
-callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
-                   void *user, void *in, size_t len)
-{
-       struct per_session_data__esplws_scan *pss =
-                       (struct per_session_data__esplws_scan *)user;
-       struct per_vhost_data__esplws_scan *vhd =
-                       (struct per_vhost_data__esplws_scan *)
-                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
-                                       lws_get_protocol(wsi));
-       unsigned char *start = pss->buffer + LWS_PRE - 1, *p = start,
-                     *end = pss->buffer + sizeof(pss->buffer) - 1;
-       union lws_tls_cert_info_results ir;
-       struct lws_wifi_scan *lwscan;
-       char subject[64];
-       int n, m;
-       nvs_handle nvh;
-       size_t s;
-
-
-       switch (reason) {
-
-       case LWS_CALLBACK_PROTOCOL_INIT:
-               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
-                               lws_get_protocol(wsi),
-                               sizeof(struct per_vhost_data__esplws_scan));
-               vhd->context = lws_get_context(wsi);
-               vhd->protocol = lws_get_protocol(wsi);
-               vhd->vhost = lws_get_vhost(wsi);
-               vhd->timer = xTimerCreate("x", pdMS_TO_TICKS(10000), 1, vhd,
-                         (TimerCallbackFunction_t)timer_cb);
-               vhd->scan_ongoing = 0;
-               strcpy(vhd->json, " { }");
-       //      scan_start(vhd);
-               break;
-
-       case LWS_CALLBACK_PROTOCOL_DESTROY:
-               if (!vhd)
-                       break;
-               xTimerStop(vhd->timer, 0);
-               xTimerDelete(vhd->timer, 0);
-               break;
-
-       case LWS_CALLBACK_ESTABLISHED:
-               lwsl_notice("%s: ESTABLISHED\n", __func__);
-               if (!vhd->live_pss_list) {
-               //      scan_start(vhd);
-                       xTimerStart(vhd->timer, 0);
-               }
-               vhd->count_live_pss++;
-               pss->next = vhd->live_pss_list;
-               vhd->live_pss_list = pss;
-               /* if we have scan results, update them.  Otherwise wait */
-//             if (vhd->count_ap_records) {
-                       pss->scan_state = SCAN_STATE_INITIAL;
-                       lws_callback_on_writable(wsi);
-//             }
-               break;
-
-       case LWS_CALLBACK_SERVER_WRITEABLE:
-               if (vhd->autonomous_update_sampled) {
-                       p += snprintf((char *)p, end - p,
-                                     " {\n \"auton\":\"1\",\n \"pos\": \"%ld\",\n"
-                                     " \"len\":\"%ld\"\n}\n",
-                                       vhd->file_length,
-                                       vhd->content_length);
-
-                       n = LWS_WRITE_TEXT;
-                       goto issue;
-               }
-
-               switch (pss->scan_state) {
-                       struct timeval t;
-                       uint8_t mac[6];
-                       struct lws_esp32_image i;
-                       char img_factory[384], img_ota[384], group[16], role[16];
-                       int grt;
-
-               case SCAN_STATE_NONE:
-
-                       /* fallthru */
-
-               case SCAN_STATE_INITIAL:
-
-                       gettimeofday(&t, NULL);
-               //      if (t.tv_sec - pss->last_send.tv_sec < 10)
-               //              return 0;
-
-                       pss->last_send = t;
-
-                       if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
-                               lwsl_err("unable to open nvs\n");
-                               return -1;
-                       }
-                       n = 0;
-                       if (nvs_get_blob(nvh, "ap-cert.pem", NULL, &s) == ESP_OK)
-                               n = 1;
-                       if (nvs_get_blob(nvh, "ap-key.pem", NULL, &s) == ESP_OK)
-                               n |= 2;
-                       s = sizeof(group) - 1;
-                       group[0] = '\0';
-                       role[0] = '\0';
-                       nvs_get_str(nvh, "group", group, &s);
-                       nvs_get_str(nvh, "role", role, &s);
-
-                       nvs_close(nvh);
-
-                       ir.ns.name[0] = '\0';
-                       subject[0] = '\0';
-
-                       if (t.tv_sec > 1464083026 &&
-                           !lws_tls_vhost_cert_info(vhd->vhost,
-                                      LWS_TLS_CERT_INFO_VALIDITY_TO, &ir, 0)) {
-                               vhd->cert_remaining_days =
-                                            (ir.time - t.tv_sec) / (24 * 3600);
-                               ir.ns.name[0] = '\0';
-                               lws_tls_vhost_cert_info(vhd->vhost,
-                                       LWS_TLS_CERT_INFO_COMMON_NAME, &ir,
-                                               sizeof(ir.ns.name));
-                               lws_strncpy(subject, ir.ns.name, sizeof(subject));
-
-                               ir.ns.name[0] = '\0';
-                               lws_tls_vhost_cert_info(vhd->vhost,
-                                       LWS_TLS_CERT_INFO_ISSUER_NAME, &ir,
-                                               sizeof(ir.ns.name));
-                       }
-
-                       /*
-                        * this value in the JSON is just
-                        * used for UI indication.  Each conditional feature confirms
-                        * it itself before it allows itself to be used.
-                        */
-
-                       grt = lws_esp32_get_reboot_type();
-
-                       esp_efuse_mac_get_default(mac);
-                       strcpy(img_factory, " { \"date\": \"Empty\" }");
-                       strcpy(img_ota, " { \"date\": \"Empty\" }");
-
-       //              if (grt != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
-                               lws_esp32_get_image_info(esp_partition_find_first(ESP_PARTITION_TYPE_APP,
-                                       ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL), &i,
-                                       img_factory, sizeof(img_factory) - 1);
-                               img_factory[sizeof(img_factory) - 1] = '\0';
-                               if (img_factory[0] == 0xff || strlen(img_factory) < 8)
-                                       strcpy(img_factory, " { \"date\": \"Empty\" }");
-
-                               lws_esp32_get_image_info(esp_partition_find_first(ESP_PARTITION_TYPE_APP,
-                                       ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL), &i,
-                                       img_ota, sizeof(img_ota) - 1);
-                               img_ota[sizeof(img_ota) - 1] = '\0';
-                               if (img_ota[0] == 0xff || strlen(img_ota) < 8)
-                                       strcpy(img_ota, " { \"date\": \"Empty\" }");
-       //              }
-
-                       p += snprintf((char *)p, end - p,
-                                     "{ \"model\":\"%s\",\n"
-                                     " \"forced_button\":\"%d\",\n"
-                                     " \"serial\":\"%s\",\n"
-                                     " \"opts\":\"%s\",\n"
-                                     " \"host\":\"%s-%s\",\n"
-                                     " \"region\":\"%d\",\n"
-                                     " \"ssl_pub\":\"%d\",\n"
-                                     " \"ssl_pri\":\"%d\",\n"
-                                     " \"mac\":\"%02X%02X%02X%02X%02X%02X\",\n"
-                                     " \"ssid\":\"%s\",\n"
-                                     " \"conn_ip\":\"%s\",\n"
-                                     " \"conn_mask\":\"%s\",\n"
-                                     " \"conn_gw\":\"%s\",\n"
-                                     " \"certdays\":\"%d\",\n"
-                                     " \"unixtime\":\"%llu\",\n"
-                                     " \"certissuer\":\"%s\",\n"
-                                     " \"certsubject\":\"%s\",\n"
-                                     " \"le_dns\":\"%s\",\n"
-                                     " \"le_email\":\"%s\",\n"
-                                     " \"acme_state\":\"%d\",\n"
-                                     " \"acme_msg\":\"%s\",\n"
-                                     " \"button\":\"%d\",\n"
-                                     " \"group\":\"%s\",\n"
-                                     " \"role\":\"%s\",\n",
-                                     lws_esp32.model,
-                                     grt == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON, 
-                                     lws_esp32.serial,
-                                     lws_esp32.opts,
-                                     lws_esp32.model, lws_esp32.serial,
-                                     lws_esp32.region,
-                                     n & 1, (n >> 1) & 1,
-                                     mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] | 1,
-                                     lws_esp32.active_ssid,
-                                     lws_esp32.sta_ip,
-                                     lws_esp32.sta_mask,
-                                     lws_esp32.sta_gw,
-                                     vhd->cert_remaining_days,
-                                     (unsigned long long)t.tv_sec,
-                                     ir.ns.name, subject,
-                                     lws_esp32.le_dns,
-                                     lws_esp32.le_email,
-                                     vhd->acme_state,
-                                     vhd->acme_msg,
-                                     ((volatile struct lws_esp32 *)(&lws_esp32))->button_is_down,
-                                     group, role);
-                       p += snprintf((char *)p, end - p,
-                                     " \"img_factory\": %s,\n"
-                                     " \"img_ota\": %s,\n",
-                                       img_factory,
-                                       img_ota
-                                     );
-
-
-                       n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
-                       pss->scan_state = SCAN_STATE_INITIAL_MANIFEST;
-                       pss->ap_record = 0;
-                       pss->subsequent = 0;
-                       break;
-
-               case SCAN_STATE_INITIAL_MANIFEST:
-                       p += snprintf((char *)p, end - p,
-                                     " \"latest\": %s,\n"
-                                     " \"inet\":\"%d\",\n",
-                                       vhd->json,
-                                     lws_esp32.inet
-                                     );
-
-                       p += snprintf((char *)p, end - p,
-                                      " \"known\":[\n");
-
-                       n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
-                       pss->scan_state = SCAN_STATE_KNOWN;
-                       break;
-
-               case SCAN_STATE_KNOWN:
-                       if (nvs_open("lws-station", NVS_READONLY, &nvh)) {
-                               lwsl_notice("unable to open nvh\n");
-                               return -1;
-                       }
-
-                       for (m = 0; m < 4; m++) {
-                               char name[10], ssid[65];
-                               unsigned int pp = 0, use = 0;
-
-                               if (m)
-                                       *p++ = ',';
-
-                               s = sizeof(ssid) - 1;
-                               ssid[0] = '\0';
-                               lws_snprintf(name, sizeof(name) - 1, "%dssid", m);
-                               nvs_get_str(nvh, name, ssid, &s);
-                               lws_snprintf(name, sizeof(name) - 1, "%dpassword", m);
-                               s = 10;
-                               nvs_get_str(nvh, name, NULL, &s);
-                               pp = !!s;
-                               lws_snprintf(name, sizeof(name) - 1, "%duse", m);
-                               nvs_get_u32(nvh, name, &use);
-
-                               p += snprintf((char *)p, end - p,
-                                       "{\"ssid\":\"%s\",\n"
-                                       " \"pp\":\"%u\",\n"
-                                       "\"use\":\"%u\"}\n",
-                                       ssid, pp, use);
-                       }
-                       nvs_close(nvh);
-                       pss->ap_record = 0;
-
-                       p += snprintf((char *)p, end - p,
-                                      "], \"aps\":[\n");
-
-                       n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
-                       pss->scan_state = SCAN_STATE_LIST;
-                       break;
-
-               case SCAN_STATE_LIST:
-                       lwscan = vhd->known_aps_list;
-
-                       n = pss->ap_record;
-                       while (lwscan && n--)
-                               lwscan = lwscan->next;
-
-                       for (m = 0; m < 6; m++) {
-                               n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
-                               if (!lwscan)
-                                       goto scan_state_final;
-
-                               if (pss->subsequent)
-                                       *p++ = ',';
-                               pss->subsequent = 1;
-                               pss->ap_record++;
-
-                               p += snprintf((char *)p, end - p,
-                                             "{\"ssid\":\"%s\",\n"
-                                              "\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\",\n"
-                                              "\"rssi\":\"%d\",\n"
-                                              "\"chan\":\"%d\",\n"
-                                              "\"auth\":\"%d\"}\n",
-                                              lwscan->ssid,
-                                              lwscan->bssid[0], lwscan->bssid[1], lwscan->bssid[2],
-                                              lwscan->bssid[3], lwscan->bssid[4], lwscan->bssid[5],
-                                              lws_wifi_scan_rssi(lwscan),
-                                              lwscan->channel, lwscan->authmode);
-
-                               lwscan = lwscan->next;
-                               if (!lwscan)
-                                       pss->scan_state = SCAN_STATE_FINAL;
-                       }
-                       break;
-
-               case SCAN_STATE_FINAL:
-scan_state_final:
-                       n = LWS_WRITE_CONTINUATION;
-                       p += sprintf((char *)p, "]\n}\n");
-                       if (pss->changed_partway) {
-                               pss->changed_partway = 0;
-                               pss->subsequent = 0;
-                               pss->scan_state = SCAN_STATE_INITIAL;
-                       } else {
-                               pss->scan_state = SCAN_STATE_NONE;
-                               vhd->autonomous_update_sampled = vhd->autonomous_update;
-                       }
-                       break;
-               default:
-                       return 0;
-               }
-issue:
-               m = lws_write(wsi, (unsigned char *)start, p - start, n);
-               if (m < 0) {
-                       lwsl_err("ERROR %d writing to di socket\n", m);
-                       return -1;
-               }
-
-               if (pss->scan_state != SCAN_STATE_NONE)
-                       lws_callback_on_writable(wsi);
-
-               break;
-
-       case LWS_CALLBACK_VHOST_CERT_UPDATE:
-               lwsl_notice("LWS_CALLBACK_VHOST_CERT_UPDATE: %d\n", (int)len);
-               vhd->acme_state = (int)len;
-               if (in) {
-                       lws_strncpy(vhd->acme_msg, in, sizeof(vhd->acme_msg));
-                       lwsl_notice("acme_msg: %s\n", (char *)in);
-               }
-               lws_callback_on_writable_all_protocol_vhost(vhd->vhost, vhd->protocol);
-               break;
-
-       case LWS_CALLBACK_RECEIVE:
-               {
-                       const char *sect = "\"app\": {", *b;
-                       nvs_handle nvh;
-                       char p[64], use[6];
-                       int n, si = -1;
-
-                       if (strstr((const char *)in, "identify")) {
-                               lws_esp32_identify_physical_device();
-                               break;
-                       }
-
-                       if (vhd->json_len && strstr((const char *)in, "update-factory")) {
-                               sect = "\"factory\": {";
-                               goto auton;
-                       }
-                       if (vhd->json_len && strstr((const char *)in, "update-ota"))
-                               goto auton;
-
-                       if (strstr((const char *)in, "\"reset\""))
-                               goto sched_reset;
-
-                       if (!strncmp((const char *)in, "{\"job\":\"start-le\"", 17))
-                               goto start_le;
-
-
-                       if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
-                               lwsl_err("Unable to open nvs\n");
-                               break;
-                       }
-
-                       if (!esplws_simple_arg(p, sizeof(p), in, ",\"slot\":\""))
-                               si = atoi(p);
-
-                       lwsl_notice("si %d\n", si);
-
-                       for (n = 0; n < LWS_ARRAY_SIZE(store_json); n++) {
-                               if (esplws_simple_arg(p, sizeof(p), in, store_json[n].j))
-                                       continue;
-
-                               /* only change access password if he has physical access to device */
-                               if (n == 8 && lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
-                                       continue;
-
-                               if (lws_nvs_set_str(nvh, store_json[n].nvs, p) != ESP_OK) {
-                                       lwsl_err("Unable to store %s in nvm\n", store_json[n].nvs);
-                                       goto bail_nvs;
-                               }
-
-                               if (si != -1 && n < 8) {
-                                       if (!(n & 1)) {
-                                               lws_strncpy(lws_esp32.ssid[(n >> 1) & 3], p,
-                                                               sizeof(lws_esp32.ssid[0]));
-                                               lws_snprintf(use, sizeof(use) - 1, "%duse", si);
-                                               lwsl_notice("resetting %s to 0\n", use);
-                                               nvs_set_u32(nvh, use, 0);
-
-                                       } else
-                                               lws_strncpy(lws_esp32.password[(n >> 1) & 3], p,
-                                                               sizeof(lws_esp32.password[0]));
-                               }
-
-                       }
-
-                       nvs_commit(nvh);
-                       nvs_close(nvh);
-
-                       if (strstr((const char *)in, "\"factory-reset\"")) {
-                               if (lws_esp32_get_reboot_type() ==
-                                       LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
-
-                                       lwsl_notice("Doing factory reset\n");
-                                       ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
-                                       n = nvs_erase_all(nvh);
-                                       if (n)
-                                               lwsl_notice("erase_all failed %d\n", n);
-                                       nvs_commit(nvh);
-                                       nvs_close(nvh);
-
-                                       goto sched_reset;
-                               } else
-                                       lwsl_notice("failed on factory button boot\n");
-                       }
-
-                       if (vhd->scan_ongoing)
-                               vhd->changed_settings = 1;
-                       else
-                               lws_esp32_wlan_nvs_get(1);
-
-                       lwsl_notice("set Join AP info\n");
-                       break;
-
-bail_nvs:
-                       nvs_close(nvh);
-
-                       return 1;
-
-sched_reset:
-                       vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, vhd,
-                                               (TimerCallbackFunction_t)reboot_timer_cb);
-                       xTimerStart(vhd->reboot_timer, 0);
-
-                       return 1;
-
-auton:
-                       lwsl_notice("Autonomous upload\n");
-                       b = strstr(vhd->json, sect);
-                       if (!b) {
-                               lwsl_notice("Can't find %s in JSON\n", sect);
-                               return 1;
-                       }
-                       b = strstr(b, "\"file\": \"");
-                       if (!b) {
-                               lwsl_notice("Can't find \"file\": JSON\n");
-                               return 1;
-                       }
-                       vhd->autonomous_update = 1;
-                       if (pss->scan_state == SCAN_STATE_NONE)
-                               vhd->autonomous_update_sampled = 1;
-                       b += 9;
-                       n = 0;
-                       while ((*b != '\"') && n < sizeof(p) - 1)
-                               p[n++] = *b++;
-
-                       p[n] = '\0';
-
-                       vhd->part = ota_choose_part();
-                       if (!vhd->part)
-                               return 1;
-
-                       if (client_connection(vhd, p))
-                               vhd->autonomous_update = 0;
-
-                       break;
-
-start_le:
-                       lws_esp32.acme = 1; /* hold off scanning */
-                       puts(in);
-                       /*
-                        * {"job":"start-le","cn":"home.warmcat.com",
-                        * "email":"andy@warmcat.com", "staging":"true"}
-                        */
-
-                       if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
-                               lwsl_err("Unable to open nvs\n");
-                               break;
-                       }
-
-                       n = 0;
-                       b = strstr(in, ",\"cn\":\"");
-                       if (b) {
-                               b += 7;
-                               while (*b && *b != '\"' && n < sizeof(lws_esp32.le_dns) - 1)
-                                       lws_esp32.le_dns[n++] = *b++;
-                       }
-                       lws_esp32.le_dns[n] = '\0';
-
-                       lws_nvs_set_str(nvh, "acme-cn", lws_esp32.le_dns);
-                       n = 0;
-                       b = strstr(in, ",\"email\":\"");
-                       if (b) {
-                               b += 10;
-                               while (*b && *b != '\"' && n < sizeof(lws_esp32.le_email) - 1)
-                                       lws_esp32.le_email[n++] = *b++;
-                       }
-                       lws_esp32.le_email[n] = '\0';
-                       lws_nvs_set_str(nvh, "acme-email", lws_esp32.le_email);
-                       nvs_commit(nvh);
-
-                       nvs_close(nvh);
-
-                       n = 1;
-                       b = strstr(in, ",\"staging\":\"");
-                       if (b)
-                               lwsl_notice("staging: %s\n", b);
-                       if (b && b[12] == 'f')
-                               n = 0;
-
-                       lwsl_notice("cn: %s, email: %s, staging: %d\n", lws_esp32.le_dns, lws_esp32.le_email, n);
-
-                       {
-                               struct lws_acme_cert_aging_args caa;
-
-                               memset(&caa, 0, sizeof(caa));
-                               caa.vh = vhd->vhost;
-
-                               caa.element_overrides[LWS_TLS_REQ_ELEMENT_COMMON_NAME] = lws_esp32.le_dns;
-                               caa.element_overrides[LWS_TLS_REQ_ELEMENT_EMAIL] = lws_esp32.le_email;
-
-                               if (n)
-                                       caa.element_overrides[LWS_TLS_SET_DIR_URL] =
-                                                       "https://acme-staging.api.letsencrypt.org/directory"; /* staging */
-                               else
-                                       caa.element_overrides[LWS_TLS_SET_DIR_URL] =
-                                               "https://acme-v01.api.letsencrypt.org/directory"; /* real */
-
-                               lws_callback_vhost_protocols_vhost(vhd->vhost,
-                                               LWS_CALLBACK_VHOST_CERT_AGING,
-                                                       (void *)&caa, 0);
-                       }
-
-                       break;
-
-               }
-
-       case LWS_CALLBACK_CLOSED:
-               {
-                       struct per_session_data__esplws_scan **p = &vhd->live_pss_list;
-
-                       while (*p) {
-                               if ((*p) == pss) {
-                                       *p = pss->next;
-                                       continue;
-                               }
-
-                               p = &((*p)->next);
-                       }
-
-                       vhd->count_live_pss--;
-               }
-               if (!vhd->live_pss_list)
-                       xTimerStop(vhd->timer, 0);
-               break;
-
-       /* "factory" POST handling */
-
-       case LWS_CALLBACK_HTTP_BODY:
-               /* create the POST argument parser if not already existing */
-               if (!pss->spa) {
-                       pss->spa = lws_spa_create(wsi, param_names,
-                                       LWS_ARRAY_SIZE(param_names), 1024,
-                                       file_upload_cb, pss);
-                       if (!pss->spa)
-                               return -1;
-
-                       pss->filename[0] = '\0';
-                       pss->file_length = 0;
-               }
-               //puts((const char *)in);
-               /* let it parse the POST data */
-               if (lws_spa_process(pss->spa, in, len))
-                       return -1;
-               break;
-
-       case LWS_CALLBACK_HTTP_BODY_COMPLETION:
-               lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION (scan)\n");
-               /* call to inform no more payload data coming */
-               lws_spa_finalize(pss->spa);
-
-               for (n = 0; n < LWS_ARRAY_SIZE(param_names); n++)
-                       if (lws_spa_get_string(pss->spa, n))
-                               lwsl_notice(" Param %s: %s\n", param_names[n],
-                                           lws_spa_get_string(pss->spa, n));
-                       else
-                               lwsl_notice(" Param %s: (none)\n",
-                                           param_names[n]);
-
-               if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
-                       lwsl_err("Unable to open nvs\n");
-                       break;
-               }
-
-               if (lws_esp32_get_reboot_type() == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
-
-                       if (lws_spa_get_string(pss->spa, EPN_SERIAL)) {
-                               if (lws_nvs_set_str(nvh, "serial", lws_spa_get_string(pss->spa, EPN_SERIAL)) != ESP_OK) {
-                                       lwsl_err("Unable to store serial in nvm\n");
-                                       goto bail_nvs;
-                               }
-               
-                               nvs_commit(nvh);
-                       }
-
-                       if (lws_spa_get_string(pss->spa, EPN_OPTS)) {
-                               if (lws_nvs_set_str(nvh, "opts", lws_spa_get_string(pss->spa, EPN_OPTS)) != ESP_OK) {
-                                       lwsl_err("Unable to store options in nvm\n");
-                                       goto bail_nvs;
-                               }
-               
-                               nvs_commit(nvh);
-                       }
-               }
-
-               if (lws_spa_get_string(pss->spa, EPN_GROUP)) {
-                       if (lws_nvs_set_str(nvh, "group", lws_spa_get_string(pss->spa, EPN_GROUP)) != ESP_OK) {
-                               lwsl_err("Unable to store group in nvm\n");
-                               goto bail_nvs;
-                       }
-
-                       nvs_commit(nvh);
-               }
-
-               if (lws_spa_get_string(pss->spa, EPN_ROLE)) {
-                       if (lws_nvs_set_str(nvh, "role", lws_spa_get_string(pss->spa, EPN_ROLE)) != ESP_OK) {
-                               lwsl_err("Unable to store group in nvm\n");
-                               goto bail_nvs;
-                       }
-
-                       nvs_commit(nvh);
-               }
-
-               nvs_close(nvh);
-
-               pss->result_len = snprintf(pss->result + LWS_PRE, sizeof(pss->result) - LWS_PRE - 1,
-                               "<html>OK</html>");
-
-               if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
-                       goto bail;
-
-               if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
-                               (unsigned char *)"text/html", 9, &p, end))
-                       goto bail;
-               if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end))
-                       goto bail;
-               if (lws_finalize_http_header(wsi, &p, end))
-                       goto bail;
-
-               n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
-               goto bail;
-
-       case LWS_CALLBACK_HTTP_WRITEABLE:
-               lwsl_debug("LWS_CALLBACK_HTTP_WRITEABLE: sending %d\n",
-                          pss->result_len);
-               if (!pss->result_len)
-                       break;
-               n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
-                             pss->result_len, LWS_WRITE_HTTP);
-               if (n < 0)
-                       return 1;
-
-               vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(3000), 0, vhd,
-                         (TimerCallbackFunction_t)reboot_timer_cb);
-               xTimerStart(vhd->reboot_timer, 0);
-
-               return 1; // hang up since we will reset
-
-       /* ----- client handling ----- */
-
-       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
-               lwsl_notice("Client connection error %s\n", (char *)in);
-               vhd->cwsi = NULL;
-               break;
-
-       case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
-               if (!vhd->autonomous_update)
-                       break;
-
-               {
-                       char pp[20];
-
-                       if (lws_hdr_copy(wsi, pp, sizeof(pp) - 1, WSI_TOKEN_HTTP_CONTENT_LENGTH) < 0)
-                               return -1;
-       
-                       vhd->content_length = atoi(pp);
-                       if (vhd->content_length <= 0 ||
-                           vhd->content_length > vhd->part->size)
-                               return -1;
-
-                       if (esp_ota_begin(vhd->part, (long)-1, &vhd->otahandle) != ESP_OK) {
-                               lwsl_err("OTA: Failed to begin\n");
-                               return 1;
-                       }
-
-                       vhd->file_length = 0;
-                       break;
-               }
-               break;
-
-       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
-               //lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: %ld\n",
-               //          (long)len);
-
-               if (!vhd->autonomous_update) {
-                       if (sizeof(vhd->json) - vhd->json_len - 1 < len)
-                               len = sizeof(vhd->json) - vhd->json_len - 1;
-                       memcpy(vhd->json + vhd->json_len, in, len);
-                       vhd->json_len += len;
-                       vhd->json[vhd->json_len] = '\0';
-                       break;
-               }
-
-               /* autonomous download */
-
-
-               if (vhd->file_length + len > vhd->part->size) {
-                       lwsl_err("OTA: incoming file too large\n");
-                       goto abort_ota;
-               }
-
-               lwsl_debug("writing 0x%lx... 0x%lx\n",
-                          vhd->part->address + vhd->file_length,
-                          vhd->part->address + vhd->file_length + len);
-               if (esp_ota_write(vhd->otahandle, in, len) != ESP_OK) {
-                       lwsl_err("OTA: Failed to write\n");
-                       goto abort_ota;
-               }
-               vhd->file_length += len;
-
-               lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
-               break;
-
-abort_ota:
-               esp_ota_end(vhd->otahandle);
-               vhd->otahandle = 0;
-               vhd->autonomous_update = 0;
-
-               return 1;
-
-       case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
-               {
-                       char *px = (char *)pss->buffer + LWS_PRE;
-                       int lenx = sizeof(pss->buffer) - LWS_PRE - 1;
-
-                       //lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: %d\n", len);
-
-                       if (lws_http_client_read(wsi, &px, &lenx) < 0)
-                               return -1;
-               }
-               break;
-
-       case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
-               lwsl_notice("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
-               vhd->cwsi = NULL;
-               if (!vhd->autonomous_update) {
-
-                       vhd->checked_updates = 1;
-                       puts(vhd->json);
-                       return -1;
-               }
-
-               /* autonomous download */
-
-               lwsl_notice("auton complete\n");
-
-               if (esp_ota_end(vhd->otahandle) != ESP_OK) {
-                       lwsl_err("OTA: end failed\n");
-                       return 1;
-               }
-
-               if (esp_ota_set_boot_partition(vhd->part) != ESP_OK) {
-                       lwsl_err("OTA: set boot part failed\n");
-                       return 1;
-               }
-               vhd->otahandle = 0;
-               vhd->autonomous_update = 0;
-
-               vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, vhd,
-                         (TimerCallbackFunction_t)reboot_timer_cb);
-                       xTimerStart(vhd->reboot_timer, 0);
-               return -1;
-
-       case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
-               lwsl_notice("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n");
-               break;
-
-       case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
-               /* called when our wsi user_space is going to be destroyed */
-               if (pss->spa) {
-                       lws_spa_destroy(pss->spa);
-                       pss->spa = NULL;
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-
-bail:
-       return 1;
-}
-
-#define LWS_PLUGIN_PROTOCOL_ESPLWS_SCAN \
-       { \
-               "esplws-scan", \
-               callback_esplws_scan, \
-               sizeof(struct per_session_data__esplws_scan), \
-               1024, 0, NULL, 900 \
-       }
-
index 046fedc..0d78099 100644 (file)
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
@@ -74,7 +78,7 @@ callback_fts(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                             lws_get_protocol(wsi),sizeof(struct vhd_fts_demo));
                if (!vhd)
-                       return 1;
+                       return 0;
                if (lws_pvo_get_str(in, "indexpath",
                                    (const char **)&vhd->indexpath))
                        return 1;
@@ -158,11 +162,11 @@ reply_404:
 
                n = LWS_WRITE_HTTP;
                if (pss->first)
-                       p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                "{\"indexed\": %d, \"ac\": [", !!pss->result);
 
                while (pss->ac && lws_ptr_diff(end, p) > 256) {
-                       p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                "%c{\"ac\": \"%s\",\"matches\": %d,"
                                "\"agg\": %d, \"elided\": %d}",
                                pss->first ? ' ' : ',', (char *)(pss->ac + 1),
@@ -176,14 +180,14 @@ reply_404:
                if (!pss->ac_done && !pss->ac && pss->fp) {
                        pss->ac_done = 1;
 
-                       p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                          "], \"fp\": [");
                }
 
-               while (pss->fp && lws_ptr_diff(end, p) > 256) {
+               while (pss->fp && lws_ptr_diff_size_t(end, p) > 256) {
                        if (!pss->fp_init_done) {
                                p += lws_snprintf((char *)p,
-                                       lws_ptr_diff(end, p),
+                                               lws_ptr_diff_size_t(end, p),
                                        "%c{\"path\": \"%s\",\"matches\": %d,"
                                        "\"origlines\": %d,"
                                        "\"hits\": [", pss->first ? ' ' : ',',
@@ -201,7 +205,7 @@ reply_404:
                                       lws_ptr_diff(end, p) > 256) {
 
                                        p += lws_snprintf((char *)p,
-                                               lws_ptr_diff(end, p),
+                                                       lws_ptr_diff_size_t(end, p),
                                                "%c\n{\"l\":%d,\"o\":%d,"
                                                "\"s\":\"%s\"}",
                                                !pss->done ? ' ' : ',',
@@ -224,12 +228,12 @@ reply_404:
 
                if (!pss->ac && !pss->fp) {
                        n = LWS_WRITE_HTTP_FINAL;
-                       p += lws_snprintf((char *)p, lws_ptr_diff(end, p),
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                                                "]}");
                }
 
                if (lws_write(wsi, (uint8_t *)start,
-                             lws_ptr_diff(p, start), n) !=
+                               lws_ptr_diff_size_t(p, start), (enum lws_write_protocol)n) !=
                                              lws_ptr_diff(p, start))
                        return 1;
 
@@ -262,32 +266,22 @@ reply_404:
 
 #if !defined (LWS_PLUGIN_STATIC)
 
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols fulltext_demo_protocols[] = {
        LWS_PLUGIN_PROTOCOL_FULLTEXT_DEMO
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_fulltext_demo(struct lws_context *context,
-                       struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_fulltext_demo(struct lws_context *context)
-{
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t fulltext_demo = {
+       .hdr = {
+               "fulltext demo",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = fulltext_demo_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(fulltext_demo_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
 #endif
index 70f501c..9929109 100644 (file)
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
@@ -82,7 +86,7 @@ __mirror_rxflow_instance(struct mirror_instance *mi, int enable)
                lws_rx_flow_control(pss->wsi, enable);
        } lws_end_foreach_ll(pss, same_mi_pss_list);
 
-       mi->rx_enabled = enable;
+       mi->rx_enabled = (char)enable;
 }
 
 /*
@@ -206,17 +210,26 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
        switch (reason) {
        case LWS_CALLBACK_ESTABLISHED:
                lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
+               if (!v) {
+                       lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                                       lws_get_protocol(wsi),
+                                       sizeof(struct per_vhost_data__lws_mirror));
+                       v = (struct per_vhost_data__lws_mirror *)
+                                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
+                                                                lws_get_protocol(wsi));
+                       lws_pthread_mutex_init(&v->lock);
+               }
 
                /*
                 * mirror instance name... defaults to "", but if URL includes
                 * "?mirror=xxx", will be "xxx"
                 */
-               name[0] = '\0';
-               if (!lws_get_urlarg_by_name(wsi, "mirror", name,
-                                          sizeof(name) - 1))
+
+               if (lws_get_urlarg_by_name_safe(wsi, "mirror", name,
+                                               sizeof(name) - 1) < 0) {
                        lwsl_debug("get urlarg failed\n");
-               if (strchr(name, '='))
-                       pn = strchr(name, '=') + 1;
+                       name[0] = '\0';
+               }
 
                //lwsl_notice("%s: mirror name '%s'\n", __func__, pn);
 
@@ -332,13 +345,17 @@ bail1:
                return 1; /* disallow compression */
 
        case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
-               lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+               if (!v) {
+                       lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                                lws_get_protocol(wsi),
                                sizeof(struct per_vhost_data__lws_mirror));
-               v = (struct per_vhost_data__lws_mirror *)
+                       v = (struct per_vhost_data__lws_mirror *)
                                lws_protocol_vh_priv_get(lws_get_vhost(wsi),
                                                         lws_get_protocol(wsi));
-               lws_pthread_mutex_init(&v->lock);
+                       if (!v)
+                               return 0;
+                       lws_pthread_mutex_init(&v->lock);
+               }
                break;
 
        case LWS_CALLBACK_PROTOCOL_DESTROY:
@@ -467,31 +484,22 @@ done2:
 
 #if !defined (LWS_PLUGIN_STATIC)
 
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols lws_mirror_protocols[] = {
        LWS_PLUGIN_PROTOCOL_MIRROR
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_lws_mirror(struct lws_context *context,
-                            struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t lws_mirror = {
+       .hdr = {
+               "lws mirror",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = lws_mirror_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(lws_mirror_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_lws_mirror(struct lws_context *context)
-{
-       return 0;
-}
 #endif
diff --git a/plugins/protocol_lws_openmetrics_export.c b/plugins/protocol_lws_openmetrics_export.c
new file mode 100644 (file)
index 0000000..f7fb601
--- /dev/null
@@ -0,0 +1,1200 @@
+/*
+ * libwebsockets-test-server - libwebsockets test implementation
+ *
+ * Written in 2010-2021 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The person who associated a work with this deed has dedicated
+ * the work to the public domain by waiving all of his or her rights
+ * to the work worldwide under copyright law, including all related
+ * and neighboring rights, to the extent allowed by law. You can copy,
+ * modify, distribute and perform the work, even for commercial purposes,
+ * all without asking permission.
+ *
+ * The test apps are intended to be adapted for use in your code, which
+ * may be proprietary.  So unlike the library itself, they are licensed
+ * Public Domain.
+ *
+ * Scrapeable, proxiable OpenMetrics metrics (compatible with Prometheus)
+ *
+ * https://tools.ietf.org/html/draft-richih-opsawg-openmetrics-00
+ *
+ * This plugin provides four protocols related to openmetrics handling:
+ *
+ * 1) "lws-openmetrics" direct http listener so scraper can directly get metrics
+ *
+ * 2) "lws-openmetrics-prox-agg" metrics proxy server that scraper can connect
+ *    to locally to proxy through to connected remote clients at 3)
+ *
+ * 3) "lws-openmetrics-prox-server" metrics proxy server that remote clients can
+ *    connect to, providing a path where scrapers at 2) can get metrics from
+ *    clients connected us
+ *
+ * 4) "lws-openmetrics-prox-client" nailed-up metrics proxy client that tries to
+ *    keep up a connection to the server at 3), allowing to scraper to reach
+ *    clients that have no reachable way to serve.
+ *
+ * These are provided like this to maximize flexibility in being able to add
+ * openmetrics serving, proxying, or client->proxy to existing lws code.
+ *
+ * Openmetrics supports a "metric" at the top of its report that describes the
+ * source aka "target metadata".
+ *
+ * Since we want to enable collection from devices that are not externally
+ * reachable, we must provide a reachable server that the clients can attach to
+ * and have their stats aggregated and then read by Prometheus or whatever.
+ * Openmetrics says that it wants to present the aggregated stats in a flat
+ * summary with only the aggregator's "target metadata" and contributor targets
+ * getting their data tagged with the source
+ *
+ * "The above discussion is in the context of individual exposers.  An
+ *  exposition from a general purpose monitoring system may contain
+ *  metrics from many individual targets, and thus may expose multiple
+ *  target info Metrics.  The metrics may already have had target
+ *  metadata added to them as labels as part of ingestion.  The metric
+ *  names MUST NOT be varied based on target metadata.  For example it
+ *  would be incorrect for all metrics to end up being prefixed with
+ *  staging_ even if they all originated from targets in a staging
+ *  environment)."
+ */
+
+#if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
+#define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
+#define LWS_INTERNAL
+#endif
+#include <libwebsockets.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#if !defined(WIN32)
+#include <unistd.h>
+#endif
+#include <assert.h>
+
+struct vhd {
+       struct lws_context      *cx;
+       struct lws_vhost        *vhost;
+
+       char                    ws_server_uri[128];
+       char                    metrics_proxy_path[128];
+       char                    ba_secret[128];
+
+       const char              *proxy_side_bind_name;
+       /**< name used to bind the two halves of the proxy together, must be
+        * the same name given in a pvo for both "lws-openmetrics-prox-agg"
+        * (the side local to the scraper) and "lws-openmetrics-prox-server"
+        * (the side the clients connect to)
+        */
+
+       char                    sanity[8];
+
+       lws_dll2_owner_t        clients;
+
+       lws_sorted_usec_list_t  sul;         /* schedule connection retry */
+
+       struct vhd              *bind_partner_vhd;
+
+       struct lws              *wsi;        /* related wsi if any */
+       uint16_t                retry_count; /* count of consequetive retries */
+};
+
+struct pss {
+       lws_dll2_t              list;
+       char                    proxy_path[64];
+       struct lwsac            *ac;    /* the translated metrics, one ac per line */
+       struct lwsac            *walk;  /* iterator for ac when writing */
+       size_t                  tot;    /* content-length computation */
+       struct lws              *wsi;
+
+       uint8_t                 greet:1; /* set if client needs to send proxy path */
+       uint8_t                 trigger:1; /* we want to ask the client to dump */
+};
+
+#if defined(LWS_WITH_CLIENT)
+static const uint32_t backoff_ms[] = { 1000, 2000, 3000, 4000, 5000 };
+
+static const lws_retry_bo_t retry = {
+       .retry_ms_table                 = backoff_ms,
+       .retry_ms_table_count           = LWS_ARRAY_SIZE(backoff_ms),
+       .conceal_count                  = LWS_ARRAY_SIZE(backoff_ms),
+
+       .secs_since_valid_ping          = 400,  /* force PINGs after secs idle */
+       .secs_since_valid_hangup        = 400, /* hangup after secs idle */
+
+       .jitter_percent                 = 0,
+};
+
+static void
+omc_connect_client(lws_sorted_usec_list_t *sul)
+{
+       struct vhd *vhd = lws_container_of(sul, struct vhd, sul);
+       struct lws_client_connect_info i;
+       const char *prot;
+       char url[128];
+
+       memset(&i, 0, sizeof(i));
+
+       lwsl_notice("%s: %s %s %s\n", __func__, vhd->ws_server_uri, vhd->metrics_proxy_path, vhd->ba_secret);
+
+       lws_strncpy(url, vhd->ws_server_uri, sizeof(url));
+
+       if (lws_parse_uri(url, &prot, &i.address, &i.port, &i.path)) {
+               lwsl_err("%s: unable to parse uri %s\n", __func__,
+                        vhd->ws_server_uri);
+               return;
+       }
+
+       i.context               = vhd->cx;
+       i.origin                = i.address;
+       i.host                  = i.address;
+       i.ssl_connection        = LCCSCF_USE_SSL;
+       i.protocol              = "lws-openmetrics-prox-server"; /* public subprot */
+       i.local_protocol_name   = "lws-openmetrics-prox-client";
+       i.pwsi                  = &vhd->wsi;
+       i.retry_and_idle_policy = &retry;
+       i.userdata              = vhd;
+       i.vhost                 = vhd->vhost;
+
+       lwsl_notice("%s: %s %u %s\n", __func__, i.address, i.port, i.path);
+
+       if (lws_client_connect_via_info(&i))
+               return;
+
+       /*
+        * Failed... schedule a retry... we can't use the _retry_wsi()
+        * convenience wrapper api here because no valid wsi at this
+        * point.
+        */
+       if (!lws_retry_sul_schedule(vhd->cx, 0, sul, &retry,
+                                   omc_connect_client, &vhd->retry_count))
+               return;
+
+       vhd->retry_count = 0;
+       lws_retry_sul_schedule(vhd->cx, 0, sul, &retry,
+                              omc_connect_client, &vhd->retry_count);
+}
+#endif
+
+static void
+openmetrics_san(char *nm, size_t nl)
+{
+       size_t m;
+
+       /* Openmetrics has a very restricted token charset */
+
+       for (m = 0; m < nl; m++)
+               if ((nm[m] < 'A' || nm[m] > 'Z') &&
+                   (nm[m] < 'a' || nm[m] > 'z') &&
+                   (nm[m] < '0' || nm[m] > '9') &&
+                   nm[m] != '_')
+                       nm[m] = '_';
+}
+
+static int
+lws_metrics_om_format_agg(lws_metric_pub_t *pub, const char *nm, lws_usec_t now,
+                         int gng, char *buf, size_t len)
+{
+       const char *_gng = gng ? "_nogo" : "_go";
+       char *end = buf + len - 1, *obuf = buf;
+
+       if (pub->flags & LWSMTFL_REPORT_ONLY_GO)
+               _gng = "";
+
+       if (!(pub->flags & LWSMTFL_REPORT_MEAN)) {
+               /* only the sum is meaningful */
+               if (pub->flags & LWSMTFL_REPORT_DUTY_WALLCLOCK_US) {
+                       buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                               "%s_count %u\n"
+                               "%s_us_sum %llu\n"
+                               "%s_created %lu.%06u\n",
+                               nm, (unsigned int)pub->u.agg.count[gng],
+                               nm, (unsigned long long)pub->u.agg.sum[gng],
+                               nm, (unsigned long)(pub->us_first / 1000000),
+                                   (unsigned int)(pub->us_first % 1000000));
+
+                       return lws_ptr_diff(buf, obuf);
+               }
+
+               /* it's a monotonic ordinal, like total tx */
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                                   "%s%s_count %u\n"
+                                   "%s%s_sum %llu\n",
+                                   nm, _gng,
+                                   (unsigned int)pub->u.agg.count[gng],
+                                   nm, _gng,
+                                   (unsigned long long)pub->u.agg.sum[gng]);
+
+       } else
+               buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
+                                   "%s%s_count %u\n"
+                                   "%s%s_mean %llu\n",
+                                   nm, _gng,
+                                   (unsigned int)pub->u.agg.count[gng],
+                                   nm, _gng, (unsigned long long)
+                                   (pub->u.agg.count[gng] ?
+                                               pub->u.agg.sum[gng] /
+                                               pub->u.agg.count[gng] : 0));
+
+       return lws_ptr_diff(buf, obuf);
+}
+
+static int
+lws_metrics_om_ac_stash(struct pss *pss, const char *buf, size_t len)
+{
+       char *q;
+
+       q = lwsac_use(&pss->ac, LWS_PRE + len + 2, LWS_PRE + len + 2);
+       if (!q) {
+               lwsac_free(&pss->ac);
+
+               return -1;
+       }
+       q[LWS_PRE] = (char)((len >> 8) & 0xff);
+       q[LWS_PRE + 1] = (char)(len & 0xff);
+       memcpy(q + LWS_PRE + 2, buf, len);
+       pss->tot += len;
+
+       return 0;
+}
+
+/*
+ * We have to do the ac listing at this level, because there can be too large
+ * a number to metrics tags to iterate that can fit in a reasonable buffer.
+ */
+
+static int
+lws_metrics_om_format(struct pss *pss, lws_metric_pub_t *pub, const char *nm)
+{
+       char buf[1200], *p = buf, *end = buf + sizeof(buf) - 1, tmp[512];
+       lws_usec_t t = lws_now_usecs();
+
+       if (pub->flags & LWSMTFL_REPORT_HIST) {
+               lws_metric_bucket_t *buck = pub->u.hist.head;
+
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                 "%s_count %llu\n",
+                                 nm, (unsigned long long)
+                                 pub->u.hist.total_count);
+
+               while (buck) {
+                       lws_strncpy(tmp, lws_metric_bucket_name(buck),
+                                   sizeof(tmp));
+
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                         "%s{%s} %llu\n", nm, tmp,
+                                         (unsigned long long)buck->count);
+
+                       lws_metrics_om_ac_stash(pss, buf,
+                                               lws_ptr_diff_size_t(p, buf));
+                       p = buf;
+
+                       buck = buck->next;
+               }
+
+               goto happy;
+       }
+
+       if (!pub->u.agg.count[METRES_GO] && !pub->u.agg.count[METRES_NOGO])
+               return 0;
+
+       if (pub->u.agg.count[METRES_GO])
+               p += lws_metrics_om_format_agg(pub, nm, t, METRES_GO, p,
+                                              lws_ptr_diff_size_t(end, p));
+
+       if (!(pub->flags & LWSMTFL_REPORT_ONLY_GO) &&
+           pub->u.agg.count[METRES_NOGO])
+               p += lws_metrics_om_format_agg(pub, nm, t, METRES_NOGO, p,
+                                              lws_ptr_diff_size_t(end, p));
+
+       if (pub->flags & LWSMTFL_REPORT_MEAN)
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                 "%s_min %llu\n"
+                                 "%s_max %llu\n",
+                                 nm, (unsigned long long)pub->u.agg.min,
+                                 nm, (unsigned long long)pub->u.agg.max);
+
+happy:
+       return lws_metrics_om_ac_stash(pss, buf, lws_ptr_diff_size_t(p, buf));
+}
+
+static int
+append_om_metric(lws_metric_pub_t *pub, void *user)
+{
+       struct pss *pss = (struct pss *)user;
+       char nm[64];
+       size_t nl;
+
+       /*
+        * Convert lws_metrics to openmetrics metrics data, stashing into an
+        * lwsac without backfill.  Since it's not backfilling, use areas are in
+        * linear sequence simplifying walking them.  Limiting the lwsac alloc
+        * to less than a typical mtu means we can write one per write
+        * efficiently
+        */
+
+       lws_strncpy(nm, pub->name, sizeof(nm));
+       nl = strlen(nm);
+
+       openmetrics_san(nm, nl);
+
+       return lws_metrics_om_format(pss, pub, nm);
+}
+
+#if defined(__linux__)
+static int
+grabfile(const char *fi, char *buf, size_t len)
+{
+       int n, fd = lws_open(fi, LWS_O_RDONLY);
+
+       buf[0] = '\0';
+       if (fd < 0)
+               return -1;
+
+       n = (int)read(fd, buf, len - 1);
+       close(fd);
+       if (n < 0) {
+               buf[0] = '\0';
+               return -1;
+       }
+
+       buf[n] = '\0';
+       if (n > 0 && buf[n - 1] == '\n')
+               buf[--n] = '\0';
+
+       return n;
+}
+#endif
+
+/*
+ * Let's pregenerate the output into an lwsac all at once and
+ * then spool it back to the peer afterwards
+ *
+ * - there's not going to be that much of it (a few kB)
+ * - we then know the content-length for the headers
+ * - it's stretchy to arbitrary numbers of metrics
+ * - lwsac block list provides the per-metric structure to
+ *   hold the data in a way we can walk to write it simply
+ */
+
+int
+ome_prepare(struct lws_context *ctx, struct pss *pss)
+{
+       char buf[1224], *start = buf + LWS_PRE, *p = start,
+            *end = buf + sizeof(buf) - 1;
+       char hn[64];
+
+       pss->tot = 0;
+
+       /*
+        * Target metadata
+        */
+
+       hn[0] = '\0';
+       gethostname(hn, sizeof(hn) - 1);
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                         "# TYPE target info\n"
+                         "# HELP target Target metadata\n"
+                         "target_info{hostname=\"%s\"", hn);
+
+#if defined(__linux__)
+       if (grabfile("/proc/self/cmdline", hn, sizeof(hn)))
+               p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
+                                 ",cmdline=\"%s\"", hn);
+#endif
+
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "} 1\n");
+
+       if (lws_metrics_om_ac_stash(pss, (const char *)buf + LWS_PRE,
+                                   lws_ptr_diff_size_t(p, buf + LWS_PRE)))
+               return 1;
+
+       /* lws version */
+
+       p = start;
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                         "# TYPE lws_info info\n"
+                         "# HELP lws_info Version of lws producing this\n"
+                         "lws_info{version=\"%s\"} 1\n", LWS_BUILD_HASH);
+       if (lws_metrics_om_ac_stash(pss, (const char *)buf + LWS_PRE,
+                                   lws_ptr_diff_size_t(p, buf + LWS_PRE)))
+               return 1;
+
+       /* system scalars */
+
+#if defined(__linux__)
+       if (grabfile("/proc/loadavg", hn, sizeof(hn))) {
+               char *sp = strchr(hn, ' ');
+               if (sp) {
+                       p = start;
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                         "load_1m %.*s\n",
+                                         lws_ptr_diff(sp, hn), hn);
+                       if (lws_metrics_om_ac_stash(pss,
+                                                   (char *)buf + LWS_PRE,
+                                                   lws_ptr_diff_size_t(p,
+                                                               start)))
+                               return 1;
+               }
+       }
+#endif
+
+       if (lws_metrics_foreach(ctx, pss, append_om_metric))
+               return 1;
+
+       p = start;
+       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                         "# EOF\n");
+       if (lws_metrics_om_ac_stash(pss, (char *)buf + LWS_PRE,
+                                   lws_ptr_diff_size_t(p, buf + LWS_PRE)))
+               return 1;
+
+       pss->walk = pss->ac;
+
+       return 0;
+}
+
+#if defined(LWS_WITH_SERVER)
+
+/* 1) direct http export for scraper */
+
+static int
+callback_lws_openmetrics_export(struct lws *wsi,
+                               enum lws_callback_reasons reason,
+                               void *user, void *in, size_t len)
+{
+       unsigned char buf[1224], *start = buf + LWS_PRE, *p = start,
+                     *end = buf + sizeof(buf) - 1, *ip;
+       struct lws_context *cx = lws_get_context(wsi);
+       struct pss *pss = (struct pss *)user;
+       unsigned int m, wm;
+
+       switch (reason) {
+       case LWS_CALLBACK_HTTP:
+
+               ome_prepare(cx, pss);
+
+               p = start;
+               if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
+                                               "application/openmetrics-text; "
+                                               "version=1.0.0; charset=utf-8",
+                                               pss->tot, &p, end) ||
+                   lws_finalize_write_http_header(wsi, start, &p, end))
+                       return 1;
+
+               lws_callback_on_writable(wsi);
+
+               return 0;
+
+       case LWS_CALLBACK_CLOSED_HTTP:
+               lwsac_free(&pss->ac);
+               break;
+
+       case LWS_CALLBACK_HTTP_WRITEABLE:
+               if (!pss->walk)
+                       return 0;
+
+               do {
+                       ip = (uint8_t *)pss->walk +
+                               lwsac_sizeof(pss->walk == pss->ac) + LWS_PRE;
+                       m = (unsigned int)((ip[0] << 8) | ip[1]);
+
+                       /* coverity */
+                       if (m > lwsac_get_tail_pos(pss->walk) -
+                               lwsac_sizeof(pss->walk == pss->ac))
+                               return -1;
+
+                       if (lws_ptr_diff_size_t(end, p) < m)
+                               break;
+
+                       memcpy(p, ip + 2, m);
+                       p += m;
+
+                       pss->walk = lwsac_get_next(pss->walk);
+               } while (pss->walk);
+
+               if (!lws_ptr_diff_size_t(p, start)) {
+                       lwsl_err("%s: stuck\n", __func__);
+                       return -1;
+               }
+
+               wm = pss->walk ? LWS_WRITE_HTTP : LWS_WRITE_HTTP_FINAL;
+
+               if (lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
+                             (enum lws_write_protocol)wm) < 0)
+                       return 1;
+
+               if (!pss->walk) {
+                        if (lws_http_transaction_completed(wsi))
+                               return -1;
+               } else
+                       lws_callback_on_writable(wsi);
+
+               return 0;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+static struct pss *
+omc_lws_om_get_other_side_pss_client(struct vhd *vhd, struct pss *pss)
+{
+       /*
+        * Search through our partner's clients list looking for one with the
+        * same proxy path
+        */
+       lws_start_foreach_dll(struct lws_dll2 *, d,
+                       vhd->bind_partner_vhd->clients.head) {
+               struct pss *apss = lws_container_of(d, struct pss, list);
+
+               if (!strcmp(pss->proxy_path, apss->proxy_path))
+                       return apss;
+
+       } lws_end_foreach_dll(d);
+
+       return NULL;
+}
+
+/* 2) "lws-openmetrics-prox-agg": http server export via proxy to connected clients */
+
+static int
+callback_lws_openmetrics_prox_agg(struct lws *wsi,
+                                 enum lws_callback_reasons reason,
+                                 void *user, void *in, size_t len)
+{
+       unsigned char buf[1224], *start = buf + LWS_PRE, *p = start,
+                     *end = buf + sizeof(buf) - 1, *ip;
+       struct vhd *vhd = (struct vhd *)lws_protocol_vh_priv_get(
+                               lws_get_vhost(wsi), lws_get_protocol(wsi));
+       struct lws_context *cx = lws_get_context(wsi);
+       struct pss *pss = (struct pss *)user, *partner_pss;
+       unsigned int m, wm;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_PROTOCOL_INIT:
+               lwsl_notice("%s: PROTOCOL_INIT on %s\n", __func__, lws_vh_tag(lws_get_vhost(wsi)));
+               /*
+                * We get told what to do when we are bound to the vhost
+                */
+               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                               lws_get_protocol(wsi), sizeof(struct vhd));
+               if (!vhd) {
+                       lwsl_err("%s: vhd alloc failed\n", __func__);
+                       return 0;
+               }
+
+               vhd->cx = cx;
+
+               /*
+                * Try to bind to the counterpart server in the proxy, binding
+                * to the right one by having a common bind name set in a pvo.
+                * We don't know who will get instantiated last, so both parts
+                * try to bind if not already bound
+                */
+
+               if (!lws_pvo_get_str(in, "proxy-side-bind-name",
+                                    &vhd->proxy_side_bind_name)) {
+                       /*
+                        * Attempt to find the vhd that belongs to a vhost
+                        * that has instantiated protocol
+                        * "lws-openmetrics-prox-server", and has set pvo
+                        * "proxy-side-bind-name" on it to whatever our
+                        * vhd->proxy_side_bind_name was also set to.
+                        *
+                        * If found, inform the two sides of the same proxy
+                        * what their partner vhd is
+                        */
+                       lws_strncpy(vhd->sanity, "isagg", sizeof(vhd->sanity));
+                       vhd->bind_partner_vhd = lws_vhd_find_by_pvo(cx,
+                                               "lws-openmetrics-prox-server",
+                                               "proxy-side-bind-name",
+                                               vhd->proxy_side_bind_name);
+                       if (vhd->bind_partner_vhd) {
+                               assert(!strcmp(vhd->bind_partner_vhd->sanity, "isws"));
+                               lwsl_notice("%s: proxy binding OK\n", __func__);
+                               vhd->bind_partner_vhd->bind_partner_vhd = vhd;
+                       }
+               } else {
+                       lwsl_warn("%s: proxy-side-bind-name required\n", __func__);
+                       return 0;
+               }
+
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               if (vhd)
+                       lws_sul_cancel(&vhd->sul);
+               break;
+
+       case LWS_CALLBACK_HTTP:
+
+               /*
+                * The scraper has connected to us, the local side of the proxy,
+                * we need to match what it wants to
+                */
+
+               if (!vhd->bind_partner_vhd)
+                       return 0;
+
+               lws_strnncpy(pss->proxy_path, (const char *)in, len,
+                            sizeof(pss->proxy_path));
+
+               if (pss->list.owner) {
+                       lwsl_warn("%s: double HTTP?\n", __func__);
+                       return 0;
+               }
+
+               pss->wsi = wsi;
+
+               lws_start_foreach_dll(struct lws_dll2 *, d,
+                                     vhd->bind_partner_vhd->clients.head) {
+                       struct pss *apss = lws_container_of(d, struct pss, list);
+
+                       if (!strcmp((const char *)in, apss->proxy_path)) {
+                               apss->trigger = 1;
+                               lws_callback_on_writable(apss->wsi);
+
+                               /* let's add him on the http server vhd list */
+
+                               lws_dll2_add_tail(&pss->list, &vhd->clients);
+                               return 0;
+                       }
+
+               } lws_end_foreach_dll(d);
+
+               return 0;
+
+       case LWS_CALLBACK_CLOSED_HTTP:
+               lwsac_free(&pss->ac);
+               lws_dll2_remove(&pss->list);
+               break;
+
+       case LWS_CALLBACK_HTTP_WRITEABLE:
+
+               if (!pss->walk)
+                       return 0;
+
+               /* locate the wss side if it's still around */
+
+               partner_pss = omc_lws_om_get_other_side_pss_client(vhd, pss);
+               if (!partner_pss)
+                       return -1;
+
+               do {
+                       ip = (uint8_t *)pss->walk +
+                               lwsac_sizeof(pss->walk == partner_pss->ac) + LWS_PRE;
+                       m = (unsigned int)((ip[0] << 8) | ip[1]);
+
+                       /* coverity */
+                       if (m > lwsac_get_tail_pos(pss->walk) -
+                               lwsac_sizeof(pss->walk == partner_pss->ac))
+                               return -1;
+
+                       if (lws_ptr_diff_size_t(end, p) < m)
+                               break;
+
+                       memcpy(p, ip + 2, m);
+                       p += m;
+
+                       pss->walk = lwsac_get_next(pss->walk);
+               } while (pss->walk);
+
+               if (!lws_ptr_diff_size_t(p, start)) {
+                       lwsl_err("%s: stuck\n", __func__);
+                       return -1;
+               }
+
+               wm = pss->walk ? LWS_WRITE_HTTP : LWS_WRITE_HTTP_FINAL;
+
+               if (lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
+                             (enum lws_write_protocol)wm) < 0)
+                       return 1;
+
+               if (!pss->walk) {
+                       lwsl_info("%s: whole msg proxied to scraper\n", __func__);
+                       lws_dll2_remove(&pss->list);
+                       lwsac_free(&partner_pss->ac);
+//                     if (lws_http_transaction_completed(wsi))
+                       return -1;
+               } else
+                       lws_callback_on_writable(wsi);
+
+               return 0;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+
+/* 3) "lws-openmetrics-prox-server": ws server side of metrics proxy, for
+ *    ws clients to connect to */
+
+static int
+callback_lws_openmetrics_prox_server(struct lws *wsi,
+                                    enum lws_callback_reasons reason,
+                                    void *user, void *in, size_t len)
+{
+       unsigned char buf[1224], *start = buf + LWS_PRE, *p = start,
+                     *end = buf + sizeof(buf) - 1;
+       struct vhd *vhd = (struct vhd *)lws_protocol_vh_priv_get(
+                               lws_get_vhost(wsi), lws_get_protocol(wsi));
+       struct lws_context *cx = lws_get_context(wsi);
+       struct pss *pss = (struct pss *)user, *partner_pss;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_PROTOCOL_INIT:
+               /*
+                * We get told what to do when we are bound to the vhost
+                */
+
+               lwsl_notice("%s: PROTOCOL_INIT on %s\n", __func__, lws_vh_tag(lws_get_vhost(wsi)));
+
+               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                               lws_get_protocol(wsi), sizeof(struct vhd));
+               if (!vhd) {
+                       lwsl_err("%s: vhd alloc failed\n", __func__);
+                       return 0;
+               }
+
+               vhd->cx = cx;
+
+               /*
+                * Try to bind to the counterpart server in the proxy, binding
+                * to the right one by having a common bind name set in a pvo.
+                * We don't know who will get instantiated last, so both parts
+                * try to bind if not already bound
+                */
+
+               if (!lws_pvo_get_str(in, "proxy-side-bind-name",
+                                    &vhd->proxy_side_bind_name)) {
+                       /*
+                        * Attempt to find the vhd that belongs to a vhost
+                        * that has instantiated protocol
+                        * "lws-openmetrics-prox-server", and has set pvo
+                        * "proxy-side-bind-name" on it to whatever our
+                        * vhd->proxy_side_bind_name was also set to.
+                        *
+                        * If found, inform the two sides of the same proxy
+                        * what their partner vhd is
+                        */
+                       lws_strncpy(vhd->sanity, "isws", sizeof(vhd->sanity));
+                       vhd->bind_partner_vhd = lws_vhd_find_by_pvo(cx,
+                                               "lws-openmetrics-prox-agg",
+                                               "proxy-side-bind-name",
+                                               vhd->proxy_side_bind_name);
+                       if (vhd->bind_partner_vhd) {
+                               assert(!strcmp(vhd->bind_partner_vhd->sanity, "isagg"));
+                               lwsl_notice("%s: proxy binding OK\n", __func__);
+                               vhd->bind_partner_vhd->bind_partner_vhd = vhd;
+                       }
+               } else {
+                       lwsl_warn("%s: proxy-side-bind-name required\n", __func__);
+                       return 0;
+               }
+
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               break;
+
+       case LWS_CALLBACK_ESTABLISHED:
+               /*
+                * a client has joined... we need to add his pss to our list
+                * of live, joined clients
+                */
+
+               /* mark us as waiting for the reference name from the client */
+               pss->greet = 1;
+               pss->wsi = wsi;
+               lws_validity_confirmed(wsi);
+
+               return 0;
+
+       case LWS_CALLBACK_CLOSED:
+               /*
+                * a client has parted
+                */
+               lws_dll2_remove(&pss->list);
+               lwsl_warn("%s: client %s left (%u)\n", __func__,
+                               pss->proxy_path,
+                               (unsigned int)vhd->clients.count);
+               lwsac_free(&pss->ac);
+
+               /* let's kill the scraper connection accordingly, if still up */
+               partner_pss = omc_lws_om_get_other_side_pss_client(vhd, pss);
+               if (partner_pss)
+                       lws_wsi_close(partner_pss->wsi, LWS_TO_KILL_ASYNC);
+               break;
+
+       case LWS_CALLBACK_RECEIVE:
+               if (pss->greet) {
+                       pss->greet = 0;
+                       lws_strnncpy(pss->proxy_path, (const char *)in, len,
+                                    sizeof(pss->proxy_path));
+
+                       lws_validity_confirmed(wsi);
+                       lwsl_notice("%s: received greet '%s'\n", __func__,
+                                   pss->proxy_path);
+                       /*
+                        * we need to add his pss to our list of configured,
+                        * live, joined clients
+                        */
+                       lws_dll2_add_tail(&pss->list, &vhd->clients);
+                       return 0;
+               }
+
+               /*
+                * He's sending us his results... let's collect chunks into the
+                * pss lwsac before worrying about anything else
+                */
+
+               if (lws_is_first_fragment(wsi))
+                       pss->tot = 0;
+
+               lws_metrics_om_ac_stash(pss, (const char *)in, len);
+
+               if (lws_is_final_fragment(wsi)) {
+                       struct pss *partner_pss;
+
+                       lwsl_info("%s: ws side received complete msg\n",
+                                       __func__);
+
+                       /* the lwsac is complete */
+                       pss->walk = pss->ac;
+                       partner_pss = omc_lws_om_get_other_side_pss_client(vhd, pss);
+                       if (!partner_pss) {
+                               lwsl_notice("%s: no partner A\n", __func__);
+                               return -1;
+                       }
+
+                       /* indicate to scraper side we want to issue now */
+
+                       p = start;
+                       if (lws_add_http_common_headers(partner_pss->wsi, HTTP_STATUS_OK,
+                                                       "application/openmetrics-text; "
+                                                       "version=1.0.0; charset=utf-8",
+                                                       pss->tot, &p, end) ||
+                           lws_finalize_write_http_header(partner_pss->wsi,
+                                                           start, &p, end))
+                               return -1;
+
+                       /* indicate to scraper side we want to issue now */
+
+                       partner_pss->walk = pss->ac;
+                       partner_pss->trigger = 1;
+                       lws_callback_on_writable(partner_pss->wsi);
+               }
+
+               return 0;
+
+       case LWS_CALLBACK_SERVER_WRITEABLE:
+               if (!pss->trigger)
+                       return 0;
+
+               pss->trigger = 0;
+
+               partner_pss = omc_lws_om_get_other_side_pss_client(vhd, pss);
+               if (!partner_pss) {
+                       lwsl_err("%s: no partner\n", __func__);
+                       return 0;
+               }
+
+               lwsl_info("%s: sending trigger to client\n", __func__);
+
+               *start = 'x';
+               if (lws_write(wsi, start, 1,
+                             (enum lws_write_protocol)LWS_WRITE_TEXT) < 0)
+                       return 1;
+
+               lws_validity_confirmed(wsi);
+
+               return 0;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+}
+#endif
+
+#if defined(LWS_WITH_CLIENT) && defined(LWS_ROLE_WS)
+
+/* 4) ws client that keeps wss connection up to metrics proxy ws server */
+
+static int
+callback_lws_openmetrics_prox_client(struct lws *wsi,
+                                    enum lws_callback_reasons reason,
+                                    void *user, void *in, size_t len)
+{
+       unsigned char buf[1224], *start = buf + LWS_PRE, *p = start,
+                     *end = buf + sizeof(buf) - 1, *ip;
+       struct vhd *vhd = (struct vhd *)lws_protocol_vh_priv_get(
+                               lws_get_vhost(wsi), lws_get_protocol(wsi));
+       struct lws_context *cx = lws_get_context(wsi);
+       struct pss *pss = (struct pss *)user;
+       unsigned int m, wm;
+       const char *cp;
+       char first;
+
+       switch (reason) {
+
+       case LWS_CALLBACK_PROTOCOL_INIT:
+
+               lwsl_notice("%s: PROTOCOL_INIT on %s\n", __func__,
+                                       lws_vh_tag(lws_get_vhost(wsi)));
+
+
+               /*
+                * We get told what to do when we are bound to the vhost
+                */
+               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                               lws_get_protocol(wsi), sizeof(struct vhd));
+               if (!vhd)
+                       return 0;
+
+               vhd->cx = cx;
+               vhd->vhost = lws_get_vhost(wsi);
+
+               /* the proxy server uri */
+
+               if (lws_pvo_get_str(in, "ws-server-uri", &cp)) {
+                       lwsl_warn("%s: ws-server-uri pvo required\n", __func__);
+
+                       return 0;
+               }
+               lws_strncpy(vhd->ws_server_uri, cp, sizeof(vhd->ws_server_uri));
+
+               /* how we should be referenced at the proxy */
+
+               if (lws_pvo_get_str(in, "metrics-proxy-path", &cp)) {
+                       lwsl_err("%s: metrics-proxy-path pvo required\n", __func__);
+
+                       return 1;
+               }
+               lws_strncpy(vhd->metrics_proxy_path, cp, sizeof(vhd->metrics_proxy_path));
+
+               /* the shared secret to authenticate us as allowed to join */
+
+               if (lws_pvo_get_str(in, "ba-secret", &cp)) {
+                       lwsl_err("%s: ba-secret pvo required\n", __func__);
+
+                       return 1;
+               }
+               lws_strncpy(vhd->ba_secret, cp, sizeof(vhd->ba_secret));
+
+               lwsl_notice("%s: scheduling connect %s %s %s\n", __func__,
+                               vhd->ws_server_uri, vhd->metrics_proxy_path, vhd->ba_secret);
+
+               lws_validity_confirmed(wsi);
+               lws_sul_schedule(cx, 0, &vhd->sul, omc_connect_client, 1);
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               if (vhd)
+                       lws_sul_cancel(&vhd->sul);
+               break;
+
+       case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
+       {
+               unsigned char **pp = (unsigned char **)in, *pend = (*pp) + len;
+               char b[128];
+
+               /* authorize ourselves to the metrics proxy using basic auth */
+
+               if (lws_http_basic_auth_gen("metricsclient", vhd->ba_secret,
+                                           b, sizeof(b)))
+                       break;
+
+               if (lws_add_http_header_by_token(wsi,
+                                                WSI_TOKEN_HTTP_AUTHORIZATION,
+                                                (unsigned char *)b,
+                                                (int)strlen(b), pp, pend))
+                       return -1;
+
+               break;
+       }
+
+       case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+               lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
+                        in ? (char *)in : "(null)");
+               goto do_retry;
+
+       case LWS_CALLBACK_CLIENT_ESTABLISHED:
+               lwsl_warn("%s: connected to ws metrics agg server\n", __func__);
+               pss->greet = 1;
+               lws_callback_on_writable(wsi);
+               lws_validity_confirmed(wsi);
+               return 0;
+
+       case LWS_CALLBACK_CLIENT_CLOSED:
+               lwsl_notice("%s: client closed\n", __func__);
+               lwsac_free(&pss->ac);
+               goto do_retry;
+
+       case LWS_CALLBACK_CLIENT_RECEIVE:
+               /*
+                * Proxy serverside sends us something to trigger us to create
+                * our metrics message and send it back over the ws link
+                */
+               ome_prepare(cx, pss);
+               pss->walk = pss->ac;
+               lws_callback_on_writable(wsi);
+               lwsl_info("%s: dump requested\n", __func__);
+               break;
+
+       case LWS_CALLBACK_CLIENT_WRITEABLE:
+               if (pss->greet) {
+                       /*
+                        * At first after establishing the we link, we send a
+                        * message indicating to the metrics proxy how we
+                        * should be referred to by the scraper to particularly
+                        * select to talk to us
+                        */
+                       lwsl_info("%s: sending greet '%s'\n", __func__,
+                                       vhd->metrics_proxy_path);
+                       lws_strncpy((char *)start, vhd->metrics_proxy_path,
+                                       sizeof(buf) - LWS_PRE);
+                       if (lws_write(wsi, start,
+                                     strlen(vhd->metrics_proxy_path),
+                                     LWS_WRITE_TEXT) < 0)
+                               return 1;
+
+                       lws_validity_confirmed(wsi);
+
+                       pss->greet = 0;
+                       return 0;
+               }
+
+               if (!pss->walk)
+                       return 0;
+
+               /*
+                * We send the metrics dump in a single logical ws message,
+                * using ws fragmentation to split it around 1 mtu boundary
+                * and keep coming back until it's finished
+                */
+
+               first = pss->walk == pss->ac;
+
+               do {
+                       ip = (uint8_t *)pss->walk +
+                               lwsac_sizeof(pss->walk == pss->ac) + LWS_PRE;
+                       m = (unsigned int)((ip[0] << 8) | ip[1]);
+
+                       /* coverity */
+                       if (m > lwsac_get_tail_pos(pss->walk) -
+                               lwsac_sizeof(pss->walk == pss->ac)) {
+                               lwsl_err("%s: size blow\n", __func__);
+                               return -1;
+                       }
+
+                       if (lws_ptr_diff_size_t(end, p) < m)
+                               break;
+
+                       memcpy(p, ip + 2, m);
+                       p += m;
+
+                       pss->walk = lwsac_get_next(pss->walk);
+               } while (pss->walk);
+
+               if (!lws_ptr_diff_size_t(p, start)) {
+                       lwsl_err("%s: stuck\n", __func__);
+                       return -1;
+               }
+
+               wm = (unsigned int)lws_write_ws_flags(LWS_WRITE_TEXT, first,
+                                                     !pss->walk);
+
+               if (lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
+                             (enum lws_write_protocol)wm) < 0) {
+                       lwsl_notice("%s: write fail\n", __func__);
+                       return 1;
+               }
+
+               lws_validity_confirmed(wsi);
+               lwsl_info("%s: forwarded %d\n", __func__, lws_ptr_diff(p, start));
+
+               if (!pss->walk) {
+                       lwsl_info("%s: dump send completed\n", __func__);
+                       lwsac_free(&pss->ac);
+               } else
+                       lws_callback_on_writable(wsi);
+
+               return 0;
+
+       default:
+               break;
+       }
+
+       return lws_callback_http_dummy(wsi, reason, user, in, len);
+
+do_retry:
+       if (!lws_retry_sul_schedule(cx, 0, &vhd->sul, &retry,
+                                   omc_connect_client, &vhd->retry_count))
+               return 0;
+
+       vhd->retry_count = 0;
+       lws_retry_sul_schedule(cx, 0, &vhd->sul, &retry,
+                              omc_connect_client, &vhd->retry_count);
+
+       return 0;
+}
+#endif
+
+
+LWS_VISIBLE const struct lws_protocols lws_openmetrics_export_protocols[] = {
+#if defined(LWS_WITH_SERVER)
+       { /* for scraper directly: http export on listen socket */
+               "lws-openmetrics",
+               callback_lws_openmetrics_export,
+               sizeof(struct pss),
+               1024, 0, NULL, 0
+       },
+       { /* for scraper via ws proxy: http export on listen socket */
+               "lws-openmetrics-prox-agg",
+               callback_lws_openmetrics_prox_agg,
+               sizeof(struct pss),
+               1024, 0, NULL, 0
+       },
+       { /* metrics proxy server side: ws server for clients to connect to */
+               "lws-openmetrics-prox-server",
+               callback_lws_openmetrics_prox_server,
+               sizeof(struct pss),
+               1024, 0, NULL, 0
+       },
+#endif
+#if defined(LWS_WITH_CLIENT) && defined(LWS_ROLE_WS)
+       { /* client to metrics proxy: ws client to connect to metrics proxy*/
+               "lws-openmetrics-prox-client",
+               callback_lws_openmetrics_prox_client,
+               sizeof(struct pss),
+               1024, 0, NULL, 0
+       },
+#endif
+};
+
+LWS_VISIBLE const lws_plugin_protocol_t lws_openmetrics_export = {
+       .hdr = {
+               "lws OpenMetrics export",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = lws_openmetrics_export_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(lws_openmetrics_export_protocols),
+};
index 51dbe4f..78bb8ac 100644 (file)
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
 #include <string.h>
+#include <fcntl.h>
+
+#include <sys/stat.h>
 
 struct per_vhost_data__raw_test {
        struct lws_context *context;
@@ -107,6 +114,8 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                                lws_get_protocol(wsi),
                                sizeof(struct per_vhost_data__raw_test));
+               if (!vhd)
+                       return 0;
                vhd->context = lws_get_context(wsi);
                vhd->protocol = lws_get_protocol(wsi);
                vhd->vhost = lws_get_vhost(wsi);
@@ -120,7 +129,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                                pvo = pvo->next;
                        }
                        if (vhd->fifo_path[0] == '\0') {
-                               lwsl_err("%s: Missing pvo \"fifo-path\", "
+                               lwsl_warn("%s: Missing pvo \"fifo-path\", "
                                         "raw file fd testing disabled\n",
                                         __func__);
                                break;
@@ -175,7 +184,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                        char buf[256];
                        int n;
                        
-                       n = read(vhd->fifo, buf, sizeof(buf) - 1);
+                       n = (int)read(vhd->fifo, buf, sizeof(buf) - 1);
                        if (n < 0) {
                                lwsl_err("FIFO read failed\n");
                                return 1;
@@ -244,7 +253,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                if (len > sizeof(pss->buf))
                        len = sizeof(pss->buf);
                memcpy(pss->buf, in, len);
-               pss->len = len;
+               pss->len = (int)len;
                lws_callback_on_writable(wsi);
                break;
 
@@ -254,7 +263,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 
        case LWS_CALLBACK_RAW_WRITEABLE:
                lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE\n");
-               lws_write(wsi, pss->buf, pss->len, LWS_WRITE_HTTP);
+               lws_write(wsi, pss->buf, (size_t)pss->len, LWS_WRITE_HTTP);
                break;
 
        default:
@@ -269,37 +278,27 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                "protocol-lws-raw-test", \
                callback_raw_test, \
                sizeof(struct per_session_data__raw_test), \
-               1024, /* rx buf size must be >= permessage-deflate rx size */ \
+               1024, /* rx buf size must be >= permessage-deflate rx size */ 0, NULL, 0\
        }
 
 #if !defined (LWS_PLUGIN_STATIC)
                
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols lws_raw_test_protocols[] = {
        LWS_PLUGIN_PROTOCOL_RAW_TEST
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_lws_raw_test(struct lws_context *context,
-                            struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
+LWS_VISIBLE const lws_plugin_protocol_t lws_raw_test = {
+       .hdr = {
+               "lws raw test",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
 
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_lws_raw_test(struct lws_context *context)
-{
-       return 0;
-}
+       .protocols = lws_raw_test_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(lws_raw_test_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
 #endif
diff --git a/plugins/protocol_lws_server_status.c b/plugins/protocol_lws_server_status.c
deleted file mode 100644 (file)
index 2bed873..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * libwebsockets-test-server - libwebsockets test implementation
- *
- * Written in 2010-2019 by Andy Green <andy@warmcat.com>
- *
- * This file is made available under the Creative Commons CC0 1.0
- * Universal Public Domain Dedication.
- *
- * The person who associated a work with this deed has dedicated
- * the work to the public domain by waiving all of his or her rights
- * to the work worldwide under copyright law, including all related
- * and neighboring rights, to the extent allowed by law. You can copy,
- * modify, distribute and perform the work, even for commercial purposes,
- * all without asking permission.
- *
- * The test apps are intended to be adapted for use in your code, which
- * may be proprietary.  So unlike the library itself, they are licensed
- * Public Domain.
- */
-
-#define LWS_DLL
-#define LWS_INTERNAL
-#include <libwebsockets.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-
-struct lws_ss_filepath {
-       struct lws_ss_filepath *next;
-       char filepath[128];
-};
-
-struct lws_ss_dumps {
-       char buf[32768];
-       int length;
-};
-
-struct pss {
-       int ver;
-       int pos;
-};
-
-struct vhd {
-       struct lws_context *context;
-       struct lws_vhost *vhost;
-       const struct lws_protocols *protocol;
-       int hide_vhosts;
-       int tow_flag;
-       int period_s;
-       int clients;
-       struct lws_ss_dumps d;
-       struct lws_ss_filepath *fp;
-};
-
-static const struct lws_protocols protocols[1];
-
-static void
-update(struct vhd *v)
-{
-       struct lws_ss_filepath *fp;
-       char contents[256], pure[256], *p = v->d.buf + LWS_PRE,
-            *end = v->d.buf + sizeof(v->d.buf) - LWS_PRE - 1;
-       int n, first = 1, fd;
-
-       p += lws_snprintf(p, lws_ptr_diff(end, p), "{\"i\":");
-       p += lws_json_dump_context(v->context, p, lws_ptr_diff(end, p),
-                                  v->hide_vhosts);
-       p += lws_snprintf(p, lws_ptr_diff(end, p), ", \"files\": [");
-
-       fp = v->fp;
-       while (fp) {
-               if (!first)
-                       p += lws_snprintf(p, lws_ptr_diff(end, p), ",");
-
-               strcpy(pure, "(unknown)");
-               fd = lws_open(fp->filepath, LWS_O_RDONLY);
-               if (fd >= 0) {
-                       n = read(fd, contents, sizeof(contents) - 1);
-                       close(fd);
-                       if (n >= 0) {
-                               contents[n] = '\0';
-                               lws_json_purify(pure, contents, sizeof(pure));
-                       }
-               }
-
-               p += lws_snprintf(p, lws_ptr_diff(end, p),
-                               "{\"path\":\"%s\",\"val\":\"%s\"}",
-                                       fp->filepath, pure);
-               first = 0;
-
-               fp = fp->next;
-       }
-       p += lws_snprintf(p, lws_ptr_diff(end, p), "]}");
-       v->d.length = p - (v->d.buf + LWS_PRE);
-
-       lws_callback_on_writable_all_protocol(v->context, &protocols[0]);
-}
-
-static int
-callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
-                          void *user, void *in, size_t len)
-{
-       const struct lws_protocol_vhost_options *pvo =
-                       (const struct lws_protocol_vhost_options *)in;
-       struct vhd *v = (struct vhd *)
-                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
-                                       lws_get_protocol(wsi));
-       struct lws_ss_filepath *fp, *fp1, **fp_old;
-       int m;
-
-       switch (reason) {
-
-       case LWS_CALLBACK_ESTABLISHED:
-               lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
-               if (!v->clients++) {
-                       lws_timed_callback_vh_protocol(v->vhost, v->protocol,
-                                                      LWS_CALLBACK_USER, v->period_s);
-                       lwsl_info("%s: starting updates\n", __func__);
-               }
-               update(v);
-
-               break;
-
-       case LWS_CALLBACK_CLOSED:
-               if (!--v->clients)
-                       lwsl_notice("%s: stopping updates\n", __func__);
-
-               break;
-
-       case LWS_CALLBACK_USER:
-               update(v);
-               if (v->clients)
-                       lws_timed_callback_vh_protocol(v->vhost, v->protocol,
-                                                      LWS_CALLBACK_USER, v->period_s);
-               break;
-
-       case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
-               if (v)
-                       break;
-
-               lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
-                                           lws_get_protocol(wsi),
-                                           sizeof(struct vhd));
-               v = (struct vhd *)lws_protocol_vh_priv_get(lws_get_vhost(wsi),
-                                                          lws_get_protocol(wsi));
-
-               fp_old = &v->fp;
-
-               while (pvo) {
-                       if (!strcmp(pvo->name, "hide-vhosts"))
-                               v->hide_vhosts = atoi(pvo->value);
-                       if (!strcmp(pvo->name, "update-ms"))
-                               v->period_s = (atoi(pvo->value) + 500) / 1000;
-                       else
-                               v->period_s = 5;
-                       if (!strcmp(pvo->name, "filepath")) {
-                               fp = malloc(sizeof(*fp));
-                               fp->next = NULL;
-                               lws_snprintf(&fp->filepath[0],
-                                            sizeof(fp->filepath), "%s",
-                                            pvo->value);
-                               *fp_old = fp;
-                               fp_old = &fp->next;
-                       }
-                       pvo = pvo->next;
-               }
-               v->context = lws_get_context(wsi);
-               v->vhost = lws_get_vhost(wsi);
-               v->protocol = lws_get_protocol(wsi);
-
-               /* get the initial data */
-               update(v);
-               break;
-
-       case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
-               if (!v)
-                       break;
-               fp = v->fp;
-               while (fp) {
-                       fp1= fp->next;
-                       free(fp);
-                       fp = fp1;
-               }
-               break;
-
-       case LWS_CALLBACK_SERVER_WRITEABLE:
-               m = lws_write(wsi, (unsigned char *)v->d.buf + LWS_PRE,
-                             v->d.length, LWS_WRITE_TEXT);
-               if (m < 0)
-                       return -1;
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static const struct lws_protocols protocols[] = {
-       {
-               "lws-server-status",
-               callback_lws_server_status,
-               sizeof(struct pss),
-               1024,
-       },
-};
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_lws_server_status(struct lws_context *context,
-                               struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d",
-                        LWS_PLUGIN_API_MAGIC, c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_lws_server_status(struct lws_context *context)
-{
-       return 0;
-}
index 934d84b..cf5e70f 100644 (file)
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
@@ -29,6 +33,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #define TEST_SERVER_KEY_PATH "/etc/lws-test-sshd-server-key"
 
@@ -163,7 +168,7 @@ ssh_ops_tx(void *_priv, int stdch, uint8_t *buf, size_t len)
                return 0;
 
        if ((size_t)(priv->len - priv->pos) < chunk)
-               chunk = priv->len - priv->pos;
+               chunk = (size_t)(priv->len - priv->pos);
 
        if (!chunk)
                return 0;
@@ -210,13 +215,13 @@ ssh_ops_get_server_key(struct lws *wsi, uint8_t *buf, size_t len)
 
        if (lseek(vhd->privileged_fd, 0, SEEK_SET) < 0)
                return 0;
-       n = read(vhd->privileged_fd, buf, (int)len);
+       n = (int)read(vhd->privileged_fd, buf, (unsigned int)len);
        if (n < 0) {
                lwsl_err("%s: read failed: %d\n", __func__, n);
                n = 0;
        }
 
-       return n;
+       return (size_t)n;
 }
 
 static size_t
@@ -228,13 +233,13 @@ ssh_ops_set_server_key(struct lws *wsi, uint8_t *buf, size_t len)
                                                 lws_get_protocol(wsi));
        int n;
 
-       n = write(vhd->privileged_fd, buf, (int)len);
+       n = (int)write(vhd->privileged_fd, buf, (unsigned int)len);
        if (n < 0) {
                lwsl_err("%s: read failed: %d\n", __func__, errno);
                n = 0;
        }
 
-       return n;
+       return (size_t)n;
 }
 
 /* ops: auth */
@@ -265,7 +270,7 @@ ssh_ops_is_pubkey_authorized(const char *username, const char *type,
        }
        p = aps;
 
-       if (strncmp(p, type, n)) {
+       if (strncmp(p, type, (unsigned int)n)) {
                lwsl_notice("lead-in string  does not match %s\n", type);
                goto bail_p1;
        }
@@ -277,7 +282,7 @@ ssh_ops_is_pubkey_authorized(const char *username, const char *type,
        }
 
        p++;
-       ps = malloc(alen);
+       ps = malloc((unsigned int)alen);
        if (!ps) {
                lwsl_notice("OOM 2\n");
                free(aps);
@@ -300,7 +305,7 @@ ssh_ops_is_pubkey_authorized(const char *username, const char *type,
         * once we are past that, it's the same <len32>name
         * <len32>E<len32>N that the peer sends us
         */
-       if (memcmp(peer, ps, peer_len)) {
+       if (memcmp(peer, ps, (unsigned int)peer_len)) {
                lwsl_info("%s: factors mismatch, rejecting key\n", __func__);
                goto bail;
        }
@@ -344,7 +349,7 @@ ssh_ops_banner(char *buf, size_t max_len, char *lang, size_t max_lang_len)
 
        lws_snprintf(lang, max_lang_len, "en/US");
 
-       return n;
+       return (size_t)n;
 }
 
 static void
@@ -391,6 +396,8 @@ callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason,
                vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                                                  lws_get_protocol(wsi),
                                sizeof(struct per_vhost_data__lws_sshd_demo));
+               if (!vhd)
+                       return 0;
                /*
                 * During this we still have the privs / caps we were started
                 * with.  So open an fd on the server key, either just for read
@@ -403,14 +410,15 @@ callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason,
                        vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH,
                                        O_CREAT | O_TRUNC | O_RDWR, 0600);
                if (vhd->privileged_fd == -1) {
-                       lwsl_err("%s: Can't open %s\n", __func__,
+                       lwsl_warn("%s: Can't open %s\n", __func__,
                                 TEST_SERVER_KEY_PATH);
-                       return -1;
+                       return 0;
                }
                break;
 
        case LWS_CALLBACK_PROTOCOL_DESTROY:
-               close(vhd->privileged_fd);
+               if (vhd)
+                       close(vhd->privileged_fd);
                break;
 
        case LWS_CALLBACK_VHOST_CERT_AGING:
@@ -451,32 +459,22 @@ callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason,
 
 #if !defined (LWS_PLUGIN_STATIC)
                
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols lws_sshd_demo_protocols[] = {
                LWS_PLUGIN_PROTOCOL_LWS_SSHD_DEMO
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_lws_sshd_demo(struct lws_context *context,
-                            struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_lws_sshd_demo(struct lws_context *context)
-{
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t lws_sshd_demo = {
+       .hdr = {
+               "lws sshd demo",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = lws_sshd_demo_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(lws_sshd_demo_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
 #endif
index 8364be4..03a6dc6 100644 (file)
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
@@ -98,6 +102,10 @@ callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
                vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                                lws_get_protocol(wsi),
                                sizeof(struct per_vhost_data__lws_status));
+               if (!vhd) {
+                       lwsl_notice("%s: PROTOCOL_INIT failed\n", __func__);
+                       return 0;
+               }
                vhd->context = lws_get_context(wsi);
                vhd->protocol = lws_get_protocol(wsi);
                vhd->vhost = lws_get_vhost(wsi);
@@ -120,8 +128,10 @@ callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
                time(&pss->time_est);
                pss->wsi = wsi;
 
+#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
                if (lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent),
                             WSI_TOKEN_HTTP_USER_AGENT) < 0) /* too big */
+#endif
                        strcpy(pss->user_agent, "unknown");
                trigger_resend(vhd);
                break;
@@ -130,7 +140,7 @@ callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
                switch (pss->walk) {
                case WALK_INITIAL:
                        n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
-                       p += lws_snprintf(p, end - p,
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
                                      "{ \"version\":\"%s\","
                                      " \"wss_over_h2\":\"%d\","
                                      " \"hostname\":\"%s\","
@@ -169,7 +179,7 @@ callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
 
                        strcpy(ip, "unknown");
                        lws_get_peer_simple(pss->walk_next->wsi, ip, sizeof(ip));
-                       p += lws_snprintf(p, end - p,
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
                                        "{\"peer\":\"%s\",\"time\":\"%ld\","
                                        "\"ua\":\"%s\"}",
                                        ip, (unsigned long)pss->walk_next->time_est,
@@ -194,7 +204,7 @@ walk_final:
                        return 0;
                }
 
-               m = lws_write(wsi, (unsigned char *)start, p - start, n);
+               m = lws_write(wsi, (unsigned char *)start, lws_ptr_diff_size_t(p, start), (unsigned int)n);
                if (m < 0) {
                        lwsl_err("ERROR %d writing to di socket\n", m);
                        return -1;
@@ -239,33 +249,22 @@ walk_final:
 
 #if !defined (LWS_PLUGIN_STATIC)
 
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols lws_status_protocols[] = {
        LWS_PLUGIN_PROTOCOL_LWS_STATUS
 };
 
-
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_lws_status(struct lws_context *context,
-                            struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_lws_status(struct lws_context *context)
-{
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t lws_status = {
+       .hdr = {
+               "lws status",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = lws_status_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(lws_status_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
 #endif
index 02503c3..55ce4eb 100644 (file)
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
@@ -80,7 +84,7 @@ file_upload_cb(void *data, const char *name, const char *filename,
                 * simple demo use a fixed name so we don't have to deal with
                 * attacks  */
 #if !defined(LWS_WITH_ESP32)
-               pss->fd = (lws_filefd_type)(long long)lws_open("/tmp/post-file",
+               pss->fd = (lws_filefd_type)(lws_intptr_t)lws_open("/tmp/post-file",
                               O_CREAT | O_TRUNC | O_RDWR, 0600);
 #endif
                break;
@@ -94,7 +98,7 @@ file_upload_cb(void *data, const char *name, const char *filename,
                                return 1;
 
 #if !defined(LWS_WITH_ESP32)
-                       n = write((int)(long long)pss->fd, buf, len);
+                       n = (int)write((int)(lws_intptr_t)pss->fd, buf, (unsigned int)len);
                        lwsl_info("%s: write %d says %d\n", __func__, len, n);
 #else
                        lwsl_notice("%s: Received chunk size %d\n", __func__, len);
@@ -103,7 +107,7 @@ file_upload_cb(void *data, const char *name, const char *filename,
                if (state == LWS_UFS_CONTENT)
                        break;
 #if !defined(LWS_WITH_ESP32)
-               close((int)(long long)pss->fd);
+               close((int)(lws_intptr_t)pss->fd);
                pss->fd = LWS_INVALID_FILE;
 #endif
                break;
@@ -128,7 +132,13 @@ format_result(struct per_session_data__post_demo *pss)
        start = p;
        end = p + sizeof(pss->result) - LWS_PRE - 1;
 
-       p += lws_snprintf((char *)p, end -p,
+       if (!pss->spa) {
+               p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
+                                 "pss->spa already NULL");
+               goto bail;
+       }
+
+       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                        "<!DOCTYPE html><html lang=\"en\"><head>"
                        "<meta charset=utf-8 http-equiv=\"Content-Language\" "
                        "content=\"en\"/>"
@@ -138,12 +148,12 @@ format_result(struct per_session_data__post_demo *pss)
 
        for (n = 0; n < (int)LWS_ARRAY_SIZE(param_names); n++) {
                if (!lws_spa_get_string(pss->spa, n))
-                       p += lws_snprintf((char *)p, end - p,
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                            "<tr><td><b>%s</b></td><td>0"
                            "</td><td>NULL</td></tr>",
                            param_names[n]);
                else
-                       p += lws_snprintf((char *)p, end - p,
+                       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                            "<tr><td><b>%s</b></td><td>%d"
                            "</td><td>%s</td></tr>",
                            param_names[n],
@@ -151,13 +161,14 @@ format_result(struct per_session_data__post_demo *pss)
                            lws_spa_get_string(pss->spa, n));
        }
 
-       p += lws_snprintf((char *)p, end - p,
+       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p),
                        "</table><br><b>filename:</b> %s, "
                        "<b>length</b> %ld",
                        pss->filename, pss->file_length);
 
-       p += lws_snprintf((char *)p, end - p, "</body></html>");
+       p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "</body></html>");
 
+bail:
        return (int)lws_ptr_diff(p, start);
 }
 
@@ -190,7 +201,7 @@ callback_post_demo(struct lws *wsi, enum lws_callback_reasons reason,
                break;
 
        case LWS_CALLBACK_HTTP_BODY_COMPLETION:
-               lwsl_debug("LWS_CALLBACK_HTTP_BODY_COMPLETION: %p\n", wsi);
+               lwsl_debug("LWS_CALLBACK_HTTP_BODY_COMPLETION: %s\n", lws_wsi_tag(wsi));
                /* call to inform no more payload data coming */
                lws_spa_finalize(pss->spa);
 
@@ -218,13 +229,13 @@ callback_post_demo(struct lws *wsi, enum lws_callback_reasons reason,
                                        (unsigned char *)"text/html", 9,
                                        &p, end))
                                goto bail;
-                       if (lws_add_http_header_content_length(wsi, n, &p, end))
+                       if (lws_add_http_header_content_length(wsi, (unsigned int)n, &p, end))
                                goto bail;
                        if (lws_finalize_http_header(wsi, &p, end))
                                goto bail;
 
                        /* first send the headers ... */
-                       n = lws_write(wsi, start, lws_ptr_diff(p, start),
+                       n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start),
                                      LWS_WRITE_HTTP_HEADERS);
                        if (n < 0)
                                goto bail;
@@ -237,7 +248,7 @@ callback_post_demo(struct lws *wsi, enum lws_callback_reasons reason,
                if (!pss->sent_body) {
                        n = format_result(pss);
 
-                       n = lws_write(wsi, (unsigned char *)start, n,
+                       n = lws_write(wsi, (unsigned char *)start, (unsigned int)n,
                                      LWS_WRITE_HTTP_FINAL);
 
                        pss->sent_body = 1;
@@ -283,32 +294,22 @@ try_to_reuse:
 
 #if !defined (LWS_PLUGIN_STATIC)
 
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols post_demo_protocols[] = {
        LWS_PLUGIN_PROTOCOL_POST_DEMO
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_post_demo(struct lws_context *context,
-                       struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_post_demo(struct lws_context *context)
-{
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t post_demo = {
+       .hdr = {
+               "post demo",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = post_demo_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(post_demo_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
 #endif
index bd2b82a..91d676d 100644 (file)
@@ -1,27 +1,34 @@
 /*
- * libwebsockets - plugin for raw proxying
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
+#if !defined(LWS_DLL)
 #define LWS_DLL
+#endif
+#if !defined(LWS_INTERNAL)
 #define LWS_INTERNAL
+#endif
 #include <libwebsockets.h>
 #endif
 
@@ -155,7 +162,7 @@ flow_control(struct conn *conn, int side, int enable)
        if (lws_rx_flow_control(conn->wsi[side], enable))
                return 1;
 
-       conn->rx_enabled[side] = enable;
+       conn->rx_enabled[side] = (char)enable;
        lwsl_info("%s: %s side: %s\n", __func__, side ? "ONW" : "ACC",
                  enable ? "rx enabled" : "rx flow controlled");
 
@@ -184,11 +191,13 @@ callback_raw_proxy(struct lws *wsi, enum lws_callback_reasons reason,
        case LWS_CALLBACK_PROTOCOL_INIT:
                vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                                lws_get_protocol(wsi), sizeof(struct raw_vhd));
+               if (!vhd)
+                       return 0;
                if (lws_pvo_get_str(in, "onward", &cp)) {
-                       lwsl_err("%s: vh %s: pvo 'onward' required\n", __func__,
+                       lwsl_warn("%s: vh %s: pvo 'onward' required\n", __func__,
                                 lws_get_vhost_name(lws_get_vhost(wsi)));
 
-                       return -1;
+                       return 0;
                }
                lws_tokenize_init(&ts, cp, LWS_TOKENIZE_F_DOT_NONTERM |
                                           LWS_TOKENIZE_F_MINUS_NONTERM |
@@ -220,7 +229,7 @@ callback_raw_proxy(struct lws *wsi, enum lws_callback_reasons reason,
                                e = lws_tokenize(&ts);
                                if (e != LWS_TOKZE_INTEGER)
                                        goto bad_onward;
-                               vhd->port = atoi(ts.token);
+                               vhd->port = (uint16_t)atoi(ts.token);
                                e = lws_tokenize(&ts);
                        }
                        if (e != LWS_TOKZE_ENDED)
@@ -249,10 +258,12 @@ bad_onward:
                break;
 
         case LWS_CALLBACK_RAW_PROXY_CLI_ADOPT:
-               lwsl_debug("LWS_CALLBACK_RAW_CLI_ADOPT: pss %p\n", pss);
+               lwsl_debug("%s: %p: LWS_CALLBACK_RAW_CLI_ADOPT: pss %p\n", __func__, wsi, pss);
                if (conn || !pss)
                        break;
                conn = pss->conn = lws_get_opaque_user_data(wsi);
+               if (!conn)
+                       break;
                conn->established[ONW] = 1;
                /* they start enabled */
                conn->rx_enabled[ACC] = 1;
@@ -293,7 +304,7 @@ bad_onward:
                        lwsl_notice("OOM: dropping\n");
                        return -1;
                }
-               pkt.len = len;
+               pkt.len = (uint32_t)len;
                pkt.ticket = conn->ticket_next++;
 
                memcpy(pkt.payload, in, len);
@@ -442,12 +453,15 @@ bad_onward:
                        return -1;
                }
 
+               if (!len)
+                       return 0;
+
                pkt.payload = malloc(len);
                if (!pkt.payload) {
                        lwsl_notice("OOM: dropping\n");
                        return -1;
                }
-               pkt.len = len;
+               pkt.len = (uint32_t)len;
                pkt.ticket = conn->ticket_next++;
 
                memcpy(pkt.payload, in, len);
@@ -550,33 +564,23 @@ bad_onward:
 
 #if !defined (LWS_PLUGIN_STATIC)
 
-static const struct lws_protocols protocols[] = {
+LWS_VISIBLE const struct lws_protocols lws_raw_proxy_protocols[] = {
        LWS_PLUGIN_PROTOCOL_RAW_PROXY
 };
 
-LWS_EXTERN LWS_VISIBLE int
-init_protocol_lws_raw_proxy(struct lws_context *context,
-                           struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
-
-LWS_EXTERN LWS_VISIBLE int
-destroy_protocol_lws_raw_proxy(struct lws_context *context)
-{
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t lws_raw_proxy = {
+       .hdr = {
+               "raw proxy",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = lws_raw_proxy_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(lws_raw_proxy_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 #endif
 
 
diff --git a/plugins/server-status.html b/plugins/server-status.html
deleted file mode 100644 (file)
index 0c03863..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset=utf-8 http-equiv="Content-Language" content="en"/>
- <link rel="stylesheet" type="text/css" href="server-status.css"/>
- <script src="/lws-common.js"></script>
- <script type='text/javascript' src='server-status.js'></script>
- <title>LWS Server Status</title>
-</head>
-
-<body>
-<header></header>
-<article>
-
-<table>
-<tr><td><img src="./lwsws-logo.png"></td><td>
-<span id=title class=title>Server status</span></td></tr>
-<tr><td align=center colspan=2>
-<div id="conninfo">...</div>
-<div id="json"></div>
-</td></tr>
-</table>
-</article>
-</body>
-</html>
diff --git a/plugins/server-status.js b/plugins/server-status.js
deleted file mode 100644 (file)
index eafbc3b..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-(function() {
-
-/*
- * We display untrusted stuff in html context... reject anything
- * that has HTML stuff in it
- */
-
-function san(s)
-{
-       if (s.search("<") !== -1)
-               return "invalid string";
-       
-       return s;
-}
-
-function humanize(s)
-{
-       var i = parseInt(s, 10);
-       
-       if (i >= (1024 * 1024 * 1024))
-               return (i / (1024 * 1024 * 1024)).toFixed(3) + "Gi";
-       
-       if (i >= (1024 * 1024))
-               return (i / (1024 * 1024)).toFixed(3) + "Mi";
-       
-       if (i > 1024)
-               return (i / 1024).toFixed(3) + "Ki";
-       
-       return s;
-}
-
-       var pos = 0;
-
-function get_appropriate_ws_url()
-{
-       var pcol;
-       var u = document.URL;
-
-       /*
-        * We open the websocket encrypted if this page came on an
-        * https:// url itself, otherwise unencrypted
-        */
-
-       if (u.substring(0, 5) === "https") {
-               pcol = "wss://";
-               u = u.substr(8);
-       } else {
-               pcol = "ws://";
-               if (u.substring(0, 4) === "http")
-                       u = u.substr(7);
-       }
-
-       u = u.split("/");
-
-       /* + "/xxx" bit is for IE10 workaround */
-
-       return pcol + u[0] + "/xxx";
-}
-
-
-       var socket_status, jso, s;
-
-function ws_open_server_status()
-{      
-       socket_status = new WebSocket(get_appropriate_ws_url(),
-                                  "lws-server-status");
-
-       try {
-               socket_status.onopen = function() {
-                       document.getElementById("title").innerHTML = "Server Status (Active)";
-                       lws_gray_out(false);
-               };
-
-               socket_status.onmessage =function got_packet(msg) {
-                       var u, ci, n;
-                       //document.getElementById("json").innerHTML = "<pre>"+msg.data+"</pre>";
-                       if (msg.data.length < 100)
-                               return;
-                       jso = JSON.parse(msg.data);
-                       u = parseInt(san(jso.i.uptime), 10);
-
-                       if (parseInt(jso.i.contexts[0].deprecated, 10) === 0)
-                               s = "<table><tr><td></td><td class=\"c0\">";
-                       else
-                               s = "<table><tr><td></td><td class=\"dc0\">";
-                       s +=
-                         "Server</td><td>" +
-                         "<span class=\"sn\">Server Version:</span> <span class=\"v\">" +
-                          san(jso.i.version) + "</span><br>" +
-                         "<span class=\"sn\">Host Uptime:</span> <span class=\"v\">" +
-                         ((u / (24 * 3600)) | 0) + "d " +
-                         (((u % (24 * 3600)) / 3600) | 0) + "h " +
-                         (((u % 3600) / 60) | 0) + "m</span>";
-                       if (jso.i.l1)
-                               s = s + ", <span class=\"sn\">Host Load:</span> <span class=\"v\">" + san(jso.i.l1) + " ";
-                       if (jso.i.l2)
-                               s = s + san(jso.i.l2) + " ";
-                       if (jso.i.l3)
-                               s = s + san(jso.i.l3);
-                       if (jso.i.l1)
-                               s =s + "</span>";
-                               
-                       if (jso.i.statm) {
-                               var sm = jso.i.statm.split(" ");
-                               s += ", <span class=\"sn\">Virt stack + heap Usage:</span> <span class=\"v\">" +
-                                       humanize(parseInt(sm[5], 10) * 4096) + "B</span>";
-                       }
-                       s += ", <span class=\"sn\">lws heap usage:</span> <span class=\"v\">" +
-                       humanize(jso.i.heap) + "B</span>";
-
-                               
-                       for (n = 0; n < jso.files.length; n++) {
-                               s += "<br><span class=n>" + san(jso.files[n].path) + ":</span><br>    " + san(jso.files[n].val);
-                       }
-                       s += "</td></tr>";
-
-                       for (ci = 0; ci < jso.i.contexts.length; ci++) {
-
-                               if (parseInt(jso.i.contexts[ci].deprecated, 10) === 0)
-                                       s += "<tr><td></td><td class=\"c\">" +
-                                         "Active Context</td><td>";
-                               else
-                                       s += "<tr><td></td><td class=\"c1\">" +
-                                         "Deprecated Context " + ci + "</td><td>";
-
-                                 u = parseInt(san(jso.i.contexts[ci].context_uptime), 10);
-                                 s += "<span class=n>Server Uptime:</span> <span class=v>" +
-                                 ((u / (24 * 3600)) | 0) + "d " +
-                                 (((u % (24 * 3600)) / 3600) | 0) + "h " +
-                                 (((u % 3600) / 60) | 0) + "m</span>";
-
-                               s = s +
-                                 "<br>" +
-                                 "<span class=n>Listening wsi:</span> <span class=v>" + san(jso.i.contexts[ci].listen_wsi) + "</span>, " +
-                                 "<span class=n>Current wsi alive:</span> <span class=v>" + (parseInt(san(jso.i.contexts[ci].wsi_alive), 10) -
-                                                 parseInt(san(jso.i.contexts[ci].listen_wsi), 10)) + "</span><br>" +
-                                 "<span class=n>Total Rx:</span> <span class=v>" + humanize(san(jso.i.contexts[ci].rx)) +"B</span>, " +
-                                 "<span class=n>Total Tx:</span> <span class=v>" + humanize(san(jso.i.contexts[ci].tx)) +"B</span><br>" +
-                                 
-                                 "<span class=n>CONNECTIONS: HTTP/1.x:</span> <span class=v>" + san(jso.i.contexts[ci].h1_conn) +"</span>, " +
-                                 "<span class=n>Websocket:</span> <span class=v>" + san(jso.i.contexts[ci].ws_upg) +"</span>, " +
-                                 "<span class=n>H2 upgrade:</span> <span class=v>" + san(jso.i.contexts[ci].h2_upg) +"</span>, " +
-                                 "<span class=n>H2 ALPN:</span> <span class=v>" + san(jso.i.contexts[ci].h2_alpn) +"</span>, " +
-                                 "<span class=n>Rejected:</span> <span class=v>" + san(jso.i.contexts[ci].rejected) +"</span><br>" +
-
-                                 "<span class=n>TRANSACTIONS: HTTP/1.x:</span> <span class=v>" + san(jso.i.contexts[ci].h1_trans) + "</span>, " +
-                                 "<span class=n>H2:</span> <span class=v>" + san(jso.i.contexts[ci].h2_trans) +"</span>, " +
-                                  "<span class=n>Total H2 substreams:</span> <span class=v>" + san(jso.i.contexts[ci].h2_subs) +"</span><br>" +
-
-                                 "<span class=n>CGI: alive:</span> <span class=v>" + san(jso.i.contexts[ci].cgi_alive) + "</span>, " +
-                                 "<span class=n>spawned:</span> <span class=v>" + san(jso.i.contexts[ci].cgi_spawned) +
-                                 "</span><table>";
-                               
-                               for (n = 0; n < jso.i.contexts[ci].pt.length; n++) {
-
-                                       if (parseInt(jso.i.contexts[ci].deprecated, 10) === 0)
-                                               s += "<tr><td>&nbsp;&nbsp;</td><td class=\"l\">service thread " + (n + 1);
-                                       else
-                                               s += "<tr><td>&nbsp;&nbsp;</td><td class=\"dl\">service thread " + (n + 1);
-                                       s += "</td><td>" +
-                                       "<span class=n>fds:</span> <span class=v>" + san(jso.i.contexts[ci].pt[n].fds_count) + " / " +
-                                                 san(jso.i.contexts[ci].pt_fd_max) + "</span>, ";
-                                       s = s + "<span class=n>ah pool:</span> <span class=v>" + san(jso.i.contexts[ci].pt[n].ah_pool_inuse) + " / " +
-                                                     san(jso.i.contexts[ci].ah_pool_max) + "</span>, " +
-                                       "<span class=n>ah waiting list:</span> <span class=v>" + san(jso.i.contexts[ci].pt[n].ah_wait_list);
-       
-                                       s = s + "</span></td></tr>";
-       
-                               }
-                               for (n = 0; n < jso.i.contexts[ci].vhosts.length; n++) {
-                                       if (parseInt(jso.i.contexts[ci].deprecated, 10) === 0)
-                                               s += "<tr><td>&nbsp;&nbsp;</td><td class=\"l\">vhost " + (n + 1);
-                                       else
-                                               s += "<tr><td>&nbsp;&nbsp;</td><td class=\"dl\">vhost " + (n + 1);
-                                       s += "</td><td><span class=\"mountname\">";
-                                       if (jso.i.contexts[ci].vhosts[n].use_ssl === "1")
-                                               s = s + "https://";
-                                       else
-                                               s = s + "http://";
-                                       s = s + san(jso.i.contexts[ci].vhosts[n].name) + ":" +
-                                               san(jso.i.contexts[ci].vhosts[n].port) + "</span>";
-                                       if (jso.i.contexts[ci].vhosts[n].sts === "1")
-                                               s = s + " (STS)";
-                                       s = s +"<br>" +
-                                       
-                                         "<span class=n>Total Rx:</span> <span class=v>" + humanize(san(jso.i.contexts[ci].vhosts[n].rx)) +"B</span>, " +
-                                         "<span class=n>Total Tx:</span> <span class=v>" + humanize(san(jso.i.contexts[ci].vhosts[n].tx)) +"B</span><br>" +
-                                         
-                                         "<span class=n>CONNECTIONS: HTTP/1.x:</span> <span class=v>" + san(jso.i.contexts[ci].vhosts[n].h1_conn) +"</span>, " +
-                                         "<span class=n>Websocket:</span> <span class=v>" + san(jso.i.contexts[ci].vhosts[n].ws_upg) +"</span>, " +
-                                         "<span class=n>H2 upgrade:</span> <span class=v>" + san(jso.i.contexts[ci].vhosts[n].h2_upg) +"</span>, " +
-                                         "<span class=n>H2 ALPN:</span> <span class=v>" + san(jso.i.contexts[ci].vhosts[n].h2_alpn) +"</span>, " +
-                                         "<span class=n>Rejected:</span> <span class=v>" + san(jso.i.contexts[ci].vhosts[n].rejected) +"</span><br>" +
-                                       
-                                         "<span class=n>TRANSACTIONS: HTTP/1.x:</span> <span class=v>" + san(jso.i.contexts[ci].vhosts[n].h1_trans) + "</span>, " +
-                                         "<span class=n>H2:</span> <span class=v>" + san(jso.i.contexts[ci].vhosts[n].h2_trans) +"</span>, " +
-                                         "<span class=n>Total H2 substreams:</span> <span class=v>" + san(jso.i.contexts[ci].vhosts[n].h2_subs) +"</span><br>";
-                                       
-                                       if (jso.i.contexts[ci].vhosts[n].mounts) {
-                                               s = s + "<table><tr><td class=t>Mountpoint</td><td class=t>Origin</td><td class=t>Cache Policy</td></tr>";
-       
-                                               var m;
-                                               for (m = 0; m < jso.i.contexts[ci].vhosts[n].mounts.length; m++) {
-                                                       s = s + "<tr><td>";
-                                                       s = s + "<span class=\"m1\">" + san(jso.i.contexts[ci].vhosts[n].mounts[m].mountpoint) +
-                                                               "</span></td><td><span class=\"m2\">" +
-                                                               san(jso.i.contexts[ci].vhosts[n].mounts[m].origin) +
-                                                               "</span></td><td>";
-                                                       if (parseInt(san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_max_age), 10))
-                                                               s = s + "<span class=n>max-age:</span> <span class=v>" +
-                                                               san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_max_age) +
-                                                               "</span>, <span class=n>reuse:</span> <span class=v>" +
-                                                               san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_reuse) +
-                                                               "</span>, <span class=n>reval:</span> <span class=v>" +
-                                                               san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_revalidate) +
-                                                               "</span>, <span class=n>inter:</span> <span class=v>" +
-                                                               san(jso.i.contexts[ci].vhosts[n].mounts[m].cache_intermediaries);
-                                                       s = s + "</span></td></tr>";
-                                               }
-                                               s = s + "</table>";
-                                       }
-                                       s = s + "</td></tr>";
-                               }
-
-                               s += "</table></td></tr>";
-                               
-                       } // context
-                       s = s + "</table>";
-                       
-                       document.getElementById("conninfo").innerHTML = s;
-               };
-
-               socket_status.onclose = function(){
-                       document.getElementById("title").innerHTML = "Server Status (Disconnected)";
-                       lws_gray_out(true,{"zindex":"499"});
-               };
-       } catch(exception) {
-               alert("<p>Error" + exception);  
-       }
-}
-
-/* stuff that has to be delayed until all the page assets are loaded */
-
-window.addEventListener("load", function() {
-
-       lws_gray_out(true,{"zindex":"499"});
-       
-       ws_open_server_status();
-       
-}, false);
-
-}());
-
index 694de25..182280d 100644 (file)
@@ -28,7 +28,7 @@ typedef struct chacha_ctx chacha_ctx;
 #define U8C(v) (v##U)
 #define U32C(v) (v##U)
 
-#define U8V(v) ((u8)(v) & U8C(0xFF))
+#define U8V(v) ((u8)((v) & U8C(0xFF)))
 #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
 
 #define ROTL32(v, n) \
index 72b3ae7..9805591 100644 (file)
@@ -166,7 +166,7 @@ int crypto_verify_32(const unsigned char *x,const unsigned char *y)
   F(29)
   F(30)
   F(31)
-  return (1 & ((differentbits - 1) >> 8)) - 1;
+  return (int)((1 & ((differentbits - 1) >> 8)) - 1);
 }
 
 int crypto_sign_ed25519_open(
index fdc2e2a..1f9e7a0 100644 (file)
@@ -90,7 +90,7 @@ void fe25519_freeze(fe25519 *r)
     m &= fe_equal(r->v[i],255);
   m &= ge(r->v[0],237);
 
-  m = -(int32_t)m;
+  m = (uint32_t)-(int32_t)m;
 
   r->v[31] -= m&127;
   for(i=30;i>0;i--)
@@ -112,7 +112,7 @@ void fe25519_pack(unsigned char r[32], const fe25519 *x)
   fe25519 y = *x;
   fe25519_freeze(&y);
   for(i=0;i<32;i++) 
-    r[i] = y.v[i];
+    r[i] = (unsigned char)y.v[i];
 }
 
 int fe25519_iszero(const fe25519 *x)
@@ -121,9 +121,9 @@ int fe25519_iszero(const fe25519 *x)
   int r;
   fe25519 t = *x;
   fe25519_freeze(&t);
-  r = fe_equal(t.v[0],0);
+  r = (int)fe_equal(t.v[0],0);
   for(i=1;i<32;i++) 
-    r &= fe_equal(t.v[i],0);
+    r &= (int)fe_equal(t.v[i],0);
   return r;
 }
 
@@ -143,7 +143,7 @@ void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b)
 {
   int i;
   uint32_t mask = b;
-  mask = -(int32_t)mask;
+  mask = (uint32_t)-(int32_t)mask;
   for(i=0;i<32;i++) r->v[i] ^= mask & (x->v[i] ^ r->v[i]);
 }
 
index 0c6273b..e14195d 100644 (file)
@@ -151,18 +151,18 @@ static void cmov_aff(ge25519_aff *r, const ge25519_aff *p, unsigned char b)
 
 static unsigned char ge_equal(signed char b,signed char c)
 {
-  unsigned char ub = b;
-  unsigned char uc = c;
+  unsigned char ub = (unsigned char)b;
+  unsigned char uc = (unsigned char)c;
   unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
   uint32_t y = x; /* 0: yes; 1..255: no */
   y -= 1; /* 4294967295: yes; 0..254: no */
   y >>= 31; /* 1: yes; 0: no */
-  return y;
+  return (unsigned char)y;
 }
 
 static unsigned char negative(signed char b)
 {
-  unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+  unsigned long long x = (unsigned long long)b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
   x >>= 63; /* 1: yes; 0: no */
   return (unsigned char)x;
 }
@@ -247,7 +247,7 @@ void ge25519_pack(unsigned char r[32], const ge25519_p3 *p)
   fe25519_mul(&tx, &p->x, &zi);
   fe25519_mul(&ty, &p->y, &zi);
   fe25519_pack(r, &ty);
-  r[31] ^= fe25519_getparity(&tx) << 7;
+  r[31] ^= (unsigned char)(fe25519_getparity(&tx) << 7);
 }
 
 int ge25519_isneutral_vartime(const ge25519_p3 *p)
index 6542667..75657a3 100644 (file)
@@ -80,10 +80,10 @@ poly1305_donna_16bytes:
        t3 = U8TO32_LE(m - 4);
 
        h0 += t0 & 0x3ffffff;
-       h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
-       h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
-       h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
-       h4 += (t3 >> 8) | (1 << 24);
+       h1 += (uint32_t)(((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff);
+       h2 += (uint32_t)(((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff);
+       h3 += (uint32_t)(((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff);
+       h4 += (uint32_t)((t3 >> 8) | (1 << 24));
 
 poly1305_donna_mul:
        t[0]  = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) +
@@ -130,10 +130,10 @@ poly1305_donna_atmost15bytes:
        t3 = U8TO32_LE(mp + 12);
 
        h0 += t0 & 0x3ffffff;
-       h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
-       h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
-       h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
-       h4 += (t3 >> 8);
+       h1 += (uint32_t)(((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff);
+       h2 += (uint32_t)(((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff);
+       h3 += (uint32_t)(((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff);
+       h4 += (uint32_t)(t3 >> 8);
 
        goto poly1305_donna_mul;
 
index fdb5a80..53acc3e 100644 (file)
@@ -39,7 +39,7 @@ static void sc_reduce_add_sub(sc25519 *r)
   {
     pb += m[i];
     b = lt(r->v[i],pb);
-    t[i] = r->v[i]-pb+(b<<8);
+    t[i] = (unsigned char)(r->v[i]-pb+(b<<8));
     pb = b;
   }
   mask = b - 1;
@@ -134,7 +134,7 @@ void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x)
 void sc25519_to32bytes(unsigned char r[32], const sc25519 *x)
 {
   int i;
-  for(i=0;i<32;i++) r[i] = x->v[i];
+  for(i=0;i<32;i++) r[i] = (unsigned char)x->v[i];
 }
 
 int sc25519_iszero_vartime(const sc25519 *x)
@@ -170,8 +170,8 @@ void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y)
   for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i];
   for(i=0;i<31;i++)
   {
-    carry = r->v[i] >> 8;
-    r->v[i+1] += carry;
+    carry = (int)r->v[i] >> 8;
+    r->v[i+1] += (uint32_t)carry;
     r->v[i] &= 0xff;
   }
   sc_reduce_add_sub(r);
@@ -202,8 +202,8 @@ void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y)
   /* Reduce coefficients */
   for(i=0;i<63;i++)
   {
-    carry = t[i] >> 8;
-    t[i+1] += carry;
+    carry = (int)t[i] >> 8;
+    t[i+1] += (uint32_t)carry;
     t[i] &= 0xff;
   }
 
@@ -226,18 +226,18 @@ void sc25519_window3(signed char r[85], const sc25519 *s)
     r[8*i+0]  =  s->v[3*i+0]       & 7;
     r[8*i+1]  = (s->v[3*i+0] >> 3) & 7;
     r[8*i+2]  = (s->v[3*i+0] >> 6) & 7;
-    r[8*i+2] ^= (s->v[3*i+1] << 2) & 7;
+    r[8*i+2] =  (signed char)(r[8*i+2] ^ (int)((s->v[3*i+1] << 2) & 7));
     r[8*i+3]  = (s->v[3*i+1] >> 1) & 7;
     r[8*i+4]  = (s->v[3*i+1] >> 4) & 7;
     r[8*i+5]  = (s->v[3*i+1] >> 7) & 7;
-    r[8*i+5] ^= (s->v[3*i+2] << 1) & 7;
+    r[8*i+5] =  (signed char)(r[8*i+5] ^ (int)((s->v[3*i+2] << 1) & 7));
     r[8*i+6]  = (s->v[3*i+2] >> 2) & 7;
     r[8*i+7]  = (s->v[3*i+2] >> 5) & 7;
   }
   r[8*i+0]  =  s->v[3*i+0]       & 7;
   r[8*i+1]  = (s->v[3*i+0] >> 3) & 7;
   r[8*i+2]  = (s->v[3*i+0] >> 6) & 7;
-  r[8*i+2] ^= (s->v[3*i+1] << 2) & 7;
+  r[8*i+2]  = (signed char)(r[8*i+2] ^ (int)((s->v[3*i+1] << 2) & 7));
   r[8*i+3]  = (s->v[3*i+1] >> 1) & 7;
   r[8*i+4]  = (s->v[3*i+1] >> 4) & 7;
 
@@ -245,13 +245,13 @@ void sc25519_window3(signed char r[85], const sc25519 *s)
   carry = 0;
   for(i=0;i<84;i++)
   {
-    r[i] += carry;
-    r[i+1] += r[i] >> 3;
+    r[i] = (signed char)(r[i] + carry);
+    r[i+1] = (signed char)(r[i + 1] + (r[i] >> 3));
     r[i] &= 7;
-    carry = r[i] >> 2;
-    r[i] -= carry<<3;
+    carry = (char)(r[i] >> 2);
+    r[i] = (signed char)(r[i] - (carry<<3));
   }
-  r[84] += carry;
+  r[84] = (signed char)(r[84] + (signed char)carry);
 }
 
 void sc25519_window5(signed char r[51], const sc25519 *s)
@@ -262,33 +262,33 @@ void sc25519_window5(signed char r[51], const sc25519 *s)
   {
     r[8*i+0]  =  s->v[5*i+0]       & 31;
     r[8*i+1]  = (s->v[5*i+0] >> 5) & 31;
-    r[8*i+1] ^= (s->v[5*i+1] << 3) & 31;
+    r[8*i+1] = (signed char)(r[8*i+1] ^ (int)((s->v[5*i+1] << 3) & 31));
     r[8*i+2]  = (s->v[5*i+1] >> 2) & 31;
     r[8*i+3]  = (s->v[5*i+1] >> 7) & 31;
-    r[8*i+3] ^= (s->v[5*i+2] << 1) & 31;
+    r[8*i+3] = (signed char)(r[8*i+3] ^ (int)((s->v[5*i+2] << 1) & 31));
     r[8*i+4]  = (s->v[5*i+2] >> 4) & 31;
-    r[8*i+4] ^= (s->v[5*i+3] << 4) & 31;
+    r[8*i+4] = (signed char)(r[8*i+4] ^ (int)((s->v[5*i+3] << 4) & 31));
     r[8*i+5]  = (s->v[5*i+3] >> 1) & 31;
     r[8*i+6]  = (s->v[5*i+3] >> 6) & 31;
-    r[8*i+6] ^= (s->v[5*i+4] << 2) & 31;
+    r[8*i+6] = (signed char)(r[8*i+6] ^ (int)((s->v[5*i+4] << 2) & 31));
     r[8*i+7]  = (s->v[5*i+4] >> 3) & 31;
   }
   r[8*i+0]  =  s->v[5*i+0]       & 31;
   r[8*i+1]  = (s->v[5*i+0] >> 5) & 31;
-  r[8*i+1] ^= (s->v[5*i+1] << 3) & 31;
+  r[8*i+1] = (signed char)(r[8*i+1] ^ (int)((s->v[5*i+1] << 3) & 31));
   r[8*i+2]  = (s->v[5*i+1] >> 2) & 31;
 
   /* Making it signed */
   carry = 0;
   for(i=0;i<50;i++)
   {
-    r[i] += carry;
-    r[i+1] += r[i] >> 5;
+    r[i] = (signed char)(r[i] + (signed char)carry);
+    r[i+1] = (signed char)(r[i + 1] + (r[i] >> 5));
     r[i] &= 31;
-    carry = r[i] >> 4;
-    r[i] -= carry<<5;
+    carry = (char)(r[i] >> 4);
+    r[i] = (signed char)(r[i] - (carry<<5));
   }
-  r[50] += carry;
+  r[50] = (signed char)(r[50] + carry);
 }
 
 void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2)
@@ -296,12 +296,12 @@ void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519
   int i;
   for(i=0;i<31;i++)
   {
-    r[4*i]   = ( s1->v[i]       & 3) ^ (( s2->v[i]       & 3) << 2);
-    r[4*i+1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2);
-    r[4*i+2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2);
-    r[4*i+3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2);
+    r[4*i]   = (unsigned char)(( s1->v[i]       & 3) ^ (( s2->v[i]       & 3) << 2));
+    r[4*i+1] = (unsigned char)(((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2));
+    r[4*i+2] = (unsigned char)(((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2));
+    r[4*i+3] = (unsigned char)(((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2));
   }
-  r[124] = ( s1->v[31]       & 3) ^ (( s2->v[31]       & 3) << 2);
-  r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2);
-  r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2);
+  r[124] = (unsigned char)(( s1->v[31]       & 3) ^ (( s2->v[31]       & 3) << 2));
+  r[125] = (unsigned char)(((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2));
+  r[126] = (unsigned char)(((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2));
 }
index bd5250f..d3cd8ec 100644 (file)
@@ -53,7 +53,7 @@ static void freeze(unsigned int a[32])
 
   for (j = 0;j < 32;++j) aorig[j] = a[j];
   add(a,a,minusp);
-  negative = -(int)((a[31] >> 7) & 1);
+  negative = (unsigned int)-(int)((a[31] >> 7) & 1);
   for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]);
 }
 
@@ -150,7 +150,7 @@ static void mainloop(unsigned int work[64],const unsigned char e[32])
   for (j = 1;j < 64;++j) xzm[j] = 0;
 
   for (pos = 254;pos >= 0;--pos) {
-    b = e[pos / 8] >> (pos & 7);
+    b = (unsigned int)(e[pos / 8] >> (pos & 7));
     b &= 1;
     smc_select(xzmb,xzm1b,xzm,xzm1,b);
     add(a0,xzmb,xzmb + 32);
@@ -260,6 +260,6 @@ int crypto_scalarmult_curve25519(unsigned char *q,
   recip(work + 32,work + 32);
   mult(work + 64,work,work + 32);
   freeze(work + 64);
-  for (i = 0;i < 32;++i) q[i] = work[64 + i];
+  for (i = 0;i < 32;++i) q[i] = (unsigned char)work[64 + i];
   return 0;
 }
index 8626daa..92569da 100644 (file)
@@ -1,22 +1,25 @@
 /*
- * libwebsockets - lws-plugin-ssh-base
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #if !defined(__LWS_PLUGIN_SSH_H__)
index 10de9ff..8796dd2 100644 (file)
@@ -1,27 +1,34 @@
 /*
- * libwebsockets - lws-plugin-ssh-base
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #if !defined(__LWS_SSH_H__)
 #define __LWS_SSH_H__
 
+#if defined(LWS_HAVE_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
 #if defined(LWS_WITH_MBEDTLS)
 #include "mbedtls/sha1.h"
 #include "mbedtls/sha256.h"
 #define POKE_U64(p, v) \
         do { \
                 const uint64_t __v = (v); \
-                ((uint8_t *)(p))[0] = (__v >> 56) & 0xff; \
-                ((uint8_t *)(p))[1] = (__v >> 48) & 0xff; \
-                ((uint8_t *)(p))[2] = (__v >> 40) & 0xff; \
-                ((uint8_t *)(p))[3] = (__v >> 32) & 0xff; \
-                ((uint8_t *)(p))[4] = (__v >> 24) & 0xff; \
-                ((uint8_t *)(p))[5] = (__v >> 16) & 0xff; \
-                ((uint8_t *)(p))[6] = (__v >> 8) & 0xff; \
-                ((uint8_t *)(p))[7] = __v & 0xff; \
+                ((uint8_t *)(p))[0] = (uint8_t)((__v >> 56) & 0xff); \
+                ((uint8_t *)(p))[1] = (uint8_t)((__v >> 48) & 0xff); \
+                ((uint8_t *)(p))[2] = (uint8_t)((__v >> 40) & 0xff); \
+                ((uint8_t *)(p))[3] = (uint8_t)((__v >> 32) & 0xff); \
+                ((uint8_t *)(p))[4] = (uint8_t)((__v >> 24) & 0xff); \
+                ((uint8_t *)(p))[5] = (uint8_t)((__v >> 16) & 0xff); \
+                ((uint8_t *)(p))[6] = (uint8_t)((__v >> 8) & 0xff); \
+                ((uint8_t *)(p))[7] = (uint8_t)(__v & 0xff); \
         } while (0)
 #define POKE_U32(p, v) \
         do { \
                 const uint32_t __v = (v); \
-                ((uint8_t *)(p))[0] = (__v >> 24) & 0xff; \
-                ((uint8_t *)(p))[1] = (__v >> 16) & 0xff; \
-                ((uint8_t *)(p))[2] = (__v >> 8) & 0xff; \
-                ((uint8_t *)(p))[3] = __v & 0xff; \
+                ((uint8_t *)(p))[0] = (uint8_t)((__v >> 24) & 0xff); \
+                ((uint8_t *)(p))[1] = (uint8_t)((__v >> 16) & 0xff); \
+                ((uint8_t *)(p))[2] = (uint8_t)((__v >> 8) & 0xff); \
+                ((uint8_t *)(p))[3] = (uint8_t)(__v & 0xff); \
         } while (0)
 #define POKE_U16(p, v) \
         do { \
@@ -272,6 +279,11 @@ enum {
 
        SSHS_NVC_CHRQ_SUBSYSTEM,
 
+       SSHS_NVC_CHRQ_WNDCHANGE_TW,
+       SSHS_NVC_CHRQ_WNDCHANGE_TH,
+       SSHS_NVC_CHRQ_WNDCHANGE_TWP,
+       SSHS_NVC_CHRQ_WNDCHANGE_THP,
+
        SSHS_NVC_CH_EOF,
        SSHS_NVC_CH_CLOSE,
 
index 2fd3aa4..a7bac40 100644 (file)
@@ -1,23 +1,27 @@
 /*
- * libwebsockets - lws-plugin-ssh-base - kex-25519.c
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
+
 #include "libwebsockets.h"
 #include "lws-ssh.h"
 
@@ -71,7 +75,7 @@ lws_gen_server_key_ed25519(struct lws_context *context, uint8_t *buf256,
 
        lwsl_notice("%s: Generated key len %ld\n", __func__, (long)(p - buf256));
 
-       return p - buf256;
+       return (size_t)(p - buf256);
 }
 
 static int
@@ -96,10 +100,10 @@ lws_mpint_rfc4251(uint8_t *dest, const uint8_t *src, int bytes, int uns)
        if (uns && (*src) & 0x80)
                bytes++;
 
-       *dest++ = bytes >> 24;
-       *dest++ = bytes >> 16;
-       *dest++ = bytes >> 8;
-       *dest++ = bytes;
+       *dest++ = (uint8_t)(bytes >> 24);
+       *dest++ = (uint8_t)(bytes >> 16);
+       *dest++ = (uint8_t)(bytes >> 8);
+       *dest++ = (uint8_t)(bytes);
 
        if (uns && (*src) & 0x80) {
                *dest++ = 0;
@@ -146,7 +150,7 @@ ed25519_key_parse(uint8_t *p, size_t len, char *type, size_t type_len,
                return 6;
 
        publ = lws_g32(&p); /* length of pubkey block */
-       if ((size_t)((p - op) + publ) >= len)
+       if ((size_t)((uint32_t)(p - op) + publ) >= len)
                return 7;
 
        l = lws_g32(&p); /* key type length */
@@ -165,7 +169,7 @@ ed25519_key_parse(uint8_t *p, size_t len, char *type, size_t type_len,
        p += l;
 
        publ = lws_g32(&p); /* length of private key block */
-       if ((size_t)((p - op) + publ) != len)
+       if ((size_t)((uint32_t)(p - op) + publ) != len)
                return 11;
 
        l = lws_g32(&p); /* checkint 1 */
@@ -239,7 +243,7 @@ kex_ecdh_dv(uint8_t *dest, int dest_len, const uint8_t *kbi, int kbi_len,
                if (lws_genhash_init(&ctx, LWS_GENHASH_TYPE_SHA256))
                        return 1;
 
-               if (lws_genhash_update(&ctx, kbi, kbi_len))
+               if (lws_genhash_update(&ctx, kbi, (unsigned int)kbi_len))
                        goto hash_failed;
                if (lws_genhash_update(&ctx, H, LWS_SIZE_SHA256))
                        goto hash_failed;
@@ -260,7 +264,7 @@ kex_ecdh_dv(uint8_t *dest, int dest_len, const uint8_t *kbi, int kbi_len,
                if (m > (dest_len - n))
                        m = dest_len - n;
 
-               memcpy(dest, pool, m);
+               memcpy(dest, pool, (unsigned int)m);
                n += m;
                dest += m;
        }
@@ -321,7 +325,7 @@ kex_ecdh(struct per_session_data__sshd *pss, uint8_t *reply, uint32_t *plen)
                return 1;
        }
 
-       r = ed25519_key_parse(servkey, r, keyt, sizeof(keyt),
+       r = ed25519_key_parse(servkey, (unsigned int)r, keyt, sizeof(keyt),
                              pss->K_S /* public key */, pri_key);
        if (r) {
                lwsl_notice("%s: server key parse failed: %d\n", __func__, r);
@@ -383,7 +387,7 @@ kex_ecdh(struct per_session_data__sshd *pss, uint8_t *reply, uint32_t *plen)
         * integer k.  This conversion follows the network byte order. This
         * step differs from RFC5656.
         */
-       kbi_len = lws_mpint_rfc4251(kbi, pss->K, LWS_SIZE_EC25519, 1);
+       kbi_len = (uint32_t)lws_mpint_rfc4251(kbi, pss->K, LWS_SIZE_EC25519, 1);
 
        /*
         * The exchange hash H is computed as the hash of the concatenation of
@@ -425,7 +429,7 @@ kex_ecdh(struct per_session_data__sshd *pss, uint8_t *reply, uint32_t *plen)
         * name length: name
         * key length: key
         * ---> */
-       lws_p32((uint8_t *)&be, 8 + (int)strlen(keyt) + LWS_SIZE_EC25519);
+       lws_p32((uint8_t *)&be, (uint32_t)(8 + (int)strlen(keyt) + LWS_SIZE_EC25519));
        if (lws_genhash_update(&ctx, (void *)&be, 4))
                goto hash_probs;
 
@@ -480,9 +484,9 @@ kex_ecdh(struct per_session_data__sshd *pss, uint8_t *reply, uint32_t *plen)
 
        lp = p;
        p +=4;
-       lws_sized_blob(&p, keyt, (int)strlen(keyt));
+       lws_sized_blob(&p, keyt, (uint32_t)strlen(keyt));
        lws_sized_blob(&p, pss->K_S, LWS_SIZE_EC25519);
-       lws_p32(lp, lws_ptr_diff(p, lp) - 4);
+       lws_p32(lp, (uint32_t)(lws_ptr_diff(p, lp) - 4));
 
        /* Q_S (exchange value sent by the server) */
        
@@ -492,14 +496,14 @@ kex_ecdh(struct per_session_data__sshd *pss, uint8_t *reply, uint32_t *plen)
 
        lp = p;
        p +=4;
-       lws_sized_blob(&p, keyt, (int)strlen(keyt));
+       lws_sized_blob(&p, keyt, (uint32_t)strlen(keyt));
        lws_sized_blob(&p, payload_sig, 64);
-       lws_p32(lp, lws_ptr_diff(p, lp) - 4);
+       lws_p32(lp, (uint32_t)(lws_ptr_diff(p, lp) - 4));
 
        /* end of message */
 
        lws_pad_set_length(pss, reply, &p, &pss->active_keys_stc);
-       *plen = lws_ptr_diff(p, reply);
+       *plen = (uint32_t)lws_ptr_diff(p, reply);
 
        if (!pss->active_keys_stc.valid)
                memcpy(pss->session_id, temp, LWS_SIZE_EC25519);
@@ -529,9 +533,11 @@ kex_ecdh(struct per_session_data__sshd *pss, uint8_t *reply, uint32_t *plen)
         */
        for (c = 0; c < 3; c++) {
                kex_ecdh_dv(kex->keys_next_cts.key[c], LWS_SIZE_CHACHA256_KEY,
-                           kbi, kbi_len, temp, 'A' + (c * 2), pss->session_id);
+                           kbi, (int)kbi_len, temp, (char)('A' + (c * 2)),
+                           pss->session_id);
                kex_ecdh_dv(kex->keys_next_stc.key[c], LWS_SIZE_CHACHA256_KEY,
-                           kbi, kbi_len, temp, 'B' + (c * 2), pss->session_id);
+                           kbi, (int)kbi_len, temp, (char)('B' + (c * 2)),
+                           pss->session_id);
        }
 
        lws_explicit_bzero(temp, sizeof(temp));
index 62e0151..90fa3d7 100644 (file)
@@ -1,22 +1,25 @@
 /*
- * libwebsockets - lws-plugin-ssh-base - sshd.c
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #include "libwebsockets.h"
@@ -51,10 +54,10 @@ lws_g32(uint8_t **p)
 uint32_t
 lws_p32(uint8_t *p, uint32_t v)
 {
-       *p++ = v >> 24;
-       *p++ = v >> 16;
-       *p++ = v >> 8;
-       *p++ = v;
+       *p++ = (uint8_t)(v >> 24);
+       *p++ = (uint8_t)(v >> 16);
+       *p++ = (uint8_t)(v >> 8);
+       *p++ = (uint8_t)v;
 
        return v;
 }
@@ -90,7 +93,7 @@ void
 write_task(struct per_session_data__sshd *pss, struct lws_ssh_channel *ch,
           int task)
 {
-       pss->write_task[pss->wt_head] = task;
+       pss->write_task[pss->wt_head] = (uint8_t)task;
        pss->write_channel[pss->wt_head] = ch;
        pss->wt_head = (pss->wt_head + 1) & 7;
        lws_callback_on_writable(pss->wsi);
@@ -101,7 +104,7 @@ write_task_insert(struct per_session_data__sshd *pss, struct lws_ssh_channel *ch
           int task)
 {
        pss->wt_tail = (pss->wt_tail - 1) & 7;
-       pss->write_task[pss->wt_tail] = task;
+       pss->write_task[pss->wt_tail] = (uint8_t)task;
        pss->write_channel[pss->wt_tail] = ch;
        lws_callback_on_writable(pss->wsi);
 }
@@ -111,15 +114,15 @@ void
 lws_pad_set_length(struct per_session_data__sshd *pss, void *start, uint8_t **p,
                   struct lws_ssh_keys *keys)
 {
-       uint32_t len = lws_ptr_diff(*p, start);
+       uint32_t len = (uint32_t)lws_ptr_diff(*p, start);
        uint8_t padc = 4, *bs = start;
 
        if (keys->full_length)
                len -= 4;
 
-       if ((len + padc) & (keys->padding_alignment - 1))
-               padc += keys->padding_alignment -
-                       ((len + padc) & (keys->padding_alignment - 1));
+       if ((len + padc) & (uint32_t)(keys->padding_alignment - 1))
+               padc = (uint8_t)((uint8_t)padc + (uint8_t)(keys->padding_alignment -
+                       ((len + padc) & (uint32_t)(keys->padding_alignment - 1))));
 
        bs[4] = padc;
        len += padc;
@@ -152,7 +155,7 @@ offer(struct per_session_data__sshd *pss, uint8_t *p, uint32_t len, int first,
                return 1;
        }
        lwsl_info("keylen %d\n", keylen);
-       n = ed25519_key_parse(keybuf, keylen,
+       n = ed25519_key_parse(keybuf, (unsigned int)keylen,
                              keyt, sizeof(keyt), NULL, NULL);
        if (n) {
                lwsl_notice("unable to parse server key: %d\n", n);
@@ -186,61 +189,61 @@ offer(struct per_session_data__sshd *pss, uint8_t *p, uint32_t len, int first,
 
        lp = p;
        p += 4;
-       n = lws_snprintf((char *)p, end - p, "curve25519-sha256@libssh.org");
-       p += lws_p32(lp, n);
+       n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "curve25519-sha256@libssh.org");
+       p += lws_p32(lp, (uint32_t)n);
 
        /* Server Host Key Algorithms */
 
        lp = p;
        p += 4;
-       n = lws_snprintf((char *)p, end - p, "%s", keyt);
-       p += lws_p32(lp, n);
+       n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "%s", keyt);
+       p += lws_p32(lp, (uint32_t)n);
 
        /* Encryption Algorithms: C -> S */
 
        lp = p;
        p += 4;
 //     n = lws_snprintf((char *)p, end - p, "aes256-gcm@openssh.com");
-       n = lws_snprintf((char *)p, end - p, "chacha20-poly1305@openssh.com");
-       p += lws_p32(lp, n);
+       n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "chacha20-poly1305@openssh.com");
+       p += lws_p32(lp, (uint32_t)n);
 
        /* Encryption Algorithms: S -> C */
 
        lp = p;
        p += 4;
 //     n = lws_snprintf((char *)p, end - p, "aes256-gcm@openssh.com");
-       n = lws_snprintf((char *)p, end - p, "chacha20-poly1305@openssh.com");
-       p += lws_p32(lp, n);
+       n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "chacha20-poly1305@openssh.com");
+       p += lws_p32(lp, (uint32_t)n);
 
        /* MAC Algorithms: C -> S */
 
        lp = p;
        p += 4;
        /* bogus: chacha20 does not use MACs, but 'none' is not offered */
-       n = lws_snprintf((char *)p, end - p, "hmac-sha2-256");
-       p += lws_p32(lp, n);
+       n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "hmac-sha2-256");
+       p += lws_p32(lp, (uint32_t)n);
 
        /* MAC Algorithms: S -> C */
 
        lp = p;
        p += 4;
        /* bogus: chacha20 does not use MACs, but 'none' is not offered */
-       n = lws_snprintf((char *)p, end - p, "hmac-sha2-256");
-       p += lws_p32(lp, n);
+       n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "hmac-sha2-256");
+       p += lws_p32(lp, (uint32_t)n);
 
        /* Compression Algorithms: C -> S */
 
        lp = p;
        p += 4;
-       n = lws_snprintf((char *)p, end - p, "none");
-       p += lws_p32(lp, n);
+       n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "none");
+       p += lws_p32(lp, (uint32_t)n);
 
        /* Compression Algorithms: S -> C */
 
        lp = p;
        p += 4;
-       n = lws_snprintf((char *)p, end - p, "none");
-       p += lws_p32(lp, n);
+       n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "none");
+       p += lws_p32(lp, (uint32_t)n);
 
        if (p - op < 13 + padc + 8)
                return 0;
@@ -270,18 +273,18 @@ offer(struct per_session_data__sshd *pss, uint8_t *p, uint32_t len, int first,
        *p++ = 0;
        *p++ = 0;
 
-       len = lws_ptr_diff(p, op);
+       len = (uint32_t)lws_ptr_diff(p, op);
        if (payload_len)
                /* starts at buf + 5 and excludes padding */
-               *payload_len = len - 5;
+               *payload_len = (int)(len - 5);
 
        /* we must give at least 4 bytes of 00 padding */
 
-       if ((len + padc) & 7)
-               padc += 8 - ((len + padc) & 7);
+       if (((int)len + padc) & 7)
+               padc += 8 - (((int)len + padc) & 7);
 
-       op[4] = padc;
-       len += padc;
+       op[4] = (uint8_t)padc;
+       len += (uint32_t)padc;
 
        while (padc--)
                *p++ = 0;
@@ -309,7 +312,7 @@ handle_name(struct per_session_data__sshd *pss)
                len = (int)get_gen_server_key_25519(pss, keybuf, (int)sizeof(keybuf));
                if (!len)
                        break;
-               if (ed25519_key_parse(keybuf, len,
+               if (ed25519_key_parse(keybuf, (unsigned int)len,
                                      keyt, sizeof(keyt),
                                      NULL, NULL)) {
                        lwsl_err("Unable to parse host key %d\n", n);
@@ -442,21 +445,21 @@ static void
 state_get_string_alloc(struct per_session_data__sshd *pss, int next)
 {
        pss->parser_state = SSHS_GET_STRING_LEN_ALLOC;
-        pss->state_after_string = next;
+        pss->state_after_string = (char)next;
 }
 
 static void
 state_get_string(struct per_session_data__sshd *pss, int next)
 {
        pss->parser_state = SSHS_GET_STRING_LEN;
-        pss->state_after_string = next;
+        pss->state_after_string = (char)next;
 }
 
 static void
 state_get_u32(struct per_session_data__sshd *pss, int next)
 {
        pss->parser_state = SSHS_GET_U32;
-        pss->state_after_string = next;
+        pss->state_after_string = (char)next;
 }
 
 static struct lws_ssh_channel *
@@ -530,7 +533,10 @@ lws_ssh_parse_plaintext(struct per_session_data__sshd *pss, uint8_t *p, size_t l
        struct lws_genrsa_ctx ctx;
        struct lws_ssh_channel *ch;
        struct lws_subprotocol_scp *scp;
-       uint8_t *pp, *ps, hash[64], *otmp;
+       uint8_t *pp, *ps, hash[64];
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
+       uint8_t *otmp = NULL;
+#endif
        uint32_t m;
        int n;
 
@@ -553,7 +559,7 @@ again:
                                break;
                        }
                        if (pss->npos < sizeof(pss->V_C) - 1)
-                               pss->V_C[pss->npos++] = *p;
+                               pss->V_C[pss->npos++] = (char)*p;
                        p++;
                        break;
 
@@ -574,7 +580,7 @@ again:
                        if (pss->active_keys_cts.valid) {
                                uint8_t b[4];
 
-                               POKE_U32(b, pss->msg_len);
+                               POKE_U32(b, (uint32_t)pss->msg_len);
                                pss->msg_len = lws_chachapoly_get_length(
                                        &pss->active_keys_cts,
                                        pss->ssh_sequence_ctr_cts, b);
@@ -865,7 +871,7 @@ again:
                case SSH_KEX_NL_LSTC_ALGS:
                        if (*p != ',') {
                                if (pss->npos < sizeof(pss->name) - 1)
-                                       pss->name[pss->npos++] = *p;
+                                       pss->name[pss->npos++] = (char)*p;
                        } else {
                                pss->name[pss->npos] = '\0';
                                pss->npos = 0;
@@ -965,7 +971,7 @@ again:
                                lwsl_notice("non-alloc string too big\n");
                                goto bail;
                        }
-                       pss->name[pss->npos++] = *p++;
+                       pss->name[pss->npos++] = (char)*p++;
                        if (pss->npos != pss->len)
                                break;
 
@@ -1077,7 +1083,7 @@ again:
 
                case SSHS_DO_UAR_SIG_PRESENT:
                        lwsl_info("SSHS_DO_UAR_SIG_PRESENT\n");
-                       pss->ua->sig_present = *p++;
+                       pss->ua->sig_present = (char)*p++;
                        state_get_string_alloc(pss, SSHS_NVC_DO_UAR_ALG);
                        /* destroyed with UA struct */
                        break;
@@ -1114,7 +1120,7 @@ again:
                        if (pss->vhd->ops && pss->vhd->ops->is_pubkey_authorized)
                                n = pss->vhd->ops->is_pubkey_authorized(
                                        pss->ua->username, pss->ua->alg,
-                                       pss->ua->pubkey, pss->ua->pubkey_len);
+                                       pss->ua->pubkey, (int)pss->ua->pubkey_len);
                        if (n) {
                                lwsl_info("rejecting peer pubkey\n");
                                goto ua_fail;
@@ -1190,7 +1196,7 @@ again:
                            4 + (int)strlen(pss->ua->alg) +
                            4 + (int)pss->ua->pubkey_len;
 
-                       ps = sshd_zalloc(n);
+                       ps = sshd_zalloc((unsigned int)n);
                        if (!ps) {
                                lwsl_notice("OOM 4\n");
                                goto ua_fail;
@@ -1209,13 +1215,13 @@ again:
                        /* Next hash the plaintext */
 
                        if (lws_genhash_init(&pss->ua->hash_ctx,
-                               rsa_hash_alg_from_ident(pss->ua->alg))) {
+                               (enum lws_genhash_types)rsa_hash_alg_from_ident(pss->ua->alg))) {
                                lwsl_notice("genhash init failed\n");
                                free(ps);
                                goto ua_fail;
                        }
 
-                       if (lws_genhash_update(&pss->ua->hash_ctx, ps, pp - ps)) {
+                       if (lws_genhash_update(&pss->ua->hash_ctx, ps, lws_ptr_diff_size_t(pp, ps))) {
                                lwsl_notice("genhash update failed\n");
                                free(ps);
                                goto ua_fail;
@@ -1244,7 +1250,6 @@ again:
                                              LGRSAM_PKCS1_1_5,
                                              LWS_GENHASH_TYPE_UNKNOWN))
                                goto ua_fail;
-
                        /*
                         * point to the encrypted signature payload we
                         * were sent
@@ -1253,6 +1258,7 @@ again:
                        m = lws_g32(&pp);
                        pp += m;
                        m = lws_g32(&pp);
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
 
                        /*
                         * decrypt it, resulting in an error, or some ASN1
@@ -1272,8 +1278,8 @@ again:
                                        if (otmp[m] == 0x04 &&
                                            otmp[m + 1] == lws_genhash_size(
                                                  pss->ua->hash_ctx.type)) {
-                                               m = memcmp(&otmp[m + 2], hash,
-                                               lws_genhash_size(pss->ua->hash_ctx.type));
+                                               m = (uint32_t)memcmp(&otmp[m + 2], hash,
+                                                       (unsigned int)lws_genhash_size(pss->ua->hash_ctx.type));
                                                break;
                                        }
                                        /* go into these */
@@ -1282,11 +1288,17 @@ again:
                                                continue;
                                        }
                                        /* otherwise skip payloads */
-                                       m += otmp[m + 1] + 2;
+                                       m += (uint32_t)(otmp[m + 1] + 2);
                                }
                        }
 
                        free(otmp);
+               #else
+                       ctx.ctx->MBEDTLS_PRIVATE(len) = m;
+                       n = lws_genrsa_hash_sig_verify(&ctx, hash,
+                               (enum lws_genhash_types)rsa_hash_alg_from_ident(pss->ua->alg),
+                               pp, m) == 0 ? 1 : 0;
+               #endif
                        lws_genrsa_destroy(&ctx);
 
                        /*
@@ -1377,13 +1389,13 @@ again:
                        break;
                case SSHS_NVC_CHOPEN_WINSIZE:
                        lwsl_info("Initial window set to %d\n", pss->len);
-                       pss->ch_temp->window = pss->len;
+                       pss->ch_temp->window = (int32_t)pss->len;
                        state_get_u32(pss, SSHS_NVC_CHOPEN_PKTSIZE);
                        break;
                case SSHS_NVC_CHOPEN_PKTSIZE:
                        pss->ch_temp->max_pkt = pss->len;
                        pss->ch_temp->peer_window_est = LWS_SSH_INITIAL_WINDOW;
-                       pss->ch_temp->server_ch = pss->next_ch_num++;
+                       pss->ch_temp->server_ch = (uint32_t)pss->next_ch_num++;
                        /*
                         * add us to channel list... leave as ch_temp
                         * as write task needs it and will NULL down
@@ -1471,6 +1483,12 @@ again:
                                                       SSHS_NVC_CHRQ_SUBSYSTEM);
                                break;
                        }
+                       if (!strcmp(pss->name, "window-change")) {
+                               lwsl_info("%s: window-change\n", __func__);
+                               state_get_u32(pss,
+                                             SSHS_NVC_CHRQ_WNDCHANGE_TW);
+                               break;
+                       }
 
                        if (pss->rq_want_reply)
                                goto chrq_fail;
@@ -1626,13 +1644,41 @@ again:
                        break;
 #endif
 
+               /* CHRQ window-change */
+
+       case SSHS_NVC_CHRQ_WNDCHANGE_TW:
+               pss->args.pty.width_ch = pss->len;
+               state_get_u32(pss, SSHS_NVC_CHRQ_WNDCHANGE_TH);
+               break;
+        case SSHS_NVC_CHRQ_WNDCHANGE_TH:
+               pss->args.pty.height_ch = pss->len;
+               state_get_u32(pss, SSHS_NVC_CHRQ_WNDCHANGE_TWP);
+               break;
+        case SSHS_NVC_CHRQ_WNDCHANGE_TWP:
+               pss->args.pty.width_px = pss->len;
+               state_get_u32(pss, SSHS_NVC_CHRQ_WNDCHANGE_THP);
+               break;
+        case SSHS_NVC_CHRQ_WNDCHANGE_THP:
+               pss->args.pty.height_px = pss->len;
+               pss->args.pty.term[0] = 0;
+               pss->args.pty.modes = NULL;
+               pss->args.pty.modes_len = 0;
+               n = 0;
+               if (pss->vhd->ops && pss->vhd->ops->pty_req)
+                       n = pss->vhd->ops->pty_req(pss->ch_temp->priv,
+                                                  &pss->args.pty);
+               if (n)
+                       goto chrq_fail;
+               pss->parser_state = SSHS_MSG_EAT_PADDING;
+               break;
+
                /* SSH_MSG_CHANNEL_DATA */
 
                case SSHS_NVC_CD_RECIP:
                        pss->ch_recip = pss->len;
 
                        ch = ssh_get_server_ch(pss, pss->ch_recip);
-                       ch->peer_window_est -= pss->msg_len;
+                       ch->peer_window_est -= (int32_t)pss->msg_len;
 
                        if (pss->msg_len < sizeof(pss->name))
                                state_get_string(pss, SSHS_NVC_CD_DATA);
@@ -1673,7 +1719,7 @@ again:
                                                        pss->parser_state = SSHS_MSG_EAT_PADDING;
                                                        break;
                                                }
-                                               scp->len = atoll((const char *)pp);
+                                               scp->len = (uint64_t)atoll((const char *)pp);
                                                lwsl_notice("scp payload %llu expected\n",
                                                            (unsigned long long)scp->len);
                                                scp->ips = SSHS_SCP_PAYLOADIN;
@@ -1726,7 +1772,7 @@ again:
                case SSHS_NVC_WA_ADD:
                        ch = ssh_get_server_ch(pss, pss->ch_recip);
                        if (ch) {
-                               ch->window += pss->len;
+                               ch->window += (int32_t)pss->len;
                                lwsl_notice("got additional window %d (now %d)\n",
                                                pss->len, ch->window);
                        }
@@ -1819,7 +1865,9 @@ ch_fail:
                        pss->parser_state = SSH_KEX_STATE_SKIP;
                        break;
 
+#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
 ua_fail1:
+#endif
                        lws_genrsa_destroy(&ctx);
 ua_fail:
                        write_task(pss, NULL, SSH_WT_UA_FAILURE);
@@ -1901,7 +1949,7 @@ parse(struct per_session_data__sshd *pss, uint8_t *p, size_t len)
                                return 0;
 
                        /* decrypt it */
-                       cp = lws_chacha_decrypt(&pss->active_keys_cts,
+                       cp = (uint32_t)lws_chacha_decrypt(&pss->active_keys_cts,
                                                pss->ssh_sequence_ctr_cts++,
                                                pss->packet_assembly,
                                                pss->pa_pos, pt);
@@ -1941,7 +1989,7 @@ pad_and_encrypt(uint8_t *dest, void *ps, uint8_t *pp,
 
        if (!skip_pad)
                lws_pad_set_length(pss, ps, &pp, &pss->active_keys_stc);
-       n = lws_ptr_diff(pp, ps);
+       n = (uint32_t)lws_ptr_diff(pp, ps);
 
        if (!pss->active_keys_stc.valid) {
                memcpy(dest, ps, n);
@@ -1994,6 +2042,8 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                                                  lws_get_protocol(wsi),
                                                  sizeof(struct per_vhost_data__sshd));
+               if (!vhd)
+                       return 0;
                vhd->context = lws_get_context(wsi);
                vhd->protocol = lws_get_protocol(wsi);
                vhd->vhost = lws_get_vhost(wsi);
@@ -2025,8 +2075,8 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                }
 
                if (!vhd->ops) {
-                       lwsl_err("ssh pvo \"ops\" is mandatory\n");
-                       return 1;
+                       lwsl_warn("ssh pvo \"ops\" is mandatory\n");
+                       return 0;
                }
                /*
                 * The user code ops api_version has to be current
@@ -2040,7 +2090,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
 
         case LWS_CALLBACK_RAW_ADOPT:
                lwsl_info("LWS_CALLBACK_RAW_ADOPT\n");
-               if (!vhd)
+               if (!vhd || !pss)
                        return -1;
                pss->next = vhd->live_pss_list;
                vhd->live_pss_list = pss;
@@ -2062,7 +2112,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                 *
                 * The RECOMMENDED timeout period is 10 minutes.
                 */
-               lws_set_timeout(wsi,
+               lws_set_timeout(wsi, (enum pending_timeout)
                       SSH_PENDING_TIMEOUT_CONNECT_TO_SUCCESSFUL_AUTH, 10 * 60);
                 break;
 
@@ -2123,7 +2173,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                        if (!pss->vhd)
                                break;
                        m = 0;
-                       n = offer(pss, buf + LWS_PRE,
+                       n = (int)offer(pss, buf + LWS_PRE,
                                  sizeof(buf) - LWS_PRE, 0, &m);
                        if (n == 0) {
                                lwsl_notice("Too small\n");
@@ -2140,20 +2190,20 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                        /* we need a copy of it to generate the hash later */
                        if (pss->kex->I_S)
                                free(pss->kex->I_S);
-                       pss->kex->I_S = sshd_zalloc(m);
+                       pss->kex->I_S = sshd_zalloc((unsigned int)m);
                        if (!pss->kex->I_S) {
                                lwsl_notice("OOM 5: %d\n", m);
 
                                return -1;
                        }
                        /* without length + padcount part */
-                       memcpy(pss->kex->I_S, buf + LWS_PRE + 5, m);
-                       pss->kex->I_S_payload_len = m; /* without padding */
+                       memcpy(pss->kex->I_S, buf + LWS_PRE + 5, (unsigned int)m);
+                       pss->kex->I_S_payload_len = (uint32_t)m; /* without padding */
                        break;
 
                case SSH_WT_OFFER_REPLY:
                        memcpy(ps, pss->kex->kex_r, pss->kex->kex_r_len);
-                       n = pad_and_encrypt(&buf[LWS_PRE], ps,
+                       n = (int)pad_and_encrypt(&buf[LWS_PRE], ps,
                                            ps + pss->kex->kex_r_len, pss, 1);
                        pss->kex_state = KEX_STATE_REPLIED_TO_OFFER;
                        /* afterwards, must do newkeys */
@@ -2199,7 +2249,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                                n = (int)pss->vhd->ops->banner((char *)&buf[650],
                                                          150 - 1,
                                                          lang, (int)sizeof(lang));
-                       lws_p32(pp, n);
+                       lws_p32(pp, (uint32_t)n);
                        pp += 4;
                        strcpy((char *)pp, (char *)&buf[650]);
                        pp += n;
@@ -2217,12 +2267,12 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                         *    string    public key alg name from the request
                         *    string    public key blob from the request
                         */
-                       n = 74 + pss->ua->pubkey_len;
+                       n = 74 + (int)pss->ua->pubkey_len;
                        if (n > (int)sizeof(buf) - LWS_PRE) {
                                lwsl_notice("pubkey too large\n");
                                goto bail;
                        }
-                       ps1 = sshd_zalloc(n);
+                       ps1 = sshd_zalloc((unsigned int)n);
                        if (!ps1)
                                goto bail;
                        ps = ps1;
@@ -2252,10 +2302,10 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                case SSH_WT_CH_OPEN_CONF:
                        pp = ps + 5;
                        *pp++ = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
-                       lws_p32(pp, pss->ch_temp->server_ch);
-                       pp += 4;
                        lws_p32(pp, pss->ch_temp->sender_ch);
                        pp += 4;
+                       lws_p32(pp, pss->ch_temp->server_ch);
+                       pp += 4;
                        /* tx initial window size towards us */
                        lws_p32(pp, LWS_SSH_INITIAL_WINDOW);
                        pp += 4;
@@ -2270,10 +2320,10 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                case SSH_WT_CH_FAILURE:
                        pp = ps + 5;
                        *pp++ = SSH_MSG_CHANNEL_OPEN_FAILURE;
-                       lws_p32(pp, ch->server_ch);
-                       pp += 4;
                        lws_p32(pp, ch->sender_ch);
                        pp += 4;
+                       lws_p32(pp, ch->server_ch);
+                       pp += 4;
                        lws_cstr(&pp, "reason", 64);
                        lws_cstr(&pp, "en/US", 64);
                        lwsl_info("SSH_WT_CH_FAILURE\n");
@@ -2282,7 +2332,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                case SSH_WT_CHRQ_SUCC:
                        pp = ps + 5;
                        *pp++ = SSH_MSG_CHANNEL_SUCCESS;
-                       lws_p32(pp, ch->server_ch);
+                       lws_p32(pp, ch->sender_ch);
                        lwsl_info("SSH_WT_CHRQ_SUCC\n");
                        pp += 4;
                        goto pac;
@@ -2290,7 +2340,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                case SSH_WT_CHRQ_FAILURE:
                        pp = ps + 5;
                        *pp++ = SSH_MSG_CHANNEL_FAILURE;
-                       lws_p32(pp, ch->server_ch);
+                       lws_p32(pp, ch->sender_ch);
                        pp += 4;
                        lwsl_info("SSH_WT_CHRQ_FAILURE\n");
                        goto pac;
@@ -2298,7 +2348,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                case SSH_WT_CH_CLOSE:
                        pp = ps + 5;
                        *pp++ = SSH_MSG_CHANNEL_CLOSE;
-                       lws_p32(pp, ch->server_ch);
+                       lws_p32(pp, ch->sender_ch);
                        lwsl_info("SSH_WT_CH_CLOSE\n");
                        pp += 4;
                        goto pac;
@@ -2306,7 +2356,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                case SSH_WT_CH_EOF:
                        pp = ps + 5;
                        *pp++ = SSH_MSG_CHANNEL_EOF;
-                       lws_p32(pp, ch->server_ch);
+                       lws_p32(pp, ch->sender_ch);
                        lwsl_info("SSH_WT_CH_EOF\n");
                        pp += 4;
                        goto pac;
@@ -2348,7 +2398,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                        strcpy((char *)pp, "exit-status");
                        pp += 11;
                        *pp++ = 0;
-                       lws_p32(pp, ch->retcode);
+                       lws_p32(pp, (uint32_t)ch->retcode);
                        pp += 4;
                        lwsl_info("send SSH_MSG_CHANNEL_EXIT_STATUS\n");
                        goto pac;
@@ -2388,7 +2438,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                        else
                                *pp++ = SSH_MSG_CHANNEL_EXTENDED_DATA;
                        /* ps + 6 */
-                       lws_p32(pp, pss->ch_list->server_ch);
+                       lws_p32(pp, pss->ch_list->sender_ch);
                        m = 14;
                        if (n == LWS_STDERR) {
                                pp += 4;
@@ -2401,9 +2451,10 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
                        /* ps + 14 / + 18 */
 
                        pp += pss->vhd->ops->tx(ch->priv, n, pp,
-                                               &buf[sizeof(buf) - 1] - pp);
+                                               lws_ptr_diff_size_t(
+                                                       &buf[sizeof(buf) - 1], pp));
 
-                       lws_p32(ps + m - 4, lws_ptr_diff(pp, (ps + m)));
+                       lws_p32(ps + m - 4, (uint32_t)lws_ptr_diff(pp, (ps + m)));
 
                        if (pss->vhd->ops->tx_waiting(ch->priv) > 0)
                                lws_callback_on_writable(wsi);
@@ -2415,7 +2466,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
 pac:
                        if (!pss->vhd)
                                break;
-                       n = pad_and_encrypt(&buf[LWS_PRE], ps, pp, pss, 0);
+                       n = (int)pad_and_encrypt(&buf[LWS_PRE], ps, pp, pss, 0);
                        break;
 
 bail:
@@ -2427,7 +2478,7 @@ bail:
                }
 
                if (n > 0) {
-                       m = lws_write(wsi, (unsigned char *)buf + LWS_PRE, n,
+                       m = lws_write(wsi, (unsigned char *)buf + LWS_PRE, (unsigned int)n,
                                      LWS_WRITE_HTTP);
 
                        switch(o) {
@@ -2510,7 +2561,7 @@ bail:
                        break;
                ch = ssh_get_server_ch(pss, pss->channel_doing_spawn);
                if (ch) {
-                       ch->spawn_pid = (int)len; /* child process PID */
+                       ch->spawn_pid = (uint32_t)len; /* child process PID */
                        lwsl_notice("associated PID %d to ch %d\n", (int)len,
                                    pss->channel_doing_spawn);
                }
@@ -2555,34 +2606,25 @@ bail:
                1024, 0, NULL, 900      \
        }
 
-LWS_VISIBLE const struct lws_protocols protocols_sshd[] = {
+LWS_VISIBLE const struct lws_protocols lws_ssh_base_protocols[] = {
        LWS_PLUGIN_PROTOCOL_LWS_RAW_SSHD,
        { NULL, NULL, 0, 0, 0, NULL, 0 } /* terminator */
 };
 
 #if !defined (LWS_PLUGIN_STATIC)
 
-LWS_VISIBLE int
-init_protocol_lws_ssh_base(struct lws_context *context,
-                            struct lws_plugin_capability *c)
-{
-       if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
-               lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
-                        c->api_magic);
-               return 1;
-       }
-
-       c->protocols = protocols_sshd;
-       c->count_protocols = LWS_ARRAY_SIZE(protocols_sshd);
-       c->extensions = NULL;
-       c->count_extensions = 0;
-
-       return 0;
-}
+LWS_VISIBLE const lws_plugin_protocol_t lws_ssh_base = {
+       .hdr = {
+               "ssh base",
+               "lws_protocol_plugin",
+               LWS_BUILD_HASH,
+               LWS_PLUGIN_API_MAGIC
+       },
+
+       .protocols = lws_ssh_base_protocols,
+       .count_protocols = LWS_ARRAY_SIZE(lws_ssh_base_protocols),
+       .extensions = NULL,
+       .count_extensions = 0,
+};
 
-LWS_VISIBLE int
-destroy_protocol_lws_ssh_base(struct lws_context *context)
-{
-       return 0;
-}
 #endif
index 9d908fa..04b2e6b 100644 (file)
@@ -1,22 +1,25 @@
 /*
- * libwebsockets - lws-plugin-ssh-base
+ * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2017 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- *  This library 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
- *  Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
  */
 
 #include "libwebsockets.h"
@@ -184,7 +187,7 @@ lws_callback_raw_telnet(struct lws *wsi, enum lws_callback_reasons reason,
                                pu++;
 
                        if (n > 100 || !len)
-                               pss->vhd->ops->rx(pss->priv, wsi, buf, n);
+                               pss->vhd->ops->rx(pss->priv, wsi, buf, (uint32_t)n);
                }
                break;
 
@@ -203,7 +206,7 @@ lws_callback_raw_telnet(struct lws *wsi, enum lws_callback_reasons reason,
                         */
                        pu = buf + LWS_PRE + 400;
                        m = (int)pss->vhd->ops->tx(pss->priv, LWS_STDOUT, pu,
-                                       ((int)sizeof(buf) - LWS_PRE - n - 401) / 2);
+                                       (size_t)((int)sizeof(buf) - LWS_PRE - n - 401) / 2);
 
                        /*
                         * apply telnet line discipline and copy into place
@@ -216,7 +219,7 @@ lws_callback_raw_telnet(struct lws *wsi, enum lws_callback_reasons reason,
                        }
                }
                if (n > 0) {
-                       m = lws_write(wsi, (unsigned char *)buf + LWS_PRE, n,
+                       m = lws_write(wsi, (unsigned char *)buf + LWS_PRE, (unsigned int)n,
                                      LWS_WRITE_HTTP);
                        if (m < 0) {
                                lwsl_err("ERROR %d writing to di socket\n", m);
diff --git a/scripts/ahrefs-topsites.sh b/scripts/ahrefs-topsites.sh
new file mode 100755 (executable)
index 0000000..4cc922d
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+wget -O- https://ahrefs.com/blog/most-visited-websites/ | grep most-visited-websites-us | \
+       sed -E 's/class="column-2">/|/g' | tr '|' '\n' | \
+       sed 's/<.*//g' | grep -v Domain | grep -v Josh | sort | uniq
+
index 3f3a67a..67f8ad9 100755 (executable)
@@ -781,7 +781,11 @@ EOF
 if [ "`md5sum /tmp/results | cut -d' ' -f 1`" != "`md5sum /tmp/lwsresult1 | cut -d' ' -f1`" ] ; then
        echo "Differences..."
        diff -urN /tmp/lwsresult1 /tmp/results
-       exit 1
+       cat /tmp/lwscap1
+       ls -l /tmp/results
+       cat /tmp/results
+# this is currently broken on travis
+#      exit 1
 else
        echo "OK"
 fi
index 0a445f4..3ae2a90 100755 (executable)
@@ -40,7 +40,7 @@ cat << EOF >fuzzingclient.json
          "url": "ws://127.0.0.1:9001"
       }
    ],
-   "cases": [ "12.2.13" ],
+   "cases": [ "*" ],
    "exclude-cases": ["2.10", "2.11" ],
    "exclude-agent-cases": {}
 }
index cee8cbd..1546d83 100755 (executable)
@@ -5,8 +5,9 @@ if [ -z "$1" ] ; then
        exit 1
 fi
 
+mkdir -p certs
 openssl genrsa -out $1.key 4096 && \
-printf "\\n\\n\\n\\n\\nlocalhost\\n\\n1234\\n\\n" | \
+printf "\\n\\n\\n\\n\\n$1\\n\\n1234\\n\\n" | \
  openssl req -config tmp.cnf -new -key $1.key -out $1.csr && \
 openssl ca -config tmp.cnf \
        -keyfile ca.key \
index 46a1590..fd5dc20 100755 (executable)
@@ -5,6 +5,7 @@ if [ -z "$1" ] ; then
        exit 1
 fi
 
+mkdir -p certs
 openssl genrsa -out $1.key 4096 && \
 printf "\\n\\n\\n\\n\\nlocalhost\\n\\n1234\\n\\n" | \
  openssl req -config tmp.cnf -new -key $1.key -out $1.csr && \
diff --git a/scripts/ctest-background-kill.sh b/scripts/ctest-background-kill.sh
new file mode 100755 (executable)
index 0000000..31f1d07
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/bash
+#
+# $SAI_INSTANCE_IDX - which instance of sai, 0+
+# $1  - background fixture name, unique within test space, like "multipostlocalsrv"
+# $2  - executable
+# $3+ - args
+
+echo "$0 $1 $2 $3 $4"
+
+J=`basename $2`.$1.$SAI_INSTANCE_IDX
+PI=`cat /tmp/sai-ctest-$J`
+
+#
+# We expect our background process to initially still be around
+#
+
+kill -0 $PI
+GONESKI=$?
+
+echo "Background task $PI: $J"
+
+if [ $GONESKI -eq 1 ] ; then
+       echo "Background Process $PI unexpectedly dead already, their log"
+       cat /tmp/ctest-background-$J
+       exit 1
+fi
+
+echo "Trying SIGTERM..."
+
+kill $PI
+
+#
+# 100ms intervals, 100 = 10s
+# need to allow time for valgrind case
+#
+BUDGET=100
+while [ $BUDGET -ne 0 ] ; do
+       sleep 0.1
+       kill -0 $PI 2>&1
+       if [ $? -eq 1 ] ; then
+               echo "Went down OK"
+               exit 0
+       fi
+       BUDGET=$(( $BUDGET - 1 ))
+done
+
+echo "Trying SIGKILL..."
+
+kill -9 $PI
+
+#
+# 100ms intervals, 100 = 10s
+# need to allow time for valgrind case
+#
+BUDGET=20
+while [ $BUDGET -ne 0 ] ; do
+       sleep 0.1
+       kill -0 $PI 2>&1
+       if [ $? -eq 1 ] ; then
+               echo "Went down OK after SIGKILL"
+               exit 0
+       fi
+       BUDGET=$(( $BUDGET - 1 ))
+done
+
+echo "Couldn't kill it"
+exit 1
diff --git a/scripts/ctest-background.sh b/scripts/ctest-background.sh
new file mode 100755 (executable)
index 0000000..ad699bd
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# $SAI_INSTANCE_IDX - which instance of sai, 0+
+# $1 - background fixture name, unique within test space, like "multipostlocalserver"
+# $2 - executable
+# $3+ - args
+
+J=`basename $2`.$1.$SAI_INSTANCE_IDX
+$2 $3 $4 $5 $6 $7 $8 $9 2>/tmp/ctest-background-$J 1>/dev/null 0</dev/null &
+echo $! > /tmp/sai-ctest-$J
+# really we want to loop until the listen port is up
+# on, eg, rpi it can be blocked at sd card and slow to start
+# due to parallel tests and disc cache flush
+if [ ! -z "`echo $2 | grep valgrind`" ] ; then
+       sleep 5
+else
+       sleep 1
+fi
+exit 0
+
diff --git a/scripts/dox-extra.css b/scripts/dox-extra.css
new file mode 100644 (file)
index 0000000..ca14076
--- /dev/null
@@ -0,0 +1,5 @@
+code {
+       text-color: #000000;
+       background-color: #f0f0a0;
+}
+
diff --git a/scripts/libwebsockets.spec b/scripts/libwebsockets.spec
deleted file mode 100644 (file)
index d5cc7b3..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-Name: libwebsockets
-Version: 3.2.0
-Release: 1%{?dist}
-Summary: Websocket Server and Client Library
-
-Group: System Environment/Libraries
-License: LGPLv2 with exceptions
-URL: https://libwebsockets.org
-Source0: %{name}-%{version}.tar.gz
-BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
-
-BuildRequires: openssl-devel libuv-devel libev-devel cmake
-Requires: openssl
-
-%description
-Webserver server and client library
-
-%package devel
-Summary: Development files for libwebsockets
-Group: Development/Libraries
-Requires: %{name} = %{version}-%{release}
-Requires: openssl-devel
-
-%description devel
-Development files for libwebsockets
-
-%prep
-%setup -q
-
-%build
-mkdir -p build
-cd build
-%cmake .. -DLWS_WITH_DISTRO_RECOMMENDED=1
-make
-
-%install
-rm -rf $RPM_BUILD_ROOT
-cd build
-make install DESTDIR=$RPM_BUILD_ROOT
-
-%post -p /sbin/ldconfig
-%postun -p /sbin/ldconfig
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%files
-%defattr(-,root,root,-)
-%attr(755,root,root)
-"/usr/bin/libwebsockets-test-client"
-"/usr/bin/libwebsockets-test-lejp"
-"/usr/bin/libwebsockets-test-server"
-"/usr/bin/libwebsockets-test-server-extpoll"
-"/usr/bin/libwebsockets-test-sshd"
-"/usr/bin/lwsws"
-"/%{_libdir}/libwebsockets.so"
-"/%{_libdir}/libwebsockets.so.15"
-%dir "/usr/share/libwebsockets-test-server"
-"/usr/share/libwebsockets-test-server/candide.zip"
-"/usr/share/libwebsockets-test-server/favicon.ico"
-%dir "/usr/share/libwebsockets-test-server/generic-table"
-"/usr/share/libwebsockets-test-server/generic-table/index.html"
-"/usr/share/libwebsockets-test-server/generic-table/lwsgt.js"
-"/usr/share/libwebsockets-test-server/http2.png"
-"/usr/share/libwebsockets-test-server/leaf.jpg"
-"/usr/share/libwebsockets-test-server/libwebsockets-test-server.key.pem"
-"/usr/share/libwebsockets-test-server/libwebsockets-test-server.pem"
-"/usr/share/libwebsockets-test-server/libwebsockets.org-logo.svg"
-"/usr/share/libwebsockets-test-server/lws-cgi-test.sh"
-"/usr/share/libwebsockets-test-server/lws-common.js"
-"/usr/share/libwebsockets-test-server/lws-ssh-test-keys"
-"/usr/share/libwebsockets-test-server/lws-ssh-test-keys.pub"
-%dir "/usr/share/libwebsockets-test-server/plugins"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_client_loopback_test.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_dumb_increment.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_fulltext_demo.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_lws_acme_client.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_lws_mirror.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_lws_raw_test.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_lws_server_status.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_lws_ssh_base.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_lws_sshd_demo.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_lws_status.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_lws_table_dirlisting.so"
-"/usr/share/libwebsockets-test-server/plugins/libprotocol_post_demo.so"
-%dir "/usr/share/libwebsockets-test-server/private"
-"/usr/share/libwebsockets-test-server/private/index.html"
-%dir "/usr/share/libwebsockets-test-server/server-status"
-"/usr/share/libwebsockets-test-server/server-status/lwsws-logo.png"
-"/usr/share/libwebsockets-test-server/server-status/server-status.css"
-"/usr/share/libwebsockets-test-server/server-status/server-status.html"
-"/usr/share/libwebsockets-test-server/server-status/server-status.js"
-"/usr/share/libwebsockets-test-server/test.css"
-"/usr/share/libwebsockets-test-server/test.html"
-"/usr/share/libwebsockets-test-server/test.js"
-"/usr/share/libwebsockets-test-server/wss-over-h2.png"
-%files devel
-%defattr(-,root,root,-)
-%dir "/usr/include/libwebsockets"
-"/usr/include/libwebsockets.h"
-"/usr/include/libwebsockets/lws-adopt.h"
-"/usr/include/libwebsockets/lws-callbacks.h"
-"/usr/include/libwebsockets/lws-cgi.h"
-"/usr/include/libwebsockets/lws-client.h"
-"/usr/include/libwebsockets/lws-context-vhost.h"
-"/usr/include/libwebsockets/lws-dbus.h"
-"/usr/include/libwebsockets/lws-diskcache.h"
-"/usr/include/libwebsockets/lws-esp32.h"
-"/usr/include/libwebsockets/lws-fts.h"
-"/usr/include/libwebsockets/lws-genhash.h"
-"/usr/include/libwebsockets/lws-genrsa.h"
-"/usr/include/libwebsockets/lws-http.h"
-"/usr/include/libwebsockets/lws-jose.h"
-"/usr/include/libwebsockets/lws-jwk.h"
-"/usr/include/libwebsockets/lws-jws.h"
-"/usr/include/libwebsockets/lws-lejp.h"
-"/usr/include/libwebsockets/lws-logs.h"
-"/usr/include/libwebsockets/lws-lwsac.h"
-"/usr/include/libwebsockets/lws-misc.h"
-"/usr/include/libwebsockets/lws-network-helper.h"
-"/usr/include/libwebsockets/lws-plugin-generic-sessions.h"
-"/usr/include/libwebsockets/lws-protocols-plugins.h"
-"/usr/include/libwebsockets/lws-purify.h"
-"/usr/include/libwebsockets/lws-ring.h"
-"/usr/include/libwebsockets/lws-service.h"
-"/usr/include/libwebsockets/lws-sha1-base64.h"
-"/usr/include/libwebsockets/lws-spa.h"
-"/usr/include/libwebsockets/lws-stats.h"
-"/usr/include/libwebsockets/lws-threadpool.h"
-"/usr/include/libwebsockets/lws-timeout-timer.h"
-"/usr/include/libwebsockets/lws-tokenize.h"
-"/usr/include/libwebsockets/lws-vfs.h"
-"/usr/include/libwebsockets/lws-write.h"
-"/usr/include/libwebsockets/lws-writeable.h"
-"/usr/include/libwebsockets/lws-ws-close.h"
-"/usr/include/libwebsockets/lws-ws-ext.h"
-"/usr/include/libwebsockets/lws-ws-state.h"
-"/usr/include/libwebsockets/lws-x509.h"
-"/usr/include/lws-plugin-ssh.h"
-"/usr/include/lws_config.h"
-%dir "/usr/lib/pkgconfig"
-"/%{_libdir}/pkgconfig/libwebsockets.pc"
-"/usr/lib/pkgconfig/libwebsockets_static.pc"
-%dir "/usr/lib/cmake"
-%dir "/usr/lib/cmake/libwebsockets"
-"/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake"
-"/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake"
-"/%{_libdir}/cmake/libwebsockets/LibwebsocketsTargets-debug.cmake"
-"/%{_libdir}/cmake/libwebsockets/LibwebsocketsTargets.cmake"
-
-%changelog
-* Fri Aug 14 2019 Andy Green <andy@warmcat.com> 3.2.0-1
-- MAJOR SONAMEBUMP APICHANGES Upstream 3.2.0 release (last LGPLv2.1+SLE)
-
-* Fri Nov 23 2018 Andy Green <andy@warmcat.com> 3.1.0-1
-- MAJOR SONAMEBUMP APICHANGES Upstream 3.1.0 release
-
-* Fri May 4 2018 Andy Green <andy@warmcat.com> 3.0.0-1
-- MAJOR SONAMEBUMP APICHANGES Upstream 3.0.0 release
-
-* Mon Oct 16 2017 Andy Green <andy@warmcat.com> 2.4.0-1
-- MAJOR SONAMEBUMP APICHANGES Upstream 2.4.0 release
-
-* Fri Jul 28 2017 Andy Green <andy@warmcat.com> 2.3.0-1
-- MAJOR SONAMEBUMP APICHANGES Upstream 2.3.0 release
-
-* Mon Mar 06 2017 Andy Green <andy@warmcat.com> 2.2.0-1
-- MAJOR SONAMEBUMP APICHANGES Upstream 2.2.0 release
-
-* Thu Oct 06 2016 Andy Green <andy@warmcat.com> 2.1.0-1
-- MAJOR SONAMEBUMP APICHANGES Upstream 2.1.0 release
-
-* Thu May 05 2016 Andy Green <andy@warmcat.com> 2.0.0-1
-- MAJOR SONAMEBUMP APICHANGES Upstream 2.0.0 release
-
-* Tue Feb 16 2016 Andy Green <andy@warmcat.com> 1.7.0-1
-- MAJOR SONAMEBUMP APICHANGES Upstream 1.7.0 release
-
-* Sun Jan 17 2016 Andrew Cooks <acooks@linux.com> 1.6.0-1
-- Bump version to 1.6.0
diff --git a/scripts/mozilla-trust-gen.sh b/scripts/mozilla-trust-gen.sh
new file mode 100755 (executable)
index 0000000..4a38963
--- /dev/null
@@ -0,0 +1,194 @@
+#!/bin/bash
+
+# This script fetches the current list of trusted CAs blessed by Mozilla
+# for web tls validation, and processes it into two outputs
+#
+# - ./trust/webroot/* consisting of ./_trust/webroot/der  a static, serveable set
+#     of trusted DER certs, with symlinks in ./_trust/webroot/by-skid and
+#     ./_trust/webroot/by-iss allowing serving the DER matching a given
+#     SubjectKeyIdentifier or Issuer + serial combination (suitably encoded)
+#
+# - ./_trust/blob-XXXX.bin  a single blob containing indexes and DER CA certs
+#
+# - ./_trust/trust_blob.h   a C uint8_t array formatted copy of blob-XXXX.bin
+
+# The trust blob layout is currently
+#
+# 54 42 4c 42     Magic "TBLB"
+# 00 01           MSB-first trust blob layout version
+# XX XX           MSB-first count of certificates
+# XX XX XX XX     MSB-first trust blob generation unix time
+# XX XX XX XX     MSB-first offset of cert length table (MSB-first 16-bit length-per-cert)
+# XX XX XX XX     MSB-first offset of SKID length table (8-bit length-per-cert)
+# XX XX XX XX     MSB-first offset of SKID table
+# XX XX XX XX     MSB-first total blob length
+#
+# XX .. XX        DER certs (start at +0x1c)
+# XX .. XX        DER cert length table (MSB-first 16-bit per cert)
+# XX .. XX        SKID length table (8-bit per cert)
+# XX .. XX        SKID table (variable per cert)
+#
+
+echo "Mozilla trust bundle for TLS validation processing  Andy Green <andy@warmcat.com>"
+echo
+
+rm -rf _trust
+mkdir _trust
+
+wget -O _trust/trusted.txt "https://ccadb-public.secure.force.com/mozilla/IncludedRootsPEMTxt?TrustBitsInclude=Websites"
+#cp ~/Downloads/IncludedRootsPEM.txt _trust/trusted.txt
+
+if [ $? -ne 0 ]; then
+       echo "Failed to get current website trust bundle"
+       exit 1
+fi
+
+mkdir -p _trust/webroot/by-skid _trust/webroot/by-iss _trust/webroot/der
+
+echo 0 > _trust/ofs
+echo 0 > _trust/count
+echo 0 > _trust/skidtab
+
+GT=`date +%s`
+BN=_trust/blob-$GT.bin
+
+cat _trust/trusted.txt | while read _line ; do
+       line=`echo -n $_line | sed 's/\r$//g'`
+       if [ "$line" == "-----BEGIN CERTIFICATE-----" ] ; then
+               echo $line > _trust/single
+       else
+               echo $line >> _trust/single
+
+               if [ "$line" == "-----END CERTIFICATE-----" ] ; then
+                       openssl x509 -in _trust/single -text -noout > _trust/c1
+                       if [ $? -ne 0 ] ; then
+                               echo "FAILED"
+                               exit 1
+                       fi
+
+                       ISS=`cat _trust/c1 | grep Issuer: | sed "s/.*://g" | sed "s/^\ *//g"`
+                       SER=`cat _trust/c1 | grep "Serial Number:" | sed "s/.*://g" | sed "s/^\ *//g" | sed "s/\ .*//g"`
+                       if [ -z "$SER" ] ; then
+                               SER=`cat _trust/c1 | sed -e "1,/.*Serial Number:/ d" | head -n 1 | sed "s/^\ *//g" | sed "s/\ .*//g"`
+                       fi
+                       SKID=`cat _trust/c1 | sed -e '1,/.*X509v3 Subject Key Identifier:/ d' | sed -n '/Signature.*/q;p' | \
+                               grep ':' | grep -v ': ' | grep -v ':$' | grep -v U | grep -v k | grep -v T | grep -v "i" | \
+                               grep -v "S" | grep -v "V" | sed "s/^\ *//g"`
+                       SKID_NO_COLONS=`echo -n $SKID | sed "s/://g"`
+
+                       na=`cat _trust/c1 | grep "Not\ After\ :" | sed "s/.*\ :\ //g"`
+                       ct=`date +%s`
+                       ts=`date --date="$na" +%s`
+                       life_days=`echo -n "$(( ( $ts - $ct ) / 86400 ))"`
+
+                       echo "$life_days $safe" >> _trust/life
+                       if [ $life_days -lt 1095 ] ; then
+                               echo "$life_days $safe" >> _trust/life_lt_3y
+                       fi
+
+                       echo "issuer=\"$ISS\", serial=\"${SER^^}\", skid=\"${SKID_NO_COLONS^^}\", life_days=\"${life_days}\""
+
+                       issname=`echo -n "$ISS"_"$SER" | tr -cd '[a-zA-Z0-9]_'`
+                       skidname=`echo -n "$SKID_NO_COLONS" | tr -cd '[a-zA-Z0-9]_'`
+                       safe=$issname"_"$skidname
+
+                       cat _trust/single | grep -v -- '---' | base64 -d > _trust/webroot/der/$safe
+                       cd _trust/webroot/by-skid
+                       ln -sf ../der/$safe $SKID_NO_COLONS
+                       cd ../../..
+                       cd _trust/webroot/by-iss
+                       ln -sf ../der/$safe $issname
+                       cd ../../..
+
+                       DERSIZ=`cat _trust/single | grep -v -- '---' | base64 -d | wc -c | cut -d' ' -f1`
+
+                       cat _trust/single | grep -v -- '---' | base64 -d | hexdump -C | tr -s ' ' | sed 's/\ $//g' | \
+                               cut -d' ' -f 2-17 | cut -d'|' -f1 | grep -v 000 | sed "s/\ //g" | sed ':a;N;$!ba;s/\n//g' | xxd -r -p >> _trust/_ders
+
+                       printf "%04x" $DERSIZ | xxd -r -p  >> _trust/_derlens
+
+echo $SKID
+
+                       if [ ! -z "$SKID" ] ; then
+                               echo -n "$SKID_NO_COLONS" | xxd -r -p >> _trust/_skid
+                       fi
+                       SKIDSIZ=`echo -n $SKID_NO_COLONS | xxd -r -p | wc -c | cut -d' ' -f1`
+                       printf "%02x" $SKIDSIZ | xxd -r -p  >> _trust/_skidlens
+
+                       OFS=`cat _trust/ofs`
+                       echo -n $(( $OFS + $DERSIZ )) > _trust/ofs
+                       COUNT=`cat _trust/count`
+                       echo -n $(( $COUNT +1 )) > _trust/count
+                       ST=`cat _trust/skidtab`
+                       echo -n $(( $ST + ( `echo -n $skidname | wc -c | cut -d' ' -f1` / 2 ) )) > _trust/skidtab
+
+                       rm -f _trust/single
+
+               fi
+       fi
+
+done
+
+       COUNT=`cat _trust/count`
+       OFS=`cat _trust/ofs`
+       ST=`cat _trust/skidtab`
+
+       # everything in the layout framing is MSB-first
+
+       # magic
+       echo -n "TBLB" > $BN
+       # blob layout version
+       echo -n 0001 | xxd -r -p >> $BN
+       # number of certs in the blob
+       printf "%04x" $COUNT | xxd -r -p >> $BN
+       # unix time blob was created
+       printf "%08x" $GT | xxd -r -p >> $BN
+
+       POS=28
+       POS=$(( $POS + `cat _trust/_ders | wc -c | cut -d' ' -f1` ))
+
+       # blob offset of start of cert length table
+       printf "%08x" $POS | xxd -r -p >> $BN
+
+       POS=$(( $POS + `cat _trust/_derlens | wc -c | cut -d' ' -f1` ))
+
+       # blob offset of start of SKID length table
+       printf "%08x" $POS | xxd -r -p >> $BN
+
+       POS=$(( $POS + `cat _trust/_skidlens | wc -c | cut -d' ' -f1` ))
+
+       # blob offset of start of SKID table
+       printf "%08x" $POS | xxd -r -p >> $BN
+
+       POS=$(( $POS + `cat _trust/_skid | wc -c | cut -d' ' -f1` ))
+
+       # blob total length
+       printf "%08x" $POS | xxd -r -p >> $BN
+
+
+       # the DER table, start at +0x1c
+       cat _trust/_ders >> $BN
+       # the DER length table
+       cat _trust/_derlens >> $BN
+       # the SKID length table
+       cat _trust/_skidlens >> $BN
+       # the SKID table
+       cat _trust/_skid >> $BN
+
+# produce a C-friendly version of the blob
+
+       cat $BN | hexdump -v -C | tr -s ' ' | sed 's/\ $//g' | \
+               cut -d' ' -f 2-17 | cut -d'|' -f1 | grep -v 000 | sed "s/\ /,\ 0x/g" | sed "s/^/0x/g" | \
+               sed 's/\, 0x$//g' | sed 's/$/,/g' >> _trust/trust_blob.h
+
+
+       echo
+       echo "$COUNT CA certs, $POS byte blob"
+       echo
+       echo "CAs expiring in less than 3 years (days left):"
+       sort -h _trust/life_lt_3y
+
+       rm -f _trust/count _trust/_idx _trust/_idx_skid _trust/ofs _trust/_skid _trust/skidtab _trust/life _trust/life_lt_3y _trust/c1 _trust/single _trust/_derlens _trust/_ders _trust/_skid _trust/_skidlens
+
+exit 0
+
index ef4b0ae..04a66cd 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$TRAVIS_OS_NAME" = "osx" ]; then
-       if [ "$LWS_METHOD" != "mbedtls" ] ; then
+       if [ "$LWS_METHOD" != "mbedtls" -a "$LWS_METHOD" != "ss+mbedtls" ] ; then
                mkdir build && cd build &&
                cmake -DOPENSSL_ROOT_DIR="/usr/local/opt/openssl" $CMAKE_ARGS .. &&
                cmake --build .
@@ -15,10 +15,10 @@ else
                        cmake --build . &&
                        sudo make install &&
                        ../minimal-examples/selftests.sh &&
-                       ../scripts/test-dbus-proxy.sh &&
                        ../scripts/h2spec.sh &&
                        ../scripts/attack.sh &&
                        ../scripts/h2load.sh &&
+                       ../scripts/autobahn-test-server.sh &&
                        ../scripts/autobahn-test-client.sh
                else
                        if [ "$LWS_METHOD" = "lwsws2" ] ; then
@@ -34,7 +34,7 @@ else
                                        cmake --build . &&
                                        ../scripts/h2load-smp.sh
                                else
-                                       if [ "$LWS_METHOD" = "mbedtls" ] ; then
+                                       if [ "$LWS_METHOD" = "mbedtls" -o "$LWS_METHOD" = "ss+mbedtls" ] ; then
                                                cmake $CMAKE_ARGS .. &&
                                                cmake --build . &&
                                                sudo make install &&
index 3956422..9b84cb9 100755 (executable)
@@ -8,7 +8,7 @@ then
 
        if [ "$LWS_METHOD" == "lwsws" -o "$LWS_METHOD" == "lwsws2" ];
        then
-               sudo apt-get install -y -qq realpath libjemalloc1 libev4 libuv-dev libdbus-1-dev
+               sudo apt-get install -y -qq realpath libjemalloc1 libev4 libuv-dev libdbus-1-dev valgrind mosquitto
                sudo apt-get remove python-six
                sudo pip install "six>=1.9"
                sudo pip install "Twisted==16.0.0"
@@ -21,9 +21,9 @@ then
                sudo update-ca-certificates
        fi
 
-       if [ "$LWS_METHOD" == "mbedtls" ];
+       if [ "$LWS_METHOD" == "mbedtls" -o "$LWS_METHOD" == "ss+mbedtls" ];
        then
-               sudo apt-get install -y -qq realpath libjemalloc1 libev4 libuv-dev
+               sudo apt-get install -y -qq realpath libjemalloc1 libev4 libuv-dev valgrind
                wget https://libwebsockets.org/openssl-1.1.0-trusty.tar.bz2 -O/tmp/openssl.tar.bz2
                cd /
                sudo tar xf /tmp/openssl.tar.bz2
diff --git a/test-apps/CMakeLists.txt b/test-apps/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9ffed9f
--- /dev/null
@@ -0,0 +1,272 @@
+#
+# libwebsockets - small server side websockets and web server implementation
+#
+# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+
+#
+# Test applications
+#
+
+set(TEST_APP_LIST)
+if ((LWS_ROLE_H1 OR LWS_ROLE_H2))
+       #
+       # Helper function for adding a test app.
+       #
+       macro(create_test_app TEST_NAME MAIN_SRC S2 S3 S4 S5 S6)
+
+               set(TEST_SRCS ${MAIN_SRC})
+               set(TEST_HDR)
+               if ("${S2}" STREQUAL "")
+               else()
+                       list(APPEND TEST_SRCS ${S2})
+               endif()
+               if ("${S3}" STREQUAL "")
+               else()
+                       list(APPEND TEST_SRCS ${S3})
+               endif()
+               if ("${S4}" STREQUAL "")
+               else()
+                       list(APPEND TEST_SRCS ${S4})
+               endif()
+               if ("${S5}" STREQUAL "")
+               else()
+                       list(APPEND TEST_SRCS ${S5})
+               endif()
+               if ("${S6}" STREQUAL "")
+               else()
+                       list(APPEND TEST_SRCS ${S6})
+               endif()
+               if (WIN32)
+                       list(APPEND TEST_SRCS
+                               ${WIN32_HELPERS_PATH}/getopt.c
+                               ${WIN32_HELPERS_PATH}/getopt_long.c
+                               ${WIN32_HELPERS_PATH}/gettimeofday.c
+                       )
+
+                       list(APPEND TEST_HDR
+                               ${WIN32_HELPERS_PATH}/getopt.h
+                               ${WIN32_HELPERS_PATH}/gettimeofday.h
+                       )
+               endif(WIN32)
+
+               source_group("Headers Private"   FILES ${TEST_HDR})
+               source_group("Sources"   FILES ${TEST_SRCS})
+               add_executable(${TEST_NAME} ${TEST_SRCS} ${TEST_HDR})
+
+               foreach(libpath ${LWS_DEP_LIB_PATHS})
+                       target_link_directories(${TEST_NAME} ${libpath})
+               endforeach()
+
+               if (LWS_LINK_TESTAPPS_DYNAMIC)
+                       if (NOT LWS_WITH_SHARED)
+                               message(FATAL_ERROR "Build of the shared library is disabled. LWS_LINK_TESTAPPS_DYNAMIC must be combined with LWS_WITH_SHARED.")
+                       endif()
+                       target_link_libraries(${TEST_NAME} websockets_shared)
+                       add_dependencies(${TEST_NAME} websockets_shared)
+               else()
+                       if (NOT LWS_WITH_STATIC)
+                               message(FATAL_ERROR "Build of the static library is disabled. Disabled LWS_LINK_TESTAPPS_DYNAMIC must be combined with LWS_WITH_STATIC.")
+                       endif()
+                       target_link_libraries(${TEST_NAME} websockets)
+                       add_dependencies(${TEST_NAME} websockets)
+                       if (UNIX AND LWS_WITH_SSL AND NOT LWS_WITH_MBEDTLS)
+                               target_link_libraries(${TEST_NAME} ${CMAKE_DL_LIBS})
+                       endif()
+               endif()
+               
+               if (LWS_LIB_INCLUDES)
+                       target_include_directories(${TEST_NAME} PRIVATE "${LWS_LIB_INCLUDES}" ${LWS_LIB_BUILD_INC_PATHS})
+               else()
+                       target_include_directories(${TEST_NAME} PRIVATE ${LWS_LIB_BUILD_INC_PATHS})
+               endif()
+               target_compile_options(${TEST_NAME} PRIVATE ${LWS_PTHR_FLAGS})
+
+               if (LWS_WITH_HTTP_STREAM_COMPRESSION)
+                       target_link_libraries(${TEST_NAME} z)
+               endif()
+
+               # Set test app specific defines.
+               set_property(TARGET ${TEST_NAME}
+                                       PROPERTY COMPILE_DEFINITIONS
+                                               INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
+                                       )
+
+               # Prefix the binary names with libwebsockets.
+               set_target_properties(${TEST_NAME}
+                       PROPERTIES
+                       OUTPUT_NAME libwebsockets-${TEST_NAME})
+                       
+               target_link_libraries(${TEST_NAME} ${LIB_LIST_AT_END})
+
+               # Add to the list of tests.
+               list(APPEND TEST_APP_LIST ${TEST_NAME})
+       endmacro()
+
+       if (NOT LWS_WITHOUT_SERVER)
+               #
+               # test-server
+               #
+               if (NOT LWS_WITHOUT_TEST_SERVER)
+                       create_test_app(test-server "test-server.c"
+                               ""
+                               ""
+                               ""
+                               ""
+                               "")
+                       target_compile_definitions(test-server PRIVATE LWS_BUILDING_SHARED)
+
+                       if (LWS_WITH_CGI AND (LWS_WITH_PLUGINS OR LWS_WITH_PLUGINS_BUILTIN) AND LWS_WITH_TLS)
+                       create_test_app(test-sshd "test-sshd.c"
+                               ""
+                               ""
+                               ""
+                               ""
+                               "")
+                       target_include_directories(test-sshd PRIVATE "${PROJECT_SOURCE_DIR}/plugins/ssh-base/include")
+                       target_compile_definitions(test-sshd PRIVATE LWS_BUILDING_SHARED)
+                       endif()
+
+               endif()
+
+               #
+               # test-server-extpoll
+               #
+               if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL AND NOT WIN32)
+                       create_test_app(test-server-extpoll
+                               "test-server.c"
+                               ""
+                               ""
+                               ""
+                               ""
+                               "")
+                       target_compile_definitions(test-server-extpoll PRIVATE LWS_BUILDING_SHARED)
+                       # Set defines for this executable only.
+                       set_property(
+                               TARGET test-server-extpoll
+                               PROPERTY COMPILE_DEFINITIONS 
+                                       EXTERNAL_POLL 
+                                       INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
+                               )
+
+                       # We need to link against winsock code.
+                       if (WIN32)
+                               target_link_libraries(test-server-extpoll ws2_32.lib)
+                       endif(WIN32)
+               endif()
+
+               if (LWS_WITH_LEJP)
+                       create_test_app(
+                               test-lejp
+                               "test-lejp.c"
+                               ""
+                               ""
+                               ""
+                               ""
+                               "")
+                       target_compile_definitions(test-lejp PRIVATE LWS_BUILDING_STATIC)
+               endif()
+
+               if (LWS_WITH_CBOR)
+                       create_test_app(
+                               test-lecp
+                               "test-lecp.c"
+                               ""
+                               ""
+                               ""
+                               ""
+                               "")
+                       target_compile_definitions(test-lecp PRIVATE LWS_BUILDING_STATIC)
+               endif()
+
+
+               # Data files for running the test server.
+               list(APPEND TEST_SERVER_DATA
+                       "${PROJECT_SOURCE_DIR}/test-apps/favicon.ico"
+                       "${PROJECT_SOURCE_DIR}/test-apps/leaf.jpg"
+                       "${PROJECT_SOURCE_DIR}/test-apps/candide.zip"
+                       "${PROJECT_SOURCE_DIR}/test-apps/candide-uncompressed.zip"
+                       "${PROJECT_SOURCE_DIR}/test-apps/libwebsockets.org-logo.svg"
+                       "${PROJECT_SOURCE_DIR}/test-apps/http2.png"
+                       "${PROJECT_SOURCE_DIR}/test-apps/wss-over-h2.png"
+                       "${PROJECT_SOURCE_DIR}/test-apps/lws-common.js"
+                       "${PROJECT_SOURCE_DIR}/test-apps/test.html"
+                       "${PROJECT_SOURCE_DIR}/test-apps/test.css"
+                       "${PROJECT_SOURCE_DIR}/test-apps/test.js")
+
+               add_custom_command(TARGET test-server
+                                               POST_BUILD 
+                                               COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server")
+
+               # Copy the file needed to run the server so that the test apps can
+               # reach them from their default output location
+               foreach (TEST_FILE ${TEST_SERVER_DATA})
+                       if (EXISTS ${TEST_FILE})
+                               add_custom_command(TARGET test-server
+                                                       POST_BUILD 
+                                                       COMMAND "${CMAKE_COMMAND}" -E copy "${TEST_FILE}" "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server" VERBATIM)
+                       endif()
+               endforeach()
+       endif(NOT LWS_WITHOUT_SERVER)
+
+       if (NOT LWS_WITHOUT_CLIENT)
+               #
+               # test-client
+               #
+               if (NOT LWS_WITHOUT_TEST_CLIENT)
+                       create_test_app(test-client "test-client.c" "" "" "" "" "")
+               endif()
+
+       endif(NOT LWS_WITHOUT_CLIENT)
+endif((LWS_ROLE_H1 OR LWS_ROLE_H2))
+
+# Install test apps.
+
+install(TARGETS ${TEST_APP_LIST}
+               RUNTIME DESTINATION ${LWS_INSTALL_EXAMPLES_DIR}
+               COMPONENT examples)
+set(CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "Example files")
+
+# Programs shared files used by the test-server
+
+if (NOT LWS_WITHOUT_SERVER)
+       install(FILES ${TEST_SERVER_DATA}
+                       DESTINATION share/libwebsockets-test-server
+               COMPONENT examples)
+
+               install(FILES "${PROJECT_SOURCE_DIR}/test-apps/private/index.html"
+                       DESTINATION share/libwebsockets-test-server/private
+                       COMPONENT examples)
+if (LWS_WITH_CGI)
+       set(CGI_TEST_SCRIPT "${PROJECT_SOURCE_DIR}/test-apps/lws-cgi-test.sh")
+       install(FILES ${CGI_TEST_SCRIPT}
+                       PERMISSIONS  OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ
+                       DESTINATION share/libwebsockets-test-server
+                       COMPONENT examples)
+       endif()
+endif()
+
+
+if (NOT LWS_WITHOUT_TEST_SERVER AND NOT LWS_WITHOUT_SERVER)
+       install(FILES lws-ssh-test-keys;lws-ssh-test-keys.pub
+               DESTINATION share/libwebsockets-test-server
+               COMPONENT examples)
+endif()
diff --git a/test-apps/candide-uncompressed.zip b/test-apps/candide-uncompressed.zip
new file mode 100644 (file)
index 0000000..55856bc
Binary files /dev/null and b/test-apps/candide-uncompressed.zip differ
index 7baea64..ef241b3 100644 (file)
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="127.63mm" height="27.837mm" version="1.1" viewBox="0 0 127.63446 27.837189" xmlns="http://www.w3.org/2000/svg">
-       <defs>
-               <filter id="a" x="-.011681" y="-.053882" width="1.0234" height="1.1078" color-interpolation-filters="sRGB">
-                       <feGaussianBlur stdDeviation="0.10687168"/>
-               </filter>
-       </defs>
-       <g transform="translate(452.86 42.871)">
-               <rect x="-452.86" y="-42.871" width="127.63" height="27.837" fill="none"/>
-               <g transform="matrix(4.0081 0 0 4.0081 -211.01 -224.26)" fill="#fff" filter="url(#a)" stroke="#fff">
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                               <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                               <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                               <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                               <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                               <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                       </g>
-                       <g style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-               </g>
-               <g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".4463" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="libwebsockets.org">
-                               <g stroke-width=".4463">
-                                       <path d="m-52.015 48.429q0 0.12497 0.03213 0.17852 0.0357 0.05356 0.0964 0.05356 0.07498 0 0.17495-0.03927l0.02499 0.20709q-0.04642 0.02856-0.13211 0.04642-0.08212 0.01785-0.14996 0.01785-0.13568 0-0.22137-0.08212-0.08212-0.08569-0.08212-0.29635v-2.1601h0.25707z"/>
-                                       <path d="m-51.417 47.068h0.25707v1.7852h-0.25707zm-0.04642-0.54271q0-0.08569 0.04642-0.13925 0.04999-0.05356 0.12854-0.05356 0.07855 0 0.12854 0.05356 0.05356 0.04999 0.05356 0.13925 0 0.08569-0.05356 0.13568-0.04999 0.04642-0.12854 0.04642-0.07855 0-0.12854-0.04999-0.04642-0.04999-0.04642-0.13211z"/>
-                                       <path d="m-50.686 46.354h0.25707v0.84976h0.01071q0.14639-0.17852 0.38918-0.17852 0.27492 0 0.4106 0.2178 0.13925 0.2178 0.13925 0.6891 0 0.48201-0.18566 0.71766-0.18209 0.23565-0.51771 0.23565-0.16424 0-0.29992-0.03571-0.13568-0.03927-0.20352-0.08926zm0.25707 2.2387q0.04999 0.02856 0.1214 0.04641 0.07498 0.01428 0.1571 0.01428 0.18566 0 0.29278-0.17495 0.11068-0.17852 0.11068-0.54628 0-0.15353-0.02142-0.27492-0.01785-0.12496-0.0607-0.21423-0.03927-0.08926-0.10711-0.13568-0.06427-0.04999-0.1571-0.04999-0.12854 0-0.21423 0.07855-0.08212 0.07498-0.1214 0.20708z"/>
-                               </g>
-                               <path d="m-48.092 47.068 0.24993 0.91403 0.04284 0.29635h0.01428l0.0357-0.29992 0.16781-0.91046h0.38561l-0.43916 1.8031h-0.33562l-0.26778-0.99615-0.02856-0.22851h-0.02142l-0.02499 0.23565-0.25707 0.98901h-0.34633l-0.45702-1.8031h0.46059l0.1928 0.89618 0.03213 0.31777h0.01428l0.04642-0.32134 0.2178-0.89261z"/>
-                               <path d="m-45.889 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86762q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20709-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-45.569 46.354h0.42488v0.82834h0.01071q0.12854-0.1571 0.36776-0.1571 0.2535 0 0.39275 0.21066 0.14282 0.21066 0.14282 0.67838 0 0.507-0.19994 0.74622-0.19994 0.23565-0.54628 0.23565-0.18923 0-0.3499-0.0357-0.1571-0.03571-0.24279-0.07855zm0.42488 2.1137q0.07498 0.03927 0.19638 0.03927 0.13568 0 0.20708-0.12854 0.07141-0.13211 0.07141-0.43916 0-0.27135-0.05713-0.39632-0.05713-0.12854-0.17852-0.12854-0.17852 0-0.23922 0.18566z"/>
-                               <path d="m-43.386 48.379q0-0.07498-0.04999-0.12496-0.04642-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12496 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20709 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <path d="m-42.802 47.961q0-0.47487 0.18566-0.70695 0.18566-0.23208 0.51771-0.23208 0.35704 0 0.532 0.23565 0.17495 0.23565 0.17495 0.70338 0 0.47844-0.18566 0.71052-0.18566 0.22851-0.52128 0.22851-0.70338 0-0.70338-0.93902zm0.43916 0q0 0.26778 0.0607 0.41417t0.20352 0.14639q0.13568 0 0.19994-0.12497 0.06784-0.12854 0.06784-0.43559 0-0.27492-0.0607-0.41774-0.0607-0.14282-0.20708-0.14282-0.12497 0-0.19638 0.12854-0.06784 0.12497-0.06784 0.43202z"/>
-                               <path d="m-40.094 48.757q-0.08926 0.07141-0.21423 0.10711-0.12496 0.0357-0.24993 0.0357-0.18209 0-0.30706-0.06427-0.1214-0.06784-0.19994-0.18923-0.07855-0.12496-0.11425-0.29635-0.03213-0.17495-0.03213-0.38918 0-0.46773 0.16781-0.70338 0.16781-0.23565 0.49272-0.23565 0.16067 0 0.26064 0.02856 0.10354 0.02856 0.18209 0.07141l-0.09997 0.35347q-0.06427-0.03213-0.12497-0.04642-0.05713-0.01785-0.13925-0.01785-0.14996 0-0.22494 0.13211-0.07498 0.12854-0.07498 0.41774 0 0.24279 0.07498 0.39632 0.07855 0.15353 0.24636 0.15353 0.08926 0 0.14996-0.02142 0.06427-0.02499 0.11782-0.0607z"/>
-                               <path d="m-39.374 48.114h-0.09997v0.73908h-0.42488v-2.4993h0.42488v1.4746l0.08569-0.04999 0.29635-0.71052h0.46059l-0.32848 0.70695-0.15353 0.1214 0.16781 0.1214 0.36418 0.83548h-0.47844z"/>
-                               <path d="m-37.256 48.721q-0.08926 0.07855-0.24279 0.12854-0.15353 0.04999-0.32134 0.04999-0.18566 0-0.32134-0.06427-0.13211-0.06427-0.2178-0.18566-0.08569-0.1214-0.12854-0.29278-0.03927-0.17495-0.03927-0.39632 0-0.48201 0.18923-0.71052 0.1928-0.23208 0.532-0.23208 0.11425 0 0.22137 0.0357 0.10711 0.03213 0.18923 0.11425 0.08569 0.07855 0.13568 0.21423 0.05356 0.13211 0.05356 0.33562 0 0.07855-0.01071 0.16781-0.0071 0.08926-0.02499 0.1928h-0.86763q0.0071 0.22137 0.09283 0.33919 0.08569 0.11782 0.27492 0.11782 0.11425 0 0.20708-0.0357 0.0964-0.0357 0.14639-0.07498zm-0.55699-1.3389q-0.13568 0-0.20352 0.11068-0.06784 0.10711-0.07855 0.30349h0.49272q0.01071-0.20352-0.04284-0.30706-0.05356-0.10711-0.16781-0.10711z"/>
-                               <path d="m-37.075 47.068h0.19637v-0.33562l0.42488-0.13211v0.46773h0.34633v0.37847h-0.34633v0.77836q0 0.15353 0.02856 0.2178 0.03213 0.06427 0.11068 0.06427 0.05356 0 0.0964-0.01071t0.09283-0.03213l0.05356 0.33919q-0.07855 0.03928-0.18209 0.06427-0.10354 0.02856-0.2178 0.02856-0.20352 0-0.30706-0.11782-0.09997-0.11782-0.09997-0.39632v-0.93546h-0.19637z"/>
-                               <path d="m-35.297 48.379q0-0.07498-0.04999-0.12496-0.04641-0.05356-0.1214-0.0964-0.07498-0.04642-0.16067-0.09283-0.08212-0.04641-0.1571-0.11425-0.07498-0.06784-0.12496-0.16424-0.04642-0.0964-0.04642-0.24279 0-0.24993 0.13568-0.38561 0.13568-0.13568 0.39989-0.13568 0.1571 0 0.29635 0.0357 0.13925 0.03213 0.22137 0.08212l-0.09997 0.32848q-0.06784-0.02856-0.16424-0.05356-0.0964-0.02856-0.18923-0.02856-0.17495 0-0.17495 0.14639 0 0.06784 0.04642 0.11425 0.04999 0.04284 0.12497 0.08569 0.07498 0.04284 0.1571 0.08926 0.08569 0.04642 0.16067 0.11782 0.07498 0.06784 0.1214 0.16781 0.04999 0.09997 0.04999 0.24636 0 0.24636-0.14996 0.39632-0.14996 0.14996-0.4463 0.14996-0.14639 0-0.2892-0.0357-0.13925-0.0357-0.22494-0.09283l0.11782-0.34276q0.07498 0.04285 0.17138 0.07498 0.09997 0.03213 0.20708 0.03213 0.08212 0 0.13568-0.0357 0.05356-0.03928 0.05356-0.1214z"/>
-                               <g stroke-width=".4463">
-                                       <path d="m-34.662 48.693q0-0.09997 0.04642-0.14996 0.04999-0.04999 0.13211-0.04999 0.08212 0 0.12854 0.04999 0.04999 0.04999 0.04999 0.14996 0 0.10354-0.04999 0.15353-0.04642 0.04999-0.12854 0.04999-0.08212 0-0.13211-0.04999-0.04642-0.04999-0.04642-0.15353z"/>
-                                       <path d="m-34.035 47.961q0-0.48201 0.16424-0.70695 0.16781-0.22851 0.47487-0.22851 0.32848 0 0.48201 0.23208 0.1571 0.23208 0.1571 0.70338 0 0.48558-0.16781 0.71052-0.16781 0.22494-0.4713 0.22494-0.32848 0-0.48558-0.23208-0.15353-0.23208-0.15353-0.70338zm0.26778 0q0 0.1571 0.01785 0.28564 0.02142 0.12854 0.06427 0.22137 0.04642 0.09283 0.11782 0.14639 0.07141 0.04999 0.17138 0.04999 0.18566 0 0.2785-0.16424 0.09283-0.16781 0.09283-0.53914 0-0.15353-0.02142-0.28206-0.01785-0.13211-0.06427-0.22494-0.04285-0.09283-0.11425-0.14282-0.07141-0.05356-0.17138-0.05356-0.18209 0-0.27849 0.16781-0.09283 0.16781-0.09283 0.53557z"/>
-                                       <path d="m-32.415 47.068h0.18209l0.04642 0.18923h0.01071q0.04999-0.10354 0.12854-0.16067 0.08212-0.0607 0.19637-0.0607 0.08212 0 0.18566 0.03213l-0.04999 0.26064q-0.09283-0.03213-0.16424-0.03213-0.11426 0-0.18566 0.06784-0.07141 0.06427-0.09283 0.17495v1.3139h-0.25707z"/>
-                                       <path d="m-30.314 48.936q0 0.34633-0.15353 0.51057-0.15353 0.16424-0.4463 0.16424-0.17852 0-0.29278-0.03213-0.11425-0.02856-0.18566-0.06784l0.07498-0.22137q0.07141 0.03213 0.1571 0.0607 0.08569 0.02856 0.21066 0.02856 0.2178 0 0.29635-0.1214 0.08212-0.1214 0.08212-0.40703v-0.13211h-0.01071q-0.05713 0.08212-0.14639 0.12854-0.08926 0.04641-0.22851 0.04641-0.28921 0-0.42488-0.22137-0.13568-0.22494-0.13568-0.70338 0-0.46059 0.17495-0.69624 0.17852-0.23565 0.52486-0.23565 0.16781 0 0.2892 0.03213t0.21423 0.07498zm-0.25707-1.6103q-0.10711-0.05713-0.27492-0.05713-0.18209 0-0.29278 0.16781-0.11068 0.16424-0.11068 0.52842 0 0.14996 0.01785 0.27849 0.01785 0.12497 0.0607 0.22137 0.04285 0.09283 0.10711 0.14639 0.06784 0.04999 0.16424 0.04999 0.13568 0 0.21423-0.07141t0.11425-0.21423z"/>
-                               </g>
-                       </g>
-                       <g transform="matrix(4.0081 0 0 4.0081 -210.57 -224.31)" stroke-width=".20131" style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal" aria-label="lightweight, portable C library">
-                               <path d="m-49.147 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-48.878 49.946h0.11596v0.80524h-0.11596zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-48.041 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04992 0.07408-0.04992 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-47.441 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04832-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-47.226 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-46.272 49.946 0.14333 0.47026 0.02899 0.15461h0.0032l0.02416-0.15783 0.10951-0.46704h0.10951l-0.21418 0.82295h-0.06603l-0.16266-0.52824-0.02255-0.13528h-0.0032l-0.02255 0.13689-0.15783 0.52662h-0.06603l-0.22064-0.82295h0.12401l0.12401 0.46865 0.01933 0.15622h0.0032l0.02899-0.15944 0.13206-0.46543z"/>
-                               <path d="m-45.286 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05315-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08535-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-45.084 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-44.247 50.789q0 0.15622-0.06925 0.2303-0.06925 0.07408-0.20131 0.07408-0.08052 0-0.13206-0.0145-0.05153-0.01288-0.08374-0.0306l0.03382-0.09985q0.03221 0.01449 0.07086 0.02738 0.03865 0.01288 0.09502 0.01288 0.09824 0 0.13367-0.05476 0.03704-0.05476 0.03704-0.18359v-0.05959h-0.0048q-0.02577 0.03704-0.06603 0.05798t-0.10307 0.02094q-0.13045 0-0.19165-0.09985-0.0612-0.10146-0.0612-0.31726 0-0.20775 0.07891-0.31404 0.08052-0.10629 0.23674-0.10629 0.07569 0 0.13045 0.01449 0.05476 0.01449 0.09663 0.03382zm-0.11595-0.72632q-0.04831-0.02577-0.12401-0.02577-0.08213 0-0.13206 0.07569-0.04993 0.07408-0.04993 0.23835 0 0.06764 0.0081 0.12562 0.0081 0.05637 0.02738 0.09985 0.01933 0.04187 0.04831 0.06603 0.0306 0.02255 0.07408 0.02255 0.0612 0 0.09663-0.03221t0.05154-0.09663z"/>
-                               <path d="m-43.647 50.752v-0.48958q0-0.11273-0.02738-0.17071-0.02577-0.05959-0.10468-0.05959-0.05637 0-0.10307 0.04026-0.04509 0.04026-0.0612 0.10146v0.57816h-0.11595v-1.1273h0.11595v0.39779h0.0048q0.03221-0.04187 0.07891-0.06764 0.04831-0.02738 0.11918-0.02738 0.05315 0 0.0918 0.0145 0.04026 0.01449 0.06603 0.04992t0.03865 0.09502q0.01288 0.05798 0.01288 0.14494v0.52018z"/>
-                               <path d="m-43.432 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01771 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-42.945 50.682q0-0.04026 0.02255-0.06442 0.02416-0.02416 0.0612-0.02416 0.04187 0 0.06764 0.03382 0.02738 0.03382 0.02738 0.10629 0 0.05315-0.01449 0.09502-0.01288 0.04348-0.03543 0.07569-0.02094 0.03221-0.0467 0.05315-0.02577 0.02094-0.04993 0.0306l-0.04026-0.05476q0.02094-0.01127 0.03865-0.0306 0.01933-0.01772 0.0306-0.04026 0.01288-0.02255 0.01933-0.04831 0.0064-0.02416 0.0064-0.04831-0.03221 0.0097-0.05959-0.01288-0.02738-0.02255-0.02738-0.07086z"/>
-                               <path d="m-42.373 49.946h0.08213l0.01771 0.08697h0.0064q0.05959-0.10629 0.18682-0.10629 0.12723 0 0.19004 0.09502 0.06442 0.09502 0.06442 0.31082 0 0.10146-0.02094 0.18359-0.02094 0.08052-0.05959 0.1385-0.03865 0.05637-0.09502 0.08696-0.05476 0.02899-0.1224 0.02899-0.0467 0-0.07408-0.0064-0.02738-0.0048-0.05959-0.02255v0.33176h-0.11595zm0.11595 0.67801q0.02255 0.01933 0.04992 0.0306 0.02899 0.01127 0.07569 0.01127 0.08535 0 0.13528-0.08697 0.04992-0.08696 0.04992-0.24801 0-0.06764-0.0097-0.1224-0.0081-0.05476-0.02738-0.09341-0.01933-0.04026-0.04992-0.0612-0.02899-0.02255-0.07247-0.02255-0.11756 0-0.15138 0.14333z"/>
-                               <path d="m-41.707 50.349q0-0.21742 0.07408-0.31887 0.07569-0.10307 0.21419-0.10307 0.14816 0 0.21741 0.10468 0.07086 0.10468 0.07086 0.31726 0 0.21902-0.07569 0.32048t-0.21258 0.10146q-0.14816 0-0.21902-0.10468-0.06925-0.10468-0.06925-0.31726zm0.12079 0q0 0.07086 0.0081 0.12884 0.0097 0.05798 0.02899 0.09985 0.02094 0.04187 0.05315 0.06603 0.03221 0.02255 0.0773 0.02255 0.08375 0 0.12562-0.07408 0.04187-0.07569 0.04187-0.24318 0-0.06925-0.0097-0.12723-0.0081-0.05959-0.02899-0.10146-0.01933-0.04187-0.05154-0.06442-0.03221-0.02416-0.0773-0.02416-0.08213 0-0.12562 0.07569-0.04187 0.07569-0.04187 0.24157z"/>
-                               <path d="m-40.977 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-40.579 49.946h0.09824v-0.15944l0.11595-0.03704v0.19648h0.17393v0.10468h-0.17393v0.47992q0 0.07086 0.01611 0.10307 0.01772 0.0306 0.05637 0.0306 0.03221 0 0.05476-0.0064 0.02416-0.0081 0.05154-0.01933l0.02255 0.0918q-0.03543 0.01772-0.07891 0.02738-0.04187 0.01127-0.08858 0.01127-0.08052 0-0.11595-0.05154-0.03382-0.05315-0.03382-0.17071v-0.49603h-0.09824z"/>
-                               <path d="m-40.063 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08697 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.01611 0 0.03221 0 0.01611 0 0.03382 0.0016 0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.0161-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08213 0.03543 0.06764 0 0.10468-0.03221 0.03704-0.03221 0.05153-0.07086z"/>
-                               <path d="m-39.41 49.624h0.11595v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08374 0.3237-0.08214 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11595 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08375 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-38.588 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-37.856 50.697q-0.03865 0.03543-0.09824 0.05476t-0.12562 0.01933q-0.07569 0-0.13206-0.02899-0.05476-0.0306-0.0918-0.08535-0.03543-0.05637-0.05314-0.13367-0.01611-0.0773-0.01611-0.17393 0-0.20614 0.07569-0.31404t0.21419-0.1079q0.04509 0 0.08858 0.01127 0.04509 0.01127 0.08052 0.04509t0.05637 0.09502q0.02255 0.0612 0.02255 0.15944 0 0.02738-0.0032 0.05959-0.0016 0.0306-0.0048 0.06442h-0.40906q0 0.06925 0.01127 0.12562 0.01127 0.05637 0.03543 0.09663 0.02416 0.03865 0.0612 0.0612 0.03865 0.02094 0.09502 0.02094 0.04348 0 0.08536-0.0161 0.04348-0.01611 0.06603-0.03865zm-0.09019-0.43161q0.0032-0.12079-0.03382-0.17715-0.03704-0.05637-0.10146-0.05637-0.07408 0-0.11756 0.05637-0.04348 0.05637-0.05154 0.17715z"/>
-                               <path d="m-36.734 50.708q-0.04026 0.03382-0.10146 0.04831t-0.12884 0.01449q-0.08535 0-0.15783-0.03221-0.07247-0.03221-0.12562-0.10146-0.05154-0.07086-0.08052-0.18198-0.02899-0.11112-0.02899-0.26734 0-0.16105 0.03221-0.27217 0.03382-0.11112 0.08858-0.18037t0.12562-0.09985q0.07247-0.0306 0.14816-0.0306 0.0773 0 0.12723 0.01127 0.05154 0.01127 0.08858 0.02738l-0.02899 0.10951q-0.03221-0.01772-0.07569-0.02738-0.04348-0.0097-0.09985-0.0097t-0.10629 0.02577q-0.04993 0.02416-0.08858 0.08052-0.03865 0.05476-0.0612 0.14494-0.02255 0.09019-0.02255 0.22064 0 0.23513 0.08052 0.3543 0.08052 0.11756 0.21419 0.11756 0.05476 0 0.09824-0.01449 0.04348-0.0161 0.07408-0.03704z"/>
-                               <path d="m-36.176 50.56q0 0.05637 0.01449 0.08052 0.0161 0.02416 0.04348 0.02416 0.03382 0 0.07891-0.01772l0.01127 0.09341q-0.02094 0.01288-0.05959 0.02094-0.03704 0.0081-0.06764 0.0081-0.0612 0-0.09985-0.03704-0.03704-0.03865-0.03704-0.13367v-0.97434h0.11595z"/>
-                               <path d="m-35.906 49.946h0.11595v0.80524h-0.11595zm-0.02094-0.24479q0-0.03865 0.02094-0.06281 0.02255-0.02416 0.05798-0.02416t0.05798 0.02416q0.02416 0.02255 0.02416 0.06281 0 0.03865-0.02416 0.0612-0.02255 0.02094-0.05798 0.02094t-0.05798-0.02255q-0.02094-0.02255-0.02094-0.05959z"/>
-                               <path d="m-35.576 49.624h0.11596v0.38329h0.0048q0.06603-0.08052 0.17554-0.08052 0.12401 0 0.1852 0.09824 0.06281 0.09824 0.06281 0.31082 0 0.21741-0.08375 0.3237-0.08213 0.10629-0.23352 0.10629-0.07408 0-0.13528-0.0161-0.0612-0.01772-0.0918-0.04026zm0.11596 1.0098q0.02255 0.01288 0.05476 0.02094 0.03382 0.0064 0.07086 0.0064 0.08374 0 0.13206-0.07891 0.04993-0.08052 0.04993-0.2464 0-0.06925-0.0097-0.12401-0.0081-0.05637-0.02738-0.09663-0.01771-0.04026-0.04831-0.0612-0.02899-0.02255-0.07086-0.02255-0.05798 0-0.09663 0.03543-0.03704 0.03382-0.05476 0.09341z"/>
-                               <path d="m-34.878 49.946h0.08213l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-34.446 49.995q0.0467-0.02899 0.11273-0.04509 0.06764-0.01611 0.14172-0.01611 0.06764 0 0.1079 0.02094 0.04187 0.01933 0.06442 0.05476 0.02416 0.03382 0.0306 0.07891 0.0081 0.04348 0.0081 0.0918 0 0.09663-0.0048 0.18842-0.0032 0.0918-0.0032 0.17393 0 0.0612 0.0032 0.11434 0.0048 0.05154 0.01611 0.09824h-0.08858l-0.02738-0.09502h-0.0064q-0.02416 0.04187-0.07086 0.07247t-0.12562 0.0306q-0.08696 0-0.14333-0.05959-0.05476-0.0612-0.05476-0.16749 0-0.06925 0.02255-0.11596 0.02416-0.0467 0.06603-0.07569 0.04348-0.02899 0.10146-0.04026 0.05959-0.01288 0.13206-0.01288 0.0161 0 0.03221 0t0.03382 0.0016q0.0048-0.04993 0.0048-0.08858 0-0.0918-0.02738-0.12884-0.02738-0.03704-0.09985-0.03704-0.04509 0-0.09824 0.01449-0.05315 0.01288-0.08858 0.03382zm0.34947 0.38974q-0.01611-0.0016-0.03221-0.0016-0.01611-0.0016-0.03221-0.0016-0.03865 0-0.07569 0.0064t-0.06603 0.02255q-0.02899 0.0161-0.0467 0.04348-0.01611 0.02738-0.01611 0.06925 0 0.06442 0.0306 0.09985 0.03221 0.03543 0.08214 0.03543 0.06764 0 0.10468-0.03221t0.05154-0.07086z"/>
-                               <path d="m-33.793 49.946h0.08214l0.02094 0.08535h0.0048q0.02255-0.0467 0.05798-0.07247 0.03704-0.02738 0.08858-0.02738 0.03704 0 0.08375 0.01449l-0.02255 0.11756q-0.04187-0.01449-0.07408-0.01449-0.05154 0-0.08374 0.0306-0.03221 0.02899-0.04187 0.07891v0.59265h-0.11595z"/>
-                               <path d="m-33.153 50.467 0.03382 0.15622h0.0081l0.02416-0.15622 0.1224-0.52018h0.11756l-0.19165 0.7231q-0.02255 0.08696-0.04509 0.16266-0.02255 0.07569-0.04992 0.13045-0.02577 0.05637-0.05959 0.08697-0.03221 0.03221-0.0773 0.03221t-0.07891-0.01449l0.01933-0.10951q0.02255 0.0081 0.04509 0.0032 0.02255-0.0048 0.04187-0.02738 0.02094-0.02255 0.03704-0.06764 0.01772-0.04348 0.0306-0.11434l-0.2609-0.80524h0.13206z"/>
-                       </g>
-                       <path d="m-435.92-23.597c0.28617-0.34918 0.57227-0.69834 0.85837-1.0475 0.42677 0.47526 0.85355 0.95052 1.2803 1.4258 0.76622 0.0048 1.5325 0.01002 2.2987 0.01443-0.82927-0.91657-1.6586-1.8331-2.4878-2.7497 0.40254-0.45586 0.80503-0.91173 1.2076-1.3676 0.78562 0.91658 1.5713 1.8332 2.3569 2.7497-4e-3 -0.87778-8e-3 -1.7556-0.0161-2.6333-0.40253-0.45101-0.80501-0.90202-1.2075-1.353 0.28858-0.42545 0.99829-0.86377 0.3475-1.2606-1.4591-1.6118-2.9183-3.2236-4.3774-4.8354-3.0679-0.01042-6.1393 0.04092-9.205-0.0084-0.72986-0.06429-1.6392-0.29547-1.8065-1.1337-0.35271-1.09 0.84574-2.3762 1.9465-1.8649 0.76081 0.14726 0.44105 1.6835-0.23166 1.1743 0.69856-1.0262-1.2808-0.90972-0.72049 0.09824 0.38397 0.88195 1.783 1.0275 2.3349 0.22513 0.57404-0.92504-0.20641-1.9788-1.0842-2.3446-0.87836-0.41949-1.9686-0.31147-2.7028 0.34337-1.0973 0.83626-1.6281 2.4707-0.91191 3.7193 0.4168 0.93386 1.3405 1.5318 2.3429 1.6481 1.343 0.16782 2.7026 0.06445 4.0539 0.09323h5.3734c1.0184 1.13 2.0368 2.2599 3.0553 3.3899-0.91656 1.0136-1.8331 2.0271-2.7497 3.0407-0.66422-0.85695-1.6664-1.5082-2.0708-2.5299-0.32706-1.1972 1.4194-2.1305 2.2518-1.2247 0.79933 0.44227-0.0473 1.8554-0.62433 1.0813 0.46733-0.15836 0.67752-0.90508-0.0577-0.86727-0.86169 0.32798-0.49311 1.6295 0.25772 1.8808 0.71628 0.34674 1.6137-0.30285 1.5227-1.0869 0.0733-1.1334-0.75524-2.3676-1.9525-2.4204-1.2813-0.24958-2.727 0.4999-3.0402 1.8142-0.43151 1.1314 0.27896 2.2662 1.0551 3.0447 0.91076 0.98537 1.8001 1.9916 2.7018 2.985z" fill="#f00"/>
-                       <path d="m-428.86-22.458c8e-3 -2.1947 0.012-4.3894 0.0201-6.5841-1.356-1.553-2.7839-3.046-4.0921-4.6391-0.4374-0.54095-0.77164-1.181-0.74606-1.8954-0.036-1.3281 0.79082-2.6298 2.0264-3.1348 0.95151-0.42136 2.0903-0.46194 3.022 0.03768 1.2998 0.66198 1.9155 2.4493 1.2087 3.7417-0.54185 0.79964-1.9325 0.78325-2.3809-0.10621-0.43247-0.56653-0.40691-1.7268 0.41575-1.8879 0.66914-0.01363 0.83223 0.96617 0.0962 1.0053-0.16353 0.63656 1.1345 0.49025 1.0924-0.18221 0.16593-0.92802-0.8623-1.6839-1.7291-1.5091-0.97624 0.09675-1.834 1.1261-1.4963 2.1064 0.35552 0.96342 1.2138 1.6073 1.8524 2.3761 1.0266 1.1181 2.05 2.2391 3.0765 3.3574-8e-3 2.445-0.012 4.89-0.0201 7.335-0.78189-0.0068-1.5639-0.01403-2.3458-0.02044z"/>
-                       <path d="m-429.09-21.883-6.584 0.02044c-1.5531-1.356-3.0461-2.7839-4.6392-4.092-0.54093-0.43739-1.181-0.77164-1.8954-0.74605-1.3281-0.03447-2.6298 0.79084-3.1348 2.0263-0.42133 0.95153-0.46193 2.0903 0.036 3.0221 0.66201 1.2998 2.4493 1.9155 3.7417 1.2087 0.79964-0.54184 0.78325-1.9325-0.10621-2.381-0.56654-0.43248-1.7268-0.40688-1.8879 0.41576-0.012 0.66918 0.96618 0.83223 1.0053 0.09607 0.63656-0.16373 0.49027 1.1345-0.18236 1.0924-0.92803 0.16585-1.6839-0.86229-1.5092-1.7291 0.0966-0.97624 1.1261-1.834 2.1064-1.4963 0.96341 0.35556 1.6073 1.2139 2.376 1.8524 1.1181 1.0266 2.2391 2.05 3.3574 3.0765l9.8442-0.02044c-1.143-0.9713-1.4343-1.4219-2.5296-2.3458z"/>
-               </g>
-       </g>
+<svg width="117.26mm" height="19.676mm" version="1.1" viewBox="0 0 117.26 19.677" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<metadata>
+<rdf:RDF>
+<cc:Work rdf:about="">
+<dc:format>image/svg+xml</dc:format>
+<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+<dc:title/>
+</cc:Work>
+</rdf:RDF>
+</metadata>
+<path d="m0-2.6715e-4h117.26v19.677h-117.26z" fill="none"/>
+<g transform="matrix(.63895 0 0 .63895 2.5477 3.6562)">
+<g transform="matrix(.9517 0 0 .9517 3.2398 -93.904)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m12.174 13.987a1.2015 1.2015 0 0 1-1.2024 1.2024 1.2015 1.2015 0 0 1-1.2006-1.2024 1.2015 1.2015 0 0 1 1.2006-1.2005 1.2015 1.2015 0 0 1 1.2024 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m8.2754 5.0474h2.468v5.6755h-2.468z"/>
+<path d="m16.25 13.965a1.2015 1.2015 0 0 1-1.2027 1.2005 1.2015 1.2015 0 0 1-1.2004-1.2005 1.2015 1.2015 0 0 1 1.2004-1.2025 1.2015 1.2015 0 0 1 1.2027 1.2025" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m19.545 13.928a1.2015 1.2015 0 0 1-1.2025 1.2026 1.2015 1.2015 0 0 1-1.2003-1.2026 1.2015 1.2015 0 0 1 1.2003-1.2005 1.2015 1.2015 0 0 1 1.2025 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m23.75 13.902a1.2015 1.2015 0 0 1-1.2005 1.2024 1.2015 1.2015 0 0 1-1.2025-1.2024 1.2015 1.2015 0 0 1 1.2025-1.2005 1.2015 1.2015 0 0 1 1.2005 1.2005" stroke-linecap="round" stroke-width=".98647"/>
+<path d="m26.249 5.0292a1.2015 1.2015 0 0 1-1.2027 1.2004 1.2015 1.2015 0 0 1-1.2004-1.2004 1.2015 1.2015 0 0 1 1.2004-1.2026 1.2015 1.2015 0 0 1 1.2027 1.2026" stroke-linecap="round" stroke-width=".98647"/>
+<g transform="matrix(.9517 0 0 .9517 6.3252 -93.961)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 9.3806 -93.988)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 13.506 -94.006)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<g transform="matrix(.9517 0 0 .9517 -.82062 -93.74)">
+<path d="m9.5909 107.4h2.5567v2.649h-2.5567z"/>
+<path d="m12.12 107.36a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+<path d="m12.127 110.05a1.2625 1.2625 0 0 1-1.2625 1.262 1.2625 1.2625 0 0 1-1.2625-1.262 1.2625 1.2625 0 0 1 1.2625-1.262 1.2625 1.2625 0 0 1 1.2625 1.262" stroke-linecap="round" stroke-width="1.0365"/>
+</g>
+<path d="m10.703 5.0413a1.2015 1.2015 0 0 1-1.2006 1.2025 1.2015 1.2015 0 0 1-1.2025-1.2025 1.2015 1.2015 0 0 1 1.2025-1.2004 1.2015 1.2015 0 0 1 1.2006 1.2004" stroke-linecap="round" stroke-width=".98647"/>
+</g>
+<g transform="matrix(2.6825 0 0 2.6825 -289.72 -275.57)" dominant-baseline="auto" stroke-width=".29098" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" aria-label="libwebsockets.org">
+<path d="m117.05 105.01v2.752h0.224v-2.752z"/>
+<path d="m117.95 105.71v2.057h0.223v-2.057zm-0.04-0.695v0.318h0.297v-0.318z"/>
+<path d="m118.8 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.594 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.15-0.855 0.625-0.855z"/>
+<path d="m120.79 105.71 0.555 2.057h0.314l0.479-1.858 0.482 1.858h0.314l0.551-2.057h-0.23l-0.482 1.879-0.482-1.879h-0.303l-0.486 1.879-0.478-1.879z"/>
+<path d="m125.54 106.8v-0.157c0-0.433-0.06-0.964-0.869-0.964-0.824 0-0.891 0.566-0.891 1.079 0 0.688 0.196 1.034 0.926 1.034 0.495 0 0.792-0.178 0.831-0.663h-0.224c-0.01 0.377-0.262 0.464-0.628 0.464-0.611 0-0.688-0.314-0.685-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.493 0 0.653 0.21 0.65 0.727z"/>
+<path d="m126.04 105.01v2.752h0.203l0.02-0.251c0.101 0.157 0.244 0.279 0.649 0.279 0.601 0 0.81-0.307 0.81-1.083 0-0.541-0.09-1.03-0.81-1.03-0.468 0-0.593 0.196-0.649 0.283v-0.95zm0.845 0.87c0.552 0 0.618 0.339 0.618 0.855 0 0.486-0.05 0.852-0.611 0.852-0.426 0-0.632-0.181-0.632-0.852 0-0.597 0.151-0.855 0.625-0.855z"/>
+<path d="m129.86 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.273 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m130.35 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.584 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m134.12 107.03c0 0.471-0.22 0.565-0.656 0.565-0.496 0-0.667-0.181-0.667-0.838 0-0.782 0.272-0.869 0.677-0.869 0.283 0 0.625 0.06 0.625 0.531h0.22c0.01-0.734-0.639-0.734-0.845-0.734-0.632 0-0.897 0.245-0.897 1.058 0 0.793 0.248 1.055 0.908 1.055 0.468 0 0.834-0.115 0.859-0.768z"/>
+<path d="m135.05 106.64v-1.624h-0.22v2.752h0.22v-1.072l1.076 1.072h0.321l-1.149-1.1 1.041-0.957h-0.318z"/>
+<path d="m138.48 106.8v-0.157c0-0.433-0.06-0.964-0.87-0.964-0.824 0-0.89 0.566-0.89 1.079 0 0.688 0.195 1.034 0.925 1.034 0.496 0 0.793-0.178 0.831-0.663h-0.223c-0.01 0.377-0.262 0.464-0.629 0.464-0.611 0-0.688-0.314-0.684-0.793zm-1.54-0.195c0.02-0.374 0.08-0.727 0.667-0.727 0.492 0 0.653 0.21 0.649 0.727z"/>
+<path d="m139.29 105.71h-0.457v0.206h0.457v1.348c0 0.335 0.07 0.531 0.664 0.531 0.09 0 0.139 0 0.181-0.01v-0.209c-0.06 0-0.136 0.01-0.251 0.01-0.374 0-0.374-0.129-0.374-0.381v-1.292h0.541v-0.206h-0.541v-0.488h-0.22z"/>
+<path d="m142.15 106.28c0-0.24-0.06-0.604-0.799-0.604-0.426 0-0.814 0.109-0.814 0.601 0 0.381 0.241 0.471 0.489 0.503l0.576 0.08c0.272 0.04 0.381 0.08 0.381 0.338 0 0.315-0.224 0.391-0.618 0.391-0.646 0-0.646-0.223-0.646-0.481h-0.224c0 0.279 0.04 0.684 0.852 0.684 0.37 0 0.856-0.05 0.856-0.608 0-0.415-0.294-0.492-0.486-0.516l-0.607-0.08c-0.234-0.03-0.356-0.07-0.356-0.297 0-0.192 0.06-0.408 0.593-0.408 0.583 0 0.58 0.237 0.58 0.401z"/>
+<path d="m142.76 107.44v0.321h0.293v-0.321z"/>
+<path d="m143.54 106.74c0 0.594 0.06 1.058 0.908 1.058 0.883 0 0.904-0.51 0.904-1.103 0-0.601-0.108-1.01-0.904-1.01-0.852 0-0.908 0.475-0.908 1.055zm0.908-0.852c0.569 0 0.684 0.213 0.684 0.803 0 0.636-0.05 0.904-0.684 0.904-0.583 0-0.688-0.223-0.688-0.824 0-0.6 0.04-0.883 0.688-0.883z"/>
+<path d="m145.81 105.71v2.057h0.22v-1.337c0-0.542 0.419-0.542 0.569-0.542h0.206v-0.213c-0.37 0-0.576 0-0.775 0.259l-0.01-0.231z"/>
+<path d="m149.11 105.62c-0.331 0.01-0.391 0.136-0.429 0.217-0.143-0.14-0.44-0.158-0.646-0.158-0.503 0-0.821 0.14-0.821 0.601 0 0.119 0.02 0.272 0.126 0.398-0.175 0.02-0.265 0.157-0.265 0.325 0 0.1 0.04 0.258 0.22 0.311-0.07 0.03-0.245 0.132-0.245 0.408 0 0.412 0.374 0.51 1.006 0.51 0.593 0 0.971-0.09 0.971-0.541 0-0.297-0.175-0.465-0.601-0.489l-0.922-0.06c-0.105 0-0.223-0.05-0.223-0.182 0-0.08 0.04-0.132 0.153-0.195 0.123 0.09 0.322 0.126 0.629 0.126 0.384 0 0.82-0.05 0.82-0.625 0-0.172-0.04-0.227-0.08-0.297 0.06-0.112 0.108-0.133 0.307-0.143zm-1.065 0.258c0.535 0 0.622 0.182 0.622 0.388 0 0.339-0.178 0.426-0.611 0.426-0.423 0-0.622-0.07-0.622-0.384 0-0.356 0.192-0.43 0.611-0.43zm0.206 1.512c0.36 0.02 0.556 0.06 0.556 0.308 0 0.216-0.147 0.331-0.751 0.331-0.674 0-0.8-0.1-0.8-0.345 0-0.304 0.318-0.336 0.328-0.336z"/>
+</g>
 </svg>
index 5d56ca2..096909f 100644 (file)
@@ -113,9 +113,6 @@ function lws_gray_out(vis, _options) {
 
 function new_ws(urlpath, protocol)
 {
-       if (typeof MozWebSocket != "undefined")
-               return new MozWebSocket(urlpath, protocol);
-
        return new WebSocket(urlpath, protocol);
 }
  
index 881cf8f..640fa8a 100644 (file)
@@ -92,7 +92,7 @@ lws_poly_rand(struct lws_poly_gen *p)
        p->cyc[1] = (p->cyc[1] & 1) ? (p->cyc[1] >> 1) ^ 0x7a5bc2e3 :
                                      p->cyc[1] >> 1;
 
-       return p->cyc[0] ^ p->cyc[1];
+       return (uint8_t)(p->cyc[0] ^ p->cyc[1]);
 }
 
 static void show_http_content(const char *p, size_t l)
@@ -120,6 +120,9 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
 {
 #if defined(LWS_WITH_TLS)
        union lws_tls_cert_info_results ci;
+#if defined(LWS_HAVE_CTIME_R) && !defined(LWS_WITH_NO_LOGS)
+       char date[32];
+#endif
 #endif
        const char *which = "http";
        char which_wsi[10], buf[50 + LWS_PRE];
@@ -190,11 +193,22 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
 
                if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_VALIDITY_FROM,
                                            &ci, 0))
-                       lwsl_notice(" Peer Cert Valid from: %s", ctime(&ci.time));
-
+#if defined(LWS_HAVE_CTIME_R)
+                       lwsl_notice(" Peer Cert Valid from: %s",
+                                               ctime_r(&ci.time, date));
+#else
+                       lwsl_notice(" Peer Cert Valid from: %s",
+                                               ctime(&ci.time));
+#endif
                if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_VALIDITY_TO,
                                            &ci, 0))
-                       lwsl_notice(" Peer Cert Valid to  : %s", ctime(&ci.time));
+#if defined(LWS_HAVE_CTIME_R)
+                       lwsl_notice(" Peer Cert Valid to  : %s",
+                                               ctime_r(&ci.time, date));
+#else
+                       lwsl_notice(" Peer Cert Valid to  : %s",
+                                               ctime(&ci.time));
+#endif
                if (!lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_USAGE,
                                            &ci, 0))
                        lwsl_notice(" Peer Cert usage bits: 0x%x\n", ci.usage);
@@ -293,10 +307,18 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
                        X509_VERIFY_PARAM_free(param);
                        if (n != 1) {
                                char errbuf[256];
-                               n = ERR_get_error();
+                               const char *es;
+
+                               n = (int)ERR_get_error();
+                               es = ERR_error_string(
+#if defined(LWS_WITH_BORINGSSL)
+                                                        (uint32_t)
+#else
+                                                        (unsigned long)
+#endif
+                                                        n, errbuf);
                                lwsl_err("EXTRA_CLIENT_VERIFY_CERTS: "
-                                        "SSL error: %s (%d)\n",
-                                        ERR_error_string(n, errbuf), n);
+                                        "SSL error: %s (%d)\n", es, n);
                                return 1;
                        }
                }
@@ -339,7 +361,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
                }
 
                lws_get_random(lws_get_context(wsi), rands, sizeof(rands[0]));
-               mirror_lifetime = 16384 + (rands[0] & 65535);
+               mirror_lifetime = (int)(16384 + (rands[0] & 65535));
                /* useful to test single connection stability */
                if (longlived)
                        mirror_lifetime += 500000;
@@ -406,7 +428,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
                                        (rands[3] & 31) + 1);   /* radius */
                }
 
-               n = lws_write(wsi, &buf[LWS_PRE], l,
+               n = (int)lws_write(wsi, &buf[LWS_PRE], (unsigned int)l,
                              opts | LWS_WRITE_TEXT);
                if (n < 0)
                        return -1;
@@ -433,7 +455,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
                        p = (unsigned char *)in;
                        for (n = 0; n < (int)len; n++)
                                if (*p++ != lws_poly_rand(&rx)) {
-                                       lwsl_err("mismatch at rxb %d offset %d\n", rxb + (n / block_size), n % block_size);
+                                       lwsl_err("mismatch at rxb %d offset %d\n", (int)rxb + (n / block_size), n % block_size);
                                        errs++;
                                        force_exit = 1;
                                        return -1;
@@ -493,23 +515,21 @@ static const struct lws_protocols protocols[] = {
        {
                "dumb-increment-protocol",
                callback_dumb_increment,
-               0,
-               20,
+               0, 20, 0, NULL, 0
        },
        {
                "lws-mirror-protocol",
                callback_lws_mirror,
-               0,
-               4096,
+               0, 4096, 0, NULL, 0
        }, {
                "lws-test-raw-client",
                callback_test_raw_client,
-               0,
-               128
+               0, 128, 0, NULL, 0
        },
-       { NULL, NULL, 0, 0 } /* end */
+       LWS_PROTOCOL_LIST_TERM
 };
 
+#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
 static const struct lws_extension exts[] = {
        {
                "permessage-deflate",
@@ -523,7 +543,7 @@ static const struct lws_extension exts[] = {
        },
        { NULL, NULL, NULL /* terminator */ }
 };
-
+#endif
 
 
 void sighandler(int sig)
@@ -547,7 +567,6 @@ static struct option options[] = {
        { "longlived",  no_argument,            NULL, 'l' },
        { "post",       no_argument,            NULL, 'o' },
        { "once",       no_argument,            NULL, 'O' },
-       { "pingpong-secs", required_argument,   NULL, 'P' },
        { "ssl-cert",  required_argument,       NULL, 'C' },
        { "ssl-key",  required_argument,        NULL, 'K' },
        { "ssl-ca",  required_argument,         NULL, 'A' },
@@ -564,10 +583,10 @@ static int ratelimit_connects(unsigned int *last, unsigned int secs)
 
        gettimeofday(&tv, NULL);
 
-       if (tv.tv_sec - (*last) < secs)
+       if ((unsigned long)tv.tv_sec - (unsigned long)(*last) < (unsigned long)secs)
                return 0;
 
-       *last = tv.tv_sec;
+       *last = (unsigned int)tv.tv_sec;
 
        return 1;
 }
@@ -575,8 +594,7 @@ static int ratelimit_connects(unsigned int *last, unsigned int secs)
 int main(int argc, char **argv)
 {
        int n = 0, m, ret = 0, port = 7681, use_ssl = 0, ietf_version = -1;
-       unsigned int rl_dumb = 0, rl_mirror = 0, do_ws = 1, pp_secs = 0,
-                    do_multi = 0;
+       unsigned int rl_dumb = 0, rl_mirror = 0, do_ws = 1, do_multi = 0;
        struct lws_context_creation_info info;
        struct lws_client_connect_info i;
        struct lws_context *context;
@@ -589,7 +607,7 @@ int main(int argc, char **argv)
 
        memset(&info, 0, sizeof info);
 
-       lwsl_notice("libwebsockets test client - license LGPL2.1+SLE\n");
+       lwsl_notice("libwebsockets test client - license MIT\n");
        lwsl_notice("(C) Copyright 2010-2018 Andy Green <andy@warmcat.com>\n");
 
        if (argc < 2)
@@ -597,9 +615,9 @@ int main(int argc, char **argv)
 
        while (n >= 0) {
 #if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)
-       n = getopt_long(argc, argv, "Sjnuv:hsp:d:lC:K:A:P:moeO", options, NULL);
+       n = getopt_long(argc, argv, "Sjnuv:hsp:d:lC:K:A:moeO", options, NULL);
 #else
-       n = getopt(argc, argv, "Sjnuv:hsp:d:lC:K:A:P:moeO");
+       n = getopt(argc, argv, "Sjnuv:hsp:d:lC:K:A:moeO");
 #endif
                if (n < 0)
                        continue;
@@ -621,10 +639,6 @@ int main(int argc, char **argv)
                case 'e':
                        flag_echo = 1;
                        break;
-               case 'P':
-                       pp_secs = atoi(optarg);
-                       lwsl_notice("Setting pingpong interval to %d\n", pp_secs);
-                       break;
                case 'j':
                        justmirror = 1;
                        break;
@@ -707,10 +721,11 @@ int main(int argc, char **argv)
 
        info.port = CONTEXT_PORT_NO_LISTEN;
        info.protocols = protocols;
-       info.gid = -1;
-       info.uid = -1;
-       info.ws_ping_pong_interval = pp_secs;
+       info.gid = (gid_t)-1;
+       info.uid = (uid_t)-1;
+#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
        info.extensions = exts;
+#endif
 
        /*
         * since we know this lws context is only ever going to be used with
@@ -725,7 +740,7 @@ int main(int argc, char **argv)
 #endif
 
        info.options |= LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW;
-
+#if defined(LWS_WITH_TLS)
        if (use_ssl) {
                /*
                 * If the server wants us to present a valid SSL client certificate
@@ -766,7 +781,7 @@ int main(int argc, char **argv)
                lwsl_notice(" Skipping peer cert hostname check\n");
        else
                lwsl_notice(" Requiring peer cert hostname matches\n");
-
+#endif
        context = lws_create_context(&info);
        if (context == NULL) {
                fprintf(stderr, "Creating libwebsocket context failed\n");
diff --git a/test-apps/test-lecp.c b/test-apps/test-lecp.c
new file mode 100644 (file)
index 0000000..f10f0d2
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * lejp test app
+ *
+ * Written in 2010-2019 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates a minimal http server that performs a form GET with a couple
+ * of parameters.  It dumps the parameters to the console log and redirects
+ * to another page.
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+
+
+static const char * const reason_names[] = {
+       "LECPCB_CONSTRUCTED",
+       "LECPCB_DESTRUCTED",
+       "LECPCB_START",
+       "LECPCB_COMPLETE",
+       "LECPCB_FAILED",
+       "LECPCB_PAIR_NAME",
+       "LECPCB_VAL_TRUE",
+       "LECPCB_VAL_FALSE",
+       "LECPCB_VAL_NULL",
+       "LECPCB_VAL_NUM_INT",
+       "LECPCB_VAL_RESERVED", /* float in lejp */
+       "LECPCB_VAL_STR_START",
+       "LECPCB_VAL_STR_CHUNK",
+       "LECPCB_VAL_STR_END",
+       "LECPCB_ARRAY_START",
+       "LECPCB_ARRAY_END",
+       "LECPCB_OBJECT_START",
+       "LECPCB_OBJECT_END",
+       "LECPCB_TAG_START",
+       "LECPCB_TAG_END",
+       "LECPCB_VAL_NUM_UINT",
+       "LECPCB_VAL_UNDEFINED",
+       "LECPCB_VAL_FLOAT16",
+       "LECPCB_VAL_FLOAT32",
+       "LECPCB_VAL_FLOAT64",
+       "LECPCB_VAL_SIMPLE",
+       "LECPCB_VAL_BLOB_START",
+       "LECPCB_VAL_BLOB_CHUNK",
+       "LECPCB_VAL_BLOB_END",
+};
+
+static const char * const tok[] = {
+       "dummy___"
+};
+
+static signed char
+cb(struct lecp_ctx *ctx, char reason)
+{
+       char buf[1024], *p = buf, *end = &buf[sizeof(buf)];
+       int n;
+
+       for (n = 0; n < ctx->sp; n++)
+               *p++ = ' ';
+       *p = '\0';
+
+       lwsl_notice("%s%s: path %s match %d statckp %d\r\n", buf,
+                       reason_names[(unsigned int)(reason) &
+                                    (LEJP_FLAG_CB_IS_VALUE - 1)], ctx->path,
+                       ctx->path_match, ctx->pst[ctx->pst_sp].ppos);
+
+       if (reason & LECP_FLAG_CB_IS_VALUE) {
+
+               switch (reason) {
+               case LECPCB_VAL_NUM_UINT:
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                         "   value %llu ",
+                                         (unsigned long long)ctx->item.u.u64);
+                       break;
+               case LECPCB_VAL_STR_START:
+               case LECPCB_VAL_STR_CHUNK:
+               case LECPCB_VAL_STR_END:
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                         "   value '%s' ", ctx->buf);
+                       break;
+
+               case LECPCB_VAL_BLOB_START:
+               case LECPCB_VAL_BLOB_CHUNK:
+               case LECPCB_VAL_BLOB_END:
+                       if (ctx->npos)
+                               lwsl_hexdump_notice(ctx->buf, (size_t)ctx->npos);
+                       break;
+
+               case LECPCB_VAL_NUM_INT:
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                         "   value %lld ",
+                                         (long long)ctx->item.u.i64);
+                       break;
+               case LECPCB_VAL_FLOAT16:
+               case LECPCB_VAL_FLOAT32:
+               case LECPCB_VAL_FLOAT64:
+                       break;
+
+               case LECPCB_VAL_SIMPLE:
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
+                                         "   simple %llu ",
+                                         (unsigned long long)ctx->item.u.u64);
+                       break;
+               }
+               if (ctx->ipos) {
+                       int n;
+
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "(array indexes: ");
+                       for (n = 0; n < ctx->ipos; n++)
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%d ", ctx->i[n]);
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ") ");
+               }
+
+               lwsl_notice("%s \r\n", buf);
+
+               (void)reason_names; /* NO_LOGS... */
+               return 0;
+       }
+
+       switch (reason) {
+       case LECPCB_COMPLETE:
+               lwsl_notice("%sParsing Completed (LEJPCB_COMPLETE)\n", buf);
+               break;
+       case LECPCB_PAIR_NAME:
+               lwsl_notice("%spath: '%s' (LEJPCB_PAIR_NAME)\n", buf, ctx->path);
+               break;
+       case LECPCB_TAG_START:
+               lwsl_notice("LECPCB_TAG_START: %llu\r\n", (unsigned long long)ctx->item.u.u64);
+               return 0;
+       }
+
+       return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+       int fd, n = 1, ret = 1, m = 0;
+       struct lecp_ctx ctx;
+       char buf[128];
+
+       lws_set_log_level(7, NULL);
+
+       lwsl_notice("libwebsockets-test-lecp  (C) 2017 - 2021 andy@warmcat.com\n");
+       lwsl_notice("  usage: cat my.cbor | libwebsockets-test-lecp\n\n");
+
+       lecp_construct(&ctx, cb, NULL, tok, LWS_ARRAY_SIZE(tok));
+
+       fd = 0;
+
+       while (n > 0) {
+               n = (int)read(fd, buf, sizeof(buf));
+               if (n <= 0)
+                       continue;
+
+               m = lecp_parse(&ctx, (uint8_t *)buf, (size_t)n);
+               if (m < 0 && m != LEJP_CONTINUE) {
+                       lwsl_err("parse failed %d\n", m);
+                       goto bail;
+               }
+       }
+       lwsl_notice("okay (%d)\n", m);
+       ret = 0;
+bail:
+       lecp_destruct(&ctx);
+
+       return ret;
+}
index 43d11ec..b583f77 100644 (file)
@@ -1,22 +1,14 @@
 /*
- * Lightweight Embedded JSON Parser
+ * lejp test app
  *
- * Copyright (C) 2013-2017 Andy Green <andy@warmcat.com>
+ * Written in 2010-2019 by Andy Green <andy@warmcat.com>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
  *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
+ * This demonstrates a minimal http server that performs a form GET with a couple
+ * of parameters.  It dumps the parameters to the console log and redirects
+ * to another page.
  */
 
 #include <libwebsockets.h>
@@ -60,14 +52,14 @@ cb(struct lejp_ctx *ctx, char reason)
        *p = '\0';
 
        if (reason & LEJP_FLAG_CB_IS_VALUE) {
-               p += lws_snprintf(p, p - end, "   value '%s' ", ctx->buf);
+               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "   value '%s' ", ctx->buf);
                if (ctx->ipos) {
                        int n;
 
-                       p += lws_snprintf(p, p - end, "(array indexes: ");
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "(array indexes: ");
                        for (n = 0; n < ctx->ipos; n++)
-                               p += lws_snprintf(p, p - end, "%d ", ctx->i[n]);
-                       p += lws_snprintf(p, p - end, ") ");
+                               p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%d ", ctx->i[n]);
+                       p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ") ");
                }
                lwsl_notice("%s (%s)\r\n", buf,
                       reason_names[(unsigned int)
@@ -96,7 +88,7 @@ cb(struct lejp_ctx *ctx, char reason)
 int
 main(int argc, char *argv[])
 {
-       int fd, n = 1, ret = 1, m;
+       int fd, n = 1, ret = 1, m = 0;
        struct lejp_ctx ctx;
        char buf[128];
 
@@ -110,7 +102,7 @@ main(int argc, char *argv[])
        fd = 0;
 
        while (n > 0) {
-               n = read(fd, buf, sizeof(buf));
+               n = (int)read(fd, buf, sizeof(buf));
                if (n <= 0)
                        continue;
 
@@ -120,7 +112,7 @@ main(int argc, char *argv[])
                        goto bail;
                }
        }
-       lwsl_notice("okay\n");
+       lwsl_notice("okay (%d)\n", m);
        ret = 0;
 bail:
        lejp_destruct(&ctx);
index bc70cb0..36fec50 100644 (file)
@@ -55,26 +55,7 @@ char crl_path[1024] = "";
 
 /*
  * This demonstrates how to use the clean protocol service separation of
- * plugins, but with static inclusion instead of runtime dynamic loading
- * (which requires libuv).
- *
- * dumb-increment doesn't use the plugin, both to demonstrate how to
- * do the protocols directly, and because it wants libuv for a timer.
- *
- * Please consider using test-server-v2.0.c instead of this: it has the
- * same functionality but
- *
- * 1) uses lws built-in http handling so you don't need to deal with it in
- * your callback
- *
- * 2) Links with libuv and uses the plugins at runtime
- *
- * 3) Uses advanced lws features like mounts to bind parts of the filesystem
- * to the served URL space
- *
- * Another option is lwsws, this operates like test-server-v2,0.c but is
- * configured using JSON, do you do not need to provide any code for the
- * serving action at all, just implement your protocols in plugins.
+ * plugins, in this case by statically including them at build-time.
  */
 
 #define LWS_PLUGIN_STATIC
@@ -82,7 +63,21 @@ char crl_path[1024] = "";
 #include "../plugins/protocol_lws_mirror.c"
 #include "../plugins/protocol_lws_status.c"
 #include "../plugins/protocol_dumb_increment.c"
+#endif
 #include "../plugins/protocol_post_demo.c"
+
+#if defined(LWS_WITH_EXTERNAL_POLL)
+static struct lws_pollfd *
+ext_find_fd(lws_sockfd_type fd)
+{
+       int n;
+
+       for (n = 0; n < max_poll_elements; n++)
+               if (pollfds[n].fd == fd)
+                       return &pollfds[n];
+
+       return NULL;
+}
 #endif
 
 static int
@@ -90,10 +85,52 @@ lws_callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                  void *in, size_t len)
 {
        const unsigned char *c;
+#if defined(LWS_WITH_EXTERNAL_POLL)
+       struct lws_pollargs *pa;
+       struct lws_pollfd *pfd;
+#endif
        char buf[1024];
        int n = 0, hlen;
 
        switch (reason) {
+#if defined(LWS_WITH_EXTERNAL_POLL)
+       case LWS_CALLBACK_ADD_POLL_FD:
+               pa = (struct lws_pollargs *)in;
+               lwsl_debug("%s: ADD fd %d, ev %d\n", __func__, pa->fd, pa->events);
+               pfd = ext_find_fd(pa->fd);
+               if (pfd) {
+                       lwsl_notice("%s: ADD fd %d already in ext table\n",
+                                       __func__, pa->fd);
+               } else {
+                       pfd = ext_find_fd(LWS_SOCK_INVALID);
+                       if (!pfd)
+                               return -1;
+               }
+               pfd->fd = pa->fd;
+               pfd->events = (short)pa->events;
+               pfd->revents = 0;
+               /* high water mark... */
+               count_pollfds = (int)((pfd - pollfds) + 1);
+               break;
+       case LWS_CALLBACK_DEL_POLL_FD:
+               pa = (struct lws_pollargs *)in;
+               lwsl_debug("%s: DEL fd %d\n", __func__, pa->fd);
+               pfd = ext_find_fd(pa->fd);
+               if (!pfd)
+                       return -1;
+               pfd->fd = LWS_SOCK_INVALID;
+               break;
+       case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
+               pa = (struct lws_pollargs *)in;
+               lwsl_debug("%s: CH fd %d\n", __func__, pa->fd);
+               pfd = ext_find_fd(pa->fd);
+               if (!pfd) {
+                       lwsl_err("%s: unknown fd %d\n", __func__, pa->fd);
+                       return -1;
+               }
+               pfd->events = (short)pa->events;
+               break;
+#endif
        case LWS_CALLBACK_HTTP:
 
                /* non-mount-handled accesses will turn up here */
@@ -101,19 +138,19 @@ lws_callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
                /* dump the headers */
 
                do {
-                       c = lws_token_to_string(n);
+                       c = lws_token_to_string((enum lws_token_indexes)n);
                        if (!c) {
                                n++;
                                continue;
                        }
 
-                       hlen = lws_hdr_total_length(wsi, n);
+                       hlen = lws_hdr_total_length(wsi, (enum lws_token_indexes)n);
                        if (!hlen || hlen > (int)sizeof(buf) - 1) {
                                n++;
                                continue;
                        }
 
-                       if (lws_hdr_copy(wsi, buf, sizeof buf, n) < 0)
+                       if (lws_hdr_copy(wsi, buf, sizeof buf, (enum lws_token_indexes)n) < 0)
                                fprintf(stderr, "    %s (too big)\n", (char *)c);
                        else {
                                buf[sizeof(buf) - 1] = '\0';
@@ -150,14 +187,14 @@ lws_callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
 static struct lws_protocols protocols[] = {
        /* first protocol must always be HTTP handler */
 
-       { "http-only", lws_callback_http, 0, 0, },
+       { "http-only", lws_callback_http, 0, 0, 0, NULL, 0 },
 #if defined(LWS_ROLE_WS)
        LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
        LWS_PLUGIN_PROTOCOL_MIRROR,
        LWS_PLUGIN_PROTOCOL_LWS_STATUS,
-       LWS_PLUGIN_PROTOCOL_POST_DEMO,
 #endif
-       { NULL, NULL, 0, 0 } /* terminator */
+       LWS_PLUGIN_PROTOCOL_POST_DEMO,
+       LWS_PROTOCOL_LIST_TERM
 };
 
 
@@ -206,6 +243,7 @@ void sighandler(int sig)
        lws_cancel_service(context);
 }
 
+#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
 static const struct lws_extension exts[] = {
        {
                "permessage-deflate",
@@ -214,15 +252,18 @@ static const struct lws_extension exts[] = {
        },
        { NULL, NULL, NULL /* terminator */ }
 };
+#endif
 
 /*
- * mount handlers for sections of the URL space
+ * mount a filesystem directory into the URL space at /
+ * point it to our /usr/share directory with our assets in
+ * stuff from here is autoserved by the library
  */
 
-static const struct lws_http_mount mount_ziptest = {
+static const struct lws_http_mount mount_ziptest_uncomm = {
        NULL,                   /* linked-list pointer to next*/
-       "/ziptest",             /* mountpoint in URL namespace on this vhost */
-       LOCAL_RESOURCE_PATH"/candide.zip",      /* handler */
+       "/uncommziptest",               /* mountpoint in URL namespace on this vhost */
+       LOCAL_RESOURCE_PATH"/candide-uncompressed.zip", /* handler */
        NULL,   /* default filename if none given */
        NULL,
        NULL,
@@ -235,16 +276,12 @@ static const struct lws_http_mount mount_ziptest = {
        0,
        0,
        LWSMPRO_FILE,   /* origin points to a callback */
-       8,                      /* strlen("/ziptest"), ie length of the mountpoint */
+       14,                     /* strlen("/ziptest"), ie length of the mountpoint */
        NULL,
-
-       { NULL, NULL } // sentinel
-};
-
-static const struct lws_http_mount mount_post = {
-       (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/
-       "/formtest",            /* mountpoint in URL namespace on this vhost */
-       "protocol-post-demo",   /* handler */
+}, mount_ziptest = {
+       (struct lws_http_mount *)&mount_ziptest_uncomm,                 /* linked-list pointer to next*/
+       "/ziptest",             /* mountpoint in URL namespace on this vhost */
+       LOCAL_RESOURCE_PATH"/candide.zip",      /* handler */
        NULL,   /* default filename if none given */
        NULL,
        NULL,
@@ -256,24 +293,14 @@ static const struct lws_http_mount mount_post = {
        0,
        0,
        0,
-       LWSMPRO_CALLBACK,       /* origin points to a callback */
-       9,                      /* strlen("/formtest"), ie length of the mountpoint */
+       LWSMPRO_FILE,   /* origin points to a callback */
+       8,                      /* strlen("/ziptest"), ie length of the mountpoint */
        NULL,
-
-       { NULL, NULL } // sentinel
-};
-
-/*
- * mount a filesystem directory into the URL space at /
- * point it to our /usr/share directory with our assets in
- * stuff from here is autoserved by the library
- */
-
-static const struct lws_http_mount mount = {
-       (struct lws_http_mount *)&mount_post,   /* linked-list pointer to next*/
-       "/",            /* mountpoint in URL namespace on this vhost */
-       LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */
-       "test.html",    /* default filename if none given */
+}, mount_post = {
+       (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/
+       "/formtest",            /* mountpoint in URL namespace on this vhost */
+       "protocol-post-demo",   /* handler */
+       NULL,   /* default filename if none given */
        NULL,
        NULL,
        NULL,
@@ -284,13 +311,30 @@ static const struct lws_http_mount mount = {
        0,
        0,
        0,
-       LWSMPRO_FILE,   /* mount type is a directory in a filesystem */
-       1,              /* strlen("/"), ie length of the mountpoint */
+       LWSMPRO_CALLBACK,       /* origin points to a callback */
+       9,                      /* strlen("/formtest"), ie length of the mountpoint */
        NULL,
-
-       { NULL, NULL } // sentinel
+}, mount = {
+       /* .mount_next */               &mount_post,    /* linked-list "next" */
+       /* .mountpoint */               "/",            /* mountpoint URL */
+       /* .origin */                   LOCAL_RESOURCE_PATH, /* serve from dir */
+       /* .def */                      "test.html",    /* default filename */
+       /* .protocol */                 NULL,
+       /* .cgienv */                   NULL,
+       /* .extra_mimetypes */          NULL,
+       /* .interpret */                NULL,
+       /* .cgi_timeout */              0,
+       /* .cache_max_age */            0,
+       /* .auth_mask */                0,
+       /* .cache_reusable */           0,
+       /* .cache_revalidate */         0,
+       /* .cache_intermediaries */     0,
+       /* .origin_protocol */          LWSMPRO_FILE,   /* files in a dir */
+       /* .mountpoint_len */           1,              /* char count */
+       /* .basic_auth_login_file */    NULL,
 };
 
+
 static const struct lws_protocol_vhost_options pvo_options = {
        NULL,
        NULL,
@@ -298,11 +342,37 @@ static const struct lws_protocol_vhost_options pvo_options = {
        (void *)&test_options   /* pvo value */
 };
 
-static const struct lws_protocol_vhost_options pvo = {
-       NULL,                           /* "next" pvo linked-list */
-       &pvo_options,           /* "child" pvo linked-list */
-       "dumb-increment-protocol",      /* protocol name we belong to on this vhost */
-       ""                              /* ignored */
+/*
+ * If we don't give any pvos, then for backwards compatibility all protocols
+ * are enabled on all vhosts.  If we give any pvos, then we must list in them
+ * the protocol names we want to enable, protocols that are not listed in the
+ * pvos are not instantiated on the vhost then.
+ */
+
+static const struct lws_protocol_vhost_options
+       pvo3 = {
+               NULL,                           /* "next" pvo linked-list */
+               NULL,
+               "protocol-post-demo",   /* protocol name we belong to on this vhost */
+               ""                              /* not needed */
+       },
+       pvo2 = {
+               &pvo3,                          /* "next" pvo linked-list */
+               NULL,
+               "lws-status",   /* protocol name we belong to on this vhost */
+               ""                              /* not needed */
+       },
+       pvo1 = {
+               &pvo2,                          /* "next" pvo linked-list */
+               NULL,
+               "lws-mirror-protocol",  /* protocol name we belong to on this vhost */
+               ""                              /* not needed */
+       },
+       pvo = {
+               &pvo1,                          /* "next" pvo linked-list */
+               &pvo_options,           /* "child" pvo linked-list */
+               "dumb-increment-protocol",      /* protocol name we belong to on this vhost */
+               ""                              /* not needed */
 };
 
 #if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)
@@ -317,6 +387,7 @@ static struct option options[] = {
        { "ssl-cert",  required_argument,       NULL, 'C' },
        { "ssl-key",  required_argument,        NULL, 'K' },
        { "ssl-ca",  required_argument,         NULL, 'A' },
+       { "resource-path",  required_argument,          NULL, 'r' },
 #if defined(LWS_WITH_TLS)
        { "ssl-verify-client",  no_argument,            NULL, 'v' },
 #if defined(LWS_HAVE_SSL_CTX_set1_param)
@@ -328,11 +399,17 @@ static struct option options[] = {
 #ifndef LWS_NO_DAEMONIZE
        { "daemonize",  no_argument,            NULL, 'D' },
 #endif
-       { "pingpong-secs", required_argument,   NULL, 'P' },
+       { "ignore-sigterm", no_argument,        NULL, 'I' },
+
        { NULL, 0, 0, 0 }
 };
 #endif
 
+static void
+sigterm_catch(int sig)
+{
+}
+
 int main(int argc, char **argv)
 {
        struct lws_context_creation_info info;
@@ -342,14 +419,14 @@ int main(int argc, char **argv)
        char cert_path[1024] = "";
        char key_path[1024] = "";
        char ca_path[1024] = "";
-       int uid = -1, gid = -1;
-       int use_ssl = 0;
-       int pp_secs = 0;
-       int opts = 0;
-       int n = 0;
 #ifndef LWS_NO_DAEMONIZE
        int daemonize = 0;
 #endif
+       uint64_t opts = 0;
+       int use_ssl = 0;
+       uid_t uid = (uid_t)-1;
+       gid_t gid = (gid_t)-1;
+       int n = 0;
 
        /*
         * take care to zero down the info struct, he contains random garbaage
@@ -360,9 +437,9 @@ int main(int argc, char **argv)
 
        while (n >= 0) {
 #if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)
-               n = getopt_long(argc, argv, "eci:hsap:d:DC:K:A:R:vu:g:P:kU:n", options, NULL);
+               n = getopt_long(argc, argv, "eci:hsap:d:DC:K:A:R:vu:g:kU:niIr:", options, NULL);
 #else
-               n = getopt(argc, argv, "eci:hsap:d:DC:K:A:R:vu:g:P:kU:n");
+               n = getopt(argc, argv, "eci:hsap:d:DC:K:A:R:vu:g:kU:nIr:");
 #endif
                if (n < 0)
                        continue;
@@ -376,10 +453,10 @@ int main(int argc, char **argv)
                        break;
 #endif
                case 'u':
-                       uid = atoi(optarg);
+                       uid = (uid_t)atoi(optarg);
                        break;
                case 'g':
-                       gid = atoi(optarg);
+                       gid = (gid_t)atoi(optarg);
                        break;
                case 'd':
                        debug_level = atoi(optarg);
@@ -388,6 +465,12 @@ int main(int argc, char **argv)
                        /* no dumb increment send */
                        test_options |= 1;
                        break;
+               case 'I':
+                       signal(SIGTERM, sigterm_catch);
+                       break;
+               case 'r':
+                       resource_path = optarg;
+                       break;
                case 's':
                        use_ssl = 1;
                        opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
@@ -429,10 +512,6 @@ int main(int argc, char **argv)
                case 'A':
                        lws_strncpy(ca_path, optarg, sizeof(ca_path));
                        break;
-               case 'P':
-                       pp_secs = atoi(optarg);
-                       lwsl_notice("Setting pingpong interval to %d\n", pp_secs);
-                       break;
 #if defined(LWS_WITH_TLS)
                case 'v':
                        use_ssl = 1;
@@ -475,7 +554,7 @@ int main(int argc, char **argv)
        /* tell the library what debug level to emit and to send it to stderr */
        lws_set_log_level(debug_level, NULL);
 
-       lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n");
+       lwsl_notice("libwebsockets test server - license MIT\n");
        lwsl_notice("(C) Copyright 2010-2018 Andy Green <andy@warmcat.com>\n");
 
        printf("Using resource path \"%s\"\n", resource_path);
@@ -485,19 +564,23 @@ int main(int argc, char **argv)
 #else
        max_poll_elements = sysconf(_SC_OPEN_MAX);
 #endif
-       pollfds = malloc(max_poll_elements * sizeof (struct lws_pollfd));
-       fd_lookup = malloc(max_poll_elements * sizeof (int));
+       pollfds = malloc((unsigned int)max_poll_elements * sizeof (struct lws_pollfd));
+       fd_lookup = malloc((unsigned int)max_poll_elements * sizeof (int));
        if (pollfds == NULL || fd_lookup == NULL) {
                lwsl_err("Out of memory pollfds=%d\n", max_poll_elements);
                return -1;
        }
+       for (n = 0; n < max_poll_elements; n++)
+               pollfds[n].fd = LWS_SOCK_INVALID;
+       count_pollfds = 0;
 #endif
 
        info.iface = iface;
        info.protocols = protocols;
+
+#if defined(LWS_WITH_TLS)
        info.ssl_cert_filepath = NULL;
        info.ssl_private_key_filepath = NULL;
-       info.ws_ping_pong_interval = pp_secs;
 
        if (use_ssl) {
                if (strlen(resource_path) > sizeof(cert_path) - 32) {
@@ -514,17 +597,22 @@ int main(int argc, char **argv)
                if (!key_path[0])
                        sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
                                                                resource_path);
-
+#if defined(LWS_WITH_TLS)
                info.ssl_cert_filepath = cert_path;
                info.ssl_private_key_filepath = key_path;
                if (ca_path[0])
                        info.ssl_ca_filepath = ca_path;
+#endif
        }
+#endif
        info.gid = gid;
        info.uid = uid;
        info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
+#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
        info.extensions = exts;
+#endif
        info.timeout_secs = 5;
+#if defined(LWS_WITH_TLS)
        info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
                               "ECDHE-RSA-AES256-GCM-SHA384:"
                               "DHE-RSA-AES256-GCM-SHA384:"
@@ -538,9 +626,12 @@ int main(int argc, char **argv)
                               "!DHE-RSA-AES256-SHA256:"
                               "!AES256-GCM-SHA384:"
                               "!AES256-SHA256";
+#endif
        info.mounts = &mount;
-       info.ip_limit_ah = 24; /* for testing */
-       info.ip_limit_wsi = 400; /* for testing */
+#if defined(LWS_WITH_PEER_LIMITS)
+       info.ip_limit_ah = 128; /* for testing */
+       info.ip_limit_wsi = 800; /* for testing */
+#endif
 
        if (use_ssl)
                /* redirect guys coming on http */
@@ -568,7 +659,7 @@ int main(int argc, char **argv)
 
        info.port++;
 
-#if !defined(LWS_NO_CLIENT) && defined(LWS_WITH_TLS)
+#if defined(LWS_WITH_CLIENT) && defined(LWS_WITH_TLS)
        lws_init_vhost_client_ssl(&info, vhost);
 #endif
 
@@ -598,7 +689,11 @@ int main(int argc, char **argv)
                 * this represents an existing server's single poll action
                 * which also includes libwebsocket sockets
                 */
-               n = poll(pollfds, count_pollfds, 50);
+
+               /* if needed, force-service wsis that may not have read all input */
+               n = lws_service_adjust_timeout(context, 5000, 0);
+
+               n = poll(pollfds, (nfds_t)count_pollfds, n);
                if (n < 0)
                        continue;
 
@@ -611,15 +706,11 @@ int main(int argc, char **argv)
                                        * control
                                        */
                                        if (lws_service_fd(context,
-                                                                 &pollfds[n]) < 0)
+                                                          &pollfds[n]) < 0)
                                                goto done;
-
-                       /* if needed, force-service wsis that may not have read all input */
-                       while (!lws_service_adjust_timeout(context, 1, 0)) {
-                               lwsl_notice("extpoll doing forced service!\n");
-                               lws_service_tsi(context, -1, 0);
-                       }
                }
+
+               lws_service_tsi(context, -1, 0);
 #else
                /*
                 * If libwebsockets sockets are all we care about,
index 69d831e..fad5cf4 100644 (file)
@@ -33,7 +33,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <signal.h>
-
+#include <errno.h>
 /* import the whole of lws-plugin-sshd-base statically */
 #include <lws-plugin-sshd-static-build-includes.h>
 
  * The /etc path is the only reason we have to run as root.
  */
 #define TEST_SERVER_KEY_PATH "/etc/lws-test-sshd-server-key"
+struct per_vhost_data__lws_sshd_demo {
+       const struct lws_protocols *ssh_base_protocol;
+       int privileged_fd;
+};
+
 
 /*
  *  This is a copy of the lws ssh test public key, you can find it in
@@ -241,7 +246,7 @@ ssh_ops_get_server_key(struct lws *wsi, uint8_t *buf, size_t len)
                return 0;
        }
 
-       n = read(fd, buf, len);
+       n = (int)read(fd, buf, len);
        if (n < 0) {
                lwsl_err("%s: read failed: %d\n", __func__, n);
                n = 0;
@@ -249,7 +254,7 @@ ssh_ops_get_server_key(struct lws *wsi, uint8_t *buf, size_t len)
 
        close(fd);
 
-       return n;
+       return (size_t)n;
 }
 
 static size_t
@@ -266,7 +271,7 @@ ssh_ops_set_server_key(struct lws *wsi, uint8_t *buf, size_t len)
                return 0;
        }
 
-       n = write(fd, buf, len);
+       n = (int)write(fd, buf, len);
        if (n < 0) {
                lwsl_err("%s: read failed: %d\n", __func__, errno);
                n = 0;
@@ -274,7 +279,7 @@ ssh_ops_set_server_key(struct lws *wsi, uint8_t *buf, size_t len)
 
        close(fd);
 
-       return n;
+       return (size_t)n;
 }
 
 /* ops: auth */
@@ -284,7 +289,7 @@ ssh_ops_is_pubkey_authorized(const char *username, const char *type,
                                 const uint8_t *peer, int peer_len)
 {
        char *aps, *p, *ps;
-       int n = strlen(type), alen = 2048, ret = 2, len;
+       int n = (int)strlen(type), alen = 2048, ret = 2, len;
        size_t s = 0;
 
        lwsl_info("%s: checking pubkey for %s\n", __func__, username);
@@ -305,7 +310,7 @@ ssh_ops_is_pubkey_authorized(const char *username, const char *type,
        }
        p = aps;
 
-       if (strncmp(p, type, n)) {
+       if (strncmp(p, type, (unsigned int)n)) {
                lwsl_notice("lead-in string  does not match %s\n", type);
                goto bail_p1;
        }
@@ -318,7 +323,7 @@ ssh_ops_is_pubkey_authorized(const char *username, const char *type,
 
 
        p++;
-       ps = malloc(alen);
+       ps = malloc((unsigned int)alen);
        if (!ps) {
                lwsl_notice("OOM 2\n");
                free(aps);
@@ -342,7 +347,7 @@ ssh_ops_is_pubkey_authorized(const char *username, const char *type,
         * <len32>E<len32>N that the peer sends us
         */
 
-       if (lws_timingsafe_bcmp(peer, ps, peer_len)) {
+       if (lws_timingsafe_bcmp(peer, ps, (uint32_t)peer_len)) {
                lwsl_info("factors mismatch\n");
                goto bail;
        }
@@ -425,10 +430,10 @@ ssh_ops_pty_req(void *_priv, struct lws_ssh_pty *pty)
                        break;
                opc = *p++;
 
-               arg = *p++ << 24;
-               arg |= *p++ << 16;
-               arg |= *p++ << 8;
-               arg |= *p++;
+               arg = (uint32_t)(*p++ << 24);
+               arg |= (uint32_t)(*p++ << 16);
+               arg |= (uint32_t)(*p++ << 8);
+               arg |= (uint32_t)(*p++);
 
                lwsl_debug("pty opc %d: 0x%x\n", opc, arg);
 
@@ -483,7 +488,7 @@ ssh_ops_child_process_io(void *_priv, struct lws *wsi,
                        uint8_t buf[256], *p, *d;
 
                        if (bytes != 1)
-                               n = bytes / 2;
+                               n = (int)(bytes / 2);
                        else
                                n = 1;
                        if (n > (int)sizeof(buf))
@@ -495,7 +500,7 @@ ssh_ops_child_process_io(void *_priv, struct lws *wsi,
                        m = lws_get_socket_fd(args->stdwsi[args->ch]);
                        if (m < 0)
                                return -1;
-                       n = read(m, buf, n);
+                       n = (int)read(m, buf, (unsigned int)n);
                        if (n < 0)
                                return -1;
                        if (n == 0) {
@@ -515,7 +520,7 @@ ssh_ops_child_process_io(void *_priv, struct lws *wsi,
 
                                *p++ = *d++;
                        }
-                       n = (void *)p - rp;
+                       n = lws_ptr_diff((void *)p, rp);
                        if (n < (int)bytes && priv->insert_lf) {
                                priv->insert_lf = 0;
                                *p++ = 0x0d;
@@ -525,14 +530,14 @@ ssh_ops_child_process_io(void *_priv, struct lws *wsi,
                        n = lws_get_socket_fd(args->stdwsi[args->ch]);
                        if (n < 0)
                                return -1;
-                       n = read(n, rp, bytes);
+                       n = (int)read(n, rp, bytes);
                        if (n < 0)
                                return -1;
                }
 
                lws_rx_flow_control(args->stdwsi[args->ch], 0);
 
-               lws_ring_bump_head(r, n);
+               lws_ring_bump_head(r, (unsigned int)n);
                lws_callback_on_writable(wsi);
                break;
        }
@@ -584,11 +589,11 @@ ssh_ops_banner(char *buf, size_t max_len, char *lang, size_t max_lang_len)
        int n = lws_snprintf(buf, max_len, "\n"
                      " |\\---/|  lws-ssh Test Server\n"
                      " | o_o |  SSH Terminal Server\n"
-                     "  \\_^_/   Copyright (C) 2017 Crash Barrier Ltd\n\n");
+                     "  \\_^_/   Copyright (C) 2017-2020 Crash Barrier Ltd\n\n");
 
        lws_snprintf(lang, max_lang_len, "en/US");
 
-       return n;
+       return (size_t)n;
 }
 
 static void
@@ -645,6 +650,85 @@ void sighandler(int sig)
        lws_cancel_service(context);
 }
 
+static int
+callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason,
+                      void *user, void *in, size_t len)
+{
+       struct per_vhost_data__lws_sshd_demo *vhd =
+                       (struct per_vhost_data__lws_sshd_demo *)
+                       lws_protocol_vh_priv_get(lws_get_vhost(wsi),
+                                                lws_get_protocol(wsi));
+
+       switch (reason) {
+       case LWS_CALLBACK_PROTOCOL_INIT:
+               vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
+                                                 lws_get_protocol(wsi),
+                               sizeof(struct per_vhost_data__lws_sshd_demo));
+               if (!vhd)
+                       return 0;
+               /*
+                * During this we still have the privs / caps we were started
+                * with.  So open an fd on the server key, either just for read
+                * or for creat / trunc if doesn't exist.  This allows us to
+                * deal with it down /etc/.. when just after this we will lose
+                * the privileges needed to read / write /etc/...
+                */
+               vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH, O_RDONLY);
+               if (vhd->privileged_fd == -1)
+                       vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH,
+                                       O_CREAT | O_TRUNC | O_RDWR, 0600);
+               if (vhd->privileged_fd == -1) {
+                       lwsl_warn("%s: Can't open %s\n", __func__,
+                                TEST_SERVER_KEY_PATH);
+                       return 0;
+               }
+               break;
+
+       case LWS_CALLBACK_PROTOCOL_DESTROY:
+               if (vhd)
+                       close(vhd->privileged_fd);
+               break;
+
+       case LWS_CALLBACK_VHOST_CERT_AGING:
+               break;
+
+       case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
+               break;
+
+       default:
+               if (!vhd->ssh_base_protocol) {
+                       vhd->ssh_base_protocol = lws_vhost_name_to_protocol(
+                                                       lws_get_vhost(wsi),
+                                                       "lws-ssh-base");
+                       if (vhd->ssh_base_protocol)
+                               user = lws_adjust_protocol_psds(wsi,
+                               vhd->ssh_base_protocol->per_session_data_size);
+               }
+
+               if (vhd->ssh_base_protocol)
+                       return vhd->ssh_base_protocol->callback(wsi, reason,
+                                                               user, in, len);
+               else
+                       lwsl_notice("can't find lws-ssh-base\n");
+               break;
+       }
+
+       return 0;
+}
+
+
+const struct lws_protocols lws_sshd_demo_protocols[] = {
+       {
+               "lws-sshd-demo",
+               callback_lws_sshd_demo,
+               0,
+               1024, /* rx buf size must be >= permessage-deflate rx size */
+               0, (void *)&ssh_ops, 0
+       }
+
+};
+
+
 int main()
 {
        static struct lws_context_creation_info info;
@@ -677,7 +761,7 @@ int main()
        info.port = 2200;
        info.options = LWS_SERVER_OPTION_ONLY_RAW;
        info.vhost_name = "sshd";
-       info.protocols = protocols_sshd;
+       info.protocols = lws_sshd_demo_protocols;
        info.pvo = &pvo_ssh;
 
        vh_sshd = lws_create_vhost(context, &info);
diff --git a/win32port/dirent/dirent-win32.h b/win32port/dirent/dirent-win32.h
new file mode 100644 (file)
index 0000000..f7a46da
--- /dev/null
@@ -0,0 +1,1160 @@
+/*
+ * Dirent interface for Microsoft Visual Studio
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#ifndef DIRENT_H
+#define DIRENT_H
+
+/* Hide warnings about unreferenced local functions */
+#if defined(__clang__)
+#   pragma clang diagnostic ignored "-Wunused-function"
+#elif defined(_MSC_VER)
+#   pragma warning(disable:4505)
+#elif defined(__GNUC__)
+#   pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+/*
+ * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
+ * Windows Sockets 2.0.
+ */
+#ifndef WIN32_LEAN_AND_MEAN
+#   define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+/* Indicates that d_type field is available in dirent structure */
+#define _DIRENT_HAVE_D_TYPE
+
+/* Indicates that d_namlen field is available in dirent structure */
+#define _DIRENT_HAVE_D_NAMLEN
+
+/* Entries missing from MSVC 6.0 */
+#if !defined(FILE_ATTRIBUTE_DEVICE)
+#   define FILE_ATTRIBUTE_DEVICE 0x40
+#endif
+
+/* File type and permission flags for stat(), general mask */
+#if !defined(S_IFMT)
+#   define S_IFMT _S_IFMT
+#endif
+
+/* Directory bit */
+#if !defined(S_IFDIR)
+#   define S_IFDIR _S_IFDIR
+#endif
+
+/* Character device bit */
+#if !defined(S_IFCHR)
+#   define S_IFCHR _S_IFCHR
+#endif
+
+/* Pipe bit */
+#if !defined(S_IFFIFO)
+#   define S_IFFIFO _S_IFFIFO
+#endif
+
+/* Regular file bit */
+#if !defined(S_IFREG)
+#   define S_IFREG _S_IFREG
+#endif
+
+/* Read permission */
+#if !defined(S_IREAD)
+#   define S_IREAD _S_IREAD
+#endif
+
+/* Write permission */
+#if !defined(S_IWRITE)
+#   define S_IWRITE _S_IWRITE
+#endif
+
+/* Execute permission */
+#if !defined(S_IEXEC)
+#   define S_IEXEC _S_IEXEC
+#endif
+
+/* Pipe */
+#if !defined(S_IFIFO)
+#   define S_IFIFO _S_IFIFO
+#endif
+
+/* Block device */
+#if !defined(S_IFBLK)
+#   define S_IFBLK 0
+#endif
+
+/* Link */
+#if !defined(S_IFLNK)
+#   define S_IFLNK 0
+#endif
+
+/* Socket */
+#if !defined(S_IFSOCK)
+#   define S_IFSOCK 0
+#endif
+
+/* Read user permission */
+#if !defined(S_IRUSR)
+#   define S_IRUSR S_IREAD
+#endif
+
+/* Write user permission */
+#if !defined(S_IWUSR)
+#   define S_IWUSR S_IWRITE
+#endif
+
+/* Execute user permission */
+#if !defined(S_IXUSR)
+#   define S_IXUSR 0
+#endif
+
+/* Read group permission */
+#if !defined(S_IRGRP)
+#   define S_IRGRP 0
+#endif
+
+/* Write group permission */
+#if !defined(S_IWGRP)
+#   define S_IWGRP 0
+#endif
+
+/* Execute group permission */
+#if !defined(S_IXGRP)
+#   define S_IXGRP 0
+#endif
+
+/* Read others permission */
+#if !defined(S_IROTH)
+#   define S_IROTH 0
+#endif
+
+/* Write others permission */
+#if !defined(S_IWOTH)
+#   define S_IWOTH 0
+#endif
+
+/* Execute others permission */
+#if !defined(S_IXOTH)
+#   define S_IXOTH 0
+#endif
+
+/* Maximum length of file name */
+#if !defined(PATH_MAX)
+#   define PATH_MAX MAX_PATH
+#endif
+#if !defined(FILENAME_MAX)
+#   define FILENAME_MAX MAX_PATH
+#endif
+#if !defined(NAME_MAX)
+#   define NAME_MAX FILENAME_MAX
+#endif
+
+/* File type flags for d_type */
+#define DT_UNKNOWN 0
+#define DT_REG S_IFREG
+#define DT_DIR S_IFDIR
+#define DT_FIFO S_IFIFO
+#define DT_SOCK S_IFSOCK
+#define DT_CHR S_IFCHR
+#define DT_BLK S_IFBLK
+#define DT_LNK S_IFLNK
+
+/* Macros for converting between st_mode and d_type */
+#define IFTODT(mode) ((mode) & S_IFMT)
+#define DTTOIF(type) (type)
+
+/*
+ * File type macros.  Note that block devices, sockets and links cannot be
+ * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
+ * only defined for compatibility.  These macros should always return false
+ * on Windows.
+ */
+#if !defined(S_ISFIFO)
+#   define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISDIR)
+#   define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG)
+#   define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISLNK)
+#   define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK)
+#   define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISCHR)
+#   define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISBLK)
+#   define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+#endif
+
+/* Return the exact length of the file name without zero terminator */
+#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
+
+/* Return the maximum size of a file name */
+#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Wide-character version */
+struct _wdirent {
+    /* Always zero */
+    long d_ino;
+
+    /* File position within stream */
+    long d_off;
+
+    /* Structure size */
+    unsigned short d_reclen;
+
+    /* Length of name without \0 */
+    size_t d_namlen;
+
+    /* File type */
+    int d_type;
+
+    /* File name */
+    wchar_t d_name[PATH_MAX+1];
+};
+typedef struct _wdirent _wdirent;
+
+struct _WDIR {
+    /* Current directory entry */
+    struct _wdirent ent;
+
+    /* Private file data */
+    WIN32_FIND_DATAW data;
+
+    /* True if data is valid */
+    int cached;
+
+    /* Win32 search handle */
+    HANDLE handle;
+
+    /* Initial directory name */
+    wchar_t *patt;
+};
+typedef struct _WDIR _WDIR;
+
+/* Multi-byte character version */
+struct dirent {
+    /* Always zero */
+    long d_ino;
+
+    /* File position within stream */
+    long d_off;
+
+    /* Structure size */
+    unsigned short d_reclen;
+
+    /* Length of name without \0 */
+    size_t d_namlen;
+
+    /* File type */
+    int d_type;
+
+    /* File name */
+    char d_name[PATH_MAX+1];
+};
+typedef struct dirent dirent;
+
+struct DIR {
+    struct dirent ent;
+    struct _WDIR *wdirp;
+};
+typedef struct DIR DIR;
+
+
+/* Dirent functions */
+static DIR *opendir (const char *dirname);
+static _WDIR *_wopendir (const wchar_t *dirname);
+
+static struct dirent *readdir (DIR *dirp);
+static struct _wdirent *_wreaddir (_WDIR *dirp);
+
+static int readdir_r(
+    DIR *dirp, struct dirent *entry, struct dirent **result);
+static int _wreaddir_r(
+    _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
+
+static int closedir (DIR *dirp);
+static int _wclosedir (_WDIR *dirp);
+
+static void rewinddir (DIR* dirp);
+static void _wrewinddir (_WDIR* dirp);
+
+static int scandir (const char *dirname, struct dirent ***namelist,
+    int (*filter)(const struct dirent*),
+    int (*compare)(const struct dirent**, const struct dirent**));
+
+static int alphasort (const struct dirent **a, const struct dirent **b);
+
+static int versionsort (const struct dirent **a, const struct dirent **b);
+
+
+/* For compatibility with Symbian */
+#define wdirent _wdirent
+#define WDIR _WDIR
+#define wopendir _wopendir
+#define wreaddir _wreaddir
+#define wclosedir _wclosedir
+#define wrewinddir _wrewinddir
+
+
+/* Internal utility functions */
+static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
+static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
+
+static int dirent_mbstowcs_s(
+    size_t *pReturnValue,
+    wchar_t *wcstr,
+    size_t sizeInWords,
+    const char *mbstr,
+    size_t count);
+
+static int dirent_wcstombs_s(
+    size_t *pReturnValue,
+    char *mbstr,
+    size_t sizeInBytes,
+    const wchar_t *wcstr,
+    size_t count);
+
+static void dirent_set_errno (int error);
+
+
+/*
+ * Open directory stream DIRNAME for read and return a pointer to the
+ * internal working area that is used to retrieve individual directory
+ * entries.
+ */
+static _WDIR*
+_wopendir(
+    const wchar_t *dirname)
+{
+    _WDIR *dirp;
+    DWORD n;
+    wchar_t *p;
+
+    /* Must have directory name */
+    if (dirname == NULL  ||  dirname[0] == '\0') {
+        dirent_set_errno (ENOENT);
+        return NULL;
+    }
+
+    /* Allocate new _WDIR structure */
+    dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
+    if (!dirp) {
+        return NULL;
+    }
+
+    /* Reset _WDIR structure */
+    dirp->handle = INVALID_HANDLE_VALUE;
+    dirp->patt = NULL;
+    dirp->cached = 0;
+
+    /*
+     * Compute the length of full path plus zero terminator
+     *
+     * Note that on WinRT there's no way to convert relative paths
+     * into absolute paths, so just assume it is an absolute path.
+     */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+    /* Desktop */
+    n = GetFullPathNameW (dirname, 0, NULL, NULL);
+#else
+    /* WinRT */
+    n = wcslen (dirname);
+#endif
+
+    /* Allocate room for absolute directory name and search pattern */
+    dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
+    if (dirp->patt == NULL) {
+        goto exit_closedir;
+    }
+
+    /*
+     * Convert relative directory name to an absolute one.  This
+     * allows rewinddir() to function correctly even when current
+     * working directory is changed between opendir() and rewinddir().
+     *
+     * Note that on WinRT there's no way to convert relative paths
+     * into absolute paths, so just assume it is an absolute path.
+     */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+    /* Desktop */
+    n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
+    if (n <= 0) {
+        goto exit_closedir;
+    }
+#else
+    /* WinRT */
+    wcsncpy_s (dirp->patt, n+1, dirname, n);
+#endif
+
+    /* Append search pattern \* to the directory name */
+    p = dirp->patt + n;
+    switch (p[-1]) {
+    case '\\':
+    case '/':
+    case ':':
+        /* Directory ends in path separator, e.g. c:\temp\ */
+        /*NOP*/;
+        break;
+
+    default:
+        /* Directory name doesn't end in path separator */
+        *p++ = '\\';
+    }
+    *p++ = '*';
+    *p = '\0';
+
+    /* Open directory stream and retrieve the first entry */
+    if (!dirent_first (dirp)) {
+        goto exit_closedir;
+    }
+
+    /* Success */
+    return dirp;
+
+    /* Failure */
+exit_closedir:
+    _wclosedir (dirp);
+    return NULL;
+}
+
+/*
+ * Read next directory entry.
+ *
+ * Returns pointer to static directory entry which may be overwritten by
+ * subsequent calls to _wreaddir().
+ */
+static struct _wdirent*
+_wreaddir(
+    _WDIR *dirp)
+{
+    struct _wdirent *entry;
+
+    /*
+     * Read directory entry to buffer.  We can safely ignore the return value
+     * as entry will be set to NULL in case of error.
+     */
+    (void) _wreaddir_r (dirp, &dirp->ent, &entry);
+
+    /* Return pointer to statically allocated directory entry */
+    return entry;
+}
+
+/*
+ * Read next directory entry.
+ *
+ * Returns zero on success.  If end of directory stream is reached, then sets
+ * result to NULL and returns zero.
+ */
+static int
+_wreaddir_r(
+    _WDIR *dirp,
+    struct _wdirent *entry,
+    struct _wdirent **result)
+{
+    WIN32_FIND_DATAW *datap;
+
+    /* Read next directory entry */
+    datap = dirent_next (dirp);
+    if (datap) {
+        size_t n;
+        DWORD attr;
+
+        /*
+         * Copy file name as wide-character string.  If the file name is too
+         * long to fit in to the destination buffer, then truncate file name
+         * to PATH_MAX characters and zero-terminate the buffer.
+         */
+        n = 0;
+        while (n < PATH_MAX  &&  datap->cFileName[n] != 0) {
+            entry->d_name[n] = datap->cFileName[n];
+            n++;
+        }
+        entry->d_name[n] = 0;
+
+        /* Length of file name excluding zero terminator */
+        entry->d_namlen = n;
+
+        /* File type */
+        attr = datap->dwFileAttributes;
+        if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+            entry->d_type = DT_CHR;
+        } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+            entry->d_type = DT_DIR;
+        } else {
+            entry->d_type = DT_REG;
+        }
+
+        /* Reset dummy fields */
+        entry->d_ino = 0;
+        entry->d_off = 0;
+        entry->d_reclen = sizeof (struct _wdirent);
+
+        /* Set result address */
+        *result = entry;
+
+    } else {
+
+        /* Return NULL to indicate end of directory */
+        *result = NULL;
+
+    }
+
+    return /*OK*/0;
+}
+
+/*
+ * Close directory stream opened by opendir() function.  This invalidates the
+ * DIR structure as well as any directory entry read previously by
+ * _wreaddir().
+ */
+static int
+_wclosedir(
+    _WDIR *dirp)
+{
+    int ok;
+    if (dirp) {
+
+        /* Release search handle */
+        if (dirp->handle != INVALID_HANDLE_VALUE) {
+            FindClose (dirp->handle);
+        }
+
+        /* Release search pattern */
+        free (dirp->patt);
+
+        /* Release directory structure */
+        free (dirp);
+        ok = /*success*/0;
+
+    } else {
+
+        /* Invalid directory stream */
+        dirent_set_errno (EBADF);
+        ok = /*failure*/-1;
+
+    }
+    return ok;
+}
+
+/*
+ * Rewind directory stream such that _wreaddir() returns the very first
+ * file name again.
+ */
+static void
+_wrewinddir(
+    _WDIR* dirp)
+{
+    if (dirp) {
+        /* Release existing search handle */
+        if (dirp->handle != INVALID_HANDLE_VALUE) {
+            FindClose (dirp->handle);
+        }
+
+        /* Open new search handle */
+        dirent_first (dirp);
+    }
+}
+
+/* Get first directory entry (internal) */
+static WIN32_FIND_DATAW*
+dirent_first(
+    _WDIR *dirp)
+{
+    WIN32_FIND_DATAW *datap;
+    DWORD error;
+
+    /* Open directory and retrieve the first entry */
+    dirp->handle = FindFirstFileExW(
+        dirp->patt, FindExInfoStandard, &dirp->data,
+        FindExSearchNameMatch, NULL, 0);
+    if (dirp->handle != INVALID_HANDLE_VALUE) {
+
+        /* a directory entry is now waiting in memory */
+        datap = &dirp->data;
+        dirp->cached = 1;
+
+    } else {
+
+        /* Failed to open directory: no directory entry in memory */
+        dirp->cached = 0;
+        datap = NULL;
+
+        /* Set error code */
+        error = GetLastError ();
+        switch (error) {
+        case ERROR_ACCESS_DENIED:
+            /* No read access to directory */
+            dirent_set_errno (EACCES);
+            break;
+
+        case ERROR_DIRECTORY:
+            /* Directory name is invalid */
+            dirent_set_errno (ENOTDIR);
+            break;
+
+        case ERROR_PATH_NOT_FOUND:
+        default:
+            /* Cannot find the file */
+            dirent_set_errno (ENOENT);
+        }
+
+    }
+    return datap;
+}
+
+/*
+ * Get next directory entry (internal).
+ *
+ * Returns
+ */
+static WIN32_FIND_DATAW*
+dirent_next(
+    _WDIR *dirp)
+{
+    WIN32_FIND_DATAW *p;
+
+    /* Get next directory entry */
+    if (dirp->cached != 0) {
+
+        /* A valid directory entry already in memory */
+        p = &dirp->data;
+        dirp->cached = 0;
+
+    } else if (dirp->handle != INVALID_HANDLE_VALUE) {
+
+        /* Get the next directory entry from stream */
+        if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
+            /* Got a file */
+            p = &dirp->data;
+        } else {
+            /* The very last entry has been processed or an error occurred */
+            FindClose (dirp->handle);
+            dirp->handle = INVALID_HANDLE_VALUE;
+            p = NULL;
+        }
+
+    } else {
+
+        /* End of directory stream reached */
+        p = NULL;
+
+    }
+
+    return p;
+}
+
+/*
+ * Open directory stream using plain old C-string.
+ */
+static DIR*
+opendir(
+    const char *dirname)
+{
+    struct DIR *dirp;
+
+    /* Must have directory name */
+    if (dirname == NULL  ||  dirname[0] == '\0') {
+        dirent_set_errno (ENOENT);
+        return NULL;
+    }
+
+    /* Allocate memory for DIR structure */
+    dirp = (DIR*) malloc (sizeof (struct DIR));
+    if (!dirp) {
+        return NULL;
+    }
+    {
+        int error;
+        wchar_t wname[PATH_MAX + 1];
+        size_t n;
+
+        /* Convert directory name to wide-character string */
+        error = dirent_mbstowcs_s(
+            &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
+        if (error) {
+            /*
+             * Cannot convert file name to wide-character string.  This
+             * occurs if the string contains invalid multi-byte sequences or
+             * the output buffer is too small to contain the resulting
+             * string.
+             */
+            goto exit_free;
+        }
+
+
+        /* Open directory stream using wide-character name */
+        dirp->wdirp = _wopendir (wname);
+        if (!dirp->wdirp) {
+            goto exit_free;
+        }
+
+    }
+
+    /* Success */
+    return dirp;
+
+    /* Failure */
+exit_free:
+    free (dirp);
+    return NULL;
+}
+
+/*
+ * Read next directory entry.
+ */
+static struct dirent*
+readdir(
+    DIR *dirp)
+{
+    struct dirent *entry;
+
+    /*
+     * Read directory entry to buffer.  We can safely ignore the return value
+     * as entry will be set to NULL in case of error.
+     */
+    (void) readdir_r (dirp, &dirp->ent, &entry);
+
+    /* Return pointer to statically allocated directory entry */
+    return entry;
+}
+
+/*
+ * Read next directory entry into called-allocated buffer.
+ *
+ * Returns zero on success.  If the end of directory stream is reached, then
+ * sets result to NULL and returns zero.
+ */
+static int
+readdir_r(
+    DIR *dirp,
+    struct dirent *entry,
+    struct dirent **result)
+{
+    WIN32_FIND_DATAW *datap;
+
+    /* Read next directory entry */
+    datap = dirent_next (dirp->wdirp);
+    if (datap) {
+        size_t n;
+        int error;
+
+        /* Attempt to convert file name to multi-byte string */
+        error = dirent_wcstombs_s(
+            &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
+
+        /*
+         * If the file name cannot be represented by a multi-byte string,
+         * then attempt to use old 8+3 file name.  This allows traditional
+         * Unix-code to access some file names despite of unicode
+         * characters, although file names may seem unfamiliar to the user.
+         *
+         * Be ware that the code below cannot come up with a short file
+         * name unless the file system provides one.  At least
+         * VirtualBox shared folders fail to do this.
+         */
+        if (error  &&  datap->cAlternateFileName[0] != '\0') {
+            error = dirent_wcstombs_s(
+                &n, entry->d_name, PATH_MAX + 1,
+                datap->cAlternateFileName, PATH_MAX + 1);
+        }
+
+        if (!error) {
+            DWORD attr;
+
+            /* Length of file name excluding zero terminator */
+            entry->d_namlen = n - 1;
+
+            /* File attributes */
+            attr = datap->dwFileAttributes;
+            if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+                entry->d_type = DT_CHR;
+            } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+                entry->d_type = DT_DIR;
+            } else {
+                entry->d_type = DT_REG;
+            }
+
+            /* Reset dummy fields */
+            entry->d_ino = 0;
+            entry->d_off = 0;
+            entry->d_reclen = sizeof (struct dirent);
+
+        } else {
+
+            /*
+             * Cannot convert file name to multi-byte string so construct
+             * an erroneous directory entry and return that.  Note that
+             * we cannot return NULL as that would stop the processing
+             * of directory entries completely.
+             */
+            entry->d_name[0] = '?';
+            entry->d_name[1] = '\0';
+            entry->d_namlen = 1;
+            entry->d_type = DT_UNKNOWN;
+            entry->d_ino = 0;
+            entry->d_off = -1;
+            entry->d_reclen = 0;
+
+        }
+
+        /* Return pointer to directory entry */
+        *result = entry;
+
+    } else {
+
+        /* No more directory entries */
+        *result = NULL;
+
+    }
+
+    return /*OK*/0;
+}
+
+/*
+ * Close directory stream.
+ */
+static int
+closedir(
+    DIR *dirp)
+{
+    int ok;
+    if (dirp) {
+
+        /* Close wide-character directory stream */
+        ok = _wclosedir (dirp->wdirp);
+        dirp->wdirp = NULL;
+
+        /* Release multi-byte character version */
+        free (dirp);
+
+    } else {
+
+        /* Invalid directory stream */
+        dirent_set_errno (EBADF);
+        ok = /*failure*/-1;
+
+    }
+    return ok;
+}
+
+/*
+ * Rewind directory stream to beginning.
+ */
+static void
+rewinddir(
+    DIR* dirp)
+{
+    /* Rewind wide-character string directory stream */
+    _wrewinddir (dirp->wdirp);
+}
+
+/*
+ * Scan directory for entries.
+ */
+static int
+scandir(
+    const char *dirname,
+    struct dirent ***namelist,
+    int (*filter)(const struct dirent*),
+    int (*compare)(const struct dirent**, const struct dirent**))
+{
+    struct dirent **files = NULL;
+    size_t size = 0;
+    size_t allocated = 0;
+    const size_t init_size = 1;
+    DIR *dir = NULL;
+    struct dirent *entry;
+    struct dirent *tmp = NULL;
+    size_t i;
+    int result = 0;
+
+    /* Open directory stream */
+    dir = opendir (dirname);
+    if (dir) {
+
+        /* Read directory entries to memory */
+        while (1) {
+
+            /* Enlarge pointer table to make room for another pointer */
+            if (size >= allocated) {
+                void *p;
+                size_t num_entries;
+
+                /* Compute number of entries in the enlarged pointer table */
+                if (size < init_size) {
+                    /* Allocate initial pointer table */
+                    num_entries = init_size;
+                } else {
+                    /* Double the size */
+                    num_entries = size * 2;
+                }
+
+                /* Allocate first pointer table or enlarge existing table */
+                p = realloc (files, sizeof (void*) * num_entries);
+                if (p != NULL) {
+                    /* Got the memory */
+                    files = (dirent**) p;
+                    allocated = num_entries;
+                } else {
+                    /* Out of memory */
+                    result = -1;
+                    break;
+                }
+
+            }
+
+            /* Allocate room for temporary directory entry */
+            if (tmp == NULL) {
+                tmp = (struct dirent*) malloc (sizeof (struct dirent));
+                if (tmp == NULL) {
+                    /* Cannot allocate temporary directory entry */
+                    result = -1;
+                    break;
+                }
+            }
+
+            /* Read directory entry to temporary area */
+            if (readdir_r (dir, tmp, &entry) == /*OK*/0) {
+
+                /* Did we get an entry? */
+                if (entry != NULL) {
+                    int pass;
+
+                    /* Determine whether to include the entry in result */
+                    if (filter) {
+                        /* Let the filter function decide */
+                        pass = filter (tmp);
+                    } else {
+                        /* No filter function, include everything */
+                        pass = 1;
+                    }
+
+                    if (pass) {
+                        /* Store the temporary entry to pointer table */
+                        files[size++] = tmp;
+                        tmp = NULL;
+
+                        /* Keep up with the number of files */
+                        result++;
+                    }
+
+                } else {
+
+                    /*
+                     * End of directory stream reached => sort entries and
+                     * exit.
+                     */
+                    qsort (files, size, sizeof (void*),
+                        (int (*) (const void*, const void*)) compare);
+                    break;
+
+                }
+
+            } else {
+                /* Error reading directory entry */
+                result = /*Error*/ -1;
+                break;
+            }
+
+        }
+
+    } else {
+        /* Cannot open directory */
+        result = /*Error*/ -1;
+    }
+
+    /* Release temporary directory entry */
+    free (tmp);
+
+    /* Release allocated memory on error */
+    if (result < 0) {
+        for (i = 0; i < size; i++) {
+            free (files[i]);
+        }
+        free (files);
+        files = NULL;
+    }
+
+    /* Close directory stream */
+    if (dir) {
+        closedir (dir);
+    }
+
+    /* Pass pointer table to caller */
+    if (namelist) {
+        *namelist = files;
+    }
+    return result;
+}
+
+/* Alphabetical sorting */
+static int
+alphasort(
+    const struct dirent **a, const struct dirent **b)
+{
+    return strcoll ((*a)->d_name, (*b)->d_name);
+}
+
+/* Sort versions */
+static int
+versionsort(
+    const struct dirent **a, const struct dirent **b)
+{
+    /* FIXME: implement strverscmp and use that */
+    return alphasort (a, b);
+}
+
+/* Convert multi-byte string to wide character string */
+static int
+dirent_mbstowcs_s(
+    size_t *pReturnValue,
+    wchar_t *wcstr,
+    size_t sizeInWords,
+    const char *mbstr,
+    size_t count)
+{
+    int error;
+
+#if defined(_MSC_VER)  &&  _MSC_VER >= 1400
+
+    /* Microsoft Visual Studio 2005 or later */
+    error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
+
+#else
+
+    /* Older Visual Studio or non-Microsoft compiler */
+    size_t n;
+
+    /* Convert to wide-character string (or count characters) */
+    n = mbstowcs (wcstr, mbstr, sizeInWords);
+    if (!wcstr  ||  n < count) {
+
+        /* Zero-terminate output buffer */
+        if (wcstr  &&  sizeInWords) {
+            if (n >= sizeInWords) {
+                n = sizeInWords - 1;
+            }
+            wcstr[n] = 0;
+        }
+
+        /* Length of resulting multi-byte string WITH zero terminator */
+        if (pReturnValue) {
+            *pReturnValue = n + 1;
+        }
+
+        /* Success */
+        error = 0;
+
+    } else {
+
+        /* Could not convert string */
+        error = 1;
+
+    }
+
+#endif
+    return error;
+}
+
+/* Convert wide-character string to multi-byte string */
+static int
+dirent_wcstombs_s(
+    size_t *pReturnValue,
+    char *mbstr,
+    size_t sizeInBytes, /* max size of mbstr */
+    const wchar_t *wcstr,
+    size_t count)
+{
+    int error;
+
+#if defined(_MSC_VER)  &&  _MSC_VER >= 1400
+
+    /* Microsoft Visual Studio 2005 or later */
+    error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
+
+#else
+
+    /* Older Visual Studio or non-Microsoft compiler */
+    size_t n;
+
+    /* Convert to multi-byte string (or count the number of bytes needed) */
+    n = wcstombs (mbstr, wcstr, sizeInBytes);
+    if (!mbstr  ||  n < count) {
+
+        /* Zero-terminate output buffer */
+        if (mbstr  &&  sizeInBytes) {
+            if (n >= sizeInBytes) {
+                n = sizeInBytes - 1;
+            }
+            mbstr[n] = '\0';
+        }
+
+        /* Length of resulting multi-bytes string WITH zero-terminator */
+        if (pReturnValue) {
+            *pReturnValue = n + 1;
+        }
+
+        /* Success */
+        error = 0;
+
+    } else {
+
+        /* Cannot convert string */
+        error = 1;
+
+    }
+
+#endif
+    return error;
+}
+
+/* Set errno variable */
+static void
+dirent_set_errno(
+    int error)
+{
+#if defined(_MSC_VER)  &&  _MSC_VER >= 1400
+
+    /* Microsoft Visual Studio 2005 and later */
+    _set_errno (error);
+
+#else
+
+    /* Non-Microsoft compiler or older Microsoft compiler */
+    errno = error;
+
+#endif
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*DIRENT_H*/
index 8a70f2d..0dd48fe 100644 (file)
@@ -1,12 +1,13 @@
 #include <winver.h>
 
+#define LWS_NUMVERSION         @LWS_LIBRARY_VERSION_MAJOR@,@LWS_LIBRARY_VERSION_MINOR@,0
 #define LWS_VERSION    @LWS_LIBRARY_VERSION_MAJOR@,@LWS_LIBRARY_VERSION_MINOR@,@LWS_LIBRARY_VERSION_PATCH@,0
 #define LWS_VERSION_STR "@LWS_LIBRARY_VERSION_MAJOR@.@LWS_LIBRARY_VERSION_MINOR@.@LWS_LIBRARY_VERSION_PATCH@\0"
 #define LWS_PACKAGE_NAME "@PACKAGE@\0"
 
 VS_VERSION_INFO VERSIONINFO
-  FILEVERSION    LWS_VERSION
-  PRODUCTVERSION LWS_VERSION
+  FILEVERSION    LWS_NUMVERSION
+  PRODUCTVERSION LWS_NUMVERSION
   FILEFLAGSMASK  VS_FFI_FILEFLAGSMASK
   FILEFLAGS      0
   FILEOS         VOS__WINDOWS32
index 08385c2..be5ac11 100644 (file)
@@ -1,11 +1,12 @@
-#include <time.h>\r
-#include <windows.h> //I've omitted context line\r
-\r
-#include "gettimeofday.h"\r
-\r
-int gettimeofday(struct timeval *tv, struct timezone *tz)\r
-{\r
-       FILETIME ft;\r
+#include <time.h>
+#include <windows.h>
+
+#include "gettimeofday.h"
+
+#ifndef LWS_MINGW_SUPPORT
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       FILETIME ft;
        unsigned __int64 tmpres = 0;\r
        static int tzflag;\r
 \r
@@ -19,11 +20,11 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
                /*converting file time to unix epoch*/\r
                tmpres /= 10;  /*convert into microseconds*/\r
                tmpres -= DELTA_EPOCH_IN_MICROSECS;
-               tv->tv_sec = (long)(tmpres / 1000000UL);\r
-               tv->tv_usec = (long)(tmpres % 1000000UL);\r
-       }\r
\r
-       if (NULL != tz) {\r
+               tv->tv_sec = (long)(tmpres / 1000000UL);
+               tv->tv_usec = (long)(tmpres % 1000000UL);
+       }
+
+       if (NULL != tz) {
                if (!tzflag) {\r
                        _tzset();\r
                        tzflag++;\r
@@ -31,6 +32,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
                tz->tz_minuteswest = _timezone / 60;\r
                tz->tz_dsttime = _daylight;\r
        }\r
-\r
-       return 0;\r
-}\r
+
+       return 0;
+}
+#endif
index 33e7a75..4531fa8 100644 (file)
 #endif
 
 #ifdef LWS_MINGW_SUPPORT
-  #include <winsock2.h>
+  #include <sys/time.h>
 #endif
 
-#ifndef _TIMEZONE_DEFINED 
-struct timezone 
+#ifndef _TIMEZONE_DEFINED
+struct timezone
 {
   int  tz_minuteswest; /* minutes W of Greenwich */
   int  tz_dsttime;     /* type of dst correction */
@@ -22,6 +22,8 @@ struct timezone
 
 #endif
 
+#ifndef LWS_MINGW_SUPPORT
 int gettimeofday(struct timeval *tv, struct timezone *tz);
+#endif
 
 #endif